[
  {
    "path": ".clang-format",
    "content": "AlignAfterOpenBracket: Align\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlinesLeft: false\nAlignOperands: true\nAlignTrailingComments: true\nAllowShortBlocksOnASingleLine: Empty\nAllowShortCaseLabelsOnASingleLine: false\nAllowShortEnumsOnASingleLine: true\nAllowShortFunctionsOnASingleLine: Empty\nAllowShortIfStatementsOnASingleLine: false\nAllowShortLambdasOnASingleLine: Inline\nAlwaysBreakTemplateDeclarations: true\nBinPackArguments: true\nBinPackParameters: true\nBraceWrapping:\n  AfterCaseLabel: true\n  AfterClass: true\n  AfterControlStatement: Always\n  AfterEnum: true\n  AfterExternBlock: true\n  AfterFunction: true\n  AfterNamespace: true\n  AfterStruct: true\n  AfterUnion: true\n  BeforeElse: true\n  BeforeWhile: true\n  SplitEmptyFunction: false\nBreakBeforeBraces: Custom\nBreakBeforeTernaryOperators: true\nColumnLimit: 0\nConstructorInitializerAllOnOneLineOrOnePerLine: false\nConstructorInitializerIndentWidth: 4\nContinuationIndentWidth: 4\nCpp11BracedListStyle: true\nIndentWidth: 4\nKeepEmptyLinesAtTheStartOfBlocks: false\nLanguage: Cpp\nMaxEmptyLinesToKeep: 1\nNamespaceIndentation: All\nObjCSpaceAfterProperty: false\nPointerAlignment: Left\nReflowComments: true\nSortIncludes: false\nSortUsingDeclarations: true\nSpaceAfterCStyleCast: false\nSpaceBeforeCtorInitializerColon: true\nSpaceAfterLogicalNot: false\nSpaceAfterTemplateKeyword: false\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeCaseColon: false\nSpaceBeforeParens: ControlStatements\nSpaceBeforeRangeBasedForLoopColon: true\nSpaceBeforeSquareBrackets: false\nSpaceInEmptyBlock: false\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 1\nSpacesInAngles: false\nSpacesInCStyleCastParentheses: false\nSpacesInConditionalStatement: false\nSpacesInContainerLiterals: true\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nStandard: Latest\nTabWidth: 4\nUseTab: Always\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Cemu Discord\n    url: https://discord.com/invite/5psYsup\n    about: If you need technical support with Cemu or have other questions the best place to ask is on the official Cemu Discord linked here\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/emulation_bug_report.yaml",
    "content": "# Docs - https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema\nname: Bug Report\ndescription: Report an issue with Cemu emulator\ntitle: \"Enter a title for the bug report here\"\nlabels: bug\nbody:\n  - type: markdown\n    id: md_readme\n    attributes:\n      value: |\n        ## Important: Read First\n        \n        If you discovered a bug you can report it here. Please make sure of the following first:\n        - That you are using the latest version of Cemu\n        - Only report something if you are sure it's a bug and not any technical issue on your end. For troubleshooting help see the [links page](https://github.com/cemu-project/Cemu#links)\n        - Problems specific to a single game should be reported on the [compatibility wiki](https://wiki.cemu.info/wiki/Main_Page) instead\n        - Verify that your problem isn't already mentioned on the [issue tracker](https://github.com/cemu-project/Cemu/issues)\n        \n        Additionally, be aware that graphic packs can also causes issues. There is a separate issue tracker for graphic pack bugs over at the [graphic pack repository](https://github.com/cemu-project/cemu_graphic_packs)\n  - type: textarea\n    id: current_behavior\n    attributes:\n      label: Current Behavior\n      description: \"What the bug is, in a brief description\"\n    validations:\n      required: true\n  - type: textarea\n    id: expected_behavior\n    attributes:\n      label: Expected Behavior\n      description: \"What did you expect to happen?\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: steps_to_reproduce\n    attributes:\n      label: Steps to Reproduce\n      description: \"How to reproduce the issue\"\n    validations:\n      required: true\n  - type: textarea\n    id: sys_info\n    attributes:\n      label: System Info (Optional)\n      description: \"Your PC specifications. Usually only the operating system and graphics card is important. But feel free to add more info.\"\n      placeholder: |\n        Info        \n        OS: Windows 10\n        GPU: NVIDIA GeForce RTX 4090\n      value: |\n        OS: \n        GPU: \n  - type: textarea\n    id: emulation_settings\n    attributes:\n      label: Emulation Settings (Optional)\n      description: |\n        Any non-default settings. You can leave this empty if you didn't change anything other than input settings.\n    validations:\n      required: false\n  - type: textarea\n    id: logs_files\n    attributes:\n      label: \"Logs (Optional)\"\n      description: |\n        \"Attach `log.txt` from your Cemu folder (*File > Open Cemu folder*)\".\n    validations:\n      required: false\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_report.yaml",
    "content": "# Docs - https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema\nname: Feature suggestion\ndescription: Suggest a new feature\ntitle: \"Enter a title for the suggestion here\"\nlabels: feature request\nbody:\n  - type: markdown\n    id: md_readme\n    attributes:\n      value: |\n        ## Important: Read First\n        \n        While we appreciate suggestions, it is important to note that we are a very small team and there are already many more ideas than we could ever implement in the near future. Therefore, please only suggest something if you believe it is a great addition and the idea is reasonably unique.\n        \n        *Avoid* to create suggestions for:\n        - Overly obvious features (\"Game xyz does not work and should be fixed\", \"Wiimote support should be improved\", \"You should add an Android port\", \"Copy feature xyz from another emulator\", \"A button to pause/stop emulation\")\n        - Niche features which are only interesting to a tiny percentage of users\n        - Large scale features (\"Add a Metal backend for MacOS\", \"Add ARM support\", \"Add savestates\")\n         \n        Note that this doesn't mean we aren't interested in these ideas, but rather we likely have them planned anyway and it's mostly up to finding the time to implement them.\n        If you believe your idea is worthwhile even if it doesn't meet all the criteria above, you can still try suggesting it but we might close it.        \n  - type: textarea\n    id: idea_suggestion\n    attributes:\n      label: Your suggestion\n      description: \"Describe what your suggestion is in as much detail as possible\"\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "name: Build Cemu\n\non:\n  workflow_call:\n    inputs:\n      next_version_major:\n        required: false\n        type: string\n      next_version_minor:\n        required: false\n        type: string\n\nenv:\n  VCPKG_ROOT: \"${{github.workspace}}/dependencies/vcpkg\"\n  VCPKG_BINARY_SOURCES: 'clear;nuget,GitHub,readwrite'\n  VCPKG_FORCE_DOWNLOADED_BINARIES: true\n  \njobs:\n  build-ubuntu:\n    continue-on-error: true\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - os: ubuntu-22.04\n            arch: x64\n          - os: ubuntu-22.04-arm\n            arch: arm\n            \n    name: build-ubuntu-${{ matrix.arch }}\n    runs-on: ${{ matrix.os }}\n    steps:\n    - name: \"Checkout repo\"\n      uses: actions/checkout@v6\n      with:\n        submodules: \"recursive\"\n        fetch-depth: 0\n\n    - name: Setup release mode parameters\n      run: |\n        echo \"BUILD_MODE=release\" >> $GITHUB_ENV\n        echo \"BUILD_FLAGS=\" >> $GITHUB_ENV\n        echo \"Build mode is release\"\n\n    - name: Setup build flags for version\n      if: ${{ inputs.next_version_major != '' }}\n      run: |\n        echo \"[INFO] Version ${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}\"\n        echo \"BUILD_FLAGS=${{ env.BUILD_FLAGS }} -DEMULATOR_VERSION_MAJOR=${{ inputs.next_version_major }} -DEMULATOR_VERSION_MINOR=${{ inputs.next_version_minor }}\" >> $GITHUB_ENV\n\n    - name: \"Install system dependencies\"\n      run: |\n        sudo apt update -qq\n        sudo apt install -y clang-15 cmake freeglut3-dev libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev libudev-dev nasm ninja-build libbluetooth-dev\n\n    - name: \"Bootstrap vcpkg\"\n      run: |\n        bash ./dependencies/vcpkg/bootstrap-vcpkg.sh\n\n    - name: 'Setup NuGet Credentials for vcpkg'\n      shell: 'bash'\n      run: |\n        mono `./dependencies/vcpkg/vcpkg fetch nuget | tail -n 1` \\\n        sources add \\\n        -source \"https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json\" \\\n        -storepasswordincleartext \\\n        -name \"GitHub\" \\\n        -username \"${{ github.repository_owner }}\" \\\n        -password \"${{ secrets.GITHUB_TOKEN }}\"\n        mono `./dependencies/vcpkg/vcpkg fetch nuget | tail -n 1` \\\n        setapikey \"${{ secrets.GITHUB_TOKEN }}\" \\\n        -source \"https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json\"\n        \n    - name: \"cmake\"\n      run: |\n        cmake -S . -B build ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DCMAKE_C_COMPILER=/usr/bin/clang-15 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-15 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja\n\n    - name: \"Build Cemu\"\n      run: |\n        cmake --build build\n\n    - name: Prepare artifact\n      run: mv bin/Cemu_release bin/Cemu\n\n    - name: Upload artifact\n      uses: actions/upload-artifact@v6\n      with:\n        name: cemu-bin-linux-${{ matrix.arch }}\n        path: ./bin/Cemu\n\n  build-appimage:\n    strategy:\n      fail-fast: false\n      matrix:\n        include:\n          - os: ubuntu-22.04\n            arch: x64\n          - os: ubuntu-22.04-arm\n            arch: arm\n            \n    name: build-appimage-${{ matrix.arch }}\n    runs-on: ${{ matrix.os }}\n    needs: build-ubuntu\n    steps:\n    - name: Checkout Upstream Repo\n      uses: actions/checkout@v6\n\n    - uses: actions/download-artifact@v8\n      with:\n        name: cemu-bin-linux-${{ matrix.arch }}\n        path: bin\n\n    - name: \"Install system dependencies\"\n      run: |\n        sudo apt update -qq\n        sudo apt install -y clang-15 cmake freeglut3-dev libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev nasm ninja-build appstream libbluetooth-dev\n\n    - name: \"Build AppImage\"\n      run: |\n        export LD_LIBRARY_PATH=\"/usr/local/lib:$LD_LIBRARY_PATH\"\n        export DEPLOY_GTK_VERSION=3\n        dist/linux/appimage.sh ${{ runner.arch }}\n\n    - name: Upload artifact\n      uses: actions/upload-artifact@v6\n      with:\n        name: cemu-appimage-${{ matrix.arch }}\n        path: artifacts\n\n  build-windows:\n    runs-on: windows-2022\n    steps:\n    - name: \"Checkout repo\"\n      uses: actions/checkout@v6\n      with:\n        submodules: \"recursive\"\n\n    - name: Setup release mode parameters\n      run: |\n        echo \"BUILD_MODE=release\" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append\n        echo \"BUILD_FLAGS=\" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append\n        echo \"Build mode is release\"\n\n    - name: Setup build flags for version\n      if: ${{ inputs.next_version_major != '' }}\n      run: |\n        echo \"[INFO] Version ${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}\"\n        echo \"BUILD_FLAGS=${{ env.BUILD_FLAGS }} -DEMULATOR_VERSION_MAJOR=${{ inputs.next_version_major }} -DEMULATOR_VERSION_MINOR=${{ inputs.next_version_minor }}\" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append\n\n    - name: \"Setup cmake\"\n      uses: jwlawson/actions-setup-cmake@v2\n      with:\n        cmake-version: '3.29.0'\n\n    - name: \"Bootstrap vcpkg\"\n      run: |\n        ./dependencies/vcpkg/bootstrap-vcpkg.bat\n\n    - name: 'Setup NuGet Credentials for vcpkg'\n      shell: 'bash'\n      run: |\n        `./dependencies/vcpkg/vcpkg.exe fetch nuget | tail -n 1` \\\n        sources add \\\n        -source \"https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json\" \\\n        -storepasswordincleartext \\\n        -name \"GitHub\" \\\n        -username \"${{ github.repository_owner }}\" \\\n        -password \"${{ secrets.GITHUB_TOKEN }}\"\n        `./dependencies/vcpkg/vcpkg.exe fetch nuget | tail -n 1` \\\n        setapikey \"${{ secrets.GITHUB_TOKEN }}\" \\\n        -source \"https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json\"\n\n    - name: \"cmake\"\n      run: |\n        mkdir -p build\n        cd build\n        echo \"[INFO] BUILD_FLAGS: ${{ env.BUILD_FLAGS }}\"\n        echo \"[INFO] BUILD_MODE: ${{ env.BUILD_MODE }}\"\n        cmake .. ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DVCPKG_INSTALL_OPTIONS=\"--clean-after-build\"\n\n    - name: \"Build Cemu\"\n      run: |\n        cd build\n        cmake --build . --config ${{ env.BUILD_MODE }}\n\n    - name: Prepare artifact\n      run: Rename-Item bin/Cemu_release.exe Cemu.exe\n\n    - name: Build NSIS Installer\n      shell: cmd\n      run: |\n        cd src\\resource\n        makensis /DPRODUCT_VERSION=${{ inputs.next_version_major }}.${{ inputs.next_version_minor }} installer.nsi\n\n    - name: Upload artifact\n      uses: actions/upload-artifact@v6\n      with:\n        name: cemu-bin-windows-x64\n        path: ./bin/Cemu.exe\n\n    - name: Upload NSIS Installer\n      uses: actions/upload-artifact@v6\n      with:\n        name: cemu-installer-windows-x64\n        path: ./src/resource/cemu-${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}-windows-x64-installer.exe\n\n  build-macos:\n    runs-on: macos-14\n    strategy:\n      matrix:\n        arch: [x86_64, arm64]\n    steps:\n    - name: \"Checkout repo\"\n      uses: actions/checkout@v6\n      with:\n        submodules: \"recursive\"\n\n    - name: Setup release mode parameters\n      run: |\n        echo \"BUILD_MODE=release\" >> $GITHUB_ENV\n        echo \"BUILD_FLAGS=\" >> $GITHUB_ENV\n        echo \"Build mode is release\"\n\n    - name: Setup build flags for version\n      if: ${{ inputs.next_version_major != '' }}\n      run: |\n        echo \"[INFO] Version ${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}\"\n        echo \"BUILD_FLAGS=${{ env.BUILD_FLAGS }} -DEMULATOR_VERSION_MAJOR=${{ inputs.next_version_major }} -DEMULATOR_VERSION_MINOR=${{ inputs.next_version_minor }}\" >> $GITHUB_ENV\n\n    - name: \"Install system dependencies\"\n      run: |\n        brew update\n        brew install ninja nasm automake libtool\n\n    - name: \"Install molten-vk\"\n      run: |\n        curl -L -O https://github.com/KhronosGroup/MoltenVK/releases/download/v1.4.1/MoltenVK-macos-privateapi.tar\n        tar xf MoltenVK-macos-privateapi.tar\n        sudo mkdir -p /usr/local/lib\n        sudo cp MoltenVK/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib /usr/local/lib\n\n    - name: \"Setup cmake\"\n      uses: jwlawson/actions-setup-cmake@v2\n      with:\n        cmake-version: '3.29.0'\n\n    - name: \"Bootstrap vcpkg\"\n      run: |\n        bash ./dependencies/vcpkg/bootstrap-vcpkg.sh\n\n    - name: 'Setup NuGet Credentials for vcpkg'\n      shell: 'bash'\n      run: |\n        mono `./dependencies/vcpkg/vcpkg fetch nuget | tail -n 1` \\\n        sources add \\\n        -source \"https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json\" \\\n        -storepasswordincleartext \\\n        -name \"GitHub\" \\\n        -username \"${{ github.repository_owner }}\" \\\n        -password \"${{ secrets.GITHUB_TOKEN }}\"\n        mono `./dependencies/vcpkg/vcpkg fetch nuget | tail -n 1` \\\n        setapikey \"${{ secrets.GITHUB_TOKEN }}\" \\\n        -source \"https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json\"\n\n    - name: \"cmake\"\n      run: |\n        mkdir build\n        cd build\n        cmake .. ${{ env.BUILD_FLAGS }} \\\n        -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} \\\n        -DCMAKE_OSX_ARCHITECTURES=${{ matrix.arch }} \\\n        -DMACOS_BUNDLE=ON \\\n        -G Ninja\n\n    - name: \"Build Cemu\"\n      run: |\n        cmake --build build\n\n    - name: Prepare artifact\n      run: |\n        mkdir bin/Cemu_app\n        mv bin/Cemu_release.app bin/Cemu_app/Cemu.app\n        mv bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu_release bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu\n        sed -i '' 's/Cemu_release/Cemu/g' bin/Cemu_app/Cemu.app/Contents/Info.plist\n        chmod a+x bin/Cemu_app/Cemu.app/Contents/MacOS/{Cemu,update.sh}\n        ln -s /Applications bin/Cemu_app/Applications\n        hdiutil create ./bin/tmp.dmg -ov -volname \"Cemu\" -fs HFS+ -srcfolder \"./bin/Cemu_app\"\n        hdiutil convert ./bin/tmp.dmg -format UDZO -o bin/Cemu.dmg\n        rm bin/tmp.dmg\n\n    - name: Upload artifact\n      uses: actions/upload-artifact@v6\n      with:\n        name: cemu-bin-macos-${{ matrix.arch }}\n        path: ./bin/Cemu.dmg\n"
  },
  {
    "path": ".github/workflows/build_check.yml",
    "content": "name: Build check\non: \n  pull_request:\n    paths-ignore:\n      - \"*.md\"\n    types:\n      - opened\n      - synchronize\n      - reopened\n  push:\n    paths-ignore:\n      - \"*.md\"\n    branches:\n      - main\n\njobs:\n  build:\n    uses: ./.github/workflows/build.yml\n"
  },
  {
    "path": ".github/workflows/deploy_release.yml",
    "content": "name: Deploy release\non: \n  workflow_dispatch:\n    inputs:\n      changelog0:\n        description: 'Enter the changelog lines for this release. Each line is a feature / bullet point. Do not use dash.'\n        required: true\n        type: string\n      changelog1:\n        description: 'Feature 2'\n        required: false\n        type: string\n      changelog2:\n        description: 'Feature 3'\n        required: false\n        type: string\n      changelog3:\n        description: 'Feature 4'\n        required: false\n        type: string\n      changelog4:\n        description: 'Feature 5'\n        required: false\n        type: string\n      changelog5:\n        description: 'Feature 6'\n        required: false\n        type: string\n      changelog6:\n        description: 'Feature 7'\n        required: false\n        type: string\n      changelog7:\n        description: 'Feature 8'\n        required: false\n        type: string\n      changelog8:\n        description: 'Feature 9'\n        required: false\n        type: string\n      changelog9:\n        description: 'Feature 10'\n        required: false\n        type: string\n\njobs:\n  calculate-version:\n    name: Calculate Version\n    uses: ./.github/workflows/determine_release_version.yml\n  call-release-build:\n    uses: ./.github/workflows/build.yml\n    needs: calculate-version\n    with:\n      next_version_major: ${{ needs.calculate-version.outputs.next_version_major }}\n      next_version_minor: ${{ needs.calculate-version.outputs.next_version_minor }}\n  deploy:\n    name: Deploy release\n    runs-on: ubuntu-22.04\n    needs: [call-release-build, calculate-version]\n    steps:\n      - uses: actions/checkout@v6\n        with:\n          fetch-depth: 0\n\n      - name: Generate changelog\n        id: generate_changelog\n        run: |\n          CHANGELOG=\"\"\n          if [ -n \"${{ github.event.inputs.changelog0 }}\" ]; then CHANGELOG=\"$CHANGELOG- ${{ github.event.inputs.changelog0 }}\\n\"; fi\n          if [ -n \"${{ github.event.inputs.changelog1 }}\" ]; then CHANGELOG=\"$CHANGELOG- ${{ github.event.inputs.changelog1 }}\\n\"; fi\n          if [ -n \"${{ github.event.inputs.changelog2 }}\" ]; then CHANGELOG=\"$CHANGELOG- ${{ github.event.inputs.changelog2 }}\\n\"; fi\n          if [ -n \"${{ github.event.inputs.changelog3 }}\" ]; then CHANGELOG=\"$CHANGELOG- ${{ github.event.inputs.changelog3 }}\\n\"; fi\n          if [ -n \"${{ github.event.inputs.changelog4 }}\" ]; then CHANGELOG=\"$CHANGELOG- ${{ github.event.inputs.changelog4 }}\\n\"; fi\n          if [ -n \"${{ github.event.inputs.changelog5 }}\" ]; then CHANGELOG=\"$CHANGELOG- ${{ github.event.inputs.changelog5 }}\\n\"; fi\n          if [ -n \"${{ github.event.inputs.changelog6 }}\" ]; then CHANGELOG=\"$CHANGELOG- ${{ github.event.inputs.changelog6 }}\\n\"; fi\n          if [ -n \"${{ github.event.inputs.changelog7 }}\" ]; then CHANGELOG=\"$CHANGELOG- ${{ github.event.inputs.changelog7 }}\\n\"; fi\n          if [ -n \"${{ github.event.inputs.changelog8 }}\" ]; then CHANGELOG=\"$CHANGELOG- ${{ github.event.inputs.changelog8 }}\\n\"; fi\n          if [ -n \"${{ github.event.inputs.changelog9 }}\" ]; then CHANGELOG=\"$CHANGELOG- ${{ github.event.inputs.changelog9 }}\\n\"; fi\n          echo -e \"$CHANGELOG\"\n          echo \"RELEASE_BODY=$CHANGELOG\" >> $GITHUB_ENV\n      - uses: actions/download-artifact@v8\n        with:\n          name: cemu-bin-linux-x64\n          path: cemu-bin-linux-x64\n\n      - uses: actions/download-artifact@v8\n        with:\n          name: cemu-appimage-x64\n          path: cemu-appimage-x64\n\n      - uses: actions/download-artifact@v8\n        with:\n          name: cemu-bin-windows-x64\n          path: cemu-bin-windows-x64\n\n      - uses: actions/download-artifact@v8\n        with:\n          name: cemu-installer-windows-x64\n          path: cemu-installer-windows-x64\n\n      - uses: actions/download-artifact@v8\n        with:\n          pattern: cemu-bin-macos*\n          path: cemu-macos\n\n      - name: Initialize\n        run: |\n          mkdir upload\n          sudo apt install zip\n\n      - name: Set version dependent vars\n        run: |\n          echo \"Version: ${{ needs.calculate-version.outputs.next_version }}\"\n          echo \"CEMU_FOLDER_NAME=Cemu_${{ needs.calculate-version.outputs.next_version }}\"\n          echo \"CEMU_VERSION=${{ needs.calculate-version.outputs.next_version }}\"\n          echo \"CEMU_FOLDER_NAME=Cemu_${{ needs.calculate-version.outputs.next_version }}\" >> $GITHUB_ENV\n          echo \"CEMU_VERSION=${{ needs.calculate-version.outputs.next_version }}\" >> $GITHUB_ENV\n\n      - name: Create release from windows-bin\n        run: |\n          ls ./\n          ls ./bin/\n          cp -R ./bin ./${{ env.CEMU_FOLDER_NAME }}\n          mv cemu-bin-windows-x64/Cemu.exe ./${{ env.CEMU_FOLDER_NAME }}/Cemu.exe\n          zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-windows-x64.zip ${{ env.CEMU_FOLDER_NAME }}\n          rm -r ./${{ env.CEMU_FOLDER_NAME }}\n\n      - name: Create release from windows-installer\n        run: cp cemu-installer-windows-x64/cemu-${{ env.CEMU_VERSION }}-windows-x64-installer.exe upload/cemu-${{ env.CEMU_VERSION }}-windows-x64-installer.exe\n\n      - name: Create appimage\n        run: |\n          VERSION=${{ env.CEMU_VERSION }}\n          echo \"Cemu Version is $VERSION\"\n          ls cemu-appimage-x64\n          mv cemu-appimage-x64/Cemu-*-x86_64.AppImage upload/Cemu-$VERSION-x86_64.AppImage\n        \n      - name: Create release from linux-bin\n        run: |\n          ls ./\n          ls ./bin/\n          cp -R ./bin ./${{ env.CEMU_FOLDER_NAME }}\n          mv cemu-bin-linux-x64/Cemu ./${{ env.CEMU_FOLDER_NAME }}/Cemu\n          zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-ubuntu-22.04-x64.zip ${{ env.CEMU_FOLDER_NAME }}\n          rm -r ./${{ env.CEMU_FOLDER_NAME }}\n          \n      - name: Create release from macos-bin\n        run: |\n          cd cemu-macos\n          for bin_dir in cemu-bin-macos-*; do\n            arch=\"${bin_dir##cemu-bin-macos-}\"\n            cp $bin_dir/Cemu.dmg ../upload/cemu-${{ env.CEMU_VERSION }}-macos-12-$arch.dmg\n          done\n\n      - name: Create release\n        run: |\n          wget -O ghr.tar.gz https://github.com/tcnksm/ghr/releases/download/v0.15.0/ghr_v0.15.0_linux_amd64.tar.gz\n          tar xvzf ghr.tar.gz; rm ghr.tar.gz\n          echo \"[INFO] Release tag: v${{ env.CEMU_VERSION }}\"\n          CHANGELOG_UNESCAPED=$(printf \"%s\\n\" \"${{ env.RELEASE_BODY }}\" | sed 's/\\\\n/\\n/g')          \n          RELEASE_BODY=$(printf \"%s\\n%s\" \\\n            \"**Changelog:**\" \\\n            \"$CHANGELOG_UNESCAPED\")\n          ghr_v0.15.0_linux_amd64/ghr -draft -t ${{ secrets.GITHUB_TOKEN }} -n \"Cemu ${{ env.CEMU_VERSION }}\" -b \"$RELEASE_BODY\" \"v${{ env.CEMU_VERSION }}\" ./upload\n"
  },
  {
    "path": ".github/workflows/determine_release_version.yml",
    "content": "name: Calculate Next Version from release history\n\non:\n  workflow_dispatch:\n  workflow_call:\n    outputs:\n      next_version:\n        description: \"The next semantic version\"\n        value: ${{ jobs.calculate-version.outputs.next_version }}\n      next_version_major:\n        description: \"The next semantic version (major)\"\n        value: ${{ jobs.calculate-version.outputs.next_version_major }}\n      next_version_minor:\n        description: \"The next semantic version (minor)\"\n        value: ${{ jobs.calculate-version.outputs.next_version_minor }}\n\njobs:\n  calculate-version:\n    runs-on: ubuntu-latest\n    outputs:\n      next_version: ${{ steps.calculate_next_version.outputs.next_version }}\n      next_version_major: ${{ steps.calculate_next_version.outputs.next_version_major }}\n      next_version_minor: ${{ steps.calculate_next_version.outputs.next_version_minor }}      \n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v6\n\n      - name: Get all releases\n        id: get_all_releases\n        run: |\n          # Fetch all releases and check for API errors\n          RESPONSE=$(curl -s -o response.json -w \"%{http_code}\" \"https://api.github.com/repos/${{ github.repository }}/releases?per_page=100\")\n          if [ \"$RESPONSE\" -ne 200 ]; then\n            echo \"Failed to fetch releases. HTTP status: $RESPONSE\"\n            cat response.json\n            exit 1\n          fi\n          \n          # Extract and sort tags\n          ALL_TAGS=$(jq -r '.[].tag_name' response.json | grep -E '^v[0-9]+\\.[0-9]+(-[0-9]+)?$' | sed 's/-.*//' | sort -V | tail -n 1)\n\n          # Exit if no tags were found\n          if [ -z \"$ALL_TAGS\" ]; then\n            echo \"No valid tags found.\"\n            exit 1\n          fi\n\n          echo \"::set-output name=tag::$ALL_TAGS\"\n          # echo \"tag=$ALL_TAGS\" >> $GITHUB_STATE\n\n      - name: Calculate next semver minor\n        id: calculate_next_version\n        run: |\n          LATEST_VERSION=${{ steps.get_all_releases.outputs.tag }}\n\n          # strip 'v' prefix and split into major.minor\n          LATEST_VERSION=${LATEST_VERSION//v/}\n          IFS='.' read -r -a VERSION_PARTS <<< \"$LATEST_VERSION\"\n\n          MAJOR=${VERSION_PARTS[0]}\n          MINOR=${VERSION_PARTS[1]}\n\n          # increment the minor version\n          MINOR=$((MINOR + 1))\n\n          NEXT_VERSION=\"${MAJOR}.${MINOR}\"\n\n          echo \"Major: $MAJOR\"\n          echo \"Minor: $MINOR\"\n\n          echo \"Next version: $NEXT_VERSION\"\n          echo \"::set-output name=next_version::$NEXT_VERSION\"\n          echo \"::set-output name=next_version_major::$MAJOR\"\n          echo \"::set-output name=next_version_minor::$MINOR\"          "
  },
  {
    "path": ".github/workflows/generate_pot.yml",
    "content": "name: Generate translation template\n\non:\n  pull_request:\n    paths-ignore:\n      - \"*.md\"\n    types:\n      - opened\n      - synchronize\n      - reopened\n  push:\n    paths-ignore:\n      - \"*.md\"\n    branches:\n      - main\n\njobs:\n  generate-pot:\n    runs-on: ubuntu-latest\n    steps:\n      - name: \"Checkout repo\"\n        uses: actions/checkout@v6\n\n      - name: \"Install gettext\"\n        run: |\n          sudo apt update -qq\n          sudo apt install -y gettext\n\n      - name: \"Generate POT file using xgettext\"\n        run: >\n          find src -name *.cpp -o -name *.hpp -o -name *.h | \n          xargs xgettext --from-code=utf-8 -w 100\n          --keyword=\"_\" --keyword=\"wxTRANSLATE\" --keyword=\"wxPLURAL:1,2\"\n          --keyword=\"_tr\" --keyword=\"TR_NOOP\"\n          --check=space-ellipsis --omit-header\n          -o cemu.pot\n\n      - name: Upload artifact\n        uses: actions/upload-artifact@v6\n        with:\n          name: POT file\n          path: ./cemu.pot\n          if-no-files-found: error"
  },
  {
    "path": ".gitignore",
    "content": "*.slo\n*.lo\n*.o\n*.obj\n*.gch\n*.pch\n*.so\n*.dylib\n*.dll\n*.a\n*.lib\n*.exe\n*.out\n*.app\n.vs\n.vscode\n.idea/\n\nbuild/\ncmake-build-*/\nout/\n.cache/\nbin/Cemu_*\nbin/Cemu_*.exe\n\n# Cemu bin files\nbin/otp.bin\nbin/seeprom.bin\nbin/log.txt\nbin/Cemu_*.pdb\nbin/Cemu_*.ilk\nbin/Cemu.exe.backup\nbin/mlc01/*\nbin/settings.xml\nbin/network_services.xml\nbin/title_list_cache.xml\nbin/debugger/*\nbin/sdcard/*\nbin/screenshots/*\nbin/dump/*\nbin/cafeLibs/*\nbin/portable/*\nbin/keys.txt\n\n!bin/shaderCache/info.txt\nbin/shaderCache/*\n\nbin/controllerProfiles/*\n\n!bin/gameProfiles/default/*\nbin/gameProfiles/*\n\nbin/graphicPacks/*\n\n# Ignore Finder view option files created by OS X\n.DS_Store"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"dependencies/ZArchive\"]\n\tpath = dependencies/ZArchive\n\turl = https://github.com/Exzap/ZArchive\n\tshallow = true\n[submodule \"dependencies/cubeb\"]\n\tpath = dependencies/cubeb\n\turl = https://github.com/mozilla/cubeb\n\tshallow = true\n[submodule \"dependencies/vcpkg\"]\n\tpath = dependencies/vcpkg\n\turl = https://github.com/microsoft/vcpkg\n\tshallow = false\n[submodule \"dependencies/Vulkan-Headers\"]\n\tpath = dependencies/Vulkan-Headers\n\turl = https://github.com/KhronosGroup/Vulkan-Headers\n\tshallow = true\n[submodule \"dependencies/imgui\"]\n\tpath = dependencies/imgui\n\turl = https://github.com/ocornut/imgui\n\tshallow = true\n[submodule \"dependencies/metal-cpp\"]\n\tpath = dependencies/metal-cpp\n\turl = https://github.com/bkaradzic/metal-cpp.git\n\tshallow = true\n[submodule \"dependencies/xbyak_aarch64\"]\n\tpath = dependencies/xbyak_aarch64\n\turl = https://github.com/fujitsu/xbyak_aarch64\n"
  },
  {
    "path": "BUILD.md",
    "content": "# Build Instructions\n\n## Table of Contents\n\n- [Windows](#windows)\n- [Linux](#linux)\n   - [Dependencies](#dependencies)\n      - [For Arch and derivatives:](#for-arch-and-derivatives)\n      - [For Debian, Ubuntu and derivatives](#for-debian-ubuntu-and-derivatives)\n      - [For Fedora and derivatives:](#for-fedora-and-derivatives)\n   - [Build Cemu](#build-cemu)\n      - [CMake and Clang](#cmake-and-clang)\n      - [GCC](#gcc)\n      - [Debug Build](#debug-build)\n      - [Troubleshooting Steps](#troubleshooting-steps)\n         - [Compiling Errors](#compiling-errors)\n         - [Building Errors](#building-errors)\n- [macOS](#macos)\n   - [Installing brew](#installing-brew)\n   - [Installing Tool Dependencies](#installing-tool-dependencies)\n   - [Installing Library Dependencies](#installing-library-dependencies)\n   - [Build Cemu using CMake](#build-cemu-using-cmake)\n- [FreeBSD](#freebsd)\n\t- [Installing Dependencies](#installing-dependencies)\n\t- [Build Cemu on BSD with CMake](#build-cemu-on-bsd-with-cmake)\n- [Updating Cemu and source code](#updating-cemu-and-source-code)\n\n## Windows\n\nPrerequisites:\n- git\n- A recent version of Visual Studio 2022 with the following additional components:\n   - C++ CMake tools for Windows\n   - Windows 10/11 SDK\n\nInstructions for Visual Studio 2022:\n\n1. Run `git clone --recursive https://github.com/cemu-project/Cemu`\n2. Open the newly created Cemu directory in Visual Studio using the \"Open a local folder\" option\n3. In the menu select Project -> Configure CMake. Wait until it is done, this may take a long time\n4. You can now build, run and debug Cemu\n\nAny other IDE should also work as long as it has CMake and MSVC support. CLion and Visual Studio Code have been confirmed to work.\n\n## Linux\n\nTo compile Cemu, a recent enough compiler and STL with C++20 support is required! Clang-15 or higher is what we recommend.\n\n### Dependencies\n\n#### For Arch and derivatives:\n`sudo pacman -S --needed base-devel bluez-libs clang cmake freeglut git glm gtk3 libgcrypt libpulse libsecret linux-headers llvm nasm ninja systemd unzip zip`\n\n#### For Debian, Ubuntu and derivatives:\n`sudo apt install -y cmake curl clang-15 freeglut3-dev git libbluetooth-dev libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev libtool nasm ninja-build`\n\nYou may also need to install `libusb-1.0-0-dev` as a workaround for an issue with the vcpkg hidapi package.\n\nAt Step 3 in [Build Cemu using cmake and clang](#build-cemu-using-cmake-and-clang), use the following command instead:\n   `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-15 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-15 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja`\n\n#### For Fedora and derivatives:\n`sudo dnf install bluez-libs-devel clang cmake cubeb-devel freeglut-devel git glm-devel gtk3-devel kernel-headers libgcrypt-devel libsecret-devel libtool libusb1-devel llvm nasm ninja-build perl-core systemd-devel wayland-protocols-devel zlib-devel zlib-static`\n\n### Build Cemu\n\n#### CMake and Clang\n\n```\ngit clone --recursive https://github.com/cemu-project/Cemu\ncd Cemu\ncmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja\ncmake --build build\n```\n\n#### GCC\n\nIf you are building using GCC, make sure you have g++ installed:\n- Installation for Arch and derivatives: `sudo pacman -S gcc`\n- Installation for Debian, Ubuntu and derivatives: `sudo apt install g++`\n- Installation for Fedora and derivatives: `sudo dnf install gcc-c++`\n\n```\ngit clone --recursive https://github.com/cemu-project/Cemu\ncd Cemu\ncmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -G Ninja\ncmake --build build\n```\n\n#### Debug Build\n\n```\ngit clone --recursive https://github.com/cemu-project/Cemu\ncd Cemu\ncmake -S . -B build -DCMAKE_BUILD_TYPE=debug -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja\ncmake --build build\n```\n\nIf you are using GCC, replace `cmake -S . -B build -DCMAKE_BUILD_TYPE=debug -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja` with `cmake -S . -B build -DCMAKE_BUILD_TYPE=debug -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -G Ninja`\n\n#### Troubleshooting Steps\n\n##### Compiling Errors\n\nThis section refers to running `cmake -S...` (truncated).\n\n* `vcpkg install failed`\n   * Run the following in the root directory and try running the command again (don't forget to change directories afterwards):\n      * `cd dependencies/vcpkg && git fetch --unshallow`\n* `Please ensure you're using the latest port files with git pull and vcpkg update.`\n   * Either:\n      * Update vcpkg by running by the following command:\n         * `git submodule update --remote dependencies/vcpkg`\n      * If you are sure vcpkg is up to date, check the following logs:\n         * `Cemu/dependencies/vcpkg/buildtrees/wxwidgets/config-x64-linux-out.log`\n         * `Cemu/dependencies/vcpkg/buildtrees/libsystemd/config-x64-linux-dbg-meson-log.txt.log`\n         * `Cemu/dependencies/vcpkg/buildtrees/libsystemd/config-x64-linux-dbg-out.log`\n* Not able to find Ninja.\n   * Add the following and try running the command again:\n      * `-DCMAKE_MAKE_PROGRAM=/usr/bin/ninja`\n* Compiling failed during the boost-build dependency.\n   * It means you don't have a working/good standard library installation. Check the integrity of your system headers and making sure that C++ related packages are installed and intact.\n* Compiling failed during rebuild after `git pull` with an error that mentions RPATH\n   * Add the following and try running the command again:\n      * `-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON`\n* Environment variable `VCPKG_FORCE_SYSTEM_BINARIES` must be set.\n   * Execute the folowing and then try running the command again:\n      * `export VCPKG_FORCE_SYSTEM_BINARIES=1`\n* If you are getting a random error, read the [package-name-and-platform]-out.log and [package-name-and-platform]-err.log for the actual reason to see if you might be lacking the headers from a dependency.\n\n\nIf you are getting a different error than any of the errors listed above, you may either open an issue in this repo or try using [GCC](#gcc). Make sure your standard library and compilers are updated since Cemu uses a lot of modern features!\n\n\n##### Building Errors\n\nThis section refers to running `cmake --build build`.\n\n* `main.cpp.o: in function 'std::__cxx11::basic_string...`\n   * You likely are experiencing a clang-14 issue. This can only be fixed by either lowering the clang version or using GCC, see [GCC](#gcc).\n* `fatal error: 'span' file not found`\n   *  You're either missing `libstdc++` or are using a version that's too old. Install at least v10 with your package manager, eg `sudo apt install libstdc++-10-dev`. See [#644](https://github.com/cemu-project/Cemu/issues/644).\n* `undefined libdecor_xx`\n   * You are likely experiencing an issue with sdl2 package that comes with vcpkg. Delete sdl2 from vcpkg.json in source file and recompile.\n\nIf you are getting a different error than any of the errors listed above, you may either open an issue in this repo or try using [GCC](#gcc). Make sure your standard library and compilers are updated since Cemu uses a lot of modern features!\n\n## macOS\n\nTo compile Cemu, a recent enough compiler and STL with C++20 support is required! LLVM 13 and below\ndon't support the C++20 feature set required, so either install LLVM from Homebrew or make sure that\nyou have a recent enough version of Xcode. Xcode 15 is known to work. The OpenGL graphics API isn't\nsupported on macOS, so Vulkan must be used through the Molten-VK compatibility layer.\n\n### Installing brew\n\n1. `/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"`\n2. Set up the Homebrew shell environment:\n   1. **On an Intel Mac:** `eval \"$(/usr/local/Homebrew/bin/brew shellenv)\"`\n   2. **On an Apple Silicon Mac:** eval `\"$(/opt/homebrew/bin/brew shellenv)\"`\n\n### Installing Tool Dependencies\n\nThe native versions of these can be used regardless of what type of Mac you have.\n\n`brew install git cmake ninja nasm automake libtool`\n\n### Installing Library Dependencies\n\n**On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used to install these dependencies:**\n1. `softwareupdate --install-rosetta` # Install Rosetta 2 if you don't have it. This only has to be done once\n2. `arch -x86_64 zsh` # run an x64 shell\n3. `/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"`\n4. `eval \"$(/usr/local/Homebrew/bin/brew shellenv)\"`\n\nThen install the dependencies:\n\n`brew install boost molten-vk`\n\n### Build Cemu using CMake\n\n1. `git clone --recursive https://github.com/cemu-project/Cemu`\n2. `cd Cemu`\n3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_OSX_ARCHITECTURES=x86_64 -G Ninja`\n4. `cmake --build build`\n5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`.\n\n#### Troubleshooting steps\n- If step 3 gives you an error about not being able to find ninja, try appending `-DCMAKE_MAKE_PROGRAM=/usr/local/bin/ninja` to the command and running it again.\n\n## FreeBSD\n\nThe following instructions to build Cemu on FreeBSD are experimental. Some features available on other platforms are not available on FreeBSD (discord rich presence, bluetooth/support for actual Wii U controllers, auto-updates, etc.)\n\nTo compile Cemu, a recent enough compiler and STL with C++20 support is required! Clang-15 or higher is what we recommend. Any version of FreeBSD 13.3-RELEASE or higher comes bundled with LLVM > version 15 as part of the base system. However, if for whatever reason your system lacks a recent version of LLVM you can install one by executing:\n\n`sudo pkg install llvm15`\n\nOr a higher version as desired.\n\n### Installing Dependencies\n\n`sudo pkg install boost-libs cmake-core curl glslang gtk3 libzip ninja png pkgconf pugixml rapidjson sdl2 wayland wayland-protocols wx32-gtk3 xorg zstd`\n\n### Build Cemu on BSD with CMake\n\n```\ngit clone --recursive https://github.com/cemu-project/Cemu\ncd Cemu\ncmake -B build -DCMAKE_BUILD_TYPE=release -DENABLE_BLUEZ=OFF -DENABLE_DISCORD_RPC=OFF -DENABLE_FERAL_GAMEMODE=OFF -DENABLE_HIDAPI=OFF -DENABLE_VCPKG=OFF -G Ninja\ncmake --build build\n\ncd build && ninja install\n```\n\nYou should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`.\n\n## Updating Cemu and source code\n1. To update your Cemu local repository, use the command `git pull --recurse-submodules` (run this command on the Cemu root).\n    - This should update your local copy of Cemu and all of its dependencies.\n2. Then, you can rebuild Cemu using the steps listed above, according to whether you use Linux or Windows.\n\nIf CMake complains about Cemu already being compiled or another similar error, try deleting the `CMakeCache.txt` file inside the `build` folder and retry building.\n\n## CMake configure flags\nSome flags can be passed during CMake configure to customise which features are enabled on build.\n\nExample usage: `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DENABLE_SDL=ON -DENABLE_VULKAN=OFF`\n\n### All platforms\n| Flag               |   | Description                                                                 | Default | Note               |\n|--------------------|:--|-----------------------------------------------------------------------------|---------|--------------------|\n| ALLOW_PORTABLE     |   | Allow Cemu to use the `portable` directory to store configs and data        | ON      |                    |\n| CEMU_CXX_FLAGS     |   | Flags passed straight to the compiler, e.g. `-march=native`, `-Wall`, `/W3` | \"\"      |                    |\n| ENABLE_CUBEB       |   | Enable cubeb audio backend                                                  | ON      |                    |\n| ENABLE_DISCORD_RPC |   | Enable Discord Rich presence support                                        | ON      |                    |\n| ENABLE_OPENGL      |   | Enable OpenGL graphics backend                                              | ON      | Currently required |\n| ENABLE_HIDAPI      |   | Enable HIDAPI (used for Wiimote controller API)                             | ON      |                    |\n| ENABLE_SDL         |   | Enable SDLController controller API                                         | ON      | Currently required |\n| ENABLE_VCPKG       |   | Use VCPKG package manager to obtain dependencies                            | ON      |                    |\n| ENABLE_VULKAN      |   | Enable the Vulkan graphics backend                                          | ON      |                    |\n| ENABLE_WXWIDGETS   |   | Enable wxWidgets UI                                                         | ON      | Currently required |\n\n### Windows\n| Flag               | Description                       | Default | Note               |\n|--------------------|-----------------------------------|---------|--------------------|\n| ENABLE_DIRECTAUDIO | Enable DirectAudio audio backend  | ON      | Currently required |\n| ENABLE_DIRECTINPUT | Enable DirectInput controller API | ON      | Currently required |\n| ENABLE_XAUDIO      | Enable XAudio audio backend       | ON      |                    |\n| ENABLE_XINPUT      | Enable XInput controller API      | ON      |                    |\n\n### Linux\n| Flag                  | Description                                        | Default |\n|-----------------------|----------------------------------------------------|---------|\n| ENABLE_BLUEZ          | Build with Bluez (used for Wiimote controller API) | ON      |\n| ENABLE_FERAL_GAMEMODE | Enable Feral Interactive GameMode support          | ON      |\n| ENABLE_WAYLAND        | Enable Wayland support                             | ON      |\n\n### macOS\n| Flag         | Description                                    | Default |\n|--------------|------------------------------------------------|---------|\n| MACOS_BUNDLE | MacOS executable will be an application bundle | OFF     |\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.21.1)\n\noption(ENABLE_VCPKG \"Enable the vcpkg package manager\" ON)\noption(MACOS_BUNDLE \"The executable when built on macOS will be created as an application bundle\" OFF)\noption(ALLOW_PORTABLE \"Allow Cemu to be run in portable mode\" ON)\n\n# used by CI script to set version:\nset(EMULATOR_VERSION_MAJOR \"0\" CACHE STRING \"\")\nset(EMULATOR_VERSION_MINOR \"0\" CACHE STRING \"\")\nset(EMULATOR_VERSION_PATCH \"0\" CACHE STRING \"\")\n\nexecute_process(\n\t\tCOMMAND git log --format=%h -1\n\t\tWORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}\n\t\tOUTPUT_VARIABLE GIT_HASH\n\t\tOUTPUT_STRIP_TRAILING_WHITESPACE\n)\nadd_definitions(-DEMULATOR_HASH=${GIT_HASH})\n\nif (ENABLE_VCPKG)\n\t# check if vcpkg is shallow and unshallow it if necessary\n\texecute_process(\n\tCOMMAND git rev-parse --is-shallow-repository\n\tWORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/dependencies/vcpkg\n\tOUTPUT_VARIABLE is_vcpkg_shallow\n\tOUTPUT_STRIP_TRAILING_WHITESPACE\n    )\n\n\tif(is_vcpkg_shallow STREQUAL \"true\")\n\t\tmessage(STATUS \"vcpkg is shallow. Unshallowing it now...\")\n\t\texecute_process(\n\t\t\tCOMMAND git fetch --unshallow\n\t\t\tWORKING_DIRECTORY \"${CMAKE_SOURCE_DIR}/dependencies/vcpkg\"\n\t\t\tRESULT_VARIABLE result\n\t\t\tOUTPUT_VARIABLE output\n\t\t)\n\tendif()\n\n\tif(UNIX AND NOT APPLE)\n\t\tset(VCPKG_OVERLAY_PORTS \"${CMAKE_CURRENT_LIST_DIR}/dependencies/vcpkg_overlay_ports_linux;${CMAKE_CURRENT_LIST_DIR}/dependencies/vcpkg_overlay_ports\")\n\telseif(APPLE)\n\t\tset(VCPKG_OVERLAY_PORTS \"${CMAKE_CURRENT_LIST_DIR}/dependencies/vcpkg_overlay_ports_mac;${CMAKE_CURRENT_LIST_DIR}/dependencies/vcpkg_overlay_ports\")\n\telse()\n\t\tset(VCPKG_OVERLAY_PORTS \"${CMAKE_CURRENT_LIST_DIR}/dependencies/vcpkg_overlay_ports_win;${CMAKE_CURRENT_LIST_DIR}/dependencies/vcpkg_overlay_ports\")\n\tendif()\n\tset(CMAKE_TOOLCHAIN_FILE \"${CMAKE_CURRENT_SOURCE_DIR}/dependencies/vcpkg/scripts/buildsystems/vcpkg.cmake\"\n\t\tCACHE STRING \"Vcpkg toolchain file\")\n\t# Set this so that all the various find_package() calls don't need an explicit\n\t# CONFIG option\n\tset(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)\n\tif (WIN32)\n\t\tset(VCPKG_TARGET_TRIPLET \"x64-windows-static\" CACHE STRING \"\")\n\tendif()\nendif()\n\nproject(Cemu VERSION 2.0.0)\n\nlist(APPEND CMAKE_MODULE_PATH \"${PROJECT_SOURCE_DIR}/cmake\")\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\n\nset(CMAKE_EXPORT_COMPILE_COMMANDS ON)\n\nadd_compile_definitions($<$<CONFIG:Debug>:CEMU_DEBUG_ASSERT>) # if build type is debug, set CEMU_DEBUG_ASSERT\n\nadd_definitions(-DEMULATOR_VERSION_MAJOR=${EMULATOR_VERSION_MAJOR})\nadd_definitions(-DEMULATOR_VERSION_MINOR=${EMULATOR_VERSION_MINOR})\nadd_definitions(-DEMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH})\n\nset_property(GLOBAL PROPERTY USE_FOLDERS ON)\n\n# enable link time optimization for release builds\nset(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)\nset(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON)\n\nif (MSVC)\n\tset_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT CemuBin)\n\t# floating point model: precise, fiber safe optimizations\n\tadd_compile_options(/EHsc /fp:precise)\n\tif (CMAKE_CXX_COMPILER_ID STREQUAL \"Clang\")\n\t\t# Speeds up static linking (especially helpful in incremental compilation)\n\t\tif((CMAKE_LINKER MATCHES \".*lld-link.*\") AND (CMAKE_AR MATCHES \".*llvm-lib.*\"))\n\t\t\tset_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY STATIC_LIBRARY_OPTIONS /llvmlibthin)\n\t\tendif()\n  \telse()\n\t  add_compile_options(/GT)\n\tendif()\n\t# enable additional optimization flags for release builds\n\tadd_compile_options($<$<CONFIG:Release,RelWithDebInfo>:/Oi>) # enable intrinsic functions\n\tadd_compile_options($<$<CONFIG:Release,RelWithDebInfo>:/Ot>) # favor speed\nendif()\n\nif (APPLE)\n    enable_language(OBJC OBJCXX)\n    set(CMAKE_OSX_DEPLOYMENT_TARGET \"13.4\")\nendif()\n\nif (UNIX AND NOT APPLE)\n\toption(ENABLE_WAYLAND \"Build with Wayland support\" ON)\n\toption(ENABLE_FERAL_GAMEMODE \"Enables Feral Interactive GameMode Support\" ON)\n\toption(ENABLE_BLUEZ \"Build with Bluez support\" ON)\nendif()\n\nif (APPLE)\n    set(ENABLE_METAL_DEFAULT ON)\nelse()\n    set(ENABLE_METAL_DEFAULT OFF)\nendif()\n\noption(ENABLE_OPENGL \"Enables the OpenGL backend\" ON)\noption(ENABLE_VULKAN \"Enables the Vulkan backend\" ON)\noption(ENABLE_METAL \"Enables the Metal backend\" ${ENABLE_METAL_DEFAULT})\noption(ENABLE_DISCORD_RPC \"Enables the Discord Rich Presence feature\" ON)\n\nif (ENABLE_METAL AND NOT APPLE)\n    message(FATAL_ERROR \"Metal backend is only supported on Apple platforms\")\nendif()\n\n# input backends\nif (WIN32)\n\toption(ENABLE_XINPUT \"Enables the usage of XInput\" ON)\n\toption(ENABLE_DIRECTINPUT \"Enables the usage of DirectInput\" ON)\n\tadd_compile_definitions(HAS_DIRECTINPUT)\nendif()\n\noption(ENABLE_HIDAPI \"Build with HIDAPI\" ON)\noption(ENABLE_SDL \"Enables the SDLController backend\" ON)\n\n# audio backends\nif (WIN32)\n\toption(ENABLE_DIRECTAUDIO \"Enables the directaudio backend\" ON)\n\toption(ENABLE_XAUDIO \"Enables the xaudio backend\" ON)\nendif()\noption(ENABLE_CUBEB \"Enabled cubeb backend\" ON)\n\noption(ENABLE_WXWIDGETS \"Build with wxWidgets UI (Currently required)\" ON)\n\nset(THREADS_PREFER_PTHREAD_FLAG true)\nfind_package(Threads REQUIRED)\nfind_package(SDL2 REQUIRED)\nfind_package(CURL REQUIRED)\nfind_package(pugixml REQUIRED)\nfind_package(RapidJSON REQUIRED)\nfind_package(Boost COMPONENTS program_options filesystem nowide REQUIRED)\nfind_package(libzip REQUIRED)\nfind_package(glslang REQUIRED)\nfind_package(ZLIB REQUIRED)\nfind_package(zstd MODULE REQUIRED) # MODULE so that zstd::zstd is available\nfind_package(OpenSSL COMPONENTS Crypto SSL REQUIRED)\nfind_package(glm REQUIRED)\nfind_package(fmt 9 REQUIRED)\nfind_package(PNG REQUIRED)\n\n# glslang versions older than 11.11.0 define targets without a namespace\nif (NOT TARGET glslang::SPIRV AND TARGET SPIRV)\n\tadd_library(glslang::SPIRV ALIAS SPIRV)\nendif()\n\nif (UNIX AND NOT APPLE)\n\tfind_package(X11 REQUIRED)\n\tif (ENABLE_WAYLAND)\n\t\tfind_package(Wayland REQUIRED Client)\n\t\tfind_package(WaylandScanner REQUIRED)\n\t\tfind_package(WaylandProtocols 1.15 REQUIRED)\n\n\t\tecm_add_wayland_client_protocol(WAYLAND_PROTOCOL_SRCS\n\t\t\tPROTOCOL \"${WaylandProtocols_DATADIR}/stable/viewporter/viewporter.xml\"\n\t\t\tBASENAME viewporter)\n\t\tadd_library(CemuWaylandProtocols STATIC ${WAYLAND_PROTOCOL_SRCS})\n\t\ttarget_include_directories(CemuWaylandProtocols PUBLIC \"${CMAKE_CURRENT_BINARY_DIR}\")\n\t\ttarget_include_directories(CemuWaylandProtocols PRIVATE ${Wayland_INCLUDE_DIRS})\n\t\tadd_compile_definitions(HAS_WAYLAND)\n\tendif()\n\tfind_package(GTK3 REQUIRED)\n\n\tif(ENABLE_BLUEZ)\n\t\tfind_package(bluez REQUIRED)\n\t\tset(SUPPORTS_WIIMOTE ON)\n\t\tadd_compile_definitions(HAS_BLUEZ)\n\tendif()\n\nendif()\n\nif (ENABLE_VULKAN)\n\tinclude_directories(\"dependencies/Vulkan-Headers/include\")\nendif()\n\nif (ENABLE_OPENGL)\n\tfind_package(OpenGL REQUIRED)\nendif()\n\nif (ENABLE_METAL)\n    include_directories(${CMAKE_SOURCE_DIR}/dependencies/metal-cpp)\n\n    add_definitions(-DENABLE_METAL=1)\nendif()\n\nif (ENABLE_DISCORD_RPC)\n\tadd_compile_definitions(ENABLE_DISCORD_RPC)\nendif()\n\nif (ENABLE_HIDAPI)\n\tfind_package(hidapi REQUIRED)\n\tset(SUPPORTS_WIIMOTE ON)\n\tadd_compile_definitions(HAS_HIDAPI)\nendif ()\n\nif(UNIX AND NOT APPLE)\n\tif(ENABLE_FERAL_GAMEMODE)\n\t\tadd_compile_definitions(ENABLE_FERAL_GAMEMODE)\n\t\tadd_subdirectory(dependencies/gamemode EXCLUDE_FROM_ALL)\n\t\ttarget_include_directories(gamemode INTERFACE ./dependencies/gamemode/lib)\n\tendif()\nendif()\n\nif (ENABLE_WXWIDGETS)\n\tfind_package(wxWidgets 3.3 REQUIRED COMPONENTS base core gl propgrid xrc)\nendif()\n\nif (ENABLE_CUBEB)\n\tif (NOT ENABLE_VCPKG)\n\t    find_package(cubeb)\n\tendif()\n\tif (NOT cubeb_FOUND)\n\t\toption(BUILD_TESTS \"\" OFF)\n\t\toption(BUILD_TOOLS \"\" OFF)\n\t\toption(BUNDLE_SPEEX \"\" OFF)\n\t\tset(USE_WINMM OFF CACHE BOOL \"\")\n\t\tadd_subdirectory(\"dependencies/cubeb\" EXCLUDE_FROM_ALL SYSTEM)\n\t\tset_property(TARGET cubeb PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\t\tadd_library(cubeb::cubeb ALIAS cubeb)\n\tendif()\n\tadd_compile_definitions(\"HAS_CUBEB=1\")\nendif()\n\nadd_subdirectory(\"dependencies/ih264d\" EXCLUDE_FROM_ALL)\n\nif (CMAKE_OSX_ARCHITECTURES)\n\tset(CEMU_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES})\nelse()\n\tset(CEMU_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})\nendif()\nif(CEMU_ARCHITECTURE MATCHES \"(aarch64)|(AARCH64)|(arm64)|(ARM64)\")\n\tadd_subdirectory(\"dependencies/xbyak_aarch64\" EXCLUDE_FROM_ALL)\nendif()\n\nfind_package(ZArchive)\nif (NOT ZArchive_FOUND)\n\tadd_subdirectory(\"dependencies/ZArchive\" EXCLUDE_FROM_ALL)\nendif()\n\nadd_subdirectory(src)\n"
  },
  {
    "path": "CMakeSettings.json",
    "content": "﻿{\n  \"configurations\": [\n    {\n      \"name\": \"RelWithDebInfo\",\n      \"configurationType\": \"RelWithDebInfo\",\n      \"generator\": \"Ninja\",\n      \"inheritEnvironments\": [ \"msvc_x64_x64\" ],\n      \"buildRoot\": \"${projectDir}\\\\out\\\\build\\\\${name}\",\n      \"installRoot\": \"${projectDir}\\\\out\\\\install\\\\${name}\"\n    },\n    {\n      \"name\": \"Release\",\n      \"configurationType\": \"Release\",\n      \"generator\": \"Ninja\",\n      \"inheritEnvironments\": [ \"msvc_x64_x64\" ],\n      \"buildRoot\": \"${projectDir}\\\\out\\\\build\\\\${name}\",\n      \"installRoot\": \"${projectDir}\\\\out\\\\install\\\\${name}\"\n    },\n    {\n      \"name\": \"Debug\",\n      \"configurationType\": \"Debug\",\n      \"generator\": \"Ninja\",\n      \"inheritEnvironments\": [ \"msvc_x64_x64\" ],\n      \"buildRoot\": \"${projectDir}\\\\out\\\\build\\\\${name}\",\n      \"installRoot\": \"${projectDir}\\\\out\\\\install\\\\${name}\"\n    }\n  ]\n}"
  },
  {
    "path": "CODING_STYLE.md",
    "content": "\n# Coding style guidelines for Cemu\n\nThis document describes the latest version of our coding-style guidelines. Since we did not use this style from the beginning, older code may not adhere to these guidelines. Nevertheless, use these rules even if the surrounding code does not match. \n\nCemu comes with a `.clang-format` file which is supported by most IDEs for formatting. Avoid auto-reformatting whole files, PRs with a lot of formatting changes are difficult to review.\n\n## Names for variables, functions and classes\n\n- Always prefix class member variables with `m_`\n- Always prefix static class variables with `s_`\n- For variable names: Camel case, starting with a lower case letter after the prefix. Examples: `m_option`, `s_audioVolume`\n- For functions/class names: Use camel case starting with a capital letter. Examples: `MyClass`, `SetActive`\n- Avoid underscores in variable names after the prefix. Use `m_myVariable` instead of `m_my_variable`\n\n## About types\n\nCemu provides its own set of basic fixed-width types. They are:\n`uint8`, `sint8`, `uint16`, `sint16`, `uint32`, `sint32`, `uint64`, `sint64`. Always use these types over something like `uint32_t`. Using `size_t` is also acceptable where suitable. Avoid C types like `int` or `long`. The only exception is when interacting with external libraries which expect these types as parameters.\n\n## When and where to put brackets\n\nAlways put curly-brackets (`{ }`) on their own line. Example:\n\n```\nvoid FooBar()\n{\n   if (m_hasFoo)\n   {\n       ...\n   }\n}\n```\nAs an exception, you can put short lambdas onto the same line:\n```\nSomeFunc([]() { .... });\n```\nYou can skip brackets for single-statement `if`. Example:\n```\nif (cond)\n    action();\n```\n\n## Printing\n\nAvoid sprintf and similar C-style formatting API. Use `fmt::format()`.  \nIn UI related code you can use `formatWxString`, but be aware that number formatting with this function will be locale dependent!\n\n## Strings and encoding\n\nWe use UTF-8 encoded `std::string` where possible. Some conversions need special handling and we have helper functions for those:\n```cpp\n// std::filesystem::path <-> std::string (in precompiled.h)\nstd::string _pathToUtf8(const fs::path& path);\nfs::path _utf8ToPath(std::string_view input);\n\n// wxString <-> std::string\nwxString wxString::FromUTF8(const std::string& s)\nstd::string wxString::utf8_string();\n\n```\n\n## Logging\n\nIf you want to write to log.txt use `cemuLog_log()`. The log type parameter should be mostly self-explanatory. Use `LogType::Force` if you always want to log something. For example:  \n`cemuLog_log(LogType::Force, \"The value is {}\", 123);`\n\n## HLE and endianness\n\nA pretty large part of Cemu's code base are re-implementations of various Cafe OS modules (e.g. `coreinit.rpl`, `gx2.rpl`...). These generally run in the context of the emulated process, thus special care has to be taken to use types with the correct size and endianness when interacting with memory.\n\nKeep in mind that the emulated Espresso CPU is 32bit big-endian, while the host architectures targeted by Cemu are 64bit little-endian! \n\nTo keep code simple and remove the need for manual endian-swapping, Cemu has templates and aliases of the basic types with explicit endian-ness.\nFor big-endian types add the suffix `be`. Example: `uint32be`\n\nWhen you need to store a pointer in the guest's memory. Use `MEMPTR<T>`. It will automatically store any pointer as 32bit big-endian. The pointer you store must point to memory that is within the guest address space.\n\n## HLE interfaces\n\nThe implementation for each HLE module is inside a namespace with a matching name. E.g. `coreinit.rpl` functions go into `coreinit` namespace.\n\nTo expose a new function as callable from within the emulated machine, use `cafeExportRegister` or `cafeExportRegisterFunc`. Here is a short example:\n```cpp\nnamespace coreinit\n{\n\tuint32 OSGetCoreCount()\n\t{\n\t\treturn Espresso::CORE_COUNT;\n\t}\n\t\n\tvoid Init()\n\t{\n\t\tcafeExportRegister(\"coreinit\", OSGetCoreCount, LogType::CoreinitThread);\n\t}\n}\n```\nYou may also see some code which uses `osLib_addFunction` directly. This is a deprecated way of registering functions.\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Mozilla Public License Version 2.0\n==================================\n\n1. Definitions\n--------------\n\n1.1. \"Contributor\"\n    means each individual or legal entity that creates, contributes to\n    the creation of, or owns Covered Software.\n\n1.2. \"Contributor Version\"\n    means the combination of the Contributions of others (if any) used\n    by a Contributor and that particular Contributor's Contribution.\n\n1.3. \"Contribution\"\n    means Covered Software of a particular Contributor.\n\n1.4. \"Covered Software\"\n    means Source Code Form to which the initial Contributor has attached\n    the notice in Exhibit A, the Executable Form of such Source Code\n    Form, and Modifications of such Source Code Form, in each case\n    including portions thereof.\n\n1.5. \"Incompatible With Secondary Licenses\"\n    means\n\n    (a) that the initial Contributor has attached the notice described\n        in Exhibit B to the Covered Software; or\n\n    (b) that the Covered Software was made available under the terms of\n        version 1.1 or earlier of the License, but not also under the\n        terms of a Secondary License.\n\n1.6. \"Executable Form\"\n    means any form of the work other than Source Code Form.\n\n1.7. \"Larger Work\"\n    means a work that combines Covered Software with other material, in\n    a separate file or files, that is not Covered Software.\n\n1.8. \"License\"\n    means this document.\n\n1.9. \"Licensable\"\n    means having the right to grant, to the maximum extent possible,\n    whether at the time of the initial grant or subsequently, any and\n    all of the rights conveyed by this License.\n\n1.10. \"Modifications\"\n    means any of the following:\n\n    (a) any file in Source Code Form that results from an addition to,\n        deletion from, or modification of the contents of Covered\n        Software; or\n\n    (b) any new file in Source Code Form that contains any Covered\n        Software.\n\n1.11. \"Patent Claims\" of a Contributor\n    means any patent claim(s), including without limitation, method,\n    process, and apparatus claims, in any patent Licensable by such\n    Contributor that would be infringed, but for the grant of the\n    License, by the making, using, selling, offering for sale, having\n    made, import, or transfer of either its Contributions or its\n    Contributor Version.\n\n1.12. \"Secondary License\"\n    means either the GNU General Public License, Version 2.0, the GNU\n    Lesser General Public License, Version 2.1, the GNU Affero General\n    Public License, Version 3.0, or any later versions of those\n    licenses.\n\n1.13. \"Source Code Form\"\n    means the form of the work preferred for making modifications.\n\n1.14. \"You\" (or \"Your\")\n    means an individual or a legal entity exercising rights under this\n    License. For legal entities, \"You\" includes any entity that\n    controls, is controlled by, or is under common control with You. For\n    purposes of this definition, \"control\" means (a) the power, direct\n    or indirect, to cause the direction or management of such entity,\n    whether by contract or otherwise, or (b) ownership of more than\n    fifty percent (50%) of the outstanding shares or beneficial\n    ownership of such entity.\n\n2. License Grants and Conditions\n--------------------------------\n\n2.1. Grants\n\nEach Contributor hereby grants You a world-wide, royalty-free,\nnon-exclusive license:\n\n(a) under intellectual property rights (other than patent or trademark)\n    Licensable by such Contributor to use, reproduce, make available,\n    modify, display, perform, distribute, and otherwise exploit its\n    Contributions, either on an unmodified basis, with Modifications, or\n    as part of a Larger Work; and\n\n(b) under Patent Claims of such Contributor to make, use, sell, offer\n    for sale, have made, import, and otherwise transfer either its\n    Contributions or its Contributor Version.\n\n2.2. Effective Date\n\nThe licenses granted in Section 2.1 with respect to any Contribution\nbecome effective for each Contribution on the date the Contributor first\ndistributes such Contribution.\n\n2.3. Limitations on Grant Scope\n\nThe licenses granted in this Section 2 are the only rights granted under\nthis License. No additional rights or licenses will be implied from the\ndistribution or licensing of Covered Software under this License.\nNotwithstanding Section 2.1(b) above, no patent license is granted by a\nContributor:\n\n(a) for any code that a Contributor has removed from Covered Software;\n    or\n\n(b) for infringements caused by: (i) Your and any other third party's\n    modifications of Covered Software, or (ii) the combination of its\n    Contributions with other software (except as part of its Contributor\n    Version); or\n\n(c) under Patent Claims infringed by Covered Software in the absence of\n    its Contributions.\n\nThis License does not grant any rights in the trademarks, service marks,\nor logos of any Contributor (except as may be necessary to comply with\nthe notice requirements in Section 3.4).\n\n2.4. Subsequent Licenses\n\nNo Contributor makes additional grants as a result of Your choice to\ndistribute the Covered Software under a subsequent version of this\nLicense (see Section 10.2) or under the terms of a Secondary License (if\npermitted under the terms of Section 3.3).\n\n2.5. Representation\n\nEach Contributor represents that the Contributor believes its\nContributions are its original creation(s) or it has sufficient rights\nto grant the rights to its Contributions conveyed by this License.\n\n2.6. Fair Use\n\nThis License is not intended to limit any rights You have under\napplicable copyright doctrines of fair use, fair dealing, or other\nequivalents.\n\n2.7. Conditions\n\nSections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted\nin Section 2.1.\n\n3. Responsibilities\n-------------------\n\n3.1. Distribution of Source Form\n\nAll distribution of Covered Software in Source Code Form, including any\nModifications that You create or to which You contribute, must be under\nthe terms of this License. You must inform recipients that the Source\nCode Form of the Covered Software is governed by the terms of this\nLicense, and how they can obtain a copy of this License. You may not\nattempt to alter or restrict the recipients' rights in the Source Code\nForm.\n\n3.2. Distribution of Executable Form\n\nIf You distribute Covered Software in Executable Form then:\n\n(a) such Covered Software must also be made available in Source Code\n    Form, as described in Section 3.1, and You must inform recipients of\n    the Executable Form how they can obtain a copy of such Source Code\n    Form by reasonable means in a timely manner, at a charge no more\n    than the cost of distribution to the recipient; and\n\n(b) You may distribute such Executable Form under the terms of this\n    License, or sublicense it under different terms, provided that the\n    license for the Executable Form does not attempt to limit or alter\n    the recipients' rights in the Source Code Form under this License.\n\n3.3. Distribution of a Larger Work\n\nYou may create and distribute a Larger Work under terms of Your choice,\nprovided that You also comply with the requirements of this License for\nthe Covered Software. If the Larger Work is a combination of Covered\nSoftware with a work governed by one or more Secondary Licenses, and the\nCovered Software is not Incompatible With Secondary Licenses, this\nLicense permits You to additionally distribute such Covered Software\nunder the terms of such Secondary License(s), so that the recipient of\nthe Larger Work may, at their option, further distribute the Covered\nSoftware under the terms of either this License or such Secondary\nLicense(s).\n\n3.4. Notices\n\nYou may not remove or alter the substance of any license notices\n(including copyright notices, patent notices, disclaimers of warranty,\nor limitations of liability) contained within the Source Code Form of\nthe Covered Software, except that You may alter any license notices to\nthe extent required to remedy known factual inaccuracies.\n\n3.5. Application of Additional Terms\n\nYou may choose to offer, and to charge a fee for, warranty, support,\nindemnity or liability obligations to one or more recipients of Covered\nSoftware. However, You may do so only on Your own behalf, and not on\nbehalf of any Contributor. You must make it absolutely clear that any\nsuch warranty, support, indemnity, or liability obligation is offered by\nYou alone, and You hereby agree to indemnify every Contributor for any\nliability incurred by such Contributor as a result of warranty, support,\nindemnity or liability terms You offer. You may include additional\ndisclaimers of warranty and limitations of liability specific to any\njurisdiction.\n\n4. Inability to Comply Due to Statute or Regulation\n---------------------------------------------------\n\nIf it is impossible for You to comply with any of the terms of this\nLicense with respect to some or all of the Covered Software due to\nstatute, judicial order, or regulation then You must: (a) comply with\nthe terms of this License to the maximum extent possible; and (b)\ndescribe the limitations and the code they affect. Such description must\nbe placed in a text file included with all distributions of the Covered\nSoftware under this License. Except to the extent prohibited by statute\nor regulation, such description must be sufficiently detailed for a\nrecipient of ordinary skill to be able to understand it.\n\n5. Termination\n--------------\n\n5.1. The rights granted under this License will terminate automatically\nif You fail to comply with any of its terms. However, if You become\ncompliant, then the rights granted under this License from a particular\nContributor are reinstated (a) provisionally, unless and until such\nContributor explicitly and finally terminates Your grants, and (b) on an\nongoing basis, if such Contributor fails to notify You of the\nnon-compliance by some reasonable means prior to 60 days after You have\ncome back into compliance. Moreover, Your grants from a particular\nContributor are reinstated on an ongoing basis if such Contributor\nnotifies You of the non-compliance by some reasonable means, this is the\nfirst time You have received notice of non-compliance with this License\nfrom such Contributor, and You become compliant prior to 30 days after\nYour receipt of the notice.\n\n5.2. If You initiate litigation against any entity by asserting a patent\ninfringement claim (excluding declaratory judgment actions,\ncounter-claims, and cross-claims) alleging that a Contributor Version\ndirectly or indirectly infringes any patent, then the rights granted to\nYou by any and all Contributors for the Covered Software under Section\n2.1 of this License shall terminate.\n\n5.3. In the event of termination under Sections 5.1 or 5.2 above, all\nend user license agreements (excluding distributors and resellers) which\nhave been validly granted by You or Your distributors under this License\nprior to termination shall survive termination.\n\n************************************************************************\n*                                                                      *\n*  6. Disclaimer of Warranty                                           *\n*  -------------------------                                           *\n*                                                                      *\n*  Covered Software is provided under this License on an \"as is\"       *\n*  basis, without warranty of any kind, either expressed, implied, or  *\n*  statutory, including, without limitation, warranties that the       *\n*  Covered Software is free of defects, merchantable, fit for a        *\n*  particular purpose or non-infringing. The entire risk as to the     *\n*  quality and performance of the Covered Software is with You.        *\n*  Should any Covered Software prove defective in any respect, You     *\n*  (not any Contributor) assume the cost of any necessary servicing,   *\n*  repair, or correction. This disclaimer of warranty constitutes an   *\n*  essential part of this License. No use of any Covered Software is   *\n*  authorized under this License except under this disclaimer.         *\n*                                                                      *\n************************************************************************\n\n************************************************************************\n*                                                                      *\n*  7. Limitation of Liability                                          *\n*  --------------------------                                          *\n*                                                                      *\n*  Under no circumstances and under no legal theory, whether tort      *\n*  (including negligence), contract, or otherwise, shall any           *\n*  Contributor, or anyone who distributes Covered Software as          *\n*  permitted above, be liable to You for any direct, indirect,         *\n*  special, incidental, or consequential damages of any character      *\n*  including, without limitation, damages for lost profits, loss of    *\n*  goodwill, work stoppage, computer failure or malfunction, or any    *\n*  and all other commercial damages or losses, even if such party      *\n*  shall have been informed of the possibility of such damages. This   *\n*  limitation of liability shall not apply to liability for death or   *\n*  personal injury resulting from such party's negligence to the       *\n*  extent applicable law prohibits such limitation. Some               *\n*  jurisdictions do not allow the exclusion or limitation of           *\n*  incidental or consequential damages, so this exclusion and          *\n*  limitation may not apply to You.                                    *\n*                                                                      *\n************************************************************************\n\n8. Litigation\n-------------\n\nAny litigation relating to this License may be brought only in the\ncourts of a jurisdiction where the defendant maintains its principal\nplace of business and such litigation shall be governed by laws of that\njurisdiction, without reference to its conflict-of-law provisions.\nNothing in this Section shall prevent a party's ability to bring\ncross-claims or counter-claims.\n\n9. Miscellaneous\n----------------\n\nThis License represents the complete agreement concerning the subject\nmatter hereof. If any provision of this License is held to be\nunenforceable, such provision shall be reformed only to the extent\nnecessary to make it enforceable. Any law or regulation which provides\nthat the language of a contract shall be construed against the drafter\nshall not be used to construe this License against a Contributor.\n\n10. Versions of the License\n---------------------------\n\n10.1. New Versions\n\nMozilla Foundation is the license steward. Except as provided in Section\n10.3, no one other than the license steward has the right to modify or\npublish new versions of this License. Each version will be given a\ndistinguishing version number.\n\n10.2. Effect of New Versions\n\nYou may distribute the Covered Software under the terms of the version\nof the License under which You originally received the Covered Software,\nor under the terms of any subsequent version published by the license\nsteward.\n\n10.3. Modified Versions\n\nIf you create software not governed by this License, and you want to\ncreate a new license for such software, you may create and use a\nmodified version of this License if you rename the license and remove\nany references to the name of the license steward (except to note that\nsuch modified license differs from this License).\n\n10.4. Distributing Source Code Form that is Incompatible With Secondary\nLicenses\n\nIf You choose to distribute Source Code Form that is Incompatible With\nSecondary Licenses under the terms of this version of the License, the\nnotice described in Exhibit B of this License must be attached.\n\nExhibit A - Source Code Form License Notice\n-------------------------------------------\n\n  This Source Code Form is subject to the terms of the Mozilla Public\n  License, v. 2.0. If a copy of the MPL was not distributed with this\n  file, You can obtain one at http://mozilla.org/MPL/2.0/.\n\nIf it is not possible or desirable to put the notice in a particular\nfile, then You may include the notice in a location (such as a LICENSE\nfile in a relevant directory) where a recipient would be likely to look\nfor such a notice.\n\nYou may add additional accurate notices of copyright ownership.\n\nExhibit B - \"Incompatible With Secondary Licenses\" Notice\n---------------------------------------------------------\n\n  This Source Code Form is \"Incompatible With Secondary Licenses\", as\n  defined by the Mozilla Public License, v. 2.0.\n"
  },
  {
    "path": "README.md",
    "content": "# **Cemu - Wii U emulator**\n\n[![Build Process](https://github.com/cemu-project/Cemu/actions/workflows/build.yml/badge.svg)](https://github.com/cemu-project/Cemu/actions/workflows/build.yml)\n[![Discord](https://img.shields.io/discord/286429969104764928?label=Cemu&logo=discord&logoColor=FFFFFF)](https://discord.gg/5psYsup)\n[![Matrix Server](https://img.shields.io/matrix/cemu:cemu.info?server_fqdn=matrix.cemu.info&label=cemu:cemu.info&logo=matrix&logoColor=FFFFFF)](https://matrix.to/#/#cemu:cemu.info)\n\nThis is the code repository of Cemu, a Wii U emulator that is able to run most Wii U games and homebrew in a playable state.\nIt's written in C/C++ and is being actively developed with new features and fixes.\n\nCemu is currently only available for 64-bit Windows, Linux & macOS devices.\n\n### Links:\n - [Open Source Announcement](https://www.reddit.com/r/cemu/comments/wwa22c/cemu_20_announcement_linux_builds_opensource_and/)\n - [Official Website](https://cemu.info)\n - [Compatibility List/Wiki](https://wiki.cemu.info/wiki/Main_Page)\n - [Official Subreddit](https://reddit.com/r/Cemu)\n - [Official Discord](https://discord.gg/5psYsup)\n - [Official Matrix Server](https://matrix.to/#/#cemu:cemu.info)\n - [Setup Guide](https://cemu.cfw.guide)\n\n#### Other relevant repositories:\n - [Cemu-Language](https://github.com/cemu-project/Cemu-Language)\n - [Cemu's Community Graphic Packs](https://github.com/cemu-project/cemu_graphic_packs)\n\n## Download\n\nYou can download the latest Cemu releases for Windows, Linux and Mac from the [GitHub Releases](https://github.com/cemu-project/Cemu/releases/). For Linux you can also find Cemu on [flathub](https://flathub.org/apps/info.cemu.Cemu).\n\nOn Windows, Cemu is available both as an installer and in a portable format, where no installation is required besides extracting it in a safe place.\n\nThe native macOS build is currently purely experimental and should not be considered stable or ready for issue-free gameplay. There are also known issues with degraded performance due to the use of MoltenVK and Rosetta for ARM Macs. We appreciate your patience while we improve Cemu for macOS.\n\nPre-2.0 releases can be found on Cemu's [changelog page](https://cemu.info/changelog.html).\n\n## Build Instructions\n\nTo compile Cemu yourself on Windows, Linux or macOS, view [BUILD.md](/BUILD.md).\n\n## Issues\n\nIssues with the emulator should be filed using [GitHub Issues](https://github.com/cemu-project/Cemu/issues).  \nThe old bug tracker can be found at [bugs.cemu.info](https://bugs.cemu.info) and still contains relevant issues and feature suggestions.\n\n## Contributing\n\nPull requests are very welcome. For easier coordination you can visit the developer discussion channel on [Discord](https://discord.gg/5psYsup) or alternatively the [Matrix Server](https://matrix.to/#/#cemu:cemu.info).\nBefore submitting a pull request, please read and follow our code style guidelines listed in [CODING_STYLE.md](/CODING_STYLE.md).\n\nIf coding isn't your thing, testing games and making detailed bug reports or updating the (usually outdated) compatibility wiki is also appreciated!\n\nQuestions about Cemu's software architecture can also be answered on Discord (or through the Matrix bridge).\n\n## License\nCemu is licensed under [Mozilla Public License 2.0](/LICENSE.txt). Exempt from this are all files in the dependencies directory for which the licenses of the original code apply as well as some individual files in the src folder, as specified in those file headers respectively.\n"
  },
  {
    "path": "boost.natvis",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n\n    <Type Name=\"boost::container::small_vector&lt;*&gt;\">\n        <Expand>\n            <Item Name=\"[size]\">m_holder.m_size</Item>\n            <ArrayItems>\n                <Size>m_holder.m_size</Size>\n                <ValuePointer>m_holder.m_start</ValuePointer>\n            </ArrayItems>\n        </Expand>\n    </Type>\n\n\t<Type Name=\"boost::container::static_vector&lt;*&gt;\">\n\t<DisplayString>{{ size={m_holder.m_size} }}</DisplayString>\n\t<Expand>\n\t  <Item Name=\"[size]\" ExcludeView=\"simple\">m_holder.m_size</Item>\n\t  <Item Name=\"[capacity]\" ExcludeView=\"simple\">static_capacity</Item>\n\t  <ArrayItems>\n\t\t<Size>m_holder.m_size</Size>\n\t\t<ValuePointer>($T1*)m_holder.storage.data</ValuePointer>\n\t  </ArrayItems>\n\t</Expand>\n\t</Type>\n\n</AutoVisualizer>\n"
  },
  {
    "path": "cmake/ECMFindModuleHelpers.cmake",
    "content": "# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>\n#\n# SPDX-License-Identifier: BSD-3-Clause\n\n#[=======================================================================[.rst:\nECMFindModuleHelpers\n--------------------\n\nHelper macros for find modules: ``ecm_find_package_version_check()``,\n``ecm_find_package_parse_components()`` and\n``ecm_find_package_handle_library_components()``.\n\n::\n\n  ecm_find_package_version_check(<name>)\n\nPrints warnings if the CMake version or the project's required CMake version\nis older than that required by extra-cmake-modules.\n\n::\n\n  ecm_find_package_parse_components(<name>\n      RESULT_VAR <variable>\n      KNOWN_COMPONENTS <component1> [<component2> [...]]\n      [SKIP_DEPENDENCY_HANDLING])\n\nThis macro will populate <variable> with a list of components found in\n<name>_FIND_COMPONENTS, after checking that all those components are in the\nlist of ``KNOWN_COMPONENTS``; if there are any unknown components, it will print\nan error or warning (depending on the value of <name>_FIND_REQUIRED) and call\n``return()``.\n\nThe order of components in <variable> is guaranteed to match the order they\nare listed in the ``KNOWN_COMPONENTS`` argument.\n\nIf ``SKIP_DEPENDENCY_HANDLING`` is not set, for each component the variable\n<name>_<component>_component_deps will be checked for dependent components.\nIf <component> is listed in <name>_FIND_COMPONENTS, then all its (transitive)\ndependencies will also be added to <variable>.\n\n::\n\n  ecm_find_package_handle_library_components(<name>\n      COMPONENTS <component> [<component> [...]]\n      [SKIP_DEPENDENCY_HANDLING])\n      [SKIP_PKG_CONFIG])\n\nCreates an imported library target for each component.  The operation of this\nmacro depends on the presence of a number of CMake variables.\n\nThe <name>_<component>_lib variable should contain the name of this library,\nand <name>_<component>_header variable should contain the name of a header\nfile associated with it (whatever relative path is normally passed to\n'#include'). <name>_<component>_header_subdir variable can be used to specify\nwhich subdirectory of the include path the headers will be found in.\n``ecm_find_package_components()`` will then search for the library\nand include directory (creating appropriate cache variables) and create an\nimported library target named <name>::<component>.\n\nAdditional variables can be used to provide additional information:\n\nIf ``SKIP_PKG_CONFIG``, the <name>_<component>_pkg_config variable is set, and\npkg-config is found, the pkg-config module given by\n<name>_<component>_pkg_config will be searched for and used to help locate the\nlibrary and header file.  It will also be used to set\n<name>_<component>_VERSION.\n\nNote that if version information is found via pkg-config,\n<name>_<component>_FIND_VERSION can be set to require a particular version\nfor each component.\n\nIf ``SKIP_DEPENDENCY_HANDLING`` is not set, the ``INTERFACE_LINK_LIBRARIES`` property\nof the imported target for <component> will be set to contain the imported\ntargets for the components listed in <name>_<component>_component_deps.\n<component>_FOUND will also be set to ``FALSE`` if any of the components in\n<name>_<component>_component_deps are not found.  This requires the components\nin <name>_<component>_component_deps to be listed before <component> in the\n``COMPONENTS`` argument.\n\nThe following variables will be set:\n\n``<name>_TARGETS``\n  the imported targets\n``<name>_LIBRARIES``\n  the found libraries\n``<name>_INCLUDE_DIRS``\n  the combined required include directories for the components\n``<name>_DEFINITIONS``\n  the \"other\" CFLAGS provided by pkg-config, if any\n``<name>_VERSION``\n  the value of ``<name>_<component>_VERSION`` for the first component that\n  has this variable set (note that components are searched for in the order\n  they are passed to the macro), although if it is already set, it will not\n  be altered\n\n.. note::\n  These variables are never cleared, so if\n  ``ecm_find_package_handle_library_components()`` is called multiple times with\n  different components (typically because of multiple ``find_package()`` calls) then\n  ``<name>_TARGETS``, for example, will contain all the targets found in any\n  call (although no duplicates).\n\nSince pre-1.0.0.\n#]=======================================================================]\n\ninclude(CMakeParseArguments)\n\nmacro(ecm_find_package_version_check module_name)\n    if(CMAKE_VERSION VERSION_LESS 3.16.0)\n        message(FATAL_ERROR \"CMake 3.16.0 is required by Find${module_name}.cmake\")\n    endif()\n    if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 3.16.0)\n        message(AUTHOR_WARNING \"Your project should require at least CMake 3.16.0 to use Find${module_name}.cmake\")\n    endif()\nendmacro()\n\nmacro(ecm_find_package_parse_components module_name)\n    set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING)\n    set(ecm_fppc_oneValueArgs RESULT_VAR)\n    set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS)\n    cmake_parse_arguments(ECM_FPPC \"${ecm_fppc_options}\" \"${ecm_fppc_oneValueArgs}\" \"${ecm_fppc_multiValueArgs}\" ${ARGN})\n\n    if(ECM_FPPC_UNPARSED_ARGUMENTS)\n        message(FATAL_ERROR \"Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}\")\n    endif()\n    if(NOT ECM_FPPC_RESULT_VAR)\n        message(FATAL_ERROR \"Missing RESULT_VAR argument to ecm_find_package_parse_components\")\n    endif()\n    if(NOT ECM_FPPC_KNOWN_COMPONENTS)\n        message(FATAL_ERROR \"Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components\")\n    endif()\n    if(NOT ECM_FPPC_DEFAULT_COMPONENTS)\n        set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS})\n    endif()\n\n    if(${module_name}_FIND_COMPONENTS)\n        set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS})\n\n        if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING)\n            # Make sure deps are included\n            foreach(ecm_fppc_comp ${ecm_fppc_requestedComps})\n                foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps})\n                    list(FIND ecm_fppc_requestedComps \"${ecm_fppc_dep_comp}\" ecm_fppc_index)\n                    if(\"${ecm_fppc_index}\" STREQUAL \"-1\")\n                        if(NOT ${module_name}_FIND_QUIETLY)\n                            message(STATUS \"${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}\")\n                        endif()\n                        list(APPEND ecm_fppc_requestedComps \"${ecm_fppc_dep_comp}\")\n                    endif()\n                endforeach()\n            endforeach()\n        else()\n            message(STATUS \"Skipping dependency handling for ${module_name}\")\n        endif()\n        list(REMOVE_DUPLICATES ecm_fppc_requestedComps)\n\n        # This makes sure components are listed in the same order as\n        # KNOWN_COMPONENTS (potentially important for inter-dependencies)\n        set(${ECM_FPPC_RESULT_VAR})\n        foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS})\n            list(FIND ecm_fppc_requestedComps \"${ecm_fppc_comp}\" ecm_fppc_index)\n            if(NOT \"${ecm_fppc_index}\" STREQUAL \"-1\")\n                list(APPEND ${ECM_FPPC_RESULT_VAR} \"${ecm_fppc_comp}\")\n                list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index})\n            endif()\n        endforeach()\n        # if there are any left, they are unknown components\n        if(ecm_fppc_requestedComps)\n            set(ecm_fppc_msgType STATUS)\n            if(${module_name}_FIND_REQUIRED)\n                set(ecm_fppc_msgType FATAL_ERROR)\n            endif()\n            if(NOT ${module_name}_FIND_QUIETLY)\n                message(${ecm_fppc_msgType} \"${module_name}: requested unknown components ${ecm_fppc_requestedComps}\")\n            endif()\n            return()\n        endif()\n    else()\n        set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS})\n    endif()\nendmacro()\n\nmacro(ecm_find_package_handle_library_components module_name)\n    set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING)\n    set(ecm_fpwc_oneValueArgs)\n    set(ecm_fpwc_multiValueArgs COMPONENTS)\n    cmake_parse_arguments(ECM_FPWC \"${ecm_fpwc_options}\" \"${ecm_fpwc_oneValueArgs}\" \"${ecm_fpwc_multiValueArgs}\" ${ARGN})\n\n    if(ECM_FPWC_UNPARSED_ARGUMENTS)\n        message(FATAL_ERROR \"Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}\")\n    endif()\n    if(NOT ECM_FPWC_COMPONENTS)\n        message(FATAL_ERROR \"Missing COMPONENTS argument to ecm_find_package_handle_components\")\n    endif()\n\n    include(FindPackageHandleStandardArgs)\n    find_package(PkgConfig QUIET)\n    foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS})\n        set(ecm_fpwc_dep_vars)\n        set(ecm_fpwc_dep_targets)\n        if(NOT SKIP_DEPENDENCY_HANDLING)\n            foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps})\n                list(APPEND ecm_fpwc_dep_vars \"${module_name}_${ecm_fpwc_dep}_FOUND\")\n                list(APPEND ecm_fpwc_dep_targets \"${module_name}::${ecm_fpwc_dep}\")\n            endforeach()\n        endif()\n\n        if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config)\n            pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET\n                              ${${module_name}_${ecm_fpwc_comp}_pkg_config})\n        endif()\n\n        find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR\n            NAMES ${${module_name}_${ecm_fpwc_comp}_header}\n            HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS}\n            PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir}\n        )\n        find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY\n            NAMES ${${module_name}_${ecm_fpwc_comp}_lib}\n            HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS}\n        )\n\n        set(${module_name}_${ecm_fpwc_comp}_VERSION \"${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}\")\n        if(NOT ${module_name}_VERSION)\n            set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION})\n        endif()\n\n        set(FPHSA_NAME_MISMATCHED 1)\n        find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp}\n            FOUND_VAR\n                ${module_name}_${ecm_fpwc_comp}_FOUND\n            REQUIRED_VARS\n                ${module_name}_${ecm_fpwc_comp}_LIBRARY\n                ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR\n                ${ecm_fpwc_dep_vars}\n            VERSION_VAR\n                ${module_name}_${ecm_fpwc_comp}_VERSION\n            )\n        unset(FPHSA_NAME_MISMATCHED)\n\n        mark_as_advanced(\n            ${module_name}_${ecm_fpwc_comp}_LIBRARY\n            ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR\n        )\n\n        if(${module_name}_${ecm_fpwc_comp}_FOUND)\n            list(APPEND ${module_name}_LIBRARIES\n                        \"${${module_name}_${ecm_fpwc_comp}_LIBRARY}\")\n            list(APPEND ${module_name}_INCLUDE_DIRS\n                        \"${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}\")\n            set(${module_name}_DEFINITIONS\n                    ${${module_name}_DEFINITIONS}\n                    ${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS})\n            if(NOT TARGET ${module_name}::${ecm_fpwc_comp})\n                add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED)\n                set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES\n                    IMPORTED_LOCATION \"${${module_name}_${ecm_fpwc_comp}_LIBRARY}\"\n                    INTERFACE_COMPILE_OPTIONS \"${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}\"\n                    INTERFACE_INCLUDE_DIRECTORIES \"${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}\"\n                    INTERFACE_LINK_LIBRARIES \"${ecm_fpwc_dep_targets}\"\n                )\n            endif()\n            list(APPEND ${module_name}_TARGETS\n                        \"${module_name}::${ecm_fpwc_comp}\")\n        endif()\n    endforeach()\n    if(${module_name}_LIBRARIES)\n        list(REMOVE_DUPLICATES ${module_name}_LIBRARIES)\n    endif()\n    if(${module_name}_INCLUDE_DIRS)\n        list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS)\n    endif()\n    if(${module_name}_DEFINITIONS)\n        list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS)\n    endif()\n    if(${module_name}_TARGETS)\n        list(REMOVE_DUPLICATES ${module_name}_TARGETS)\n    endif()\nendmacro()\n"
  },
  {
    "path": "cmake/ECMFindModuleHelpersStub.cmake",
    "content": "include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpers.cmake)\n"
  },
  {
    "path": "cmake/FindGTK3.cmake",
    "content": "# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>\n# SPDX-License-Identifier: ISC\n\ninclude(FindPackageHandleStandardArgs)\n\nfind_package(PkgConfig)\nif (PKG_CONFIG_FOUND)\n    pkg_search_module(GTK3 IMPORTED_TARGET gtk+-3.0)\n    if (GTK3_FOUND)\n        add_library(GTK3::gtk ALIAS PkgConfig::GTK3)\n    endif()\n    find_package_handle_standard_args(GTK3\n            REQUIRED_VARS GTK3_LINK_LIBRARIES\n            VERSION_VAR GTK3_VERSION\n    )\nendif()\n"
  },
  {
    "path": "cmake/FindWayland.cmake",
    "content": "# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>\n# SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>\n#\n# SPDX-License-Identifier: BSD-3-Clause\n\n#[=======================================================================[.rst:\nFindWayland\n-----------\n\nTry to find Wayland.\n\nThis is a component-based find module, which makes use of the COMPONENTS\nand OPTIONAL_COMPONENTS arguments to find_module.  The following components\nare available::\n\n  Client  Server  Cursor  Egl\n\nIf no components are specified, this module will act as though all components\nwere passed to OPTIONAL_COMPONENTS.\n\nThis module will define the following variables, independently of the\ncomponents searched for or found:\n\n``Wayland_FOUND``\n    TRUE if (the requested version of) Wayland is available\n``Wayland_VERSION``\n    Found Wayland version\n``Wayland_TARGETS``\n    A list of all targets imported by this module (note that there may be more\n    than the components that were requested)\n``Wayland_LIBRARIES``\n    This can be passed to target_link_libraries() instead of the imported\n    targets\n``Wayland_INCLUDE_DIRS``\n    This should be passed to target_include_directories() if the targets are\n    not used for linking\n``Wayland_DEFINITIONS``\n    This should be passed to target_compile_options() if the targets are not\n    used for linking\n``Wayland_DATADIR``\n    The core wayland protocols data directory\n    Since 5.73.0\n\nFor each searched-for components, ``Wayland_<component>_FOUND`` will be set to\nTRUE if the corresponding Wayland library was found, and FALSE otherwise.  If\n``Wayland_<component>_FOUND`` is TRUE, the imported target\n``Wayland::<component>`` will be defined.  This module will also attempt to\ndetermine ``Wayland_*_VERSION`` variables for each imported target, although\n``Wayland_VERSION`` should normally be sufficient.\n\nIn general we recommend using the imported targets, as they are easier to use\nand provide more control.  Bear in mind, however, that if any target is in the\nlink interface of an exported library, it must be made available by the\npackage config file.\n\nSince pre-1.0.0.\n#]=======================================================================]\n\ninclude(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)\n\necm_find_package_version_check(Wayland)\n\nset(Wayland_known_components\n    Client\n    Server\n    Cursor\n    Egl\n)\nforeach(_comp ${Wayland_known_components})\n    string(TOLOWER \"${_comp}\" _lc_comp)\n    set(Wayland_${_comp}_component_deps)\n    set(Wayland_${_comp}_pkg_config \"wayland-${_lc_comp}\")\n    set(Wayland_${_comp}_lib \"wayland-${_lc_comp}\")\n    set(Wayland_${_comp}_header \"wayland-${_lc_comp}.h\")\nendforeach()\nset(Wayland_Egl_component_deps Client)\n\necm_find_package_parse_components(Wayland\n    RESULT_VAR Wayland_components\n    KNOWN_COMPONENTS ${Wayland_known_components}\n)\necm_find_package_handle_library_components(Wayland\n    COMPONENTS ${Wayland_components}\n)\n\n# If pkg-config didn't provide us with version information,\n# try to extract it from wayland-version.h\n# (Note that the version from wayland-egl.pc will probably be\n# the Mesa version, rather than the Wayland version, but that\n# version will be ignored as we always find wayland-client.pc\n# first).\nif(NOT Wayland_VERSION)\n    find_file(Wayland_VERSION_HEADER\n        NAMES wayland-version.h\n        HINTS ${Wayland_INCLUDE_DIRS}\n    )\n    mark_as_advanced(Wayland_VERSION_HEADER)\n    if(Wayland_VERSION_HEADER)\n        file(READ ${Wayland_VERSION_HEADER} _wayland_version_header_contents)\n        string(REGEX REPLACE\n            \"^.*[ \\t]+WAYLAND_VERSION[ \\t]+\\\"([0-9.]*)\\\".*$\"\n            \"\\\\1\"\n            Wayland_VERSION\n            \"${_wayland_version_header_contents}\"\n        )\n        unset(_wayland_version_header_contents)\n    endif()\nendif()\n\nfind_package_handle_standard_args(Wayland\n    FOUND_VAR\n        Wayland_FOUND\n    REQUIRED_VARS\n        Wayland_LIBRARIES\n    VERSION_VAR\n        Wayland_VERSION\n    HANDLE_COMPONENTS\n)\n\npkg_get_variable(Wayland_DATADIR wayland-scanner pkgdatadir)\nif (CMAKE_CROSSCOMPILING AND (NOT EXISTS \"${Wayland_DATADIR}/wayland.xml\"))\n    # PKG_CONFIG_SYSROOT_DIR only applies to -I and -L flags, so pkg-config\n    # does not prepend CMAKE_SYSROOT when cross-compiling unless you pass\n    # --define-prefix explicitly. Therefore we have to  manually do prepend\n    # it here when cross-compiling.\n    # See https://gitlab.kitware.com/cmake/cmake/-/issues/16647#note_844761\n    set(Wayland_DATADIR ${CMAKE_SYSROOT}${Wayland_DATADIR})\nendif()\nif (NOT EXISTS \"${Wayland_DATADIR}/wayland.xml\")\n    message(WARNING \"Could not find wayland.xml in ${Wayland_DATADIR}\")\nendif()\n\ninclude(FeatureSummary)\nset_package_properties(Wayland PROPERTIES\n    URL \"https://wayland.freedesktop.org/\"\n    DESCRIPTION \"C library implementation of the Wayland protocol: a protocol for a compositor to talk to its clients\"\n)\n"
  },
  {
    "path": "cmake/FindWaylandProtocols.cmake",
    "content": "# SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>\n#\n# SPDX-License-Identifier: BSD-3-Clause\n\n#[=======================================================================[.rst:\nFindWaylandProtocols\n--------------------\n\nTry to find wayland-protocols on a Unix system.\n\nThis will define the following variables:\n\n``WaylandProtocols_FOUND``\n    True if (the requested version of) wayland-protocols is available\n``WaylandProtocols_VERSION``\n    The version of wayland-protocols\n``WaylandProtocols_DATADIR``\n    The wayland protocols data directory\n#]=======================================================================]\n\nfind_package(PkgConfig QUIET)\npkg_check_modules(PKG_wayland_protocols QUIET wayland-protocols)\n\nset(WaylandProtocols_VERSION ${PKG_wayland_protocols_VERSION})\npkg_get_variable(WaylandProtocols_DATADIR wayland-protocols pkgdatadir)\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(WaylandProtocols\n    FOUND_VAR WaylandProtocols_FOUND\n    REQUIRED_VARS WaylandProtocols_DATADIR\n    VERSION_VAR WaylandProtocols_VERSION\n)\n\ninclude(FeatureSummary)\nset_package_properties(WaylandProtocols PROPERTIES\n    DESCRIPTION \"Specifications of extended Wayland protocols\"\n    URL \"https://wayland.freedesktop.org/\"\n)\n"
  },
  {
    "path": "cmake/FindWaylandScanner.cmake",
    "content": "# SPDX-FileCopyrightText: 2012-2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>\n#\n# SPDX-License-Identifier: BSD-3-Clause\n\n#[=======================================================================[.rst:\nFindWaylandScanner\n------------------\n\nTry to find wayland-scanner.\n\nIf the wayland-scanner executable is not in your PATH, you can provide\nan alternative name or full path location with the ``WaylandScanner_EXECUTABLE``\nvariable.\n\nThis will define the following variables:\n\n``WaylandScanner_FOUND``\n    True if wayland-scanner is available.\n\n``WaylandScanner_EXECUTABLE``\n    The wayland-scanner executable.\n\nIf ``WaylandScanner_FOUND`` is TRUE, it will also define the following imported\ntarget:\n\n``Wayland::Scanner``\n    The wayland-scanner executable.\n\nThis module provides the following functions to generate C protocol\nimplementations:\n\n  - ``ecm_add_wayland_client_protocol``\n  - ``ecm_add_wayland_server_protocol``\n\n::\n\n  ecm_add_wayland_client_protocol(<target>\n                                  PROTOCOL <xmlfile>\n                                  BASENAME <basename>)\n\n  ecm_add_wayland_client_protocol(<source_files_var>\n                                  PROTOCOL <xmlfile>\n                                  BASENAME <basename>)\n\nGenerate Wayland client protocol files from ``<xmlfile>`` XML\ndefinition for the ``<basename>`` interface and append those files\nto ``<source_files_var>`` or ``<target>``.\n\n::\n\n  ecm_add_wayland_server_protocol(<target>\n                                  PROTOCOL <xmlfile>\n                                  BASENAME <basename>)\n\n  ecm_add_wayland_server_protocol(<source_files_var>\n                                  PROTOCOL <xmlfile>\n                                  BASENAME <basename>)\n\nGenerate Wayland server protocol files from ``<xmlfile>`` XML\ndefinition for the ``<basename>`` interface and append those files\nto ``<source_files_var>`` or ``<target>``.\n\nSince 1.4.0.\n#]=======================================================================]\n\ninclude(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)\n\necm_find_package_version_check(WaylandScanner)\n\n# Find wayland-scanner\nfind_program(WaylandScanner_EXECUTABLE NAMES wayland-scanner)\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(WaylandScanner\n    FOUND_VAR\n        WaylandScanner_FOUND\n    REQUIRED_VARS\n        WaylandScanner_EXECUTABLE\n)\n\nmark_as_advanced(WaylandScanner_EXECUTABLE)\n\nif(NOT TARGET Wayland::Scanner AND WaylandScanner_FOUND)\n    add_executable(Wayland::Scanner IMPORTED)\n    set_target_properties(Wayland::Scanner PROPERTIES\n        IMPORTED_LOCATION \"${WaylandScanner_EXECUTABLE}\"\n    )\nendif()\n\ninclude(FeatureSummary)\nset_package_properties(WaylandScanner PROPERTIES\n    URL \"https://wayland.freedesktop.org/\"\n    DESCRIPTION \"Executable that converts XML protocol files to C code\"\n)\n\n\ninclude(CMakeParseArguments)\n\nfunction(ecm_add_wayland_client_protocol target_or_sources_var)\n    # Parse arguments\n    set(oneValueArgs PROTOCOL BASENAME)\n    cmake_parse_arguments(ARGS \"\" \"${oneValueArgs}\" \"\" ${ARGN})\n\n    if(ARGS_UNPARSED_ARGUMENTS)\n        message(FATAL_ERROR \"Unknown keywords given to ecm_add_wayland_client_protocol(): \\\"${ARGS_UNPARSED_ARGUMENTS}\\\"\")\n    endif()\n\n    get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE)\n    set(_client_header \"${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-client-protocol.h\")\n    set(_code \"${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-protocol.c\")\n\n    set_source_files_properties(${_client_header} GENERATED)\n    set_source_files_properties(${_code} GENERATED)\n    set_property(SOURCE ${_client_header} ${_code} PROPERTY SKIP_AUTOMOC ON)\n\n    add_custom_command(OUTPUT \"${_client_header}\"\n        COMMAND ${WaylandScanner_EXECUTABLE} client-header ${_infile} ${_client_header}\n        DEPENDS ${_infile} VERBATIM)\n\n    add_custom_command(OUTPUT \"${_code}\"\n        COMMAND ${WaylandScanner_EXECUTABLE} public-code ${_infile} ${_code}\n        DEPENDS ${_infile} ${_client_header} VERBATIM)\n\n    if (TARGET ${target_or_sources_var})\n        target_sources(${target_or_sources_var} PRIVATE \"${_client_header}\" \"${_code}\")\n    else()\n        list(APPEND ${target_or_sources_var} \"${_client_header}\" \"${_code}\")\n        set(${target_or_sources_var} ${${target_or_sources_var}} PARENT_SCOPE)\n    endif()\nendfunction()\n\n\nfunction(ecm_add_wayland_server_protocol target_or_sources_var)\n    # Parse arguments\n    set(oneValueArgs PROTOCOL BASENAME)\n    cmake_parse_arguments(ARGS \"\" \"${oneValueArgs}\" \"\" ${ARGN})\n\n    if(ARGS_UNPARSED_ARGUMENTS)\n        message(FATAL_ERROR \"Unknown keywords given to ecm_add_wayland_server_protocol(): \\\"${ARGS_UNPARSED_ARGUMENTS}\\\"\")\n    endif()\n\n    ecm_add_wayland_client_protocol(${target_or_sources_var}\n                                    PROTOCOL ${ARGS_PROTOCOL}\n                                    BASENAME ${ARGS_BASENAME})\n\n    get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE)\n    set(_server_header \"${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-server-protocol.h\")\n    set(_server_code \"${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-protocol.c\")\n    set_property(SOURCE ${_server_header} ${_server_code} PROPERTY SKIP_AUTOMOC ON)\n    set_source_files_properties(${_server_header} GENERATED)\n\n    add_custom_command(OUTPUT \"${_server_header}\"\n        COMMAND ${WaylandScanner_EXECUTABLE} server-header ${_infile} ${_server_header}\n        DEPENDS ${_infile} VERBATIM)\n\n    if (TARGET ${target_or_sources_var})\n        target_sources(${target_or_sources_var} PRIVATE \"${_server_header}\")\n    else()\n        list(APPEND ${target_or_sources_var} \"${_server_header}\")\n        set(${target_or_sources_var} ${${target_or_sources_var}} PARENT_SCOPE)\n    endif()\nendfunction()\n"
  },
  {
    "path": "cmake/FindZArchive.cmake",
    "content": "# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>\n# SPDX-License-Identifier: ISC\n\nfind_package(PkgConfig)\n\nif (PKG_CONFIG_FOUND)\n\tpkg_search_module(zarchive IMPORTED_TARGET GLOBAL zarchive)\n\tif (zarchive_FOUND)\n\t\tadd_library(ZArchive::zarchive ALIAS PkgConfig::zarchive)\n\tendif()\nendif()\n\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(ZArchive\n\tREQUIRED_VARS\n\t\tzarchive_LINK_LIBRARIES\n\t\tzarchive_FOUND\n\tVERSION_VAR\n\t\tzarchive_VERSION\n)\n"
  },
  {
    "path": "cmake/Findbluez.cmake",
    "content": "# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>\n# SPDX-License-Identifier: ISC\n\nfind_package(bluez CONFIG)\nif (NOT bluez_FOUND)\n  find_package(PkgConfig)\n  if (PKG_CONFIG_FOUND)\n    pkg_search_module(bluez IMPORTED_TARGET GLOBAL bluez-1.0 bluez)\n    if (bluez_FOUND)\n      add_library(bluez::bluez ALIAS PkgConfig::bluez)\n    endif ()\n  endif ()\nendif ()\n\nfind_package_handle_standard_args(bluez\n    REQUIRED_VARS\n    bluez_LINK_LIBRARIES\n    bluez_FOUND\n    VERSION_VAR bluez_VERSION\n)\n"
  },
  {
    "path": "cmake/Findimgui.cmake",
    "content": "# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>\n# SPDX-License-Identifier: ISC\n\ninclude(FindPackageHandleStandardArgs)\n\nfind_package(imgui CONFIG)\nif (imgui_FOUND)\n\t# Use upstream imguiConfig.cmake if possible\n\tfind_package_handle_standard_args(imgui CONFIG_MODE)\nelse()\n\t# Fallback to pkg-config otherwise\n\tfind_package(PkgConfig)\n\tif (PKG_CONFIG_FOUND)\n\t\tpkg_search_module(imgui IMPORTED_TARGET GLOBAL imgui)\n\t\tif (imgui_FOUND)\n\t\t\tadd_library(imgui::imgui ALIAS PkgConfig::imgui)\n\t\tendif()\n\tendif()\n\n\tfind_package_handle_standard_args(imgui\n\t\tREQUIRED_VARS\n\t\t\timgui_LINK_LIBRARIES\n\t\t\timgui_FOUND\n\t\tVERSION_VAR\n\t\t\timgui_VERSION\n\t)\nendif()\n"
  },
  {
    "path": "cmake/Findlibusb.cmake",
    "content": "# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>\n# SPDX-License-Identifier: ISC\n\nfind_package(libusb CONFIG)\nif (NOT libusb_FOUND)\n    find_package(PkgConfig)\n    if (PKG_CONFIG_FOUND)\n        pkg_search_module(libusb IMPORTED_TARGET GLOBAL libusb-1.0 libusb)\n        if (libusb_FOUND)\n            add_library(libusb::libusb ALIAS PkgConfig::libusb)\n        endif ()\n    endif ()\nendif ()\n\nfind_package_handle_standard_args(libusb\n        REQUIRED_VARS\n        libusb_LINK_LIBRARIES\n        libusb_FOUND\n        VERSION_VAR libusb_VERSION\n)\n"
  },
  {
    "path": "cmake/FindwxWidgets.cmake",
    "content": "# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>\n# SPDX-License-Identifier: ISC\n\ninclude(FindPackageHandleStandardArgs)\nfind_package(wxWidgets CONFIG COMPONENTS ${wxWidgets_FIND_COMPONENTS})\n\nif (wxWidgets_FOUND)\n\t# Use upstream wxWidgetsConfig.cmake if possible\n\tfind_package_handle_standard_args(wxWidgets CONFIG_MODE)\nelse()\n\t# Fall back to CMake's FindwxWidgets\n\t# Temporarily unset CMAKE_MODULE_PATH to avoid calling the current find\n\t# module recursively\n\tset(_tmp_module_path \"${CMAKE_MODULE_PATH}\")\n\tset(CMAKE_MODULE_PATH \"\")\n\n\tfind_package(wxWidgets MODULE QUIET COMPONENTS ${wxWidgets_FIND_COMPONENTS})\n\n\tset(CMAKE_MODULE_PATH \"${_tmp_module_path}\")\n\tunset(_tmp_module_path)\n\n\tif (wxWidgets_FOUND)\n\t\tadd_library(wx::base IMPORTED INTERFACE)\n\t\ttarget_include_directories(wx::base INTERFACE ${wxWidgets_INCLUDE_DIRS})\n\t\ttarget_link_libraries(wx::base INTERFACE ${wxWidgets_LIBRARIES})\n\t\ttarget_link_directories(wx::base INTERFACE ${wxWidgets_LIBRARY_DIRS})\n\t\ttarget_compile_definitions(wx::base INTERFACE ${wxWidgets_DEFINITIONS})\n\t\ttarget_compile_options(wx::base INTERFACE ${wxWidgets_CXX_FLAGS})\n\n\t\t# FindwxWidgets sets everything into a single set of variables, so it is\n\t\t# impossible to tell what libraries are required for what component.\n\t\t# To be compatible with wxWidgetsConfig, we create an alias for each\n\t\t# component so that the user can still use target_link_libraries(wx::gl)\n\t\tforeach(component ${wxWidgets_FIND_COMPONENTS})\n\t\t\tif (NOT component STREQUAL \"base\")\n\t\t\t\t# don't alias base to itself\n\t\t\t\tadd_library(wx::${component} ALIAS wx::base)\n\t\t\tendif()\n\t\tendforeach()\n\tendif()\n\n\tfind_package_handle_standard_args(wxWidgets\n\t\tREQUIRED_VARS\n\t\t\twxWidgets_LIBRARIES\n\t\t\twxWidgets_FOUND\n\t\tVERSION_VAR\n\t\t\twxWidgets_VERSION_STRING\n\t)\nendif()\n"
  },
  {
    "path": "cmake/Findzstd.cmake",
    "content": "# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>\n# SPDX-License-Identifier: ISC\n\ninclude(FindPackageHandleStandardArgs)\n\nfind_package(zstd CONFIG)\nif (zstd_FOUND)\n\t# Use upstream zstdConfig.cmake if possible\n\tif (NOT TARGET zstd::zstd)\n\t\tif (TARGET zstd::libzstd_static)\n\t\t\tadd_library(zstd::zstd ALIAS zstd::libzstd_static)\n\t\telseif (TARGET zstd::libzstd_shared)\n\t\t\tadd_library(zstd::zstd ALIAS zstd::libzstd_shared)\n\t\tendif()\n\tendif()\n\tfind_package_handle_standard_args(zstd CONFIG_MODE)\nelse()\n\t# Fallback to pkg-config otherwise\n\tfind_package(PkgConfig)\n\tif (PKG_CONFIG_FOUND)\n\t\tpkg_search_module(libzstd IMPORTED_TARGET GLOBAL libzstd)\n\t\tif (libzstd_FOUND)\n\t\t\tadd_library(zstd::zstd ALIAS PkgConfig::libzstd)\n\t\tendif()\n\tendif()\n\n\tfind_package_handle_standard_args(zstd\n\t\tREQUIRED_VARS\n\t\t\tlibzstd_LINK_LIBRARIES\n\t\t\tlibzstd_FOUND\n\t\tVERSION_VAR libzstd_VERSION\n\t)\nendif()\n"
  },
  {
    "path": "dependencies/DirectX_2010/XAudio2.h",
    "content": "/**************************************************************************\n *\n * Copyright (c) Microsoft Corporation.  All rights reserved.\n *\n * File:    xaudio2.h\n * Content: Declarations for the XAudio2 game audio API.\n *\n **************************************************************************/\n\n#ifndef __XAUDIO2_INCLUDED__\n#define __XAUDIO2_INCLUDED__\n\n\n/**************************************************************************\n *\n * XAudio2 COM object class and interface IDs.\n *\n **************************************************************************/\n\n#include \"comdecl.h\"        // For DEFINE_CLSID and DEFINE_IID\n\n// XAudio 2.0 (March 2008 SDK)\n//DEFINE_CLSID(XAudio2, fac23f48, 31f5, 45a8, b4, 9b, 52, 25, d6, 14, 01, aa);\n//DEFINE_CLSID(XAudio2_Debug, fac23f48, 31f5, 45a8, b4, 9b, 52, 25, d6, 14, 01, db);\n\n// XAudio 2.1 (June 2008 SDK)\n//DEFINE_CLSID(XAudio2, e21a7345, eb21, 468e, be, 50, 80, 4d, b9, 7c, f7, 08);\n//DEFINE_CLSID(XAudio2_Debug, f7a76c21, 53d4, 46bb, ac, 53, 8b, 45, 9c, ae, 46, bd);\n\n// XAudio 2.2 (August 2008 SDK)\n//DEFINE_CLSID(XAudio2, b802058a, 464a, 42db, bc, 10, b6, 50, d6, f2, 58, 6a);\n//DEFINE_CLSID(XAudio2_Debug, 97dfb7e7, 5161, 4015, 87, a9, c7, 9e, 6a, 19, 52, cc);\n\n// XAudio 2.3 (November 2008 SDK)\n//DEFINE_CLSID(XAudio2, 4c5e637a, 16c7, 4de3, 9c, 46, 5e, d2, 21, 81, 96, 2d);\n//DEFINE_CLSID(XAudio2_Debug, ef0aa05d, 8075, 4e5d, be, ad, 45, be, 0c, 3c, cb, b3);\n\n// XAudio 2.4 (March 2009 SDK)\n//DEFINE_CLSID(XAudio2, 03219e78, 5bc3, 44d1, b9, 2e, f6, 3d, 89, cc, 65, 26);\n//DEFINE_CLSID(XAudio2_Debug, 4256535c, 1ea4, 4d4b, 8a, d5, f9, db, 76, 2e, ca, 9e);\n\n// XAudio 2.5 (August 2009 SDK)\n//DEFINE_CLSID(XAudio2, 4c9b6dde, 6809, 46e6, a2, 78, 9b, 6a, 97, 58, 86, 70);\n//DEFINE_CLSID(XAudio2_Debug, 715bdd1a, aa82, 436b, b0, fa, 6a, ce, a3, 9b, d0, a1);\n\n// XAudio 2.6 (February 2010 SDK)\n//DEFINE_CLSID(XAudio2, 3eda9b49, 2085, 498b, 9b, b2, 39, a6, 77, 84, 93, de);\n//DEFINE_CLSID(XAudio2_Debug, 47199894, 7cc2, 444d, 98, 73, ce, d2, 56, 2c, c6, 0e);\n\n// XAudio 2.7 (June 2010 SDK)\n#ifdef __clang__\nclass __declspec(uuid(\"5a508685-a254-4fba-9b82-9a24b00306af\")) XAudio2; extern \"C\" const GUID CLSID_XAudio2;\nclass __declspec(uuid(\"db05ea35-0329-4d4b-a53a-6dead03d3852\")) XAudio2_Debug; extern \"C\" const GUID CLSID_XAudio2_Debug;\nstruct __declspec(uuid(\"8bcf1f58-9fe7-4583-8ac6-e2adc465c8bb\")) IXAudio2; extern \"C\" const GUID IID_IXAudio2;\n#else\nDEFINE_CLSID(XAudio2, 5a508685, a254, 4fba, 9b, 82, 9a, 24, b0, 03, 06, af);\nDEFINE_CLSID(XAudio2_Debug, db05ea35, 0329, 4d4b, a5, 3a, 6d, ea, d0, 3d, 38, 52);\nDEFINE_IID(IXAudio2, 8bcf1f58, 9fe7, 4583, 8a, c6, e2, ad, c4, 65, c8, bb);\n#endif\n\n// Ignore the rest of this header if only the GUID definitions were requested\n#ifndef GUID_DEFS_ONLY\n\n#ifdef _XBOX\n    #include <xobjbase.h>   // Xbox COM declarations (IUnknown, etc)\n#else\n    #include <objbase.h>    // Windows COM declarations\n#endif\n\n#include <sal.h>            // Markers for documenting API semantics\n#include \"audiodefs.h\"      // Basic audio data types and constants\n#include \"xma2defs.h\"       // Data types and constants for XMA2 audio\n\n// All structures defined in this file use tight field packing\n#pragma pack(push, 1)\n\n\n/**************************************************************************\n *\n * XAudio2 constants, flags and error codes.\n *\n **************************************************************************/\n\n// Numeric boundary values\n#define XAUDIO2_MAX_BUFFER_BYTES        0x80000000    // Maximum bytes allowed in a source buffer\n#define XAUDIO2_MAX_QUEUED_BUFFERS      64            // Maximum buffers allowed in a voice queue\n#define XAUDIO2_MAX_BUFFERS_SYSTEM      2             // Maximum buffers allowed for system threads (Xbox 360 only)\n#define XAUDIO2_MAX_AUDIO_CHANNELS      64            // Maximum channels in an audio stream\n#define XAUDIO2_MIN_SAMPLE_RATE         1000          // Minimum audio sample rate supported\n#define XAUDIO2_MAX_SAMPLE_RATE         200000        // Maximum audio sample rate supported\n#define XAUDIO2_MAX_VOLUME_LEVEL        16777216.0f   // Maximum acceptable volume level (2^24)\n#define XAUDIO2_MIN_FREQ_RATIO          (1/1024.0f)   // Minimum SetFrequencyRatio argument\n#define XAUDIO2_MAX_FREQ_RATIO          1024.0f       // Maximum MaxFrequencyRatio argument\n#define XAUDIO2_DEFAULT_FREQ_RATIO      2.0f          // Default MaxFrequencyRatio argument\n#define XAUDIO2_MAX_FILTER_ONEOVERQ     1.5f          // Maximum XAUDIO2_FILTER_PARAMETERS.OneOverQ\n#define XAUDIO2_MAX_FILTER_FREQUENCY    1.0f          // Maximum XAUDIO2_FILTER_PARAMETERS.Frequency\n#define XAUDIO2_MAX_LOOP_COUNT          254           // Maximum non-infinite XAUDIO2_BUFFER.LoopCount\n#define XAUDIO2_MAX_INSTANCES           8             // Maximum simultaneous XAudio2 objects on Xbox 360\n\n// For XMA voices on Xbox 360 there is an additional restriction on the MaxFrequencyRatio\n// argument and the voice's sample rate: the product of these numbers cannot exceed 600000\n// for one-channel voices or 300000 for voices with more than one channel.\n#define XAUDIO2_MAX_RATIO_TIMES_RATE_XMA_MONO         600000\n#define XAUDIO2_MAX_RATIO_TIMES_RATE_XMA_MULTICHANNEL 300000\n\n// Numeric values with special meanings\n#define XAUDIO2_COMMIT_NOW              0             // Used as an OperationSet argument\n#define XAUDIO2_COMMIT_ALL              0             // Used in IXAudio2::CommitChanges\n#define XAUDIO2_INVALID_OPSET           (UINT32)(-1)  // Not allowed for OperationSet arguments\n#define XAUDIO2_NO_LOOP_REGION          0             // Used in XAUDIO2_BUFFER.LoopCount\n#define XAUDIO2_LOOP_INFINITE           255           // Used in XAUDIO2_BUFFER.LoopCount\n#define XAUDIO2_DEFAULT_CHANNELS        0             // Used in CreateMasteringVoice\n#define XAUDIO2_DEFAULT_SAMPLERATE      0             // Used in CreateMasteringVoice\n\n// Flags\n#define XAUDIO2_DEBUG_ENGINE            0x0001        // Used in XAudio2Create on Windows only\n#define XAUDIO2_VOICE_NOPITCH           0x0002        // Used in IXAudio2::CreateSourceVoice\n#define XAUDIO2_VOICE_NOSRC             0x0004        // Used in IXAudio2::CreateSourceVoice\n#define XAUDIO2_VOICE_USEFILTER         0x0008        // Used in IXAudio2::CreateSource/SubmixVoice\n#define XAUDIO2_VOICE_MUSIC             0x0010        // Used in IXAudio2::CreateSourceVoice\n#define XAUDIO2_PLAY_TAILS              0x0020        // Used in IXAudio2SourceVoice::Stop\n#define XAUDIO2_END_OF_STREAM           0x0040        // Used in XAUDIO2_BUFFER.Flags\n#define XAUDIO2_SEND_USEFILTER          0x0080        // Used in XAUDIO2_SEND_DESCRIPTOR.Flags\n\n// Default parameters for the built-in filter\n#define XAUDIO2_DEFAULT_FILTER_TYPE     LowPassFilter\n#define XAUDIO2_DEFAULT_FILTER_FREQUENCY XAUDIO2_MAX_FILTER_FREQUENCY\n#define XAUDIO2_DEFAULT_FILTER_ONEOVERQ 1.0f\n\n// Internal XAudio2 constants\n#ifdef _XBOX\n    #define XAUDIO2_QUANTUM_NUMERATOR   2             // On Xbox 360, XAudio2 processes audio\n    #define XAUDIO2_QUANTUM_DENOMINATOR 375           //  in 5.333ms chunks (= 2/375 seconds)\n#else\n    #define XAUDIO2_QUANTUM_NUMERATOR   1             // On Windows, XAudio2 processes audio\n    #define XAUDIO2_QUANTUM_DENOMINATOR 100           //  in 10ms chunks (= 1/100 seconds)\n#endif\n#define XAUDIO2_QUANTUM_MS (1000.0f * XAUDIO2_QUANTUM_NUMERATOR / XAUDIO2_QUANTUM_DENOMINATOR)\n\n// XAudio2 error codes\n#define FACILITY_XAUDIO2 0x896\n#define XAUDIO2_E_INVALID_CALL          0x88960001    // An API call or one of its arguments was illegal\n#define XAUDIO2_E_XMA_DECODER_ERROR     0x88960002    // The XMA hardware suffered an unrecoverable error\n#define XAUDIO2_E_XAPO_CREATION_FAILED  0x88960003    // XAudio2 failed to initialize an XAPO effect\n#define XAUDIO2_E_DEVICE_INVALIDATED    0x88960004    // An audio device became unusable (unplugged, etc)\n\n\n/**************************************************************************\n *\n * Forward declarations for the XAudio2 interfaces.\n *\n **************************************************************************/\n\n#ifdef __cplusplus\n    #define FWD_DECLARE(x) interface x\n#else\n    #define FWD_DECLARE(x) typedef interface x x\n#endif\n\nFWD_DECLARE(IXAudio2);\nFWD_DECLARE(IXAudio2Voice);\nFWD_DECLARE(IXAudio2SourceVoice);\nFWD_DECLARE(IXAudio2SubmixVoice);\nFWD_DECLARE(IXAudio2MasteringVoice);\nFWD_DECLARE(IXAudio2EngineCallback);\nFWD_DECLARE(IXAudio2VoiceCallback);\n\n\n/**************************************************************************\n *\n * XAudio2 structures and enumerations.\n *\n **************************************************************************/\n\n// Used in IXAudio2::Initialize\n#ifdef _XBOX\n    typedef enum XAUDIO2_XBOX_HWTHREAD_SPECIFIER\n    {\n        XboxThread0 = 0x01,\n        XboxThread1 = 0x02,\n        XboxThread2 = 0x04,\n        XboxThread3 = 0x08,\n        XboxThread4 = 0x10,\n        XboxThread5 = 0x20,\n        XAUDIO2_ANY_PROCESSOR = XboxThread4,\n        XAUDIO2_DEFAULT_PROCESSOR = XAUDIO2_ANY_PROCESSOR\n    } XAUDIO2_XBOX_HWTHREAD_SPECIFIER, XAUDIO2_PROCESSOR;\n#else\n    typedef enum XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER\n    {\n        Processor1  = 0x00000001,\n        Processor2  = 0x00000002,\n        Processor3  = 0x00000004,\n        Processor4  = 0x00000008,\n        Processor5  = 0x00000010,\n        Processor6  = 0x00000020,\n        Processor7  = 0x00000040,\n        Processor8  = 0x00000080,\n        Processor9  = 0x00000100,\n        Processor10 = 0x00000200,\n        Processor11 = 0x00000400,\n        Processor12 = 0x00000800,\n        Processor13 = 0x00001000,\n        Processor14 = 0x00002000,\n        Processor15 = 0x00004000,\n        Processor16 = 0x00008000,\n        Processor17 = 0x00010000,\n        Processor18 = 0x00020000,\n        Processor19 = 0x00040000,\n        Processor20 = 0x00080000,\n        Processor21 = 0x00100000,\n        Processor22 = 0x00200000,\n        Processor23 = 0x00400000,\n        Processor24 = 0x00800000,\n        Processor25 = 0x01000000,\n        Processor26 = 0x02000000,\n        Processor27 = 0x04000000,\n        Processor28 = 0x08000000,\n        Processor29 = 0x10000000,\n        Processor30 = 0x20000000,\n        Processor31 = 0x40000000,\n        Processor32 = 0x80000000,\n        XAUDIO2_ANY_PROCESSOR = 0xffffffff,\n        XAUDIO2_DEFAULT_PROCESSOR = XAUDIO2_ANY_PROCESSOR\n    } XAUDIO2_WINDOWS_PROCESSOR_SPECIFIER, XAUDIO2_PROCESSOR;\n#endif\n\n// Used in XAUDIO2_DEVICE_DETAILS below to describe the types of applications\n// that the user has specified each device as a default for.  0 means that the\n// device isn't the default for any role.\ntypedef enum XAUDIO2_DEVICE_ROLE\n{\n    NotDefaultDevice            = 0x0,\n    DefaultConsoleDevice        = 0x1,\n    DefaultMultimediaDevice     = 0x2,\n    DefaultCommunicationsDevice = 0x4,\n    DefaultGameDevice           = 0x8,\n    GlobalDefaultDevice         = 0xf,\n    InvalidDeviceRole = ~GlobalDefaultDevice\n} XAUDIO2_DEVICE_ROLE;\n\n// Returned by IXAudio2::GetDeviceDetails\ntypedef struct XAUDIO2_DEVICE_DETAILS\n{\n    WCHAR DeviceID[256];                // String identifier for the audio device.\n    WCHAR DisplayName[256];             // Friendly name suitable for display to a human.\n    XAUDIO2_DEVICE_ROLE Role;           // Roles that the device should be used for.\n    WAVEFORMATEXTENSIBLE OutputFormat;  // The device's native PCM audio output format.\n} XAUDIO2_DEVICE_DETAILS;\n\n// Returned by IXAudio2Voice::GetVoiceDetails\ntypedef struct XAUDIO2_VOICE_DETAILS\n{\n    UINT32 CreationFlags;               // Flags the voice was created with.\n    UINT32 InputChannels;               // Channels in the voice's input audio.\n    UINT32 InputSampleRate;             // Sample rate of the voice's input audio.\n} XAUDIO2_VOICE_DETAILS;\n\n// Used in XAUDIO2_VOICE_SENDS below\ntypedef struct XAUDIO2_SEND_DESCRIPTOR\n{\n    UINT32 Flags;                       // Either 0 or XAUDIO2_SEND_USEFILTER.\n    IXAudio2Voice* pOutputVoice;        // This send's destination voice.\n} XAUDIO2_SEND_DESCRIPTOR;\n\n// Used in the voice creation functions and in IXAudio2Voice::SetOutputVoices\ntypedef struct XAUDIO2_VOICE_SENDS\n{\n    UINT32 SendCount;                   // Number of sends from this voice.\n    XAUDIO2_SEND_DESCRIPTOR* pSends;    // Array of SendCount send descriptors.\n} XAUDIO2_VOICE_SENDS;\n\n// Used in XAUDIO2_EFFECT_CHAIN below\ntypedef struct XAUDIO2_EFFECT_DESCRIPTOR\n{\n    IUnknown* pEffect;                  // Pointer to the effect object's IUnknown interface.\n    BOOL InitialState;                  // TRUE if the effect should begin in the enabled state.\n    UINT32 OutputChannels;              // How many output channels the effect should produce.\n} XAUDIO2_EFFECT_DESCRIPTOR;\n\n// Used in the voice creation functions and in IXAudio2Voice::SetEffectChain\ntypedef struct XAUDIO2_EFFECT_CHAIN\n{\n    UINT32 EffectCount;                 // Number of effects in this voice's effect chain.\n    XAUDIO2_EFFECT_DESCRIPTOR* pEffectDescriptors; // Array of effect descriptors.\n} XAUDIO2_EFFECT_CHAIN;\n\n// Used in XAUDIO2_FILTER_PARAMETERS below\ntypedef enum XAUDIO2_FILTER_TYPE\n{\n    LowPassFilter,                      // Attenuates frequencies above the cutoff frequency.\n    BandPassFilter,                     // Attenuates frequencies outside a given range.\n    HighPassFilter,                     // Attenuates frequencies below the cutoff frequency.\n    NotchFilter                         // Attenuates frequencies inside a given range.\n} XAUDIO2_FILTER_TYPE;\n\n// Used in IXAudio2Voice::Set/GetFilterParameters and Set/GetOutputFilterParameters\ntypedef struct XAUDIO2_FILTER_PARAMETERS\n{\n    XAUDIO2_FILTER_TYPE Type;           // Low-pass, band-pass or high-pass.\n    float Frequency;                    // Radian frequency (2 * sin(pi*CutoffFrequency/SampleRate));\n                                        //  must be >= 0 and <= XAUDIO2_MAX_FILTER_FREQUENCY\n                                        //  (giving a maximum CutoffFrequency of SampleRate/6).\n    float OneOverQ;                     // Reciprocal of the filter's quality factor Q;\n                                        //  must be > 0 and <= XAUDIO2_MAX_FILTER_ONEOVERQ.\n} XAUDIO2_FILTER_PARAMETERS;\n\n// Used in IXAudio2SourceVoice::SubmitSourceBuffer\ntypedef struct XAUDIO2_BUFFER\n{\n    UINT32 Flags;                       // Either 0 or XAUDIO2_END_OF_STREAM.\n    UINT32 AudioBytes;                  // Size of the audio data buffer in bytes.\n    const BYTE* pAudioData;             // Pointer to the audio data buffer.\n    UINT32 PlayBegin;                   // First sample in this buffer to be played.\n    UINT32 PlayLength;                  // Length of the region to be played in samples,\n                                        //  or 0 to play the whole buffer.\n    UINT32 LoopBegin;                   // First sample of the region to be looped.\n    UINT32 LoopLength;                  // Length of the desired loop region in samples,\n                                        //  or 0 to loop the entire buffer.\n    UINT32 LoopCount;                   // Number of times to repeat the loop region,\n                                        //  or XAUDIO2_LOOP_INFINITE to loop forever.\n    void* pContext;                     // Context value to be passed back in callbacks.\n} XAUDIO2_BUFFER;\n\n// Used in IXAudio2SourceVoice::SubmitSourceBuffer when submitting XWMA data.\n// NOTE: If an XWMA sound is submitted in more than one buffer, each buffer's\n// pDecodedPacketCumulativeBytes[PacketCount-1] value must be subtracted from\n// all the entries in the next buffer's pDecodedPacketCumulativeBytes array.\n// And whether a sound is submitted in more than one buffer or not, the final\n// buffer of the sound should use the XAUDIO2_END_OF_STREAM flag, or else the\n// client must call IXAudio2SourceVoice::Discontinuity after submitting it.\ntypedef struct XAUDIO2_BUFFER_WMA\n{\n    const UINT32* pDecodedPacketCumulativeBytes; // Decoded packet's cumulative size array.\n                                                 //  Each element is the number of bytes accumulated\n                                                 //  when the corresponding XWMA packet is decoded in\n                                                 //  order.  The array must have PacketCount elements.\n    UINT32 PacketCount;                          // Number of XWMA packets submitted. Must be >= 1 and\n                                                 //  divide evenly into XAUDIO2_BUFFER.AudioBytes.\n} XAUDIO2_BUFFER_WMA;\n\n// Returned by IXAudio2SourceVoice::GetState\ntypedef struct XAUDIO2_VOICE_STATE\n{\n    void* pCurrentBufferContext;        // The pContext value provided in the XAUDIO2_BUFFER\n                                        //  that is currently being processed, or NULL if\n                                        //  there are no buffers in the queue.\n    UINT32 BuffersQueued;               // Number of buffers currently queued on the voice\n                                        //  (including the one that is being processed).\n    UINT64 SamplesPlayed;               // Total number of samples produced by the voice since\n                                        //  it began processing the current audio stream.\n} XAUDIO2_VOICE_STATE;\n\n// Returned by IXAudio2::GetPerformanceData\ntypedef struct XAUDIO2_PERFORMANCE_DATA\n{\n    // CPU usage information\n    UINT64 AudioCyclesSinceLastQuery;   // CPU cycles spent on audio processing since the\n                                        //  last call to StartEngine or GetPerformanceData.\n    UINT64 TotalCyclesSinceLastQuery;   // Total CPU cycles elapsed since the last call\n                                        //  (only counts the CPU XAudio2 is running on).\n    UINT32 MinimumCyclesPerQuantum;     // Fewest CPU cycles spent processing any one\n                                        //  audio quantum since the last call.\n    UINT32 MaximumCyclesPerQuantum;     // Most CPU cycles spent processing any one\n                                        //  audio quantum since the last call.\n\n    // Memory usage information\n    UINT32 MemoryUsageInBytes;          // Total heap space currently in use.\n\n    // Audio latency and glitching information\n    UINT32 CurrentLatencyInSamples;     // Minimum delay from when a sample is read from a\n                                        //  source buffer to when it reaches the speakers.\n    UINT32 GlitchesSinceEngineStarted;  // Audio dropouts since the engine was started.\n\n    // Data about XAudio2's current workload\n    UINT32 ActiveSourceVoiceCount;      // Source voices currently playing.\n    UINT32 TotalSourceVoiceCount;       // Source voices currently existing.\n    UINT32 ActiveSubmixVoiceCount;      // Submix voices currently playing/existing.\n\n    UINT32 ActiveResamplerCount;        // Resample xAPOs currently active.\n    UINT32 ActiveMatrixMixCount;        // MatrixMix xAPOs currently active.\n\n    // Usage of the hardware XMA decoder (Xbox 360 only)\n    UINT32 ActiveXmaSourceVoices;       // Number of source voices decoding XMA data.\n    UINT32 ActiveXmaStreams;            // A voice can use more than one XMA stream.\n} XAUDIO2_PERFORMANCE_DATA;\n\n// Used in IXAudio2::SetDebugConfiguration\ntypedef struct XAUDIO2_DEBUG_CONFIGURATION\n{\n    UINT32 TraceMask;                   // Bitmap of enabled debug message types.\n    UINT32 BreakMask;                   // Message types that will break into the debugger.\n    BOOL LogThreadID;                   // Whether to log the thread ID with each message.\n    BOOL LogFileline;                   // Whether to log the source file and line number.\n    BOOL LogFunctionName;               // Whether to log the function name.\n    BOOL LogTiming;                     // Whether to log message timestamps.\n} XAUDIO2_DEBUG_CONFIGURATION;\n\n// Values for the TraceMask and BreakMask bitmaps.  Only ERRORS and WARNINGS\n// are valid in BreakMask.  WARNINGS implies ERRORS, DETAIL implies INFO, and\n// FUNC_CALLS implies API_CALLS.  By default, TraceMask is ERRORS and WARNINGS\n// and all the other settings are zero.\n#define XAUDIO2_LOG_ERRORS     0x0001   // For handled errors with serious effects.\n#define XAUDIO2_LOG_WARNINGS   0x0002   // For handled errors that may be recoverable.\n#define XAUDIO2_LOG_INFO       0x0004   // Informational chit-chat (e.g. state changes).\n#define XAUDIO2_LOG_DETAIL     0x0008   // More detailed chit-chat.\n#define XAUDIO2_LOG_API_CALLS  0x0010   // Public API function entries and exits.\n#define XAUDIO2_LOG_FUNC_CALLS 0x0020   // Internal function entries and exits.\n#define XAUDIO2_LOG_TIMING     0x0040   // Delays detected and other timing data.\n#define XAUDIO2_LOG_LOCKS      0x0080   // Usage of critical sections and mutexes.\n#define XAUDIO2_LOG_MEMORY     0x0100   // Memory heap usage information.\n#define XAUDIO2_LOG_STREAMING  0x1000   // Audio streaming information.\n\n\n/**************************************************************************\n *\n * IXAudio2: Top-level XAudio2 COM interface.\n *\n **************************************************************************/\n\n// Use default arguments if compiling as C++\n#ifdef __cplusplus\n    #define X2DEFAULT(x) =x\n#else\n    #define X2DEFAULT(x)\n#endif\n\n#undef INTERFACE\n#define INTERFACE IXAudio2\nDECLARE_INTERFACE_(IXAudio2, IUnknown)\n{\n    // NAME: IXAudio2::QueryInterface\n    // DESCRIPTION: Queries for a given COM interface on the XAudio2 object.\n    //              Only IID_IUnknown and IID_IXAudio2 are supported.\n    //\n    // ARGUMENTS:\n    //  riid - IID of the interface to be obtained.\n    //  ppvInterface - Returns a pointer to the requested interface.\n    //\n    STDMETHOD(QueryInterface) (THIS_ REFIID riid, __deref_out void** ppvInterface) PURE;\n\n    // NAME: IXAudio2::AddRef\n    // DESCRIPTION: Adds a reference to the XAudio2 object.\n    //\n    STDMETHOD_(ULONG, AddRef) (THIS) PURE;\n\n    // NAME: IXAudio2::Release\n    // DESCRIPTION: Releases a reference to the XAudio2 object.\n    //\n    STDMETHOD_(ULONG, Release) (THIS) PURE;\n\n    // NAME: IXAudio2::GetDeviceCount\n    // DESCRIPTION: Returns the number of audio output devices available.\n    //\n    // ARGUMENTS:\n    //  pCount - Returns the device count.\n    //\n    STDMETHOD(GetDeviceCount) (THIS_ __out UINT32* pCount) PURE;\n\n    // NAME: IXAudio2::GetDeviceDetails\n    // DESCRIPTION: Returns information about the device with the given index.\n    //\n    // ARGUMENTS:\n    //  Index - Index of the device to be queried.\n    //  pDeviceDetails - Returns the device details.\n    //\n    STDMETHOD(GetDeviceDetails) (THIS_ UINT32 Index, __out XAUDIO2_DEVICE_DETAILS* pDeviceDetails) PURE;\n\n    // NAME: IXAudio2::Initialize\n    // DESCRIPTION: Sets global XAudio2 parameters and prepares it for use.\n    //\n    // ARGUMENTS:\n    //  Flags - Flags specifying the XAudio2 object's behavior.  Currently unused.\n    //  XAudio2Processor - An XAUDIO2_PROCESSOR enumeration value that specifies\n    //  the hardware thread (Xbox) or processor (Windows) that XAudio2 will use.\n    //  The enumeration values are platform-specific; platform-independent code\n    //  can use XAUDIO2_DEFAULT_PROCESSOR to use the default on each platform.\n    //\n    STDMETHOD(Initialize) (THIS_ UINT32 Flags X2DEFAULT(0),\n                           XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR)) PURE;\n\n    // NAME: IXAudio2::RegisterForCallbacks\n    // DESCRIPTION: Adds a new client to receive XAudio2's engine callbacks.\n    //\n    // ARGUMENTS:\n    //  pCallback - Callback interface to be called during each processing pass.\n    //\n    STDMETHOD(RegisterForCallbacks) (__in IXAudio2EngineCallback* pCallback) PURE;\n\n    // NAME: IXAudio2::UnregisterForCallbacks\n    // DESCRIPTION: Removes an existing receiver of XAudio2 engine callbacks.\n    //\n    // ARGUMENTS:\n    //  pCallback - Previously registered callback interface to be removed.\n    //\n    STDMETHOD_(void, UnregisterForCallbacks) (__in IXAudio2EngineCallback* pCallback) PURE;\n\n    // NAME: IXAudio2::CreateSourceVoice\n    // DESCRIPTION: Creates and configures a source voice.\n    //\n    // ARGUMENTS:\n    //  ppSourceVoice - Returns the new object's IXAudio2SourceVoice interface.\n    //  pSourceFormat - Format of the audio that will be fed to the voice.\n    //  Flags - XAUDIO2_VOICE flags specifying the source voice's behavior.\n    //  MaxFrequencyRatio - Maximum SetFrequencyRatio argument to be allowed.\n    //  pCallback - Optional pointer to a client-provided callback interface.\n    //  pSendList - Optional list of voices this voice should send audio to.\n    //  pEffectChain - Optional list of effects to apply to the audio data.\n    //\n    STDMETHOD(CreateSourceVoice) (THIS_ __deref_out IXAudio2SourceVoice** ppSourceVoice,\n                                  __in const WAVEFORMATEX* pSourceFormat,\n                                  UINT32 Flags X2DEFAULT(0),\n                                  float MaxFrequencyRatio X2DEFAULT(XAUDIO2_DEFAULT_FREQ_RATIO),\n                                  __in_opt IXAudio2VoiceCallback* pCallback X2DEFAULT(NULL),\n                                  __in_opt const XAUDIO2_VOICE_SENDS* pSendList X2DEFAULT(NULL),\n                                  __in_opt const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE;\n\n    // NAME: IXAudio2::CreateSubmixVoice\n    // DESCRIPTION: Creates and configures a submix voice.\n    //\n    // ARGUMENTS:\n    //  ppSubmixVoice - Returns the new object's IXAudio2SubmixVoice interface.\n    //  InputChannels - Number of channels in this voice's input audio data.\n    //  InputSampleRate - Sample rate of this voice's input audio data.\n    //  Flags - XAUDIO2_VOICE flags specifying the submix voice's behavior.\n    //  ProcessingStage - Arbitrary number that determines the processing order.\n    //  pSendList - Optional list of voices this voice should send audio to.\n    //  pEffectChain - Optional list of effects to apply to the audio data.\n    //\n    STDMETHOD(CreateSubmixVoice) (THIS_ __deref_out IXAudio2SubmixVoice** ppSubmixVoice,\n                                  UINT32 InputChannels, UINT32 InputSampleRate,\n                                  UINT32 Flags X2DEFAULT(0), UINT32 ProcessingStage X2DEFAULT(0),\n                                  __in_opt const XAUDIO2_VOICE_SENDS* pSendList X2DEFAULT(NULL),\n                                  __in_opt const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE;\n\n\n    // NAME: IXAudio2::CreateMasteringVoice\n    // DESCRIPTION: Creates and configures a mastering voice.\n    //\n    // ARGUMENTS:\n    //  ppMasteringVoice - Returns the new object's IXAudio2MasteringVoice interface.\n    //  InputChannels - Number of channels in this voice's input audio data.\n    //  InputSampleRate - Sample rate of this voice's input audio data.\n    //  Flags - XAUDIO2_VOICE flags specifying the mastering voice's behavior.\n    //  DeviceIndex - Identifier of the device to receive the output audio.\n    //  pEffectChain - Optional list of effects to apply to the audio data.\n    //\n    STDMETHOD(CreateMasteringVoice) (THIS_ __deref_out IXAudio2MasteringVoice** ppMasteringVoice,\n                                     UINT32 InputChannels X2DEFAULT(XAUDIO2_DEFAULT_CHANNELS),\n                                     UINT32 InputSampleRate X2DEFAULT(XAUDIO2_DEFAULT_SAMPLERATE),\n                                     UINT32 Flags X2DEFAULT(0), UINT32 DeviceIndex X2DEFAULT(0),\n                                     __in_opt const XAUDIO2_EFFECT_CHAIN* pEffectChain X2DEFAULT(NULL)) PURE;\n\n    // NAME: IXAudio2::StartEngine\n    // DESCRIPTION: Creates and starts the audio processing thread.\n    //\n    STDMETHOD(StartEngine) (THIS) PURE;\n\n    // NAME: IXAudio2::StopEngine\n    // DESCRIPTION: Stops and destroys the audio processing thread.\n    //\n    STDMETHOD_(void, StopEngine) (THIS) PURE;\n\n    // NAME: IXAudio2::CommitChanges\n    // DESCRIPTION: Atomically applies a set of operations previously tagged\n    //              with a given identifier.\n    //\n    // ARGUMENTS:\n    //  OperationSet - Identifier of the set of operations to be applied.\n    //\n    STDMETHOD(CommitChanges) (THIS_ UINT32 OperationSet) PURE;\n\n    // NAME: IXAudio2::GetPerformanceData\n    // DESCRIPTION: Returns current resource usage details: memory, CPU, etc.\n    //\n    // ARGUMENTS:\n    //  pPerfData - Returns the performance data structure.\n    //\n    STDMETHOD_(void, GetPerformanceData) (THIS_ __out XAUDIO2_PERFORMANCE_DATA* pPerfData) PURE;\n\n    // NAME: IXAudio2::SetDebugConfiguration\n    // DESCRIPTION: Configures XAudio2's debug output (in debug builds only).\n    //\n    // ARGUMENTS:\n    //  pDebugConfiguration - Structure describing the debug output behavior.\n    //  pReserved - Optional parameter; must be NULL.\n    //\n    STDMETHOD_(void, SetDebugConfiguration) (THIS_ __in_opt const XAUDIO2_DEBUG_CONFIGURATION* pDebugConfiguration,\n                                             __in_opt __reserved void* pReserved X2DEFAULT(NULL)) PURE;\n};\n\n\n/**************************************************************************\n *\n * IXAudio2Voice: Base voice management interface.\n *\n **************************************************************************/\n\n#undef INTERFACE\n#define INTERFACE IXAudio2Voice\nDECLARE_INTERFACE(IXAudio2Voice)\n{\n    // These methods are declared in a macro so that the same declarations\n    // can be used in the derived voice types (IXAudio2SourceVoice, etc).\n\n    #define Declare_IXAudio2Voice_Methods() \\\n    \\\n    /* NAME: IXAudio2Voice::GetVoiceDetails\n    // DESCRIPTION: Returns the basic characteristics of this voice.\n    //\n    // ARGUMENTS:\n    //  pVoiceDetails - Returns the voice's details.\n    */\\\n    STDMETHOD_(void, GetVoiceDetails) (THIS_ __out XAUDIO2_VOICE_DETAILS* pVoiceDetails) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::SetOutputVoices\n    // DESCRIPTION: Replaces the set of submix/mastering voices that receive\n    //              this voice's output.\n    //\n    // ARGUMENTS:\n    //  pSendList - Optional list of voices this voice should send audio to.\n    */\\\n    STDMETHOD(SetOutputVoices) (THIS_ __in_opt const XAUDIO2_VOICE_SENDS* pSendList) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::SetEffectChain\n    // DESCRIPTION: Replaces this voice's current effect chain with a new one.\n    //\n    // ARGUMENTS:\n    //  pEffectChain - Structure describing the new effect chain to be used.\n    */\\\n    STDMETHOD(SetEffectChain) (THIS_ __in_opt const XAUDIO2_EFFECT_CHAIN* pEffectChain) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::EnableEffect\n    // DESCRIPTION: Enables an effect in this voice's effect chain.\n    //\n    // ARGUMENTS:\n    //  EffectIndex - Index of an effect within this voice's effect chain.\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    */\\\n    STDMETHOD(EnableEffect) (THIS_ UINT32 EffectIndex, \\\n                             UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::DisableEffect\n    // DESCRIPTION: Disables an effect in this voice's effect chain.\n    //\n    // ARGUMENTS:\n    //  EffectIndex - Index of an effect within this voice's effect chain.\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    */\\\n    STDMETHOD(DisableEffect) (THIS_ UINT32 EffectIndex, \\\n                              UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::GetEffectState\n    // DESCRIPTION: Returns the running state of an effect.\n    //\n    // ARGUMENTS:\n    //  EffectIndex - Index of an effect within this voice's effect chain.\n    //  pEnabled - Returns the enabled/disabled state of the given effect.\n    */\\\n    STDMETHOD_(void, GetEffectState) (THIS_ UINT32 EffectIndex, __out BOOL* pEnabled) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::SetEffectParameters\n    // DESCRIPTION: Sets effect-specific parameters.\n    //\n    // REMARKS: Unlike IXAPOParameters::SetParameters, this method may\n    //          be called from any thread.  XAudio2 implements\n    //          appropriate synchronization to copy the parameters to the\n    //          realtime audio processing thread.\n    //\n    // ARGUMENTS:\n    //  EffectIndex - Index of an effect within this voice's effect chain.\n    //  pParameters - Pointer to an effect-specific parameters block.\n    //  ParametersByteSize - Size of the pParameters array  in bytes.\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    */\\\n    STDMETHOD(SetEffectParameters) (THIS_ UINT32 EffectIndex, \\\n                                    __in_bcount(ParametersByteSize) const void* pParameters, \\\n                                    UINT32 ParametersByteSize, \\\n                                    UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::GetEffectParameters\n    // DESCRIPTION: Obtains the current effect-specific parameters.\n    //\n    // ARGUMENTS:\n    //  EffectIndex - Index of an effect within this voice's effect chain.\n    //  pParameters - Returns the current values of the effect-specific parameters.\n    //  ParametersByteSize - Size of the pParameters array in bytes.\n    */\\\n    STDMETHOD(GetEffectParameters) (THIS_ UINT32 EffectIndex, \\\n                                    __out_bcount(ParametersByteSize) void* pParameters, \\\n                                    UINT32 ParametersByteSize) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::SetFilterParameters\n    // DESCRIPTION: Sets this voice's filter parameters.\n    //\n    // ARGUMENTS:\n    //  pParameters - Pointer to the filter's parameter structure.\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    */\\\n    STDMETHOD(SetFilterParameters) (THIS_ __in const XAUDIO2_FILTER_PARAMETERS* pParameters, \\\n                                    UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::GetFilterParameters\n    // DESCRIPTION: Returns this voice's current filter parameters.\n    //\n    // ARGUMENTS:\n    //  pParameters - Returns the filter parameters.\n    */\\\n    STDMETHOD_(void, GetFilterParameters) (THIS_ __out XAUDIO2_FILTER_PARAMETERS* pParameters) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::SetOutputFilterParameters\n    // DESCRIPTION: Sets the filter parameters on one of this voice's sends.\n    //\n    // ARGUMENTS:\n    //  pDestinationVoice - Destination voice of the send whose filter parameters will be set.\n    //  pParameters - Pointer to the filter's parameter structure.\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    */\\\n    STDMETHOD(SetOutputFilterParameters) (THIS_ __in_opt IXAudio2Voice* pDestinationVoice, \\\n                                          __in const XAUDIO2_FILTER_PARAMETERS* pParameters, \\\n                                          UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::GetOutputFilterParameters\n    // DESCRIPTION: Returns the filter parameters from one of this voice's sends.\n    //\n    // ARGUMENTS:\n    //  pDestinationVoice - Destination voice of the send whose filter parameters will be read.\n    //  pParameters - Returns the filter parameters.\n    */\\\n    STDMETHOD_(void, GetOutputFilterParameters) (THIS_ __in_opt IXAudio2Voice* pDestinationVoice, \\\n                                                 __out XAUDIO2_FILTER_PARAMETERS* pParameters) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::SetVolume\n    // DESCRIPTION: Sets this voice's overall volume level.\n    //\n    // ARGUMENTS:\n    //  Volume - New overall volume level to be used, as an amplitude factor.\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    */\\\n    STDMETHOD(SetVolume) (THIS_ float Volume, \\\n                          UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::GetVolume\n    // DESCRIPTION: Obtains this voice's current overall volume level.\n    //\n    // ARGUMENTS:\n    //  pVolume: Returns the voice's current overall volume level.\n    */\\\n    STDMETHOD_(void, GetVolume) (THIS_ __out float* pVolume) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::SetChannelVolumes\n    // DESCRIPTION: Sets this voice's per-channel volume levels.\n    //\n    // ARGUMENTS:\n    //  Channels - Used to confirm the voice's channel count.\n    //  pVolumes - Array of per-channel volume levels to be used.\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    */\\\n    STDMETHOD(SetChannelVolumes) (THIS_ UINT32 Channels, __in_ecount(Channels) const float* pVolumes, \\\n                                  UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::GetChannelVolumes\n    // DESCRIPTION: Returns this voice's current per-channel volume levels.\n    //\n    // ARGUMENTS:\n    //  Channels - Used to confirm the voice's channel count.\n    //  pVolumes - Returns an array of the current per-channel volume levels.\n    */\\\n    STDMETHOD_(void, GetChannelVolumes) (THIS_ UINT32 Channels, __out_ecount(Channels) float* pVolumes) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::SetOutputMatrix\n    // DESCRIPTION: Sets the volume levels used to mix from each channel of this\n    //              voice's output audio to each channel of a given destination\n    //              voice's input audio.\n    //\n    // ARGUMENTS:\n    //  pDestinationVoice - The destination voice whose mix matrix to change.\n    //  SourceChannels - Used to confirm this voice's output channel count\n    //   (the number of channels produced by the last effect in the chain).\n    //  DestinationChannels - Confirms the destination voice's input channels.\n    //  pLevelMatrix - Array of [SourceChannels * DestinationChannels] send\n    //   levels.  The level used to send from source channel S to destination\n    //   channel D should be in pLevelMatrix[S + SourceChannels * D].\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    */\\\n    STDMETHOD(SetOutputMatrix) (THIS_ __in_opt IXAudio2Voice* pDestinationVoice, \\\n                                UINT32 SourceChannels, UINT32 DestinationChannels, \\\n                                __in_ecount(SourceChannels * DestinationChannels) const float* pLevelMatrix, \\\n                                UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::GetOutputMatrix\n    // DESCRIPTION: Obtains the volume levels used to send each channel of this\n    //              voice's output audio to each channel of a given destination\n    //              voice's input audio.\n    //\n    // ARGUMENTS:\n    //  pDestinationVoice - The destination voice whose mix matrix to obtain.\n    //  SourceChannels - Used to confirm this voice's output channel count\n    //   (the number of channels produced by the last effect in the chain).\n    //  DestinationChannels - Confirms the destination voice's input channels.\n    //  pLevelMatrix - Array of send levels, as above.\n    */\\\n    STDMETHOD_(void, GetOutputMatrix) (THIS_ __in_opt IXAudio2Voice* pDestinationVoice, \\\n                                       UINT32 SourceChannels, UINT32 DestinationChannels, \\\n                                       __out_ecount(SourceChannels * DestinationChannels) float* pLevelMatrix) PURE; \\\n    \\\n    /* NAME: IXAudio2Voice::DestroyVoice\n    // DESCRIPTION: Destroys this voice, stopping it if necessary and removing\n    //              it from the XAudio2 graph.\n    */\\\n    STDMETHOD_(void, DestroyVoice) (THIS) PURE\n\n    Declare_IXAudio2Voice_Methods();\n};\n\n\n/**************************************************************************\n *\n * IXAudio2SourceVoice: Source voice management interface.\n *\n **************************************************************************/\n\n#undef INTERFACE\n#define INTERFACE IXAudio2SourceVoice\nDECLARE_INTERFACE_(IXAudio2SourceVoice, IXAudio2Voice)\n{\n    // Methods from IXAudio2Voice base interface\n    Declare_IXAudio2Voice_Methods();\n\n    // NAME: IXAudio2SourceVoice::Start\n    // DESCRIPTION: Makes this voice start consuming and processing audio.\n    //\n    // ARGUMENTS:\n    //  Flags - Flags controlling how the voice should be started.\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    //\n    STDMETHOD(Start) (THIS_ UINT32 Flags X2DEFAULT(0), UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE;\n\n    // NAME: IXAudio2SourceVoice::Stop\n    // DESCRIPTION: Makes this voice stop consuming audio.\n    //\n    // ARGUMENTS:\n    //  Flags - Flags controlling how the voice should be stopped.\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    //\n    STDMETHOD(Stop) (THIS_ UINT32 Flags X2DEFAULT(0), UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE;\n\n    // NAME: IXAudio2SourceVoice::SubmitSourceBuffer\n    // DESCRIPTION: Adds a new audio buffer to this voice's input queue.\n    //\n    // ARGUMENTS:\n    //  pBuffer - Pointer to the buffer structure to be queued.\n    //  pBufferWMA - Additional structure used only when submitting XWMA data.\n    //\n    STDMETHOD(SubmitSourceBuffer) (THIS_ __in const XAUDIO2_BUFFER* pBuffer, __in_opt const XAUDIO2_BUFFER_WMA* pBufferWMA X2DEFAULT(NULL)) PURE;\n\n    // NAME: IXAudio2SourceVoice::FlushSourceBuffers\n    // DESCRIPTION: Removes all pending audio buffers from this voice's queue.\n    //\n    STDMETHOD(FlushSourceBuffers) (THIS) PURE;\n\n    // NAME: IXAudio2SourceVoice::Discontinuity\n    // DESCRIPTION: Notifies the voice of an intentional break in the stream of\n    //              audio buffers (e.g. the end of a sound), to prevent XAudio2\n    //              from interpreting an empty buffer queue as a glitch.\n    //\n    STDMETHOD(Discontinuity) (THIS) PURE;\n\n    // NAME: IXAudio2SourceVoice::ExitLoop\n    // DESCRIPTION: Breaks out of the current loop when its end is reached.\n    //\n    // ARGUMENTS:\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    //\n    STDMETHOD(ExitLoop) (THIS_ UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE;\n\n    // NAME: IXAudio2SourceVoice::GetState\n    // DESCRIPTION: Returns the number of buffers currently queued on this voice,\n    //              the pContext value associated with the currently processing\n    //              buffer (if any), and other voice state information.\n    //\n    // ARGUMENTS:\n    //  pVoiceState - Returns the state information.\n    //\n    STDMETHOD_(void, GetState) (THIS_ __out XAUDIO2_VOICE_STATE* pVoiceState) PURE;\n\n    // NAME: IXAudio2SourceVoice::SetFrequencyRatio\n    // DESCRIPTION: Sets this voice's frequency adjustment, i.e. its pitch.\n    //\n    // ARGUMENTS:\n    //  Ratio - Frequency change, expressed as source frequency / target frequency.\n    //  OperationSet - Used to identify this call as part of a deferred batch.\n    //\n    STDMETHOD(SetFrequencyRatio) (THIS_ float Ratio,\n                                  UINT32 OperationSet X2DEFAULT(XAUDIO2_COMMIT_NOW)) PURE;\n\n    // NAME: IXAudio2SourceVoice::GetFrequencyRatio\n    // DESCRIPTION: Returns this voice's current frequency adjustment ratio.\n    //\n    // ARGUMENTS:\n    //  pRatio - Returns the frequency adjustment.\n    //\n    STDMETHOD_(void, GetFrequencyRatio) (THIS_ __out float* pRatio) PURE;\n\n    // NAME: IXAudio2SourceVoice::SetSourceSampleRate\n    // DESCRIPTION: Reconfigures this voice to treat its source data as being\n    //              at a different sample rate than the original one specified\n    //              in CreateSourceVoice's pSourceFormat argument.\n    //\n    // ARGUMENTS:\n    //  UINT32 - The intended sample rate of further submitted source data.\n    //\n    STDMETHOD(SetSourceSampleRate) (THIS_ UINT32 NewSourceSampleRate) PURE;\n};\n\n\n/**************************************************************************\n *\n * IXAudio2SubmixVoice: Submixing voice management interface.\n *\n **************************************************************************/\n\n#undef INTERFACE\n#define INTERFACE IXAudio2SubmixVoice\nDECLARE_INTERFACE_(IXAudio2SubmixVoice, IXAudio2Voice)\n{\n    // Methods from IXAudio2Voice base interface\n    Declare_IXAudio2Voice_Methods();\n\n    // There are currently no methods specific to submix voices.\n};\n\n\n/**************************************************************************\n *\n * IXAudio2MasteringVoice: Mastering voice management interface.\n *\n **************************************************************************/\n\n#undef INTERFACE\n#define INTERFACE IXAudio2MasteringVoice\nDECLARE_INTERFACE_(IXAudio2MasteringVoice, IXAudio2Voice)\n{\n    // Methods from IXAudio2Voice base interface\n    Declare_IXAudio2Voice_Methods();\n\n    // There are currently no methods specific to mastering voices.\n};\n\n\n/**************************************************************************\n *\n * IXAudio2EngineCallback: Client notification interface for engine events.\n *\n * REMARKS: Contains methods to notify the client when certain events happen\n *          in the XAudio2 engine.  This interface should be implemented by\n *          the client.  XAudio2 will call these methods via the interface\n *          pointer provided by the client when it calls XAudio2Create or\n *          IXAudio2::Initialize.\n *\n **************************************************************************/\n\n#undef INTERFACE\n#define INTERFACE IXAudio2EngineCallback\nDECLARE_INTERFACE(IXAudio2EngineCallback)\n{\n    // Called by XAudio2 just before an audio processing pass begins.\n    STDMETHOD_(void, OnProcessingPassStart) (THIS) PURE;\n\n    // Called just after an audio processing pass ends.\n    STDMETHOD_(void, OnProcessingPassEnd) (THIS) PURE;\n\n    // Called in the event of a critical system error which requires XAudio2\n    // to be closed down and restarted.  The error code is given in Error.\n    STDMETHOD_(void, OnCriticalError) (THIS_ HRESULT Error) PURE;\n};\n\n\n/**************************************************************************\n *\n * IXAudio2VoiceCallback: Client notification interface for voice events.\n *\n * REMARKS: Contains methods to notify the client when certain events happen\n *          in an XAudio2 voice.  This interface should be implemented by the\n *          client.  XAudio2 will call these methods via an interface pointer\n *          provided by the client in the IXAudio2::CreateSourceVoice call.\n *\n **************************************************************************/\n\n#undef INTERFACE\n#define INTERFACE IXAudio2VoiceCallback\nDECLARE_INTERFACE(IXAudio2VoiceCallback)\n{\n    // Called just before this voice's processing pass begins.\n    STDMETHOD_(void, OnVoiceProcessingPassStart) (THIS_ UINT32 BytesRequired) PURE;\n\n    // Called just after this voice's processing pass ends.\n    STDMETHOD_(void, OnVoiceProcessingPassEnd) (THIS) PURE;\n\n    // Called when this voice has just finished playing a buffer stream\n    // (as marked with the XAUDIO2_END_OF_STREAM flag on the last buffer).\n    STDMETHOD_(void, OnStreamEnd) (THIS) PURE;\n\n    // Called when this voice is about to start processing a new buffer.\n    STDMETHOD_(void, OnBufferStart) (THIS_ void* pBufferContext) PURE;\n\n    // Called when this voice has just finished processing a buffer.\n    // The buffer can now be reused or destroyed.\n    STDMETHOD_(void, OnBufferEnd) (THIS_ void* pBufferContext) PURE;\n\n    // Called when this voice has just reached the end position of a loop.\n    STDMETHOD_(void, OnLoopEnd) (THIS_ void* pBufferContext) PURE;\n\n    // Called in the event of a critical error during voice processing,\n    // such as a failing xAPO or an error from the hardware XMA decoder.\n    // The voice may have to be destroyed and re-created to recover from\n    // the error.  The callback arguments report which buffer was being\n    // processed when the error occurred, and its HRESULT code.\n    STDMETHOD_(void, OnVoiceError) (THIS_ void* pBufferContext, HRESULT Error) PURE;\n};\n\n\n/**************************************************************************\n *\n * Macros to make it easier to use the XAudio2 COM interfaces in C code.\n *\n **************************************************************************/\n\n#ifndef __cplusplus\n\n// IXAudio2\n#define IXAudio2_QueryInterface(This,riid,ppvInterface) ((This)->lpVtbl->QueryInterface(This,riid,ppvInterface))\n#define IXAudio2_AddRef(This) ((This)->lpVtbl->AddRef(This))\n#define IXAudio2_Release(This) ((This)->lpVtbl->Release(This))\n#define IXAudio2_GetDeviceCount(This,puCount) ((This)->lpVtbl->GetDeviceCount(This,puCount))\n#define IXAudio2_GetDeviceDetails(This,Index,pDeviceDetails) ((This)->lpVtbl->GetDeviceDetails(This,Index,pDeviceDetails))\n#define IXAudio2_Initialize(This,Flags,XAudio2Processor) ((This)->lpVtbl->Initialize(This,Flags,XAudio2Processor))\n#define IXAudio2_CreateSourceVoice(This,ppSourceVoice,pSourceFormat,Flags,MaxFrequencyRatio,pCallback,pSendList,pEffectChain) ((This)->lpVtbl->CreateSourceVoice(This,ppSourceVoice,pSourceFormat,Flags,MaxFrequencyRatio,pCallback,pSendList,pEffectChain))\n#define IXAudio2_CreateSubmixVoice(This,ppSubmixVoice,InputChannels,InputSampleRate,Flags,ProcessingStage,pSendList,pEffectChain) ((This)->lpVtbl->CreateSubmixVoice(This,ppSubmixVoice,InputChannels,InputSampleRate,Flags,ProcessingStage,pSendList,pEffectChain))\n#define IXAudio2_CreateMasteringVoice(This,ppMasteringVoice,InputChannels,InputSampleRate,Flags,DeviceIndex,pEffectChain) ((This)->lpVtbl->CreateMasteringVoice(This,ppMasteringVoice,InputChannels,InputSampleRate,Flags,DeviceIndex,pEffectChain))\n#define IXAudio2_StartEngine(This) ((This)->lpVtbl->StartEngine(This))\n#define IXAudio2_StopEngine(This) ((This)->lpVtbl->StopEngine(This))\n#define IXAudio2_CommitChanges(This,OperationSet) ((This)->lpVtbl->CommitChanges(This,OperationSet))\n#define IXAudio2_GetPerformanceData(This,pPerfData) ((This)->lpVtbl->GetPerformanceData(This,pPerfData))\n#define IXAudio2_SetDebugConfiguration(This,pDebugConfiguration,pReserved) ((This)->lpVtbl->SetDebugConfiguration(This,pDebugConfiguration,pReserved))\n\n// IXAudio2Voice\n#define IXAudio2Voice_GetVoiceDetails(This,pVoiceDetails) ((This)->lpVtbl->GetVoiceDetails(This,pVoiceDetails))\n#define IXAudio2Voice_SetOutputVoices(This,pSendList) ((This)->lpVtbl->SetOutputVoices(This,pSendList))\n#define IXAudio2Voice_SetEffectChain(This,pEffectChain) ((This)->lpVtbl->SetEffectChain(This,pEffectChain))\n#define IXAudio2Voice_EnableEffect(This,EffectIndex,OperationSet) ((This)->lpVtbl->EnableEffect(This,EffectIndex,OperationSet))\n#define IXAudio2Voice_DisableEffect(This,EffectIndex,OperationSet) ((This)->lpVtbl->DisableEffect(This,EffectIndex,OperationSet))\n#define IXAudio2Voice_GetEffectState(This,EffectIndex,pEnabled) ((This)->lpVtbl->GetEffectState(This,EffectIndex,pEnabled))\n#define IXAudio2Voice_SetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize, OperationSet) ((This)->lpVtbl->SetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize,OperationSet))\n#define IXAudio2Voice_GetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize) ((This)->lpVtbl->GetEffectParameters(This,EffectIndex,pParameters,ParametersByteSize))\n#define IXAudio2Voice_SetFilterParameters(This,pParameters,OperationSet) ((This)->lpVtbl->SetFilterParameters(This,pParameters,OperationSet))\n#define IXAudio2Voice_GetFilterParameters(This,pParameters) ((This)->lpVtbl->GetFilterParameters(This,pParameters))\n#define IXAudio2Voice_SetOutputFilterParameters(This,pDestinationVoice,pParameters,OperationSet) ((This)->lpVtbl->SetOutputFilterParameters(This,pDestinationVoice,pParameters,OperationSet))\n#define IXAudio2Voice_GetOutputFilterParameters(This,pDestinationVoice,pParameters) ((This)->lpVtbl->GetOutputFilterParameters(This,pDestinationVoice,pParameters))\n#define IXAudio2Voice_SetVolume(This,Volume,OperationSet) ((This)->lpVtbl->SetVolume(This,Volume,OperationSet))\n#define IXAudio2Voice_GetVolume(This,pVolume) ((This)->lpVtbl->GetVolume(This,pVolume))\n#define IXAudio2Voice_SetChannelVolumes(This,Channels,pVolumes,OperationSet) ((This)->lpVtbl->SetChannelVolumes(This,Channels,pVolumes,OperationSet))\n#define IXAudio2Voice_GetChannelVolumes(This,Channels,pVolumes) ((This)->lpVtbl->GetChannelVolumes(This,Channels,pVolumes))\n#define IXAudio2Voice_SetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix,OperationSet) ((This)->lpVtbl->SetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix,OperationSet))\n#define IXAudio2Voice_GetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix) ((This)->lpVtbl->GetOutputMatrix(This,pDestinationVoice,SourceChannels,DestinationChannels,pLevelMatrix))\n#define IXAudio2Voice_DestroyVoice(This) ((This)->lpVtbl->DestroyVoice(This))\n\n// IXAudio2SourceVoice\n#define IXAudio2SourceVoice_GetVoiceDetails IXAudio2Voice_GetVoiceDetails\n#define IXAudio2SourceVoice_SetOutputVoices IXAudio2Voice_SetOutputVoices\n#define IXAudio2SourceVoice_SetEffectChain IXAudio2Voice_SetEffectChain\n#define IXAudio2SourceVoice_EnableEffect IXAudio2Voice_EnableEffect\n#define IXAudio2SourceVoice_DisableEffect IXAudio2Voice_DisableEffect\n#define IXAudio2SourceVoice_GetEffectState IXAudio2Voice_GetEffectState\n#define IXAudio2SourceVoice_SetEffectParameters IXAudio2Voice_SetEffectParameters\n#define IXAudio2SourceVoice_GetEffectParameters IXAudio2Voice_GetEffectParameters\n#define IXAudio2SourceVoice_SetFilterParameters IXAudio2Voice_SetFilterParameters\n#define IXAudio2SourceVoice_GetFilterParameters IXAudio2Voice_GetFilterParameters\n#define IXAudio2SourceVoice_SetOutputFilterParameters IXAudio2Voice_SetOutputFilterParameters\n#define IXAudio2SourceVoice_GetOutputFilterParameters IXAudio2Voice_GetOutputFilterParameters\n#define IXAudio2SourceVoice_SetVolume IXAudio2Voice_SetVolume\n#define IXAudio2SourceVoice_GetVolume IXAudio2Voice_GetVolume\n#define IXAudio2SourceVoice_SetChannelVolumes IXAudio2Voice_SetChannelVolumes\n#define IXAudio2SourceVoice_GetChannelVolumes IXAudio2Voice_GetChannelVolumes\n#define IXAudio2SourceVoice_SetOutputMatrix IXAudio2Voice_SetOutputMatrix\n#define IXAudio2SourceVoice_GetOutputMatrix IXAudio2Voice_GetOutputMatrix\n#define IXAudio2SourceVoice_DestroyVoice IXAudio2Voice_DestroyVoice\n#define IXAudio2SourceVoice_Start(This,Flags,OperationSet) ((This)->lpVtbl->Start(This,Flags,OperationSet))\n#define IXAudio2SourceVoice_Stop(This,Flags,OperationSet) ((This)->lpVtbl->Stop(This,Flags,OperationSet))\n#define IXAudio2SourceVoice_SubmitSourceBuffer(This,pBuffer,pBufferWMA) ((This)->lpVtbl->SubmitSourceBuffer(This,pBuffer,pBufferWMA))\n#define IXAudio2SourceVoice_FlushSourceBuffers(This) ((This)->lpVtbl->FlushSourceBuffers(This))\n#define IXAudio2SourceVoice_Discontinuity(This) ((This)->lpVtbl->Discontinuity(This))\n#define IXAudio2SourceVoice_ExitLoop(This,OperationSet) ((This)->lpVtbl->ExitLoop(This,OperationSet))\n#define IXAudio2SourceVoice_GetState(This,pVoiceState) ((This)->lpVtbl->GetState(This,pVoiceState))\n#define IXAudio2SourceVoice_SetFrequencyRatio(This,Ratio,OperationSet) ((This)->lpVtbl->SetFrequencyRatio(This,Ratio,OperationSet))\n#define IXAudio2SourceVoice_GetFrequencyRatio(This,pRatio) ((This)->lpVtbl->GetFrequencyRatio(This,pRatio))\n#define IXAudio2SourceVoice_SetSourceSampleRate(This,NewSourceSampleRate) ((This)->lpVtbl->SetSourceSampleRate(This,NewSourceSampleRate))\n\n// IXAudio2SubmixVoice\n#define IXAudio2SubmixVoice_GetVoiceDetails IXAudio2Voice_GetVoiceDetails\n#define IXAudio2SubmixVoice_SetOutputVoices IXAudio2Voice_SetOutputVoices\n#define IXAudio2SubmixVoice_SetEffectChain IXAudio2Voice_SetEffectChain\n#define IXAudio2SubmixVoice_EnableEffect IXAudio2Voice_EnableEffect\n#define IXAudio2SubmixVoice_DisableEffect IXAudio2Voice_DisableEffect\n#define IXAudio2SubmixVoice_GetEffectState IXAudio2Voice_GetEffectState\n#define IXAudio2SubmixVoice_SetEffectParameters IXAudio2Voice_SetEffectParameters\n#define IXAudio2SubmixVoice_GetEffectParameters IXAudio2Voice_GetEffectParameters\n#define IXAudio2SubmixVoice_SetFilterParameters IXAudio2Voice_SetFilterParameters\n#define IXAudio2SubmixVoice_GetFilterParameters IXAudio2Voice_GetFilterParameters\n#define IXAudio2SubmixVoice_SetOutputFilterParameters IXAudio2Voice_SetOutputFilterParameters\n#define IXAudio2SubmixVoice_GetOutputFilterParameters IXAudio2Voice_GetOutputFilterParameters\n#define IXAudio2SubmixVoice_SetVolume IXAudio2Voice_SetVolume\n#define IXAudio2SubmixVoice_GetVolume IXAudio2Voice_GetVolume\n#define IXAudio2SubmixVoice_SetChannelVolumes IXAudio2Voice_SetChannelVolumes\n#define IXAudio2SubmixVoice_GetChannelVolumes IXAudio2Voice_GetChannelVolumes\n#define IXAudio2SubmixVoice_SetOutputMatrix IXAudio2Voice_SetOutputMatrix\n#define IXAudio2SubmixVoice_GetOutputMatrix IXAudio2Voice_GetOutputMatrix\n#define IXAudio2SubmixVoice_DestroyVoice IXAudio2Voice_DestroyVoice\n\n// IXAudio2MasteringVoice\n#define IXAudio2MasteringVoice_GetVoiceDetails IXAudio2Voice_GetVoiceDetails\n#define IXAudio2MasteringVoice_SetOutputVoices IXAudio2Voice_SetOutputVoices\n#define IXAudio2MasteringVoice_SetEffectChain IXAudio2Voice_SetEffectChain\n#define IXAudio2MasteringVoice_EnableEffect IXAudio2Voice_EnableEffect\n#define IXAudio2MasteringVoice_DisableEffect IXAudio2Voice_DisableEffect\n#define IXAudio2MasteringVoice_GetEffectState IXAudio2Voice_GetEffectState\n#define IXAudio2MasteringVoice_SetEffectParameters IXAudio2Voice_SetEffectParameters\n#define IXAudio2MasteringVoice_GetEffectParameters IXAudio2Voice_GetEffectParameters\n#define IXAudio2MasteringVoice_SetFilterParameters IXAudio2Voice_SetFilterParameters\n#define IXAudio2MasteringVoice_GetFilterParameters IXAudio2Voice_GetFilterParameters\n#define IXAudio2MasteringVoice_SetOutputFilterParameters IXAudio2Voice_SetOutputFilterParameters\n#define IXAudio2MasteringVoice_GetOutputFilterParameters IXAudio2Voice_GetOutputFilterParameters\n#define IXAudio2MasteringVoice_SetVolume IXAudio2Voice_SetVolume\n#define IXAudio2MasteringVoice_GetVolume IXAudio2Voice_GetVolume\n#define IXAudio2MasteringVoice_SetChannelVolumes IXAudio2Voice_SetChannelVolumes\n#define IXAudio2MasteringVoice_GetChannelVolumes IXAudio2Voice_GetChannelVolumes\n#define IXAudio2MasteringVoice_SetOutputMatrix IXAudio2Voice_SetOutputMatrix\n#define IXAudio2MasteringVoice_GetOutputMatrix IXAudio2Voice_GetOutputMatrix\n#define IXAudio2MasteringVoice_DestroyVoice IXAudio2Voice_DestroyVoice\n\n#endif // #ifndef __cplusplus\n\n\n/**************************************************************************\n *\n * Utility functions used to convert from pitch in semitones and volume\n * in decibels to the frequency and amplitude ratio units used by XAudio2.\n * These are only defined if the client #defines XAUDIO2_HELPER_FUNCTIONS\n * prior to #including xaudio2.h.\n *\n **************************************************************************/\n\n#ifdef XAUDIO2_HELPER_FUNCTIONS\n\n#define _USE_MATH_DEFINES   // Make math.h define M_PI\n#include <math.h>           // For powf, log10f, sinf and asinf\n\n// Calculate the argument to SetVolume from a decibel value\n__inline float XAudio2DecibelsToAmplitudeRatio(float Decibels)\n{\n    return powf(10.0f, Decibels / 20.0f);\n}\n\n// Recover a volume in decibels from an amplitude factor\n__inline float XAudio2AmplitudeRatioToDecibels(float Volume)\n{\n    if (Volume == 0)\n    {\n        return -3.402823466e+38f; // Smallest float value (-FLT_MAX)\n    }\n    return 20.0f * log10f(Volume);\n}\n\n// Calculate the argument to SetFrequencyRatio from a semitone value\n__inline float XAudio2SemitonesToFrequencyRatio(float Semitones)\n{\n    // FrequencyRatio = 2 ^ Octaves\n    //                = 2 ^ (Semitones / 12)\n    return powf(2.0f, Semitones / 12.0f);\n}\n\n// Recover a pitch in semitones from a frequency ratio\n__inline float XAudio2FrequencyRatioToSemitones(float FrequencyRatio)\n{\n    // Semitones = 12 * log2(FrequencyRatio)\n    //           = 12 * log2(10) * log10(FrequencyRatio)\n    return 39.86313713864835f * log10f(FrequencyRatio);\n}\n\n// Convert from filter cutoff frequencies expressed in Hertz to the radian\n// frequency values used in XAUDIO2_FILTER_PARAMETERS.Frequency.  Note that\n// the highest CutoffFrequency supported is SampleRate/6.  Higher values of\n// CutoffFrequency will return XAUDIO2_MAX_FILTER_FREQUENCY.\n__inline float XAudio2CutoffFrequencyToRadians(float CutoffFrequency, UINT32 SampleRate)\n{\n    if ((UINT32)(CutoffFrequency * 6.0f) >= SampleRate)\n    {\n        return XAUDIO2_MAX_FILTER_FREQUENCY;\n    }\n    return 2.0f * sinf((float)M_PI * CutoffFrequency / SampleRate);\n}\n\n// Convert from radian frequencies back to absolute frequencies in Hertz\n__inline float XAudio2RadiansToCutoffFrequency(float Radians, float SampleRate)\n{\n    return SampleRate * asinf(Radians / 2.0f) / (float)M_PI;\n}\n#endif // #ifdef XAUDIO2_HELPER_FUNCTIONS\n\n\n/**************************************************************************\n *\n * XAudio2Create: Top-level function that creates an XAudio2 instance.\n *\n * On Windows this is just an inline function that calls CoCreateInstance\n * and Initialize.  The arguments are described above, under Initialize,\n * except that the XAUDIO2_DEBUG_ENGINE flag can be used here to select\n * the debug version of XAudio2.\n *\n * On Xbox, this function is implemented in the XAudio2 library, and the\n * XAUDIO2_DEBUG_ENGINE flag has no effect; the client must explicitly\n * link with the debug version of the library to obtain debug behavior.\n *\n **************************************************************************/\n\n#ifdef _XBOX\n\nSTDAPI XAudio2Create(__deref_out IXAudio2** ppXAudio2, UINT32 Flags X2DEFAULT(0),\n                     XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR));\n\n#else // Windows\n\n__inline HRESULT XAudio2Create(__deref_out IXAudio2** ppXAudio2, UINT32 Flags X2DEFAULT(0),\n                               XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR))\n{\n    // Instantiate the appropriate XAudio2 engine\n    IXAudio2* pXAudio2;\n\n    #ifdef __cplusplus\n\n        HRESULT hr = CoCreateInstance((Flags & XAUDIO2_DEBUG_ENGINE) ? __uuidof(XAudio2_Debug) : __uuidof(XAudio2),\n                                      NULL, CLSCTX_INPROC_SERVER, __uuidof(IXAudio2), (void**)&pXAudio2);\n        if (SUCCEEDED(hr))\n        {\n            hr = pXAudio2->Initialize(Flags, XAudio2Processor);\n\n            if (SUCCEEDED(hr))\n            {\n                *ppXAudio2 = pXAudio2;\n            }\n            else\n            {\n                pXAudio2->Release();\n            }\n        }\n\n    #else\n\n        HRESULT hr = CoCreateInstance((Flags & XAUDIO2_DEBUG_ENGINE) ? &CLSID_XAudio2_Debug : &CLSID_XAudio2,\n                                      NULL, CLSCTX_INPROC_SERVER, &IID_IXAudio2, (void**)&pXAudio2);\n        if (SUCCEEDED(hr))\n        {\n            hr = pXAudio2->lpVtbl->Initialize(pXAudio2, Flags, XAudio2Processor);\n\n            if (SUCCEEDED(hr))\n            {\n                *ppXAudio2 = pXAudio2;\n            }\n            else\n            {\n                pXAudio2->lpVtbl->Release(pXAudio2);\n            }\n        }\n\n    #endif // #ifdef __cplusplus\n\n    return hr;\n}\n\n#endif // #ifdef _XBOX\n\n\n// Undo the #pragma pack(push, 1) directive at the top of this file\n#pragma pack(pop)\n\n#endif // #ifndef GUID_DEFS_ONLY\n#endif // #ifndef __XAUDIO2_INCLUDED__\n"
  },
  {
    "path": "dependencies/DirectX_2010/audiodefs.h",
    "content": "/***************************************************************************\n *\n *  Copyright (c) Microsoft Corporation.  All rights reserved.\n *\n *  File:     audiodefs.h\n *  Content:  Basic constants and data types for audio work.\n *\n *  Remarks:  This header file defines all of the audio format constants and\n *            structures required for XAudio2 and XACT work.  Providing these\n *            in a single location avoids certain dependency problems in the\n *            legacy audio headers (mmreg.h, mmsystem.h, ksmedia.h).\n *\n *            NOTE: Including the legacy headers after this one may cause a\n *            compilation error, because they define some of the same types\n *            defined here without preprocessor guards to avoid multiple\n *            definitions.  If a source file needs one of the old headers,\n *            it must include it before including audiodefs.h.\n *\n ***************************************************************************/\n\n#ifndef __AUDIODEFS_INCLUDED__\n#define __AUDIODEFS_INCLUDED__\n\n#include <windef.h>  // For WORD, DWORD, etc.\n\n#pragma pack(push, 1)  // Pack structures to 1-byte boundaries\n\n\n/**************************************************************************\n *\n *  WAVEFORMATEX: Base structure for many audio formats.  Format-specific\n *  extensions can be defined for particular formats by using a non-zero\n *  cbSize value and adding extra fields to the end of this structure.\n *\n ***************************************************************************/\n\n#ifndef _WAVEFORMATEX_\n\n    #define _WAVEFORMATEX_\n    typedef struct tWAVEFORMATEX\n    {\n        WORD wFormatTag;        // Integer identifier of the format\n        WORD nChannels;         // Number of audio channels\n        DWORD nSamplesPerSec;   // Audio sample rate\n        DWORD nAvgBytesPerSec;  // Bytes per second (possibly approximate)\n        WORD nBlockAlign;       // Size in bytes of a sample block (all channels)\n        WORD wBitsPerSample;    // Size in bits of a single per-channel sample\n        WORD cbSize;            // Bytes of extra data appended to this struct\n    } WAVEFORMATEX;\n\n#endif\n\n// Defining pointer types outside of the #if block to make sure they are\n// defined even if mmreg.h or mmsystem.h is #included before this file\n\ntypedef WAVEFORMATEX *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;\ntypedef const WAVEFORMATEX *PCWAVEFORMATEX, *LPCWAVEFORMATEX;\n\n\n/**************************************************************************\n *\n *  WAVEFORMATEXTENSIBLE: Extended version of WAVEFORMATEX that should be\n *  used as a basis for all new audio formats.  The format tag is replaced\n *  with a GUID, allowing new formats to be defined without registering a\n *  format tag with Microsoft.  There are also new fields that can be used\n *  to specify the spatial positions for each channel and the bit packing\n *  used for wide samples (e.g. 24-bit PCM samples in 32-bit containers).\n *\n ***************************************************************************/\n\n#ifndef _WAVEFORMATEXTENSIBLE_\n\n    #define _WAVEFORMATEXTENSIBLE_\n    typedef struct\n    {\n        WAVEFORMATEX Format;          // Base WAVEFORMATEX data\n        union\n        {\n            WORD wValidBitsPerSample; // Valid bits in each sample container\n            WORD wSamplesPerBlock;    // Samples per block of audio data; valid\n                                      // if wBitsPerSample=0 (but rarely used).\n            WORD wReserved;           // Zero if neither case above applies.\n        } Samples;\n        DWORD dwChannelMask;          // Positions of the audio channels\n        GUID SubFormat;               // Format identifier GUID\n    } WAVEFORMATEXTENSIBLE;\n\n#endif\n\ntypedef WAVEFORMATEXTENSIBLE *PWAVEFORMATEXTENSIBLE, *LPWAVEFORMATEXTENSIBLE;\ntypedef const WAVEFORMATEXTENSIBLE *PCWAVEFORMATEXTENSIBLE, *LPCWAVEFORMATEXTENSIBLE;\n\n\n\n/**************************************************************************\n *\n *  Define the most common wave format tags used in WAVEFORMATEX formats.\n *\n ***************************************************************************/\n\n#ifndef WAVE_FORMAT_PCM  // Pulse Code Modulation\n\n    // If WAVE_FORMAT_PCM is not defined, we need to define some legacy types\n    // for compatibility with the Windows mmreg.h / mmsystem.h header files.\n\n    // Old general format structure (information common to all formats)\n    typedef struct waveformat_tag\n    {\n        WORD wFormatTag;\n        WORD nChannels;\n        DWORD nSamplesPerSec;\n        DWORD nAvgBytesPerSec;\n        WORD nBlockAlign;\n    } WAVEFORMAT, *PWAVEFORMAT, NEAR *NPWAVEFORMAT, FAR *LPWAVEFORMAT;\n\n    // Specific format structure for PCM data\n    typedef struct pcmwaveformat_tag\n    {\n        WAVEFORMAT wf;\n        WORD wBitsPerSample;\n    } PCMWAVEFORMAT, *PPCMWAVEFORMAT, NEAR *NPPCMWAVEFORMAT, FAR *LPPCMWAVEFORMAT;\n\n    #define WAVE_FORMAT_PCM 0x0001\n\n#endif\n\n#ifndef WAVE_FORMAT_ADPCM  // Microsoft Adaptive Differental PCM\n\n    // Replicate the Microsoft ADPCM type definitions from mmreg.h.\n\n    typedef struct adpcmcoef_tag\n    {\n        short iCoef1;\n        short iCoef2;\n    } ADPCMCOEFSET;\n\n    #pragma warning(push)\n    #pragma warning(disable:4200)  // Disable zero-sized array warnings\n\n    typedef struct adpcmwaveformat_tag {\n        WAVEFORMATEX wfx;\n        WORD wSamplesPerBlock;\n        WORD wNumCoef;\n        ADPCMCOEFSET aCoef[];  // Always 7 coefficient pairs for MS ADPCM\n    } ADPCMWAVEFORMAT;\n\n    #pragma warning(pop)\n\n    #define WAVE_FORMAT_ADPCM 0x0002\n\n#endif\n\n// Other frequently used format tags\n\n#ifndef WAVE_FORMAT_UNKNOWN\n    #define WAVE_FORMAT_UNKNOWN         0x0000 // Unknown or invalid format tag\n#endif\n\n#ifndef WAVE_FORMAT_IEEE_FLOAT\n    #define WAVE_FORMAT_IEEE_FLOAT      0x0003 // 32-bit floating-point\n#endif\n\n#ifndef WAVE_FORMAT_MPEGLAYER3\n    #define WAVE_FORMAT_MPEGLAYER3      0x0055 // ISO/MPEG Layer3\n#endif\n\n#ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF\n    #define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 // Dolby Audio Codec 3 over S/PDIF\n#endif\n\n#ifndef WAVE_FORMAT_WMAUDIO2\n    #define WAVE_FORMAT_WMAUDIO2        0x0161 // Windows Media Audio\n#endif\n\n#ifndef WAVE_FORMAT_WMAUDIO3\n    #define WAVE_FORMAT_WMAUDIO3        0x0162 // Windows Media Audio Pro\n#endif\n\n#ifndef WAVE_FORMAT_WMASPDIF\n    #define WAVE_FORMAT_WMASPDIF        0x0164 // Windows Media Audio over S/PDIF\n#endif\n\n#ifndef WAVE_FORMAT_EXTENSIBLE\n    #define WAVE_FORMAT_EXTENSIBLE      0xFFFE // All WAVEFORMATEXTENSIBLE formats\n#endif\n\n\n/**************************************************************************\n *\n *  Define the most common wave format GUIDs used in WAVEFORMATEXTENSIBLE\n *  formats.  Note that including the Windows ksmedia.h header after this\n *  one will cause build problems; this cannot be avoided, since ksmedia.h\n *  defines these macros without preprocessor guards.\n *\n ***************************************************************************/\n\n#ifdef __cplusplus // uuid() and __uuidof() are only available in C++\n\n    #ifndef KSDATAFORMAT_SUBTYPE_PCM\n        struct __declspec(uuid(\"00000001-0000-0010-8000-00aa00389b71\")) KSDATAFORMAT_SUBTYPE_PCM_STRUCT;\n        #define KSDATAFORMAT_SUBTYPE_PCM __uuidof(KSDATAFORMAT_SUBTYPE_PCM_STRUCT)\n    #endif\n\n    #ifndef KSDATAFORMAT_SUBTYPE_ADPCM\n        struct __declspec(uuid(\"00000002-0000-0010-8000-00aa00389b71\")) KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT;\n        #define KSDATAFORMAT_SUBTYPE_ADPCM __uuidof(KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT)\n    #endif\n\n    #ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n        struct __declspec(uuid(\"00000003-0000-0010-8000-00aa00389b71\")) KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT;\n        #define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT __uuidof(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT)\n    #endif\n\n#endif\n\n\n/**************************************************************************\n *\n *  Speaker positions used in the WAVEFORMATEXTENSIBLE dwChannelMask field.\n *\n ***************************************************************************/\n\n#ifndef SPEAKER_FRONT_LEFT\n    #define SPEAKER_FRONT_LEFT            0x00000001\n    #define SPEAKER_FRONT_RIGHT           0x00000002\n    #define SPEAKER_FRONT_CENTER          0x00000004\n    #define SPEAKER_LOW_FREQUENCY         0x00000008\n    #define SPEAKER_BACK_LEFT             0x00000010\n    #define SPEAKER_BACK_RIGHT            0x00000020\n    #define SPEAKER_FRONT_LEFT_OF_CENTER  0x00000040\n    #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080\n    #define SPEAKER_BACK_CENTER           0x00000100\n    #define SPEAKER_SIDE_LEFT             0x00000200\n    #define SPEAKER_SIDE_RIGHT            0x00000400\n    #define SPEAKER_TOP_CENTER            0x00000800\n    #define SPEAKER_TOP_FRONT_LEFT        0x00001000\n    #define SPEAKER_TOP_FRONT_CENTER      0x00002000\n    #define SPEAKER_TOP_FRONT_RIGHT       0x00004000\n    #define SPEAKER_TOP_BACK_LEFT         0x00008000\n    #define SPEAKER_TOP_BACK_CENTER       0x00010000\n    #define SPEAKER_TOP_BACK_RIGHT        0x00020000\n    #define SPEAKER_RESERVED              0x7FFC0000\n    #define SPEAKER_ALL                   0x80000000\n    #define _SPEAKER_POSITIONS_\n#endif\n\n#ifndef SPEAKER_STEREO\n    #define SPEAKER_MONO             (SPEAKER_FRONT_CENTER)\n    #define SPEAKER_STEREO           (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)\n    #define SPEAKER_2POINT1          (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY)\n    #define SPEAKER_SURROUND         (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER)\n    #define SPEAKER_QUAD             (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)\n    #define SPEAKER_4POINT1          (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)\n    #define SPEAKER_5POINT1          (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)\n    #define SPEAKER_7POINT1          (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER)\n    #define SPEAKER_5POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)\n    #define SPEAKER_7POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT  | SPEAKER_SIDE_RIGHT)\n#endif\n\n\n#pragma pack(pop)\n\n#endif // #ifndef __AUDIODEFS_INCLUDED__\n"
  },
  {
    "path": "dependencies/DirectX_2010/comdecl.h",
    "content": "// comdecl.h: Macros to facilitate COM interface and GUID declarations.\n// Copyright (c) Microsoft Corporation.  All rights reserved.\n\n#ifndef _COMDECL_H_\n#define _COMDECL_H_\n\n#ifndef _XBOX\n    #include <basetyps.h>   // For standard COM interface macros\n#else\n    #pragma warning(push)\n    #pragma warning(disable:4061)\n    #include <xtl.h>        // Required by xobjbase.h\n    #include <xobjbase.h>   // Special definitions for Xbox build\n    #pragma warning(pop)\n#endif\n\n// The DEFINE_CLSID() and DEFINE_IID() macros defined below allow COM GUIDs to\n// be declared and defined in such a way that clients can obtain the GUIDs using\n// either the __uuidof() extension or the old-style CLSID_Foo / IID_IFoo names.\n// If using the latter approach, the client can also choose whether to get the\n// GUID definitions by defining the INITGUID preprocessor constant or by linking\n// to a GUID library.  This works in either C or C++.\n\n#ifdef __cplusplus\n\n    #define DECLSPEC_UUID_WRAPPER(x) __declspec(uuid(#x))\n    #ifdef INITGUID\n\n        #define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n            class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \\\n            EXTERN_C const GUID DECLSPEC_SELECTANY CLSID_##className = __uuidof(className)\n\n        #define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n            interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \\\n            EXTERN_C const GUID DECLSPEC_SELECTANY IID_##interfaceName = __uuidof(interfaceName)\n\n    #else // INITGUID\n\n        #define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n            class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \\\n            EXTERN_C const GUID CLSID_##className\n\n        #define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n            interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \\\n            EXTERN_C const GUID IID_##interfaceName\n\n    #endif // INITGUID\n\n#else // __cplusplus\n\n    #define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n        DEFINE_GUID(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)\n\n    #define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n        DEFINE_GUID(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)\n\n#endif // __cplusplus\n\n#endif // #ifndef _COMDECL_H_\n"
  },
  {
    "path": "dependencies/DirectX_2010/xma2defs.h",
    "content": "/***************************************************************************\n *\n * Copyright (c) Microsoft Corporation.  All rights reserved.\n *\n * File:     xma2defs.h\n * Content:  Constants, data types and functions for XMA2 compressed audio.\n *\n ***************************************************************************/\n\n#ifndef __XMA2DEFS_INCLUDED__\n#define __XMA2DEFS_INCLUDED__\n\n#include <sal.h>        // Markers for documenting API semantics\n#include <winerror.h>   // For S_OK, E_FAIL\n#include \"audiodefs.h\"  // Basic data types and constants for audio work\n\n\n/***************************************************************************\n *  Overview\n ***************************************************************************/\n\n// A typical XMA2 file contains these RIFF chunks:\n//\n// 'fmt' or 'XMA2' chunk (or both): A description of the XMA data's structure\n// and characteristics (length, channels, sample rate, loops, block size, etc).\n//\n// 'seek' chunk: A seek table to help navigate the XMA data.\n//\n// 'data' chunk: The encoded XMA2 data.\n//\n// The encoded XMA2 data is structured as a set of BLOCKS, which contain PACKETS,\n// which contain FRAMES, which contain SUBFRAMES (roughly speaking).  The frames\n// in a file may also be divided into several subsets, called STREAMS.\n//\n// FRAME: A variable-sized segment of XMA data that decodes to exactly 512 mono\n//      or stereo PCM samples.  This is the smallest unit of XMA data that can\n//      be decoded in isolation.  Frames are an arbitrary number of bits in\n//      length, and need not be byte-aligned.  See \"XMA frame structure\" below.\n//\n// SUBFRAME: A region of bits in an XMA frame that decodes to 128 mono or stereo\n//      samples.  The XMA decoder cannot decode a subframe in isolation; it needs\n//      a whole frame to work with.  However, it can begin emitting the frame's\n//      decoded samples at any one of the four subframe boundaries.  Subframes\n//      can be addressed for seeking and looping purposes.\n//\n// PACKET: A 2Kb region containing a 32-bit header and some XMA frames.  Frames\n//      can (and usually do) span packets.  A packet's header includes the offset\n//      in bits of the first frame that begins within that packet.  All of the\n//      frames that begin in a given packet belong to the same \"stream\" (see the\n//      Multichannel Audio section below).\n//\n// STREAM: A set of packets within an XMA file that all contain data for the\n//      same mono or stereo component of a PCM file with more than two channels.\n//      The packets comprising a given stream may be interleaved with each other\n//      more or less arbitrarily; see Multichannel Audio.\n//\n// BLOCK: An array of XMA packets; or, to break it down differently, a series of\n//      consecutive XMA frames, padded at the end with reserved data.  A block\n//      must contain at least one 2Kb packet per stream, and it can hold up to\n//      4095 packets (8190Kb), but its size is typically in the 32Kb-128Kb range.\n//      (The size chosen involves a trade-off between memory use and efficiency\n//      of reading from permanent storage.)\n//\n//      XMA frames do not span blocks, so a block is guaranteed to begin with a\n//      set of complete frames, one per stream.  Also, a block in a multi-stream\n//      XMA2 file always contains the same number of samples for each stream;\n//      see Multichannel Audio.\n//\n// The 'data' chunk in an XMA2 file is an array of XMA2WAVEFORMAT.BlockCount XMA\n// blocks, all the same size (as specified in XMA2WAVEFORMAT.BlockSizeInBytes)\n// except for the last one, which may be shorter.\n\n\n// MULTICHANNEL AUDIO: the XMA decoder can only decode raw XMA data into either\n// mono or stereo PCM data.  In order to encode a 6-channel file (say), the file\n// must be deinterleaved into 3 stereo streams that are encoded independently,\n// producing 3 encoded XMA data streams.  Then the packets in these 3 streams\n// are interleaved to produce a single XMA2 file, and some information is added\n// to the file so that the original 6-channel audio can be reconstructed at\n// decode time.  This works using the concept of an XMA stream (see above).\n//\n// The frames for all the streams in an XMA file are interleaved in an arbitrary\n// order.  To locate a frame that belongs to a given stream in a given XMA block,\n// you must examine the first few packets in the block.  Here (and only here) the\n// packets are guaranteed to be presented in stream order, so that all frames\n// beginning in packet 0 belong to stream 0 (the first stereo pair), etc.\n//\n// (This means that when decoding multi-stream XMA files, only entire XMA blocks\n// should be submitted to the decoder; otherwise it cannot know which frames\n// belong to which stream.)\n//\n// Once you have one frame that belongs to a given stream, you can find the next\n// one by looking at the frame's 'NextFrameOffsetBits' value (which is stored in\n// its first 15 bits; see XMAFRAME below).  The GetXmaFrameBitPosition function\n// uses this technique.\n\n\n// SEEKING IN XMA2 FILES: Here is some pseudocode to find the byte position and\n// subframe in an XMA2 file which will contain sample S when decoded.\n//\n// 1. Traverse the seek table to find the XMA2 block containing sample S. The\n//    seek table is an array of big-endian DWORDs, one per block in the file.\n//    The Nth DWORD is the total number of PCM samples that would be obtained\n//    by decoding the entire XMA file up to the end of block N.  Hence, the\n//    block we want is the first one whose seek table entry is greater than S.\n//    (See the GetXmaBlockContainingSample helper function.)\n//\n// 2. Calculate which frame F within the block found above contains sample S.\n//    Since each frame decodes to 512 samples, this is straightforward.  The\n//    first frame in the block produces samples X to X + 512, where X is the\n//    seek table entry for the prior block.  So F is (S - X) / 512.\n//\n// 3. Find the bit offset within the block where frame F starts.  Since frames\n//    are variable-sized, this can only be done by traversing all the frames in\n//    the block until we reach frame F.  (See GetXmaFrameBitPosition.)\n//\n// 4. Frame F has four 128-sample subframes.  To find the subframe containing S,\n//    we can use the formula (S % 512) / 128.\n//\n// In the case of multi-stream XMA files, sample S is a multichannel sample with\n// parts coming from several frames, one per stream.  To find all these frames,\n// steps 2-4 need to be repeated for each stream N, using the knowledge that the\n// first packets in a block are presented in stream order.  The frame traversal\n// in step 3 must be started at the first frame in the Nth packet of the block,\n// which will be the first frame for stream N.  (And the packet header will tell\n// you the first frame's start position within the packet.)\n//\n// Step 1 can be performed using the GetXmaBlockContainingSample function below,\n// and steps 2-4 by calling GetXmaDecodePositionForSample once for each stream.\n\n\n\n/***************************************************************************\n *  XMA constants\n ***************************************************************************/\n\n// Size of the PCM samples produced by the XMA decoder\n#define XMA_OUTPUT_SAMPLE_BYTES         2u\n#define XMA_OUTPUT_SAMPLE_BITS          (XMA_OUTPUT_SAMPLE_BYTES * 8u)\n\n// Size of an XMA packet\n#define XMA_BYTES_PER_PACKET            2048u\n#define XMA_BITS_PER_PACKET             (XMA_BYTES_PER_PACKET * 8u)\n\n// Size of an XMA packet header\n#define XMA_PACKET_HEADER_BYTES         4u\n#define XMA_PACKET_HEADER_BITS          (XMA_PACKET_HEADER_BYTES * 8u)\n\n// Sample blocks in a decoded XMA frame\n#define XMA_SAMPLES_PER_FRAME           512u\n\n// Sample blocks in a decoded XMA subframe\n#define XMA_SAMPLES_PER_SUBFRAME        128u\n\n// Maximum encoded data that can be submitted to the XMA decoder at a time\n#define XMA_READBUFFER_MAX_PACKETS      4095u\n#define XMA_READBUFFER_MAX_BYTES        (XMA_READBUFFER_MAX_PACKETS * XMA_BYTES_PER_PACKET)\n\n// Maximum size allowed for the XMA decoder's output buffers\n#define XMA_WRITEBUFFER_MAX_BYTES       (31u * 256u)\n\n// Required byte alignment of the XMA decoder's output buffers\n#define XMA_WRITEBUFFER_BYTE_ALIGNMENT  256u\n\n// Decode chunk sizes for the XMA_PLAYBACK_INIT.subframesToDecode field\n#define XMA_MIN_SUBFRAMES_TO_DECODE     1u\n#define XMA_MAX_SUBFRAMES_TO_DECODE     8u\n#define XMA_OPTIMAL_SUBFRAMES_TO_DECODE 4u\n\n// LoopCount<255 means finite repetitions; LoopCount=255 means infinite looping\n#define XMA_MAX_LOOPCOUNT               254u\n#define XMA_INFINITE_LOOP               255u\n\n\n\n/***************************************************************************\n *  XMA format structures\n ***************************************************************************/\n\n// The currently recommended way to express format information for XMA2 files\n// is the XMA2WAVEFORMATEX structure.  This structure is fully compliant with\n// the WAVEFORMATEX standard and contains all the information needed to parse\n// and manage XMA2 files in a compact way.\n\n#define WAVE_FORMAT_XMA2 0x166\n\ntypedef struct XMA2WAVEFORMATEX\n{\n    WAVEFORMATEX wfx;\n    // Meaning of the WAVEFORMATEX fields here:\n    //    wFormatTag;        // Audio format type; always WAVE_FORMAT_XMA2\n    //    nChannels;         // Channel count of the decoded audio\n    //    nSamplesPerSec;    // Sample rate of the decoded audio\n    //    nAvgBytesPerSec;   // Used internally by the XMA encoder\n    //    nBlockAlign;       // Decoded sample size; channels * wBitsPerSample / 8\n    //    wBitsPerSample;    // Bits per decoded mono sample; always 16 for XMA\n    //    cbSize;            // Size in bytes of the rest of this structure (34)\n\n    WORD  NumStreams;        // Number of audio streams (1 or 2 channels each)\n    DWORD ChannelMask;       // Spatial positions of the channels in this file,\n                             // stored as SPEAKER_xxx values (see audiodefs.h)\n    DWORD SamplesEncoded;    // Total number of PCM samples the file decodes to\n    DWORD BytesPerBlock;     // XMA block size (but the last one may be shorter)\n    DWORD PlayBegin;         // First valid sample in the decoded audio\n    DWORD PlayLength;        // Length of the valid part of the decoded audio\n    DWORD LoopBegin;         // Beginning of the loop region in decoded sample terms\n    DWORD LoopLength;        // Length of the loop region in decoded sample terms\n    BYTE  LoopCount;         // Number of loop repetitions; 255 = infinite\n    BYTE  EncoderVersion;    // Version of XMA encoder that generated the file\n    WORD  BlockCount;        // XMA blocks in file (and entries in its seek table)\n} XMA2WAVEFORMATEX, *PXMA2WAVEFORMATEX;\n\n\n// The legacy XMA format structures are described here for reference, but they\n// should not be used in new content.  XMAWAVEFORMAT was the structure used in\n// XMA version 1 files.  XMA2WAVEFORMAT was used in early XMA2 files; it is not\n// placed in the usual 'fmt' RIFF chunk but in its own 'XMA2' chunk.\n\n#ifndef WAVE_FORMAT_XMA\n#define WAVE_FORMAT_XMA 0x0165\n\n// Values used in the ChannelMask fields below.  Similar to the SPEAKER_xxx\n// values defined in audiodefs.h, but modified to fit in a single byte.\n#ifndef XMA_SPEAKER_LEFT\n    #define XMA_SPEAKER_LEFT            0x01\n    #define XMA_SPEAKER_RIGHT           0x02\n    #define XMA_SPEAKER_CENTER          0x04\n    #define XMA_SPEAKER_LFE             0x08\n    #define XMA_SPEAKER_LEFT_SURROUND   0x10\n    #define XMA_SPEAKER_RIGHT_SURROUND  0x20\n    #define XMA_SPEAKER_LEFT_BACK       0x40\n    #define XMA_SPEAKER_RIGHT_BACK      0x80\n#endif\n\n\n// Used in XMAWAVEFORMAT for per-stream data\ntypedef struct XMASTREAMFORMAT\n{\n    DWORD PsuedoBytesPerSec; // Used by the XMA encoder (typo preserved for legacy reasons)\n    DWORD SampleRate;        // The stream's decoded sample rate (in XMA2 files,\n                             // this is the same for all streams in the file).\n    DWORD LoopStart;         // Bit offset of the frame containing the loop start\n                             // point, relative to the beginning of the stream.\n    DWORD LoopEnd;           // Bit offset of the frame containing the loop end.\n    BYTE  SubframeData;      // Two 4-bit numbers specifying the exact location of\n                             // the loop points within the frames that contain them.\n                             //   SubframeEnd: Subframe of the loop end frame where\n                             //                the loop ends.  Ranges from 0 to 3.\n                             //   SubframeSkip: Subframes to skip in the start frame to\n                             //                 reach the loop.  Ranges from 0 to 4.\n    BYTE  Channels;          // Number of channels in the stream (1 or 2)\n    WORD  ChannelMask;       // Spatial positions of the channels in the stream\n} XMASTREAMFORMAT;\n\n// Legacy XMA1 format structure\ntypedef struct XMAWAVEFORMAT\n{\n    WORD FormatTag;          // Audio format type (always WAVE_FORMAT_XMA)\n    WORD BitsPerSample;      // Bit depth (currently required to be 16)\n    WORD EncodeOptions;      // Options for XMA encoder/decoder\n    WORD LargestSkip;        // Largest skip used in interleaving streams\n    WORD NumStreams;         // Number of interleaved audio streams\n    BYTE LoopCount;          // Number of loop repetitions; 255 = infinite\n    BYTE Version;            // XMA encoder version that generated the file.\n                             // Always 3 or higher for XMA2 files.\n    XMASTREAMFORMAT XmaStreams[1]; // Per-stream format information; the actual\n                                   // array length is in the NumStreams field.\n} XMAWAVEFORMAT;\n\n\n// Used in XMA2WAVEFORMAT for per-stream data\ntypedef struct XMA2STREAMFORMAT\n{\n    BYTE Channels;           // Number of channels in the stream (1 or 2)\n    BYTE RESERVED;           // Reserved for future use\n    WORD ChannelMask;        // Spatial positions of the channels in the stream\n} XMA2STREAMFORMAT;\n\n// Legacy XMA2 format structure (big-endian byte ordering)\ntypedef struct XMA2WAVEFORMAT\n{\n    BYTE  Version;           // XMA encoder version that generated the file.\n                             // Always 3 or higher for XMA2 files.\n    BYTE  NumStreams;        // Number of interleaved audio streams\n    BYTE  RESERVED;          // Reserved for future use\n    BYTE  LoopCount;         // Number of loop repetitions; 255 = infinite\n    DWORD LoopBegin;         // Loop begin point, in samples\n    DWORD LoopEnd;           // Loop end point, in samples\n    DWORD SampleRate;        // The file's decoded sample rate\n    DWORD EncodeOptions;     // Options for the XMA encoder/decoder\n    DWORD PsuedoBytesPerSec; // Used internally by the XMA encoder\n    DWORD BlockSizeInBytes;  // Size in bytes of this file's XMA blocks (except\n                             // possibly the last one).  Always a multiple of\n                             // 2Kb, since XMA blocks are arrays of 2Kb packets.\n    DWORD SamplesEncoded;    // Total number of PCM samples encoded in this file\n    DWORD SamplesInSource;   // Actual number of PCM samples in the source\n                             // material used to generate this file\n    DWORD BlockCount;        // Number of XMA blocks in this file (and hence\n                             // also the number of entries in its seek table)\n    XMA2STREAMFORMAT Streams[1]; // Per-stream format information; the actual\n                                 // array length is in the NumStreams field.\n} XMA2WAVEFORMAT;\n\n#endif // #ifndef WAVE_FORMAT_XMA\n\n\n\n/***************************************************************************\n *  XMA packet structure (in big-endian form)\n ***************************************************************************/\n\ntypedef struct XMA2PACKET\n{\n    int FrameCount        :  6;  // Number of XMA frames that begin in this packet\n    int FrameOffsetInBits : 15;  // Bit of XmaData where the first complete frame begins\n    int PacketMetaData    :  3;  // Metadata stored in the packet (always 1 for XMA2)\n    int PacketSkipCount   :  8;  // How many packets belonging to other streams must be\n                                 // skipped to find the next packet belonging to this one\n    BYTE XmaData[XMA_BYTES_PER_PACKET - sizeof(DWORD)];  // XMA encoded data\n} XMA2PACKET;\n\n// E.g. if the first DWORD of a packet is 0x30107902:\n//\n// 001100 000001000001111 001 00000010\n//    |          |         |      |____ Skip 2 packets to find the next one for this stream\n//    |          |         |___________ XMA2 signature (always 001)\n//    |          |_____________________ First frame starts 527 bits into packet\n//    |________________________________ Packet contains 12 frames\n\n\n// Helper functions to extract the fields above from an XMA packet.  (Note that\n// the bitfields cannot be read directly on little-endian architectures such as\n// the Intel x86, as they are laid out in big-endian form.)\n\n__inline DWORD GetXmaPacketFrameCount(__in_bcount(1) const BYTE* pPacket)\n{\n    return (DWORD)(pPacket[0] >> 2);\n}\n\n__inline DWORD GetXmaPacketFirstFrameOffsetInBits(__in_bcount(3) const BYTE* pPacket)\n{\n    return ((DWORD)(pPacket[0] & 0x3) << 13) |\n           ((DWORD)(pPacket[1]) << 5) |\n           ((DWORD)(pPacket[2]) >> 3);\n}\n\n__inline DWORD GetXmaPacketMetadata(__in_bcount(3) const BYTE* pPacket)\n{\n    return (DWORD)(pPacket[2] & 0x7);\n}\n\n__inline DWORD GetXmaPacketSkipCount(__in_bcount(4) const BYTE* pPacket)\n{\n    return (DWORD)(pPacket[3]);\n}\n\n\n\n/***************************************************************************\n *  XMA frame structure\n ***************************************************************************/\n\n// There is no way to represent the XMA frame as a C struct, since it is a\n// variable-sized string of bits that need not be stored at a byte-aligned\n// position in memory.  This is the layout:\n//\n// XMAFRAME\n// {\n//    LengthInBits: A 15-bit number representing the length of this frame.\n//    XmaData: Encoded XMA data; its size in bits is (LengthInBits - 15).\n// }\n\n// Size in bits of the frame's initial LengthInBits field\n#define XMA_BITS_IN_FRAME_LENGTH_FIELD 15\n\n// Special LengthInBits value that marks an invalid final frame\n#define XMA_FINAL_FRAME_MARKER 0x7FFF\n\n\n\n/***************************************************************************\n *  XMA helper functions\n ***************************************************************************/\n\n// We define a local ASSERT macro to equal the global one if it exists.\n// You can define XMA2DEFS_ASSERT in advance to override this default.\n#ifndef XMA2DEFS_ASSERT\n    #ifdef ASSERT\n        #define XMA2DEFS_ASSERT ASSERT\n    #else\n        #define XMA2DEFS_ASSERT(a) /* No-op by default */\n    #endif\n#endif\n\n\n// GetXmaBlockContainingSample: Use a given seek table to find the XMA block\n// containing a given decoded sample.  Note that the seek table entries in an\n// XMA file are stored in big-endian form and may need to be converted prior\n// to calling this function.\n\n__inline HRESULT GetXmaBlockContainingSample\n(\n    DWORD nBlockCount,                      // Blocks in the file (= seek table entries)\n    __in_ecount(nBlockCount) const DWORD* pSeekTable,  // Pointer to the seek table data\n    DWORD nDesiredSample,                   // Decoded sample to locate\n    __out DWORD* pnBlockContainingSample,   // Index of the block containing the sample\n    __out DWORD* pnSampleOffsetWithinBlock  // Position of the sample in this block\n)\n{\n    DWORD nPreviousTotalSamples = 0;\n    DWORD nBlock;\n    DWORD nTotalSamplesSoFar;\n\n    XMA2DEFS_ASSERT(pSeekTable);\n    XMA2DEFS_ASSERT(pnBlockContainingSample);\n    XMA2DEFS_ASSERT(pnSampleOffsetWithinBlock);\n\n    for (nBlock = 0; nBlock < nBlockCount; ++nBlock)\n    {\n        nTotalSamplesSoFar = pSeekTable[nBlock];\n        if (nTotalSamplesSoFar > nDesiredSample)\n        {\n            *pnBlockContainingSample = nBlock;\n            *pnSampleOffsetWithinBlock = nDesiredSample - nPreviousTotalSamples;\n            return S_OK;\n        }\n        nPreviousTotalSamples = nTotalSamplesSoFar;\n    }\n\n    return E_FAIL;\n}\n\n\n// GetXmaFrameLengthInBits: Reads a given frame's LengthInBits field.\n\n__inline DWORD GetXmaFrameLengthInBits\n(\n    __in_bcount(nBitPosition / 8 + 3)\n    __in const BYTE* pPacket,  // Pointer to XMA packet[s] containing the frame\n    DWORD nBitPosition         // Bit offset of the frame within this packet\n)\n{\n    DWORD nRegion;\n    DWORD nBytePosition = nBitPosition / 8;\n    DWORD nBitOffset = nBitPosition % 8;\n\n    if (nBitOffset < 2) // Only need to read 2 bytes (and might not be safe to read more)\n    {\n        nRegion = (DWORD)(pPacket[nBytePosition+0]) << 8 |\n                  (DWORD)(pPacket[nBytePosition+1]);\n        return (nRegion >> (1 - nBitOffset)) & 0x7FFF;  // Last 15 bits\n    }\n    else // Need to read 3 bytes\n    {\n        nRegion = (DWORD)(pPacket[nBytePosition+0]) << 16 |\n                  (DWORD)(pPacket[nBytePosition+1]) << 8 |\n                  (DWORD)(pPacket[nBytePosition+2]);\n        return (nRegion >> (9 - nBitOffset)) & 0x7FFF;  // Last 15 bits\n    }\n}\n\n\n// GetXmaFrameBitPosition: Calculates the bit offset of a given frame within\n// an XMA block or set of blocks.  Returns 0 on failure.\n\n__inline DWORD GetXmaFrameBitPosition\n(\n    __in_bcount(nXmaDataBytes) const BYTE* pXmaData,  // Pointer to XMA block[s]\n    DWORD nXmaDataBytes,                              // Size of pXmaData in bytes\n    DWORD nStreamIndex,                               // Stream within which to seek\n    DWORD nDesiredFrame                               // Frame sought\n)\n{\n    const BYTE* pCurrentPacket;\n    DWORD nPacketsExamined = 0;\n    DWORD nFrameCountSoFar = 0;\n    DWORD nFramesToSkip;\n    DWORD nFrameBitOffset;\n\n    XMA2DEFS_ASSERT(pXmaData);\n    XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);\n\n    // Get the first XMA packet belonging to the desired stream, relying on the\n    // fact that the first packets for each stream are in consecutive order at\n    // the beginning of an XMA block.\n\n    pCurrentPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;\n    for (;;)\n    {\n        // If we have exceeded the size of the XMA data, return failure\n        if (pCurrentPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)\n        {\n            return 0;\n        }\n\n        // If the current packet contains the frame we are looking for...\n        if (nFrameCountSoFar + GetXmaPacketFrameCount(pCurrentPacket) > nDesiredFrame)\n        {\n            // See how many frames in this packet we need to skip to get to it\n            XMA2DEFS_ASSERT(nDesiredFrame >= nFrameCountSoFar);\n            nFramesToSkip = nDesiredFrame - nFrameCountSoFar;\n\n            // Get the bit offset of the first frame in this packet\n            nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pCurrentPacket);\n\n            // Advance nFrameBitOffset to the frame of interest\n            while (nFramesToSkip--)\n            {\n                nFrameBitOffset += GetXmaFrameLengthInBits(pCurrentPacket, nFrameBitOffset);\n            }\n\n            // The bit offset to return is the number of bits from pXmaData to\n            // pCurrentPacket plus the bit offset of the frame of interest\n            return (DWORD)(pCurrentPacket - pXmaData) * 8 + nFrameBitOffset;\n        }\n\n        // If we haven't found the right packet yet, advance our counters\n        ++nPacketsExamined;\n        nFrameCountSoFar += GetXmaPacketFrameCount(pCurrentPacket);\n\n        // And skip to the next packet belonging to the same stream\n        pCurrentPacket += XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pCurrentPacket) + 1);\n    }\n}\n\n\n// GetLastXmaFrameBitPosition: Calculates the bit offset of the last complete\n// frame in an XMA block or set of blocks.\n\n__inline DWORD GetLastXmaFrameBitPosition\n(\n    __in_bcount(nXmaDataBytes) const BYTE* pXmaData,  // Pointer to XMA block[s]\n    DWORD nXmaDataBytes,                              // Size of pXmaData in bytes\n    DWORD nStreamIndex                                // Stream within which to seek\n)\n{\n    const BYTE* pLastPacket;\n    DWORD nBytesToNextPacket;\n    DWORD nFrameBitOffset;\n    DWORD nFramesInLastPacket;\n\n    XMA2DEFS_ASSERT(pXmaData);\n    XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);\n    XMA2DEFS_ASSERT(nXmaDataBytes >= XMA_BYTES_PER_PACKET * (nStreamIndex + 1));\n\n    // Get the first XMA packet belonging to the desired stream, relying on the\n    // fact that the first packets for each stream are in consecutive order at\n    // the beginning of an XMA block.\n    pLastPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;\n\n    // Search for the last packet belonging to the desired stream\n    for (;;)\n    {\n        nBytesToNextPacket = XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pLastPacket) + 1);\n        XMA2DEFS_ASSERT(nBytesToNextPacket);\n        if (pLastPacket + nBytesToNextPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)\n        {\n            break;  // The next packet would extend beyond the end of pXmaData\n        }\n        pLastPacket += nBytesToNextPacket;\n    }\n\n    // The last packet can sometimes have no seekable frames, in which case we\n    // have to use the previous one\n    if (GetXmaPacketFrameCount(pLastPacket) == 0)\n    {\n        pLastPacket -= nBytesToNextPacket;\n    }\n\n    // Found the last packet.  Get the bit offset of its first frame.\n    nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pLastPacket);\n\n    // Traverse frames until we reach the last one\n    nFramesInLastPacket = GetXmaPacketFrameCount(pLastPacket);\n    while (--nFramesInLastPacket)\n    {\n        nFrameBitOffset += GetXmaFrameLengthInBits(pLastPacket, nFrameBitOffset);\n    }\n\n    // The bit offset to return is the number of bits from pXmaData to\n    // pLastPacket plus the offset of the last frame in this packet.\n    return (DWORD)(pLastPacket - pXmaData) * 8 + nFrameBitOffset;\n}\n\n\n// GetXmaDecodePositionForSample: Obtains the information needed to make the\n// decoder generate audio starting at a given sample position relative to the\n// beginning of the given XMA block: the bit offset of the appropriate frame,\n// and the right subframe within that frame.  This data can be passed directly\n// to the XMAPlaybackSetDecodePosition function.\n\n__inline HRESULT GetXmaDecodePositionForSample\n(\n    __in_bcount(nXmaDataBytes) const BYTE* pXmaData,  // Pointer to XMA block[s]\n    DWORD nXmaDataBytes,                              // Size of pXmaData in bytes\n    DWORD nStreamIndex,                               // Stream within which to seek\n    DWORD nDesiredSample,                             // Sample sought\n    __out DWORD* pnBitOffset,                         // Returns the bit offset within pXmaData of\n                                                      // the frame containing the sample sought\n    __out DWORD* pnSubFrame                           // Returns the subframe containing the sample\n)\n{\n    DWORD nDesiredFrame = nDesiredSample / XMA_SAMPLES_PER_FRAME;\n    DWORD nSubFrame = (nDesiredSample % XMA_SAMPLES_PER_FRAME) / XMA_SAMPLES_PER_SUBFRAME;\n    DWORD nBitOffset = GetXmaFrameBitPosition(pXmaData, nXmaDataBytes, nStreamIndex, nDesiredFrame);\n\n    XMA2DEFS_ASSERT(pnBitOffset);\n    XMA2DEFS_ASSERT(pnSubFrame);\n\n    if (nBitOffset)\n    {\n        *pnBitOffset = nBitOffset;\n        *pnSubFrame = nSubFrame;\n        return S_OK;\n    }\n    else\n    {\n        return E_FAIL;\n    }\n}\n\n\n// GetXmaSampleRate: Obtains the legal XMA sample rate (24, 32, 44.1 or 48Khz)\n// corresponding to a generic sample rate.\n\n__inline DWORD GetXmaSampleRate(DWORD dwGeneralRate)\n{\n    DWORD dwXmaRate = 48000; // Default XMA rate for all rates above 44100Hz\n\n    if (dwGeneralRate <= 24000)      dwXmaRate = 24000;\n    else if (dwGeneralRate <= 32000) dwXmaRate = 32000;\n    else if (dwGeneralRate <= 44100) dwXmaRate = 44100;\n\n    return dwXmaRate;\n}\n\n\n// Functions to convert between WAVEFORMATEXTENSIBLE channel masks (combinations\n// of the SPEAKER_xxx flags defined in audiodefs.h) and XMA channel masks (which\n// are limited to eight possible speaker positions: left, right, center, low\n// frequency, side left, side right, back left and back right).\n\n__inline DWORD GetStandardChannelMaskFromXmaMask(BYTE bXmaMask)\n{\n    DWORD dwStandardMask = 0;\n\n    if (bXmaMask & XMA_SPEAKER_LEFT)           dwStandardMask |= SPEAKER_FRONT_LEFT;\n    if (bXmaMask & XMA_SPEAKER_RIGHT)          dwStandardMask |= SPEAKER_FRONT_RIGHT;\n    if (bXmaMask & XMA_SPEAKER_CENTER)         dwStandardMask |= SPEAKER_FRONT_CENTER;\n    if (bXmaMask & XMA_SPEAKER_LFE)            dwStandardMask |= SPEAKER_LOW_FREQUENCY;\n    if (bXmaMask & XMA_SPEAKER_LEFT_SURROUND)  dwStandardMask |= SPEAKER_SIDE_LEFT;\n    if (bXmaMask & XMA_SPEAKER_RIGHT_SURROUND) dwStandardMask |= SPEAKER_SIDE_RIGHT;\n    if (bXmaMask & XMA_SPEAKER_LEFT_BACK)      dwStandardMask |= SPEAKER_BACK_LEFT;\n    if (bXmaMask & XMA_SPEAKER_RIGHT_BACK)     dwStandardMask |= SPEAKER_BACK_RIGHT;\n\n    return dwStandardMask;\n}\n\n__inline BYTE GetXmaChannelMaskFromStandardMask(DWORD dwStandardMask)\n{\n    BYTE bXmaMask = 0;\n\n    if (dwStandardMask & SPEAKER_FRONT_LEFT)    bXmaMask |= XMA_SPEAKER_LEFT;\n    if (dwStandardMask & SPEAKER_FRONT_RIGHT)   bXmaMask |= XMA_SPEAKER_RIGHT;\n    if (dwStandardMask & SPEAKER_FRONT_CENTER)  bXmaMask |= XMA_SPEAKER_CENTER;\n    if (dwStandardMask & SPEAKER_LOW_FREQUENCY) bXmaMask |= XMA_SPEAKER_LFE;\n    if (dwStandardMask & SPEAKER_SIDE_LEFT)     bXmaMask |= XMA_SPEAKER_LEFT_SURROUND;\n    if (dwStandardMask & SPEAKER_SIDE_RIGHT)    bXmaMask |= XMA_SPEAKER_RIGHT_SURROUND;\n    if (dwStandardMask & SPEAKER_BACK_LEFT)     bXmaMask |= XMA_SPEAKER_LEFT_BACK;\n    if (dwStandardMask & SPEAKER_BACK_RIGHT)    bXmaMask |= XMA_SPEAKER_RIGHT_BACK;\n\n    return bXmaMask;\n}\n\n\n// LocalizeXma2Format: Modifies a XMA2WAVEFORMATEX structure in place to comply\n// with the current platform's byte-ordering rules (little- or big-endian).\n\n__inline HRESULT LocalizeXma2Format(__inout XMA2WAVEFORMATEX* pXma2Format)\n{\n    #define XMASWAP2BYTES(n) ((WORD)(((n) >> 8) | (((n) & 0xff) << 8)))\n    #define XMASWAP4BYTES(n) ((DWORD)((n) >> 24 | (n) << 24 | ((n) & 0xff00) << 8 | ((n) & 0xff0000) >> 8))\n\n    if (pXma2Format->wfx.wFormatTag == WAVE_FORMAT_XMA2)\n    {\n        return S_OK;\n    }\n    else if (XMASWAP2BYTES(pXma2Format->wfx.wFormatTag) == WAVE_FORMAT_XMA2)\n    {\n        pXma2Format->wfx.wFormatTag      = XMASWAP2BYTES(pXma2Format->wfx.wFormatTag);\n        pXma2Format->wfx.nChannels       = XMASWAP2BYTES(pXma2Format->wfx.nChannels);\n        pXma2Format->wfx.nSamplesPerSec  = XMASWAP4BYTES(pXma2Format->wfx.nSamplesPerSec);\n        pXma2Format->wfx.nAvgBytesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nAvgBytesPerSec);\n        pXma2Format->wfx.nBlockAlign     = XMASWAP2BYTES(pXma2Format->wfx.nBlockAlign);\n        pXma2Format->wfx.wBitsPerSample  = XMASWAP2BYTES(pXma2Format->wfx.wBitsPerSample);\n        pXma2Format->wfx.cbSize          = XMASWAP2BYTES(pXma2Format->wfx.cbSize);\n        pXma2Format->NumStreams          = XMASWAP2BYTES(pXma2Format->NumStreams);\n        pXma2Format->ChannelMask         = XMASWAP4BYTES(pXma2Format->ChannelMask);\n        pXma2Format->SamplesEncoded      = XMASWAP4BYTES(pXma2Format->SamplesEncoded);\n        pXma2Format->BytesPerBlock       = XMASWAP4BYTES(pXma2Format->BytesPerBlock);\n        pXma2Format->PlayBegin           = XMASWAP4BYTES(pXma2Format->PlayBegin);\n        pXma2Format->PlayLength          = XMASWAP4BYTES(pXma2Format->PlayLength);\n        pXma2Format->LoopBegin           = XMASWAP4BYTES(pXma2Format->LoopBegin);\n        pXma2Format->LoopLength          = XMASWAP4BYTES(pXma2Format->LoopLength);\n        pXma2Format->BlockCount          = XMASWAP2BYTES(pXma2Format->BlockCount);\n        return S_OK;\n    }\n    else\n    {\n        return E_FAIL; // Not a recognizable XMA2 format\n    }\n\n    #undef XMASWAP2BYTES\n    #undef XMASWAP4BYTES\n}\n\n\n#endif // #ifndef __XMA2DEFS_INCLUDED__\n"
  },
  {
    "path": "dependencies/gamemode/CMakeLists.txt",
    "content": "project( gamemode LANGUAGES C )\nadd_library (gamemode\n        \"lib/gamemode_client.h\"\n        \"lib/client_loader.c\")"
  },
  {
    "path": "dependencies/gamemode/lib/client_loader.c",
    "content": "/*\n\nCopyright (c) 2017-2019, Feral Interactive\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice,\n   this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n * Neither the name of Feral Interactive nor the names of its contributors\n   may be used to endorse or promote products derived from this software\n   without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n\n */\n\n// Simply include the header with GAMEMODE_AUTO set\n// This will ensure it calls the functions when it's loaded\n#define GAMEMODE_AUTO\n#include \"gamemode_client.h\"\n"
  },
  {
    "path": "dependencies/gamemode/lib/gamemode_client.h",
    "content": "/*\n\nCopyright (c) 2017-2019, Feral Interactive\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice,\n   this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n * Neither the name of Feral Interactive nor the names of its contributors\n   may be used to endorse or promote products derived from this software\n   without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n\n */\n#ifndef CLIENT_GAMEMODE_H\n#define CLIENT_GAMEMODE_H\n/*\n * GameMode supports the following client functions\n * Requests are refcounted in the daemon\n *\n * int gamemode_request_start() - Request gamemode starts\n *   0 if the request was sent successfully\n *   -1 if the request failed\n *\n * int gamemode_request_end() - Request gamemode ends\n *   0 if the request was sent successfully\n *   -1 if the request failed\n *\n * GAMEMODE_AUTO can be defined to make the above two functions apply during static init and\n * destruction, as appropriate. In this configuration, errors will be printed to stderr\n *\n * int gamemode_query_status() - Query the current status of gamemode\n *   0 if gamemode is inactive\n *   1 if gamemode is active\n *   2 if gamemode is active and this client is registered\n *   -1 if the query failed\n *\n * int gamemode_request_start_for(pid_t pid) - Request gamemode starts for another process\n *   0 if the request was sent successfully\n *   -1 if the request failed\n *   -2 if the request was rejected\n *\n * int gamemode_request_end_for(pid_t pid) - Request gamemode ends for another process\n *   0 if the request was sent successfully\n *   -1 if the request failed\n *   -2 if the request was rejected\n *\n * int gamemode_query_status_for(pid_t pid) - Query status of gamemode for another process\n *   0 if gamemode is inactive\n *   1 if gamemode is active\n *   2 if gamemode is active and this client is registered\n *   -1 if the query failed\n *\n * const char* gamemode_error_string() - Get an error string\n *   returns a string describing any of the above errors\n *\n * Note: All the above requests can be blocking - dbus requests can and will block while the daemon\n * handles the request. It is not recommended to make these calls in performance critical code\n */\n\n#include <stdbool.h>\n#include <stdio.h>\n\n#include <dlfcn.h>\n#include <string.h>\n\n#include <assert.h>\n\n#include <sys/types.h>\n\nstatic char internal_gamemode_client_error_string[512] = { 0 };\n\n/**\n * Load libgamemode dynamically to dislodge us from most dependencies.\n * This allows clients to link and/or use this regardless of runtime.\n * See SDL2 for an example of the reasoning behind this in terms of\n * dynamic versioning as well.\n */\nstatic volatile int internal_libgamemode_loaded = 1;\n\n/* Typedefs for the functions to load */\ntypedef int (*api_call_return_int)(void);\ntypedef const char *(*api_call_return_cstring)(void);\ntypedef int (*api_call_pid_return_int)(pid_t);\n\n/* Storage for functors */\nstatic api_call_return_int REAL_internal_gamemode_request_start = NULL;\nstatic api_call_return_int REAL_internal_gamemode_request_end = NULL;\nstatic api_call_return_int REAL_internal_gamemode_query_status = NULL;\nstatic api_call_return_cstring REAL_internal_gamemode_error_string = NULL;\nstatic api_call_pid_return_int REAL_internal_gamemode_request_start_for = NULL;\nstatic api_call_pid_return_int REAL_internal_gamemode_request_end_for = NULL;\nstatic api_call_pid_return_int REAL_internal_gamemode_query_status_for = NULL;\n\n/**\n * Internal helper to perform the symbol binding safely.\n *\n * Returns 0 on success and -1 on failure\n */\n__attribute__((always_inline)) static inline int internal_bind_libgamemode_symbol(\n    void *handle, const char *name, void **out_func, size_t func_size, bool required)\n{\n\tvoid *symbol_lookup = NULL;\n\tchar *dl_error = NULL;\n\n\t/* Safely look up the symbol */\n\tsymbol_lookup = dlsym(handle, name);\n\tdl_error = dlerror();\n\tif (required && (dl_error || !symbol_lookup)) {\n\t\tsnprintf(internal_gamemode_client_error_string,\n\t\t         sizeof(internal_gamemode_client_error_string),\n\t\t         \"dlsym failed - %s\",\n\t\t         dl_error);\n\t\treturn -1;\n\t}\n\n\t/* Have the symbol correctly, copy it to make it usable */\n\tmemcpy(out_func, &symbol_lookup, func_size);\n\treturn 0;\n}\n\n/**\n * Loads libgamemode and needed functions\n *\n * Returns 0 on success and -1 on failure\n */\n__attribute__((always_inline)) static inline int internal_load_libgamemode(void)\n{\n\t/* We start at 1, 0 is a success and -1 is a fail */\n\tif (internal_libgamemode_loaded != 1) {\n\t\treturn internal_libgamemode_loaded;\n\t}\n\n\t/* Anonymous struct type to define our bindings */\n\tstruct binding {\n\t\tconst char *name;\n\t\tvoid **functor;\n\t\tsize_t func_size;\n\t\tbool required;\n\t} bindings[] = {\n\t\t{ \"real_gamemode_request_start\",\n\t\t  (void **)&REAL_internal_gamemode_request_start,\n\t\t  sizeof(REAL_internal_gamemode_request_start),\n\t\t  true },\n\t\t{ \"real_gamemode_request_end\",\n\t\t  (void **)&REAL_internal_gamemode_request_end,\n\t\t  sizeof(REAL_internal_gamemode_request_end),\n\t\t  true },\n\t\t{ \"real_gamemode_query_status\",\n\t\t  (void **)&REAL_internal_gamemode_query_status,\n\t\t  sizeof(REAL_internal_gamemode_query_status),\n\t\t  false },\n\t\t{ \"real_gamemode_error_string\",\n\t\t  (void **)&REAL_internal_gamemode_error_string,\n\t\t  sizeof(REAL_internal_gamemode_error_string),\n\t\t  true },\n\t\t{ \"real_gamemode_request_start_for\",\n\t\t  (void **)&REAL_internal_gamemode_request_start_for,\n\t\t  sizeof(REAL_internal_gamemode_request_start_for),\n\t\t  false },\n\t\t{ \"real_gamemode_request_end_for\",\n\t\t  (void **)&REAL_internal_gamemode_request_end_for,\n\t\t  sizeof(REAL_internal_gamemode_request_end_for),\n\t\t  false },\n\t\t{ \"real_gamemode_query_status_for\",\n\t\t  (void **)&REAL_internal_gamemode_query_status_for,\n\t\t  sizeof(REAL_internal_gamemode_query_status_for),\n\t\t  false },\n\t};\n\n\tvoid *libgamemode = NULL;\n\n\t/* Try and load libgamemode */\n\tlibgamemode = dlopen(\"libgamemode.so.0\", RTLD_NOW);\n\tif (!libgamemode) {\n\t\t/* Attempt to load unversioned library for compatibility with older\n\t\t * versions (as of writing, there are no ABI changes between the two -\n\t\t * this may need to change if ever ABI-breaking changes are made) */\n\t\tlibgamemode = dlopen(\"libgamemode.so\", RTLD_NOW);\n\t\tif (!libgamemode) {\n\t\t\tsnprintf(internal_gamemode_client_error_string,\n\t\t\t         sizeof(internal_gamemode_client_error_string),\n\t\t\t         \"dlopen failed - %s\",\n\t\t\t         dlerror());\n\t\t\tinternal_libgamemode_loaded = -1;\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\t/* Attempt to bind all symbols */\n\tfor (size_t i = 0; i < sizeof(bindings) / sizeof(bindings[0]); i++) {\n\t\tstruct binding *binder = &bindings[i];\n\n\t\tif (internal_bind_libgamemode_symbol(libgamemode,\n\t\t                                     binder->name,\n\t\t                                     binder->functor,\n\t\t                                     binder->func_size,\n\t\t                                     binder->required)) {\n\t\t\tinternal_libgamemode_loaded = -1;\n\t\t\treturn -1;\n\t\t};\n\t}\n\n\t/* Success */\n\tinternal_libgamemode_loaded = 0;\n\treturn 0;\n}\n\n/**\n * Redirect to the real libgamemode\n */\n__attribute__((always_inline)) static inline const char *gamemode_error_string(void)\n{\n\t/* If we fail to load the system gamemode, or we have an error string already, return our error\n\t * string instead of diverting to the system version */\n\tif (internal_load_libgamemode() < 0 || internal_gamemode_client_error_string[0] != '\\0') {\n\t\treturn internal_gamemode_client_error_string;\n\t}\n\n\t/* Assert for static analyser that the function is not NULL */\n\tassert(REAL_internal_gamemode_error_string != NULL);\n\n\treturn REAL_internal_gamemode_error_string();\n}\n\n/**\n * Redirect to the real libgamemode\n * Allow automatically requesting game mode\n * Also prints errors as they happen.\n */\n#ifdef GAMEMODE_AUTO\n__attribute__((constructor))\n#else\n__attribute__((always_inline)) static inline\n#endif\nint gamemode_request_start(void)\n{\n\t/* Need to load gamemode */\n\tif (internal_load_libgamemode() < 0) {\n#ifdef GAMEMODE_AUTO\n\t\tfprintf(stderr, \"gamemodeauto: %s\\n\", gamemode_error_string());\n#endif\n\t\treturn -1;\n\t}\n\n\t/* Assert for static analyser that the function is not NULL */\n\tassert(REAL_internal_gamemode_request_start != NULL);\n\n\tif (REAL_internal_gamemode_request_start() < 0) {\n#ifdef GAMEMODE_AUTO\n\t\tfprintf(stderr, \"gamemodeauto: %s\\n\", gamemode_error_string());\n#endif\n\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\n/* Redirect to the real libgamemode */\n#ifdef GAMEMODE_AUTO\n__attribute__((destructor))\n#else\n__attribute__((always_inline)) static inline\n#endif\nint gamemode_request_end(void)\n{\n\t/* Need to load gamemode */\n\tif (internal_load_libgamemode() < 0) {\n#ifdef GAMEMODE_AUTO\n\t\tfprintf(stderr, \"gamemodeauto: %s\\n\", gamemode_error_string());\n#endif\n\t\treturn -1;\n\t}\n\n\t/* Assert for static analyser that the function is not NULL */\n\tassert(REAL_internal_gamemode_request_end != NULL);\n\n\tif (REAL_internal_gamemode_request_end() < 0) {\n#ifdef GAMEMODE_AUTO\n\t\tfprintf(stderr, \"gamemodeauto: %s\\n\", gamemode_error_string());\n#endif\n\t\treturn -1;\n\t}\n\n\treturn 0;\n}\n\n/* Redirect to the real libgamemode */\n__attribute__((always_inline)) static inline int gamemode_query_status(void)\n{\n\t/* Need to load gamemode */\n\tif (internal_load_libgamemode() < 0) {\n\t\treturn -1;\n\t}\n\n\tif (REAL_internal_gamemode_query_status == NULL) {\n\t\tsnprintf(internal_gamemode_client_error_string,\n\t\t         sizeof(internal_gamemode_client_error_string),\n\t\t         \"gamemode_query_status missing (older host?)\");\n\t\treturn -1;\n\t}\n\n\treturn REAL_internal_gamemode_query_status();\n}\n\n/* Redirect to the real libgamemode */\n__attribute__((always_inline)) static inline int gamemode_request_start_for(pid_t pid)\n{\n\t/* Need to load gamemode */\n\tif (internal_load_libgamemode() < 0) {\n\t\treturn -1;\n\t}\n\n\tif (REAL_internal_gamemode_request_start_for == NULL) {\n\t\tsnprintf(internal_gamemode_client_error_string,\n\t\t         sizeof(internal_gamemode_client_error_string),\n\t\t         \"gamemode_request_start_for missing (older host?)\");\n\t\treturn -1;\n\t}\n\n\treturn REAL_internal_gamemode_request_start_for(pid);\n}\n\n/* Redirect to the real libgamemode */\n__attribute__((always_inline)) static inline int gamemode_request_end_for(pid_t pid)\n{\n\t/* Need to load gamemode */\n\tif (internal_load_libgamemode() < 0) {\n\t\treturn -1;\n\t}\n\n\tif (REAL_internal_gamemode_request_end_for == NULL) {\n\t\tsnprintf(internal_gamemode_client_error_string,\n\t\t         sizeof(internal_gamemode_client_error_string),\n\t\t         \"gamemode_request_end_for missing (older host?)\");\n\t\treturn -1;\n\t}\n\n\treturn REAL_internal_gamemode_request_end_for(pid);\n}\n\n/* Redirect to the real libgamemode */\n__attribute__((always_inline)) static inline int gamemode_query_status_for(pid_t pid)\n{\n\t/* Need to load gamemode */\n\tif (internal_load_libgamemode() < 0) {\n\t\treturn -1;\n\t}\n\n\tif (REAL_internal_gamemode_query_status_for == NULL) {\n\t\tsnprintf(internal_gamemode_client_error_string,\n\t\t         sizeof(internal_gamemode_client_error_string),\n\t\t         \"gamemode_query_status_for missing (older host?)\");\n\t\treturn -1;\n\t}\n\n\treturn REAL_internal_gamemode_query_status_for(pid);\n}\n\n#endif // CLIENT_GAMEMODE_H\n"
  },
  {
    "path": "dependencies/ih264d/CHANGES",
    "content": "Code adjustments made by Team Cemu for Cemu emulator project as of 2022-02-01:\n- Stripped encoder, tests and fuzzer. We only need the decoder\n- Extended ih264_platform_macros.h to support MSVC instrinsics\n- Extended ithread.c to use WinAPI natives instead of requiring pthread.h\n- The decoder will output images without regarding SPS crop flag and instead pass the crop values in the decode output structure\n- Modified decoder/x86/ih264d_function_selector.c ih264d_init_arch() to automatically choose the best e_processor_arch for the current CPU"
  },
  {
    "path": "dependencies/ih264d/CMakeLists.txt",
    "content": "﻿cmake_minimum_required (VERSION 3.8)\n\nproject (\"ih264d\")\n\nadd_library (ih264d \n\"common/ih264_buf_mgr.c\"\n\"common/ih264_buf_mgr.h\"\n\"common/ih264_cabac_tables.c\"\n\"common/ih264_cabac_tables.h\"\n\"common/ih264_cavlc_tables.c\"\n\"common/ih264_cavlc_tables.h\"\n\"common/ih264_chroma_intra_pred_filters.c\"\n\"common/ih264_common_tables.c\"\n\"common/ih264_common_tables.h\"\n\"common/ih264_deblk_edge_filters.c\"\n\"common/ih264_deblk_edge_filters.h\"\n\"common/ih264_deblk_tables.c\"\n\"common/ih264_deblk_tables.h\"\n\"common/ih264_debug.h\"\n\"common/ih264_defs.h\"\n\"common/ih264_disp_mgr.c\"\n\"common/ih264_disp_mgr.h\"\n\"common/ih264_dpb_mgr.c\"\n\"common/ih264_dpb_mgr.h\"\n\"common/ih264_error.h\"\n\"common/ih264_ihadamard_scaling.c\"\n\"common/ih264_inter_pred_filters.c\"\n\"common/ih264_inter_pred_filters.h\"\n\"common/ih264_intra_pred_filters.h\"\n\"common/ih264_iquant_itrans_recon.c\"\n\"common/ih264_list.c\"\n\"common/ih264_list.h\"\n\"common/ih264_luma_intra_pred_filters.c\"\n\"common/ih264_macros.h\"\n\"common/ih264_mem_fns.c\"\n\"common/ih264_mem_fns.h\"\n\"common/ih264_padding.c\"\n\"common/ih264_padding.h\"\n\"common/ih264_resi_trans.h\"\n\"common/ih264_resi_trans_quant.c\"\n\"common/ih264_size_defs.h\"\n\"common/ih264_structs.h\"\n\"common/ih264_trans_data.c\"\n\"common/ih264_trans_data.h\"\n\"common/ih264_trans_macros.h\"\n\"common/ih264_trans_quant_itrans_iquant.h\"\n\"common/ih264_typedefs.h\"\n\"common/ih264_weighted_pred.c\"\n\"common/ih264_weighted_pred.h\"\n\"common/ithread.c\"\n\"common/ithread.h\"\n\"decoder/ih264d.h\"\n\"decoder/ih264d_api.c\"\n\"decoder/ih264d_bitstrm.c\"\n\"decoder/ih264d_bitstrm.h\"\n\"decoder/ih264d_cabac.c\"\n\"decoder/ih264d_cabac.h\"\n\"decoder/ih264d_cabac_init_tables.c\"\n\"decoder/ih264d_compute_bs.c\"\n\"decoder/ih264d_deblocking.c\"\n\"decoder/ih264d_deblocking.h\"\n\"decoder/ih264d_debug.h\"\n\"decoder/ih264d_defs.h\"\n\"decoder/ih264d_dpb_manager.h\"\n\"decoder/ih264d_dpb_mgr.c\"\n\"decoder/ih264d_error_handler.h\"\n\"decoder/ih264d_format_conv.c\"\n\"decoder/ih264d_format_conv.h\"\n\"decoder/ih264d_function_selector.h\"\n\"decoder/ih264d_function_selector_generic.c\"\n\"decoder/ih264d_inter_pred.c\"\n\"decoder/ih264d_inter_pred.h\"\n\"decoder/ih264d_mb_utils.c\"\n\"decoder/ih264d_mb_utils.h\"\n\"decoder/ih264d_mem_request.h\"\n\"decoder/ih264d_mvpred.c\"\n\"decoder/ih264d_mvpred.h\"\n\"decoder/ih264d_nal.c\"\n\"decoder/ih264d_nal.h\"\n\"decoder/ih264d_parse_bslice.c\"\n\"decoder/ih264d_parse_cabac.c\"\n\"decoder/ih264d_parse_cabac.h\"\n\"decoder/ih264d_parse_cavlc.c\"\n\"decoder/ih264d_parse_cavlc.h\"\n\"decoder/ih264d_parse_headers.c\"\n\"decoder/ih264d_parse_headers.h\"\n\"decoder/ih264d_parse_islice.c\"\n\"decoder/ih264d_parse_islice.h\"\n\"decoder/ih264d_parse_mb_header.c\"\n\"decoder/ih264d_parse_mb_header.h\"\n\"decoder/ih264d_parse_pslice.c\"\n\"decoder/ih264d_parse_slice.c\"\n\"decoder/ih264d_parse_slice.h\"\n\"decoder/ih264d_process_bslice.c\"\n\"decoder/ih264d_process_bslice.h\"\n\"decoder/ih264d_process_intra_mb.c\"\n\"decoder/ih264d_process_intra_mb.h\"\n\"decoder/ih264d_process_pslice.c\"\n\"decoder/ih264d_process_pslice.h\"\n\"decoder/ih264d_quant_scaling.c\"\n\"decoder/ih264d_quant_scaling.h\"\n\"decoder/ih264d_sei.c\"\n\"decoder/ih264d_sei.h\"\n\"decoder/ih264d_structs.h\"\n\"decoder/ih264d_tables.c\"\n\"decoder/ih264d_tables.h\"\n\"decoder/ih264d_thread_compute_bs.c\"\n\"decoder/ih264d_thread_compute_bs.h\"\n\"decoder/ih264d_thread_parse_decode.c\"\n\"decoder/ih264d_thread_parse_decode.h\"\n\"decoder/ih264d_transfer_address.h\"\n\"decoder/ih264d_utils.c\"\n\"decoder/ih264d_utils.h\"\n\"decoder/ih264d_vui.c\"\n\"decoder/ih264d_vui.h\"\n\"decoder/iv.h\"\n\"decoder/ivd.h\"\n)\n\nif (CMAKE_OSX_ARCHITECTURES)\nset(IH264D_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES})\nelse()\nset(IH264D_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})\nendif()\n\nif (IH264D_ARCHITECTURE STREQUAL \"x86_64\" OR IH264D_ARCHITECTURE STREQUAL \"amd64\" OR IH264D_ARCHITECTURE STREQUAL \"AMD64\")\nset(LIBAVCDEC_X86_INCLUDES \"common/x86\" \"decoder/x86\")\ninclude_directories(\"common/\" \"decoder/\" ${LIBAVCDEC_X86_INCLUDES})\ntarget_sources(ih264d PRIVATE\n\"common/x86/ih264_chroma_intra_pred_filters_ssse3.c\"\n\"common/x86/ih264_deblk_chroma_ssse3.c\"\n\"common/x86/ih264_deblk_luma_ssse3.c\"\n\"common/x86/ih264_ihadamard_scaling_sse42.c\"\n\"common/x86/ih264_ihadamard_scaling_ssse3.c\"\n\"common/x86/ih264_inter_pred_filters_ssse3.c\"\n\"common/x86/ih264_iquant_itrans_recon_dc_ssse3.c\"\n\"common/x86/ih264_iquant_itrans_recon_sse42.c\"\n\"common/x86/ih264_iquant_itrans_recon_ssse3.c\"\n\"common/x86/ih264_luma_intra_pred_filters_ssse3.c\"\n\"common/x86/ih264_mem_fns_ssse3.c\"\n\"common/x86/ih264_padding_ssse3.c\"\n\"common/x86/ih264_platform_macros.h\"\n\"common/x86/ih264_resi_trans_quant_sse42.c\"\n\"common/x86/ih264_weighted_pred_sse42.c\"\n\"decoder/x86/ih264d_function_selector.c\"\n\"decoder/x86/ih264d_function_selector_sse42.c\"\n\"decoder/x86/ih264d_function_selector_ssse3.c\"\n)\nelseif(IH264D_ARCHITECTURE STREQUAL \"aarch64\" OR IH264D_ARCHITECTURE STREQUAL \"arm64\")\nenable_language( C CXX ASM )\nset(LIBAVCDEC_ARM_INCLUDES \"common/armv8\" \"decoder/arm\")\ninclude_directories(\"common/\" \"decoder/\" ${LIBAVCDEC_ARM_INCLUDES})\ntarget_sources(ih264d PRIVATE\n\"common/armv8/ih264_deblk_chroma_av8.s\"\n\"common/armv8/ih264_deblk_luma_av8.s\"\n\"common/armv8/ih264_default_weighted_pred_av8.s\"\n\"common/armv8/ih264_ihadamard_scaling_av8.s\"\n\"common/armv8/ih264_inter_pred_chroma_av8.s\"\n\"common/armv8/ih264_inter_pred_filters_luma_horz_av8.s\"\n\"common/armv8/ih264_inter_pred_filters_luma_vert_av8.s\"\n\"common/armv8/ih264_inter_pred_luma_copy_av8.s\"\n\"common/armv8/ih264_inter_pred_luma_horz_hpel_vert_hpel_av8.s\"\n\"common/armv8/ih264_inter_pred_luma_horz_hpel_vert_qpel_av8.s\"\n\"common/armv8/ih264_inter_pred_luma_horz_qpel_av8.s\"\n\"common/armv8/ih264_inter_pred_luma_horz_qpel_vert_hpel_av8.s\"\n\"common/armv8/ih264_inter_pred_luma_horz_qpel_vert_qpel_av8.s\"\n\"common/armv8/ih264_inter_pred_luma_vert_qpel_av8.s\"\n\"common/armv8/ih264_intra_pred_chroma_av8.s\"\n\"common/armv8/ih264_intra_pred_luma_16x16_av8.s\"\n\"common/armv8/ih264_intra_pred_luma_4x4_av8.s\"\n\"common/armv8/ih264_intra_pred_luma_8x8_av8.s\"\n\"common/armv8/ih264_iquant_itrans_recon_av8.s\"\n\"common/armv8/ih264_iquant_itrans_recon_dc_av8.s\"\n\"common/armv8/ih264_mem_fns_neon_av8.s\"\n\"common/armv8/ih264_neon_macros.s\"\n\"common/armv8/ih264_padding_neon_av8.s\"\n\"common/armv8/ih264_platform_macros.h\"\n\"common/armv8/ih264_resi_trans_quant_av8.s\"\n\"common/armv8/ih264_weighted_bi_pred_av8.s\"\n\"common/armv8/ih264_weighted_pred_av8.s\"\n\"decoder/arm/ih264d_function_selector_a9q.c\"\n\"decoder/arm/ih264d_function_selector_av8.c\"\n\"decoder/arm/ih264d_function_selector.c\"\n)\ntarget_compile_options(ih264d PRIVATE -DARMV8 $<$<COMPILE_LANGUAGE:ASM,Clang>:-Wno-unused-command-line-argument>)\nif(NOT MSVC)\n    set(CMAKE_ASM_FLAGS \"${CFLAGS} -x assembler-with-cpp\")\nendif()\nif(APPLE)\n    target_sources(ih264d PRIVATE \"common/armv8/macos_arm_symbol_aliases.s\")\nendif()\nelse()\nmessage(FATAL_ERROR \"ih264d unknown architecture: ${IH264D_ARCHITECTURE}\")\nendif()\n\nif(MSVC)\nset_property(TARGET ih264d PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\n# tune settings for slightly better performance\ntarget_compile_options(ih264d PRIVATE $<$<CONFIG:Release,RelWithDebInfo>:/Oi>) # enable intrinsic functions\ntarget_compile_options(ih264d PRIVATE $<$<CONFIG:Release,RelWithDebInfo>:/Ot>) # favor speed\ntarget_compile_options(ih264d PRIVATE \"/GS-\") # disable runtime checks\n\nendif()\n"
  },
  {
    "path": "dependencies/ih264d/CMakeSettings.json",
    "content": "﻿{\n  \"configurations\": [\n    {\n      \"name\": \"x64-Debug\",\n      \"generator\": \"Ninja\",\n      \"configurationType\": \"Debug\",\n      \"inheritEnvironments\": [ \"msvc_x64_x64\" ],\n      \"buildRoot\": \"${projectDir}\\\\out\\\\build\\\\${name}\",\n      \"installRoot\": \"${projectDir}\\\\out\\\\install\\\\${name}\",\n      \"cmakeCommandArgs\": \"\",\n      \"buildCommandArgs\": \"\",\n      \"ctestCommandArgs\": \"\"\n    },\n    {\n      \"name\": \"x64-Release\",\n      \"generator\": \"Ninja\",\n      \"configurationType\": \"Release\",\n      \"buildRoot\": \"${projectDir}\\\\out\\\\build\\\\${name}\",\n      \"installRoot\": \"${projectDir}\\\\out\\\\install\\\\${name}\",\n      \"cmakeCommandArgs\": \"\",\n      \"buildCommandArgs\": \"\",\n      \"ctestCommandArgs\": \"\",\n      \"inheritEnvironments\": [ \"msvc_x64_x64\" ]\n    }\n  ]\n}"
  },
  {
    "path": "dependencies/ih264d/NOTICE",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*****************************************************************************/\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_arm_memory_barrier.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@*******************************************************************************\n@* @file\n@*  ih264_arm_memory_barrier.s\n@*\n@* @brief\n@*  Contains function definitions for data synchronization.\n@*\n@* @author\n@*  Ittiam\n@*\n@* @par List of Functions:\n@*\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n\n.text\n.p2align 2\n\n@*****************************************************************************\n@*\n@* Function Name    : ih264_arm_dsb\n@* Description      : Adds DSB\n@* Revision History  :\n@*        DD MM YYYY    Author(s)   Changes\n@*        03 07 2008    100355      First version\n@*\n@*****************************************************************************\n\n        .global ih264_arm_dsb\nih264_arm_dsb:\n    dsb\n    bx            lr\n\n\n\n@*****************************************************************************\n@*\n@* Function Name    : ih264_arm_dmb\n@* Description      : Adds DMB\n@* Revision History  :\n@*        DD MM YYYY    Author(s)   Changes\n@*        03 07 2008    100355      First version\n@*\n@*****************************************************************************\n\n        .global ih264_arm_dmb\n\nih264_arm_dmb:\n    dmb\n    bx            lr\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_deblk_chroma_a9.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@/*****************************************************************************/\n@/*                                                                           */\n@/*  File Name         : ih264_deblk_chroma_a9.s                              */\n@/*                                                                           */\n@/*  Description       : Contains function definitions for deblocking luma    */\n@/*                      edge. Functions are coded in NEON assembly and can   */\n@/*                      be compiled using ARM RVDS.                          */\n@/*                                                                           */\n@/*  List of Functions : ih264_deblk_chroma_vert_bs4_bp_a9()                  */\n@/*                      ih264_deblk_chroma_vert_bslt4_bp_a9()                */\n@/*                      ih264_deblk_chroma_horz_bs4_bp_a9()                  */\n@/*                      ih264_deblk_chroma_horz_bslt4_bp_a9()                */\n@/*                      ih264_deblk_chroma_vert_bs4_mbaff_bp_a9()            */\n@/*                      ih264_deblk_chroma_vert_bslt4_mbaff_bp_a9()          */\n@/*                      ih264_deblk_chroma_vert_bs4_a9()                     */\n@/*                      ih264_deblk_chroma_vert_bslt4_a9()                   */\n@/*                      ih264_deblk_chroma_horz_bs4_a9()                     */\n@/*                      ih264_deblk_chroma_horz_bslt4_a9()                   */\n@/*                      ih264_deblk_chroma_vert_bs4_mbaff_a9()               */\n@/*                      ih264_deblk_chroma_vert_bslt4_mbaff_a9()             */\n@/*                                                                           */\n@/*  Issues / Problems : None                                                 */\n@/*                                                                           */\n@/*  Revision History  :                                                      */\n@/*                                                                           */\n@/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n@/*         28 11 2013   Ittiam          Draft                                */\n@/*         05 01 2015   Kaushik         Added double-call functions for      */\n@/*                      Senthoor        vertical deblocking, and high        */\n@/*                                      profile functions.                   */\n@/*                                                                           */\n@/*****************************************************************************/\n\n\n.text\n.p2align 2\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block horizontal edge when the\n@*     boundary strength is set to 4\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_horz_bs4_bp_a9\n\nih264_deblk_chroma_horz_bs4_bp_a9:\n\n    stmfd         sp!, {r4, lr}         @\n    vpush         {d8 - d15}\n    sub           r0, r0, r1, lsl #1    @R0 = uc_edgePixel pointing to p1 of chroma\n    vld2.8        {d6, d7}, [r0], r1    @D6 = p1u , D7 = p1v\n    mov           r4, r0                @Keeping a backup of the pointer p0 of chroma\n    vld2.8        {d4, d5}, [r0], r1    @D4 = p0u , D5 = p0v\n    vdup.8        q10, r2               @Q10 contains alpha\n    vld2.8        {d0, d1}, [r0], r1    @D0 = q0u , D1 = q0v\n    vaddl.u8      q4, d6, d0            @\n    vaddl.u8      q5, d7, d1            @Q4,Q5 = q0 + p1\n    vmov.i8       d31, #2               @\n    vld2.8        {d2, d3}, [r0]        @D2 = q1u , D3 = q1v\n    vabd.u8       q13, q3, q2           @Q13 = ABS(p1 - p0)\n    vmlal.u8      q4, d2, d31           @\n    vmlal.u8      q5, d3, d31           @Q5,Q4 = (X2(q1U) + q0U + p1U)\n    vabd.u8       q11, q2, q0           @Q11 = ABS(p0 - q0)\n    vabd.u8       q12, q1, q0           @Q12 = ABS(q1 - q0)\n    vaddl.u8      q7, d4, d2            @\n    vaddl.u8      q14, d5, d3           @Q14,Q7 = P0 + Q1\n    vdup.8        q8, r3                @Q8 contains beta\n    vmlal.u8      q7, d6, d31           @\n    vmlal.u8      q14, d7, d31          @Q14,Q7 = (X2(p1U) + p0U + q1U)\n    vcge.u8       q9, q11, q10          @Q9 = ( ABS(p0 - q0) >= Alpha )\n    vcge.u8       q12, q12, q8          @Q12= ( ABS(q1 - q0) >= Beta )\n    vcge.u8       q13, q13, q8          @Q13= ( ABS(p1 - p0) >= Beta )\n    vrshrn.u16    d8, q4, #2            @\n    vrshrn.u16    d9, q5, #2            @Q4 = (X2(q1U) + q0U + p1U + 2) >> 2\n    vorr          q9, q9, q12           @Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta )\n    vrshrn.u16    d10, q7, #2           @\n    vrshrn.u16    d11, q14, #2          @Q5 = (X2(p1U) + p0U + q1U + 2) >> 2\n    vorr          q9, q9, q13           @Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta ) | ( ABS(p1 - p0) >= Beta )\n    vbit          q5, q2, q9            @\n    vbit          q4, q0, q9            @\n    vst2.8        {d10, d11}, [r4], r1  @\n    vst2.8        {d8, d9}, [r4]        @\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r4, pc}         @\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block vertical edge when the\n@*     boundary strength is set to 4\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_vert_bs4_bp_a9\n\nih264_deblk_chroma_vert_bs4_bp_a9:\n\n    stmfd         sp!, {r12, r14}\n    vpush         {d8 - d15}\n    sub           r0, r0, #4            @point r0 to p1u of row0.\n    mov           r12, r0               @keep a back up of r0 for buffer write\n\n    vld4.16       {d0[0], d2[0], d4[0], d6[0]}, [r0], r1\n    vld4.16       {d0[1], d2[1], d4[1], d6[1]}, [r0], r1\n    vld4.16       {d0[2], d2[2], d4[2], d6[2]}, [r0], r1\n    vld4.16       {d0[3], d2[3], d4[3], d6[3]}, [r0], r1\n\n    vld4.16       {d1[0], d3[0], d5[0], d7[0]}, [r0], r1\n    vld4.16       {d1[1], d3[1], d5[1], d7[1]}, [r0], r1\n    vld4.16       {d1[2], d3[2], d5[2], d7[2]}, [r0], r1\n    vld4.16       {d1[3], d3[3], d5[3], d7[3]}, [r0], r1\n\n    vdup.8        q11, r2               @Q4 = alpha\n    vdup.8        q12, r3               @Q5 = beta\n    vmov.i8       d31, #2\n\n    vabd.u8       q4, q1, q2            @|p0-q0|\n    vabd.u8       q5, q3, q2            @|q1-q0|\n    vabd.u8       q6, q0, q1            @|p1-p0|\n    vaddl.u8      q7, d2, d6\n    vaddl.u8      q8, d3, d7            @(p0 + q1)\n    vclt.u8       q4, q4, q11           @|p0-q0| < alpha ?\n    vclt.u8       q5, q5, q12           @|q1-q0| < beta ?\n    vclt.u8       q6, q6, q12           @|p1-p0| < beta ?\n    vmlal.u8      q7, d0, d31\n    vmlal.u8      q8, d1, d31           @2*p1 + (p0 + q1)\n    vaddl.u8      q9, d0, d4\n    vaddl.u8      q10, d1, d5           @(p1 + q0)\n    vand.u8       q4, q4, q5            @|p0-q0| < alpha && |q1-q0| < beta\n    vmlal.u8      q9, d6, d31\n    vmlal.u8      q10, d7, d31          @2*q1 + (p1 + q0)\n\n    vrshrn.i16    d14, q7, #2\n    vrshrn.i16    d15, q8, #2           @(2*p1 + (p0 + q1) + 2) >> 2\n    vand.u8       q4, q4, q6            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta\n    vrshrn.i16    d18, q9, #2\n    vrshrn.i16    d19, q10, #2          @(2*q1 + (p1 + q0) + 2) >> 2\n\n    vbit          q1, q7, q4\n    vbit          q2, q9, q4\n\n    vst4.16       {d0[0], d2[0], d4[0], d6[0]}, [r12], r1\n    vst4.16       {d0[1], d2[1], d4[1], d6[1]}, [r12], r1\n    vst4.16       {d0[2], d2[2], d4[2], d6[2]}, [r12], r1\n    vst4.16       {d0[3], d2[3], d4[3], d6[3]}, [r12], r1\n\n    vst4.16       {d1[0], d3[0], d5[0], d7[0]}, [r12], r1\n    vst4.16       {d1[1], d3[1], d5[1], d7[1]}, [r12], r1\n    vst4.16       {d1[2], d3[2], d5[2], d7[2]}, [r12], r1\n    vst4.16       {d1[3], d3[3], d5[3], d7[3]}, [r12], r1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r12, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block horizontal edge for cases where the\n@*     boundary strength is less than 4\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @param[in] sp(0) - u4_bs\n@*  Packed Boundary strength array\n@*\n@* @param[in] sp(4) - pu1_cliptab\n@*  tc0_table\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_horz_bslt4_bp_a9\n\nih264_deblk_chroma_horz_bslt4_bp_a9:\n\n    stmfd         sp!, {r4-r6, lr}      @\n\n    ldrd          r4, r5, [sp, #0x10]   @r4 = u4_bs , r5 = pu1_cliptab\n    vpush         {d8 - d15}\n    sub           r0, r0, r1, lsl #1    @R0 = uc_edgePixelU pointing to p2 of chroma U\n    rev           r4, r4                @\n    vmov.32       d12[0], r4            @d12[0] = ui_Bs\n    vld1.32       d16[0], [r5]          @D16[0] contains cliptab\n    vld2.8        {d6, d7}, [r0], r1    @Q3=p1\n    vtbl.8        d14, {d16}, d12       @\n    vmovl.u8      q6, d12               @q6 = uc_Bs in each 16 bit scalar\n    mov           r6, r0                @Keeping a backup of the pointer to chroma U P0\n    vld2.8        {d4, d5}, [r0], r1    @Q2=p0\n    vmov.i8       d30, #1               @\n    vdup.8        q10, r2               @Q10 contains alpha\n    vld2.8        {d0, d1}, [r0], r1    @Q0=q0\n    vmovl.u8      q7, d14               @\n    vld2.8        {d2, d3}, [r0]        @Q1=q1\n    vsubl.u8      q5, d1, d5            @\n    vsubl.u8      q4, d0, d4            @Q5,Q4 = (q0 - p0)\n    vabd.u8       q13, q3, q2           @Q13 = ABS(p1 - p0)\n    vshl.i16      q5, q5, #2            @Q5 = (q0 - p0)<<2\n    vabd.u8       q11, q2, q0           @Q11 = ABS(p0 - q0)\n    vshl.i16      q4, q4, #2            @Q4 = (q0 - p0)<<2\n    vsli.16       q7, q7, #8            @\n    vabd.u8       q12, q1, q0           @Q12 = ABS(q1 - q0)\n    vcge.u8       q9, q11, q10          @Q9 = ( ABS(p0 - q0) >= Alpha )\n    vsubl.u8      q10, d6, d2           @Q10 = (p1 - q1)L\n    vsubl.u8      q3, d7, d3            @Q3 = (p1 - q1)H\n    vdup.8        q8, r3                @Q8 contains beta\n    vadd.i16      q4, q4, q10           @\n    vadd.i16      q5, q5, q3            @Q5,Q4 = [ (q0 - p0)<<2 ] + (p1 - q1)\n    vcge.u8       q12, q12, q8          @Q12= ( ABS(q1 - q0) >= Beta )\n    vcgt.s16      d12, d12, #0          @Q6 = (us_Bs > 0)\n    vqrshrn.s16   d8, q4, #3            @\n    vqrshrn.s16   d9, q5, #3            @Q4 = i_macro = (((q0 - p0)<<2) + (p1 - q1) + 4)>>3\n    vadd.i8       d14, d14, d30         @Q7 = C = C0+1\n    vcge.u8       q13, q13, q8          @Q13= ( ABS(p1 - p0) >= Beta )\n    vorr          q9, q9, q12           @Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta )\n    vabs.s8       q3, q4                @Q4 = ABS (i_macro)\n    vmov.i8       d15, d14              @\n    vmov.i8       d13, d12              @\n    vorr          q9, q9, q13           @Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta ) | ( ABS(p1 - p0) >= Beta )\n    vmin.u8       q7, q3, q7            @Q7 = delta = (ABS(i_macro) > C) ? C : ABS(i_macro)\n    vbic          q6, q6, q9            @final condition\n    vcge.s8       q4, q4, #0            @Q4  = (i_macro >= 0)\n    vand          q7, q7, q6            @Making delta zero in places where values shouldn be filterd\n    vqadd.u8      q8, q2, q7            @Q8  = p0 + delta\n    vqsub.u8      q2, q2, q7            @Q2 = p0 - delta\n    vqadd.u8      q9, q0, q7            @Q9 = q0 + delta\n    vqsub.u8      q0, q0, q7            @Q0 = q0 - delta\n    vbif          q8, q2, q4            @Q8  = (i_macro >= 0 ) ? (p0+delta) : (p0-delta)\n    vbif          q0, q9, q4            @Q0  = (i_macro >= 0 ) ? (q0-delta) : (q0+delta)\n    vst2.8        {d16, d17}, [r6], r1  @\n    vst2.8        {d0, d1}, [r6]        @\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r4-r6, pc}      @\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block vertical edge for cases where the\n@*     boundary strength is less than 4\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @param[in] sp(0) - u4_bs\n@*  Packed Boundary strength array\n@*\n@* @param[in] sp(4) - pu1_cliptab\n@*  tc0_table\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_vert_bslt4_bp_a9\n\nih264_deblk_chroma_vert_bslt4_bp_a9:\n\n    stmfd         sp!, {r10-r12, r14}\n\n    sub           r0, r0, #4            @point r0 to p1u of row0.\n    ldr           r11, [sp, #16]        @r12 = ui_Bs\n\n    ldr           r10, [sp, #20]        @r14 = puc_ClipTab\n    mov           r12, r0               @keep a back up of r0 for buffer write\n    vpush         {d8 - d15}\n    vld4.16       {d0[0], d2[0], d4[0], d6[0]}, [r0], r1\n    vld4.16       {d0[1], d2[1], d4[1], d6[1]}, [r0], r1\n    vld4.16       {d0[2], d2[2], d4[2], d6[2]}, [r0], r1\n    vld4.16       {d0[3], d2[3], d4[3], d6[3]}, [r0], r1\n\n    vld4.16       {d1[0], d3[0], d5[0], d7[0]}, [r0], r1\n    vld4.16       {d1[1], d3[1], d5[1], d7[1]}, [r0], r1\n    vld4.16       {d1[2], d3[2], d5[2], d7[2]}, [r0], r1\n    vld4.16       {d1[3], d3[3], d5[3], d7[3]}, [r0], r1\n\n\n    vdup.8        q11, r2               @Q4 = alpha\n    vabd.u8       q4, q1, q2            @|p0-q0|\n    vdup.8        q12, r3               @Q5 = beta\n    vabd.u8       q5, q3, q2            @|q1-q0|\n    vabd.u8       q6, q0, q1            @|p1-p0|\n    vclt.u8       q4, q4, q11           @|p0-q0| < alpha ?\n    vsubl.u8      q7, d0, d6\n    vclt.u8       q5, q5, q12           @|q1-q0| < beta ?\n    vsubl.u8      q8, d1, d7            @(p1 - q1)\n    vclt.u8       q6, q6, q12           @|p1-p0| < beta ?\n    vsubl.u8      q9, d4, d2\n    vand.u8       q4, q4, q5            @|p0-q0| < alpha && |q1-q0| < beta\n    vsubl.u8      q10, d5, d3           @(q0 - p0)\n    vmov.u16      q14, #4\n    vld1.32       {d24[0]}, [r10]       @Load ClipTable\n    rev           r11, r11              @Blocking strengths\n    vand.u8       q4, q4, q6            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta\n\n    vmov.32       d10[0], r11\n\n    vmla.s16      q7, q9, q14\n    vmla.s16      q8, q10, q14          @4*(q0 - p0) + (p1 - q1)\n\n    vmovl.u8      q5, d10\n\n\n    vsli.u16      d10, d10, #8\n    vmovl.u16     q5, d10\n    vsli.u32      q5, q5, #16\n    vtbl.8        d12, {d24}, d10\n    vtbl.8        d13, {d24}, d11       @tC0\n    vmov.u8       q12, #1\n    vadd.u8       q6, q6, q12           @tC0 + 1\n    vcge.u8       q5, q5, q12           @u4_bS > 0 ?\n    vand.u8       q4, q4, q5            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta && u4_bs != 0\n\n    @ Q0 - Q3(inputs),\n    @ Q4 (|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta && u4_bs != 0),\n    @ Q6 (tC)\n\n    vrshr.s16     q7, q7, #3\n    vrshr.s16     q8, q8, #3            @(((q0 - p0) << 2) + (p1 - q1) + 4) >> 3)\n\n    vcgt.s16      q9, q7, #0\n    vcgt.s16      q10, q8, #0\n    vmovn.i16     d18, q9\n    vmovn.i16     d19, q10              @Q9 = sign(delta)\n    vabs.s16      q7, q7\n    vabs.s16      q8, q8\n    vmovn.u16     d14, q7\n    vmovn.u16     d15, q8\n    vmin.u8       q7, q7, q6            @Q7 = |delta|\n\n    vqadd.u8      q10, q1, q7           @p0+|delta|\n    vqadd.u8      q11, q2, q7           @q0+|delta|\n    vqsub.u8      q12, q1, q7           @p0-|delta|\n    vqsub.u8      q13, q2, q7           @q0-|delta|\n\n    vbit          q12, q10, q9          @p0 + delta\n    vbit          q11, q13, q9          @q0 - delta\n\n    vbit          q1, q12, q4\n    vbit          q2, q11, q4\n\n    vst4.16       {d0[0], d2[0], d4[0], d6[0]}, [r12], r1\n    vst4.16       {d0[1], d2[1], d4[1], d6[1]}, [r12], r1\n    vst4.16       {d0[2], d2[2], d4[2], d6[2]}, [r12], r1\n    vst4.16       {d0[3], d2[3], d4[3], d6[3]}, [r12], r1\n\n    vst4.16       {d1[0], d3[0], d5[0], d7[0]}, [r12], r1\n    vst4.16       {d1[1], d3[1], d5[1], d7[1]}, [r12], r1\n    vst4.16       {d1[2], d3[2], d5[2], d7[2]}, [r12], r1\n    vst4.16       {d1[3], d3[3], d5[3], d7[3]}, [r12], r1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r10-r12, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block vertical edge when the\n@*     boundary strength is set to 4 on calling twice\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_vert_bs4_mbaff_bp_a9\n\nih264_deblk_chroma_vert_bs4_mbaff_bp_a9:\n\n    stmfd         sp!, {r12, r14}\n    vpush         {d8 - d15}\n    sub           r0, r0, #4            @point r0 to p1u of row0.\n    mov           r12, r0               @keep a back up of r0 for buffer write\n\n    vld4.16       {d0[0], d1[0], d2[0], d3[0]}, [r0], r1\n    vld4.16       {d0[1], d1[1], d2[1], d3[1]}, [r0], r1\n    vld4.16       {d0[2], d1[2], d2[2], d3[2]}, [r0], r1\n    vld4.16       {d0[3], d1[3], d2[3], d3[3]}, [r0], r1\n\n    vdup.8        d11, r2               @D11 = alpha\n    vdup.8        d12, r3               @D12 = beta\n    vmov.i8       d31, #2\n\n    vabd.u8       d4, d1, d2            @|p0-q0|\n    vabd.u8       d5, d3, d2            @|q1-q0|\n    vabd.u8       d6, d0, d1            @|p1-p0|\n    vaddl.u8      q14, d1, d3           @(p0 + q1)\n    vclt.u8       d4, d4, d11           @|p0-q0| < alpha ?\n    vclt.u8       d5, d5, d12           @|q1-q0| < beta ?\n    vclt.u8       d6, d6, d12           @|p1-p0| < beta ?\n    vmlal.u8      q14, d0, d31          @2*p1 + (p0 + q1)\n    vaddl.u8      q13, d0, d2           @(p1 + q0)\n    vand.u8       d4, d4, d5            @|p0-q0| < alpha && |q1-q0| < beta\n    vmlal.u8      q13, d3, d31          @2*q1 + (p1 + q0)\n\n    vrshrn.i16    d7, q14, #2           @(2*p1 + (p0 + q1) + 2) >> 2\n    vand.u8       d4, d4, d6            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta\n    vrshrn.i16    d9, q13, #2           @(2*q1 + (p1 + q0) + 2) >> 2\n\n    vbit          d1, d7, d4\n    vbit          d2, d9, d4\n\n    vst4.16       {d0[0], d1[0], d2[0], d3[0]}, [r12], r1\n    vst4.16       {d0[1], d1[1], d2[1], d3[1]}, [r12], r1\n    vst4.16       {d0[2], d1[2], d2[2], d3[2]}, [r12], r1\n    vst4.16       {d0[3], d1[3], d2[3], d3[3]}, [r12], r1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r12, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block vertical edge for cases where the\n@*     boundary strength is less than 4 on calling twice\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @param[in] sp(0) - u4_bs\n@*  Packed Boundary strength array\n@*\n@* @param[in] sp(4) - pu1_cliptab\n@*  tc0_table\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_vert_bslt4_mbaff_bp_a9\n\nih264_deblk_chroma_vert_bslt4_mbaff_bp_a9:\n\n    stmfd         sp!, {r10-r12, r14}\n\n    sub           r0, r0, #4            @point r0 to p1u of row0.\n    ldr           r11, [sp, #16]        @r11 = ui_Bs\n\n    ldr           r10, [sp, #20]        @r10 = puc_ClipTab\n    mov           r12, r0               @keep a back up of r0 for buffer write\n    vpush         {d8 - d15}\n    vld4.16       {d0[0], d1[0], d2[0], d3[0]}, [r0], r1\n    vld4.16       {d0[1], d1[1], d2[1], d3[1]}, [r0], r1\n    vld4.16       {d0[2], d1[2], d2[2], d3[2]}, [r0], r1\n    vld4.16       {d0[3], d1[3], d2[3], d3[3]}, [r0], r1\n\n    vdup.8        d11, r2               @D11 = alpha\n    vabd.u8       d4, d1, d2            @|p0-q0|\n    vdup.8        d12, r3               @D12 = beta\n    vabd.u8       d5, d3, d2            @|q1-q0|\n    vabd.u8       d6, d0, d1            @|p1-p0|\n    vclt.u8       d4, d4, d11           @|p0-q0| < alpha ?\n    vclt.u8       d5, d5, d12           @|q1-q0| < beta ?\n    vsubl.u8      q14, d0, d3           @(p1 - q1)\n    vclt.u8       d6, d6, d12           @|p1-p0| < beta ?\n    vand.u8       d4, d4, d5            @|p0-q0| < alpha && |q1-q0| < beta\n    vsubl.u8      q12, d2, d1           @(q0 - p0)\n    vmov.u16      q10, #4\n\n    vld1.32       {d31[0]}, [r10]       @Load ClipTable\n    rev           r11, r11              @Blocking strengths\n    vand.u8       d4, d4, d6            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta\n    vmov.32       d22[0], r11\n    vmla.s16      q14, q12, q10         @4*(q0 - p0) + (p1 - q1)\n    vmovl.u8      q11, d22\n    vsli.u16      d22, d22, #8\n    vtbl.8        d6, {d31}, d22        @tC0\n    vmov.u8       d12, #1\n    vadd.u8       d6, d6, d12           @tC0 + 1\n    vcge.u8       d5, d22, d12          @u4_bS > 0 ?\n    vand.u8       d4, d4, d5            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta && u4_bs != 0\n\n    @ D0 - D3(inputs),\n    @ D4 (|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta && u4_bs != 0),\n    @ D6 (tC)\n\n    vrshr.s16     q14, q14, #3          @(((q0 - p0) << 2) + (p1 - q1) + 4) >> 3)\n\n    vcgt.s16      q13, q14, #0\n    vmovn.i16     d9, q13               @D9 = sign(delta)\n    vabs.s16      q14, q14\n    vmovn.u16     d7, q14\n    vmin.u8       d7, d7, d6            @D7 = |delta|\n\n    vqadd.u8      d10, d1, d7           @p0+|delta|\n    vqadd.u8      d11, d2, d7           @q0+|delta|\n    vqsub.u8      d12, d1, d7           @p0-|delta|\n    vqsub.u8      d13, d2, d7           @q0-|delta|\n\n    vbit          d12, d10, d9          @p0 + delta\n    vbit          d11, d13, d9          @q0 - delta\n\n    vbit          d1, d12, d4\n    vbit          d2, d11, d4\n\n    vst4.16       {d0[0], d1[0], d2[0], d3[0]}, [r12], r1\n    vst4.16       {d0[1], d1[1], d2[1], d3[1]}, [r12], r1\n    vst4.16       {d0[2], d1[2], d2[2], d3[2]}, [r12], r1\n    vst4.16       {d0[3], d1[3], d2[3], d3[3]}, [r12], r1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r10-r12, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block horizontal edge when the\n@*     boundary strength is set to 4 in high profile\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha_cb\n@*  Alpha Value for the boundary in U\n@*\n@* @param[in] r3 - beta_cb\n@*  Beta Value for the boundary in U\n@*\n@* @param[in] sp(0) - alpha_cr\n@*  Alpha Value for the boundary in V\n@*\n@* @param[in] sp(4) - beta_cr\n@*  Beta Value for the boundary in V\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_horz_bs4_a9\n\nih264_deblk_chroma_horz_bs4_a9:\n\n    stmfd         sp!, {r4-r6, lr}      @\n\n    ldr           r5, [sp, #16]         @R5 = alpha_cr\n    ldr           r6, [sp, #20]         @R6 = beta_cr\n    vpush         {d8 - d15}\n    sub           r0, r0, r1, lsl #1    @R0 = uc_edgePixel pointing to p1 of chroma\n    vld2.8        {d6, d7}, [r0], r1    @D6 = p1u , D7 = p1v\n    mov           r4, r0                @Keeping a backup of the pointer p0 of chroma\n    vld2.8        {d4, d5}, [r0], r1    @D4 = p0u , D5 = p0v\n    vdup.8        d20, r2               @D20 contains alpha_cb\n    vdup.8        d21, r5               @D21 contains alpha_cr\n    vld2.8        {d0, d1}, [r0], r1    @D0 = q0u , D1 = q0v\n    vaddl.u8      q4, d6, d0            @\n    vaddl.u8      q5, d7, d1            @Q4,Q5 = q0 + p1\n    vmov.i8       d31, #2               @\n    vld2.8        {d2, d3}, [r0]        @D2 = q1u , D3 = q1v\n    vabd.u8       q13, q3, q2           @Q13 = ABS(p1 - p0)\n    vmlal.u8      q4, d2, d31           @\n    vmlal.u8      q5, d3, d31           @Q5,Q4 = (X2(q1U) + q0U + p1U)\n    vabd.u8       q11, q2, q0           @Q11 = ABS(p0 - q0)\n    vabd.u8       q12, q1, q0           @Q12 = ABS(q1 - q0)\n    vaddl.u8      q7, d4, d2            @\n    vaddl.u8      q14, d5, d3           @Q14,Q7 = P0 + Q1\n    vdup.8        d16, r3               @D16 contains beta_cb\n    vdup.8        d17, r6               @D17 contains beta_cr\n    vmlal.u8      q7, d6, d31           @\n    vmlal.u8      q14, d7, d31          @Q14,Q7 = (X2(p1U) + p0U + q1U)\n    vcge.u8       q9, q11, q10          @Q9 = ( ABS(p0 - q0) >= Alpha )\n    vcge.u8       q12, q12, q8          @Q12= ( ABS(q1 - q0) >= Beta )\n    vcge.u8       q13, q13, q8          @Q13= ( ABS(p1 - p0) >= Beta )\n    vrshrn.u16    d8, q4, #2            @\n    vrshrn.u16    d9, q5, #2            @Q4 = (X2(q1U) + q0U + p1U + 2) >> 2\n    vorr          q9, q9, q12           @Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta )\n    vrshrn.u16    d10, q7, #2           @\n    vrshrn.u16    d11, q14, #2          @Q5 = (X2(p1U) + p0U + q1U + 2) >> 2\n    vorr          q9, q9, q13           @Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta ) | ( ABS(p1 - p0) >= Beta )\n    vbit          q5, q2, q9            @\n    vbit          q4, q0, q9            @\n    vst2.8        {d10, d11}, [r4], r1  @\n    vst2.8        {d8, d9}, [r4]        @\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r4-r6, pc}      @\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block vertical edge when the\n@*     boundary strength is set to 4 in high profile\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha_cb\n@*  Alpha Value for the boundary in U\n@*\n@* @param[in] r3 - beta_cb\n@*  Beta Value for the boundary in U\n@*\n@* @param[in] sp(0) - alpha_cr\n@*  Alpha Value for the boundary in V\n@*\n@* @param[in] sp(4) - beta_cr\n@*  Beta Value for the boundary in V\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_vert_bs4_a9\n\nih264_deblk_chroma_vert_bs4_a9:\n\n    stmfd         sp!, {r4, r5, r12, r14}\n\n    sub           r0, r0, #4            @point r0 to p1u of row0.\n    mov           r12, r0               @keep a back up of r0 for buffer write\n\n    ldr           r4, [sp, #16]         @r4 = alpha_cr\n    ldr           r5, [sp, #20]         @r5 = beta_cr\n    add           r2, r2, r4, lsl #8    @r2 = (alpha_cr,alpha_cb)\n    add           r3, r3, r5, lsl #8    @r3 = (beta_cr,beta_cb)\n    vpush         {d8 - d15}\n    vld4.16       {d0[0], d2[0], d4[0], d6[0]}, [r0], r1\n    vld4.16       {d0[1], d2[1], d4[1], d6[1]}, [r0], r1\n    vld4.16       {d0[2], d2[2], d4[2], d6[2]}, [r0], r1\n    vld4.16       {d0[3], d2[3], d4[3], d6[3]}, [r0], r1\n\n    vld4.16       {d1[0], d3[0], d5[0], d7[0]}, [r0], r1\n    vld4.16       {d1[1], d3[1], d5[1], d7[1]}, [r0], r1\n    vld4.16       {d1[2], d3[2], d5[2], d7[2]}, [r0], r1\n    vld4.16       {d1[3], d3[3], d5[3], d7[3]}, [r0], r1\n\n    vdup.16       q11, r2               @Q11 = alpha\n    vdup.16       q12, r3               @Q12 = beta\n    vmov.i8       d31, #2\n\n    vabd.u8       q4, q1, q2            @|p0-q0|\n    vabd.u8       q5, q3, q2            @|q1-q0|\n    vabd.u8       q6, q0, q1            @|p1-p0|\n    vaddl.u8      q7, d2, d6\n    vaddl.u8      q8, d3, d7            @(p0 + q1)\n    vclt.u8       q4, q4, q11           @|p0-q0| < alpha ?\n    vclt.u8       q5, q5, q12           @|q1-q0| < beta ?\n    vclt.u8       q6, q6, q12           @|p1-p0| < beta ?\n    vmlal.u8      q7, d0, d31\n    vmlal.u8      q8, d1, d31           @2*p1 + (p0 + q1)\n    vaddl.u8      q9, d0, d4\n    vaddl.u8      q10, d1, d5           @(p1 + q0)\n    vand.u8       q4, q4, q5            @|p0-q0| < alpha && |q1-q0| < beta\n    vmlal.u8      q9, d6, d31\n    vmlal.u8      q10, d7, d31          @2*q1 + (p1 + q0)\n\n    vrshrn.i16    d14, q7, #2\n    vrshrn.i16    d15, q8, #2           @(2*p1 + (p0 + q1) + 2) >> 2\n    vand.u8       q4, q4, q6            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta\n    vrshrn.i16    d18, q9, #2\n    vrshrn.i16    d19, q10, #2          @(2*q1 + (p1 + q0) + 2) >> 2\n\n    vbit          q1, q7, q4\n    vbit          q2, q9, q4\n\n    vst4.16       {d0[0], d2[0], d4[0], d6[0]}, [r12], r1\n    vst4.16       {d0[1], d2[1], d4[1], d6[1]}, [r12], r1\n    vst4.16       {d0[2], d2[2], d4[2], d6[2]}, [r12], r1\n    vst4.16       {d0[3], d2[3], d4[3], d6[3]}, [r12], r1\n\n    vst4.16       {d1[0], d3[0], d5[0], d7[0]}, [r12], r1\n    vst4.16       {d1[1], d3[1], d5[1], d7[1]}, [r12], r1\n    vst4.16       {d1[2], d3[2], d5[2], d7[2]}, [r12], r1\n    vst4.16       {d1[3], d3[3], d5[3], d7[3]}, [r12], r1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r4, r5, r12, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block horizontal edge for cases where the\n@*     boundary strength is less than 4 in high profile\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha_cb\n@*  Alpha Value for the boundary in U\n@*\n@* @param[in] r3 - beta_cb\n@*  Beta Value for the boundary in U\n@*\n@* @param[in] sp(0) - alpha_cr\n@*  Alpha Value for the boundary in V\n@*\n@* @param[in] sp(4) - beta_cr\n@*  Beta Value for the boundary in V\n@*\n@* @param[in] sp(8) - u4_bs\n@*  Packed Boundary strength array\n@*\n@* @param[in] sp(12) - pu1_cliptab_cb\n@*  tc0_table for U\n@*\n@* @param[in] sp(16) - pu1_cliptab_cr\n@*  tc0_table for V\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_horz_bslt4_a9\n\nih264_deblk_chroma_horz_bslt4_a9:\n\n    stmfd         sp!, {r4-r9, lr}      @\n\n    ldrd          r4, r5, [sp, #28]     @R4 = alpha_cr , R5 = beta_cr\n    ldr           r7, [sp, #36]         @R7 = u4_bs\n    ldrd          r8, r9, [sp, #40]     @R8 = pu1_cliptab_cb , R9 = pu1_cliptab_cr\n    sub           r0, r0, r1, lsl #1    @R0 = uc_edgePixelU pointing to p1 of chroma U\n    vpush         {d8 - d15}\n    rev           r7, r7                @\n    vmov.32       d12[0], r7            @D12[0] = ui_Bs\n\n    vld1.32       d16[0], [r8]          @D16[0] contains cliptab_cb\n    vld1.32       d17[0], [r9]          @D17[0] contains cliptab_cr\n    vld2.8        {d6, d7}, [r0], r1    @Q3=p1\n    vtbl.8        d14, {d16}, d12       @Retreiving cliptab values for U\n    vtbl.8        d28, {d17}, d12       @Retrieving cliptab values for V\n    vmovl.u8      q6, d12               @Q6 = uc_Bs in each 16 bit scalar\n    mov           r6, r0                @Keeping a backup of the pointer to chroma U P0\n    vld2.8        {d4, d5}, [r0], r1    @Q2=p0\n    vmov.i8       d30, #1               @\n    vdup.8        d20, r2               @D20 contains alpha_cb\n    vdup.8        d21, r4               @D21 contains alpha_cr\n    vld2.8        {d0, d1}, [r0], r1    @Q0=q0\n    vmovl.u8      q7, d14               @\n    vmovl.u8      q14, d28              @\n    vmov.i16      d15, d28              @D14 has cliptab values for U, D15 for V\n    vld2.8        {d2, d3}, [r0]        @Q1=q1\n    vsubl.u8      q5, d1, d5            @\n    vsubl.u8      q4, d0, d4            @Q5,Q4 = (q0 - p0)\n    vabd.u8       q13, q3, q2           @Q13 = ABS(p1 - p0)\n    vshl.i16      q5, q5, #2            @Q5 = (q0 - p0)<<2\n    vabd.u8       q11, q2, q0           @Q11 = ABS(p0 - q0)\n    vshl.i16      q4, q4, #2            @Q4 = (q0 - p0)<<2\n    vsli.16       q7, q7, #8            @\n    vabd.u8       q12, q1, q0           @Q12 = ABS(q1 - q0)\n    vcge.u8       q9, q11, q10          @Q9 = ( ABS(p0 - q0) >= Alpha )\n    vsubl.u8      q10, d6, d2           @Q10 = (p1 - q1)L\n    vsubl.u8      q3, d7, d3            @Q3 = (p1 - q1)H\n    vdup.8        d16, r3               @Q8 contains beta_cb\n    vdup.8        d17, r5               @Q8 contains beta_cr\n    vadd.i16      q4, q4, q10           @\n    vadd.i16      q5, q5, q3            @Q5,Q4 = [ (q0 - p0)<<2 ] + (p1 - q1)\n    vcge.u8       q12, q12, q8          @Q12= ( ABS(q1 - q0) >= Beta )\n    vcgt.s16      d12, d12, #0          @Q6 = (us_Bs > 0)\n    vqrshrn.s16   d8, q4, #3            @\n    vqrshrn.s16   d9, q5, #3            @Q4 = i_macro = (((q0 - p0)<<2) + (p1 - q1) + 4)>>3\n    vadd.i8       d14, d14, d30         @D14 = C = C0+1 for U\n    vcge.u8       q13, q13, q8          @Q13= ( ABS(p1 - p0) >= Beta )\n    vorr          q9, q9, q12           @Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta )\n    vabs.s8       q3, q4                @Q4 = ABS (i_macro)\n    vadd.i8       d15, d15, d30         @D15 = C = C0+1 for V\n    vmov.i8       d13, d12              @\n    vorr          q9, q9, q13           @Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta ) | ( ABS(p1 - p0) >= Beta )\n    vmin.u8       q7, q3, q7            @Q7 = delta = (ABS(i_macro) > C) ? C : ABS(i_macro)\n    vbic          q6, q6, q9            @final condition\n    vcge.s8       q4, q4, #0            @Q4  = (i_macro >= 0)\n    vand          q7, q7, q6            @Making delta zero in places where values shouldn be filterd\n    vqadd.u8      q8, q2, q7            @Q8 = p0 + delta\n    vqsub.u8      q2, q2, q7            @Q2 = p0 - delta\n    vqadd.u8      q9, q0, q7            @Q9 = q0 + delta\n    vqsub.u8      q0, q0, q7            @Q0 = q0 - delta\n    vbif          q8, q2, q4            @Q8 = (i_macro >= 0 ) ? (p0+delta) : (p0-delta)\n    vbif          q0, q9, q4            @Q0 = (i_macro >= 0 ) ? (q0-delta) : (q0+delta)\n    vst2.8        {d16, d17}, [r6], r1  @\n    vst2.8        {d0, d1}, [r6]        @\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r4-r9, pc}      @\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block vertical edge for cases where the\n@*     boundary strength is less than 4 in high profile\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha_cb\n@*  Alpha Value for the boundary in U\n@*\n@* @param[in] r3 - beta_cb\n@*  Beta Value for the boundary in U\n@*\n@* @param[in] sp(0) - alpha_cr\n@*  Alpha Value for the boundary in V\n@*\n@* @param[in] sp(4) - beta_cr\n@*  Beta Value for the boundary in V\n@*\n@* @param[in] sp(8) - u4_bs\n@*  Packed Boundary strength array\n@*\n@* @param[in] sp(12) - pu1_cliptab_cb\n@*  tc0_table for U\n@*\n@* @param[in] sp(16) - pu1_cliptab_cr\n@*  tc0_table for V\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_vert_bslt4_a9\n\nih264_deblk_chroma_vert_bslt4_a9:\n\n    stmfd         sp!, {r4-r7, r10-r12, r14}\n\n    sub           r0, r0, #4            @point r0 to p1u of row0.\n    ldrd          r4, r5, [sp, #32]     @R4 = alpha_cr , R5 = beta_cr\n    add           r2, r2, r4, lsl #8\n    add           r3, r3, r5, lsl #8\n    ldr           r6, [sp, #40]         @R6 = u4_bs\n    ldrd          r10, r11, [sp, #44]   @R10 = pu1_cliptab_cb , R11 = pu1_cliptab_cr\n    vpush         {d8 - d15}\n    mov           r12, r0               @keep a back up of R0 for buffer write\n\n    vld4.16       {d0[0], d2[0], d4[0], d6[0]}, [r0], r1\n    vld4.16       {d0[1], d2[1], d4[1], d6[1]}, [r0], r1\n    vld4.16       {d0[2], d2[2], d4[2], d6[2]}, [r0], r1\n    vld4.16       {d0[3], d2[3], d4[3], d6[3]}, [r0], r1\n\n    vld4.16       {d1[0], d3[0], d5[0], d7[0]}, [r0], r1\n    vld4.16       {d1[1], d3[1], d5[1], d7[1]}, [r0], r1\n    vld4.16       {d1[2], d3[2], d5[2], d7[2]}, [r0], r1\n    vld4.16       {d1[3], d3[3], d5[3], d7[3]}, [r0], r1\n\n\n    vdup.16       q11, r2               @Q11 = alpha\n    vabd.u8       q4, q1, q2            @|p0-q0|\n    vdup.16       q12, r3               @Q12 = beta\n    vabd.u8       q5, q3, q2            @|q1-q0|\n    vabd.u8       q6, q0, q1            @|p1-p0|\n    vclt.u8       q4, q4, q11           @|p0-q0| < alpha ?\n    vsubl.u8      q7, d0, d6\n    vclt.u8       q5, q5, q12           @|q1-q0| < beta ?\n    vsubl.u8      q8, d1, d7            @(p1 - q1)\n    vclt.u8       q6, q6, q12           @|p1-p0| < beta ?\n    vsubl.u8      q9, d4, d2\n    vand.u8       q4, q4, q5            @|p0-q0| < alpha && |q1-q0| < beta\n    vsubl.u8      q10, d5, d3           @(q0 - p0)\n    vmov.u16      q14, #4\n    vld1.32       {d24[0]}, [r10]       @Load ClipTable for U\n    vld1.32       {d25[0]}, [r11]       @Load ClipTable for V\n    rev           r6, r6                @Blocking strengths\n    vand.u8       q4, q4, q6            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta\n\n    vmov.32       d10[0], r6\n\n    vmla.s16      q7, q9, q14\n    vmla.s16      q8, q10, q14          @4*(q0 - p0) + (p1 - q1)\n\n    vmovl.u8      q5, d10\n    vsli.u16      d10, d10, #8\n    vtbl.8        d12, {d24}, d10       @tC0 for U\n    vtbl.8        d13, {d25}, d10       @tC0 for V\n    vzip.8        d12, d13\n    vmovl.u16     q5, d10\n    vsli.u32      q5, q5, #16\n    vmov.u8       q12, #1\n    vadd.u8       q6, q6, q12           @tC0 + 1\n    vcge.u8       q5, q5, q12           @u4_bS > 0 ?\n    vand.u8       q4, q4, q5            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta && u4_bs != 0\n\n    @ Q0 - Q3(inputs),\n    @ Q4 (|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta && u4_bs != 0),\n    @ Q6 (tC)\n\n    vrshr.s16     q7, q7, #3\n    vrshr.s16     q8, q8, #3            @(((q0 - p0) << 2) + (p1 - q1) + 4) >> 3)\n\n    vcgt.s16      q9, q7, #0\n    vcgt.s16      q10, q8, #0\n    vmovn.i16     d18, q9\n    vmovn.i16     d19, q10              @Q9 = sign(delta)\n    vabs.s16      q7, q7\n    vabs.s16      q8, q8\n    vmovn.u16     d14, q7\n    vmovn.u16     d15, q8\n    vmin.u8       q7, q7, q6            @Q7 = |delta|\n\n    vqadd.u8      q10, q1, q7           @p0+|delta|\n    vqadd.u8      q11, q2, q7           @q0+|delta|\n    vqsub.u8      q12, q1, q7           @p0-|delta|\n    vqsub.u8      q13, q2, q7           @q0-|delta|\n\n    vbit          q12, q10, q9          @p0 + delta\n    vbit          q11, q13, q9          @q0 - delta\n\n    vbit          q1, q12, q4\n    vbit          q2, q11, q4\n\n    vst4.16       {d0[0], d2[0], d4[0], d6[0]}, [r12], r1\n    vst4.16       {d0[1], d2[1], d4[1], d6[1]}, [r12], r1\n    vst4.16       {d0[2], d2[2], d4[2], d6[2]}, [r12], r1\n    vst4.16       {d0[3], d2[3], d4[3], d6[3]}, [r12], r1\n\n    vst4.16       {d1[0], d3[0], d5[0], d7[0]}, [r12], r1\n    vst4.16       {d1[1], d3[1], d5[1], d7[1]}, [r12], r1\n    vst4.16       {d1[2], d3[2], d5[2], d7[2]}, [r12], r1\n    vst4.16       {d1[3], d3[3], d5[3], d7[3]}, [r12], r1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r4-r7, r10-r12, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block vertical edge when the\n@*     boundary strength is set to 4 on calling twice in high profile\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha_cb\n@*  Alpha Value for the boundary in U\n@*\n@* @param[in] r3 - beta_cb\n@*  Beta Value for the boundary in U\n@*\n@* @param[in] sp(0) - alpha_cr\n@*  Alpha Value for the boundary in V\n@*\n@* @param[in] sp(4) - beta_cr\n@*  Beta Value for the boundary in V\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_vert_bs4_mbaff_a9\n\nih264_deblk_chroma_vert_bs4_mbaff_a9:\n\n    stmfd         sp!, {r4, r5, r12, r14}\n\n    sub           r0, r0, #4            @point r0 to p1u of row0.\n    mov           r12, r0               @keep a back up of r0 for buffer write\n    ldrd          r4, r5, [sp, #16]     @R4 = alpha_cr , R5 = beta_cr\n    add           r2, r2, r4, lsl #8\n    add           r3, r3, r5, lsl #8\n    vpush         {d8 - d15}\n    vld4.16       {d0[0], d1[0], d2[0], d3[0]}, [r0], r1\n    vld4.16       {d0[1], d1[1], d2[1], d3[1]}, [r0], r1\n    vld4.16       {d0[2], d1[2], d2[2], d3[2]}, [r0], r1\n    vld4.16       {d0[3], d1[3], d2[3], d3[3]}, [r0], r1\n\n    vdup.16       d11, r2               @D11 = alpha\n    vdup.16       d12, r3               @D12 = beta\n    vmov.i8       d31, #2\n\n    vabd.u8       d4, d1, d2            @|p0-q0|\n    vabd.u8       d5, d3, d2            @|q1-q0|\n    vabd.u8       d6, d0, d1            @|p1-p0|\n    vaddl.u8      q14, d1, d3           @(p0 + q1)\n    vclt.u8       d4, d4, d11           @|p0-q0| < alpha ?\n    vclt.u8       d5, d5, d12           @|q1-q0| < beta ?\n    vclt.u8       d6, d6, d12           @|p1-p0| < beta ?\n    vmlal.u8      q14, d0, d31          @2*p1 + (p0 + q1)\n    vaddl.u8      q13, d0, d2           @(p1 + q0)\n    vand.u8       d4, d4, d5            @|p0-q0| < alpha && |q1-q0| < beta\n    vmlal.u8      q13, d3, d31          @2*q1 + (p1 + q0)\n\n    vrshrn.i16    d7, q14, #2           @(2*p1 + (p0 + q1) + 2) >> 2\n    vand.u8       d4, d4, d6            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta\n    vrshrn.i16    d9, q13, #2           @(2*q1 + (p1 + q0) + 2) >> 2\n\n    vbit          d1, d7, d4\n    vbit          d2, d9, d4\n\n    vst4.16       {d0[0], d1[0], d2[0], d3[0]}, [r12], r1\n    vst4.16       {d0[1], d1[1], d2[1], d3[1]}, [r12], r1\n    vst4.16       {d0[2], d1[2], d2[2], d3[2]}, [r12], r1\n    vst4.16       {d0[3], d1[3], d2[3], d3[3]}, [r12], r1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r4, r5, r12, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a chroma block vertical edge for cases where the\n@*     boundary strength is less than 4 on calling twice in high profile\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha_cb\n@*  Alpha Value for the boundary in U\n@*\n@* @param[in] r3 - beta_cb\n@*  Beta Value for the boundary in U\n@*\n@* @param[in] sp(0) - alpha_cr\n@*  Alpha Value for the boundary in V\n@*\n@* @param[in] sp(4) - beta_cr\n@*  Beta Value for the boundary in V\n@*\n@* @param[in] sp(8) - u4_bs\n@*  Packed Boundary strength array\n@*\n@* @param[in] sp(12) - pu1_cliptab_cb\n@*  tc0_table for U\n@*\n@* @param[in] sp(16) - pu1_cliptab_cr\n@*  tc0_table for V\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_chroma_vert_bslt4_mbaff_a9\n\nih264_deblk_chroma_vert_bslt4_mbaff_a9:\n\n    stmfd         sp!, {r4-r6, r10-r12, r14}\n\n    sub           r0, r0, #4            @point r0 to p1u of row0.\n    mov           r12, r0               @keep a back up of r0 for buffer write\n\n    ldrd          r4, r5, [sp, #28]     @R4 = alpha_cr , R5 = beta_cr\n    add           r2, r2, r4, lsl #8\n    add           r3, r3, r5, lsl #8\n    ldr           r6, [sp, #36]         @R6 = u4_bs\n    ldrd          r10, r11, [sp, #40]   @R10 = pu1_cliptab_cb , R11 = pu1_cliptab_cr\n    vpush         {d8 - d15}\n    vld4.16       {d0[0], d1[0], d2[0], d3[0]}, [r0], r1\n    vld4.16       {d0[1], d1[1], d2[1], d3[1]}, [r0], r1\n    vld4.16       {d0[2], d1[2], d2[2], d3[2]}, [r0], r1\n    vld4.16       {d0[3], d1[3], d2[3], d3[3]}, [r0], r1\n\n    vdup.16       d11, r2               @D11 = alpha\n    vabd.u8       d4, d1, d2            @|p0-q0|\n    vdup.16       d12, r3               @D12 = beta\n    vabd.u8       d5, d3, d2            @|q1-q0|\n    vabd.u8       d6, d0, d1            @|p1-p0|\n    vclt.u8       d4, d4, d11           @|p0-q0| < alpha ?\n    vclt.u8       d5, d5, d12           @|q1-q0| < beta ?\n    vsubl.u8      q14, d0, d3           @(p1 - q1)\n    vclt.u8       d6, d6, d12           @|p1-p0| < beta ?\n    vand.u8       d4, d4, d5            @|p0-q0| < alpha && |q1-q0| < beta\n    vsubl.u8      q12, d2, d1           @(q0 - p0)\n    vmov.u16      q10, #4\n\n    vld1.32       {d31[1]}, [r10]       @Load ClipTable for U\n    vld1.32       {d31[0]}, [r11]       @Load ClipTable for V\n    rev           r6, r6                @Blocking strengths\n    vand.u8       d4, d4, d6            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta\n    vmov.32       d22[0], r6\n    vmla.s16      q14, q12, q10         @4*(q0 - p0) + (p1 - q1)\n    vmovl.u8      q11, d22\n    vsli.u16      d22, d22, #8\n    vmov.u16      d13, #4\n    vadd.u8       d22, d22, d13\n    vtbl.8        d6, {d31}, d22        @tC0\n    vmov.u8       d12, #1\n    vsub.u8       d22, d22, d13\n    vadd.u8       d6, d6, d12           @tC0 + 1\n    vcge.u8       d5, d22, d12          @u4_bS > 0 ?\n    vand.u8       d4, d4, d5            @|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta && u4_bs != 0\n\n    @ D0 - D3(inputs),\n    @ D4 (|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta && u4_bs != 0),\n    @ D6 (tC)\n\n    vrshr.s16     q14, q14, #3          @(((q0 - p0) << 2) + (p1 - q1) + 4) >> 3)\n\n    vcgt.s16      q13, q14, #0\n    vmovn.i16     d9, q13               @D9 = sign(delta)\n    vabs.s16      q14, q14\n    vmovn.u16     d7, q14\n    vmin.u8       d7, d7, d6            @D7 = |delta|\n\n    vqadd.u8      d10, d1, d7           @p0+|delta|\n    vqadd.u8      d11, d2, d7           @q0+|delta|\n    vqsub.u8      d12, d1, d7           @p0-|delta|\n    vqsub.u8      d13, d2, d7           @q0-|delta|\n\n    vbit          d12, d10, d9          @p0 + delta\n    vbit          d11, d13, d9          @q0 - delta\n\n    vbit          d1, d12, d4\n    vbit          d2, d11, d4\n\n    vst4.16       {d0[0], d1[0], d2[0], d3[0]}, [r12], r1\n    vst4.16       {d0[1], d1[1], d2[1], d3[1]}, [r12], r1\n    vst4.16       {d0[2], d1[2], d2[2], d3[2]}, [r12], r1\n    vst4.16       {d0[3], d1[3], d2[3], d3[3]}, [r12], r1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r4-r6, r10-r12, pc}\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_deblk_luma_a9.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@/*****************************************************************************/\n@/*                                                                           */\n@/*  File Name         : ih264_deblk_luma_a9.s                                */\n@/*                                                                           */\n@/*  Description       : Contains function definitions for deblocking luma    */\n@/*                      edge. Functions are coded in NEON assembly and can   */\n@/*                      be compiled using ARM RVDS.                          */\n@/*                                                                           */\n@/*  List of Functions : ih264_deblk_luma_vert_bs4_a9()                       */\n@/*                      ih264_deblk_luma_vert_bslt4_a9()                     */\n@/*                      ih264_deblk_luma_horz_bs4_a9()                       */\n@/*                      ih264_deblk_luma_horz_bslt4_a9()                     */\n@/*                      ih264_deblk_luma_vert_bs4_mbaff_a9()                 */\n@/*                      ih264_deblk_luma_vert_bslt4_mbaff_a9()               */\n@/*                                                                           */\n@/*  Issues / Problems : None                                                 */\n@/*                                                                           */\n@/*  Revision History  :                                                      */\n@/*                                                                           */\n@/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n@/*         28 11 2013   Ittiam          Draft                                */\n@/*         05 01 2015   Kaushik         Added double-call functions for      */\n@/*                      Senthoor        vertical deblocking.                 */\n@/*                                                                           */\n@/*****************************************************************************/\n\n\n.text\n.p2align 2\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a luma block horizontal edge for cases where the\n@*     boundary strength is less than 4\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @param[in] sp(0) - u4_bs\n@*  Packed Boundary strength array\n@*\n@* @param[in] sp(4) - pu1_cliptab\n@*  tc0_table\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_luma_horz_bslt4_a9\n\nih264_deblk_luma_horz_bslt4_a9:\n\n    stmfd         sp!, {r4-r7, lr}\n\n    ldrd          r4, r5, [sp, #0x14]   @r4 = ui_Bs , r5 = *puc_ClpTab\n    vpush         {d8 - d15}\n    sub           r0, r0, r1, lsl #1    @R1 = uc_Horizonpad\n    sub           r0, r0, r1            @r0 pointer to p2\n    rev           r4, r4                @\n    vld1.8        {q5}, [r0], r1        @p2 values are loaded into q5\n    vmov.32       d12[0], r4            @d12[0] = ui_Bs\n    mov           r6, r0                @keeping backup of pointer to p1\n    vld1.8        {q4}, [r0], r1        @p1 values are loaded into q4\n    mov           r7, r0                @keeping backup of pointer to p0\n    vld1.8        {q3}, [r0], r1        @p0 values are loaded into q3\n    vmovl.u8      q6, d12               @q6 = uc_Bs in each 16 bt scalar\n    vld1.8        {q0}, [r0], r1        @q0 values are loaded into q0\n    vabd.u8       q13, q4, q3           @Q13 = ABS(p1 - p0)\n    vld1.8        {q1}, [r0], r1        @q1 values are loaded into q1\n    vabd.u8       q11, q3, q0           @Q11 = ABS(p0 - q0)\n    vld1.32       d16[0], [r5]          @D16[0] contains cliptab\n    vabd.u8       q12, q1, q0           @Q12 = ABS(q1 - q0)\n    vld1.8        {q2}, [r0], r1        @q2 values are loaded into q2\n    vtbl.8        d14, {d16}, d12       @\n    vdup.8        q10, r2               @Q10 contains alpha\n    vdup.8        q8, r3                @Q8 contains beta\n    vmovl.u16     q6, d12               @\n    vmovl.u16     q7, d14               @\n    vabd.u8       q14, q5, q3           @Q14 = Ap = ABS(p2 - p0)\n    vabd.u8       q15, q2, q0           @Q15 = Aq = ABS(q2 - q0)\n    vcgt.s32      q6, q6, #0            @Q6 = (us_Bs > 0)\n    vsli.32       q7, q7, #8            @\n    vcge.u8       q9, q11, q10          @Q9 = ( ABS(p0 - q0) >= Alpha )\n    vcge.u8       q12, q12, q8          @Q12=( ABS(q1 - q0) >= Beta )\n    vcge.u8       q13, q13, q8          @Q13=( ABS(p1 - p0) >= Beta )\n    vcgt.u8       q10, q8, q14          @Q10=(Ap<Beta)\n    vcgt.u8       q11, q8, q15          @Q11=(Aq<Beta)\n    vsli.32       q7, q7, #16           @Q7  = C0\n    vorr          q9, q9, q12           @Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta )\n    vsubl.u8      q15, d1, d7           @\n    vsubl.u8      q12, d0, d6           @Q15,Q12 = (q0 - p0)\n    vorr          q9, q9, q13           @Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta ) | ( ABS(p1 - p0) >= Beta )\n    vsubl.u8      q14, d8, d2           @Q14 = (p1 - q1)L\n    vshl.i16      q13, q15, #2          @Q13 = (q0 - p0)<<2\n    vshl.i16      q12, q12, #2          @Q12 = (q0 - p0)<<2\n    vsubl.u8      q15, d9, d3           @Q15 = (p1 - q1)H\n    vbic          q6, q6, q9            @final condition\n    vadd.i16      q12, q12, q14         @\n    vadd.i16      q13, q13, q15         @Q13,Q12 = [ (q0 - p0)<<2 ] + (p1 - q1)\n    vsub.i8       q9, q7, q10           @Q9 = C0 + (Ap < Beta)\n    vrhadd.u8     q8, q3, q0            @Q8 = ((p0+q0+1) >> 1)\n    vqrshrn.s16   d24, q12, #3          @\n    vqrshrn.s16   d25, q13, #3          @Q12 = i_macro = (((q0 - p0)<<2) + (p1 - q1) + 4)>>3\n    vsub.i8       q9, q9, q11           @Q9 = C0 + (Ap < Beta) + (Aq < Beta)\n    vand.i8       q10, q10, q6          @\n    vand.i8       q11, q11, q6          @\n    vabs.s8       q13, q12              @Q13 = ABS (i_macro)\n    vaddl.u8      q14, d17, d11         @\n    vaddl.u8      q5, d16, d10          @Q14,Q5 = p2 + (p0+q0+1)>>1\n    vaddl.u8      q15, d17, d5          @\n    vmin.u8       q9, q13, q9           @Q9 = delta = (ABS(i_macro) > C) ? C : ABS(i_macro)\n    vshll.u8      q13, d9, #1           @\n    vaddl.u8      q2, d16, d4           @Q15,Q2 = q2 + (p0+q0+1)>>1\n    vshll.u8      q8, d8, #1            @Q13,Q8 = (p1<<1)\n    vand          q9, q9, q6            @Making delta zero in places where values shouldn be filterd\n    vsub.i16      q14, q14, q13         @Q14,Q5 = [p2 + (p0+q0+1)>>1] - (p1<<1)\n    vsub.i16      q5, q5, q8            @\n    vshll.u8      q8, d2, #1            @\n    vshll.u8      q13, d3, #1           @Q13,Q8 = (q1<<1)\n    vqshrn.s16    d29, q14, #1          @\n    vqshrn.s16    d28, q5, #1           @Q14 = i_macro_p1\n    vsub.i16      q2, q2, q8            @\n    vsub.i16      q15, q15, q13         @Q15,Q2  = [q2 + (p0+q0+1)>>1] - (q1<<1)\n    vneg.s8       q13, q7               @Q13 = -C0\n    vmin.s8       q14, q14, q7          @Q14 = min(C0,i_macro_p1)\n    vcge.s8       q12, q12, #0          @Q12 = (i_macro >= 0)\n    vqshrn.s16    d31, q15, #1          @\n    vqshrn.s16    d30, q2, #1           @Q15 = i_macro_q1\n    vmax.s8       q14, q14, q13         @Q14 = max( - C0 , min(C0, i_macro_p1) )\n    vqadd.u8      q8, q3, q9            @Q8  = p0 + delta\n    vqsub.u8      q3, q3, q9            @Q3 = p0 - delta\n    vmin.s8       q15, q15, q7          @Q15 = min(C0,i_macro_q1)\n    vand.i8       q14, q10, q14         @condition check Ap<beta\n    vqadd.u8      q7, q0, q9            @Q7 = q0 + delta\n    vqsub.u8      q0, q0, q9            @Q0   = q0 - delta\n    vmax.s8       q15, q15, q13         @Q15 = max( - C0 , min(C0, i_macro_q1) )\n    vbif          q8, q3, q12           @Q8  = (i_macro >= 0 ) ? (p0+delta) : (p0-delta)\n    vbif          q0, q7, q12           @Q0  = (i_macro >= 0 ) ? (q0-delta) : (q0+delta)\n    vadd.i8       q14, q14, q4          @\n    vand.i8       q15, q11, q15         @condition check Aq<beta\n    vst1.8        {q8}, [r7], r1        @writting back filtered value of p0\n    vadd.i8       q15, q15, q1          @\n    vst1.8        {q0}, [r7], r1        @writting back filtered value of q0\n    vst1.8        {q14}, [r6]           @writting back filtered value of p1\n    vst1.8        {q15}, [r7], r1       @writting back filtered value of q1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r4-r7, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a luma block horizontal edge when the\n@*     boundary strength is set to 4\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_luma_horz_bs4_a9\n\nih264_deblk_luma_horz_bs4_a9:\n\n    @ Back up necessary registers on stack\n    stmfd         sp!, {r12, r14}\n    vpush         {d8 - d15}\n    @ Init\n    vdup.8        q0, r2                @duplicate alpha\n    sub           r12, r0, r1           @pointer to p0 = q0 - src_strd\n    vdup.8        q1, r3                @duplicate beta\n    sub           r14, r0, r1, lsl#1    @pointer to p1 = q0 - src_strd*2\n    sub           r2, r0, r1, lsl#2     @pointer to p3 = q0 - src_strd*4\n    sub           r3, r14, r1           @pointer to p2 = p1 - src_strd\n\n    @ Load Data\n    vld1.8        {d4, d5}, [r0], r1    @load q0 to Q2, q0 = q0 + src_strd\n    vld1.8        {d6, d7}, [r12]       @load p0 to Q3\n    vld1.8        {d8, d9}, [r0], r1    @load q1 to Q4, q0 = q0 + src_strd\n    vld1.8        {d10, d11}, [r14]     @load p1 to Q5\n\n    @ Filter Decision\n    vabd.u8       q6, q2, q3            @ABS(p0 - q0)\n    vabd.u8       q7, q4, q2            @ABS(q1 - q0)\n    vabd.u8       q8, q5, q3            @ABS(p1 - p0)\n    vcge.u8       q9, q6, q0            @ABS(p0 - q0) >= Alpha\n    vcge.u8       q7, q7, q1            @ABS(q1 - q0) >= Beta\n    vcge.u8       q8, q8, q1            @ABS(p1 - p0) >= Beta\n    vmov.i8       q10, #2\n    vorr          q9, q9, q7            @ABS(p0 - q0) >= Alpha || ABS(q1 - q0) >= Beta\n    vld1.8        {d14, d15}, [r0], r1  @load q2 to Q7, q0 = q0 + src_strd\n    vorr          q9, q9, q8            @ABS(p0 - q0) >= Alpha || ABS(q1 - q0) >= Beta || ABS(p1 - p0) >= Beta\n    vsra.u8       q10, q0, #2           @((Alpha >> 2) + 2)\n    vabd.u8       q11, q7, q2           @Aq  = ABS(q2 - q0)\n    vaddl.u8      q12, d4, d6           @p0+q0 L\n    vaddl.u8      q13, d5, d7           @p0+q0 H\n    vclt.u8       q11, q11, q1          @Aq < Beta\n    vclt.u8       q10, q6, q10          @(ABS(p0 - q0) <((Alpha >>2) + 2))\n\n    @ Deblock Filtering q0', q1', q2'\n    vaddw.u8      q14, q12, d8          @p0+q0+q1 L\n    vaddw.u8      q15, q13, d9          @p0+q0+q1 H\n    vand          q11, q11, q10         @(Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2))\n    @ q0' if (Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2)) TRUE\n    vadd.i16      q8, q14, q14          @2*(p0+q0+q1)L\n    vadd.i16      q0, q15, q15          @2*(p0+q0+q1)H\n    vaddw.u8      q8, q8, d14           @2*(p0+q0+q1)+q2 L\n    vaddw.u8      q0, q0, d15           @2*(p0+q0+q1)+q2 H\n    vaddw.u8      q8, q8, d10           @2*(p0+q0+q1)+q2 +p1 L\n    vaddw.u8      q0, q0, d11           @2*(p0+q0+q1)+q2 +p1 H\n    vrshrn.u16    d12, q8, #3           @(2*(p0+q0+q1)+q2 +p1 +4)>> 3 L [q0']\n    vrshrn.u16    d13, q0, #3           @(2*(p0+q0+q1)+q2 +p1 +4)>> 3 H [q0']\n    @ q0\" if (Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2)) FALSE\n    vaddl.u8      q8, d8, d8            @2*q1 L\n    vaddl.u8      q0, d9, d9            @2*q1 H\n    vaddw.u8      q8, q8, d4            @2*q1+q0 L\n    vaddw.u8      q0, q0, d5            @2*q1+q0 H\n    vaddw.u8      q8, q8, d10           @2*q1+q0+p1  L\n    vaddw.u8      q0, q0, d11           @2*q1+q0+p1 H\n    vrshrn.u16    d16, q8, #2           @(2*q1+q0+p1+2)>>2 L [q0\"]\n    vrshrn.u16    d17, q0, #2           @(2*q1+q0+p1+2)>>2 H [q0\"]\n    @ q1'\n    vaddw.u8      q14, q14, d14         @p0+q0+q1+q2 L\n    vaddw.u8      q15, q15, d15         @p0+q0+q1+q2 H\n    vld1.8        {q0}, [r0], r1        @load q3 to Q0, q0 = q0 + src_strd\n    vbit          q8, q6, q11           @choosing between q0' and q0\" depending on condn\n    sub           r0, r0, r1, lsl #2    @pointer to q0\n    vbic          q11, q11, q9          @((ABS(p0 - q0) >= Alpha  || ABS(q1 - q0) >= Beta || ABS(p1 - p0) >= Beta))\n                                        @ && (Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2))\n    vrshrn.u16    d12, q14, #2          @(p0+q0+q1+q2+2)>>2 L [q1']\n    vrshrn.u16    d13, q15, #2          @(p0+q0+q1+q2+2)>>2 H [q1']\n    vbif          q2, q8, q9            @choose q0 or filtered q0\n    @ q2'\n    vaddl.u8      q8, d14, d0           @q2+q3,L\n    vaddl.u8      q0, d15, d1           @q2+q3,H\n    vadd.i16      q14, q14, q8          @p0+q0+q1+2*q2+q3 L\n    vst1.8        {d4, d5}, [r0], r1    @store q0\n    vadd.i16      q15, q15, q0          @p0+q0+q1+2*q2+q3 H\n    vadd.i16      q14, q14, q8          @p0+q0+q1+3*q2+2*q3 L\n    vadd.i16      q15, q15, q0          @p0+q0+q1+3*q2+2*q3 H\n    vrshrn.u16    d0, q14, #3           @(p0+q0+q1+3*q2+2*q3+4)>>3 L [q2']\n    vrshrn.u16    d1, q15, #3           @(p0+q0+q1+3*q2+2*q3+4)>>3 H [q2']\n    vld1.8        {d30, d31}, [r3]      @load p2 to Q15\n    vbif          q6, q4, q11           @choose q1 or filtered value of q1\n\n    vabd.u8       q8, q15, q3           @Ap,ABS(p2 - p0)\n    vaddw.u8      q12, q12, d10         @p0+q0+p1 L\n    vbif          q0, q7, q11           @choose q2 or filtered q2\n    vaddw.u8      q13, q13, d11         @p0+q0+p1 H\n    vst1.8        {d12, d13}, [r0], r1  @store q1\n    vclt.u8       q8, q8, q1            @Ap < Beta\n    vadd.i16      q14, q12, q12         @2*(p0+q0+p1) L\n    vadd.i16      q2, q13, q13          @2*(p0+q0+p1) H\n    vst1.8        {d0, d1}, [r0], r1    @store q2\n    vand          q10, q10, q8          @((Ap < Beta) && (ABS(p0 - q0) <((Alpha >>2) + 2)))\n    vaddw.u8      q14, q14, d30         @2*(p0+q0+p1)+p2 l\n    vaddw.u8      q2, q2, d31           @2*(p0+q0+p1)+p2 H\n    vaddw.u8      q14, q14, d8          @2*(p0+q0+p1)+p2+q1 L\n    vaddw.u8      q2, q2, d9            @2*(p0+q0+p1)+p2+q1 H\n    vrshrn.u16    d28, q14, #3          @(2*(p0+q0+p1)+p2+q1+4)>>3  L,p0'\n    vrshrn.u16    d29, q2, #3           @(2*(p0+q0+p1)+p2+q1+4)>>3  H,p0'\n    vmov.i8       d0, #2\n    vmov.i16      d1, #2\n    vaddl.u8      q1, d6, d8            @p0+q1      L\n    vmlal.u8      q1, d10, d0           @2*p1+p0+q1 L\n    vaddl.u8      q8, d7, d9            @p0+q1  H\n    vmlal.u8      q8, d11, d0           @2*p1+p0+q1 H\n    vaddw.u8      q6, q12, d30          @(p0+q0+p1) +p2 L\n    vld1.8        {d24, d25}, [r2]      @load p3,Q12\n    vaddw.u8      q2, q13, d31          @(p0+q0+p1) +p2 H\n    vaddl.u8      q4, d30, d24          @p2+p3 L\n    vrshrn.u16    d26, q6, #2           @((p0+q0+p1)+p2 +2)>>2,p1' L\n    vrshrn.u16    d2, q1, #2            @(2*p1+p0+q1+2)>>2,p0\"L\n    vrshrn.u16    d27, q2, #2           @((p0+q0+p1)+p2 +2)>>2,p1' H\n    vrshrn.u16    d3, q8, #2            @(2*p1+p0+q1+2)>>2,p0\" H\n    vaddl.u8      q8, d31, d25          @p2+p3 H\n    vmla.u16      q6, q4, d1[0]         @(p0+q0+p1)+3*p2+2*p3 L\n    vmla.u16      q2, q8, d1[0]         @(p0+q0+p1)+3*p2+2*p3 H\n    vbic          q8, q10, q9           @((ABS(p0 - q0) >= Alpha  || ABS(q1 - q0) >= Beta || ABS(p1 - p0) >= Beta))\n                                        @&& (Ap < Beta && ABS(p0 - q0) <((Alpha >>2) + 2))\n    vbit          q1, q14, q10          @choosing between po' and p0\"\n    vrshrn.u16    d12, q6, #3           @((p0+q0+p1)+3*p2+2*p3+4)>>3 L p2'\n    vrshrn.u16    d13, q2, #3           @((p0+q0+p1)+3*p2+2*p3+4)>>3 H p2'\n    vbif          q3, q1, q9            @choosing between p0 and filtered value of p0\n    vbit          q5, q13, q8           @choosing between p1 and p1'\n    vbit          q15, q6, q8           @choosing between p2 and p2'\n    vst1.8        {d6, d7}, [r12]       @store p0\n    vst1.8        {d10, d11}, [r14]     @store p1\n    vst1.8        {d30, d31}, [r3]      @store p2\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r12, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a luma block vertical edge for cases where the\n@*     boundary strength is less than 4\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @param[in] sp(0) - u4_bs\n@*  Packed Boundary strength array\n@*\n@* @param[in] sp(4) - pu1_cliptab\n@*  tc0_table\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_luma_vert_bslt4_a9\n\nih264_deblk_luma_vert_bslt4_a9:\n\n    stmfd         sp!, {r12, lr}\n\n    sub           r0, r0, #4            @pointer uc_edgePixel-4\n    ldr           r12, [sp, #8]         @r12 = ui_Bs\n    ldr           r14, [sp, #12]        @r14 = *puc_ClpTab\n    vpush         {d8 - d15}\n    @loading p3:p2:p1:p0:q0:q1:q2:q3 for every row\n    vld1.8        {d0}, [r0], r1        @row1\n    vld1.8        d2, [r0], r1          @row2\n    vld1.8        d4, [r0], r1          @row3\n    rev           r12, r12              @reversing ui_bs\n    vld1.8        d6, [r0], r1          @row4\n    vmov.32       d18[0], r12           @d12[0] = ui_Bs\n    vld1.32       d16[0], [r14]         @D16[0] contains cliptab\n    vld1.8        d8, [r0], r1          @row5\n    vmovl.u8      q9, d18               @q6 = uc_Bs in each 16 bt scalar\n    vld1.8        d10, [r0], r1         @row6\n    vld1.8        d12, [r0], r1         @row7\n    vtbl.8        d16, {d16}, d18       @puc_ClipTab[uc_Bs]\n    vld1.8        d14, [r0], r1         @row8\n    vld1.8        d1, [r0], r1          @row9\n    vmovl.u16     q8, d16               @\n    vld1.8        d3, [r0], r1          @row10\n    vld1.8        d5, [r0], r1          @row11\n    vld1.8        d7, [r0], r1          @row12\n    vsli.32       q8, q8, #8            @\n    vld1.8        d9, [r0], r1          @row13\n    vld1.8        d11, [r0], r1         @row14\n    vld1.8        d13, [r0], r1         @row15\n    vsli.32       q8, q8, #16           @Q8  = C0\n    vld1.8        d15, [r0], r1         @row16\n\n    @taking two 8x8 transposes\n    @2X2 transposes\n    vtrn.8        d0, d2                @row1 &2\n    vtrn.8        d4, d6                @row3&row4\n    vtrn.8        d8, d10               @row5&6\n    vtrn.8        d12, d14              @row7 & 8\n    vtrn.8        d1, d3                @row9 &10\n    vtrn.8        d5, d7                @row11 & 12\n    vtrn.8        d9, d11               @row13 &14\n    vtrn.8        d13, d15              @row15 & 16\n    @4x4 transposes\n    vtrn.16       d2, d6                @row2 & row4\n    vtrn.16       d10, d14              @row6 & row8\n    vtrn.16       d3, d7                @row10 & 12\n    vtrn.16       d11, d15              @row14 & row16\n    vtrn.32       d6, d14               @row4 & 8\n    vtrn.32       d7, d15               @row 12 & 16\n\n    @now Q3 ->p0 and Q7->q3\n    vtrn.16       d0, d4                @row1 & 3\n    vtrn.16       d8, d12               @row 5 & 7\n    vtrn.16       d1, d5                @row9 & row11\n    vtrn.16       d9, d13               @row13 & row15\n    vtrn.32       d0, d8                @row1 & row5\n    vtrn.32       d1, d9                @row9 & 13\n\n    @now Q0->p3 & Q4->q0\n    @starting processing as p0 and q0 are now ready\n    vtrn.32       d2, d10               @row2 &6\n    vrhadd.u8     q10, q3, q4           @((p0 + q0 + 1) >> 1)\n    vtrn.32       d3, d11               @row10&row14\n    vmov.i8       d19, #2\n    @now Q1->p2     & Q5->q1\n    vtrn.32       d4, d12               @row3 & 7\n    vabd.u8       q11, q3, q4           @ABS(p0 - q0)\n    vtrn.32       d5, d13               @row11 & row15\n    vaddl.u8      q12, d20, d2          @(p2 + ((p0 + q0 + 1) >> 1) L\n    @now            Q2->p1,Q6->q2\n    vaddl.u8      q13, d21, d3          @(p2 + ((p0 + q0 + 1) >> 1) H\n    vmlsl.u8      q12, d4, d19          @(p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) L\n    vmlsl.u8      q13, d5, d19          @(p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) H\n    vdup.8        q14, r2               @alpha\n    vcle.u8       q11, q14, q11         @ABS(p0 - q0) >= Alpha(Alpha <=ABS(p0 - q0))\n    vdup.i8       q14, r3               @beta\n    vabd.u8       q15, q5, q4           @ABS(q1 - q0)\n    vqshrn.s16    d24, q12, #1          @((p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1) L\n    vqshrn.s16    d25 , q13, #1         @((p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1) H\n    vcge.u8       q15, q15, q14         @ABS(q1 - q0) >= Beta\n    vabd.u8       q13, q2, q3           @ABS(p1 - p0)\n    vmin.s8       q12, q12, q8          @min(deltap1 ,C0)\n    vorr          q11, q11, q15         @ABS(q1 - q0) >= Beta ||ABS(p0 - q0) >= Alpha\n    vneg.s8       q15, q8               @-C0\n    vcge.u8       q13, q13, q14         @ABS(p1 - p0) >= Beta\n    vmax.s8       q12, q12, q15         @max(deltap1,-C0)\n    vorr          q11, q11, q13         @ABS(p0 - q0) >= Alpha  || ABS(q1 - q0) >= Beta ||  ABS(p1 - p0) >= Beta)\n    vmovl.u16     q13, d18              @ui_bs\n    vaddl.u8      q9, d20, d12          @q2 + ((p0 + q0 + 1) >> 1) L\n    vceq.u32      q13, q13, #0          @ui_bs == 0\n    vsubw.u8      q9, q9, d10           @(q2 + ((p0 + q0 + 1) >> 1) - q1) L\n    vaddl.u8      q10, d21, d13         @q2 + ((p0 + q0 + 1) >> 1) H\n    vsubw.u8      q9, q9, d10           @(q2 + ((p0 + q0 + 1) >> 1) - 2*q1)L\n    vsubw.u8      q10, q10, d11         @(q2 + ((p0 + q0 + 1) >> 1) - q1) H\n    vorr          q13, q13, q11         @(ABS(p0 - q0) >= Alpha  || ABS(q1 - q0) >= Beta || ABS(p1 - p0) >= Beta)) &&(ui_bs)\n    vsubw.u8      q10, q10, d11         @(q2 + ((p0 + q0 + 1) >> 1) - 2*q1) H\n    vqshrn.s16    d18, q9, #1           @((q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1) L\n    vabd.u8       q11, q1, q3           @Ap = ABS(p2 - p0)\n    vqshrn.s16    d19, q10, #1          @((q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1) H\n    vabd.u8       q10, q6, q4           @Aq= ABS(q2 - q0)\n    vclt.u8       q11, q11, q14         @Ap < Beta\n    vmin.s8       q9, q9, q8            @min(delatq1,C0)\n    vclt.u8       q10, q10, q14         @Aq <Beta\n    vsubl.u8      q14, d8, d6           @(q0 - p0) L\n    vmax.s8       q9, q9, q15           @max(deltaq1,-C0)\n    vsubl.u8      q15, d9, d7           @(q0 - p0) H\n    vshl.s16      q14, q14, #2          @(q0 - p0)<<2 L\n    vsub.u8       q8, q8, q11           @C0 + (Ap < Beta)\n    vshl.s16      q15, q15, #2          @(q0 - p0) << 2) H\n    vaddw.u8      q14, q14, d4          @((q0 - p0) << 2) + (p1  L\n    vaddw.u8      q15, q15, d5          @((q0 - p0) << 2) + (p1 H\n    vsubw.u8      q14, q14, d10         @((q0 - p0) << 2) + (p1 - q1) L\n    vsubw.u8      q15, q15, d11         @((q0 - p0) << 2) + (p1 - q1) H\n    vbic          q11, q11, q13         @final condition for p1\n    vrshrn.s16    d28, q14, #3          @delta = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3); L\n    vrshrn.s16    d29, q15, #3          @delta = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3) H\n    vsub.u8       q8, q8, q10           @C0 + (Ap < Beta) + (Aq < Beta)\n    vbic          q10, q10, q13         @final condition for q1\n    vabs.s8       q15, q14              @abs(delta)\n    vand          q12, q12, q11         @delatp1\n    vand          q9, q9, q10           @delta q1\n    vmin.u8       q15, q15, q8          @min((abs(delta),C)\n    vadd.i8       q2, q2, q12           @p1+deltap1\n    vadd.i8       q5, q5, q9            @q1+deltaq1\n    vbic          q15, q15, q13         @abs(delta) of pixels to be changed only\n    vcge.s8       q14, q14, #0          @sign(delta)\n    vqsub.u8      q11, q3, q15          @clip(p0-delta)\n    vtrn.8        d0, d2                @row1 &2\n    vqadd.u8      q3, q3, q15           @clip(p0+delta)\n    vtrn.8        d1, d3                @row9 &10\n    vqadd.u8      q12, q4, q15          @clip(q0+delta)\n    vtrn.8        d12, d14              @row7 & 8\n    vqsub.u8      q4, q4, q15           @clip(q0-delta)\n    vtrn.8        d13, d15              @row15 & 16\n    vbif          q3, q11, q14          @p0\n    vbif          q4, q12, q14          @q0\n    vtrn.8        d4, d6                @row3&row4\n    vtrn.8        d8, d10               @row5&6\n    vtrn.8        d5, d7                @row11 & 12\n    vtrn.8        d9, d11               @row13 &14\n    vtrn.16       d2, d6                @row2 & row4\n    vtrn.16       d10, d14              @row6 & row8\n    vtrn.16       d3, d7                @row10 & 12\n    vtrn.16       d11, d15              @row14 & row16\n    vtrn.32       d6, d14               @row4 & 8\n    vtrn.32       d7, d15               @row 12 & 16\n    @now Q3 ->p0 and Q7->q3\n    vtrn.16       d0, d4                @row1 & 3\n    vtrn.16       d8, d12               @row 5 & 7\n    vtrn.16       d1, d5                @row9 & row11\n    vtrn.16       d9, d13               @row13 & row15\n    sub           r0, r0, r1, lsl#4     @restore pointer\n    vtrn.32       d0, d8                @row1 & row5\n    vtrn.32       d1, d9                @row9 & 13\n    vtrn.32       d2, d10               @row2 &6\n    vtrn.32       d3, d11               @row10&row14\n    vtrn.32       d4, d12               @row3 & 7\n    vtrn.32       d5, d13               @row11 & row15\n    vst1.8        {d0}, [r0], r1        @row1\n    vst1.8        d2, [r0], r1          @row2\n    vst1.8        d4, [r0], r1          @row3\n    vst1.8        d6, [r0], r1          @row4\n    vst1.8        d8, [r0], r1          @row5\n    vst1.8        d10, [r0], r1         @row6\n    vst1.8        d12, [r0], r1         @row7\n    vst1.8        d14, [r0], r1         @row8\n    vst1.8        d1, [r0], r1          @row9\n    vst1.8        d3, [r0], r1          @row10\n    vst1.8        d5, [r0], r1          @row11\n    vst1.8        d7, [r0], r1          @row12\n    vst1.8        d9, [r0], r1          @row13\n    vst1.8        d11, [r0], r1         @row14\n    vst1.8        d13, [r0], r1         @row15\n    vst1.8        d15, [r0], r1         @row16\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r12, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a luma block vertical edge when the\n@*     boundary strength is set to 4\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_luma_vert_bs4_a9\n\nih264_deblk_luma_vert_bs4_a9:\n\n    stmfd         sp!, {r12, lr}\n    vpush         {d8 - d15}\n    sub           r0, r0, #4            @pointer uc_edgePixel-4\n    @loading p3:p2:p1:p0:q0:q1:q2:q3 for every row\n    vld1.8        d0, [r0], r1          @row1\n    vld1.8        d2, [r0], r1          @row2\n    vld1.8        d4, [r0], r1          @row3\n    vld1.8        d6, [r0], r1          @row4\n    vld1.8        d8, [r0], r1          @row5\n    vld1.8        d10, [r0], r1         @row6\n    vld1.8        d12, [r0], r1         @row7\n    vld1.8        d14, [r0], r1         @row8\n    vld1.8        d1, [r0], r1          @row9\n    vld1.8        d3, [r0], r1          @row10\n    vld1.8        d5, [r0], r1          @row11\n    vld1.8        d7, [r0], r1          @row12\n    vld1.8        d9, [r0], r1          @row13\n    vld1.8        d11, [r0], r1         @row14\n    vld1.8        d13, [r0], r1         @row15\n    vld1.8        d15, [r0], r1         @row16\n    @taking two 8x8 transposes\n    @2X2 transposes\n    vtrn.8        d0, d2                @row1 &2\n    vtrn.8        d4, d6                @row3&row4\n    vtrn.8        d8, d10               @row5&6\n    vtrn.8        d12, d14              @row7 & 8\n    vtrn.8        d1, d3                @row9 &10\n    vtrn.8        d5, d7                @row11 & 12\n    vtrn.8        d9, d11               @row13 &14\n    vtrn.8        d13, d15              @row15 & 16\n    @4x4 transposes\n    vtrn.16       d2, d6                @row2 & row4\n    vtrn.16       d10, d14              @row6 & row8\n    vtrn.16       d3, d7                @row10 & 12\n    vtrn.16       d11, d15              @row14 & row16\n    vtrn.32       d6, d14               @row4 & 8\n    vtrn.32       d7, d15               @row 12 & 16\n    @now Q3 ->p0 and Q7->q3\n    vtrn.16       d0, d4                @row1 & 3\n    vtrn.16       d8, d12               @row 5 & 7\n    vtrn.16       d1, d5                @row9 & row11\n    vtrn.16       d9, d13               @row13 & row15\n    vtrn.32       d0, d8                @row1 & row5\n    vtrn.32       d1, d9                @row9 & 13\n    @now Q0->p3 & Q4->q0\n    @starting processing as p0 and q0 are now ready\n    @now Q1->p2 & Q5->q1\n    vpush         {q7}                  @saving in stack\n    vtrn.32       d4, d12               @row3 & 7\n    vmov.i16      q14, #2\n    vtrn.32       d5, d13               @row11 & row15\n    vaddl.u8      q8, d6, d8            @p0+q0 L\n    vtrn.32       d2, d10               @row2 &6\n    vaddl.u8      q9, d7, d9            @p0+q0 H\n    vtrn.32       d3, d11               @row10&row14\n    vaddw.u8      q10, q8, d4           @p0+q0+p1 L\n    vaddw.u8      q11, q9, d5           @p0+q0+p1 H\n    vaddl.u8      q12, d2, d10          @p2+q1 L\n    vaddl.u8      q13, d3, d11          @p2+q1 H\n    vmla.u16      q12, q10, q14         @p2 + X2(p1) + X2(p0) + X2(q0) + q1 L\n    vmla.u16      q13, q11, q14         @p2 + X2(p1) + X2(p0) + X2(q0) + q1 H\n    vmov.i8       q14, #2\n    vaddw.u8      q8, q10, d2           @p0+q0+p1+p2 L\n    vaddw.u8      q9, q11, d3           @p0+q0+p1+p2 H\n    vdup.i8       q15, r2               @duplicate alpha\n    vrshrn.u16    d20, q8, #2           @(p2 + p1 + p0 + q0 + 2) >> 2)L p1'\n    vrshrn.u16    d21, q9, #2           @(p2 + p1 + p0 + q0 + 2) >> 2)H p1'\n    vabd.u8       q11, q3, q4           @ABD(p0-q0)\n    vsra.u8       q14, q15, #2          @alpha >>2 +2\n    vabd.u8       q15, q1, q3           @Ap = ABD(p2-p0)\n    vrshrn.u16    d24, q12, #3          @((p2 + X2(p1) + X2(p0) + X2(q0) + q1 + 4) >> 3) L p0'\n    vrshrn.u16    d25, q13, #3          @((p2 + X2(p1) + X2(p0) + X2(q0) + q1 + 4) >> 3) H p0'\n    vdup.i8       q13, r3               @beta\n    vcgt.u8       q14, q14, q11         @ABS(p0 - q0) <((Alpha >>2) + 2)\n    vaddl.u8      q11, d6, d10          @p0+q1 L\n    vcgt.u8       q7, q13, q15          @beta>Ap\n    vaddl.u8      q15, d7, d11          @p0+q1 H\n    vaddw.u8      q11, q11, d4          @p0+q1+p1 L\n    vaddw.u8      q15, q15, d5          @p0+q1+p1 H\n    vaddw.u8      q11, q11, d4          @p0+q1+2*p1 L\n    vaddw.u8      q15, q15, d5          @p0+q1+2*p1 H\n    vand          q7, q7, q14           @(Ap < Beta && ABS(p0 - q0) <((Alpha >>2) + 2)\n    vrshrn.u16    d22, q11, #2          @((X2(p1) + p0 + q1 + 2) >> 2) L p0\"\n    vrshrn.u16    d23, q15, #2          @((X2(p1) + p0 + q1 + 2) >> 2) H p0\"\n    vaddl.u8      q15, d2, d0           @p2+p3 L\n    vbif          q12, q11, q7          @p0' or p0 \"\n    vaddl.u8      q11, d3, d1           @p2+p3 H\n    vadd.u16      q15, q15, q15         @2*(p2+p3) L\n    vadd.u16      q11, q11, q11         @2*(p2+p3)H\n    vadd.u16      q8, q8, q15           @(X2(p3) + X3(p2) + p1 + p0 + q0) L\n    vadd.u16      q9, q9, q11           @(X2(p3) + X3(p2) + p1 + p0 + q0) H\n    vabd.u8       q15, q6, q4           @Aq = abs(q2-q0)\n    vabd.u8       q11, q5, q4           @ABS(Q1-Q0)\n    vrshrn.u16    d16, q8, #3           @((X2(p3) + X3(p2) + p1 + p0 + q0 + 4) >> 3); L p2'\n    vrshrn.u16    d17, q9, #3           @((X2(p3) + X3(p2) + p1 + p0 + q0 + 4) >> 3); H p2'\n    vabd.u8       q9, q2, q3            @ABS(p1-p0)\n    vcgt.u8       q15, q13, q15         @Aq < Beta\n    vcge.u8       q11, q11, q13         @ABS(q1 - q0) >= Beta\n    vcge.u8       q9, q9, q13           @ABS(p1 - p0) >= beta\n    vdup.i8       q13, r2               @duplicate alpha\n    vand          q15, q15, q14         @(Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2))\n    vabd.u8       q14, q3, q4           @abs(p0-q0)\n    vorr          q11, q11, q9          @ABS(p1 - p0) >= Beta || ABS(q1 - q0) >= Beta\n    vaddl.u8      q9, d6, d8            @p0+q0 L\n    vcge.u8       q14, q14, q13         @ABS(p0 - q0) >= Alpha\n    vaddl.u8      q13, d7, d9           @p0+q0 H\n    vaddw.u8      q9, q9, d10           @p0+q0+q1 L\n    vorr          q11, q11, q14         @ABS(p1 - p0) >= Beta || ABS(q1 - q0) >= Beta||ABS(p0 - q0) >= Alpha\n    vaddw.u8      q13, q13, d11         @p0+q0+q1 H\n    vbic          q7, q7, q11           @final condn for p's\n    vmov.i8       q14, #2\n    vbif          q3, q12, q11          @final p0\n    vbit          q1, q8, q7            @final p2\n    vbif          q10, q2, q7           @final p1\n    vaddl.u8      q12, d8, d4           @q0+p1 L\n    vmlal.u8      q12, d10, d28         @X2(q1) + q0 + p1 L\n    vaddl.u8      q8, d9, d5            @q0+p1 H\n    vmlal.u8      q8, d11, d28          @X2(q1) + q0 + p1 H\n    vmov.i16      q14, #2\n    vaddl.u8      q7, d4, d12           @p1+q2 L\n    vmla.u16      q7, q9, q14           @p1 + X2(p0) + X2(q0) + X2(q1) + q2L\n    vaddl.u8      q2, d5, d13           @p1+q2H\n    vmla.u16      q2, q13, q14          @p1 + X2(p0) + X2(q0) + X2(q1) + q2H\n    vrshrn.u16    d24, q12, #2          @(X2(q1) + q0 + p1 + 2) >> 2; L q0'\n    vrshrn.u16    d25, q8, #2           @(X2(q1) + q0 + p1 + 2) >> 2; H q0'\n    vaddw.u8      q9, q9, d12           @p0 + q0 + q1 + q2 L\n    vaddw.u8      q13, q13, d13         @p0 + q0 + q1 + q2 H\n    vrshrn.u16    d16, q7, #3           @(p1 + X2(p0) + X2(q0) + X2(q1) + q2 + 4) >> 3 L qo\"\n    vpop          {q7}\n    vrshrn.u16    d17, q2, #3           @(p1 + X2(p0) + X2(q0) + X2(q1) + q2 + 4) >> 3 H qo\"\n    vrshrn.u16    d4, q9, #2            @p0 + q0 + q1 + q2 + 2)>>2 L q1'\n    vrshrn.u16    d5, q13, #2           @p0 + q0 + q1 + q2 + 2)>>2 H q1'\n    vbit          q12, q8, q15          @q0' or q0\"\n    vbic          q15, q15, q11         @final condn for q's\n    vtrn.8        d0, d2                @row1 &2\n    vbit          q5, q2, q15           @final q1\n    vtrn.8        d1, d3                @row9 &10\n    vaddl.u8      q8, d12, d14          @q2+q3 L\n    vtrn.8        d20, d6               @row3&row4\n    vaddl.u8      q2, d13, d15          @q2+q3 H\n    vtrn.8        d21, d7               @row11 & 12\n    vmla.u16      q9, q8, q14           @X2(q3) + X3(q2) + q1 + q0 + p0 L\n    vtrn.16       d2, d6                @row2 & row4\n    vmla.u16      q13, q2, q14          @X2(q3) + X3(q2) + q1 + q0 + p0 H\n    vtrn.16       d3, d7                @row10 & 12\n    vbif          q4, q12, q11          @final q0\n    vtrn.16       d0, d20               @row1 & 3\n    vrshrn.u16    d18, q9, #3           @(X2(q3) + X3(q2) + q1 + q0 + p0 + 4) >> 3; L\n    vtrn.16       d1, d21               @row9 & row11\n    vrshrn.u16    d19, q13, #3          @(X2(q3) + X3(q2) + q1 + q0 + p0 + 4) >> 3; H\n    vtrn.8        d8, d10               @row5&6\n    vbit          q6, q9, q15           @final q2\n    vtrn.8        d9, d11               @row13 &14\n    vtrn.8        d12, d14              @row7 & 8\n    vtrn.8        d13, d15              @row15 & 16\n    vtrn.16       d10, d14              @row6 & row8\n    vtrn.16       d11, d15              @row14 & row16\n    @now Q3 ->p0 and Q7->q3\n    vtrn.16       d8, d12               @row 5 & 7\n    vtrn.16       d9, d13               @row13 & row15\n    sub           r0, r0, r1, lsl#4     @restore pointer\n    vtrn.32       d6, d14               @row4 & 8\n    vtrn.32       d7, d15               @row 12 & 16\n    vtrn.32       d0, d8                @row1 & row5\n    vtrn.32       d1, d9                @row9 & 13\n    vtrn.32       d2, d10               @row2 &6\n    vtrn.32       d3, d11               @row10&row14\n    vtrn.32       d20, d12              @row3 & 7\n    vtrn.32       d21, d13              @row11 & row15\n    vst1.8        d0, [r0], r1          @row1\n    vst1.8        d2, [r0], r1          @row2\n    vst1.8        d20, [r0], r1         @row3\n    vst1.8        d6, [r0], r1          @row4\n    vst1.8        d8, [r0], r1          @row5\n    vst1.8        d10, [r0], r1         @row6\n    vst1.8        d12, [r0], r1         @row7\n    vst1.8        d14, [r0], r1         @row8\n    vst1.8        d1, [r0], r1          @row9\n    vst1.8        d3, [r0], r1          @row10\n    vst1.8        d21, [r0], r1         @row11\n    vst1.8        d7, [r0], r1          @row12\n    vst1.8        d9, [r0], r1          @row13\n    vst1.8        d11, [r0], r1         @row14\n    vst1.8        d13, [r0], r1         @row15\n    vst1.8        d15, [r0], r1         @row16\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r12, pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a luma block vertical edge when the\n@*     boundary strength is set to 4 on calling twice\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_luma_vert_bs4_mbaff_a9\n\nih264_deblk_luma_vert_bs4_mbaff_a9:\n\n    stmfd         sp!, {lr}\n\n    sub           r0, r0, #4            @pointer uc_edgePixel-4\n    vpush         {d8 - d15}\n    @loading [p3:p2],[p1:p0]:[q0:q1]:[q2:q3] for every row\n    vld4.16       {d0[0], d2[0], d4[0], d6[0]}, [r0], r1\n    vld4.16       {d0[1], d2[1], d4[1], d6[1]}, [r0], r1\n    vld4.16       {d0[2], d2[2], d4[2], d6[2]}, [r0], r1\n    vld4.16       {d0[3], d2[3], d4[3], d6[3]}, [r0], r1\n    vld4.16       {d1[0], d3[0], d5[0], d7[0]}, [r0], r1\n    vld4.16       {d1[1], d3[1], d5[1], d7[1]}, [r0], r1\n    vld4.16       {d1[2], d3[2], d5[2], d7[2]}, [r0], r1\n    vld4.16       {d1[3], d3[3], d5[3], d7[3]}, [r0], r1\n\n    vuzp.8        d0, d1                @D0->p3, D1->p2\n    vuzp.8        d2, d3                @D2->p1, D3->p0\n    vuzp.8        d4, d5                @D4->q0, D5->q1\n    vuzp.8        d6, d7                @D6->q2, D7->q3\n\n    vmov.i16      q14, #2\n    vaddl.u8      q4, d3, d4            @p0+q0\n    vaddw.u8      q5, q4, d2            @p0+q0+p1\n    vaddl.u8      q6, d1, d5            @p2+q1\n    vmla.u16      q6, q5, q14           @p2 + X2(p1) + X2(p0) + X2(q0) + q1\n\n    vmov.i8       d14, #2\n    vaddw.u8      q4, q5, d1            @p0+q0+p1+p2\n    vdup.i8       d15, r2               @duplicate alpha\n    vrshrn.u16    d10, q4, #2           @(p2 + p1 + p0 + q0 + 2) >> 2) p1'\n    vabd.u8       d11, d3, d4           @ABD(p0-q0)\n    vsra.u8       d14, d15, #2          @alpha >>2 +2\n    vabd.u8       d15, d1, d3           @Ap = ABD(p2-p0)\n    vrshrn.u16    d12, q6, #3           @((p2 + X2(p1) + X2(p0) + X2(q0) + q1 + 4) >> 3) p0'\n    vdup.i8       d13, r3               @beta\n    vcgt.u8       d14, d14, d11         @ABS(p0 - q0) <((Alpha >>2) + 2)\n    vaddl.u8      q8, d3, d5            @p0+q1\n    vcgt.u8       d26, d13, d15         @beta>Ap\n    vaddw.u8      q8, q8, d2            @p0+q1+p1\n    vaddw.u8      q8, q8, d2            @p0+q1+2*p1\n    vand          d26, d26, d14         @(Ap < Beta && ABS(p0 - q0) <((Alpha >>2) + 2)\n    vrshrn.u16    d11, q8, #2           @((X2(p1) + p0 + q1 + 2) >> 2) p0\"\n    vbif          d12, d11, d26         @p0' or p0 \"\n    vaddl.u8      q9, d1, d0            @p2+p3\n    vadd.u16      q9, q9, q9            @2*(p2+p3)\n    vadd.u16      q4, q4, q9            @(X2(p3) + X3(p2) + p1 + p0 + q0)\n    vabd.u8       d15, d6, d4           @Aq = abs(q2-q0)\n    vabd.u8       d11, d5, d4           @ABS(q1-q0)\n    vrshrn.u16    d8, q4, #3            @((X2(p3) + X3(p2) + p1 + p0 + q0 + 4) >> 3); p2'\n    vabd.u8       d9, d2, d3            @ABS(p1-p0)\n    vcgt.u8       d15, d13, d15         @Aq < Beta\n    vcge.u8       d11, d11, d13         @ABS(q1 - q0) >= Beta\n    vcge.u8       d9, d9, d13           @ABS(p1 - p0) >= beta\n    vdup.i8       d13, r2               @duplicate alpha\n    vand          d15, d15, d14         @(Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2))\n    vabd.u8       d14, d3, d4           @abs(p0-q0)\n    vorr          d11, d11, d9          @ABS(p1 - p0) >= Beta || ABS(q1 - q0) >= Beta\n    vcge.u8       d14, d14, d13         @ABS(p0 - q0) >= Alpha\n    vaddl.u8      q10, d3, d4           @p0+q0\n    vorr          d11, d11, d14         @ABS(p1 - p0) >= Beta || ABS(q1 - q0) >= Beta||ABS(p0 - q0) >= Alpha\n    vaddw.u8      q10, q10, d5          @p0+q0+q1\n    vbic          d26, d26, d11         @final condn for p's\n    vmov.i8       d14, #2\n    vbif          d3, d12, d11          @final p0\n    vbit          d1, d8, d26           @final p2\n    vbif          d10, d2, d26          @final p1\n    vaddl.u8      q6, d4, d2            @q0+p1\n    vmlal.u8      q6, d5, d14           @X2(q1) + q0 + p1\n\n    vaddl.u8      q11, d2, d6           @p1+q2\n    vmla.u16      q11, q10, q14         @p1 + X2(p0) + X2(q0) + X2(q1) + q2\n    vrshrn.u16    d12, q6, #2           @(X2(q1) + q0 + p1 + 2) >> 2; q0'\n    vaddw.u8      q10, q10, d6          @p0 + q0 + q1 + q2\n    vrshrn.u16    d8, q11, #3           @(p1 + X2(p0) + X2(q0) + X2(q1) + q2 + 4) >> 3 qo\"\n\n    vrshrn.u16    d2, q10, #2           @p0 + q0 + q1 + q2 + 2)>>2 q1'\n    vbit          d12, d8, d15          @q0' or q0\"\n    vbic          d15, d15, d11         @final condn for q's\n    vbit          d5, d2, d15           @final q1\n    vaddl.u8      q12, d6, d7           @q2+q3\n    vmla.u16      q10, q12, q14         @X2(q3) + X3(q2) + q1 + q0 + p0\n    vbif          d4, d12, d11          @final q0\n    vrshrn.u16    d9, q10, #3           @(X2(q3) + X3(q2) + q1 + q0 + p0 + 4) >> 3;\n    vbit          d6, d9, d15           @final q2\n    vand          d2, d10, d10          @D0->p3, D1->p2, D2->p1, D3->p0, D4->q0, D5->q1, D6->q2, D7->q3\n\n    vzip.8        d0, d1                @D0,D1 -> [p3:p2]\n    vzip.8        d2, d3                @D2,D3 -> [p1:p0]\n    vzip.8        d4, d5                @D4,D5 -> [q0:q1]\n    vzip.8        d6, d7                @D6,D7 -> [q2:q3]\n\n    sub           r0, r0, r1, lsl#3     @restore pointer\n\n    @storing [p3:p2],[p1:p0]:[q0:q1]:[q2:q3] in every row\n    vst4.16       {d0[0], d2[0], d4[0], d6[0]}, [r0], r1\n    vst4.16       {d0[1], d2[1], d4[1], d6[1]}, [r0], r1\n    vst4.16       {d0[2], d2[2], d4[2], d6[2]}, [r0], r1\n    vst4.16       {d0[3], d2[3], d4[3], d6[3]}, [r0], r1\n    vst4.16       {d1[0], d3[0], d5[0], d7[0]}, [r0], r1\n    vst4.16       {d1[1], d3[1], d5[1], d7[1]}, [r0], r1\n    vst4.16       {d1[2], d3[2], d5[2], d7[2]}, [r0], r1\n    vst4.16       {d1[3], d3[3], d5[3], d7[3]}, [r0], r1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {pc}\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Performs filtering of a luma block vertical edge for cases where the\n@*     boundary strength is less than 4 on calling twice\n@*\n@* @par Description:\n@*    This operation is described in  Sec. 8.7.2.4 under the title\n@*    \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n@*\n@* @param[in] r0 - pu1_src\n@*  Pointer to the src sample q0\n@*\n@* @param[in] r1 - src_strd\n@*  Source stride\n@*\n@* @param[in] r2 - alpha\n@*  Alpha Value for the boundary\n@*\n@* @param[in] r3 - beta\n@*  Beta Value for the boundary\n@*\n@* @param[in] sp(0) - u4_bs\n@*  Packed Boundary strength array\n@*\n@* @param[in] sp(4) - pu1_cliptab\n@*  tc0_table\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n    .global ih264_deblk_luma_vert_bslt4_mbaff_a9\n\nih264_deblk_luma_vert_bslt4_mbaff_a9:\n\n    stmfd         sp!, {r12, lr}\n\n    sub           r0, r0, #4            @pointer uc_edgePixel-4\n    ldr           r12, [sp, #8]         @r12 = ui_Bs\n    ldr           r14, [sp, #12]        @r14 = pu1_ClipTab\n    vpush         {d8 - d15}\n    @loading [p3:p2],[p1:p0]:[q0:q1]:[q2:q3] for every row\n    vld4.16       {d0[0], d2[0], d4[0], d6[0]}, [r0], r1\n    vld4.16       {d0[1], d2[1], d4[1], d6[1]}, [r0], r1\n    vld4.16       {d0[2], d2[2], d4[2], d6[2]}, [r0], r1\n    vld4.16       {d0[3], d2[3], d4[3], d6[3]}, [r0], r1\n    vld4.16       {d1[0], d3[0], d5[0], d7[0]}, [r0], r1\n    vld4.16       {d1[1], d3[1], d5[1], d7[1]}, [r0], r1\n    vld4.16       {d1[2], d3[2], d5[2], d7[2]}, [r0], r1\n    vld4.16       {d1[3], d3[3], d5[3], d7[3]}, [r0], r1\n\n    vuzp.8        d0, d1                @D0->p3, D1->p2\n    vuzp.8        d2, d3                @D2->p1, D3->p0\n    vuzp.8        d4, d5                @D4->q0, D5->q1\n    vuzp.8        d6, d7                @D6->q2, D7->q3\n\n    rev           r12, r12              @reversing ui_bs\n    vmov.32       d8[0], r12            @D8[0] = ui_Bs\n    vld1.32       d9[0], [r14]          @D9[0] contains cliptab\n    vmovl.u8      q15, d8               @D30 = ui_Bs in each 16 bt scalar\n    vtbl.8        d8, {d9}, d30         @puc_ClipTab[ui_Bs]\n    vsli.16       d8, d8, #8            @D8 = C0\n\n    vrhadd.u8     d10, d3, d4           @((p0 + q0 + 1) >> 1)\n    vmov.i8       d31, #2\n    vabd.u8       d11, d3, d4           @ABS(p0 - q0)\n    vaddl.u8      q6, d10, d1           @(p2 + ((p0 + q0 + 1) >> 1)\n    vmlsl.u8      q6, d2, d31           @(p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1))\n    vdup.8        d14, r2               @alpha\n    vcle.u8       d11, d14, d11         @ABS(p0 - q0) >= Alpha(Alpha <=ABS(p0 - q0))\n    vdup.i8       d14, r3               @beta\n    vabd.u8       d15, d5, d4           @ABS(q1 - q0)\n    vqshrn.s16    d12, q6, #1           @((p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1)\n    vcge.u8       d15, d15, d14         @ABS(q1 - q0) >= Beta\n    vabd.u8       d13, d2, d3           @ABS(p1 - p0)\n    vmin.s8       d12, d12, d8          @min(deltap1 ,C0)\n    vorr          d11, d11, d15         @ABS(q1 - q0) >= Beta ||ABS(p0 - q0) >= Alpha\n    vneg.s8       d15, d8               @-C0\n    vcge.u8       d13, d13, d14         @ABS(p1 - p0) >= Beta\n    vmax.s8       d12, d12, d15         @max(deltap1,-C0)\n    vorr          d11, d11, d13         @ABS(p0 - q0) >= Alpha  || ABS(q1 - q0) >= Beta ||  ABS(p1 - p0) >= Beta)\n    vceq.u16      d13, d30, #0          @ui_bs == 0\n    vaddl.u8      q14, d10, d6          @q2 + ((p0 + q0 + 1) >> 1)\n    vsubw.u8      q14, q14, d5          @q2 + ((p0 + q0 + 1) >> 1) - q1\n    vsubw.u8      q14, q14, d5          @q2 + ((p0 + q0 + 1) >> 1) - 2*q1\n    vorr          d13, d13, d11         @(ABS(p0 - q0) >= Alpha  || ABS(q1 - q0) >= Beta || ABS(p1 - p0) >= Beta))\n                                        @|| (ui_bs == 0)\n    vqshrn.s16    d9, q14, #1           @(q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1\n    vabd.u8       d11, d1, d3           @Ap = ABS(p2 - p0)\n    vabd.u8       d10, d6, d4           @Aq= ABS(q2 - q0)\n    vclt.u8       d11, d11, d14         @Ap < Beta\n    vmin.s8       d9, d9, d8            @min(deltaq1,C0)\n    vclt.u8       d10, d10, d14         @Aq < Beta\n    vmax.s8       d9, d9, d15           @max(deltaq1,-C0)\n    vsubl.u8      q7, d4, d3            @q0 - p0\n    vshl.s16      q7, q7, #2            @(q0 - p0) << 2\n    vsub.u8       d8, d8, d11           @C0 + (Ap < Beta)\n    vaddw.u8      q7, q7, d2            @((q0 - p0) << 2) + p1\n    vsubw.u8      q7, q7, d5            @((q0 - p0) << 2) + (p1 - q1)\n    vbic          d11, d11, d13         @final condition for p1\n    vrshr.s16     q15, q7, #3           @delta = (((q0 - p0) << 2) + (p1 - q1) + 4) >> 3\n    vsub.u8       d8, d8, d10           @C0 + (Ap < Beta) + (Aq < Beta)\n    vbic          d10, d10, d13         @final condition for q1\n    vabs.s16      q14, q15\n    vmovn.i16     d15, q14              @abs(delta)\n    vand          d12, d12, d11         @delatp1\n    vand          d9, d9, d10           @deltaq1\n    vmin.u8       d15, d15, d8          @min((abs(delta),C)\n    vadd.i8       d2, d2, d12           @p1+deltap1\n    vadd.i8       d5, d5, d9            @q1+deltaq1\n    vbic          d15, d15, d13         @abs(delta) of pixels to be changed only\n    vcge.s16      q14, q15, #0\n    vmovn.i16     d14, q14              @sign(delta)\n    vqsub.u8      d11, d3, d15          @clip(p0-delta)\n    vqadd.u8      d3, d3, d15           @clip(p0+delta)\n    vqadd.u8      d12, d4, d15          @clip(q0+delta)\n    vqsub.u8      d4, d4, d15           @clip(q0-delta)\n    vbif          d3, d11, d14          @p0\n    vbif          d4, d12, d14          @q0\n\n    sub           r0, r0, r1, lsl#3     @restore pointer\n                                        @D0->p3, D1->p2, D2->p1, D3->p0, D4->q0, D5->q1, D6->q2, D7->q3\n    vzip.8        d0, d1                @D0,D1 -> [p3:p2]\n    vzip.8        d2, d3                @D2,D3 -> [p1:p0]\n    vzip.8        d4, d5                @D4,D5 -> [q0:q1]\n    vzip.8        d6, d7                @D6,D7 -> [q2:q3]\n\n    @storing [p3:p2],[p1:p0]:[q0:q1]:[q2:q3] in every row\n    vst4.16       {d0[0], d2[0], d4[0], d6[0]}, [r0], r1\n    vst4.16       {d0[1], d2[1], d4[1], d6[1]}, [r0], r1\n    vst4.16       {d0[2], d2[2], d4[2], d6[2]}, [r0], r1\n    vst4.16       {d0[3], d2[3], d4[3], d6[3]}, [r0], r1\n    vst4.16       {d1[0], d3[0], d5[0], d7[0]}, [r0], r1\n    vst4.16       {d1[1], d3[1], d5[1], d7[1]}, [r0], r1\n    vst4.16       {d1[2], d3[2], d5[2], d7[2]}, [r0], r1\n    vst4.16       {d1[3], d3[3], d5[3], d7[3]}, [r0], r1\n    vpop          {d8 - d15}\n    ldmfd         sp!, {r12, pc}\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_default_weighted_pred_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_default_weighted_pred_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for default weighted prediction.\n@*\n@* @author\n@*  Kaushik Senthoor R\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_default_weighted_pred_luma_a9q()\n@*  - ih264_default_weighted_pred_chroma_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@*******************************************************************************\n@* @function\n@*  ih264_default_weighted_pred_luma_a9q()\n@*\n@* @brief\n@*  This routine performs the default weighted prediction as described in sec\n@* 8.4.2.3.1 titled \"Default weighted sample prediction process\" for luma.\n@*\n@* @par Description:\n@*  This function gets two ht x wd blocks, calculates their rounded-average and\n@* stores it in the destination block.\n@*\n@* @param[in] pu1_src1:\n@*  UWORD8 Pointer to the buffer containing the first input block.\n@*\n@* @param[in] pu1_src2:\n@*  UWORD8 Pointer to the buffer containing the second input block.\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination where the output block is stored.\n@*\n@* @param[in] src_strd1\n@*  Stride of the first input buffer\n@*\n@* @param[in] src_strd2\n@*  Stride of the second input buffer\n@*\n@* @param[in] dst_strd\n@*  Stride of the destination buffer\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  (ht,wd) can be (4,4), (4,8), (8,4), (8,8), (8,16), (16,8) or (16,16).\n@*\n@*******************************************************************************\n@*\n@void ih264_default_weighted_pred_luma_a9q(UWORD8 *pu1_src1,\n@                                          UWORD8 *pu1_src2,\n@                                          UWORD8 *pu1_dst,\n@                                          WORD32 src_strd1,\n@                                          WORD32 src_strd2,\n@                                          WORD32 dst_strd,\n@                                          WORD32 ht,\n@                                          WORD32 wd)\n@\n@**************Variables Vs Registers*****************************************\n@   r0      => pu1_src1\n@   r1      => pu1_src2\n@   r2      => pu1_dst\n@   r3      => src_strd1\n@   [sp]    => src_strd2 (r4)\n@   [sp+4]  => dst_strd  (r5)\n@   [sp+8]  => ht        (r6)\n@   [sp+12] => wd        (r7)\n@\n.text\n.p2align 2\n\n    .global ih264_default_weighted_pred_luma_a9q\n\nih264_default_weighted_pred_luma_a9q:\n\n    stmfd         sp!, {r4-r7, r14}     @stack stores the values of the arguments\n    ldr           r7, [sp, #32]         @Load wd\n    ldr           r4, [sp, #20]         @Load src_strd2\n    ldr           r5, [sp, #24]         @Load dst_strd\n    cmp           r7, #16\n    ldr           r6, [sp, #28]         @Load ht\n    vpush         {d8-d15}\n    beq           loop_16               @branch if wd is 16\n    cmp           r7, #8\n    beq           loop_8                @branch if wd is 8\n\nloop_4:                                 @each iteration processes four rows\n\n    vld1.32       d0[0], [r0], r3       @load row 1 in source 1\n    vld1.32       d0[1], [r0], r3       @load row 2 in source 1\n    vld1.32       d2[0], [r1], r4       @load row 1 in source 2\n    vld1.32       d2[1], [r1], r4       @load row 2 in source 2\n\n    vld1.32       d1[0], [r0], r3       @load row 3 in source 1\n    vld1.32       d1[1], [r0], r3       @load row 4 in source 1\n    vrhadd.u8     d0, d0, d2\n    vld1.32       d3[0], [r1], r4       @load row 3 in source 2\n    vld1.32       d3[1], [r1], r4       @load row 4 in source 2\n\n    subs          r6, r6, #4            @decrement ht by 4\n    vst1.32       d0[0], [r2], r5       @load row 1 in destination\n    vst1.32       d0[1], [r2], r5       @load row 2 in destination\n    vrhadd.u8     d1, d1, d3\n    vst1.32       d1[0], [r2], r5       @load row 3 in destination\n    vst1.32       d1[1], [r2], r5       @load row 4 in destination\n\n    bgt           loop_4                @if greater than 0 repeat the loop again\n\n    b             end_loops\n\nloop_8:                                 @each iteration processes four rows\n\n    vld1.8        d0, [r0], r3          @load row 1 in source 1\n    vld1.8        d4, [r1], r4          @load row 1 in source 2\n    vld1.8        d1, [r0], r3          @load row 2 in source 1\n    vld1.8        d5, [r1], r4          @load row 2 in source 2\n    vld1.8        d2, [r0], r3          @load row 3 in source 1\n    vrhadd.u8     q0, q0, q2\n    vld1.8        d6, [r1], r4          @load row 3 in source 2\n    vld1.8        d3, [r0], r3          @load row 4 in source 1\n    vrhadd.u8     d2, d2, d6\n    vld1.8        d7, [r1], r4          @load row 4 in source 2\n\n    subs          r6, r6, #4            @decrement ht by 4\n    vst1.8        d0, [r2], r5          @load row 1 in destination\n    vrhadd.u8     d3, d3, d7\n    vst1.8        d1, [r2], r5          @load row 2 in destination\n    vst1.8        d2, [r2], r5          @load row 3 in destination\n    vst1.8        d3, [r2], r5          @load row 4 in destination\n\n    bgt           loop_8                @if greater than 0 repeat the loop again\n\n    b             end_loops\n\nloop_16:                                @each iteration processes eight rows\n\n    vld1.8        {q0}, [r0], r3        @load row 1 in source 1\n    vld1.8        {q8}, [r1], r4        @load row 1 in source 2\n    vld1.8        {q1}, [r0], r3        @load row 2 in source 1\n    vld1.8        {q9}, [r1], r4        @load row 2 in source 2\n    vrhadd.u8     q0, q0, q8\n    vld1.8        {q2}, [r0], r3        @load row 3 in source 1\n    vld1.8        {q10}, [r1], r4       @load row 3 in source 2\n    vrhadd.u8     q1, q1, q9\n    vld1.8        {q3}, [r0], r3        @load row 4 in source 1\n    vld1.8        {q11}, [r1], r4       @load row 4 in source 2\n    vrhadd.u8     q2, q2, q10\n    vld1.8        {q4}, [r0], r3        @load row 5 in source 1\n    vld1.8        {q12}, [r1], r4       @load row 5 in source 2\n    vrhadd.u8     q3, q3, q11\n    vld1.8        {q5}, [r0], r3        @load row 6 in source 1\n    vld1.8        {q13}, [r1], r4       @load row 6 in source 2\n    vrhadd.u8     q4, q4, q12\n    vld1.8        {q6}, [r0], r3        @load row 7 in source 1\n    vld1.8        {q14}, [r1], r4       @load row 7 in source 2\n    vrhadd.u8     q5, q5, q13\n    vld1.8        {q7}, [r0], r3        @load row 8 in source 1\n    vld1.8        {q15}, [r1], r4       @load row 8 in source 2\n\n    vrhadd.u8     q6, q6, q14\n    vst1.8        {q0}, [r2], r5        @load row 1 in destination\n    vst1.8        {q1}, [r2], r5        @load row 2 in destination\n    vrhadd.u8     q7, q7, q15\n    vst1.8        {q2}, [r2], r5        @load row 3 in destination\n    vst1.8        {q3}, [r2], r5        @load row 4 in destination\n    subs          r6, r6, #8            @decrement ht by 8\n    vst1.8        {q4}, [r2], r5        @load row 5 in destination\n    vst1.8        {q5}, [r2], r5        @load row 6 in destination\n    vst1.8        {q6}, [r2], r5        @load row 7 in destination\n    vst1.8        {q7}, [r2], r5        @load row 8 in destination\n\n    bgt           loop_16               @if greater than 0 repeat the loop again\n\nend_loops:\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r7, r15}     @Reload the registers from sp\n\n\n@*******************************************************************************\n@* @function\n@*  ih264_default_weighted_pred_chroma_a9q()\n@*\n@* @brief\n@*  This routine performs the default weighted prediction as described in sec\n@* 8.4.2.3.1 titled \"Default weighted sample prediction process\" for chroma.\n@*\n@* @par Description:\n@*  This function gets two ht x wd blocks, calculates their rounded-average and\n@* stores it in the destination block for U and V.\n@*\n@* @param[in] pu1_src1:\n@*  UWORD8 Pointer to the buffer containing the first input block.\n@*\n@* @param[in] pu1_src2:\n@*  UWORD8 Pointer to the buffer containing the second input block.\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination where the output block is stored.\n@*\n@* @param[in] src_strd1\n@*  Stride of the first input buffer\n@*\n@* @param[in] src_strd2\n@*  Stride of the second input buffer\n@*\n@* @param[in] dst_strd\n@*  Stride of the destination buffer\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  (ht,wd) can be (2,2), (2,4), (4,2), (4,4), (4,8), (8,4) or (8,8).\n@*\n@*******************************************************************************\n@*\n@void ih264_default_weighted_pred_chroma_a9q(UWORD8 *pu1_src1,\n@                                            UWORD8 *pu1_src2,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd1,\n@                                            WORD32 src_strd2,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ht,\n@                                            WORD32 wd)\n@\n@**************Variables Vs Registers*****************************************\n@   r0      => pu1_src1\n@   r1      => pu1_src2\n@   r2      => pu1_dst\n@   r3      => src_strd1\n@   [sp]    => src_strd2 (r4)\n@   [sp+4]  => dst_strd  (r5)\n@   [sp+8]  => ht        (r6)\n@   [sp+12] => wd        (r7)\n@\n\n\n    .global ih264_default_weighted_pred_chroma_a9q\n\nih264_default_weighted_pred_chroma_a9q:\n\n    stmfd         sp!, {r4-r7, r14}     @stack stores the values of the arguments\n    ldr           r7, [sp, #32]         @Load wd\n    ldr           r4, [sp, #20]         @Load src_strd2\n    ldr           r5, [sp, #24]         @Load dst_strd\n    cmp           r7, #8\n    ldr           r6, [sp, #28]         @Load ht\n    vpush         {d8-d15}\n    beq           loop_8_uv             @branch if wd is 8\n    cmp           r7, #4\n    beq           loop_4_uv             @branch if wd is 4\n\nloop_2_uv:                              @each iteration processes two rows\n\n    vld1.32       d0[0], [r0], r3       @load row 1 in source 1\n    vld1.32       d0[1], [r0], r3       @load row 2 in source 1\n\n    vld1.32       d1[0], [r1], r4       @load row 1 in source 2\n    vld1.32       d1[1], [r1], r4       @load row 2 in source 2\n\n    vrhadd.u8     d0, d0, d1\n\n    subs          r6, r6, #2            @decrement ht by 2\n    vst1.32       d0[0], [r2], r5       @load row 1 in destination\n    vst1.32       d0[1], [r2], r5       @load row 2 in destination\n\n    bgt           loop_2_uv             @if greater than 0 repeat the loop again\n\n    b             end_loops_uv\n\nloop_4_uv:                              @each iteration processes two rows\n\n    vld1.8        d0, [r0], r3          @load row 1 in source 1\n    vld1.8        d2, [r1], r4          @load row 1 in source 2\n    vld1.8        d1, [r0], r3          @load row 2 in source 1\n    vrhadd.u8     d0, d0, d2\n    vld1.8        d3, [r1], r4          @load row 2 in source 2\n\n    vrhadd.u8     d1, d1, d3\n    vst1.8        d0, [r2], r5          @load row 1 in destination\n    subs          r6, r6, #2            @decrement ht by 2\n    vst1.8        d1, [r2], r5          @load row 2 in destination\n\n    bgt           loop_4_uv             @if greater than 0 repeat the loop again\n\n    b             end_loops_uv\n\nloop_8_uv:                              @each iteration processes four rows\n\n    vld1.8        {q0}, [r0], r3        @load row 1 in source 1\n    vld1.8        {q4}, [r1], r4        @load row 1 in source 2\n    vld1.8        {q1}, [r0], r3        @load row 2 in source 1\n    vrhadd.u8     q0, q0, q4\n    vld1.8        {q5}, [r1], r4        @load row 2 in source 2\n    vld1.8        {q2}, [r0], r3        @load row 3 in source 1\n    vrhadd.u8     q1, q1, q5\n    vld1.8        {q6}, [r1], r4        @load row 3 in source 2\n    vld1.8        {q3}, [r0], r3        @load row 4 in source 1\n    vrhadd.u8     q2, q2, q6\n    vld1.8        {q7}, [r1], r4        @load row 4 in source 2\n\n    vst1.8        {q0}, [r2], r5        @load row 1 in destination\n    vrhadd.u8     q3, q3, q7\n    vst1.8        {q1}, [r2], r5        @load row 2 in destination\n    subs          r6, r6, #4            @decrement ht by 4\n    vst1.8        {q2}, [r2], r5        @load row 3 in destination\n    vst1.8        {q3}, [r2], r5        @load row 4 in destination\n\n    bgt           loop_8_uv             @if greater than 0 repeat the loop again\n\nend_loops_uv:\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r7, r15}     @Reload the registers from sp\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_ihadamard_scaling_a9.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@ *******************************************************************************\n@ * @file\n@ *  ih264_ihadamard_scaling_a9.s\n@ *\n@ * @brief\n@ *  Contains function definitions for inverse hadamard transform on 4x4 DC outputs\n@ *  of 16x16 intra-prediction\n@ *\n@ * @author\n@ *  Mohit\n@ *\n@ * @par List of Functions:\n@ *  - ih264_ihadamard_scaling_4x4_a9()\n@ *  - ih264_ihadamard_scaling_2x2_uv_a9()\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n@ *\n@ * @brief This function performs a 4x4 inverse hadamard transform on the 4x4 DC coefficients\n@ * of a 16x16 intra prediction macroblock, and then performs scaling.\n@ * prediction buffer\n@ *\n@ * @par Description:\n@ *  The DC coefficients pass through a 2-stage inverse hadamard transform.\n@ *  This inverse transformed content is scaled to based on Qp value.\n@ *\n@ * @param[in] pi2_src\n@ *  input 4x4 block of DC coefficients\n@ *\n@ * @param[out] pi2_out\n@ *  output 4x4 block\n@ *\n@ * @param[in] pu2_iscal_mat\n@ *  pointer to scaling list\n@ *\n@ * @param[in] pu2_weigh_mat\n@ *  pointer to weight matrix\n@ *\n@ * @param[in] u4_qp_div_6\n@ *  Floor (qp/6)\n@ *\n@ * @param[in] pi4_tmp\n@ * temporary buffer of size 1*16\n@ *\n@ * @returns none\n@ *\n@ * @remarks none\n@ *\n@ *******************************************************************************\n@ *\n@ *\n@ *******************************************************************************\n@ *\n@ void ih264_ihadamard_scaling_4x4(WORD16* pi2_src,\n@       WORD16* pi2_out,\n@       const UWORD16 *pu2_iscal_mat,\n@       const UWORD16 *pu2_weigh_mat,\n@       UWORD32 u4_qp_div_6,\n@       WORD32* pi4_tmp)\n@**************Variables Vs Registers*****************************************\n@r0 => *pi2_src\n@r1 => *pi2_out\n@r2 =>  *pu2_iscal_mat\n@r3 =>  *pu2_weigh_mat\n@r4 =>  u4_qp_div_6\n\n.text\n.p2align 2\n\n    .global ih264_ihadamard_scaling_4x4_a9\n\nih264_ihadamard_scaling_4x4_a9:\n\n@VLD4.S16 is used because the pointer is incremented by SUB_BLK_WIDTH_4x4\n@If the macro value changes need to change the instruction according to it.\n@Only one shift is done in horizontal inverse because,\n@if u4_qp_div_6 is lesser than 4 then shift value will be neagative and do negative left shift, in this case rnd_factor has value\n@if u4_qp_div_6 is greater than 4 then shift value will be positive and do left shift, here rnd_factor is 0\n\n    stmfd         sp!, {r4-r12, r14}    @ stack stores the values of the arguments\n    ldr           r4, [sp, #40]         @ Loads u4_qp_div_6\n    vdup.s32      q10, r4               @ Populate the u4_qp_div_6 in Q10\n    ldrh          r6, [r3]              @ load pu2_weight_mat[0] , H for unsigned halfword load\n    ldrh          r7, [r2]              @ load pu2_iscal_mat[0] , H for unsigned halfword load\n    mul           r6, r6, r7            @ pu2_iscal_mat[0]*pu2_weigh_mat[0]\n    vdup.s32      q9, r6                @ Populate pu2_iscal_mat[0]*pu2_weigh_mat[0] 32-bit in Q9\n    vpush         {d8-d15}\n@=======================INVERSE HADAMARD TRANSFORM================================\n\n    vld4.s16      {d0, d1, d2, d3}, [r0] @load x4,x5,x6,x7\n    vaddl.s16     q12, d0, d3           @x0 = x4 + x7\n    vaddl.s16     q13, d1, d2           @x1 = x5 + x6\n    vsubl.s16     q14, d1, d2           @x2 = x5 - x6\n    vsubl.s16     q15, d0, d3           @x3 = x4 - x7\n\n    vadd.s32      q2, q12, q13          @pi4_tmp_ptr[0] = x0 + x1\n    vadd.s32      q3, q15, q14          @pi4_tmp_ptr[1] = x3 + x2\n    vsub.s32      q4, q12, q13          @pi4_tmp_ptr[2] = x0 - x1\n    vsub.s32      q5, q15, q14          @pi4_tmp_ptr[3] = x3 - x2\n\n    vtrn.32       q2, q3                @Transpose the register for vertical transform\n    vtrn.32       q4, q5\n\n    vswp          d5, d8                @Q2 = x4, Q4 = x6\n    vswp          d7, d10               @Q3 = x5, Q5 = x7\n\n\n    vadd.s32      q12, q2, q5           @x0 = x4+x7\n    vadd.s32      q13, q3, q4           @x1 = x5+x6\n    vsub.s32      q14, q3, q4           @x2 = x5-x6\n    vsub.s32      q15, q2, q5           @x3 = x4-x7\n\n    vadd.s32      q0, q12, q13          @pi4_tmp_ptr[0] = x0 + x1\n    vadd.s32      q1, q15, q14          @pi4_tmp_ptr[1] = x3 + x2\n    vsub.s32      q2, q12, q13          @pi4_tmp_ptr[2] = x0 - x1\n    vsub.s32      q3, q15, q14          @pi4_tmp_ptr[3] = x3 - x2\n\n\n    vmul.s32      q0, q0, q9            @ Q0  = p[i] = (x[i] * trns_coeff[i]) where i = 0..3\n    vmul.s32      q1, q1, q9            @ Q1  = p[i] = (x[i] * trns_coeff[i]) where i = 4..7\n    vmul.s32      q2, q2, q9            @ Q2  = p[i] = (x[i] * trns_coeff[i]) where i = 8..11\n    vmul.s32      q3, q3, q9            @ Q3  = p[i] = (x[i] * trns_coeff[i]) where i = 12..15\n\n    vshl.s32      q0, q0, q10           @ Q0  = q[i] = (p[i] << (qP/6)) where i = 0..3\n    vshl.s32      q1, q1, q10           @ Q1  = q[i] = (p[i] << (qP/6)) where i = 4..7\n    vshl.s32      q2, q2, q10           @ Q2  = q[i] = (p[i] << (qP/6)) where i = 8..11\n    vshl.s32      q3, q3, q10           @ Q3  = q[i] = (p[i] << (qP/6)) where i = 12..15\n\n    vqrshrn.s32   d0, q0, #0x6          @ D0  = c[i] = ((q[i] + 32) >> 4) where i = 0..3\n    vqrshrn.s32   d1, q1, #0x6          @ D1  = c[i] = ((q[i] + 32) >> 4) where i = 4..7\n    vqrshrn.s32   d2, q2, #0x6          @ D2  = c[i] = ((q[i] + 32) >> 4) where i = 8..11\n    vqrshrn.s32   d3, q3, #0x6          @ D3  = c[i] = ((q[i] + 32) >> 4) where i = 12..15\n\n    vst1.s16      {d0, d1, d2, d3}, [r1] @IV row store the value\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r12, r15}    @Reload the registers from SP\n\n\n\n@ *******************************************************************************\n@ *\n@ * @brief This function performs a 2x2 inverse hadamard transform for chroma block\n@ *\n@ * @par Description:\n@ *  The DC coefficients pass through a 2-stage inverse hadamard transform.\n@ *  This inverse transformed content is scaled to based on Qp value.\n@ *  Both DC blocks of U and v blocks are processesd\n@ *\n@ * @param[in] pi2_src\n@ *  input 1x8 block of ceffs. First 4 are from U and next from V\n@ *\n@ * @param[out] pi2_out\n@ *  output 1x8 block\n@ *\n@ * @param[in] pu2_iscal_mat\n@ *  pointer to scaling list\n@ *\n@ * @param[in] pu2_weigh_mat\n@ *  pointer to weight matrix\n@ *\n@ * @param[in] u4_qp_div_6\n@ *  Floor (qp/6)\n@ *\n@ * @returns none\n@ *\n@ * @remarks none\n@ *\n@ *******************************************************************************\n@ *\n@ *\n@ *******************************************************************************\n@ *\n@ void ih264_ihadamard_scaling_2x2_uv(WORD16* pi2_src,\n@                                  WORD16* pi2_out,\n@                                  const UWORD16 *pu2_iscal_mat,\n@                                  const UWORD16 *pu2_weigh_mat,\n@                                  UWORD32 u4_qp_div_6,\n\n    .global ih264_ihadamard_scaling_2x2_uv_a9\nih264_ihadamard_scaling_2x2_uv_a9:\n\n@Registers used\n@   r0 : *pi2_src\n@   r1 : *pi2_out\n@   r2 : *pu2_iscal_mat\n@   r3 : *pu2_weigh_mat\n\n    vld1.u16      d26[0], [r2]\n    vld1.u16      d27[0], [r3]\n    vmull.u16     q15, d26, d27         @pu2_iscal_mat[0] *  pu2_weigh_mat[0]\n    vdup.u32      q15, d30[0]\n\n    vld1.u16      d28[0], [sp]          @load qp/6\n\n    vpush         {d8-d15}\n\n    vmov.u16      d29, #5\n    vsubl.u16     q14, d28, d29         @qp\\6 - 5\n    vdup.s32      q14, d28[0]\n\n    vld2.s16      {d0, d1}, [r0]        @load 8 dc coeffs\n                                        @i2_x4,i2_x6,i2_y4,i1_y6 -> d0\n                                        @i2_x5,i2_x7,i2_y5,i1_y6 -> d1\n\n    vaddl.s16     q1, d0, d1            @  i4_x0 = i4_x4 + i4_x5;...x2\n    vsubl.s16     q2, d0, d1            @  i4_x1 = i4_x4 - i4_x5;...x3\n\n    vtrn.s32      q1, q2                @i4_x0 i4_x1 -> q1\n\n    vadd.s32      q3, q1, q2            @i4_x4 = i4_x0+i4_x2;.. i4_x5\n    vsub.s32      q1, q1, q2            @i4_x6 = i4_x0-i4_x2;.. i4_x7\n\n    vmul.s32      q5, q3, q15\n    vmul.s32      q6, q1, q15\n\n    vshl.s32      q7, q5, q14\n    vshl.s32      q8, q6, q14\n\n    vmovn.s32     d18, q7               @i4_x4 i4_x5 i4_y4 i4_y5\n    vmovn.s32     d19, q8               @i4_x6 i4_x7 i4_y6 i4_y7\n\n    vst2.s32      {d18-d19}, [r1]\n\n    vpop          {d8-d15}\n    bx            lr\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_chroma_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_inter_pred_chroma_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for inter prediction  interpolation.\n@*\n@* @author\n@*  Ittaim\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_inter_pred_chroma_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_inter_pred_filters.c\n@\n\n@**\n@**\n@**\n@\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*    Interprediction chroma filter\n@*\n@* @par Description:\n@*   Applies filtering to chroma samples as mentioned in\n@*    sec 8.4.2.2.2 titled \"chroma sample interpolation process\"\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source containing alternate U and V samples\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in]uc_dx\n@*  dx value where the sample is to be produced(refer sec 8.4.2.2.2 )\n@*\n@* @param[in] uc_dy\n@*  dy value where the sample is to be produced(refer sec 8.4.2.2.2 )\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@void ih264_inter_pred_chroma(UWORD8 *pu1_src,\n@                             UWORD8 *pu1_dst,\n@                             WORD32 src_strd,\n@                             WORD32 dst_strd,\n@                             WORD32 u1_dx,\n@                             WORD32 u1_dy,\n@                             WORD32 ht,\n@                             WORD32 wd)\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  u1_dx\n@   r5 =>  u1_dy\n@   r6 =>  height\n@   r7 => width\n@\n.text\n.p2align 2\n\n    .global ih264_inter_pred_chroma_a9q\n\nih264_inter_pred_chroma_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r4, [sp, #104]\n    ldr           r5, [sp, #108]\n    ldr           r6, [sp, #112]\n    ldr           r7, [sp, #116]\n\n    rsb           r8, r4, #8            @8-u1_dx\n    rsb           r9, r5, #8            @8-u1_dy\n    mul           r10, r8, r9\n    mul           r11, r4, r9\n\n    vdup.u8       d28, r10\n    vdup.u8       d29, r11\n\n    mul           r10, r8, r5\n    mul           r11, r4, r5\n\n    vdup.u8       d30, r10\n    vdup.u8       d31, r11\n\n    subs          r12, r7, #2           @if wd=4 branch to loop_4\n    beq           loop_2\n    subs          r12, r7, #4           @if wd=8 branch to loop_8\n    beq           loop_4\n\nloop_8:\n    sub           r6, #1\n    vld1.8        {d0, d1, d2}, [r0], r2 @ Load row0\n    vld1.8        {d5, d6, d7}, [r0], r2 @ Load row1\n    vext.8        d3, d0, d1, #2\n    vext.8        d8, d5, d6, #2\n\n    vmull.u8      q5, d0, d28\n    vmlal.u8      q5, d5, d30\n    vmlal.u8      q5, d3, d29\n    vmlal.u8      q5, d8, d31\n    vext.8        d9, d6, d7, #2\n    vext.8        d4, d1, d2, #2\n\ninner_loop_8:\n    vmull.u8      q6, d6, d30\n    vmlal.u8      q6, d1, d28\n    vmlal.u8      q6, d9, d31\n    vmlal.u8      q6, d4, d29\n    vmov          d0, d5\n    vmov          d3, d8\n\n    vqrshrun.s16  d14, q5, #6\n    vmov          d1, d6\n    vmov          d4, d9\n\n    vld1.8        {d5, d6, d7}, [r0], r2 @ Load row1\n    vqrshrun.s16  d15, q6, #6\n\n    vext.8        d8, d5, d6, #2\n    subs          r6, #1\n    vext.8        d9, d6, d7, #2\n    vst1.8        {q7}, [r1], r3        @ Store dest row\n\n    vmull.u8      q5, d0, d28\n    vmlal.u8      q5, d5, d30\n    vmlal.u8      q5, d3, d29\n    vmlal.u8      q5, d8, d31\n    bne           inner_loop_8\n\n    vmull.u8      q6, d6, d30\n    vmlal.u8      q6, d1, d28\n    vmlal.u8      q6, d9, d31\n    vmlal.u8      q6, d4, d29\n\n    vqrshrun.s16  d14, q5, #6\n    vqrshrun.s16  d15, q6, #6\n\n    vst1.8        {q7}, [r1], r3        @ Store dest row\n\n    b             end_func\n\nloop_4:\n    sub           r6, #1\n    vld1.8        {d0, d1}, [r0], r2    @ Load row0\n    vld1.8        {d2, d3}, [r0], r2    @ Load row1\n    vext.8        d1, d0, d1, #2\n    vext.8        d3, d2, d3, #2\n\n    vmull.u8      q2, d2, d30\n    vmlal.u8      q2, d0, d28\n    vmlal.u8      q2, d3, d31\n    vmlal.u8      q2, d1, d29\n\ninner_loop_4:\n    subs          r6, #1\n    vmov          d0, d2\n    vmov          d1, d3\n\n    vld1.8        {d2, d3}, [r0], r2    @ Load row1\n    vqrshrun.s16  d6, q2, #6\n\n    vext.8        d3, d2, d3, #2\n    vst1.8        {d6}, [r1], r3        @ Store dest row\n\n    vmull.u8      q2, d0, d28\n    vmlal.u8      q2, d2, d30\n    vmlal.u8      q2, d1, d29\n    vmlal.u8      q2, d3, d31\n    bne           inner_loop_4\n\n    vqrshrun.s16  d6, q2, #6\n    vst1.8        {d6}, [r1], r3        @ Store dest row\n\n    b             end_func\n\nloop_2:\n    vld1.8        {d0}, [r0], r2        @ Load row0\n    vext.8        d1, d0, d0, #2\n    vld1.8        {d2}, [r0], r2        @ Load row1\n    vext.8        d3, d2, d2, #2\n    vmull.u8      q2, d0, d28\n    vmlal.u8      q2, d1, d29\n    vmlal.u8      q2, d2, d30\n    vmlal.u8      q2, d3, d31\n    vld1.8        {d6}, [r0]            @ Load row2\n    vqrshrun.s16  d4, q2, #6\n    vext.8        d7, d6, d6, #2\n    vst1.32       d4[0], [r1], r3       @ Store dest row0\n    vmull.u8      q4, d2, d28\n    vmlal.u8      q4, d3, d29\n    vmlal.u8      q4, d6, d30\n    vmlal.u8      q4, d7, d31\n    subs          r6, #2\n    vqrshrun.s16  d8, q4, #6\n    vst1.32       d8[0], [r1], r3       @ Store dest row1\n    bne           loop_2                @ repeat if ht=2\n\nend_func:\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, pc}     @ Restoring registers from stack\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_filters_luma_horz_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_inter_pred_luma_horz_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for inter prediction  interpolation.\n@*\n@* @author\n@*  Ittiam\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_inter_pred_luma_horz_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_inter_pred_filters.c\n@\n\n@**\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Interprediction luma filter for horizontal input\n@*\n@* @par Description:\n@* Applies a 6 tap horizontal filter .The output is  clipped to 8 bits\n@* sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*\n@ @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@void ih264_inter_pred_luma_horz (\n@                            UWORD8 *pu1_src,\n@                            UWORD8 *pu1_dst,\n@                            WORD32 src_strd,\n@                            WORD32 dst_strd,\n@                            WORD32 ht,\n@                            WORD32 wd   )\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r5 =>  ht\n@   r6 =>  wd\n\n.text\n.p2align 2\n\n\n    .global ih264_inter_pred_luma_horz_a9q\n\nih264_inter_pred_luma_horz_a9q:\n\n\n\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r5, [sp, #104]        @Loads ht\n    sub           r0, r0, #2            @pu1_src-2\n    ldr           r6, [sp, #108]        @Loads wd\n    vmov.i8       d0, #5                @filter coeff\n    subs          r12, r6, #8           @if wd=8 branch to loop_8\n    vmov.i8       d1, #20               @filter coeff\n    beq           loop_8\n\n    subs          r12, r6, #4           @if wd=4 branch to loop_4\n    beq           loop_4\n\nloop_16:                                @when  wd=16\n    @ Processing row0 and row1\n    vld1.8        {d2, d3, d4}, [r0], r2 @// Load row0                        ;for checking loop\n    vext.8        d31, d2, d3, #5       @//extract a[5]                         (column1,row0)\n    vld1.8        {d5, d6, d7}, [r0], r2 @// Load row1\n    vext.8        d30, d3, d4, #5       @//extract a[5]                         (column2,row0)\n    vaddl.u8      q4, d31, d2           @// a0 + a5                             (column1,row0)\n    vext.8        d28, d5, d6, #5       @//extract a[5]                         (column1,row1)\n    vaddl.u8      q5, d30, d3           @// a0 + a5                             (column2,row0)\n    vext.8        d27, d6, d7, #5       @//extract a[5]                         (column2,row1)\n    vaddl.u8      q7, d28, d5           @// a0 + a5                             (column1,row1)\n    vext.8        d31, d2, d3, #2       @//extract a[2]                         (column1,row0)\n    vaddl.u8      q8, d27, d6           @// a0 + a5                             (column2,row1)\n    vext.8        d30, d3, d4, #2       @//extract a[2]                         (column2,row0)\n    vmlal.u8      q4, d31, d1           @// a0 + a5 + 20a2                      (column1,row0)\n    vext.8        d28, d5, d6, #2       @//extract a[2]                         (column1,row1)\n    vmlal.u8      q5, d30, d1           @// a0 + a5 + 20a2                      (column2,row0)\n    vext.8        d27, d6, d7, #2       @//extract a[2]                         (column2,row1)\n    vmlal.u8      q7, d28, d1           @// a0 + a5 + 20a2                      (column1,row1)\n    vext.8        d31, d2, d3, #3       @//extract a[3]                         (column1,row0)\n    vmlal.u8      q8, d27, d1           @// a0 + a5 + 20a2                      (column2,row1)\n    vext.8        d30, d3, d4, #3       @//extract a[3]                         (column2,row0)\n    vmlal.u8      q4, d31, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row0)\n    vext.8        d28, d5, d6, #3       @//extract a[3]                         (column1,row1)\n    vmlal.u8      q5, d30, d1           @// a0 + a5 + 20a2 + 20a3               (column2,row0)\n    vext.8        d27, d6, d7, #3       @//extract a[3]                         (column2,row1)\n    vmlal.u8      q7, d28, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row1)\n    vext.8        d31, d2, d3, #1       @//extract a[1]                         (column1,row0)\n    vmlal.u8      q8, d27, d1           @// a0 + a5 + 20a2 + 20a3               (column2,row1)\n    vext.8        d30, d3, d4, #1       @//extract a[1]                         (column2,row0)\n    vmlsl.u8      q4, d31, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row0)\n    vext.8        d28, d5, d6, #1       @//extract a[1]                         (column1,row1)\n    vmlsl.u8      q5, d30, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column2,row0)\n    vext.8        d27, d6, d7, #1       @//extract a[1]                         (column2,row1)\n    vmlsl.u8      q7, d28, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row1)\n    vext.8        d31, d2, d3, #4       @//extract a[4]                         (column1,row0)\n    vmlsl.u8      q8, d27, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column2,row1)\n    vext.8        d30, d3, d4, #4       @//extract a[4]                         (column2,row0)\n    vmlsl.u8      q4, d31, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row0)\n    vext.8        d28, d5, d6, #4       @//extract a[4]                         (column1,row1)\n    vmlsl.u8      q5, d30, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column2,row0)\n    vext.8        d27, d6, d7, #4       @//extract a[4]                         (column2,row1)\n    vmlsl.u8      q7, d28, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row1)\n    vmlsl.u8      q8, d27, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column2,row1)\n    vqrshrun.s16  d20, q4, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row0)\n    vqrshrun.s16  d21, q5, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column2,row0)\n    vext.8        d31, d2, d3, #5       @//extract a[5]                         (column1,row2)\n    vst1.8        {d20, d21}, [r1], r3  @//Store dest row0\n    vqrshrun.s16  d23, q7, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row1)\n    vext.8        d30, d3, d4, #5       @//extract a[5]                         (column2,row2)\n    vqrshrun.s16  d24, q8, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column2,row1)\n    vst1.8        {d23, d24}, [r1], r3  @//Store dest row1\n    subs          r5, r5, #2            @ 2 rows done, decrement by 2\n\n    beq           end_func\n    b             loop_16               @ loop if height == 8 or 16\n\nloop_8:\n@ Processing row0 and row1\n    vld1.8        {d5, d6}, [r0], r2    @// Load row1\n    vext.8        d28, d5, d6, #5       @//extract a[5]                         (column1,row1)\n    vld1.8        {d2, d3}, [r0], r2    @// Load row0\n    vext.8        d25, d5, d6, #2       @//extract a[2]                         (column1,row1)\n    vext.8        d31, d2, d3, #5       @//extract a[5]                         (column1,row0)\n    vext.8        d24, d5, d6, #3       @//extract a[3]                         (column1,row1)\n    vext.8        d23, d5, d6, #1       @//extract a[1]                         (column1,row1)\n    vext.8        d22, d5, d6, #4       @//extract a[4]                         (column1,row1)\n    vaddl.u8      q7, d28, d5           @// a0 + a5                             (column1,row1)\n    vext.8        d29, d2, d3, #3       @//extract a[3]                         (column1,row0)\n    vmlal.u8      q7, d25, d1           @// a0 + a5 + 20a2                      (column1,row1)\n    vmlal.u8      q7, d24, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row1)\n    vmlsl.u8      q7, d23, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row1)\n    vmlsl.u8      q7, d22, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row1)\n    vext.8        d30, d2, d3, #2       @//extract a[2]                         (column1,row0)\n    vaddl.u8      q4, d31, d2           @// a0 + a5                             (column1,row0)\n    vext.8        d27, d2, d3, #1       @//extract a[1]                         (column1,row0)\n    vext.8        d26, d2, d3, #4       @//extract a[4]                         (column1,row0)\n    vmlal.u8      q4, d29, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row0)\n    vmlal.u8      q4, d30, d1           @// a0 + a5 + 20a2                      (column1,row0)\n    vmlsl.u8      q4, d27, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row0)\n    vmlsl.u8      q4, d26, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row0)\n    vqrshrun.s16  d23, q7, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row0)\n    vst1.8        {d23}, [r1], r3       @//Store dest row0\n    vqrshrun.s16  d20, q4, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row1)\n    vst1.8        {d20}, [r1], r3       @//Store dest row1\n    subs          r5, r5, #2            @ 2 rows done, decrement by 2\n\n    beq           end_func              @ Branch if height==4\n\n    b             loop_8                @looping if height =8 or 16\n\nloop_4:\n    vld1.8        {d5, d6}, [r0], r2    @// Load row1\n    vext.8        d28, d5, d6, #5       @//extract a[5]                         (column1,row1)\n    vld1.8        {d2, d3}, [r0], r2    @// Load row0\n    vext.8        d25, d5, d6, #2       @//extract a[2]                         (column1,row1)\n    vext.8        d31, d2, d3, #5       @//extract a[5]                         (column1,row0)\n    vaddl.u8      q7, d28, d5           @// a0 + a5                             (column1,row1)\n    vext.8        d24, d5, d6, #3       @//extract a[3]                         (column1,row1)\n    vext.8        d23, d5, d6, #1       @//extract a[1]                         (column1,row1)\n    vext.8        d22, d5, d6, #4       @//extract a[4]                         (column1,row1)\n    vext.8        d29, d2, d3, #3       @//extract a[3]                         (column1,row0)\n    vmlal.u8      q7, d25, d1           @// a0 + a5 + 20a2                      (column1,row1)\n    vmlal.u8      q7, d24, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row1)\n    vmlsl.u8      q7, d23, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row1)\n    vmlsl.u8      q7, d22, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row1)\n    vaddl.u8      q4, d31, d2           @// a0 + a5                             (column1,row0)\n    vext.8        d30, d2, d3, #2       @//extract a[2]                         (column1,row0)\n    vext.8        d27, d2, d3, #1       @//extract a[1]                         (column1,row0)\n    vext.8        d26, d2, d3, #4       @//extract a[4]                         (column1,row0)\n    vmlal.u8      q4, d29, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row0)\n    vmlal.u8      q4, d30, d1           @// a0 + a5 + 20a2                      (column1,row0)\n    vmlsl.u8      q4, d27, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row0)\n    vmlsl.u8      q4, d26, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row0)\n    vqrshrun.s16  d23, q7, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row0)\n    vst1.32       d23[0], [r1], r3      @//Store dest row0\n    vqrshrun.s16  d20, q4, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row1)\n    vst1.32       d20[0], [r1], r3      @//Store dest row1\n    subs          r5, r5, #2            @ 2 rows done, decrement by 2\n    beq           end_func\n\n    b             loop_4\n\nend_func:\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_filters_luma_vert_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_inter_pred_luma_vert_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for inter prediction  interpolation.\n@*\n@* @author\n@*  Ittiam\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_inter_pred_luma_vert_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_inter_pred_filters.c\n@\n\n@**\n@**\n@**\n@ *******************************************************************************\n@ *\n@ * @brief\n@ *    Interprediction luma filter for vertical input\n@ *\n@ * @par Description:\n@ *   Applies a 6 tap vertcal filter.The output is  clipped to 8 bits\n@ *    sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n@ *\n@ * @param[in] pu1_src\n@ *  UWORD8 pointer to the source\n@ *\n@ * @param[out] pu1_dst\n@ *  UWORD8 pointer to the destination\n@ *\n@ * @param[in] src_strd\n@ *  integer source stride\n@ *\n@ * @param[in] dst_strd\n@ *  integer destination stride\n@ *\n@ * @param[in] ht\n@ *  integer height of the array\n@ *\n@ * @param[in] wd\n@ *  integer width of the array\n@ *\n@ * @returns\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n\n@void ih264_inter_pred_luma_vert (\n@                            UWORD8 *pu1_src,\n@                            UWORD8 *pu1_dst,\n@                            WORD32 src_strd,\n@                            WORD32 dst_strd,\n@                            WORD32 ht,\n@                            WORD32 wd   )\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r5 =>  ht\n@   r6 =>  wd\n\n.text\n.p2align 2\n\n\n    .global ih264_inter_pred_luma_vert_a9q\n\nih264_inter_pred_luma_vert_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r5, [sp, #104]        @Loads ht\n    sub           r0, r0, r2, lsl #1    @pu1_src-2*src_strd\n    ldr           r6, [sp, #108]        @Loads wd\n    vmov.u16      q11, #20              @ Filter coeff 0x14 into Q11\n\n    subs          r12, r6, #8           @if wd=8 branch to loop_8\n    vmov.u16      q12, #5               @ Filter coeff 0x5  into Q12\n    beq           loop_8\n\n    subs          r12, r6, #4           @if wd=4 branch to loop_4\n    beq           loop_4\n\nloop_16:                                @when  wd=16\n\n    vld1.u32      {q0}, [r0], r2        @ Vector load from src[0_0]\n    vld1.u32      {q1}, [r0], r2        @ Vector load from src[1_0]\n    vld1.u32      {q2}, [r0], r2        @ Vector load from src[2_0]\n    vld1.u32      {q3}, [r0], r2        @ Vector load from src[3_0]\n    vld1.u32      {q4}, [r0], r2        @ Vector load from src[4_0]\n    vaddl.u8      q6, d4, d6            @ temp1 = src[2_0] + src[3_0]\n    vld1.u32      {q5}, [r0], r2        @ Vector load from src[5_0]\n\n    vaddl.u8      q7, d0, d10           @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q8, d2, d8            @ temp2 = src[1_0] + src[4_0]\n    vmla.u16      q7, q6, q11           @ temp += temp1 * 20\n    vaddl.u8      q10, d1, d11          @ temp4 = src[0_8] + src[5_8]\n    vaddl.u8      q9, d5, d7            @ temp3 = src[2_8] + src[3_8]\n    vmla.u16      q10, q9, q11          @ temp4 += temp3 * 20\n    vld1.u32      {q0}, [r0], r2\n    vaddl.u8      q13, d3, d9           @ temp5 = src[1_8] + src[4_8]\n    vaddl.u8      q6, d6, d8\n    vmls.u16      q7, q8, q12           @ temp -= temp2 * 5\n    vaddl.u8      q8, d2, d0\n    vaddl.u8      q9, d4, d10\n    vmla.u16      q8, q6, q11\n    vmls.u16      q10, q13, q12         @ temp4 -= temp5 * 5\n    vaddl.u8      q13, d5, d11\n    vaddl.u8      q6, d7, d9\n    vqrshrun.s16  d30, q7, #5           @ dst[0_0] = CLIP_U8((temp +16) >> 5)\n    vaddl.u8      q7, d3, d1\n    vld1.u32      {q1}, [r0], r2\n    vmla.u16      q7, q6, q11\n    vmls.u16      q8, q9, q12\n    vqrshrun.s16  d31, q10, #5          @ dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    vaddl.u8      q9, d4, d2\n    vaddl.u8      q6, d8, d10\n\n    vst1.u32      {q15}, [r1], r3       @ Vector store to dst[0_0]\n    vmla.u16      q9, q6, q11\n    vaddl.u8      q10, d6, d0\n    vmls.u16      q7, q13, q12\n    vqrshrun.s16  d30, q8, #5\n    vaddl.u8      q6, d9, d11\n    vaddl.u8      q8, d5, d3\n    vaddl.u8      q13, d7, d1\n    vmla.u16      q8, q6, q11\n    vmls.u16      q9, q10, q12\n    vld1.u32      {q2}, [r0], r2\n\n    vqrshrun.s16  d31, q7, #5\n    vaddl.u8      q6, d10, d0\n    vaddl.u8      q7, d6, d4\n    vaddl.u8      q10, d8, d2\n    vmla.u16      q7, q6, q11\n    vmls.u16      q8, q13, q12\n    vst1.u32      {q15}, [r1], r3       @store row 1\n    vqrshrun.s16  d30, q9, #5\n    vaddl.u8      q9, d7, d5\n    vaddl.u8      q6, d11, d1\n    vmla.u16      q9, q6, q11\n    vaddl.u8      q13, d9, d3\n    vmls.u16      q7, q10, q12\n\n    vqrshrun.s16  d31, q8, #5\n    vmls.u16      q9, q13, q12\n    vaddl.u8      q6, d0, d2            @ temp1 = src[2_0] + src[3_0]\n    vst1.u32      {q15}, [r1], r3       @store row 2\n    vaddl.u8      q8, d10, d4           @ temp2 = src[1_0] + src[4_0]\n    vaddl.u8      q10, d9, d7           @ temp4 = src[0_8] + src[5_8]\n    vqrshrun.s16  d30, q7, #5\n    vaddl.u8      q13, d5, d11          @ temp5 = src[1_8] + src[4_8]\n    vaddl.u8      q7, d8, d6            @ temp = src[0_0] + src[5_0]\n    vqrshrun.s16  d31, q9, #5\n    vmla.u16      q7, q6, q11           @ temp += temp1 * 20\n    vaddl.u8      q9, d1, d3            @ temp3 = src[2_8] + src[3_8]\n    vst1.u32      {q15}, [r1], r3       @store row 3\n    subs          r5, r5, #4            @ 4 rows processed, decrement by 4\n    subne         r0, r0 , r2, lsl #2\n    subne         r0, r0, r2\n    beq           end_func              @ Branch if height==4\n\n    b             loop_16               @ looping if height = 8 or 16\n\nloop_8:\n@ Processing row0 and row1\n\n    vld1.u32      d0, [r0], r2          @ Vector load from src[0_0]\n    vld1.u32      d1, [r0], r2          @ Vector load from src[1_0]\n    vld1.u32      d2, [r0], r2          @ Vector load from src[2_0]\n    vld1.u32      d3, [r0], r2          @ Vector load from src[3_0]\n    vld1.u32      d4, [r0], r2          @ Vector load from src[4_0]\n    vld1.u32      d5, [r0], r2          @ Vector load from src[5_0]\n\n    vaddl.u8      q3, d2, d3            @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q4, d0, d5            @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q5, d1, d4            @ temp2 = src[1_0] + src[4_0]\n    vmla.u16      q4, q3, q11           @ temp += temp1 * 20\n    vld1.u32      d6, [r0], r2\n    vaddl.u8      q7, d3, d4\n    vaddl.u8      q8, d1, d6\n    vaddl.u8      q9, d2, d5\n    vmls.u16      q4, q5, q12           @ temp -= temp2 * 5\n    vmla.u16      q8, q7, q11\n    vld1.u32      d7, [r0], r2\n    vaddl.u8      q10, d4, d5\n    vaddl.u8      q6, d2, d7\n    vaddl.u8      q5, d3, d6\n    vmls.u16      q8, q9, q12\n    vqrshrun.s16  d26, q4, #5           @ dst[0_0] = CLIP_U8( (temp + 16) >> 5)\n    vmla.u16      q6, q10, q11\n    vld1.u32      d0, [r0], r2\n    vaddl.u8      q7, d5, d6\n    vqrshrun.s16  d27, q8, #5\n    vaddl.u8      q10, d3, d0\n    vmls.u16      q6, q5, q12\n    vst1.u32      d26, [r1], r3         @ Vector store to dst[0_0]\n    vaddl.u8      q9, d4, d7\n    vmla.u16      q10, q7, q11\n    vst1.u32      d27, [r1], r3\n    vqrshrun.s16  d28, q6, #5\n    vst1.u32      d28, [r1], r3\n    vmls.u16      q10, q9, q12\n    vqrshrun.s16  d29, q10, #5\n    vst1.u32      d29, [r1], r3         @store row 3\n\n    subs          r5, r5, #4            @ 4 rows processed, decrement by 4\n    subne         r0, r0 , r2, lsl #2\n    subne         r0, r0, r2\n    beq           end_func              @ Branch if height==4\n\n    b             loop_8                @looping if height == 8 or 16\n\n\nloop_4:\n@ Processing row0 and row1\n\n    vld1.u32      d0[0], [r0], r2       @ Vector load from src[0_0]\n    vld1.u32      d1[0], [r0], r2       @ Vector load from src[1_0]\n    vld1.u32      d2[0], [r0], r2       @ Vector load from src[2_0]\n    vld1.u32      d3[0], [r0], r2       @ Vector load from src[3_0]\n    vld1.u32      d4[0], [r0], r2       @ Vector load from src[4_0]\n    vld1.u32      d5[0], [r0], r2       @ Vector load from src[5_0]\n\n    vaddl.u8      q3, d2, d3            @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q4, d0, d5            @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q5, d1, d4            @ temp2 = src[1_0] + src[4_0]\n    vmla.u16      q4, q3, q11           @ temp += temp1 * 20\n    vld1.u32      d6[0], [r0], r2\n    vaddl.u8      q7, d3, d4\n    vaddl.u8      q8, d1, d6\n    vaddl.u8      q9, d2, d5\n    vmls.u16      q4, q5, q12           @ temp -= temp2 * 5\n    vld1.u32      d7[0], [r0], r2\n    vmla.u16      q8, q7, q11\n    vaddl.u8      q10, d4, d5\n    vaddl.u8      q6, d2, d7\n    vaddl.u8      q5, d3, d6\n    vmls.u16      q8, q9, q12\n    vqrshrun.s16  d26, q4, #5           @ dst[0_0] = CLIP_U8( (temp + 16) >> 5)\n    vmla.u16      q6, q10, q11\n    vld1.u32      d0[0], [r0], r2\n    vaddl.u8      q7, d5, d6\n    vqrshrun.s16  d27, q8, #5\n    vaddl.u8      q10, d3, d0\n    vmls.u16      q6, q5, q12\n    vst1.u32      d26[0], [r1], r3      @ Vector store to dst[0_0]\n    vaddl.u8      q9, d4, d7\n    vmla.u16      q10, q7, q11\n    vst1.u32      d27[0], [r1], r3\n    vqrshrun.s16  d28, q6, #5\n    vst1.u32      d28[0], [r1], r3\n    vmls.u16      q10, q9, q12\n    vqrshrun.s16  d29, q10, #5\n    vst1.u32      d29[0], [r1], r3      @store row 3\n\n    subs          r5, r5, #8\n    subeq         r0, r0, r2, lsl #2\n    subeq         r0, r0, r2\n    beq           loop_4                @ Loop if height==8\n\nend_func:\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_luma_bilinear_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_inter_pred_luma_bilinear_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for inter prediction  interpolation.\n@*\n@* @author\n@* Ittiam\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_inter_pred_luma_bilinear_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_inter_pred_filters.c\n@\n\n@**\n@**\n@**\n@ *******************************************************************************\n@ *  function:ih264_inter_pred_luma_bilinear\n@ *\n@* @brief\n@*    This routine applies the bilinear filter to the predictors .\n@*    The  filtering operation is described in\n@*    sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n@*\n@* @par Description:\n@\\note\n@*     This function is called to obtain pixels lying at the following\n@*    locations (1/4,1), (3/4,1),(1,1/4), (1,3/4) ,(1/4,1/2), (3/4,1/2),(1/2,1/4), (1/2,3/4),(3/4,1/4),(1/4,3/4),(3/4,3/4)&& (1/4,1/4) .\n@*    The function averages the two adjacent values from the two input arrays in horizontal direction.\n@*\n@*\n@* @param[in] pu1_src1:\n@*  UWORD8 Pointer to the buffer containing the first input array.\n@*\n@* @param[in] pu1_src2:\n@*  UWORD8 Pointer to the buffer containing the second input array.\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination where the output of bilinear filter is stored.\n@*\n@* @param[in] src_strd1\n@*  Stride of the first input buffer\n@*\n@* @param[in] src_strd2\n@*  Stride of the second input buffer\n@*\n@* @param[in] dst_strd\n@*  integer destination stride of pu1_dst\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@void ih264_inter_pred_luma_bilinear(UWORD8 *pu1_src1,\n@                                   UWORD8 *pu1_src2,\n@                                   UWORD8 *pu1_dst,\n@                                   WORD32 src_strd1,\n@                                   WORD32 src_strd2,\n@                                   WORD32 dst_strd,\n@                                   WORD32 height,\n@                                   WORD32 width)\n@\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src1\n@   r1 => *pu1_src2\n@   r2 => *pu1_dst\n@   r3 =>  src_strd1\n@   r4 =>  src_strd2\n@   r5 =>  dst_strd\n@   r6 =>  height\n@   r7 => width\n@\n.text\n.p2align 2\n\n    .global ih264_inter_pred_luma_bilinear_a9q\n\nih264_inter_pred_luma_bilinear_a9q:\n\n\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r4, [sp, #104]\n    ldr           r5, [sp, #108]        @\n    ldr           r6, [sp, #112]\n    ldr           r7, [sp, #116]\n\n    subs          r12, r7, #4           @if wd=4 branch to loop_4\n    beq           loop_4\n    subs          r12, r7, #8           @if wd=8 branch to loop_8\n    beq           loop_8\n\nloop_16:                                @when  wd=16\n\n    vld1.8        {q0}, [r0], r3        @// Load row0 ;src1\n    vld1.8        {q2}, [r1], r4        @// Load row0  ;src2\n    vld1.8        {q1}, [r0], r3        @// Load row1 ;src1\n    vaddl.u8      q10, d0, d4\n    vld1.8        {q3}, [r1], r4        @// Load row1  ;src2\n    vaddl.u8      q11, d1, d5\n    vld1.8        {q4}, [r0], r3        @// Load row2 ;src1\n    vaddl.u8      q12, d2, d6\n    vld1.8        {q5}, [r0], r3        @// Load row3 ;src1\n    vaddl.u8      q13, d3, d7\n    vld1.8        {q6}, [r1], r4        @// Load row2  ;src2\n    vaddl.u8      q8, d8, d12\n    vld1.8        {q7}, [r1], r4        @// Load row3  ;src2\n    vaddl.u8      q9, d9, d13\n    vqrshrun.s16  d28, q10, #1\n    vqrshrun.s16  d29, q11, #1\n    vaddl.u8      q10, d10, d14\n    vqrshrun.s16  d30, q12, #1\n    vqrshrun.s16  d31, q13, #1\n    vst1.8        {q14}, [r2], r5       @//Store dest row0\n    vaddl.u8      q11, d11, d15\n    vst1.8        {q15}, [r2], r5       @//Store dest row1\n    vqrshrun.s16  d28, q8, #1\n    vld1.8        {q0}, [r0], r3        @// Load row4 ;src1\n    vqrshrun.s16  d29, q9, #1\n    vld1.8        {q1}, [r0], r3        @// Load row5 ;src1\n    vqrshrun.s16  d30, q10, #1\n    vld1.8        {q2}, [r1], r4        @// Load row4  ;src2\n    vqrshrun.s16  d31, q11, #1\n    vld1.8        {q3}, [r1], r4        @// Load row5  ;src2\n    vaddl.u8      q10, d0, d4\n    vst1.8        {q14}, [r2], r5       @//Store dest row2\n    vaddl.u8      q13, d3, d7\n    vst1.8        {q15}, [r2], r5       @//Store dest row3\n    vaddl.u8      q11, d1, d5\n    vld1.8        {q4}, [r0], r3        @// Load row6 ;src1\n    vaddl.u8      q12, d2, d6\n    vld1.8        {q5}, [r0], r3        @// Load row7 ;src1\n    vqrshrun.s16  d28, q10, #1\n    vld1.8        {q6}, [r1], r4        @// Load row6  ;src2\n    vqrshrun.s16  d29, q11, #1\n    vld1.8        {q7}, [r1], r4        @// Load row7  ;src2\n    vaddl.u8      q8, d8, d12\n    vaddl.u8      q9, d9, d13\n    vaddl.u8      q10, d10, d14\n    vqrshrun.s16  d30, q12, #1\n    vqrshrun.s16  d31, q13, #1\n    vst1.8        {q14}, [r2], r5       @//Store dest row4\n    vaddl.u8      q11, d11, d15\n    vst1.8        {q15}, [r2], r5       @//Store dest row5\n    vqrshrun.s16  d28, q8, #1\n    vqrshrun.s16  d30, q10, #1\n    vqrshrun.s16  d29, q9, #1\n    vld1.8        {q2}, [r1], r4        @// Load row8  ;src2\n    vqrshrun.s16  d31, q11, #1\n    vst1.8        {q14}, [r2], r5       @//Store dest row6\n    subs          r12, r6, #8\n    vst1.8        {q15}, [r2], r5       @//Store dest row7\n\n    beq           end_func              @ end function if ht=8\n\n    vld1.8        {q0}, [r0], r3        @// Load row8 ;src1\n    vaddl.u8      q10, d0, d4\n    vld1.8        {q1}, [r0], r3        @// Load row9 ;src1\n    vaddl.u8      q11, d1, d5\n    vld1.8        {q3}, [r1], r4        @// Load row9  ;src2\n    vqrshrun.s16  d28, q10, #1\n    vld1.8        {q4}, [r0], r3        @// Load row10 ;src1\n    vqrshrun.s16  d29, q11, #1\n    vld1.8        {q5}, [r0], r3        @// Load row11 ;src1\n    vaddl.u8      q12, d2, d6\n    vld1.8        {q6}, [r1], r4        @// Load row10  ;src2\n    vaddl.u8      q13, d3, d7\n    vld1.8        {q7}, [r1], r4        @// Load row11 ;src2\n    vaddl.u8      q8, d8, d12\n    vaddl.u8      q9, d9, d13\n    vaddl.u8      q10, d10, d14\n    vqrshrun.s16  d30, q12, #1\n    vst1.8        {q14}, [r2], r5       @//Store dest row8\n    vqrshrun.s16  d31, q13, #1\n    vst1.8        {q15}, [r2], r5       @//Store dest row9\n    vqrshrun.s16  d28, q8, #1\n    vld1.8        {q0}, [r0], r3        @// Load row12 ;src1\n    vaddl.u8      q11, d11, d15\n    vld1.8        {q1}, [r0], r3        @// Load row13 ;src1\n    vqrshrun.s16  d29, q9, #1\n    vld1.8        {q2}, [r1], r4        @// Load row12  ;src2\n    vqrshrun.s16  d30, q10, #1\n    vld1.8        {q3}, [r1], r4        @// Load row13  ;src2\n    vqrshrun.s16  d31, q11, #1\n    vst1.8        {q14}, [r2], r5       @//Store dest row10\n    vaddl.u8      q10, d0, d4\n    vst1.8        {q15}, [r2], r5       @//Store dest row11\n    vaddl.u8      q11, d1, d5\n    vld1.8        {q4}, [r0], r3        @// Load row14 ;src1\n    vaddl.u8      q13, d3, d7\n    vld1.8        {q5}, [r0], r3        @// Load row15 ;src1\n    vaddl.u8      q12, d2, d6\n    vld1.8        {q6}, [r1], r4        @// Load row14  ;src2\n    vaddl.u8      q8, d8, d12\n    vld1.8        {q7}, [r1], r4        @// Load row15  ;src2\n    vaddl.u8      q9, d9, d13\n    vqrshrun.s16  d28, q10, #1\n    vqrshrun.s16  d29, q11, #1\n    vaddl.u8      q10, d10, d14\n    vst1.8        {q14}, [r2], r5       @//Store dest row12\n    vqrshrun.s16  d30, q12, #1\n    vqrshrun.s16  d31, q13, #1\n    vaddl.u8      q11, d11, d15\n    vst1.8        {q15}, [r2], r5       @//Store dest row13\n    vqrshrun.s16  d28, q8, #1\n    vqrshrun.s16  d29, q9, #1\n    vqrshrun.s16  d30, q10, #1\n    vst1.8        {q14}, [r2], r5       @//Store dest row14\n    vqrshrun.s16  d31, q11, #1\n    vst1.8        {q15}, [r2], r5       @//Store dest row15\n    b             end_func\n\n\n\nloop_8: @wd=8;\n    vld1.8        {d0}, [r0], r3        @// Load row0 ;src1\n    vld1.8        {d4}, [r1], r4        @// Load row0  ;src2\n    vld1.8        {d1}, [r0], r3        @// Load row1 ;src1\n    vaddl.u8      q10, d0, d4\n    vld1.8        {d5}, [r1], r4        @// Load row1  ;src2\n    vld1.8        {d2}, [r0], r3        @// Load row2 ;src1\n    vqrshrun.s16  d28, q10, #1\n    vld1.8        {d6}, [r1], r4        @// Load row2  ;src2\n    vaddl.u8      q11, d1, d5\n    vld1.8        {d3}, [r0], r3        @// Load row3 ;src1\n    vaddl.u8      q12, d2, d6\n    vst1.8        {d28}, [r2], r5       @//Store dest row0\n    vqrshrun.s16  d29, q11, #1\n    vld1.8        {d7}, [r1], r4        @// Load row3  ;src2\n    vqrshrun.s16  d30, q12, #1\n    vst1.8        {d29}, [r2], r5       @//Store dest row1\n    vaddl.u8      q13, d3, d7\n    vst1.8        {d30}, [r2], r5       @//Store dest row2\n    vqrshrun.s16  d31, q13, #1\n    subs          r12, r6, #4\n    vst1.8        {d31}, [r2], r5       @//Store dest row3\n    beq           end_func              @ end function if ht=4\n\n    vld1.8        {d12}, [r1], r4       @// Load row4 ;src2\n    vld1.8        {d8}, [r0], r3        @// Load row4 ;src1\n    vld1.8        {d9}, [r0], r3        @// Load row5 ;src1\n    vaddl.u8      q8, d8, d12\n    vld1.8        {d13}, [r1], r4       @// Load row5  ;src2\n    vld1.8        {d10}, [r0], r3       @// Load row6;src1\n    vaddl.u8      q9, d9, d13\n    vld1.8        {d14}, [r1], r4       @// Load row6  ;src2\n    vqrshrun.s16  d28, q8, #1\n    vld1.8        {d11}, [r0], r3       @// Load row7 ;src1\n    vqrshrun.s16  d29, q9, #1\n    vst1.8        {d28}, [r2], r5       @//Store dest row4\n    vaddl.u8      q10, d10, d14\n    vst1.8        {d29}, [r2], r5       @//Store dest row5\n    vqrshrun.s16  d30, q10, #1\n    vld1.8        {d15}, [r1], r4       @// Load row7 ;src2\n    vaddl.u8      q11, d11, d15\n    vst1.8        {d30}, [r2], r5       @//Store dest row6\n    vqrshrun.s16  d31, q11, #1\n    subs          r12, r6, #8\n    vst1.8        {d31}, [r2], r5       @//Store dest row7\n    beq           end_func              @ end function if ht=8\n\n    vld1.8        {d0}, [r0], r3        @// Load row8 ;src1\n    vld1.8        {d4}, [r1], r4        @// Load row8  ;src2\n    vld1.8        {d1}, [r0], r3        @// Load row9 ;src1\n    vaddl.u8      q10, d0, d4\n    vld1.8        {d5}, [r1], r4        @// Load row9  ;src2\n    vld1.8        {d2}, [r0], r3        @// Load row10 ;src1\n    vaddl.u8      q11, d1, d5\n    vld1.8        {d6}, [r1], r4        @// Load row10  ;src2\n    vqrshrun.s16  d28, q10, #1\n    vld1.8        {d3}, [r0], r3        @// Load row11 ;src1\n    vaddl.u8      q12, d2, d6\n    vld1.8        {d7}, [r1], r4        @// Load row11  ;src2\n    vqrshrun.s16  d29, q11, #1\n    vld1.8        {d8}, [r0], r3        @// Load row12 ;src1\n    vaddl.u8      q13, d3, d7\n    vst1.8        {d28}, [r2], r5       @//Store dest row8\n    vqrshrun.s16  d30, q12, #1\n    vld1.8        {d12}, [r1], r4       @// Load row12  ;src2\n    vqrshrun.s16  d31, q13, #1\n    vst1.8        {d29}, [r2], r5       @//Store dest row9\n    vaddl.u8      q8, d8, d12\n    vld1.8        {d9}, [r0], r3        @// Load row13 ;src1\n    vqrshrun.s16  d28, q8, #1\n    vld1.8        {d13}, [r1], r4       @// Load row13  ;src2\n    vld1.8        {d10}, [r0], r3       @// Load row14;src1\n    vaddl.u8      q9, d9, d13\n    vld1.8        {d11}, [r0], r3       @// Load row15 ;src1\n    vld1.8        {d14}, [r1], r4       @// Load row14  ;src2\n    vqrshrun.s16  d29, q9, #1\n    vld1.8        {d15}, [r1], r4       @// Load roW15 ;src2\n    vaddl.u8      q10, d10, d14\n    vst1.8        {d30}, [r2], r5       @//Store dest row10\n    vaddl.u8      q11, d11, d15\n    vst1.8        {d31}, [r2], r5       @//Store dest row11\n    vqrshrun.s16  d30, q10, #1\n    vst1.8        {d28}, [r2], r5       @//Store dest row12\n    vqrshrun.s16  d31, q11, #1\n    vst1.8        {d29}, [r2], r5       @//Store dest row13\n    vst1.8        {d30}, [r2], r5       @//Store dest row14\n    vst1.8        {d31}, [r2], r5       @//Store dest row15\n\n    b             end_func\n\n\n\nloop_4:\n    vld1.32       d0[0], [r0], r3       @// Load row0 ;src1\n    vld1.32       d4[0], [r1], r4       @// Load row0  ;src2\n    vld1.32       d1[0], [r0], r3       @// Load row1 ;src1\n    vaddl.u8      q10, d0, d4\n    vld1.32       d5[0], [r1], r4       @// Load row1  ;src2\n    vld1.32       d2[0], [r0], r3       @// Load row2 ;src1\n    vqrshrun.s16  d28, q10, #1\n    vld1.32       d6[0], [r1], r4       @// Load row2  ;src2\n    vaddl.u8      q11, d1, d5\n    vld1.32       d3[0], [r0], r3       @// Load row3 ;src1\n    vaddl.u8      q12, d2, d6\n    vst1.32       d28[0], [r2], r5      @//Store dest row0\n    vqrshrun.s16  d29, q11, #1\n    vld1.32       d7[0], [r1], r4       @// Load row3  ;src2\n    vqrshrun.s16  d30, q12, #1\n    vst1.32       d29[0], [r2], r5      @//Store dest row1\n    vaddl.u8      q13, d3, d7\n    vst1.32       d30[0], [r2], r5      @//Store dest row2\n    vqrshrun.s16  d31, q13, #1\n    subs          r12, r6, #4\n    vst1.32       d31[0], [r2], r5      @//Store dest row3\n    beq           end_func              @ end function if ht=4\n\n    vld1.32       d12[0], [r1], r4      @// Load row4 ;src2\n    vld1.32       d8[0], [r0], r3       @// Load row4 ;src1\n    vld1.32       d9[0], [r0], r3       @// Load row5 ;src1\n    vaddl.u8      q8, d8, d12\n    vld1.32       d13[0], [r1], r4      @// Load row5  ;src2\n    vld1.32       d10[0], [r0], r3      @// Load row6;src1\n    vaddl.u8      q9, d9, d13\n    vld1.32       d14[0], [r1], r4      @// Load row6  ;src2\n    vqrshrun.s16  d28, q8, #1\n    vld1.32       d11[0], [r0], r3      @// Load row7 ;src1\n    vqrshrun.s16  d29, q9, #1\n    vst1.32       d28[0], [r2], r5      @//Store dest row4\n    vaddl.u8      q10, d10, d14\n    vst1.32       d29[0], [r2], r5      @//Store dest row5\n    vqrshrun.s16  d30, q10, #1\n    vld1.32       d15[0], [r1], r4      @// Load row7 ;src2\n    vaddl.u8      q11, d11, d15\n    vst1.32       d30[0], [r2], r5      @//Store dest row6\n    vqrshrun.s16  d31, q11, #1\n    vst1.32       d31[0], [r2], r5      @//Store dest row7\n\nend_func:\n\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_luma_copy_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Interprediction luma function for copy\n@*\n@* @par Description:\n@*   Copies the array of width 'wd' and height 'ht' from the  location pointed\n@*   by 'src' to the location pointed by 'dst'\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@void ih264_inter_pred_luma_copy (\n@                            UWORD8 *pu1_src,\n@                            UWORD8 *pu1_dst,\n@                            WORD32 src_strd,\n@                            WORD32 dst_strd,\n@                            WORD32 ht,\n@                            WORD32 wd   )\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r7 =>  ht\n@   r12 => wd\n\n.text\n.p2align 2\n\n    .global ih264_inter_pred_luma_copy_a9q\n\nih264_inter_pred_luma_copy_a9q:\n    stmfd         sp!, {r4-r12, r14}    @stack stores the values of the arguments\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r12, [sp, #108]       @Loads wd\n    ldr           r7, [sp, #104]        @Loads ht\n    cmp           r7, #0                @checks ht == 0\n    ble           end_loops\n    tst           r12, #15              @checks wd for multiples for 4 & 8\n    beq           core_loop_wd_16\n    tst           r12, #7               @checks wd for multiples for 4 & 8\n    beq           core_loop_wd_8\n    sub           r11, r12, #4\n\nouter_loop_wd_4:\n    subs          r4, r12, #0           @checks wd == 0\n    ble           end_inner_loop_wd_4\n\ninner_loop_wd_4:\n    vld1.32       {d0[0]}, [r0]         @vld1_lane_u32((uint32_t *)pu1_src_tmp, src_tmp, 0)\n    add           r5, r0, r2            @pu1_src_tmp += src_strd\n    add           r6, r1, r3            @pu1_dst_tmp += dst_strd\n    vst1.32       {d0[0]}, [r1]         @vst1_lane_u32((uint32_t *)pu1_dst_tmp, src_tmp, 0)\n    vld1.32       {d0[0]}, [r5], r2     @vld1_lane_u32((uint32_t *)pu1_src_tmp, src_tmp, 0)\n    add           r0, r0, #4            @pu1_src += 4\n    vst1.32       {d0[0]}, [r6], r3     @vst1_lane_u32((uint32_t *)pu1_dst_tmp, src_tmp, 0)\n    vld1.32       {d0[0]}, [r5], r2     @vld1_lane_u32((uint32_t *)pu1_src_tmp, src_tmp, 0)\n    subs          r4, r4, #4            @(wd -4)\n    vst1.32       {d0[0]}, [r6], r3     @vst1_lane_u32((uint32_t *)pu1_dst_tmp, src_tmp, 0)\n    vld1.32       {d0[0]}, [r5], r2     @vld1_lane_u32((uint32_t *)pu1_src_tmp, src_tmp, 0)\n    add           r1, r1, #4            @pu1_dst += 4\n    vst1.32       {d0[0]}, [r6], r3     @vst1_lane_u32((uint32_t *)pu1_dst_tmp, src_tmp, 0)\n\n    bgt           inner_loop_wd_4\n\nend_inner_loop_wd_4:\n    subs          r7, r7, #4            @ht - 4\n    sub           r0, r5, r11           @pu1_src = pu1_src_tmp\n    sub           r1, r6, r11           @pu1_dst = pu1_dst_tmp\n    bgt           outer_loop_wd_4\n\nend_loops:\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, r15}    @Reload the registers from SP\n\n\n\ncore_loop_wd_8:\n    sub           r11, r12, #8\n\nouter_loop_wd_8:\n    subs          r4, r12, #0           @checks wd\n    ble           end_inner_loop_wd_8\n\ninner_loop_wd_8:\n    add           r5, r0, r2            @pu1_src_tmp += src_strd\n    vld1.8        {d0}, [r0]!           @vld1_u8(pu1_src_tmp)\n    add           r6, r1, r3            @pu1_dst_tmp += dst_strd\n    vst1.8        {d0}, [r1]!           @vst1_u8(pu1_dst_tmp, tmp_src)\n    vld1.8        {d1}, [r5], r2        @vld1_u8(pu1_src_tmp)\n    vst1.8        {d1}, [r6], r3        @vst1_u8(pu1_dst_tmp, tmp_src)\n    subs          r4, r4, #8            @wd - 8(Loop condition)\n    vld1.8        {d2}, [r5], r2        @vld1_u8(pu1_src_tmp)\n    vst1.8        {d2}, [r6], r3        @vst1_u8(pu1_dst_tmp, tmp_src)\n    vld1.8        {d3}, [r5], r2        @vld1_u8(pu1_src_tmp)\n    vst1.8        {d3}, [r6], r3        @vst1_u8(pu1_dst_tmp, tmp_src)\n    bgt           inner_loop_wd_8\n\nend_inner_loop_wd_8:\n    subs          r7, r7, #4            @ht -= 4\n    sub           r0, r5, r11           @pu1_src = pu1_src_tmp\n    sub           r1, r6, r11           @pu1_dst = pu1_dst_tmp\n    bgt           outer_loop_wd_8\n\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, r15}    @Reload the registers from SP\n\ncore_loop_wd_16:\n    sub           r11, r12, #16\n\nouter_loop_wd_16:\n    subs          r4, r12, #0           @checks wd\n    ble           end_inner_loop_wd_16\n\ninner_loop_wd_16:\n    add           r5, r0, r2            @pu1_src_tmp += src_strd\n    vld1.8        {q0}, [r0]!           @vld1_u8(pu1_src_tmp)\n    add           r6, r1, r3            @pu1_dst_tmp += dst_strd\n    vst1.8        {q0}, [r1]!           @vst1_u8(pu1_dst_tmp, tmp_src)\n    vld1.8        {q1}, [r5], r2        @vld1_u8(pu1_src_tmp)\n    vst1.8        {q1}, [r6], r3        @vst1_u8(pu1_dst_tmp, tmp_src)\n    subs          r4, r4, #16           @wd - 8(Loop condition)\n    vld1.8        {q2}, [r5], r2        @vld1_u8(pu1_src_tmp)\n    vst1.8        {q2}, [r6], r3        @vst1_u8(pu1_dst_tmp, tmp_src)\n    vld1.8        {q3}, [r5], r2        @vld1_u8(pu1_src_tmp)\n    vst1.8        {q3}, [r6], r3        @vst1_u8(pu1_dst_tmp, tmp_src)\n    bgt           inner_loop_wd_16\n\nend_inner_loop_wd_16:\n    subs          r7, r7, #4            @ht -= 4\n    sub           r0, r5, r11           @pu1_src = pu1_src_tmp\n    sub           r1, r6, r11           @pu1_dst = pu1_dst_tmp\n    bgt           outer_loop_wd_16\n\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, r15}    @Reload the registers from SP\n\n\n@ *\n@ ********************************************************************************\n@ *\n@ * @brief This function copies a 4x4 block to destination\n@ *\n@ * @par Description:\n@ * Copies a 4x4 block to destination, where both src and dst are interleaved\n@ *\n@ * @param[in] pi2_src\n@ *  Source\n@ *\n@ * @param[in] pu1_out\n@ *  Output pointer\n@ *\n@ * @param[in] pred_strd,\n@ *  Prediction buffer stride\n@ *\n@ * @param[in] out_strd\n@ *  output buffer buffer Stride\n@ *\n@ * @returns none\n@ *\n@ * @remarks none\n@ * Currently wd and height is not used, ie a 4x4 block is always copied\n@ *\n@ *******************************************************************************\n@ *\n@ void ih264_interleave_copy(WORD16 *pi2_src,\n@                            UWORD8 *pu1_out,\n@                            WORD32 pred_strd,\n@                            WORD32 out_strd\n@                            WORD32 wd\n@                            WORD32 ht)\n@ Register Usage\n@ r0 : pi2_src\n@ r1 : pu1_out\n@ r2 : src_strd\n@ r3 : out_strd\n@ Neon registers d0-d7, d16-d30 are used\n@ No need for pushing  arm and neon registers\n\n    .global ih264_interleave_copy_a9\nih264_interleave_copy_a9:\n\n    vld1.u8       d2, [r0], r2          @load src plane 1 => d2 &pred palne 2 => d3\n    vld1.u8       d3, [r0], r2\n    vld1.u8       d4, [r0], r2\n    vld1.u8       d5, [r0], r2\n\n    mov           r0, r1\n\n    vld1.u8       d18, [r1], r3         @load out [8 bit size) -8 coeffs\n    vld1.u8       d19, [r1], r3\n    vmov.u16      q15, #0x00ff\n    vld1.u8       d20, [r1], r3\n    vld1.u8       d21, [r1], r3\n\n    vbit.u8       q9, q1, q15\n    vbit.u8       q10, q2, q15\n\n    vst1.u8       d18, [r0], r3         @store  out\n    vst1.u8       d19, [r0], r3\n    vst1.u8       d20, [r0], r3\n    vst1.u8       d21, [r0], r3\n\n    bx            lr\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_luma_horz_hpel_vert_hpel_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_inter_pred_luma_horz_hpel_vert_hpel_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for inter prediction  interpolation.\n@*\n@* @author\n@*  Mohit\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_inter_pred_luma_horz_hpel_vert_hpel_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_inter_pred_filters.c\n@\n\n@**\n@**\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*   This function implements a two stage cascaded six tap filter. It\n@*    applies the six tap filter in the vertical direction on the\n@*    predictor values, followed by applying the same filter in the\n@*    horizontal direction on the output of the first stage. The six tap\n@*    filtering operation is described in sec 8.4.2.2.1 titled \"Luma sample\n@*    interpolation process\"\n@*\n@* @par Description:\n@*     This function is called to obtain pixels lying at the following\n@*    location (1/2,1/2). The function interpolates\n@*    the predictors first in the horizontal direction and then in the\n@*    vertical direction to output the (1/2,1/2).\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @param[in] pu1_tmp: temporary buffer\n@*\n@* @param[in] dydx: x and y reference offset for qpel calculations: UNUSED in this function.\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*;\n\n@void ih264_inter_pred_luma_horz_hpel_vert_hpel(UWORD8 *pu1_src,\n@                                UWORD8 *pu1_dst,\n@                                WORD32 src_strd,,\n@                                WORD32 dst_strd,\n@                                WORD32 ht,\n@                                WORD32 wd,\n@                                UWORD8* pu1_tmp,\n@                                UWORD32 dydx)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r8 =>  ht\n@   r9 =>  wd\n\n.text\n.p2align 2\n\n    .global ih264_inter_pred_luma_horz_hpel_vert_hpel_a9q\n\nih264_inter_pred_luma_horz_hpel_vert_hpel_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r8, [sp, #104]        @ loads ht\n    sub           r0, r0, r2, lsl #1    @pu1_src-2*src_strd\n    sub           r0, r0, #2            @pu1_src-2\n    ldr           r9, [sp, #108]        @ loads wd\n\n    vmov.s16      d0, #20               @ Filter coeff 20\n    vmov.s16      d1, #5                @ Filter coeff 5\n    subs          r12, r9, #4           @if wd=4 branch to loop_4\n    beq           loop_4\n    subs          r12, r9, #8           @if wd=8 branch to loop_8\n    beq           loop_8\n\n    mov           r10, #8\n    sub           r7, r3, r10\n    @when  wd=16\n\nloop_16:\n    vld1.u32      {d2, d3, d4}, [r0], r2 @ Vector load from src[0_0]\n    vld1.u32      {d5, d6, d7}, [r0], r2 @ Vector load from src[1_0]\n    vld1.u32      {d8, d9, d10}, [r0], r2 @ Vector load from src[2_0]\n    vld1.u32      {d11, d12, d13}, [r0], r2 @ Vector load from src[3_0]\n    vld1.u32      {d14, d15, d16}, [r0], r2 @ Vector load from src[4_0]\n    vld1.u32      {d17, d18, d19}, [r0], r2 @ Vector load from src[5_0]\n\n    @ vERTICAL FILTERING FOR ROW 0\n    vaddl.u8      q10, d8, d11          @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q12, d2, d17          @ temp2 = src[0_0] + src[5_0]\n    vaddl.u8      q11, d5, d14          @ temp = src[1_0] + src[4_0]\n    vaddl.u8      q13, d3, d18          @ temp2 = src[0_0] + src[5_0]\n    vmla.u16      q12, q10, d0[0]       @ temp += temp1 * 20\n    vmls.s16      q12, q11, d1[0]       @ temp -= temp2 * 5\n    vaddl.u8      q10, d6, d15          @ temp = src[1_0] + src[4_0]\n    vaddl.u8      q11, d9, d12          @ temp3 = src[2_0] + src[3_0]\n    vaddl.u8      q14, d4, d19          @ temp2 = src[0_0] + src[5_0]\n    vmla.u16      q13, q11, d0[0]       @ temp4 += temp3 * 20\n    vmls.s16      q13, q10, d1[0]       @ temp -= temp2 * 5\n    vaddl.u8      q11, d10, d13         @ temp3 = src[2_0] + src[3_0]\n    vaddl.u8      q10, d7, d16          @ temp = src[1_0] + src[4_0]\n    vmla.u16      q14, q11, d0[0]       @ temp4 += temp3 * 20\n    vmls.s16      q14, q10, d1[0]       @ temp -= temp2 * 5\n    vext.16       q10, q12, q13, #5     @//extract a[5]                         (column1)\n\n    @Q12,Q13,Q14  HAVE VERTICAL FILTERED VALUES\n    @CASCADED FILTERING FOR ROW 0\n    vext.16       q11, q12, q13, #2     @//extract a[2]                         (column1)\n    vaddl.s16     q1, d20, d24          @// a0 + a5                             (column1)\n    vaddl.s16     q15, d21, d25         @// a0 + a5                             (column1)\n    vmlal.s16     q1, d22, d0[0]        @// a0 + a5 + 20a2                      (column1)\n    vmlal.s16     q15, d23, d0[0]       @// a0 + a5 + 20a2                      (column1)\n    vext.16       q11, q12, q13, #1     @//extract a[1]                         (column1)\n    vext.16       q10, q12, q13, #3     @//extract a[3]                         (column1)\n    vmlsl.s16     q1, d22, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlsl.s16     q15, d23, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlal.s16     q1, d20, d0[0]        @// a0 + a5 + 20a2 + 20a3               (column1)\n    vmlal.s16     q15, d21, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column1)\n    vext.16       q11, q12, q13, #4     @//extract a[4]                         (column1)\n    vext.16       q10, q13, q14, #5     @//extract a[5]                         (column2)\n    vmlsl.s16     q1, d22, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vmlsl.s16     q15, d23, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vqrshrun.s32  d22, q1, #10\n    vqrshrun.s32  d23, q15, #10\n    vqmovun.s16   d22, q11\n    vst1.u8       {d22}, [r1], r10      @//Store dest row0, column 1; (1/2,1/2)\n    vext.16       q11, q13, q14, #2     @//extract a[2]                         (column2)\n    vaddl.s16     q1, d20, d26          @// a0 + a5                             (column2)\n    vaddl.s16     q15, d21, d27         @// a0 + a5                             (column2)\n    vmlal.s16     q1, d22, d0[0]        @// a0 + a5 + 20a2                      (column2)\n    vmlal.s16     q15, d23, d0[0]       @// a0 + a5 + 20a2                      (column2)\n    vext.16       q10, q13, q14, #3     @//extract a[3]                         (column2)\n    vext.16       q11, q13, q14, #1     @//extract a[1]                         (column2)\n    vmlal.s16     q1, d20, d0[0]        @// a0 + a5 + 20a2 + 20a3               (column2)\n    vmlal.s16     q15, d21, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column2)\n    vext.16       q10, q13, q14, #4     @//extract a[4]                         (column2)\n    vmlsl.s16     q1, d22, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1         (column2)\n    vmlsl.s16     q15, d23, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column2)\n    vmlsl.s16     q1, d20, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column2)\n    vmlsl.s16     q15, d21, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column2)\n    vqrshrun.s32  d20, q1, #10\n    vqrshrun.s32  d21, q15, #10\n    vld1.u32      {d2, d3, d4}, [r0], r2 @ Vector load from src[6_0]\n    vqmovun.s16   d22, q10\n    vst1.u8       {d22}, [r1], r7       @//Store dest row0 ,column 2; (1/2,1/2)\n\n    @ vERTICAL FILTERING FOR ROW 1\n    vaddl.u8      q10, d11, d14         @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q12, d5, d2           @ temp2 = src[0_0] + src[5_0]\n    vaddl.u8      q11, d8, d17          @ temp = src[1_0] + src[4_0]\n    vaddl.u8      q13, d6, d3           @ temp2 = src[0_0] + src[5_0]\n    vmla.u16      q12, q10, d0[0]       @ temp += temp1 * 20\n    vaddl.u8      q10, d9, d18          @ temp = src[1_0] + src[4_0]\n    vmls.s16      q12, q11, d1[0]       @ temp -= temp2 * 5\n    vaddl.u8      q11, d12, d15         @ temp3 = src[2_0] + src[3_0]\n    vaddl.u8      q14, d7, d4           @ temp2 = src[0_0] + src[5_0]\n    vmla.u16      q13, q11, d0[0]       @ temp4 += temp3 * 20\n    vaddl.u8      q11, d13, d16         @ temp3 = src[2_0] + src[3_0]\n    vmls.s16      q13, q10, d1[0]       @ temp -= temp2 * 5\n    vmla.u16      q14, q11, d0[0]       @ temp4 += temp3 * 20\n    vaddl.u8      q10, d10, d19         @ temp = src[1_0] + src[4_0]\n    vmls.s16      q14, q10, d1[0]       @ temp -= temp2 * 5\n    vext.16       q10, q12, q13, #5     @//extract a[5]                         (column1)\n\n    @Q12,Q13,Q14  HAVE VERTICAL FILTERED VALUES\n    @CASCADED FILTERING FOR ROW 1\n    vext.16       q11, q12, q13, #2     @//extract a[2]                         (column1)\n    vaddl.s16     q3, d20, d24          @// a0 + a5                             (column1)\n    vaddl.s16     q15, d21, d25         @// a0 + a5                             (column1)\n    vmlal.s16     q3, d22, d0[0]        @// a0 + a5 + 20a2                      (column1)\n    vmlal.s16     q15, d23, d0[0]       @// a0 + a5 + 20a2                      (column1)\n    vext.16       q11, q12, q13, #1     @//extract a[1]                         (column1)\n    vext.16       q10, q12, q13, #3     @//extract a[3]                         (column1)\n    vmlsl.s16     q3, d22, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlsl.s16     q15, d23, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlal.s16     q3, d20, d0[0]        @// a0 + a5 + 20a2 + 20a3               (column1)\n    vmlal.s16     q15, d21, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column1)\n    vext.16       q11, q12, q13, #4     @//extract a[4]                         (column1)\n    vext.16       q10, q13, q14, #5     @//extract a[5]                         (column2)\n    vmlsl.s16     q3, d22, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vmlsl.s16     q15, d23, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vqrshrun.s32  d22, q3, #10\n    vqrshrun.s32  d23, q15, #10\n    vqmovun.s16   d22, q11\n    vst1.u8       {d22}, [r1], r10      @//Store dest row1, column 1; (1/2,1/2)\n    vext.16       q11, q13, q14, #2     @//extract a[2]                         (column2)\n    vaddl.s16     q3, d20, d26          @// a0 + a5                             (column2)\n    vaddl.s16     q15, d21, d27         @// a0 + a5                             (column2)\n    vmlal.s16     q3, d22, d0[0]        @// a0 + a5 + 20a2                      (column2)\n    vmlal.s16     q15, d23, d0[0]       @// a0 + a5 + 20a2                      (column2)\n    vext.16       q10, q13, q14, #3     @//extract a[3]                         (column2)\n    vext.16       q11, q13, q14, #1     @//extract a[1]                         (column2)\n    vmlal.s16     q3, d20, d0[0]        @// a0 + a5 + 20a2 + 20a3               (column2)\n    vmlal.s16     q15, d21, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column2)\n    vext.16       q10, q13, q14, #4     @//extract a[4]                         (column2)\n    vmlsl.s16     q3, d22, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1         (column2)\n    vmlsl.s16     q15, d23, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column2)\n    vmlsl.s16     q3, d20, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column2)\n    vmlsl.s16     q15, d21, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column2)\n    vqrshrun.s32  d20, q3, #10\n    vqrshrun.s32  d21, q15, #10\n    vqmovun.s16   d22, q10\n    vst1.u8       {d22}, [r1], r7       @//Store dest row1 ,column 2; (1/2,1/2)\n\n    subs          r8, r8, #2            @ 2 rows processed, decrement by 2\n    subne         r0, r0 , r2, lsl #2\n    subne         r0, r0, r2\n    beq           end_func              @ Branch if height==4\n\n    b             loop_16               @ looping if height = 8 or 16\n\nloop_8:\n    vld1.u32      {d2, d3}, [r0], r2    @ Vector load from src[0_0]\n    vld1.u32      {d4, d5}, [r0], r2    @ Vector load from src[1_0]\n    vld1.u32      {d6, d7}, [r0], r2    @ Vector load from src[2_0]\n    vld1.u32      {d8, d9}, [r0], r2    @ Vector load from src[3_0]\n    vld1.u32      {d10, d11}, [r0], r2  @ Vector load from src[4_0]\n    vld1.u32      {d12, d13}, [r0], r2  @ Vector load from src[5_0]\n\n    @ vERTICAL FILTERING FOR ROW 0\n    vaddl.u8      q10, d6, d8           @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q11, d4, d10          @ temp2 = src[1_0] + src4_0]\n    vaddl.u8      q12, d2, d12          @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q13, d3, d13          @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q14, d7, d9           @ temp1 = src[2_0] + src[3_0]\n    vmla.u16      q12, q10, d0[0]       @ temp += temp1 * 20\n    vmls.s16      q12, q11, d1[0]       @ temp -= temp2 * 5\n    vaddl.u8      q15, d5, d11          @ temp2 = src[1_0] + src4_0]\n    vmla.u16      q13, q14, d0[0]       @ temp += temp1 * 20\n    vmls.s16      q13, q15, d1[0]       @ temp -= temp2 * 5\n    @Q12,Q13 HAVE VERTICAL FILTERED VALUES\n    @CASCADED FILTERING FOR ROW 0\n\n    vext.16       q10, q12, q13, #5     @//extract a[5]                         (column1)\n    vext.16       q11, q12, q13, #2     @//extract a[2]                         (column1)\n    vaddl.s16     q14, d20, d24         @// a0 + a5                             (column1)\n    vaddl.s16     q15, d21, d25         @// a0 + a5                             (column1)\n    vext.16       q9, q12, q13, #1      @//extract a[1]                         (column1)\n    vext.16       q10, q12, q13, #3     @//extract a[3]                         (column1)\n    vext.16       q1, q12, q13, #4      @//extract a[4]                         (column1)\n    vmlal.s16     q14, d22, d0[0]       @// a0 + a5 + 20a2                      (column1)\n    vmlsl.s16     q14, d18, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlal.s16     q14, d20, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column1)\n    vmlsl.s16     q14, d2, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vld1.u32      {d14, d15}, [r0], r2  @ Vector load from src[6_0]\n    vmlal.s16     q15, d23, d0[0]       @// a0 + a5 + 20a2                      (column1)\n    vmlal.s16     q15, d21, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column1)\n    vmlsl.s16     q15, d19, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlsl.s16     q15, d3, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n\n    vaddl.u8      q12, d4, d14          @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q13, d5, d15          @ temp = src[0_0] + src[5_0]\n    vqrshrun.s32  d18, q14, #10\n    vaddl.u8      q14, d9, d11          @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q10, d8, d10          @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q11, d6, d12          @ temp2 = src[1_0] + src4_0]\n    vqrshrun.s32  d19, q15, #10\n    vmla.u16      q12, q10, d0[0]       @ temp += temp1 * 20\n    vmls.s16      q12, q11, d1[0]       @ temp -= temp2 * 5\n    vaddl.u8      q15, d7, d13          @ temp2 = src[1_0] + src4_0]\n    vmla.u16      q13, q14, d0[0]       @ temp += temp1 * 20\n    vmls.s16      q13, q15, d1[0]       @ temp -= temp2 * 5\n    vqmovun.s16   d2, q9\n    @ vERTICAL FILTERING FOR ROW 1\n\n    @Q12,Q13 HAVE VERTICAL FILTERED VALUES\n    @CASCADED FILTERING FOR ROW 1\n    vext.16       q10, q12, q13, #5     @//extract a[5]                         (column1)\n    vext.16       q11, q12, q13, #2     @//extract a[2]                         (column1)\n    vaddl.s16     q14, d20, d24         @// a0 + a5                             (column1)\n    vaddl.s16     q15, d21, d25         @// a0 + a5                             (column1)\n    vst1.u8       {d2}, [r1], r3        @//Store dest row0, column 1; (1/2,1/2)\n    vext.16       q9, q12, q13, #1      @//extract a[1]                         (column1)\n    vext.16       q10, q12, q13, #3     @//extract a[3]                         (column1)\n    vext.16       q2, q12, q13, #4      @//extract a[4]                         (column1)\n    vmlal.s16     q14, d22, d0[0]       @// a0 + a5 + 20a2                      (column1)\n    vmlsl.s16     q14, d18, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlal.s16     q14, d20, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column1)\n    vmlsl.s16     q14, d4, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vmlal.s16     q15, d23, d0[0]       @// a0 + a5 + 20a2                      (column1)\n    vmlal.s16     q15, d21, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column1)\n    vmlsl.s16     q15, d19, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlsl.s16     q15, d5, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vqrshrun.s32  d18, q14, #10\n    vqrshrun.s32  d19, q15, #10\n    vqmovun.s16   d3, q9\n    vst1.u8       {d3}, [r1], r3        @//Store dest row1, column 1; (1/2,1/2)\n\n    subs          r8, r8, #2            @ 2 rows processed, decrement by 2\n    subne         r0, r0 , r2, lsl #2\n    subne         r0, r0, r2\n    beq           end_func              @ Branch if height==4\n\n    b             loop_8                @looping if height == 8 or 16\n\nloop_4:\n    vld1.u32      {d2, d3}, [r0], r2    @ Vector load from src[0_0]\n    vld1.u32      {d4, d5}, [r0], r2    @ Vector load from src[1_0]\n    vld1.u32      {d6, d7}, [r0], r2    @ Vector load from src[2_0]\n    vld1.u32      {d8, d9}, [r0], r2    @ Vector load from src[3_0]\n    vld1.u32      {d10, d11}, [r0], r2  @ Vector load from src[4_0]\n    vld1.u32      {d12, d13}, [r0], r2  @ Vector load from src[5_0]\n\n    @ vERTICAL FILTERING FOR ROW 0\n    vaddl.u8      q10, d6, d8           @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q11, d4, d10          @ temp2 = src[1_0] + src4_0]\n    vaddl.u8      q12, d2, d12          @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q13, d3, d13          @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q14, d7, d9           @ temp1 = src[2_0] + src[3_0]\n    vmla.u16      q12, q10, d0[0]       @ temp += temp1 * 20\n    vmls.s16      q12, q11, d1[0]       @ temp -= temp2 * 5\n    vaddl.u8      q15, d5, d11          @ temp2 = src[1_0] + src4_0]\n    vmla.u16      q13, q14, d0[0]       @ temp += temp1 * 20\n    vmls.s16      q13, q15, d1[0]       @ temp -= temp2 * 5\n    @Q12,Q13 HAVE VERTICAL FILTERED VALUES\n    @CASCADED FILTERING FOR ROW 0\n\n    vext.16       q10, q12, q13, #5     @//extract a[5]                         (column1)\n    vext.16       q11, q12, q13, #2     @//extract a[2]                         (column1)\n    vaddl.s16     q14, d20, d24         @// a0 + a5                             (column1)\n    vaddl.s16     q15, d21, d25         @// a0 + a5                             (column1)\n\n    vext.16       q1, q12, q13, #4      @//extract a[4]                         (column1)\n    vext.16       q9, q12, q13, #1      @//extract a[1]                         (column1)\n    vext.16       q10, q12, q13, #3     @//extract a[3]                         (column1)\n\n    vmlal.s16     q14, d22, d0[0]       @// a0 + a5 + 20a2                      (column1)\n    vmlsl.s16     q14, d18, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlal.s16     q14, d20, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column1)\n    vmlsl.s16     q14, d2, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vld1.u32      {d14, d15}, [r0], r2  @ Vector load from src[6_0]\n    vmlal.s16     q15, d23, d0[0]       @// a0 + a5 + 20a2                      (column1)\n    vmlal.s16     q15, d21, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column1)\n    vmlsl.s16     q15, d19, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlsl.s16     q15, d3, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vaddl.u8      q12, d4, d14          @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q13, d5, d15          @ temp = src[0_0] + src[5_0]\n    vqrshrun.s32  d18, q14, #10\n    vaddl.u8      q14, d9, d11          @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q11, d6, d12          @ temp2 = src[1_0] + src4_0]\n    vaddl.u8      q10, d8, d10          @ temp1 = src[2_0] + src[3_0]\n    vqrshrun.s32  d19, q15, #10\n    vmla.u16      q12, q10, d0[0]       @ temp += temp1 * 20\n    vmls.s16      q12, q11, d1[0]       @ temp -= temp2 * 5\n    vaddl.u8      q15, d7, d13          @ temp2 = src[1_0] + src4_0]\n    vqmovun.s16   d2, q9\n    vmla.u16      q13, q14, d0[0]       @ temp += temp1 * 20\n    vmls.s16      q13, q15, d1[0]       @ temp -= temp2 * 5\n\n    @ vERTICAL FILTERING FOR ROW 1\n\n    @Q12,Q13 HAVE VERTICAL FILTERED VALUES\n    @CASCADED FILTERING FOR ROW 1\n    vext.16       q10, q12, q13, #5     @//extract a[5]                         (column1)\n    vext.16       q11, q12, q13, #2     @//extract a[2]                         (column1)\n    vst1.u32      {d2[0]}, [r1], r3     @//Store dest row0, column 1; (1/2,1/2)\n    vaddl.s16     q14, d20, d24         @// a0 + a5                             (column1)\n    vaddl.s16     q15, d21, d25         @// a0 + a5                             (column1)\n    vext.16       q9, q12, q13, #1      @//extract a[1]                         (column1)\n    vext.16       q10, q12, q13, #3     @//extract a[3]                         (column1)\n    vext.16       q2, q12, q13, #4      @//extract a[4]                         (column1)\n    vmlal.s16     q14, d22, d0[0]       @// a0 + a5 + 20a2                      (column1)\n    vmlsl.s16     q14, d18, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlal.s16     q14, d20, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column1)\n    vmlsl.s16     q14, d4, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vmlal.s16     q15, d23, d0[0]       @// a0 + a5 + 20a2                      (column1)\n    vmlal.s16     q15, d21, d0[0]       @// a0 + a5 + 20a2 + 20a3               (column1)\n    vmlsl.s16     q15, d19, d1[0]       @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1)\n    vmlsl.s16     q15, d5, d1[0]        @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1)\n    vqrshrun.s32  d18, q14, #10\n    vqrshrun.s32  d19, q15, #10\n    vqmovun.s16   d4, q9\n    vst1.u32      {d4[0]}, [r1], r3     @//Store dest row1, column 1; (1/2,1/2)\n\n    subs          r8, r8, #2            @ 2 rows processed, decrement by 2\n    subne         r0, r0 , r2, lsl #2\n    subne         r0, r0, r2\n    beq           end_func              @ Branch if height==4\n\n    b             loop_4                @looping if height == 8 or 16\n\nend_func:\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_luma_horz_hpel_vert_qpel_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_inter_pred_luma_horz_hpel_vert_qpel_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for inter prediction  interpolation.\n@*\n@* @author\n@*  Mohit\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_inter_pred_luma_horz_hpel_vert_qpel_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_inter_pred_filters.c\n@\n\n@**\n@**\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*   This function implements a two stage cascaded six tap filter. It\n@*    applies the six tap filter in the horizontal direction on the\n@*    predictor values, followed by applying the same filter in the\n@*    vertical direction on the output of the first stage. It then averages\n@*    the output of the 1st stage and the output of the 2nd stage to obtain\n@*    the quarter pel values. The six tap filtering operation is described\n@*    in sec 8.4.2.2.1 titled \"Luma sample interpolation process\".\n@*\n@* @par Description:\n@*     This function is called to obtain pixels lying at the following\n@*    location (1/2,1/4) or (1/2,3/4). The function interpolates\n@*    the predictors first in the horizontal direction and then in the\n@*    vertical direction to output the (1/2,1/2). It then averages\n@*    the output of the 2nd stage and (1/2,1/2) value to obtain (1/2,1/4)\n@*    or (1/2,3/4) depending on the offset.\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @param[in] pu1_tmp: temporary buffer\n@*\n@* @param[in] dydx: x and y reference offset for qpel calculations\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*;\n\n@void ih264_inter_pred_luma_horz_hpel_vert_qpel(UWORD8 *pu1_src,\n@                                UWORD8 *pu1_dst,\n@                                WORD32 src_strd,,\n@                                WORD32 dst_strd,\n@                                WORD32 ht,\n@                                WORD32 wd,\n@                                UWORD8* pu1_tmp,\n@                                UWORD32 dydx)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ht\n@   r5 =>  wd\n@   r7 =>  dydx\n@   r9 => *pu1_tmp\n\n.text\n.p2align 2\n\n    .global ih264_inter_pred_luma_horz_hpel_vert_qpel_a9q\n\nih264_inter_pred_luma_horz_hpel_vert_qpel_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @ store register values to stack\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r4, [sp, #104]        @ loads ht\n    sub           r0, r0, r2, lsl #1    @ pu1_src-2*src_strd\n    sub           r0, r0, #2            @ pu1_src-2\n    ldr           r5, [sp, #108]        @ loads wd\n    ldr           r7, [sp, #116]        @ loads dydx\n    lsr           r7, r7, #3            @ dydx >> 2 followed by dydx & 0x3 and dydx>>1 to obtain the deciding bit\n    ldr           r9, [sp, #112]        @ pu1_tmp\n    add           r7, r7, #2\n    mov           r6, #48\n    mla           r7, r7, r6, r9\n\n    subs          r12, r5, #4           @if wd=4 branch to loop_4\n    beq           loop_4_start\n\n    subs          r12, r5, #8           @if wd=8 branch to loop_8\n    beq           loop_8_start\n\n    @when  wd=16\n    vmov.u16      q11, #20              @ Filter coeff 0x14 into Q11\n    vmov.u16      q12, #5               @ Filter coeff 0x5  into Q12\n    add           r8, r0, #8\n    add           r14, r1, #8\n    add           r10, r9, #8\n    mov           r12, r4\n    add           r11, r7, #8\n\nloop_16_lowhalf_start:\n    vld1.32       {q0}, [r0], r2        @ row -2 load for horizontal filter\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q3, d0, d5\n\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q4, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q3, q4, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q4, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row -1 load for horizontal filter\n    vmls.u16      q3, q4, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q4, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q5, d2, d3\n\n    vst1.32       {q3}, [r9], r6        @ store temp buffer 0\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q4, q5, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q5, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row 0 load for horizontal filter\n    vmls.u16      q4, q5, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q5, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q6, d2, d3\n\n    vst1.32       {q4}, [r9], r6        @ store temp buffer 1\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q5, q6, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q6, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row 1 load for horizontal filter\n    vmls.u16      q5, q6, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q6, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q7, d2, d3\n\n    vst1.32       {q5}, [r9], r6        @ store temp buffer 2\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q6, q7, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q7, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row 2 load for horizontal filter\n    vmls.u16      q6, q7, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q7, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q8, d2, d3\n\n    vst1.32       {q6}, [r9], r6        @ store temp buffer 3\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q7, q8, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q8, d1, d4\n\n    vmls.u16      q7, q8, q12\nloop_16_lowhalf:\n\n    vld1.32       {q0}, [r0], r2        @ row 3 load for horizontal filter\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q8, d0, d5\n\n    vst1.32       {q7}, [r9], r6        @ store temp buffer 4\n    vaddl.u8      q9, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q8, q9, q11\n    vext.8        d1, d0, d1, #1\n    vadd.s16      q14, q4, q7\n    vaddl.u8      q9, d1, d4\n    vadd.s16      q15, q5, q6\n    vmls.u16      q8, q9, q12\n    vld1.32       {q0}, [r0], r2        @ row 4 load for hoorizontal filter\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q10, d0, d5\n\n    vst1.32       {q8}, [r9], r6        @ store temp buffer r5\n\n    vaddl.s16     q9, d6, d16\n\n    vld1.32       {q13}, [r7], r6       @ load from temp buffer 0\n\n    vaddl.s16     q3, d7, d17\n\n    vqrshrun.s16  d26, q13, #5\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d28, d24\n    vmlal.s16     q3, d31, d22\n    vmlsl.s16     q3, d29, d24\n    vaddl.u8      q1, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q10, q1, q11\n    vqrshrun.s32  d18, q9, #10\n    vext.8        d1, d0, d1, #1\n    vqrshrun.s32  d19, q3, #10\n    vadd.s16      q14, q5, q8\n    vaddl.u8      q1, d1, d4\n    vadd.s16      q15, q6, q7\n    vmls.u16      q10, q1, q12\n    vqmovn.u16    d18, q9\n    vld1.32       {q0}, [r0], r2        @ row 5 load for horizontal filter\n\n    vrhadd.u8     d26, d18, d26\n\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n\n    vst1.32       {q10}, [r9], r6       @ store temp buffer r6\n\n    vaddl.s16     q9, d8, d20\n\n    vaddl.s16     q3, d9, d21\n\n    vld1.32       {q4}, [r7], r6        @load from temp buffer 1\n\n\n    vst1.32       d26, [r1], r3         @ store row 0\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d28, d24\n\n    vqrshrun.s16  d28, q4, #5\n\n    vmlal.s16     q3, d31, d22\n    vmlsl.s16     q3, d29, d24\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q4, d0, d5\n    vaddl.u8      q1, d2, d3\n    vqrshrun.s32  d18, q9, #10\n    vext.8        d4, d0, d1, #4\n    vqrshrun.s32  d19, q3, #10\n    vmla.u16      q4, q1, q11\n    vext.8        d1, d0, d1, #1\n    vadd.s16      q13, q6, q10\n    vaddl.u8      q1, d1, d4\n    vqmovn.u16    d18, q9\n    vadd.s16      q15, q7, q8\n    vmls.u16      q4, q1, q12\n    vld1.32       {q0}, [r0], r2        @ row 6 load for horizontal filter\n\n    vrhadd.u8     d28, d28, d18\n\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n\n    vst1.32       d28, [r1], r3         @ store row 1\n\n    vaddl.u8      q14, d0, d5\n\n    vst1.32       {q4}, [r9], r6        @ store temp buffer r7\n\n    vaddl.s16     q9, d10, d8\n    vaddl.s16     q3, d11, d9\n\n    vld1.32       {q5}, [r7], r6        @ load from temp buffer 2\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d26, d24\n    vmlal.s16     q3, d31, d22\n\n    vqrshrun.s16  d26, q5, #5\n\n    vmlsl.s16     q3, d27, d24\n    vaddl.u8      q1, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q14, q1, q11\n    vqrshrun.s32  d18, q9, #10\n    vext.8        d1, d0, d1, #1\n    vqrshrun.s32  d19, q3, #10\n    vadd.s16      q5, q7, q4\n    vaddl.u8      q1, d1, d4\n    vadd.s16      q15, q8, q10\n    vmls.u16      q14, q1, q12\n    vqmovn.u16    d27, q9\n\n    vaddl.s16     q9, d12, d28\n    vaddl.s16     q3, d13, d29\n\n    vrhadd.u8     d26, d26, d27\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d10, d24\n    vmlal.s16     q3, d31, d22\n    vmlsl.s16     q3, d11, d24\n\n    vst1.32       d26, [r1], r3         @ store row 2\n\n    vst1.32       {q14}, [r9]\n\n\n    vqrshrun.s32  d18, q9, #10\n    vmov          q5, q10\n    vld1.32       {q15}, [r7], r6       @ load from temp buffer 3\n\n    vqrshrun.s32  d19, q3, #10\n    subs          r4, r4, #4\n\n    vqrshrun.s16  d30, q15, #5\n\n    vqmovn.u16    d18, q9\n    vmov          q6, q4\n    vmov          q3, q7\n    vrhadd.u8     d30, d18, d30\n    vmov          q4, q8\n    vmov          q7, q14\n    vst1.32       d30, [r1], r3         @ store row 3\n\n    bgt           loop_16_lowhalf       @ looping if height =16\n\n\nloop_16_highhalf_start:\n    vld1.32       {q0}, [r8], r2\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q3, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q4, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q3, q4, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q4, d1, d4\n    vld1.32       {q0}, [r8], r2\n    vmls.u16      q3, q4, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q4, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q5, d2, d3\n\n    vst1.32       {q3}, [r10], r6\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q4, q5, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q5, d1, d4\n    vld1.32       {q0}, [r8], r2\n    vmls.u16      q4, q5, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q5, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q6, d2, d3\n\n    vst1.32       {q4}, [r10], r6\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q5, q6, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q6, d1, d4\n    vld1.32       {q0}, [r8], r2\n    vmls.u16      q5, q6, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q6, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q7, d2, d3\n\n    vst1.32       {q5}, [r10], r6\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q6, q7, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q7, d1, d4\n    vld1.32       {q0}, [r8], r2\n    vmls.u16      q6, q7, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q7, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q8, d2, d3\n\n    vst1.32       {q6}, [r10], r6\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q7, q8, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q8, d1, d4\n\n    vmls.u16      q7, q8, q12\n\nloop_16_highhalf:\n\n    vld1.32       {q0}, [r8], r2\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q8, d0, d5\n\n    vst1.32       {q7}, [r10], r6\n\n    vaddl.u8      q9, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q8, q9, q11\n    vext.8        d1, d0, d1, #1\n    vadd.s16      q14, q4, q7\n    vaddl.u8      q9, d1, d4\n    vadd.s16      q15, q5, q6\n    vmls.u16      q8, q9, q12\n    vld1.32       {q0}, [r8], r2\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q10, d0, d5\n\n    vst1.32       {q8}, [r10], r6\n\n    vaddl.s16     q9, d6, d16\n\n    vld1.32       {q13}, [r11], r6\n\n    vaddl.s16     q3, d7, d17\n\n    vqrshrun.s16  d26, q13, #5\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d28, d24\n    vmlal.s16     q3, d31, d22\n    vmlsl.s16     q3, d29, d24\n    vaddl.u8      q1, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q10, q1, q11\n    vqrshrun.s32  d18, q9, #10\n    vext.8        d1, d0, d1, #1\n    vqrshrun.s32  d19, q3, #10\n    vadd.s16      q14, q5, q8\n    vaddl.u8      q1, d1, d4\n    vadd.s16      q15, q6, q7\n    vmls.u16      q10, q1, q12\n    vqmovn.u16    d18, q9\n    vld1.32       {q0}, [r8], r2\n\n    vrhadd.u8     d26, d18, d26\n\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n\n    vst1.32       {q10}, [r10], r6\n\n    vaddl.s16     q9, d8, d20\n    vaddl.s16     q3, d9, d21\n\n    vld1.32       {q4}, [r11], r6\n\n\n    vst1.32       d26, [r14], r3        @store row 0\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d28, d24\n\n    vqrshrun.s16  d28, q4, #5\n\n    vmlal.s16     q3, d31, d22\n    vmlsl.s16     q3, d29, d24\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q4, d0, d5\n    vaddl.u8      q1, d2, d3\n    vqrshrun.s32  d18, q9, #10\n    vext.8        d4, d0, d1, #4\n    vqrshrun.s32  d19, q3, #10\n    vmla.u16      q4, q1, q11\n    vext.8        d1, d0, d1, #1\n    vadd.s16      q13, q6, q10\n    vaddl.u8      q1, d1, d4\n    vqmovn.u16    d18, q9\n    vadd.s16      q15, q7, q8\n    vmls.u16      q4, q1, q12\n    vld1.32       {q0}, [r8], r2\n\n    vrhadd.u8     d28, d28, d18\n\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n\n    vst1.32       d28, [r14], r3        @store row 1\n\n    vaddl.u8      q14, d0, d5\n\n    vst1.32       {q4}, [r10], r6\n\n    vaddl.s16     q9, d10, d8\n    vaddl.s16     q3, d11, d9\n\n    vld1.32       {q5}, [r11], r6\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d26, d24\n    vmlal.s16     q3, d31, d22\n\n    vqrshrun.s16  d26, q5, #5\n\n    vmlsl.s16     q3, d27, d24\n    vaddl.u8      q1, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q14, q1, q11\n    vqrshrun.s32  d18, q9, #10\n    vext.8        d1, d0, d1, #1\n    vqrshrun.s32  d19, q3, #10\n    vadd.s16      q5, q7, q4\n    vaddl.u8      q1, d1, d4\n    vadd.s16      q15, q8, q10\n    vmls.u16      q14, q1, q12\n    vqmovn.u16    d27, q9\n\n\n    vaddl.s16     q9, d12, d28\n    vaddl.s16     q3, d13, d29\n\n    vrhadd.u8     d26, d26, d27\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d10, d24\n    vmlal.s16     q3, d31, d22\n    vmlsl.s16     q3, d11, d24\n\n    vst1.32       d26, [r14], r3        @ store row 2\n\n    vst1.32       {q14}, [r10]\n\n    vqrshrun.s32  d18, q9, #10\n    vmov          q5, q10\n    vld1.32       {q15}, [r11], r6\n\n    vqrshrun.s32  d19, q3, #10\n    subs          r12, r12, #4\n\n    vqrshrun.s16  d30, q15, #5\n\n    vqmovn.u16    d18, q9\n    vmov          q6, q4\n    vmov          q3, q7\n    vrhadd.u8     d30, d18, d30\n    vmov          q4, q8\n    vmov          q7, q14\n    vst1.32       d30, [r14], r3        @ store row 3\n\n    bgt           loop_16_highhalf      @ looping if height = 8 or 16\n    b             end_func\n\nloop_8_start:\n\n    vmov.u16      q11, #20              @ Filter coeff 20 into Q11\n    vmov.u16      q12, #5               @ Filter coeff 5  into Q12\n    vld1.32       {q0}, [r0], r2        @ row -2 load for horizontal filter\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q3, d0, d5\n\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q4, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q3, q4, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q4, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row -1 load for horizontal filter\n    vmls.u16      q3, q4, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q4, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q5, d2, d3\n\n    vst1.32       {q3}, [r9], r6        @ store temp buffer 0\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q4, q5, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q5, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row 0 load for horizontal filter\n    vmls.u16      q4, q5, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q5, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q6, d2, d3\n\n    vst1.32       {q4}, [r9], r6        @ store temp buffer 1\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q5, q6, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q6, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row 1 load for horizontal filter\n    vmls.u16      q5, q6, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q6, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q7, d2, d3\n\n    vst1.32       {q5}, [r9], r6        @ store temp buffer 2\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q6, q7, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q7, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row 2 load for horizontal filter\n    vmls.u16      q6, q7, q12\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q7, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q8, d2, d3\n\n    vst1.32       {q6}, [r9], r6        @ store temp buffer 3\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q7, q8, q11\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q8, d1, d4\n\n    vmls.u16      q7, q8, q12\nloop_8:\n\n    vld1.32       {q0}, [r0], r2        @ row 3 load for horizontal filter\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q8, d0, d5\n\n    vst1.32       {q7}, [r9], r6        @ store temp buffer 4\n\n    vaddl.u8      q9, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q8, q9, q11\n    vext.8        d1, d0, d1, #1\n    vadd.s16      q14, q4, q7\n    vaddl.u8      q9, d1, d4\n    vadd.s16      q15, q5, q6\n    vmls.u16      q8, q9, q12\n    vld1.32       {q0}, [r0], r2        @ row 4 load for hoorizontal filter\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q10, d0, d5\n\n    vst1.32       {q8}, [r9], r6        @ store temp buffer r5\n\n    vaddl.s16     q9, d6, d16\n\n    vld1.32       {q13}, [r7], r6       @ load from temp buffer 0\n\n    vaddl.s16     q3, d7, d17\n\n    vqrshrun.s16  d26, q13, #5\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d28, d24\n    vmlal.s16     q3, d31, d22\n    vmlsl.s16     q3, d29, d24\n    vaddl.u8      q1, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q10, q1, q11\n    vqrshrun.s32  d18, q9, #10\n    vext.8        d1, d0, d1, #1\n    vqrshrun.s32  d19, q3, #10\n    vadd.s16      q14, q5, q8\n    vaddl.u8      q1, d1, d4\n    vadd.s16      q15, q6, q7\n    vmls.u16      q10, q1, q12\n    vqmovn.u16    d18, q9\n    vld1.32       {q0}, [r0], r2        @ row 5 load for horizontal filter\n\n    vrhadd.u8     d26, d18, d26\n\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n\n    vst1.32       {q10}, [r9], r6       @ store temp buffer r6\n\n    vaddl.s16     q9, d8, d20\n\n    vaddl.s16     q3, d9, d21\n\n    vld1.32       {q4}, [r7], r6        @load from temp buffer 1\n\n\n    vst1.32       d26, [r1], r3         @ store row 0\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d28, d24\n\n    vqrshrun.s16  d28, q4, #5\n\n    vmlal.s16     q3, d31, d22\n    vmlsl.s16     q3, d29, d24\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q4, d0, d5\n    vaddl.u8      q1, d2, d3\n    vqrshrun.s32  d18, q9, #10\n    vext.8        d4, d0, d1, #4\n    vqrshrun.s32  d19, q3, #10\n    vmla.u16      q4, q1, q11\n    vext.8        d1, d0, d1, #1\n    vadd.s16      q13, q6, q10\n    vaddl.u8      q1, d1, d4\n    vqmovn.u16    d18, q9\n    vadd.s16      q15, q7, q8\n    vmls.u16      q4, q1, q12\n    vld1.32       {q0}, [r0], r2        @ row 6 load for horizontal filter\n\n    vrhadd.u8     d28, d28, d18\n\n    vext.8        d5, d0, d1, #5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n\n    vst1.32       d28, [r1], r3         @ store row 1\n\n    vaddl.u8      q14, d0, d5\n\n    vst1.32       {q4}, [r9], r6        @ store temp buffer r7\n\n    vaddl.s16     q9, d10, d8\n    vaddl.s16     q3, d11, d9\n\n    vld1.32       {q5}, [r7], r6        @ load from temp buffer 2\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d26, d24\n    vmlal.s16     q3, d31, d22\n\n    vqrshrun.s16  d26, q5, #5\n\n    vmlsl.s16     q3, d27, d24\n    vaddl.u8      q1, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      q14, q1, q11\n    vqrshrun.s32  d18, q9, #10\n    vext.8        d1, d0, d1, #1\n    vqrshrun.s32  d19, q3, #10\n    vadd.s16      q5, q7, q4\n    vaddl.u8      q1, d1, d4\n    vadd.s16      q15, q8, q10\n    vmls.u16      q14, q1, q12\n    vqmovn.u16    d27, q9\n\n    vaddl.s16     q9, d12, d28\n    vaddl.s16     q3, d13, d29\n\n    vrhadd.u8     d26, d26, d27\n\n    vmlal.s16     q9, d30, d22\n    vmlsl.s16     q9, d10, d24\n    vmlal.s16     q3, d31, d22\n    vmlsl.s16     q3, d11, d24\n\n    vst1.32       d26, [r1], r3         @ store row 2\n\n    vst1.32       {q14}, [r9]\n\n\n    vqrshrun.s32  d18, q9, #10\n    vmov          q5, q10\n    vld1.32       {q15}, [r7], r6       @ load from temp buffer 3\n\n    vqrshrun.s32  d19, q3, #10\n    subs          r4, r4, #4\n\n    vqrshrun.s16  d30, q15, #5\n\n    vqmovn.u16    d18, q9\n    vmov          q6, q4\n    vmov          q3, q7\n    vrhadd.u8     d30, d18, d30\n    vmov          q4, q8\n    vmov          q7, q14\n    vst1.32       d30, [r1], r3         @ store row 3\n\n    bgt           loop_8                @if height =8 or 16  loop\n    b             end_func\n\nloop_4_start:\n    vmov.u16      d22, #20              @ Filter coeff 20 into D22\n    vmov.u16      d23, #5               @ Filter coeff 5  into D23\n\n    vld1.32       {q0}, [r0], r2        @row -2 load\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q3, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q4, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      d6, d8, d22\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q4, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row -1 load\n    vmls.u16      d6, d8, d23\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q4, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q5, d2, d3\n\n    vst1.32       d6, [r9], r6          @ store temp buffer 0\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      d8, d10, d22\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q5, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row 0 load\n    vmls.u16      d8, d10, d23\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q5, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q6, d2, d3\n\n    vst1.32       d8, [r9], r6          @ store temp buffer 1\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      d10, d12, d22\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q6, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row 1 load\n    vmls.u16      d10, d12, d23\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q6, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q7, d2, d3\n\n    vst1.32       d10, [r9], r6         @ store temp buffer 2\n\n    vext.8        d4, d0, d1, #4\n    vmla.u16      d12, d14, d22\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q7, d1, d4\n    vld1.32       {q0}, [r0], r2        @ row 2 load\n    vmls.u16      d12, d14, d23\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q7, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q8, d2, d3\n    vext.8        d4, d0, d1, #4\n    vmla.u16      d14, d16, d22\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q8, d1, d4\n\n    vst1.32       d12, [r9], r6         @ store temp buffer 3\n\n    vmls.u16      d14, d16, d23\n\nloop_4:\n\n    vld1.32       {q0}, [r0], r2        @ row 3 load\n    vext.8        d5, d0, d1, #5\n    vaddl.u8      q8, d0, d5\n    vext.8        d2, d0, d1, #2\n    vext.8        d3, d0, d1, #3\n    vaddl.u8      q9, d2, d3\n    vst1.32       d14, [r9], r6         @ store temp buffer 4\n    vext.8        d4, d0, d1, #4\n    vmla.u16      d16, d18, d22\n    vext.8        d1, d0, d1, #1\n    vaddl.u8      q9, d1, d4\n    vadd.s16      d2, d10, d12\n    vmls.u16      d16, d18, d23\n    vadd.s16      d3, d8, d14\n    vld1.32       {q9}, [r0], r2        @ row 4 load\n    vext.8        d25, d18, d19, #5\n    vaddl.u8      q13, d18, d25\n    vext.8        d20, d18, d19, #2\n\n    vst1.32       d16, [r9], r6         @ store temp buffer 5\n\n    vaddl.s16     q0, d6, d16\n    vmlal.s16     q0, d2, d22\n    vext.8        d21, d18, d19, #3\n    vaddl.u8      q14, d20, d21\n    vext.8        d24, d18, d19, #4\n    vmlsl.s16     q0, d3, d23\n    vmla.u16      d26, d28, d22\n    vext.8        d19, d18, d19, #1\n    vaddl.u8      q14, d19, d24\n    vadd.s16      d2, d12, d14\n    vmls.u16      d26, d28, d23\n    vqrshrun.s32  d0, q0, #0xa\n    vadd.s16      d3, d10, d16\n    vld1.32       {q9}, [r0], r2        @ row 5 load\n    vext.8        d25, d18, d19, #5\n    vqmovn.u16    d11, q0\n    vaddl.u8      q14, d18, d25\n\n    vst1.32       d26, [r9], r6         @ store temp buffer 6\n\n    @Q3 available here\n    vld1.32       d6, [r7], r6          @ load from temp buffer 0\n    vld1.32       d7, [r7], r6          @ load from temp buffer 1\n    vqrshrun.s16  d9, q3, #5\n\n    vext.8        d20, d18, d19, #2\n\n    vaddl.s16     q0, d8, d26\n    vmlal.s16     q0, d2, d22\n    vext.8        d21, d18, d19, #3\n    vaddl.u8      q3, d20, d21\n    vext.8        d24, d18, d19, #4\n    vmlsl.s16     q0, d3, d23\n    vmla.u16      d28, d6, d22\n    vext.8        d19, d18, d19, #1\n    vaddl.u8      q3, d19, d24\n    vadd.s16      d2, d14, d16\n    vmls.u16      d28, d6, d23\n    vqrshrun.s32  d0, q0, #0xa\n    vadd.s16      d3, d12, d26\n    vld1.32       {q9}, [r0], r2        @ row 6 load\n    vext.8        d25, d18, d19, #5\n    vqmovn.u16    d13, q0\n\n    vtrn.32       d11, d13\n    vaddl.s16     q0, d10, d28\n    vrhadd.u8     d9, d9, d11\n\n    vst1.32       d28, [r9], r6         @ store temp buffer 7\n\n    vmlal.s16     q0, d2, d22\n    vaddl.u8      q15, d18, d25\n\n    vst1.32       d9[0], [r1], r3       @ store row 0\n\n    vext.8        d20, d18, d19, #2\n\n    vst1.32       d9[1], [r1], r3       @ store row 1\n\n    vext.8        d21, d18, d19, #3\n    vmlsl.s16     q0, d3, d23\n    vaddl.u8      q4, d20, d21\n    vext.8        d24, d18, d19, #4\n    vmla.u16      d30, d8, d22\n    vext.8        d19, d18, d19, #1\n    vaddl.u8      q4, d19, d24\n    vqrshrun.s32  d0, q0, #0xa\n    vadd.s16      d2, d16, d26\n    vmls.u16      d30, d8, d23\n    vqmovn.u16    d4, q0\n\n    vadd.s16      d3, d14, d28\n\n\n    vaddl.s16     q0, d12, d30\n\n    vst1.32       d30, [r9]\n\n    vmlal.s16     q0, d2, d22\n\n    vld1.32       d8, [r7], r6          @ load from temp buffer 2\n    vld1.32       d9, [r7], r6          @ load from temp buffer 3\n    vmlsl.s16     q0, d3, d23\n    subs          r4, r4, #4\n    vqrshrun.s16  d10, q4, #5\n\n    vmov          d12, d28\n\n    vqrshrun.s32  d0, q0, #0xa\n    vmov          d6, d14\n    vmov          d8, d16\n\n    vqmovn.u16    d5, q0\n\n    vtrn.32       d4, d5\n    vrhadd.u8     d4, d4, d10\n    vmov          d10, d26\n    vmov          d14, d30\n\n    vst1.32       d4[0], [r1], r3       @ store row 2\n    vst1.32       d4[1], [r1], r3       @ store row 3\n\n    bgt           loop_4\n\nend_func:\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_luma_horz_qpel_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_inter_pred_luma_horz_qpel_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for inter prediction horizontal quarter pel interpolation.\n@*\n@* @author\n@*  Mohit\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_inter_pred_luma_horz_qpel_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_inter_pred_filters.c\n@\n\n@**\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*     Quarter pel interprediction luma filter for horizontal input\n@*\n@* @par Description:\n@* Applies a 6 tap horizontal filter .The output is  clipped to 8 bits\n@* sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@ @param[in] pu1_tmp: temporary buffer: UNUSED in this function\n@*\n@* @param[in] dydx: x and y reference offset for qpel calculations.\n@* @returns\n@*\n@ @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@void ih264_inter_pred_luma_horz (\n@                            UWORD8 *pu1_src,\n@                            UWORD8 *pu1_dst,\n@                            WORD32 src_strd,\n@                            WORD32 dst_strd,\n@                            WORD32 ht,\n@                            WORD32 wd,\n@                            UWORD8* pu1_tmp,\n@                            UWORD32 dydx)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r5 =>  ht\n@   r6 =>  wd\n@   r7 =>  dydx\n\n.text\n.p2align 2\n\n\n    .global ih264_inter_pred_luma_horz_qpel_a9q\n\nih264_inter_pred_luma_horz_qpel_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r5, [sp, #104]        @Loads ht\n    ldr           r6, [sp, #108]        @Loads wd\n    ldr           r7, [sp, #116]        @Loads dydx\n    and           r7, r7, #3            @Finds x-offset\n    add           r7, r0, r7, lsr #1    @pu1_src + (x_offset>>1)\n    sub           r0, r0, #2            @pu1_src-2\n    vmov.i8       d0, #5                @filter coeff\n    subs          r12, r6, #8           @if wd=8 branch to loop_8\n    vmov.i8       d1, #20               @filter coeff\n\n    beq           loop_8\n\n    subs          r12, r6, #4           @if wd=4 branch to loop_4\n    beq           loop_4\n\nloop_16:                                @when  wd=16\n    @ Processing row0 and row1\n    vld1.8        {d2, d3, d4}, [r0], r2 @// Load row0\n    vext.8        d31, d2, d3, #5       @//extract a[5]                         (column1,row0)\n    vld1.8        {d5, d6, d7}, [r0], r2 @// Load row1\n    vext.8        d30, d3, d4, #5       @//extract a[5]                         (column2,row0)\n    vaddl.u8      q4, d31, d2           @// a0 + a5                             (column1,row0)\n    vext.8        d28, d5, d6, #5       @//extract a[5]                         (column1,row1)\n    vaddl.u8      q5, d30, d3           @// a0 + a5                             (column2,row0)\n    vext.8        d27, d6, d7, #5       @//extract a[5]                         (column2,row1)\n    vaddl.u8      q7, d28, d5           @// a0 + a5                             (column1,row1)\n    vext.8        d31, d2, d3, #2       @//extract a[2]                         (column1,row0)\n    vaddl.u8      q8, d27, d6           @// a0 + a5                             (column2,row1)\n    vext.8        d30, d3, d4, #2       @//extract a[2]                         (column2,row0)\n    vmlal.u8      q4, d31, d1           @// a0 + a5 + 20a2                      (column1,row0)\n    vext.8        d28, d5, d6, #2       @//extract a[2]                         (column1,row1)\n    vmlal.u8      q5, d30, d1           @// a0 + a5 + 20a2                      (column2,row0)\n    vext.8        d27, d6, d7, #2       @//extract a[2]                         (column2,row1)\n    vmlal.u8      q7, d28, d1           @// a0 + a5 + 20a2                      (column1,row1)\n    vext.8        d31, d2, d3, #3       @//extract a[3]                         (column1,row0)\n    vmlal.u8      q8, d27, d1           @// a0 + a5 + 20a2                      (column2,row1)\n    vext.8        d30, d3, d4, #3       @//extract a[3]                         (column2,row0)\n    vmlal.u8      q4, d31, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row0)\n    vext.8        d28, d5, d6, #3       @//extract a[3]                         (column1,row1)\n    vmlal.u8      q5, d30, d1           @// a0 + a5 + 20a2 + 20a3               (column2,row0)\n    vext.8        d27, d6, d7, #3       @//extract a[3]                         (column2,row1)\n    vmlal.u8      q7, d28, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row1)\n    vext.8        d31, d2, d3, #1       @//extract a[1]                         (column1,row0)\n    vmlal.u8      q8, d27, d1           @// a0 + a5 + 20a2 + 20a3               (column2,row1)\n    vext.8        d30, d3, d4, #1       @//extract a[1]                         (column2,row0)\n    vmlsl.u8      q4, d31, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row0)\n    vext.8        d28, d5, d6, #1       @//extract a[1]                         (column1,row1)\n    vmlsl.u8      q5, d30, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column2,row0)\n    vext.8        d27, d6, d7, #1       @//extract a[1]                         (column2,row1)\n    vmlsl.u8      q7, d28, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row1)\n    vext.8        d31, d2, d3, #4       @//extract a[4]                         (column1,row0)\n    vmlsl.u8      q8, d27, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column2,row1)\n    vext.8        d30, d3, d4, #4       @//extract a[4]                         (column2,row0)\n    vmlsl.u8      q4, d31, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row0)\n    vext.8        d28, d5, d6, #4       @//extract a[4]                         (column1,row1)\n    vmlsl.u8      q5, d30, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column2,row0)\n    vext.8        d27, d6, d7, #4       @//extract a[4]                         (column2,row1)\n    vmlsl.u8      q7, d28, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row1)\n    vmlsl.u8      q8, d27, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column2,row1)\n    vld1.32       {d12, d13}, [r7], r2  @Load value for interpolation           (column1,row0)\n    vqrshrun.s16  d20, q4, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row0)\n    vqrshrun.s16  d21, q5, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column2,row0)\n    vext.8        d31, d2, d3, #5       @//extract a[5]                         (column1,row2)\n    vrhadd.u8     q10, q6, q10          @Interpolation step for qpel calculation\n    vqrshrun.s16  d18, q7, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row1)\n    vst1.8        {d20, d21}, [r1], r3  @//Store dest row0\n    vext.8        d30, d3, d4, #5       @//extract a[5]                         (column2,row2)\n    vqrshrun.s16  d19, q8, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column2,row1)\n    vld1.32       {d12, d13}, [r7], r2  @Load value for interpolation           (column1,row1)\n    vrhadd.u8     q9, q6, q9            @Interpolation step for qpel calculation\n    vst1.8        {d18, d19}, [r1], r3  @//Store dest row1\n    subs          r5, r5, #2            @ 2 rows done, decrement by 2\n\n    beq           end_func\n    b             loop_16\n\nloop_8:\n@ Processing row0 and row1\n\n    vld1.8        {d5, d6}, [r0], r2    @// Load row1\n    vext.8        d28, d5, d6, #5       @//extract a[5]                         (column1,row1)\n    vld1.8        {d2, d3}, [r0], r2    @// Load row0\n    vext.8        d25, d5, d6, #2       @//extract a[2]                         (column1,row1)\n    vext.8        d31, d2, d3, #5       @//extract a[5]                         (column1,row0)\n    vext.8        d24, d5, d6, #3       @//extract a[3]                         (column1,row1)\n    vext.8        d23, d5, d6, #1       @//extract a[1]                         (column1,row1)\n    vext.8        d22, d5, d6, #4       @//extract a[4]                         (column1,row1)\n    vaddl.u8      q7, d28, d5           @// a0 + a5                             (column1,row1)\n    vext.8        d29, d2, d3, #3       @//extract a[3]                         (column1,row0)\n    vmlal.u8      q7, d25, d1           @// a0 + a5 + 20a2                      (column1,row1)\n    vmlal.u8      q7, d24, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row1)\n    vmlsl.u8      q7, d23, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row1)\n    vmlsl.u8      q7, d22, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row1)\n    vext.8        d30, d2, d3, #2       @//extract a[2]                         (column1,row0)\n    vaddl.u8      q4, d31, d2           @// a0 + a5                             (column1,row0)\n    vext.8        d27, d2, d3, #1       @//extract a[1]                         (column1,row0)\n    vext.8        d26, d2, d3, #4       @//extract a[4]                         (column1,row0)\n    vmlal.u8      q4, d29, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row0)\n    vmlal.u8      q4, d30, d1           @// a0 + a5 + 20a2                      (column1,row0)\n    vmlsl.u8      q4, d27, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row0)\n    vmlsl.u8      q4, d26, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row0)\n    vqrshrun.s16  d18, q7, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row0)\n    vld1.32       d12, [r7], r2         @Load value for interpolation           (column1,row0)\n    vld1.32       d13, [r7], r2         @Load value for interpolation           (column1,row1)\n    vqrshrun.s16  d19, q4, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row1)\n    vrhadd.u8     q9, q6, q9            @Interpolation step for qpel calculation\n    vst1.8        {d18}, [r1], r3       @//Store dest row0\n    vst1.8        {d19}, [r1], r3       @//Store dest row1\n    subs          r5, r5, #2            @ 2 rows done, decrement by 2\n\n    beq           end_func              @ Branch if height==4\n    b             loop_8                @looping if height == 8 or 16\n\nloop_4:\n    vld1.8        {d5, d6}, [r0], r2    @// Load row1\n    vext.8        d28, d5, d6, #5       @//extract a[5]                         (column1,row1)\n    vld1.8        {d2, d3}, [r0], r2    @// Load row0\n    vext.8        d25, d5, d6, #2       @//extract a[2]                         (column1,row1)\n    vext.8        d31, d2, d3, #5       @//extract a[5]                         (column1,row0)\n    vaddl.u8      q7, d28, d5           @// a0 + a5                             (column1,row1)\n    vext.8        d24, d5, d6, #3       @//extract a[3]                         (column1,row1)\n    vext.8        d23, d5, d6, #1       @//extract a[1]                         (column1,row1)\n    vext.8        d22, d5, d6, #4       @//extract a[4]                         (column1,row1)\n    vext.8        d29, d2, d3, #3       @//extract a[3]                         (column1,row0)\n    vmlal.u8      q7, d25, d1           @// a0 + a5 + 20a2                      (column1,row1)\n    vmlal.u8      q7, d24, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row1)\n    vmlsl.u8      q7, d23, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row1)\n    vmlsl.u8      q7, d22, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row1)\n    vaddl.u8      q4, d31, d2           @// a0 + a5                             (column1,row0)\n    vext.8        d30, d2, d3, #2       @//extract a[2]                         (column1,row0)\n    vld1.32       d12, [r7], r2         @Load value for interpolation           (column1,row0)\n    vld1.32       d13, [r7], r2         @Load value for interpolation           (column1,row1)\n    vext.8        d27, d2, d3, #1       @//extract a[1]                         (column1,row0)\n    vext.8        d26, d2, d3, #4       @//extract a[4]                         (column1,row0)\n    vmlal.u8      q4, d29, d1           @// a0 + a5 + 20a2 + 20a3               (column1,row0)\n    vmlal.u8      q4, d30, d1           @// a0 + a5 + 20a2                      (column1,row0)\n    vmlsl.u8      q4, d27, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1         (column1,row0)\n    vmlsl.u8      q4, d26, d0           @// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4   (column1,row0)\n    vqrshrun.s16  d18, q7, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row0)\n    vqrshrun.s16  d19, q4, #5           @// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5   (column1,row1)\n    vrhadd.u8     q9, q6, q9            @Interpolation step for qpel calculation\n    vst1.32       d18[0], [r1], r3      @//Store dest row0\n    vst1.32       d19[0], [r1], r3      @//Store dest row1\n\n    subs          r5, r5, #2            @ 2 rows done, decrement by 2\n    beq           end_func\n\n    b             loop_4\n\nend_func:\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_luma_horz_qpel_vert_hpel_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_inter_pred_luma_horz_qpel_vert_hpel_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for inter prediction  interpolation.\n@*\n@* @author\n@*  Mohit\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_inter_pred_luma_horz_qpel_vert_hpel_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_inter_pred_filters.c\n@\n\n@**\n@**\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*   This function implements a two stage cascaded six tap filter. It\n@*   applies the six tap filter in the vertical direction on the\n@*   predictor values, followed by applying the same filter in the\n@*   horizontal direction on the output of the first stage. It then averages\n@*   the output of the 1st stage and the final stage to obtain the quarter\n@*   pel values.The six tap filtering operation is described in sec 8.4.2.2.1\n@*   titled \"Luma sample interpolation process\".\n@*\n@* @par Description:\n@*    This function is called to obtain pixels lying at the following\n@*    location (1/4,1/2) or (3/4,1/2). The function interpolates\n@*    the predictors first in the verical direction and then in the\n@*    horizontal direction to output the (1/2,1/2). It then averages\n@*    the output of the 2nd stage and (1/2,1/2) value to obtain (1/4,1/2)\n@*    or (3/4,1/2) depending on the offset.\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @param[in] pu1_tmp: temporary buffer\n@*\n@* @param[in] dydx: x and y reference offset for qpel calculations\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*;\n\n@void ih264_inter_pred_luma_horz_qpel_vert_hpel(UWORD8 *pu1_src,\n@                                UWORD8 *pu1_dst,\n@                                WORD32 src_strd,,\n@                                WORD32 dst_strd,\n@                                WORD32 ht,\n@                                WORD32 wd,\n@                                UWORD8* pu1_tmp,\n@                                UWORD32 dydx)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ht\n@   r5 =>  wd\n@   r6 =>  dydx\n@   r9 => *pu1_tmp\n\n.text\n.p2align 2\n\n    .global ih264_inter_pred_luma_horz_qpel_vert_hpel_a9q\n\nih264_inter_pred_luma_horz_qpel_vert_hpel_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r4, [sp, #104]        @ loads ht\n    sub           r0, r0, r2, lsl #1    @pu1_src-2*src_strd\n    sub           r0, r0, #2            @pu1_src-2\n    ldr           r5, [sp, #108]        @ loads wd\n    ldr           r6, [sp, #116]        @ loads dydx\n    and           r6, r6, #2            @ dydx & 0x3 followed by dydx>>1 and dydx<<1\n    ldr           r9, [sp, #112]        @pu1_tmp\n    add           r7, r9, #4\n    add           r6, r7, r6            @ pi16_pred1_temp += (x_offset>>1)\n\n    vmov.u16      q13, #0x14            @ Filter coeff 20 into Q13\n    vmov.u16      q12, #0x5             @ Filter coeff 5  into Q12\n    mov           r7, #0x20\n    mov           r8, #0x30\n    subs          r12, r5, #4           @if wd=4 branch to loop_4\n    beq           loop_4\n\n    subs          r12, r5, #8           @if wd=8 branch to loop_8\n    beq           loop_8\n\n    @when  wd=16\n    vmov.u16      q14, #0x14            @ Filter coeff 20 into Q13\n    vmov.u16      q15, #0x5             @ Filter coeff 5  into Q12\n    add           r14, r2, #0\n    sub           r2, r2, #16\n\n\nloop_16:\n\n    vld1.u32      {q0}, [r0]!           @ Vector load from src[0_0]\n    vld1.u32      d12, [r0], r2         @ Vector load from src[0_0]\n    vld1.u32      {q1}, [r0]!           @ Vector load from src[1_0]\n    vld1.u32      d13, [r0], r2         @ Vector load from src[1_0]\n    vld1.u32      {q2}, [r0]!           @ Vector load from src[2_0]\n    vld1.u32      d14, [r0], r2         @ Vector load from src[2_0]\n    vld1.u32      {q3}, [r0]!           @ Vector load from src[3_0]\n    vld1.u32      d15, [r0], r2         @ Vector load from src[3_0]\n    vld1.u32      {q4}, [r0]!           @ Vector load from src[4_0]\n    vld1.u32      d16, [r0], r2         @ Vector load from src[4_0]\n\n    vld1.u32      {q5}, [r0]!           @ Vector load from src[5_0]\n    vld1.u32      d17, [r0], r2         @ Vector load from src[5_0]\n\n    vaddl.u8      q10, d4, d6\n    vaddl.u8      q9, d0, d10\n    vaddl.u8      q11, d2, d8\n    vmla.u16      q9, q10, q14\n    vaddl.u8      q12, d5, d7\n    vaddl.u8      q10, d1, d11\n    vaddl.u8      q13, d3, d9\n    vmla.u16      q10, q12, q14\n    vaddl.u8      q12, d14, d15\n    vmls.u16      q9, q11, q15\n    vaddl.u8      q11, d12, d17\n    vmls.u16      q10, q13, q15\n    vaddl.u8      q13, d13, d16\n    vmla.u16      q11, q12, q14\n    vmls.u16      q11, q13, q15\n    vst1.32       {q9}, [r9]!\n    vst1.32       {q10}, [r9]!\n    vext.16       q12, q9, q10, #2\n    vext.16       q13, q9, q10, #3\n    vst1.32       {q11}, [r9]\n    vext.16       q11, q9, q10, #5\n    vadd.s16      q0, q12, q13\n    vext.16       q12, q9, q10, #1\n    vext.16       q13, q9, q10, #4\n    vadd.s16      q12, q12, q13\n\n    vaddl.s16     q13, d18, d22\n    vmlal.s16     q13, d0, d28\n    vmlsl.s16     q13, d24, d30\n\n    vaddl.s16     q11, d19, d23\n    vmlal.s16     q11, d1, d28\n    vmlsl.s16     q11, d25, d30\n\n    vqrshrun.s32  d18, q13, #10\n    vqrshrun.s32  d19, q11, #10\n    vld1.32       {q11}, [r9]!\n    vqmovn.u16    d18, q9\n\n    vext.16       q12, q10, q11, #2\n    vext.16       q13, q10, q11, #3\n    vext.16       q0, q10, q11, #5\n    vst1.32       d18, [r1]\n    vadd.s16      q9, q12, q13\n    vext.16       q12, q10, q11, #1\n    vext.16       q13, q10, q11, #4\n    vadd.s16      q12, q12, q13\n\n    vaddl.s16     q13, d0, d20\n    vmlal.s16     q13, d18, d28\n    vmlsl.s16     q13, d24, d30\n\n    vaddl.s16     q11, d1, d21\n    vmlal.s16     q11, d19, d28\n    vmlsl.s16     q11, d25, d30\n\n    vqrshrun.s32  d18, q13, #10\n    vqrshrun.s32  d19, q11, #10\n\n    vaddl.u8      q12, d7, d9\n    vld1.32       {q10}, [r6]!\n    vld1.32       {q11}, [r6], r7\n\n    vqmovn.u16    d19, q9\n\n    vld1.32       d18, [r1]\n    vqrshrun.s16  d20, q10, #5\n    vqrshrun.s16  d21, q11, #5\n    vaddl.u8      q11, d4, d10\n    vld1.u32      {q0}, [r0]!           @ Vector load from src[6_0]\n    vrhadd.u8     q9, q9, q10\n    vld1.u32      d12, [r0], r2         @ Vector load from src[6_0]\n    vaddl.u8      q10, d6, d8\n    vaddl.u8      q13, d5, d11\n    vst1.32       {q9}, [r1], r3        @ store row 0\n\n@ROW_2\n\n    vaddl.u8      q9, d2, d0\n\n    vmla.u16      q9, q10, q14\n\n    vaddl.u8      q10, d3, d1\n\n    vmla.u16      q10, q12, q14\n    vaddl.u8      q12, d15, d16\n    vmls.u16      q9, q11, q15\n    vaddl.u8      q11, d13, d12\n    vmls.u16      q10, q13, q15\n    vaddl.u8      q13, d14, d17\n    vmla.u16      q11, q12, q14\n    vmls.u16      q11, q13, q15\n    vst1.32       {q9}, [r9]!\n    vst1.32       {q10}, [r9]!\n    vext.16       q12, q9, q10, #2\n    vext.16       q13, q9, q10, #3\n    vst1.32       {q11}, [r9]\n    vext.16       q11, q9, q10, #5\n    vadd.s16      q1, q12, q13\n    vext.16       q12, q9, q10, #1\n    vext.16       q13, q9, q10, #4\n    vadd.s16      q12, q12, q13\n\n    vaddl.s16     q13, d18, d22\n    vmlal.s16     q13, d2, d28\n    vmlsl.s16     q13, d24, d30\n\n    vaddl.s16     q11, d19, d23\n    vmlal.s16     q11, d3, d28\n    vmlsl.s16     q11, d25, d30\n\n    vqrshrun.s32  d18, q13, #10\n    vqrshrun.s32  d19, q11, #10\n    vld1.32       {q11}, [r9]!\n    vqmovn.u16    d18, q9\n\n    vext.16       q12, q10, q11, #2\n    vext.16       q13, q10, q11, #3\n    vext.16       q1, q10, q11, #5\n    vst1.32       d18, [r1]\n    vadd.s16      q9, q12, q13\n    vext.16       q12, q10, q11, #1\n    vext.16       q13, q10, q11, #4\n    vadd.s16      q12, q12, q13\n\n    vaddl.s16     q13, d2, d20\n    vmlal.s16     q13, d18, d28\n    vmlsl.s16     q13, d24, d30\n\n    vaddl.s16     q11, d3, d21\n    vmlal.s16     q11, d19, d28\n    vmlsl.s16     q11, d25, d30\n\n    vqrshrun.s32  d18, q13, #10\n    vqrshrun.s32  d19, q11, #10\n    vaddl.u8      q12, d9, d11\n    vld1.32       {q10}, [r6]!\n    vld1.32       {q11}, [r6], r7\n    vqmovn.u16    d19, q9\n    vld1.32       d18, [r1]\n    vqrshrun.s16  d20, q10, #5\n    vqrshrun.s16  d21, q11, #5\n\n    vrhadd.u8     q9, q9, q10\n\n    vst1.32       {q9}, [r1], r3        @ store row 1\n\n    subs          r4, r4, #2\n    subne         r0, r0 , r14, lsl #2\n    subne         r0, r0, r14\n\n    beq           end_func              @ Branch if height==4\n    b             loop_16               @ Loop if height==8\n\nloop_8:\n    vld1.u32      {q0}, [r0], r2        @ Vector load from src[0_0]\n    vld1.u32      {q1}, [r0], r2        @ Vector load from src[1_0]\n    vld1.u32      {q2}, [r0], r2        @ Vector load from src[2_0]\n    vld1.u32      {q3}, [r0], r2        @ Vector load from src[3_0]\n    vld1.u32      {q4}, [r0], r2        @ Vector load from src[4_0]\n\n    vld1.u32      {q5}, [r0], r2        @ Vector load from src[5_0]\n    vaddl.u8      q7, d4, d6\n    vaddl.u8      q6, d0, d10\n    vaddl.u8      q8, d2, d8\n    vmla.u16      q6, q7, q13\n    vaddl.u8      q9, d5, d7\n    vaddl.u8      q7, d1, d11\n    vaddl.u8      q11, d3, d9\n    vmla.u16      q7, q9, q13\n    vmls.u16      q6, q8, q12\n    vld1.32       {q0}, [r0], r2        @ Vector load from src[6_0]\n    vaddl.u8      q8, d6, d8\n    vmls.u16      q7, q11, q12\n    vaddl.u8      q14, d2, d0\n    vst1.32       {q6}, [r9]!           @ store row 0 to temp buffer: col 0\n    vext.16       q11, q6, q7, #5\n    vaddl.u8      q9, d4, d10\n    vmla.u16      q14, q8, q13\n    vaddl.s16     q15, d12, d22\n    vst1.32       {q7}, [r9], r7        @ store row 0 to temp buffer: col 1\n    vaddl.s16     q11, d13, d23\n    vext.16       q8, q6, q7, #2\n    vmls.u16      q14, q9, q12\n    vext.16       q9, q6, q7, #3\n    vext.16       q10, q6, q7, #4\n    vext.16       q7, q6, q7, #1\n    vadd.s16      q8, q8, q9\n    vadd.s16      q9, q7, q10\n    vaddl.u8      q10, d7, d9\n    vmlal.s16     q15, d16, d26\n    vmlsl.s16     q15, d18, d24\n    vmlal.s16     q11, d17, d26\n    vmlsl.s16     q11, d19, d24\n    vaddl.u8      q7, d3, d1\n    vst1.32       {q14}, [r9]!          @ store row 1 to temp buffer: col 0\n    vmla.u16      q7, q10, q13\n    vqrshrun.s32  d12, q15, #10\n    vaddl.u8      q8, d5, d11\n    vqrshrun.s32  d13, q11, #10\n    vmls.u16      q7, q8, q12\n@   vld1.32     {q1},[r0],r2            ; Vector load from src[7_0]\n    vqmovn.u16    d25, q6\n    vaddl.u8      q8, d8, d10\n\n\n    vext.16       q11, q14, q7, #5\n    vaddl.u8      q10, d4, d2\n    vaddl.s16     q15, d28, d22\n    vmla.u16      q10, q8, q13\n    vst1.32       {q7}, [r9], r7        @ store row 1 to temp buffer: col 1\n    vaddl.s16     q11, d29, d23\n    vext.16       q8, q14, q7, #2\n    vext.16       q9, q14, q7, #3\n    vext.16       q6, q14, q7, #4\n    vext.16       q7, q14, q7, #1\n    vadd.s16      q8, q8, q9\n    vadd.s16      q9, q6, q7\n    vld1.32       {q7}, [r6], r8        @ load row 0 from temp buffer\n    vmlal.s16     q15, d16, d26\n    vmlsl.s16     q15, d18, d24\n    vmlal.s16     q11, d17, d26\n    vmlsl.s16     q11, d19, d24\n    vqrshrun.s16  d14, q7, #0x5\n    vld1.32       {q14}, [r6], r8       @ load row 1 from temp buffer\n    vaddl.u8      q9, d6, d0\n    vqrshrun.s32  d16, q15, #10\n    vqrshrun.s16  d15, q14, #0x5\n    vqrshrun.s32  d17, q11, #10\n    vmov          d12, d25\n    vmov          d25, d24\n\n    vqmovn.u16    d13, q8\n    vrhadd.u8     q6, q6, q7\n\n    vst1.32       d12, [r1], r3         @ store row 0\n    vst1.32       d13, [r1], r3         @ store row 1\n\n    subs          r4, r4, #2\n    subne         r0, r0 , r2, lsl #2\n    subne         r0, r0, r2\n\n    beq           end_func              @ Branch if height==4\n    b             loop_8                @ Loop if height==8\n\nloop_4:\n    vld1.u32      {q0}, [r0], r2        @ Vector load from src[0_0]\n    vld1.u32      {q1}, [r0], r2        @ Vector load from src[1_0]\n    vld1.u32      {q2}, [r0], r2        @ Vector load from src[2_0]\n    vld1.u32      {q3}, [r0], r2        @ Vector load from src[3_0]\n    vld1.u32      {q4}, [r0], r2        @ Vector load from src[4_0]\n    vld1.u32      {q5}, [r0], r2        @ Vector load from src[5_0]\n\n    vaddl.u8      q7, d4, d6            @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q6, d0, d10           @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q8, d2, d8            @ temp2 = src[1_0] + src[4_0]\n    vmla.u16      q6, q7, q13           @ temp += temp1 * 20\n    vaddl.u8      q9, d5, d7            @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q7, d1, d11           @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q11, d3, d9           @ temp2 = src[1_0] + src[4_0]\n    vmla.u16      q7, q9, q13           @ temp += temp1 * 20\n    vmls.u16      q6, q8, q12           @ temp -= temp2 * 5\n    vld1.32       {q0}, [r0], r2        @ Vector load from src[6_0]\n    vaddl.u8      q8, d6, d8\n    vmls.u16      q7, q11, q12          @ temp -= temp2 * 5\n    @Q6 and Q7 have filtered values\n    vaddl.u8      q14, d2, d0\n    vst1.32       {q6}, [r9]!           @ store row 0 to temp buffer: col 0\n    vext.16       q11, q6, q7, #5\n    vaddl.u8      q9, d4, d10\n    vmla.u16      q14, q8, q13\n    vaddl.s16     q15, d12, d22\n    vst1.32       {q7}, [r9], r7        @ store row 0 to temp buffer: col 1\n    vaddl.s16     q11, d13, d23\n    vext.16       q8, q6, q7, #2\n    vmls.u16      q14, q9, q12\n    vext.16       q9, q6, q7, #3\n    vext.16       q10, q6, q7, #4\n    vext.16       q7, q6, q7, #1\n    vadd.s16      q8, q8, q9\n    vadd.s16      q9, q7, q10\n    vaddl.u8      q10, d7, d9\n    vmlal.s16     q15, d16, d26\n    vmlsl.s16     q15, d18, d24\n    vmlal.s16     q11, d17, d26\n    vmlsl.s16     q11, d19, d24\n    vaddl.u8      q7, d3, d1\n    vst1.32       {q14}, [r9]!          @ store row 1 to temp buffer: col 0\n    vmla.u16      q7, q10, q13\n    vqrshrun.s32  d12, q15, #10\n    vaddl.u8      q8, d5, d11\n    vqrshrun.s32  d13, q11, #10\n    vmls.u16      q7, q8, q12\n    vqmovn.u16    d25, q6\n    vaddl.u8      q8, d8, d10\n\n    vext.16       q11, q14, q7, #5\n    vaddl.u8      q10, d4, d2\n    vaddl.s16     q15, d28, d22\n    vmla.u16      q10, q8, q13\n    vst1.32       {q7}, [r9], r7        @ store row 1 to temp buffer: col 1\n    vaddl.s16     q11, d29, d23\n    vext.16       q8, q14, q7, #2\n    vext.16       q9, q14, q7, #3\n    vext.16       q6, q14, q7, #4\n    vext.16       q7, q14, q7, #1\n    vadd.s16      q8, q8, q9\n    vadd.s16      q9, q6, q7\n    vld1.32       d14, [r6], r8         @load row 0 from temp buffer\n    vmlal.s16     q15, d16, d26\n    vmlsl.s16     q15, d18, d24\n    vmlal.s16     q11, d17, d26\n    vmlsl.s16     q11, d19, d24\n    vqrshrun.s16  d14, q7, #0x5\n    vld1.32       d28, [r6], r8         @load row 1 from temp buffer\n    vaddl.u8      q9, d6, d0\n    vqrshrun.s32  d16, q15, #10\n    vqrshrun.s16  d15, q14, #0x5\n    vqrshrun.s32  d17, q11, #10\n    vmov          d12, d25\n    vmov          d25, d24\n\n    vqmovn.u16    d13, q8\n    vrhadd.u8     q6, q6, q7\n    vst1.32       d12[0], [r1], r3      @ store row 0\n    vst1.32       d13[0], [r1], r3      @store row 1\n\n    subs          r4, r4, #2\n    subne         r0, r0 , r2, lsl #2\n    subne         r0, r0, r2\n\n    beq           end_func              @ Branch if height==4\n    b             loop_4                @ Loop if height==8\n\nend_func:\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_luma_horz_qpel_vert_qpel_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_inter_pred_luma_horz_qpel_vert_qpel_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for inter prediction  interpolation.\n@*\n@* @author\n@*  Mohit\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_inter_pred_luma_horz_qpel_vert_qpel_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_inter_pred_filters.c\n@\n\n@*******************************************************************************\n@*\n@* @brief\n@*   This function implements two six tap filters. It\n@*    applies the six tap filter in the horizontal direction on the\n@*    predictor values, then applies the same filter in the\n@*    vertical direction on the predictor values. It then averages these\n@*    two outputs to obtain quarter pel values in horizontal and vertical direction.\n@*    The six tap filtering operation is described in sec 8.4.2.2.1 titled\n@*    \"Luma sample interpolation process\"\n@*\n@* @par Description:\n@*    This function is called to obtain pixels lying at the following\n@*    location (1/4,1/4) or (3/4,1/4) or (1/4,3/4) or (3/4,3/4).\n@*    The function interpolates the predictors first in the horizontal direction\n@*    and then in the vertical direction, and then averages these two\n@*    values.\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @param[in] pu1_tmp: temporary buffer\n@*\n@* @param[in] dydx: x and y reference offset for qpel calculations\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*;\n\n@void ih264_inter_pred_luma_horz_qpel_vert_qpel(UWORD8 *pu1_src,\n@                                UWORD8 *pu1_dst,\n@                                WORD32 src_strd,,\n@                                WORD32 dst_strd,\n@                                WORD32 ht,\n@                                WORD32 wd,\n@                                UWORD8* pu1_tmp,\n@                                UWORD32 dydx)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ht\n@   r5 =>  wd\n@   r6 =>  dydx\n\n.text\n.p2align 2\n\n    .global ih264_inter_pred_luma_horz_qpel_vert_qpel_a9q\n\nih264_inter_pred_luma_horz_qpel_vert_qpel_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r4, [sp, #104]        @ loads ht\n    ldr           r5, [sp, #108]        @ loads wd\n    ldr           r6, [sp, #116]        @dydx\n    and           r7, r6, #3\n    add           r7, r0, r7, lsr #1    @pu1_pred_vert = pu1_src + (x_offset>>1)\n\n    and           r6, r6, #12           @Finds y-offset\n    lsr           r6, r6, #3            @dydx>>3\n    mul           r6, r2, r6\n    add           r6, r0, r6            @pu1_pred_horz = pu1_src + (y_offset>>1)*src_strd\n    sub           r7, r7, r2, lsl #1    @pu1_pred_vert-2*src_strd\n    sub           r6, r6, #2            @pu1_pred_horz-2\n    vmov.u8       d30, #20              @ Filter coeff 20\n    vmov.u8       d31, #5               @ Filter coeff 5\n\n    subs          r12, r5, #4           @if wd=4 branch to loop_4\n    beq           loop_4\n    subs          r12, r5, #8           @if wd=8 branch to loop_8\n    beq           loop_8\n\nloop_16:\n    vld1.32       {q0}, [r7], r2        @ Vector load from src[0_0]\n    vld1.32       {q1}, [r7], r2        @ Vector load from src[1_0]\n    vld1.32       {q2}, [r7], r2        @ Vector load from src[2_0]\n    vld1.32       {q3}, [r7], r2        @ Vector load from src[3_0]\n    vld1.32       {q4}, [r7], r2        @ Vector load from src[4_0]\n    add           r11, r6, #8\n    vld1.32       {q5}, [r7], r2        @ Vector load from src[5_0]\n    vld1.32       {q9}, [r6], r2        @ horz row0, col 0\n    vaddl.u8      q12, d0, d10\n    vmlal.u8      q12, d4, d30\n    vmlal.u8      q12, d6, d30\n    vmlsl.u8      q12, d2, d31\n    vmlsl.u8      q12, d8, d31\n    vext.8        d23, d18, d19, #5\n    vext.8        d20, d18, d19, #2\n    vext.8        d21, d18, d19, #3\n    vext.8        d22, d18, d19, #4\n    vext.8        d19, d18, d19, #1\n    vqrshrun.s16  d26, q12, #5\n    vaddl.u8      q14, d18, d23\n    vmlal.u8      q14, d20, d30\n    vmlal.u8      q14, d21, d30\n    vmlsl.u8      q14, d19, d31\n    vmlsl.u8      q14, d22, d31\n    vld1.32       {q9}, [r11], r2       @ horz row 0, col 1\n    vaddl.u8      q12, d1, d11\n    vmlal.u8      q12, d5, d30\n    vmlal.u8      q12, d7, d30\n    vmlsl.u8      q12, d3, d31\n    vmlsl.u8      q12, d9, d31\n    vqrshrun.s16  d28, q14, #5\n    vext.8        d23, d18, d19, #5\n    vext.8        d20, d18, d19, #2\n    vext.8        d21, d18, d19, #3\n    vext.8        d22, d18, d19, #4\n    vext.8        d19, d18, d19, #1\n    vqrshrun.s16  d27, q12, #5\n    vld1.32       {q6}, [r7], r2        @ src[6_0]\n\n    vaddl.u8      q12, d18, d23\n    vmlal.u8      q12, d20, d30\n    vmlal.u8      q12, d21, d30\n    vmlsl.u8      q12, d19, d31\n    vmlsl.u8      q12, d22, d31\n\n    vaddl.u8      q8, d2, d12\n    vmlal.u8      q8, d6, d30\n    vmlal.u8      q8, d8, d30\n    vmlsl.u8      q8, d4, d31\n    vmlsl.u8      q8, d10, d31\n    vqrshrun.s16  d29, q12, #5\n    vld1.32       {q9}, [r6], r2        @ horz row 1, col 0\n\n    vaddl.u8      q12, d3, d13\n    vmlal.u8      q12, d7, d30\n    vmlal.u8      q12, d9, d30\n    vmlsl.u8      q12, d5, d31\n    vmlsl.u8      q12, d11, d31\n    vrhadd.u8     q14, q14, q13\n    vqrshrun.s16  d26, q8, #5\n    vext.8        d23, d18, d19, #5\n    vext.8        d20, d18, d19, #2\n    vext.8        d21, d18, d19, #3\n    vext.8        d22, d18, d19, #4\n    vst1.32       {q14}, [r1], r3       @ store row 0\n    vext.8        d19, d18, d19, #1\n    vqrshrun.s16  d27, q12, #5\n\n    vaddl.u8      q14, d18, d23\n    vmlal.u8      q14, d20, d30\n    vmlal.u8      q14, d21, d30\n    vmlsl.u8      q14, d19, d31\n    vmlsl.u8      q14, d22, d31\n\n    vld1.32       {q9}, [r11], r2       @ horz row 1, col 1\n\n    vext.8        d23, d18, d19, #5\n    vext.8        d20, d18, d19, #2\n    vext.8        d21, d18, d19, #3\n    vext.8        d22, d18, d19, #4\n    vext.8        d19, d18, d19, #1\n\n    vqrshrun.s16  d28, q14, #5\n    vaddl.u8      q12, d18, d23\n    vmlal.u8      q12, d20, d30\n    vmlal.u8      q12, d21, d30\n    vmlsl.u8      q12, d19, d31\n    vmlsl.u8      q12, d22, d31\n\n    vqrshrun.s16  d29, q12, #5\n    vrhadd.u8     q14, q14, q13\n    vst1.32       {q14}, [r1], r3       @ store row 1\n\n    subs          r4, r4, #2            @ 2 rows processed, decrement by 2\n    subne         r7, r7 , r2, lsl #2\n    subne         r7, r7, r2\n    beq           end_func              @ Branch if height==4\n\n    b             loop_16               @ looping if height = 8 or 16\n\n\nloop_8:\n    vld1.32       d0, [r7], r2          @ Vector load from src[0_0]\n    vld1.32       d1, [r7], r2          @ Vector load from src[1_0]\n    vld1.32       d2, [r7], r2          @ Vector load from src[2_0]\n    vld1.32       d3, [r7], r2          @ Vector load from src[3_0]\n    vld1.32       d4, [r7], r2          @ Vector load from src[4_0]\n    vld1.32       d5, [r7], r2          @ Vector load from src[5_0]\n    vaddl.u8      q5, d0, d5\n    vmlal.u8      q5, d2, d30\n    vmlal.u8      q5, d3, d30\n    vmlsl.u8      q5, d1, d31\n    vmlsl.u8      q5, d4, d31\n    vld1.32       {q6}, [r6], r2        @horz row 0\n    vext.8        d17, d12, d13, #5\n    vext.8        d14, d12, d13, #2\n    vext.8        d15, d12, d13, #3\n    vext.8        d16, d12, d13, #4\n    vext.8        d13, d12, d13, #1\n    vqrshrun.s16  d26, q5, #5\n    vld1.32       d6, [r7], r2          @ src[6_0]\n    vaddl.u8      q5, d12, d17\n    vmlal.u8      q5, d14, d30\n    vmlal.u8      q5, d15, d30\n    vmlsl.u8      q5, d13, d31\n    vmlsl.u8      q5, d16, d31\n    vld1.32       {q6}, [r6], r2        @ horz row 1\n    vaddl.u8      q9, d1, d6\n    vmlal.u8      q9, d3, d30\n    vmlal.u8      q9, d4, d30\n    vmlsl.u8      q9, d2, d31\n    vmlsl.u8      q9, d5, d31\n    vqrshrun.s16  d28, q5, #5\n    vext.8        d17, d12, d13, #5\n    vext.8        d14, d12, d13, #2\n    vext.8        d15, d12, d13, #3\n    vext.8        d16, d12, d13, #4\n    vext.8        d13, d12, d13, #1\n    vqrshrun.s16  d27, q9, #5\n    vaddl.u8      q5, d12, d17\n    vmlal.u8      q5, d14, d30\n    vmlal.u8      q5, d15, d30\n    vmlsl.u8      q5, d13, d31\n    vmlsl.u8      q5, d16, d31\n    vqrshrun.s16  d29, q5, #5\n    vrhadd.u8     q13, q13, q14\n    vst1.32       d26, [r1], r3\n    vst1.32       d27, [r1], r3\n\n    subs          r4, r4, #2            @ 2 rows processed, decrement by 2\n    subne         r7, r7 , r2, lsl #2\n    subne         r7, r7, r2\n    beq           end_func              @ Branch if height==4\n    b             loop_8                @looping if height == 8 or 16\n\nloop_4:\n    vld1.32       d0[0], [r7], r2       @ Vector load from src[0_0]\n    vld1.32       d1[0], [r7], r2       @ Vector load from src[1_0]\n    vld1.32       d2[0], [r7], r2       @ Vector load from src[2_0]\n    vld1.32       d3[0], [r7], r2       @ Vector load from src[3_0]\n    vld1.32       d4[0], [r7], r2       @ Vector load from src[4_0]\n    vld1.32       d5[0], [r7], r2       @ Vector load from src[5_0]\n    vaddl.u8      q5, d0, d5\n    vmlal.u8      q5, d2, d30\n    vmlal.u8      q5, d3, d30\n    vmlsl.u8      q5, d1, d31\n    vmlsl.u8      q5, d4, d31\n    vld1.32       {q6}, [r6], r2        @load for horz filter row 0\n    vext.8        d17, d12, d13, #5\n    vext.8        d14, d12, d13, #2\n    vext.8        d15, d12, d13, #3\n    vext.8        d16, d12, d13, #4\n    vext.8        d13, d12, d13, #1\n    vqrshrun.s16  d26, q5, #5\n    vld1.32       d6[0], [r7], r2       @ Vector load from src[6_0]\n    vaddl.u8      q5, d12, d17\n    vmlal.u8      q5, d14, d30\n    vmlal.u8      q5, d15, d30\n    vmlsl.u8      q5, d13, d31\n    vmlsl.u8      q5, d16, d31\n    vld1.32       {q6}, [r6], r2        @horz row 1\n    vaddl.u8      q9, d1, d6\n    vmlal.u8      q9, d3, d30\n    vmlal.u8      q9, d4, d30\n    vmlsl.u8      q9, d2, d31\n    vmlsl.u8      q9, d5, d31\n    vqrshrun.s16  d28, q5, #5\n    vext.8        d17, d12, d13, #5\n    vext.8        d14, d12, d13, #2\n    vext.8        d15, d12, d13, #3\n    vext.8        d16, d12, d13, #4\n    vext.8        d13, d12, d13, #1\n    vqrshrun.s16  d27, q9, #5\n    vaddl.u8      q5, d12, d17\n    vmlal.u8      q5, d14, d30\n    vmlal.u8      q5, d15, d30\n    vmlsl.u8      q5, d13, d31\n    vmlsl.u8      q5, d16, d31\n    vqrshrun.s16  d29, q5, #5\n    vrhadd.u8     q13, q13, q14\n    vst1.32       d26[0], [r1], r3\n    vst1.32       d27[0], [r1], r3\n\n    subs          r4, r4, #2            @ 2 rows processed, decrement by 2\n    subne         r7, r7 , r2, lsl #2\n    subne         r7, r7, r2\n    beq           end_func              @ Branch if height==4\n    b             loop_4                @ Loop if height==8\nend_func:\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_inter_pred_luma_vert_qpel_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_inter_pred_luma_vert_qpel_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for inter prediction vertical quarter pel interpolation.\n@*\n@* @author\n@*  Mohit\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_inter_pred_luma_vert_qpel_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_inter_pred_filters.c\n@\n\n@*******************************************************************************\n@*\n@* @brief\n@*     Quarter pel interprediction luma filter for vertical input\n@*\n@* @par Description:\n@* Applies a 6 tap horizontal filter .The output is  clipped to 8 bits\n@* sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @param[in] pu1_tmp: temporary buffer: UNUSED in this function\n@*\n@* @param[in] dydx: x and y reference offset for qpel calculations.\n@* @returns\n@*\n@ @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@void ih264_inter_pred_luma_vert (\n@                            UWORD8 *pu1_src,\n@                            UWORD8 *pu1_dst,\n@                            WORD32 src_strd,\n@                            WORD32 dst_strd,\n@                            WORD32 ht,\n@                            WORD32 wd,\n@                            UWORD8* pu1_tmp,\n@                            UWORD32 dydx)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r5 =>  ht\n@   r6 =>  wd\n@   r7 =>  dydx\n\n.text\n.p2align 2\n\n    .global ih264_inter_pred_luma_vert_qpel_a9q\n\nih264_inter_pred_luma_vert_qpel_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vstmdb        sp!, {d8-d15}         @push neon registers to stack\n    ldr           r5, [sp, #104]        @Loads ht\n\n    ldr           r6, [sp, #108]        @Loads wd\n    ldr           r7, [sp, #116]        @Loads dydx\n    and           r7, r7, #12           @Finds y-offset\n    lsr           r7, r7, #3            @dydx>>3\n    mul           r7, r2, r7\n    add           r7, r0, r7            @pu1_src + (y_offset>>1)*src_strd\n    vmov.u16      q11, #20              @ Filter coeff 0x14 into Q11\n    sub           r0, r0, r2, lsl #1    @pu1_src-2*src_strd\n    subs          r12, r6, #8           @if wd=8 branch to loop_8\n    vmov.u16      q12, #5               @ Filter coeff 0x5  into Q12\n    beq           loop_8\n\n    subs          r12, r6, #4           @if wd=4 branch to loop_4\n    beq           loop_4\n\nloop_16:                                @when  wd=16\n\n    vld1.u32      {q0}, [r0], r2        @ Vector load from src[0_0]\n    vld1.u32      {q1}, [r0], r2        @ Vector load from src[1_0]\n    vld1.u32      {q2}, [r0], r2        @ Vector load from src[2_0]\n    vld1.u32      {q3}, [r0], r2        @ Vector load from src[3_0]\n    vld1.u32      {q4}, [r0], r2        @ Vector load from src[4_0]\n    vaddl.u8      q6, d4, d6            @ temp1 = src[2_0] + src[3_0]\n    vld1.u32      {q5}, [r0], r2        @ Vector load from src[5_0]\n    vaddl.u8      q7, d0, d10           @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q8, d2, d8            @ temp2 = src[1_0] + src[4_0]\n    vmla.u16      q7, q6, q11           @ temp += temp1 * 20\n    vaddl.u8      q10, d1, d11          @ temp4 = src[0_8] + src[5_8]\n    vaddl.u8      q9, d5, d7            @ temp3 = src[2_8] + src[3_8]\n    vmla.u16      q10, q9, q11          @ temp4 += temp3 * 20\n    vld1.u32      {q0}, [r0], r2\n    vaddl.u8      q13, d3, d9           @ temp5 = src[1_8] + src[4_8]\n    vaddl.u8      q6, d6, d8\n    vmls.u16      q7, q8, q12           @ temp -= temp2 * 5\n    vaddl.u8      q8, d2, d0\n    vaddl.u8      q9, d4, d10\n    vmla.u16      q8, q6, q11\n    vmls.u16      q10, q13, q12         @ temp4 -= temp5 * 5\n    vaddl.u8      q13, d5, d11\n    vaddl.u8      q6, d7, d9\n    vqrshrun.s16  d30, q7, #5           @ dst[0_0] = CLIP_U8((temp +16) >> 5)\n    vaddl.u8      q7, d3, d1\n    vld1.u32      {q1}, [r0], r2\n    vmla.u16      q7, q6, q11\n    vmls.u16      q8, q9, q12\n    vqrshrun.s16  d31, q10, #5          @ dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    vld1.u32      {q10}, [r7], r2       @ Load for interpolation row 0\n    vrhadd.u8     q15, q10, q15         @ Interpolation to obtain qpel value\n    vaddl.u8      q9, d4, d2\n    vaddl.u8      q6, d8, d10\n\n    vst1.u32      {q15}, [r1], r3       @ Vector store to dst[0_0]\n    vmla.u16      q9, q6, q11\n    vaddl.u8      q10, d6, d0\n    vmls.u16      q7, q13, q12\n    vqrshrun.s16  d30, q8, #5\n    vaddl.u8      q6, d9, d11\n    vaddl.u8      q8, d5, d3\n    vaddl.u8      q13, d7, d1\n    vmla.u16      q8, q6, q11\n    vmls.u16      q9, q10, q12\n    vld1.u32      {q2}, [r0], r2\n\n    vqrshrun.s16  d31, q7, #5\n    vld1.u32      {q7}, [r7], r2        @ Load for interpolation row 1\n    vaddl.u8      q6, d10, d0\n    vrhadd.u8     q15, q7, q15          @ Interpolation to obtain qpel value\n    vaddl.u8      q7, d6, d4\n    vaddl.u8      q10, d8, d2\n    vmla.u16      q7, q6, q11\n    vmls.u16      q8, q13, q12\n    vst1.u32      {q15}, [r1], r3       @store row 1\n    vqrshrun.s16  d30, q9, #5\n    vaddl.u8      q9, d7, d5\n    vaddl.u8      q6, d11, d1\n    vmla.u16      q9, q6, q11\n    vaddl.u8      q13, d9, d3\n    vmls.u16      q7, q10, q12\n    vqrshrun.s16  d31, q8, #5\n    vld1.u32      {q8}, [r7], r2        @ Load for interpolation row 2\n    vmls.u16      q9, q13, q12\n    vrhadd.u8     q15, q8, q15          @ Interpolation to obtain qpel value\n    vaddl.u8      q6, d0, d2            @ temp1 = src[2_0] + src[3_0]\n    vst1.u32      {q15}, [r1], r3       @store row 2\n    vaddl.u8      q8, d10, d4           @ temp2 = src[1_0] + src[4_0]\n    vaddl.u8      q10, d9, d7           @ temp4 = src[0_8] + src[5_8]\n    vqrshrun.s16  d30, q7, #5\n    vaddl.u8      q13, d5, d11          @ temp5 = src[1_8] + src[4_8]\n    vaddl.u8      q7, d8, d6            @ temp = src[0_0] + src[5_0]\n    vqrshrun.s16  d31, q9, #5\n    vld1.u32      {q9}, [r7], r2        @ Load for interpolation row 3\n    vmla.u16      q7, q6, q11           @ temp += temp1 * 20\n    vrhadd.u8     q15, q9, q15          @ Interpolation to obtain qpel value\n    vaddl.u8      q9, d1, d3            @ temp3 = src[2_8] + src[3_8]\n    vst1.u32      {q15}, [r1], r3       @store row 3\n    subs          r5, r5, #4            @ 4 rows processed, decrement by 4\n    subne         r0, r0 , r2, lsl #2\n    subne         r0, r0, r2\n    beq           end_func              @ Branch if height==4\n\n    b             loop_16               @ looping if height = 8 or 16\n\n\nloop_8:\n\n    @ Processing row0 and row1\n    vld1.u32      d0, [r0], r2          @ Vector load from src[0_0]\n    vld1.u32      d1, [r0], r2          @ Vector load from src[1_0]\n    vld1.u32      d2, [r0], r2          @ Vector load from src[2_0]\n    vld1.u32      d3, [r0], r2          @ Vector load from src[3_0]\n    vld1.u32      d4, [r0], r2          @ Vector load from src[4_0]\n    vld1.u32      d5, [r0], r2          @ Vector load from src[5_0]\n\n    vaddl.u8      q3, d2, d3            @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q4, d0, d5            @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q5, d1, d4            @ temp2 = src[1_0] + src[4_0]\n    vmla.u16      q4, q3, q11           @ temp += temp1 * 20\n    vld1.u32      d6, [r0], r2\n    vaddl.u8      q7, d3, d4\n    vaddl.u8      q8, d1, d6\n    vaddl.u8      q9, d2, d5\n    vmls.u16      q4, q5, q12           @ temp -= temp2 * 5\n    vmla.u16      q8, q7, q11\n    vld1.u32      d7, [r0], r2\n    vaddl.u8      q10, d4, d5\n    vaddl.u8      q6, d2, d7\n    vaddl.u8      q5, d3, d6\n    vmls.u16      q8, q9, q12\n    vqrshrun.s16  d26, q4, #5           @ dst[0_0] = CLIP_U8( (temp + 16) >> 5)\n    vmla.u16      q6, q10, q11\n    vld1.32       d8, [r7], r2          @Load value for interpolation           (row0)\n    vld1.32       d9, [r7], r2          @Load value for interpolation           (row1)\n    vld1.u32      d0, [r0], r2\n    vaddl.u8      q7, d5, d6\n    vqrshrun.s16  d27, q8, #5\n    vrhadd.u8     q13, q4, q13          @ Interpolation step for qpel calculation\n    vaddl.u8      q10, d3, d0\n    vmls.u16      q6, q5, q12\n    vst1.u32      d26, [r1], r3         @ Vector store to dst[0_0]\n    vaddl.u8      q9, d4, d7\n    vmla.u16      q10, q7, q11\n    vst1.u32      d27, [r1], r3         @ Vector store to dst[1_0]\n    vqrshrun.s16  d28, q6, #5\n    vmls.u16      q10, q9, q12\n    vld1.32       d12, [r7], r2         @Load value for interpolation           (row2)\n    vld1.32       d13, [r7], r2         @Load value for interpolation           (row3)\n    vqrshrun.s16  d29, q10, #5\n    subs          r9, r5, #4\n    vrhadd.u8     q14, q6, q14\n    vst1.u32      d28, [r1], r3         @store row 2\n    vst1.u32      d29, [r1], r3         @store row 3\n\n    subs          r5, r5, #4            @ 4 rows processed, decrement by 4\n    subne         r0, r0 , r2, lsl #2\n    subne         r0, r0, r2\n    beq           end_func              @ Branch if height==4\n    b             loop_8                @looping if height == 8 or 16\n\nloop_4:\n@ Processing row0 and row1\n\n    vld1.u32      d0[0], [r0], r2       @ Vector load from src[0_0]\n    vld1.u32      d1[0], [r0], r2       @ Vector load from src[1_0]\n    vld1.u32      d2[0], [r0], r2       @ Vector load from src[2_0]\n    vld1.u32      d3[0], [r0], r2       @ Vector load from src[3_0]\n    vld1.u32      d4[0], [r0], r2       @ Vector load from src[4_0]\n    vld1.u32      d5[0], [r0], r2       @ Vector load from src[5_0]\n\n    vaddl.u8      q3, d2, d3            @ temp1 = src[2_0] + src[3_0]\n    vaddl.u8      q4, d0, d5            @ temp = src[0_0] + src[5_0]\n    vaddl.u8      q5, d1, d4            @ temp2 = src[1_0] + src[4_0]\n    vmla.u16      q4, q3, q11           @ temp += temp1 * 20\n    vld1.u32      d6, [r0], r2\n    vaddl.u8      q7, d3, d4\n    vaddl.u8      q8, d1, d6\n    vaddl.u8      q9, d2, d5\n    vmls.u16      q4, q5, q12           @ temp -= temp2 * 5\n    vld1.u32      d7[0], [r0], r2\n    vmla.u16      q8, q7, q11\n    vaddl.u8      q10, d4, d5\n    vaddl.u8      q6, d2, d7\n    vaddl.u8      q5, d3, d6\n    vmls.u16      q8, q9, q12\n    vqrshrun.s16  d26, q4, #5           @ dst[0_0] = CLIP_U8( (temp + 16) >> 5)\n    vld1.u32      d8[0], [r7], r2       @Load value for interpolation - row 0\n    vld1.u32      d9[0], [r7], r2       @Load value for interpolation - row 1\n    vmla.u16      q6, q10, q11\n    vld1.u32      d0[0], [r0], r2\n    vaddl.u8      q7, d5, d6\n    vqrshrun.s16  d27, q8, #5\n    vaddl.u8      q10, d3, d0\n    vrhadd.u8     q13, q13, q4          @Interpolation step for qpel calculation\n    vmls.u16      q6, q5, q12\n    vst1.u32      d26[0], [r1], r3      @ Vector store to dst[0_0]\n    vaddl.u8      q9, d4, d7\n    vmla.u16      q10, q7, q11\n    vst1.u32      d27[0], [r1], r3      @ store row 1\n    vqrshrun.s16  d28, q6, #5\n    vld1.u32      d12[0], [r7], r2      @Load value for interpolation - row 2\n    vld1.u32      d13[0], [r7], r2      @Load value for interpolation - row 3\n\n    vmls.u16      q10, q9, q12\n    vqrshrun.s16  d29, q10, #5\n    vrhadd.u8     q14, q6, q14          @Interpolation step for qpel calculation\n    vst1.u32      d28[0], [r1], r3      @store row 2\n    vst1.u32      d29[0], [r1], r3      @store row 3\n\n    subs          r5, r5, #8\n    subeq         r0, r0, r2, lsl #2\n    subeq         r0, r0, r2\n    beq           loop_4                @ Loop if height==8\n\nend_func:\n    vldmia        sp!, {d8-d15}         @ Restore neon registers that were saved\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_intra_pred_chroma_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_intra_pred_chroma_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for intra chroma prediction .\n@*\n@* @author\n@*  Ittiam\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_intra_pred_chroma_mode_horz_a9q()\n@*  - ih264_intra_pred_chroma_8x8_mode_vert_a9q()\n@*  - ih264_intra_pred_chroma_mode_dc_a9q()\n@*  - ih264_intra_pred_chroma_mode_plane_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_chroma_intra_pred_filters.c\n@\n\n.text\n.p2align 2\n\n    .extern ih264_gai1_intrapred_chroma_plane_coeffs1\n.hidden ih264_gai1_intrapred_chroma_plane_coeffs1\n    .extern ih264_gai1_intrapred_chroma_plane_coeffs2\n.hidden ih264_gai1_intrapred_chroma_plane_coeffs2\nscratch_chroma_intrapred_addr1:\n    .long ih264_gai1_intrapred_chroma_plane_coeffs1 - scrlblc1 - 8\n\nscratch_intrapred_chroma_plane_addr1:\n    .long ih264_gai1_intrapred_chroma_plane_coeffs2 - scrlblc2 - 8\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_chroma_8x8_mode_dc\n@*\n@* @brief\n@*     Perform Intra prediction for  chroma_8x8 mode:DC\n@*\n@* @par Description:\n@*    Perform Intra prediction for  chroma_8x8 mode:DC ,described in sec 8.3.4.1\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source containing alternate U and V samples\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination with alternate U and V samples\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@** @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_chroma_8x8_mode_dc(UWORD8 *pu1_src,\n@                                        UWORD8 *pu1_dst,\n@                                        WORD32 src_strd,\n@                                        WORD32 dst_strd,\n@                                        WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_chroma_8x8_mode_dc_a9q\n\nih264_intra_pred_chroma_8x8_mode_dc_a9q:\n\n    stmfd         sp!, {r4, r14}        @store register values to stack\n    ldr           r4, [sp, #8]          @r4 =>  ui_neighboravailability\n    vpush         {d8-d15}\n\n    ands          r2, r4, #0x01         @CHECKING IF LEFT_AVAILABLE ELSE BRANCHING TO ONLY TOP AVAILABLE\n    beq           top_available\n    ands          r2, r4, #0x04         @CHECKING IF TOP_AVAILABLE ELSE BRANCHING TO ONLY LEFT AVAILABLE\n    beq           left_available\n\n    vld1.u8       {q0}, [r0]            @BOTH LEFT AND TOP AVAILABLE\n    add           r0, r0, #18\n    vld1.u8       {q1}, [r0]\n    vaddl.u8      q2, d1, d2\n    vaddl.u8      q3, d0, d3\n    vmovl.u8      q1, d3\n    vmovl.u8      q0, d0\n\n    vadd.u16      d12, d4, d5\n    vadd.u16      d13, d2, d3\n    vadd.u16      d15, d6, d7\n    vadd.u16      d14, d0, d1\n\n    vpadd.u32     d12, d12, d15\n    vpadd.u32     d14, d13, d14\n    vqrshrun.s16  d12, q6, #3\n    vqrshrun.s16  d14, q7, #2\n    vdup.u16      d8, d12[0]\n    vdup.u16      d9, d14[0]\n    vdup.u16      d10, d14[1]\n    vdup.u16      d11, d12[1]\n    b             str_pred\n\ntop_available:                          @ONLY TOP AVAILABLE\n    ands          r2, r4, #0x04         @CHECKING TOP AVAILABILTY OR ELSE BRANCH TO NONE AVAILABLE\n    beq           none_available\n\n    add           r0, r0, #18\n    vld1.u8       {q0}, [r0]\n    vmovl.u8      q1, d0\n    vmovl.u8      q2, d1\n    vadd.u16      d0, d2, d3\n    vadd.u16      d1, d4, d5\n    vpaddl.u32    q0, q0\n    vqrshrun.s16  d0, q0, #2\n    vdup.u16      d8, d0[0]\n    vdup.u16      d9, d0[2]\n    vmov          q5, q4\n    b             str_pred\n\nleft_available:                         @ONLY LEFT AVAILABLE\n    vld1.u8       {q0}, [r0]\n    vmovl.u8      q1, d0\n    vmovl.u8      q2, d1\n    vadd.u16      d0, d2, d3\n    vadd.u16      d1, d4, d5\n    vpaddl.u32    q0, q0\n    vqrshrun.s16  d0, q0, #2\n    vdup.u16      q5, d0[0]\n    vdup.u16      q4, d0[2]\n    b             str_pred\n\nnone_available:                         @NONE AVAILABLE\n    vmov.u8       q4, #128\n    vmov.u8       q5, #128\n\nstr_pred:\n    vst1.8        {q4}, [r1], r3\n    vst1.8        {q4}, [r1], r3\n    vst1.8        {q4}, [r1], r3\n    vst1.8        {q4}, [r1], r3\n    vst1.8        {q5}, [r1], r3\n    vst1.8        {q5}, [r1], r3\n    vst1.8        {q5}, [r1], r3\n    vst1.8        {q5}, [r1], r3\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4, pc}         @Restoring registers from stack\n\n\n\n@******************************************************************************\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_chroma_8x8_mode_horz\n@*\n@* @brief\n@*  Perform Intra prediction for  chroma_8x8 mode:Horizontal\n@*\n@* @par Description:\n@*   Perform Intra prediction for  chroma_8x8 mode:Horizontal ,described in sec 8.3.4.2\n@*\n@* @param[in] pu1_src\n@* UWORD8 pointer to the source containing alternate U and V samples\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination with alternate U and V samples\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@* availability of neighbouring pixels(Not used in this function)\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@void ih264_intra_pred_chroma_8x8_mode_horz(UWORD8 *pu1_src,\n@                                         UWORD8 *pu1_dst,\n@                                         WORD32 src_strd,\n@                                         WORD32 dst_strd,\n@                                         WORD32 ui_neighboravailability)\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_chroma_8x8_mode_horz_a9q\n\nih264_intra_pred_chroma_8x8_mode_horz_a9q:\n\n    stmfd         sp!, {r14}            @store register values to stack\n\n    vld1.u8       {q0}, [r0]\n    mov           r2, #6\n\n    vdup.u16      q1, d1[3]\n    vdup.u16      q2, d1[2]\n    vst1.8        {q1}, [r1], r3\n\nloop_8x8_horz:\n    vext.8        q0, q0, q0, #12\n    vst1.8        {q2}, [r1], r3\n    vdup.u16      q1, d1[3]\n    subs          r2, #2\n    vdup.u16      q2, d1[2]\n    vst1.8        {q1}, [r1], r3\n    bne           loop_8x8_horz\n\n    vext.8        q0, q0, q0, #12\n    vst1.8        {q2}, [r1], r3\n\n    ldmfd         sp!, {pc}             @restoring registers from stack\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_chroma_8x8_mode_vert\n@*\n@* @brief\n@*   Perform Intra prediction for  chroma_8x8 mode:vertical\n@*\n@* @par Description:\n@*Perform Intra prediction for  chroma_8x8 mode:vertical ,described in sec 8.3.4.3\n@*\n@* @param[in] pu1_src\n@* UWORD8 pointer to the source containing alternate U and V samples\n@*\n@* @param[out] pu1_dst\n@*   UWORD8 pointer to the destination with alternate U and V samples\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@* availability of neighbouring pixels(Not used in this function)\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_chroma_8x8_mode_vert(UWORD8 *pu1_src,\n@                                        UWORD8 *pu1_dst,\n@                                        WORD32 src_strd,\n@                                        WORD32 dst_strd,\n@                                        WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_chroma_8x8_mode_vert_a9q\n\nih264_intra_pred_chroma_8x8_mode_vert_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n    add           r0, r0, #18\n    vld1.8        {q0}, [r0]\n\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n@******************************************************************************\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_chroma_8x8_mode_plane\n@*\n@* @brief\n@*   Perform Intra prediction for  chroma_8x8 mode:PLANE\n@*\n@* @par Description:\n@*  Perform Intra prediction for  chroma_8x8 mode:PLANE ,described in sec 8.3.4.4\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source containing alternate U and V samples\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination with alternate U and V samples\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_chroma_8x8_mode_plane(UWORD8 *pu1_src,\n@                                        UWORD8 *pu1_dst,\n@                                        WORD32 src_strd,\n@                                        WORD32 dst_strd,\n@                                        WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_chroma_8x8_mode_plane_a9q\nih264_intra_pred_chroma_8x8_mode_plane_a9q:\n\n    stmfd         sp!, {r4-r10, r12, lr}\n    vpush         {d8-d15}\n\n    vld1.32       d0, [r0]\n    add           r10, r0, #10\n    vld1.32       d1, [r10]\n    add           r10, r10, #6\n    vrev64.16     d5, d0\n    vld1.32       d2, [r10]!\n    add           r10, r10, #2\n    vrev64.16     d7, d2\n    vld1.32       d3, [r10]\n    sub           r5, r3, #8\n    ldr           r12, scratch_chroma_intrapred_addr1\nscrlblc1:\n    add           r12, r12, pc\n    vsubl.u8      q5, d5, d1\n    vld1.64       {q4}, [r12]           @ Load multiplication factors 1 to 8 into D3\n    vsubl.u8      q6, d3, d7\n    vmul.s16      q7, q5, q4\n    vmul.s16      q8, q6, q4\n    vuzp.16       q7, q8\n\n    vpadd.s16     d14, d14\n    vpadd.s16     d15, d15\n    vpadd.s16     d16, d16\n    vpadd.s16     d17, d17\n    vpadd.s16     d14, d14\n    vpadd.s16     d15, d15\n    vpadd.s16     d16, d16\n    vpadd.s16     d17, d17\n\n    mov           r6, #34\n    vdup.16       q9, r6\n\n    vmull.s16     q11, d14, d18\n    vmull.s16     q12, d15, d18\n    vmull.s16     q13, d16, d18\n    vmull.s16     q14, d17, d18\n\n    vrshrn.s32    d10, q11, #6\n    vrshrn.s32    d12, q12, #6\n    vrshrn.s32    d13, q13, #6\n    vrshrn.s32    d14, q14, #6\n\n\n    ldrb          r6, [r0], #1\n    add           r10, r0, #31\n    ldrb          r8, [r0], #1\n    ldrb          r7, [r10], #1\n    ldrb          r9, [r10], #1\n\n    add           r6, r6, r7\n    add           r8, r8, r9\n    lsl           r6, r6, #4\n    lsl           r8, r8, #4\n\n    vdup.16       q0, r6\n    vdup.16       q1, r8\n    vdup.16       q2, d12[0]\n    vdup.16       q3, d10[0]\n\n    vdup.16       q12, d14[0]\n    vdup.16       q13, d13[0]\n    vzip.16       q2, q12\n    vzip.16       q3, q13\n    vzip.16       q0, q1\n\n    ldr           r12, scratch_intrapred_chroma_plane_addr1\nscrlblc2:\n    add           r12, r12, pc\n    vld1.64       {q4}, [r12]\n    vmov.16       q5, q4\n    vmov          q11, q4\n    vzip.16       q4, q5\n\n    vmul.s16      q6, q2, q4\n    vmul.s16      q8, q2, q5\n    vadd.s16      q6, q0, q6\n    vadd.s16      q8, q0, q8\n\n\n    vdup.16       q10, d22[0]\n    vmul.s16      q2, q3, q10\n    vdup.16       q15, d22[1]\n    vmul.s16      q9, q3, q10\n    vmul.s16      q7, q3, q15\n    vmul.s16      q4, q3, q15\n    vadd.s16      q12, q6, q2\n    vadd.s16      q0, q8, q9\n    vadd.s16      q1, q6, q7\n    vqrshrun.s16  d28, q12, #5\n    vadd.s16      q13, q8, q4\n    vqrshrun.s16  d29, q0, #5\n    vdup.16       q10, d22[2]\n    vst1.8        {q14}, [r1], r3\n    vqrshrun.s16  d28, q1, #5\n    vqrshrun.s16  d29, q13, #5\n    vmul.s16      q2, q3, q10\n    vmul.s16      q9, q3, q10\n    vst1.8        {q14}, [r1], r3\n    vadd.s16      q12, q6, q2\n    vadd.s16      q0, q8, q9\n    vdup.16       q15, d22[3]\n    vqrshrun.s16  d28, q12, #5\n    vqrshrun.s16  d29, q0, #5\n    vmul.s16      q7, q3, q15\n    vmul.s16      q4, q3, q15\n    vst1.8        {q14}, [r1], r3\n    vadd.s16      q1, q6, q7\n    vadd.s16      q13, q8, q4\n    vdup.16       q10, d23[0]\n    vqrshrun.s16  d28, q1, #5\n    vqrshrun.s16  d29, q13, #5\n    vmul.s16      q2, q3, q10\n    vmul.s16      q9, q3, q10\n    vst1.8        {q14}, [r1], r3\n    vadd.s16      q12, q6, q2\n    vadd.s16      q0, q8, q9\n    vdup.16       q15, d23[1]\n    vqrshrun.s16  d28, q12, #5\n    vqrshrun.s16  d29, q0, #5\n    vmul.s16      q7, q3, q15\n    vmul.s16      q4, q3, q15\n    vst1.8        {q14}, [r1], r3\n    vadd.s16      q1, q6, q7\n    vadd.s16      q13, q8, q4\n    vdup.16       q10, d23[2]\n    vqrshrun.s16  d28, q1, #5\n    vqrshrun.s16  d29, q13, #5\n    vmul.s16      q2, q3, q10\n    vmul.s16      q9, q3, q10\n    vst1.8        {q14}, [r1], r3\n    vadd.s16      q12, q6, q2\n    vadd.s16      q0, q8, q9\n    vdup.16       q15, d23[3]\n    vqrshrun.s16  d28, q12, #5\n    vqrshrun.s16  d29, q0, #5\n    vmul.s16      q7, q3, q15\n    vmul.s16      q4, q3, q15\n    vst1.8        {q14}, [r1], r3\n    vadd.s16      q1, q6, q7\n    vadd.s16      q13, q8, q4\n    vqrshrun.s16  d28, q1, #5\n    vqrshrun.s16  d29, q13, #5\n    vst1.8        {q14}, [r1], r3\n\n\n\nend_func_plane:\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r10, r12, pc}\n\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_intra_pred_luma_16x16_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_intra_pred_luma_16x16_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for intra 16x16 Luma prediction .\n@*\n@* @author\n@*  Ittiam\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_intra_pred_luma_16x16_mode_vert_a9q()\n@*  - ih264_intra_pred_luma_16x16_mode_horz_a9q()\n@*  - ih264_intra_pred_luma_16x16_mode_dc_a9q()\n@*  - ih264_intra_pred_luma_16x16_mode_plane_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_intra_pred_filters.c\n@\n\n@**\n@**\n@**\n@\n\n.text\n.p2align 2\n\n\n    .extern ih264_gai1_intrapred_luma_plane_coeffs\n.hidden ih264_gai1_intrapred_luma_plane_coeffs\nscratch_intrapred_addr1:\n    .long ih264_gai1_intrapred_luma_plane_coeffs - scrlbl1 - 8\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_16x16_mode_vert\n@*\n@* @brief\n@*   Perform Intra prediction for  luma_16x16 mode:vertical\n@*\n@* @par Description:\n@* Perform Intra prediction for  luma_16x16 mode:Vertical ,described in sec 8.3.3.1\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@* availability of neighbouring pixels(Not used in this function)\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_16x16_mode_vert(UWORD8 *pu1_src,\n@                                        UWORD8 *pu1_dst,\n@                                        WORD32 src_strd,\n@                                        WORD32 dst_strd,\n@                                        WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_16x16_mode_vert_a9q\n\nih264_intra_pred_luma_16x16_mode_vert_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n    add           r0, r0, #17\n    vld1.8        {q0}, [r0]\n\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n@******************************************************************************\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_16x16_mode_horz\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_16x16 mode:horizontal\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_16x16 mode:horizontal ,described in sec 8.3.3.2\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@* availability of neighbouring pixels(Not used in this function)\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@void ih264_intra_pred_luma_16x16_mode_horz(UWORD8 *pu1_src,\n@                                         UWORD8 *pu1_dst,\n@                                         WORD32 src_strd,\n@                                         WORD32 dst_strd,\n@                                         WORD32 ui_neighboravailability)\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_16x16_mode_horz_a9q\n\nih264_intra_pred_luma_16x16_mode_horz_a9q:\n\n    stmfd         sp!, {r14}            @store register values to stack\n\n    vld1.u8       {q0}, [r0]\n    mov           r2, #14\n\n    vdup.u8       q1, d1[7]\n    vdup.u8       q2, d1[6]\n    vst1.8        {q1}, [r1], r3\n\nloop_16x16_horz:\n    vext.8        q0, q0, q0, #14\n    vst1.8        {q2}, [r1], r3\n    vdup.u8       q1, d1[7]\n    subs          r2, #2\n    vdup.u8       q2, d1[6]\n    vst1.8        {q1}, [r1], r3\n    bne           loop_16x16_horz\n\n    vext.8        q0, q0, q0, #14\n    vst1.8        {q2}, [r1], r3\n\n    ldmfd         sp!, {pc}             @Restoring registers from stack\n\n\n\n\n@******************************************************************************\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_16x16_mode_dc\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_16x16 mode:DC\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_16x16 mode:DC ,described in sec 8.3.3.3\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_16x16_mode_dc(UWORD8 *pu1_src,\n@                                       UWORD8 *pu1_dst,\n@                                       WORD32 src_strd,\n@                                       WORD32 dst_strd,\n@                                       WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_16x16_mode_dc_a9q\n\nih264_intra_pred_luma_16x16_mode_dc_a9q:\n\n    stmfd         sp!, {r4, r14}        @store register values to stack\n    ldr           r4, [sp, #8]          @r4 =>  ui_neighboravailability\n\n    ands          r2, r4, #0x01         @CHECKING IF LEFT_AVAILABLE ELSE BRANCHING TO ONLY TOP AVAILABLE\n    beq           top_available\n    ands          r2, r4, #0x04         @CHECKING IF TOP_AVAILABLE ELSE BRANCHING TO ONLY LEFT AVAILABLE\n    beq           left_available\n\n    vld1.u8       {q0}, [r0]            @BOTH LEFT AND TOP AVAILABLE\n    add           r0, r0, #17\n    vpaddl.u8     q0, q0\n    vld1.u8       {q1}, [r0]\n    vpaddl.u8     q1, q1\n    vadd.u16      q0, q0, q1\n    vadd.u16      d0, d0, d1\n    vpaddl.u16    d0, d0\n    vpaddl.u32    d0, d0\n    vqrshrun.s16  d0, q0, #5\n    vdup.u8       q0, d0[0]\n    b             str_pred\n\ntop_available:                          @ONLY TOP AVAILABLE\n    ands          r2, r4, #0x04         @CHECKING TOP AVAILABILTY OR ELSE BRANCH TO NONE AVAILABLE\n    beq           none_available\n\n    add           r0, r0, #17\n    vld1.u8       {q0}, [r0]\n    vpaddl.u8     q0, q0\n    vadd.u16      d0, d0, d1\n    vpaddl.u16    d0, d0\n    vpaddl.u32    d0, d0\n    vqrshrun.s16  d0, q0, #4\n    vdup.u8       q0, d0[0]\n    b             str_pred\n\nleft_available:                         @ONLY LEFT AVAILABLE\n    vld1.u8       {q0}, [r0]\n    vpaddl.u8     q0, q0\n    vadd.u16      d0, d0, d1\n    vpaddl.u16    d0, d0\n    vpaddl.u32    d0, d0\n    vqrshrun.s16  d0, q0, #4\n    vdup.u8       q0, d0[0]\n    b             str_pred\n\nnone_available:                         @NONE AVAILABLE\n    vmov.u8       q0, #128\n\nstr_pred:\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n    vst1.8        {q0}, [r1], r3\n\n    ldmfd         sp!, {r4, pc}         @Restoring registers from stack\n\n\n\n\n\n@******************************************************************************\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_16x16_mode_plane\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_16x16 mode:PLANE\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_16x16 mode:PLANE ,described in sec 8.3.3.4\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_16x16_mode_plane(UWORD8 *pu1_src,\n@                                        UWORD8 *pu1_dst,\n@                                        WORD32 src_strd,\n@                                        WORD32 dst_strd,\n@                                        WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_16x16_mode_plane_a9q\nih264_intra_pred_luma_16x16_mode_plane_a9q:\n\n    stmfd         sp!, {r4-r10, r12, lr}\n\n    mov           r2, r1\n    add           r1, r0, #17\n    add           r0, r0, #15\n\n    mov           r8, #9\n    sub           r1, r1, #1\n    mov           r10, r1               @top_left\n    mov           r4, #-1\n    vld1.32       d2, [r1], r8\n    ldr           r7, scratch_intrapred_addr1\nscrlbl1:\n    add           r7, r7, pc\n\n    vld1.32       d0, [r1]\n    vrev64.8      d2, d2\n    vld1.32       {q3}, [r7]\n    vsubl.u8      q0, d0, d2\n    vmovl.u8      q8, d6\n    vmul.s16      q0, q0, q8\n    vmovl.u8      q9, d7\n\n    add           r7, r0, r4, lsl #3\n    sub           r0, r7, r4, lsl #1\n    neg           lr, r4\n\n    vpadd.s16     d0, d0, d1\n\n    ldrb          r8, [r7], r4\n    ldrb          r9, [r0], lr\n\n    vpaddl.s16    d0, d0\n    sub           r12, r8, r9\n\n    ldrb          r8, [r7], r4\n\n    vpaddl.s32    d0, d0\n    ldrb          r9, [r0], lr\n    sub           r8, r8, r9\n    vshl.s32      d2, d0, #2\n    add           r12, r12, r8, lsl #1\n\n    vadd.s32      d0, d0, d2\n    ldrb          r8, [r7], r4\n    ldrb          r9, [r0], lr\n    vrshr.s32     d0, d0, #6            @ i_b = D0[0]\n    sub           r8, r8, r9\n    ldrb          r5, [r7], r4\n    add           r8, r8, r8, lsl #1\n\n    vdup.16       q2, d0[0]\n    add           r12, r12, r8\n    ldrb          r9, [r0], lr\n    vmul.s16      q0, q2, q8\n    sub           r5, r5, r9\n    vmul.s16      q1, q2, q9\n    add           r12, r12, r5, lsl #2\n\n    ldrb          r8, [r7], r4\n    ldrb          r9, [r0], lr\n    sub           r8, r8, r9\n    ldrb          r5, [r7], r4\n    add           r8, r8, r8, lsl #2\n    ldrb          r6, [r0], lr\n    add           r12, r12, r8\n    ldrb          r8, [r7], r4\n    ldrb          r9, [r0], lr\n\n    sub           r5, r5, r6\n    sub           r8, r8, r9\n    add           r5, r5, r5, lsl #1\n    rsb           r8, r8, r8, lsl #3\n    add           r12, r12, r5, lsl #1\n    ldrb          r5, [r7], r4\n    ldrb          r6, [r10]             @top_left\n    add           r12, r12, r8\n    sub           r9, r5, r6\n    ldrb          r6, [r1, #7]\n    add           r12, r12, r9, lsl #3  @ i_c = r12\n    add           r8, r5, r6\n\n    add           r12, r12, r12, lsl #2\n    lsl           r8, r8, #4            @ i_a = r8\n\n    add           r12, r12, #0x20\n    lsr           r12, r12, #6\n\n    vshl.s16      q14, q2, #3\n    vdup.16       q3, r12\n\n    vdup.16       q15, r8\n    vshl.s16      q13, q3, #3\n    vsub.s16      q15, q15, q14\n    vsub.s16      q15, q15, q13\n    vadd.s16      q14, q15, q3\n\n    mov           r0, #14\n    vadd.s16      q13, q14, q0\n    vadd.s16      q14, q14, q1\n    vqrshrun.s16  d20, q13, #5\n    vqrshrun.s16  d21, q14, #5\n\nloop_16x16_plane:\n\n    vadd.s16      q13, q13, q3\n    vadd.s16      q14, q14, q3\n    vqrshrun.s16  d22, q13, #5\n    vst1.32       {q10}, [r2], r3\n    vqrshrun.s16  d23, q14, #5\n\n    vadd.s16      q13, q13, q3\n    subs          r0, #2\n    vadd.s16      q14, q14, q3\n    vqrshrun.s16  d20, q13, #5\n    vst1.32       {q11}, [r2], r3\n    vqrshrun.s16  d21, q14, #5\n    bne           loop_16x16_plane\n\n    vadd.s16      q13, q13, q3\n    vadd.s16      q14, q14, q3\n    vqrshrun.s16  d22, q13, #5\n    vst1.32       {q10}, [r2], r3\n    vqrshrun.s16  d23, q14, #5\n    vst1.32       {q11}, [r2], r3\n\n    ldmfd         sp!, {r4-r10, r12, pc}\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_intra_pred_luma_4x4_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_intra_pred_luma_4x4_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for intra 4x4 Luma prediction .\n@*\n@* @author\n@*  Ittiam\n@*\n@* @par List of Functions:\n@*\n@*  -ih264_intra_pred_luma_4x4_mode_vert_a9q\n@*  -ih264_intra_pred_luma_4x4_mode_horz_a9q\n@*  -ih264_intra_pred_luma_4x4_mode_dc_a9q\n@*  -ih264_intra_pred_luma_4x4_mode_diag_dl_a9q\n@*  -ih264_intra_pred_luma_4x4_mode_diag_dr_a9q\n@*  -ih264_intra_pred_luma_4x4_mode_vert_r_a9q\n@*  -ih264_intra_pred_luma_4x4_mode_horz_d_a9q\n@*  -ih264_intra_pred_luma_4x4_mode_vert_l_a9q\n@*  -ih264_intra_pred_luma_4x4_mode_horz_u_a9q\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_intra_pred_filters.c\n@\n\n.text\n.p2align 2\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_4x4_mode_vert\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_4x4 mode:vertical\n@*\n@* @par Description:\n@* Perform Intra prediction for  luma_4x4 mode:vertical ,described in sec 8.3.1.2.1\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@* availability of neighbouring pixels(Not used in this function)\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_4x4_mode_vert(UWORD8 *pu1_src,\n@                                        UWORD8 *pu1_dst,\n@                                        WORD32 src_strd,\n@                                        WORD32 dst_strd,\n@                                        WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_4x4_mode_vert_a9q\n\nih264_intra_pred_luma_4x4_mode_vert_a9q:\n\n\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n    add           r0, r0, #5\n\n    vld1.32       d0[0], [r0]\n\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n\n\n\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n@******************************************************************************\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_4x4_mode_horz\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_4x4 mode:horizontal\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_4x4 mode:horizontal ,described in sec 8.3.1.2.2\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@* availability of neighbouring pixels(Not used in this function)\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@void ih264_intra_pred_luma_4x4_mode_horz(UWORD8 *pu1_src,\n@                                         UWORD8 *pu1_dst,\n@                                         WORD32 src_strd,\n@                                         WORD32 dst_strd,\n@                                         WORD32 ui_neighboravailability)\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n\n    .global ih264_intra_pred_luma_4x4_mode_horz_a9q\n\nih264_intra_pred_luma_4x4_mode_horz_a9q:\n\n\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    add           r0, r0, #3\n    mov           r2 , #-1\n\n    ldrb          r5, [r0], r2\n    vdup.u8       d0, r5\n    ldrb          r6, [r0], r2\n    vst1.32       d0[0], [r1], r3\n    vdup.u8       d1, r6\n    ldrb          r7, [r0], r2\n    vst1.32       d1[0], [r1], r3\n    vdup.u8       d2, r7\n    ldrb          r8, [r0], r2\n    vst1.32       d2[0], [r1], r3\n    vdup.u8       d3, r8\n    vst1.32       d3[0], [r1], r3\n\n\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n\n\n@******************************************************************************\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_4x4_mode_dc\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_4x4 mode:DC\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_4x4 mode:DC ,described in sec 8.3.1.2.3\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_4x4_mode_dc(UWORD8 *pu1_src,\n@                                       UWORD8 *pu1_dst,\n@                                       WORD32 src_strd,\n@                                       WORD32 dst_strd,\n@                                       WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n\n    .global ih264_intra_pred_luma_4x4_mode_dc_a9q\n\nih264_intra_pred_luma_4x4_mode_dc_a9q:\n\n\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    ldr           r4, [sp, #40]         @   r4 =>  ui_neighboravailability\n\n    ands          r5, r4, #0x01\n    beq           top_available         @LEFT NOT AVAILABLE\n\n    add           r10, r0, #3\n    mov           r2, #-1\n    ldrb          r5, [r10], r2\n    ldrb          r6, [r10], r2\n    ldrb          r7, [r10], r2\n    add           r5, r5, r6\n    ldrb          r8, [r10], r2\n    add           r5, r5, r7\n    ands          r11, r4, #0x04        @ CHECKING IF TOP_AVAILABLE  ELSE BRANCHING TO ONLY LEFT AVAILABLE\n    add           r5, r5, r8\n    beq           left_available\n    add           r10, r0, #5\n    @    BOTH LEFT AND TOP AVAILABLE\n    ldrb          r6, [r10], #1\n    ldrb          r7, [r10], #1\n    add           r5, r5, r6\n    ldrb          r8, [r10], #1\n    add           r5, r5, r7\n    ldrb          r9, [r10], #1\n    add           r5, r5, r8\n    add           r5, r5, r9\n    add           r5, r5, #4\n    lsr           r5, r5, #3\n    vdup.u8       d0, r5\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    b             end_func\n\ntop_available: @ ONLT TOP AVAILABLE\n    ands          r11, r4, #0x04        @ CHECKING TOP AVAILABILTY  OR ELSE BRANCH TO NONE AVAILABLE\n    beq           none_available\n\n    add           r10, r0, #5\n    ldrb          r6, [r10], #1\n    ldrb          r7, [r10], #1\n    ldrb          r8, [r10], #1\n    add           r5, r6, r7\n    ldrb          r9, [r10], #1\n    add           r5, r5, r8\n    add           r5, r5, r9\n    add           r5, r5, #2\n    lsr           r5, r5, #2\n    vdup.u8       d0, r5\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    b             end_func\n\nleft_available: @ONLY LEFT AVAILABLE\n    add           r5, r5, #2\n    lsr           r5, r5, #2\n    vdup.u8       d0, r5\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    b             end_func\n\nnone_available:                         @NONE AVAILABLE\n    mov           r5, #128\n    vdup.u8       d0, r5\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    vst1.32       d0[0], [r1], r3\n    b             end_func\n\n\nend_func:\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_4x4_mode_diag_dl\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Left\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Left ,described in sec 8.3.1.2.4\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_4x4_mode_diag_dl(UWORD8 *pu1_src,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_diag_dl_a9q\n\nih264_intra_pred_luma_4x4_mode_diag_dl_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n    add           r0, r0, #5\n    sub           r5, r3, #2\n    add           r6, r0, #7\n    vld1.8        {d0}, [r0]\n    vext.8        d1, d0, d0, #1\n    vext.8        d2, d0, d0, #2\n    vld1.8        {d2[6]}, [r6]\n    vaddl.u8      q10, d0, d1\n    vaddl.u8      q11, d1, d2\n    vadd.u16      q12, q10, q11\n    vqrshrun.s16  d3, q12, #2\n    vst1.32       {d3[0]}, [r1], r3\n    vext.8        d4, d3, d3, #1\n    vst1.32       {d4[0]}, [r1], r3\n    vst1.16       {d3[1]}, [r1]!\n    vst1.16       {d3[2]}, [r1], r5\n    vst1.16       {d4[1]}, [r1]!\n    vst1.16       {d4[2]}, [r1]\n\nend_func_diag_dl:\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_4x4_mode_diag_dr\n@*\n@* @brief\n@* Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Right\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Right ,described in sec 8.3.1.2.5\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_4x4_mode_diag_dr(UWORD8 *pu1_src,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_diag_dr_a9q\n\nih264_intra_pred_luma_4x4_mode_diag_dr_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n\n    vld1.u8       {d0}, [r0]\n    add           r0, r0, #1\n    vld1.u8       {d1}, [r0]\n    vext.8        d2, d1, d1, #1\n    vaddl.u8      q10, d0, d1\n    vaddl.u8      q11, d1, d2\n    vadd.u16      q12, q10, q11\n    vqrshrun.s16  d3, q12, #2\n\n    vext.8        d4, d3, d3, #1\n    sub           r5, r3, #2\n    vst1.16       {d4[1]}, [r1]!\n    vst1.16       {d4[2]}, [r1], r5\n    vst1.16       {d3[1]}, [r1]!\n    vst1.16       {d3[2]}, [r1], r5\n    vst1.32       {d4[0]}, [r1], r3\n    vst1.32       {d3[0]}, [r1], r3\n\nend_func_diag_dr:\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_4x4_mode_vert_r\n@*\n@* @brief\n@* Perform Intra prediction for  luma_4x4 mode:Vertical_Right\n@*\n@* @par Description:\n@*   Perform Intra prediction for  luma_4x4 mode:Vertical_Right ,described in sec 8.3.1.2.6\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_4x4_mode_vert_r(UWORD8 *pu1_src,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_vert_r_a9q\n\nih264_intra_pred_luma_4x4_mode_vert_r_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n\n    vld1.u8       {d0}, [r0]\n    add           r0, r0, #1\n    vld1.u8       {d1}, [r0]\n    vext.8        d2, d1, d1, #1\n    vaddl.u8      q10, d0, d1\n    vaddl.u8      q11, d1, d2\n    vadd.u16      q12, q10, q11\n    vqrshrun.s16  d4, q10, #1\n    vqrshrun.s16  d3, q12, #2\n    sub           r5, r3, #2\n    vext.8        d5, d3, d3, #3\n    vst1.32       {d4[1]}, [r1], r3\n    vst1.32       {d5[0]}, [r1], r3\n    sub           r8, r3, #3\n    vst1.u8       {d3[2]}, [r1]!\n    vst1.16       {d4[2]}, [r1]!\n    vst1.u8       {d4[6]}, [r1], r8\n    vst1.u8       {d3[1]}, [r1]!\n    vst1.16       {d5[0]}, [r1]!\n    vst1.u8       {d5[2]}, [r1]\n\n\nend_func_vert_r:\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_4x4_mode_horz_d\n@*\n@* @brief\n@* Perform Intra prediction for  luma_4x4 mode:Horizontal_Down\n@*\n@* @par Description:\n@*   Perform Intra prediction for  luma_4x4 mode:Horizontal_Down ,described in sec 8.3.1.2.7\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_4x4_mode_horz_d(UWORD8 *pu1_src,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_horz_d_a9q\n\nih264_intra_pred_luma_4x4_mode_horz_d_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n    vld1.u8       {d0}, [r0]\n    add           r0, r0, #1\n    vld1.u8       {d1}, [r0]\n    vext.8        d2, d1, d0, #1\n    vaddl.u8      q10, d0, d1\n    vaddl.u8      q11, d1, d2\n    vadd.u16      q12, q10, q11\n    vqrshrun.s16  d4, q10, #1\n    vqrshrun.s16  d5, q12, #2\n    sub           r5, r3, #2\n    vmov.8        d6, d5\n    vtrn.8        d4, d5                @\n    vst1.u16      {d5[1]}, [r1]!\n    vst1.16       {d6[2]}, [r1], r5\n    vst1.u16      {d4[1]}, [r1]!\n    vst1.16       {d5[1]}, [r1], r5\n    vst1.u16      {d5[0]}, [r1]!\n    vst1.16       {d4[1]}, [r1], r5\n    vst1.u16      {d4[0]}, [r1]!\n    vst1.16       {d5[0]}, [r1], r5\n\nend_func_horz_d:\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_4x4_mode_vert_l\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_4x4 mode:Vertical_Left\n@*\n@* @par Description:\n@*   Perform Intra prediction for  luma_4x4 mode:Vertical_Left ,described in sec 8.3.1.2.8\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_4x4_mode_vert_l(UWORD8 *pu1_src,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_vert_l_a9q\n\nih264_intra_pred_luma_4x4_mode_vert_l_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    add           r0, r0, #4\n    vld1.u8       {d0}, [r0]\n    add           r0, r0, #1\n    vld1.u8       {d1}, [r0]\n    vext.8        d2, d1, d0, #1\n    vaddl.u8      q10, d0, d1\n    vaddl.u8      q11, d1, d2\n    vadd.u16      q12, q10, q11\n    vqrshrun.s16  d4, q10, #1\n    vqrshrun.s16  d5, q12, #2\n    vext.8        d6, d4, d4, #1\n    vext.8        d7, d5, d5, #1\n    vst1.32       {d6[0]}, [r1], r3\n    vext.8        d16, d4, d4, #2\n    vext.8        d17, d5, d5, #2\n    vst1.32       {d7[0]}, [r1], r3\n    vst1.32       {d16[0]}, [r1], r3\n    vst1.32       {d17[0]}, [r1], r3\n\n\n\nend_func_vert_l:\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_4x4_mode_horz_u\n@*\n@* @brief\n@*     Perform Intra prediction for  luma_4x4 mode:Horizontal_Up\n@*\n@* @par Description:\n@*      Perform Intra prediction for  luma_4x4 mode:Horizontal_Up ,described in sec 8.3.1.2.9\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_4x4_mode_horz_u(UWORD8 *pu1_src,\n@                                           UWORD8 *pu1_dst,\n@                                           WORD32 src_strd,\n@                                           WORD32 dst_strd,\n@                                           WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_horz_u_a9q\n\nih264_intra_pred_luma_4x4_mode_horz_u_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    mov           r10, r0\n    vld1.u8       {d0}, [r0]\n    ldrb          r9, [r0], #1\n    vext.8        d1, d0, d0, #1\n    vld1.u8       {d0[7]}, [r10]\n    vext.8        d2, d1, d1, #1\n    vaddl.u8      q10, d0, d1\n    vaddl.u8      q11, d1, d2\n    vadd.u16      q12, q10, q11\n    vqrshrun.s16  d4, q10, #1\n    vqrshrun.s16  d5, q12, #2\n    vmov          d6, d4\n    vext.8        d6, d5, d4, #1\n    vst1.8        {d4[2]}, [r1]!\n    vst1.8        {d6[0]}, [r1]!\n    vtrn.8        d6, d5                @\n    sub           r5, r3, #2\n    vtrn.8        d4, d6                @\n    vdup.8        d7, r9\n    vst1.16       {d6[0]}, [r1], r5\n    vst1.16       {d6[0]}, [r1]!\n    vst1.16       {d5[3]}, [r1], r5\n    vst1.16       {d5[3]}, [r1]!\n    vst1.16       {d7[3]}, [r1], r5\n    vst1.32       {d7[0]}, [r1], r3\n\nend_func_horz_u:\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_intra_pred_luma_8x8_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_intra_pred_luma_8x8_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for intra 8x8 Luma prediction .\n@*\n@* @author\n@*  Ittiam\n@*\n@* @par List of Functions:\n@*\n@*  -ih264_intra_pred_luma_8x8_mode_ref_filtering_a9q\n@*  -ih264_intra_pred_luma_8x8_mode_vert_a9q\n@*  -ih264_intra_pred_luma_8x8_mode_horz_a9q\n@*  -ih264_intra_pred_luma_8x8_mode_dc_a9q\n@*  -ih264_intra_pred_luma_8x8_mode_diag_dl_a9q\n@*  -ih264_intra_pred_luma_8x8_mode_diag_dr_a9q\n@*  -ih264_intra_pred_luma_8x8_mode_vert_r_a9q\n@*  -ih264_intra_pred_luma_8x8_mode_horz_d_a9q\n@*  -ih264_intra_pred_luma_8x8_mode_vert_l_a9q\n@*  -ih264_intra_pred_luma_8x8_mode_horz_u_a9q\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n\n@* All the functions here are replicated from ih264_intra_pred_filters.c\n@\n\n.text\n.p2align 2\n\n    .extern ih264_gai1_intrapred_luma_8x8_horz_u\n.hidden ih264_gai1_intrapred_luma_8x8_horz_u\nscratch_intrapred_addr_8x8:\n    .long ih264_gai1_intrapred_luma_8x8_horz_u -  scrlb8x8l2 - 8\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_8x8_mode_ref_filtering\n@*\n@* @brief\n@* Reference sample filtering process for Intra_8x8 sample prediction\n@*\n@* @par Description:\n@*  Perform Reference sample filtering process for Intra_8x8 sample prediction ,described in sec 8.3.2.2.1\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride [Not used]\n@*\n@* @param[in] dst_strd\n@*  integer destination stride[Not used]\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels[Not used]\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_8x8_mode_ref_filtering(UWORD8 *pu1_src,\n@                                                 UWORD8 *pu1_dst)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n\n\n    .global ih264_intra_pred_luma_8x8_mode_ref_filtering_a9q\n\nih264_intra_pred_luma_8x8_mode_ref_filtering_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vpush         {d8-d15}\n\n    vld1.u8       {q0}, [r0]!           @\n    vld1.u8       {q1}, [r0]\n    add           r0, r0, #8            @\n    vext.8        q2, q0, q1, #1\n    vext.8        q3, q1, q1, #1\n    vext.8        q4, q2, q3, #1\n    vext.8        q5, q3, q3, #1\n    vld1.8        {d10[7]}, [r0]        @ LOADING SRC[24] AGIN TO THE END FOR p'[ 15, -1 ] = ( p[ 14, -1 ] + 3 * p[ 15, -1 ] + 2 ) >> 2\n    vaddl.u8      q10, d0, d4\n    vaddl.u8      q7, d0, d0            @    SPECIAL CASE FOR p'[ -1 ,7 ] = ( p[ -1, 6 ] + 3 * p[ -1, 7 ] + 2 ) >> 2\n    vadd.u16      q7, q10, q7\n    vaddl.u8      q11, d1, d5\n    vqrshrun.s16  d14, q7, #2\n    vaddl.u8      q12, d4, d8\n    vaddl.u8      q13, d5, d9\n    vst1.8        {d14[0]}, [r1]!\n    vadd.u16      q12, q10, q12\n    vadd.u16      q13, q11, q13\n    vaddl.u8      q9, d2, d6\n    vaddl.u8      q8, d6, d10\n    vqrshrun.s16  d4, q12, #2\n    vqrshrun.s16  d5, q13, #2\n    vadd.u16      q6, q8, q9\n    vst1.8        {q2}, [r1]!\n    vqrshrun.s16  d6, q6, #2\n    vst1.8        {d6}, [r1]\n\n\nend_func_ref_filt:\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_8x8_mode_vert\n@*\n@* @brief\n@*   Perform Intra prediction for  luma_8x8 mode:vertical\n@*\n@* @par Description:\n@* Perform Intra prediction for  luma_8x8 mode:vertical ,described in sec 8.3.2.2.2\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@* availability of neighbouring pixels(Not used in this function)\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_8x8_mode_vert(UWORD8 *pu1_src,\n@                                        UWORD8 *pu1_dst,\n@                                        WORD32 src_strd,\n@                                        WORD32 dst_strd,\n@                                        WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_vert_a9q\n\nih264_intra_pred_luma_8x8_mode_vert_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n    add           r0, r0, #9\n    vld1.8        d0, [r0]\n\n    vst1.8        d0, [r1], r3\n    vst1.8        d0, [r1], r3\n    vst1.8        d0, [r1], r3\n    vst1.8        d0, [r1], r3\n    vst1.8        d0, [r1], r3\n    vst1.8        d0, [r1], r3\n    vst1.8        d0, [r1], r3\n    vst1.8        d0, [r1], r3\n\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n@******************************************************************************\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_8x8_mode_horz\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_8x8 mode:horizontal\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_8x8 mode:horizontal ,described in sec 8.3.2.2.2\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@* availability of neighbouring pixels(Not used in this function)\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@void ih264_intra_pred_luma_8x8_mode_horz(UWORD8 *pu1_src,\n@                                         UWORD8 *pu1_dst,\n@                                         WORD32 src_strd,\n@                                         WORD32 dst_strd,\n@                                         WORD32 ui_neighboravailability)\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_horz_a9q\n\nih264_intra_pred_luma_8x8_mode_horz_a9q:\n\n    stmfd         sp!, {r14}            @store register values to stack\n\n    vld1.u8       {d0}, [r0]\n    mov           r2, #6\n\n    vdup.u8       d1, d0[7]\n    vdup.u8       d2, d0[6]\n    vst1.8        {d1}, [r1], r3\n\nloop_8x8_horz:\n    vext.8        d0, d0, d0, #6\n    vst1.8        {d2}, [r1], r3\n    vdup.u8       d1, d0[7]\n    subs          r2, #2\n    vdup.u8       d2, d0[6]\n    vst1.8        {d1}, [r1], r3\n    bne           loop_8x8_horz\n\n    vext.8        d0, d0, d0, #6\n    vst1.8        {d2}, [r1], r3\n\n    ldmfd         sp!, {pc}             @restoring registers from stack\n\n\n\n\n\n@******************************************************************************\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_8x8_mode_dc\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_8x8 mode:DC\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_8x8 mode:DC ,described in sec 8.3.2.2.3\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_8x8_mode_dc(UWORD8 *pu1_src,\n@                                       UWORD8 *pu1_dst,\n@                                       WORD32 src_strd,\n@                                       WORD32 dst_strd,\n@                                       WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_dc_a9q\n\nih264_intra_pred_luma_8x8_mode_dc_a9q:\n\n    stmfd         sp!, {r4, r14}        @store register values to stack\n    ldr           r4, [sp, #8]          @r4 =>  ui_neighboravailability\n\n    ands          r2, r4, #0x01         @CHECKING IF LEFT_AVAILABLE ELSE BRANCHING TO ONLY TOP AVAILABLE\n    beq           top_available\n    ands          r2, r4, #0x04         @CHECKING IF TOP_AVAILABLE ELSE BRANCHING TO ONLY LEFT AVAILABLE\n    beq           left_available\n\n    vld1.u8       {d0}, [r0]            @BOTH LEFT AND TOP AVAILABLE\n    add           r0, r0, #9\n    vld1.u8       {d1}, [r0]\n    vpaddl.u8     q0, q0\n    vadd.u16      d0, d0, d1\n    vpaddl.u16    d0, d0\n    vpaddl.u32    d0, d0\n    vqrshrun.s16  d0, q0, #4\n    vdup.u8       d0, d0[0]\n    b             str_pred\n\ntop_available:                          @ONLY TOP AVAILABLE\n    ands          r2, r4, #0x04         @CHECKING TOP AVAILABILTY OR ELSE BRANCH TO NONE AVAILABLE\n    beq           none_available\n\n    add           r0, r0, #9\n    vld1.u8       {d0}, [r0]\n    vpaddl.u8     d0, d0\n    vpaddl.u16    d0, d0\n    vpaddl.u32    d0, d0\n    vqrshrun.s16  d0, q0, #3\n    vdup.u8       d0, d0[0]\n    b             str_pred\n\nleft_available:                         @ONLY LEFT AVAILABLE\n    vld1.u8       {d0}, [r0]\n    vpaddl.u8     d0, d0\n    vpaddl.u16    d0, d0\n    vpaddl.u32    d0, d0\n    vqrshrun.s16  d0, q0, #3\n    vdup.u8       d0, d0[0]\n    b             str_pred\n\nnone_available:                         @NONE AVAILABLE\n    vmov.u8       q0, #128\n\nstr_pred:\n    vst1.8        {d0}, [r1], r3\n    vst1.8        {d0}, [r1], r3\n    vst1.8        {d0}, [r1], r3\n    vst1.8        {d0}, [r1], r3\n    vst1.8        {d0}, [r1], r3\n    vst1.8        {d0}, [r1], r3\n    vst1.8        {d0}, [r1], r3\n    vst1.8        {d0}, [r1], r3\n\n    ldmfd         sp!, {r4, pc}         @Restoring registers from stack\n\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_8x8_mode_diag_dl\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Left\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Left ,described in sec 8.3.2.2.4\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_8x8_mode_diag_dl(UWORD8 *pu1_src,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_8x8_mode_diag_dl_a9q\n\nih264_intra_pred_luma_8x8_mode_diag_dl_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n    add           r0, r0, #9\n    sub           r5, r3, #4\n    add           r6, r0, #15\n    vld1.8        {q0}, [r0]\n    vext.8        q2, q0, q0, #2\n    vext.8        q1, q0, q0, #1\n    vld1.8        {d5[6]}, [r6]\n    @ q1 = q0 shifted to left once\n    @ q2 = q1 shifted to left once\n    vaddl.u8      q10, d0, d2           @Adding for FILT121\n    vaddl.u8      q11, d1, d3\n    vaddl.u8      q12, d2, d4\n    vaddl.u8      q13, d3, d5\n    vadd.u16      q12, q10, q12\n    vadd.u16      q13, q11, q13\n\n    vqrshrun.s16  d4, q12, #2\n    vqrshrun.s16  d5, q13, #2\n    @Q2 has all FILT121 values\n    vst1.8        {d4}, [r1], r3\n    vext.8        q9, q2, q2, #1\n    vext.8        q8, q9, q9, #1\n    vst1.8        {d18}, [r1], r3\n    vext.8        q15, q8, q8, #1\n    vst1.8        {d16}, [r1], r3\n    vst1.8        {d30}, [r1], r3\n    vst1.32       {d4[1]}, [r1]!\n    vst1.32       {d5[0]}, [r1], r5\n    vst1.32       {d18[1]}, [r1]!\n    vst1.32       {d19[0]}, [r1], r5\n    vst1.32       {d16[1]}, [r1]!\n    vst1.32       {d17[0]}, [r1], r5\n    vst1.32       {d30[1]}, [r1]!\n    vst1.32       {d31[0]}, [r1], r5\n\n\nend_func_diag_dl:\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_8x8_mode_diag_dr\n@*\n@* @brief\n@* Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Right\n@*\n@* @par Description:\n@*  Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Right ,described in sec 8.3.2.2.5\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_8x8_mode_diag_dr(UWORD8 *pu1_src,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_diag_dr_a9q\n\nih264_intra_pred_luma_8x8_mode_diag_dr_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n\n    vld1.u8       {q0}, [r0]\n    add           r0, r0, #1\n    vld1.u8       {q1}, [r0]\n    vext.8        q2, q1, q1, #1\n    @ q1 = q0 shifted to left once\n    @ q2 = q1 shifted to left once\n    vaddl.u8      q10, d0, d2           @Adding for FILT121\n    vaddl.u8      q11, d1, d3\n    vaddl.u8      q12, d2, d4\n    vaddl.u8      q13, d3, d5\n    vadd.u16      q12, q10, q12\n    vadd.u16      q13, q11, q13\n    vqrshrun.s16  d4, q12, #2\n    vqrshrun.s16  d5, q13, #2\n    @Q2 has all FILT121 values\n    sub           r5, r3, #4\n    vext.8        q9, q2, q2, #15\n    vst1.8        {d19}, [r1], r3\n    vext.8        q8, q9, q9, #15\n    vst1.8        {d17}, [r1], r3\n    vext.8        q15, q8, q8, #15\n    vst1.8        {d31}, [r1], r3\n    vst1.32       {d4[1]}, [r1]!\n    vst1.32       {d5[0]}, [r1], r5\n    vst1.32       {d18[1]}, [r1]!\n    vst1.32       {d19[0]}, [r1], r5\n    vst1.32       {d16[1]}, [r1]!\n    vst1.32       {d17[0]}, [r1], r5\n    vst1.32       {d30[1]}, [r1]!\n    vst1.32       {d31[0]}, [r1], r5\n    vst1.8        {d4}, [r1], r3\n\nend_func_diag_dr:\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_8x8_mode_vert_r\n@*\n@* @brief\n@* Perform Intra prediction for  luma_8x8 mode:Vertical_Right\n@*\n@* @par Description:\n@*   Perform Intra prediction for  luma_8x8 mode:Vertical_Right ,described in sec 8.3.2.2.6\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_8x8_mode_vert_r(UWORD8 *pu1_src,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_vert_r_a9q\n\nih264_intra_pred_luma_8x8_mode_vert_r_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n\n    vld1.u8       {q0}, [r0]\n    add           r0, r0, #1\n    vld1.u8       {q1}, [r0]\n    vext.8        q2, q1, q1, #1\n    @ q1 = q0 shifted to left once\n    @ q2 = q1 shifted to left once\n    vaddl.u8      q10, d0, d2\n    vaddl.u8      q11, d1, d3\n    vaddl.u8      q12, d2, d4\n    vaddl.u8      q13, d3, d5\n    vadd.u16      q12, q10, q12\n    vadd.u16      q13, q11, q13\n\n    vqrshrun.s16  d4, q10, #1\n    vqrshrun.s16  d5, q11, #1\n    vqrshrun.s16  d6, q12, #2\n    vqrshrun.s16  d7, q13, #2\n    @Q2 has all FILT11 values\n    @Q3 has all FILT121 values\n    sub           r5, r3, #6\n    sub           r6, r3, #4\n    vst1.8        {d5}, [r1], r3        @ row 0\n    vext.8        q9, q3, q3, #15\n    vmov.8        q11, q9\n    vext.8        q8, q2, q2, #1\n    vst1.8        {d19}, [r1], r3       @row 1\n\n    vmov.8        q15, q8\n    vext.8        q10, q2, q2, #15\n    vuzp.8        q8, q9\n    @row 2\n    vext.8        q14, q8, q8, #1\n    vst1.8        {d21}, [r1]\n    vst1.8        {d6[6]}, [r1], r3\n    @row 3\n\n    vst1.16       {d29[1]}, [r1]!\n    vst1.32       {d7[0]}, [r1]!\n    vst1.16       {d7[2]}, [r1], r5\n@row 4\n    vst1.16       {d19[1]}, [r1]!\n    vst1.32       {d5[0]}, [r1]!\n    vst1.16       {d5[2]}, [r1], r5\n\n@row 5\n    vext.8        q13, q9, q9, #1\n    vst1.16       {d17[1]}, [r1]!\n    vst1.32       {d23[0]}, [r1]!\n    vst1.16       {d23[2]}, [r1], r5\n\n\n@row 6\n    vst1.16       {d27[0]}, [r1]!\n    vst1.8        {d27[2]}, [r1]!\n    vst1.8        {d5[0]}, [r1]!\n    vst1.32       {d31[0]}, [r1], r6\n@row 7\n    vst1.32       {d29[0]}, [r1]!\n    vst1.32       {d7[0]}, [r1]!\n\n\n\nend_func_vert_r:\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_8x8_mode_horz_d\n@*\n@* @brief\n@* Perform Intra prediction for  luma_8x8 mode:Horizontal_Down\n@*\n@* @par Description:\n@*   Perform Intra prediction for  luma_8x8 mode:Horizontal_Down ,described in sec 8.3.2.2.7\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_8x8_mode_horz_d(UWORD8 *pu1_src,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_8x8_mode_horz_d_a9q\n\nih264_intra_pred_luma_8x8_mode_horz_d_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vpush         {d8-d15}\n\n    vld1.u8       {q0}, [r0]\n    add           r0, r0, #1\n    vld1.u8       {q1}, [r0]\n    vext.8        q2, q1, q1, #1\n    @ q1 = q0 shifted to left once\n    @ q2 = q1 shifted to left once\n    vaddl.u8      q10, d0, d2\n    vaddl.u8      q11, d1, d3\n    vaddl.u8      q12, d2, d4\n    vaddl.u8      q13, d3, d5\n    vadd.u16      q12, q10, q12\n    vadd.u16      q13, q11, q13\n\n    vqrshrun.s16  d4, q10, #1\n    vqrshrun.s16  d5, q11, #1\n    vqrshrun.s16  d6, q12, #2\n    vqrshrun.s16  d7, q13, #2\n    @Q2 has all FILT11 values\n    @Q3 has all FILT121 values\n    vmov.8        q4, q2\n    vmov.8        q5, q3\n    sub           r6, r3, #6\n    vtrn.8        q4, q5                @\n    vmov.8        q6, q4\n    vmov.8        q7, q5\n    sub           r5, r3, #4\n    vtrn.16       q6, q7\n    vext.8        q8, q3, q3, #14\n    @ROW 0\n    vst1.8        {d17}, [r1]\n    vst1.16       {d10[3]}, [r1], r3\n\n    @ROW 1\n    vst1.32       {d14[1]}, [r1]!\n    vst1.32       {d7[0]}, [r1], r5\n    @ROW 2\n    vst1.16       {d10[2]}, [r1]!\n    vst1.32       {d14[1]}, [r1]!\n    vst1.16       {d7[0]}, [r1], r6\n    @ROW 3\n    vst1.32       {d12[1]}, [r1]!\n    vst1.32       {d14[1]}, [r1], r5\n    @ROW 4\n    vst1.16       {d14[1]}, [r1]!\n    vst1.32       {d12[1]}, [r1]!\n    vst1.16       {d14[2]}, [r1], r6\n    @ROW 5\n    vst1.32       {d14[0]}, [r1]!\n    vst1.32       {d12[1]}, [r1], r5\n    @ROW 6\n    vst1.16       {d10[0]}, [r1]!\n    vst1.16       {d8[1]}, [r1]!\n    vst1.16       {d14[1]}, [r1]!\n    vst1.16       {d12[2]}, [r1], r6\n    @ROW 7\n    vst1.32       {d12[0]}, [r1]!\n    vst1.32       {d14[0]}, [r1], r5\n\nend_func_horz_d:\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_8x8_mode_vert_l\n@*\n@* @brief\n@*  Perform Intra prediction for  luma_8x8 mode:Vertical_Left\n@*\n@* @par Description:\n@*   Perform Intra prediction for  luma_8x8 mode:Vertical_Left ,described in sec 8.3.2.2.8\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_8x8_mode_vert_l(UWORD8 *pu1_src,\n@                                            UWORD8 *pu1_dst,\n@                                            WORD32 src_strd,\n@                                            WORD32 dst_strd,\n@                                            WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_vert_l_a9q\n\nih264_intra_pred_luma_8x8_mode_vert_l_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @Restoring registers from stack\n    vpush         {d8-d15}\n\n    add           r0, r0, #9\n    vld1.u8       {q0}, [r0]\n    add           r0, r0, #1\n    vld1.u8       {q1}, [r0]\n    vext.8        q2, q1, q1, #1\n    vaddl.u8      q10, d0, d2\n    vaddl.u8      q11, d1, d3\n    vaddl.u8      q12, d2, d4\n    vaddl.u8      q13, d3, d5\n    vadd.u16      q12, q10, q12\n    vadd.u16      q13, q11, q13\n\n    vqrshrun.s16  d4, q10, #1\n    vqrshrun.s16  d5, q11, #1\n    vqrshrun.s16  d6, q12, #2\n    vext.8        q4, q2, q2, #1\n    vqrshrun.s16  d7, q13, #2\n    @Q2 has all FILT11 values\n    @Q3 has all FILT121 values\n\n    vext.8        q5, q3, q3, #1\n    @ROW 0,1\n    vst1.8        {d4}, [r1], r3\n    vst1.8        {d6}, [r1], r3\n\n    vext.8        q6, q4, q4, #1\n    vext.8        q7, q5, q5, #1\n    @ROW 2,3\n    vst1.8        {d8}, [r1], r3\n    vst1.8        {d10}, [r1], r3\n\n    vext.8        q8, q6, q6, #1\n    vext.8        q9, q7, q7, #1\n    @ROW 4,5\n    vst1.8        {d12}, [r1], r3\n    vst1.8        {d14}, [r1], r3\n    @ROW 6,7\n    vst1.8        {d16}, [r1], r3\n    vst1.8        {d18}, [r1], r3\n\nend_func_vert_l:\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@*ih264_intra_pred_luma_8x8_mode_horz_u\n@*\n@* @brief\n@*     Perform Intra prediction for  luma_8x8 mode:Horizontal_Up\n@*\n@* @par Description:\n@*      Perform Intra prediction for  luma_8x8 mode:Horizontal_Up ,described in sec 8.3.2.2.9\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] dst_strd\n@*  integer destination stride\n@*\n@* @param[in] ui_neighboravailability\n@*  availability of neighbouring pixels\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@void ih264_intra_pred_luma_8x8_mode_horz_u(UWORD8 *pu1_src,\n@                                           UWORD8 *pu1_dst,\n@                                           WORD32 src_strd,\n@                                           WORD32 dst_strd,\n@                                           WORD32 ui_neighboravailability)\n\n@**************Variables Vs Registers*****************************************\n@   r0 => *pu1_src\n@   r1 => *pu1_dst\n@   r2 =>  src_strd\n@   r3 =>  dst_strd\n@   r4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_8x8_mode_horz_u_a9q\n\nih264_intra_pred_luma_8x8_mode_horz_u_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @store register values to stack\n    vpush         {d8-d15}\n\n    vld1.u8       {q0}, [r0]\n    vld1.u8       {d1[7]}, [r0]\n    vext.8        q1, q0, q0, #1\n    vext.8        q2, q1, q1, #1\n    @ LOADING V TABLE\n    ldr           r12, scratch_intrapred_addr_8x8\nscrlb8x8l2:\n    add           r12, r12, pc\n    vaddl.u8      q10, d0, d2\n    vaddl.u8      q11, d1, d3\n    vaddl.u8      q12, d2, d4\n    vaddl.u8      q13, d3, d5\n    vadd.u16      q12, q10, q12\n    vadd.u16      q13, q11, q13\n    vld1.u8       {q5}, [r12]\n    vqrshrun.s16  d4, q10, #1\n    vqrshrun.s16  d5, q11, #1\n    vqrshrun.s16  d6, q12, #2\n    vqrshrun.s16  d7, q13, #2\n    @Q2 has all FILT11 values\n    @Q3 has all FILT121 values\n    vtbl.u8       d12, {q2, q3}, d10\n    vdup.u8       q7, d5[7]             @\n    vtbl.u8       d13, {q2, q3}, d11\n    vext.8        q8, q6, q7, #2\n    vext.8        q9, q8, q7, #2\n    vst1.8        {d12}, [r1], r3\n    vext.8        q10, q9, q7, #2\n    vst1.8        {d16}, [r1], r3\n    vst1.8        {d18}, [r1], r3\n    vst1.8        {d20}, [r1], r3\n    vst1.8        {d13}, [r1], r3\n    vst1.8        {d17}, [r1], r3\n    vst1.8        {d19}, [r1], r3\n    vst1.8        {d21}, [r1], r3\n\n\nend_func_horz_u:\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r12, pc}     @Restoring registers from stack\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_iquant_itrans_recon_a9.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@ *******************************************************************************\n@ * @file\n@ *  ih264_iquant_itrans_recon_a9.s\n@ *\n@ * @brief\n@ *  Contains function definitions for single stage  inverse transform\n@ *\n@ * @author\n@ *  Mohit\n@ *  Harinarayanaan\n@ *\n@ * @par List of Functions:\n@ *  - ih264_iquant_itrans_recon_4x4_a9()\n@ *  - ih264_iquant_itrans_recon_8x8_a9()\n@ *  - ih264_iquant_itrans_recon_chroma_4x4_a9()\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n@*\n@**\n@ *******************************************************************************\n@ *\n@ * @brief\n@ *  This function performs inverse quant and Inverse transform type Ci4 for 4*4 block\n@ *\n@ * @par Description:\n@ *  Performs inverse transform Ci4 and adds the residue to get the\n@ *  reconstructed block\n@ *\n@ * @param[in] pi2_src\n@ *  Input 4x4 coefficients\n@ *\n@ * @param[in] pu1_pred\n@ *  Prediction 4x4 block\n@ *\n@ * @param[out] pu1_out\n@ *  Output 4x4 block\n@ *\n@ * @param[in] u4_qp_div_6\n@ *     QP\n@ *\n@ * @param[in] pu2_weigh_mat\n@ * Pointer to weight matrix\n@ *\n@ * @param[in] pred_strd,\n@ *  Prediction stride\n@ *\n@ * @param[in] out_strd\n@ *  Output Stride\n@ *\n@ *@param[in] pi2_tmp\n@ * temporary buffer of size 1*16\n@ *\n@ * @param[in] pu2_iscal_mat\n@ * Pointer to the inverse quantization matrix\n@ *\n@ * @returns  Void\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n@ *\n@void ih264_iquant_itrans_recon_4x4(WORD16 *pi2_src,\n@                                   UWORD8 *pu1_pred,\n@                                   UWORD8 *pu1_out,\n@                                   WORD32 pred_strd,\n@                                   WORD32 out_strd,\n@                                   const UWORD16 *pu2_iscal_mat,\n@                                   const UWORD16 *pu2_weigh_mat,\n@                                   UWORD32 u4_qp_div_6,\n@                                   WORD32 *pi4_tmp,\n@                                   WORD32 iq_start_idx\n@                                   WORD16 *pi2_dc_ld_addr)\n@**************Variables Vs Registers*****************************************\n@r0 => *pi2_src\n@r1 => *pu1_pred\n@r2 => *pu1_out\n@r3 =>  pred_strd\n@r4 =>  out_strd\n@r5 =>  *pu2_iscal_mat\n@r6 =>  *pu2_weigh_mat\n@r7 =>  u4_qp_div_6\n@r8 =>  iq_start_idx\n@r10=>  pi2_dc_ld_addr\n.text\n.syntax unified\n.p2align 2\n\n    .global ih264_iquant_itrans_recon_4x4_a9\n\nih264_iquant_itrans_recon_4x4_a9:\n\n@VLD4.S16 is used because the pointer is incremented by SUB_BLK_WIDTH_4x4\n@If the macro value changes need to change the instruction according to it.\n@Only one shift is done in horizontal inverse because,\n@if u4_qp_div_6 is lesser than 4 then shift value will be neagative and do negative left shift, in this case rnd_factor has value\n@if u4_qp_div_6 is greater than 4 then shift value will be positive and do left shift, here rnd_factor is 0\n\n    stmfd         sp!, {r4-r12, r14}    @stack stores the values of the arguments\n    ldr           r7, [sp, #52]         @Loads u4_qp_div_6\n    ldr           r4, [sp, #40]         @Loads out_strd\n    vdup.s32      q15, r7               @Populate the u4_qp_div_6 in Q15\n    ldr           r5, [sp, #44]         @Loads *pu2_iscal_mat\n\n    ldr           r6, [sp, #48]         @Loads *pu2_weigh_mat\n\n    ldr           r8, [sp, #60]         @Loads iq_start_idx\n\n    ldr           r10, [sp, #64]        @Load alternate dc address\n\n    vpush         {d8-d15}\n@=======================DEQUANT FROM HERE===================================\n\n    vld4.s16      {d20, d21, d22, d23}, [r5] @Load pu2_iscal_mat[i], i =0..15\n    vld4.s16      {d26, d27, d28, d29}, [r6] @pu2_weigh_mat[i], i =0..15\n    vmul.s16      q10, q10, q13         @x[i]=(scale[i] * dequant[i]) where i = 0..7\n    vld4.s16      {d16, d17, d18, d19}, [r0] @pi2_src_tmp[i], i =0..15\n\n    vmul.s16      q11, q11, q14         @x[i]=(scale[i] * dequant[i]) where i = 8..15\n\n    subs          r8, r8, #1            @ if r8 == 1 => intra case , so result of subtraction is zero and Z flag is set\n    ldrsheq       r9, [r10]             @ Loads signed halfword pi2_dc_ld_addr[0], if r8==1\n\n    vmull.s16     q0, d16, d20          @ Q0  = p[i] = (x[i] * trns_coeff[i]) where i = 0..3\n    vmull.s16     q1, d17, d21          @ Q1  = p[i] = (x[i] * trns_coeff[i]) where i = 4..7\n    vmull.s16     q2, d18, d22          @ Q2  = p[i] = (x[i] * trns_coeff[i]) where i = 8..11\n    vmull.s16     q3, d19, d23          @ Q3  = p[i] = (x[i] * trns_coeff[i]) where i = 12..15\n\n    vshl.s32      q0, q0, q15           @ Q0  = q[i] = (p[i] << (qP/6)) where i = 0..3\n    vshl.s32      q1, q1, q15           @ Q1  = q[i] = (p[i] << (qP/6)) where i = 4..7\n    vshl.s32      q2, q2, q15           @ Q2  = q[i] = (p[i] << (qP/6)) where i = 8..11\n    vshl.s32      q3, q3, q15           @ Q3  = q[i] = (p[i] << (qP/6)) where i = 12..15\n\n    vqrshrn.s32   d0, q0, #0x4          @ D0  = c[i] = ((q[i] + 32) >> 4) where i = 0..3\n    vqrshrn.s32   d1, q1, #0x4          @ D1  = c[i] = ((q[i] + 32) >> 4) where i = 4..7\n    vqrshrn.s32   d2, q2, #0x4          @ D2  = c[i] = ((q[i] + 32) >> 4) where i = 8..11\n    vqrshrn.s32   d3, q3, #0x4          @ D3  = c[i] = ((q[i] + 32) >> 4) where i = 12..15\n\n    vmoveq.16     d0[0], r9             @ Restore dc value in case of intra, i.e. r8 == 1\n\n@========= PROCESS IDCT FROM HERE =======\n@Steps for Stage 1:\n@------------------\n    vld1.32       d30[0], [r1], r3      @I row Load pu1_pred buffer\n    vadd.s16      d4, d0, d2            @x0 = q0 + q1;\n\n    vsub.s16      d5, d0, d2            @x1 = q0 - q1;\n\n    vshr.s16      d8, d1, #1            @q0>>1\n    vshr.s16      d9, d3, #1            @q1>>1\n\n    vsub.s16      d6, d8, d3            @x2 = (q0 >> 1) -  q1;\n    vadd.s16      d7, d1, d9            @x3 = q0+ (q1 >> 1);\n    vld1.32       d30[1], [r1], r3      @II row Load pu1_pred buffer\n\n    vswp          d6, d7                @Reverse positions of x2 and x3\n\n    vsub.s16      q6, q2, q3            @x0-x3 and x1-x2 combined\n    vadd.s16      q5, q2, q3            @x0 + x3 and x1+x2 combined\n\n    vld1.32       d31[0], [r1], r3      @III row Load pu1_pred buf\n\n    vswp          d12, d13\n@Steps for Stage 2:\n@------------------\n    vtrn.16       d10, d11\n    vtrn.16       d12, d13\n    vtrn.32       d10, d12\n    vtrn.32       d11, d13\n    vadd.s16      d14, d10, d12         @x0 = q0 + q1;\n\n    vsub.s16      d15, d10, d12         @x1 = q0 - q1;\n\n    vshr.s16      d18, d11, #1          @q0>>1\n    vshr.s16      d19, d13, #1          @q1>>1\n\n    vsub.s16      d16, d18, d13         @x2 = (q0 >> 1) -  q1;\n    vadd.s16      d17, d11, d19         @x3 = q0+ (q1 >> 1);\n\n    vld1.32       d31[1], [r1], r3      @IV row Load pu1_pred buffer\n    vswp          d16, d17              @Reverse positions of x2 and x3\n\n    vsub.s16      q11, q7, q8           @x0-x3 and x1-x2 combined\n    vadd.s16      q10, q7, q8           @x0 + x3 and x1+x2 combined\n\n    vswp          d22, d23\n\n    vrshr.s16     q10, q10, #6          @\n    vrshr.s16     q11, q11, #6\n\n    vaddw.u8      q10, q10, d30\n    vaddw.u8      q11, q11, d31\n\n    vqmovun.s16   d0, q10\n    vqmovun.s16   d1, q11\n\n    vst1.32       d0[0], [r2], r4       @I row store the value\n    vst1.32       d0[1], [r2], r4       @II row store the value\n    vst1.32       d1[0], [r2], r4       @III row store the value\n    vst1.32       d1[1], [r2]           @IV row store the value\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r12, r15}    @Reload the registers from SP\n\n\n@**\n@ *******************************************************************************\n@ *\n@ * @brief\n@ *  This function performs inverse quant and Inverse transform type Ci4 for 4*4 block\n@ *\n@ * @par Description:\n@ *  Performs inverse transform Ci4 and adds the residue to get the\n@ *  reconstructed block\n@ *\n@ * @param[in] pi2_src\n@ *  Input 4x4 coefficients\n@ *\n@ * @param[in] pu1_pred\n@ *  Prediction 4x4 block\n@ *\n@ * @param[out] pu1_out\n@ *  Output 4x4 block\n@ *\n@ * @param[in] u4_qp_div_6\n@ *     QP\n@ *\n@ * @param[in] pu2_weigh_mat\n@ * Pointer to weight matrix\n@ *\n@ * @param[in] pred_strd,\n@ *  Prediction stride\n@ *\n@ * @param[in] out_strd\n@ *  Output Stride\n@ *\n@ *@param[in] pi2_tmp\n@ * temporary buffer of size 1*16\n@ *\n@ * @param[in] pu2_iscal_mat\n@ * Pointer to the inverse quantization matrix\n@ *\n@ * @returns  Void\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n@ *\n@void ih264_iquant_itrans_recon_chroma_4x4(WORD16 *pi2_src,\n@                                   UWORD8 *pu1_pred,\n@                                   UWORD8 *pu1_out,\n@                                   WORD32 pred_strd,\n@                                   WORD32 out_strd,\n@                                   const UWORD16 *pu2_iscal_mat,\n@                                   const UWORD16 *pu2_weigh_mat,\n@                                   UWORD32 u4_qp_div_6,\n@                                   WORD32 *pi4_tmp\n@                                   WORD16 *pi2_dc_src)\n@**************Variables Vs Registers*****************************************\n@r0 => *pi2_src\n@r1 => *pu1_pred\n@r2 => *pu1_out\n@r3 =>  pred_strd\n@r4 =>  out_strd\n@r5 =>  *pu2_iscal_mat\n@r6 =>  *pu2_weigh_mat\n@r7 =>  u4_qp_div_6\n\n    .global ih264_iquant_itrans_recon_chroma_4x4_a9\nih264_iquant_itrans_recon_chroma_4x4_a9:\n\n@VLD4.S16 is used because the pointer is incremented by SUB_BLK_WIDTH_4x4\n@If the macro value changes need to change the instruction according to it.\n@Only one shift is done in horizontal inverse because,\n@if u4_qp_div_6 is lesser than 4 then shift value will be neagative and do negative left shift, in this case rnd_factor has value\n@if u4_qp_div_6 is greater than 4 then shift value will be positive and do left shift, here rnd_factor is 0\n\n    stmfd         sp!, {r4-r12, r14}    @stack stores the values of the arguments\n    ldr           r7, [sp, #52]         @Loads u4_qp_div_6\n    ldr           r4, [sp, #40]         @Loads out_strd\n    vdup.s32      q15, r7               @Populate the u4_qp_div_6 in Q15\n    ldr           r5, [sp, #44]         @Loads *pu2_iscal_mat\n    ldr           r6, [sp, #48]         @Loads *pu2_weigh_mat\n    ldr           r8, [sp, #60]         @loads *pi2_dc_src\n\n    vpush         {d8-d15}\n@=======================DEQUANT FROM HERE===================================\n\n    vld4.s16      {d20, d21, d22, d23}, [r5] @Load pu2_iscal_mat[i], i =0..15\n    vld4.s16      {d26, d27, d28, d29}, [r6] @pu2_weigh_mat[i], i =0..15\n    vmul.s16      q10, q10, q13         @x[i]=(scale[i] * dequant[i]) where i = 0..7\n    vld4.s16      {d16, d17, d18, d19}, [r0] @pi2_src_tmp[i], i =0..15\n\n    vmul.s16      q11, q11, q14         @x[i]=(scale[i] * dequant[i]) where i = 8..15\n\n    vmull.s16     q0, d16, d20          @ Q0  = p[i] = (x[i] * trns_coeff[i]) where i = 0..3\n    vmull.s16     q1, d17, d21          @ Q1  = p[i] = (x[i] * trns_coeff[i]) where i = 4..7\n    vmull.s16     q2, d18, d22          @ Q2  = p[i] = (x[i] * trns_coeff[i]) where i = 8..11\n    vmull.s16     q3, d19, d23          @ Q3  = p[i] = (x[i] * trns_coeff[i]) where i = 12..15\n\n    vshl.s32      q0, q0, q15           @ Q0  = q[i] = (p[i] << (qP/6)) where i = 0..3\n    vshl.s32      q1, q1, q15           @ Q1  = q[i] = (p[i] << (qP/6)) where i = 4..7\n    vshl.s32      q2, q2, q15           @ Q2  = q[i] = (p[i] << (qP/6)) where i = 8..11\n    vshl.s32      q3, q3, q15           @ Q3  = q[i] = (p[i] << (qP/6)) where i = 12..15\n\n    vqrshrn.s32   d0, q0, #0x4          @ D0  = c[i] = ((q[i] + 32) >> 4) where i = 0..3\n    vqrshrn.s32   d1, q1, #0x4          @ D1  = c[i] = ((q[i] + 32) >> 4) where i = 4..7\n    vqrshrn.s32   d2, q2, #0x4          @ D2  = c[i] = ((q[i] + 32) >> 4) where i = 8..11\n    vqrshrn.s32   d3, q3, #0x4          @ D3  = c[i] = ((q[i] + 32) >> 4) where i = 12..15\n\n    ldrsh         r9, [r8]              @ Loads signed halfword pi2_dc_src[0]\n    vmov.16       d0[0], r9             @ Restore dc value since its chroma iq-it\n\n@========= PROCESS IDCT FROM HERE =======\n@Steps for Stage 1:\n@------------------\n    vld2.8        {d28, d29}, [r1], r3  @I row Load pu1_pred buffer\n    vadd.s16      d4, d0, d2            @x0 = q0 + q1;\n\n    vsub.s16      d5, d0, d2            @x1 = q0 - q1;\n\n    vshr.s16      d8, d1, #1            @q0>>1\n    vshr.s16      d9, d3, #1            @q1>>1\n\n    vsub.s16      d6, d8, d3            @x2 = (q0 >> 1) -  q1;\n    vadd.s16      d7, d1, d9            @x3 = q0+ (q1 >> 1);\n    vld2.8        {d29, d30}, [r1], r3  @II row Load pu1_pred buffer\n\n    vswp          d6, d7                @Reverse positions of x2 and x3\n\n    vsub.s16      q6, q2, q3            @x0-x3 and x1-x2 combined\n    vtrn.32       d28, d29              @ D28 -- row I and II of pu1_pred_buffer\n    vadd.s16      q5, q2, q3            @x0 + x3 and x1+x2 combined\n\n    vld2.8        {d29, d30}, [r1], r3  @III row Load pu1_pred buf\n\n    vswp          d12, d13\n@Steps for Stage 2:\n@------------------\n    vtrn.16       d10, d11\n    vtrn.16       d12, d13\n    vtrn.32       d10, d12\n    vtrn.32       d11, d13\n    vadd.s16      d14, d10, d12         @x0 = q0 + q1;\n\n    vsub.s16      d15, d10, d12         @x1 = q0 - q1;\n\n    vshr.s16      d18, d11, #1          @q0>>1\n    vshr.s16      d19, d13, #1          @q1>>1\n\n    vsub.s16      d16, d18, d13         @x2 = (q0 >> 1) -  q1;\n    vadd.s16      d17, d11, d19         @x3 = q0+ (q1 >> 1);\n\n    vld2.8        {d30, d31}, [r1], r3  @IV row Load pu1_pred buffer\n    vswp          d16, d17              @Reverse positions of x2 and x3\n\n    vsub.s16      q11, q7, q8           @x0-x3 and x1-x2 combined\n    vtrn.32       d29, d30              @ D29 -- row III and IV of pu1_pred_buf\n    vadd.s16      q10, q7, q8           @x0 + x3 and x1+x2 combined\n\n    vswp          d22, d23\n\n    vrshr.s16     q10, q10, #6          @\n    vrshr.s16     q11, q11, #6\n\n    vaddw.u8      q10, q10, d28\n    vaddw.u8      q11, q11, d29\n\n    vld1.u8       d0, [r2], r4          @Loading out buffer 16 coeffs\n    vld1.u8       d1, [r2], r4\n    vld1.u8       d2, [r2], r4\n    vld1.u8       d3, [r2], r4\n\n    sub           r2, r2, r4, lsl #2\n\n    vqmovun.s16   d20, q10              @Getting quantized coeffs\n    vqmovun.s16   d22, q11\n\n    vmovl.u8      q10, d20              @Move the coffs into 16 bit\n    vmovl.u8      q11, d22              @so that we can use vbit to copy\n\n    vmov.u16      q14, #0x00ff          @Copy lsb from qantized(long)coeffs\n\n    vbit.u8       q0, q10, q14\n    vbit.u8       q1, q11, q14\n\n    vst1.u8       d0, [r2], r4\n    vst1.u8       d1, [r2], r4\n    vst1.u8       d2, [r2], r4\n    vst1.u8       d3, [r2]\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r12, r15}    @Reload the registers from SP\n\n\n@*\n@ *******************************************************************************\n@ *\n@ * @brief\n@ *  This function performs inverse quant and Inverse transform type Ci4 for 8*8 block\n@ *\n@ * @par Description:\n@ *  Performs inverse transform Ci8 and adds the residue to get the\n@ *  reconstructed block\n@ *\n@ * @param[in] pi2_src\n@ *  Input 4x4 coefficients\n@ *\n@ * @param[in] pu1_pred\n@ *  Prediction 4x4 block\n@ *\n@ * @param[out] pu1_out\n@ *  Output 4x4 block\n@ *\n@ * @param[in] u4_qp_div_6\n@ *     QP\n@ *\n@ * @param[in] pu2_weigh_mat\n@ * Pointer to weight matrix\n@ *\n@ * @param[in] pred_strd,\n@ *  Prediction stride\n@ *\n@ * @param[in] out_strd\n@ *  Output Stride\n@ *\n@ *@param[in] pi2_tmp\n@ * temporary buffer of size 1*64\n@ *\n@ * @param[in] pu2_iscal_mat\n@ * Pointer to the inverse quantization matrix\n@ *\n@ * @returns  Void\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n@ *\n@void ih264_iquant_itrans_recon_8x8(WORD16 *pi2_src,\n@                                   UWORD8 *pu1_pred,\n@                                   UWORD8 *pu1_out,\n@                                   WORD32 pred_strd,\n@                                   WORD32 out_strd,\n@                                   const UWORD16 *pu2_iscal_mat,\n@                                   const UWORD16 *pu2_weigh_mat,\n@                                   UWORD32 u4_qp_div_6,\n@                                   WORD32 *pi4_tmp,\n@                                   WORD32 iq_start_idx)\n@**************Variables Vs Registers*****************************************\n@r0 => *pi2_src\n@r1 => *pu1_pred\n@r2 => *pu1_out\n@r3 =>  pred_strd\n@r4 =>  out_strd\n@r5 =>  *pu2_iscal_mat\n@r6 =>  *pu2_weigh_mat\n@r7 =>  u4_qp_div_6\n\n\n    .global ih264_iquant_itrans_recon_8x8_a9\nih264_iquant_itrans_recon_8x8_a9:\n\n    stmfd         sp!, {r4-r12, r14}    @stack stores the values of the arguments\n    ldr           r7, [sp, #52]         @Loads u4_qp_div_6\n    ldr           r4, [sp, #40]         @Loads out_strd\n\n    ldr           r5, [sp, #44]         @Loads *pu2_iscal_mat\n    ldr           r6, [sp, #48]         @Loads *pu2_weigh_mat\n    vdup.s32      q15, r7               @Populate the u4_qp_div_6 in Q15\n    vpush         {d8-d15}\n\nidct_8x8_begin:\n\n@========= DEQUANT FROM HERE ===========\n\n    vld1.32       {q13}, [r5]!          @ Q13 = dequant values row 0\n    vld1.32       {q10}, [r6]!          @ Q10 = scaling factors row 0\n    vld1.32       {q14}, [r5]!          @ Q14 = dequant values row 1\n    vmul.s16      q10, q10, q13         @ Q10 = x[i] = (scale[i] * dequant[i]) where i = 0..7\n    vld1.32       {q11}, [r6]!          @ Q11 = scaling factors row 1\n    vld1.32       {q8}, [r0]!           @ Q8  = Source row 0\n    vmul.s16      q11, q11, q14         @ Q11 = x[i] = (scale[i] * dequant[i]) where i = 8..15\n    vmull.s16     q0, d16, d20          @ Q0  = p[i] = (x[i] * trns_coeff[i]) where i = 0..3\n    vld1.32       {q9}, [r0]!           @ Q8  = Source row 1\n    vmull.s16     q1, d17, d21          @ Q1  = p[i] = (x[i] * trns_coeff[i]) where i = 4..7\n    vmull.s16     q2, d18, d22          @ Q2  = p[i] = (x[i] * trns_coeff[i]) where i = 8..11\n    vld1.32       {q13}, [r6]!          @ Scaling factors row 2\n    vmull.s16     q3, d19, d23          @ Q3  = p[i] = (x[i] * trns_coeff[i]) where i = 12..15\n    vld1.32       {q14}, [r6]!          @ Scaling factors row 3\n    vshl.s32      q0, q0, q15           @ Q0  = q[i] = (p[i] << (qP/6)) where i = 0..3\n    vld1.32       {q10}, [r5]!          @ Q10 = Dequant values row 2\n    vshl.s32      q1, q1, q15           @ Q1  = q[i] = (p[i] << (qP/6)) where i = 4..7\n    vld1.32       {q8}, [r0]!           @ Source Row 2\n    vshl.s32      q2, q2, q15           @ Q2  = q[i] = (p[i] << (qP/6)) where i = 8..11\n    vld1.32       {q11}, [r5]!          @ Q11 = Dequant values row 3\n    vshl.s32      q3, q3, q15           @ Q3  = q[i] = (p[i] << (qP/6)) where i = 12..15\n    vld1.32       {q9}, [r0]!           @ Source Row 3\n    vmul.s16      q10, q10, q13         @ Dequant row2*scale matrix row 2\n    vmul.s16      q11, q11, q14         @ Dequant row 3*scale matrix row 3\n    vld1.32       {q4}, [r6]!           @ Scaling factors row 4\n    vqrshrn.s32   d0, q0, #0x6          @ D0  = c[i] = ((q[i] + 32) >> 6) where i = 0..3\n    vqrshrn.s32   d1, q1, #0x6          @ D1  = c[i] = ((q[i] + 32) >> 6) where i = 4..7\n    vld1.32       {q5}, [r6]!           @ Scaling factors row 5\n    vqrshrn.s32   d2, q2, #0x6          @ D2  = c[i] = ((q[i] + 32) >> 6) where i = 8..11\n    vqrshrn.s32   d3, q3, #0x6          @ D3  = c[i] = ((q[i] + 32) >> 6) where i = 12..15\n    vld1.32       {q13}, [r5]!          @ Q13 = Dequant values row 4\n    vmull.s16     q2, d16, d20          @ p[i] = (x[i] * trns_coeff[i]) where i=16..19\n    vmull.s16     q3, d17, d21          @ p[i] = (x[i] * trns_coeff[i]) where i=20..23\n    vld1.32       {q12}, [r5]!          @ Q12 = Dequant values row 5\n    vmull.s16     q6, d18, d22          @ p[i] = (x[i] * trns_coeff[i]) where i=24..27\n    vmull.s16     q7, d19, d23          @ p[i] = (x[i] * trns_coeff[i]) where i=28..31\n\n    vld1.32       {q14}, [r0]!          @ Source row 4\n    vmul.s16      q10, q4, q13          @ Dequant row4*scale matrix row 4\n    vmul.s16      q11, q5, q12          @ Dequant row5*scale matrix row 5\n    vld1.32       {q9}, [r0]!           @ Source row 5\n    vshl.s32      q2, q2, q15           @\n    vshl.s32      q3, q3, q15           @\n    vld1.32       {q13}, [r6]!          @ Scaling factors row 6\n    vshl.s32      q6, q6, q15           @\n    vshl.s32      q7, q7, q15           @\n    vmull.s16     q4, d28, d20          @ i = 32..35\n    vqrshrn.s32   d4, q2, #0x6          @ D4  = c[i] = ((q[i] + 32) >> 6) where i = 16..19\n    vqrshrn.s32   d5, q3, #0x6          @ D5  = c[i] = ((q[i] + 32) >> 6) where i = 20..23\n    vmull.s16     q5, d29, d21          @ i =36..39\n    vld1.32       {q10}, [r5]!          @ Dequant values row 6\n    vqrshrn.s32   d6, q6, #0x6          @ D6  = c[i] = ((q[i] + 32) >> 6) where i = 24..27\n    vqrshrn.s32   d7, q7, #0x6          @ D7  = c[i] = ((q[i] + 32) >> 6) where i = 28..31\n    vld1.32       {q14}, [r6]!          @ Scaling factors row 7\n    vmull.s16     q6, d18, d22          @\n    vld1.32       {q8}, [r0]!           @ Source row 6\n    vmull.s16     q7, d19, d23          @\n    vld1.32       {q11}, [r5]!          @ Dequant values row 7\n    vshl.s32      q4, q4, q15           @\n    vld1.32       {q9}, [r0]!           @ Source row 7\n    vshl.s32      q5, q5, q15           @\n\n    vshl.s32      q6, q6, q15           @\n    vshl.s32      q7, q7, q15           @\n    vmul.s16      q10, q10, q13         @ Dequant*scaling row 6\n    vmul.s16      q11, q11, q14         @ Dequant*scaling row 7\n    vqrshrn.s32   d8, q4, #0x6          @ D8  = c[i] = ((q[i] + 32) >> 6) where i = 32..35\n    vqrshrn.s32   d9, q5, #0x6          @ D9  = c[i] = ((q[i] + 32) >> 6) where i = 36..39\n    vqrshrn.s32   d10, q6, #0x6         @ D10  = c[i] = ((q[i] + 32) >> 6) where i = 40..43\n    vqrshrn.s32   d11, q7, #0x6         @ D11  = c[i] = ((q[i] + 32) >> 6) where i = 44..47\n    vmull.s16     q6, d16, d20          @ i= 48..51\n    vmull.s16     q7, d17, d21          @ i= 52..55\n    vmull.s16     q8, d18, d22          @ i=56..59\n    vmull.s16     q9, d19, d23          @ i=60..63\n    vshl.s32      q6, q6, q15           @\n    vzip.s16      q0, q1                @Transpose\n    vshl.s32      q7, q7, q15           @\n    vshl.s32      q8, q8, q15           @\n    vzip.s16      q2, q3                @\n    vshl.s32      q9, q9, q15           @\n    vqrshrn.s32   d12, q6, #0x6         @ D12  = c[i] = ((q[i] + 32) >> 6) where i = 48..51\n    vzip.s16      q4, q5                @Transpose\n    vqrshrn.s32   d13, q7, #0x6         @ D13  = c[i] = ((q[i] + 32) >> 6) where i = 52..55\n    vqrshrn.s32   d14, q8, #0x6         @ D14  = c[i] = ((q[i] + 32) >> 6) where i = 56..59\n    vzip.s32      q0, q2                @Transpose\n    vqrshrn.s32   d15, q9, #0x6         @ D15  = c[i] = ((q[i] + 32) >> 6) where i = 60..63\n\n@========= PROCESS IDCT FROM HERE =======\n\n@Steps for Stage 2:\n@------------------\n\n@   TRANSPOSE 8x8 coeffs to actual order\n\n    vzip.s16      q6, q7                @\n\n    vzip.s32      q1, q3                @\n    vzip.s32      q4, q6                @\n    vzip.s32      q5, q7                @\n\n    vswp          d1, d8                @ Q0/Q1 = Row order x0/x1\n    vswp          d3, d10               @ Q2/Q3 = Row order x2/x3\n    vswp          d5, d12               @ Q4/Q5 = Row order x4/x5\n    vswp          d7, d14               @ Q6/Q7 = Row order x6/x7\n\n    vswp          q1, q4                @\n    vshr.s16      q10, q2, #0x1         @\n    vswp          q3, q6                @\n\n@Steps for Stage 1:\n@------------------\n\n    vadd.s16      q8, q0, q4            @ Q8 = y0\n    vsub.s16      q9, q0, q4            @ Q9 = y2\n\n    vsra.s16      q2, q6, #0x1          @ Q2 = y6\n    vsub.s16      q6, q10, q6           @ Q6 = y4\n\n    vaddl.s16     q12, d14, d2          @ y3 (0-3) 1+7\n    vaddl.s16     q13, d15, d3          @ y3 (4-7) 1+7\n\n    vsubl.s16     q10, d14, d2          @ y5 (0-3) 7-1\n    vsubl.s16     q11, d15, d3          @ y5 (4-7) 7-1\n\n    vadd.s16      q0, q8, q2            @ Q0 = z0\n    vsub.s16      q4, q8, q2            @ Q4 = z6\n\n    vadd.s16      q8, q9, q6            @ Q8 = z2\n    vsub.s16      q2, q9, q6            @ Q2 = z4\n\n    vsubw.s16     q12, q12, d6          @ y3 (0-3) 1+7-3\n    vsubw.s16     q13, q13, d7          @ y3 (0-7) 1+7-3\n\n    vshr.s16      q6, q3, #0x1          @\n\n    vaddw.s16     q10, q10, d10         @\n    vaddw.s16     q11, q11, d11         @\n\n    vshr.s16      q9, q5, #0x1          @\n\n    vsubw.s16     q12, q12, d12         @\n    vsubw.s16     q13, q13, d13         @\n\n    vaddw.s16     q10, q10, d18         @\n    vaddw.s16     q11, q11, d19         @\n\n    vqmovn.s32    d12, q12              @\n    vaddl.s16     q12, d10, d6          @\n    vqmovn.s32    d13, q13              @ Q6 = y3\n    vaddl.s16     q13, d11, d7          @\n    vqmovn.s32    d18, q10              @\n    vsubl.s16     q10, d10, d6          @\n    vqmovn.s32    d19, q11              @ Q9 = y5\n    vsubl.s16     q11, d11, d7          @\n\n    vshr.s16      q3, q6, #0x2          @\n\n    vsra.s16      q6, q9, #0x2          @ Q6 = z3\n\n    vaddw.s16     q12, q12, d2          @\n    vaddw.s16     q13, q13, d3          @\n\n    vshr.s16      q1, #0x1              @\n\n    vsub.s16      q5, q3, q9            @ Q5 = z5\n\n    vsubw.s16     q10, q10, d14         @\n    vsubw.s16     q11, q11, d15         @\n\n    vshr.s16      q7, #0x1              @\n\n    vaddw.s16     q12, q12, d2          @\n    vaddw.s16     q13, q13, d3          @\n\n    vsubw.s16     q10, q10, d14         @\n    vsubw.s16     q11, q11, d15         @\n\n\n    vqmovn.s32    d14, q12              @\n    vadd.s16      q1, q8, q5            @ Q1 = x1\n    vqmovn.s32    d15, q13              @ Q7 = y7\n    vsub.s16      q3, q8, q5            @ Q3 = x6\n    vqmovn.s32    d18, q10              @\n    vsub.s16      q5, q2, q6            @ Q5 = x5\n    vqmovn.s32    d19, q11              @ Q9 = y1\n    vadd.s16      q2, q2, q6            @ Q2 = x2\n\n    vshr.s16      q12, q9, #0x2         @\n    vsra.s16      q9, q7, #0x2          @ Q9 = z1\n\n    vsub.s16      q11, q7, q12          @ Q11 = z7\n\n    vadd.s16      q6, q4, q9            @ Q6 = x3\n    vsub.s16      q4, q4, q9            @ Q4 = x4\n\n    vsub.s16      q7, q0, q11           @ Q7 = x7\n    vadd.s16      q0, q0, q11           @ Q0 = x0\n\n    vswp.s16      q3, q6                @ Q3 = x3, Q6 = x6\n\n\n@Steps for Stage 2:\n@------------------\n\n@   TRANSPOSE 8x8 coeffs to actual order\n\n    vzip.s16      q0, q1                @\n    vzip.s16      q2, q3                @\n    vzip.s16      q4, q5                @\n    vzip.s16      q6, q7                @\n\n    vzip.s32      q0, q2                @\n    vzip.s32      q1, q3                @\n    vzip.s32      q4, q6                @\n    vzip.s32      q5, q7                @\n\n    vswp          d1, d8                @ Q0/Q1 = Row order x0/x1\n    vswp          d3, d10               @ Q2/Q3 = Row order x2/x3\n    vswp          d5, d12               @ Q4/Q5 = Row order x4/x5\n    vswp          d7, d14               @ Q6/Q7 = Row order x6/x7\n\n    vswp          q1, q4                @\n    vshr.s16      q10, q2, #0x1         @\n    vswp          q3, q6                @\n\n@Steps for Stage 3:\n@------------------\n\n@Repeat stage 1 again for vertical transform\n\n    vadd.s16      q8, q0, q4            @ Q8 = y0\n    vld1.32       d28, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vsub.s16      q9, q0, q4            @ Q9 = y2\n\n    vsra.s16      q2, q6, #0x1          @ Q2 = y6\n    vsub.s16      q6, q10, q6           @ Q6 = y4\n\n    vaddl.s16     q12, d14, d2          @\n    vld1.32       d29, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vaddl.s16     q13, d15, d3          @\n\n    vsubl.s16     q10, d14, d2          @\n    vld1.32       d30, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vsubl.s16     q11, d15, d3          @\n\n    vadd.s16      q0, q8, q2            @ Q0 = z0\n    vld1.32       d31, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vsub.s16      q4, q8, q2            @ Q4 = z6\n\n    vadd.s16      q8, q9, q6            @ Q8 = z2\n    vsub.s16      q2, q9, q6            @ Q2 = z4\n\n    vsubw.s16     q12, q12, d6          @\n    vsubw.s16     q13, q13, d7          @\n\n    vshr.s16      q6, q3, #0x1          @\n\n    vaddw.s16     q10, q10, d10         @\n    vaddw.s16     q11, q11, d11         @\n\n    vshr.s16      q9, q5, #0x1          @\n\n    vsubw.s16     q12, q12, d12         @\n    vsubw.s16     q13, q13, d13         @\n\n    vaddw.s16     q10, q10, d18         @\n    vaddw.s16     q11, q11, d19         @\n\n    vqmovn.s32    d12, q12              @\n    vaddl.s16     q12, d10, d6          @\n    vqmovn.s32    d13, q13              @ Q6 = y3\n    vaddl.s16     q13, d11, d7          @\n    vqmovn.s32    d18, q10              @\n    vsubl.s16     q10, d10, d6          @\n    vqmovn.s32    d19, q11              @ Q9 = y5\n    vsubl.s16     q11, d11, d7          @\n\n    vshr.s16      q3, q6, #0x2          @\n\n    vsra.s16      q6, q9, #0x2          @ Q6 = z3\n\n    vaddw.s16     q12, q12, d2          @\n    vaddw.s16     q13, q13, d3          @\n\n    vshr.s16      q1, #0x1              @\n\n    vsub.s16      q5, q3, q9            @ Q5 = z5\n\n    vsubw.s16     q10, q10, d14         @\n    vsubw.s16     q11, q11, d15         @\n\n    vshr.s16      q7, #0x1              @\n\n    vaddw.s16     q12, q12, d2          @\n    vaddw.s16     q13, q13, d3          @\n\n    vsubw.s16     q10, q10, d14         @\n    vsubw.s16     q11, q11, d15         @\n\n    vqmovn.s32    d14, q12              @\n    vadd.s16      q1, q8, q5            @ Q1 = x1\n    vqmovn.s32    d15, q13              @ Q7 = y7\n    vsub.s16      q3, q8, q5            @ Q3 = x6\n    vqmovn.s32    d18, q10              @\n    vsub.s16      q5, q2, q6            @ Q5 = x5\n    vqmovn.s32    d19, q11              @ Q9 = y1\n    vadd.s16      q2, q2, q6            @ Q2 = x2\n\n    vshr.s16      q12, q9, #0x2         @\n    vsra.s16      q9, q7, #0x2          @ Q9 = z1\n\n    vsub.s16      q11, q7, q12          @ Q11 = z7\n\n    vadd.s16      q6, q4, q9            @ Q6 = x3\n    vsub.s16      q4, q4, q9            @ Q4 = x4\n\n    vsub.s16      q7, q0, q11           @ Q7 = x7\n    vadd.s16      q0, q0, q11           @ Q0 = x0\n\n    vswp.s16      q3, q6                @ Q3 <-> Q6\n\n    vrshr.s16     q1, q1, #6            @\n    vld1.32       d16, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vrshr.s16     q2, q2, #6            @\n    vrshr.s16     q4, q4, #6            @\n    vld1.32       d17, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vrshr.s16     q5, q5, #6            @\n    vrshr.s16     q7, q7, #6            @\n    vld1.32       d18, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vrshr.s16     q0, q0, #6            @\n    vrshr.s16     q3, q3, #6            @\n    vld1.32       d19, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vrshr.s16     q6, q6, #6            @\n\n@ Code Added to pack sign and magnitudes\n\n    vaddw.u8      q0, q0, d28\n    vaddw.u8      q1, q1, d29\n    vaddw.u8      q2, q2, d30\n    vaddw.u8      q3, q3, d31\n    vqmovun.s16   d0, q0\n    vaddw.u8      q4, q4, d16\n    vqmovun.s16   d1, q1\n    vaddw.u8      q5, q5, d17\n    vqmovun.s16   d2, q2\n    vaddw.u8      q6, q6, d18\n    vqmovun.s16   d3, q3\n    vaddw.u8      q7, q7, d19\n\n    vqmovun.s16   d4, q4\n    vst1.32       d0, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vqmovun.s16   d5, q5\n    vst1.32       d1, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vqmovun.s16   d6, q6\n    vst1.32       d2, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vqmovun.s16   d7, q7\n    vst1.32       d3, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vst1.32       d4, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n\n    vst1.32       d5, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n\n\n    vst1.32       d6, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n\n\n    vst1.32       d7, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n\nidct_8x8_end:\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r12, r15}\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_iquant_itrans_recon_dc_a9.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@ *******************************************************************************\n@ * @file\n@ *  ih264_iquant_itrans_recon_dc_a9.s\n@ *\n@ * @brief\n@ *  Contains function definitions for single stage  inverse transform\n@ *\n@ * @author\n@ *  Mohit\n@ *\n@ * @par List of Functions:\n@ *  - ih264_iquant_itrans_recon_4x4_dc_a9()\n@ *  - ih264_iquant_itrans_recon_8x8_dc_a9()\n@ *  - ih264_iquant_itrans_recon_chroma_4x4_dc_a9()\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n@*\n@**\n@ *******************************************************************************\n@ *\n@ * @brief\n@ *  This function performs inverse quant and Inverse transform type Ci4 for 4*4 block\n@ *  for dc input pattern only, i.e. only the (0,0) element of the input 4x4 block is\n@ *  non-zero. For complete function, refer ih264_iquant_itrans_recon_a9.s\n@ *\n@ * @par Description:\n@ *  Performs inverse transform Ci4 and adds the residue to get the\n@ *  reconstructed block\n@ *\n@ * @param[in] pi2_src\n@ *  Input 4x4 coefficients\n@ *\n@ * @param[in] pu1_pred\n@ *  Prediction 4x4 block\n@ *\n@ * @param[out] pu1_out\n@ *  Output 4x4 block\n@ *\n@ * @param[in] u4_qp_div_6\n@ *     QP\n@ *\n@ * @param[in] pu2_weigh_mat\n@ * Pointer to weight matrix\n@ *\n@ * @param[in] pred_strd,\n@ *  Prediction stride\n@ *\n@ * @param[in] out_strd\n@ *  Output Stride\n@ *\n@ *@param[in] pi2_tmp\n@ * temporary buffer of size 1*16\n@ *\n@ * @param[in] pu2_iscal_mat\n@ * Pointer to the inverse quantization matrix\n@ *\n@ * @returns  Void\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n@ *\n@void ih264_iquant_itrans_recon_4x4_dc(WORD16 *pi2_src,\n@                                   UWORD8 *pu1_pred,\n@                                   UWORD8 *pu1_out,\n@                                   WORD32 pred_strd,\n@                                   WORD32 out_strd,\n@                                   const UWORD16 *pu2_iscal_mat,\n@                                   const UWORD16 *pu2_weigh_mat,\n@                                   UWORD32 u4_qp_div_6,\n@                                   WORD32 *pi4_tmp,\n@                                   WORD32 iq_start_idx\n@                                   WORD16 *pi2_dc_ld_addr)\n@**************Variables Vs Registers*****************************************\n@r0 => *pi2_src\n@r1 => *pu1_pred\n@r2 => *pu1_out\n@r3 =>  pred_strd\n@r4 =>  out_strd\n@r5 =>  *pu2_iscal_mat\n@r6 =>  *pu2_weigh_mat\n@r7 =>  u4_qp_div_6\n@r9 =>  iq_start_idx\n@unused =>  pi2_dc_ld_addr\n\n.text\n.syntax unified\n.p2align 2\n\n    .global ih264_iquant_itrans_recon_4x4_dc_a9\n\nih264_iquant_itrans_recon_4x4_dc_a9:\n\n@Only one shift is done in horizontal inverse because,\n@if u4_qp_div_6 is lesser than 4 then shift value will be neagative and do negative left shift, in this case rnd_factor has value\n@if u4_qp_div_6 is greater than 4 then shift value will be positive and do left shift, here rnd_factor is 0\n\n    stmfd         sp!, {r4-r10, r14}    @stack stores the values of the arguments\n    ldr           r5, [sp, #36]         @Loads *pu2_iscal_mat\n    ldr           r6, [sp, #40]         @Loads *pu2_weigh_mat\n    ldrsh         r8, [r0]              @load pi2_src[0], SH for signed halfword load\n    ldrh          r6, [r6]              @load pu2_weight_mat[0] , H for unsigned halfword load\n    ldrh          r5, [r5]              @load pu2_iscal_mat[0] , H for unsigned halfword load\n@=======================DEQUANT FROM HERE===================================\n    mul           r6, r6, r5            @pu2_iscal_mat[0]*pu2_weigh_mat[0]\n    ldr           r7, [sp, #44]         @Loads u4_qp_div_6\n    mul           r6, r6, r8            @pi2_src[0]*pu2_iscal_mat[0]*pu2_weigh_mat[0]\n    ldr           r4, [sp, #32]         @Loads out_strd\n    ldr           r9, [sp, #52]         @Loads iq_start_idx\n\n    lsl           r6, r6, r7            @(pi2_src[0]*pu2_iscal_mat[0]*pu2_weigh_mat[0])<<u4_qp_div_6\n    add           r6, r6, #8            @(pi2_src[0]*pu2_iscal_mat[0]*pu2_weigh_mat[0])<<u4_qp_div_6 + rnd_fact\n    asr           r6, r6, #4            @q0 = (pi2_src[0]*pu2_iscal_mat[0]*pu2_weigh_mat[0] + rnd_fact)<<(u4_qp_div_6-4)\n\n    subs          r9, r9, #1            @ if r8 == 1 => intra case , so result of subtraction is zero and Z flag is set\n    ldrsheq       r10, [r0]             @ Loads signed halfword pi2_src[0], if r9==1\n    moveq         r6, r10               @ Restore dc value in case of intra, i.e. r9 == 1\n\n    add           r6, r6, #32           @i_macro = q0 + 32\n    asr           r6, r6, #6            @i_macro >>6 = DC output of 2-stage transform\n    vdup.s16      q0, r6                @copy transform output to Q0\n\n    vld1.32       d30[0], [r1], r3      @I row Load pu1_pred buffer\n\n    vld1.32       d30[1], [r1], r3      @II row Load pu1_pred buffer\n\n    vld1.32       d31[0], [r1], r3      @III row Load pu1_pred buf\n\n    vld1.32       d31[1], [r1], r3      @IV row Load pu1_pred buffer\n    vaddw.u8      q10, q0, d30\n\n    vaddw.u8      q11, q0, d31\n\n    vqmovun.s16   d0, q10\n\n    vst1.32       d0[0], [r2], r4       @I row store the value\n    vqmovun.s16   d1, q11\n    vst1.32       d0[1], [r2], r4       @II row store the value\n    vst1.32       d1[0], [r2], r4       @III row store the value\n    vst1.32       d1[1], [r2]           @IV row store the value\n\n    ldmfd         sp!, {r4-r10, r15}    @Reload the registers from SP\n\n\n\n\n@*\n@ *******************************************************************************\n@ *\n@ * @brief\n@ *  This function performs inverse quant and Inverse transform type Ci4 for 8*8 block\n@ *  for dc input pattern only, i.e. only the (0,0) element of the input 8x8 block is\n@ *  non-zero. For complete function, refer ih264_iquant_itrans_recon_a9.s\n@ *\n@ * @par Description:\n@ *  Performs inverse transform Ci8 and adds the residue to get the\n@ *  reconstructed block\n@ *\n@ * @param[in] pi2_src\n@ *  Input 4x4 coefficients\n@ *\n@ * @param[in] pu1_pred\n@ *  Prediction 4x4 block\n@ *\n@ * @param[out] pu1_out\n@ *  Output 4x4 block\n@ *\n@ * @param[in] u4_qp_div_6\n@ *     QP\n@ *\n@ * @param[in] pu2_weigh_mat\n@ * Pointer to weight matrix\n@ *\n@ * @param[in] pred_strd,\n@ *  Prediction stride\n@ *\n@ * @param[in] out_strd\n@ *  Output Stride\n@ *\n@ *@param[in] pi2_tmp\n@ * temporary buffer of size 1*64\n@ *\n@ * @param[in] pu2_iscal_mat\n@ * Pointer to the inverse quantization matrix\n@ *\n@ * @returns  Void\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n@ *\n@void ih264_iquant_itrans_recon_8x8_dc(WORD16 *pi2_src,\n@                                   UWORD8 *pu1_pred,\n@                                   UWORD8 *pu1_out,\n@                                   WORD32 pred_strd,\n@                                   WORD32 out_strd,\n@                                   const UWORD16 *pu2_iscal_mat,\n@                                   const UWORD16 *pu2_weigh_mat,\n@                                   UWORD32 u4_qp_div_6,\n@                                   WORD32 *pi4_tmp,\n@                                   WORD32 iq_start_idx)\n@**************Variables Vs Registers*****************************************\n@r0 => *pi2_src\n@r1 => *pu1_pred\n@r2 => *pu1_out\n@r3 =>  pred_strd\n@r4 =>  out_strd\n@r5 =>  *pu2_iscal_mat\n@r6 =>  *pu2_weigh_mat\n@r7 =>  u4_qp_div_6\n\n\n    .global ih264_iquant_itrans_recon_8x8_dc_a9\nih264_iquant_itrans_recon_8x8_dc_a9:\n\n    stmfd         sp!, {r4-r8, r14}     @stack stores the values of the arguments\n    ldr           r5, [sp, #28]         @Loads *pu2_iscal_mat\n    ldr           r6, [sp, #32]         @Loads *pu2_weigh_mat\n    ldrsh         r8, [r0]              @load pi2_src[0], SH for signed halfword load\n    ldrh          r6, [r6]              @load pu2_weight_mat[0] , H for unsigned halfword load\n    ldrh          r5, [r5]              @load pu2_iscal_mat[0] , H for unsigned halfword load\n@=======================DEQUANT FROM HERE===================================\n    mul           r6, r6, r5            @pu2_iscal_mat[0]*pu2_weigh_mat[0]\n    ldr           r7, [sp, #36]         @Loads u4_qp_div_6\n    mul           r6, r6, r8            @pi2_src[0]*pu2_iscal_mat[0]*pu2_weigh_mat[0]\n    ldr           r4, [sp, #24]         @Loads out_strd\n\n    vpush         {d8-d15}\n    lsl           r6, r6, r7            @(pi2_src[0]*pu2_iscal_mat[0]*pu2_weigh_mat[0])<<u4_qp_div_6\n    add           r6, r6, #32           @(pi2_src[0]*pu2_iscal_mat[0]*pu2_weigh_mat[0])<<u4_qp_div_6 + rnd_fact\n    asr           r6, r6, #6            @q0 = (pi2_src[0]*pu2_iscal_mat[0]*pu2_weigh_mat[0] + rnd_fact)<<(u4_qp_div_6-4)\n    add           r6, r6, #32           @i_macro = q0 + 32\n    asr           r6, r6, #6            @i_macro >>6 = DC output of 2-stage transform\n    vdup.s16      q8, r6                @copy transform output to Q0\n\n    vld1.32       d24, [r1], r3         @ Q12 = 0x070605....0x070605....\n\n    vld1.32       d25, [r1], r3         @ Q12 = 0x070605....0x070605....\n\n    vld1.32       d26, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vaddw.u8      q0, q8, d24\n    vld1.32       d27, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vaddw.u8      q1, q8, d25\n    vld1.32       d28, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vaddw.u8      q2, q8, d26\n    vld1.32       d29, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vaddw.u8      q3, q8, d27\n    vld1.32       d30, [r1], r3         @ Q12 = 0x070605....0x070605....\n    vaddw.u8      q4, q8, d28\n    vld1.32       d31, [r1], r3         @ Q12 = 0x070605....0x070605....\n\n@ Code Added to pack sign and magnitudes\n\n\n    vqmovun.s16   d0, q0\n    vaddw.u8      q5, q8, d29\n    vqmovun.s16   d1, q1\n    vaddw.u8      q6, q8, d30\n    vqmovun.s16   d2, q2\n    vqmovun.s16   d3, q3\n    vaddw.u8      q7, q8, d31\n    vqmovun.s16   d4, q4\n    vqmovun.s16   d5, q5\n    vst1.32       d0, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vqmovun.s16   d6, q6\n    vst1.32       d1, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vqmovun.s16   d7, q7\n    vst1.32       d2, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vst1.32       d3, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vst1.32       d4, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vst1.32       d5, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vst1.32       d6, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n    vst1.32       d7, [r2], r4          @ Magnitudes of 1st 4x4 block coeffs\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r8, r15}\n\n\n@ *\n@ ********************************************************************************\n@ *\n@ * @brief This function reconstructs a 4x4 sub block from quantized resiude and\n@ * prediction buffer if only dc value is present for residue\n@ *\n@ * @par Description:\n@ *  The quantized residue is first inverse quantized,\n@ *  This inverse quantized content is added to the prediction buffer to recon-\n@ *  struct the end output\n@ *\n@ * @param[in] pi2_src\n@ *  quantized dc coeffiient\n@ *\n@ * @param[in] pu1_pred\n@ *  prediction 4x4 block in interleaved format\n@ *\n@ * @param[in] pred_strd,\n@ *  Prediction buffer stride in interleaved format\n@ *\n@ * @param[in] out_strd\n@ *  recon buffer Stride\n@ *\n@ * @returns none\n@ *\n@ * @remarks none\n@ *\n@ *******************************************************************************\n@ *\n@ void ih264_iquant_itrans_recon_chroma_4x4_dc(WORD16 *pi2_src,\n@                                             UWORD8 *pu1_pred,\n@                                             UWORD8 *pu1_out,\n@                                             WORD32 pred_strd,\n@                                             WORD32 out_strd,\n@                                             const UWORD16 *pu2_iscal_mat,\n@                                             const UWORD16 *pu2_weigh_mat,\n@                                             UWORD32 u4_qp_div_6,\n@                                             WORD16 *pi2_tmp,\n@                                             WORD16 *pi2_dc_src)\n@ Register Usage\n@ r0 : pi2_src\n@ r1 : pu1_pred\n@ r2 : pu1_out\n@ r3 : pred_strd\n@ Neon registers d0-d7, d16-d30 are used\n@ No need for pushing  arm and neon registers\n    .global ih264_iquant_itrans_recon_chroma_4x4_dc_a9\nih264_iquant_itrans_recon_chroma_4x4_dc_a9:\n\n    ldr           r0, [sp, #20]\n    vld1.s16      d0, [r0]              @load pi2_dc_src\n\n    ldr           r0, [sp]              @load out_strd\n\n    vld2.s8       {d2, d3}, [r1], r3    @load pred plane 1 => d2 &pred palne 2 => d3\n    vld2.s8       {d3, d4}, [r1], r3\n    vrshr.s16     d0, d0, #6            @i_macro = ((q0 + 32) >> 6);\n    vld2.s8       {d4, d5}, [r1], r3\n    vld2.s8       {d5, d6}, [r1], r3\n\n    vdup.s16      q0, d0[0]             @duplicate pi2_sr[0]\n    mov           r1, r2                @backup pu1_out\n\n    vtrn.32       d2, d3                @mov the 4 coeffs of current block to d2\n    vtrn.32       d4, d5\n\n    vmov.u16      q15, #0x00ff\n\n\n    vld1.u8       d18, [r2], r0         @load out [8 bit size) -8 coeffs\n    vaddw.u8      q1, q0, d2            @Add pred\n    vld1.u8       d19, [r2], r0\n    vaddw.u8      q2, q0, d4\n    vld1.u8       d20, [r2], r0\n    vld1.u8       d21, [r2], r0\n\n    vqmovun.s16   d2, q1\n    vqmovun.s16   d4, q2\n\n    vmovl.u8      q1, d2\n    vmovl.u8      q2, d4\n\n    vbit.u8       q9, q1, q15\n    vbit.u8       q10, q2, q15\n\n    vst1.u8       d18, [r1], r0         @store  out\n    vst1.u8       d19, [r1], r0\n    vst1.u8       d20, [r1], r0\n    vst1.u8       d21, [r1], r0\n\n    bx            lr\n\n\n\n\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_mem_fns_neon.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@ *******************************************************************************\n@ * @file\n@ *  ih264_mem_fns_neon.s\n@ *\n@ * @brief\n@ *  Contains function definitions for memory manipulation\n@ *\n@ * @author\n@ *  Naveen SR\n@ *\n@ * @par List of Functions:\n@ *  - ih264_memcpy_mul_8_a9q()\n@ *  - ih264_memcpy_a9q()\n@ *  - ih264_memset_mul_8_a9q()\n@ *  - ih264_memset_a9q()\n@ *  - ih264_memset_16bit_mul_8_a9q()\n@ *  - ih264_memset_a9q()\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n@*\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*   memcpy of a 1d array\n@*\n@* @par Description:\n@*   Does memcpy of 8bit data from source to destination for 8,16 or 32 number of bytes\n@*\n@* @param[in] pu1_dst\n@*  UWORD8 pointer to the destination\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[in] num_bytes\n@*  number of bytes to copy\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@void ih264_memcpy_mul_8(UWORD8 *pu1_dst,\n@                    UWORD8 *pu1_src,\n@                   UWORD32 num_bytes)\n@**************Variables Vs Registers*************************\n@   r0 => *pu1_dst\n@   r1 => *pu1_src\n@   r2 => num_bytes\n\n.text\n.p2align 2\n\n\n    .global ih264_memcpy_mul_8_a9q\n\nih264_memcpy_mul_8_a9q:\n\nloop_neon_memcpy_mul_8:\n    @ Memcpy 8 bytes\n    vld1.8        d0, [r1]!\n    vst1.8        d0, [r0]!\n\n    subs          r2, r2, #8\n    bne           loop_neon_memcpy_mul_8\n    bx            lr\n\n\n\n@*******************************************************************************\n@*\n@void ih264_memcpy(UWORD8 *pu1_dst,\n@                  UWORD8 *pu1_src,\n@                  UWORD32 num_bytes)\n@**************Variables Vs Registers*************************\n@   r0 => *pu1_dst\n@   r1 => *pu1_src\n@   r2 => num_bytes\n\n\n\n    .global ih264_memcpy_a9q\n\nih264_memcpy_a9q:\n    subs          r2, #8\n    blt           memcpy\nloop_neon_memcpy:\n    @ Memcpy 8 bytes\n    vld1.8        d0, [r1]!\n    vst1.8        d0, [r0]!\n\n    subs          r2, #8\n    bge           loop_neon_memcpy\n    cmp           r2, #-8\n    bxeq          lr\n\nmemcpy:\n    add           r2, #8\n\nloop_memcpy:\n    ldrb          r3, [r1], #1\n    strb          r3, [r0], #1\n    subs          r2, #1\n    bne           loop_memcpy\n    bx            lr\n\n\n\n\n@void ih264_memset_mul_8(UWORD8 *pu1_dst,\n@                       UWORD8 value,\n@                       UWORD32 num_bytes)\n@**************Variables Vs Registers*************************\n@   r0 => *pu1_dst\n@   r1 => value\n@   r2 => num_bytes\n\n\n\n\n\n    .global ih264_memset_mul_8_a9q\n\nih264_memset_mul_8_a9q:\n\n@ Assumptions: numbytes is either 8, 16 or 32\n    vdup.8        d0, r1\nloop_memset_mul_8:\n    @ Memset 8 bytes\n    vst1.8        d0, [r0]!\n\n    subs          r2, r2, #8\n    bne           loop_memset_mul_8\n\n    bx            lr\n\n\n\n\n@void ih264_memset(UWORD8 *pu1_dst,\n@                       UWORD8 value,\n@                       UWORD8 num_bytes)\n@**************Variables Vs Registers*************************\n@   r0 => *pu1_dst\n@   r1 => value\n@   r2 => num_bytes\n\n\n\n    .global ih264_memset_a9q\n\nih264_memset_a9q:\n    subs          r2, #8\n    blt           memset\n    vdup.8        d0, r1\nloop_neon_memset:\n    @ Memcpy 8 bytes\n    vst1.8        d0, [r0]!\n\n    subs          r2, #8\n    bge           loop_neon_memset\n    cmp           r2, #-8\n    bxeq          lr\n\nmemset:\n    add           r2, #8\n\nloop_memset:\n    strb          r1, [r0], #1\n    subs          r2, #1\n    bne           loop_memset\n    bx            lr\n\n\n\n\n@void ih264_memset_16bit_mul_8(UWORD16 *pu2_dst,\n@                                   UWORD16 value,\n@                                   UWORD32 num_words)\n@**************Variables Vs Registers*************************\n@   r0 => *pu2_dst\n@   r1 => value\n@   r2 => num_words\n\n\n\n\n\n    .global ih264_memset_16bit_mul_8_a9q\n\nih264_memset_16bit_mul_8_a9q:\n\n@ Assumptions: num_words is either 8, 16 or 32\n\n    @ Memset 8 words\n    vdup.16       d0, r1\nloop_memset_16bit_mul_8:\n    vst1.16       d0, [r0]!\n    vst1.16       d0, [r0]!\n\n    subs          r2, r2, #8\n    bne           loop_memset_16bit_mul_8\n\n    bx            lr\n\n\n\n\n@void ih264_memset_16bit(UWORD16 *pu2_dst,\n@                       UWORD16 value,\n@                       UWORD32 num_words)\n@**************Variables Vs Registers*************************\n@   r0 => *pu2_dst\n@   r1 => value\n@   r2 => num_words\n\n\n\n    .global ih264_memset_16bit_a9q\n\nih264_memset_16bit_a9q:\n    subs          r2, #8\n    blt           memset_16bit\n    vdup.16       d0, r1\nloop_neon_memset_16bit:\n    @ Memset 8 words\n    vst1.16       d0, [r0]!\n    vst1.16       d0, [r0]!\n\n    subs          r2, #8\n    bge           loop_neon_memset_16bit\n    cmp           r2, #-8\n    bxeq          lr\n\nmemset_16bit:\n    add           r2, #8\n\nloop_memset_16bit:\n    strh          r1, [r0], #2\n    subs          r2, #1\n    bne           loop_memset_16bit\n    bx            lr\n\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_padding_neon.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@*\n@ *******************************************************************************\n@ * @file\n@ *  ih264_padding_neon.s\n@ *\n@ * @brief\n@ *  Contains function definitions padding\n@ *\n@ * @author\n@ *  Ittiam\n@ *\n@ * @par List of Functions:\n@ *  - ih264_pad_top_a9q()\n@ *  - ih264_pad_left_luma_a9q()\n@ *  - ih264_pad_left_chroma_a9q()\n@ *  - ih264_pad_right_luma_a9q()\n@ *  - ih264_pad_right_chroma_a9q()\n@ *\n@ * @remarks\n@ *  None\n@ *\n@ *******************************************************************************\n@*\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief pad at the top of a 2d array\n@*\n@* @par Description:\n@*  The top row of a 2d array is replicated for pad_size times at the top\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @param[in] pad_size\n@*  integer -padding size of the array\n@*\n@* @returns none\n@*\n@* @remarks none\n@*\n@*******************************************************************************\n@*\n@void ih264_pad_top(UWORD8 *pu1_src,\n@                   WORD32 src_strd,\n@                   WORD32 wd,\n@                   WORD32 pad_size)\n@**************Variables Vs Registers*************************\n@   r0 => *pu1_src\n@   r1 => src_strd\n@   r2 => wd\n@   r3 => pad_size\n\n.text\n.p2align 2\n\n    .global ih264_pad_top_a9q\n\nih264_pad_top_a9q:\n\n    stmfd         sp!, {r4-r11, lr}     @stack stores the values of the arguments\n\n    sub           r5, r0, r1\n    neg           r6, r1\n\nloop_neon_memcpy_mul_16:\n    @ Load 16 bytes\n    vld1.8        {d0, d1}, [r0]!\n    mov           r4, r5\n    mov           r7, r3\n    add           r5, r5, #16\n\nloop_neon_pad_top:\n    vst1.8        {d0, d1}, [r4], r6\n    subs          r7, r7, #1\n    bne           loop_neon_pad_top\n\n    subs          r2, r2, #16\n    bne           loop_neon_memcpy_mul_16\n\n    ldmfd         sp!, {r4-r11, pc}     @Reload the registers from SP\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*   Padding (luma block) at the left of a 2d array\n@*\n@* @par Description:\n@*   The left column of a 2d array is replicated for pad_size times at the left\n@*\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @param[in] pad_size\n@*  integer -padding size of the array\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@#if PAD_LEFT_LUMA == C\n@void ih264_pad_left_luma(UWORD8 *pu1_src,\n@                        WORD32 src_strd,\n@                        WORD32 ht,\n@                        WORD32 pad_size)\n@**************Variables Vs Registers*************************\n@   r0 => *pu1_src\n@   r1 => src_strd\n@   r2 => ht\n@   r3 => pad_size\n\n\n\n    .global ih264_pad_left_luma_a9q\n\nih264_pad_left_luma_a9q:\n\n    stmfd         sp!, {r4-r11, lr}     @stack stores the values of the arguments\n\n\n    sub           r4, r0, r3\n    sub           r6, r1, #16\n    subs          r5, r3, #16\n    bne           loop_32\nloop_16:                                @  /*hard coded for width=16  ,height =8,16*/\n    ldrb          r8, [r0], r1\n    ldrb          r9, [r0], r1\n    vdup.u8       q0, r8\n    ldrb          r10, [r0], r1\n    vst1.8        {q0}, [r4], r1        @ 16 bytes store\n    vdup.u8       q1, r9\n    vst1.8        {q1}, [r4], r1        @ 16 bytes store\n    ldrb          r11, [r0], r1\n    vdup.u8       q2, r10\n    vdup.u8       q3, r11\n    vst1.8        {q2}, [r4], r1        @ 16 bytes store\n    ldrb          r8, [r0], r1\n    vst1.8        {q3}, [r4], r1        @ 16 bytes store\n    ldrb          r9, [r0], r1\n    vdup.u8       q0, r8\n    ldrb          r10, [r0], r1\n    vst1.8        {q0}, [r4], r1        @ 16 bytes store\n    vdup.u8       q1, r9\n    ldrb          r11, [r0], r1\n    vst1.8        {q1}, [r4], r1        @ 16 bytes store\n    vdup.u8       q2, r10\n    vdup.u8       q3, r11\n    subs          r2, r2, #8\n    vst1.8        {q2}, [r4], r1        @ 16 bytes store\n    vst1.8        {q3}, [r4], r1        @ 16 bytes store\n    bne           loop_16\n    b             end_func\n\nloop_32:                                @  /*hard coded for width=32 ,height =8,16*/\n    ldrb          r8, [r0], r1\n    ldrb          r9, [r0], r1\n    vdup.u8       q0, r8\n    ldrb          r10, [r0], r1\n    vst1.8        {q0}, [r4]!           @ 16 bytes store\n    vdup.u8       q1, r9\n    vst1.8        {q0}, [r4], r6\n    vst1.8        {q1}, [r4]!           @ 16 bytes store\n    vdup.u8       q2, r10\n    vst1.8        {q1}, [r4], r6        @ 16 bytes store\n    ldrb          r11, [r0], r1\n    vst1.8        {q2}, [r4]!           @ 16 bytes store\n    vdup.u8       q3, r11\n    vst1.8        {q2}, [r4], r6        @ 16 bytes store\n    ldrb          r8, [r0], r1\n    vst1.8        {q3}, [r4]!           @ 16 bytes store\n    vdup.u8       q0, r8\n    ldrb          r9, [r0], r1\n    vst1.8        {q3}, [r4], r6        @ 16 bytes store\n    ldrb          r10, [r0], r1\n    vst1.8        {q0}, [r4]!           @ 16 bytes store\n    vdup.u8       q1, r9\n    vst1.8        {q0}, [r4], r6        @ 16 bytes store\n    ldrb          r11, [r0], r1\n    vst1.8        {q1}, [r4]!           @ 16 bytes store\n    vdup.u8       q2, r10\n    vst1.8        {q1}, [r4], r6        @ 16 bytes store\n    vst1.8        {q2}, [r4]!           @ 16 bytes store\n    vdup.u8       q3, r11\n    vst1.8        {q2}, [r4], r6        @ 16 bytes store\n    subs          r2, r2, #8\n    vst1.8        {q3}, [r4]!           @ 16 bytes store\n    vst1.8        {q3}, [r4], r6        @ 16 bytes store\n    bne           loop_32\n\n\n\nend_func:\n    ldmfd         sp!, {r4-r11, pc}     @Reload the registers from SP\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@*   Padding (chroma block) at the left of a 2d array\n@*\n@* @par Description:\n@*   The left column of a 2d array is replicated for pad_size times at the left\n@*\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array (each colour component)\n@*\n@* @param[in] pad_size\n@*  integer -padding size of the array\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@#if PAD_LEFT_CHROMA == C\n@void ih264_pad_left_chroma(UWORD8 *pu1_src,\n@                            WORD32 src_strd,\n@                            WORD32 ht,\n@                            WORD32 pad_size)\n@{\n@   r0 => *pu1_src\n@   r1 => src_strd\n@   r2 => ht\n@   r3 => pad_size\n\n\n\n    .global ih264_pad_left_chroma_a9q\n\nih264_pad_left_chroma_a9q:\n\n    stmfd         sp!, {r4-r11, lr}     @stack stores the values of the arguments\n\n    sub           r4, r0, r3\n    sub           r6, r1, #16\n\n\nloop_32_l_c:                            @  /*hard coded for width=32  ,height =4,8,12*/\n    ldrh          r8, [r0], r1\n    ldrh          r9, [r0], r1\n    vdup.u16      q0, r8\n    ldrh          r10, [r0], r1\n    vst1.8        {q0}, [r4]!           @ 16 bytes store\n    vdup.u16      q1, r9\n    vst1.8        {q0}, [r4], r6        @ 16 bytes store\n    ldrh          r11, [r0], r1\n    vst1.8        {q1}, [r4]!           @ 16 bytes store\n    vdup.u16      q2, r10\n    vst1.8        {q1}, [r4], r6        @ 16 bytes store\n    vdup.u16      q3, r11\n    vst1.8        {q2}, [r4]!           @ 16 bytes store\n    vst1.8        {q2}, [r4], r6        @ 16 bytes store\n    subs          r2, r2, #4\n    vst1.8        {q3}, [r4]!           @ 16 bytes store\n    vst1.8        {q3}, [r4], r6        @ 16 bytes store\n\n\n    beq           end_func_l_c          @/* Branching when ht=4*/\n\n    ldrh          r8, [r0], r1\n    ldrh          r9, [r0], r1\n    vdup.u16      q0, r8\n    ldrh          r10, [r0], r1\n    vst1.8        {q0}, [r4]!           @ 16 bytes store\n    vdup.u16      q1, r9\n    vst1.8        {q0}, [r4], r6\n    ldrh          r11, [r0], r1\n    vst1.8        {q1}, [r4]!           @ 16 bytes store\n    vdup.u16      q2, r10\n    vst1.8        {q1}, [r4], r6        @ 16 bytes store\n    vdup.u16      q3, r11\n    vst1.8        {q2}, [r4]!           @ 16 bytes store\n    vst1.8        {q2}, [r4], r6        @ 16 bytes store\n    subs          r2, r2, #4\n    vst1.8        {q3}, [r4]!           @ 16 bytes store\n    vst1.8        {q3}, [r4], r6        @ 16 bytes store\n\n    beq           end_func_l_c          @/* Branching when ht=8*/\n    bne           loop_32_l_c\n\n    ldrh          r8, [r0], r1\n    ldrh          r9, [r0], r1\n    vdup.u16      q0, r8\n    ldrh          r10, [r0], r1\n    vst1.8        {q0}, [r4]!           @ 16 bytes store\n    vdup.u16      q1, r9\n    vst1.8        {q0}, [r4], r6\n    ldrh          r11, [r0], r1\n    vst1.8        {q1}, [r4]!           @ 16 bytes store\n    vdup.u16      q2, r10\n    vst1.8        {q1}, [r4], r6        @ 16 bytes store\n    vdup.u16      q3, r11\n    vst1.8        {q2}, [r4]!           @ 16 bytes store\n    vst1.8        {q2}, [r4], r6        @ 16 bytes store\n    vst1.8        {q3}, [r4]!           @ 16 bytes store\n    vst1.8        {q3}, [r4], r6        @ 16 bytes store\n\nend_func_l_c:\n    ldmfd         sp!, {r4-r11, pc}     @Reload the registers from SP\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@* Padding (luma block) at the right of a 2d array\n@*\n@* @par Description:\n@* The right column of a 2d array is replicated for pad_size times at the right\n@*\n@*\n@* @param[in] pu1_src\n@*  UWORD8 pointer to the source\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @param[in] pad_size\n@*  integer -padding size of the array\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@#if PAD_RIGHT_LUMA == C\n@void ih264_pad_right_luma(UWORD8 *pu1_src,\n@                        WORD32 src_strd,\n@                        WORD32 ht,\n@                        WORD32 pad_size)\n@{\n@    WORD32 row;\n@\n@    for(row = 0; row < ht; row++)\n@    {\n@        memset(pu1_src, *(pu1_src -1), pad_size);\n@\n@        pu1_src += src_strd;\n@    }\n@}\n@\n@   r0 => *pu1_src\n@   r1 => src_strd\n@   r2 => ht\n@   r3 => pad_size\n\n\n\n    .global ih264_pad_right_luma_a9q\n\nih264_pad_right_luma_a9q:\n\n    stmfd         sp!, {r4-r11, lr}     @stack stores the values of the arguments\n\n    mov           r4, r0\n    sub           r6, r1, #16\n    sub           r0, r0, #1\n    subs          r5, r3, #16\n    bne           loop_32\nloop_16_r: @  /*hard coded for width=16  ,height =8,16*/\n    ldrb          r8, [r0], r1\n    ldrb          r9, [r0], r1\n    vdup.u8       q0, r8\n    ldrb          r10, [r0], r1\n    vst1.8        {q0}, [r4], r1        @ 16 bytes store\n    vdup.u8       q1, r9\n    vst1.8        {q1}, [r4], r1        @ 16 bytes store\n    ldrb          r11, [r0], r1\n    vdup.u8       q2, r10\n    vdup.u8       q3, r11\n    vst1.8        {q2}, [r4], r1        @ 16 bytes store\n    ldrb          r8, [r0], r1\n    vst1.8        {q3}, [r4], r1        @ 16 bytes store\n    ldrb          r9, [r0], r1\n    vdup.u8       q0, r8\n    ldrb          r10, [r0], r1\n    vst1.8        {q0}, [r4], r1        @ 16 bytes store\n    vdup.u8       q1, r9\n    ldrb          r11, [r0], r1\n    vst1.8        {q1}, [r4], r1        @ 16 bytes store\n    vdup.u8       q2, r10\n    vdup.u8       q3, r11\n    subs          r2, r2, #8\n    vst1.8        {q2}, [r4], r1        @ 16 bytes store\n    vst1.8        {q3}, [r4], r1        @ 16 bytes store\n    bne           loop_16_r\n    b             end_func_r\n\nloop_32_r:                              @  /*hard coded for width=32  ,height =8,16*/\n    ldrb          r8, [r0], r1\n    ldrb          r9, [r0], r1\n    vdup.u8       q0, r8\n    ldrb          r10, [r0], r1\n    vst1.8        {q0}, [r4]!           @ 16 bytes store\n    vdup.u8       q1, r9\n    vst1.8        {q0}, [r4], r6\n    vst1.8        {q1}, [r4]!           @ 16 bytes store\n    vdup.u8       q2, r10\n    vst1.8        {q1}, [r4], r6        @ 16 bytes store\n    ldrb          r11, [r0], r1\n    vst1.8        {q2}, [r4]!           @ 16 bytes store\n    vdup.u8       q3, r11\n    vst1.8        {q2}, [r4], r6        @ 16 bytes store\n    ldrb          r8, [r0], r1\n    vst1.8        {q3}, [r4]!           @ 16 bytes store\n    ldrb          r9, [r0], r1\n    vdup.u8       q0, r8\n    vst1.8        {q3}, [r4], r6        @ 16 bytes store\n    ldrb          r10, [r0], r1\n    vst1.8        {q0}, [r4]!           @ 16 bytes store\n    vdup.u8       q1, r9\n    vst1.8        {q0}, [r4], r6        @ 16 bytes store\n    ldrb          r11, [r0], r1\n    vst1.8        {q1}, [r4]!           @ 16 bytes store\n    vdup.u8       q2, r10\n    vst1.8        {q1}, [r4], r6        @ 16 bytes store\n    vst1.8        {q2}, [r4]!           @ 16 bytes store\n    vdup.u8       q3, r11\n    vst1.8        {q2}, [r4], r6        @ 16 bytes store\n    subs          r2, r2, #8\n    vst1.8        {q3}, [r4]!           @ 16 bytes store\n    vst1.8        {q3}, [r4], r6        @ 16 bytes store\n    bne           loop_32_r\n\n\n\nend_func_r:\n    ldmfd         sp!, {r4-r11, pc}     @Reload the registers from SP\n\n\n\n\n\n@**\n@*******************************************************************************\n@*\n@* @brief\n@;* Padding (chroma block) at the right of a 2d array\n@*\n@* @par Description:\n@* The right column of a 2d array is replicated for pad_size times at the right\n@*\n@*\n@* @param[in] pu1_src\n@;*  UWORD8 pointer to the source\n@*\n@* @param[in] src_strd\n@*  integer source stride\n@*\n@* @param[in] ht\n@;*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array (each colour component)\n@*\n@* @param[in] pad_size\n@*  integer -padding size of the array\n@*\n@* @param[in] ht\n@;*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@#if PAD_RIGHT_CHROMA == C\n@void ih264_pad_right_chroma(UWORD8 *pu1_src,\n@                        WORD32 src_strd,\n@                        WORD32 ht,\n@                        WORD32 pad_size)\n@   r0 => *pu1_src\n@   r1 => src_strd\n@   r2 => ht\n@   r3 => pad_size\n\n\n\n    .global ih264_pad_right_chroma_a9q\n\nih264_pad_right_chroma_a9q:\n\n    stmfd         sp!, {r4-r11, lr}     @stack stores the values of the arguments\n\n    mov           r4, r0\n    sub           r6, r1, #16\n    sub           r0, r0, #2\nloop_32_r_c: @  /*hard coded for width=32 ,height =8,4*/\n    ldrh          r8, [r0], r1\n    ldrh          r9, [r0], r1\n    vdup.u16      q0, r8\n    ldrh          r10, [r0], r1\n    vst1.8        {q0}, [r4]!           @ 16 bytes store\n    vdup.u16      q1, r9\n    vst1.8        {q0}, [r4], r6\n    vst1.8        {q1}, [r4]!           @ 16 bytes store\n    vdup.u16      q2, r10\n    vst1.8        {q1}, [r4], r6        @ 16 bytes store\n    subs          r2, r2, #4\n    ldrh          r11, [r0], r1\n    vst1.8        {q2}, [r4]!           @ 16 bytes store\n    vdup.u16      q3, r11\n    vst1.8        {q2}, [r4], r6        @ 16 bytes store\n    vst1.8        {q3}, [r4]!           @ 16 bytes store\n    vst1.8        {q3}, [r4], r6        @ 16 bytes store\n\n    beq           end_func_r_c          @/* Branching when ht=4*/\n\n    ldrh          r8, [r0], r1\n    vdup.u16      q0, r8\n    ldrh          r9, [r0], r1\n    ldrh          r10, [r0], r1\n    vst1.8        {q0}, [r4]!           @ 16 bytes store\n    vdup.u16      q1, r9\n    vst1.8        {q0}, [r4], r6        @ 16 bytes store\n    ldrh          r11, [r0], r1\n    vst1.8        {q1}, [r4]!           @ 16 bytes store\n    vdup.u16      q2, r10\n    vst1.8        {q1}, [r4], r6        @ 16 bytes store\n    vst1.8        {q2}, [r4]!           @ 16 bytes store\n    vdup.u16      q3, r11\n    vst1.8        {q2}, [r4], r6        @ 16 bytes store\n    subs          r2, r2, #4\n    vst1.8        {q3}, [r4]!           @ 16 bytes store\n    vst1.8        {q3}, [r4], r6        @ 16 bytes store\n\n    beq           end_func_r_c          @/* Branching when ht=8*/\n    bne           loop_32_r_c\n\n    ldrh          r8, [r0], r1\n    vdup.u16      q0, r8\n    ldrh          r9, [r0], r1\n    ldrh          r10, [r0], r1\n    vst1.8        {q0}, [r4]!           @ 16 bytes store\n    vdup.u16      q1, r9\n    vst1.8        {q0}, [r4], r6        @ 16 bytes store\n    ldrh          r11, [r0], r1\n    vst1.8        {q1}, [r4]!           @ 16 bytes store\n    vdup.u16      q2, r10\n    vst1.8        {q1}, [r4], r6        @ 16 bytes store\n    vst1.8        {q2}, [r4]!           @ 16 bytes store\n    vdup.u16      q3, r11\n    vst1.8        {q2}, [r4], r6        @ 16 bytes store\n    vst1.8        {q3}, [r4]!           @ 16 bytes store\n    vst1.8        {q3}, [r4], r6        @ 16 bytes store\n\nend_func_r_c:\n    ldmfd         sp!, {r4-r11, pc}     @Reload the registers from SP\n\n\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_platform_macros.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_platform_macros.h\n*\n* @brief\n*  Platform specific Macro definitions used in the codec\n*\n* @author\n*  Ittiam\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n#ifndef _IH264_PLATFORM_MACROS_H_\n#define _IH264_PLATFORM_MACROS_H_\n\n#include <stdint.h>\n\n#ifndef  ARMV8\n\nstatic __inline WORD32 CLIP_U8(WORD32 x)\n{\n    asm(\"usat %0, #8, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_S8(WORD32 x)\n{\n    asm(\"ssat %0, #8, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_U10(WORD32 x)\n{\n    asm(\"usat %0, #10, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_S10(WORD32 x)\n{\n    asm(\"ssat %0, #10, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_U11(WORD32 x)\n{\n    asm(\"usat %0, #11, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_S11(WORD32 x)\n{\n    asm(\"ssat %0, #11, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_U12(WORD32 x)\n{\n    asm(\"usat %0, #12, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_S12(WORD32 x)\n{\n    asm(\"ssat %0, #12, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_U16(WORD32 x)\n{\n    asm(\"usat %0, #16, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\nstatic __inline WORD32 CLIP_S16(WORD32 x)\n{\n    asm(\"ssat %0, #16, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\n\nstatic __inline UWORD32 ITT_BIG_ENDIAN(UWORD32 x)\n{\n    asm(\"rev %0, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n#define NOP(nop_cnt)    {UWORD32 nop_i; for (nop_i = 0; nop_i < nop_cnt; nop_i++) asm(\"nop\");}\n\n#else\n\n#define CLIP_U8(x) CLIP3(0, UINT8_MAX, (x))\n#define CLIP_S8(x) CLIP3(INT8_MIN, INT8_MAX, (x))\n\n#define CLIP_U10(x) CLIP3(0, 1023, (x))\n#define CLIP_S10(x) CLIP3(-512, 511, (x))\n\n#define CLIP_U11(x) CLIP3(0, 2047, (x))\n#define CLIP_S11(x) CLIP3(-1024, 1023, (x))\n\n#define CLIP_U12(x) CLIP3(0, 4095, (x))\n#define CLIP_S12(x) CLIP3(-2048, 2047, (x))\n\n#define CLIP_U16(x) CLIP3(0, UINT16_MAX, (x))\n#define CLIP_S16(x) CLIP3(INT16_MIN, INT16_MAX, (x))\n\n#define ITT_BIG_ENDIAN(x)       __asm__(\"rev %0, %1\" : \"=r\"(x) : \"r\"(x));\n\n#define NOP(nop_cnt)                                \\\n{                                                   \\\n    UWORD32 nop_i;                                  \\\n    for (nop_i = 0; nop_i < nop_cnt; nop_i++)       \\\n        __asm__ __volatile__(\"mov x0, x0\");         \\\n}\n\n#endif\n\n/*saturating instructions are not available for WORD64 in ARMv7, hence we cannot\n * use inline assembly like other clips*/\n#define CLIP_U32(x) CLIP3(0, UINT32_MAX, (x))\n#define CLIP_S32(x) CLIP3(INT32_MIN, INT32_MAX, (x))\n\n#define DATA_SYNC() __sync_synchronize()\n\n#define SHL(x,y) (((y) < 32) ? ((x) << (y)) : 0)\n#define SHR(x,y) (((y) < 32) ? ((x) >> (y)) : 0)\n\n#define SHR_NEG(val,shift)  ((shift>0)?(val>>shift):(val<<(-shift)))\n#define SHL_NEG(val,shift)  ((shift<0)?(val>>(-shift)):(val<<shift))\n\n#define INLINE inline\n\n/* In normal cases, 0 will not be passed as an argument to CLZ and CTZ.\nAs CLZ and CTZ outputs are used as a shift value in few places, these return\n31 for u4_word == 0 case, just to handle error cases gracefully without any\nundefined behaviour */\n\nstatic INLINE UWORD32 CLZ(UWORD32 u4_word)\n{\n    if(u4_word)\n        return (__builtin_clz(u4_word));\n    else\n        return 31;\n}\nstatic INLINE UWORD32 CTZ(UWORD32 u4_word)\n{\n    if(0 == u4_word)\n        return 31;\n    else\n    {\n        unsigned int index;\n        index = __builtin_ctz(u4_word);\n        return (UWORD32)index;\n    }\n}\n\n#define MEM_ALIGN8 __attribute__ ((aligned (8)))\n#define MEM_ALIGN16 __attribute__ ((aligned (16)))\n#define MEM_ALIGN32 __attribute__ ((aligned (32)))\n\n#endif /* _IH264_PLATFORM_MACROS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_resi_trans_quant_a9.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@*******************************************************************************\n@* @file\n@*  ih264_resi_trans_quant_a9.s\n@*\n@* @brief\n@*  Contains function definitions for residual and forward trans\n@*\n@* @author\n@*  Ittiam\n@*\n@* @par List of Functions:\n@*  ih264_resi_trans_quant_4x4_a9\n@*  ih264_resi_trans_quant_8x8_a9\n@*  ih264_resi_trans_quant_chroma_4x4_a9\n@*  ih264_hadamard_quant_4x4_a9\n@*  ih264_hadamard_quant_2x2_uv_a9\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n\n\n.text\n.p2align 2\n@*****************************************************************************\n@*\n@* Function Name     : ih264_resi_trans_quant_4x4_a9\n@* Description       : This function does cf4 of H264\n@*\n@* Arguments         :  R0 :pointer to src buffer\n@                       R1 :pointer to pred buffer\n@                       R2 :pointer to dst buffer\n@                       R3 :source stride\n@                       STACK : pred stride,\n@                               dst stride,\n@                               pointer to scaling matrix,\n@                               pointer to threshold matrix,\n@                               qbits,\n@                               rounding factor,\n@                               pointer to store nnz\n@                               pointer to store non quantized dc value\n@ Values Returned   : NONE\n@\n@ Register Usage    :\n@ Stack Usage       : 40 bytes\n@ Cycles            : Around\n@ Interruptiaility  : Interruptable\n@\n@ Known Limitations\n@   \\Assumptions    :\n@\n@ Revision History  :\n@         DD MM YYYY    Author(s)   Changes\n@         1 12 2013    100633      First version\n@         20 1 2014    100633      Changes the API, Optimization\n@\n@*****************************************************************************\n\n    .global ih264_resi_trans_quant_4x4_a9\nih264_resi_trans_quant_4x4_a9:\n\n    @R0     :pointer to src buffer\n    @R1     :pointer to pred buffer\n    @R2     :pointer to dst buffer\n    @R3     :Source stride\n    @STACk  :pred stride\n    @       :scale matirx,\n    @       :threshold matrix\n    @       :qbits\n    @       :round factor\n    @       :nnz\n\n    push          {r4-r12, lr}          @push all the variables first\n\n    add           r11, sp, #40          @decrement stack pointer,to accomodate two variables\n    ldmfd         r11, {r4-r10}         @load the strides into registers\n\n    @R0     :pointer to src buffer\n    @R1     :pointer to pred buffer\n    @R2     :pointer to dst buffer\n    @R3     :Source stride\n    @R4     :Pred stride\n    @R5     :scale matirx,\n    @R6     :threshold matrix\n    @R7     :qbits\n    @R8     :round factor\n    @R9     :nnz\n\n    vpush         {d8-d15}\n\n    mov           r11, #0\n    sub           r7, r11, r7           @Negate the qbit value for usiing LSL\n\n    @------------Fucntion Loading done----------------;\n\n    vld1.u8       d30, [r0], r3         @load first 8 pix src row 1\n\n    vld1.u8       d31, [r1], r4         @load first 8 pix pred row 1\n\n    vld1.u8       d28, [r0], r3         @load first 8 pix src row 2\n\n    vld1.u8       d29, [r1], r4         @load first 8 pix pred row 2\n\n    vld1.u8       d26, [r0], r3         @load first 8 pix src row 3\n\n    vld1.u8       d27, [r1], r4         @load first 8 pix pred row 3\n    vsubl.u8      q0, d30, d31          @find residue row 1\n\n    vld1.u8       d24, [r0], r3         @load first 8 pix src row 4\n\n    vld1.u8       d25, [r1], r4         @load first 8 pix pred row 4\n    vsubl.u8      q1, d28, d29          @find residue row 2\n\n    vsubl.u8      q2, d26, d27          @find residue row 3\n    vsubl.u8      q3, d24, d25          @find residue row 4\n\n    vtrn.16       d0, d2                @T12\n    vtrn.16       d4, d6                @T23\n    vtrn.32       d0, d4                @T13\n    vtrn.32       d2, d6                @T14\n\n    vadd.s16      d8 , d0, d6           @x0 = x4+x7\n    vadd.s16      d9 , d2, d4           @x1 = x5+x6\n    vsub.s16      d10, d2, d4           @x2 = x5-x6\n    vsub.s16      d11, d0, d6           @x3 = x4-x7\n\n    vshl.s16      d12, d10, #1          @U_SHIFT(x2,1,shft)\n    vshl.s16      d13, d11, #1          @U_SHIFT(x3,1,shft)\n\n    vadd.s16      d14, d8, d9           @x4 = x0 + x1;\n    vsub.s16      d16, d8, d9           @x6 = x0 - x1;\n    vadd.s16      d15, d13, d10         @x5 = U_SHIFT(x3,1,shft) + x2;\n    vsub.s16      d17, d11, d12         @x7 = x3 - U_SHIFT(x2,1,shft);\n\n    @taking transpose again so as to make do vert transform\n    vtrn.16       d14, d15              @T12\n    vtrn.16       d16, d17              @T23\n    vtrn.32       d14, d16              @T13\n    vtrn.32       d15, d17              @T24\n\n    @let us do vertical transform\n    @same code as horiz\n    vadd.s16      d18, d14, d17         @x0 = x4+x7\n    vadd.s16      d19, d15, d16         @x1 = x5+x6\n    vsub.s16      d20, d15, d16         @x2 = x5-x6\n    vsub.s16      d21, d14, d17         @x3 = x4-x7\n\n    vshl.s16      d22, d20, #1          @U_SHIFT(x2,1,shft)\n    vshl.s16      d23, d21, #1          @U_SHIFT(x3,1,shft)\n\n    vdup.s32      q4, r8                @Load rounding value row 1\n\n    vadd.s16      d24, d18, d19         @x5 = x0 + x1;\n    vsub.s16      d26, d18, d19         @x7 = x0 - x1;\n    vadd.s16      d25, d23, d20         @x6 = U_SHIFT(x3,1,shft) + x2;\n    vsub.s16      d27, d21, d22         @x8 = x3 - U_SHIFT(x2,1,shft);\n    vdup.s32      q10, r7               @Load qbit values\n\n    vst1.s16      d24[0], [r10]         @Store the dc value to alternate dc sddress\n\n@core tranform is done for 4x8 block 1\n    vld1.s16      {q14-q15}, [r5]       @load the scaling values\n\n    vabs.s16      q0, q12               @Abs val of row 1 blk 1\n\n    vabs.s16      q1, q13               @Abs val of row 2 blk 1\n\n    vmov.s32      q5, q4                @copy round fact for row 2\n\n    vmov.s32      q6, q4                @copy round fact for row 2\n    vclt.s16      q2, q12, #0           @Get the sign of row 1 blk 1\n\n    vmov.s32      q7, q4                @copy round fact for row 2\n    vclt.s16      q3, q13, #0           @Get the sign of row 2 blk 1\n\n    vmlal.s16     q4, d0, d28           @Multiply and add row 1\n    vmlal.s16     q5, d1, d29           @Multiply and add row 2\n    vmlal.s16     q6, d2, d30           @Multiply and add row 3\n    vmlal.s16     q7, d3, d31           @Multiply and add row 4\n\n    vshl.s32      q11, q4, q10          @Shift row 1\n    vshl.s32      q12, q5, q10          @Shift row 2\n    vshl.s32      q13, q6, q10          @Shift row 3\n    vshl.s32      q14, q7, q10          @Shift row 4\n\n    vmovn.s32     d30, q11              @Narrow row 1\n    vmovn.s32     d31, q12              @Narrow row 2\n    vmovn.s32     d0 , q13              @Narrow row 3\n    vmovn.s32     d1 , q14              @Narrow row 4\n\n    vneg.s16      q1, q15               @Get negative\n    vneg.s16      q4, q0                @Get negative\n\n    vceq.s16      q5, q15, #0           @I  compare with zero row 1 and 2 blk 1\n    vceq.s16      q6, q0 , #0           @I  compare with zero row 1 and 2 blk 1\n\n    vbsl.s16      q2, q1, q15           @Restore sign of row 1 and 2\n    vbsl.s16      q3, q4, q0            @Restore sign of row 3 and 4\n\n\n    vmovn.u16     d14, q5               @I  Narrow the comparison for row 1 and 2 blk 1\n    vmovn.u16     d15, q6               @I  Narrow the comparison for row 1 and 2 blk 2\n\n    vshr.u8       q8, q7, #7            @I  Reduce comaparison bit to a signle bit row 1 and 2 blk  1 and 2 [ keep the value for later use ]\n\n    vpadd.u8      d18, d16, d17         @I pair add nnz 1\n    vpadd.u8      d20, d18, d19         @I Pair add nnz 2\n    vpadd.u8      d22, d20, d21         @I Pair add nnz 3\n    vpadd.u8      d24, d22, d23         @I Pair add nnz4\n    vst1.s16      {q2-q3}, [r2]         @Store blk\n\n    vmov.u8       d25, #16              @I Get max nnz\n    vsub.u8       d26, d25, d24         @I invert current nnz\n\n    vst1.u8       d26[0], [r9]          @I  Write nnz\n\n    vpop          {d8-d15}\n    pop           {r4-r12, pc}\n\n\n\n@*****************************************************************************\n@*\n@* Function Name     : ih264_resi_trans_quant_chroma_4x4_a9\n@* Description       : This function does residue calculation, forward transform\n@*                     and quantization for 4x4 chroma block.\n@*\n@* Arguments         :  R0 :pointer to src buffer\n@                       R1 :pointer to pred buffer\n@                       R2 :pointer to dst buffer\n@                       R3 :source stride\n@                       STACK : pred stride,\n@                               dst stride,\n@                               pointer to scaling matrix,\n@                               pointer to threshold matrix,\n@                               qbits,\n@                               rounding factor,\n@                               pointer to store nnz\n@                               pointer to store unquantized dc values\n@ Values Returned   : NONE\n@\n@ Register Usage    :\n@ Stack Usage       : 40 bytes\n@ Cycles            : Around\n@ Interruptiaility  : Interruptable\n@\n@ Known Limitations\n@   \\Assumptions    :\n@\n@ Revision History  :\n@         DD MM YYYY    Author(s)   Changes\n@         11 2 2015    100664      First version\n@\n@*****************************************************************************\n\n    .global ih264_resi_trans_quant_chroma_4x4_a9\nih264_resi_trans_quant_chroma_4x4_a9:\n\n    @R0     :pointer to src buffer\n    @R1     :pointer to pred buffer\n    @R2     :pointer to dst buffer\n    @R3     :Source stride\n    @STACk  :pred stride\n    @       :scale matirx,\n    @       :threshold matrix\n    @       :qbits\n    @       :round factor\n    @       :nnz\n    @       :pu1_dc_alt_addr\n    push          {r4-r12, lr}          @push all the variables first\n\n    add           r11, sp, #40          @decrement stack pointer,to accomodate two variables\n    ldmfd         r11, {r4-r10}         @load the strides into registers\n\n    @R0     :pointer to src buffer\n    @R1     :pointer to pred buffer\n    @R2     :pointer to dst buffer\n    @R3     :Source stride\n    @R4     :Pred stride\n    @R5     :scale matirx,\n    @R6     :threshold matrix\n    @R7     :qbits\n    @R8     :round factor\n    @R9     :nnz\n    vpush         {d8-d15}\n    mov           r11, #0\n    sub           r7, r11, r7           @Negate the qbit value for usiing LSL\n\n    @------------Fucntion Loading done----------------;\n\n    vld2.u8       {d10, d11}, [r0], r3  @load first 8 pix src row 1\n\n    vld2.u8       {d11, d12}, [r1], r4  @load first 8 pix pred row 1\n\n    vld2.u8       {d28, d29}, [r0], r3  @load first 8 pix src row 2\n\n    vld2.u8       {d29, d30}, [r1], r4  @load first 8 pix pred row 2\n\n    vld2.u8       {d25, d26}, [r0], r3  @load first 8 pix src row 3\n\n    vld2.u8       {d26, d27}, [r1], r4  @load first 8 pix pred row 3\n    vsubl.u8      q0, d10, d11          @find residue row 1\n\n    vld2.u8       {d22, d23}, [r0], r3  @load first 8 pix src row 4\n\n    vld2.u8       {d23, d24}, [r1], r4  @load first 8 pix pred row 4\n    vsubl.u8      q1, d28, d29          @find residue row 2\n\n    vsubl.u8      q2, d25, d26          @find residue row 3\n    vsubl.u8      q3, d22, d23          @find residue row 4\n\n    vtrn.16       d0, d2                @T12\n    vtrn.16       d4, d6                @T23\n    vtrn.32       d0, d4                @T13\n    vtrn.32       d2, d6                @T14\n\n    vadd.s16      d8 , d0, d6           @x0 = x4+x7\n    vadd.s16      d9 , d2, d4           @x1 = x5+x6\n    vsub.s16      d10, d2, d4           @x2 = x5-x6\n    vsub.s16      d11, d0, d6           @x3 = x4-x7\n\n    vshl.s16      d12, d10, #1          @U_SHIFT(x2,1,shft)\n    vshl.s16      d13, d11, #1          @U_SHIFT(x3,1,shft)\n\n    vadd.s16      d14, d8, d9           @x4 = x0 + x1;\n    vsub.s16      d16, d8, d9           @x6 = x0 - x1;\n    vadd.s16      d15, d13, d10         @x5 = U_SHIFT(x3,1,shft) + x2;\n    vsub.s16      d17, d11, d12         @x7 = x3 - U_SHIFT(x2,1,shft);\n\n    @taking transpose again so as to make do vert transform\n    vtrn.16       d14, d15              @T12\n    vtrn.16       d16, d17              @T23\n    vtrn.32       d14, d16              @T13\n    vtrn.32       d15, d17              @T24\n\n    @let us do vertical transform\n    @same code as horiz\n    vadd.s16      d18, d14, d17         @x0 = x4+x7\n    vadd.s16      d19, d15, d16         @x1 = x5+x6\n    vsub.s16      d20, d15, d16         @x2 = x5-x6\n    vsub.s16      d21, d14, d17         @x3 = x4-x7\n\n    vshl.s16      d22, d20, #1          @U_SHIFT(x2,1,shft)\n    vshl.s16      d23, d21, #1          @U_SHIFT(x3,1,shft)\n\n    vdup.s32      q4, r8                @Load rounding value row 1\n\n    vadd.s16      d24, d18, d19         @x5 = x0 + x1;\n    vsub.s16      d26, d18, d19         @x7 = x0 - x1;\n    vadd.s16      d25, d23, d20         @x6 = U_SHIFT(x3,1,shft) + x2;\n    vsub.s16      d27, d21, d22         @x8 = x3 - U_SHIFT(x2,1,shft);\n    vdup.s32      q10, r7               @Load qbit values\n\n    vst1.s16      d24[0], [r10]         @Store Unquantized dc value to dc alte address\n\n@core tranform is done for 4x8 block 1\n    vld1.s16      {q14-q15}, [r5]       @load the scaling values\n\n    vabs.s16      q0, q12               @Abs val of row 1 blk 1\n\n    vabs.s16      q1, q13               @Abs val of row 2 blk 1\n\n    vmov.s32      q5, q4                @copy round fact for row 2\n\n    vmov.s32      q6, q4                @copy round fact for row 2\n    vclt.s16      q2, q12, #0           @Get the sign of row 1 blk 1\n\n    vmov.s32      q7, q4                @copy round fact for row 2\n    vclt.s16      q3, q13, #0           @Get the sign of row 2 blk 1\n\n    vmlal.s16     q4, d0, d28           @Multiply and add row 1\n    vmlal.s16     q5, d1, d29           @Multiply and add row 2\n    vmlal.s16     q6, d2, d30           @Multiply and add row 3\n    vmlal.s16     q7, d3, d31           @Multiply and add row 4\n\n    vshl.s32      q11, q4, q10          @Shift row 1\n    vshl.s32      q12, q5, q10          @Shift row 2\n    vshl.s32      q13, q6, q10          @Shift row 3\n    vshl.s32      q14, q7, q10          @Shift row 4\n\n    vmovn.s32     d30, q11              @Narrow row 1\n    vmovn.s32     d31, q12              @Narrow row 2\n    vmovn.s32     d0 , q13              @Narrow row 3\n    vmovn.s32     d1 , q14              @Narrow row 4\n\n    vneg.s16      q1, q15               @Get negative\n    vneg.s16      q4, q0                @Get negative\n\n    vceq.s16      q5, q15, #0           @I  compare with zero row 1 and 2 blk 1\n    vceq.s16      q6, q0 , #0           @I  compare with zero row 1 and 2 blk 1\n\n    vbsl.s16      q2, q1, q15           @Restore sign of row 1 and 2\n    vbsl.s16      q3, q4, q0            @Restore sign of row 3 and 4\n\n    vmovn.u16     d14, q5               @I  Narrow the comparison for row 1 and 2 blk 1\n    vmovn.u16     d15, q6               @I  Narrow the comparison for row 1 and 2 blk 2\n\n    vshr.u8       q8, q7, #7            @I  Reduce comaparison bit to a signle bit row 1 and 2 blk  1 and 2 [ keep the value for later use ]\n\n    vpadd.u8      d18, d16, d17         @I pair add nnz 1\n    vpadd.u8      d20, d18, d19         @I Pair add nnz 2\n    vpadd.u8      d22, d20, d21         @I Pair add nnz 3\n    vpadd.u8      d24, d22, d23         @I Pair add nnz4\n    vst1.s16      {q2-q3}, [r2]         @Store blk\n\n    vmov.u8       d25, #16              @I Get max nnz\n    vsub.u8       d26, d25, d24         @I invert current nnz\n\n    vst1.u8       d26[0], [r9]          @I  Write nnz\n\n    vpop          {d8-d15}\n    pop           {r4-r12, pc}\n\n\n\n@*****************************************************************************\n@*\n@* Function Name     : ih264_hadamard_quant_4x4_a9\n@* Description       : This function does forward hadamard transform and\n@*                     quantization for luma dc block\n@*\n@* Arguments         :  R0 :pointer to src buffer\n@                       R1 :pointer to dst buffer\n@                       R2 :pu2_scale_matrix\n@                       R2 :pu2_threshold_matrix\n@                       STACk : u4_qbits\n@                               u4_round_factor\n@                               pu1_nnz\n@ Values Returned   : NONE\n@\n@ Register Usage    :\n@ Stack Usage       : 0 bytes\n@ Cycles            : Around\n@ Interruptiaility  : Interruptable\n@\n@ Known Limitations\n@   \\Assumptions    :\n@\n@ Revision History  :\n@         DD MM YYYY    Author(s)   Changes\n@         20 2 2015    100633      First version\n@\n@*****************************************************************************\n@ih264_hadamard_quant_4x4_a9(WORD16 *pi2_src, WORD16 *pi2_dst,\n@                           const UWORD16 *pu2_scale_matrix,\n@                           const UWORD16 *pu2_threshold_matrix, UWORD32 u4_qbits,\n@                           UWORD32 u4_round_factor,UWORD8  *pu1_nnz\n@                           )\n    .global ih264_hadamard_quant_4x4_a9\nih264_hadamard_quant_4x4_a9:\n\n@Registert usage\n@   r0 : src\n@   r1 : dst\n@   r2 : *pu2_scale_matrix\n@   r3 : *pu2_threshold_matrix\n\n    vld4.s16      {d0, d1, d2, d3}, [r0]! @Load 4x4 block\n    vpush         {d8-d15}\n\n    vld1.u16      d30[0], [r2]          @load pu2_scale_matrix[0]\n\n    vaddl.s16     q3, d0, d3            @x0 = x4 + x7;\n    vaddl.s16     q4, d1, d2            @x1 = x5 + x6;\n    vsubl.s16     q5, d1, d2            @x2 = x5 - x6;\n    vsubl.s16     q6, d0, d3            @x3 = x4 - x7;\n\n    vdup.u16      d30, d30[0]           @pu2_scale_matrix[0]\n\n    vadd.s32      q7, q3, q4            @pi2_dst[0] = x0 + x1;\n    vadd.s32      q8, q6, q5            @pi2_dst[1] = x3 + x2;\n    add           r3, sp, #68           @Get address of u4_round_factor\n    vsub.s32      q9, q3, q4            @pi2_dst[2] = x0 - x1;\n    vsub.s32      q10, q6, q5           @pi2_dst[3] = x3 - x2;\n\n    vtrn.s32      q7, q8                @transpose 4x4 block\n    vtrn.s32      q9, q10\n    vld1.s32      d0[0], [r3]           @load   u4_round_factor\n    vswp          d15, d18\n    vswp          d17, d20\n\n    add           r3, sp, #64           @Get address of u4_qbits\n    vadd.s32      q11, q7, q10          @x0 = x4 + x7;\n    vadd.s32      q12, q8, q9           @x1 = x5 + x6;\n    vld1.s32      d31[0], [r3]          @load  u4_qbits\n    vsub.s32      q13, q8, q9           @x2 = x5 - x6;\n    vsub.s32      q14, q7, q10          @x3 = x4 - x7;\n\n    vdup.s32      q7, d0[0]             @u4_round_factor\n\n    vadd.s32      q0, q11, q12          @(x0 + x1)\n    vadd.s32      q1, q14, q13          @(x3 + x2)\n    vsub.s32      q2, q11, q12          @(x0 - x1)\n    vsub.s32      q3, q14, q13          @(x3 - x2)\n\n    vdup.s32      q11, d31[0]           @u4_round_factor\n\n    vshrn.s32     d0, q0, #1            @i4_value = (x0 + x1) >> 1;\n    vshrn.s32     d1, q1, #1            @i4_value = (x3 + x2) >> 1;\n    vshrn.s32     d2, q2, #1            @i4_value = (x0 - x1) >> 1;\n    vshrn.s32     d3, q3, #1            @i4_value = (x3 - x2) >> 1;\n\n    vabs.s16      q5, q0\n    vabs.s16      q6, q1\n\n    vmov.s32      q8, q7                @Get the round fact\n    vmov.s32      q9, q7\n    vmov.s32      q10, q7\n\n    vclt.s16      q3, q0, #0            @get the sign row 1,2\n    vclt.s16      q4, q1, #0\n\n    vneg.s32      q11, q11              @-u4_round_factor\n\n    vmlal.u16     q7, d10, d30\n    vmlal.u16     q8, d11, d30\n    vmlal.u16     q9, d12, d30\n    vmlal.u16     q10, d13, d30\n\n    vshl.u32      q7, q7, q11\n    vshl.u32      q8, q8, q11\n    vshl.u32      q9, q9, q11\n    vshl.u32      q10, q10, q11\n\n    vqmovn.u32    d22, q7\n    vqmovn.u32    d23, q8\n    vqmovn.u32    d24, q9\n    vqmovn.u32    d25, q10\n\n    vneg.s16      q13, q11\n    vneg.s16      q14, q12\n\n    vbsl.s16      q3, q13, q11\n    vbsl.s16      q4, q14, q12\n\n    vceq.s16      q5, q11, #0\n    vceq.s16      q6, q12, #0\n\n    vst1.s16      {q3}, [r1]!\n\n    vshrn.u16     d14, q5, #8\n    vshrn.u16     d15, q6, #8\n\n    ldr           r3, [sp, #72]         @Load *pu1_nnz\n\n    vshr.u8       q7, q7, #7\n\n    vst1.s16      {q4}, [r1]!\n\n    vadd.u8       d16, d14, d15\n    vmov.u8       d20, #16\n    vpadd.u8      d17, d16, d16\n    vpadd.u8      d18, d17, d17\n    vpadd.u8      d19, d18, d18\n    vsub.u8       d20, d20, d19\n    vst1.u8       d20[0], [r3]\n\n    vpop          {d8-d15}\n    bx            lr\n\n\n\n\n@*****************************************************************************\n@*\n@* Function Name     : ih264_hadamard_quant_2x2_uv_a9\n@* Description       : This function does forward hadamard transform and\n@*                     quantization for dc block of chroma for both planes\n@*\n@* Arguments         :  R0 :pointer to src buffer\n@                       R1 :pointer to dst buffer\n@                       R2 :pu2_scale_matrix\n@                       R2 :pu2_threshold_matrix\n@                       STACk : u4_qbits\n@                               u4_round_factor\n@                               pu1_nnz\n@ Values Returned   : NONE\n@\n@ Register Usage    :\n@ Stack Usage       : 0 bytes\n@ Cycles            : Around\n@ Interruptiaility  : Interruptable\n@\n@ Known Limitations\n@   \\Assumptions    :\n@\n@ Revision History  :\n@         DD MM YYYY    Author(s)   Changes\n@         20 2 2015    100633      First version\n@\n@*****************************************************************************\n@ ih264_hadamard_quant_2x2_uv_a9(WORD16 *pi2_src, WORD16 *pi2_dst,\n@                             const UWORD16 *pu2_scale_matrix,\n@                             const UWORD16 *pu2_threshold_matrix, UWORD32 u4_qbits,\n@                             UWORD32 u4_round_factor,UWORD8  *pu1_nnz\n@                             )\n\n    .global ih264_hadamard_quant_2x2_uv_a9\nih264_hadamard_quant_2x2_uv_a9:\n\n    vpush         {d8-d15}\n    vld2.s16      {d0-d1}, [r0]         @load src\n\n    add           r3, sp, #68           @Get address of u4_round_factor\n\n    vaddl.s16     q3, d0, d1            @x0 = x4 + x5;, x2 = x6 + x7;\n    vld1.u16      d30[0], [r2]          @load pu2_scale_matrix[0]\n    vsubl.s16     q4, d0, d1            @x1 = x4 - x5;  x3 = x6 - x7;\n\n    add           r0, sp, #64           @Get affress of u4_qbits\n    vld1.s32      d28[0], [r3]          @load   u4_round_factor\n    vtrn.s32      q3, q4                @q1 -> x0 x1, q2 -> x2 x3\n\n    vadd.s32      q0, q3, q4            @ (x0 + x2) (x1 + x3)  (y0 + y2); (y1 + y3);\n    vld1.s32      d24[0], [r0]          @load  u4_qbits\n    vsub.s32      q1, q3, q4            @ (x0 - x2) (x1 - x3)  (y0 - y2); (y1 - y3);\n\n    vdup.u16      d30, d30[0]           @pu2_scale_matrix\n\n    vabs.s32      q2, q0\n    vabs.s32      q3, q1\n\n    vdup.s32      q14, d28[0]           @u4_round_factor\n\n    vmovl.u16     q15, d30              @pu2_scale_matrix\n\n    vclt.s32      q4, q0, #0            @get the sign row 1,2\n    vdup.s32      q12, d24[0]           @u4_round_factor\n    vclt.s32      q5, q1, #0\n\n    vqmovn.u32    d8, q4\n    vqmovn.s32    d9, q5\n\n    vmov.s32      q13, q14              @Get the round fact\n    vneg.s32      q12, q12              @-u4_round_factor\n\n    vmla.u32      q13, q2, q15\n    vmla.u32      q14, q3, q15\n\n    vshl.u32      q13, q13, q12         @>>qbit\n    vshl.u32      q14, q14, q12         @>>qbit\n\n    vqmovn.u32    d10, q13\n    vqmovn.u32    d11, q14\n\n    vneg.s16      q6, q5\n\n    vbsl.s16      q4, q6, q5            @*sign\n\n    vtrn.s32      d8, d9\n\n    vceq.s16      q7, q4, #0            @Compute nnz\n\n    vshrn.u16     d14, q7, #8           @reduce nnz comparison to 1 bit\n\n    ldr           r3, [sp, #72]         @Load *pu1_nnz\n    vshr.u8       d14, d14, #7          @reduce nnz comparison to 1 bit\n    vmov.u8       d20, #4               @Since we add zeros, we need to subtract from 4 to get nnz\n    vpadd.u8      d17, d14, d14         @Sum up nnz\n\n    vst1.s16      {q4}, [r1]!           @Store the block\n\n    vpadd.u8      d17, d17, d17         @Sum up nnz\n    vsub.u8       d20, d20, d17         @4- numzeros\n    vst1.u16      d20[0], [r3]          @store nnz\n\n    vpop          {d8-d15}\n    bx            lr\n\n\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_weighted_bi_pred_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_weighted_bi_pred_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for weighted biprediction.\n@*\n@* @author\n@*  Kaushik Senthoor R\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_weighted_bi_pred_luma_a9q()\n@*  - ih264_weighted_bi_pred_chroma_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@*******************************************************************************\n@* @function\n@*  ih264_weighted_bi_pred_luma_a9q()\n@*\n@* @brief\n@*  This routine performs the weighted biprediction as described in sec\n@* 8.4.2.3.2 titled \"Weighted sample prediction process\" for luma.\n@*\n@* @par Description:\n@*  This function gets two ht x wd blocks, calculates the weighted samples,\n@* rounds off, adds offset and stores it in the destination block.\n@*\n@* @param[in] pu1_src1\n@*  UWORD8 Pointer to the buffer containing the input block 1.\n@*\n@* @param[in] pu1_src2\n@*  UWORD8 Pointer to the buffer containing the input block 2.\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination where the output block is stored.\n@*\n@* @param[in] src_strd1\n@*  Stride of the input buffer 1\n@*\n@* @param[in] src_strd2\n@*  Stride of the input buffer 2\n@*\n@* @param[in] dst_strd\n@*  Stride of the destination buffer\n@*\n@* @param[in] log_wd\n@*  number of bits to be rounded off\n@*\n@* @param[in] wt1\n@*  weight for the weighted prediction\n@*\n@* @param[in] wt2\n@*  weight for the weighted prediction\n@*\n@* @param[in] ofst1\n@*  offset 1 used after rounding off\n@*\n@* @param[in] ofst2\n@*  offset 2 used after rounding off\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  (ht,wd) can be (4,4), (4,8), (8,4), (8,8), (8,16), (16,8) or (16,16).\n@*\n@*******************************************************************************\n@*\n@void ih264_weighted_bi_pred_luma_a9q(UWORD8 *pu1_src1,\n@                                     UWORD8 *pu1_src2,\n@                                     UWORD8 *pu1_dst,\n@                                     WORD32 src_strd1,\n@                                     WORD32 src_strd2,\n@                                     WORD32 dst_strd,\n@                                     WORD32 log_wd,\n@                                     WORD32 wt1,\n@                                     WORD32 wt2,\n@                                     WORD32 ofst1,\n@                                     WORD32 ofst2,\n@                                     WORD32 ht,\n@                                     WORD32 wd)\n@\n@**************Variables Vs Registers*****************************************\n@   r0      => pu1_src1\n@   r1      => pu1_src2\n@   r2      => pu1_dst\n@   r3      => src_strd1\n@   [sp]    => src_strd2 (r4)\n@   [sp+4]  => dst_strd  (r5)\n@   [sp+8]  => log_wd    (r6)\n@   [sp+12] => wt1       (r7)\n@   [sp+16] => wt2       (r8)\n@   [sp+20] => ofst1     (r9)\n@   [sp+24] => ofst2     (r10)\n@   [sp+28] => ht        (r11)\n@   [sp+32] => wd        (r12)\n@\n.text\n.p2align 2\n\n    .global ih264_weighted_bi_pred_luma_a9q\n\nih264_weighted_bi_pred_luma_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @stack stores the values of the arguments\n    ldr           r6, [sp, #48]         @Load log_wd in r6\n    ldr           r7, [sp, #52]         @Load wt1 in r7\n    ldr           r8, [sp, #56]         @Load wt2 in r8\n    ldr           r9, [sp, #60]         @Load ofst1 in r9\n\n    add           r6, r6, #1            @r6  = log_wd + 1\n    sxtb          r7, r7                @sign-extend 16-bit wt1 to 32-bit\n    ldr           r4, [sp, #40]         @Load src_strd2 in r4\n    ldr           r5, [sp, #44]         @Load dst_strd in r5\n    sxtb          r9, r9                @sign-extend 8-bit ofst1 to 32-bit\n    neg           r10, r6               @r10 = -(log_wd + 1)\n    ldr           r11, [sp, #68]        @Load ht in r11\n    ldr           r12, [sp, #72]        @Load wd in r12\n    vdup.16       q0, r10               @Q0  = -(log_wd + 1) (32-bit)\n    add           r9, r9, #1            @r9 = ofst1 + 1\n\n    ldr           r10, [sp, #64]        @Load ofst2 in r10\n    sxtb          r8, r8                @sign-extend 16-bit wt2 to 32-bit\n    cmp           r12, #16              @check if wd is 16\n    vpush         {d8-d15}\n    sxtb          r10, r10              @sign-extend 8-bit ofst2 to 32-bit\n    add           r9, r9, r10           @r9 = ofst1 + ofst2 + 1\n    vmov          d2, r7, r8            @D2 = {wt1(32-bit), wt2(32-bit)}\n    asr           r9, r9, #1            @r9 = ofst = (ofst1 + ofst2 + 1) >> 1\n    vdup.8        d3, r9                @D3 = ofst (8-bit)\n    beq           loop_16               @branch if wd is 16\n\n    cmp           r12, #8               @check if wd is 8\n    beq           loop_8                @branch if wd is 8\n\nloop_4:                                 @each iteration processes four rows\n\n    vld1.32       d4[0], [r0], r3       @load row 1 in source 1\n    vld1.32       d4[1], [r0], r3       @load row 2 in source 1\n    vld1.32       d6[0], [r1], r4       @load row 1 in source 2\n    vld1.32       d6[1], [r1], r4       @load row 2 in source 2\n\n    vmovl.u8      q2, d4                @converting rows 1,2 in source 1 to 16-bit\n    vld1.32       d8[0], [r0], r3       @load row 3 in source 1\n    vld1.32       d8[1], [r0], r3       @load row 4 in source 1\n    vmovl.u8      q3, d6                @converting rows 1,2 in source 2 to 16-bit\n    vld1.32       d10[0], [r1], r4      @load row 3 in source 2\n    vld1.32       d10[1], [r1], r4      @load row 4 in source 2\n\n    vmovl.u8      q4, d8                @converting rows 3,4 in source 1 to 16-bit\n    vmovl.u8      q5, d10               @converting rows 3,4 in source 2 to 16-bit\n\n    vmul.s16      q2, q2, d2[0]         @weight 1 mult. for rows 1,2\n    vmla.s16      q2, q3, d2[2]         @weight 2 mult. for rows 1,2\n    vmul.s16      q4, q4, d2[0]         @weight 1 mult. for rows 3,4\n    vmla.s16      q4, q5, d2[2]         @weight 2 mult. for rows 3,4\n\n    subs          r11, r11, #4          @decrement ht by 4\n    vrshl.s16     q2, q2, q0            @rounds off the weighted samples from rows 1,2\n    vrshl.s16     q4, q4, q0            @rounds off the weighted samples from rows 3,4\n\n    vaddw.s8      q2, q2, d3            @adding offset for rows 1,2\n    vaddw.s8      q4, q4, d3            @adding offset for rows 3,4\n\n    vqmovun.s16   d4, q2                @saturating rows 1,2 to unsigned 8-bit\n    vqmovun.s16   d8, q4                @saturating rows 3,4 to unsigned 8-bit\n\n    vst1.32       d4[0], [r2], r5       @store row 1 in destination\n    vst1.32       d4[1], [r2], r5       @store row 2 in destination\n    vst1.32       d8[0], [r2], r5       @store row 3 in destination\n    vst1.32       d8[1], [r2], r5       @store row 4 in destination\n\n    bgt           loop_4                @if greater than 0 repeat the loop again\n\n    b             end_loops\n\nloop_8:                                 @each iteration processes four rows\n\n    vld1.8        d4, [r0], r3          @load row 1 in source 1\n    vld1.8        d6, [r1], r4          @load row 1 in source 2\n    vld1.8        d8, [r0], r3          @load row 2 in source 1\n    vld1.8        d10, [r1], r4         @load row 2 in source 2\n    vmovl.u8      q2, d4                @converting row 1 in source 1 to 16-bit\n    vld1.8        d12, [r0], r3         @load row 3 in source 1\n    vld1.8        d14, [r1], r4         @load row 3 in source 2\n    vmovl.u8      q3, d6                @converting row 1 in source 2 to 16-bit\n    vld1.8        d16, [r0], r3         @load row 4 in source 1\n    vld1.8        d18, [r1], r4         @load row 4 in source 2\n\n    vmovl.u8      q4, d8                @converting row 2 in source 1 to 16-bit\n    vmovl.u8      q5, d10               @converting row 2 in source 2 to 16-bit\n\n    vmul.s16      q2, q2, d2[0]         @weight 1 mult. for row 1\n    vmla.s16      q2, q3, d2[2]         @weight 2 mult. for row 1\n    vmovl.u8      q6, d12               @converting row 3 in source 1 to 16-bit\n    vmovl.u8      q7, d14               @converting row 3 in source 2 to 16-bit\n    vmul.s16      q4, q4, d2[0]         @weight 1 mult. for row 2\n    vmla.s16      q4, q5, d2[2]         @weight 2 mult. for row 2\n    vmovl.u8      q8, d16               @converting row 4 in source 1 to 16-bit\n    vmovl.u8      q9, d18               @converting row 4 in source 2 to 16-bit\n\n    vmul.s16      q6, q6, d2[0]         @weight 1 mult. for row 3\n    vmla.s16      q6, q7, d2[2]         @weight 2 mult. for row 3\n    vmul.s16      q8, q8, d2[0]         @weight 1 mult. for row 4\n    vmla.s16      q8, q9, d2[2]         @weight 2 mult. for row 4\n\n    vrshl.s16     q2, q2, q0            @rounds off the weighted samples from row 1\n    vrshl.s16     q4, q4, q0            @rounds off the weighted samples from row 2\n    vrshl.s16     q6, q6, q0            @rounds off the weighted samples from row 3\n    vaddw.s8      q2, q2, d3            @adding offset for row 1\n    vrshl.s16     q8, q8, q0            @rounds off the weighted samples from row 4\n    vaddw.s8      q4, q4, d3            @adding offset for row 2\n\n    vaddw.s8      q6, q6, d3            @adding offset for row 3\n    vqmovun.s16   d4, q2                @saturating row 1 to unsigned 8-bit\n    vaddw.s8      q8, q8, d3            @adding offset for row 4\n    vqmovun.s16   d8, q4                @saturating row 2 to unsigned 8-bit\n\n    vqmovun.s16   d12, q6               @saturating row 3 to unsigned 8-bit\n    vqmovun.s16   d16, q8               @saturating row 4 to unsigned 8-bit\n\n    vst1.8        d4, [r2], r5          @store row 1 in destination\n    vst1.8        d8, [r2], r5          @store row 2 in destination\n    subs          r11, r11, #4          @decrement ht by 4\n    vst1.8        d12, [r2], r5         @store row 3 in destination\n    vst1.8        d16, [r2], r5         @store row 4 in destination\n\n    bgt           loop_8                @if greater than 0 repeat the loop again\n\n    b             end_loops\n\nloop_16:                                @each iteration processes two rows\n\n    vld1.8        {q2}, [r0], r3        @load row 1 in source 1\n    vld1.8        {q3}, [r1], r4        @load row 1 in source 2\n    vld1.8        {q4}, [r0], r3        @load row 2 in source 1\n    vld1.8        {q5}, [r1], r4        @load row 2 in source 2\n    vmovl.u8      q10, d4               @converting row 1L in source 1 to 16-bit\n    vld1.8        {q6}, [r0], r3        @load row 3 in source 1\n    vld1.8        {q7}, [r1], r4        @load row 3 in source 2\n    vmovl.u8      q11, d6               @converting row 1L in source 2 to 16-bit\n    vld1.8        {q8}, [r0], r3        @load row 4 in source 1\n    vld1.8        {q9}, [r1], r4        @load row 4 in source 2\n\n    vmovl.u8      q2, d5                @converting row 1H in source 1 to 16-bit\n    vmovl.u8      q3, d7                @converting row 1H in source 2 to 16-bit\n\n    vmul.s16      q10, q10, d2[0]       @weight 1 mult. for row 1L\n    vmla.s16      q10, q11, d2[2]       @weight 2 mult. for row 1L\n    vmovl.u8      q12, d8               @converting row 2L in source 1 to 16-bit\n    vmovl.u8      q13, d10              @converting row 2L in source 2 to 16-bit\n\n    vmul.s16      q2, q2, d2[0]         @weight 1 mult. for row 1H\n    vmla.s16      q2, q3, d2[2]         @weight 2 mult. for row 1H\n    vmovl.u8      q4, d9                @converting row 2H in source 1 to 16-bit\n    vmovl.u8      q5, d11               @converting row 2H in source 2 to 16-bit\n\n    vmul.s16      q12, q12, d2[0]       @weight 1 mult. for row 2L\n    vmla.s16      q12, q13, d2[2]       @weight 2 mult. for row 2L\n    vmovl.u8      q14, d12              @converting row 3L in source 1 to 16-bit\n    vmovl.u8      q15, d14              @converting row 3L in source 2 to 16-bit\n\n    vmul.s16      q4, q4, d2[0]         @weight 1 mult. for row 2H\n    vmla.s16      q4, q5, d2[2]         @weight 2 mult. for row 2H\n    vmovl.u8      q6, d13               @converting row 3H in source 1 to 16-bit\n    vmovl.u8      q7, d15               @converting row 3H in source 2 to 16-bit\n\n    vmul.s16      q14, q14, d2[0]       @weight 1 mult. for row 3L\n    vmla.s16      q14, q15, d2[2]       @weight 2 mult. for row 3L\n    vmovl.u8      q11, d16              @converting row 4L in source 1 to 16-bit\n    vmovl.u8      q3, d18               @converting row 4L in source 2 to 16-bit\n\n    vmul.s16      q6, q6, d2[0]         @weight 1 mult. for row 3H\n    vmla.s16      q6, q7, d2[2]         @weight 2 mult. for row 3H\n    vmovl.u8      q8, d17               @converting row 4H in source 1 to 16-bit\n    vmovl.u8      q9, d19               @converting row 4H in source 2 to 16-bit\n\n    vmul.s16      q11, q11, d2[0]       @weight 1 mult. for row 4L\n    vmla.s16      q11, q3, d2[2]        @weight 2 mult. for row 4L\n    vrshl.s16     q10, q10, q0          @rounds off the weighted samples from row 1L\n\n    vmul.s16      q8, q8, d2[0]         @weight 1 mult. for row 4H\n    vmla.s16      q8, q9, d2[2]         @weight 2 mult. for row 4H\n    vrshl.s16     q2, q2, q0            @rounds off the weighted samples from row 1H\n\n    vrshl.s16     q12, q12, q0          @rounds off the weighted samples from row 2L\n    vaddw.s8      q10, q10, d3          @adding offset for row 1L\n    vrshl.s16     q4, q4, q0            @rounds off the weighted samples from row 2H\n    vaddw.s8      q2, q2, d3            @adding offset for row 1H\n    vrshl.s16     q14, q14, q0          @rounds off the weighted samples from row 3L\n    vaddw.s8      q12, q12, d3          @adding offset for row 2L\n    vrshl.s16     q6, q6, q0            @rounds off the weighted samples from row 3H\n    vaddw.s8      q4, q4, d3            @adding offset for row 2H\n    vrshl.s16     q11, q11, q0          @rounds off the weighted samples from row 4L\n    vaddw.s8      q14, q14, d3          @adding offset for row 3L\n    vrshl.s16     q8, q8, q0            @rounds off the weighted samples from row 4H\n    vaddw.s8      q6, q6, d3            @adding offset for row 3H\n\n    vqmovun.s16   d26, q10              @saturating row 1L to unsigned 8-bit\n    vaddw.s8      q11, q11, d3          @adding offset for row 4L\n    vqmovun.s16   d27, q2               @saturating row 1H to unsigned 8-bit\n    vaddw.s8      q8, q8, d3            @adding offset for row 4H\n\n    vqmovun.s16   d10, q12              @saturating row 2L to unsigned 8-bit\n    vqmovun.s16   d11, q4               @saturating row 2H to unsigned 8-bit\n    vqmovun.s16   d30, q14              @saturating row 3L to unsigned 8-bit\n    vqmovun.s16   d31, q6               @saturating row 3H to unsigned 8-bit\n    vst1.8        {q13}, [r2], r5       @store row 1 in destination\n    vqmovun.s16   d14, q11              @saturating row 4L to unsigned 8-bit\n    vqmovun.s16   d15, q8               @saturating row 4H to unsigned 8-bit\n\n    vst1.8        {q5}, [r2], r5        @store row 2 in destination\n    subs          r11, r11, #4          @decrement ht by 4\n    vst1.8        {q15}, [r2], r5       @store row 3 in destination\n    vst1.8        {q7}, [r2], r5        @store row 4 in destination\n\n    bgt           loop_16               @if greater than 0 repeat the loop again\n\nend_loops:\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r12, r15}    @Reload the registers from sp\n\n\n@*******************************************************************************\n@* @function\n@*  ih264_weighted_bi_pred_chroma_a9q()\n@*\n@* @brief\n@*  This routine performs the default weighted prediction as described in sec\n@* 8.4.2.3.2 titled \"Weighted sample prediction process\" for chroma.\n@*\n@* @par Description:\n@*  This function gets two ht x wd blocks, calculates the weighted samples,\n@* rounds off, adds offset and stores it in the destination block for U and V.\n@*\n@* @param[in] pu1_src1\n@*  UWORD8 Pointer to the buffer containing the input block 1.\n@*\n@* @param[in] pu1_src2\n@*  UWORD8 Pointer to the buffer containing the input block 2.\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination where the output block is stored.\n@*\n@* @param[in] src_strd1\n@*  Stride of the input buffer 1\n@*\n@* @param[in] src_strd2\n@*  Stride of the input buffer 2\n@*\n@* @param[in] dst_strd\n@*  Stride of the destination buffer\n@*\n@* @param[in] log_wd\n@*  number of bits to be rounded off\n@*\n@* @param[in] wt1\n@*  weights for the weighted prediction in U and V\n@*\n@* @param[in] wt2\n@*  weights for the weighted prediction in U and V\n@*\n@* @param[in] ofst1\n@*  offset 1 used after rounding off for U an dV\n@*\n@* @param[in] ofst2\n@*  offset 2 used after rounding off for U and V\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  (ht,wd) can be (2,2), (2,4), (4,2), (4,4), (4,8), (8,4) or (8,8).\n@*\n@*******************************************************************************\n@*\n@void ih264_weighted_bi_pred_chroma_a9q(UWORD8 *pu1_src1,\n@                                       UWORD8 *pu1_src2,\n@                                       UWORD8 *pu1_dst,\n@                                       WORD32 src_strd1,\n@                                       WORD32 src_strd2,\n@                                       WORD32 dst_strd,\n@                                       WORD32 log_wd,\n@                                       WORD32 wt1,\n@                                       WORD32 wt2,\n@                                       WORD32 ofst1,\n@                                       WORD32 ofst2,\n@                                       WORD32 ht,\n@                                       WORD32 wd)\n@\n@**************Variables Vs Registers*****************************************\n@   r0      => pu1_src1\n@   r1      => pu1_src2\n@   r2      => pu1_dst\n@   r3      => src_strd1\n@   [sp]    => src_strd2 (r4)\n@   [sp+4]  => dst_strd  (r5)\n@   [sp+8]  => log_wd    (r6)\n@   [sp+12] => wt1       (r7)\n@   [sp+16] => wt2       (r8)\n@   [sp+20] => ofst1     (r9)\n@   [sp+24] => ofst2     (r10)\n@   [sp+28] => ht        (r11)\n@   [sp+32] => wd        (r12)\n@\n\n\n    .global ih264_weighted_bi_pred_chroma_a9q\n\nih264_weighted_bi_pred_chroma_a9q:\n\n    stmfd         sp!, {r4-r12, r14}    @stack stores the values of the arguments\n\n    ldr           r6, [sp, #48]         @Load log_wd in r6\n    ldr           r7, [sp, #52]         @Load wt1 in r7\n    ldr           r8, [sp, #56]         @Load wt2 in r8\n    add           r6, r6, #1            @r6  = log_wd + 1\n    ldr           r9, [sp, #60]         @Load ofst1 in r9\n    ldr           r10, [sp, #64]        @Load ofst2 in r10\n\n    neg           r12, r6               @r12 = -(log_wd + 1)\n    ldr           r4, [sp, #40]         @Load src_strd2 in r4\n    ldr           r5, [sp, #44]         @Load dst_strd in r5\n    vdup.16       q0, r12               @Q0  = -(log_wd + 1) (16-bit)\n\n    ldr           r11, [sp, #68]        @Load ht in r11\n    vdup.32       q1, r7                @Q1 = (wt1_u, wt1_v) (32-bit)\n    ldr           r12, [sp, #72]        @Load wd in r12\n    vdup.32       q2, r8                @Q2 = (wt2_u, wt2_v) (32-bit)\n    asr           r7, r9, #8            @r7 = ofst1_v\n    asr           r8, r10, #8           @r8 = ofst2_v\n    vpush         {d8-d15}\n    sxtb          r9, r9                @sign-extend 8-bit ofst1_u to 32-bit\n    sxtb          r10, r10              @sign-extend 8-bit ofst2_u to 32-bit\n    sxtb          r7, r7                @sign-extend 8-bit ofst1_v to 32-bit\n    sxtb          r8, r8                @sign-extend 8-bit ofst2_v to 32-bit\n\n    add           r9, r9, #1            @r9 = ofst1_u + 1\n    add           r7, r7, #1            @r7 = ofst1_v + 1\n    add           r9, r9, r10           @r9 = ofst1_u + ofst2_u + 1\n    add           r7, r7, r8            @r7 = ofst1_v + ofst2_v + 1\n    asr           r9, r9, #1            @r9 = ofst_u = (ofst1_u + ofst2_u + 1) >> 1\n    asr           r7, r7, #1            @r7 = ofst_v = (ofst1_v + ofst2_v + 1) >> 1\n    cmp           r12, #8               @check if wd is 8\n    pkhbt         r9, r9, r7, lsl #16   @r9 = {ofst_u(16-bit), ofst_v(16-bit)}\n    vdup.32       q3, r9                @Q3 = {ofst_u(16-bit), ofst_v(16-bit)}\n    beq           loop_8_uv             @branch if wd is 8\n\n    cmp           r12, #4               @check if wd is 4\n    beq           loop_4_uv             @branch if wd is 4\n\nloop_2_uv:                              @each iteration processes two rows\n\n    vld1.32       d8[0], [r0], r3       @load row 1 in source 1\n    vld1.32       d8[1], [r0], r3       @load row 2 in source 1\n    vld1.32       d10[0], [r1], r4      @load row 1 in source 2\n    vld1.32       d10[1], [r1], r4      @load row 2 in source 2\n\n    vmovl.u8      q4, d8                @converting rows 1,2 in source 1 to 16-bit\n    vmovl.u8      q5, d10               @converting rows 1,2 in source 2 to 16-bit\n\n    vmul.s16      q4, q4, q1            @weight 1 mult. for rows 1,2\n    vmla.s16      q4, q5, q2            @weight 2 mult. for rows 1,2\n\n    vrshl.s16     q4, q4, q0            @rounds off the weighted samples from rows 1,2\n\n    vadd.s16      q4, q4, q3            @adding offset for rows 1,2\n\n    vqmovun.s16   d8, q4                @saturating rows 1,2 to unsigned 8-bit\n\n    vst1.32       d8[0], [r2], r5       @store row 1 in destination\n    vst1.32       d8[1], [r2], r5       @store row 2 in destination\n\n    subs          r11, r11, #2          @decrement ht by 2\n    bgt           loop_2_uv             @if greater than 0 repeat the loop again\n\n    b             end_loops_uv\n\nloop_4_uv:                              @each iteration processes two rows\n\n    vld1.8        d8, [r0], r3          @load row 1 in source 1\n    vld1.8        d10, [r1], r4         @load row 1 in source 2\n    vmovl.u8      q4, d8                @converting row 1 in source 1 to 16-bit\n    vld1.8        d12, [r0], r3         @load row 2 in source 1\n    vmovl.u8      q5, d10               @converting row 1 in source 2 to 16-bit\n    vld1.8        d14, [r1], r4         @load row 2 in source 2\n\n    vmovl.u8      q6, d12               @converting row 2 in source 1 to 16-bit\n    vmul.s16      q4, q4, q1            @weight 1 mult. for row 1\n    vmla.s16      q4, q5, q2            @weight 2 mult. for row 1\n    vmovl.u8      q7, d14               @converting row 2 in source 2 to 16-bit\n\n    vmul.s16      q6, q6, q1            @weight 1 mult. for row 2\n    vmla.s16      q6, q7, q2            @weight 2 mult. for row 2\n\n    subs          r11, r11, #2          @decrement ht by 2\n    vrshl.s16     q4, q4, q0            @rounds off the weighted samples from row 1\n    vrshl.s16     q6, q6, q0            @rounds off the weighted samples from row 2\n    vadd.s16      q4, q4, q3            @adding offset for row 1\n    vadd.s16      q6, q6, q3            @adding offset for row 2\n\n    vqmovun.s16   d8, q4                @saturating row 1 to unsigned 8-bit\n    vqmovun.s16   d12, q6               @saturating row 2 to unsigned 8-bit\n\n    vst1.8        d8, [r2], r5          @store row 1 in destination\n    vst1.8        d12, [r2], r5         @store row 2 in destination\n\n    bgt           loop_4_uv             @if greater than 0 repeat the loop again\n\n    b             end_loops_uv\n\nloop_8_uv:                              @each iteration processes two rows\n\n    vld1.8        {q4}, [r0], r3        @load row 1 in source 1\n    vld1.8        {q5}, [r1], r4        @load row 1 in source 2\n    vld1.8        {q6}, [r0], r3        @load row 2 in source 1\n    vld1.8        {q7}, [r1], r4        @load row 2 in source 2\n    vmovl.u8      q12, d8               @converting row 1L in source 1 to 16-bit\n    vld1.8        {q8}, [r0], r3        @load row 3 in source 1\n    vld1.8        {q9}, [r1], r4        @load row 3 in source 2\n    vmovl.u8      q13, d10              @converting row 1L in source 2 to 16-bit\n    vld1.8        {q10}, [r0], r3       @load row 4 in source 1\n    vld1.8        {q11}, [r1], r4       @load row 4 in source 2\n\n    vmovl.u8      q4, d9                @converting row 1H in source 1 to 16-bit\n    vmovl.u8      q5, d11               @converting row 1H in source 2 to 16-bit\n\n    vmul.s16      q12, q12, q1          @weight 1 mult. for row 1L\n    vmla.s16      q12, q13, q2          @weight 2 mult. for row 1L\n    vmovl.u8      q14, d12              @converting row 2L in source 1 to 16-bit\n    vmovl.u8      q15, d14              @converting row 2L in source 2 to 16-bit\n\n    vmul.s16      q4, q4, q1            @weight 1 mult. for row 1H\n    vmla.s16      q4, q5, q2            @weight 2 mult. for row 1H\n    vmovl.u8      q6, d13               @converting row 2H in source 1 to 16-bit\n    vmovl.u8      q7, d15               @converting row 2H in source 2 to 16-bit\n\n    vmul.s16      q14, q14, q1          @weight 1 mult. for row 2L\n    vmla.s16      q14, q15, q2          @weight 2 mult. for row 2L\n    vmovl.u8      q13, d16              @converting row 3L in source 1 to 16-bit\n    vmovl.u8      q5, d18               @converting row 3L in source 2 to 16-bit\n\n    vmul.s16      q6, q6, q1            @weight 1 mult. for row 2H\n    vmla.s16      q6, q7, q2            @weight 2 mult. for row 2H\n    vmovl.u8      q8, d17               @converting row 3H in source 1 to 16-bit\n    vmovl.u8      q9, d19               @converting row 3H in source 2 to 16-bit\n\n    vmul.s16      q13, q13, q1          @weight 1 mult. for row 3L\n    vmla.s16      q13, q5, q2           @weight 2 mult. for row 3L\n    vmovl.u8      q15, d20              @converting row 4L in source 1 to 16-bit\n    vmovl.u8      q7, d22               @converting row 4L in source 2 to 16-bit\n\n    vmul.s16      q8, q8, q1            @weight 1 mult. for row 3H\n    vmla.s16      q8, q9, q2            @weight 2 mult. for row 3H\n    vmovl.u8      q10, d21              @converting row 4H in source 1 to 16-bit\n    vmovl.u8      q11, d23              @converting row 4H in source 2 to 16-bit\n\n    vmul.s16      q15, q15, q1          @weight 1 mult. for row 4L\n    vmla.s16      q15, q7, q2           @weight 2 mult. for row 4L\n    vrshl.s16     q12, q12, q0          @rounds off the weighted samples from row 1L\n\n    vmul.s16      q10, q10, q1          @weight 1 mult. for row 4H\n    vmla.s16      q10, q11, q2          @weight 2 mult. for row 4H\n    vrshl.s16     q4, q4, q0            @rounds off the weighted samples from row 1H\n\n    vrshl.s16     q14, q14, q0          @rounds off the weighted samples from row 2L\n    vadd.s16      q12, q12, q3          @adding offset for row 1L\n    vrshl.s16     q6, q6, q0            @rounds off the weighted samples from row 2H\n    vadd.s16      q4, q4, q3            @adding offset for row 1H\n    vrshl.s16     q13, q13, q0          @rounds off the weighted samples from row 3L\n    vadd.s16      q14, q14, q3          @adding offset for row 2L\n    vrshl.s16     q8, q8, q0            @rounds off the weighted samples from row 3H\n    vadd.s16      q6, q6, q3            @adding offset for row 2H\n    vrshl.s16     q15, q15, q0          @rounds off the weighted samples from row 4L\n    vadd.s16      q13, q13, q3          @adding offset for row 3L\n    vrshl.s16     q10, q10, q0          @rounds off the weighted samples from row 4H\n    vadd.s16      q8, q8, q3            @adding offset for row 3H\n\n    vqmovun.s16   d10, q12              @saturating row 1L to unsigned 8-bit\n    vadd.s16      q15, q15, q3          @adding offset for row 4L\n    vqmovun.s16   d11, q4               @saturating row 1H to unsigned 8-bit\n    vadd.s16      q10, q10, q3          @adding offset for row 4H\n\n    vqmovun.s16   d18, q14              @saturating row 2L to unsigned 8-bit\n    vqmovun.s16   d19, q6               @saturating row 2H to unsigned 8-bit\n    vqmovun.s16   d14, q13              @saturating row 3L to unsigned 8-bit\n    vqmovun.s16   d15, q8               @saturating row 3H to unsigned 8-bit\n    vst1.8        {q5}, [r2], r5        @store row 1 in destination\n    vqmovun.s16   d22, q15              @saturating row 4L to unsigned 8-bit\n    vqmovun.s16   d23, q10              @saturating row 4H to unsigned 8-bit\n\n    vst1.8        {q9}, [r2], r5        @store row 2 in destination\n    subs          r11, r11, #4          @decrement ht by 4\n    vst1.8        {q7}, [r2], r5        @store row 3 in destination\n    vst1.8        {q11}, [r2], r5       @store row 4 in destination\n\n    bgt           loop_8_uv             @if greater than 0 repeat the loop again\n\nend_loops_uv:\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r12, r15}    @Reload the registers from sp\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/arm/ih264_weighted_pred_a9q.s",
    "content": "@/******************************************************************************\n@ *\n@ * Copyright (C) 2015 The Android Open Source Project\n@ *\n@ * Licensed under the Apache License, Version 2.0 (the \"License\");\n@ * you may not use this file except in compliance with the License.\n@ * You may obtain a copy of the License at:\n@ *\n@ * http://www.apache.org/licenses/LICENSE-2.0\n@ *\n@ * Unless required by applicable law or agreed to in writing, software\n@ * distributed under the License is distributed on an \"AS IS\" BASIS,\n@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@ * See the License for the specific language governing permissions and\n@ * limitations under the License.\n@ *\n@ *****************************************************************************\n@ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n@*/\n@**\n@******************************************************************************\n@* @file\n@*  ih264_weighted_pred_a9q.s\n@*\n@* @brief\n@*  Contains function definitions for weighted prediction.\n@*\n@* @author\n@*  Kaushik Senthoor R\n@*\n@* @par List of Functions:\n@*\n@*  - ih264_weighted_pred_luma_a9q()\n@*  - ih264_weighted_pred_chroma_a9q()\n@*\n@* @remarks\n@*  None\n@*\n@*******************************************************************************\n@*\n@*******************************************************************************\n@* @function\n@*  ih264_weighted_pred_luma_a9q()\n@*\n@* @brief\n@*  This routine performs the default weighted prediction as described in sec\n@* 8.4.2.3.2 titled \"Weighted sample prediction process\" for luma.\n@*\n@* @par Description:\n@*  This function gets a ht x wd block, calculates the weighted sample, rounds\n@* off, adds offset and stores it in the destination block.\n@*\n@* @param[in] pu1_src:\n@*  UWORD8 Pointer to the buffer containing the input block.\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination where the output block is stored.\n@*\n@* @param[in] src_strd\n@*  Stride of the input buffer\n@*\n@* @param[in] dst_strd\n@*  Stride of the destination buffer\n@*\n@* @param[in] log_wd\n@*  number of bits to be rounded off\n@*\n@* @param[in] wt\n@*  weight for the weighted prediction\n@*\n@* @param[in] ofst\n@*  offset used after rounding off\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  (ht,wd) can be (4,4), (4,8), (8,4), (8,8), (8,16), (16,8) or (16,16).\n@*\n@*******************************************************************************\n@*\n@void ih264_weighted_pred_luma_a9q(UWORD8 *pu1_src,\n@                                  UWORD8 *pu1_dst,\n@                                  WORD32 src_strd,\n@                                  WORD32 dst_strd,\n@                                  WORD32 log_wd,\n@                                  WORD32 wt,\n@                                  WORD32 ofst,\n@                                  WORD32 ht,\n@                                  WORD32 wd)\n@\n@**************Variables Vs Registers*****************************************\n@   r0      => pu1_src\n@   r1      => pu1_dst\n@   r2      => src_strd\n@   r3      => dst_strd\n@   [sp]    => log_wd (r4)\n@   [sp+4]  => wt     (r5)\n@   [sp+8]  => ofst   (r6)\n@   [sp+12] => ht     (r7)\n@   [sp+16] => wd     (r8)\n@\n.text\n.p2align 2\n\n    .global ih264_weighted_pred_luma_a9q\n\nih264_weighted_pred_luma_a9q:\n\n    stmfd         sp!, {r4-r9, r14}     @stack stores the values of the arguments\n    ldr           r5, [sp, #32]         @Load wt\n    ldr           r4, [sp, #28]         @Load log_wd in r4\n    ldr           r6, [sp, #36]         @Load ofst\n    ldr           r7, [sp, #40]         @Load ht\n    ldr           r8, [sp, #44]         @Load wd\n    vpush         {d8-d15}\n\n    vdup.16       d2, r5                @D2 = wt (16-bit)\n    neg           r9, r4                @r9 = -log_wd\n    vdup.8        d3, r6                @D3 = ofst (8-bit)\n    cmp           r8, #16               @check if wd is 16\n    vdup.16       q0, r9                @Q0 = -log_wd (16-bit)\n    beq           loop_16               @branch if wd is 16\n\n    cmp           r8, #8                @check if wd is 8\n    beq           loop_8                @branch if wd is 8\n\nloop_4:                                 @each iteration processes four rows\n\n    vld1.32       d4[0], [r0], r2       @load row 1 in source\n    vld1.32       d4[1], [r0], r2       @load row 2 in source\n    vld1.32       d6[0], [r0], r2       @load row 3 in source\n    vld1.32       d6[1], [r0], r2       @load row 4 in source\n\n    vmovl.u8      q2, d4                @converting rows 1,2 to 16-bit\n    vmovl.u8      q3, d6                @converting rows 3,4 to 16-bit\n\n    vmul.s16      q2, q2, d2[0]         @weight mult. for rows 1,2\n    vmul.s16      q3, q3, d2[0]         @weight mult. for rows 3,4\n\n    subs          r7, r7, #4            @decrement ht by 4\n    vrshl.s16     q2, q2, q0            @rounds off the weighted samples from rows 1,2\n    vrshl.s16     q3, q3, q0            @rounds off the weighted samples from rows 3,4\n\n    vaddw.s8      q2, q2, d3            @adding offset for rows 1,2\n    vaddw.s8      q3, q3, d3            @adding offset for rows 3,4\n\n    vqmovun.s16   d4, q2                @saturating rows 1,2 to unsigned 8-bit\n    vqmovun.s16   d6, q3                @saturating rows 3,4 to unsigned 8-bit\n\n    vst1.32       d4[0], [r1], r3       @store row 1 in destination\n    vst1.32       d4[1], [r1], r3       @store row 2 in destination\n    vst1.32       d6[0], [r1], r3       @store row 3 in destination\n    vst1.32       d6[1], [r1], r3       @store row 4 in destination\n\n    bgt           loop_4                @if greater than 0 repeat the loop again\n\n    b             end_loops\n\nloop_8:                                 @each iteration processes four rows\n\n    vld1.8        d4, [r0], r2          @load row 1 in source\n    vld1.8        d6, [r0], r2          @load row 2 in source\n    vld1.8        d8, [r0], r2          @load row 3 in source\n    vmovl.u8      q2, d4                @converting row 1 to 16-bit\n    vld1.8        d10, [r0], r2         @load row 4 in source\n    vmovl.u8      q3, d6                @converting row 2 to 16-bit\n\n    vmovl.u8      q4, d8                @converting row 3 to 16-bit\n    vmul.s16      q2, q2, d2[0]         @weight mult. for row 1\n    vmovl.u8      q5, d10               @converting row 4 to 16-bit\n    vmul.s16      q3, q3, d2[0]         @weight mult. for row 2\n    vmul.s16      q4, q4, d2[0]         @weight mult. for row 3\n    vmul.s16      q5, q5, d2[0]         @weight mult. for row 4\n\n    vrshl.s16     q2, q2, q0            @rounds off the weighted samples from row 1\n    vrshl.s16     q3, q3, q0            @rounds off the weighted samples from row 2\n    vrshl.s16     q4, q4, q0            @rounds off the weighted samples from row 3\n    vaddw.s8      q2, q2, d3            @adding offset for row 1\n    vrshl.s16     q5, q5, q0            @rounds off the weighted samples from row 4\n    vaddw.s8      q3, q3, d3            @adding offset for row 2\n\n    vaddw.s8      q4, q4, d3            @adding offset for row 3\n    vqmovun.s16   d4, q2                @saturating row 1 to unsigned 8-bit\n    vaddw.s8      q5, q5, d3            @adding offset for row 4\n    vqmovun.s16   d6, q3                @saturating row 2 to unsigned 8-bit\n    vqmovun.s16   d8, q4                @saturating row 3 to unsigned 8-bit\n    vqmovun.s16   d10, q5               @saturating row 4 to unsigned 8-bit\n\n    vst1.8        d4, [r1], r3          @store row 1 in destination\n    vst1.8        d6, [r1], r3          @store row 2 in destination\n    subs          r7, r7, #4            @decrement ht by 4\n    vst1.8        d8, [r1], r3          @store row 3 in destination\n    vst1.8        d10, [r1], r3         @store row 4 in destination\n\n    bgt           loop_8                @if greater than 0 repeat the loop again\n\n    b             end_loops\n\nloop_16:                                @each iteration processes two rows\n\n    vld1.8        {q2}, [r0], r2        @load row 1 in source\n    vld1.8        {q3}, [r0], r2        @load row 2 in source\n    vmovl.u8      q6, d4                @converting row 1L to 16-bit\n    vld1.8        {q4}, [r0], r2        @load row 3 in source\n    vmovl.u8      q7, d5                @converting row 1H to 16-bit\n    vld1.8        {q5}, [r0], r2        @load row 4 in source\n\n    vmovl.u8      q8, d6                @converting row 2L to 16-bit\n    vmul.s16      q6, q6, d2[0]         @weight mult. for row 1L\n    vmovl.u8      q9, d7                @converting row 2H to 16-bit\n    vmul.s16      q7, q7, d2[0]         @weight mult. for row 1H\n    vmovl.u8      q10, d8               @converting row 3L to 16-bit\n    vmul.s16      q8, q8, d2[0]         @weight mult. for row 2L\n    vmovl.u8      q11, d9               @converting row 3H to 16-bit\n    vmul.s16      q9, q9, d2[0]         @weight mult. for row 2H\n    vmovl.u8      q12, d10              @converting row 4L to 16-bit\n    vmul.s16      q10, q10, d2[0]       @weight mult. for row 3L\n    vmovl.u8      q13, d11              @converting row 4H to 16-bit\n    vmul.s16      q11, q11, d2[0]       @weight mult. for row 3H\n\n    vmul.s16      q12, q12, d2[0]       @weight mult. for row 4L\n    vrshl.s16     q6, q6, q0            @rounds off the weighted samples from row 1L\n    vmul.s16      q13, q13, d2[0]       @weight mult. for row 4H\n\n    vrshl.s16     q7, q7, q0            @rounds off the weighted samples from row 1H\n    vrshl.s16     q8, q8, q0            @rounds off the weighted samples from row 2L\n    vaddw.s8      q6, q6, d3            @adding offset for row 1L\n    vrshl.s16     q9, q9, q0            @rounds off the weighted samples from row 2H\n    vaddw.s8      q7, q7, d3            @adding offset for row 1H\n    vqmovun.s16   d4, q6                @saturating row 1L to unsigned 8-bit\n    vrshl.s16     q10, q10, q0          @rounds off the weighted samples from row 3L\n    vaddw.s8      q8, q8, d3            @adding offset for row 2L\n    vqmovun.s16   d5, q7                @saturating row 1H to unsigned 8-bit\n    vrshl.s16     q11, q11, q0          @rounds off the weighted samples from row 3H\n    vaddw.s8      q9, q9, d3            @adding offset for row 2H\n    vqmovun.s16   d6, q8                @saturating row 2L to unsigned 8-bit\n    vrshl.s16     q12, q12, q0          @rounds off the weighted samples from row 4L\n    vaddw.s8      q10, q10, d3          @adding offset for row 3L\n    vqmovun.s16   d7, q9                @saturating row 2H to unsigned 8-bit\n    vrshl.s16     q13, q13, q0          @rounds off the weighted samples from row 4H\n    vaddw.s8      q11, q11, d3          @adding offset for row 3H\n\n    vqmovun.s16   d8, q10               @saturating row 3L to unsigned 8-bit\n    vaddw.s8      q12, q12, d3          @adding offset for row 4L\n    vqmovun.s16   d9, q11               @saturating row 3H to unsigned 8-bit\n    vaddw.s8      q13, q13, d3          @adding offset for row 4H\n\n    vqmovun.s16   d10, q12              @saturating row 4L to unsigned 8-bit\n    vst1.8        {q2}, [r1], r3        @store row 1 in destination\n    vqmovun.s16   d11, q13              @saturating row 4H to unsigned 8-bit\n    vst1.8        {q3}, [r1], r3        @store row 2 in destination\n    subs          r7, r7, #4            @decrement ht by 4\n    vst1.8        {q4}, [r1], r3        @store row 3 in destination\n    vst1.8        {q5}, [r1], r3        @store row 4 in destination\n\n    bgt           loop_16               @if greater than 0 repeat the loop again\n\nend_loops:\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r9, r15}     @Reload the registers from sp\n\n\n@*******************************************************************************\n@* @function\n@*  ih264_weighted_pred_chroma_a9q()\n@*\n@* @brief\n@*  This routine performs the default weighted prediction as described in sec\n@* 8.4.2.3.2 titled \"Weighted sample prediction process\" for chroma.\n@*\n@* @par Description:\n@*  This function gets a ht x wd block, calculates the weighted sample, rounds\n@* off, adds offset and stores it in the destination block for U and V.\n@*\n@* @param[in] pu1_src:\n@*  UWORD8 Pointer to the buffer containing the input block.\n@*\n@* @param[out] pu1_dst\n@*  UWORD8 pointer to the destination where the output block is stored.\n@*\n@* @param[in] src_strd\n@*  Stride of the input buffer\n@*\n@* @param[in] dst_strd\n@*  Stride of the destination buffer\n@*\n@* @param[in] log_wd\n@*  number of bits to be rounded off\n@*\n@* @param[in] wt\n@*  weights for the weighted prediction for U and V\n@*\n@* @param[in] ofst\n@*  offsets used after rounding off for U and V\n@*\n@* @param[in] ht\n@*  integer height of the array\n@*\n@* @param[in] wd\n@*  integer width of the array\n@*\n@* @returns\n@*  None\n@*\n@* @remarks\n@*  (ht,wd) can be (2,2), (2,4), (4,2), (4,4), (4,8), (8,4) or (8,8).\n@*\n@*******************************************************************************\n@*\n@void ih264_weighted_pred_chroma_a9q(UWORD8 *pu1_src,\n@                                    UWORD8 *pu1_dst,\n@                                    WORD32 src_strd,\n@                                    WORD32 dst_strd,\n@                                    WORD32 log_wd,\n@                                    WORD32 wt,\n@                                    WORD32 ofst,\n@                                    WORD32 ht,\n@                                    WORD32 wd)\n@\n@**************Variables Vs Registers*****************************************\n@   r0      => pu1_src\n@   r1      => pu1_dst\n@   r2      => src_strd\n@   r3      => dst_strd\n@   [sp]    => log_wd (r4)\n@   [sp+4]  => wt     (r5)\n@   [sp+8]  => ofst   (r6)\n@   [sp+12] => ht     (r7)\n@   [sp+16] => wd     (r8)\n@\n\n\n    .global ih264_weighted_pred_chroma_a9q\n\nih264_weighted_pred_chroma_a9q:\n\n    stmfd         sp!, {r4-r9, r14}     @stack stores the values of the arguments\n\n    ldr           r4, [sp, #28]         @Load log_wd in r4\n    ldr           r5, [sp, #32]         @Load wt = {wt_u (16-bit), wt_v (16-bit)}\n    ldr           r6, [sp, #36]         @Load ofst = {ofst_u (8-bit), ofst_v (8-bit)}\n    ldr           r8, [sp, #44]         @Load wd\n\n    neg           r9, r4                @r9 = -log_wd\n    vdup.32       q1, r5                @Q1 = {wt_u (16-bit), wt_v (16-bit)}\n    ldr           r7, [sp, #40]         @Load ht\n    vpush         {d8-d15}\n    vdup.16       d4, r6                @D4 = {ofst_u (8-bit), ofst_v (8-bit)}\n    cmp           r8, #8                @check if wd is 8\n    vdup.16       q0, r9                @Q0 = -log_wd (16-bit)\n    beq           loop_8_uv             @branch if wd is 8\n\n    cmp           r8, #4                @check if ws is 4\n    beq           loop_4_uv             @branch if wd is 4\n\nloop_2_uv:                              @each iteration processes two rows\n\n    vld1.32       d6[0], [r0], r2       @load row 1 in source\n    vld1.32       d6[1], [r0], r2       @load row 2 in source\n\n    vmovl.u8      q3, d6                @converting rows 1,2 to 16-bit\n\n    vmul.s16      q3, q3, q1            @weight mult. for rows 1,2\n\n    vrshl.s16     q3, q3, q0            @rounds off the weighted samples from rows 1,2\n\n    vaddw.s8      q3, q3, d4            @adding offset for rows 1,2\n\n    vqmovun.s16   d6, q3                @saturating rows 1,2 to unsigned 8-bit\n\n    subs          r7, r7, #2            @decrement ht by 2\n    vst1.32       d6[0], [r1], r3       @store row 1 in destination\n    vst1.32       d6[1], [r1], r3       @store row 2 in destination\n\n    bgt           loop_2_uv             @if greater than 0 repeat the loop again\n\n    b             end_loops_uv\n\nloop_4_uv:                              @each iteration processes two rows\n\n    vld1.8        d6, [r0], r2          @load row 1 in source\n    vld1.8        d8, [r0], r2          @load row 2 in source\n\n    vmovl.u8      q3, d6                @converting row 1 to 16-bit\n    vmovl.u8      q4, d8                @converting row 2 to 16-bit\n\n    vmul.s16      q3, q3, q1            @weight mult. for row 1\n    vmul.s16      q4, q4, q1            @weight mult. for row 2\n\n    subs          r7, r7, #2            @decrement ht by 2\n    vrshl.s16     q3, q3, q0            @rounds off the weighted samples from row 1\n    vrshl.s16     q4, q4, q0            @rounds off the weighted samples from row 2\n\n    vaddw.s8      q3, q3, d4            @adding offset for row 1\n    vaddw.s8      q4, q4, d4            @adding offset for row 2\n\n    vqmovun.s16   d6, q3                @saturating row 1 to unsigned 8-bit\n    vqmovun.s16   d8, q4                @saturating row 2 to unsigned 8-bit\n\n    vst1.8        d6, [r1], r3          @store row 1 in destination\n    vst1.8        d8, [r1], r3          @store row 2 in destination\n\n    bgt           loop_4_uv             @if greater than 0 repeat the loop again\n\n    b             end_loops_uv\n\nloop_8_uv:                              @each iteration processes two rows\n\n    vld1.8        {q3}, [r0], r2        @load row 1 in source\n    vld1.8        {q4}, [r0], r2        @load row 2 in source\n    vmovl.u8      q7, d6                @converting row 1L to 16-bit\n    vld1.8        {q5}, [r0], r2        @load row 3 in source\n    vmovl.u8      q8, d7                @converting row 1H to 16-bit\n    vld1.8        {q6}, [r0], r2        @load row 4 in source\n\n    vmul.s16      q7, q7, q1            @weight mult. for row 1L\n    vmovl.u8      q9, d8                @converting row 2L to 16-bit\n    vmul.s16      q8, q8, q1            @weight mult. for row 1H\n    vmovl.u8      q10, d9               @converting row 2H to 16-bit\n    vmul.s16      q9, q9, q1            @weight mult. for row 2L\n    vmovl.u8      q11, d10              @converting row 3L to 16-bit\n    vmul.s16      q10, q10, q1          @weight mult. for row 2H\n    vmovl.u8      q12, d11              @converting row 3H to 16-bit\n    vmul.s16      q11, q11, q1          @weight mult. for row 3L\n    vmovl.u8      q13, d12              @converting row 4L to 16-bit\n    vmul.s16      q12, q12, q1          @weight mult. for row 3H\n    vmovl.u8      q14, d13              @converting row 4H to 16-bit\n\n    vmul.s16      q13, q13, q1          @weight mult. for row 4L\n    vrshl.s16     q7, q7, q0            @rounds off the weighted samples from row 1L\n    vmul.s16      q14, q14, q1          @weight mult. for row 4H\n\n    vrshl.s16     q8, q8, q0            @rounds off the weighted samples from row 1H\n    vrshl.s16     q9, q9, q0            @rounds off the weighted samples from row 2L\n    vaddw.s8      q7, q7, d4            @adding offset for row 1L\n    vrshl.s16     q10, q10, q0          @rounds off the weighted samples from row 2H\n    vaddw.s8      q8, q8, d4            @adding offset for row 1H\n    vqmovun.s16   d6, q7                @saturating row 1L to unsigned 8-bit\n    vrshl.s16     q11, q11, q0          @rounds off the weighted samples from row 3L\n    vaddw.s8      q9, q9, d4            @adding offset for row 2L\n    vqmovun.s16   d7, q8                @saturating row 1H to unsigned 8-bit\n    vrshl.s16     q12, q12, q0          @rounds off the weighted samples from row 3H\n    vaddw.s8      q10, q10, d4          @adding offset for row 2H\n    vqmovun.s16   d8, q9                @saturating row 2L to unsigned 8-bit\n    vrshl.s16     q13, q13, q0          @rounds off the weighted samples from row 4L\n    vaddw.s8      q11, q11, d4          @adding offset for row 3L\n    vqmovun.s16   d9, q10               @saturating row 2H to unsigned 8-bit\n    vrshl.s16     q14, q14, q0          @rounds off the weighted samples from row 4H\n    vaddw.s8      q12, q12, d4          @adding offset for row 3H\n\n    vqmovun.s16   d10, q11              @saturating row 3L to unsigned 8-bit\n    vaddw.s8      q13, q13, d4          @adding offset for row 4L\n    vqmovun.s16   d11, q12              @saturating row 3H to unsigned 8-bit\n    vaddw.s8      q14, q14, d4          @adding offset for row 4H\n\n    vqmovun.s16   d12, q13              @saturating row 4L to unsigned 8-bit\n    vst1.8        {q3}, [r1], r3        @store row 1 in destination\n    vqmovun.s16   d13, q14              @saturating row 4H to unsigned 8-bit\n    vst1.8        {q4}, [r1], r3        @store row 2 in destination\n    subs          r7, r7, #4            @decrement ht by 4\n    vst1.8        {q5}, [r1], r3        @store row 3 in destination\n    vst1.8        {q6}, [r1], r3        @store row 4 in destination\n\n    bgt           loop_8_uv             @if greater than 0 repeat the loop again\n\nend_loops_uv:\n\n    vpop          {d8-d15}\n    ldmfd         sp!, {r4-r9, r15}     @Reload the registers from sp\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_deblk_chroma_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///*****************************************************************************/\n///*                                                                           */\n///*  File Name         : ih264_deblk_chroma_av8.s                              */\n///*                                                                           */\n///*  Description       : Contains function definitions for deblocking luma    */\n///*                      edge. Functions are coded in NEON assembly and can   */\n///*                      be compiled using ARM RVDS.                          */\n///*                                                                           */\n///*  List of Functions : ih264_deblk_chroma_vert_bs4_av8()              */\n///*                      ih264_deblk_chroma_vert_bslt4_av8()            */\n///*                      ih264_deblk_chroma_horz_bs4_av8()              */\n///*                      ih264_deblk_chroma_horz_bslt4_av8()            */\n///*  Issues / Problems : None                                                 */\n///*                                                                           */\n///*  Revision History  :                                                      */\n///*                                                                           */\n///*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n///*         28 11 2013   Ittiam          Draft                                */\n///*****************************************************************************/\n\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Performs filtering of a chroma block horizontal edge when the\n//*     boundary strength is set to 4 in high profile\n//*\n//* @par Description:\n//*       This operation is described in  Sec. 8.7.2.4 under the title\n//*       \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n//*\n//* @param[in] x0 - pu1_src\n//*  Pointer to the src sample q0\n//*\n//* @param[in] w1 - src_strd\n//*  Source stride\n//*\n//* @param[in] w2 - alpha_cb\n//*  Alpha Value for the boundary in U\n//*\n//* @param[in] w3 - beta_cb\n//*  Beta Value for the boundary in U\n//*\n//* @param[in] w4 - alpha_cr\n//*    Alpha Value for the boundary in V\n//*\n//* @param[in] w5 - beta_cr\n//*    Beta Value for the boundary in V\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n    .global ih264_deblk_chroma_horz_bs4_av8\n\nih264_deblk_chroma_horz_bs4_av8:\n\n    // STMFD sp!,{x4-x6,x14}            //\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x1, w1\n    mov       x6, x5\n    mov       x5, x4\n    sub       x0, x0, x1, lsl #1        //x0 = uc_edgePixel pointing to p1 of chroma\n    ld2       {v6.8b, v7.8b}, [x0], x1  //D6 = p1u , D7 = p1v\n    mov       x4, x0                    //Keeping a backup of the pointer p0 of chroma\n    ld2       {v4.8b, v5.8b}, [x0], x1  //D4 = p0u , D5 = p0v\n    dup       v20.8b, w2                //D20 contains alpha_cb\n    dup       v21.8b, w5                //D21 contains alpha_cr\n    mov       v20.d[1], v21.d[0]\n    ld2       {v0.8b, v1.8b}, [x0], x1  //D0 = q0u , D1 = q0v\n    uaddl     v8.8h, v6.8b, v0.8b       //\n    uaddl     v10.8h, v7.8b, v1.8b      //Q4,Q5 = q0 + p1\n    movi      v31.8b, #2                //\n    ld2       {v2.8b, v3.8b}, [x0]      //D2 = q1u , D3 = q1v\n    mov       v0.d[1], v1.d[0]\n    mov       v2.d[1], v3.d[0]\n    mov       v4.d[1], v5.d[0]\n    mov       v6.d[1], v7.d[0]\n    uabd      v26.16b, v6.16b , v4.16b  //Q13 = ABS(p1 - p0)\n    umlal     v8.8h, v2.8b, v31.8b      //\n    umlal     v10.8h, v3.8b, v31.8b     //Q5,Q4 = (X2(q1U) + q0U + p1U)\n    uabd      v22.16b, v4.16b , v0.16b  //Q11 = ABS(p0 - q0)\n    uabd      v24.16b, v2.16b , v0.16b  //Q12 = ABS(q1 - q0)\n    uaddl     v14.8h, v4.8b, v2.8b      //\n    uaddl     v28.8h, v5.8b, v3.8b      //Q14,Q7 = P0 + Q1\n    dup       v16.8b, w3                //D16 contains beta_cb\n    dup       v17.8b, w6                //D17 contains beta_cr\n    mov       v16.d[1], v17.d[0]\n    umlal     v14.8h, v6.8b, v31.8b     //\n    umlal     v28.8h, v7.8b, v31.8b     //Q14,Q7 = (X2(p1U) + p0U + q1U)\n    cmhs      v18.16b, v22.16b, v20.16b\n    cmhs      v24.16b, v24.16b, v16.16b\n    cmhs      v26.16b, v26.16b, v16.16b\n    rshrn     v8.8b, v8.8h, #2          //\n    rshrn     v9.8b, v10.8h, #2         //Q4 = (X2(q1U) + q0U + p1U + 2) >> 2\n    mov       v8.d[1], v9.d[0]\n    orr       v18.16b, v18.16b , v24.16b //Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta )\n    rshrn     v10.8b, v14.8h, #2        //\n    rshrn     v11.8b, v28.8h, #2        //Q5 = (X2(p1U) + p0U + q1U + 2) >> 2\n    mov       v10.d[1], v11.d[0]\n    orr       v18.16b, v18.16b , v26.16b //Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta ) | ( ABS(p1 - p0) >= Beta )\n    bit       v10.16b, v4.16b , v18.16b //\n    bit       v8.16b, v0.16b , v18.16b  //\n    mov       v11.d[0], v10.d[1]\n    mov       v9.d[0], v8.d[1]\n    st2       {v10.8b, v11.8b}, [x4], x1 //\n    st2       {v8.8b, v9.8b}, [x4]      //\n    // LDMFD sp!,{x4-x6,pc}                //\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Performs filtering of a chroma block vertical edge when the\n//*     boundary strength is set to 4 in high profile\n//*\n//* @par Description:\n//*       This operation is described in  Sec. 8.7.2.4 under the title\n//*       \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n//*\n//* @param[in] x0 - pu1_src\n//*  Pointer to the src sample q0\n//*\n//* @param[in] w1 - src_strd\n//*  Source stride\n//*\n//* @param[in] w2 - alpha_cb\n//*  Alpha Value for the boundary in U\n//*\n//* @param[in] w3 - beta_cb\n//*  Beta Value for the boundary in U\n//*\n//* @param[in] w4 - alpha_cr\n//*    Alpha Value for the boundary in V\n//*\n//* @param[in] w5 - beta_cr\n//*    Beta Value for the boundary in V\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n    .global ih264_deblk_chroma_vert_bs4_av8\n\nih264_deblk_chroma_vert_bs4_av8:\n\n    // STMFD sp!,{x4,x5,x12,x14}\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x1, w1\n\n    sub       x0, x0, #4                //point x0 to p1u of row0.\n    mov       x12, x0                   //keep a back up of x0 for buffer write\n\n    add       w2, w2, w4, lsl #8        //w2 = (alpha_cr,alpha_cb)\n    add       w3, w3, w5, lsl #8        //w3 = (beta_cr,beta_cb)\n\n    ld4       {v0.h, v1.h, v2.h, v3.h}[0], [x0], x1\n    ld4       {v0.h, v1.h, v2.h, v3.h}[1], [x0], x1\n    ld4       {v0.h, v1.h, v2.h, v3.h}[2], [x0], x1\n    ld4       {v0.h, v1.h, v2.h, v3.h}[3], [x0], x1\n\n    ld4       {v4.h, v5.h, v6.h, v7.h}[0], [x0], x1\n    ld4       {v4.h, v5.h, v6.h, v7.h}[1], [x0], x1\n    ld4       {v4.h, v5.h, v6.h, v7.h}[2], [x0], x1\n    ld4       {v4.h, v5.h, v6.h, v7.h}[3], [x0], x1\n\n    mov       v10.16b, v2.16b\n    mov       v2.16b, v1.16b\n    mov       v1.16b, v4.16b\n    mov       v4.16b, v10.16b\n    mov       v10.16b, v6.16b\n    mov       v6.16b, v3.16b\n    mov       v3.16b, v5.16b\n    mov       v5.16b, v10.16b\n\n    dup       v22.8h, w2                //Q11 = alpha\n    dup       v24.8h, w3                //Q12 = beta\n    movi      v31.8b, #2\n\n    mov       v0.d[1], v1.d[0]\n    mov       v2.d[1], v3.d[0]\n    mov       v4.d[1], v5.d[0]\n    mov       v6.d[1], v7.d[0]\n\n    uabd      v8.16b, v2.16b , v4.16b   //|p0-q0|\n    uabd      v10.16b, v6.16b , v4.16b  //|q1-q0|\n    uabd      v12.16b, v0.16b , v2.16b  //|p1-p0|\n    uaddl     v14.8h, v2.8b, v6.8b\n    uaddl     v16.8h, v3.8b, v7.8b      //(p0 + q1)\n    cmhi      v8.16b, v22.16b , v8.16b  //|p0-q0| < alpha ?\n    cmhi      v10.16b, v24.16b , v10.16b //|q1-q0| < beta ?\n    cmhi      v12.16b, v24.16b , v12.16b //|p1-p0| < beta ?\n    umlal     v14.8h, v0.8b, v31.8b\n    umlal     v16.8h, v1.8b, v31.8b     //2*p1 + (p0 + q1)\n    uaddl     v18.8h, v0.8b, v4.8b\n    uaddl     v20.8h, v1.8b, v5.8b      //(p1 + q0)\n    and       v8.16b, v8.16b , v10.16b  //|p0-q0| < alpha && |q1-q0| < beta\n    umlal     v18.8h, v6.8b, v31.8b\n    umlal     v20.8h, v7.8b, v31.8b     //2*q1 + (p1 + q0)\n\n    rshrn     v14.8b, v14.8h, #2\n    rshrn     v15.8b, v16.8h, #2        //(2*p1 + (p0 + q1) + 2) >> 2\n    mov       v14.d[1], v15.d[0]\n    and       v8.16b, v8.16b , v12.16b  //|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta\n    rshrn     v18.8b, v18.8h, #2\n    rshrn     v19.8b, v20.8h, #2        //(2*q1 + (p1 + q0) + 2) >> 2\n    mov       v18.d[1], v19.d[0]\n    bit       v2.16b, v14.16b , v8.16b\n    bit       v4.16b, v18.16b , v8.16b\n\n    mov       v1.d[0], v0.d[1]\n    mov       v3.d[0], v2.d[1]\n    mov       v5.d[0], v4.d[1]\n    mov       v7.d[0], v6.d[1]\n\n    mov       v10.16b, v1.16b\n    mov       v1.16b, v2.16b\n    mov       v2.16b, v4.16b\n    mov       v4.16b, v10.16b\n    mov       v10.16b, v3.16b\n    mov       v3.16b, v6.16b\n    mov       v6.16b, v5.16b\n    mov       v5.16b, v10.16b\n\n    st4       {v0.h, v1.h, v2.h, v3.h}[0], [x12], x1\n    st4       {v0.h, v1.h, v2.h, v3.h}[1], [x12], x1\n    st4       {v0.h, v1.h, v2.h, v3.h}[2], [x12], x1\n    st4       {v0.h, v1.h, v2.h, v3.h}[3], [x12], x1\n\n    st4       {v4.h, v5.h, v6.h, v7.h}[0], [x12], x1\n    st4       {v4.h, v5.h, v6.h, v7.h}[1], [x12], x1\n    st4       {v4.h, v5.h, v6.h, v7.h}[2], [x12], x1\n    st4       {v4.h, v5.h, v6.h, v7.h}[3], [x12], x1\n\n    // LDMFD sp!,{x4,x5,x12,pc}\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Performs filtering of a chroma block horizontal edge for cases where the\n//*     boundary strength is less than 4 in high profile\n//*\n//* @par Description:\n//*       This operation is described in  Sec. 8.7.2.4 under the title\n//*       \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n//*\n//* @param[in] x0 - pu1_src\n//*  Pointer to the src sample q0\n//*\n//* @param[in] w1 - src_strd\n//*  Source stride\n//*\n//* @param[in] w2 - alpha_cb\n//*  Alpha Value for the boundary in U\n//*\n//* @param[in] w3 - beta_cb\n//*  Beta Value for the boundary in U\n//*\n//* @param[in] w4 - alpha_cr\n//*    Alpha Value for the boundary in V\n//*\n//* @param[in] w5 - beta_cr\n//*    Beta Value for the boundary in V\n//*\n//* @param[in] w6 - u4_bs\n//*    Packed Boundary strength array\n//*\n//* @param[in] x7 - pu1_cliptab_cb\n//*    tc0_table for U\n//*\n//* @param[in] sp(0) - pu1_cliptab_cr\n//*    tc0_table for V\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n    .global ih264_deblk_chroma_horz_bslt4_av8\n\nih264_deblk_chroma_horz_bslt4_av8:\n\n    // STMFD sp!,{x4-x9,x14}        //\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x1, w1\n    ldr       x8, [sp, #80]\n    sub       x0, x0, x1, lsl #1        //x0 = uc_edgePixelU pointing to p1 of chroma U\n    rev       w6, w6                    //\n    mov       v12.s[0], w6              //D12[0] = ui_Bs\n    ld1       {v16.s}[0], [x7]          //D16[0] contains cliptab_cb\n    ld1       {v17.s}[0], [x8]          //D17[0] contains cliptab_cr\n    ld2       {v6.8b, v7.8b}, [x0], x1  //Q3=p1\n    tbl       v14.8b, {v16.16b}, v12.8b //Retreiving cliptab values for U\n    tbl       v28.8b, {v17.16b}, v12.8b //Retrieving cliptab values for V\n    uxtl      v12.8h, v12.8b            //Q6 = uc_Bs in each 16 bit scalar\n    mov       x6, x0                    //Keeping a backup of the pointer to chroma U P0\n    ld2       {v4.8b, v5.8b}, [x0], x1  //Q2=p0\n    movi      v30.8b, #1                //\n    dup       v20.8b, w2                //D20 contains alpha_cb\n    dup       v21.8b, w4                //D21 contains alpha_cr\n    mov       v20.d[1], v21.d[0]\n    ld2       {v0.8b, v1.8b}, [x0], x1  //Q0=q0\n    uxtl      v14.8h, v14.8b            //\n    uxtl      v28.8h, v28.8b            //\n    mov       v15.d[0], v28.d[0]        //D14 has cliptab values for U, D15 for V\n    mov       v14.d[1], v28.d[0]\n    ld2       {v2.8b, v3.8b}, [x0]      //Q1=q1\n    usubl     v10.8h, v1.8b, v5.8b      //\n    usubl     v8.8h, v0.8b, v4.8b       //Q5,Q4 = (q0 - p0)\n    mov       v6.d[1], v7.d[0]\n    mov       v4.d[1], v5.d[0]\n    uabd      v26.16b, v6.16b , v4.16b  //Q13 = ABS(p1 - p0)\n    shl       v10.8h, v10.8h, #2        //Q5 = (q0 - p0)<<2\n    mov       v0.d[1], v1.d[0]\n    uabd      v22.16b, v4.16b , v0.16b  //Q11 = ABS(p0 - q0)\n    shl       v8.8h, v8.8h, #2          //Q4 = (q0 - p0)<<2\n    mov       v14.d[1], v15.d[0]\n    sli       v14.8h, v14.8h, #8\n    mov       v15.d[0], v14.d[1]\n    mov       v2.d[1], v3.d[0]\n    uabd      v24.16b, v2.16b , v0.16b  //Q12 = ABS(q1 - q0)\n    cmhs      v18.16b, v22.16b, v20.16b\n    usubl     v20.8h, v6.8b, v2.8b      //Q10 = (p1 - q1)L\n    usubl     v6.8h, v7.8b, v3.8b       //Q3 = (p1 - q1)H\n    dup       v16.8b, w3                //Q8 contains beta_cb\n    dup       v17.8b, w5                //Q8 contains beta_cr\n    mov       v16.d[1], v17.d[0]\n    add       v8.8h, v8.8h , v20.8h     //\n    add       v10.8h, v10.8h , v6.8h    //Q5,Q4 = [ (q0 - p0)<<2 ] + (p1 - q1)\n    cmhs      v24.16b, v24.16b, v16.16b\n    cmgt      v12.4h, v12.4h, #0\n    sqrshrn   v8.8b, v8.8h, #3          //\n    sqrshrn   v9.8b, v10.8h, #3         //Q4 = i_macro = (((q0 - p0)<<2) + (p1 - q1) + 4)>>3\n    mov       v8.d[1], v9.d[0]\n    add       v14.8b, v14.8b , v30.8b   //D14 = C = C0+1 for U\n    cmhs      v26.16b, v26.16b, v16.16b\n    orr       v18.16b, v18.16b , v24.16b //Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta )\n    abs       v6.16b, v8.16b            //Q4 = ABS (i_macro)\n    add       v15.8b, v15.8b , v30.8b   //D15 = C = C0+1 for V\n    mov       v14.d[1], v15.d[0]\n    mov       v13.8b, v12.8b\n    mov       v12.d[1], v13.d[0]        //\n    orr       v18.16b, v18.16b , v26.16b //Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta ) | ( ABS(p1 - p0) >= Beta )\n    umin      v14.16b, v6.16b , v14.16b //Q7 = delta = (ABS(i_macro) > C) ? C : ABS(i_macro)\n    bic       v12.16b, v12.16b , v18.16b //final condition\n    cmge      v8.16b, v8.16b, #0\n    and       v14.16b, v14.16b , v12.16b //Making delta zero in places where values shouldn be filterd\n    uqadd     v16.16b, v4.16b , v14.16b //Q8 = p0 + delta\n    uqsub     v4.16b, v4.16b , v14.16b  //Q2 = p0 - delta\n    uqadd     v18.16b, v0.16b , v14.16b //Q9 = q0 + delta\n    uqsub     v0.16b, v0.16b , v14.16b  //Q0 = q0 - delta\n    bif       v16.16b, v4.16b , v8.16b  //Q8 = (i_macro >= 0 ) ? (p0+delta) : (p0-delta)\n    bif       v0.16b, v18.16b , v8.16b  //Q0 = (i_macro >= 0 ) ? (q0-delta) : (q0+delta)\n    mov       v17.d[0], v16.d[1]\n    mov       v1.d[0], v0.d[1]\n    st2       {v16.8b, v17.8b}, [x6], x1 //\n    st2       {v0.8b, v1.8b}, [x6]      //\n\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Performs filtering of a chroma block vertical edge for cases where the\n//*     boundary strength is less than 4 in high profile\n//*\n//* @par Description:\n//*       This operation is described in  Sec. 8.7.2.4 under the title\n//*       \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n//*\n//* @param[in] x0 - pu1_src\n//*  Pointer to the src sample q0\n//*\n//* @param[in] w1 - src_strd\n//*  Source stride\n//*\n//* @param[in] w2 - alpha_cb\n//*  Alpha Value for the boundary in U\n//*\n//* @param[in] w3 - beta_cb\n//*  Beta Value for the boundary in U\n//*\n//* @param[in] w4 - alpha_cr\n//*    Alpha Value for the boundary in V\n//*\n//* @param[in] w5 - beta_cr\n//*    Beta Value for the boundary in V\n//*\n//* @param[in] w6 - u4_bs\n//*    Packed Boundary strength array\n//*\n//* @param[in] x7 - pu1_cliptab_cb\n//*    tc0_table for U\n//*\n//* @param[in] sp(0) - pu1_cliptab_cr\n//*    tc0_table for V\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n    .global ih264_deblk_chroma_vert_bslt4_av8\n\nih264_deblk_chroma_vert_bslt4_av8:\n\n    // STMFD sp!,{x4-x7,x10-x12,x14}\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x1, w1\n    mov       x10, x7\n    ldr       x11, [sp, #80]            //x11 = u4_bs\n    sub       x0, x0, #4                //point x0 to p1u of row0.\n    add       w2, w2, w4, lsl #8\n    add       w3, w3, w5, lsl #8\n    mov       x12, x0                   //keep a back up of x0 for buffer write\n    ld4       {v0.h, v1.h, v2.h, v3.h}[0], [x0], x1\n    ld4       {v0.h, v1.h, v2.h, v3.h}[1], [x0], x1\n    ld4       {v0.h, v1.h, v2.h, v3.h}[2], [x0], x1\n    ld4       {v0.h, v1.h, v2.h, v3.h}[3], [x0], x1\n\n    ld4       {v4.h, v5.h, v6.h, v7.h}[0], [x0], x1\n    ld4       {v4.h, v5.h, v6.h, v7.h}[1], [x0], x1\n    ld4       {v4.h, v5.h, v6.h, v7.h}[2], [x0], x1\n    ld4       {v4.h, v5.h, v6.h, v7.h}[3], [x0], x1\n\n    mov       v10.16b, v2.16b\n    mov       v2.16b, v1.16b\n    mov       v1.16b, v4.16b\n    mov       v4.16b, v10.16b\n    mov       v10.16b, v6.16b\n    mov       v6.16b, v3.16b\n    mov       v3.16b, v5.16b\n    mov       v5.16b, v10.16b\n    dup       v22.8h, w2                //Q11 = alpha\n    mov       v2.d[1], v3.d[0]\n    mov       v4.d[1], v5.d[0]\n    uabd      v8.16b, v2.16b , v4.16b   //|p0-q0|\n    dup       v24.8h, w3                //Q12 = beta\n    mov       v25.d[0], v24.d[1]\n    mov       v6.d[1], v7.d[0]\n    mov       v0.d[1], v1.d[0]\n    uabd      v10.16b, v6.16b , v4.16b  //|q1-q0|\n    uabd      v12.16b, v0.16b , v2.16b  //|p1-p0|\n    cmhi      v8.16b, v22.16b , v8.16b  //|p0-q0| < alpha ?\n    usubl     v14.8h, v0.8b, v6.8b\n    cmhi      v10.16b, v24.16b , v10.16b //|q1-q0| < beta ?\n    usubl     v16.8h, v1.8b, v7.8b      //(p1 - q1)\n    cmhi      v12.16b, v24.16b , v12.16b //|p1-p0| < beta ?\n    usubl     v18.8h, v4.8b, v2.8b\n    and       v8.16b, v8.16b , v10.16b  //|p0-q0| < alpha && |q1-q0| < beta\n    usubl     v20.8h, v5.8b, v3.8b      //(q0 - p0)\n    movi      v28.8h, #4\n    ld1       {v24.s}[0], [x10]         //Load ClipTable for U\n    ld1       {v25.s}[0], [x11]         //Load ClipTable for V\n    rev       w6, w6                    //Blocking strengths\n    and       v8.16b, v8.16b , v12.16b  //|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta\n    mov       v10.s[0], w6\n    mla       v14.8h, v18.8h , v28.8h\n    mla       v16.8h, v20.8h , v28.8h   //4*(q0 - p0) + (p1 - q1)\n    uxtl      v10.8h, v10.8b\n    sli       v10.4h, v10.4h, #8\n    tbl       v12.8b, {v24.16b}, v10.8b //tC0 for U\n    tbl       v13.8b, {v25.16b}, v10.8b //tC0 for V\n    zip1      v31.8b, v12.8b, v13.8b\n    zip2      v13.8b, v12.8b, v13.8b\n    mov       v12.8b, v31.8b\n    mov       v12.d[1], v13.d[0]\n    uxtl      v10.4s, v10.4h\n    sli       v10.4s, v10.4s, #16\n    movi      v24.16b, #1\n    add       v12.16b, v12.16b , v24.16b //tC0 + 1\n    cmhs      v10.16b, v10.16b , v24.16b\n    and       v8.16b, v8.16b , v10.16b  //|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta && u4_bs != 0\n    // Q0 - Q3(inputs),\n    // Q4 (|p0-q0| < alpha && |q1-q0| < beta && |p1-p0| < beta && u4_bs != 0),\n    // Q6 (tC)\n    srshr     v14.8h, v14.8h, #3\n    srshr     v16.8h, v16.8h, #3        //(((q0 - p0) << 2) + (p1 - q1) + 4) >> 3)\n    cmgt      v18.8h, v14.8h , #0\n    cmgt      v20.8h, v16.8h , #0\n    xtn       v18.8b, v18.8h\n    xtn       v19.8b, v20.8h            //Q9 = sign(delta)\n    mov       v18.d[1], v19.d[0]\n    abs       v14.8h, v14.8h\n    abs       v16.8h, v16.8h\n    xtn       v14.8b, v14.8h\n    xtn       v15.8b, v16.8h\n    mov       v14.d[1], v15.d[0]\n    umin      v14.16b, v14.16b , v12.16b //Q7 = |delta|\n    uqadd     v20.16b, v2.16b , v14.16b //p0+|delta|\n    uqadd     v22.16b, v4.16b , v14.16b //q0+|delta|\n    uqsub     v24.16b, v2.16b , v14.16b //p0-|delta|\n    uqsub     v26.16b, v4.16b , v14.16b //q0-|delta|\n    bit       v24.16b, v20.16b , v18.16b //p0 + delta\n    bit       v22.16b, v26.16b , v18.16b //q0 - delta\n    bit       v2.16b, v24.16b , v8.16b\n    bit       v4.16b, v22.16b , v8.16b\n    mov       v1.d[0], v0.d[1]\n    mov       v3.d[0], v2.d[1]\n    mov       v5.d[0], v4.d[1]\n    mov       v7.d[0], v6.d[1]\n    mov       v10.16b, v1.16b\n    mov       v1.16b, v2.16b\n    mov       v2.16b, v4.16b\n    mov       v4.16b, v10.16b\n    mov       v10.16b, v3.16b\n    mov       v3.16b, v6.16b\n    mov       v6.16b, v5.16b\n    mov       v5.16b, v10.16b\n    st4       {v0.h, v1.h, v2.h, v3.h}[0], [x12], x1\n    st4       {v0.h, v1.h, v2.h, v3.h}[1], [x12], x1\n    st4       {v0.h, v1.h, v2.h, v3.h}[2], [x12], x1\n    st4       {v0.h, v1.h, v2.h, v3.h}[3], [x12], x1\n\n    st4       {v4.h, v5.h, v6.h, v7.h}[0], [x12], x1\n    st4       {v4.h, v5.h, v6.h, v7.h}[1], [x12], x1\n    st4       {v4.h, v5.h, v6.h, v7.h}[2], [x12], x1\n    st4       {v4.h, v5.h, v6.h, v7.h}[3], [x12], x1\n\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_deblk_luma_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///*****************************************************************************/\n///*                                                                           */\n///*  File Name         : ih264_deblk_luma_av8.s                               */\n///*                                                                           */\n///*  Description       : Contains function definitions for deblocking luma    */\n///*                      edge. Functions are coded in NEON assembly and can   */\n///*                      be compiled using ARM RVDS.                          */\n///*                                                                           */\n///*  List of Functions : ih264_deblk_luma_vert_bs4_av8()                      */\n///*                      ih264_deblk_luma_vert_bslt4_av8()                    */\n///*                      ih264_deblk_luma_horz_bs4_av8()                      */\n///*                      ih264_deblk_luma_horz_bslt4_av8()                    */\n///*                                                                           */\n///*  Issues / Problems : None                                                 */\n///*                                                                           */\n///*  Revision History  :                                                      */\n///*                                                                           */\n///*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n///*         28 11 2013   Ittiam          Draft                                */\n///*                                                                           */\n///*****************************************************************************/\n\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Performs filtering of a luma block horizontal edge for cases where the\n//*     boundary strength is less than 4\n//*\n//* @par Description:\n//*       This operation is described in  Sec. 8.7.2.4 under the title\n//*       \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n//*\n//* @param[in] x0 - pu1_src\n//*  Pointer to the src sample q0\n//*\n//* @param[in] w1 - src_strd\n//*  Source stride\n//*\n//* @param[in] w2 - alpha\n//*  Alpha Value for the boundary\n//*\n//* @param[in] w3 - beta\n//*  Beta Value for the boundary\n//*\n//* @param[in] w4 - u4_bs\n//*    Packed Boundary strength array\n//*\n//* @param[in] x5 - pu1_cliptab\n//*    tc0_table\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n    .global ih264_deblk_luma_horz_bslt4_av8\n\nih264_deblk_luma_horz_bslt4_av8:\n\n    // STMFD sp!,{x4-x7,x14}\n    push_v_regs\n    sxtw      x1, w1\n    stp       x19, x20, [sp, #-16]!\n\n    //LDRD            x4,x5,[SP,#0x14]        //x4 = ui_Bs , x5 = *puc_ClpTab\n    sub       x0, x0, x1, lsl #1        //x1 = uc_Horizonpad\n    sub       x0, x0, x1                //x0 pointer to p2\n    rev       w4, w4                    //\n    ld1       {v10.8b, v11.8b}, [x0], x1 //p2 values are loaded into q5\n    mov       v12.s[0], w4              //d12[0] = ui_Bs\n    mov       x6, x0                    //keeping backup of pointer to p1\n    ld1       {v8.8b, v9.8b}, [x0], x1  //p1 values are loaded into q4\n    mov       x7, x0                    //keeping backup of pointer to p0\n    ld1       {v6.8b, v7.8b}, [x0], x1  //p0 values are loaded into q3\n    uxtl      v12.8h, v12.8b            //q6 = uc_Bs in each 16 bt scalar\n    ld1       {v0.8b, v1.8b}, [x0], x1  //q0 values are loaded into q0\n    mov       v10.d[1], v11.d[0]\n    mov       v8.d[1], v9.d[0]\n    mov       v6.d[1], v7.d[0]\n    uabd      v26.16b, v8.16b, v6.16b\n    ld1       {v2.8b, v3.8b}, [x0], x1  //q1 values are loaded into q1\n    mov       v0.d[1], v1.d[0]\n    mov       v2.d[1], v3.d[0]\n    uabd      v22.16b, v6.16b, v0.16b\n    ld1       {v16.s}[0], [x5]          //D16[0] contains cliptab\n    uabd      v24.16b, v2.16b, v0.16b\n    ld1       {v4.8b, v5.8b}, [x0], x1  //q2 values are loaded into q2\n    tbl       v14.8b, {v16.16b}, v12.8b //\n    mov       v4.d[1], v5.d[0]\n    dup       v20.16b, w2               //Q10 contains alpha\n    dup       v16.16b, w3               //Q8 contains beta\n    uxtl      v12.4s, v12.4h            //\n    uxtl      v14.4s, v14.4h            //\n    uabd      v28.16b, v10.16b, v6.16b\n    uabd      v30.16b, v4.16b, v0.16b\n    cmgt      v12.4s, v12.4s, #0\n    sli       v14.4s, v14.4s, #8\n    cmhs      v18.16b, v22.16b, v20.16b\n    cmhs      v24.16b, v24.16b, v16.16b\n    cmhs      v26.16b, v26.16b, v16.16b\n    cmhi      v20.16b, v16.16b , v28.16b //Q10=(Ap<Beta)\n    cmhi      v22.16b, v16.16b , v30.16b //Q11=(Aq<Beta)\n    sli       v14.4s, v14.4s, #16\n    orr       v18.16b, v18.16b , v24.16b //Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta )\n    usubl     v30.8h, v1.8b, v7.8b      //\n    usubl     v24.8h, v0.8b, v6.8b      //Q15,Q12 = (q0 - p0)\n    orr       v18.16b, v18.16b , v26.16b //Q9 = ( ABS(p0 - q0) >= Alpha ) | ( ABS(q1 - q0) >= Beta ) | ( ABS(p1 - p0) >= Beta )\n    usubl     v28.8h, v8.8b, v2.8b      //Q14 = (p1 - q1)L\n    shl       v26.8h, v30.8h, #2        //Q13 = (q0 - p0)<<2\n    shl       v24.8h, v24.8h, #2        //Q12 = (q0 - p0)<<2\n    usubl     v30.8h, v9.8b, v3.8b      //Q15 = (p1 - q1)H\n    bic       v12.16b, v12.16b , v18.16b //final condition\n    add       v24.8h, v24.8h , v28.8h   //\n    add       v26.8h, v26.8h , v30.8h   //Q13,Q12 = [ (q0 - p0)<<2 ] + (p1 - q1)\n    sub       v18.16b, v14.16b , v20.16b //Q9 = C0 + (Ap < Beta)\n    urhadd    v16.16b, v6.16b , v0.16b  //Q8 = ((p0+q0+1) >> 1)\n    mov       v17.d[0], v16.d[1]\n    sqrshrn   v24.8b, v24.8h, #3        //\n    sqrshrn   v25.8b, v26.8h, #3        //Q12 = i_macro = (((q0 - p0)<<2) + (p1 - q1) + 4)>>3\n    mov       v24.d[1], v25.d[0]\n    sub       v18.16b, v18.16b , v22.16b //Q9 = C0 + (Ap < Beta) + (Aq < Beta)\n    and       v20.16b, v20.16b , v12.16b //\n    and       v22.16b, v22.16b , v12.16b //\n    abs       v26.16b, v24.16b          //Q13 = ABS (i_macro)\n    uaddl     v28.8h, v17.8b, v11.8b    //\n    uaddl     v10.8h, v16.8b, v10.8b    //Q14,Q5 = p2 + (p0+q0+1)>>1\n    uaddl     v30.8h, v17.8b, v5.8b     //\n    umin      v18.16b, v26.16b , v18.16b //Q9 = delta = (ABS(i_macro) > C) ? C : ABS(i_macro)\n    ushll     v26.8h, v9.8b, #1         //\n    uaddl     v4.8h, v16.8b, v4.8b      //Q15,Q2 = q2 + (p0+q0+1)>>1\n    ushll     v16.8h, v8.8b, #1         //Q13,Q8 = (p1<<1)\n    and       v18.16b, v18.16b , v12.16b //Making delta zero in places where values shouldn be filterd\n    sub       v28.8h, v28.8h , v26.8h   //Q14,Q5 = [p2 + (p0+q0+1)>>1] - (p1<<1)\n    sub       v10.8h, v10.8h , v16.8h   //\n    ushll     v16.8h, v2.8b, #1         //\n    ushll     v26.8h, v3.8b, #1         //Q13,Q8 = (q1<<1)\n    sqshrn    v29.8b, v28.8h, #1        //\n    sqshrn    v28.8b, v10.8h, #1        //Q14 = i_macro_p1\n    mov       v28.d[1], v29.d[0]\n    sub       v4.8h, v4.8h , v16.8h     //\n    sub       v30.8h, v30.8h , v26.8h   //Q15,Q2  = [q2 + (p0+q0+1)>>1] - (q1<<1)\n    neg       v26.16b, v14.16b          //Q13 = -C0\n    smin      v28.16b, v28.16b , v14.16b //Q14 = min(C0,i_macro_p1)\n    cmge      v24.16b, v24.16b, #0\n    sqshrn    v31.8b, v30.8h, #1        //\n    sqshrn    v30.8b, v4.8h, #1         //Q15 = i_macro_q1\n    mov       v30.d[1], v31.d[0]\n    smax      v28.16b, v28.16b , v26.16b //Q14 = max( - C0 , min(C0, i_macro_p1) )\n    uqadd     v16.16b, v6.16b , v18.16b //Q8  = p0 + delta\n    uqsub     v6.16b, v6.16b , v18.16b  //Q3 = p0 - delta\n    smin      v30.16b, v30.16b , v14.16b //Q15 = min(C0,i_macro_q1)\n    and       v28.16b, v20.16b , v28.16b //condition check Ap<beta\n    uqadd     v14.16b, v0.16b , v18.16b //Q7 = q0 + delta\n    uqsub     v0.16b, v0.16b , v18.16b  //Q0   = q0 - delta\n    smax      v30.16b, v30.16b , v26.16b //Q15 = max( - C0 , min(C0, i_macro_q1) )\n    bif       v16.16b, v6.16b , v24.16b //Q8  = (i_macro >= 0 ) ? (p0+delta) : (p0-delta)\n    bif       v0.16b, v14.16b , v24.16b //Q0  = (i_macro >= 0 ) ? (q0-delta) : (q0+delta)\n    add       v28.16b, v28.16b , v8.16b //\n    and       v30.16b, v22.16b , v30.16b //condition check Aq<beta\n    st1       {v16.16b}, [x7], x1       //writting back filtered value of p0\n    add       v30.16b, v30.16b , v2.16b //\n    st1       {v0.16b}, [x7], x1        //writting back filtered value of q0\n    st1       {v28.16b}, [x6]           //writting back filtered value of p1\n    st1       {v30.16b}, [x7], x1       //writting back filtered value of q1\n\n    // LDMFD sp!,{x4-x7,pc}\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Performs filtering of a luma block horizontal edge when the\n//*     boundary strength is set to 4\n//*\n//* @par Description:\n//*       This operation is described in  Sec. 8.7.2.4 under the title\n//*       \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n//*\n//* @param[in] x0 - pu1_src\n//*  Pointer to the src sample q0\n//*\n//* @param[in] w1 - src_strd\n//*  Source stride\n//*\n//* @param[in] w2 - alpha\n//*  Alpha Value for the boundary\n//*\n//* @param[in] w3 - beta\n//*  Beta Value for the boundary\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n    .global ih264_deblk_luma_horz_bs4_av8\n\nih264_deblk_luma_horz_bs4_av8:\n\n    // Back up necessary registers on stack\n    // STMFD sp!,{x12,x14}\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x1, w1\n\n    // Init\n    dup       v0.16b, w2                //duplicate alpha\n    sub       x12, x0, x1               //pointer to p0 = q0 - src_strd\n    dup       v2.16b, w3                //duplicate beta\n    sub       x14, x0, x1, lsl#1        //pointer to p1 = q0 - src_strd*2\n    sub       x2, x0, x1, lsl#2         //pointer to p3 = q0 - src_strd*4\n    sub       x3, x14, x1               //pointer to p2 = p1 - src_strd\n\n    // Load Data\n    ld1       {v4.8b, v5.8b}, [x0], x1  //load q0 to Q2, q0 = q0 + src_strd\n    ld1       {v6.8b, v7.8b}, [x12]     //load p0 to Q3\n    ld1       {v8.8b, v9.8b}, [x0], x1  //load q1 to Q4, q0 = q0 + src_strd\n    ld1       {v10.8b, v11.8b}, [x14]   //load p1 to Q5\n    mov       v4.d[1] , v5.d[0]\n    mov       v6.d[1] , v7.d[0]\n    mov       v8.d[1] , v9.d[0]\n    mov       v10.d[1] , v11.d[0]\n\n    // Filter Decision\n    uabd      v12.16b  , v4.16b, v6.16b\n    uabd      v14.16b  , v8.16b, v4.16b\n    uabd      v16.16b  , v10.16b, v6.16b\n    cmhs      v18.16b, v12.16b , v0.16b //ABS(p0 - q0) >= Alpha\n    cmhs      v14.16b, v14.16b , v2.16b //ABS(q1 - q0) >= Beta\n    cmhs      v16.16b, v16.16b , v2.16b //ABS(q1 - q0) >= Beta\n    movi      v20.16b, #2\n    orr       v18.16b, v18.16b , v14.16b //ABS(p0 - q0) >= Alpha || ABS(q1 - q0) >= Beta\n    ld1       {v14.8b, v15.8b}, [x0], x1 //load q2 to Q7, q0 = q0 + src_strd\n    mov       v14.d[1] , v15.d[0]\n    orr       v18.16b, v18.16b , v16.16b //ABS(p0 - q0) >= Alpha || ABS(q1 - q0) >= Beta || ABS(p1 - p0) >= Beta\n    usra      v20.16b, v0.16b, #2       //alpha >>2 +2\n    uabd      v22.16b  , v14.16b, v4.16b\n    uaddl     v24.8h, v4.8b, v6.8b      //p0+q0 L\n    uaddl     v26.8h, v5.8b, v7.8b      //p0+q0 H\n    cmhi      v22.16b, v2.16b , v22.16b //Aq < Beta\n    cmhi      v20.16b, v20.16b , v12.16b //(ABS(p0 - q0) <((Alpha >>2) + 2))\n    // Deblock Filtering q0', q1', q2'\n    uaddw     v28.8h, v24.8h , v8.8b    //p0+q0+q1 L\n    uaddw     v30.8h, v26.8h , v9.8b    //p0+q0+q1 H\n    and       v22.16b, v22.16b , v20.16b //(Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2))\n    // q0' if (Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2)) TRUE\n    add       v16.8h, v28.8h , v28.8h   //2*(p0+q0+q1)L\n    add       v0.8h, v30.8h , v30.8h    //2*(p0+q0+q1)H\n    uaddw     v16.8h, v16.8h , v14.8b   //2*(p0+q0+q1)+q2 L\n    uaddw     v0.8h, v0.8h , v15.8b     //2*(p0+q0+q1)+q2 H\n    uaddw     v16.8h, v16.8h , v10.8b   //2*(p0+q0+q1)+q2 +p1 L\n    uaddw     v0.8h, v0.8h , v11.8b     //2*(p0+q0+q1)+q2 +p1 H\n    rshrn     v12.8b, v16.8h, #3        //(2*(p0+q0+q1)+q2 +p1 +4)>> 3 L [q0']\n    rshrn     v13.8b, v0.8h, #3         //(2*(p0+q0+q1)+q2 +p1 +4)>> 3 H [q0']\n    mov       v12.d[1] , v13.d[0]\n    // q0\" if (Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2)) FALSE\n    uaddl     v16.8h, v8.8b, v8.8b      //2*q1 L\n    uaddl     v0.8h, v9.8b, v9.8b       //2*q1 H\n    uaddw     v16.8h, v16.8h , v4.8b    //2*q1+q0 L\n    uaddw     v0.8h, v0.8h , v5.8b      //2*q1+q0 H\n    uaddw     v16.8h, v16.8h , v10.8b   //2*q1+q0+p1  L\n    uaddw     v0.8h, v0.8h , v11.8b     //2*q1+q0+p1 H\n    rshrn     v16.8b, v16.8h, #2        //(2*q1+q0+p1+2)>>2 L [q0\"]\n    rshrn     v17.8b, v0.8h, #2         //(2*q1+q0+p1+2)>>2 H [q0\"]\n    mov       v16.d[1] , v17.d[0]\n    uaddw     v28.8h, v28.8h , v14.8b   //p0+q0+q1+q2 L\n    uaddw     v30.8h, v30.8h , v15.8b   //p0+q0+q1+q2 H\n    ld1       {v0.8b, v1.8b}, [x0], x1  //load q3 to Q0, q0 = q0 + src_strd\n    mov       v0.d[1] , v1.d[0]\n    bit       v16.16b, v12.16b , v22.16b //choosing between q0' and q0\" depending on condn\n    sub       x0, x0, x1, lsl #2        //pointer to q0\n    bic       v22.16b, v22.16b , v18.16b //((ABS(p0 - q0) >= Alpha  || ABS(q1 - q0) >= Beta || ABS(p1 - p0) >= Beta))\n                                        // && (Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2))\n    rshrn     v12.8b, v28.8h, #2        //(p0+q0+q1+q2+2)>>2 L [q1']\n    rshrn     v13.8b, v30.8h, #2        //(p0+q0+q1+q2+2)>>2 H [q1']\n    mov       v12.d[1] , v13.d[0]\n    bif       v4.16b, v16.16b , v18.16b //choose q0 or filtered q0\n    mov       v5.d[0] , v4.d[1]\n    uaddl     v16.8h, v14.8b, v0.8b     //q2+q3,L\n    uaddl     v0.8h, v15.8b, v1.8b      //q2+q3,H\n    add       v28.8h, v28.8h , v16.8h   //p0+q0+q1+2*q2+q3 L\n    st1       {v4.8b, v5.8b}, [x0], x1  //store q0\n    add       v30.8h, v30.8h , v0.8h    //p0+q0+q1+2*q2+q3 H\n    add       v28.8h, v28.8h , v16.8h   //p0+q0+q1+3*q2+2*q3 L\n    add       v30.8h, v30.8h , v0.8h    //p0+q0+q1+3*q2+2*q3 H\n    rshrn     v0.8b, v28.8h, #3         //(p0+q0+q1+3*q2+2*q3+4)>>3 L [q2']\n    rshrn     v1.8b, v30.8h, #3         //(p0+q0+q1+3*q2+2*q3+4)>>3 H [q2']\n    mov       v0.d[1] , v1.d[0]\n    ld1       {v30.8b, v31.8b}, [x3]    //load p2 to Q15\n    mov       v30.d[1] , v31.d[0]\n    bif       v12.16b, v8.16b , v22.16b //choose q1 or filtered value of q1\n    mov       v13.d[0] , v12.d[1]\n    uabd      v16.16b  , v30.16b, v6.16b\n    uaddw     v24.8h, v24.8h , v10.8b   //p0+q0+p1 L\n    bif       v0.16b, v14.16b , v22.16b //choose q2 or filtered q2\n    mov       v1.d[0] , v0.d[1]\n    uaddw     v26.8h, v26.8h , v11.8b   //p0+q0+p1 H\n    st1       {v12.8b, v13.8b}, [x0], x1 //store q1\n    cmhi      v16.16b, v2.16b , v16.16b //Ap < Beta\n    add       v28.8h, v24.8h , v24.8h   //2*(p0+q0+p1) L\n    add       v4.8h, v26.8h , v26.8h    //2*(p0+q0+p1) H\n    st1       {v0.8b, v1.8b}, [x0], x1  //store q2\n    and       v20.16b, v20.16b , v16.16b //((Ap < Beta) && (ABS(p0 - q0) <((Alpha >>2) + 2)))\n    uaddw     v28.8h, v28.8h , v30.8b   //2*(p0+q0+p1)+p2 l\n    uaddw     v4.8h, v4.8h , v31.8b     //2*(p0+q0+p1)+p2 H\n    uaddw     v28.8h, v28.8h , v8.8b    //2*(p0+q0+p1)+p2+q1 L\n    uaddw     v4.8h, v4.8h , v9.8b      //2*(p0+q0+p1)+p2+q1 H\n    rshrn     v28.8b, v28.8h, #3        //(2*(p0+q0+p1)+p2+q1+4)>>3  L,p0'\n    rshrn     v29.8b, v4.8h, #3         //(2*(p0+q0+p1)+p2+q1+4)>>3  H,p0'\n    mov       v28.d[1] , v29.d[0]\n    movi      v0.8b, #2\n    movi      v1.4h, #2\n    uaddl     v2.8h, v6.8b, v8.8b       //p0+q1      L\n    umlal     v2.8h, v10.8b, v0.8b      //2*p1+p0+q1 L\n    uaddl     v16.8h, v7.8b, v9.8b      //p0+q1  H\n    umlal     v16.8h, v11.8b, v0.8b     //2*p1+p0+q1 H\n    uaddw     v12.8h, v24.8h , v30.8b   //(p0+q0+p1) +p2 L\n    ld1       {v24.8b, v25.8b}, [x2]    //load p3,Q12\n    mov       v24.d[1] , v25.d[0]\n    uaddw     v4.8h, v26.8h , v31.8b    //(p0+q0+p1) +p2 H\n    uaddl     v8.8h, v30.8b, v24.8b     //p2+p3 L\n    rshrn     v26.8b, v12.8h, #2        //((p0+q0+p1)+p2 +2)>>2,p1' L\n    rshrn     v2.8b, v2.8h, #2          //(2*p1+p0+q1+2)>>2,p0\"L\n    rshrn     v27.8b, v4.8h, #2         //((p0+q0+p1)+p2 +2)>>2,p1' H\n    rshrn     v3.8b, v16.8h, #2         //(2*p1+p0+q1+2)>>2,p0\" H\n    mov       v26.d[1] , v27.d[0]\n    mov       v2.d[1] , v3.d[0]\n    uaddl     v16.8h, v31.8b, v25.8b    //p2+p3 H\n    mla       v12.8h, v8.8h , v1.h[0]   //(p0+q0+p1)+3*p2+2*p3 L\n    mla       v4.8h, v16.8h , v1.h[0]   //(p0+q0+p1)+3*p2+2*p3 H\n    bic       v16.16b, v20.16b , v18.16b //((ABS(p0 - q0) >= Alpha  || ABS(q1 - q0) >= Beta || ABS(p1 - p0) >= Beta))\n    mov       v17.d[0] , v16.d[1]       //&& (Ap < Beta && ABS(p0 - q0) <((Alpha >>2) + 2))\n    bit       v2.16b, v28.16b , v20.16b //choosing between po' and p0\"\n    mov       v3.d[0] , v2.d[1]\n    rshrn     v12.8b, v12.8h, #3        //((p0+q0+p1)+3*p2+2*p3+4)>>3 L p2'\n    rshrn     v13.8b, v4.8h, #3         //((p0+q0+p1)+3*p2+2*p3+4)>>3 H p2'\n    mov       v12.d[1] , v13.d[0]\n    bif       v6.16b, v2.16b , v18.16b  //choosing between p0 and filtered value of p0\n    bit       v10.16b, v26.16b , v16.16b //choosing between p1 and p1'\n    bit       v30.16b, v12.16b , v16.16b //choosing between p2 and p2'\n    st1       {v6.16b}, [x12]           //store p0\n    st1       {v10.16b}, [x14]          //store p1\n    st1       {v30.16b}, [x3]           //store p2\n\n    // LDMFD sp!,{x12,pc}\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Performs filtering of a luma block vertical edge for cases where the\n//*     boundary strength is less than 4\n//*\n//* @par Description:\n//*       This operation is described in  Sec. 8.7.2.4 under the title\n//*       \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n//*\n//* @param[in] x0 - pu1_src\n//*  Pointer to the src sample q0\n//*\n//* @param[in] w1 - src_strd\n//*  Source stride\n//*\n//* @param[in] w2 - alpha\n//*  Alpha Value for the boundary\n//*\n//* @param[in] w3 - beta\n//*  Beta Value for the boundary\n//*\n//* @param[in] w4 - u4_bs\n//*    Packed Boundary strength array\n//*\n//* @param[in] x5 - pu1_cliptab\n//*    tc0_table\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n    .global ih264_deblk_luma_vert_bslt4_av8\n\nih264_deblk_luma_vert_bslt4_av8:\n\n    // STMFD sp!,{x12,x14}\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x1, w1\n\n    sub       x0, x0, #4                //pointer uc_edgePixel-4\n    mov       x12, x4\n    mov       x14, x5\n    mov       x17, x0\n    //loading p3:p2:p1:p0:q0:q1:q2:q3 for every row\n    ld1       {v0.8b}, [x0], x1         //row1\n    ld1       {v2.8b}, [x0], x1         //row2\n    ld1       {v4.8b}, [x0], x1         //row3\n    rev       w12, w12                  //reversing ui_bs\n    ld1       {v6.8b}, [x0], x1         //row4\n    mov       v18.s[0], w12             //d12[0] = ui_Bs\n    ld1       {v16.s}[0], [x14]         //D16[0] contains cliptab\n    ld1       {v8.8b}, [x0], x1         //row5\n    uxtl      v18.8h, v18.8b            //q6 = uc_Bs in each 16 bt scalar\n    ld1       {v10.8b}, [x0], x1        //row6\n    ld1       {v12.8b}, [x0], x1        //row7\n    tbl       v16.8b, {v16.16b}, v18.8b //puc_ClipTab[uc_Bs]\n    ld1       {v14.8b}, [x0], x1        //row8\n    ld1       {v1.8b}, [x0], x1         //row9\n    uxtl      v16.4s, v16.4h            //\n    ld1       {v3.8b}, [x0], x1         //row10\n    ld1       {v5.8b}, [x0], x1         //row11\n    ld1       {v7.8b}, [x0], x1         //row12\n    sli       v16.4s, v16.4s, #8        //\n    ld1       {v9.8b}, [x0], x1         //row13\n    ld1       {v11.8b}, [x0], x1        //row14\n    ld1       {v13.8b}, [x0], x1        //row15\n    sli       v16.4s, v16.4s, #16\n    ld1       {v15.8b}, [x0], x1        //row16\n\n\n    //taking two 8x8 transposes\n    //2X2 transposes\n    trn1      v21.8b, v0.8b, v2.8b\n    trn2      v2.8b, v0.8b, v2.8b       //row1 &2\n    mov       v0.8b, v21.8b\n    trn1      v21.8b, v4.8b, v6.8b\n    trn2      v6.8b, v4.8b, v6.8b       //row3&row4\n    mov       v4.8b, v21.8b\n    trn1      v21.8b, v8.8b, v10.8b\n    trn2      v10.8b, v8.8b, v10.8b     //row5&6\n    mov       v8.8b, v21.8b\n    trn1      v21.8b, v12.8b, v14.8b\n    trn2      v14.8b, v12.8b, v14.8b    //row7 & 8\n    mov       v12.8b, v21.8b\n    trn1      v21.8b, v1.8b, v3.8b\n    trn2      v3.8b, v1.8b, v3.8b       //row9 &10\n    mov       v1.8b, v21.8b\n    trn1      v21.8b, v5.8b, v7.8b\n    trn2      v7.8b, v5.8b, v7.8b       //row11 & 12\n    mov       v5.8b, v21.8b\n    trn1      v21.8b, v9.8b, v11.8b\n    trn2      v11.8b, v9.8b, v11.8b     //row13 &14\n    mov       v9.8b, v21.8b\n    trn1      v21.8b, v13.8b, v15.8b\n    trn2      v15.8b, v13.8b, v15.8b    //row15 & 16\n    mov       v13.8b, v21.8b\n    //4x4 transposes\n    trn1      v21.4h, v2.4h, v6.4h\n    trn2      v6.4h, v2.4h, v6.4h       //row2 & row4\n    mov       v2.8b, v21.8b\n    trn1      v21.4h, v10.4h, v14.4h\n    trn2      v14.4h, v10.4h, v14.4h    //row6 & row8\n    mov       v10.8b, v21.8b\n    trn1      v21.4h, v3.4h, v7.4h\n    trn2      v7.4h, v3.4h, v7.4h       //row10 & 12\n    mov       v3.8b, v21.8b\n    trn1      v21.4h, v11.4h, v15.4h\n    trn2      v15.4h, v11.4h, v15.4h    //row14 & row16\n    mov       v11.8b, v21.8b\n    trn1      v21.2s, v6.2s, v14.2s\n    trn2      v14.2s, v6.2s, v14.2s     //row4 & 8\n    mov       v6.8b, v21.8b\n    trn1      v21.2s, v7.2s, v15.2s\n    trn2      v15.2s, v7.2s, v15.2s     //row 12 & 16\n    mov       v7.8b, v21.8b\n    //now Q3 ->p0 and Q7->q3\n    trn1      v21.4h, v0.4h, v4.4h\n    trn2      v4.4h, v0.4h, v4.4h       //row1 & 3\n    mov       v0.8b, v21.8b\n    trn1      v21.4h, v8.4h, v12.4h\n    trn2      v12.4h, v8.4h, v12.4h     //row 5 & 7\n    mov       v8.8b, v21.8b\n    trn1      v21.4h, v1.4h, v5.4h\n    trn2      v5.4h, v1.4h, v5.4h       //row9 & row11\n    mov       v1.8b, v21.8b\n    trn1      v21.4h, v9.4h, v13.4h\n    trn2      v13.4h, v9.4h, v13.4h     //row13 & row15\n    mov       v9.8b, v21.8b\n    trn1      v21.2s, v0.2s, v8.2s\n    trn2      v8.2s, v0.2s, v8.2s       //row1 & row5\n    mov       v0.8b, v21.8b\n    trn1      v21.2s, v1.2s, v9.2s\n    trn2      v9.2s, v1.2s, v9.2s       //row9 & 13\n    mov       v1.8b, v21.8b\n    //now Q0->p3 & Q4->q0\n    //starting processing as p0 and q0 are now ready\n    trn1      v21.2s, v2.2s, v10.2s\n    trn2      v10.2s, v2.2s, v10.2s     //row2 &6\n    mov       v2.8b, v21.8b\n    mov       v6.d[1] , v7.d[0]\n    mov       v8.d[1] , v9.d[0]\n    urhadd    v20.16b, v6.16b , v8.16b  //((p0 + q0 + 1) >> 1)\n    mov       v21.d[0], v20.d[1]\n    trn1      v31.2s, v3.2s, v11.2s\n    trn2      v11.2s, v3.2s, v11.2s     //row10&row14\n    mov       v3.8b, v31.8b\n    movi      v19.8b, #2\n    mov       v18.d[1], v19.d[0]\n    //now Q1->p2     & Q5->q1\n    trn1      v31.2s, v4.2s, v12.2s\n    trn2      v12.2s, v4.2s, v12.2s     //row3 & 7\n    mov       v4.8b, v31.8b\n    uabd      v22.16b  , v6.16b, v8.16b //ABS(q1 - q0)\n    trn1      v31.2s, v5.2s, v13.2s\n    trn2      v13.2s, v5.2s, v13.2s     //row11 & row15\n    mov       v5.8b, v31.8b\n    mov       v0.d[1] , v1.d[0]\n    mov       v2.d[1] , v3.d[0]\n    mov       v4.d[1] , v5.d[0]\n    mov       v10.d[1] , v11.d[0]\n    mov       v12.d[1] , v13.d[0]\n    mov       v14.d[1] , v15.d[0]\n    uaddl     v24.8h, v20.8b, v2.8b     //(p2 + ((p0 + q0 + 1) >> 1) L\n    //now            Q2->p1,Q6->q2\n    uaddl     v26.8h, v21.8b, v3.8b     //(p2 + ((p0 + q0 + 1) >> 1) H\n    umlsl     v24.8h, v4.8b, v19.8b     //(p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) L\n    umlsl     v26.8h, v5.8b, v19.8b     //(p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) H\n    dup       v28.16b, w2               //alpha\n    cmhs      v22.16b, v22.16b , v28.16b //ABS(p0 - q0) >= Alpha(Alpha <=ABS(p0 - q0))\n    dup       v28.16b, w3               //beta\n    uabd      v30.16b  , v10.16b, v8.16b //ABS(q1 - q0)\n    sqshrn    v24.8b, v24.8h, #1        //((p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1) L\n    sqshrn    v25.8b, v26.8h, #1        //((p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1) H\n    mov       v24.d[1], v25.d[0]\n    cmhs      v30.16b, v30.16b , v28.16b //ABS(p0 - q0) >= Alpha(Alpha <=ABS(p0 - q0))\n    uabd      v26.16b  , v4.16b, v6.16b //ABS(q1 - q0)\n\n    smin      v24.16b, v24.16b , v16.16b //min(deltap1 ,C0)\n    orr       v22.16b, v22.16b , v30.16b //ABS(q1 - q0) >= Beta ||ABS(p0 - q0) >= Alpha\n    neg       v30.16b, v16.16b          //-C0\n    cmhs      v26.16b, v26.16b , v28.16b //ABS(p0 - q0) >= Alpha(Alpha <=ABS(p0 - q0))\n    smax      v24.16b, v24.16b , v30.16b //max(deltap1,-C0)\n    orr       v22.16b, v22.16b , v26.16b //ABS(p0 - q0) >= Alpha  || ABS(q1 - q0) >= Beta ||    ABS(p1 - p0) >= Beta)\n    uxtl      v26.4s, v18.4h            //ui_bs\n    uaddl     v18.8h, v20.8b, v12.8b    //q2 + ((p0 + q0 + 1) >> 1) L\n    cmeq      v26.4s, v26.4s , #0       //ABS(p0 - q0) >= Alpha(Alpha <=ABS(p0 - q0))\n    usubw     v18.8h, v18.8h , v10.8b   //(q2 + ((p0 + q0 + 1) >> 1) - q1) L\n    uaddl     v20.8h, v21.8b, v13.8b    //q2 + ((p0 + q0 + 1) >> 1) H\n    usubw     v18.8h, v18.8h , v10.8b   //(q2 + ((p0 + q0 + 1) >> 1) - 2*q1)L\n    usubw     v20.8h, v20.8h , v11.8b   //(q2 + ((p0 + q0 + 1) >> 1) - q1) H\n    orr       v26.16b, v26.16b , v22.16b //(ABS(p0 - q0) >= Alpha  || ABS(q1 - q0) >= Beta || ABS(p1 - p0) >= Beta)) &&(ui_bs)\n    usubw     v20.8h, v20.8h , v11.8b   //(q2 + ((p0 + q0 + 1) >> 1) - 2*q1) H\n    sqshrn    v18.8b, v18.8h, #1        //((q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1) L\n    uabd      v22.16b  , v2.16b, v6.16b //ABS(q1 - q0)\n    sqshrn    v19.8b, v20.8h, #1        //((q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1) H\n    mov       v18.d[1], v19.d[0]\n    uabd      v20.16b  , v12.16b, v8.16b //ABS(q1 - q0)\n    cmhi      v22.16b, v28.16b , v22.16b //Ap < Beta\n    smin      v18.16b, v18.16b , v16.16b //min(delatq1,C0)\n    cmhi      v20.16b, v28.16b , v20.16b //Aq <Beta\n    usubl     v28.8h, v8.8b, v6.8b      //(q0 - p0) L\n    smax      v18.16b, v18.16b , v30.16b //max(deltaq1,-C0)\n    usubl     v30.8h, v9.8b, v7.8b      //(q0 - p0) H\n    shl       v28.8h, v28.8h, #2        //(q0 - p0)<<2 L\n    sub       v16.16b, v16.16b , v22.16b //C0 + (Ap < Beta)\n    shl       v30.8h, v30.8h, #2        //(q0 - p0) << 2) H\n    uaddw     v28.8h, v28.8h , v4.8b    //((q0 - p0) << 2) + (p1  L\n    uaddw     v30.8h, v30.8h , v5.8b    //((q0 - p0) << 2) + (p1 H\n    usubw     v28.8h, v28.8h , v10.8b   //((q0 - p0) << 2) + (p1 - q1) L\n    usubw     v30.8h, v30.8h , v11.8b   //((q0 - p0) << 2) + (p1 - q1) H\n    bic       v22.16b, v22.16b , v26.16b //final condition for p1\n    rshrn     v28.8b, v28.8h, #3        //delta = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3); L\n    rshrn     v29.8b, v30.8h, #3        //delta = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3) H\n    mov       v28.d[1], v29.d[0]\n    sub       v16.16b, v16.16b , v20.16b //C0 + (Ap < Beta) + (Aq < Beta)\n    bic       v20.16b, v20.16b , v26.16b //final condition for q1\n    abs       v30.16b, v28.16b          //abs(delta)\n    and       v24.16b, v24.16b , v22.16b //delatp1\n    and       v18.16b, v18.16b , v20.16b //delta q1\n    umin      v30.16b, v30.16b , v16.16b //min((abs(delta),C)\n    add       v4.16b, v4.16b , v24.16b  //p1+deltap1\n    add       v10.16b, v10.16b , v18.16b //q1+deltaq1\n    mov       v5.d[0], v4.d[1]\n    mov       v11.d[0], v10.d[1]\n    bic       v30.16b, v30.16b , v26.16b //abs(delta) of pixels to be changed only\n    // VCGE.S8 Q14,    Q14,#0                    //sign(delta)\n    cmge      v28.16b, v28.16b , #0\n    uqsub     v22.16b, v6.16b , v30.16b //clip(p0-delta)\n\n    trn1      v21.8b, v0.8b, v2.8b\n    trn2      v2.8b, v0.8b, v2.8b       //row1 &2\n    mov       v0.8b, v21.8b\n    uqadd     v6.16b, v6.16b , v30.16b  //clip(p0+delta)\n\n    trn1      v21.8b, v1.8b, v3.8b\n    trn2      v3.8b, v1.8b, v3.8b       //row9 &10\n    mov       v1.8b, v21.8b\n    uqadd     v24.16b, v8.16b , v30.16b //clip(q0+delta)\n    trn1      v21.8b, v12.8b, v14.8b\n    trn2      v14.8b, v12.8b, v14.8b    //row7 & 8\n    mov       v12.8b, v21.8b\n    uqsub     v8.16b, v8.16b , v30.16b  //clip(q0-delta)\n    trn1      v21.8b, v13.8b, v15.8b\n    trn2      v15.8b, v13.8b, v15.8b    //row15 & 16\n    mov       v13.8b, v21.8b\n    bif       v6.16b, v22.16b , v28.16b //p0\n    bif       v8.16b, v24.16b , v28.16b //q0\n    mov       v7.d[0], v6.d[1]\n    mov       v9.d[0], v8.d[1]\n    trn1      v21.8b, v4.8b, v6.8b\n    trn2      v6.8b, v4.8b, v6.8b       //row3&row4\n    mov       v4.8b, v21.8b\n    trn1      v21.8b, v8.8b, v10.8b\n    trn2      v10.8b, v8.8b, v10.8b     //row5&6\n    mov       v8.8b, v21.8b\n    trn1      v21.8b, v5.8b, v7.8b\n    trn2      v7.8b, v5.8b, v7.8b       //row11 & 12\n    mov       v5.8b, v21.8b\n    trn1      v21.8b, v9.8b, v11.8b\n    trn2      v11.8b, v9.8b, v11.8b     //row13 &14\n    mov       v9.8b, v21.8b\n    trn1      v21.4h, v2.4h, v6.4h\n    trn2      v6.4h, v2.4h, v6.4h       //row2 & row4\n    mov       v2.8b, v21.8b\n    trn1      v21.4h, v10.4h, v14.4h\n    trn2      v14.4h, v10.4h, v14.4h    //row6 & row8\n    mov       v10.8b, v21.8b\n    trn1      v21.4h, v3.4h, v7.4h\n    trn2      v7.4h, v3.4h, v7.4h       //row10 & 12\n    mov       v3.8b, v21.8b\n    trn1      v21.4h, v11.4h, v15.4h\n    trn2      v15.4h, v11.4h, v15.4h    //row14 & row16\n    mov       v11.8b, v21.8b\n    trn1      v21.2s, v6.2s, v14.2s\n    trn2      v14.2s, v6.2s, v14.2s     //row4 & 8\n    mov       v6.8b, v21.8b\n    trn1      v21.2s, v7.2s, v15.2s\n    trn2      v15.2s, v7.2s, v15.2s     //row 12 & 16\n    mov       v7.8b, v21.8b\n    //now Q3 ->p0 and Q7->q3\n    trn1      v21.4h, v0.4h, v4.4h\n    trn2      v4.4h, v0.4h, v4.4h       //row1 & 3\n    mov       v0.8b, v21.8b\n    trn1      v21.4h, v8.4h, v12.4h\n    trn2      v12.4h, v8.4h, v12.4h     //row 5 & 7\n    mov       v8.8b, v21.8b\n    trn1      v21.4h, v1.4h, v5.4h\n    trn2      v5.4h, v1.4h, v5.4h       //row9 & row11\n    mov       v1.8b, v21.8b\n    trn1      v21.4h, v9.4h, v13.4h\n    trn2      v13.4h, v9.4h, v13.4h     //row13 & row15\n    mov       v9.8b, v21.8b\n    sub       x0, x0, x1, lsl#4         //restore pointer\n    trn1      v21.2s, v0.2s, v8.2s\n    trn2      v8.2s, v0.2s, v8.2s       //row1 & row5\n    mov       v0.8b, v21.8b\n    trn1      v21.2s, v1.2s, v9.2s\n    trn2      v9.2s, v1.2s, v9.2s       //row9 & 13\n    mov       v1.8b, v21.8b\n    trn1      v21.2s, v2.2s, v10.2s\n    trn2      v10.2s, v2.2s, v10.2s     //row2 &6\n    mov       v2.8b, v21.8b\n    trn1      v21.2s, v3.2s, v11.2s\n    trn2      v11.2s, v3.2s, v11.2s     //row10&row14\n    mov       v3.8b, v21.8b\n    trn1      v21.2s, v4.2s, v12.2s\n    trn2      v12.2s, v4.2s, v12.2s     //row3 & 7\n    mov       v4.8b, v21.8b\n    trn1      v21.2s, v5.2s, v13.2s\n    trn2      v13.2s, v5.2s, v13.2s     //row11 & row15\n    mov       v5.8b, v21.8b\n    st1       {v0.8b}, [x0], x1         //row1\n    st1       {v2.8b}, [x0], x1         //row2\n    st1       {v4.8b}, [x0], x1         //row3\n    st1       {v6.8b}, [x0], x1         //row4\n    st1       {v8.8b}, [x0], x1         //row5\n    st1       {v10.8b}, [x0], x1        //row6\n    st1       {v12.8b}, [x0], x1        //row7\n    st1       {v14.8b}, [x0], x1        //row8\n    st1       {v1.8b}, [x0], x1         //row9\n    st1       {v3.8b}, [x0], x1         //row10\n    st1       {v5.8b}, [x0], x1         //row11\n    st1       {v7.8b}, [x0], x1         //row12\n    st1       {v9.8b}, [x0], x1         //row13\n    st1       {v11.8b}, [x0], x1        //row14\n    st1       {v13.8b}, [x0], x1        //row15\n    st1       {v15.8b}, [x0], x1        //row16\n\n    // LDMFD sp!,{x12,pc}\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Performs filtering of a luma block vertical edge when the\n//*     boundary strength is set to 4\n//*\n//* @par Description:\n//*       This operation is described in  Sec. 8.7.2.4 under the title\n//*       \"Filtering process for edges for bS equal to 4\" in ITU T Rec H.264.\n//*\n//* @param[in] x0 - pu1_src\n//*  Pointer to the src sample q0\n//*\n//* @param[in] w1 - src_strd\n//*  Source stride\n//*\n//* @param[in] w2 - alpha\n//*  Alpha Value for the boundary\n//*\n//* @param[in] w3 - beta\n//*  Beta Value for the boundary\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n    .global ih264_deblk_luma_vert_bs4_av8\n\nih264_deblk_luma_vert_bs4_av8:\n\n    // STMFD sp!,{x12,x14}\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n\n    sub       x0, x0, #4                //pointer uc_edgePixel-4\n    mov       x17, x0\n    //loading p3:p2:p1:p0:q0:q1:q2:q3 for every row\n    ld1       {v0.8b}, [x0], x1         //row1\n    ld1       {v2.8b}, [x0], x1         //row2\n    ld1       {v4.8b}, [x0], x1         //row3\n    ld1       {v6.8b}, [x0], x1         //row4\n    ld1       {v8.8b}, [x0], x1         //row5\n    ld1       {v10.8b}, [x0], x1        //row6\n    ld1       {v12.8b}, [x0], x1        //row7\n    ld1       {v14.8b}, [x0], x1        //row8\n    ld1       {v1.8b}, [x0], x1         //row9\n    ld1       {v3.8b}, [x0], x1         //row10\n    ld1       {v5.8b}, [x0], x1         //row11\n    ld1       {v7.8b}, [x0], x1         //row12\n    ld1       {v9.8b}, [x0], x1         //row13\n    ld1       {v11.8b}, [x0], x1        //row14\n    ld1       {v13.8b}, [x0], x1        //row15\n    ld1       {v15.8b}, [x0], x1        //row16\n\n    //taking two 8x8 transposes\n    //2X2 transposes\n    trn1      v21.8b, v0.8b, v2.8b\n    trn2      v2.8b, v0.8b, v2.8b       //row1 &2\n    mov       v0.8b, v21.8b\n    trn1      v21.8b, v4.8b, v6.8b\n    trn2      v6.8b, v4.8b, v6.8b       //row3&row4\n    mov       v4.8b, v21.8b\n    trn1      v21.8b, v8.8b, v10.8b\n    trn2      v10.8b, v8.8b, v10.8b     //row5&6\n    mov       v8.8b, v21.8b\n    trn1      v21.8b, v12.8b, v14.8b\n    trn2      v14.8b, v12.8b, v14.8b    //row7 & 8\n    mov       v12.8b, v21.8b\n    trn1      v21.8b, v1.8b, v3.8b\n    trn2      v3.8b, v1.8b, v3.8b       //row9 &10\n    mov       v1.8b , v21.8b\n    trn1      v21.8b, v5.8b, v7.8b\n    trn2      v7.8b, v5.8b, v7.8b       //row11 & 12\n    mov       v5.8b , v21.8b\n    trn1      v21.8b, v9.8b, v11.8b\n    trn2      v11.8b, v9.8b, v11.8b     //row13 &14\n    mov       v9.8b , v21.8b\n    trn1      v21.8b, v13.8b, v15.8b\n    trn2      v15.8b, v13.8b, v15.8b    //row15 & 16\n    mov       v13.8b , v21.8b\n    //4x4 transposes\n    trn1      v21.4h, v2.4h, v6.4h\n    trn2      v6.4h, v2.4h, v6.4h       //row2 & row4\n    mov       v2.8b, v21.8b\n    trn1      v21.4h, v10.4h, v14.4h\n    trn2      v14.4h, v10.4h, v14.4h    //row6 & row8\n    mov       v10.8b , v21.8b\n    trn1      v21.4h, v3.4h, v7.4h\n    trn2      v7.4h, v3.4h, v7.4h       //row10 & 12\n    mov       v3.8b, v21.8b\n    trn1      v21.4h, v11.4h, v15.4h\n    trn2      v15.4h, v11.4h, v15.4h    //row14 & row16\n    mov       v11.8b, v21.8b\n    trn1      v21.2s, v6.2s, v14.2s\n    trn2      v14.2s, v6.2s, v14.2s     //row4 & 8\n    mov       v6.8b, v21.8b\n    trn1      v21.2s, v7.2s, v15.2s\n    trn2      v15.2s, v7.2s, v15.2s     //row 12 & 16\n    mov       v7.8b, v21.8b\n    //now Q3 ->p0 and Q7->q3\n    trn1      v21.4h, v0.4h, v4.4h\n    trn2      v4.4h, v0.4h, v4.4h       //row1 & 3\n    mov       v0.8b , v21.8b\n    trn1      v21.4h, v8.4h, v12.4h\n    trn2      v12.4h, v8.4h, v12.4h     //row 5 & 7\n    mov       v8.8b, v21.8b\n    trn1      v21.4h, v1.4h, v5.4h\n    trn2      v5.4h, v1.4h, v5.4h       //row9 & row11\n    mov       v1.8b, v21.8b\n    trn1      v21.4h, v9.4h, v13.4h\n    trn2      v13.4h, v9.4h, v13.4h     //row13 & row15\n    mov       v9.8b , v21.8b\n    trn1      v21.2s, v0.2s, v8.2s\n    trn2      v8.2s, v0.2s, v8.2s       //row1 & row5\n    mov       v0.8b, v21.8b\n    trn1      v21.2s, v1.2s, v9.2s\n    trn2      v9.2s, v1.2s, v9.2s       //row9 & 13\n    mov       v1.8b, v21.8b\n    //now Q0->p3 & Q4->q0\n    //starting processing as p0 and q0 are now ready\n    //now Q1->p2 & Q5->q1\n    mov       v31.d[0], v14.d[0]\n    mov       v31.d[1], v15.d[0]\n    trn1      v21.2s, v4.2s, v12.2s\n    trn2      v12.2s, v4.2s, v12.2s     //row3 & 7\n    mov       v4.8b, v21.8b\n    movi      v28.8h, #2\n    trn1      v21.2s, v5.2s, v13.2s\n    trn2      v13.2s, v5.2s, v13.2s     //row11 & row15\n    mov       v5.8b, v21.8b\n    uaddl     v16.8h, v6.8b, v8.8b      //p0+q0 L\n    trn1      v21.2s, v2.2s, v10.2s\n    trn2      v10.2s, v2.2s, v10.2s     //row2 &6\n    mov       v2.8b, v21.8b\n    uaddl     v18.8h, v7.8b, v9.8b      //p0+q0 H\n    trn1      v21.2s, v3.2s, v11.2s\n    trn2      v11.2s, v3.2s, v11.2s     //row10&row14\n    mov       v3.8b, v21.8b\n    uaddw     v20.8h, v16.8h , v4.8b    //p0+q0+p1 L\n    uaddw     v22.8h, v18.8h , v5.8b    //p0+q0+p1 H\n    uaddl     v24.8h, v2.8b, v10.8b     //p2+q1 L\n    uaddl     v26.8h, v3.8b, v11.8b     //p2+q1 H\n    mla       v24.8h, v20.8h , v28.8h   //p2 + X2(p1) + X2(p0) + X2(q0) + q1 L\n    mla       v26.8h, v22.8h , v28.8h   //p2 + X2(p1) + X2(p0) + X2(q0) + q1 H\n    movi      v28.16b, #2\n    uaddw     v16.8h, v20.8h , v2.8b    //p0+q0+p1+p2 L\n    uaddw     v18.8h, v22.8h , v3.8b    //p0+q0+p1+p2 H\n    dup       v30.16b, w2               //duplicate alpha\n    rshrn     v20.8b, v16.8h, #2        //(p2 + p1 + p0 + q0 + 2) >> 2)L p1'\n    rshrn     v21.8b, v18.8h, #2        //(p2 + p1 + p0 + q0 + 2) >> 2)H p1'\n    mov       v20.d[1] , v21.d[0]\n    mov       v0.d[1] , v1.d[0]\n    mov       v2.d[1] , v3.d[0]\n    mov       v4.d[1] , v5.d[0]\n    mov       v6.d[1] , v7.d[0]\n    mov       v8.d[1] , v9.d[0]\n    mov       v10.d[1] , v11.d[0]\n    mov       v12.d[1] , v13.d[0]\n    mov       v14.d[1] , v15.d[0]\n    uabd      v22.16b  , v6.16b, v8.16b\n    usra      v28.16b, v30.16b, #2      //alpha >>2 +2\n    uabd      v30.16b  , v2.16b, v6.16b\n    rshrn     v24.8b, v24.8h, #3        //((p2 + X2(p1) + X2(p0) + X2(q0) + q1 + 4) >> 3) L p0'\n    rshrn     v25.8b, v26.8h, #3        //((p2 + X2(p1) + X2(p0) + X2(q0) + q1 + 4) >> 3) H p0'\n    mov       v24.d[1] , v25.d[0]\n    dup       v26.16b, w3               //beta\n    cmhi      v28.16b, v28.16b , v22.16b //ABS(p0 - q0) <((Alpha >>2) + 2)\n    uaddl     v22.8h, v6.8b, v10.8b     //p0+q1 L\n    cmhi      v14.16b, v26.16b , v30.16b //beta>Ap\n    uaddl     v30.8h, v7.8b, v11.8b     //p0+q1 H\n    uaddw     v22.8h, v22.8h , v4.8b    //p0+q1+p1 L\n    uaddw     v30.8h, v30.8h , v5.8b    //p0+q1+p1 H\n    uaddw     v22.8h, v22.8h , v4.8b    //p0+q1+2*p1 L\n    uaddw     v30.8h, v30.8h , v5.8b    //p0+q1+2*p1 H\n    and       v14.16b, v14.16b , v28.16b //(Ap < Beta && ABS(p0 - q0) <((Alpha >>2) + 2)\n    rshrn     v22.8b, v22.8h, #2        //((X2(p1) + p0 + q1 + 2) >> 2) L p0\"\n    rshrn     v23.8b, v30.8h, #2        //((X2(p1) + p0 + q1 + 2) >> 2) H p0\"\n    mov       v22.d[1] , v23.d[0]\n    uaddl     v30.8h, v2.8b, v0.8b      //p2+p3 L\n    bif       v24.16b, v22.16b , v14.16b //p0' or p0 \"\n    uaddl     v22.8h, v3.8b, v1.8b      //p2+p3 H\n    add       v30.8h, v30.8h , v30.8h   //2*(p2+p3) L\n    add       v22.8h, v22.8h , v22.8h   //2*(p2+p3)H\n    add       v16.8h, v16.8h , v30.8h   //(X2(p3) + X3(p2) + p1 + p0 + q0) L\n    add       v18.8h, v18.8h , v22.8h   //(X2(p3) + X3(p2) + p1 + p0 + q0) H\n    uabd      v30.16b  , v12.16b, v8.16b\n    uabd      v22.16b  , v10.16b, v8.16b\n    rshrn     v16.8b, v16.8h, #3        //((X2(p3) + X3(p2) + p1 + p0 + q0 + 4) >> 3); L p2'\n    rshrn     v17.8b, v18.8h, #3        //((X2(p3) + X3(p2) + p1 + p0 + q0 + 4) >> 3); H p2'\n    mov       v16.d[1] , v17.d[0]\n    uabd      v18.16b  , v4.16b, v6.16b\n    cmhi      v30.16b, v26.16b , v30.16b //Aq < Beta\n    cmhs      v22.16b, v22.16b, v26.16b\n    cmhs      v18.16b, v18.16b, v26.16b\n    dup       v26.16b, w2               //duplicate alpha\n    and       v30.16b, v30.16b , v28.16b //(Aq < Beta && ABS(p0 - q0) <((Alpha >>2) + 2))\n    uabd      v28.16b  , v6.16b, v8.16b\n    orr       v22.16b, v22.16b , v18.16b //ABS(p1 - p0) >= Beta || ABS(q1 - q0) >= Beta\n    uaddl     v18.8h, v6.8b, v8.8b      //p0+q0 L\n    cmhs      v28.16b, v28.16b, v26.16b\n    uaddl     v26.8h, v7.8b, v9.8b      //p0+q0 H\n    uaddw     v18.8h, v18.8h , v10.8b   //p0+q0+q1 L\n    orr       v22.16b, v22.16b , v28.16b //ABS(p1 - p0) >= Beta || ABS(q1 - q0) >= Beta||ABS(p0 - q0) >= Alpha\n    uaddw     v26.8h, v26.8h , v11.8b   //p0+q0+q1 H\n    bic       v14.16b, v14.16b , v22.16b //final condn for p's\n    movi      v28.16b, #2\n    bif       v6.16b, v24.16b , v22.16b //final p0\n    bit       v2.16b, v16.16b , v14.16b //final p2\n    bif       v20.16b, v4.16b , v14.16b //final p1\n    mov       v7.d[0] , v6.d[1]\n    mov       v3.d[0] , v2.d[1]\n    mov       v21.d[0] , v20.d[1]\n    uaddl     v24.8h, v8.8b, v4.8b      //q0+p1 L\n    umlal     v24.8h, v10.8b, v28.8b    //X2(q1) + q0 + p1 L\n    uaddl     v16.8h, v9.8b, v5.8b      //q0+p1 H\n    umlal     v16.8h, v11.8b, v28.8b    //X2(q1) + q0 + p1 H\n    movi      v28.8h, #2\n    uaddl     v14.8h, v4.8b, v12.8b     //p1+q2 L\n    mla       v14.8h, v18.8h , v28.8h   //p1 + X2(p0) + X2(q0) + X2(q1) + q2L\n    uaddl     v4.8h, v5.8b, v13.8b      //p1+q2H\n    mla       v4.8h, v26.8h , v28.8h    //p1 + X2(p0) + X2(q0) + X2(q1) + q2H\n    rshrn     v24.8b, v24.8h, #2        //(X2(q1) + q0 + p1 + 2) >> 2; L q0'\n    rshrn     v25.8b, v16.8h, #2        //(X2(q1) + q0 + p1 + 2) >> 2; H q0'\n    mov       v24.d[1] , v25.d[0]\n    uaddw     v18.8h, v18.8h , v12.8b   //p0 + q0 + q1 + q2 L\n    uaddw     v26.8h, v26.8h , v13.8b   //p0 + q0 + q1 + q2 H\n    rshrn     v16.8b, v14.8h, #3        //(p1 + X2(p0) + X2(q0) + X2(q1) + q2 + 4) >> 3 L qo\"\n    mov       v14.16b, v31.16b\n    rshrn     v17.8b, v4.8h, #3         //(p1 + X2(p0) + X2(q0) + X2(q1) + q2 + 4) >> 3 H qo\"\n    mov       v16.d[1] , v17.d[0]\n    rshrn     v4.8b, v18.8h, #2         //p0 + q0 + q1 + q2 + 2)>>2 L q1'\n    rshrn     v5.8b, v26.8h, #2         //p0 + q0 + q1 + q2 + 2)>>2 H q1'\n    mov       v4.d[1] , v5.d[0]\n    bit       v24.16b, v16.16b , v30.16b //q0' or q0\"\n    bic       v30.16b, v30.16b , v22.16b //final condn for q's\n    trn1      v31.8b, v0.8b, v2.8b\n    trn2      v2.8b, v0.8b, v2.8b       //row1 &2\n    mov       v0.8b, v31.8b\n    bit       v10.16b, v4.16b , v30.16b\n    mov       v11.d[0] , v10.d[1]\n    mov       v25.d[0] , v24.d[1]\n    mov       v31.d[0] , v30.d[1]\n    trn1      v31.8b, v1.8b, v3.8b\n    trn2      v3.8b, v1.8b, v3.8b       //row9 &10\n    mov       v1.8b, v31.8b\n    uaddl     v16.8h, v12.8b, v14.8b    //q2+q3 L\n    trn1      v31.8b, v20.8b, v6.8b\n    trn2      v6.8b, v20.8b, v6.8b      //row3&row4\n    mov       v20.8b , v31.8b\n    uaddl     v4.8h, v13.8b, v15.8b     //q2+q3 H\n    trn1      v31.8b, v21.8b, v7.8b\n    trn2      v7.8b, v21.8b, v7.8b      //row11 & 12\n    mov       v21.8b , v31.8b\n    mla       v18.8h, v16.8h , v28.8h   //X2(q3) + X3(q2) + q1 + q0 + p0 L\n    trn1      v31.4h, v2.4h, v6.4h\n    trn2      v6.4h, v2.4h, v6.4h       //row2 & row4\n    mov       v2.8b, v31.8b\n    mla       v26.8h, v4.8h , v28.8h    //X2(q3) + X3(q2) + q1 + q0 + p0 H\n    trn1      v31.4h, v3.4h, v7.4h\n    trn2      v7.4h, v3.4h, v7.4h       //row10 & 12\n    mov       v3.8b , v31.8b\n    bif       v8.16b, v24.16b , v22.16b //final q0\n    mov       v9.d[0] , v8.d[1]\n    trn1      v31.4h, v0.4h, v20.4h\n    trn2      v20.4h, v0.4h, v20.4h     //row1 & 3\n    mov       v0.8b , v31.8b\n    rshrn     v18.8b, v18.8h, #3        //(X2(q3) + X3(q2) + q1 + q0 + p0 + 4) >> 3; L\n    trn1      v31.4h, v1.4h, v21.4h\n    trn2      v21.4h, v1.4h, v21.4h     //row9 & row11\n    mov       v1.8b, v31.8b\n    rshrn     v19.8b, v26.8h, #3        //(X2(q3) + X3(q2) + q1 + q0 + p0 + 4) >> 3; H\n    mov       v18.d[1] , v19.d[0]\n    trn1      v31.8b, v8.8b, v10.8b\n    trn2      v10.8b, v8.8b, v10.8b     //row5&6\n    mov       v8.8b, v31.8b\n    bit       v12.16b, v18.16b , v30.16b //final q2\n    mov       v13.d[0] , v12.d[1]\n    trn1      v31.8b, v9.8b, v11.8b\n    trn2      v11.8b, v9.8b, v11.8b     //row13 &14\n    mov       v9.8b, v31.8b\n    trn1      v31.8b, v12.8b, v14.8b\n    trn2      v14.8b, v12.8b, v14.8b    //row7 & 8\n    mov       v12.8b, v31.8b\n    trn1      v31.8b, v13.8b, v15.8b\n    trn2      v15.8b, v13.8b, v15.8b    //row15 & 16\n    mov       v13.8b , v31.8b\n    trn1      v31.4h, v10.4h, v14.4h\n    trn2      v14.4h, v10.4h, v14.4h    //row6 & row8\n    mov       v10.8b, v31.8b\n    trn1      v31.4h, v11.4h, v15.4h\n    trn2      v15.4h, v11.4h, v15.4h    //row14 & row16\n    mov       v11.8b, v31.8b\n    //now Q3 ->p0 and Q7->q3\n    trn1      v31.4h, v8.4h, v12.4h\n    trn2      v12.4h, v8.4h, v12.4h     //row 5 & 7\n    mov       v8.8b, v31.8b\n    trn1      v31.4h, v9.4h, v13.4h\n    trn2      v13.4h, v9.4h, v13.4h     //row13 & row15\n    mov       v9.8b, v31.8b\n    sub       x0, x0, x1, lsl#4         //restore pointer\n    trn1      v31.2s, v6.2s, v14.2s\n    trn2      v14.2s, v6.2s, v14.2s     //row4 & 8\n    mov       v6.8b , v31.8b\n    trn1      v31.2s, v7.2s, v15.2s\n    trn2      v15.2s, v7.2s, v15.2s     //row 12 & 16\n    mov       v7.8b, v31.8b\n    trn1      v31.2s, v0.2s, v8.2s\n    trn2      v8.2s, v0.2s, v8.2s       //row1 & row5\n    mov       v0.8b , v31.8b\n    trn1      v31.2s, v1.2s, v9.2s\n    trn2      v9.2s, v1.2s, v9.2s       //row9 & 13\n    mov       v1.8b , v31.8b\n    trn1      v31.2s, v2.2s, v10.2s\n    trn2      v10.2s, v2.2s, v10.2s     //row2 &6\n    mov       v2.8b , v31.8b\n    trn1      v31.2s, v3.2s, v11.2s\n    trn2      v11.2s, v3.2s, v11.2s     //row10&row14\n    mov       v3.8b , v31.8b\n    trn1      v31.2s, v20.2s, v12.2s\n    trn2      v12.2s, v20.2s, v12.2s    //row3 & 7\n    mov       v20.8b , v31.8b\n    trn1      v31.2s, v21.2s, v13.2s\n    trn2      v13.2s, v21.2s, v13.2s    //row11 & row15\n    mov       v21.8b, v31.8b\n    st1       {v0.8b}, [x0], x1         //row1\n    st1       {v2.8b}, [x0], x1         //row2\n    st1       {v20.8b}, [x0], x1        //row3\n    st1       {v6.8b}, [x0], x1         //row4\n    st1       {v8.8b}, [x0], x1         //row5\n    st1       {v10.8b}, [x0], x1        //row6\n    st1       {v12.8b}, [x0], x1        //row7\n    st1       {v14.8b}, [x0], x1        //row8\n    st1       {v1.8b}, [x0], x1         //row9\n    st1       {v3.8b}, [x0], x1         //row10\n    st1       {v21.8b}, [x0], x1        //row11\n    st1       {v7.8b}, [x0], x1         //row12\n    st1       {v9.8b}, [x0], x1         //row13\n    st1       {v11.8b}, [x0], x1        //row14\n    st1       {v13.8b}, [x0], x1        //row15\n    st1       {v15.8b}, [x0], x1        //row16\n\n    // LDMFD sp!,{x12,pc}\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_default_weighted_pred_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_default_weighted_pred_av8.s\n//*\n//* @brief\n//*  Contains function definitions for default weighted prediction.\n//*\n//* @author\n//*  Kaushik Senthoor R\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_default_weighted_pred_luma_av8()\n//*  - ih264_default_weighted_pred_chroma_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//*******************************************************************************\n//* @function\n//*  ih264_default_weighted_pred_luma_av8()\n//*\n//* @brief\n//*  This routine performs the default weighted prediction as described in sec\n//* 8.4.2.3.1 titled \"Default weighted sample prediction process\" for luma.\n//*\n//* @par Description:\n//*  This function gets two ht x wd blocks, calculates their rounded-average and\n//* stores it in the destination block.\n//*\n//* @param[in] puc_src1:\n//*  UWORD8 Pointer to the buffer containing the first input block.\n//*\n//* @param[in] puc_src2:\n//*  UWORD8 Pointer to the buffer containing the second input block.\n//*\n//* @param[out] puc_dst\n//*  UWORD8 pointer to the destination where the output block is stored.\n//*\n//* @param[in] src_strd1\n//*  Stride of the first input buffer\n//*\n//* @param[in] src_strd2\n//*  Stride of the second input buffer\n//*\n//* @param[in] dst_strd\n//*  Stride of the destination buffer\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  (ht,wd) can be (4,4), (4,8), (8,4), (8,8), (8,16), (16,8) or (16,16).\n//*\n//*******************************************************************************\n//*/\n//void ih264_default_weighted_pred_luma_av8(UWORD8 *puc_src1,\n//                                          UWORD8 *puc_src2,\n//                                          UWORD8 *puc_dst,\n//                                          WORD32 src_strd1,\n//                                          WORD32 src_strd2,\n//                                          WORD32 dst_strd,\n//                                          WORD32 ht,\n//                                          WORD32 wd)\n//\n//**************Variables Vs Registers*****************************************\n//    x0      => puc_src1\n//    x1      => puc_src2\n//    x2      => puc_dst\n//    w3      => src_strd1\n//    w4      => src_strd2\n//    w5      => dst_strd\n//    w6      => ht\n//    w7      => wd\n//\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_default_weighted_pred_luma_av8\n\nih264_default_weighted_pred_luma_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n    cmp       w7, #16\n    beq       loop_16                   //branch if wd is 16\n    cmp       w7, #8\n    beq       loop_8                    //branch if wd is 8\n\nloop_4:                                 //each iteration processes four rows\n\n    ld1       {v0.s}[0], [x0], x3       //load row 1 in source 1\n    ld1       {v0.s}[1], [x0], x3       //load row 2 in source 1\n    ld1       {v2.s}[0], [x1], x4       //load row 1 in source 2\n    ld1       {v2.s}[1], [x1], x4       //load row 2 in source 2\n    ld1       {v1.s}[0], [x0], x3       //load row 3 in source 1\n    ld1       {v1.s}[1], [x0], x3       //load row 4 in source 1\n    urhadd    v0.8b, v0.8b , v2.8b\n    ld1       {v3.s}[0], [x1], x4       //load row 3 in source 2\n    ld1       {v3.s}[1], [x1], x4       //load row 4 in source 2\n    subs      w6, w6, #4                //decrement ht by 4\n    st1       {v0.s}[0], [x2], x5       //load row 1 in destination\n    st1       {v0.s}[1], [x2], x5       //load row 2 in destination\n    urhadd    v1.8b, v1.8b , v3.8b\n    st1       {v1.s}[0], [x2], x5       //load row 3 in destination\n    st1       {v1.s}[1], [x2], x5       //load row 4 in destination\n    bgt       loop_4                    //if greater than 0 repeat the loop again\n    b         end_loops\n\nloop_8:                                 //each iteration processes four rows\n\n    ld1       {v0.8b}, [x0], x3         //load row 1 in source 1\n    ld1       {v4.8b}, [x1], x4         //load row 1 in source 2\n    ld1       {v1.8b}, [x0], x3         //load row 2 in source 1\n    ld1       {v5.8b}, [x1], x4         //load row 2 in source 2\n    ld1       {v2.8b}, [x0], x3         //load row 3 in source 1\n    urhadd    v0.16b, v0.16b , v4.16b\n    urhadd    v1.16b, v1.16b , v5.16b\n    ld1       {v6.8b}, [x1], x4         //load row 3 in source 2\n    ld1       {v3.8b}, [x0], x3         //load row 4 in source 1\n    urhadd    v2.8b, v2.8b , v6.8b\n    ld1       {v7.8b}, [x1], x4         //load row 4 in source 2\n    subs      w6, w6, #4                //decrement ht by 4\n    st1       {v0.8b}, [x2], x5         //load row 1 in destination\n    urhadd    v3.8b, v3.8b , v7.8b\n    st1       {v1.8b}, [x2], x5         //load row 2 in destination\n    st1       {v2.8b}, [x2], x5         //load row 3 in destination\n    st1       {v3.8b}, [x2], x5         //load row 4 in destination\n    bgt       loop_8                    //if greater than 0 repeat the loop again\n    b         end_loops\n\nloop_16:                                //each iteration processes eight rows\n\n    ld1       {v0.8b, v1.8b}, [x0], x3  //load row 1 in source 1\n    ld1       {v16.8b, v17.8b}, [x1], x4 //load row 1 in source 2\n    ld1       {v2.8b, v3.8b}, [x0], x3  //load row 2 in source 1\n    ld1       {v18.8b, v19.8b}, [x1], x4 //load row 2 in source 2\n    urhadd    v0.16b, v0.16b , v16.16b\n    urhadd    v1.16b, v1.16b , v17.16b\n    ld1       {v4.8b, v5.8b}, [x0], x3  //load row 3 in source 1\n    ld1       {v20.8b, v21.8b}, [x1], x4 //load row 3 in source 2\n    urhadd    v2.16b, v2.16b , v18.16b\n    urhadd    v3.16b, v3.16b , v19.16b\n    ld1       {v6.8b, v7.8b}, [x0], x3  //load row 4 in source 1\n    ld1       {v22.8b, v23.8b}, [x1], x4 //load row 4 in source 2\n    urhadd    v4.16b, v4.16b , v20.16b\n    urhadd    v5.16b, v5.16b , v21.16b\n    ld1       {v8.8b, v9.8b}, [x0], x3  //load row 5 in source 1\n    ld1       {v24.8b, v25.8b}, [x1], x4 //load row 5 in source 2\n    urhadd    v6.16b, v6.16b , v22.16b\n    urhadd    v7.16b, v7.16b , v23.16b\n    ld1       {v10.8b, v11.8b}, [x0], x3 //load row 6 in source 1\n    ld1       {v26.8b, v27.8b}, [x1], x4 //load row 6 in source 2\n    urhadd    v8.16b, v8.16b , v24.16b\n    urhadd    v9.16b, v9.16b , v25.16b\n    ld1       {v12.8b, v13.8b}, [x0], x3 //load row 7 in source 1\n    ld1       {v28.8b, v29.8b}, [x1], x4 //load row 7 in source 2\n    urhadd    v10.16b, v10.16b , v26.16b\n    urhadd    v11.16b, v11.16b , v27.16b\n    ld1       {v14.8b, v15.8b}, [x0], x3 //load row 8 in source 1\n    ld1       {v30.8b, v31.8b}, [x1], x4 //load row 8 in source 2\n    urhadd    v12.16b, v12.16b , v28.16b\n    urhadd    v13.16b, v13.16b , v29.16b\n    st1       {v0.8b, v1.8b}, [x2], x5  //load row 1 in destination\n    st1       {v2.8b, v3.8b}, [x2], x5  //load row 2 in destination\n    urhadd    v14.16b, v14.16b , v30.16b\n    urhadd    v15.16b, v15.16b , v31.16b\n    st1       {v4.8b, v5.8b}, [x2], x5  //load row 3 in destination\n    st1       {v6.8b, v7.8b}, [x2], x5  //load row 4 in destination\n    subs      w6, w6, #8                //decrement ht by 8\n    st1       {v8.8b, v9.8b}, [x2], x5  //load row 5 in destination\n    st1       {v10.8b, v11.8b}, [x2], x5 //load row 6 in destination\n    st1       {v12.8b, v13.8b}, [x2], x5 //load row 7 in destination\n    st1       {v14.8b, v15.8b}, [x2], x5 //load row 8 in destination\n    bgt       loop_16                   //if greater than 0 repeat the loop again\n\nend_loops:\n\n    // LDMFD sp!,{x4-x7,x15}                      //Reload the registers from sp\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n//*******************************************************************************\n//* @function\n//*  ih264_default_weighted_pred_chroma_av8()\n//*\n//* @brief\n//*  This routine performs the default weighted prediction as described in sec\n//* 8.4.2.3.1 titled \"Default weighted sample prediction process\" for chroma.\n//*\n//* @par Description:\n//*  This function gets two ht x wd blocks, calculates their rounded-average and\n//* stores it in the destination block for U and V.\n//*\n//* @param[in] puc_src1:\n//*  UWORD8 Pointer to the buffer containing the first input block.\n//*\n//* @param[in] puc_src2:\n//*  UWORD8 Pointer to the buffer containing the second input block.\n//*\n//* @param[out] puc_dst\n//*  UWORD8 pointer to the destination where the output block is stored.\n//*\n//* @param[in] src_strd1\n//*  Stride of the first input buffer\n//*\n//* @param[in] src_strd2\n//*  Stride of the second input buffer\n//*\n//* @param[in] dst_strd\n//*  Stride of the destination buffer\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  (ht,wd) can be (2,2), (2,4), (4,2), (4,4), (4,8), (8,4) or (8,8).\n//*\n//*******************************************************************************\n//*/\n//void ih264_default_weighted_pred_chroma_av8(UWORD8 *puc_src1,\n//                                            UWORD8 *puc_src2,\n//                                            UWORD8 *puc_dst,\n//                                            WORD32 src_strd1,\n//                                            WORD32 src_strd2,\n//                                            WORD32 dst_strd,\n//                                            WORD32 ht,\n//                                            WORD32 wd)\n//\n//**************Variables Vs Registers*****************************************\n//    x0      => puc_src1\n//    x1      => puc_src2\n//    x2      => puc_dst\n//    w3      => src_strd1\n//    w4      => src_strd2\n//    w5      => dst_strd\n//    w6      => ht\n//    w7      => wd\n//\n\n\n\n\n    .global ih264_default_weighted_pred_chroma_av8\n\nih264_default_weighted_pred_chroma_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n    cmp       w7, #8\n    beq       loop_8_uv                 //branch if wd is 8\n    cmp       w7, #4\n    beq       loop_4_uv                 //branch if wd is 4\n\nloop_2_uv:                              //each iteration processes two rows\n\n    ld1       {v0.s}[0], [x0], x3       //load row 1 in source 1\n    ld1       {v0.s}[1], [x0], x3       //load row 2 in source 1\n    ld1       {v1.s}[0], [x1], x4       //load row 1 in source 2\n    ld1       {v1.s}[1], [x1], x4       //load row 2 in source 2\n    urhadd    v0.8b, v0.8b , v1.8b\n    subs      w6, w6, #2                //decrement ht by 2\n    st1       {v0.s}[0], [x2], x5       //load row 1 in destination\n    st1       {v0.s}[1], [x2], x5       //load row 2 in destination\n    bgt       loop_2_uv                 //if greater than 0 repeat the loop again\n    b         end_loops_uv\n\nloop_4_uv:                              //each iteration processes two rows\n\n    ld1       {v0.8b}, [x0], x3         //load row 1 in source 1\n    ld1       {v2.8b}, [x1], x4         //load row 1 in source 2\n    ld1       {v1.8b}, [x0], x3         //load row 2 in source 1\n    urhadd    v0.8b, v0.8b , v2.8b\n    ld1       {v3.8b}, [x1], x4         //load row 2 in source 2\n    urhadd    v1.8b, v1.8b , v3.8b\n    st1       {v0.8b}, [x2], x5         //load row 1 in destination\n    subs      w6, w6, #2                //decrement ht by 2\n    st1       {v1.8b}, [x2], x5         //load row 2 in destination\n    bgt       loop_4_uv                 //if greater than 0 repeat the loop again\n    b         end_loops_uv\n\nloop_8_uv:                              //each iteration processes four rows\n\n    ld1       {v0.8b, v1.8b}, [x0], x3  //load row 1 in source 1\n    ld1       {v8.8b, v9.8b}, [x1], x4  //load row 1 in source 2\n    ld1       {v2.8b, v3.8b}, [x0], x3  //load row 2 in source 1\n    urhadd    v0.16b, v0.16b , v8.16b\n    urhadd    v1.16b, v1.16b , v9.16b\n    ld1       {v10.8b, v11.8b}, [x1], x4 //load row 2 in source 2\n    ld1       {v4.8b, v5.8b}, [x0], x3  //load row 3 in source 1\n    urhadd    v2.16b, v2.16b , v10.16b\n    urhadd    v3.16b, v3.16b , v11.16b\n    ld1       {v12.8b, v13.8b}, [x1], x4 //load row 3 in source 2\n    ld1       {v6.8b, v7.8b}, [x0], x3  //load row 4 in source 1\n    urhadd    v4.16b, v4.16b , v12.16b\n    urhadd    v5.16b, v5.16b , v13.16b\n    ld1       {v14.8b, v15.8b}, [x1], x4 //load row 4 in source 2\n    st1       {v0.8b, v1.8b}, [x2], x5  //load row 1 in destination\n    urhadd    v6.16b, v6.16b , v14.16b\n    urhadd    v7.16b, v7.16b , v15.16b\n    st1       {v2.8b, v3.8b}, [x2], x5  //load row 2 in destination\n    subs      w6, w6, #4                //decrement ht by 4\n    st1       {v4.8b, v5.8b}, [x2], x5  //load row 3 in destination\n    st1       {v6.8b, v7.8b}, [x2], x5  //load row 4 in destination\n    bgt       loop_8_uv                 //if greater than 0 repeat the loop again\n\nend_loops_uv:\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_ihadamard_scaling_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n// *******************************************************************************\n// * @file\n// *  ih264_ihadamard_scaling_av8.s\n// *\n// * @brief\n// *  Contains function definitions for inverse hadamard transform on 4x4 DC outputs\n// *  of 16x16 intra-prediction\n// *\n// * @author\n// *  Mohit\n// *\n// * @par List of Functions:\n// *  - ih264_ihadamard_scaling_4x4_av8()\n// *\n// * @remarks\n// *  None\n// *\n.include \"ih264_neon_macros.s\"\n\n// *******************************************************************************\n// */\n// * @brief This function performs a 4x4 inverse hadamard transform on the 4x4 DC coefficients\n// * of a 16x16 intra prediction macroblock, and then performs scaling.\n// * prediction buffer\n// *\n// * @par Description:\n// *  The DC coefficients pass through a 2-stage inverse hadamard transform.\n// *  This inverse transformed content is scaled to based on Qp value.\n// *\n// * @param[in] pi2_src\n// *  input 4x4 block of DC coefficients\n// *\n// * @param[out] pi2_out\n// *  output 4x4 block\n// *\n// * @param[in] pu2_iscal_mat\n// *  pointer to scaling list\n// *\n// * @param[in] pu2_weigh_mat\n// *  pointer to weight matrix\n// *\n// * @param[in] u4_qp_div_6\n// *  Floor (qp/6)\n// *\n// * @param[in] pi4_tmp\n// * temporary buffer of size 1*16\n// *\n// * @returns none\n// *\n// * @remarks none\n// *\n// *******************************************************************************\n// */\n// *\n// *******************************************************************************\n// */\n// void ih264_ihadamard_scaling_4x4(word16* pi2_src,\n//        word16* pi2_out,\n//        const uword16 *pu2_iscal_mat,\n//        const uword16 *pu2_weigh_mat,\n//        uword32 u4_qp_div_6,\n//        word32* pi4_tmp)\n//**************variables vs registers*****************************************\n//x0 => *pi2_src\n//x1 => *pi2_out\n//x2 => *pu2_iscal_mat\n//x3 => *pu2_weigh_mat\n//x4=>   u4_qp_div_6\n\n.text\n.p2align 2\n\n    .global ih264_ihadamard_scaling_4x4_av8\nih264_ihadamard_scaling_4x4_av8:\n\n//only one shift is done in horizontal inverse because,\n//if u4_qp_div_6 is lesser than 4 then shift value will be neagative and do negative left shift, in this case rnd_factor has value\n//if u4_qp_div_6 is greater than 4 then shift value will be positive and do left shift, here rnd_factor is 0\n    push_v_regs\n\n//=======================inverse hadamard transform================================\n\n    ld4       {v0.4h-v3.4h}, [x0]       //load x4,x5,x6,x7\n\n    dup       v14.4s, w4                // populate the u4_qp_div_6\n    ld1       {v15.h}[0], [x3]          // pu2_weigh_mat\n    ld1       {v16.h}[0], [x2]          //pu2_iscal_mat\n\n    saddl     v4.4s, v0.4h, v3.4h       //x0 = x4 + x7\n    saddl     v5.4s, v1.4h, v2.4h       //x1 = x5 + x6\n    ssubl     v6.4s, v1.4h, v2.4h       //x2 = x5 - x6\n    ssubl     v7.4s, v0.4h, v3.4h       //x3 = x4 - x7\n\n    add       v0.4s, v4.4s, v5.4s       //pi4_tmp_ptr[0] = x0 + x1\n    add       v1.4s, v7.4s, v6.4s       //pi4_tmp_ptr[1] = x3 + x2\n    sub       v2.4s, v4.4s, v5.4s       //pi4_tmp_ptr[2] = x0 - x1\n    sub       v3.4s, v7.4s, v6.4s       //pi4_tmp_ptr[3] = x3 - x2\n\n    umull     v15.4s, v15.4h, v16.4h\n    dup       v15.4s, v15.s[0]          //pu2_weigh_mat[0]*pu2_iscal_mat[0]\n\n    //transpose\n    trn1      v4.4s, v0.4s, v1.4s\n    trn2      v5.4s, v0.4s, v1.4s\n    trn1      v6.4s, v2.4s, v3.4s\n    trn2      v7.4s, v2.4s, v3.4s\n\n    trn1      v0.2d, v4.2d, v6.2d\n    trn2      v2.2d, v4.2d, v6.2d\n    trn1      v1.2d, v5.2d, v7.2d\n    trn2      v3.2d, v5.2d, v7.2d\n    //end transpose\n\n    add       v4.4s, v0.4s, v3.4s       //x0 = x4+x7\n    add       v5.4s, v1.4s, v2.4s       //x1 = x5+x6\n    sub       v6.4s, v1.4s, v2.4s       //x2 = x5-x6\n    sub       v7.4s, v0.4s, v3.4s       //x3 = x4-x7\n\n    add       v0.4s, v4.4s, v5.4s       //pi4_tmp_ptr[0] = x0 + x1\n    add       v1.4s, v7.4s, v6.4s       //pi4_tmp_ptr[1] = x3 + x2\n    sub       v2.4s, v4.4s, v5.4s       //pi4_tmp_ptr[2] = x0 - x1\n    sub       v3.4s, v7.4s, v6.4s       //pi4_tmp_ptr[3] = x3 - x2\n\n    mul       v0.4s, v0.4s, v15.4s      // q0  = p[i] = (x[i] * trns_coeff[i]) where i = 0..3\n    mul       v1.4s, v1.4s, v15.4s      // q1  = p[i] = (x[i] * trns_coeff[i]) where i = 4..7\n    mul       v2.4s, v2.4s, v15.4s      // q2  = p[i] = (x[i] * trns_coeff[i]) where i = 8..11\n    mul       v3.4s, v3.4s, v15.4s      // q3  = p[i] = (x[i] * trns_coeff[i]) where i = 12..15\n\n    sshl      v0.4s, v0.4s, v14.4s      // q0  = q[i] = (p[i] << (qp/6)) where i = 0..3\n    sshl      v1.4s, v1.4s, v14.4s      // q1  = q[i] = (p[i] << (qp/6)) where i = 4..7\n    sshl      v2.4s, v2.4s, v14.4s      // q2  = q[i] = (p[i] << (qp/6)) where i = 8..11\n    sshl      v3.4s, v3.4s, v14.4s      // q3  = q[i] = (p[i] << (qp/6)) where i = 12..15\n\n    sqrshrn   v0.4h, v0.4s, #6          // d0  = c[i] = ((q[i] + 32) >> 4) where i = 0..3\n    sqrshrn   v1.4h, v1.4s, #6          // d1  = c[i] = ((q[i] + 32) >> 4) where i = 4..7\n    sqrshrn   v2.4h, v2.4s, #6          // d2  = c[i] = ((q[i] + 32) >> 4) where i = 8..11\n    sqrshrn   v3.4h, v3.4s, #6          // d3  = c[i] = ((q[i] + 32) >> 4) where i = 12..15\n\n    st1       {v0.4h-v3.4h}, [x1]       //store the result\n\n    pop_v_regs\n    ret\n\n\n// *******************************************************************************\n// */\n// * @brief This function performs a 2x2 inverse hadamard transform for chroma block\n// *\n// * @par Description:\n// *  The DC coefficients pass through a 2-stage inverse hadamard transform.\n// *  This inverse transformed content is scaled to based on Qp value.\n// *  Both DC blocks of U and v blocks are processesd\n// *\n// * @param[in] pi2_src\n// *  input 1x8 block of ceffs. First 4 are from U and next from V\n// *\n// * @param[out] pi2_out\n// *  output 1x8 block\n// *\n// * @param[in] pu2_iscal_mat\n// *  pointer to scaling list\n// *\n// * @param[in] pu2_weigh_mat\n// *  pointer to weight matrix\n// *\n// * @param[in] u4_qp_div_6\n// *  Floor (qp/6)\n// *\n// * @returns none\n// *\n// * @remarks none\n// *\n// *******************************************************************************\n// */\n// *\n// *******************************************************************************\n// */\n// void ih264_ihadamard_scaling_2x2_uv(WORD16* pi2_src,\n//                                  WORD16* pi2_out,\n//                                  const UWORD16 *pu2_iscal_mat,\n//                                  const UWORD16 *pu2_weigh_mat,\n//                                  UWORD32 u4_qp_div_6,\n\n    .global ih264_ihadamard_scaling_2x2_uv_av8\nih264_ihadamard_scaling_2x2_uv_av8:\n\n//Registers used\n//   x0 : *pi2_src\n//   x1 : *pi2_out\n//   x2 : *pu2_iscal_mat\n//   x3 : *pu2_weigh_mat\n//   x4 : u4_qp_div_6\n    push_v_regs\n    ld1       {v26.h}[0], [x2]\n    ld1       {v27.h}[0], [x3]\n\n    sub       w4, w4, #5                //qp/6 - 4\n    dup       v28.4s, w4                //load qp/6\n\n    ld2       {v0.4h, v1.4h}, [x0]      //load 8 dc coeffs\n                                        //i2_x4,i2_x6,i2_y4,i1_y6 -> d0\n                                        //i2_x5,i2_x7,i2_y5,i1_y6 -> d1\n\n    saddl     v2.4s, v0.4h, v1.4h       //i4_x0 = i4_x4 + i4_x5;...x2\n    ssubl     v4.4s, v0.4h, v1.4h       //i4_x1 = i4_x4 - i4_x5;...x3\n\n    umull     v30.4s, v26.4h, v27.4h    //pu2_iscal_mat[0]*pu2_weigh_mat[0]\n    dup       v30.4s, v30.s[0]\n\n    trn1      v0.4s, v2.4s, v4.4s\n    trn2      v1.4s, v2.4s, v4.4s       //i4_x0 i4_x1 -> q1\n\n    add       v2.4s, v0.4s, v1.4s       //i4_x4 = i4_x0+i4_x2;.. i4_x5\n    sub       v3.4s, v0.4s, v1.4s       //i4_x6 = i4_x0-i4_x2;.. i4_x7\n\n    mul       v2.4s, v2.4s, v30.4s\n    mul       v3.4s, v3.4s, v30.4s\n\n    sshl      v2.4s, v2.4s, v28.4s\n    sshl      v3.4s, v3.4s, v28.4s\n\n    xtn       v0.4h, v2.4s              //i4_x4 i4_x5 i4_y4 i4_y5\n    xtn       v1.4h, v3.4s              //i4_x6 i4_x7 i4_y6 i4_y7\n\n    st2       {v0.4s-v1.4s}, [x1]\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_inter_pred_chroma_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_inter_pred_chroma_av8.s\n//*\n//* @brief\n//*  Contains function definitions for inter prediction  interpolation.\n//*\n//* @author\n//*  Ittaim\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_inter_pred_chroma_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_inter_pred_filters.c\n//\n\n///**\n///**\n///**\n//\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*    Interprediction chroma filter\n//*\n//* @par Description:\n//*   Applies filtering to chroma samples as mentioned in\n//*    sec 8.4.2.2.2 titled \"chroma sample interpolation process\"\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source containing alternate U and V samples\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in]uc_dx\n//*  dx value where the sample is to be produced(refer sec 8.4.2.2.2 )\n//*\n//* @param[in] uc_dy\n//*  dy value where the sample is to be produced(refer sec 8.4.2.2.2 )\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n//void ih264_inter_pred_chroma(UWORD8 *pu1_src,\n//                             UWORD8 *pu1_dst,\n//                             WORD32 src_strd,\n//                             WORD32 dst_strd,\n//                             WORD32 u1_dx,\n//                             WORD32 u1_dy,\n//                             WORD32 ht,\n//                             WORD32 wd)\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  u1_dx\n//    w5 =>  u1_dy\n//    w6 =>  height\n//    w7 =>  width\n//\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_inter_pred_chroma_av8\n\nih264_inter_pred_chroma_av8:\n\n\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x2, w2\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n    sxtw      x6, w6\n    sxtw      x7, w7\n\n\n\n\n\n    sub       x20, x4, #8               //8-u1_dx\n    neg       x8, x20\n    sub       x20, x5, #8               //8-u1_dy\n    neg       x9, x20\n    mul       x10, x8, x9               //\n    mul       x11, x4, x9               //\n\n    dup       v28.8b, w10\n    dup       v29.8b, w11\n\n    mul       x10, x8, x5               //\n    mul       x11, x4, x5               //\n\n    dup       v30.8b, w10\n    dup       v31.8b, w11\n\n    subs      x12, x7, #2               //if wd=4 branch to loop_4\n    beq       loop_2\n    subs      x12, x7, #4               //if wd=8 branch to loop_8\n    beq       loop_4\n\nloop_8:\n    ld1       {v0.8b, v1.8b, v2.8b}, [x0], x2 //// Load row0 ;\n    ext       v3.8b, v0.8b , v1.8b , #2\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row1;\n    umull     v20.8h, v0.8b, v28.8b\n    ext       v8.8b, v5.8b , v6.8b , #2\n    umlal     v20.8h, v3.8b, v29.8b\n    ext       v9.8b, v6.8b , v7.8b , #2\n    umlal     v20.8h, v5.8b, v30.8b\n    ext       v4.8b, v1.8b , v2.8b , #2\n    umlal     v20.8h, v8.8b, v31.8b\n    sqrshrun  v26.8b, v20.8h, #6\n    umull     v22.8h, v1.8b, v28.8b\n    ld1       {v10.8b, v11.8b, v12.8b}, [x0], x2 //// Load row2 ;\n    umlal     v22.8h, v4.8b, v29.8b\n    ext       v13.8b, v10.8b , v11.8b , #2\n    umlal     v22.8h, v6.8b, v30.8b\n    ext       v14.8b, v11.8b , v12.8b , #2\n    umlal     v22.8h, v9.8b, v31.8b\n    sqrshrun  v27.8b, v22.8h, #6\n    umull     v24.8h, v5.8b, v28.8b\n    st1       { v26.8b, v27.8b}, [x1], x3 ////Store dest row\n    umlal     v24.8h, v8.8b, v29.8b\n    ld1       {v0.8b, v1.8b, v2.8b}, [x0], x2 //// Load row3 ;\n    umlal     v24.8h, v10.8b, v30.8b\n    ext       v3.8b, v0.8b , v1.8b , #2\n    umlal     v24.8h, v13.8b, v31.8b\n    ext       v4.8b, v1.8b , v2.8b , #2\n    umull     v16.8h, v6.8b, v28.8b\n    sqrshrun  v18.8b, v24.8h, #6\n    umlal     v16.8h, v9.8b, v29.8b\n    umlal     v16.8h, v11.8b, v30.8b\n    umlal     v16.8h, v14.8b, v31.8b\n    sqrshrun  v19.8b, v16.8h, #6\n    st1       {v18.8b, v19.8b}, [x1], x3 // store row 1\n    umull     v20.8h, v10.8b, v28.8b\n    umlal     v20.8h, v13.8b, v29.8b\n    umlal     v20.8h, v0.8b, v30.8b\n    umlal     v20.8h, v3.8b, v31.8b\n    sqrshrun  v26.8b, v20.8h, #6\n    umull     v24.8h, v11.8b, v28.8b\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row4;\n    umlal     v24.8h, v14.8b, v29.8b\n    ext       v8.8b, v5.8b , v6.8b , #2\n    umlal     v24.8h, v1.8b, v30.8b\n    ext       v9.8b, v6.8b , v7.8b , #2\n    umlal     v24.8h, v4.8b, v31.8b\n    umull     v20.8h, v0.8b, v28.8b\n    sqrshrun  v27.8b, v24.8h, #6\n    umlal     v20.8h, v3.8b, v29.8b\n    st1       { v26.8b, v27.8b}, [x1], x3 ////Store dest row2\n    umlal     v20.8h, v5.8b, v30.8b\n    umlal     v20.8h, v8.8b, v31.8b\n    umull     v22.8h, v1.8b, v28.8b\n    umlal     v22.8h, v4.8b, v29.8b\n    umlal     v22.8h, v6.8b, v30.8b\n    sqrshrun  v26.8b, v20.8h, #6\n    umlal     v22.8h, v9.8b, v31.8b\n    subs      x12, x6, #4\n    sqrshrun  v27.8b, v22.8h, #6\n    st1       { v26.8b, v27.8b}, [x1], x3 ////Store dest row3\n\n    beq       end_func                  //If ht=4\n\n    ld1       {v10.8b, v11.8b, v12.8b}, [x0], x2 //// Load row5\n    ext       v13.8b, v10.8b , v11.8b , #2\n    umull     v24.8h, v5.8b, v28.8b\n    ext       v14.8b, v11.8b , v12.8b , #2\n    ld1       {v0.8b, v1.8b, v2.8b}, [x0], x2 //// Load row6;\n    umlal     v24.8h, v8.8b, v29.8b\n    umlal     v24.8h, v10.8b, v30.8b\n    umlal     v24.8h, v13.8b, v31.8b\n    ext       v3.8b, v0.8b , v1.8b , #2\n    umull     v16.8h, v6.8b, v28.8b\n    sqrshrun  v18.8b, v24.8h, #6\n    umlal     v16.8h, v9.8b, v29.8b\n    umlal     v16.8h, v11.8b, v30.8b\n    umlal     v16.8h, v14.8b, v31.8b\n    ext       v4.8b, v1.8b , v2.8b , #2\n    sqrshrun  v19.8b, v16.8h, #6\n    st1       { v18.8b, v19.8b}, [x1], x3 // store row 4\n    umull     v20.8h, v10.8b, v28.8b\n    umlal     v20.8h, v13.8b, v29.8b\n    umlal     v20.8h, v0.8b, v30.8b\n    umlal     v20.8h, v3.8b, v31.8b\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row7;\n    sqrshrun  v26.8b, v20.8h, #6\n    umull     v24.8h, v11.8b, v28.8b\n    umlal     v24.8h, v14.8b, v29.8b\n    ext       v8.8b, v5.8b , v6.8b , #2\n    umlal     v24.8h, v1.8b, v30.8b\n    umlal     v24.8h, v4.8b, v31.8b\n    ext       v9.8b, v6.8b , v7.8b , #2\n    sqrshrun  v27.8b, v24.8h, #6\n    st1       {v26.8b, v27.8b}, [x1], x3 ////Store dest row5\n    umull     v20.8h, v0.8b, v28.8b\n    umlal     v20.8h, v3.8b, v29.8b\n    umlal     v20.8h, v5.8b, v30.8b\n    umlal     v20.8h, v8.8b, v31.8b\n    ld1       {v10.8b, v11.8b, v12.8b}, [x0], x2 //// Load row8 ;\n    sqrshrun  v26.8b, v20.8h, #6\n    umull     v22.8h, v1.8b, v28.8b\n    umlal     v22.8h, v4.8b, v29.8b\n    umlal     v22.8h, v6.8b, v30.8b\n    ext       v13.8b, v10.8b , v11.8b , #2\n    umlal     v22.8h, v9.8b, v31.8b\n    ext       v14.8b, v11.8b , v12.8b , #2\n    sqrshrun  v27.8b, v22.8h, #6\n    st1       { v26.8b, v27.8b}, [x1], x3 ////Store dest row6\n    umull     v24.8h, v5.8b, v28.8b\n    umlal     v24.8h, v8.8b, v29.8b\n    umlal     v24.8h, v10.8b, v30.8b\n    umlal     v24.8h, v13.8b, v31.8b\n    umull     v16.8h, v6.8b, v28.8b\n    sqrshrun  v18.8b, v24.8h, #6\n    umlal     v16.8h, v9.8b, v29.8b\n    umlal     v16.8h, v11.8b, v30.8b\n    umlal     v16.8h, v14.8b, v31.8b\n    sqrshrun  v19.8b, v16.8h, #6\n    st1       { v18.8b, v19.8b}, [x1], x3 // store row 7\n    b         end_func\n\nloop_4:\n    ld1       {v0.8b, v1.8b}, [x0], x2  //// Load row0 ;\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ld1       {v3.8b, v4.8b}, [x0], x2  //// Load row1;\n    ext       v5.8b, v3.8b , v4.8b , #2\n    umull     v20.8h, v0.8b, v28.8b\n    umlal     v20.8h, v2.8b, v29.8b\n    umlal     v20.8h, v3.8b, v30.8b\n    umlal     v20.8h, v5.8b, v31.8b\n    ld1       {v6.8b, v7.8b}, [x0], x2  //// Load row2\n    sqrshrun  v26.8b, v20.8h, #6\n    ext       v8.8b, v6.8b , v7.8b , #2\n    st1       {v26.8b}, [x1], x3        ////Store dest row0\n    umull     v22.8h, v3.8b, v28.8b\n    umlal     v22.8h, v5.8b, v29.8b\n    umlal     v22.8h, v6.8b, v30.8b\n    umlal     v22.8h, v8.8b, v31.8b\n    subs      x12, x6, #2\n    sqrshrun  v27.8b, v22.8h, #6\n    st1       {v27.8b}, [x1], x3        ////Store dest row1\n    beq       end_func                  //If ht=2\n\n    ld1       {v9.8b, v10.8b}, [x0], x2 //// Load row3;\n    ext       v11.8b, v9.8b , v10.8b , #2\n    umull     v24.8h, v6.8b, v28.8b\n    umlal     v24.8h, v8.8b, v29.8b\n    umlal     v24.8h, v9.8b, v30.8b\n    umlal     v24.8h, v11.8b, v31.8b\n    ld1       {v0.8b, v1.8b}, [x0], x2  //// Load row4 ;\n    sqrshrun  v16.8b, v24.8h, #6\n    ext       v2.8b, v0.8b , v1.8b , #2\n    st1       {v16.8b}, [x1], x3        ////Store dest row2\n    umull     v18.8h, v9.8b, v28.8b\n    umlal     v18.8h, v11.8b, v29.8b\n    umlal     v18.8h, v0.8b, v30.8b\n    umlal     v18.8h, v2.8b, v31.8b\n    subs      x12, x6, #4\n    sqrshrun  v17.8b, v18.8h, #6\n    st1       {v17.8b}, [x1], x3        ////Store dest row3\n    beq       end_func                  //If ht=4\n\n    ld1       {v3.8b, v4.8b}, [x0], x2  //// Load row5;\n    ext       v5.8b, v3.8b , v4.8b , #2\n    umull     v20.8h, v0.8b, v28.8b\n    umlal     v20.8h, v2.8b, v29.8b\n    umlal     v20.8h, v3.8b, v30.8b\n    umlal     v20.8h, v5.8b, v31.8b\n    ld1       {v6.8b, v7.8b}, [x0], x2  //// Load row6 ;\n    sqrshrun  v26.8b, v20.8h, #6\n    ext       v8.8b, v6.8b , v7.8b , #2\n    st1       {v26.8b}, [x1], x3        ////Store dest row4\n    umull     v22.8h, v3.8b, v28.8b\n    umlal     v22.8h, v5.8b, v29.8b\n    umlal     v22.8h, v6.8b, v30.8b\n    umlal     v22.8h, v8.8b, v31.8b\n    ld1       {v9.8b, v10.8b}, [x0], x2 //// Load row7;\n    sqrshrun  v27.8b, v22.8h, #6\n    ext       v11.8b, v9.8b , v10.8b , #2\n    st1       {v27.8b}, [x1], x3        ////Store dest row5\n    umull     v24.8h, v6.8b, v28.8b\n    umlal     v24.8h, v8.8b, v29.8b\n    umlal     v24.8h, v9.8b, v30.8b\n    umlal     v24.8h, v11.8b, v31.8b\n    ld1       {v0.8b, v1.8b}, [x0], x2  //// Load row8;\n    sqrshrun  v16.8b, v24.8h, #6\n    ext       v2.8b, v0.8b , v1.8b , #2\n    st1       {v16.8b}, [x1], x3        ////Store dest row6\n    umull     v18.8h, v9.8b, v28.8b\n    umlal     v18.8h, v11.8b, v29.8b\n    umlal     v18.8h, v0.8b, v30.8b\n    umlal     v18.8h, v2.8b, v31.8b\n    sqrshrun  v17.8b, v18.8h, #6\n    st1       {v17.8b}, [x1], x3        ////Store dest row7\n    b         end_func\n\nloop_2:\n    ld1       {v0.8b}, [x0], x2         //// Load row0 ;\n    ext       v2.8b, v0.8b , v0.8b , #2\n    ld1       {v3.8b}, [x0], x2         //// Load row1;\n    ext       v5.8b, v3.8b , v3.8b , #2\n    umull     v20.8h, v0.8b, v28.8b\n    umlal     v20.8h, v2.8b, v29.8b\n    umlal     v20.8h, v3.8b, v30.8b\n    umlal     v20.8h, v5.8b, v31.8b\n    ld1       {v6.8b}, [x0], x2         //// Load row2\n    sqrshrun  v26.8b, v20.8h, #6\n    ext       v8.8b, v6.8b , v6.8b , #2\n    st1       {v26.s}[0], [x1], x3      ////Store dest row0\n    umull     v22.8h, v3.8b, v28.8b\n    umlal     v22.8h, v5.8b, v29.8b\n    umlal     v22.8h, v6.8b, v30.8b\n    umlal     v22.8h, v8.8b, v31.8b\n    subs      x12, x6, #2\n    sqrshrun  v27.8b, v22.8h, #6\n    st1       {v27.s}[0], [x1], x3      ////Store dest row1\n    beq       end_func                  //If ht=2\n\n    ld1       {v9.8b}, [x0], x2         //// Load row3;\n    ext       v11.8b, v9.8b , v9.8b , #2\n    umull     v24.8h, v6.8b, v28.8b\n    umlal     v24.8h, v8.8b, v29.8b\n    umlal     v24.8h, v9.8b, v30.8b\n    umlal     v24.8h, v11.8b, v31.8b\n    ld1       {v0.8b}, [x0], x2         //// Load row4 ;\n    sqrshrun  v16.8b, v24.8h, #6\n    ext       v2.8b, v0.8b , v0.8b , #2\n    st1       {v16.s}[0], [x1], x3      ////Store dest row2\n    umull     v18.8h, v9.8b, v28.8b\n    umlal     v18.8h, v11.8b, v29.8b\n    umlal     v18.8h, v0.8b, v30.8b\n    umlal     v18.8h, v2.8b, v31.8b\n    sqrshrun  v17.8b, v18.8h, #6\n    st1       {v17.s}[0], [x1], x3      ////Store dest row3\n\n\nend_func:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_inter_pred_filters_luma_horz_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_inter_pred_luma_horz_av8.s\n//*\n//* @brief\n//*  Contains function definitions for inter prediction  interpolation.\n//*\n//* @author\n//*  Ittiam\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_inter_pred_luma_horz_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_inter_pred_filters.c\n//\n\n///**\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Interprediction luma filter for horizontal input\n//*\n//* @par Description:\n//* Applies a 6 tap horizontal filter .The output is  clipped to 8 bits\n//* sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*\n// @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n//void ih264_inter_pred_luma_horz (\n//                            UWORD8 *pu1_src,\n//                            UWORD8 *pu1_dst,\n//                            WORD32 src_strd,\n//                            WORD32 dst_strd,\n//                            WORD32 ht,\n//                            WORD32 wd   )\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ht\n//    w5 =>  wd\n\n.text\n.p2align 2\n\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_inter_pred_luma_horz_av8\n\nih264_inter_pred_luma_horz_av8:\n\n\n\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x2, w2\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n    sub       x0, x0, #2                //pu1_src-2\n    sub       x14, x4, #16\n    movi      v0.8b, #5                 //filter coeff\n    subs      x12, x5, #8               //if wd=8 branch to loop_8\n    movi      v1.8b, #20                //filter coeff\n    beq       loop_8\n\n    subs      x12, x5, #4               //if wd=4 branch to loop_4\n    beq       loop_4\n\nloop_16:                                //when  wd=16\n    //// Processing row0 and row1\n    ld1       {v2.8b, v3.8b, v4.8b}, [x0], x2 //// Load row0\n    add       x14, x14, #1              //for checking loop\n    ext       v31.8b, v2.8b , v3.8b, #5 ////extract a[5]                            (column1,row0)\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row1\n    ext       v30.8b, v3.8b , v4.8b, #5 ////extract a[5]                            (column2,row0)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row0)\n    ext       v28.8b, v5.8b , v6.8b, #5 ////extract a[5]                            (column1,row1)\n    uaddl     v10.8h, v30.8b, v3.8b     //// a0 + a5                             (column2,row0)\n    ext       v27.8b, v6.8b , v7.8b, #5 ////extract a[5]                            (column2,row1)\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row1)\n    ext       v31.8b, v2.8b , v3.8b, #2 ////extract a[2]                            (column1,row0)\n    uaddl     v16.8h, v27.8b, v6.8b     //// a0 + a5                             (column2,row1)\n    ext       v30.8b, v3.8b , v4.8b, #2 ////extract a[2]                            (column2,row0)\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row0)\n    ext       v28.8b, v5.8b , v6.8b, #2 ////extract a[2]                            (column1,row1)\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row0)\n    ext       v27.8b, v6.8b , v7.8b, #2 ////extract a[2]                            (column2,row1)\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row1)\n    ext       v31.8b, v2.8b , v3.8b, #3 ////extract a[3]                            (column1,row0)\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row1)\n    ext       v30.8b, v3.8b , v4.8b, #3 ////extract a[3]                            (column2,row0)\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row0)\n    ext       v28.8b, v5.8b , v6.8b, #3 ////extract a[3]                            (column1,row1)\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row0)\n    ext       v27.8b, v6.8b , v7.8b, #3 ////extract a[3]                            (column2,row1)\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row1)\n    ext       v31.8b, v2.8b , v3.8b, #1 ////extract a[1]                            (column1,row0)\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row1)\n    ext       v30.8b, v3.8b , v4.8b, #1 ////extract a[1]                            (column2,row0)\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row0)\n    ext       v28.8b, v5.8b , v6.8b, #1 ////extract a[1]                            (column1,row1)\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row0)\n    ext       v27.8b, v6.8b , v7.8b, #1 ////extract a[1]                            (column2,row1)\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row1)\n    ext       v31.8b, v2.8b , v3.8b, #4 ////extract a[4]                            (column1,row0)\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row1)\n    ext       v30.8b, v3.8b , v4.8b, #4 ////extract a[4]                            (column2,row0)\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row0)\n    ext       v28.8b, v5.8b , v6.8b, #4 ////extract a[4]                            (column1,row1)\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row0)\n    ext       v27.8b, v6.8b , v7.8b, #4 ////extract a[4]                            (column2,row1)\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row1)\n    ld1       {v2.8b, v3.8b, v4.8b}, [x0], x2 //// Load row2\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row1)\n\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row0)\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row3\n    sqrshrun  v21.8b, v10.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row0)\n    ext       v31.8b, v2.8b , v3.8b, #5 ////extract a[5]                            (column1,row2)\n    st1       {v20.8b, v21.8b}, [x1], x3 ////Store dest row0\n    sqrshrun  v23.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row1)\n    ext       v30.8b, v3.8b , v4.8b, #5 ////extract a[5]                            (column2,row2)\n    sqrshrun  v24.8b, v16.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row1)\n\n\n\n//// Processing row2 and row3\n    ext       v28.8b, v5.8b , v6.8b, #5 ////extract a[5]                            (column1,row3)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row2)\n    st1       {v23.8b, v24.8b}, [x1], x3 ////Store dest row1\n    uaddl     v10.8h, v30.8b, v3.8b     //// a0 + a5                             (column2,row2)\n    ext       v27.8b, v6.8b , v7.8b, #5 ////extract a[5]                            (column2,row3)\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row3)\n    ext       v31.8b, v2.8b , v3.8b, #2 ////extract a[2]                            (column1,row2)\n    uaddl     v16.8h, v27.8b, v6.8b     //// a0 + a5                             (column2,row3)\n    ext       v30.8b, v3.8b , v4.8b, #2 ////extract a[2]                            (column2,row2)\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row2)\n    ext       v27.8b, v6.8b , v7.8b, #2 ////extract a[2]                            (column2,row3)\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row2)\n    ext       v28.8b, v5.8b , v6.8b, #2 ////extract a[2]                            (column1,row3)\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row3)\n    ext       v31.8b, v2.8b , v3.8b, #3 ////extract a[3]                            (column1,row2)\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row3)\n    ext       v30.8b, v3.8b , v4.8b, #3 ////extract a[3]                            (column2,row2)\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row2)\n    ext       v28.8b, v5.8b , v6.8b, #3 ////extract a[3]                            (column1,row3)\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row2)\n    ext       v27.8b, v6.8b , v7.8b, #3 ////extract a[3]                            (column2,row3)\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row3)\n    ext       v31.8b, v2.8b , v3.8b, #1 ////extract a[1]                            (column1,row2)\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row3)\n    ext       v30.8b, v3.8b , v4.8b, #1 ////extract a[1]                            (column2,row2)\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row2)\n    ext       v28.8b, v5.8b , v6.8b, #1 ////extract a[1]                            (column1,row3)\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row2)\n    ext       v27.8b, v6.8b , v7.8b, #1 ////extract a[1]                            (column2,row3)\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row3)\n    ext       v31.8b, v2.8b , v3.8b, #4 ////extract a[4]                            (column1,row2)\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row3)\n    ext       v30.8b, v3.8b , v4.8b, #4 ////extract a[4]                            (column2,row2)\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row2)\n    ext       v28.8b, v5.8b , v6.8b, #4 ////extract a[4]                            (column1,row3)\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row2)\n    ext       v27.8b, v6.8b , v7.8b, #4 ////extract a[4]                            (column2,row3)\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row3)\n    ld1       {v2.8b, v3.8b, v4.8b}, [x0], x2 //// Load row4\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row3)\n\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row2)\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row5\n    sqrshrun  v21.8b, v10.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row2)\n    ext       v31.8b, v2.8b , v3.8b, #5 ////extract a[5]                            (column1,row4)\n    st1       {v20.8b, v21.8b}, [x1], x3 ////Store dest row2\n    sqrshrun  v23.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row3)\n    ext       v30.8b, v3.8b , v4.8b, #5 ////extract a[5]                            (column2,row4)\n    sqrshrun  v24.8b, v16.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row3)\n\n\n//// Processing row4 and row5\n    ext       v28.8b, v5.8b , v6.8b, #5 ////extract a[5]                            (column1,row5)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row4)\n    st1       {v23.8b, v24.8b}, [x1], x3 ////Store dest row3\n    uaddl     v10.8h, v30.8b, v3.8b     //// a0 + a5                             (column2,row4)\n    ext       v27.8b, v6.8b , v7.8b, #5 ////extract a[5]                            (column2,row5)\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row5)\n    ext       v31.8b, v2.8b , v3.8b, #2 ////extract a[2]                            (column1,row4)\n    uaddl     v16.8h, v27.8b, v6.8b     //// a0 + a5                             (column2,row5)\n    ext       v30.8b, v3.8b , v4.8b, #2 ////extract a[2]                            (column2,row4)\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row4)\n    ext       v27.8b, v6.8b , v7.8b, #2 ////extract a[2]                            (column2,row5)\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row4)\n    ext       v28.8b, v5.8b , v6.8b, #2 ////extract a[2]                            (column1,row5)\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row5)\n    ext       v31.8b, v2.8b , v3.8b, #3 ////extract a[3]                            (column1,row4)\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row5)\n    ext       v30.8b, v3.8b , v4.8b, #3 ////extract a[3]                            (column2,row4)\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row4)\n    ext       v28.8b, v5.8b , v6.8b, #3 ////extract a[3]                            (column1,row5)\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row4)\n    ext       v27.8b, v6.8b , v7.8b, #3 ////extract a[3]                            (column2,row5)\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row5)\n    ext       v31.8b, v2.8b , v3.8b, #1 ////extract a[1]                            (column1,row4)\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row5)\n    ext       v30.8b, v3.8b , v4.8b, #1 ////extract a[1]                            (column2,row4)\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row4)\n    ext       v28.8b, v5.8b , v6.8b, #1 ////extract a[1]                            (column1,row5)\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row4)\n    ext       v27.8b, v6.8b , v7.8b, #1 ////extract a[1]                            (column2,row5)\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row4)\n    ext       v31.8b, v2.8b , v3.8b, #4 ////extract a[4]                            (column1,row4)\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row5)\n    ext       v30.8b, v3.8b , v4.8b, #4 ////extract a[4]                            (column2,row4)\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row4)\n    ext       v28.8b, v5.8b , v6.8b, #4 ////extract a[4]                            (column1,row5)\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row4)\n    ext       v27.8b, v6.8b , v7.8b, #4 ////extract a[4]                            (column2,row5)\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row5)\n    ld1       {v2.8b, v3.8b, v4.8b}, [x0], x2 //// Load row6\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row5)\n\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row4)\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row7\n    sqrshrun  v21.8b, v10.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row4)\n    ext       v31.8b, v2.8b , v3.8b, #5 ////extract a[5]                            (column1,row6)\n    st1       {v20.8b, v21.8b}, [x1], x3 ////Store dest row2\n    sqrshrun  v23.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row5)\n    ext       v30.8b, v3.8b , v4.8b, #5 ////extract a[5]                            (column2,row6)\n    sqrshrun  v24.8b, v16.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row5)\n\n\n\n    //// Processing row6 and row7\n\n    ext       v28.8b, v5.8b , v6.8b, #5 ////extract a[5]                            (column1,row7)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row6)\n    st1       {v23.8b, v24.8b}, [x1], x3 ////Store dest row5\n    uaddl     v10.8h, v30.8b, v3.8b     //// a0 + a5                             (column2,row6)\n    ext       v27.8b, v6.8b , v7.8b, #5 ////extract a[5]                            (column2,row7)\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row7)\n    ext       v31.8b, v2.8b , v3.8b, #2 ////extract a[2]                            (column1,row6)\n    uaddl     v16.8h, v27.8b, v6.8b     //// a0 + a5                             (column2,row7)\n    ext       v30.8b, v3.8b , v4.8b, #2 ////extract a[2]                            (column2,row6)\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row6)\n    ext       v27.8b, v6.8b , v7.8b, #2 ////extract a[2]                            (column2,row7)\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row6)\n    ext       v28.8b, v5.8b , v6.8b, #2 ////extract a[2]                            (column1,row7)\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row7)\n    ext       v31.8b, v2.8b , v3.8b, #3 ////extract a[3]                            (column1,row6)\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row7)\n    ext       v30.8b, v3.8b , v4.8b, #3 ////extract a[3]                            (column2,row6)\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row6)\n    ext       v28.8b, v5.8b , v6.8b, #3 ////extract a[3]                            (column1,row7)\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row6)\n    ext       v27.8b, v6.8b , v7.8b, #3 ////extract a[3]                            (column2,row7)\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row7)\n    ext       v31.8b, v2.8b , v3.8b, #1 ////extract a[1]                            (column1,row6)\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row7)\n    ext       v30.8b, v3.8b , v4.8b, #1 ////extract a[1]                            (column2,row6)\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row6)\n    ext       v28.8b, v5.8b , v6.8b, #1 ////extract a[1]                            (column1,row7)\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row6)\n    ext       v27.8b, v6.8b , v7.8b, #1 ////extract a[1]                            (column2,row7)\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row6)\n    ext       v31.8b, v2.8b , v3.8b, #4 ////extract a[4]                            (column1,row6)\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row7)\n    ext       v30.8b, v3.8b , v4.8b, #4 ////extract a[4]                            (column2,row6)\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row6)\n    ext       v28.8b, v5.8b , v6.8b, #4 ////extract a[4]                            (column1,row7)\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row6)\n    ext       v27.8b, v6.8b , v7.8b, #4 ////extract a[4]                            (column2,row6)\n\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row6)\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row7)\n    sqrshrun  v21.8b, v10.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row6)\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row7)\n    sqrshrun  v23.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row7)\n    st1       {v20.8b, v21.8b}, [x1], x3 ////Store dest row6\n    sqrshrun  v24.8b, v16.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row7)\n    subs      x12, x14, #1              // if height==16  - looping\n    st1       {v23.8b, v24.8b}, [x1], x3 ////Store dest row7\n\n\n\n    beq       loop_16\n    b         end_func\n\n\n\nloop_8:\n//// Processing row0 and row1\n\n\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row1\n    add       x14, x14, #1              //for checking loop\n    ext       v28.8b, v5.8b , v6.8b, #5 ////extract a[5]                            (column1,row1)\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row0\n    ext       v25.8b, v5.8b , v6.8b, #2 ////extract a[2]                            (column1,row1)\n    ext       v31.8b, v2.8b , v3.8b, #5 ////extract a[5]                            (column1,row0)\n    ext       v24.8b, v5.8b , v6.8b, #3 ////extract a[3]                            (column1,row1)\n    ext       v23.8b, v5.8b , v6.8b, #1 ////extract a[1]                            (column1,row1)\n    ext       v22.8b, v5.8b , v6.8b, #4 ////extract a[4]                            (column1,row1)\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row1)\n    ext       v29.8b, v2.8b , v3.8b, #3 ////extract a[3]                            (column1,row0)\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row1)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row1)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row1)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row1)\n    ext       v30.8b, v2.8b , v3.8b, #2 ////extract a[2]                            (column1,row0)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row0)\n    ext       v27.8b, v2.8b , v3.8b, #1 ////extract a[1]                            (column1,row0)\n    ext       v26.8b, v2.8b , v3.8b, #4 ////extract a[4]                            (column1,row0)\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row2\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row0)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row0)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row0)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row0)\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row3\n    sqrshrun  v23.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row0)\n\n    //// Processing row2 and row3\n    ext       v28.8b, v5.8b , v6.8b, #5 ////extract a[5]                            (column1,row3)\n    ext       v25.8b, v5.8b , v6.8b, #2 ////extract a[2]                            (column1,row3)\n    ext       v31.8b, v2.8b , v3.8b, #5 ////extract a[5]                            (column1,row2)\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row3)\n    st1       {v23.8b}, [x1], x3        ////Store dest row0\n    ext       v24.8b, v5.8b , v6.8b, #3 ////extract a[3]                            (column1,row2)\n    ext       v23.8b, v5.8b , v6.8b, #1 ////extract a[1]                            (column1,row3)\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row1)\n    ext       v22.8b, v5.8b , v6.8b, #4 ////extract a[4]                            (column1,row3)\n    ext       v29.8b, v2.8b , v3.8b, #3 ////extract a[3]                            (column1,row2)\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row3)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row3)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row3)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row3)\n    st1       {v20.8b}, [x1], x3        ////Store dest row1\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row2)\n    ext       v30.8b, v2.8b , v3.8b, #2 ////extract a[2]                            (column1,row2)\n    ext       v27.8b, v2.8b , v3.8b, #1 ////extract a[1]                            (column1,row2)\n    ext       v26.8b, v2.8b , v3.8b, #4 ////extract a[4]                            (column1,row2)\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row4\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row2)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row2)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row2)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row2)\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row3\n    subs      x9, x4, #4\n    sqrshrun  v23.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row3)\n    ext       v28.8b, v5.8b , v6.8b, #5 ////extract a[5]                            (column1,row5)\n    ext       v25.8b, v5.8b , v6.8b, #2 ////extract a[2]                            (column1,row5)\n    ext       v31.8b, v2.8b , v3.8b, #5 ////extract a[5]                            (column1,row4)\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row5)\n    ext       v24.8b, v5.8b , v6.8b, #3 ////extract a[3]                            (column1,row5)\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row2)\n    ext       v22.8b, v5.8b , v6.8b, #4 ////extract a[4]                            (column1,row5)\n    ext       v29.8b, v2.8b , v3.8b, #3 ////extract a[3]                            (column1,row4)\n    st1       {v20.8b}, [x1], x3        ////Store dest row2\n    ext       v30.8b, v2.8b , v3.8b, #2 ////extract a[2]                            (column1,row4)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row4)\n    st1       {v23.8b}, [x1], x3        ////Store dest row3\n    beq       end_func                  // Branch if height==4\n\n//// Processing row4 and row5\n    ext       v23.8b, v5.8b , v6.8b, #1 ////extract a[1]                            (column1,row5)\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row5)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row5)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row5)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row5)\n    ext       v27.8b, v2.8b , v3.8b, #1 ////extract a[1]                            (column1,row4)\n    ext       v26.8b, v2.8b , v3.8b, #4 ////extract a[4]                            (column1,row4)\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row6\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row4)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row4)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row4)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row4)\n    sqrshrun  v23.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row5)\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row7\n    ext       v31.8b, v2.8b , v3.8b, #5 ////extract a[5]                            (column1,row6)\n    ext       v28.8b, v5.8b , v6.8b, #5 ////extract a[5]                            (column1,row7)\n    ext       v25.8b, v5.8b , v6.8b, #2 ////extract a[2]                            (column1,row7)\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row7)\n    ext       v24.8b, v5.8b , v6.8b, #3 ////extract a[3]                            (column1,row7)\n    ext       v22.8b, v5.8b , v6.8b, #4 ////extract a[4]                            (column1,row7)\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row4)\n    ext       v29.8b, v2.8b , v3.8b, #3 ////extract a[3]                            (column1,row6)\n    ext       v30.8b, v2.8b , v3.8b, #2 ////extract a[2]                            (column1,row6)\n    st1       {v20.8b}, [x1], x3        ////Store dest row4\n    ext       v27.8b, v2.8b , v3.8b, #1 ////extract a[1]                            (column1,row6)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row6)\n    ext       v26.8b, v2.8b , v3.8b, #4 ////extract a[4]                            (column1,row6)\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row6)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row6)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row6)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row6)\n    //// Processing row6 and row7\n    st1       {v23.8b}, [x1], x3        ////Store dest row5\n    ext       v23.8b, v5.8b , v6.8b, #1 ////extract a[1]                            (column1,row7)\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row7)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row7)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row7)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row7)\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row6)\n    subs      x12, x14, #1\n    st1       {v20.8b}, [x1], x3        ////Store dest row6\n    sqrshrun  v23.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row7)\n    st1       {v23.8b}, [x1], x3        ////Store dest row7\n\n    beq       loop_8                    //looping if height ==16\n\n    b         end_func\nloop_4:\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row1\n    ext       v28.8b, v5.8b , v6.8b, #5 ////extract a[5]                            (column1,row1)\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row0\n    ext       v25.8b, v5.8b , v6.8b, #2 ////extract a[2]                            (column1,row1)\n    ext       v31.8b, v2.8b , v3.8b, #5 ////extract a[5]                            (column1,row0)\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row1)\n    ext       v24.8b, v5.8b , v6.8b, #3 ////extract a[3]                            (column1,row1)\n    ext       v23.8b, v5.8b , v6.8b, #1 ////extract a[1]                            (column1,row1)\n    ext       v22.8b, v5.8b , v6.8b, #4 ////extract a[4]                            (column1,row1)\n    ext       v29.8b, v2.8b , v3.8b, #3 ////extract a[3]                            (column1,row0)\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row1)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row1)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row1)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row1)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row0)\n    ext       v30.8b, v2.8b , v3.8b, #2 ////extract a[2]                            (column1,row0)\n    ext       v27.8b, v2.8b , v3.8b, #1 ////extract a[1]                            (column1,row0)\n    ext       v26.8b, v2.8b , v3.8b, #4 ////extract a[4]                            (column1,row0)\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row2\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row0)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row0)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row0)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row0)\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row3\n    ext       v28.8b, v5.8b , v6.8b, #5 ////extract a[5]                            (column1,row3)\n    ext       v25.8b, v5.8b , v6.8b, #2 ////extract a[2]                            (column1,row3)\n    sqrshrun  v23.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row0)\n    ext       v31.8b, v2.8b , v3.8b, #5 ////extract a[5]                            (column1,row2)\n    ext       v24.8b, v5.8b , v6.8b, #3 ////extract a[3]                            (column1,row2)\n    st1       {v23.s}[0], [x1], x3      ////Store dest row0\n    ext       v23.8b, v5.8b , v6.8b, #1 ////extract a[1]                            (column1,row3)\n    ext       v22.8b, v5.8b , v6.8b, #4 ////extract a[4]                            (column1,row3)\n    ext       v29.8b, v2.8b , v3.8b, #3 ////extract a[3]                            (column1,row2)\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row1)\n    ext       v30.8b, v2.8b , v3.8b, #2 ////extract a[2]                            (column1,row2)\n    ext       v27.8b, v2.8b , v3.8b, #1 ////extract a[1]                            (column1,row2)\n\n    //// Processing row2 and row3\n    st1       {v20.s}[0], [x1], x3      ////Store dest row1\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row3)\n    ext       v26.8b, v2.8b , v3.8b, #4 ////extract a[4]                            (column1,row2)\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row3)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row3)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row3)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row3)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row2)\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row2)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row2)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row2)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row2)\n    sqrshrun  v23.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row3)\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row2)\n    st1       {v20.s}[0], [x1], x3      ////Store dest row2\n    subs      x4, x4, #8                // Loop if height =8\n    st1       {v23.s}[0], [x1], x3      ////Store dest row3\n    beq       loop_4\n\nend_func:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_inter_pred_filters_luma_vert_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_inter_pred_luma_vert_av8.s\n//*\n//* @brief\n//*  Contains function definitions for inter prediction  interpolation.\n//*\n//* @author\n//*  Ittiam\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_inter_pred_luma_vert_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_inter_pred_filters.c\n//\n\n///**\n///**\n///**\n// *******************************************************************************\n// *\n// * @brief\n// *    Interprediction luma filter for vertical input\n// *\n// * @par Description:\n// *   Applies a 6 tap vertcal filter.The output is  clipped to 8 bits\n// *    sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n// *\n// * @param[in] pu1_src\n// *  UWORD8 pointer to the source\n// *\n// * @param[out] pu1_dst\n// *  UWORD8 pointer to the destination\n// *\n// * @param[in] src_strd\n// *  integer source stride\n// *\n// * @param[in] dst_strd\n// *  integer destination stride\n// *\n// * @param[in] ht\n// *  integer height of the array\n// *\n// * @param[in] wd\n// *  integer width of the array\n// *\n// * @returns\n// *\n// * @remarks\n// *  None\n// *\n// *******************************************************************************\n\n//void ih264_inter_pred_luma_vert (\n//                            UWORD8 *pu1_src,\n//                            UWORD8 *pu1_dst,\n//                            WORD32 src_strd,\n//                            WORD32 dst_strd,\n//                            WORD32 ht,\n//                            WORD32 wd   )\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ht\n//    w5 =>  wd\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n\n    .global ih264_inter_pred_luma_vert_av8\n\nih264_inter_pred_luma_vert_av8:\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x2, w2\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n\n    sub       x0, x0, x2, lsl #1        //pu1_src-2*src_strd\n\n    sub       x14, x4, #16\n    movi      v22.8h, #20               // Filter coeff 0x14 into Q11\n\n    subs      x12, x5, #8               //if wd=8 branch to loop_8\n    movi      v24.8h, #5                // Filter coeff 0x4  into Q12\n    beq       loop_8_start\n\n    subs      x12, x5, #4               //if wd=4 branch to loop_4\n    beq       loop_4_start\n\n\n    ld1       {v0.2s, v1.2s}, [x0], x2  // Vector load from src[0_0]\n    ld1       {v2.2s, v3.2s}, [x0], x2  // Vector load from src[1_0]\n    ld1       {v4.2s, v5.2s}, [x0], x2  // Vector load from src[2_0]\n    ld1       {v6.2s, v7.2s}, [x0], x2  // Vector load from src[3_0]\n    add       x14, x14, #1              //for checking loop\n    ld1       {v8.2s, v9.2s}, [x0], x2  // Vector load from src[4_0]\n    uaddl     v12.8h, v4.8b, v6.8b      // temp1 = src[2_0] + src[3_0]\n    ld1       {v10.2s, v11.2s}, [x0], x2 // Vector load from src[5_0]\n\nloop_16:                                //when  wd=16\n\n    uaddl     v14.8h, v0.8b, v10.8b     // temp = src[0_0] + src[5_0]\n    uaddl     v16.8h, v2.8b, v8.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v14.8h, v12.8h, v22.8h    // temp += temp1 * 20\n    uaddl     v20.8h, v1.8b, v11.8b     // temp4 = src[0_8] + src[5_8]\n    uaddl     v18.8h, v5.8b, v7.8b      // temp3 = src[2_8] + src[3_8]\n    mla       v20.8h, v18.8h , v22.8h   // temp4 += temp3 * 20\n    ld1       {v0.2s, v1.2s}, [x0], x2\n    uaddl     v26.8h, v3.8b, v9.8b      // temp5 = src[1_8] + src[4_8]\n    uaddl     v12.8h, v6.8b, v8.8b\n    mls       v14.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v16.8h, v2.8b, v0.8b\n    uaddl     v18.8h, v4.8b, v10.8b\n    mla       v16.8h, v12.8h , v22.8h\n    mls       v20.8h, v26.8h , v24.8h   // temp4 -= temp5 * 5\n    uaddl     v26.8h, v5.8b, v11.8b\n    uaddl     v12.8h, v7.8b, v9.8b\n    sqrshrun  v30.8b, v14.8h, #5        // dst[0_0] = CLIP_U8((temp +16) >> 5)\n    uaddl     v14.8h, v3.8b, v1.8b\n    ld1       {v2.2s, v3.2s}, [x0], x2\n    mla       v14.8h, v12.8h , v22.8h\n    mls       v16.8h, v18.8h , v24.8h\n    sqrshrun  v31.8b, v20.8h, #5        // dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    uaddl     v18.8h, v4.8b, v2.8b\n    uaddl     v12.8h, v8.8b, v10.8b\n\n    st1       {v30.2s, v31.2s}, [x1], x3 // Vector store to dst[0_0]\n    mla       v18.8h, v12.8h , v22.8h\n    uaddl     v20.8h, v6.8b, v0.8b\n    mls       v14.8h, v26.8h , v24.8h\n    sqrshrun  v30.8b, v16.8h, #5\n    uaddl     v12.8h, v9.8b, v11.8b\n    uaddl     v16.8h, v5.8b, v3.8b\n    uaddl     v26.8h, v7.8b, v1.8b\n    mla       v16.8h, v12.8h , v22.8h\n    mls       v18.8h, v20.8h , v24.8h\n    ld1       {v4.2s, v5.2s}, [x0], x2\n\n    sqrshrun  v31.8b, v14.8h, #5\n    uaddl     v12.8h, v10.8b, v0.8b\n    uaddl     v14.8h, v6.8b, v4.8b\n    uaddl     v20.8h, v8.8b, v2.8b\n    mla       v14.8h, v12.8h , v22.8h\n    mls       v16.8h, v26.8h , v24.8h\n    st1       {v30.2s, v31.2s}, [x1], x3 //store row 1\n    sqrshrun  v30.8b, v18.8h, #5\n    uaddl     v18.8h, v7.8b, v5.8b\n    uaddl     v12.8h, v11.8b, v1.8b\n    mla       v18.8h, v12.8h , v22.8h\n    uaddl     v26.8h, v9.8b, v3.8b\n    mls       v14.8h, v20.8h , v24.8h\n    ld1       {v6.2s, v7.2s}, [x0], x2\n    sqrshrun  v31.8b, v16.8h, #5\n    mls       v18.8h, v26.8h , v24.8h\n    uaddl     v12.8h, v0.8b, v2.8b      // temp1 = src[2_0] + src[3_0]\n    st1       {v30.2s, v31.2s}, [x1], x3 //store row 2\n    uaddl     v16.8h, v10.8b, v4.8b     // temp2 = src[1_0] + src[4_0]\n    uaddl     v20.8h, v9.8b, v7.8b      // temp4 = src[0_8] + src[5_8]\n    sqrshrun  v30.8b, v14.8h, #5\n    uaddl     v26.8h, v5.8b, v11.8b     // temp5 = src[1_8] + src[4_8]\n    uaddl     v14.8h, v8.8b, v6.8b      // temp = src[0_0] + src[5_0]\n    sqrshrun  v31.8b, v18.8h, #5\n    mla       v14.8h, v12.8h , v22.8h   // temp += temp1 * 20\n    uaddl     v18.8h, v1.8b, v3.8b      // temp3 = src[2_8] + src[3_8]\n    st1       {v30.2s, v31.2s}, [x1], x3 //store row 3\n    // 4 rows processed\n    mla       v20.8h, v18.8h , v22.8h   // temp4 += temp3 * 20\n    ld1       {v8.2s, v9.2s}, [x0], x2\n    uaddl     v12.8h, v2.8b, v4.8b\n    uaddl     v18.8h, v3.8b, v5.8b\n    mls       v14.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v28.8h, v9.8b, v11.8b\n    uaddl     v16.8h, v6.8b, v0.8b\n    mla       v28.8h, v18.8h , v22.8h   // temp4 += temp3 * 20\n    mls       v20.8h, v26.8h , v24.8h   // temp4 -= temp5 * 5\n    uaddl     v26.8h, v1.8b, v7.8b\n    uaddl     v18.8h, v5.8b, v7.8b\n    sqrshrun  v30.8b, v14.8h, #5        // dst[0_0] = CLIP_U8((temp +16) >> 5)\n    uaddl     v14.8h, v8.8b, v10.8b\n\n    sqrshrun  v31.8b, v20.8h, #5        // dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    ld1       {v10.2s, v11.2s}, [x0], x2\n    mls       v28.8h, v26.8h , v24.8h   // temp4 -= temp5 * 5\n    st1       {v30.2s, v31.2s}, [x1], x3 //  store row 4\n    mla       v14.8h, v12.8h , v22.8h   // temp += temp1 * 20\n    uaddl     v20.8h, v11.8b, v1.8b\n    uaddl     v26.8h, v3.8b, v9.8b\n    mla       v20.8h, v18.8h , v22.8h   // temp4 += temp3 * 20\n    uaddl     v12.8h, v6.8b, v4.8b\n    uaddl     v18.8h, v7.8b, v9.8b\n    sqrshrun  v31.8b, v28.8h, #5        // dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    mls       v14.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v16.8h, v8.8b, v2.8b\n    sqrshrun  v30.8b, v14.8h, #5        // dst[0_0] = CLIP_U8((temp +16) >> 5)\n    mls       v20.8h, v26.8h , v24.8h   // temp4 -= temp5 * 5\n    uaddl     v14.8h, v10.8b, v0.8b\n    st1       {v30.2s, v31.2s}, [x1], x3 //  store row 5\n    mla       v14.8h, v12.8h , v22.8h   // temp += temp1 * 20\n    ld1       {v0.2s, v1.2s}, [x0], x2\n    uaddl     v26.8h, v5.8b, v11.8b\n    uaddl     v12.8h, v8.8b, v6.8b\n    uaddl     v28.8h, v0.8b, v2.8b\n    sqrshrun  v31.8b, v20.8h, #5        // dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    mla       v28.8h, v12.8h , v22.8h   // temp += temp1 * 20\n    uaddl     v20.8h, v1.8b, v3.8b\n    mls       v14.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    mla       v20.8h, v18.8h , v22.8h   // temp4 += temp3 * 20\n    uaddl     v16.8h, v10.8b, v4.8b\n    sqrshrun  v30.8b, v14.8h, #5        // dst[0_0] = CLIP_U8((temp +16) >> 5)\n    mov       v2.8b, v6.8b\n    mov       v3.8b, v7.8b\n    mls       v28.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    st1       {v30.2s, v31.2s}, [x1], x3 //  store row 6\n    sqrshrun  v30.8b, v28.8h, #5        // dst[0_0] = CLIP_U8((temp +16) >> 5)\n\n    swp       v0.8b, v4.8b\n    swp       v1.8b, v5.8b\n\n\n\n    mls       v20.8h, v26.8h , v24.8h   // temp4 -= temp5 * 5\n    mov       v6.8b, v10.8b\n    mov       v7.8b, v11.8b\n    subs      x12, x14, #1              // if height==16  - looping\n\n    swp       v4.8b, v8.8b\n    swp       v5.8b, v9.8b\n\n\n    sqrshrun  v31.8b, v20.8h, #5        // dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    st1       {v30.2s, v31.2s}, [x1], x3 //  store row 7\n    bne       end_func                  //if height =8  end function\n    add       x14, x14, #1              //for checking loop\n    ld1       {v10.2s, v11.2s}, [x0], x2\n    uaddl     v12.8h, v4.8b, v6.8b      // temp1 = src[2_0] + src[3_0]\n\n    b         loop_16                   // looping if height =16\n\nloop_8_start:\n//// Processing row0 and row1\n\n    ld1       {v0.2s}, [x0], x2         // Vector load from src[0_0]\n    ld1       {v1.2s}, [x0], x2         // Vector load from src[1_0]\n    ld1       {v2.2s}, [x0], x2         // Vector load from src[2_0]\n    ld1       {v3.2s}, [x0], x2         // Vector load from src[3_0]\n    add       x14, x14, #1              //for checking loop\n    ld1       {v4.2s}, [x0], x2         // Vector load from src[4_0]\n    ld1       {v5.2s}, [x0], x2         // Vector load from src[5_0]\n\nloop_8:\n                                        //for checking loop\n    uaddl     v6.8h, v2.8b, v3.8b       // temp1 = src[2_0] + src[3_0]\n    uaddl     v8.8h, v0.8b, v5.8b       // temp = src[0_0] + src[5_0]\n    uaddl     v10.8h, v1.8b, v4.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v8.8h, v6.8h , v22.8h     // temp += temp1 * 20\n    ld1       {v6.2s}, [x0], x2\n    uaddl     v14.8h, v3.8b, v4.8b\n    uaddl     v16.8h, v1.8b, v6.8b\n    uaddl     v18.8h, v2.8b, v5.8b\n    mls       v8.8h, v10.8h , v24.8h    // temp -= temp2 * 5\n    mla       v16.8h, v14.8h , v22.8h\n    ld1       {v7.2s}, [x0], x2\n    uaddl     v20.8h, v4.8b, v5.8b\n    uaddl     v12.8h, v2.8b, v7.8b\n    uaddl     v10.8h, v3.8b, v6.8b\n    mls       v16.8h, v18.8h , v24.8h\n    sqrshrun  v26.8b, v8.8h, #5         // dst[0_0] = CLIP_U8( (temp + 16) >> 5)\n    mla       v12.8h, v20.8h , v22.8h\n    ld1       {v0.2s}, [x0], x2\n    uaddl     v14.8h, v5.8b, v6.8b\n    sqrshrun  v27.8b, v16.8h, #5\n    uaddl     v20.8h, v3.8b, v0.8b\n    mls       v12.8h, v10.8h , v24.8h\n    st1       {v26.2s}, [x1], x3        // Vector store to dst[0_0]\n    uaddl     v18.8h, v4.8b, v7.8b\n    mla       v20.8h, v14.8h , v22.8h\n    st1       {v27.2s}, [x1], x3\n    sqrshrun  v28.8b, v12.8h, #5\n    st1       {v28.2s}, [x1], x3\n    mls       v20.8h, v18.8h , v24.8h\n    ld1       {v1.2s}, [x0], x2\n    sqrshrun  v29.8b, v20.8h, #5\n    subs      x9, x4, #4\n    st1       {v29.2s}, [x1], x3        //store row 3\n\n\n    beq       end_func                  // Branch if height==4\n\n\n    uaddl     v14.8h, v6.8b, v7.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v16.8h, v0.8b, v5.8b      // temp = src[0_0] + src[5_0]\n    uaddl     v18.8h, v1.8b, v4.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v18.8h, v14.8h , v22.8h   // temp += temp1 * 20\n    ld1       {v2.2s}, [x0], x2\n    mls       v18.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v8.8h, v0.8b, v7.8b\n    uaddl     v10.8h, v1.8b, v6.8b\n    uaddl     v12.8h, v2.8b, v5.8b\n    sqrshrun  v26.8b, v18.8h, #5\n    mla       v12.8h, v8.8h , v22.8h\n    ld1       {v3.2s}, [x0], x2\n    mls       v12.8h, v10.8h , v24.8h\n    st1       {v26.2s}, [x1], x3\n    sqrshrun  v27.8b, v12.8h, #5\n    st1       {v27.2s}, [x1], x3\n    uaddl     v14.8h, v0.8b, v1.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v16.8h, v2.8b, v7.8b      // temp = src[0_0] + src[5_0]\n    uaddl     v18.8h, v3.8b, v6.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v18.8h, v14.8h , v22.8h   // temp += temp1 * 20\n    ld1       {v4.2s}, [x0], x2\n    mls       v18.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v8.8h, v2.8b, v1.8b\n    uaddl     v10.8h, v3.8b, v0.8b\n    uaddl     v12.8h, v4.8b, v7.8b\n    sqrshrun  v26.8b, v18.8h, #5\n    mla       v12.8h, v8.8h , v22.8h\n    ld1       {v5.2s}, [x0], x2\n    mls       v12.8h, v10.8h , v24.8h\n    st1       {v26.2s}, [x1], x3\n    sqrshrun  v27.8b, v12.8h, #5\n    subs      x12, x14, #1\n    st1       {v27.2s}, [x1], x3\n    add       x14, x14, #1\n    beq       loop_8                    //looping if height ==16\n\n    b         end_func\n\n\nloop_4_start:\n//// Processing row0 and row1\n\n\n    ld1       {v0.s}[0], [x0], x2       // Vector load from src[0_0]\n    ld1       {v1.s}[0], [x0], x2       // Vector load from src[1_0]\n    ld1       {v2.s}[0], [x0], x2       // Vector load from src[2_0]\n    ld1       {v3.s}[0], [x0], x2       // Vector load from src[3_0]\n    ld1       {v4.s}[0], [x0], x2       // Vector load from src[4_0]\n    ld1       {v5.s}[0], [x0], x2       // Vector load from src[5_0]\n\n    uaddl     v6.8h, v2.8b, v3.8b       // temp1 = src[2_0] + src[3_0]\n    uaddl     v8.8h, v0.8b, v5.8b       // temp = src[0_0] + src[5_0]\n    uaddl     v10.8h, v1.8b, v4.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v8.8h, v6.8h , v22.8h     // temp += temp1 * 20\n    ld1       {v6.2s}, [x0], x2\n    uaddl     v14.8h, v3.8b, v4.8b\n    uaddl     v16.8h, v1.8b, v6.8b\n    uaddl     v18.8h, v2.8b, v5.8b\n    mls       v8.8h, v10.8h , v24.8h    // temp -= temp2 * 5\n    ld1       {v7.s}[0], [x0], x2\n    mla       v16.8h, v14.8h , v22.8h\n    uaddl     v20.8h, v4.8b, v5.8b\n    uaddl     v12.8h, v2.8b, v7.8b\n    uaddl     v10.8h, v3.8b, v6.8b\n    mls       v16.8h, v18.8h , v24.8h\n    sqrshrun  v26.8b, v8.8h, #5         // dst[0_0] = CLIP_U8( (temp + 16) >> 5)\n    mla       v12.8h, v20.8h , v22.8h\n    ld1       {v0.s}[0], [x0], x2\n    uaddl     v14.8h, v5.8b, v6.8b\n    sqrshrun  v27.8b, v16.8h, #5\n    uaddl     v20.8h, v3.8b, v0.8b\n    mls       v12.8h, v10.8h , v24.8h\n    st1       {v26.s}[0], [x1], x3      // Vector store to dst[0_0]\n    uaddl     v18.8h, v4.8b, v7.8b\n    mla       v20.8h, v14.8h , v22.8h\n    st1       {v27.s}[0], [x1], x3\n    sqrshrun  v28.8b, v12.8h, #5\n    st1       {v28.s}[0], [x1], x3\n    mls       v20.8h, v18.8h , v24.8h\n    ld1       {v1.s}[0], [x0], x2\n    sqrshrun  v29.8b, v20.8h, #5\n    st1       {v29.s}[0], [x1], x3      //store row 3\n\n    subs      x9, x4, #4\n    beq       end_func                  // Branch if height==4\n\n\n    uaddl     v14.8h, v6.8b, v7.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v16.8h, v0.8b, v5.8b      // temp = src[0_0] + src[5_0]\n    uaddl     v18.8h, v1.8b, v4.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v18.8h, v14.8h , v22.8h   // temp += temp1 * 20\n    ld1       {v2.s}[0], [x0], x2\n    mls       v18.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v8.8h, v0.8b, v7.8b\n    uaddl     v10.8h, v1.8b, v6.8b\n    uaddl     v12.8h, v2.8b, v5.8b\n    sqrshrun  v26.8b, v18.8h, #5\n    mla       v12.8h, v8.8h , v22.8h\n    ld1       {v3.s}[0], [x0], x2\n    mls       v12.8h, v10.8h , v24.8h\n    st1       {v26.s}[0], [x1], x3\n    sqrshrun  v27.8b, v12.8h, #5\n    st1       {v27.s}[0], [x1], x3\n    uaddl     v14.8h, v0.8b, v1.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v16.8h, v2.8b, v7.8b      // temp = src[0_0] + src[5_0]\n    uaddl     v18.8h, v3.8b, v6.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v18.8h, v14.8h , v22.8h   // temp += temp1 * 20\n    ld1       {v4.s}[0], [x0], x2\n    mls       v18.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v8.8h, v2.8b, v1.8b\n    uaddl     v10.8h, v3.8b, v0.8b\n    uaddl     v12.8h, v4.8b, v7.8b\n    sqrshrun  v26.8b, v18.8h, #5\n    mla       v12.8h, v8.8h , v22.8h\n    ld1       {v5.s}[0], [x0], x2\n    mls       v12.8h, v10.8h , v24.8h\n    st1       {v26.s}[0], [x1], x3\n    sqrshrun  v27.8b, v12.8h, #5\n    st1       {v27.s}[0], [x1], x3\n\n\nend_func:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_inter_pred_luma_copy_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Interprediction luma function for copy\n//*\n//* @par Description:\n//*   Copies the array of width 'wd' and height 'ht' from the  location pointed\n//*   by 'src' to the location pointed by 'dst'\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//void ih264_inter_pred_luma_copy (\n//                            UWORD8 *pu1_src,\n//                            UWORD8 *pu1_dst,\n//                            WORD32 src_strd,\n//                            WORD32 dst_strd,\n//                            WORD32 ht,\n//                            WORD32 wd   )\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ht\n//    w5 =>  wd\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_inter_pred_luma_copy_av8\n\nih264_inter_pred_luma_copy_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x2, w2\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n\n    mov       x12, x5\n    mov       x7, x4\n    cmp       x7, #0                    //checks ht == 0\n    ble       end_loops\n    tst       x12, #15                  //checks wd for multiples for 4 & 8\n    beq       core_loop_wd_16\n    tst       x12, #7                   //checks wd for multiples for 4 & 8\n    beq       core_loop_wd_8\n    sub       x11, x12, #4\n\nouter_loop_wd_4:\n    subs      x4, x12, #0               //checks wd == 0\n    ble       end_inner_loop_wd_4\n\ninner_loop_wd_4:\n    ld1       {v0.s}[0], [x0]           //vld1_lane_u32((uint32_t *)pu1_src_tmp, src_tmp, 0)\n    add       x5, x0, x2                //pu1_src_tmp += src_strd\n    add       x6, x1, x3                //pu1_dst_tmp += dst_strd\n    st1       {v0.s}[0], [x1]           //vst1_lane_u32((uint32_t *)pu1_dst_tmp, src_tmp, 0)\n    ld1       {v0.s}[0], [x5], x2       //vld1_lane_u32((uint32_t *)pu1_src_tmp, src_tmp, 0)\n    add       x0, x0, #4                //pu1_src += 4\n    st1       {v0.s}[0], [x6], x3       //vst1_lane_u32((uint32_t *)pu1_dst_tmp, src_tmp, 0)\n    ld1       {v0.s}[0], [x5], x2       //vld1_lane_u32((uint32_t *)pu1_src_tmp, src_tmp, 0)\n    subs      x4, x4, #4                //(wd -4)\n    st1       {v0.s}[0], [x6], x3       //vst1_lane_u32((uint32_t *)pu1_dst_tmp, src_tmp, 0)\n    ld1       {v0.s}[0], [x5], x2       //vld1_lane_u32((uint32_t *)pu1_src_tmp, src_tmp, 0)\n    add       x1, x1, #4                //pu1_dst += 4\n    st1       {v0.s}[0], [x6], x3       //vst1_lane_u32((uint32_t *)pu1_dst_tmp, src_tmp, 0)\n\n    bgt       inner_loop_wd_4\n\nend_inner_loop_wd_4:\n    subs      x7, x7, #4                //ht - 4\n    sub       x0, x5, x11               //pu1_src = pu1_src_tmp\n    sub       x1, x6, x11               //pu1_dst = pu1_dst_tmp\n    bgt       outer_loop_wd_4\n\nend_loops:\n    // LDMFD sp!,{x4-x12,x15}                  //Reload the registers from SP\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\ncore_loop_wd_8:\n    sub       x11, x12, #8\n\nouter_loop_wd_8:\n    subs      x4, x12, #0               //checks wd\n    ble       end_inner_loop_wd_8\n\ninner_loop_wd_8:\n    add       x5, x0, x2                //pu1_src_tmp += src_strd\n    ld1       {v0.8b}, [x0], #8         //vld1_u8(pu1_src_tmp)\n    add       x6, x1, x3                //pu1_dst_tmp += dst_strd\n    st1       {v0.8b}, [x1], #8         //vst1_u8(pu1_dst_tmp, tmp_src)\n    ld1       {v1.8b}, [x5], x2         //vld1_u8(pu1_src_tmp)\n    st1       {v1.8b}, [x6], x3         //vst1_u8(pu1_dst_tmp, tmp_src)\n    subs      x4, x4, #8                //wd - 8(Loop condition)\n    ld1       {v2.8b}, [x5], x2         //vld1_u8(pu1_src_tmp)\n    st1       {v2.8b}, [x6], x3         //vst1_u8(pu1_dst_tmp, tmp_src)\n    ld1       {v3.8b}, [x5], x2         //vld1_u8(pu1_src_tmp)\n    st1       {v3.8b}, [x6], x3         //vst1_u8(pu1_dst_tmp, tmp_src)\n    bgt       inner_loop_wd_8\n\nend_inner_loop_wd_8:\n    subs      x7, x7, #4                //ht -= 4\n    sub       x0, x5, x11               //pu1_src = pu1_src_tmp\n    sub       x1, x6, x11               //pu1_dst = pu1_dst_tmp\n    bgt       outer_loop_wd_8\n\n    // LDMFD sp!,{x4-x12,x15}                  //Reload the registers from SP\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\ncore_loop_wd_16:\n    sub       x11, x12, #16\n\nouter_loop_wd_16:\n    subs      x4, x12, #0               //checks wd\n    ble       end_inner_loop_wd_16\n\ninner_loop_wd_16:\n    add       x5, x0, x2                //pu1_src_tmp += src_strd\n    ld1       { v0.16b}, [x0], #16      //vld1_u8(pu1_src_tmp)\n    add       x6, x1, x3                //pu1_dst_tmp += dst_strd\n    st1       { v0.16b}, [x1], #16      //vst1_u8(pu1_dst_tmp, tmp_src)\n    ld1       { v2.16b}, [x5], x2       //vld1_u8(pu1_src_tmp)\n    st1       { v2.16b}, [x6], x3       //vst1_u8(pu1_dst_tmp, tmp_src)\n    subs      x4, x4, #16               //wd - 8(Loop condition)\n    ld1       { v4.16b}, [x5], x2       //vld1_u8(pu1_src_tmp)\n    st1       { v4.16b}, [x6], x3       //vst1_u8(pu1_dst_tmp, tmp_src)\n    ld1       { v6.16b}, [x5], x2       //vld1_u8(pu1_src_tmp)\n    st1       { v6.16b}, [x6], x3       //vst1_u8(pu1_dst_tmp, tmp_src)\n    bgt       inner_loop_wd_16\n\nend_inner_loop_wd_16:\n    subs      x7, x7, #4                //ht -= 4\n    sub       x0, x5, x11               //pu1_src = pu1_src_tmp\n    sub       x1, x6, x11               //pu1_dst = pu1_dst_tmp\n    bgt       outer_loop_wd_16\n\n\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n// /*\n// ********************************************************************************\n// *\n// * @brief This function copies a 4x4 block to destination\n// *\n// * @par Description:\n// * Copies a 4x4 block to destination, where both src and dst are interleaved\n// *\n// * @param[in] pi2_src\n// *  Source\n// *\n// * @param[in] pu1_out\n// *  Output pointer\n// *\n// * @param[in] pred_strd,\n// *  Prediction buffer stride\n// *\n// * @param[in] out_strd\n// *  output buffer buffer Stride\n// *\n// * @returns none\n// *\n// * @remarks none\n// * Currently wd and height is not used, ie a 4x4 block is always copied\n// *\n// *******************************************************************************\n// */\n// void ih264_interleave_copy(WORD16 *pi2_src,\n//                            UWORD8 *pu1_out,\n//                            WORD32 pred_strd,\n//                            WORD32 out_strd\n//                            WORD32 wd\n//                            WORD32 ht)\n// Register Usage\n// x0 : pi2_src\n// x1 : pu1_out\n// w2 : src_strd\n// w3 : out_strd\n// Neon registers d0-d7, d16-d30 are used\n// No need for pushing  arm and neon registers\n\n    .global ih264_interleave_copy_av8\nih264_interleave_copy_av8:\n    push_v_regs\n    sxtw      x2, w2\n    sxtw      x3, w3\n    ld1       {v2.8b}, [x0], x2         //load src plane 1 => d2 &pred palne 2 => d3\n    ld1       {v3.8b}, [x0], x2\n    mov       v2.d[1], v3.d[0]\n    ld1       {v4.8b}, [x0], x2\n    ld1       {v5.8b}, [x0], x2\n    mov       v4.d[1], v5.d[0]\n\n    mov       x0, x1\n\n    ld1       {v18.8b}, [x1], x3        //load out [8 bit size) -8 coeffs\n    ld1       {v19.8b}, [x1], x3\n    mov       v18.d[1], v19.d[0]\n    movi      v30.8h, #0x00ff\n    ld1       {v20.8b}, [x1], x3\n    ld1       {v21.8b}, [x1], x3\n    mov       v20.d[1], v21.d[0]\n\n    bit       v18.16b, v2.16b , v30.16b\n    bit       v20.16b, v4.16b , v30.16b\n\n    st1       {v18.8b}, [x0], x3        //store  out\n    st1       {v18.d}[1], [x0], x3\n    st1       {v20.8b}, [x0], x3\n    st1       {v20.d}[1], [x0], x3\n\n    pop_v_regs\n    ret\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_inter_pred_luma_horz_hpel_vert_hpel_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_inter_pred_luma_horz_hpel_vert_hpel_av8.s\n//*\n//* @brief\n//*  Contains function definitions for inter prediction  interpolation.\n//*\n//* @author\n//*  Mohit\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_inter_pred_luma_horz_hpel_vert_hpel_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n\n\n//void ih264_inter_pred_luma_horz_hpel_vert_hpel(UWORD8 *pu1_src,\n//                                UWORD8 *pu1_dst,\n//                                WORD32 src_strd,,\n//                                WORD32 dst_strd,\n//                                WORD32 ht,\n//                                WORD32 wd,\n//                                    UWORD8* pu1_tmp,\n//                                  UWORD32 dydx)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ht\n//    w5 =>  wd\n\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_inter_pred_luma_horz_hpel_vert_hpel_av8\n\nih264_inter_pred_luma_horz_hpel_vert_hpel_av8:\n\n    //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x2, w2\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n\n    sub       x0, x0, x2, lsl #1        //pu1_src-2*src_strd\n    sub       x0, x0, #2                //pu1_src-2\n\n    movi      v26.8h, #0x14             // Filter coeff 20 into Q13\n    movi      v24.8h, #0x5              // Filter coeff 5  into Q12\n    movi      v27.8h, #0x14             // Filter coeff 20 into Q13\n    movi      v25.8h, #0x5              // Filter coeff 5  into Q12\n    mov       x7, #0x20\n    mov       x8, #0x30\n    subs      x12, x5, #4               //if wd=4 branch to loop_4\n    beq       loop_4_start\n\n    subs      x12, x5, #8               //if wd=8 branch to loop_8\n    beq       loop_8_start\n\n    //when  wd=16\n    movi      v28.8h, #0x14             // Filter coeff 20 into Q13\n    movi      v30.8h, #0x5              // Filter coeff 5  into Q12\n    sub       x2, x2, #16\n    ld1       {v0.2s, v1.2s}, [x0], #16 // Vector load from src[0_0]\n    ld1       {v12.2s}, [x0], x2        // Vector load from src[0_0]\n    ld1       {v2.2s, v3.2s}, [x0], #16 // Vector load from src[1_0]\n    ld1       {v13.2s}, [x0], x2        // Vector load from src[1_0]\n    ld1       {v4.2s, v5.2s}, [x0], #16 // Vector load from src[2_0]\n    ld1       {v14.2s}, [x0], x2        // Vector load from src[2_0]\n    ld1       {v6.2s, v7.2s}, [x0], #16 // Vector load from src[3_0]\n    ld1       {v15.2s}, [x0], x2        // Vector load from src[3_0]\n    ld1       {v8.2s, v9.2s}, [x0], #16 // Vector load from src[4_0]\n    ld1       {v16.2s}, [x0], x2        // Vector load from src[4_0]\nloop_16:\n\n    ld1       {v10.2s, v11.2s}, [x0], #16 // Vector load from src[5_0]\n    ld1       {v17.2s}, [x0], x2        // Vector load from src[5_0]\n\n\n    uaddl     v20.8h, v4.8b, v6.8b\n    uaddl     v18.8h, v0.8b, v10.8b\n    uaddl     v22.8h, v2.8b, v8.8b\n    mla       v18.8h, v20.8h , v28.8h\n    uaddl     v24.8h, v5.8b, v7.8b\n    uaddl     v20.8h, v1.8b, v11.8b\n    uaddl     v26.8h, v3.8b, v9.8b\n    mla       v20.8h, v24.8h , v28.8h\n    uaddl     v24.8h, v14.8b, v15.8b\n    mls       v18.8h, v22.8h , v30.8h\n    uaddl     v22.8h, v12.8b, v17.8b\n    mls       v20.8h, v26.8h , v30.8h\n    uaddl     v26.8h, v13.8b, v16.8b\n    mla       v22.8h, v24.8h , v28.8h\n    mls       v22.8h, v26.8h , v30.8h\n\n    ext       v24.16b, v18.16b , v20.16b , #4\n    ext       v26.16b, v18.16b , v20.16b , #6\n\n    ext       v23.16b, v18.16b , v20.16b , #10\n    add       v0.8h, v24.8h , v26.8h\n    ext       v24.16b, v18.16b , v20.16b , #2\n    ext       v26.16b, v18.16b , v20.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v18.4h, v23.4h\n    smlal     v26.4s, v0.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v23.4s, v18.8h, v23.8h\n    smlal2    v23.4s, v0.8h, v28.8h\n    smlsl2    v23.4s, v24.8h, v30.8h\n\n    sqrshrun  v18.4h, v26.4s, #10\n    sqrshrun  v19.4h, v23.4s, #10\n\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n    ext       v24.16b, v20.16b , v22.16b , #4\n    ext       v26.16b, v20.16b , v22.16b , #6\n    ext       v0.16b, v20.16b , v22.16b , #10\n\n    add       v25.8h, v24.8h , v26.8h\n    ext       v24.16b, v20.16b , v22.16b , #2\n    ext       v26.16b, v20.16b , v22.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v0.4h, v20.4h\n    smlal     v26.4s, v25.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v0.8h, v20.8h\n    smlal2    v22.4s, v25.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    sqrshrun  v19.4h, v26.4s, #10\n    sqrshrun  v25.4h, v22.4s, #10\n\n    uaddl     v24.8h, v7.8b, v9.8b\n\n\n\n    uqxtn     v19.8b, v19.8h\n    uqxtn     v25.8b, v25.8h\n    mov       v19.s[1], v25.s[0]\n\n    uaddl     v22.8h, v4.8b, v10.8b\n    ld1       {v0.2s, v1.2s}, [x0], #16 // Vector load from src[6_0]\n\n\n    ld1       {v12.2s}, [x0], x2        // Vector load from src[6_0]\n    uaddl     v20.8h, v6.8b, v8.8b\n    uaddl     v26.8h, v5.8b, v11.8b\n    st1       {v18.2s, v19.2s}, [x1], x3 // store row 0\n\n\n//ROW_2\n\n\n    uaddl     v18.8h, v2.8b, v0.8b\n\n    mla       v18.8h, v20.8h , v28.8h\n\n    uaddl     v20.8h, v3.8b, v1.8b\n\n    mla       v20.8h, v24.8h , v28.8h\n    uaddl     v24.8h, v15.8b, v16.8b\n    mls       v18.8h, v22.8h , v30.8h\n    uaddl     v22.8h, v13.8b, v12.8b\n    mls       v20.8h, v26.8h , v30.8h\n    uaddl     v26.8h, v14.8b, v17.8b\n    mla       v22.8h, v24.8h , v28.8h\n    mls       v22.8h, v26.8h , v30.8h\n\n    ext       v24.16b, v18.16b , v20.16b , #4\n    ext       v26.16b, v18.16b , v20.16b , #6\n\n    ext       v23.16b, v18.16b , v20.16b , #10\n    add       v2.8h, v24.8h , v26.8h\n    ext       v24.16b, v18.16b , v20.16b , #2\n    ext       v26.16b, v18.16b , v20.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v18.4h, v23.4h\n    smlal     v26.4s, v2.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v23.4s, v18.8h, v23.8h\n    smlal2    v23.4s, v2.8h, v28.8h\n    smlsl2    v23.4s, v24.8h, v30.8h\n\n    sqrshrun  v18.4h, v26.4s, #10\n    sqrshrun  v19.4h, v23.4s, #10\n\n\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n    ext       v24.16b, v20.16b , v22.16b , #4\n    ext       v26.16b, v20.16b , v22.16b , #6\n    ext       v2.16b, v20.16b , v22.16b , #10\n\n    add       v25.8h, v24.8h , v26.8h\n    ext       v24.16b, v20.16b , v22.16b , #2\n    ext       v26.16b, v20.16b , v22.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v2.4h, v20.4h\n    smlal     v26.4s, v25.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v2.8h, v20.8h\n    smlal2    v22.4s, v25.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    sqrshrun  v19.4h, v26.4s, #10\n    sqrshrun  v25.4h, v22.4s, #10\n    uaddl     v24.8h, v9.8b, v11.8b\n\n    uqxtn     v19.8b, v19.8h\n    uqxtn     v25.8b, v25.8h\n    mov       v19.s[1], v25.s[0]\n\n\n    uaddl     v22.8h, v6.8b, v0.8b\n    ld1       {v2.2s, v3.2s}, [x0], #16 // Vector load from src[7_0]\n\n\n    ld1       {v13.2s}, [x0], x2        // Vector load from src[7_0]\n    uaddl     v20.8h, v8.8b, v10.8b\n    uaddl     v26.8h, v7.8b, v1.8b\n    st1       {v18.2s, v19.2s}, [x1], x3 // store row 1\n\n//ROW_3\n\n\n    uaddl     v18.8h, v4.8b, v2.8b\n\n    mla       v18.8h, v20.8h , v28.8h\n\n    uaddl     v20.8h, v5.8b, v3.8b\n\n    mla       v20.8h, v24.8h , v28.8h\n    uaddl     v24.8h, v16.8b, v17.8b\n    mls       v18.8h, v22.8h , v30.8h\n    uaddl     v22.8h, v14.8b, v13.8b\n    mls       v20.8h, v26.8h , v30.8h\n    uaddl     v26.8h, v15.8b, v12.8b\n    mla       v22.8h, v24.8h , v28.8h\n    mls       v22.8h, v26.8h , v30.8h\n\n    ext       v24.16b, v18.16b , v20.16b , #4\n    ext       v26.16b, v18.16b , v20.16b , #6\n\n    ext       v23.16b, v18.16b , v20.16b , #10\n    add       v4.8h, v24.8h , v26.8h\n    ext       v24.16b, v18.16b , v20.16b , #2\n    ext       v26.16b, v18.16b , v20.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v18.4h, v23.4h\n    smlal     v26.4s, v4.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v23.4s, v18.8h, v23.8h\n    smlal2    v23.4s, v4.8h, v28.8h\n    smlsl2    v23.4s, v24.8h, v30.8h\n\n    sqrshrun  v18.4h, v26.4s, #10\n    sqrshrun  v19.4h, v23.4s, #10\n\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n\n    ext       v24.16b, v20.16b , v22.16b , #4\n    ext       v26.16b, v20.16b , v22.16b , #6\n    ext       v4.16b, v20.16b , v22.16b , #10\n\n    add       v25.8h, v24.8h , v26.8h\n    ext       v24.16b, v20.16b , v22.16b , #2\n    ext       v26.16b, v20.16b , v22.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v4.4h, v20.4h\n    smlal     v26.4s, v25.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v4.8h, v20.8h\n    smlal2    v22.4s, v25.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    sqrshrun  v19.4h, v26.4s, #10\n    sqrshrun  v25.4h, v22.4s, #10\n\n    uaddl     v24.8h, v11.8b, v1.8b\n\n\n    uqxtn     v19.8b, v19.8h\n    uqxtn     v25.8b, v25.8h\n    mov       v19.s[1], v25.s[0]\n\n\n\n    uaddl     v22.8h, v8.8b, v2.8b\n    ld1       {v4.2s, v5.2s}, [x0], #16 // Vector load from src[8_0]\n\n\n    ld1       {v14.2s}, [x0], x2        // Vector load from src[8_0]\n    uaddl     v20.8h, v10.8b, v0.8b\n    uaddl     v26.8h, v9.8b, v3.8b\n    st1       {v18.2s, v19.2s}, [x1], x3 // store row 2\n\n\n//ROW_4\n\n    uaddl     v18.8h, v6.8b, v4.8b\n\n    mla       v18.8h, v20.8h , v28.8h\n\n    uaddl     v20.8h, v7.8b, v5.8b\n\n    mla       v20.8h, v24.8h , v28.8h\n    uaddl     v24.8h, v17.8b, v12.8b\n    mls       v18.8h, v22.8h , v30.8h\n    uaddl     v22.8h, v15.8b, v14.8b\n    mls       v20.8h, v26.8h , v30.8h\n    uaddl     v26.8h, v16.8b, v13.8b\n    mla       v22.8h, v24.8h , v28.8h\n    mls       v22.8h, v26.8h , v30.8h\n\n    ext       v24.16b, v18.16b , v20.16b , #4\n    ext       v26.16b, v18.16b , v20.16b , #6\n\n    ext       v23.16b, v18.16b , v20.16b , #10\n    add       v6.8h, v24.8h , v26.8h\n    ext       v24.16b, v18.16b , v20.16b , #2\n    ext       v26.16b, v18.16b , v20.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v18.4h, v23.4h\n    smlal     v26.4s, v6.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v23.4s, v18.8h, v23.8h\n    smlal2    v23.4s, v6.8h, v28.8h\n    smlsl2    v23.4s, v24.8h, v30.8h\n\n    sqrshrun  v18.4h, v26.4s, #10\n    sqrshrun  v19.4h, v23.4s, #10\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n\n    ext       v24.16b, v20.16b , v22.16b , #4\n    ext       v26.16b, v20.16b , v22.16b , #6\n    ext       v6.16b, v20.16b , v22.16b , #10\n\n    add       v25.8h, v24.8h , v26.8h\n    ext       v24.16b, v20.16b , v22.16b , #2\n    ext       v26.16b, v20.16b , v22.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v6.4h, v20.4h\n    smlal     v26.4s, v25.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v6.8h, v20.8h\n    smlal2    v22.4s, v25.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    mov       v6.16b, v2.16b\n    mov       v7.16b, v3.16b\n\n    mov       v2.16b, v10.16b\n    mov       v3.16b, v11.16b\n\n    subs      x4, x4, #4\n    sqrshrun  v19.4h, v26.4s, #10\n    sqrshrun  v25.4h, v22.4s, #10\n    mov       v10.16b, v0.16b\n    mov       v11.16b, v1.16b\n\n    mov       v24.8b, v14.8b\n\n    mov       v14.16b, v12.16b\n    mov       v15.16b, v13.16b\n\n\n    uqxtn     v19.8b, v19.8h\n    uqxtn     v25.8b, v25.8h\n    mov       v19.s[1], v25.s[0]\n\n\n\n    mov       v0.16b, v8.16b\n    mov       v1.16b, v9.16b\n\n    mov       v8.16b, v4.16b\n    mov       v9.16b, v5.16b\n\n    mov       v12.16b, v16.16b\n    mov       v13.16b, v17.16b\n\n    mov       v4.16b, v10.16b\n    mov       v5.16b, v11.16b\n\n    mov       v16.8b, v24.8b\n    st1       {v18.2s, v19.2s}, [x1], x3 // store row 3\n\n    bgt       loop_16                   // looping if height =16\n    b         end_func\n\nloop_8_start:\n    ld1       {v0.2s, v1.2s}, [x0], x2  // Vector load from src[0_0]\n    ld1       {v2.2s, v3.2s}, [x0], x2  // Vector load from src[1_0]\n    ld1       {v4.2s, v5.2s}, [x0], x2  // Vector load from src[2_0]\n    ld1       {v6.2s, v7.2s}, [x0], x2  // Vector load from src[3_0]\n    ld1       {v8.2s, v9.2s}, [x0], x2  // Vector load from src[4_0]\n\nloop_8:\n\n    ld1       {v10.2s, v11.2s}, [x0], x2 // Vector load from src[5_0]\n    uaddl     v14.8h, v4.8b, v6.8b\n    uaddl     v12.8h, v0.8b, v10.8b\n    uaddl     v16.8h, v2.8b, v8.8b\n    mla       v12.8h, v14.8h , v26.8h\n    uaddl     v18.8h, v5.8b, v7.8b\n    uaddl     v14.8h, v1.8b, v11.8b\n    uaddl     v22.8h, v3.8b, v9.8b\n    mla       v14.8h, v18.8h , v26.8h\n    mls       v12.8h, v16.8h , v24.8h\n    ld1       {v0.2s, v1.2s}, [x0], x2  // Vector load from src[6_0]\n    uaddl     v16.8h, v6.8b, v8.8b\n    mls       v14.8h, v22.8h , v24.8h\n    uaddl     v28.8h, v2.8b, v0.8b\n\n    ext       v22.16b, v12.16b , v14.16b , #10\n    uaddl     v18.8h, v4.8b, v10.8b\n    mla       v28.8h, v16.8h , v26.8h\n    saddl     v30.4s, v12.4h, v22.4h\n\n    saddl2    v22.4s, v12.8h, v22.8h\n    ext       v16.16b, v12.16b , v14.16b , #4\n    mls       v28.8h, v18.8h , v24.8h\n    ext       v18.16b, v12.16b , v14.16b , #6\n    ext       v20.16b, v12.16b , v14.16b , #8\n    ext       v14.16b, v12.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v14.8h , v20.8h\n    uaddl     v20.8h, v7.8b, v9.8b\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal2    v22.4s, v16.8h, v26.8h\n    smlsl2    v22.4s, v18.8h, v24.8h\n    uaddl     v14.8h, v3.8b, v1.8b\n\n    mla       v14.8h, v20.8h , v26.8h\n    sqrshrun  v12.4h, v30.4s, #10\n    uaddl     v16.8h, v5.8b, v11.8b\n    sqrshrun  v13.4h, v22.4s, #10\n    mls       v14.8h, v16.8h , v24.8h\n    ld1       {v2.2s, v3.2s}, [x0], x2  // Vector load from src[7_0]\n    uqxtn     v25.8b, v12.8h\n    uqxtn     v13.8b, v13.8h\n    mov       v25.s[1], v13.s[0]\n    uaddl     v16.8h, v8.8b, v10.8b\n\n\n    ext       v22.16b, v28.16b , v14.16b , #10\n    uaddl     v20.8h, v4.8b, v2.8b\n    saddl     v30.4s, v28.4h, v22.4h\n    mla       v20.8h, v16.8h , v26.8h\n\n    saddl2    v22.4s, v28.8h, v22.8h\n    ext       v16.16b, v28.16b , v14.16b , #4\n    ext       v18.16b, v28.16b , v14.16b , #6\n    ext       v12.16b, v28.16b , v14.16b , #8\n    ext       v14.16b, v28.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v12.8h , v14.8h\n\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal2    v22.4s, v16.8h, v26.8h\n    smlsl2    v22.4s, v18.8h, v24.8h\n\n\n    uaddl     v18.8h, v6.8b, v0.8b\n    sqrshrun  v16.4h, v30.4s, #10\n\n    sqrshrun  v17.4h, v22.4s, #10\n\n    mov       v12.8b, v25.8b\n    mov       v25.8b, v24.8b\n\n    uaddl     v28.8h, v9.8b, v11.8b\n    uqxtn     v13.8b, v16.8h\n    uqxtn     v17.8b, v17.8h\n    mov       v13.s[1], v17.s[0]\n\n\n    uaddl     v14.8h, v5.8b, v3.8b\n    uaddl     v22.8h, v7.8b, v1.8b\n    mls       v20.8h, v18.8h , v24.8h\n    st1       {v12.2s}, [x1], x3        // store row 0\n    mla       v14.8h, v28.8h , v26.8h\n    ld1       {v4.2s, v5.2s}, [x0], x2  // Vector load from src[8_0]\n    uaddl     v30.8h, v10.8b, v0.8b\n    uaddl     v28.8h, v6.8b, v4.8b\n    mls       v14.8h, v22.8h , v24.8h\n    st1       {v13.2s}, [x1], x3        // store row 1\n    mla       v28.8h, v30.8h , v26.8h\n\n    ext       v22.16b, v20.16b , v14.16b , #10\n    saddl     v30.4s, v20.4h, v22.4h\n\n    saddl2    v22.4s, v20.8h, v22.8h\n    ext       v16.16b, v20.16b , v14.16b , #4\n    ext       v18.16b, v20.16b , v14.16b , #6\n    ext       v12.16b, v20.16b , v14.16b , #8\n    ext       v14.16b, v20.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v14.8h , v12.8h\n    uaddl     v20.8h, v8.8b, v2.8b\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal2    v22.4s, v16.8h, v26.8h\n    smlsl2    v22.4s, v18.8h, v24.8h\n    uaddl     v18.8h, v11.8b, v1.8b\n    uaddl     v16.8h, v7.8b, v5.8b\n    sqrshrun  v12.4h, v30.4s, #10\n    uaddl     v30.8h, v9.8b, v3.8b\n    mla       v16.8h, v18.8h , v26.8h\n    sqrshrun  v13.4h, v22.4s, #10\n    mls       v28.8h, v20.8h , v24.8h\n\n    mls       v16.8h, v30.8h , v24.8h\n    uqxtn     v27.8b, v12.8h\n    uqxtn     v13.8b, v13.8h\n    mov       v27.s[1], v13.s[0]\n\n\n    ext       v22.16b, v28.16b , v16.16b , #10\n\n    saddl     v30.4s, v28.4h, v22.4h\n\n    saddl2    v22.4s, v28.8h, v22.8h\n    ext       v12.16b, v28.16b , v16.16b , #4\n    ext       v18.16b, v28.16b , v16.16b , #6\n    ext       v20.16b, v28.16b , v16.16b , #8\n    ext       v28.16b, v28.16b , v16.16b , #2\n    add       v12.8h, v12.8h , v18.8h\n    add       v18.8h, v28.8h , v20.8h\n\n    smlal     v30.4s, v12.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal2    v22.4s, v12.8h, v26.8h\n    smlsl2    v22.4s, v18.8h, v24.8h\n\n\n    mov       v12.8b, v27.8b\n    mov       v27.8b, v26.8b\n\n    sqrshrun  v16.4h, v30.4s, #10\n\n    mov       v6.16b, v2.16b\n    mov       v7.16b, v3.16b\n\n    sqrshrun  v17.4h, v22.4s, #10\n\n    mov       v2.16b, v10.16b\n    mov       v3.16b, v11.16b\n\n    mov       v10.16b, v0.16b\n    mov       v11.16b, v1.16b\n\n    subs      x4, x4, #4\n    uqxtn     v13.8b, v16.8h\n    uqxtn     v17.8b, v17.8h\n    mov       v13.s[1], v17.s[0]\n\n\n    mov       v0.16b, v8.16b\n    mov       v1.16b, v9.16b\n\n    mov       v8.16b, v4.16b\n    mov       v9.16b, v5.16b\n\n    mov       v4.16b, v10.16b\n    mov       v5.16b, v11.16b\n\n    st1       {v12.2s}, [x1], x3        // store row 2\n    st1       {v13.2s}, [x1], x3        // store row 3\n\n    bgt       loop_8                    //if height =8  loop\n    b         end_func\n\nloop_4_start:\n    ld1       {v0.2s, v1.2s}, [x0], x2  // Vector load from src[0_0]\n    ld1       {v2.2s, v3.2s}, [x0], x2  // Vector load from src[1_0]\n    ld1       {v4.2s, v5.2s}, [x0], x2  // Vector load from src[2_0]\n    ld1       {v6.2s, v7.2s}, [x0], x2  // Vector load from src[3_0]\n    ld1       {v8.2s, v9.2s}, [x0], x2  // Vector load from src[4_0]\n\nloop_4:\n    ld1       {v10.2s, v11.2s}, [x0], x2 // Vector load from src[5_0]\n    uaddl     v14.8h, v4.8b, v6.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v12.8h, v0.8b, v10.8b     // temp = src[0_0] + src[5_0]\n    uaddl     v16.8h, v2.8b, v8.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v12.8h, v14.8h , v26.8h   // temp += temp1 * 20\n    uaddl     v18.8h, v5.8b, v7.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v14.8h, v1.8b, v11.8b     // temp = src[0_0] + src[5_0]\n    uaddl     v22.8h, v3.8b, v9.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v14.8h, v18.8h , v26.8h   // temp += temp1 * 20\n    mls       v12.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    ld1       {v0.2s, v1.2s}, [x0], x2  // Vector load from src[6_0]\n    uaddl     v16.8h, v6.8b, v8.8b\n    mls       v14.8h, v22.8h , v24.8h   // temp -= temp2 * 5\n    //Q6 and Q7 have filtered values\n    uaddl     v28.8h, v2.8b, v0.8b\n\n    ext       v22.16b, v12.16b , v14.16b , #10\n    uaddl     v18.8h, v4.8b, v10.8b\n    mla       v28.8h, v16.8h , v26.8h\n    saddl     v30.4s, v12.4h, v22.4h\n\n    saddl     v22.4s, v13.4h, v23.4h\n    ext       v16.16b, v12.16b , v14.16b , #4\n    mls       v28.8h, v18.8h , v24.8h\n    ext       v18.16b, v12.16b , v14.16b , #6\n    ext       v20.16b, v12.16b , v14.16b , #8\n    ext       v14.16b, v12.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v14.8h , v20.8h\n    uaddl     v20.8h, v7.8b, v9.8b\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal     v22.4s, v17.4h, v26.4h\n    smlsl     v22.4s, v19.4h, v24.4h\n    uaddl     v14.8h, v3.8b, v1.8b\n\n    mla       v14.8h, v20.8h , v26.8h\n    sqrshrun  v12.4h, v30.4s, #10\n    uaddl     v16.8h, v5.8b, v11.8b\n    sqrshrun  v13.4h, v22.4s, #10\n    mls       v14.8h, v16.8h , v24.8h\n    ld1       {v2.2s, v3.2s}, [x0], x2  // Vector load from src[7_0]\n    uqxtn     v25.8b, v12.8h\n    uaddl     v16.8h, v8.8b, v10.8b\n\n    ext       v22.16b, v28.16b , v14.16b , #10\n    uaddl     v20.8h, v4.8b, v2.8b\n    saddl     v30.4s, v28.4h, v22.4h\n    mla       v20.8h, v16.8h , v26.8h\n\n    saddl     v22.4s, v29.4h, v23.4h\n    ext       v16.16b, v28.16b , v14.16b , #4\n    ext       v18.16b, v28.16b , v14.16b , #6\n    ext       v12.16b, v28.16b , v14.16b , #8\n    ext       v14.16b, v28.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v12.8h , v14.8h\n\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal     v22.4s, v17.4h, v26.4h\n    smlsl     v22.4s, v19.4h, v24.4h\n\n\n    uaddl     v18.8h, v6.8b, v0.8b\n    sqrshrun  v16.4h, v30.4s, #10\n\n    sqrshrun  v17.4h, v22.4s, #10\n\n    mov       v12.8b, v25.8b\n    mov       v25.8b, v24.8b\n\n    uaddl     v28.8h, v9.8b, v11.8b\n    uqxtn     v13.8b, v16.8h\n\n\n\n    uaddl     v14.8h, v5.8b, v3.8b\n    uaddl     v22.8h, v7.8b, v1.8b\n    mls       v20.8h, v18.8h , v24.8h\n    st1       {v12.s}[0], [x1], x3      // store row 0\n    mla       v14.8h, v28.8h , v26.8h\n    ld1       {v4.2s, v5.2s}, [x0], x2  // Vector load from src[8_0]\n    uaddl     v30.8h, v10.8b, v0.8b\n    uaddl     v28.8h, v6.8b, v4.8b\n    mls       v14.8h, v22.8h , v24.8h\n    st1       {v13.s}[0], [x1], x3      //store row 1\n    mla       v28.8h, v30.8h , v26.8h\n\n    ext       v22.16b, v20.16b , v14.16b , #10\n    saddl     v30.4s, v20.4h, v22.4h\n\n    saddl     v22.4s, v21.4h, v23.4h\n    ext       v16.16b, v20.16b , v14.16b , #4\n    ext       v18.16b, v20.16b , v14.16b , #6\n    ext       v12.16b, v20.16b , v14.16b , #8\n    ext       v14.16b, v20.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v14.8h , v12.8h\n    uaddl     v20.8h, v8.8b, v2.8b\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal     v22.4s, v17.4h, v26.4h\n    smlsl     v22.4s, v19.4h, v24.4h\n    uaddl     v18.8h, v11.8b, v1.8b\n    uaddl     v16.8h, v7.8b, v5.8b\n    sqrshrun  v12.4h, v30.4s, #10\n    uaddl     v30.8h, v9.8b, v3.8b\n    mla       v16.8h, v18.8h , v26.8h\n    sqrshrun  v13.4h, v22.4s, #10\n    mls       v28.8h, v20.8h , v24.8h\n\n    mls       v16.8h, v30.8h , v24.8h\n    uqxtn     v27.8b, v12.8h\n\n    ext       v22.16b, v28.16b , v16.16b , #10\n\n    saddl     v30.4s, v28.4h, v22.4h\n\n    saddl     v22.4s, v29.4h, v23.4h\n    ext       v12.16b, v28.16b , v16.16b , #4\n    ext       v18.16b, v28.16b , v16.16b , #6\n    ext       v20.16b, v28.16b , v16.16b , #8\n    ext       v28.16b, v28.16b , v16.16b , #2\n    add       v12.8h, v12.8h , v18.8h\n    add       v18.8h, v28.8h , v20.8h\n\n    smlal     v30.4s, v12.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal     v22.4s, v13.4h, v26.4h\n    smlsl     v22.4s, v19.4h, v24.4h\n\n\n    mov       v12.8b, v27.8b\n    mov       v27.8b, v26.8b\n\n    sqrshrun  v16.4h, v30.4s, #10\n\n    mov       v6.16b, v2.16b\n    mov       v7.16b, v3.16b\n\n    sqrshrun  v17.4h, v22.4s, #10\n\n    mov       v2.16b, v10.16b\n    mov       v3.16b, v11.16b\n\n    mov       v10.16b, v0.16b\n    mov       v11.16b, v1.16b\n\n    subs      x4, x4, #4\n    uqxtn     v13.8b, v16.8h\n\n    mov       v0.16b, v8.16b\n    mov       v1.16b, v9.16b\n\n    mov       v8.16b, v4.16b\n    mov       v9.16b, v5.16b\n\n\n    mov       v4.16b, v10.16b\n    mov       v5.16b, v11.16b\n\n\n    st1       {v12.s}[0], [x1], x3      // store row 2\n    st1       {v13.s}[0], [x1], x3      // store row 3\n\n    bgt       loop_4\n\nend_func:\n    //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_inter_pred_luma_horz_hpel_vert_qpel_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_inter_pred_luma_horz_hpel_vert_qpel_av8.s\n//*\n//* @brief\n//*  Contains function definitions for inter prediction  interpolation.\n//*\n//* @author\n//*  Mohit\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_inter_pred_luma_horz_hpel_vert_qpel_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_inter_pred_filters.c\n//\n\n///**\n///**\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*   This function implements a two stage cascaded six tap filter. It\n//*    applies the six tap filter in the horizontal direction on the\n//*    predictor values, followed by applying the same filter in the\n//*    vertical direction on the output of the first stage. It then averages\n//*    the output of the 1st stage and the output of the 2nd stage to obtain\n//*    the quarter pel values. The six tap filtering operation is described\n//*    in sec 8.4.2.2.1 titled \"Luma sample interpolation process\".\n//*\n//* @par Description:\n//*     This function is called to obtain pixels lying at the following\n//*    location (1/2,1/4) or (1/2,3/4). The function interpolates\n//*    the predictors first in the horizontal direction and then in the\n//*    vertical direction to output the (1/2,1/2). It then averages\n//*      the output of the 2nd stage and (1/2,1/2) value to obtain (1/2,1/4)\n//*       or (1/2,3/4) depending on the offset.\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @param[in] pu1_tmp: temporary buffer\n//*\n//* @param[in] dydx: x and y reference offset for qpel calculations\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/;\n\n//void ih264_inter_pred_luma_horz_hpel_vert_qpel(UWORD8 *pu1_src,\n//                                UWORD8 *pu1_dst,\n//                                WORD32 src_strd,,\n//                                WORD32 dst_strd,\n//                                WORD32 ht,\n//                                WORD32 wd,\n//                                    UWORD8* pu1_tmp,\n//                                  UWORD32 dydx)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ht\n//    w5 =>  wd\n//    x6 => *pu1_tmp\n//    w7 =>  dydx\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_inter_pred_luma_horz_hpel_vert_qpel_av8\n\nih264_inter_pred_luma_horz_hpel_vert_qpel_av8:\n\n\n    // store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x2, w2\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n\n\n\n    sub       x0, x0, x2, lsl #1        // pu1_src-2*src_strd\n    sub       x0, x0, #2                // pu1_src-2\n\n    mov       x9, x6\n\n                                        // by writing to w7 here, we clear the upper half of x7\n    lsr       w7, w7, #3                // dydx >> 2 followed by dydx & 0x3 and dydx>>1 to obtain the deciding bit\n\n    add       x7, x7, #2\n    mov       x6, #48\n    madd      x7, x7, x6, x9\n\n    subs      x12, x5, #4               //if wd=4 branch to loop_4\n    beq       loop_4_start\n\n    subs      x12, x5, #8               //if wd=8 branch to loop_8\n    beq       loop_8_start\n\n    //when  wd=16\n    movi      v22.8h, #20               // Filter coeff 0x14 into Q11\n    movi      v24.8h, #5                // Filter coeff 0x5  into Q12\n    add       x8, x0, #8\n    add       x14, x1, #8\n    add       x10, x9, #8\n    mov       x12, x4\n    add       x11, x7, #8\nloop_16_lowhalf_start:\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row -2 load for horizontal filter\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v6.8h, v0.8b, v5.8b\n\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v8.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v6.8h, v8.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v8.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row -1 load for horizontal filter\n    mls       v6.8h, v8.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v8.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v10.8h, v2.8b, v3.8b\n\n    st1       {v6.4s}, [x9], x6         // store temp buffer 0\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v8.8h, v10.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v10.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 0 load for horizontal filter\n    mls       v8.8h, v10.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v10.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v12.8h, v2.8b, v3.8b\n\n    st1       {v8.4s}, [x9], x6         // store temp buffer 1\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v10.8h, v12.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v12.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 1 load for horizontal filter\n    mls       v10.8h, v12.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v12.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v14.8h, v2.8b, v3.8b\n\n    st1       {v10.4s}, [x9], x6        // store temp buffer 2\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v12.8h, v14.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v14.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 2 load for horizontal filter\n    mls       v12.8h, v14.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v14.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v16.8h, v2.8b, v3.8b\n\n    st1       {v12.4s}, [x9], x6        // store temp buffer 3\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v14.8h, v16.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v16.8h, v1.8b, v4.8b\n\n    mls       v14.8h, v16.8h , v24.8h\nloop_16_lowhalf:\n\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 3 load for horizontal filter\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v16.8h, v0.8b, v5.8b\n\n    st1       {v14.4s}, [x9], x6        // store temp buffer 4\n\n    uaddl     v18.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v16.8h, v18.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    add       v28.8h, v8.8h , v14.8h\n    uaddl     v18.8h, v1.8b, v4.8b\n    add       v30.8h, v10.8h , v12.8h\n    mls       v16.8h, v18.8h , v24.8h\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 4 load for hoorizontal filter\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v20.8h, v0.8b, v5.8b\n\n    st1       {v16.4s}, [x9], x6        // store temp buffer x5\n\n    saddl     v18.4s, v6.4h, v16.4h\n\n    ld1       {v26.4s}, [x7], x6        // load from temp buffer 0\n\n    saddl2    v6.4s, v6.8h, v16.8h\n\n    sqrshrun  v26.8b, v26.8h, #5\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v28.4h, v24.4h\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v28.8h, v24.8h\n    uaddl     v2.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v20.8h, v2.8h , v22.8h\n    sqrshrun  v18.4h, v18.4s, #10\n    ext       v1.8b, v0.8b , v1.8b , #1\n    sqrshrun  v19.4h, v6.4s, #10\n    add       v28.8h, v10.8h , v16.8h\n    uaddl     v2.8h, v1.8b, v4.8b\n    add       v30.8h, v12.8h , v14.8h\n    mls       v20.8h, v2.8h , v24.8h\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 5 load for horizontal filter\n\n    urhadd    v26.8b, v18.8b , v26.8b\n\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n\n    st1       {v20.4s}, [x9], x6        // store temp buffer x6\n\n    saddl     v18.4s, v8.4h, v20.4h\n\n    saddl2    v6.4s, v8.8h, v20.8h\n\n    ld1       {v8.4s}, [x7], x6         //load from temp buffer 1\n\n\n    st1       {v26.2s}, [x1], x3        // store row 0\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v28.4h, v24.4h\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v28.8h, v24.8h\n\n    sqrshrun  v28.8b, v8.8h, #5\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v8.8h, v0.8b, v5.8b\n    uaddl     v2.8h, v2.8b, v3.8b\n    sqrshrun  v18.4h, v18.4s, #10\n    ext       v4.8b, v0.8b , v1.8b , #4\n    sqrshrun  v19.4h, v6.4s, #10\n    mla       v8.8h, v2.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    add       v26.8h, v12.8h , v20.8h\n    uaddl     v2.8h, v1.8b, v4.8b\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n    add       v30.8h, v14.8h , v16.8h\n    mls       v8.8h, v2.8h , v24.8h\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 6 load for horizontal filter\n\n    urhadd    v28.8b, v28.8b , v18.8b\n\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n\n    st1       {v28.2s}, [x1], x3        // store row 1\n\n    uaddl     v28.8h, v0.8b, v5.8b\n\n    st1       {v8.4s}, [x9], x6         // store temp buffer x7\n\n    saddl     v18.4s, v10.4h, v8.4h\n    saddl2    v6.4s, v10.8h, v8.8h\n\n    ld1       {v10.4s}, [x7], x6        // load from temp buffer 2\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v26.4h, v24.4h\n\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v26.8h, v24.8h\n\n    sqrshrun  v26.8b, v10.8h, #5\n\n    uaddl     v2.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v28.8h, v2.8h , v22.8h\n    sqrshrun  v18.4h, v18.4s, #10\n    ext       v1.8b, v0.8b , v1.8b , #1\n    sqrshrun  v19.4h, v6.4s, #10\n    add       v10.8h, v14.8h , v8.8h\n    uaddl     v2.8h, v1.8b, v4.8b\n    add       v30.8h, v16.8h , v20.8h\n    mls       v28.8h, v2.8h , v24.8h\n    uqxtn     v27.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v27.s[1], v19.s[0]\n    saddl     v18.4s, v12.4h, v28.4h\n    saddl2    v6.4s, v12.8h, v28.8h\n\n    urhadd    v26.8b, v26.8b , v27.8b\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v10.4h, v24.4h\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v10.8h, v24.8h\n\n    st1       {v26.2s}, [x1], x3        // store row 2\n\n    st1       {v28.2s, v29.2s}, [x9]\n\n\n    sqrshrun  v18.4h, v18.4s, #10\n\n    mov       v10.16b, v20.16b\n    mov       v11.16b, v21.16b\n    ld1       {v30.4s}, [x7], x6        // load from temp buffer 3\n\n    sqrshrun  v19.4h, v6.4s, #10\n    subs      x4, x4, #4\n\n    sqrshrun  v30.8b, v30.8h, #5\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n    mov       v12.16b, v8.16b\n    mov       v13.16b, v9.16b\n    mov       v6.16b, v14.16b\n    mov       v7.16b, v15.16b\n\n    urhadd    v30.8b, v18.8b , v30.8b\n\n    mov       v8.16b, v16.16b\n    mov       v9.16b, v17.16b\n    mov       v14.16b, v28.16b\n    mov       v15.16b, v29.16b\n\n    st1       {v30.2s}, [x1], x3        // store row 3\n\n    bgt       loop_16_lowhalf           // looping if height =16\n\n\nloop_16_highhalf_start:\n    ld1       {v0.2s, v1.2s}, [x8], x2\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v6.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v8.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v6.8h, v8.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v8.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x8], x2\n    mls       v6.8h, v8.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v8.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v10.8h, v2.8b, v3.8b\n\n    st1       {v6.4s}, [x10], x6\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v8.8h, v10.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v10.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x8], x2\n    mls       v8.8h, v10.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v10.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v12.8h, v2.8b, v3.8b\n\n    st1       {v8.4s}, [x10], x6\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v10.8h, v12.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v12.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x8], x2\n    mls       v10.8h, v12.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v12.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v14.8h, v2.8b, v3.8b\n\n    st1       {v10.4s}, [x10], x6\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v12.8h, v14.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v14.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x8], x2\n    mls       v12.8h, v14.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v14.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v16.8h, v2.8b, v3.8b\n\n    st1       {v12.4s}, [x10], x6\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v14.8h, v16.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v16.8h, v1.8b, v4.8b\n\n    mls       v14.8h, v16.8h , v24.8h\n\nloop_16_highhalf:\n\n    ld1       {v0.2s, v1.2s}, [x8], x2\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v16.8h, v0.8b, v5.8b\n\n    st1       {v14.4s}, [x10], x6\n\n    uaddl     v18.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v16.8h, v18.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    add       v28.8h, v8.8h , v14.8h\n    uaddl     v18.8h, v1.8b, v4.8b\n    add       v30.8h, v10.8h , v12.8h\n    mls       v16.8h, v18.8h , v24.8h\n    ld1       {v0.2s, v1.2s}, [x8], x2\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v20.8h, v0.8b, v5.8b\n\n    st1       {v16.4s}, [x10], x6\n\n    saddl     v18.4s, v6.4h, v16.4h\n\n    ld1       {v26.4s}, [x11], x6\n\n    saddl2    v6.4s, v6.8h, v16.8h\n\n    sqrshrun  v26.8b, v26.8h, #5\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v28.4h, v24.4h\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v28.8h, v24.8h\n    uaddl     v2.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v20.8h, v2.8h , v22.8h\n    sqrshrun  v18.4h, v18.4s, #10\n    ext       v1.8b, v0.8b , v1.8b , #1\n    sqrshrun  v19.4h, v6.4s, #10\n    add       v28.8h, v10.8h , v16.8h\n    uaddl     v2.8h, v1.8b, v4.8b\n    add       v30.8h, v12.8h , v14.8h\n    mls       v20.8h, v2.8h , v24.8h\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n    ld1       {v0.2s, v1.2s}, [x8], x2\n\n    urhadd    v26.8b, v18.8b , v26.8b\n\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n\n    st1       {v20.4s}, [x10], x6\n\n    saddl     v18.4s, v8.4h, v20.4h\n    saddl2    v6.4s, v8.8h, v20.8h\n\n    ld1       {v8.4s}, [x11], x6\n\n\n    st1       {v26.2s}, [x14], x3       //store row 0\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v28.4h, v24.4h\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v28.8h, v24.8h\n    sqrshrun  v28.8b, v8.8h, #5\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v8.8h, v0.8b, v5.8b\n    uaddl     v2.8h, v2.8b, v3.8b\n    sqrshrun  v18.4h, v18.4s, #10\n    ext       v4.8b, v0.8b , v1.8b , #4\n    sqrshrun  v19.4h, v6.4s, #10\n    mla       v8.8h, v2.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    add       v26.8h, v12.8h , v20.8h\n    uaddl     v2.8h, v1.8b, v4.8b\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n    add       v30.8h, v14.8h , v16.8h\n    mls       v8.8h, v2.8h , v24.8h\n    ld1       {v0.2s, v1.2s}, [x8], x2\n\n    urhadd    v28.8b, v28.8b , v18.8b\n\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n\n    st1       {v28.2s}, [x14], x3       //store row 1\n\n    uaddl     v28.8h, v0.8b, v5.8b\n\n    st1       {v8.4s}, [x10], x6\n\n    saddl     v18.4s, v10.4h, v8.4h\n    saddl2    v6.4s, v10.8h, v8.8h\n\n    ld1       {v10.4s}, [x11], x6\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v26.4h, v24.4h\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v26.8h, v24.8h\n\n    sqrshrun  v26.8b, v10.8h, #5\n    uaddl     v2.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v28.8h, v2.8h , v22.8h\n    sqrshrun  v18.4h, v18.4s, #10\n    ext       v1.8b, v0.8b , v1.8b , #1\n    sqrshrun  v19.4h, v6.4s, #10\n    add       v10.8h, v14.8h , v8.8h\n    uaddl     v2.8h, v1.8b, v4.8b\n    add       v30.8h, v16.8h , v20.8h\n    mls       v28.8h, v2.8h , v24.8h\n    uqxtn     v27.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v27.s[1], v19.s[0]\n\n\n    saddl     v18.4s, v12.4h, v28.4h\n    saddl2    v6.4s, v12.8h, v28.8h\n\n    urhadd    v26.8b, v26.8b , v27.8b\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v10.4h, v24.4h\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v10.8h, v24.8h\n\n    st1       {v26.2s}, [x14], x3       // store row 2\n\n    st1       {v28.4s}, [x10]\n\n    sqrshrun  v18.4h, v18.4s, #10\n    mov       v10.16b, v20.16b\n    mov       v11.16b, v21.16b\n    ld1       {v30.4s}, [x11], x6\n\n    sqrshrun  v19.4h, v6.4s, #10\n    subs      x12, x12, #4\n\n    sqrshrun  v30.8b, v30.8h, #5\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n    mov       v12.16b, v8.16b\n    mov       v13.16b, v9.16b\n    mov       v6.16b, v14.16b\n    mov       v7.16b, v15.16b\n    urhadd    v30.8b, v18.8b , v30.8b\n\n    mov       v8.16b, v16.16b\n    mov       v9.16b, v17.16b\n    mov       v14.16b, v28.16b\n    mov       v15.16b, v29.16b\n    st1       {v30.2s}, [x14], x3       // store row 3\n\n    bgt       loop_16_highhalf          // looping if height = 8 or 16\n    b         end_func\n\nloop_8_start:\n\n    movi      v22.8h, #0x14             // Filter coeff 20 into Q11\n    movi      v24.8h, #5                // Filter coeff 5  into Q12\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row -2 load for horizontal filter\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v6.8h, v0.8b, v5.8b\n\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v8.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v6.8h, v8.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v8.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row -1 load for horizontal filter\n    mls       v6.8h, v8.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v8.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v10.8h, v2.8b, v3.8b\n\n    st1       {v6.4s}, [x9], x6         // store temp buffer 0\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v8.8h, v10.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v10.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 0 load for horizontal filter\n    mls       v8.8h, v10.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v10.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v12.8h, v2.8b, v3.8b\n\n    st1       {v8.4s}, [x9], x6         // store temp buffer 1\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v10.8h, v12.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v12.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 1 load for horizontal filter\n    mls       v10.8h, v12.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v12.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v14.8h, v2.8b, v3.8b\n\n    st1       {v10.4s}, [x9], x6        // store temp buffer 2\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v12.8h, v14.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v14.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 2 load for horizontal filter\n    mls       v12.8h, v14.8h , v24.8h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v14.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v16.8h, v2.8b, v3.8b\n\n    st1       {v12.4s}, [x9], x6        // store temp buffer 3\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v14.8h, v16.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v16.8h, v1.8b, v4.8b\n\n    mls       v14.8h, v16.8h , v24.8h\nloop_8:\n\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 3 load for horizontal filter\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v16.8h, v0.8b, v5.8b\n\n    st1       {v14.4s}, [x9], x6        // store temp buffer 4\n\n    uaddl     v18.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v16.8h, v18.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    add       v28.8h, v8.8h , v14.8h\n    uaddl     v18.8h, v1.8b, v4.8b\n    add       v30.8h, v10.8h , v12.8h\n    mls       v16.8h, v18.8h , v24.8h\n    ld1       {v0.2s, v1.2s}     , [x0], x2 // row 4 load for hoorizontal filter\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v20.8h, v0.8b, v5.8b\n\n    st1       {v16.4s}, [x9], x6        // store temp buffer x5\n\n    saddl     v18.4s, v6.4h, v16.4h\n\n    ld1       {v26.4s}, [x7], x6        // load from temp buffer 0\n\n    saddl2    v6.4s, v6.8h, v16.8h\n\n    sqrshrun  v26.8b, v26.8h, #5\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v28.4h, v24.4h\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v28.8h, v24.8h\n    uaddl     v2.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v20.8h, v2.8h , v22.8h\n    sqrshrun  v18.4h, v18.4s, #10\n    ext       v1.8b, v0.8b , v1.8b , #1\n    sqrshrun  v19.4h, v6.4s, #10\n    add       v28.8h, v10.8h , v16.8h\n    uaddl     v2.8h, v1.8b, v4.8b\n    add       v30.8h, v12.8h , v14.8h\n    mls       v20.8h, v2.8h , v24.8h\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 5 load for horizontal filter\n\n    urhadd    v26.8b, v18.8b , v26.8b\n\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n\n    st1       {v20.4s}, [x9], x6        // store temp buffer x6\n\n    saddl     v18.4s, v8.4h, v20.4h\n\n    saddl2    v6.4s, v8.8h, v20.8h\n\n    ld1       {v8.4s}, [x7], x6         //load from temp buffer 1\n\n\n    st1       {v26.2s}, [x1], x3        // store row 0\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v28.4h, v24.4h\n\n\n\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v28.8h, v24.8h\n\n    sqrshrun  v28.8b, v8.8h, #5\n\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v8.8h, v0.8b, v5.8b\n    uaddl     v2.8h, v2.8b, v3.8b\n    sqrshrun  v18.4h, v18.4s, #10\n    ext       v4.8b, v0.8b , v1.8b , #4\n    sqrshrun  v19.4h, v6.4s, #10\n    mla       v8.8h, v2.8h , v22.8h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    add       v26.8h, v12.8h , v20.8h\n    uaddl     v2.8h, v1.8b, v4.8b\n\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n    add       v30.8h, v14.8h , v16.8h\n    mls       v8.8h, v2.8h , v24.8h\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 6 load for horizontal filter\n\n    urhadd    v28.8b, v28.8b , v18.8b\n\n    ext       v5.8b, v0.8b , v1.8b , #5\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n\n    st1       {v28.2s}, [x1], x3        // store row 1\n\n    uaddl     v28.8h, v0.8b, v5.8b\n\n    st1       {v8.4s}, [x9], x6         // store temp buffer x7\n\n    saddl     v18.4s, v10.4h, v8.4h\n    saddl2    v6.4s, v10.8h, v8.8h\n\n    ld1       {v10.4s}, [x7], x6        // load from temp buffer 2\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v26.4h, v24.4h\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v26.8h, v24.8h\n\n    sqrshrun  v26.8b, v10.8h, #5\n    uaddl     v2.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v28.8h, v2.8h , v22.8h\n    sqrshrun  v18.4h, v18.4s, #10\n    ext       v1.8b, v0.8b , v1.8b , #1\n    sqrshrun  v19.4h, v6.4s, #10\n    add       v10.8h, v14.8h , v8.8h\n    uaddl     v2.8h, v1.8b, v4.8b\n    add       v30.8h, v16.8h , v20.8h\n    mls       v28.8h, v2.8h , v24.8h\n\n    uqxtn     v27.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n\n    mov       v27.s[1], v19.s[0]\n\n    saddl     v18.4s, v12.4h, v28.4h\n    saddl2    v6.4s, v12.8h, v28.8h\n\n    urhadd    v26.8b, v26.8b , v27.8b\n\n    smlal     v18.4s, v30.4h, v22.4h\n    smlsl     v18.4s, v10.4h, v24.4h\n    smlal2    v6.4s, v30.8h, v22.8h\n    smlsl2    v6.4s, v10.8h, v24.8h\n\n    st1       {v26.2s}, [x1], x3        // store row 2\n\n    st1       {v28.2s, v29.2s}, [x9]\n\n\n    sqrshrun  v18.4h, v18.4s, #10\n    mov       v10.16b, v20.16b\n    mov       v11.16b, v21.16b\n    ld1       {v30.4s}, [x7], x6        // load from temp buffer 3\n\n    sqrshrun  v19.4h, v6.4s, #10\n    subs      x4, x4, #4\n\n    sqrshrun  v30.8b, v30.8h, #5\n\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n\n    mov       v12.16b, v8.16b\n    mov       v13.16b, v9.16b\n    mov       v6.16b, v14.16b\n    mov       v7.16b, v15.16b\n\n    urhadd    v30.8b, v18.8b , v30.8b\n    mov       v8.16b, v16.16b\n    mov       v9.16b, v17.16b\n    mov       v14.16b, v28.16b\n    mov       v15.16b, v29.16b\n    st1       {v30.2s}, [x1], x3        // store row 3\n\n    bgt       loop_8                    //if height =8 or 16  loop\n    b         end_func\n\nloop_4_start:\n    movi      v22.8h, #20               // Filter coeff 20 into D22\n    movi      v23.8h, #5                // Filter coeff 5  into D23\n\n    ld1       {v0.2s, v1.2s}, [x0], x2  //row -2 load\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v6.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v8.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v6.4h, v8.4h , v22.4h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v8.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row -1 load\n    mls       v6.4h, v8.4h , v23.4h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v8.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v10.8h, v2.8b, v3.8b\n\n    st1       {v6.2s}, [x9], x6         // store temp buffer 0\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v8.4h, v10.4h , v22.4h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v10.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 0 load\n    mls       v8.4h, v10.4h , v23.4h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v10.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v12.8h, v2.8b, v3.8b\n\n    st1       {v8.2s}, [x9], x6         // store temp buffer 1\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v10.4h, v12.4h , v22.4h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v12.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 1 load\n    mls       v10.4h, v12.4h , v23.4h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v12.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v14.8h, v2.8b, v3.8b\n\n    st1       {v10.2s}, [x9], x6        // store temp buffer 2\n\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v12.4h, v14.4h , v22.4h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v14.8h, v1.8b, v4.8b\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 2 load\n    mls       v12.4h, v14.4h , v23.4h\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v14.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v16.8h, v2.8b, v3.8b\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v14.4h, v16.4h , v22.4h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v16.8h, v1.8b, v4.8b\n\n    st1       {v12.2s}, [x9], x6        // store temp buffer 3\n\n    mls       v14.4h, v16.4h , v23.4h\n\nloop_4:\n\n    ld1       {v0.2s, v1.2s}, [x0], x2  // row 3 load\n    ext       v5.8b, v0.8b , v1.8b , #5\n    uaddl     v16.8h, v0.8b, v5.8b\n    ext       v2.8b, v0.8b , v1.8b , #2\n    ext       v3.8b, v0.8b , v1.8b , #3\n    uaddl     v18.8h, v2.8b, v3.8b\n    st1       {v14.2s}, [x9], x6        // store temp buffer 4\n    ext       v4.8b, v0.8b , v1.8b , #4\n    mla       v16.4h, v18.4h , v22.4h\n    ext       v1.8b, v0.8b , v1.8b , #1\n    uaddl     v18.8h, v1.8b, v4.8b\n    add       v2.4h, v10.4h , v12.4h\n    mls       v16.4h, v18.4h , v23.4h\n    add       v3.4h, v8.4h , v14.4h\n    ld1       {v18.2s, v19.2s}, [x0], x2 // row 4 load\n    ext       v25.8b, v18.8b , v19.8b , #5\n    uaddl     v26.8h, v18.8b, v25.8b\n    ext       v20.8b, v18.8b , v19.8b , #2\n\n    st1       {v16.2s}, [x9], x6        // store temp buffer 5\n\n    saddl     v0.4s, v6.4h, v16.4h\n    smlal     v0.4s, v2.4h, v22.4h\n    ext       v21.8b, v18.8b , v19.8b , #3\n    uaddl     v28.8h, v20.8b, v21.8b\n    ext       v24.8b, v18.8b , v19.8b , #4\n    smlsl     v0.4s, v3.4h, v23.4h\n    mla       v26.4h, v28.4h , v22.4h\n    ext       v19.8b, v18.8b , v19.8b , #1\n    uaddl     v28.8h, v19.8b, v24.8b\n    add       v2.4h, v12.4h , v14.4h\n    mls       v26.4h, v28.4h , v23.4h\n    sqrshrun  v0.4h, v0.4s, #0xa\n    add       v3.4h, v10.4h , v16.4h\n    ld1       {v18.2s, v19.2s}, [x0], x2 // row 5 load\n    ext       v25.8b, v18.8b , v19.8b , #5\n    uqxtn     v11.8b, v0.8h\n    uaddl     v28.8h, v18.8b, v25.8b\n\n    st1       {v26.2s}, [x9], x6        // store temp buffer 6\n\n    //Q3 available here\n    ld1       {v6.2s}, [x7], x6         // load from temp buffer 0\n    ld1       {v7.2s}, [x7], x6         // load from temp buffer 1\n\n    sqrshrun  v9.8b, v6.8h, #5\n    sqrshrun  v7.8b, v7.8h, #5\n    mov       v9.s[1], v7.s[0]\n\n    ext       v20.8b, v18.8b , v19.8b , #2\n\n    saddl     v0.4s, v8.4h, v26.4h\n    smlal     v0.4s, v2.4h, v22.4h\n    ext       v21.8b, v18.8b , v19.8b , #3\n    uaddl     v6.8h, v20.8b, v21.8b\n    ext       v24.8b, v18.8b , v19.8b , #4\n    smlsl     v0.4s, v3.4h, v23.4h\n    mla       v28.4h, v6.4h , v22.4h\n    ext       v19.8b, v18.8b , v19.8b , #1\n    uaddl     v6.8h, v19.8b, v24.8b\n    add       v2.4h, v14.4h , v16.4h\n    mls       v28.4h, v6.4h , v23.4h\n    sqrshrun  v0.4h, v0.4s, #0xa\n    add       v3.4h, v12.4h , v26.4h\n    ld1       {v18.2s, v19.2s}, [x0], x2 // row 6 load\n    ext       v25.8b, v18.8b , v19.8b , #5\n    uqxtn     v13.8b, v0.8h\n\n    trn1      v11.2s, v11.2s, v13.2s\n    trn2      v13.2s, v11.2s, v13.2s\n    saddl     v0.4s, v10.4h, v28.4h\n    urhadd    v9.8b, v9.8b , v11.8b\n\n    st1       {v28.2s}, [x9], x6        // store temp buffer 7\n\n    smlal     v0.4s, v2.4h, v22.4h\n    uaddl     v30.8h, v18.8b, v25.8b\n\n    st1       {v9.s}[0], [x1], x3       // store row 0\n\n    ext       v20.8b, v18.8b , v19.8b , #2\n\n    st1       {v9.s}[1], [x1], x3       // store row 1\n\n    ext       v21.8b, v18.8b , v19.8b , #3\n    smlsl     v0.4s, v3.4h, v23.4h\n    uaddl     v8.8h, v20.8b, v21.8b\n    ext       v24.8b, v18.8b , v19.8b , #4\n    mla       v30.4h, v8.4h , v22.4h\n    ext       v19.8b, v18.8b , v19.8b , #1\n    uaddl     v8.8h, v19.8b, v24.8b\n    sqrshrun  v0.4h, v0.4s, #0xa\n    add       v2.4h, v16.4h , v26.4h\n    mls       v30.4h, v8.4h , v23.4h\n    uqxtn     v4.8b, v0.8h\n\n    add       v3.4h, v14.4h , v28.4h\n\n\n    saddl     v0.4s, v12.4h, v30.4h\n\n    st1       {v30.2s}, [x9]\n\n    smlal     v0.4s, v2.4h, v22.4h\n\n    ld1       {v8.2s}, [x7], x6         // load from temp buffer 2\n    ld1       {v9.2s}, [x7], x6         // load from temp buffer 3\n    smlsl     v0.4s, v3.4h, v23.4h\n    subs      x4, x4, #4\n\n    sqrshrun  v10.8b, v8.8h, #5\n    sqrshrun  v9.8b, v9.8h, #5\n    mov       v10.s[1], v9.s[0]\n\n    mov       v12.8b, v28.8b\n\n    sqrshrun  v0.4h, v0.4s, #0xa\n    mov       v6.8b, v14.8b\n    mov       v8.8b, v16.8b\n\n    uqxtn     v5.8b, v0.8h\n\n    trn1      v4.2s, v4.2s, v5.2s\n    trn2      v5.2s, v4.2s, v5.2s\n    urhadd    v4.8b, v4.8b , v10.8b\n    mov       v10.8b, v26.8b\n    mov       v14.8b, v30.8b\n\n    st1       {v4.s}[0], [x1], x3       // store row 2\n    st1       {v4.s}[1], [x1], x3       // store row 3\n\n    bgt       loop_4\n\nend_func:\n    //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_inter_pred_luma_horz_qpel_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_inter_pred_luma_horz_qpel_av8.s\n//*\n//* @brief\n//*  Contains function definitions for inter prediction horizontal quarter pel interpolation.\n//*\n//* @author\n//*  Mohit\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_inter_pred_luma_horz_qpel_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_inter_pred_filters.c\n//\n\n///**\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Quarter pel interprediction luma filter for horizontal input\n//*\n//* @par Description:\n//* Applies a 6 tap horizontal filter .The output is  clipped to 8 bits\n//* sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n// @param[in] pu1_tmp: temporary buffer: UNUSED in this function\n//*\n//* @param[in] dydx: x and y reference offset for qpel calculations.\n//* @returns\n//*\n// @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n//void ih264_inter_pred_luma_horz (\n//                            UWORD8 *pu1_src,\n//                            UWORD8 *pu1_dst,\n//                            WORD32 src_strd,\n//                            WORD32 dst_strd,\n//                            WORD32 ht,\n//                            WORD32 wd,\n//                              UWORD8* pu1_tmp,\n//                             UWORD32 dydx)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ht\n//    w5 =>  wd\n//    w7 =>  dydx\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n\n    .global ih264_inter_pred_luma_horz_qpel_av8\n\nih264_inter_pred_luma_horz_qpel_av8:\n\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x2, w2\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n\n\n    and       x7, x7, #3                //Finds x-offset\n    add       x7, x0, x7, lsr #1        //pu1_src + (x_offset>>1)\n    sub       x0, x0, #2                //pu1_src-2\n    sub       x14, x4, #16\n    movi      v0.16b, #5                //filter coeff\n    subs      x12, x5, #8               //if wd=8 branch to loop_8\n    movi      v1.16b, #20               //filter coeff\n\n    beq       loop_8\n\n    subs      x12, x5, #4               //if wd=4 branch to loop_4\n    beq       loop_4\n\nloop_16:                                //when  wd=16\n    //// Processing row0 and row1\n    ld1       {v2.8b, v3.8b, v4.8b}, [x0], x2 //// Load row0\n    add       x14, x14, #1              //for checking loop\n    ext       v31.8b, v2.8b , v3.8b , #5\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row1\n    ext       v30.8b, v3.8b , v4.8b , #5\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row0)\n    ext       v28.8b, v5.8b , v6.8b , #5\n    uaddl     v10.8h, v30.8b, v3.8b     //// a0 + a5                             (column2,row0)\n    ext       v27.8b, v6.8b , v7.8b , #5\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row1)\n    ext       v31.8b, v2.8b , v3.8b , #2\n    uaddl     v16.8h, v27.8b, v6.8b     //// a0 + a5                             (column2,row1)\n    ext       v30.8b, v3.8b , v4.8b , #2\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row0)\n    ext       v28.8b, v5.8b , v6.8b , #2\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row0)\n    ext       v27.8b, v6.8b , v7.8b , #2\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row1)\n    ext       v31.8b, v2.8b , v3.8b , #3\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row1)\n    ext       v30.8b, v3.8b , v4.8b , #3\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row0)\n    ext       v28.8b, v5.8b , v6.8b , #3\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row0)\n    ext       v27.8b, v6.8b , v7.8b , #3\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row1)\n    ext       v31.8b, v2.8b , v3.8b , #1\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row1)\n    ext       v30.8b, v3.8b , v4.8b , #1\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row0)\n    ext       v28.8b, v5.8b , v6.8b , #1\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row0)\n    ext       v27.8b, v6.8b , v7.8b , #1\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row1)\n    ext       v31.8b, v2.8b , v3.8b , #4\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row1)\n    ext       v30.8b, v3.8b , v4.8b , #4\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row0)\n    ext       v28.8b, v5.8b , v6.8b , #4\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row0)\n    ext       v27.8b, v6.8b , v7.8b , #4\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row1)\n    ld1       {v2.8b, v3.8b, v4.8b}, [x0], x2 //// Load row2\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row1)\n\n    ld1       {v12.2s, v13.2s}, [x7], x2 //Load value for interpolation            (column1,row0)\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row0)\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row3\n    sqrshrun  v21.8b, v10.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row0)\n    ext       v31.8b, v2.8b , v3.8b , #5\n    urhadd    v20.16b, v12.16b , v20.16b //Interpolation step for qpel calculation\n    urhadd    v21.16b, v13.16b , v21.16b //Interpolation step for qpel calculation\n\n    sqrshrun  v18.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row1)\n    st1       {v20.8b, v21.8b}, [x1], x3 ////Store dest row0\n    ext       v30.8b, v3.8b , v4.8b , #5\n    sqrshrun  v19.8b, v16.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row1)\n\n\n\n//// Processing row2 and row3\n    ld1       {v12.2s, v13.2s}, [x7], x2 //Load value for interpolation            (column1,row1)\n    ext       v28.8b, v5.8b , v6.8b , #5\n    urhadd    v18.16b, v12.16b , v18.16b //Interpolation step for qpel calculation\n    urhadd    v19.16b, v13.16b , v19.16b //Interpolation step for qpel calculation\n\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row2)\n    st1       {v18.8b, v19.8b}, [x1], x3 ////Store dest row1\n    uaddl     v10.8h, v30.8b, v3.8b     //// a0 + a5                             (column2,row2)\n    ext       v27.8b, v6.8b , v7.8b , #5\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row3)\n    ext       v31.8b, v2.8b , v3.8b , #2\n    uaddl     v16.8h, v27.8b, v6.8b     //// a0 + a5                             (column2,row3)\n    ext       v30.8b, v3.8b , v4.8b , #2\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row2)\n    ext       v27.8b, v6.8b , v7.8b , #2\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row2)\n    ext       v28.8b, v5.8b , v6.8b , #2\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row3)\n    ext       v31.8b, v2.8b , v3.8b , #3\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row3)\n    ext       v30.8b, v3.8b , v4.8b , #3\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row2)\n    ext       v28.8b, v5.8b , v6.8b , #3\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row2)\n    ext       v27.8b, v6.8b , v7.8b , #3\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row3)\n    ext       v31.8b, v2.8b , v3.8b , #1\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row3)\n    ext       v30.8b, v3.8b , v4.8b , #1\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row2)\n    ext       v28.8b, v5.8b , v6.8b , #1\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row2)\n    ext       v27.8b, v6.8b , v7.8b , #1\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row3)\n    ext       v31.8b, v2.8b , v3.8b , #4\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row3)\n    ext       v30.8b, v3.8b , v4.8b , #4\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row2)\n    ext       v28.8b, v5.8b , v6.8b , #4\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row2)\n    ext       v27.8b, v6.8b , v7.8b , #4\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row3)\n    ld1       {v2.8b, v3.8b, v4.8b}, [x0], x2 //// Load row4\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row3)\n\n    ld1       {v12.2s, v13.2s}, [x7], x2 //Load value for interpolation            (column1,row2)\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row2)\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row5\n    sqrshrun  v21.8b, v10.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row2)\n    ext       v31.8b, v2.8b , v3.8b , #5\n    urhadd    v20.16b, v12.16b , v20.16b //Interpolation step for qpel calculation\n    urhadd    v21.16b, v13.16b , v21.16b //Interpolation step for qpel calculation\n\n    sqrshrun  v18.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row3)\n    ext       v30.8b, v3.8b , v4.8b , #5\n    st1       {v20.8b, v21.8b}, [x1], x3 ////Store dest row2\n    sqrshrun  v19.8b, v16.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row3)\n    ld1       {v12.2s, v13.2s}, [x7], x2 //Load value for interpolation            (column1,row3)\n\n//// Processing row4 and row5\n    ext       v28.8b, v5.8b , v6.8b , #5\n    urhadd    v18.16b, v12.16b , v18.16b //Interpolation step for qpel calculation\n    urhadd    v19.16b, v13.16b , v19.16b //Interpolation step for qpel calculation\n\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row4)\n    st1       {v18.8b, v19.8b}, [x1], x3 ////Store dest row3\n    uaddl     v10.8h, v30.8b, v3.8b     //// a0 + a5                             (column2,row4)\n    ext       v27.8b, v6.8b , v7.8b , #5\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row5)\n    ext       v31.8b, v2.8b , v3.8b , #2\n    uaddl     v16.8h, v27.8b, v6.8b     //// a0 + a5                             (column2,row5)\n    ext       v30.8b, v3.8b , v4.8b , #2\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row4)\n    ext       v27.8b, v6.8b , v7.8b , #2\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row4)\n    ext       v28.8b, v5.8b , v6.8b , #2\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row5)\n    ext       v31.8b, v2.8b , v3.8b , #3\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row5)\n    ext       v30.8b, v3.8b , v4.8b , #3\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row4)\n    ext       v28.8b, v5.8b , v6.8b , #3\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row4)\n    ext       v27.8b, v6.8b , v7.8b , #3\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row5)\n    ext       v31.8b, v2.8b , v3.8b , #1\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row5)\n    ext       v30.8b, v3.8b , v4.8b , #1\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row4)\n    ext       v28.8b, v5.8b , v6.8b , #1\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row4)\n    ext       v27.8b, v6.8b , v7.8b , #1\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row4)\n    ext       v31.8b, v2.8b , v3.8b , #4\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row5)\n    ext       v30.8b, v3.8b , v4.8b , #4\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row4)\n    ext       v28.8b, v5.8b , v6.8b , #4\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row4)\n    ext       v27.8b, v6.8b , v7.8b , #4\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row5)\n    ld1       {v2.8b, v3.8b, v4.8b}, [x0], x2 //// Load row6\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row5)\n    ld1       {v12.2s, v13.2s}, [x7], x2 //Load value for interpolation            (column1,row4)\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row4)\n    ld1       {v5.8b, v6.8b, v7.8b}, [x0], x2 //// Load row7\n    sqrshrun  v21.8b, v10.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row4)\n    ext       v31.8b, v2.8b , v3.8b , #5\n    urhadd    v20.16b, v12.16b , v20.16b //Interpolation step for qpel calculation\n    urhadd    v21.16b, v13.16b , v21.16b //Interpolation step for qpel calculation\n\n    sqrshrun  v18.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row5)\n    st1       {v20.8b, v21.8b}, [x1], x3 ////Store dest row4\n    ext       v30.8b, v3.8b , v4.8b , #5\n    sqrshrun  v19.8b, v16.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row5)\n    ld1       {v12.2s, v13.2s}, [x7], x2 //Load value for interpolation            (column1,row5)\n\n\n    //// Processing row6 and row7\n\n    ext       v28.8b, v5.8b , v6.8b , #5\n    urhadd    v18.16b, v12.16b , v18.16b //Interpolation step for qpel calculation\n    urhadd    v19.16b, v13.16b , v19.16b //Interpolation step for qpel calculation\n\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row6)\n    st1       {v18.8b, v19.8b}, [x1], x3 ////Store dest row5\n    uaddl     v10.8h, v30.8b, v3.8b     //// a0 + a5                             (column2,row6)\n    ext       v27.8b, v6.8b , v7.8b , #5\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row7)\n    ext       v31.8b, v2.8b , v3.8b , #2\n    uaddl     v16.8h, v27.8b, v6.8b     //// a0 + a5                             (column2,row7)\n    ext       v30.8b, v3.8b , v4.8b , #2\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row6)\n    ext       v27.8b, v6.8b , v7.8b , #2\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row6)\n    ext       v28.8b, v5.8b , v6.8b , #2\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row7)\n    ext       v31.8b, v2.8b , v3.8b , #3\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2                         (column2,row7)\n    ext       v30.8b, v3.8b , v4.8b , #3\n    umlal     v8.8h, v31.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row6)\n    ext       v28.8b, v5.8b , v6.8b , #3\n    umlal     v10.8h, v30.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row6)\n    ext       v27.8b, v6.8b , v7.8b , #3\n    umlal     v14.8h, v28.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row7)\n    ext       v31.8b, v2.8b , v3.8b , #1\n    umlal     v16.8h, v27.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column2,row7)\n    ext       v30.8b, v3.8b , v4.8b , #1\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row6)\n    ext       v28.8b, v5.8b , v6.8b , #1\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row6)\n    ext       v27.8b, v6.8b , v7.8b , #1\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row6)\n    ext       v31.8b, v2.8b , v3.8b , #4\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column2,row7)\n    ext       v30.8b, v3.8b , v4.8b , #4\n    umlsl     v8.8h, v31.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row6)\n    ext       v28.8b, v5.8b , v6.8b , #4\n    umlsl     v10.8h, v30.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row6)\n    ext       v27.8b, v6.8b , v7.8b , #4\n    ld1       {v12.2s, v13.2s}, [x7], x2 //Load value for interpolation            (column1,row6)\n    sqrshrun  v20.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row6)\n    umlsl     v14.8h, v28.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row7)\n    sqrshrun  v21.8b, v10.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row6)\n    umlsl     v16.8h, v27.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column2,row7)\n    urhadd    v20.16b, v12.16b , v20.16b //Interpolation step for qpel calculation\n    urhadd    v21.16b, v13.16b , v21.16b //Interpolation step for qpel calculation\n\n    ld1       {v12.2s, v13.2s}, [x7], x2 //Load value for interpolation            (column1,row7)\n    sqrshrun  v18.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row7)\n    st1       {v20.8b, v21.8b}, [x1], x3 ////Store dest row6\n    sqrshrun  v19.8b, v16.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column2,row7)\n    urhadd    v18.16b, v12.16b , v18.16b //Interpolation step for qpel calculation\n    urhadd    v19.16b, v13.16b , v19.16b //Interpolation step for qpel calculation\n\n    subs      x12, x14, #1              // if height==16  - looping\n    st1       {v18.8b, v19.8b}, [x1], x3 ////Store dest row7\n\n\n\n    beq       loop_16\n    b         end_func\n\nloop_8:\n//// Processing row0 and row1\n\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row1\n    add       x14, x14, #1              //for checking loop\n    ext       v28.8b, v5.8b , v6.8b , #5\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row0\n    ext       v25.8b, v5.8b , v6.8b , #2\n    ext       v31.8b, v2.8b , v3.8b , #5\n    ext       v24.8b, v5.8b , v6.8b , #3\n    ext       v23.8b, v5.8b , v6.8b , #1\n    ext       v22.8b, v5.8b , v6.8b , #4\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row1)\n    ext       v29.8b, v2.8b , v3.8b , #3\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row1)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row1)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row1)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row1)\n    ext       v30.8b, v2.8b , v3.8b , #2\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row0)\n    ext       v27.8b, v2.8b , v3.8b , #1\n    ext       v26.8b, v2.8b , v3.8b , #4\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row2\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row0)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row0)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row0)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row0)\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row3\n    sqrshrun  v18.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row0)\n\n    //// Processing row2 and row3\n    ext       v28.8b, v5.8b , v6.8b , #5\n    ext       v25.8b, v5.8b , v6.8b , #2\n    ext       v31.8b, v2.8b , v3.8b , #5\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row3)\n    ld1       {v12.2s}, [x7], x2        //Load value for interpolation            (column1,row0)\n    ld1       {v13.2s}, [x7], x2        //Load value for interpolation            (column1,row1)\n    ext       v24.8b, v5.8b , v6.8b , #3\n    ext       v23.8b, v5.8b , v6.8b , #1\n    sqrshrun  v19.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row1)\n    ext       v22.8b, v5.8b , v6.8b , #4\n    ext       v29.8b, v2.8b , v3.8b , #3\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row3)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row3)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row3)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row3)\n    urhadd    v18.16b, v12.16b , v18.16b //Interpolation step for qpel calculation\n    urhadd    v19.16b, v13.16b , v19.16b //Interpolation step for qpel calculation\n\n    st1       {v18.8b}, [x1], x3        ////Store dest row0\n    st1       {v19.8b}, [x1], x3        ////Store dest row1\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row2)\n    ext       v30.8b, v2.8b , v3.8b , #2\n    ext       v27.8b, v2.8b , v3.8b , #1\n    ext       v26.8b, v2.8b , v3.8b , #4\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row4\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row2)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row2)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row2)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row2)\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row5\n    subs      x9, x4, #4\n    sqrshrun  v19.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row3)\n    ld1       {v12.2s}, [x7], x2        //Load value for interpolation            (column1,row2)\n    ld1       {v13.2s}, [x7], x2        //Load value for interpolation            (column1,row3)\n    ext       v28.8b, v5.8b , v6.8b , #5\n    ext       v25.8b, v5.8b , v6.8b , #2\n    ext       v31.8b, v2.8b , v3.8b , #5\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row5)\n    ext       v24.8b, v5.8b , v6.8b , #3\n    sqrshrun  v18.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row2)\n    ext       v22.8b, v5.8b , v6.8b , #4\n    ext       v29.8b, v2.8b , v3.8b , #3\n    urhadd    v18.16b, v12.16b , v18.16b //Interpolation step for qpel calculation\n    urhadd    v19.16b, v13.16b , v19.16b //Interpolation step for qpel calculation\n\n    st1       {v18.8b}, [x1], x3        ////Store dest row2\n    ext       v30.8b, v2.8b , v3.8b , #2\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row4)\n    st1       {v19.8b}, [x1], x3        ////Store dest row3\n    beq       end_func                  // Branch if height==4\n\n//// Processing row4 and row5\n    ext       v23.8b, v5.8b , v6.8b , #1\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row5)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row5)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row5)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row5)\n    ext       v27.8b, v2.8b , v3.8b , #1\n    ext       v26.8b, v2.8b , v3.8b , #4\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row6\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row4)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row4)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row4)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row4)\n    sqrshrun  v19.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row5)\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row7\n    ext       v31.8b, v2.8b , v3.8b , #5\n    ext       v28.8b, v5.8b , v6.8b , #5\n    ld1       {v12.2s}, [x7], x2        //Load value for interpolation            (column1,row4)\n    ld1       {v13.2s}, [x7], x2        //Load value for interpolation            (column1,row5)\n    ext       v25.8b, v5.8b , v6.8b , #2\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row7)\n    ext       v24.8b, v5.8b , v6.8b , #3\n    ext       v22.8b, v5.8b , v6.8b , #4\n    sqrshrun  v18.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row4)\n    ext       v29.8b, v2.8b , v3.8b , #3\n    ext       v30.8b, v2.8b , v3.8b , #2\n    urhadd    v18.16b, v12.16b , v18.16b //Interpolation step for qpel calculation\n    urhadd    v19.16b, v13.16b , v19.16b //Interpolation step for qpel calculation\n\n    st1       {v18.8b}, [x1], x3        ////Store dest row4\n    ext       v27.8b, v2.8b , v3.8b , #1\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row6)\n    ext       v26.8b, v2.8b , v3.8b , #4\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row6)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row6)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row6)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row6)\n    //// Processing row6 and row7\n    st1       {v19.8b}, [x1], x3        ////Store dest row5\n    ext       v23.8b, v5.8b , v6.8b , #1\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row7)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row7)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row7)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row7)\n    ld1       {v12.2s}, [x7], x2        //Load value for interpolation            (column1,row6)\n    ld1       {v13.2s}, [x7], x2        //Load value for interpolation            (column1,row7)\n    sqrshrun  v18.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row6)\n    subs      x12, x14, #1\n    sqrshrun  v19.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row7)\n    urhadd    v18.16b, v12.16b , v18.16b //Interpolation step for qpel calculation\n    urhadd    v19.16b, v13.16b , v19.16b //Interpolation step for qpel calculation\n\n    st1       {v18.8b}, [x1], x3        ////Store dest row6\n    st1       {v19.8b}, [x1], x3        ////Store dest row7\n\n    beq       loop_8                    //looping if height ==16\n\n    b         end_func\n\nloop_4:\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row1\n    ext       v28.8b, v5.8b , v6.8b , #5\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row0\n    ext       v25.8b, v5.8b , v6.8b , #2\n    ext       v31.8b, v2.8b , v3.8b , #5\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row1)\n    ext       v24.8b, v5.8b , v6.8b , #3\n    ext       v23.8b, v5.8b , v6.8b , #1\n    ext       v22.8b, v5.8b , v6.8b , #4\n    ext       v29.8b, v2.8b , v3.8b , #3\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row1)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row1)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row1)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row1)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row0)\n    ext       v30.8b, v2.8b , v3.8b , #2\n    ld1       {v12.2s}, [x7], x2        //Load value for interpolation            (column1,row0)\n    ld1       {v13.2s}, [x7], x2        //Load value for interpolation            (column1,row1)\n    ext       v27.8b, v2.8b , v3.8b , #1\n    ext       v26.8b, v2.8b , v3.8b , #4\n    ld1       {v2.8b, v3.8b}, [x0], x2  //// Load row2\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row0)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row0)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row0)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row0)\n    ld1       {v5.8b, v6.8b}, [x0], x2  //// Load row3\n    ext       v28.8b, v5.8b , v6.8b , #5\n    ext       v25.8b, v5.8b , v6.8b , #2\n    sqrshrun  v18.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row0)\n    ext       v31.8b, v2.8b , v3.8b , #5\n    ext       v24.8b, v5.8b , v6.8b , #3\n\n    ext       v23.8b, v5.8b , v6.8b , #1\n    ext       v22.8b, v5.8b , v6.8b , #4\n    ext       v29.8b, v2.8b , v3.8b , #3\n    sqrshrun  v19.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row1)\n    ext       v30.8b, v2.8b , v3.8b , #2\n    ext       v27.8b, v2.8b , v3.8b , #1\n\n    //// Processing row2 and row3\n    urhadd    v18.16b, v12.16b , v18.16b //Interpolation step for qpel calculation\n    urhadd    v19.16b, v13.16b , v19.16b //Interpolation step for qpel calculation\n\n    st1       {v18.s}[0], [x1], x3      ////Store dest row0\n    st1       {v19.s}[0], [x1], x3      ////Store dest row1\n    uaddl     v14.8h, v28.8b, v5.8b     //// a0 + a5                             (column1,row3)\n    ext       v26.8b, v2.8b , v3.8b , #4\n    ld1       {v12.2s}, [x7], x2        //Load value for interpolation            (column1,row2)\n    ld1       {v13.2s}, [x7], x2        //Load value for interpolation            (column1,row3)\n\n    umlal     v14.8h, v25.8b, v1.8b     //// a0 + a5 + 20a2                         (column1,row3)\n    umlal     v14.8h, v24.8b, v1.8b     //// a0 + a5 + 20a2 + 20a3                  (column1,row3)\n    umlsl     v14.8h, v23.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row3)\n    umlsl     v14.8h, v22.8b, v0.8b     //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row3)\n    uaddl     v8.8h, v31.8b, v2.8b      //// a0 + a5                             (column1,row2)\n    umlal     v8.8h, v29.8b, v1.8b      //// a0 + a5 + 20a2 + 20a3                  (column1,row2)\n    umlal     v8.8h, v30.8b, v1.8b      //// a0 + a5 + 20a2                         (column1,row2)\n    umlsl     v8.8h, v27.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1           (column1,row2)\n    umlsl     v8.8h, v26.8b, v0.8b      //// a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4     (column1,row2)\n    sqrshrun  v19.8b, v14.8h, #5        //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row3)\n    sqrshrun  v18.8b, v8.8h, #5         //// (a0 + a5 + 20a2 + 20a3 - 5a1 - 5a4 + 16) >> 5    (column1,row2)\n    urhadd    v18.16b, v12.16b , v18.16b //Interpolation step for qpel calculation\n    urhadd    v19.16b, v13.16b , v19.16b //Interpolation step for qpel calculation\n\n    st1       {v18.s}[0], [x1], x3      ////Store dest row2\n    subs      x4, x4, #8                // Loop if height =8\n    st1       {v19.s}[0], [x1], x3      ////Store dest row3\n\n    beq       loop_4\n\nend_func:\n\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_inter_pred_luma_horz_qpel_vert_hpel_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_inter_pred_luma_horz_qpel_vert_hpel_av8.s\n//*\n//* @brief\n//*  Contains function definitions for inter prediction  interpolation.\n//*\n//* @author\n//*  Mohit\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_inter_pred_luma_horz_qpel_vert_hpel_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_inter_pred_filters.c\n//\n\n///**\n///**\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*   This function implements a two stage cascaded six tap filter. It\n//*   applies the six tap filter in the vertical direction on the\n//*   predictor values, followed by applying the same filter in the\n//*   horizontal direction on the output of the first stage. It then averages\n//*     the output of the 1st stage and the final stage to obtain the quarter\n//*   pel values.The six tap filtering operation is described in sec 8.4.2.2.1\n//*   titled \"Luma sample interpolation process\".\n//*\n//* @par Description:\n//*    This function is called to obtain pixels lying at the following\n//*    location (1/4,1/2) or (3/4,1/2). The function interpolates\n//*    the predictors first in the verical direction and then in the\n//*    horizontal direction to output the (1/2,1/2). It then averages\n//*      the output of the 2nd stage and (1/2,1/2) value to obtain (1/4,1/2)\n//*       or (3/4,1/2) depending on the offset.\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @param[in] pu1_tmp: temporary buffer\n//*\n//* @param[in] dydx: x and y reference offset for qpel calculations\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/;\n\n//void ih264_inter_pred_luma_horz_qpel_vert_hpel(UWORD8 *pu1_src,\n//                                UWORD8 *pu1_dst,\n//                                WORD32 src_strd,,\n//                                WORD32 dst_strd,\n//                                WORD32 ht,\n//                                WORD32 wd,\n//                                    UWORD8* pu1_tmp,\n//                                  UWORD32 dydx)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ht\n//    w5 =>  wd\n//    x6 => *pu1_tmp\n//    w7 =>  dydx\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_inter_pred_luma_horz_qpel_vert_hpel_av8\n\nih264_inter_pred_luma_horz_qpel_vert_hpel_av8:\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x2, w2\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n\n    sub       x0, x0, x2, lsl #1        //pu1_src-2*src_strd\n    sub       x0, x0, #2                //pu1_src-2\n    mov       x9, x6\n    mov       w6, w7\n\n    and       x6, x6, #2                // dydx & 0x3 followed by dydx>>1 and dydx<<1\n\n    add       x7, x9, #4\n    add       x6, x7, x6                // pi16_pred1_temp += (x_offset>>1)\n\n    movi      v26.8h, #0x14             // Filter coeff 20 into Q13\n    movi      v24.8h, #0x5              // Filter coeff 5  into Q12\n    movi      v27.8h, #0x14             // Filter coeff 20 into Q13\n    movi      v25.8h, #0x5              // Filter coeff 5  into Q12\n    mov       x7, #0x20\n    mov       x8, #0x30\n    subs      x12, x5, #4               //if wd=4 branch to loop_4\n    beq       loop_4_start\n\n    subs      x12, x5, #8               //if wd=8 branch to loop_8\n    beq       loop_8_start\n\n    //when  wd=16\n    movi      v28.8h, #0x14             // Filter coeff 20 into Q13\n    movi      v30.8h, #0x5              // Filter coeff 5  into Q12\n    sub       x2, x2, #16\n    ld1       {v0.2s, v1.2s}, [x0], #16 // Vector load from src[0_0]\n    ld1       {v12.2s}, [x0], x2        // Vector load from src[0_0]\n    ld1       {v2.2s, v3.2s}, [x0], #16 // Vector load from src[1_0]\n    ld1       {v13.2s}, [x0], x2        // Vector load from src[1_0]\n    ld1       {v4.2s, v5.2s}, [x0], #16 // Vector load from src[2_0]\n    ld1       {v14.2s}, [x0], x2        // Vector load from src[2_0]\n    ld1       {v6.2s, v7.2s}, [x0], #16 // Vector load from src[3_0]\n    ld1       {v15.2s}, [x0], x2        // Vector load from src[3_0]\n    ld1       {v8.2s, v9.2s}, [x0], #16 // Vector load from src[4_0]\n    ld1       {v16.2s}, [x0], x2        // Vector load from src[4_0]\n\nloop_16:\n\n    ld1       {v10.2s, v11.2s}, [x0], #16 // Vector load from src[5_0]\n    ld1       {v17.2s}, [x0], x2        // Vector load from src[5_0]\n\n\n    uaddl     v20.8h, v4.8b, v6.8b\n    uaddl     v18.8h, v0.8b, v10.8b\n    uaddl     v22.8h, v2.8b, v8.8b\n    mla       v18.8h, v20.8h , v28.8h\n    uaddl     v24.8h, v5.8b, v7.8b\n    uaddl     v20.8h, v1.8b, v11.8b\n    uaddl     v26.8h, v3.8b, v9.8b\n    mla       v20.8h, v24.8h , v28.8h\n    uaddl     v24.8h, v14.8b, v15.8b\n    mls       v18.8h, v22.8h , v30.8h\n    uaddl     v22.8h, v12.8b, v17.8b\n    mls       v20.8h, v26.8h , v30.8h\n    uaddl     v26.8h, v13.8b, v16.8b\n    mla       v22.8h, v24.8h , v28.8h\n    mls       v22.8h, v26.8h , v30.8h\n    st1       {v18.4s }, [x9], #16\n    st1       {v20.4s}, [x9], #16\n    ext       v24.16b, v18.16b , v20.16b , #4\n    ext       v26.16b, v18.16b , v20.16b , #6\n    st1       {v22.4s}, [x9]\n    ext       v22.16b, v18.16b , v20.16b , #10\n    add       v0.8h, v24.8h , v26.8h\n    ext       v24.16b, v18.16b , v20.16b , #2\n    ext       v26.16b, v18.16b , v20.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v18.4h, v22.4h\n    smlal     v26.4s, v0.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v18.8h, v22.8h\n    smlal2    v22.4s, v0.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    sqrshrun  v18.4h, v26.4s, #10\n    sqrshrun  v19.4h, v22.4s, #10\n    ld1       {v22.4s}, [x9], #16\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n    ext       v24.16b, v20.16b , v22.16b , #4\n    ext       v26.16b, v20.16b , v22.16b , #6\n    ext       v0.16b, v20.16b , v22.16b , #10\n    st1       {v18.2s}, [x1]\n    add       v18.8h, v24.8h , v26.8h\n    ext       v24.16b, v20.16b , v22.16b , #2\n    ext       v26.16b, v20.16b , v22.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v0.4h, v20.4h\n    smlal     v26.4s, v18.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v0.8h, v20.8h\n    smlal2    v22.4s, v18.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    sqrshrun  v19.4h, v26.4s, #10\n    sqrshrun  v18.4h, v22.4s, #10\n\n    uaddl     v24.8h, v7.8b, v9.8b\n    ld1       {v20.4s}, [x6], #16\n    ld1       {v22.4s}, [x6], x7\n\n\n    uqxtn     v19.8b, v19.8h\n    uqxtn     v18.8b, v18.8h\n    mov       v19.s[1], v18.s[0]\n\n    ld1       {v18.2s}, [x1]\n    sqrshrun  v20.8b, v20.8h, #5\n    sqrshrun  v21.8b, v22.8h, #5\n    uaddl     v22.8h, v4.8b, v10.8b\n    ld1       {v0.2s, v1.2s}, [x0], #16 // Vector load from src[6_0]\n    urhadd    v18.16b, v18.16b , v20.16b\n    urhadd    v19.16b, v19.16b , v21.16b\n\n    ld1       {v12.2s}, [x0], x2        // Vector load from src[6_0]\n    uaddl     v20.8h, v6.8b, v8.8b\n    uaddl     v26.8h, v5.8b, v11.8b\n    st1       {v18.2s, v19.2s}, [x1], x3 // store row 0\n\n\n//ROW_2\n\n\n    uaddl     v18.8h, v2.8b, v0.8b\n\n    mla       v18.8h, v20.8h , v28.8h\n\n    uaddl     v20.8h, v3.8b, v1.8b\n\n    mla       v20.8h, v24.8h , v28.8h\n    uaddl     v24.8h, v15.8b, v16.8b\n    mls       v18.8h, v22.8h , v30.8h\n    uaddl     v22.8h, v13.8b, v12.8b\n    mls       v20.8h, v26.8h , v30.8h\n    uaddl     v26.8h, v14.8b, v17.8b\n    mla       v22.8h, v24.8h , v28.8h\n    mls       v22.8h, v26.8h , v30.8h\n    st1       {v18.4s}, [x9], #16\n    st1       {v20.4s}, [x9], #16\n    ext       v24.16b, v18.16b , v20.16b , #4\n    ext       v26.16b, v18.16b , v20.16b , #6\n    st1       {v22.4s}, [x9]\n    ext       v22.16b, v18.16b , v20.16b , #10\n    add       v2.8h, v24.8h , v26.8h\n    ext       v24.16b, v18.16b , v20.16b , #2\n    ext       v26.16b, v18.16b , v20.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v18.4h, v22.4h\n    smlal     v26.4s, v2.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v18.8h, v22.8h\n    smlal2    v22.4s, v2.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    sqrshrun  v18.4h, v26.4s, #10\n    sqrshrun  v19.4h, v22.4s, #10\n\n    ld1       {v22.4s}, [x9], #16\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n    ext       v24.16b, v20.16b , v22.16b , #4\n    ext       v26.16b, v20.16b , v22.16b , #6\n    ext       v2.16b, v20.16b , v22.16b , #10\n    st1       {v18.2s}, [x1]\n    add       v18.8h, v24.8h , v26.8h\n    ext       v24.16b, v20.16b , v22.16b , #2\n    ext       v26.16b, v20.16b , v22.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v2.4h, v20.4h\n    smlal     v26.4s, v18.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v2.8h, v20.8h\n    smlal2    v22.4s, v18.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    sqrshrun  v19.4h, v26.4s, #10\n    sqrshrun  v18.4h, v22.4s, #10\n    uaddl     v24.8h, v9.8b, v11.8b\n    ld1       {v20.4s}, [x6], #16\n    ld1       {v22.4s}, [x6], x7\n    uqxtn     v19.8b, v19.8h\n    uqxtn     v18.8b, v18.8h\n    mov       v19.s[1], v18.s[0]\n    ld1       {v18.4s}, [x1]\n    sqrshrun  v20.8b, v20.8h, #5\n    sqrshrun  v21.8b, v22.8h, #5\n\n    uaddl     v22.8h, v6.8b, v0.8b\n    ld1       {v2.2s, v3.2s}, [x0], #16 // Vector load from src[7_0]\n\n    urhadd    v18.16b, v18.16b , v20.16b\n    urhadd    v19.16b, v19.16b , v21.16b\n    ld1       {v13.2s}, [x0], x2        // Vector load from src[7_0]\n    uaddl     v20.8h, v8.8b, v10.8b\n    uaddl     v26.8h, v7.8b, v1.8b\n    st1       {v18.2s, v19.2s}, [x1], x3 // store row 1\n\n//ROW_3\n\n\n    uaddl     v18.8h, v4.8b, v2.8b\n\n    mla       v18.8h, v20.8h , v28.8h\n\n    uaddl     v20.8h, v5.8b, v3.8b\n\n    mla       v20.8h, v24.8h , v28.8h\n    uaddl     v24.8h, v16.8b, v17.8b\n    mls       v18.8h, v22.8h , v30.8h\n    uaddl     v22.8h, v14.8b, v13.8b\n    mls       v20.8h, v26.8h , v30.8h\n    uaddl     v26.8h, v15.8b, v12.8b\n    mla       v22.8h, v24.8h , v28.8h\n    mls       v22.8h, v26.8h , v30.8h\n    st1       {v18.4s}, [x9], #16\n    st1       {v20.4s}, [x9], #16\n    ext       v24.16b, v18.16b , v20.16b , #4\n    ext       v26.16b, v18.16b , v20.16b , #6\n    st1       {v22.4s}, [x9]\n    ext       v22.16b, v18.16b , v20.16b , #10\n    add       v4.8h, v24.8h , v26.8h\n    ext       v24.16b, v18.16b , v20.16b , #2\n    ext       v26.16b, v18.16b , v20.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v18.4h, v22.4h\n    smlal     v26.4s, v4.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v18.8h, v22.8h\n    smlal2    v22.4s, v4.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    sqrshrun  v18.4h, v26.4s, #10\n    sqrshrun  v19.4h, v22.4s, #10\n    ld1       {v22.4s}, [x9], #16\n\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n\n    ext       v24.16b, v20.16b , v22.16b , #4\n    ext       v26.16b, v20.16b , v22.16b , #6\n    ext       v4.16b, v20.16b , v22.16b , #10\n    st1       {v18.2s}, [x1]\n    add       v18.8h, v24.8h , v26.8h\n    ext       v24.16b, v20.16b , v22.16b , #2\n    ext       v26.16b, v20.16b , v22.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v4.4h, v20.4h\n    smlal     v26.4s, v18.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v4.8h, v20.8h\n    smlal2    v22.4s, v18.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    sqrshrun  v19.4h, v26.4s, #10\n    sqrshrun  v18.4h, v22.4s, #10\n\n    uaddl     v24.8h, v11.8b, v1.8b\n    ld1       {v20.4s}, [x6], #16\n    ld1       {v22.4s}, [x6], x7\n\n    uqxtn     v19.8b, v19.8h\n    uqxtn     v18.8b, v18.8h\n    mov       v19.s[1], v18.s[0]\n\n    ld1       {v18.2s}, [x1]\n    sqrshrun  v20.8b, v20.8h, #5\n    sqrshrun  v21.8b, v22.8h, #5\n\n    uaddl     v22.8h, v8.8b, v2.8b\n    ld1       {v4.2s, v5.2s}, [x0], #16 // Vector load from src[8_0]\n\n    urhadd    v18.16b, v18.16b , v20.16b\n    urhadd    v19.16b, v19.16b , v21.16b\n    ld1       {v14.2s}, [x0], x2        // Vector load from src[8_0]\n    uaddl     v20.8h, v10.8b, v0.8b\n    uaddl     v26.8h, v9.8b, v3.8b\n    st1       {v18.2s, v19.2s}, [x1], x3 // store row 2\n\n\n//ROW_4\n\n    uaddl     v18.8h, v6.8b, v4.8b\n\n    mla       v18.8h, v20.8h , v28.8h\n\n    uaddl     v20.8h, v7.8b, v5.8b\n\n    mla       v20.8h, v24.8h , v28.8h\n    uaddl     v24.8h, v17.8b, v12.8b\n    mls       v18.8h, v22.8h , v30.8h\n    uaddl     v22.8h, v15.8b, v14.8b\n    mls       v20.8h, v26.8h , v30.8h\n    uaddl     v26.8h, v16.8b, v13.8b\n    mla       v22.8h, v24.8h , v28.8h\n    mls       v22.8h, v26.8h , v30.8h\n    st1       {v18.4s}, [x9], #16\n    st1       {v20.4s}, [x9], #16\n    ext       v24.16b, v18.16b , v20.16b , #4\n    ext       v26.16b, v18.16b , v20.16b , #6\n    st1       {v22.4s}, [x9]\n    ext       v22.16b, v18.16b , v20.16b , #10\n    add       v6.8h, v24.8h , v26.8h\n    ext       v24.16b, v18.16b , v20.16b , #2\n    ext       v26.16b, v18.16b , v20.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v18.4h, v22.4h\n    smlal     v26.4s, v6.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v18.8h, v22.8h\n    smlal2    v22.4s, v6.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    sqrshrun  v18.4h, v26.4s, #10\n    sqrshrun  v19.4h, v22.4s, #10\n    ld1       {v22.4s}, [x9], #16\n    uqxtn     v18.8b, v18.8h\n    uqxtn     v19.8b, v19.8h\n    mov       v18.s[1], v19.s[0]\n\n\n    ext       v24.16b, v20.16b , v22.16b , #4\n    ext       v26.16b, v20.16b , v22.16b , #6\n    ext       v6.16b, v20.16b , v22.16b , #10\n    st1       {v18.2s}, [x1]\n    add       v18.8h, v24.8h , v26.8h\n    ext       v24.16b, v20.16b , v22.16b , #2\n    ext       v26.16b, v20.16b , v22.16b , #8\n    add       v24.8h, v24.8h , v26.8h\n\n    saddl     v26.4s, v6.4h, v20.4h\n    smlal     v26.4s, v18.4h, v28.4h\n    smlsl     v26.4s, v24.4h, v30.4h\n\n    saddl2    v22.4s, v6.8h, v20.8h\n    smlal2    v22.4s, v18.8h, v28.8h\n    smlsl2    v22.4s, v24.8h, v30.8h\n\n    mov       v6.16b, v2.16b\n    mov       v7.16b, v3.16b\n\n    mov       v2.16b, v10.16b\n    mov       v3.16b, v11.16b\n\n    subs      x4, x4, #4\n    sqrshrun  v19.4h, v26.4s, #10\n    sqrshrun  v18.4h, v22.4s, #10\n    mov       v10.16b, v0.16b\n    mov       v11.16b, v1.16b\n\n    mov       v24.8b, v14.8b\n\n    mov       v14.16b, v12.16b\n    mov       v15.16b, v13.16b\n\n\n    uqxtn     v19.8b, v19.8h\n    uqxtn     v18.8b, v18.8h\n    mov       v19.s[1], v18.s[0]\n\n    ld1       {v20.4s}, [x6], #16\n    ld1       {v22.4s}, [x6], x7\n    ld1       {v18.2s}, [x1]\n    sqrshrun  v20.8b, v20.8h, #5\n    sqrshrun  v21.8b, v22.8h, #5\n\n    mov       v0.16b, v8.16b\n    mov       v1.16b, v9.16b\n\n    mov       v8.16b, v4.16b\n    mov       v9.16b, v5.16b\n\n    mov       v12.16b, v16.16b\n    mov       v13.16b, v17.16b\n    urhadd    v18.16b, v18.16b , v20.16b\n    urhadd    v19.16b, v19.16b , v21.16b\n\n    mov       v4.16b, v10.16b\n    mov       v5.16b, v11.16b\n\n    mov       v16.8b, v24.8b\n    st1       {v18.2s, v19.2s}, [x1], x3 // store row 3\n\n    bgt       loop_16                   // looping if height =16\n    b         end_func\n\nloop_8_start:\n    ld1       {v0.2s, v1.2s}, [x0], x2  // Vector load from src[0_0]\n    ld1       {v2.2s, v3.2s}, [x0], x2  // Vector load from src[1_0]\n    ld1       {v4.2s, v5.2s}, [x0], x2  // Vector load from src[2_0]\n    ld1       {v6.2s, v7.2s}, [x0], x2  // Vector load from src[3_0]\n    ld1       {v8.2s, v9.2s}, [x0], x2  // Vector load from src[4_0]\n\nloop_8:\n\n    ld1       {v10.2s, v11.2s}, [x0], x2 // Vector load from src[5_0]\n    uaddl     v14.8h, v4.8b, v6.8b\n    uaddl     v12.8h, v0.8b, v10.8b\n    uaddl     v16.8h, v2.8b, v8.8b\n    mla       v12.8h, v14.8h , v26.8h\n    uaddl     v18.8h, v5.8b, v7.8b\n    uaddl     v14.8h, v1.8b, v11.8b\n    uaddl     v22.8h, v3.8b, v9.8b\n    mla       v14.8h, v18.8h , v26.8h\n    mls       v12.8h, v16.8h , v24.8h\n    ld1       {v0.2s, v1.2s}, [x0], x2  // Vector load from src[6_0]\n    uaddl     v16.8h, v6.8b, v8.8b\n    mls       v14.8h, v22.8h , v24.8h\n    uaddl     v28.8h, v2.8b, v0.8b\n    st1       {v12.4s}, [x9], #16       // store row 0 to temp buffer: col 0\n    ext       v22.16b, v12.16b , v14.16b , #10\n    uaddl     v18.8h, v4.8b, v10.8b\n    mla       v28.8h, v16.8h , v26.8h\n    saddl     v30.4s, v12.4h, v22.4h\n    st1       {v14.4s}, [x9], x7        // store row 0 to temp buffer: col 1\n    saddl2    v22.4s, v12.8h, v22.8h\n    ext       v16.16b, v12.16b , v14.16b , #4\n    mls       v28.8h, v18.8h , v24.8h\n    ext       v18.16b, v12.16b , v14.16b , #6\n    ext       v20.16b, v12.16b , v14.16b , #8\n    ext       v14.16b, v12.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v14.8h , v20.8h\n    uaddl     v20.8h, v7.8b, v9.8b\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal2    v22.4s, v16.8h, v26.8h\n    smlsl2    v22.4s, v18.8h, v24.8h\n    uaddl     v14.8h, v3.8b, v1.8b\n    st1       {v28.4s}, [x9], #16       // store row 1 to temp buffer: col 0\n    mla       v14.8h, v20.8h , v26.8h\n    sqrshrun  v12.4h, v30.4s, #10\n    uaddl     v16.8h, v5.8b, v11.8b\n    sqrshrun  v13.4h, v22.4s, #10\n    mls       v14.8h, v16.8h , v24.8h\n    ld1       {v2.2s, v3.2s}, [x0], x2  // Vector load from src[7_0]\n    uqxtn     v25.8b, v12.8h\n    uqxtn     v13.8b, v13.8h\n    mov       v25.s[1], v13.s[0]\n    uaddl     v16.8h, v8.8b, v10.8b\n\n\n    ext       v22.16b, v28.16b , v14.16b , #10\n    uaddl     v20.8h, v4.8b, v2.8b\n    saddl     v30.4s, v28.4h, v22.4h\n    mla       v20.8h, v16.8h , v26.8h\n    st1       {v14.4s}, [x9], x7        // store row 1 to temp buffer: col 1\n    saddl2    v22.4s, v28.8h, v22.8h\n    ext       v16.16b, v28.16b , v14.16b , #4\n    ext       v18.16b, v28.16b , v14.16b , #6\n    ext       v12.16b, v28.16b , v14.16b , #8\n    ext       v14.16b, v28.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v12.8h , v14.8h\n    ld1       {v14.4s, v15.4s}, [x6], x8 // load row 0 from temp buffer\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal2    v22.4s, v16.8h, v26.8h\n    smlsl2    v22.4s, v18.8h, v24.8h\n    sqrshrun  v14.8b, v14.8h, #0x5\n    ld1       {v28.4s, v29.4s}, [x6], x8 // load row 1 from temp buffer\n    uaddl     v18.8h, v6.8b, v0.8b\n    sqrshrun  v16.4h, v30.4s, #10\n    sqrshrun  v15.8b, v28.8h, #0x5\n    sqrshrun  v17.4h, v22.4s, #10\n\n    mov       v12.8b, v25.8b\n    mov       v25.8b, v24.8b\n\n    uaddl     v28.8h, v9.8b, v11.8b\n    uqxtn     v13.8b, v16.8h\n    uqxtn     v17.8b, v17.8h\n    mov       v13.s[1], v17.s[0]\n\n    urhadd    v12.16b, v12.16b , v14.16b\n    urhadd    v13.16b, v13.16b , v15.16b\n    uaddl     v14.8h, v5.8b, v3.8b\n    uaddl     v22.8h, v7.8b, v1.8b\n    mls       v20.8h, v18.8h , v24.8h\n    st1       {v12.2s}, [x1], x3        // store row 0\n    mla       v14.8h, v28.8h , v26.8h\n    ld1       {v4.2s, v5.2s}, [x0], x2  // Vector load from src[8_0]\n    uaddl     v30.8h, v10.8b, v0.8b\n    uaddl     v28.8h, v6.8b, v4.8b\n    mls       v14.8h, v22.8h , v24.8h\n    st1       {v13.2s}, [x1], x3        // store row 1\n    mla       v28.8h, v30.8h , v26.8h\n    st1       {v20.4s}, [x9], #16       // store row 2 to temp buffer: col 0\n    ext       v22.16b, v20.16b , v14.16b , #10\n    saddl     v30.4s, v20.4h, v22.4h\n    st1       {v14.2s, v15.2s}, [x9], x7 // store row 2 to temp buffer: col 0\n    saddl2    v22.4s, v20.8h, v22.8h\n    ext       v16.16b, v20.16b , v14.16b , #4\n    ext       v18.16b, v20.16b , v14.16b , #6\n    ext       v12.16b, v20.16b , v14.16b , #8\n    ext       v14.16b, v20.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v14.8h , v12.8h\n    uaddl     v20.8h, v8.8b, v2.8b\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal2    v22.4s, v16.8h, v26.8h\n    smlsl2    v22.4s, v18.8h, v24.8h\n    uaddl     v18.8h, v11.8b, v1.8b\n    uaddl     v16.8h, v7.8b, v5.8b\n    sqrshrun  v12.4h, v30.4s, #10\n    uaddl     v30.8h, v9.8b, v3.8b\n    mla       v16.8h, v18.8h , v26.8h\n    sqrshrun  v13.4h, v22.4s, #10\n    mls       v28.8h, v20.8h , v24.8h\n    ld1       {v14.4s, v15.4s}, [x6], x8 // load row 2 from temp buffer\n    mls       v16.8h, v30.8h , v24.8h\n    uqxtn     v27.8b, v12.8h\n    uqxtn     v13.8b, v13.8h\n    mov       v27.s[1], v13.s[0]\n\n    sqrshrun  v14.8b, v14.8h, #5\n    ext       v22.16b, v28.16b , v16.16b , #10\n    st1       {v28.4s}, [x9], #16       // store row 3 to temp buffer: col 0\n    saddl     v30.4s, v28.4h, v22.4h\n    st1       {v16.2s, v17.2s}, [x9], x7 // store row 3 to temp buffer: col 1\n    saddl2    v22.4s, v28.8h, v22.8h\n    ext       v12.16b, v28.16b , v16.16b , #4\n    ext       v18.16b, v28.16b , v16.16b , #6\n    ext       v20.16b, v28.16b , v16.16b , #8\n    ext       v28.16b, v28.16b , v16.16b , #2\n    add       v12.8h, v12.8h , v18.8h\n    add       v18.8h, v28.8h , v20.8h\n    ld1       {v16.4s, v17.4s}, [x6], x8 // load row 3 from temp buffer\n    smlal     v30.4s, v12.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal2    v22.4s, v12.8h, v26.8h\n    smlsl2    v22.4s, v18.8h, v24.8h\n    sqrshrun  v15.8b, v16.8h, #0x5\n\n    mov       v12.8b, v27.8b\n    mov       v27.8b, v26.8b\n\n    sqrshrun  v16.4h, v30.4s, #10\n\n    mov       v6.16b, v2.16b\n    mov       v7.16b, v3.16b\n\n    sqrshrun  v17.4h, v22.4s, #10\n\n    mov       v2.16b, v10.16b\n    mov       v3.16b, v11.16b\n\n    mov       v10.16b, v0.16b\n    mov       v11.16b, v1.16b\n\n    subs      x4, x4, #4\n    uqxtn     v13.8b, v16.8h\n    uqxtn     v17.8b, v17.8h\n    mov       v13.s[1], v17.s[0]\n    urhadd    v12.16b, v12.16b , v14.16b\n    urhadd    v13.16b, v13.16b , v15.16b\n\n    mov       v0.16b, v8.16b\n    mov       v1.16b, v9.16b\n\n    mov       v8.16b, v4.16b\n    mov       v9.16b, v5.16b\n\n    mov       v4.16b, v10.16b\n    mov       v5.16b, v11.16b\n\n    st1       {v12.2s}, [x1], x3        // store row 2\n    st1       {v13.2s}, [x1], x3        // store row 3\n\n    bgt       loop_8                    //if height =8  loop\n    b         end_func\n\nloop_4_start:\n    ld1       {v0.2s, v1.2s}, [x0], x2  // Vector load from src[0_0]\n    ld1       {v2.2s, v3.2s}, [x0], x2  // Vector load from src[1_0]\n    ld1       {v4.2s, v5.2s}, [x0], x2  // Vector load from src[2_0]\n    ld1       {v6.2s, v7.2s}, [x0], x2  // Vector load from src[3_0]\n    ld1       {v8.2s, v9.2s}, [x0], x2  // Vector load from src[4_0]\n\nloop_4:\n    ld1       {v10.2s, v11.2s}, [x0], x2 // Vector load from src[5_0]\n    uaddl     v14.8h, v4.8b, v6.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v12.8h, v0.8b, v10.8b     // temp = src[0_0] + src[5_0]\n    uaddl     v16.8h, v2.8b, v8.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v12.8h, v14.8h , v26.8h   // temp += temp1 * 20\n    uaddl     v18.8h, v5.8b, v7.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v14.8h, v1.8b, v11.8b     // temp = src[0_0] + src[5_0]\n    uaddl     v22.8h, v3.8b, v9.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v14.8h, v18.8h , v26.8h   // temp += temp1 * 20\n    mls       v12.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    ld1       {v0.2s, v1.2s}, [x0], x2  // Vector load from src[6_0]\n    uaddl     v16.8h, v6.8b, v8.8b\n    mls       v14.8h, v22.8h , v24.8h   // temp -= temp2 * 5\n    //Q6 and Q7 have filtered values\n    uaddl     v28.8h, v2.8b, v0.8b\n    st1       {v12.4s}, [x9], #16       // store row 0 to temp buffer: col 0\n    ext       v22.16b, v12.16b , v14.16b , #10\n    uaddl     v18.8h, v4.8b, v10.8b\n    mla       v28.8h, v16.8h , v26.8h\n    saddl     v30.4s, v12.4h, v22.4h\n    st1       {v14.4s}, [x9], x7        // store row 0 to temp buffer: col 1\n    saddl     v22.4s, v13.4h, v23.4h\n    ext       v16.16b, v12.16b , v14.16b , #4\n    mls       v28.8h, v18.8h , v24.8h\n    ext       v18.16b, v12.16b , v14.16b , #6\n    ext       v20.16b, v12.16b , v14.16b , #8\n    ext       v14.16b, v12.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v14.8h , v20.8h\n    uaddl     v20.8h, v7.8b, v9.8b\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal     v22.4s, v17.4h, v26.4h\n    smlsl     v22.4s, v19.4h, v24.4h\n    uaddl     v14.8h, v3.8b, v1.8b\n    st1       {v28.4s}, [x9], #16       // store row 1 to temp buffer: col 0\n    mla       v14.8h, v20.8h , v26.8h\n    sqrshrun  v12.4h, v30.4s, #10\n    uaddl     v16.8h, v5.8b, v11.8b\n    sqrshrun  v13.4h, v22.4s, #10\n    mls       v14.8h, v16.8h , v24.8h\n    ld1       {v2.2s, v3.2s}, [x0], x2  // Vector load from src[7_0]\n    uqxtn     v25.8b, v12.8h\n    uaddl     v16.8h, v8.8b, v10.8b\n\n    ext       v22.16b, v28.16b , v14.16b , #10\n    uaddl     v20.8h, v4.8b, v2.8b\n    saddl     v30.4s, v28.4h, v22.4h\n    mla       v20.8h, v16.8h , v26.8h\n    st1       {v14.4s}, [x9], x7        // store row 1 to temp buffer: col 1\n    saddl     v22.4s, v29.4h, v23.4h\n    ext       v16.16b, v28.16b , v14.16b , #4\n    ext       v18.16b, v28.16b , v14.16b , #6\n    ext       v12.16b, v28.16b , v14.16b , #8\n    ext       v14.16b, v28.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v12.8h , v14.8h\n    ld1       {v14.2s}, [x6], x8        //load row 0 from temp buffer\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal     v22.4s, v17.4h, v26.4h\n    smlsl     v22.4s, v19.4h, v24.4h\n    sqrshrun  v14.8b, v14.8h, #0x5\n    ld1       {v28.2s}, [x6], x8        //load row 1 from temp buffer\n    uaddl     v18.8h, v6.8b, v0.8b\n    sqrshrun  v16.4h, v30.4s, #10\n    sqrshrun  v15.8b, v28.8h, #0x5\n    sqrshrun  v17.4h, v22.4s, #10\n\n    mov       v12.8b, v25.8b\n    mov       v25.8b, v24.8b\n\n    uaddl     v28.8h, v9.8b, v11.8b\n    uqxtn     v13.8b, v16.8h\n\n    urhadd    v12.16b, v12.16b , v14.16b\n    urhadd    v13.16b, v13.16b , v15.16b\n\n    uaddl     v14.8h, v5.8b, v3.8b\n    uaddl     v22.8h, v7.8b, v1.8b\n    mls       v20.8h, v18.8h , v24.8h\n    st1       {v12.s}[0], [x1], x3      // store row 0\n    mla       v14.8h, v28.8h , v26.8h\n    ld1       {v4.2s, v5.2s}, [x0], x2  // Vector load from src[8_0]\n    uaddl     v30.8h, v10.8b, v0.8b\n    uaddl     v28.8h, v6.8b, v4.8b\n    mls       v14.8h, v22.8h , v24.8h\n    st1       {v13.s}[0], [x1], x3      //store row 1\n    mla       v28.8h, v30.8h , v26.8h\n    st1       {v20.4s}, [x9], #16       // store row 2 to temp buffer: col 0\n    ext       v22.16b, v20.16b , v14.16b , #10\n    saddl     v30.4s, v20.4h, v22.4h\n    st1       {v14.4s}, [x9], x7        // store row 2 to temp buffer: col 1\n    saddl     v22.4s, v21.4h, v23.4h\n    ext       v16.16b, v20.16b , v14.16b , #4\n    ext       v18.16b, v20.16b , v14.16b , #6\n    ext       v12.16b, v20.16b , v14.16b , #8\n    ext       v14.16b, v20.16b , v14.16b , #2\n    add       v16.8h, v16.8h , v18.8h\n    add       v18.8h, v14.8h , v12.8h\n    uaddl     v20.8h, v8.8b, v2.8b\n    smlal     v30.4s, v16.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal     v22.4s, v17.4h, v26.4h\n    smlsl     v22.4s, v19.4h, v24.4h\n    uaddl     v18.8h, v11.8b, v1.8b\n    uaddl     v16.8h, v7.8b, v5.8b\n    sqrshrun  v12.4h, v30.4s, #10\n    uaddl     v30.8h, v9.8b, v3.8b\n    mla       v16.8h, v18.8h , v26.8h\n    sqrshrun  v13.4h, v22.4s, #10\n    mls       v28.8h, v20.8h , v24.8h\n    ld1       {v14.2s}, [x6], x8        //load row 3 from temp buffer\n    mls       v16.8h, v30.8h , v24.8h\n    uqxtn     v27.8b, v12.8h\n    sqrshrun  v14.8b, v14.8h, #5\n    ext       v22.16b, v28.16b , v16.16b , #10\n    st1       {v28.4s}, [x9], #16       // store row 3 to temp buffer: col 0\n    saddl     v30.4s, v28.4h, v22.4h\n    st1       {v16.4s}, [x9], x7        // store row 3 to temp buffer: col 1\n    saddl     v22.4s, v29.4h, v23.4h\n    ext       v12.16b, v28.16b , v16.16b , #4\n    ext       v18.16b, v28.16b , v16.16b , #6\n    ext       v20.16b, v28.16b , v16.16b , #8\n    ext       v28.16b, v28.16b , v16.16b , #2\n    add       v12.8h, v12.8h , v18.8h\n    add       v18.8h, v28.8h , v20.8h\n    ld1       {v16.2s}, [x6], x8        //load row 4 from temp buffer\n    smlal     v30.4s, v12.4h, v26.4h\n    smlsl     v30.4s, v18.4h, v24.4h\n    smlal     v22.4s, v13.4h, v26.4h\n    smlsl     v22.4s, v19.4h, v24.4h\n    sqrshrun  v15.8b, v16.8h, #0x5\n\n    mov       v12.8b, v27.8b\n    mov       v27.8b, v26.8b\n\n    sqrshrun  v16.4h, v30.4s, #10\n\n    mov       v6.16b, v2.16b\n    mov       v7.16b, v3.16b\n\n    sqrshrun  v17.4h, v22.4s, #10\n\n    mov       v2.16b, v10.16b\n    mov       v3.16b, v11.16b\n\n    mov       v10.16b, v0.16b\n    mov       v11.16b, v1.16b\n\n    subs      x4, x4, #4\n    uqxtn     v13.8b, v16.8h\n    urhadd    v12.16b, v12.16b , v14.16b\n    urhadd    v13.16b, v13.16b , v15.16b\n\n    mov       v0.16b, v8.16b\n    mov       v1.16b, v9.16b\n\n    mov       v8.16b, v4.16b\n    mov       v9.16b, v5.16b\n\n\n    mov       v4.16b, v10.16b\n    mov       v5.16b, v11.16b\n\n\n    st1       {v12.s}[0], [x1], x3      // store row 2\n    st1       {v13.s}[0], [x1], x3      // store row 3\n\n    bgt       loop_4\n\nend_func:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_inter_pred_luma_horz_qpel_vert_qpel_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_inter_pred_luma_horz_qpel_vert_qpel_av8.s\n//*\n//* @brief\n//*  Contains function definitions for inter prediction  interpolation.\n//*\n//* @author\n//*  Mohit\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_inter_pred_luma_horz_qpel_vert_qpel_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_inter_pred_filters.c\n//\n\n///**\n///**\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*   This function implements two six tap filters. It\n//*    applies the six tap filter in the horizontal direction on the\n//*    predictor values, then applies the same filter in the\n//*    vertical direction on the predictor values. It then averages these\n//*      two outputs to obtain quarter pel values in horizontal and vertical direction.\n//*    The six tap filtering operation is described in sec 8.4.2.2.1 titled\n//*    \"Luma sample interpolation process\"\n//*\n//* @par Description:\n//*    This function is called to obtain pixels lying at the following\n//*    location (1/4,1/4) or (3/4,1/4) or (1/4,3/4) or (3/4,3/4).\n//*    The function interpolates the predictors first in the horizontal direction\n//*    and then in the vertical direction, and then averages these two\n//*      values.\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @param[in] pu1_tmp: temporary buffer\n//*\n//* @param[in] dydx: x and y reference offset for qpel calculations\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/;\n\n//void ih264_inter_pred_luma_horz_qpel_vert_qpel(UWORD8 *pu1_src,\n//                                UWORD8 *pu1_dst,\n//                                WORD32 src_strd,,\n//                                WORD32 dst_strd,\n//                                WORD32 ht,\n//                                WORD32 wd,\n//                                    UWORD8* pu1_tmp,\n//                                  UWORD32 dydx)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ht\n//    w5 =>  wd\n//    w7 =>  dydx\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_inter_pred_luma_horz_qpel_vert_qpel_av8\n\nih264_inter_pred_luma_horz_qpel_vert_qpel_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x2, w2\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n    mov       w6, w7\n    and       x7, x6, #3\n    add       x7, x0, x7, lsr #1        //pu1_pred_vert = pu1_src + (x_offset>>1)\n\n    and       x6, x6, #12               //Finds y-offset\n    lsr       x6, x6, #3                //dydx>>3\n    mul       x6, x2, x6\n    add       x6, x0, x6                //pu1_pred_horz = pu1_src + (y_offset>>1)*src_strd\n    sub       x7, x7, x2, lsl #1        //pu1_pred_vert-2*src_strd\n    sub       x6, x6, #2                //pu1_pred_horz-2\n    movi      v30.8b, #20               // Filter coeff 20\n    movi      v31.8b, #5                // Filter coeff 5\n\n    subs      x12, x5, #4               //if wd=4 branch to loop_4\n    beq       loop_4_start\n    subs      x12, x5, #8               //if wd=8 branch to loop_8\n    beq       loop_8_start\n\n    ld1       {v0.2s, v1.2s}, [x7], x2  // Vector load from src[0_0]\n    ld1       {v2.2s, v3.2s}, [x7], x2  // Vector load from src[1_0]\n\n    ld1       {v4.2s, v5.2s}, [x7], x2  // Vector load from src[2_0]\n    ld1       {v6.2s, v7.2s}, [x7], x2  // Vector load from src[3_0]\n    ld1       {v8.2s, v9.2s}, [x7], x2  // Vector load from src[4_0]\n    add       x11, x6, #8\nloop_16:\n    ld1       {v10.2s, v11.2s}, [x7], x2 // Vector load from src[5_0]\n    ld1       {v18.2s, v19.2s}, [x6], x2 // horz row0, col 0\n    uaddl     v24.8h, v0.8b, v10.8b\n    umlal     v24.8h, v4.8b, v30.8b\n    umlal     v24.8h, v6.8b, v30.8b\n    umlsl     v24.8h, v2.8b, v31.8b\n    umlsl     v24.8h, v8.8b, v31.8b\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n    sqrshrun  v26.8b, v24.8h, #5\n    uaddl     v28.8h, v18.8b, v23.8b\n    umlal     v28.8h, v20.8b, v30.8b\n    umlal     v28.8h, v21.8b, v30.8b\n    umlsl     v28.8h, v19.8b, v31.8b\n    umlsl     v28.8h, v22.8b, v31.8b\n    ld1       {v18.2s, v19.2s}, [x11], x2 // horz row 0, col 1\n    uaddl     v24.8h, v1.8b, v11.8b\n    umlal     v24.8h, v5.8b, v30.8b\n    umlal     v24.8h, v7.8b, v30.8b\n    umlsl     v24.8h, v3.8b, v31.8b\n    umlsl     v24.8h, v9.8b, v31.8b\n    sqrshrun  v28.8b, v28.8h, #5\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n\n    sqrshrun  v27.8b, v24.8h, #5\n    ld1       {v12.2s, v13.2s}, [x7], x2 // src[6_0]\n\n    uaddl     v24.8h, v18.8b, v23.8b\n    umlal     v24.8h, v20.8b, v30.8b\n    umlal     v24.8h, v21.8b, v30.8b\n    umlsl     v24.8h, v19.8b, v31.8b\n    umlsl     v24.8h, v22.8b, v31.8b\n\n    uaddl     v16.8h, v2.8b, v12.8b\n    umlal     v16.8h, v6.8b, v30.8b\n    umlal     v16.8h, v8.8b, v30.8b\n    umlsl     v16.8h, v4.8b, v31.8b\n    umlsl     v16.8h, v10.8b, v31.8b\n\n    sqrshrun  v29.8b, v24.8h, #5\n    ld1       {v18.2s, v19.2s}, [x6], x2 // horz row 1, col 0\n\n    uaddl     v24.8h, v3.8b, v13.8b\n    umlal     v24.8h, v7.8b, v30.8b\n    umlal     v24.8h, v9.8b, v30.8b\n    umlsl     v24.8h, v5.8b, v31.8b\n    umlsl     v24.8h, v11.8b, v31.8b\n    urhadd    v28.16b, v28.16b , v26.16b\n    urhadd    v29.16b, v29.16b , v27.16b\n    sqrshrun  v26.8b, v16.8h, #5\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    st1       {v28.2s, v29.2s}, [x1], x3 // store row 0\n    ext       v19.8b, v18.8b , v19.8b , #1\n\n    sqrshrun  v27.8b, v24.8h, #5\n\n    uaddl     v28.8h, v18.8b, v23.8b\n    umlal     v28.8h, v20.8b, v30.8b\n    umlal     v28.8h, v21.8b, v30.8b\n    umlsl     v28.8h, v19.8b, v31.8b\n    umlsl     v28.8h, v22.8b, v31.8b\n\n    ld1       {v18.2s, v19.2s}, [x11], x2 // horz row 1, col 1\n    ld1       {v14.2s, v15.2s}, [x7], x2 // src[7_0]\n\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n\n    sqrshrun  v28.8b, v28.8h, #5\n    uaddl     v24.8h, v18.8b, v23.8b\n    umlal     v24.8h, v20.8b, v30.8b\n    umlal     v24.8h, v21.8b, v30.8b\n    umlsl     v24.8h, v19.8b, v31.8b\n    umlsl     v24.8h, v22.8b, v31.8b\n\n    ld1       {v18.2s, v19.2s}, [x6], x2 // horz row 2, col 0\n    uaddl     v16.8h, v4.8b, v14.8b\n    umlal     v16.8h, v8.8b, v30.8b\n    umlal     v16.8h, v10.8b, v30.8b\n    umlsl     v16.8h, v6.8b, v31.8b\n    umlsl     v16.8h, v12.8b, v31.8b\n\n    sqrshrun  v29.8b, v24.8h, #5\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n    urhadd    v28.16b, v28.16b , v26.16b\n    urhadd    v29.16b, v29.16b , v27.16b\n    sqrshrun  v26.8b, v16.8h, #5\n\n    uaddl     v24.8h, v5.8b, v15.8b\n    umlal     v24.8h, v9.8b, v30.8b\n    umlal     v24.8h, v11.8b, v30.8b\n    umlsl     v24.8h, v7.8b, v31.8b\n    umlsl     v24.8h, v13.8b, v31.8b\n\n    st1       {v28.2s, v29.2s}, [x1], x3 // store row 1\n\n    uaddl     v28.8h, v18.8b, v23.8b\n    umlal     v28.8h, v20.8b, v30.8b\n    umlal     v28.8h, v21.8b, v30.8b\n    umlsl     v28.8h, v19.8b, v31.8b\n    umlsl     v28.8h, v22.8b, v31.8b\n\n    ld1       {v18.2s, v19.2s}, [x11], x2 // horz row 2, col 1\n    sqrshrun  v27.8b, v24.8h, #5\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n\n    sqrshrun  v28.8b, v28.8h, #5\n    ld1       {v16.2s, v17.2s}, [x7], x2 // src[8_0]\n    uaddl     v24.8h, v18.8b, v23.8b\n    umlal     v24.8h, v20.8b, v30.8b\n    umlal     v24.8h, v21.8b, v30.8b\n    umlsl     v24.8h, v19.8b, v31.8b\n    umlsl     v24.8h, v22.8b, v31.8b\n\n    ld1       {v18.2s, v19.2s}, [x6], x2 // horz row 3, col 0\n    uaddl     v0.8h, v6.8b, v16.8b\n    umlal     v0.8h, v10.8b, v30.8b\n    umlal     v0.8h, v12.8b, v30.8b\n    umlsl     v0.8h, v8.8b, v31.8b\n    umlsl     v0.8h, v14.8b, v31.8b\n\n    sqrshrun  v29.8b, v24.8h, #5\n\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    urhadd    v28.16b, v28.16b , v26.16b\n    urhadd    v29.16b, v29.16b , v27.16b\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n    sqrshrun  v26.8b, v0.8h, #5\n    st1       {v28.2s, v29.2s}, [x1], x3 // store row 2\n\n    uaddl     v24.8h, v18.8b, v23.8b\n    umlal     v24.8h, v20.8b, v30.8b\n    umlal     v24.8h, v21.8b, v30.8b\n    umlsl     v24.8h, v19.8b, v31.8b\n    umlsl     v24.8h, v22.8b, v31.8b\n\n    ld1       {v18.2s, v19.2s}, [x11], x2 // horz row 3, col 1\n\n    uaddl     v0.8h, v7.8b, v17.8b\n    umlal     v0.8h, v11.8b, v30.8b\n    umlal     v0.8h, v13.8b, v30.8b\n    umlsl     v0.8h, v9.8b, v31.8b\n    umlsl     v0.8h, v15.8b, v31.8b\n\n    sqrshrun  v28.8b, v24.8h, #5\n\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n\n    sqrshrun  v27.8b, v0.8h, #5\n\n    uaddl     v24.8h, v18.8b, v23.8b\n    umlal     v24.8h, v20.8b, v30.8b\n    umlal     v24.8h, v21.8b, v30.8b\n    umlsl     v24.8h, v19.8b, v31.8b\n    umlsl     v24.8h, v22.8b, v31.8b\n\n    mov       v0.16b, v8.16b\n    mov       v1.16b, v9.16b\n\n    mov       v2.16b, v10.16b\n    mov       v3.16b, v11.16b\n\n    mov       v4.16b, v12.16b\n    mov       v5.16b, v13.16b\n\n    mov       v6.16b, v14.16b\n    mov       v7.16b, v15.16b\n\n    mov       v8.16b, v16.16b\n    mov       v9.16b, v17.16b\n\n    sqrshrun  v29.8b, v24.8h, #5\n    urhadd    v28.16b, v28.16b , v26.16b\n    urhadd    v29.16b, v29.16b , v27.16b\n    st1       {v28.2s, v29.2s}, [x1], x3 // store row 3\n\n    ld1       {v10.2s, v11.2s}, [x7], x2 // Vector load from src[9_0]\n    ld1       {v18.2s, v19.2s}, [x6], x2 // horz row4, col 0\n    uaddl     v24.8h, v0.8b, v10.8b\n    umlal     v24.8h, v4.8b, v30.8b\n    umlal     v24.8h, v6.8b, v30.8b\n    umlsl     v24.8h, v2.8b, v31.8b\n    umlsl     v24.8h, v8.8b, v31.8b\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n    sqrshrun  v26.8b, v24.8h, #5\n    uaddl     v28.8h, v18.8b, v23.8b\n    umlal     v28.8h, v20.8b, v30.8b\n    umlal     v28.8h, v21.8b, v30.8b\n    umlsl     v28.8h, v19.8b, v31.8b\n    umlsl     v28.8h, v22.8b, v31.8b\n    ld1       {v18.2s, v19.2s}, [x11], x2 // horz row 4, col 1\n    uaddl     v24.8h, v1.8b, v11.8b\n    umlal     v24.8h, v5.8b, v30.8b\n    umlal     v24.8h, v7.8b, v30.8b\n    umlsl     v24.8h, v3.8b, v31.8b\n    umlsl     v24.8h, v9.8b, v31.8b\n    sqrshrun  v28.8b, v28.8h, #5\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n\n    sqrshrun  v27.8b, v24.8h, #5\n    ld1       {v12.2s, v13.2s}, [x7], x2 // src[10_0]\n    uaddl     v24.8h, v18.8b, v23.8b\n    umlal     v24.8h, v20.8b, v30.8b\n    umlal     v24.8h, v21.8b, v30.8b\n    umlsl     v24.8h, v19.8b, v31.8b\n    umlsl     v24.8h, v22.8b, v31.8b\n    uaddl     v16.8h, v2.8b, v12.8b\n    umlal     v16.8h, v6.8b, v30.8b\n    umlal     v16.8h, v8.8b, v30.8b\n    umlsl     v16.8h, v4.8b, v31.8b\n    umlsl     v16.8h, v10.8b, v31.8b\n    sqrshrun  v29.8b, v24.8h, #5\n    ld1       {v18.2s, v19.2s}, [x6], x2 // horz row 5, col 0\n    uaddl     v24.8h, v3.8b, v13.8b\n    umlal     v24.8h, v7.8b, v30.8b\n    umlal     v24.8h, v9.8b, v30.8b\n    umlsl     v24.8h, v5.8b, v31.8b\n    umlsl     v24.8h, v11.8b, v31.8b\n    urhadd    v28.16b, v28.16b , v26.16b\n    urhadd    v29.16b, v29.16b , v27.16b\n    sqrshrun  v26.8b, v16.8h, #5\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    st1       {v28.2s, v29.2s}, [x1], x3 // store row 4\n    ext       v19.8b, v18.8b , v19.8b , #1\n\n    sqrshrun  v27.8b, v24.8h, #5\n\n    uaddl     v28.8h, v18.8b, v23.8b\n    umlal     v28.8h, v20.8b, v30.8b\n    umlal     v28.8h, v21.8b, v30.8b\n    umlsl     v28.8h, v19.8b, v31.8b\n    umlsl     v28.8h, v22.8b, v31.8b\n\n    ld1       {v18.2s, v19.2s}, [x11], x2 // horz row 5, col 1\n    ld1       {v14.2s, v15.2s}, [x7], x2 // src[11_0]\n\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n\n    sqrshrun  v28.8b, v28.8h, #5\n    uaddl     v24.8h, v18.8b, v23.8b\n    umlal     v24.8h, v20.8b, v30.8b\n    umlal     v24.8h, v21.8b, v30.8b\n    umlsl     v24.8h, v19.8b, v31.8b\n    umlsl     v24.8h, v22.8b, v31.8b\n\n    ld1       {v18.2s, v19.2s}, [x6], x2 // horz row 6, col 0\n    uaddl     v16.8h, v4.8b, v14.8b\n    umlal     v16.8h, v8.8b, v30.8b\n    umlal     v16.8h, v10.8b, v30.8b\n    umlsl     v16.8h, v6.8b, v31.8b\n    umlsl     v16.8h, v12.8b, v31.8b\n\n    sqrshrun  v29.8b, v24.8h, #5\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n    urhadd    v28.16b, v28.16b , v26.16b\n    urhadd    v29.16b, v29.16b , v27.16b\n    sqrshrun  v26.8b, v16.8h, #5\n\n    uaddl     v24.8h, v5.8b, v15.8b\n    umlal     v24.8h, v9.8b, v30.8b\n    umlal     v24.8h, v11.8b, v30.8b\n    umlsl     v24.8h, v7.8b, v31.8b\n    umlsl     v24.8h, v13.8b, v31.8b\n\n    st1       {v28.2s, v29.2s}, [x1], x3 // store row 5\n\n    uaddl     v28.8h, v18.8b, v23.8b\n    umlal     v28.8h, v20.8b, v30.8b\n    umlal     v28.8h, v21.8b, v30.8b\n    umlsl     v28.8h, v19.8b, v31.8b\n    umlsl     v28.8h, v22.8b, v31.8b\n\n    ld1       {v18.2s, v19.2s}, [x11], x2 // horz row 6, col 1\n    sqrshrun  v27.8b, v24.8h, #5\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n\n    sqrshrun  v28.8b, v28.8h, #5\n    ld1       {v16.2s, v17.2s}, [x7], x2 // src[12_0]\n    uaddl     v24.8h, v18.8b, v23.8b\n    umlal     v24.8h, v20.8b, v30.8b\n    umlal     v24.8h, v21.8b, v30.8b\n    umlsl     v24.8h, v19.8b, v31.8b\n    umlsl     v24.8h, v22.8b, v31.8b\n\n    ld1       {v18.2s, v19.2s}, [x6], x2 // horz row 7, col 0\n    uaddl     v0.8h, v6.8b, v16.8b\n    umlal     v0.8h, v10.8b, v30.8b\n    umlal     v0.8h, v12.8b, v30.8b\n    umlsl     v0.8h, v8.8b, v31.8b\n    umlsl     v0.8h, v14.8b, v31.8b\n\n    sqrshrun  v29.8b, v24.8h, #5\n\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    urhadd    v28.16b, v28.16b , v26.16b\n    urhadd    v29.16b, v29.16b , v27.16b\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n    sqrshrun  v26.8b, v0.8h, #5\n    st1       {v28.2s, v29.2s}, [x1], x3 // store row 6\n\n    uaddl     v24.8h, v18.8b, v23.8b\n    umlal     v24.8h, v20.8b, v30.8b\n    umlal     v24.8h, v21.8b, v30.8b\n    umlsl     v24.8h, v19.8b, v31.8b\n    umlsl     v24.8h, v22.8b, v31.8b\n\n    ld1       {v18.2s, v19.2s}, [x11], x2 // horz row 7, col 1\n\n    uaddl     v0.8h, v7.8b, v17.8b\n    umlal     v0.8h, v11.8b, v30.8b\n    umlal     v0.8h, v13.8b, v30.8b\n    umlsl     v0.8h, v9.8b, v31.8b\n    umlsl     v0.8h, v15.8b, v31.8b\n\n    sqrshrun  v28.8b, v24.8h, #5\n\n    ext       v23.8b, v18.8b , v19.8b , #5\n    ext       v20.8b, v18.8b , v19.8b , #2\n    ext       v21.8b, v18.8b , v19.8b , #3\n    ext       v22.8b, v18.8b , v19.8b , #4\n    ext       v19.8b, v18.8b , v19.8b , #1\n\n    sqrshrun  v27.8b, v0.8h, #5\n\n    uaddl     v24.8h, v18.8b, v23.8b\n    umlal     v24.8h, v20.8b, v30.8b\n    umlal     v24.8h, v21.8b, v30.8b\n    umlsl     v24.8h, v19.8b, v31.8b\n    umlsl     v24.8h, v22.8b, v31.8b\n\n    mov       v0.16b, v8.16b\n    mov       v1.16b, v9.16b\n\n    mov       v2.16b, v10.16b\n    mov       v3.16b, v11.16b\n\n    mov       v4.16b, v12.16b\n    mov       v5.16b, v13.16b\n\n    mov       v6.16b, v14.16b\n    mov       v7.16b, v15.16b\n\n    mov       v8.16b, v16.16b\n    mov       v9.16b, v17.16b\n\n    sqrshrun  v29.8b, v24.8h, #5\n    subs      x4, x4, #8\n    urhadd    v28.16b, v28.16b , v26.16b\n    urhadd    v29.16b, v29.16b , v27.16b\n    st1       {v28.2s, v29.2s}, [x1], x3 // store row 7\n\n    beq       end_func                  // stop looping if ht == 8\n    b         loop_16\n\n\nloop_8_start:\n    ld1       {v0.2s}, [x7], x2         // Vector load from src[0_0]\n    ld1       {v1.2s}, [x7], x2         // Vector load from src[1_0]\n    ld1       {v2.2s}, [x7], x2         // Vector load from src[2_0]\n    ld1       {v3.2s}, [x7], x2         // Vector load from src[3_0]\n    ld1       {v4.2s}, [x7], x2         // Vector load from src[4_0]\n\nloop_8:\n    ld1       {v5.2s}, [x7], x2         // Vector load from src[5_0]\n    uaddl     v10.8h, v0.8b, v5.8b\n    umlal     v10.8h, v2.8b, v30.8b\n    umlal     v10.8h, v3.8b, v30.8b\n    umlsl     v10.8h, v1.8b, v31.8b\n    umlsl     v10.8h, v4.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 //horz row 0\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v26.8b, v10.8h, #5\n    ld1       {v6.2s}, [x7], x2         // src[6_0]\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 // horz row 1\n    uaddl     v18.8h, v1.8b, v6.8b\n    umlal     v18.8h, v3.8b, v30.8b\n    umlal     v18.8h, v4.8b, v30.8b\n    umlsl     v18.8h, v2.8b, v31.8b\n    umlsl     v18.8h, v5.8b, v31.8b\n    sqrshrun  v28.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v27.8b, v18.8h, #5\n    ld1       {v7.2s}, [x7], x2         // src[7_0]\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 // horz row 2\n    uaddl     v18.8h, v2.8b, v7.8b\n    umlal     v18.8h, v4.8b, v30.8b\n    umlal     v18.8h, v5.8b, v30.8b\n    umlsl     v18.8h, v3.8b, v31.8b\n    umlsl     v18.8h, v6.8b, v31.8b\n    sqrshrun  v29.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    urhadd    v26.16b, v26.16b , v28.16b\n    urhadd    v27.16b, v27.16b , v29.16b\n    sqrshrun  v28.8b, v18.8h, #5\n    ld1       {v8.2s}, [x7], x2         // src[8_0]\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 // horz row 3\n    uaddl     v18.8h, v3.8b, v8.8b\n    umlal     v18.8h, v5.8b, v30.8b\n    umlal     v18.8h, v6.8b, v30.8b\n    umlsl     v18.8h, v4.8b, v31.8b\n    umlsl     v18.8h, v7.8b, v31.8b\n    sqrshrun  v24.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v29.8b, v18.8h, #5\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    st1       {v26.2s}, [x1], x3\n\n    mov       v0.16b, v4.16b\n    mov       v1.16b, v5.16b\n\n    st1       {v27.2s}, [x1], x3\n\n    mov       v2.16b, v6.16b\n    mov       v3.16b, v7.16b\n\n    mov       v4.8b, v8.8b\n\n    sqrshrun  v25.8b, v10.8h, #5\n    subs      x9, x4, #4\n    urhadd    v24.16b, v24.16b , v28.16b\n    urhadd    v25.16b, v25.16b , v29.16b\n    st1       {v24.2s}, [x1], x3\n    st1       {v25.2s}, [x1], x3\n    beq       end_func                  // Branch if height==4\n\n    ld1       {v5.2s}, [x7], x2         // Vector load from src[9_0]\n    uaddl     v10.8h, v0.8b, v5.8b\n    umlal     v10.8h, v2.8b, v30.8b\n    umlal     v10.8h, v3.8b, v30.8b\n    umlsl     v10.8h, v1.8b, v31.8b\n    umlsl     v10.8h, v4.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 //horz row 4\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v26.8b, v10.8h, #5\n    ld1       {v6.2s}, [x7], x2         // src[10_0]\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 // horz row 5\n    uaddl     v18.8h, v1.8b, v6.8b\n    umlal     v18.8h, v3.8b, v30.8b\n    umlal     v18.8h, v4.8b, v30.8b\n    umlsl     v18.8h, v2.8b, v31.8b\n    umlsl     v18.8h, v5.8b, v31.8b\n    sqrshrun  v28.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v27.8b, v18.8h, #5\n    ld1       {v7.2s}, [x7], x2         // src[11_0]\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 // horz row 6\n    uaddl     v18.8h, v2.8b, v7.8b\n    umlal     v18.8h, v4.8b, v30.8b\n    umlal     v18.8h, v5.8b, v30.8b\n    umlsl     v18.8h, v3.8b, v31.8b\n    umlsl     v18.8h, v6.8b, v31.8b\n    sqrshrun  v29.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    urhadd    v26.16b, v26.16b , v28.16b\n    urhadd    v27.16b, v27.16b , v29.16b\n    sqrshrun  v28.8b, v18.8h, #5\n    ld1       {v8.2s}, [x7], x2         // src[12_0]\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 // horz row 7\n    uaddl     v18.8h, v3.8b, v8.8b\n    umlal     v18.8h, v5.8b, v30.8b\n    umlal     v18.8h, v6.8b, v30.8b\n    umlsl     v18.8h, v4.8b, v31.8b\n    umlsl     v18.8h, v7.8b, v31.8b\n    sqrshrun  v24.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v29.8b, v18.8h, #5\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    st1       {v26.2s}, [x1], x3\n\n    mov       v0.16b, v4.16b\n    mov       v1.16b, v5.16b\n    st1       {v27.2s}, [x1], x3\n\n    mov       v2.16b, v6.16b\n    mov       v3.16b, v7.16b\n\n    mov       v4.8b, v8.8b\n    mov       v5.8b, v9.8b\n\n    sqrshrun  v25.8b, v10.8h, #5\n    subs      x4, x4, #8\n    urhadd    v24.16b, v24.16b , v28.16b\n    urhadd    v25.16b, v25.16b , v29.16b\n    st1       {v24.2s}, [x1], x3\n    st1       {v25.2s}, [x1], x3\n    bgt       loop_8                    //if height =8  loop\n    b         end_func\n\nloop_4_start:\n    ld1       {v0.s}[0], [x7], x2       // Vector load from src[0_0]\n    ld1       {v1.s}[0], [x7], x2       // Vector load from src[1_0]\n\n    ld1       {v2.s}[0], [x7], x2       // Vector load from src[2_0]\n    ld1       {v3.s}[0], [x7], x2       // Vector load from src[3_0]\n    ld1       {v4.s}[0], [x7], x2       // Vector load from src[4_0]\n\n    ld1       {v5.s}[0], [x7], x2       // Vector load from src[5_0]\n    uaddl     v10.8h, v0.8b, v5.8b\n    umlal     v10.8h, v2.8b, v30.8b\n    umlal     v10.8h, v3.8b, v30.8b\n    umlsl     v10.8h, v1.8b, v31.8b\n    umlsl     v10.8h, v4.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 //load for horz filter row 0\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v26.8b, v10.8h, #5\n    ld1       {v6.s}[0], [x7], x2       // Vector load from src[6_0]\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 //horz row 1\n    uaddl     v18.8h, v1.8b, v6.8b\n    umlal     v18.8h, v3.8b, v30.8b\n    umlal     v18.8h, v4.8b, v30.8b\n    umlsl     v18.8h, v2.8b, v31.8b\n    umlsl     v18.8h, v5.8b, v31.8b\n    sqrshrun  v28.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v27.8b, v18.8h, #5\n    ld1       {v7.s}[0], [x7], x2       // Vector load from src[7_0]\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 //horz row 2\n    uaddl     v18.8h, v2.8b, v7.8b\n    umlal     v18.8h, v4.8b, v30.8b\n    umlal     v18.8h, v5.8b, v30.8b\n    umlsl     v18.8h, v3.8b, v31.8b\n    umlsl     v18.8h, v6.8b, v31.8b\n    sqrshrun  v29.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    urhadd    v26.16b, v26.16b , v28.16b\n    urhadd    v27.16b, v27.16b , v29.16b\n    sqrshrun  v28.8b, v18.8h, #5\n    ld1       {v8.s}[0], [x7], x2       // Vector load from src[8_0]\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 //horz row 3\n    uaddl     v18.8h, v3.8b, v8.8b\n    umlal     v18.8h, v5.8b, v30.8b\n    umlal     v18.8h, v6.8b, v30.8b\n    umlsl     v18.8h, v4.8b, v31.8b\n    umlsl     v18.8h, v7.8b, v31.8b\n    sqrshrun  v24.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v29.8b, v18.8h, #5\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    st1       {v26.s}[0], [x1], x3\n\n    mov       v0.16b, v4.16b\n    mov       v1.16b, v5.16b\n\n    st1       {v27.s}[0], [x1], x3\n\n    mov       v2.16b, v6.16b\n    mov       v3.16b, v7.16b\n    mov       v4.8b, v8.8b\n\n    sqrshrun  v25.8b, v10.8h, #5\n    subs      x4, x4, #4\n    urhadd    v24.16b, v24.16b , v28.16b\n    urhadd    v25.16b, v25.16b , v29.16b\n    st1       {v24.s}[0], [x1], x3\n    st1       {v25.s}[0], [x1], x3\n    beq       end_func                  // Branch if height==4\n\n    ld1       {v5.s}[0], [x7], x2       // Vector load from src[5_0]\n    uaddl     v10.8h, v0.8b, v5.8b\n    umlal     v10.8h, v2.8b, v30.8b\n    umlal     v10.8h, v3.8b, v30.8b\n    umlsl     v10.8h, v1.8b, v31.8b\n    umlsl     v10.8h, v4.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 //load for horz filter row 4\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v26.8b, v10.8h, #5\n    ld1       {v6.s}[0], [x7], x2\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 //horz row 5\n    uaddl     v18.8h, v1.8b, v6.8b\n    umlal     v18.8h, v3.8b, v30.8b\n    umlal     v18.8h, v4.8b, v30.8b\n    umlsl     v18.8h, v2.8b, v31.8b\n    umlsl     v18.8h, v5.8b, v31.8b\n    sqrshrun  v28.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v27.8b, v18.8h, #5\n    ld1       {v7.s}[0], [x7], x2\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 //horz row 6\n    uaddl     v18.8h, v2.8b, v7.8b\n    umlal     v18.8h, v4.8b, v30.8b\n    umlal     v18.8h, v5.8b, v30.8b\n    umlsl     v18.8h, v3.8b, v31.8b\n    umlsl     v18.8h, v6.8b, v31.8b\n    sqrshrun  v29.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    urhadd    v26.16b, v26.16b , v28.16b\n    urhadd    v27.16b, v27.16b , v29.16b\n    sqrshrun  v28.8b, v18.8h, #5\n    ld1       {v8.s}[0], [x7], x2\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    ld1       {v12.2s, v13.2s}, [x6], x2 //horz row 7\n    uaddl     v18.8h, v3.8b, v8.8b\n    umlal     v18.8h, v5.8b, v30.8b\n    umlal     v18.8h, v6.8b, v30.8b\n    umlsl     v18.8h, v4.8b, v31.8b\n    umlsl     v18.8h, v7.8b, v31.8b\n    sqrshrun  v24.8b, v10.8h, #5\n    ext       v17.8b, v12.8b , v13.8b , #5\n    ext       v14.8b, v12.8b , v13.8b , #2\n    ext       v15.8b, v12.8b , v13.8b , #3\n    ext       v16.8b, v12.8b , v13.8b , #4\n    ext       v13.8b, v12.8b , v13.8b , #1\n    sqrshrun  v29.8b, v18.8h, #5\n    uaddl     v10.8h, v12.8b, v17.8b\n    umlal     v10.8h, v14.8b, v30.8b\n    umlal     v10.8h, v15.8b, v30.8b\n    umlsl     v10.8h, v13.8b, v31.8b\n    umlsl     v10.8h, v16.8b, v31.8b\n    st1       {v26.s}[0], [x1], x3\n    st1       {v27.s}[0], [x1], x3\n    sqrshrun  v25.8b, v10.8h, #5\n    urhadd    v24.16b, v24.16b , v28.16b\n    urhadd    v25.16b, v25.16b , v29.16b\n    st1       {v24.s}[0], [x1], x3\n    st1       {v25.s}[0], [x1], x3\n\nend_func:\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_inter_pred_luma_vert_qpel_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_inter_pred_luma_vert_qpel_av8.s\n//*\n//* @brief\n//*  Contains function definitions for inter prediction vertical quarter pel interpolation.\n//*\n//* @author\n//*  Mohit\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_inter_pred_luma_vert_qpel_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_inter_pred_filters.c\n//\n\n///**\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*     Quarter pel interprediction luma filter for vertical input\n//*\n//* @par Description:\n//* Applies a 6 tap horizontal filter .The output is  clipped to 8 bits\n//* sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @param[in] pu1_tmp: temporary buffer: UNUSED in this function\n//*\n//* @param[in] dydx: x and y reference offset for qpel calculations.\n//* @returns\n//*\n// @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n//void ih264_inter_pred_luma_vert (\n//                            UWORD8 *pu1_src,\n//                            UWORD8 *pu1_dst,\n//                            WORD32 src_strd,\n//                            WORD32 dst_strd,\n//                            WORD32 ht,\n//                            WORD32 wd,\n//                              UWORD8* pu1_tmp,\n//                             UWORD32 dydx)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ht\n//    w5 =>  wd\n//    w7 =>  dydx\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_inter_pred_luma_vert_qpel_av8\n\nih264_inter_pred_luma_vert_qpel_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x2, w2\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n\n\n    and       x7, x7, #12               //Finds y-offset\n    lsr       x7, x7, #3                //dydx>>3\n    mul       x7, x2, x7\n    add       x7, x0, x7                //pu1_src + (y_offset>>1)*src_strd\n    sub       x14, x4, #16\n    movi      v22.8h, #20               // Filter coeff 0x14 into Q11\n    sub       x0, x0, x2, lsl #1        //pu1_src-2*src_strd\n    subs      x12, x5, #8               //if wd=8 branch to loop_8\n    movi      v24.8h, #5                // Filter coeff 0x4  into Q12\n    beq       loop_8_start\n\n    subs      x12, x5, #4               //if wd=4 branch to loop_4\n    beq       loop_4_start\n\n\n    ld1       {v0.2s, v1.2s}, [x0], x2  // Vector load from src[0_0]\n    ld1       {v2.2s, v3.2s}, [x0], x2  // Vector load from src[1_0]\n    ld1       {v4.2s, v5.2s}, [x0], x2  // Vector load from src[2_0]\n    ld1       {v6.2s, v7.2s}, [x0], x2  // Vector load from src[3_0]\n    add       x14, x14, #1              //for checking loop\n    ld1       {v8.2s, v9.2s}, [x0], x2  // Vector load from src[4_0]\n    uaddl     v12.8h, v4.8b, v6.8b      // temp1 = src[2_0] + src[3_0]\n    ld1       {v10.2s, v11.2s}, [x0], x2 // Vector load from src[5_0]\n\nloop_16:                                //when  wd=16\n\n    uaddl     v14.8h, v0.8b, v10.8b     // temp = src[0_0] + src[5_0]\n    uaddl     v16.8h, v2.8b, v8.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v14.8h, v12.8h , v22.8h   // temp += temp1 * 20\n    uaddl     v20.8h, v1.8b, v11.8b     // temp4 = src[0_8] + src[5_8]\n    uaddl     v18.8h, v5.8b, v7.8b      // temp3 = src[2_8] + src[3_8]\n    mla       v20.8h, v18.8h , v22.8h   // temp4 += temp3 * 20\n    ld1       {v0.2s, v1.2s}, [x0], x2\n    uaddl     v26.8h, v3.8b, v9.8b      // temp5 = src[1_8] + src[4_8]\n    uaddl     v12.8h, v6.8b, v8.8b\n    mls       v14.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v16.8h, v2.8b, v0.8b\n    uaddl     v18.8h, v4.8b, v10.8b\n    mla       v16.8h, v12.8h , v22.8h\n    mls       v20.8h, v26.8h , v24.8h   // temp4 -= temp5 * 5\n    uaddl     v26.8h, v5.8b, v11.8b\n    uaddl     v12.8h, v7.8b, v9.8b\n    sqrshrun  v30.8b, v14.8h, #5        // dst[0_0] = CLIP_U8((temp +16) >> 5)\n    uaddl     v14.8h, v3.8b, v1.8b\n    ld1       {v2.2s, v3.2s}, [x0], x2\n    mla       v14.8h, v12.8h , v22.8h\n    mls       v16.8h, v18.8h , v24.8h\n    sqrshrun  v31.8b, v20.8h, #5        // dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    ld1       {v20.2s, v21.2s}, [x7], x2 // Load for interpolation row 0\n    urhadd    v30.16b, v20.16b , v30.16b // Interpolation to obtain qpel value\n    urhadd    v31.16b, v21.16b , v31.16b // Interpolation to obtain qpel value\n    uaddl     v18.8h, v4.8b, v2.8b\n    uaddl     v12.8h, v8.8b, v10.8b\n    st1       {v30.2s, v31.2s}, [x1], x3 // Vector store to dst[0_0]\n    mla       v18.8h, v12.8h , v22.8h\n    uaddl     v20.8h, v6.8b, v0.8b\n    mls       v14.8h, v26.8h , v24.8h\n    sqrshrun  v30.8b, v16.8h, #5\n    uaddl     v12.8h, v9.8b, v11.8b\n    uaddl     v16.8h, v5.8b, v3.8b\n    uaddl     v26.8h, v7.8b, v1.8b\n    mla       v16.8h, v12.8h , v22.8h\n    mls       v18.8h, v20.8h , v24.8h\n    ld1       {v4.2s, v5.2s}, [x0], x2\n    sqrshrun  v31.8b, v14.8h, #5\n    ld1       {v14.2s, v15.2s}, [x7], x2 // Load for interpolation row 1\n    uaddl     v12.8h, v10.8b, v0.8b\n    urhadd    v30.16b, v14.16b , v30.16b // Interpolation to obtain qpel value\n    urhadd    v31.16b, v15.16b , v31.16b // Interpolation to obtain qpel value\n    uaddl     v14.8h, v6.8b, v4.8b\n    uaddl     v20.8h, v8.8b, v2.8b\n    mla       v14.8h, v12.8h , v22.8h\n    mls       v16.8h, v26.8h , v24.8h\n    st1       {v30.2s, v31.2s}, [x1], x3 //store row 1\n    sqrshrun  v30.8b, v18.8h, #5\n    uaddl     v18.8h, v7.8b, v5.8b\n    uaddl     v12.8h, v11.8b, v1.8b\n    mla       v18.8h, v12.8h , v22.8h\n    uaddl     v26.8h, v9.8b, v3.8b\n    mls       v14.8h, v20.8h , v24.8h\n    ld1       {v6.2s, v7.2s}, [x0], x2\n    sqrshrun  v31.8b, v16.8h, #5\n    ld1       {v16.2s, v17.2s}, [x7], x2 // Load for interpolation row 2\n    mls       v18.8h, v26.8h , v24.8h\n    urhadd    v30.16b, v16.16b , v30.16b // Interpolation to obtain qpel value\n    urhadd    v31.16b, v17.16b , v31.16b // Interpolation to obtain qpel value\n    uaddl     v12.8h, v0.8b, v2.8b      // temp1 = src[2_0] + src[3_0]\n    st1       {v30.2s, v31.2s}, [x1], x3 //store row 2\n    uaddl     v16.8h, v10.8b, v4.8b     // temp2 = src[1_0] + src[4_0]\n    uaddl     v20.8h, v9.8b, v7.8b      // temp4 = src[0_8] + src[5_8]\n    sqrshrun  v30.8b, v14.8h, #5\n    uaddl     v26.8h, v5.8b, v11.8b     // temp5 = src[1_8] + src[4_8]\n    uaddl     v14.8h, v8.8b, v6.8b      // temp = src[0_0] + src[5_0]\n    sqrshrun  v31.8b, v18.8h, #5\n    ld1       {v18.2s, v19.2s}, [x7], x2 // Load for interpolation row 3\n    mla       v14.8h, v12.8h , v22.8h   // temp += temp1 * 20\n    urhadd    v30.16b, v18.16b , v30.16b // Interpolation to obtain qpel value\n    urhadd    v31.16b, v19.16b , v31.16b // Interpolation to obtain qpel value\n    uaddl     v18.8h, v1.8b, v3.8b      // temp3 = src[2_8] + src[3_8]\n    st1       {v30.2s, v31.2s}, [x1], x3 //store row 3\n    // 4 rows processed\n    mla       v20.8h, v18.8h , v22.8h   // temp4 += temp3 * 20\n    ld1       {v8.2s, v9.2s}, [x0], x2\n    uaddl     v12.8h, v2.8b, v4.8b\n    uaddl     v18.8h, v3.8b, v5.8b\n    mls       v14.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v28.8h, v9.8b, v11.8b\n    uaddl     v16.8h, v6.8b, v0.8b\n    mla       v28.8h, v18.8h , v22.8h   // temp4 += temp3 * 20\n    mls       v20.8h, v26.8h , v24.8h   // temp4 -= temp5 * 5\n    uaddl     v26.8h, v1.8b, v7.8b\n    uaddl     v18.8h, v5.8b, v7.8b\n    sqrshrun  v30.8b, v14.8h, #5        // dst[0_0] = CLIP_U8((temp +16) >> 5)\n    uaddl     v14.8h, v8.8b, v10.8b\n    sqrshrun  v31.8b, v20.8h, #5        // dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    ld1       {v20.2s, v21.2s}, [x7], x2 // Load for interpolation row 4\n    ld1       {v10.2s, v11.2s}, [x0], x2\n    urhadd    v30.16b, v20.16b , v30.16b // Interpolation to obtain qpel value\n    urhadd    v31.16b, v21.16b , v31.16b // Interpolation to obtain qpel value\n    mls       v28.8h, v26.8h , v24.8h   // temp4 -= temp5 * 5\n    st1       {v30.2s, v31.2s}, [x1], x3 //  store row 4\n    mla       v14.8h, v12.8h , v22.8h   // temp += temp1 * 20\n    uaddl     v20.8h, v11.8b, v1.8b\n    uaddl     v26.8h, v3.8b, v9.8b\n    mla       v20.8h, v18.8h , v22.8h   // temp4 += temp3 * 20\n    uaddl     v12.8h, v6.8b, v4.8b\n    uaddl     v18.8h, v7.8b, v9.8b\n    sqrshrun  v31.8b, v28.8h, #5        // dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    mls       v14.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v16.8h, v8.8b, v2.8b\n    sqrshrun  v30.8b, v14.8h, #5        // dst[0_0] = CLIP_U8((temp +16) >> 5)\n    ld1       {v14.2s, v15.2s}, [x7], x2 // Load for interpolation row 5\n    mls       v20.8h, v26.8h , v24.8h   // temp4 -= temp5 * 5\n    urhadd    v30.16b, v14.16b , v30.16b // Interpolation to obtain qpel value\n    urhadd    v31.16b, v15.16b , v31.16b // Interpolation to obtain qpel value\n    uaddl     v14.8h, v10.8b, v0.8b\n    st1       {v30.2s, v31.2s}, [x1], x3 //  store row 5\n    mla       v14.8h, v12.8h , v22.8h   // temp += temp1 * 20\n    ld1       {v0.2s, v1.2s}, [x0], x2\n    uaddl     v26.8h, v5.8b, v11.8b\n    uaddl     v12.8h, v8.8b, v6.8b\n    uaddl     v28.8h, v0.8b, v2.8b\n    sqrshrun  v31.8b, v20.8h, #5        // dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    mla       v28.8h, v12.8h , v22.8h   // temp += temp1 * 20\n    uaddl     v20.8h, v1.8b, v3.8b\n    mls       v14.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    mla       v20.8h, v18.8h , v22.8h   // temp4 += temp3 * 20\n    uaddl     v16.8h, v10.8b, v4.8b\n    sqrshrun  v30.8b, v14.8h, #5        // dst[0_0] = CLIP_U8((temp +16) >> 5)\n    ld1       {v14.2s, v15.2s}, [x7], x2 // Load for interpolation row 6\n    mov       v2.8b, v6.8b\n    mov       v3.8b, v7.8b\n    urhadd    v30.16b, v14.16b , v30.16b // Interpolation to obtain qpel value\n    urhadd    v31.16b, v15.16b , v31.16b // Interpolation to obtain qpel value\n\n    mls       v28.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    st1       {v30.2s, v31.2s}, [x1], x3 //  store row 6\n    sqrshrun  v30.8b, v28.8h, #5        // dst[0_0] = CLIP_U8((temp +16) >> 5)\n    swp       v0.8b, v4.8b              // swapping registers to put it in order\n    swp       v1.8b, v5.8b              // swapping registers to put it in order\n\n    mls       v20.8h, v26.8h , v24.8h   // temp4 -= temp5 * 5\n    mov       v6.8b, v10.8b\n    mov       v7.8b, v11.8b\n    subs      x12, x14, #1              // if height==16  - looping\n    swp       v4.8b, v8.8b\n    swp       v5.8b, v9.8b\n    sqrshrun  v31.8b, v20.8h, #5        // dst[0_8] = CLIP_U8((temp4 +16) >> 5)\n    ld1       {v20.2s, v21.2s}, [x7], x2 // Load for interpolation row 7\n    urhadd    v30.16b, v20.16b , v30.16b // Interpolation to obtain qpel value\n    urhadd    v31.16b, v21.16b , v31.16b // Interpolation to obtain qpel value\n    st1       {v30.2s, v31.2s}, [x1], x3 //  store row 7\n    bne       end_func                  //if height =8  end function\n    add       x14, x14, #1              //for checking loop\n    ld1       {v10.2s, v11.2s}, [x0], x2\n    uaddl     v12.8h, v4.8b, v6.8b      // temp1 = src[2_0] + src[3_0]\n\n    b         loop_16                   // looping if height =16\n\nloop_8_start:\n//// Processing row0 and row1\n\n    ld1       {v0.2s}, [x0], x2         // Vector load from src[0_0]\n    ld1       {v1.2s}, [x0], x2         // Vector load from src[1_0]\n    ld1       {v2.2s}, [x0], x2         // Vector load from src[2_0]\n    ld1       {v3.2s}, [x0], x2         // Vector load from src[3_0]\n    add       x14, x14, #1              //for checking loop\n    ld1       {v4.2s}, [x0], x2         // Vector load from src[4_0]\n    ld1       {v5.2s}, [x0], x2         // Vector load from src[5_0]\n\nloop_8:\n                                        //for checking loop\n    uaddl     v6.8h, v2.8b, v3.8b       // temp1 = src[2_0] + src[3_0]\n    uaddl     v8.8h, v0.8b, v5.8b       // temp = src[0_0] + src[5_0]\n    uaddl     v10.8h, v1.8b, v4.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v8.8h, v6.8h , v22.8h     // temp += temp1 * 20\n    ld1       {v6.2s}, [x0], x2\n    uaddl     v14.8h, v3.8b, v4.8b\n    uaddl     v16.8h, v1.8b, v6.8b\n    uaddl     v18.8h, v2.8b, v5.8b\n    mls       v8.8h, v10.8h , v24.8h    // temp -= temp2 * 5\n    mla       v16.8h, v14.8h , v22.8h\n    ld1       {v7.2s}, [x0], x2\n    uaddl     v20.8h, v4.8b, v5.8b\n    uaddl     v12.8h, v2.8b, v7.8b\n    uaddl     v10.8h, v3.8b, v6.8b\n    mls       v16.8h, v18.8h , v24.8h\n    sqrshrun  v26.8b, v8.8h, #5         // dst[0_0] = CLIP_U8( (temp + 16) >> 5)\n    mla       v12.8h, v20.8h , v22.8h\n    ld1       {v8.2s}, [x7], x2         //Load value for interpolation            (row0)\n    ld1       {v9.2s}, [x7], x2         //Load value for interpolation            (row1)\n    ld1       {v0.2s}, [x0], x2\n    uaddl     v14.8h, v5.8b, v6.8b\n    sqrshrun  v27.8b, v16.8h, #5\n    urhadd    v26.16b, v8.16b , v26.16b // Interpolation step for qpel calculation\n    urhadd    v27.16b, v9.16b , v27.16b // Interpolation step for qpel calculation\n\n    uaddl     v20.8h, v3.8b, v0.8b\n    mls       v12.8h, v10.8h , v24.8h\n    st1       {v26.2s}, [x1], x3        // Vector store to dst[0_0]\n    uaddl     v18.8h, v4.8b, v7.8b\n    mla       v20.8h, v14.8h , v22.8h\n    st1       {v27.2s}, [x1], x3        // Vector store to dst[1_0]\n    sqrshrun  v28.8b, v12.8h, #5\n    mls       v20.8h, v18.8h , v24.8h\n    ld1       {v12.2s}, [x7], x2        //Load value for interpolation            (row2)\n    ld1       {v13.2s}, [x7], x2        //Load value for interpolation            (row3)\n    ld1       {v1.2s}, [x0], x2\n    sqrshrun  v29.8b, v20.8h, #5\n    subs      x9, x4, #4\n    urhadd    v28.16b, v12.16b , v28.16b\n    urhadd    v29.16b, v13.16b , v29.16b\n    st1       {v28.2s}, [x1], x3        //store row 2\n    st1       {v29.2s}, [x1], x3        //store row 3\n    beq       end_func                  // Branch if height==4\n    uaddl     v14.8h, v6.8b, v7.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v16.8h, v0.8b, v5.8b      // temp = src[0_0] + src[5_0]\n    uaddl     v18.8h, v1.8b, v4.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v18.8h, v14.8h , v22.8h   // temp += temp1 * 20\n    ld1       {v2.2s}, [x0], x2\n    mls       v18.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v8.8h, v0.8b, v7.8b\n    uaddl     v10.8h, v1.8b, v6.8b\n    uaddl     v12.8h, v2.8b, v5.8b\n    sqrshrun  v26.8b, v18.8h, #5\n    mla       v12.8h, v8.8h , v22.8h\n    ld1       {v18.2s}, [x7], x2        //Load value for interpolation            (row4)\n    ld1       {v19.2s}, [x7], x2        //Load value for interpolation            (row5)\n    ld1       {v3.2s}, [x0], x2\n    mls       v12.8h, v10.8h , v24.8h\n    sqrshrun  v27.8b, v12.8h, #5\n    urhadd    v26.16b, v18.16b , v26.16b // Interpolation step for qpel calculation\n    urhadd    v27.16b, v19.16b , v27.16b // Interpolation step for qpel calculation\n\n    st1       {v26.2s}, [x1], x3        // store row 4\n    st1       {v27.2s}, [x1], x3        // store row 5\n    uaddl     v14.8h, v0.8b, v1.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v16.8h, v2.8b, v7.8b      // temp = src[0_0] + src[5_0]\n    uaddl     v18.8h, v3.8b, v6.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v18.8h, v14.8h , v22.8h   // temp += temp1 * 20\n    ld1       {v4.2s}, [x0], x2\n    mls       v18.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v8.8h, v2.8b, v1.8b\n    uaddl     v10.8h, v3.8b, v0.8b\n    uaddl     v12.8h, v4.8b, v7.8b\n    sqrshrun  v26.8b, v18.8h, #5\n    mla       v12.8h, v8.8h , v22.8h\n    ld1       {v18.2s}, [x7], x2        //Load value for interpolation            (row6)\n    ld1       {v19.2s}, [x7], x2        //Load value for interpolation            (row7)\n    ld1       {v5.2s}, [x0], x2\n    mls       v12.8h, v10.8h , v24.8h\n    sqrshrun  v27.8b, v12.8h, #5\n    urhadd    v26.16b, v18.16b , v26.16b // Interpolation step for qpel calculation\n    urhadd    v27.16b, v19.16b , v27.16b // Interpolation step for qpel calculation\n\n    subs      x12, x14, #1\n    st1       {v26.2s}, [x1], x3        // store row 6\n    st1       {v27.2s}, [x1], x3        // store row 7\n    add       x14, x14, #1\n    beq       loop_8                    //looping if height ==16\n\n    b         end_func\n\n\nloop_4_start:\n//// Processing row0 and row1\n\n\n    ld1       {v0.s}[0], [x0], x2       // Vector load from src[0_0]\n    ld1       {v1.s}[0], [x0], x2       // Vector load from src[1_0]\n    ld1       {v2.s}[0], [x0], x2       // Vector load from src[2_0]\n    ld1       {v3.s}[0], [x0], x2       // Vector load from src[3_0]\n    ld1       {v4.s}[0], [x0], x2       // Vector load from src[4_0]\n    ld1       {v5.s}[0], [x0], x2       // Vector load from src[5_0]\n\n    uaddl     v6.8h, v2.8b, v3.8b       // temp1 = src[2_0] + src[3_0]\n    uaddl     v8.8h, v0.8b, v5.8b       // temp = src[0_0] + src[5_0]\n    uaddl     v10.8h, v1.8b, v4.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v8.8h, v6.8h , v22.8h     // temp += temp1 * 20\n    ld1       {v6.2s}, [x0], x2\n    uaddl     v14.8h, v3.8b, v4.8b\n    uaddl     v16.8h, v1.8b, v6.8b\n    uaddl     v18.8h, v2.8b, v5.8b\n    mls       v8.8h, v10.8h , v24.8h    // temp -= temp2 * 5\n    ld1       {v7.s}[0], [x0], x2\n    mla       v16.8h, v14.8h , v22.8h\n    uaddl     v20.8h, v4.8b, v5.8b\n    uaddl     v12.8h, v2.8b, v7.8b\n    uaddl     v10.8h, v3.8b, v6.8b\n    mls       v16.8h, v18.8h , v24.8h\n    sqrshrun  v26.8b, v8.8h, #5         // dst[0_0] = CLIP_U8( (temp + 16) >> 5)\n    ld1       {v8.s}[0], [x7], x2       //Load value for interpolation - row 0\n    ld1       {v9.s}[0], [x7], x2       //Load value for interpolation - row 1\n    mla       v12.8h, v20.8h , v22.8h\n    ld1       {v0.s}[0], [x0], x2\n    uaddl     v14.8h, v5.8b, v6.8b\n    sqrshrun  v27.8b, v16.8h, #5\n    uaddl     v20.8h, v3.8b, v0.8b\n    urhadd    v26.16b, v26.16b , v8.16b //Interpolation step for qpel calculation\n    urhadd    v27.16b, v27.16b , v9.16b //Interpolation step for qpel calculation\n\n    mls       v12.8h, v10.8h , v24.8h\n    st1       {v26.s}[0], [x1], x3      // Vector store to dst[0_0]\n    uaddl     v18.8h, v4.8b, v7.8b\n    mla       v20.8h, v14.8h , v22.8h\n    st1       {v27.s}[0], [x1], x3      // store row 1\n    sqrshrun  v28.8b, v12.8h, #5\n    ld1       {v12.s}[0], [x7], x2      //Load value for interpolation - row 2\n    ld1       {v13.s}[0], [x7], x2      //Load value for interpolation - row 3\n\n    mls       v20.8h, v18.8h , v24.8h\n    ld1       {v1.s}[0], [x0], x2\n    sqrshrun  v29.8b, v20.8h, #5\n    urhadd    v28.16b, v12.16b , v28.16b //Interpolation step for qpel calculation\n    urhadd    v29.16b, v13.16b , v29.16b //Interpolation step for qpel calculation\n\n    st1       {v28.s}[0], [x1], x3      //store row 2\n    st1       {v29.s}[0], [x1], x3      //store row 3\n\n    subs      x9, x4, #4\n    beq       end_func                  // Branch if height==4\n\n\n    uaddl     v14.8h, v6.8b, v7.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v16.8h, v0.8b, v5.8b      // temp = src[0_0] + src[5_0]\n    uaddl     v18.8h, v1.8b, v4.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v18.8h, v14.8h , v22.8h   // temp += temp1 * 20\n    ld1       {v2.s}[0], [x0], x2\n    mls       v18.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v8.8h, v0.8b, v7.8b\n    uaddl     v10.8h, v1.8b, v6.8b\n    uaddl     v12.8h, v2.8b, v5.8b\n    sqrshrun  v26.8b, v18.8h, #5\n    ld1       {v18.s}[0], [x7], x2      //Load value for interpolation - row 4\n    ld1       {v19.s}[0], [x7], x2      //Load value for interpolation - row 5\n    mla       v12.8h, v8.8h , v22.8h\n    ld1       {v3.s}[0], [x0], x2\n    mls       v12.8h, v10.8h , v24.8h\n    sqrshrun  v27.8b, v12.8h, #5\n    urhadd    v26.16b, v18.16b , v26.16b //Interpolation step for qpel calculation\n    urhadd    v27.16b, v27.16b , v19.16b //Interpolation step for qpel calculation\n\n    st1       {v26.s}[0], [x1], x3      //store row 4\n    st1       {v27.s}[0], [x1], x3      // store row 5\n    uaddl     v14.8h, v0.8b, v1.8b      // temp1 = src[2_0] + src[3_0]\n    uaddl     v16.8h, v2.8b, v7.8b      // temp = src[0_0] + src[5_0]\n    uaddl     v18.8h, v3.8b, v6.8b      // temp2 = src[1_0] + src[4_0]\n    mla       v18.8h, v14.8h , v22.8h   // temp += temp1 * 20\n    ld1       {v4.s}[0], [x0], x2\n    mls       v18.8h, v16.8h , v24.8h   // temp -= temp2 * 5\n    uaddl     v8.8h, v2.8b, v1.8b\n    uaddl     v10.8h, v3.8b, v0.8b\n    uaddl     v12.8h, v4.8b, v7.8b\n    sqrshrun  v26.8b, v18.8h, #5\n    ld1       {v18.s}[0], [x7], x2      //Load value for interpolation - row 6\n    ld1       {v19.s}[0], [x7], x2      //Load value for interpolation - row 7\n    mla       v12.8h, v8.8h , v22.8h\n    ld1       {v5.s}[0], [x0], x2\n    mls       v12.8h, v10.8h , v24.8h\n    sqrshrun  v27.8b, v12.8h, #5\n    urhadd    v26.16b, v18.16b , v26.16b //Interpolation step for qpel calculation\n    urhadd    v27.16b, v19.16b , v27.16b //Interpolation step for qpel calculation\n\n    st1       {v26.s}[0], [x1], x3      // store row 6\n    st1       {v27.s}[0], [x1], x3      // store row 7\n\n\nend_func:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_intra_pred_chroma_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_intra_pred_chroma.s\n//*\n//* @brief\n//*  Contains function definitions for intra chroma prediction .\n//*\n//* @author\n//*  Ittiam\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_intra_pred_luma_chroma_mode_vert_av8()\n//*  - ih264_intra_pred_luma_chroma_mode_horz_av8()\n//*  - ih264_intra_pred_luma_chroma_mode_dc_av8()\n//*  - ih264_intra_pred_luma_chroma_mode_plane_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_chroma_intra_pred_filters.c\n//\n\n///**\n///**\n///**\n//\n\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n.extern ih264_gai1_intrapred_chroma_plane_coeffs1\n.extern ih264_gai1_intrapred_chroma_plane_coeffs2\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_chroma_8x8_mode_dc\n//*\n//* @brief\n//*     Perform Intra prediction for  chroma_8x8 mode:DC\n//*\n//* @par Description:\n//*    Perform Intra prediction for  chroma_8x8 mode:DC ,described in sec 8.3.4.1\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source containing alternate U and V samples\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination with alternate U and V samples\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//** @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_chroma_8x8_mode_dc(UWORD8 *pu1_src,\n//                                        UWORD8 *pu1_dst,\n//                                        WORD32 src_strd,\n//                                        WORD32 dst_strd,\n//                                        WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n\n    .global ih264_intra_pred_chroma_8x8_mode_dc_av8\n\nih264_intra_pred_chroma_8x8_mode_dc_av8:\n\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n    mov       w19, #5\n    ands      w6, w4, w19\n    beq       none_available\n    cmp       w6, #1\n    beq       left_only_available\n    cmp       w6, #4\n    beq       top_only_available\n\nall_available:\n    ld1       {v0.8b, v1.8b}, [x0]\n    add       x6, x0, #18\n    ld1       {v2.8b, v3.8b}, [x6]\n    uxtl      v0.8h, v0.8b\n    uxtl      v1.8h, v1.8b\n    addp      v0.4s, v0.4s , v0.4s\n    addp      v1.4s, v1.4s , v1.4s\n    addp      v0.4s, v0.4s , v0.4s\n    addp      v1.4s, v1.4s , v1.4s\n    uxtl      v2.8h, v2.8b\n    uxtl      v3.8h, v3.8b\n    addp      v2.4s, v2.4s , v2.4s\n    addp      v3.4s, v3.4s , v3.4s\n    addp      v2.4s, v2.4s , v2.4s\n    addp      v3.4s, v3.4s , v3.4s\n    rshrn     v5.8b, v0.8h, #2\n    dup       v21.8h, v5.h[0]\n    rshrn     v6.8b, v3.8h, #2\n    dup       v20.8h, v6.h[0]\n    add       v1.8h, v1.8h, v2.8h\n    rshrn     v1.8b, v1.8h, #3\n    dup       v23.8h, v1.h[0]\n    mov       v20.d[0], v23.d[0]\n    add       v0.8h, v0.8h, v3.8h\n    rshrn     v0.8b, v0.8h, #3\n    dup       v23.8h, v0.h[0]\n    mov       v21.d[1], v23.d[0]\n    b         store\nleft_only_available:\n    ld1       {v0.8b, v1.8b}, [x0]\n    uxtl      v0.8h, v0.8b\n    uxtl      v1.8h, v1.8b\n    addp      v0.4s, v0.4s , v0.4s\n    addp      v1.4s, v1.4s , v1.4s\n    addp      v0.4s, v0.4s , v0.4s\n    addp      v1.4s, v1.4s , v1.4s\n    rshrn     v0.8b, v0.8h, #2\n    rshrn     v1.8b, v1.8h, #2\n    dup       v20.8h , v1.h[0]\n    dup       v21.8h, v0.h[0]\n    b         store\n\ntop_only_available:\n    add       x6, x0, #18\n    ld1       {v0.8b, v1.8b}, [x6]\n    uxtl      v0.8h, v0.8b\n    uxtl      v1.8h, v1.8b\n    addp      v0.4s, v0.4s , v0.4s\n    addp      v1.4s, v1.4s , v1.4s\n    addp      v0.4s, v0.4s , v0.4s\n    addp      v1.4s, v1.4s , v1.4s\n    rshrn     v0.8b, v0.8h, #2\n    rshrn     v1.8b, v1.8h, #2\n    dup       v20.8h , v0.h[0]\n    dup       v21.8h, v1.h[0]\n    mov       v20.d[1], v21.d[1]\n    mov       v21.d[0], v20.d[0]\n    b         store\nnone_available:\n    mov       w15, #128\n    dup       v20.16b, w15\n    dup       v21.16b, w15\n\n\nstore:\n\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v21.16b}, [x1], x3\n    st1       { v21.16b}, [x1], x3\n    st1       { v21.16b}, [x1], x3\n    st1       { v21.16b}, [x1], x3\nend_func:\n\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n///******************************************************************************\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_chroma_8x8_mode_horz\n//*\n//* @brief\n//*  Perform Intra prediction for  chroma_8x8 mode:Horizontal\n//*\n//* @par Description:\n//*   Perform Intra prediction for  chroma_8x8 mode:Horizontal ,described in sec 8.3.4.2\n//*\n//* @param[in] pu1_src\n//* UWORD8 pointer to the source containing alternate U and V samples\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination with alternate U and V samples\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//* availability of neighbouring pixels(Not used in this function)\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//void ih264_intra_pred_chroma_8x8_mode_horz(UWORD8 *pu1_src,\n//                                         UWORD8 *pu1_dst,\n//                                         WORD32 src_strd,\n//                                         WORD32 dst_strd,\n//                                         WORD32 ui_neighboravailability)\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_chroma_8x8_mode_horz_av8\n\nih264_intra_pred_chroma_8x8_mode_horz_av8:\n\n\n\n    push_v_regs\n    sxtw      x3, w3\n    ld1       {v0.8h}, [x0]\n\n    dup       v10.8h, v0.h[7]\n    dup       v11.8h, v0.h[6]\n    dup       v12.8h, v0.h[5]\n    dup       v13.8h, v0.h[4]\n    st1       {v10.8h}, [x1], x3\n    dup       v14.8h, v0.h[3]\n    st1       {v11.8h}, [x1], x3\n    dup       v15.8h, v0.h[2]\n    st1       {v12.8h}, [x1], x3\n    dup       v16.8h, v0.h[1]\n    st1       {v13.8h}, [x1], x3\n    dup       v17.8h, v0.h[0]\n    st1       {v14.8h}, [x1], x3\n    st1       {v15.8h}, [x1], x3\n    st1       {v16.8h}, [x1], x3\n    st1       {v17.8h}, [x1], x3\n\n\n    pop_v_regs\n    ret\n\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_chroma_8x8_mode_vert\n//*\n//* @brief\n//*   Perform Intra prediction for  chroma_8x8 mode:vertical\n//*\n//* @par Description:\n//*Perform Intra prediction for  chroma_8x8 mode:vertical ,described in sec 8.3.4.3\n//*\n//* @param[in] pu1_src\n//* UWORD8 pointer to the source containing alternate U and V samples\n//*\n//* @param[out] pu1_dst\n//*   UWORD8 pointer to the destination with alternate U and V samples\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//* availability of neighbouring pixels(Not used in this function)\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//void ih264_intra_pred_chroma_8x8_mode_vert(UWORD8 *pu1_src,\n//                                        UWORD8 *pu1_dst,\n//                                        WORD32 src_strd,\n//                                        WORD32 dst_strd,\n//                                        WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_chroma_8x8_mode_vert_av8\n\nih264_intra_pred_chroma_8x8_mode_vert_av8:\n\n    push_v_regs\n    sxtw      x3, w3\n\n    add       x0, x0, #18\n    ld1       {v0.8b, v1.8b}, [x0]\n\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n\n    pop_v_regs\n    ret\n\n\n\n\n///******************************************************************************\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_chroma_8x8_mode_plane\n//*\n//* @brief\n//*   Perform Intra prediction for  chroma_8x8 mode:PLANE\n//*\n//* @par Description:\n//*  Perform Intra prediction for  chroma_8x8 mode:PLANE ,described in sec 8.3.4.4\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source containing alternate U and V samples\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination with alternate U and V samples\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_chroma_8x8_mode_plane(UWORD8 *pu1_src,\n//                                        UWORD8 *pu1_dst,\n//                                        WORD32 src_strd,\n//                                        WORD32 dst_strd,\n//                                        WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_chroma_8x8_mode_plane_av8\nih264_intra_pred_chroma_8x8_mode_plane_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n    ld1       {v0.2s}, [x0]\n    add       x10, x0, #10\n    ld1       {v1.2s}, [x10]\n    add       x10, x10, #6\n    rev64     v5.4h, v0.4h\n    ld1       {v2.2s}, [x10], #8\n    add       x10, x10, #2\n    rev64     v7.4h, v2.4h\n    ld1       {v3.2s}, [x10]\n    sub       x5, x3, #8\n#ifdef __APPLE__\n    adrp      x12, _ih264_gai1_intrapred_chroma_plane_coeffs1@GOTPAGE\n    ldr       x12, [x12, _ih264_gai1_intrapred_chroma_plane_coeffs1@GOTPAGEOFF]\n#else\n    adrp      x12, :got:ih264_gai1_intrapred_chroma_plane_coeffs1\n    ldr       x12, [x12, #:got_lo12:ih264_gai1_intrapred_chroma_plane_coeffs1]\n#endif\n    usubl     v10.8h, v5.8b, v1.8b\n    ld1       {v8.8b, v9.8b}, [x12]     // Load multiplication factors 1 to 8 into D3\n    mov       v8.d[1], v9.d[0]\n    usubl     v12.8h, v3.8b, v7.8b\n    mul       v14.8h, v10.8h , v8.8h\n    mul       v16.8h, v12.8h , v8.8h\n    uzp1      v15.8h, v14.8h, v16.8h\n    uzp2      v16.8h, v14.8h, v16.8h\n    mov       v14.16b, v15.16b\n    mov       v15.d[0], v14.d[1]\n    mov       v17.d[0], v16.d[1]\n    addp      v14.4h, v14.4h, v14.4h\n    addp      v15.4h, v15.4h, v15.4h\n    addp      v16.4h, v16.4h, v16.4h\n    addp      v17.4h, v17.4h, v17.4h\n    addp      v14.4h, v14.4h, v14.4h\n    addp      v15.4h, v15.4h, v15.4h\n    addp      v16.4h, v16.4h, v16.4h\n    addp      v17.4h, v17.4h, v17.4h\n    mov       x6, #34\n    dup       v18.8h, w6\n    smull     v22.4s, v14.4h, v18.4h\n    smull     v24.4s, v15.4h, v18.4h\n    smull     v26.4s, v16.4h, v18.4h\n    smull     v28.4s, v17.4h, v18.4h\n    rshrn     v10.4h, v22.4s, #6\n    rshrn     v12.4h, v24.4s, #6\n    rshrn     v13.4h, v26.4s, #6\n    rshrn     v14.4h, v28.4s, #6\n    ldrb      w6, [x0], #1\n    add       x10, x0, #31\n    ldrb      w8, [x0], #1\n    ldrb      w7, [x10], #1\n    ldrb      w9, [x10], #1\n    add       w6, w6, w7\n    add       w8, w8, w9\n    lsl       w6, w6, #4\n    lsl       w8, w8, #4\n    dup       v0.8h, w6\n    dup       v2.8h, w8\n    dup       v4.8h, v12.h[0]\n    dup       v6.8h, v10.h[0]\n    dup       v24.8h, v14.h[0]\n    dup       v26.8h, v13.h[0]\n    zip1      v5.8h, v4.8h, v24.8h\n    zip2      v24.8h, v4.8h, v24.8h\n    mov       v4.16b, v5.16b\n    zip1      v7.8h, v6.8h, v26.8h\n    zip2      v26.8h, v6.8h, v26.8h\n    mov       v6.16b, v7.16b\n    zip1      v1.8h, v0.8h, v2.8h\n    zip2      v2.8h, v0.8h, v2.8h\n    mov       v0.16b, v1.16b\n#ifdef __APPLE__\n    adrp      x12, _ih264_gai1_intrapred_chroma_plane_coeffs2@GOTPAGE\n    ldr       x12, [x12, _ih264_gai1_intrapred_chroma_plane_coeffs2@GOTPAGEOFF]\n#else\n    adrp      x12, :got:ih264_gai1_intrapred_chroma_plane_coeffs2\n    ldr       x12, [x12, #:got_lo12:ih264_gai1_intrapred_chroma_plane_coeffs2]\n#endif\n    ld1       {v8.2s, v9.2s}, [x12]\n    mov       v8.d[1], v9.d[0]\n    mov       v10.16b, v8.16b\n    mov       v22.16b, v8.16b\n    zip1      v9.8h, v8.8h, v10.8h\n    zip2      v10.8h, v8.8h, v10.8h\n    mov       v8.16b, v9.16b\n    mul       v12.8h, v4.8h , v8.8h\n    mul       v16.8h, v4.8h , v10.8h\n    add       v12.8h, v0.8h , v12.8h\n    add       v16.8h, v0.8h , v16.8h\n    dup       v20.8h, v22.h[0]\n    mul       v4.8h, v6.8h , v20.8h\n    dup       v30.8h, v22.h[1]\n    mul       v18.8h, v6.8h , v20.8h\n    mul       v14.8h, v6.8h , v30.8h\n    mul       v8.8h, v6.8h , v30.8h\n    add       v24.8h, v12.8h , v4.8h\n    add       v0.8h, v16.8h , v18.8h\n    add       v2.8h, v12.8h , v14.8h\n    sqrshrun  v28.8b, v24.8h, #5\n    add       v26.8h, v16.8h , v8.8h\n    sqrshrun  v29.8b, v0.8h, #5\n    dup       v20.8h, v22.h[2]\n    st1       {v28.8b, v29.8b}, [x1], x3\n    sqrshrun  v28.8b, v2.8h, #5\n    sqrshrun  v29.8b, v26.8h, #5\n    mul       v4.8h, v6.8h , v20.8h\n    mul       v18.8h, v6.8h , v20.8h\n    st1       {v28.8b, v29.8b}, [x1], x3\n    add       v24.8h, v12.8h , v4.8h\n    add       v0.8h, v16.8h , v18.8h\n    dup       v30.8h, v22.h[3]\n    sqrshrun  v28.8b, v24.8h, #5\n    sqrshrun  v29.8b, v0.8h, #5\n    mul       v14.8h, v6.8h , v30.8h\n    mul       v8.8h, v6.8h , v30.8h\n    st1       {v28.8b, v29.8b}, [x1], x3\n    add       v2.8h, v12.8h , v14.8h\n    add       v26.8h, v16.8h , v8.8h\n    dup       v20.8h, v22.h[4]\n    sqrshrun  v28.8b, v2.8h, #5\n    sqrshrun  v29.8b, v26.8h, #5\n    mul       v4.8h, v6.8h , v20.8h\n    mul       v18.8h, v6.8h , v20.8h\n    st1       {v28.8b, v29.8b}, [x1], x3\n    add       v24.8h, v12.8h , v4.8h\n    add       v0.8h, v16.8h , v18.8h\n    dup       v30.8h, v22.h[5]\n    sqrshrun  v28.8b, v24.8h, #5\n    sqrshrun  v29.8b, v0.8h, #5\n    mul       v14.8h, v6.8h , v30.8h\n    mul       v8.8h, v6.8h , v30.8h\n    st1       {v28.8b, v29.8b}, [x1], x3\n    add       v2.8h, v12.8h , v14.8h\n    add       v26.8h, v16.8h , v8.8h\n    dup       v20.8h, v22.h[6]\n    sqrshrun  v28.8b, v2.8h, #5\n    sqrshrun  v29.8b, v26.8h, #5\n    mul       v4.8h, v6.8h , v20.8h\n    mul       v18.8h, v6.8h , v20.8h\n    st1       {v28.8b, v29.8b}, [x1], x3\n    add       v24.8h, v12.8h , v4.8h\n    add       v0.8h, v16.8h , v18.8h\n    dup       v30.8h, v22.h[7]\n    sqrshrun  v28.8b, v24.8h, #5\n    sqrshrun  v29.8b, v0.8h, #5\n    mul       v14.8h, v6.8h , v30.8h\n    mul       v8.8h, v6.8h , v30.8h\n    st1       {v28.8b, v29.8b}, [x1], x3\n    add       v2.8h, v12.8h , v14.8h\n    add       v26.8h, v16.8h , v8.8h\n    sqrshrun  v28.8b, v2.8h, #5\n    sqrshrun  v29.8b, v26.8h, #5\n    st1       {v28.8b, v29.8b}, [x1], x3\n\nend_func_plane:\n\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_intra_pred_luma_16x16_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_intra_pred_luma_16x16_av8.s\n//*\n//* @brief\n//*  Contains function definitions for intra 16x16 Luma prediction .\n//*\n//* @author\n//*  Ittiam\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_intra_pred_luma_16x16_mode_vert_av8()\n//*  - ih264_intra_pred_luma_16x16_mode_horz_av8()\n//*  - ih264_intra_pred_luma_16x16_mode_dc_av8()\n//*  - ih264_intra_pred_luma_16x16_mode_plane_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_intra_pred_filters.c\n//\n\n///**\n///**\n///**\n//\n\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n.extern ih264_gai1_intrapred_luma_plane_coeffs\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_16x16_mode_vert\n//*\n//* @brief\n//*   Perform Intra prediction for  luma_16x16 mode:vertical\n//*\n//* @par Description:\n//* Perform Intra prediction for  luma_16x16 mode:Vertical ,described in sec 8.3.3.1\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//* availability of neighbouring pixels(Not used in this function)\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//void ih264_intra_pred_luma_16x16_mode_vert(UWORD8 *pu1_src,\n//                                        UWORD8 *pu1_dst,\n//                                        WORD32 src_strd,\n//                                        WORD32 dst_strd,\n//                                        WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_16x16_mode_vert_av8\n\nih264_intra_pred_luma_16x16_mode_vert_av8:\n\n    push_v_regs\n    sxtw      x3, w3\n\n\n    add       x0, x0, #17\n    ld1       {v0.8b, v1.8b}, [x0]\n\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n    st1       {v0.8b, v1.8b}, [x1], x3\n\n    pop_v_regs\n    ret\n\n\n\n\n\n///******************************************************************************\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_16x16_mode_horz\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_16x16 mode:horizontal\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_16x16 mode:horizontal ,described in sec 8.3.3.2\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//* availability of neighbouring pixels(Not used in this function)\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//void ih264_intra_pred_luma_16x16_mode_horz(UWORD8 *pu1_src,\n//                                         UWORD8 *pu1_dst,\n//                                         WORD32 src_strd,\n//                                         WORD32 dst_strd,\n//                                         WORD32 ui_neighboravailability)\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_16x16_mode_horz_av8\n\nih264_intra_pred_luma_16x16_mode_horz_av8:\n\n\n\n    push_v_regs\n    sxtw      x3, w3\n\n    ld1       {v0.16b}, [x0]\n\n\n\n    dup       v10.16b, v0.b[15]\n    dup       v11.16b, v0.b[14]\n    dup       v12.16b, v0.b[13]\n    dup       v13.16b, v0.b[12]\n    st1       {v10.16b}, [x1], x3\n    dup       v14.16b, v0.b[11]\n    st1       {v11.16b}, [x1], x3\n    dup       v15.16b, v0.b[10]\n    st1       {v12.16b}, [x1], x3\n    dup       v16.16b, v0.b[9]\n    st1       {v13.16b}, [x1], x3\n    dup       v17.16b, v0.b[8]\n    st1       {v14.16b}, [x1], x3\n    dup       v18.16b, v0.b[7]\n    st1       {v15.16b}, [x1], x3\n    dup       v19.16b, v0.b[6]\n    st1       {v16.16b}, [x1], x3\n    dup       v20.16b, v0.b[5]\n    st1       {v17.16b}, [x1], x3\n    dup       v21.16b, v0.b[4]\n    st1       {v18.16b}, [x1], x3\n    dup       v22.16b, v0.b[3]\n    st1       {v19.16b}, [x1], x3\n    dup       v23.16b, v0.b[2]\n    st1       {v20.16b}, [x1], x3\n    dup       v24.16b, v0.b[1]\n    st1       {v21.16b}, [x1], x3\n    dup       v25.16b, v0.b[0]\n    st1       {v22.16b}, [x1], x3\n    st1       {v23.16b}, [x1], x3\n    st1       {v24.16b}, [x1], x3\n    st1       {v25.16b}, [x1], x3\n\n    pop_v_regs\n    ret\n\n\n\n\n\n\n\n///******************************************************************************\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_16x16_mode_dc\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_16x16 mode:DC\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_16x16 mode:DC ,described in sec 8.3.3.3\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_16x16_mode_dc(UWORD8 *pu1_src,\n//                                       UWORD8 *pu1_dst,\n//                                       WORD32 src_strd,\n//                                       WORD32 dst_strd,\n//                                       WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_16x16_mode_dc_av8\n\nih264_intra_pred_luma_16x16_mode_dc_av8:\n\n\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n    sub       v0.16b, v0.16b, v0.16b\n    sub       v1.16b, v1.16b, v1.16b\n    mov       w10, #0\n    mov       w11 , #3\n    ands      w6, w4, #0x01\n    beq       top_available             //LEFT NOT AVAILABLE\n    ld1       {v0.16b}, [x0]\n    add       w10, w10, #8\n    add       w11, w11, #1\ntop_available:\n    ands      w6, w4, #0x04\n    beq       none_available\n    add       x6, x0, #17\n    ld1       {v1.16b}, [x6]\n    add       w10, w10, #8\n    add       w11, w11, #1\n    b         summation\nnone_available:\n    cmp       w4, #0\n    bne       summation\n    mov       w15, #128\n    dup       v20.16b, w15\n    b         store\nsummation:\n    uaddl     v2.8h, v0.8b, v1.8b\n    uaddl2    v3.8h, v0.16b, v1.16b\n    dup       v10.8h, w10\n    neg       w11, w11\n    dup       v20.8h, w11\n    add       v0.8h, v2.8h, v3.8h\n    mov       v1.d[0], v0.d[1]\n    add       v0.4h, v0.4h, v1.4h\n    addp      v0.4h, v0.4h , v0.4h\n    addp      v0.4h, v0.4h , v0.4h\n    add       v0.4h, v0.4h, v10.4h\n    uqshl     v0.8h, v0.8h, v20.8h\n    sqxtun    v0.8b, v0.8h\n    dup       v20.16b, v0.b[0]\n\nstore:\n\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n    st1       { v20.16b}, [x1], x3\n\n\n\nend_func:\n\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n///******************************************************************************\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_16x16_mode_plane\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_16x16 mode:PLANE\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_16x16 mode:PLANE ,described in sec 8.3.3.4\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_16x16_mode_plane(UWORD8 *pu1_src,\n//                                        UWORD8 *pu1_dst,\n//                                        WORD32 src_strd,\n//                                        WORD32 dst_strd,\n//                                        WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_16x16_mode_plane_av8\nih264_intra_pred_luma_16x16_mode_plane_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n    mov       x2, x1\n    add       x1, x0, #17\n    add       x0, x0, #15\n    mov       x8, #9\n    sub       x1, x1, #1\n    mov       x10, x1                   //top_left\n    mov       x4, #-1\n    ld1       {v2.2s}, [x1], x8\n#ifdef __APPLE__\n    adrp      x7, _ih264_gai1_intrapred_luma_plane_coeffs@GOTPAGE\n    ldr       x7, [x7, _ih264_gai1_intrapred_luma_plane_coeffs@GOTPAGEOFF]\n#else\n    adrp      x7, :got:ih264_gai1_intrapred_luma_plane_coeffs\n    ldr       x7, [x7, #:got_lo12:ih264_gai1_intrapred_luma_plane_coeffs]\n#endif\n    ld1       {v0.2s}, [x1]\n    rev64     v2.8b, v2.8b\n    ld1       {v6.2s, v7.2s}, [x7]\n    usubl     v0.8h, v0.8b, v2.8b\n    uxtl      v16.8h, v6.8b\n    mul       v0.8h, v0.8h , v16.8h\n    uxtl      v18.8h, v7.8b\n    add       x7, x0, x4, lsl #3\n    sub       x0, x7, x4, lsl #1\n    neg       x14, x4\n    addp      v0.8h, v0.8h, v1.8h\n    ldrb      w8, [x7], #-1\n    ldrb      w9, [x0], #1\n    saddlp    v0.2s, v0.4h\n    sub       w12, w8, w9\n    ldrb      w8, [x7], #-1\n    saddlp    v0.1d, v0.2s\n    ldrb      w9, [x0], #1\n    sub       w8, w8, w9\n    shl       v2.2s, v0.2s, #2\n    add       w12, w12, w8, lsl #1\n    add       v0.2s, v0.2s , v2.2s\n    ldrb      w8, [x7], #-1\n    ldrb      w9, [x0], #1\n    srshr     v0.2s, v0.2s, #6          // i_b = D0[0]\n    sub       w8, w8, w9\n    ldrb      w5, [x7], #-1\n    add       w8, w8, w8, lsl #1\n    dup       v4.8h, v0.h[0]\n    add       w12, w12, w8\n    ldrb      w9, [x0], #1\n    mul       v0.8h, v4.8h , v16.8h\n    sub       w5, w5, w9\n    mul       v2.8h, v4.8h , v18.8h\n    add       w12, w12, w5, lsl #2\n    ldrb      w8, [x7], #-1\n    ldrb      w9, [x0], #1\n    sub       w8, w8, w9\n    ldrb      w5, [x7], #-1\n    add       w8, w8, w8, lsl #2\n    ldrb      w6, [x0], #1\n    add       w12, w12, w8\n    ldrb      w8, [x7], #-1\n    ldrb      w9, [x0], #1\n    sub       w5, w5, w6\n    sub       w8, w8, w9\n    add       w5, w5, w5, lsl #1\n    sub       w20, w8, w8, lsl #3\n    neg       w8, w20\n    add       w12, w12, w5, lsl #1\n    ldrb      w5, [x7], #-1\n    ldrb      w6, [x10]                 //top_left\n    add       w12, w12, w8\n    sub       w9, w5, w6\n    ldrb      w6, [x1, #7]\n    add       w12, w12, w9, lsl #3      // i_c = w12\n    add       w8, w5, w6\n    add       w12, w12, w12, lsl #2\n    lsl       w8, w8, #4                // i_a = w8\n    add       w12, w12, #0x20\n    lsr       w12, w12, #6\n    shl       v28.8h, v4.8h, #3\n    dup       v6.8h, w12\n    dup       v30.8h, w8\n    shl       v26.8h, v6.8h, #3\n    sub       v30.8h, v30.8h , v28.8h\n    sub       v30.8h, v30.8h , v26.8h\n    add       v28.8h, v30.8h , v6.8h\n    add       v26.8h, v28.8h , v0.8h\n    add       v28.8h, v28.8h , v2.8h\n    sqrshrun  v20.8b, v26.8h, #5\n    sqrshrun  v21.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v22.8b, v26.8h, #5\n    st1       {v20.2s, v21.2s}, [x2], x3\n    sqrshrun  v23.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v20.8b, v26.8h, #5\n    st1       {v22.2s, v23.2s}, [x2], x3\n    sqrshrun  v21.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v22.8b, v26.8h, #5\n    st1       {v20.2s, v21.2s}, [x2], x3\n    sqrshrun  v23.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v20.8b, v26.8h, #5\n    st1       {v22.2s, v23.2s}, [x2], x3\n    sqrshrun  v21.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v22.8b, v26.8h, #5\n    st1       {v20.2s, v21.2s}, [x2], x3\n    sqrshrun  v23.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v20.8b, v26.8h, #5\n    st1       {v22.2s, v23.2s}, [x2], x3\n    sqrshrun  v21.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v22.8b, v26.8h, #5\n    st1       {v20.2s, v21.2s}, [x2], x3\n    sqrshrun  v23.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v20.8b, v26.8h, #5\n    st1       {v22.2s, v23.2s}, [x2], x3\n    sqrshrun  v21.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v22.8b, v26.8h, #5\n    st1       {v20.2s, v21.2s}, [x2], x3\n    sqrshrun  v23.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v20.8b, v26.8h, #5\n    st1       {v22.2s, v23.2s}, [x2], x3\n    sqrshrun  v21.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v22.8b, v26.8h, #5\n    st1       {v20.2s, v21.2s}, [x2], x3\n    sqrshrun  v23.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v20.8b, v26.8h, #5\n    st1       {v22.2s, v23.2s}, [x2], x3\n    sqrshrun  v21.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v22.8b, v26.8h, #5\n    st1       {v20.2s, v21.2s}, [x2], x3\n    sqrshrun  v23.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v20.8b, v26.8h, #5\n    st1       {v22.2s, v23.2s}, [x2], x3\n    sqrshrun  v21.8b, v28.8h, #5\n    add       v26.8h, v26.8h , v6.8h\n    add       v28.8h, v28.8h , v6.8h\n    sqrshrun  v22.8b, v26.8h, #5\n    st1       {v20.2s, v21.2s}, [x2], x3\n    sqrshrun  v23.8b, v28.8h, #5\n    st1       {v22.2s, v23.2s}, [x2], x3\n\nend_func_plane:\n\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_intra_pred_luma_4x4_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_intra_pred_luma_4x4_av8.s\n//*\n//* @brief\n//*  Contains function definitions for intra 4x4 Luma prediction .\n//*\n//* @author\n//*  Ittiam\n//*\n//* @par List of Functions:\n//*\n//*  -ih264_intra_pred_luma_4x4_mode_vert_av8\n//*  -ih264_intra_pred_luma_4x4_mode_horz_av8\n//*  -ih264_intra_pred_luma_4x4_mode_dc_av8\n//*  -ih264_intra_pred_luma_4x4_mode_diag_dl_av8\n//*  -ih264_intra_pred_luma_4x4_mode_diag_dr_av8\n//*  -ih264_intra_pred_luma_4x4_mode_vert_r_av8\n//*  -ih264_intra_pred_luma_4x4_mode_horz_d_av8\n//*  -ih264_intra_pred_luma_4x4_mode_vert_l_av8\n//*  -ih264_intra_pred_luma_4x4_mode_horz_u_av8\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_intra_pred_filters.c\n//\n\n///**\n///**\n///**\n//\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_4x4_mode_vert\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_4x4 mode:vertical\n//*\n//* @par Description:\n//* Perform Intra prediction for  luma_4x4 mode:vertical ,described in sec 8.3.1.2.1\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//* availability of neighbouring pixels(Not used in this function)\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//void ih264_intra_pred_luma_4x4_mode_vert(UWORD8 *pu1_src,\n//                                        UWORD8 *pu1_dst,\n//                                        WORD32 src_strd,\n//                                        WORD32 dst_strd,\n//                                        WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_4x4_mode_vert_av8\n\nih264_intra_pred_luma_4x4_mode_vert_av8:\n\n    push_v_regs\n    sxtw      x3, w3\n\n    add       x0, x0, #5\n\n    ld1       {v0.s}[0], [x0]\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n\n    pop_v_regs\n    ret\n\n\n\n\n\n///******************************************************************************\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_4x4_mode_horz\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_4x4 mode:horizontal\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_4x4 mode:horizontal ,described in sec 8.3.1.2.2\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//* availability of neighbouring pixels(Not used in this function)\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//void ih264_intra_pred_luma_4x4_mode_horz(UWORD8 *pu1_src,\n//                                         UWORD8 *pu1_dst,\n//                                         WORD32 src_strd,\n//                                         WORD32 dst_strd,\n//                                         WORD32 ui_neighboravailability)\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n\n    .global ih264_intra_pred_luma_4x4_mode_horz_av8\n\nih264_intra_pred_luma_4x4_mode_horz_av8:\n\n    push_v_regs\n    sxtw      x3, w3\n\n    ld1       {v1.s}[0], [x0]\n    dup       v0.8b, v1.b[3]\n    dup       v2.8b, v1.b[2]\n    st1       {v0.s}[0], [x1], x3\n    dup       v3.8b, v1.b[1]\n    st1       {v2.s}[0], [x1], x3\n    dup       v4.8b, v1.b[0]\n    st1       {v3.s}[0], [x1], x3\n    st1       {v4.s}[0], [x1], x3\n\n    pop_v_regs\n    ret\n\n\n\n\n\n\n\n///******************************************************************************\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_4x4_mode_dc\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_4x4 mode:DC\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_4x4 mode:DC ,described in sec 8.3.1.2.3\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_4x4_mode_dc(UWORD8 *pu1_src,\n//                                       UWORD8 *pu1_dst,\n//                                       WORD32 src_strd,\n//                                       WORD32 dst_strd,\n//                                       WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n\n    .global ih264_intra_pred_luma_4x4_mode_dc_av8\n\nih264_intra_pred_luma_4x4_mode_dc_av8:\n\n\n\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n    ands      w5, w4, #0x01\n    beq       top_available             //LEFT NOT AVAILABLE\n\n    add       x10, x0, #3\n    mov       x2, #-1\n    ldrb      w5, [x10], #-1\n    ldrb      w6, [x10], #-1\n    ldrb      w7, [x10], #-1\n    add       w5, w5, w6\n    ldrb      w8, [x10], #-1\n    add       w5, w5, w7\n    ands      w11, w4, #0x04            // CHECKING IF TOP_AVAILABLE  ELSE BRANCHING TO ONLY LEFT AVAILABLE\n    add       w5, w5, w8\n    beq       left_available\n    add       x10, x0, #5\n    //    BOTH LEFT AND TOP AVAILABLE\n    ldrb      w6, [x10], #1\n    ldrb      w7, [x10], #1\n    add       w5, w5, w6\n    ldrb      w8, [x10], #1\n    add       w5, w5, w7\n    ldrb      w9, [x10], #1\n    add       w5, w5, w8\n    add       w5, w5, w9\n    add       w5, w5, #4\n    lsr       w5, w5, #3\n    dup       v0.8b, w5\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    b         end_func\n\ntop_available: // ONLT TOP AVAILABLE\n    ands      w11, w4, #0x04            // CHECKING TOP AVAILABILTY  OR ELSE BRANCH TO NONE AVAILABLE\n    beq       none_available\n\n    add       x10, x0, #5\n    ldrb      w6, [x10], #1\n    ldrb      w7, [x10], #1\n    ldrb      w8, [x10], #1\n    add       w5, w6, w7\n    ldrb      w9, [x10], #1\n    add       w5, w5, w8\n    add       w5, w5, w9\n    add       w5, w5, #2\n    lsr       w5, w5, #2\n    dup       v0.8b, w5\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    b         end_func\n\nleft_available: //ONLY LEFT AVAILABLE\n    add       x5, x5, #2\n    lsr       x5, x5, #2\n    dup       v0.8b, w5\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    b         end_func\n\nnone_available:                         //NONE AVAILABLE\n    mov       x5, #128\n    dup       v0.8b, w5\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    st1       {v0.s}[0], [x1], x3\n    b         end_func\n\n\nend_func:\n\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_4x4_mode_diag_dl\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Left\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Left ,described in sec 8.3.1.2.4\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_4x4_mode_diag_dl(UWORD8 *pu1_src,\n//                                            UWORD8 *pu1_dst,\n//                                            WORD32 src_strd,\n//                                              WORD32 dst_strd,\n//                                              WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_diag_dl_av8\n\nih264_intra_pred_luma_4x4_mode_diag_dl_av8:\n\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n    add       x0, x0, #5\n    sub       x5, x3, #2\n    add       x6, x0, #7\n    ld1       {v0.8b}, [x0]\n    ext       v1.8b, v0.8b , v0.8b , #1\n    ext       v2.8b, v0.8b , v0.8b , #2\n    ld1       {v2.b}[6], [x6]\n    uaddl     v20.8h, v0.8b, v1.8b\n    uaddl     v22.8h, v1.8b, v2.8b\n    add       v24.8h, v20.8h , v22.8h\n    sqrshrun  v3.8b, v24.8h, #2\n    st1       {v3.s}[0], [x1], x3\n    ext       v4.8b, v3.8b , v3.8b , #1\n    st1       {v4.s}[0], [x1], x3\n    st1       {v3.h}[1], [x1], #2\n    st1       {v3.h}[2], [x1], x5\n    st1       {v4.h}[1], [x1], #2\n    st1       {v4.h}[2], [x1]\n\nend_func_diag_dl:\n\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_4x4_mode_diag_dr\n//*\n//* @brief\n//* Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Right\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Right ,described in sec 8.3.1.2.5\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_4x4_mode_diag_dr(UWORD8 *pu1_src,\n//                                            UWORD8 *pu1_dst,\n//                                            WORD32 src_strd,\n//                                              WORD32 dst_strd,\n//                                              WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_diag_dr_av8\n\nih264_intra_pred_luma_4x4_mode_diag_dr_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n\n    ld1       {v0.8b}, [x0]\n    add       x0, x0, #1\n    ld1       {v1.8b}, [x0]\n    ext       v2.8b, v1.8b , v1.8b , #1\n    uaddl     v20.8h, v0.8b, v1.8b\n    uaddl     v22.8h, v1.8b, v2.8b\n    add       v24.8h, v20.8h , v22.8h\n    sqrshrun  v3.8b, v24.8h, #2\n\n    ext       v4.8b, v3.8b , v3.8b , #1\n    sub       x5, x3, #2\n    st1       {v4.h}[1], [x1], #2\n    st1       {v4.h}[2], [x1], x5\n    st1       {v3.h}[1], [x1], #2\n    st1       {v3.h}[2], [x1], x5\n    st1       {v4.s}[0], [x1], x3\n    st1       {v3.s}[0], [x1], x3\n\nend_func_diag_dr:\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_4x4_mode_vert_r\n//*\n//* @brief\n//* Perform Intra prediction for  luma_4x4 mode:Vertical_Right\n//*\n//* @par Description:\n//*   Perform Intra prediction for  luma_4x4 mode:Vertical_Right ,described in sec 8.3.1.2.6\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_4x4_mode_vert_r(UWORD8 *pu1_src,\n//                                            UWORD8 *pu1_dst,\n//                                            WORD32 src_strd,\n//                                              WORD32 dst_strd,\n//                                              WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_vert_r_av8\n\nih264_intra_pred_luma_4x4_mode_vert_r_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n\n    ld1       {v0.8b}, [x0]\n    add       x0, x0, #1\n    ld1       {v1.8b}, [x0]\n    ext       v2.8b, v1.8b , v1.8b , #1\n    uaddl     v20.8h, v0.8b, v1.8b\n    uaddl     v22.8h, v1.8b, v2.8b\n    add       v24.8h, v20.8h , v22.8h\n    sqrshrun  v4.8b, v20.8h, #1\n    sqrshrun  v3.8b, v24.8h, #2\n    sub       x5, x3, #2\n    ext       v5.8b, v3.8b , v3.8b , #3\n    st1       {v4.s}[1], [x1], x3\n    st1       {v5.s}[0], [x1], x3\n    sub       x8, x3, #3\n    st1       {v3.b}[2], [x1], #1\n    st1       {v4.h}[2], [x1], #2\n    st1       {v4.b}[6], [x1], x8\n    st1       {v3.b}[1], [x1], #1\n    st1       {v5.h}[0], [x1], #2\n    st1       {v5.b}[2], [x1]\n\n\nend_func_vert_r:\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_4x4_mode_horz_d\n//*\n//* @brief\n//* Perform Intra prediction for  luma_4x4 mode:Horizontal_Down\n//*\n//* @par Description:\n//*   Perform Intra prediction for  luma_4x4 mode:Horizontal_Down ,described in sec 8.3.1.2.7\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_4x4_mode_horz_d(UWORD8 *pu1_src,\n//                                            UWORD8 *pu1_dst,\n//                                            WORD32 src_strd,\n//                                              WORD32 dst_strd,\n//                                              WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_horz_d_av8\n\nih264_intra_pred_luma_4x4_mode_horz_d_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n    ld1       {v0.8b}, [x0]\n    add       x0, x0, #1\n    ld1       {v1.8b}, [x0]\n    ext       v2.8b, v1.8b , v0.8b , #1\n    uaddl     v20.8h, v0.8b, v1.8b\n    uaddl     v22.8h, v1.8b, v2.8b\n    add       v24.8h, v20.8h , v22.8h\n    sqrshrun  v4.8b, v20.8h, #1\n    sqrshrun  v5.8b, v24.8h, #2\n    sub       x5, x3, #2\n    mov       v6.8b, v5.8b\n    trn1      v10.8b, v4.8b, v5.8b\n    trn2      v5.8b, v4.8b, v5.8b       //\n    mov       v4.8b, v10.8b\n    st1       {v5.h}[1], [x1], #2\n    st1       {v6.h}[2], [x1], x5\n    st1       {v4.h}[1], [x1], #2\n    st1       {v5.h}[1], [x1], x5\n    st1       {v5.h}[0], [x1], #2\n    st1       {v4.h}[1], [x1], x5\n    st1       {v4.h}[0], [x1], #2\n    st1       {v5.h}[0], [x1], x5\n\nend_func_horz_d:\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_4x4_mode_vert_l\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_4x4 mode:Vertical_Left\n//*\n//* @par Description:\n//*   Perform Intra prediction for  luma_4x4 mode:Vertical_Left ,described in sec 8.3.1.2.8\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_4x4_mode_vert_l(UWORD8 *pu1_src,\n//                                            UWORD8 *pu1_dst,\n//                                            WORD32 src_strd,\n//                                              WORD32 dst_strd,\n//                                              WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_vert_l_av8\n\nih264_intra_pred_luma_4x4_mode_vert_l_av8:\n\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n    add       x0, x0, #4\n    ld1       {v0.8b}, [x0]\n    add       x0, x0, #1\n    ld1       {v1.8b}, [x0]\n    ext       v2.8b, v1.8b , v0.8b , #1\n    uaddl     v20.8h, v0.8b, v1.8b\n    uaddl     v22.8h, v1.8b, v2.8b\n    add       v24.8h, v20.8h , v22.8h\n    sqrshrun  v4.8b, v20.8h, #1\n    sqrshrun  v5.8b, v24.8h, #2\n    ext       v6.8b, v4.8b , v4.8b , #1\n    ext       v7.8b, v5.8b , v5.8b , #1\n    st1       {v6.s}[0], [x1], x3\n    ext       v8.8b, v4.8b , v4.8b , #2\n    ext       v9.8b, v5.8b , v5.8b , #2\n    st1       {v7.s}[0], [x1], x3\n    st1       {v8.s}[0], [x1], x3\n    st1       {v9.s}[0], [x1], x3\n\nend_func_vert_l:\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_4x4_mode_horz_u\n//*\n//* @brief\n//*     Perform Intra prediction for  luma_4x4 mode:Horizontal_Up\n//*\n//* @par Description:\n//*      Perform Intra prediction for  luma_4x4 mode:Horizontal_Up ,described in sec 8.3.1.2.9\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_4x4_mode_horz_u(UWORD8 *pu1_src,\n//                                           UWORD8 *pu1_dst,\n//                                           WORD32 src_strd,\n//                                             WORD32 dst_strd,\n//                                             WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_4x4_mode_horz_u_av8\n\nih264_intra_pred_luma_4x4_mode_horz_u_av8:\n\n    push_v_regs\n    sxtw      x3, w3\n    stp       x19, x20, [sp, #-16]!\n    mov       x10, x0\n    ld1       {v0.8b}, [x0]\n    ldrb      w9, [x0], #1\n    ext       v1.8b, v0.8b , v0.8b , #1\n    ld1       {v0.b}[7], [x10]\n    ext       v2.8b, v1.8b , v1.8b , #1\n    uaddl     v20.8h, v0.8b, v1.8b\n    uaddl     v22.8h, v1.8b, v2.8b\n    add       v24.8h, v20.8h , v22.8h\n    sqrshrun  v4.8b, v20.8h, #1\n    sqrshrun  v5.8b, v24.8h, #2\n    mov       v6.8b, v4.8b\n    ext       v6.8b, v5.8b , v4.8b , #1\n    st1       {v4.b}[2], [x1], #1\n    st1       {v6.b}[0], [x1], #1\n    trn1      v10.8b, v6.8b, v5.8b\n    trn2      v5.8b, v6.8b, v5.8b       //\n    mov       v6.8b , v10.8b\n    sub       x5, x3, #2\n    trn1      v10.8b, v4.8b, v6.8b\n    trn2      v6.8b, v4.8b, v6.8b       //\n    mov       v4.8b , v10.8b\n    dup       v7.8b, w9\n    st1       {v6.h}[0], [x1], x5\n    st1       {v6.h}[0], [x1], #2\n    st1       {v5.h}[3], [x1], x5\n    st1       {v5.h}[3], [x1], #2\n    st1       {v7.h}[3], [x1], x5\n    st1       {v7.s}[0], [x1], x3\n\nend_func_horz_u:\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_intra_pred_luma_8x8_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_intra_pred_luma_8x8_av8.s\n//*\n//* @brief\n//*  Contains function definitions for intra 8x8 Luma prediction .\n//*\n//* @author\n//*  Ittiam\n//*\n//* @par List of Functions:\n//*\n//*  -ih264_intra_pred_luma_8x8_mode_vert_av8\n//*  -ih264_intra_pred_luma_8x8_mode_horz_av8\n//*  -ih264_intra_pred_luma_8x8_mode_dc_av8\n//*  -ih264_intra_pred_luma_8x8_mode_diag_dl_av8\n//*  -ih264_intra_pred_luma_8x8_mode_diag_dr_av8\n//*  -ih264_intra_pred_luma_8x8_mode_vert_r_av8\n//*  -ih264_intra_pred_luma_8x8_mode_horz_d_av8\n//*  -ih264_intra_pred_luma_8x8_mode_vert_l_av8\n//*  -ih264_intra_pred_luma_8x8_mode_horz_u_av8\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n\n///* All the functions here are replicated from ih264_intra_pred_filters.c\n//\n\n///**\n///**\n///**\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n.extern ih264_gai1_intrapred_luma_8x8_horz_u\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_8x8_mode_vert\n//*\n//* @brief\n//*   Perform Intra prediction for  luma_8x8 mode:vertical\n//*\n//* @par Description:\n//* Perform Intra prediction for  luma_8x8 mode:vertical ,described in sec 8.3.2.2.2\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//* availability of neighbouring pixels(Not used in this function)\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//void ih264_intra_pred_luma_8x8_mode_vert(UWORD8 *pu1_src,\n//                                        UWORD8 *pu1_dst,\n//                                        WORD32 src_strd,\n//                                        WORD32 dst_strd,\n//                                        WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_vert_av8\n\nih264_intra_pred_luma_8x8_mode_vert_av8:\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    //stp x19, x20,[sp,#-16]!\n    sxtw      x3, w3\n\n    add       x0, x0, #9\n    ld1       {v0.8b}, [x0]\n\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    //ldp x19, x20,[sp],#16\n    pop_v_regs\n    ret\n\n\n\n\n\n///******************************************************************************\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_8x8_mode_horz\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_8x8 mode:horizontal\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_8x8 mode:horizontal ,described in sec 8.3.2.2.2\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//* availability of neighbouring pixels(Not used in this function)\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//void ih264_intra_pred_luma_8x8_mode_horz(UWORD8 *pu1_src,\n//                                         UWORD8 *pu1_dst,\n//                                         WORD32 src_strd,\n//                                         WORD32 dst_strd,\n//                                         WORD32 ui_neighboravailability)\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_horz_av8\n\nih264_intra_pred_luma_8x8_mode_horz_av8:\n\n\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n    add       x0, x0, #7\n\n    ldrb      w5, [x0], #-1\n    ldrb      w6, [x0], #-1\n    dup       v0.8b, w5\n    st1       {v0.8b}, [x1], x3\n    ldrb      w7, [x0], #-1\n    dup       v1.8b, w6\n    st1       {v1.8b}, [x1], x3\n    dup       v2.8b, w7\n    ldrb      w8, [x0], #-1\n    dup       v3.8b, w8\n    st1       {v2.8b}, [x1], x3\n    ldrb      w5, [x0], #-1\n    st1       {v3.8b}, [x1], x3\n    dup       v0.8b, w5\n    ldrb      w6, [x0], #-1\n    st1       {v0.8b}, [x1], x3\n    ldrb      w7, [x0], #-1\n    dup       v1.8b, w6\n    dup       v2.8b, w7\n    st1       {v1.8b}, [x1], x3\n    ldrb      w8, [x0], #-1\n    dup       v3.8b, w8\n    st1       {v2.8b}, [x1], x3\n    st1       {v3.8b}, [x1], x3\n\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n\n\n///******************************************************************************\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_8x8_mode_dc\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_8x8 mode:DC\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_8x8 mode:DC ,described in sec 8.3.2.2.3\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_8x8_mode_dc(UWORD8 *pu1_src,\n//                                       UWORD8 *pu1_dst,\n//                                       WORD32 src_strd,\n//                                       WORD32 dst_strd,\n//                                       WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_dc_av8\n\nih264_intra_pred_luma_8x8_mode_dc_av8:\n\n\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    sxtw      x3, w3\n    stp       x19, x20, [sp, #-16]!\n\n    ands      w6, w4, #0x01\n    beq       top_available             //LEFT NOT AVAILABLE\n\n    add       x10, x0, #7\n    mov       x2, #-1\n    ldrb      w5, [x10], -1\n    ldrb      w6, [x10], -1\n    ldrb      w7, [x10], -1\n    add       w5, w5, w6\n    ldrb      w8, [x10], -1\n    add       w5, w5, w7\n    ldrb      w6, [x10], -1\n    add       w5, w5, w8\n    ldrb      w7, [x10], -1\n    add       w5, w5, w6\n    ldrb      w8, [x10], -1\n    add       w5, w5, w7\n    ands      w11, w4, #0x04            // CHECKING IF TOP_AVAILABLE  ELSE BRANCHING TO ONLY LEFT AVAILABLE\n    add       w5, w5, w8\n    ldrb      w6, [x10], -1\n    add       w5, w5, w6\n    beq       left_available\n    add       x10, x0, #9\n    //    BOTH LEFT AND TOP AVAILABLE\n    ld1       {v0.8b}, [x10]\n    uaddlp    v1.4h, v0.8b\n    uaddlp    v3.2s, v1.4h\n    uaddlp    v2.1d, v3.2s\n    dup       v10.8h, w5\n    dup       v8.8h, v2.h[0]\n    add       v12.8h, v8.8h , v10.8h\n    sqrshrun  v31.8b, v12.8h, #4\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    b         end_func\n\ntop_available: // ONLT TOP AVAILABLE\n    ands      w11, w4, #0x04            // CHECKING TOP AVAILABILTY  OR ELSE BRANCH TO NONE AVAILABLE\n    beq       none_available\n\n    add       x10, x0, #9\n    ld1       {v10.8b}, [x10]\n    uaddlp    v14.4h, v10.8b\n    uaddlp    v13.2s, v14.4h\n    uaddlp    v12.1d, v13.2s\n    rshrn     v4.8b, v12.8h, #3\n    dup       v31.8b, v4.b[0]\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    st1       {v31.8b}, [x1], x3\n    b         end_func\n\n\nleft_available: //ONLY LEFT AVAILABLE\n    add       x5, x5, #4\n    lsr       x5, x5, #3\n    dup       v0.8b, w5\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    b         end_func\n\nnone_available:                         //NONE AVAILABLE\n    mov       x9, #128\n    dup       v0.8b, w9\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n    st1       {v0.8b}, [x1], x3\n\n\nend_func:\n\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_8x8_mode_diag_dl\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Left\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Left ,described in sec 8.3.2.2.4\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_8x8_mode_diag_dl(UWORD8 *pu1_src,\n//                                            UWORD8 *pu1_dst,\n//                                            WORD32 src_strd,\n//                                              WORD32 dst_strd,\n//                                              WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_8x8_mode_diag_dl_av8\n\nih264_intra_pred_luma_8x8_mode_diag_dl_av8:\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n    add       x0, x0, #9\n    sub       x5, x3, #4\n    add       x6, x0, #15\n    ld1       { v0.16b}, [x0]\n    mov       v1.d[0], v0.d[1]\n    ext       v4.16b, v0.16b , v0.16b , #2\n    mov       v5.d[0], v4.d[1]\n    ext       v2.16b, v0.16b , v0.16b , #1\n    mov       v3.d[0], v2.d[1]\n    ld1       {v5.b}[6], [x6]\n    // q1 = q0 shifted to left once\n    // q2 = q1 shifted to left once\n    uaddl     v20.8h, v0.8b, v2.8b      //Adding for FILT121\n    uaddl     v22.8h, v1.8b, v3.8b\n    uaddl     v24.8h, v2.8b, v4.8b\n    uaddl     v26.8h, v3.8b, v5.8b\n    add       v24.8h, v20.8h , v24.8h\n    add       v26.8h, v22.8h , v26.8h\n\n    sqrshrun  v4.8b, v24.8h, #2\n    sqrshrun  v5.8b, v26.8h, #2\n    mov       v4.d[1], v5.d[0]\n    //Q2 has all FILT121 values\n    st1       {v4.8b}, [x1], x3\n    ext       v18.16b, v4.16b , v4.16b , #1\n    ext       v16.16b, v18.16b , v18.16b , #1\n    st1       {v18.8b}, [x1], x3\n    ext       v14.16b, v16.16b , v16.16b , #1\n    st1       {v16.8b}, [x1], x3\n    st1       {v14.8b}, [x1], x3\n    st1       {v4.s}[1], [x1], #4\n    st1       {v5.s}[0], [x1], x5\n    st1       {v18.s}[1], [x1], #4\n    st1       {v18.s}[2], [x1], x5\n    st1       {v16.s}[1], [x1], #4\n    st1       {v16.s}[2], [x1], x5\n    st1       {v14.s}[1], [x1], #4\n    st1       {v14.s}[2], [x1], x5\n\n\nend_func_diag_dl:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_8x8_mode_diag_dr\n//*\n//* @brief\n//* Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Right\n//*\n//* @par Description:\n//*  Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Right ,described in sec 8.3.2.2.5\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_8x8_mode_diag_dr(UWORD8 *pu1_src,\n//                                            UWORD8 *pu1_dst,\n//                                            WORD32 src_strd,\n//                                              WORD32 dst_strd,\n//                                              WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_diag_dr_av8\n\nih264_intra_pred_luma_8x8_mode_diag_dr_av8:\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n\n    ld1       { v0.16b}, [x0]\n    mov       v1.d[0], v0.d[1]\n    add       x0, x0, #1\n    ld1       { v2.16b}, [x0]\n    mov       v3.d[0], v2.d[1]\n    ext       v4.16b, v2.16b , v2.16b , #1\n    mov       v5.d[0], v4.d[1]\n    // q1 = q0 shifted to left once\n    // q2 = q1 shifted to left once\n    uaddl     v20.8h, v0.8b, v2.8b      //Adding for FILT121\n    uaddl     v22.8h, v1.8b, v3.8b\n    uaddl     v24.8h, v2.8b, v4.8b\n    uaddl     v26.8h, v3.8b, v5.8b\n    add       v24.8h, v20.8h , v24.8h\n    add       v26.8h, v22.8h , v26.8h\n    sqrshrun  v4.8b, v24.8h, #2\n    sqrshrun  v5.8b, v26.8h, #2\n    mov       v4.d[1], v5.d[0]\n    //Q2 has all FILT121 values\n    sub       x5, x3, #4\n    ext       v18.16b, v4.16b , v4.16b , #15\n    st1       {v18.d}[1], [x1], x3\n    ext       v16.16b, v18.16b , v18.16b , #15\n    st1       {v16.d}[1], [x1], x3\n    ext       v14.16b, v16.16b , v16.16b , #15\n    st1       {v14.d}[1], [x1], x3\n    st1       {v4.s}[1], [x1], #4\n    st1       {v5.s}[0], [x1], x5\n    st1       {v18.s}[1], [x1], #4\n    st1       {v18.s}[2], [x1], x5\n    st1       {v16.s}[1], [x1], #4\n    st1       {v16.s}[2], [x1], x5\n    st1       {v14.s}[1], [x1], #4\n    st1       {v14.s}[2], [x1], x5\n    st1       {v4.8b}, [x1], x3\n\nend_func_diag_dr:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_8x8_mode_vert_r\n//*\n//* @brief\n//* Perform Intra prediction for  luma_8x8 mode:Vertical_Right\n//*\n//* @par Description:\n//*   Perform Intra prediction for  luma_8x8 mode:Vertical_Right ,described in sec 8.3.2.2.6\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_8x8_mode_vert_r(UWORD8 *pu1_src,\n//                                            UWORD8 *pu1_dst,\n//                                            WORD32 src_strd,\n//                                              WORD32 dst_strd,\n//                                              WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_vert_r_av8\n\nih264_intra_pred_luma_8x8_mode_vert_r_av8:\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n    ld1       { v0.16b}, [x0]\n    mov       v1.d[0], v0.d[1]\n    add       x0, x0, #1\n    ld1       { v2.16b}, [x0]\n    mov       v3.d[0], v2.d[1]\n    ext       v4.16b, v2.16b , v2.16b , #1\n    mov       v5.d[0], v4.d[1]\n    // q1 = q0 shifted to left once\n    // q2 = q1 shifted to left once\n    uaddl     v20.8h, v0.8b, v2.8b\n    uaddl     v22.8h, v1.8b, v3.8b\n    uaddl     v24.8h, v2.8b, v4.8b\n    uaddl     v26.8h, v3.8b, v5.8b\n    add       v24.8h, v20.8h , v24.8h\n    add       v26.8h, v22.8h , v26.8h\n\n    sqrshrun  v4.8b, v20.8h, #1\n    sqrshrun  v5.8b, v22.8h, #1\n    mov       v4.d[1], v5.d[0]\n    sqrshrun  v6.8b, v24.8h, #2\n    sqrshrun  v7.8b, v26.8h, #2\n    mov       v6.d[1], v7.d[0]\n    //Q2 has all FILT11 values\n    //Q3 has all FILT121 values\n    sub       x5, x3, #6\n    sub       x6, x3, #4\n    st1       {v5.8b}, [x1], x3         // row 0\n    ext       v18.16b, v6.16b , v6.16b , #15\n    mov       v22.16b , v18.16b\n    ext       v16.16b, v4.16b , v4.16b , #1\n    st1       {v18.d}[1], [x1], x3      //row 1\n    mov       v14.16b , v16.16b\n    ext       v20.16b, v4.16b , v4.16b , #15\n    uzp1      v17.16b, v16.16b, v18.16b\n    uzp2      v18.16b, v16.16b, v18.16b\n    mov       v16.16b , v17.16b\n    //row 2\n    ext       v12.16b, v16.16b , v16.16b , #1\n    st1       {v20.d}[1], [x1]\n    st1       {v6.b}[6], [x1], x3\n    //row 3\n\n    st1       {v12.h}[5], [x1], #2\n    st1       {v6.s}[2], [x1], #4\n    st1       {v6.h}[6], [x1], x5\n    //row 4\n    st1       {v18.h}[5], [x1], #2\n    st1       {v4.s}[2], [x1], #4\n    st1       {v4.h}[6], [x1], x5\n    //row 5\n    ext       v26.16b, v18.16b , v18.16b , #1\n    st1       {v16.h}[5], [x1], #2\n    st1       {v22.s}[2], [x1], #4\n    st1       {v22.h}[6], [x1], x5\n    //row 6\n    st1       {v26.h}[4], [x1], #2\n    st1       {v26.b}[10], [x1], #1\n    st1       {v4.b}[8], [x1], #1\n    st1       {v14.s}[2], [x1], x6\n    //row 7\n    st1       {v12.s}[2], [x1], #4\n    st1       {v6.s}[2], [x1], #4\n\nend_func_vert_r:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_8x8_mode_horz_d\n//*\n//* @brief\n//* Perform Intra prediction for  luma_8x8 mode:Horizontal_Down\n//*\n//* @par Description:\n//*   Perform Intra prediction for  luma_8x8 mode:Horizontal_Down ,described in sec 8.3.2.2.7\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_8x8_mode_horz_d(UWORD8 *pu1_src,\n//                                            UWORD8 *pu1_dst,\n//                                            WORD32 src_strd,\n//                                              WORD32 dst_strd,\n//                                              WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_8x8_mode_horz_d_av8\n\nih264_intra_pred_luma_8x8_mode_horz_d_av8:\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n    ld1       { v0.16b}, [x0]\n    mov       v1.d[0], v0.d[1]\n    add       x0, x0, #1\n    ld1       { v2.16b}, [x0]\n    mov       v3.d[0], v2.d[1]\n    ext       v4.16b, v2.16b , v2.16b , #1\n    mov       v5.d[0], v4.d[1]\n    // q1 = q0 shifted to left once\n    // q2 = q1 shifted to left once\n    uaddl     v20.8h, v0.8b, v2.8b\n    uaddl     v22.8h, v1.8b, v3.8b\n    uaddl     v24.8h, v2.8b, v4.8b\n    uaddl     v26.8h, v3.8b, v5.8b\n    add       v24.8h, v20.8h , v24.8h\n    add       v26.8h, v22.8h , v26.8h\n\n    sqrshrun  v4.8b, v20.8h, #1\n    sqrshrun  v5.8b, v22.8h, #1\n    mov       v4.d[1], v5.d[0]\n    sqrshrun  v6.8b, v24.8h, #2\n    sqrshrun  v7.8b, v26.8h, #2\n    mov       v6.d[1], v7.d[0]\n    //Q2 has all FILT11 values\n    //Q3 has all FILT121 values\n    mov       v8.16b, v4.16b\n    mov       v10.16b, v6.16b\n    sub       x6, x3, #6\n    trn1      v9.16b, v8.16b, v10.16b\n    trn2      v10.16b, v8.16b, v10.16b  //\n    mov       v8.16b, v9.16b\n    mov       v12.16b, v8.16b\n    mov       v14.16b, v10.16b\n    sub       x5, x3, #4\n    trn1      v13.8h, v12.8h, v14.8h\n    trn2      v14.8h, v12.8h, v14.8h\n    mov       v12.16b, v13.16b\n    ext       v16.16b, v6.16b , v6.16b , #14\n    //ROW 0\n    st1       {v16.d}[1], [x1]\n    st1       {v10.h}[3], [x1], x3\n\n    //ROW 1\n    st1       {v14.s}[1], [x1], #4\n    st1       {v6.s}[2], [x1], x5\n    //ROW 2\n    st1       {v10.h}[2], [x1], #2\n    st1       {v14.s}[1], [x1], #4\n    st1       {v7.h}[0], [x1], x6\n    //ROW 3\n    st1       {v12.s}[1], [x1], #4\n    st1       {v14.s}[1], [x1], x5\n    //ROW 4\n    st1       {v14.h}[1], [x1], #2\n    st1       {v12.s}[1], [x1], #4\n    st1       {v14.h}[2], [x1], x6\n    //ROW 5\n    st1       {v14.s}[0], [x1], #4\n    st1       {v12.s}[1], [x1], x5\n    //ROW 6\n    st1       {v10.h}[0], [x1], #2\n    st1       {v8.h}[1], [x1], #2\n    st1       {v14.h}[1], [x1], #2\n    st1       {v12.h}[2], [x1], x6\n    //ROW 7\n    st1       {v12.s}[0], [x1], #4\n    st1       {v14.s}[0], [x1], x5\n\nend_func_horz_d:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_8x8_mode_vert_l\n//*\n//* @brief\n//*  Perform Intra prediction for  luma_8x8 mode:Vertical_Left\n//*\n//* @par Description:\n//*   Perform Intra prediction for  luma_8x8 mode:Vertical_Left ,described in sec 8.3.2.2.8\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_8x8_mode_vert_l(UWORD8 *pu1_src,\n//                                            UWORD8 *pu1_dst,\n//                                            WORD32 src_strd,\n//                                              WORD32 dst_strd,\n//                                              WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n\n    .global ih264_intra_pred_luma_8x8_mode_vert_l_av8\n\nih264_intra_pred_luma_8x8_mode_vert_l_av8:\n\n    // STMFD sp!, {x4-x12, x14}         //Restoring registers from stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n    add       x0, x0, #9\n    ld1       { v0.16b}, [x0]\n    mov       v1.d[0], v0.d[1]\n    add       x0, x0, #1\n    ld1       { v2.16b}, [x0]\n    mov       v3.d[0], v2.d[1]\n    ext       v4.16b, v2.16b , v2.16b , #1\n    mov       v5.d[0], v4.d[1]\n    uaddl     v20.8h, v0.8b, v2.8b\n    uaddl     v22.8h, v1.8b, v3.8b\n    uaddl     v24.8h, v2.8b, v4.8b\n    uaddl     v26.8h, v3.8b, v5.8b\n    add       v24.8h, v20.8h , v24.8h\n    add       v26.8h, v22.8h , v26.8h\n\n    sqrshrun  v4.8b, v20.8h, #1\n    sqrshrun  v5.8b, v22.8h, #1\n    mov       v4.d[1], v5.d[0]\n    sqrshrun  v6.8b, v24.8h, #2\n    ext       v8.16b, v4.16b , v4.16b , #1\n    sqrshrun  v7.8b, v26.8h, #2\n    mov       v6.d[1], v7.d[0]\n    //Q2 has all FILT11 values\n    //Q3 has all FILT121 values\n\n    ext       v10.16b, v6.16b , v6.16b , #1\n    //ROW 0,1\n    st1       {v4.8b}, [x1], x3\n    st1       {v6.8b}, [x1], x3\n\n    ext       v12.16b, v8.16b , v8.16b , #1\n    ext       v14.16b, v10.16b , v10.16b , #1\n    //ROW 2,3\n    st1       {v8.8b}, [x1], x3\n    st1       {v10.8b}, [x1], x3\n\n    ext       v16.16b, v12.16b , v12.16b , #1\n    ext       v18.16b, v14.16b , v14.16b , #1\n    //ROW 4,5\n    st1       {v12.8b}, [x1], x3\n    st1       {v14.8b}, [x1], x3\n    //ROW 6,7\n    st1       {v16.8b}, [x1], x3\n    st1       {v18.8b}, [x1], x3\n\nend_func_vert_l:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//*ih264_intra_pred_luma_8x8_mode_horz_u\n//*\n//* @brief\n//*     Perform Intra prediction for  luma_8x8 mode:Horizontal_Up\n//*\n//* @par Description:\n//*      Perform Intra prediction for  luma_8x8 mode:Horizontal_Up ,described in sec 8.3.2.2.9\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[out] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] dst_strd\n//*  integer destination stride\n//*\n//* @param[in] ui_neighboravailability\n//*  availability of neighbouring pixels\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************/\n//void ih264_intra_pred_luma_8x8_mode_horz_u(UWORD8 *pu1_src,\n//                                           UWORD8 *pu1_dst,\n//                                           WORD32 src_strd,\n//                                             WORD32 dst_strd,\n//                                             WORD32 ui_neighboravailability)\n\n//**************Variables Vs Registers*****************************************\n//    x0 => *pu1_src\n//    x1 => *pu1_dst\n//    w2 =>  src_strd\n//    w3 =>  dst_strd\n//    w4 =>  ui_neighboravailability\n\n    .global ih264_intra_pred_luma_8x8_mode_horz_u_av8\n\nih264_intra_pred_luma_8x8_mode_horz_u_av8:\n\n    // STMFD sp!, {x4-x12, x14}          //store register values to stack\n    push_v_regs\n    stp       x19, x20, [sp, #-16]!\n    sxtw      x3, w3\n\n    ld1       {v0.8b}, [x0]\n    ld1       {v1.b}[7], [x0]\n    mov       v0.d[1], v1.d[0]\n    ext       v2.16b, v0.16b , v0.16b , #1\n    mov       v3.d[0], v2.d[1]\n    ext       v4.16b, v2.16b , v2.16b , #1\n    mov       v5.d[0], v4.d[1]\n#ifdef __APPLE__\n    adrp      x12, _ih264_gai1_intrapred_luma_8x8_horz_u@GOTPAGE\n    ldr       x12, [x12, _ih264_gai1_intrapred_luma_8x8_horz_u@GOTPAGEOFF]\n#else\n    adrp      x12, :got:ih264_gai1_intrapred_luma_8x8_horz_u\n    ldr       x12, [x12, #:got_lo12:ih264_gai1_intrapred_luma_8x8_horz_u]\n#endif\n    uaddl     v20.8h, v0.8b, v2.8b\n    uaddl     v22.8h, v1.8b, v3.8b\n    uaddl     v24.8h, v2.8b, v4.8b\n    uaddl     v26.8h, v3.8b, v5.8b\n    add       v24.8h, v20.8h , v24.8h\n    add       v26.8h, v22.8h , v26.8h\n    ld1       { v10.16b}, [x12]\n    mov       v11.d[0], v10.d[1]\n    sqrshrun  v4.8b, v20.8h, #1\n    sqrshrun  v5.8b, v22.8h, #1\n    mov       v4.d[1], v5.d[0]\n    sqrshrun  v6.8b, v24.8h, #2\n    sqrshrun  v7.8b, v26.8h, #2\n    mov       v6.d[1], v7.d[0]\n    //Q2 has all FILT11 values\n    //Q3 has all FILT121 values\n    mov       v30.16b, v4.16b\n    mov       v31.16b, v6.16b\n    tbl       v12.8b, {v30.16b, v31.16b}, v10.8b\n    dup       v14.16b, v5.b[7]          //\n    tbl       v13.8b, {v30.16b, v31.16b}, v11.8b\n    mov       v12.d[1], v13.d[0]\n    ext       v16.16b, v12.16b , v14.16b , #2\n    ext       v18.16b, v16.16b , v14.16b , #2\n    st1       {v12.8b}, [x1], x3        //0\n    ext       v20.16b, v18.16b , v14.16b , #2\n    st1       {v16.8b}, [x1], x3        //1\n    st1       {v18.8b}, [x1], x3        //2\n    st1       {v20.8b}, [x1], x3        //3\n    st1       {v13.8b}, [x1], x3        //4\n    st1       {v16.d}[1], [x1], x3      //5\n    st1       {v18.d}[1], [x1], x3      //6\n    st1       {v20.d}[1], [x1], x3      //7\n\n\nend_func_horz_u:\n    // LDMFD sp!,{x4-x12,PC}         //Restoring registers from stack\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_iquant_itrans_recon_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n///*******************************************************************************\n// * //file\n// *  ih264_iquant_itrans_recon_a9.s\n// *\n// * //brief\n// *  Contains function definitions for single stage  inverse transform\n// *\n// * //author\n// *  Parthiban V\n// *     Mohit\n// *  Harinarayanaan\n// *\n// * //par List of Functions:\n// *  - ih264_iquant_itrans_recon_4x4_av8()\n// *     - ih264_iquant_itrans_recon_8x8_av8()\n// *     - ih264_iquant_itrans_recon_chroma_4x4_av8()\n// *\n// * //remarks\n// *  None\n// *\n// *******************************************************************************\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n///*\n// *******************************************************************************\n// *\n// * //brief\n// *  This function performs inverse quant and Inverse transform type Ci4 for 4*4 block\n// *\n// * //par Description:\n// *  Performs inverse transform Ci4 and adds the residue to get the\n// *  reconstructed block\n// *\n// * //param[in] pi2_src\n// *  Input 4x4 coefficients\n// *\n// * //param[in] pu1_pred\n// *  Prediction 4x4 block\n// *\n// * //param[out] pu1_out\n// *  Output 4x4 block\n// *\n// * //param[in] u4_qp_div_6\n// *     QP\n// *\n// * //param[in] pu2_weigh_mat\n// * Pointer to weight matrix\n// *\n// * //param[in] pred_strd,\n// *  Prediction stride\n// *\n// * //param[in] out_strd\n// *  Output Stride\n// *\n// *//param[in] pi2_tmp\n// * temporary buffer of size 1*16\n// *\n// * //param[in] pu2_iscal_mat\n// * Pointer to the inverse quantization matrix\n// *\n// * //returns  Void\n// *\n// * //remarks\n// *  None\n// *\n// *******************************************************************************\n// */\n//void ih264_iquant_itrans_recon_4x4(WORD16 *pi2_src,\n//                                    UWORD8 *pu1_pred,\n//                                    UWORD8 *pu1_out,\n//                                    WORD32 pred_strd,\n//                                    WORD32 out_strd,\n//                                    const UWORD16 *pu2_iscal_mat,\n//                                    const UWORD16 *pu2_weigh_mat,\n//                                    UWORD32 u4_qp_div_6,\n//                                    WORD32 *pi4_tmp,\n//                                    WORD32 iq_start_idx\n//                                    WORD16 *pi2_dc_ld_addr)\n//**************Variables Vs Registers*****************************************\n//x0 => *pi2_src\n//x1 => *pu1_pred\n//x2 => *pu1_out\n//w3 =>  pred_strd\n//w4 =>  out_strd\n//x5 => *pu2_iscal_mat\n//x6 => *pu2_weigh_mat\n//w7 =>  u4_qp_div_6\n//   =>  pi4_tmp\n//   =>  iq_start_idx\n//   =>  pi2_dc_ld_addr\n//Only one shift is done in horizontal inverse because,\n//if u4_qp_div_6 is lesser than 4 then shift value will be neagative and do negative left shift, in this case rnd_factor has value\n//if u4_qp_div_6 is greater than 4 then shift value will be positive and do left shift, here rnd_factor is 0\n\n    .global ih264_iquant_itrans_recon_4x4_av8\nih264_iquant_itrans_recon_4x4_av8:\n\n    push_v_regs\n    sxtw      x3, w3\n    sxtw      x4, w4\n\n    dup       v30.4s, w7                //Populate the u4_qp_div_6 in Q15\n\n    ldr       w8, [sp, #72]             //Loads iq_start_idx\n    sxtw      x8, w8\n\n    ldr       x10, [sp, #80]            //Load alternate dc address\n\n    subs      x8, x8, #1                // if x8 == 1 => intra case , so result of subtraction is zero and z flag is set\n\n\n//=======================DEQUANT FROM HERE===================================\n\n    ld4       {v20.4h - v23.4h}, [x5]   // load pu2_iscal_mat[i], i =0..15\n    ld4       {v26.4h - v29.4h}, [x6]   // pu2_weigh_mat[i], i =0..15\n    ld4       {v16.4h - v19.4h}, [x0]   // pi2_src_tmp[i], i =0..15\n\n\n    mul       v20.4h, v20.4h, v26.4h    // x[i]=(scale[i] * dequant[i]) where i = 0..3\n    mul       v21.4h, v21.4h, v27.4h    // x[i]=(scale[i] * dequant[i]) where i = 4..7\n    mul       v22.4h, v22.4h, v28.4h    // x[i]=(scale[i] * dequant[i]) where i = 8..11\n    mul       v23.4h, v23.4h, v29.4h    // x[i]=(scale[i] * dequant[i]) where i = 12..14\n\n    smull     v0.4s, v16.4h, v20.4h     // q0  = p[i] = (x[i] * trns_coeff[i]) where i = 0..3\n    smull     v2.4s, v17.4h, v21.4h     // q1  = p[i] = (x[i] * trns_coeff[i]) where i = 4..7\n    smull     v4.4s, v18.4h, v22.4h     // q2  = p[i] = (x[i] * trns_coeff[i]) where i = 8..11\n    smull     v6.4s, v19.4h, v23.4h     // q3  = p[i] = (x[i] * trns_coeff[i]) where i = 12..15\n\n    sshl      v0.4s, v0.4s, v30.4s      // q0  = q[i] = (p[i] << (qp/6)) where i = 0..3\n    sshl      v2.4s, v2.4s, v30.4s      // q1  = q[i] = (p[i] << (qp/6)) where i = 4..7\n    sshl      v4.4s, v4.4s, v30.4s      // q2  = q[i] = (p[i] << (qp/6)) where i = 8..11\n    sshl      v6.4s, v6.4s, v30.4s      // q3  = q[i] = (p[i] << (qp/6)) where i = 12..15\n\n    sqrshrn   v0.4h, v0.4s, #0x4        // d0  = c[i] = ((q[i] + 32) >> 4) where i = 0..3\n    sqrshrn   v1.4h, v2.4s, #0x4        // d1  = c[i] = ((q[i] + 32) >> 4) where i = 4..7\n    sqrshrn   v2.4h, v4.4s, #0x4        // d2  = c[i] = ((q[i] + 32) >> 4) where i = 8..11\n    sqrshrn   v3.4h, v6.4s, #0x4        // d3  = c[i] = ((q[i] + 32) >> 4) where i = 12..15\n\n    bne       skip_loading_luma_dc_src\n    ld1       {v0.h}[0], [x10]          // loads signed halfword pi2_dc_ld_addr[0], if x8==1\nskip_loading_luma_dc_src:\n\n    //========= PROCESS IDCT FROM HERE =======\n    //Steps for Stage 1:\n    //------------------\n    ld1       {v30.s}[0], [x1], x3      // i row load pu1_pred buffer\n\n    sshr      v8.4h, v1.4h, #1          // d1>>1\n    sshr      v9.4h, v3.4h, #1          // d3>>1\n\n    add       v4.4h, v0.4h, v2.4h       // x0 = d0 + d2//\n    sub       v5.4h, v0.4h, v2.4h       // x1 = d0 - d2//\n    sub       v6.4h, v8.4h, v3.4h       // x2 = (d1 >> 1) -  d3//\n    add       v7.4h, v1.4h, v9.4h       // x3 =  d1  + (d3 >>  1)//\n\n    ld1       {v30.s}[1], [x1], x3      // ii row load pu1_pred buffer\n\n    add       v10.4h, v4.4h , v7.4h     // x0+x3\n    add       v11.4h, v5.4h , v6.4h     // x1+x2\n    sub       v12.4h, v5.4h , v6.4h     // x1-x2\n    sub       v13.4h, v4.4h , v7.4h\n\n    ld1       {v31.s}[0], [x1], x3      // iii row load pu1_pred buf\n\n\n    //Steps for Stage 2:\n    //transopose\n    trn1      v4.4h, v10.4h, v11.4h\n    trn2      v5.4h, v10.4h, v11.4h\n    trn1      v6.4h, v12.4h, v13.4h\n    trn2      v7.4h, v12.4h, v13.4h\n\n    trn1      v10.2s, v4.2s, v6.2s      // 0\n    trn1      v11.2s, v5.2s, v7.2s      // 8\n    trn2      v12.2s, v4.2s, v6.2s      // 4\n    trn2      v13.2s, v5.2s, v7.2s\n    //end transpose\n\n    sshr      v18.4h, v11.4h, #1        // q0>>1\n    sshr      v19.4h, v13.4h, #1        // q1>>1\n\n    add       v14.4h, v10.4h, v12.4h    // x0 = q0 + q2//\n    sub       v15.4h, v10.4h, v12.4h    // x1 = q0 - q2//\n    sub       v16.4h, v18.4h, v13.4h    // x2 = (q1 >> 1) -  q3//\n    add       v17.4h, v11.4h, v19.4h    // x3 = q1+ (q3 >> 3)//\n\n\n    ld1       {v31.s}[1], [x1], x3      // iv row load pu1_pred buffer\n\n    add       v20.4h, v14.4h, v17.4h    // x0 + x3\n    add       v21.4h, v15.4h, v16.4h    // x1 + x2\n    sub       v22.4h, v15.4h, v16.4h    // x1 - x2\n    sub       v23.4h, v14.4h, v17.4h    // x0 - x3\n\n    mov       v20.d[1], v21.d[0]\n    mov       v22.d[1], v23.d[0]\n\n    srshr     v20.8h, v20.8h, #6\n    srshr     v22.8h, v22.8h, #6\n\n    uaddw     v20.8h, v20.8h , v30.8b\n    uaddw     v22.8h, v22.8h , v31.8b\n\n    sqxtun    v0.8b, v20.8h\n    sqxtun    v1.8b, v22.8h\n\n    st1       {v0.s}[0], [x2], x4       //i row store the value\n    st1       {v0.s}[1], [x2], x4       //ii row store the value\n    st1       {v1.s}[0], [x2], x4       //iii row store the value\n    st1       {v1.s}[1], [x2]           //iv row store the value\n\n    pop_v_regs\n    ret\n\n\n///**\n// *******************************************************************************\n// *\n// * @brief\n// *  This function performs inverse quant and Inverse transform type Ci4 for 4*4 block\n// *\n// * @par Description:\n// *  Performs inverse transform Ci4 and adds the residue to get the\n// *  reconstructed block\n// *\n// * @param[in] pi2_src\n// *  Input 4x4 coefficients\n// *\n// * @param[in] pu1_pred\n// *  Prediction 4x4 block\n// *\n// * @param[out] pu1_out\n// *  Output 4x4 block\n// *\n// * @param[in] u4_qp_div_6\n// *     QP\n// *\n// * @param[in] pu2_weigh_mat\n// * Pointer to weight matrix\n// *\n// * @param[in] pred_strd,\n// *  Prediction stride\n// *\n// * @param[in] out_strd\n// *  Output Stride\n// *\n// *@param[in] pi2_tmp\n// * temporary buffer of size 1*16\n// *\n// * @param[in] pu2_iscal_mat\n// * Pointer to the inverse quantization matrix\n// *\n// * @returns  Void\n// *\n// * @remarks\n// *  None\n// *\n// *******************************************************************************\n// */\n//void ih264_iquant_itrans_recon_chroma_4x4(WORD16 *pi2_src,\n//                                          UWORD8 *pu1_pred,\n//                                          UWORD8 *pu1_out,\n//                                          WORD32 pred_strd,\n//                                          WORD32 out_strd,\n//                                          const UWORD16 *pu2_iscal_mat,\n//                                          const UWORD16 *pu2_weigh_mat,\n//                                          UWORD32 u4_qp_div_6,\n//                                          WORD32 *pi4_tmp\n//                                          WORD16 *pi2_dc_src)\n//**************Variables Vs Registers*****************************************\n//x0 => *pi2_src\n//x1 => *pu1_pred\n//x2 => *pu1_out\n//w3 =>  pred_strd\n//w4 =>  out_strd\n//x5 => *pu2_iscal_mat\n//x6 => *pu2_weigh_mat\n//w7 =>  u4_qp_div_6\n//sp =>  pi4_tmp\n//sp#8 => *pi2_dc_src\n\n    .global ih264_iquant_itrans_recon_chroma_4x4_av8\nih264_iquant_itrans_recon_chroma_4x4_av8:\n\n//VLD4.S16 is used because the pointer is incremented by SUB_BLK_WIDTH_4x4\n//If the macro value changes need to change the instruction according to it.\n//Only one shift is done in horizontal inverse because,\n//if u4_qp_div_6 is lesser than 4 then shift value will be neagative and do negative left shift, in this case rnd_factor has value\n//if u4_qp_div_6 is greater than 4 then shift value will be positive and do left shift, here rnd_factor is 0\n\n//at the end of the fucntion, we could have moved 64 bits into heigher 64 bits of register and done further processing\n//but it seem to give only reduce the number of instruction by 1. [Since a15 we saw add and sub to be very high throughput\n//all instructions were taken as equal\n\n    //reduce sp by 64\n    push_v_regs\n    sxtw      x3, w3\n    sxtw      x4, w4\n\n    dup       v30.4s, w7                //Populate the u4_qp_div_6 in Q15\n\n    //was at sp + 8, hence now at sp+64+8 = sp+72\n    ldr       x10, [sp, #72]            //Load alternate dc address\n\n//=======================DEQUANT FROM HERE===================================\n\n    ld4       {v20.4h - v23.4h}, [x5]   // load pu2_iscal_mat[i], i =0..15\n    ld4       {v26.4h - v29.4h}, [x6]   // pu2_weigh_mat[i], i =0..15\n    ld4       {v16.4h - v19.4h}, [x0]   // pi2_src_tmp[i], i =0..15\n\n\n    mul       v20.4h, v20.4h, v26.4h    // x[i]=(scale[i] * dequant[i]) where i = 0..3\n    mul       v21.4h, v21.4h, v27.4h    // x[i]=(scale[i] * dequant[i]) where i = 4..7\n    mul       v22.4h, v22.4h, v28.4h    // x[i]=(scale[i] * dequant[i]) where i = 8..11\n    mul       v23.4h, v23.4h, v29.4h    // x[i]=(scale[i] * dequant[i]) where i = 12..14\n\n    smull     v0.4s, v16.4h, v20.4h     // q0  = p[i] = (x[i] * trns_coeff[i]) where i = 0..3\n    smull     v2.4s, v17.4h, v21.4h     // q1  = p[i] = (x[i] * trns_coeff[i]) where i = 4..7\n    smull     v4.4s, v18.4h, v22.4h     // q2  = p[i] = (x[i] * trns_coeff[i]) where i = 8..11\n    smull     v6.4s, v19.4h, v23.4h     // q3  = p[i] = (x[i] * trns_coeff[i]) where i = 12..15\n\n    sshl      v0.4s, v0.4s, v30.4s      // q0  = q[i] = (p[i] << (qp/6)) where i = 0..3\n    sshl      v2.4s, v2.4s, v30.4s      // q1  = q[i] = (p[i] << (qp/6)) where i = 4..7\n    sshl      v4.4s, v4.4s, v30.4s      // q2  = q[i] = (p[i] << (qp/6)) where i = 8..11\n    sshl      v6.4s, v6.4s, v30.4s      // q3  = q[i] = (p[i] << (qp/6)) where i = 12..15\n\n    sqrshrn   v0.4h, v0.4s, #0x4        // d0  = c[i] = ((q[i] + 32) >> 4) where i = 0..3\n    sqrshrn   v1.4h, v2.4s, #0x4        // d1  = c[i] = ((q[i] + 32) >> 4) where i = 4..7\n    sqrshrn   v2.4h, v4.4s, #0x4        // d2  = c[i] = ((q[i] + 32) >> 4) where i = 8..11\n    sqrshrn   v3.4h, v6.4s, #0x4        // d3  = c[i] = ((q[i] + 32) >> 4) where i = 12..15\n\n    ld1       {v0.h}[0], [x10]          // loads signed halfword pi2_dc_src[0]\n\n    //========= PROCESS IDCT FROM HERE =======\n    //Steps for Stage 1:\n    //------------------\n\n    sshr      v8.4h, v1.4h, #1          // d1>>1\n    sshr      v9.4h, v3.4h, #1          // d3>>1\n\n    add       v4.4h, v0.4h, v2.4h       // x0 = d0 + d2//\n    sub       v5.4h, v0.4h, v2.4h       // x1 = d0 - d2//\n    sub       v6.4h, v8.4h, v3.4h       // x2 = (d1 >> 1) -  d3//\n    add       v7.4h, v1.4h, v9.4h       // x3 =  d1  + (d3 >>  1)//\n\n\n    add       v10.4h, v4.4h , v7.4h     // x0+x3\n    add       v11.4h, v5.4h , v6.4h     // x1+x2\n    sub       v12.4h, v5.4h , v6.4h     // x1-x2\n    sub       v13.4h, v4.4h , v7.4h\n\n    ld1       {v26.8b}, [x1], x3        // i row load pu1_pred buffer\n    ld1       {v27.8b}, [x1], x3        // ii row load pu1_pred buffer\n    ld1       {v28.8b}, [x1], x3        // iii row load pu1_pred buf\n    ld1       {v29.8b}, [x1], x3        // iv row load pu1_pred buffer\n\n    //Steps for Stage 2:\n    //transopose\n    trn1      v4.4h, v10.4h, v11.4h\n    trn2      v5.4h, v10.4h, v11.4h\n    trn1      v6.4h, v12.4h, v13.4h\n    trn2      v7.4h, v12.4h, v13.4h\n\n    trn1      v10.2s, v4.2s, v6.2s      // 0\n    trn1      v11.2s, v5.2s, v7.2s      // 8\n    trn2      v12.2s, v4.2s, v6.2s      // 4\n    trn2      v13.2s, v5.2s, v7.2s\n    //end transpose\n\n    sshr      v18.4h, v11.4h, #1        // q0>>1\n    sshr      v19.4h, v13.4h, #1        // q1>>1\n\n    add       v14.4h, v10.4h, v12.4h    // x0 = q0 + q2//\n    sub       v15.4h, v10.4h, v12.4h    // x1 = q0 - q2//\n    sub       v16.4h, v18.4h, v13.4h    // x2 = (q1 >> 1) -  q3//\n    add       v17.4h, v11.4h, v19.4h    // x3 = q1+ (q3 >> 3)//\n\n    //Backup the output addr\n    mov       x0, x2\n\n    //load outpt buufer for interleaving\n    ld1       {v10.8b}, [x2], x4\n    ld1       {v11.8b}, [x2], x4\n    ld1       {v12.8b}, [x2], x4\n    ld1       {v13.8b}, [x2]\n\n    add       v20.4h, v14.4h, v17.4h    // x0 + x3\n    add       v21.4h, v15.4h, v16.4h    // x1 + x2\n    sub       v22.4h, v15.4h, v16.4h    // x1 - x2\n    sub       v23.4h, v14.4h, v17.4h    // x0 - x3\n\n    srshr     v20.4h, v20.4h, #6\n    srshr     v21.4h, v21.4h, #6\n    srshr     v22.4h, v22.4h, #6\n    srshr     v23.4h, v23.4h, #6\n\n    //nop       v30.8b                            //dummy for deinterleaving\n    movi      v31.4h, #0x00ff           //mask for interleaving [copy lower 8 bits]\n\n    //Extract u/v plane from interleaved data\n    uzp1      v26.8b, v26.8b, v30.8b\n    uzp1      v27.8b, v27.8b, v30.8b\n    uzp1      v28.8b, v28.8b, v30.8b\n    uzp1      v29.8b, v29.8b, v30.8b\n\n    uaddw     v20.8h, v20.8h, v26.8b\n    uaddw     v21.8h, v21.8h, v27.8b\n    uaddw     v22.8h, v22.8h, v28.8b\n    uaddw     v23.8h, v23.8h, v29.8b\n\n    sqxtun    v0.8b, v20.8h\n    sqxtun    v1.8b, v21.8h\n    sqxtun    v2.8b, v22.8h\n    sqxtun    v3.8b, v23.8h\n\n    //long the output so that we have 0 at msb and value at lsb\n    uxtl      v6.8h, v0.8b\n    uxtl      v7.8h, v1.8b\n    uxtl      v8.8h, v2.8b\n    uxtl      v9.8h, v3.8b\n\n    //select lsbs from proceesd data and msbs from pu1_out loaded data\n    bit       v10.8b, v6.8b, v31.8b\n    bit       v11.8b, v7.8b, v31.8b\n    bit       v12.8b, v8.8b, v31.8b\n    bit       v13.8b, v9.8b, v31.8b\n\n    //store the interleaved result\n    st1       {v10.8b}, [x0], x4\n    st1       {v11.8b}, [x0], x4\n    st1       {v12.8b}, [x0], x4\n    st1       {v13.8b}, [x0]\n\n    pop_v_regs\n    ret\n\n///*\n// *******************************************************************************\n// *\n// * //brief\n// *  This function performs inverse quant and Inverse transform type Ci4 for 8*8 block\n// *\n// * //par Description:\n// *  Performs inverse transform Ci8 and adds the residue to get the\n// *  reconstructed block\n// *\n// * //param[in] pi2_src\n// *  Input 4x4 coefficients\n// *\n// * //param[in] pu1_pred\n// *  Prediction 4x4 block\n// *\n// * //param[out] pu1_out\n// *  Output 4x4 block\n// *\n// * //param[in] u4_qp_div_6\n// *     QP\n// *\n// * //param[in] pu2_weigh_mat\n// * Pointer to weight matrix\n// *\n// * //param[in] pred_strd,\n// *  Prediction stride\n// *\n// * //param[in] out_strd\n// *  Output Stride\n// *\n// *//param[in] pi2_tmp\n// * temporary buffer of size 1*64\n// *\n// * //param[in] pu2_iscal_mat\n// * Pointer to the inverse quantization matrix\n// *\n// * //returns  Void\n// *\n// * //remarks\n// *  None\n// *\n// *******************************************************************************\n// */\n//void ih264_iquant_itrans_recon_8x8(WORD16 *pi2_src,\n//                                   UWORD8 *pu1_pred,\n//                                   UWORD8 *pu1_out,\n//                                   WORD32 pred_strd,\n//                                   WORD32 out_strd,\n//                                   const UWORD16 *pu2_iscal_mat,\n//                                   const UWORD16 *pu2_weigh_mat,\n//                                   UWORD32 u4_qp_div_6,\n//                                   WORD32 *pi4_tmp,\n//                                   WORD32 iq_start_idx\n//                                   WORD16 *pi2_dc_ld_addr)\n//**************Variables Vs Registers*****************************************\n//x0       => *pi2_src\n//x1       => *pu1_pred\n//x2       => *pu1_out\n//w3       =>  pred_strd\n//w4       =>  out_strd\n//x5       =>  *pu2_iscal_mat\n//x6       =>  *pu2_weigh_mat\n//w7       =>  u4_qp_div_6\n//NOT USED =>  pi4_tmp\n//NOT USED =>  iq_start_idx\n//NOT USED =>  pi2_dc_ld_addr\n\n    .global ih264_iquant_itrans_recon_8x8_av8\nih264_iquant_itrans_recon_8x8_av8:\n\n    push_v_regs\n    sxtw      x3, w3\n    sxtw      x4, w4\n\n    ld1       {v8.8h -v11.8h}, [x5], #64\n    ld1       {v12.8h-v15.8h}, [x5]\n\n    ld1       {v16.8h -v19.8h}, [x6], #64\n    ld1       {v20.8h -v23.8h}, [x6]\n\n    mov       x8, #16\n    ld1       {v0.8h}, [x0], x8\n    ld1       {v1.8h}, [x0], x8\n    ld1       {v2.8h}, [x0], x8\n    ld1       {v3.8h}, [x0], x8\n    ld1       {v4.8h}, [x0], x8\n    ld1       {v5.8h}, [x0], x8\n    ld1       {v6.8h}, [x0], x8\n    ld1       {v7.8h}, [x0]\n\n    mul       v8.8h, v8.8h, v16.8h\n    mul       v9.8h, v9.8h, v17.8h\n    mul       v10.8h, v10.8h, v18.8h\n    mul       v11.8h, v11.8h, v19.8h\n    mul       v12.8h, v12.8h, v20.8h\n    mul       v13.8h, v13.8h, v21.8h\n    mul       v14.8h, v14.8h, v22.8h\n    mul       v15.8h, v15.8h, v23.8h\n\n    smull     v16.4s, v0.4h, v8.4h\n    smull2    v17.4s, v0.8h, v8.8h\n    smull     v18.4s, v1.4h, v9.4h\n    smull2    v19.4s, v1.8h, v9.8h\n    smull     v20.4s, v2.4h, v10.4h\n    smull2    v21.4s, v2.8h, v10.8h\n    smull     v22.4s, v3.4h, v11.4h\n    smull2    v23.4s, v3.8h, v11.8h\n    smull     v24.4s, v4.4h, v12.4h\n    smull2    v25.4s, v4.8h, v12.8h\n    smull     v26.4s, v5.4h, v13.4h\n    smull2    v27.4s, v5.8h, v13.8h\n    smull     v28.4s, v6.4h, v14.4h\n    smull2    v29.4s, v6.8h, v14.8h\n    smull     v30.4s, v7.4h, v15.4h\n    smull2    v31.4s, v7.8h, v15.8h\n\n    dup       v0.4s, w7\n\n    sshl      v16.4s, v16.4s, v0.4s\n    sshl      v17.4s, v17.4s, v0.4s\n    sshl      v18.4s, v18.4s, v0.4s\n    sshl      v19.4s, v19.4s, v0.4s\n    sshl      v20.4s, v20.4s, v0.4s\n    sshl      v21.4s, v21.4s, v0.4s\n    sshl      v22.4s, v22.4s, v0.4s\n    sshl      v23.4s, v23.4s, v0.4s\n    sshl      v24.4s, v24.4s, v0.4s\n    sshl      v25.4s, v25.4s, v0.4s\n    sshl      v26.4s, v26.4s, v0.4s\n    sshl      v27.4s, v27.4s, v0.4s\n    sshl      v28.4s, v28.4s, v0.4s\n    sshl      v29.4s, v29.4s, v0.4s\n    sshl      v30.4s, v30.4s, v0.4s\n    sshl      v31.4s, v31.4s, v0.4s\n\n    sqrshrn   v0.4h, v16.4s, #6\n    sqrshrn2  v0.8h, v17.4s, #6\n    sqrshrn   v1.4h, v18.4s, #6\n    sqrshrn2  v1.8h, v19.4s, #6\n    sqrshrn   v2.4h, v20.4s, #6\n    sqrshrn2  v2.8h, v21.4s, #6\n    sqrshrn   v3.4h, v22.4s, #6\n    sqrshrn2  v3.8h, v23.4s, #6\n    sqrshrn   v4.4h, v24.4s, #6\n    sqrshrn2  v4.8h, v25.4s, #6\n    sqrshrn   v5.4h, v26.4s, #6\n    sqrshrn2  v5.8h, v27.4s, #6\n    sqrshrn   v6.4h, v28.4s, #6\n    sqrshrn2  v6.8h, v29.4s, #6\n    sqrshrn   v7.4h, v30.4s, #6\n    sqrshrn2  v7.8h, v31.4s, #6\n\n    //loop counter\n    mov       x8, #2\n//1x8 transofORM\ntrans_1x8_1d:\n\n    //transpose 8x8\n    trn1      v8.8h, v0.8h, v1.8h\n    trn2      v9.8h, v0.8h, v1.8h\n    trn1      v10.8h, v2.8h, v3.8h\n    trn2      v11.8h, v2.8h, v3.8h\n    trn1      v12.8h, v4.8h, v5.8h\n    trn2      v13.8h, v4.8h, v5.8h\n    trn1      v14.8h, v6.8h, v7.8h\n    trn2      v15.8h, v6.8h, v7.8h\n\n    trn1      v0.4s, v8.4s, v10.4s\n    trn2      v2.4s, v8.4s, v10.4s\n    trn1      v1.4s, v9.4s, v11.4s\n    trn2      v3.4s, v9.4s, v11.4s\n    trn1      v4.4s, v12.4s, v14.4s\n    trn2      v6.4s, v12.4s, v14.4s\n    trn1      v5.4s, v13.4s, v15.4s\n    trn2      v7.4s, v13.4s, v15.4s\n\n    trn1      v8.2d, v0.2d, v4.2d       //0\n    trn2      v12.2d, v0.2d, v4.2d      //1\n    trn1      v9.2d, v1.2d, v5.2d       //2\n    trn2      v13.2d, v1.2d, v5.2d      //3\n    trn1      v10.2d, v2.2d, v6.2d      //4\n    trn2      v14.2d, v2.2d, v6.2d      //5\n    trn1      v11.2d, v3.2d, v7.2d      //6\n    trn2      v15.2d, v3.2d, v7.2d      //7\n\n    // 1 3 5 6 7\n    sshr      v16.8h, v9.8h, #1         //(pi2_tmp_ptr[1] >> 1)\n    sshr      v17.8h, v10.8h, #1        //(pi2_tmp_ptr[2] >> 1)\n    sshr      v18.8h, v11.8h, #1        //(pi2_tmp_ptr[3] >> 1)\n    sshr      v19.8h, v13.8h, #1        //(pi2_tmp_ptr[5] >> 1)\n    sshr      v20.8h, v14.8h, #1        //(pi2_tmp_ptr[6] >> 1)\n    sshr      v21.8h, v15.8h, #1        //(pi2_tmp_ptr[7] >> 1)\n\n    add       v0.8h, v8.8h, v12.8h      // i_y0 = (pi2_tmp_ptr[0] + pi2_tmp_ptr[4] );\n    sub       v2.8h, v8.8h, v12.8h      // i_y2 = (pi2_tmp_ptr[0] - pi2_tmp_ptr[4] );\n\n    sub       v4.8h, v17.8h, v14.8h     //i_y4 = ((pi2_tmp_ptr[2] >> 1) - pi2_tmp_ptr[6] );\n    add       v6.8h, v10.8h, v20.8h     //i_y6 = (pi2_tmp_ptr[2] + (pi2_tmp_ptr[6] >> 1));\n\n    //-w3 + w5\n    ssubl     v22.4s, v13.4h, v11.4h\n    ssubl2    v23.4s, v13.8h, v11.8h\n    //w3 + w5\n    saddl     v24.4s, v13.4h, v11.4h\n    saddl2    v25.4s, v13.8h, v11.8h\n    //-w1 + w7\n    ssubl     v26.4s, v15.4h, v9.4h\n    ssubl2    v27.4s, v15.8h, v9.8h\n    //w1 + w7\n    saddl     v28.4s, v15.4h, v9.4h\n    saddl2    v29.4s, v15.8h, v9.8h\n\n    //-w3 + w5 - w7\n    ssubw     v22.4s, v22.4s, v15.4h\n    ssubw2    v23.4s, v23.4s, v15.8h\n    //w3 + w5 + w1\n    saddw     v24.4s, v24.4s, v9.4h\n    saddw2    v25.4s, v25.4s, v9.8h\n    //-w1 + w7 + w5\n    saddw     v26.4s, v26.4s, v13.4h\n    saddw2    v27.4s, v27.4s, v13.8h\n    //w1 + w7 - w3\n    ssubw     v28.4s, v28.4s, v11.4h\n    ssubw2    v29.4s, v29.4s, v11.8h\n\n    //-w3 + w5 - w7 - (w7 >> 1)\n    ssubw     v22.4s, v22.4s, v21.4h\n    ssubw2    v23.4s, v23.4s, v21.8h\n    //w3 + w5 + w1 + (w1 >> 1)\n    saddw     v24.4s, v24.4s, v16.4h\n    saddw2    v25.4s, v25.4s, v16.8h\n    //-w1 + w7 + w5 + (w5 >> 1)\n    saddw     v26.4s, v26.4s, v19.4h\n    saddw2    v27.4s, v27.4s, v19.8h\n    //w1 + w7 - w3 - (w3 >> 1)\n    ssubw     v28.4s, v28.4s, v18.4h\n    ssubw2    v29.4s, v29.4s, v18.8h\n\n    xtn       v1.4h, v22.4s\n    xtn2      v1.8h, v23.4s\n    xtn       v3.4h, v28.4s\n    xtn2      v3.8h, v29.4s\n    xtn       v5.4h, v26.4s\n    xtn2      v5.8h, v27.4s\n    xtn       v7.4h, v24.4s\n    xtn2      v7.8h, v25.4s\n\n    sshr      v16.8h, v1.8h, #2         //(y1 >> 2)\n    sshr      v17.8h, v3.8h, #2         //(y3 >> 2)\n    sshr      v18.8h, v5.8h, #2         //(y5 >> 2)\n    sshr      v19.8h, v7.8h, #2         //(y7 >> 2)\n\n    add       v8.8h, v0.8h, v6.8h\n    add       v9.8h, v1.8h, v19.8h\n    add       v10.8h, v2.8h, v4.8h\n    add       v11.8h, v3.8h, v18.8h\n    sub       v12.8h, v2.8h, v4.8h\n    sub       v13.8h, v17.8h, v5.8h\n    sub       v14.8h, v0.8h, v6.8h\n    sub       v15.8h, v7.8h, v16.8h\n\n    add       v0.8h, v8.8h, v15.8h\n    add       v1.8h, v10.8h, v13.8h\n    add       v2.8h, v12.8h, v11.8h\n    add       v3.8h, v14.8h, v9.8h\n    sub       v4.8h, v14.8h, v9.8h\n    sub       v5.8h, v12.8h, v11.8h\n    sub       v6.8h, v10.8h, v13.8h\n    sub       v7.8h, v8.8h, v15.8h\n\n    subs      x8, x8, #1\n    bne       trans_1x8_1d\n\n    ld1       {v22.8b}, [x1], x3\n    ld1       {v23.8b}, [x1], x3\n    ld1       {v24.8b}, [x1], x3\n    ld1       {v25.8b}, [x1], x3\n    ld1       {v26.8b}, [x1], x3\n    ld1       {v27.8b}, [x1], x3\n    ld1       {v28.8b}, [x1], x3\n    ld1       {v29.8b}, [x1]\n\n    srshr     v0.8h, v0.8h, #6\n    srshr     v1.8h, v1.8h, #6\n    srshr     v2.8h, v2.8h, #6\n    srshr     v3.8h, v3.8h, #6\n    srshr     v4.8h, v4.8h, #6\n    srshr     v5.8h, v5.8h, #6\n    srshr     v6.8h, v6.8h, #6\n    srshr     v7.8h, v7.8h, #6\n\n    uaddw     v0.8h, v0.8h, v22.8b\n    uaddw     v1.8h, v1.8h, v23.8b\n    uaddw     v2.8h, v2.8h, v24.8b\n    uaddw     v3.8h, v3.8h, v25.8b\n    uaddw     v4.8h, v4.8h, v26.8b\n    uaddw     v5.8h, v5.8h, v27.8b\n    uaddw     v6.8h, v6.8h, v28.8b\n    uaddw     v7.8h, v7.8h, v29.8b\n\n    sqxtun    v0.8b, v0.8h\n    sqxtun    v1.8b, v1.8h\n    sqxtun    v2.8b, v2.8h\n    sqxtun    v3.8b, v3.8h\n    sqxtun    v4.8b, v4.8h\n    sqxtun    v5.8b, v5.8h\n    sqxtun    v6.8b, v6.8h\n    sqxtun    v7.8b, v7.8h\n\n    st1       {v0.8b}, [x2], x4\n    st1       {v1.8b}, [x2], x4\n    st1       {v2.8b}, [x2], x4\n    st1       {v3.8b}, [x2], x4\n    st1       {v4.8b}, [x2], x4\n    st1       {v5.8b}, [x2], x4\n    st1       {v6.8b}, [x2], x4\n    st1       {v7.8b}, [x2]\n\n    pop_v_regs\n    ret\n\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_iquant_itrans_recon_dc_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n// *******************************************************************************\n// * @file\n// *  ih264_iquant_itrans_recon_dc_av8.s\n// *\n// * @brief\n// *  Contains function definitions for single stage  inverse transform\n// *\n// * @author\n// *  Mohit\n// *\n// * @par List of Functions:\n// *  - ih264_iquant_itrans_recon_4x4_dc_av8()\n// *     - ih264_iquant_itrans_recon_8x8_dc_av8()\n// *  - ih264_iquant_itrans_recon_chroma_4x4_dc_av8()\n// *\n// * @remarks\n// *  None\n// *\n// *******************************************************************************\n//*/\n\n\n.include \"ih264_neon_macros.s\"\n\n\n///**\n// *******************************************************************************\n// *\n// * @brief\n// *  This function performs inverse quant and Inverse transform type Ci4 for 4*4 block\n// *     for dc input pattern only, i.e. only the (0,0) element of the input 4x4 block is\n// *  non-zero. For complete function, refer ih264_iquant_itrans_recon_a9.s\n// *\n// * @par Description:\n// *  Performs inverse transform Ci4 and adds the residue to get the\n// *  reconstructed block\n// *\n// * @param[in] pi2_src\n// *  Input 4x4 coefficients\n// *\n// * @param[in] pu1_pred\n// *  Prediction 4x4 block\n// *\n// * @param[out] pu1_out\n// *  Output 4x4 block\n// *\n// * @param[in] u4_qp_div_6\n// *     QP\n// *\n// * @param[in] pu2_weigh_mat\n// * Pointer to weight matrix\n// *\n// * @param[in] pred_strd,\n// *  Prediction stride\n// *\n// * @param[in] out_strd\n// *  Output Stride\n// *\n// *@param[in] pi2_tmp\n// * temporary buffer of size 1*16\n// *\n// * @param[in] pu2_iscal_mat\n// * Pointer to the inverse quantization matrix\n// *\n// * @returns  Void\n// *\n// * @remarks\n// *  None\n// *\n// *******************************************************************************\n// */\n//void ih264_iquant_itrans_recon_4x4_dc(WORD16 *pi2_src,\n//                                    UWORD8 *pu1_pred,\n//                                    UWORD8 *pu1_out,\n//                                    WORD32 pred_strd,\n//                                    WORD32 out_strd,\n//                                    const UWORD16 *pu2_iscal_mat,\n//                                    const UWORD16 *pu2_weigh_mat,\n//                                    UWORD32 u4_qp_div_6,\n//                                    WORD32 *pi4_tmp,\n//                                    WORD32 iq_start_idx\n//                                   WORD16 *pi2_dc_ld_addr)\n//**************Variables Vs Registers*****************************************\n//x0 => *pi2_src\n//x1 => *pu1_pred\n//x2 => *pu1_out\n//w3 =>  pred_strd\n//w4 =>  out_strd\n//x5 => *pu2_iscal_mat\n//x6 => *pu2_weigh_mat\n//w7 =>  u4_qp_div_6\n//   =>  pi4_tmp\n//   =>  iq_start_idx\n//   =>  pi2_dc_ld_addr\n\n.text\n.p2align 2\n\n    .global ih264_iquant_itrans_recon_4x4_dc_av8\nih264_iquant_itrans_recon_4x4_dc_av8:\n\n    sxtw      x3, w3\n    sxtw      x4, w4\n    ldr       w8, [sp, #8]              //Loads iq_start_idx\n    subs      w8, w8, #1                // if x8 == 1 => intra case , so result of subtraction is zero and z flag is set\n\n    ldr       x10, [sp, #16]            //Load alternate dc address\n    push_v_regs\n    dup       v30.4s, w7                //Populate the u4_qp_div_6 in Q15\n\n\n    bne       donot_use_pi2_dc_ld_addr_luma_dc\n    ld1       {v0.h}[0], [x10]\ndonot_use_pi2_dc_ld_addr_luma_dc:\n\n    beq       donot_use_pi2_src_luma_dc\n    ld1       {v0.h}[0], [x5]\n    ld1       {v1.h}[0], [x6]\n    ld1       {v2.h}[0], [x0]\n    mul       v0.4h, v1.4h, v0.4h\n    smull     v0.4s, v0.4h, v2.4h\n    sshl      v0.4s, v0.4s, v30.4s\n    sqrshrn   v0.4h, v0.4s, #4\ndonot_use_pi2_src_luma_dc:\n\n\n    dup       v0.8h, v0.h[0]\n    srshr     v0.8h, v0.8h, #6\n\n    ld1       {v1.s}[0], [x1], x3\n    ld1       {v1.s}[1], [x1], x3\n    ld1       {v2.s}[0], [x1], x3\n    ld1       {v2.s}[1], [x1]\n\n    uxtl      v1.8h, v1.8b\n    uxtl      v2.8h, v2.8b\n\n    add       v1.8h, v0.8h, v1.8h\n    add       v2.8h, v0.8h, v2.8h\n\n    sqxtun    v1.8b, v1.8h\n    sqxtun    v2.8b, v2.8h\n\n    st1       {v1.s}[0], [x2], x4\n    st1       {v1.s}[1], [x2], x4\n    st1       {v2.s}[0], [x2], x4\n    st1       {v2.s}[1], [x2]\n    pop_v_regs\n    ret\n\n// /*\n// ********************************************************************************\n// *\n// * @brief This function reconstructs a 4x4 sub block from quantized resiude and\n// * prediction buffer if only dc value is present for residue\n// *\n// * @par Description:\n// *  The quantized residue is first inverse quantized,\n// *  This inverse quantized content is added to the prediction buffer to recon-\n// *  struct the end output\n// *\n// * @param[in] pi2_src\n// *  quantized dc coeffiient\n// *\n// * @param[in] pu1_pred\n// *  prediction 4x4 block in interleaved format\n// *\n// * @param[in] pred_strd,\n// *  Prediction buffer stride in interleaved format\n// *\n// * @param[in] out_strd\n// *  recon buffer Stride\n// *\n// * @returns none\n// *\n// * @remarks none\n// *\n// *******************************************************************************\n// */\n// void ih264_iquant_itrans_recon_chroma_4x4_dc(WORD16 *pi2_src,\n//                                             UWORD8 *pu1_pred,\n//                                             UWORD8 *pu1_out,\n//                                             WORD32 pred_strd,\n//                                             WORD32 out_strd,\n//                                             const UWORD16 *pu2_iscal_mat,\n//                                             const UWORD16 *pu2_weigh_mat,\n//                                             UWORD32 u4_qp_div_6,\n//                                             WORD16 *pi2_tmp,\n//                                             WORD16 *pi2_dc_src)\n// Register Usage\n// x0 : pi2_src\n// x1 : pu1_pred\n// x2 : pu1_out\n// w3 : pred_strd\n// w4 : out_strd\n// x5 : pu2_iscal_mat\n// x6 : pu2_weigh_mat\n// w7 : u4_qp_div_6\n//    : pi2_tmp\n//    : pi2_dc_src\n// Neon registers d0-d7, d16-d30 are used\n// No need for pushing  arm and neon registers\n\n\n    .global ih264_iquant_itrans_recon_chroma_4x4_dc_av8\nih264_iquant_itrans_recon_chroma_4x4_dc_av8:\n\n    sxtw      x3, w3\n    sxtw      x4, w4\n    ldr       x0, [sp, #8]\n    push_v_regs\n    ld1       {v0.h}[0], [x0]\n    dup       v0.8h, v0.h[0]\n    srshr     v0.8h, v0.8h, #6\n\n\n    //backup pu1_out\n    mov       x0, x2\n\n    //nop       v3.16b                            //dummy for deinterleaving\n    movi      v31.8h, #0x00ff           //mask for interleaving [copy lower 8 bits]\n\n    ld1       {v1.d}[0], [x1], x3\n    ld1       {v1.d}[1], [x1], x3\n    ld1       {v2.d}[0], [x1], x3\n    ld1       {v2.d}[1], [x1], x3\n\n    ld1       {v11.d}[0], [x2], x4      //load pu1_out for interleaving\n    ld1       {v11.d}[1], [x2], x4\n    ld1       {v12.d}[0], [x2], x4\n    ld1       {v12.d}[1], [x2]\n\n    uzp1      v1.16b, v1.16b, v3.16b\n    uzp1      v2.16b, v2.16b, v3.16b\n\n    uaddw     v1.8h, v0.8h, v1.8b\n    uaddw     v2.8h, v0.8h, v2.8b\n\n    sqxtun    v1.8b, v1.8h\n    sqxtun    v2.8b, v2.8h\n\n    uxtl      v1.8h, v1.8b\n    uxtl      v2.8h, v2.8b\n\n    bit       v11.16b, v1.16b, v31.16b\n    bit       v12.16b, v2.16b, v31.16b\n\n    st1       {v11.d}[0], [x0], x4\n    st1       {v11.d}[1], [x0], x4\n    st1       {v12.d}[0], [x0], x4\n    st1       {v12.d}[1], [x0]\n    pop_v_regs\n    ret\n\n///*\n// *******************************************************************************\n// *\n// * //brief\n// *  This function performs inverse quant and Inverse transform type Ci4 for 8*8 block\n// *   [Only for Dc coeff]\n// * //par Description:\n// *  Performs inverse transform Ci8 and adds the residue to get the\n// *  reconstructed block\n// *\n// * //param[in] pi2_src\n// *  Input 4x4 coefficients\n// *\n// * //param[in] pu1_pred\n// *  Prediction 4x4 block\n// *\n// * //param[out] pu1_out\n// *  Output 4x4 block\n// *\n// * //param[in] u4_qp_div_6\n// *     QP\n// *\n// * //param[in] pu2_weigh_mat\n// * Pointer to weight matrix\n// *\n// * //param[in] pred_strd,\n// *  Prediction stride\n// *\n// * //param[in] out_strd\n// *  Output Stride\n// *\n// *//param[in] pi2_tmp\n// * temporary buffer of size 1*64\n// *\n// * //param[in] pu2_iscal_mat\n// * Pointer to the inverse quantization matrix\n// *\n// * //returns  Void\n// *\n// * //remarks\n// *  None\n// *\n// *******************************************************************************\n// */\n//void ih264_iquant_itrans_recon_dc_8x8(WORD16 *pi2_src,\n//                                   UWORD8 *pu1_pred,\n//                                   UWORD8 *pu1_out,\n//                                   WORD32 pred_strd,\n//                                   WORD32 out_strd,\n//                                   const UWORD16 *pu2_iscal_mat,\n//                                   const UWORD16 *pu2_weigh_mat,\n//                                   UWORD32 u4_qp_div_6,\n//                                   WORD32 *pi4_tmp,\n//                                   WORD32 iq_start_idx\n//                                   WORD16 *pi2_dc_ld_addr)\n//**************Variables Vs Registers*****************************************\n//x0       => *pi2_src\n//x1       => *pu1_pred\n//x2       => *pu1_out\n//w3       =>  pred_strd\n//w4       =>  out_strd\n//x5       =>  *pu2_iscal_mat\n//x6       =>  *pu2_weigh_mat\n//w7       =>  u4_qp_div_6\n//NOT USED =>  pi4_tmp\n//NOT USED =>  iq_start_idx\n//NOT USED =>  pi2_dc_ld_addr\n\n    .global ih264_iquant_itrans_recon_8x8_dc_av8\nih264_iquant_itrans_recon_8x8_dc_av8:\n\n    push_v_regs\n    sxtw      x3, w3\n    sxtw      x4, w4\n\n    ld1       {v1.h}[0], [x5]\n    ld1       {v2.h}[0], [x6]\n    ld1       {v0.h}[0], [x0]\n    dup       v3.4s, w7\n\n\n    mul       v1.8h, v1.8h, v2.8h\n    smull     v0.4s, v0.4h, v1.4h\n    sshl      v0.4s, v0.4s, v3.4s\n\n    sqrshrn   v0.4h, v0.4s, #6\n    srshr     v0.8h, v0.8h, #6\n    dup       v0.8h, v0.h[0]\n\n    ld1       {v22.8b}, [x1], x3\n    ld1       {v23.8b}, [x1], x3\n    ld1       {v24.8b}, [x1], x3\n    ld1       {v25.8b}, [x1], x3\n    ld1       {v26.8b}, [x1], x3\n    ld1       {v27.8b}, [x1], x3\n    ld1       {v28.8b}, [x1], x3\n    ld1       {v29.8b}, [x1]\n\n    uaddw     v1.8h, v0.8h, v22.8b\n    uaddw     v2.8h, v0.8h, v23.8b\n    uaddw     v3.8h, v0.8h, v24.8b\n    uaddw     v8.8h, v0.8h, v25.8b\n    uaddw     v9.8h, v0.8h, v26.8b\n    uaddw     v10.8h, v0.8h, v27.8b\n    uaddw     v11.8h, v0.8h, v28.8b\n    uaddw     v12.8h, v0.8h, v29.8b\n\n    sqxtun    v1.8b, v1.8h\n    sqxtun    v2.8b, v2.8h\n    sqxtun    v3.8b, v3.8h\n    sqxtun    v8.8b, v8.8h\n    sqxtun    v9.8b, v9.8h\n    sqxtun    v10.8b, v10.8h\n    sqxtun    v11.8b, v11.8h\n    sqxtun    v12.8b, v12.8h\n\n    st1       {v1.8b}, [x2], x4\n    st1       {v2.8b}, [x2], x4\n    st1       {v3.8b}, [x2], x4\n    st1       {v8.8b}, [x2], x4\n    st1       {v9.8b}, [x2], x4\n    st1       {v10.8b}, [x2], x4\n    st1       {v11.8b}, [x2], x4\n    st1       {v12.8b}, [x2]\n\n    pop_v_regs\n    ret\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_mem_fns_neon_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n// *******************************************************************************\n// * @file\n// *  ih264_mem_fns_neon.s\n// *\n// * @brief\n// *  Contains function definitions for memory manipulation\n// *\n// * @author\n// *     Naveen SR\n// *\n// * @par List of Functions:\n// *  - ih264_memcpy_av8()\n// *  - ih264_memcpy_mul_8_av8()\n// *  - ih264_memset_mul_8_av8()\n// *  - ih264_memset_16bit_mul_8_av8()\n// *  - ih264_memset_16bit_av8()\n// *\n// * @remarks\n// *  None\n// *\n// *******************************************************************************\n//*/\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*   memcpy of a 1d array\n//*\n//* @par Description:\n//*   Does memcpy of 8bit data from source to destination for 8,16 or 32 number of bytes\n//*\n//* @param[in] pu1_dst\n//*  UWORD8 pointer to the destination\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[in] num_bytes\n//*  number of bytes to copy\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//void ih264_memcpy_mul_8(UWORD8 *pu1_dst,\n//                      UWORD8 *pu1_src,\n//                      UWORD32 num_bytes)\n//**************Variables Vs Registers*************************\n//    x0 => *pu1_dst\n//    x1 => *pu1_src\n//    w2 => num_bytes\n\n\n\n\n\n    .global ih264_memcpy_mul_8_av8\n\nih264_memcpy_mul_8_av8:\n\nloop_neon_memcpy_mul_8:\n    // Memcpy 8 bytes\n    ld1       {v0.8b}, [x1], #8\n    st1       {v0.8b}, [x0], #8\n\n    subs      w2, w2, #8\n    bne       loop_neon_memcpy_mul_8\n    ret\n\n\n\n//*******************************************************************************\n//*/\n//void ih264_memcpy(UWORD8 *pu1_dst,\n//                  UWORD8 *pu1_src,\n//                  UWORD32 num_bytes)\n//**************Variables Vs Registers*************************\n//    x0 => *pu1_dst\n//    x1 => *pu1_src\n//    w2 => num_bytes\n\n\n\n    .global ih264_memcpy_av8\n\nih264_memcpy_av8:\n    subs      w2, w2, #8\n    blt       arm_memcpy\nloop_neon_memcpy:\n    // Memcpy 8 bytes\n    ld1       {v0.8b}, [x1], #8\n    st1       {v0.8b}, [x0], #8\n\n    subs      w2, w2, #8\n    bge       loop_neon_memcpy\n    cmn       w2, #8\n    beq       end_func1\n\narm_memcpy:\n    add       w2, w2, #8\n\nloop_arm_memcpy:\n    ldrb      w3, [x1], #1\n    strb      w3, [x0], #1\n    subs      w2, w2, #1\n    bne       loop_arm_memcpy\n    ret\nend_func1:\n    ret\n\n\n//void ih264_memset_mul_8(UWORD8 *pu1_dst,\n//                       UWORD8 value,\n//                       UWORD32 num_bytes)\n//**************Variables Vs Registers*************************\n//    x0 => *pu1_dst\n//    x1 => value\n//    x2 => num_bytes\n\n\n    .global ih264_memset_mul_8_av8\n\nih264_memset_mul_8_av8:\n\n// Assumptions: numbytes is either 8, 16 or 32\n    dup       v0.8b, w1\nloop_memset_mul_8:\n    // Memset 8 bytes\n    st1       {v0.8b}, [x0], #8\n\n    subs      w2, w2, #8\n    bne       loop_memset_mul_8\n\n    ret\n\n\n//void ih264_memset(UWORD8 *pu1_dst,\n//                       UWORD8 value,\n//                       UWORD32 num_bytes)\n//**************Variables Vs Registers*************************\n//    x0 => *pu1_dst\n//    w1 => value\n//    w2 => num_bytes\n\n\n\n    .global ih264_memset_av8\n\nih264_memset_av8:\n    subs      w2, w2, #8\n    blt       arm_memset\n    dup       v0.8b, w1\nloop_neon_memset:\n    // Memcpy 8 bytes\n    st1       {v0.8b}, [x0], #8\n\n    subs      w2, w2, #8\n    bge       loop_neon_memset\n    cmn       w2, #8\n    beq       end_func2\n\narm_memset:\n    add       w2, w2, #8\n\nloop_arm_memset:\n    strb      w1, [x0], #1\n    subs      w2, w2, #1\n    bne       loop_arm_memset\n    ret\nend_func2:\n    ret\n\n\n\n\n\n//void ih264_memset_16bit_mul_8(UWORD16 *pu2_dst,\n//                                      UWORD16 value,\n//                                      UWORD32 num_words)\n//**************Variables Vs Registers*************************\n//    x0 => *pu2_dst\n//    w1 => value\n//    w2 => num_words\n\n\n    .global ih264_memset_16bit_mul_8_av8\n\nih264_memset_16bit_mul_8_av8:\n\n// Assumptions: num_words is either 8, 16 or 32\n\n    // Memset 8 words\n    dup       v0.4h, w1\nloop_memset_16bit_mul_8:\n    st1       {v0.4h}, [x0], #8\n    st1       {v0.4h}, [x0], #8\n\n    subs      w2, w2, #8\n    bne       loop_memset_16bit_mul_8\n\n    ret\n\n\n\n//void ih264_memset_16bit(UWORD16 *pu2_dst,\n//                       UWORD16 value,\n//                       UWORD32 num_words)\n//**************Variables Vs Registers*************************\n//    x0 => *pu2_dst\n//    w1 => value\n//    w2 => num_words\n\n\n\n    .global ih264_memset_16bit_av8\n\nih264_memset_16bit_av8:\n    subs      w2, w2, #8\n    blt       arm_memset_16bit\n    dup       v0.4h, w1\nloop_neon_memset_16bit:\n    // Memset 8 words\n    st1       {v0.4h}, [x0], #8\n    st1       {v0.4h}, [x0], #8\n\n    subs      w2, w2, #8\n    bge       loop_neon_memset_16bit\n    cmn       w2, #8\n    beq       end_func3\n\narm_memset_16bit:\n    add       w2, w2, #8\n\nloop_arm_memset_16bit:\n    strh      w1, [x0], #2\n    subs      w2, w2, #1\n    bne       loop_arm_memset_16bit\n    ret\n\nend_func3:\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_neon_macros.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n//*******************************************************************************\n\n\n.macro push_v_regs\n    stp       d8, d9, [sp, #-16]!\n    stp       d10, d11, [sp, #-16]!\n    stp       d12, d13, [sp, #-16]!\n    stp       d14, d15, [sp, #-16]!\n.endm\n.macro pop_v_regs\n    ldp       d14, d15, [sp], #16\n    ldp       d12, d13, [sp], #16\n    ldp       d10, d11, [sp], #16\n    ldp       d8, d9, [sp], #16\n.endm\n\n.macro swp reg1, reg2\n    eor       \\reg1, \\reg1, \\reg2\n    eor       \\reg2, \\reg1, \\reg2\n    eor       \\reg1, \\reg1, \\reg2\n.endm\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_padding_neon_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n// *******************************************************************************\n// * @file\n// *  ih264_padding_neon.s\n// *\n// * @brief\n// *  Contains function definitions padding\n// *\n// * @author\n// *     Ittiam\n// *\n// * @par List of Functions:\n// *  - ih264_pad_top_av8()\n// *  - ih264_pad_left_luma_av8()\n// *  - ih264_pad_left_chroma_av8()\n// *  - ih264_pad_right_luma_av8()\n// *  - ih264_pad_right_chroma_av8()\n// *\n// * @remarks\n// *  None\n// *\n// *******************************************************************************\n//*/\n\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n///**\n//*******************************************************************************\n//*\n//* @brief pad at the top of a 2d array\n//*\n//* @par Description:\n//*  The top row of a 2d array is replicated for pad_size times at the top\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @param[in] pad_size\n//*  integer -padding size of the array\n//*\n//* @returns none\n//*\n//* @remarks none\n//*\n//*******************************************************************************\n//*/\n//void ih264_pad_top(UWORD8 *pu1_src,\n//                   WORD32 src_strd,\n//                   WORD32 wd,\n//                   WORD32 pad_size)\n//**************Variables Vs Registers*************************\n//    x0 => *pu1_src\n//    w1 => src_strd\n//    w2 => wd\n//    w3 => pad_size\n\n    .global ih264_pad_top_av8\n\nih264_pad_top_av8:\n\n    // STMFD sp!, {x4-x11,x14}                //stack stores the values of the arguments\n    push_v_regs\n    sxtw      x1, w1\n    stp       x19, x20, [sp, #-16]!\n\n    sub       x5, x0, x1\n    neg       x6, x1\n\nloop_neon_memcpy_mul_16:\n    // Load 16 bytes\n    ld1       {v0.8b, v1.8b}, [x0], #16\n    mov       x4, x5\n    mov       w7, w3\n    add       x5, x5, #16\n\nloop_neon_pad_top:\n    st1       {v0.8b, v1.8b}, [x4], x6\n    subs      w7, w7, #1\n    bne       loop_neon_pad_top\n\n    subs      w2, w2, #16\n    bne       loop_neon_memcpy_mul_16\n\n    // LDMFD sp!,{x4-x11,pc}                //Reload the registers from SP\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*   Padding (luma block) at the left of a 2d array\n//*\n//* @par Description:\n//*   The left column of a 2d array is replicated for pad_size times at the left\n//*\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @param[in] pad_size\n//*  integer -padding size of the array\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//#if PAD_LEFT_LUMA == C\n//void ih264_pad_left_luma(UWORD8 *pu1_src,\n//                        WORD32 src_strd,\n//                        WORD32 ht,\n//                        WORD32 pad_size)\n//**************Variables Vs Registers*************************\n//    x0 => *pu1_src\n//    w1 => src_strd\n//    w2 => ht\n//    w3 => pad_size\n\n\n\n    .global ih264_pad_left_luma_av8\n\nih264_pad_left_luma_av8:\n\n    // STMFD sp!, {x4-x11,x14}                //stack stores the values of the arguments\n    push_v_regs\n    sxtw      x1, w1\n    sxtw      x3, w3\n    stp       x19, x20, [sp, #-16]!\n\n\n    sub       x4, x0, x3\n    sub       x6, x1, #16\n    subs      x5, x3, #16\n    bne       loop_32\nloop_16:                                //  /*hard coded for width=16  ,height =8,16*/\n    ldrb      w8, [x0]\n    add       x0, x0, x1\n    ldrb      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.16b, w8\n    ldrb      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], x1        // 16 bytes store\n    dup       v2.16b, w9\n    st1       {v2.16b}, [x4], x1        // 16 bytes store\n    ldrb      w11, [x0]\n    add       x0, x0, x1\n    dup       v4.16b, w10\n    dup       v6.16b, w11\n    st1       {v4.16b}, [x4], x1        // 16 bytes store\n    ldrb      w8, [x0]\n    add       x0, x0, x1\n    st1       {v6.16b}, [x4], x1        // 16 bytes store\n    ldrb      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.16b, w8\n    ldrb      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], x1        // 16 bytes store\n    dup       v2.16b, w9\n    ldrb      w11, [x0]\n    add       x0, x0, x1\n    st1       {v2.16b}, [x4], x1        // 16 bytes store\n    dup       v4.16b, w10\n    dup       v6.16b, w11\n    subs      w2, w2, #8\n    st1       {v4.16b}, [x4], x1        // 16 bytes store\n    st1       {v6.16b}, [x4], x1        // 16 bytes store\n    bne       loop_16\n    b         end_func\n\nloop_32:                                //  /*hard coded for width=32 ,height =8,16*/\n    ldrb      w8, [x0]\n    add       x0, x0, x1\n    ldrb      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.16b, w8\n    ldrb      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], #16       // 16 bytes store\n    dup       v2.16b, w9\n    st1       {v0.16b}, [x4], x6\n    st1       {v2.16b}, [x4], #16       // 16 bytes store\n    dup       v4.16b, w10\n    st1       {v2.16b}, [x4], x6        // 16 bytes store\n    ldrb      w11, [x0]\n    add       x0, x0, x1\n    st1       {v4.16b}, [x4], #16       // 16 bytes store\n    dup       v6.16b, w11\n    st1       {v4.16b}, [x4], x6        // 16 bytes store\n    ldrb      w8, [x0]\n    add       x0, x0, x1\n    st1       {v6.16b}, [x4], #16       // 16 bytes store\n    dup       v0.16b, w8\n    ldrb      w9, [x0]\n    add       x0, x0, x1\n    st1       {v6.16b}, [x4], x6        // 16 bytes store\n    ldrb      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], #16       // 16 bytes store\n    dup       v2.16b, w9\n    st1       {v0.16b}, [x4], x6        // 16 bytes store\n    ldrb      w11, [x0]\n    add       x0, x0, x1\n    st1       {v2.16b}, [x4], #16       // 16 bytes store\n    dup       v4.16b, w10\n    st1       {v2.16b}, [x4], x6        // 16 bytes store\n    st1       {v4.16b}, [x4], #16       // 16 bytes store\n    dup       v6.16b, w11\n    st1       {v4.16b}, [x4], x6        // 16 bytes store\n    subs      w2, w2, #8\n    st1       {v6.16b}, [x4], #16       // 16 bytes store\n    st1       {v6.16b}, [x4], x6        // 16 bytes store\n    bne       loop_32\n\n\n\nend_func:\n    // LDMFD sp!,{x4-x11,pc}                //Reload the registers from SP\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//*   Padding (chroma block) at the left of a 2d array\n//*\n//* @par Description:\n//*   The left column of a 2d array is replicated for pad_size times at the left\n//*\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array (each colour component)\n//*\n//* @param[in] pad_size\n//*  integer -padding size of the array\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//#if PAD_LEFT_CHROMA == C\n//void ih264_pad_left_chroma(UWORD8 *pu1_src,\n//                            WORD32 src_strd,\n//                            WORD32 ht,\n//                            WORD32 pad_size)\n//{\n//    x0 => *pu1_src\n//    w1 => src_strd\n//    w2 => ht\n//    w3 => pad_size\n\n\n\n    .global ih264_pad_left_chroma_av8\n\nih264_pad_left_chroma_av8:\n\n    // STMFD sp!, {x4-x11, x14}                //stack stores the values of the arguments\n    push_v_regs\n    sxtw      x1, w1\n    sxtw      x3, w3\n    stp       x19, x20, [sp, #-16]!\n\n    sub       x4, x0, x3\n    sub       x6, x1, #16\n\n\nloop_32_l_c:                            //  /*hard coded for width=32  ,height =4,8,12*/\n    ldrh      w8, [x0]\n    add       x0, x0, x1\n    ldrh      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.8h, w8\n    ldrh      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], #16       // 16 bytes store\n    dup       v2.8h, w9\n    st1       {v0.16b}, [x4], x6        // 16 bytes store\n    ldrh      w11, [x0]\n    add       x0, x0, x1\n    st1       {v2.16b}, [x4], #16       // 16 bytes store\n    dup       v4.8h, w10\n    st1       {v2.16b}, [x4], x6        // 16 bytes store\n    dup       v6.8h, w11\n    st1       {v4.16b}, [x4], #16       // 16 bytes store\n    st1       {v4.16b}, [x4], x6        // 16 bytes store\n    subs      w2, w2, #4\n    st1       {v6.16b}, [x4], #16       // 16 bytes store\n    st1       {v6.16b}, [x4], x6        // 16 bytes store\n\n\n    beq       end_func_l_c              ///* Branching when ht=4*/\n\n    ldrh      w8, [x0]\n    add       x0, x0, x1\n    ldrh      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.8h, w8\n    ldrh      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], #16       // 16 bytes store\n    dup       v2.8h, w9\n    st1       {v0.16b}, [x4], x6\n    ldrh      w11, [x0]\n    add       x0, x0, x1\n    st1       {v2.16b}, [x4], #16       // 16 bytes store\n    dup       v4.8h, w10\n    st1       {v2.16b}, [x4], x6        // 16 bytes store\n    dup       v6.8h, w11\n    st1       {v4.16b}, [x4], #16       // 16 bytes store\n    st1       {v4.16b}, [x4], x6        // 16 bytes store\n    subs      w2, w2, #4\n    st1       {v6.16b}, [x4], #16       // 16 bytes store\n    st1       {v6.16b}, [x4], x6        // 16 bytes store\n\n    beq       end_func_l_c              ///* Branching when ht=8*/\n    bne       loop_32_l_c\n\n    ldrh      w8, [x0]\n    add       x0, x0, x1\n    ldrh      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.8h, w8\n    ldrh      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], #16       // 16 bytes store\n    dup       v2.8h, w9\n    st1       {v0.16b}, [x4], x6\n    ldrh      w11, [x0]\n    add       x0, x0, x1\n    st1       {v2.16b}, [x4], #16       // 16 bytes store\n    dup       v4.8h, w10\n    st1       {v2.16b}, [x4], x6        // 16 bytes store\n    dup       v6.8h, w11\n    st1       {v4.16b}, [x4], #16       // 16 bytes store\n    st1       {v4.16b}, [x4], x6        // 16 bytes store\n    st1       {v6.16b}, [x4], #16       // 16 bytes store\n    st1       {v6.16b}, [x4], x6        // 16 bytes store\n\nend_func_l_c:\n    // LDMFD sp!,{x4-x11,pc}                //Reload the registers from SP\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//* Padding (luma block) at the right of a 2d array\n//*\n//* @par Description:\n//* The right column of a 2d array is replicated for pad_size times at the right\n//*\n//*\n//* @param[in] pu1_src\n//*  UWORD8 pointer to the source\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @param[in] pad_size\n//*  integer -padding size of the array\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//#if PAD_RIGHT_LUMA == C\n//void ih264_pad_right_luma(UWORD8 *pu1_src,\n//                        WORD32 src_strd,\n//                        WORD32 ht,\n//                        WORD32 pad_size)\n//{\n//    WORD32 row;\n//\n//    for(row = 0; row < ht; row++)\n//    {\n//        memset(pu1_src, *(pu1_src -1), pad_size);\n//\n//        pu1_src += src_strd;\n//    }\n//}\n//\n//    x0 => *pu1_src\n//    w1 => src_strd\n//    w2 => ht\n//    w3 => pad_size\n\n\n\n    .global ih264_pad_right_luma_av8\n\nih264_pad_right_luma_av8:\n\n    // STMFD sp!, {x4-x11, x14}                //stack stores the values of the arguments\n    push_v_regs\n    sxtw      x1, w1\n    sxtw      x3, w3\n    stp       x19, x20, [sp, #-16]!\n\n    mov       x4, x0\n    sub       x6, x1, #16\n    sub       x0, x0, #1\n    subs      x5, x3, #16\n    bne       loop_32\nloop_16_r: //  /*hard coded for width=16  ,height =8,16*/\n    ldrb      w8, [x0]\n    add       x0, x0, x1\n    ldrb      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.16b, w8\n    ldrb      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], x1        // 16 bytes store\n    dup       v2.16b, w9\n    st1       {v2.16b}, [x4], x1        // 16 bytes store\n    ldrb      w11, [x0]\n    add       x0, x0, x1\n    dup       v4.16b, w10\n    dup       v6.16b, w11\n    st1       {v4.16b}, [x4], x1        // 16 bytes store\n    ldrb      w8, [x0]\n    add       x0, x0, x1\n    st1       {v6.16b}, [x4], x1        // 16 bytes store\n    ldrb      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.16b, w8\n    ldrb      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], x1        // 16 bytes store\n    dup       v2.16b, w9\n    ldrb      w11, [x0]\n    add       x0, x0, x1\n    st1       {v2.16b}, [x4], x1        // 16 bytes store\n    dup       v4.16b, w10\n    dup       v6.16b, w11\n    subs      w2, w2, #8\n    st1       {v4.16b}, [x4], x1        // 16 bytes store\n    st1       {v6.16b}, [x4], x1        // 16 bytes store\n    bne       loop_16_r\n    b         end_func_r\n\nloop_32_r:                              //  /*hard coded for width=32  ,height =8,16*/\n    ldrb      w8, [x0]\n    add       x0, x0, x1\n    ldrb      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.16b, w8\n    ldrb      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], #16       // 16 bytes store\n    dup       v2.16b, w9\n    st1       {v0.16b}, [x4], x6\n    st1       {v2.16b}, [x4], #16       // 16 bytes store\n    dup       v4.16b, w10\n    st1       {v2.16b}, [x4], x6        // 16 bytes store\n    ldrb      w11, [x0]\n    add       x0, x0, x1\n    st1       {v4.16b}, [x4], #16       // 16 bytes store\n    dup       v6.16b, w11\n    st1       {v4.16b}, [x4], x6        // 16 bytes store\n    ldrb      w8, [x0]\n    add       x0, x0, x1\n    st1       {v6.16b}, [x4], #16       // 16 bytes store\n    ldrb      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.16b, w8\n    st1       {v6.16b}, [x4], x6        // 16 bytes store\n    ldrb      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], #16       // 16 bytes store\n    dup       v2.16b, w9\n    st1       {v0.16b}, [x4], x6        // 16 bytes store\n    ldrb      w11, [x0]\n    add       x0, x0, x1\n    st1       {v2.16b}, [x4], #16       // 16 bytes store\n    dup       v4.16b, w10\n    st1       {v2.16b}, [x4], x6        // 16 bytes store\n    st1       {v4.16b}, [x4], #16       // 16 bytes store\n    dup       v6.16b, w11\n    st1       {v4.16b}, [x4], x6        // 16 bytes store\n    subs      w2, w2, #8\n    st1       {v6.16b}, [x4], #16       // 16 bytes store\n    st1       {v6.16b}, [x4], x6        // 16 bytes store\n    bne       loop_32_r\n\n\n\nend_func_r:\n    // LDMFD sp!,{x4-x11,pc}                //Reload the registers from SP\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n///**\n//*******************************************************************************\n//*\n//* @brief\n//;* Padding (chroma block) at the right of a 2d array\n//*\n//* @par Description:\n//* The right column of a 2d array is replicated for pad_size times at the right\n//*\n//*\n//* @param[in] pu1_src\n//;*  UWORD8 pointer to the source\n//*\n//* @param[in] src_strd\n//*  integer source stride\n//*\n//* @param[in] ht\n//;*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array (each colour component)\n//*\n//* @param[in] pad_size\n//*  integer -padding size of the array\n//*\n//* @param[in] ht\n//;*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//#if PAD_RIGHT_CHROMA == C\n//void ih264_pad_right_chroma(UWORD8 *pu1_src,\n//                        WORD32 src_strd,\n//                        WORD32 ht,\n//                        WORD32 pad_size)\n//    x0 => *pu1_src\n//    w1 => src_strd\n//    w2 => ht\n//    w3 => pad_size\n\n\n\n    .global ih264_pad_right_chroma_av8\n\nih264_pad_right_chroma_av8:\n\n    // STMFD sp!, {x4-x11, x14}                //stack stores the values of the arguments\n    push_v_regs\n    sxtw      x1, w1\n    sxtw      x3, w3\n    stp       x19, x20, [sp, #-16]!\n\n    mov       x4, x0\n    sub       x6, x1, #16\n    sub       x0, x0, #2\nloop_32_r_c: //  /*hard coded for width=32 ,height =8,4*/\n    ldrh      w8, [x0]\n    add       x0, x0, x1\n    ldrh      w9, [x0]\n    add       x0, x0, x1\n    dup       v0.8h, w8\n    ldrh      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], #16       // 16 bytes store\n    dup       v2.8h, w9\n    st1       {v0.16b}, [x4], x6\n    st1       {v2.16b}, [x4], #16       // 16 bytes store\n    dup       v4.8h, w10\n    st1       {v2.16b}, [x4], x6        // 16 bytes store\n    subs      w2, w2, #4\n    ldrh      w11, [x0]\n    add       x0, x0, x1\n    st1       {v4.16b}, [x4], #16       // 16 bytes store\n    dup       v6.8h, w11\n    st1       {v4.16b}, [x4], x6        // 16 bytes store\n    st1       {v6.16b}, [x4], #16       // 16 bytes store\n    st1       {v6.16b}, [x4], x6        // 16 bytes store\n\n    beq       end_func_r_c              ///* Branching when ht=4*/\n\n    ldrh      w8, [x0]\n    add       x0, x0, x1\n    dup       v0.8h, w8\n    ldrh      w9, [x0]\n    add       x0, x0, x1\n    ldrh      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], #16       // 16 bytes store\n    dup       v2.8h, w9\n    st1       {v0.16b}, [x4], x6        // 16 bytes store\n    ldrh      w11, [x0]\n    add       x0, x0, x1\n    st1       {v2.16b}, [x4], #16       // 16 bytes store\n    dup       v4.8h, w10\n    st1       {v2.16b}, [x4], x6        // 16 bytes store\n    st1       {v4.16b}, [x4], #16       // 16 bytes store\n    dup       v6.8h, w11\n    st1       {v4.16b}, [x4], x6        // 16 bytes store\n    subs      w2, w2, #4\n    st1       {v6.16b}, [x4], #16       // 16 bytes store\n    st1       {v6.16b}, [x4], x6        // 16 bytes store\n\n    beq       end_func_r_c              ///* Branching when ht=8*/\n    bne       loop_32_r_c\n    ldrh      w8, [x0]\n    add       x0, x0, x1\n    dup       v0.8h, w8\n    ldrh      w9, [x0]\n    add       x0, x0, x1\n    ldrh      w10, [x0]\n    add       x0, x0, x1\n    st1       {v0.16b}, [x4], #16       // 16 bytes store\n    dup       v2.8h, w9\n    st1       {v0.16b}, [x4], x6        // 16 bytes store\n    ldrh      w11, [x0]\n    add       x0, x0, x1\n    st1       {v2.16b}, [x4], #16       // 16 bytes store\n    dup       v4.8h, w10\n    st1       {v2.16b}, [x4], x6        // 16 bytes store\n    st1       {v4.16b}, [x4], #16       // 16 bytes store\n    dup       v6.8h, w11\n    st1       {v4.16b}, [x4], x6        // 16 bytes store\n    st1       {v6.16b}, [x4], #16       // 16 bytes store\n    st1       {v6.16b}, [x4], x6        // 16 bytes store\n\nend_func_r_c:\n    // LDMFD sp!,{x4-x11,pc}                //Reload the registers from SP\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_platform_macros.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_platform_macros.h\n*\n* @brief\n*  Platform specific Macro definitions used in the codec\n*\n* @author\n*  Ittiam\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n#ifndef _IH264_PLATFORM_MACROS_H_\n#define _IH264_PLATFORM_MACROS_H_\n\n#include <stdint.h>\n\n#ifndef  ARMV8\n\nstatic __inline WORD32 CLIP_U8(WORD32 x)\n{\n    asm(\"usat %0, #8, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_S8(WORD32 x)\n{\n    asm(\"ssat %0, #8, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_U10(WORD32 x)\n{\n    asm(\"usat %0, #10, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_S10(WORD32 x)\n{\n    asm(\"ssat %0, #10, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_U11(WORD32 x)\n{\n    asm(\"usat %0, #11, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_S11(WORD32 x)\n{\n    asm(\"ssat %0, #11, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_U12(WORD32 x)\n{\n    asm(\"usat %0, #12, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_S12(WORD32 x)\n{\n    asm(\"ssat %0, #12, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\nstatic __inline WORD32 CLIP_U16(WORD32 x)\n{\n    asm(\"usat %0, #16, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\nstatic __inline WORD32 CLIP_S16(WORD32 x)\n{\n    asm(\"ssat %0, #16, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n\n\nstatic __inline UWORD32 ITT_BIG_ENDIAN(UWORD32 x)\n{\n    asm(\"rev %0, %1\" : \"=r\"(x) : \"r\"(x));\n    return x;\n}\n#define NOP(nop_cnt)    {UWORD32 nop_i; for (nop_i = 0; nop_i < nop_cnt; nop_i++) asm(\"nop\");}\n\n#else\n\n#define CLIP_U8(x) CLIP3(0, UINT8_MAX, (x))\n#define CLIP_S8(x) CLIP3(INT8_MIN, INT8_MAX, (x))\n\n#define CLIP_U10(x) CLIP3(0, 1023, (x))\n#define CLIP_S10(x) CLIP3(-512, 511, (x))\n\n#define CLIP_U11(x) CLIP3(0, 2047, (x))\n#define CLIP_S11(x) CLIP3(-1024, 1023, (x))\n\n#define CLIP_U12(x) CLIP3(0, 4095, (x))\n#define CLIP_S12(x) CLIP3(-2048, 2047, (x))\n\n#define CLIP_U16(x) CLIP3(0, UINT16_MAX, (x))\n#define CLIP_S16(x) CLIP3(INT16_MIN, INT16_MAX, (x))\n\n#define ITT_BIG_ENDIAN(x)       __asm__(\"rev %0, %1\" : \"=r\"(x) : \"r\"(x));\n\n#define NOP(nop_cnt)                                \\\n{                                                   \\\n    UWORD32 nop_i;                                  \\\n    for (nop_i = 0; nop_i < nop_cnt; nop_i++)       \\\n        __asm__ __volatile__(\"mov x0, x0\");         \\\n}\n\n#endif\n\n/*saturating instructions are not available for WORD64 in ARMv7, hence we cannot\n * use inline assembly like other clips*/\n#define CLIP_U32(x) CLIP3(0, UINT32_MAX, (x))\n#define CLIP_S32(x) CLIP3(INT32_MIN, INT32_MAX, (x))\n\n#define DATA_SYNC() __sync_synchronize()\n\n#define SHL(x,y) (((y) < 32) ? ((x) << (y)) : 0)\n#define SHR(x,y) (((y) < 32) ? ((x) >> (y)) : 0)\n\n#define SHR_NEG(val,shift)  ((shift>0)?(val>>shift):(val<<(-shift)))\n#define SHL_NEG(val,shift)  ((shift<0)?(val>>(-shift)):(val<<shift))\n\n#define INLINE inline\n\n/* In normal cases, 0 will not be passed as an argument to CLZ and CTZ.\nAs CLZ and CTZ outputs are used as a shift value in few places, these return\n31 for u4_word == 0 case, just to handle error cases gracefully without any\nundefined behaviour */\n\nstatic INLINE UWORD32 CLZ(UWORD32 u4_word)\n{\n    if(u4_word)\n        return (__builtin_clz(u4_word));\n    else\n        return 31;\n}\nstatic INLINE UWORD32 CTZ(UWORD32 u4_word)\n{\n    if(0 == u4_word)\n        return 31;\n    else\n    {\n        unsigned int index;\n        index = __builtin_ctz(u4_word);\n        return (UWORD32)index;\n    }\n}\n\n#define MEM_ALIGN8 __attribute__ ((aligned (8)))\n#define MEM_ALIGN16 __attribute__ ((aligned (16)))\n#define MEM_ALIGN32 __attribute__ ((aligned (32)))\n\n#endif /* _IH264_PLATFORM_MACROS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_resi_trans_quant_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///*****************************************************************************/\n///**\n//*******************************************************************************\n//* @file\n//*  ih264_resi_trans_quant_av8.c\n//*\n//* @brief\n//*  contains function definitions for residual and forward trans\n//*\n//* @author\n//*  ittiam\n//*\n//* @par list of functions:\n//*    ih264_resi_trans_quant_4x4_av8\n//*    ih264_resi_trans_quant_8x8_av8\n//*    ih264_resi_trans_quant_chroma_4x4_av8\n//* @remarks\n//*  none\n//*\n//*******************************************************************************\n.include \"ih264_neon_macros.s\"\n.text\n.p2align 2\n//*****************************************************************************\n//*\n//* function name     : ih264_resi_trans_quant_4x4\n//* description       : this function does cf4 of h264\n//*\n// values returned   : none\n//\n// register usage    :\n// stack usage       : 64 bytes\n// cycles            :\n// interruptiaility  : interruptable\n//\n// known limitations\n//   \\assumptions    :\n//\n// revision history  :\n//         dd mm yyyy    author(s)   changes\n//         1 12 2013    100633      first version\n//         20 1 2014    100633      changes the api, optimization\n//\n//*****************************************************************************\n\n    .global ih264_resi_trans_quant_4x4_av8\nih264_resi_trans_quant_4x4_av8:\n\n    push_v_regs\n    //x0     :pointer to src buffer\n    //x1     :pointer to pred buffer\n    //x2     :pointer to dst buffer\n    //w3     :source stride\n    //w4     :pred stride\n    //w5     :scale matirx,\n    //x6     :threshold matrix\n    //w7     :qbits\n    //w8        :round factor\n    //x9        :nnz\n    //x10       :pointer to store non quantized dc value\n\n    sxtw      x3, w3\n    sxtw      x4, w4\n    ldr       w8, [sp, #64]             //load round factor\n    ldr       x10, [sp, #80]            //load addres for non quant val\n    neg       w7, w7                    //negate the qbit value for usiing lsl\n    ldr       x9, [sp, #72]\n\n    //------------fucntion loading done----------------;\n\n    ld1       {v30.8b}, [x0], x3        //load first 8 pix src  row 1\n    ld1       {v31.8b}, [x1], x4        //load first 8 pix pred row 1\n    ld1       {v28.8b}, [x0], x3        //load first 8 pix src  row 2\n    ld1       {v29.8b}, [x1], x4        //load first 8 pix pred row 2\n    ld1       {v26.8b}, [x0], x3        //load first 8 pix src  row 3\n    ld1       {v27.8b}, [x1], x4        //load first 8 pix pred row 3\n    ld1       {v24.8b}, [x0]            //load first 8 pix src row 4\n    ld1       {v25.8b}, [x1]            //load first 8 pix pred row 4\n\n    usubl     v0.8h, v30.8b, v31.8b     //find residue row 1\n    usubl     v2.8h, v28.8b, v29.8b     //find residue row 2\n    usubl     v4.8h, v26.8b, v27.8b     //find residue row 3\n    usubl     v6.8h, v24.8b, v25.8b     //find residue row 4\n\n    trn1      v1.4h, v0.4h, v2.4h\n    trn2      v3.4h, v0.4h, v2.4h       //t12\n    trn1      v5.4h, v4.4h, v6.4h\n    trn2      v7.4h, v4.4h, v6.4h       //t23\n\n    trn1      v0.2s, v1.2s, v5.2s\n    trn2      v4.2s, v1.2s, v5.2s       //t13\n    trn1      v2.2s, v3.2s, v7.2s\n    trn2      v6.2s, v3.2s, v7.2s       //t14\n\n    add       v8.4h, v0.4h, v6.4h       //x0 = x4+x7\n    add       v9.4h, v2.4h, v4.4h       //x1 = x5+x6\n    sub       v10.4h, v2.4h, v4.4h      //x2 = x5-x6\n    sub       v11.4h, v0.4h, v6.4h      //x3 = x4-x7\n\n    shl       v12.4h, v10.4h, #1        //u_shift(x2,1,shft)\n    shl       v13.4h, v11.4h, #1        //u_shift(x3,1,shft)\n\n    add       v14.4h, v8.4h, v9.4h      //x4 = x0 + x1;\n    sub       v16.4h, v8.4h, v9.4h      //x6 = x0 - x1;\n    add       v15.4h, v13.4h, v10.4h    //x5 = u_shift(x3,1,shft) + x2;\n    sub       v17.4h, v11.4h, v12.4h    //x7 = x3 - u_shift(x2,1,shft);\n\n    //taking transpose again so as to make do vert transform\n    trn1      v0.4h, v14.4h, v15.4h\n    trn2      v1.4h, v14.4h, v15.4h     //t12\n    trn1      v2.4h, v16.4h, v17.4h\n    trn2      v3.4h, v16.4h, v17.4h     //t23\n\n    trn1      v14.2s, v0.2s, v2.2s\n    trn2      v16.2s, v0.2s, v2.2s      //t13\n    trn1      v15.2s, v1.2s, v3.2s\n    trn2      v17.2s, v1.2s, v3.2s      //t24\n\n    //let us do vertical transform\n    //same code as horiz\n    add       v18.4h, v14.4h , v17.4h   //x0 = x4+x7\n    add       v19.4h, v15.4h , v16.4h   //x1 = x5+x6\n    sub       v20.4h, v15.4h , v16.4h   //x2 = x5-x6\n    sub       v21.4h, v14.4h , v17.4h   //x3 = x4-x7\n\n    shl       v22.4h, v20.4h, #1        //u_shift(x2,1,shft)\n    shl       v23.4h, v21.4h, #1        //u_shift(x3,1,shft)\n\n    dup       v8.4s, w8                 //load rounding value row 1\n\n    add       v24.4h, v18.4h , v19.4h   //x5 = x0 + x1;\n    sub       v26.4h, v18.4h , v19.4h   //x7 = x0 - x1;\n    add       v25.4h, v23.4h , v20.4h   //x6 = u_shift(x3,1,shft) + x2;\n    sub       v27.4h, v21.4h , v22.4h   //x8 = x3 - u_shift(x2,1,shft);\n\n    dup       v23.4s, w8                //load round factor values\n\n    st1       {v24.h}[0], [x10]         //store the dc value to alternate dc sddress\n//core tranform is done for 4x8 block 1\n    ld1       {v28.4h-v31.4h}, [x5]     //load the scaling values\n\n    abs       v0.4h, v24.4h             //abs val of row 1\n    abs       v1.4h, v25.4h             //abs val of row 2\n    abs       v2.4h, v26.4h             //abs val of row 3\n    abs       v3.4h, v27.4h             //abs val of row 4\n\n    cmgt      v4.4h, v24.4h, #0\n    cmgt      v5.4h, v25.4h, #0\n    cmgt      v6.4h, v26.4h, #0\n    cmgt      v7.4h, v27.4h, #0\n\n    smull     v0.4s, v0.4h, v28.4h      //multiply and add row 1\n    smull     v1.4s, v1.4h, v29.4h      //multiply and add row 2\n    smull     v2.4s, v2.4h, v30.4h      //multiply and add row 3\n    smull     v3.4s, v3.4h, v31.4h      //multiply and add row 4\n\n    add       v20.4s, v0.4s, v23.4s\n    add       v21.4s, v1.4s, v23.4s\n    add       v22.4s, v2.4s, v23.4s\n    add       v23.4s, v3.4s, v23.4s\n\n    dup       v24.4s, w7\n\n    sshl      v20.4s, v20.4s, v24.4s    //shift row 1\n    sshl      v21.4s, v21.4s, v24.4s    //shift row 2\n    sshl      v22.4s, v22.4s, v24.4s    //shift row 3\n    sshl      v23.4s, v23.4s, v24.4s    //shift row 4\n\n    xtn       v20.4h, v20.4s            //narrow row 1\n    xtn       v21.4h, v21.4s            //narrow row 2\n    xtn       v22.4h, v22.4s            //narrow row 3\n    xtn       v23.4h, v23.4s            //narrow row 4\n\n    neg       v24.8h, v20.8h            //get negative\n    neg       v25.8h, v21.8h            //get negative\n    neg       v26.8h, v22.8h            //get negative\n    neg       v27.8h, v23.8h            //get negative\n\n    //compare with zero for computng nnz\n    cmeq      v0.4h, v20.4h, #0\n    cmeq      v1.4h, v21.4h, #0\n    cmeq      v2.4h, v22.4h, #0\n    cmeq      v3.4h, v23.4h, #0\n\n    bsl       v4.8b, v20.8b, v24.8b     //restore sign of row 1 and 2\n    bsl       v5.8b, v21.8b, v25.8b     //restore sign of row 3 and 4\n    bsl       v6.8b, v22.8b, v26.8b     //restore sign of row 1 and 2\n    bsl       v7.8b, v23.8b, v27.8b     //restore sign of row 3 and 4\n\n    //narrow the comaprison result\n    mov       v0.d[1], v2.d[0]\n    mov       v1.d[1], v3.d[0]\n\n    xtn       v0.8b, v0.8h\n    xtn       v1.8b, v1.8h\n\n    ushr      v0.8b, v0.8b, #7          //i    reduce comaparison bit to a signle bit row 1 and 2 blk  1 and 2 [ keep the value for later use ]\n    ushr      v1.8b, v1.8b, #7          //i    reduce comaparison bit to a signle bit row 1 and 2 blk  1 and 2 [ keep the value for later use ]\n\n    add       v0.8b, v0.8b, v1.8b       //i pair add nnz 1\n    addp      v0.8b, v0.8b, v0.8b       //i pair add nnz 1\n    addp      v0.8b, v0.8b, v0.8b       //i pair add nnz 1\n    addp      v0.8b, v0.8b, v0.8b       //i pair add nnz 1\n\n    st1       {v4.4h-v7.4h}, [x2]       //store blk\n\n    movi      v25.8b, #16               //get max nnz\n    sub       v26.8b, v25.8b , v0.8b    //invert current nnz\n    st1       {v26.b}[0], [x9]          //write nnz\n\n    pop_v_regs\n    ret\n\n\n//*****************************************************************************\n//*\n//* function name     : ih264_resi_trans_quant_chroma_4x4\n//* description       : this function does residue calculation, forward transform\n//*                        and quantization for 4x4 chroma block.\n//*\n// values returned   : none\n//\n// register usage    :\n// stack usage       : 64 bytes\n// cycles            :\n// interruptiaility  : interruptable\n//\n// known limitations\n//   \\assumptions    :\n//\n// revision history  :\n//         dd mm yyyy    author(s)   changes\n//         11 2 2015    100664      first version\n//         25 2 2015    100633      first av8 version\n//*****************************************************************************\n\n    .global ih264_resi_trans_quant_chroma_4x4_av8\nih264_resi_trans_quant_chroma_4x4_av8:\n\n    push_v_regs\n    //x0     :pointer to src buffer\n    //x1     :pointer to pred buffer\n    //x2     :pointer to dst buffer\n    //w3     :source stride\n    //w4     :pred stride\n    //x5     :scale matirx,\n    //x6     :threshold matrix\n    //w7     :qbits\n    //w8        :round factor\n    //x9        :nnz\n    //x10       :pointer to store non quantized dc value\n\n    sxtw      x3, w3\n    sxtw      x4, w4\n    ldr       w8, [sp, #64]             //load round factor\n    ldr       x10, [sp, #80]            //load addres for non quant val\n    neg       w7, w7                    //negate the qbit value for usiing lsl\n    ldr       x9, [sp, #72]\n    //------------fucntion loading done----------------;\n\n    ld1       {v30.8b}, [x0], x3        //load first 8 pix src  row 1\n    ld1       {v31.8b}, [x1], x4        //load first 8 pix pred row 1\n    ld1       {v28.8b}, [x0], x3        //load first 8 pix src  row 2\n    ld1       {v29.8b}, [x1], x4        //load first 8 pix pred row 2\n    ld1       {v26.8b}, [x0], x3        //load first 8 pix src  row 3\n    ld1       {v27.8b}, [x1], x4        //load first 8 pix pred row 3\n    ld1       {v24.8b}, [x0]            //load first 8 pix src row 4\n    ld1       {v25.8b}, [x1]            //load first 8 pix pred row 4\n\n\n    //deinterleave the loaded values\n    uzp1      v30.8b, v30.8b, v30.8b\n    uzp1      v31.8b, v31.8b, v31.8b\n    uzp1      v28.8b, v28.8b, v28.8b\n    uzp1      v29.8b, v29.8b, v29.8b\n    uzp1      v26.8b, v26.8b, v26.8b\n    uzp1      v27.8b, v27.8b, v27.8b\n    uzp1      v24.8b, v24.8b, v24.8b\n    uzp1      v25.8b, v25.8b, v25.8b\n    //this deinterleaving is the only differnece betweenchrom and luma fucntions\n\n    usubl     v0.8h, v30.8b, v31.8b     //find residue row 1\n    usubl     v2.8h, v28.8b, v29.8b     //find residue row 2\n    usubl     v4.8h, v26.8b, v27.8b     //find residue row 3\n    usubl     v6.8h, v24.8b, v25.8b     //find residue row 4\n\n    trn1      v1.4h, v0.4h, v2.4h\n    trn2      v3.4h, v0.4h, v2.4h       //t12\n    trn1      v5.4h, v4.4h, v6.4h\n    trn2      v7.4h, v4.4h, v6.4h       //t23\n\n    trn1      v0.2s, v1.2s, v5.2s\n    trn2      v4.2s, v1.2s, v5.2s       //t13\n    trn1      v2.2s, v3.2s, v7.2s\n    trn2      v6.2s, v3.2s, v7.2s       //t14\n\n    add       v8.4h, v0.4h, v6.4h       //x0 = x4+x7\n    add       v9.4h, v2.4h, v4.4h       //x1 = x5+x6\n    sub       v10.4h, v2.4h, v4.4h      //x2 = x5-x6\n    sub       v11.4h, v0.4h, v6.4h      //x3 = x4-x7\n\n    shl       v12.4h, v10.4h, #1        //u_shift(x2,1,shft)\n    shl       v13.4h, v11.4h, #1        //u_shift(x3,1,shft)\n\n    add       v14.4h, v8.4h, v9.4h      //x4 = x0 + x1;\n    sub       v16.4h, v8.4h, v9.4h      //x6 = x0 - x1;\n    add       v15.4h, v13.4h, v10.4h    //x5 = u_shift(x3,1,shft) + x2;\n    sub       v17.4h, v11.4h, v12.4h    //x7 = x3 - u_shift(x2,1,shft);\n\n    //taking transpose again so as to make do vert transform\n    trn1      v0.4h, v14.4h, v15.4h\n    trn2      v1.4h, v14.4h, v15.4h     //t12\n    trn1      v2.4h, v16.4h, v17.4h\n    trn2      v3.4h, v16.4h, v17.4h     //t23\n\n    trn1      v14.2s, v0.2s, v2.2s\n    trn2      v16.2s, v0.2s, v2.2s      //t13\n    trn1      v15.2s, v1.2s, v3.2s\n    trn2      v17.2s, v1.2s, v3.2s      //t24\n\n    //let us do vertical transform\n    //same code as horiz\n    add       v18.4h, v14.4h , v17.4h   //x0 = x4+x7\n    add       v19.4h, v15.4h , v16.4h   //x1 = x5+x6\n    sub       v20.4h, v15.4h , v16.4h   //x2 = x5-x6\n    sub       v21.4h, v14.4h , v17.4h   //x3 = x4-x7\n\n    shl       v22.4h, v20.4h, #1        //u_shift(x2,1,shft)\n    shl       v23.4h, v21.4h, #1        //u_shift(x3,1,shft)\n\n    dup       v8.4s, w8                 //load rounding value row 1\n\n    add       v24.4h, v18.4h , v19.4h   //x5 = x0 + x1;\n    sub       v26.4h, v18.4h , v19.4h   //x7 = x0 - x1;\n    add       v25.4h, v23.4h , v20.4h   //x6 = u_shift(x3,1,shft) + x2;\n    sub       v27.4h, v21.4h , v22.4h   //x8 = x3 - u_shift(x2,1,shft);\n\n    dup       v23.4s, w8                //load round factor values\n\n    st1       {v24.h}[0], [x10]         //store the dc value to alternate dc sddress\n//core tranform is done for 4x8 block 1\n    ld1       {v28.4h-v31.4h}, [x5]     //load the scaling values\n\n    abs       v0.4h, v24.4h             //abs val of row 1\n    abs       v1.4h, v25.4h             //abs val of row 2\n    abs       v2.4h, v26.4h             //abs val of row 3\n    abs       v3.4h, v27.4h             //abs val of row 4\n\n    cmgt      v4.4h, v24.4h, #0\n    cmgt      v5.4h, v25.4h, #0\n    cmgt      v6.4h, v26.4h, #0\n    cmgt      v7.4h, v27.4h, #0\n\n    smull     v0.4s, v0.4h, v28.4h      //multiply and add row 1\n    smull     v1.4s, v1.4h, v29.4h      //multiply and add row 2\n    smull     v2.4s, v2.4h, v30.4h      //multiply and add row 3\n    smull     v3.4s, v3.4h, v31.4h      //multiply and add row 4\n\n    add       v20.4s, v0.4s, v23.4s\n    add       v21.4s, v1.4s, v23.4s\n    add       v22.4s, v2.4s, v23.4s\n    add       v23.4s, v3.4s, v23.4s\n\n    dup       v24.4s, w7\n\n    sshl      v20.4s, v20.4s, v24.4s    //shift row 1\n    sshl      v21.4s, v21.4s, v24.4s    //shift row 2\n    sshl      v22.4s, v22.4s, v24.4s    //shift row 3\n    sshl      v23.4s, v23.4s, v24.4s    //shift row 4\n\n    xtn       v20.4h, v20.4s            //narrow row 1\n    xtn       v21.4h, v21.4s            //narrow row 2\n    xtn       v22.4h, v22.4s            //narrow row 3\n    xtn       v23.4h, v23.4s            //narrow row 4\n\n    neg       v24.8h, v20.8h            //get negative\n    neg       v25.8h, v21.8h            //get negative\n    neg       v26.8h, v22.8h            //get negative\n    neg       v27.8h, v23.8h            //get negative\n\n    //compare with zero for computng nnz\n    cmeq      v0.4h, v20.4h, #0\n    cmeq      v1.4h, v21.4h, #0\n    cmeq      v2.4h, v22.4h, #0\n    cmeq      v3.4h, v23.4h, #0\n\n    bsl       v4.8b, v20.8b, v24.8b     //restore sign of row 1 and 2\n    bsl       v5.8b, v21.8b, v25.8b     //restore sign of row 3 and 4\n    bsl       v6.8b, v22.8b, v26.8b     //restore sign of row 1 and 2\n    bsl       v7.8b, v23.8b, v27.8b     //restore sign of row 3 and 4\n\n    //narrow the comaprison result\n    mov       v0.d[1], v2.d[0]\n    mov       v1.d[1], v3.d[0]\n\n    xtn       v0.8b, v0.8h\n    xtn       v1.8b, v1.8h\n\n    ushr      v0.8b, v0.8b, #7          //i    reduce comaparison bit to a signle bit row 1 and 2 blk  1 and 2 [ keep the value for later use ]\n    ushr      v1.8b, v1.8b, #7          //i    reduce comaparison bit to a signle bit row 1 and 2 blk  1 and 2 [ keep the value for later use ]\n\n    add       v0.8b, v0.8b, v1.8b       //i pair add nnz 1\n    addp      v0.8b, v0.8b, v0.8b       //i pair add nnz 1\n    addp      v0.8b, v0.8b, v0.8b       //i pair add nnz 1\n    addp      v0.8b, v0.8b, v0.8b       //i pair add nnz 1\n\n    st1       {v4.4h-v7.4h}, [x2]       //store blk\n\n    movi      v25.8b, #16               //get max nnz\n    sub       v26.8b, v25.8b , v0.8b    //invert current nnz\n    st1       {v26.b}[0], [x9]          //write nnz\n\n    pop_v_regs\n    ret\n\n\n//*****************************************************************************\n//*\n//* function name     : ih264_hadamard_quant_4x4_av8\n//* description       : this function does forward hadamard transform and\n//*                     quantization for luma dc block\n//*\n//* arguments         :  x0 :pointer to src buffer\n//                       x1 :pointer to dst buffer\n//                       x2 :pu2_scale_matrix\n//                       x3 :pu2_threshold_matrix\n//                       w4 :u4_qbits\n//                       w5 :u4_round_factor\n//                       x6 :pu1_nnz\n// values returned   : none\n//\n// register usage    :\n// stack usage       : 0 bytes\n// cycles            : around\n// interruptiaility  : interruptable\n//\n// known limitations\n//   \\assumptions    :\n//\n// revision history  :\n//         dd mm yyyy    author(s)   changes\n//         20 2 2015    100633      first version\n//\n//*****************************************************************************\n//ih264_hadamard_quant_4x4_av8(word16 *pi2_src, word16 *pi2_dst,\n//                           const uword16 *pu2_scale_matrix,\n//                           const uword16 *pu2_threshold_matrix, uword32 u4_qbits,\n//                           uword32 u4_round_factor,uword8  *pu1_nnz\n//                           )\n    .global ih264_hadamard_quant_4x4_av8\nih264_hadamard_quant_4x4_av8:\n\n//x0 :pointer to src buffer\n//x1 :pointer to dst buffer\n//x2 :pu2_scale_matrix\n//x3 :pu2_threshold_matrix\n//w4 :u4_qbits\n//w5 :u4_round_factor\n//x6 :pu1_nnz\n\n    push_v_regs\n\n    ld4       {v0.4h-v3.4h}, [x0]       //load 4x4 block\n    ld1       {v30.h}[0], [x2]          //load pu2_scale_matrix[0]\n\n    saddl     v4.4s, v0.4h, v3.4h       //x0 = x4 + x7;\n    saddl     v5.4s, v1.4h, v2.4h       //x1 = x5 + x6;\n    ssubl     v6.4s, v1.4h, v2.4h       //x2 = x5 - x6;\n    ssubl     v7.4s, v0.4h, v3.4h       //x3 = x4 - x7;\n\n    dup       v30.8h, v30.h[0]          //pu2_scale_matrix[0]\n\n    add       v14.4s, v4.4s, v5.4s      //pi2_dst[0] = x0 + x1;\n    add       v15.4s, v7.4s, v6.4s      //pi2_dst[1] = x3 + x2;\n    sub       v16.4s, v4.4s, v5.4s      //pi2_dst[2] = x0 - x1;\n    sub       v17.4s, v7.4s, v6.4s      //pi2_dst[3] = x3 - x2;\n\n    //transpose 4x4 block\n    trn1      v18.4s, v14.4s, v15.4s\n    trn2      v19.4s, v14.4s, v15.4s\n    trn1      v20.4s, v16.4s, v17.4s\n    trn2      v21.4s, v16.4s, v17.4s\n\n    trn1      v14.2d, v18.2d, v20.2d\n    trn2      v16.2d, v18.2d, v20.2d\n    trn1      v15.2d, v19.2d, v21.2d\n    trn2      v17.2d, v19.2d, v21.2d\n    //end transpose\n\n    add       v18.4s, v14.4s, v17.4s    //x0 = x4 + x7;\n    add       v19.4s, v15.4s, v16.4s    //x1 = x5 + x6;\n    sub       v20.4s, v15.4s, v16.4s    //x2 = x5 - x6;\n    sub       v21.4s, v14.4s, v17.4s    //x3 = x4 - x7;\n\n    dup       v14.4s, w5                //round factor\n    dup       v15.4s, v14.s[0]\n    dup       v16.4s, v14.s[0]\n    dup       v17.4s, v14.s[0]\n\n    add       v22.4s, v18.4s, v19.4s    //(x0 + x1)\n    add       v23.4s, v21.4s, v20.4s    //(x3 + x2)\n    sub       v24.4s, v18.4s, v19.4s    //(x0 - x1)\n    sub       v25.4s, v21.4s, v20.4s    //(x3 - x2)\n\n    shrn      v0.4h, v22.4s, #1         //i4_value = (x0 + x1) >> 1;\n    shrn2     v0.8h, v23.4s, #1         //i4_value = (x3 + x2) >> 1;\n    shrn      v1.4h, v24.4s, #1         //i4_value = (x0 - x1) >> 1;\n    shrn2     v1.8h, v25.4s, #1         //i4_value = (x3 - x2) >> 1;\n\n    abs       v2.8h, v0.8h\n    abs       v3.8h, v1.8h\n\n    cmgt      v4.8h, v0.8h, #0          //get the sign row 1,2\n    cmgt      v5.8h, v1.8h, #0\n\n    neg       w4, w4                    //-u4_qbits\n    dup       v22.4s, w4                //load  -u4_qbits\n\n    umlal     v14.4s, v2.4h, v30.4h\n    umlal2    v15.4s, v2.8h, v30.8h\n    umlal     v16.4s, v3.4h, v30.4h\n    umlal2    v17.4s, v3.8h, v30.8h\n\n    ushl      v14.4s, v14.4s, v22.4s\n    ushl      v15.4s, v15.4s, v22.4s\n    ushl      v16.4s, v16.4s, v22.4s\n    ushl      v17.4s, v17.4s, v22.4s\n\n    uqxtn     v14.4h, v14.4s\n    uqxtn2    v14.8h, v15.4s\n    uqxtn     v16.4h, v16.4s\n    uqxtn2    v16.8h, v17.4s\n\n    neg       v15.8h, v14.8h\n    neg       v17.8h, v16.8h\n\n    bsl       v4.16b, v14.16b, v15.16b\n    bsl       v5.16b, v16.16b, v17.16b\n\n    cmeq      v0.8h, v14.8h, #0\n    cmeq      v1.8h, v16.8h, #0\n\n    st1       {v4.8h-v5.8h}, [x1]\n\n    movi      v20.8b, #16\n\n    xtn       v2.8b, v0.8h\n    xtn       v3.8b, v1.8h\n\n    ushr      v2.8b, v2.8b, #7\n    ushr      v3.8b, v3.8b, #7\n\n    add       v2.8b, v2.8b, v3.8b\n    addp      v2.8b, v2.8b, v2.8b\n    addp      v2.8b, v2.8b, v2.8b\n    addp      v2.8b, v2.8b, v2.8b\n    sub       v20.8b, v20.8b, v2.8b\n    st1       {v20.b}[0], [x6]\n\n    pop_v_regs\n    ret\n\n\n//*****************************************************************************\n//*\n//* function name     : ih264_hadamard_quant_2x2_uv\n//* description       : this function does forward hadamard transform and\n//*                     quantization for dc block of chroma for both planes\n//*\n//* arguments         :  x0 :pointer to src buffer\n//                       x1 :pointer to dst buffer\n//                       x2 :pu2_scale_matrix\n//                       x3 :pu2_threshold_matrix\n//                       w4 :u4_qbits\n//                       w5 :u4_round_factor\n//                       x6 :pu1_nnz\n// values returned   : none\n//\n// register usage    :\n// stack usage       : 0 bytes\n// cycles            : around\n// interruptiaility  : interruptable\n//\n// known limitations\n//   \\assumptions    :\n//\n// revision history  :\n//         dd mm yyyy    author(s)   changes\n//         20 2 2015    100633      first version\n//\n//*****************************************************************************\n// ih264_hadamard_quant_2x2_uv_av8(word16 *pi2_src, word16 *pi2_dst,\n//                             const uword16 *pu2_scale_matrix,\n//                             const uword16 *pu2_threshold_matrix, uword32 u4_qbits,\n//                             uword32 u4_round_factor,uword8  *pu1_nnz\n//                             )\n\n    .global ih264_hadamard_quant_2x2_uv_av8\nih264_hadamard_quant_2x2_uv_av8:\n\n    push_v_regs\n\n    ld2       {v0.4h-v1.4h}, [x0]       //load src\n\n    ld1       {v30.h}[0], [x2]          //load pu2_scale_matrix[0]\n    dup       v30.4h, v30.h[0]          //pu2_scale_matrix\n    uxtl      v30.4s, v30.4h            //pu2_scale_matrix\n\n    neg       w4, w4\n    dup       v24.4s, w4                //u4_qbits\n\n    dup       v25.4s, w5                //round fact\n    dup       v26.4s, v25.s[0]\n\n    saddl     v2.4s, v0.4h, v1.4h       //x0 = x4 + x5;, x2 = x6 + x7;\n    ssubl     v3.4s, v0.4h, v1.4h       //x1 = x4 - x5;  x3 = x6 - x7;\n\n    trn1      v4.4s, v2.4s, v3.4s\n    trn2      v5.4s, v2.4s, v3.4s       //q1 -> x0 x1, q2 -> x2 x3\n\n    add       v0.4s, v4.4s , v5.4s      // (x0 + x2) (x1 + x3)  (y0 + y2); (y1 + y3);\n    sub       v1.4s, v4.4s , v5.4s      // (x0 - x2) (x1 - x3)  (y0 - y2); (y1 - y3);\n\n    abs       v2.4s, v0.4s\n    abs       v3.4s, v1.4s\n\n    cmgt      v4.4s, v0.4s, #0          //get the sign row 1,2\n    cmgt      v5.4s, v1.4s, #0\n\n    uqxtn     v4.4h, v4.4s\n    sqxtn2    v4.8h, v5.4s\n\n    mla       v25.4s, v2.4s, v30.4s\n    mla       v26.4s, v3.4s, v30.4s\n\n    ushl      v2.4s, v25.4s, v24.4s     //>>qbit\n    ushl      v3.4s, v26.4s, v24.4s     //>>qbit\n\n    uqxtn     v2.4h, v2.4s\n    uqxtn2    v2.8h, v3.4s\n\n    neg       v5.8h, v2.8h\n\n    bsl       v4.16b, v2.16b, v5.16b    //*sign\n\n    //rearrange such that we get each plane coeffs as continous\n    mov       v5.s[0], v4.s[1]\n    mov       v4.s[1], v4.s[2]\n    mov       v4.s[2], v5.s[0]\n\n    cmeq      v5.8h, v4.8h, #0          //compute nnz\n    xtn       v5.8b, v5.8h              //reduce nnz comparison to 1 bit\n    ushr      v5.8b, v5.8b, #7          //reduce nnz comparison to 1 bit\n    movi      v20.8b, #4                //since we add zeros, we need to subtract from 4 to get nnz\n    addp      v5.8b, v5.8b, v5.8b       //sum up nnz\n    addp      v5.8b, v5.8b, v5.8b       //sum up nnz\n\n    st1       {v4.8h}, [x1]             //store the block\n\n    st1       {v4.8h}, [x1]             //store the block\n    sub       v20.8b, v20.8b, v5.8b     //4- numzeros\n\n    st1       {v20.h}[0], [x6]          //store nnz\n\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_weighted_bi_pred_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_weighted_bi_pred_av8.s\n//*\n//* @brief\n//*  Contains function definitions for weighted biprediction.\n//*\n//* @author\n//*  Kaushik Senthoor R\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_weighted_bi_pred_luma_av8()\n//*  - ih264_weighted_bi_pred_chroma_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//*******************************************************************************\n//* @function\n//*  ih264_weighted_bi_pred_luma_av8()\n//*\n//* @brief\n//*  This routine performs the default weighted prediction as described in sec\n//* 8.4.2.3.2 titled \"Weighted sample prediction process\" for luma.\n//*\n//* @par Description:\n//*  This function gets two ht x wd blocks, calculates the weighted samples,\n//* rounds off, adds offset and stores it in the destination block.\n//*\n//* @param[in] puc_src1\n//*  UWORD8 Pointer to the buffer containing the input block 1.\n//*\n//* @param[in] puc_src2\n//*  UWORD8 Pointer to the buffer containing the input block 2.\n//*\n//* @param[out] puc_dst\n//*  UWORD8 pointer to the destination where the output block is stored.\n//*\n//* @param[in] src_strd1\n//*  Stride of the input buffer 1\n//*\n//* @param[in] src_strd2\n//*  Stride of the input buffer 2\n//*\n//* @param[in] dst_strd\n//*  Stride of the destination buffer\n//*\n//* @param[in] log_WD\n//*  number of bits to be rounded off\n//*\n//* @param[in] wt1\n//*  weight for the weighted prediction\n//*\n//* @param[in] wt2\n//*  weight for the weighted prediction\n//*\n//* @param[in] ofst1\n//*  offset 1 used after rounding off\n//*\n//* @param[in] ofst2\n//*  offset 2 used after rounding off\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  (ht,wd) can be (4,4), (4,8), (8,4), (8,8), (8,16), (16,8) or (16,16).\n//*\n//*******************************************************************************\n//*/\n//void ih264_weighted_bi_pred_luma_av8(UWORD8 *puc_src1,\n//                                     UWORD8 *puc_src2,\n//                                     UWORD8 *puc_dst,\n//                                     WORD32 src_strd1,\n//                                     WORD32 src_strd2,\n//                                     WORD32 dst_strd,\n//                                     WORD32 log_WD,\n//                                     WORD32 wt1,\n//                                     WORD32 wt2,\n//                                     WORD16 ofst1,\n//                                     WORD16 ofst2,\n//                                     WORD32 ht,\n//                                     WORD32 wd)\n//\n//**************Variables Vs Registers*****************************************\n//    x0      => puc_src1\n//    x1      => puc_src2\n//    x2      => puc_dst\n//    w3      => src_strd1\n//    w4      => src_strd2\n//    w5      => dst_strd\n//    w6      => log_WD\n//    w7      => wt1\n//    [sp]    => wt2       (w8)\n//    [sp+8]  => ofst1     (w9)\n//    [sp+16] => ofst2     (w10)\n//    [sp+24] => ht        (w11)\n//    [sp+32] => wd        (w12)\n//\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_weighted_bi_pred_luma_av8\n\nih264_weighted_bi_pred_luma_av8:\n\n    // STMFD sp!, {x4-x12,x14}                //stack stores the values of the arguments\n    push_v_regs\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n    stp       x19, x20, [sp, #-16]!\n#ifndef __APPLE__\n    ldr       w8, [sp, #80]             //Load wt2 in w8\n    ldr       w9, [sp, #88]             //Load ofst1 in w9\n    ldr       w10, [sp, #96]            //Load ofst2 in w10\n    ldr       w11, [sp, #104]           //Load ht in w11\n    ldr       w12, [sp, #112]           //Load wd in w12\n#else\n    ldr       w8, [sp, #80]             //Load wt2 in w8\n    ldr       w9, [sp, #84]             //Load ofst1 in w9\n    ldr       w10, [sp, #88]            //Load ofst2 in w10\n    ldr       w11,  [sp, #92]           //Load ht in w11\n    ldr       w12,  [sp, #96]           //Load wd in w12\n#endif\n    add       w6, w6, #1                //w6  = log_WD + 1\n    neg       w10, w6                   //w10 = -(log_WD + 1)\n    dup       v0.8h, w10                //Q0  = -(log_WD + 1) (32-bit)\n    add       w9, w9, #1                //w9 = ofst1 + 1\n    add       w9, w9, w10               //w9 = ofst1 + ofst2 + 1\n    mov       v2.s[0], w7\n    mov       v2.s[1], w8               //D2 = {wt1(32-bit), wt2(32-bit)}\n    asr       w9, w9, #1                //w9 = ofst = (ofst1 + ofst2 + 1) >> 1\n    dup       v3.8b, w9                 //D3 = ofst (8-bit)\n    cmp       w12, #16\n    beq       loop_16                   //branch if wd is 16\n    cmp       w12, #8                   //check if wd is 8\n    beq       loop_8                    //branch if wd is 8\n\nloop_4:                                 //each iteration processes four rows\n\n    ld1       {v4.s}[0], [x0], x3       //load row 1 in source 1\n    ld1       {v4.s}[1], [x0], x3       //load row 2 in source 1\n    ld1       {v6.s}[0], [x1], x4       //load row 1 in source 2\n    ld1       {v6.s}[1], [x1], x4       //load row 2 in source 2\n    uxtl      v4.8h, v4.8b              //converting rows 1,2 in source 1 to 16-bit\n    ld1       {v8.s}[0], [x0], x3       //load row 3 in source 1\n    ld1       {v8.s}[1], [x0], x3       //load row 4 in source 1\n    uxtl      v6.8h, v6.8b              //converting rows 1,2 in source 2 to 16-bit\n    ld1       {v10.s}[0], [x1], x4      //load row 3 in source 2\n    ld1       {v10.s}[1], [x1], x4      //load row 4 in source 2\n    uxtl      v8.8h, v8.8b              //converting rows 3,4 in source 1 to 16-bit\n    uxtl      v10.8h, v10.8b            //converting rows 3,4 in source 2 to 16-bit\n    mul       v4.8h, v4.8h , v2.h[0]    //weight 1 mult. for rows 1,2\n    mla       v4.8h, v6.8h , v2.h[2]    //weight 2 mult. for rows 1,2\n    mul       v8.8h, v8.8h , v2.h[0]    //weight 1 mult. for rows 3,4\n    mla       v8.8h, v10.8h , v2.h[2]   //weight 2 mult. for rows 3,4\n    subs      w11, w11, #4              //decrement ht by 4\n    srshl     v4.8h, v4.8h , v0.8h      //rounds off the weighted samples from rows 1,2\n    srshl     v8.8h, v8.8h , v0.8h      //rounds off the weighted samples from rows 3,4\n    saddw     v4.8h, v4.8h , v3.8b      //adding offset for rows 1,2\n    saddw     v8.8h, v8.8h , v3.8b      //adding offset for rows 3,4\n    sqxtun    v4.8b, v4.8h              //saturating rows 1,2 to unsigned 8-bit\n    sqxtun    v8.8b, v8.8h              //saturating rows 3,4 to unsigned 8-bit\n    st1       {v4.s}[0], [x2], x5       //store row 1 in destination\n    st1       {v4.s}[1], [x2], x5       //store row 2 in destination\n    st1       {v8.s}[0], [x2], x5       //store row 3 in destination\n    st1       {v8.s}[1], [x2], x5       //store row 4 in destination\n    bgt       loop_4                    //if greater than 0 repeat the loop again\n    b         end_loops\n\nloop_8:                                 //each iteration processes four rows\n\n    ld1       {v4.8b}, [x0], x3         //load row 1 in source 1\n    ld1       {v6.8b}, [x1], x4         //load row 1 in source 2\n    ld1       {v8.8b}, [x0], x3         //load row 2 in source 1\n    ld1       {v10.8b}, [x1], x4        //load row 2 in source 2\n    uxtl      v4.8h, v4.8b              //converting row 1 in source 1 to 16-bit\n    ld1       {v12.8b}, [x0], x3        //load row 3 in source 1\n    ld1       {v14.8b}, [x1], x4        //load row 3 in source 2\n    uxtl      v6.8h, v6.8b              //converting row 1 in source 2 to 16-bit\n    ld1       {v16.8b}, [x0], x3        //load row 4 in source 1\n    ld1       {v18.8b}, [x1], x4        //load row 4 in source 2\n    uxtl      v8.8h, v8.8b              //converting row 2 in source 1 to 16-bit\n    uxtl      v10.8h, v10.8b            //converting row 2 in source 2 to 16-bit\n    mul       v4.8h, v4.8h , v2.h[0]    //weight 1 mult. for row 1\n    mla       v4.8h, v6.8h , v2.h[2]    //weight 2 mult. for row 1\n    uxtl      v12.8h, v12.8b            //converting row 3 in source 1 to 16-bit\n    uxtl      v14.8h, v14.8b            //converting row 3 in source 2 to 16-bit\n    mul       v8.8h, v8.8h , v2.h[0]    //weight 1 mult. for row 2\n    mla       v8.8h, v10.8h , v2.h[2]   //weight 2 mult. for row 2\n    uxtl      v16.8h, v16.8b            //converting row 4 in source 1 to 16-bit\n    uxtl      v18.8h, v18.8b            //converting row 4 in source 2 to 16-bit\n    mul       v12.8h, v12.8h , v2.h[0]  //weight 1 mult. for row 3\n    mla       v12.8h, v14.8h , v2.h[2]  //weight 2 mult. for row 3\n    mul       v16.8h, v16.8h , v2.h[0]  //weight 1 mult. for row 4\n    mla       v16.8h, v18.8h , v2.h[2]  //weight 2 mult. for row 4\n    srshl     v4.8h, v4.8h , v0.8h      //rounds off the weighted samples from row 1\n    srshl     v8.8h, v8.8h , v0.8h      //rounds off the weighted samples from row 2\n    srshl     v12.8h, v12.8h , v0.8h    //rounds off the weighted samples from row 3\n    saddw     v4.8h, v4.8h , v3.8b      //adding offset for row 1\n    srshl     v16.8h, v16.8h , v0.8h    //rounds off the weighted samples from row 4\n    saddw     v8.8h, v8.8h , v3.8b      //adding offset for row 2\n    saddw     v12.8h, v12.8h , v3.8b    //adding offset for row 3\n    sqxtun    v4.8b, v4.8h              //saturating row 1 to unsigned 8-bit\n    saddw     v16.8h, v16.8h , v3.8b    //adding offset for row 4\n    sqxtun    v8.8b, v8.8h              //saturating row 2 to unsigned 8-bit\n    sqxtun    v12.8b, v12.8h            //saturating row 3 to unsigned 8-bit\n    sqxtun    v16.8b, v16.8h            //saturating row 4 to unsigned 8-bit\n    st1       {v4.8b}, [x2], x5         //store row 1 in destination\n    st1       {v8.8b}, [x2], x5         //store row 2 in destination\n    subs      w11, w11, #4              //decrement ht by 4\n    st1       {v12.8b}, [x2], x5        //store row 3 in destination\n    st1       {v16.8b}, [x2], x5        //store row 4 in destination\n    bgt       loop_8                    //if greater than 0 repeat the loop again\n    b         end_loops\n\nloop_16:                                //each iteration processes two rows\n\n    ld1       {v4.8b, v5.8b}, [x0], x3  //load row 1 in source 1\n    ld1       {v6.8b, v7.8b}, [x1], x4  //load row 1 in source 2\n    ld1       {v8.8b, v9.8b}, [x0], x3  //load row 2 in source 1\n    ld1       {v10.8b, v11.8b}, [x1], x4 //load row 2 in source 2\n    uxtl      v20.8h, v4.8b             //converting row 1L in source 1 to 16-bit\n    ld1       {v12.8b, v13.8b}, [x0], x3 //load row 3 in source 1\n    ld1       {v14.8b, v15.8b}, [x1], x4 //load row 3 in source 2\n    uxtl      v22.8h, v6.8b             //converting row 1L in source 2 to 16-bit\n    ld1       {v16.8b, v17.8b}, [x0], x3 //load row 4 in source 1\n    ld1       {v18.8b, v19.8b}, [x1], x4 //load row 4 in source 2\n    uxtl      v4.8h, v5.8b              //converting row 1H in source 1 to 16-bit\n    uxtl      v6.8h, v7.8b              //converting row 1H in source 2 to 16-bit\n    mul       v20.8h, v20.8h , v2.h[0]  //weight 1 mult. for row 1L\n    mla       v20.8h, v22.8h , v2.h[2]  //weight 2 mult. for row 1L\n    uxtl      v24.8h, v8.8b             //converting row 2L in source 1 to 16-bit\n    uxtl      v26.8h, v10.8b            //converting row 2L in source 2 to 16-bit\n    mul       v4.8h, v4.8h , v2.h[0]    //weight 1 mult. for row 1H\n    mla       v4.8h, v6.8h , v2.h[2]    //weight 2 mult. for row 1H\n    uxtl      v8.8h, v9.8b              //converting row 2H in source 1 to 16-bit\n    uxtl      v10.8h, v11.8b            //converting row 2H in source 2 to 16-bit\n    mul       v24.8h, v24.8h , v2.h[0]  //weight 1 mult. for row 2L\n    mla       v24.8h, v26.8h , v2.h[2]  //weight 2 mult. for row 2L\n    uxtl      v28.8h, v12.8b            //converting row 3L in source 1 to 16-bit\n    uxtl      v30.8h, v14.8b            //converting row 3L in source 2 to 16-bit\n    mul       v8.8h, v8.8h , v2.h[0]    //weight 1 mult. for row 2H\n    mla       v8.8h, v10.8h , v2.h[2]   //weight 2 mult. for row 2H\n    uxtl      v12.8h, v13.8b            //converting row 3H in source 1 to 16-bit\n    uxtl      v14.8h, v15.8b            //converting row 3H in source 2 to 16-bit\n    mul       v28.8h, v28.8h , v2.h[0]  //weight 1 mult. for row 3L\n    mla       v28.8h, v30.8h , v2.h[2]  //weight 2 mult. for row 3L\n    uxtl      v22.8h, v16.8b            //converting row 4L in source 1 to 16-bit\n    uxtl      v6.8h, v18.8b             //converting row 4L in source 2 to 16-bit\n    mul       v12.8h, v12.8h , v2.h[0]  //weight 1 mult. for row 3H\n    mla       v12.8h, v14.8h , v2.h[2]  //weight 2 mult. for row 3H\n    uxtl      v16.8h, v17.8b            //converting row 4H in source 1 to 16-bit\n    uxtl      v18.8h, v19.8b            //converting row 4H in source 2 to 16-bit\n    mul       v22.8h, v22.8h , v2.h[0]  //weight 1 mult. for row 4L\n    mla       v22.8h, v6.8h , v2.h[2]   //weight 2 mult. for row 4L\n    srshl     v20.8h, v20.8h , v0.8h    //rounds off the weighted samples from row 1L\n    mul       v16.8h, v16.8h , v2.h[0]  //weight 1 mult. for row 4H\n    mla       v16.8h, v18.8h , v2.h[2]  //weight 2 mult. for row 4H\n    srshl     v4.8h, v4.8h , v0.8h      //rounds off the weighted samples from row 1H\n    srshl     v24.8h, v24.8h , v0.8h    //rounds off the weighted samples from row 2L\n    saddw     v20.8h, v20.8h , v3.8b    //adding offset for row 1L\n    srshl     v8.8h, v8.8h , v0.8h      //rounds off the weighted samples from row 2H\n    saddw     v4.8h, v4.8h , v3.8b      //adding offset for row 1H\n    srshl     v28.8h, v28.8h , v0.8h    //rounds off the weighted samples from row 3L\n    saddw     v24.8h, v24.8h , v3.8b    //adding offset for row 2L\n    srshl     v12.8h, v12.8h , v0.8h    //rounds off the weighted samples from row 3H\n    saddw     v8.8h, v8.8h , v3.8b      //adding offset for row 2H\n    srshl     v22.8h, v22.8h , v0.8h    //rounds off the weighted samples from row 4L\n    saddw     v28.8h, v28.8h , v3.8b    //adding offset for row 3L\n    srshl     v16.8h, v16.8h , v0.8h    //rounds off the weighted samples from row 4H\n    saddw     v12.8h, v12.8h , v3.8b    //adding offset for row 3H\n    sqxtun    v26.8b, v20.8h            //saturating row 1L to unsigned 8-bit\n    saddw     v22.8h, v22.8h , v3.8b    //adding offset for row 4L\n    sqxtun    v27.8b, v4.8h             //saturating row 1H to unsigned 8-bit\n    saddw     v16.8h, v16.8h , v3.8b    //adding offset for row 4H\n    sqxtun    v10.8b, v24.8h            //saturating row 2L to unsigned 8-bit\n    sqxtun    v11.8b, v8.8h             //saturating row 2H to unsigned 8-bit\n    sqxtun    v30.8b, v28.8h            //saturating row 3L to unsigned 8-bit\n    sqxtun    v31.8b, v12.8h            //saturating row 3H to unsigned 8-bit\n    st1       {v26.8b, v27.8b}, [x2], x5 //store row 1 in destination\n    sqxtun    v14.8b, v22.8h            //saturating row 4L to unsigned 8-bit\n    sqxtun    v15.8b, v16.8h            //saturating row 4H to unsigned 8-bit\n    st1       {v10.8b, v11.8b}, [x2], x5 //store row 2 in destination\n    subs      w11, w11, #4              //decrement ht by 4\n    st1       {v30.8b, v31.8b}, [x2], x5 //store row 3 in destination\n    st1       {v14.8b, v15.8b}, [x2], x5 //store row 4 in destination\n    bgt       loop_16                   //if greater than 0 repeat the loop again\n\nend_loops:\n\n    // LDMFD sp!,{x4-x12,x15}                //Reload the registers from sp\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n//*******************************************************************************\n//* @function\n//*  ih264_weighted_bi_pred_chroma_av8()\n//*\n//* @brief\n//*  This routine performs the default weighted prediction as described in sec\n//* 8.4.2.3.2 titled \"Weighted sample prediction process\" for chroma.\n//*\n//* @par Description:\n//*  This function gets two ht x wd blocks, calculates the weighted samples,\n//* rounds off, adds offset and stores it in the destination block for U and V.\n//*\n//* @param[in] puc_src1\n//*  UWORD8 Pointer to the buffer containing the input block 1.\n//*\n//* @param[in] puc_src2\n//*  UWORD8 Pointer to the buffer containing the input block 2.\n//*\n//* @param[out] puc_dst\n//*  UWORD8 pointer to the destination where the output block is stored.\n//*\n//* @param[in] src_strd1\n//*  Stride of the input buffer 1\n//*\n//* @param[in] src_strd2\n//*  Stride of the input buffer 2\n//*\n//* @param[in] dst_strd\n//*  Stride of the destination buffer\n//*\n//* @param[in] log_WD\n//*  number of bits to be rounded off\n//*\n//* @param[in] wt1\n//*  weights for the weighted prediction in U and V\n//*\n//* @param[in] wt2\n//*  weights for the weighted prediction in U and V\n//*\n//* @param[in] ofst1\n//*  offset 1 used after rounding off for U an dV\n//*\n//* @param[in] ofst2\n//*  offset 2 used after rounding off for U and V\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  (ht,wd) can be (2,2), (2,4), (4,2), (4,4), (4,8), (8,4) or (8,8).\n//*\n//*******************************************************************************\n//*/\n//void ih264_weighted_bi_pred_chroma_av8(UWORD8 *puc_src1,\n//                                       UWORD8 *puc_src2,\n//                                       UWORD8 *puc_dst,\n//                                       WORD32 src_strd1,\n//                                       WORD32 src_strd2,\n//                                       WORD32 dst_strd,\n//                                       WORD32 log_WD,\n//                                       WORD32 wt1,\n//                                       WORD32 wt2,\n//                                       WORD32 ofst1,\n//                                       WORD32 ofst2,\n//                                       WORD32 ht,\n//                                       WORD32 wd)\n//\n//**************Variables Vs Registers*****************************************\n//    x0      => puc_src1\n//    x1      => puc_src2\n//    x2      => puc_dst\n//    w3      => src_strd1\n//    w4      => src_strd2\n//    w5      => dst_strd\n//    w6      => log_WD\n//    w7      => wt1\n//    [sp]    => wt2       (w8)\n//    [sp+8]  => ofst1     (w9)\n//    [sp+16] => ofst2     (w10)\n//    [sp+24] => ht        (w11)\n//    [sp+32] => wd        (w12)\n//\n\n\n\n\n\n    .global ih264_weighted_bi_pred_chroma_av8\n\nih264_weighted_bi_pred_chroma_av8:\n\n    // STMFD sp!, {x4-x12,x14}                //stack stores the values of the arguments\n    push_v_regs\n    sxtw      x3, w3\n    sxtw      x4, w4\n    sxtw      x5, w5\n    stp       x19, x20, [sp, #-16]!\n\n#ifndef __APPLE__\n    ldr       w8, [sp, #80]             //Load wt2 in w8\n    ldr       w9, [sp, #88]             //Load ofst1 in w9\n    ldr       w10, [sp, #96]            //Load ofst2 in w10\n    ldr       w11, [sp, #104]           //Load ht in w11\n    ldr       w12, [sp, #112]           //Load wd in w12\n#else\n    ldr       w8, [sp, #80]             //Load wt2 in w8\n    ldr       w9, [sp, #84]             //Load ofst1 in w9\n    ldr       w10, [sp, #88]            //Load ofst2 in w10\n    ldr       w11,  [sp, #92]           //Load ht in w11\n    ldr       w12,  [sp, #96]           //Load wd in w12\n#endif\n    dup       v4.4s, w8                 //Q2 = (wt2_u, wt2_v) (32-bit)\n    dup       v2.4s, w7                 //Q1 = (wt1_u, wt1_v) (32-bit)\n    add       w6, w6, #1                //w6  = log_WD + 1\n    neg       w20, w6                   //w20 = -(log_WD + 1)\n    dup       v0.8h, w20                //Q0  = -(log_WD + 1) (16-bit)\n    dup       v20.8h, w9                //0ffset1\n    dup       v21.8h, w10               //0ffset2\n    srhadd    v6.8b, v20.8b, v21.8b\n    sxtl      v6.8h, v6.8b\n    cmp       w12, #8                   //check if wd is 8\n    beq       loop_8_uv                 //branch if wd is 8\n    cmp       w12, #4                   //check if wd is 4\n    beq       loop_4_uv                 //branch if wd is 4\n\nloop_2_uv:                              //each iteration processes two rows\n\n    ld1       {v8.s}[0], [x0], x3       //load row 1 in source 1\n    ld1       {v8.s}[1], [x0], x3       //load row 2 in source 1\n    ld1       {v10.s}[0], [x1], x4      //load row 1 in source 2\n    ld1       {v10.s}[1], [x1], x4      //load row 2 in source 2\n    uxtl      v8.8h, v8.8b              //converting rows 1,2 in source 1 to 16-bit\n    uxtl      v10.8h, v10.8b            //converting rows 1,2 in source 2 to 16-bit\n    mul       v8.8h, v8.8h , v2.8h      //weight 1 mult. for rows 1,2\n    mla       v8.8h, v10.8h , v4.8h     //weight 2 mult. for rows 1,2\n    srshl     v8.8h, v8.8h , v0.8h      //rounds off the weighted samples from rows 1,2\n    add       v8.8h, v8.8h , v6.8h      //adding offset for rows 1,2\n    sqxtun    v8.8b, v8.8h              //saturating rows 1,2 to unsigned 8-bit/\n    st1       {v8.s}[0], [x2], x5       //store row 1 in destination\n    st1       {v8.s}[1], [x2], x5       //store row 2 in destination\n    subs      w11, w11, #2              //decrement ht by 2\n    bgt       loop_2_uv                 //if greater than 0 repeat the loop again\n    b         end_loops_uv\n\nloop_4_uv:                              //each iteration processes two rows\n\n    ld1       {v8.8b}, [x0], x3         //load row 1 in source 1\n    ld1       {v10.8b}, [x1], x4        //load row 1 in source 2\n    uxtl      v8.8h, v8.8b              //converting row 1 in source 1 to 16-bit\n    ld1       {v12.8b}, [x0], x3        //load row 2 in source 1\n    uxtl      v10.8h, v10.8b            //converting row 1 in source 2 to 16-bit\n    ld1       {v14.8b}, [x1], x4        //load row 2 in source 2\n    uxtl      v12.8h, v12.8b            //converting row 2 in source 1 to 16-bit\n    mul       v8.8h, v8.8h , v2.8h      //weight 1 mult. for row 1\n    mla       v8.8h, v10.8h , v4.8h     //weight 2 mult. for row 1\n    uxtl      v14.8h, v14.8b            //converting row 2 in source 2 to 16-bit\n    mul       v12.8h, v12.8h , v2.8h    //weight 1 mult. for row 2\n    mla       v12.8h, v14.8h , v4.8h    //weight 2 mult. for row 2\n    subs      w11, w11, #2              //decrement ht by 2\n    srshl     v8.8h, v8.8h , v0.8h      //rounds off the weighted samples from row 1\n    srshl     v12.8h, v12.8h , v0.8h    //rounds off the weighted samples from row 2\n    add       v8.8h, v8.8h , v6.8h      //adding offset for row 1\n    add       v12.8h, v12.8h , v6.8h    //adding offset for row 2\n    sqxtun    v8.8b, v8.8h              //saturating row 1 to unsigned 8-bit\n    sqxtun    v12.8b, v12.8h            //saturating row 2 to unsigned 8-bit\n    st1       {v8.8b}, [x2], x5         //store row 1 in destination\n    st1       {v12.8b}, [x2], x5        //store row 2 in destination\n    bgt       loop_4_uv                 //if greater than 0 repeat the loop again\n    b         end_loops_uv\n\nloop_8_uv:                              //each iteration processes two rows\n\n    ld1       {v8.8b, v9.8b}, [x0], x3  //load row 1 in source 1\n    ld1       {v10.8b, v11.8b}, [x1], x4 //load row 1 in source 2\n    ld1       {v12.8b, v13.8b}, [x0], x3 //load row 2 in source 1\n    ld1       {v14.8b, v15.8b}, [x1], x4 //load row 2 in source 2\n    uxtl      v24.8h, v8.8b             //converting row 1L in source 1 to 16-bit\n    ld1       {v16.8b, v17.8b}, [x0], x3 //load row 3 in source 1\n    ld1       {v18.8b, v19.8b}, [x1], x4 //load row 3 in source 2\n    uxtl      v26.8h, v10.8b            //converting row 1L in source 2 to 16-bit\n    ld1       {v20.8b, v21.8b}, [x0], x3 //load row 4 in source 1\n    ld1       {v22.8b, v23.8b}, [x1], x4 //load row 4 in source 2\n    uxtl      v8.8h, v9.8b              //converting row 1H in source 1 to 16-bit\n    uxtl      v10.8h, v11.8b            //converting row 1H in source 2 to 16-bit\n    mul       v24.8h, v24.8h , v2.8h    //weight 1 mult. for row 1L\n    mla       v24.8h, v26.8h , v4.8h    //weight 2 mult. for row 1L\n    uxtl      v28.8h, v12.8b            //converting row 2L in source 1 to 16-bit\n    uxtl      v30.8h, v14.8b            //converting row 2L in source 2 to 16-bit\n    mul       v8.8h, v8.8h , v2.8h      //weight 1 mult. for row 1H\n    mla       v8.8h, v10.8h , v4.8h     //weight 2 mult. for row 1H\n    uxtl      v12.8h, v13.8b            //converting row 2H in source 1 to 16-bit\n    uxtl      v14.8h, v15.8b            //converting row 2H in source 2 to 16-bit\n    mul       v28.8h, v28.8h , v2.8h    //weight 1 mult. for row 2L\n    mla       v28.8h, v30.8h , v4.8h    //weight 2 mult. for row 2L\n    uxtl      v26.8h, v16.8b            //converting row 3L in source 1 to 16-bit\n    uxtl      v10.8h, v18.8b            //converting row 3L in source 2 to 16-bit\n    mul       v12.8h, v12.8h , v2.8h    //weight 1 mult. for row 2H\n    mla       v12.8h, v14.8h , v4.8h    //weight 2 mult. for row 2H\n    uxtl      v16.8h, v17.8b            //converting row 3H in source 1 to 16-bit\n    uxtl      v18.8h, v19.8b            //converting row 3H in source 2 to 16-bit\n    mul       v26.8h, v26.8h , v2.8h    //weight 1 mult. for row 3L\n    mla       v26.8h, v10.8h , v4.8h    //weight 2 mult. for row 3L\n    uxtl      v30.8h, v20.8b            //converting row 4L in source 1 to 16-bit\n    uxtl      v14.8h, v22.8b            //converting row 4L in source 2 to 16-bit\n    mul       v16.8h, v16.8h , v2.8h    //weight 1 mult. for row 3H\n    mla       v16.8h, v18.8h , v4.8h    //weight 2 mult. for row 3H\n    uxtl      v20.8h, v21.8b            //converting row 4H in source 1 to 16-bit\n    uxtl      v22.8h, v23.8b            //converting row 4H in source 2 to 16-bit\n    mul       v30.8h, v30.8h , v2.8h    //weight 1 mult. for row 4L\n    mla       v30.8h, v14.8h , v4.8h    //weight 2 mult. for row 4L\n    srshl     v24.8h, v24.8h , v0.8h    //rounds off the weighted samples from row 1L\n    mul       v20.8h, v20.8h , v2.8h    //weight 1 mult. for row 4H\n    mla       v20.8h, v22.8h , v4.8h    //weight 2 mult. for row 4H\n    srshl     v8.8h, v8.8h , v0.8h      //rounds off the weighted samples from row 1H\n    srshl     v28.8h, v28.8h , v0.8h    //rounds off the weighted samples from row 2L\n    add       v24.8h, v24.8h , v6.8h    //adding offset for row 1L\n    srshl     v12.8h, v12.8h , v0.8h    //rounds off the weighted samples from row 2H\n    add       v8.8h, v8.8h , v6.8h      //adding offset for row 1H\n    srshl     v26.8h, v26.8h , v0.8h    //rounds off the weighted samples from row 3L\n    add       v28.8h, v28.8h , v6.8h    //adding offset for row 2L\n    srshl     v16.8h, v16.8h , v0.8h    //rounds off the weighted samples from row 3H\n    add       v12.8h, v12.8h , v6.8h    //adding offset for row 2H\n    srshl     v30.8h, v30.8h , v0.8h    //rounds off the weighted samples from row 4L\n    add       v26.8h, v26.8h , v6.8h    //adding offset for row 3L\n    srshl     v20.8h, v20.8h , v0.8h    //rounds off the weighted samples from row 4H\n    add       v16.8h, v16.8h , v6.8h    //adding offset for row 3H\n    sqxtun    v10.8b, v24.8h            //saturating row 1L to unsigned 8-bit\n    add       v30.8h, v30.8h , v6.8h    //adding offset for row 4L\n    sqxtun    v11.8b, v8.8h             //saturating row 1H to unsigned 8-bit\n    add       v20.8h, v20.8h , v6.8h    //adding offset for row 4H\n    sqxtun    v18.8b, v28.8h            //saturating row 2L to unsigned 8-bit\n    sqxtun    v19.8b, v12.8h            //saturating row 2H to unsigned 8-bit\n    sqxtun    v14.8b, v26.8h            //saturating row 3L to unsigned 8-bit\n    sqxtun    v15.8b, v16.8h            //saturating row 3H to unsigned 8-bit\n    st1       {v10.8b, v11.8b}, [x2], x5 //store row 1 in destination\n    sqxtun    v22.8b, v30.8h            //saturating row 4L to unsigned 8-bit\n    sqxtun    v23.8b, v20.8h            //saturating row 4H to unsigned 8-bit\n    st1       {v18.8b, v19.8b}, [x2], x5 //store row 2 in destination\n    subs      w11, w11, #4              //decrement ht by 4\n    st1       {v14.8b, v15.8b}, [x2], x5 //store row 3 in destination\n    st1       {v22.8b, v23.8b}, [x2], x5 //store row 4 in destination\n    bgt       loop_8_uv                 //if greater than 0 repeat the loop again\n\nend_loops_uv:\n\n    // LDMFD sp!,{x4-x12,x15}                //Reload the registers from sp\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/ih264_weighted_pred_av8.s",
    "content": "//******************************************************************************\n//*\n//* Copyright (C) 2015 The Android Open Source Project\n//*\n//* Licensed under the Apache License, Version 2.0 (the \"License\");\n//* you may not use this file except in compliance with the License.\n//* You may obtain a copy of the License at:\n//*\n//* http://www.apache.org/licenses/LICENSE-2.0\n//*\n//* Unless required by applicable law or agreed to in writing, software\n//* distributed under the License is distributed on an \"AS IS\" BASIS,\n//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//* See the License for the specific language governing permissions and\n//* limitations under the License.\n//*\n//*****************************************************************************\n//* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n//*/\n///**\n//******************************************************************************\n//* @file\n//*  ih264_weighted_pred_av8.s\n//*\n//* @brief\n//*  Contains function definitions for weighted prediction.\n//*\n//* @author\n//*  Kaushik Senthoor R\n//*\n//* @par List of Functions:\n//*\n//*  - ih264_weighted_pred_luma_av8()\n//*  - ih264_weighted_pred_chroma_av8()\n//*\n//* @remarks\n//*  None\n//*\n//*******************************************************************************\n//*/\n//*******************************************************************************\n//* @function\n//*  ih264_weighted_pred_luma_av8()\n//*\n//* @brief\n//*  This routine performs the default weighted prediction as described in sec\n//* 8.4.2.3.2 titled \"Weighted sample prediction process\" for luma.\n//*\n//* @par Description:\n//*  This function gets a ht x wd block, calculates the weighted sample, rounds\n//* off, adds offset and stores it in the destination block.\n//*\n//* @param[in] puc_src:\n//*  UWORD8 Pointer to the buffer containing the input block.\n//*\n//* @param[out] puc_dst\n//*  UWORD8 pointer to the destination where the output block is stored.\n//*\n//* @param[in] src_strd\n//*  Stride of the input buffer\n//*\n//* @param[in] dst_strd\n//*  Stride of the destination buffer\n//*\n//* @param[in] log_WD\n//*  number of bits to be rounded off\n//*\n//* @param[in] wt\n//*  weight for the weighted prediction\n//*\n//* @param[in] ofst\n//*  offset used after rounding off\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  (ht,wd) can be (4,4), (4,8), (8,4), (8,8), (8,16), (16,8) or (16,16).\n//*\n//*******************************************************************************\n//*/\n//void ih264_weighted_pred_luma_av8(UWORD8 *puc_src,\n//                                  UWORD8 *puc_dst,\n//                                  WORD32 src_strd,\n//                                  WORD32 dst_strd,\n//                                  WORD32 log_WD,\n//                                  WORD32 wt,\n//                                  WORD32 ofst,\n//                                  WORD32 ht,\n//                                  WORD32 wd)\n//\n//**************Variables Vs Registers*****************************************\n//    x0      => puc_src\n//    x1      => puc_dst\n//    w2      => src_strd\n//    w3      => dst_strd\n//    w4      => log_WD\n//    w5      => wt\n//    w6      => ofst\n//    w7      => ht\n//    [sp]    => wd     (w8)\n//\n.text\n.p2align 2\n.include \"ih264_neon_macros.s\"\n\n\n\n    .global ih264_weighted_pred_luma_av8\n\nih264_weighted_pred_luma_av8:\n\n    // STMFD sp!, {x4-x9,x14}                //stack stores the values of the arguments\n    push_v_regs\n    sxtw      x2, w2\n    sxtw      x3, w3\n    stp       x19, x20, [sp, #-16]!\n    ldr       w8, [sp, #80]             //Load wd\n    sxtw      x8, w8\n\n    dup       v2.4h, w5                 //D2 = wt (16-bit)\n    neg       w9, w4                    //w9 = -log_WD\n    dup       v3.8b, w6                 //D3 = ofst (8-bit)\n    cmp       w8, #16                   //check if wd is 16\n    dup       v0.8h, w9                 //Q0 = -log_WD (16-bit)\n    beq       loop_16                   //branch if wd is 16\n\n    cmp       w8, #8                    //check if wd is 8\n    beq       loop_8                    //branch if wd is 8\n\nloop_4:                                 //each iteration processes four rows\n\n    ld1       {v4.s}[0], [x0], x2       //load row 1 in source\n    ld1       {v4.s}[1], [x0], x2       //load row 2 in source\n    ld1       {v6.s}[0], [x0], x2       //load row 3 in source\n    ld1       {v6.s}[1], [x0], x2       //load row 4 in source\n\n    uxtl      v4.8h, v4.8b              //converting rows 1,2 to 16-bit\n    uxtl      v6.8h, v6.8b              //converting rows 3,4 to 16-bit\n\n    mul       v4.8h, v4.8h , v2.h[0]    //weight mult. for rows 1,2\n    mul       v6.8h, v6.8h , v2.h[0]    //weight mult. for rows 3,4\n\n    subs      w7, w7, #4                //decrement ht by 4\n    srshl     v4.8h, v4.8h , v0.8h      //rounds off the weighted samples from rows 1,2\n    srshl     v6.8h, v6.8h , v0.8h      //rounds off the weighted samples from rows 3,4\n\n    saddw     v4.8h, v4.8h , v3.8b      //adding offset for rows 1,2\n    saddw     v6.8h, v6.8h , v3.8b      //adding offset for rows 3,4\n\n    sqxtun    v4.8b, v4.8h              //saturating rows 1,2 to unsigned 8-bit\n    sqxtun    v6.8b, v6.8h              //saturating rows 3,4 to unsigned 8-bit\n\n    st1       {v4.s}[0], [x1], x3       //store row 1 in destination\n    st1       {v4.s}[1], [x1], x3       //store row 2 in destination\n    st1       {v6.s}[0], [x1], x3       //store row 3 in destination\n    st1       {v6.s}[1], [x1], x3       //store row 4 in destination\n\n    bgt       loop_4                    //if greater than 0 repeat the loop again\n\n    b         end_loops\n\nloop_8:                                 //each iteration processes four rows\n\n    ld1       {v4.8b}, [x0], x2         //load row 1 in source\n    ld1       {v6.8b}, [x0], x2         //load row 2 in source\n    ld1       {v8.8b}, [x0], x2         //load row 3 in source\n    uxtl      v4.8h, v4.8b              //converting row 1 to 16-bit\n    ld1       {v10.8b}, [x0], x2        //load row 4 in source\n    uxtl      v6.8h, v6.8b              //converting row 2 to 16-bit\n\n    uxtl      v8.8h, v8.8b              //converting row 3 to 16-bit\n    mul       v4.8h, v4.8h , v2.h[0]    //weight mult. for row 1\n    uxtl      v10.8h, v10.8b            //converting row 4 to 16-bit\n    mul       v6.8h, v6.8h , v2.h[0]    //weight mult. for row 2\n    mul       v8.8h, v8.8h , v2.h[0]    //weight mult. for row 3\n    mul       v10.8h, v10.8h , v2.h[0]  //weight mult. for row 4\n\n    srshl     v4.8h, v4.8h , v0.8h      //rounds off the weighted samples from row 1\n    srshl     v6.8h, v6.8h , v0.8h      //rounds off the weighted samples from row 2\n    srshl     v8.8h, v8.8h , v0.8h      //rounds off the weighted samples from row 3\n    saddw     v4.8h, v4.8h , v3.8b      //adding offset for row 1\n    srshl     v10.8h, v10.8h , v0.8h    //rounds off the weighted samples from row 4\n    saddw     v6.8h, v6.8h , v3.8b      //adding offset for row 2\n\n    saddw     v8.8h, v8.8h , v3.8b      //adding offset for row 3\n    sqxtun    v4.8b, v4.8h              //saturating row 1 to unsigned 8-bit\n    saddw     v10.8h, v10.8h , v3.8b    //adding offset for row 4\n    sqxtun    v6.8b, v6.8h              //saturating row 2 to unsigned 8-bit\n    sqxtun    v8.8b, v8.8h              //saturating row 3 to unsigned 8-bit\n    sqxtun    v10.8b, v10.8h            //saturating row 4 to unsigned 8-bit\n\n    st1       {v4.8b}, [x1], x3         //store row 1 in destination\n    st1       {v6.8b}, [x1], x3         //store row 2 in destination\n    subs      w7, w7, #4                //decrement ht by 4\n    st1       {v8.8b}, [x1], x3         //store row 3 in destination\n    st1       {v10.8b}, [x1], x3        //store row 4 in destination\n\n    bgt       loop_8                    //if greater than 0 repeat the loop again\n\n    b         end_loops\n\nloop_16:                                //each iteration processes two rows\n\n    ld1       {v4.8b, v5.8b}, [x0], x2  //load row 1 in source\n    ld1       {v6.8b, v7.8b}, [x0], x2  //load row 2 in source\n    uxtl      v12.8h, v4.8b             //converting row 1L to 16-bit\n    ld1       {v8.8b, v9.8b}, [x0], x2  //load row 3 in source\n    uxtl      v14.8h, v5.8b             //converting row 1H to 16-bit\n    ld1       {v10.8b, v11.8b}, [x0], x2 //load row 4 in source\n    uxtl      v16.8h, v6.8b             //converting row 2L to 16-bit\n    mul       v12.8h, v12.8h , v2.h[0]  //weight mult. for row 1L\n    uxtl      v18.8h, v7.8b             //converting row 2H to 16-bit\n    mul       v14.8h, v14.8h , v2.h[0]  //weight mult. for row 1H\n    uxtl      v20.8h, v8.8b             //converting row 3L to 16-bit\n    mul       v16.8h, v16.8h , v2.h[0]  //weight mult. for row 2L\n    uxtl      v22.8h, v9.8b             //converting row 3H to 16-bit\n    mul       v18.8h, v18.8h , v2.h[0]  //weight mult. for row 2H\n    uxtl      v24.8h, v10.8b            //converting row 4L to 16-bit\n    mul       v20.8h, v20.8h , v2.h[0]  //weight mult. for row 3L\n    uxtl      v26.8h, v11.8b            //converting row 4H to 16-bit\n    mul       v22.8h, v22.8h , v2.h[0]  //weight mult. for row 3H\n    mul       v24.8h, v24.8h , v2.h[0]  //weight mult. for row 4L\n    srshl     v12.8h, v12.8h , v0.8h    //rounds off the weighted samples from row 1L\n    mul       v26.8h, v26.8h , v2.h[0]  //weight mult. for row 4H\n    srshl     v14.8h, v14.8h , v0.8h    //rounds off the weighted samples from row 1H\n    srshl     v16.8h, v16.8h , v0.8h    //rounds off the weighted samples from row 2L\n    saddw     v12.8h, v12.8h , v3.8b    //adding offset for row 1L\n    srshl     v18.8h, v18.8h , v0.8h    //rounds off the weighted samples from row 2H\n    saddw     v14.8h, v14.8h , v3.8b    //adding offset for row 1H\n    sqxtun    v4.8b, v12.8h             //saturating row 1L to unsigned 8-bit\n    srshl     v20.8h, v20.8h , v0.8h    //rounds off the weighted samples from row 3L\n    saddw     v16.8h, v16.8h , v3.8b    //adding offset for row 2L\n    sqxtun    v5.8b, v14.8h             //saturating row 1H to unsigned 8-bit\n    srshl     v22.8h, v22.8h , v0.8h    //rounds off the weighted samples from row 3H\n    saddw     v18.8h, v18.8h , v3.8b    //adding offset for row 2H\n    sqxtun    v6.8b, v16.8h             //saturating row 2L to unsigned 8-bit\n    srshl     v24.8h, v24.8h , v0.8h    //rounds off the weighted samples from row 4L\n    saddw     v20.8h, v20.8h , v3.8b    //adding offset for row 3L\n    sqxtun    v7.8b, v18.8h             //saturating row 2H to unsigned 8-bit\n    srshl     v26.8h, v26.8h , v0.8h    //rounds off the weighted samples from row 4H\n    saddw     v22.8h, v22.8h , v3.8b    //adding offset for row 3H\n    sqxtun    v8.8b, v20.8h             //saturating row 3L to unsigned 8-bit\n    saddw     v24.8h, v24.8h , v3.8b    //adding offset for row 4L\n    sqxtun    v9.8b, v22.8h             //saturating row 3H to unsigned 8-bit\n    saddw     v26.8h, v26.8h , v3.8b    //adding offset for row 4H\n    sqxtun    v10.8b, v24.8h            //saturating row 4L to unsigned 8-bit\n    st1       {v4.8b, v5.8b}, [x1], x3  //store row 1 in destination\n    sqxtun    v11.8b, v26.8h            //saturating row 4H to unsigned 8-bit\n    st1       {v6.8b, v7.8b}, [x1], x3  //store row 2 in destination\n    subs      w7, w7, #4                //decrement ht by 4\n    st1       {v8.8b, v9.8b}, [x1], x3  //store row 3 in destination\n    st1       {v10.8b, v11.8b}, [x1], x3 //store row 4 in destination\n\n    bgt       loop_16                   //if greater than 0 repeat the loop again\n\nend_loops:\n\n    // LDMFD sp!,{x4-x9,x15}                      //Reload the registers from sp\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n//*******************************************************************************\n//* @function\n//*  ih264_weighted_pred_chroma_av8()\n//*\n//* @brief\n//*  This routine performs the default weighted prediction as described in sec\n//* 8.4.2.3.2 titled \"Weighted sample prediction process\" for chroma.\n//*\n//* @par Description:\n//*  This function gets a ht x wd block, calculates the weighted sample, rounds\n//* off, adds offset and stores it in the destination block for U and V.\n//*\n//* @param[in] puc_src:\n//*  UWORD8 Pointer to the buffer containing the input block.\n//*\n//* @param[out] puc_dst\n//*  UWORD8 pointer to the destination where the output block is stored.\n//*\n//* @param[in] src_strd\n//*  Stride of the input buffer\n//*\n//* @param[in] dst_strd\n//*  Stride of the destination buffer\n//*\n//* @param[in] log_WD\n//*  number of bits to be rounded off\n//*\n//* @param[in] wt\n//*  weights for the weighted prediction for U and V\n//*\n//* @param[in] ofst\n//*  offsets used after rounding off for U and V\n//*\n//* @param[in] ht\n//*  integer height of the array\n//*\n//* @param[in] wd\n//*  integer width of the array\n//*\n//* @returns\n//*  None\n//*\n//* @remarks\n//*  (ht,wd) can be (2,2), (2,4), (4,2), (4,4), (4,8), (8,4) or (8,8).\n//*\n//*******************************************************************************\n//*/\n//void ih264_weighted_pred_chroma_av8(UWORD8 *puc_src,\n//                                    UWORD8 *puc_dst,\n//                                    WORD32 src_strd,\n//                                    WORD32 dst_strd,\n//                                    WORD32 log_WD,\n//                                    WORD32 wt,\n//                                    WORD32 ofst,\n//                                    WORD32 ht,\n//                                    WORD32 wd)\n//\n//**************Variables Vs Registers*****************************************\n//    x0      => puc_src\n//    x1      => puc_dst\n//    w2      => src_strd\n//    w3      => dst_strd\n//    w4      => log_WD\n//    w5      => wt\n//    w6      => ofst\n//    w7      => ht\n//    [sp]    => wd     (w8)\n//\n\n\n\n\n    .global ih264_weighted_pred_chroma_av8\n\nih264_weighted_pred_chroma_av8:\n\n    // STMFD sp!, {x4-x9,x14}                //stack stores the values of the arguments\n    push_v_regs\n    sxtw      x2, w2\n    sxtw      x3, w3\n    stp       x19, x20, [sp, #-16]!\n\n    ldr       w8, [sp, #80]             //Load wd\n    sxtw      x8, w8\n\n    neg       w9, w4                    //w9 = -log_WD\n    dup       v2.4s, w5                 //Q1 = {wt_u (16-bit), wt_v (16-bit)}\n\n\n    dup       v4.4h, w6                 //D4 = {ofst_u (8-bit), ofst_v (8-bit)}\n    cmp       w8, #8                    //check if wd is 8\n    dup       v0.8h, w9                 //Q0 = -log_WD (16-bit)\n    beq       loop_8_uv                 //branch if wd is 8\n\n    cmp       w8, #4                    //check if ws is 4\n    beq       loop_4_uv                 //branch if wd is 4\n\nloop_2_uv:                              //each iteration processes two rows\n\n    ld1       {v6.s}[0], [x0], x2       //load row 1 in source\n    ld1       {v6.s}[1], [x0], x2       //load row 2 in source\n    uxtl      v6.8h, v6.8b              //converting rows 1,2 to 16-bit\n    mul       v6.8h, v6.8h , v2.8h      //weight mult. for rows 1,2\n    srshl     v6.8h, v6.8h , v0.8h      //rounds off the weighted samples from rows 1,2\n    saddw     v6.8h, v6.8h , v4.8b      //adding offset for rows 1,2\n    sqxtun    v6.8b, v6.8h              //saturating rows 1,2 to unsigned 8-bit\n    subs      w7, w7, #2                //decrement ht by 2\n    st1       {v6.s}[0], [x1], x3       //store row 1 in destination\n    st1       {v6.s}[1], [x1], x3       //store row 2 in destination\n    bgt       loop_2_uv                 //if greater than 0 repeat the loop again\n    b         end_loops_uv\n\nloop_4_uv:                              //each iteration processes two rows\n\n    ld1       {v6.8b}, [x0], x2         //load row 1 in source\n    ld1       {v8.8b}, [x0], x2         //load row 2 in source\n    uxtl      v6.8h, v6.8b              //converting row 1 to 16-bit\n    uxtl      v8.8h, v8.8b              //converting row 2 to 16-bit\n    mul       v6.8h, v6.8h , v2.8h      //weight mult. for row 1\n    mul       v8.8h, v8.8h , v2.8h      //weight mult. for row 2\n    subs      w7, w7, #2                //decrement ht by 2\n    srshl     v6.8h, v6.8h , v0.8h      //rounds off the weighted samples from row 1\n    srshl     v8.8h, v8.8h , v0.8h      //rounds off the weighted samples from row 2\n    saddw     v6.8h, v6.8h , v4.8b      //adding offset for row 1\n    saddw     v8.8h, v8.8h , v4.8b      //adding offset for row 2\n    sqxtun    v6.8b, v6.8h              //saturating row 1 to unsigned 8-bit\n    sqxtun    v8.8b, v8.8h              //saturating row 2 to unsigned 8-bit\n    st1       {v6.8b}, [x1], x3         //store row 1 in destination\n    st1       {v8.8b}, [x1], x3         //store row 2 in destination\n\n    bgt       loop_4_uv                 //if greater than 0 repeat the loop again\n\n    b         end_loops_uv\n\nloop_8_uv:                              //each iteration processes two rows\n\n    ld1       {v6.8b, v7.8b}, [x0], x2  //load row 1 in source\n    ld1       {v8.8b, v9.8b}, [x0], x2  //load row 2 in source\n    uxtl      v14.8h, v6.8b             //converting row 1L to 16-bit\n    ld1       {v10.8b, v11.8b}, [x0], x2 //load row 3 in source\n    uxtl      v16.8h, v7.8b             //converting row 1H to 16-bit\n    ld1       {v12.8b, v13.8b}, [x0], x2 //load row 4 in source\n\n    mul       v14.8h, v14.8h , v2.8h    //weight mult. for row 1L\n    uxtl      v18.8h, v8.8b             //converting row 2L to 16-bit\n    mul       v16.8h, v16.8h , v2.8h    //weight mult. for row 1H\n    uxtl      v20.8h, v9.8b             //converting row 2H to 16-bit\n    mul       v18.8h, v18.8h , v2.8h    //weight mult. for row 2L\n    uxtl      v22.8h, v10.8b            //converting row 3L to 16-bit\n    mul       v20.8h, v20.8h , v2.8h    //weight mult. for row 2H\n    uxtl      v24.8h, v11.8b            //converting row 3H to 16-bit\n    mul       v22.8h, v22.8h , v2.8h    //weight mult. for row 3L\n    uxtl      v26.8h, v12.8b            //converting row 4L to 16-bit\n    mul       v24.8h, v24.8h , v2.8h    //weight mult. for row 3H\n    uxtl      v28.8h, v13.8b            //converting row 4H to 16-bit\n\n    mul       v26.8h, v26.8h , v2.8h    //weight mult. for row 4L\n    srshl     v14.8h, v14.8h , v0.8h    //rounds off the weighted samples from row 1L\n    mul       v28.8h, v28.8h , v2.8h    //weight mult. for row 4H\n\n    srshl     v16.8h, v16.8h , v0.8h    //rounds off the weighted samples from row 1H\n    srshl     v18.8h, v18.8h , v0.8h    //rounds off the weighted samples from row 2L\n    saddw     v14.8h, v14.8h , v4.8b    //adding offset for row 1L\n    srshl     v20.8h, v20.8h , v0.8h    //rounds off the weighted samples from row 2H\n    saddw     v16.8h, v16.8h , v4.8b    //adding offset for row 1H\n    sqxtun    v6.8b, v14.8h             //saturating row 1L to unsigned 8-bit\n    srshl     v22.8h, v22.8h , v0.8h    //rounds off the weighted samples from row 3L\n    saddw     v18.8h, v18.8h , v4.8b    //adding offset for row 2L\n    sqxtun    v7.8b, v16.8h             //saturating row 1H to unsigned 8-bit\n    srshl     v24.8h, v24.8h , v0.8h    //rounds off the weighted samples from row 3H\n    saddw     v20.8h, v20.8h , v4.8b    //adding offset for row 2H\n    sqxtun    v8.8b, v18.8h             //saturating row 2L to unsigned 8-bit\n    srshl     v26.8h, v26.8h , v0.8h    //rounds off the weighted samples from row 4L\n    saddw     v22.8h, v22.8h , v4.8b    //adding offset for row 3L\n    sqxtun    v9.8b, v20.8h             //saturating row 2H to unsigned 8-bit\n    srshl     v28.8h, v28.8h , v0.8h    //rounds off the weighted samples from row 4H\n    saddw     v24.8h, v24.8h , v4.8b    //adding offset for row 3H\n\n    sqxtun    v10.8b, v22.8h            //saturating row 3L to unsigned 8-bit\n    saddw     v26.8h, v26.8h , v4.8b    //adding offset for row 4L\n    sqxtun    v11.8b, v24.8h            //saturating row 3H to unsigned 8-bit\n    saddw     v28.8h, v28.8h , v4.8b    //adding offset for row 4H\n\n    sqxtun    v12.8b, v26.8h            //saturating row 4L to unsigned 8-bit\n    st1       {v6.8b, v7.8b}, [x1], x3  //store row 1 in destination\n    sqxtun    v13.8b, v28.8h            //saturating row 4H to unsigned 8-bit\n    st1       {v8.8b, v9.8b}, [x1], x3  //store row 2 in destination\n    subs      w7, w7, #4                //decrement ht by 4\n    st1       {v10.8b, v11.8b}, [x1], x3 //store row 3 in destination\n    st1       {v12.8b, v13.8b}, [x1], x3 //store row 4 in destination\n\n    bgt       loop_8_uv                 //if greater than 0 repeat the loop again\n\nend_loops_uv:\n\n    // LDMFD sp!,{x4-x9,x15}                      //Reload the registers from sp\n    ldp       x19, x20, [sp], #16\n    pop_v_regs\n    ret\n\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/armv8/macos_arm_symbol_aliases.s",
    "content": "// macOS clang compilers append preceding underscores to function names, this is to prevent\n// mismatches with the assembly function names and the C functions as defined in the header.\n\n.global _ih264_deblk_chroma_horz_bs4_av8\n_ih264_deblk_chroma_horz_bs4_av8 = ih264_deblk_chroma_horz_bs4_av8\n\n.global _ih264_deblk_chroma_horz_bslt4_av8\n_ih264_deblk_chroma_horz_bslt4_av8 = ih264_deblk_chroma_horz_bslt4_av8\n\n.global _ih264_deblk_chroma_vert_bs4_av8\n_ih264_deblk_chroma_vert_bs4_av8 = ih264_deblk_chroma_vert_bs4_av8\n\n.global _ih264_deblk_chroma_vert_bslt4_av8\n_ih264_deblk_chroma_vert_bslt4_av8 = ih264_deblk_chroma_vert_bslt4_av8\n\n.global _ih264_deblk_luma_horz_bs4_av8\n_ih264_deblk_luma_horz_bs4_av8 = ih264_deblk_luma_horz_bs4_av8\n\n.global _ih264_deblk_luma_horz_bslt4_av8\n_ih264_deblk_luma_horz_bslt4_av8 = ih264_deblk_luma_horz_bslt4_av8\n\n.global _ih264_deblk_luma_vert_bs4_av8\n_ih264_deblk_luma_vert_bs4_av8 = ih264_deblk_luma_vert_bs4_av8\n\n.global _ih264_deblk_luma_vert_bslt4_av8\n_ih264_deblk_luma_vert_bslt4_av8 = ih264_deblk_luma_vert_bslt4_av8\n\n.global _ih264_default_weighted_pred_chroma_av8\n_ih264_default_weighted_pred_chroma_av8 = ih264_default_weighted_pred_chroma_av8\n\n.global _ih264_default_weighted_pred_luma_av8\n_ih264_default_weighted_pred_luma_av8 = ih264_default_weighted_pred_luma_av8\n\n.global _ih264_ihadamard_scaling_4x4_av8\n_ih264_ihadamard_scaling_4x4_av8 = ih264_ihadamard_scaling_4x4_av8\n\n.global _ih264_inter_pred_chroma_av8\n_ih264_inter_pred_chroma_av8 = ih264_inter_pred_chroma_av8\n\n.global _ih264_inter_pred_luma_copy_av8\n_ih264_inter_pred_luma_copy_av8 = ih264_inter_pred_luma_copy_av8\n\n.global _ih264_inter_pred_luma_horz_av8\n_ih264_inter_pred_luma_horz_av8 = ih264_inter_pred_luma_horz_av8\n\n.global _ih264_inter_pred_luma_horz_hpel_vert_hpel_av8\n_ih264_inter_pred_luma_horz_hpel_vert_hpel_av8 = ih264_inter_pred_luma_horz_hpel_vert_hpel_av8\n\n.global _ih264_inter_pred_luma_horz_hpel_vert_qpel_av8\n_ih264_inter_pred_luma_horz_hpel_vert_qpel_av8 = ih264_inter_pred_luma_horz_hpel_vert_qpel_av8\n\n.global _ih264_inter_pred_luma_horz_qpel_av8\n_ih264_inter_pred_luma_horz_qpel_av8 = ih264_inter_pred_luma_horz_qpel_av8\n\n.global _ih264_inter_pred_luma_horz_qpel_vert_hpel_av8\n_ih264_inter_pred_luma_horz_qpel_vert_hpel_av8 = ih264_inter_pred_luma_horz_qpel_vert_hpel_av8\n\n.global _ih264_inter_pred_luma_horz_qpel_vert_qpel_av8\n_ih264_inter_pred_luma_horz_qpel_vert_qpel_av8 = ih264_inter_pred_luma_horz_qpel_vert_qpel_av8\n\n.global _ih264_inter_pred_luma_vert_av8\n_ih264_inter_pred_luma_vert_av8 = ih264_inter_pred_luma_vert_av8\n\n.global _ih264_inter_pred_luma_vert_qpel_av8\n_ih264_inter_pred_luma_vert_qpel_av8 = ih264_inter_pred_luma_vert_qpel_av8\n\n.global _ih264_intra_pred_chroma_8x8_mode_horz_av8\n_ih264_intra_pred_chroma_8x8_mode_horz_av8 = ih264_intra_pred_chroma_8x8_mode_horz_av8\n\n.global _ih264_intra_pred_chroma_8x8_mode_plane_av8\n_ih264_intra_pred_chroma_8x8_mode_plane_av8 = ih264_intra_pred_chroma_8x8_mode_plane_av8\n\n.global _ih264_intra_pred_chroma_8x8_mode_vert_av8\n_ih264_intra_pred_chroma_8x8_mode_vert_av8 = ih264_intra_pred_chroma_8x8_mode_vert_av8\n\n.global _ih264_intra_pred_luma_16x16_mode_dc_av8\n_ih264_intra_pred_luma_16x16_mode_dc_av8 = ih264_intra_pred_luma_16x16_mode_dc_av8\n\n.global _ih264_intra_pred_luma_16x16_mode_horz_av8\n_ih264_intra_pred_luma_16x16_mode_horz_av8 = ih264_intra_pred_luma_16x16_mode_horz_av8\n\n.global _ih264_intra_pred_luma_16x16_mode_plane_av8\n_ih264_intra_pred_luma_16x16_mode_plane_av8 = ih264_intra_pred_luma_16x16_mode_plane_av8\n\n.global _ih264_intra_pred_luma_16x16_mode_vert_av8\n_ih264_intra_pred_luma_16x16_mode_vert_av8 = ih264_intra_pred_luma_16x16_mode_vert_av8\n\n.global _ih264_intra_pred_luma_4x4_mode_dc_av8\n_ih264_intra_pred_luma_4x4_mode_dc_av8 = ih264_intra_pred_luma_4x4_mode_dc_av8\n\n.global _ih264_intra_pred_luma_4x4_mode_diag_dl_av8\n_ih264_intra_pred_luma_4x4_mode_diag_dl_av8 = ih264_intra_pred_luma_4x4_mode_diag_dl_av8\n\n.global _ih264_intra_pred_luma_4x4_mode_diag_dr_av8\n_ih264_intra_pred_luma_4x4_mode_diag_dr_av8 = ih264_intra_pred_luma_4x4_mode_diag_dr_av8\n\n.global _ih264_intra_pred_luma_4x4_mode_horz_av8\n_ih264_intra_pred_luma_4x4_mode_horz_av8 = ih264_intra_pred_luma_4x4_mode_horz_av8\n\n.global _ih264_intra_pred_luma_4x4_mode_horz_d_av8\n_ih264_intra_pred_luma_4x4_mode_horz_d_av8 = ih264_intra_pred_luma_4x4_mode_horz_d_av8\n\n.global _ih264_intra_pred_luma_4x4_mode_horz_u_av8\n_ih264_intra_pred_luma_4x4_mode_horz_u_av8 = ih264_intra_pred_luma_4x4_mode_horz_u_av8\n\n.global _ih264_intra_pred_luma_4x4_mode_vert_av8\n_ih264_intra_pred_luma_4x4_mode_vert_av8 = ih264_intra_pred_luma_4x4_mode_vert_av8\n\n.global _ih264_intra_pred_luma_4x4_mode_vert_l_av8\n_ih264_intra_pred_luma_4x4_mode_vert_l_av8 = ih264_intra_pred_luma_4x4_mode_vert_l_av8\n\n.global _ih264_intra_pred_luma_4x4_mode_vert_r_av8\n_ih264_intra_pred_luma_4x4_mode_vert_r_av8 = ih264_intra_pred_luma_4x4_mode_vert_r_av8\n\n.global _ih264_intra_pred_luma_8x8_mode_dc_av8\n_ih264_intra_pred_luma_8x8_mode_dc_av8 = ih264_intra_pred_luma_8x8_mode_dc_av8\n\n.global _ih264_intra_pred_luma_8x8_mode_diag_dl_av8\n_ih264_intra_pred_luma_8x8_mode_diag_dl_av8 = ih264_intra_pred_luma_8x8_mode_diag_dl_av8\n\n.global _ih264_intra_pred_luma_8x8_mode_diag_dr_av8\n_ih264_intra_pred_luma_8x8_mode_diag_dr_av8 = ih264_intra_pred_luma_8x8_mode_diag_dr_av8\n\n.global _ih264_intra_pred_luma_8x8_mode_horz_av8\n_ih264_intra_pred_luma_8x8_mode_horz_av8 = ih264_intra_pred_luma_8x8_mode_horz_av8\n\n.global _ih264_intra_pred_luma_8x8_mode_horz_d_av8\n_ih264_intra_pred_luma_8x8_mode_horz_d_av8 = ih264_intra_pred_luma_8x8_mode_horz_d_av8\n\n.global _ih264_intra_pred_luma_8x8_mode_horz_u_av8\n_ih264_intra_pred_luma_8x8_mode_horz_u_av8 = ih264_intra_pred_luma_8x8_mode_horz_u_av8\n\n.global _ih264_intra_pred_luma_8x8_mode_vert_av8\n_ih264_intra_pred_luma_8x8_mode_vert_av8 = ih264_intra_pred_luma_8x8_mode_vert_av8\n\n.global _ih264_intra_pred_luma_8x8_mode_vert_l_av8\n_ih264_intra_pred_luma_8x8_mode_vert_l_av8 = ih264_intra_pred_luma_8x8_mode_vert_l_av8\n\n.global _ih264_intra_pred_luma_8x8_mode_vert_r_av8\n_ih264_intra_pred_luma_8x8_mode_vert_r_av8 = ih264_intra_pred_luma_8x8_mode_vert_r_av8\n\n.global _ih264_iquant_itrans_recon_4x4_av8\n_ih264_iquant_itrans_recon_4x4_av8 = ih264_iquant_itrans_recon_4x4_av8\n\n.global _ih264_iquant_itrans_recon_4x4_dc_av8\n_ih264_iquant_itrans_recon_4x4_dc_av8 = ih264_iquant_itrans_recon_4x4_dc_av8\n\n.global _ih264_iquant_itrans_recon_8x8_av8\n_ih264_iquant_itrans_recon_8x8_av8 = ih264_iquant_itrans_recon_8x8_av8\n\n.global _ih264_iquant_itrans_recon_8x8_dc_av8\n_ih264_iquant_itrans_recon_8x8_dc_av8 = ih264_iquant_itrans_recon_8x8_dc_av8\n\n.global _ih264_iquant_itrans_recon_chroma_4x4_av8\n_ih264_iquant_itrans_recon_chroma_4x4_av8 = ih264_iquant_itrans_recon_chroma_4x4_av8\n\n.global _ih264_iquant_itrans_recon_chroma_4x4_dc_av8\n_ih264_iquant_itrans_recon_chroma_4x4_dc_av8 = ih264_iquant_itrans_recon_chroma_4x4_dc_av8\n\n.global _ih264_pad_left_chroma_av8\n_ih264_pad_left_chroma_av8 = ih264_pad_left_chroma_av8\n\n.global _ih264_pad_left_luma_av8\n_ih264_pad_left_luma_av8 = ih264_pad_left_luma_av8\n\n.global _ih264_pad_right_chroma_av8\n_ih264_pad_right_chroma_av8 = ih264_pad_right_chroma_av8\n\n.global _ih264_pad_right_luma_av8\n_ih264_pad_right_luma_av8 = ih264_pad_right_luma_av8\n\n.global _ih264_pad_top_av8\n_ih264_pad_top_av8 = ih264_pad_top_av8\n\n.global _ih264_weighted_bi_pred_chroma_av8\n_ih264_weighted_bi_pred_chroma_av8 = ih264_weighted_bi_pred_chroma_av8\n\n.global _ih264_weighted_bi_pred_luma_av8\n_ih264_weighted_bi_pred_luma_av8 = ih264_weighted_bi_pred_luma_av8\n\n.global _ih264_weighted_pred_chroma_av8\n_ih264_weighted_pred_chroma_av8 = ih264_weighted_pred_chroma_av8\n\n.global _ih264_weighted_pred_luma_av8\n_ih264_weighted_pred_luma_av8 = ih264_weighted_pred_luma_av8"
  },
  {
    "path": "dependencies/ih264d/common/ih264_buf_mgr.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_buf_mgr.c\n*\n* @brief\n*  Contains function definitions for buffer management\n*\n* @author\n*  Srinivas T\n*\n* @par List of Functions:\n*   - ih264_buf_mgr_size()\n*   - ih264_buf_mgr_lock()\n*   - ih264_buf_mgr_unlock()\n*   - ih264_buf_mgr_yield()\n*   - ih264_buf_mgr_free()\n*   - ih264_buf_mgr_init()\n*   - ih264_buf_mgr_add()\n*   - ih264_buf_mgr_get_next_free()\n*   - ih264_buf_mgr_check_free()\n*   - ih264_buf_mgr_set_status()\n*   - ih264_buf_mgr_get_status()\n*   - ih264_buf_mgr_get_buf()\n*   - ih264_buf_mgr_get_bufid()\n*   - ih264_buf_mgr_get_num_active_buf()\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n#include <stdio.h>\n#include <stdlib.h>\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_error.h\"\n#include \"ih264_buf_mgr.h\"\n\n#include \"ithread.h\"\n\n/**\n*******************************************************************************\n*\n* @brief Returns size for buf queue context. Does not include buf queue buffer\n* requirements\n*\n* @par   Description\n* Returns size for buf queue context. Does not include buf queue buffer\n* requirements. Buffer size required to store the bufs should be allocated in\n* addition to the value returned here.\n*\n* @returns Size of the buf queue context\n*\n* @remarks\n*\n*******************************************************************************\n*/\nWORD32 ih264_buf_mgr_size(void)\n{\n    WORD32 size;\n\n    size = sizeof(buf_mgr_t);\n    size += ithread_get_mutex_lock_size();\n\n    return size;\n}\n\n/**\n*******************************************************************************\n*\n* @brief\n*   Locks the buf_mgr context\n*\n* @par   Description\n*   Locks the buf_mgr context by calling ithread_mutex_lock()\n*\n* @param[in] ps_buf_mgr\n*   Job Queue context\n*\n* @returns IH264_FAIL if mutex lock fails else IH264_SUCCESS\n*\n* @remarks\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_buf_mgr_lock(buf_mgr_t *ps_buf_mgr)\n{\n    WORD32 retval;\n    retval = ithread_mutex_lock(ps_buf_mgr->pv_mutex);\n    if(retval)\n    {\n        return IH264_FAIL;\n    }\n    return IH264_SUCCESS;\n}\n\n/**\n*******************************************************************************\n*\n* @brief\n*   Unlocks the buf_mgr context\n*\n* @par   Description\n*   Unlocks the buf_mgr context by calling ithread_mutex_unlock()\n*\n* @param[in] ps_buf_mgr\n*   Job Queue context\n*\n* @returns IH264_FAIL if mutex unlock fails else IH264_SUCCESS\n*\n* @remarks\n*\n*******************************************************************************\n*/\n\nIH264_ERROR_T ih264_buf_mgr_unlock(buf_mgr_t *ps_buf_mgr)\n{\n    WORD32 retval;\n    retval = ithread_mutex_unlock(ps_buf_mgr->pv_mutex);\n    if(retval)\n    {\n        return IH264_FAIL;\n    }\n    return IH264_SUCCESS;\n\n}\n/**\n*******************************************************************************\n*\n* @brief\n*   Yeilds the thread\n*\n* @par   Description\n*   Unlocks the buf_mgr context by calling\n* ih264_buf_mgr_unlock(), ithread_yield() and then ih264_buf_mgr_lock()\n* buf_mgr is unlocked before to ensure the buf_mgr can be accessed by other threads\n* If unlock is not done before calling yield then no other thread can access\n* the buf_mgr functions and update buf_mgr.\n*\n* @param[in] ps_buf_mgr\n*   Job Queue context\n*\n* @returns IH264_FAIL if mutex lock unlock or yield fails else IH264_SUCCESS\n*\n* @remarks\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_buf_mgr_yield(buf_mgr_t *ps_buf_mgr)\n{\n\n    IH264_ERROR_T ret = IH264_SUCCESS;\n\n    IH264_ERROR_T rettmp;\n    rettmp = ih264_buf_mgr_unlock(ps_buf_mgr);\n    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);\n\n    //ithread_usleep(10);\n    ithread_yield();\n\n    rettmp = ih264_buf_mgr_lock(ps_buf_mgr);\n    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);\n    return ret;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief free the buf queue pointers\n*\n* @par   Description\n* Frees the buf_mgr context\n*\n* @param[in] pv_buf\n* Memoy for buf queue buffer and buf queue context\n*\n* @returns Pointer to buf queue context\n*\n* @remarks\n* Since it will be called only once by master thread this is not thread safe.\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_buf_mgr_free(buf_mgr_t *ps_buf_mgr)\n{\n    WORD32 ret;\n    ret = ithread_mutex_destroy(ps_buf_mgr->pv_mutex);\n\n    if(0 == ret)\n        return IH264_SUCCESS;\n    else\n        return IH264_FAIL;\n}\n/**\n*******************************************************************************\n*\n* @brief\n*      Buffer manager initialization function.\n*\n* @par Description:\n*    Initializes the buffer manager structure\n*\n* @param[in] ps_buf_mgr\n*  Pointer to the buffer manager\n*\n* @returns\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n\nvoid *ih264_buf_mgr_init(void *pv_buf)\n{\n    WORD32 id;\n    UWORD8 *pu1_buf;\n    buf_mgr_t *ps_buf_mgr;\n    pu1_buf = (UWORD8 *)pv_buf;\n\n    ps_buf_mgr = (buf_mgr_t *)pu1_buf;\n    pu1_buf += sizeof(buf_mgr_t);\n\n    ps_buf_mgr->pv_mutex = pu1_buf;\n    pu1_buf += ithread_get_mutex_lock_size();\n\n    ithread_mutex_init(ps_buf_mgr->pv_mutex);\n\n    ps_buf_mgr->i4_max_buf_cnt = BUF_MGR_MAX_CNT;\n    ps_buf_mgr->i4_active_buf_cnt = 0;\n\n    for(id = 0; id < BUF_MGR_MAX_CNT; id++)\n    {\n        ps_buf_mgr->au4_status[id] = 0;\n        ps_buf_mgr->apv_ptr[id] = NULL;\n    }\n\n    return ps_buf_mgr;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*       Adds and increments the buffer and buffer count.\n*\n* @par Description:\n*     Adds a buffer to the buffer manager if it is not already  present and\n*   increments the  active buffer count\n*\n* @param[in] ps_buf_mgr\n*  Pointer to the buffer manager\n*\n* @param[in] pv_ptr\n*  Pointer to the buffer to be added\n*\n* @returns  Returns 0 on success, -1 otherwise\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_buf_mgr_add(buf_mgr_t *ps_buf_mgr,\n                                void *pv_ptr,\n                                WORD32 buf_id)\n{\n\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    ret = ih264_buf_mgr_lock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    /* Check if buffer ID is within allowed range */\n    if(buf_id >= ps_buf_mgr->i4_max_buf_cnt)\n    {\n        ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n        RETURN_IF((ret != IH264_SUCCESS), ret);\n\n        return IH264_FAIL;\n    }\n\n    /* Check if the current ID is being used to hold some other buffer */\n    if((ps_buf_mgr->apv_ptr[buf_id] != NULL) &&\n       (ps_buf_mgr->apv_ptr[buf_id] !=pv_ptr))\n    {\n        ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n        RETURN_IF((ret != IH264_SUCCESS), ret);\n\n        return IH264_FAIL;\n    }\n    ps_buf_mgr->apv_ptr[buf_id] = pv_ptr;\n    ps_buf_mgr->i4_active_buf_cnt++;\n\n    ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    return ret;\n}\n\n/**\n*******************************************************************************\n*\n* @brief\n*   Gets the next free buffer.\n*\n* @par Description:\n*     Returns the next free buffer available and sets the  corresponding status\n*   to DEC\n*\n* @param[in] ps_buf_mgr\n*  Pointer to the buffer manager\n*\n* @param[in] pi4_buf_id\n*  Pointer to the id of the free buffer\n*\n* @returns  Pointer to the free buffer\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nvoid* ih264_buf_mgr_get_next_free(buf_mgr_t *ps_buf_mgr, WORD32 *pi4_buf_id)\n{\n    WORD32 id;\n    void *pv_ret_ptr;\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    ret = ih264_buf_mgr_lock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), NULL);\n\n    pv_ret_ptr = NULL;\n    for(id = 0; id < ps_buf_mgr->i4_active_buf_cnt; id++)\n    {\n        /* Check if the buffer is non-null and status is zero */\n        if((ps_buf_mgr->au4_status[id] == 0) && (ps_buf_mgr->apv_ptr[id]))\n        {\n            *pi4_buf_id = id;\n            /* DEC is set to 1 */\n            ps_buf_mgr->au4_status[id] = 1;\n            pv_ret_ptr = ps_buf_mgr->apv_ptr[id];\n            break;\n        }\n    }\n    ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), NULL);\n\n    return pv_ret_ptr;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*      Checks the buffer manager for free buffers available.\n*\n* @par Description:\n*  Checks if there are any free buffers available\n*\n* @param[in] ps_buf_mgr\n*  Pointer to the buffer manager\n*\n* @returns  Returns 0 if available, -1 otherwise\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_buf_mgr_check_free(buf_mgr_t *ps_buf_mgr)\n{\n    WORD32 id;\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    IH264_ERROR_T rettmp = IH264_SUCCESS;\n    rettmp = ih264_buf_mgr_lock(ps_buf_mgr);\n    RETURN_IF((rettmp != IH264_SUCCESS), ret);\n\n    ret = IH264_FAIL;\n    for(id = 0; id < ps_buf_mgr->i4_active_buf_cnt; id++)\n    {\n        if((ps_buf_mgr->au4_status[id] == 0) &&\n           (ps_buf_mgr->apv_ptr[id]))\n        {\n            ret = IH264_SUCCESS;\n            break;\n        }\n    }\n    rettmp = ih264_buf_mgr_unlock(ps_buf_mgr);\n    RETURN_IF((rettmp != IH264_SUCCESS), ret);\n\n    return ret;\n\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*       Resets the status bits.\n*\n* @par Description:\n*     resets the status bits that the mask contains (status  corresponding to\n*    the id)\n*\n* @param[in] ps_buf_mgr\n*  Pointer to the buffer manager\n*\n* @param[in] buf_id\n*  ID of the buffer status to be released\n*\n* @param[in] mask\n*  Contains the bits that are to be reset\n*\n* @returns  0 if success, -1 otherwise\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_buf_mgr_release(buf_mgr_t *ps_buf_mgr,\n                                    WORD32 buf_id,\n                                    UWORD32 mask)\n{\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    ret = ih264_buf_mgr_lock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n\n    /* If the given id is pointing to an id which is not yet added */\n    if(buf_id >= ps_buf_mgr->i4_active_buf_cnt)\n    {\n        ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n        RETURN_IF((ret != IH264_SUCCESS), ret);\n        return IH264_FAIL;\n    }\n\n    ps_buf_mgr->au4_status[buf_id] &= ~mask;\n\n\n/*     If both the REF and DISP are zero, DEC is set to zero */\n    if(ps_buf_mgr->au4_status[buf_id] == 1)\n    {\n        ps_buf_mgr->au4_status[buf_id] = 0;\n    }\n\n\n    ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    return ret;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*      Sets the status bit.\n*\n* @par Description:\n*     sets the status bits that the mask contains (status  corresponding to the\n*    id)\n*\n*\n* @param[in] ps_buf_mgr\n*  Pointer to the buffer manager\n*\n* @param[in] buf_id\n*  ID of the buffer whose status needs to be modified\n*\n*\n* @param[in] mask\n*  Contains the bits that are to be set\n*\n* @returns  0 if success, -1 otherwise\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_buf_mgr_set_status(buf_mgr_t *ps_buf_mgr,\n                                       WORD32 buf_id,\n                                       UWORD32 mask)\n{\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    ret = ih264_buf_mgr_lock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    if(buf_id >= ps_buf_mgr->i4_active_buf_cnt)\n    {\n        ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n        RETURN_IF((ret != IH264_SUCCESS), ret);\n        return IH264_FAIL;\n    }\n\n\n    if((ps_buf_mgr->au4_status[buf_id] & mask) != 0)\n    {\n        ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n        RETURN_IF((ret != IH264_SUCCESS), ret);\n        return IH264_FAIL;\n    }\n\n    ps_buf_mgr->au4_status[buf_id] |= mask;\n    ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    return ret;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*   Returns the status of the buffer.\n*\n* @par Description:\n*  Returns the status of the buffer corresponding to the id\n*\n* @param[in] ps_buf_mgr\n*  Pointer to the buffer manager\n*\n* @param[in] buf_id\n*  ID of the buffer status required\n*\n* @returns  Status of the buffer corresponding to the id\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nWORD32 ih264_buf_mgr_get_status( buf_mgr_t *ps_buf_mgr, WORD32 buf_id )\n{\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    UWORD32 status;\n\n    ret = ih264_buf_mgr_lock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    status = ps_buf_mgr->au4_status[buf_id];\n\n    ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    return status;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*      Gets the buffer from the buffer manager\n*\n* @par Description:\n*        Returns the pointer to the buffer corresponding to the id\n*\n* @param[in] ps_buf_mgr\n*  Pointer to the buffer manager\n*\n* @param[in] buf_id\n*  ID of the buffer required\n*\n* @returns  Pointer to the buffer required\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nvoid* ih264_buf_mgr_get_buf(buf_mgr_t *ps_buf_mgr, WORD32 buf_id)\n{\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    void *pv_buf;\n    ret = ih264_buf_mgr_lock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), NULL);\n\n    pv_buf = ps_buf_mgr->apv_ptr[buf_id];\n\n    ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), NULL);\n\n    return pv_buf;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*  Gets the buffer id from the buffer manager if the buffer is added to the\n*  buffer manager\n*\n* @par Description:\n*  Returns the buffer id corresponding to the given buffer if it exists\n*\n* @param[in] ps_buf_mgr\n*  Pointer to the buffer manager\n*\n* @param[in] pv_buf\n*  Pointer to the buffer\n*\n* @returns  Buffer id if exists, else -1\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nWORD32 ih264_buf_mgr_get_bufid(buf_mgr_t *ps_buf_mgr, void *pv_buf)\n{\n    WORD32 id;\n    WORD32 buf_id = -1;\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    ret = ih264_buf_mgr_lock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    for(id = 0; id < ps_buf_mgr->i4_active_buf_cnt; id++)\n    {\n        if(ps_buf_mgr->apv_ptr[id] == pv_buf)\n        {\n            buf_id = id;\n            break;\n        }\n    }\n    ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    return buf_id;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*        Gets the no.of active buffer\n*\n* @par Description:\n*      Return the number of active buffers in the buffer manager\n*\n* @param[in] ps_buf_mgr\n*  Pointer to the buffer manager\n*\n* @returns  number of active buffers\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nUWORD32 ih264_buf_mgr_get_num_active_buf(buf_mgr_t *ps_buf_mgr)\n{\n    UWORD32 u4_buf_cnt;\n    IH264_ERROR_T ret = IH264_SUCCESS;\n\n    u4_buf_cnt = 0;\n\n    ret = ih264_buf_mgr_lock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n    u4_buf_cnt = ps_buf_mgr->i4_active_buf_cnt;\n\n    ret = ih264_buf_mgr_unlock(ps_buf_mgr);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    return u4_buf_cnt;\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_buf_mgr.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_buf_mgr.h\n*\n* @brief\n*  Function declarations used for buffer management\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n#ifndef _IH264_BUF_MGR_H_\n#define _IH264_BUF_MGR_H_\n\n#define BUF_MGR_MAX_CNT 64\n\n/** Flag for current encoding decoder */\n#define BUF_MGR_CODEC        (1 << 1)\n\n/** Flag for reference status */\n#define BUF_MGR_REF          (1 << 2)\n\n/** Flag for I/O - Display/output in case of decoder, capture/input in case of encoder */\n#define BUF_MGR_IO           (1 << 3)\n\ntypedef struct\n{\n    /**\n     * Mutex used to keep the functions thread-safe\n     */\n    void *pv_mutex;\n\n    /**\n     * max_buf_cnt\n     */\n    WORD32 i4_max_buf_cnt;\n\n    /**\n     * active_buf_cnt\n     */\n    WORD32 i4_active_buf_cnt;\n\n    /**\n     *  au4_status[BUF_MGR_MAX_CNT]\n     */\n    UWORD32 au4_status[BUF_MGR_MAX_CNT];\n\n    /* The last three bit of status are:    */\n\n    /* Bit 0 - IN USE                       */\n    /* Bit 1 - CODEC                        */\n    /* Bit 2 - REF                          */\n    /* Bit 3 - DISP/IO/RECON                */\n    void    *apv_ptr[BUF_MGR_MAX_CNT];\n\n}buf_mgr_t;\n\n// Returns size of the buffer manager context\nWORD32 ih264_buf_mgr_size(void);\n\n//Free buffer manager\nIH264_ERROR_T ih264_buf_mgr_free(buf_mgr_t *ps_buf_mgr);\n\n// Initializes the buffer API structure\nvoid *ih264_buf_mgr_init(void *pv_buf);\n\n// Add buffer to buffer manager. 0: success, -1: fail (u4_active_buf_cnt has reached u4_max_buf_cnt)\nIH264_ERROR_T ih264_buf_mgr_add(buf_mgr_t *ps_buf_mgr,\n                                void *pv_ptr,\n                                WORD32 buf_id);\n\n// this function will set the buffer status to DEC\nvoid* ih264_buf_mgr_get_next_free(buf_mgr_t *ps_buf_mgr, WORD32 *pi4_id);\n\n// this function will check if there are any free buffers\nIH264_ERROR_T ih264_buf_mgr_check_free(buf_mgr_t *ps_buf_mgr);\n\n// mask will have who released it: DISP:REF:DEC\nIH264_ERROR_T ih264_buf_mgr_release(buf_mgr_t *ps_buf_mgr,\n                                    WORD32 id,\n                                    UWORD32 mask);\n\n// sets the status to one or all of DISP:REF:DEC\nIH264_ERROR_T ih264_buf_mgr_set_status(buf_mgr_t *ps_buf_mgr,\n                                       WORD32 id,\n                                       UWORD32 mask);\n\n// Gets status of the buffer\nWORD32 ih264_buf_mgr_get_status(buf_mgr_t *ps_buf_mgr, WORD32 id);\n\n// pass the ID - buffer will be returned\nvoid* ih264_buf_mgr_get_buf(buf_mgr_t *ps_buf_mgr, WORD32 id);\n//Pass buffer to get ID\nWORD32 ih264_buf_mgr_get_bufid(buf_mgr_t *ps_buf_mgr, void *pv_buf);\n\n// will return number of active buffers\nUWORD32 ih264_buf_mgr_get_num_active_buf(buf_mgr_t *ps_buf_mgr);\n\n\n\n#endif  /* _IH264_BUF_MGR_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_cabac_tables.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n\n/**\n******************************************************************************\n* @file\n*  ih264_cabac_tables.c\n*\n* @brief\n*  This file contains H264 cabac tables for init contexts, rlps and\n*  cabac state transitions\n*\n* @author\n*   Ittiam\n*\n* @par List of Tables\n*   - gau4_ih264_cabac_table[][]\n*   - gau1_ih264_cabac_ctxt_init_table[][][]\n*\n******************************************************************************\n*/\n\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_cabac_tables.h\"\n\n\n/*****************************************************************************/\n/* Extern global definitions                                                 */\n/*****************************************************************************/\n/*****************************************************************************/\n/*  CABAC TABLES                                                             */\n/*****************************************************************************/\n/*combined table :guc_RTAB,NextStateLPS,NextStateMPS\n input(combined_state):\n bits 0-5: state\n bits 6:mps\n output\n bits 0-7:rangeTabLPS\n bits 8-14 :combined_next_state_if_mps\n bits 15 -21:combined_next_state_if_lps\n\n */\n\nconst UWORD32 gau4_ih264_cabac_table[128][4] =\n    {\n        { 2097536, 2097584, 2097616, 2097648 },\n\n          { 640, 679, 709, 739 },\n\n          { 33664, 33694, 33723, 33752 },\n\n          { 66683, 66710, 66738, 66765 },\n\n          { 66932, 66958, 66985, 67011 },\n\n          { 132719, 132743, 132768, 132793 },\n\n          { 132969, 132992, 133016, 133039 },\n\n          { 165988, 166010, 166032, 166054 },\n\n          { 199007, 199028, 199049, 199070 },\n\n          { 232026, 232046, 232066, 232086 },\n\n          { 265045, 265064, 265083, 265102 },\n\n          { 298065, 298083, 298101, 298119 },\n\n          { 298317, 298334, 298351, 298368 },\n\n          { 364105, 364121, 364137, 364154 },\n\n          { 364357, 364373, 364388, 364404 },\n\n          { 397378, 397392, 397407, 397422 },\n\n          { 430398, 430412, 430426, 430440 },\n\n          { 430651, 430664, 430678, 430691 },\n\n          { 496440, 496453, 496465, 496478 },\n\n          { 496693, 496705, 496717, 496729 },\n\n          { 529715, 529726, 529737, 529749 },\n\n          { 529968, 529979, 529989, 530000 },\n\n          { 595758, 595768, 595778, 595788 },\n\n          { 596011, 596021, 596031, 596040 },\n\n          { 629033, 629042, 629051, 629061 },\n\n          { 629287, 629296, 629304, 629313 },\n\n          { 695077, 695085, 695094, 695102 },\n\n          { 695331, 695339, 695347, 695355 },\n\n          { 728353, 728361, 728368, 728376 },\n\n          { 728608, 728615, 728622, 728629 },\n\n          { 761630, 761637, 761643, 761650 },\n\n          { 794653, 794659, 794665, 794672 },\n\n          { 794907, 794913, 794919, 794925 },\n\n          { 827930, 827935, 827941, 827947 },\n\n          { 860952, 860958, 860963, 860969 },\n\n          { 861207, 861212, 861217, 861223 },\n\n          { 894230, 894235, 894240, 894245 },\n\n          { 894485, 894490, 894494, 894499 },\n\n          { 927508, 927512, 927517, 927521 },\n\n          { 960531, 960535, 960539, 960543 },\n\n          { 960786, 960790, 960794, 960798 },\n\n          { 993809, 993813, 993817, 993820 },\n\n          { 994064, 994068, 994071, 994075 },\n\n          { 994319, 994323, 994326, 994329 },\n\n          { 1027342, 1027346, 1027349, 1027352 },\n\n          { 1060366, 1060369, 1060372, 1060375 },\n\n          { 1060621, 1060624, 1060627, 1060630 },\n\n          { 1093644, 1093647, 1093650, 1093653 },\n\n          { 1093900, 1093902, 1093905, 1093908 },\n\n          { 1094155, 1094158, 1094160, 1094163 },\n\n          { 1127179, 1127181, 1127183, 1127186 },\n\n          { 1127434, 1127436, 1127439, 1127441 },\n\n          { 1160458, 1160460, 1160462, 1160464 },\n\n          { 1160713, 1160715, 1160717, 1160719 },\n\n          { 1160969, 1160971, 1160972, 1160974 },\n\n          { 1193992, 1193994, 1193996, 1193998 },\n\n          { 1194248, 1194249, 1194251, 1194253 },\n\n          { 1194503, 1194505, 1194507, 1194508 },\n\n          { 1227527, 1227529, 1227530, 1227532 },\n\n          { 1227783, 1227784, 1227786, 1227787 },\n\n          { 1228038, 1228040, 1228041, 1228043 },\n\n          { 1261062, 1261063, 1261065, 1261066 },\n\n          { 1261062, 1261063, 1261064, 1261065 },\n\n          { 2080514, 2080514, 2080514, 2080514 },\n\n          { 16768, 16816, 16848, 16880 },\n\n          { 2114176, 2114215, 2114245, 2114275 },\n\n          { 2147200, 2147230, 2147259, 2147288 },\n\n          { 2180219, 2180246, 2180274, 2180301 },\n\n          { 2180468, 2180494, 2180521, 2180547 },\n\n          { 2246255, 2246279, 2246304, 2246329 },\n\n          { 2246505, 2246528, 2246552, 2246575 },\n\n          { 2279524, 2279546, 2279568, 2279590 },\n\n          { 2312543, 2312564, 2312585, 2312606 },\n\n          { 2345562, 2345582, 2345602, 2345622 },\n\n          { 2378581, 2378600, 2378619, 2378638 },\n\n          { 2411601, 2411619, 2411637, 2411655 },\n\n          { 2411853, 2411870, 2411887, 2411904 },\n\n          { 2477641, 2477657, 2477673, 2477690 },\n\n          { 2477893, 2477909, 2477924, 2477940 },\n\n          { 2510914, 2510928, 2510943, 2510958 },\n\n          { 2543934, 2543948, 2543962, 2543976 },\n\n          { 2544187, 2544200, 2544214, 2544227 },\n\n          { 2609976, 2609989, 2610001, 2610014 },\n\n          { 2610229, 2610241, 2610253, 2610265 },\n\n          { 2643251, 2643262, 2643273, 2643285 },\n\n          { 2643504, 2643515, 2643525, 2643536 },\n\n          { 2709294, 2709304, 2709314, 2709324 },\n\n          { 2709547, 2709557, 2709567, 2709576 },\n\n          { 2742569, 2742578, 2742587, 2742597 },\n\n          { 2742823, 2742832, 2742840, 2742849 },\n\n          { 2808613, 2808621, 2808630, 2808638 },\n\n          { 2808867, 2808875, 2808883, 2808891 },\n\n          { 2841889, 2841897, 2841904, 2841912 },\n\n          { 2842144, 2842151, 2842158, 2842165 },\n\n          { 2875166, 2875173, 2875179, 2875186 },\n\n          { 2908189, 2908195, 2908201, 2908208 },\n\n          { 2908443, 2908449, 2908455, 2908461 },\n\n          { 2941466, 2941471, 2941477, 2941483 },\n\n          { 2974488, 2974494, 2974499, 2974505 },\n\n          { 2974743, 2974748, 2974753, 2974759 },\n\n          { 3007766, 3007771, 3007776, 3007781 },\n\n          { 3008021, 3008026, 3008030, 3008035 },\n\n          { 3041044, 3041048, 3041053, 3041057 },\n\n          { 3074067, 3074071, 3074075, 3074079 },\n\n          { 3074322, 3074326, 3074330, 3074334 },\n\n          { 3107345, 3107349, 3107353, 3107356 },\n\n          { 3107600, 3107604, 3107607, 3107611 },\n\n          { 3107855, 3107859, 3107862, 3107865 },\n\n          { 3140878, 3140882, 3140885, 3140888 },\n\n          { 3173902, 3173905, 3173908, 3173911 },\n\n          { 3174157, 3174160, 3174163, 3174166 },\n\n          { 3207180, 3207183, 3207186, 3207189 },\n\n          { 3207436, 3207438, 3207441, 3207444 },\n\n          { 3207691, 3207694, 3207696, 3207699 },\n\n          { 3240715, 3240717, 3240719, 3240722 },\n\n          { 3240970, 3240972, 3240975, 3240977 },\n\n          { 3273994, 3273996, 3273998, 3274000 },\n\n          { 3274249, 3274251, 3274253, 3274255 },\n\n          { 3274505, 3274507, 3274508, 3274510 },\n\n          { 3307528, 3307530, 3307532, 3307534 },\n\n          { 3307784, 3307785, 3307787, 3307789 },\n\n          { 3308039, 3308041, 3308043, 3308044 },\n\n          { 3341063, 3341065, 3341066, 3341068 },\n\n          { 3341319, 3341320, 3341322, 3341323 },\n\n          { 3341574, 3341576, 3341577, 3341579 },\n\n          { 3374598, 3374599, 3374601, 3374602 },\n\n          { 3374598, 3374599, 3374600, 3374601 },\n\n          { 4194050, 4194050, 4194050, 4194050 },\n\n    };\n\n/*****************************************************************************/\n/* Global Variable Initialization                                            */\n/*****************************************************************************/\nconst UWORD8 gau1_ih264_cabac_ctxt_init_table[NUM_CAB_INIT_IDC_PLUS_ONE][QP_RANGE][NUM_CABAC_CTXTS] =\n\n                    {\n\n                        {\n\n                            {\n\n                            62,\n                              9, 74, 62, 9, 74, 126, 104, 10, 9, 12, 30, 61, 62,\n                              54, 14, 118, 6, 78, 65, 1, 14, 73, 13, 64, 20, 62,\n                              67, 90, 104, 126, 104, 67, 78, 65, 1, 86, 95, 2,\n                              18, 69, 81, 96, 8, 67, 86, 88, 5, 76, 94, 9, 69,\n                              81, 88, 67, 74, 74, 80, 72, 5, 22, 0, 0, 0, 83,\n                              86, 97, 72, 22, 1, 18, 78, 96, 126, 98, 101, 67,\n                              82, 94, 83, 110, 91, 102, 93, 126, 92, 89, 96,\n                              108, 17, 65, 6, 93, 74, 92, 87, 126, 9, 3, 4, 69,\n                              15, 68, 69, 88, 85, 78, 75, 77, 9, 13, 68, 13, 21,\n                              81, 0, 70, 67, 6, 76, 28, 64, 2, 28, 38, 39, 34,\n                              27, 93, 73, 73, 17, 14, 100, 10, 10, 10, 2, 7, 7,\n                              0, 3, 1, 6, 69, 6, 24, 12, 68, 64, 2, 0, 13, 24,\n                              19, 11, 15, 3, 4, 4, 30, 19, 20, 78, 3, 69, 35,\n                              23, 19, 14, 17, 19, 12, 16, 24, 1, 17, 9, 9, 5, 0,\n                              12, 6, 10, 11, 8, 18, 27, 10, 82, 8, 78, 17, 32,\n                              84, 56, 62, 60, 59, 62, 62, 57, 57, 54, 44, 36,\n                              33, 43, 29, 70, 67, 4, 67, 33, 31, 28, 34, 32, 25,\n                              20, 22, 0, 4, 64, 94, 89, 108, 76, 19, 18, 11, 64,\n                              4, 70, 75, 82, 102, 77, 39, 21, 15, 8, 4, 71, 83,\n                              87, 119, 5, 34, 27, 25, 20, 8, 5, 64, 74, 90, 70,\n                              34, 32, 21, 4, 5, 72, 81, 97, 5, 58, 49, 45, 36,\n                              23, 5, 70, 79, 85, 62, 106, 106, 87, 114, 110, 98,\n                              110, 106, 103, 107, 108, 112, 96, 95, 91, 93, 94,\n                              86, 67, 80, 85, 70, 3, 5, 2, 13, 13, 14, 9, 22,\n                              17, 12, 14, 11, 22, 16, 8, 22, 19, 13, 10, 14, 0,\n                              64, 69, 4, 70, 19, 32, 20, 10, 29, 25, 11, 23, 31,\n                              19, 25, 13, 6, 20, 52, 49, 52, 52, 54, 62, 62, 62,\n                              62, 62, 62, 62, 62, 62, 34, 62, 62, 62, 62, 62,\n                              62, 54, 37, 36, 6, 82, 75, 97, 125, 62, 62, 62,\n                              57, 55, 53, 41, 44, 31, 32, 22, 19, 16, 65, 71, 3,\n                              0, 65, 39, 43, 40, 31, 40, 39, 23, 31, 34, 21, 6,\n                              10, 2, 86, 23, 12, 4, 79, 71, 69, 70, 66, 68, 73,\n                              69, 70, 67, 1, 70, 66, 65, 0, 62, 62, 62, 62, 62,\n                              60, 54, 36, 4, 66, 28, 21, 18, 15, 7, 3, 1, 66,\n                              76, 85, 81, 77, 81, 80, 73, 74, 83, 71, 67, 2, 66,\n                              66, 4, 4, 62, 62, 62, 62, 61, 57, 46, 29, 1 },\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 125, 102, 11, 10, 12, 29, 60,\n                                62, 54, 14, 115, 6, 77, 64, 1, 14, 72, 12, 65,\n                                20, 62, 68, 91, 104, 124, 102, 67, 77, 64, 1,\n                                85, 93, 3, 18, 68, 80, 95, 8, 67, 85, 88, 5, 75,\n                                93, 9, 69, 80, 88, 66, 73, 73, 79, 71, 5, 22, 0,\n                                0, 0, 82, 86, 97, 71, 22, 1, 18, 77, 95, 124,\n                                96, 99, 65, 80, 92, 82, 108, 89, 100, 92, 125,\n                                91, 88, 95, 107, 18, 64, 7, 92, 73, 91, 86, 124,\n                                9, 3, 4, 69, 16, 68, 68, 87, 84, 77, 74, 76, 9,\n                                13, 67, 13, 21, 80, 0, 69, 67, 6, 75, 28, 64, 2,\n                                28, 37, 39, 34, 27, 92, 72, 72, 17, 14, 99, 10,\n                                10, 10, 3, 7, 7, 1, 4, 2, 6, 68, 6, 24, 12, 68,\n                                64, 2, 0, 13, 23, 19, 11, 15, 4, 5, 4, 29, 19,\n                                20, 77, 3, 69, 35, 23, 19, 14, 17, 19, 12, 16,\n                                24, 1, 17, 9, 9, 5, 0, 12, 6, 10, 11, 8, 18, 27,\n                                10, 81, 8, 77, 17, 31, 83, 55, 62, 59, 58, 61,\n                                62, 56, 56, 52, 43, 35, 32, 41, 28, 71, 67, 4,\n                                67, 32, 30, 27, 33, 31, 24, 19, 21, 0, 4, 64,\n                                93, 88, 107, 75, 20, 18, 11, 0, 5, 69, 74, 81,\n                                100, 76, 39, 21, 15, 8, 5, 70, 82, 86, 117, 5,\n                                35, 28, 25, 20, 9, 5, 64, 73, 89, 70, 35, 32,\n                                21, 4, 6, 71, 80, 96, 5, 58, 49, 45, 36, 23, 5,\n                                69, 78, 84, 62, 105, 105, 86, 112, 108, 97, 108,\n                                104, 101, 105, 106, 110, 95, 94, 90, 92, 92, 85,\n                                67, 79, 84, 69, 3, 5, 2, 13, 13, 13, 8, 22, 17,\n                                13, 14, 11, 22, 16, 8, 22, 19, 13, 10, 14, 0,\n                                64, 68, 5, 70, 19, 32, 20, 10, 29, 25, 12, 23,\n                                30, 19, 25, 13, 6, 19, 52, 49, 52, 51, 53, 62,\n                                62, 62, 62, 62, 62, 62, 62, 62, 33, 62, 62, 62,\n                                62, 62, 62, 53, 36, 35, 6, 81, 74, 95, 122, 62,\n                                62, 62, 56, 53, 52, 40, 42, 30, 31, 21, 18, 15,\n                                66, 71, 3, 0, 66, 38, 42, 39, 30, 39, 38, 22,\n                                30, 33, 20, 5, 9, 1, 86, 23, 12, 4, 78, 70, 68,\n                                69, 65, 67, 71, 68, 69, 66, 3, 68, 65, 0, 2, 62,\n                                62, 62, 62, 62, 58, 51, 34, 2, 65, 29, 22, 19,\n                                16, 8, 4, 2, 65, 75, 84, 80, 76, 80, 78, 71, 73,\n                                82, 70, 66, 3, 65, 65, 4, 4, 62, 62, 62, 62, 58,\n                                54, 43, 26, 64 },\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 123, 101, 11, 10, 12, 28, 59,\n                                61, 54, 14, 113, 6, 76, 0, 1, 13, 72, 11, 66,\n                                19, 60, 70, 92, 105, 121, 101, 67, 76, 0, 1, 85,\n                                92, 3, 17, 68, 80, 94, 8, 67, 85, 88, 5, 75, 92,\n                                9, 69, 80, 88, 66, 73, 73, 79, 71, 5, 22, 0, 0,\n                                0, 81, 86, 97, 71, 21, 1, 18, 77, 95, 122, 94,\n                                97, 64, 78, 91, 81, 107, 88, 99, 91, 123, 91,\n                                88, 95, 106, 18, 64, 7, 91, 73, 90, 86, 123, 9,\n                                3, 4, 69, 16, 68, 68, 87, 84, 77, 74, 76, 9, 13,\n                                67, 13, 21, 80, 0, 69, 67, 6, 75, 27, 64, 2, 27,\n                                36, 38, 33, 26, 91, 72, 72, 16, 13, 99, 9, 10,\n                                10, 3, 7, 7, 2, 4, 2, 6, 68, 6, 23, 12, 69, 64,\n                                2, 64, 13, 22, 19, 11, 14, 4, 5, 4, 28, 19, 19,\n                                77, 3, 70, 34, 23, 19, 14, 17, 19, 12, 16, 24,\n                                1, 17, 9, 9, 5, 0, 12, 6, 10, 11, 8, 17, 26, 9,\n                                81, 8, 77, 16, 30, 83, 53, 62, 57, 56, 59, 60,\n                                54, 54, 50, 41, 33, 30, 39, 26, 72, 67, 4, 68,\n                                31, 29, 26, 32, 29, 23, 18, 20, 64, 3, 65, 93,\n                                88, 106, 75, 20, 18, 11, 0, 5, 69, 74, 81, 99,\n                                75, 39, 21, 15, 8, 5, 70, 81, 85, 115, 5, 35,\n                                28, 25, 20, 9, 5, 64, 73, 88, 70, 35, 32, 21, 4,\n                                6, 71, 80, 95, 5, 57, 48, 44, 35, 23, 5, 69, 78,\n                                84, 62, 104, 104, 85, 111, 107, 96, 107, 103,\n                                100, 104, 105, 108, 94, 93, 90, 91, 91, 85, 68,\n                                79, 83, 69, 3, 4, 2, 12, 12, 12, 7, 21, 17, 13,\n                                14, 10, 21, 16, 8, 21, 18, 13, 10, 13, 0, 64,\n                                68, 5, 70, 18, 31, 19, 10, 28, 24, 12, 22, 29,\n                                19, 25, 12, 5, 17, 51, 48, 51, 50, 52, 62, 62,\n                                62, 62, 62, 62, 62, 62, 62, 32, 62, 62, 62, 62,\n                                62, 62, 51, 35, 34, 6, 80, 74, 94, 120, 60, 60,\n                                62, 54, 51, 50, 38, 40, 29, 29, 20, 16, 14, 67,\n                                72, 2, 0, 67, 37, 41, 37, 28, 37, 36, 21, 28,\n                                31, 19, 4, 8, 0, 87, 22, 11, 3, 78, 70, 68, 68,\n                                65, 66, 70, 67, 68, 65, 4, 67, 64, 1, 3, 62, 62,\n                                62, 62, 60, 55, 48, 31, 0, 65, 29, 22, 19, 16,\n                                9, 4, 2, 65, 75, 84, 80, 75, 80, 77, 70, 73, 81,\n                                69, 65, 3, 65, 64, 4, 4, 62, 62, 62, 60, 55, 50,\n                                39, 23, 67 },\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 121, 99, 12, 10, 11, 26, 57,\n                                60, 54, 14, 111, 6, 75, 1, 1, 12, 72, 10, 67,\n                                19, 58, 71, 93, 105, 118, 100, 67, 75, 1, 1, 84,\n                                91, 4, 17, 68, 79, 93, 7, 68, 85, 88, 5, 75, 92,\n                                9, 69, 80, 88, 65, 73, 73, 79, 70, 5, 22, 0, 0,\n                                0, 81, 86, 97, 70, 20, 1, 18, 77, 95, 120, 92,\n                                96, 1, 76, 90, 80, 105, 87, 98, 90, 121, 90, 88,\n                                94, 105, 18, 64, 7, 91, 73, 90, 85, 121, 9, 2,\n                                3, 70, 16, 68, 68, 86, 84, 76, 74, 75, 9, 13,\n                                67, 13, 20, 80, 0, 69, 67, 6, 75, 26, 64, 2, 26,\n                                35, 37, 32, 25, 91, 71, 72, 15, 13, 98, 9, 10,\n                                10, 3, 7, 7, 3, 4, 2, 6, 67, 6, 22, 12, 70, 64,\n                                2, 64, 12, 21, 19, 11, 13, 4, 5, 4, 26, 19, 18,\n                                77, 3, 70, 33, 23, 19, 14, 17, 19, 12, 16, 24,\n                                1, 16, 9, 9, 5, 0, 11, 5, 9, 10, 7, 16, 25, 9,\n                                81, 7, 77, 15, 28, 83, 52, 62, 55, 54, 57, 58,\n                                52, 52, 48, 39, 32, 29, 37, 24, 73, 67, 4, 68,\n                                30, 28, 25, 30, 28, 21, 17, 19, 65, 3, 65, 93,\n                                88, 106, 74, 20, 18, 11, 0, 5, 69, 74, 80, 98,\n                                75, 39, 21, 15, 8, 6, 69, 80, 84, 113, 5, 35,\n                                28, 25, 20, 10, 5, 64, 73, 88, 70, 35, 32, 20,\n                                4, 6, 71, 80, 94, 5, 57, 48, 43, 34, 23, 5, 69,\n                                77, 83, 62, 103, 103, 85, 110, 106, 95, 105,\n                                102, 99, 103, 103, 107, 94, 92, 90, 91, 89, 85,\n                                68, 79, 83, 69, 2, 4, 2, 11, 11, 11, 6, 21, 16,\n                                13, 13, 10, 21, 15, 8, 20, 18, 12, 10, 12, 0,\n                                65, 68, 5, 71, 18, 31, 18, 10, 27, 24, 12, 21,\n                                28, 18, 24, 11, 5, 16, 50, 47, 51, 49, 51, 61,\n                                62, 62, 62, 62, 62, 62, 62, 62, 31, 62, 62, 62,\n                                62, 62, 62, 49, 34, 33, 6, 79, 74, 93, 118, 58,\n                                58, 62, 52, 49, 48, 37, 38, 27, 28, 19, 15, 12,\n                                68, 73, 2, 64, 68, 36, 39, 36, 26, 35, 34, 19,\n                                27, 29, 17, 3, 6, 65, 88, 21, 10, 2, 78, 69, 68,\n                                68, 64, 66, 69, 66, 67, 64, 5, 66, 0, 3, 4, 62,\n                                62, 62, 62, 58, 52, 45, 28, 65, 64, 30, 23, 20,\n                                16, 10, 5, 2, 64, 74, 84, 79, 75, 79, 76, 69,\n                                73, 81, 69, 65, 3, 64, 0, 4, 4, 62, 62, 62, 57,\n                                52, 46, 35, 19, 69 },\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 120, 98, 12, 10, 11, 25, 56,\n                                58, 54, 14, 108, 5, 74, 1, 1, 11, 72, 9, 68, 18,\n                                56, 73, 94, 106, 115, 99, 67, 74, 1, 1, 84, 90,\n                                4, 16, 68, 79, 93, 7, 68, 84, 88, 5, 75, 91, 8,\n                                70, 80, 88, 65, 72, 73, 78, 70, 5, 22, 0, 0, 0,\n                                80, 87, 97, 70, 19, 1, 18, 77, 95, 119, 91, 94,\n                                2, 75, 89, 79, 104, 85, 97, 89, 119, 90, 87, 94,\n                                104, 18, 64, 7, 90, 73, 89, 85, 120, 8, 2, 3,\n                                70, 16, 68, 68, 86, 84, 76, 74, 75, 9, 12, 67,\n                                13, 20, 80, 0, 69, 67, 6, 75, 26, 65, 2, 26, 34,\n                                36, 31, 24, 90, 71, 72, 14, 12, 98, 8, 10, 9, 3,\n                                7, 7, 4, 5, 2, 5, 67, 5, 21, 11, 71, 64, 2, 65,\n                                12, 20, 18, 10, 13, 5, 5, 4, 25, 18, 17, 77, 3,\n                                71, 33, 23, 19, 14, 17, 19, 12, 16, 23, 1, 16,\n                                9, 9, 5, 64, 11, 5, 9, 10, 7, 16, 24, 8, 81, 7,\n                                77, 14, 27, 83, 50, 62, 53, 52, 55, 56, 50, 50,\n                                46, 37, 30, 27, 34, 22, 74, 67, 3, 69, 29, 27,\n                                24, 29, 26, 20, 16, 17, 65, 2, 66, 93, 88, 105,\n                                74, 20, 18, 11, 0, 5, 69, 74, 80, 97, 74, 39,\n                                21, 15, 8, 6, 69, 80, 84, 111, 5, 35, 28, 25,\n                                20, 10, 5, 64, 73, 87, 70, 35, 31, 20, 4, 6, 71,\n                                80, 94, 5, 56, 47, 42, 33, 23, 5, 69, 77, 83,\n                                62, 102, 102, 84, 108, 105, 94, 104, 100, 98,\n                                101, 102, 105, 93, 92, 89, 90, 88, 84, 69, 79,\n                                82, 69, 2, 3, 1, 10, 10, 10, 5, 20, 16, 13, 13,\n                                9, 20, 15, 8, 19, 17, 12, 9, 11, 64, 65, 68, 5,\n                                71, 17, 30, 17, 10, 26, 23, 12, 20, 27, 18, 24,\n                                10, 4, 14, 49, 47, 50, 48, 49, 60, 62, 62, 62,\n                                62, 62, 62, 62, 62, 29, 62, 62, 62, 62, 62, 62,\n                                47, 33, 31, 6, 78, 73, 92, 116, 57, 56, 60, 51,\n                                47, 46, 35, 36, 26, 26, 17, 13, 11, 69, 74, 1,\n                                64, 69, 34, 38, 34, 25, 33, 32, 18, 25, 27, 16,\n                                2, 5, 66, 88, 20, 10, 1, 78, 69, 67, 67, 64, 65,\n                                68, 66, 66, 0, 6, 65, 1, 4, 5, 62, 62, 62, 61,\n                                55, 49, 42, 25, 68, 64, 30, 23, 20, 17, 10, 5,\n                                3, 64, 74, 83, 79, 74, 79, 75, 68, 73, 80, 68,\n                                64, 3, 64, 1, 4, 4, 62, 62, 61, 54, 49, 42, 31,\n                                16, 72 },\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 118, 96, 12, 10, 10, 23, 54,\n                                57, 54, 14, 106, 5, 73, 2, 1, 11, 71, 8, 69, 18,\n                                54, 75, 95, 106, 112, 97, 67, 73, 2, 1, 84, 89,\n                                4, 16, 68, 79, 92, 7, 69, 84, 88, 5, 75, 90, 8,\n                                70, 80, 88, 64, 72, 72, 78, 69, 5, 22, 0, 0, 0,\n                                80, 87, 97, 69, 18, 1, 18, 76, 95, 117, 89, 93,\n                                4, 73, 87, 78, 103, 84, 96, 88, 117, 89, 87, 93,\n                                103, 18, 64, 7, 90, 73, 89, 84, 118, 8, 2, 3,\n                                70, 16, 68, 67, 85, 84, 76, 74, 74, 9, 12, 67,\n                                13, 20, 79, 0, 68, 67, 6, 75, 25, 65, 2, 25, 33,\n                                36, 30, 23, 89, 70, 72, 13, 12, 97, 8, 10, 9, 3,\n                                7, 7, 5, 5, 2, 5, 67, 5, 20, 11, 72, 64, 2, 65,\n                                11, 19, 18, 10, 12, 5, 5, 4, 24, 18, 16, 77, 3,\n                                71, 32, 23, 19, 14, 17, 19, 12, 16, 23, 1, 16,\n                                9, 9, 5, 64, 11, 5, 8, 10, 7, 15, 23, 8, 81, 6,\n                                77, 13, 26, 83, 49, 61, 52, 51, 53, 54, 48, 48,\n                                44, 35, 28, 25, 32, 21, 75, 67, 3, 69, 28, 26,\n                                23, 28, 25, 18, 15, 16, 66, 2, 66, 93, 88, 105,\n                                74, 20, 18, 11, 0, 5, 68, 73, 79, 96, 74, 39,\n                                21, 15, 8, 6, 68, 79, 83, 109, 5, 35, 28, 25,\n                                20, 10, 5, 64, 73, 86, 70, 36, 31, 19, 4, 6, 71,\n                                80, 93, 5, 56, 46, 41, 32, 23, 5, 69, 77, 82,\n                                62, 101, 101, 83, 107, 104, 93, 103, 99, 97,\n                                100, 100, 103, 92, 91, 89, 90, 87, 84, 69, 78,\n                                81, 69, 1, 3, 1, 10, 9, 9, 4, 19, 15, 13, 12, 9,\n                                20, 15, 8, 18, 16, 12, 9, 10, 64, 65, 68, 5, 71,\n                                16, 30, 17, 10, 25, 22, 12, 19, 26, 17, 23, 9,\n                                3, 12, 48, 46, 50, 47, 48, 58, 62, 62, 62, 62,\n                                62, 62, 62, 62, 28, 62, 62, 62, 62, 62, 61, 45,\n                                32, 30, 6, 77, 73, 91, 114, 55, 55, 58, 49, 45,\n                                44, 34, 34, 25, 24, 16, 11, 9, 70, 75, 1, 64,\n                                70, 33, 36, 32, 23, 32, 31, 16, 24, 26, 14, 1,\n                                4, 67, 89, 20, 9, 0, 77, 68, 67, 67, 0, 64, 67,\n                                65, 65, 1, 8, 64, 2, 5, 7, 62, 62, 62, 58, 53,\n                                46, 39, 22, 70, 64, 31, 24, 21, 17, 11, 5, 3, 0,\n                                73, 83, 79, 73, 78, 74, 67, 72, 79, 68, 64, 3,\n                                0, 2, 4, 4, 62, 62, 58, 51, 46, 39, 27, 12, 75 },\n\n                              {\n\n                              62,\n                                9, 75, 62, 9, 75, 116, 95, 13, 10, 10, 22, 53,\n                                56, 54, 14, 104, 5, 73, 3, 1, 10, 71, 7, 70, 17,\n                                53, 76, 96, 107, 109, 96, 67, 73, 3, 1, 83, 88,\n                                5, 15, 67, 78, 91, 6, 69, 84, 88, 5, 74, 90, 8,\n                                70, 79, 88, 64, 72, 72, 78, 69, 5, 22, 0, 0, 0,\n                                79, 87, 97, 69, 18, 0, 18, 76, 94, 115, 87, 91,\n                                5, 71, 86, 77, 101, 83, 95, 88, 116, 89, 87, 93,\n                                103, 19, 64, 7, 89, 72, 88, 84, 117, 8, 1, 2,\n                                71, 16, 68, 67, 85, 84, 75, 74, 74, 9, 12, 66,\n                                13, 19, 79, 0, 68, 67, 6, 75, 24, 65, 2, 24, 32,\n                                35, 30, 23, 89, 70, 72, 13, 11, 97, 7, 10, 9, 3,\n                                7, 7, 5, 5, 2, 5, 66, 5, 19, 11, 72, 65, 2, 66,\n                                11, 18, 18, 10, 11, 5, 5, 4, 22, 18, 15, 77, 3,\n                                72, 31, 23, 18, 14, 17, 19, 12, 16, 23, 1, 15,\n                                9, 8, 5, 64, 10, 4, 8, 9, 6, 14, 22, 7, 81, 6,\n                                76, 12, 24, 83, 47, 59, 50, 49, 51, 52, 46, 46,\n                                42, 33, 27, 24, 30, 19, 76, 67, 3, 70, 27, 25,\n                                22, 26, 23, 17, 14, 15, 67, 1, 67, 93, 88, 104,\n                                73, 20, 18, 11, 1, 5, 68, 73, 79, 95, 73, 38,\n                                21, 15, 8, 7, 68, 78, 82, 107, 5, 36, 28, 25,\n                                20, 11, 5, 64, 72, 86, 70, 36, 31, 19, 4, 6, 70,\n                                79, 92, 5, 55, 46, 40, 32, 23, 5, 68, 76, 82,\n                                62, 101, 100, 83, 106, 103, 92, 101, 98, 96, 99,\n                                99, 102, 92, 90, 89, 89, 85, 84, 70, 78, 81, 69,\n                                1, 2, 1, 9, 8, 8, 3, 19, 15, 13, 12, 8, 19, 14,\n                                8, 18, 16, 11, 9, 10, 64, 66, 68, 5, 72, 16, 29,\n                                16, 9, 24, 22, 13, 19, 25, 17, 23, 9, 3, 11, 47,\n                                45, 49, 46, 47, 57, 62, 62, 62, 62, 62, 62, 62,\n                                61, 27, 62, 62, 62, 62, 62, 59, 43, 31, 29, 6,\n                                76, 73, 89, 111, 53, 53, 56, 47, 43, 42, 32, 32,\n                                23, 23, 15, 10, 8, 71, 76, 0, 65, 71, 32, 35,\n                                31, 21, 30, 29, 15, 22, 24, 13, 64, 2, 69, 90,\n                                19, 8, 64, 77, 68, 67, 66, 0, 64, 65, 64, 64, 2,\n                                9, 1, 3, 7, 8, 62, 62, 60, 56, 50, 44, 36, 20,\n                                72, 0, 31, 24, 21, 17, 12, 6, 3, 0, 73, 83, 78,\n                                73, 78, 73, 66, 72, 79, 67, 0, 3, 0, 3, 4, 4,\n                                62, 62, 56, 48, 42, 35, 24, 9, 77 },\n\n                              {\n\n                              62,\n                                9, 75, 62, 9, 75, 114, 93, 13, 10, 9, 20, 51,\n                                54, 54, 14, 101, 4, 72, 3, 1, 9, 71, 6, 71, 17,\n                                51, 78, 97, 107, 106, 95, 67, 72, 3, 1, 83, 87,\n                                5, 15, 67, 78, 91, 6, 70, 83, 88, 5, 74, 89, 7,\n                                70, 79, 88, 0, 71, 72, 77, 68, 5, 22, 0, 0, 0,\n                                79, 87, 97, 68, 17, 0, 18, 76, 94, 114, 85, 90,\n                                7, 69, 85, 76, 100, 81, 94, 87, 114, 88, 86, 92,\n                                102, 19, 64, 7, 89, 72, 88, 83, 115, 7, 1, 2,\n                                71, 16, 68, 67, 84, 84, 75, 74, 73, 9, 11, 66,\n                                13, 19, 79, 0, 68, 67, 6, 75, 24, 65, 2, 24, 31,\n                                34, 29, 22, 88, 69, 72, 12, 11, 96, 7, 10, 8, 3,\n                                7, 7, 6, 6, 2, 5, 66, 5, 18, 11, 73, 65, 2, 66,\n                                10, 17, 17, 10, 11, 6, 5, 4, 21, 17, 14, 77, 3,\n                                72, 31, 23, 18, 14, 17, 19, 12, 16, 23, 1, 15,\n                                9, 8, 5, 64, 10, 4, 7, 9, 6, 14, 21, 7, 81, 5,\n                                76, 11, 23, 83, 46, 57, 48, 47, 49, 50, 44, 44,\n                                40, 31, 25, 22, 27, 17, 77, 67, 2, 70, 26, 24,\n                                21, 25, 22, 15, 13, 14, 67, 1, 67, 93, 88, 104,\n                                73, 20, 18, 11, 1, 5, 68, 73, 78, 94, 73, 38,\n                                21, 15, 8, 7, 67, 77, 82, 105, 5, 36, 28, 25,\n                                20, 11, 5, 64, 72, 85, 70, 36, 30, 18, 4, 6, 70,\n                                79, 92, 5, 55, 45, 39, 31, 23, 5, 68, 76, 81,\n                                62, 100, 99, 82, 104, 102, 91, 100, 96, 95, 97,\n                                97, 100, 91, 89, 88, 89, 84, 83, 70, 78, 80, 69,\n                                0, 2, 0, 8, 7, 7, 2, 18, 14, 13, 11, 8, 19, 14,\n                                8, 17, 15, 11, 8, 9, 64, 66, 68, 5, 72, 15, 29,\n                                15, 9, 23, 21, 13, 18, 24, 16, 22, 8, 2, 9, 46,\n                                45, 49, 45, 45, 55, 62, 62, 62, 62, 62, 62, 62,\n                                59, 25, 62, 62, 62, 62, 62, 56, 41, 30, 28, 6,\n                                75, 72, 88, 109, 52, 51, 54, 46, 41, 40, 31, 30,\n                                22, 21, 13, 8, 6, 72, 77, 0, 65, 72, 30, 33, 29,\n                                20, 28, 27, 13, 21, 22, 11, 65, 1, 70, 90, 18,\n                                8, 65, 77, 67, 66, 66, 1, 0, 64, 0, 0, 3, 10, 2,\n                                4, 8, 9, 62, 61, 58, 53, 48, 41, 33, 17, 74, 0,\n                                32, 25, 22, 18, 13, 6, 4, 1, 72, 82, 78, 72, 77,\n                                72, 65, 72, 78, 67, 0, 3, 1, 4, 4, 4, 62, 62,\n                                53, 45, 39, 31, 20, 5, 80 },\n\n                              {\n\n                              62,\n                                8, 75, 62, 8, 75, 113, 92, 13, 10, 9, 19, 50,\n                                53, 54, 14, 99, 4, 71, 4, 1, 8, 71, 5, 73, 16,\n                                49, 80, 98, 108, 104, 94, 67, 71, 4, 1, 83, 86,\n                                5, 14, 67, 78, 90, 5, 70, 83, 89, 5, 74, 89, 7,\n                                71, 79, 88, 0, 71, 72, 77, 68, 5, 22, 0, 0, 0,\n                                78, 88, 97, 68, 16, 0, 18, 76, 94, 112, 84, 88,\n                                8, 68, 84, 75, 99, 80, 93, 86, 112, 88, 86, 92,\n                                101, 19, 64, 7, 88, 72, 87, 83, 114, 7, 0, 1,\n                                72, 16, 68, 67, 84, 84, 75, 74, 73, 8, 11, 66,\n                                13, 18, 79, 0, 68, 67, 5, 75, 23, 66, 2, 23, 29,\n                                33, 28, 21, 88, 69, 72, 11, 10, 96, 6, 9, 8, 3,\n                                7, 7, 7, 6, 2, 4, 66, 4, 17, 10, 74, 65, 2, 67,\n                                10, 16, 17, 9, 10, 6, 5, 4, 19, 17, 13, 77, 3,\n                                73, 30, 22, 18, 14, 17, 18, 11, 16, 22, 0, 14,\n                                9, 8, 4, 65, 9, 3, 7, 8, 5, 13, 20, 6, 81, 5,\n                                76, 10, 21, 83, 44, 55, 46, 45, 47, 47, 42, 42,\n                                38, 29, 23, 20, 25, 15, 78, 67, 2, 71, 25, 22,\n                                19, 23, 20, 14, 11, 12, 68, 0, 68, 93, 88, 103,\n                                73, 20, 18, 11, 1, 5, 68, 73, 78, 93, 72, 38,\n                                21, 15, 8, 7, 67, 77, 81, 104, 5, 36, 28, 25,\n                                19, 11, 5, 64, 72, 85, 70, 36, 30, 18, 4, 6, 70,\n                                79, 91, 5, 54, 44, 38, 30, 22, 5, 68, 76, 81,\n                                62, 99, 98, 82, 103, 101, 91, 99, 95, 94, 96,\n                                96, 99, 91, 89, 88, 88, 83, 83, 71, 78, 80, 69,\n                                0, 1, 0, 7, 6, 5, 1, 17, 14, 13, 11, 7, 18, 13,\n                                7, 16, 14, 10, 8, 8, 65, 67, 68, 5, 73, 14, 28,\n                                14, 9, 22, 20, 13, 17, 23, 16, 22, 7, 1, 7, 45,\n                                44, 48, 43, 44, 54, 62, 62, 62, 62, 62, 62, 62,\n                                56, 24, 62, 62, 62, 62, 61, 54, 39, 28, 26, 6,\n                                75, 72, 87, 107, 50, 49, 52, 44, 38, 38, 29, 28,\n                                20, 19, 12, 6, 5, 73, 78, 64, 66, 73, 29, 32,\n                                27, 18, 26, 25, 12, 19, 20, 10, 66, 64, 72, 91,\n                                17, 7, 66, 77, 67, 66, 65, 1, 0, 0, 0, 1, 4, 11,\n                                3, 5, 9, 10, 61, 59, 56, 51, 45, 38, 30, 14, 77,\n                                0, 32, 25, 22, 18, 13, 6, 4, 1, 72, 82, 78, 72,\n                                77, 71, 64, 72, 78, 66, 1, 3, 1, 4, 4, 3, 62,\n                                61, 51, 42, 36, 27, 16, 2, 83 },\n\n                              {\n\n                              62,\n                                8, 75, 62, 8, 75, 111, 91, 14, 10, 9, 18, 49,\n                                52, 54, 14, 97, 4, 70, 5, 1, 8, 70, 4, 74, 15,\n                                47, 81, 99, 109, 101, 92, 67, 70, 5, 1, 82, 85,\n                                6, 13, 67, 77, 89, 5, 70, 83, 89, 5, 74, 88, 7,\n                                71, 79, 88, 0, 71, 71, 77, 68, 5, 22, 0, 0, 0,\n                                77, 88, 97, 68, 15, 0, 18, 75, 94, 110, 82, 86,\n                                9, 66, 82, 74, 97, 79, 91, 85, 110, 88, 86, 92,\n                                100, 19, 64, 7, 87, 72, 86, 82, 113, 7, 0, 1,\n                                72, 16, 68, 66, 83, 83, 74, 74, 73, 8, 11, 66,\n                                13, 18, 78, 0, 67, 67, 5, 74, 22, 66, 2, 22, 28,\n                                33, 27, 20, 87, 69, 71, 10, 9, 96, 5, 9, 8, 4,\n                                7, 7, 8, 6, 2, 4, 65, 4, 17, 10, 75, 65, 2, 68,\n                                10, 15, 17, 9, 9, 6, 5, 4, 18, 17, 13, 77, 3,\n                                74, 29, 22, 18, 14, 17, 18, 11, 16, 22, 0, 14,\n                                9, 8, 4, 65, 9, 3, 7, 8, 5, 12, 20, 6, 81, 5,\n                                76, 9, 20, 83, 42, 54, 45, 44, 45, 45, 41, 41,\n                                36, 27, 22, 19, 23, 14, 79, 67, 2, 72, 24, 21,\n                                18, 22, 19, 13, 10, 11, 69, 64, 69, 93, 87, 102,\n                                72, 21, 18, 11, 1, 6, 67, 72, 77, 92, 71, 38,\n                                21, 15, 8, 8, 67, 76, 80, 102, 5, 36, 28, 25,\n                                19, 12, 5, 64, 72, 84, 70, 37, 30, 18, 4, 7, 70,\n                                79, 90, 5, 54, 44, 38, 29, 22, 5, 68, 75, 80,\n                                62, 98, 97, 81, 102, 99, 90, 97, 94, 92, 95, 95,\n                                97, 90, 88, 88, 87, 81, 83, 72, 77, 79, 69, 0,\n                                0, 0, 7, 5, 4, 0, 17, 14, 13, 11, 7, 17, 13, 7,\n                                15, 14, 10, 8, 7, 65, 67, 67, 6, 73, 14, 27, 14,\n                                9, 22, 20, 13, 16, 22, 16, 22, 6, 1, 6, 45, 43,\n                                47, 42, 43, 53, 60, 60, 62, 62, 62, 62, 62, 54,\n                                23, 62, 62, 62, 62, 58, 52, 38, 27, 25, 6, 74,\n                                72, 86, 105, 48, 48, 50, 42, 36, 37, 28, 26, 19,\n                                18, 11, 5, 4, 74, 78, 64, 66, 74, 28, 31, 26,\n                                16, 25, 24, 11, 18, 19, 9, 67, 65, 73, 92, 17,\n                                6, 66, 76, 67, 66, 64, 2, 1, 1, 1, 2, 5, 13, 4,\n                                6, 11, 12, 60, 58, 54, 49, 42, 35, 27, 11, 79,\n                                1, 32, 25, 23, 18, 14, 7, 4, 2, 71, 82, 77, 71,\n                                77, 70, 1, 71, 77, 65, 2, 3, 2, 5, 4, 3, 62, 59,\n                                49, 40, 33, 24, 12, 64, 85 },\n\n                              {\n\n                              62,\n                                8, 75, 62, 8, 75, 109, 89, 14, 10, 8, 16, 47,\n                                50, 54, 14, 94, 3, 69, 5, 1, 7, 70, 3, 75, 15,\n                                45, 83, 100, 109, 98, 91, 67, 69, 5, 1, 82, 84,\n                                6, 13, 67, 77, 89, 5, 71, 82, 89, 5, 74, 87, 6,\n                                71, 79, 88, 1, 70, 71, 76, 67, 5, 22, 0, 0, 0,\n                                77, 88, 97, 67, 14, 0, 18, 75, 94, 109, 80, 85,\n                                11, 64, 81, 73, 96, 77, 90, 84, 108, 87, 85, 91,\n                                99, 19, 64, 7, 87, 72, 86, 82, 111, 6, 0, 1, 72,\n                                16, 68, 66, 83, 83, 74, 74, 72, 8, 10, 66, 13,\n                                18, 78, 0, 67, 67, 5, 74, 22, 66, 2, 22, 27, 32,\n                                26, 19, 86, 68, 71, 9, 9, 95, 5, 9, 7, 4, 7, 7,\n                                9, 7, 2, 4, 65, 4, 16, 10, 76, 65, 2, 68, 9, 14,\n                                16, 9, 9, 7, 5, 4, 17, 16, 12, 77, 3, 74, 29,\n                                22, 18, 14, 17, 18, 11, 16, 22, 0, 14, 9, 8, 4,\n                                65, 9, 3, 6, 8, 5, 12, 19, 5, 81, 4, 76, 8, 19,\n                                83, 41, 52, 43, 42, 43, 43, 39, 39, 34, 25, 20,\n                                17, 20, 12, 80, 67, 1, 72, 23, 20, 17, 21, 17,\n                                11, 9, 10, 69, 64, 69, 93, 87, 102, 72, 21, 18,\n                                11, 1, 6, 67, 72, 77, 91, 71, 38, 21, 15, 8, 8,\n                                66, 75, 80, 100, 5, 36, 28, 25, 19, 12, 5, 64,\n                                72, 83, 70, 37, 29, 17, 4, 7, 70, 79, 90, 5, 53,\n                                43, 37, 28, 22, 5, 68, 75, 80, 62, 97, 96, 80,\n                                100, 98, 89, 96, 92, 91, 93, 93, 95, 89, 87, 87,\n                                87, 80, 82, 72, 77, 78, 69, 64, 0, 64, 6, 4, 3,\n                                64, 16, 13, 13, 10, 6, 17, 13, 7, 14, 13, 10, 7,\n                                6, 65, 67, 67, 6, 73, 13, 27, 13, 9, 21, 19, 13,\n                                15, 21, 15, 21, 5, 0, 4, 44, 43, 47, 41, 41, 51,\n                                58, 58, 62, 62, 62, 62, 62, 52, 21, 59, 62, 59,\n                                62, 56, 49, 36, 26, 24, 6, 73, 71, 85, 103, 47,\n                                46, 48, 41, 34, 35, 26, 24, 18, 16, 9, 3, 2, 75,\n                                79, 65, 66, 75, 26, 29, 24, 15, 23, 22, 9, 16,\n                                17, 7, 68, 66, 74, 92, 16, 6, 67, 76, 66, 65,\n                                64, 2, 2, 2, 2, 3, 6, 14, 5, 7, 12, 13, 60, 56,\n                                52, 46, 40, 32, 24, 8, 81, 1, 33, 26, 23, 19,\n                                15, 7, 5, 2, 71, 81, 77, 70, 76, 69, 2, 71, 76,\n                                65, 2, 3, 2, 6, 4, 3, 62, 57, 46, 37, 30, 20, 8,\n                                68, 88 },\n\n                              {\n\n                              62,\n                                8, 76, 62, 8, 76, 107, 88, 15, 10, 8, 15, 46,\n                                49, 54, 14, 92, 3, 69, 6, 1, 6, 70, 2, 76, 14,\n                                44, 84, 101, 110, 95, 90, 67, 69, 6, 1, 81, 83,\n                                7, 12, 66, 76, 88, 4, 71, 82, 89, 5, 73, 87, 6,\n                                71, 78, 88, 1, 70, 71, 76, 67, 5, 22, 0, 0, 0,\n                                76, 88, 97, 67, 14, 64, 18, 75, 93, 107, 78, 83,\n                                12, 1, 80, 72, 94, 76, 89, 84, 107, 87, 85, 91,\n                                99, 20, 64, 7, 86, 71, 85, 81, 110, 6, 64, 0,\n                                73, 16, 68, 66, 82, 83, 73, 74, 72, 8, 10, 65,\n                                13, 17, 78, 0, 67, 67, 5, 74, 21, 66, 2, 21, 26,\n                                31, 26, 19, 86, 68, 71, 9, 8, 95, 4, 9, 7, 4, 7,\n                                7, 9, 7, 2, 4, 64, 4, 15, 10, 76, 66, 2, 69, 9,\n                                13, 16, 9, 8, 7, 5, 4, 15, 16, 11, 77, 3, 75,\n                                28, 22, 17, 14, 17, 18, 11, 16, 22, 0, 13, 9, 7,\n                                4, 65, 8, 2, 6, 7, 4, 11, 18, 5, 81, 4, 75, 7,\n                                17, 83, 39, 50, 41, 40, 41, 41, 37, 37, 32, 23,\n                                19, 16, 18, 10, 81, 67, 1, 73, 22, 19, 16, 19,\n                                16, 10, 8, 9, 70, 65, 70, 93, 87, 101, 71, 21,\n                                18, 11, 2, 6, 67, 72, 76, 90, 70, 37, 21, 15, 8,\n                                9, 66, 74, 79, 98, 5, 37, 28, 25, 19, 13, 5, 64,\n                                71, 83, 70, 37, 29, 17, 4, 7, 69, 78, 89, 5, 53,\n                                43, 36, 28, 22, 5, 67, 74, 79, 62, 97, 95, 80,\n                                99, 97, 88, 94, 91, 90, 92, 92, 94, 89, 86, 87,\n                                86, 78, 82, 73, 77, 78, 69, 64, 64, 64, 5, 3, 2,\n                                65, 16, 13, 13, 10, 6, 16, 12, 7, 14, 13, 9, 7,\n                                6, 65, 68, 67, 6, 74, 13, 26, 12, 8, 20, 19, 14,\n                                15, 20, 15, 21, 5, 0, 3, 43, 42, 46, 40, 40, 50,\n                                56, 56, 61, 60, 62, 62, 60, 49, 20, 57, 62, 56,\n                                62, 53, 47, 34, 25, 23, 6, 72, 71, 83, 100, 45,\n                                44, 46, 39, 32, 33, 25, 22, 16, 15, 8, 2, 1, 76,\n                                80, 65, 67, 76, 25, 28, 23, 13, 21, 20, 8, 15,\n                                15, 6, 70, 68, 76, 93, 15, 5, 68, 76, 66, 65, 0,\n                                3, 2, 4, 3, 4, 7, 15, 7, 8, 14, 14, 59, 55, 50,\n                                44, 37, 30, 21, 6, 83, 2, 33, 26, 24, 19, 16, 8,\n                                5, 3, 70, 81, 76, 70, 76, 68, 3, 71, 76, 64, 3,\n                                3, 3, 7, 4, 3, 62, 55, 44, 34, 26, 16, 5, 71, 90 },\n\n                              {\n\n                              62,\n                                8, 76, 62, 8, 76, 106, 86, 15, 10, 7, 13, 44,\n                                48, 54, 14, 90, 3, 68, 7, 1, 5, 70, 1, 77, 14,\n                                42, 86, 102, 110, 92, 89, 67, 68, 7, 1, 81, 82,\n                                7, 12, 66, 76, 87, 4, 72, 82, 89, 5, 73, 86, 6,\n                                72, 78, 88, 2, 70, 71, 76, 66, 5, 22, 0, 0, 0,\n                                76, 89, 97, 66, 13, 64, 18, 75, 93, 105, 77, 82,\n                                14, 2, 79, 71, 93, 75, 88, 83, 105, 86, 85, 90,\n                                98, 20, 64, 7, 86, 71, 85, 81, 108, 6, 64, 0,\n                                73, 16, 68, 66, 82, 83, 73, 74, 71, 8, 10, 65,\n                                13, 17, 78, 0, 67, 67, 5, 74, 20, 67, 2, 20, 25,\n                                30, 25, 18, 85, 67, 71, 8, 8, 94, 4, 9, 7, 4, 7,\n                                7, 10, 7, 2, 3, 64, 3, 14, 9, 77, 66, 2, 69, 8,\n                                12, 16, 8, 7, 7, 5, 4, 14, 16, 10, 77, 3, 75,\n                                27, 22, 17, 14, 17, 18, 11, 16, 21, 0, 13, 9, 7,\n                                4, 66, 8, 2, 5, 7, 4, 10, 17, 4, 81, 3, 75, 6,\n                                16, 83, 38, 48, 39, 38, 39, 39, 35, 35, 30, 21,\n                                17, 14, 16, 8, 82, 67, 1, 73, 21, 18, 15, 18,\n                                14, 8, 7, 7, 71, 65, 70, 93, 87, 101, 71, 21,\n                                18, 11, 2, 6, 67, 72, 76, 89, 70, 37, 21, 15, 8,\n                                9, 65, 74, 78, 96, 5, 37, 28, 25, 19, 13, 5, 64,\n                                71, 82, 70, 37, 29, 16, 4, 7, 69, 78, 88, 5, 52,\n                                42, 35, 27, 22, 5, 67, 74, 79, 62, 96, 94, 79,\n                                98, 96, 87, 93, 90, 89, 91, 90, 92, 88, 86, 87,\n                                86, 77, 82, 73, 77, 77, 69, 65, 64, 64, 4, 2, 1,\n                                66, 15, 12, 13, 9, 5, 16, 12, 7, 13, 12, 9, 7,\n                                5, 66, 68, 67, 6, 74, 12, 26, 11, 8, 19, 18, 14,\n                                14, 19, 14, 20, 4, 64, 1, 42, 41, 46, 39, 39,\n                                48, 54, 54, 59, 57, 62, 62, 57, 47, 19, 54, 62,\n                                53, 58, 50, 44, 32, 24, 21, 6, 71, 71, 82, 98,\n                                43, 42, 44, 37, 30, 31, 23, 20, 15, 13, 7, 0,\n                                64, 77, 81, 66, 67, 77, 24, 26, 21, 11, 19, 18,\n                                6, 13, 13, 4, 71, 69, 77, 94, 14, 4, 69, 76, 65,\n                                65, 0, 3, 3, 5, 3, 5, 8, 16, 8, 9, 15, 15, 59,\n                                53, 48, 41, 35, 27, 18, 3, 86, 2, 34, 27, 24,\n                                19, 16, 8, 5, 3, 70, 81, 76, 69, 75, 67, 4, 71,\n                                75, 64, 3, 3, 3, 8, 4, 3, 61, 53, 41, 31, 23,\n                                12, 1, 75, 93 },\n\n                              {\n\n                              62,\n                                8, 76, 62, 8, 76, 104, 85, 15, 10, 7, 12, 43,\n                                46, 54, 14, 87, 2, 67, 7, 1, 5, 69, 0, 78, 13,\n                                40, 88, 103, 111, 89, 87, 67, 67, 7, 1, 81, 81,\n                                7, 11, 66, 76, 87, 4, 72, 81, 89, 5, 73, 85, 5,\n                                72, 78, 88, 2, 69, 70, 75, 66, 5, 22, 0, 0, 0,\n                                75, 89, 97, 66, 12, 64, 18, 74, 93, 104, 75, 80,\n                                15, 4, 77, 70, 92, 73, 87, 82, 103, 86, 84, 90,\n                                97, 20, 64, 7, 85, 71, 84, 80, 107, 5, 64, 0,\n                                73, 16, 68, 65, 81, 83, 73, 74, 71, 8, 9, 65,\n                                13, 17, 77, 0, 66, 67, 5, 74, 20, 67, 2, 20, 24,\n                                30, 24, 17, 84, 67, 71, 7, 7, 94, 3, 9, 6, 4, 7,\n                                7, 11, 8, 2, 3, 64, 3, 13, 9, 78, 66, 2, 70, 8,\n                                11, 15, 8, 7, 8, 5, 4, 13, 15, 9, 77, 3, 76, 27,\n                                22, 17, 14, 17, 18, 11, 16, 21, 0, 13, 9, 7, 4,\n                                66, 8, 2, 5, 7, 4, 10, 16, 4, 81, 3, 75, 5, 15,\n                                83, 36, 46, 38, 37, 37, 37, 33, 33, 28, 19, 15,\n                                12, 13, 7, 83, 67, 0, 74, 20, 17, 14, 17, 13, 7,\n                                6, 6, 71, 66, 71, 93, 87, 100, 71, 21, 18, 11,\n                                2, 6, 66, 71, 75, 88, 69, 37, 21, 15, 8, 9, 65,\n                                73, 78, 94, 5, 37, 28, 25, 19, 13, 5, 64, 71,\n                                81, 70, 38, 28, 16, 4, 7, 69, 78, 88, 5, 52, 41,\n                                34, 26, 22, 5, 67, 74, 78, 62, 95, 93, 78, 96,\n                                95, 86, 92, 88, 88, 89, 89, 90, 87, 85, 86, 85,\n                                76, 81, 74, 76, 76, 69, 65, 65, 65, 4, 1, 0, 67,\n                                14, 12, 13, 9, 5, 15, 12, 7, 12, 11, 9, 6, 4,\n                                66, 68, 67, 6, 74, 11, 25, 11, 8, 18, 17, 14,\n                                13, 18, 14, 20, 3, 65, 64, 41, 41, 45, 38, 37,\n                                47, 52, 52, 57, 55, 62, 61, 54, 45, 17, 51, 62,\n                                50, 54, 48, 42, 30, 23, 20, 6, 70, 70, 81, 96,\n                                42, 41, 42, 36, 28, 29, 22, 18, 14, 11, 5, 65,\n                                65, 78, 82, 66, 67, 78, 22, 25, 19, 10, 18, 17,\n                                5, 12, 12, 3, 72, 70, 78, 94, 14, 4, 70, 75, 65,\n                                64, 1, 4, 4, 6, 4, 6, 9, 18, 9, 10, 16, 17, 58,\n                                51, 46, 39, 32, 24, 15, 0, 88, 2, 34, 27, 25,\n                                20, 17, 8, 6, 4, 69, 80, 76, 68, 75, 66, 5, 70,\n                                74, 0, 4, 3, 4, 9, 4, 3, 59, 51, 39, 28, 20, 9,\n                                66, 78, 96 },\n\n                              {\n\n                              61,\n                                8, 76, 61, 8, 76, 102, 83, 16, 10, 6, 10, 41,\n                                45, 54, 14, 85, 2, 66, 8, 1, 4, 69, 64, 79, 13,\n                                38, 89, 104, 111, 86, 86, 67, 66, 8, 1, 80, 80,\n                                8, 11, 66, 75, 86, 3, 73, 81, 89, 5, 73, 85, 5,\n                                72, 78, 88, 3, 69, 70, 75, 65, 5, 22, 0, 0, 0,\n                                75, 89, 97, 65, 11, 64, 18, 74, 93, 102, 73, 79,\n                                17, 6, 76, 69, 90, 72, 86, 81, 101, 85, 84, 89,\n                                96, 20, 64, 7, 85, 71, 84, 80, 105, 5, 65, 64,\n                                74, 16, 68, 65, 81, 83, 72, 74, 70, 8, 9, 65,\n                                13, 16, 77, 0, 66, 67, 5, 74, 19, 67, 2, 19, 23,\n                                29, 23, 16, 84, 66, 71, 6, 7, 93, 3, 9, 6, 4, 7,\n                                7, 12, 8, 2, 3, 0, 3, 12, 9, 79, 66, 2, 70, 7,\n                                10, 15, 8, 6, 8, 5, 4, 11, 15, 8, 77, 3, 76, 26,\n                                22, 17, 14, 17, 18, 11, 16, 21, 0, 12, 9, 7, 4,\n                                66, 7, 1, 4, 6, 3, 9, 15, 3, 81, 2, 75, 4, 13,\n                                83, 35, 44, 36, 35, 35, 35, 31, 31, 26, 17, 14,\n                                11, 11, 5, 84, 67, 0, 74, 19, 16, 13, 15, 11, 5,\n                                5, 5, 72, 66, 71, 93, 87, 100, 70, 21, 18, 11,\n                                2, 6, 66, 71, 75, 87, 69, 37, 21, 15, 8, 10, 64,\n                                72, 77, 92, 5, 37, 28, 25, 19, 14, 5, 64, 71,\n                                81, 70, 38, 28, 15, 4, 7, 69, 78, 87, 5, 51, 41,\n                                33, 25, 22, 5, 67, 73, 78, 62, 94, 92, 78, 95,\n                                94, 85, 90, 87, 87, 88, 87, 89, 87, 84, 86, 85,\n                                74, 81, 74, 76, 76, 69, 66, 65, 65, 3, 0, 64,\n                                68, 14, 11, 13, 8, 4, 15, 11, 7, 11, 11, 8, 6,\n                                3, 66, 69, 67, 6, 75, 11, 25, 10, 8, 17, 17, 14,\n                                12, 17, 13, 19, 2, 65, 65, 40, 40, 45, 37, 36,\n                                45, 50, 50, 55, 52, 60, 59, 51, 42, 16, 48, 62,\n                                47, 50, 45, 39, 28, 22, 19, 6, 69, 70, 80, 94,\n                                40, 39, 40, 34, 26, 27, 20, 16, 12, 10, 4, 66,\n                                67, 79, 83, 67, 68, 79, 21, 23, 18, 8, 16, 15,\n                                3, 10, 10, 1, 73, 72, 80, 95, 13, 3, 71, 75, 64,\n                                64, 1, 4, 4, 7, 5, 7, 10, 19, 10, 11, 18, 18,\n                                58, 50, 44, 36, 30, 21, 12, 66, 90, 3, 35, 28,\n                                25, 20, 18, 9, 6, 4, 69, 80, 75, 68, 74, 65, 6,\n                                70, 74, 0, 4, 3, 4, 10, 4, 3, 58, 49, 36, 25,\n                                17, 5, 70, 82, 98 },\n\n                              {\n\n                              60,\n                                8, 76, 60, 8, 76, 100, 82, 16, 10, 6, 9, 40, 44,\n                                54, 14, 83, 2, 65, 9, 1, 3, 69, 65, 80, 12, 36,\n                                91, 105, 112, 83, 85, 67, 65, 9, 1, 80, 79, 8,\n                                10, 66, 75, 85, 3, 73, 81, 89, 5, 73, 84, 5, 72,\n                                78, 88, 3, 69, 70, 75, 65, 5, 22, 0, 0, 0, 74,\n                                89, 97, 65, 10, 64, 18, 74, 93, 100, 71, 77, 18,\n                                8, 75, 68, 89, 71, 85, 80, 99, 85, 84, 89, 95,\n                                20, 64, 7, 84, 71, 83, 79, 104, 5, 65, 64, 74,\n                                16, 68, 65, 80, 83, 72, 74, 70, 8, 9, 65, 13,\n                                16, 77, 0, 66, 67, 5, 74, 18, 67, 2, 18, 22, 28,\n                                22, 15, 83, 66, 71, 5, 6, 93, 2, 9, 6, 4, 7, 7,\n                                13, 8, 2, 3, 0, 3, 11, 9, 80, 66, 2, 71, 7, 9,\n                                15, 8, 5, 8, 5, 4, 10, 15, 7, 77, 3, 77, 25, 22,\n                                17, 14, 17, 18, 11, 16, 21, 0, 12, 9, 7, 4, 66,\n                                7, 1, 4, 6, 3, 8, 14, 3, 81, 2, 75, 3, 12, 83,\n                                33, 42, 34, 33, 33, 33, 29, 29, 24, 15, 12, 9,\n                                9, 3, 85, 67, 0, 75, 18, 15, 12, 14, 10, 4, 4,\n                                4, 73, 67, 72, 93, 87, 99, 70, 21, 18, 11, 2, 6,\n                                66, 71, 74, 86, 68, 37, 21, 15, 8, 10, 64, 71,\n                                76, 90, 5, 37, 28, 25, 19, 14, 5, 64, 71, 80,\n                                70, 38, 28, 15, 4, 7, 69, 78, 86, 5, 51, 40, 32,\n                                24, 22, 5, 67, 73, 77, 62, 93, 91, 77, 94, 93,\n                                84, 89, 86, 86, 87, 86, 87, 86, 83, 86, 84, 73,\n                                81, 75, 76, 75, 69, 66, 66, 65, 2, 64, 65, 69,\n                                13, 11, 13, 8, 4, 14, 11, 7, 10, 10, 8, 6, 2,\n                                66, 69, 67, 6, 75, 10, 24, 9, 8, 16, 16, 14, 11,\n                                16, 13, 19, 1, 66, 67, 39, 39, 44, 36, 35, 44,\n                                48, 48, 53, 50, 57, 56, 48, 40, 15, 45, 59, 44,\n                                46, 42, 37, 26, 21, 18, 6, 68, 70, 79, 92, 38,\n                                37, 38, 32, 24, 25, 19, 14, 11, 8, 3, 68, 68,\n                                80, 84, 67, 68, 80, 20, 22, 16, 6, 14, 13, 2, 9,\n                                8, 0, 74, 73, 81, 96, 12, 2, 72, 75, 64, 64, 2,\n                                5, 5, 8, 6, 8, 11, 20, 11, 12, 19, 19, 57, 48,\n                                42, 34, 27, 18, 9, 69, 92, 3, 35, 28, 26, 20,\n                                19, 9, 6, 5, 68, 80, 75, 67, 74, 64, 7, 70, 73,\n                                1, 5, 3, 5, 11, 4, 3, 57, 47, 34, 22, 14, 1, 74,\n                                85, 101 },\n\n                              {\n\n                              58,\n                                7, 77, 58, 7, 77, 99, 81, 16, 10, 5, 7, 38, 42,\n                                53, 14, 81, 1, 65, 9, 0, 2, 69, 67, 82, 11, 34,\n                                93, 106, 113, 81, 84, 68, 65, 9, 0, 80, 78, 8,\n                                9, 66, 75, 85, 2, 74, 81, 90, 5, 73, 84, 4, 73,\n                                78, 88, 3, 69, 70, 75, 65, 4, 22, 0, 0, 0, 74,\n                                90, 97, 65, 9, 65, 18, 74, 93, 99, 70, 76, 19,\n                                9, 74, 67, 88, 70, 84, 80, 98, 85, 84, 89, 95,\n                                20, 64, 7, 84, 71, 83, 79, 103, 4, 66, 65, 75,\n                                16, 68, 65, 80, 83, 72, 74, 70, 7, 8, 65, 12,\n                                15, 77, 64, 66, 67, 4, 74, 17, 68, 1, 17, 20,\n                                27, 21, 14, 83, 66, 71, 4, 5, 93, 1, 8, 5, 4, 7,\n                                7, 13, 8, 2, 2, 0, 2, 10, 8, 81, 67, 1, 72, 6,\n                                8, 14, 7, 4, 8, 5, 4, 8, 14, 6, 77, 3, 78, 24,\n                                21, 16, 14, 17, 17, 10, 16, 20, 64, 11, 9, 6, 3,\n                                67, 6, 0, 3, 5, 2, 7, 13, 2, 81, 1, 75, 2, 10,\n                                83, 31, 40, 32, 31, 31, 30, 27, 27, 22, 13, 10,\n                                7, 6, 1, 87, 68, 64, 76, 17, 13, 10, 12, 8, 2,\n                                2, 2, 74, 68, 73, 93, 87, 99, 70, 21, 18, 11, 2,\n                                6, 66, 71, 74, 85, 68, 36, 21, 15, 8, 10, 64,\n                                71, 76, 89, 4, 37, 28, 24, 18, 14, 5, 64, 71,\n                                80, 70, 38, 27, 14, 3, 7, 69, 78, 86, 5, 50, 39,\n                                31, 23, 21, 5, 67, 73, 77, 62, 93, 90, 77, 93,\n                                92, 84, 88, 85, 85, 86, 85, 86, 86, 83, 86, 84,\n                                72, 81, 76, 76, 75, 69, 67, 67, 66, 1, 65, 67,\n                                71, 12, 10, 13, 7, 3, 13, 10, 6, 9, 9, 7, 5, 1,\n                                67, 70, 67, 6, 76, 9, 23, 8, 7, 15, 15, 14, 10,\n                                14, 12, 18, 0, 67, 69, 38, 38, 43, 34, 33, 42,\n                                46, 46, 50, 47, 54, 53, 45, 37, 13, 42, 55, 41,\n                                41, 39, 34, 24, 19, 16, 6, 68, 70, 78, 90, 36,\n                                35, 36, 30, 21, 23, 17, 11, 9, 6, 1, 70, 70, 81,\n                                85, 68, 69, 82, 18, 20, 14, 4, 12, 11, 0, 7, 6,\n                                65, 76, 75, 83, 97, 11, 1, 73, 75, 64, 64, 2, 5,\n                                5, 9, 6, 9, 11, 21, 12, 13, 20, 20, 56, 46, 39,\n                                31, 24, 15, 5, 72, 95, 3, 35, 28, 26, 20, 19, 9,\n                                6, 5, 68, 80, 75, 67, 74, 0, 8, 70, 73, 1, 5, 3,\n                                5, 11, 4, 2, 55, 44, 31, 19, 10, 66, 78, 89, 104 },\n\n                              {\n\n                              57,\n                                7, 77, 57, 7, 77, 97, 79, 17, 11, 5, 6, 37, 41,\n                                53, 14, 78, 1, 64, 10, 0, 2, 68, 68, 83, 11, 33,\n                                94, 107, 113, 78, 82, 68, 64, 10, 0, 79, 76, 9,\n                                9, 65, 74, 84, 2, 74, 80, 90, 5, 72, 83, 4, 73,\n                                77, 88, 4, 68, 69, 74, 64, 4, 22, 0, 0, 0, 73,\n                                90, 97, 64, 9, 65, 18, 73, 92, 97, 68, 74, 21,\n                                11, 72, 66, 86, 68, 82, 79, 96, 84, 83, 88, 94,\n                                21, 0, 8, 83, 70, 82, 78, 101, 4, 66, 65, 75,\n                                17, 68, 64, 79, 82, 71, 73, 69, 7, 8, 64, 12,\n                                15, 76, 64, 65, 67, 4, 73, 17, 68, 1, 17, 19,\n                                27, 21, 14, 82, 65, 70, 4, 5, 92, 1, 8, 5, 5, 7,\n                                7, 14, 9, 3, 2, 1, 2, 10, 8, 81, 67, 1, 72, 6,\n                                7, 14, 7, 4, 9, 6, 4, 7, 14, 6, 76, 3, 78, 24,\n                                21, 16, 14, 17, 17, 10, 16, 20, 64, 11, 9, 6, 3,\n                                67, 6, 0, 3, 5, 2, 7, 13, 2, 80, 1, 74, 2, 9,\n                                82, 30, 39, 31, 30, 29, 28, 26, 26, 20, 12, 9,\n                                6, 4, 0, 88, 68, 64, 76, 16, 12, 9, 11, 7, 1, 1,\n                                1, 74, 68, 73, 92, 86, 98, 69, 22, 18, 11, 3, 7,\n                                65, 70, 73, 83, 67, 36, 21, 15, 8, 11, 0, 70,\n                                75, 87, 4, 38, 29, 24, 18, 15, 5, 64, 70, 79,\n                                70, 39, 27, 14, 3, 8, 68, 77, 85, 5, 50, 39, 31,\n                                23, 21, 5, 66, 72, 76, 62, 92, 89, 76, 91, 90,\n                                83, 86, 83, 83, 84, 83, 84, 85, 82, 85, 83, 70,\n                                80, 76, 75, 74, 68, 67, 67, 66, 1, 65, 68, 72,\n                                12, 10, 14, 7, 3, 13, 10, 6, 9, 9, 7, 5, 1, 67,\n                                70, 66, 7, 76, 9, 23, 8, 7, 15, 15, 15, 10, 13,\n                                12, 18, 0, 67, 70, 38, 38, 43, 33, 32, 41, 44,\n                                44, 48, 45, 52, 51, 43, 35, 12, 40, 52, 38, 37,\n                                37, 32, 23, 18, 15, 6, 67, 69, 76, 87, 35, 34,\n                                35, 29, 19, 22, 16, 9, 8, 5, 0, 71, 71, 82, 85,\n                                68, 69, 83, 17, 19, 13, 3, 11, 10, 64, 6, 5, 66,\n                                77, 76, 84, 97, 11, 1, 73, 74, 0, 0, 3, 6, 6,\n                                11, 7, 10, 12, 23, 14, 14, 22, 22, 56, 45, 37,\n                                29, 22, 13, 2, 74, 97, 4, 36, 29, 27, 21, 20,\n                                10, 7, 6, 67, 79, 74, 66, 73, 2, 10, 69, 72, 2,\n                                6, 4, 6, 12, 4, 2, 54, 42, 29, 17, 7, 69, 81,\n                                92, 106 },\n\n                              {\n\n                              56,\n                                7, 77, 56, 7, 77, 95, 78, 17, 11, 5, 5, 36, 40,\n                                53, 14, 76, 1, 0, 11, 0, 1, 68, 69, 84, 10, 31,\n                                96, 108, 114, 75, 81, 68, 0, 11, 0, 79, 75, 9,\n                                8, 65, 74, 83, 2, 74, 80, 90, 5, 72, 82, 4, 73,\n                                77, 88, 4, 68, 69, 74, 64, 4, 22, 0, 0, 0, 72,\n                                90, 97, 64, 8, 65, 18, 73, 92, 95, 66, 72, 22,\n                                13, 71, 65, 85, 67, 81, 78, 94, 84, 83, 88, 93,\n                                21, 0, 8, 82, 70, 81, 78, 100, 4, 66, 65, 75,\n                                17, 68, 64, 79, 82, 71, 73, 69, 7, 8, 64, 12,\n                                15, 76, 64, 65, 67, 4, 73, 16, 68, 1, 16, 18,\n                                26, 20, 13, 81, 65, 70, 3, 4, 92, 0, 8, 5, 5, 7,\n                                7, 15, 9, 3, 2, 1, 2, 9, 8, 82, 67, 1, 73, 6, 6,\n                                14, 7, 3, 9, 6, 4, 6, 14, 5, 76, 3, 79, 23, 21,\n                                16, 14, 17, 17, 10, 16, 20, 64, 11, 9, 6, 3, 67,\n                                6, 0, 3, 5, 2, 6, 12, 1, 80, 1, 74, 1, 8, 82,\n                                28, 37, 29, 28, 27, 26, 24, 24, 18, 10, 7, 4, 2,\n                                65, 89, 68, 64, 77, 15, 11, 8, 10, 5, 0, 0, 0,\n                                75, 69, 74, 92, 86, 97, 69, 22, 18, 11, 3, 7,\n                                65, 70, 73, 82, 66, 36, 21, 15, 8, 11, 0, 69,\n                                74, 85, 4, 38, 29, 24, 18, 15, 5, 64, 70, 78,\n                                70, 39, 27, 14, 3, 8, 68, 77, 84, 5, 49, 38, 30,\n                                22, 21, 5, 66, 72, 76, 62, 91, 88, 75, 90, 89,\n                                82, 85, 82, 82, 83, 82, 82, 84, 81, 85, 82, 69,\n                                80, 77, 75, 73, 68, 67, 68, 66, 0, 66, 69, 73,\n                                11, 10, 14, 7, 2, 12, 10, 6, 8, 8, 7, 5, 0, 67,\n                                70, 66, 7, 76, 8, 22, 7, 7, 14, 14, 15, 9, 12,\n                                12, 18, 64, 68, 72, 37, 37, 42, 32, 31, 40, 42,\n                                42, 46, 43, 49, 48, 40, 33, 11, 37, 49, 35, 33,\n                                34, 30, 21, 17, 14, 6, 66, 69, 75, 85, 33, 32,\n                                33, 27, 17, 20, 14, 7, 7, 3, 64, 73, 72, 83, 86,\n                                69, 69, 84, 16, 18, 11, 1, 9, 8, 65, 4, 3, 67,\n                                78, 77, 85, 98, 10, 0, 74, 74, 0, 0, 4, 6, 7,\n                                12, 8, 11, 13, 24, 15, 15, 23, 23, 55, 43, 35,\n                                27, 19, 10, 64, 77, 99, 4, 36, 29, 27, 21, 21,\n                                10, 7, 6, 67, 79, 74, 65, 73, 3, 11, 69, 71, 3,\n                                7, 4, 6, 13, 4, 2, 53, 40, 27, 14, 4, 73, 85,\n                                95, 109 },\n\n                              {\n\n                              55,\n                                7, 77, 55, 7, 77, 93, 76, 18, 11, 4, 3, 34, 39,\n                                53, 14, 74, 1, 1, 12, 0, 0, 68, 70, 85, 10, 29,\n                                97, 109, 114, 72, 80, 68, 1, 12, 0, 78, 74, 10,\n                                8, 65, 73, 82, 1, 75, 80, 90, 5, 72, 82, 4, 73,\n                                77, 88, 5, 68, 69, 74, 0, 4, 22, 0, 0, 0, 72,\n                                90, 97, 0, 7, 65, 18, 73, 92, 93, 64, 71, 24,\n                                15, 70, 64, 83, 66, 80, 77, 92, 83, 83, 87, 92,\n                                21, 0, 8, 82, 70, 81, 77, 98, 4, 67, 66, 76, 17,\n                                68, 64, 78, 82, 70, 73, 68, 7, 8, 64, 12, 14,\n                                76, 64, 65, 67, 4, 73, 15, 68, 1, 15, 17, 25,\n                                19, 12, 81, 64, 70, 2, 4, 91, 0, 8, 5, 5, 7, 7,\n                                16, 9, 3, 2, 2, 2, 8, 8, 83, 67, 1, 73, 5, 5,\n                                14, 7, 2, 9, 6, 4, 4, 14, 4, 76, 3, 79, 22, 21,\n                                16, 14, 17, 17, 10, 16, 20, 64, 10, 9, 6, 3, 67,\n                                5, 64, 2, 4, 1, 5, 11, 1, 80, 0, 74, 0, 6, 82,\n                                27, 35, 27, 26, 25, 24, 22, 22, 16, 8, 6, 3, 0,\n                                67, 90, 68, 64, 77, 14, 10, 7, 8, 4, 65, 64, 64,\n                                76, 69, 74, 92, 86, 97, 68, 22, 18, 11, 3, 7,\n                                65, 70, 72, 81, 66, 36, 21, 15, 8, 12, 1, 68,\n                                73, 83, 4, 38, 29, 24, 18, 16, 5, 64, 70, 78,\n                                70, 39, 27, 13, 3, 8, 68, 77, 83, 5, 49, 38, 29,\n                                21, 21, 5, 66, 71, 75, 62, 90, 87, 75, 89, 88,\n                                81, 83, 81, 81, 82, 80, 81, 84, 80, 85, 82, 67,\n                                80, 77, 75, 73, 68, 68, 68, 66, 64, 67, 70, 74,\n                                11, 9, 14, 6, 2, 12, 9, 6, 7, 8, 6, 5, 64, 67,\n                                71, 66, 7, 77, 8, 22, 6, 7, 13, 14, 15, 8, 11,\n                                11, 17, 65, 68, 73, 36, 36, 42, 31, 30, 38, 40,\n                                40, 44, 40, 47, 46, 37, 30, 10, 34, 46, 32, 29,\n                                31, 27, 19, 16, 13, 6, 65, 69, 74, 83, 31, 30,\n                                31, 25, 15, 18, 13, 5, 5, 2, 65, 74, 74, 84, 87,\n                                69, 70, 85, 15, 16, 10, 64, 7, 6, 67, 3, 1, 69,\n                                79, 79, 87, 99, 9, 64, 75, 74, 1, 0, 4, 7, 7,\n                                13, 9, 12, 14, 25, 16, 16, 25, 24, 55, 42, 33,\n                                24, 17, 7, 67, 80, 101, 5, 37, 30, 28, 21, 22,\n                                11, 7, 7, 66, 79, 73, 65, 72, 4, 12, 69, 71, 3,\n                                7, 4, 7, 14, 4, 2, 52, 38, 24, 11, 1, 77, 89,\n                                99, 111 },\n\n                              {\n\n                              53,\n                                7, 77, 53, 7, 77, 92, 75, 18, 11, 4, 2, 33, 37,\n                                53, 14, 71, 0, 2, 12, 0, 64, 68, 71, 86, 9, 27,\n                                99, 110, 115, 69, 79, 68, 2, 12, 0, 78, 73, 10,\n                                7, 65, 73, 82, 1, 75, 79, 90, 5, 72, 81, 3, 74,\n                                77, 88, 5, 67, 69, 73, 0, 4, 22, 0, 0, 0, 71,\n                                91, 97, 0, 6, 65, 18, 73, 92, 92, 0, 69, 25, 16,\n                                69, 0, 82, 64, 79, 76, 90, 83, 82, 87, 91, 21,\n                                0, 8, 81, 70, 80, 77, 97, 3, 67, 66, 76, 17, 68,\n                                64, 78, 82, 70, 73, 68, 7, 7, 64, 12, 14, 76,\n                                64, 65, 67, 4, 73, 15, 69, 1, 15, 16, 24, 18,\n                                11, 80, 64, 70, 1, 3, 91, 64, 8, 4, 5, 7, 7, 17,\n                                10, 3, 1, 2, 1, 7, 7, 84, 67, 1, 74, 5, 4, 13,\n                                6, 2, 10, 6, 4, 3, 13, 3, 76, 3, 80, 22, 21, 16,\n                                14, 17, 17, 10, 16, 19, 64, 10, 9, 6, 3, 68, 5,\n                                64, 2, 4, 1, 5, 10, 0, 80, 0, 74, 64, 5, 82, 25,\n                                33, 25, 24, 23, 22, 20, 20, 14, 6, 4, 1, 66, 69,\n                                91, 68, 65, 78, 13, 9, 6, 7, 2, 66, 65, 66, 76,\n                                70, 75, 92, 86, 96, 68, 22, 18, 11, 3, 7, 65,\n                                70, 72, 80, 65, 36, 21, 15, 8, 12, 1, 68, 73,\n                                81, 4, 38, 29, 24, 18, 16, 5, 64, 70, 77, 70,\n                                39, 26, 13, 3, 8, 68, 77, 83, 5, 48, 37, 28, 20,\n                                21, 5, 66, 71, 75, 62, 89, 86, 74, 87, 87, 80,\n                                82, 79, 80, 80, 79, 79, 83, 80, 84, 81, 66, 79,\n                                78, 75, 72, 68, 68, 69, 67, 65, 68, 71, 75, 10,\n                                9, 14, 6, 1, 11, 9, 6, 6, 7, 6, 4, 65, 68, 71,\n                                66, 7, 77, 7, 21, 5, 7, 12, 13, 15, 7, 10, 11,\n                                17, 66, 69, 75, 35, 36, 41, 30, 28, 37, 38, 38,\n                                42, 38, 44, 43, 34, 28, 8, 31, 42, 29, 25, 29,\n                                25, 17, 15, 11, 6, 64, 68, 73, 81, 30, 28, 29,\n                                24, 13, 16, 11, 3, 4, 0, 67, 76, 75, 85, 88, 70,\n                                70, 86, 13, 15, 8, 65, 5, 4, 68, 1, 64, 70, 80,\n                                80, 88, 99, 8, 64, 76, 74, 1, 1, 5, 7, 8, 14, 9,\n                                13, 15, 26, 17, 17, 26, 25, 54, 40, 31, 22, 14,\n                                4, 70, 83, 104, 5, 37, 30, 28, 22, 22, 11, 8, 7,\n                                66, 78, 73, 64, 72, 5, 13, 69, 70, 4, 8, 4, 7,\n                                15, 4, 2, 50, 36, 22, 8, 65, 81, 93, 102, 114 },\n\n                              {\n\n                              52,\n                                7, 77, 52, 7, 77, 90, 73, 18, 11, 3, 0, 31, 36,\n                                53, 14, 69, 0, 3, 13, 0, 64, 67, 72, 87, 9, 25,\n                                101, 111, 115, 66, 77, 68, 3, 13, 0, 78, 72, 10,\n                                7, 65, 73, 81, 1, 76, 79, 90, 5, 72, 80, 3, 74,\n                                77, 88, 6, 67, 68, 73, 1, 4, 22, 0, 0, 0, 71,\n                                91, 97, 1, 5, 65, 18, 72, 92, 90, 2, 68, 27, 18,\n                                67, 1, 81, 0, 78, 75, 88, 82, 82, 86, 90, 21, 0,\n                                8, 81, 70, 80, 76, 95, 3, 67, 66, 76, 17, 68, 0,\n                                77, 82, 70, 73, 67, 7, 7, 64, 12, 14, 75, 64,\n                                64, 67, 4, 73, 14, 69, 1, 14, 15, 24, 17, 10,\n                                79, 0, 70, 0, 3, 90, 64, 8, 4, 5, 7, 7, 18, 10,\n                                3, 1, 2, 1, 6, 7, 85, 67, 1, 74, 4, 3, 13, 6, 1,\n                                10, 6, 4, 2, 13, 2, 76, 3, 80, 21, 21, 16, 14,\n                                17, 17, 10, 16, 19, 64, 10, 9, 6, 3, 68, 5, 64,\n                                1, 4, 1, 4, 9, 0, 80, 64, 74, 65, 4, 82, 24, 31,\n                                24, 23, 21, 20, 18, 18, 12, 4, 2, 64, 68, 70,\n                                92, 68, 65, 78, 12, 8, 5, 6, 1, 68, 66, 67, 77,\n                                70, 75, 92, 86, 96, 68, 22, 18, 11, 3, 7, 64,\n                                69, 71, 79, 65, 36, 21, 15, 8, 12, 2, 67, 72,\n                                79, 4, 38, 29, 24, 18, 16, 5, 64, 70, 76, 70,\n                                40, 26, 12, 3, 8, 68, 77, 82, 5, 48, 36, 27, 19,\n                                21, 5, 66, 71, 74, 62, 88, 85, 73, 86, 86, 79,\n                                81, 78, 79, 79, 77, 77, 82, 79, 84, 81, 65, 79,\n                                78, 74, 71, 68, 69, 69, 67, 65, 69, 72, 76, 9,\n                                8, 14, 5, 1, 11, 9, 6, 5, 6, 6, 4, 66, 68, 71,\n                                66, 7, 77, 6, 21, 5, 7, 11, 12, 15, 6, 9, 10,\n                                16, 67, 70, 77, 34, 35, 41, 29, 27, 35, 36, 36,\n                                40, 35, 41, 41, 31, 26, 7, 28, 39, 26, 21, 26,\n                                22, 15, 14, 10, 6, 0, 68, 72, 79, 28, 27, 27,\n                                22, 11, 14, 10, 1, 3, 65, 68, 78, 77, 86, 89,\n                                70, 70, 87, 12, 13, 6, 67, 4, 3, 70, 0, 65, 72,\n                                81, 81, 89, 100, 8, 65, 77, 73, 2, 1, 5, 8, 9,\n                                15, 10, 14, 16, 28, 18, 18, 27, 27, 54, 38, 29,\n                                19, 12, 1, 73, 86, 106, 5, 38, 31, 29, 22, 23,\n                                11, 8, 8, 65, 78, 73, 0, 71, 6, 14, 68, 69, 4,\n                                8, 4, 8, 16, 4, 2, 49, 34, 19, 5, 68, 84, 97,\n                                106, 117 },\n\n                              {\n\n                              51,\n                                7, 78, 51, 7, 78, 88, 72, 19, 11, 3, 64, 30, 35,\n                                53, 14, 67, 0, 3, 14, 0, 65, 67, 73, 88, 8, 24,\n                                102, 112, 116, 0, 76, 68, 3, 14, 0, 77, 71, 11,\n                                6, 64, 72, 80, 0, 76, 79, 90, 5, 71, 80, 3, 74,\n                                76, 88, 6, 67, 68, 73, 1, 4, 22, 0, 0, 0, 70,\n                                91, 97, 1, 5, 66, 18, 72, 91, 88, 4, 66, 28, 20,\n                                66, 2, 79, 1, 77, 75, 87, 82, 82, 86, 90, 22, 0,\n                                8, 80, 69, 79, 76, 94, 3, 68, 67, 77, 17, 68, 0,\n                                77, 82, 69, 73, 67, 7, 7, 0, 12, 13, 75, 64, 64,\n                                67, 4, 73, 13, 69, 1, 13, 14, 23, 17, 10, 79, 0,\n                                70, 0, 2, 90, 65, 8, 4, 5, 7, 7, 18, 10, 3, 1,\n                                3, 1, 5, 7, 85, 68, 1, 75, 4, 2, 13, 6, 0, 10,\n                                6, 4, 0, 13, 1, 76, 3, 81, 20, 21, 15, 14, 17,\n                                17, 10, 16, 19, 64, 9, 9, 5, 3, 68, 4, 65, 1, 3,\n                                0, 3, 8, 64, 80, 64, 73, 66, 2, 82, 22, 29, 22,\n                                21, 19, 18, 16, 16, 10, 2, 1, 65, 70, 72, 93,\n                                68, 65, 79, 11, 7, 4, 4, 64, 69, 67, 68, 78, 71,\n                                76, 92, 86, 95, 67, 22, 18, 11, 4, 7, 64, 69,\n                                71, 78, 64, 35, 21, 15, 8, 13, 2, 66, 71, 77, 4,\n                                39, 29, 24, 18, 17, 5, 64, 69, 76, 70, 40, 26,\n                                12, 3, 8, 67, 76, 81, 5, 47, 36, 26, 19, 21, 5,\n                                65, 70, 74, 62, 88, 84, 73, 85, 85, 78, 79, 77,\n                                78, 78, 76, 76, 82, 78, 84, 80, 0, 79, 79, 74,\n                                71, 68, 69, 70, 67, 66, 70, 73, 77, 9, 8, 14, 5,\n                                0, 10, 8, 6, 5, 6, 5, 4, 66, 68, 72, 66, 7, 78,\n                                6, 20, 4, 6, 10, 12, 16, 6, 8, 10, 16, 67, 70,\n                                78, 33, 34, 40, 28, 26, 34, 34, 34, 38, 33, 39,\n                                38, 28, 23, 6, 26, 36, 23, 17, 23, 20, 13, 13,\n                                9, 6, 1, 68, 70, 76, 26, 25, 25, 20, 9, 12, 8,\n                                64, 1, 66, 69, 79, 78, 87, 90, 71, 71, 88, 11,\n                                12, 5, 69, 2, 1, 71, 65, 67, 73, 83, 83, 91,\n                                101, 7, 66, 78, 73, 2, 1, 6, 8, 9, 17, 11, 15,\n                                17, 29, 20, 19, 29, 28, 53, 37, 27, 17, 9, 64,\n                                76, 88, 108, 6, 38, 31, 29, 22, 24, 12, 8, 8,\n                                65, 78, 72, 0, 71, 7, 15, 68, 69, 5, 9, 4, 8,\n                                17, 4, 2, 48, 32, 17, 2, 72, 88, 100, 109, 119 },\n\n                              {\n\n                              50,\n                                7, 78, 50, 7, 78, 86, 70, 19, 11, 2, 66, 28, 33,\n                                53, 14, 64, 64, 4, 14, 0, 66, 67, 74, 89, 8, 22,\n                                104, 113, 116, 3, 75, 68, 4, 14, 0, 77, 70, 11,\n                                6, 64, 72, 80, 0, 77, 78, 90, 5, 71, 79, 2, 74,\n                                76, 88, 7, 66, 68, 72, 2, 4, 22, 0, 0, 0, 70,\n                                91, 97, 2, 4, 66, 18, 72, 91, 87, 6, 65, 30, 22,\n                                65, 3, 78, 3, 76, 74, 85, 81, 81, 85, 89, 22, 0,\n                                8, 80, 69, 79, 75, 92, 2, 68, 67, 77, 17, 68, 0,\n                                76, 82, 69, 73, 66, 7, 6, 0, 12, 13, 75, 64, 64,\n                                67, 4, 73, 13, 69, 1, 13, 13, 22, 16, 9, 78, 1,\n                                70, 64, 2, 89, 65, 8, 3, 5, 7, 7, 19, 11, 3, 1,\n                                3, 1, 4, 7, 86, 68, 1, 75, 3, 1, 12, 6, 0, 11,\n                                6, 4, 64, 12, 0, 76, 3, 81, 20, 21, 15, 14, 17,\n                                17, 10, 16, 19, 64, 9, 9, 5, 3, 68, 4, 65, 0, 3,\n                                0, 3, 7, 64, 80, 65, 73, 67, 1, 82, 21, 27, 20,\n                                19, 17, 16, 14, 14, 8, 0, 64, 67, 73, 74, 94,\n                                68, 66, 79, 10, 6, 3, 3, 65, 71, 68, 69, 78, 71,\n                                76, 92, 86, 95, 67, 22, 18, 11, 4, 7, 64, 69,\n                                70, 77, 64, 35, 21, 15, 8, 13, 3, 65, 71, 75, 4,\n                                39, 29, 24, 18, 17, 5, 64, 69, 75, 70, 40, 25,\n                                11, 3, 8, 67, 76, 81, 5, 47, 35, 25, 18, 21, 5,\n                                65, 70, 73, 62, 87, 83, 72, 83, 84, 77, 78, 75,\n                                77, 76, 74, 74, 81, 77, 83, 80, 1, 78, 79, 74,\n                                70, 68, 70, 70, 68, 67, 71, 74, 78, 8, 7, 14, 4,\n                                0, 10, 8, 6, 4, 5, 5, 3, 67, 68, 72, 66, 7, 78,\n                                5, 20, 3, 6, 9, 11, 16, 5, 7, 9, 15, 68, 71, 80,\n                                32, 34, 40, 27, 24, 32, 32, 32, 36, 30, 36, 36,\n                                25, 21, 4, 23, 32, 20, 13, 21, 17, 11, 12, 8, 6,\n                                2, 67, 69, 74, 25, 23, 23, 19, 7, 10, 7, 66, 0,\n                                68, 71, 81, 80, 88, 91, 71, 71, 89, 9, 10, 3,\n                                70, 0, 64, 73, 66, 69, 75, 84, 84, 92, 101, 6,\n                                66, 79, 73, 3, 2, 6, 9, 10, 18, 12, 16, 18, 30,\n                                21, 20, 30, 29, 53, 35, 25, 14, 7, 67, 79, 91,\n                                110, 6, 39, 32, 30, 23, 25, 12, 9, 9, 64, 77,\n                                72, 1, 70, 8, 16, 68, 68, 5, 9, 4, 9, 18, 4, 2,\n                                46, 30, 14, 64, 75, 92, 104, 113, 122 },\n\n                              {\n\n                              48,\n                                6, 78, 48, 6, 78, 85, 69, 19, 11, 2, 67, 27, 32,\n                                53, 14, 1, 64, 5, 15, 0, 67, 67, 75, 91, 7, 20,\n                                106, 114, 117, 5, 74, 68, 5, 15, 0, 77, 69, 11,\n                                5, 64, 72, 79, 64, 77, 78, 91, 5, 71, 79, 2, 75,\n                                76, 88, 7, 66, 68, 72, 2, 4, 22, 0, 0, 0, 69,\n                                92, 97, 2, 3, 66, 18, 72, 91, 85, 7, 0, 31, 23,\n                                64, 4, 77, 4, 75, 73, 83, 81, 81, 85, 88, 22, 0,\n                                8, 79, 69, 78, 75, 91, 2, 69, 68, 78, 17, 68, 0,\n                                76, 82, 69, 73, 66, 6, 6, 0, 12, 12, 75, 64, 64,\n                                67, 3, 73, 12, 70, 1, 12, 11, 21, 15, 8, 78, 1,\n                                70, 65, 1, 89, 66, 7, 3, 5, 7, 7, 20, 11, 3, 0,\n                                3, 0, 3, 6, 87, 68, 1, 76, 3, 0, 12, 5, 64, 11,\n                                6, 4, 66, 12, 64, 76, 3, 82, 19, 20, 15, 14, 17,\n                                16, 9, 16, 18, 65, 8, 9, 5, 2, 69, 3, 66, 0, 2,\n                                64, 2, 6, 65, 80, 65, 73, 68, 64, 82, 19, 25,\n                                18, 17, 15, 13, 12, 12, 6, 65, 66, 69, 75, 76,\n                                95, 68, 66, 80, 9, 4, 1, 1, 67, 72, 70, 71, 79,\n                                72, 77, 92, 86, 94, 67, 22, 18, 11, 4, 7, 64,\n                                69, 70, 76, 0, 35, 21, 15, 8, 13, 3, 65, 70, 74,\n                                4, 39, 29, 24, 17, 17, 5, 64, 69, 75, 70, 40,\n                                25, 11, 3, 8, 67, 76, 80, 5, 46, 34, 24, 17, 20,\n                                5, 65, 70, 73, 62, 86, 82, 72, 82, 83, 77, 77,\n                                74, 76, 75, 73, 73, 81, 77, 83, 79, 2, 78, 80,\n                                74, 70, 68, 70, 71, 68, 68, 72, 76, 79, 7, 7,\n                                14, 4, 64, 9, 7, 5, 3, 4, 4, 3, 68, 69, 73, 66,\n                                7, 79, 4, 19, 2, 6, 8, 10, 16, 4, 6, 9, 15, 69,\n                                72, 82, 31, 33, 39, 25, 23, 31, 30, 30, 33, 28,\n                                33, 33, 22, 18, 3, 20, 29, 17, 9, 18, 15, 9, 10,\n                                6, 6, 2, 67, 68, 72, 23, 21, 21, 17, 4, 8, 5,\n                                68, 65, 70, 72, 83, 81, 89, 92, 72, 72, 90, 8,\n                                9, 1, 72, 65, 66, 74, 68, 71, 76, 85, 86, 94,\n                                102, 5, 67, 80, 73, 3, 2, 7, 9, 10, 19, 12, 17,\n                                19, 31, 22, 21, 31, 30, 52, 33, 23, 12, 4, 70,\n                                82, 94, 113, 6, 39, 32, 30, 23, 25, 12, 9, 9,\n                                64, 77, 72, 1, 70, 9, 17, 68, 68, 6, 10, 4, 9,\n                                18, 4, 1, 45, 28, 12, 67, 78, 96, 108, 116, 125 },\n\n                              {\n\n                              47,\n                                6, 78, 47, 6, 78, 83, 68, 20, 11, 2, 68, 26, 31,\n                                53, 14, 3, 64, 6, 16, 0, 67, 66, 76, 92, 6, 18,\n                                107, 115, 118, 8, 72, 68, 6, 16, 0, 76, 68, 12,\n                                4, 64, 71, 78, 64, 77, 78, 91, 5, 71, 78, 2, 75,\n                                76, 88, 7, 66, 67, 72, 2, 4, 22, 0, 0, 0, 68,\n                                92, 97, 2, 2, 66, 18, 71, 91, 83, 9, 2, 32, 25,\n                                1, 5, 75, 5, 73, 72, 81, 81, 81, 85, 87, 22, 0,\n                                8, 78, 69, 77, 74, 90, 2, 69, 68, 78, 17, 68, 1,\n                                75, 81, 68, 73, 66, 6, 6, 0, 12, 12, 74, 64, 0,\n                                67, 3, 72, 11, 70, 1, 11, 10, 21, 14, 7, 77, 1,\n                                69, 66, 0, 89, 67, 7, 3, 6, 7, 7, 21, 11, 3, 0,\n                                4, 0, 3, 6, 88, 68, 1, 77, 3, 64, 12, 5, 65, 11,\n                                6, 4, 67, 12, 64, 76, 3, 83, 18, 20, 15, 14, 17,\n                                16, 9, 16, 18, 65, 8, 9, 5, 2, 69, 3, 66, 0, 2,\n                                64, 1, 6, 65, 80, 65, 73, 69, 65, 82, 17, 24,\n                                17, 16, 13, 11, 11, 11, 4, 67, 67, 70, 77, 77,\n                                96, 68, 66, 81, 8, 3, 0, 0, 68, 73, 71, 72, 80,\n                                73, 78, 92, 85, 93, 66, 23, 18, 11, 4, 8, 0, 68,\n                                69, 75, 1, 35, 21, 15, 8, 14, 3, 64, 69, 72, 4,\n                                39, 29, 24, 17, 18, 5, 64, 69, 74, 70, 41, 25,\n                                11, 3, 9, 67, 76, 79, 5, 46, 34, 24, 16, 20, 5,\n                                65, 69, 72, 62, 85, 81, 71, 81, 81, 76, 75, 73,\n                                74, 74, 72, 71, 80, 76, 83, 78, 4, 78, 81, 73,\n                                69, 68, 70, 72, 68, 68, 73, 77, 80, 7, 7, 14, 4,\n                                64, 8, 7, 5, 2, 4, 4, 3, 69, 69, 73, 65, 8, 79,\n                                4, 18, 2, 6, 8, 10, 16, 3, 5, 9, 15, 70, 72, 83,\n                                31, 32, 38, 24, 22, 30, 28, 28, 31, 26, 31, 30,\n                                20, 16, 2, 17, 26, 14, 5, 15, 13, 8, 9, 5, 6, 3,\n                                67, 67, 70, 21, 20, 19, 15, 2, 7, 4, 70, 66, 71,\n                                73, 84, 82, 90, 92, 72, 72, 91, 7, 8, 0, 74, 66,\n                                67, 75, 69, 72, 77, 86, 87, 95, 103, 5, 68, 80,\n                                72, 3, 2, 8, 10, 11, 20, 13, 18, 20, 33, 23, 22,\n                                33, 32, 51, 32, 21, 10, 1, 73, 85, 97, 115, 7,\n                                39, 32, 31, 23, 26, 13, 9, 10, 0, 77, 71, 2, 70,\n                                10, 19, 67, 67, 7, 11, 4, 10, 19, 4, 1, 44, 26,\n                                10, 69, 81, 99, 112, 119, 126 },\n\n                              {\n\n                              46,\n                                6, 78, 46, 6, 78, 81, 66, 20, 11, 1, 70, 24, 29,\n                                53, 14, 6, 65, 7, 16, 0, 68, 66, 77, 93, 6, 16,\n                                109, 116, 118, 11, 71, 68, 7, 16, 0, 76, 67, 12,\n                                4, 64, 71, 78, 64, 78, 77, 91, 5, 71, 77, 1, 75,\n                                76, 88, 8, 65, 67, 71, 3, 4, 22, 0, 0, 0, 68,\n                                92, 97, 3, 1, 66, 18, 71, 91, 82, 11, 3, 34, 27,\n                                2, 6, 74, 7, 72, 71, 79, 80, 80, 84, 86, 22, 0,\n                                8, 78, 69, 77, 74, 88, 1, 69, 68, 78, 17, 68, 1,\n                                75, 81, 68, 73, 65, 6, 5, 0, 12, 12, 74, 64, 0,\n                                67, 3, 72, 11, 70, 1, 11, 9, 20, 13, 6, 76, 2,\n                                69, 67, 0, 88, 67, 7, 2, 6, 7, 7, 22, 12, 3, 0,\n                                4, 0, 2, 6, 89, 68, 1, 77, 2, 65, 11, 5, 65, 12,\n                                6, 4, 68, 11, 65, 76, 3, 83, 18, 20, 15, 14, 17,\n                                16, 9, 16, 18, 65, 8, 9, 5, 2, 69, 3, 66, 64, 2,\n                                64, 1, 5, 66, 80, 66, 73, 70, 66, 82, 16, 22,\n                                15, 14, 11, 9, 9, 9, 2, 69, 69, 72, 80, 79, 97,\n                                68, 67, 81, 7, 2, 64, 64, 70, 75, 72, 73, 80,\n                                73, 78, 92, 85, 93, 66, 23, 18, 11, 4, 8, 0, 68,\n                                69, 74, 1, 35, 21, 15, 8, 14, 4, 0, 69, 70, 4,\n                                39, 29, 24, 17, 18, 5, 64, 69, 73, 70, 41, 24,\n                                10, 3, 9, 67, 76, 79, 5, 45, 33, 23, 15, 20, 5,\n                                65, 69, 72, 62, 84, 80, 70, 79, 80, 75, 74, 71,\n                                73, 72, 70, 69, 79, 75, 82, 78, 5, 77, 81, 73,\n                                68, 68, 71, 72, 69, 69, 74, 78, 81, 6, 6, 14, 3,\n                                65, 8, 7, 5, 1, 3, 4, 2, 70, 69, 73, 65, 8, 79,\n                                3, 18, 1, 6, 7, 9, 16, 2, 4, 8, 14, 71, 73, 85,\n                                30, 32, 38, 23, 20, 28, 26, 26, 29, 23, 28, 28,\n                                17, 14, 0, 14, 22, 11, 1, 13, 10, 6, 8, 4, 6, 4,\n                                66, 66, 68, 20, 18, 17, 14, 0, 5, 2, 72, 67, 73,\n                                75, 86, 84, 91, 93, 73, 72, 92, 5, 6, 65, 75,\n                                68, 69, 77, 71, 74, 79, 87, 88, 96, 103, 4, 68,\n                                81, 72, 4, 3, 8, 10, 12, 21, 14, 19, 21, 34, 24,\n                                23, 34, 33, 51, 30, 19, 7, 64, 76, 88, 100, 117,\n                                7, 40, 33, 31, 24, 27, 13, 10, 10, 0, 76, 71, 3,\n                                69, 11, 20, 67, 66, 7, 11, 4, 10, 20, 4, 1, 42,\n                                24, 7, 72, 84, 103, 116, 123, 126 },\n\n                              {\n\n                              45,\n                                6, 79, 45, 6, 79, 79, 65, 21, 11, 1, 71, 23, 28,\n                                53, 14, 8, 65, 7, 17, 0, 69, 66, 78, 94, 5, 15,\n                                110, 117, 119, 14, 70, 68, 7, 17, 0, 75, 66, 13,\n                                3, 0, 70, 77, 65, 78, 77, 91, 5, 70, 77, 1, 75,\n                                75, 88, 8, 65, 67, 71, 3, 4, 22, 0, 0, 0, 67,\n                                92, 97, 3, 1, 67, 18, 71, 90, 80, 13, 5, 35, 29,\n                                3, 7, 72, 8, 71, 71, 78, 80, 80, 84, 86, 23, 0,\n                                8, 77, 68, 76, 73, 87, 1, 70, 69, 79, 17, 68, 1,\n                                74, 81, 67, 73, 65, 6, 5, 1, 12, 11, 74, 64, 0,\n                                67, 3, 72, 10, 70, 1, 10, 8, 19, 13, 6, 76, 2,\n                                69, 67, 64, 88, 68, 7, 2, 6, 7, 7, 22, 12, 3, 0,\n                                5, 0, 1, 6, 89, 69, 1, 78, 2, 66, 11, 5, 66, 12,\n                                6, 4, 70, 11, 66, 76, 3, 84, 17, 20, 14, 14, 17,\n                                16, 9, 16, 18, 65, 7, 9, 4, 2, 69, 2, 67, 64, 1,\n                                65, 0, 4, 66, 80, 66, 72, 71, 68, 82, 14, 20,\n                                13, 12, 9, 7, 7, 7, 0, 71, 70, 73, 82, 81, 98,\n                                68, 67, 82, 6, 1, 65, 66, 71, 76, 73, 74, 81,\n                                74, 79, 92, 85, 92, 65, 23, 18, 11, 5, 8, 0, 68,\n                                68, 73, 2, 34, 21, 15, 8, 15, 4, 1, 68, 68, 4,\n                                40, 29, 24, 17, 19, 5, 64, 68, 73, 70, 41, 24,\n                                10, 3, 9, 66, 75, 78, 5, 45, 33, 22, 15, 20, 5,\n                                64, 68, 71, 62, 84, 79, 70, 78, 79, 74, 72, 70,\n                                72, 71, 69, 68, 79, 74, 82, 77, 7, 77, 82, 73,\n                                68, 68, 71, 73, 69, 70, 75, 79, 82, 6, 6, 14, 3,\n                                65, 7, 6, 5, 1, 3, 3, 2, 70, 69, 74, 65, 8, 80,\n                                3, 17, 0, 5, 6, 9, 17, 2, 3, 8, 14, 71, 73, 86,\n                                29, 31, 37, 22, 19, 27, 24, 24, 27, 21, 26, 25,\n                                14, 11, 64, 12, 19, 8, 66, 10, 8, 4, 7, 3, 6, 5,\n                                66, 64, 65, 18, 16, 15, 12, 65, 3, 1, 74, 69,\n                                74, 76, 87, 85, 92, 94, 73, 73, 93, 4, 5, 66,\n                                77, 70, 71, 78, 72, 76, 80, 89, 90, 98, 104, 3,\n                                69, 82, 72, 4, 3, 9, 11, 12, 23, 15, 20, 22, 35,\n                                26, 24, 36, 34, 50, 29, 17, 5, 67, 78, 91, 102,\n                                119, 8, 40, 33, 32, 24, 28, 14, 10, 11, 1, 76,\n                                70, 3, 69, 12, 21, 67, 66, 8, 12, 4, 11, 21, 4,\n                                1, 41, 22, 5, 75, 88, 107, 119, 126, 126 },\n\n                              {\n\n                              43,\n                                6, 79, 43, 6, 79, 78, 0, 21, 11, 0, 73, 21, 27,\n                                53, 14, 10, 65, 8, 18, 0, 70, 66, 79, 95, 5, 13,\n                                112, 118, 119, 17, 69, 68, 8, 18, 0, 75, 65, 13,\n                                3, 0, 70, 76, 65, 79, 77, 91, 5, 70, 76, 1, 76,\n                                75, 88, 9, 65, 67, 71, 4, 4, 22, 0, 0, 0, 67,\n                                93, 97, 4, 0, 67, 18, 71, 90, 78, 14, 6, 37, 30,\n                                4, 8, 71, 9, 70, 70, 76, 79, 80, 83, 85, 23, 0,\n                                8, 77, 68, 76, 73, 85, 1, 70, 69, 79, 17, 68, 1,\n                                74, 81, 67, 73, 64, 6, 5, 1, 12, 11, 74, 64, 0,\n                                67, 3, 72, 9, 71, 1, 9, 7, 18, 12, 5, 75, 3, 69,\n                                68, 64, 87, 68, 7, 2, 6, 7, 7, 23, 12, 3, 64, 5,\n                                64, 0, 5, 90, 69, 1, 78, 1, 67, 11, 4, 67, 12,\n                                6, 4, 71, 11, 67, 76, 3, 84, 16, 20, 14, 14, 17,\n                                16, 9, 16, 17, 65, 7, 9, 4, 2, 70, 2, 67, 65, 1,\n                                65, 64, 3, 67, 80, 67, 72, 72, 69, 82, 13, 18,\n                                11, 10, 7, 5, 5, 5, 65, 73, 72, 75, 84, 83, 99,\n                                68, 67, 82, 5, 0, 66, 67, 73, 78, 74, 76, 82,\n                                74, 79, 92, 85, 92, 65, 23, 18, 11, 5, 8, 0, 68,\n                                68, 72, 2, 34, 21, 15, 8, 15, 5, 1, 67, 66, 4,\n                                40, 29, 24, 17, 19, 5, 64, 68, 72, 70, 41, 24,\n                                9, 3, 9, 66, 75, 77, 5, 44, 32, 21, 14, 20, 5,\n                                64, 68, 71, 62, 83, 78, 69, 77, 78, 73, 71, 69,\n                                71, 70, 67, 66, 78, 74, 82, 77, 8, 77, 82, 73,\n                                67, 68, 72, 73, 69, 71, 76, 80, 83, 5, 5, 14, 2,\n                                66, 7, 6, 5, 0, 2, 3, 2, 71, 70, 74, 65, 8, 80,\n                                2, 17, 64, 5, 5, 8, 17, 1, 2, 7, 13, 72, 74, 88,\n                                28, 30, 37, 21, 18, 25, 22, 22, 25, 18, 23, 23,\n                                11, 9, 65, 9, 16, 5, 70, 7, 5, 2, 6, 1, 6, 6,\n                                66, 0, 0, 16, 14, 13, 10, 67, 1, 64, 76, 70, 76,\n                                77, 89, 87, 93, 95, 74, 73, 94, 3, 3, 68, 79,\n                                72, 73, 80, 74, 78, 82, 90, 91, 99, 105, 2, 70,\n                                83, 72, 5, 3, 9, 11, 13, 24, 15, 21, 23, 36, 27,\n                                25, 37, 35, 50, 27, 15, 2, 69, 81, 94, 105, 122,\n                                8, 41, 34, 32, 24, 28, 14, 10, 11, 1, 76, 70, 4,\n                                68, 13, 22, 67, 65, 8, 12, 4, 11, 22, 4, 1, 40,\n                                20, 2, 78, 91, 111, 123, 126, 126 },\n\n                              {\n\n                              42,\n                                6, 79, 42, 6, 79, 76, 1, 21, 11, 0, 74, 20, 25,\n                                53, 14, 13, 66, 9, 18, 0, 70, 65, 80, 96, 4, 11,\n                                114, 119, 120, 20, 67, 68, 9, 18, 0, 75, 64, 13,\n                                2, 0, 70, 76, 65, 79, 76, 91, 5, 70, 75, 0, 76,\n                                75, 88, 9, 64, 66, 70, 4, 4, 22, 0, 0, 0, 66,\n                                93, 97, 4, 64, 67, 18, 70, 90, 77, 16, 8, 38,\n                                32, 6, 9, 70, 11, 69, 69, 74, 79, 79, 83, 84,\n                                23, 0, 8, 76, 68, 75, 72, 84, 0, 70, 69, 79, 17,\n                                68, 2, 73, 81, 67, 73, 64, 6, 4, 1, 12, 11, 73,\n                                64, 1, 67, 3, 72, 9, 71, 1, 9, 6, 18, 11, 4, 74,\n                                3, 69, 69, 65, 87, 69, 7, 1, 6, 7, 7, 24, 13, 3,\n                                64, 5, 64, 64, 5, 91, 69, 1, 79, 1, 68, 10, 4,\n                                67, 13, 6, 4, 72, 10, 68, 76, 3, 85, 16, 20, 14,\n                                14, 17, 16, 9, 16, 17, 65, 7, 9, 4, 2, 70, 2,\n                                67, 65, 1, 65, 64, 2, 67, 80, 67, 72, 73, 70,\n                                82, 11, 16, 10, 9, 5, 3, 3, 3, 67, 75, 74, 77,\n                                87, 84, 100, 68, 68, 83, 4, 64, 67, 68, 74, 79,\n                                75, 77, 82, 75, 80, 92, 85, 91, 65, 23, 18, 11,\n                                5, 8, 1, 67, 67, 71, 3, 34, 21, 15, 8, 15, 5, 2,\n                                67, 64, 4, 40, 29, 24, 17, 19, 5, 64, 68, 71,\n                                70, 42, 23, 9, 3, 9, 66, 75, 77, 5, 44, 31, 20,\n                                13, 20, 5, 64, 68, 70, 62, 82, 77, 68, 75, 77,\n                                72, 70, 67, 70, 68, 66, 64, 77, 73, 81, 76, 9,\n                                76, 83, 72, 66, 68, 72, 74, 70, 71, 77, 81, 84,\n                                4, 5, 14, 2, 66, 6, 6, 5, 64, 1, 3, 1, 72, 70,\n                                74, 65, 8, 80, 1, 16, 64, 5, 4, 7, 17, 0, 1, 7,\n                                13, 73, 75, 90, 27, 30, 36, 20, 16, 24, 20, 20,\n                                23, 16, 20, 20, 8, 7, 67, 6, 12, 2, 74, 5, 3, 0,\n                                5, 0, 6, 7, 65, 1, 2, 15, 13, 11, 9, 69, 64, 65,\n                                78, 71, 78, 79, 91, 88, 94, 96, 74, 73, 95, 1,\n                                2, 70, 80, 73, 74, 81, 75, 79, 83, 91, 92, 100,\n                                105, 2, 70, 84, 71, 5, 4, 10, 12, 14, 25, 16,\n                                22, 24, 38, 28, 26, 38, 37, 49, 25, 13, 0, 72,\n                                84, 97, 108, 124, 8, 41, 34, 33, 25, 29, 14, 11,\n                                12, 2, 75, 70, 5, 68, 14, 23, 66, 64, 9, 13, 4,\n                                12, 23, 4, 1, 38, 18, 0, 81, 94, 114, 126, 126,\n                                126 },\n\n                              {\n\n                              41,\n                                6, 79, 41, 6, 79, 74, 3, 22, 11, 64, 76, 18, 24,\n                                53, 14, 15, 66, 10, 19, 0, 71, 65, 81, 97, 4, 9,\n                                115, 120, 120, 23, 66, 68, 10, 19, 0, 74, 0, 14,\n                                2, 0, 69, 75, 66, 80, 76, 91, 5, 70, 75, 0, 76,\n                                75, 88, 10, 64, 66, 70, 5, 4, 22, 0, 0, 0, 66,\n                                93, 97, 5, 65, 67, 18, 70, 90, 75, 18, 9, 40,\n                                34, 7, 10, 68, 12, 68, 68, 72, 78, 79, 82, 83,\n                                23, 0, 8, 76, 68, 75, 72, 82, 0, 71, 70, 80, 17,\n                                68, 2, 73, 81, 66, 73, 0, 6, 4, 1, 12, 10, 73,\n                                64, 1, 67, 3, 72, 8, 71, 1, 8, 5, 17, 10, 3, 74,\n                                4, 69, 70, 65, 86, 69, 7, 1, 6, 7, 7, 25, 13, 3,\n                                64, 6, 64, 65, 5, 92, 69, 1, 79, 0, 69, 10, 4,\n                                68, 13, 6, 4, 74, 10, 69, 76, 3, 85, 15, 20, 14,\n                                14, 17, 16, 9, 16, 17, 65, 6, 9, 4, 2, 70, 1,\n                                68, 66, 0, 66, 65, 1, 68, 80, 68, 72, 74, 72,\n                                82, 10, 14, 8, 7, 3, 1, 1, 1, 69, 77, 75, 78,\n                                89, 86, 101, 68, 68, 83, 3, 65, 68, 70, 76, 81,\n                                76, 78, 83, 75, 80, 92, 85, 91, 64, 23, 18, 11,\n                                5, 8, 1, 67, 67, 70, 3, 34, 21, 15, 8, 16, 6, 3,\n                                66, 1, 4, 40, 29, 24, 17, 20, 5, 64, 68, 71, 70,\n                                42, 23, 8, 3, 9, 66, 75, 76, 5, 43, 31, 19, 12,\n                                20, 5, 64, 67, 70, 62, 81, 76, 68, 74, 76, 71,\n                                68, 66, 69, 67, 64, 0, 77, 72, 81, 76, 11, 76,\n                                83, 72, 66, 68, 73, 74, 70, 72, 78, 82, 85, 4,\n                                4, 14, 1, 67, 6, 5, 5, 65, 1, 2, 1, 73, 70, 75,\n                                65, 8, 81, 1, 16, 65, 5, 3, 7, 17, 64, 0, 6, 12,\n                                74, 75, 91, 26, 29, 36, 19, 15, 22, 18, 18, 21,\n                                13, 18, 18, 5, 4, 68, 3, 9, 64, 78, 2, 0, 65, 4,\n                                64, 6, 8, 65, 2, 4, 13, 11, 9, 7, 71, 66, 67,\n                                80, 73, 79, 80, 92, 90, 95, 97, 75, 74, 96, 0,\n                                0, 71, 82, 75, 76, 83, 77, 81, 85, 92, 94, 102,\n                                106, 1, 71, 85, 71, 6, 4, 10, 12, 14, 26, 17,\n                                23, 25, 39, 29, 27, 40, 38, 49, 24, 11, 66, 74,\n                                87, 100, 111, 126, 9, 42, 35, 33, 25, 30, 15,\n                                11, 12, 2, 75, 69, 5, 67, 15, 24, 66, 64, 9, 13,\n                                4, 12, 24, 4, 1, 37, 16, 66, 84, 97, 118, 126,\n                                126, 126 },\n\n                              {\n\n                              40,\n                                6, 79, 40, 6, 79, 72, 4, 22, 11, 64, 77, 17, 23,\n                                53, 14, 17, 66, 11, 20, 0, 72, 65, 82, 98, 3, 7,\n                                117, 121, 121, 26, 65, 68, 11, 20, 0, 74, 1, 14,\n                                1, 0, 69, 74, 66, 80, 76, 91, 5, 70, 74, 0, 76,\n                                75, 88, 10, 64, 66, 70, 5, 4, 22, 0, 0, 0, 65,\n                                93, 97, 5, 66, 67, 18, 70, 90, 73, 20, 11, 41,\n                                36, 8, 11, 67, 13, 67, 67, 70, 78, 79, 82, 82,\n                                23, 0, 8, 75, 68, 74, 71, 81, 0, 71, 70, 80, 17,\n                                68, 2, 72, 81, 66, 73, 0, 6, 4, 1, 12, 10, 73,\n                                64, 1, 67, 3, 72, 7, 71, 1, 7, 4, 16, 9, 2, 73,\n                                4, 69, 71, 66, 86, 70, 7, 1, 6, 7, 7, 26, 13, 3,\n                                64, 6, 64, 66, 5, 93, 69, 1, 80, 0, 70, 10, 4,\n                                69, 13, 6, 4, 75, 10, 70, 76, 3, 86, 14, 20, 14,\n                                14, 17, 16, 9, 16, 17, 65, 6, 9, 4, 2, 70, 1,\n                                68, 66, 0, 66, 66, 0, 68, 80, 68, 72, 75, 73,\n                                82, 8, 12, 6, 5, 1, 64, 64, 64, 71, 79, 77, 80,\n                                91, 88, 102, 68, 68, 84, 2, 66, 69, 71, 77, 82,\n                                77, 79, 84, 76, 81, 92, 85, 90, 64, 23, 18, 11,\n                                5, 8, 1, 67, 66, 69, 4, 34, 21, 15, 8, 16, 6, 4,\n                                65, 3, 4, 40, 29, 24, 17, 20, 5, 64, 68, 70, 70,\n                                42, 23, 8, 3, 9, 66, 75, 75, 5, 43, 30, 18, 11,\n                                20, 5, 64, 67, 69, 62, 80, 75, 67, 73, 75, 70,\n                                67, 65, 68, 66, 0, 2, 76, 71, 81, 75, 12, 76,\n                                84, 72, 65, 68, 73, 75, 70, 73, 79, 83, 86, 3,\n                                4, 14, 1, 67, 5, 5, 5, 66, 0, 2, 1, 74, 70, 75,\n                                65, 8, 81, 0, 15, 66, 5, 2, 6, 17, 65, 64, 6,\n                                12, 75, 76, 93, 25, 28, 35, 18, 14, 21, 16, 16,\n                                19, 11, 15, 15, 2, 2, 69, 0, 6, 67, 82, 64, 65,\n                                67, 3, 65, 6, 9, 65, 3, 6, 11, 9, 7, 5, 73, 68,\n                                68, 82, 74, 81, 81, 94, 91, 96, 98, 75, 74, 97,\n                                64, 64, 73, 84, 77, 78, 84, 78, 83, 86, 93, 95,\n                                103, 107, 0, 72, 86, 71, 6, 4, 11, 13, 15, 27,\n                                18, 24, 26, 40, 30, 28, 41, 39, 48, 22, 9, 68,\n                                77, 90, 103, 114, 126, 9, 42, 35, 34, 25, 31,\n                                15, 11, 13, 3, 75, 69, 6, 67, 16, 25, 66, 0, 10,\n                                14, 4, 13, 25, 4, 1, 36, 14, 68, 87, 100, 122,\n                                126, 126, 126 },\n\n                              {\n\n                              38,\n                                5, 80, 38, 5, 80, 71, 5, 22, 11, 65, 79, 15, 21,\n                                52, 14, 19, 67, 11, 20, 64, 73, 65, 84, 100, 2,\n                                5, 119, 122, 122, 28, 64, 69, 11, 20, 64, 74, 2,\n                                14, 0, 0, 69, 74, 67, 81, 76, 92, 5, 70, 74, 64,\n                                77, 75, 88, 10, 64, 66, 70, 5, 3, 22, 0, 0, 0,\n                                65, 94, 97, 5, 67, 68, 18, 70, 90, 72, 21, 12,\n                                42, 37, 9, 12, 66, 14, 66, 67, 69, 78, 79, 82,\n                                82, 23, 0, 8, 75, 68, 74, 71, 80, 64, 72, 71,\n                                81, 17, 68, 2, 72, 81, 66, 73, 0, 5, 3, 1, 11,\n                                9, 73, 65, 1, 67, 2, 72, 6, 72, 0, 6, 2, 15, 8,\n                                1, 73, 4, 69, 72, 67, 86, 71, 6, 0, 6, 7, 7, 26,\n                                13, 3, 65, 6, 65, 67, 4, 94, 70, 0, 81, 64, 71,\n                                9, 3, 70, 13, 6, 4, 77, 9, 71, 76, 3, 87, 13,\n                                19, 13, 14, 17, 15, 8, 16, 16, 66, 5, 9, 3, 1,\n                                71, 0, 69, 67, 64, 67, 67, 64, 69, 80, 69, 72,\n                                76, 75, 82, 6, 10, 4, 3, 64, 67, 66, 66, 73, 81,\n                                79, 82, 94, 90, 104, 69, 69, 85, 1, 68, 71, 73,\n                                79, 84, 79, 81, 85, 77, 82, 92, 85, 90, 64, 23,\n                                18, 11, 5, 8, 1, 67, 66, 68, 4, 33, 21, 15, 8,\n                                16, 6, 4, 65, 4, 3, 40, 29, 23, 16, 20, 5, 64,\n                                68, 70, 70, 42, 22, 7, 2, 9, 66, 75, 75, 5, 42,\n                                29, 17, 10, 19, 5, 64, 67, 69, 62, 80, 74, 67,\n                                72, 74, 70, 66, 64, 67, 65, 1, 3, 76, 71, 81,\n                                75, 13, 76, 85, 72, 65, 68, 74, 76, 71, 74, 80,\n                                85, 88, 2, 3, 14, 0, 68, 4, 4, 4, 67, 64, 1, 0,\n                                75, 71, 76, 65, 8, 82, 64, 14, 67, 4, 1, 5, 17,\n                                66, 66, 5, 11, 76, 77, 95, 24, 27, 34, 16, 12,\n                                19, 14, 14, 16, 8, 12, 12, 64, 64, 71, 66, 2,\n                                70, 87, 67, 68, 69, 1, 67, 6, 9, 65, 4, 8, 9, 7,\n                                5, 3, 76, 70, 70, 85, 76, 83, 83, 96, 93, 97,\n                                99, 76, 75, 99, 66, 66, 75, 86, 79, 80, 86, 80,\n                                85, 88, 95, 97, 105, 108, 64, 73, 87, 71, 6, 4,\n                                11, 13, 15, 28, 18, 25, 26, 41, 31, 29, 42, 40,\n                                47, 20, 6, 71, 80, 93, 107, 117, 126, 9, 42, 35,\n                                34, 25, 31, 15, 11, 13, 3, 75, 69, 6, 67, 17,\n                                26, 66, 0, 10, 14, 4, 13, 25, 4, 0, 34, 11, 71,\n                                90, 104, 126, 126, 126, 126 },\n\n                              {\n\n                              37,\n                                5, 80, 37, 5, 80, 69, 7, 23, 12, 65, 80, 14, 20,\n                                52, 14, 22, 67, 12, 21, 64, 73, 64, 85, 101, 2,\n                                4, 120, 123, 122, 31, 1, 69, 12, 21, 64, 73, 4,\n                                15, 0, 1, 68, 73, 67, 81, 75, 92, 5, 69, 73, 64,\n                                77, 74, 88, 11, 0, 65, 69, 6, 3, 22, 0, 0, 0,\n                                64, 94, 97, 6, 67, 68, 18, 69, 89, 70, 23, 14,\n                                44, 39, 11, 13, 64, 16, 64, 66, 67, 77, 78, 81,\n                                81, 24, 1, 9, 74, 67, 73, 70, 78, 64, 72, 71,\n                                81, 18, 68, 3, 71, 80, 65, 72, 1, 5, 3, 2, 11,\n                                9, 72, 65, 2, 67, 2, 71, 6, 72, 0, 6, 1, 15, 8,\n                                1, 72, 5, 68, 72, 67, 85, 71, 6, 0, 7, 7, 7, 27,\n                                14, 4, 65, 7, 65, 67, 4, 94, 70, 0, 81, 64, 72,\n                                9, 3, 70, 14, 7, 4, 78, 9, 71, 75, 3, 87, 13,\n                                19, 13, 14, 17, 15, 8, 16, 16, 66, 5, 9, 3, 1,\n                                71, 0, 69, 67, 64, 67, 67, 64, 69, 79, 69, 71,\n                                76, 76, 81, 5, 9, 3, 2, 66, 69, 67, 67, 75, 82,\n                                80, 83, 96, 91, 105, 69, 69, 85, 0, 69, 72, 74,\n                                80, 85, 80, 82, 85, 77, 82, 91, 84, 89, 0, 24,\n                                18, 11, 6, 9, 2, 66, 65, 66, 5, 33, 21, 15, 8,\n                                17, 7, 5, 64, 6, 3, 41, 30, 23, 16, 21, 5, 64,\n                                67, 69, 70, 43, 22, 7, 2, 10, 65, 74, 74, 5, 42,\n                                29, 17, 10, 19, 5, 0, 66, 68, 62, 79, 73, 66,\n                                70, 72, 69, 64, 1, 65, 0, 3, 5, 75, 70, 80, 74,\n                                15, 75, 85, 71, 64, 67, 74, 76, 71, 74, 80, 86,\n                                89, 2, 3, 15, 0, 68, 4, 4, 4, 67, 64, 1, 0, 75,\n                                71, 76, 64, 9, 82, 64, 14, 67, 4, 1, 5, 18, 66,\n                                67, 5, 11, 76, 77, 96, 24, 27, 34, 15, 11, 18,\n                                12, 12, 14, 6, 10, 10, 66, 66, 72, 68, 64, 73,\n                                91, 69, 70, 70, 0, 68, 6, 10, 64, 6, 11, 8, 6,\n                                4, 2, 78, 71, 71, 87, 77, 84, 84, 97, 94, 98,\n                                99, 76, 75, 100, 67, 67, 76, 87, 80, 81, 87, 81,\n                                86, 89, 96, 98, 106, 108, 64, 73, 87, 70, 7, 5,\n                                12, 14, 16, 30, 19, 26, 27, 43, 33, 30, 44, 42,\n                                47, 19, 4, 73, 82, 95, 110, 119, 126, 10, 43,\n                                36, 35, 26, 32, 16, 12, 14, 4, 74, 68, 7, 66,\n                                19, 28, 65, 1, 11, 15, 5, 14, 26, 4, 0, 33, 9,\n                                73, 92, 107, 126, 126, 126, 126 },\n\n                              {\n\n                              36,\n                                5, 80, 36, 5, 80, 67, 8, 23, 12, 65, 81, 13, 19,\n                                52, 14, 24, 67, 13, 22, 64, 74, 64, 86, 102, 1,\n                                2, 122, 124, 123, 34, 2, 69, 13, 22, 64, 73, 5,\n                                15, 64, 1, 68, 72, 67, 81, 75, 92, 5, 69, 72,\n                                64, 77, 74, 88, 11, 0, 65, 69, 6, 3, 22, 0, 0,\n                                0, 0, 94, 97, 6, 68, 68, 18, 69, 89, 68, 25, 16,\n                                45, 41, 12, 14, 0, 17, 0, 65, 65, 77, 78, 81,\n                                80, 24, 1, 9, 73, 67, 72, 70, 77, 64, 72, 71,\n                                81, 18, 68, 3, 71, 80, 65, 72, 1, 5, 3, 2, 11,\n                                9, 72, 65, 2, 67, 2, 71, 5, 72, 0, 5, 0, 14, 7,\n                                0, 71, 5, 68, 73, 68, 85, 72, 6, 0, 7, 7, 7, 28,\n                                14, 4, 65, 7, 65, 68, 4, 95, 70, 0, 82, 64, 73,\n                                9, 3, 71, 14, 7, 4, 79, 9, 72, 75, 3, 88, 12,\n                                19, 13, 14, 17, 15, 8, 16, 16, 66, 5, 9, 3, 1,\n                                71, 0, 69, 67, 64, 67, 68, 65, 70, 79, 69, 71,\n                                77, 77, 81, 3, 7, 1, 0, 68, 71, 69, 69, 77, 84,\n                                82, 85, 98, 93, 106, 69, 69, 86, 64, 70, 73, 75,\n                                82, 86, 81, 83, 86, 78, 83, 91, 84, 88, 0, 24,\n                                18, 11, 6, 9, 2, 66, 65, 65, 6, 33, 21, 15, 8,\n                                17, 7, 6, 0, 8, 3, 41, 30, 23, 16, 21, 5, 64,\n                                67, 68, 70, 43, 22, 7, 2, 10, 65, 74, 73, 5, 41,\n                                28, 16, 9, 19, 5, 0, 66, 68, 62, 78, 72, 65, 69,\n                                71, 68, 0, 2, 64, 1, 4, 7, 74, 69, 80, 73, 16,\n                                75, 86, 71, 0, 67, 74, 77, 71, 75, 81, 87, 90,\n                                1, 3, 15, 0, 69, 3, 4, 4, 68, 65, 1, 0, 76, 71,\n                                76, 64, 9, 82, 65, 13, 68, 4, 0, 4, 18, 67, 68,\n                                5, 11, 77, 78, 98, 23, 26, 33, 14, 10, 17, 10,\n                                10, 12, 4, 7, 7, 69, 68, 73, 71, 67, 76, 95, 72,\n                                72, 72, 64, 69, 6, 11, 64, 7, 13, 6, 4, 2, 0,\n                                80, 73, 73, 89, 78, 86, 85, 99, 95, 99, 100, 77,\n                                75, 101, 68, 68, 78, 89, 82, 83, 88, 83, 88, 90,\n                                97, 99, 107, 109, 65, 74, 88, 70, 7, 5, 13, 14,\n                                17, 31, 20, 27, 28, 44, 34, 31, 45, 43, 46, 17,\n                                2, 75, 85, 98, 113, 122, 126, 10, 43, 36, 35,\n                                26, 33, 16, 12, 14, 4, 74, 68, 8, 66, 20, 29,\n                                65, 2, 12, 16, 5, 14, 27, 4, 0, 32, 7, 75, 95,\n                                110, 126, 126, 126, 126 },\n\n                              {\n\n                              35,\n                                5, 80, 35, 5, 80, 65, 10, 24, 12, 66, 83, 11,\n                                18, 52, 14, 26, 67, 14, 23, 64, 75, 64, 87, 103,\n                                1, 0, 123, 125, 123, 37, 3, 69, 14, 23, 64, 72,\n                                6, 16, 64, 1, 67, 71, 68, 82, 75, 92, 5, 69, 72,\n                                64, 77, 74, 88, 12, 0, 65, 69, 7, 3, 22, 0, 0,\n                                0, 0, 94, 97, 7, 69, 68, 18, 69, 89, 66, 27, 17,\n                                47, 43, 13, 15, 2, 18, 1, 64, 0, 76, 78, 80, 79,\n                                24, 1, 9, 73, 67, 72, 69, 75, 64, 73, 72, 82,\n                                18, 68, 3, 70, 80, 64, 72, 2, 5, 3, 2, 11, 8,\n                                72, 65, 2, 67, 2, 71, 4, 72, 0, 4, 64, 13, 6,\n                                64, 71, 6, 68, 74, 68, 84, 72, 6, 0, 7, 7, 7,\n                                29, 14, 4, 65, 8, 65, 69, 4, 96, 70, 0, 82, 65,\n                                74, 9, 3, 72, 14, 7, 4, 81, 9, 73, 75, 3, 88,\n                                11, 19, 13, 14, 17, 15, 8, 16, 16, 66, 4, 9, 3,\n                                1, 71, 64, 70, 68, 65, 68, 69, 66, 70, 79, 70,\n                                71, 78, 79, 81, 2, 5, 64, 65, 70, 73, 71, 71,\n                                79, 86, 83, 86, 100, 95, 107, 69, 69, 86, 65,\n                                71, 74, 77, 83, 88, 82, 84, 87, 78, 83, 91, 84,\n                                88, 1, 24, 18, 11, 6, 9, 2, 66, 64, 64, 6, 33,\n                                21, 15, 8, 18, 8, 7, 1, 10, 3, 41, 30, 23, 16,\n                                22, 5, 64, 67, 68, 70, 43, 22, 6, 2, 10, 65, 74,\n                                72, 5, 41, 28, 15, 8, 19, 5, 0, 65, 67, 62, 77,\n                                71, 65, 68, 70, 67, 2, 3, 0, 2, 6, 8, 74, 68,\n                                80, 73, 18, 75, 86, 71, 0, 67, 75, 77, 71, 76,\n                                82, 88, 91, 1, 2, 15, 64, 69, 3, 3, 4, 69, 65,\n                                0, 0, 77, 71, 77, 64, 9, 83, 65, 13, 69, 4, 64,\n                                4, 18, 68, 69, 4, 10, 78, 78, 99, 22, 25, 33,\n                                13, 9, 15, 8, 8, 10, 1, 5, 5, 72, 71, 74, 74,\n                                70, 79, 99, 75, 75, 74, 65, 70, 6, 12, 64, 8,\n                                15, 4, 2, 0, 65, 82, 75, 74, 91, 80, 87, 86,\n                                100, 97, 100, 101, 77, 76, 102, 69, 70, 79, 91,\n                                84, 85, 90, 84, 90, 92, 98, 101, 109, 110, 66,\n                                75, 89, 70, 8, 5, 13, 15, 17, 32, 21, 28, 29,\n                                45, 35, 32, 47, 44, 46, 16, 0, 78, 87, 101, 116,\n                                125, 126, 11, 44, 37, 36, 26, 34, 17, 12, 15, 5,\n                                74, 67, 8, 65, 21, 30, 65, 2, 12, 16, 5, 15, 28,\n                                4, 0, 31, 5, 78, 98, 113, 126, 126, 126, 126 },\n\n                              {\n\n                              33,\n                                5, 80, 33, 5, 80, 64, 11, 24, 12, 66, 84, 10,\n                                16, 52, 14, 29, 68, 15, 23, 64, 76, 64, 88, 104,\n                                0, 65, 125, 126, 124, 40, 4, 69, 15, 23, 64, 72,\n                                7, 16, 65, 1, 67, 71, 68, 82, 74, 92, 5, 69, 71,\n                                65, 78, 74, 88, 12, 1, 65, 68, 7, 3, 22, 0, 0,\n                                0, 1, 95, 97, 7, 70, 68, 18, 69, 89, 65, 28, 19,\n                                48, 44, 14, 16, 3, 20, 2, 0, 2, 76, 77, 80, 78,\n                                24, 1, 9, 72, 67, 71, 69, 74, 65, 73, 72, 82,\n                                18, 68, 3, 70, 80, 64, 72, 2, 5, 2, 2, 11, 8,\n                                72, 65, 2, 67, 2, 71, 4, 73, 0, 4, 65, 12, 5,\n                                65, 70, 6, 68, 75, 69, 84, 73, 6, 64, 7, 7, 7,\n                                30, 15, 4, 66, 8, 66, 70, 3, 97, 70, 0, 83, 65,\n                                75, 8, 2, 72, 15, 7, 4, 82, 8, 74, 75, 3, 89,\n                                11, 19, 13, 14, 17, 15, 8, 16, 15, 66, 4, 9, 3,\n                                1, 72, 64, 70, 68, 65, 68, 69, 67, 71, 79, 70,\n                                71, 79, 80, 81, 0, 3, 66, 67, 72, 75, 73, 73,\n                                81, 88, 85, 88, 103, 97, 108, 69, 70, 87, 66,\n                                72, 75, 78, 85, 89, 83, 86, 87, 79, 84, 91, 84,\n                                87, 1, 24, 18, 11, 6, 9, 2, 66, 64, 0, 7, 33,\n                                21, 15, 8, 18, 8, 7, 1, 12, 3, 41, 30, 23, 16,\n                                22, 5, 64, 67, 67, 70, 43, 21, 6, 2, 10, 65, 74,\n                                72, 5, 40, 27, 14, 7, 19, 5, 0, 65, 67, 62, 76,\n                                70, 64, 66, 69, 66, 3, 5, 1, 4, 7, 10, 73, 68,\n                                79, 72, 19, 74, 87, 71, 1, 67, 75, 78, 72, 77,\n                                83, 89, 92, 0, 2, 15, 64, 70, 2, 3, 4, 70, 66,\n                                0, 64, 78, 72, 77, 64, 9, 83, 66, 12, 70, 4, 65,\n                                3, 18, 69, 70, 4, 10, 79, 79, 101, 21, 25, 32,\n                                12, 7, 14, 6, 6, 8, 64, 2, 2, 75, 73, 76, 77,\n                                74, 82, 103, 77, 77, 76, 66, 72, 6, 13, 0, 9,\n                                17, 3, 0, 65, 66, 84, 77, 76, 93, 81, 89, 88,\n                                102, 98, 101, 102, 78, 76, 103, 71, 71, 81, 92,\n                                86, 87, 91, 86, 92, 93, 99, 102, 110, 110, 67,\n                                75, 90, 70, 8, 6, 14, 15, 18, 33, 21, 29, 30,\n                                46, 36, 33, 48, 45, 45, 14, 65, 80, 90, 104,\n                                119, 126, 126, 11, 44, 37, 36, 27, 34, 17, 13,\n                                15, 5, 73, 67, 9, 65, 22, 31, 65, 3, 13, 17, 5,\n                                15, 29, 4, 0, 29, 3, 80, 101, 116, 126, 126,\n                                126, 126 },\n\n                              {\n\n                              32,\n                                5, 80, 32, 5, 80, 1, 13, 24, 12, 67, 86, 8, 15,\n                                52, 14, 31, 68, 16, 24, 64, 76, 0, 89, 105, 0,\n                                67, 126, 126, 124, 43, 6, 69, 16, 24, 64, 72, 8,\n                                16, 65, 1, 67, 70, 68, 83, 74, 92, 5, 69, 70,\n                                65, 78, 74, 88, 13, 1, 64, 68, 8, 3, 22, 0, 0,\n                                0, 1, 95, 97, 8, 71, 68, 18, 68, 89, 0, 30, 20,\n                                50, 46, 16, 17, 4, 21, 3, 1, 4, 75, 77, 79, 77,\n                                24, 1, 9, 72, 67, 71, 68, 72, 65, 73, 72, 82,\n                                18, 68, 4, 69, 80, 64, 72, 3, 5, 2, 2, 11, 8,\n                                71, 65, 3, 67, 2, 71, 3, 73, 0, 3, 66, 12, 4,\n                                66, 69, 7, 68, 76, 69, 83, 73, 6, 64, 7, 7, 7,\n                                31, 15, 4, 66, 8, 66, 71, 3, 98, 70, 0, 83, 66,\n                                76, 8, 2, 73, 15, 7, 4, 83, 8, 75, 75, 3, 89,\n                                10, 19, 13, 14, 17, 15, 8, 16, 15, 66, 4, 9, 3,\n                                1, 72, 64, 70, 69, 65, 68, 70, 68, 71, 79, 71,\n                                71, 80, 81, 81, 64, 1, 67, 68, 74, 77, 75, 75,\n                                83, 90, 87, 90, 105, 98, 109, 69, 70, 87, 67,\n                                73, 76, 79, 86, 91, 84, 87, 88, 79, 84, 91, 84,\n                                87, 1, 24, 18, 11, 6, 9, 3, 65, 0, 1, 7, 33, 21,\n                                15, 8, 18, 9, 8, 2, 14, 3, 41, 30, 23, 16, 22,\n                                5, 64, 67, 66, 70, 44, 21, 5, 2, 10, 65, 74, 71,\n                                5, 40, 26, 13, 6, 19, 5, 0, 65, 66, 62, 75, 69,\n                                0, 65, 68, 65, 4, 6, 2, 5, 9, 12, 72, 67, 79,\n                                72, 20, 74, 87, 70, 2, 67, 76, 78, 72, 77, 84,\n                                90, 93, 64, 1, 15, 65, 70, 2, 3, 4, 71, 67, 0,\n                                64, 79, 72, 77, 64, 9, 83, 67, 12, 70, 4, 66, 2,\n                                18, 70, 71, 3, 9, 80, 80, 103, 20, 24, 32, 11,\n                                6, 12, 4, 4, 6, 67, 64, 0, 78, 75, 77, 80, 77,\n                                85, 107, 80, 80, 78, 67, 73, 6, 14, 0, 10, 19,\n                                1, 64, 67, 68, 86, 79, 77, 95, 82, 91, 89, 104,\n                                100, 102, 103, 78, 76, 104, 72, 73, 83, 94, 87,\n                                88, 93, 87, 93, 95, 100, 103, 111, 111, 67, 76,\n                                91, 69, 9, 6, 14, 16, 19, 34, 22, 30, 31, 48,\n                                37, 34, 49, 47, 45, 12, 67, 83, 92, 107, 122,\n                                126, 126, 11, 45, 38, 37, 27, 35, 17, 13, 16, 6,\n                                73, 67, 10, 64, 23, 32, 64, 4, 13, 17, 5, 16,\n                                30, 4, 0, 28, 1, 83, 104, 119, 126, 126, 126,\n                                126 },\n\n                              {\n\n                              31,\n                                5, 81, 31, 5, 81, 3, 14, 25, 12, 67, 87, 7, 14,\n                                52, 14, 33, 68, 16, 25, 64, 77, 0, 90, 106, 64,\n                                68, 126, 126, 125, 46, 7, 69, 16, 25, 64, 71, 9,\n                                17, 66, 2, 66, 69, 69, 83, 74, 92, 5, 68, 70,\n                                65, 78, 73, 88, 13, 1, 64, 68, 8, 3, 22, 0, 0,\n                                0, 2, 95, 97, 8, 71, 69, 18, 68, 88, 2, 32, 22,\n                                51, 48, 17, 18, 6, 22, 4, 1, 5, 75, 77, 79, 77,\n                                25, 1, 9, 71, 66, 70, 68, 71, 65, 74, 73, 83,\n                                18, 68, 4, 69, 80, 0, 72, 3, 5, 2, 3, 11, 7, 71,\n                                65, 3, 67, 2, 71, 2, 73, 0, 2, 67, 11, 4, 66,\n                                69, 7, 68, 76, 70, 83, 74, 6, 64, 7, 7, 7, 31,\n                                15, 4, 66, 9, 66, 72, 3, 98, 71, 0, 84, 66, 77,\n                                8, 2, 74, 15, 7, 4, 85, 8, 76, 75, 3, 90, 9, 19,\n                                12, 14, 17, 15, 8, 16, 15, 66, 3, 9, 2, 1, 72,\n                                65, 71, 69, 66, 69, 71, 69, 72, 79, 71, 70, 81,\n                                83, 81, 66, 64, 69, 70, 76, 79, 77, 77, 85, 92,\n                                88, 91, 107, 100, 110, 69, 70, 88, 68, 74, 77,\n                                81, 88, 92, 85, 88, 89, 80, 85, 91, 84, 86, 2,\n                                24, 18, 11, 7, 9, 3, 65, 0, 2, 8, 32, 21, 15, 8,\n                                19, 9, 9, 3, 16, 3, 42, 30, 23, 16, 23, 5, 64,\n                                66, 66, 70, 44, 21, 5, 2, 10, 64, 73, 70, 5, 39,\n                                26, 12, 6, 19, 5, 1, 64, 66, 62, 75, 68, 0, 64,\n                                67, 64, 6, 7, 3, 6, 10, 13, 72, 66, 79, 71, 22,\n                                74, 88, 70, 2, 67, 76, 79, 72, 78, 85, 91, 94,\n                                64, 1, 15, 65, 71, 1, 2, 4, 71, 67, 64, 64, 79,\n                                72, 78, 64, 9, 84, 67, 11, 71, 3, 67, 2, 19, 70,\n                                72, 3, 9, 80, 80, 104, 19, 23, 31, 10, 5, 11, 2,\n                                2, 4, 69, 66, 66, 81, 78, 78, 82, 80, 88, 111,\n                                83, 82, 80, 68, 74, 6, 15, 0, 12, 22, 64, 66,\n                                69, 70, 88, 81, 79, 97, 84, 92, 90, 105, 101,\n                                103, 104, 79, 77, 105, 73, 74, 84, 96, 89, 90,\n                                94, 89, 95, 96, 102, 105, 113, 112, 68, 77, 92,\n                                69, 9, 6, 15, 16, 19, 36, 23, 31, 32, 49, 39,\n                                35, 51, 48, 44, 11, 69, 85, 95, 109, 125, 126,\n                                126, 12, 45, 38, 37, 27, 36, 18, 13, 16, 6, 73,\n                                66, 10, 64, 24, 33, 64, 4, 14, 18, 5, 16, 31, 4,\n                                0, 27, 64, 85, 107, 123, 126, 126, 126, 126 },\n\n                              {\n\n                              30,\n                                5, 81, 30, 5, 81, 5, 16, 25, 12, 68, 89, 5, 12,\n                                52, 14, 36, 69, 17, 25, 64, 78, 0, 91, 107, 64,\n                                70, 126, 126, 125, 49, 8, 69, 17, 25, 64, 71,\n                                10, 17, 66, 2, 66, 69, 69, 84, 73, 92, 5, 68,\n                                69, 66, 78, 73, 88, 14, 2, 64, 67, 9, 3, 22, 0,\n                                0, 0, 2, 95, 97, 9, 72, 69, 18, 68, 88, 3, 34,\n                                23, 53, 50, 18, 19, 7, 24, 5, 2, 7, 74, 76, 78,\n                                76, 25, 1, 9, 71, 66, 70, 67, 69, 66, 74, 73,\n                                83, 18, 68, 4, 68, 80, 0, 72, 4, 5, 1, 3, 11, 7,\n                                71, 65, 3, 67, 2, 71, 2, 73, 0, 2, 68, 10, 3,\n                                67, 68, 8, 68, 77, 70, 82, 74, 6, 65, 7, 7, 7,\n                                32, 16, 4, 66, 9, 66, 73, 3, 99, 71, 0, 84, 67,\n                                78, 7, 2, 74, 16, 7, 4, 86, 7, 77, 75, 3, 90, 9,\n                                19, 12, 14, 17, 15, 8, 16, 15, 66, 3, 9, 2, 1,\n                                72, 65, 71, 70, 66, 69, 71, 70, 72, 79, 72, 70,\n                                82, 84, 81, 67, 66, 71, 72, 78, 81, 79, 79, 87,\n                                94, 90, 93, 110, 102, 111, 69, 71, 88, 69, 75,\n                                78, 82, 89, 94, 86, 89, 89, 80, 85, 91, 84, 86,\n                                2, 24, 18, 11, 7, 9, 3, 65, 1, 3, 8, 32, 21, 15,\n                                8, 19, 10, 10, 3, 18, 3, 42, 30, 23, 16, 23, 5,\n                                64, 66, 65, 70, 44, 20, 4, 2, 10, 64, 73, 70, 5,\n                                39, 25, 11, 5, 19, 5, 1, 64, 65, 62, 74, 67, 1,\n                                1, 66, 0, 7, 9, 4, 8, 12, 15, 71, 65, 78, 71,\n                                23, 73, 88, 70, 3, 67, 77, 79, 73, 79, 86, 92,\n                                95, 65, 0, 15, 66, 71, 1, 2, 4, 72, 68, 64, 65,\n                                80, 72, 78, 64, 9, 84, 68, 11, 72, 3, 68, 1, 19,\n                                71, 73, 2, 8, 81, 81, 106, 18, 23, 31, 9, 3, 9,\n                                0, 0, 2, 72, 69, 68, 84, 80, 80, 85, 84, 91,\n                                115, 85, 85, 82, 69, 75, 6, 16, 1, 13, 24, 65,\n                                68, 71, 71, 90, 83, 80, 99, 85, 94, 92, 107,\n                                103, 104, 105, 79, 77, 106, 75, 76, 86, 97, 91,\n                                92, 96, 90, 97, 98, 103, 106, 114, 112, 69, 77,\n                                93, 69, 10, 7, 15, 17, 20, 37, 24, 32, 33, 50,\n                                40, 36, 52, 49, 44, 9, 71, 88, 97, 112, 126,\n                                126, 126, 12, 46, 39, 38, 28, 37, 18, 14, 17, 7,\n                                72, 66, 11, 0, 25, 34, 64, 5, 14, 18, 5, 17, 32,\n                                4, 0, 25, 66, 88, 110, 126, 126, 126, 126, 126 },\n\n                              {\n\n                              28,\n                                4, 81, 28, 4, 81, 6, 17, 25, 12, 68, 90, 4, 11,\n                                52, 14, 38, 69, 18, 26, 64, 79, 0, 92, 109, 65,\n                                72, 126, 126, 126, 51, 9, 69, 18, 26, 64, 71,\n                                11, 17, 67, 2, 66, 68, 70, 84, 73, 93, 5, 68,\n                                69, 66, 79, 73, 88, 14, 2, 64, 67, 9, 3, 22, 0,\n                                0, 0, 3, 96, 97, 9, 73, 69, 18, 68, 88, 5, 35,\n                                25, 54, 51, 19, 20, 8, 25, 6, 3, 9, 74, 76, 78,\n                                75, 25, 1, 9, 70, 66, 69, 67, 68, 66, 75, 74,\n                                84, 18, 68, 4, 68, 80, 0, 72, 4, 4, 1, 3, 11, 6,\n                                71, 65, 3, 67, 1, 71, 1, 74, 0, 1, 70, 9, 2, 68,\n                                68, 8, 68, 78, 71, 82, 75, 5, 65, 7, 7, 7, 33,\n                                16, 4, 67, 9, 67, 74, 2, 100, 71, 0, 85, 67, 79,\n                                7, 1, 75, 16, 7, 4, 88, 7, 78, 75, 3, 91, 8, 18,\n                                12, 14, 17, 14, 7, 16, 14, 67, 2, 9, 2, 0, 73,\n                                66, 72, 70, 67, 70, 72, 71, 73, 79, 72, 70, 83,\n                                86, 81, 69, 68, 73, 74, 80, 84, 81, 81, 89, 96,\n                                92, 95, 112, 104, 112, 69, 71, 89, 70, 77, 80,\n                                84, 91, 95, 88, 91, 90, 81, 86, 91, 84, 85, 2,\n                                24, 18, 11, 7, 9, 3, 65, 1, 4, 9, 32, 21, 15, 8,\n                                19, 10, 10, 4, 19, 3, 42, 30, 23, 15, 23, 5, 64,\n                                66, 65, 70, 44, 20, 4, 2, 10, 64, 73, 69, 5, 38,\n                                24, 10, 4, 18, 5, 1, 64, 65, 62, 73, 66, 1, 2,\n                                65, 0, 8, 10, 5, 9, 13, 16, 71, 65, 78, 70, 24,\n                                73, 89, 70, 3, 67, 77, 80, 73, 80, 87, 94, 96,\n                                66, 0, 15, 66, 72, 0, 1, 3, 73, 69, 65, 65, 81,\n                                73, 79, 64, 9, 85, 69, 10, 73, 3, 69, 0, 19, 72,\n                                74, 2, 8, 82, 82, 108, 17, 22, 30, 7, 2, 8, 65,\n                                65, 64, 74, 72, 71, 87, 83, 81, 88, 87, 94, 119,\n                                88, 87, 84, 71, 77, 6, 16, 1, 14, 26, 67, 70,\n                                73, 73, 93, 85, 82, 101, 87, 96, 93, 109, 104,\n                                105, 106, 80, 78, 107, 76, 77, 88, 99, 93, 94,\n                                97, 92, 99, 99, 104, 108, 116, 113, 70, 78, 94,\n                                69, 10, 7, 16, 17, 20, 38, 24, 33, 34, 51, 41,\n                                37, 53, 50, 43, 7, 73, 90, 100, 115, 126, 126,\n                                126, 12, 46, 39, 38, 28, 37, 18, 14, 17, 7, 72,\n                                66, 11, 0, 26, 35, 64, 5, 15, 19, 5, 17, 32, 4,\n                                64, 24, 68, 90, 113, 126, 126, 126, 126, 126 },\n\n                              {\n\n                              27,\n                                4, 81, 27, 4, 81, 8, 18, 26, 12, 68, 91, 3, 10,\n                                52, 14, 40, 69, 19, 27, 64, 79, 1, 93, 110, 66,\n                                74, 126, 126, 126, 54, 11, 69, 19, 27, 64, 70,\n                                12, 18, 68, 2, 65, 67, 70, 84, 73, 93, 5, 68,\n                                68, 66, 79, 73, 88, 14, 2, 0, 67, 9, 3, 22, 0,\n                                0, 0, 4, 96, 97, 9, 74, 69, 18, 67, 88, 7, 37,\n                                27, 55, 53, 21, 21, 10, 26, 8, 4, 11, 74, 76,\n                                78, 74, 25, 1, 9, 69, 66, 68, 66, 67, 66, 75,\n                                74, 84, 18, 68, 5, 67, 79, 1, 72, 4, 4, 1, 3,\n                                11, 6, 70, 65, 4, 67, 1, 70, 0, 74, 0, 0, 71, 9,\n                                1, 69, 67, 8, 67, 79, 72, 82, 76, 5, 65, 8, 7,\n                                7, 34, 16, 4, 67, 10, 67, 74, 2, 101, 71, 0, 86,\n                                67, 80, 7, 1, 76, 16, 7, 4, 89, 7, 78, 75, 3,\n                                92, 7, 18, 12, 14, 17, 14, 7, 16, 14, 67, 2, 9,\n                                2, 0, 73, 66, 72, 70, 67, 70, 73, 71, 73, 79,\n                                72, 70, 84, 87, 81, 71, 69, 74, 75, 82, 86, 82,\n                                82, 91, 98, 93, 96, 114, 105, 113, 69, 71, 90,\n                                71, 78, 81, 85, 92, 96, 89, 92, 91, 82, 87, 91,\n                                83, 84, 3, 25, 18, 11, 7, 10, 4, 64, 2, 5, 10,\n                                32, 21, 15, 8, 20, 10, 11, 5, 21, 3, 42, 30, 23,\n                                15, 24, 5, 64, 66, 64, 70, 45, 20, 4, 2, 11, 64,\n                                73, 68, 5, 38, 24, 10, 3, 18, 5, 1, 0, 64, 62,\n                                72, 65, 2, 3, 0, 1, 10, 11, 7, 10, 14, 18, 70,\n                                64, 78, 69, 26, 73, 90, 69, 4, 67, 77, 81, 73,\n                                80, 88, 95, 97, 66, 0, 15, 66, 72, 64, 1, 3, 74,\n                                69, 65, 65, 82, 73, 79, 0, 10, 85, 69, 9, 73, 3,\n                                69, 0, 19, 73, 75, 2, 8, 83, 82, 109, 17, 21,\n                                29, 6, 1, 7, 67, 67, 66, 76, 74, 74, 89, 85, 82,\n                                91, 90, 97, 123, 91, 89, 85, 72, 78, 6, 17, 1,\n                                15, 28, 69, 71, 75, 75, 95, 86, 83, 103, 88, 97,\n                                94, 110, 105, 106, 106, 80, 78, 108, 77, 78, 89,\n                                101, 94, 95, 98, 93, 100, 100, 105, 109, 117,\n                                114, 70, 79, 94, 68, 10, 7, 17, 18, 21, 39, 25,\n                                34, 35, 53, 42, 38, 55, 52, 42, 6, 75, 92, 103,\n                                118, 126, 126, 126, 13, 46, 39, 39, 28, 38, 19,\n                                14, 18, 8, 72, 65, 12, 0, 27, 37, 0, 6, 16, 20,\n                                5, 18, 33, 4, 64, 23, 70, 92, 115, 126, 126,\n                                126, 126, 126 },\n\n                              {\n\n                              26,\n                                4, 81, 26, 4, 81, 10, 20, 26, 12, 69, 93, 1, 8,\n                                52, 14, 43, 70, 20, 27, 64, 80, 1, 94, 111, 66,\n                                76, 126, 126, 126, 57, 12, 69, 20, 27, 64, 70,\n                                13, 18, 68, 2, 65, 67, 70, 85, 72, 93, 5, 68,\n                                67, 67, 79, 73, 88, 15, 3, 0, 66, 10, 3, 22, 0,\n                                0, 0, 4, 96, 97, 10, 75, 69, 18, 67, 88, 8, 39,\n                                28, 57, 55, 22, 22, 11, 28, 9, 5, 13, 73, 75,\n                                77, 73, 25, 1, 9, 69, 66, 68, 66, 65, 67, 75,\n                                74, 84, 18, 68, 5, 67, 79, 1, 72, 5, 4, 0, 3,\n                                11, 6, 70, 65, 4, 67, 1, 70, 0, 74, 0, 0, 72, 8,\n                                0, 70, 66, 9, 67, 80, 72, 81, 76, 5, 66, 8, 7,\n                                7, 35, 17, 4, 67, 10, 67, 75, 2, 102, 71, 0, 86,\n                                68, 81, 6, 1, 76, 17, 7, 4, 90, 6, 79, 75, 3,\n                                92, 7, 18, 12, 14, 17, 14, 7, 16, 14, 67, 2, 9,\n                                2, 0, 73, 66, 72, 71, 67, 70, 73, 72, 74, 79,\n                                73, 70, 85, 88, 81, 72, 71, 76, 77, 84, 88, 84,\n                                84, 93, 100, 95, 98, 117, 107, 114, 69, 72, 90,\n                                72, 79, 82, 86, 94, 98, 90, 93, 91, 82, 87, 91,\n                                83, 84, 3, 25, 18, 11, 7, 10, 4, 64, 2, 6, 10,\n                                32, 21, 15, 8, 20, 11, 12, 5, 23, 3, 42, 30, 23,\n                                15, 24, 5, 64, 66, 0, 70, 45, 19, 3, 2, 11, 64,\n                                73, 68, 5, 37, 23, 9, 2, 18, 5, 1, 0, 64, 62,\n                                71, 64, 3, 5, 1, 2, 11, 13, 8, 12, 16, 20, 69,\n                                0, 77, 69, 27, 72, 90, 69, 5, 67, 78, 81, 74,\n                                81, 89, 96, 98, 67, 64, 15, 67, 73, 64, 1, 3,\n                                75, 70, 65, 66, 83, 73, 79, 0, 10, 85, 70, 9,\n                                74, 3, 70, 64, 19, 74, 76, 1, 7, 84, 83, 111,\n                                16, 21, 29, 5, 64, 5, 69, 69, 68, 79, 77, 76,\n                                92, 87, 84, 94, 94, 100, 126, 93, 92, 87, 73,\n                                79, 6, 18, 2, 16, 30, 70, 73, 77, 76, 97, 88,\n                                85, 105, 89, 99, 96, 112, 107, 107, 107, 81, 78,\n                                109, 79, 80, 91, 102, 96, 97, 100, 95, 102, 102,\n                                106, 110, 118, 114, 71, 79, 95, 68, 11, 8, 17,\n                                18, 22, 40, 26, 35, 36, 54, 43, 39, 56, 53, 42,\n                                4, 77, 95, 105, 121, 126, 126, 126, 13, 47, 40,\n                                39, 29, 39, 19, 15, 18, 8, 71, 65, 13, 1, 28,\n                                38, 0, 7, 16, 20, 5, 18, 34, 4, 64, 21, 72, 95,\n                                118, 126, 126, 126, 126, 126 },\n\n                              {\n\n                              25,\n                                4, 82, 25, 4, 82, 12, 21, 27, 12, 69, 94, 0, 7,\n                                52, 14, 45, 70, 20, 28, 64, 81, 1, 95, 112, 67,\n                                77, 126, 126, 126, 60, 13, 69, 20, 28, 64, 69,\n                                14, 19, 69, 3, 64, 66, 71, 85, 72, 93, 5, 67,\n                                67, 67, 79, 72, 88, 15, 3, 0, 66, 10, 3, 22, 0,\n                                0, 0, 5, 96, 97, 10, 75, 70, 18, 67, 87, 10, 41,\n                                30, 58, 57, 23, 23, 13, 29, 10, 5, 14, 73, 75,\n                                77, 73, 26, 1, 9, 68, 65, 67, 65, 64, 67, 76,\n                                75, 85, 18, 68, 5, 66, 79, 2, 72, 5, 4, 0, 4,\n                                11, 5, 70, 65, 4, 67, 1, 70, 64, 74, 0, 64, 73,\n                                7, 0, 70, 66, 9, 67, 80, 73, 81, 77, 5, 66, 8,\n                                7, 7, 35, 17, 4, 67, 11, 67, 76, 2, 102, 72, 0,\n                                87, 68, 82, 6, 1, 77, 17, 7, 4, 92, 6, 80, 75,\n                                3, 93, 6, 18, 11, 14, 17, 14, 7, 16, 14, 67, 1,\n                                9, 1, 0, 73, 67, 73, 71, 68, 71, 74, 73, 74, 79,\n                                73, 69, 86, 90, 81, 74, 73, 78, 79, 86, 90, 86,\n                                86, 95, 102, 96, 99, 119, 109, 115, 69, 72, 91,\n                                73, 80, 83, 88, 95, 99, 91, 94, 92, 83, 88, 91,\n                                83, 83, 4, 25, 18, 11, 8, 10, 4, 64, 3, 7, 11,\n                                31, 21, 15, 8, 21, 11, 13, 6, 25, 3, 43, 30, 23,\n                                15, 25, 5, 64, 65, 0, 70, 45, 19, 3, 2, 11, 0,\n                                72, 67, 5, 37, 23, 8, 2, 18, 5, 2, 1, 0, 62, 71,\n                                0, 3, 6, 2, 3, 13, 14, 9, 13, 17, 21, 69, 1, 77,\n                                68, 29, 72, 91, 69, 5, 67, 78, 82, 74, 82, 90,\n                                97, 99, 67, 64, 15, 67, 73, 65, 0, 3, 75, 70,\n                                66, 66, 83, 73, 80, 0, 10, 86, 70, 8, 75, 2, 71,\n                                64, 20, 74, 77, 1, 7, 84, 83, 112, 15, 20, 28,\n                                4, 65, 4, 71, 71, 70, 81, 79, 79, 95, 90, 85,\n                                96, 97, 103, 126, 96, 94, 89, 74, 80, 6, 19, 2,\n                                18, 33, 72, 75, 79, 78, 99, 90, 86, 107, 91,\n                                100, 97, 113, 108, 108, 108, 81, 79, 110, 80,\n                                81, 92, 104, 98, 99, 101, 96, 104, 103, 108,\n                                112, 120, 115, 72, 80, 96, 68, 11, 8, 18, 19,\n                                22, 42, 27, 36, 37, 55, 45, 40, 58, 54, 41, 3,\n                                79, 97, 108, 123, 126, 126, 126, 14, 47, 40, 40,\n                                29, 40, 20, 15, 19, 9, 71, 64, 13, 1, 29, 39, 0,\n                                7, 17, 21, 5, 19, 35, 4, 64, 20, 74, 97, 121,\n                                126, 126, 126, 126, 126 },\n\n                              {\n\n                              23,\n                                4, 82, 23, 4, 82, 13, 23, 27, 12, 70, 96, 65, 6,\n                                52, 14, 47, 70, 21, 29, 64, 82, 1, 96, 113, 67,\n                                79, 126, 126, 126, 62, 14, 69, 21, 29, 64, 69,\n                                15, 19, 69, 3, 64, 65, 71, 86, 72, 93, 5, 67,\n                                66, 67, 80, 72, 88, 16, 3, 0, 66, 11, 3, 22, 0,\n                                0, 0, 5, 97, 97, 11, 76, 70, 18, 67, 87, 12, 42,\n                                31, 60, 58, 24, 24, 14, 30, 11, 6, 16, 72, 75,\n                                76, 72, 26, 1, 9, 68, 65, 67, 65, 1, 67, 76, 75,\n                                85, 18, 68, 5, 66, 79, 2, 72, 6, 4, 0, 4, 11, 5,\n                                70, 65, 4, 67, 1, 70, 65, 75, 0, 65, 74, 6, 64,\n                                71, 65, 10, 67, 81, 73, 80, 77, 5, 66, 8, 7, 7,\n                                36, 17, 4, 68, 11, 68, 77, 1, 103, 72, 0, 87,\n                                69, 83, 6, 0, 78, 17, 7, 4, 93, 6, 81, 75, 3,\n                                93, 5, 18, 11, 14, 17, 14, 7, 16, 13, 67, 1, 9,\n                                1, 0, 74, 67, 73, 72, 68, 71, 75, 74, 75, 79,\n                                74, 69, 87, 91, 81, 75, 75, 80, 81, 88, 92, 88,\n                                88, 97, 104, 98, 101, 121, 111, 116, 69, 72, 91,\n                                74, 81, 84, 89, 97, 101, 92, 96, 93, 83, 88, 91,\n                                83, 83, 4, 25, 18, 11, 8, 10, 4, 64, 3, 8, 11,\n                                31, 21, 15, 8, 21, 12, 13, 7, 27, 3, 43, 30, 23,\n                                15, 25, 5, 64, 65, 1, 70, 45, 19, 2, 2, 11, 0,\n                                72, 66, 5, 36, 22, 7, 1, 18, 5, 2, 1, 0, 62, 70,\n                                1, 4, 7, 3, 4, 14, 15, 10, 14, 19, 23, 68, 1,\n                                77, 68, 30, 72, 91, 69, 6, 67, 79, 82, 74, 83,\n                                91, 98, 100, 68, 65, 15, 68, 74, 65, 0, 3, 76,\n                                71, 66, 66, 84, 74, 80, 0, 10, 86, 71, 8, 76, 2,\n                                72, 65, 20, 75, 78, 0, 6, 85, 84, 114, 14, 19,\n                                28, 3, 66, 2, 73, 73, 72, 84, 82, 81, 98, 92,\n                                86, 99, 100, 106, 126, 99, 97, 91, 75, 82, 6,\n                                20, 2, 19, 35, 74, 77, 81, 80, 101, 92, 88, 109,\n                                92, 102, 98, 115, 110, 109, 109, 82, 79, 111,\n                                81, 83, 94, 106, 100, 101, 103, 98, 106, 105,\n                                109, 113, 121, 116, 73, 81, 97, 68, 12, 8, 18,\n                                19, 23, 43, 27, 37, 38, 56, 46, 41, 59, 55, 41,\n                                1, 81, 100, 110, 126, 126, 126, 126, 14, 48, 41,\n                                40, 29, 40, 20, 15, 19, 9, 71, 64, 14, 2, 30,\n                                40, 0, 8, 17, 21, 5, 19, 36, 4, 64, 19, 76, 100,\n                                124, 126, 126, 126, 126, 126 },\n\n                              {\n\n                              22,\n                                4, 82, 22, 4, 82, 15, 24, 27, 12, 70, 97, 66, 4,\n                                52, 14, 50, 71, 22, 29, 64, 82, 2, 97, 114, 68,\n                                81, 126, 126, 126, 62, 16, 69, 22, 29, 64, 69,\n                                16, 19, 70, 3, 64, 65, 71, 86, 71, 93, 5, 67,\n                                65, 68, 80, 72, 88, 16, 4, 1, 65, 11, 3, 22, 0,\n                                0, 0, 6, 97, 97, 11, 77, 70, 18, 66, 87, 13, 44,\n                                33, 61, 60, 26, 25, 15, 32, 12, 7, 18, 72, 74,\n                                76, 71, 26, 1, 9, 67, 65, 66, 64, 2, 68, 76, 75,\n                                85, 18, 68, 6, 65, 79, 2, 72, 6, 4, 64, 4, 11,\n                                5, 69, 65, 5, 67, 1, 70, 65, 75, 0, 65, 75, 6,\n                                65, 72, 64, 10, 67, 82, 74, 80, 78, 5, 67, 8, 7,\n                                7, 37, 18, 4, 68, 11, 68, 78, 1, 104, 72, 0, 88,\n                                69, 84, 5, 0, 78, 18, 7, 4, 94, 5, 82, 75, 3,\n                                94, 5, 18, 11, 14, 17, 14, 7, 16, 13, 67, 1, 9,\n                                1, 0, 74, 67, 73, 72, 68, 71, 75, 75, 75, 79,\n                                74, 69, 88, 92, 81, 77, 77, 81, 82, 90, 94, 90,\n                                90, 99, 106, 100, 103, 124, 112, 117, 69, 73,\n                                92, 75, 82, 85, 90, 98, 102, 93, 97, 93, 84, 89,\n                                91, 83, 82, 4, 25, 18, 11, 8, 10, 5, 0, 4, 9,\n                                12, 31, 21, 15, 8, 21, 12, 14, 7, 29, 3, 43, 30,\n                                23, 15, 25, 5, 64, 65, 2, 70, 46, 18, 2, 2, 11,\n                                0, 72, 66, 5, 36, 21, 6, 0, 18, 5, 2, 1, 1, 62,\n                                69, 2, 5, 9, 4, 5, 15, 17, 11, 16, 20, 25, 67,\n                                2, 76, 67, 31, 71, 92, 68, 7, 67, 79, 83, 75,\n                                83, 92, 99, 101, 69, 65, 15, 68, 74, 66, 0, 3,\n                                77, 72, 66, 67, 85, 74, 80, 0, 10, 86, 72, 7,\n                                76, 2, 73, 66, 20, 76, 79, 0, 6, 86, 85, 116,\n                                13, 19, 27, 2, 68, 1, 75, 75, 74, 86, 85, 84,\n                                101, 94, 88, 102, 104, 109, 126, 101, 99, 93,\n                                76, 83, 6, 21, 3, 20, 37, 75, 78, 83, 81, 103,\n                                94, 89, 111, 93, 104, 100, 117, 111, 110, 110,\n                                82, 79, 112, 83, 84, 96, 107, 101, 102, 104, 99,\n                                107, 106, 110, 114, 122, 116, 73, 81, 98, 67,\n                                12, 9, 19, 20, 24, 44, 28, 38, 39, 58, 47, 42,\n                                60, 57, 40, 64, 83, 102, 113, 126, 126, 126,\n                                126, 14, 48, 41, 41, 30, 41, 20, 16, 20, 10, 70,\n                                64, 15, 2, 31, 41, 1, 9, 18, 22, 5, 20, 37, 4,\n                                64, 17, 78, 102, 126, 126, 126, 126, 126, 126 },\n\n                              {\n\n                              21,\n                                4, 82, 21, 4, 82, 17, 26, 28, 12, 71, 99, 68, 3,\n                                52, 14, 52, 71, 23, 30, 64, 83, 2, 98, 115, 68,\n                                83, 126, 126, 126, 62, 17, 69, 23, 30, 64, 68,\n                                17, 20, 70, 3, 0, 64, 72, 87, 71, 93, 5, 67, 65,\n                                68, 80, 72, 88, 17, 4, 1, 65, 12, 3, 22, 0, 0,\n                                0, 6, 97, 97, 12, 78, 70, 18, 66, 87, 15, 46,\n                                34, 62, 62, 27, 26, 17, 33, 13, 8, 20, 71, 74,\n                                75, 70, 26, 1, 9, 67, 65, 66, 64, 4, 68, 77, 76,\n                                86, 18, 68, 6, 65, 79, 3, 72, 7, 4, 64, 4, 11,\n                                4, 69, 65, 5, 67, 1, 70, 66, 75, 0, 66, 76, 5,\n                                66, 73, 64, 11, 67, 83, 74, 79, 78, 5, 67, 8, 7,\n                                7, 38, 18, 4, 68, 12, 68, 79, 1, 105, 72, 0, 88,\n                                70, 85, 5, 0, 79, 18, 7, 4, 96, 5, 83, 75, 3,\n                                94, 4, 18, 11, 14, 17, 14, 7, 16, 13, 67, 0, 9,\n                                1, 0, 74, 68, 74, 73, 69, 72, 76, 76, 76, 79,\n                                75, 69, 89, 94, 81, 78, 79, 83, 84, 92, 96, 92,\n                                92, 101, 108, 101, 104, 126, 114, 118, 69, 73,\n                                92, 76, 83, 86, 92, 100, 104, 94, 98, 94, 84,\n                                89, 91, 83, 82, 5, 25, 18, 11, 8, 10, 5, 0, 4,\n                                10, 12, 31, 21, 15, 8, 22, 13, 15, 8, 31, 3, 43,\n                                30, 23, 15, 26, 5, 64, 65, 2, 70, 46, 18, 1, 2,\n                                11, 0, 72, 65, 5, 35, 21, 5, 64, 18, 5, 2, 2, 1,\n                                62, 68, 3, 5, 10, 5, 6, 17, 18, 12, 17, 22, 26,\n                                67, 3, 76, 67, 33, 71, 92, 68, 7, 67, 80, 83,\n                                75, 84, 93, 100, 102, 69, 66, 15, 69, 75, 66,\n                                64, 3, 78, 72, 67, 67, 86, 74, 81, 0, 10, 87,\n                                72, 7, 77, 2, 74, 66, 20, 77, 80, 64, 5, 87, 85,\n                                117, 12, 18, 27, 1, 69, 64, 77, 77, 76, 89, 87,\n                                86, 104, 97, 89, 105, 107, 112, 126, 104, 102,\n                                95, 77, 84, 6, 22, 3, 21, 39, 77, 80, 85, 83,\n                                105, 96, 91, 113, 95, 105, 101, 118, 113, 111,\n                                111, 83, 80, 113, 84, 86, 97, 109, 103, 104,\n                                106, 101, 109, 108, 111, 116, 124, 117, 74, 82,\n                                99, 67, 13, 9, 19, 20, 24, 45, 29, 39, 40, 59,\n                                48, 43, 62, 58, 40, 65, 85, 105, 115, 126, 126,\n                                126, 126, 15, 49, 42, 41, 30, 42, 21, 16, 20,\n                                10, 70, 0, 15, 3, 32, 42, 1, 9, 18, 22, 5, 20,\n                                38, 4, 64, 16, 80, 105, 126, 126, 126, 126, 126,\n                                126 },\n\n                              {\n\n                              20,\n                                4, 82, 20, 4, 82, 19, 27, 28, 12, 71, 100, 69,\n                                2, 52, 14, 54, 71, 24, 31, 64, 84, 2, 99, 116,\n                                69, 85, 126, 126, 126, 62, 18, 69, 24, 31, 64,\n                                68, 18, 20, 71, 3, 0, 0, 72, 87, 71, 93, 5, 67,\n                                64, 68, 80, 72, 88, 17, 4, 1, 65, 12, 3, 22, 0,\n                                0, 0, 7, 97, 97, 12, 79, 70, 18, 66, 87, 17, 48,\n                                36, 62, 62, 28, 27, 18, 34, 14, 9, 22, 71, 74,\n                                75, 69, 26, 1, 9, 66, 65, 65, 0, 5, 68, 77, 76,\n                                86, 18, 68, 6, 64, 79, 3, 72, 7, 4, 64, 4, 11,\n                                4, 69, 65, 5, 67, 1, 70, 67, 75, 0, 67, 77, 4,\n                                67, 74, 0, 11, 67, 84, 75, 79, 79, 5, 67, 8, 7,\n                                7, 39, 18, 4, 68, 12, 68, 80, 1, 106, 72, 0, 89,\n                                70, 86, 5, 0, 80, 18, 7, 4, 97, 5, 84, 75, 3,\n                                95, 3, 18, 11, 14, 17, 14, 7, 16, 13, 67, 0, 9,\n                                1, 0, 74, 68, 74, 73, 69, 72, 77, 77, 76, 79,\n                                75, 69, 90, 95, 81, 80, 81, 85, 86, 94, 98, 94,\n                                94, 103, 110, 103, 106, 126, 116, 119, 69, 73,\n                                93, 77, 84, 87, 93, 101, 105, 95, 99, 95, 85,\n                                90, 91, 83, 81, 5, 25, 18, 11, 8, 10, 5, 0, 5,\n                                11, 13, 31, 21, 15, 8, 22, 13, 16, 9, 33, 3, 43,\n                                30, 23, 15, 26, 5, 64, 65, 3, 70, 46, 18, 1, 2,\n                                11, 0, 72, 64, 5, 35, 20, 4, 65, 18, 5, 2, 2, 2,\n                                62, 67, 4, 6, 11, 6, 7, 18, 19, 13, 18, 23, 28,\n                                66, 4, 76, 66, 34, 71, 93, 68, 8, 67, 80, 84,\n                                75, 85, 94, 101, 103, 70, 66, 15, 69, 75, 67,\n                                64, 3, 79, 73, 67, 67, 87, 74, 81, 0, 10, 87,\n                                73, 6, 78, 2, 75, 67, 20, 78, 81, 64, 5, 88, 86,\n                                119, 11, 17, 26, 0, 70, 65, 79, 79, 78, 91, 90,\n                                89, 107, 99, 90, 108, 110, 115, 126, 107, 104,\n                                97, 78, 85, 6, 23, 3, 22, 41, 79, 82, 87, 85,\n                                107, 98, 92, 115, 96, 107, 102, 120, 114, 112,\n                                112, 83, 80, 114, 85, 87, 99, 111, 105, 106,\n                                107, 102, 111, 109, 112, 117, 125, 118, 75, 83,\n                                100, 67, 13, 9, 20, 21, 25, 46, 30, 40, 41, 60,\n                                49, 44, 62, 59, 39, 67, 87, 107, 118, 126, 126,\n                                126, 126, 15, 49, 42, 42, 30, 43, 21, 16, 21,\n                                11, 70, 0, 16, 3, 33, 43, 1, 10, 19, 23, 5, 21,\n                                39, 4, 64, 15, 82, 107, 126, 126, 126, 126, 126,\n                                126 },\n\n                              {\n\n                              18,\n                                3, 83, 18, 3, 83, 20, 28, 28, 12, 72, 102, 71,\n                                0, 51, 14, 56, 72, 24, 31, 65, 85, 2, 101, 118,\n                                70, 87, 126, 126, 126, 62, 19, 70, 24, 31, 65,\n                                68, 19, 20, 72, 3, 0, 0, 73, 88, 71, 94, 5, 67,\n                                64, 69, 81, 72, 88, 17, 4, 1, 65, 12, 2, 22, 0,\n                                0, 0, 7, 98, 97, 12, 80, 71, 18, 66, 87, 18, 49,\n                                37, 62, 62, 29, 28, 19, 35, 15, 9, 23, 71, 74,\n                                75, 69, 26, 1, 9, 66, 65, 65, 0, 6, 69, 78, 77,\n                                87, 18, 68, 6, 64, 79, 3, 72, 7, 3, 65, 4, 10,\n                                3, 69, 66, 5, 67, 0, 70, 68, 76, 64, 68, 79, 3,\n                                68, 75, 0, 11, 67, 85, 76, 79, 80, 4, 68, 8, 7,\n                                7, 39, 18, 4, 69, 12, 69, 81, 0, 107, 73, 64,\n                                90, 71, 87, 4, 64, 81, 18, 7, 4, 99, 4, 85, 75,\n                                3, 96, 2, 17, 10, 14, 17, 13, 6, 16, 12, 68, 64,\n                                9, 0, 64, 75, 69, 75, 74, 70, 73, 78, 78, 77,\n                                79, 76, 69, 91, 97, 81, 82, 83, 87, 88, 96, 101,\n                                96, 96, 105, 112, 105, 108, 126, 118, 121, 70,\n                                74, 94, 78, 86, 89, 95, 103, 107, 97, 101, 96,\n                                86, 91, 91, 83, 81, 5, 25, 18, 11, 8, 10, 5, 0,\n                                5, 12, 13, 30, 21, 15, 8, 22, 13, 16, 9, 34, 2,\n                                43, 30, 22, 14, 26, 5, 64, 65, 3, 70, 46, 17, 0,\n                                1, 11, 0, 72, 64, 5, 34, 19, 3, 66, 17, 5, 2, 2,\n                                2, 62, 67, 5, 6, 12, 7, 7, 19, 20, 14, 19, 24,\n                                29, 66, 4, 76, 66, 35, 71, 94, 68, 8, 67, 81,\n                                85, 76, 86, 95, 103, 105, 71, 67, 15, 70, 76,\n                                68, 65, 2, 80, 74, 68, 68, 88, 75, 82, 0, 10,\n                                88, 74, 5, 79, 1, 76, 68, 20, 79, 83, 65, 4, 89,\n                                87, 121, 10, 16, 25, 65, 72, 67, 81, 81, 81, 94,\n                                93, 92, 110, 102, 92, 111, 114, 118, 126, 110,\n                                107, 99, 80, 87, 6, 23, 3, 23, 43, 81, 84, 89,\n                                87, 110, 100, 94, 118, 98, 109, 104, 122, 116,\n                                113, 113, 84, 81, 116, 87, 89, 101, 113, 107,\n                                108, 109, 104, 113, 111, 114, 119, 126, 119, 76,\n                                84, 101, 67, 13, 9, 20, 21, 25, 47, 30, 41, 41,\n                                61, 50, 45, 62, 60, 38, 69, 90, 110, 121, 126,\n                                126, 126, 126, 15, 49, 42, 42, 30, 43, 21, 16,\n                                21, 11, 70, 0, 16, 3, 34, 44, 1, 10, 19, 23, 5,\n                                21, 39, 4, 65, 13, 85, 110, 126, 126, 126, 126,\n                                126, 126 },\n\n                              {\n\n                              17,\n                                3, 83, 17, 3, 83, 22, 30, 29, 13, 72, 103, 72,\n                                64, 51, 14, 59, 72, 25, 32, 65, 85, 3, 102, 119,\n                                70, 88, 126, 126, 126, 62, 21, 70, 25, 32, 65,\n                                67, 21, 21, 72, 4, 1, 1, 73, 88, 70, 94, 5, 66,\n                                0, 69, 81, 71, 88, 18, 5, 2, 64, 13, 2, 22, 0,\n                                0, 0, 8, 98, 97, 13, 80, 71, 18, 65, 86, 20, 51,\n                                39, 62, 62, 31, 29, 21, 37, 17, 10, 25, 70, 73,\n                                74, 68, 27, 2, 10, 65, 64, 64, 1, 8, 69, 78, 77,\n                                87, 19, 68, 7, 0, 78, 4, 71, 8, 3, 65, 5, 10, 3,\n                                68, 66, 6, 67, 0, 69, 68, 76, 64, 68, 80, 3, 68,\n                                75, 1, 12, 66, 85, 76, 78, 80, 4, 68, 9, 7, 7,\n                                40, 19, 5, 69, 13, 69, 81, 0, 107, 73, 64, 90,\n                                71, 88, 4, 64, 81, 19, 8, 4, 100, 4, 85, 74, 3,\n                                96, 2, 17, 10, 14, 17, 13, 6, 16, 12, 68, 64, 9,\n                                0, 64, 75, 69, 75, 74, 70, 73, 78, 78, 77, 78,\n                                76, 68, 91, 98, 80, 83, 84, 88, 89, 98, 103, 97,\n                                97, 107, 113, 106, 109, 126, 119, 122, 70, 74,\n                                94, 79, 87, 90, 96, 104, 108, 98, 102, 96, 86,\n                                91, 90, 82, 80, 6, 26, 18, 11, 9, 11, 6, 1, 6,\n                                14, 14, 30, 21, 15, 8, 23, 14, 17, 10, 36, 2,\n                                44, 31, 22, 14, 27, 5, 64, 64, 4, 70, 47, 17, 0,\n                                1, 12, 1, 71, 0, 5, 34, 19, 3, 66, 17, 5, 3, 3,\n                                3, 62, 66, 6, 7, 14, 9, 8, 21, 22, 16, 21, 26,\n                                31, 65, 5, 75, 65, 37, 70, 94, 67, 9, 66, 81,\n                                85, 76, 86, 95, 104, 106, 71, 67, 16, 70, 76,\n                                68, 65, 2, 80, 74, 68, 68, 88, 75, 82, 1, 11,\n                                88, 74, 5, 79, 1, 76, 68, 21, 79, 84, 65, 4, 89,\n                                87, 122, 10, 16, 25, 66, 73, 68, 83, 83, 83, 96,\n                                95, 94, 112, 104, 93, 113, 117, 121, 126, 112,\n                                109, 100, 81, 88, 6, 24, 4, 25, 46, 82, 85, 90,\n                                88, 112, 101, 95, 120, 99, 110, 105, 123, 117,\n                                114, 113, 84, 81, 117, 88, 90, 102, 114, 108,\n                                109, 110, 105, 114, 112, 115, 120, 126, 119, 76,\n                                84, 101, 66, 14, 10, 21, 22, 26, 49, 31, 42, 42,\n                                62, 52, 46, 62, 62, 38, 70, 92, 112, 123, 126,\n                                126, 126, 126, 16, 50, 43, 43, 31, 44, 22, 17,\n                                22, 12, 69, 1, 17, 4, 36, 46, 2, 11, 20, 24, 6,\n                                22, 40, 4, 65, 12, 87, 112, 126, 126, 126, 126,\n                                126, 126 },\n\n                              {\n\n                              16,\n                                3, 83, 16, 3, 83, 24, 31, 29, 13, 72, 104, 73,\n                                65, 51, 14, 61, 72, 26, 33, 65, 86, 3, 103, 120,\n                                71, 90, 126, 126, 126, 62, 22, 70, 26, 33, 65,\n                                67, 22, 21, 73, 4, 1, 2, 73, 88, 70, 94, 5, 66,\n                                1, 69, 81, 71, 88, 18, 5, 2, 64, 13, 2, 22, 0,\n                                0, 0, 9, 98, 97, 13, 81, 71, 18, 65, 86, 22, 53,\n                                41, 62, 62, 32, 30, 22, 38, 18, 11, 27, 70, 73,\n                                74, 67, 27, 2, 10, 64, 64, 0, 1, 9, 69, 78, 77,\n                                87, 19, 68, 7, 0, 78, 4, 71, 8, 3, 65, 5, 10, 3,\n                                68, 66, 6, 67, 0, 69, 69, 76, 64, 69, 81, 2, 69,\n                                76, 2, 12, 66, 86, 77, 78, 81, 4, 68, 9, 7, 7,\n                                41, 19, 5, 69, 13, 69, 82, 0, 108, 73, 64, 91,\n                                71, 89, 4, 64, 82, 19, 8, 4, 101, 4, 86, 74, 3,\n                                97, 1, 17, 10, 14, 17, 13, 6, 16, 12, 68, 64, 9,\n                                0, 64, 75, 69, 75, 74, 70, 73, 79, 79, 78, 78,\n                                76, 68, 92, 99, 80, 85, 86, 90, 91, 100, 105,\n                                99, 99, 109, 115, 108, 111, 126, 121, 123, 70,\n                                74, 95, 80, 88, 91, 97, 106, 109, 99, 103, 97,\n                                87, 92, 90, 82, 79, 6, 26, 18, 11, 9, 11, 6, 1,\n                                6, 15, 15, 30, 21, 15, 8, 23, 14, 18, 11, 38, 2,\n                                44, 31, 22, 14, 27, 5, 64, 64, 5, 70, 47, 17, 0,\n                                1, 12, 1, 71, 1, 5, 33, 18, 2, 67, 17, 5, 3, 3,\n                                3, 62, 65, 7, 8, 15, 10, 9, 22, 23, 17, 22, 27,\n                                33, 64, 6, 75, 64, 38, 70, 95, 67, 10, 66, 81,\n                                86, 76, 87, 96, 105, 107, 72, 67, 16, 70, 77,\n                                69, 65, 2, 81, 75, 68, 68, 89, 75, 82, 1, 11,\n                                88, 75, 4, 80, 1, 77, 69, 21, 80, 85, 65, 4, 90,\n                                88, 124, 9, 15, 24, 67, 74, 69, 85, 85, 85, 98,\n                                98, 97, 115, 106, 94, 116, 120, 124, 126, 115,\n                                111, 102, 82, 89, 6, 25, 4, 26, 48, 84, 87, 92,\n                                90, 114, 103, 97, 122, 100, 112, 106, 125, 118,\n                                115, 114, 85, 81, 118, 89, 91, 104, 116, 110,\n                                111, 111, 107, 116, 113, 116, 121, 126, 120, 77,\n                                85, 102, 66, 14, 10, 22, 22, 27, 50, 32, 43, 43,\n                                62, 53, 47, 62, 62, 37, 72, 94, 114, 126, 126,\n                                126, 126, 126, 16, 50, 43, 43, 31, 45, 22, 17,\n                                22, 12, 69, 1, 18, 4, 37, 47, 2, 12, 21, 25, 6,\n                                22, 41, 4, 65, 11, 89, 114, 126, 126, 126, 126,\n                                126, 126 },\n\n                              {\n\n                              15,\n                                3, 83, 15, 3, 83, 26, 33, 30, 13, 73, 106, 75,\n                                66, 51, 14, 62, 72, 27, 34, 65, 87, 3, 104, 121,\n                                71, 92, 126, 126, 126, 62, 23, 70, 27, 34, 65,\n                                66, 23, 22, 73, 4, 2, 3, 74, 89, 70, 94, 5, 66,\n                                1, 69, 81, 71, 88, 19, 5, 2, 64, 14, 2, 22, 0,\n                                0, 0, 9, 98, 97, 14, 82, 71, 18, 65, 86, 24, 55,\n                                42, 62, 62, 33, 31, 24, 39, 19, 12, 29, 69, 73,\n                                73, 66, 27, 2, 10, 64, 64, 0, 2, 11, 69, 79, 78,\n                                88, 19, 68, 7, 1, 78, 5, 71, 9, 3, 65, 5, 10, 2,\n                                68, 66, 6, 67, 0, 69, 70, 76, 64, 70, 82, 1, 70,\n                                77, 2, 13, 66, 87, 77, 77, 81, 4, 68, 9, 7, 7,\n                                42, 19, 5, 69, 14, 69, 83, 0, 109, 73, 64, 91,\n                                72, 90, 4, 64, 83, 19, 8, 4, 103, 4, 87, 74, 3,\n                                97, 0, 17, 10, 14, 17, 13, 6, 16, 12, 68, 65, 9,\n                                0, 64, 75, 70, 76, 75, 71, 74, 80, 80, 78, 78,\n                                77, 68, 93, 101, 80, 86, 88, 92, 93, 102, 107,\n                                101, 101, 111, 117, 109, 112, 126, 123, 124, 70,\n                                74, 95, 81, 89, 92, 99, 107, 111, 100, 104, 98,\n                                87, 92, 90, 82, 79, 7, 26, 18, 11, 9, 11, 6, 1,\n                                7, 16, 15, 30, 21, 15, 8, 24, 15, 19, 12, 40, 2,\n                                44, 31, 22, 14, 28, 5, 64, 64, 5, 70, 47, 17,\n                                64, 1, 12, 1, 71, 2, 5, 33, 18, 1, 68, 17, 5, 3,\n                                4, 4, 62, 64, 8, 8, 16, 11, 10, 24, 24, 18, 23,\n                                29, 34, 64, 7, 75, 64, 40, 70, 95, 67, 10, 66,\n                                82, 86, 76, 88, 97, 106, 108, 72, 68, 16, 71,\n                                77, 69, 66, 2, 82, 75, 69, 68, 90, 75, 83, 1,\n                                11, 89, 75, 4, 81, 1, 78, 69, 21, 81, 86, 66, 3,\n                                91, 88, 125, 8, 14, 24, 68, 75, 71, 87, 87, 87,\n                                101, 100, 99, 118, 109, 95, 119, 123, 126, 126,\n                                118, 114, 104, 83, 90, 6, 26, 4, 27, 50, 86, 89,\n                                94, 92, 116, 105, 98, 124, 102, 113, 107, 126,\n                                120, 116, 115, 85, 82, 119, 90, 93, 105, 118,\n                                112, 113, 113, 108, 118, 115, 117, 123, 126,\n                                121, 78, 86, 103, 66, 15, 10, 22, 23, 27, 51,\n                                33, 44, 44, 62, 54, 48, 62, 62, 37, 73, 96, 117,\n                                126, 126, 126, 126, 126, 17, 51, 44, 44, 31, 46,\n                                23, 17, 23, 13, 69, 2, 18, 5, 38, 48, 2, 12, 21,\n                                25, 6, 23, 42, 4, 65, 10, 91, 117, 126, 126,\n                                126, 126, 126, 126 },\n\n                        },\n\n                          {\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 126, 104, 10, 9, 12, 38, 62,\n                                62, 54, 22, 118, 65, 71, 79, 11, 13, 70, 9, 29,\n                                41, 62, 61, 27, 69, 126, 101, 76, 71, 79, 11,\n                                69, 90, 11, 20, 69, 82, 96, 4, 75, 87, 100, 7,\n                                74, 85, 4, 81, 86, 95, 66, 77, 70, 86, 72, 2,\n                                22, 0, 0, 0, 83, 86, 97, 72, 22, 1, 48, 12, 80,\n                                126, 91, 96, 81, 98, 102, 97, 119, 99, 110, 102,\n                                126, 80, 89, 94, 92, 24, 65, 84, 126, 73, 104,\n                                91, 126, 8, 7, 8, 2, 10, 68, 74, 88, 103, 91,\n                                89, 92, 76, 87, 110, 105, 78, 112, 99, 126, 126,\n                                126, 126, 66, 78, 71, 72, 4, 8, 70, 75, 89, 119,\n                                75, 43, 41, 126, 9, 2, 5, 3, 2, 67, 84, 74, 65,\n                                11, 6, 2, 69, 70, 8, 71, 5, 2, 22, 38, 31, 20,\n                                16, 19, 12, 17, 25, 66, 25, 21, 29, 89, 18, 35,\n                                32, 62, 62, 48, 62, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 53, 62, 62, 62, 62, 62, 62, 62, 56, 62,\n                                62, 62, 27, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 53, 45, 38, 22, 75, 72, 77, 28, 32, 28,\n                                33, 18, 21, 18, 37, 9, 66, 7, 73, 67, 116, 112,\n                                71, 2, 10, 66, 77, 80, 84, 87, 126, 101, 24, 10,\n                                2, 75, 77, 91, 107, 111, 122, 76, 19, 11, 6, 5,\n                                72, 69, 69, 74, 86, 66, 29, 31, 32, 11, 8, 67,\n                                73, 89, 11, 59, 55, 55, 44, 26, 2, 73, 70, 78,\n                                62, 126, 124, 110, 126, 124, 105, 121, 117, 102,\n                                117, 116, 122, 95, 100, 95, 111, 114, 89, 80,\n                                82, 85, 81, 72, 64, 67, 7, 69, 69, 69, 69, 67,\n                                77, 64, 2, 67, 64, 6, 65, 66, 1, 12, 66, 71, 75,\n                                70, 72, 3, 26, 16, 28, 26, 22, 22, 15, 22, 22,\n                                4, 13, 23, 66, 13, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 62, 62, 62, 62, 62, 54, 62, 62, 62, 62,\n                                62, 62, 62, 62, 62, 49, 37, 26, 8, 65, 62, 62,\n                                62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 43, 33,\n                                19, 15, 14, 18, 41, 41, 42, 43, 35, 39, 29, 21,\n                                24, 13, 70, 9, 71, 83, 31, 14, 9, 85, 81, 77,\n                                81, 80, 73, 74, 83, 71, 67, 2, 66, 66, 4, 4, 62,\n                                62, 62, 62, 62, 60, 53, 36, 6, 71, 39, 27, 21,\n                                11, 6, 0, 65, 67, 82, 81, 76, 72, 78, 72, 68,\n                                70, 76, 66, 1, 6, 2, 3, 9, 5, 62, 62, 62, 62,\n                                62, 60, 53, 36, 6 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 125, 102, 11, 10, 12, 37,\n                                  61, 62, 55, 22, 116, 65, 70, 78, 11, 13, 69,\n                                  9, 28, 40, 61, 58, 25, 70, 124, 100, 75, 70,\n                                  78, 11, 69, 89, 11, 20, 68, 81, 95, 4, 75, 86,\n                                  99, 7, 73, 84, 4, 80, 85, 94, 65, 76, 70, 85,\n                                  71, 2, 22, 0, 0, 0, 82, 86, 97, 71, 22, 1, 48,\n                                  12, 80, 124, 89, 94, 79, 95, 100, 95, 117, 97,\n                                  108, 100, 124, 80, 88, 93, 91, 24, 65, 83,\n                                  124, 72, 103, 90, 125, 8, 7, 8, 2, 11, 68, 73,\n                                  87, 102, 90, 88, 91, 75, 86, 108, 103, 77,\n                                  110, 97, 122, 122, 123, 124, 65, 77, 70, 71,\n                                  4, 9, 69, 74, 88, 116, 74, 41, 40, 124, 9, 3,\n                                  5, 4, 3, 66, 82, 73, 64, 11, 6, 2, 68, 69, 7,\n                                  70, 5, 2, 22, 37, 31, 20, 16, 19, 12, 17, 24,\n                                  65, 25, 21, 29, 89, 18, 35, 32, 62, 62, 47,\n                                  62, 62, 62, 61, 62, 62, 62, 62, 62, 62, 52,\n                                  62, 62, 62, 62, 62, 62, 62, 54, 62, 60, 62,\n                                  26, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  61, 52, 44, 37, 21, 75, 72, 77, 28, 31, 27,\n                                  32, 17, 20, 17, 36, 8, 66, 6, 73, 67, 115,\n                                  110, 70, 3, 10, 65, 76, 79, 83, 86, 124, 99,\n                                  25, 11, 3, 74, 76, 89, 105, 109, 120, 75, 20,\n                                  12, 7, 6, 71, 68, 68, 73, 85, 66, 30, 31, 32,\n                                  11, 9, 66, 73, 88, 11, 59, 55, 54, 43, 26, 3,\n                                  72, 69, 77, 62, 124, 122, 108, 124, 122, 103,\n                                  119, 115, 100, 115, 114, 119, 94, 99, 94, 109,\n                                  112, 88, 79, 81, 84, 80, 71, 64, 67, 7, 69,\n                                  69, 69, 68, 66, 76, 0, 2, 66, 0, 6, 64, 65, 1,\n                                  12, 65, 70, 74, 69, 71, 3, 25, 16, 27, 26, 22,\n                                  22, 15, 22, 22, 4, 13, 22, 66, 12, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  52, 62, 62, 62, 62, 62, 62, 62, 61, 62, 48,\n                                  36, 25, 8, 65, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 42, 32, 18, 15, 14, 17, 40,\n                                  40, 41, 41, 34, 38, 28, 20, 23, 12, 70, 8, 71,\n                                  83, 30, 13, 8, 84, 80, 76, 80, 78, 71, 73, 82,\n                                  70, 66, 3, 65, 65, 4, 4, 62, 62, 62, 62, 60,\n                                  56, 49, 32, 4, 70, 39, 28, 22, 12, 7, 1, 64,\n                                  66, 81, 80, 75, 71, 77, 71, 67, 69, 75, 65, 2,\n                                  6, 3, 4, 9, 5, 62, 62, 62, 62, 60, 56, 49, 32,\n                                  4 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 123, 101, 11, 10, 12, 36,\n                                  59, 61, 55, 22, 114, 65, 70, 77, 11, 12, 69,\n                                  8, 26, 39, 58, 54, 22, 72, 121, 99, 75, 70,\n                                  77, 11, 69, 88, 11, 19, 68, 81, 94, 4, 75, 86,\n                                  99, 7, 73, 84, 4, 80, 85, 94, 65, 76, 70, 85,\n                                  71, 2, 22, 0, 0, 0, 81, 86, 97, 71, 21, 1, 47,\n                                  12, 80, 122, 88, 93, 77, 93, 99, 94, 115, 96,\n                                  107, 99, 122, 80, 88, 93, 91, 24, 65, 82, 122,\n                                  72, 102, 89, 123, 8, 7, 8, 1, 11, 68, 73, 86,\n                                  101, 89, 87, 90, 75, 85, 107, 102, 76, 109,\n                                  96, 117, 118, 120, 121, 65, 77, 70, 71, 4, 9,\n                                  69, 74, 88, 114, 74, 39, 38, 121, 9, 3, 5, 4,\n                                  3, 66, 80, 72, 64, 11, 6, 2, 67, 68, 6, 70, 5,\n                                  2, 21, 36, 30, 20, 15, 19, 12, 17, 23, 65, 24,\n                                  20, 28, 89, 18, 34, 31, 62, 62, 46, 60, 62,\n                                  62, 59, 62, 62, 62, 62, 62, 62, 50, 62, 62,\n                                  62, 62, 62, 62, 62, 52, 62, 58, 62, 24, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 59, 50,\n                                  42, 35, 19, 75, 72, 78, 27, 30, 26, 31, 16,\n                                  19, 16, 34, 7, 66, 5, 74, 68, 114, 109, 69, 3,\n                                  10, 65, 75, 78, 82, 85, 122, 98, 25, 11, 3,\n                                  73, 75, 88, 103, 107, 118, 74, 21, 13, 8, 7,\n                                  70, 68, 68, 73, 84, 66, 31, 31, 31, 11, 9, 66,\n                                  73, 88, 11, 59, 54, 53, 42, 26, 3, 72, 69, 77,\n                                  62, 123, 121, 107, 122, 120, 102, 117, 113,\n                                  99, 113, 112, 117, 93, 98, 94, 108, 110, 88,\n                                  79, 81, 83, 80, 71, 64, 67, 6, 69, 69, 69, 68,\n                                  66, 75, 0, 2, 66, 0, 6, 64, 65, 1, 11, 65, 70,\n                                  74, 69, 70, 2, 24, 16, 26, 25, 21, 21, 15, 21,\n                                  21, 4, 13, 21, 66, 11, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 50, 62, 62,\n                                  62, 62, 62, 62, 62, 59, 59, 46, 34, 24, 7, 66,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 40, 30, 16, 14, 13, 15, 39, 39, 39, 39,\n                                  32, 36, 26, 19, 21, 11, 71, 7, 72, 84, 28, 12,\n                                  7, 84, 80, 75, 80, 77, 70, 73, 81, 69, 65, 3,\n                                  65, 64, 4, 4, 62, 62, 62, 62, 57, 52, 45, 28,\n                                  1, 70, 39, 28, 22, 12, 8, 1, 64, 66, 81, 80,\n                                  75, 71, 77, 70, 66, 69, 75, 65, 2, 6, 3, 5, 9,\n                                  5, 62, 62, 62, 62, 57, 52, 45, 28, 1 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 121, 99, 12, 10, 11, 34, 57,\n                                  60, 55, 22, 112, 65, 69, 76, 11, 12, 69, 8,\n                                  25, 38, 56, 51, 20, 73, 118, 98, 75, 69, 76,\n                                  11, 70, 87, 11, 19, 68, 81, 94, 4, 75, 86, 99,\n                                  7, 73, 83, 4, 80, 84, 94, 65, 76, 70, 85, 71,\n                                  2, 22, 0, 0, 0, 81, 86, 97, 70, 20, 1, 46, 11,\n                                  80, 119, 87, 92, 76, 91, 97, 92, 113, 94, 106,\n                                  98, 120, 80, 88, 92, 91, 24, 65, 81, 120, 72,\n                                  101, 89, 121, 8, 6, 7, 1, 11, 68, 72, 86, 100,\n                                  88, 87, 89, 74, 84, 105, 100, 76, 108, 95,\n                                  112, 113, 117, 118, 65, 77, 70, 70, 4, 9, 68,\n                                  73, 87, 112, 74, 37, 36, 118, 9, 3, 5, 4, 3,\n                                  65, 79, 71, 64, 11, 6, 2, 67, 67, 5, 70, 5, 1,\n                                  21, 35, 30, 20, 15, 19, 12, 17, 22, 65, 23,\n                                  19, 28, 89, 18, 34, 31, 62, 62, 45, 58, 62,\n                                  62, 57, 62, 62, 62, 62, 62, 61, 48, 62, 62,\n                                  62, 62, 62, 62, 60, 50, 62, 56, 62, 22, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 57, 48,\n                                  40, 34, 17, 75, 72, 78, 26, 29, 25, 30, 15,\n                                  18, 15, 32, 6, 67, 4, 75, 68, 114, 107, 68, 4,\n                                  10, 65, 74, 78, 82, 85, 120, 97, 25, 11, 4,\n                                  72, 74, 87, 102, 106, 116, 73, 21, 13, 8, 7,\n                                  69, 67, 68, 73, 84, 66, 31, 31, 30, 11, 9, 66,\n                                  73, 87, 11, 58, 54, 52, 41, 26, 3, 72, 69, 77,\n                                  62, 122, 119, 106, 121, 119, 101, 115, 111,\n                                  98, 112, 110, 115, 93, 97, 93, 107, 108, 87,\n                                  79, 81, 83, 79, 71, 64, 67, 6, 69, 69, 70, 67,\n                                  65, 74, 0, 2, 65, 0, 6, 64, 65, 1, 11, 65, 70,\n                                  74, 69, 70, 1, 23, 16, 25, 24, 20, 21, 15, 20,\n                                  20, 4, 13, 20, 66, 10, 62, 62, 61, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 48, 62, 62,\n                                  62, 62, 62, 62, 62, 57, 57, 44, 32, 22, 6, 67,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 59,\n                                  60, 38, 28, 15, 13, 12, 14, 37, 37, 37, 37,\n                                  31, 34, 24, 18, 20, 10, 72, 6, 73, 85, 27, 11,\n                                  6, 84, 79, 75, 79, 76, 69, 73, 81, 69, 65, 3,\n                                  64, 0, 4, 4, 62, 62, 62, 59, 54, 48, 41, 24,\n                                  65, 70, 39, 28, 22, 12, 8, 2, 64, 66, 80, 80,\n                                  75, 70, 76, 69, 65, 69, 74, 65, 2, 6, 3, 5, 9,\n                                  5, 62, 62, 62, 59, 54, 48, 41, 24, 65 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 120, 98, 12, 10, 11, 33, 55,\n                                  59, 55, 21, 110, 65, 69, 75, 10, 11, 69, 7,\n                                  23, 37, 53, 47, 17, 75, 115, 97, 75, 69, 75,\n                                  10, 70, 86, 11, 18, 68, 80, 93, 4, 75, 86, 99,\n                                  7, 73, 83, 4, 80, 84, 93, 65, 76, 70, 85, 70,\n                                  2, 22, 0, 0, 0, 80, 87, 97, 70, 19, 1, 45, 11,\n                                  80, 117, 86, 91, 74, 89, 96, 91, 112, 93, 104,\n                                  97, 118, 80, 87, 92, 91, 24, 65, 80, 118, 72,\n                                  101, 88, 119, 8, 6, 7, 0, 11, 68, 72, 85, 99,\n                                  87, 86, 88, 74, 84, 104, 99, 75, 107, 94, 107,\n                                  109, 114, 115, 65, 76, 70, 70, 4, 9, 68, 73,\n                                  87, 110, 74, 35, 34, 116, 9, 4, 5, 4, 3, 65,\n                                  77, 70, 0, 10, 6, 2, 66, 67, 4, 70, 5, 1, 20,\n                                  34, 29, 19, 14, 19, 12, 17, 21, 65, 22, 18,\n                                  27, 89, 17, 33, 30, 62, 62, 44, 56, 62, 62,\n                                  55, 62, 62, 62, 62, 62, 59, 46, 59, 62, 62,\n                                  62, 62, 62, 57, 48, 62, 54, 62, 21, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 60, 55, 46, 38,\n                                  32, 15, 75, 72, 79, 25, 28, 24, 28, 14, 16,\n                                  14, 31, 5, 67, 3, 75, 69, 113, 106, 67, 4, 10,\n                                  64, 74, 77, 81, 84, 118, 95, 25, 12, 4, 72,\n                                  73, 86, 100, 104, 115, 73, 22, 14, 9, 8, 68,\n                                  67, 68, 72, 83, 66, 32, 31, 30, 10, 9, 66, 73,\n                                  87, 11, 58, 53, 51, 40, 26, 3, 71, 69, 77, 62,\n                                  120, 118, 105, 119, 117, 100, 114, 110, 97,\n                                  110, 109, 113, 92, 96, 93, 106, 107, 87, 79,\n                                  81, 82, 79, 71, 65, 67, 5, 69, 69, 70, 67, 65,\n                                  73, 0, 2, 65, 0, 6, 64, 65, 1, 10, 65, 70, 74,\n                                  69, 69, 0, 22, 16, 24, 24, 19, 20, 15, 19, 19,\n                                  4, 13, 19, 66, 9, 62, 62, 60, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 46, 62, 62, 62,\n                                  62, 62, 62, 62, 54, 54, 42, 30, 21, 5, 67, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 57, 57,\n                                  36, 26, 13, 12, 12, 12, 36, 36, 36, 35, 29,\n                                  32, 23, 17, 18, 9, 73, 4, 74, 85, 25, 9, 4,\n                                  83, 79, 74, 79, 75, 68, 73, 80, 68, 64, 3, 64,\n                                  1, 4, 4, 62, 62, 62, 56, 50, 44, 36, 20, 68,\n                                  69, 39, 28, 22, 12, 9, 2, 64, 66, 80, 80, 75,\n                                  70, 76, 69, 64, 69, 74, 64, 3, 6, 3, 6, 9, 5,\n                                  62, 62, 62, 56, 50, 44, 36, 20, 68 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 118, 96, 12, 10, 10, 32, 53,\n                                  58, 55, 21, 108, 65, 69, 74, 10, 11, 69, 6,\n                                  21, 36, 51, 44, 15, 77, 112, 96, 74, 69, 74,\n                                  10, 70, 85, 11, 18, 68, 80, 92, 4, 75, 86, 99,\n                                  7, 73, 83, 4, 80, 83, 93, 65, 76, 70, 85, 70,\n                                  2, 22, 0, 0, 0, 80, 87, 97, 69, 18, 1, 44, 10,\n                                  80, 114, 85, 90, 72, 87, 94, 89, 110, 91, 103,\n                                  96, 115, 80, 87, 91, 90, 24, 65, 79, 116, 72,\n                                  100, 88, 117, 8, 5, 6, 0, 11, 68, 71, 85, 98,\n                                  86, 86, 87, 73, 83, 102, 97, 74, 105, 93, 102,\n                                  105, 111, 112, 64, 76, 69, 69, 4, 9, 67, 73,\n                                  86, 108, 74, 33, 32, 113, 9, 4, 5, 4, 3, 64,\n                                  76, 69, 0, 10, 6, 2, 66, 66, 3, 69, 5, 0, 20,\n                                  33, 29, 19, 14, 19, 12, 17, 20, 64, 21, 18,\n                                  27, 89, 17, 32, 29, 62, 62, 43, 55, 62, 62,\n                                  53, 62, 62, 62, 62, 61, 57, 44, 57, 62, 60,\n                                  62, 62, 62, 55, 46, 62, 52, 62, 19, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 61, 58, 53, 44, 37,\n                                  30, 13, 75, 72, 79, 24, 27, 23, 27, 13, 15,\n                                  13, 29, 4, 68, 2, 76, 70, 112, 104, 66, 5, 10,\n                                  64, 73, 77, 81, 83, 116, 94, 25, 12, 5, 71,\n                                  72, 85, 99, 103, 113, 72, 23, 15, 10, 8, 67,\n                                  66, 67, 72, 83, 66, 32, 31, 29, 10, 9, 66, 73,\n                                  86, 11, 57, 52, 50, 39, 26, 3, 71, 69, 76, 62,\n                                  119, 116, 103, 117, 116, 99, 112, 108, 96,\n                                  108, 107, 111, 91, 95, 92, 105, 105, 87, 79,\n                                  80, 82, 78, 71, 65, 67, 5, 69, 69, 71, 66, 65,\n                                  72, 0, 2, 65, 0, 6, 64, 65, 1, 10, 65, 70, 74,\n                                  69, 69, 64, 21, 16, 23, 23, 19, 19, 15, 19,\n                                  18, 4, 13, 18, 66, 8, 62, 62, 59, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 44, 62, 62,\n                                  62, 62, 62, 62, 61, 52, 52, 40, 29, 19, 5, 68,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 61, 55,\n                                  54, 34, 24, 12, 12, 11, 10, 35, 34, 34, 33,\n                                  27, 30, 21, 16, 17, 8, 73, 3, 75, 86, 24, 8,\n                                  3, 83, 79, 73, 78, 74, 67, 72, 79, 68, 64, 3,\n                                  0, 2, 4, 4, 62, 62, 59, 53, 47, 40, 32, 16,\n                                  71, 69, 39, 28, 22, 12, 9, 2, 0, 65, 79, 80,\n                                  75, 69, 76, 68, 0, 69, 74, 64, 3, 6, 4, 6, 9,\n                                  5, 62, 62, 59, 53, 47, 40, 32, 16, 71 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 116, 95, 13, 10, 10, 30, 51,\n                                  57, 55, 21, 107, 65, 68, 74, 10, 10, 68, 6,\n                                  20, 34, 48, 40, 12, 78, 110, 95, 74, 68, 74,\n                                  10, 71, 85, 11, 17, 68, 80, 92, 4, 75, 85, 98,\n                                  7, 72, 82, 4, 79, 83, 93, 65, 76, 70, 85, 70,\n                                  2, 22, 0, 0, 0, 79, 87, 97, 69, 18, 0, 44, 10,\n                                  80, 112, 84, 89, 71, 84, 93, 88, 108, 90, 102,\n                                  95, 113, 80, 87, 91, 90, 24, 65, 78, 113, 72,\n                                  99, 87, 115, 7, 5, 6, 64, 12, 68, 71, 84, 98,\n                                  86, 85, 86, 73, 82, 101, 96, 74, 104, 92, 97,\n                                  100, 108, 109, 64, 76, 69, 69, 4, 9, 67, 72,\n                                  86, 106, 73, 31, 30, 110, 9, 4, 5, 4, 4, 64,\n                                  74, 68, 0, 10, 6, 2, 65, 65, 2, 69, 5, 0, 19,\n                                  32, 28, 19, 13, 19, 12, 17, 18, 64, 20, 17,\n                                  26, 89, 17, 32, 29, 62, 62, 42, 53, 62, 62,\n                                  51, 62, 62, 62, 62, 57, 55, 43, 55, 62, 58,\n                                  62, 62, 62, 52, 44, 62, 50, 62, 17, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 59, 56, 50, 42, 35,\n                                  29, 12, 75, 72, 80, 23, 26, 22, 26, 12, 14,\n                                  12, 27, 3, 68, 1, 77, 70, 112, 103, 65, 5, 10,\n                                  64, 72, 76, 80, 83, 114, 93, 26, 12, 5, 70,\n                                  71, 84, 97, 101, 111, 71, 23, 15, 10, 9, 66,\n                                  66, 67, 72, 82, 66, 33, 31, 28, 10, 9, 66, 73,\n                                  86, 10, 57, 52, 49, 38, 25, 3, 71, 69, 76, 62,\n                                  118, 115, 102, 116, 114, 98, 110, 106, 95,\n                                  107, 105, 109, 91, 94, 92, 104, 103, 86, 79,\n                                  80, 81, 78, 71, 65, 67, 4, 69, 69, 71, 66, 64,\n                                  71, 0, 2, 64, 1, 6, 0, 64, 1, 9, 65, 70, 74,\n                                  69, 68, 65, 20, 16, 22, 22, 18, 19, 15, 18,\n                                  18, 4, 12, 16, 67, 7, 62, 62, 58, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 42, 62, 62,\n                                  62, 62, 62, 62, 58, 50, 49, 38, 27, 18, 4, 69,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 61, 58, 52,\n                                  51, 32, 23, 10, 11, 10, 9, 33, 33, 32, 31, 26,\n                                  28, 19, 15, 15, 7, 74, 2, 76, 87, 22, 7, 2,\n                                  83, 78, 73, 78, 73, 66, 72, 79, 67, 0, 3, 0,\n                                  3, 4, 4, 62, 62, 57, 50, 44, 36, 28, 12, 74,\n                                  69, 39, 28, 22, 12, 10, 3, 0, 65, 79, 79, 74,\n                                  69, 75, 67, 1, 68, 73, 64, 3, 6, 4, 7, 9, 5,\n                                  62, 62, 57, 50, 44, 36, 28, 12, 74 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 114, 93, 13, 10, 9, 29, 49,\n                                  56, 55, 21, 105, 65, 68, 73, 9, 10, 68, 5, 18,\n                                  33, 46, 37, 10, 80, 107, 94, 74, 68, 73, 9,\n                                  71, 84, 11, 17, 68, 79, 91, 4, 75, 85, 98, 7,\n                                  72, 82, 4, 79, 82, 92, 65, 76, 70, 85, 69, 2,\n                                  22, 0, 0, 0, 79, 87, 97, 68, 17, 0, 43, 9, 80,\n                                  109, 83, 88, 69, 82, 91, 86, 107, 88, 100, 94,\n                                  111, 80, 86, 90, 90, 24, 65, 77, 111, 72, 98,\n                                  87, 113, 7, 4, 5, 64, 12, 68, 70, 84, 97, 85,\n                                  85, 85, 72, 81, 99, 94, 73, 103, 91, 92, 96,\n                                  105, 106, 64, 75, 69, 68, 4, 9, 66, 72, 85,\n                                  104, 73, 29, 28, 107, 9, 5, 5, 4, 4, 0, 73,\n                                  67, 1, 9, 6, 2, 65, 65, 1, 69, 5, 64, 19, 31,\n                                  28, 18, 13, 19, 12, 17, 17, 64, 19, 16, 26,\n                                  89, 17, 31, 28, 60, 62, 41, 51, 62, 62, 49,\n                                  62, 61, 62, 62, 54, 53, 41, 52, 62, 55, 62,\n                                  62, 62, 49, 42, 62, 48, 62, 16, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 57, 53, 48, 40, 33, 27,\n                                  10, 75, 72, 80, 22, 25, 21, 24, 11, 13, 11,\n                                  26, 2, 69, 0, 77, 71, 111, 101, 64, 6, 10, 0,\n                                  72, 76, 80, 82, 112, 91, 26, 13, 6, 70, 70,\n                                  83, 96, 100, 109, 71, 24, 16, 11, 9, 65, 65,\n                                  67, 71, 82, 66, 33, 31, 28, 9, 9, 66, 73, 85,\n                                  10, 56, 51, 48, 37, 25, 3, 70, 69, 76, 62,\n                                  116, 113, 101, 114, 113, 97, 109, 105, 94,\n                                  105, 104, 107, 90, 93, 91, 103, 101, 86, 79,\n                                  80, 81, 77, 71, 66, 67, 4, 69, 69, 72, 65, 64,\n                                  70, 0, 2, 64, 1, 6, 0, 64, 1, 9, 65, 70, 74,\n                                  69, 68, 66, 19, 16, 21, 22, 17, 18, 15, 17,\n                                  17, 4, 12, 15, 67, 6, 61, 62, 57, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 40, 62, 62,\n                                  62, 62, 62, 62, 56, 48, 47, 36, 25, 16, 3, 69,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 59, 56, 50,\n                                  48, 30, 21, 9, 10, 10, 7, 32, 31, 31, 29, 24,\n                                  26, 18, 14, 14, 6, 75, 0, 77, 87, 21, 5, 0,\n                                  82, 78, 72, 77, 72, 65, 72, 78, 67, 0, 3, 1,\n                                  4, 4, 4, 62, 62, 54, 47, 40, 32, 24, 8, 77,\n                                  68, 39, 28, 22, 12, 10, 3, 0, 65, 78, 79, 74,\n                                  68, 75, 66, 2, 68, 73, 0, 4, 6, 4, 7, 9, 5,\n                                  62, 62, 54, 47, 40, 32, 24, 8, 77 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 113, 92, 13, 10, 9, 27, 46,\n                                  55, 55, 20, 103, 66, 68, 72, 9, 9, 68, 4, 16,\n                                  32, 43, 33, 7, 82, 104, 93, 74, 68, 72, 9, 72,\n                                  83, 11, 16, 68, 79, 91, 3, 76, 85, 98, 7, 72,\n                                  82, 4, 79, 82, 92, 65, 76, 70, 85, 69, 2, 22,\n                                  0, 0, 0, 78, 88, 97, 68, 16, 0, 42, 9, 81,\n                                  107, 82, 87, 68, 80, 90, 85, 105, 87, 99, 93,\n                                  109, 80, 86, 90, 90, 24, 65, 76, 109, 72, 98,\n                                  86, 111, 7, 4, 5, 65, 12, 68, 70, 83, 96, 84,\n                                  84, 85, 72, 81, 98, 93, 73, 102, 90, 88, 92,\n                                  102, 104, 64, 75, 69, 68, 3, 9, 66, 72, 85,\n                                  102, 73, 27, 26, 105, 9, 5, 5, 4, 4, 0, 71,\n                                  67, 1, 9, 5, 2, 64, 64, 64, 69, 5, 64, 18, 29,\n                                  27, 18, 12, 19, 12, 16, 16, 64, 18, 15, 25,\n                                  89, 16, 30, 27, 58, 62, 39, 49, 62, 62, 46,\n                                  62, 59, 62, 62, 50, 51, 39, 50, 62, 53, 62,\n                                  62, 62, 46, 40, 62, 46, 62, 14, 62, 62, 62,\n                                  62, 62, 62, 62, 60, 55, 51, 46, 38, 31, 25, 8,\n                                  75, 73, 81, 21, 23, 20, 23, 10, 11, 9, 24, 1,\n                                  69, 64, 78, 72, 111, 100, 0, 6, 10, 0, 71, 75,\n                                  79, 82, 110, 90, 26, 13, 6, 69, 69, 82, 94,\n                                  98, 108, 70, 24, 16, 11, 10, 64, 65, 67, 71,\n                                  81, 67, 34, 31, 27, 9, 9, 66, 73, 85, 10, 56,\n                                  50, 47, 36, 25, 3, 70, 69, 76, 62, 115, 112,\n                                  100, 113, 111, 96, 107, 103, 93, 104, 102,\n                                  105, 90, 93, 91, 102, 100, 86, 79, 80, 80, 77,\n                                  71, 66, 67, 3, 69, 69, 72, 65, 64, 69, 0, 1,\n                                  64, 1, 5, 0, 64, 1, 8, 65, 70, 74, 69, 67, 67,\n                                  18, 16, 19, 21, 16, 17, 14, 16, 16, 4, 12, 14,\n                                  67, 4, 60, 60, 56, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 60, 38, 62, 62, 62, 62, 62, 62,\n                                  53, 45, 44, 34, 23, 15, 2, 70, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 56, 53, 47, 45, 28, 19, 7, 9,\n                                  9, 5, 30, 30, 29, 27, 22, 24, 16, 12, 12, 4,\n                                  76, 64, 78, 88, 19, 4, 64, 82, 78, 72, 77, 71,\n                                  64, 72, 78, 66, 1, 3, 1, 4, 4, 3, 62, 60, 51,\n                                  44, 37, 28, 19, 3, 80, 68, 39, 28, 22, 12, 11,\n                                  3, 0, 65, 78, 79, 74, 68, 75, 66, 2, 68, 73,\n                                  0, 4, 6, 4, 8, 9, 4, 62, 60, 51, 44, 37, 28,\n                                  19, 3, 80 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 111, 91, 14, 10, 9, 26, 44,\n                                  54, 56, 20, 101, 66, 67, 71, 9, 8, 68, 4, 15,\n                                  31, 41, 29, 4, 83, 101, 92, 73, 67, 71, 9, 72,\n                                  82, 11, 16, 67, 79, 90, 3, 76, 85, 98, 7, 72,\n                                  81, 4, 79, 82, 92, 65, 76, 70, 84, 69, 2, 22,\n                                  0, 0, 0, 77, 88, 97, 68, 15, 0, 41, 9, 81,\n                                  105, 80, 86, 66, 78, 88, 84, 103, 85, 98, 91,\n                                  106, 80, 86, 90, 89, 24, 65, 75, 107, 71, 97,\n                                  85, 109, 7, 4, 5, 65, 12, 68, 70, 82, 95, 83,\n                                  83, 84, 71, 80, 97, 91, 72, 100, 89, 83, 87,\n                                  98, 101, 0, 75, 68, 67, 3, 9, 66, 71, 84, 99,\n                                  73, 25, 25, 102, 9, 5, 5, 4, 4, 1, 69, 66, 1,\n                                  9, 5, 2, 0, 0, 65, 68, 5, 64, 17, 28, 26, 18,\n                                  11, 19, 12, 16, 15, 0, 17, 15, 24, 89, 16, 30,\n                                  27, 56, 62, 38, 48, 62, 62, 44, 60, 57, 62,\n                                  62, 47, 49, 37, 48, 62, 51, 62, 62, 62, 44,\n                                  38, 62, 44, 62, 12, 62, 62, 62, 62, 62, 62,\n                                  60, 58, 53, 49, 44, 37, 30, 24, 6, 75, 73, 81,\n                                  21, 22, 19, 22, 9, 10, 8, 22, 0, 69, 65, 79,\n                                  72, 110, 99, 1, 6, 10, 0, 70, 74, 78, 81, 107,\n                                  89, 26, 13, 6, 68, 68, 81, 92, 96, 106, 69,\n                                  25, 17, 12, 11, 0, 65, 66, 71, 80, 67, 35, 31,\n                                  26, 9, 10, 65, 73, 84, 10, 56, 50, 46, 35, 25,\n                                  3, 70, 69, 75, 62, 114, 111, 98, 111, 109, 95,\n                                  105, 101, 92, 102, 100, 103, 89, 92, 90, 101,\n                                  98, 85, 78, 79, 79, 76, 71, 66, 67, 2, 69, 69,\n                                  72, 65, 0, 68, 1, 1, 0, 1, 5, 0, 64, 1, 7, 65,\n                                  69, 73, 69, 66, 67, 17, 16, 18, 20, 16, 17,\n                                  14, 16, 15, 4, 12, 13, 67, 3, 59, 59, 56, 61,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 57, 36,\n                                  62, 62, 62, 62, 62, 62, 50, 43, 42, 33, 22,\n                                  14, 2, 71, 62, 62, 62, 62, 62, 62, 62, 62, 54,\n                                  51, 45, 43, 26, 17, 5, 9, 8, 4, 29, 29, 27,\n                                  25, 21, 23, 14, 11, 10, 3, 76, 65, 78, 89, 17,\n                                  3, 65, 82, 77, 71, 77, 70, 1, 71, 77, 65, 2,\n                                  3, 2, 5, 4, 3, 62, 58, 49, 41, 34, 24, 15, 64,\n                                  83, 68, 39, 28, 23, 13, 12, 4, 1, 64, 78, 79,\n                                  74, 68, 74, 65, 3, 68, 72, 0, 4, 6, 5, 9, 9,\n                                  4, 62, 58, 49, 41, 34, 24, 15, 64, 83 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 109, 89, 14, 10, 8, 25, 42,\n                                  53, 56, 20, 99, 66, 67, 70, 8, 8, 68, 3, 13,\n                                  30, 38, 26, 2, 85, 98, 91, 73, 67, 70, 8, 72,\n                                  81, 11, 15, 67, 78, 89, 3, 76, 85, 98, 7, 72,\n                                  81, 4, 79, 81, 91, 65, 76, 70, 84, 68, 2, 22,\n                                  0, 0, 0, 77, 88, 97, 67, 14, 0, 40, 8, 81,\n                                  102, 79, 85, 64, 76, 87, 82, 102, 84, 96, 90,\n                                  104, 80, 85, 89, 89, 24, 65, 74, 105, 71, 96,\n                                  85, 107, 7, 3, 4, 66, 12, 68, 69, 82, 94, 82,\n                                  83, 83, 71, 79, 95, 90, 71, 99, 88, 78, 83,\n                                  95, 98, 0, 74, 68, 67, 3, 9, 65, 71, 84, 97,\n                                  73, 23, 23, 99, 9, 6, 5, 4, 4, 1, 68, 65, 2,\n                                  8, 5, 2, 0, 0, 66, 68, 5, 65, 17, 27, 26, 17,\n                                  11, 19, 12, 16, 14, 0, 16, 14, 24, 89, 16, 29,\n                                  26, 54, 62, 37, 46, 62, 62, 42, 57, 55, 62,\n                                  62, 43, 47, 35, 45, 61, 48, 62, 62, 62, 41,\n                                  36, 58, 42, 62, 11, 62, 62, 62, 62, 62, 60,\n                                  58, 56, 51, 46, 42, 35, 28, 22, 4, 75, 73, 82,\n                                  20, 21, 18, 20, 8, 9, 7, 21, 64, 70, 66, 79,\n                                  73, 109, 97, 2, 7, 10, 1, 70, 74, 78, 80, 105,\n                                  87, 26, 14, 7, 68, 67, 80, 91, 95, 104, 69,\n                                  26, 18, 13, 11, 1, 64, 66, 70, 80, 67, 35, 31,\n                                  26, 8, 10, 65, 73, 84, 10, 55, 49, 45, 34, 25,\n                                  3, 69, 69, 75, 62, 112, 109, 97, 109, 108, 94,\n                                  104, 100, 91, 100, 99, 101, 88, 91, 90, 100,\n                                  96, 85, 78, 79, 79, 76, 71, 67, 67, 2, 69, 69,\n                                  73, 64, 0, 67, 1, 1, 0, 1, 5, 0, 64, 1, 7, 65,\n                                  69, 73, 69, 66, 68, 16, 16, 17, 20, 15, 16,\n                                  14, 15, 14, 4, 12, 12, 67, 2, 58, 58, 55, 59,\n                                  60, 62, 62, 62, 62, 62, 62, 62, 62, 55, 34,\n                                  62, 62, 62, 62, 62, 62, 48, 41, 39, 31, 20,\n                                  12, 1, 71, 62, 62, 62, 62, 62, 62, 62, 62, 52,\n                                  48, 43, 40, 24, 15, 4, 8, 8, 2, 28, 27, 26,\n                                  23, 19, 21, 13, 10, 9, 2, 77, 67, 79, 89, 16,\n                                  1, 67, 81, 77, 70, 76, 69, 2, 71, 76, 65, 2,\n                                  3, 2, 6, 4, 3, 62, 56, 46, 38, 30, 20, 11, 68,\n                                  86, 67, 39, 28, 23, 13, 12, 4, 1, 64, 77, 79,\n                                  74, 67, 74, 64, 4, 68, 72, 1, 5, 6, 5, 9, 9,\n                                  4, 62, 56, 46, 38, 30, 20, 11, 68, 86 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 107, 88, 15, 10, 8, 23, 40,\n                                  52, 56, 20, 98, 66, 66, 70, 8, 7, 67, 3, 12,\n                                  28, 36, 22, 64, 86, 96, 90, 73, 66, 70, 8, 73,\n                                  81, 11, 15, 67, 78, 89, 3, 76, 84, 97, 7, 71,\n                                  80, 4, 78, 81, 91, 65, 76, 70, 84, 68, 2, 22,\n                                  0, 0, 0, 76, 88, 97, 67, 14, 64, 40, 8, 81,\n                                  100, 78, 84, 0, 73, 85, 81, 100, 82, 95, 89,\n                                  102, 80, 85, 89, 89, 24, 65, 73, 102, 71, 95,\n                                  84, 105, 6, 3, 4, 66, 13, 68, 69, 81, 94, 82,\n                                  82, 82, 70, 78, 94, 88, 71, 98, 87, 73, 78,\n                                  92, 95, 0, 74, 68, 66, 3, 9, 65, 70, 83, 95,\n                                  72, 21, 21, 96, 9, 6, 5, 4, 5, 2, 66, 64, 2,\n                                  8, 5, 2, 1, 1, 67, 68, 5, 65, 16, 26, 25, 17,\n                                  10, 19, 12, 16, 12, 0, 15, 13, 23, 89, 16, 29,\n                                  26, 52, 62, 36, 44, 61, 62, 40, 55, 53, 62,\n                                  62, 40, 45, 34, 43, 57, 46, 62, 62, 62, 38,\n                                  34, 55, 40, 62, 9, 62, 62, 62, 62, 62, 58, 55,\n                                  54, 49, 44, 39, 33, 26, 21, 3, 75, 73, 82, 19,\n                                  20, 17, 19, 7, 8, 6, 19, 65, 70, 67, 80, 73,\n                                  109, 96, 3, 7, 10, 1, 69, 73, 77, 80, 103, 86,\n                                  27, 14, 7, 67, 66, 79, 89, 93, 102, 68, 26,\n                                  18, 13, 12, 2, 64, 66, 70, 79, 67, 36, 31, 25,\n                                  8, 10, 65, 73, 83, 9, 55, 49, 44, 33, 24, 3,\n                                  69, 69, 75, 62, 111, 108, 96, 108, 106, 93,\n                                  102, 98, 90, 99, 97, 99, 88, 90, 89, 99, 94,\n                                  84, 78, 79, 78, 75, 71, 67, 67, 1, 69, 69, 73,\n                                  64, 1, 66, 1, 1, 1, 2, 5, 1, 0, 1, 6, 65, 69,\n                                  73, 69, 65, 69, 15, 16, 16, 19, 14, 16, 14,\n                                  14, 14, 4, 11, 10, 68, 1, 56, 57, 54, 58, 58,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 52, 32, 62,\n                                  62, 62, 62, 62, 62, 45, 39, 37, 29, 18, 11, 0,\n                                  72, 62, 62, 62, 62, 62, 62, 60, 59, 49, 46,\n                                  40, 37, 22, 14, 2, 7, 7, 1, 26, 26, 24, 21,\n                                  18, 19, 11, 9, 7, 1, 78, 68, 80, 90, 14, 0,\n                                  68, 81, 76, 70, 76, 68, 3, 71, 76, 64, 3, 3,\n                                  3, 7, 4, 3, 62, 54, 44, 35, 27, 16, 7, 72, 89,\n                                  67, 39, 28, 23, 13, 13, 5, 1, 64, 77, 78, 73,\n                                  67, 73, 0, 5, 67, 71, 1, 5, 6, 5, 10, 9, 4,\n                                  62, 54, 44, 35, 27, 16, 7, 72, 89 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 106, 86, 15, 10, 7, 22, 38,\n                                  51, 56, 19, 96, 66, 66, 69, 8, 7, 67, 2, 10,\n                                  27, 33, 19, 66, 88, 93, 89, 73, 66, 69, 8, 73,\n                                  80, 11, 14, 67, 78, 88, 3, 76, 84, 97, 7, 71,\n                                  80, 4, 78, 80, 91, 65, 76, 70, 84, 68, 2, 22,\n                                  0, 0, 0, 76, 89, 97, 66, 13, 64, 39, 7, 81,\n                                  97, 77, 83, 2, 71, 84, 79, 98, 81, 94, 88,\n                                  100, 80, 85, 88, 89, 24, 65, 72, 100, 71, 95,\n                                  84, 103, 6, 2, 3, 67, 13, 68, 68, 81, 93, 81,\n                                  82, 81, 70, 78, 92, 87, 70, 97, 86, 68, 74,\n                                  89, 92, 0, 74, 68, 66, 3, 9, 64, 70, 83, 93,\n                                  72, 19, 19, 94, 9, 6, 5, 4, 5, 2, 65, 0, 2, 8,\n                                  5, 2, 1, 2, 68, 68, 5, 66, 16, 25, 25, 17, 10,\n                                  19, 12, 16, 11, 0, 14, 12, 23, 89, 15, 28, 25,\n                                  50, 62, 35, 42, 59, 60, 38, 52, 51, 62, 62,\n                                  36, 43, 32, 41, 54, 43, 58, 62, 62, 35, 32,\n                                  51, 38, 62, 7, 62, 62, 62, 62, 62, 56, 53, 52,\n                                  47, 42, 37, 31, 24, 19, 1, 75, 73, 83, 18, 19,\n                                  16, 18, 6, 6, 5, 17, 66, 71, 68, 81, 74, 108,\n                                  94, 4, 8, 10, 1, 68, 73, 77, 79, 101, 85, 27,\n                                  14, 8, 66, 65, 78, 88, 92, 101, 67, 27, 19,\n                                  14, 12, 3, 0, 66, 70, 79, 67, 36, 31, 24, 8,\n                                  10, 65, 73, 83, 9, 54, 48, 43, 32, 24, 3, 69,\n                                  69, 75, 62, 110, 106, 95, 106, 105, 92, 100,\n                                  96, 89, 97, 95, 97, 87, 89, 89, 98, 93, 84,\n                                  78, 79, 78, 75, 71, 67, 67, 1, 69, 69, 74, 0,\n                                  1, 65, 1, 1, 1, 2, 5, 1, 0, 1, 6, 65, 69, 73,\n                                  69, 65, 70, 14, 16, 15, 18, 13, 15, 14, 13,\n                                  13, 4, 11, 9, 68, 0, 55, 56, 53, 56, 56, 62,\n                                  61, 62, 62, 62, 62, 62, 61, 50, 30, 62, 62,\n                                  62, 62, 62, 59, 43, 36, 34, 27, 16, 9, 64, 73,\n                                  62, 62, 62, 62, 62, 62, 57, 56, 47, 43, 38,\n                                  34, 20, 12, 1, 6, 6, 64, 25, 24, 22, 19, 16,\n                                  17, 9, 8, 6, 0, 79, 69, 81, 91, 13, 64, 69,\n                                  81, 76, 69, 75, 67, 4, 71, 75, 64, 3, 3, 3, 8,\n                                  4, 3, 61, 52, 41, 32, 24, 12, 2, 76, 92, 67,\n                                  39, 28, 23, 13, 13, 5, 1, 64, 76, 78, 73, 66,\n                                  73, 0, 6, 67, 71, 1, 5, 6, 5, 10, 9, 4, 61,\n                                  52, 41, 32, 24, 12, 2, 76, 92 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 104, 85, 15, 10, 7, 21, 36,\n                                  50, 56, 19, 94, 66, 66, 68, 7, 6, 67, 1, 8,\n                                  26, 31, 15, 69, 90, 90, 88, 72, 66, 68, 7, 73,\n                                  79, 11, 14, 67, 77, 87, 3, 76, 84, 97, 7, 71,\n                                  80, 4, 78, 80, 90, 65, 76, 70, 84, 67, 2, 22,\n                                  0, 0, 0, 75, 89, 97, 66, 12, 64, 38, 7, 81,\n                                  95, 76, 82, 4, 69, 82, 78, 97, 79, 92, 87, 97,\n                                  80, 84, 88, 88, 24, 65, 71, 98, 71, 94, 83,\n                                  101, 6, 2, 3, 67, 13, 68, 68, 80, 92, 80, 81,\n                                  80, 69, 77, 91, 85, 69, 95, 85, 0, 70, 86, 89,\n                                  1, 73, 67, 65, 3, 9, 64, 70, 82, 91, 72, 17,\n                                  17, 91, 9, 7, 5, 4, 5, 3, 0, 1, 3, 7, 5, 2, 2,\n                                  2, 69, 67, 5, 66, 15, 24, 24, 16, 9, 19, 12,\n                                  16, 10, 1, 13, 12, 22, 89, 15, 27, 24, 48, 62,\n                                  34, 41, 57, 58, 36, 50, 49, 62, 62, 33, 41,\n                                  30, 38, 51, 41, 55, 62, 62, 33, 30, 48, 36,\n                                  62, 6, 62, 62, 62, 61, 60, 54, 51, 50, 45, 39,\n                                  35, 29, 23, 17, 64, 75, 73, 83, 17, 18, 15,\n                                  16, 5, 5, 4, 16, 67, 71, 69, 81, 75, 107, 93,\n                                  5, 8, 10, 2, 68, 72, 76, 78, 99, 83, 27, 15,\n                                  8, 66, 64, 77, 86, 90, 99, 67, 28, 20, 15, 13,\n                                  4, 0, 65, 69, 78, 67, 37, 31, 24, 7, 10, 65,\n                                  73, 82, 9, 54, 47, 42, 31, 24, 3, 68, 69, 74,\n                                  62, 108, 105, 93, 104, 103, 91, 99, 95, 88,\n                                  95, 94, 95, 86, 88, 88, 97, 91, 84, 78, 78,\n                                  77, 74, 71, 68, 67, 0, 69, 69, 74, 0, 1, 64,\n                                  1, 1, 1, 2, 5, 1, 0, 1, 5, 65, 69, 73, 69, 64,\n                                  71, 13, 16, 14, 18, 13, 14, 14, 13, 12, 4, 11,\n                                  8, 68, 64, 54, 55, 52, 54, 54, 62, 59, 61, 62,\n                                  59, 62, 62, 58, 47, 28, 62, 62, 62, 62, 59,\n                                  56, 40, 34, 32, 25, 15, 8, 64, 73, 62, 62, 62,\n                                  62, 59, 59, 55, 53, 45, 41, 36, 31, 18, 10,\n                                  64, 6, 6, 66, 24, 23, 21, 17, 14, 15, 8, 7, 4,\n                                  64, 79, 71, 82, 91, 11, 66, 71, 80, 76, 68,\n                                  75, 66, 5, 70, 74, 0, 4, 3, 4, 9, 4, 3, 60,\n                                  50, 38, 29, 20, 8, 65, 80, 95, 66, 39, 28, 23,\n                                  13, 14, 5, 2, 0, 76, 78, 73, 66, 73, 1, 7, 67,\n                                  71, 2, 6, 6, 6, 11, 9, 4, 60, 50, 38, 29, 20,\n                                  8, 65, 80, 95 },\n\n                                {\n\n                                61,\n                                  8, 76, 61, 8, 76, 102, 83, 16, 10, 6, 19, 34,\n                                  49, 56, 19, 92, 66, 65, 67, 7, 6, 67, 1, 7,\n                                  25, 28, 12, 71, 91, 87, 87, 72, 65, 67, 7, 74,\n                                  78, 11, 13, 67, 77, 87, 3, 76, 84, 97, 7, 71,\n                                  79, 4, 78, 79, 90, 65, 76, 70, 84, 67, 2, 22,\n                                  0, 0, 0, 75, 89, 97, 65, 11, 64, 37, 6, 81,\n                                  92, 75, 81, 5, 67, 81, 76, 95, 78, 91, 86, 95,\n                                  80, 84, 87, 88, 24, 65, 70, 96, 71, 93, 83,\n                                  99, 6, 1, 2, 68, 13, 68, 67, 80, 91, 79, 81,\n                                  79, 69, 76, 89, 84, 69, 94, 84, 5, 65, 83, 86,\n                                  1, 73, 67, 65, 3, 9, 0, 69, 82, 89, 72, 15,\n                                  15, 88, 9, 7, 5, 4, 5, 3, 1, 2, 3, 7, 5, 2, 2,\n                                  3, 70, 67, 5, 67, 15, 23, 24, 16, 9, 19, 12,\n                                  16, 9, 1, 12, 11, 22, 89, 15, 27, 24, 46, 61,\n                                  33, 39, 55, 55, 34, 47, 47, 62, 62, 29, 39,\n                                  28, 36, 48, 38, 52, 61, 62, 30, 28, 44, 34,\n                                  62, 4, 60, 62, 60, 58, 57, 52, 49, 48, 43, 37,\n                                  33, 27, 21, 16, 66, 75, 73, 84, 16, 17, 14,\n                                  15, 4, 4, 3, 14, 68, 72, 70, 82, 75, 107, 91,\n                                  6, 9, 10, 2, 67, 72, 76, 78, 97, 82, 27, 15,\n                                  9, 65, 0, 76, 85, 89, 97, 66, 28, 20, 15, 13,\n                                  5, 1, 65, 69, 78, 67, 37, 31, 23, 7, 10, 65,\n                                  73, 82, 9, 53, 47, 41, 30, 24, 3, 68, 69, 74,\n                                  62, 107, 103, 92, 103, 102, 90, 97, 93, 87,\n                                  94, 92, 93, 86, 87, 88, 96, 89, 83, 78, 78,\n                                  77, 74, 71, 68, 67, 0, 69, 69, 75, 1, 2, 0, 1,\n                                  1, 2, 2, 5, 1, 0, 1, 5, 65, 69, 73, 69, 64,\n                                  72, 12, 16, 13, 17, 12, 14, 14, 12, 11, 4, 11,\n                                  7, 68, 65, 53, 54, 51, 53, 52, 60, 57, 59, 59,\n                                  57, 62, 60, 55, 45, 26, 62, 62, 62, 62, 55,\n                                  53, 38, 32, 29, 23, 13, 6, 65, 74, 62, 62, 62,\n                                  60, 56, 57, 52, 50, 42, 38, 33, 28, 16, 8, 65,\n                                  5, 5, 67, 22, 21, 19, 15, 13, 13, 6, 6, 3, 65,\n                                  80, 72, 83, 92, 10, 67, 72, 80, 75, 68, 74,\n                                  65, 6, 70, 74, 0, 4, 3, 4, 10, 4, 3, 59, 48,\n                                  36, 26, 17, 4, 69, 84, 98, 66, 39, 28, 23, 13,\n                                  14, 6, 2, 0, 75, 78, 73, 65, 72, 2, 8, 67, 70,\n                                  2, 6, 6, 6, 11, 9, 4, 59, 48, 36, 26, 17, 4,\n                                  69, 84, 98 },\n\n                                {\n\n                                60,\n                                  8, 76, 60, 8, 76, 100, 82, 16, 10, 6, 18, 32,\n                                  48, 56, 19, 90, 66, 65, 66, 7, 5, 67, 0, 5,\n                                  24, 26, 8, 74, 93, 84, 86, 72, 65, 66, 7, 74,\n                                  77, 11, 13, 67, 77, 86, 3, 76, 84, 97, 7, 71,\n                                  79, 4, 78, 79, 90, 65, 76, 70, 84, 67, 2, 22,\n                                  0, 0, 0, 74, 89, 97, 65, 10, 64, 36, 6, 81,\n                                  90, 74, 80, 7, 65, 79, 75, 93, 76, 90, 85, 93,\n                                  80, 84, 87, 88, 24, 65, 69, 94, 71, 92, 82,\n                                  97, 6, 1, 2, 68, 13, 68, 67, 79, 90, 78, 80,\n                                  78, 68, 75, 88, 82, 68, 93, 83, 10, 2, 80, 83,\n                                  1, 73, 67, 64, 3, 9, 0, 69, 81, 87, 72, 13,\n                                  13, 85, 9, 7, 5, 4, 5, 4, 3, 3, 3, 7, 5, 2, 3,\n                                  4, 71, 67, 5, 67, 14, 22, 23, 16, 8, 19, 12,\n                                  16, 8, 1, 11, 10, 21, 89, 15, 26, 23, 44, 58,\n                                  32, 37, 53, 53, 32, 45, 45, 62, 62, 26, 37,\n                                  26, 34, 45, 36, 49, 57, 62, 27, 26, 41, 32,\n                                  62, 2, 58, 62, 58, 56, 55, 50, 47, 46, 41, 35,\n                                  31, 25, 19, 14, 68, 75, 73, 84, 15, 16, 13,\n                                  14, 3, 3, 2, 12, 69, 72, 71, 83, 76, 106, 90,\n                                  7, 9, 10, 2, 66, 71, 75, 77, 95, 81, 27, 15,\n                                  9, 64, 1, 75, 83, 87, 95, 65, 29, 21, 16, 14,\n                                  6, 1, 65, 69, 77, 67, 38, 31, 22, 7, 10, 65,\n                                  73, 81, 9, 53, 46, 40, 29, 24, 3, 68, 69, 74,\n                                  62, 106, 102, 91, 101, 100, 89, 95, 91, 86,\n                                  92, 90, 91, 85, 86, 87, 95, 87, 83, 78, 78,\n                                  76, 73, 71, 68, 67, 64, 69, 69, 75, 1, 2, 1,\n                                  1, 1, 2, 2, 5, 1, 0, 1, 4, 65, 69, 73, 69, 0,\n                                  73, 11, 16, 12, 16, 11, 13, 14, 11, 10, 4, 11,\n                                  6, 68, 66, 52, 53, 50, 51, 50, 58, 55, 57, 57,\n                                  54, 61, 57, 52, 42, 24, 62, 62, 62, 62, 52,\n                                  50, 35, 30, 27, 21, 11, 5, 66, 75, 62, 62, 62,\n                                  58, 53, 54, 50, 47, 40, 36, 31, 25, 14, 6, 67,\n                                  4, 4, 69, 21, 20, 17, 13, 11, 11, 4, 5, 1, 66,\n                                  81, 73, 84, 93, 8, 68, 73, 80, 75, 67, 74, 64,\n                                  7, 70, 73, 1, 5, 3, 5, 11, 4, 3, 58, 46, 33,\n                                  23, 14, 0, 73, 88, 101, 66, 39, 28, 23, 13,\n                                  15, 6, 2, 0, 75, 78, 73, 65, 72, 3, 9, 67, 70,\n                                  2, 6, 6, 6, 12, 9, 4, 58, 46, 33, 23, 14, 0,\n                                  73, 88, 101 },\n\n                                {\n\n                                58,\n                                  7, 77, 58, 7, 77, 99, 81, 16, 10, 5, 16, 29,\n                                  47, 56, 18, 89, 67, 65, 66, 6, 4, 67, 64, 3,\n                                  22, 23, 4, 77, 95, 82, 86, 72, 65, 66, 6, 75,\n                                  77, 11, 12, 67, 77, 86, 2, 77, 84, 97, 6, 71,\n                                  79, 4, 78, 79, 90, 65, 76, 71, 84, 67, 2, 22,\n                                  0, 0, 0, 74, 90, 97, 65, 9, 65, 35, 5, 82, 88,\n                                  73, 79, 8, 0, 78, 74, 92, 75, 89, 84, 91, 80,\n                                  84, 87, 88, 24, 65, 69, 92, 71, 92, 82, 96, 5,\n                                  0, 1, 69, 13, 68, 67, 79, 90, 78, 80, 78, 68,\n                                  75, 87, 81, 68, 92, 82, 14, 6, 77, 81, 1, 73,\n                                  67, 64, 2, 9, 0, 69, 81, 85, 72, 11, 11, 83,\n                                  9, 7, 5, 4, 5, 4, 4, 3, 3, 6, 4, 2, 3, 4, 73,\n                                  67, 5, 68, 13, 20, 22, 15, 7, 19, 12, 15, 6,\n                                  1, 10, 9, 20, 89, 14, 25, 22, 41, 54, 30, 35,\n                                  50, 50, 29, 42, 43, 55, 62, 22, 34, 24, 31,\n                                  41, 33, 45, 52, 59, 24, 24, 37, 30, 62, 0, 55,\n                                  59, 55, 53, 52, 47, 44, 43, 39, 32, 28, 23,\n                                  17, 12, 70, 75, 74, 85, 14, 14, 11, 12, 1, 1,\n                                  0, 10, 70, 73, 72, 84, 77, 106, 89, 7, 9, 10,\n                                  2, 66, 71, 75, 77, 93, 80, 27, 15, 9, 64, 1,\n                                  74, 82, 86, 94, 65, 29, 21, 16, 14, 7, 1, 65,\n                                  69, 77, 68, 38, 30, 21, 6, 10, 65, 73, 81, 8,\n                                  52, 45, 38, 28, 23, 3, 68, 69, 74, 62, 105,\n                                  101, 90, 100, 99, 88, 94, 90, 85, 91, 89, 89,\n                                  85, 86, 87, 94, 86, 83, 78, 78, 76, 73, 71,\n                                  69, 68, 65, 69, 70, 76, 1, 2, 2, 1, 0, 2, 2,\n                                  4, 1, 0, 1, 3, 65, 69, 73, 69, 0, 74, 10, 16,\n                                  10, 15, 10, 12, 13, 10, 9, 4, 10, 4, 69, 68,\n                                  50, 51, 49, 49, 48, 55, 52, 54, 54, 51, 58,\n                                  54, 48, 39, 22, 62, 62, 61, 60, 48, 46, 32,\n                                  27, 24, 19, 9, 3, 67, 76, 59, 60, 60, 55, 50,\n                                  51, 47, 43, 37, 33, 28, 22, 12, 4, 69, 3, 3,\n                                  71, 19, 18, 15, 10, 9, 9, 2, 3, 64, 68, 82,\n                                  75, 85, 94, 6, 70, 75, 80, 75, 67, 74, 0, 8,\n                                  70, 73, 1, 5, 3, 5, 11, 4, 2, 56, 44, 30, 19,\n                                  10, 67, 78, 93, 104, 66, 39, 28, 23, 13, 15,\n                                  6, 2, 0, 75, 78, 73, 65, 72, 3, 9, 67, 70, 2,\n                                  6, 6, 6, 12, 8, 3, 56, 44, 30, 19, 10, 67, 78,\n                                  93, 104 },\n\n                                {\n\n                                57,\n                                  7, 77, 57, 7, 77, 97, 79, 17, 11, 5, 15, 27,\n                                  46, 57, 18, 87, 67, 64, 65, 6, 4, 66, 64, 2,\n                                  21, 21, 1, 79, 96, 79, 85, 71, 64, 65, 6, 75,\n                                  76, 11, 12, 66, 76, 85, 2, 77, 83, 96, 6, 70,\n                                  78, 4, 77, 78, 89, 64, 75, 71, 83, 66, 2, 22,\n                                  0, 0, 0, 73, 90, 97, 64, 9, 65, 35, 5, 82, 85,\n                                  71, 77, 10, 3, 76, 72, 90, 73, 87, 82, 88, 80,\n                                  83, 86, 87, 24, 65, 68, 89, 70, 91, 81, 94, 5,\n                                  0, 1, 69, 14, 68, 66, 78, 89, 77, 79, 77, 67,\n                                  74, 85, 79, 67, 90, 80, 19, 11, 73, 78, 2, 72,\n                                  66, 0, 2, 10, 1, 68, 80, 82, 71, 9, 10, 80, 9,\n                                  8, 5, 5, 6, 5, 6, 4, 4, 6, 4, 2, 4, 5, 74, 66,\n                                  5, 68, 13, 19, 22, 15, 7, 19, 12, 15, 5, 2,\n                                  10, 9, 20, 89, 14, 25, 22, 39, 51, 29, 34, 48,\n                                  48, 27, 40, 41, 49, 62, 19, 32, 23, 29, 38,\n                                  31, 42, 48, 55, 22, 22, 34, 28, 62, 64, 53,\n                                  57, 53, 51, 50, 45, 42, 41, 37, 30, 26, 22,\n                                  16, 11, 71, 75, 74, 85, 14, 13, 10, 11, 0, 0,\n                                  64, 9, 71, 73, 73, 84, 77, 105, 87, 8, 10, 10,\n                                  3, 65, 70, 74, 76, 90, 78, 28, 16, 10, 0, 2,\n                                  72, 80, 84, 92, 64, 30, 22, 17, 15, 8, 2, 64,\n                                  68, 76, 68, 39, 30, 21, 6, 11, 64, 73, 80, 8,\n                                  52, 45, 37, 27, 23, 4, 67, 68, 73, 62, 103,\n                                  99, 88, 98, 97, 86, 92, 88, 83, 89, 87, 86,\n                                  84, 85, 86, 92, 84, 82, 77, 77, 75, 72, 70,\n                                  69, 68, 65, 69, 70, 76, 2, 3, 3, 2, 0, 3, 3,\n                                  4, 2, 1, 1, 3, 64, 68, 72, 68, 1, 74, 9, 16,\n                                  9, 15, 10, 12, 13, 10, 9, 4, 10, 3, 69, 69,\n                                  49, 50, 49, 48, 47, 53, 50, 52, 52, 49, 56,\n                                  52, 45, 37, 20, 61, 60, 57, 56, 45, 43, 30,\n                                  25, 22, 18, 8, 2, 67, 76, 57, 58, 58, 53, 48,\n                                  49, 45, 40, 35, 31, 26, 20, 11, 3, 70, 3, 3,\n                                  72, 18, 17, 14, 8, 8, 8, 1, 2, 65, 69, 82, 76,\n                                  85, 94, 5, 71, 76, 79, 74, 66, 73, 2, 10, 69,\n                                  72, 2, 6, 4, 6, 12, 4, 2, 55, 42, 28, 16, 7,\n                                  71, 82, 97, 106, 65, 39, 29, 24, 14, 16, 7, 3,\n                                  1, 74, 77, 72, 64, 71, 4, 10, 66, 69, 3, 7, 6,\n                                  7, 13, 8, 3, 55, 42, 28, 16, 7, 71, 82, 97,\n                                  106 },\n\n                                {\n\n                                56,\n                                  7, 77, 56, 7, 77, 95, 78, 17, 11, 5, 14, 25,\n                                  45, 57, 18, 85, 67, 64, 64, 6, 3, 66, 65, 0,\n                                  20, 18, 66, 82, 98, 76, 84, 71, 64, 64, 6, 75,\n                                  75, 11, 11, 66, 76, 84, 2, 77, 83, 96, 6, 70,\n                                  78, 4, 77, 78, 89, 64, 75, 71, 83, 66, 2, 22,\n                                  0, 0, 0, 72, 90, 97, 64, 8, 65, 34, 5, 82, 83,\n                                  70, 76, 12, 5, 75, 71, 88, 72, 86, 81, 86, 80,\n                                  83, 86, 87, 24, 65, 67, 87, 70, 90, 80, 92, 5,\n                                  0, 1, 70, 14, 68, 66, 77, 88, 76, 78, 76, 67,\n                                  73, 84, 78, 66, 89, 79, 24, 15, 70, 75, 2, 72,\n                                  66, 0, 2, 10, 1, 68, 80, 80, 71, 7, 8, 77, 9,\n                                  8, 5, 5, 6, 5, 8, 5, 4, 6, 4, 2, 5, 6, 75, 66,\n                                  5, 68, 12, 18, 21, 15, 6, 19, 12, 15, 4, 2, 9,\n                                  8, 19, 89, 14, 24, 21, 37, 48, 28, 32, 46, 46,\n                                  25, 38, 39, 43, 62, 15, 30, 21, 27, 35, 29,\n                                  39, 44, 51, 19, 20, 31, 26, 62, 66, 51, 55,\n                                  51, 49, 48, 43, 40, 39, 35, 28, 24, 20, 14, 9,\n                                  73, 75, 74, 86, 13, 12, 9, 10, 64, 64, 65, 7,\n                                  72, 73, 74, 85, 78, 104, 86, 9, 10, 10, 3, 64,\n                                  69, 73, 75, 88, 77, 28, 16, 10, 1, 3, 71, 78,\n                                  82, 90, 0, 31, 23, 18, 16, 9, 2, 64, 68, 75,\n                                  68, 40, 30, 20, 6, 11, 64, 73, 80, 8, 52, 44,\n                                  36, 26, 23, 4, 67, 68, 73, 62, 102, 98, 87,\n                                  96, 95, 85, 90, 86, 82, 87, 85, 84, 83, 84,\n                                  86, 91, 82, 82, 77, 77, 74, 72, 70, 69, 68,\n                                  66, 69, 70, 76, 2, 3, 4, 2, 0, 3, 3, 4, 2, 1,\n                                  1, 2, 64, 68, 72, 68, 2, 75, 8, 16, 8, 14, 9,\n                                  11, 13, 9, 8, 4, 10, 2, 69, 70, 48, 49, 48,\n                                  46, 45, 51, 48, 50, 50, 46, 53, 49, 42, 34,\n                                  18, 57, 56, 53, 51, 42, 40, 27, 23, 19, 16, 6,\n                                  1, 68, 77, 55, 56, 55, 51, 45, 46, 42, 37, 33,\n                                  28, 24, 17, 9, 1, 72, 2, 2, 74, 17, 16, 12, 6,\n                                  6, 6, 64, 1, 67, 70, 83, 77, 86, 95, 3, 72,\n                                  77, 79, 74, 65, 73, 3, 11, 69, 71, 3, 7, 4, 6,\n                                  13, 4, 2, 54, 40, 25, 13, 4, 75, 86, 101, 109,\n                                  65, 39, 29, 24, 14, 17, 7, 3, 1, 74, 77, 72,\n                                  64, 71, 5, 11, 66, 69, 3, 7, 6, 7, 14, 8, 3,\n                                  54, 40, 25, 13, 4, 75, 86, 101, 109 },\n\n                                {\n\n                                55,\n                                  7, 77, 55, 7, 77, 93, 76, 18, 11, 4, 12, 23,\n                                  44, 57, 18, 83, 67, 0, 0, 6, 3, 66, 65, 64,\n                                  19, 16, 69, 84, 99, 73, 83, 71, 0, 0, 6, 76,\n                                  74, 11, 11, 66, 76, 84, 2, 77, 83, 96, 6, 70,\n                                  77, 4, 77, 77, 89, 64, 75, 71, 83, 66, 2, 22,\n                                  0, 0, 0, 72, 90, 97, 0, 7, 65, 33, 4, 82, 80,\n                                  69, 75, 13, 7, 73, 69, 86, 70, 85, 80, 84, 80,\n                                  83, 85, 87, 24, 65, 66, 85, 70, 89, 80, 90, 5,\n                                  64, 0, 70, 14, 68, 65, 77, 87, 75, 78, 75, 66,\n                                  72, 82, 76, 66, 88, 78, 29, 20, 67, 72, 2, 72,\n                                  66, 1, 2, 10, 2, 67, 79, 78, 71, 5, 6, 74, 9,\n                                  8, 5, 5, 6, 6, 9, 6, 4, 6, 4, 2, 5, 7, 76, 66,\n                                  5, 69, 12, 17, 21, 15, 6, 19, 12, 15, 3, 2, 8,\n                                  7, 19, 89, 14, 24, 21, 35, 45, 27, 30, 44, 43,\n                                  23, 35, 37, 36, 62, 12, 28, 19, 25, 32, 26,\n                                  36, 40, 47, 16, 18, 27, 24, 62, 68, 49, 53,\n                                  49, 46, 45, 41, 38, 37, 33, 26, 22, 18, 12, 8,\n                                  75, 75, 74, 86, 12, 11, 8, 9, 65, 65, 66, 5,\n                                  73, 74, 75, 86, 78, 104, 84, 10, 11, 10, 3, 0,\n                                  69, 73, 75, 86, 76, 28, 16, 11, 2, 4, 70, 77,\n                                  81, 88, 1, 31, 23, 18, 16, 10, 3, 64, 68, 75,\n                                  68, 40, 30, 19, 6, 11, 64, 73, 79, 8, 51, 44,\n                                  35, 25, 23, 4, 67, 68, 73, 62, 101, 96, 86,\n                                  95, 94, 84, 88, 84, 81, 86, 83, 82, 83, 83,\n                                  85, 90, 80, 81, 77, 77, 74, 71, 70, 69, 68,\n                                  66, 69, 70, 77, 3, 4, 5, 2, 0, 4, 3, 4, 2, 1,\n                                  1, 2, 64, 68, 72, 68, 2, 76, 7, 16, 7, 13, 8,\n                                  11, 13, 8, 7, 4, 10, 1, 69, 71, 47, 48, 47,\n                                  45, 43, 49, 46, 48, 47, 44, 50, 46, 39, 32,\n                                  16, 53, 52, 49, 46, 38, 37, 25, 21, 17, 14, 4,\n                                  64, 69, 78, 53, 53, 53, 48, 42, 44, 40, 34,\n                                  30, 26, 21, 14, 7, 64, 73, 1, 1, 75, 15, 14,\n                                  10, 4, 5, 4, 66, 0, 68, 71, 84, 78, 87, 96, 2,\n                                  73, 78, 79, 73, 65, 72, 4, 12, 69, 71, 3, 7,\n                                  4, 7, 14, 4, 2, 53, 38, 23, 10, 1, 79, 90,\n                                  105, 112, 65, 39, 29, 24, 14, 17, 8, 3, 1, 73,\n                                  77, 72, 0, 70, 6, 12, 66, 68, 3, 7, 6, 7, 14,\n                                  8, 3, 53, 38, 23, 10, 1, 79, 90, 105, 112 },\n\n                                {\n\n                                53,\n                                  7, 77, 53, 7, 77, 92, 75, 18, 11, 4, 11, 21,\n                                  43, 57, 17, 81, 67, 0, 1, 5, 2, 66, 66, 66,\n                                  18, 13, 73, 87, 101, 70, 82, 71, 0, 1, 5, 76,\n                                  73, 11, 10, 66, 75, 83, 2, 77, 83, 96, 6, 70,\n                                  77, 4, 77, 77, 88, 64, 75, 71, 83, 65, 2, 22,\n                                  0, 0, 0, 71, 91, 97, 0, 6, 65, 32, 4, 82, 78,\n                                  68, 74, 15, 9, 72, 68, 85, 69, 83, 79, 82, 80,\n                                  82, 85, 87, 24, 65, 65, 83, 70, 89, 79, 88, 5,\n                                  64, 0, 71, 14, 68, 65, 76, 86, 74, 77, 74, 66,\n                                  72, 81, 75, 65, 87, 77, 34, 24, 64, 69, 2, 71,\n                                  66, 1, 2, 10, 2, 67, 79, 76, 71, 3, 4, 72, 9,\n                                  9, 5, 5, 6, 6, 11, 7, 5, 5, 4, 2, 6, 7, 77,\n                                  66, 5, 69, 11, 16, 20, 14, 5, 19, 12, 15, 2,\n                                  2, 7, 6, 18, 89, 13, 23, 20, 33, 41, 26, 28,\n                                  42, 41, 21, 33, 35, 30, 62, 8, 26, 17, 22, 29,\n                                  24, 32, 35, 43, 13, 16, 24, 22, 62, 69, 47,\n                                  51, 46, 44, 43, 39, 36, 35, 31, 23, 20, 16,\n                                  10, 6, 77, 75, 74, 87, 11, 10, 7, 7, 66, 67,\n                                  67, 4, 74, 74, 76, 86, 79, 103, 83, 11, 11,\n                                  10, 4, 0, 68, 72, 74, 84, 74, 28, 17, 11, 2,\n                                  5, 69, 75, 79, 87, 1, 32, 24, 19, 17, 11, 3,\n                                  64, 67, 74, 68, 41, 30, 19, 5, 11, 64, 73, 79,\n                                  8, 51, 43, 34, 24, 23, 4, 66, 68, 73, 62, 99,\n                                  95, 85, 93, 92, 83, 87, 83, 80, 84, 82, 80,\n                                  82, 82, 85, 89, 79, 81, 77, 77, 73, 71, 70,\n                                  70, 68, 67, 69, 70, 77, 3, 4, 6, 2, 0, 4, 3,\n                                  4, 2, 1, 1, 1, 64, 68, 72, 68, 3, 77, 6, 16,\n                                  6, 13, 7, 10, 13, 7, 6, 4, 10, 0, 69, 72, 46,\n                                  47, 46, 43, 41, 47, 44, 45, 45, 41, 47, 43,\n                                  36, 29, 14, 48, 48, 45, 41, 35, 33, 22, 18,\n                                  14, 12, 2, 65, 70, 78, 50, 51, 50, 46, 39, 41,\n                                  37, 31, 28, 23, 19, 11, 5, 66, 75, 0, 1, 77,\n                                  14, 13, 9, 2, 3, 2, 67, 64, 70, 72, 85, 80,\n                                  88, 96, 0, 75, 80, 78, 73, 64, 72, 5, 13, 69,\n                                  70, 4, 8, 4, 7, 15, 4, 2, 52, 36, 20, 7, 66,\n                                  83, 95, 109, 115, 64, 39, 29, 24, 14, 18, 8,\n                                  3, 1, 73, 77, 72, 0, 70, 6, 13, 66, 68, 4, 8,\n                                  6, 7, 15, 8, 3, 52, 36, 20, 7, 66, 83, 95,\n                                  109, 115 },\n\n                                {\n\n                                52,\n                                  7, 77, 52, 7, 77, 90, 73, 18, 11, 3, 10, 19,\n                                  42, 57, 17, 79, 67, 0, 2, 5, 2, 66, 67, 68,\n                                  17, 11, 76, 89, 103, 67, 81, 70, 0, 2, 5, 76,\n                                  72, 11, 10, 66, 75, 82, 2, 77, 83, 96, 6, 70,\n                                  77, 4, 77, 76, 88, 64, 75, 71, 83, 65, 2, 22,\n                                  0, 0, 0, 71, 91, 97, 1, 5, 65, 31, 3, 82, 75,\n                                  67, 73, 17, 11, 70, 66, 83, 67, 82, 78, 79,\n                                  80, 82, 84, 86, 24, 65, 64, 81, 70, 88, 79,\n                                  86, 5, 65, 64, 71, 14, 68, 64, 76, 85, 73, 77,\n                                  73, 65, 71, 79, 73, 64, 85, 76, 39, 28, 2, 66,\n                                  3, 71, 65, 2, 2, 10, 3, 67, 78, 74, 71, 1, 2,\n                                  69, 9, 9, 5, 5, 6, 7, 12, 8, 5, 5, 4, 2, 6, 8,\n                                  78, 65, 5, 70, 11, 15, 20, 14, 5, 19, 12, 15,\n                                  1, 3, 6, 6, 18, 89, 13, 22, 19, 31, 38, 25,\n                                  27, 40, 39, 19, 30, 33, 24, 62, 5, 24, 15, 20,\n                                  26, 21, 29, 31, 39, 11, 14, 20, 20, 62, 71,\n                                  45, 49, 44, 42, 41, 37, 34, 33, 29, 21, 18,\n                                  14, 9, 4, 79, 75, 74, 87, 10, 9, 6, 6, 67, 68,\n                                  68, 2, 75, 75, 77, 87, 80, 102, 81, 12, 12,\n                                  10, 4, 1, 68, 72, 73, 82, 73, 28, 17, 12, 3,\n                                  6, 68, 74, 78, 85, 2, 33, 25, 20, 17, 12, 4,\n                                  0, 67, 74, 68, 41, 30, 18, 5, 11, 64, 73, 78,\n                                  8, 50, 42, 33, 23, 23, 4, 66, 68, 72, 62, 98,\n                                  93, 83, 91, 91, 82, 85, 81, 79, 82, 80, 78,\n                                  81, 81, 84, 88, 77, 81, 77, 76, 73, 70, 70,\n                                  70, 68, 67, 69, 70, 78, 4, 4, 7, 2, 0, 4, 3,\n                                  4, 2, 1, 1, 1, 64, 68, 72, 68, 3, 78, 5, 16,\n                                  5, 12, 7, 9, 13, 7, 5, 4, 10, 64, 69, 73, 45,\n                                  46, 45, 41, 39, 45, 42, 43, 42, 38, 44, 40,\n                                  33, 27, 12, 44, 44, 41, 36, 32, 30, 20, 16,\n                                  12, 10, 1, 67, 70, 79, 48, 48, 48, 44, 36, 38,\n                                  35, 28, 26, 21, 17, 8, 3, 68, 76, 0, 0, 79,\n                                  13, 11, 7, 0, 1, 0, 69, 65, 71, 73, 85, 81,\n                                  89, 97, 64, 76, 81, 78, 73, 0, 71, 6, 14, 68,\n                                  69, 4, 8, 4, 8, 16, 4, 2, 51, 34, 17, 4, 69,\n                                  87, 99, 113, 118, 64, 39, 29, 24, 14, 18, 8,\n                                  4, 2, 72, 77, 72, 1, 70, 7, 14, 66, 68, 4, 8,\n                                  6, 8, 15, 8, 3, 51, 34, 17, 4, 69, 87, 99,\n                                  113, 118 },\n\n                                {\n\n                                51,\n                                  7, 78, 51, 7, 78, 88, 72, 19, 11, 3, 8, 17,\n                                  41, 57, 17, 78, 67, 1, 2, 5, 1, 65, 67, 69,\n                                  15, 8, 80, 92, 104, 65, 80, 70, 1, 2, 5, 77,\n                                  72, 11, 9, 66, 75, 82, 2, 77, 82, 95, 6, 69,\n                                  76, 4, 76, 76, 88, 64, 75, 71, 83, 65, 2, 22,\n                                  0, 0, 0, 70, 91, 97, 1, 5, 66, 31, 3, 82, 73,\n                                  66, 72, 18, 14, 69, 65, 81, 66, 81, 77, 77,\n                                  80, 82, 84, 86, 24, 65, 0, 78, 70, 87, 78, 84,\n                                  4, 65, 64, 72, 15, 68, 64, 75, 85, 73, 76, 72,\n                                  65, 70, 78, 72, 64, 84, 75, 44, 33, 5, 0, 3,\n                                  71, 65, 2, 2, 10, 3, 66, 78, 72, 70, 64, 0,\n                                  66, 9, 9, 5, 5, 7, 7, 14, 9, 5, 5, 4, 2, 7, 9,\n                                  79, 65, 5, 70, 10, 14, 19, 14, 4, 19, 12, 15,\n                                  64, 3, 5, 5, 17, 89, 13, 22, 19, 29, 35, 24,\n                                  25, 37, 36, 17, 28, 31, 17, 62, 1, 22, 14, 18,\n                                  22, 19, 26, 27, 34, 8, 12, 17, 18, 62, 73, 43,\n                                  47, 42, 39, 38, 35, 31, 31, 27, 19, 15, 12, 7,\n                                  3, 80, 75, 74, 88, 9, 8, 5, 5, 68, 69, 69, 0,\n                                  76, 75, 78, 88, 80, 102, 80, 13, 12, 10, 4, 2,\n                                  67, 71, 73, 80, 72, 29, 17, 12, 4, 7, 67, 72,\n                                  76, 83, 3, 33, 25, 20, 18, 13, 4, 0, 67, 73,\n                                  68, 42, 30, 17, 5, 11, 64, 73, 78, 7, 50, 42,\n                                  32, 22, 22, 4, 66, 68, 72, 62, 97, 92, 82, 90,\n                                  89, 81, 83, 79, 78, 81, 78, 76, 81, 80, 84,\n                                  87, 75, 80, 77, 76, 72, 70, 70, 70, 68, 68,\n                                  69, 70, 78, 4, 5, 8, 2, 0, 5, 4, 4, 3, 2, 1,\n                                  0, 64, 68, 72, 68, 4, 79, 4, 16, 4, 11, 6, 9,\n                                  13, 6, 5, 4, 9, 66, 70, 74, 43, 45, 44, 40,\n                                  37, 43, 40, 41, 40, 36, 41, 38, 30, 24, 10,\n                                  40, 40, 37, 32, 28, 27, 17, 14, 9, 8, 64, 68,\n                                  71, 80, 46, 46, 45, 41, 33, 36, 32, 25, 23,\n                                  18, 14, 5, 1, 69, 78, 64, 64, 80, 11, 10, 5,\n                                  65, 0, 65, 71, 66, 73, 74, 86, 82, 90, 98, 66,\n                                  77, 82, 78, 72, 0, 71, 7, 15, 68, 69, 5, 9, 4,\n                                  8, 17, 4, 2, 50, 32, 15, 1, 72, 91, 103, 117,\n                                  121, 64, 39, 29, 24, 14, 19, 9, 4, 2, 72, 76,\n                                  71, 1, 69, 8, 15, 65, 67, 4, 8, 6, 8, 16, 8,\n                                  3, 50, 32, 15, 1, 72, 91, 103, 117, 121 },\n\n                                {\n\n                                50,\n                                  7, 78, 50, 7, 78, 86, 70, 19, 11, 2, 7, 15,\n                                  40, 57, 17, 76, 67, 1, 3, 4, 1, 65, 68, 71,\n                                  14, 6, 83, 94, 106, 1, 79, 70, 1, 3, 4, 77,\n                                  71, 11, 9, 66, 74, 81, 2, 77, 82, 95, 6, 69,\n                                  76, 4, 76, 75, 87, 64, 75, 71, 83, 64, 2, 22,\n                                  0, 0, 0, 70, 91, 97, 2, 4, 66, 30, 2, 82, 70,\n                                  65, 71, 20, 16, 67, 0, 80, 64, 79, 76, 75, 80,\n                                  81, 83, 86, 24, 65, 1, 76, 70, 86, 78, 82, 4,\n                                  66, 65, 72, 15, 68, 0, 75, 84, 72, 76, 71, 64,\n                                  69, 76, 70, 0, 83, 74, 49, 37, 8, 3, 3, 70,\n                                  65, 3, 2, 10, 4, 66, 77, 70, 70, 66, 65, 0, 9,\n                                  10, 5, 5, 7, 8, 15, 10, 6, 4, 4, 2, 7, 9, 80,\n                                  65, 5, 71, 10, 13, 19, 13, 4, 19, 12, 15, 65,\n                                  3, 4, 4, 17, 89, 13, 21, 18, 27, 32, 23, 23,\n                                  35, 34, 15, 25, 29, 11, 62, 65, 20, 12, 15,\n                                  19, 16, 23, 22, 30, 5, 10, 13, 16, 62, 74, 41,\n                                  45, 40, 37, 36, 33, 29, 29, 25, 16, 13, 10, 5,\n                                  1, 82, 75, 74, 88, 8, 7, 4, 3, 69, 70, 70, 64,\n                                  77, 76, 79, 88, 81, 101, 78, 14, 13, 10, 5, 2,\n                                  67, 71, 72, 78, 70, 29, 18, 13, 4, 8, 66, 71,\n                                  75, 81, 3, 34, 26, 21, 18, 14, 5, 0, 66, 73,\n                                  68, 42, 30, 17, 4, 11, 64, 73, 77, 7, 49, 41,\n                                  31, 21, 22, 4, 65, 68, 72, 62, 95, 90, 81, 88,\n                                  88, 80, 82, 78, 77, 79, 77, 74, 80, 79, 83,\n                                  86, 73, 80, 77, 76, 72, 69, 70, 71, 68, 68,\n                                  69, 70, 79, 5, 5, 9, 2, 0, 5, 4, 4, 3, 2, 1,\n                                  0, 64, 68, 72, 68, 4, 80, 3, 16, 3, 11, 5, 8,\n                                  13, 5, 4, 4, 9, 67, 70, 75, 42, 44, 43, 38,\n                                  35, 41, 38, 38, 37, 33, 38, 35, 27, 22, 8, 35,\n                                  36, 33, 27, 25, 24, 15, 12, 7, 6, 66, 70, 72,\n                                  80, 43, 43, 43, 39, 30, 33, 30, 22, 21, 16,\n                                  12, 2, 64, 71, 79, 65, 64, 82, 10, 8, 4, 67,\n                                  65, 67, 72, 67, 74, 75, 87, 84, 91, 98, 67,\n                                  79, 84, 77, 72, 1, 70, 8, 16, 68, 68, 5, 9, 4,\n                                  9, 18, 4, 2, 49, 30, 12, 65, 76, 95, 107, 121,\n                                  124, 0, 39, 29, 24, 14, 19, 9, 4, 2, 71, 76,\n                                  71, 2, 69, 9, 16, 65, 67, 5, 9, 6, 8, 16, 8,\n                                  3, 49, 30, 12, 65, 76, 95, 107, 121, 124 },\n\n                                {\n\n                                48,\n                                  6, 78, 48, 6, 78, 85, 69, 19, 11, 2, 5, 12,\n                                  39, 57, 16, 74, 68, 1, 4, 4, 0, 65, 69, 73,\n                                  13, 3, 87, 97, 108, 4, 78, 70, 1, 4, 4, 78,\n                                  70, 11, 8, 66, 74, 81, 1, 78, 82, 95, 6, 69,\n                                  76, 4, 76, 75, 87, 64, 75, 71, 83, 64, 2, 22,\n                                  0, 0, 0, 69, 92, 97, 2, 3, 66, 29, 2, 83, 68,\n                                  64, 70, 21, 18, 66, 1, 78, 0, 78, 75, 73, 80,\n                                  81, 83, 86, 24, 65, 2, 74, 70, 86, 77, 80, 4,\n                                  66, 65, 73, 15, 68, 0, 74, 83, 71, 75, 71, 64,\n                                  69, 75, 69, 0, 82, 73, 53, 41, 11, 5, 3, 70,\n                                  65, 3, 1, 10, 4, 66, 77, 68, 70, 68, 67, 2, 9,\n                                  10, 5, 5, 7, 8, 17, 10, 6, 4, 3, 2, 8, 10, 82,\n                                  65, 5, 71, 9, 11, 18, 13, 3, 19, 12, 14, 66,\n                                  3, 3, 3, 16, 89, 12, 20, 17, 25, 28, 21, 21,\n                                  33, 31, 12, 23, 27, 4, 62, 69, 18, 10, 13, 16,\n                                  14, 19, 18, 26, 2, 8, 10, 14, 62, 76, 39, 42,\n                                  37, 34, 33, 30, 27, 26, 23, 14, 11, 8, 3, 64,\n                                  84, 75, 75, 89, 7, 5, 3, 2, 70, 72, 72, 66,\n                                  78, 76, 80, 89, 82, 101, 77, 15, 13, 10, 5, 3,\n                                  66, 70, 72, 76, 69, 29, 18, 13, 5, 9, 65, 69,\n                                  73, 80, 4, 34, 26, 21, 19, 15, 5, 0, 66, 72,\n                                  69, 43, 30, 16, 4, 11, 64, 73, 77, 7, 49, 40,\n                                  30, 20, 22, 4, 65, 68, 72, 62, 94, 89, 80, 87,\n                                  86, 79, 80, 76, 76, 78, 75, 72, 80, 79, 83,\n                                  85, 72, 80, 77, 76, 71, 69, 70, 71, 68, 69,\n                                  69, 70, 79, 5, 5, 10, 2, 64, 5, 4, 3, 3, 2, 1,\n                                  64, 64, 68, 72, 68, 5, 81, 2, 16, 1, 10, 4, 7,\n                                  12, 4, 3, 4, 9, 68, 70, 77, 41, 42, 42, 36,\n                                  33, 39, 36, 36, 35, 30, 35, 32, 24, 19, 6, 31,\n                                  32, 28, 22, 21, 20, 12, 9, 4, 4, 68, 71, 73,\n                                  81, 41, 41, 40, 36, 27, 30, 27, 19, 18, 13, 9,\n                                  64, 66, 73, 81, 66, 65, 84, 8, 7, 2, 69, 67,\n                                  69, 74, 69, 76, 77, 88, 85, 92, 99, 69, 80,\n                                  85, 77, 72, 1, 70, 9, 17, 68, 68, 6, 10, 4, 9,\n                                  18, 4, 1, 48, 28, 9, 68, 79, 99, 112, 126,\n                                  126, 0, 39, 29, 24, 14, 20, 9, 4, 2, 71, 76,\n                                  71, 2, 69, 9, 16, 65, 67, 5, 9, 6, 8, 17, 8,\n                                  2, 48, 28, 9, 68, 79, 99, 112, 126, 126 },\n\n                                {\n\n                                47,\n                                  6, 78, 47, 6, 78, 83, 68, 20, 11, 2, 4, 10,\n                                  38, 58, 16, 72, 68, 2, 5, 4, 64, 65, 69, 74,\n                                  12, 1, 91, 100, 109, 7, 77, 69, 2, 5, 4, 78,\n                                  69, 11, 8, 65, 74, 80, 1, 78, 82, 95, 6, 69,\n                                  75, 4, 76, 75, 87, 64, 75, 71, 82, 64, 2, 22,\n                                  0, 0, 0, 68, 92, 97, 2, 2, 66, 28, 2, 83, 66,\n                                  1, 69, 23, 20, 64, 2, 76, 2, 77, 73, 70, 80,\n                                  81, 83, 85, 24, 65, 3, 72, 69, 85, 76, 78, 4,\n                                  66, 65, 73, 15, 68, 0, 73, 82, 70, 74, 70, 0,\n                                  68, 74, 67, 1, 80, 72, 58, 46, 15, 8, 4, 70,\n                                  64, 4, 1, 10, 4, 65, 76, 65, 70, 70, 68, 5, 9,\n                                  10, 5, 5, 7, 9, 19, 11, 6, 4, 3, 2, 9, 11, 83,\n                                  64, 5, 71, 8, 10, 17, 13, 2, 19, 12, 14, 67,\n                                  4, 2, 3, 15, 89, 12, 20, 17, 23, 25, 20, 20,\n                                  31, 29, 10, 21, 25, 65, 62, 72, 16, 8, 11, 13,\n                                  12, 16, 14, 22, 0, 6, 7, 12, 62, 78, 37, 40,\n                                  35, 32, 31, 28, 25, 24, 21, 12, 9, 7, 2, 65,\n                                  86, 75, 75, 89, 7, 4, 2, 1, 71, 73, 73, 68,\n                                  79, 76, 81, 90, 82, 100, 76, 16, 13, 10, 5, 4,\n                                  65, 69, 71, 73, 68, 29, 18, 13, 6, 10, 64, 67,\n                                  71, 78, 5, 35, 27, 22, 20, 16, 5, 1, 66, 71,\n                                  69, 44, 30, 15, 4, 12, 0, 73, 76, 7, 49, 40,\n                                  29, 19, 22, 4, 65, 68, 71, 62, 93, 88, 78, 85,\n                                  84, 78, 78, 74, 75, 76, 73, 70, 79, 78, 82,\n                                  84, 70, 79, 76, 75, 70, 68, 70, 71, 68, 70,\n                                  69, 70, 79, 5, 6, 11, 3, 64, 6, 4, 3, 3, 2, 1,\n                                  65, 64, 67, 71, 68, 6, 81, 1, 16, 0, 9, 4, 7,\n                                  12, 4, 2, 4, 9, 69, 70, 78, 40, 41, 42, 35,\n                                  31, 37, 34, 34, 33, 28, 32, 29, 21, 16, 4, 27,\n                                  28, 24, 17, 18, 17, 9, 7, 2, 3, 69, 72, 73,\n                                  82, 39, 39, 38, 34, 25, 28, 25, 16, 16, 11, 7,\n                                  66, 68, 75, 83, 66, 66, 85, 7, 6, 0, 71, 68,\n                                  70, 76, 70, 78, 78, 88, 86, 92, 100, 71, 81,\n                                  86, 77, 71, 2, 70, 10, 19, 67, 67, 7, 11, 4,\n                                  10, 19, 4, 1, 47, 26, 7, 71, 82, 103, 116,\n                                  126, 126, 0, 39, 29, 25, 15, 21, 10, 5, 3, 71,\n                                  76, 71, 2, 68, 10, 17, 65, 66, 5, 9, 6, 9, 18,\n                                  8, 2, 47, 26, 7, 71, 82, 103, 116, 126, 126 },\n\n                                {\n\n                                46,\n                                  6, 78, 46, 6, 78, 81, 66, 20, 11, 1, 3, 8, 37,\n                                  58, 16, 70, 68, 2, 6, 3, 64, 65, 70, 76, 11,\n                                  65, 94, 102, 111, 10, 76, 69, 2, 6, 3, 78, 68,\n                                  11, 7, 65, 73, 79, 1, 78, 82, 95, 6, 69, 75,\n                                  4, 76, 74, 86, 64, 75, 71, 82, 0, 2, 22, 0, 0,\n                                  0, 68, 92, 97, 3, 1, 66, 27, 1, 83, 0, 2, 68,\n                                  25, 22, 0, 4, 75, 3, 75, 72, 68, 80, 80, 82,\n                                  85, 24, 65, 4, 70, 69, 84, 76, 76, 4, 67, 66,\n                                  74, 15, 68, 1, 73, 81, 69, 74, 69, 0, 67, 72,\n                                  66, 2, 79, 71, 62, 50, 18, 11, 4, 69, 64, 4,\n                                  1, 10, 5, 65, 76, 0, 70, 72, 70, 8, 9, 11, 5,\n                                  5, 7, 9, 20, 12, 7, 3, 3, 2, 9, 11, 84, 64, 5,\n                                  72, 8, 9, 17, 12, 2, 19, 12, 14, 68, 4, 1, 2,\n                                  15, 89, 12, 19, 16, 21, 22, 19, 18, 29, 27, 8,\n                                  18, 23, 71, 62, 76, 14, 6, 8, 10, 9, 13, 9,\n                                  18, 66, 4, 3, 10, 62, 79, 35, 38, 33, 30, 29,\n                                  26, 23, 22, 19, 9, 7, 5, 0, 67, 88, 75, 75,\n                                  90, 6, 3, 1, 64, 72, 74, 74, 69, 80, 77, 82,\n                                  90, 83, 99, 74, 17, 14, 10, 6, 4, 65, 69, 70,\n                                  71, 66, 29, 19, 14, 6, 11, 0, 66, 70, 76, 5,\n                                  36, 28, 23, 20, 17, 6, 1, 65, 71, 69, 44, 30,\n                                  15, 3, 12, 0, 73, 76, 7, 48, 39, 28, 18, 22,\n                                  4, 64, 68, 71, 62, 91, 86, 77, 83, 83, 77, 77,\n                                  73, 74, 74, 72, 68, 78, 77, 82, 83, 68, 79,\n                                  76, 75, 70, 68, 70, 72, 68, 70, 69, 70, 80, 6,\n                                  6, 12, 3, 64, 6, 4, 3, 3, 2, 1, 65, 64, 67,\n                                  71, 68, 6, 82, 0, 16, 64, 9, 3, 6, 12, 3, 1,\n                                  4, 9, 70, 70, 79, 39, 40, 41, 33, 29, 35, 32,\n                                  31, 30, 25, 29, 26, 18, 14, 2, 22, 24, 20, 12,\n                                  15, 14, 7, 5, 64, 1, 71, 74, 74, 82, 36, 36,\n                                  35, 32, 22, 25, 22, 13, 14, 8, 5, 69, 70, 77,\n                                  84, 67, 66, 87, 6, 4, 64, 73, 70, 72, 77, 71,\n                                  79, 79, 89, 88, 93, 100, 72, 83, 88, 76, 71,\n                                  3, 69, 11, 20, 67, 66, 7, 11, 4, 10, 20, 4, 1,\n                                  46, 24, 4, 74, 86, 107, 120, 126, 126, 1, 39,\n                                  29, 25, 15, 21, 10, 5, 3, 70, 76, 71, 3, 68,\n                                  11, 18, 65, 66, 6, 10, 6, 9, 18, 8, 2, 46, 24,\n                                  4, 74, 86, 107, 120, 126, 126 },\n\n                                {\n\n                                45,\n                                  6, 79, 45, 6, 79, 79, 65, 21, 11, 1, 1, 6, 36,\n                                  58, 16, 69, 68, 3, 6, 3, 65, 64, 70, 77, 9,\n                                  67, 98, 105, 112, 12, 75, 69, 3, 6, 3, 79, 68,\n                                  11, 7, 65, 73, 79, 1, 78, 81, 94, 6, 68, 74,\n                                  4, 75, 74, 86, 64, 75, 71, 82, 0, 2, 22, 0, 0,\n                                  0, 67, 92, 97, 3, 1, 67, 27, 1, 83, 2, 3, 67,\n                                  26, 25, 2, 5, 73, 5, 74, 71, 66, 80, 80, 82,\n                                  85, 24, 65, 5, 67, 69, 83, 75, 74, 3, 67, 66,\n                                  74, 16, 68, 1, 72, 81, 69, 73, 68, 1, 66, 71,\n                                  64, 2, 78, 70, 62, 55, 21, 14, 4, 69, 64, 5,\n                                  1, 10, 5, 64, 75, 2, 69, 74, 72, 11, 9, 11, 5,\n                                  5, 8, 10, 22, 13, 7, 3, 3, 2, 10, 12, 85, 64,\n                                  5, 72, 7, 8, 16, 12, 1, 19, 12, 14, 70, 4, 0,\n                                  1, 14, 89, 12, 19, 16, 19, 19, 18, 16, 26, 24,\n                                  6, 16, 21, 78, 62, 79, 12, 5, 6, 6, 7, 10, 5,\n                                  13, 69, 2, 0, 8, 62, 81, 33, 36, 31, 27, 26,\n                                  24, 20, 20, 17, 7, 4, 3, 65, 68, 89, 75, 75,\n                                  90, 5, 2, 0, 65, 73, 75, 75, 71, 81, 77, 83,\n                                  91, 83, 99, 73, 18, 14, 10, 6, 5, 64, 68, 70,\n                                  69, 65, 30, 19, 14, 7, 12, 1, 64, 68, 74, 6,\n                                  36, 28, 23, 21, 18, 6, 1, 65, 70, 69, 45, 30,\n                                  14, 3, 12, 0, 73, 75, 6, 48, 39, 27, 17, 21,\n                                  4, 64, 68, 71, 62, 90, 85, 76, 82, 81, 76, 75,\n                                  71, 73, 73, 70, 66, 78, 76, 81, 82, 66, 78,\n                                  76, 75, 69, 67, 70, 72, 68, 71, 69, 70, 80, 6,\n                                  7, 13, 3, 64, 7, 5, 3, 4, 3, 1, 66, 64, 67,\n                                  71, 68, 7, 83, 64, 16, 65, 8, 2, 6, 12, 2, 1,\n                                  4, 8, 72, 71, 80, 37, 39, 40, 32, 27, 33, 30,\n                                  29, 28, 23, 26, 24, 15, 11, 0, 18, 20, 16, 8,\n                                  11, 11, 4, 3, 66, 64, 73, 75, 75, 83, 34, 34,\n                                  33, 29, 19, 23, 20, 10, 11, 6, 2, 72, 72, 78,\n                                  86, 68, 67, 88, 4, 3, 66, 75, 71, 74, 79, 72,\n                                  81, 80, 90, 89, 94, 101, 74, 84, 89, 76, 70,\n                                  3, 69, 12, 21, 67, 66, 8, 12, 4, 11, 21, 4, 1,\n                                  45, 22, 2, 77, 89, 111, 124, 126, 126, 1, 39,\n                                  29, 25, 15, 22, 11, 5, 3, 70, 75, 70, 3, 67,\n                                  12, 19, 64, 65, 6, 10, 6, 9, 19, 8, 2, 45, 22,\n                                  2, 77, 89, 111, 124, 126, 126 },\n\n                                {\n\n                                43,\n                                  6, 79, 43, 6, 79, 78, 0, 21, 11, 0, 0, 4, 35,\n                                  58, 15, 67, 68, 3, 7, 3, 65, 64, 71, 79, 8,\n                                  70, 101, 107, 114, 15, 74, 69, 3, 7, 3, 79,\n                                  67, 11, 6, 65, 73, 78, 1, 78, 81, 94, 6, 68,\n                                  74, 4, 75, 73, 86, 64, 75, 71, 82, 0, 2, 22,\n                                  0, 0, 0, 67, 93, 97, 4, 0, 67, 26, 0, 83, 5,\n                                  4, 66, 28, 27, 3, 7, 71, 6, 73, 70, 64, 80,\n                                  80, 81, 85, 24, 65, 6, 65, 69, 83, 75, 72, 3,\n                                  68, 67, 75, 16, 68, 2, 72, 80, 68, 73, 67, 1,\n                                  66, 69, 0, 3, 77, 69, 62, 59, 24, 17, 4, 69,\n                                  64, 5, 1, 10, 6, 64, 75, 4, 69, 76, 74, 13, 9,\n                                  11, 5, 5, 8, 10, 23, 14, 7, 3, 3, 2, 10, 13,\n                                  86, 64, 5, 73, 7, 7, 16, 12, 1, 19, 12, 14,\n                                  71, 4, 64, 0, 14, 89, 11, 18, 15, 17, 15, 17,\n                                  14, 24, 22, 4, 13, 19, 84, 62, 83, 10, 3, 4,\n                                  3, 4, 6, 1, 9, 72, 0, 67, 6, 62, 83, 31, 34,\n                                  28, 25, 24, 22, 18, 18, 15, 5, 2, 1, 67, 70,\n                                  91, 75, 75, 91, 4, 1, 64, 66, 74, 77, 76, 73,\n                                  82, 78, 84, 92, 84, 98, 71, 19, 15, 10, 6, 6,\n                                  64, 68, 69, 67, 64, 30, 19, 15, 8, 13, 2, 0,\n                                  67, 73, 7, 37, 29, 24, 21, 19, 7, 1, 65, 70,\n                                  69, 45, 30, 13, 3, 12, 0, 73, 75, 6, 47, 38,\n                                  26, 16, 21, 4, 64, 68, 71, 62, 89, 83, 75, 80,\n                                  80, 75, 73, 69, 72, 71, 68, 64, 77, 75, 81,\n                                  81, 65, 78, 76, 75, 69, 67, 70, 72, 68, 71,\n                                  69, 70, 81, 7, 7, 14, 3, 64, 7, 5, 3, 4, 3, 1,\n                                  66, 64, 67, 71, 68, 7, 84, 65, 16, 66, 7, 1,\n                                  5, 12, 1, 0, 4, 8, 73, 71, 81, 36, 38, 39, 30,\n                                  25, 31, 28, 27, 25, 20, 23, 21, 12, 9, 65, 14,\n                                  16, 12, 3, 8, 7, 2, 0, 69, 66, 75, 77, 76, 84,\n                                  32, 31, 30, 27, 16, 20, 17, 7, 9, 3, 0, 75,\n                                  74, 80, 87, 69, 68, 90, 3, 1, 68, 77, 73, 76,\n                                  81, 73, 82, 81, 91, 90, 95, 102, 75, 85, 90,\n                                  76, 70, 4, 68, 13, 22, 67, 65, 8, 12, 4, 11,\n                                  22, 4, 1, 44, 20, 64, 80, 92, 115, 126, 126,\n                                  126, 1, 39, 29, 25, 15, 22, 11, 5, 3, 69, 75,\n                                  70, 4, 67, 12, 20, 64, 65, 6, 10, 6, 9, 19, 8,\n                                  2, 44, 20, 64, 80, 92, 115, 126, 126, 126 },\n\n                                {\n\n                                42,\n                                  6, 79, 42, 6, 79, 76, 1, 21, 11, 0, 64, 2, 34,\n                                  58, 15, 65, 68, 3, 8, 2, 66, 64, 72, 81, 7,\n                                  72, 105, 110, 116, 18, 73, 68, 3, 8, 2, 79,\n                                  66, 11, 6, 65, 72, 77, 1, 78, 81, 94, 6, 68,\n                                  74, 4, 75, 73, 85, 64, 75, 71, 82, 1, 2, 22,\n                                  0, 0, 0, 66, 93, 97, 4, 64, 67, 25, 0, 83, 7,\n                                  5, 65, 30, 29, 5, 8, 70, 8, 71, 69, 2, 80, 79,\n                                  81, 84, 24, 65, 7, 0, 69, 82, 74, 70, 3, 68,\n                                  67, 75, 16, 68, 2, 71, 79, 67, 72, 66, 2, 65,\n                                  68, 2, 4, 75, 68, 62, 62, 27, 20, 5, 68, 0, 6,\n                                  1, 10, 6, 64, 74, 6, 69, 78, 76, 16, 9, 12, 5,\n                                  5, 8, 11, 25, 15, 8, 2, 3, 2, 11, 13, 87, 0,\n                                  5, 73, 6, 6, 15, 11, 0, 19, 12, 14, 72, 5, 65,\n                                  0, 13, 89, 11, 17, 14, 15, 12, 16, 13, 22, 20,\n                                  2, 11, 17, 90, 62, 86, 8, 1, 1, 0, 2, 3, 67,\n                                  5, 74, 65, 70, 4, 62, 84, 29, 32, 26, 23, 22,\n                                  20, 16, 16, 13, 2, 0, 64, 68, 72, 93, 75, 75,\n                                  91, 3, 0, 65, 68, 75, 78, 77, 74, 83, 78, 85,\n                                  92, 85, 97, 70, 20, 15, 10, 7, 6, 0, 67, 68,\n                                  65, 1, 30, 20, 15, 8, 14, 3, 2, 65, 71, 7, 38,\n                                  30, 25, 22, 20, 7, 2, 64, 69, 69, 46, 30, 13,\n                                  2, 12, 0, 73, 74, 6, 47, 37, 25, 15, 21, 4, 0,\n                                  68, 70, 62, 87, 82, 73, 78, 78, 74, 72, 68,\n                                  71, 69, 67, 1, 76, 74, 80, 80, 0, 78, 76, 74,\n                                  68, 66, 70, 73, 68, 72, 69, 70, 81, 7, 7, 15,\n                                  3, 64, 7, 5, 3, 4, 3, 1, 67, 64, 67, 71, 68,\n                                  8, 85, 66, 16, 67, 7, 1, 4, 12, 1, 64, 4, 8,\n                                  74, 71, 82, 35, 37, 38, 28, 23, 29, 26, 24,\n                                  23, 17, 20, 18, 9, 6, 67, 9, 12, 8, 65, 5, 4,\n                                  64, 65, 71, 68, 76, 78, 76, 84, 29, 29, 28,\n                                  25, 13, 17, 15, 4, 7, 1, 65, 78, 76, 82, 89,\n                                  69, 68, 92, 2, 0, 69, 79, 75, 78, 82, 74, 84,\n                                  82, 91, 92, 96, 102, 77, 87, 92, 75, 70, 5,\n                                  68, 14, 23, 66, 64, 9, 13, 4, 12, 23, 4, 1,\n                                  43, 18, 67, 83, 96, 119, 126, 126, 126, 2, 39,\n                                  29, 25, 15, 23, 11, 6, 4, 69, 75, 70, 4, 67,\n                                  13, 21, 64, 65, 7, 11, 6, 10, 20, 8, 2, 43,\n                                  18, 67, 83, 96, 119, 126, 126, 126 },\n\n                                {\n\n                                41,\n                                  6, 79, 41, 6, 79, 74, 3, 22, 11, 64, 66, 0,\n                                  33, 58, 15, 0, 68, 4, 9, 2, 66, 64, 72, 82, 6,\n                                  75, 108, 112, 117, 21, 72, 68, 4, 9, 2, 80,\n                                  65, 11, 5, 65, 72, 77, 1, 78, 81, 94, 6, 68,\n                                  73, 4, 75, 72, 85, 64, 75, 71, 82, 1, 2, 22,\n                                  0, 0, 0, 66, 93, 97, 5, 65, 67, 24, 64, 83,\n                                  10, 6, 64, 31, 31, 6, 10, 68, 9, 70, 68, 4,\n                                  80, 79, 80, 84, 24, 65, 8, 2, 69, 81, 74, 68,\n                                  3, 69, 68, 76, 16, 68, 3, 71, 78, 66, 72, 65,\n                                  2, 64, 66, 3, 4, 74, 67, 62, 62, 30, 23, 5,\n                                  68, 0, 6, 1, 10, 7, 0, 74, 8, 69, 80, 78, 19,\n                                  9, 12, 5, 5, 8, 11, 26, 16, 8, 2, 3, 2, 11,\n                                  14, 88, 0, 5, 74, 6, 5, 15, 11, 0, 19, 12, 14,\n                                  73, 5, 66, 64, 13, 89, 11, 17, 14, 13, 9, 15,\n                                  11, 20, 17, 0, 8, 15, 97, 62, 90, 6, 64, 64,\n                                  66, 64, 0, 71, 1, 77, 67, 74, 2, 62, 86, 27,\n                                  30, 24, 20, 19, 18, 14, 14, 11, 0, 65, 66, 70,\n                                  73, 95, 75, 75, 92, 2, 64, 66, 69, 76, 79, 78,\n                                  76, 84, 79, 86, 93, 85, 97, 68, 21, 16, 10, 7,\n                                  7, 0, 67, 68, 0, 2, 30, 20, 16, 9, 15, 4, 3,\n                                  64, 69, 8, 38, 30, 25, 22, 21, 8, 2, 64, 69,\n                                  69, 46, 30, 12, 2, 12, 0, 73, 74, 6, 46, 37,\n                                  24, 14, 21, 4, 0, 68, 70, 62, 86, 80, 72, 77,\n                                  77, 73, 70, 66, 70, 68, 65, 3, 76, 73, 80, 79,\n                                  2, 77, 76, 74, 68, 66, 70, 73, 68, 72, 69, 70,\n                                  82, 8, 8, 16, 3, 64, 8, 5, 3, 4, 3, 1, 67, 64,\n                                  67, 71, 68, 8, 86, 67, 16, 68, 6, 0, 4, 12, 0,\n                                  65, 4, 8, 75, 71, 83, 34, 36, 37, 27, 21, 27,\n                                  24, 22, 20, 15, 17, 15, 6, 4, 69, 5, 8, 4, 70,\n                                  1, 1, 66, 67, 74, 70, 78, 80, 77, 85, 27, 26,\n                                  25, 22, 10, 15, 12, 1, 4, 65, 68, 81, 78, 84,\n                                  90, 70, 69, 93, 0, 65, 71, 81, 76, 80, 84, 75,\n                                  85, 83, 92, 93, 97, 103, 78, 88, 93, 75, 69,\n                                  5, 67, 15, 24, 66, 64, 9, 13, 4, 12, 24, 4, 1,\n                                  42, 16, 69, 86, 99, 123, 126, 126, 126, 2, 39,\n                                  29, 25, 15, 23, 12, 6, 4, 68, 75, 70, 5, 66,\n                                  14, 22, 64, 64, 7, 11, 6, 10, 20, 8, 2, 42,\n                                  16, 69, 86, 99, 123, 126, 126, 126 },\n\n                                {\n\n                                40,\n                                  6, 79, 40, 6, 79, 72, 4, 22, 11, 64, 67, 65,\n                                  32, 58, 15, 2, 68, 4, 10, 2, 67, 64, 73, 84,\n                                  5, 77, 112, 115, 119, 24, 71, 68, 4, 10, 2,\n                                  80, 64, 11, 5, 65, 72, 76, 1, 78, 81, 94, 6,\n                                  68, 73, 4, 75, 72, 85, 64, 75, 71, 82, 1, 2,\n                                  22, 0, 0, 0, 65, 93, 97, 5, 66, 67, 23, 64,\n                                  83, 12, 7, 0, 33, 33, 8, 11, 66, 11, 69, 67,\n                                  6, 80, 79, 80, 84, 24, 65, 9, 4, 69, 80, 73,\n                                  66, 3, 69, 68, 76, 16, 68, 3, 70, 77, 65, 71,\n                                  64, 3, 0, 65, 5, 5, 73, 66, 62, 62, 33, 26, 5,\n                                  68, 0, 7, 1, 10, 7, 0, 73, 10, 69, 82, 80, 22,\n                                  9, 12, 5, 5, 8, 12, 28, 17, 8, 2, 3, 2, 12,\n                                  15, 89, 0, 5, 74, 5, 4, 14, 11, 64, 19, 12,\n                                  14, 74, 5, 67, 65, 12, 89, 11, 16, 13, 11, 6,\n                                  14, 9, 18, 15, 65, 6, 13, 103, 62, 93, 4, 66,\n                                  66, 69, 66, 66, 75, 66, 80, 69, 77, 0, 62, 88,\n                                  25, 28, 22, 18, 17, 16, 12, 12, 9, 65, 67, 68,\n                                  72, 75, 97, 75, 75, 92, 1, 65, 67, 70, 77, 80,\n                                  79, 78, 85, 79, 87, 94, 86, 96, 67, 22, 16,\n                                  10, 7, 8, 1, 66, 67, 2, 3, 30, 20, 16, 10, 16,\n                                  5, 5, 1, 67, 9, 39, 31, 26, 23, 22, 8, 2, 64,\n                                  68, 69, 47, 30, 11, 2, 12, 0, 73, 73, 6, 46,\n                                  36, 23, 13, 21, 4, 0, 68, 70, 62, 85, 79, 71,\n                                  75, 75, 72, 68, 64, 69, 66, 0, 5, 75, 72, 79,\n                                  78, 4, 77, 76, 74, 67, 65, 70, 73, 68, 73, 69,\n                                  70, 82, 8, 8, 17, 3, 64, 8, 5, 3, 4, 3, 1, 68,\n                                  64, 67, 71, 68, 9, 87, 68, 16, 69, 5, 64, 3,\n                                  12, 64, 66, 4, 8, 76, 71, 84, 33, 35, 36, 25,\n                                  19, 25, 22, 20, 18, 12, 14, 12, 3, 1, 71, 1,\n                                  4, 0, 75, 65, 65, 69, 69, 76, 72, 80, 81, 78,\n                                  86, 25, 24, 23, 20, 7, 12, 10, 65, 2, 67, 70,\n                                  84, 80, 86, 92, 71, 70, 95, 64, 66, 73, 83,\n                                  78, 82, 86, 76, 87, 84, 93, 94, 98, 104, 80,\n                                  89, 94, 75, 69, 6, 67, 16, 25, 66, 0, 10, 14,\n                                  4, 13, 25, 4, 1, 41, 14, 72, 89, 102, 126,\n                                  126, 126, 126, 2, 39, 29, 25, 15, 24, 12, 6,\n                                  4, 68, 75, 70, 5, 66, 15, 23, 64, 64, 7, 11,\n                                  6, 10, 21, 8, 2, 41, 14, 72, 89, 102, 126,\n                                  126, 126, 126 },\n\n                                {\n\n                                38,\n                                  5, 80, 38, 5, 80, 71, 5, 22, 11, 65, 69, 68,\n                                  31, 58, 14, 3, 69, 4, 10, 1, 68, 64, 74, 86,\n                                  3, 80, 116, 118, 121, 26, 71, 68, 4, 10, 1,\n                                  81, 64, 11, 4, 65, 72, 76, 0, 79, 81, 94, 5,\n                                  68, 73, 4, 75, 72, 85, 64, 75, 72, 82, 1, 2,\n                                  22, 0, 0, 0, 65, 94, 97, 5, 67, 68, 22, 65,\n                                  84, 14, 8, 1, 34, 35, 9, 12, 65, 12, 68, 66,\n                                  8, 80, 79, 80, 84, 24, 65, 9, 6, 69, 80, 73,\n                                  65, 2, 70, 69, 77, 16, 68, 3, 70, 77, 65, 71,\n                                  64, 3, 0, 64, 6, 5, 72, 65, 62, 62, 36, 28, 5,\n                                  68, 0, 7, 0, 10, 7, 0, 73, 12, 69, 84, 82, 24,\n                                  9, 12, 5, 5, 8, 12, 29, 17, 8, 1, 2, 2, 12,\n                                  15, 91, 0, 5, 75, 4, 2, 13, 10, 65, 19, 12,\n                                  13, 76, 5, 68, 66, 11, 89, 10, 15, 12, 8, 2,\n                                  12, 7, 15, 12, 68, 3, 11, 110, 62, 97, 1, 68,\n                                  69, 73, 69, 70, 80, 71, 83, 71, 81, 65, 62,\n                                  90, 22, 25, 19, 15, 14, 13, 9, 9, 7, 68, 70,\n                                  70, 74, 77, 99, 75, 76, 93, 0, 67, 69, 72, 79,\n                                  82, 81, 80, 86, 80, 88, 95, 87, 96, 66, 22,\n                                  16, 10, 7, 8, 1, 66, 67, 4, 4, 30, 20, 16, 10,\n                                  16, 6, 6, 2, 66, 9, 39, 31, 26, 23, 23, 8, 2,\n                                  64, 68, 70, 47, 29, 10, 1, 12, 0, 73, 73, 5,\n                                  45, 35, 21, 12, 20, 4, 0, 68, 70, 62, 84, 78,\n                                  70, 74, 74, 71, 67, 0, 68, 65, 1, 7, 75, 72,\n                                  79, 77, 5, 77, 76, 74, 67, 65, 70, 74, 69, 74,\n                                  69, 71, 83, 8, 8, 18, 3, 65, 8, 5, 2, 4, 3, 1,\n                                  69, 64, 67, 71, 68, 9, 88, 69, 16, 71, 4, 65,\n                                  2, 11, 65, 67, 4, 7, 78, 72, 86, 31, 33, 35,\n                                  23, 17, 22, 19, 17, 15, 9, 11, 9, 64, 65, 73,\n                                  67, 0, 68, 80, 69, 69, 72, 72, 79, 74, 82, 83,\n                                  79, 87, 22, 21, 20, 17, 4, 9, 7, 69, 64, 70,\n                                  73, 87, 82, 88, 94, 72, 71, 97, 66, 68, 75,\n                                  86, 80, 84, 88, 78, 89, 86, 94, 96, 99, 105,\n                                  82, 91, 96, 75, 69, 6, 67, 17, 26, 66, 0, 10,\n                                  14, 4, 13, 25, 4, 0, 39, 12, 75, 93, 106, 126,\n                                  126, 126, 126, 2, 39, 29, 25, 15, 24, 12, 6,\n                                  4, 68, 75, 70, 5, 66, 15, 23, 64, 64, 7, 11,\n                                  6, 10, 21, 7, 1, 39, 12, 75, 93, 106, 126,\n                                  126, 126, 126 },\n\n                                {\n\n                                37,\n                                  5, 80, 37, 5, 80, 69, 7, 23, 12, 65, 70, 70,\n                                  30, 59, 14, 5, 69, 5, 11, 1, 68, 0, 74, 87, 2,\n                                  82, 119, 120, 122, 29, 70, 67, 5, 11, 1, 81,\n                                  0, 11, 4, 64, 71, 75, 0, 79, 80, 93, 5, 67,\n                                  72, 4, 74, 71, 84, 0, 74, 72, 81, 2, 2, 22, 0,\n                                  0, 0, 64, 94, 97, 6, 67, 68, 22, 65, 84, 17,\n                                  10, 3, 36, 38, 11, 14, 0, 14, 66, 64, 11, 80,\n                                  78, 79, 83, 24, 65, 10, 9, 68, 79, 72, 0, 2,\n                                  70, 69, 77, 17, 68, 4, 69, 76, 64, 70, 0, 4,\n                                  1, 1, 8, 6, 70, 0, 62, 62, 40, 31, 6, 67, 1,\n                                  8, 0, 11, 8, 1, 72, 15, 68, 86, 83, 27, 9, 13,\n                                  5, 6, 9, 13, 31, 18, 9, 1, 2, 2, 13, 16, 92,\n                                  1, 5, 75, 4, 1, 13, 10, 65, 19, 12, 13, 77, 6,\n                                  68, 66, 11, 89, 10, 15, 12, 6, 64, 11, 6, 13,\n                                  10, 70, 1, 9, 116, 62, 100, 64, 69, 71, 76,\n                                  71, 73, 84, 75, 85, 73, 84, 67, 62, 91, 20,\n                                  23, 17, 13, 12, 11, 7, 7, 5, 70, 72, 71, 75,\n                                  78, 100, 75, 76, 93, 0, 68, 70, 73, 80, 83,\n                                  82, 81, 87, 80, 89, 95, 87, 95, 64, 23, 17,\n                                  10, 8, 9, 2, 65, 66, 7, 6, 31, 21, 17, 11, 17,\n                                  8, 8, 4, 64, 10, 40, 32, 27, 24, 24, 9, 3, 0,\n                                  67, 70, 48, 29, 10, 1, 13, 1, 73, 72, 5, 45,\n                                  35, 20, 11, 20, 5, 1, 67, 69, 62, 82, 76, 68,\n                                  72, 72, 69, 65, 2, 66, 0, 3, 10, 74, 71, 78,\n                                  75, 7, 76, 75, 73, 66, 64, 69, 74, 69, 74, 69,\n                                  71, 83, 9, 9, 19, 4, 65, 9, 6, 2, 5, 4, 1, 69,\n                                  0, 66, 70, 67, 10, 88, 70, 16, 72, 4, 65, 2,\n                                  11, 65, 67, 4, 7, 79, 72, 87, 30, 32, 35, 22,\n                                  16, 20, 17, 15, 13, 7, 9, 7, 67, 67, 75, 71,\n                                  66, 72, 84, 72, 72, 74, 74, 81, 75, 83, 84,\n                                  79, 87, 20, 19, 18, 15, 2, 7, 5, 72, 66, 72,\n                                  75, 89, 83, 89, 95, 72, 71, 98, 67, 69, 76,\n                                  88, 81, 85, 89, 79, 90, 87, 94, 97, 99, 105,\n                                  83, 92, 97, 74, 68, 7, 66, 19, 28, 65, 1, 11,\n                                  15, 5, 14, 26, 4, 0, 38, 10, 77, 96, 109, 126,\n                                  126, 126, 126, 3, 39, 30, 26, 16, 25, 13, 7,\n                                  5, 67, 74, 69, 6, 65, 16, 24, 0, 0, 8, 12, 6,\n                                  11, 22, 7, 1, 38, 10, 77, 96, 109, 126, 126,\n                                  126, 126 },\n\n                                {\n\n                                36,\n                                  5, 80, 36, 5, 80, 67, 8, 23, 12, 65, 71, 72,\n                                  29, 59, 14, 7, 69, 5, 12, 1, 69, 0, 75, 89, 1,\n                                  85, 123, 123, 124, 32, 69, 67, 5, 12, 1, 81,\n                                  1, 11, 3, 64, 71, 74, 0, 79, 80, 93, 5, 67,\n                                  72, 4, 74, 71, 84, 0, 74, 72, 81, 2, 2, 22, 0,\n                                  0, 0, 0, 94, 97, 6, 68, 68, 21, 65, 84, 19,\n                                  11, 4, 38, 40, 12, 15, 2, 15, 65, 0, 13, 80,\n                                  78, 79, 83, 24, 65, 11, 11, 68, 78, 71, 2, 2,\n                                  70, 69, 78, 17, 68, 4, 68, 75, 0, 69, 1, 4, 2,\n                                  2, 9, 7, 69, 1, 62, 62, 43, 34, 6, 67, 1, 8,\n                                  0, 11, 8, 1, 72, 17, 68, 88, 85, 30, 9, 13, 5,\n                                  6, 9, 13, 33, 19, 9, 1, 2, 2, 14, 17, 93, 1,\n                                  5, 75, 3, 0, 12, 10, 66, 19, 12, 13, 78, 6,\n                                  69, 67, 10, 89, 10, 14, 11, 4, 67, 10, 4, 11,\n                                  8, 72, 64, 7, 122, 62, 104, 66, 71, 73, 79,\n                                  73, 76, 88, 79, 88, 75, 87, 69, 62, 93, 18,\n                                  21, 15, 11, 10, 9, 5, 5, 3, 72, 74, 73, 77,\n                                  80, 102, 75, 76, 94, 64, 69, 71, 74, 81, 84,\n                                  83, 83, 88, 80, 90, 96, 88, 94, 0, 24, 17, 10,\n                                  8, 10, 3, 64, 65, 9, 7, 31, 21, 17, 12, 18, 9,\n                                  10, 6, 1, 11, 41, 33, 28, 25, 25, 9, 3, 0, 66,\n                                  70, 49, 29, 9, 1, 13, 1, 73, 72, 5, 45, 34,\n                                  19, 10, 20, 5, 1, 67, 69, 62, 81, 75, 67, 70,\n                                  70, 68, 0, 4, 65, 2, 5, 12, 73, 70, 78, 74, 9,\n                                  76, 75, 73, 65, 64, 69, 74, 69, 75, 69, 71,\n                                  83, 9, 9, 20, 4, 65, 9, 6, 2, 5, 4, 1, 70, 0,\n                                  66, 70, 67, 11, 89, 71, 16, 73, 3, 66, 1, 11,\n                                  66, 68, 4, 7, 80, 72, 88, 29, 31, 34, 20, 14,\n                                  18, 15, 13, 11, 4, 6, 4, 70, 70, 77, 75, 70,\n                                  76, 89, 75, 75, 77, 76, 84, 77, 85, 85, 80,\n                                  88, 18, 17, 15, 13, 64, 4, 2, 75, 68, 75, 77,\n                                  92, 85, 91, 97, 73, 72, 100, 68, 70, 78, 90,\n                                  83, 87, 91, 80, 92, 88, 95, 98, 100, 106, 85,\n                                  93, 98, 74, 68, 8, 66, 20, 29, 65, 2, 12, 16,\n                                  5, 14, 27, 4, 0, 37, 8, 80, 99, 112, 126, 126,\n                                  126, 126, 3, 39, 30, 26, 16, 26, 13, 7, 5, 67,\n                                  74, 69, 6, 65, 17, 25, 0, 0, 8, 12, 6, 11, 23,\n                                  7, 1, 37, 8, 80, 99, 112, 126, 126, 126, 126 },\n\n                                {\n\n                                35,\n                                  5, 80, 35, 5, 80, 65, 10, 24, 12, 66, 73, 74,\n                                  28, 59, 14, 9, 69, 6, 13, 1, 69, 0, 75, 90, 0,\n                                  87, 126, 125, 125, 35, 68, 67, 6, 13, 1, 82,\n                                  2, 11, 3, 64, 71, 74, 0, 79, 80, 93, 5, 67,\n                                  71, 4, 74, 70, 84, 0, 74, 72, 81, 2, 2, 22, 0,\n                                  0, 0, 0, 94, 97, 7, 69, 68, 20, 66, 84, 22,\n                                  12, 5, 39, 42, 14, 17, 4, 17, 64, 1, 15, 80,\n                                  78, 78, 83, 24, 65, 12, 13, 68, 77, 71, 4, 2,\n                                  71, 70, 78, 17, 68, 5, 68, 74, 1, 69, 2, 5, 3,\n                                  4, 11, 7, 68, 2, 62, 62, 46, 37, 6, 67, 1, 9,\n                                  0, 11, 9, 2, 71, 19, 68, 90, 87, 33, 9, 13, 5,\n                                  6, 9, 14, 34, 20, 9, 1, 2, 2, 14, 18, 94, 1,\n                                  5, 76, 3, 64, 12, 10, 66, 19, 12, 13, 79, 6,\n                                  70, 68, 10, 89, 10, 14, 11, 2, 70, 9, 2, 9, 5,\n                                  74, 67, 5, 126, 62, 107, 68, 73, 75, 82, 76,\n                                  79, 92, 83, 91, 77, 91, 71, 62, 95, 16, 19,\n                                  13, 8, 7, 7, 3, 3, 1, 74, 76, 75, 79, 81, 104,\n                                  75, 76, 94, 65, 70, 72, 75, 82, 85, 84, 85,\n                                  89, 81, 91, 97, 88, 94, 2, 25, 18, 10, 8, 11,\n                                  3, 64, 65, 11, 8, 31, 21, 18, 13, 19, 10, 11,\n                                  7, 3, 12, 41, 33, 28, 25, 26, 10, 3, 0, 66,\n                                  70, 49, 29, 8, 1, 13, 1, 73, 71, 5, 44, 34,\n                                  18, 9, 20, 5, 1, 67, 69, 62, 80, 73, 66, 69,\n                                  69, 67, 2, 6, 64, 3, 7, 14, 73, 69, 77, 73,\n                                  11, 75, 75, 73, 65, 0, 69, 74, 69, 75, 69, 71,\n                                  84, 10, 10, 21, 4, 65, 10, 6, 2, 5, 4, 1, 70,\n                                  0, 66, 70, 67, 11, 90, 72, 16, 74, 2, 67, 1,\n                                  11, 67, 69, 4, 7, 81, 72, 89, 28, 30, 33, 19,\n                                  12, 16, 13, 11, 8, 2, 3, 1, 73, 72, 79, 79,\n                                  74, 80, 94, 79, 78, 79, 78, 86, 79, 87, 87,\n                                  81, 89, 16, 14, 13, 10, 67, 2, 0, 78, 71, 77,\n                                  80, 95, 87, 93, 98, 74, 73, 101, 70, 72, 80,\n                                  92, 84, 89, 93, 81, 93, 89, 96, 99, 101, 107,\n                                  86, 94, 99, 74, 67, 8, 65, 21, 30, 65, 2, 12,\n                                  16, 5, 15, 28, 4, 0, 36, 6, 82, 102, 115, 126,\n                                  126, 126, 126, 3, 39, 30, 26, 16, 26, 14, 7,\n                                  5, 66, 74, 69, 7, 64, 18, 26, 0, 1, 8, 12, 6,\n                                  11, 23, 7, 1, 36, 6, 82, 102, 115, 126, 126,\n                                  126, 126 },\n\n                                {\n\n                                33,\n                                  5, 80, 33, 5, 80, 64, 11, 24, 12, 66, 74, 76,\n                                  27, 59, 13, 11, 69, 6, 14, 0, 70, 0, 76, 92,\n                                  64, 90, 126, 126, 126, 38, 67, 67, 6, 14, 0,\n                                  82, 3, 11, 2, 64, 70, 73, 0, 79, 80, 93, 5,\n                                  67, 71, 4, 74, 70, 83, 0, 74, 72, 81, 3, 2,\n                                  22, 0, 0, 0, 1, 95, 97, 7, 70, 68, 19, 66, 84,\n                                  24, 13, 6, 41, 44, 15, 18, 5, 18, 1, 2, 17,\n                                  80, 77, 78, 83, 24, 65, 13, 15, 68, 77, 70, 6,\n                                  2, 71, 70, 79, 17, 68, 5, 67, 73, 2, 68, 3, 5,\n                                  3, 5, 12, 8, 67, 3, 62, 62, 49, 40, 6, 66, 1,\n                                  9, 0, 11, 9, 2, 71, 21, 68, 92, 89, 35, 9, 14,\n                                  5, 6, 9, 14, 36, 21, 10, 0, 2, 2, 15, 18, 95,\n                                  1, 5, 76, 2, 65, 11, 9, 67, 19, 12, 13, 80, 6,\n                                  71, 69, 9, 89, 9, 13, 10, 0, 74, 8, 0, 7, 3,\n                                  76, 69, 3, 126, 62, 111, 70, 75, 78, 85, 78,\n                                  83, 97, 87, 94, 79, 94, 73, 62, 96, 14, 17,\n                                  10, 6, 5, 5, 1, 1, 64, 77, 78, 77, 81, 83,\n                                  106, 75, 76, 95, 66, 71, 73, 77, 83, 87, 85,\n                                  86, 90, 81, 92, 97, 89, 93, 3, 26, 18, 10, 9,\n                                  11, 4, 0, 64, 13, 10, 31, 22, 18, 13, 20, 11,\n                                  13, 9, 4, 12, 42, 34, 29, 26, 27, 10, 3, 1,\n                                  65, 70, 50, 29, 8, 0, 13, 1, 73, 71, 5, 44,\n                                  33, 17, 8, 20, 5, 2, 67, 69, 62, 78, 72, 65,\n                                  67, 67, 66, 3, 7, 0, 5, 8, 16, 72, 68, 77, 72,\n                                  12, 75, 75, 73, 64, 0, 69, 75, 69, 76, 69, 71,\n                                  84, 10, 10, 22, 4, 65, 10, 6, 2, 5, 4, 1, 71,\n                                  0, 66, 70, 67, 12, 91, 73, 16, 75, 2, 68, 0,\n                                  11, 68, 70, 4, 7, 82, 72, 90, 27, 29, 32, 17,\n                                  10, 14, 11, 8, 6, 64, 0, 65, 76, 75, 81, 84,\n                                  78, 84, 99, 82, 82, 82, 81, 89, 81, 89, 88,\n                                  82, 89, 13, 12, 10, 8, 70, 64, 66, 81, 73, 80,\n                                  82, 98, 89, 95, 100, 75, 73, 103, 71, 73, 81,\n                                  94, 86, 91, 94, 82, 95, 90, 97, 101, 102, 107,\n                                  88, 96, 101, 73, 67, 9, 65, 22, 31, 65, 3, 13,\n                                  17, 5, 15, 29, 4, 0, 35, 4, 85, 105, 119, 126,\n                                  126, 126, 126, 4, 39, 30, 26, 16, 27, 14, 7,\n                                  5, 66, 74, 69, 7, 64, 18, 27, 0, 1, 9, 13, 6,\n                                  11, 24, 7, 1, 35, 4, 85, 105, 119, 126, 126,\n                                  126, 126 },\n\n                                {\n\n                                32,\n                                  5, 80, 32, 5, 80, 1, 13, 24, 12, 67, 75, 78,\n                                  26, 59, 13, 13, 69, 6, 15, 0, 70, 0, 77, 94,\n                                  65, 92, 126, 126, 126, 41, 66, 66, 6, 15, 0,\n                                  82, 4, 11, 2, 64, 70, 72, 0, 79, 80, 93, 5,\n                                  67, 71, 4, 74, 69, 83, 0, 74, 72, 81, 3, 2,\n                                  22, 0, 0, 0, 1, 95, 97, 8, 71, 68, 18, 67, 84,\n                                  27, 14, 7, 43, 46, 17, 20, 7, 20, 2, 3, 20,\n                                  80, 77, 77, 82, 24, 65, 14, 17, 68, 76, 70, 8,\n                                  2, 72, 71, 79, 17, 68, 6, 67, 72, 3, 68, 4, 6,\n                                  4, 7, 14, 9, 65, 4, 62, 62, 52, 43, 7, 66, 2,\n                                  10, 0, 11, 10, 2, 70, 23, 68, 94, 91, 38, 9,\n                                  14, 5, 6, 9, 15, 37, 22, 10, 0, 2, 2, 15, 19,\n                                  96, 2, 5, 77, 2, 66, 11, 9, 67, 19, 12, 13,\n                                  81, 7, 72, 69, 9, 89, 9, 12, 9, 65, 77, 7, 64,\n                                  5, 1, 78, 72, 1, 126, 62, 114, 72, 77, 80, 88,\n                                  81, 86, 101, 91, 96, 81, 98, 75, 62, 98, 12,\n                                  15, 8, 4, 3, 3, 64, 64, 66, 79, 80, 79, 82,\n                                  85, 108, 75, 76, 95, 67, 72, 74, 78, 84, 88,\n                                  86, 88, 91, 82, 93, 98, 90, 92, 5, 27, 19, 10,\n                                  9, 12, 4, 0, 0, 15, 11, 31, 22, 19, 14, 21,\n                                  12, 14, 10, 6, 13, 43, 35, 30, 26, 28, 11, 4,\n                                  1, 65, 70, 50, 29, 7, 0, 13, 1, 73, 70, 5, 43,\n                                  32, 16, 7, 20, 5, 2, 67, 68, 62, 77, 70, 0,\n                                  65, 66, 65, 5, 9, 1, 7, 10, 18, 71, 67, 76,\n                                  71, 14, 75, 75, 72, 64, 1, 69, 75, 69, 76, 69,\n                                  71, 85, 11, 10, 23, 4, 65, 10, 6, 2, 5, 4, 1,\n                                  71, 0, 66, 70, 67, 12, 92, 74, 16, 76, 1, 68,\n                                  64, 11, 68, 71, 4, 7, 83, 72, 91, 26, 28, 31,\n                                  15, 8, 12, 9, 6, 3, 67, 66, 68, 79, 77, 83,\n                                  88, 82, 88, 104, 85, 85, 84, 83, 91, 83, 90,\n                                  90, 82, 90, 11, 9, 8, 6, 73, 67, 68, 84, 75,\n                                  82, 84, 101, 91, 97, 101, 75, 74, 105, 72, 75,\n                                  83, 96, 88, 93, 96, 83, 96, 91, 97, 102, 103,\n                                  108, 89, 97, 102, 73, 67, 10, 64, 23, 32, 64,\n                                  4, 13, 17, 5, 16, 30, 4, 0, 34, 2, 88, 108,\n                                  122, 126, 126, 126, 126, 4, 39, 30, 26, 16,\n                                  27, 14, 8, 6, 65, 74, 69, 8, 64, 19, 28, 0, 1,\n                                  9, 13, 6, 12, 24, 7, 1, 34, 2, 88, 108, 122,\n                                  126, 126, 126, 126 },\n\n                                {\n\n                                31,\n                                  5, 81, 31, 5, 81, 3, 14, 25, 12, 67, 77, 80,\n                                  25, 59, 13, 14, 69, 7, 15, 0, 71, 1, 77, 95,\n                                  67, 95, 126, 126, 126, 43, 65, 66, 7, 15, 0,\n                                  83, 4, 11, 1, 64, 70, 72, 0, 79, 79, 92, 5,\n                                  66, 70, 4, 73, 69, 83, 0, 74, 72, 81, 3, 2,\n                                  22, 0, 0, 0, 2, 95, 97, 8, 71, 69, 18, 67, 84,\n                                  29, 15, 8, 44, 49, 18, 21, 9, 21, 3, 4, 22,\n                                  80, 77, 77, 82, 24, 65, 15, 20, 68, 75, 69,\n                                  10, 1, 72, 71, 80, 18, 68, 6, 66, 72, 3, 67,\n                                  5, 6, 5, 8, 15, 9, 64, 5, 62, 62, 55, 46, 7,\n                                  66, 2, 10, 0, 11, 10, 3, 70, 25, 67, 96, 93,\n                                  41, 9, 14, 5, 6, 10, 15, 39, 23, 10, 0, 2, 2,\n                                  16, 20, 97, 2, 5, 77, 1, 67, 10, 9, 68, 19,\n                                  12, 13, 83, 7, 73, 70, 8, 89, 9, 12, 9, 67,\n                                  80, 6, 66, 2, 65, 80, 74, 64, 126, 62, 118,\n                                  74, 78, 82, 92, 83, 89, 105, 96, 99, 83, 101,\n                                  77, 62, 100, 10, 13, 6, 1, 0, 1, 67, 66, 68,\n                                  81, 83, 81, 84, 86, 109, 75, 76, 96, 68, 73,\n                                  75, 79, 85, 89, 87, 90, 92, 82, 94, 99, 90,\n                                  92, 6, 28, 19, 10, 9, 13, 5, 1, 0, 17, 12, 32,\n                                  22, 19, 15, 22, 13, 16, 12, 8, 14, 43, 35, 30,\n                                  27, 29, 11, 4, 1, 64, 70, 51, 29, 6, 0, 13, 1,\n                                  73, 70, 4, 43, 32, 15, 6, 19, 5, 2, 67, 68,\n                                  62, 76, 69, 1, 64, 64, 64, 7, 11, 2, 8, 12,\n                                  20, 71, 66, 76, 70, 16, 74, 75, 72, 0, 1, 69,\n                                  75, 69, 77, 69, 71, 85, 11, 11, 24, 4, 65, 11,\n                                  7, 2, 6, 5, 1, 72, 0, 66, 70, 67, 13, 93, 75,\n                                  16, 77, 0, 69, 64, 11, 69, 71, 4, 6, 85, 73,\n                                  92, 24, 27, 30, 14, 6, 10, 7, 4, 1, 69, 69,\n                                  70, 82, 80, 85, 92, 86, 92, 108, 89, 88, 87,\n                                  85, 94, 85, 92, 91, 83, 91, 9, 7, 5, 3, 76,\n                                  69, 71, 87, 78, 85, 87, 104, 93, 98, 103, 76,\n                                  75, 106, 74, 76, 85, 98, 89, 95, 98, 84, 98,\n                                  92, 98, 103, 104, 109, 91, 98, 103, 73, 66,\n                                  10, 64, 24, 33, 64, 4, 14, 18, 5, 16, 31, 4,\n                                  0, 33, 0, 90, 111, 125, 126, 126, 126, 126, 4,\n                                  39, 30, 26, 16, 28, 15, 8, 6, 65, 73, 68, 8,\n                                  0, 20, 29, 1, 2, 9, 13, 6, 12, 25, 7, 1, 33,\n                                  0, 90, 111, 125, 126, 126, 126, 126 },\n\n                                {\n\n                                30,\n                                  5, 81, 30, 5, 81, 5, 16, 25, 12, 68, 78, 82,\n                                  24, 59, 13, 16, 69, 7, 16, 64, 71, 1, 78, 97,\n                                  68, 97, 126, 126, 126, 46, 64, 66, 7, 16, 64,\n                                  83, 5, 11, 1, 64, 69, 71, 0, 79, 79, 92, 5,\n                                  66, 70, 4, 73, 68, 82, 0, 74, 72, 81, 4, 2,\n                                  22, 0, 0, 0, 2, 95, 97, 9, 72, 69, 17, 68, 84,\n                                  32, 16, 9, 46, 51, 20, 23, 10, 23, 5, 5, 24,\n                                  80, 76, 76, 82, 24, 65, 16, 22, 68, 74, 69,\n                                  12, 1, 73, 72, 80, 18, 68, 7, 66, 71, 4, 67,\n                                  6, 7, 6, 10, 17, 10, 0, 6, 62, 62, 58, 49, 7,\n                                  65, 2, 11, 0, 11, 11, 3, 69, 27, 67, 98, 95,\n                                  44, 9, 15, 5, 6, 10, 16, 40, 24, 11, 64, 2, 2,\n                                  16, 20, 98, 2, 5, 78, 1, 68, 10, 8, 68, 19,\n                                  12, 13, 84, 7, 74, 71, 8, 89, 9, 11, 8, 69,\n                                  83, 5, 68, 0, 67, 82, 77, 66, 126, 62, 121,\n                                  76, 80, 85, 95, 86, 92, 110, 100, 102, 85,\n                                  105, 79, 62, 101, 8, 11, 4, 64, 65, 64, 69,\n                                  68, 70, 84, 85, 83, 86, 88, 111, 75, 76, 96,\n                                  69, 74, 76, 81, 86, 90, 88, 91, 93, 83, 95,\n                                  99, 91, 91, 8, 29, 20, 10, 10, 13, 5, 1, 1,\n                                  19, 14, 32, 23, 20, 15, 23, 14, 17, 13, 10,\n                                  14, 44, 36, 31, 27, 30, 12, 4, 2, 64, 70, 51,\n                                  29, 6, 64, 13, 1, 73, 69, 4, 42, 31, 14, 5,\n                                  19, 5, 3, 67, 68, 62, 74, 67, 2, 1, 0, 0, 8,\n                                  12, 3, 10, 13, 22, 70, 65, 75, 69, 18, 74, 75,\n                                  72, 0, 2, 69, 76, 69, 77, 69, 71, 86, 12, 11,\n                                  25, 4, 65, 11, 7, 2, 6, 5, 1, 72, 0, 66, 70,\n                                  67, 13, 94, 76, 16, 78, 0, 70, 65, 11, 70, 72,\n                                  4, 6, 86, 73, 93, 23, 26, 29, 12, 4, 8, 5, 1,\n                                  65, 72, 72, 73, 85, 82, 87, 97, 90, 96, 113,\n                                  92, 91, 89, 87, 96, 87, 94, 93, 84, 91, 6, 4,\n                                  3, 1, 79, 72, 73, 90, 80, 87, 89, 107, 95,\n                                  100, 104, 77, 75, 108, 75, 78, 86, 100, 91,\n                                  97, 99, 85, 99, 93, 99, 105, 105, 109, 92,\n                                  100, 105, 72, 66, 11, 0, 25, 34, 64, 5, 14,\n                                  18, 5, 17, 32, 4, 0, 32, 65, 93, 114, 126,\n                                  126, 126, 126, 126, 5, 39, 30, 26, 16, 28, 15,\n                                  8, 6, 64, 73, 68, 9, 0, 21, 30, 1, 2, 10, 14,\n                                  6, 12, 25, 7, 1, 32, 65, 93, 114, 126, 126,\n                                  126, 126, 126 },\n\n                                {\n\n                                28,\n                                  4, 81, 28, 4, 81, 6, 17, 25, 12, 68, 80, 85,\n                                  23, 59, 12, 18, 70, 7, 17, 64, 72, 1, 79, 99,\n                                  69, 100, 126, 126, 126, 49, 0, 66, 7, 17, 64,\n                                  84, 6, 11, 0, 64, 69, 71, 64, 80, 79, 92, 5,\n                                  66, 70, 4, 73, 68, 82, 0, 74, 72, 81, 4, 2,\n                                  22, 0, 0, 0, 3, 96, 97, 9, 73, 69, 16, 68, 85,\n                                  34, 17, 10, 47, 53, 21, 24, 12, 24, 6, 6, 26,\n                                  80, 76, 76, 82, 24, 65, 17, 24, 68, 74, 68,\n                                  14, 1, 73, 72, 81, 18, 68, 7, 65, 70, 5, 66,\n                                  6, 7, 6, 11, 18, 10, 1, 7, 62, 62, 61, 51, 7,\n                                  65, 2, 11, 64, 11, 11, 3, 69, 29, 67, 100, 97,\n                                  46, 9, 15, 5, 6, 10, 16, 42, 24, 11, 64, 1, 2,\n                                  17, 21, 100, 2, 5, 78, 0, 70, 9, 8, 69, 19,\n                                  12, 12, 85, 7, 75, 72, 7, 89, 8, 10, 7, 71,\n                                  87, 3, 70, 65, 70, 85, 79, 68, 126, 62, 125,\n                                  78, 82, 87, 98, 88, 96, 114, 104, 105, 87,\n                                  108, 81, 62, 103, 6, 8, 1, 67, 68, 67, 71, 71,\n                                  72, 86, 87, 85, 88, 90, 113, 75, 77, 97, 70,\n                                  76, 77, 82, 87, 92, 90, 93, 94, 83, 96, 100,\n                                  92, 91, 9, 30, 20, 10, 10, 14, 6, 2, 1, 21,\n                                  15, 32, 23, 20, 16, 24, 15, 19, 15, 11, 15,\n                                  44, 36, 31, 28, 31, 12, 4, 2, 0, 71, 52, 29,\n                                  5, 64, 13, 1, 73, 69, 4, 42, 30, 13, 4, 19, 5,\n                                  3, 67, 68, 62, 73, 66, 3, 2, 2, 1, 10, 14, 4,\n                                  11, 15, 24, 70, 65, 75, 68, 19, 74, 75, 72, 1,\n                                  2, 69, 76, 69, 78, 69, 71, 86, 12, 11, 26, 4,\n                                  66, 11, 7, 1, 6, 5, 1, 73, 0, 66, 70, 67, 14,\n                                  95, 77, 16, 80, 64, 71, 66, 10, 71, 73, 4, 6,\n                                  87, 73, 95, 22, 24, 28, 10, 2, 6, 3, 64, 67,\n                                  75, 75, 76, 88, 85, 89, 101, 94, 101, 118, 96,\n                                  95, 92, 90, 99, 89, 96, 94, 85, 92, 4, 2, 0,\n                                  65, 82, 75, 76, 93, 83, 90, 92, 110, 97, 102,\n                                  106, 78, 76, 110, 77, 79, 88, 102, 93, 99,\n                                  101, 87, 101, 95, 100, 106, 106, 110, 94, 101,\n                                  106, 72, 66, 11, 0, 26, 35, 64, 5, 15, 19, 5,\n                                  17, 32, 4, 64, 31, 67, 96, 117, 126, 126, 126,\n                                  126, 126, 5, 39, 30, 26, 16, 29, 15, 8, 6, 64,\n                                  73, 68, 9, 0, 21, 30, 1, 2, 10, 14, 6, 12, 26,\n                                  7, 0, 31, 67, 96, 117, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                27,\n                                  4, 81, 27, 4, 81, 8, 18, 26, 12, 68, 81, 87,\n                                  22, 60, 12, 20, 70, 8, 18, 64, 73, 1, 79, 100,\n                                  70, 102, 126, 126, 126, 52, 1, 65, 8, 18, 64,\n                                  84, 7, 11, 0, 0, 69, 70, 64, 80, 79, 92, 5,\n                                  66, 69, 4, 73, 68, 82, 0, 74, 72, 80, 4, 2,\n                                  22, 0, 0, 0, 4, 96, 97, 9, 74, 69, 15, 68, 85,\n                                  36, 19, 11, 49, 55, 23, 25, 14, 26, 7, 8, 29,\n                                  80, 76, 76, 81, 24, 65, 18, 26, 67, 73, 67,\n                                  16, 1, 73, 72, 81, 18, 68, 7, 64, 69, 6, 65,\n                                  7, 8, 7, 12, 20, 11, 3, 8, 62, 62, 62, 54, 8,\n                                  65, 3, 12, 64, 11, 11, 4, 68, 32, 67, 102, 98,\n                                  49, 9, 15, 5, 6, 10, 17, 44, 25, 11, 64, 1, 2,\n                                  18, 22, 101, 3, 5, 78, 64, 71, 8, 8, 70, 19,\n                                  12, 12, 86, 8, 76, 72, 6, 89, 8, 10, 7, 73,\n                                  90, 2, 71, 67, 72, 87, 81, 70, 126, 62, 126,\n                                  80, 84, 89, 101, 90, 99, 118, 108, 107, 89,\n                                  111, 83, 62, 105, 4, 6, 64, 69, 70, 69, 73,\n                                  73, 74, 88, 89, 86, 89, 91, 115, 75, 77, 97,\n                                  70, 77, 78, 83, 88, 93, 91, 95, 95, 83, 97,\n                                  101, 92, 90, 10, 31, 20, 10, 10, 15, 7, 3, 2,\n                                  24, 16, 32, 23, 20, 17, 25, 16, 21, 17, 13,\n                                  16, 45, 37, 32, 29, 32, 12, 5, 2, 1, 71, 53,\n                                  29, 4, 64, 14, 2, 73, 68, 4, 42, 30, 12, 3,\n                                  19, 5, 3, 67, 67, 62, 72, 65, 5, 4, 4, 2, 12,\n                                  16, 5, 13, 17, 26, 69, 64, 74, 67, 21, 73, 74,\n                                  71, 2, 3, 69, 76, 69, 79, 69, 71, 86, 12, 12,\n                                  27, 5, 66, 12, 7, 1, 6, 5, 1, 74, 0, 65, 69,\n                                  67, 15, 95, 78, 16, 81, 65, 71, 66, 10, 71,\n                                  74, 4, 6, 88, 73, 96, 21, 23, 28, 9, 0, 4, 1,\n                                  66, 69, 77, 78, 79, 91, 88, 91, 105, 98, 105,\n                                  123, 99, 98, 95, 92, 101, 90, 97, 95, 85, 93,\n                                  2, 0, 65, 67, 84, 77, 78, 96, 85, 92, 94, 112,\n                                  99, 104, 108, 78, 77, 111, 78, 80, 90, 104,\n                                  94, 100, 103, 88, 103, 96, 100, 107, 106, 111,\n                                  96, 102, 107, 72, 65, 12, 0, 27, 37, 0, 6, 16,\n                                  20, 5, 18, 33, 4, 64, 30, 69, 98, 120, 126,\n                                  126, 126, 126, 126, 5, 39, 30, 27, 17, 30, 16,\n                                  9, 7, 64, 73, 68, 9, 1, 22, 31, 1, 3, 10, 14,\n                                  6, 13, 27, 7, 0, 30, 69, 98, 120, 126, 126,\n                                  126, 126, 126 },\n\n                                {\n\n                                26,\n                                  4, 81, 26, 4, 81, 10, 20, 26, 12, 69, 82, 89,\n                                  21, 60, 12, 22, 70, 8, 19, 65, 73, 1, 80, 102,\n                                  71, 105, 126, 126, 126, 55, 2, 65, 8, 19, 65,\n                                  84, 8, 11, 64, 0, 68, 69, 64, 80, 79, 92, 5,\n                                  66, 69, 4, 73, 67, 81, 0, 74, 72, 80, 5, 2,\n                                  22, 0, 0, 0, 4, 96, 97, 10, 75, 69, 14, 69,\n                                  85, 39, 20, 12, 51, 57, 24, 27, 15, 27, 9, 9,\n                                  31, 80, 75, 75, 81, 24, 65, 19, 28, 67, 72,\n                                  67, 18, 1, 74, 73, 82, 18, 68, 8, 64, 68, 7,\n                                  65, 8, 8, 8, 14, 21, 12, 4, 9, 62, 62, 62, 57,\n                                  8, 64, 3, 12, 64, 11, 12, 4, 68, 34, 67, 104,\n                                  100, 52, 9, 16, 5, 6, 10, 17, 45, 26, 12, 65,\n                                  1, 2, 18, 22, 102, 3, 5, 79, 64, 72, 8, 7, 70,\n                                  19, 12, 12, 87, 8, 77, 73, 6, 89, 8, 9, 6, 75,\n                                  93, 1, 73, 69, 74, 89, 84, 72, 126, 62, 126,\n                                  82, 86, 92, 104, 93, 102, 123, 112, 110, 91,\n                                  115, 85, 62, 106, 2, 4, 66, 71, 72, 71, 75,\n                                  75, 76, 91, 91, 88, 91, 93, 117, 75, 77, 98,\n                                  71, 78, 79, 85, 89, 94, 92, 96, 96, 84, 98,\n                                  101, 93, 89, 12, 32, 21, 10, 11, 15, 7, 3, 3,\n                                  26, 18, 32, 24, 21, 17, 26, 17, 22, 18, 15,\n                                  16, 46, 38, 33, 29, 33, 13, 5, 3, 1, 71, 53,\n                                  29, 4, 65, 14, 2, 73, 68, 4, 41, 29, 11, 2,\n                                  19, 5, 4, 67, 67, 62, 70, 0, 6, 6, 5, 3, 13,\n                                  17, 6, 15, 18, 28, 68, 0, 74, 66, 23, 73, 74,\n                                  71, 2, 3, 69, 77, 69, 79, 69, 71, 87, 13, 12,\n                                  28, 5, 66, 12, 7, 1, 6, 5, 1, 74, 0, 65, 69,\n                                  67, 15, 96, 79, 16, 82, 65, 72, 67, 10, 72,\n                                  75, 4, 6, 89, 73, 97, 20, 22, 27, 7, 65, 2,\n                                  64, 69, 72, 80, 81, 82, 94, 90, 93, 110, 102,\n                                  109, 126, 102, 101, 97, 94, 104, 92, 99, 97,\n                                  86, 93, 64, 66, 68, 69, 87, 80, 81, 99, 87,\n                                  95, 96, 115, 101, 106, 109, 79, 77, 113, 79,\n                                  82, 91, 106, 96, 102, 104, 89, 104, 97, 101,\n                                  109, 107, 111, 97, 104, 109, 71, 65, 13, 1,\n                                  28, 38, 0, 7, 16, 20, 5, 18, 34, 4, 64, 29,\n                                  71, 101, 123, 126, 126, 126, 126, 126, 6, 39,\n                                  30, 27, 17, 30, 16, 9, 7, 0, 73, 68, 10, 1,\n                                  23, 32, 1, 3, 11, 15, 6, 13, 27, 7, 0, 29, 71,\n                                  101, 123, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                25,\n                                  4, 82, 25, 4, 82, 12, 21, 27, 12, 69, 84, 91,\n                                  20, 60, 12, 23, 70, 9, 19, 65, 74, 2, 80, 103,\n                                  73, 107, 126, 126, 126, 57, 3, 65, 9, 19, 65,\n                                  85, 8, 11, 64, 0, 68, 69, 64, 80, 78, 91, 5,\n                                  65, 68, 4, 72, 67, 81, 0, 74, 72, 80, 5, 2,\n                                  22, 0, 0, 0, 5, 96, 97, 10, 75, 70, 14, 69,\n                                  85, 41, 21, 13, 52, 60, 26, 28, 17, 29, 10,\n                                  10, 33, 80, 75, 75, 81, 24, 65, 20, 31, 67,\n                                  71, 66, 20, 0, 74, 73, 82, 19, 68, 8, 0, 68,\n                                  7, 64, 9, 9, 9, 15, 23, 12, 5, 10, 62, 62, 62,\n                                  60, 8, 64, 3, 13, 64, 11, 12, 5, 67, 36, 66,\n                                  106, 102, 55, 9, 16, 5, 6, 11, 18, 47, 27, 12,\n                                  65, 1, 2, 19, 23, 103, 3, 5, 79, 65, 73, 7, 7,\n                                  71, 19, 12, 12, 89, 8, 78, 74, 5, 89, 8, 9, 6,\n                                  77, 96, 0, 75, 72, 77, 91, 86, 74, 126, 62,\n                                  126, 84, 87, 94, 108, 95, 105, 126, 117, 113,\n                                  93, 118, 87, 62, 108, 0, 2, 68, 74, 75, 73,\n                                  78, 77, 78, 93, 94, 90, 93, 94, 118, 75, 77,\n                                  98, 72, 79, 80, 86, 90, 95, 93, 98, 97, 84,\n                                  99, 102, 93, 89, 13, 33, 21, 10, 11, 16, 8, 4,\n                                  3, 28, 19, 33, 24, 21, 18, 27, 18, 24, 20, 17,\n                                  17, 46, 38, 33, 30, 34, 13, 5, 3, 2, 71, 54,\n                                  29, 3, 65, 14, 2, 73, 67, 3, 41, 29, 10, 1,\n                                  18, 5, 4, 67, 67, 62, 69, 1, 7, 7, 7, 4, 15,\n                                  19, 7, 16, 20, 30, 68, 1, 73, 65, 25, 72, 74,\n                                  71, 3, 4, 69, 77, 69, 80, 69, 71, 87, 13, 13,\n                                  29, 5, 66, 13, 8, 1, 7, 6, 1, 75, 0, 65, 69,\n                                  67, 16, 97, 80, 16, 83, 66, 73, 67, 10, 73,\n                                  75, 4, 5, 91, 74, 98, 18, 21, 26, 6, 67, 0,\n                                  66, 71, 74, 82, 84, 84, 97, 93, 95, 114, 106,\n                                  113, 126, 106, 104, 100, 96, 106, 94, 101, 98,\n                                  87, 94, 66, 68, 70, 72, 90, 82, 83, 102, 90,\n                                  97, 99, 118, 103, 107, 111, 80, 78, 114, 81,\n                                  83, 93, 108, 97, 104, 106, 90, 106, 98, 102,\n                                  110, 108, 112, 99, 105, 110, 71, 64, 13, 1,\n                                  29, 39, 0, 7, 17, 21, 5, 19, 35, 4, 64, 28,\n                                  73, 103, 126, 126, 126, 126, 126, 126, 6, 39,\n                                  30, 27, 17, 31, 17, 9, 7, 0, 72, 67, 10, 2,\n                                  24, 33, 2, 4, 11, 15, 6, 13, 28, 7, 0, 28, 73,\n                                  103, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                23,\n                                  4, 82, 23, 4, 82, 13, 23, 27, 12, 70, 85, 93,\n                                  19, 60, 11, 25, 70, 9, 20, 65, 74, 2, 81, 105,\n                                  74, 110, 126, 126, 126, 60, 4, 65, 9, 20, 65,\n                                  85, 9, 11, 65, 0, 68, 68, 64, 80, 78, 91, 5,\n                                  65, 68, 4, 72, 66, 81, 0, 74, 72, 80, 5, 2,\n                                  22, 0, 0, 0, 5, 97, 97, 11, 76, 70, 13, 70,\n                                  85, 44, 22, 14, 54, 62, 27, 30, 19, 30, 11,\n                                  11, 35, 80, 75, 74, 81, 24, 65, 21, 33, 67,\n                                  71, 66, 22, 0, 75, 74, 83, 19, 68, 9, 0, 67,\n                                  8, 64, 10, 9, 9, 17, 24, 13, 6, 11, 62, 62,\n                                  62, 62, 8, 64, 3, 13, 64, 11, 13, 5, 67, 38,\n                                  66, 108, 104, 57, 9, 16, 5, 6, 11, 18, 48, 28,\n                                  12, 65, 1, 2, 19, 24, 104, 3, 5, 80, 65, 74,\n                                  7, 7, 71, 19, 12, 12, 90, 8, 79, 75, 5, 89, 7,\n                                  8, 5, 79, 100, 64, 77, 74, 79, 93, 89, 76,\n                                  126, 62, 126, 86, 89, 96, 111, 98, 109, 126,\n                                  121, 116, 95, 122, 89, 62, 110, 65, 0, 71, 76,\n                                  77, 75, 80, 79, 80, 95, 96, 92, 95, 96, 120,\n                                  75, 77, 99, 73, 80, 81, 87, 91, 97, 94, 100,\n                                  98, 85, 100, 103, 94, 88, 15, 34, 22, 10, 11,\n                                  17, 8, 4, 4, 30, 20, 33, 24, 22, 19, 28, 19,\n                                  25, 21, 18, 18, 47, 39, 34, 30, 35, 14, 5, 3,\n                                  2, 71, 54, 29, 2, 65, 14, 2, 73, 67, 3, 40,\n                                  28, 9, 0, 18, 5, 4, 67, 67, 62, 68, 3, 8, 9,\n                                  8, 5, 17, 21, 8, 18, 22, 32, 67, 2, 73, 64,\n                                  26, 72, 74, 71, 3, 4, 69, 77, 69, 80, 69, 71,\n                                  88, 14, 13, 30, 5, 66, 13, 8, 1, 7, 6, 1, 75,\n                                  0, 65, 69, 67, 16, 98, 81, 16, 84, 67, 74, 68,\n                                  10, 74, 76, 4, 5, 92, 74, 99, 17, 20, 25, 4,\n                                  69, 65, 68, 73, 77, 85, 87, 87, 100, 95, 97,\n                                  118, 110, 117, 126, 109, 108, 102, 99, 109,\n                                  96, 103, 100, 88, 95, 68, 71, 73, 74, 93, 85,\n                                  86, 105, 92, 100, 101, 121, 105, 109, 112, 81,\n                                  79, 116, 82, 85, 95, 110, 99, 106, 108, 91,\n                                  107, 99, 103, 111, 109, 113, 100, 106, 111,\n                                  71, 64, 14, 2, 30, 40, 0, 8, 17, 21, 5, 19,\n                                  36, 4, 64, 27, 75, 106, 126, 126, 126, 126,\n                                  126, 126, 6, 39, 30, 27, 17, 31, 17, 9, 7, 1,\n                                  72, 67, 11, 2, 24, 34, 2, 4, 11, 15, 6, 13,\n                                  28, 7, 0, 27, 75, 106, 126, 126, 126, 126,\n                                  126, 126 },\n\n                                {\n\n                                22,\n                                  4, 82, 22, 4, 82, 15, 24, 27, 12, 70, 86, 95,\n                                  18, 60, 11, 27, 70, 9, 21, 66, 75, 2, 82, 107,\n                                  75, 112, 126, 126, 126, 62, 5, 64, 9, 21, 66,\n                                  85, 10, 11, 65, 0, 67, 67, 64, 80, 78, 91, 5,\n                                  65, 68, 4, 72, 66, 80, 0, 74, 72, 80, 6, 2,\n                                  22, 0, 0, 0, 6, 97, 97, 11, 77, 70, 12, 70,\n                                  85, 46, 23, 15, 56, 62, 29, 31, 20, 32, 13,\n                                  12, 38, 80, 74, 74, 80, 24, 65, 22, 35, 67,\n                                  70, 65, 24, 0, 75, 74, 83, 19, 68, 9, 1, 66,\n                                  9, 0, 11, 10, 10, 18, 26, 14, 8, 12, 62, 62,\n                                  62, 62, 9, 0, 4, 14, 64, 11, 13, 5, 66, 40,\n                                  66, 110, 106, 60, 9, 17, 5, 6, 11, 19, 50, 29,\n                                  13, 66, 1, 2, 20, 24, 105, 4, 5, 80, 66, 75,\n                                  6, 6, 72, 19, 12, 12, 91, 9, 80, 75, 4, 89, 7,\n                                  7, 4, 81, 103, 65, 78, 76, 81, 95, 91, 78,\n                                  126, 62, 126, 88, 91, 99, 114, 100, 112, 126,\n                                  125, 118, 97, 125, 91, 62, 111, 67, 65, 73,\n                                  78, 79, 77, 82, 81, 82, 98, 98, 94, 96, 98,\n                                  122, 75, 77, 99, 74, 81, 82, 89, 92, 98, 95,\n                                  101, 99, 85, 101, 103, 95, 87, 16, 35, 22, 10,\n                                  12, 17, 9, 5, 5, 32, 22, 33, 25, 22, 19, 29,\n                                  20, 27, 23, 20, 18, 48, 40, 35, 31, 36, 14, 6,\n                                  4, 3, 71, 55, 29, 2, 66, 14, 2, 73, 66, 3, 40,\n                                  27, 8, 64, 18, 5, 5, 67, 66, 62, 66, 4, 10,\n                                  11, 10, 6, 18, 22, 9, 20, 23, 34, 66, 3, 72,\n                                  0, 28, 72, 74, 70, 4, 5, 69, 78, 69, 81, 69,\n                                  71, 88, 14, 13, 31, 5, 66, 13, 8, 1, 7, 6, 1,\n                                  76, 0, 65, 69, 67, 17, 99, 82, 16, 85, 67, 74,\n                                  69, 10, 74, 77, 4, 5, 93, 74, 100, 16, 19, 24,\n                                  2, 71, 67, 70, 76, 79, 88, 90, 90, 103, 98,\n                                  99, 123, 114, 121, 126, 112, 111, 105, 101,\n                                  111, 98, 104, 101, 88, 95, 71, 73, 75, 76, 96,\n                                  88, 88, 108, 94, 102, 103, 124, 107, 111, 114,\n                                  81, 79, 118, 83, 86, 96, 112, 101, 108, 109,\n                                  92, 109, 100, 103, 113, 110, 113, 102, 108,\n                                  113, 70, 64, 15, 2, 31, 41, 1, 9, 18, 22, 5,\n                                  20, 37, 4, 64, 26, 77, 109, 126, 126, 126,\n                                  126, 126, 126, 7, 39, 30, 27, 17, 32, 17, 10,\n                                  8, 1, 72, 67, 11, 2, 25, 35, 2, 4, 12, 16, 6,\n                                  14, 29, 7, 0, 26, 77, 109, 126, 126, 126, 126,\n                                  126, 126 },\n\n                                {\n\n                                21,\n                                  4, 82, 21, 4, 82, 17, 26, 28, 12, 71, 88, 97,\n                                  17, 60, 11, 29, 70, 10, 22, 66, 75, 2, 82,\n                                  108, 76, 115, 126, 126, 126, 62, 6, 64, 10,\n                                  22, 66, 86, 11, 11, 66, 0, 67, 67, 64, 80, 78,\n                                  91, 5, 65, 67, 4, 72, 65, 80, 0, 74, 72, 80,\n                                  6, 2, 22, 0, 0, 0, 6, 97, 97, 12, 78, 70, 11,\n                                  71, 85, 49, 24, 16, 57, 62, 30, 33, 22, 33,\n                                  14, 13, 40, 80, 74, 73, 80, 24, 65, 23, 37,\n                                  67, 69, 65, 26, 0, 76, 75, 84, 19, 68, 10, 1,\n                                  65, 10, 0, 12, 10, 11, 20, 27, 14, 9, 13, 62,\n                                  62, 62, 62, 9, 0, 4, 14, 64, 11, 14, 6, 66,\n                                  42, 66, 112, 108, 62, 9, 17, 5, 6, 11, 19, 51,\n                                  30, 13, 66, 1, 2, 20, 25, 106, 4, 5, 81, 66,\n                                  76, 6, 6, 72, 19, 12, 12, 92, 9, 81, 76, 4,\n                                  89, 7, 7, 4, 83, 106, 66, 80, 78, 84, 97, 94,\n                                  80, 126, 62, 126, 90, 93, 101, 117, 103, 115,\n                                  126, 126, 121, 99, 126, 93, 62, 113, 69, 67,\n                                  75, 81, 82, 79, 84, 83, 84, 100, 100, 96, 98,\n                                  99, 124, 75, 77, 100, 75, 82, 83, 90, 93, 99,\n                                  96, 103, 100, 86, 102, 104, 95, 87, 18, 36,\n                                  23, 10, 12, 18, 9, 5, 5, 34, 23, 33, 25, 23,\n                                  20, 30, 21, 28, 24, 22, 19, 48, 40, 35, 31,\n                                  37, 15, 6, 4, 3, 71, 55, 29, 1, 66, 14, 2, 73,\n                                  66, 3, 39, 27, 7, 65, 18, 5, 5, 67, 66, 62,\n                                  65, 6, 11, 12, 11, 7, 20, 24, 10, 21, 25, 36,\n                                  66, 4, 72, 1, 30, 71, 74, 70, 4, 5, 69, 78,\n                                  69, 81, 69, 71, 89, 15, 14, 32, 5, 66, 14, 8,\n                                  1, 7, 6, 1, 76, 0, 65, 69, 67, 17, 100, 83,\n                                  16, 86, 68, 75, 69, 10, 75, 78, 4, 5, 94, 74,\n                                  101, 15, 18, 23, 1, 73, 69, 72, 78, 82, 90,\n                                  93, 93, 106, 100, 101, 126, 118, 125, 126,\n                                  116, 114, 107, 103, 114, 100, 106, 103, 89,\n                                  96, 73, 76, 78, 79, 99, 90, 91, 111, 97, 105,\n                                  106, 126, 109, 113, 115, 82, 80, 119, 85, 88,\n                                  98, 114, 102, 110, 111, 93, 110, 101, 104,\n                                  114, 111, 114, 103, 109, 114, 70, 0, 15, 3,\n                                  32, 42, 1, 9, 18, 22, 5, 20, 38, 4, 64, 25,\n                                  79, 111, 126, 126, 126, 126, 126, 126, 7, 39,\n                                  30, 27, 17, 32, 18, 10, 8, 2, 72, 67, 12, 3,\n                                  26, 36, 2, 5, 12, 16, 6, 14, 29, 7, 0, 25, 79,\n                                  111, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                20,\n                                  4, 82, 20, 4, 82, 19, 27, 28, 12, 71, 89, 99,\n                                  16, 60, 11, 31, 70, 10, 23, 66, 76, 2, 83,\n                                  110, 77, 117, 126, 126, 126, 62, 7, 64, 10,\n                                  23, 66, 86, 12, 11, 66, 0, 67, 66, 64, 80, 78,\n                                  91, 5, 65, 67, 4, 72, 65, 80, 0, 74, 72, 80,\n                                  6, 2, 22, 0, 0, 0, 7, 97, 97, 12, 79, 70, 10,\n                                  71, 85, 51, 25, 17, 59, 62, 32, 34, 24, 35,\n                                  15, 14, 42, 80, 74, 73, 80, 24, 65, 24, 39,\n                                  67, 68, 64, 28, 0, 76, 75, 84, 19, 68, 10, 2,\n                                  64, 11, 1, 13, 11, 12, 21, 29, 15, 10, 14, 62,\n                                  62, 62, 62, 9, 0, 4, 15, 64, 11, 14, 6, 65,\n                                  44, 66, 114, 110, 62, 9, 17, 5, 6, 11, 20, 53,\n                                  31, 13, 66, 1, 2, 21, 26, 107, 4, 5, 81, 67,\n                                  77, 5, 6, 73, 19, 12, 12, 93, 9, 82, 77, 3,\n                                  89, 7, 6, 3, 85, 109, 67, 82, 80, 86, 99, 96,\n                                  82, 126, 62, 126, 92, 95, 103, 120, 105, 118,\n                                  126, 126, 124, 101, 126, 95, 62, 115, 71, 69,\n                                  77, 83, 84, 81, 86, 85, 86, 102, 102, 98, 100,\n                                  101, 126, 75, 77, 100, 76, 83, 84, 91, 94,\n                                  100, 97, 105, 101, 86, 103, 105, 96, 86, 19,\n                                  37, 23, 10, 12, 19, 10, 6, 6, 36, 24, 33, 25,\n                                  23, 21, 31, 22, 30, 26, 24, 20, 49, 41, 36,\n                                  32, 38, 15, 6, 4, 4, 71, 56, 29, 0, 66, 14, 2,\n                                  73, 65, 3, 39, 26, 6, 66, 18, 5, 5, 67, 66,\n                                  62, 64, 7, 12, 14, 13, 8, 22, 26, 11, 23, 27,\n                                  38, 65, 5, 71, 2, 32, 71, 74, 70, 5, 6, 69,\n                                  78, 69, 82, 69, 71, 89, 15, 14, 33, 5, 66, 14,\n                                  8, 1, 7, 6, 1, 77, 0, 65, 69, 67, 18, 101, 84,\n                                  16, 87, 69, 76, 70, 10, 76, 79, 4, 5, 95, 74,\n                                  102, 14, 17, 22, 64, 75, 71, 74, 80, 84, 93,\n                                  96, 96, 109, 103, 103, 126, 122, 126, 126,\n                                  119, 117, 110, 105, 116, 102, 108, 104, 90,\n                                  97, 75, 78, 80, 81, 102, 93, 93, 114, 99, 107,\n                                  108, 126, 111, 115, 117, 83, 81, 121, 86, 89,\n                                  100, 116, 104, 112, 113, 94, 112, 102, 105,\n                                  115, 112, 115, 105, 110, 115, 70, 0, 16, 3,\n                                  33, 43, 1, 10, 19, 23, 5, 21, 39, 4, 64, 24,\n                                  81, 114, 126, 126, 126, 126, 126, 126, 7, 39,\n                                  30, 27, 17, 33, 18, 10, 8, 2, 72, 67, 12, 3,\n                                  27, 37, 2, 5, 12, 16, 6, 14, 30, 7, 0, 24, 81,\n                                  114, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                18,\n                                  3, 83, 18, 3, 83, 20, 28, 28, 12, 72, 91, 102,\n                                  15, 60, 10, 32, 71, 10, 23, 67, 77, 2, 84,\n                                  112, 79, 120, 126, 126, 126, 62, 7, 64, 10,\n                                  23, 67, 87, 12, 11, 67, 0, 67, 66, 65, 81, 78,\n                                  91, 4, 65, 67, 4, 72, 65, 80, 0, 74, 73, 80,\n                                  6, 2, 22, 0, 0, 0, 7, 98, 97, 12, 80, 71, 9,\n                                  72, 86, 53, 26, 18, 60, 62, 33, 35, 25, 36,\n                                  16, 15, 44, 80, 74, 73, 80, 24, 65, 24, 41,\n                                  67, 68, 64, 29, 64, 77, 76, 85, 19, 68, 10, 2,\n                                  64, 11, 1, 13, 11, 12, 22, 30, 15, 11, 15, 62,\n                                  62, 62, 62, 9, 0, 4, 15, 65, 11, 14, 6, 65,\n                                  46, 66, 116, 112, 62, 9, 17, 5, 6, 11, 20, 54,\n                                  31, 13, 67, 0, 2, 21, 26, 109, 4, 5, 82, 68,\n                                  79, 4, 5, 74, 19, 12, 11, 95, 9, 83, 78, 2,\n                                  89, 6, 5, 2, 88, 113, 69, 84, 83, 89, 102, 99,\n                                  84, 126, 62, 126, 95, 97, 106, 124, 108, 122,\n                                  126, 126, 126, 103, 126, 97, 62, 117, 74, 72,\n                                  80, 86, 87, 84, 89, 88, 88, 105, 105, 100,\n                                  102, 103, 126, 75, 78, 101, 77, 85, 86, 93,\n                                  96, 102, 99, 107, 102, 87, 104, 106, 97, 86,\n                                  20, 37, 23, 10, 12, 19, 10, 6, 6, 38, 25, 33,\n                                  25, 23, 21, 31, 23, 31, 27, 25, 20, 49, 41,\n                                  36, 32, 39, 15, 6, 4, 4, 72, 56, 28, 64, 67,\n                                  14, 2, 73, 65, 2, 38, 25, 4, 67, 17, 5, 5, 67,\n                                  66, 62, 0, 8, 13, 15, 14, 9, 23, 27, 12, 24,\n                                  28, 40, 65, 5, 71, 3, 33, 71, 74, 70, 5, 6,\n                                  69, 79, 70, 83, 69, 72, 90, 15, 14, 34, 5, 67,\n                                  14, 8, 0, 7, 6, 1, 78, 0, 65, 69, 67, 18, 102,\n                                  85, 16, 89, 70, 77, 71, 9, 77, 80, 4, 4, 97,\n                                  75, 104, 12, 15, 21, 66, 77, 74, 77, 83, 87,\n                                  96, 99, 99, 113, 106, 105, 126, 126, 126, 126,\n                                  123, 121, 113, 108, 119, 104, 110, 106, 91,\n                                  98, 78, 81, 83, 84, 105, 96, 96, 118, 102,\n                                  110, 111, 126, 113, 117, 119, 84, 82, 123, 88,\n                                  91, 102, 119, 106, 114, 115, 96, 114, 104,\n                                  106, 117, 113, 116, 107, 112, 117, 70, 0, 16,\n                                  3, 34, 44, 1, 10, 19, 23, 5, 21, 39, 4, 65,\n                                  22, 83, 117, 126, 126, 126, 126, 126, 126, 7,\n                                  39, 30, 27, 17, 33, 18, 10, 8, 2, 72, 67, 12,\n                                  3, 27, 37, 2, 5, 12, 16, 6, 14, 30, 6, 64, 22,\n                                  83, 117, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                17,\n                                  3, 83, 17, 3, 83, 22, 30, 29, 13, 72, 92, 104,\n                                  14, 61, 10, 34, 71, 11, 24, 67, 77, 3, 84,\n                                  113, 80, 122, 126, 126, 126, 62, 8, 0, 11, 24,\n                                  67, 87, 13, 11, 67, 1, 66, 65, 65, 81, 77, 90,\n                                  4, 64, 66, 4, 71, 64, 79, 1, 73, 73, 79, 7, 2,\n                                  22, 0, 0, 0, 8, 98, 97, 13, 80, 71, 9, 72, 86,\n                                  56, 28, 20, 62, 62, 35, 37, 27, 38, 18, 17,\n                                  47, 80, 73, 72, 79, 24, 65, 25, 44, 66, 67, 0,\n                                  31, 64, 77, 76, 85, 20, 68, 11, 3, 0, 12, 2,\n                                  14, 12, 13, 24, 32, 16, 13, 17, 62, 62, 62,\n                                  62, 10, 1, 5, 16, 65, 12, 15, 7, 64, 49, 65,\n                                  118, 113, 62, 9, 18, 5, 7, 12, 21, 56, 32, 14,\n                                  67, 0, 2, 22, 27, 110, 5, 5, 82, 68, 80, 4, 5,\n                                  74, 19, 12, 11, 96, 10, 83, 78, 2, 89, 6, 5,\n                                  2, 90, 116, 70, 85, 85, 91, 104, 101, 86, 126,\n                                  62, 126, 97, 98, 108, 126, 110, 125, 126, 126,\n                                  126, 105, 126, 99, 62, 118, 76, 74, 82, 88,\n                                  89, 86, 91, 90, 90, 107, 107, 101, 103, 104,\n                                  126, 75, 78, 101, 77, 86, 87, 94, 97, 103,\n                                  100, 108, 103, 87, 105, 106, 97, 85, 22, 38,\n                                  24, 10, 13, 20, 11, 7, 7, 41, 27, 34, 26, 24,\n                                  22, 32, 25, 33, 29, 27, 21, 50, 42, 37, 33,\n                                  40, 16, 7, 5, 5, 72, 57, 28, 64, 67, 15, 3,\n                                  73, 64, 2, 38, 25, 3, 68, 17, 6, 6, 66, 65,\n                                  62, 2, 10, 15, 17, 16, 11, 25, 29, 14, 26, 30,\n                                  43, 64, 6, 70, 5, 35, 70, 73, 69, 6, 7, 68,\n                                  79, 70, 83, 69, 72, 90, 16, 15, 35, 6, 67, 15,\n                                  9, 0, 8, 7, 1, 78, 1, 64, 68, 66, 19, 102, 86,\n                                  16, 90, 70, 77, 71, 9, 77, 80, 4, 4, 98, 75,\n                                  105, 11, 14, 21, 67, 78, 76, 79, 85, 89, 98,\n                                  101, 101, 116, 108, 107, 126, 126, 126, 126,\n                                  126, 124, 115, 110, 121, 105, 111, 107, 91,\n                                  98, 80, 83, 85, 86, 107, 98, 98, 121, 104,\n                                  112, 113, 126, 114, 118, 120, 84, 82, 124, 89,\n                                  92, 103, 121, 107, 115, 116, 97, 115, 105,\n                                  106, 118, 113, 116, 108, 113, 118, 69, 1, 17,\n                                  4, 36, 46, 2, 11, 20, 24, 6, 22, 40, 4, 65,\n                                  21, 85, 119, 126, 126, 126, 126, 126, 126, 8,\n                                  39, 31, 28, 18, 34, 19, 11, 9, 3, 71, 66, 13,\n                                  4, 28, 38, 3, 6, 13, 17, 6, 15, 31, 6, 64, 21,\n                                  85, 119, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                16,\n                                  3, 83, 16, 3, 83, 24, 31, 29, 13, 72, 93, 106,\n                                  13, 61, 10, 36, 71, 11, 25, 67, 78, 3, 85,\n                                  115, 81, 125, 126, 126, 126, 62, 9, 0, 11, 25,\n                                  67, 87, 14, 11, 68, 1, 66, 64, 65, 81, 77, 90,\n                                  4, 64, 66, 4, 71, 64, 79, 1, 73, 73, 79, 7, 2,\n                                  22, 0, 0, 0, 9, 98, 97, 13, 81, 71, 8, 72, 86,\n                                  58, 29, 21, 62, 62, 36, 38, 29, 39, 19, 18,\n                                  49, 80, 73, 72, 79, 24, 65, 26, 46, 66, 66, 1,\n                                  33, 64, 77, 76, 86, 20, 68, 11, 4, 1, 13, 3,\n                                  15, 12, 14, 25, 33, 17, 14, 18, 62, 62, 62,\n                                  62, 10, 1, 5, 16, 65, 12, 15, 7, 64, 51, 65,\n                                  120, 115, 62, 9, 18, 5, 7, 12, 21, 58, 33, 14,\n                                  67, 0, 2, 23, 28, 111, 5, 5, 82, 69, 81, 3, 5,\n                                  75, 19, 12, 11, 97, 10, 84, 79, 1, 89, 6, 4,\n                                  1, 92, 119, 71, 87, 87, 93, 106, 103, 88, 126,\n                                  62, 126, 99, 100, 110, 126, 112, 126, 126,\n                                  126, 126, 107, 126, 101, 62, 120, 78, 76, 84,\n                                  90, 91, 88, 93, 92, 92, 109, 109, 103, 105,\n                                  106, 126, 75, 78, 102, 78, 87, 88, 95, 98,\n                                  104, 101, 110, 104, 87, 106, 107, 98, 84, 23,\n                                  39, 24, 10, 13, 21, 12, 8, 8, 43, 28, 34, 26,\n                                  24, 23, 33, 26, 35, 31, 29, 22, 51, 43, 38,\n                                  34, 41, 16, 7, 5, 6, 72, 58, 28, 65, 67, 15,\n                                  3, 73, 64, 2, 38, 24, 2, 69, 17, 6, 6, 66, 65,\n                                  62, 3, 11, 16, 19, 18, 12, 27, 31, 15, 28, 32,\n                                  45, 0, 7, 70, 6, 37, 70, 73, 69, 7, 7, 68, 79,\n                                  70, 84, 69, 72, 90, 16, 15, 36, 6, 67, 15, 9,\n                                  0, 8, 7, 1, 79, 1, 64, 68, 66, 20, 103, 87,\n                                  16, 91, 71, 78, 72, 9, 78, 81, 4, 4, 99, 75,\n                                  106, 10, 13, 20, 69, 80, 78, 81, 87, 91, 101,\n                                  104, 104, 119, 111, 109, 126, 126, 126, 126,\n                                  126, 126, 118, 112, 124, 107, 113, 108, 92,\n                                  99, 82, 85, 88, 88, 110, 101, 101, 124, 106,\n                                  115, 115, 126, 116, 120, 122, 85, 83, 126, 90,\n                                  93, 105, 123, 109, 117, 118, 98, 117, 106,\n                                  107, 119, 114, 117, 110, 114, 119, 69, 1, 18,\n                                  4, 37, 47, 2, 12, 21, 25, 6, 22, 41, 4, 65,\n                                  20, 87, 122, 126, 126, 126, 126, 126, 126, 8,\n                                  39, 31, 28, 18, 35, 19, 11, 9, 3, 71, 66, 13,\n                                  4, 29, 39, 3, 6, 13, 17, 6, 15, 32, 6, 64, 20,\n                                  87, 122, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                15,\n                                  3, 83, 15, 3, 83, 26, 33, 30, 13, 73, 95, 108,\n                                  12, 61, 10, 38, 71, 12, 26, 67, 78, 3, 85,\n                                  116, 82, 126, 126, 126, 126, 62, 10, 0, 12,\n                                  26, 67, 88, 15, 11, 68, 1, 66, 64, 65, 81, 77,\n                                  90, 4, 64, 65, 4, 71, 0, 79, 1, 73, 73, 79, 7,\n                                  2, 22, 0, 0, 0, 9, 98, 97, 14, 82, 71, 7, 73,\n                                  86, 61, 30, 22, 62, 62, 38, 40, 31, 41, 20,\n                                  19, 51, 80, 73, 71, 79, 24, 65, 27, 48, 66,\n                                  65, 1, 35, 64, 78, 77, 86, 20, 68, 12, 4, 2,\n                                  14, 3, 16, 13, 15, 27, 35, 17, 15, 19, 62, 62,\n                                  62, 62, 10, 1, 5, 17, 65, 12, 16, 8, 0, 53,\n                                  65, 122, 117, 62, 9, 18, 5, 7, 12, 22, 59, 34,\n                                  14, 67, 0, 2, 23, 29, 112, 5, 5, 83, 69, 82,\n                                  3, 5, 75, 19, 12, 11, 98, 10, 85, 80, 1, 89,\n                                  6, 4, 1, 94, 122, 72, 89, 89, 96, 108, 106,\n                                  90, 126, 62, 126, 101, 102, 112, 126, 115,\n                                  126, 126, 126, 126, 109, 126, 103, 62, 122,\n                                  80, 78, 86, 93, 94, 90, 95, 94, 94, 111, 111,\n                                  105, 107, 107, 126, 75, 78, 102, 79, 88, 89,\n                                  96, 99, 105, 102, 112, 105, 88, 107, 108, 98,\n                                  84, 25, 40, 25, 10, 13, 22, 12, 8, 8, 45, 29,\n                                  34, 26, 25, 24, 34, 27, 36, 32, 31, 23, 51,\n                                  43, 38, 34, 42, 17, 7, 5, 6, 72, 58, 28, 66,\n                                  67, 15, 3, 73, 0, 2, 37, 24, 1, 70, 17, 6, 6,\n                                  66, 65, 62, 4, 13, 17, 20, 19, 13, 29, 33, 16,\n                                  29, 34, 47, 0, 8, 69, 7, 39, 69, 73, 69, 7, 8,\n                                  68, 79, 70, 84, 69, 72, 91, 17, 16, 37, 6, 67,\n                                  16, 9, 0, 8, 7, 1, 79, 1, 64, 68, 66, 20, 104,\n                                  88, 16, 92, 72, 79, 72, 9, 79, 82, 4, 4, 100,\n                                  75, 107, 9, 12, 19, 70, 82, 80, 83, 89, 94,\n                                  103, 107, 107, 122, 113, 111, 126, 126, 126,\n                                  126, 126, 126, 120, 114, 126, 109, 115, 110,\n                                  93, 100, 84, 88, 90, 91, 113, 103, 103, 126,\n                                  109, 117, 118, 126, 118, 122, 123, 86, 84,\n                                  126, 92, 95, 107, 125, 110, 119, 120, 99, 118,\n                                  107, 108, 120, 115, 118, 111, 115, 120, 69, 2,\n                                  18, 5, 38, 48, 2, 12, 21, 25, 6, 23, 42, 4,\n                                  65, 19, 89, 124, 126, 126, 126, 126, 126, 126,\n                                  8, 39, 31, 28, 18, 35, 20, 11, 9, 4, 71, 66,\n                                  14, 5, 30, 40, 3, 7, 13, 17, 6, 15, 32, 6, 64,\n                                  19, 89, 124, 126, 126, 126, 126, 126, 126 },\n\n                          },\n\n                          {\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 126, 104, 10, 9, 12, 47, 62,\n                                62, 12, 1, 99, 47, 85, 102, 6, 6, 73, 6, 23, 53,\n                                62, 62, 21, 97, 126, 117, 74, 85, 102, 6, 93,\n                                88, 19, 8, 89, 103, 116, 6, 5, 84, 96, 0, 85,\n                                106, 0, 75, 90, 101, 8, 79, 75, 97, 13, 3, 22,\n                                0, 0, 0, 83, 86, 97, 72, 22, 1, 29, 88, 126,\n                                126, 91, 95, 84, 86, 89, 91, 126, 76, 103, 90,\n                                126, 80, 76, 84, 78, 8, 2, 83, 126, 79, 104, 91,\n                                126, 65, 79, 72, 92, 7, 68, 71, 98, 86, 88, 82,\n                                72, 67, 72, 89, 69, 4, 66, 6, 71, 71, 5, 74, 19,\n                                69, 1, 12, 16, 21, 22, 10, 76, 78, 83, 11, 67,\n                                90, 67, 72, 75, 80, 83, 64, 32, 64, 94, 75, 0,\n                                74, 28, 36, 91, 65, 69, 77, 66, 1, 68, 81, 33,\n                                56, 40, 74, 66, 124, 26, 62, 62, 126, 24, 21,\n                                29, 34, 32, 26, 21, 23, 30, 20, 27, 16, 8, 5, 3,\n                                19, 19, 21, 15, 7, 11, 26, 14, 5, 15, 18, 69,\n                                30, 0, 62, 62, 62, 53, 62, 62, 62, 62, 46, 38,\n                                34, 30, 48, 43, 73, 29, 32, 19, 47, 27, 27, 35,\n                                42, 43, 51, 47, 21, 93, 7, 6, 25, 126, 115, 82,\n                                1, 10, 4, 85, 89, 94, 92, 126, 100, 6, 67, 71,\n                                77, 85, 88, 104, 98, 126, 82, 15, 2, 66, 70, 75,\n                                79, 83, 92, 108, 79, 69, 75, 5, 5, 78, 83, 81,\n                                99, 81, 25, 1, 5, 4, 73, 76, 86, 83, 87, 62,\n                                126, 126, 120, 126, 114, 117, 118, 117, 113,\n                                118, 120, 124, 94, 102, 99, 106, 126, 92, 6, 86,\n                                94, 91, 77, 71, 73, 64, 81, 64, 6, 67, 68, 67,\n                                68, 77, 64, 68, 78, 8, 4, 65, 9, 19, 3, 70, 76,\n                                86, 70, 64, 70, 8, 7, 69, 65, 74, 9, 9, 76, 82,\n                                77, 77, 21, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 62, 62, 62, 52, 62, 62, 62, 62, 62, 62,\n                                48, 62, 62, 46, 25, 18, 9, 79, 62, 62, 62, 62,\n                                48, 48, 38, 41, 47, 45, 35, 22, 35, 16, 1, 32,\n                                37, 39, 40, 47, 33, 34, 22, 21, 3, 11, 3, 78,\n                                123, 10, 7, 2, 30, 13, 2, 78, 74, 72, 72, 75,\n                                71, 0, 70, 75, 72, 67, 10, 4, 11, 68, 62, 62,\n                                62, 62, 56, 51, 40, 25, 64, 71, 26, 19, 14, 7,\n                                4, 0, 67, 68, 79, 78, 74, 72, 72, 75, 71, 0, 70,\n                                75, 72, 67, 10, 4, 11, 68, 62, 62, 62, 62, 56,\n                                51, 40, 25, 64 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 125, 102, 11, 10, 12, 46,\n                                  62, 62, 13, 2, 97, 46, 84, 100, 6, 6, 71, 6,\n                                  22, 52, 62, 60, 19, 97, 125, 115, 73, 84, 100,\n                                  6, 92, 87, 20, 8, 88, 102, 114, 5, 4, 84, 96,\n                                  0, 84, 105, 0, 75, 89, 100, 8, 78, 74, 96, 14,\n                                  3, 22, 0, 0, 0, 82, 86, 97, 71, 22, 1, 29, 87,\n                                  125, 124, 89, 94, 82, 84, 88, 89, 125, 75,\n                                  101, 89, 124, 80, 76, 84, 78, 9, 2, 82, 124,\n                                  78, 103, 90, 125, 65, 78, 72, 91, 8, 68, 70,\n                                  97, 85, 87, 81, 71, 66, 71, 88, 68, 5, 66, 6,\n                                  70, 70, 5, 73, 20, 68, 1, 13, 17, 22, 23, 11,\n                                  76, 77, 82, 11, 67, 89, 67, 71, 74, 79, 81, 1,\n                                  33, 1, 92, 75, 64, 73, 29, 37, 91, 65, 68, 77,\n                                  65, 1, 67, 79, 33, 56, 41, 72, 67, 122, 25,\n                                  62, 62, 125, 24, 21, 29, 34, 32, 26, 21, 23,\n                                  30, 20, 27, 16, 8, 5, 3, 19, 19, 21, 15, 7,\n                                  11, 26, 14, 4, 15, 18, 69, 29, 0, 62, 62, 62,\n                                  52, 62, 62, 62, 62, 45, 37, 32, 29, 46, 42,\n                                  74, 28, 31, 18, 46, 27, 27, 34, 41, 42, 50,\n                                  46, 20, 93, 7, 6, 24, 125, 113, 80, 2, 10, 4,\n                                  84, 88, 93, 91, 125, 98, 7, 66, 70, 76, 83,\n                                  87, 102, 97, 124, 81, 16, 3, 65, 69, 74, 78,\n                                  82, 91, 106, 78, 67, 74, 6, 5, 77, 82, 80, 98,\n                                  80, 26, 2, 6, 5, 72, 75, 85, 82, 86, 62, 125,\n                                  125, 118, 125, 112, 115, 116, 115, 111, 116,\n                                  118, 121, 93, 101, 98, 105, 123, 91, 5, 85,\n                                  93, 90, 76, 71, 72, 64, 80, 64, 6, 67, 68, 66,\n                                  68, 77, 64, 68, 77, 8, 4, 65, 9, 19, 3, 70,\n                                  75, 84, 70, 64, 69, 8, 7, 69, 65, 73, 9, 9,\n                                  75, 81, 76, 76, 20, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 50, 62, 62,\n                                  62, 62, 62, 62, 47, 60, 60, 45, 24, 17, 9, 79,\n                                  62, 62, 62, 60, 46, 47, 37, 39, 46, 43, 34,\n                                  20, 33, 15, 0, 31, 36, 37, 39, 46, 32, 33, 21,\n                                  20, 2, 11, 3, 78, 122, 9, 6, 1, 29, 12, 1, 77,\n                                  73, 71, 71, 73, 70, 1, 69, 73, 71, 66, 11, 5,\n                                  12, 67, 62, 62, 62, 62, 54, 50, 38, 24, 65,\n                                  70, 27, 20, 15, 8, 5, 1, 66, 67, 78, 77, 73,\n                                  71, 71, 73, 70, 1, 69, 73, 71, 66, 11, 5, 12,\n                                  67, 62, 62, 62, 62, 54, 50, 38, 24, 65 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 123, 101, 11, 10, 12, 44,\n                                  60, 62, 14, 2, 95, 44, 84, 99, 6, 6, 70, 5,\n                                  21, 51, 60, 57, 17, 98, 123, 114, 73, 84, 99,\n                                  6, 92, 86, 20, 8, 87, 101, 113, 4, 3, 84, 96,\n                                  0, 84, 104, 0, 75, 89, 100, 8, 78, 74, 95, 14,\n                                  3, 22, 0, 0, 0, 81, 86, 97, 71, 21, 1, 29, 86,\n                                  124, 122, 88, 93, 80, 82, 87, 88, 123, 74,\n                                  100, 88, 122, 81, 76, 84, 78, 9, 2, 81, 122,\n                                  78, 102, 89, 123, 65, 78, 72, 91, 8, 68, 70,\n                                  96, 85, 86, 81, 71, 66, 71, 87, 67, 5, 66, 6,\n                                  70, 70, 5, 73, 20, 68, 1, 13, 17, 22, 23, 11,\n                                  77, 76, 81, 10, 67, 89, 67, 70, 74, 79, 80, 2,\n                                  34, 3, 90, 76, 65, 73, 29, 37, 92, 65, 68, 78,\n                                  64, 1, 67, 78, 33, 56, 41, 71, 68, 121, 24,\n                                  62, 62, 124, 24, 21, 29, 33, 31, 26, 21, 23,\n                                  29, 19, 26, 16, 8, 5, 3, 18, 18, 20, 15, 7,\n                                  11, 25, 13, 3, 14, 17, 69, 28, 64, 62, 62, 62,\n                                  50, 60, 62, 62, 62, 44, 35, 30, 27, 44, 40,\n                                  75, 27, 30, 16, 45, 26, 26, 33, 39, 40, 48,\n                                  44, 18, 93, 6, 5, 22, 124, 112, 79, 3, 10, 4,\n                                  83, 87, 92, 90, 123, 97, 8, 65, 69, 75, 82,\n                                  86, 101, 96, 122, 80, 16, 3, 65, 69, 73, 77,\n                                  81, 90, 105, 78, 66, 73, 6, 5, 76, 81, 80, 97,\n                                  79, 26, 3, 6, 5, 71, 74, 84, 81, 85, 62, 124,\n                                  123, 116, 123, 111, 114, 114, 113, 110, 114,\n                                  116, 119, 92, 100, 97, 104, 120, 91, 4, 85,\n                                  92, 89, 76, 71, 72, 64, 80, 64, 5, 67, 68, 65,\n                                  68, 77, 64, 68, 77, 8, 4, 65, 8, 18, 3, 70,\n                                  75, 83, 71, 64, 68, 7, 7, 69, 65, 73, 9, 9,\n                                  75, 80, 76, 76, 18, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 48, 62, 62,\n                                  62, 62, 62, 61, 45, 58, 58, 43, 23, 16, 8, 79,\n                                  62, 62, 62, 58, 44, 45, 35, 37, 44, 41, 32,\n                                  18, 31, 13, 64, 30, 35, 35, 37, 44, 30, 31,\n                                  20, 19, 1, 10, 2, 78, 121, 8, 5, 64, 28, 11,\n                                  0, 77, 73, 70, 70, 72, 69, 2, 69, 72, 70, 65,\n                                  11, 6, 13, 66, 62, 62, 62, 60, 52, 48, 36, 22,\n                                  66, 69, 27, 20, 16, 9, 6, 1, 65, 67, 77, 77,\n                                  73, 70, 70, 72, 69, 2, 69, 72, 70, 65, 11, 6,\n                                  13, 66, 62, 62, 62, 60, 52, 48, 36, 22, 66 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 121, 99, 12, 10, 11, 42, 59,\n                                  61, 14, 2, 93, 43, 84, 97, 6, 5, 69, 4, 20,\n                                  50, 58, 53, 15, 99, 121, 112, 73, 84, 97, 6,\n                                  91, 85, 21, 8, 86, 100, 112, 3, 2, 84, 97, 0,\n                                  84, 103, 0, 76, 89, 100, 8, 78, 74, 94, 15, 3,\n                                  22, 0, 0, 0, 81, 86, 97, 70, 20, 1, 28, 86,\n                                  123, 120, 87, 92, 79, 81, 86, 87, 121, 73, 99,\n                                  87, 120, 82, 76, 84, 78, 10, 2, 80, 120, 78,\n                                  101, 88, 121, 65, 78, 72, 91, 9, 68, 69, 95,\n                                  85, 85, 81, 71, 66, 70, 86, 67, 5, 66, 6, 70,\n                                  70, 5, 73, 20, 68, 1, 14, 17, 23, 23, 12, 77,\n                                  76, 80, 10, 67, 89, 67, 69, 74, 78, 79, 3, 35,\n                                  4, 88, 76, 66, 72, 29, 37, 93, 65, 67, 78, 64,\n                                  1, 67, 77, 33, 56, 41, 70, 69, 119, 23, 62,\n                                  62, 122, 24, 21, 28, 32, 31, 25, 20, 23, 29,\n                                  18, 25, 16, 8, 5, 2, 18, 17, 19, 14, 7, 11,\n                                  24, 13, 2, 14, 16, 69, 27, 64, 62, 62, 61, 49,\n                                  58, 62, 62, 62, 43, 33, 28, 26, 42, 38, 77,\n                                  26, 29, 14, 44, 25, 25, 32, 38, 38, 46, 42,\n                                  17, 93, 5, 4, 21, 122, 110, 77, 3, 10, 4, 82,\n                                  86, 91, 89, 121, 96, 9, 64, 68, 75, 81, 85,\n                                  99, 95, 120, 80, 17, 4, 64, 68, 72, 77, 81,\n                                  89, 104, 78, 64, 72, 6, 5, 75, 81, 80, 96, 78,\n                                  27, 4, 7, 5, 70, 74, 83, 81, 85, 62, 122, 122,\n                                  115, 121, 110, 112, 113, 112, 108, 112, 114,\n                                  117, 92, 99, 97, 103, 117, 91, 3, 85, 91, 88,\n                                  76, 71, 72, 64, 79, 64, 4, 67, 68, 65, 68, 77,\n                                  64, 68, 77, 7, 4, 65, 7, 17, 3, 70, 75, 82,\n                                  72, 64, 67, 6, 7, 69, 65, 72, 9, 8, 74, 79,\n                                  76, 76, 17, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 46, 62, 62, 62, 62,\n                                  62, 59, 43, 56, 55, 41, 22, 15, 7, 79, 62, 62,\n                                  62, 56, 42, 43, 34, 35, 42, 39, 30, 16, 29,\n                                  11, 65, 29, 34, 33, 36, 42, 29, 29, 18, 17, 0,\n                                  9, 1, 78, 120, 7, 3, 65, 27, 10, 64, 77, 72,\n                                  70, 70, 71, 68, 3, 69, 71, 69, 64, 12, 7, 13,\n                                  65, 62, 62, 62, 58, 50, 46, 34, 20, 67, 69,\n                                  28, 21, 17, 9, 7, 2, 65, 66, 77, 77, 72, 70,\n                                  70, 71, 68, 3, 69, 71, 69, 64, 12, 7, 13, 65,\n                                  62, 62, 62, 58, 50, 46, 34, 20, 67 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 120, 98, 12, 10, 11, 40, 57,\n                                  60, 15, 2, 92, 41, 84, 96, 5, 5, 68, 3, 18,\n                                  48, 56, 50, 12, 100, 119, 111, 73, 84, 96, 5,\n                                  91, 84, 21, 7, 86, 99, 110, 2, 0, 85, 97, 0,\n                                  83, 102, 64, 76, 89, 100, 8, 78, 74, 94, 15,\n                                  3, 22, 0, 0, 0, 80, 87, 97, 70, 19, 1, 28, 85,\n                                  122, 118, 86, 91, 77, 79, 86, 86, 119, 72, 98,\n                                  86, 117, 82, 77, 84, 79, 10, 1, 79, 117, 77,\n                                  101, 88, 119, 65, 78, 72, 91, 9, 68, 69, 94,\n                                  85, 85, 80, 71, 66, 70, 85, 66, 5, 67, 5, 70,\n                                  70, 5, 73, 20, 68, 1, 14, 17, 23, 23, 12, 78,\n                                  75, 80, 9, 67, 88, 67, 68, 73, 78, 77, 5, 36,\n                                  6, 86, 77, 67, 72, 30, 37, 94, 65, 67, 79, 0,\n                                  1, 67, 76, 33, 56, 41, 68, 70, 118, 22, 62,\n                                  62, 121, 23, 21, 28, 32, 30, 25, 20, 23, 28,\n                                  17, 24, 15, 8, 5, 2, 17, 17, 18, 14, 6, 10,\n                                  23, 12, 1, 13, 15, 69, 25, 65, 62, 62, 59, 47,\n                                  57, 62, 62, 62, 42, 31, 25, 24, 40, 36, 78,\n                                  24, 28, 13, 43, 24, 24, 30, 36, 36, 44, 41,\n                                  15, 93, 4, 3, 19, 121, 109, 76, 4, 10, 4, 81,\n                                  85, 90, 89, 119, 94, 10, 64, 68, 74, 79, 84,\n                                  98, 94, 117, 79, 17, 4, 64, 68, 71, 76, 80,\n                                  89, 103, 78, 0, 71, 6, 5, 74, 80, 80, 95, 77,\n                                  27, 5, 7, 5, 69, 73, 82, 80, 84, 62, 121, 120,\n                                  113, 120, 109, 111, 111, 110, 107, 111, 112,\n                                  114, 91, 98, 96, 102, 114, 90, 2, 84, 90, 88,\n                                  76, 71, 72, 65, 79, 65, 3, 67, 68, 64, 68, 77,\n                                  64, 68, 76, 7, 3, 65, 6, 16, 2, 70, 75, 81,\n                                  73, 65, 67, 6, 6, 69, 65, 72, 8, 8, 74, 79,\n                                  76, 76, 15, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 44, 62, 62, 62, 62,\n                                  62, 57, 41, 54, 53, 39, 20, 14, 6, 79, 62, 62,\n                                  62, 54, 40, 41, 32, 33, 40, 37, 28, 14, 26,\n                                  10, 67, 28, 33, 30, 34, 41, 27, 27, 17, 16,\n                                  64, 8, 0, 78, 119, 5, 2, 67, 25, 9, 65, 77,\n                                  72, 69, 69, 70, 68, 3, 68, 70, 68, 0, 12, 8,\n                                  14, 65, 62, 62, 60, 56, 48, 44, 31, 18, 69,\n                                  68, 28, 21, 17, 10, 7, 2, 64, 66, 76, 77, 72,\n                                  69, 69, 70, 68, 3, 68, 70, 68, 0, 12, 8, 14,\n                                  65, 62, 62, 60, 56, 48, 44, 31, 18, 69 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 118, 96, 12, 10, 10, 38, 56,\n                                  59, 16, 2, 90, 39, 83, 94, 5, 5, 67, 2, 17,\n                                  47, 54, 47, 10, 100, 117, 110, 73, 83, 94, 5,\n                                  91, 83, 21, 7, 85, 98, 109, 1, 64, 85, 97, 0,\n                                  83, 101, 64, 76, 89, 100, 8, 77, 74, 93, 16,\n                                  3, 22, 0, 0, 0, 80, 87, 97, 69, 18, 1, 27, 85,\n                                  120, 115, 85, 90, 76, 78, 85, 85, 117, 71, 97,\n                                  85, 115, 83, 77, 84, 79, 10, 1, 78, 115, 77,\n                                  100, 87, 117, 65, 78, 72, 90, 9, 68, 68, 93,\n                                  84, 84, 80, 71, 65, 69, 84, 66, 5, 67, 5, 69,\n                                  70, 5, 73, 21, 68, 1, 15, 18, 23, 23, 12, 78,\n                                  75, 79, 9, 67, 88, 67, 67, 73, 77, 76, 6, 37,\n                                  7, 84, 77, 68, 71, 30, 37, 95, 65, 66, 79, 1,\n                                  1, 67, 74, 33, 56, 41, 67, 71, 116, 21, 62,\n                                  62, 120, 23, 21, 27, 31, 30, 25, 19, 23, 28,\n                                  16, 23, 15, 8, 5, 2, 17, 16, 17, 13, 6, 10,\n                                  22, 12, 0, 12, 15, 69, 24, 65, 62, 62, 58, 46,\n                                  55, 62, 62, 62, 41, 29, 23, 23, 38, 34, 79,\n                                  23, 27, 11, 42, 23, 23, 29, 35, 34, 42, 39,\n                                  14, 93, 3, 2, 17, 119, 107, 75, 4, 10, 4, 80,\n                                  84, 89, 88, 117, 93, 11, 0, 67, 73, 78, 83,\n                                  96, 93, 115, 78, 18, 5, 0, 67, 70, 75, 80, 88,\n                                  102, 77, 1, 70, 6, 5, 73, 80, 79, 94, 76, 27,\n                                  6, 7, 5, 68, 72, 81, 80, 83, 62, 120, 119,\n                                  112, 118, 108, 109, 110, 108, 105, 109, 110,\n                                  112, 90, 97, 95, 101, 111, 90, 1, 84, 89, 87,\n                                  76, 71, 72, 65, 78, 65, 2, 67, 68, 0, 68, 77,\n                                  64, 68, 76, 6, 3, 65, 5, 15, 2, 70, 75, 80,\n                                  73, 65, 66, 5, 6, 69, 65, 72, 8, 7, 74, 78,\n                                  76, 76, 14, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 42, 62, 62, 62, 62,\n                                  62, 55, 40, 52, 50, 37, 19, 13, 5, 79, 62, 62,\n                                  62, 52, 38, 39, 31, 31, 38, 35, 26, 12, 24, 8,\n                                  68, 27, 32, 28, 33, 39, 26, 25, 16, 15, 65, 7,\n                                  64, 78, 118, 4, 1, 68, 24, 8, 66, 77, 71, 69,\n                                  68, 69, 67, 4, 68, 69, 67, 1, 13, 9, 14, 64,\n                                  62, 62, 58, 54, 46, 42, 29, 16, 70, 68, 29,\n                                  22, 18, 11, 8, 3, 64, 66, 75, 77, 71, 69, 68,\n                                  69, 67, 4, 68, 69, 67, 1, 13, 9, 14, 64, 62,\n                                  62, 58, 54, 46, 42, 29, 16, 70 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 116, 95, 13, 10, 10, 37, 54,\n                                  58, 16, 3, 88, 38, 83, 93, 5, 4, 66, 1, 16,\n                                  46, 53, 43, 8, 101, 115, 108, 73, 83, 93, 5,\n                                  90, 82, 22, 7, 84, 97, 108, 64, 65, 85, 98, 0,\n                                  83, 101, 64, 77, 88, 100, 7, 77, 74, 92, 16,\n                                  3, 22, 0, 0, 0, 79, 87, 97, 69, 18, 0, 27, 84,\n                                  119, 113, 84, 89, 74, 76, 84, 84, 115, 70, 96,\n                                  85, 113, 84, 77, 84, 79, 11, 1, 77, 113, 77,\n                                  99, 86, 115, 65, 78, 72, 90, 10, 69, 68, 93,\n                                  84, 83, 80, 70, 65, 69, 83, 65, 5, 67, 5, 69,\n                                  70, 5, 73, 21, 68, 1, 15, 18, 24, 24, 13, 79,\n                                  74, 78, 8, 67, 88, 67, 66, 73, 77, 75, 7, 37,\n                                  9, 83, 78, 69, 71, 30, 37, 95, 66, 66, 80, 1,\n                                  0, 66, 73, 33, 56, 42, 66, 72, 115, 20, 62,\n                                  62, 118, 23, 21, 27, 30, 29, 24, 19, 22, 27,\n                                  16, 23, 15, 7, 5, 1, 16, 15, 16, 13, 6, 10,\n                                  22, 11, 65, 12, 14, 69, 23, 66, 62, 62, 56,\n                                  44, 53, 62, 62, 62, 39, 27, 21, 21, 36, 32,\n                                  81, 22, 25, 9, 40, 22, 22, 28, 33, 32, 40, 37,\n                                  12, 93, 2, 1, 16, 118, 106, 73, 5, 10, 4, 79,\n                                  84, 89, 87, 116, 92, 12, 1, 66, 73, 77, 82,\n                                  95, 92, 113, 78, 18, 5, 0, 67, 69, 75, 79, 87,\n                                  101, 77, 3, 69, 6, 5, 73, 79, 79, 94, 76, 28,\n                                  6, 8, 5, 67, 72, 81, 79, 83, 62, 118, 117,\n                                  110, 116, 106, 108, 108, 107, 104, 107, 108,\n                                  110, 90, 96, 95, 101, 108, 90, 0, 84, 89, 86,\n                                  76, 71, 72, 65, 78, 65, 1, 67, 68, 0, 68, 77,\n                                  64, 68, 76, 6, 3, 65, 4, 14, 2, 70, 75, 79,\n                                  74, 65, 65, 4, 6, 69, 65, 71, 8, 7, 73, 77,\n                                  76, 76, 12, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 40, 62, 62, 62, 62,\n                                  62, 52, 38, 50, 48, 35, 18, 12, 4, 79, 62, 62,\n                                  62, 50, 36, 38, 29, 29, 36, 32, 24, 10, 22, 6,\n                                  69, 26, 30, 26, 31, 37, 24, 23, 14, 13, 66, 6,\n                                  65, 79, 117, 3, 64, 70, 23, 6, 67, 76, 71, 68,\n                                  68, 68, 66, 5, 68, 68, 66, 2, 13, 10, 15, 0,\n                                  62, 62, 56, 52, 44, 40, 27, 14, 71, 67, 29,\n                                  22, 19, 11, 9, 3, 0, 65, 75, 76, 71, 68, 68,\n                                  68, 66, 5, 68, 68, 66, 2, 13, 10, 15, 0, 62,\n                                  62, 56, 52, 44, 40, 27, 14, 71 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 114, 93, 13, 10, 9, 35, 53,\n                                  57, 17, 3, 87, 36, 83, 91, 4, 4, 65, 0, 15,\n                                  45, 51, 40, 5, 102, 113, 107, 73, 83, 91, 4,\n                                  90, 81, 22, 7, 84, 96, 106, 65, 66, 85, 98, 0,\n                                  82, 100, 65, 77, 88, 100, 7, 77, 74, 91, 17,\n                                  3, 22, 0, 0, 0, 79, 87, 97, 68, 17, 0, 26, 84,\n                                  118, 111, 83, 88, 73, 75, 83, 83, 113, 69, 95,\n                                  84, 110, 84, 78, 84, 80, 11, 1, 76, 110, 76,\n                                  99, 86, 113, 65, 78, 72, 90, 10, 69, 67, 92,\n                                  84, 82, 79, 70, 65, 68, 82, 65, 5, 68, 5, 69,\n                                  70, 5, 73, 21, 68, 1, 16, 18, 24, 24, 13, 79,\n                                  74, 78, 8, 67, 87, 67, 65, 72, 76, 73, 9, 38,\n                                  10, 81, 78, 70, 70, 31, 37, 96, 66, 65, 80, 2,\n                                  0, 66, 72, 33, 56, 42, 64, 73, 113, 19, 62,\n                                  62, 117, 23, 21, 26, 30, 29, 24, 18, 22, 27,\n                                  15, 22, 15, 7, 5, 1, 16, 15, 15, 12, 6, 10,\n                                  21, 11, 66, 11, 13, 69, 22, 66, 62, 62, 54,\n                                  43, 52, 62, 62, 62, 38, 25, 19, 20, 34, 30,\n                                  82, 21, 24, 8, 39, 21, 21, 26, 32, 30, 38, 36,\n                                  11, 93, 1, 0, 14, 116, 104, 72, 5, 10, 4, 78,\n                                  83, 88, 87, 114, 90, 13, 2, 66, 72, 75, 81,\n                                  93, 91, 110, 77, 19, 6, 1, 66, 68, 74, 79, 86,\n                                  100, 77, 4, 68, 6, 5, 72, 79, 79, 93, 75, 28,\n                                  7, 8, 5, 66, 71, 80, 79, 82, 62, 117, 116,\n                                  109, 115, 105, 106, 107, 105, 102, 105, 106,\n                                  107, 89, 95, 94, 100, 105, 89, 64, 83, 88, 85,\n                                  76, 71, 72, 65, 77, 66, 0, 67, 68, 1, 68, 77,\n                                  64, 68, 75, 5, 2, 65, 3, 13, 1, 70, 75, 78,\n                                  75, 66, 64, 4, 5, 69, 65, 71, 7, 6, 73, 77,\n                                  76, 76, 11, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 38, 62, 62, 62, 62,\n                                  62, 50, 36, 48, 45, 33, 17, 11, 3, 79, 62, 61,\n                                  62, 48, 34, 36, 28, 27, 34, 30, 22, 8, 20, 5,\n                                  71, 25, 29, 24, 30, 36, 23, 21, 13, 12, 67, 5,\n                                  66, 79, 116, 1, 65, 71, 21, 5, 68, 76, 70, 68,\n                                  67, 67, 65, 5, 67, 67, 65, 3, 14, 11, 15, 0,\n                                  62, 60, 54, 50, 42, 38, 24, 12, 72, 67, 30,\n                                  23, 19, 12, 10, 4, 0, 65, 74, 76, 70, 68, 67,\n                                  67, 65, 5, 67, 67, 65, 3, 14, 11, 15, 0, 62,\n                                  60, 54, 50, 42, 38, 24, 12, 72 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 113, 92, 13, 10, 9, 33, 51,\n                                  56, 17, 3, 85, 34, 83, 90, 4, 3, 64, 64, 13,\n                                  43, 49, 36, 3, 103, 111, 106, 73, 83, 90, 4,\n                                  90, 81, 22, 6, 83, 95, 105, 66, 68, 86, 99, 0,\n                                  82, 99, 65, 78, 88, 100, 7, 77, 74, 91, 17, 3,\n                                  22, 0, 0, 0, 78, 88, 97, 68, 16, 0, 26, 83,\n                                  117, 109, 82, 88, 71, 73, 83, 82, 111, 69, 94,\n                                  83, 108, 85, 78, 85, 80, 11, 0, 76, 108, 76,\n                                  98, 85, 112, 65, 78, 72, 90, 10, 69, 67, 91,\n                                  84, 82, 79, 70, 65, 68, 81, 64, 5, 68, 4, 69,\n                                  70, 4, 73, 21, 68, 1, 16, 18, 24, 24, 13, 80,\n                                  73, 77, 7, 67, 87, 67, 64, 72, 76, 72, 10, 39,\n                                  12, 79, 79, 71, 70, 31, 37, 97, 66, 65, 81, 2,\n                                  0, 66, 71, 33, 56, 42, 0, 74, 112, 18, 59, 62,\n                                  116, 22, 21, 26, 29, 28, 23, 18, 22, 26, 14,\n                                  21, 14, 7, 4, 0, 15, 14, 14, 12, 5, 9, 20, 10,\n                                  67, 10, 12, 69, 20, 67, 62, 62, 52, 41, 50,\n                                  60, 62, 62, 37, 23, 16, 18, 31, 28, 84, 19,\n                                  23, 6, 38, 20, 20, 25, 30, 28, 36, 34, 9, 93,\n                                  0, 64, 12, 115, 103, 71, 6, 10, 4, 78, 82, 87,\n                                  86, 112, 89, 13, 2, 65, 72, 74, 80, 92, 90,\n                                  108, 77, 19, 6, 1, 66, 68, 74, 78, 86, 99, 77,\n                                  5, 67, 6, 5, 71, 78, 79, 92, 74, 28, 8, 8, 5,\n                                  65, 71, 79, 78, 82, 62, 116, 114, 107, 113,\n                                  104, 105, 105, 104, 101, 104, 104, 105, 89,\n                                  94, 94, 99, 102, 89, 65, 83, 87, 85, 76, 71,\n                                  72, 66, 77, 66, 64, 67, 68, 1, 68, 77, 65, 68,\n                                  75, 5, 2, 66, 2, 12, 1, 71, 75, 77, 76, 66,\n                                  64, 3, 5, 69, 66, 71, 7, 6, 73, 76, 76, 76, 9,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 61, 36, 62, 62, 62, 62, 61, 48, 34,\n                                  45, 43, 31, 15, 9, 2, 79, 61, 59, 62, 46, 31,\n                                  34, 26, 24, 32, 28, 20, 6, 17, 3, 72, 23, 28,\n                                  21, 28, 34, 21, 19, 11, 10, 68, 4, 67, 79,\n                                  115, 0, 67, 73, 20, 4, 69, 76, 70, 67, 67, 66,\n                                  65, 6, 67, 66, 65, 4, 14, 11, 16, 1, 61, 58,\n                                  52, 48, 40, 36, 22, 10, 74, 66, 30, 23, 20,\n                                  12, 10, 4, 1, 65, 74, 76, 70, 67, 67, 66, 65,\n                                  6, 67, 66, 65, 4, 14, 11, 16, 1, 61, 58, 52,\n                                  48, 40, 36, 22, 10, 74 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 111, 91, 14, 10, 9, 31, 49,\n                                  56, 18, 3, 83, 33, 82, 88, 4, 3, 0, 64, 12,\n                                  42, 47, 33, 1, 103, 109, 104, 72, 82, 88, 4,\n                                  89, 80, 23, 6, 82, 94, 104, 67, 69, 86, 99, 0,\n                                  82, 98, 65, 78, 88, 100, 7, 76, 73, 90, 17, 3,\n                                  22, 0, 0, 0, 77, 88, 97, 68, 15, 0, 26, 82,\n                                  115, 106, 81, 87, 69, 71, 82, 81, 109, 68, 92,\n                                  82, 106, 86, 78, 85, 80, 12, 0, 75, 106, 76,\n                                  97, 84, 110, 65, 77, 72, 89, 11, 69, 66, 90,\n                                  83, 81, 79, 70, 64, 67, 80, 0, 5, 68, 4, 68,\n                                  69, 4, 73, 22, 68, 1, 16, 19, 25, 24, 14, 80,\n                                  72, 76, 6, 67, 87, 67, 0, 72, 75, 71, 11, 40,\n                                  14, 77, 80, 72, 69, 31, 38, 98, 66, 65, 81, 3,\n                                  0, 66, 69, 33, 56, 42, 1, 75, 111, 17, 57, 62,\n                                  114, 22, 21, 26, 28, 28, 23, 18, 22, 26, 13,\n                                  20, 14, 7, 4, 0, 15, 13, 14, 12, 5, 9, 19, 9,\n                                  68, 10, 12, 69, 19, 67, 62, 62, 51, 40, 48,\n                                  58, 62, 62, 36, 21, 14, 17, 29, 27, 85, 18,\n                                  22, 4, 37, 19, 19, 24, 28, 27, 34, 32, 8, 93,\n                                  0, 65, 11, 113, 101, 69, 7, 10, 4, 77, 81, 86,\n                                  85, 110, 88, 14, 3, 64, 71, 73, 79, 91, 89,\n                                  106, 76, 20, 7, 2, 66, 67, 73, 77, 85, 97, 76,\n                                  7, 66, 7, 5, 70, 77, 78, 91, 73, 29, 9, 9, 6,\n                                  64, 70, 78, 77, 81, 62, 114, 112, 105, 111,\n                                  103, 104, 103, 102, 99, 102, 102, 103, 88, 93,\n                                  93, 98, 98, 89, 66, 83, 86, 84, 75, 71, 72,\n                                  66, 77, 66, 65, 67, 68, 2, 68, 77, 65, 68, 75,\n                                  5, 2, 66, 2, 11, 1, 71, 74, 75, 76, 66, 0, 2,\n                                  5, 69, 66, 70, 7, 6, 72, 75, 75, 75, 7, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 58, 34, 62, 62, 62, 62, 58, 46, 33, 43,\n                                  41, 30, 14, 8, 1, 79, 59, 57, 60, 44, 29, 32,\n                                  25, 22, 30, 26, 18, 4, 15, 1, 73, 22, 27, 19,\n                                  27, 32, 20, 17, 10, 9, 69, 3, 67, 79, 114, 64,\n                                  68, 75, 19, 3, 70, 76, 69, 66, 66, 64, 64, 7,\n                                  67, 65, 64, 5, 15, 12, 17, 2, 60, 57, 50, 46,\n                                  38, 34, 20, 8, 75, 65, 30, 24, 21, 13, 11, 5,\n                                  2, 64, 73, 76, 69, 66, 66, 64, 64, 7, 67, 65,\n                                  64, 5, 15, 12, 17, 2, 60, 57, 50, 46, 38, 34,\n                                  20, 8, 75 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 109, 89, 14, 10, 8, 29, 48,\n                                  55, 19, 3, 82, 31, 82, 87, 3, 3, 1, 65, 11,\n                                  41, 45, 30, 65, 104, 107, 103, 72, 82, 87, 3,\n                                  89, 79, 23, 6, 82, 93, 102, 68, 70, 86, 99, 0,\n                                  81, 97, 66, 78, 88, 100, 7, 76, 73, 89, 18, 3,\n                                  22, 0, 0, 0, 77, 88, 97, 67, 14, 0, 25, 82,\n                                  114, 104, 80, 86, 68, 70, 81, 80, 107, 67, 91,\n                                  81, 103, 86, 79, 85, 81, 12, 0, 74, 103, 75,\n                                  97, 84, 108, 65, 77, 72, 89, 11, 69, 66, 89,\n                                  83, 80, 78, 70, 64, 67, 79, 0, 5, 69, 4, 68,\n                                  69, 4, 73, 22, 68, 1, 17, 19, 25, 24, 14, 81,\n                                  72, 76, 6, 67, 86, 67, 1, 71, 75, 69, 13, 41,\n                                  15, 75, 80, 73, 69, 32, 38, 99, 66, 64, 82, 4,\n                                  0, 66, 68, 33, 56, 42, 3, 76, 109, 16, 54, 62,\n                                  113, 22, 21, 25, 28, 27, 23, 17, 22, 25, 12,\n                                  19, 14, 7, 4, 0, 14, 13, 13, 11, 5, 9, 18, 9,\n                                  69, 9, 11, 69, 18, 68, 60, 62, 49, 38, 47, 56,\n                                  62, 62, 35, 19, 12, 15, 27, 25, 86, 17, 21, 3,\n                                  36, 18, 18, 22, 27, 25, 32, 31, 6, 93, 64, 66,\n                                  9, 112, 100, 68, 7, 10, 4, 76, 80, 85, 85,\n                                  108, 86, 15, 4, 64, 70, 71, 78, 89, 88, 103,\n                                  75, 20, 7, 2, 65, 66, 72, 77, 84, 96, 76, 8,\n                                  65, 7, 5, 69, 77, 78, 90, 72, 29, 10, 9, 6, 0,\n                                  69, 77, 77, 80, 62, 113, 111, 104, 110, 102,\n                                  102, 102, 100, 98, 100, 100, 100, 87, 92, 92,\n                                  97, 95, 88, 67, 82, 85, 83, 75, 71, 72, 66,\n                                  76, 67, 66, 67, 68, 3, 68, 77, 65, 68, 74, 4,\n                                  1, 66, 1, 10, 0, 71, 74, 74, 77, 67, 1, 2, 4,\n                                  69, 66, 70, 6, 5, 72, 75, 75, 75, 6, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  56, 32, 62, 62, 62, 62, 55, 44, 31, 41, 38,\n                                  28, 13, 7, 0, 79, 57, 54, 57, 42, 27, 30, 23,\n                                  20, 28, 24, 16, 2, 13, 0, 75, 21, 26, 17, 25,\n                                  31, 18, 15, 9, 8, 70, 2, 68, 79, 113, 66, 69,\n                                  76, 17, 2, 71, 76, 69, 66, 65, 0, 0, 7, 66,\n                                  64, 0, 6, 15, 13, 17, 2, 60, 55, 48, 44, 36,\n                                  32, 17, 6, 76, 65, 31, 24, 21, 14, 12, 5, 2,\n                                  64, 72, 76, 69, 66, 65, 0, 0, 7, 66, 64, 0, 6,\n                                  15, 13, 17, 2, 60, 55, 48, 44, 36, 32, 17, 6,\n                                  76 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 107, 88, 15, 10, 8, 28, 46,\n                                  54, 19, 4, 80, 30, 82, 85, 3, 2, 2, 66, 10,\n                                  40, 44, 26, 67, 105, 105, 101, 72, 82, 85, 3,\n                                  88, 78, 24, 6, 81, 92, 101, 70, 71, 86, 100,\n                                  0, 81, 97, 66, 79, 87, 100, 6, 76, 73, 88, 18,\n                                  3, 22, 0, 0, 0, 76, 88, 97, 67, 14, 64, 25,\n                                  81, 113, 102, 79, 85, 66, 68, 80, 79, 105, 66,\n                                  90, 81, 101, 87, 79, 85, 81, 13, 0, 73, 101,\n                                  75, 96, 83, 106, 65, 77, 72, 89, 12, 70, 65,\n                                  89, 83, 79, 78, 69, 64, 66, 78, 1, 5, 69, 4,\n                                  68, 69, 4, 73, 22, 68, 1, 17, 19, 26, 25, 15,\n                                  81, 71, 75, 5, 67, 86, 67, 2, 71, 74, 68, 14,\n                                  41, 17, 74, 81, 74, 68, 32, 38, 99, 67, 64,\n                                  82, 4, 64, 65, 67, 33, 56, 43, 4, 77, 108, 15,\n                                  51, 62, 111, 22, 21, 25, 27, 27, 22, 17, 21,\n                                  25, 12, 19, 14, 6, 4, 64, 14, 12, 12, 11, 5,\n                                  9, 18, 8, 71, 9, 10, 69, 17, 68, 57, 62, 47,\n                                  37, 45, 54, 62, 61, 33, 17, 10, 14, 25, 23,\n                                  88, 16, 19, 1, 34, 17, 17, 21, 25, 23, 30, 29,\n                                  5, 93, 65, 67, 8, 110, 98, 66, 8, 10, 4, 75,\n                                  80, 85, 84, 107, 85, 16, 5, 0, 70, 70, 77, 88,\n                                  87, 101, 75, 21, 8, 3, 65, 65, 72, 76, 83, 95,\n                                  76, 10, 64, 7, 5, 69, 76, 78, 90, 72, 30, 10,\n                                  10, 6, 1, 69, 77, 76, 80, 62, 111, 109, 102,\n                                  108, 100, 101, 100, 99, 96, 98, 98, 98, 87,\n                                  91, 92, 97, 92, 88, 68, 82, 85, 82, 75, 71,\n                                  72, 66, 76, 67, 67, 67, 68, 3, 68, 77, 65, 68,\n                                  74, 4, 1, 66, 0, 9, 0, 71, 74, 73, 78, 67, 2,\n                                  1, 4, 69, 66, 69, 6, 5, 71, 74, 75, 75, 4, 62,\n                                  61, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 53, 30, 62, 62, 62, 62, 53, 41, 29, 39,\n                                  36, 26, 12, 6, 64, 79, 55, 52, 55, 40, 25, 29,\n                                  22, 18, 26, 21, 14, 0, 11, 65, 76, 20, 24, 15,\n                                  24, 29, 17, 13, 7, 6, 71, 1, 69, 80, 112, 67,\n                                  71, 78, 16, 0, 72, 75, 68, 65, 65, 1, 1, 8,\n                                  66, 0, 1, 7, 16, 14, 18, 3, 59, 53, 46, 42,\n                                  34, 30, 15, 4, 77, 64, 31, 25, 22, 14, 13, 6,\n                                  3, 0, 72, 75, 68, 65, 65, 1, 1, 8, 66, 0, 1,\n                                  7, 16, 14, 18, 3, 59, 53, 46, 42, 34, 30, 15,\n                                  4, 77 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 106, 86, 15, 10, 7, 26, 45,\n                                  53, 20, 4, 78, 28, 82, 84, 3, 2, 3, 67, 8, 38,\n                                  42, 23, 69, 106, 103, 100, 72, 82, 84, 3, 88,\n                                  77, 24, 5, 80, 91, 100, 71, 73, 87, 100, 0,\n                                  81, 96, 66, 79, 87, 100, 6, 76, 73, 88, 19, 3,\n                                  22, 0, 0, 0, 76, 89, 97, 66, 13, 64, 24, 81,\n                                  112, 100, 78, 84, 65, 67, 80, 78, 103, 65, 89,\n                                  80, 99, 88, 79, 85, 81, 13, 64, 72, 99, 75,\n                                  95, 82, 104, 65, 77, 72, 89, 12, 70, 65, 88,\n                                  83, 79, 78, 69, 64, 66, 77, 1, 5, 69, 3, 68,\n                                  69, 4, 73, 22, 68, 1, 18, 19, 26, 25, 15, 82,\n                                  71, 74, 5, 67, 86, 67, 3, 71, 74, 67, 15, 42,\n                                  18, 72, 81, 75, 68, 32, 38, 100, 67, 0, 83, 5,\n                                  64, 65, 66, 33, 56, 43, 5, 78, 106, 14, 48,\n                                  60, 110, 21, 21, 24, 26, 26, 22, 16, 21, 24,\n                                  11, 18, 13, 6, 4, 64, 13, 11, 11, 10, 4, 8,\n                                  17, 8, 72, 8, 9, 69, 15, 69, 55, 62, 45, 35,\n                                  43, 52, 62, 58, 32, 15, 7, 12, 23, 21, 89, 14,\n                                  18, 64, 33, 16, 16, 20, 24, 21, 28, 27, 3, 93,\n                                  66, 68, 6, 109, 97, 65, 8, 10, 4, 74, 79, 84,\n                                  83, 105, 84, 17, 5, 1, 69, 69, 76, 86, 86, 99,\n                                  74, 21, 8, 3, 64, 64, 71, 76, 83, 94, 76, 11,\n                                  0, 7, 5, 68, 76, 78, 89, 71, 30, 11, 10, 6, 2,\n                                  68, 76, 76, 79, 62, 110, 108, 101, 106, 99,\n                                  99, 99, 97, 95, 97, 96, 96, 86, 90, 91, 96,\n                                  89, 88, 69, 82, 84, 82, 75, 71, 72, 67, 75,\n                                  67, 68, 67, 68, 4, 68, 77, 65, 68, 74, 3, 1,\n                                  66, 64, 8, 0, 71, 74, 72, 79, 67, 2, 0, 4, 69,\n                                  66, 69, 6, 4, 71, 73, 75, 75, 3, 62, 60, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 50,\n                                  28, 62, 62, 62, 62, 50, 39, 27, 37, 33, 24,\n                                  10, 5, 65, 79, 52, 50, 53, 38, 23, 27, 20, 16,\n                                  24, 19, 12, 65, 8, 67, 77, 19, 23, 12, 22, 27,\n                                  15, 11, 6, 5, 72, 0, 70, 80, 111, 68, 72, 79,\n                                  15, 64, 73, 75, 68, 65, 64, 2, 1, 9, 66, 1, 2,\n                                  8, 16, 15, 18, 4, 59, 51, 44, 40, 32, 28, 13,\n                                  2, 79, 64, 32, 25, 23, 15, 13, 6, 3, 0, 71,\n                                  75, 68, 65, 64, 2, 1, 9, 66, 1, 2, 8, 16, 15,\n                                  18, 4, 59, 51, 44, 40, 32, 28, 13, 2, 79 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 104, 85, 15, 10, 7, 24, 43,\n                                  52, 21, 4, 77, 26, 81, 82, 2, 2, 4, 68, 7, 37,\n                                  40, 20, 72, 106, 101, 99, 72, 81, 82, 2, 88,\n                                  76, 24, 5, 80, 90, 98, 72, 74, 87, 100, 0, 80,\n                                  95, 67, 79, 87, 100, 6, 75, 73, 87, 19, 3, 22,\n                                  0, 0, 0, 75, 89, 97, 66, 12, 64, 24, 80, 110,\n                                  97, 77, 83, 0, 65, 79, 77, 101, 64, 88, 79,\n                                  96, 88, 80, 85, 82, 13, 64, 71, 96, 74, 95,\n                                  82, 102, 65, 77, 72, 88, 12, 70, 64, 87, 82,\n                                  78, 77, 69, 0, 65, 76, 2, 5, 70, 3, 67, 69, 4,\n                                  73, 23, 68, 1, 18, 20, 26, 25, 15, 82, 70, 74,\n                                  4, 67, 85, 67, 4, 70, 73, 65, 17, 43, 20, 70,\n                                  82, 76, 67, 33, 38, 101, 67, 0, 83, 6, 64, 65,\n                                  64, 33, 56, 43, 7, 79, 105, 13, 46, 57, 109,\n                                  21, 21, 24, 26, 26, 22, 16, 21, 24, 10, 17,\n                                  13, 6, 4, 64, 13, 11, 10, 10, 4, 8, 16, 7, 73,\n                                  7, 9, 69, 14, 69, 53, 62, 44, 34, 42, 50, 62,\n                                  56, 31, 13, 5, 11, 21, 19, 90, 13, 17, 65, 32,\n                                  15, 15, 18, 22, 19, 26, 26, 2, 93, 67, 69, 4,\n                                  107, 95, 64, 9, 10, 4, 73, 78, 83, 83, 103,\n                                  82, 18, 6, 1, 68, 67, 75, 85, 85, 96, 73, 22,\n                                  9, 4, 64, 0, 70, 75, 82, 93, 75, 12, 1, 7, 5,\n                                  67, 75, 77, 88, 70, 30, 12, 10, 6, 3, 67, 75,\n                                  75, 78, 62, 109, 106, 99, 105, 98, 98, 97, 95,\n                                  93, 95, 94, 93, 85, 89, 90, 95, 86, 87, 70,\n                                  81, 83, 81, 75, 71, 72, 67, 75, 68, 69, 67,\n                                  68, 5, 68, 77, 65, 68, 73, 3, 0, 66, 65, 7,\n                                  64, 71, 74, 71, 79, 68, 3, 0, 3, 69, 66, 69,\n                                  5, 4, 71, 73, 75, 75, 1, 62, 59, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 60, 48, 26, 62,\n                                  62, 62, 62, 47, 37, 26, 35, 31, 22, 9, 4, 66,\n                                  79, 50, 47, 50, 36, 21, 25, 19, 14, 22, 17,\n                                  10, 67, 6, 68, 79, 18, 22, 10, 21, 26, 14, 9,\n                                  5, 4, 73, 64, 71, 80, 110, 70, 73, 81, 13, 65,\n                                  74, 75, 67, 64, 0, 3, 2, 9, 65, 2, 3, 9, 17,\n                                  16, 19, 4, 58, 49, 42, 38, 30, 26, 10, 0, 80,\n                                  0, 32, 26, 23, 16, 14, 7, 4, 0, 70, 75, 67,\n                                  64, 0, 3, 2, 9, 65, 2, 3, 9, 17, 16, 19, 4,\n                                  58, 49, 42, 38, 30, 26, 10, 0, 80 },\n\n                                {\n\n                                61,\n                                  8, 76, 61, 8, 76, 102, 83, 16, 10, 6, 22, 42,\n                                  51, 21, 4, 75, 25, 81, 81, 2, 1, 5, 69, 6, 36,\n                                  38, 16, 74, 107, 99, 97, 72, 81, 81, 2, 87,\n                                  75, 25, 5, 79, 89, 97, 73, 75, 87, 101, 0, 80,\n                                  94, 67, 80, 87, 100, 6, 75, 73, 86, 20, 3, 22,\n                                  0, 0, 0, 75, 89, 97, 65, 11, 64, 23, 80, 109,\n                                  95, 76, 82, 1, 64, 78, 76, 99, 0, 87, 78, 94,\n                                  89, 80, 85, 82, 14, 64, 70, 94, 74, 94, 81,\n                                  100, 65, 77, 72, 88, 13, 70, 64, 86, 82, 77,\n                                  77, 69, 0, 65, 75, 2, 5, 70, 3, 67, 69, 4, 73,\n                                  23, 68, 1, 19, 20, 27, 25, 16, 83, 70, 73, 4,\n                                  67, 85, 67, 5, 70, 73, 64, 18, 44, 21, 68, 82,\n                                  77, 67, 33, 38, 102, 67, 1, 84, 6, 64, 65, 0,\n                                  33, 56, 43, 8, 80, 103, 12, 43, 54, 107, 21,\n                                  21, 23, 25, 25, 21, 15, 21, 23, 9, 16, 13, 6,\n                                  4, 65, 12, 10, 9, 9, 4, 8, 15, 7, 74, 7, 8,\n                                  69, 13, 70, 51, 60, 42, 32, 40, 48, 62, 53,\n                                  30, 11, 3, 9, 19, 17, 92, 12, 16, 67, 31, 14,\n                                  14, 17, 21, 17, 24, 24, 0, 93, 68, 70, 3, 106,\n                                  94, 1, 9, 10, 4, 72, 77, 82, 82, 101, 81, 19,\n                                  7, 2, 68, 66, 74, 83, 84, 94, 73, 22, 9, 4, 0,\n                                  1, 70, 75, 81, 92, 75, 14, 2, 7, 5, 66, 75,\n                                  77, 87, 69, 31, 13, 11, 6, 4, 67, 74, 75, 78,\n                                  62, 107, 105, 98, 103, 97, 96, 96, 94, 92, 93,\n                                  92, 91, 85, 88, 90, 94, 83, 87, 71, 81, 82,\n                                  80, 75, 71, 72, 67, 74, 68, 70, 67, 68, 5, 68,\n                                  77, 65, 68, 73, 2, 0, 66, 66, 6, 64, 71, 74,\n                                  70, 80, 68, 4, 64, 3, 69, 66, 68, 5, 3, 70,\n                                  72, 75, 75, 0, 62, 58, 61, 61, 61, 62, 62, 62,\n                                  61, 62, 62, 62, 57, 45, 24, 62, 60, 59, 60,\n                                  44, 35, 24, 33, 28, 20, 8, 3, 67, 79, 48, 45,\n                                  48, 34, 19, 23, 17, 12, 20, 15, 8, 69, 4, 70,\n                                  80, 17, 21, 8, 19, 24, 12, 7, 3, 2, 74, 65,\n                                  72, 80, 109, 71, 75, 82, 12, 66, 75, 75, 67,\n                                  64, 0, 4, 3, 10, 65, 3, 4, 10, 17, 17, 19, 5,\n                                  58, 47, 40, 36, 28, 24, 8, 65, 81, 0, 33, 26,\n                                  24, 16, 15, 7, 4, 1, 70, 75, 67, 64, 0, 4, 3,\n                                  10, 65, 3, 4, 10, 17, 17, 19, 5, 58, 47, 40,\n                                  36, 28, 24, 8, 65, 81 },\n\n                                {\n\n                                60,\n                                  8, 76, 60, 8, 76, 100, 82, 16, 10, 6, 20, 40,\n                                  50, 22, 4, 73, 23, 81, 79, 2, 1, 6, 70, 5, 35,\n                                  36, 13, 76, 108, 97, 96, 72, 81, 79, 2, 87,\n                                  74, 25, 5, 78, 88, 96, 74, 76, 87, 101, 0, 80,\n                                  93, 67, 80, 87, 100, 6, 75, 73, 85, 20, 3, 22,\n                                  0, 0, 0, 74, 89, 97, 65, 10, 64, 23, 79, 108,\n                                  93, 75, 81, 3, 1, 77, 75, 97, 1, 86, 77, 92,\n                                  90, 80, 85, 82, 14, 64, 69, 92, 74, 93, 80,\n                                  98, 65, 77, 72, 88, 13, 70, 0, 85, 82, 76, 77,\n                                  69, 0, 64, 74, 3, 5, 70, 3, 67, 69, 4, 73, 23,\n                                  68, 1, 19, 20, 27, 25, 16, 83, 69, 72, 3, 67,\n                                  85, 67, 6, 70, 72, 0, 19, 45, 23, 66, 83, 78,\n                                  66, 33, 38, 103, 67, 1, 84, 7, 64, 65, 1, 33,\n                                  56, 43, 9, 81, 102, 11, 40, 51, 106, 21, 21,\n                                  23, 24, 25, 21, 15, 21, 23, 8, 15, 13, 6, 4,\n                                  65, 12, 9, 8, 9, 4, 8, 14, 6, 75, 6, 7, 69,\n                                  12, 70, 49, 58, 40, 31, 38, 46, 59, 51, 29, 9,\n                                  1, 8, 17, 15, 93, 11, 15, 69, 30, 13, 13, 16,\n                                  19, 15, 22, 22, 64, 93, 69, 71, 1, 104, 92, 2,\n                                  10, 10, 4, 71, 76, 81, 81, 99, 80, 20, 8, 3,\n                                  67, 65, 73, 82, 83, 92, 72, 23, 10, 5, 0, 2,\n                                  69, 74, 80, 91, 75, 15, 3, 7, 5, 65, 74, 77,\n                                  86, 68, 31, 14, 11, 6, 5, 66, 73, 74, 77, 62,\n                                  106, 103, 96, 101, 96, 95, 94, 92, 90, 91, 90,\n                                  89, 84, 87, 89, 93, 80, 87, 72, 81, 81, 79,\n                                  75, 71, 72, 67, 74, 68, 71, 67, 68, 6, 68, 77,\n                                  65, 68, 73, 2, 0, 66, 67, 5, 64, 71, 74, 69,\n                                  81, 68, 5, 65, 3, 69, 66, 68, 5, 3, 70, 71,\n                                  75, 75, 65, 61, 57, 60, 59, 59, 62, 62, 62,\n                                  59, 60, 62, 61, 54, 42, 22, 61, 57, 55, 55,\n                                  41, 33, 22, 31, 26, 18, 7, 2, 68, 79, 46, 43,\n                                  46, 32, 17, 21, 16, 10, 18, 13, 6, 71, 2, 72,\n                                  81, 16, 20, 6, 18, 22, 11, 5, 2, 1, 75, 66,\n                                  73, 80, 108, 72, 76, 84, 11, 67, 76, 75, 66,\n                                  0, 1, 5, 4, 11, 65, 4, 5, 11, 18, 18, 20, 6,\n                                  57, 45, 38, 34, 26, 22, 6, 67, 82, 1, 33, 27,\n                                  25, 17, 16, 8, 5, 1, 69, 75, 66, 0, 1, 5, 4,\n                                  11, 65, 4, 5, 11, 18, 18, 20, 6, 57, 45, 38,\n                                  34, 26, 22, 6, 67, 82 },\n\n                                {\n\n                                58,\n                                  7, 77, 58, 7, 77, 99, 81, 16, 10, 5, 18, 38,\n                                  49, 22, 4, 72, 21, 81, 78, 1, 0, 7, 71, 3, 33,\n                                  34, 9, 79, 109, 95, 95, 72, 81, 78, 1, 87, 74,\n                                  25, 4, 78, 88, 95, 76, 78, 88, 102, 64, 80,\n                                  93, 68, 81, 87, 100, 5, 75, 73, 85, 20, 2, 22,\n                                  0, 0, 0, 74, 90, 97, 65, 9, 65, 22, 79, 107,\n                                  91, 74, 81, 4, 2, 77, 74, 96, 1, 85, 77, 90,\n                                  91, 81, 86, 83, 14, 65, 69, 90, 74, 93, 80,\n                                  97, 65, 77, 72, 88, 13, 71, 0, 85, 82, 76, 77,\n                                  69, 0, 64, 73, 3, 5, 71, 2, 67, 69, 3, 73, 23,\n                                  68, 1, 19, 20, 27, 25, 16, 84, 69, 72, 2, 67,\n                                  85, 68, 6, 70, 72, 1, 20, 45, 24, 65, 84, 80,\n                                  66, 33, 38, 104, 68, 1, 85, 7, 65, 65, 2, 33,\n                                  55, 43, 10, 82, 101, 9, 37, 47, 105, 20, 21,\n                                  22, 23, 24, 20, 14, 20, 22, 7, 14, 12, 5, 3,\n                                  66, 11, 8, 7, 8, 3, 7, 13, 5, 77, 5, 6, 69,\n                                  10, 71, 46, 55, 38, 29, 36, 43, 55, 48, 27, 7,\n                                  65, 6, 14, 13, 95, 9, 13, 71, 28, 12, 12, 14,\n                                  17, 13, 20, 20, 66, 93, 70, 72, 64, 103, 91,\n                                  3, 10, 10, 4, 71, 76, 81, 81, 98, 79, 20, 8,\n                                  3, 67, 64, 72, 81, 83, 90, 72, 23, 10, 5, 0,\n                                  2, 69, 74, 80, 90, 75, 16, 4, 7, 4, 65, 74,\n                                  77, 86, 68, 31, 14, 11, 6, 6, 66, 73, 74, 77,\n                                  62, 105, 102, 95, 100, 95, 94, 93, 91, 89, 90,\n                                  89, 87, 84, 87, 89, 93, 77, 87, 74, 81, 81,\n                                  79, 75, 71, 72, 68, 74, 69, 72, 68, 68, 6, 69,\n                                  77, 66, 68, 73, 1, 64, 67, 68, 4, 65, 72, 74,\n                                  68, 82, 69, 5, 66, 2, 69, 67, 68, 4, 2, 70,\n                                  71, 75, 75, 67, 59, 56, 58, 57, 56, 62, 62,\n                                  62, 56, 57, 62, 58, 50, 39, 20, 57, 53, 51,\n                                  49, 38, 30, 20, 28, 23, 16, 5, 0, 69, 79, 43,\n                                  40, 43, 30, 14, 19, 14, 7, 16, 10, 4, 74, 64,\n                                  74, 83, 14, 18, 3, 16, 20, 9, 3, 0, 64, 76,\n                                  67, 74, 81, 107, 74, 78, 86, 9, 69, 78, 75,\n                                  66, 0, 1, 6, 4, 11, 65, 5, 5, 12, 18, 18, 20,\n                                  6, 56, 43, 36, 31, 23, 20, 3, 69, 84, 1, 33,\n                                  27, 25, 17, 16, 8, 5, 1, 69, 75, 66, 0, 1, 6,\n                                  4, 11, 65, 5, 5, 12, 18, 18, 20, 6, 56, 43,\n                                  36, 31, 23, 20, 3, 69, 84 },\n\n                                {\n\n                                57,\n                                  7, 77, 57, 7, 77, 97, 79, 17, 11, 5, 17, 37,\n                                  49, 23, 5, 70, 20, 80, 76, 1, 0, 9, 71, 2, 32,\n                                  33, 6, 81, 109, 93, 93, 71, 80, 76, 1, 86, 73,\n                                  26, 4, 77, 87, 93, 77, 79, 88, 102, 64, 79,\n                                  92, 68, 81, 86, 99, 5, 74, 72, 84, 21, 2, 22,\n                                  0, 0, 0, 73, 90, 97, 64, 9, 65, 22, 78, 105,\n                                  88, 72, 80, 6, 4, 76, 72, 94, 2, 83, 76, 87,\n                                  91, 81, 86, 83, 15, 65, 68, 87, 73, 92, 79,\n                                  95, 65, 76, 72, 87, 14, 71, 1, 84, 81, 75, 76,\n                                  68, 1, 0, 72, 4, 6, 71, 2, 66, 68, 3, 72, 24,\n                                  67, 1, 20, 21, 28, 26, 17, 84, 68, 71, 2, 67,\n                                  84, 68, 7, 69, 71, 3, 22, 46, 26, 0, 84, 81,\n                                  65, 34, 39, 104, 68, 2, 85, 8, 65, 64, 4, 33,\n                                  55, 44, 12, 83, 99, 8, 35, 44, 103, 20, 21,\n                                  22, 23, 24, 20, 14, 20, 22, 7, 14, 12, 5, 3,\n                                  66, 11, 8, 7, 8, 3, 7, 13, 5, 78, 5, 6, 69, 9,\n                                  71, 44, 53, 37, 28, 35, 41, 52, 46, 26, 6, 67,\n                                  5, 12, 12, 96, 8, 12, 72, 27, 12, 12, 13, 16,\n                                  12, 19, 19, 67, 93, 70, 72, 65, 101, 89, 5,\n                                  11, 10, 4, 70, 75, 80, 80, 96, 77, 21, 9, 4,\n                                  66, 1, 71, 79, 82, 87, 71, 24, 11, 6, 1, 3,\n                                  68, 73, 79, 88, 74, 18, 5, 8, 4, 64, 73, 76,\n                                  85, 67, 32, 15, 12, 7, 7, 65, 72, 73, 76, 62,\n                                  103, 100, 93, 98, 93, 92, 91, 89, 87, 88, 87,\n                                  84, 83, 86, 88, 92, 73, 86, 75, 80, 80, 78,\n                                  74, 71, 71, 68, 73, 69, 72, 68, 68, 7, 69, 77,\n                                  66, 68, 72, 1, 64, 67, 68, 4, 65, 72, 73, 66,\n                                  82, 69, 6, 66, 2, 69, 67, 67, 4, 2, 69, 70,\n                                  74, 74, 68, 58, 55, 57, 56, 54, 60, 60, 59,\n                                  54, 55, 59, 56, 47, 37, 18, 54, 50, 48, 44,\n                                  36, 28, 19, 26, 21, 15, 4, 64, 69, 79, 41, 38,\n                                  41, 28, 12, 18, 13, 5, 15, 8, 3, 76, 66, 75,\n                                  84, 13, 17, 1, 15, 19, 8, 2, 64, 65, 77, 67,\n                                  74, 81, 106, 75, 79, 87, 8, 70, 79, 74, 65, 1,\n                                  2, 8, 5, 12, 64, 7, 6, 13, 19, 19, 21, 7, 56,\n                                  42, 35, 29, 21, 19, 1, 70, 85, 2, 34, 28, 26,\n                                  18, 17, 9, 6, 2, 68, 74, 65, 1, 2, 8, 5, 12,\n                                  64, 7, 6, 13, 19, 19, 21, 7, 56, 42, 35, 29,\n                                  21, 19, 1, 70, 85 },\n\n                                {\n\n                                56,\n                                  7, 77, 56, 7, 77, 95, 78, 17, 11, 5, 15, 35,\n                                  48, 24, 5, 68, 18, 80, 75, 1, 0, 10, 72, 1,\n                                  31, 31, 3, 83, 110, 91, 92, 71, 80, 75, 1, 86,\n                                  72, 26, 4, 76, 86, 92, 78, 80, 88, 102, 64,\n                                  79, 91, 68, 81, 86, 99, 5, 74, 72, 83, 21, 2,\n                                  22, 0, 0, 0, 72, 90, 97, 64, 8, 65, 22, 77,\n                                  104, 86, 71, 79, 8, 6, 75, 71, 92, 3, 82, 75,\n                                  85, 92, 81, 86, 83, 15, 65, 67, 85, 73, 91,\n                                  78, 93, 65, 76, 72, 87, 14, 71, 1, 83, 81, 74,\n                                  76, 68, 1, 0, 71, 5, 6, 71, 2, 66, 68, 3, 72,\n                                  24, 67, 1, 20, 21, 28, 26, 17, 85, 67, 70, 1,\n                                  67, 84, 68, 8, 69, 71, 4, 23, 47, 28, 2, 85,\n                                  82, 65, 34, 39, 105, 68, 2, 86, 9, 65, 64, 5,\n                                  33, 55, 44, 13, 84, 98, 7, 32, 41, 102, 20,\n                                  21, 22, 22, 23, 20, 14, 20, 21, 6, 13, 12, 5,\n                                  3, 66, 10, 7, 6, 8, 3, 7, 12, 4, 79, 4, 5, 69,\n                                  8, 72, 42, 51, 35, 26, 33, 39, 49, 44, 25, 4,\n                                  69, 3, 10, 10, 97, 7, 11, 74, 26, 11, 11, 12,\n                                  14, 10, 17, 17, 69, 93, 71, 73, 67, 100, 88,\n                                  6, 12, 10, 4, 69, 74, 79, 79, 94, 76, 22, 10,\n                                  5, 65, 2, 70, 78, 81, 85, 70, 24, 11, 6, 1, 4,\n                                  67, 72, 78, 87, 74, 19, 6, 8, 4, 0, 72, 76,\n                                  84, 66, 32, 16, 12, 7, 8, 64, 71, 72, 75, 62,\n                                  102, 98, 91, 96, 92, 91, 89, 87, 86, 86, 85,\n                                  82, 82, 85, 87, 91, 70, 86, 76, 80, 79, 77,\n                                  74, 71, 71, 68, 73, 69, 73, 68, 68, 8, 69, 77,\n                                  66, 68, 72, 1, 64, 67, 69, 3, 65, 72, 73, 65,\n                                  83, 69, 7, 67, 2, 69, 67, 67, 4, 2, 69, 69,\n                                  74, 74, 70, 57, 54, 56, 54, 52, 57, 57, 56,\n                                  52, 52, 56, 53, 44, 34, 16, 50, 46, 44, 39,\n                                  33, 26, 17, 24, 19, 13, 3, 65, 70, 79, 39, 36,\n                                  39, 26, 10, 16, 11, 3, 13, 6, 1, 78, 68, 77,\n                                  85, 12, 16, 64, 13, 17, 6, 0, 65, 66, 78, 68,\n                                  75, 81, 105, 76, 80, 89, 7, 71, 80, 74, 65, 2,\n                                  3, 9, 6, 13, 64, 8, 7, 14, 19, 20, 22, 8, 55,\n                                  40, 33, 27, 19, 17, 64, 72, 86, 3, 34, 28, 27,\n                                  19, 18, 9, 7, 2, 67, 74, 65, 2, 3, 9, 6, 13,\n                                  64, 8, 7, 14, 19, 20, 22, 8, 55, 40, 33, 27,\n                                  19, 17, 64, 72, 86 },\n\n                                {\n\n                                55,\n                                  7, 77, 55, 7, 77, 93, 76, 18, 11, 4, 13, 34,\n                                  47, 24, 5, 66, 17, 80, 73, 1, 64, 11, 73, 0,\n                                  30, 29, 64, 85, 111, 89, 90, 71, 80, 73, 1,\n                                  85, 71, 27, 4, 75, 85, 91, 79, 81, 88, 103,\n                                  64, 79, 90, 68, 82, 86, 99, 5, 74, 72, 82, 22,\n                                  2, 22, 0, 0, 0, 72, 90, 97, 0, 7, 65, 21, 77,\n                                  103, 84, 70, 78, 9, 7, 74, 70, 90, 4, 81, 74,\n                                  83, 93, 81, 86, 83, 16, 65, 66, 83, 73, 90,\n                                  77, 91, 65, 76, 72, 87, 15, 71, 2, 82, 81, 73,\n                                  76, 68, 1, 1, 70, 5, 6, 71, 2, 66, 68, 3, 72,\n                                  24, 67, 1, 21, 21, 29, 26, 18, 85, 67, 69, 1,\n                                  67, 84, 68, 9, 69, 70, 5, 24, 48, 29, 4, 85,\n                                  83, 64, 34, 39, 106, 68, 3, 86, 9, 65, 64, 6,\n                                  33, 55, 44, 14, 85, 96, 6, 29, 38, 100, 20,\n                                  21, 21, 21, 23, 19, 13, 20, 21, 5, 12, 12, 5,\n                                  3, 67, 10, 6, 5, 7, 3, 7, 11, 4, 80, 4, 4, 69,\n                                  7, 72, 40, 49, 33, 25, 31, 37, 46, 41, 24, 2,\n                                  71, 2, 8, 8, 99, 6, 10, 76, 25, 10, 10, 11,\n                                  13, 8, 15, 15, 70, 93, 72, 74, 68, 98, 86, 8,\n                                  12, 10, 4, 68, 73, 78, 78, 92, 75, 23, 11, 6,\n                                  65, 3, 69, 76, 80, 83, 70, 25, 12, 7, 2, 5,\n                                  67, 72, 77, 86, 74, 21, 7, 8, 4, 1, 72, 76,\n                                  83, 65, 33, 17, 13, 7, 9, 64, 70, 72, 75, 62,\n                                  100, 97, 90, 94, 91, 89, 88, 86, 84, 84, 83,\n                                  80, 82, 84, 87, 90, 67, 86, 77, 80, 78, 76,\n                                  74, 71, 71, 68, 72, 69, 74, 68, 68, 8, 69, 77,\n                                  66, 68, 72, 0, 64, 67, 70, 2, 65, 72, 73, 64,\n                                  84, 69, 8, 68, 2, 69, 67, 66, 4, 1, 68, 68,\n                                  74, 74, 71, 56, 53, 55, 52, 50, 55, 55, 53,\n                                  49, 49, 53, 50, 41, 31, 14, 46, 43, 40, 34,\n                                  30, 24, 15, 22, 16, 11, 2, 66, 71, 79, 37, 34,\n                                  37, 24, 8, 14, 10, 1, 11, 4, 64, 80, 70, 79,\n                                  86, 11, 15, 66, 12, 15, 5, 65, 67, 68, 79, 69,\n                                  76, 81, 104, 77, 82, 90, 6, 72, 81, 74, 64, 2,\n                                  3, 10, 7, 14, 64, 9, 8, 15, 20, 21, 22, 9, 55,\n                                  38, 31, 25, 17, 15, 66, 74, 87, 3, 35, 29, 28,\n                                  19, 19, 10, 7, 3, 67, 74, 64, 2, 3, 10, 7, 14,\n                                  64, 9, 8, 15, 20, 21, 22, 9, 55, 38, 31, 25,\n                                  17, 15, 66, 74, 87 },\n\n                                {\n\n                                53,\n                                  7, 77, 53, 7, 77, 92, 75, 18, 11, 4, 11, 32,\n                                  46, 25, 5, 65, 15, 80, 72, 0, 64, 12, 74, 65,\n                                  28, 27, 67, 88, 112, 87, 89, 71, 80, 72, 0,\n                                  85, 70, 27, 3, 75, 84, 89, 80, 83, 89, 103,\n                                  64, 78, 89, 69, 82, 86, 99, 5, 74, 72, 82, 22,\n                                  2, 22, 0, 0, 0, 71, 91, 97, 0, 6, 65, 21, 76,\n                                  102, 82, 69, 77, 11, 9, 74, 69, 88, 5, 80, 73,\n                                  80, 93, 82, 86, 84, 16, 66, 65, 80, 72, 90,\n                                  77, 89, 65, 76, 72, 87, 15, 71, 2, 81, 81, 73,\n                                  75, 68, 1, 1, 69, 6, 6, 72, 1, 66, 68, 3, 72,\n                                  24, 67, 1, 21, 21, 29, 26, 18, 86, 66, 69, 0,\n                                  67, 83, 68, 10, 68, 70, 7, 26, 49, 31, 6, 86,\n                                  84, 64, 35, 39, 107, 68, 3, 87, 10, 65, 64, 7,\n                                  33, 55, 44, 16, 86, 95, 5, 26, 35, 99, 19, 21,\n                                  21, 21, 22, 19, 13, 20, 20, 4, 11, 11, 5, 3,\n                                  67, 9, 6, 4, 7, 2, 6, 10, 3, 81, 3, 3, 69, 5,\n                                  73, 38, 47, 31, 23, 30, 35, 42, 39, 23, 0, 74,\n                                  0, 6, 6, 100, 4, 9, 77, 24, 9, 9, 9, 11, 6,\n                                  13, 14, 72, 93, 73, 75, 70, 97, 85, 9, 13, 10,\n                                  4, 67, 72, 77, 78, 90, 73, 24, 11, 6, 64, 5,\n                                  68, 75, 79, 80, 69, 25, 12, 7, 2, 6, 66, 71,\n                                  77, 85, 74, 22, 8, 8, 4, 2, 71, 76, 82, 64,\n                                  33, 18, 13, 7, 10, 0, 69, 71, 74, 62, 99, 95,\n                                  88, 93, 90, 88, 86, 84, 83, 83, 81, 77, 81,\n                                  83, 86, 89, 64, 85, 78, 79, 77, 76, 74, 71,\n                                  71, 69, 72, 70, 75, 68, 68, 9, 69, 77, 66, 68,\n                                  71, 0, 65, 67, 71, 1, 66, 72, 73, 0, 85, 70,\n                                  8, 68, 1, 69, 67, 66, 3, 1, 68, 68, 74, 74,\n                                  73, 55, 52, 54, 51, 47, 52, 52, 50, 47, 46,\n                                  49, 47, 37, 29, 12, 42, 39, 36, 29, 27, 22,\n                                  13, 20, 14, 9, 0, 67, 72, 79, 34, 31, 34, 22,\n                                  6, 12, 8, 64, 9, 2, 66, 82, 73, 80, 88, 10,\n                                  14, 69, 10, 14, 3, 67, 68, 69, 80, 70, 77, 81,\n                                  103, 79, 83, 92, 4, 73, 82, 74, 64, 3, 4, 11,\n                                  7, 14, 0, 10, 9, 16, 20, 22, 23, 9, 54, 36,\n                                  29, 23, 15, 13, 69, 76, 89, 4, 35, 29, 28, 20,\n                                  19, 10, 8, 3, 66, 74, 64, 3, 4, 11, 7, 14, 0,\n                                  10, 9, 16, 20, 22, 23, 9, 54, 36, 29, 23, 15,\n                                  13, 69, 76, 89 },\n\n                                {\n\n                                52,\n                                  7, 77, 52, 7, 77, 90, 73, 18, 11, 3, 9, 31,\n                                  45, 26, 5, 0, 13, 79, 70, 0, 64, 13, 75, 66,\n                                  27, 25, 70, 90, 112, 85, 88, 71, 79, 70, 0,\n                                  85, 69, 27, 3, 74, 83, 88, 81, 84, 89, 103,\n                                  64, 78, 88, 69, 82, 86, 99, 5, 73, 72, 81, 23,\n                                  2, 22, 0, 0, 0, 71, 91, 97, 1, 5, 65, 20, 76,\n                                  100, 79, 68, 76, 12, 10, 73, 68, 86, 6, 79,\n                                  72, 78, 94, 82, 86, 84, 16, 66, 64, 78, 72,\n                                  89, 76, 87, 65, 76, 72, 86, 15, 71, 3, 80, 80,\n                                  72, 75, 68, 2, 2, 68, 6, 6, 72, 1, 65, 68, 3,\n                                  72, 25, 67, 1, 22, 22, 29, 26, 18, 86, 66, 68,\n                                  0, 67, 83, 68, 11, 68, 69, 8, 27, 50, 32, 8,\n                                  86, 85, 0, 35, 39, 108, 68, 4, 87, 11, 65, 64,\n                                  9, 33, 55, 44, 17, 87, 93, 4, 24, 32, 98, 19,\n                                  21, 20, 20, 22, 19, 12, 20, 20, 3, 10, 11, 5,\n                                  3, 67, 9, 5, 3, 6, 2, 6, 9, 3, 82, 2, 3, 69,\n                                  4, 73, 36, 45, 30, 22, 28, 33, 39, 36, 22, 65,\n                                  76, 64, 4, 4, 101, 3, 8, 79, 23, 8, 8, 8, 10,\n                                  4, 11, 12, 73, 93, 74, 76, 72, 95, 83, 10, 13,\n                                  10, 4, 66, 71, 76, 77, 88, 72, 25, 12, 7, 0,\n                                  6, 67, 73, 78, 78, 68, 26, 13, 8, 3, 7, 65,\n                                  71, 76, 84, 73, 23, 9, 8, 4, 3, 71, 75, 81, 0,\n                                  33, 19, 13, 7, 11, 1, 68, 71, 73, 62, 98, 94,\n                                  87, 91, 89, 86, 85, 82, 81, 81, 79, 75, 80,\n                                  82, 85, 88, 2, 85, 79, 79, 76, 75, 74, 71, 71,\n                                  69, 71, 70, 76, 68, 68, 10, 69, 77, 66, 68,\n                                  71, 64, 65, 67, 72, 0, 66, 72, 73, 1, 85, 70,\n                                  9, 69, 1, 69, 67, 66, 3, 0, 68, 67, 74, 74,\n                                  74, 54, 51, 53, 49, 45, 50, 49, 47, 44, 43,\n                                  46, 44, 34, 26, 10, 38, 36, 32, 24, 24, 20,\n                                  12, 18, 11, 7, 64, 68, 73, 79, 32, 29, 32, 20,\n                                  4, 10, 7, 66, 7, 0, 68, 84, 75, 82, 89, 9, 13,\n                                  71, 9, 12, 2, 69, 69, 70, 81, 71, 78, 81, 102,\n                                  80, 84, 93, 3, 74, 83, 74, 0, 3, 5, 12, 8, 15,\n                                  0, 11, 10, 17, 21, 23, 23, 10, 54, 34, 27, 21,\n                                  13, 11, 71, 78, 90, 4, 36, 30, 29, 21, 20, 11,\n                                  8, 3, 65, 74, 0, 3, 5, 12, 8, 15, 0, 11, 10,\n                                  17, 21, 23, 23, 10, 54, 34, 27, 21, 13, 11,\n                                  71, 78, 90 },\n\n                                {\n\n                                51,\n                                  7, 78, 51, 7, 78, 88, 72, 19, 11, 3, 8, 29,\n                                  44, 26, 6, 2, 12, 79, 69, 0, 65, 14, 76, 67,\n                                  26, 24, 74, 92, 113, 83, 86, 71, 79, 69, 0,\n                                  84, 68, 28, 3, 73, 82, 87, 83, 85, 89, 104,\n                                  64, 78, 88, 69, 83, 85, 99, 4, 73, 72, 80, 23,\n                                  2, 22, 0, 0, 0, 70, 91, 97, 1, 5, 66, 20, 75,\n                                  99, 77, 67, 75, 14, 12, 72, 67, 84, 7, 78, 72,\n                                  76, 95, 82, 86, 84, 17, 66, 0, 76, 72, 88, 75,\n                                  85, 65, 76, 72, 86, 16, 72, 3, 80, 80, 71, 75,\n                                  67, 2, 2, 67, 7, 6, 72, 1, 65, 68, 3, 72, 25,\n                                  67, 1, 22, 22, 30, 27, 19, 87, 65, 67, 64, 67,\n                                  83, 68, 12, 68, 69, 9, 28, 50, 34, 9, 87, 86,\n                                  0, 35, 39, 108, 69, 4, 88, 11, 66, 0, 10, 33,\n                                  55, 45, 18, 88, 92, 3, 21, 29, 96, 19, 21, 20,\n                                  19, 21, 18, 12, 19, 19, 3, 10, 11, 4, 3, 68,\n                                  8, 4, 2, 6, 2, 6, 9, 2, 84, 2, 2, 69, 3, 74,\n                                  33, 43, 28, 20, 26, 31, 36, 34, 20, 67, 78,\n                                  66, 2, 2, 103, 2, 6, 81, 21, 7, 7, 7, 8, 2, 9,\n                                  10, 75, 93, 75, 77, 73, 94, 82, 12, 14, 10, 4,\n                                  65, 71, 76, 76, 87, 71, 26, 13, 8, 0, 7, 66,\n                                  72, 77, 76, 68, 26, 13, 8, 3, 8, 65, 70, 75,\n                                  83, 73, 25, 10, 8, 4, 3, 70, 75, 81, 0, 34,\n                                  19, 14, 7, 12, 1, 68, 70, 73, 62, 96, 92, 85,\n                                  89, 87, 85, 83, 81, 80, 79, 77, 73, 80, 81,\n                                  85, 88, 5, 85, 80, 79, 76, 74, 74, 71, 71, 69,\n                                  71, 70, 77, 68, 68, 10, 69, 77, 66, 68, 71,\n                                  64, 65, 67, 73, 64, 66, 72, 73, 2, 86, 70, 10,\n                                  70, 1, 69, 67, 65, 3, 0, 67, 66, 74, 74, 76,\n                                  53, 50, 52, 47, 43, 47, 47, 44, 42, 40, 43,\n                                  41, 31, 23, 8, 35, 32, 28, 19, 22, 17, 10, 16,\n                                  9, 5, 65, 69, 74, 79, 30, 27, 30, 18, 2, 9, 5,\n                                  68, 5, 66, 70, 86, 77, 84, 90, 8, 11, 73, 7,\n                                  10, 0, 71, 71, 72, 82, 72, 79, 82, 101, 81,\n                                  86, 95, 2, 76, 84, 73, 0, 4, 5, 13, 9, 16, 0,\n                                  12, 11, 18, 21, 24, 24, 11, 53, 32, 25, 19,\n                                  11, 9, 73, 80, 91, 5, 36, 30, 30, 21, 21, 11,\n                                  9, 4, 65, 73, 0, 4, 5, 13, 9, 16, 0, 12, 11,\n                                  18, 21, 24, 24, 11, 53, 32, 25, 19, 11, 9, 73,\n                                  80, 91 },\n\n                                {\n\n                                50,\n                                  7, 78, 50, 7, 78, 86, 70, 19, 11, 2, 6, 28,\n                                  43, 27, 6, 3, 10, 79, 67, 64, 65, 15, 77, 68,\n                                  25, 22, 77, 95, 114, 81, 85, 71, 79, 67, 64,\n                                  84, 67, 28, 3, 73, 81, 85, 84, 86, 89, 104,\n                                  64, 77, 87, 70, 83, 85, 99, 4, 73, 72, 79, 24,\n                                  2, 22, 0, 0, 0, 70, 91, 97, 2, 4, 66, 19, 75,\n                                  98, 75, 66, 74, 15, 13, 71, 66, 82, 8, 77, 71,\n                                  73, 95, 83, 86, 85, 17, 66, 1, 73, 71, 88, 75,\n                                  83, 65, 76, 72, 86, 16, 72, 4, 79, 80, 70, 74,\n                                  67, 2, 3, 66, 7, 6, 73, 1, 65, 68, 3, 72, 25,\n                                  67, 1, 23, 22, 30, 27, 19, 87, 65, 67, 64, 67,\n                                  82, 68, 13, 67, 68, 11, 30, 51, 35, 11, 87,\n                                  87, 1, 36, 39, 109, 69, 5, 88, 12, 66, 0, 11,\n                                  33, 55, 45, 20, 89, 90, 2, 18, 26, 95, 19, 21,\n                                  19, 19, 21, 18, 11, 19, 19, 2, 9, 11, 4, 3,\n                                  68, 8, 4, 1, 5, 2, 6, 8, 2, 85, 1, 1, 69, 2,\n                                  74, 31, 41, 26, 19, 25, 29, 33, 31, 19, 69,\n                                  80, 67, 0, 0, 104, 1, 5, 82, 20, 6, 6, 5, 7,\n                                  0, 7, 9, 76, 93, 76, 78, 75, 92, 80, 13, 14,\n                                  10, 4, 64, 70, 75, 76, 85, 69, 27, 14, 8, 1,\n                                  9, 65, 70, 76, 73, 67, 27, 14, 9, 4, 9, 64,\n                                  70, 74, 82, 73, 26, 11, 8, 4, 4, 70, 75, 80,\n                                  1, 34, 20, 14, 7, 13, 2, 67, 70, 72, 62, 95,\n                                  91, 84, 88, 86, 83, 82, 79, 78, 77, 75, 70,\n                                  79, 80, 84, 87, 8, 84, 81, 78, 75, 73, 74, 71,\n                                  71, 69, 70, 71, 78, 68, 68, 11, 69, 77, 66,\n                                  68, 70, 65, 66, 67, 74, 65, 67, 72, 73, 3, 87,\n                                  71, 11, 70, 0, 69, 67, 65, 2, 64, 67, 66, 74,\n                                  74, 77, 52, 49, 51, 46, 40, 45, 44, 41, 39,\n                                  37, 40, 38, 28, 21, 6, 31, 29, 24, 14, 19, 15,\n                                  8, 14, 6, 3, 66, 70, 75, 79, 28, 24, 27, 16,\n                                  0, 7, 4, 70, 3, 68, 72, 88, 79, 85, 92, 7, 10,\n                                  75, 6, 9, 64, 73, 72, 73, 83, 73, 80, 82, 100,\n                                  83, 87, 96, 0, 77, 85, 73, 1, 4, 6, 14, 10,\n                                  16, 1, 13, 12, 19, 22, 25, 24, 11, 53, 30, 23,\n                                  17, 9, 7, 76, 82, 92, 5, 37, 31, 30, 22, 22,\n                                  12, 9, 4, 64, 73, 1, 4, 6, 14, 10, 16, 1, 13,\n                                  12, 19, 22, 25, 24, 11, 53, 30, 23, 17, 9, 7,\n                                  76, 82, 92 },\n\n                                {\n\n                                48,\n                                  6, 78, 48, 6, 78, 85, 69, 19, 11, 2, 4, 26,\n                                  42, 27, 6, 5, 8, 79, 66, 64, 66, 16, 78, 70,\n                                  23, 20, 81, 97, 115, 79, 84, 71, 79, 66, 64,\n                                  84, 67, 28, 2, 72, 80, 84, 85, 88, 90, 105,\n                                  64, 77, 86, 70, 84, 85, 99, 4, 73, 72, 79, 24,\n                                  2, 22, 0, 0, 0, 69, 92, 97, 2, 3, 66, 19, 74,\n                                  97, 73, 65, 74, 17, 15, 71, 65, 80, 8, 76, 70,\n                                  71, 96, 83, 87, 85, 17, 67, 1, 71, 71, 87, 74,\n                                  82, 65, 76, 72, 86, 16, 72, 4, 78, 80, 70, 74,\n                                  67, 2, 3, 65, 8, 6, 73, 0, 65, 68, 2, 72, 25,\n                                  67, 1, 23, 22, 30, 27, 19, 88, 64, 66, 65, 67,\n                                  82, 68, 14, 67, 68, 12, 31, 52, 37, 13, 88,\n                                  88, 1, 36, 39, 110, 69, 5, 89, 12, 66, 0, 12,\n                                  33, 55, 45, 21, 90, 89, 1, 15, 22, 94, 18, 21,\n                                  19, 18, 20, 17, 11, 19, 18, 1, 8, 10, 4, 2,\n                                  69, 7, 3, 0, 5, 1, 5, 7, 1, 86, 0, 0, 69, 0,\n                                  75, 29, 39, 24, 17, 23, 26, 29, 29, 18, 71,\n                                  83, 69, 66, 65, 106, 64, 4, 84, 19, 5, 5, 4,\n                                  5, 65, 5, 7, 78, 93, 77, 79, 77, 91, 79, 14,\n                                  15, 10, 4, 64, 69, 74, 75, 83, 68, 27, 14, 9,\n                                  1, 10, 64, 69, 75, 71, 67, 27, 14, 9, 4, 9,\n                                  64, 69, 74, 81, 73, 27, 12, 8, 4, 5, 69, 75,\n                                  79, 2, 34, 21, 14, 7, 14, 2, 66, 69, 72, 62,\n                                  94, 89, 82, 86, 85, 82, 80, 78, 77, 76, 73,\n                                  68, 79, 79, 84, 86, 11, 84, 82, 78, 74, 73,\n                                  74, 71, 71, 70, 70, 71, 79, 68, 68, 11, 69,\n                                  77, 67, 68, 70, 65, 66, 68, 75, 66, 67, 73,\n                                  73, 4, 88, 71, 11, 71, 0, 69, 68, 65, 2, 64,\n                                  67, 65, 74, 74, 79, 51, 48, 50, 44, 38, 42,\n                                  41, 38, 37, 34, 36, 35, 24, 18, 4, 27, 25, 20,\n                                  9, 16, 13, 6, 11, 4, 1, 68, 72, 76, 79, 25,\n                                  22, 25, 14, 66, 5, 2, 73, 1, 70, 74, 90, 82,\n                                  87, 93, 5, 9, 78, 4, 7, 66, 75, 74, 75, 84,\n                                  74, 81, 82, 99, 84, 89, 98, 64, 78, 86, 73, 1,\n                                  5, 6, 15, 10, 17, 1, 14, 12, 20, 22, 25, 25,\n                                  12, 52, 28, 21, 15, 7, 5, 78, 84, 94, 6, 37,\n                                  31, 31, 22, 22, 12, 10, 4, 64, 73, 1, 5, 6,\n                                  15, 10, 17, 1, 14, 12, 20, 22, 25, 25, 12, 52,\n                                  28, 21, 15, 7, 5, 78, 84, 94 },\n\n                                {\n\n                                47,\n                                  6, 78, 47, 6, 78, 83, 68, 20, 11, 2, 2, 24,\n                                  42, 28, 6, 7, 7, 78, 64, 64, 66, 17, 78, 71,\n                                  22, 18, 84, 99, 115, 77, 82, 70, 78, 64, 64,\n                                  83, 66, 29, 2, 71, 79, 83, 86, 89, 90, 105,\n                                  64, 77, 85, 70, 84, 85, 99, 4, 72, 71, 78, 24,\n                                  2, 22, 0, 0, 0, 68, 92, 97, 2, 2, 66, 19, 73,\n                                  95, 70, 64, 73, 19, 17, 70, 64, 78, 9, 74, 69,\n                                  69, 97, 83, 87, 85, 18, 67, 2, 69, 71, 86, 73,\n                                  80, 65, 75, 72, 85, 17, 72, 5, 77, 79, 69, 74,\n                                  67, 3, 4, 64, 9, 6, 73, 0, 64, 67, 2, 72, 26,\n                                  67, 1, 23, 23, 31, 27, 20, 88, 0, 65, 66, 67,\n                                  82, 68, 15, 67, 67, 13, 32, 53, 39, 15, 89,\n                                  89, 2, 36, 40, 111, 69, 5, 89, 13, 66, 0, 14,\n                                  33, 55, 45, 22, 91, 88, 0, 13, 19, 92, 18, 21,\n                                  19, 17, 20, 17, 11, 19, 18, 0, 7, 10, 4, 2,\n                                  69, 7, 2, 0, 5, 1, 5, 6, 0, 87, 0, 0, 69, 64,\n                                  75, 27, 37, 23, 16, 21, 24, 26, 27, 17, 73,\n                                  85, 70, 68, 66, 107, 65, 3, 86, 18, 4, 4, 3,\n                                  3, 66, 3, 5, 79, 93, 77, 80, 78, 89, 77, 16,\n                                  16, 10, 4, 0, 68, 73, 74, 81, 67, 28, 15, 10,\n                                  2, 11, 0, 68, 74, 69, 66, 28, 15, 10, 4, 10,\n                                  0, 68, 73, 79, 72, 29, 13, 9, 4, 6, 68, 74,\n                                  78, 3, 35, 22, 15, 8, 15, 3, 65, 68, 71, 62,\n                                  92, 87, 80, 84, 84, 81, 78, 76, 75, 74, 71,\n                                  66, 78, 78, 83, 85, 15, 84, 83, 78, 73, 72,\n                                  73, 71, 71, 70, 70, 71, 80, 68, 68, 12, 69,\n                                  77, 67, 68, 70, 65, 66, 68, 75, 67, 67, 73,\n                                  72, 6, 88, 71, 12, 72, 0, 69, 68, 64, 2, 64,\n                                  66, 64, 73, 73, 81, 50, 47, 49, 42, 36, 39,\n                                  39, 35, 35, 32, 33, 33, 21, 15, 2, 23, 22, 17,\n                                  4, 13, 11, 5, 9, 2, 0, 69, 73, 77, 79, 23, 20,\n                                  23, 12, 68, 3, 1, 75, 64, 72, 76, 92, 84, 89,\n                                  94, 4, 8, 80, 3, 5, 67, 77, 75, 76, 85, 75,\n                                  81, 82, 98, 85, 90, 100, 65, 79, 87, 73, 2, 6,\n                                  7, 17, 11, 18, 1, 15, 13, 21, 23, 26, 26, 13,\n                                  51, 27, 19, 13, 5, 3, 80, 86, 95, 7, 37, 32,\n                                  32, 23, 23, 13, 11, 5, 0, 73, 2, 6, 7, 17, 11,\n                                  18, 1, 15, 13, 21, 23, 26, 26, 13, 51, 27, 19,\n                                  13, 5, 3, 80, 86, 95 },\n\n                                {\n\n                                46,\n                                  6, 78, 46, 6, 78, 81, 66, 20, 11, 1, 0, 23,\n                                  41, 29, 6, 8, 5, 78, 0, 65, 66, 18, 79, 72,\n                                  21, 16, 87, 102, 116, 75, 81, 70, 78, 0, 65,\n                                  83, 65, 29, 2, 71, 78, 81, 87, 90, 90, 105,\n                                  64, 76, 84, 71, 84, 85, 99, 4, 72, 71, 77, 25,\n                                  2, 22, 0, 0, 0, 68, 92, 97, 3, 1, 66, 18, 73,\n                                  94, 68, 0, 72, 20, 18, 69, 0, 76, 10, 73, 68,\n                                  66, 97, 84, 87, 86, 18, 67, 3, 66, 70, 86, 73,\n                                  78, 65, 75, 72, 85, 17, 72, 5, 76, 79, 68, 73,\n                                  67, 3, 4, 0, 9, 6, 74, 0, 64, 67, 2, 72, 26,\n                                  67, 1, 24, 23, 31, 27, 20, 89, 0, 65, 66, 67,\n                                  81, 68, 16, 66, 67, 15, 34, 54, 40, 17, 89,\n                                  90, 2, 37, 40, 112, 69, 6, 90, 14, 66, 0, 15,\n                                  33, 55, 45, 24, 92, 86, 64, 10, 16, 91, 18,\n                                  21, 18, 17, 19, 17, 10, 19, 17, 64, 6, 10, 4,\n                                  2, 69, 6, 2, 64, 4, 1, 5, 5, 0, 88, 64, 64,\n                                  69, 65, 76, 25, 35, 21, 14, 20, 22, 23, 24,\n                                  16, 75, 87, 72, 70, 68, 108, 66, 2, 87, 17, 3,\n                                  3, 1, 2, 68, 1, 4, 81, 93, 78, 81, 80, 88, 76,\n                                  17, 16, 10, 4, 1, 67, 72, 74, 79, 65, 29, 16,\n                                  10, 3, 13, 1, 66, 73, 66, 65, 28, 15, 10, 5,\n                                  11, 1, 68, 72, 78, 72, 30, 14, 9, 4, 7, 68,\n                                  74, 77, 4, 35, 23, 15, 8, 16, 4, 64, 68, 70,\n                                  62, 91, 86, 79, 83, 83, 79, 77, 74, 74, 72,\n                                  69, 0, 77, 77, 82, 84, 18, 83, 84, 77, 72, 71,\n                                  73, 71, 71, 70, 69, 72, 81, 68, 68, 13, 69,\n                                  77, 67, 68, 69, 66, 67, 68, 76, 68, 68, 73,\n                                  72, 7, 89, 72, 13, 72, 64, 69, 68, 64, 1, 65,\n                                  66, 64, 73, 73, 82, 49, 46, 48, 41, 33, 37,\n                                  36, 32, 32, 29, 30, 30, 18, 13, 0, 19, 18, 13,\n                                  64, 10, 9, 3, 7, 64, 65, 70, 74, 78, 79, 21,\n                                  17, 20, 10, 70, 1, 64, 77, 66, 74, 78, 94, 86,\n                                  90, 96, 3, 7, 82, 1, 4, 69, 79, 76, 77, 86,\n                                  76, 82, 82, 97, 87, 91, 101, 67, 80, 88, 73,\n                                  2, 6, 8, 18, 12, 18, 2, 16, 14, 22, 23, 27,\n                                  26, 13, 51, 25, 17, 11, 3, 1, 83, 88, 96, 7,\n                                  38, 32, 32, 24, 24, 13, 11, 5, 1, 73, 2, 6, 8,\n                                  18, 12, 18, 2, 16, 14, 22, 23, 27, 26, 13, 51,\n                                  25, 17, 11, 3, 1, 83, 88, 96 },\n\n                                {\n\n                                45,\n                                  6, 79, 45, 6, 79, 79, 65, 21, 11, 1, 64, 21,\n                                  40, 29, 7, 10, 4, 78, 2, 65, 67, 19, 80, 73,\n                                  20, 15, 91, 104, 117, 73, 79, 70, 78, 2, 65,\n                                  82, 64, 30, 2, 70, 77, 80, 89, 91, 90, 106,\n                                  64, 76, 84, 71, 85, 84, 99, 3, 72, 71, 76, 25,\n                                  2, 22, 0, 0, 0, 67, 92, 97, 3, 1, 67, 18, 72,\n                                  93, 66, 1, 71, 22, 20, 68, 1, 74, 11, 72, 68,\n                                  64, 98, 84, 87, 86, 19, 67, 4, 64, 70, 85, 72,\n                                  76, 65, 75, 72, 85, 18, 73, 6, 76, 79, 67, 73,\n                                  66, 3, 5, 1, 10, 6, 74, 0, 64, 67, 2, 72, 26,\n                                  67, 1, 24, 23, 32, 28, 21, 89, 1, 64, 67, 67,\n                                  81, 68, 17, 66, 66, 16, 35, 54, 42, 18, 90,\n                                  91, 3, 37, 40, 112, 70, 6, 90, 14, 67, 1, 16,\n                                  33, 55, 46, 25, 93, 85, 65, 7, 13, 89, 18, 21,\n                                  18, 16, 19, 16, 10, 18, 17, 64, 6, 10, 3, 2,\n                                  70, 6, 1, 65, 4, 1, 5, 5, 64, 90, 64, 65, 69,\n                                  66, 76, 22, 33, 19, 13, 18, 20, 20, 22, 14,\n                                  77, 89, 73, 72, 70, 110, 67, 0, 89, 15, 2, 2,\n                                  0, 0, 70, 64, 2, 82, 93, 79, 82, 81, 86, 74,\n                                  19, 17, 10, 4, 2, 67, 72, 73, 78, 64, 30, 17,\n                                  11, 3, 14, 2, 65, 72, 64, 65, 29, 16, 11, 5,\n                                  12, 1, 67, 71, 77, 72, 32, 15, 9, 4, 7, 67,\n                                  74, 77, 4, 36, 23, 16, 8, 17, 4, 64, 67, 70,\n                                  62, 89, 84, 77, 81, 81, 78, 75, 73, 72, 70,\n                                  67, 2, 77, 76, 82, 84, 21, 83, 85, 77, 72, 70,\n                                  73, 71, 71, 70, 69, 72, 82, 68, 68, 13, 69,\n                                  77, 67, 68, 69, 66, 67, 68, 77, 69, 68, 73,\n                                  72, 8, 90, 72, 14, 73, 64, 69, 68, 0, 1, 65,\n                                  65, 0, 73, 73, 84, 48, 45, 47, 39, 31, 34, 34,\n                                  29, 30, 26, 27, 27, 15, 10, 65, 16, 15, 9, 69,\n                                  8, 6, 1, 5, 66, 67, 71, 75, 79, 79, 19, 15,\n                                  18, 8, 72, 0, 65, 79, 68, 77, 80, 96, 88, 92,\n                                  97, 2, 5, 84, 0, 2, 70, 81, 78, 79, 87, 77,\n                                  83, 83, 96, 88, 93, 103, 68, 82, 89, 72, 3, 7,\n                                  8, 19, 13, 19, 2, 17, 15, 23, 24, 28, 27, 14,\n                                  50, 23, 15, 9, 1, 64, 85, 90, 97, 8, 38, 33,\n                                  33, 24, 25, 14, 12, 6, 1, 72, 3, 7, 8, 19, 13,\n                                  19, 2, 17, 15, 23, 24, 28, 27, 14, 50, 23, 15,\n                                  9, 1, 64, 85, 90, 97 },\n\n                                {\n\n                                43,\n                                  6, 79, 43, 6, 79, 78, 0, 21, 11, 0, 66, 20,\n                                  39, 30, 7, 12, 2, 78, 3, 65, 67, 20, 81, 75,\n                                  18, 13, 94, 106, 118, 71, 78, 70, 78, 3, 65,\n                                  82, 0, 30, 1, 69, 76, 79, 90, 93, 91, 106, 64,\n                                  76, 83, 71, 85, 84, 99, 3, 72, 71, 76, 26, 2,\n                                  22, 0, 0, 0, 67, 93, 97, 4, 0, 67, 17, 72, 92,\n                                  64, 2, 70, 23, 21, 68, 2, 72, 12, 71, 67, 1,\n                                  99, 84, 87, 86, 19, 68, 5, 1, 70, 84, 71, 74,\n                                  65, 75, 72, 85, 18, 73, 6, 75, 79, 67, 73, 66,\n                                  3, 5, 2, 10, 6, 74, 64, 64, 67, 2, 72, 26, 67,\n                                  1, 25, 23, 32, 28, 21, 90, 1, 0, 67, 67, 81,\n                                  68, 18, 66, 66, 17, 36, 55, 43, 20, 90, 92, 3,\n                                  37, 40, 113, 70, 7, 91, 15, 67, 1, 17, 33, 55,\n                                  46, 26, 94, 83, 66, 4, 10, 88, 17, 21, 17, 15,\n                                  18, 16, 9, 18, 16, 65, 5, 9, 3, 2, 70, 5, 0,\n                                  66, 3, 0, 4, 4, 64, 91, 65, 66, 69, 68, 77,\n                                  20, 31, 17, 11, 16, 18, 16, 19, 13, 79, 92,\n                                  75, 74, 72, 111, 69, 64, 91, 14, 1, 1, 64, 64,\n                                  72, 66, 0, 84, 93, 80, 83, 83, 85, 73, 20, 17,\n                                  10, 4, 3, 66, 71, 72, 76, 0, 31, 17, 12, 4,\n                                  15, 3, 0, 71, 1, 64, 29, 16, 11, 6, 13, 2, 67,\n                                  71, 76, 72, 33, 16, 9, 4, 8, 67, 74, 76, 5,\n                                  36, 24, 16, 8, 18, 5, 0, 67, 69, 62, 88, 83,\n                                  76, 79, 80, 76, 74, 71, 71, 69, 65, 4, 76, 75,\n                                  81, 83, 24, 83, 86, 77, 71, 70, 73, 71, 71,\n                                  71, 68, 72, 83, 68, 68, 14, 69, 77, 67, 68,\n                                  69, 67, 67, 68, 78, 70, 68, 73, 72, 9, 91, 72,\n                                  14, 74, 64, 69, 68, 0, 1, 66, 65, 1, 73, 73,\n                                  85, 47, 44, 46, 37, 29, 32, 31, 26, 27, 23,\n                                  23, 24, 11, 7, 67, 12, 11, 5, 74, 5, 4, 64, 3,\n                                  69, 69, 73, 76, 80, 79, 16, 13, 16, 6, 74, 65,\n                                  67, 81, 70, 79, 82, 98, 91, 94, 98, 1, 4, 87,\n                                  65, 0, 72, 83, 79, 80, 88, 78, 84, 83, 95, 89,\n                                  94, 104, 69, 83, 90, 72, 3, 7, 9, 20, 13, 20,\n                                  2, 18, 16, 24, 24, 29, 27, 15, 50, 21, 13, 7,\n                                  64, 66, 87, 92, 99, 8, 39, 33, 34, 25, 25, 14,\n                                  12, 6, 2, 72, 3, 7, 9, 20, 13, 20, 2, 18, 16,\n                                  24, 24, 29, 27, 15, 50, 21, 13, 7, 64, 66, 87,\n                                  92, 99 },\n\n                                {\n\n                                42,\n                                  6, 79, 42, 6, 79, 76, 1, 21, 11, 0, 68, 18,\n                                  38, 31, 7, 13, 0, 77, 5, 66, 67, 21, 82, 76,\n                                  17, 11, 97, 109, 118, 69, 77, 70, 77, 5, 66,\n                                  82, 1, 30, 1, 69, 75, 77, 91, 94, 91, 106, 64,\n                                  75, 82, 72, 85, 84, 99, 3, 71, 71, 75, 26, 2,\n                                  22, 0, 0, 0, 66, 93, 97, 4, 64, 67, 17, 71,\n                                  90, 2, 3, 69, 25, 23, 67, 3, 70, 13, 70, 66,\n                                  4, 99, 85, 87, 87, 19, 68, 6, 4, 69, 84, 71,\n                                  72, 65, 75, 72, 84, 18, 73, 7, 74, 78, 66, 72,\n                                  66, 4, 6, 3, 11, 6, 75, 64, 0, 67, 2, 72, 27,\n                                  67, 1, 25, 24, 32, 28, 21, 90, 2, 0, 68, 67,\n                                  80, 68, 19, 65, 65, 19, 38, 56, 45, 22, 91,\n                                  93, 4, 38, 40, 114, 70, 7, 91, 16, 67, 1, 19,\n                                  33, 55, 46, 28, 95, 82, 67, 2, 7, 87, 17, 21,\n                                  17, 15, 18, 16, 9, 18, 16, 66, 4, 9, 3, 2, 70,\n                                  5, 0, 67, 3, 0, 4, 3, 65, 92, 66, 66, 69, 69,\n                                  77, 18, 29, 16, 10, 15, 16, 13, 17, 12, 81,\n                                  94, 76, 76, 74, 112, 70, 65, 92, 13, 0, 0, 66,\n                                  66, 74, 68, 64, 85, 93, 81, 84, 85, 83, 71,\n                                  21, 18, 10, 4, 4, 65, 70, 72, 74, 2, 32, 18,\n                                  12, 5, 17, 4, 1, 70, 4, 0, 30, 17, 12, 6, 14,\n                                  3, 66, 70, 75, 71, 34, 17, 9, 4, 9, 66, 73,\n                                  75, 6, 36, 25, 16, 8, 19, 6, 1, 66, 68, 62,\n                                  87, 81, 74, 78, 79, 75, 72, 69, 69, 67, 0, 7,\n                                  75, 74, 80, 82, 27, 82, 87, 76, 70, 69, 73,\n                                  71, 71, 71, 68, 73, 84, 68, 68, 15, 69, 77,\n                                  67, 68, 68, 67, 68, 68, 79, 71, 69, 73, 72,\n                                  10, 91, 73, 15, 74, 65, 69, 68, 0, 0, 66, 65,\n                                  1, 73, 73, 87, 46, 43, 45, 36, 26, 29, 28, 23,\n                                  25, 20, 20, 21, 8, 5, 69, 8, 8, 1, 79, 2, 2,\n                                  65, 1, 71, 71, 74, 77, 81, 79, 14, 10, 13, 4,\n                                  76, 67, 68, 83, 72, 81, 84, 100, 93, 95, 100,\n                                  0, 3, 89, 66, 64, 73, 85, 80, 81, 89, 79, 85,\n                                  83, 94, 91, 95, 106, 71, 84, 91, 72, 4, 8, 10,\n                                  21, 14, 20, 3, 19, 17, 25, 25, 30, 28, 15, 49,\n                                  19, 11, 5, 66, 68, 90, 94, 100, 9, 39, 34, 34,\n                                  26, 26, 15, 13, 6, 3, 72, 4, 8, 10, 21, 14,\n                                  20, 3, 19, 17, 25, 25, 30, 28, 15, 49, 19, 11,\n                                  5, 66, 68, 90, 94, 100 },\n\n                                {\n\n                                41,\n                                  6, 79, 41, 6, 79, 74, 3, 22, 11, 64, 70, 17,\n                                  37, 31, 7, 15, 64, 77, 6, 66, 68, 22, 83, 77,\n                                  16, 9, 101, 111, 119, 67, 75, 70, 77, 6, 66,\n                                  81, 2, 31, 1, 68, 74, 76, 92, 95, 91, 107, 64,\n                                  75, 81, 72, 86, 84, 99, 3, 71, 71, 74, 27, 2,\n                                  22, 0, 0, 0, 66, 93, 97, 5, 65, 67, 16, 71,\n                                  89, 4, 4, 68, 26, 24, 66, 4, 68, 14, 69, 65,\n                                  6, 100, 85, 87, 87, 20, 68, 7, 6, 69, 83, 70,\n                                  70, 65, 75, 72, 84, 19, 73, 7, 73, 78, 65, 72,\n                                  66, 4, 6, 4, 11, 6, 75, 64, 0, 67, 2, 72, 27,\n                                  67, 1, 26, 24, 33, 28, 22, 91, 2, 1, 68, 67,\n                                  80, 68, 20, 65, 65, 20, 39, 57, 46, 24, 91,\n                                  94, 4, 38, 40, 115, 70, 8, 92, 16, 67, 1, 20,\n                                  33, 55, 46, 29, 96, 80, 68, 64, 4, 85, 17, 21,\n                                  16, 14, 17, 15, 8, 18, 15, 67, 3, 9, 3, 2, 71,\n                                  4, 64, 68, 2, 0, 4, 2, 65, 93, 66, 67, 69, 70,\n                                  78, 16, 27, 14, 8, 13, 14, 10, 14, 11, 83, 96,\n                                  78, 78, 76, 114, 71, 66, 94, 12, 64, 64, 67,\n                                  67, 76, 70, 66, 87, 93, 82, 85, 86, 82, 70,\n                                  23, 18, 10, 4, 5, 64, 69, 71, 72, 3, 33, 19,\n                                  13, 5, 18, 5, 3, 69, 6, 0, 30, 17, 12, 7, 15,\n                                  3, 66, 69, 74, 71, 36, 18, 9, 4, 10, 66, 73,\n                                  74, 7, 37, 26, 17, 8, 20, 6, 2, 66, 68, 62,\n                                  85, 80, 73, 76, 78, 73, 71, 68, 68, 65, 2, 9,\n                                  75, 73, 80, 81, 30, 82, 88, 76, 69, 68, 73,\n                                  71, 71, 71, 67, 73, 85, 68, 68, 15, 69, 77,\n                                  67, 68, 68, 68, 68, 68, 80, 72, 69, 73, 72,\n                                  11, 92, 73, 16, 75, 65, 69, 68, 1, 0, 67, 64,\n                                  2, 73, 73, 88, 45, 42, 44, 34, 24, 27, 26, 20,\n                                  22, 17, 17, 18, 5, 2, 71, 4, 4, 66, 84, 64, 0,\n                                  67, 64, 74, 73, 75, 78, 82, 79, 12, 8, 11, 2,\n                                  78, 69, 70, 85, 74, 83, 86, 102, 95, 97, 101,\n                                  64, 2, 91, 68, 66, 75, 87, 82, 83, 90, 80, 86,\n                                  83, 93, 92, 97, 107, 72, 85, 92, 72, 4, 8, 10,\n                                  22, 15, 21, 3, 20, 18, 26, 25, 31, 28, 16, 49,\n                                  17, 9, 3, 68, 70, 92, 96, 101, 9, 40, 34, 35,\n                                  26, 27, 15, 13, 7, 3, 72, 4, 8, 10, 22, 15,\n                                  21, 3, 20, 18, 26, 25, 31, 28, 16, 49, 17, 9,\n                                  3, 68, 70, 92, 96, 101 },\n\n                                {\n\n                                40,\n                                  6, 79, 40, 6, 79, 72, 4, 22, 11, 64, 72, 15,\n                                  36, 32, 7, 17, 66, 77, 8, 66, 68, 23, 84, 78,\n                                  15, 7, 104, 113, 120, 65, 74, 70, 77, 8, 66,\n                                  81, 3, 31, 1, 67, 73, 75, 93, 96, 91, 107, 64,\n                                  75, 80, 72, 86, 84, 99, 3, 71, 71, 73, 27, 2,\n                                  22, 0, 0, 0, 65, 93, 97, 5, 66, 67, 16, 70,\n                                  88, 6, 5, 67, 28, 26, 65, 5, 66, 15, 68, 64,\n                                  8, 101, 85, 87, 87, 20, 68, 8, 8, 69, 82, 69,\n                                  68, 65, 75, 72, 84, 19, 73, 8, 72, 78, 64, 72,\n                                  66, 4, 7, 5, 12, 6, 75, 64, 0, 67, 2, 72, 27,\n                                  67, 1, 26, 24, 33, 28, 22, 91, 3, 2, 69, 67,\n                                  80, 68, 21, 65, 64, 21, 40, 58, 48, 26, 92,\n                                  95, 5, 38, 40, 116, 70, 8, 92, 17, 67, 1, 21,\n                                  33, 55, 46, 30, 97, 79, 69, 67, 1, 84, 17, 21,\n                                  16, 13, 17, 15, 8, 18, 15, 68, 2, 9, 3, 2, 71,\n                                  4, 65, 69, 2, 0, 4, 1, 66, 94, 67, 68, 69, 71,\n                                  78, 14, 25, 12, 7, 11, 12, 7, 12, 10, 85, 98,\n                                  79, 80, 78, 115, 72, 67, 96, 11, 65, 65, 68,\n                                  69, 78, 72, 68, 88, 93, 83, 86, 88, 80, 68,\n                                  24, 19, 10, 4, 6, 0, 68, 70, 70, 4, 34, 20,\n                                  14, 6, 19, 6, 4, 68, 8, 1, 31, 18, 13, 7, 16,\n                                  4, 65, 68, 73, 71, 37, 19, 9, 4, 11, 65, 73,\n                                  73, 8, 37, 27, 17, 8, 21, 7, 3, 65, 67, 62,\n                                  84, 78, 71, 74, 77, 72, 69, 66, 66, 0, 4, 11,\n                                  74, 72, 79, 80, 33, 82, 89, 76, 68, 67, 73,\n                                  71, 71, 71, 67, 73, 86, 68, 68, 16, 69, 77,\n                                  67, 68, 68, 68, 68, 68, 81, 73, 69, 73, 72,\n                                  12, 93, 73, 17, 76, 65, 69, 68, 1, 0, 67, 64,\n                                  3, 73, 73, 90, 44, 41, 43, 32, 22, 24, 23, 17,\n                                  20, 14, 14, 15, 2, 64, 73, 0, 1, 70, 89, 67,\n                                  65, 69, 66, 76, 75, 76, 79, 83, 79, 10, 6, 9,\n                                  0, 80, 71, 71, 87, 76, 85, 88, 104, 97, 99,\n                                  102, 65, 1, 93, 69, 68, 76, 89, 83, 84, 91,\n                                  81, 87, 83, 92, 93, 98, 109, 73, 86, 93, 72,\n                                  5, 9, 11, 23, 16, 22, 3, 21, 19, 27, 26, 32,\n                                  29, 17, 48, 15, 7, 1, 70, 72, 94, 98, 102, 10,\n                                  40, 35, 36, 27, 28, 16, 14, 7, 4, 72, 5, 9,\n                                  11, 23, 16, 22, 3, 21, 19, 27, 26, 32, 29, 17,\n                                  48, 15, 7, 1, 70, 72, 94, 98, 102 },\n\n                                {\n\n                                38,\n                                  5, 80, 38, 5, 80, 71, 5, 22, 11, 65, 74, 13,\n                                  35, 32, 7, 18, 68, 77, 9, 67, 69, 24, 85, 80,\n                                  13, 5, 108, 116, 121, 0, 73, 70, 77, 9, 67,\n                                  81, 3, 31, 0, 67, 73, 74, 95, 98, 92, 108, 65,\n                                  75, 80, 73, 87, 84, 99, 2, 71, 71, 73, 27, 1,\n                                  22, 0, 0, 0, 65, 94, 97, 5, 67, 68, 15, 70,\n                                  87, 8, 6, 67, 29, 27, 65, 6, 65, 15, 67, 64,\n                                  10, 102, 86, 88, 88, 20, 69, 8, 10, 69, 82,\n                                  69, 67, 65, 75, 72, 84, 19, 74, 8, 72, 78, 64,\n                                  72, 66, 4, 7, 6, 12, 6, 76, 65, 0, 67, 1, 72,\n                                  27, 67, 1, 26, 24, 33, 28, 22, 92, 3, 2, 70,\n                                  67, 80, 69, 21, 65, 64, 22, 41, 58, 49, 27,\n                                  93, 97, 5, 38, 40, 117, 71, 8, 93, 17, 68, 1,\n                                  22, 33, 54, 46, 31, 98, 78, 71, 70, 66, 83,\n                                  16, 21, 15, 12, 16, 14, 7, 17, 14, 69, 1, 8,\n                                  2, 1, 72, 3, 66, 70, 1, 64, 3, 0, 67, 96, 68,\n                                  69, 69, 73, 79, 11, 22, 10, 5, 9, 9, 3, 9, 8,\n                                  87, 101, 81, 83, 80, 117, 74, 69, 98, 9, 66,\n                                  66, 70, 71, 80, 74, 70, 90, 93, 84, 87, 90,\n                                  79, 67, 25, 19, 10, 4, 6, 0, 68, 70, 69, 5,\n                                  34, 20, 14, 6, 20, 7, 5, 68, 10, 1, 31, 18,\n                                  13, 7, 16, 4, 65, 68, 72, 71, 38, 20, 9, 3,\n                                  11, 65, 73, 73, 8, 37, 27, 17, 8, 22, 7, 3,\n                                  65, 67, 62, 83, 77, 70, 73, 76, 71, 68, 65,\n                                  65, 1, 5, 13, 74, 72, 79, 80, 36, 82, 91, 76,\n                                  68, 67, 73, 71, 71, 72, 67, 74, 87, 69, 68,\n                                  16, 70, 77, 68, 68, 68, 69, 69, 69, 82, 74,\n                                  70, 74, 72, 13, 94, 74, 17, 77, 66, 69, 69, 1,\n                                  64, 68, 64, 3, 73, 73, 92, 42, 40, 41, 30, 19,\n                                  21, 20, 14, 17, 11, 10, 12, 65, 67, 75, 67,\n                                  66, 74, 95, 70, 68, 71, 69, 79, 77, 78, 81,\n                                  84, 79, 7, 3, 6, 65, 83, 73, 73, 90, 78, 88,\n                                  90, 107, 100, 101, 104, 67, 64, 96, 71, 70,\n                                  78, 91, 85, 86, 92, 82, 88, 84, 91, 95, 100,\n                                  111, 75, 88, 95, 72, 5, 9, 11, 24, 16, 22, 3,\n                                  22, 19, 28, 26, 32, 29, 17, 47, 13, 5, 65, 73,\n                                  74, 97, 100, 104, 10, 40, 35, 36, 27, 28, 16,\n                                  14, 7, 4, 72, 5, 9, 11, 24, 16, 22, 3, 22, 19,\n                                  28, 26, 32, 29, 17, 47, 13, 5, 65, 73, 74, 97,\n                                  100, 104 },\n\n                                {\n\n                                37,\n                                  5, 80, 37, 5, 80, 69, 7, 23, 12, 65, 75, 12,\n                                  35, 33, 8, 20, 69, 76, 11, 67, 69, 26, 85, 81,\n                                  12, 4, 111, 118, 121, 2, 71, 69, 76, 11, 67,\n                                  80, 4, 32, 0, 66, 72, 72, 96, 99, 92, 108, 65,\n                                  74, 79, 73, 87, 83, 98, 2, 70, 70, 72, 28, 1,\n                                  22, 0, 0, 0, 64, 94, 97, 6, 67, 68, 15, 69,\n                                  85, 11, 8, 66, 31, 29, 64, 8, 0, 16, 65, 0,\n                                  13, 102, 86, 88, 88, 21, 69, 9, 13, 68, 81,\n                                  68, 65, 65, 74, 72, 83, 20, 74, 9, 71, 77, 0,\n                                  71, 65, 5, 8, 7, 13, 7, 76, 65, 1, 66, 1, 71,\n                                  28, 66, 1, 27, 25, 34, 29, 23, 92, 4, 3, 70,\n                                  67, 79, 69, 22, 64, 0, 24, 43, 59, 51, 29, 93,\n                                  98, 6, 39, 41, 117, 71, 9, 93, 18, 68, 2, 24,\n                                  33, 54, 47, 33, 99, 76, 72, 72, 69, 81, 16,\n                                  21, 15, 12, 16, 14, 7, 17, 14, 69, 1, 8, 2, 1,\n                                  72, 3, 66, 70, 1, 64, 3, 0, 67, 97, 68, 69,\n                                  69, 74, 79, 9, 20, 9, 4, 8, 7, 0, 7, 7, 88,\n                                  103, 82, 85, 81, 118, 75, 70, 99, 8, 66, 66,\n                                  71, 72, 81, 75, 71, 91, 93, 84, 87, 91, 77,\n                                  65, 27, 20, 10, 4, 7, 1, 67, 69, 67, 7, 35,\n                                  21, 15, 7, 22, 8, 7, 67, 13, 2, 32, 19, 14, 8,\n                                  17, 5, 64, 67, 70, 70, 40, 21, 10, 3, 12, 64,\n                                  72, 72, 9, 38, 28, 18, 9, 23, 8, 4, 64, 66,\n                                  62, 81, 75, 68, 71, 74, 69, 66, 0, 0, 3, 7,\n                                  16, 73, 71, 78, 79, 40, 81, 92, 75, 67, 66,\n                                  72, 71, 70, 72, 66, 74, 87, 69, 68, 17, 70,\n                                  77, 68, 68, 67, 69, 69, 69, 82, 74, 70, 74,\n                                  71, 15, 94, 74, 18, 77, 66, 69, 69, 2, 64, 68,\n                                  0, 4, 72, 72, 93, 41, 39, 40, 29, 17, 19, 18,\n                                  11, 15, 9, 7, 10, 68, 69, 77, 70, 69, 77, 100,\n                                  72, 70, 72, 71, 81, 78, 79, 82, 84, 79, 5, 1,\n                                  4, 67, 85, 74, 74, 92, 79, 90, 91, 109, 102,\n                                  102, 105, 68, 65, 98, 72, 71, 79, 92, 86, 87,\n                                  93, 82, 88, 84, 90, 96, 101, 112, 76, 89, 96,\n                                  71, 6, 10, 12, 26, 17, 23, 4, 24, 20, 29, 27,\n                                  33, 30, 18, 47, 12, 4, 67, 75, 75, 99, 101,\n                                  105, 11, 41, 36, 37, 28, 29, 17, 15, 8, 5, 71,\n                                  6, 10, 12, 26, 17, 23, 4, 24, 20, 29, 27, 33,\n                                  30, 18, 47, 12, 4, 67, 75, 75, 99, 101, 105 },\n\n                                {\n\n                                36,\n                                  5, 80, 36, 5, 80, 67, 8, 23, 12, 65, 77, 10,\n                                  34, 34, 8, 22, 71, 76, 12, 67, 69, 27, 86, 82,\n                                  11, 2, 114, 120, 122, 4, 70, 69, 76, 12, 67,\n                                  80, 5, 32, 0, 65, 71, 71, 97, 100, 92, 108,\n                                  65, 74, 78, 73, 87, 83, 98, 2, 70, 70, 71, 28,\n                                  1, 22, 0, 0, 0, 0, 94, 97, 6, 68, 68, 15, 68,\n                                  84, 13, 9, 65, 33, 31, 0, 9, 2, 17, 64, 1, 15,\n                                  103, 86, 88, 88, 21, 69, 10, 15, 68, 80, 67,\n                                  0, 65, 74, 72, 83, 20, 74, 9, 70, 77, 1, 71,\n                                  65, 5, 8, 8, 14, 7, 76, 65, 1, 66, 1, 71, 28,\n                                  66, 1, 27, 25, 34, 29, 23, 93, 5, 4, 71, 67,\n                                  79, 69, 23, 64, 0, 25, 44, 60, 53, 31, 94, 99,\n                                  6, 39, 41, 118, 71, 9, 94, 19, 68, 2, 25, 33,\n                                  54, 47, 34, 100, 75, 73, 75, 72, 80, 16, 21,\n                                  15, 11, 15, 14, 7, 17, 13, 70, 0, 8, 2, 1, 72,\n                                  2, 67, 71, 1, 64, 3, 64, 68, 98, 69, 70, 69,\n                                  75, 80, 7, 18, 7, 2, 6, 5, 66, 5, 6, 90, 105,\n                                  84, 87, 83, 119, 76, 71, 101, 7, 67, 67, 72,\n                                  74, 83, 77, 73, 93, 93, 85, 88, 93, 76, 64,\n                                  28, 21, 10, 4, 8, 2, 66, 68, 65, 8, 36, 22,\n                                  16, 8, 23, 9, 8, 66, 15, 3, 32, 19, 14, 8, 18,\n                                  6, 0, 66, 69, 70, 41, 22, 10, 3, 13, 0, 72,\n                                  71, 10, 38, 29, 18, 9, 24, 9, 5, 0, 65, 62,\n                                  80, 73, 66, 69, 73, 68, 64, 2, 1, 5, 9, 18,\n                                  72, 70, 77, 78, 43, 81, 93, 75, 66, 65, 72,\n                                  71, 70, 72, 66, 74, 88, 69, 68, 18, 70, 77,\n                                  68, 68, 67, 69, 69, 69, 83, 75, 70, 74, 71,\n                                  16, 95, 74, 19, 78, 66, 69, 69, 2, 64, 68, 0,\n                                  5, 72, 72, 95, 40, 38, 39, 27, 15, 16, 15, 8,\n                                  13, 6, 4, 7, 71, 72, 79, 74, 73, 81, 105, 75,\n                                  72, 74, 73, 83, 80, 80, 83, 85, 79, 3, 64, 2,\n                                  69, 87, 76, 76, 94, 81, 92, 93, 111, 104, 104,\n                                  106, 69, 66, 100, 74, 73, 81, 94, 87, 88, 94,\n                                  83, 89, 84, 89, 97, 102, 114, 77, 90, 97, 71,\n                                  6, 11, 13, 27, 18, 24, 4, 25, 21, 30, 27, 34,\n                                  31, 19, 46, 10, 2, 69, 77, 77, 101, 103, 106,\n                                  12, 41, 36, 38, 29, 30, 17, 16, 8, 6, 71, 6,\n                                  11, 13, 27, 18, 24, 4, 25, 21, 30, 27, 34, 31,\n                                  19, 46, 10, 2, 69, 77, 77, 101, 103, 106 },\n\n                                {\n\n                                35,\n                                  5, 80, 35, 5, 80, 65, 10, 24, 12, 66, 79, 9,\n                                  33, 34, 8, 24, 72, 76, 14, 67, 70, 28, 87, 83,\n                                  10, 0, 118, 122, 123, 6, 68, 69, 76, 14, 67,\n                                  79, 6, 33, 0, 64, 70, 70, 98, 101, 92, 109,\n                                  65, 74, 77, 73, 88, 83, 98, 2, 70, 70, 70, 29,\n                                  1, 22, 0, 0, 0, 0, 94, 97, 7, 69, 68, 14, 68,\n                                  83, 15, 10, 64, 34, 32, 1, 10, 4, 18, 0, 2,\n                                  17, 104, 86, 88, 88, 22, 69, 11, 17, 68, 79,\n                                  66, 2, 65, 74, 72, 83, 21, 74, 10, 69, 77, 2,\n                                  71, 65, 5, 9, 9, 14, 7, 76, 65, 1, 66, 1, 71,\n                                  28, 66, 1, 28, 25, 35, 29, 24, 93, 5, 5, 71,\n                                  67, 79, 69, 24, 64, 1, 26, 45, 61, 54, 33, 94,\n                                  100, 7, 39, 41, 119, 71, 10, 94, 19, 68, 2,\n                                  26, 33, 54, 47, 35, 101, 73, 74, 78, 75, 78,\n                                  16, 21, 14, 10, 15, 13, 6, 17, 13, 71, 64, 8,\n                                  2, 1, 73, 2, 68, 72, 0, 64, 3, 65, 68, 99, 69,\n                                  71, 69, 76, 80, 5, 16, 5, 1, 4, 3, 69, 2, 5,\n                                  92, 107, 85, 89, 85, 121, 77, 72, 103, 6, 68,\n                                  68, 73, 75, 85, 79, 75, 94, 93, 86, 89, 94,\n                                  74, 1, 30, 21, 10, 4, 9, 3, 65, 67, 0, 9, 37,\n                                  23, 17, 8, 24, 10, 10, 65, 17, 3, 33, 20, 15,\n                                  9, 19, 6, 0, 65, 68, 70, 43, 23, 10, 3, 14, 0,\n                                  72, 70, 11, 39, 30, 19, 9, 25, 9, 6, 0, 65,\n                                  62, 78, 72, 65, 67, 72, 66, 0, 3, 3, 7, 11,\n                                  20, 72, 69, 77, 77, 46, 81, 94, 75, 65, 64,\n                                  72, 71, 70, 72, 65, 74, 89, 69, 68, 18, 70,\n                                  77, 68, 68, 67, 70, 69, 69, 84, 76, 70, 74,\n                                  71, 17, 96, 74, 20, 79, 66, 69, 69, 3, 64, 69,\n                                  1, 6, 72, 72, 96, 39, 37, 38, 25, 13, 14, 13,\n                                  5, 10, 3, 1, 4, 74, 75, 81, 78, 76, 85, 110,\n                                  78, 74, 76, 75, 86, 82, 81, 84, 86, 79, 1, 66,\n                                  0, 71, 89, 78, 77, 96, 83, 94, 95, 113, 106,\n                                  106, 107, 70, 67, 102, 75, 75, 82, 96, 89, 90,\n                                  95, 84, 90, 84, 88, 98, 104, 115, 78, 91, 98,\n                                  71, 7, 11, 13, 28, 19, 25, 4, 26, 22, 31, 28,\n                                  35, 31, 20, 46, 8, 0, 71, 79, 79, 103, 105,\n                                  107, 12, 42, 37, 39, 29, 31, 18, 16, 9, 6, 71,\n                                  7, 11, 13, 28, 19, 25, 4, 26, 22, 31, 28, 35,\n                                  31, 20, 46, 8, 0, 71, 79, 79, 103, 105, 107 },\n\n                                {\n\n                                33,\n                                  5, 80, 33, 5, 80, 64, 11, 24, 12, 66, 81, 7,\n                                  32, 35, 8, 25, 74, 76, 15, 68, 70, 29, 88, 85,\n                                  8, 65, 121, 125, 124, 8, 67, 69, 76, 15, 68,\n                                  79, 7, 33, 64, 64, 69, 68, 99, 103, 93, 109,\n                                  65, 73, 76, 74, 88, 83, 98, 2, 70, 70, 70, 29,\n                                  1, 22, 0, 0, 0, 1, 95, 97, 7, 70, 68, 14, 67,\n                                  82, 17, 11, 0, 36, 34, 1, 11, 6, 19, 1, 3, 20,\n                                  104, 87, 88, 89, 22, 70, 12, 20, 67, 79, 66,\n                                  4, 65, 74, 72, 83, 21, 74, 10, 68, 77, 2, 70,\n                                  65, 5, 9, 10, 15, 7, 77, 66, 1, 66, 1, 71, 28,\n                                  66, 1, 28, 25, 35, 29, 24, 94, 6, 5, 72, 67,\n                                  78, 69, 25, 0, 1, 28, 47, 62, 56, 35, 95, 101,\n                                  7, 40, 41, 120, 71, 10, 95, 20, 68, 2, 27, 33,\n                                  54, 47, 37, 102, 72, 75, 81, 78, 77, 15, 21,\n                                  14, 10, 14, 13, 6, 17, 12, 72, 65, 7, 2, 1,\n                                  73, 1, 68, 73, 0, 65, 2, 66, 69, 100, 70, 72,\n                                  69, 78, 81, 3, 14, 3, 64, 3, 1, 73, 0, 4, 94,\n                                  110, 87, 91, 87, 122, 79, 73, 104, 5, 69, 69,\n                                  75, 77, 87, 81, 76, 96, 93, 87, 90, 96, 73, 2,\n                                  31, 22, 10, 4, 10, 4, 64, 67, 2, 11, 38, 23,\n                                  17, 9, 26, 11, 11, 64, 20, 4, 33, 20, 15, 9,\n                                  20, 7, 1, 65, 67, 70, 44, 24, 10, 3, 15, 1,\n                                  72, 69, 12, 39, 31, 19, 9, 26, 10, 7, 1, 64,\n                                  62, 77, 70, 0, 66, 71, 65, 2, 5, 4, 8, 13, 23,\n                                  71, 68, 76, 76, 49, 80, 95, 74, 64, 64, 72,\n                                  71, 70, 73, 65, 75, 90, 69, 68, 19, 70, 77,\n                                  68, 68, 66, 70, 70, 69, 85, 77, 71, 74, 71,\n                                  18, 97, 75, 20, 79, 67, 69, 69, 3, 65, 69, 1,\n                                  6, 72, 72, 98, 38, 36, 37, 24, 10, 11, 10, 2,\n                                  8, 0, 66, 1, 78, 77, 83, 82, 80, 89, 115, 81,\n                                  76, 78, 77, 88, 84, 83, 85, 87, 79, 65, 69,\n                                  66, 73, 91, 80, 79, 98, 85, 96, 97, 115, 109,\n                                  107, 109, 71, 68, 105, 77, 76, 84, 98, 90, 91,\n                                  96, 85, 91, 84, 87, 100, 105, 117, 80, 92, 99,\n                                  71, 7, 12, 14, 29, 19, 25, 5, 27, 23, 32, 28,\n                                  36, 32, 20, 45, 6, 65, 73, 81, 81, 106, 107,\n                                  109, 13, 42, 37, 39, 30, 31, 18, 17, 9, 7, 71,\n                                  7, 12, 14, 29, 19, 25, 5, 27, 23, 32, 28, 36,\n                                  32, 20, 45, 6, 65, 73, 81, 81, 106, 107, 109 },\n\n                                {\n\n                                32,\n                                  5, 80, 32, 5, 80, 1, 13, 24, 12, 67, 83, 6,\n                                  31, 36, 8, 27, 76, 75, 17, 68, 70, 30, 89, 86,\n                                  7, 67, 124, 126, 124, 10, 66, 69, 75, 17, 68,\n                                  79, 8, 33, 64, 0, 68, 67, 100, 104, 93, 109,\n                                  65, 73, 75, 74, 88, 83, 98, 2, 69, 70, 69, 30,\n                                  1, 22, 0, 0, 0, 1, 95, 97, 8, 71, 68, 13, 67,\n                                  80, 20, 12, 1, 37, 35, 2, 12, 8, 20, 2, 4, 22,\n                                  105, 87, 88, 89, 22, 70, 13, 22, 67, 78, 65,\n                                  6, 65, 74, 72, 82, 21, 74, 11, 67, 76, 3, 70,\n                                  65, 6, 10, 11, 15, 7, 77, 66, 2, 66, 1, 71,\n                                  29, 66, 1, 29, 26, 35, 29, 24, 94, 6, 6, 72,\n                                  67, 78, 69, 26, 0, 2, 29, 48, 62, 57, 37, 95,\n                                  102, 8, 40, 41, 121, 71, 11, 95, 21, 68, 2,\n                                  29, 33, 54, 47, 38, 103, 70, 76, 83, 81, 76,\n                                  15, 21, 13, 9, 14, 13, 5, 17, 12, 73, 66, 7,\n                                  2, 1, 73, 1, 69, 74, 64, 65, 2, 67, 69, 101,\n                                  71, 72, 69, 79, 81, 1, 12, 2, 65, 1, 64, 76,\n                                  66, 3, 96, 112, 88, 93, 89, 123, 80, 74, 106,\n                                  4, 70, 70, 76, 78, 89, 83, 78, 97, 93, 88, 91,\n                                  98, 71, 4, 32, 22, 10, 4, 11, 5, 0, 66, 4, 12,\n                                  39, 24, 18, 10, 27, 12, 13, 0, 22, 5, 34, 21,\n                                  16, 10, 21, 8, 1, 64, 66, 69, 45, 25, 10, 3,\n                                  16, 1, 71, 68, 13, 39, 32, 19, 9, 27, 11, 8,\n                                  1, 0, 62, 76, 69, 1, 64, 70, 0, 3, 7, 6, 10,\n                                  15, 25, 70, 67, 75, 75, 52, 80, 96, 74, 0, 0,\n                                  72, 71, 70, 73, 64, 75, 91, 69, 68, 20, 70,\n                                  77, 68, 68, 66, 71, 70, 69, 86, 78, 71, 74,\n                                  71, 19, 97, 75, 21, 80, 67, 69, 69, 3, 65, 70,\n                                  1, 7, 72, 72, 99, 37, 35, 36, 22, 8, 9, 7, 64,\n                                  5, 66, 69, 65, 81, 80, 85, 86, 83, 93, 120,\n                                  84, 78, 79, 79, 91, 86, 84, 86, 88, 79, 67,\n                                  71, 68, 75, 93, 82, 80, 100, 87, 98, 99, 117,\n                                  111, 109, 110, 72, 69, 107, 78, 78, 85, 100,\n                                  91, 92, 97, 86, 92, 84, 86, 101, 106, 118, 81,\n                                  93, 100, 71, 8, 12, 15, 30, 20, 26, 5, 28, 24,\n                                  33, 29, 37, 32, 21, 45, 4, 67, 75, 83, 83,\n                                  108, 109, 110, 13, 43, 38, 40, 31, 32, 19, 17,\n                                  9, 8, 71, 8, 12, 15, 30, 20, 26, 5, 28, 24,\n                                  33, 29, 37, 32, 21, 45, 4, 67, 75, 83, 83,\n                                  108, 109, 110 },\n\n                                {\n\n                                31,\n                                  5, 81, 31, 5, 81, 3, 14, 25, 12, 67, 84, 4,\n                                  30, 36, 9, 29, 77, 75, 18, 68, 71, 31, 90, 87,\n                                  6, 68, 126, 126, 125, 12, 64, 69, 75, 18, 68,\n                                  78, 9, 34, 64, 1, 67, 66, 102, 105, 93, 110,\n                                  65, 73, 75, 74, 89, 82, 98, 1, 69, 70, 68, 30,\n                                  1, 22, 0, 0, 0, 2, 95, 97, 8, 71, 69, 13, 66,\n                                  79, 22, 13, 2, 39, 37, 3, 13, 10, 21, 3, 4,\n                                  24, 106, 87, 88, 89, 23, 70, 14, 24, 67, 77,\n                                  64, 8, 65, 74, 72, 82, 22, 75, 11, 67, 76, 4,\n                                  70, 64, 6, 10, 12, 16, 7, 77, 66, 2, 66, 1,\n                                  71, 29, 66, 1, 29, 26, 36, 30, 25, 95, 7, 7,\n                                  73, 67, 78, 69, 27, 0, 2, 30, 49, 62, 59, 38,\n                                  96, 103, 8, 40, 41, 121, 72, 11, 96, 21, 69,\n                                  3, 30, 33, 54, 48, 39, 104, 69, 77, 86, 84,\n                                  74, 15, 21, 13, 8, 13, 12, 5, 16, 11, 73, 66,\n                                  7, 1, 1, 74, 0, 70, 75, 64, 65, 2, 67, 70,\n                                  103, 71, 73, 69, 80, 82, 65, 10, 0, 67, 64,\n                                  66, 79, 68, 1, 98, 114, 90, 95, 91, 125, 81,\n                                  76, 108, 2, 71, 71, 77, 80, 91, 85, 80, 99,\n                                  93, 89, 92, 99, 70, 5, 34, 23, 10, 4, 12, 5,\n                                  0, 65, 5, 13, 40, 25, 19, 10, 28, 13, 14, 1,\n                                  24, 5, 34, 21, 16, 10, 22, 8, 2, 0, 65, 69,\n                                  47, 26, 10, 3, 16, 2, 71, 68, 13, 40, 32, 20,\n                                  9, 28, 11, 8, 2, 0, 62, 74, 67, 3, 1, 68, 1,\n                                  5, 8, 7, 12, 17, 27, 70, 66, 75, 75, 55, 80,\n                                  97, 74, 0, 1, 72, 71, 70, 73, 64, 75, 92, 69,\n                                  68, 20, 70, 77, 68, 68, 66, 71, 70, 69, 87,\n                                  79, 71, 74, 71, 20, 98, 75, 22, 81, 67, 69,\n                                  69, 4, 65, 70, 2, 8, 72, 72, 101, 36, 34, 35,\n                                  20, 6, 6, 5, 67, 3, 69, 72, 68, 84, 83, 87,\n                                  89, 87, 97, 125, 86, 81, 81, 81, 93, 88, 85,\n                                  87, 89, 79, 69, 73, 70, 77, 95, 83, 82, 102,\n                                  89, 101, 101, 119, 113, 111, 111, 73, 71, 109,\n                                  80, 80, 87, 102, 93, 94, 98, 87, 93, 85, 85,\n                                  102, 108, 120, 82, 95, 101, 70, 8, 13, 15, 31,\n                                  21, 27, 5, 29, 25, 34, 29, 38, 33, 22, 44, 2,\n                                  69, 77, 85, 85, 110, 111, 111, 14, 43, 38, 41,\n                                  31, 33, 19, 18, 10, 8, 70, 8, 13, 15, 31, 21,\n                                  27, 5, 29, 25, 34, 29, 38, 33, 22, 44, 2, 69,\n                                  77, 85, 85, 110, 111, 111 },\n\n                                {\n\n                                30,\n                                  5, 81, 30, 5, 81, 5, 16, 25, 12, 68, 86, 3,\n                                  29, 37, 9, 30, 79, 75, 20, 69, 71, 32, 91, 88,\n                                  5, 70, 126, 126, 126, 14, 0, 69, 75, 20, 69,\n                                  78, 10, 34, 64, 1, 66, 64, 103, 106, 93, 110,\n                                  65, 72, 74, 75, 89, 82, 98, 1, 69, 70, 67, 31,\n                                  1, 22, 0, 0, 0, 2, 95, 97, 9, 72, 69, 12, 66,\n                                  78, 24, 14, 3, 40, 38, 4, 14, 12, 22, 4, 5,\n                                  27, 106, 88, 88, 90, 23, 70, 15, 27, 66, 77,\n                                  64, 10, 65, 74, 72, 82, 22, 75, 12, 66, 76, 5,\n                                  69, 64, 6, 11, 13, 16, 7, 78, 66, 2, 66, 1,\n                                  71, 29, 66, 1, 30, 26, 36, 30, 25, 95, 7, 7,\n                                  73, 67, 77, 69, 28, 1, 3, 32, 51, 62, 60, 40,\n                                  96, 104, 9, 41, 41, 122, 72, 12, 96, 22, 69,\n                                  3, 31, 33, 54, 48, 41, 105, 67, 78, 89, 87,\n                                  73, 15, 21, 12, 8, 13, 12, 4, 16, 11, 74, 67,\n                                  7, 1, 1, 74, 0, 70, 76, 65, 65, 2, 68, 70,\n                                  104, 72, 74, 69, 81, 82, 67, 8, 65, 68, 65,\n                                  68, 82, 71, 0, 100, 116, 91, 97, 93, 126, 82,\n                                  77, 109, 1, 72, 72, 79, 81, 93, 87, 81, 100,\n                                  93, 90, 93, 101, 68, 7, 35, 23, 10, 4, 13, 6,\n                                  1, 65, 7, 15, 41, 26, 19, 11, 30, 14, 16, 2,\n                                  27, 6, 35, 22, 17, 11, 23, 9, 2, 1, 64, 69,\n                                  48, 27, 10, 3, 17, 2, 71, 67, 14, 40, 33, 20,\n                                  9, 29, 12, 9, 2, 1, 62, 73, 66, 4, 2, 67, 3,\n                                  6, 10, 9, 14, 19, 30, 69, 65, 74, 74, 58, 79,\n                                  98, 73, 1, 2, 72, 71, 70, 73, 0, 76, 93, 69,\n                                  68, 21, 70, 77, 68, 68, 65, 72, 71, 69, 88,\n                                  80, 72, 74, 71, 21, 99, 76, 23, 81, 68, 69,\n                                  69, 4, 66, 71, 2, 8, 72, 72, 102, 35, 33, 34,\n                                  19, 3, 4, 2, 70, 0, 72, 75, 71, 87, 85, 89,\n                                  93, 90, 101, 126, 89, 83, 83, 83, 96, 90, 86,\n                                  88, 90, 79, 71, 76, 73, 79, 97, 85, 83, 104,\n                                  91, 103, 103, 121, 115, 112, 113, 74, 72, 111,\n                                  81, 81, 88, 104, 94, 95, 99, 88, 94, 85, 84,\n                                  104, 109, 121, 84, 96, 102, 70, 9, 13, 16, 32,\n                                  22, 27, 6, 30, 26, 35, 30, 39, 33, 22, 44, 0,\n                                  71, 79, 87, 87, 113, 113, 112, 14, 44, 39, 41,\n                                  32, 34, 20, 18, 10, 9, 70, 9, 13, 16, 32, 22,\n                                  27, 6, 30, 26, 35, 30, 39, 33, 22, 44, 0, 71,\n                                  79, 87, 87, 113, 113, 112 },\n\n                                {\n\n                                28,\n                                  4, 81, 28, 4, 81, 6, 17, 25, 12, 68, 88, 1,\n                                  28, 37, 9, 32, 81, 75, 21, 69, 72, 33, 92, 90,\n                                  3, 72, 126, 126, 126, 16, 1, 69, 75, 21, 69,\n                                  78, 10, 34, 65, 2, 65, 0, 104, 108, 94, 111,\n                                  65, 72, 73, 75, 90, 82, 98, 1, 69, 70, 67, 31,\n                                  1, 22, 0, 0, 0, 3, 96, 97, 9, 73, 69, 12, 65,\n                                  77, 26, 15, 3, 42, 40, 4, 15, 14, 22, 5, 6,\n                                  29, 107, 88, 89, 90, 23, 71, 15, 29, 66, 76,\n                                  0, 11, 65, 74, 72, 82, 22, 75, 12, 65, 76, 5,\n                                  69, 64, 6, 11, 14, 17, 7, 78, 67, 2, 66, 0,\n                                  71, 29, 66, 1, 30, 26, 36, 30, 25, 96, 8, 8,\n                                  74, 67, 77, 69, 29, 1, 3, 33, 52, 62, 62, 42,\n                                  97, 105, 9, 41, 41, 123, 72, 12, 97, 22, 69,\n                                  3, 32, 33, 54, 48, 42, 106, 66, 79, 92, 91,\n                                  72, 14, 21, 12, 7, 12, 11, 4, 16, 10, 75, 68,\n                                  6, 1, 0, 75, 64, 71, 77, 65, 66, 1, 69, 71,\n                                  105, 73, 75, 69, 83, 83, 69, 6, 67, 70, 67,\n                                  71, 86, 73, 64, 102, 119, 93, 100, 95, 126,\n                                  84, 78, 111, 0, 73, 73, 80, 83, 95, 89, 83,\n                                  102, 93, 91, 94, 103, 67, 8, 36, 24, 10, 4,\n                                  13, 7, 2, 64, 9, 16, 41, 26, 20, 11, 31, 15,\n                                  17, 3, 29, 6, 35, 22, 17, 11, 23, 9, 3, 1, 0,\n                                  69, 49, 28, 10, 3, 18, 3, 71, 66, 15, 40, 34,\n                                  20, 9, 30, 12, 10, 3, 1, 62, 72, 64, 6, 4, 66,\n                                  4, 8, 11, 10, 15, 21, 32, 69, 64, 74, 73, 61,\n                                  79, 99, 73, 2, 2, 72, 71, 70, 74, 0, 76, 94,\n                                  69, 68, 21, 70, 77, 69, 68, 65, 72, 71, 70,\n                                  89, 81, 72, 75, 71, 22, 100, 76, 23, 82, 68,\n                                  69, 70, 4, 66, 71, 2, 9, 72, 72, 104, 34, 32,\n                                  33, 17, 1, 1, 64, 73, 65, 75, 79, 74, 91, 88,\n                                  91, 97, 94, 105, 126, 92, 85, 85, 86, 98, 92,\n                                  88, 90, 91, 79, 74, 78, 75, 81, 100, 87, 85,\n                                  107, 93, 105, 105, 123, 118, 114, 114, 76, 73,\n                                  114, 83, 83, 90, 106, 96, 97, 100, 89, 95, 85,\n                                  83, 105, 111, 123, 85, 97, 103, 70, 9, 14, 16,\n                                  33, 22, 28, 6, 31, 26, 36, 30, 39, 34, 23, 43,\n                                  65, 73, 81, 89, 89, 115, 115, 114, 15, 44, 39,\n                                  42, 32, 34, 20, 19, 10, 9, 70, 9, 14, 16, 33,\n                                  22, 28, 6, 31, 26, 36, 30, 39, 34, 23, 43, 65,\n                                  73, 81, 89, 89, 115, 115, 114 },\n\n                                {\n\n                                27,\n                                  4, 81, 27, 4, 81, 8, 18, 26, 12, 68, 90, 64,\n                                  28, 38, 9, 34, 82, 74, 23, 69, 72, 34, 92, 91,\n                                  2, 74, 126, 126, 126, 18, 3, 68, 74, 23, 69,\n                                  77, 11, 35, 65, 3, 64, 1, 105, 109, 94, 111,\n                                  65, 72, 72, 75, 90, 82, 98, 1, 68, 69, 66, 31,\n                                  1, 22, 0, 0, 0, 4, 96, 97, 9, 74, 69, 12, 64,\n                                  75, 29, 16, 4, 44, 42, 5, 16, 16, 23, 7, 7,\n                                  31, 108, 88, 89, 90, 24, 71, 16, 31, 66, 75,\n                                  1, 13, 65, 73, 72, 81, 23, 75, 13, 64, 75, 6,\n                                  69, 64, 7, 12, 15, 18, 7, 78, 67, 3, 65, 0,\n                                  71, 30, 66, 1, 30, 27, 37, 30, 26, 96, 9, 9,\n                                  75, 67, 77, 69, 30, 1, 4, 34, 53, 62, 62, 44,\n                                  98, 106, 10, 41, 42, 124, 72, 12, 97, 23, 69,\n                                  3, 34, 33, 54, 48, 43, 107, 65, 80, 94, 94,\n                                  70, 14, 21, 12, 6, 12, 11, 4, 16, 10, 76, 69,\n                                  6, 1, 0, 75, 64, 72, 77, 65, 66, 1, 70, 72,\n                                  106, 73, 75, 69, 84, 83, 71, 4, 68, 71, 69,\n                                  73, 89, 75, 65, 104, 121, 94, 102, 96, 126,\n                                  85, 79, 113, 64, 74, 74, 81, 85, 96, 91, 85,\n                                  103, 93, 91, 95, 104, 65, 10, 38, 25, 10, 4,\n                                  14, 8, 3, 0, 11, 17, 42, 27, 21, 12, 32, 16,\n                                  18, 4, 31, 7, 36, 23, 18, 11, 24, 10, 4, 2, 2,\n                                  68, 51, 29, 11, 3, 19, 4, 70, 65, 16, 41, 35,\n                                  21, 10, 31, 13, 11, 4, 2, 62, 70, 1, 8, 6, 65,\n                                  5, 10, 13, 12, 17, 23, 34, 68, 0, 73, 72, 62,\n                                  79, 100, 73, 3, 3, 71, 71, 70, 74, 0, 76, 95,\n                                  69, 68, 22, 70, 77, 69, 68, 65, 72, 71, 70,\n                                  89, 82, 72, 75, 70, 24, 100, 76, 24, 83, 68,\n                                  69, 70, 5, 66, 71, 3, 10, 71, 71, 106, 33, 31,\n                                  32, 15, 64, 65, 66, 76, 67, 77, 82, 76, 94,\n                                  91, 93, 101, 97, 108, 126, 95, 87, 86, 88,\n                                  100, 93, 89, 91, 92, 79, 76, 80, 77, 83, 102,\n                                  89, 86, 109, 95, 107, 107, 125, 120, 116, 115,\n                                  77, 74, 116, 84, 85, 91, 108, 97, 98, 101, 90,\n                                  95, 85, 82, 106, 112, 125, 86, 98, 104, 70,\n                                  10, 15, 17, 35, 23, 29, 6, 32, 27, 37, 31, 40,\n                                  35, 24, 42, 66, 75, 83, 91, 91, 117, 117, 115,\n                                  16, 44, 40, 43, 33, 35, 21, 20, 11, 10, 70,\n                                  10, 15, 17, 35, 23, 29, 6, 32, 27, 37, 31, 40,\n                                  35, 24, 42, 66, 75, 83, 91, 91, 117, 117, 115 },\n\n                                {\n\n                                26,\n                                  4, 81, 26, 4, 81, 10, 20, 26, 12, 69, 92, 65,\n                                  27, 39, 9, 35, 84, 74, 24, 70, 72, 35, 93, 92,\n                                  1, 76, 126, 126, 126, 20, 4, 68, 74, 24, 70,\n                                  77, 12, 35, 65, 3, 0, 3, 106, 110, 94, 111,\n                                  65, 71, 71, 76, 90, 82, 98, 1, 68, 69, 65, 32,\n                                  1, 22, 0, 0, 0, 4, 96, 97, 10, 75, 69, 11, 64,\n                                  74, 31, 17, 5, 45, 43, 6, 17, 18, 24, 8, 8,\n                                  34, 108, 89, 89, 91, 24, 71, 17, 34, 65, 75,\n                                  1, 15, 65, 73, 72, 81, 23, 75, 13, 0, 75, 7,\n                                  68, 64, 7, 12, 16, 18, 7, 79, 67, 3, 65, 0,\n                                  71, 30, 66, 1, 31, 27, 37, 30, 26, 97, 9, 9,\n                                  75, 67, 76, 69, 31, 2, 4, 36, 55, 62, 62, 46,\n                                  98, 107, 10, 42, 42, 125, 72, 13, 98, 24, 69,\n                                  3, 35, 33, 54, 48, 45, 108, 0, 81, 97, 97, 69,\n                                  14, 21, 11, 6, 11, 11, 3, 16, 9, 77, 70, 6, 1,\n                                  0, 75, 65, 72, 78, 66, 66, 1, 71, 72, 107, 74,\n                                  76, 69, 85, 84, 73, 2, 70, 73, 70, 75, 92, 78,\n                                  66, 106, 123, 96, 104, 98, 126, 86, 80, 114,\n                                  65, 75, 75, 83, 86, 98, 93, 86, 105, 93, 92,\n                                  96, 106, 64, 11, 39, 25, 10, 4, 15, 9, 4, 0,\n                                  13, 19, 43, 28, 21, 13, 34, 17, 20, 5, 34, 8,\n                                  36, 23, 18, 12, 25, 11, 4, 3, 3, 68, 52, 30,\n                                  11, 3, 20, 4, 70, 64, 17, 41, 36, 21, 10, 32,\n                                  14, 12, 4, 3, 62, 69, 2, 9, 7, 64, 7, 11, 15,\n                                  13, 19, 25, 37, 67, 1, 72, 71, 62, 78, 101,\n                                  72, 4, 4, 71, 71, 70, 74, 1, 77, 96, 69, 68,\n                                  23, 70, 77, 69, 68, 64, 73, 72, 70, 90, 83,\n                                  73, 75, 70, 25, 101, 77, 25, 83, 69, 69, 70,\n                                  5, 67, 72, 3, 10, 71, 71, 107, 32, 30, 31, 14,\n                                  67, 67, 69, 79, 70, 80, 85, 79, 97, 93, 95,\n                                  105, 101, 112, 126, 98, 89, 88, 90, 103, 95,\n                                  90, 92, 93, 79, 78, 83, 80, 85, 104, 91, 88,\n                                  111, 97, 109, 109, 126, 122, 117, 117, 78, 75,\n                                  118, 86, 86, 93, 110, 98, 99, 102, 91, 96, 85,\n                                  81, 108, 113, 126, 88, 99, 105, 70, 10, 15,\n                                  18, 36, 24, 29, 7, 33, 28, 38, 31, 41, 35, 24,\n                                  42, 68, 77, 85, 93, 93, 120, 119, 116, 16, 45,\n                                  40, 43, 34, 36, 21, 20, 11, 11, 70, 10, 15,\n                                  18, 36, 24, 29, 7, 33, 28, 38, 31, 41, 35, 24,\n                                  42, 68, 77, 85, 93, 93, 120, 119, 116 },\n\n                                {\n\n                                25,\n                                  4, 82, 25, 4, 82, 12, 21, 27, 12, 69, 93, 67,\n                                  26, 39, 10, 37, 85, 74, 26, 70, 73, 36, 94,\n                                  93, 0, 77, 126, 126, 126, 22, 6, 68, 74, 26,\n                                  70, 76, 13, 36, 65, 4, 1, 4, 108, 111, 94,\n                                  112, 65, 71, 71, 76, 91, 81, 98, 0, 68, 69,\n                                  64, 32, 1, 22, 0, 0, 0, 5, 96, 97, 10, 75, 70,\n                                  11, 0, 73, 33, 18, 6, 47, 45, 7, 18, 20, 25,\n                                  9, 8, 36, 109, 89, 89, 91, 25, 71, 18, 36, 65,\n                                  74, 2, 17, 65, 73, 72, 81, 24, 76, 14, 0, 75,\n                                  8, 68, 0, 7, 13, 17, 19, 7, 79, 67, 3, 65, 0,\n                                  71, 30, 66, 1, 31, 27, 38, 31, 27, 97, 10, 10,\n                                  76, 67, 76, 69, 32, 2, 5, 37, 56, 62, 62, 47,\n                                  99, 108, 11, 42, 42, 125, 73, 13, 98, 24, 70,\n                                  4, 36, 33, 54, 49, 46, 109, 1, 82, 100, 100,\n                                  67, 14, 21, 11, 5, 11, 10, 3, 15, 9, 77, 70,\n                                  6, 0, 0, 76, 65, 73, 79, 66, 66, 1, 71, 73,\n                                  109, 74, 77, 69, 86, 84, 76, 0, 72, 74, 72,\n                                  77, 95, 80, 68, 108, 125, 97, 106, 100, 126,\n                                  87, 82, 116, 67, 76, 76, 84, 88, 100, 95, 88,\n                                  106, 93, 93, 97, 107, 1, 13, 41, 26, 10, 4,\n                                  16, 9, 4, 1, 14, 20, 44, 29, 22, 13, 35, 18,\n                                  21, 6, 36, 8, 37, 24, 19, 12, 26, 11, 5, 4, 4,\n                                  68, 54, 31, 11, 3, 20, 5, 70, 64, 17, 42, 36,\n                                  22, 10, 33, 14, 12, 5, 3, 62, 67, 4, 11, 9, 1,\n                                  8, 13, 16, 15, 21, 27, 39, 67, 2, 72, 71, 62,\n                                  78, 102, 72, 4, 5, 71, 71, 70, 74, 1, 77, 97,\n                                  69, 68, 23, 70, 77, 69, 68, 64, 73, 72, 70,\n                                  91, 84, 73, 75, 70, 26, 102, 77, 26, 84, 69,\n                                  69, 70, 6, 67, 72, 4, 11, 71, 71, 109, 31, 29,\n                                  30, 12, 69, 70, 71, 82, 72, 83, 88, 82, 100,\n                                  96, 97, 108, 104, 116, 126, 100, 92, 90, 92,\n                                  105, 97, 91, 93, 94, 79, 80, 85, 82, 87, 106,\n                                  92, 89, 113, 99, 112, 111, 126, 124, 119, 118,\n                                  79, 77, 120, 87, 88, 94, 112, 100, 101, 103,\n                                  92, 97, 86, 80, 109, 115, 126, 89, 101, 106,\n                                  69, 11, 16, 18, 37, 25, 30, 7, 34, 29, 39, 32,\n                                  42, 36, 25, 41, 70, 79, 87, 95, 95, 122, 121,\n                                  117, 17, 45, 41, 44, 34, 37, 22, 21, 12, 11,\n                                  69, 11, 16, 18, 37, 25, 30, 7, 34, 29, 39, 32,\n                                  42, 36, 25, 41, 70, 79, 87, 95, 95, 122, 121,\n                                  117 },\n\n                                {\n\n                                23,\n                                  4, 82, 23, 4, 82, 13, 23, 27, 12, 70, 95, 68,\n                                  25, 40, 10, 39, 87, 74, 27, 70, 73, 37, 95,\n                                  95, 65, 79, 126, 126, 126, 24, 7, 68, 74, 27,\n                                  70, 76, 14, 36, 66, 5, 2, 5, 109, 113, 95,\n                                  112, 65, 71, 70, 76, 91, 81, 98, 0, 68, 69,\n                                  64, 33, 1, 22, 0, 0, 0, 5, 97, 97, 11, 76, 70,\n                                  10, 0, 72, 35, 19, 7, 48, 46, 7, 19, 22, 26,\n                                  10, 9, 38, 110, 89, 89, 91, 25, 72, 19, 38,\n                                  65, 73, 3, 19, 65, 73, 72, 81, 24, 76, 14, 1,\n                                  75, 8, 68, 0, 7, 13, 18, 19, 7, 79, 68, 3, 65,\n                                  0, 71, 30, 66, 1, 32, 27, 38, 31, 27, 98, 10,\n                                  11, 76, 67, 76, 69, 33, 2, 5, 38, 57, 62, 62,\n                                  49, 99, 109, 11, 42, 42, 126, 73, 14, 99, 25,\n                                  70, 4, 37, 33, 54, 49, 47, 110, 3, 83, 103,\n                                  103, 66, 13, 21, 10, 4, 10, 10, 2, 15, 8, 78,\n                                  71, 5, 0, 0, 76, 66, 74, 80, 67, 67, 0, 72,\n                                  73, 110, 75, 78, 69, 88, 85, 78, 65, 74, 76,\n                                  74, 79, 99, 83, 69, 110, 126, 99, 108, 102,\n                                  126, 89, 83, 118, 68, 77, 77, 85, 89, 102, 97,\n                                  90, 108, 93, 94, 98, 109, 2, 14, 42, 26, 10,\n                                  4, 17, 10, 5, 2, 16, 21, 45, 29, 23, 14, 36,\n                                  19, 23, 7, 38, 9, 37, 24, 19, 13, 27, 12, 5,\n                                  4, 5, 68, 55, 32, 11, 3, 21, 5, 70, 0, 18, 42,\n                                  37, 22, 10, 34, 15, 13, 5, 4, 62, 66, 5, 12,\n                                  11, 2, 10, 14, 18, 16, 22, 29, 41, 66, 3, 71,\n                                  70, 62, 78, 103, 72, 5, 5, 71, 71, 70, 75, 2,\n                                  77, 98, 69, 68, 24, 70, 77, 69, 68, 64, 74,\n                                  72, 70, 92, 85, 73, 75, 70, 27, 103, 77, 26,\n                                  85, 69, 69, 70, 6, 67, 73, 4, 12, 71, 71, 110,\n                                  30, 28, 29, 10, 71, 72, 74, 85, 75, 86, 92,\n                                  85, 104, 99, 99, 112, 108, 120, 126, 103, 94,\n                                  92, 94, 108, 99, 93, 94, 95, 79, 83, 87, 84,\n                                  89, 108, 94, 91, 115, 101, 114, 113, 126, 126,\n                                  121, 119, 80, 78, 123, 89, 90, 96, 114, 101,\n                                  102, 104, 93, 98, 86, 79, 110, 116, 126, 90,\n                                  102, 107, 69, 11, 16, 19, 38, 25, 31, 7, 35,\n                                  30, 40, 32, 43, 36, 26, 41, 72, 81, 89, 97,\n                                  97, 124, 123, 119, 17, 46, 41, 45, 35, 37, 22,\n                                  21, 12, 12, 69, 11, 16, 19, 38, 25, 31, 7, 35,\n                                  30, 40, 32, 43, 36, 26, 41, 72, 81, 89, 97,\n                                  97, 124, 123, 119 },\n\n                                {\n\n                                22,\n                                  4, 82, 22, 4, 82, 15, 24, 27, 12, 70, 97, 70,\n                                  24, 41, 10, 40, 89, 73, 29, 71, 73, 38, 96,\n                                  96, 66, 81, 126, 126, 126, 26, 8, 68, 73, 29,\n                                  71, 76, 15, 36, 66, 5, 3, 7, 110, 114, 95,\n                                  112, 65, 70, 69, 77, 91, 81, 98, 0, 67, 69, 0,\n                                  33, 1, 22, 0, 0, 0, 6, 97, 97, 11, 77, 70, 10,\n                                  1, 70, 38, 20, 8, 50, 48, 8, 20, 24, 27, 11,\n                                  10, 41, 110, 90, 89, 92, 25, 72, 20, 41, 64,\n                                  73, 3, 21, 65, 73, 72, 80, 24, 76, 15, 2, 74,\n                                  9, 67, 0, 8, 14, 19, 20, 7, 80, 68, 4, 65, 0,\n                                  71, 31, 66, 1, 32, 28, 38, 31, 27, 98, 11, 11,\n                                  77, 67, 75, 69, 34, 3, 6, 40, 59, 62, 62, 51,\n                                  100, 110, 12, 43, 42, 126, 73, 14, 99, 26, 70,\n                                  4, 39, 33, 54, 49, 49, 111, 4, 84, 105, 106,\n                                  65, 13, 21, 10, 4, 10, 10, 2, 15, 8, 79, 72,\n                                  5, 0, 0, 76, 66, 74, 81, 67, 67, 0, 73, 74,\n                                  111, 76, 78, 69, 89, 85, 80, 67, 75, 77, 75,\n                                  81, 102, 85, 70, 112, 126, 100, 110, 104, 126,\n                                  90, 84, 119, 69, 78, 78, 87, 91, 104, 99, 91,\n                                  109, 93, 95, 99, 111, 4, 16, 43, 27, 10, 4,\n                                  18, 11, 6, 2, 18, 23, 46, 30, 23, 15, 38, 20,\n                                  24, 8, 41, 10, 38, 25, 20, 13, 28, 13, 6, 5,\n                                  6, 67, 56, 33, 11, 3, 22, 6, 69, 1, 19, 42,\n                                  38, 22, 10, 35, 16, 14, 6, 5, 62, 65, 7, 14,\n                                  12, 3, 11, 16, 20, 18, 24, 31, 44, 65, 4, 70,\n                                  69, 62, 77, 104, 71, 6, 6, 71, 71, 70, 75, 2,\n                                  78, 99, 69, 68, 25, 70, 77, 69, 68, 0, 74, 73,\n                                  70, 93, 86, 74, 75, 70, 28, 103, 78, 27, 85,\n                                  70, 69, 70, 6, 68, 73, 4, 12, 71, 71, 112, 29,\n                                  27, 28, 9, 74, 75, 77, 88, 77, 89, 95, 88,\n                                  107, 101, 101, 116, 111, 124, 126, 106, 96,\n                                  93, 96, 110, 101, 94, 95, 96, 79, 85, 90, 87,\n                                  91, 110, 96, 92, 117, 103, 116, 115, 126, 126,\n                                  122, 121, 81, 79, 125, 90, 91, 97, 116, 102,\n                                  103, 105, 94, 99, 86, 78, 112, 117, 126, 92,\n                                  103, 108, 69, 12, 17, 20, 39, 26, 31, 8, 36,\n                                  31, 41, 33, 44, 37, 26, 40, 74, 83, 91, 99,\n                                  99, 126, 125, 120, 18, 46, 42, 45, 36, 38, 23,\n                                  22, 12, 13, 69, 12, 17, 20, 39, 26, 31, 8, 36,\n                                  31, 41, 33, 44, 37, 26, 40, 74, 83, 91, 99,\n                                  99, 126, 125, 120 },\n\n                                {\n\n                                21,\n                                  4, 82, 21, 4, 82, 17, 26, 28, 12, 71, 99, 71,\n                                  23, 41, 10, 42, 90, 73, 30, 71, 74, 39, 97,\n                                  97, 67, 83, 126, 126, 126, 28, 10, 68, 73, 30,\n                                  71, 75, 16, 37, 66, 6, 4, 8, 111, 115, 95,\n                                  113, 65, 70, 68, 77, 92, 81, 98, 0, 67, 69, 1,\n                                  34, 1, 22, 0, 0, 0, 6, 97, 97, 12, 78, 70, 9,\n                                  1, 69, 40, 21, 9, 51, 49, 9, 21, 26, 28, 12,\n                                  11, 43, 111, 90, 89, 92, 26, 72, 21, 43, 64,\n                                  72, 4, 23, 65, 73, 72, 80, 25, 76, 15, 3, 74,\n                                  10, 67, 0, 8, 14, 20, 20, 7, 80, 68, 4, 65, 0,\n                                  71, 31, 66, 1, 33, 28, 39, 31, 28, 99, 11, 12,\n                                  77, 67, 75, 69, 35, 3, 6, 41, 60, 62, 62, 53,\n                                  100, 111, 12, 43, 42, 126, 73, 15, 100, 26,\n                                  70, 4, 40, 33, 54, 49, 50, 112, 6, 85, 108,\n                                  109, 0, 13, 21, 9, 3, 9, 9, 1, 15, 7, 80, 73,\n                                  5, 0, 0, 77, 67, 75, 82, 68, 67, 0, 74, 74,\n                                  112, 76, 79, 69, 90, 86, 82, 69, 77, 79, 77,\n                                  83, 105, 88, 71, 114, 126, 102, 112, 106, 126,\n                                  91, 85, 121, 70, 79, 79, 88, 92, 106, 101, 93,\n                                  111, 93, 96, 100, 112, 5, 17, 45, 27, 10, 4,\n                                  19, 12, 7, 3, 20, 24, 47, 31, 24, 15, 39, 21,\n                                  26, 9, 43, 10, 38, 25, 20, 14, 29, 13, 6, 6,\n                                  7, 67, 58, 34, 11, 3, 23, 6, 69, 2, 20, 43,\n                                  39, 23, 10, 36, 16, 15, 6, 5, 62, 0, 8, 15,\n                                  14, 4, 13, 17, 21, 19, 26, 33, 46, 65, 5, 70,\n                                  68, 62, 77, 105, 71, 7, 7, 71, 71, 70, 75, 3,\n                                  78, 100, 69, 68, 25, 70, 77, 69, 68, 0, 75,\n                                  73, 70, 94, 87, 74, 75, 70, 29, 104, 78, 28,\n                                  86, 70, 69, 70, 7, 68, 74, 5, 13, 71, 71, 113,\n                                  28, 26, 27, 7, 76, 77, 79, 91, 80, 92, 98, 91,\n                                  110, 104, 103, 120, 115, 126, 126, 109, 98,\n                                  95, 98, 113, 103, 95, 96, 97, 79, 87, 92, 89,\n                                  93, 112, 98, 94, 119, 105, 118, 117, 126, 126,\n                                  124, 122, 82, 80, 126, 92, 93, 99, 118, 104,\n                                  105, 106, 95, 100, 86, 77, 113, 119, 126, 93,\n                                  104, 109, 69, 12, 17, 20, 40, 27, 32, 8, 37,\n                                  32, 42, 33, 45, 37, 27, 40, 76, 85, 93, 101,\n                                  101, 126, 126, 121, 18, 47, 42, 46, 36, 39,\n                                  23, 22, 13, 13, 69, 12, 17, 20, 40, 27, 32, 8,\n                                  37, 32, 42, 33, 45, 37, 27, 40, 76, 85, 93,\n                                  101, 101, 126, 126, 121 },\n\n                                {\n\n                                20,\n                                  4, 82, 20, 4, 82, 19, 27, 28, 12, 71, 101, 73,\n                                  22, 42, 10, 44, 92, 73, 32, 71, 74, 40, 98,\n                                  98, 68, 85, 126, 126, 126, 30, 11, 68, 73, 32,\n                                  71, 75, 17, 37, 66, 7, 5, 9, 112, 116, 95,\n                                  113, 65, 70, 67, 77, 92, 81, 98, 0, 67, 69, 2,\n                                  34, 1, 22, 0, 0, 0, 7, 97, 97, 12, 79, 70, 9,\n                                  2, 68, 42, 22, 10, 53, 51, 10, 22, 28, 29, 13,\n                                  12, 45, 112, 90, 89, 92, 26, 72, 22, 45, 64,\n                                  71, 5, 25, 65, 73, 72, 80, 25, 76, 16, 4, 74,\n                                  11, 67, 0, 8, 15, 21, 21, 7, 80, 68, 4, 65, 0,\n                                  71, 31, 66, 1, 33, 28, 39, 31, 28, 99, 12, 13,\n                                  78, 67, 75, 69, 36, 3, 7, 42, 61, 62, 62, 55,\n                                  101, 112, 13, 43, 42, 126, 73, 15, 100, 27,\n                                  70, 4, 41, 33, 54, 49, 51, 113, 7, 86, 111,\n                                  112, 1, 13, 21, 9, 2, 9, 9, 1, 15, 7, 81, 74,\n                                  5, 0, 0, 77, 67, 76, 83, 68, 67, 0, 75, 75,\n                                  113, 77, 80, 69, 91, 86, 84, 71, 79, 80, 79,\n                                  85, 108, 90, 72, 116, 126, 103, 114, 108, 126,\n                                  92, 86, 123, 71, 80, 80, 89, 94, 108, 103, 95,\n                                  112, 93, 97, 101, 114, 7, 19, 46, 28, 10, 4,\n                                  20, 13, 8, 4, 22, 25, 48, 32, 25, 16, 40, 22,\n                                  27, 10, 45, 11, 39, 26, 21, 14, 30, 14, 7, 7,\n                                  8, 67, 59, 35, 11, 3, 24, 7, 69, 3, 21, 43,\n                                  40, 23, 10, 37, 17, 16, 7, 6, 62, 1, 10, 17,\n                                  16, 5, 14, 19, 23, 21, 28, 35, 48, 64, 6, 69,\n                                  67, 62, 77, 106, 71, 8, 8, 71, 71, 70, 75, 3,\n                                  78, 101, 69, 68, 26, 70, 77, 69, 68, 0, 75,\n                                  73, 70, 95, 88, 74, 75, 70, 30, 105, 78, 29,\n                                  87, 70, 69, 70, 7, 68, 74, 5, 14, 71, 71, 115,\n                                  27, 25, 26, 5, 78, 80, 82, 94, 82, 95, 101,\n                                  94, 113, 107, 105, 124, 118, 126, 126, 112,\n                                  100, 97, 100, 115, 105, 96, 97, 98, 79, 89,\n                                  94, 91, 95, 114, 100, 95, 121, 107, 120, 119,\n                                  126, 126, 126, 123, 83, 81, 126, 93, 95, 100,\n                                  120, 105, 106, 107, 96, 101, 86, 76, 114, 120,\n                                  126, 94, 105, 110, 69, 13, 18, 21, 41, 28, 33,\n                                  8, 38, 33, 43, 34, 46, 38, 28, 39, 78, 87, 95,\n                                  103, 103, 126, 126, 122, 19, 47, 43, 47, 37,\n                                  40, 24, 23, 13, 14, 69, 13, 18, 21, 41, 28,\n                                  33, 8, 38, 33, 43, 34, 46, 38, 28, 39, 78, 87,\n                                  95, 103, 103, 126, 126, 122 },\n\n                                {\n\n                                18,\n                                  3, 83, 18, 3, 83, 20, 28, 28, 12, 72, 103, 75,\n                                  21, 42, 10, 45, 94, 73, 33, 72, 75, 41, 99,\n                                  100, 70, 87, 126, 126, 126, 32, 12, 68, 73,\n                                  33, 72, 75, 17, 37, 67, 7, 5, 10, 114, 118,\n                                  96, 114, 66, 70, 67, 78, 93, 81, 98, 64, 67,\n                                  69, 2, 34, 0, 22, 0, 0, 0, 7, 98, 97, 12, 80,\n                                  71, 8, 2, 67, 44, 23, 10, 54, 52, 10, 23, 29,\n                                  29, 14, 12, 47, 113, 91, 90, 93, 26, 73, 22,\n                                  47, 64, 71, 5, 26, 65, 73, 72, 80, 25, 77, 16,\n                                  4, 74, 11, 67, 0, 8, 15, 22, 21, 7, 81, 69, 4,\n                                  65, 64, 71, 31, 66, 1, 33, 28, 39, 31, 28,\n                                  100, 12, 13, 79, 67, 75, 70, 36, 3, 7, 43, 62,\n                                  62, 62, 56, 102, 114, 13, 43, 42, 126, 74, 15,\n                                  101, 27, 71, 4, 42, 33, 53, 49, 52, 114, 8,\n                                  88, 114, 116, 2, 12, 21, 8, 1, 8, 8, 0, 14, 6,\n                                  82, 75, 4, 64, 64, 78, 68, 77, 84, 69, 68, 64,\n                                  76, 76, 115, 78, 81, 69, 93, 87, 87, 74, 81,\n                                  82, 81, 88, 112, 93, 74, 118, 126, 105, 117,\n                                  110, 126, 94, 88, 125, 73, 81, 81, 91, 96,\n                                  110, 105, 97, 114, 93, 98, 102, 116, 8, 20,\n                                  47, 28, 10, 4, 20, 13, 8, 4, 23, 26, 48, 32,\n                                  25, 16, 41, 23, 28, 10, 47, 11, 39, 26, 21,\n                                  14, 30, 14, 7, 7, 9, 67, 60, 36, 11, 2, 24, 7,\n                                  69, 3, 21, 43, 40, 23, 10, 38, 17, 16, 7, 6,\n                                  62, 2, 11, 18, 17, 6, 15, 20, 24, 22, 29, 36,\n                                  50, 64, 6, 69, 67, 62, 77, 108, 71, 8, 8, 71,\n                                  71, 70, 76, 3, 79, 102, 70, 68, 26, 71, 77,\n                                  70, 68, 0, 76, 74, 71, 96, 89, 75, 76, 70, 31,\n                                  106, 79, 29, 88, 71, 69, 71, 7, 69, 75, 5, 14,\n                                  71, 71, 117, 25, 24, 24, 3, 81, 83, 85, 97,\n                                  85, 98, 105, 97, 117, 110, 107, 126, 122, 126,\n                                  126, 115, 103, 99, 103, 118, 107, 98, 99, 99,\n                                  79, 92, 97, 94, 97, 117, 102, 97, 124, 109,\n                                  123, 121, 126, 126, 126, 125, 85, 83, 126, 95,\n                                  97, 102, 122, 107, 108, 108, 97, 102, 87, 75,\n                                  116, 122, 126, 96, 107, 112, 69, 13, 18, 21,\n                                  42, 28, 33, 8, 39, 33, 44, 34, 46, 38, 28, 38,\n                                  80, 89, 98, 106, 105, 126, 126, 124, 19, 47,\n                                  43, 47, 37, 40, 24, 23, 13, 14, 69, 13, 18,\n                                  21, 42, 28, 33, 8, 39, 33, 44, 34, 46, 38, 28,\n                                  38, 80, 89, 98, 106, 105, 126, 126, 124 },\n\n                                {\n\n                                17,\n                                  3, 83, 17, 3, 83, 22, 30, 29, 13, 72, 104, 76,\n                                  21, 43, 11, 47, 95, 72, 35, 72, 75, 43, 99,\n                                  101, 71, 88, 126, 126, 126, 34, 14, 67, 72,\n                                  35, 72, 74, 18, 38, 67, 8, 6, 12, 115, 119,\n                                  96, 114, 66, 69, 66, 78, 93, 80, 97, 64, 66,\n                                  68, 3, 35, 0, 22, 0, 0, 0, 8, 98, 97, 13, 80,\n                                  71, 8, 3, 65, 47, 25, 11, 56, 54, 11, 25, 31,\n                                  30, 16, 13, 50, 113, 91, 90, 93, 27, 73, 23,\n                                  50, 0, 70, 6, 28, 65, 72, 72, 79, 26, 77, 17,\n                                  5, 73, 12, 66, 1, 9, 16, 23, 22, 8, 81, 69, 5,\n                                  64, 64, 70, 32, 65, 1, 34, 29, 40, 32, 29,\n                                  100, 13, 14, 79, 67, 74, 70, 37, 4, 8, 45, 62,\n                                  62, 62, 58, 102, 115, 14, 44, 43, 126, 74, 16,\n                                  101, 28, 71, 5, 44, 33, 53, 50, 54, 115, 10,\n                                  89, 116, 119, 4, 12, 21, 8, 1, 8, 8, 0, 14, 6,\n                                  82, 75, 4, 64, 64, 78, 68, 77, 84, 69, 68, 64,\n                                  76, 76, 116, 78, 81, 69, 94, 87, 89, 76, 82,\n                                  83, 82, 90, 115, 95, 75, 119, 126, 106, 119,\n                                  111, 126, 95, 89, 126, 74, 81, 81, 92, 97,\n                                  111, 106, 98, 115, 93, 98, 102, 117, 10, 22,\n                                  49, 29, 10, 4, 21, 14, 9, 5, 25, 28, 49, 33,\n                                  26, 17, 43, 24, 30, 11, 50, 12, 40, 27, 22,\n                                  15, 31, 15, 8, 8, 11, 66, 62, 37, 12, 2, 25,\n                                  8, 68, 4, 22, 44, 41, 24, 11, 39, 18, 17, 8,\n                                  7, 62, 4, 13, 20, 19, 8, 17, 22, 26, 24, 31,\n                                  38, 53, 0, 7, 68, 66, 62, 76, 109, 70, 9, 9,\n                                  70, 71, 69, 76, 4, 79, 102, 70, 68, 27, 71,\n                                  77, 70, 68, 1, 76, 74, 71, 96, 89, 75, 76, 69,\n                                  33, 106, 79, 30, 88, 71, 69, 71, 8, 69, 75, 6,\n                                  15, 70, 70, 118, 24, 23, 23, 2, 83, 85, 87,\n                                  100, 87, 100, 108, 99, 120, 112, 109, 126,\n                                  125, 126, 126, 117, 105, 100, 105, 120, 108,\n                                  99, 100, 99, 79, 94, 99, 96, 99, 119, 103, 98,\n                                  126, 110, 125, 122, 126, 126, 126, 126, 86,\n                                  84, 126, 96, 98, 103, 123, 108, 109, 109, 97,\n                                  102, 87, 74, 117, 123, 126, 97, 108, 113, 68,\n                                  14, 19, 22, 44, 29, 34, 9, 41, 34, 45, 35, 47,\n                                  39, 29, 38, 81, 90, 100, 108, 106, 126, 126,\n                                  125, 20, 48, 44, 48, 38, 41, 25, 24, 14, 15,\n                                  68, 14, 19, 22, 44, 29, 34, 9, 41, 34, 45, 35,\n                                  47, 39, 29, 38, 81, 90, 100, 108, 106, 126,\n                                  126, 125 },\n\n                                {\n\n                                16,\n                                  3, 83, 16, 3, 83, 24, 31, 29, 13, 72, 106, 78,\n                                  20, 44, 11, 49, 97, 72, 36, 72, 75, 44, 100,\n                                  102, 72, 90, 126, 126, 126, 36, 15, 67, 72,\n                                  36, 72, 74, 19, 38, 67, 9, 7, 13, 116, 120,\n                                  96, 114, 66, 69, 65, 78, 93, 80, 97, 64, 66,\n                                  68, 4, 35, 0, 22, 0, 0, 0, 9, 98, 97, 13, 81,\n                                  71, 8, 4, 64, 49, 26, 12, 58, 56, 12, 26, 33,\n                                  31, 17, 14, 52, 114, 91, 90, 93, 27, 73, 24,\n                                  52, 0, 69, 7, 30, 65, 72, 72, 79, 26, 77, 17,\n                                  6, 73, 13, 66, 1, 9, 16, 24, 23, 8, 81, 69, 5,\n                                  64, 64, 70, 32, 65, 1, 34, 29, 40, 32, 29,\n                                  101, 14, 15, 80, 67, 74, 70, 38, 4, 8, 46, 62,\n                                  62, 62, 60, 103, 116, 14, 44, 43, 126, 74, 16,\n                                  102, 29, 71, 5, 45, 33, 53, 50, 55, 116, 11,\n                                  90, 119, 122, 5, 12, 21, 8, 0, 7, 8, 0, 14, 5,\n                                  83, 76, 4, 64, 64, 78, 69, 78, 85, 69, 68, 64,\n                                  77, 77, 117, 79, 82, 69, 95, 88, 91, 78, 84,\n                                  85, 84, 92, 118, 97, 76, 121, 126, 108, 121,\n                                  113, 126, 96, 90, 126, 75, 82, 82, 93, 99,\n                                  113, 108, 100, 117, 93, 99, 103, 119, 11, 23,\n                                  50, 30, 10, 4, 22, 15, 10, 6, 27, 29, 50, 34,\n                                  27, 18, 44, 25, 31, 12, 52, 13, 40, 27, 22,\n                                  15, 32, 16, 9, 9, 12, 66, 62, 38, 12, 2, 26,\n                                  9, 68, 5, 23, 44, 42, 24, 11, 40, 19, 18, 9,\n                                  8, 62, 5, 15, 22, 21, 9, 18, 24, 28, 25, 33,\n                                  40, 55, 1, 8, 67, 65, 62, 76, 110, 70, 10, 10,\n                                  70, 71, 69, 76, 4, 79, 103, 70, 68, 28, 71,\n                                  77, 70, 68, 1, 76, 74, 71, 97, 90, 75, 76, 69,\n                                  34, 107, 79, 31, 89, 71, 69, 71, 8, 69, 75, 6,\n                                  16, 70, 70, 120, 23, 22, 22, 0, 85, 88, 90,\n                                  103, 89, 103, 111, 102, 123, 115, 111, 126,\n                                  126, 126, 126, 120, 107, 102, 107, 122, 110,\n                                  100, 101, 100, 79, 96, 101, 98, 101, 121, 105,\n                                  100, 126, 112, 126, 124, 126, 126, 126, 126,\n                                  87, 85, 126, 98, 100, 105, 125, 109, 110, 110,\n                                  98, 103, 87, 73, 118, 124, 126, 98, 109, 114,\n                                  68, 14, 20, 23, 45, 30, 35, 9, 42, 35, 46, 35,\n                                  48, 40, 30, 37, 83, 92, 102, 110, 108, 126,\n                                  126, 126, 21, 48, 44, 49, 39, 42, 25, 25, 14,\n                                  16, 68, 14, 20, 23, 45, 30, 35, 9, 42, 35, 46,\n                                  35, 48, 40, 30, 37, 83, 92, 102, 110, 108,\n                                  126, 126, 126 },\n\n                                {\n\n                                15,\n                                  3, 83, 15, 3, 83, 26, 33, 30, 13, 73, 108, 79,\n                                  19, 44, 11, 51, 98, 72, 38, 72, 76, 45, 101,\n                                  103, 73, 92, 126, 126, 126, 38, 17, 67, 72,\n                                  38, 72, 73, 20, 39, 67, 10, 8, 14, 117, 121,\n                                  96, 115, 66, 69, 64, 78, 94, 80, 97, 64, 66,\n                                  68, 5, 36, 0, 22, 0, 0, 0, 9, 98, 97, 14, 82,\n                                  71, 7, 4, 0, 51, 27, 13, 59, 57, 13, 27, 35,\n                                  32, 18, 15, 54, 115, 91, 90, 93, 28, 73, 25,\n                                  54, 0, 68, 8, 32, 65, 72, 72, 79, 27, 77, 18,\n                                  7, 73, 14, 66, 1, 9, 17, 25, 23, 8, 81, 69, 5,\n                                  64, 64, 70, 32, 65, 1, 35, 29, 41, 32, 30,\n                                  101, 14, 16, 80, 67, 74, 70, 39, 4, 9, 47, 62,\n                                  62, 62, 62, 103, 117, 15, 44, 43, 126, 74, 17,\n                                  102, 29, 71, 5, 46, 33, 53, 50, 56, 117, 13,\n                                  91, 122, 125, 7, 12, 21, 7, 64, 7, 7, 64, 14,\n                                  5, 84, 77, 4, 64, 64, 79, 69, 79, 86, 70, 68,\n                                  64, 78, 77, 118, 79, 83, 69, 96, 88, 93, 80,\n                                  86, 86, 86, 94, 121, 100, 77, 123, 126, 109,\n                                  123, 115, 126, 97, 91, 126, 76, 83, 83, 94,\n                                  100, 115, 110, 102, 118, 93, 100, 104, 120,\n                                  13, 25, 52, 30, 10, 4, 23, 16, 11, 7, 29, 30,\n                                  51, 35, 28, 18, 45, 26, 33, 13, 54, 13, 41,\n                                  28, 23, 16, 33, 16, 9, 10, 13, 66, 62, 39, 12,\n                                  2, 27, 9, 68, 6, 24, 45, 43, 25, 11, 41, 19,\n                                  19, 9, 8, 62, 7, 16, 23, 23, 10, 20, 25, 29,\n                                  27, 35, 42, 57, 1, 9, 67, 64, 62, 76, 111, 70,\n                                  11, 11, 70, 71, 69, 76, 5, 79, 104, 70, 68,\n                                  28, 71, 77, 70, 68, 1, 77, 74, 71, 98, 91, 75,\n                                  76, 69, 35, 108, 79, 32, 90, 71, 69, 71, 9,\n                                  69, 76, 7, 17, 70, 70, 121, 22, 21, 21, 65,\n                                  87, 90, 92, 106, 92, 106, 114, 105, 126, 118,\n                                  113, 126, 126, 126, 126, 123, 109, 104, 109,\n                                  125, 112, 101, 102, 101, 79, 98, 103, 100,\n                                  103, 123, 107, 101, 126, 114, 126, 126, 126,\n                                  126, 126, 126, 88, 86, 126, 99, 102, 106, 126,\n                                  111, 112, 111, 99, 104, 87, 72, 119, 126, 126,\n                                  99, 110, 115, 68, 15, 20, 23, 46, 31, 36, 9,\n                                  43, 36, 47, 36, 49, 40, 31, 37, 85, 94, 104,\n                                  112, 110, 126, 126, 126, 21, 49, 45, 50, 39,\n                                  43, 26, 25, 15, 16, 68, 15, 20, 23, 46, 31,\n                                  36, 9, 43, 36, 47, 36, 49, 40, 31, 37, 85, 94,\n                                  104, 112, 110, 126, 126, 126 },\n\n                          },\n\n                          {\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 126, 104, 10, 9, 12, 30, 61,\n                                62, 54, 14, 118, 6, 78, 65, 1, 14, 73, 13, 64,\n                                20, 62, 67, 90, 104, 126, 104, 67, 78, 65, 1,\n                                86, 95, 2, 18, 69, 81, 96, 8, 67, 86, 88, 5, 76,\n                                94, 9, 69, 81, 88, 67, 74, 74, 80, 72, 5, 22, 0,\n                                0, 0, 83, 86, 97, 72, 22, 1, 52, 8, 69, 126,\n                                102, 82, 74, 107, 126, 126, 126, 95, 126, 114,\n                                126, 123, 115, 122, 115, 0, 68, 84, 104, 70, 93,\n                                90, 126, 74, 97, 91, 126, 7, 82, 76, 125, 93,\n                                87, 77, 71, 0, 68, 84, 1, 65, 2, 7, 66, 64, 2,\n                                78, 13, 11, 28, 19, 25, 18, 17, 19, 46, 12, 13,\n                                44, 30, 1, 108, 100, 101, 91, 94, 88, 84, 86,\n                                83, 87, 94, 70, 72, 74, 4, 102, 100, 95, 75, 72,\n                                75, 71, 17, 69, 1, 65, 26, 72, 6, 9, 1, 72, 62,\n                                54, 38, 45, 54, 44, 26, 45, 34, 30, 33, 18, 5,\n                                1, 2, 25, 18, 24, 21, 19, 18, 22, 14, 29, 21, 8,\n                                12, 17, 89, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 62, 62, 62, 46, 62, 60, 41, 62, 62, 62,\n                                62, 60, 58, 62, 47, 41, 15, 26, 3, 68, 97, 71,\n                                21, 13, 9, 1, 5, 0, 72, 74, 91, 67, 36, 24, 19,\n                                17, 64, 68, 78, 77, 86, 92, 8, 3, 1, 65, 73, 76,\n                                80, 88, 110, 97, 84, 79, 73, 74, 86, 96, 97,\n                                117, 78, 30, 15, 10, 1, 71, 79, 86, 90, 97, 62,\n                                93, 84, 79, 66, 71, 1, 3, 4, 75, 1, 5, 66, 79,\n                                71, 68, 19, 1, 27, 23, 36, 34, 19, 27, 31, 21,\n                                15, 1, 17, 64, 104, 97, 96, 88, 85, 85, 85, 88,\n                                66, 77, 76, 76, 5, 76, 83, 99, 95, 95, 76, 74,\n                                70, 75, 68, 65, 73, 1, 1, 68, 75, 8, 64, 70, 57,\n                                44, 47, 49, 50, 52, 48, 47, 40, 40, 43, 37, 19,\n                                23, 16, 46, 42, 41, 36, 34, 28, 13, 6, 0, 77,\n                                82, 94, 69, 109, 62, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 62, 61, 50, 28, 5, 62, 62, 33, 62, 62,\n                                62, 60, 62, 58, 52, 58, 51, 52, 34, 37, 24, 66,\n                                42, 32, 13, 120, 112, 114, 85, 92, 89, 71, 81,\n                                80, 68, 70, 7, 68, 13, 74, 62, 62, 62, 62, 60,\n                                57, 29, 9, 82, 75, 40, 29, 20, 9, 8, 2, 64, 68,\n                                92, 106, 97, 90, 90, 88, 73, 79, 86, 73, 70, 69,\n                                66, 64, 5, 4, 62, 62, 62, 62, 60, 54, 43, 27, 67 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 125, 102, 11, 10, 12, 29,\n                                  60, 62, 54, 14, 115, 6, 77, 64, 1, 14, 72, 12,\n                                  65, 20, 62, 68, 91, 104, 124, 102, 67, 77, 64,\n                                  1, 85, 93, 3, 18, 68, 80, 95, 8, 67, 85, 88,\n                                  5, 75, 93, 9, 69, 80, 88, 66, 73, 73, 79, 71,\n                                  5, 22, 0, 0, 0, 82, 86, 97, 71, 22, 1, 52, 8,\n                                  69, 125, 101, 82, 73, 105, 125, 125, 125, 93,\n                                  125, 112, 125, 121, 114, 121, 114, 1, 67, 83,\n                                  103, 69, 92, 89, 125, 73, 96, 90, 125, 8, 81,\n                                  75, 123, 92, 86, 76, 70, 1, 67, 83, 2, 64, 2,\n                                  7, 65, 64, 2, 77, 13, 11, 28, 19, 25, 18, 17,\n                                  19, 45, 12, 13, 43, 29, 1, 107, 99, 100, 90,\n                                  93, 87, 83, 85, 82, 86, 92, 70, 72, 73, 3,\n                                  101, 99, 95, 74, 72, 74, 70, 17, 68, 1, 65,\n                                  25, 71, 6, 8, 1, 72, 62, 54, 38, 45, 54, 44,\n                                  26, 45, 34, 29, 33, 18, 5, 1, 2, 25, 18, 24,\n                                  21, 19, 17, 22, 14, 28, 20, 8, 11, 16, 89, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 60, 44, 62, 59, 40, 62, 62, 62, 62, 58,\n                                  56, 61, 45, 39, 15, 25, 2, 68, 97, 70, 22, 14,\n                                  10, 2, 5, 0, 71, 73, 90, 66, 37, 25, 20, 17,\n                                  0, 67, 77, 76, 85, 91, 9, 4, 2, 64, 72, 75,\n                                  79, 87, 108, 96, 82, 78, 72, 73, 85, 95, 96,\n                                  115, 77, 31, 16, 11, 2, 70, 78, 85, 89, 96,\n                                  62, 92, 83, 78, 66, 70, 1, 4, 5, 74, 2, 6, 65,\n                                  78, 71, 68, 19, 2, 27, 23, 35, 34, 19, 26, 30,\n                                  21, 15, 1, 16, 64, 103, 96, 95, 87, 84, 84,\n                                  84, 87, 66, 76, 75, 75, 5, 75, 82, 98, 94, 95,\n                                  76, 73, 70, 74, 68, 65, 72, 1, 1, 67, 74, 8,\n                                  64, 70, 57, 44, 47, 49, 49, 52, 48, 47, 40,\n                                  40, 43, 37, 19, 22, 15, 45, 41, 40, 35, 33,\n                                  27, 13, 6, 0, 76, 81, 93, 69, 108, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 61, 59, 48, 27, 5,\n                                  62, 62, 32, 62, 62, 62, 58, 62, 56, 50, 56,\n                                  49, 50, 33, 35, 23, 67, 41, 31, 12, 118, 110,\n                                  112, 84, 91, 88, 69, 80, 79, 68, 69, 9, 66,\n                                  15, 73, 62, 62, 62, 62, 58, 55, 27, 7, 83, 74,\n                                  41, 29, 20, 9, 9, 2, 64, 68, 91, 105, 96, 89,\n                                  89, 86, 72, 78, 85, 72, 69, 68, 65, 0, 6, 4,\n                                  62, 62, 62, 62, 59, 53, 41, 26, 67 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 123, 101, 11, 10, 12, 28,\n                                  59, 61, 54, 14, 113, 6, 76, 0, 1, 13, 72, 11,\n                                  66, 19, 60, 70, 92, 105, 121, 101, 67, 76, 0,\n                                  1, 85, 92, 3, 17, 68, 80, 94, 8, 67, 85, 88,\n                                  5, 75, 92, 9, 69, 80, 88, 66, 73, 73, 79, 71,\n                                  5, 22, 0, 0, 0, 81, 86, 97, 71, 21, 1, 52, 8,\n                                  69, 124, 100, 82, 73, 104, 123, 123, 124, 92,\n                                  123, 111, 123, 120, 113, 120, 113, 2, 67, 82,\n                                  102, 69, 92, 88, 123, 73, 96, 90, 124, 8, 81,\n                                  75, 122, 92, 85, 76, 70, 1, 67, 82, 2, 64, 1,\n                                  7, 65, 64, 2, 77, 13, 11, 27, 19, 24, 18, 17,\n                                  19, 43, 12, 13, 41, 28, 0, 106, 98, 99, 89,\n                                  92, 86, 82, 84, 82, 85, 91, 70, 72, 73, 2,\n                                  101, 98, 95, 74, 72, 73, 70, 16, 67, 1, 65,\n                                  24, 70, 5, 7, 1, 73, 60, 53, 37, 44, 53, 43,\n                                  25, 44, 34, 28, 32, 18, 5, 1, 2, 24, 17, 23,\n                                  20, 18, 16, 21, 13, 26, 19, 7, 10, 15, 89, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 58, 41, 62, 57, 38, 62, 62, 62, 62, 56,\n                                  54, 58, 43, 37, 14, 23, 1, 69, 97, 70, 22, 14,\n                                  10, 2, 5, 0, 71, 73, 89, 66, 37, 25, 20, 17,\n                                  1, 67, 76, 76, 84, 90, 10, 5, 2, 64, 71, 75,\n                                  79, 86, 107, 95, 81, 77, 72, 73, 84, 94, 95,\n                                  114, 77, 31, 16, 11, 2, 69, 77, 84, 88, 95,\n                                  62, 92, 83, 78, 66, 70, 1, 4, 5, 74, 2, 6, 64,\n                                  78, 71, 68, 18, 2, 26, 22, 34, 33, 19, 25, 29,\n                                  21, 15, 0, 15, 65, 102, 95, 94, 87, 84, 84,\n                                  83, 86, 66, 76, 75, 75, 4, 75, 82, 98, 93, 95,\n                                  76, 73, 70, 73, 68, 65, 71, 1, 1, 67, 73, 7,\n                                  64, 71, 56, 44, 47, 48, 48, 51, 47, 46, 39,\n                                  39, 42, 36, 18, 21, 14, 43, 40, 38, 33, 32,\n                                  26, 12, 5, 0, 76, 81, 93, 70, 107, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 59, 57, 46, 26, 4,\n                                  62, 60, 31, 62, 62, 62, 56, 60, 54, 48, 54,\n                                  47, 48, 31, 33, 21, 68, 39, 29, 10, 117, 109,\n                                  111, 83, 90, 87, 67, 79, 78, 68, 68, 10, 65,\n                                  16, 72, 62, 62, 62, 62, 55, 52, 24, 5, 84, 74,\n                                  41, 29, 20, 9, 9, 2, 64, 68, 90, 104, 95, 88,\n                                  88, 85, 71, 77, 84, 71, 68, 67, 65, 1, 6, 4,\n                                  62, 62, 62, 61, 57, 51, 39, 24, 68 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 121, 99, 12, 10, 11, 26, 57,\n                                  60, 54, 14, 111, 6, 75, 1, 1, 12, 72, 10, 67,\n                                  19, 58, 71, 93, 105, 118, 100, 67, 75, 1, 1,\n                                  84, 91, 4, 17, 68, 79, 93, 7, 68, 85, 88, 5,\n                                  75, 92, 9, 69, 80, 88, 65, 73, 73, 79, 70, 5,\n                                  22, 0, 0, 0, 81, 86, 97, 70, 20, 1, 52, 8, 69,\n                                  123, 99, 82, 72, 103, 121, 121, 122, 91, 121,\n                                  110, 121, 119, 112, 119, 112, 3, 67, 81, 101,\n                                  69, 91, 88, 121, 73, 95, 89, 123, 8, 81, 74,\n                                  120, 91, 84, 76, 70, 1, 67, 81, 3, 0, 1, 7,\n                                  65, 64, 2, 77, 13, 10, 27, 19, 23, 18, 17, 19,\n                                  41, 12, 12, 39, 27, 64, 105, 97, 98, 88, 91,\n                                  86, 81, 84, 81, 84, 90, 70, 72, 73, 1, 100,\n                                  97, 95, 74, 72, 72, 70, 15, 66, 1, 65, 23, 69,\n                                  5, 6, 1, 74, 59, 52, 37, 43, 52, 42, 25, 43,\n                                  33, 27, 31, 18, 5, 1, 1, 23, 16, 22, 19, 17,\n                                  15, 20, 13, 24, 18, 7, 9, 14, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 55,\n                                  39, 62, 55, 37, 62, 61, 62, 59, 54, 51, 56,\n                                  41, 34, 13, 21, 0, 70, 97, 70, 23, 14, 10, 2,\n                                  5, 0, 71, 73, 89, 66, 37, 25, 20, 17, 2, 66,\n                                  76, 75, 84, 89, 11, 5, 3, 64, 70, 74, 78, 86,\n                                  106, 94, 80, 76, 71, 73, 83, 93, 94, 113, 76,\n                                  31, 16, 11, 2, 68, 77, 83, 87, 94, 62, 91, 82,\n                                  77, 66, 70, 1, 4, 5, 74, 2, 6, 64, 78, 71, 68,\n                                  18, 3, 25, 21, 33, 32, 19, 24, 28, 21, 15, 0,\n                                  14, 65, 101, 94, 93, 86, 83, 83, 83, 85, 66,\n                                  76, 75, 74, 4, 75, 82, 97, 92, 95, 76, 73, 70,\n                                  72, 68, 65, 70, 1, 1, 67, 72, 6, 64, 72, 55,\n                                  43, 46, 47, 47, 50, 46, 45, 38, 38, 41, 35,\n                                  17, 20, 13, 42, 39, 37, 31, 30, 25, 11, 5, 64,\n                                  76, 81, 93, 70, 106, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 57, 54, 44, 24, 3, 61, 59, 29,\n                                  62, 62, 60, 54, 58, 52, 46, 52, 45, 45, 29,\n                                  31, 19, 69, 37, 27, 9, 116, 108, 110, 82, 89,\n                                  86, 66, 78, 77, 68, 67, 12, 0, 18, 71, 62, 62,\n                                  62, 62, 52, 49, 21, 3, 85, 74, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 90, 103, 94, 87, 87, 84, 71, 77,\n                                  83, 71, 68, 67, 65, 1, 6, 4, 62, 62, 62, 59,\n                                  55, 49, 37, 22, 69 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 120, 98, 12, 10, 11, 25, 56,\n                                  58, 54, 14, 108, 5, 74, 1, 1, 11, 72, 9, 68,\n                                  18, 56, 73, 94, 106, 115, 99, 67, 74, 1, 1,\n                                  84, 90, 4, 16, 68, 79, 93, 7, 68, 84, 88, 5,\n                                  75, 91, 8, 70, 80, 88, 65, 72, 73, 78, 70, 5,\n                                  22, 0, 0, 0, 80, 87, 97, 70, 19, 1, 52, 8, 69,\n                                  122, 98, 82, 72, 101, 120, 119, 121, 90, 120,\n                                  108, 119, 118, 112, 118, 112, 3, 67, 80, 100,\n                                  69, 91, 87, 119, 73, 95, 89, 122, 8, 80, 74,\n                                  119, 91, 84, 76, 69, 1, 67, 81, 3, 0, 0, 6,\n                                  65, 64, 2, 77, 13, 10, 26, 19, 23, 18, 17, 18,\n                                  39, 12, 12, 37, 26, 65, 104, 96, 97, 87, 91,\n                                  85, 80, 83, 81, 83, 89, 70, 72, 72, 0, 100,\n                                  96, 95, 74, 72, 72, 70, 14, 65, 1, 65, 21, 68,\n                                  4, 5, 1, 75, 57, 51, 36, 42, 51, 41, 24, 42,\n                                  33, 25, 30, 17, 5, 1, 1, 22, 16, 21, 19, 16,\n                                  14, 19, 12, 22, 17, 6, 8, 13, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 59, 53,\n                                  36, 62, 54, 35, 62, 59, 62, 57, 51, 49, 53,\n                                  39, 32, 12, 20, 65, 71, 97, 70, 23, 15, 10, 2,\n                                  5, 0, 71, 73, 88, 65, 38, 25, 20, 17, 3, 66,\n                                  75, 75, 83, 89, 12, 6, 3, 64, 70, 74, 78, 85,\n                                  105, 94, 79, 76, 71, 73, 82, 92, 94, 112, 76,\n                                  32, 16, 11, 2, 67, 76, 83, 86, 93, 62, 91, 82,\n                                  77, 66, 70, 1, 4, 5, 73, 2, 6, 0, 78, 71, 68,\n                                  17, 3, 24, 20, 32, 31, 19, 22, 27, 20, 15, 64,\n                                  13, 66, 101, 94, 92, 86, 83, 83, 82, 84, 67,\n                                  76, 75, 74, 3, 75, 82, 97, 91, 95, 76, 72, 70,\n                                  72, 68, 65, 69, 1, 0, 67, 71, 6, 65, 73, 54,\n                                  43, 46, 46, 46, 49, 45, 44, 37, 37, 40, 34,\n                                  16, 19, 12, 40, 37, 35, 29, 29, 24, 10, 4, 64,\n                                  76, 81, 93, 71, 106, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 60, 55, 52, 42, 23, 2, 59, 57, 28,\n                                  62, 62, 58, 52, 55, 50, 44, 50, 43, 43, 27,\n                                  29, 17, 70, 35, 25, 7, 115, 107, 109, 82, 88,\n                                  85, 64, 77, 76, 68, 66, 13, 1, 19, 71, 62, 62,\n                                  62, 62, 49, 46, 18, 1, 86, 74, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 89, 102, 93, 86, 87, 83, 70, 76,\n                                  82, 70, 67, 66, 64, 2, 7, 4, 62, 62, 62, 57,\n                                  53, 47, 35, 20, 70 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 118, 96, 12, 10, 10, 23, 54,\n                                  57, 54, 14, 106, 5, 73, 2, 1, 11, 71, 8, 69,\n                                  18, 54, 75, 95, 106, 112, 97, 67, 73, 2, 1,\n                                  84, 89, 4, 16, 68, 79, 92, 7, 69, 84, 88, 5,\n                                  75, 90, 8, 70, 80, 88, 64, 72, 72, 78, 69, 5,\n                                  22, 0, 0, 0, 80, 87, 97, 69, 18, 1, 52, 8, 69,\n                                  121, 97, 82, 71, 100, 118, 117, 119, 89, 118,\n                                  107, 117, 117, 111, 117, 111, 4, 67, 79, 99,\n                                  69, 90, 86, 117, 73, 95, 88, 120, 9, 80, 73,\n                                  118, 90, 83, 76, 69, 2, 66, 80, 4, 1, 0, 6,\n                                  65, 64, 2, 77, 13, 9, 25, 19, 22, 18, 17, 18,\n                                  37, 12, 11, 36, 25, 66, 103, 95, 96, 86, 90,\n                                  84, 79, 82, 80, 82, 88, 70, 72, 72, 64, 99,\n                                  95, 95, 73, 72, 71, 70, 13, 64, 1, 65, 20, 67,\n                                  4, 4, 1, 75, 56, 50, 36, 41, 50, 40, 23, 42,\n                                  33, 24, 29, 17, 5, 1, 0, 22, 15, 20, 18, 15,\n                                  13, 19, 11, 20, 16, 5, 7, 12, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 57, 51,\n                                  34, 60, 52, 33, 62, 57, 60, 55, 49, 47, 50,\n                                  37, 29, 11, 18, 66, 71, 97, 70, 23, 15, 10, 2,\n                                  5, 0, 71, 73, 88, 65, 38, 25, 20, 17, 4, 65,\n                                  74, 75, 82, 88, 13, 7, 3, 0, 69, 73, 77, 85,\n                                  104, 93, 77, 75, 71, 72, 81, 91, 93, 111, 75,\n                                  32, 17, 11, 2, 66, 75, 82, 85, 92, 62, 91, 82,\n                                  76, 66, 70, 1, 4, 5, 73, 2, 7, 0, 78, 71, 68,\n                                  16, 4, 23, 19, 31, 31, 19, 21, 26, 20, 15, 65,\n                                  12, 66, 100, 93, 91, 85, 82, 82, 82, 83, 67,\n                                  76, 75, 74, 2, 75, 82, 96, 90, 95, 76, 72, 70,\n                                  71, 68, 65, 68, 1, 0, 67, 70, 5, 65, 73, 53,\n                                  43, 45, 46, 45, 48, 44, 43, 37, 36, 39, 33,\n                                  15, 18, 11, 39, 36, 34, 27, 28, 23, 9, 3, 65,\n                                  76, 80, 93, 71, 105, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 60, 58, 53, 50, 40, 21, 1, 57, 55, 27,\n                                  61, 62, 56, 50, 53, 48, 42, 48, 41, 40, 25,\n                                  27, 15, 71, 33, 23, 6, 114, 105, 108, 81, 87,\n                                  84, 1, 76, 75, 68, 65, 15, 3, 21, 70, 62, 62,\n                                  62, 62, 47, 43, 16, 64, 87, 74, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 89, 101, 92, 85, 86, 82, 69, 76,\n                                  81, 69, 66, 65, 64, 2, 7, 4, 62, 62, 62, 56,\n                                  51, 45, 33, 18, 71 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 116, 95, 13, 10, 10, 22, 53,\n                                  56, 54, 14, 104, 5, 73, 3, 1, 10, 71, 7, 70,\n                                  17, 53, 76, 96, 107, 109, 96, 67, 73, 3, 1,\n                                  83, 88, 5, 15, 67, 78, 91, 6, 69, 84, 88, 5,\n                                  74, 90, 8, 70, 79, 88, 64, 72, 72, 78, 69, 5,\n                                  22, 0, 0, 0, 79, 87, 97, 69, 18, 0, 52, 8, 69,\n                                  120, 97, 82, 71, 99, 116, 115, 118, 88, 116,\n                                  106, 115, 116, 110, 116, 110, 5, 67, 78, 99,\n                                  68, 90, 86, 115, 73, 94, 88, 119, 9, 80, 73,\n                                  116, 90, 82, 75, 69, 2, 66, 79, 4, 1, 64, 6,\n                                  65, 64, 2, 77, 13, 9, 25, 19, 21, 18, 17, 18,\n                                  35, 12, 11, 34, 24, 67, 103, 94, 96, 86, 89,\n                                  84, 78, 82, 80, 82, 86, 70, 72, 72, 65, 99,\n                                  94, 95, 73, 72, 70, 69, 12, 64, 1, 65, 19, 66,\n                                  3, 3, 1, 76, 54, 49, 35, 41, 49, 40, 23, 41,\n                                  32, 23, 28, 17, 5, 1, 0, 21, 14, 19, 17, 15,\n                                  12, 18, 11, 18, 15, 5, 6, 11, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 54, 48,\n                                  31, 58, 50, 32, 62, 54, 57, 52, 47, 44, 48,\n                                  34, 27, 10, 16, 67, 72, 97, 69, 24, 15, 11, 2,\n                                  5, 0, 71, 73, 87, 65, 38, 26, 20, 17, 5, 65,\n                                  74, 74, 82, 87, 14, 7, 4, 0, 68, 73, 77, 84,\n                                  103, 92, 76, 74, 70, 72, 81, 91, 92, 109, 75,\n                                  32, 17, 11, 3, 66, 75, 81, 85, 91, 62, 90, 81,\n                                  76, 66, 70, 1, 4, 5, 73, 3, 7, 1, 78, 71, 69,\n                                  16, 4, 22, 18, 30, 30, 19, 20, 25, 20, 15, 65,\n                                  11, 67, 99, 92, 90, 85, 82, 82, 81, 83, 67,\n                                  75, 74, 73, 2, 75, 82, 96, 89, 95, 76, 72, 70,\n                                  70, 68, 65, 67, 0, 0, 67, 70, 4, 65, 74, 52,\n                                  42, 45, 45, 44, 48, 44, 42, 36, 36, 38, 32,\n                                  14, 17, 10, 37, 35, 32, 25, 26, 21, 8, 3, 65,\n                                  76, 80, 92, 72, 104, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 58, 55, 51, 47, 38, 20, 1, 56, 54, 25,\n                                  59, 62, 54, 48, 51, 46, 40, 45, 39, 38, 23,\n                                  25, 14, 73, 31, 21, 4, 113, 104, 107, 80, 86,\n                                  83, 2, 75, 74, 68, 64, 16, 4, 22, 69, 62, 62,\n                                  62, 59, 44, 41, 13, 66, 89, 73, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 88, 100, 92, 84, 85, 81, 69, 75,\n                                  80, 69, 66, 65, 64, 3, 7, 4, 62, 62, 61, 54,\n                                  50, 44, 30, 17, 72 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 114, 93, 13, 10, 9, 20, 51,\n                                  54, 54, 14, 101, 4, 72, 3, 1, 9, 71, 6, 71,\n                                  17, 51, 78, 97, 107, 106, 95, 67, 72, 3, 1,\n                                  83, 87, 5, 15, 67, 78, 91, 6, 70, 83, 88, 5,\n                                  74, 89, 7, 70, 79, 88, 0, 71, 72, 77, 68, 5,\n                                  22, 0, 0, 0, 79, 87, 97, 68, 17, 0, 52, 8, 69,\n                                  119, 96, 82, 70, 97, 115, 113, 116, 87, 115,\n                                  104, 113, 115, 109, 115, 110, 6, 67, 77, 98,\n                                  68, 89, 85, 113, 73, 94, 87, 118, 9, 79, 72,\n                                  115, 89, 82, 75, 68, 2, 66, 78, 5, 2, 64, 5,\n                                  65, 64, 2, 77, 13, 8, 24, 19, 21, 18, 17, 17,\n                                  33, 12, 10, 32, 23, 68, 102, 93, 95, 85, 88,\n                                  83, 77, 81, 79, 81, 85, 70, 72, 71, 66, 98,\n                                  93, 95, 73, 72, 70, 69, 11, 0, 1, 65, 17, 65,\n                                  3, 2, 1, 77, 53, 48, 35, 40, 48, 39, 22, 40,\n                                  32, 22, 27, 17, 5, 1, 64, 20, 14, 18, 17, 14,\n                                  11, 17, 10, 16, 14, 4, 5, 10, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 60, 61, 52, 46,\n                                  29, 56, 49, 30, 62, 52, 55, 50, 44, 42, 45,\n                                  32, 24, 9, 15, 69, 73, 97, 69, 24, 16, 11, 2,\n                                  5, 0, 71, 73, 87, 64, 39, 26, 20, 17, 6, 64,\n                                  73, 74, 81, 86, 15, 8, 4, 0, 67, 72, 76, 84,\n                                  102, 92, 75, 74, 70, 72, 80, 90, 92, 108, 74,\n                                  33, 17, 11, 3, 65, 74, 80, 84, 90, 62, 90, 81,\n                                  75, 66, 70, 1, 4, 5, 72, 3, 7, 1, 78, 71, 69,\n                                  15, 5, 21, 17, 29, 29, 19, 19, 24, 19, 15, 66,\n                                  10, 67, 98, 92, 89, 84, 81, 81, 81, 82, 67,\n                                  75, 74, 73, 1, 75, 82, 95, 88, 95, 76, 71, 70,\n                                  70, 68, 65, 66, 0, 0, 67, 69, 4, 66, 75, 51,\n                                  42, 44, 44, 43, 47, 43, 41, 35, 35, 37, 31,\n                                  13, 16, 9, 36, 33, 31, 23, 25, 20, 7, 2, 66,\n                                  76, 80, 92, 72, 103, 62, 62, 62, 62, 62, 62,\n                                  62, 61, 56, 53, 49, 45, 36, 18, 0, 54, 52, 24,\n                                  57, 62, 52, 46, 49, 44, 38, 43, 37, 35, 21,\n                                  23, 12, 74, 29, 19, 3, 112, 103, 106, 80, 85,\n                                  82, 4, 74, 73, 68, 0, 18, 6, 24, 69, 62, 62,\n                                  61, 56, 41, 38, 10, 68, 90, 73, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 88, 99, 91, 83, 84, 80, 68, 75,\n                                  79, 68, 65, 64, 0, 3, 8, 4, 62, 62, 59, 52,\n                                  48, 42, 28, 15, 73 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 113, 92, 13, 10, 9, 19, 50,\n                                  53, 54, 14, 99, 4, 71, 4, 1, 8, 71, 5, 73, 16,\n                                  49, 80, 98, 108, 104, 94, 67, 71, 4, 1, 83,\n                                  86, 5, 14, 67, 78, 90, 5, 70, 83, 89, 5, 74,\n                                  89, 7, 71, 79, 88, 0, 71, 72, 77, 68, 5, 22,\n                                  0, 0, 0, 78, 88, 97, 68, 16, 0, 52, 8, 69,\n                                  118, 95, 82, 70, 96, 113, 111, 115, 86, 113,\n                                  103, 112, 114, 109, 114, 109, 6, 67, 76, 97,\n                                  68, 89, 85, 112, 73, 94, 87, 117, 9, 79, 72,\n                                  114, 89, 81, 75, 68, 2, 66, 78, 5, 2, 65, 5,\n                                  65, 64, 2, 77, 13, 8, 23, 19, 20, 18, 17, 17,\n                                  31, 12, 10, 30, 22, 69, 101, 92, 94, 84, 88,\n                                  83, 76, 81, 79, 80, 84, 70, 72, 71, 68, 98,\n                                  92, 95, 73, 73, 69, 69, 10, 1, 1, 65, 16, 64,\n                                  2, 1, 1, 78, 51, 47, 34, 39, 47, 38, 21, 39,\n                                  31, 20, 26, 16, 5, 1, 64, 19, 13, 17, 16, 13,\n                                  10, 16, 9, 14, 12, 3, 4, 9, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 61, 58, 58, 49, 43,\n                                  26, 54, 47, 28, 61, 50, 52, 47, 42, 39, 42,\n                                  30, 22, 8, 13, 70, 74, 98, 69, 24, 16, 11, 2,\n                                  5, 0, 71, 73, 86, 64, 39, 26, 20, 17, 7, 64,\n                                  73, 74, 81, 86, 16, 8, 4, 0, 67, 72, 76, 83,\n                                  101, 91, 74, 73, 70, 72, 79, 89, 91, 107, 74,\n                                  33, 17, 11, 3, 64, 74, 80, 83, 90, 62, 90, 81,\n                                  75, 66, 70, 1, 4, 5, 72, 3, 7, 2, 78, 71, 69,\n                                  14, 5, 20, 16, 28, 28, 19, 17, 22, 19, 15, 67,\n                                  9, 68, 98, 91, 88, 84, 81, 81, 80, 81, 68, 75,\n                                  74, 73, 0, 75, 82, 95, 88, 96, 76, 71, 70, 69,\n                                  68, 65, 66, 0, 64, 67, 68, 3, 66, 76, 50, 41,\n                                  44, 43, 41, 46, 42, 40, 34, 34, 36, 30, 12,\n                                  15, 8, 34, 32, 29, 21, 23, 19, 6, 1, 66, 76,\n                                  80, 92, 73, 103, 62, 62, 62, 62, 62, 62, 61,\n                                  58, 54, 51, 47, 42, 34, 17, 64, 52, 50, 22,\n                                  55, 61, 49, 43, 46, 41, 36, 41, 34, 33, 19,\n                                  20, 10, 75, 27, 17, 1, 111, 102, 105, 79, 84,\n                                  82, 5, 73, 73, 68, 0, 19, 7, 25, 68, 62, 62,\n                                  58, 53, 38, 35, 7, 70, 91, 73, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 87, 99, 90, 82, 84, 79, 68, 74,\n                                  79, 68, 65, 64, 0, 4, 8, 3, 62, 62, 57, 50,\n                                  46, 40, 26, 13, 74 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 111, 91, 14, 10, 9, 18, 49,\n                                  52, 54, 14, 97, 4, 70, 5, 1, 8, 70, 4, 74, 15,\n                                  47, 81, 99, 109, 101, 92, 67, 70, 5, 1, 82,\n                                  85, 6, 13, 67, 77, 89, 5, 70, 83, 89, 5, 74,\n                                  88, 7, 71, 79, 88, 0, 71, 71, 77, 68, 5, 22,\n                                  0, 0, 0, 77, 88, 97, 68, 15, 0, 52, 8, 69,\n                                  117, 94, 82, 70, 95, 111, 109, 113, 84, 111,\n                                  102, 110, 113, 108, 113, 108, 7, 66, 75, 96,\n                                  68, 88, 84, 110, 73, 93, 87, 115, 10, 79, 72,\n                                  112, 89, 80, 75, 68, 3, 65, 77, 5, 2, 65, 5,\n                                  64, 64, 2, 76, 13, 8, 23, 19, 19, 18, 17, 17,\n                                  29, 12, 10, 29, 21, 69, 100, 91, 93, 83, 87,\n                                  82, 75, 80, 79, 79, 83, 70, 72, 71, 69, 97,\n                                  91, 95, 72, 73, 68, 69, 9, 2, 1, 65, 15, 0, 1,\n                                  0, 1, 78, 50, 46, 34, 38, 46, 37, 21, 39, 31,\n                                  19, 25, 16, 5, 1, 64, 19, 12, 16, 15, 12, 9,\n                                  16, 9, 13, 11, 3, 3, 8, 89, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 59, 56, 56, 46, 41, 23,\n                                  53, 45, 27, 59, 48, 50, 45, 40, 37, 40, 28,\n                                  20, 8, 11, 71, 74, 98, 69, 25, 16, 11, 3, 5,\n                                  0, 70, 73, 85, 64, 39, 26, 21, 17, 8, 0, 72,\n                                  73, 80, 85, 17, 9, 5, 1, 66, 71, 76, 82, 100,\n                                  90, 72, 72, 69, 71, 78, 88, 90, 106, 73, 33,\n                                  18, 12, 3, 0, 73, 79, 82, 89, 62, 89, 80, 74,\n                                  66, 70, 1, 5, 6, 72, 3, 8, 3, 78, 71, 69, 14,\n                                  5, 19, 16, 27, 28, 19, 16, 21, 19, 15, 67, 8,\n                                  69, 97, 90, 87, 84, 80, 81, 79, 80, 68, 75,\n                                  74, 72, 0, 75, 82, 95, 87, 96, 76, 71, 70, 68,\n                                  68, 65, 65, 0, 64, 67, 67, 2, 66, 76, 49, 41,\n                                  44, 43, 40, 45, 41, 39, 34, 33, 35, 30, 12,\n                                  14, 7, 33, 31, 27, 19, 22, 18, 6, 1, 66, 75,\n                                  79, 92, 74, 102, 62, 62, 62, 62, 62, 62, 59,\n                                  56, 52, 49, 45, 40, 32, 16, 65, 50, 49, 21,\n                                  53, 59, 47, 41, 44, 39, 34, 39, 32, 31, 18,\n                                  18, 8, 76, 25, 15, 64, 110, 100, 103, 78, 83,\n                                  81, 7, 72, 72, 68, 1, 21, 8, 27, 67, 62, 62,\n                                  56, 50, 36, 32, 5, 72, 92, 73, 41, 29, 20, 9,\n                                  10, 2, 64, 68, 86, 98, 89, 81, 83, 77, 67, 73,\n                                  78, 67, 64, 0, 0, 5, 8, 3, 62, 61, 56, 49, 44,\n                                  38, 24, 11, 74 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 109, 89, 14, 10, 8, 16, 47,\n                                  50, 54, 14, 94, 3, 69, 5, 1, 7, 70, 3, 75, 15,\n                                  45, 83, 100, 109, 98, 91, 67, 69, 5, 1, 82,\n                                  84, 6, 13, 67, 77, 89, 5, 71, 82, 89, 5, 74,\n                                  87, 6, 71, 79, 88, 1, 70, 71, 76, 67, 5, 22,\n                                  0, 0, 0, 77, 88, 97, 67, 14, 0, 52, 8, 69,\n                                  116, 93, 82, 69, 93, 110, 107, 112, 83, 110,\n                                  100, 108, 112, 107, 112, 108, 8, 66, 74, 95,\n                                  68, 88, 83, 108, 73, 93, 86, 114, 10, 78, 71,\n                                  111, 88, 80, 75, 67, 3, 65, 76, 6, 3, 66, 4,\n                                  64, 64, 2, 76, 13, 7, 22, 19, 19, 18, 17, 16,\n                                  27, 12, 9, 27, 20, 70, 99, 90, 92, 82, 86, 81,\n                                  74, 79, 78, 78, 82, 70, 72, 70, 70, 97, 90,\n                                  95, 72, 73, 68, 69, 8, 3, 1, 65, 13, 1, 1, 64,\n                                  1, 79, 48, 45, 33, 37, 45, 36, 20, 38, 31, 18,\n                                  24, 16, 5, 1, 65, 18, 12, 15, 15, 11, 8, 15,\n                                  8, 11, 10, 2, 2, 7, 89, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 57, 54, 53, 44, 39, 21, 51,\n                                  44, 25, 56, 46, 48, 43, 37, 35, 37, 26, 17, 7,\n                                  10, 73, 75, 98, 69, 25, 17, 11, 3, 5, 0, 70,\n                                  73, 85, 0, 40, 26, 21, 17, 9, 0, 71, 73, 79,\n                                  84, 18, 10, 5, 1, 65, 71, 75, 82, 99, 90, 71,\n                                  72, 69, 71, 77, 87, 90, 105, 73, 34, 18, 12,\n                                  3, 1, 72, 78, 81, 88, 62, 89, 80, 74, 66, 70,\n                                  1, 5, 6, 71, 3, 8, 3, 78, 71, 69, 13, 6, 18,\n                                  15, 26, 27, 19, 15, 20, 18, 15, 68, 7, 69, 96,\n                                  90, 86, 83, 80, 80, 79, 79, 68, 75, 74, 72,\n                                  64, 75, 82, 94, 86, 96, 76, 70, 70, 68, 68,\n                                  65, 64, 0, 64, 67, 66, 2, 67, 77, 48, 41, 43,\n                                  42, 39, 44, 40, 38, 33, 32, 34, 29, 11, 13, 6,\n                                  31, 29, 26, 17, 21, 17, 5, 0, 67, 75, 79, 92,\n                                  74, 101, 62, 62, 62, 62, 62, 60, 57, 53, 50,\n                                  47, 43, 38, 30, 14, 66, 48, 47, 20, 51, 57,\n                                  45, 39, 42, 37, 32, 37, 30, 28, 16, 16, 6, 77,\n                                  23, 13, 65, 109, 99, 102, 78, 82, 80, 9, 71,\n                                  71, 68, 2, 22, 10, 28, 67, 62, 60, 53, 47, 33,\n                                  29, 2, 74, 93, 73, 41, 29, 20, 9, 10, 2, 64,\n                                  68, 86, 97, 88, 80, 82, 76, 66, 73, 77, 66, 0,\n                                  1, 1, 5, 9, 3, 60, 59, 54, 47, 42, 36, 22, 9,\n                                  75 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 107, 88, 15, 10, 8, 15, 46,\n                                  49, 54, 14, 92, 3, 69, 6, 1, 6, 70, 2, 76, 14,\n                                  44, 84, 101, 110, 95, 90, 67, 69, 6, 1, 81,\n                                  83, 7, 12, 66, 76, 88, 4, 71, 82, 89, 5, 73,\n                                  87, 6, 71, 78, 88, 1, 70, 71, 76, 67, 5, 22,\n                                  0, 0, 0, 76, 88, 97, 67, 14, 64, 52, 8, 69,\n                                  115, 93, 82, 69, 92, 108, 105, 110, 82, 108,\n                                  99, 106, 111, 106, 111, 107, 9, 66, 73, 95,\n                                  67, 87, 83, 106, 73, 92, 86, 113, 10, 78, 71,\n                                  109, 88, 79, 74, 67, 3, 65, 75, 6, 3, 66, 4,\n                                  64, 64, 2, 76, 13, 7, 22, 19, 18, 18, 17, 16,\n                                  25, 12, 9, 25, 19, 71, 99, 89, 92, 82, 85, 81,\n                                  73, 79, 78, 78, 80, 70, 72, 70, 71, 96, 89,\n                                  95, 72, 73, 67, 68, 7, 3, 1, 65, 12, 2, 0, 65,\n                                  1, 80, 47, 44, 33, 37, 44, 36, 20, 37, 30, 17,\n                                  23, 16, 5, 1, 65, 17, 11, 14, 14, 11, 7, 14,\n                                  8, 9, 9, 2, 1, 6, 89, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 54, 52, 51, 41, 36, 18, 49, 42,\n                                  24, 54, 43, 45, 40, 35, 32, 35, 23, 15, 6, 8,\n                                  74, 76, 98, 68, 26, 17, 12, 3, 5, 0, 70, 73,\n                                  84, 0, 40, 27, 21, 17, 10, 1, 71, 72, 79, 83,\n                                  19, 10, 6, 1, 64, 70, 75, 81, 98, 89, 70, 71,\n                                  68, 71, 77, 87, 89, 103, 72, 34, 18, 12, 4, 1,\n                                  72, 77, 81, 87, 62, 88, 79, 73, 66, 70, 1, 5,\n                                  6, 71, 4, 8, 4, 78, 71, 70, 13, 6, 17, 14, 25,\n                                  26, 19, 14, 19, 18, 15, 68, 6, 70, 95, 89, 85,\n                                  83, 79, 80, 78, 79, 68, 74, 73, 71, 64, 75,\n                                  82, 94, 85, 96, 76, 70, 70, 67, 68, 65, 0, 64,\n                                  64, 67, 66, 1, 67, 78, 47, 40, 43, 41, 38, 44,\n                                  40, 37, 32, 32, 33, 28, 10, 12, 5, 30, 28, 24,\n                                  15, 19, 15, 4, 0, 67, 75, 79, 91, 75, 100, 62,\n                                  62, 62, 62, 62, 58, 55, 51, 48, 44, 41, 35,\n                                  28, 13, 66, 47, 46, 18, 49, 54, 43, 37, 40,\n                                  35, 30, 34, 28, 26, 14, 14, 5, 79, 21, 11, 67,\n                                  108, 98, 101, 77, 81, 79, 10, 70, 70, 68, 3,\n                                  24, 11, 30, 66, 61, 59, 51, 44, 30, 27, 64,\n                                  76, 95, 72, 41, 29, 20, 9, 10, 2, 64, 68, 85,\n                                  96, 88, 79, 81, 75, 66, 72, 76, 66, 0, 1, 1,\n                                  6, 9, 3, 59, 58, 52, 45, 41, 35, 19, 8, 76 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 106, 86, 15, 10, 7, 13, 44,\n                                  48, 54, 14, 90, 3, 68, 7, 1, 5, 70, 1, 77, 14,\n                                  42, 86, 102, 110, 92, 89, 67, 68, 7, 1, 81,\n                                  82, 7, 12, 66, 76, 87, 4, 72, 82, 89, 5, 73,\n                                  86, 6, 72, 78, 88, 2, 70, 71, 76, 66, 5, 22,\n                                  0, 0, 0, 76, 89, 97, 66, 13, 64, 52, 8, 69,\n                                  114, 92, 82, 68, 91, 106, 103, 109, 81, 106,\n                                  98, 104, 110, 106, 110, 106, 9, 66, 72, 94,\n                                  67, 87, 82, 104, 73, 92, 85, 112, 10, 78, 70,\n                                  108, 87, 78, 74, 67, 3, 65, 75, 7, 4, 67, 4,\n                                  64, 64, 2, 76, 13, 6, 21, 19, 17, 18, 17, 16,\n                                  23, 12, 8, 23, 18, 72, 98, 88, 91, 81, 85, 80,\n                                  72, 78, 77, 77, 79, 70, 72, 70, 72, 96, 88,\n                                  95, 72, 73, 66, 68, 6, 4, 1, 65, 11, 3, 0, 66,\n                                  1, 81, 45, 43, 32, 36, 43, 35, 19, 36, 30, 15,\n                                  22, 15, 5, 1, 66, 16, 10, 13, 13, 10, 6, 13,\n                                  7, 7, 8, 1, 0, 5, 89, 62, 62, 61, 62, 62, 62,\n                                  62, 62, 61, 52, 50, 48, 39, 34, 16, 47, 40,\n                                  22, 52, 41, 43, 38, 33, 30, 32, 21, 12, 5, 6,\n                                  75, 77, 98, 68, 26, 17, 12, 3, 5, 0, 70, 73,\n                                  84, 0, 40, 27, 21, 17, 11, 1, 70, 72, 78, 83,\n                                  20, 11, 6, 1, 64, 70, 74, 81, 97, 88, 69, 70,\n                                  68, 71, 76, 86, 88, 102, 72, 34, 18, 12, 4, 2,\n                                  71, 77, 80, 86, 62, 88, 79, 73, 66, 70, 1, 5,\n                                  6, 71, 4, 8, 4, 78, 71, 70, 12, 7, 16, 13, 24,\n                                  25, 19, 12, 18, 18, 15, 69, 5, 70, 95, 88, 84,\n                                  82, 79, 79, 78, 78, 69, 74, 73, 71, 65, 75,\n                                  82, 93, 84, 96, 76, 70, 70, 66, 68, 65, 1, 64,\n                                  65, 67, 65, 0, 67, 79, 46, 40, 42, 40, 37, 43,\n                                  39, 36, 31, 31, 32, 27, 9, 11, 4, 28, 27, 23,\n                                  13, 18, 14, 3, 64, 68, 75, 79, 91, 75, 100,\n                                  62, 62, 62, 62, 62, 56, 53, 48, 46, 42, 39,\n                                  33, 26, 11, 67, 45, 44, 17, 47, 52, 41, 35,\n                                  37, 33, 28, 32, 26, 23, 12, 12, 3, 80, 19, 9,\n                                  68, 107, 97, 100, 76, 80, 78, 12, 69, 69, 68,\n                                  4, 25, 13, 31, 65, 59, 57, 48, 41, 27, 24, 67,\n                                  78, 96, 72, 41, 29, 20, 9, 10, 2, 64, 68, 85,\n                                  95, 87, 78, 81, 74, 65, 72, 75, 65, 1, 2, 1,\n                                  6, 9, 3, 58, 56, 50, 43, 39, 33, 17, 6, 77 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 104, 85, 15, 10, 7, 12, 43,\n                                  46, 54, 14, 87, 2, 67, 7, 1, 5, 69, 0, 78, 13,\n                                  40, 88, 103, 111, 89, 87, 67, 67, 7, 1, 81,\n                                  81, 7, 11, 66, 76, 87, 4, 72, 81, 89, 5, 73,\n                                  85, 5, 72, 78, 88, 2, 69, 70, 75, 66, 5, 22,\n                                  0, 0, 0, 75, 89, 97, 66, 12, 64, 52, 8, 69,\n                                  113, 91, 82, 68, 89, 105, 101, 107, 80, 105,\n                                  96, 102, 109, 105, 109, 106, 10, 66, 71, 93,\n                                  67, 86, 81, 102, 73, 92, 85, 110, 11, 77, 70,\n                                  107, 87, 78, 74, 66, 4, 64, 74, 7, 4, 67, 3,\n                                  64, 64, 2, 76, 13, 6, 20, 19, 17, 18, 17, 15,\n                                  21, 12, 8, 22, 17, 73, 97, 87, 90, 80, 84, 79,\n                                  71, 77, 77, 76, 78, 70, 72, 69, 73, 95, 87,\n                                  95, 71, 73, 66, 68, 5, 5, 1, 65, 9, 4, 64, 67,\n                                  1, 81, 44, 42, 32, 35, 42, 34, 18, 36, 30, 14,\n                                  21, 15, 5, 1, 66, 16, 10, 12, 13, 9, 5, 13, 6,\n                                  5, 7, 0, 64, 4, 89, 61, 62, 59, 62, 61, 60,\n                                  60, 60, 59, 50, 48, 46, 36, 32, 13, 45, 39,\n                                  20, 49, 39, 41, 36, 30, 28, 29, 19, 10, 4, 5,\n                                  77, 77, 98, 68, 26, 18, 12, 3, 5, 0, 70, 73,\n                                  83, 1, 41, 27, 21, 17, 12, 2, 69, 72, 77, 82,\n                                  21, 12, 6, 2, 0, 69, 74, 80, 96, 88, 67, 70,\n                                  68, 70, 75, 85, 88, 101, 71, 35, 19, 12, 4, 3,\n                                  70, 76, 79, 85, 62, 88, 79, 72, 66, 70, 1, 5,\n                                  6, 70, 4, 9, 5, 78, 71, 70, 11, 7, 15, 12, 23,\n                                  25, 19, 11, 17, 17, 15, 70, 4, 71, 94, 88, 83,\n                                  82, 78, 79, 77, 77, 69, 74, 73, 71, 66, 75,\n                                  82, 93, 83, 96, 76, 69, 70, 66, 68, 65, 2, 64,\n                                  65, 67, 64, 0, 68, 79, 45, 40, 42, 40, 36, 42,\n                                  38, 35, 31, 30, 31, 26, 8, 10, 3, 27, 25, 21,\n                                  11, 17, 13, 2, 65, 68, 75, 78, 91, 76, 99, 62,\n                                  62, 62, 62, 60, 54, 51, 46, 44, 40, 37, 31,\n                                  24, 10, 68, 43, 42, 16, 45, 50, 39, 33, 35,\n                                  31, 26, 30, 24, 21, 10, 10, 1, 81, 17, 7, 70,\n                                  106, 95, 99, 76, 79, 77, 14, 68, 68, 68, 5,\n                                  27, 14, 33, 65, 58, 55, 46, 38, 25, 21, 69,\n                                  80, 97, 72, 41, 29, 20, 9, 10, 2, 64, 68, 84,\n                                  94, 86, 77, 80, 73, 64, 71, 74, 64, 2, 3, 2,\n                                  7, 10, 3, 56, 55, 49, 42, 37, 31, 15, 4, 78 },\n\n                                {\n\n                                61,\n                                  8, 76, 61, 8, 76, 102, 83, 16, 10, 6, 10, 41,\n                                  45, 54, 14, 85, 2, 66, 8, 1, 4, 69, 64, 79,\n                                  13, 38, 89, 104, 111, 86, 86, 67, 66, 8, 1,\n                                  80, 80, 8, 11, 66, 75, 86, 3, 73, 81, 89, 5,\n                                  73, 85, 5, 72, 78, 88, 3, 69, 70, 75, 65, 5,\n                                  22, 0, 0, 0, 75, 89, 97, 65, 11, 64, 52, 8,\n                                  69, 112, 90, 82, 67, 88, 103, 99, 106, 79,\n                                  103, 95, 100, 108, 104, 108, 105, 11, 66, 70,\n                                  92, 67, 86, 81, 100, 73, 91, 84, 109, 11, 77,\n                                  69, 105, 86, 77, 74, 66, 4, 64, 73, 8, 5, 68,\n                                  3, 64, 64, 2, 76, 13, 5, 20, 19, 16, 18, 17,\n                                  15, 19, 12, 7, 20, 16, 74, 96, 86, 89, 79, 83,\n                                  79, 70, 77, 76, 75, 77, 70, 72, 69, 74, 95,\n                                  86, 95, 71, 73, 65, 68, 4, 6, 1, 65, 8, 5, 64,\n                                  68, 1, 82, 42, 41, 31, 34, 41, 33, 18, 35, 29,\n                                  13, 20, 15, 5, 1, 67, 15, 9, 11, 12, 8, 4, 12,\n                                  6, 3, 6, 0, 65, 3, 89, 60, 61, 58, 62, 59, 58,\n                                  58, 58, 56, 47, 46, 43, 34, 29, 11, 43, 37,\n                                  19, 47, 37, 38, 33, 28, 25, 27, 17, 7, 3, 3,\n                                  78, 78, 98, 68, 27, 18, 12, 3, 5, 0, 70, 73,\n                                  83, 1, 41, 27, 21, 17, 13, 2, 69, 71, 77, 81,\n                                  22, 12, 7, 2, 1, 69, 73, 80, 95, 87, 66, 69,\n                                  67, 70, 74, 84, 87, 100, 71, 35, 19, 12, 4, 4,\n                                  70, 75, 78, 84, 62, 87, 78, 72, 66, 70, 1, 5,\n                                  6, 70, 4, 9, 5, 78, 71, 70, 11, 8, 14, 11, 22,\n                                  24, 19, 10, 16, 17, 15, 70, 3, 71, 93, 87, 82,\n                                  81, 78, 78, 77, 76, 69, 74, 73, 70, 66, 75,\n                                  82, 92, 82, 96, 76, 69, 70, 65, 68, 65, 3, 64,\n                                  65, 67, 0, 64, 68, 80, 44, 39, 41, 39, 35, 41,\n                                  37, 34, 30, 29, 30, 25, 7, 9, 2, 25, 24, 20,\n                                  9, 15, 12, 1, 65, 69, 75, 78, 91, 76, 98, 62,\n                                  62, 61, 61, 57, 52, 49, 43, 42, 38, 35, 28,\n                                  22, 8, 69, 41, 41, 14, 43, 48, 37, 31, 33, 29,\n                                  24, 28, 22, 18, 8, 8, 64, 82, 15, 5, 71, 105,\n                                  94, 98, 75, 78, 76, 15, 67, 67, 68, 6, 28, 16,\n                                  34, 64, 56, 54, 43, 35, 22, 18, 72, 82, 98,\n                                  72, 41, 29, 20, 9, 10, 2, 64, 68, 84, 93, 85,\n                                  76, 79, 72, 64, 71, 73, 64, 2, 3, 2, 7, 10, 3,\n                                  55, 53, 47, 40, 35, 29, 13, 2, 79 },\n\n                                {\n\n                                60,\n                                  8, 76, 60, 8, 76, 100, 82, 16, 10, 6, 9, 40,\n                                  44, 54, 14, 83, 2, 65, 9, 1, 3, 69, 65, 80,\n                                  12, 36, 91, 105, 112, 83, 85, 67, 65, 9, 1,\n                                  80, 79, 8, 10, 66, 75, 85, 3, 73, 81, 89, 5,\n                                  73, 84, 5, 72, 78, 88, 3, 69, 70, 75, 65, 5,\n                                  22, 0, 0, 0, 74, 89, 97, 65, 10, 64, 52, 8,\n                                  69, 111, 89, 82, 67, 87, 101, 97, 104, 78,\n                                  101, 94, 98, 107, 103, 107, 104, 12, 66, 69,\n                                  91, 67, 85, 80, 98, 73, 91, 84, 108, 11, 77,\n                                  69, 104, 86, 76, 74, 66, 4, 64, 72, 8, 5, 68,\n                                  3, 64, 64, 2, 76, 13, 5, 19, 19, 15, 18, 17,\n                                  15, 17, 12, 7, 18, 15, 75, 95, 85, 88, 78, 82,\n                                  78, 69, 76, 76, 74, 76, 70, 72, 69, 75, 94,\n                                  85, 95, 71, 73, 64, 68, 3, 7, 1, 65, 7, 6, 65,\n                                  69, 1, 83, 41, 40, 31, 33, 40, 32, 17, 34, 29,\n                                  12, 19, 15, 5, 1, 67, 14, 8, 10, 11, 7, 3, 11,\n                                  5, 1, 5, 64, 66, 2, 89, 58, 60, 56, 60, 57,\n                                  56, 56, 56, 54, 45, 44, 41, 31, 27, 8, 41, 35,\n                                  17, 45, 35, 36, 31, 26, 23, 24, 15, 5, 2, 1,\n                                  79, 79, 98, 68, 27, 18, 12, 3, 5, 0, 70, 73,\n                                  82, 1, 41, 27, 21, 17, 14, 3, 68, 71, 76, 80,\n                                  23, 13, 7, 2, 2, 68, 73, 79, 94, 86, 65, 68,\n                                  67, 70, 73, 83, 86, 99, 70, 35, 19, 12, 4, 5,\n                                  69, 74, 77, 83, 62, 87, 78, 71, 66, 70, 1, 5,\n                                  6, 70, 4, 9, 6, 78, 71, 70, 10, 8, 13, 10, 21,\n                                  23, 19, 9, 15, 17, 15, 71, 2, 72, 92, 86, 81,\n                                  81, 77, 78, 76, 75, 69, 74, 73, 70, 67, 75,\n                                  82, 92, 81, 96, 76, 69, 70, 64, 68, 65, 4, 64,\n                                  65, 67, 1, 65, 68, 81, 43, 39, 41, 38, 34, 40,\n                                  36, 33, 29, 28, 29, 24, 6, 8, 1, 24, 23, 18,\n                                  7, 14, 11, 0, 66, 69, 75, 78, 91, 77, 97, 62,\n                                  62, 59, 59, 54, 50, 47, 41, 40, 36, 33, 26,\n                                  20, 7, 70, 39, 39, 13, 41, 46, 35, 29, 31, 27,\n                                  22, 26, 20, 16, 6, 6, 66, 83, 13, 3, 73, 104,\n                                  93, 97, 74, 77, 75, 17, 66, 66, 68, 7, 30, 17,\n                                  36, 0, 55, 52, 41, 32, 19, 15, 75, 84, 99, 72,\n                                  41, 29, 20, 9, 10, 2, 64, 68, 83, 92, 84, 75,\n                                  78, 71, 0, 70, 72, 0, 3, 4, 2, 8, 10, 3, 54,\n                                  52, 45, 38, 33, 27, 11, 0, 80 },\n\n                                {\n\n                                58,\n                                  7, 77, 58, 7, 77, 99, 81, 16, 10, 5, 7, 38,\n                                  42, 53, 14, 81, 1, 65, 9, 0, 2, 69, 67, 82,\n                                  11, 34, 93, 106, 113, 81, 84, 68, 65, 9, 0,\n                                  80, 78, 8, 9, 66, 75, 85, 2, 74, 81, 90, 5,\n                                  73, 84, 4, 73, 78, 88, 3, 69, 70, 75, 65, 4,\n                                  22, 0, 0, 0, 74, 90, 97, 65, 9, 65, 52, 7, 69,\n                                  110, 89, 82, 67, 86, 100, 96, 103, 77, 100,\n                                  93, 97, 106, 103, 106, 104, 12, 66, 69, 91,\n                                  67, 85, 80, 97, 73, 91, 84, 107, 11, 77, 69,\n                                  103, 86, 76, 74, 66, 4, 64, 72, 8, 5, 69, 2,\n                                  64, 65, 2, 76, 12, 4, 18, 19, 14, 17, 17, 14,\n                                  15, 11, 6, 16, 14, 76, 95, 85, 88, 78, 82, 78,\n                                  68, 76, 76, 74, 75, 71, 72, 69, 77, 94, 85,\n                                  95, 71, 74, 64, 68, 2, 7, 1, 65, 5, 6, 66, 70,\n                                  1, 84, 39, 39, 30, 32, 39, 31, 16, 33, 28, 10,\n                                  18, 14, 4, 1, 68, 13, 7, 9, 10, 6, 2, 10, 4,\n                                  64, 3, 65, 68, 0, 89, 56, 58, 54, 58, 55, 53,\n                                  53, 53, 51, 42, 41, 38, 28, 24, 5, 39, 33, 15,\n                                  42, 32, 33, 28, 23, 20, 21, 12, 2, 1, 64, 81,\n                                  80, 99, 68, 27, 18, 12, 3, 5, 64, 70, 73, 82,\n                                  1, 41, 27, 21, 17, 15, 3, 68, 71, 76, 80, 23,\n                                  13, 7, 2, 2, 68, 73, 79, 93, 86, 64, 68, 67,\n                                  70, 73, 83, 86, 98, 70, 35, 19, 12, 4, 5, 69,\n                                  74, 77, 83, 62, 87, 78, 71, 66, 70, 1, 5, 6,\n                                  70, 4, 9, 6, 78, 71, 71, 9, 8, 12, 9, 20, 22,\n                                  18, 7, 13, 16, 14, 72, 0, 73, 92, 86, 80, 81,\n                                  77, 78, 76, 75, 70, 74, 73, 70, 68, 75, 82,\n                                  92, 81, 97, 76, 69, 70, 64, 69, 65, 4, 65, 66,\n                                  67, 1, 66, 69, 82, 42, 38, 40, 37, 32, 39, 35,\n                                  32, 28, 27, 28, 23, 5, 6, 64, 22, 21, 16, 5,\n                                  12, 9, 64, 67, 70, 75, 78, 91, 78, 97, 62, 61,\n                                  57, 56, 51, 47, 44, 38, 37, 33, 30, 23, 17, 5,\n                                  71, 37, 37, 11, 39, 43, 32, 26, 28, 24, 20,\n                                  23, 17, 13, 4, 3, 68, 85, 11, 1, 75, 103, 92,\n                                  96, 74, 77, 75, 18, 66, 66, 68, 7, 31, 18, 37,\n                                  0, 53, 50, 38, 28, 16, 12, 78, 87, 101, 72,\n                                  41, 28, 19, 9, 10, 2, 65, 68, 83, 92, 84, 75,\n                                  78, 70, 0, 70, 72, 0, 3, 4, 2, 8, 10, 2, 52,\n                                  50, 43, 36, 31, 25, 8, 65, 81 },\n\n                                {\n\n                                57,\n                                  7, 77, 57, 7, 77, 97, 79, 17, 11, 5, 6, 37,\n                                  41, 53, 14, 78, 1, 64, 10, 0, 2, 68, 68, 83,\n                                  11, 33, 94, 107, 113, 78, 82, 68, 64, 10, 0,\n                                  79, 76, 9, 9, 65, 74, 84, 2, 74, 80, 90, 5,\n                                  72, 83, 4, 73, 77, 88, 4, 68, 69, 74, 64, 4,\n                                  22, 0, 0, 0, 73, 90, 97, 64, 9, 65, 52, 7, 69,\n                                  108, 88, 82, 66, 84, 98, 94, 101, 75, 98, 91,\n                                  95, 104, 102, 105, 103, 13, 65, 68, 90, 66,\n                                  84, 79, 95, 72, 90, 83, 105, 12, 76, 68, 101,\n                                  85, 75, 73, 65, 5, 0, 71, 9, 6, 69, 2, 0, 65,\n                                  2, 75, 12, 4, 18, 19, 14, 17, 17, 14, 14, 11,\n                                  6, 15, 13, 76, 94, 84, 87, 77, 81, 77, 67, 75,\n                                  75, 73, 73, 71, 72, 68, 78, 93, 84, 95, 70,\n                                  74, 0, 67, 2, 8, 1, 65, 4, 7, 66, 71, 1, 84,\n                                  38, 39, 30, 32, 39, 31, 16, 33, 28, 9, 18, 14,\n                                  4, 1, 68, 13, 7, 9, 10, 6, 1, 10, 4, 65, 2,\n                                  65, 69, 64, 89, 55, 57, 53, 57, 54, 51, 51,\n                                  51, 49, 40, 39, 36, 26, 22, 3, 38, 32, 14, 40,\n                                  30, 31, 26, 21, 18, 19, 10, 0, 1, 65, 82, 80,\n                                  99, 67, 28, 19, 13, 4, 5, 64, 69, 72, 81, 2,\n                                  42, 28, 22, 17, 16, 4, 67, 70, 75, 79, 24, 14,\n                                  8, 3, 3, 67, 72, 78, 91, 85, 1, 67, 66, 69,\n                                  72, 82, 85, 96, 69, 36, 20, 13, 5, 6, 68, 73,\n                                  76, 82, 62, 86, 77, 70, 66, 69, 1, 6, 7, 69,\n                                  5, 10, 7, 77, 71, 71, 9, 9, 12, 9, 19, 22, 18,\n                                  6, 12, 16, 14, 72, 64, 73, 91, 85, 79, 80, 76,\n                                  77, 75, 74, 70, 73, 72, 69, 68, 74, 81, 91,\n                                  80, 97, 76, 68, 70, 0, 69, 65, 5, 65, 66, 66,\n                                  2, 66, 69, 82, 42, 38, 40, 37, 31, 39, 35, 32,\n                                  28, 27, 28, 23, 5, 5, 65, 21, 20, 15, 4, 11,\n                                  8, 64, 67, 70, 74, 77, 90, 78, 96, 60, 59, 55,\n                                  54, 49, 45, 42, 36, 35, 31, 28, 21, 15, 4, 71,\n                                  36, 36, 10, 38, 41, 30, 24, 26, 22, 18, 21,\n                                  15, 11, 3, 1, 69, 86, 10, 0, 76, 101, 90, 94,\n                                  73, 76, 74, 20, 65, 65, 68, 8, 33, 20, 39, 1,\n                                  52, 49, 36, 25, 14, 10, 80, 89, 102, 71, 42,\n                                  28, 19, 9, 11, 2, 65, 68, 82, 91, 83, 74, 77,\n                                  68, 1, 69, 71, 1, 4, 5, 3, 9, 11, 2, 51, 49,\n                                  42, 35, 30, 24, 6, 66, 81 },\n\n                                {\n\n                                56,\n                                  7, 77, 56, 7, 77, 95, 78, 17, 11, 5, 5, 36,\n                                  40, 53, 14, 76, 1, 0, 11, 0, 1, 68, 69, 84,\n                                  10, 31, 96, 108, 114, 75, 81, 68, 0, 11, 0,\n                                  79, 75, 9, 8, 65, 74, 83, 2, 74, 80, 90, 5,\n                                  72, 82, 4, 73, 77, 88, 4, 68, 69, 74, 64, 4,\n                                  22, 0, 0, 0, 72, 90, 97, 64, 8, 65, 52, 7, 69,\n                                  107, 87, 82, 66, 83, 96, 92, 100, 74, 96, 90,\n                                  93, 103, 101, 104, 102, 14, 65, 67, 89, 66,\n                                  84, 78, 93, 72, 90, 83, 104, 12, 76, 68, 100,\n                                  85, 74, 73, 65, 5, 0, 70, 9, 6, 70, 2, 0, 65,\n                                  2, 75, 12, 4, 17, 19, 13, 17, 17, 14, 12, 11,\n                                  6, 13, 12, 77, 93, 83, 86, 76, 80, 76, 66, 74,\n                                  75, 72, 72, 71, 72, 68, 79, 93, 83, 95, 70,\n                                  74, 1, 67, 1, 9, 1, 65, 3, 8, 67, 72, 1, 85,\n                                  36, 38, 29, 31, 38, 30, 15, 32, 28, 8, 17, 14,\n                                  4, 1, 68, 12, 6, 8, 9, 5, 0, 9, 3, 67, 1, 66,\n                                  70, 65, 89, 53, 56, 51, 55, 52, 49, 49, 49,\n                                  46, 38, 37, 33, 23, 20, 0, 36, 30, 12, 38, 28,\n                                  29, 24, 19, 16, 16, 8, 65, 0, 67, 83, 81, 99,\n                                  67, 28, 19, 13, 4, 5, 64, 69, 72, 80, 2, 42,\n                                  28, 22, 17, 17, 4, 66, 70, 74, 78, 25, 15, 8,\n                                  3, 4, 67, 72, 77, 90, 84, 2, 66, 66, 69, 71,\n                                  81, 84, 95, 69, 36, 20, 13, 5, 7, 67, 72, 75,\n                                  81, 62, 86, 77, 70, 66, 69, 1, 6, 7, 69, 5,\n                                  10, 8, 77, 71, 71, 8, 9, 11, 8, 18, 21, 18, 5,\n                                  11, 16, 14, 73, 65, 74, 90, 84, 78, 80, 76,\n                                  77, 74, 73, 70, 73, 72, 69, 69, 74, 81, 91,\n                                  79, 97, 76, 68, 70, 1, 69, 65, 6, 65, 66, 66,\n                                  3, 67, 69, 83, 41, 38, 40, 36, 30, 38, 34, 31,\n                                  27, 26, 27, 22, 4, 4, 66, 19, 19, 13, 2, 10,\n                                  7, 65, 68, 70, 74, 77, 90, 79, 95, 58, 57, 53,\n                                  52, 46, 43, 40, 33, 33, 29, 26, 19, 13, 3, 72,\n                                  34, 34, 9, 36, 39, 28, 22, 24, 20, 16, 19, 13,\n                                  9, 1, 64, 71, 87, 8, 65, 78, 100, 89, 93, 72,\n                                  75, 73, 22, 64, 64, 68, 9, 34, 21, 40, 2, 51,\n                                  47, 33, 22, 11, 7, 83, 91, 103, 71, 42, 28,\n                                  19, 9, 11, 2, 65, 68, 81, 90, 82, 73, 76, 67,\n                                  2, 68, 70, 2, 5, 6, 3, 10, 11, 2, 50, 47, 40,\n                                  33, 28, 22, 4, 68, 82 },\n\n                                {\n\n                                55,\n                                  7, 77, 55, 7, 77, 93, 76, 18, 11, 4, 3, 34,\n                                  39, 53, 14, 74, 1, 1, 12, 0, 0, 68, 70, 85,\n                                  10, 29, 97, 109, 114, 72, 80, 68, 1, 12, 0,\n                                  78, 74, 10, 8, 65, 73, 82, 1, 75, 80, 90, 5,\n                                  72, 82, 4, 73, 77, 88, 5, 68, 69, 74, 0, 4,\n                                  22, 0, 0, 0, 72, 90, 97, 0, 7, 65, 52, 7, 69,\n                                  106, 86, 82, 65, 82, 94, 90, 98, 73, 94, 89,\n                                  91, 102, 100, 103, 101, 15, 65, 66, 88, 66,\n                                  83, 78, 91, 72, 89, 82, 103, 12, 76, 67, 98,\n                                  84, 73, 73, 65, 5, 0, 69, 10, 7, 70, 2, 0, 65,\n                                  2, 75, 12, 3, 17, 19, 12, 17, 17, 14, 10, 11,\n                                  5, 11, 11, 78, 92, 82, 85, 75, 79, 76, 65, 74,\n                                  74, 71, 71, 71, 72, 68, 80, 92, 82, 95, 70,\n                                  74, 2, 67, 0, 10, 1, 65, 2, 9, 67, 73, 1, 86,\n                                  35, 37, 29, 30, 37, 29, 15, 31, 27, 7, 16, 14,\n                                  4, 1, 69, 11, 5, 7, 8, 4, 64, 8, 3, 69, 0, 66,\n                                  71, 66, 89, 52, 54, 50, 53, 50, 47, 47, 47,\n                                  44, 35, 35, 31, 21, 17, 65, 34, 28, 11, 36,\n                                  26, 26, 21, 17, 13, 14, 6, 68, 64, 69, 84, 82,\n                                  99, 67, 29, 19, 13, 4, 5, 64, 69, 72, 80, 2,\n                                  42, 28, 22, 17, 18, 5, 66, 69, 74, 77, 26, 15,\n                                  9, 3, 5, 66, 71, 77, 89, 83, 3, 65, 65, 69,\n                                  70, 80, 83, 94, 68, 36, 20, 13, 5, 8, 67, 71,\n                                  74, 80, 62, 85, 76, 69, 66, 69, 1, 6, 7, 69,\n                                  5, 10, 8, 77, 71, 71, 8, 10, 10, 7, 17, 20,\n                                  18, 4, 10, 16, 14, 73, 66, 74, 89, 83, 77, 79,\n                                  75, 76, 74, 72, 70, 73, 72, 68, 69, 74, 81,\n                                  90, 78, 97, 76, 68, 70, 2, 69, 65, 7, 65, 66,\n                                  66, 4, 68, 69, 84, 40, 37, 39, 35, 29, 37, 33,\n                                  30, 26, 25, 26, 21, 3, 3, 67, 18, 18, 12, 0,\n                                  8, 6, 66, 68, 71, 74, 77, 90, 79, 94, 56, 55,\n                                  51, 50, 43, 41, 38, 31, 31, 27, 24, 16, 11, 1,\n                                  73, 32, 33, 7, 34, 37, 26, 20, 22, 18, 14, 17,\n                                  11, 6, 64, 66, 73, 88, 6, 67, 79, 99, 88, 92,\n                                  71, 74, 72, 23, 0, 0, 68, 10, 36, 23, 42, 3,\n                                  49, 46, 31, 19, 8, 4, 86, 93, 104, 71, 42, 28,\n                                  19, 9, 11, 2, 65, 68, 81, 89, 81, 72, 75, 66,\n                                  2, 68, 69, 2, 5, 6, 3, 10, 11, 2, 49, 46, 38,\n                                  31, 26, 20, 2, 70, 83 },\n\n                                {\n\n                                53,\n                                  7, 77, 53, 7, 77, 92, 75, 18, 11, 4, 2, 33,\n                                  37, 53, 14, 71, 0, 2, 12, 0, 64, 68, 71, 86,\n                                  9, 27, 99, 110, 115, 69, 79, 68, 2, 12, 0, 78,\n                                  73, 10, 7, 65, 73, 82, 1, 75, 79, 90, 5, 72,\n                                  81, 3, 74, 77, 88, 5, 67, 69, 73, 0, 4, 22, 0,\n                                  0, 0, 71, 91, 97, 0, 6, 65, 52, 7, 69, 105,\n                                  85, 82, 65, 80, 93, 88, 97, 72, 93, 87, 89,\n                                  101, 100, 102, 101, 15, 65, 65, 87, 66, 83,\n                                  77, 89, 72, 89, 82, 102, 12, 75, 67, 97, 84,\n                                  73, 73, 64, 5, 0, 69, 10, 7, 71, 1, 0, 65, 2,\n                                  75, 12, 3, 16, 19, 12, 17, 17, 13, 8, 11, 5,\n                                  9, 10, 79, 91, 81, 84, 74, 79, 75, 64, 73, 74,\n                                  70, 70, 71, 72, 67, 81, 92, 81, 95, 70, 74, 2,\n                                  67, 64, 11, 1, 65, 0, 10, 68, 74, 1, 87, 33,\n                                  36, 28, 29, 36, 28, 14, 30, 27, 5, 15, 13, 4,\n                                  1, 69, 10, 5, 6, 8, 3, 65, 7, 2, 71, 64, 67,\n                                  72, 67, 89, 50, 53, 48, 51, 48, 45, 44, 45,\n                                  41, 33, 33, 28, 18, 15, 68, 32, 27, 9, 33, 24,\n                                  24, 19, 14, 11, 11, 4, 70, 65, 70, 86, 83, 99,\n                                  67, 29, 20, 13, 4, 5, 64, 69, 72, 79, 3, 43,\n                                  28, 22, 17, 19, 5, 65, 69, 73, 77, 27, 16, 9,\n                                  3, 5, 66, 71, 76, 88, 83, 4, 65, 65, 69, 69,\n                                  79, 83, 93, 68, 37, 20, 13, 5, 9, 66, 71, 73,\n                                  79, 62, 85, 76, 69, 66, 69, 1, 6, 7, 68, 5,\n                                  10, 9, 77, 71, 71, 7, 10, 9, 6, 16, 19, 18, 2,\n                                  9, 15, 14, 74, 67, 75, 89, 83, 76, 79, 75, 76,\n                                  73, 71, 71, 73, 72, 68, 70, 74, 81, 90, 77,\n                                  97, 76, 67, 70, 2, 69, 65, 8, 65, 67, 66, 5,\n                                  68, 70, 85, 39, 37, 39, 34, 28, 36, 32, 29,\n                                  25, 24, 25, 20, 2, 2, 68, 16, 16, 10, 65, 7,\n                                  5, 67, 69, 71, 74, 77, 90, 80, 94, 53, 52, 49,\n                                  47, 40, 39, 36, 28, 29, 25, 22, 14, 9, 0, 74,\n                                  30, 31, 6, 32, 35, 24, 18, 19, 16, 12, 15, 9,\n                                  4, 66, 68, 75, 89, 4, 69, 81, 98, 87, 91, 71,\n                                  73, 71, 25, 1, 1, 68, 11, 37, 24, 43, 3, 48,\n                                  44, 28, 16, 5, 1, 89, 95, 105, 71, 42, 28, 19,\n                                  9, 11, 2, 65, 68, 80, 88, 80, 71, 75, 65, 3,\n                                  67, 68, 3, 6, 7, 4, 11, 12, 2, 47, 44, 36, 29,\n                                  24, 18, 0, 72, 84 },\n\n                                {\n\n                                52,\n                                  7, 77, 52, 7, 77, 90, 73, 18, 11, 3, 0, 31,\n                                  36, 53, 14, 69, 0, 3, 13, 0, 64, 67, 72, 87,\n                                  9, 25, 101, 111, 115, 66, 77, 68, 3, 13, 0,\n                                  78, 72, 10, 7, 65, 73, 81, 1, 76, 79, 90, 5,\n                                  72, 80, 3, 74, 77, 88, 6, 67, 68, 73, 1, 4,\n                                  22, 0, 0, 0, 71, 91, 97, 1, 5, 65, 52, 7, 69,\n                                  104, 84, 82, 64, 79, 91, 86, 95, 71, 91, 86,\n                                  87, 100, 99, 101, 100, 16, 65, 64, 86, 66, 82,\n                                  76, 87, 72, 89, 81, 100, 13, 75, 66, 96, 83,\n                                  72, 73, 64, 6, 1, 68, 11, 8, 71, 1, 0, 65, 2,\n                                  75, 12, 2, 15, 19, 11, 17, 17, 13, 6, 11, 4,\n                                  8, 9, 80, 90, 80, 83, 73, 78, 74, 0, 72, 73,\n                                  69, 69, 71, 72, 67, 82, 91, 80, 95, 69, 74, 3,\n                                  67, 65, 12, 1, 65, 64, 11, 68, 75, 1, 87, 32,\n                                  35, 28, 28, 35, 27, 13, 30, 27, 4, 14, 13, 4,\n                                  1, 70, 10, 4, 5, 7, 2, 66, 7, 1, 73, 65, 68,\n                                  73, 68, 89, 48, 52, 46, 49, 47, 43, 42, 43,\n                                  39, 31, 31, 26, 16, 13, 70, 30, 25, 7, 31, 22,\n                                  22, 17, 12, 9, 8, 2, 73, 66, 72, 87, 83, 99,\n                                  67, 29, 20, 13, 4, 5, 64, 69, 72, 79, 3, 43,\n                                  28, 22, 17, 20, 6, 64, 69, 72, 76, 28, 17, 9,\n                                  4, 6, 65, 70, 76, 87, 82, 6, 64, 65, 68, 68,\n                                  78, 82, 92, 67, 37, 21, 13, 5, 10, 65, 70, 72,\n                                  78, 62, 85, 76, 68, 66, 69, 1, 6, 7, 68, 5,\n                                  11, 9, 77, 71, 71, 6, 11, 8, 5, 15, 19, 18, 1,\n                                  8, 15, 14, 75, 68, 75, 88, 82, 75, 78, 74, 75,\n                                  73, 70, 71, 73, 72, 68, 71, 74, 81, 89, 76,\n                                  97, 76, 67, 70, 3, 69, 65, 9, 65, 67, 66, 6,\n                                  69, 70, 85, 38, 37, 38, 34, 27, 35, 31, 28,\n                                  25, 23, 24, 19, 1, 1, 69, 15, 15, 9, 67, 6, 4,\n                                  68, 70, 72, 74, 76, 90, 80, 93, 51, 50, 47,\n                                  45, 38, 37, 34, 26, 27, 23, 20, 12, 7, 65, 75,\n                                  28, 29, 5, 30, 33, 22, 16, 17, 14, 10, 13, 7,\n                                  1, 68, 70, 77, 90, 2, 71, 82, 97, 85, 90, 70,\n                                  72, 70, 27, 2, 2, 68, 12, 39, 26, 45, 4, 46,\n                                  42, 26, 13, 3, 65, 91, 97, 106, 71, 42, 28,\n                                  19, 9, 11, 2, 65, 68, 80, 87, 79, 70, 74, 64,\n                                  4, 67, 67, 4, 7, 8, 4, 11, 12, 2, 46, 43, 35,\n                                  28, 22, 16, 65, 74, 85 },\n\n                                {\n\n                                51,\n                                  7, 78, 51, 7, 78, 88, 72, 19, 11, 3, 64, 30,\n                                  35, 53, 14, 67, 0, 3, 14, 0, 65, 67, 73, 88,\n                                  8, 24, 102, 112, 116, 0, 76, 68, 3, 14, 0, 77,\n                                  71, 11, 6, 64, 72, 80, 0, 76, 79, 90, 5, 71,\n                                  80, 3, 74, 76, 88, 6, 67, 68, 73, 1, 4, 22, 0,\n                                  0, 0, 70, 91, 97, 1, 5, 66, 52, 7, 69, 103,\n                                  84, 82, 64, 78, 89, 84, 94, 70, 89, 85, 85,\n                                  99, 98, 100, 99, 17, 65, 0, 86, 65, 82, 76,\n                                  85, 72, 88, 81, 99, 13, 75, 66, 94, 83, 71,\n                                  72, 64, 6, 1, 67, 11, 8, 72, 1, 0, 65, 2, 75,\n                                  12, 2, 15, 19, 10, 17, 17, 13, 4, 11, 4, 6, 8,\n                                  81, 90, 79, 83, 73, 77, 74, 1, 72, 73, 69, 67,\n                                  71, 72, 67, 83, 91, 79, 95, 69, 74, 4, 66, 66,\n                                  12, 1, 65, 65, 12, 69, 76, 1, 88, 30, 34, 27,\n                                  28, 34, 27, 13, 29, 26, 3, 13, 13, 4, 1, 70,\n                                  9, 3, 4, 6, 2, 67, 6, 1, 75, 66, 68, 74, 69,\n                                  89, 47, 50, 45, 47, 45, 41, 40, 41, 36, 28,\n                                  29, 23, 13, 10, 73, 28, 23, 6, 29, 19, 19, 14,\n                                  10, 6, 6, 64, 75, 67, 74, 88, 84, 99, 66, 30,\n                                  20, 14, 4, 5, 64, 69, 72, 78, 3, 43, 29, 22,\n                                  17, 21, 6, 64, 68, 72, 75, 29, 17, 10, 4, 7,\n                                  65, 70, 75, 86, 81, 7, 0, 64, 68, 68, 78, 81,\n                                  90, 67, 37, 21, 13, 6, 10, 65, 69, 72, 77, 62,\n                                  84, 75, 68, 66, 69, 1, 6, 7, 68, 6, 11, 10,\n                                  77, 71, 72, 6, 11, 7, 4, 14, 18, 18, 0, 7, 15,\n                                  14, 75, 69, 76, 87, 81, 74, 78, 74, 75, 72,\n                                  70, 71, 72, 71, 67, 71, 74, 81, 89, 75, 97,\n                                  76, 67, 70, 4, 69, 65, 10, 66, 67, 66, 6, 70,\n                                  70, 86, 37, 36, 38, 33, 26, 35, 31, 27, 24,\n                                  23, 23, 18, 0, 0, 70, 13, 14, 7, 69, 4, 2, 69,\n                                  70, 72, 74, 76, 89, 81, 92, 49, 48, 45, 43,\n                                  35, 35, 32, 23, 25, 20, 18, 9, 5, 66, 75, 27,\n                                  28, 3, 28, 30, 20, 14, 15, 12, 8, 10, 5, 64,\n                                  70, 72, 78, 92, 0, 73, 84, 96, 84, 89, 69, 71,\n                                  69, 28, 3, 3, 68, 13, 40, 27, 46, 5, 45, 41,\n                                  23, 10, 0, 67, 94, 99, 108, 70, 42, 28, 19, 9,\n                                  11, 2, 65, 68, 79, 86, 79, 69, 73, 0, 4, 66,\n                                  66, 4, 7, 8, 4, 12, 12, 2, 45, 41, 33, 26, 21,\n                                  15, 68, 75, 86 },\n\n                                {\n\n                                50,\n                                  7, 78, 50, 7, 78, 86, 70, 19, 11, 2, 66, 28,\n                                  33, 53, 14, 64, 64, 4, 14, 0, 66, 67, 74, 89,\n                                  8, 22, 104, 113, 116, 3, 75, 68, 4, 14, 0, 77,\n                                  70, 11, 6, 64, 72, 80, 0, 77, 78, 90, 5, 71,\n                                  79, 2, 74, 76, 88, 7, 66, 68, 72, 2, 4, 22, 0,\n                                  0, 0, 70, 91, 97, 2, 4, 66, 52, 7, 69, 102,\n                                  83, 82, 0, 76, 88, 82, 92, 69, 88, 83, 83, 98,\n                                  97, 99, 99, 18, 65, 1, 85, 65, 81, 75, 83, 72,\n                                  88, 80, 98, 13, 74, 65, 93, 82, 71, 72, 0, 6,\n                                  1, 66, 12, 9, 72, 0, 0, 65, 2, 75, 12, 1, 14,\n                                  19, 10, 17, 17, 12, 2, 11, 3, 4, 7, 82, 89,\n                                  78, 82, 72, 76, 73, 2, 71, 72, 68, 66, 71, 72,\n                                  66, 84, 90, 78, 95, 69, 74, 4, 66, 67, 13, 1,\n                                  65, 67, 13, 69, 77, 1, 89, 29, 33, 27, 27, 33,\n                                  26, 12, 28, 26, 2, 12, 13, 4, 1, 71, 8, 3, 3,\n                                  6, 1, 68, 5, 0, 77, 67, 69, 75, 70, 89, 45,\n                                  49, 43, 45, 43, 39, 37, 39, 34, 26, 27, 21,\n                                  11, 8, 75, 26, 22, 4, 26, 17, 17, 12, 7, 4, 3,\n                                  66, 78, 68, 75, 90, 85, 99, 66, 30, 21, 14, 4,\n                                  5, 64, 69, 72, 78, 4, 44, 29, 22, 17, 22, 7,\n                                  0, 68, 71, 74, 30, 18, 10, 4, 8, 64, 69, 75,\n                                  85, 81, 8, 0, 64, 68, 67, 77, 81, 89, 66, 38,\n                                  21, 13, 6, 11, 64, 68, 71, 76, 62, 84, 75, 67,\n                                  66, 69, 1, 6, 7, 67, 6, 11, 10, 77, 71, 72, 5,\n                                  12, 6, 3, 13, 17, 18, 64, 6, 14, 14, 76, 70,\n                                  76, 86, 81, 73, 77, 73, 74, 72, 69, 71, 72,\n                                  71, 67, 72, 74, 81, 88, 74, 97, 76, 66, 70, 4,\n                                  69, 65, 11, 66, 67, 66, 7, 70, 71, 87, 36, 36,\n                                  37, 32, 25, 34, 30, 26, 23, 22, 22, 17, 64,\n                                  64, 71, 12, 12, 6, 71, 3, 1, 70, 71, 73, 74,\n                                  76, 89, 81, 91, 47, 46, 43, 40, 32, 33, 30,\n                                  21, 23, 18, 16, 7, 3, 68, 76, 25, 26, 2, 26,\n                                  28, 18, 12, 13, 10, 6, 8, 3, 67, 72, 74, 80,\n                                  93, 65, 75, 85, 95, 83, 88, 69, 70, 68, 30, 4,\n                                  4, 68, 14, 42, 29, 48, 5, 43, 39, 21, 7, 66,\n                                  70, 97, 101, 109, 70, 42, 28, 19, 9, 11, 2,\n                                  65, 68, 79, 85, 78, 68, 72, 1, 5, 66, 65, 5,\n                                  8, 9, 5, 12, 13, 2, 43, 40, 31, 24, 19, 13,\n                                  70, 77, 87 },\n\n                                {\n\n                                48,\n                                  6, 78, 48, 6, 78, 85, 69, 19, 11, 2, 67, 27,\n                                  32, 53, 14, 1, 64, 5, 15, 0, 67, 67, 75, 91,\n                                  7, 20, 106, 114, 117, 5, 74, 68, 5, 15, 0, 77,\n                                  69, 11, 5, 64, 72, 79, 64, 77, 78, 91, 5, 71,\n                                  79, 2, 75, 76, 88, 7, 66, 68, 72, 2, 4, 22, 0,\n                                  0, 0, 69, 92, 97, 2, 3, 66, 52, 7, 69, 101,\n                                  82, 82, 0, 75, 86, 80, 91, 68, 86, 82, 82, 97,\n                                  97, 98, 98, 18, 65, 2, 84, 65, 81, 75, 82, 72,\n                                  88, 80, 97, 13, 74, 65, 92, 82, 70, 72, 0, 6,\n                                  1, 66, 12, 9, 73, 0, 0, 65, 2, 75, 12, 1, 13,\n                                  19, 9, 17, 17, 12, 0, 11, 3, 2, 6, 83, 88, 77,\n                                  81, 71, 76, 73, 3, 71, 72, 67, 65, 71, 72, 66,\n                                  86, 90, 77, 95, 69, 75, 5, 66, 68, 14, 1, 65,\n                                  68, 14, 70, 78, 1, 90, 27, 32, 26, 26, 32, 25,\n                                  11, 27, 25, 0, 11, 12, 4, 1, 71, 7, 2, 2, 5,\n                                  0, 69, 4, 64, 79, 69, 70, 76, 71, 89, 43, 47,\n                                  41, 43, 41, 37, 35, 37, 31, 23, 25, 18, 8, 5,\n                                  78, 24, 20, 2, 24, 15, 14, 9, 5, 1, 0, 68, 80,\n                                  69, 77, 91, 86, 100, 66, 30, 21, 14, 4, 5, 64,\n                                  69, 72, 77, 4, 44, 29, 22, 17, 23, 7, 0, 68,\n                                  71, 74, 31, 18, 10, 4, 8, 64, 69, 74, 84, 80,\n                                  9, 1, 64, 68, 66, 76, 80, 88, 66, 38, 21, 13,\n                                  6, 12, 64, 68, 70, 76, 62, 84, 75, 67, 66, 69,\n                                  1, 6, 7, 67, 6, 11, 11, 77, 71, 72, 4, 12, 5,\n                                  2, 12, 16, 18, 66, 4, 14, 14, 77, 71, 77, 86,\n                                  80, 72, 77, 73, 74, 71, 68, 72, 72, 71, 67,\n                                  73, 74, 81, 88, 74, 98, 76, 66, 70, 5, 69, 65,\n                                  11, 66, 68, 66, 8, 71, 71, 88, 35, 35, 37, 31,\n                                  23, 33, 29, 25, 22, 21, 21, 16, 65, 65, 72,\n                                  10, 11, 4, 73, 1, 0, 71, 72, 73, 74, 76, 89,\n                                  82, 91, 44, 43, 41, 38, 29, 30, 27, 18, 21,\n                                  16, 14, 4, 1, 69, 77, 23, 24, 0, 24, 26, 15,\n                                  9, 10, 7, 4, 6, 0, 69, 74, 77, 82, 94, 67, 77,\n                                  87, 94, 82, 87, 68, 69, 68, 31, 5, 4, 68, 14,\n                                  43, 30, 49, 6, 42, 37, 18, 4, 69, 73, 100,\n                                  103, 110, 70, 42, 28, 19, 9, 11, 2, 65, 68,\n                                  78, 85, 77, 67, 72, 2, 5, 65, 65, 5, 8, 9, 5,\n                                  13, 13, 1, 42, 38, 29, 22, 17, 11, 72, 79, 88 },\n\n                                {\n\n                                47,\n                                  6, 78, 47, 6, 78, 83, 68, 20, 11, 2, 68, 26,\n                                  31, 53, 14, 3, 64, 6, 16, 0, 67, 66, 76, 92,\n                                  6, 18, 107, 115, 118, 8, 72, 68, 6, 16, 0, 76,\n                                  68, 12, 4, 64, 71, 78, 64, 77, 78, 91, 5, 71,\n                                  78, 2, 75, 76, 88, 7, 66, 67, 72, 2, 4, 22, 0,\n                                  0, 0, 68, 92, 97, 2, 2, 66, 52, 7, 69, 100,\n                                  81, 82, 0, 74, 84, 78, 89, 66, 84, 81, 80, 96,\n                                  96, 97, 97, 19, 64, 3, 83, 65, 80, 74, 80, 72,\n                                  87, 80, 95, 14, 74, 65, 90, 82, 69, 72, 0, 7,\n                                  2, 65, 12, 9, 73, 0, 1, 65, 2, 74, 12, 1, 13,\n                                  19, 8, 17, 17, 12, 65, 11, 3, 1, 5, 83, 87,\n                                  76, 80, 70, 75, 72, 4, 70, 72, 66, 64, 71, 72,\n                                  66, 87, 89, 76, 95, 68, 75, 6, 66, 69, 15, 1,\n                                  65, 69, 15, 71, 79, 1, 90, 26, 31, 26, 25, 31,\n                                  24, 11, 27, 25, 64, 10, 12, 4, 1, 71, 7, 1, 1,\n                                  4, 64, 70, 4, 64, 80, 70, 70, 77, 72, 89, 42,\n                                  46, 40, 42, 40, 35, 33, 35, 29, 21, 23, 16, 5,\n                                  3, 81, 23, 18, 1, 22, 13, 12, 7, 3, 64, 65,\n                                  70, 82, 69, 79, 92, 86, 100, 66, 31, 21, 14,\n                                  5, 5, 64, 68, 72, 76, 4, 44, 29, 23, 17, 24,\n                                  8, 1, 67, 70, 73, 32, 19, 11, 5, 9, 0, 69, 73,\n                                  83, 79, 11, 2, 0, 67, 65, 75, 79, 87, 65, 38,\n                                  22, 14, 6, 13, 0, 67, 69, 75, 62, 83, 74, 66,\n                                  66, 69, 1, 7, 8, 67, 6, 12, 12, 77, 71, 72, 4,\n                                  12, 4, 2, 11, 16, 18, 67, 3, 14, 14, 77, 72,\n                                  78, 85, 79, 71, 77, 72, 74, 70, 67, 72, 72,\n                                  71, 66, 73, 74, 81, 88, 73, 98, 76, 66, 70, 6,\n                                  69, 65, 12, 66, 68, 66, 9, 72, 71, 88, 34, 35,\n                                  37, 31, 22, 32, 28, 24, 22, 20, 20, 16, 65,\n                                  66, 73, 9, 10, 2, 75, 0, 64, 71, 72, 73, 73,\n                                  75, 89, 83, 90, 42, 41, 39, 36, 27, 28, 25,\n                                  16, 19, 14, 12, 2, 64, 70, 78, 21, 23, 64, 22,\n                                  24, 13, 7, 8, 5, 2, 4, 65, 71, 75, 79, 84, 95,\n                                  69, 79, 89, 93, 80, 85, 67, 68, 67, 33, 6, 5,\n                                  68, 15, 45, 31, 51, 7, 41, 36, 16, 1, 71, 76,\n                                  102, 105, 111, 70, 42, 28, 19, 9, 12, 2, 65,\n                                  68, 77, 84, 76, 66, 71, 4, 6, 64, 64, 6, 9,\n                                  10, 5, 14, 13, 1, 41, 37, 28, 21, 15, 9, 74,\n                                  81, 88 },\n\n                                {\n\n                                46,\n                                  6, 78, 46, 6, 78, 81, 66, 20, 11, 1, 70, 24,\n                                  29, 53, 14, 6, 65, 7, 16, 0, 68, 66, 77, 93,\n                                  6, 16, 109, 116, 118, 11, 71, 68, 7, 16, 0,\n                                  76, 67, 12, 4, 64, 71, 78, 64, 78, 77, 91, 5,\n                                  71, 77, 1, 75, 76, 88, 8, 65, 67, 71, 3, 4,\n                                  22, 0, 0, 0, 68, 92, 97, 3, 1, 66, 52, 7, 69,\n                                  99, 80, 82, 1, 72, 83, 76, 88, 65, 83, 79, 78,\n                                  95, 95, 96, 97, 20, 64, 4, 82, 65, 80, 73, 78,\n                                  72, 87, 79, 94, 14, 73, 64, 89, 81, 69, 72, 1,\n                                  7, 2, 64, 13, 10, 74, 64, 1, 65, 2, 74, 12, 0,\n                                  12, 19, 8, 17, 17, 11, 67, 11, 2, 64, 4, 84,\n                                  86, 75, 79, 69, 74, 71, 5, 69, 71, 65, 0, 71,\n                                  72, 65, 88, 89, 75, 95, 68, 75, 6, 66, 70, 16,\n                                  1, 65, 71, 16, 71, 80, 1, 91, 24, 30, 25, 24,\n                                  30, 23, 10, 26, 25, 65, 9, 12, 4, 1, 72, 6, 1,\n                                  0, 4, 65, 71, 3, 65, 82, 71, 71, 78, 73, 89,\n                                  40, 45, 38, 40, 38, 33, 30, 33, 26, 19, 21,\n                                  13, 3, 1, 83, 21, 17, 64, 19, 11, 10, 5, 0,\n                                  66, 68, 72, 85, 70, 80, 94, 87, 100, 66, 31,\n                                  22, 14, 5, 5, 64, 68, 72, 76, 5, 45, 29, 23,\n                                  17, 25, 8, 2, 67, 69, 72, 33, 20, 11, 5, 10,\n                                  0, 68, 73, 82, 79, 12, 2, 0, 67, 64, 74, 79,\n                                  86, 65, 39, 22, 14, 6, 14, 1, 66, 68, 74, 62,\n                                  83, 74, 66, 66, 69, 1, 7, 8, 66, 6, 12, 12,\n                                  77, 71, 72, 3, 13, 3, 1, 10, 15, 18, 68, 2,\n                                  13, 14, 78, 73, 78, 84, 79, 70, 76, 72, 73,\n                                  70, 66, 72, 72, 71, 66, 74, 74, 81, 87, 72,\n                                  98, 76, 65, 70, 6, 69, 65, 13, 66, 68, 66, 10,\n                                  72, 72, 89, 33, 35, 36, 30, 21, 31, 27, 23,\n                                  21, 19, 19, 15, 66, 67, 74, 7, 8, 1, 77, 64,\n                                  65, 72, 73, 74, 73, 75, 89, 83, 89, 40, 39,\n                                  37, 33, 24, 26, 23, 13, 17, 12, 10, 0, 66, 72,\n                                  79, 19, 21, 65, 20, 22, 11, 5, 6, 3, 0, 2, 67,\n                                  74, 77, 81, 86, 96, 71, 81, 90, 92, 79, 84,\n                                  67, 67, 66, 35, 7, 6, 68, 16, 46, 33, 52, 7,\n                                  39, 34, 13, 65, 74, 79, 105, 107, 112, 70, 42,\n                                  28, 19, 9, 12, 2, 65, 68, 77, 83, 75, 65, 70,\n                                  5, 7, 64, 0, 7, 10, 11, 6, 14, 14, 1, 39, 35,\n                                  26, 19, 13, 7, 76, 83, 89 },\n\n                                {\n\n                                45,\n                                  6, 79, 45, 6, 79, 79, 65, 21, 11, 1, 71, 23,\n                                  28, 53, 14, 8, 65, 7, 17, 0, 69, 66, 78, 94,\n                                  5, 15, 110, 117, 119, 14, 70, 68, 7, 17, 0,\n                                  75, 66, 13, 3, 0, 70, 77, 65, 78, 77, 91, 5,\n                                  70, 77, 1, 75, 75, 88, 8, 65, 67, 71, 3, 4,\n                                  22, 0, 0, 0, 67, 92, 97, 3, 1, 67, 52, 7, 69,\n                                  98, 80, 82, 1, 71, 81, 74, 86, 64, 81, 78, 76,\n                                  94, 94, 95, 96, 21, 64, 5, 82, 64, 79, 73, 76,\n                                  72, 86, 79, 93, 14, 73, 64, 87, 81, 68, 71, 1,\n                                  7, 2, 0, 13, 10, 74, 64, 1, 65, 2, 74, 12, 0,\n                                  12, 19, 7, 17, 17, 11, 69, 11, 2, 66, 3, 85,\n                                  86, 74, 79, 69, 73, 71, 6, 69, 71, 65, 2, 71,\n                                  72, 65, 89, 88, 74, 95, 68, 75, 7, 65, 71, 16,\n                                  1, 65, 72, 17, 72, 81, 1, 92, 23, 29, 25, 24,\n                                  29, 23, 10, 25, 24, 66, 8, 12, 4, 1, 72, 5, 0,\n                                  64, 3, 65, 72, 2, 65, 84, 72, 71, 79, 74, 89,\n                                  39, 43, 37, 38, 36, 31, 28, 31, 24, 16, 19,\n                                  11, 0, 65, 86, 19, 15, 65, 17, 8, 7, 2, 65,\n                                  69, 70, 75, 87, 71, 82, 95, 88, 100, 65, 32,\n                                  22, 15, 5, 5, 64, 68, 72, 75, 5, 45, 30, 23,\n                                  17, 26, 9, 2, 66, 69, 71, 34, 20, 12, 5, 11,\n                                  1, 68, 72, 81, 78, 13, 3, 1, 67, 64, 74, 78,\n                                  84, 64, 39, 22, 14, 7, 14, 1, 65, 68, 73, 62,\n                                  82, 73, 65, 66, 69, 1, 7, 8, 66, 7, 12, 13,\n                                  77, 71, 73, 3, 13, 2, 0, 9, 14, 18, 69, 1, 13,\n                                  14, 78, 74, 79, 83, 78, 69, 76, 71, 73, 69,\n                                  66, 72, 71, 70, 65, 74, 74, 81, 87, 71, 98,\n                                  76, 65, 70, 7, 69, 65, 14, 67, 68, 66, 10, 73,\n                                  72, 90, 32, 34, 36, 29, 20, 31, 27, 22, 20,\n                                  19, 18, 14, 67, 68, 75, 6, 7, 64, 79, 66, 67,\n                                  73, 73, 74, 73, 75, 88, 84, 88, 38, 37, 35,\n                                  31, 21, 24, 21, 11, 15, 9, 8, 66, 68, 73, 79,\n                                  18, 20, 67, 18, 19, 9, 3, 4, 1, 65, 64, 69,\n                                  76, 79, 83, 87, 98, 73, 83, 92, 91, 78, 83,\n                                  66, 66, 65, 36, 8, 7, 68, 17, 48, 34, 54, 8,\n                                  38, 33, 11, 68, 77, 81, 108, 109, 114, 69, 42,\n                                  28, 19, 9, 12, 2, 65, 68, 76, 82, 75, 64, 69,\n                                  6, 7, 0, 1, 7, 10, 11, 6, 15, 14, 1, 38, 34,\n                                  24, 17, 12, 6, 79, 84, 90 },\n\n                                {\n\n                                43,\n                                  6, 79, 43, 6, 79, 78, 0, 21, 11, 0, 73, 21,\n                                  27, 53, 14, 10, 65, 8, 18, 0, 70, 66, 79, 95,\n                                  5, 13, 112, 118, 119, 17, 69, 68, 8, 18, 0,\n                                  75, 65, 13, 3, 0, 70, 76, 65, 79, 77, 91, 5,\n                                  70, 76, 1, 76, 75, 88, 9, 65, 67, 71, 4, 4,\n                                  22, 0, 0, 0, 67, 93, 97, 4, 0, 67, 52, 7, 69,\n                                  97, 79, 82, 2, 70, 79, 72, 85, 0, 79, 77, 74,\n                                  93, 94, 94, 95, 21, 64, 6, 81, 64, 79, 72, 74,\n                                  72, 86, 78, 92, 14, 73, 0, 86, 80, 67, 71, 1,\n                                  7, 2, 0, 14, 11, 75, 64, 1, 65, 2, 74, 12, 64,\n                                  11, 19, 6, 17, 17, 11, 71, 11, 1, 68, 2, 86,\n                                  85, 73, 78, 68, 73, 70, 7, 68, 70, 64, 3, 71,\n                                  72, 65, 90, 88, 73, 95, 68, 75, 8, 65, 72, 17,\n                                  1, 65, 73, 18, 72, 82, 1, 93, 21, 28, 24, 23,\n                                  28, 22, 9, 24, 24, 68, 7, 11, 4, 1, 73, 4, 64,\n                                  65, 2, 66, 73, 1, 66, 86, 73, 72, 80, 75, 89,\n                                  37, 42, 35, 36, 34, 29, 26, 29, 21, 14, 17, 8,\n                                  65, 67, 88, 17, 13, 67, 15, 6, 5, 0, 67, 71,\n                                  73, 77, 90, 72, 84, 96, 89, 100, 65, 32, 22,\n                                  15, 5, 5, 64, 68, 72, 75, 5, 45, 30, 23, 17,\n                                  27, 9, 3, 66, 68, 71, 35, 21, 12, 5, 11, 1,\n                                  67, 72, 80, 77, 14, 4, 1, 67, 0, 73, 77, 83,\n                                  64, 39, 22, 14, 7, 15, 2, 65, 67, 72, 62, 82,\n                                  73, 65, 66, 69, 1, 7, 8, 66, 7, 12, 13, 77,\n                                  71, 73, 2, 14, 1, 64, 8, 13, 18, 71, 0, 13,\n                                  14, 79, 75, 79, 83, 77, 68, 75, 71, 72, 69,\n                                  65, 73, 71, 70, 65, 75, 74, 81, 86, 70, 98,\n                                  76, 65, 70, 8, 69, 65, 15, 67, 69, 66, 11, 74,\n                                  72, 91, 31, 34, 35, 28, 19, 30, 26, 21, 19,\n                                  18, 17, 13, 68, 69, 76, 4, 6, 65, 81, 67, 68,\n                                  74, 74, 75, 73, 75, 88, 84, 88, 35, 34, 33,\n                                  29, 18, 22, 19, 8, 13, 7, 6, 68, 70, 75, 80,\n                                  16, 18, 68, 16, 17, 7, 1, 1, 64, 67, 66, 71,\n                                  79, 81, 85, 89, 99, 75, 85, 93, 90, 77, 82,\n                                  65, 65, 64, 38, 9, 8, 68, 18, 49, 36, 55, 9,\n                                  36, 31, 8, 71, 80, 84, 111, 111, 115, 69, 42,\n                                  28, 19, 9, 12, 2, 65, 68, 76, 81, 74, 0, 69,\n                                  7, 8, 0, 2, 8, 11, 12, 6, 15, 14, 1, 37, 32,\n                                  22, 15, 10, 4, 81, 86, 91 },\n\n                                {\n\n                                42,\n                                  6, 79, 42, 6, 79, 76, 1, 21, 11, 0, 74, 20,\n                                  25, 53, 14, 13, 66, 9, 18, 0, 70, 65, 80, 96,\n                                  4, 11, 114, 119, 120, 20, 67, 68, 9, 18, 0,\n                                  75, 64, 13, 2, 0, 70, 76, 65, 79, 76, 91, 5,\n                                  70, 75, 0, 76, 75, 88, 9, 64, 66, 70, 4, 4,\n                                  22, 0, 0, 0, 66, 93, 97, 4, 64, 67, 52, 7, 69,\n                                  96, 78, 82, 2, 68, 78, 70, 83, 1, 78, 75, 72,\n                                  92, 93, 93, 95, 22, 64, 7, 80, 64, 78, 71, 72,\n                                  72, 86, 78, 90, 15, 72, 0, 85, 80, 67, 71, 2,\n                                  8, 3, 1, 14, 11, 75, 65, 1, 65, 2, 74, 12, 64,\n                                  10, 19, 6, 17, 17, 10, 73, 11, 1, 69, 1, 87,\n                                  84, 72, 77, 67, 72, 69, 8, 67, 70, 0, 4, 71,\n                                  72, 64, 91, 87, 72, 95, 67, 75, 8, 65, 73, 18,\n                                  1, 65, 75, 19, 73, 83, 1, 93, 20, 27, 24, 22,\n                                  27, 21, 8, 24, 24, 69, 6, 11, 4, 1, 73, 4, 64,\n                                  66, 2, 67, 74, 1, 67, 88, 74, 73, 81, 76, 89,\n                                  35, 41, 33, 34, 33, 27, 23, 27, 19, 12, 15, 6,\n                                  68, 69, 91, 15, 12, 69, 12, 4, 3, 65, 70, 73,\n                                  76, 79, 92, 73, 85, 98, 89, 100, 65, 32, 23,\n                                  15, 5, 5, 64, 68, 72, 74, 6, 46, 30, 23, 17,\n                                  28, 10, 4, 66, 67, 70, 36, 22, 12, 6, 12, 2,\n                                  67, 71, 79, 77, 16, 4, 1, 66, 1, 72, 77, 82,\n                                  0, 40, 23, 14, 7, 16, 3, 64, 66, 71, 62, 82,\n                                  73, 64, 66, 69, 1, 7, 8, 65, 7, 13, 14, 77,\n                                  71, 73, 1, 14, 0, 65, 7, 13, 18, 72, 64, 12,\n                                  14, 80, 76, 80, 82, 77, 67, 75, 70, 72, 68,\n                                  64, 73, 71, 70, 65, 76, 74, 81, 86, 69, 98,\n                                  76, 64, 70, 8, 69, 65, 16, 67, 69, 66, 12, 74,\n                                  73, 91, 30, 34, 35, 28, 18, 29, 25, 20, 19,\n                                  17, 16, 12, 69, 70, 77, 3, 4, 67, 83, 68, 69,\n                                  75, 75, 75, 73, 74, 88, 85, 87, 33, 32, 31,\n                                  26, 16, 20, 17, 6, 11, 5, 4, 70, 72, 76, 81,\n                                  14, 16, 69, 14, 15, 5, 64, 64, 66, 69, 68, 73,\n                                  81, 83, 87, 91, 100, 77, 87, 95, 89, 75, 81,\n                                  65, 64, 0, 40, 10, 9, 68, 19, 51, 37, 57, 9,\n                                  35, 29, 6, 74, 82, 87, 113, 113, 116, 69, 42,\n                                  28, 19, 9, 12, 2, 65, 68, 75, 80, 73, 1, 68,\n                                  8, 9, 1, 3, 9, 12, 13, 7, 16, 15, 1, 35, 31,\n                                  21, 14, 8, 2, 83, 88, 92 },\n\n                                {\n\n                                41,\n                                  6, 79, 41, 6, 79, 74, 3, 22, 11, 64, 76, 18,\n                                  24, 53, 14, 15, 66, 10, 19, 0, 71, 65, 81, 97,\n                                  4, 9, 115, 120, 120, 23, 66, 68, 10, 19, 0,\n                                  74, 0, 14, 2, 0, 69, 75, 66, 80, 76, 91, 5,\n                                  70, 75, 0, 76, 75, 88, 10, 64, 66, 70, 5, 4,\n                                  22, 0, 0, 0, 66, 93, 97, 5, 65, 67, 52, 7, 69,\n                                  95, 77, 82, 3, 67, 76, 68, 82, 2, 76, 74, 70,\n                                  91, 92, 92, 94, 23, 64, 8, 79, 64, 78, 71, 70,\n                                  72, 85, 77, 89, 15, 72, 1, 83, 79, 66, 71, 2,\n                                  8, 3, 2, 15, 12, 76, 65, 1, 65, 2, 74, 12, 65,\n                                  10, 19, 5, 17, 17, 10, 75, 11, 0, 71, 0, 88,\n                                  83, 71, 76, 66, 71, 69, 9, 67, 69, 1, 5, 71,\n                                  72, 64, 92, 87, 71, 95, 67, 75, 9, 65, 74, 19,\n                                  1, 65, 76, 20, 73, 84, 1, 94, 18, 26, 23, 21,\n                                  26, 20, 8, 23, 23, 70, 5, 11, 4, 1, 74, 3, 65,\n                                  67, 1, 68, 75, 0, 67, 90, 75, 73, 82, 77, 89,\n                                  34, 39, 32, 32, 31, 25, 21, 25, 16, 9, 13, 3,\n                                  70, 72, 93, 13, 10, 70, 10, 2, 0, 68, 72, 76,\n                                  78, 81, 95, 74, 87, 99, 90, 100, 65, 33, 23,\n                                  15, 5, 5, 64, 68, 72, 74, 6, 46, 30, 23, 17,\n                                  29, 10, 4, 65, 67, 69, 37, 22, 13, 6, 13, 2,\n                                  66, 71, 78, 76, 17, 5, 2, 66, 2, 71, 76, 81,\n                                  0, 40, 23, 14, 7, 17, 3, 0, 65, 70, 62, 81,\n                                  72, 64, 66, 69, 1, 7, 8, 65, 7, 13, 14, 77,\n                                  71, 73, 1, 15, 64, 66, 6, 12, 18, 73, 65, 12,\n                                  14, 80, 77, 80, 81, 76, 66, 74, 70, 71, 68, 0,\n                                  73, 71, 70, 64, 76, 74, 81, 85, 68, 98, 76,\n                                  64, 70, 9, 69, 65, 17, 67, 69, 66, 13, 75, 73,\n                                  92, 29, 33, 34, 27, 17, 28, 24, 19, 18, 16,\n                                  15, 11, 70, 71, 78, 1, 3, 68, 85, 70, 70, 76,\n                                  75, 76, 73, 74, 88, 85, 86, 31, 30, 29, 24,\n                                  13, 18, 15, 3, 9, 3, 2, 73, 74, 78, 82, 12,\n                                  15, 71, 12, 13, 3, 66, 66, 68, 71, 70, 75, 84,\n                                  85, 89, 93, 101, 79, 89, 96, 88, 74, 80, 64,\n                                  0, 1, 41, 11, 10, 68, 20, 52, 39, 58, 10, 33,\n                                  28, 3, 77, 85, 90, 116, 115, 117, 69, 42, 28,\n                                  19, 9, 12, 2, 65, 68, 75, 79, 72, 2, 67, 9, 9,\n                                  1, 4, 9, 12, 13, 7, 16, 15, 1, 34, 29, 19, 12,\n                                  6, 0, 85, 90, 93 },\n\n                                {\n\n                                40,\n                                  6, 79, 40, 6, 79, 72, 4, 22, 11, 64, 77, 17,\n                                  23, 53, 14, 17, 66, 11, 20, 0, 72, 65, 82, 98,\n                                  3, 7, 117, 121, 121, 26, 65, 68, 11, 20, 0,\n                                  74, 1, 14, 1, 0, 69, 74, 66, 80, 76, 91, 5,\n                                  70, 74, 0, 76, 75, 88, 10, 64, 66, 70, 5, 4,\n                                  22, 0, 0, 0, 65, 93, 97, 5, 66, 67, 52, 7, 69,\n                                  94, 76, 82, 3, 66, 74, 66, 80, 3, 74, 73, 68,\n                                  90, 91, 91, 93, 24, 64, 9, 78, 64, 77, 70, 68,\n                                  72, 85, 77, 88, 15, 72, 1, 82, 79, 65, 71, 2,\n                                  8, 3, 3, 15, 12, 76, 65, 1, 65, 2, 74, 12, 65,\n                                  9, 19, 4, 17, 17, 10, 77, 11, 0, 73, 64, 89,\n                                  82, 70, 75, 65, 70, 68, 10, 66, 69, 2, 6, 71,\n                                  72, 64, 93, 86, 70, 95, 67, 75, 10, 65, 75,\n                                  20, 1, 65, 77, 21, 74, 85, 1, 95, 17, 25, 23,\n                                  20, 25, 19, 7, 22, 23, 71, 4, 11, 4, 1, 74, 2,\n                                  66, 68, 0, 69, 76, 64, 68, 92, 76, 74, 83, 78,\n                                  89, 32, 38, 30, 30, 29, 23, 19, 23, 14, 7, 11,\n                                  1, 73, 74, 96, 11, 8, 72, 8, 0, 65, 70, 74,\n                                  78, 81, 83, 97, 75, 89, 100, 91, 100, 65, 33,\n                                  23, 15, 5, 5, 64, 68, 72, 73, 6, 46, 30, 23,\n                                  17, 30, 11, 5, 65, 66, 68, 38, 23, 13, 6, 14,\n                                  3, 66, 70, 77, 75, 18, 6, 2, 66, 3, 70, 75,\n                                  80, 1, 40, 23, 14, 7, 18, 4, 1, 64, 69, 62,\n                                  81, 72, 0, 66, 69, 1, 7, 8, 65, 7, 13, 15, 77,\n                                  71, 73, 0, 15, 65, 67, 5, 11, 18, 74, 66, 12,\n                                  14, 81, 78, 81, 80, 75, 65, 74, 69, 71, 67, 1,\n                                  73, 71, 70, 64, 77, 74, 81, 85, 67, 98, 76,\n                                  64, 70, 10, 69, 65, 18, 67, 69, 66, 14, 76,\n                                  73, 93, 28, 33, 34, 26, 16, 27, 23, 18, 17,\n                                  15, 14, 10, 71, 72, 79, 0, 2, 70, 87, 71, 71,\n                                  77, 76, 76, 73, 74, 88, 86, 85, 29, 28, 27,\n                                  22, 10, 16, 13, 1, 7, 1, 0, 75, 76, 79, 83,\n                                  10, 13, 72, 10, 11, 1, 68, 68, 70, 73, 72, 77,\n                                  86, 87, 91, 95, 102, 81, 91, 98, 87, 73, 79,\n                                  0, 1, 2, 43, 12, 11, 68, 21, 54, 40, 60, 11,\n                                  32, 26, 1, 80, 88, 93, 119, 117, 118, 69, 42,\n                                  28, 19, 9, 12, 2, 65, 68, 74, 78, 71, 3, 66,\n                                  10, 10, 2, 5, 10, 13, 14, 7, 17, 15, 1, 33,\n                                  28, 17, 10, 4, 65, 87, 92, 94 },\n\n                                {\n\n                                38,\n                                  5, 80, 38, 5, 80, 71, 5, 22, 11, 65, 79, 15,\n                                  21, 52, 14, 19, 67, 11, 20, 64, 73, 65, 84,\n                                  100, 2, 5, 119, 122, 122, 28, 64, 69, 11, 20,\n                                  64, 74, 2, 14, 0, 0, 69, 74, 67, 81, 76, 92,\n                                  5, 70, 74, 64, 77, 75, 88, 10, 64, 66, 70, 5,\n                                  3, 22, 0, 0, 0, 65, 94, 97, 5, 67, 68, 52, 6,\n                                  69, 93, 76, 82, 3, 65, 73, 65, 79, 4, 73, 72,\n                                  67, 89, 91, 90, 93, 24, 64, 9, 78, 64, 77, 70,\n                                  67, 72, 85, 77, 87, 15, 72, 1, 81, 79, 65, 71,\n                                  2, 8, 3, 3, 15, 12, 77, 66, 1, 66, 2, 74, 11,\n                                  66, 8, 19, 3, 16, 17, 9, 79, 10, 64, 75, 65,\n                                  90, 82, 70, 75, 65, 70, 68, 11, 66, 69, 2, 7,\n                                  72, 72, 64, 95, 86, 70, 95, 67, 76, 10, 65,\n                                  76, 20, 1, 65, 79, 21, 75, 86, 1, 96, 15, 24,\n                                  22, 19, 24, 18, 6, 21, 22, 73, 3, 10, 3, 1,\n                                  75, 1, 67, 69, 64, 70, 77, 65, 69, 94, 78, 75,\n                                  85, 80, 89, 30, 36, 28, 28, 27, 20, 16, 20,\n                                  11, 4, 8, 65, 76, 77, 99, 9, 6, 74, 5, 66, 68,\n                                  73, 77, 81, 84, 86, 100, 76, 91, 102, 92, 101,\n                                  65, 33, 23, 15, 5, 5, 65, 68, 72, 73, 6, 46,\n                                  30, 23, 17, 31, 11, 5, 65, 66, 68, 38, 23, 13,\n                                  6, 14, 3, 66, 70, 76, 75, 19, 6, 2, 66, 3, 70,\n                                  75, 79, 1, 40, 23, 14, 7, 18, 4, 1, 64, 69,\n                                  62, 81, 72, 0, 66, 69, 1, 7, 8, 65, 7, 13, 15,\n                                  77, 71, 74, 64, 15, 66, 68, 4, 10, 17, 76, 68,\n                                  11, 13, 82, 80, 82, 80, 75, 64, 74, 69, 71,\n                                  67, 1, 74, 71, 70, 64, 78, 74, 81, 85, 67, 99,\n                                  76, 64, 70, 10, 70, 65, 18, 68, 70, 66, 14,\n                                  77, 74, 94, 27, 32, 33, 25, 14, 26, 22, 17,\n                                  16, 14, 13, 9, 72, 74, 81, 65, 0, 72, 89, 73,\n                                  73, 78, 77, 77, 73, 74, 88, 87, 85, 26, 25,\n                                  25, 19, 7, 13, 10, 65, 4, 65, 66, 78, 79, 81,\n                                  84, 8, 11, 74, 8, 8, 65, 71, 71, 73, 75, 75,\n                                  80, 89, 89, 94, 97, 104, 83, 93, 100, 86, 72,\n                                  78, 0, 1, 2, 44, 12, 11, 68, 21, 55, 41, 61,\n                                  11, 30, 24, 65, 84, 91, 96, 122, 120, 120, 69,\n                                  42, 27, 18, 9, 12, 2, 66, 68, 74, 78, 71, 3,\n                                  66, 11, 10, 2, 5, 10, 13, 14, 7, 17, 15, 0,\n                                  31, 26, 15, 8, 2, 67, 90, 94, 95 },\n\n                                {\n\n                                37,\n                                  5, 80, 37, 5, 80, 69, 7, 23, 12, 65, 80, 14,\n                                  20, 52, 14, 22, 67, 12, 21, 64, 73, 64, 85,\n                                  101, 2, 4, 120, 123, 122, 31, 1, 69, 12, 21,\n                                  64, 73, 4, 15, 0, 1, 68, 73, 67, 81, 75, 92,\n                                  5, 69, 73, 64, 77, 74, 88, 11, 0, 65, 69, 6,\n                                  3, 22, 0, 0, 0, 64, 94, 97, 6, 67, 68, 52, 6,\n                                  69, 91, 75, 82, 4, 0, 71, 0, 77, 6, 71, 70,\n                                  65, 87, 90, 89, 92, 25, 0, 10, 77, 0, 76, 69,\n                                  65, 71, 84, 76, 85, 16, 71, 2, 79, 78, 64, 70,\n                                  3, 9, 4, 4, 16, 13, 77, 66, 2, 66, 2, 73, 11,\n                                  66, 8, 19, 3, 16, 17, 9, 80, 10, 64, 76, 66,\n                                  90, 81, 69, 74, 64, 69, 67, 12, 65, 68, 3, 9,\n                                  72, 72, 0, 96, 85, 69, 95, 66, 76, 11, 64, 76,\n                                  21, 1, 65, 80, 22, 75, 87, 1, 96, 14, 24, 22,\n                                  19, 24, 18, 6, 21, 22, 74, 3, 10, 3, 1, 75, 1,\n                                  67, 69, 64, 70, 78, 65, 69, 95, 79, 75, 86,\n                                  81, 89, 29, 35, 27, 27, 26, 18, 14, 18, 9, 2,\n                                  6, 67, 78, 79, 101, 8, 5, 75, 3, 68, 70, 75,\n                                  79, 83, 86, 88, 102, 76, 92, 103, 92, 101, 64,\n                                  34, 24, 16, 6, 5, 65, 67, 71, 72, 7, 47, 31,\n                                  24, 17, 32, 12, 6, 64, 65, 67, 39, 24, 14, 7,\n                                  15, 4, 65, 69, 74, 74, 21, 7, 3, 65, 4, 69,\n                                  74, 77, 2, 41, 24, 15, 8, 19, 5, 2, 0, 68, 62,\n                                  80, 71, 1, 66, 68, 1, 8, 9, 64, 8, 14, 16, 76,\n                                  71, 74, 64, 16, 66, 68, 3, 10, 17, 77, 69, 11,\n                                  13, 82, 81, 82, 79, 74, 0, 73, 68, 70, 66, 2,\n                                  74, 70, 69, 0, 78, 73, 80, 84, 66, 99, 76, 0,\n                                  70, 11, 70, 65, 19, 68, 70, 65, 15, 77, 74,\n                                  94, 27, 32, 33, 25, 13, 26, 22, 17, 16, 14,\n                                  13, 9, 72, 75, 82, 66, 64, 73, 90, 74, 74, 78,\n                                  77, 77, 72, 73, 87, 87, 84, 24, 23, 23, 17, 5,\n                                  11, 8, 67, 2, 67, 68, 80, 81, 82, 84, 7, 10,\n                                  75, 7, 6, 67, 73, 73, 75, 77, 77, 82, 91, 90,\n                                  96, 98, 105, 84, 94, 101, 84, 70, 76, 1, 2, 3,\n                                  46, 13, 12, 68, 22, 57, 43, 62, 12, 29, 23,\n                                  67, 87, 93, 98, 124, 122, 121, 68, 43, 27, 18,\n                                  9, 13, 2, 66, 68, 73, 77, 70, 4, 65, 13, 11,\n                                  3, 6, 11, 14, 15, 8, 18, 16, 0, 30, 25, 14, 7,\n                                  1, 68, 92, 95, 95 },\n\n                                {\n\n                                36,\n                                  5, 80, 36, 5, 80, 67, 8, 23, 12, 65, 81, 13,\n                                  19, 52, 14, 24, 67, 13, 22, 64, 74, 64, 86,\n                                  102, 1, 2, 122, 124, 123, 34, 2, 69, 13, 22,\n                                  64, 73, 5, 15, 64, 1, 68, 72, 67, 81, 75, 92,\n                                  5, 69, 72, 64, 77, 74, 88, 11, 0, 65, 69, 6,\n                                  3, 22, 0, 0, 0, 0, 94, 97, 6, 68, 68, 52, 6,\n                                  69, 90, 74, 82, 4, 1, 69, 2, 76, 7, 69, 69, 0,\n                                  86, 89, 88, 91, 26, 0, 11, 76, 0, 76, 68, 0,\n                                  71, 84, 76, 84, 16, 71, 2, 78, 78, 0, 70, 3,\n                                  9, 4, 5, 16, 13, 78, 66, 2, 66, 2, 73, 11, 66,\n                                  7, 19, 2, 16, 17, 9, 82, 10, 64, 78, 67, 91,\n                                  80, 68, 73, 0, 68, 66, 13, 64, 68, 4, 10, 72,\n                                  72, 0, 97, 85, 68, 95, 66, 76, 12, 64, 77, 22,\n                                  1, 65, 81, 23, 76, 88, 1, 97, 12, 23, 21, 18,\n                                  23, 17, 5, 20, 22, 75, 2, 10, 3, 1, 75, 0, 68,\n                                  70, 65, 71, 79, 66, 70, 97, 80, 76, 87, 82,\n                                  89, 27, 34, 25, 25, 24, 16, 12, 16, 6, 0, 4,\n                                  70, 81, 81, 104, 6, 3, 77, 1, 70, 72, 77, 81,\n                                  85, 89, 90, 104, 77, 94, 104, 93, 101, 64, 34,\n                                  24, 16, 6, 5, 65, 67, 71, 71, 7, 47, 31, 24,\n                                  17, 33, 12, 7, 64, 64, 66, 40, 25, 14, 7, 16,\n                                  4, 65, 68, 73, 73, 22, 8, 3, 65, 5, 68, 73,\n                                  76, 2, 41, 24, 15, 8, 20, 6, 3, 1, 67, 62, 80,\n                                  71, 1, 66, 68, 1, 8, 9, 64, 8, 14, 17, 76, 71,\n                                  74, 65, 16, 67, 69, 2, 9, 17, 78, 70, 11, 13,\n                                  83, 82, 83, 78, 73, 1, 73, 68, 70, 65, 3, 74,\n                                  70, 69, 0, 79, 73, 80, 84, 65, 99, 76, 0, 70,\n                                  12, 70, 65, 20, 68, 70, 65, 16, 78, 74, 95,\n                                  26, 32, 33, 24, 12, 25, 21, 16, 15, 13, 12, 8,\n                                  73, 76, 83, 68, 65, 75, 92, 75, 75, 79, 78,\n                                  77, 72, 73, 87, 88, 83, 22, 21, 21, 15, 2, 9,\n                                  6, 70, 0, 69, 70, 82, 83, 83, 85, 5, 8, 76, 5,\n                                  4, 69, 75, 75, 77, 79, 79, 84, 93, 92, 98,\n                                  100, 106, 86, 96, 103, 83, 69, 75, 2, 3, 4,\n                                  48, 14, 13, 68, 23, 58, 44, 62, 13, 28, 21,\n                                  70, 90, 96, 101, 126, 124, 122, 68, 43, 27,\n                                  18, 9, 13, 2, 66, 68, 72, 76, 69, 5, 64, 14,\n                                  12, 4, 7, 12, 15, 16, 8, 19, 16, 0, 29, 23,\n                                  12, 5, 64, 70, 94, 97, 96 },\n\n                                {\n\n                                35,\n                                  5, 80, 35, 5, 80, 65, 10, 24, 12, 66, 83, 11,\n                                  18, 52, 14, 26, 67, 14, 23, 64, 75, 64, 87,\n                                  103, 1, 0, 123, 125, 123, 37, 3, 69, 14, 23,\n                                  64, 72, 6, 16, 64, 1, 67, 71, 68, 82, 75, 92,\n                                  5, 69, 72, 64, 77, 74, 88, 12, 0, 65, 69, 7,\n                                  3, 22, 0, 0, 0, 0, 94, 97, 7, 69, 68, 52, 6,\n                                  69, 89, 73, 82, 5, 2, 67, 4, 74, 8, 67, 68, 2,\n                                  85, 88, 87, 90, 27, 0, 12, 75, 0, 75, 68, 2,\n                                  71, 83, 75, 83, 16, 71, 3, 76, 77, 1, 70, 3,\n                                  9, 4, 6, 17, 14, 78, 66, 2, 66, 2, 73, 11, 67,\n                                  7, 19, 1, 16, 17, 9, 84, 10, 65, 80, 68, 92,\n                                  79, 67, 72, 1, 67, 66, 14, 64, 67, 5, 11, 72,\n                                  72, 0, 98, 84, 67, 95, 66, 76, 13, 64, 78, 23,\n                                  1, 65, 82, 24, 76, 89, 1, 98, 11, 22, 21, 17,\n                                  22, 16, 5, 19, 21, 76, 1, 10, 3, 1, 76, 64,\n                                  69, 71, 66, 72, 80, 67, 70, 99, 81, 76, 88,\n                                  83, 89, 26, 32, 24, 23, 22, 14, 10, 14, 4, 66,\n                                  2, 72, 83, 84, 106, 4, 1, 78, 64, 72, 75, 80,\n                                  83, 88, 91, 92, 107, 78, 96, 105, 94, 101, 64,\n                                  35, 24, 16, 6, 5, 65, 67, 71, 71, 7, 47, 31,\n                                  24, 17, 34, 13, 7, 0, 64, 65, 41, 25, 15, 7,\n                                  17, 5, 64, 68, 72, 72, 23, 9, 4, 65, 6, 67,\n                                  72, 75, 3, 41, 24, 15, 8, 21, 6, 4, 2, 66, 62,\n                                  79, 70, 2, 66, 68, 1, 8, 9, 64, 8, 14, 17, 76,\n                                  71, 74, 65, 17, 68, 70, 1, 8, 17, 79, 71, 11,\n                                  13, 83, 83, 83, 77, 72, 2, 72, 67, 69, 65, 4,\n                                  74, 70, 69, 1, 79, 73, 80, 83, 64, 99, 76, 0,\n                                  70, 13, 70, 65, 21, 68, 70, 65, 17, 79, 74,\n                                  96, 25, 31, 32, 23, 11, 24, 20, 15, 14, 12,\n                                  11, 7, 74, 77, 84, 69, 66, 76, 94, 77, 76, 80,\n                                  78, 78, 72, 73, 87, 88, 82, 20, 19, 19, 13,\n                                  64, 7, 4, 72, 65, 71, 72, 85, 85, 85, 86, 3,\n                                  7, 78, 3, 2, 71, 77, 77, 79, 81, 81, 86, 96,\n                                  94, 100, 102, 107, 88, 98, 104, 82, 68, 74, 3,\n                                  4, 5, 49, 15, 14, 68, 24, 60, 46, 62, 14, 26,\n                                  20, 72, 93, 99, 104, 126, 126, 123, 68, 43,\n                                  27, 18, 9, 13, 2, 66, 68, 72, 75, 68, 6, 0,\n                                  15, 12, 4, 8, 12, 15, 16, 8, 19, 16, 0, 28,\n                                  22, 10, 3, 66, 72, 96, 99, 97 },\n\n                                {\n\n                                33,\n                                  5, 80, 33, 5, 80, 64, 11, 24, 12, 66, 84, 10,\n                                  16, 52, 14, 29, 68, 15, 23, 64, 76, 64, 88,\n                                  104, 0, 65, 125, 126, 124, 40, 4, 69, 15, 23,\n                                  64, 72, 7, 16, 65, 1, 67, 71, 68, 82, 74, 92,\n                                  5, 69, 71, 65, 78, 74, 88, 12, 1, 65, 68, 7,\n                                  3, 22, 0, 0, 0, 1, 95, 97, 7, 70, 68, 52, 6,\n                                  69, 88, 72, 82, 5, 4, 66, 6, 73, 9, 66, 66, 4,\n                                  84, 88, 86, 90, 27, 0, 13, 74, 0, 75, 67, 4,\n                                  71, 83, 75, 82, 16, 70, 3, 75, 77, 1, 70, 4,\n                                  9, 4, 6, 17, 14, 79, 67, 2, 66, 2, 73, 11, 67,\n                                  6, 19, 1, 16, 17, 8, 86, 10, 65, 82, 69, 93,\n                                  78, 66, 71, 2, 67, 65, 15, 0, 67, 6, 12, 72,\n                                  72, 1, 99, 84, 66, 95, 66, 76, 13, 64, 79, 24,\n                                  1, 65, 84, 25, 77, 90, 1, 99, 9, 21, 20, 16,\n                                  21, 15, 4, 18, 21, 78, 0, 9, 3, 1, 76, 65, 69,\n                                  72, 66, 73, 81, 68, 71, 101, 82, 77, 89, 84,\n                                  89, 24, 31, 22, 21, 20, 12, 7, 12, 1, 68, 0,\n                                  75, 86, 86, 109, 2, 0, 80, 67, 74, 77, 82, 86,\n                                  90, 94, 94, 109, 79, 97, 107, 95, 101, 64, 35,\n                                  25, 16, 6, 5, 65, 67, 71, 70, 8, 48, 31, 24,\n                                  17, 35, 13, 8, 0, 0, 65, 42, 26, 15, 7, 17, 5,\n                                  64, 67, 71, 72, 24, 9, 4, 65, 7, 66, 72, 74,\n                                  3, 42, 24, 15, 8, 22, 7, 4, 3, 65, 62, 79, 70,\n                                  2, 66, 68, 1, 8, 9, 0, 8, 14, 18, 76, 71, 74,\n                                  66, 17, 69, 71, 0, 7, 17, 81, 72, 10, 13, 84,\n                                  84, 84, 77, 72, 3, 72, 67, 69, 64, 5, 75, 70,\n                                  69, 1, 80, 73, 80, 83, 0, 99, 76, 1, 70, 13,\n                                  70, 65, 22, 68, 71, 65, 18, 79, 75, 97, 24,\n                                  31, 32, 22, 10, 23, 19, 14, 13, 11, 10, 6, 75,\n                                  78, 85, 71, 68, 78, 96, 78, 77, 81, 79, 78,\n                                  72, 73, 87, 89, 82, 17, 16, 17, 10, 67, 5, 2,\n                                  75, 67, 73, 74, 87, 87, 86, 87, 1, 5, 79, 1,\n                                  0, 73, 79, 80, 81, 83, 83, 88, 98, 96, 102,\n                                  104, 108, 90, 100, 106, 81, 67, 73, 3, 5, 6,\n                                  51, 16, 15, 68, 25, 61, 47, 62, 14, 25, 18,\n                                  75, 96, 102, 107, 126, 126, 124, 68, 43, 27,\n                                  18, 9, 13, 2, 66, 68, 71, 74, 67, 7, 0, 16,\n                                  13, 5, 9, 13, 16, 17, 9, 20, 17, 0, 26, 20, 8,\n                                  1, 68, 74, 98, 101, 98 },\n\n                                {\n\n                                32,\n                                  5, 80, 32, 5, 80, 1, 13, 24, 12, 67, 86, 8,\n                                  15, 52, 14, 31, 68, 16, 24, 64, 76, 0, 89,\n                                  105, 0, 67, 126, 126, 124, 43, 6, 69, 16, 24,\n                                  64, 72, 8, 16, 65, 1, 67, 70, 68, 83, 74, 92,\n                                  5, 69, 70, 65, 78, 74, 88, 13, 1, 64, 68, 8,\n                                  3, 22, 0, 0, 0, 1, 95, 97, 8, 71, 68, 52, 6,\n                                  69, 87, 71, 82, 6, 5, 64, 8, 71, 10, 64, 65,\n                                  6, 83, 87, 85, 89, 28, 0, 14, 73, 0, 74, 66,\n                                  6, 71, 83, 74, 80, 17, 70, 4, 74, 76, 2, 70,\n                                  4, 10, 5, 7, 18, 15, 79, 67, 2, 66, 2, 73, 11,\n                                  68, 5, 19, 0, 16, 17, 8, 88, 10, 66, 83, 70,\n                                  94, 77, 65, 70, 3, 66, 64, 16, 1, 66, 7, 13,\n                                  72, 72, 1, 100, 83, 65, 95, 65, 76, 14, 64,\n                                  80, 25, 1, 65, 85, 26, 77, 91, 1, 99, 8, 20,\n                                  20, 15, 20, 14, 3, 18, 21, 79, 64, 9, 3, 1,\n                                  77, 65, 70, 73, 67, 74, 82, 68, 72, 103, 83,\n                                  78, 90, 85, 89, 22, 30, 20, 19, 19, 10, 5, 10,\n                                  64, 70, 65, 77, 88, 88, 111, 0, 65, 82, 69,\n                                  76, 79, 84, 88, 92, 97, 96, 112, 80, 99, 108,\n                                  95, 101, 64, 35, 25, 16, 6, 5, 65, 67, 71, 70,\n                                  8, 48, 31, 24, 17, 36, 14, 9, 0, 1, 64, 43,\n                                  27, 15, 8, 18, 6, 0, 67, 70, 71, 26, 10, 4,\n                                  64, 8, 65, 71, 73, 4, 42, 25, 15, 8, 23, 8, 5,\n                                  4, 64, 62, 79, 70, 3, 66, 68, 1, 8, 9, 0, 8,\n                                  15, 18, 76, 71, 74, 67, 18, 70, 72, 64, 7, 17,\n                                  82, 73, 10, 13, 85, 85, 84, 76, 71, 4, 71, 66,\n                                  68, 64, 6, 75, 70, 69, 1, 81, 73, 80, 82, 1,\n                                  99, 76, 1, 70, 14, 70, 65, 23, 68, 71, 65, 19,\n                                  80, 75, 97, 23, 31, 31, 22, 9, 22, 18, 13, 13,\n                                  10, 9, 5, 76, 79, 86, 72, 69, 79, 98, 79, 78,\n                                  82, 80, 79, 72, 72, 87, 89, 81, 15, 14, 15, 8,\n                                  69, 3, 0, 77, 69, 75, 76, 89, 89, 88, 88, 64,\n                                  3, 80, 64, 65, 75, 81, 82, 83, 85, 85, 90,\n                                  101, 98, 104, 106, 109, 92, 102, 107, 80, 65,\n                                  72, 4, 6, 7, 53, 17, 16, 68, 26, 62, 49, 62,\n                                  15, 23, 16, 77, 99, 104, 110, 126, 126, 125,\n                                  68, 43, 27, 18, 9, 13, 2, 66, 68, 71, 73, 66,\n                                  8, 1, 17, 14, 5, 10, 14, 17, 18, 9, 20, 17, 0,\n                                  25, 19, 7, 0, 70, 76, 100, 103, 99 },\n\n                                {\n\n                                31,\n                                  5, 81, 31, 5, 81, 3, 14, 25, 12, 67, 87, 7,\n                                  14, 52, 14, 33, 68, 16, 25, 64, 77, 0, 90,\n                                  106, 64, 68, 126, 126, 125, 46, 7, 69, 16, 25,\n                                  64, 71, 9, 17, 66, 2, 66, 69, 69, 83, 74, 92,\n                                  5, 68, 70, 65, 78, 73, 88, 13, 1, 64, 68, 8,\n                                  3, 22, 0, 0, 0, 2, 95, 97, 8, 71, 69, 52, 6,\n                                  69, 86, 71, 82, 6, 6, 1, 10, 70, 11, 1, 64, 8,\n                                  82, 86, 84, 88, 29, 0, 15, 73, 1, 74, 66, 8,\n                                  71, 82, 74, 79, 17, 70, 4, 72, 76, 3, 69, 4,\n                                  10, 5, 8, 18, 15, 80, 67, 2, 66, 2, 73, 11,\n                                  68, 5, 19, 64, 16, 17, 8, 90, 10, 66, 85, 71,\n                                  95, 77, 64, 70, 3, 65, 64, 17, 1, 66, 7, 15,\n                                  72, 72, 1, 101, 83, 64, 95, 65, 76, 15, 0, 81,\n                                  25, 1, 65, 86, 27, 78, 92, 1, 100, 6, 19, 19,\n                                  15, 19, 14, 3, 17, 20, 80, 65, 9, 3, 1, 77,\n                                  66, 71, 74, 68, 74, 83, 69, 72, 105, 84, 78,\n                                  91, 86, 89, 21, 28, 19, 17, 17, 8, 3, 8, 67,\n                                  73, 67, 80, 91, 91, 114, 65, 67, 83, 71, 79,\n                                  82, 87, 90, 95, 99, 99, 114, 81, 101, 109, 96,\n                                  101, 0, 36, 25, 17, 6, 5, 65, 67, 71, 69, 8,\n                                  48, 32, 24, 17, 37, 14, 9, 1, 1, 0, 44, 27,\n                                  16, 8, 19, 6, 0, 66, 69, 70, 27, 11, 5, 64, 8,\n                                  65, 70, 71, 4, 42, 25, 15, 9, 23, 8, 6, 4, 0,\n                                  62, 78, 69, 3, 66, 68, 1, 8, 9, 0, 9, 15, 19,\n                                  76, 71, 75, 67, 18, 71, 73, 65, 6, 17, 83, 74,\n                                  10, 13, 85, 86, 85, 75, 70, 5, 71, 66, 68, 0,\n                                  6, 75, 69, 68, 2, 81, 73, 80, 82, 2, 99, 76,\n                                  1, 70, 15, 70, 65, 24, 69, 71, 65, 19, 81, 75,\n                                  98, 22, 30, 31, 21, 8, 22, 18, 12, 12, 10, 8,\n                                  4, 77, 80, 87, 74, 70, 81, 100, 81, 80, 83,\n                                  80, 79, 72, 72, 86, 90, 80, 13, 12, 13, 6, 72,\n                                  1, 65, 80, 71, 78, 78, 92, 91, 89, 88, 65, 2,\n                                  82, 66, 68, 77, 83, 84, 85, 87, 88, 92, 103,\n                                  100, 106, 107, 111, 94, 104, 109, 79, 64, 71,\n                                  5, 7, 8, 54, 18, 17, 68, 27, 62, 50, 62, 16,\n                                  22, 15, 80, 102, 107, 112, 126, 126, 126, 67,\n                                  43, 27, 18, 9, 13, 2, 66, 68, 70, 72, 66, 9,\n                                  2, 18, 14, 6, 11, 14, 17, 18, 9, 21, 17, 0,\n                                  24, 17, 5, 65, 71, 77, 103, 104, 100 },\n\n                                {\n\n                                30,\n                                  5, 81, 30, 5, 81, 5, 16, 25, 12, 68, 89, 5,\n                                  12, 52, 14, 36, 69, 17, 25, 64, 78, 0, 91,\n                                  107, 64, 70, 126, 126, 125, 49, 8, 69, 17, 25,\n                                  64, 71, 10, 17, 66, 2, 66, 69, 69, 84, 73, 92,\n                                  5, 68, 69, 66, 78, 73, 88, 14, 2, 64, 67, 9,\n                                  3, 22, 0, 0, 0, 2, 95, 97, 9, 72, 69, 52, 6,\n                                  69, 85, 70, 82, 7, 8, 2, 12, 68, 12, 2, 1, 10,\n                                  81, 85, 83, 88, 30, 0, 16, 72, 1, 73, 65, 10,\n                                  71, 82, 73, 78, 17, 69, 5, 71, 75, 3, 69, 5,\n                                  10, 5, 9, 19, 16, 80, 68, 2, 66, 2, 73, 11,\n                                  69, 4, 19, 64, 16, 17, 7, 92, 10, 67, 87, 72,\n                                  96, 76, 0, 69, 4, 64, 0, 18, 2, 65, 8, 16, 72,\n                                  72, 2, 102, 82, 0, 95, 65, 76, 15, 0, 82, 26,\n                                  1, 65, 88, 28, 78, 93, 1, 101, 5, 18, 19, 14,\n                                  18, 13, 2, 16, 20, 81, 66, 9, 3, 1, 78, 67,\n                                  71, 75, 68, 75, 84, 70, 73, 107, 85, 79, 92,\n                                  87, 89, 19, 27, 17, 15, 15, 6, 0, 6, 69, 75,\n                                  69, 82, 93, 93, 116, 67, 68, 85, 74, 81, 84,\n                                  89, 93, 97, 102, 101, 117, 82, 102, 111, 97,\n                                  101, 0, 36, 26, 17, 6, 5, 65, 67, 71, 69, 9,\n                                  49, 32, 24, 17, 38, 15, 10, 1, 2, 1, 45, 28,\n                                  16, 8, 20, 7, 1, 66, 68, 70, 28, 11, 5, 64, 9,\n                                  64, 70, 70, 5, 43, 25, 15, 9, 24, 9, 7, 5, 1,\n                                  62, 78, 69, 4, 66, 68, 1, 8, 9, 1, 9, 15, 19,\n                                  76, 71, 75, 68, 19, 72, 74, 66, 5, 17, 84, 75,\n                                  9, 13, 86, 87, 85, 74, 70, 6, 70, 65, 67, 0,\n                                  7, 75, 69, 68, 2, 82, 73, 80, 81, 3, 99, 76,\n                                  2, 70, 15, 70, 65, 25, 69, 71, 65, 20, 81, 76,\n                                  99, 21, 30, 30, 20, 7, 21, 17, 11, 11, 9, 7,\n                                  3, 78, 81, 88, 75, 72, 82, 102, 82, 81, 84,\n                                  81, 80, 72, 72, 86, 90, 79, 11, 10, 11, 3, 75,\n                                  64, 67, 82, 73, 80, 80, 94, 93, 91, 89, 67, 0,\n                                  83, 68, 70, 79, 85, 86, 87, 89, 90, 94, 106,\n                                  102, 108, 109, 112, 96, 106, 110, 78, 0, 70,\n                                  5, 8, 9, 56, 19, 18, 68, 28, 62, 52, 62, 16,\n                                  20, 13, 82, 105, 110, 115, 126, 126, 126, 67,\n                                  43, 27, 18, 9, 13, 2, 66, 68, 70, 71, 65, 10,\n                                  3, 19, 15, 6, 12, 15, 18, 19, 10, 21, 18, 0,\n                                  22, 16, 3, 67, 73, 79, 105, 106, 101 },\n\n                                {\n\n                                28,\n                                  4, 81, 28, 4, 81, 6, 17, 25, 12, 68, 90, 4,\n                                  11, 52, 14, 38, 69, 18, 26, 64, 79, 0, 92,\n                                  109, 65, 72, 126, 126, 126, 51, 9, 69, 18, 26,\n                                  64, 71, 11, 17, 67, 2, 66, 68, 70, 84, 73, 93,\n                                  5, 68, 69, 66, 79, 73, 88, 14, 2, 64, 67, 9,\n                                  3, 22, 0, 0, 0, 3, 96, 97, 9, 73, 69, 52, 6,\n                                  69, 84, 69, 82, 7, 9, 4, 14, 67, 13, 4, 2, 11,\n                                  80, 85, 82, 87, 30, 0, 17, 71, 1, 73, 65, 11,\n                                  71, 82, 73, 77, 17, 69, 5, 70, 75, 4, 69, 5,\n                                  10, 5, 9, 19, 16, 81, 68, 2, 66, 2, 73, 11,\n                                  69, 3, 19, 65, 16, 17, 7, 94, 10, 67, 89, 73,\n                                  97, 75, 1, 68, 5, 64, 0, 19, 2, 65, 9, 17, 72,\n                                  72, 2, 104, 82, 1, 95, 65, 77, 16, 0, 83, 27,\n                                  1, 65, 89, 29, 79, 94, 1, 102, 3, 17, 18, 13,\n                                  17, 12, 1, 15, 19, 83, 67, 8, 3, 1, 78, 68,\n                                  72, 76, 69, 76, 85, 71, 74, 109, 87, 80, 93,\n                                  88, 89, 17, 25, 15, 13, 13, 4, 65, 4, 72, 78,\n                                  71, 85, 96, 96, 119, 69, 70, 87, 76, 83, 87,\n                                  92, 95, 100, 105, 103, 119, 83, 104, 112, 98,\n                                  102, 0, 36, 26, 17, 6, 5, 65, 67, 71, 68, 9,\n                                  49, 32, 24, 17, 39, 15, 10, 1, 2, 1, 46, 28,\n                                  16, 8, 20, 7, 1, 65, 67, 69, 29, 12, 5, 64,\n                                  10, 0, 69, 69, 5, 43, 25, 15, 9, 25, 9, 7, 6,\n                                  1, 62, 78, 69, 4, 66, 68, 1, 8, 9, 1, 9, 15,\n                                  20, 76, 71, 75, 69, 19, 73, 75, 67, 4, 17, 86,\n                                  77, 9, 13, 87, 88, 86, 74, 69, 7, 70, 65, 67,\n                                  1, 8, 76, 69, 68, 2, 83, 73, 80, 81, 3, 100,\n                                  76, 2, 70, 16, 70, 65, 25, 69, 72, 65, 21, 82,\n                                  76, 100, 20, 29, 30, 19, 5, 20, 16, 10, 10, 8,\n                                  6, 2, 79, 82, 89, 77, 73, 84, 104, 84, 82, 85,\n                                  82, 80, 72, 72, 86, 91, 79, 8, 7, 9, 1, 78,\n                                  67, 70, 85, 75, 82, 82, 97, 95, 92, 90, 69,\n                                  65, 85, 70, 72, 82, 88, 89, 90, 91, 92, 97,\n                                  108, 104, 111, 111, 113, 98, 108, 112, 77, 1,\n                                  69, 6, 9, 9, 57, 20, 18, 68, 28, 62, 53, 62,\n                                  17, 19, 11, 85, 108, 113, 118, 126, 126, 126,\n                                  67, 43, 27, 18, 9, 13, 2, 66, 68, 69, 71, 64,\n                                  11, 3, 20, 15, 7, 12, 15, 18, 19, 10, 22, 18,\n                                  64, 21, 14, 1, 69, 75, 81, 107, 108, 102 },\n\n                                {\n\n                                27,\n                                  4, 81, 27, 4, 81, 8, 18, 26, 12, 68, 91, 3,\n                                  10, 52, 14, 40, 69, 19, 27, 64, 79, 1, 93,\n                                  110, 66, 74, 126, 126, 126, 54, 11, 69, 19,\n                                  27, 64, 70, 12, 18, 68, 2, 65, 67, 70, 84, 73,\n                                  93, 5, 68, 68, 66, 79, 73, 88, 14, 2, 0, 67,\n                                  9, 3, 22, 0, 0, 0, 4, 96, 97, 9, 74, 69, 52,\n                                  6, 69, 83, 68, 82, 7, 10, 6, 16, 65, 15, 6, 3,\n                                  13, 79, 84, 81, 86, 31, 1, 18, 70, 1, 72, 64,\n                                  13, 71, 81, 73, 75, 18, 69, 5, 68, 75, 5, 69,\n                                  5, 11, 6, 10, 19, 16, 81, 68, 3, 66, 2, 72,\n                                  11, 69, 3, 19, 66, 16, 17, 7, 96, 10, 67, 90,\n                                  74, 97, 74, 2, 67, 6, 0, 1, 20, 3, 65, 10, 18,\n                                  72, 72, 2, 105, 81, 2, 95, 64, 77, 17, 0, 84,\n                                  28, 1, 65, 90, 30, 80, 95, 1, 102, 2, 16, 18,\n                                  12, 16, 11, 1, 15, 19, 84, 68, 8, 3, 1, 78,\n                                  68, 73, 77, 70, 77, 86, 71, 74, 110, 88, 80,\n                                  94, 89, 89, 16, 24, 14, 12, 12, 2, 67, 2, 74,\n                                  80, 73, 87, 99, 98, 122, 70, 72, 88, 78, 85,\n                                  89, 94, 97, 102, 107, 105, 121, 83, 106, 113,\n                                  98, 102, 0, 37, 26, 17, 7, 5, 65, 66, 71, 67,\n                                  9, 49, 32, 25, 17, 40, 16, 11, 2, 3, 2, 47,\n                                  29, 17, 9, 21, 8, 1, 64, 66, 68, 31, 13, 6, 0,\n                                  11, 1, 68, 68, 6, 43, 26, 16, 9, 26, 10, 8, 7,\n                                  2, 62, 77, 68, 5, 66, 68, 1, 9, 10, 1, 9, 16,\n                                  21, 76, 71, 75, 69, 19, 74, 75, 68, 4, 17, 87,\n                                  78, 9, 13, 87, 89, 87, 73, 68, 8, 70, 64, 67,\n                                  2, 9, 76, 69, 68, 3, 83, 73, 80, 81, 4, 100,\n                                  76, 2, 70, 17, 70, 65, 26, 69, 72, 65, 22, 83,\n                                  76, 100, 19, 29, 30, 19, 4, 19, 15, 9, 10, 7,\n                                  5, 2, 79, 83, 90, 78, 74, 86, 106, 85, 83, 85,\n                                  82, 80, 71, 71, 86, 92, 78, 6, 5, 7, 64, 80,\n                                  69, 72, 87, 77, 84, 84, 99, 97, 93, 91, 71,\n                                  66, 86, 72, 74, 84, 90, 91, 92, 93, 94, 99,\n                                  110, 105, 113, 113, 114, 100, 110, 114, 76, 3,\n                                  67, 7, 10, 10, 59, 21, 19, 68, 29, 62, 54, 62,\n                                  18, 18, 10, 87, 111, 115, 121, 126, 126, 126,\n                                  67, 43, 27, 18, 9, 14, 2, 66, 68, 68, 70, 0,\n                                  12, 4, 22, 16, 8, 13, 16, 19, 20, 10, 23, 18,\n                                  64, 20, 13, 0, 70, 77, 83, 109, 110, 102 },\n\n                                {\n\n                                26,\n                                  4, 81, 26, 4, 81, 10, 20, 26, 12, 69, 93, 1,\n                                  8, 52, 14, 43, 70, 20, 27, 64, 80, 1, 94, 111,\n                                  66, 76, 126, 126, 126, 57, 12, 69, 20, 27, 64,\n                                  70, 13, 18, 68, 2, 65, 67, 70, 85, 72, 93, 5,\n                                  68, 67, 67, 79, 73, 88, 15, 3, 0, 66, 10, 3,\n                                  22, 0, 0, 0, 4, 96, 97, 10, 75, 69, 52, 6, 69,\n                                  82, 67, 82, 8, 12, 7, 18, 64, 16, 7, 5, 15,\n                                  78, 83, 80, 86, 32, 1, 19, 69, 1, 72, 0, 15,\n                                  71, 81, 72, 74, 18, 68, 6, 67, 74, 5, 69, 6,\n                                  11, 6, 11, 20, 17, 82, 69, 3, 66, 2, 72, 11,\n                                  70, 2, 19, 66, 16, 17, 6, 98, 10, 68, 92, 75,\n                                  98, 73, 3, 66, 7, 1, 2, 21, 4, 64, 11, 19, 72,\n                                  72, 3, 106, 81, 3, 95, 64, 77, 17, 0, 85, 29,\n                                  1, 65, 92, 31, 80, 96, 1, 103, 0, 15, 17, 11,\n                                  15, 10, 0, 14, 19, 85, 69, 8, 3, 1, 79, 69,\n                                  73, 78, 70, 78, 87, 72, 75, 112, 89, 81, 95,\n                                  90, 89, 14, 23, 12, 10, 10, 0, 70, 0, 77, 82,\n                                  75, 90, 101, 100, 124, 72, 73, 90, 81, 87, 91,\n                                  96, 100, 104, 110, 107, 124, 84, 107, 115, 99,\n                                  102, 0, 37, 27, 17, 7, 5, 65, 66, 71, 67, 10,\n                                  50, 32, 25, 17, 41, 16, 12, 2, 4, 3, 48, 30,\n                                  17, 9, 22, 8, 2, 64, 65, 68, 32, 13, 6, 0, 12,\n                                  2, 68, 67, 6, 44, 26, 16, 9, 27, 11, 9, 8, 3,\n                                  62, 77, 68, 5, 66, 68, 1, 9, 10, 2, 9, 16, 21,\n                                  76, 71, 75, 70, 20, 75, 76, 69, 3, 17, 88, 79,\n                                  8, 13, 88, 90, 87, 72, 68, 9, 69, 64, 66, 2,\n                                  10, 76, 69, 68, 3, 84, 73, 80, 80, 5, 100, 76,\n                                  3, 70, 17, 70, 65, 27, 69, 72, 65, 23, 83, 77,\n                                  101, 18, 29, 29, 18, 3, 18, 14, 8, 9, 6, 4, 1,\n                                  80, 84, 91, 80, 76, 87, 108, 86, 84, 86, 83,\n                                  81, 71, 71, 86, 92, 77, 4, 3, 5, 67, 83, 71,\n                                  74, 90, 79, 86, 86, 101, 99, 95, 92, 73, 68,\n                                  87, 74, 76, 86, 92, 93, 94, 95, 96, 101, 113,\n                                  107, 115, 115, 115, 102, 112, 115, 75, 4, 66,\n                                  7, 11, 11, 61, 22, 20, 68, 30, 62, 56, 62, 18,\n                                  16, 8, 90, 114, 118, 124, 126, 126, 126, 67,\n                                  43, 27, 18, 9, 14, 2, 66, 68, 68, 69, 1, 13,\n                                  5, 23, 17, 8, 14, 17, 20, 21, 11, 23, 19, 64,\n                                  18, 11, 65, 72, 79, 85, 111, 112, 103 },\n\n                                {\n\n                                25,\n                                  4, 82, 25, 4, 82, 12, 21, 27, 12, 69, 94, 0,\n                                  7, 52, 14, 45, 70, 20, 28, 64, 81, 1, 95, 112,\n                                  67, 77, 126, 126, 126, 60, 13, 69, 20, 28, 64,\n                                  69, 14, 19, 69, 3, 64, 66, 71, 85, 72, 93, 5,\n                                  67, 67, 67, 79, 72, 88, 15, 3, 0, 66, 10, 3,\n                                  22, 0, 0, 0, 5, 96, 97, 10, 75, 70, 52, 6, 69,\n                                  81, 67, 82, 8, 13, 9, 20, 1, 17, 9, 6, 17, 77,\n                                  82, 79, 85, 33, 1, 20, 69, 2, 71, 0, 17, 71,\n                                  80, 72, 73, 18, 68, 6, 65, 74, 6, 68, 6, 11,\n                                  6, 12, 20, 17, 82, 69, 3, 66, 2, 72, 11, 70,\n                                  2, 19, 67, 16, 17, 6, 100, 10, 68, 94, 76, 99,\n                                  73, 4, 66, 7, 2, 2, 22, 4, 64, 11, 21, 72, 72,\n                                  3, 107, 80, 4, 95, 64, 77, 18, 1, 86, 29, 1,\n                                  65, 93, 32, 81, 97, 1, 104, 64, 14, 17, 11,\n                                  14, 10, 0, 13, 18, 86, 70, 8, 3, 1, 79, 70,\n                                  74, 79, 71, 78, 88, 73, 75, 114, 90, 81, 96,\n                                  91, 89, 13, 21, 11, 8, 8, 65, 72, 65, 79, 85,\n                                  77, 92, 104, 103, 126, 74, 75, 91, 83, 90, 94,\n                                  99, 102, 107, 112, 110, 126, 85, 109, 116,\n                                  100, 102, 1, 38, 27, 18, 7, 5, 65, 66, 71, 66,\n                                  10, 50, 33, 25, 17, 42, 17, 12, 3, 4, 4, 49,\n                                  30, 18, 9, 23, 9, 2, 0, 64, 67, 33, 14, 7, 0,\n                                  12, 2, 67, 65, 7, 44, 26, 16, 10, 27, 11, 10,\n                                  8, 4, 62, 76, 67, 6, 66, 68, 1, 9, 10, 2, 10,\n                                  16, 22, 76, 71, 76, 70, 20, 76, 77, 70, 2, 17,\n                                  89, 80, 8, 13, 88, 91, 88, 71, 67, 10, 69, 0,\n                                  66, 3, 10, 76, 68, 67, 4, 84, 73, 80, 80, 6,\n                                  100, 76, 3, 70, 18, 70, 65, 28, 70, 72, 65,\n                                  23, 84, 77, 102, 17, 28, 29, 17, 2, 18, 14, 7,\n                                  8, 6, 3, 0, 81, 85, 92, 81, 77, 89, 110, 88,\n                                  86, 87, 83, 81, 71, 71, 85, 93, 76, 2, 1, 3,\n                                  69, 86, 73, 76, 92, 81, 89, 88, 104, 101, 96,\n                                  92, 74, 69, 89, 76, 79, 88, 94, 95, 96, 97,\n                                  99, 103, 115, 109, 117, 116, 117, 104, 114,\n                                  117, 74, 5, 65, 8, 12, 12, 62, 23, 21, 68, 31,\n                                  62, 57, 62, 19, 15, 7, 92, 117, 121, 126, 126,\n                                  126, 126, 66, 43, 27, 18, 9, 14, 2, 66, 68,\n                                  67, 68, 1, 14, 6, 24, 17, 9, 15, 17, 20, 21,\n                                  11, 24, 19, 64, 17, 10, 67, 74, 80, 86, 114,\n                                  113, 104 },\n\n                                {\n\n                                23,\n                                  4, 82, 23, 4, 82, 13, 23, 27, 12, 70, 96, 65,\n                                  6, 52, 14, 47, 70, 21, 29, 64, 82, 1, 96, 113,\n                                  67, 79, 126, 126, 126, 62, 14, 69, 21, 29, 64,\n                                  69, 15, 19, 69, 3, 64, 65, 71, 86, 72, 93, 5,\n                                  67, 66, 67, 80, 72, 88, 16, 3, 0, 66, 11, 3,\n                                  22, 0, 0, 0, 5, 97, 97, 11, 76, 70, 52, 6, 69,\n                                  80, 66, 82, 9, 14, 11, 22, 2, 18, 11, 7, 19,\n                                  76, 82, 78, 84, 33, 1, 21, 68, 2, 71, 1, 19,\n                                  71, 80, 71, 72, 18, 68, 7, 64, 73, 7, 68, 6,\n                                  11, 6, 12, 21, 18, 83, 69, 3, 66, 2, 72, 11,\n                                  71, 1, 19, 68, 16, 17, 6, 102, 10, 69, 96, 77,\n                                  100, 72, 5, 65, 8, 2, 3, 23, 5, 0, 12, 22, 72,\n                                  72, 3, 108, 80, 5, 95, 64, 77, 19, 1, 87, 30,\n                                  1, 65, 94, 33, 81, 98, 1, 105, 66, 13, 16, 10,\n                                  13, 9, 64, 12, 18, 88, 71, 7, 3, 1, 80, 71,\n                                  75, 80, 72, 79, 89, 74, 76, 116, 91, 82, 97,\n                                  92, 89, 11, 20, 9, 6, 6, 67, 74, 67, 82, 87,\n                                  79, 95, 106, 105, 126, 76, 77, 93, 85, 92, 96,\n                                  101, 104, 109, 115, 112, 126, 86, 111, 117,\n                                  101, 102, 1, 38, 27, 18, 7, 5, 65, 66, 71, 66,\n                                  10, 50, 33, 25, 17, 43, 17, 13, 3, 5, 4, 50,\n                                  31, 18, 9, 23, 9, 3, 0, 0, 66, 34, 15, 7, 0,\n                                  13, 3, 66, 64, 7, 44, 26, 16, 10, 28, 12, 10,\n                                  9, 5, 62, 76, 67, 6, 66, 68, 1, 9, 10, 2, 10,\n                                  16, 22, 76, 71, 76, 71, 21, 77, 78, 71, 1, 17,\n                                  91, 81, 8, 13, 89, 92, 88, 71, 66, 11, 68, 0,\n                                  65, 3, 11, 77, 68, 67, 4, 85, 73, 80, 79, 7,\n                                  100, 76, 3, 70, 19, 70, 65, 29, 70, 73, 65,\n                                  24, 85, 77, 103, 16, 28, 28, 16, 1, 17, 13, 6,\n                                  7, 5, 2, 64, 82, 86, 93, 83, 78, 90, 112, 89,\n                                  87, 88, 84, 82, 71, 71, 85, 93, 76, 64, 65, 1,\n                                  71, 89, 75, 78, 95, 83, 91, 90, 106, 103, 98,\n                                  93, 76, 71, 90, 78, 81, 90, 96, 98, 98, 99,\n                                  101, 105, 118, 111, 119, 118, 118, 106, 116,\n                                  118, 73, 6, 64, 9, 13, 13, 62, 24, 22, 68, 32,\n                                  62, 59, 62, 20, 13, 5, 95, 120, 124, 126, 126,\n                                  126, 126, 66, 43, 27, 18, 9, 14, 2, 66, 68,\n                                  67, 67, 2, 15, 6, 25, 18, 9, 16, 18, 21, 22,\n                                  11, 24, 19, 64, 16, 8, 69, 76, 82, 88, 116,\n                                  115, 105 },\n\n                                {\n\n                                22,\n                                  4, 82, 22, 4, 82, 15, 24, 27, 12, 70, 97, 66,\n                                  4, 52, 14, 50, 71, 22, 29, 64, 82, 2, 97, 114,\n                                  68, 81, 126, 126, 126, 62, 16, 69, 22, 29, 64,\n                                  69, 16, 19, 70, 3, 64, 65, 71, 86, 71, 93, 5,\n                                  67, 65, 68, 80, 72, 88, 16, 4, 1, 65, 11, 3,\n                                  22, 0, 0, 0, 6, 97, 97, 11, 77, 70, 52, 6, 69,\n                                  79, 65, 82, 9, 16, 12, 24, 4, 19, 12, 9, 21,\n                                  75, 81, 77, 84, 34, 1, 22, 67, 2, 70, 2, 21,\n                                  71, 80, 71, 70, 19, 67, 7, 0, 73, 7, 68, 7,\n                                  12, 7, 13, 21, 18, 83, 70, 3, 66, 2, 72, 11,\n                                  71, 0, 19, 68, 16, 17, 5, 104, 10, 69, 97, 78,\n                                  101, 71, 6, 64, 9, 3, 4, 24, 6, 0, 13, 23, 72,\n                                  72, 4, 109, 79, 6, 95, 0, 77, 19, 1, 88, 31,\n                                  1, 65, 96, 34, 82, 99, 1, 105, 67, 12, 16, 9,\n                                  12, 8, 65, 12, 18, 89, 72, 7, 3, 1, 80, 71,\n                                  75, 81, 72, 80, 90, 74, 77, 118, 92, 83, 98,\n                                  93, 89, 9, 19, 7, 4, 5, 69, 77, 69, 84, 89,\n                                  81, 97, 109, 107, 126, 78, 78, 95, 88, 94, 98,\n                                  103, 107, 111, 118, 114, 126, 87, 112, 119,\n                                  101, 102, 1, 38, 28, 18, 7, 5, 65, 66, 71, 65,\n                                  11, 51, 33, 25, 17, 44, 18, 14, 3, 6, 5, 51,\n                                  32, 18, 10, 24, 10, 3, 1, 1, 66, 36, 15, 7, 1,\n                                  14, 4, 66, 0, 8, 45, 27, 16, 10, 29, 13, 11,\n                                  10, 6, 62, 76, 67, 7, 66, 68, 1, 9, 10, 3, 10,\n                                  17, 23, 76, 71, 76, 72, 21, 78, 79, 72, 1, 17,\n                                  92, 82, 7, 13, 90, 93, 89, 70, 66, 12, 68, 1,\n                                  65, 4, 12, 77, 68, 67, 4, 86, 73, 80, 79, 8,\n                                  100, 76, 4, 70, 19, 70, 65, 30, 70, 73, 65,\n                                  25, 85, 78, 103, 15, 28, 28, 16, 0, 16, 12, 5,\n                                  7, 4, 1, 65, 83, 87, 94, 84, 80, 92, 114, 90,\n                                  88, 89, 85, 82, 71, 70, 85, 94, 75, 66, 67,\n                                  64, 74, 91, 77, 80, 97, 85, 93, 92, 108, 105,\n                                  99, 94, 78, 73, 91, 80, 83, 92, 98, 100, 100,\n                                  101, 103, 107, 120, 113, 121, 120, 119, 108,\n                                  118, 120, 72, 8, 0, 9, 14, 14, 62, 25, 23, 68,\n                                  33, 62, 60, 62, 20, 12, 3, 97, 123, 126, 126,\n                                  126, 126, 126, 66, 43, 27, 18, 9, 14, 2, 66,\n                                  68, 66, 66, 3, 16, 7, 26, 19, 10, 17, 19, 22,\n                                  23, 12, 25, 20, 64, 14, 7, 70, 77, 84, 90,\n                                  118, 117, 106 },\n\n                                {\n\n                                21,\n                                  4, 82, 21, 4, 82, 17, 26, 28, 12, 71, 99, 68,\n                                  3, 52, 14, 52, 71, 23, 30, 64, 83, 2, 98, 115,\n                                  68, 83, 126, 126, 126, 62, 17, 69, 23, 30, 64,\n                                  68, 17, 20, 70, 3, 0, 64, 72, 87, 71, 93, 5,\n                                  67, 65, 68, 80, 72, 88, 17, 4, 1, 65, 12, 3,\n                                  22, 0, 0, 0, 6, 97, 97, 12, 78, 70, 52, 6, 69,\n                                  78, 64, 82, 10, 17, 14, 26, 5, 20, 14, 10, 23,\n                                  74, 80, 76, 83, 35, 1, 23, 66, 2, 70, 2, 23,\n                                  71, 79, 70, 69, 19, 67, 8, 2, 72, 8, 68, 7,\n                                  12, 7, 14, 22, 19, 84, 70, 3, 66, 2, 72, 11,\n                                  72, 0, 19, 69, 16, 17, 5, 106, 10, 70, 99, 79,\n                                  102, 70, 7, 0, 10, 4, 4, 25, 6, 1, 14, 24, 72,\n                                  72, 4, 110, 79, 7, 95, 0, 77, 20, 1, 89, 32,\n                                  1, 65, 97, 35, 82, 100, 1, 106, 69, 11, 15, 8,\n                                  11, 7, 65, 11, 17, 90, 73, 7, 3, 1, 81, 72,\n                                  76, 82, 73, 81, 91, 75, 77, 120, 93, 83, 99,\n                                  94, 89, 8, 17, 6, 2, 3, 71, 79, 71, 87, 92,\n                                  83, 100, 111, 110, 126, 80, 80, 96, 90, 96,\n                                  101, 106, 109, 114, 120, 116, 126, 88, 114,\n                                  120, 102, 102, 1, 39, 28, 18, 7, 5, 65, 66,\n                                  71, 65, 11, 51, 33, 25, 17, 45, 18, 14, 4, 6,\n                                  6, 52, 32, 19, 10, 25, 10, 4, 1, 2, 65, 37,\n                                  16, 8, 1, 15, 5, 65, 1, 8, 45, 27, 16, 10, 30,\n                                  13, 12, 11, 7, 62, 75, 66, 7, 66, 68, 1, 9,\n                                  10, 3, 10, 17, 23, 76, 71, 76, 72, 22, 79, 80,\n                                  73, 0, 17, 93, 83, 7, 13, 90, 94, 89, 69, 65,\n                                  13, 67, 1, 64, 4, 13, 77, 68, 67, 5, 86, 73,\n                                  80, 78, 9, 100, 76, 4, 70, 20, 70, 65, 31, 70,\n                                  73, 65, 26, 86, 78, 104, 14, 27, 27, 15, 64,\n                                  15, 11, 4, 6, 3, 0, 66, 84, 88, 95, 86, 81,\n                                  93, 116, 92, 89, 90, 85, 83, 71, 70, 85, 94,\n                                  74, 68, 69, 66, 76, 94, 79, 82, 100, 87, 95,\n                                  94, 111, 107, 101, 95, 80, 74, 93, 82, 85, 94,\n                                  100, 102, 102, 103, 105, 109, 123, 115, 123,\n                                  122, 120, 110, 120, 121, 71, 9, 1, 10, 15, 15,\n                                  62, 26, 24, 68, 34, 62, 62, 62, 21, 10, 2,\n                                  100, 126, 126, 126, 126, 126, 126, 66, 43, 27,\n                                  18, 9, 14, 2, 66, 68, 66, 65, 4, 17, 8, 27,\n                                  19, 10, 18, 19, 22, 23, 12, 25, 20, 64, 13, 5,\n                                  72, 79, 86, 92, 120, 119, 107 },\n\n                                {\n\n                                20,\n                                  4, 82, 20, 4, 82, 19, 27, 28, 12, 71, 100, 69,\n                                  2, 52, 14, 54, 71, 24, 31, 64, 84, 2, 99, 116,\n                                  69, 85, 126, 126, 126, 62, 18, 69, 24, 31, 64,\n                                  68, 18, 20, 71, 3, 0, 0, 72, 87, 71, 93, 5,\n                                  67, 64, 68, 80, 72, 88, 17, 4, 1, 65, 12, 3,\n                                  22, 0, 0, 0, 7, 97, 97, 12, 79, 70, 52, 6, 69,\n                                  77, 0, 82, 10, 18, 16, 28, 7, 21, 16, 11, 25,\n                                  73, 79, 75, 82, 36, 1, 24, 65, 2, 69, 3, 25,\n                                  71, 79, 70, 68, 19, 67, 8, 3, 72, 9, 68, 7,\n                                  12, 7, 15, 22, 19, 84, 70, 3, 66, 2, 72, 11,\n                                  72, 64, 19, 70, 16, 17, 5, 108, 10, 70, 101,\n                                  80, 103, 69, 8, 1, 11, 5, 5, 26, 7, 1, 15, 25,\n                                  72, 72, 4, 111, 78, 8, 95, 0, 77, 21, 1, 90,\n                                  33, 1, 65, 98, 36, 83, 101, 1, 107, 70, 10,\n                                  15, 7, 10, 6, 66, 10, 17, 91, 74, 7, 3, 1, 81,\n                                  73, 77, 83, 74, 82, 92, 76, 78, 122, 94, 84,\n                                  100, 95, 89, 6, 16, 4, 0, 1, 73, 81, 73, 89,\n                                  94, 85, 102, 114, 112, 126, 82, 82, 98, 92,\n                                  98, 103, 108, 111, 116, 123, 118, 126, 89,\n                                  116, 121, 103, 102, 1, 39, 28, 18, 7, 5, 65,\n                                  66, 71, 64, 11, 51, 33, 25, 17, 46, 19, 15, 4,\n                                  7, 7, 53, 33, 19, 10, 26, 11, 4, 2, 3, 64, 38,\n                                  17, 8, 1, 16, 6, 64, 2, 9, 45, 27, 16, 10, 31,\n                                  14, 13, 12, 8, 62, 75, 66, 8, 66, 68, 1, 9,\n                                  10, 3, 10, 17, 24, 76, 71, 76, 73, 22, 80, 81,\n                                  74, 64, 17, 94, 84, 7, 13, 91, 95, 90, 68, 64,\n                                  14, 67, 2, 64, 5, 14, 77, 68, 67, 5, 87, 73,\n                                  80, 78, 10, 100, 76, 4, 70, 21, 70, 65, 32,\n                                  70, 73, 65, 27, 87, 78, 105, 13, 27, 27, 14,\n                                  65, 14, 10, 3, 5, 2, 64, 67, 85, 89, 96, 87,\n                                  82, 95, 118, 93, 90, 91, 86, 83, 71, 70, 85,\n                                  95, 73, 70, 71, 68, 78, 97, 81, 84, 102, 89,\n                                  97, 96, 113, 109, 102, 96, 82, 76, 94, 84, 87,\n                                  96, 102, 104, 104, 105, 107, 111, 125, 117,\n                                  125, 124, 121, 112, 122, 123, 70, 10, 2, 11,\n                                  16, 16, 62, 27, 25, 68, 35, 62, 62, 62, 22, 9,\n                                  0, 102, 126, 126, 126, 126, 126, 126, 66, 43,\n                                  27, 18, 9, 14, 2, 66, 68, 65, 64, 5, 18, 9,\n                                  28, 20, 11, 19, 20, 23, 24, 12, 26, 20, 64,\n                                  12, 4, 74, 81, 88, 94, 122, 121, 108 },\n\n                                {\n\n                                18,\n                                  3, 83, 18, 3, 83, 20, 28, 28, 12, 72, 102, 71,\n                                  0, 51, 14, 56, 72, 24, 31, 65, 85, 2, 101,\n                                  118, 70, 87, 126, 126, 126, 62, 19, 70, 24,\n                                  31, 65, 68, 19, 20, 72, 3, 0, 0, 73, 88, 71,\n                                  94, 5, 67, 64, 69, 81, 72, 88, 17, 4, 1, 65,\n                                  12, 2, 22, 0, 0, 0, 7, 98, 97, 12, 80, 71, 52,\n                                  5, 69, 76, 0, 82, 10, 19, 17, 29, 8, 22, 17,\n                                  12, 26, 72, 79, 74, 82, 36, 1, 24, 65, 2, 69,\n                                  3, 26, 71, 79, 70, 67, 19, 67, 8, 4, 72, 9,\n                                  68, 7, 12, 7, 15, 22, 19, 85, 71, 3, 67, 2,\n                                  72, 10, 73, 65, 19, 71, 15, 17, 4, 110, 9, 71,\n                                  103, 81, 104, 69, 8, 1, 11, 5, 5, 27, 7, 1,\n                                  15, 26, 73, 72, 4, 113, 78, 8, 95, 0, 78, 21,\n                                  1, 91, 33, 1, 65, 100, 36, 84, 102, 1, 108,\n                                  72, 9, 14, 6, 9, 5, 67, 9, 16, 93, 75, 6, 2,\n                                  1, 82, 74, 78, 84, 75, 83, 93, 77, 79, 124,\n                                  96, 85, 102, 97, 89, 4, 14, 2, 65, 64, 76, 84,\n                                  76, 92, 97, 88, 105, 117, 115, 126, 84, 84,\n                                  100, 95, 101, 106, 111, 114, 119, 126, 121,\n                                  126, 90, 118, 123, 104, 103, 1, 39, 28, 18, 7,\n                                  5, 66, 66, 71, 64, 11, 51, 33, 25, 17, 47, 19,\n                                  15, 4, 7, 7, 53, 33, 19, 10, 26, 11, 4, 2, 4,\n                                  64, 39, 17, 8, 1, 16, 6, 64, 3, 9, 45, 27, 16,\n                                  10, 31, 14, 13, 12, 8, 62, 75, 66, 8, 66, 68,\n                                  1, 9, 10, 3, 10, 17, 24, 76, 71, 77, 74, 22,\n                                  81, 82, 75, 65, 16, 96, 86, 6, 12, 92, 97, 91,\n                                  68, 64, 15, 67, 2, 64, 5, 14, 78, 68, 67, 5,\n                                  88, 73, 80, 78, 10, 101, 76, 4, 70, 21, 71,\n                                  65, 32, 71, 74, 65, 27, 88, 79, 106, 12, 26,\n                                  26, 13, 67, 13, 9, 2, 4, 1, 65, 68, 86, 91,\n                                  98, 89, 84, 97, 120, 95, 92, 92, 87, 84, 71,\n                                  70, 85, 96, 73, 73, 74, 70, 81, 100, 84, 87,\n                                  105, 92, 100, 99, 116, 112, 104, 97, 84, 78,\n                                  96, 86, 90, 99, 105, 107, 107, 107, 110, 114,\n                                  126, 119, 126, 126, 123, 114, 124, 125, 69,\n                                  11, 3, 11, 16, 16, 62, 27, 25, 68, 35, 62, 62,\n                                  62, 22, 7, 65, 105, 126, 126, 126, 126, 126,\n                                  126, 66, 43, 26, 17, 9, 14, 2, 67, 68, 65, 64,\n                                  5, 18, 9, 29, 20, 11, 19, 20, 23, 24, 12, 26,\n                                  20, 65, 10, 2, 76, 83, 90, 96, 125, 123, 109 },\n\n                                {\n\n                                17,\n                                  3, 83, 17, 3, 83, 22, 30, 29, 13, 72, 103, 72,\n                                  64, 51, 14, 59, 72, 25, 32, 65, 85, 3, 102,\n                                  119, 70, 88, 126, 126, 126, 62, 21, 70, 25,\n                                  32, 65, 67, 21, 21, 72, 4, 1, 1, 73, 88, 70,\n                                  94, 5, 66, 0, 69, 81, 71, 88, 18, 5, 2, 64,\n                                  13, 2, 22, 0, 0, 0, 8, 98, 97, 13, 80, 71, 52,\n                                  5, 69, 74, 1, 82, 11, 21, 19, 31, 10, 24, 19,\n                                  14, 28, 70, 78, 73, 81, 37, 2, 25, 64, 3, 68,\n                                  4, 28, 70, 78, 69, 65, 20, 66, 9, 6, 71, 10,\n                                  67, 8, 13, 8, 16, 23, 20, 85, 71, 4, 67, 2,\n                                  71, 10, 73, 65, 19, 71, 15, 17, 4, 111, 9, 71,\n                                  104, 82, 104, 68, 9, 2, 12, 6, 6, 28, 8, 2,\n                                  16, 28, 73, 72, 5, 114, 77, 9, 95, 1, 78, 22,\n                                  2, 91, 34, 1, 65, 101, 37, 84, 103, 1, 108,\n                                  73, 9, 14, 6, 9, 5, 67, 9, 16, 94, 75, 6, 2,\n                                  1, 82, 74, 78, 84, 75, 83, 94, 77, 79, 125,\n                                  97, 85, 103, 98, 89, 3, 13, 1, 66, 65, 78, 86,\n                                  78, 94, 99, 90, 107, 119, 117, 126, 85, 85,\n                                  101, 97, 103, 108, 113, 116, 121, 126, 123,\n                                  126, 90, 119, 124, 104, 103, 2, 40, 29, 19, 8,\n                                  5, 66, 65, 70, 0, 12, 52, 34, 26, 17, 48, 20,\n                                  16, 5, 8, 8, 54, 34, 20, 11, 27, 12, 5, 3, 6,\n                                  0, 41, 18, 9, 2, 17, 7, 0, 5, 10, 46, 28, 17,\n                                  11, 32, 15, 14, 13, 9, 62, 74, 65, 9, 66, 67,\n                                  1, 10, 11, 4, 11, 18, 25, 75, 71, 77, 74, 23,\n                                  81, 82, 76, 65, 16, 97, 87, 6, 12, 92, 98, 91,\n                                  67, 0, 16, 66, 3, 0, 6, 15, 78, 67, 66, 6, 88,\n                                  72, 79, 77, 11, 101, 76, 5, 70, 22, 71, 65,\n                                  33, 71, 74, 64, 28, 88, 79, 106, 12, 26, 26,\n                                  13, 68, 13, 9, 2, 4, 1, 65, 68, 86, 92, 99,\n                                  90, 85, 98, 121, 96, 93, 92, 87, 84, 70, 69,\n                                  84, 96, 72, 75, 76, 72, 83, 102, 86, 89, 107,\n                                  94, 102, 101, 118, 114, 105, 97, 85, 79, 97,\n                                  87, 92, 101, 107, 109, 109, 109, 112, 116,\n                                  126, 120, 126, 126, 124, 115, 125, 126, 67,\n                                  13, 5, 12, 17, 17, 62, 28, 26, 68, 36, 62, 62,\n                                  62, 23, 6, 66, 107, 126, 126, 126, 126, 126,\n                                  126, 65, 44, 26, 17, 9, 15, 2, 67, 68, 64, 0,\n                                  6, 19, 10, 31, 21, 12, 20, 21, 24, 25, 13, 27,\n                                  21, 65, 9, 1, 77, 84, 91, 97, 126, 124, 109 },\n\n                                {\n\n                                16,\n                                  3, 83, 16, 3, 83, 24, 31, 29, 13, 72, 104, 73,\n                                  65, 51, 14, 61, 72, 26, 33, 65, 86, 3, 103,\n                                  120, 71, 90, 126, 126, 126, 62, 22, 70, 26,\n                                  33, 65, 67, 22, 21, 73, 4, 1, 2, 73, 88, 70,\n                                  94, 5, 66, 1, 69, 81, 71, 88, 18, 5, 2, 64,\n                                  13, 2, 22, 0, 0, 0, 9, 98, 97, 13, 81, 71, 52,\n                                  5, 69, 73, 2, 82, 11, 22, 21, 33, 11, 25, 21,\n                                  15, 30, 69, 77, 72, 80, 38, 2, 26, 0, 3, 68,\n                                  5, 30, 70, 78, 69, 64, 20, 66, 9, 7, 71, 11,\n                                  67, 8, 13, 8, 17, 23, 20, 86, 71, 4, 67, 2,\n                                  71, 10, 73, 66, 19, 72, 15, 17, 4, 113, 9, 71,\n                                  106, 83, 105, 67, 10, 3, 13, 7, 7, 29, 9, 2,\n                                  17, 29, 73, 72, 5, 115, 77, 10, 95, 1, 78, 23,\n                                  2, 92, 35, 1, 65, 102, 38, 85, 104, 1, 109,\n                                  75, 8, 13, 5, 8, 4, 68, 8, 16, 95, 76, 6, 2,\n                                  1, 82, 75, 79, 85, 76, 84, 95, 78, 80, 126,\n                                  98, 86, 104, 99, 89, 1, 12, 64, 68, 67, 80,\n                                  88, 80, 97, 101, 92, 110, 122, 119, 126, 87,\n                                  87, 103, 99, 105, 110, 115, 118, 123, 126,\n                                  125, 126, 91, 121, 125, 105, 103, 2, 40, 29,\n                                  19, 8, 5, 66, 65, 70, 1, 12, 52, 34, 26, 17,\n                                  49, 20, 17, 5, 9, 9, 55, 35, 20, 11, 28, 12,\n                                  5, 4, 7, 1, 42, 19, 9, 2, 18, 8, 1, 6, 10, 46,\n                                  28, 17, 11, 33, 16, 15, 14, 10, 62, 74, 65, 9,\n                                  66, 67, 1, 10, 11, 4, 11, 18, 26, 75, 71, 77,\n                                  75, 23, 82, 83, 77, 66, 16, 98, 88, 6, 12, 93,\n                                  99, 92, 66, 1, 17, 66, 3, 0, 7, 16, 78, 67,\n                                  66, 6, 89, 72, 79, 77, 12, 101, 76, 5, 70, 23,\n                                  71, 65, 34, 71, 74, 64, 29, 89, 79, 107, 11,\n                                  26, 26, 12, 69, 12, 8, 1, 3, 0, 66, 69, 87,\n                                  93, 100, 92, 86, 100, 123, 97, 94, 93, 88, 84,\n                                  70, 69, 84, 97, 71, 77, 78, 74, 85, 105, 88,\n                                  91, 110, 96, 104, 103, 120, 116, 106, 98, 87,\n                                  81, 98, 89, 94, 103, 109, 111, 111, 111, 114,\n                                  118, 126, 122, 126, 126, 125, 117, 126, 126,\n                                  66, 14, 6, 13, 18, 18, 62, 29, 27, 68, 37, 62,\n                                  62, 62, 24, 5, 68, 110, 126, 126, 126, 126,\n                                  126, 126, 65, 44, 26, 17, 9, 15, 2, 67, 68, 0,\n                                  1, 7, 20, 11, 32, 22, 13, 21, 22, 25, 26, 13,\n                                  28, 21, 65, 8, 64, 79, 86, 93, 99, 126, 126,\n                                  110 },\n\n                                {\n\n                                15,\n                                  3, 83, 15, 3, 83, 26, 33, 30, 13, 73, 106, 75,\n                                  66, 51, 14, 62, 72, 27, 34, 65, 87, 3, 104,\n                                  121, 71, 92, 126, 126, 126, 62, 23, 70, 27,\n                                  34, 65, 66, 23, 22, 73, 4, 2, 3, 74, 89, 70,\n                                  94, 5, 66, 1, 69, 81, 71, 88, 19, 5, 2, 64,\n                                  14, 2, 22, 0, 0, 0, 9, 98, 97, 14, 82, 71, 52,\n                                  5, 69, 72, 3, 82, 12, 23, 23, 35, 13, 26, 23,\n                                  16, 32, 68, 76, 71, 79, 39, 2, 27, 1, 3, 67,\n                                  5, 32, 70, 77, 68, 0, 20, 66, 10, 9, 70, 12,\n                                  67, 8, 13, 8, 18, 24, 21, 86, 71, 4, 67, 2,\n                                  71, 10, 74, 66, 19, 73, 15, 17, 4, 115, 9, 72,\n                                  108, 84, 106, 66, 11, 4, 14, 8, 7, 30, 9, 3,\n                                  18, 30, 73, 72, 5, 116, 76, 11, 95, 1, 78, 24,\n                                  2, 93, 36, 1, 65, 103, 39, 85, 105, 1, 110,\n                                  76, 7, 13, 4, 7, 3, 68, 7, 15, 96, 77, 6, 2,\n                                  1, 83, 76, 80, 86, 77, 85, 96, 79, 80, 126,\n                                  99, 86, 105, 100, 89, 0, 10, 65, 70, 69, 82,\n                                  90, 82, 99, 104, 94, 112, 124, 122, 126, 89,\n                                  89, 104, 101, 107, 113, 118, 120, 126, 126,\n                                  126, 126, 92, 123, 126, 106, 103, 2, 41, 29,\n                                  19, 8, 5, 66, 65, 70, 1, 12, 52, 34, 26, 17,\n                                  50, 21, 17, 6, 9, 10, 56, 35, 21, 11, 29, 13,\n                                  6, 4, 8, 2, 43, 20, 10, 2, 19, 9, 2, 7, 11,\n                                  46, 28, 17, 11, 34, 16, 16, 15, 11, 62, 73,\n                                  64, 10, 66, 67, 1, 10, 11, 4, 11, 18, 26, 75,\n                                  71, 77, 75, 24, 83, 84, 78, 67, 16, 99, 89, 6,\n                                  12, 93, 100, 92, 65, 2, 18, 65, 4, 1, 7, 17,\n                                  78, 67, 66, 7, 89, 72, 79, 76, 13, 101, 76, 5,\n                                  70, 24, 71, 65, 35, 71, 74, 64, 30, 90, 79,\n                                  108, 10, 25, 25, 11, 70, 11, 7, 0, 2, 64, 67,\n                                  70, 88, 94, 101, 93, 87, 101, 125, 99, 95, 94,\n                                  88, 85, 70, 69, 84, 97, 70, 79, 80, 76, 87,\n                                  108, 90, 93, 112, 98, 106, 105, 123, 118, 108,\n                                  99, 89, 82, 100, 91, 96, 105, 111, 113, 113,\n                                  113, 116, 120, 126, 124, 126, 126, 126, 119,\n                                  126, 126, 65, 15, 7, 14, 19, 19, 62, 30, 28,\n                                  68, 38, 62, 62, 62, 25, 3, 69, 112, 126, 126,\n                                  126, 126, 126, 126, 65, 44, 26, 17, 9, 15, 2,\n                                  67, 68, 0, 2, 8, 21, 12, 33, 22, 13, 22, 22,\n                                  25, 26, 13, 28, 21, 65, 7, 65, 81, 88, 95,\n                                  101, 126, 126, 111 },\n\n                          },\n\n                    };\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_cabac_tables.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/**\n******************************************************************************\n* @file ih264_cabac_tables.h\n*\n* @brief\n*  This file contains enumerations, macros and extern declarations of H264\n*  cabac tables\n*\n* @author\n*  Ittiam\n*\n* @remarks\n*  none\n******************************************************************************\n*/\n\n#ifndef IH264_CABAC_TABLES_H_\n#define IH264_CABAC_TABLES_H_\n\n/*****************************************************************************/\n/* Constant Macros                                                           */\n/*****************************************************************************/\n\n/**\n******************************************************************************\n *  @brief  maximum range of cabac_init_idc (0-2) + 1 for ISLICE\n******************************************************************************\n */\n#define NUM_CAB_INIT_IDC_PLUS_ONE 4\n\n/**\n******************************************************************************\n *  @brief  max range of qps in H264 (0-51)\n******************************************************************************\n */\n#define QP_RANGE        52\n\n/**\n******************************************************************************\n *  @brief  max range of cabac contexts in H264 (0-459)\n******************************************************************************\n */\n#define NUM_CABAC_CTXTS 460\n\n\n/** Macros for Cabac checks */\n/** MbType */\n/** |x|x|I_PCM|SKIP|\n |S|Inter/Intra|P/B|NON-BD16x16/BD16x16,I16x16/I4x4| */\n#define CAB_INTRA         0x00 /* 0000 00xx */\n#define CAB_INTER         0x04 /* 0000 01xx */\n#define CAB_I4x4          0x00 /* 0000 00x0 */\n#define CAB_I16x16        0x01 /* 0000 00x1 */\n#define CAB_BD16x16       0x04 /* 0000 0100 */\n#define CAB_NON_BD16x16   0x05 /* 0000 0101 */\n#define CAB_P             0x07 /* 0000 0111 */\n#define CAB_SI4x4         0x08 /* 0000 10x0 */\n#define CAB_SI16x16       0x09 /* 0000 10x1 */\n#define CAB_SKIP_MASK     0x10 /* 0001 0000 */\n#define CAB_SKIP          0x10 /* 0001 0000 */\n#define CAB_P_SKIP        0x16 /* 0001 x11x */\n#define CAB_B_SKIP        0x14 /* 0001 x100 */\n#define CAB_BD16x16_MASK  0x07 /* 0000 0111 */\n#define CAB_INTRA_MASK    0x04 /* 0000 0100 */\n#define CAB_I_PCM         0x20 /* 001x xxxx */\n\n/**\n******************************************************************************\n *  @enum  ctxBlockCat\n\n******************************************************************************\n*/\ntypedef enum\n{\n    LUMA_DC_CTXCAT   = 0,\n    LUMA_AC_CTXCAT   = 1,\n    LUMA_4X4_CTXCAT  = 2,\n    CHROMA_DC_CTXCAT = 3,\n    CHROMA_AC_CTXCAT = 4,\n    LUMA_8X8_CTXCAT  = 5,\n    NUM_CTX_CAT      = 6\n} CTX_BLOCK_CAT;\n\n\n/**\n******************************************************************************\n *  @enum ctxIdxOffset\n\n******************************************************************************\n*/\ntypedef enum\n{\n    MB_TYPE_SI_SLICE = 0,\n    MB_TYPE_I_SLICE = 3,\n    MB_SKIP_FLAG_P_SLICE = 11,\n    MB_TYPE_P_SLICE = 14,\n    SUB_MB_TYPE_P_SLICE = 21,\n    MB_SKIP_FLAG_B_SLICE = 24,\n    MB_TYPE_B_SLICE = 27,\n    SUB_MB_TYPE_B_SLICE = 36,\n    MVD_X = 40,\n    MVD_Y = 47,\n    REF_IDX = 54,\n    MB_QP_DELTA = 60,\n    INTRA_CHROMA_PRED_MODE = 64,\n    PREV_INTRA4X4_PRED_MODE_FLAG = 68,\n    REM_INTRA4X4_PRED_MODE = 69,\n    MB_FIELD_DECODING_FLAG = 70,\n    CBP_LUMA = 73,\n    CBP_CHROMA = 77,\n    CBF = 85,\n    SIGNIFICANT_COEFF_FLAG_FRAME = 105,\n    SIGNIFICANT_COEFF_FLAG_FLD = 277,\n    LAST_SIGNIFICANT_COEFF_FLAG_FRAME = 166,\n    LAST_SIGNIFICANT_COEFF_FLAG_FLD = 338,\n    COEFF_ABS_LEVEL_MINUS1 = 227,\n\n    /* High profile related Syntax element CABAC offsets */\n    TRANSFORM_SIZE_8X8_FLAG = 399,\n    SIGNIFICANT_COEFF_FLAG_8X8_FRAME = 402,\n    LAST_SIGNIFICANT_COEFF_FLAG_8X8_FRAME = 417,\n    COEFF_ABS_LEVEL_MINUS1_8X8 = 426,\n    SIGNIFICANT_COEFF_FLAG_8X8_FIELD = 436,\n    LAST_SIGNIFICANT_COEFF_FLAG_8X8_FIELD = 451\n\n} cabac_table_num_t;\n\n\n/**\n******************************************************************************\n *  @enum  ctxIdxOffset\n\n******************************************************************************\n*/\ntypedef enum\n{\n    SIG_COEFF_CTXT_CAT_0_OFFSET = 0,\n    SIG_COEFF_CTXT_CAT_1_OFFSET = 15,\n    SIG_COEFF_CTXT_CAT_2_OFFSET = 29,\n    SIG_COEFF_CTXT_CAT_3_OFFSET = 44,\n    SIG_COEFF_CTXT_CAT_4_OFFSET = 47,\n    SIG_COEFF_CTXT_CAT_5_OFFSET = 0,\n    COEFF_ABS_LEVEL_CAT_0_OFFSET = 0,\n    COEFF_ABS_LEVEL_CAT_1_OFFSET = 10,\n    COEFF_ABS_LEVEL_CAT_2_OFFSET = 20,\n    COEFF_ABS_LEVEL_CAT_3_OFFSET = 30,\n    COEFF_ABS_LEVEL_CAT_4_OFFSET = 39,\n    COEFF_ABS_LEVEL_CAT_5_OFFSET = 0\n} cabac_blk_cat_offset_t;\n\n\n\n\n/*****************************************************************************/\n/* Extern global declarations                                                */\n/*****************************************************************************/\n\n\n/* CABAC Table declaration*/\nextern const UWORD32 gau4_ih264_cabac_table[128][4];\n\n\n/*****************************************************************************/\n/* Cabac tables for context initialization depending upon type of Slice,     */\n/* cabac init Idc value and Qp.                                              */\n/*****************************************************************************/\nextern const UWORD8 gau1_ih264_cabac_ctxt_init_table[NUM_CAB_INIT_IDC_PLUS_ONE][QP_RANGE][NUM_CABAC_CTXTS];\n\n\n#endif /* IH264_CABAC_TABLES_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_cavlc_tables.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n\n/**\n******************************************************************************\n* @file\n*  ih264_cavlc_tables.c\n*\n* @brief\n*  This file contains H264 cavlc tables for encoding coeff_tokens, levels, total\n*  zeros and runs before zeros\n*\n* @author\n*   Ittiam\n*\n* @par List of Tables\n*   - gu1_code_coeff_token_table\n*   - gu1_size_coeff_token_table\n*   - gu1_code_coeff_token_table_chroma\n*   - gu1_size_coeff_token_table_chroma\n*   - gu1_threshold_vlc_level\n*   - gu1_size_zero_table\n*   - gu1_code_zero_table\n*   - gu1_size_zero_table_chroma\n*   - gu1_code_zero_table_chroma\n*   - gu1_index_zero_table\n*   - gu1_size_run_table\n*   - gu1_code_run_table\n*   - gu4_codeword_level_tables\n*   - gu1_codesize_level_tables\n*\n* @remarks\n*  none\n*\n******************************************************************************\n*/\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_cavlc_tables.h\"\n\n\n/*****************************************************************************/\n/* Extern global definitions                                                 */\n/*****************************************************************************/\n\n/**\n ******************************************************************************\n * @brief  Assignment of cbp to a codenum for intra and inter prediction modes\n * chroma format idc != 0\n * input  : cbp, intra - 0/inter - 1\n * output : codenum\n * @remarks Table 9-4  Assignment of codeNum to values of coded_block_pattern\n * for macroblock prediction modes in H264 spec\n ******************************************************************************\n */\nconst UWORD8 gu1_cbp_map_tables[48][2]=\n{\n    { 3,  0},   {29,  2},   {30,  3},   {17,  7},   {31,  4},   {18,  8},   {37, 17},   { 8, 13},\n    {32,  5},   {38, 18},   {19,  9},   { 9, 14},   {20, 10},   {10, 15},   {11, 16},   { 2, 11},\n    {16,  1},   {33, 32},   {34, 33},   {21, 36},   {35, 34},   {22, 37},   {39, 44},   { 4, 40},\n    {36, 35},   {40, 45},   {23, 38},   { 5, 41},   {24, 39},   { 6, 42},   { 7, 43},   { 1, 19},\n    {41,  6},   {42, 24},   {43, 25},   {25, 20},   {44, 26},   {26, 21},   {46, 46},   {12, 28},\n    {45, 27},   {47, 47},   {27, 22},   {13, 29},   {28, 23},   {14, 30},   {15, 31},   { 0, 12},\n};\n\n\n/**\n ******************************************************************************\n * @brief  total non-zero coefficients and numbers of trailing ones of a residual\n * block are mapped to coeff_token using the tables given below.\n * input  : VLC-Num  | Trailing ones | Total coeffs\n * output : coeff_token (code word, size of the code word)\n * @remarks Table-9-5 coeff_token mapping to TotalCoeff( coeff_token )\n * and TrailingOnes( coeff_token ) in H264 spec\n ******************************************************************************\n */\nconst UWORD8 gu1_code_coeff_token_table[3][4][16] =\n{\n    {\n        { 5,  7,  7,  7,  7, 15, 11,  8, 15, 11, 15, 11, 15, 11,  7,  4, },\n        { 1,  4,  6,  6,  6,  6, 14, 10, 14, 10, 14, 10,  1, 14, 10,  6, },\n        { 0,  1,  5,  5,  5,  5,  5, 13,  9, 13,  9, 13,  9, 13,  9,  5, },\n        { 0,  0,  3,  3,  4,  4,  4,  4,  4, 12, 12,  8, 12,  8, 12,  8, },\n    },\n    {\n        {11,  7,  7,  7,  4,  7, 15, 11, 15, 11,  8, 15, 11,  7,  9,  7, },\n        { 2,  7, 10,  6,  6,  6,  6, 14, 10, 14, 10, 14, 10, 11,  8,  6, },\n        { 0,  3,  9,  5,  5,  5,  5, 13,  9, 13,  9, 13,  9,  6, 10,  5, },\n        { 0,  0,  5,  4,  6,  8,  4,  4,  4, 12,  8, 12, 12,  8,  1,  4, },\n    },\n    {\n        {15, 11,  8, 15, 11,  9,  8, 15, 11, 15, 11,  8, 13,  9,  5,  1, },\n        {14, 15, 12, 10,  8, 14, 10, 14, 14, 10, 14, 10,  7, 12,  8,  4, },\n        { 0, 13, 14, 11,  9, 13,  9, 13, 10, 13,  9, 13,  9, 11,  7,  3, },\n        { 0,  0, 12, 11, 10,  9,  8, 13, 12, 12, 12,  8, 12, 10,  6,  2, },\n    },\n};\n\nconst UWORD8 gu1_size_coeff_token_table[3][4][16] =\n{\n    {\n        { 6,  8,  9, 10, 11, 13, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, },\n        { 2,  6,  8,  9, 10, 11, 13, 13, 14, 14, 15, 15, 15, 16, 16, 16, },\n        { 0,  3,  7,  8,  9, 10, 11, 13, 13, 14, 14, 15, 15, 16, 16, 16, },\n        { 0,  0,  5,  6,  7,  8,  9, 10, 11, 13, 14, 14, 15, 15, 16, 16, },\n    },\n    {\n        { 6,  6,  7,  8,  8,  9, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, },\n        { 2,  5,  6,  6,  7,  8,  9, 11, 11, 12, 12, 13, 13, 14, 14, 14, },\n        { 0,  3,  6,  6,  7,  8,  9, 11, 11, 12, 12, 13, 13, 13, 14, 14, },\n        { 0,  0,  4,  4,  5,  6,  6,  7,  9, 11, 11, 12, 13, 13, 13, 14, },\n    },\n    {\n        { 6,  6,  6,  7,  7,  7,  7,  8,  8,  9,  9,  9, 10, 10, 10, 10, },\n        { 4,  5,  5,  5,  5,  6,  6,  7,  8,  8,  9,  9,  9, 10, 10, 10, },\n        { 0,  4,  5,  5,  5,  6,  6,  7,  7,  8,  8,  9,  9, 10, 10, 10, },\n        { 0,  0,  4,  4,  4,  4,  4,  5,  6,  7,  8,  8,  9, 10, 10, 10, },\n    },\n};\nconst UWORD8 gu1_code_coeff_token_table_chroma[4][4] =\n{\n    { 7,  4,  3,  2, },\n    { 1,  6,  3,  3, },\n    { 0,  1,  2,  2, },\n    { 0,  0,  5,  0, },\n};\n\nconst UWORD8 gu1_size_coeff_token_table_chroma[4][4] =\n{\n    { 6,  6,  6,  6, },\n    { 1,  6,  7,  8, },\n    { 0,  3,  7,  8, },\n    { 0,  0,  6,  7, },\n};\n\n/**\n ******************************************************************************\n * @brief  After encoding the current Level, to encode the next level, the choice\n * of VLC table needs to be updated. The update is carried basing on a set of thresholds.\n * These thresholds are listed in the table below for lookup.\n * input  : suffix_length\n * output : threshold\n ******************************************************************************\n */\nconst UWORD8 gu1_threshold_vlc_level[6] =\n{\n    0, 3, 6, 12, 24, 48\n};\n\n\n/**\n ******************************************************************************\n * @brief  table for encoding total number of zeros\n * input  : coeff_token, total zeros\n * output : code word, size of the code word\n * @remarks Table-9-7, 9-8  total_zeros tables for 4x4 blocks with\n * TotalCoeff( coeff_token ) in H264 spec\n ******************************************************************************\n */\nconst UWORD8 gu1_size_zero_table[135] =\n{\n     1, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9,\n     3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6,\n     4, 3, 3, 3, 4, 4, 3, 3, 4, 5, 5, 6, 5, 6,\n     5, 3, 4, 4, 3, 3, 3, 4, 3, 4, 5, 5, 5,\n     4, 4, 4, 3, 3, 3, 3, 3, 4, 5, 4, 5,\n     6, 5, 3, 3, 3, 3, 3, 3, 4, 3, 6,\n     6, 5, 3, 3, 3, 2, 3, 4, 3, 6,\n     6, 4, 5, 3, 2, 2, 3, 3, 6,\n     6, 6, 4, 2, 2, 3, 2, 5,\n     5, 5, 3, 2, 2, 2, 4,\n     4, 4, 3, 3, 1, 3,\n     4, 4, 2, 1, 3,\n     3, 3, 1, 2,\n     2, 2, 1,\n     1, 1,\n};\nconst UWORD8 gu1_code_zero_table[135] =\n{\n     1, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 1,\n     7, 6, 5, 4, 3, 5, 4, 3, 2, 3, 2, 3, 2, 1, 0,\n     5, 7, 6, 5, 4, 3, 4, 3, 2, 3, 2, 1, 1, 0,\n     3, 7, 5, 4, 6, 5, 4, 3, 3, 2, 2, 1, 0,\n     5, 4, 3, 7, 6, 5, 4, 3, 2, 1, 1, 0,\n     1, 1, 7, 6, 5, 4, 3, 2, 1, 1, 0,\n     1, 1, 5, 4, 3, 3, 2, 1, 1, 0,\n     1, 1, 1, 3, 3, 2, 2, 1, 0,\n     1, 0, 1, 3, 2, 1, 1, 1,\n     1, 0, 1, 3, 2, 1, 1,\n     0, 1, 1, 2, 1, 3,\n     0, 1, 1, 1, 1,\n     0, 1, 1, 1,\n     0, 1, 1,\n     0, 1,\n};\nconst UWORD8 gu1_size_zero_table_chroma[9] =\n{\n     1, 2, 3, 3,\n     1, 2, 2,\n     1, 1,\n};\nconst UWORD8 gu1_code_zero_table_chroma[9] =\n{\n     1, 1, 1, 0,\n     1, 1, 0,\n     1, 0,\n};\n\n/**\n ******************************************************************************\n * @brief  index to access zero table (look up)\n * input  : TotalCoeff( coeff_token )\n * output : index to access zero table\n ******************************************************************************\n */\nconst UWORD8 gu1_index_zero_table[15] =\n{\n    0,  16,  31,  45,  58,  70,  81,  91, 100, 108, 115, 121, 126, 130, 133,\n};\n\n/**\n ******************************************************************************\n * @brief  table for encoding runs of zeros before\n * input  : zeros left, runs of zeros before\n * output : code word, size of the code word\n * @remarks Table-9-10  table for run_before in H264 spec\n ******************************************************************************\n */\nconst UWORD8 gu1_size_run_table[42] =\n{\n      1,  1,\n      1,  2,  2,\n      2,  2,  2,  2,\n      2,  2,  2,  3,  3,\n      2,  2,  3,  3,  3,  3,\n      2,  3,  3,  3,  3,  3,  3,\n      3,  3,  3,  3,  3,  3,  3,  4,  5,  6,  7,  8,  9, 10, 11,\n};\nconst UWORD8 gu1_code_run_table[42] =\n{\n      1,  0,\n      1,  1,  0,\n      3,  2,  1,  0,\n      3,  2,  1,  1,  0,\n      3,  2,  3,  2,  1,  0,\n      3,  0,  1,  3,  2,  5,  4,\n      7,  6,  5,  4,  3,  2,  1,  1,  1,  1,  1,  1,  1,  1,  1,\n};\n/**\n ******************************************************************************\n * @brief  index to access zero table (look up)\n * input  : TotalCoeff( coeff_token )\n * output : index to access zero table\n ******************************************************************************\n */\nconst UWORD8 gu1_index_run_table[7] =\n{\n    0,  2,  5,  9,  14,  20,  27,\n};\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_cavlc_tables.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/**\n******************************************************************************\n* @file ih264_cavlc_tables.h\n*\n* @brief\n*  This file contains enumerations, macros and extern declarations of H264\n*  cavlc tables\n*\n* @author\n*  Ittiam\n*\n*  @remarks\n*   none\n******************************************************************************\n*/\n\n#ifndef IH264_CAVLC_TABLES_H_\n#define IH264_CAVLC_TABLES_H_\n\n/*****************************************************************************/\n/* Constant Macros                                                           */\n/*****************************************************************************/\n/**\n******************************************************************************\n *  @brief  maximum zeros left\n******************************************************************************\n */\n#define MAX_ZERO_LEFT 6\n\n/*****************************************************************************/\n/* Extern global declarations                                                */\n/*****************************************************************************/\n\n/**\n ******************************************************************************\n * @brief  Assignment of cbp to a codenum for intra and inter prediction modes\n * chroma format idc != 0\n * input  : cbp, intra - 0/inter - 1\n * output : codenum\n * @remarks Table 9-4  Assignment of codeNum to values of coded_block_pattern\n * for macroblock prediction modes in H264 spec\n ******************************************************************************\n */\nextern const UWORD8 gu1_cbp_map_tables[48][2];\n\n/**\n ******************************************************************************\n * @brief  total non-zero coefficients and numbers of trailing ones of a residual\n * block are mapped to coefftoken using the tables given below.\n * input  : VLC-Num  | Trailing ones | Total coeffs\n * output : coeff_token (code word, size of the code word)\n * @remarks Table-9-5 coeff_token mapping to TotalCoeff( coeff_token )\n * and TrailingOnes( coeff_token ) in H264 spec\n ******************************************************************************\n */\nextern const UWORD8 gu1_code_coeff_token_table[3][4][16];\nextern const UWORD8 gu1_size_coeff_token_table[3][4][16];\nextern const UWORD8 gu1_code_coeff_token_table_chroma[4][4];\nextern const UWORD8 gu1_size_coeff_token_table_chroma[4][4];\n\n/**\n ******************************************************************************\n * @brief  Thresholds for determining whether to increment Level table number.\n * input  : suffix_length\n * output : threshold\n ******************************************************************************\n */\nextern const UWORD8 gu1_threshold_vlc_level[6];\n\n/**\n ******************************************************************************\n * @brief  table for encoding total number of zeros\n * input  : coeff_token, total zeros\n * output : code word, size of the code word\n * @remarks Table-9-7, 9-8  total_zeros tables for 4x4 blocks with\n * TotalCoeff( coeff_token ) in H264 spec\n ******************************************************************************\n */\nextern const UWORD8 gu1_size_zero_table[135];\nextern const UWORD8 gu1_code_zero_table[135];\nextern const UWORD8 gu1_size_zero_table_chroma[9];\nextern const UWORD8 gu1_code_zero_table_chroma[9];\n\n/**\n ******************************************************************************\n * @brief  index to access zero table (for speed)\n * input  : TotalCoeff( coeff_token )\n * output : index to access zero table\n ******************************************************************************\n */\nextern const UWORD8 gu1_index_zero_table[15];\n\n/**\n ******************************************************************************\n * @brief  table for encoding runs of zeros before\n * input  : zeros left, runs of zeros before\n * output : code word, size of the code word\n * @remarks Table-9-10  table for run_before in H264 spec\n ******************************************************************************\n */\nextern const UWORD8 gu1_size_run_table[42];\nextern const UWORD8 gu1_code_run_table[42];\n\n/**\n ******************************************************************************\n * @brief  index to access run table (look up)\n * input  : zeros left\n * output : index to access run table\n ******************************************************************************\n */\nextern const UWORD8 gu1_index_run_table[7];\n\n#endif /* IH264_CAVLC_TABLES_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_chroma_intra_pred_filters.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_chroma_intra_pred_filters.c\n*\n* @brief\n*  Contains function definitions for chroma intra prediction  filters\n*\n* @author\n*  Ittiam\n*\n* @par List of Functions:\n*  -ih264_intra_pred_chroma_8x8_mode_dc\n*  -ih264_intra_pred_chroma_8x8_mode_horz\n*  -ih264_intra_pred_chroma_8x8_mode_vert\n*  -ih264_intra_pred_chroma_8x8_mode_plane\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System include files */\n#include <stdio.h>\n#include <stddef.h>\n#include <string.h>\n\n/* User include files */\n#include \"ih264_defs.h\"\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_intra_pred_filters.h\"\n\n/* Global variables used only in assembly files*/\nconst WORD8  ih264_gai1_intrapred_chroma_plane_coeffs1[] =\n{ 0x01,0x00,0x01,0x00,\n  0x02,0x00,0x02,0x00,\n  0x03,0x00,0x03,0x00,\n  0x04,0x00,0x04,0x00\n};\n const WORD8  ih264_gai1_intrapred_chroma_plane_coeffs2[] =\n { 0xfd,0xff,0xfe,0xff,\n   0xff,0xff,0x00,0x00,\n   0x01,0x00,0x02,0x00,\n   0x03,0x00,0x04,0x00,\n };\n\n/*****************************************************************************/\n/* Chroma Intra prediction 8x8 filters                                       */\n/*****************************************************************************/\n\n/**\n*******************************************************************************\n*\n* ih264_intra_pred_chroma_8x8_mode_dc\n*\n* @brief\n*  Perform Intra prediction for  chroma_8x8 mode:DC\n*\n* @par Description:\n*  Perform Intra prediction for  chroma_8x8 mode:DC ,described in sec 8.3.4.1\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source containing alternate U and V samples\n*\n* @param[out] pu1_dst\n*  UWORD8 pointer to the destination with alternate U and V samples\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] dst_strd\n*  integer destination stride\n*\n** @param[in] ngbr_avail\n*  availability of neighbouring pixels\n*\n* @returns\n*\n* @remarks\n*  None\n*\n******************************************************************************\n*/\nvoid ih264_intra_pred_chroma_8x8_mode_dc(UWORD8 *pu1_src,\n                                         UWORD8 *pu1_dst,\n                                         WORD32 src_strd,\n                                         WORD32 dst_strd,\n                                         WORD32 ngbr_avail)\n{\n    WORD32 left_avail, left_avail1, left_avail2; /* availability of left predictors (only for DC) */\n    WORD32 top_avail; /* availability of top predictors (only for DC) */\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n\n    /* temporary variables to store accumulated first left half,second left half,\n     * first top half,second top half of U and  V values*/\n    WORD32 val_u_l1 = 0, val_u_l2 = 0, val_u_t1 = 0, val_u_t2 = 0;\n    WORD32 val_v_l1 = 0, val_v_l2 = 0, val_v_t1 = 0, val_v_t2 = 0;\n\n    WORD32 val_u1 = 0, val_u2 = 0, val_v1 = 0, val_v2 = 0;\n\n    WORD32 col, row; /*loop variables*/\n    UNUSED(src_strd);\n\n    left_avail = ngbr_avail & 0x11;\n    left_avail1 = ngbr_avail & 1;\n    left_avail2 = (ngbr_avail >> 4) & 1;\n    top_avail = (ngbr_avail >> 2) & 1;\n\n    pu1_top = pu1_src + 2 * BLK8x8SIZE + 2;\n    pu1_left = pu1_src + 2 * BLK8x8SIZE - 2;\n\n    if(left_avail1)\n    { /* First 4x4 block*/\n        val_u_l1 += *pu1_left;\n        val_v_l1 += *(pu1_left + 1);\n        pu1_left -= 2;\n        val_u_l1 += *pu1_left;\n        val_v_l1 += *(pu1_left + 1);\n        pu1_left -= 2;\n        val_u_l1 += *pu1_left;\n        val_v_l1 += *(pu1_left + 1);\n        pu1_left -= 2;\n        val_u_l1 += *pu1_left + 2;\n        val_v_l1 += *(pu1_left + 1) + 2;\n        pu1_left -= 2;\n    }\n    else\n        pu1_left -= 2 * 4;\n\n    if(left_avail2)\n    {\n        /* Second 4x4 block*/\n        val_u_l2 += *pu1_left;\n        val_v_l2 += *(pu1_left + 1);\n        pu1_left -= 2;\n        val_u_l2 += *pu1_left;\n        val_v_l2 += *(pu1_left + 1);\n        pu1_left -= 2;\n        val_u_l2 += *pu1_left;\n        val_v_l2 += *(pu1_left + 1);\n        pu1_left -= 2;\n        val_u_l2 += *pu1_left + 2;\n        val_v_l2 += *(pu1_left + 1) + 2;\n        pu1_left -= 2;\n    }\n    else\n        pu1_left -= 2 * 4;\n\n    if(top_avail)\n    {\n        val_u_t1 += *pu1_top + *(pu1_top + 2) + *(pu1_top + 4)\n                        + *(pu1_top + 6) + 2;\n        val_u_t2 += *(pu1_top + 8) + *(pu1_top + 10) + *(pu1_top + 12)\n                        + *(pu1_top + 14) + 2;\n        val_v_t1 += *(pu1_top + 1) + *(pu1_top + 3) + *(pu1_top + 5)\n                        + *(pu1_top + 7) + 2;\n        val_v_t2 += *(pu1_top + 9) + *(pu1_top + 11) + *(pu1_top + 13)\n                        + *(pu1_top + 15) + 2;\n    }\n\n    if(left_avail + top_avail)\n    {\n        val_u1 = (left_avail1 + top_avail) ?\n                        ((val_u_l1 + val_u_t1)\n                                        >> (1 + left_avail1 + top_avail)) :128;\n        val_v1 = (left_avail1 + top_avail) ?\n                        ((val_v_l1 + val_v_t1)\n                                        >> (1 + left_avail1 + top_avail)) :128;\n        if(top_avail)\n        {\n            val_u2 = val_u_t2 >> 2;\n            val_v2 = val_v_t2 >> 2;\n        }\n        else if(left_avail1)\n        {\n            val_u2 = val_u_l1 >> 2;\n            val_v2 = val_v_l1 >> 2;\n        }\n        else\n        {\n            val_u2 = val_v2 = 128;\n        }\n\n        for(row = 0; row < 4; row++)\n        {\n            /*top left 4x4 block*/\n            for(col = 0; col < 8; col += 2)\n            {\n                *(pu1_dst + row * dst_strd + col) = val_u1;\n                *(pu1_dst + row * dst_strd + col + 1) = val_v1;\n            }\n            /*top right 4x4 block*/\n            for(col = 8; col < 16; col += 2)\n            {\n                *(pu1_dst + row * dst_strd + col) = val_u2;\n                *(pu1_dst + row * dst_strd + col + 1) = val_v2;\n            }\n        }\n\n        if(left_avail2)\n        {\n            val_u1 = val_u_l2 >> 2;\n            val_v1 = val_v_l2 >> 2;\n        }\n        else if(top_avail)\n        {\n            val_u1 = val_u_t1 >> 2;\n            val_v1 = val_v_t1 >> 2;\n        }\n        else\n        {\n            val_u1 = val_v1 = 128;\n        }\n        val_u2 = (left_avail2 + top_avail) ?\n                        ((val_u_l2 + val_u_t2)\n                                        >> (1 + left_avail2 + top_avail)) : 128;\n        val_v2 = (left_avail2 + top_avail) ?\n                        ((val_v_l2 + val_v_t2)\n                                        >> (1 + left_avail2 + top_avail)) :  128;\n\n        for(row = 4; row < 8; row++)\n        { /*bottom left 4x4 block*/\n            for(col = 0; col < 8; col += 2)\n            {\n                *(pu1_dst + row * dst_strd + col) = val_u1;\n                *(pu1_dst + row * dst_strd + col + 1) = val_v1;\n            }\n            /*bottom right 4x4 block*/\n            for(col = 8; col < 16; col += 2)\n            {\n                *(pu1_dst + row * dst_strd + col) = val_u2;\n                *(pu1_dst + row * dst_strd + col + 1) = val_v2;\n            }\n        }\n    }\n    else\n    {\n        /* Both left and top are unavailable, set the block to 128 */\n        for(row = 0; row < 8; row++)\n        {\n            memset(pu1_dst + row * dst_strd, 128, 8 * sizeof(UWORD16));\n        }\n    }\n}\n\n/**\n*******************************************************************************\n*\n*ih264_intra_pred_chroma_8x8_mode_horz\n*\n* @brief\n*  Perform Intra prediction for  chroma_8x8 mode:Horizontal\n*\n* @par Description:\n*  Perform Intra prediction for  chroma_8x8 mode:Horizontal ,described in sec 8.3.4.2\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source containing alternate U and V samples\n*\n* @param[out] pu1_dst\n*  UWORD8 pointer to the destination with alternate U and V samples\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] dst_strd\n*  integer destination stride\n*\n* @param[in] ngbr_avail\n* availability of neighbouring pixels(Not used in this function)\n*\n* @returns\n*\n* @remarks\n*  None\n*\n******************************************************************************\n*/\nvoid ih264_intra_pred_chroma_8x8_mode_horz(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n\n    UWORD8 *pu1_left = NULL; /* Pointer to start of top predictors */\n    WORD32 rows, cols; /* loop variables*/\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_left = pu1_src + 2 * BLK8x8SIZE - 2;\n    for(rows = 0; rows < 8; rows++)\n    {\n        for(cols = 0; cols < 16; cols += 2)\n        {\n            *(pu1_dst + rows * dst_strd + cols) = *pu1_left;\n\n            *(pu1_dst + rows * dst_strd + cols + 1) = *(pu1_left + 1);\n        }\n        pu1_left -= 2;\n    }\n\n}\n\n/**\n*******************************************************************************\n*\n*ih264_intra_pred_chroma_8x8_mode_vert\n*\n* @brief\n*  Perform Intra prediction for  chroma_8x8 mode:vertical\n*\n* @par Description:\n*  Perform Intra prediction for  chroma_8x8 mode:vertical ,described in sec 8.3.4.3\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source containing alternate U and V samples\n*\n* @param[out] pu1_dst\n*  UWORD8 pointer to the destination with alternate U and V samples\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] dst_strd\n*  integer destination stride\n*\n* @param[in] ngbr_avail\n* availability of neighbouring pixels(Not used in this function)\n*\n* @returns\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nvoid ih264_intra_pred_chroma_8x8_mode_vert(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    WORD32 row;/*loop variable*/\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + 2 * BLK8x8SIZE + 2;\n\n    /* 8 bytes are copied from src to dst */\n    for(row = 0; row < 2; row++)\n    {\n        memcpy(pu1_dst, pu1_top, 16);\n\n        pu1_dst += dst_strd;\n        memcpy(pu1_dst, pu1_top, 16);\n\n        pu1_dst += dst_strd;\n        memcpy(pu1_dst, pu1_top, 16);\n\n        pu1_dst += dst_strd;\n        memcpy(pu1_dst, pu1_top, 16);\n\n        pu1_dst += dst_strd;\n    }\n}\n\n/**\n*******************************************************************************\n*\n* ih264_intra_pred_chroma_8x8_mode_plane\n*\n* @brief\n*  Perform Intra prediction for  chroma_8x8 mode:PLANE\n*\n* @par Description:\n*  Perform Intra prediction for  chroma_8x8 mode:PLANE ,described in sec 8.3.4.4\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source containing alternate U and V samples\n*\n* @param[out] pu1_dst\n*  UWORD8 pointer to the destination with alternate U and V samples\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] dst_strd\n*  integer destination stride\n*\n* @param[in] ngbr_avail\n* availability of neighbouring pixels(Not used in this function)\n*\n* @returns\n*\n* @remarks\n*  None\n*\n******************************************************************************\n*/\nvoid ih264_intra_pred_chroma_8x8_mode_plane(UWORD8 *pu1_src,\n                                            UWORD8 *pu1_dst,\n                                            WORD32 src_strd,\n                                            WORD32 dst_strd,\n                                            WORD32 ngbr_avail)\n{\n\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    WORD32 val = 0;\n    WORD32 rows, cols; /* loop variables*/\n    WORD32 a_u, b_u, c_u, h_u, v_u; /* Implementing section 8.3.4.4 . The variables represent the corresponding variables in the section*/\n    WORD32 a_v, b_v, c_v, h_v, v_v;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    a_u = b_u = c_u = h_u = v_u = 0;\n    a_v = b_v = c_v = h_v = v_v = 0;\n    /* As chroma format 4:2:0 is used,xCF = 4 * ( chroma_format_idc = = 3 ) = 0 and\n     yCF = 4 * ( chroma_format_idc != 1  ) = 0   */\n    pu1_top = pu1_src + 2 * BLK8x8SIZE + 2;\n    pu1_left = pu1_src + 2 * BLK8x8SIZE - 2;\n    /* Implementing section 8.3.4.4 */\n    for(cols = 0; cols < 4; cols++)\n    {\n        h_u += (cols + 1) * (pu1_top[8 + 2 * cols] - pu1_top[4 - 2 * cols]);/*section 8.3.4.4   equation (8-144)*/\n        h_v += (cols + 1) * (pu1_top[8 + 2 * cols + 1] - pu1_top[4 - 2 * cols+ 1]);\n\n        v_u += (cols + 1) * (pu1_left[(4 + cols) * (-2)] - pu1_left[(2 - cols) * (-2)]);\n        v_v += (cols + 1)  * (pu1_left[(4 + cols) * (-2) + 1]  - pu1_left[(2 - cols) * (-2) + 1]);/*section 8.3.4.4   equation (8-145)*/\n    }\n    a_u = 16 * (pu1_left[7 * (-2)] + pu1_top[14]);\n    a_v = 16 * (pu1_left[7 * (-2) + 1] + pu1_top[15]);/*section 8.3.3.4   equation (8-141)*/\n    b_u = (34 * h_u + 32) >> 6;/*section 8.3.3.4   equation (8-142)*/\n    b_v = (34 * h_v + 32) >> 6;/*section 8.3.3.4   equation (8-142)*/\n    c_u = (34 * v_u + 32) >> 6;/*section 8.3.3.4   equation (8-143)*/\n    c_v = (34 * v_v + 32) >> 6;/*section 8.3.3.4   equation (8-143)*/\n\n    for(rows = 0; rows < 8; rows++)\n    {\n        for(cols = 0; cols < 8; cols++)\n        {\n            val = (a_u + b_u * (cols - 3) + c_u * (rows - 3) );/*section 8.3.4.4   equation (8-140)*/\n            val = (val + 16) >> 5;\n            *(pu1_dst + rows * dst_strd + 2 * cols) = CLIP_U8(val);\n            val = (a_v + b_v * (cols - 3) + c_v * (rows - 3) );/*section 8.3.4.4   equation (8-140)*/\n            val = (val + 16) >> 5;\n            *(pu1_dst + rows * dst_strd + 2 * cols + 1) = CLIP_U8(val);\n        }\n    }\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_common_tables.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_common_tables.c\n*\n* @brief\n*  Contains common global tables\n*\n* @author\n*  Harish M\n*\n* @par List of Functions:\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_common_tables.h\"\n\n\n/*****************************************************************************/\n/* Extern global definitions                                                 */\n/*****************************************************************************/\n\n/**\n ******************************************************************************\n * @brief  while encoding, basing on the input configuration parameters, the\n * the level of the bitstream is computed basing on the table below.\n * input  : table_idx\n * output : level_idc or cpb size\n * @remarks Table A-1  level table limits\n ******************************************************************************\n */\nconst level_tables_t gas_ih264_lvl_tbl[16] =\n{\n    { IH264_LEVEL_10,    1485,       99,         297,       64,         175,         64  },\n    { IH264_LEVEL_1B,    1485,       99,         297,       128,        350,         64  },\n    { IH264_LEVEL_11,    3000,       396,        675,       192,        500,         128 },\n    { IH264_LEVEL_12,    6000,       396,        1782,      384,        1000,        128 },\n    { IH264_LEVEL_13,    11880,      396,        1782,      768,        2000,        128 },\n    { IH264_LEVEL_20,    11880,      396,        1782,      2000,       2000,        128 },\n    { IH264_LEVEL_21,    19800,      792,        3564,      4000,       4000,        256 },\n    { IH264_LEVEL_22,    20250,      1620,       6075,      4000,       4000,        256 },\n    { IH264_LEVEL_30,    40500,      1620,       6075,      10000,      10000,       256 },\n    { IH264_LEVEL_31,    108000,     3600,       13500,     14000,      14000,       512 },\n    { IH264_LEVEL_32,    216000,     5120,       15360,     20000,      20000,       512 },\n    { IH264_LEVEL_40,    245760,     8192,       24576,     20000,      25000,       512 },\n    { IH264_LEVEL_41,    245760,     8192,       24576,     50000,      62500,       512 },\n    { IH264_LEVEL_42,    522240,     8704,       26112,     50000,      62500,       512 },\n    { IH264_LEVEL_50,    589824,     22080,      82800,     135000,     135000,      512 },\n    { IH264_LEVEL_51,    983040,     36864,      138240,    240000,     240000,      512 },\n};\n\n\n/**\n * Array containing supported levels\n */\nconst WORD32 gai4_ih264_levels[] =\n{\n    IH264_LEVEL_10,\n    IH264_LEVEL_11,\n    IH264_LEVEL_12,\n    IH264_LEVEL_13,\n    IH264_LEVEL_20,\n    IH264_LEVEL_21,\n    IH264_LEVEL_22,\n    IH264_LEVEL_30,\n    IH264_LEVEL_31,\n    IH264_LEVEL_32,\n    IH264_LEVEL_40,\n    IH264_LEVEL_41,\n    IH264_LEVEL_42,\n    IH264_LEVEL_50,\n    IH264_LEVEL_51,\n};\n\n\n/**\n * Array giving size of max luma samples in a picture for a given level\n */\nconst WORD32 gai4_ih264_max_luma_pic_size[] =\n{\n    /* Level 1 */\n    25344,\n    /* Level 1.1 */\n    101376,\n    /* Level 1.2 */\n    101376,\n    /* Level 1.3 */\n    101376,\n    /* Level 2 */\n    101376,\n    /* Level 2.1 */\n    202752,\n    /* Level 2.2 */\n    414720,\n    /* Level 3 */\n    414720,\n    /* Level 3.1 */\n    921600,\n    /* Level 3.2 */\n    1310720,\n    /* Level 4 */\n    2097152,\n    /* Level 4.1 */\n    2097152,\n    /* Level 4.2 */\n    2228224,\n    /* Level 5 */\n    5652480,\n    /* Level 5.1 */\n    9437184\n};\n\n\n/** Max width and height allowed for a given level */\n/** This is derived as SQRT(8 * gai4_ih264_max_luma_pic_size[]) */\nconst WORD32 gai4_ih264_max_wd_ht[] =\n{\n    /* Level 1 */\n    451,\n    /* Level 1.1 */\n    901,\n    /* Level 1.2 */\n    901,\n    /* Level 1.3 */\n    901,\n    /* Level 2 */\n    901,\n    /* Level 2.1 */\n    1274,\n    /* Level 2.2 */\n    1822,\n    /* Level 3 */\n    1822,\n    /* Level 3.1 */\n    2716,\n    /* Level 3.2 */\n    3239,\n    /* Level 4 */\n    4096,\n    /* Level 4.1 */\n    4096,\n    /* Level 4.2 */\n    4223,\n    /* Level 5 */\n    6725,\n    /* Level 5.1 */\n    8689\n};\n\n/** Min width and height allowed for a given level */\n/** This is derived as gai4_ih264_max_luma_pic_size[]/gai4_ih264_max_wd_ht[] */\nconst WORD32 gai4_ih264_min_wd_ht[] =\n{\n    /* Level 1 */\n    57,\n    /* Level 1.1 */\n    113,\n    /* Level 1.2 */\n    113,\n    /* Level 1.3 */\n    113,\n    /* Level 2 */\n    113,\n    /* Level 2.1 */\n    160,\n    /* Level 2.2 */\n    228,\n    /* Level 3 */\n    228,\n    /* Level 3.1 */\n    340,\n    /* Level 3.2 */\n    405,\n    /* Level 4 */\n    512,\n    /* Level 4.1 */\n    512,\n    /* Level 4.2 */\n    528,\n    /* Level 5 */\n    841,\n    /* Level 5.1 */\n    1087\n\n};\n\n\n/** Table 7-11 Macroblock types for I slices */\nintra_mbtype_info_t gas_ih264_i_mbtype_info[] =\n{\n    /* For first entry, if transform_size_8x8_flag is 1, mode will be MBPART_I8x8 */\n    /* This has to be taken care while accessing the table */\n    {0, MBPART_I4x4,   VERT_I16x16,     0,  0},\n    {0, MBPART_I16x16, VERT_I16x16,     0,  0},\n    {0, MBPART_I16x16, HORZ_I16x16,     0,  0},\n    {0, MBPART_I16x16, DC_I16x16,       0,  0},\n    {0, MBPART_I16x16, PLANE_I16x16,    0,  0},\n    {0, MBPART_I16x16, VERT_I16x16,     1,  0},\n    {0, MBPART_I16x16, HORZ_I16x16,     1,  0},\n    {0, MBPART_I16x16, DC_I16x16,       1,  0},\n    {0, MBPART_I16x16, PLANE_I16x16,    1,  0},\n    {0, MBPART_I16x16, VERT_I16x16,     2,  0},\n    {0, MBPART_I16x16, HORZ_I16x16,     2,  0},\n    {0, MBPART_I16x16, DC_I16x16,       2,  0},\n    {0, MBPART_I16x16, PLANE_I16x16,    2,  0},\n    {0, MBPART_I16x16, VERT_I16x16,     0,  15},\n    {0, MBPART_I16x16, HORZ_I16x16,     0,  15},\n    {0, MBPART_I16x16, DC_I16x16,       0,  15},\n    {0, MBPART_I16x16, PLANE_I16x16,    0,  15},\n    {0, MBPART_I16x16, VERT_I16x16,     1,  15},\n    {0, MBPART_I16x16, HORZ_I16x16,     1,  15},\n    {0, MBPART_I16x16, DC_I16x16,       1,  15},\n    {0, MBPART_I16x16, PLANE_I16x16,    1,  15},\n    {0, MBPART_I16x16, VERT_I16x16,     2,  15},\n    {0, MBPART_I16x16, HORZ_I16x16,     2,  15},\n    {0, MBPART_I16x16, DC_I16x16,       2,  15},\n    {0, MBPART_I16x16, PLANE_I16x16,    2,  15},\n    {0, MBPART_IPCM,   VERT_I16x16,     0,  0}\n};\n\n/** Table 7-13 Macroblock types for P slices */\ninter_mbtype_info_t gas_ih264_p_mbtype_info[] =\n{\n    {1, MBPART_L0,  MBPART_NA,  16, 16},\n    {2, MBPART_L0,  MBPART_L0,  16, 8},\n    {2, MBPART_L0,  MBPART_L0,  8,  16},\n    {4, MBPART_NA,  MBPART_NA,  8,  8},\n    {4, MBPART_NA,  MBPART_NA,  8,  8},\n};\n\n/** Table 7-14 Macroblock types for B slices */\ninter_mbtype_info_t gas_ih264_b_mbtype_info[] =\n{\n    {0, MBPART_DIRECT,  MBPART_NA,  8,  8,  },\n    {1, MBPART_L0,      MBPART_NA,  16, 16, },\n    {1, MBPART_L1,      MBPART_NA,  16, 16, },\n    {1, MBPART_BI,      MBPART_NA,  16, 16, },\n    {2, MBPART_L0,      MBPART_L0,  16, 8,  },\n    {2, MBPART_L0,      MBPART_L0,  8,  16, },\n    {2, MBPART_L1,      MBPART_L1,  16, 8,  },\n    {2, MBPART_L1,      MBPART_L1,  8,  16, },\n    {2, MBPART_L0,      MBPART_L1,  16, 8,  },\n    {2, MBPART_L0,      MBPART_L1,  8,  16, },\n    {2, MBPART_L1,      MBPART_L0,  16, 8,  },\n    {2, MBPART_L1,      MBPART_L0,  8,  16, },\n    {2, MBPART_L0,      MBPART_BI,  16, 8,  },\n    {2, MBPART_L0,      MBPART_BI,  8,  16, },\n    {2, MBPART_L1,      MBPART_BI,  16, 8,  },\n    {2, MBPART_L1,      MBPART_BI,  8,  16, },\n    {2, MBPART_BI,      MBPART_L0,  16, 8,  },\n    {2, MBPART_BI,      MBPART_L0,  8,  16, },\n    {2, MBPART_BI,      MBPART_L1,  16, 8,  },\n    {2, MBPART_BI,      MBPART_L1,  8,  16, },\n    {2, MBPART_BI,      MBPART_BI,  16, 8,  },\n    {2, MBPART_BI,      MBPART_BI,  8,  16, },\n    {4, MBPART_NA,      MBPART_NA,  8,  8,  },\n};\n\n/** Table 7-17  Sub-macroblock types in P macroblocks */\nsubmbtype_info_t gas_ih264_p_submbtype_info[] =\n{\n   {1, MBPART_L0, 8,  8},\n   {2, MBPART_L0, 8,  4},\n   {2, MBPART_L0, 4,  8},\n   {4, MBPART_L0, 4,  4},\n};\n\n/** Table 7-18  Sub-macroblock types in B macroblocks */\nsubmbtype_info_t gas_ih264_b_submbtype_info[] =\n{\n    {4, MBPART_DIRECT,  4,  4},\n    {1, MBPART_L0,      8,  8},\n    {1, MBPART_L1,      8,  8},\n    {1, MBPART_BI,      8,  8},\n    {2, MBPART_L0,      8,  4},\n    {2, MBPART_L0,      4,  8},\n    {2, MBPART_L1,      8,  4},\n    {2, MBPART_L1,      4,  8},\n    {2, MBPART_BI,      8,  4},\n    {2, MBPART_BI,      4,  8},\n    {4, MBPART_L0,      4,  4},\n    {4, MBPART_L1,      4,  4},\n    {4, MBPART_BI,      4,  4},\n};\n\n\n\n\nconst UWORD8 gau1_ih264_inv_scan_prog4x4[] =\n{\n    0,   1,  4,  8,\n    5,   2,  3,  6,\n    9,  12, 13, 10,\n    7,  11, 14, 15\n};\n\nconst UWORD8 gau1_ih264_inv_scan_int4x4[] =\n{\n     0, 4,  1,  8,\n    12, 5,  9,  13,\n     2, 6, 10,  14,\n     3, 7, 11,  15\n};\n\n/** Inverse scan tables for individual 4x4 blocks of 8x8 transform coeffs of CAVLC */\n/* progressive */\nconst UWORD8 gau1_ih264_inv_scan_prog8x8_cavlc[64] =\n{\n     0,  9, 17, 18, 12, 40, 27,  7,\n    35, 57, 29, 30, 58, 38, 53, 47,\n     1,  2, 24, 11, 19, 48, 20, 14,\n    42, 50, 22, 37, 59, 31, 60, 55,\n     8,  3, 32,  4, 26, 41, 13, 21,\n    49, 43, 15, 44, 52, 39, 61, 62,\n    16, 10, 25,  5, 33, 34,  6, 28,\n    56, 36, 23, 51, 45, 46, 54, 63\n};\n\n/* interlace */\nconst UWORD8 gau1_ih264_inv_scan_int8x8_cavlc[64] =\n{\n     0,  9,  2, 56, 18, 26, 34, 27,\n    35, 28, 36, 29, 45,  7, 54, 39,\n     8, 24, 25, 33, 41, 11, 42, 12,\n    43, 13, 44, 14, 53, 15, 62, 47,\n    16, 32, 40, 10, 49,  4, 50,  5,\n    51,  6, 52, 22, 61, 38, 23, 55,\n     1, 17, 48,  3, 57, 19, 58, 20,\n    59, 21, 60, 37, 30, 46, 31, 63\n};\n\n\n\n/*Inverse scan tables for individual 8x8 blocks of 8x8 transform coeffs of CABAC */\n/* progressive */\n\nconst UWORD8 gau1_ih264_inv_scan_prog8x8_cabac[64] =\n{\n     0,  1,  8, 16,  9, 2,   3, 10,\n    17, 24, 32, 25, 18, 11,  4,  5,\n    12, 19, 26, 33, 40, 48, 41, 34,\n    27, 20, 13,  6,  7, 14, 21, 28,\n    35, 42, 49, 56, 57, 50, 43, 36,\n    29, 22, 15, 23, 30, 37, 44, 51,\n    58, 59, 52, 45, 38, 31, 39, 46,\n    53, 60, 61, 54, 47, 55, 62, 63\n};\n\n\n/* interlace */\n\nconst UWORD8 gau1_ih264_inv_scan_int8x8_cabac[64] =\n{\n     0,  8, 16,  1,  9, 24, 32, 17,\n     2, 25, 40, 48, 56, 33, 10, 3,\n    18, 41, 49, 57, 26, 11,  4, 19,\n    34, 42, 50, 58, 27, 12,  5, 20,\n    35, 43, 51, 59, 28, 13,  6, 21,\n    36, 44, 52, 60, 29, 14, 22, 37,\n    45, 53, 61, 30,  7, 15, 38, 46,\n    54, 62, 23, 31, 39, 47, 55, 63\n};\n\n\nconst UWORD8 *const gpau1_ih264_inv_scan8x8[] =\n{\n     gau1_ih264_inv_scan_prog8x8_cavlc,\n     gau1_ih264_inv_scan_int8x8_cavlc,\n     gau1_ih264_inv_scan_prog8x8_cabac,\n     gau1_ih264_inv_scan_int8x8_cabac\n};\n\nconst UWORD8 *const gpau1_ih264_inv_scan4x4[] =\n{\n     gau1_ih264_inv_scan_prog4x4,\n     gau1_ih264_inv_scan_int4x4,\n};\n\nconst UWORD8 gau1_ih264_8x8_subblk_idx[] =\n{\n      0,    1,   4,  5,\n      2,    3,   6,  7,\n      8,    9,  12, 13,\n     10,   11,  14, 15\n};\n\n\n/* Table 8-15 Chroma QP offset table */\nconst UWORD8 gau1_ih264_chroma_qp[] =\n{\n      0,  1,  2,  3,  4,  5,  6,  7,\n      8,  9, 10, 11, 12, 13, 14, 15,\n     16, 17, 18, 19, 20, 21, 22, 23,\n     24, 25, 26, 27, 28, 29, 29, 30,\n     31, 32, 32, 33, 34, 34, 35, 35,\n     36, 36, 37, 37, 37, 38, 38, 38,\n     39, 39, 39, 39\n};\n\n\n/**\n******************************************************************************\n* @brief  look up table to compute neigbour availability of 4x4 blocks\n* input  : subblk idx, mb neighbor availability\n* output : sub blk neighbor availability\n* @remarks\n******************************************************************************\n*/\nconst UWORD8 gau1_ih264_4x4_ngbr_avbl[16][16] =\n{\n    {  0x0, 0x1, 0xc, 0x7, 0x1, 0x1, 0xf, 0x7, 0xc, 0xf, 0xc, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0x1, 0x1, 0xf, 0x7, 0x1, 0x1, 0xf, 0x7, 0xf, 0xf, 0xf, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0x2, 0x1, 0xc, 0x7, 0x1, 0x1, 0xf, 0x7, 0xc, 0xf, 0xc, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0x3, 0x1, 0xf, 0x7, 0x1, 0x1, 0xf, 0x7, 0xf, 0xf, 0xf, 0x7, 0xf, 0x7, 0xf, 0x7 },\n\n    {  0xc, 0xf, 0xc, 0x7, 0xf, 0x7, 0xf, 0x7, 0xc, 0xf, 0xc, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0xd, 0xf, 0xf, 0x7, 0xf, 0x7, 0xf, 0x7, 0xf, 0xf, 0xf, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0xe, 0xf, 0xc, 0x7, 0xf, 0x7, 0xf, 0x7, 0xc, 0xf, 0xc, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0xf, 0xf, 0xf, 0x7, 0xf, 0x7, 0xf, 0x7, 0xf, 0xf, 0xf, 0x7, 0xf, 0x7, 0xf, 0x7 },\n\n    {  0x0, 0x1, 0xc, 0x7, 0x1, 0x9, 0xf, 0x7, 0xc, 0xf, 0xc, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0x1, 0x1, 0xf, 0x7, 0x1, 0x9, 0xf, 0x7, 0xf, 0xf, 0xf, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0x2, 0x1, 0xc, 0x7, 0x1, 0x9, 0xf, 0x7, 0xc, 0xf, 0xc, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0x3, 0x1, 0xf, 0x7, 0x1, 0x9, 0xf, 0x7, 0xf, 0xf, 0xf, 0x7, 0xf, 0x7, 0xf, 0x7 },\n\n    {  0xc, 0xf, 0xc, 0x7, 0xf, 0xf, 0xf, 0x7, 0xc, 0xf, 0xc, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0xd, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0xe, 0xf, 0xc, 0x7, 0xf, 0xf, 0xf, 0x7, 0xc, 0xf, 0xc, 0x7, 0xf, 0x7, 0xf, 0x7 },\n    {  0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0x7, 0xf, 0x7, 0xf, 0x7 },\n};\n\n\n/**\n******************************************************************************\n* @brief  look up table to compute neigbour availability of 8x8 blocks\n* input  : subblk idx, mb neighbor availability\n* output : sub blk neighbor availability\n* @remarks\n******************************************************************************\n*/\nconst UWORD8 gau1_ih264_8x8_ngbr_avbl[16][4] =\n{\n    {  0x0, 0x1, 0xc, 0x7 },\n    {  0x1, 0x1, 0xf, 0x7 },\n    {  0x2, 0x1, 0xc, 0x7 },\n    {  0x3, 0x1, 0xf, 0x7 },\n\n    {  0xc, 0x7, 0xc, 0x7 },\n    {  0xd, 0x7, 0xf, 0x7 },\n    {  0xe, 0x7, 0xc, 0x7 },\n    {  0xf, 0x7, 0xf, 0x7 },\n\n    {  0x0, 0x9, 0xc, 0x7 },\n    {  0x1, 0x9, 0xf, 0x7 },\n    {  0x2, 0x9, 0xc, 0x7 },\n    {  0x3, 0x9, 0xf, 0x7 },\n\n    {  0xc, 0xf, 0xc, 0x7 },\n    {  0xd, 0xf, 0xf, 0x7 },\n    {  0xe, 0xf, 0xc, 0x7 },\n    {  0xf, 0xf, 0xf, 0x7 },\n};\n\n/** Table 7-3 Default intra 4x4 scaling list */\nconst UWORD16 gau2_ih264_default_intra4x4_scaling_list[] =\n{\n     6, 13, 13, 20,\n    20, 20, 28, 28,\n    28, 28, 32, 32,\n    32, 37, 37, 42\n};\n\n/** Table 7-3 Default inter 4x4 scaling list */\nconst UWORD16 gau2_ih264_default_inter4x4_scaling_list[] =\n{\n    10, 14, 14, 20,\n    20, 20, 24, 24,\n    24, 24, 27, 27,\n    27, 30, 30, 34\n};\n\n/* Inverse scanned output of gau2_ih264_default_intra4x4_scaling_list */\nconst UWORD16 gau2_ih264_default_intra4x4_weight_scale[] =\n{\n     6, 13, 20, 28,\n    13, 20, 28, 32,\n    20, 28, 32, 37,\n    28, 32, 37, 42\n};\n\n/* Inverse scanned output of gau2_ih264_default_inter4x4_scaling_list */\nconst UWORD16 gau2_ih264_default_inter4x4_weight_scale[] =\n{\n     10, 14, 20, 24,\n     14, 20, 24, 27,\n     20, 24, 27, 30,\n     24, 27, 30, 34\n};\n\n/** Table 7-4 Default intra 8x8 scaling list */\nconst UWORD16 gau2_ih264_default_intra8x8_scaling_list[] =\n{\n     6, 10, 10, 13, 11, 13, 16, 16,\n    16, 16, 18, 18, 18, 18, 18, 23,\n    23, 23, 23, 23, 23, 25, 25, 25,\n    25, 25, 25, 25, 27, 27, 27, 27,\n    27, 27, 27, 27, 29, 29, 29, 29,\n    29, 29, 29, 31, 31, 31, 31, 31,\n    31, 33, 33, 33, 33, 33, 36, 36,\n    36, 36, 38, 38, 38, 40, 40, 42\n};\n\n/** Table 7-4 Default inter 8x8 scaling list */\nconst UWORD16 gau2_ih264_default_inter8x8_scaling_list[] =\n{\n    9,  13, 13, 15, 13, 15, 17, 17,\n    17, 17, 19, 19, 19, 19, 19, 21,\n    21, 21, 21, 21, 21, 22, 22, 22,\n    22, 22, 22, 22, 24, 24, 24, 24,\n    24, 24, 24, 24, 25, 25, 25, 25,\n    25, 25, 25, 27, 27, 27, 27, 27,\n    27, 28, 28, 28, 28, 28, 30, 30,\n    30, 30, 32, 32, 32, 33, 33, 35\n};\n\n/* Inverse scanned output of gau2_ih264_default_intra8x8_scaling_list */\nconst UWORD16 gau2_ih264_default_intra8x8_weight_scale[] =\n{\n     6, 10, 13, 16, 18, 23, 25, 27,\n    10, 11, 16, 18, 23, 25, 27, 29,\n    13, 16, 18, 23, 25, 27, 29, 31,\n    16, 18, 23, 25, 27, 29, 31, 33,\n    18, 23, 25, 27, 29, 31, 33, 36,\n    23, 25, 27, 29, 31, 33, 36, 38,\n    25, 27, 29, 31, 33, 36, 38, 40,\n    27, 29, 31, 33, 36, 38, 40, 42\n};\n\n/* Inverse scanned output of gau2_ih264_default_inter8x8_scaling_list */\nconst UWORD16 gau2_ih264_default_inter8x8_weight_scale[] =\n{\n     9, 13, 15, 17, 19, 21, 22, 24,\n    13, 13, 17, 19, 21, 22, 24, 25,\n    15, 17, 19, 21, 22, 24, 25, 27,\n    17, 19, 21, 22, 24, 25, 27, 28,\n    19, 21, 22, 24, 25, 27, 28, 30,\n    21, 22, 24, 25, 27, 28, 30, 32,\n    22, 24, 25, 27, 28, 30, 32, 33,\n    24, 25, 27, 28, 30, 32, 33, 35\n};\n/* Eq 7-8 Flat scaling matrix for 4x4 */\nconst UWORD16 gau2_ih264_flat_4x4_weight_scale[] =\n{\n    16, 16, 16, 16,\n    16, 16, 16, 16,\n    16, 16, 16, 16,\n    16, 16, 16, 16\n};\n\n/* Eq 7-9 Flat scaling matrix for 8x8 */\nconst UWORD16 gau2_ih264_flat_8x8_weight_scale[] =\n{\n    16, 16, 16, 16, 16, 16, 16, 16,\n    16, 16, 16, 16, 16, 16, 16, 16,\n    16, 16, 16, 16, 16, 16, 16, 16,\n    16, 16, 16, 16, 16, 16, 16, 16,\n    16, 16, 16, 16, 16, 16, 16, 16,\n    16, 16, 16, 16, 16, 16, 16, 16,\n    16, 16, 16, 16, 16, 16, 16, 16,\n    16, 16, 16, 16, 16, 16, 16, 16\n};\n\n\n/**\n ******************************************************************************\n * @brief  Scale Table for inverse quantizing 4x4 subblock. To inverse quantize\n * a given 4x4 quantized block, the coefficient at index location (i,j) is scaled\n * by one of the constants in this table and right shift the result by abs (4 -\n * floor(qp/6)), here qp is the quantization parameter used to quantize the mb.\n *\n * input   : 16 * qp%6, index location (i,j)\n * output  : scale constant.\n *\n * @remarks 16 constants for each index position of the subblock and 6 for each\n * qp%6 in the range 0-5 inclusive.\n ******************************************************************************\n */\n\nconst UWORD16 gau2_ih264_iquant_scale_matrix_4x4[96] =\n{\n      10,  13,  10,  13,\n      13,  16,  13,  16,\n      10,  13,  10,  13,\n      13,  16,  13,  16,\n\n      11,  14,  11,  14,\n      14,  18,  14,  18,\n      11,  14,  11,  14,\n      14,  18,  14,  18,\n\n      13,  16,  13,  16,\n      16,  20,  16,  20,\n      13,  16,  13,  16,\n      16,  20,  16,  20,\n\n      14,  18,  14,  18,\n      18,  23,  18,  23,\n      14,  18,  14,  18,\n      18,  23,  18,  23,\n\n      16,  20,  16,  20,\n      20,  25,  20,  25,\n      16,  20,  16,  20,\n      20,  25,  20,  25,\n\n      18,  23,  18,  23,\n      23,  29,  23,  29,\n      18,  23,  18,  23,\n      23,  29,  23,  29,\n\n};\n\n/**\n ******************************************************************************\n * @brief  Scale Table for inverse quantizing 8x8 subblock. To inverse quantize\n * a given 8x8 quantized block, the coefficient at index location (i,j) is scaled\n * by one of the constants in this table and right shift the result by abs (4 -\n * floor(qp/6)), here qp is the quantization parameter used to quantize the mb.\n *\n * input   : qp%6, index location (i,j)\n * output  : scale constant.\n *\n * @remarks 64 constants for each index position of the subblock and 6 for each\n * qp%6 in the range 0-5 inclusive.\n ******************************************************************************\n */\nconst UWORD16 gau2_ih264_iquant_scale_matrix_8x8 [384] =\n{\n      20,  19,  25,  19,  20,  19,  25,  19,\n      19,  18,  24,  18,  19,  18,  24,  18,\n      25,  24,  32,  24,  25,  24,  32,  24,\n      19,  18,  24,  18,  19,  18,  24,  18,\n      20,  19,  25,  19,  20,  19,  25,  19,\n      19,  18,  24,  18,  19,  18,  24,  18,\n      25,  24,  32,  24,  25,  24,  32,  24,\n      19,  18,  24,  18,  19,  18,  24,  18,\n\n      22,  21,  28,  21,  22,  21,  28,  21,\n      21,  19,  26,  19,  21,  19,  26,  19,\n      28,  26,  35,  26,  28,  26,  35,  26,\n      21,  19,  26,  19,  21,  19,  26,  19,\n      22,  21,  28,  21,  22,  21,  28,  21,\n      21,  19,  26,  19,  21,  19,  26,  19,\n      28,  26,  35,  26,  28,  26,  35,  26,\n      21,  19,  26,  19,  21,  19,  26,  19,\n\n      26,  24,  33,  24,  26,  24,  33,  24,\n      24,  23,  31,  23,  24,  23,  31,  23,\n      33,  31,  42,  31,  33,  31,  42,  31,\n      24,  23,  31,  23,  24,  23,  31,  23,\n      26,  24,  33,  24,  26,  24,  33,  24,\n      24,  23,  31,  23,  24,  23,  31,  23,\n      33,  31,  42,  31,  33,  31,  42,  31,\n      24,  23,  31,  23,  24,  23,  31,  23,\n\n      28,  26,  35,  26,  28,  26,  35,  26,\n      26,  25,  33,  25,  26,  25,  33,  25,\n      35,  33,  45,  33,  35,  33,  45,  33,\n      26,  25,  33,  25,  26,  25,  33,  25,\n      28,  26,  35,  26,  28,  26,  35,  26,\n      26,  25,  33,  25,  26,  25,  33,  25,\n      35,  33,  45,  33,  35,  33,  45,  33,\n      26,  25,  33,  25,  26,  25,  33,  25,\n\n      32,  30,  40,  30,  32,  30,  40,  30,\n      30,  28,  38,  28,  30,  28,  38,  28,\n      40,  38,  51,  38,  40,  38,  51,  38,\n      30,  28,  38,  28,  30,  28,  38,  28,\n      32,  30,  40,  30,  32,  30,  40,  30,\n      30,  28,  38,  28,  30,  28,  38,  28,\n      40,  38,  51,  38,  40,  38,  51,  38,\n      30,  28,  38,  28,  30,  28,  38,  28,\n\n      36,  34,  46,  34,  36,  34,  46,  34,\n      34,  32,  43,  32,  34,  32,  43,  32,\n      46,  43,  58,  43,  46,  43,  58,  43,\n      34,  32,  43,  32,  34,  32,  43,  32,\n      36,  34,  46,  34,  36,  34,  46,  34,\n      34,  32,  43,  32,  34,  32,  43,  32,\n      46,  43,  58,  43,  46,  43,  58,  43,\n      34,  32,  43,  32,  34,  32,  43,  32,\n\n};\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_common_tables.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_common_tables.h\n*\n* @brief\n*  Common tables\n*\n* @author\n*  Harish\n*\n* @par List of Functions:\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n#ifndef _IH264_COMMON_TABLES_H_\n#define _IH264_COMMON_TABLES_H_\n\n\n/*****************************************************************************/\n/* Structures                                                                */\n/*****************************************************************************/\n\n/**\n******************************************************************************\n *  @brief      level tables\n******************************************************************************\n */\ntypedef struct\n{\n    /* level */\n    IH264_LEVEL_T     u4_level_idc;\n\n    /* max macroblock processing rate */\n    UWORD32     u4_max_mbps;\n\n    /* max frame size in mbs */\n    UWORD32     u4_max_fs;\n\n    /* max dpb size / 768 */\n    UWORD32     u4_max_dpb_size;\n\n    /* max bit rate */\n    UWORD32     u4_max_br;\n\n    /* max cpb size */\n    UWORD32     u4_max_cpb_size;\n\n    /* max vertical MV component range */\n    UWORD32     u4_max_mv_y;\n\n}level_tables_t;\n\n/*****************************************************************************/\n/* Extern global declarations                                                */\n/*****************************************************************************/\n\n/**\n ******************************************************************************\n * @brief  while encoding, basing on the input configuration parameters, the\n * the level of the bitstream is computed basing on the table below.\n * input  : table_idx\n * output : level_idc or cpb size\n * @remarks Table A-1  level table limits\n ******************************************************************************\n */\nextern const level_tables_t gas_ih264_lvl_tbl[16];\n\nextern const WORD32 gai4_ih264_levels[];\nextern const WORD32 gai4_ih264_max_luma_pic_size[];\nextern const WORD32 gai4_ih264_max_wd_ht[];\nextern const WORD32 gai4_ih264_min_wd_ht[];\n\nextern intra_mbtype_info_t gas_ih264_i_mbtype_info[];\nextern inter_mbtype_info_t gas_ih264_p_mbtype_info[];\nextern inter_mbtype_info_t gas_ih264_b_mbtype_info[];\nextern submbtype_info_t gas_ih264_p_submbtype_info[];\nextern submbtype_info_t gas_ih264_b_submbtype_info[];\n\n\nextern const UWORD8 gau1_ih264_inv_scan_prog4x4[];\nextern const UWORD8 gau1_ih264_inv_scan_int4x4[];\nextern const UWORD8 gau1_ih264_inv_scan_prog8x8_cavlc[64];\nextern const UWORD8 gau1_ih264_inv_scan_int8x8_cavlc[64];\nextern const UWORD8 gau1_ih264_inv_scan_prog8x8_cabac[64];\nextern const UWORD8 gau1_ih264_inv_scan_int8x8_cabac[64];\n\nextern const UWORD8 *const gpau1_ih264_inv_scan8x8[];\nextern const UWORD8 *const gpau1_ih264_inv_scan4x4[];\n\nextern const UWORD8 gau1_ih264_8x8_subblk_idx[];\n\nextern const UWORD8 gau1_ih264_chroma_qp[];\n\nextern const UWORD8 gau1_ih264_4x4_ngbr_avbl[16][16];\nextern const UWORD8 gau1_ih264_8x8_ngbr_avbl[16][4];\n\n\nextern const UWORD16 gau2_ih264_default_inter4x4_weight_scale[];\nextern const UWORD16 gau2_ih264_default_intra4x4_weight_scale[];\nextern const UWORD16 gau2_ih264_default_intra4x4_scaling_list[];\nextern const UWORD16 gau2_ih264_default_inter4x4_scaling_list[];\nextern const UWORD16 gau2_ih264_default_intra8x8_scaling_list[];\nextern const UWORD16 gau2_ih264_default_inter8x8_scaling_list[];\nextern const UWORD16 gau2_ih264_default_intra8x8_weight_scale[];\nextern const UWORD16 gau2_ih264_default_inter8x8_weight_scale[];\nextern const UWORD16 gau2_ih264_flat_4x4_weight_scale[];\nextern const UWORD16 gau2_ih264_flat_8x8_weight_scale[];\n\nextern const UWORD16 gau2_ih264_iquant_scale_matrix_4x4 [96];\nextern const UWORD16 gau2_ih264_iquant_scale_matrix_8x8 [384];\n\n#endif /*_IH264_COMMON_TABLES_H_*/\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_deblk_edge_filters.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**************************************************************************** */\n/*                                                                            */\n/*  File Name         : ih264_deblk_edge_filters.c                            */\n/*                                                                            */\n/*  Description       : Contains function definitions for deblocking          */\n/*                                                                            */\n/*  List of Functions : ih264_deblk_luma_vert_bs4()                           */\n/*                      ih264_deblk_luma_horz_bs4()                           */\n/*                      ih264_deblk_luma_vert_bslt4()                         */\n/*                      ih264_deblk_luma_horz_bslt4()                         */\n/*                      ih264_deblk_luma_vert_bs4_mbaff()                     */\n/*                      ih264_deblk_luma_vert_bslt4_mbaff()                   */\n/*                      ih264_deblk_chroma_vert_bs4_bp()                      */\n/*                      ih264_deblk_chroma_horz_bs4_bp()                      */\n/*                      ih264_deblk_chroma_vert_bslt4_bp()                    */\n/*                      ih264_deblk_chroma_horz_bslt4_bp()                    */\n/*                      ih264_deblk_chroma_vert_bs4_mbaff_bp()                */\n/*                      ih264_deblk_chroma_vert_bslt4_mbaff_bp()              */\n/*                      ih264_deblk_chroma_vert_bs4()                         */\n/*                      ih264_deblk_chroma_horz_bs4()                         */\n/*                      ih264_deblk_chroma_vert_bslt4()                       */\n/*                      ih264_deblk_chroma_horz_bslt4()                       */\n/*                      ih264_deblk_chroma_vert_bs4_mbaff()                   */\n/*                      ih264_deblk_chroma_vert_bslt4_mbaff()                 */\n/*                                                                            */\n/*  Issues / Problems : None                                                  */\n/*                                                                            */\n/*  Revision History  :                                                       */\n/*                                                                            */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)   */\n/*         28 11 2013   Ittiam          Draft                                 */\n/*         29 12 2014   Kaushik         Added double-call vertical            */\n/*                      Senthoor        deblocking and high profile           */\n/*                                      deblocking functions                  */\n/*                                                                            */\n/******************************************************************************/\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System include files */\n#include <stdio.h>\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_deblk_edge_filters.h\"\n#include \"ih264_macros.h\"\n\n/*****************************************************************************/\n/* Function Definitions                                                      */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_vert_bs4()                              */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  vertical edge when the boundary strength is set to 4.    */\n/*                                                                           */\n/*  Inputs        : pu1_src    - pointer to the src sample q0                */\n/*                  src_strd   - source stride                               */\n/*                  alpha      - alpha value for the boundary                */\n/*                  beta       - beta value for the boundary                 */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.4 under the    */\n/*                  title \"Filtering process for edges for bS equal to 4\" in */\n/*                  ITU T Rec H.264.                                         */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         28 11 2013   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_luma_vert_bs4(UWORD8 *pu1_src,\n                               WORD32 src_strd,\n                               WORD32 alpha,\n                               WORD32 beta)\n{\n    UWORD8 p3, p2, p1, p0, q0, q1, q2, q3;\n    WORD32 pos_p3, pos_p2, pos_p1, pos_p0;\n    WORD32 pos_q0, pos_q1, pos_q2,pos_q3;\n    UWORD8 a_p, a_q; /* threshold variables */\n    WORD32 blk_strd = src_strd << 2; /* block_increment = src_strd * 4 */\n    UWORD8 *pu1_src_temp;\n    WORD8 i = 0, edge;\n\n    pos_q0 = 0;\n    pos_q1 = 1;\n    pos_q2 = 2;\n    pos_q3 = 3;\n    pos_p0 = -1;\n    pos_p1 = -2;\n    pos_p2 = -3;\n    pos_p3 = -4;\n\n    for(edge = 0; edge < 4; edge++, pu1_src += blk_strd)\n    {\n        pu1_src_temp = pu1_src;\n        for(i = 0; i < 4; ++i, pu1_src_temp += src_strd)\n        {\n            q0 = pu1_src_temp[pos_q0];\n            q1 = pu1_src_temp[pos_q1];\n            p0 = pu1_src_temp[pos_p0];\n            p1 = pu1_src_temp[pos_p1];\n\n            /* Filter Decision */\n            if((ABS(p0 - q0) >= alpha) ||\n               (ABS(q1 - q0) >= beta)  ||\n               (ABS(p1 - p0) >= beta))\n                continue;\n\n            p2 = pu1_src_temp[pos_p2];\n            p3 = pu1_src_temp[pos_p3];\n            q2 = pu1_src_temp[pos_q2];\n            q3 = pu1_src_temp[pos_q3];\n\n            if(ABS(p0 - q0) < ((alpha >> 2) + 2))\n            {\n                /* Threshold Variables */\n                a_p = (UWORD8)ABS(p2 - p0);\n                a_q = (UWORD8)ABS(q2 - q0);\n\n                if(a_p < beta)\n                {\n                    /* p0', p1', p2' */\n                    pu1_src_temp[pos_p0] = ((p2 + X2(p1) + X2(p0) + X2(q0) + q1\n                                    + 4) >> 3);\n                    pu1_src_temp[pos_p1] = ((p2 + p1 + p0 + q0 + 2) >> 2);\n                    pu1_src_temp[pos_p2] =\n                                    ((X2(p3) + X3(p2) + p1 + p0 + q0\n                                                    + 4) >> 3);\n                }\n                else\n                {\n                    /* p0'*/\n                    pu1_src_temp[pos_p0] = ((X2(p1) + p0 + q1 + 2) >> 2);\n                }\n\n                if(a_q < beta)\n                {\n                    /* q0', q1', q2' */\n                    pu1_src_temp[pos_q0] = (p1 + X2(p0) + X2(q0) + X2(q1) + q2\n                                    + 4) >> 3;\n                    pu1_src_temp[pos_q1] = (p0 + q0 + q1 + q2 + 2) >> 2;\n                    pu1_src_temp[pos_q2] = (X2(q3) + X3(q2) + q1 + q0 + p0 + 4)\n                                    >> 3;\n                }\n                else\n                {\n                    /* q0'*/\n                    pu1_src_temp[pos_q0] = (X2(q1) + q0 + p1 + 2) >> 2;\n                }\n            }\n            else\n            {\n                /* p0', q0'*/\n                pu1_src_temp[pos_p0] = ((X2(p1) + p0 + q1 + 2) >> 2);\n                pu1_src_temp[pos_q0] = (X2(q1) + q0 + p1 + 2) >> 2;\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_horz_bs4()                              */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  horizontal edge when the boundary strength is set to 4.  */\n/*                                                                           */\n/*  Inputs        : pu1_src    - pointer to the src sample q0                */\n/*                  src_strd   - source stride                               */\n/*                  alpha      - alpha value for the boundary                */\n/*                  beta       - beta value for the boundary                 */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.4 under the    */\n/*                  title \"Filtering process for edges for bS equal to 4\" in */\n/*                  ITU T Rec H.264.                                         */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         28 11 2013   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_luma_horz_bs4(UWORD8 *pu1_src,\n                               WORD32 src_strd,\n                               WORD32 alpha,\n                               WORD32 beta)\n{\n    UWORD8 p3, p2, p1, p0, q0, q1, q2, q3;\n    WORD32 pos_p3, pos_p2, pos_p1, pos_p0, pos_q0, pos_q1,\n                    pos_q2, pos_q3;\n    UWORD8 a_p, a_q; /* threshold variables */\n    UWORD8 *pu1_p3; /* pointer to the src sample p3 */\n    UWORD8 *pu1_p3_temp;\n    UWORD8 *pu1_src_temp;\n    WORD8 i = 0, edge;\n\n    pu1_p3 = pu1_src - (src_strd << 2);\n    pos_q0 = 0;\n    pos_q1 = src_strd;\n    pos_q2 = X2(src_strd);\n    pos_q3 = X3(src_strd);\n    pos_p0 = X3(src_strd);\n    pos_p1 = X2(src_strd);\n    pos_p2 = src_strd;\n    pos_p3 = 0;\n\n    for(edge = 0; edge < 4; edge++, pu1_src += 4, pu1_p3 += 4)\n    {\n        pu1_src_temp = pu1_src;\n        pu1_p3_temp = pu1_p3;\n        for(i = 0; i < 4; ++i, pu1_src_temp++, pu1_p3_temp++)\n        {\n            q0 = pu1_src_temp[pos_q0];\n            q1 = pu1_src_temp[pos_q1];\n            p0 = pu1_p3_temp[pos_p0];\n            p1 = pu1_p3_temp[pos_p1];\n\n            /* Filter Decision */\n            if((ABS(p0 - q0) >= alpha) ||\n               (ABS(q1 - q0) >= beta) ||\n               (ABS(p1 - p0) >= beta))\n                continue;\n\n            p2 = pu1_p3_temp[pos_p2];\n            p3 = pu1_p3_temp[pos_p3];\n            q2 = pu1_src_temp[pos_q2];\n            q3 = pu1_src_temp[pos_q3];\n\n            if(ABS(p0 - q0) < ((alpha >> 2) + 2))\n            {\n                /* Threshold Variables */\n                a_p = ABS(p2 - p0);\n                a_q = ABS(q2 - q0);\n\n                if((a_p < beta))\n                {\n                    /* p0', p1', p2' */\n                    pu1_p3_temp[pos_p0] = (p2 + X2(p1) + X2(p0) + X2(q0) + q1\n                                    + 4) >> 3;\n                    pu1_p3_temp[pos_p1] = (p2 + p1 + p0 + q0 + 2) >> 2;\n                    pu1_p3_temp[pos_p2] =\n                                    (X2(p3) + X3(p2) + p1 + p0 + q0\n                                                    + 4) >> 3;\n                }\n                else\n                {\n                    /* p0'*/\n                    pu1_p3_temp[pos_p0] = (X2(p1) + p0 + q1 + 2) >> 2;\n                }\n\n                if(a_q < beta)\n                {\n                    /* q0', q1', q2' */\n                    pu1_src_temp[pos_q0] = (p1 + X2(p0) + X2(q0) + X2(q1)\n                                    + q2 + 4) >> 3;\n                    pu1_src_temp[pos_q1] = (p0 + q0 + q1 + q2 + 2) >> 2;\n                    pu1_src_temp[pos_q2] = (X2(q3) + X3(q2) + q1 + q0 + p0\n                                    + 4) >> 3;\n                }\n                else\n                {\n                    /* q0'*/\n                    pu1_src_temp[pos_q0] = (X2(q1) + q0 + p1 + 2) >> 2;\n                }\n            }\n            else\n            {\n                /* p0', q0'*/\n                pu1_p3_temp[pos_p0] = (X2(p1) + p0 + q1 + 2) >> 2;\n                pu1_src_temp[pos_q0] = (X2(q1) + q0 + p1 + 2) >> 2;\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bs4_bp()                         */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when the boundary strength is set to 4.    */\n/*                                                                           */\n/*  Inputs        : pu1_src    - pointer to the src sample q0 of U           */\n/*                  src_strd   - source stride                               */\n/*                  alpha      - alpha value for the boundary                */\n/*                  beta       - beta value for the boundary                 */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.4 under the    */\n/*                  title \"Filtering process for edges for bS equal to 4\" in */\n/*                  ITU T Rec H.264.                                         */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         28 11 2013   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_vert_bs4_bp(UWORD8 *pu1_src,\n                                    WORD32 src_strd,\n                                    WORD32 alpha,\n                                    WORD32 beta)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* pointer to the src sample q0 of U */\n    UWORD8 *pu1_src_v = pu1_src + 1; /* pointer to the src sample q0 of V */\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 blk_strd = src_strd << 1; /* block_increment = src_strd * 2 */\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    WORD8 i = 0, edge;\n\n    pos_q0 = 0;\n    pos_q1 = 2;\n    pos_p0 = -2;\n    pos_p1 = -4;\n\n    for(edge = 0; edge < 4;\n                    edge++, pu1_src_u += blk_strd, pu1_src_v += blk_strd)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_src_temp_v = pu1_src_v;\n        for(i = 0; i < 2; ++i, pu1_src_temp_u += src_strd, pu1_src_temp_v +=\n                        src_strd)\n        {\n            q0_u = pu1_src_temp_u[pos_q0];\n            q1_u = pu1_src_temp_u[pos_q1];\n            p0_u = pu1_src_temp_u[pos_p0];\n            p1_u = pu1_src_temp_u[pos_p1];\n            q0_v = pu1_src_temp_v[pos_q0];\n            q1_v = pu1_src_temp_v[pos_q1];\n            p0_v = pu1_src_temp_v[pos_p0];\n            p1_v = pu1_src_temp_v[pos_p1];\n\n            /* Filter Decision */\n            if((ABS(p0_u - q0_u) < alpha) &&\n               (ABS(q1_u - q0_u) < beta) &&\n               (ABS(p1_u - p0_u) < beta))\n            {\n                /* p0' */\n                pu1_src_temp_u[pos_p0] = ((X2(p1_u) + p0_u + q1_u + 2) >> 2);\n                /* q0' */\n                pu1_src_temp_u[pos_q0] = (X2(q1_u) + q0_u + p1_u + 2) >> 2;\n            }\n\n            /* Filter Decision */\n            if((ABS(p0_v - q0_v) < alpha) &&\n               (ABS(q1_v - q0_v) < beta) &&\n               (ABS(p1_v - p0_v) < beta))\n            {\n                /* p0' */\n                pu1_src_temp_v[pos_p0] = ((X2(p1_v) + p0_v + q1_v + 2) >> 2);\n                /* q0' */\n                pu1_src_temp_v[pos_q0] = (X2(q1_v) + q0_v + p1_v + 2) >> 2;\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_horz_bs4_bp()                         */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  horizontal edge when the boundary strength is set to 4.  */\n/*                                                                           */\n/*  Inputs        : pu1_src    - pointer to the src sample q0 of U           */\n/*                  src_strd   - source stride                               */\n/*                  alpha      - alpha value for the boundary                */\n/*                  beta       - beta value for the boundary                 */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.4 under the    */\n/*                  title \"Filtering process for edges for bS equal to 4\" in */\n/*                  ITU T Rec H.264.                                         */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         28 11 2013   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_horz_bs4_bp(UWORD8 *pu1_src,\n                                    WORD32 src_strd,\n                                    WORD32 alpha,\n                                    WORD32 beta)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* pointer to the src sample q0 of U */\n    UWORD8 *pu1_src_v = pu1_src + 1; /* pointer to the src sample q0 of V */\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    UWORD8 *pu1_p1_u; /* pointer to the src sample p1 of U */\n    UWORD8 *pu1_p1_v; /* pointer to the src sample p1 of U */\n    UWORD8 *pu1_p1_temp_u, *pu1_p1_temp_v;\n    WORD8 i = 0, edge;\n\n    pu1_p1_u = pu1_src_u - (src_strd << 1);\n    pu1_p1_v = pu1_src_v - (src_strd << 1);\n    pos_q0 = 0;\n    pos_q1 = src_strd;\n    pos_p0 = src_strd;\n    pos_p1 = 0;\n\n    for(edge = 0; edge < 4; edge++, pu1_src_u += 4, pu1_p1_u += 4,\n                    pu1_src_v += 4, pu1_p1_v += 4)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_p1_temp_u = pu1_p1_u;\n        pu1_src_temp_v = pu1_src_v;\n        pu1_p1_temp_v = pu1_p1_v;\n        for(i = 0; i < 2; ++i, pu1_src_temp_u += 2, pu1_p1_temp_u += 2,\n                    pu1_src_temp_v += 2, pu1_p1_temp_v += 2)\n        {\n            q0_u = pu1_src_temp_u[pos_q0];\n            q1_u = pu1_src_temp_u[pos_q1];\n            p0_u = pu1_p1_temp_u[pos_p0];\n            p1_u = pu1_p1_temp_u[pos_p1];\n\n            q0_v = pu1_src_temp_v[pos_q0];\n            q1_v = pu1_src_temp_v[pos_q1];\n            p0_v = pu1_p1_temp_v[pos_p0];\n            p1_v = pu1_p1_temp_v[pos_p1];\n\n            /* Filter Decision */\n            if((ABS(p0_u - q0_u) < alpha) &&\n               (ABS(q1_u - q0_u) < beta) &&\n               (ABS(p1_u - p0_u) < beta))\n            {\n                /* p0' */\n                pu1_p1_temp_u[pos_p0] = (X2(p1_u) + p0_u + q1_u + 2) >> 2;\n                /* q0' */\n                pu1_src_temp_u[pos_q0] = (X2(q1_u) + q0_u + p1_u + 2) >> 2;\n            }\n\n            /* Filter Decision */\n            if((ABS(p0_v - q0_v) < alpha) &&\n               (ABS(q1_v - q0_v) < beta) &&\n               (ABS(p1_v - p0_v) < beta))\n            {\n                /* p0' */\n                pu1_p1_temp_v[pos_p0] = (X2(p1_v) + p0_v + q1_v + 2) >> 2;\n                /* q0' */\n                pu1_src_temp_v[pos_q0] = (X2(q1_v) + q0_v + p1_v + 2) >> 2;\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_vert_bslt4()                            */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  vertical edge when the boundary strength is less than 4. */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0             */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                  u4_bs         - packed Boundary strength array           */\n/*                  pu1_cliptab   - tc0_table                                */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.3 under the    */\n/*                  title \"Filtering process for edges for bS less than 4\"   */\n/*                  in ITU T Rec H.264.                                      */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         28 11 2013   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_luma_vert_bslt4(UWORD8 *pu1_src,\n                                 WORD32 src_strd,\n                                 WORD32 alpha,\n                                 WORD32 beta,\n                                 UWORD32 u4_bs,\n                                 const UWORD8 *pu1_cliptab)\n{\n    WORD8 i = 0, edge;\n    UWORD8 p2, p1, p0, q0, q1, q2;\n    WORD32 pos_p2, pos_p1, pos_p0, pos_q0, pos_q1, pos_q2;\n    UWORD8 a_p, a_q; /* threshold variables */\n    WORD32 blk_strd = src_strd << 2; /* block_increment = src_strd * 4 */\n    UWORD8 *pu1_src_temp;\n    WORD8 delta;\n    WORD8 tc;\n    WORD16 val;\n    UWORD8 tc0, u1_bs;\n\n    pos_q0 = 0;\n    pos_q1 = 1;\n    pos_q2 = 2;\n    pos_p0 = -1;\n    pos_p1 = -2;\n    pos_p2 = -3;\n\n    for(edge = 0; edge < 4; edge++, pu1_src += blk_strd)\n    {\n        pu1_src_temp = pu1_src;\n        /* Filter Decision */\n        u1_bs = (UWORD8)((u4_bs >> ((3 - edge) << 3)) & 0x0ff);\n        if(!u1_bs)\n            continue;\n        /* tc0 */\n        tc0 = pu1_cliptab[u1_bs];\n        for(i = 0; i < 4; ++i, pu1_src_temp += src_strd)\n        {\n            q0 = pu1_src_temp[pos_q0];\n            q1 = pu1_src_temp[pos_q1];\n            p0 = pu1_src_temp[pos_p0];\n            p1 = pu1_src_temp[pos_p1];\n\n            /* Filter Decision */\n            if((ABS(p0 - q0) >= alpha) ||\n               (ABS(q1 - q0) >= beta) ||\n               (ABS(p1 - p0) >= beta))\n                continue;\n\n            q2 = pu1_src_temp[pos_q2];\n            p2 = pu1_src_temp[pos_p2];\n\n            a_p = ABS(p2 - p0);\n            a_q = ABS(q2 - q0);\n\n            /* tc */\n            tc = tc0 + (a_p < beta) + (a_q < beta);\n\n            val = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3);\n            delta = CLIP3(-tc, tc, val);\n\n            /* p0' */\n            val = p0 + delta;\n            pu1_src_temp[pos_p0] = CLIP_U8(val);\n            /* q0' */\n            val = q0 - delta;\n            pu1_src_temp[pos_q0] = CLIP_U8(val);\n\n            /* Luma only */\n            if(a_p < beta)\n            {\n                /* p1' */\n                val = ((p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1);\n                pu1_src_temp[pos_p1] += CLIP3(-tc0, tc0, val);\n            }\n\n            if(a_q < beta)\n            {\n                /* q1' */\n                val = ((q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1);\n                pu1_src_temp[pos_q1] += CLIP3(-tc0, tc0, val);\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bslt4_bp()                       */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when the boundary strength is less than 4. */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0 of U        */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                  u4_bs         - packed Boundary strength array           */\n/*                  pu1_cliptab   - tc0_table                                */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.3 under the    */\n/*                  title \"Filtering process for edges for bS less than 4\"   */\n/*                  in ITU T Rec H.264.                                      */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         28 11 2013   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_vert_bslt4_bp(UWORD8 *pu1_src,\n                                      WORD32 src_strd,\n                                      WORD32 alpha,\n                                      WORD32 beta,\n                                      UWORD32 u4_bs,\n                                      const UWORD8 *pu1_cliptab)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    UWORD8 *pu1_src_v = pu1_src + 1; /* Pointer to the src sample q0 of plane V*/\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 blk_strd = src_strd << 1; /* block_increment = src_strd * (4 >> 1)*/\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    WORD8 i = 0, edge;\n    WORD8 delta;\n    WORD8 tc;\n    WORD16 val;\n    UWORD8 tc0, u1_bs;\n\n    pos_q0 = 0;\n    pos_q1 = 2;\n    pos_p0 = -2;\n    pos_p1 = -4;\n\n    for(edge = 0; edge < 4;\n                    edge++, pu1_src_u += blk_strd, pu1_src_v += blk_strd)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_src_temp_v = pu1_src_v;\n        /* Filter Decision */\n        u1_bs = (UWORD8)((u4_bs >> ((3 - edge) << 3)) & 0x0ff);\n        if(!u1_bs)\n            continue;\n        /* tc0 */\n        tc0 = pu1_cliptab[u1_bs];\n        tc = tc0 + 1;\n        for(i = 0; i < 2; ++i, pu1_src_temp_u += src_strd, pu1_src_temp_v +=\n                        src_strd)\n        {\n            q0_u = pu1_src_temp_u[pos_q0];\n            q1_u = pu1_src_temp_u[pos_q1];\n            p0_u = pu1_src_temp_u[pos_p0];\n            p1_u = pu1_src_temp_u[pos_p1];\n\n            q0_v = pu1_src_temp_v[pos_q0];\n            q1_v = pu1_src_temp_v[pos_q1];\n            p0_v = pu1_src_temp_v[pos_p0];\n            p1_v = pu1_src_temp_v[pos_p1];\n\n            /* Filter Decision */\n            if((ABS(p0_u - q0_u) < alpha) &&\n               (ABS(q1_u - q0_u) < beta) &&\n               (ABS(p1_u - p0_u) < beta))\n            {\n                val = ((((q0_u - p0_u) << 2) + (p1_u - q1_u) + 4) >> 3);\n                delta = CLIP3(-tc, tc, val);\n                /* p0' */\n                val = p0_u + delta;\n                pu1_src_temp_u[pos_p0] = CLIP_U8(val);\n                /* q0' */\n                val = q0_u - delta;\n                pu1_src_temp_u[pos_q0] = CLIP_U8(val);\n            }\n\n            /* Filter Decision */\n            if((ABS(p0_v - q0_v) < alpha) &&\n               (ABS(q1_v - q0_v) < beta) &&\n               (ABS(p1_v - p0_v) < beta))\n            {\n                val = ((((q0_v - p0_v) << 2) + (p1_v - q1_v) + 4) >> 3);\n                delta = CLIP3(-tc, tc, val);\n                /* p0' */\n                val = p0_v + delta;\n                pu1_src_temp_v[pos_p0] = CLIP_U8(val);\n                /* q0' */\n                val = q0_v - delta;\n                pu1_src_temp_v[pos_q0] = CLIP_U8(val);\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_horz_bslt4()                            */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  horizontal edge when boundary strength is less than 4.   */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0             */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                  u4_bs         - packed Boundary strength array           */\n/*                  pu1_cliptab   - tc0_table                                */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.3 under the    */\n/*                  title \"Filtering process for edges for bS less than 4\"   */\n/*                  in ITU T Rec H.264.                                      */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         28 11 2013   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_luma_horz_bslt4(UWORD8 *pu1_src,\n                                 WORD32 src_strd,\n                                 WORD32 alpha,\n                                 WORD32 beta,\n                                 UWORD32 u4_bs,\n                                 const UWORD8 *pu1_cliptab)\n{\n    UWORD8 p2, p1, p0, q0, q1, q2;\n    WORD32 pos_p2, pos_p1, pos_p0, pos_q0, pos_q1, pos_q2;\n    UWORD8 a_p, a_q; /* Threshold variables */\n    UWORD8 *pu1_p2; /* Pointer to the src sample p2 */\n    UWORD8 *pu1_p2_temp;\n    UWORD8 *pu1_src_temp;\n    WORD8 i = 0, edge;\n    WORD8 delta;\n    WORD8 tc;\n    WORD16 val;\n    UWORD8 tc0, u1_bs;\n\n    pu1_p2 = pu1_src - (src_strd << 2);\n    pos_q0 = 0;\n    pos_q1 = src_strd;\n    pos_q2 = X2(src_strd);\n    pos_p0 = X3(src_strd);\n    pos_p1 = X2(src_strd);\n    pos_p2 = src_strd;\n\n    for(edge = 0; edge < 4; edge++, pu1_src += 4, pu1_p2 += 4)\n    {\n        pu1_src_temp = pu1_src;\n        pu1_p2_temp = pu1_p2;\n\n        /* Filter Decision */\n        u1_bs = (UWORD8)((u4_bs >> ((3 - edge) << 3)) & 0x0ff);\n        if(!u1_bs)\n            continue;\n        /* tc0 */\n        tc0 = pu1_cliptab[u1_bs];\n\n        for(i = 0; i < 4; ++i, pu1_src_temp++, pu1_p2_temp++)\n        {\n            q0 = pu1_src_temp[pos_q0];\n            q1 = pu1_src_temp[pos_q1];\n            p0 = pu1_p2_temp[pos_p0];\n            p1 = pu1_p2_temp[pos_p1];\n\n            /* Filter Decision */\n            if((ABS(p0 - q0) >= alpha) ||\n               (ABS(q1 - q0) >= beta) ||\n               (ABS(p1 - p0) >= beta))\n                continue;\n\n            q2 = pu1_src_temp[pos_q2];\n            p2 = pu1_p2_temp[pos_p2];\n\n            a_p = ABS(p2 - p0);\n            a_q = ABS(q2 - q0);\n\n            /* tc */\n            tc = tc0 + (a_p < beta) + (a_q < beta);\n            val = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3);\n            delta = CLIP3(-tc, tc, val);\n            /* p0' */\n            val = p0 + delta;\n            pu1_p2_temp[pos_p0] = CLIP_U8(val);\n            /* q0' */\n            val = q0 - delta;\n            pu1_src_temp[pos_q0] = CLIP_U8(val);\n\n            /* Luma */\n            if(a_p < beta)\n            {\n                /* p1' */\n                val = ((p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1);\n                pu1_p2_temp[pos_p1] += CLIP3(-tc0, tc0, val);\n            }\n\n            if(a_q < beta)\n            {\n                /* q1' */\n                val = ((q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1);\n                pu1_src_temp[pos_q1] += CLIP3(-tc0, tc0, val);\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_horz_bslt4_bp()                       */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  horizontal edge when boundary strength is less than 4.   */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0 of U        */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                  u4_bs         - packed Boundary strength array           */\n/*                  pu1_cliptab   - tc0_table                                */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.3 under the    */\n/*                  title \"Filtering process for edges for bS less than 4\"   */\n/*                  in ITU T Rec H.264.                                      */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         28 11 2013   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_horz_bslt4_bp(UWORD8 *pu1_src,\n                                      WORD32 src_strd,\n                                      WORD32 alpha,\n                                      WORD32 beta,\n                                      UWORD32 u4_bs,\n                                      const UWORD8 *pu1_cliptab)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    UWORD8 *pu1_src_v = pu1_src + 1; /* Pointer to the src sample q0 of plane V*/\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    UWORD8 *pu1_p1_u; /* Pointer to the src sample p1 of plane U*/\n    UWORD8 *pu1_p1_v; /* Pointer to the src sample p1 of plane V*/\n    UWORD8 *pu1_p1_temp_u, *pu1_p1_temp_v;\n    WORD8 i = 0, edge;\n    WORD8 delta;\n    WORD8 tc;\n    WORD16 val;\n    UWORD8 u1_bs;\n    UWORD8 tc0;\n\n    pu1_p1_u = pu1_src_u - (src_strd << 1);\n    pu1_p1_v = pu1_src_v - (src_strd << 1);\n    pos_q0 = 0;\n    pos_q1 = src_strd;\n    pos_p0 = src_strd;\n    pos_p1 = 0;\n\n    for(edge = 0; edge < 4; edge++, pu1_src_u += 4, pu1_p1_u += 4,\n                    pu1_src_v += 4, pu1_p1_v += 4)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_p1_temp_u = pu1_p1_u;\n        pu1_src_temp_v = pu1_src_v;\n        pu1_p1_temp_v = pu1_p1_v;\n\n        /* Filter Decision */\n        u1_bs = (UWORD8)((u4_bs >> ((3 - edge) << 3)) & 0x0ff);\n        if(!u1_bs)\n            continue;\n        /* tc0 */\n        tc0 = pu1_cliptab[u1_bs];\n\n        for(i = 0; i < 2; ++i, pu1_src_temp_u += 2, pu1_p1_temp_u += 2,\n                       pu1_src_temp_v += 2, pu1_p1_temp_v += 2)\n        {\n            q0_u = pu1_src_temp_u[pos_q0];\n            q1_u = pu1_src_temp_u[pos_q1];\n            p0_u = pu1_p1_temp_u[pos_p0];\n            p1_u = pu1_p1_temp_u[pos_p1];\n\n            q0_v = pu1_src_temp_v[pos_q0];\n            q1_v = pu1_src_temp_v[pos_q1];\n            p0_v = pu1_p1_temp_v[pos_p0];\n            p1_v = pu1_p1_temp_v[pos_p1];\n\n            /* tc */\n            tc = tc0 + 1;\n            /* Filter Decision */\n            if(ABS(p0_u - q0_u) < alpha && ABS(q1_u - q0_u) < beta\n                            && ABS(p1_u - p0_u) < beta)\n            {\n                val = ((((q0_u - p0_u) << 2) + (p1_u - q1_u) + 4) >> 3);\n                delta = CLIP3(-tc, tc, val);\n                /* p0' */\n                val = p0_u + delta;\n                pu1_p1_temp_u[pos_p0] = CLIP_U8(val);\n                /* q0' */\n                val = q0_u - delta;\n                pu1_src_temp_u[pos_q0] = CLIP_U8(val);\n            }\n            /* Filter Decision */\n            if(ABS(p0_v - q0_v) < alpha && ABS(q1_v - q0_v) < beta\n                            && ABS(p1_v - p0_v) < beta)\n            {\n                val = ((((q0_v - p0_v) << 2) + (p1_v - q1_v) + 4) >> 3);\n                delta = CLIP3(-tc, tc, val);\n                /* p0' */\n                val = p0_v + delta;\n                pu1_p1_temp_v[pos_p0] = CLIP_U8(val);\n                /* q0' */\n                val = q0_v - delta;\n                pu1_src_temp_v[pos_q0] = CLIP_U8(val);\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/* Function Definitions for vertical edge deblocking for double-call         */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_vert_bs4_mbaff()                        */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  vertical edge when boundary strength is set to 4.        */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0             */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : When the function is called twice, this operation is as  */\n/*                  described in Sec. 8.7.2.3 under the title \"Filtering     */\n/*                  process for edges for bS equal to 4\" in ITU T Rec H.264. */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         29 12 2014   Kaushik         Draft                                */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_luma_vert_bs4_mbaff(UWORD8 *pu1_src,\n                                     WORD32 src_strd,\n                                     WORD32 alpha,\n                                     WORD32 beta)\n{\n    UWORD8 p3, p2, p1, p0, q0, q1, q2, q3;\n    WORD32 pos_p3, pos_p2, pos_p1, pos_p0;\n    WORD32 pos_q0, pos_q1, pos_q2, pos_q3;\n    UWORD8 a_p, a_q; /* threshold variables */\n    WORD32 blk_strd = src_strd << 1; /* block_increment = src_strd * 2 */\n    UWORD8 *pu1_src_temp;\n    WORD8 i = 0, edge;\n\n    pos_q0 = 0;\n    pos_q1 = 1;\n    pos_q2 = 2;\n    pos_q3 = 3;\n    pos_p0 = -1;\n    pos_p1 = -2;\n    pos_p2 = -3;\n    pos_p3 = -4;\n\n    for(edge = 0; edge < 4; edge++, pu1_src += blk_strd)\n    {\n        pu1_src_temp = pu1_src;\n        for(i = 0; i < 2; ++i, pu1_src_temp += src_strd)\n        {\n            q0 = pu1_src_temp[pos_q0];\n            q1 = pu1_src_temp[pos_q1];\n            p0 = pu1_src_temp[pos_p0];\n            p1 = pu1_src_temp[pos_p1];\n\n            /* Filter Decision */\n            if((ABS(p0 - q0) >= alpha) ||\n               (ABS(q1 - q0) >= beta) ||\n               (ABS(p1 - p0) >= beta))\n                continue;\n\n            p2 = pu1_src_temp[pos_p2];\n            p3 = pu1_src_temp[pos_p3];\n            q2 = pu1_src_temp[pos_q2];\n            q3 = pu1_src_temp[pos_q3];\n\n            if(ABS(p0 - q0) < ((alpha >> 2) + 2))\n            {\n                /* Threshold Variables */\n                a_p = (UWORD8)ABS(p2 - p0);\n                a_q = (UWORD8)ABS(q2 - q0);\n\n                if(a_p < beta)\n                {\n                    /* p0', p1', p2' */\n                    pu1_src_temp[pos_p0] = ((p2 + X2(p1) + X2(p0) + X2(q0) + q1\n                                    + 4) >> 3);\n                    pu1_src_temp[pos_p1] = ((p2 + p1 + p0 + q0 + 2) >> 2);\n                    pu1_src_temp[pos_p2] =\n                                    ((X2(p3) + X3(p2) + p1 + p0 + q0\n                                                    + 4) >> 3);\n                }\n                else\n                {\n                    /* p0'*/\n                    pu1_src_temp[pos_p0] = ((X2(p1) + p0 + q1 + 2) >> 2);\n                }\n\n                if(a_q < beta)\n                {\n                    /* q0', q1', q2' */\n                    pu1_src_temp[pos_q0] = (p1 + X2(p0) + X2(q0) + X2(q1) + q2\n                                    + 4) >> 3;\n                    pu1_src_temp[pos_q1] = (p0 + q0 + q1 + q2 + 2) >> 2;\n                    pu1_src_temp[pos_q2] = (X2(q3) + X3(q2) + q1 + q0 + p0 + 4)\n                                    >> 3;\n                }\n                else\n                {\n                    /* q0'*/\n                    pu1_src_temp[pos_q0] = (X2(q1) + q0 + p1 + 2) >> 2;\n                }\n            }\n            else\n            {\n                /* p0', q0'*/\n                pu1_src_temp[pos_p0] = ((X2(p1) + p0 + q1 + 2) >> 2);\n                pu1_src_temp[pos_q0] = (X2(q1) + q0 + p1 + 2) >> 2;\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bs4_mbaff_bp()                   */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when boundary strength is set to 4.        */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0 of U        */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : When the function is called twice, this operation is as  */\n/*                  described in Sec. 8.7.2.3 under the title \"Filtering     */\n/*                  process for edges for bS equal to 4\" in ITU T Rec H.264. */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         29 12 2014   Kaushik         Draft                                */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_vert_bs4_mbaff_bp(UWORD8 *pu1_src,\n                                          WORD32 src_strd,\n                                          WORD32 alpha,\n                                          WORD32 beta)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* Pointer to the src sample q0 of U */\n    UWORD8 *pu1_src_v = pu1_src + 1; /* Pointer to the src sample q0 of V */\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 blk_strd = src_strd;\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    WORD8 edge;\n\n    pos_q0 = 0;\n    pos_q1 = 2;\n    pos_p0 = -2;\n    pos_p1 = -4;\n\n    for(edge = 0; edge < 4;\n                    edge++, pu1_src_u += blk_strd, pu1_src_v += blk_strd)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_src_temp_v = pu1_src_v;\n\n        q0_u = pu1_src_temp_u[pos_q0];\n        q1_u = pu1_src_temp_u[pos_q1];\n        p0_u = pu1_src_temp_u[pos_p0];\n        p1_u = pu1_src_temp_u[pos_p1];\n        q0_v = pu1_src_temp_v[pos_q0];\n        q1_v = pu1_src_temp_v[pos_q1];\n        p0_v = pu1_src_temp_v[pos_p0];\n        p1_v = pu1_src_temp_v[pos_p1];\n\n        /* Filter Decision */\n        if((ABS(p0_u - q0_u) < alpha) &&\n           (ABS(q1_u - q0_u) < beta) &&\n           (ABS(p1_u - p0_u) < beta))\n        {\n            /* p0' */\n            pu1_src_temp_u[pos_p0] = ((X2(p1_u) + p0_u + q1_u + 2) >> 2);\n            /* q0' */\n            pu1_src_temp_u[pos_q0] = (X2(q1_u) + q0_u + p1_u + 2) >> 2;\n        }\n\n        /* Filter Decision */\n        if(ABS(p0_v - q0_v) < alpha && ABS(q1_v - q0_v) < beta\n                        && ABS(p1_v - p0_v) < beta)\n        {\n            /* p0' */\n            pu1_src_temp_v[pos_p0] = ((X2(p1_v) + p0_v + q1_v + 2) >> 2);\n            /* q0' */\n            pu1_src_temp_v[pos_q0] = (X2(q1_v) + q0_v + p1_v + 2) >> 2;\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_vert_bslt4_mbaff()                      */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  vertical edge when boundary strength is less than 4.     */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0             */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                  u4_bs         - packed Boundary strength array           */\n/*                  pu1_cliptab   - tc0_table                                */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : When the function is called twice, this operation is as  */\n/*                  described in Sec. 8.7.2.3 under the title \"Filtering     */\n/*                  process for edges for bS less than 4\" in ITU T Rec H.264.*/\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         29 12 2014   Kaushik         Draft                                */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_luma_vert_bslt4_mbaff(UWORD8 *pu1_src,\n                                       WORD32 src_strd,\n                                       WORD32 alpha,\n                                       WORD32 beta,\n                                       UWORD32 u4_bs,\n                                       const UWORD8 *pu1_cliptab)\n{\n    WORD8 i = 0, edge;\n    UWORD8 p2, p1, p0, q0, q1, q2;\n    WORD32 pos_p2, pos_p1, pos_p0, pos_q0, pos_q1, pos_q2;\n    UWORD8 a_p, a_q; /* Threshold variables */\n    WORD32 blk_strd = src_strd << 1; /* block_increment = src_strd * 2 */\n    UWORD8 *pu1_src_temp;\n    WORD8 delta;\n    WORD8 tc;\n    WORD16 val;\n    UWORD8 tc0, u1_bs;\n\n    pos_q0 = 0;\n    pos_q1 = 1;\n    pos_q2 = 2;\n    pos_p0 = -1;\n    pos_p1 = -2;\n    pos_p2 = -3;\n\n    for(edge = 0; edge < 4; edge++, pu1_src += blk_strd)\n    {\n        pu1_src_temp = pu1_src;\n        /* Filter Decision */\n        u1_bs = (UWORD8)((u4_bs >> ((3 - edge) << 3)) & 0x0ff);\n        if(!u1_bs)\n            continue;\n        /* tc0 */\n        tc0 = pu1_cliptab[u1_bs];\n        for(i = 0; i < 2; ++i, pu1_src_temp += src_strd)\n        {\n            q0 = pu1_src_temp[pos_q0];\n            q1 = pu1_src_temp[pos_q1];\n            p0 = pu1_src_temp[pos_p0];\n            p1 = pu1_src_temp[pos_p1];\n\n            /* Filter Decision */\n            if((ABS(p0 - q0) >= alpha) ||\n               (ABS(q1 - q0) >= beta) ||\n               (ABS(p1 - p0) >= beta))\n                continue;\n\n            q2 = pu1_src_temp[pos_q2];\n            p2 = pu1_src_temp[pos_p2];\n\n            a_p = ABS(p2 - p0);\n            a_q = ABS(q2 - q0);\n\n            /* tc */\n            tc = tc0 + (a_p < beta) + (a_q < beta);\n\n            val = ((((q0 - p0) << 2) + (p1 - q1) + 4) >> 3);\n            delta = CLIP3(-tc, tc, val);\n            /* p0' */\n            val = p0 + delta;\n            pu1_src_temp[pos_p0] = CLIP_U8(val);\n            /* q0' */\n            val = q0 - delta;\n            pu1_src_temp[pos_q0] = CLIP_U8(val);\n\n            /* Luma only */\n            if(a_p < beta)\n            {\n                /* p1' */\n                val = ((p2 + ((p0 + q0 + 1) >> 1) - (p1 << 1)) >> 1);\n                pu1_src_temp[pos_p1] += CLIP3(-tc0, tc0, val);\n            }\n\n            if(a_q < beta)\n            {\n                /* q1' */\n                val = ((q2 + ((p0 + q0 + 1) >> 1) - (q1 << 1)) >> 1);\n                pu1_src_temp[pos_q1] += CLIP3(-tc0, tc0, val);\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bslt4_mbaff_bp()                 */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when boundary strength is less than 4.     */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0 of U        */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                  u4_bs         - packed Boundary strength array           */\n/*                  pu1_cliptab   - tc0_table                                */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : When the function is called twice, this operation is as  */\n/*                  described in Sec. 8.7.2.3 under the title \"Filtering     */\n/*                  process for edges for bS less than 4\" in ITU T Rec H.264.*/\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         29 12 2014   Kaushik         Draft                                */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_vert_bslt4_mbaff_bp(UWORD8 *pu1_src,\n                                            WORD32 src_strd,\n                                            WORD32 alpha,\n                                            WORD32 beta,\n                                            UWORD32 u4_bs,\n                                            const UWORD8 *pu1_cliptab)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    UWORD8 *pu1_src_v = pu1_src + 1; /* Pointer to the src sample q0 of plane V*/\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 blk_strd = src_strd;\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    WORD8 edge;\n    WORD8 delta;\n    WORD8 tc;\n    WORD16 val;\n    UWORD8 tc0, u1_bs;\n\n    pos_q0 = 0;\n    pos_q1 = 2;\n    pos_p0 = -2;\n    pos_p1 = -4;\n\n    for(edge = 0; edge < 4;\n                    edge++, pu1_src_u += blk_strd, pu1_src_v += blk_strd)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_src_temp_v = pu1_src_v;\n        /* Filter Decision */\n        u1_bs = (UWORD8)((u4_bs >> ((3 - edge) << 3)) & 0x0ff);\n        if(!u1_bs)\n            continue;\n        /* tc0 */\n        tc0 = pu1_cliptab[u1_bs];\n        tc = tc0 + 1;\n\n        q0_u = pu1_src_temp_u[pos_q0];\n        q1_u = pu1_src_temp_u[pos_q1];\n        p0_u = pu1_src_temp_u[pos_p0];\n        p1_u = pu1_src_temp_u[pos_p1];\n\n        q0_v = pu1_src_temp_v[pos_q0];\n        q1_v = pu1_src_temp_v[pos_q1];\n        p0_v = pu1_src_temp_v[pos_p0];\n        p1_v = pu1_src_temp_v[pos_p1];\n\n        /* Filter Decision */\n        if((ABS(p0_u - q0_u) < alpha) &&\n           (ABS(q1_u - q0_u) < beta) &&\n           (ABS(p1_u - p0_u) < beta))\n        {\n            val = ((((q0_u - p0_u) << 2) + (p1_u - q1_u) + 4) >> 3);\n            delta = CLIP3(-tc, tc, val);\n            /* p0' */\n            val = p0_u + delta;\n            pu1_src_temp_u[pos_p0] = CLIP_U8(val);\n            /* q0' */\n            val = q0_u - delta;\n            pu1_src_temp_u[pos_q0] = CLIP_U8(val);\n        }\n\n        /* Filter Decision */\n        if((ABS(p0_v - q0_v) < alpha) &&\n           (ABS(q1_v - q0_v) < beta) &&\n           (ABS(p1_v - p0_v) < beta))\n        {\n            val = ((((q0_v - p0_v) << 2) + (p1_v - q1_v) + 4) >> 3);\n            delta = CLIP3(-tc, tc, val);\n            /* p0' */\n            val = p0_v + delta;\n            pu1_src_temp_v[pos_p0] = CLIP_U8(val);\n            /* q0' */\n            val = q0_v - delta;\n            pu1_src_temp_v[pos_q0] = CLIP_U8(val);\n        }\n    }\n}\n\n/*****************************************************************************/\n/* Function Definitions for chroma deblocking in high profile                */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bs4()                            */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when the boundary strength is set to 4 in  */\n/*                  high profile.                                            */\n/*                                                                           */\n/*  Inputs        : pu1_src    - pointer to the src sample q0 of U           */\n/*                  src_strd   - source stride                               */\n/*                  alpha_cb   - alpha value for the boundary in U           */\n/*                  beta_cb    - beta value for the boundary in U            */\n/*                  alpha_cr   - alpha value for the boundary in V           */\n/*                  beta_cr    - beta value for the boundary in V            */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.4 under the    */\n/*                  title \"Filtering process for edges for bS equal to 4\" in */\n/*                  ITU T Rec H.264 with alpha and beta values different in  */\n/*                  U and V.                                                 */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         29 12 2014   Kaushik         Draft                                */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_vert_bs4(UWORD8 *pu1_src,\n                                 WORD32 src_strd,\n                                 WORD32 alpha_cb,\n                                 WORD32 beta_cb,\n                                 WORD32 alpha_cr,\n                                 WORD32 beta_cr)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* Pointer to the src sample q0 of U */\n    UWORD8 *pu1_src_v = pu1_src + 1; /* Pointer to the src sample q0 of V */\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 blk_strd = src_strd << 1; /* block_increment = src_strd * 2*/\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    WORD8 i = 0, edge;\n\n    pos_q0 = 0;\n    pos_q1 = 2;\n    pos_p0 = -2;\n    pos_p1 = -4;\n\n    for(edge = 0; edge < 4;\n                    edge++, pu1_src_u += blk_strd, pu1_src_v += blk_strd)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_src_temp_v = pu1_src_v;\n        for(i = 0; i < 2; ++i, pu1_src_temp_u += src_strd, pu1_src_temp_v +=\n                        src_strd)\n        {\n            q0_u = pu1_src_temp_u[pos_q0];\n            q1_u = pu1_src_temp_u[pos_q1];\n            p0_u = pu1_src_temp_u[pos_p0];\n            p1_u = pu1_src_temp_u[pos_p1];\n            q0_v = pu1_src_temp_v[pos_q0];\n            q1_v = pu1_src_temp_v[pos_q1];\n            p0_v = pu1_src_temp_v[pos_p0];\n            p1_v = pu1_src_temp_v[pos_p1];\n\n            /* Filter Decision */\n            if((ABS(p0_u - q0_u) < alpha_cb) &&\n               (ABS(q1_u - q0_u) < beta_cb) &&\n               (ABS(p1_u - p0_u) < beta_cb))\n            {\n                /* p0' */\n                pu1_src_temp_u[pos_p0] = ((X2(p1_u) + p0_u + q1_u + 2) >> 2);\n                /* q0' */\n                pu1_src_temp_u[pos_q0] = (X2(q1_u) + q0_u + p1_u + 2) >> 2;\n            }\n\n            /* Filter Decision */\n            if((ABS(p0_v - q0_v) < alpha_cr) &&\n               (ABS(q1_v - q0_v) < beta_cr) &&\n               (ABS(p1_v - p0_v) < beta_cr))\n            {\n                /* p0' */\n                pu1_src_temp_v[pos_p0] = ((X2(p1_v) + p0_v + q1_v + 2) >> 2);\n                /* q0' */\n                pu1_src_temp_v[pos_q0] = (X2(q1_v) + q0_v + p1_v + 2) >> 2;\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_horz_bs4()                            */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  horizontal edge when the boundary strength is set to 4   */\n/*                  in high profile.                                         */\n/*                                                                           */\n/*  Inputs        : pu1_src    - pointer to the src sample q0 of U           */\n/*                  src_strd   - source stride                               */\n/*                  alpha_cb   - alpha value for the boundary in U           */\n/*                  beta_cb    - beta value for the boundary in U            */\n/*                  alpha_cr   - alpha value for the boundary in V           */\n/*                  beta_cr    - beta value for the boundary in V            */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.4 under the    */\n/*                  title \"Filtering process for edges for bS equal to 4\" in */\n/*                  ITU T Rec H.264 with alpha and beta values different in  */\n/*                  U and V.                                                 */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         29 12 2014   Kaushik         Draft                                */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_horz_bs4(UWORD8 *pu1_src,\n                                 WORD32 src_strd,\n                                 WORD32 alpha_cb,\n                                 WORD32 beta_cb,\n                                 WORD32 alpha_cr,\n                                 WORD32 beta_cr)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* Pointer to the src sample q0 of U */\n    UWORD8 *pu1_src_v = pu1_src + 1; /* Pointer to the src sample q0 of V */\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    UWORD8 *pu1_p1_u; /* Pointer to the src sample p1 of U */\n    UWORD8 *pu1_p1_v; /* Pointer to the src sample p1 of U */\n    UWORD8 *pu1_p1_temp_u, *pu1_p1_temp_v;\n    WORD8 i = 0, edge;\n\n    pu1_p1_u = pu1_src_u - (src_strd << 1);\n    pu1_p1_v = pu1_src_v - (src_strd << 1);\n    pos_q0 = 0;\n    pos_q1 = src_strd;\n    pos_p0 = src_strd;\n    pos_p1 = 0;\n\n    for(edge = 0; edge < 4; edge++, pu1_src_u += 4, pu1_p1_u += 4, pu1_src_v +=\n                    4, pu1_p1_v += 4)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_p1_temp_u = pu1_p1_u;\n        pu1_src_temp_v = pu1_src_v;\n        pu1_p1_temp_v = pu1_p1_v;\n        for(i = 0; i < 2; ++i, pu1_src_temp_u += 2, pu1_p1_temp_u += 2,\n                       pu1_src_temp_v += 2, pu1_p1_temp_v += 2)\n        {\n            q0_u = pu1_src_temp_u[pos_q0];\n            q1_u = pu1_src_temp_u[pos_q1];\n            p0_u = pu1_p1_temp_u[pos_p0];\n            p1_u = pu1_p1_temp_u[pos_p1];\n\n            q0_v = pu1_src_temp_v[pos_q0];\n            q1_v = pu1_src_temp_v[pos_q1];\n            p0_v = pu1_p1_temp_v[pos_p0];\n            p1_v = pu1_p1_temp_v[pos_p1];\n\n            /* Filter Decision */\n            if(ABS(p0_u - q0_u) < alpha_cb && ABS(q1_u - q0_u) < beta_cb\n                            && ABS(p1_u - p0_u) < beta_cb)\n            {\n                /* p0' */\n                pu1_p1_temp_u[pos_p0] = (X2(p1_u) + p0_u + q1_u + 2) >> 2;\n                /* q0' */\n                pu1_src_temp_u[pos_q0] = (X2(q1_u) + q0_u + p1_u + 2) >> 2;\n            }\n\n            /* Filter Decision */\n            if(ABS(p0_v - q0_v) < alpha_cr && ABS(q1_v - q0_v) < beta_cr\n                            && ABS(p1_v - p0_v) < beta_cr)\n            {\n                /* p0' */\n                pu1_p1_temp_v[pos_p0] = (X2(p1_v) + p0_v + q1_v + 2) >> 2;\n                /* q0' */\n                pu1_src_temp_v[pos_q0] = (X2(q1_v) + q0_v + p1_v + 2) >> 2;\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bslt4()                          */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when the boundary strength is less than 4  */\n/*                  in high profile.                                         */\n/*                                                                           */\n/*  Inputs        : pu1_src          - pointer to the src sample q0 of U     */\n/*                  src_strd         - source stride                         */\n/*                  alpha_cb         - alpha value for the boundary in U     */\n/*                  beta_cb          - beta value for the boundary in U      */\n/*                  alpha_cr         - alpha value for the boundary in V     */\n/*                  beta_cr          - beta value for the boundary in V      */\n/*                  u4_bs            - packed Boundary strength array        */\n/*                  pu1_cliptab_cb   - tc0_table for U                       */\n/*                  pu1_cliptab_cr   - tc0_table for V                       */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.3 under the    */\n/*                  title \"Filtering process for edges for bS less than 4\"   */\n/*                  in ITU T Rec H.264 with alpha and beta values different  */\n/*                  in U and V.                                              */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         29 12 2014   Kaushik         Draft                                */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_vert_bslt4(UWORD8 *pu1_src,\n                                   WORD32 src_strd,\n                                   WORD32 alpha_cb,\n                                   WORD32 beta_cb,\n                                   WORD32 alpha_cr,\n                                   WORD32 beta_cr,\n                                   UWORD32 u4_bs,\n                                   const UWORD8 *pu1_cliptab_cb,\n                                   const UWORD8 *pu1_cliptab_cr)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    UWORD8 *pu1_src_v = pu1_src + 1; /* Pointer to the src sample q0 of plane V*/\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 blk_strd = src_strd << 1; /* block_increment = src_strd * 2 */\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    WORD8 i = 0, edge;\n    WORD8 delta;\n    WORD8 tcb, tcr;\n    WORD16 val;\n    UWORD8 tcb0, tcr0, u1_bs;\n\n    pos_q0 = 0;\n    pos_q1 = 2;\n    pos_p0 = -2;\n    pos_p1 = -4;\n\n    for(edge = 0; edge < 4;\n                    edge++, pu1_src_u += blk_strd, pu1_src_v += blk_strd)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_src_temp_v = pu1_src_v;\n        /* Filter Decision */\n        u1_bs = (UWORD8)((u4_bs >> ((3 - edge) << 3)) & 0x0ff);\n        if(!u1_bs)\n            continue;\n        /* tc0 */\n        tcb0 = pu1_cliptab_cb[u1_bs];\n        tcr0 = pu1_cliptab_cr[u1_bs];\n        tcb = tcb0 + 1;\n        tcr = tcr0 + 1;\n        for(i = 0; i < 2; ++i, pu1_src_temp_u += src_strd, pu1_src_temp_v +=\n                        src_strd)\n        {\n            q0_u = pu1_src_temp_u[pos_q0];\n            q1_u = pu1_src_temp_u[pos_q1];\n            p0_u = pu1_src_temp_u[pos_p0];\n            p1_u = pu1_src_temp_u[pos_p1];\n\n            q0_v = pu1_src_temp_v[pos_q0];\n            q1_v = pu1_src_temp_v[pos_q1];\n            p0_v = pu1_src_temp_v[pos_p0];\n            p1_v = pu1_src_temp_v[pos_p1];\n\n            /* Filter Decision */\n            if(ABS(p0_u - q0_u) < alpha_cb && ABS(q1_u - q0_u) < beta_cb\n                            && ABS(p1_u - p0_u) < beta_cb)\n            {\n                val = ((((q0_u - p0_u) << 2) + (p1_u - q1_u) + 4) >> 3);\n                delta = CLIP3(-tcb, tcb, val);\n                /* p0' */\n                val = p0_u + delta;\n                pu1_src_temp_u[pos_p0] = CLIP_U8(val);\n                /* q0' */\n                val = q0_u - delta;\n                pu1_src_temp_u[pos_q0] = CLIP_U8(val);\n            }\n\n            /* Filter Decision */\n            if(ABS(p0_v - q0_v) < alpha_cr && ABS(q1_v - q0_v) < beta_cr\n                            && ABS(p1_v - p0_v) < beta_cr)\n            {\n                val = ((((q0_v - p0_v) << 2) + (p1_v - q1_v) + 4) >> 3);\n                delta = CLIP3(-tcr, tcr, val);\n                /* p0' */\n                val = p0_v + delta;\n                pu1_src_temp_v[pos_p0] = CLIP_U8(val);\n                /* q0' */\n                val = q0_v - delta;\n                pu1_src_temp_v[pos_q0] = CLIP_U8(val);\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_horz_bslt4()                          */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  horizontal edge when the boundary strength is less than  */\n/*                  4 in high profile.                                       */\n/*                                                                           */\n/*  Inputs        : pu1_src          - pointer to the src sample q0 of U     */\n/*                  src_strd         - source stride                         */\n/*                  alpha_cb         - alpha value for the boundary in U     */\n/*                  beta_cb          - beta value for the boundary in U      */\n/*                  alpha_cr         - alpha value for the boundary in V     */\n/*                  beta_cr          - beta value for the boundary in V      */\n/*                  u4_bs            - packed Boundary strength array        */\n/*                  pu1_cliptab_cb   - tc0_table for U                       */\n/*                  pu1_cliptab_cr   - tc0_table for V                       */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.3 under the    */\n/*                  title \"Filtering process for edges for bS less than 4\"   */\n/*                  in ITU T Rec H.264 with alpha and beta values different  */\n/*                  in U and V.                                              */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         29 12 2014   Kaushik         Draft                                */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_horz_bslt4(UWORD8 *pu1_src,\n                                   WORD32 src_strd,\n                                   WORD32 alpha_cb,\n                                   WORD32 beta_cb,\n                                   WORD32 alpha_cr,\n                                   WORD32 beta_cr,\n                                   UWORD32 u4_bs,\n                                   const UWORD8 *pu1_cliptab_cb,\n                                   const UWORD8 *pu1_cliptab_cr)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    UWORD8 *pu1_src_v = pu1_src + 1; /* Pointer to the src sample q0 of plane V*/\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    UWORD8 *pu1_p1_u; /* Pointer to the src sample p1 of plane U*/\n    UWORD8 *pu1_p1_v; /* Pointer to the src sample p1 of plane V*/\n    UWORD8 *pu1_p1_temp_u, *pu1_p1_temp_v;\n    WORD8 i = 0, edge;\n    WORD8 delta;\n    WORD8 tcb, tcr;\n    WORD16 val;\n    UWORD8 u1_bs;\n    UWORD8 tcb0, tcr0;\n\n    pu1_p1_u = pu1_src_u - (src_strd << 1);\n    pu1_p1_v = pu1_src_v - (src_strd << 1);\n    pos_q0 = 0;\n    pos_q1 = src_strd;\n    pos_p0 = src_strd;\n    pos_p1 = 0;\n\n    for(edge = 0; edge < 4; edge++, pu1_src_u += 4, pu1_p1_u += 4,\n                    pu1_src_v += 4, pu1_p1_v += 4)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_p1_temp_u = pu1_p1_u;\n        pu1_src_temp_v = pu1_src_v;\n        pu1_p1_temp_v = pu1_p1_v;\n\n        /* Filter Decision */\n        u1_bs = (UWORD8)((u4_bs >> ((3 - edge) << 3)) & 0x0ff);\n        if(!u1_bs)\n            continue;\n        /* tc0 */\n        tcb0 = pu1_cliptab_cb[u1_bs];\n        tcr0 = pu1_cliptab_cr[u1_bs];\n\n        for(i = 0; i < 2; ++i, pu1_src_temp_u += 2, pu1_p1_temp_u += 2,\n                       pu1_src_temp_v += 2, pu1_p1_temp_v += 2)\n        {\n            q0_u = pu1_src_temp_u[pos_q0];\n            q1_u = pu1_src_temp_u[pos_q1];\n            p0_u = pu1_p1_temp_u[pos_p0];\n            p1_u = pu1_p1_temp_u[pos_p1];\n\n            q0_v = pu1_src_temp_v[pos_q0];\n            q1_v = pu1_src_temp_v[pos_q1];\n            p0_v = pu1_p1_temp_v[pos_p0];\n            p1_v = pu1_p1_temp_v[pos_p1];\n\n            /* tc */\n            tcb = tcb0 + 1;\n            tcr = tcr0 + 1;\n            /* Filter Decision */\n            if(ABS(p0_u - q0_u) < alpha_cb && ABS(q1_u - q0_u) < beta_cb\n                            && ABS(p1_u - p0_u) < beta_cb)\n            {\n                val = ((((q0_u - p0_u) << 2) + (p1_u - q1_u) + 4) >> 3);\n                delta = CLIP3(-tcb, tcb, val);\n                /* p0' */\n                val = p0_u + delta;\n                pu1_p1_temp_u[pos_p0] = CLIP_U8(val);\n                /* q0' */\n                val = q0_u - delta;\n                pu1_src_temp_u[pos_q0] = CLIP_U8(val);\n            }\n            /* Filter Decision */\n            if(ABS(p0_v - q0_v) < alpha_cr && ABS(q1_v - q0_v) < beta_cr\n                            && ABS(p1_v - p0_v) < beta_cr)\n            {\n                val = ((((q0_v - p0_v) << 2) + (p1_v - q1_v) + 4) >> 3);\n                delta = CLIP3(-tcr, tcr, val);\n                /* p0' */\n                val = p0_v + delta;\n                pu1_p1_temp_v[pos_p0] = CLIP_U8(val);\n                /* q0' */\n                val = q0_v - delta;\n                pu1_src_temp_v[pos_q0] = CLIP_U8(val);\n            }\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bs4_mbaff()                      */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when boundary strength is set to 4 in high */\n/*                  profile.                                                 */\n/*                                                                           */\n/*  Inputs        : pu1_src          - pointer to the src sample q0 of U     */\n/*                  src_strd         - source stride                         */\n/*                  alpha_cb         - alpha value for the boundary in U     */\n/*                  beta_cb          - beta value for the boundary in U      */\n/*                  alpha_cr         - alpha value for the boundary in V     */\n/*                  beta_cr          - beta value for the boundary in V      */\n/*                  u4_bs            - packed Boundary strength array        */\n/*                  pu1_cliptab_cb   - tc0_table for U                       */\n/*                  pu1_cliptab_cr   - tc0_table for V                       */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : When the function is called twice, this operation is as  */\n/*                  described in Sec. 8.7.2.4 under the title \"Filtering     */\n/*                  process for edges for bS equal to 4\" in ITU T Rec H.264  */\n/*                  with alpha and beta values different in U and V.         */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         29 12 2014   Kaushik         Draft                                */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_vert_bs4_mbaff(UWORD8 *pu1_src,\n                                       WORD32 src_strd,\n                                       WORD32 alpha_cb,\n                                       WORD32 beta_cb,\n                                       WORD32 alpha_cr,\n                                       WORD32 beta_cr)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* Pointer to the src sample q0 of U */\n    UWORD8 *pu1_src_v = pu1_src + 1; /* Pointer to the src sample q0 of V */\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 blk_strd = src_strd;\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    WORD8 edge;\n\n    pos_q0 = 0;\n    pos_q1 = 2;\n    pos_p0 = -2;\n    pos_p1 = -4;\n\n    for(edge = 0; edge < 4;\n                    edge++, pu1_src_u += blk_strd, pu1_src_v += blk_strd)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_src_temp_v = pu1_src_v;\n        q0_u = pu1_src_temp_u[pos_q0];\n        q1_u = pu1_src_temp_u[pos_q1];\n        p0_u = pu1_src_temp_u[pos_p0];\n        p1_u = pu1_src_temp_u[pos_p1];\n        q0_v = pu1_src_temp_v[pos_q0];\n        q1_v = pu1_src_temp_v[pos_q1];\n        p0_v = pu1_src_temp_v[pos_p0];\n        p1_v = pu1_src_temp_v[pos_p1];\n\n        /* Filter Decision */\n        if((ABS(p0_u - q0_u) < alpha_cb) &&\n           (ABS(q1_u - q0_u) < beta_cb)  &&\n           (ABS(p1_u - p0_u) < beta_cb))\n        {\n            /* p0' */\n            pu1_src_temp_u[pos_p0] = ((X2(p1_u) + p0_u + q1_u + 2) >> 2);\n            /* q0' */\n            pu1_src_temp_u[pos_q0] = (X2(q1_u) + q0_u + p1_u + 2) >> 2;\n        }\n\n        /* Filter Decision */\n        if((ABS(p0_v - q0_v) < alpha_cr) &&\n           (ABS(q1_v - q0_v) < beta_cr) &&\n           (ABS(p1_v - p0_v) < beta_cr))\n        {\n            /* p0' */\n            pu1_src_temp_v[pos_p0] = ((X2(p1_v) + p0_v + q1_v + 2) >> 2);\n            /* q0' */\n            pu1_src_temp_v[pos_q0] = (X2(q1_v) + q0_v + p1_v + 2) >> 2;\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bslt4_mbaff()                    */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when boundary strength is less than 4 in   */\n/*                  high profile.                                            */\n/*                                                                           */\n/*  Inputs        : pu1_src          - pointer to the src sample q0 of U     */\n/*                  src_strd         - source stride                         */\n/*                  alpha_cb         - alpha value for the boundary in U     */\n/*                  beta_cb          - beta value for the boundary in U      */\n/*                  alpha_cr         - alpha value for the boundary in V     */\n/*                  beta_cr          - beta value for the boundary in V      */\n/*                  u4_bs            - packed Boundary strength array        */\n/*                  pu1_cliptab_cb   - tc0_table for U                       */\n/*                  pu1_cliptab_cr   - tc0_table for V                       */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : When the function is called twice, this operation is as  */\n/*                  described in Sec. 8.7.2.4 under the title \"Filtering     */\n/*                  process for edges for bS less than 4\" in ITU T Rec H.264 */\n/*                  with alpha and beta values different in U and V.         */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         29 12 2014   Kaushik         Draft                                */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_deblk_chroma_vert_bslt4_mbaff(UWORD8 *pu1_src,\n                                         WORD32 src_strd,\n                                         WORD32 alpha_cb,\n                                         WORD32 beta_cb,\n                                         WORD32 alpha_cr,\n                                         WORD32 beta_cr,\n                                         UWORD32 u4_bs,\n                                         const UWORD8 *pu1_cliptab_cb,\n                                         const UWORD8 *pu1_cliptab_cr)\n{\n    UWORD8 *pu1_src_u = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    UWORD8 *pu1_src_v = pu1_src + 1; /* Pointer to the src sample q0 of plane V*/\n    UWORD8 p1_u, p0_u, q0_u, q1_u, p1_v, p0_v, q0_v, q1_v;\n    WORD32 blk_strd = src_strd;\n    WORD32 pos_p1, pos_p0, pos_q0, pos_q1;\n    UWORD8 *pu1_src_temp_u, *pu1_src_temp_v;\n    WORD8 edge;\n    WORD8 delta;\n    WORD8 tcb, tcr;\n    WORD16 val;\n    UWORD8 tcb0, tcr0, u1_bs;\n\n    pos_q0 = 0;\n    pos_q1 = 2;\n    pos_p0 = -2;\n    pos_p1 = -4;\n\n    for(edge = 0; edge < 4;\n                    edge++, pu1_src_u += blk_strd, pu1_src_v += blk_strd)\n    {\n        pu1_src_temp_u = pu1_src_u;\n        pu1_src_temp_v = pu1_src_v;\n        /* Filter Decision */\n        u1_bs = (UWORD8)((u4_bs >> ((3 - edge) << 3)) & 0x0ff);\n        if(!u1_bs)\n            continue;\n        /* tc0 */\n        tcb0 = pu1_cliptab_cb[u1_bs];\n        tcr0 = pu1_cliptab_cr[u1_bs];\n        tcb = tcb0 + 1;\n        tcr = tcr0 + 1;\n        q0_u = pu1_src_temp_u[pos_q0];\n        q1_u = pu1_src_temp_u[pos_q1];\n        p0_u = pu1_src_temp_u[pos_p0];\n        p1_u = pu1_src_temp_u[pos_p1];\n\n        q0_v = pu1_src_temp_v[pos_q0];\n        q1_v = pu1_src_temp_v[pos_q1];\n        p0_v = pu1_src_temp_v[pos_p0];\n        p1_v = pu1_src_temp_v[pos_p1];\n\n        /* Filter Decision */\n        if((ABS(p0_u - q0_u) < alpha_cb) &&\n           (ABS(q1_u - q0_u) < beta_cb) &&\n           (ABS(p1_u - p0_u) < beta_cb))\n        {\n            val = ((((q0_u - p0_u) << 2) + (p1_u - q1_u) + 4) >> 3);\n            delta = CLIP3(-tcb, tcb, val);\n            /* p0' */\n            val = p0_u + delta;\n            pu1_src_temp_u[pos_p0] = CLIP_U8(val);\n            /* q0' */\n            val = q0_u - delta;\n            pu1_src_temp_u[pos_q0] = CLIP_U8(val);\n        }\n\n        /* Filter Decision */\n        if((ABS(p0_v - q0_v) < alpha_cr) &&\n           (ABS(q1_v - q0_v) < beta_cr) &&\n           (ABS(p1_v - p0_v) < beta_cr))\n        {\n            val = ((((q0_v - p0_v) << 2) + (p1_v - q1_v) + 4) >> 3);\n            delta = CLIP3(-tcr, tcr, val);\n            /* p0' */\n            val = p0_v + delta;\n            pu1_src_temp_v[pos_p0] = CLIP_U8(val);\n            /* q0' */\n            val = q0_v - delta;\n            pu1_src_temp_v[pos_q0] = CLIP_U8(val);\n        }\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_deblk_edge_filters.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_deblk_edge_filters.h\n *\n * @brief\n *  This file contains declarations of functions used for deblocking\n *\n * @author\n *  Ittiam\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n#ifndef IH264_DEBLK_H_\n#define IH264_DEBLK_H_\n\n/*****************************************************************************/\n/* Extern Function Declarations                                              */\n/*****************************************************************************/\n\ntypedef void ih264_deblk_edge_bslt4_ft(UWORD8 *pu1_src,\n                                       WORD32 src_strd,\n                                       WORD32 alpha,\n                                       WORD32 beta,\n                                       UWORD32 u4_bs,\n                                       const UWORD8 *pu1_cliptab );\n\ntypedef void ih264_deblk_edge_bs4_ft(UWORD8 *pu1_src,\n                                     WORD32 src_strd,\n                                     WORD32 alpha,\n                                     WORD32 beta );\n\ntypedef void ih264_deblk_chroma_edge_bslt4_ft(UWORD8 *pu1_src,\n                                              WORD32 src_strd,\n                                              WORD32 alpha_cb,\n                                              WORD32 beta_cb,\n                                              WORD32 alpha_cr,\n                                              WORD32 beta_cr,\n                                              UWORD32 u4_bs,\n                                              const UWORD8 *pu1_cliptab_cb,\n                                              const UWORD8 *pu1_cliptab_cr);\n\ntypedef void ih264_deblk_chroma_edge_bs4_ft(UWORD8 *pu1_src,\n                                            WORD32 src_strd,\n                                            WORD32 alpha_cb,\n                                            WORD32 beta_cb,\n                                            WORD32 alpha_cr,\n                                            WORD32 beta_cr);\n\n\n\nih264_deblk_edge_bs4_ft ih264_deblk_luma_horz_bs4;\nih264_deblk_edge_bs4_ft ih264_deblk_luma_vert_bs4;\nih264_deblk_edge_bs4_ft ih264_deblk_luma_vert_bs4_mbaff;\n\n\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_horz_bs4_bp;\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_vert_bs4_bp;\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_vert_bs4_mbaff_bp;\n\n\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_horz_bslt4;\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_vert_bslt4;\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_vert_bslt4_mbaff;\n\n\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_bp;\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_bp;\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_mbaff_bp;\n\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_vert_bs4;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_horz_bs4;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_vert_bs4_mbaff;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_horz_bs4_mbaff;\n\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_mbaff;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_mbaff;\n\n\n/*A9*/\nih264_deblk_edge_bs4_ft ih264_deblk_luma_horz_bs4_a9;\nih264_deblk_edge_bs4_ft ih264_deblk_luma_vert_bs4_a9;\nih264_deblk_edge_bs4_ft ih264_deblk_luma_vert_bs4_mbaff_a9;\n\n\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_horz_bs4_bp_a9;\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_vert_bs4_bp_a9;\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_vert_bs4_mbaff_bp_a9;\n\n\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_horz_bslt4_a9;\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_vert_bslt4_a9;\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_vert_bslt4_mbaff_a9;\n\n\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_bp_a9;\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_bp_a9;\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_mbaff_bp_a9;\n\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_vert_bs4_a9;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_horz_bs4_a9;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_vert_bs4_mbaff_a9;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_horz_bs4_mbaff_a9;\n\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_a9;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_a9;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_mbaff_a9;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_mbaff_a9;\n\n/*AV8*/\nih264_deblk_edge_bs4_ft ih264_deblk_luma_horz_bs4_av8;\nih264_deblk_edge_bs4_ft ih264_deblk_luma_vert_bs4_av8;\nih264_deblk_edge_bs4_ft ih264_deblk_luma_vert_bs4_mbaff_av8;\n\n\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_horz_bs4_bp_av8;\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_vert_bs4_bp_av8;\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_vert_bs4_mbaff_bp_av8;\n\n\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_horz_bslt4_av8;\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_vert_bslt4_av8;\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_vert_bslt4_mbaff_av8;\n\n\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_bp_av8;\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_bp_av8;\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_mbaff_bp_av8;\n\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_vert_bs4_av8;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_horz_bs4_av8;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_vert_bs4_mbaff_av8;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_horz_bs4_mbaff_av8;\n\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_av8;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_av8;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_mbaff_av8;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_mbaff_av8;\n\n/*SSE3*/\nih264_deblk_edge_bs4_ft ih264_deblk_luma_horz_bs4_ssse3;\nih264_deblk_edge_bs4_ft ih264_deblk_luma_vert_bs4_ssse3;\nih264_deblk_edge_bs4_ft ih264_deblk_luma_vert_bs4_mbaff_ssse3;\n\n\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_horz_bs4_bp_ssse3;\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_vert_bs4_bp_ssse3;\nih264_deblk_edge_bs4_ft ih264_deblk_chroma_vert_bs4_mbaff_bp_ssse3;\n\n\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_horz_bslt4_ssse3;\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_vert_bslt4_ssse3;\nih264_deblk_edge_bslt4_ft ih264_deblk_luma_vert_bslt4_mbaff_ssse3;\n\n\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_bp_ssse3;\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_bp_ssse3;\nih264_deblk_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_mbaff_bp_ssse3;\n\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_vert_bs4_ssse3;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_horz_bs4_ssse3;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_vert_bs4_mbaff_ssse3;\nih264_deblk_chroma_edge_bs4_ft ih264_deblk_chroma_horz_bs4_mbaff_ssse3;\n\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_ssse3;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_ssse3;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_vert_bslt4_mbaff_ssse3;\nih264_deblk_chroma_edge_bslt4_ft ih264_deblk_chroma_horz_bslt4_mbaff_ssse3;\n\n#endif /* IH264_DEBLK_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_deblk_tables.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_deblk_tables.c\n*\n* @brief\n*  Contains tables used for deblocking\n*\n* @author\n*  Ittiam\n*\n* @par List of Tables:\n*  - guc_ih264_qp_scale_cr[]\n*  - guc_ih264_alpha_table[]\n*  - guc_ih264_beta_table[]\n*  - guc_ih264_clip_table[][]\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System include files */\n#include <stdio.h>\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_deblk_tables.h\"\n\n/*****************************************************************************/\n/* Extern global definitions                                                 */\n/*****************************************************************************/\n\n/**\n ******************************************************************************\n * @brief  alpha & beta tables for deblocking\n * input   : indexA [0-51] & indexB [0-51]\n * output  : alpha & beta\n *\n * @remarks Table 8-16  in H264 Specification,\n * Derivation of offset dependent threshold variables\n *  alpha and beta from indexA and indexB\n ******************************************************************************\n */\nconst UWORD8 gu1_ih264_alpha_table[52] =\n{\n     /* indexA :: 0-51 inclusive */\n     0,     0,     0,     0,     0,     0,     0,     0,\n     0,     0,     0,     0,     0,     0,     0,     0,\n     4,     4,     5,     6,     7,     8,     9,    10,\n    12,    13,    15,    17,    20,    22,    25,    28,\n    32,    36,    40,    45,    50,    56,    63,    71,\n    80,    90,   101,   113,   127,   144,   162,   182,\n   203,   226,   255,   255,\n};\n\nconst UWORD8 gu1_ih264_beta_table[52] =\n{\n     /* indexB :: 0-51 inclusive */\n     0,     0,     0,     0,     0,     0,     0,     0,\n     0,     0,     0,     0,     0,     0,     0,     0,\n     2,     2,     2,     3,     3,     3,     3,     4,\n     4,     4,     6,     6,     7,     7,     8,     8,\n     9,     9,    10,    10,    11,    11,    12,    12,\n    13,    13,    14,    14,    15,    15,    16,    16,\n    17,    17,    18,    18,\n};\n\n/**\n ******************************************************************************\n * @brief  t'C0 table for deblocking\n * input   : indexA [0-51] and bS [1,3]\n * output  : t'C0\n *\n * @remarks Table 8-17  in H264 Specification,\n * Value of variable t'C0 as a function of indexA and bS\n ******************************************************************************\n */\nconst UWORD8 gu1_ih264_clip_table[52][4] =\n{\n    /* indexA :: 0-51 inclusive */\n    { 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0},\n    { 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0},\n    { 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0},\n    { 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0}, { 0, 0, 0, 0},\n    { 0, 0, 0, 0}, { 0, 0, 0, 1}, { 0, 0, 0, 1}, { 0, 0, 0, 1},\n    { 0, 0, 0, 1}, { 0, 0, 1, 1}, { 0, 0, 1, 1}, { 0, 1, 1, 1},\n    { 0, 1, 1, 1}, { 0, 1, 1, 1}, { 0, 1, 1, 1}, { 0, 1, 1, 2},\n    { 0, 1, 1, 2}, { 0, 1, 1, 2}, { 0, 1, 1, 2}, { 0, 1, 2, 3},\n    { 0, 1, 2, 3}, { 0, 2, 2, 3}, { 0, 2, 2, 4}, { 0, 2, 3, 4},\n    { 0, 2, 3, 4}, { 0, 3, 3, 5}, { 0, 3, 4, 6}, { 0, 3, 4, 6},\n    { 0, 4, 5, 7}, { 0, 4, 5, 8}, { 0, 4, 6, 9}, { 0, 5, 7,10},\n    { 0, 6, 8,11}, { 0, 6, 8,13}, { 0, 7,10,14}, { 0, 8,11,16},\n    { 0, 9,12,18}, { 0,10,13,20}, { 0,11,15,23}, { 0,13,17,25},\n};\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_deblk_tables.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_deblk_tables.h\n *\n * @brief\n *  This file contains declarations of tables used for deblocking\n *\n * @author\n *  Ittiam\n *\n * @par List of Functions:\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n#ifndef IH264_DEBLK_TABLES_H_\n#define IH264_DEBLK_TABLES_H_\n\n/*****************************************************************************/\n/* Extern global declarations                                                */\n/*****************************************************************************/\n\n/**\n ******************************************************************************\n * @brief  alpha & beta tables for deblocking\n * input   : indexA [0-51] & indexB [0-51]\n * output  : alpha & beta\n *\n * @remarks Table 8-16  in H264 Specification,\n * Derivation of offset dependent threshold variables\n *  alpha and beta from indexA and indexB\n ******************************************************************************\n */\nextern const UWORD8 gu1_ih264_alpha_table[52];\n\nextern const UWORD8 gu1_ih264_beta_table[52];\n\n/**\n ******************************************************************************\n * @brief  t'C0 table for deblocking\n * input   : indexA [0-51] and bS [1,3]\n * output  : t'C0\n *\n * @remarks Table 8-17  in H264 Specification,\n * Value of variable t'C0 as a function of indexA and bS\n ******************************************************************************\n */\nextern const UWORD8 gu1_ih264_clip_table[52][4];\n\n#endif /* IH264_DEBLK_TABLES_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_debug.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_debug.h\n*\n* @brief\n*  Definitions for codec debugging\n*\n* @author\n*  Ittiam\n*\n* @par List of Functions:\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n#ifndef _IH264_DEBUG_H_\n#define _IH264_DEBUG_H_\n\n\n#if DEBUG_PRINT\n\n#define DEBUG(...)                                                          \\\n{                                                                           \\\n    printf(\"\\n[H264 DBG] %s/%d:: \", __FUNCTION__, __LINE__);                \\\n    printf(__VA_ARGS__);                                                    \\\n}\n\n#else\n\n#define DEBUG(...) {}\n\n#endif\n\n\n#define ASSERT(x) assert((x))\n\n\n#endif /* _IH264_DEBUG_H_ */\n\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_defs.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_defs.h\n*\n* @brief\n*  Definitions used in the codec\n*\n* @author\n*  Ittiam\n*\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n#ifndef IH264_DEFS_H_\n#define IH264_DEFS_H_\n\n/*****************************************************************************/\n/* Enums                                                                     */\n/*****************************************************************************/\n\n\n/*****************************************************************************/\n/* Profile and Levels                                                        */\n/*****************************************************************************/\n\n/**\n******************************************************************************\n *  @enum  PROFILE_IDC\n *  @brief Defines the set of possible profiles\n******************************************************************************\n*/\nenum\n{\n    IH264_PROFILE_BASELINE = 66,\n    IH264_PROFILE_MAIN = 77,\n    IH264_PROFILE_EXTENDED = 88,\n    IH264_PROFILE_HIGH = 100,\n    IH264_PROFILE_HIGH10 = 110,\n    IH264_PROFILE_HIGH422 = 122,\n    IH264_PROFILE_HIGH444 = 144,\n};\n\n/**\n******************************************************************************\n *  @enum  LEVEL_IDC\n *  @brief Defines the set of possible levels\n******************************************************************************\n*/\ntypedef enum\n{\n    IH264_LEVEL_10         = 10,\n    IH264_LEVEL_1B         = 9,\n    IH264_LEVEL_11         = 11,\n    IH264_LEVEL_12         = 12,\n    IH264_LEVEL_13         = 13,\n    IH264_LEVEL_20         = 20,\n    IH264_LEVEL_21         = 21,\n    IH264_LEVEL_22         = 22,\n    IH264_LEVEL_30         = 30,\n    IH264_LEVEL_31         = 31,\n    IH264_LEVEL_32         = 32,\n    IH264_LEVEL_40         = 40,\n    IH264_LEVEL_41         = 41,\n    IH264_LEVEL_42         = 42,\n    IH264_LEVEL_50         = 50,\n    IH264_LEVEL_51         = 51,\n}IH264_LEVEL_T;\n\n\n/**\n******************************************************************************\n *  @enum  PIC TYPES\n *  @brief Defines the set of possible picture type - not signaled in bitstream\n******************************************************************************\n*/\ntypedef enum\n{\n    PIC_NA = 0x7FFFFFFF,\n    PIC_IDR = 0,\n    PIC_I = 1,\n    PIC_P = 2,\n    PIC_B = 3,\n    PIC_P_NONREF = 4,\n    PIC_B_NONREF = 5,\n    PIC_MAX,\n}PIC_TYPE_T;\n\n/**\n******************************************************************************\n *  @enum  FRAME-FIELD types\n *  @brief Defines the set of possible field types.\n******************************************************************************\n*/\nenum\n{\n    TOP_FIELD,\n    BOTTOM_FIELD,\n    FRAME,\n};\n\n/**\n******************************************************************************\n *  @enum  SLICE TYPES\n *  @brief Defines the set of possible SLICE TYPES\n******************************************************************************\n*/\nenum\n{\n    PSLICE = 0,\n    BSLICE = 1,\n    ISLICE = 2,\n    SPSLICE = 3,\n    SISLICE = 4,\n    MAXSLICE_TYPE,\n};\n\n/**\n******************************************************************************\n *  @enum  NAL_UNIT_TYPE\n *  @brief Defines the set of possible nal unit types\n******************************************************************************\n*/\nenum\n{\n    NAL_UNSPEC_0        = 0,\n    NAL_SLICE_NON_IDR   = 1,\n    NAL_SLICE_DPA       = 2,\n    NAL_SLICE_DPB       = 3,\n    NAL_SLICE_DPC       = 4,\n    NAL_SLICE_IDR       = 5,\n    NAL_SEI             = 6,\n    NAL_SPS             = 7,\n    NAL_PPS             = 8,\n    NAL_AUD             = 9,\n    NAL_EOSEQ           = 10,\n    NAL_EOSTR           = 11,\n    NAL_FILLER          = 12,\n    NAL_SPSE            = 13,\n    NAL_RES_18          = 14,\n    NAL_AUX_PIC         = 19,\n    NAL_RES_23          = 20,\n    NAL_UNSPEC_31       = 24,\n};\n\n/**\n******************************************************************************\n *  @enum  CHROMA_FORMAT_IDC\n *  @brief Defines the set of possible chroma formats\n *  Note Chorma format Do not change enum values\n******************************************************************************\n*/\nenum\n{\n    CHROMA_FMT_IDC_MONOCHROME   = 0,\n    CHROMA_FMT_IDC_YUV420       = 1,\n    CHROMA_FMT_IDC_YUV422       = 2,\n    CHROMA_FMT_IDC_YUV444       = 3,\n    CHROMA_FMT_IDC_YUV444_PLANES = 4,\n};\n\n\n/**\n******************************************************************************\n *  @enum  MBMODES_I16x16\n *  @brief Defines the set of possible intra 16x16 mb modes\n******************************************************************************\n*/\ntypedef enum\n{\n    VERT_I16x16     = 0,\n    HORZ_I16x16     = 1,\n    DC_I16x16       = 2,\n    PLANE_I16x16    = 3,\n    MAX_I16x16      = 4,\n}MBMODES_I16x16;\n\n/**\n******************************************************************************\n *  @enum  MBMODES_I4x4\n *  @brief Defines the set of possible intra 4x4 mb modes\n******************************************************************************\n*/\ntypedef enum\n{\n    VERT_I4x4     = 0,\n    HORZ_I4x4     = 1,\n    DC_I4x4       = 2,\n    DIAG_DL_I4x4  = 3,\n    DIAG_DR_I4x4  = 4,\n    VERT_R_I4x4   = 5,\n    HORZ_D_I4x4   = 6,\n    VERT_L_I4x4   = 7,\n    HORZ_U_I4x4   = 8,\n    MAX_I4x4      = 9,\n}MBMODES_I4x4;\n\n/**\n******************************************************************************\n *  @enum  MBMODES_I8x8\n *  @brief Defines the set of possible intra 8x8 mb modes\n******************************************************************************\n*/\ntypedef enum\n{\n    VERT_I8x8     = 0,\n    HORZ_I8x8     = 1,\n    DC_I8x8       = 2,\n    DIAG_DL_I8x8  = 3,\n    DIAG_DR_I8x8  = 4,\n    VERT_R_I8x8   = 5,\n    HORZ_D_I8x8   = 6,\n    VERT_L_I8x8   = 7,\n    HORZ_U_I8x8   = 8,\n    MAX_I8x8      = 9,\n}MBMODES_I8x8;\n\n/**\n******************************************************************************\n *  @enum  MBMODES_CHROMA_I8x8 (Chroma)\n *  @brief Defines the set of possible intra 8x8 mb modes for chroma\n******************************************************************************\n*/\ntypedef enum\n{\n    DC_CH_I8x8     = 0,\n    HORZ_CH_I8x8   = 1,\n    VERT_CH_I8x8   = 2,\n    PLANE_CH_I8x8  = 3,\n    MAX_CH_I8x8    = 4,\n}MBMODES_CHROMA_I8x8;\n\n/**\n******************************************************************************\n *  @enum  MBTYPES\n *  @brief Defines the set of possible macro block types\n******************************************************************************\n*/\ntypedef enum\n{\n    I16x16      = 0,\n    I4x4        = 1,\n    I8x8        = 2,\n    P16x16      = 3,\n    P16x8       = 4,\n    P8x16       = 5,\n    P8x8        = 6,\n    PSKIP       = 7,\n    IPCM        = 8,\n    B16x16      = 9,\n    BSKIP       = 10,\n    BDIRECT     = 11,\n    MAX_MBTYPES,\n}MBTYPES_T;\n\n/* Prediction list */\n/* Do not change enum values */\nenum\n{\n    PRED_L0 = 0,\n    PRED_L1 = 1,\n    PRED_BI = 2\n};\n\n\n/**\n******************************************************************************\n *  @enum  ENTROPY_BLK_TYPE\n *  @brief Defines the nature of blocks employed in entropy coding\n******************************************************************************\n*/\ntypedef enum\n{\n    ENTROPY_BLK_INVALID = -1,\n    CAVLC_LUMA_4x4_DC = 0,\n    CAVLC_LUMA_4x4_AC = 1,\n    CAVLC_LUMA_4x4 = 2,\n    CAVLC_CHROMA_4x4_DC = 3,\n    CAVLC_CHROMA_4x4_AC = 4,\n} ENTROPY_BLK_TYPE;\n\n/**\n******************************************************************************\n *  @enum  ENTROPY_MODE\n *  @brief Entropy coding modes\n******************************************************************************\n*/\ntypedef enum\n{\n    CAVLC = 0,\n    CABAC = 1,\n} ENTROPY_MODE;\n\n/**\n******************************************************************************\n *  @enum  COMPONENT_TYPE\n *  @brief components Y, U & V\n******************************************************************************\n*/\ntypedef enum\n{\n    Y,\n    U,\n    V,\n} COMPONENT_TYPE;\n\n\n/**\n******************************************************************************\n *  @enum  MBPART_PREDMODE_T\n *  @brief MbPartps_pred_mode_ctxt Table 7-11 to 7-14\n******************************************************************************\n*/\ntypedef enum\n{\n    MBPART_NA,\n    MBPART_I4x4,\n    MBPART_I8x8,\n    MBPART_I16x16,\n    MBPART_L0,\n    MBPART_L1,\n    MBPART_BI,\n    MBPART_DIRECT,\n    MBPART_IPCM,\n}MBPART_PREDMODE_T;\n\n\ntypedef enum\n{\n    I_NxN,\n    I_16x16_0_0_0,\n    I_16x16_1_0_0,\n    I_16x16_2_0_0,\n    I_16x16_3_0_0,\n    I_16x16_0_1_0,\n    I_16x16_1_1_0,\n    I_16x16_2_1_0,\n    I_16x16_3_1_0,\n    I_16x16_0_2_0,\n    I_16x16_1_2_0,\n    I_16x16_2_2_0,\n    I_16x16_3_2_0,\n    I_16x16_0_0_1,\n    I_16x16_1_0_1,\n    I_16x16_2_0_1,\n    I_16x16_3_0_1,\n    I_16x16_0_1_1,\n    I_16x16_1_1_1,\n    I_16x16_2_1_1,\n    I_16x16_3_1_1,\n    I_16x16_0_2_1,\n    I_16x16_1_2_1,\n    I_16x16_2_2_1,\n    I_16x16_3_2_1,\n    I_PCM,\n}MBTYPE_ISLICE_T;\n\ntypedef enum\n{\n    P_L0_16x16,\n    P_L0_L0_16x8,\n    P_L0_L0_8x16,\n    P_8x8,\n    P_8x8REF0,\n    P_SKIP\n}MBTYPE_PSLICE_T;\n\ntypedef enum\n{\n    B_DIRECT_16x16,\n    B_L0_16x16,\n    B_L1_16x16,\n    B_BI_16x16,\n    B_L0_L0_16x8,\n    B_L0_L0_8x16,\n    B_L1_L1_16x8,\n    B_L1_L1_8x16,\n    B_L0_L1_16x8,\n    B_L0_L1_8x16,\n    B_L1_L0_16x8,\n    B_L1_L0_8x16,\n    B_L0_BI_16x8,\n    B_L0_BI_8x16,\n    B_L1_BI_16x8,\n    B_L1_BI_8x16,\n    B_BI_L0_16x8,\n    B_BI_L0_8x16,\n    B_BI_L1_16x8,\n    B_BI_L1_8x16,\n    B_BI_BI_16x8,\n    B_BI_BI_8x16,\n    B_8x8,\n    B_SKIP,\n}MBTYPE_BSLICE_T;\n\n\ntypedef enum\n{\n    P_L0_8x8,\n    P_L0_8x4,\n    P_L0_4x8,\n    P_L0_4x4,\n}SUBMBTYPE_PSLICE_T;\n\ntypedef enum\n{\n    B_DIRECT_8x8,\n    B_L0_8x8,\n    B_L1_8x8,\n    B_BI_8x8,\n    B_L0_8x4,\n    B_L0_4x8,\n    B_L1_8x4,\n    B_L1_4x8,\n    B_BI_8x4,\n    B_BI_4x8,\n    B_L0_4x4,\n    B_L1_4x4,\n    B_BI_4x4,\n}SUBMBTYPE_BSLICE_T;\n\n/**\n * DC Mode pattern for 4 4x4 sub blocks in an MB row\n */\n#define DC_I16X16_MB_ROW (DC_I16x16 << 24) | (DC_I16x16 << 16) | \\\n                         (DC_I16x16 << 8)  | DC_I16x16\n\n\n\n/*****************************************************************************/\n/* Constant Macros                                                           */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/* Reference frame defs                                                      */\n/*****************************************************************************/\n/* Maximum DPB size */\n#define MAX_DPB_SIZE 16\n\n/* Maximum mmco commands in slice header */\n#define MAX_MMCO_COMMANDS 32\n\n/* Maximum reference reorder idc */\n#define MAX_MODICATION_IDC 32\n\n/*****************************************************************************/\n/* SPS restrictions                                                          */\n/*****************************************************************************/\n\n/* Number of SPS allowed */\n/* An extra buffer is allocated to write the parsed data\n * It is copied to the appropriate location later */\n#define MAX_SPS_CNT         (32 + 1)\n\n/* Maximum long term reference pics */\n#define MAX_LTREF_PICS_SPS 16\n\n/* Maximum short term reference pics */\n#define MAX_STREF_PICS_SPS 64\n\n\n/*****************************************************************************/\n/* PPS restrictions                                                          */\n/*****************************************************************************/\n\n/* Number of PPS allowed  */\n/* An extra buffer is allocated to write the parsed data\n * It is copied to the appropriate location later */\n#define MAX_PPS_CNT         (256 + 1)\n\n/*****************************************************************************/\n/* Macro definitions for sizes of MB, PU, TU, CU                            */\n/*****************************************************************************/\n#define MB_SIZE             16\n#define BLK8x8SIZE          8\n#define BLK_SIZE            4\n\n\n/* TU Size Range */\n#define MAX_TU_SIZE         8\n#define MIN_TU_SIZE         4\n\n/* Max Transform Size */\n#define MAX_TRANS_SIZE      (MAX_TU_SIZE*MAX_TU_SIZE)\n\n/* PU Size Range */\n#define MAX_PU_SIZE         16\n#define MIN_PU_SIZE         4\n\n/* Number of max TU in a MB row */\n#define MAX_TU_IN_MB_ROW   ((MB_SIZE / MIN_TU_SIZE))\n\n/* Number of max PU in a CTb row */\n#define MAX_PU_IN_MB_ROW   ((MB_SIZE / MIN_PU_SIZE))\n\n\n/* Number of max PU in a MB */\n/*****************************************************************************/\n/* Note though for 64 x 64 MB, Max PU in MB is 128, in order to store      */\n/*  intra pred info, 256 entries are needed                                  */\n/*****************************************************************************/\n#define MAX_PU_IN_MB       ((MB_SIZE / MIN_PU_SIZE) * \\\n                             (MB_SIZE / MIN_PU_SIZE))\n\n/* Number of max TU in a MB */\n#define MAX_TU_IN_MB       ((MB_SIZE / MIN_TU_SIZE) * \\\n                             (MB_SIZE / MIN_TU_SIZE))\n\n\n\n/**\n * Maximum transform depths\n */\n#define MAX_TRAFO_DEPTH 5\n\n#define MAX_DC_4x4_SUBBLK_LUMA 1\n#define MAX_AC_4x4_SUBBLK_LUMA 16\n#define MAX_DC_4x4_SUBBLK_CHROMA 2\n#define MAX_AC_4x4_SUBBLK_CHROMA 8\n\n#define MAX_4x4_SUBBLKS (MAX_DC_4x4_SUBBLK_LUMA + MAX_DC_4x4_SUBBLK_CHROMA +\\\n                         MAX_AC_4x4_SUBBLK_LUMA + MAX_AC_4x4_SUBBLK_CHROMA)\n\n/* Max number of deblocking edges */\n#define MAX_VERT_DEBLK_EDGES ((MB_SIZE/8) * (MB_SIZE/4))\n#define MAX_HORZ_DEBLK_EDGES ((MB_SIZE/4) * (MB_SIZE/8))\n\n/* Qp can not change below 8x8 level */\n#define MAX_DEBLK_QP_CNT     ((MB_SIZE/8) * (MB_SIZE/8))\n\n/*****************************************************************************/\n/* Parsing related macros                                                    */\n/*****************************************************************************/\n#define SUBBLK_COEFF_CNT    16\n\n/* Quant and Trans defs */\n\n/*****************************************************************************/\n/* Sizes for Transform functions                                             */\n/*****************************************************************************/\n#define TRANS_SIZE_4   4\n#define TRANS_SIZE_8   8\n#define TRANS_SIZE_16 16\n#define TRANS_SIZE_32 32\n\n\n#define IT_SHIFT_STAGE_1 7\n#define IT_SHIFT_STAGE_2 12\n\n/**\n * @breif  Maximum transform dynamic range (excluding sign bit)\n */\n#define MAX_TR_DYNAMIC_RANGE  15\n\n/**\n * @brief  Q(QP%6) * IQ(QP%6) = 2^20\n */\n#define QUANT_IQUANT_SHIFT    20\n\n/**\n * @breif Q factor for Qp%6 multiplication\n */\n#define QUANT_SHIFT           14\n\n/**\n * @breif Q shift factor for flat rescale matrix weights\n */\n#define FLAT_RESCALE_MAT_Q_SHIFT    11\n\n/**\n * @breif  Scaling matrix is represented in Q15 format\n */\n#define SCALING_Q_SHIFT       15\n\n/**\n * @brief  rounding factor for quantization represented in Q9 format\n */\n#define QUANT_ROUND_FACTOR_Q   9\n\n/**\n * @brief  Minimum qp supported in H264 spec\n */\n#define MIN_H264_QP 0\n\n/**\n * @brief  Maximum qp supported in H264 spec\n */\n#define MAX_H264_QP 51\n\n/**\n * @brief  Minimum delta scale supported in H264 spec\n */\n#define MIN_H264_DELTA_SCALE (-128)\n\n/**\n * @brief  Maximum delta scale supported in H264 spec\n */\n#define MAX_H264_DELTA_SCALE 127\n\n/**\n * @breif  Total number of transform sizes\n * used for sizeID while getting scale matrix\n */\n#define NUM_UNIQUE_TRANS_SIZE 4\n\n/**\n * @breif  Maximum number of bits in frameNumber signaling\n */\n#define MAX_BITS_IN_FRAME_NUM     16\n\n/**\n * @breif  Maximum number of bits in POC LSB signaling\n */\n#define MAX_BITS_IN_POC_LSB     16\n\n\n/**\n * @breif  Maximum PIC Order Count type\n */\n#define MAX_PIC_ORDER_COUNT_TYPE    2\n\n\n/**\n * @breif  Maximum Weighted bipred idc\n */\n#define MAX_WEIGHT_BIPRED_IDC 2\n\n/*****************************************************************************/\n/* Number of scaling matrices for each transform size                        */\n/*****************************************************************************/\n#define SCALE_MAT_CNT_TRANS_SIZE_4    6\n#define SCALE_MAT_CNT_TRANS_SIZE_8    6\n#define SCALE_MAT_CNT_TRANS_SIZE_16   6\n#define SCALE_MAT_CNT_TRANS_SIZE_32   2\n\n/* Maximum number of scale matrices for a given transform size */\n#define SCALE_MAT_CNT_MAX_PER_TRANS_SIZE 6\n\n/* Total number of scale matrices */\n#define TOTAL_SCALE_MAT_COUNT   (SCALE_MAT_CNT_TRANS_SIZE_4     + \\\n                                 SCALE_MAT_CNT_TRANS_SIZE_8     + \\\n                                 SCALE_MAT_CNT_TRANS_SIZE_16    + \\\n                                 SCALE_MAT_CNT_TRANS_SIZE_32)\n\n\n/*****************************************************************************/\n/* Intra pred Macros                                                         */\n/*****************************************************************************/\n/** Planar Intra prediction mode */\n#define INTRA_PLANAR             0\n\n/** DC Intra prediction mode */\n#define INTRA_DC                 1\n\n/** Gives angular mode for intra prediction */\n#define INTRA_ANGULAR(x) (x)\n\n/** Following is used to signal no intra prediction in case of pcm blocks\n */\n#define INTRA_PRED_NONE  63\n\n\n/** Following is used to signal no intra prediction is needed for first three\n * 4x4 luma blocks in case of 4x4 TU sizes\n * Also used in pcm cases\n */\n#define INTRA_PRED_CHROMA_IDX_NONE  7\n\n\n/**\n******************************************************************************\n *  @brief  neighbor availability masks\n******************************************************************************\n */\n#define LEFT_MB_AVAILABLE_MASK      0x01\n#define TOP_LEFT_MB_AVAILABLE_MASK  0x02\n#define TOP_MB_AVAILABLE_MASK       0x04\n#define TOP_RIGHT_MB_AVAILABLE_MASK 0x08\n\n/**\n******************************************************************************\n *  @brief  SEI macros\n******************************************************************************\n */\n/*\n * @brief  specifies the number of colour primary components of the mastering display\n */\n#define NUM_SEI_MDCV_PRIMARIES      3\n\n/*\n * @brief  specifies the number of colour primary components of the nominal content colour volume\n */\n#define NUM_SEI_CCV_PRIMARIES       3\n\n#define DISPLAY_PRIMARIES_X_UPPER_LIMIT                37000\n#define DISPLAY_PRIMARIES_X_LOWER_LIMIT                5\n#define DISPLAY_PRIMARIES_X_DIVISION_FACTOR            5\n\n#define DISPLAY_PRIMARIES_Y_UPPER_LIMIT                42000\n#define DISPLAY_PRIMARIES_Y_LOWER_LIMIT                5\n#define DISPLAY_PRIMARIES_Y_DIVISION_FACTOR            5\n\n#define WHITE_POINT_X_UPPER_LIMIT                      37000\n#define WHITE_POINT_X_LOWER_LIMIT                      5\n#define WHITE_POINT_X_DIVISION_FACTOR                  5\n\n#define WHITE_POINT_Y_UPPER_LIMIT                      42000\n#define WHITE_POINT_Y_LOWER_LIMIT                      5\n#define WHITE_POINT_Y_DIVISION_FACTOR                  5\n\n#define MAX_DISPLAY_MASTERING_LUMINANCE_UPPER_LIMIT        100000000\n#define MAX_DISPLAY_MASTERING_LUMINANCE_LOWER_LIMIT        50000\n#define MAX_DISPLAY_MASTERING_LUMINANCE_DIVISION_FACTOR    10000\n\n#define MIN_DISPLAY_MASTERING_LUMINANCE_UPPER_LIMIT        50000\n#define MIN_DISPLAY_MASTERING_LUMINANCE_LOWER_LIMIT        1\n\n#define AMBIENT_LIGHT_X_UPPER_LIMIT        50000\n#define AMBIENT_LIGHT_Y_UPPER_LIMIT        50000\n\n#define CCV_PRIMARIES_X_UPPER_LIMIT        5000000\n#define CCV_PRIMARIES_X_LOWER_LIMIT        -5000000\n#define CCV_PRIMARIES_Y_UPPER_LIMIT        5000000\n#define CCV_PRIMARIES_Y_LOWER_LIMIT        -5000000\n\n#endif /* IH264_DEFS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_disp_mgr.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_disp_mgr.c\n*\n* @brief\n*  Contains function definitions for display management\n*\n* @author\n*  Srinivas T\n*\n* @par List of Functions:\n*   - ih264_disp_mgr_init()\n*   - ih264_disp_mgr_add()\n*   - ih264_disp_mgr_get()\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n#include <stdlib.h>\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_disp_mgr.h\"\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*    Initialization function for display buffer manager\n*\n* @par Description:\n*    Initializes the display buffer management structure\n*\n* @param[in] ps_disp_mgr\n*  Pointer to the display buffer management structure\n*\n* @returns none\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nvoid ih264_disp_mgr_init(disp_mgr_t *ps_disp_mgr)\n{\n    WORD32 id;\n\n    ps_disp_mgr->u4_last_abs_poc = DEFAULT_POC;\n\n    for(id = 0; id < DISP_MGR_MAX_CNT; id++)\n    {\n        ps_disp_mgr->ai4_abs_poc[id] = DEFAULT_POC;\n        ps_disp_mgr->apv_ptr[id] = NULL;\n    }\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*     Adds a buffer to the display manager\n*\n* @par Description:\n*      Adds a buffer to the display buffer manager\n*\n* @param[in] ps_disp_mgr\n*  Pointer to the display buffer management structure\n*\n* @param[in] buf_id\n*  ID of the display buffer\n*\n* @param[in] abs_poc\n*  Absolute POC of the display buffer\n*\n* @param[in] pv_ptr\n*  Pointer to the display buffer\n*\n* @returns  0 if success, -1 otherwise\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nWORD32 ih264_disp_mgr_add(disp_mgr_t *ps_disp_mgr,\n                          WORD32 buf_id,\n                          WORD32 abs_poc,\n                          void *pv_ptr)\n{\n    if(buf_id >= DISP_MGR_MAX_CNT)\n    {\n        return (-1);\n    }\n\n    if(ps_disp_mgr->apv_ptr[buf_id] != NULL)\n    {\n        return (-1);\n    }\n\n    ps_disp_mgr->apv_ptr[buf_id] = pv_ptr;\n    ps_disp_mgr->ai4_abs_poc[buf_id] = abs_poc;\n    return 0;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*  Gets the next buffer\n*\n* @par Description:\n*  Gets the next display buffer\n*\n* @param[in] ps_disp_mgr\n*  Pointer to the display buffer structure\n*\n* @param[out]  pi4_buf_id\n*  Pointer to hold buffer id of the display buffer being returned\n*\n* @returns  Pointer to the next display buffer\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\nvoid* ih264_disp_mgr_get(disp_mgr_t *ps_disp_mgr, WORD32 *pi4_buf_id)\n{\n    WORD32 id;\n    void *pv_ret_ptr;\n    WORD32 i4_min_poc;\n    WORD32 min_poc_id;\n\n\n    pv_ret_ptr = NULL;\n    i4_min_poc = 0x7FFFFFFF;\n    min_poc_id = -1;\n\n    /* Find minimum POC */\n    for(id = 0; id < DISP_MGR_MAX_CNT; id++)\n    {\n        if((DEFAULT_POC != ps_disp_mgr->ai4_abs_poc[id]) &&\n           (ps_disp_mgr->ai4_abs_poc[id] <= i4_min_poc))\n        {\n            i4_min_poc = ps_disp_mgr->ai4_abs_poc[id];\n            min_poc_id = id;\n        }\n    }\n    *pi4_buf_id = min_poc_id;\n    /* If all pocs are still default_poc then return NULL */\n    if(-1 == min_poc_id)\n    {\n        return NULL;\n    }\n\n    pv_ret_ptr = ps_disp_mgr->apv_ptr[min_poc_id];\n\n    /* Set abs poc to default and apv_ptr to null so that the buffer is not returned again */\n    ps_disp_mgr->apv_ptr[min_poc_id] = NULL;\n    ps_disp_mgr->ai4_abs_poc[min_poc_id] = DEFAULT_POC;\n    return pv_ret_ptr;\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_disp_mgr.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_disp_mgr.h\n*\n* @brief\n*  Function declarations used for display management\n*\n* @author\n*  Srinivas T\n*\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n#ifndef _DISP_MGR_H_\n#define _DISP_MGR_H_\n\n#define DISP_MGR_MAX_CNT 64\n#define DEFAULT_POC 0x7FFFFFFF\n\ntypedef struct\n{\n    /**\n     * last_abs_poc\n     */\n    UWORD32 u4_last_abs_poc;\n\n    /**\n     * au4_abs_poc[DISP_MGR_MAX_CNT]\n     */\n    WORD32 ai4_abs_poc[DISP_MGR_MAX_CNT];\n\n    /**\n     * apv_ptr[DISP_MGR_MAX_CNT]\n     */\n    void    *apv_ptr[DISP_MGR_MAX_CNT];\n}disp_mgr_t;\n\nvoid ih264_disp_mgr_init(disp_mgr_t *ps_disp_mgr);\n\nWORD32 ih264_disp_mgr_add(disp_mgr_t *ps_disp_mgr,\n                          WORD32 id,\n                          WORD32 abs_poc,\n                          void *pv_ptr);\n\nvoid* ih264_disp_mgr_get(disp_mgr_t *ps_disp_mgr, WORD32 *pi4_buf_id);\n\n#endif  //_DISP_MGR_H_\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_dpb_mgr.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_dpb_mgr.c\n *\n * @brief\n *  Function definitions used for decoded picture buffer management\n *\n * @author\n *  Srinivas T\n *\n * @par List of Functions:\n *   - ih264_dpb_mgr_init()\n *   - ih264_dpb_mgr_sort_short_term_fields_by_frame_num()\n *   - ih264_dpb_mgr_sort_short_term_fields_by_poc_l0()\n *   - ih264_dpb_mgr_sort_short_term_fields_by_poc_l1()\n *   - ih264_dpb_mgr_sort_long_term_fields_by_frame_idx()\n *   - ih264_dpb_mgr_alternate_ref_fields()\n *   - ih264_dpb_mgr_insert_ref_field()\n *   - ih264_dpb_mgr_insert_ref_frame()\n *   - ih264_dpb_mgr_count_ref_frames()\n *   - ih264_dpb_mgr_delete_ref_frame()\n *   - ih264_dpb_mgr_delete_long_ref_fields_max_frame_idx()\n *   - ih264_dpb_mgr_delete_short_ref_frame()\n *   - ih264_dpb_mgr_delete_all_ref_frames()\n *   - ih264_dpb_mgr_reset()\n *   - ih264_dpb_mgr_release_pics()\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <assert.h>\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_error.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_buf_mgr.h\"\n#include \"ih264_dpb_mgr.h\"\n#include \"ih264_debug.h\"\n\n/**\n *******************************************************************************\n *\n * @brief\n *  DPB manager initializer\n *\n * @par Description:\n *  Initialises the DPB manager structure\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\n\nvoid ih264_dpb_mgr_init(dpb_mgr_t *ps_dpb_mgr)\n{\n    UWORD32 i;\n    dpb_info_t *ps_dpb_info = ps_dpb_mgr->as_dpb_info;\n    for(i = 0; i < MAX_DPB_BUFS; i++)\n    {\n        ps_dpb_info[i].ps_prev_dpb = NULL;\n        ps_dpb_info[i].ps_pic_buf = NULL;\n        ps_dpb_mgr->as_top_field_pics[i].i4_used_as_ref    = INVALID;\n        ps_dpb_mgr->as_bottom_field_pics[i].i4_used_as_ref = INVALID;\n        ps_dpb_mgr->as_top_field_pics[i].i1_field_type     = INVALID;\n        ps_dpb_mgr->as_bottom_field_pics[i].i1_field_type  = INVALID;\n        ps_dpb_mgr->as_top_field_pics[i].i4_long_term_frame_idx    = -1;\n        ps_dpb_mgr->as_bottom_field_pics[i].i4_long_term_frame_idx = -1;\n    }\n\n    ps_dpb_mgr->u1_num_short_term_ref_bufs = 0;\n    ps_dpb_mgr->u1_num_long_term_ref_bufs = 0;\n    ps_dpb_mgr->ps_dpb_short_term_head = NULL;\n    ps_dpb_mgr->ps_dpb_long_term_head = NULL;\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Function to sort sort term pics by frame_num.\n *\n * @par Description:\n *  Sorts short term fields by frame_num. For 2 fields having same frame_num,\n *  orders them based on requested first field type.\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] curr_frame_num\n *  frame_num of the current pic\n *\n * @param[in] first_field_type\n *  For complementary fields, required first field\n *\n * @param[in] max_frame_num\n *  Maximum frame_num allowed\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_sort_short_term_fields_by_frame_num(dpb_mgr_t *ps_dpb_mgr,\n                                                         WORD32 curr_frame_num,\n                                                         WORD32 first_field_type,\n                                                         WORD32 max_frame_num)\n{\n    dpb_info_t *ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;\n    dpb_info_t *ps_dpb_node2;\n    WORD32 frame_num_node1;\n    WORD32 frame_num_node2;\n    pic_buf_t *ps_pic_buf;\n\n    if(ps_dpb_node1 == NULL)\n        return -1;\n\n    for (; ps_dpb_node1 != NULL; ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb)\n    {\n        for (ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb; ps_dpb_node2 != NULL; ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb)\n        {\n            frame_num_node1 = ps_dpb_node1->ps_pic_buf->i4_frame_num;\n            frame_num_node2 = ps_dpb_node2->ps_pic_buf->i4_frame_num;\n\n            if(frame_num_node1 > curr_frame_num)\n                frame_num_node1 = frame_num_node1 - max_frame_num;\n            if(frame_num_node2 > curr_frame_num)\n                frame_num_node2 = frame_num_node2 - max_frame_num;\n\n            if(frame_num_node1 < frame_num_node2)\n            {\n                ps_pic_buf = ps_dpb_node1->ps_pic_buf;\n                ps_dpb_node1->ps_pic_buf = ps_dpb_node2->ps_pic_buf;\n                ps_dpb_node2->ps_pic_buf = ps_pic_buf;\n            }\n        }\n    }\n\n    /**\n     * For frames and complementary field pairs,\n     * ensure first_field_type appears first in the list\n     */\n    ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;\n    ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;\n    while(ps_dpb_node2 != NULL)\n    {\n        pic_buf_t *ps_pic_node1 = ps_dpb_node1->ps_pic_buf;\n        pic_buf_t *ps_pic_node2 = ps_dpb_node2->ps_pic_buf;\n        frame_num_node1 = ps_pic_node1->i4_frame_num;\n        frame_num_node2 = ps_pic_node2->i4_frame_num;\n        if(frame_num_node1 == frame_num_node2)\n        {\n            ASSERT(ps_pic_node1->i1_field_type != ps_pic_node2->i1_field_type);\n            if(ps_pic_node1->i1_field_type != first_field_type)\n            {\n                ps_dpb_node1->ps_pic_buf = ps_pic_node2;\n                ps_dpb_node2->ps_pic_buf = ps_pic_node1;\n            }\n        }\n        ps_dpb_node1 = ps_dpb_node2;\n        ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb;\n    }\n    return 0;\n\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Function to sort sort term pics by poc for list 0.\n *\n * @par Description:\n *  Orders all the pocs less than current poc in the descending order.\n *  Then orders all the pocs greater than current poc in the ascending order.\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] curr_poc\n *  Poc of the current pic\n *\n * @param[in] first_field_type\n *  For complementary fields, required first field\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_sort_short_term_fields_by_poc_l0(dpb_mgr_t *ps_dpb_mgr,\n                                                      WORD32 curr_poc,\n                                                      WORD32 first_field_type)\n{\n    dpb_info_t *ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;\n    dpb_info_t *ps_dpb_node2;\n    WORD32 poc_node1;\n    WORD32 poc_node2;\n    WORD32 frame_num_node1;\n    WORD32 frame_num_node2;\n    pic_buf_t *ps_pic_buf;\n\n    if(ps_dpb_node1 == NULL)\n        return -1;\n\n    /**\n     * Sort the fields by poc.\n     * All POCs less than current poc are first placed in the descending order.\n     * Then all POCs greater than current poc are placed in the ascending order.\n     */\n    for (; ps_dpb_node1 != NULL; ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb)\n    {\n        for (ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb; ps_dpb_node2 != NULL; ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb)\n        {\n            poc_node1 = ps_dpb_node1->ps_pic_buf->i4_abs_poc;\n            poc_node2 = ps_dpb_node2->ps_pic_buf->i4_abs_poc;\n            ASSERT(poc_node1 != curr_poc);\n            ASSERT(poc_node2 != curr_poc);\n            if(((poc_node1 < curr_poc) && (poc_node2 > curr_poc)) ||\n                    ((poc_node1 < curr_poc) && (poc_node2 < curr_poc) && (poc_node1 > poc_node2)) ||\n                    ((poc_node1 > curr_poc) && (poc_node2 > curr_poc) && (poc_node1 < poc_node2)))\n                    continue;\n\n            ps_pic_buf = ps_dpb_node1->ps_pic_buf;\n            ps_dpb_node1->ps_pic_buf = ps_dpb_node2->ps_pic_buf;\n            ps_dpb_node2->ps_pic_buf = ps_pic_buf;\n        }\n    }\n\n    ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;\n    ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;\n    while(ps_dpb_node2 != NULL)\n    {\n        pic_buf_t *ps_pic_node1 = ps_dpb_node1->ps_pic_buf;\n        pic_buf_t *ps_pic_node2 = ps_dpb_node2->ps_pic_buf;\n        frame_num_node1 = ps_pic_node1->i4_frame_num;\n        frame_num_node2 = ps_pic_node2->i4_frame_num;\n        if(frame_num_node1 == frame_num_node2)\n        {\n            ASSERT(ps_pic_node1->i1_field_type != ps_pic_node2->i1_field_type);\n            if(ps_pic_node1->i1_field_type != first_field_type)\n            {\n                ps_dpb_node1->ps_pic_buf = ps_pic_node2;\n                ps_dpb_node2->ps_pic_buf = ps_pic_node1;\n            }\n        }\n        ps_dpb_node1 = ps_dpb_node2;\n        ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb;\n    }\n    return 0;\n\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Function to sort sort term pics by poc for list 1.\n *\n * @par Description:\n *  Orders all the pocs greater than current poc in the ascending order.\n *  Then rrders all the pocs less than current poc in the descending order.\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] curr_poc\n *  Poc of the current pic\n *\n * @param[in] first_field_type\n *  For complementary fields, required first field\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_sort_short_term_fields_by_poc_l1(dpb_mgr_t *ps_dpb_mgr,\n                                                      WORD32 curr_poc,\n                                                      WORD32 first_field_type)\n{\n    dpb_info_t *ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;\n    dpb_info_t *ps_dpb_node2;\n    WORD32 poc_node1;\n    WORD32 poc_node2;\n    WORD32 frame_num_node1;\n    WORD32 frame_num_node2;\n    pic_buf_t *ps_pic_buf;\n\n    if(ps_dpb_node1 == NULL)\n        return -1;\n\n    /**\n     * Sort the fields by poc.\n     * All POCs greater than current poc are first placed in the ascending order.\n     * Then all POCs less than current poc are placed in the decending order.\n     */\n    for (; ps_dpb_node1 != NULL; ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb)\n    {\n        for (ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb; ps_dpb_node2 != NULL; ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb)\n        {\n            poc_node1 = ps_dpb_node1->ps_pic_buf->i4_abs_poc;\n            poc_node2 = ps_dpb_node2->ps_pic_buf->i4_abs_poc;\n            ASSERT(poc_node1 != curr_poc);\n            ASSERT(poc_node2 != curr_poc);\n            if(((poc_node1 > curr_poc) && (poc_node2 < curr_poc)) ||\n                    ((poc_node1 < curr_poc) && (poc_node2 < curr_poc) && (poc_node1 > poc_node2)) ||\n                    ((poc_node1 > curr_poc) && (poc_node2 > curr_poc) && (poc_node1 < poc_node2)))\n                    continue;\n\n            ps_pic_buf = ps_dpb_node1->ps_pic_buf;\n            ps_dpb_node1->ps_pic_buf = ps_dpb_node2->ps_pic_buf;\n            ps_dpb_node2->ps_pic_buf = ps_pic_buf;\n        }\n    }\n\n    ps_dpb_node1 = ps_dpb_mgr->ps_dpb_short_term_head;\n    ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;\n    while(ps_dpb_node2 != NULL)\n    {\n        pic_buf_t *ps_pic_node1 = ps_dpb_node1->ps_pic_buf;\n        pic_buf_t *ps_pic_node2 = ps_dpb_node2->ps_pic_buf;\n        frame_num_node1 = ps_pic_node1->i4_frame_num;\n        frame_num_node2 = ps_pic_node2->i4_frame_num;\n        if(frame_num_node1 == frame_num_node2)\n        {\n            ASSERT(ps_pic_node1->i1_field_type != ps_pic_node2->i1_field_type);\n            if(ps_pic_node1->i1_field_type != first_field_type)\n            {\n                ps_dpb_node1->ps_pic_buf = ps_pic_node2;\n                ps_dpb_node2->ps_pic_buf = ps_pic_node1;\n            }\n        }\n        ps_dpb_node1 = ps_dpb_node2;\n        ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb;\n    }\n    return 0;\n}\n/**\n *******************************************************************************\n *\n * @brief\n *  Function to sort long term pics by long term frame idx.\n *\n * @par Description:\n *  Sorts long term fields by long term frame idx. For 2 fields\n *  having same frame_num, orders them based on requested first field type.\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] first_field_type\n *  For complementary fields, required first field\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_sort_long_term_fields_by_frame_idx(dpb_mgr_t *ps_dpb_mgr,\n                                                        WORD32 first_field_type)\n{\n    dpb_info_t *ps_dpb_node1 = ps_dpb_mgr->ps_dpb_long_term_head;\n    dpb_info_t *ps_dpb_node2;\n    WORD32 frame_idx_node1;\n    WORD32 frame_idx_node2;\n    pic_buf_t *ps_pic_buf;\n\n    if(ps_dpb_node1 == NULL)\n        return -1;\n\n    /* Sort the fields by frame idx */\n    for (; ps_dpb_node1 != NULL; ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb)\n    {\n        for (ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb; ps_dpb_node2 != NULL; ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb)\n        {\n            frame_idx_node1 = ps_dpb_node1->ps_pic_buf->i4_long_term_frame_idx;\n            frame_idx_node2 = ps_dpb_node2->ps_pic_buf->i4_long_term_frame_idx;\n\n            if(frame_idx_node1 > frame_idx_node2)\n            {\n                ps_pic_buf = ps_dpb_node1->ps_pic_buf;\n                ps_dpb_node1->ps_pic_buf = ps_dpb_node2->ps_pic_buf;\n                ps_dpb_node2->ps_pic_buf = ps_pic_buf;\n            }\n        }\n    }\n\n    /**\n     * For frames and complementary field pairs,\n     * ensure first_field_type appears first in the list\n     */\n    ps_dpb_node1 = ps_dpb_mgr->ps_dpb_long_term_head;\n    ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;\n    while(ps_dpb_node2 != NULL)\n    {\n        pic_buf_t *ps_pic_node1 = ps_dpb_node1->ps_pic_buf;\n        pic_buf_t *ps_pic_node2 = ps_dpb_node2->ps_pic_buf;\n        frame_idx_node1 = ps_pic_node1->i4_long_term_frame_idx;\n        frame_idx_node2 = ps_pic_node2->i4_long_term_frame_idx;\n        if(frame_idx_node1 == frame_idx_node2)\n        {\n            ASSERT(ps_pic_node1->i1_field_type != ps_pic_node2->i1_field_type);\n            if(ps_pic_node1->i1_field_type != first_field_type)\n            {\n                ps_dpb_node1->ps_pic_buf = ps_pic_node2;\n                ps_dpb_node2->ps_pic_buf = ps_pic_node1;\n            }\n        }\n        ps_dpb_node1 = ps_dpb_node2;\n        ps_dpb_node2 = ps_dpb_node2->ps_prev_dpb;\n    }\n    return 0;\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Function to alternate fields.\n *\n * @par Description:\n *  In the ordered list of fields, alternate fields starting with\n *  first_field_type\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] reference_type\n *  This is used to select between short-term and long-term linked list.\n *\n * @param[in] first_field_type\n *  For complementary fields, required first field\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_alternate_ref_fields(dpb_mgr_t *ps_dpb_mgr,\n                                          WORD32 reference_type,\n                                          WORD32 first_field_type)\n{\n    dpb_info_t s_dpb_head;\n    dpb_info_t *ps_dpb_head;\n    dpb_info_t *ps_dpb_node1;\n    dpb_info_t *ps_dpb_node2;\n    dpb_info_t *ps_dpb_node3;\n    dpb_info_t *ps_dpb_node4;\n    WORD32 expected_field;\n\n    expected_field = first_field_type;\n\n    ps_dpb_head = &s_dpb_head;\n\n    ps_dpb_head->ps_prev_dpb = (reference_type == SHORT_TERM_REF) ?\n            ps_dpb_mgr->ps_dpb_short_term_head:\n            ps_dpb_mgr->ps_dpb_long_term_head;\n\n    ps_dpb_node1 = ps_dpb_head;\n    ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;\n    while(ps_dpb_node2 != NULL)\n    {\n        pic_buf_t *ps_pic_node2 = ps_dpb_node2->ps_pic_buf;\n        if(ps_pic_node2->i1_field_type != expected_field)\n        {\n            /*\n             * If it is not expected field, loop over the node till\n             * the expected field.\n             */\n            ps_dpb_node3 = ps_dpb_node2;\n            ps_dpb_node4 = ps_dpb_node2->ps_prev_dpb;\n            while((ps_dpb_node4 != NULL) &&\n                    (ps_dpb_node4->ps_pic_buf->i1_field_type != expected_field))\n            {\n                ps_dpb_node3 = ps_dpb_node4;\n                ps_dpb_node4 = ps_dpb_node4->ps_prev_dpb;\n            }\n            if(ps_dpb_node4 != NULL)\n            {\n                ps_dpb_node1->ps_prev_dpb = ps_dpb_node4;\n                ps_dpb_node3->ps_prev_dpb = ps_dpb_node4->ps_prev_dpb;\n                ps_dpb_node4->ps_prev_dpb = ps_dpb_node2;\n            }\n            else\n            {\n                /* node4 null means we have reached the end */\n                break;\n            }\n        }\n        ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb;\n        ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;\n        expected_field = (ps_dpb_node1->ps_pic_buf->i1_field_type == TOP_FIELD)?\n                            BOTTOM_FIELD:TOP_FIELD;\n    }\n\n    if(reference_type == SHORT_TERM_REF)\n    {\n        ps_dpb_mgr->ps_dpb_short_term_head = ps_dpb_head->ps_prev_dpb;\n    }\n    else\n    {\n        ps_dpb_mgr->ps_dpb_long_term_head = ps_dpb_head->ps_prev_dpb;\n    }\n\n    return 0;\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Add a ref field to short-term or long-term linked list.\n *\n * @par Description:\n *  This function adds a ref field to either short-term or long-term linked\n *  list. It picks up memory for the link from the array of dpb_info in\n *  dpb_mgr. The field is added to the beginning of the linked list and the\n *  head is set the the field.\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] ps_pic_buf\n *  Pic buf structure for the field being added.\n *\n * @param[in] reference_type\n *  This is used to select between short-term and long-term linked list.\n *\n * @param[in] frame_num\n *  frame_num for the field.\n *\n * @param[in] long_term_frame_idx\n *  If the ref being added is long-term, long_term_frame_idx of the field.\n *  Otherwise invalid.\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_insert_ref_field(dpb_mgr_t *ps_dpb_mgr,\n                                    pic_buf_t *ps_pic_buf,\n                                    WORD32 reference_type,\n                                    UWORD32 frame_num,\n                                    WORD32 long_term_frame_idx)\n{\n    WORD32 i;\n    dpb_info_t *ps_dpb_info;\n    dpb_info_t *ps_dpb_head;\n\n    ps_dpb_info = ps_dpb_mgr->as_dpb_info;\n\n    /* Return error if buffer is already present in the DPB */\n    for(i = 0; i < MAX_DPB_BUFS; i++)\n    {\n        if( (ps_dpb_info[i].ps_pic_buf == ps_pic_buf)\n                        && (ps_dpb_info[i].ps_pic_buf->i4_used_as_ref == reference_type) )\n        {\n            return (-1);\n        }\n    }\n\n    /* Find an unused DPB location */\n    for(i = 0; i < MAX_DPB_BUFS; i++)\n    {\n        if(NULL == ps_dpb_info[i].ps_pic_buf)\n        {\n            break;\n        }\n    }\n    if(i == MAX_DPB_BUFS)\n    {\n        return (-1);\n    }\n\n    ps_dpb_head = (reference_type == SHORT_TERM_REF)\n                    ?ps_dpb_mgr->ps_dpb_short_term_head\n                    :ps_dpb_mgr->ps_dpb_long_term_head;\n\n    if(reference_type == SHORT_TERM_REF)\n        long_term_frame_idx = -1;\n\n    /* Create DPB info */\n    ps_dpb_info[i].ps_pic_buf = ps_pic_buf;\n    ps_dpb_info[i].ps_prev_dpb = ps_dpb_head;\n    ps_dpb_info[i].ps_pic_buf->i4_used_as_ref = reference_type;\n    ps_dpb_info[i].ps_pic_buf->i4_frame_num = frame_num;\n    ps_dpb_info[i].ps_pic_buf->i4_long_term_frame_idx = long_term_frame_idx;\n\n    /* update the head node of linked list to point to the current picture */\n    if(reference_type == SHORT_TERM_REF)\n    {\n        ps_dpb_mgr->ps_dpb_short_term_head = ps_dpb_info + i;\n\n        /* Increment Short term buffer count */\n        ps_dpb_mgr->u1_num_short_term_ref_bufs++;\n\n    }\n    else\n    {\n        ps_dpb_mgr->ps_dpb_long_term_head = ps_dpb_info + i;\n\n        /* Increment Long term buffer count */\n        ps_dpb_mgr->u1_num_long_term_ref_bufs++;\n    }\n\n    return 0;\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Add a ref frame to short-term or long-term linked list.\n *\n * @par Description:\n *  This function adds a ref frame to either short-term or long-term linked\n *  list. Internally it calls add ref field twice to add top and bottom field.\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] ps_pic_buf\n *  Pic buf structure for the field being added.\n *\n * @param[in] reference_type\n *  This is used to select between short-term and long-term linked list.\n *\n * @param[in] frame_num\n *  frame_num for the field.\n *\n * @param[in] long_term_frame_idx\n *  If the ref being added is long-term, long_term_frame_idx of the field.\n *  Otherwise invalid.\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_insert_ref_frame(dpb_mgr_t *ps_dpb_mgr,\n                                      pic_buf_t *ps_pic_buf,\n                                      WORD32 reference_type,\n                                      UWORD32 frame_num,\n                                      WORD32 long_term_frame_idx)\n{\n    WORD32 buf_id;\n    pic_buf_t *ps_pic_top;\n    pic_buf_t *ps_pic_bottom;\n    WORD32 ret;\n\n    /*\n     * For a frame, since the ps_pic_buf passed to this function is that of top field\n     * obtain bottom field using buf_id.\n     */\n    ps_pic_top = ps_pic_buf;\n    buf_id = ps_pic_top->i4_buf_id;\n    ps_pic_bottom = &ps_dpb_mgr->as_bottom_field_pics[buf_id];\n\n    /* Insert top field */\n    ret = ih264_dpb_mgr_insert_ref_field(ps_dpb_mgr,\n                                       ps_pic_top,\n                                       reference_type,\n                                       frame_num,\n                                       long_term_frame_idx);\n\n    if(ret != 0)\n        return ret;\n\n    /* Insert bottom field */\n    ret = ih264_dpb_mgr_insert_ref_field(ps_dpb_mgr,\n                                       ps_pic_bottom,\n                                       reference_type,\n                                       frame_num,\n                                       long_term_frame_idx);\n\n    if(ret != 0)\n        return ret;\n\n    return ret;\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Returns the number of ref frames in both the linked list.\n *\n * @par Description:\n *  Returns the count of number of frames, number of complementary field pairs\n *  and number of unpaired fields.\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] curr_frame_num\n *  frame_num for the field.\n *\n * @param[in] max_frame_num\n *  Maximum frame_num allowed\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_count_ref_frames(dpb_mgr_t *ps_dpb_mgr,\n                                      WORD32 curr_frame_num,\n                                      WORD32 max_frame_num)\n{\n    WORD32 numShortTerm = 0;\n    WORD32 numLongTerm = 0;\n    dpb_info_t *ps_dpb_node;\n    WORD32 frame_num;\n    WORD32 prev_frame_num;\n\n    /*\n     * Compute the number of short-term frames/complementary field pairs/\n     * unpaired fields\n     */\n    if(ps_dpb_mgr->ps_dpb_short_term_head != NULL)\n    {\n        /* Sort the short-term list by frame_num */\n        ih264_dpb_mgr_sort_short_term_fields_by_frame_num(ps_dpb_mgr,\n                                                        curr_frame_num,\n                                                        TOP_FIELD,\n                                                        max_frame_num);\n\n        ps_dpb_node = ps_dpb_mgr->ps_dpb_short_term_head;\n        if(ps_dpb_node != NULL)\n        {\n            numShortTerm++;\n            prev_frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;\n            ps_dpb_node = ps_dpb_node->ps_prev_dpb;\n        }\n\n        while(ps_dpb_node != NULL)\n        {\n            frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;\n            if(frame_num != prev_frame_num)\n                numShortTerm++;\n            prev_frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;\n            ps_dpb_node = ps_dpb_node->ps_prev_dpb;\n        }\n    }\n\n    /*\n     * Compute the number of long-term frames/complementary field pairs/\n     * unpaired fields\n     */\n    if(ps_dpb_mgr->ps_dpb_long_term_head != NULL)\n    {\n        ih264_dpb_mgr_sort_long_term_fields_by_frame_idx(ps_dpb_mgr,\n                                                        TOP_FIELD);\n\n        ps_dpb_node = ps_dpb_mgr->ps_dpb_long_term_head;\n        if(ps_dpb_node != NULL)\n        {\n            numLongTerm++;\n            prev_frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;\n            ps_dpb_node = ps_dpb_node->ps_prev_dpb;\n        }\n\n        while(ps_dpb_node != NULL)\n        {\n            frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;\n            if(frame_num != prev_frame_num)\n                numLongTerm++;\n            prev_frame_num = ps_dpb_node->ps_pic_buf->i4_frame_num;\n            ps_dpb_node = ps_dpb_node->ps_prev_dpb;\n        }\n    }\n    return (numShortTerm + numLongTerm);\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Deletes the ref frame at the end of the linked list.\n *\n * @par Description:\n *  Deletes the ref frame at the end of the linked list. For unpaired fields,\n *  it deletes just the last node. For frame or complementary field pair, it\n *  deletes the last two nodes.\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] reference_type\n *  This is used to select between short-term and long-term linked list.\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_delete_ref_frame(dpb_mgr_t *ps_dpb_mgr,\n                                      WORD32 reference_type)\n{\n    dpb_info_t *ps_dpb_node1;\n    dpb_info_t *ps_dpb_node2;\n    dpb_info_t *ps_dpb_node3;\n\n    /*\n     * Assumption: The nodes sorted for frame num.\n     */\n\n\n    /* Select bw short-term and long-term list. */\n    ps_dpb_node1 = (reference_type == SHORT_TERM_REF)\n                    ?ps_dpb_mgr->ps_dpb_short_term_head\n                    :ps_dpb_mgr->ps_dpb_long_term_head;\n    /* If null, no entries in the list. Hence return. */\n    if(ps_dpb_node1 == NULL)\n        return 0;\n\n    /* If only one node in the list, set as unsed for refer and return. */\n    if(ps_dpb_node1->ps_prev_dpb == NULL)\n    {\n        /* Set the picture as unused for reference */\n        ps_dpb_node1->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;\n        ps_dpb_node1->ps_pic_buf = NULL;\n\n        if(reference_type == SHORT_TERM_REF)\n        {\n            ps_dpb_mgr->ps_dpb_short_term_head = NULL;\n\n            /* Increment Short term buffer count */\n            ps_dpb_mgr->u1_num_short_term_ref_bufs = 0;\n\n        }\n        else\n        {\n            ps_dpb_mgr->ps_dpb_long_term_head = NULL;\n\n            /* Increment Long term buffer count */\n            ps_dpb_mgr->u1_num_long_term_ref_bufs = 0;\n\n        }\n        return 0;\n    }\n\n    /**\n     * If there are only 2 nodes in the list, set second node as unused for reference.\n     * If the frame_num of second node and first node is same, set first node also as\n     * unused for reference and set the corresponding head to NULL.\n     */\n    ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;\n    if(ps_dpb_node2->ps_prev_dpb == NULL)\n    {\n        /* Set the picture as unused for reference */\n        if(ps_dpb_node2->ps_pic_buf->i4_frame_num == ps_dpb_node1->ps_pic_buf->i4_frame_num)\n        {\n            /* Set the picture as unused for reference */\n            ps_dpb_node1->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;\n            ps_dpb_node1->ps_pic_buf = NULL;\n            if(reference_type == SHORT_TERM_REF)\n            {\n                ps_dpb_mgr->ps_dpb_short_term_head = NULL;\n\n                /* Increment Short term buffer count */\n                ps_dpb_mgr->u1_num_short_term_ref_bufs = 0;\n\n            }\n            else\n            {\n                ps_dpb_mgr->ps_dpb_long_term_head = NULL;\n\n                /* Increment Long term buffer count */\n                ps_dpb_mgr->u1_num_long_term_ref_bufs = 0;\n\n            }\n\n        }\n        ps_dpb_node2->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;\n        ps_dpb_node2->ps_pic_buf = NULL;\n        ps_dpb_node1->ps_prev_dpb = NULL;\n        return 0;\n    }\n    /*\n     * If there are more than 2 nodes, run a loop to get the last 3 nodes.\n     */\n    ps_dpb_node3 = ps_dpb_node2->ps_prev_dpb;\n    while(ps_dpb_node3->ps_prev_dpb != NULL)\n    {\n        ps_dpb_node1 = ps_dpb_node2;\n        ps_dpb_node2 = ps_dpb_node3;\n        ps_dpb_node3 = ps_dpb_node3->ps_prev_dpb;\n    }\n    /*\n     * If node 2 and node 3 frame_nums are same, set node 2 also as unsed for\n     * reference and del reference from node1.\n     */\n    if(ps_dpb_node2->ps_pic_buf->i4_frame_num == ps_dpb_node3->ps_pic_buf->i4_frame_num)\n    {\n        ps_dpb_node2->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;\n        ps_dpb_node2->ps_pic_buf = NULL;\n        ps_dpb_node1->ps_prev_dpb = NULL;\n\n    }\n    /* Set the third node as unused for reference */\n    ps_dpb_node3->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;\n    ps_dpb_node3->ps_pic_buf = NULL;\n    ps_dpb_node2->ps_prev_dpb = NULL;\n\n    return 0;\n}\n/**\n *******************************************************************************\n *\n * @brief\n *  Delete long-term ref fields above max frame idx.\n *\n * @par Description:\n *  Deletes all the long-term ref fields having idx greater than max_frame_idx\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] max_frame_idx\n *  Max long-term frame idx allowed.\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_delete_long_ref_fields_max_frame_idx(dpb_mgr_t *ps_dpb_mgr,\n                                                          WORD32 max_frame_idx)\n{\n    dpb_info_t *ps_dpb_node1;\n    dpb_info_t *ps_dpb_node2;\n    /*\n     * Loop until there is node which isn't to be deleted is encountered.\n     */\n    while(ps_dpb_mgr->ps_dpb_long_term_head != NULL)\n    {\n        if(ps_dpb_mgr->ps_dpb_long_term_head->ps_pic_buf->i4_long_term_frame_idx\n                        <= max_frame_idx)\n        {\n            break;\n        }\n        ps_dpb_mgr->ps_dpb_long_term_head->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;\n        ps_dpb_mgr->ps_dpb_long_term_head->ps_pic_buf = NULL;\n        ps_dpb_mgr->ps_dpb_long_term_head = ps_dpb_mgr->ps_dpb_long_term_head->ps_prev_dpb;\n    }\n\n    ps_dpb_node1 = ps_dpb_mgr->ps_dpb_long_term_head;\n    if(ps_dpb_node1 == NULL)\n        return 0;\n    /*\n     * With the node that isn't to be deleted as head, loop until the end.\n     */\n    ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;\n    while(ps_dpb_node2 != NULL)\n    {\n        if(ps_dpb_node2->ps_pic_buf->i4_long_term_frame_idx > max_frame_idx)\n        {\n            ps_dpb_node2->ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;\n            ps_dpb_node2->ps_pic_buf = NULL;\n            ps_dpb_node1->ps_prev_dpb = ps_dpb_node2->ps_prev_dpb;\n        }\n        ps_dpb_node1 = ps_dpb_node1->ps_prev_dpb;\n        if(ps_dpb_node1 == NULL)\n            break;\n        ps_dpb_node2 = ps_dpb_node1->ps_prev_dpb;\n    }\n    return 0;\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Deletes the short-term with least frame_num\n *\n * @par Description:\n *  Deletes the short-term with least frame_num. It sorts the function the\n *  short-term linked list by frame-num and the function that deletes the last\n *  frame in the linked list.\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @param[in] curr_frame_num\n *  frame_num of the current pic\n *\n * @param[in] max_frame_num\n *  Maximum frame_num allowed\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_delete_short_ref_frame(dpb_mgr_t *ps_dpb_mgr,\n                                            WORD32 curr_frame_num,\n                                            WORD32 max_frame_num)\n{\n    WORD32 ret;\n    /* Sort the short-term list by frame_num */\n    ret = ih264_dpb_mgr_sort_short_term_fields_by_frame_num(ps_dpb_mgr,\n                                                          curr_frame_num,\n                                                          TOP_FIELD,\n                                                          max_frame_num);\n\n    /* Delete the last reference frame or field */\n    ret = ih264_dpb_mgr_delete_ref_frame(ps_dpb_mgr,SHORT_TERM_REF);\n\n    if(ret != 0)\n    {\n        ASSERT(0);\n    }\n\n    return ret;\n}\n/**\n *******************************************************************************\n *\n * @brief\n *  Deletes all the ref frames.\n *\n * @par Description:\n *  Deletes all of the ref frames/fields in the short-term and long-term linked\n *  list.\n *\n * @param[in] ps_dpb_mgr\n *  Pointer to the DPB manager structure\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\nWORD32 ih264_dpb_mgr_delete_all_ref_frames(dpb_mgr_t *ps_dpb_mgr)\n{\n    /* Loop over short-term linked list. */\n    while(ps_dpb_mgr->ps_dpb_short_term_head != NULL)\n    {\n        ih264_dpb_mgr_delete_ref_frame(ps_dpb_mgr,SHORT_TERM_REF);\n    }\n\n    /* Loop over long-term linked list. */\n    while(ps_dpb_mgr->ps_dpb_long_term_head != NULL)\n    {\n        ih264_dpb_mgr_delete_ref_frame(ps_dpb_mgr,LONG_TERM_REF);\n    }\n    return 0;\n}\n\n\nvoid ih264_dpb_mgr_reset(dpb_mgr_t *ps_dpb_mgr, buf_mgr_t *ps_buf_mgr)\n{\n    WORD32 i;\n    dpb_info_t *ps_dpb_info;\n    ASSERT(0);\n\n\n    ps_dpb_info = ps_dpb_mgr->as_dpb_info;\n\n    for(i = 0; i < MAX_DPB_BUFS; i++)\n    {\n        if(ps_dpb_info[i].ps_pic_buf->i4_used_as_ref)\n        {\n            ps_dpb_info[i].ps_pic_buf->i4_used_as_ref = UNUSED_FOR_REF;\n            ps_dpb_info[i].ps_prev_dpb = NULL;\n            //Release physical buffer\n            ih264_buf_mgr_release(ps_buf_mgr, ps_dpb_info[i].ps_pic_buf->i4_buf_id,\n                                  BUF_MGR_REF);\n\n            ps_dpb_info[i].ps_pic_buf = NULL;\n        }\n    }\n    ps_dpb_mgr->u1_num_short_term_ref_bufs = 0;\n    ps_dpb_mgr->u1_num_long_term_ref_bufs  = 0;\n    ps_dpb_mgr->ps_dpb_short_term_head = NULL;\n    ps_dpb_mgr->ps_dpb_long_term_head  = NULL;\n\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  deletes all pictures from DPB\n *\n * @par Description:\n *  Deletes all pictures present in the DPB manager\n *\n * @param[in] ps_buf_mgr\n *  Pointer to buffer manager structure\n *\n * @param[in] u1_disp_bufs\n *  Number of buffers to be deleted\n *\n * @returns\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\n\nvoid ih264_dpb_mgr_release_pics(buf_mgr_t *ps_buf_mgr, UWORD8 u1_disp_bufs)\n{\n    WORD8 i;\n    UWORD32 buf_status;\n    ASSERT(0);\n\n    for(i = 0; i < u1_disp_bufs; i++)\n    {\n        buf_status = ih264_buf_mgr_get_status(ps_buf_mgr, i);\n        if(0 != buf_status)\n        {\n            ih264_buf_mgr_release((buf_mgr_t *)ps_buf_mgr, i, BUF_MGR_REF);\n        }\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_dpb_mgr.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/**\n *******************************************************************************\n * @file\n *  ih264_dpb_mgr.h\n *\n * @brief\n *  Function declarations used for decoded picture buffer management\n *\n * @author\n *  Srinivas T\n *\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n#ifndef _IH264_DPB_MGR_H_\n#define _IH264_DPB_MGR_H_\n\n/* Temporary definitions. Have to be defined later */\n\n#define MAX_DPB_BUFS                (MAX_DPB_SIZE * 4)\n\n#define MARK_ST_PICNUM_AS_NONREF    1\n#define MARK_LT_INDEX_AS_NONREF     2\n#define MARK_ST_PICNUM_AS_LT_INDEX  3\n#define RESET_REF_PICTURES          5\n\ntypedef struct dpb_info_t dpb_info_t;\n\nenum\n{\n    INVALID = -1,\n    UNUSED_FOR_REF = 0  ,\n    LONG_TERM_REF       ,\n    SHORT_TERM_REF      ,\n};\nstruct dpb_info_t\n{\n    /**\n     * Pointer to picture buffer structure\n     */\n    pic_buf_t *ps_pic_buf;\n\n    /**\n     * Link to the DPB buffer with previous link\n     */\n    dpb_info_t *ps_prev_dpb;\n\n};\n\ntypedef struct\n{\n    /**\n     * Pointer to the most recent pic Num\n     */\n    dpb_info_t *ps_dpb_short_term_head;\n\n    /**\n     * Pointer to the most recent pic Num\n     */\n    dpb_info_t *ps_dpb_long_term_head;\n\n    /**\n     * Physical storage for dpbInfo for ref bufs\n     */\n    dpb_info_t as_dpb_info[MAX_DPB_BUFS];\n\n    /**\n     * Array of structures for bottom field.\n     */\n    pic_buf_t as_top_field_pics[MAX_DPB_BUFS];\n\n    /**\n     * Array of structures for bottom field.\n     */\n    pic_buf_t as_bottom_field_pics[MAX_DPB_BUFS];\n\n    /**\n     * Number of short-term reference buffers\n     */\n    UWORD8 u1_num_short_term_ref_bufs;\n\n    /**\n     * Number of long-term reference buffers\n     */\n    UWORD8 u1_num_long_term_ref_bufs;\n\n    /**\n     * buffer ID current frame\n     */\n    WORD32 i4_cur_frame_buf_id;\n\n} dpb_mgr_t;\n\nvoid ih264_dpb_mgr_init(dpb_mgr_t *ps_dpb_mgr);\n\nWORD32 ih264_dpb_mgr_insert_ref_frame(dpb_mgr_t *ps_dpb_mgr,\n                                      pic_buf_t *ps_pic_buf,\n                                      WORD32 reference_type,\n                                      UWORD32 frame_num,\n                                      WORD32 long_term_frame_idx);\n\nWORD32 ih264_dpb_mgr_delete_ref_frame(dpb_mgr_t *ps_dpb_mgr,\n                                      WORD32 reference_type);\n\nWORD32 ih264_dpb_mgr_delete_all_ref_frames(dpb_mgr_t *ps_dpb_mgr);\n\nWORD32 ih264_dpb_mgr_count_ref_frames(dpb_mgr_t *ps_dpb_mgr,\n                                      WORD32 curr_frame_num,\n                                      WORD32 max_frame_num);\n\nWORD32 ih264_dpb_mgr_delete_short_ref_frame(dpb_mgr_t *ps_dpb_mgr,\n                                            WORD32 curr_frame_num,\n                                            WORD32 max_frame_num);\n\nWORD32 ih264_dpb_mgr_insert_ref_field(dpb_mgr_t *ps_dpb_mgr,\n                                      pic_buf_t *ps_pic_buf,\n                                      WORD32 reference_type,\n                                      UWORD32 frame_num,\n                                      WORD32 long_term_frame_idx);\n\nWORD32 ih264_dpb_mgr_delete_ref_field(dpb_mgr_t *ps_dpb_mgr,\n                                      WORD32 reference_type);\n\nWORD32 ih264_dpb_mgr_alternate_ref_fields(dpb_mgr_t *ps_dpb_mgr,\n                                          WORD32 reference_type,\n                                          WORD32 first_field_type);\n\nWORD32 ih264_dpb_mgr_sort_short_term_fields_by_frame_num(dpb_mgr_t *ps_dpb_mgr,\n                                                         WORD32 curr_frame_num,\n                                                         WORD32 first_field_type,\n                                                         WORD32 max_frame_num);\n\nWORD32 ih264_dpb_mgr_sort_short_term_fields_by_poc_l0(dpb_mgr_t *ps_dpb_mgr,\n                                                      WORD32 curr_poc,\n                                                      WORD32 first_field_type);\n\nWORD32 ih264_dpb_mgr_sort_short_term_fields_by_poc_l1(dpb_mgr_t *ps_dpb_mgr,\n                                                      WORD32 curr_poc,\n                                                      WORD32 first_field_type);\n\nWORD32 ih264_dpb_mgr_sort_long_term_fields_by_frame_idx(dpb_mgr_t *ps_dpb_mgr,\n                                                        WORD32 first_field_type);\n\nWORD32 ih264_dpb_mgr_delete_long_ref_fields_max_frame_idx(dpb_mgr_t *ps_dpb_mgr,\n                                                          WORD32 max_frame_idx);\n\nvoid ih264_dpb_mgr_del_ref(dpb_mgr_t *ps_dpb_mgr,\n                           buf_mgr_t *ps_buf_mgr,\n                           WORD32 u4_abs_poc);\n\npic_buf_t *ih264_dpb_mgr_get_ref_by_nearest_poc(dpb_mgr_t *ps_dpb_mgr,\n                                                WORD32 cur_abs_poc);\n\npic_buf_t *ih264_dpb_mgr_get_ref_by_poc(dpb_mgr_t *ps_dpb_mgr, WORD32 abs_poc);\n\npic_buf_t *ih264_dpb_mgr_get_ref_by_poc_lsb(dpb_mgr_t *ps_dpb_mgr,\n                                            WORD32 poc_lsb);\n\nvoid ih264_dpb_mgr_reset(dpb_mgr_t *ps_dpb_mgr, buf_mgr_t *ps_buf_mgr);\n\nvoid ih264_dpb_mgr_release_pics(buf_mgr_t *ps_buf_mgr, UWORD8 u1_disp_bufs);\n\n#endif /*  _IH264_DPB_MGR_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_error.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_error.h\n*\n* @brief\n*  Definitions related to error handling for common modules\n*\n* @author\n*  Harish\n*\n* @par List of Functions:\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n#ifndef _IH264_ERROR_H_\n#define _IH264_ERROR_H_\n\n/**\n * Enumerations for error codes used in the codec.\n * Not all these are expected to be returned to the application.\n * Only select few will be exported\n */\ntypedef enum\n{\n    /**\n     *  No error\n     */\n    IH264_SUCCESS = 0,\n    /**\n     *  Start error code for decoder\n     */\n    IH264_DEC_ERROR_START = 0x100,\n\n    /**\n     *  Start error code for encoder\n     */\n    IH264_ENC_ERROR_START = 0x200,\n    /**\n     * Generic failure\n     */\n    IH264_FAIL                             = 0x7FFFFFFF\n}IH264_ERROR_T;\n\n#endif /* _IH264_ERROR_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_ihadamard_scaling.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_ihadamard_scaling.c\n *\n * @brief\n *  Contains definition of functions for h264 inverse hadamard 4x4 transform and scaling\n *\n * @author\n *  Mohit\n *\n *  @par List of Functions:\n *  - ih264_ihadamard_scaling_4x4()\n *\n * @remarks\n *\n *******************************************************************************\n */\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_trans_macros.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_trans_data.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n\n/*\n ********************************************************************************\n *\n * @brief This function performs a 4x4 inverse hadamard transform on the 4x4 DC coefficients\n * of a 16x16 intra prediction macroblock, and then performs scaling.\n * prediction buffer\n *\n * @par Description:\n *  The DC coefficients pass through a 2-stage inverse hadamard transform.\n *  This inverse transformed content is scaled to based on Qp value.\n *\n * @param[in] pi2_src\n *  input 4x4 block of DC coefficients\n *\n * @param[out] pi2_out\n *  output 4x4 block\n *\n * @param[in] pu2_iscal_mat\n *  pointer to scaling list\n *\n * @param[in] pu2_weigh_mat\n *  pointer to weight matrix\n *\n * @param[in] u4_qp_div_6\n *  Floor (qp/6)\n *\n * @param[in] pi4_tmp\n * temporary buffer of size 1*16\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nvoid ih264_ihadamard_scaling_4x4(WORD16* pi2_src,\n                                 WORD16* pi2_out,\n                                 const UWORD16 *pu2_iscal_mat,\n                                 const UWORD16 *pu2_weigh_mat,\n                                 UWORD32 u4_qp_div_6,\n                                 WORD32* pi4_tmp)\n{\n    WORD32 i;\n    WORD32 x0, x1, x2, x3, x4, x5, x6, x7;\n    WORD16* pi2_src_ptr, *pi2_out_ptr;\n    WORD32* pi4_tmp_ptr;\n    WORD32 rnd_fact = (u4_qp_div_6 < 6) ? (1 << (5 - u4_qp_div_6)) : 0;\n    pi4_tmp_ptr = pi4_tmp;\n    pi2_src_ptr = pi2_src;\n    pi2_out_ptr = pi2_out;\n    // Horizontal transform\n    for(i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        x4 = pi2_src_ptr[0];\n        x5 = pi2_src_ptr[1];\n        x6 = pi2_src_ptr[2];\n        x7 = pi2_src_ptr[3];\n\n        x0 = x4 + x7;\n        x1 = x5 + x6;\n        x2 = x5 - x6;\n        x3 = x4 - x7;\n\n        pi4_tmp_ptr[0] = x0 + x1;\n        pi4_tmp_ptr[1] = x2 + x3;\n        pi4_tmp_ptr[2] = x0 - x1;\n        pi4_tmp_ptr[3] = x3 - x2;\n\n        pi4_tmp_ptr += SUB_BLK_WIDTH_4x4;\n        pi2_src_ptr += SUB_BLK_WIDTH_4x4;\n    }\n    pi4_tmp_ptr = pi4_tmp;\n    // Vertical Transform\n    for(i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        x4 = pi4_tmp_ptr[0];\n        x5 = pi4_tmp_ptr[4];\n        x6 = pi4_tmp_ptr[8];\n        x7 = pi4_tmp_ptr[12];\n\n        x0 = x4 + x7;\n        x1 = x5 + x6;\n        x2 = x5 - x6;\n        x3 = x4 - x7;\n\n        pi4_tmp_ptr[0] = x0 + x1;\n        pi4_tmp_ptr[4] = x2 + x3;\n        pi4_tmp_ptr[8] = x0 - x1;\n        pi4_tmp_ptr[12] = x3 - x2;\n\n        pi4_tmp_ptr++;\n    }\n    pi4_tmp_ptr = pi4_tmp;\n    //Scaling\n    for(i = 0; i < (SUB_BLK_WIDTH_4x4 * SUB_BLK_WIDTH_4x4); i++)\n    {\n      INV_QUANT(pi4_tmp_ptr[i], pu2_iscal_mat[0], pu2_weigh_mat[0], u4_qp_div_6,\n                rnd_fact, 6);\n      pi2_out_ptr[i] = pi4_tmp_ptr[i];\n    }\n}\n\nvoid ih264_ihadamard_scaling_2x2_uv(WORD16* pi2_src,\n                                    WORD16* pi2_out,\n                                    const UWORD16 *pu2_iscal_mat,\n                                    const UWORD16 *pu2_weigh_mat,\n                                    UWORD32 u4_qp_div_6,\n                                    WORD32* pi4_tmp)\n{\n  WORD32 i4_x0,i4_x1,i4_x2,i4_x3,i4_x4,i4_x5,i4_x6,i4_x7;\n  WORD32 i4_y0,i4_y1,i4_y2,i4_y3,i4_y4,i4_y5,i4_y6,i4_y7;\n\n  UNUSED(pi4_tmp);\n\n  i4_x4 = pi2_src[0];\n  i4_x5 = pi2_src[1];\n  i4_x6 = pi2_src[2];\n  i4_x7 = pi2_src[3];\n\n  i4_x0 = i4_x4 + i4_x5;\n  i4_x1 = i4_x4 - i4_x5;\n  i4_x2 = i4_x6 + i4_x7;\n  i4_x3 = i4_x6 - i4_x7;\n\n  i4_x4 = i4_x0+i4_x2;\n  i4_x5 = i4_x1+i4_x3;\n  i4_x6 = i4_x0-i4_x2;\n  i4_x7 = i4_x1-i4_x3;\n\n  INV_QUANT(i4_x4,pu2_iscal_mat[0],pu2_weigh_mat[0],u4_qp_div_6,0,5);\n  INV_QUANT(i4_x5,pu2_iscal_mat[0],pu2_weigh_mat[0],u4_qp_div_6,0,5);\n  INV_QUANT(i4_x6,pu2_iscal_mat[0],pu2_weigh_mat[0],u4_qp_div_6,0,5);\n  INV_QUANT(i4_x7,pu2_iscal_mat[0],pu2_weigh_mat[0],u4_qp_div_6,0,5);\n\n  pi2_out[0] = i4_x4;\n  pi2_out[1] = i4_x5;\n  pi2_out[2] = i4_x6;\n  pi2_out[3] = i4_x7;\n\n  i4_y4 = pi2_src[4];\n  i4_y5 = pi2_src[5];\n  i4_y6 = pi2_src[6];\n  i4_y7 = pi2_src[7];\n\n  i4_y0 = i4_y4 + i4_y5;\n  i4_y1 = i4_y4 - i4_y5;\n  i4_y2 = i4_y6 + i4_y7;\n  i4_y3 = i4_y6 - i4_y7;\n\n  i4_y4 = i4_y0+i4_y2;\n  i4_y5 = i4_y1+i4_y3;\n  i4_y6 = i4_y0-i4_y2;\n  i4_y7 = i4_y1-i4_y3;\n\n  INV_QUANT(i4_y4,pu2_iscal_mat[0],pu2_weigh_mat[0],u4_qp_div_6,0,5);\n  INV_QUANT(i4_y5,pu2_iscal_mat[0],pu2_weigh_mat[0],u4_qp_div_6,0,5);\n  INV_QUANT(i4_y6,pu2_iscal_mat[0],pu2_weigh_mat[0],u4_qp_div_6,0,5);\n  INV_QUANT(i4_y7,pu2_iscal_mat[0],pu2_weigh_mat[0],u4_qp_div_6,0,5);\n\n  pi2_out[4] = i4_y4;\n  pi2_out[5] = i4_y5;\n  pi2_out[6] = i4_y6;\n  pi2_out[7] = i4_y7;\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_inter_pred_filters.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_inter_pred_filters.c\n *\n * @brief\n *  Contains function definitions for inter prediction interpolation filters\n *\n * @author\n *  Ittiam\n *\n * @par List of Functions:\n *  - ih264_inter_pred_luma_copy\n *  - ih264_interleave_copy\n *  - ih264_inter_pred_luma_horz\n *  - ih264_inter_pred_luma_vert\n *  - ih264_inter_pred_luma_horz_hpel_vert_hpel\n *  - ih264_inter_pred_luma_horz_qpel\n *  - ih264_inter_pred_luma_vert_qpel\n *  - ih264_inter_pred_luma_horz_qpel_vert_qpel\n *  - ih264_inter_pred_luma_horz_hpel_vert_qpel\n *  - ih264_inter_pred_luma_horz_qpel_vert_hpel\n *  - ih264_inter_pred_luma_bilinear\n *  - ih264_inter_pred_chroma\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_inter_pred_filters.h\"\n\n\n/*****************************************************************************/\n/* Constant Data variables                                                   */\n/*****************************************************************************/\n\n/* coefficients for 6 tap filtering*/\nconst WORD32 ih264_g_six_tap[3] ={1,-5,20};\n\n\n/*****************************************************************************/\n/*  Function definitions .                                                   */\n/*****************************************************************************/\n/**\n *******************************************************************************\n *\n * @brief\n * Interprediction luma function for copy\n *\n * @par Description:\n *    Copies the array of width 'wd' and height 'ht' from the  location pointed\n *    by 'src' to the location pointed by 'dst'\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n *\n * @param[in] ht\n *  integer height of the array\n *\n * @param[in] wd\n *  integer width of the array\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\nvoid ih264_inter_pred_luma_copy(UWORD8 *pu1_src,\n                                UWORD8 *pu1_dst,\n                                WORD32 src_strd,\n                                WORD32 dst_strd,\n                                WORD32 ht,\n                                WORD32 wd,\n                                UWORD8* pu1_tmp,\n                                WORD32 dydx)\n{\n    WORD32 row, col;\n    UNUSED(pu1_tmp);\n    UNUSED(dydx);\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd; col++)\n        {\n            pu1_dst[col] = pu1_src[col];\n        }\n\n        pu1_src += src_strd;\n        pu1_dst += dst_strd;\n    }\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n * Fucntion for copying to an interleaved destination\n *\n * @par Description:\n *    Copies the array of width 'wd' and height 'ht' from the  location pointed\n *    by 'src' to the location pointed by 'dst'\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ht\n *  integer height of the array\n *\n * @param[in] wd\n *  integer width of the array\n *\n * @returns\n *\n * @remarks\n *  The alternate elements of src will be copied to alternate locations in dsr\n *  Other locations are not touched\n *\n *******************************************************************************\n */\nvoid ih264_interleave_copy(UWORD8 *pu1_src,\n                           UWORD8 *pu1_dst,\n                           WORD32 src_strd,\n                           WORD32 dst_strd,\n                           WORD32 ht,\n                           WORD32 wd)\n{\n    WORD32 row, col;\n    wd *= 2;\n\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd; col+=2)\n        {\n            pu1_dst[col] = pu1_src[col];\n        }\n\n        pu1_src += src_strd;\n        pu1_dst += dst_strd;\n    }\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *     Interprediction luma filter for horizontal input\n *\n * @par Description:\n *    Applies a 6 tap horizontal filter .The output is  clipped to 8 bits\n *    sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ht\n *  integer height of the array\n *\n * @param[in] wd\n *  integer width of the array\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nvoid ih264_inter_pred_luma_horz(UWORD8 *pu1_src,\n                                UWORD8 *pu1_dst,\n                                WORD32 src_strd,\n                                WORD32 dst_strd,\n                                WORD32 ht,\n                                WORD32 wd,\n                                UWORD8* pu1_tmp,\n                                WORD32 dydx)\n{\n    WORD32 row, col;\n    WORD16 i2_tmp;\n    UNUSED(pu1_tmp);\n    UNUSED(dydx);\n\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd; col++)\n        {\n            i2_tmp = 0;/*ih264_g_six_tap[] is the array containing the filter coeffs*/\n            i2_tmp = ih264_g_six_tap[0] *\n                            (pu1_src[col - 2] + pu1_src[col + 3])\n                     + ih264_g_six_tap[1] *\n                            (pu1_src[col - 1] + pu1_src[col + 2])\n                     + ih264_g_six_tap[2] *\n                            (pu1_src[col] + pu1_src[col + 1]);\n            i2_tmp = (i2_tmp + 16) >> 5;\n            pu1_dst[col] = CLIP_U8(i2_tmp);\n        }\n\n        pu1_src += src_strd;\n        pu1_dst += dst_strd;\n    }\n\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *    Interprediction luma filter for vertical input\n *\n * @par Description:\n *   Applies a 6 tap vertical filter.The output is  clipped to 8 bits\n *    sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ht\n *  integer height of the array\n *\n * @param[in] wd\n *  integer width of the array\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nvoid ih264_inter_pred_luma_vert(UWORD8 *pu1_src,\n                                UWORD8 *pu1_dst,\n                                WORD32 src_strd,\n                                WORD32 dst_strd,\n                                WORD32 ht,\n                                WORD32 wd,\n                                UWORD8* pu1_tmp,\n                                WORD32 dydx)\n{\n    WORD32 row, col;\n    WORD16 i2_tmp;\n    UNUSED(pu1_tmp);\n    UNUSED(dydx);\n\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd; col++)\n        {\n            i2_tmp = 0; /*ih264_g_six_tap[] is the array containing the filter coeffs*/\n            i2_tmp = ih264_g_six_tap[0] *\n                            (pu1_src[col - 2 * src_strd] + pu1_src[col + 3 * src_strd])\n                     + ih264_g_six_tap[1] *\n                            (pu1_src[col - 1 * src_strd] + pu1_src[col + 2 * src_strd])\n                     + ih264_g_six_tap[2] *\n                            (pu1_src[col] + pu1_src[col + 1 * src_strd]);\n            i2_tmp = (i2_tmp + 16) >> 5;\n            pu1_dst[col] = CLIP_U8(i2_tmp);\n        }\n        pu1_src += src_strd;\n        pu1_dst += dst_strd;\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264_inter_pred_luma_horz_hpel_vert_hpel \\endif\n *\n * \\brief\n *    This function implements a two stage cascaded six tap filter. It\n *    applies the six tap filter in the horizontal direction on the\n *    predictor values, followed by applying the same filter in the\n *    vertical direction on the output of the first stage. The six tap\n *    filtering operation is described in sec 8.4.2.2.1 titled \"Luma sample\n *    interpolation process\"\n *\n * \\param pu1_src: Pointer to the buffer containing the predictor values.\n *     pu1_src could point to the frame buffer or the predictor buffer.\n * \\param pu1_dst: Pointer to the destination buffer where the output of\n *     the six tap filter is stored.\n * \\param ht: Height of the rectangular pixel grid to be interpolated\n * \\param wd: Width of the rectangular pixel grid to be interpolated\n * \\param src_strd: Width of the buffer pointed to by pu1_src.\n * \\param dst_strd: Width of the destination buffer\n * \\param pu1_tmp: temporary buffer.\n * \\param dydx: x and y reference offset for qpel calculations: UNUSED in this function.\n *\n * \\return\n *    None.\n *\n * \\note\n *    This function takes the 8 bit predictor values, applies the six tap\n *    filter in the horizontal direction and outputs the result clipped to\n *    8 bit precision. The input is stored in the buffer pointed to by\n *    pu1_src while the output is stored in the buffer pointed by pu1_dst.\n *    Both pu1_src and pu1_dst could point to the same buffer i.e. the\n *    six tap filter could be done in place.\n *\n **************************************************************************\n */\nvoid ih264_inter_pred_luma_horz_hpel_vert_hpel(UWORD8 *pu1_src,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 src_strd,\n                                               WORD32 dst_strd,\n                                               WORD32 ht,\n                                               WORD32 wd,\n                                               UWORD8* pu1_tmp,\n                                               WORD32 dydx)\n{\n    WORD32 row, col;\n    WORD32 tmp;\n    WORD16* pi2_pred1_temp;\n    WORD16* pi2_pred1;\n    UNUSED(dydx);\n    pi2_pred1_temp = (WORD16*)pu1_tmp;\n    pi2_pred1_temp += 2;\n    pi2_pred1 = pi2_pred1_temp;\n    for(row = 0; row < ht; row++)\n    {\n        for(col = -2; col < wd + 3; col++)\n        {\n            tmp = 0;/*ih264_g_six_tap[] is the array containing the filter coeffs*/\n            tmp = ih264_g_six_tap[0] *\n                            (pu1_src[col - 2 * src_strd] + pu1_src[col + 3 * src_strd])\n                  + ih264_g_six_tap[1] *\n                            (pu1_src[col - 1 * src_strd] + pu1_src[col + 2 * src_strd])\n                  + ih264_g_six_tap[2] *\n                            (pu1_src[col] + pu1_src[col + 1 * src_strd]);\n            pi2_pred1_temp[col] = tmp;\n        }\n        pu1_src += src_strd;\n        pi2_pred1_temp = pi2_pred1_temp + wd + 5;\n    }\n\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd; col++)\n        {\n            tmp = 0;/*ih264_g_six_tap[] is the array containing the filter coeffs*/\n            tmp = ih264_g_six_tap[0] *\n                            (pi2_pred1[col - 2] + pi2_pred1[col + 3])\n                  + ih264_g_six_tap[1] *\n                            (pi2_pred1[col - 1] + pi2_pred1[col + 2])\n                  + ih264_g_six_tap[2] * (pi2_pred1[col] + pi2_pred1[col + 1]);\n            tmp = (tmp + 512) >> 10;\n            pu1_dst[col] = CLIP_U8(tmp);\n        }\n        pi2_pred1 += (wd + 5);\n        pu1_dst += dst_strd;\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264_inter_pred_luma_horz_qpel \\endif\n *\n * \\brief\n *    This routine applies the six tap filter to the predictors in the\n *    horizontal direction. The six tap filtering operation is described in\n *    sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n *\n * \\param pu1_src: Pointer to the buffer containing the predictor values.\n *     pu1_src could point to the frame buffer or the predictor buffer.\n * \\param pu1_dst: Pointer to the destination buffer where the output of\n *     the six tap filter is stored.\n * \\param ht: Height of the rectangular pixel grid to be interpolated\n * \\param wd: Width of the rectangular pixel grid to be interpolated\n * \\param src_strd: Width of the buffer pointed to by pu1_src.\n * \\param dst_strd: Width of the destination buffer\n * \\param pu1_tmp: temporary buffer: UNUSED in this function\n * \\param dydx: x and y reference offset for qpel calculations.\n *\n * \\return\n *    None.\n *\n * \\note\n *    This function takes the 8 bit predictor values, applies the six tap\n *    filter in the horizontal direction and outputs the result clipped to\n *    8 bit precision. The input is stored in the buffer pointed to by\n *    pu1_src while the output is stored in the buffer pointed by pu1_dst.\n *    Both pu1_src and pu1_dst could point to the same buffer i.e. the\n *    six tap filter could be done in place.\n *\n **************************************************************************\n */\nvoid ih264_inter_pred_luma_horz_qpel(UWORD8 *pu1_src,\n                                     UWORD8 *pu1_dst,\n                                     WORD32 src_strd,\n                                     WORD32 dst_strd,\n                                     WORD32 ht,\n                                     WORD32 wd,\n                                     UWORD8* pu1_tmp,\n                                     WORD32 dydx)\n{\n    WORD32 row, col;\n    UWORD8 *pu1_pred1;\n    WORD32 x_offset = dydx & 0x3;\n    UNUSED(pu1_tmp);\n    pu1_pred1 = pu1_src + (x_offset >> 1);\n\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd; col++, pu1_src++, pu1_dst++)\n        {\n            WORD16 i2_temp;\n            /* The logic below implements the following equation\n             i2_temp = puc_pred[-2] - 5 * (puc_pred[-1] + puc_pred[2]) +\n             20 * (puc_pred[0] + puc_pred[1]) + puc_pred[3]; */\n            i2_temp = pu1_src[-2] + pu1_src[3]\n                      - (pu1_src[-1] + pu1_src[2])\n                      + ((pu1_src[0] + pu1_src[1] - pu1_src[-1] - pu1_src[2]) << 2)\n                      + ((pu1_src[0] + pu1_src[1]) << 4);\n            i2_temp = (i2_temp + 16) >> 5;\n            i2_temp = CLIP_U8(i2_temp);\n            *pu1_dst = (i2_temp + *pu1_pred1 + 1) >> 1;\n\n            pu1_pred1++;\n        }\n        pu1_dst += dst_strd - wd;\n        pu1_src += src_strd - wd;\n        pu1_pred1 += src_strd - wd;\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264_inter_pred_luma_vert_qpel \\endif\n *\n * \\brief\n *    This routine applies the six tap filter to the predictors in the\n *    vertical direction and interpolates them to obtain pixels at quarter vertical\n *    positions (0, 1/4) and (0, 3/4). The six tap filtering operation is\n *    described in sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n *\n * \\param pu1_src: Pointer to the buffer containing the predictor values.\n *     pu1_src could point to the frame buffer or the predictor buffer.\n * \\param pu1_dst: Pointer to the destination buffer where the output of\n *     the six tap filter is stored.\n * \\param ht: Height of the rectangular pixel grid to be interpolated\n * \\param wd: Width of the rectangular pixel grid to be interpolated\n * \\param src_strd: Width of the buffer pointed to by puc_pred.\n * \\param dst_strd: Width of the destination buffer\n * \\param pu1_tmp: temporary buffer: UNUSED in this function\n * \\param dydx: x and y reference offset for qpel calculations.\n *\n * \\return\n *    void\n *\n * \\note\n *    This function takes the 8 bit predictor values, applies the six tap\n *    filter in the vertical direction and outputs the result clipped to\n *    8 bit precision. The input is stored in the buffer pointed to by\n *    puc_pred while the output is stored in the buffer pointed by puc_dest.\n *    Both puc_pred and puc_dest could point to the same buffer i.e. the\n *    six tap filter could be done in place.\n *\n * \\para <title>\n *    <paragraph>\n *  ...\n **************************************************************************\n */\nvoid ih264_inter_pred_luma_vert_qpel(UWORD8 *pu1_src,\n                                     UWORD8 *pu1_dst,\n                                     WORD32 src_strd,\n                                     WORD32 dst_strd,\n                                     WORD32 ht,\n                                     WORD32 wd,\n                                     UWORD8* pu1_tmp,\n                                     WORD32 dydx)\n{\n    WORD32 row, col;\n    WORD32 y_offset = dydx >> 2;\n    WORD32 off1, off2, off3;\n    UWORD8 *pu1_pred1;\n    UNUSED(pu1_tmp);\n    y_offset = y_offset & 0x3;\n\n    off1 = src_strd;\n    off2 = src_strd << 1;\n    off3 = off1 + off2;\n\n    pu1_pred1 = pu1_src + (y_offset >> 1) * src_strd;\n\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd; col++, pu1_dst++, pu1_src++, pu1_pred1++)\n        {\n            WORD16 i2_temp;\n            /* The logic below implements the following equation\n             i16_temp = puc_pred[-2*src_strd] + puc_pred[3*src_strd] -\n             5 * (puc_pred[-1*src_strd] + puc_pred[2*src_strd])  +\n             20 * (puc_pred[0] + puc_pred[src_strd]); */\n            i2_temp = pu1_src[-off2] + pu1_src[off3]\n                       - (pu1_src[-off1] + pu1_src[off2])\n                       + ((pu1_src[0] + pu1_src[off1] - pu1_src[-off1] - pu1_src[off2]) << 2)\n                       + ((pu1_src[0] + pu1_src[off1]) << 4);\n            i2_temp = (i2_temp + 16) >> 5;\n            i2_temp = CLIP_U8(i2_temp);\n\n            *pu1_dst = (i2_temp + *pu1_pred1 + 1) >> 1;\n        }\n        pu1_src += src_strd - wd;\n        pu1_pred1 += src_strd - wd;\n        pu1_dst += dst_strd - wd;\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264_inter_pred_luma_horz_qpel_vert_qpel \\endif\n *\n * \\brief\n *    This routine applies the six tap filter to the predictors in the\n *    vertical and horizontal direction and averages them to get pixels at locations\n *    (1/4,1/4), (1/4, 3/4), (3/4, 1/4) & (3/4, 3/4). The six tap filtering operation\n *    is described in sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n *\n * \\param pu1_src: Pointer to the buffer containing the predictor values.\n *     pu1_src could point to the frame buffer or the predictor buffer.\n * \\param pu1_dst: Pointer to the destination buffer where the output of\n *     the six tap filter is stored.\n * \\param wd: Width of the rectangular pixel grid to be interpolated\n * \\param ht: Height of the rectangular pixel grid to be interpolated\n * \\param src_strd: Width of the buffer pointed to by puc_pred.\n * \\param dst_strd: Width of the destination buffer\n * \\param pu1_tmp: temporary buffer, UNUSED in this function\n * \\param dydx: x and y reference offset for qpel calculations.\n *\n * \\return\n *    void\n *\n * \\note\n *    This function takes the 8 bit predictor values, applies the six tap\n *    filter in the vertical direction and outputs the result clipped to\n *    8 bit precision. The input is stored in the buffer pointed to by\n *    puc_pred while the output is stored in the buffer pointed by puc_dest.\n *    Both puc_pred and puc_dest could point to the same buffer i.e. the\n *    six tap filter could be done in place.\n *\n * \\para <title>\n *    <paragraph>\n *  ...\n **************************************************************************\n */\nvoid ih264_inter_pred_luma_horz_qpel_vert_qpel(UWORD8 *pu1_src,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 src_strd,\n                                               WORD32 dst_strd,\n                                               WORD32 ht,\n                                               WORD32 wd,\n                                               UWORD8* pu1_tmp,\n                                               WORD32 dydx)\n{\n    WORD32 row, col;\n    WORD32 x_offset = dydx & 0x3;\n    WORD32 y_offset = dydx >> 2;\n\n    WORD32 off1, off2, off3;\n    UWORD8* pu1_pred_vert, *pu1_pred_horz;\n    UNUSED(pu1_tmp);\n    y_offset = y_offset & 0x3;\n\n    off1 = src_strd;\n    off2 = src_strd << 1;\n    off3 = off1 + off2;\n\n    pu1_pred_horz = pu1_src + (y_offset >> 1) * src_strd;\n    pu1_pred_vert = pu1_src + (x_offset >> 1);\n\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd;\n                        col++, pu1_dst++, pu1_pred_vert++, pu1_pred_horz++)\n        {\n            WORD16 i2_temp_vert, i2_temp_horz;\n            /* The logic below implements the following equation\n             i2_temp = puc_pred[-2*src_strd] + puc_pred[3*src_strd] -\n             5 * (puc_pred[-1*src_strd] + puc_pred[2*src_strd])  +\n             20 * (puc_pred[0] + puc_pred[src_strd]); */\n            i2_temp_vert = pu1_pred_vert[-off2] + pu1_pred_vert[off3]\n                            - (pu1_pred_vert[-off1] + pu1_pred_vert[off2])\n                            + ((pu1_pred_vert[0] + pu1_pred_vert[off1]\n                                            - pu1_pred_vert[-off1]\n                                            - pu1_pred_vert[off2]) << 2)\n                            + ((pu1_pred_vert[0] + pu1_pred_vert[off1]) << 4);\n            i2_temp_vert = (i2_temp_vert + 16) >> 5;\n            i2_temp_vert = CLIP_U8(i2_temp_vert);\n\n            /* The logic below implements the following equation\n             i16_temp = puc_pred[-2] - 5 * (puc_pred[-1] + puc_pred[2]) +\n             20 * (puc_pred[0] + puc_pred[1]) + puc_pred[3]; */\n            i2_temp_horz = pu1_pred_horz[-2] + pu1_pred_horz[3]\n                            - (pu1_pred_horz[-1] + pu1_pred_horz[2])\n                            + ((pu1_pred_horz[0] + pu1_pred_horz[1]\n                                            - pu1_pred_horz[-1]\n                                            - pu1_pred_horz[2]) << 2)\n                            + ((pu1_pred_horz[0] + pu1_pred_horz[1]) << 4);\n            i2_temp_horz = (i2_temp_horz + 16) >> 5;\n            i2_temp_horz = CLIP_U8(i2_temp_horz);\n            *pu1_dst = (i2_temp_vert + i2_temp_horz + 1) >> 1;\n        }\n        pu1_pred_vert += (src_strd - wd);\n        pu1_pred_horz += (src_strd - wd);\n        pu1_dst += (dst_strd - wd);\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264_inter_pred_luma_horz_qpel_vert_hpel \\endif\n *\n * \\brief\n *    This routine applies the six tap filter to the predictors in the vertical\n *    and horizontal direction to obtain the pixel at (1/2,1/2). It then interpolates\n *    pixel at (0,1/2) and (1/2,1/2) to obtain pixel at (1/4,1/2). Similarly for (3/4,1/2).\n *    The six tap filtering operation is described in sec 8.4.2.2.1 titled\n *    \"Luma sample interpolation process\"\n *\n * \\param pu1_src: Pointer to the buffer containing the predictor values.\n *     pu1_src could point to the frame buffer or the predictor buffer.\n * \\param pu1_dst: Pointer to the destination buffer where the output of\n *     the six tap filter followed by interpolation is stored.\n * \\param wd: Width of the rectangular pixel grid to be interpolated\n * \\param ht: Height of the rectangular pixel grid to be interpolated\n * \\param src_strd: Width of the buffer pointed to by puc_pred.\n * \\param dst_strd: Width of the destination buffer\n * \\param pu1_tmp: buffer to store temporary output after 1st 6-tap filter.\n * \\param dydx: x and y reference offset for qpel calculations.\n *\n * \\return\n *    void\n *\n * \\note\n *    This function takes the 8 bit predictor values, applies the six tap\n *    filter in the vertical direction and outputs the result clipped to\n *    8 bit precision. The input is stored in the buffer pointed to by\n *    puc_pred while the output is stored in the buffer pointed by puc_dest.\n *    Both puc_pred and puc_dest could point to the same buffer i.e. the\n *    six tap filter could be done in place.\n *\n * \\para <title>\n *    <paragraph>\n *  ...\n **************************************************************************\n */\nvoid ih264_inter_pred_luma_horz_qpel_vert_hpel(UWORD8 *pu1_src,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 src_strd,\n                                               WORD32 dst_strd,\n                                               WORD32 ht,\n                                               WORD32 wd,\n                                               UWORD8* pu1_tmp,\n                                               WORD32 dydx)\n{\n    WORD32 row, col;\n    WORD32 tmp;\n    WORD16* pi2_pred1_temp, *pi2_pred1;\n    UWORD8* pu1_dst_tmp;\n    WORD32 x_offset = dydx & 0x3;\n    WORD16 i2_macro;\n\n    pi2_pred1_temp = (WORD16*)pu1_tmp;\n    pi2_pred1_temp += 2;\n    pi2_pred1 = pi2_pred1_temp;\n    pu1_dst_tmp = pu1_dst;\n\n    for(row = 0; row < ht; row++)\n    {\n        for(col = -2; col < wd + 3; col++)\n        {\n            tmp = 0;/*ih264_g_six_tap[] is the array containing the filter coeffs*/\n            tmp = ih264_g_six_tap[0] *\n                            (pu1_src[col - 2 * src_strd] + pu1_src[col + 3 * src_strd])\n                  + ih264_g_six_tap[1] *\n                            (pu1_src[col - 1 * src_strd] + pu1_src[col + 2 * src_strd])\n                  + ih264_g_six_tap[2] *\n                            (pu1_src[col] + pu1_src[col + 1 * src_strd]);\n            pi2_pred1_temp[col] = tmp;\n        }\n\n        pu1_src += src_strd;\n        pi2_pred1_temp = pi2_pred1_temp + wd + 5;\n    }\n\n    pi2_pred1_temp = pi2_pred1;\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd; col++)\n        {\n            tmp = 0;/*ih264_g_six_tap[] is the array containing the filter coeffs*/\n            tmp = ih264_g_six_tap[0] *\n                            (pi2_pred1[col - 2] + pi2_pred1[col + 3])\n                  + ih264_g_six_tap[1] *\n                            (pi2_pred1[col - 1] + pi2_pred1[col + 2])\n                  + ih264_g_six_tap[2] *\n                            (pi2_pred1[col] + pi2_pred1[col + 1]);\n            tmp = (tmp + 512) >> 10;\n            pu1_dst[col] = CLIP_U8(tmp);\n        }\n        pi2_pred1 += (wd + 5);\n        pu1_dst += dst_strd;\n    }\n\n    pu1_dst = pu1_dst_tmp;\n    pi2_pred1_temp += (x_offset >> 1);\n    for(row = ht; row != 0; row--)\n    {\n        for(col = wd; col != 0; col--, pu1_dst++, pi2_pred1_temp++)\n        {\n            UWORD8 uc_temp;\n            /* Clipping the output of the six tap filter obtained from the\n             first stage of the 2d filter stage */\n            *pi2_pred1_temp = (*pi2_pred1_temp + 16) >> 5;\n            i2_macro = (*pi2_pred1_temp);\n            uc_temp = CLIP_U8(i2_macro);\n            *pu1_dst = (*pu1_dst + uc_temp + 1) >> 1;\n        }\n        pi2_pred1_temp += 5;\n        pu1_dst += dst_strd - wd;\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264_inter_pred_luma_horz_hpel_vert_qpel \\endif\n *\n * \\brief\n *    This routine applies the six tap filter to the predictors in the horizontal\n *    and vertical direction to obtain the pixel at (1/2,1/2). It then interpolates\n *    pixel at (1/2,0) and (1/2,1/2) to obtain pixel at (1/2,1/4). Similarly for (1/2,3/4).\n *    The six tap filtering operation is described in sec 8.4.2.2.1 titled\n *    \"Luma sample interpolation process\"\n *\n * \\param pu1_src: Pointer to the buffer containing the predictor values.\n *     pu1_src could point to the frame buffer or the predictor buffer.\n * \\param pu1_dst: Pointer to the destination buffer where the output of\n *     the six tap filter followed by interpolation is stored.\n * \\param wd: Width of the rectangular pixel grid to be interpolated\n * \\param ht: Height of the rectangular pixel grid to be interpolated\n * \\param src_strd: Width of the buffer pointed to by puc_pred.\n * \\param dst_strd: Width of the destination buffer\n * \\param pu1_tmp: buffer to store temporary output after 1st 6-tap filter.\n * \\param dydx: x and y reference offset for qpel calculations.\n *\n * \\return\n *    void\n *\n * \\note\n *    This function takes the 8 bit predictor values, applies the six tap\n *    filter in the vertical direction and outputs the result clipped to\n *    8 bit precision. The input is stored in the buffer pointed to by\n *    puc_pred while the output is stored in the buffer pointed by puc_dest.\n *    Both puc_pred and puc_dest could point to the same buffer i.e. the\n *    six tap filter could be done in place.\n *\n * \\para <title>\n *    <paragraph>\n *  ...\n **************************************************************************\n */\nvoid ih264_inter_pred_luma_horz_hpel_vert_qpel(UWORD8 *pu1_src,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 src_strd,\n                                               WORD32 dst_strd,\n                                               WORD32 ht,\n                                               WORD32 wd,\n                                               UWORD8* pu1_tmp,\n                                               WORD32 dydx)\n{\n\n    WORD32 row, col;\n    WORD32 tmp;\n    WORD32 y_offset = dydx >> 2;\n    WORD16* pi2_pred1_temp, *pi2_pred1;\n    UWORD8* pu1_dst_tmp;\n    //WORD32 x_offset = dydx & 0x3;\n    WORD16 i2_macro;\n\n    y_offset = y_offset & 0x3;\n\n    pi2_pred1_temp = (WORD16*)pu1_tmp;\n    pi2_pred1_temp += 2 * wd;\n    pi2_pred1 = pi2_pred1_temp;\n    pu1_dst_tmp = pu1_dst;\n    pu1_src -= 2 * src_strd;\n    for(row = -2; row < ht + 3; row++)\n    {\n        for(col = 0; col < wd; col++)\n        {\n            tmp = 0;/*ih264_g_six_tap[] is the array containing the filter coeffs*/\n            tmp = ih264_g_six_tap[0] * (pu1_src[col - 2] + pu1_src[col + 3])\n                  + ih264_g_six_tap[1] * (pu1_src[col - 1] + pu1_src[col + 2])\n                  + ih264_g_six_tap[2] * (pu1_src[col] + pu1_src[col + 1]);\n            pi2_pred1_temp[col - 2 * wd] = tmp;\n        }\n\n        pu1_src += src_strd;\n        pi2_pred1_temp += wd;\n    }\n    pi2_pred1_temp = pi2_pred1;\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd; col++)\n        {\n            tmp = 0;/*ih264_g_six_tap[] is the array containing the filter coeffs*/\n            tmp = ih264_g_six_tap[0] * (pi2_pred1[col - 2 * wd] + pi2_pred1[col + 3 * wd])\n                  + ih264_g_six_tap[1] * (pi2_pred1[col - 1 * wd] + pi2_pred1[col + 2 * wd])\n                  + ih264_g_six_tap[2] * (pi2_pred1[col] + pi2_pred1[col + 1 * wd]);\n            tmp = (tmp + 512) >> 10;\n            pu1_dst[col] = CLIP_U8(tmp);\n        }\n        pi2_pred1 += wd;\n        pu1_dst += dst_strd;\n    }\n    pu1_dst = pu1_dst_tmp;\n    pi2_pred1_temp += (y_offset >> 1) * wd;\n    for(row = ht; row != 0; row--)\n\n    {\n        for(col = wd; col != 0; col--, pu1_dst++, pi2_pred1_temp++)\n        {\n            UWORD8 u1_temp;\n            /* Clipping the output of the six tap filter obtained from the\n             first stage of the 2d filter stage */\n            *pi2_pred1_temp = (*pi2_pred1_temp + 16) >> 5;\n            i2_macro = (*pi2_pred1_temp);\n            u1_temp = CLIP_U8(i2_macro);\n            *pu1_dst = (*pu1_dst + u1_temp + 1) >> 1;\n        }\n        //pi16_pred1_temp += wd;\n        pu1_dst += dst_strd - wd;\n    }\n}\n\n/**\n *******************************************************************************\n *  function:ih264_inter_pred_luma_bilinear\n *\n * @brief\n *    This routine applies the bilinear filter to the predictors .\n *    The  filtering operation is described in\n *    sec 8.4.2.2.1 titled \"Luma sample interpolation process\"\n *\n * @par Description:\n\\note\n *     This function is called to obtain pixels lying at the following\n *    locations (1/4,1), (3/4,1),(1,1/4), (1,3/4) ,(1/4,1/2), (3/4,1/2),(1/2,1/4), (1/2,3/4),(3/4,1/4),(1/4,3/4),(3/4,3/4)&& (1/4,1/4) .\n *    The function averages the two adjacent values from the two input arrays in horizontal direction.\n *\n *\n * @param[in] pu1_src1:\n *  UWORD8 Pointer to the buffer containing the first input array.\n *\n * @param[in] pu1_src2:\n *  UWORD8 Pointer to the buffer containing the second input array.\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination where the output of bilinear filter is stored.\n *\n * @param[in] src_strd1\n *  Stride of the first input buffer\n *\n * @param[in] src_strd2\n *  Stride of the second input buffer\n *\n * @param[in] dst_strd\n *  integer destination stride of pu1_dst\n *\n * @param[in] ht\n *  integer height of the array\n *\n * @param[in] wd\n *  integer width of the array\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nvoid ih264_inter_pred_luma_bilinear(UWORD8 *pu1_src1,\n                                    UWORD8 *pu1_src2,\n                                    UWORD8 *pu1_dst,\n                                    WORD32 src_strd1,\n                                    WORD32 src_strd2,\n                                    WORD32 dst_strd,\n                                    WORD32 ht,\n                                    WORD32 wd)\n{\n    WORD32 row, col;\n    WORD16 i2_tmp;\n\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < wd; col++)\n        {\n            i2_tmp = pu1_src1[col] + pu1_src2[col];\n            i2_tmp = (i2_tmp + 1) >> 1;\n            pu1_dst[col] = CLIP_U8(i2_tmp);\n        }\n        pu1_src1 += src_strd1;\n        pu1_src2 += src_strd2;\n        pu1_dst += dst_strd;\n    }\n\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *    Interprediction chroma filter\n *\n * @par Description:\n *   Applies filtering to chroma samples as mentioned in\n *    sec 8.4.2.2.2 titled \"chroma sample interpolation process\"\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source containing alternate U and V samples\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] u1_dx\n *  dx value where the sample is to be produced(refer sec 8.4.2.2.2 )\n *\n * @param[in] u1_dy\n *  dy value where the sample is to be produced(refer sec 8.4.2.2.2 )\n *\n * @param[in] ht\n *  integer height of the array\n *\n * @param[in] wd\n *  integer width of the array\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nvoid ih264_inter_pred_chroma(UWORD8 *pu1_src,\n                             UWORD8 *pu1_dst,\n                             WORD32 src_strd,\n                             WORD32 dst_strd,\n                             WORD32 dx,\n                             WORD32 dy,\n                             WORD32 ht,\n                             WORD32 wd)\n{\n    WORD32 row, col;\n    WORD16 i2_tmp;\n\n    for(row = 0; row < ht; row++)\n    {\n        for(col = 0; col < 2 * wd; col++)\n        {\n            i2_tmp = 0; /* applies equation (8-266) in section 8.4.2.2.2 */\n            i2_tmp = (8 - dx) * (8 - dy) * pu1_src[col]\n                     + (dx) * (8 - dy) * pu1_src[col + 2]\n                     + (8 - dx) * (dy) * (pu1_src + src_strd)[col]\n                     + (dx) * (dy) * (pu1_src + src_strd)[col + 2];\n            i2_tmp = (i2_tmp + 32) >> 6;\n            pu1_dst[col] = CLIP_U8(i2_tmp);\n        }\n        pu1_src += src_strd;\n        pu1_dst += dst_strd;\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_inter_pred_filters.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/**\n *******************************************************************************\n * @file\n *  ih264_inter_pred_filters.h\n *\n * @brief\n *  Declarations of functions used for inter prediction\n *\n * @author\n *  Ittiam\n *\n * @par List of Functions:\n *  -ih264_inter_pred_luma_copy\n *  -ih264_interleave_copy\n *  -ih264_inter_pred_luma_horz\n *  -ih264_inter_pred_luma_vert\n *  -ih264_inter_pred_luma_horz_hpel_vert_hpel\n *  -ih264_inter_pred_luma_vert_qpel\n *  -ih264_inter_pred_luma_horz_qpel\n *  -ih264_inter_pred_luma_horz_qpel_vert_qpel\n *  -ih264_inter_pred_luma_horz_qpel_vert_hpel\n *  -ih264_inter_pred_luma_horz_hpel_vert_qpel\n *  -ih264_inter_pred_luma_bilinear\n *  -ih264_inter_pred_chroma\n *  -ih264_inter_pred_luma_copy_a9q\n *  -ih264_interleave_copy_a9\n *  -ih264_inter_pred_luma_horz_a9q\n *  -ih264_inter_pred_luma_vert_a9q\n *  -ih264_inter_pred_luma_bilinear_a9q\n *  -ih264_inter_pred_luma_horz_hpel_vert_hpel_a9q\n *  -ih264_inter_pred_luma_horz_qpel_a9q\n *  -ih264_inter_pred_luma_vert_qpel_a9q\n *  -ih264_inter_pred_luma_horz_qpel_vert_qpel_a9q\n *  -ih264_inter_pred_luma_horz_qpel_vert_hpel_a9q\n *  -ih264_inter_pred_luma_horz_hpel_vert_qpel_a9q\n *  -ih264_inter_pred_chroma_a9q\n *  -ih264_inter_pred_luma_copy_av8\n *  -ih264_interleave_copy_av8\n *  -ih264_inter_pred_luma_horz_av8\n *  -ih264_inter_pred_luma_vert_av8\n  *  -ih264_inter_pred_luma_bilinear_av8\n *  -ih264_inter_pred_luma_horz_hpel_vert_hpel_av8\n *  -ih264_inter_pred_luma_horz_qpel_av8\n *  -ih264_inter_pred_luma_vert_qpel_av8\n *  -ih264_inter_pred_luma_horz_qpel_vert_qpel_av8\n *  -ih264_inter_pred_luma_horz_qpel_vert_hpel_av8\n *  -ih264_inter_pred_luma_horz_hpel_vert_qpel_av8\n *  -ih264_inter_pred_chroma_av8\n *  -ih264_inter_pred_chroma_dx_zero_av8\n *  -ih264_inter_pred_chroma_dy_zero_av8\n *  -ih264_inter_pred_luma_copy_ssse3\n *  -ih264_inter_pred_luma_copy_ssse3\n *  -ih264_inter_pred_luma_horz_ssse3\n *  -ih264_inter_pred_luma_vert_ssse3\n *  -ih264_inter_pred_luma_bilinear_ssse3\n *  -ih264_inter_pred_luma_horz_hpel_vert_hpel_ssse3\n *  -ih264_inter_pred_luma_horz_qpel_ssse3\n *  -ih264_inter_pred_luma_vert_qpel_ssse3\n *  -ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3\n *  -ih264_inter_pred_luma_horz_qpel_vert_hpel_ssse3\n *  -ih264_inter_pred_luma_horz_hpel_vert_qpel_ssse3\n *  -ih264_inter_pred_chroma_ssse3\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n#ifndef _IH264_INTER_PRED_H_\n#define _IH264_INTER_PRED_H_\n\n/*****************************************************************************/\n/* Constant Data variables                                                   */\n/*****************************************************************************/\n\nextern const WORD32 ih264_g_six_tap[3];/* coefficients for 6 tap filtering*/\n\n/*****************************************************************************/\n/* Extern Function Declarations                                              */\n/*****************************************************************************/\n\ntypedef void ih264_inter_pred_luma_ft(UWORD8 *pu1_src,\n                                      UWORD8 *pu1_dst,\n                                      WORD32 src_strd,\n                                      WORD32 dst_strd,\n                                      WORD32 ht,\n                                      WORD32 wd,\n                                      UWORD8* pu1_tmp,\n                                      WORD32 dydx);\n\ntypedef void ih264_interleave_copy_ft(UWORD8 *pu1_src,\n                                      UWORD8 *pu1_dst,\n                                      WORD32 src_strd,\n                                      WORD32 dst_strd,\n                                      WORD32 ht,\n                                      WORD32 wd);\n\ntypedef void ih264_inter_pred_luma_bilinear_ft(UWORD8 *pu1_src1,\n                                               UWORD8 *pu1_src2,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 src_strd1,\n                                               WORD32 src_strd2,\n                                               WORD32 dst_strd,\n                                               WORD32 height,\n                                               WORD32 width);\n\ntypedef void ih264_inter_pred_chroma_ft(UWORD8 *pu1_src,\n                                        UWORD8 *pu1_dst,\n                                        WORD32 src_strd,\n                                        WORD32 dst_strd,\n                                        WORD32 dx,\n                                        WORD32 dy,\n                                        WORD32 ht,\n                                        WORD32 wd);\n\n/* No NEON Declarations */\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_copy;\n\nih264_interleave_copy_ft ih264_interleave_copy;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_vert;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_hpel_vert_hpel;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_vert_qpel;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_vert_qpel;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_vert_hpel;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_hpel_vert_qpel;\n\nih264_inter_pred_luma_bilinear_ft ih264_inter_pred_luma_bilinear;\n\nih264_inter_pred_chroma_ft ih264_inter_pred_chroma;\n\n/* A9 NEON Declarations */\nih264_inter_pred_luma_ft ih264_inter_pred_luma_copy_a9q;\n\nih264_interleave_copy_ft ih264_interleave_copy_a9;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_a9q;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_vert_a9q;\n\nih264_inter_pred_luma_bilinear_ft ih264_inter_pred_luma_bilinear_a9q;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_hpel_vert_hpel_a9q;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_a9q;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_vert_qpel_a9q;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_vert_qpel_a9q;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_vert_hpel_a9q;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_hpel_vert_qpel_a9q;\n\nih264_inter_pred_chroma_ft ih264_inter_pred_chroma_a9q;\n\n/* AV8 NEON Declarations */\nih264_inter_pred_luma_ft ih264_inter_pred_luma_copy_av8;\n\nih264_interleave_copy_ft ih264_interleave_copy_av8;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_av8;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_vert_av8;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_hpel_vert_hpel_av8;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_av8;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_vert_qpel_av8;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_vert_qpel_av8;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_vert_hpel_av8;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_hpel_vert_qpel_av8;\n\nih264_inter_pred_chroma_ft ih264_inter_pred_chroma_av8;\n\nih264_inter_pred_chroma_ft ih264_inter_pred_chroma_dx_zero_av8;\n\nih264_inter_pred_chroma_ft ih264_inter_pred_chroma_dy_zero_av8;\n\n\n/* SSSE3 Intrinsic Declarations */\nih264_inter_pred_luma_ft ih264_inter_pred_luma_copy_ssse3;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_ssse3;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_vert_ssse3;\n\nih264_inter_pred_luma_bilinear_ft ih264_inter_pred_luma_bilinear_ssse3;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_hpel_vert_hpel_ssse3;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_ssse3;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_vert_qpel_ssse3;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_qpel_vert_hpel_ssse3;\n\nih264_inter_pred_luma_ft ih264_inter_pred_luma_horz_hpel_vert_qpel_ssse3;\n\nih264_inter_pred_chroma_ft ih264_inter_pred_chroma_ssse3;\n\n#endif\n\n/** Nothing past this point */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_intra_pred_filters.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_intra_pred_filters.h\n *\n * @brief\n *  Declarations of functions used for intra prediction\n *\n * @author\n *  Ittiam\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n#ifndef IH264_INTRA_PRED_FILTERS_H_\n\n#define IH264_INTRA_PRED_FILTERS_H_\n\n/*****************************************************************************/\n/*  Macro Expansion                                                          */\n/*****************************************************************************/\n\n/*! Filter (1,2,1) i.e (a + 2b + c) / 4 */\n#define FILT121(a,b,c) ((a + (b<<1) + c + 2)>>2)\n/*! Filter (1,1) i.e (a + b) / 2 */\n#define FILT11(a,b) ((a + b + 1)>>1)\n/*****************************************************************************/\n/*  Global Variables                                                        */\n/*****************************************************************************/\n\n/* Global variables used only in assembly files*/\nextern const WORD8  ih264_gai1_intrapred_luma_plane_coeffs[];\nextern const WORD8  ih264_gai1_intrapred_chroma_plane_coeffs1[];\nextern const WORD8  ih264_gai1_intrapred_chroma_plane_coeffs2[];\nextern const WORD8  ih264_gai1_intrapred_luma_8x8_horz_u[];\n\n/*****************************************************************************/\n/* Extern Function Declarations                                              */\n/*****************************************************************************/\n\n\ntypedef void ih264_intra_pred_ref_filtering_ft(UWORD8 *pu1_left,\n                                               UWORD8 *pu1_topleft,\n                                               UWORD8 *pu1_top,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 left_strd,\n                                               WORD32 ngbr_avail);\n\ntypedef void ih264_intra_pred_luma_ft(UWORD8 *pu1_src,\n                                      UWORD8 *pu1_dst,\n                                      WORD32 src_strd,\n                                      WORD32 dst_strd,\n                                      WORD32 ngbr_avail);\n\n/* No Neon Definitions */\n\n/* Luma 4x4 Intra pred filters */\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_dc;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_diag_dl;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_diag_dr;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_r;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_d;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_l;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_u;\n\n/* Luma 8x8 Intra pred filters */\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_dc;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_diag_dl;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_diag_dr;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_r;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_d;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_l;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_u;\n\n/* Luma 16x16 Intra pred filters */\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_vert;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_horz;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_dc;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_plane;\n\n/* Chroma 8x8 Intra pred filters */\n\ntypedef ih264_intra_pred_luma_ft ih264_intra_pred_chroma_ft;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_dc;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_horz;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_vert;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_plane;\n\n\nih264_intra_pred_ref_filtering_ft  ih264_intra_pred_luma_8x8_mode_ref_filtering;\n\n/* A9 Definition */\n\n/* Luma 4x4 Intra pred filters */\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_dc_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_diag_dl_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_diag_dr_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_r_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_d_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_l_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_u_a9q;\n\n/* Luma 8x8 Intra pred filters */\n\nih264_intra_pred_ref_filtering_ft  ih264_intra_pred_luma_8x8_mode_ref_filtering_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_dc_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_diag_dl_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_diag_dr_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_r_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_d_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_l_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_u_a9q;\n\n/* Luma 16x16 Intra pred filters */\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_vert_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_horz_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_dc_a9q;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_plane_a9q;\n\n/* Chroma 8x8 Intra pred filters */\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_dc_a9q;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_horz_a9q;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_vert_a9q;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_plane_a9q;\n\n/* X86 Intrinsic Definitions */\n\n/* Luma 4x4 Intra pred filters */\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_dc_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_diag_dl_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_diag_dr_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_r_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_d_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_l_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_u_ssse3;\n\n/* Luma 8x8 Intra pred filters */\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_dc_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_diag_dl_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_diag_dr_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_r_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_d_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_l_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_u_ssse3;\n\n/* Luma 16x16 Intra pred filters */\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_vert_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_horz_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_dc_ssse3;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_plane_ssse3;\n\n/* Chroma 8x8 Intra pred filters */\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_dc_ssse3;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_horz_ssse3;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_vert_ssse3;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_plane_ssse3;\n\n/* AV8 Definition */\n\n/* Luma 4x4 Intra pred filters */\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_dc_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_diag_dl_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_diag_dr_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_r_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_d_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_vert_l_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_4x4_mode_horz_u_av8;\n\n/* Luma 8x8 Intra pred filters */\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_dc_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_diag_dl_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_diag_dr_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_r_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_d_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_vert_l_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_8x8_mode_horz_u_av8;\n\n/* Luma 16x16 Intra pred filters */\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_vert_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_horz_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_dc_av8;\n\nih264_intra_pred_luma_ft  ih264_intra_pred_luma_16x16_mode_plane_av8;\n\n/* Chroma 8x8 Intra pred filters */\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_dc_av8;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_horz_av8;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_vert_av8;\n\nih264_intra_pred_chroma_ft ih264_intra_pred_chroma_8x8_mode_plane_av8;\n\n#endif /* IH264_INTRA_PRED_FILTERS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_iquant_itrans_recon.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_iquant_itrans_recon.c\n *\n * @brief\n *  Contains definition of functions for h264 inverse quantization inverse transformation and recon\n *\n * @author\n *  Ittiam\n *\n *  @par List of Functions:\n *  - ih264_iquant_itrans_recon_4x4()\n *  - ih264_iquant_itrans_recon_8x8()\n *  - ih264_iquant_itrans_recon_4x4_dc()\n *  - ih264_iquant_itrans_recon_8x8_dc()\n *  - ih264_iquant_itrans_recon_chroma_4x4()\n *  -ih264_iquant_itrans_recon_chroma_4x4_dc()\n *\n * @remarks\n *\n *******************************************************************************\n */\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_trans_macros.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_trans_data.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n\n/*\n ********************************************************************************\n *\n * @brief This function reconstructs a 4x4 sub block from quantized resiude and\n * prediction buffer\n *\n * @par Description:\n *  The quantized residue is first inverse quantized, then inverse transformed.\n *  This inverse transformed content is added to the prediction buffer to recon-\n *  struct the end output\n *\n * @param[in] pi2_src\n *  quantized 4x4 block\n *\n * @param[in] pu1_pred\n *  prediction 4x4 block\n *\n * @param[out] pu1_out\n *  reconstructed 4x4 block\n *\n * @param[in] src_strd\n *  quantization buffer stride\n *\n * @param[in] pred_strd,\n *  Prediction buffer stride\n *\n * @param[in] out_strd\n *  recon buffer Stride\n *\n * @param[in] pu2_scaling_list\n *  pointer to scaling list\n *\n * @param[in] pu2_norm_adjust\n *  pointer to inverse scale matrix\n *\n * @param[in] u4_qp_div_6\n *  Floor (qp/6)\n *\n * @param[in] pi4_tmp\n * temporary buffer of size 1*16\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nvoid ih264_iquant_itrans_recon_4x4(WORD16 *pi2_src,\n                                   UWORD8 *pu1_pred,\n                                   UWORD8 *pu1_out,\n                                   WORD32 pred_strd,\n                                   WORD32 out_strd,\n                                   const UWORD16 *pu2_iscal_mat,\n                                   const UWORD16 *pu2_weigh_mat,\n                                   UWORD32 u4_qp_div_6,\n                                   WORD16 *pi2_tmp,\n                                   WORD32 iq_start_idx,\n                                   WORD16 *pi2_dc_ld_addr\n)\n{\n    WORD16 *pi2_src_ptr = pi2_src;\n    WORD16 *pi2_tmp_ptr = pi2_tmp;\n    UWORD8 *pu1_pred_ptr = pu1_pred;\n    UWORD8 *pu1_out_ptr = pu1_out;\n    WORD16 x0, x1, x2, x3, i;\n    WORD32 q0, q1, q2, q3;\n    WORD16 i_macro;\n    WORD16 rnd_fact = (u4_qp_div_6 < 4) ? 1 << (3 - u4_qp_div_6) : 0;\n\n    /* inverse quant */\n    /*horizontal inverse transform */\n    for(i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        q0 = pi2_src_ptr[0];\n        INV_QUANT(q0, pu2_iscal_mat[0], pu2_weigh_mat[0], u4_qp_div_6, rnd_fact,\n                  4);\n        if (i==0 && iq_start_idx == 1)\n            q0 = pi2_dc_ld_addr[0];     // Restoring dc value for intra case\n\n        q2 = pi2_src_ptr[2];\n        INV_QUANT(q2, pu2_iscal_mat[2], pu2_weigh_mat[2], u4_qp_div_6, rnd_fact,\n                  4);\n\n        x0 = q0 + q2;\n        x1 = q0 - q2;\n\n        q1 = pi2_src_ptr[1];\n        INV_QUANT(q1, pu2_iscal_mat[1], pu2_weigh_mat[1], u4_qp_div_6, rnd_fact,\n                  4);\n\n        q3 = pi2_src_ptr[3];\n        INV_QUANT(q3, pu2_iscal_mat[3], pu2_weigh_mat[3], u4_qp_div_6, rnd_fact,\n                  4);\n\n        x2 = (q1 >> 1) - q3;\n        x3 = q1 + (q3 >> 1);\n\n        pi2_tmp_ptr[0] = x0 + x3;\n        pi2_tmp_ptr[1] = x1 + x2;\n        pi2_tmp_ptr[2] = x1 - x2;\n        pi2_tmp_ptr[3] = x0 - x3;\n\n        pi2_src_ptr += SUB_BLK_WIDTH_4x4;\n        pi2_tmp_ptr += SUB_BLK_WIDTH_4x4;\n        pu2_iscal_mat += SUB_BLK_WIDTH_4x4;\n        pu2_weigh_mat += SUB_BLK_WIDTH_4x4;\n    }\n\n    /* vertical inverse transform */\n    pi2_tmp_ptr = pi2_tmp;\n    for(i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        pu1_pred_ptr = pu1_pred;\n        pu1_out = pu1_out_ptr;\n\n        x0 = (pi2_tmp_ptr[0] + pi2_tmp_ptr[8]);\n        x1 = (pi2_tmp_ptr[0] - pi2_tmp_ptr[8]);\n        x2 = (pi2_tmp_ptr[4] >> 1) - pi2_tmp_ptr[12];\n        x3 = pi2_tmp_ptr[4] + (pi2_tmp_ptr[12] >> 1);\n\n        /* inverse prediction */\n        i_macro = x0 + x3;\n        i_macro = ((i_macro + 32) >> 6);\n        i_macro += *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = x1 + x2;\n        i_macro = ((i_macro + 32) >> 6);\n        i_macro += *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = x1 - x2;\n        i_macro = ((i_macro + 32) >> 6);\n        i_macro += *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = x0 - x3;\n        i_macro = ((i_macro + 32) >> 6);\n        i_macro += *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n\n        pi2_tmp_ptr++;\n        pu1_out_ptr++;\n        pu1_pred++;\n    }\n\n}\n\nvoid ih264_iquant_itrans_recon_4x4_dc(WORD16 *pi2_src,\n                                      UWORD8 *pu1_pred,\n                                      UWORD8 *pu1_out,\n                                      WORD32 pred_strd,\n                                      WORD32 out_strd,\n                                      const UWORD16 *pu2_iscal_mat,\n                                      const UWORD16 *pu2_weigh_mat,\n                                      UWORD32 u4_qp_div_6,\n                                      WORD16 *pi2_tmp,\n                                      WORD32 iq_start_idx,\n                                      WORD16 *pi2_dc_ld_addr)\n{\n    UWORD8 *pu1_pred_ptr = pu1_pred;\n    UWORD8 *pu1_out_ptr = pu1_out;\n    WORD32 q0;\n    WORD16 x, i_macro, i;\n    WORD16 rnd_fact = (u4_qp_div_6 < 4) ? 1 << (3 - u4_qp_div_6) : 0;\n    UNUSED(pi2_tmp);\n\n    if (iq_start_idx == 0)\n    {\n      q0 = pi2_src[0];\n      INV_QUANT(q0, pu2_iscal_mat[0], pu2_weigh_mat[0], u4_qp_div_6, rnd_fact, 4);\n    }\n    else\n    {\n      q0 = pi2_dc_ld_addr[0];    // Restoring dc value for intra case3\n    }\n    i_macro = ((q0 + 32) >> 6);\n    for(i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        pu1_pred_ptr = pu1_pred;\n        pu1_out = pu1_out_ptr;\n\n        /* inverse prediction */\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n\n        pu1_out_ptr++;\n        pu1_pred++;\n    }\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  This function performs inverse quant and Inverse transform type Ci4 for 8x8 block\n *\n * @par Description:\n *  Performs inverse transform Ci8 and adds the residue to get the\n *  reconstructed block\n *\n * @param[in] pi2_src\n *  Input 8x8coefficients\n *\n * @param[in] pu1_pred\n *  Prediction 8x8 block\n *\n * @param[out] pu1_recon\n *  Output 8x8 block\n *\n * @param[in] q_div\n *  QP/6\n *\n * @param[in] q_rem\n *  QP%6\n *\n * @param[in] q_lev\n *  Quantizer level\n *\n * @param[in] src_strd\n *  Input stride\n *\n * @param[in] pred_strd,\n *  Prediction stride\n *\n * @param[in] out_strd\n *  Output Stride\n *\n * @param[in] pi4_tmp\n *  temporary buffer of size 1*16 we dont need a bigger blcok since we reuse\n *  the tmp for each block\n *\n * @param[in] pu4_iquant_mat\n *  Pointer to the inverse quantization matrix\n *\n * @returns  Void\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nvoid ih264_iquant_itrans_recon_8x8(WORD16 *pi2_src,\n                                   UWORD8 *pu1_pred,\n                                   UWORD8 *pu1_out,\n                                   WORD32 pred_strd,\n                                   WORD32 out_strd,\n                                   const UWORD16 *pu2_iscale_mat,\n                                   const UWORD16 *pu2_weigh_mat,\n                                   UWORD32 qp_div,\n                                   WORD16 *pi2_tmp,\n                                   WORD32 iq_start_idx,\n                                   WORD16 *pi2_dc_ld_addr\n)\n{\n    WORD32 i;\n    WORD16 *pi2_tmp_ptr = pi2_tmp;\n    UWORD8 *pu1_pred_ptr = pu1_pred;\n    UWORD8 *pu1_out_ptr = pu1_out;\n    WORD16 i_z0, i_z1, i_z2, i_z3, i_z4, i_z5, i_z6, i_z7;\n    WORD16 i_y0, i_y1, i_y2, i_y3, i_y4, i_y5, i_y6, i_y7;\n    WORD16 i_macro;\n    WORD32 q;\n    WORD32 rnd_fact = (qp_div < 6) ? (1 << (5 - qp_div)) : 0;\n    UNUSED(iq_start_idx);\n    UNUSED(pi2_dc_ld_addr);\n    /*************************************************************/\n    /* De quantization of coefficients. Will be replaced by SIMD */\n    /* operations on platform. Note : DC coeff is not scaled     */\n    /*************************************************************/\n    for(i = 0; i < (SUB_BLK_WIDTH_8x8 * SUB_BLK_WIDTH_8x8); i++)\n    {\n        q = pi2_src[i];\n        INV_QUANT(q, pu2_iscale_mat[i], pu2_weigh_mat[i], qp_div, rnd_fact, 6);\n        pi2_tmp_ptr[i] = q;\n    }\n    /* Perform Inverse transform */\n    /*--------------------------------------------------------------------*/\n    /* IDCT [ Horizontal transformation ]                                 */\n    /*--------------------------------------------------------------------*/\n    for(i = 0; i < SUB_BLK_WIDTH_8x8; i++)\n    {\n        /*------------------------------------------------------------------*/\n        /* y0 = w0 + w4                                                     */\n        /* y1 = -w3 + w5 - w7 - (w7 >> 1)                                   */\n        /* y2 = w0 - w4                                                     */\n        /* y3 = w1 + w7 - w3 - (w3 >> 1)                                    */\n        /* y4 = (w2 >> 1) - w6                                              */\n        /* y5 = -w1 + w7 + w5 + (w5 >> 1)                                   */\n        /* y6 = w2 + (w6 >> 1)                                              */\n        /* y7 = w3 + w5 + w1 + (w1 >> 1)                                    */\n        /*------------------------------------------------------------------*/\n        i_y0 = (pi2_tmp_ptr[0] + pi2_tmp_ptr[4] );\n\n        i_y1 = ((WORD32)(-pi2_tmp_ptr[3]) + pi2_tmp_ptr[5] - pi2_tmp_ptr[7]\n                        - (pi2_tmp_ptr[7] >> 1));\n\n        i_y2 = (pi2_tmp_ptr[0] - pi2_tmp_ptr[4] );\n\n        i_y3 = ((WORD32)pi2_tmp_ptr[1] + pi2_tmp_ptr[7] - pi2_tmp_ptr[3]\n                        - (pi2_tmp_ptr[3] >> 1));\n\n        i_y4 = ((pi2_tmp_ptr[2] >> 1) - pi2_tmp_ptr[6] );\n\n        i_y5 = ((WORD32)(-pi2_tmp_ptr[1]) + pi2_tmp_ptr[7] + pi2_tmp_ptr[5]\n                        + (pi2_tmp_ptr[5] >> 1));\n\n        i_y6 = (pi2_tmp_ptr[2] + (pi2_tmp_ptr[6] >> 1));\n\n        i_y7 = ((WORD32)pi2_tmp_ptr[3] + pi2_tmp_ptr[5] + pi2_tmp_ptr[1]\n                        + (pi2_tmp_ptr[1] >> 1));\n\n        /*------------------------------------------------------------------*/\n        /* z0 = y0 + y6                                                     */\n        /* z1 = y1 + (y7 >> 2)                                              */\n        /* z2 = y2 + y4                                                     */\n        /* z3 = y3 + (y5 >> 2)                                              */\n        /* z4 = y2 - y4                                                     */\n        /* z5 = (y3 >> 2) - y5                                              */\n        /* z6 = y0 - y6                                                     */\n        /* z7 = y7 - (y1 >> 2)                                              */\n        /*------------------------------------------------------------------*/\n        i_z0 = i_y0 + i_y6;\n        i_z1 = i_y1 + (i_y7 >> 2);\n        i_z2 = i_y2 + i_y4;\n        i_z3 = i_y3 + (i_y5 >> 2);\n        i_z4 = i_y2 - i_y4;\n        i_z5 = (i_y3 >> 2) - i_y5;\n        i_z6 = i_y0 - i_y6;\n        i_z7 = i_y7 - (i_y1 >> 2);\n\n        /*------------------------------------------------------------------*/\n        /* x0 = z0 + z7                                                     */\n        /* x1 = z2 + z5                                                     */\n        /* x2 = z4 + z3                                                     */\n        /* x3 = z6 + z1                                                     */\n        /* x4 = z6 - z1                                                     */\n        /* x5 = z4 - z3                                                     */\n        /* x6 = z2 - z5                                                     */\n        /* x7 = z0 - z7                                                     */\n        /*------------------------------------------------------------------*/\n        pi2_tmp_ptr[0] = i_z0 + i_z7;\n        pi2_tmp_ptr[1] = i_z2 + i_z5;\n        pi2_tmp_ptr[2] = i_z4 + i_z3;\n        pi2_tmp_ptr[3] = i_z6 + i_z1;\n        pi2_tmp_ptr[4] = i_z6 - i_z1;\n        pi2_tmp_ptr[5] = i_z4 - i_z3;\n        pi2_tmp_ptr[6] = i_z2 - i_z5;\n        pi2_tmp_ptr[7] = i_z0 - i_z7;\n\n        /* move to the next row */\n        //pi2_src_ptr += SUB_BLK_WIDTH_8x8;\n        pi2_tmp_ptr += SUB_BLK_WIDTH_8x8;\n    }\n    /*--------------------------------------------------------------------*/\n    /* IDCT [ Vertical transformation] and Xij = (xij + 32)>>6            */\n    /*                                                                    */\n    /* Add the prediction and store it back to reconstructed frame buffer */\n    /* [Prediction buffer itself in this case]                            */\n    /*--------------------------------------------------------------------*/\n\n    pi2_tmp_ptr = pi2_tmp;\n    for(i = 0; i < SUB_BLK_WIDTH_8x8; i++)\n    {\n        pu1_pred_ptr = pu1_pred;\n        pu1_out = pu1_out_ptr;\n        /*------------------------------------------------------------------*/\n        /* y0j = w0j + w4j                                                  */\n        /* y1j = -w3j + w5j -w7j -(w7j >> 1)                                */\n        /* y2j = w0j -w4j                                                   */\n        /* y3j = w1j + w7j -w3j -(w3j >> 1)                                 */\n        /* y4j = ( w2j >> 1 ) -w6j                                          */\n        /* y5j = -w1j + w7j + w5j + (w5j >> 1)                              */\n        /* y6j = w2j + ( w6j >> 1 )                                         */\n        /* y7j = w3j + w5j + w1j + (w1j >> 1)                               */\n        /*------------------------------------------------------------------*/\n        i_y0 = pi2_tmp_ptr[0] + pi2_tmp_ptr[32];\n\n        i_y1 = (WORD32)(-pi2_tmp_ptr[24]) + pi2_tmp_ptr[40] - pi2_tmp_ptr[56]\n                        - (pi2_tmp_ptr[56] >> 1);\n\n        i_y2 = pi2_tmp_ptr[0] - pi2_tmp_ptr[32];\n\n        i_y3 = (WORD32)pi2_tmp_ptr[8] + pi2_tmp_ptr[56] - pi2_tmp_ptr[24]\n                        - (pi2_tmp_ptr[24] >> 1);\n\n        i_y4 = (pi2_tmp_ptr[16] >> 1) - pi2_tmp_ptr[48];\n\n        i_y5 = (WORD32)(-pi2_tmp_ptr[8]) + pi2_tmp_ptr[56] + pi2_tmp_ptr[40]\n                        + (pi2_tmp_ptr[40] >> 1);\n\n        i_y6 = pi2_tmp_ptr[16] + (pi2_tmp_ptr[48] >> 1);\n\n        i_y7 = (WORD32)pi2_tmp_ptr[24] + pi2_tmp_ptr[40] + pi2_tmp_ptr[8]\n                        + (pi2_tmp_ptr[8] >> 1);\n\n        /*------------------------------------------------------------------*/\n        /* z0j = y0j + y6j                                                  */\n        /* z1j = y1j + (y7j >> 2)                                           */\n        /* z2j = y2j + y4j                                                  */\n        /* z3j = y3j + (y5j >> 2)                                           */\n        /* z4j = y2j -y4j                                                   */\n        /* z5j = (y3j >> 2) -y5j                                            */\n        /* z6j = y0j -y6j                                                   */\n        /* z7j = y7j -(y1j >> 2)                                            */\n        /*------------------------------------------------------------------*/\n        i_z0 = i_y0 + i_y6;\n        i_z1 = i_y1 + (i_y7 >> 2);\n        i_z2 = i_y2 + i_y4;\n        i_z3 = i_y3 + (i_y5 >> 2);\n        i_z4 = i_y2 - i_y4;\n        i_z5 = (i_y3 >> 2) - i_y5;\n        i_z6 = i_y0 - i_y6;\n        i_z7 = i_y7 - (i_y1 >> 2);\n\n        /*------------------------------------------------------------------*/\n        /* x0j = z0j + z7j                                                  */\n        /* x1j = z2j + z5j                                                  */\n        /* x2j = z4j + z3j                                                  */\n        /* x3j = z6j + z1j                                                  */\n        /* x4j = z6j -z1j                                                   */\n        /* x5j = z4j -z3j                                                   */\n        /* x6j = z2j -z5j                                                   */\n        /* x7j = z0j -z7j                                                   */\n        /*------------------------------------------------------------------*/\n        i_macro = ((i_z0 + i_z7 + 32) >> 6) + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        /* Change uc_recBuffer to Point to next element in the same column*/\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = ((i_z2 + i_z5 + 32) >> 6) + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = ((i_z4 + i_z3 + 32) >> 6) + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = ((i_z6 + i_z1 + 32) >> 6) + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = ((i_z6 - i_z1 + 32) >> 6) + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = ((i_z4 - i_z3 + 32) >> 6) + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = ((i_z2 - i_z5 + 32) >> 6) + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = ((i_z0 - i_z7 + 32) >> 6) + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n\n        pi2_tmp_ptr++;\n        pu1_out_ptr++;\n        pu1_pred++;\n    }\n}\n\nvoid ih264_iquant_itrans_recon_8x8_dc(WORD16 *pi2_src,\n                                      UWORD8 *pu1_pred,\n                                      UWORD8 *pu1_out,\n                                      WORD32 pred_strd,\n                                      WORD32 out_strd,\n                                      const UWORD16 *pu2_iscale_mat,\n                                      const UWORD16 *pu2_weigh_mat,\n                                      UWORD32 qp_div,\n                                      WORD16 *pi2_tmp,\n                                      WORD32 iq_start_idx,\n                                      WORD16 *pi2_dc_ld_addr)\n{\n    UWORD8 *pu1_pred_ptr = pu1_pred;\n    UWORD8 *pu1_out_ptr = pu1_out;\n    WORD16 x, i, i_macro;\n    WORD32 q;\n    WORD32 rnd_fact = (qp_div < 6) ? (1 << (5 - qp_div)) : 0;\n    UNUSED(pi2_tmp);\n    UNUSED(iq_start_idx);\n    UNUSED(pi2_dc_ld_addr);\n    /*************************************************************/\n    /* Dequantization of coefficients. Will be replaced by SIMD  */\n    /* operations on platform. Note : DC coeff is not scaled     */\n    /*************************************************************/\n    q = pi2_src[0];\n    INV_QUANT(q, pu2_iscale_mat[0], pu2_weigh_mat[0], qp_div, rnd_fact, 6);\n    i_macro = (q + 32) >> 6;\n    /* Perform Inverse transform */\n    /*--------------------------------------------------------------------*/\n    /* IDCT [ Horizontal transformation ]                                 */\n    /*--------------------------------------------------------------------*/\n    /*--------------------------------------------------------------------*/\n    /* IDCT [ Vertical transformation] and Xij = (xij + 32)>>6            */\n    /*                                                                    */\n    /* Add the prediction and store it back to reconstructed frame buffer */\n    /* [Prediction buffer itself in this case]                            */\n    /*--------------------------------------------------------------------*/\n    for(i = 0; i < SUB_BLK_WIDTH_8x8; i++)\n    {\n        pu1_pred_ptr = pu1_pred;\n        pu1_out = pu1_out_ptr;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        /* Change uc_recBuffer to Point to next element in the same column*/\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n\n        pu1_out_ptr++;\n        pu1_pred++;\n    }\n}\n\n/*\n ********************************************************************************\n *\n * @brief This function reconstructs a 4x4 sub block from quantized resiude and\n * prediction buffer\n *\n * @par Description:\n *  The quantized residue is first inverse quantized, then inverse transformed.\n *  This inverse transformed content is added to the prediction buffer to recon-\n *  struct the end output\n *\n * @param[in] pi2_src\n *  quantized 4x4 block\n *\n * @param[in] pu1_pred\n *  prediction 4x4 block\n *\n * @param[out] pu1_out\n *  reconstructed 4x4 block\n *\n * @param[in] src_strd\n *  quantization buffer stride\n *\n * @param[in] pred_strd,\n *  Prediction buffer stride\n *\n * @param[in] out_strd\n *  recon buffer Stride\n *\n * @param[in] pu2_scaling_list\n *  pointer to scaling list\n *\n * @param[in] pu2_norm_adjust\n *  pointer to inverse scale matrix\n *\n * @param[in] u4_qp_div_6\n *  Floor (qp/6)\n *\n * @param[in] pi4_tmp\n * temporary buffer of size 1*16\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nvoid ih264_iquant_itrans_recon_chroma_4x4(WORD16 *pi2_src,\n                                          UWORD8 *pu1_pred,\n                                          UWORD8 *pu1_out,\n                                          WORD32 pred_strd,\n                                          WORD32 out_strd,\n                                          const UWORD16 *pu2_iscal_mat,\n                                          const UWORD16 *pu2_weigh_mat,\n                                          UWORD32 u4_qp_div_6,\n                                          WORD16 *pi2_tmp,\n                                          WORD16 *pi2_dc_src)\n{\n    WORD16 *pi2_src_ptr = pi2_src;\n    WORD16 *pi2_tmp_ptr = pi2_tmp;\n    UWORD8 *pu1_pred_ptr = pu1_pred;\n    UWORD8 *pu1_out_ptr = pu1_out;\n    WORD16 x0, x1, x2, x3, i;\n    WORD32 q0, q1, q2, q3;\n    WORD16 i_macro;\n    WORD16 rnd_fact = (u4_qp_div_6 < 4) ? 1 << (3 - u4_qp_div_6) : 0;\n\n    /* inverse quant */\n    /*horizontal inverse transform */\n    for(i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n      if(i==0)\n      {\n        q0 = pi2_dc_src[0];\n      }\n      else\n      {\n        q0 = pi2_src_ptr[0];\n        INV_QUANT(q0, pu2_iscal_mat[0], pu2_weigh_mat[0], u4_qp_div_6, rnd_fact, 4);\n      }\n\n      q2 = pi2_src_ptr[2];\n      INV_QUANT(q2, pu2_iscal_mat[2], pu2_weigh_mat[2], u4_qp_div_6, rnd_fact,\n                4);\n\n      x0 = q0 + q2;\n      x1 = q0 - q2;\n\n      q1 = pi2_src_ptr[1];\n      INV_QUANT(q1, pu2_iscal_mat[1], pu2_weigh_mat[1], u4_qp_div_6, rnd_fact,\n                4);\n\n      q3 = pi2_src_ptr[3];\n      INV_QUANT(q3, pu2_iscal_mat[3], pu2_weigh_mat[3], u4_qp_div_6, rnd_fact,\n                4);\n\n      x2 = (q1 >> 1) - q3;\n      x3 = q1 + (q3 >> 1);\n\n      pi2_tmp_ptr[0] = x0 + x3;\n      pi2_tmp_ptr[1] = x1 + x2;\n      pi2_tmp_ptr[2] = x1 - x2;\n      pi2_tmp_ptr[3] = x0 - x3;\n\n      pi2_src_ptr += SUB_BLK_WIDTH_4x4;\n      pi2_tmp_ptr += SUB_BLK_WIDTH_4x4;\n      pu2_iscal_mat += SUB_BLK_WIDTH_4x4;\n      pu2_weigh_mat += SUB_BLK_WIDTH_4x4;\n    }\n\n    /* vertical inverse transform */\n    pi2_tmp_ptr = pi2_tmp;\n    for(i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        pu1_pred_ptr = pu1_pred;\n        pu1_out = pu1_out_ptr;\n\n        x0 = (pi2_tmp_ptr[0] + pi2_tmp_ptr[8]);\n        x1 = (pi2_tmp_ptr[0] - pi2_tmp_ptr[8]);\n        x2 = (pi2_tmp_ptr[4] >> 1) - pi2_tmp_ptr[12];\n        x3 =  pi2_tmp_ptr[4] + (pi2_tmp_ptr[12] >> 1);\n\n        /* inverse prediction */\n        i_macro = x0 + x3;\n        i_macro = ((i_macro + 32) >> 6);\n        i_macro += *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = x1 + x2;\n        i_macro = ((i_macro + 32) >> 6);\n        i_macro += *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = x1 - x2;\n        i_macro = ((i_macro + 32) >> 6);\n        i_macro += *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        i_macro = x0 - x3;\n        i_macro = ((i_macro + 32) >> 6);\n        i_macro += *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(i_macro);\n\n        pi2_tmp_ptr++;\n        pu1_out_ptr+= 2;    //Interleaved store for output\n        pu1_pred+= 2;       //Interleaved load for pred buffer\n    }\n}\n\n/*\n ********************************************************************************\n *\n * @brief This function reconstructs a 4x4 sub block from quantized resiude and\n * prediction buffer if only dc value is present for residue\n *\n * @par Description:\n *  The quantized residue is first inverse quantized,\n *  This inverse quantized content is added to the prediction buffer to recon-\n *  struct the end output\n *\n * @param[in] pi2_src\n *  quantized dc coefficient\n *\n * @param[in] pu1_pred\n *  prediction 4x4 block in interleaved format\n *\n * @param[in] pred_strd,\n *  Prediction buffer stride in interleaved format\n *\n * @param[in] out_strd\n *  recon buffer Stride\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\n\nvoid ih264_iquant_itrans_recon_chroma_4x4_dc(WORD16 *pi2_src,\n                                             UWORD8 *pu1_pred,\n                                             UWORD8 *pu1_out,\n                                             WORD32 pred_strd,\n                                             WORD32 out_strd,\n                                             const UWORD16 *pu2_iscal_mat,\n                                             const UWORD16 *pu2_weigh_mat,\n                                             UWORD32 u4_qp_div_6,\n                                             WORD16 *pi2_tmp,\n                                             WORD16 *pi2_dc_src)\n{\n    UWORD8 *pu1_pred_ptr = pu1_pred;\n    UWORD8 *pu1_out_ptr = pu1_out;\n    WORD32 q0;\n    WORD16 x, i_macro, i;\n    UNUSED(pi2_src);\n    UNUSED(pu2_iscal_mat);\n    UNUSED(pu2_weigh_mat);\n    UNUSED(u4_qp_div_6);\n    UNUSED(pi2_tmp);\n\n    q0 = pi2_dc_src[0];    // Restoring dc value for intra case3\n    i_macro = ((q0 + 32) >> 6);\n\n    for(i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        pu1_pred_ptr = pu1_pred;\n        pu1_out = pu1_out_ptr;\n\n        /* inverse prediction */\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out =  CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n        pu1_pred_ptr += pred_strd;\n        pu1_out += out_strd;\n\n        x = i_macro + *pu1_pred_ptr;\n        *pu1_out = CLIP_U8(x);\n\n        pu1_out_ptr+=2;\n        pu1_pred+=2;\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_list.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_list.c\n*\n* @brief\n*  Contains functions for buf queue\n*\n* @author\n*  Harish\n*\n* @par List of Functions:\n*  ih264_list_size()\n*  ih264_list_lock()\n*  ih264_list_unlock()\n*  ih264_list_yield()\n*  ih264_list_free()\n*  ih264_list_init()\n*  ih264_list_reset()\n*  ih264_list_deinit()\n*  ih264_list_terminate()\n*  ih264_list_queue()\n*  ih264_list_dequeue()\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"ih264_typedefs.h\"\n#include \"ithread.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_debug.h\"\n#include \"ih264_error.h\"\n#include \"ih264_list.h\"\n\n/**\n*******************************************************************************\n*\n* @brief Returns size for buf queue context. Does not include buf queue buffer\n* requirements\n*\n* @par   Description\n* Returns size for buf queue context. Does not include buf queue buffer\n* requirements. Buffer size required to store the bufs should be allocated in\n* addition to the value returned here.\n*\n* @returns Size of the buf queue context\n*\n* @remarks\n*\n*******************************************************************************\n*/\nWORD32 ih264_list_size(WORD32 num_entries, WORD32 entry_size)\n{\n    WORD32 size;\n    WORD32 clz;\n    size = sizeof(list_t);\n    size += ithread_get_mutex_lock_size();\n\n    /* Use next power of two number of entries*/\n    clz = CLZ(num_entries);\n    num_entries = 1 << (32 - clz);\n\n    size  += num_entries * entry_size;\n    return size;\n}\n\n/**\n*******************************************************************************\n*\n* @brief\n*   Locks the list context\n*\n* @par   Description\n*   Locks the list context by calling ithread_mutex_lock()\n*\n* @param[in] ps_list\n*   Job Queue context\n*\n* @returns IH264_FAIL if mutex lock fails else IH264_SUCCESS\n*\n* @remarks\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_list_lock(list_t *ps_list)\n{\n    WORD32 retval;\n    retval = ithread_mutex_lock(ps_list->pv_mutex);\n    if(retval)\n    {\n        return IH264_FAIL;\n    }\n    return IH264_SUCCESS;\n}\n\n/**\n*******************************************************************************\n*\n* @brief\n*   Unlocks the list context\n*\n* @par   Description\n*   Unlocks the list context by calling ithread_mutex_unlock()\n*\n* @param[in] ps_list\n*   Job Queue context\n*\n* @returns IH264_FAIL if mutex unlock fails else IH264_SUCCESS\n*\n* @remarks\n*\n*******************************************************************************\n*/\n\nIH264_ERROR_T ih264_list_unlock(list_t *ps_list)\n{\n    WORD32 retval;\n    retval = ithread_mutex_unlock(ps_list->pv_mutex);\n    if(retval)\n    {\n        return IH264_FAIL;\n    }\n    return IH264_SUCCESS;\n\n}\n/**\n*******************************************************************************\n*\n* @brief\n*   Yields the thread\n*\n* @par   Description\n*   Unlocks the list context by calling\n* ih264_list_unlock(), ithread_yield() and then ih264_list_lock()\n* list is unlocked before to ensure the list can be accessed by other threads\n* If unlock is not done before calling yield then no other thread can access\n* the list functions and update list.\n*\n* @param[in] ps_list\n*   Job Queue context\n*\n* @returns IH264_FAIL if mutex lock unlock or yield fails else IH264_SUCCESS\n*\n* @remarks\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_list_yield(list_t *ps_list)\n{\n\n    IH264_ERROR_T ret = IH264_SUCCESS;\n\n    IH264_ERROR_T rettmp;\n    rettmp = ih264_list_unlock(ps_list);\n    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);\n\n    ithread_yield();\n\n    if(ps_list->i4_yeild_interval_us > 0)\n        ithread_usleep(ps_list->i4_yeild_interval_us);\n\n    rettmp = ih264_list_lock(ps_list);\n    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);\n    return ret;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief free the buf queue pointers\n*\n* @par   Description\n* Frees the list context\n*\n* @param[in] pv_buf\n* Memory for buf queue buffer and buf queue context\n*\n* @returns Pointer to buf queue context\n*\n* @remarks\n* Since it will be called only once by master thread this is not thread safe.\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_list_free(list_t *ps_list)\n{\n    WORD32 ret;\n    ret = ithread_mutex_destroy(ps_list->pv_mutex);\n\n    if(0 == ret)\n        return IH264_SUCCESS;\n    else\n        return IH264_FAIL;\n}\n\n/**\n*******************************************************************************\n*\n* @brief Initialize the buf queue\n*\n* @par   Description\n* Initializes the list context and sets write and read pointers to start of\n* buf queue buffer\n*\n* @param[in] pv_buf\n* Memoy for buf queue buffer and buf queue context\n*\n* @param[in] buf_size\n* Size of the total memory allocated\n*\n* @returns Pointer to buf queue context\n*\n* @remarks\n* Since it will be called only once by master thread this is not thread safe.\n*\n*******************************************************************************\n*/\nvoid* ih264_list_init(void *pv_buf,\n                      WORD32 buf_size,\n                      WORD32 num_entries,\n                      WORD32 entry_size,\n                      WORD32 yeild_interval_us)\n{\n    list_t *ps_list;\n    UWORD8 *pu1_buf;\n\n    pu1_buf = (UWORD8 *)pv_buf;\n\n    ps_list = (list_t *)pu1_buf;\n    pu1_buf += sizeof(list_t);\n    buf_size -= sizeof(list_t);\n\n    ps_list->pv_mutex = pu1_buf;\n    pu1_buf += ithread_get_mutex_lock_size();\n    buf_size -= ithread_get_mutex_lock_size();\n\n    if (buf_size <= 0)\n      return NULL;\n\n    ithread_mutex_init(ps_list->pv_mutex);\n\n    /* Ensure num_entries is power of two */\n    ASSERT(0 == (num_entries & (num_entries - 1)));\n\n    /* Ensure remaining buffer is large enough to hold given number of entries */\n    ASSERT((num_entries * entry_size) <= buf_size);\n\n    ps_list->pv_buf_base = pu1_buf;\n    ps_list->i4_terminate = 0;\n    ps_list->i4_entry_size = entry_size;\n    ps_list->i4_buf_rd_idx = 0;\n    ps_list->i4_buf_wr_idx = 0;\n    ps_list->i4_log2_buf_max_idx = 32 - CLZ(num_entries);\n    ps_list->i4_buf_max_idx = num_entries;\n    ps_list->i4_yeild_interval_us = yeild_interval_us;\n\n    return ps_list;\n}\n/**\n*******************************************************************************\n*\n* @brief\n*   Resets the list context\n*\n* @par   Description\n*   Resets the list context by initializing buf queue context elements\n*\n* @param[in] ps_list\n*   Job Queue context\n*\n* @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS\n*\n* @remarks\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_list_reset(list_t *ps_list)\n{\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    ret = ih264_list_lock(ps_list);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    ps_list->i4_terminate  = 0;\n    ps_list->i4_buf_rd_idx = 0;\n    ps_list->i4_buf_wr_idx = 0;\n\n    ret = ih264_list_unlock(ps_list);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    return ret;\n}\n\n/**\n*******************************************************************************\n*\n* @brief\n*   Deinitializes the list context\n*\n* @par   Description\n*   Deinitializes the list context by calling ih264_list_reset()\n* and then destrying the mutex created\n*\n* @param[in] ps_list\n*   Job Queue context\n*\n* @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS\n*\n* @remarks\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_list_deinit(list_t *ps_list)\n{\n    WORD32 retval;\n    IH264_ERROR_T ret = IH264_SUCCESS;\n\n    ret = ih264_list_reset(ps_list);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    retval = ithread_mutex_destroy(ps_list->pv_mutex);\n    if(retval)\n    {\n        return IH264_FAIL;\n    }\n\n    return IH264_SUCCESS;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*   Terminates the list\n*\n* @par   Description\n*   Terminates the list by setting a flag in context.\n*\n* @param[in] ps_list\n*   Job Queue context\n*\n* @returns IH264_FAIL if lock unlock fails else IH264_SUCCESS\n*\n* @remarks\n*\n*******************************************************************************\n*/\n\nIH264_ERROR_T ih264_list_terminate(list_t *ps_list)\n{\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    ret = ih264_list_lock(ps_list);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n\n    ps_list->i4_terminate = 1;\n\n    ret = ih264_list_unlock(ps_list);\n    RETURN_IF((ret != IH264_SUCCESS), ret);\n    return ret;\n}\n\n\n/**\n*******************************************************************************\n*\n* @brief Adds a buf to the queue\n*\n* @par   Description\n* Adds a buf to the queue and updates wr address to next location.\n* Format/content of the buf structure is abstracted and hence size of the buf\n* buffer is being passed.\n*\n* @param[in] ps_list\n*   Job Queue context\n*\n* @param[in] pv_buf\n*   Pointer to the location that contains details of the buf to be added\n*\n* @param[in] buf_size\n*   Size of the buf buffer\n*\n* @param[in] blocking\n*   To signal if the write is blocking or non-blocking.\n*\n* @returns\n*\n* @remarks\n* Job Queue buffer is assumed to be allocated to handle worst case number of bufs\n* Wrap around is not supported\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_list_queue(list_t *ps_list, void *pv_buf, WORD32 blocking)\n{\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    IH264_ERROR_T rettmp;\n\n    WORD32 diff;\n    void *pv_buf_wr;\n\n    volatile WORD32 *pi4_wr_idx, *pi4_rd_idx;\n    WORD32 buf_size = ps_list->i4_entry_size;\n\n\n    rettmp = ih264_list_lock(ps_list);\n    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);\n\n\n\n    while(1)\n    {\n        /* Ensure wr idx does not go beyond rd idx by more than number of entries\n         */\n        pi4_wr_idx = &ps_list->i4_buf_wr_idx;\n        pi4_rd_idx = &ps_list->i4_buf_rd_idx;\n        diff = *pi4_wr_idx - *pi4_rd_idx;\n\n        if(diff < ps_list->i4_buf_max_idx)\n        {\n            WORD32 wr_idx;\n            wr_idx = ps_list->i4_buf_wr_idx & (ps_list->i4_buf_max_idx - 1);\n            pv_buf_wr = (UWORD8 *)ps_list->pv_buf_base + wr_idx * buf_size;\n\n            memcpy(pv_buf_wr, pv_buf, buf_size);\n            ps_list->i4_buf_wr_idx++;\n            break;\n        }\n        else\n        {\n            /* wr is ahead, so wait for rd to consume */\n            if(blocking)\n            {\n                ih264_list_yield(ps_list);\n            }\n            else\n            {\n                ret = IH264_FAIL;\n                break;\n            }\n        }\n\n    }\n    ps_list->i4_terminate = 0;\n\n    rettmp = ih264_list_unlock(ps_list);\n    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);\n\n    return ret;\n}\n/**\n*******************************************************************************\n*\n* @brief Gets next from the Job queue\n*\n* @par   Description\n* Gets next buf from the buf queue and updates rd address to next location.\n* Format/content of the buf structure is abstracted and hence size of the buf\n* buffer is being passed. If it is a blocking call and if there is no new buf\n* then this functions unlocks the mutex and calls yield and then locks it back.\n* and continues till a buf is available or terminate is set\n*\n* @param[in] ps_list\n*   Job Queue context\n*\n* @param[out] pv_buf\n*   Pointer to the location that contains details of the buf to be written\n*\n* @param[in] buf_size\n*   Size of the buf buffer\n*\n* @param[in] blocking\n*   To signal if the read is blocking or non-blocking.\n*\n* @returns\n*\n* @remarks\n* Job Queue buffer is assumed to be allocated to handle worst case number of bufs\n* Wrap around is not supported\n*\n*******************************************************************************\n*/\nIH264_ERROR_T ih264_list_dequeue(list_t *ps_list, void *pv_buf, WORD32 blocking)\n{\n    IH264_ERROR_T ret = IH264_SUCCESS;\n    IH264_ERROR_T rettmp;\n    WORD32 buf_size = ps_list->i4_entry_size;\n    WORD32 diff;\n\n    void *pv_buf_rd;\n    volatile WORD32 *pi4_wr_idx, *pi4_rd_idx;\n\n    rettmp = ih264_list_lock(ps_list);\n    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);\n\n    while(1)\n    {\n        /* Ensure wr idx is ahead of rd idx and\n         * wr idx does not go beyond rd idx by more than number of entries\n         */\n        pi4_wr_idx = &ps_list->i4_buf_wr_idx;\n        pi4_rd_idx = &ps_list->i4_buf_rd_idx;\n        diff = *pi4_wr_idx - *pi4_rd_idx;\n\n\n        if(diff > 0)\n        {\n            WORD32 rd_idx;\n            rd_idx = ps_list->i4_buf_rd_idx & (ps_list->i4_buf_max_idx - 1);\n            pv_buf_rd = (UWORD8 *)ps_list->pv_buf_base + rd_idx * buf_size;\n\n            memcpy(pv_buf, pv_buf_rd, buf_size);\n            ps_list->i4_buf_rd_idx++;\n            break;\n        }\n        else\n        {\n            /* If terminate is signaled then break */\n            if(ps_list->i4_terminate)\n            {\n                ret = IH264_FAIL;\n                break;\n            }\n            /* wr is ahead, so wait for rd to consume */\n            if(blocking)\n            {\n                ih264_list_yield(ps_list);\n            }\n            else\n            {\n                ret = IH264_FAIL;\n                break;\n            }\n        }\n\n    }\n\n\n    rettmp = ih264_list_unlock(ps_list);\n    RETURN_IF((rettmp != IH264_SUCCESS), rettmp);\n\n    return ret;\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_list.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_list.h\n*\n* @brief\n*  Contains functions for buf queue\n*\n* @author\n*  Harish\n*\n* @par List of Functions:\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n#ifndef _IH264_LIST_H_\n#define _IH264_LIST_H_\n\ntypedef struct\n{\n    /** Pointer to buffer base which contains the bufs */\n    void *pv_buf_base;\n\n    /** Mutex used to keep the functions thread-safe */\n    void *pv_mutex;\n\n    /** Current write index */\n    volatile WORD32 i4_buf_wr_idx;\n\n    /** Current read index */\n    volatile WORD32 i4_buf_rd_idx;\n\n    /** Maximum index */\n    WORD32 i4_buf_max_idx;\n\n    /** Log2(buf_max_idx) -\n     * To ensure number of entries is power of two\n     * This makes it easier to wrap around by using AND with buf_max_idx - 1\n     * */\n    WORD32 i4_log2_buf_max_idx;\n\n    /** Flag to indicate list has to be terminated */\n    WORD32 i4_terminate;\n\n    /** Size of each entry */\n    WORD32 i4_entry_size;\n\n    /** If the list is to be used frequently send this as zero, else send a large value\n     * to ensure cores are not loaded unnecessarily.\n     * For eg: For picture level queues this can be a large value like 100us\n     * but for jobq this will be zero.\n     */\n    WORD32 i4_yeild_interval_us;\n\n}list_t;\n\nWORD32 ih264_list_size(WORD32 num_entries, WORD32 entry_size);\nvoid* ih264_list_init(void *pv_buf,\n                      WORD32 buf_size,\n                      WORD32 num_entries,\n                      WORD32 entry_size,\n                      WORD32 yeild_interval_us);\nIH264_ERROR_T ih264_list_free(list_t *ps_list);\nIH264_ERROR_T ih264_list_reset(list_t *ps_list);\nIH264_ERROR_T ih264_list_deinit(list_t *ps_list);\nIH264_ERROR_T ih264_list_terminate(list_t *ps_list);\nIH264_ERROR_T ih264_list_queue(list_t *ps_list, void *pv_buf, WORD32 blocking);\nIH264_ERROR_T ih264_list_dequeue(list_t *ps_list, void *pv_buf, WORD32 blocking);\n\n#endif /* _IH264_PROCESS_SLICE_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_luma_intra_pred_filters.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_luma_intra_pred_filters.c\n *\n * @brief\n *  Contains function definitions for intra prediction  filters\n *\n * @author\n *  Ittiam\n *\n * @par List of Functions:\n *  - ih264_intra_pred_luma_4x4_mode_vert\n *  - ih264_intra_pred_luma_4x4_mode_horz\n *  - ih264_intra_pred_luma_4x4_mode_dc\n *  - ih264_intra_pred_luma_4x4_mode_diag_dl\n *  - ih264_intra_pred_luma_4x4_mode_diag_dr\n *  - ih264_intra_pred_luma_4x4_mode_vert_r\n *  - ih264_intra_pred_luma_4x4_mode_horz_d\n *  - ih264_intra_pred_luma_4x4_mode_vert_l\n *  - ih264_intra_pred_luma_4x4_mode_horz_u\n *  - ih264_intra_pred_luma_8x8_mode_ref_filtering\n *  - ih264_intra_pred_luma_8x8_mode_vert\n *  - ih264_intra_pred_luma_8x8_mode_horz\n *  - ih264_intra_pred_luma_8x8_mode_dc\n *  - ih264_intra_pred_luma_8x8_mode_diag_dl\n *  - ih264_intra_pred_luma_8x8_mode_diag_dr\n *  - ih264_intra_pred_luma_8x8_mode_vert_r\n *  - ih264_intra_pred_luma_8x8_mode_horz_d\n *  - ih264_intra_pred_luma_8x8_mode_vert_l\n *  - ih264_intra_pred_luma_8x8_mode_horz_u\n *  - ih264_intra_pred_luma_16x16_mode_vert\n *  - ih264_intra_pred_luma_16x16_mode_horz\n *  - ih264_intra_pred_luma_16x16_mode_dc\n *  - ih264_intra_pred_luma_16x16_mode_plane\n *\n *\n * @remarks\n *  None\n *\n ******************************************************************************\n */\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n/* System include files */\n#include <stdio.h>\n#include <stddef.h>\n#include <string.h>\n\n/* User include files */\n#include \"ih264_defs.h\"\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_intra_pred_filters.h\"\n\n/* Global variables used only in assembly files*/\nconst WORD8 ih264_gai1_intrapred_luma_plane_coeffs[] =\n{ 0x01, 0x02, 0x03, 0x04,\n  0x05, 0x06, 0x07, 0x08,\n  0x09, 0x0A, 0x0B, 0x0C,\n  0x0D, 0x0E, 0x0F, 0x10, };\n\nconst WORD8  ih264_gai1_intrapred_luma_8x8_horz_u[] =\n{ 0x06,0x15,0x05,0x14,\n  0x04,0x13,0x03,0x12,\n  0x02,0x11,0x01,0x10,\n  0x00,0x1F,0x0F,0x0F\n};\n\n/*******************    LUMA INTRAPREDICTION    *******************/\n\n/*******************    4x4 Modes    *******************/\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_4x4_mode_vert\n *\n * @brief\n *  Perform Intra prediction for  luma_4x4 mode:vertical\n *\n * @par Description:\n * Perform Intra prediction for  luma_4x4 mode:vertical ,described in sec 8.3.1.2.1\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nvoid ih264_intra_pred_luma_4x4_mode_vert(UWORD8 *pu1_src,\n                                         UWORD8 *pu1_dst,\n                                         WORD32 src_strd,\n                                         WORD32 dst_strd,\n                                         WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK_SIZE + 1;\n\n    memcpy(pu1_dst, pu1_top, 4);\n    memcpy(pu1_dst + dst_strd, pu1_top, 4);\n    memcpy(pu1_dst + 2 * dst_strd, pu1_top, 4);\n    memcpy(pu1_dst + 3 * dst_strd, pu1_top, 4);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_4x4_mode_horz\n *\n * @brief\n *  Perform Intra prediction for  luma_4x4 mode:horizontal\n *\n * @par Description:\n *  Perform Intra prediction for  luma_4x4 mode:horizontal ,described in sec 8.3.1.2.2\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nvoid ih264_intra_pred_luma_4x4_mode_horz(UWORD8 *pu1_src,\n                                         UWORD8 *pu1_dst,\n                                         WORD32 src_strd,\n                                         WORD32 dst_strd,\n                                         WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_left = pu1_src + BLK_SIZE - 1;\n\n    memset(pu1_dst, *pu1_left, 4);\n    memset(pu1_dst + dst_strd, *(pu1_left - 1), 4);\n    memset(pu1_dst + 2 * dst_strd, *(pu1_left - 2), 4);\n    memset(pu1_dst + 3 * dst_strd, *(pu1_left - 3), 4);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_4x4_mode_dc\n *\n * @brief\n *  Perform Intra prediction for  luma_4x4 mode:DC\n *\n * @par Description:\n *  Perform Intra prediction for  luma_4x4 mode:DC ,described in sec 8.3.1.2.3\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n *  availability of neighbouring pixels\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_4x4_mode_dc(UWORD8 *pu1_src,\n                                       UWORD8 *pu1_dst,\n                                       WORD32 src_strd,\n                                       WORD32 dst_strd,\n                                       WORD32 ngbr_avail)\n{\n    UWORD8 u1_useleft; /* availability of left predictors (only for DC) */\n    UWORD8 u1_usetop; /* availability of top predictors (only for DC) */\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    WORD32 val = 0;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    u1_useleft = BOOLEAN(ngbr_avail & LEFT_MB_AVAILABLE_MASK);\n    u1_usetop = BOOLEAN(ngbr_avail & TOP_MB_AVAILABLE_MASK);\n    pu1_top = pu1_src + BLK_SIZE + 1;\n    pu1_left = pu1_src + BLK_SIZE - 1;\n\n    if(u1_useleft)\n    {\n        val += *pu1_left--;\n        val += *pu1_left--;\n        val += *pu1_left--;\n        val += *pu1_left + 2;\n    }\n    if(u1_usetop)\n    {\n        val += *pu1_top + *(pu1_top + 1) + *(pu1_top + 2) + *(pu1_top + 3)\n                        + 2;\n    }\n    /* Since 2 is added if either left/top pred is there,\n     val still being zero implies both preds are not there */\n    val = (val) ? (val >> (1 + u1_useleft + u1_usetop)) : 128;\n\n    /* 4 bytes are copied from src to dst */\n    memset(pu1_dst, val, 4);\n    memset(pu1_dst + dst_strd, val, 4);\n    memset(pu1_dst + 2 * dst_strd, val, 4);\n    memset(pu1_dst + 3 * dst_strd, val, 4);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_4x4_mode_diag_dl\n *\n * @brief\n *     Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Left\n *\n * @par Description:\n *    Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Left ,described in sec 8.3.1.2.4\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_4x4_mode_diag_dl(UWORD8 *pu1_src,\n                                            UWORD8 *pu1_dst,\n                                            WORD32 src_strd,\n                                            WORD32 dst_strd,\n                                            WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD32 ui4_a, ui4_b, ui4_c, ui4_d, ui4_e, ui4_f, ui4_g, ui4_h;\n    UWORD8 predicted_pixels[7];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src +BLK_SIZE + 1;\n\n    ui4_a = *pu1_top++;\n    ui4_b = *pu1_top++;\n    ui4_c = *pu1_top++;\n    ui4_d = *pu1_top++;\n    ui4_e = *pu1_top++;\n    ui4_f = *pu1_top++;\n    ui4_g = *pu1_top++;\n    ui4_h = *pu1_top;\n\n    predicted_pixels[0] = FILT121(ui4_a, ui4_b, ui4_c);\n    predicted_pixels[1] = FILT121(ui4_b, ui4_c, ui4_d);\n    predicted_pixels[2] = FILT121(ui4_c, ui4_d, ui4_e);\n    predicted_pixels[3] = FILT121(ui4_d, ui4_e, ui4_f);\n    predicted_pixels[4] = FILT121(ui4_e, ui4_f, ui4_g);\n    predicted_pixels[5] = FILT121(ui4_f, ui4_g, ui4_h);\n    predicted_pixels[6] = FILT121(ui4_g, ui4_h, ui4_h);\n\n    memcpy(pu1_dst, predicted_pixels, 4);\n    memcpy(pu1_dst + dst_strd, predicted_pixels + 1, 4);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 2, 4);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels + 3, 4);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_4x4_mode_diag_dr\n *\n * @brief\n *     Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Right\n *\n * @par Description:\n *    Perform Intra prediction for  luma_4x4 mode:Diagonal_Down_Right ,described in sec 8.3.1.2.5\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_4x4_mode_diag_dr(UWORD8 *pu1_src,\n                                            UWORD8 *pu1_dst,\n                                            WORD32 src_strd,\n                                            WORD32 dst_strd,\n                                            WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_topleft = NULL;/* Pointer to top left predictor */\n    UWORD32 ui4_a, ui4_b, ui4_c, ui4_d, ui4_i, ui4_j, ui4_k, ui4_l, ui4_m;\n    UWORD8 predicted_pixels[7];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK_SIZE + 1;\n    pu1_left = pu1_src + BLK_SIZE - 1;\n    pu1_topleft = pu1_src +BLK_SIZE;\n\n    ui4_a = *pu1_top++;\n    ui4_b = *pu1_top++;\n    ui4_c = *pu1_top++;\n    ui4_d = *pu1_top++;\n    ui4_i = *pu1_left--;\n    ui4_j = *pu1_left--;\n    ui4_k = *pu1_left--;\n    ui4_l = *pu1_left;\n    ui4_m = *pu1_topleft;\n\n    predicted_pixels[2] = FILT121(ui4_j, ui4_i, ui4_m);\n    predicted_pixels[1] = FILT121(ui4_k, ui4_j, ui4_i);\n    predicted_pixels[0] = FILT121(ui4_l, ui4_k, ui4_j);\n    predicted_pixels[3] = FILT121(ui4_i, ui4_m, ui4_a);\n    predicted_pixels[4] = FILT121(ui4_m, ui4_a, ui4_b);\n    predicted_pixels[5] = FILT121(ui4_a, ui4_b, ui4_c);\n    predicted_pixels[6] = FILT121(ui4_b, ui4_c, ui4_d);\n\n    memcpy(pu1_dst, predicted_pixels + 3, 4);\n    memcpy(pu1_dst + dst_strd, predicted_pixels + 2, 4);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 1, 4);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels, 4);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_4x4_mode_vert_r\n *\n * @brief\n *     Perform Intra prediction for  luma_4x4 mode:Vertical_Right\n *\n * @par Description:\n *    Perform Intra prediction for  luma_4x4 mode:Vertical_Right ,described in sec 8.3.1.2.6\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_4x4_mode_vert_r(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n\n    UWORD32 ui4_a, ui4_b, ui4_c, ui4_d, ui4_i, ui4_j, ui4_k, ui4_m;\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_topleft = NULL;/* Pointer to top left predictor */\n    UWORD8 predicted_pixels[10];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src +BLK_SIZE + 1;\n    pu1_left = pu1_src + BLK_SIZE - 1;\n    pu1_topleft = pu1_src + BLK_SIZE;\n\n    ui4_a = *pu1_top++;\n    ui4_b = *pu1_top++;\n    ui4_c = *pu1_top++;\n    ui4_d = *pu1_top++;\n    ui4_i = *pu1_left--;\n    ui4_j = *pu1_left--;\n    ui4_k = *pu1_left;\n    ui4_m = *pu1_topleft;\n\n    predicted_pixels[6] = FILT11(ui4_m, ui4_a);\n    predicted_pixels[7] = FILT11(ui4_a, ui4_b);\n    predicted_pixels[8] = FILT11(ui4_b, ui4_c);\n    predicted_pixels[9] = FILT11(ui4_c, ui4_d);\n    predicted_pixels[1] = FILT121(ui4_i, ui4_m, ui4_a);\n    predicted_pixels[2] = FILT121(ui4_m, ui4_a, ui4_b);\n    predicted_pixels[3] = FILT121(ui4_a, ui4_b, ui4_c);\n    predicted_pixels[4] = FILT121(ui4_b, ui4_c, ui4_d);\n    predicted_pixels[5] = FILT121(ui4_j, ui4_i, ui4_m);\n    predicted_pixels[0] = FILT121(ui4_k, ui4_j, ui4_i);\n\n    memcpy(pu1_dst, predicted_pixels + 6, 4);\n    memcpy(pu1_dst + dst_strd, predicted_pixels + 1, 4);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 5, 4);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels, 4);\n}\n\n/*\n *******************************************************************************\n *\n *ih264_intra_pred_luma_4x4_mode_horz_d\n *\n * @brief\n *     Perform Intra prediction for  luma_4x4 mode:Horizontal_Down\n *\n * @par Description:\n *    Perform Intra prediction for  luma_4x4 mode:Horizontal_Down ,described in sec 8.3.1.2.7\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_4x4_mode_horz_d(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_topleft = NULL;/* Pointer to top left predictor */\n    UWORD32 ui4_a, ui4_b, ui4_c, ui4_i, ui4_j, ui4_k, ui4_l, ui4_m;\n    UWORD8 predicted_pixels[10];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK_SIZE + 1;\n    pu1_left = pu1_src + BLK_SIZE - 1;\n    pu1_topleft = pu1_src + BLK_SIZE;\n\n    ui4_a = *pu1_top++;\n    ui4_b = *pu1_top++;\n    ui4_c = *pu1_top++;\n    ui4_i = *pu1_left--;\n    ui4_j = *pu1_left--;\n    ui4_k = *pu1_left--;\n    ui4_l = *pu1_left--;\n    ui4_m = *pu1_topleft;\n\n    predicted_pixels[6] = FILT11(ui4_i, ui4_m);\n    predicted_pixels[7] = FILT121(ui4_i, ui4_m, ui4_a);\n    predicted_pixels[8] = FILT121(ui4_m, ui4_a, ui4_b);\n    predicted_pixels[9] = FILT121(ui4_a, ui4_b, ui4_c);\n    predicted_pixels[1] = FILT121(ui4_l, ui4_k, ui4_j);\n    predicted_pixels[2] = FILT11(ui4_k, ui4_j);\n    predicted_pixels[3] = FILT121(ui4_k, ui4_j, ui4_i);\n    predicted_pixels[4] = FILT11(ui4_j, ui4_i);\n    predicted_pixels[5] = FILT121(ui4_j, ui4_i, ui4_m);\n    predicted_pixels[0] = FILT11(ui4_l, ui4_k);\n\n    memcpy(pu1_dst, predicted_pixels + 6, 4);\n    memcpy(pu1_dst + dst_strd, predicted_pixels + 4, 4);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 2, 4);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels, 4);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_4x4_mode_vert_l\n *\n * @brief\n *     Perform Intra prediction for  luma_4x4 mode:Vertical_Left\n *\n * @par Description:\n *    Perform Intra prediction for  luma_4x4 mode:Vertical_Left ,described in sec 8.3.1.2.8\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_4x4_mode_vert_l(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD32 ui4_a, ui4_b, ui4_c, ui4_d, ui4_e, ui4_f, ui4_g;\n    UWORD8 predicted_pixels[10];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK_SIZE + 1;\n\n    ui4_a = *pu1_top++;\n    ui4_b = *pu1_top++;\n    ui4_c = *pu1_top++;\n    ui4_d = *pu1_top++;\n    ui4_e = *pu1_top++;\n    ui4_f = *pu1_top++;\n    ui4_g = *pu1_top;\n\n    predicted_pixels[5] = FILT11(ui4_a, ui4_b);\n    predicted_pixels[6] = FILT11(ui4_b, ui4_c);\n    predicted_pixels[7] = FILT11(ui4_c, ui4_d);\n    predicted_pixels[8] = FILT11(ui4_d, ui4_e);\n    predicted_pixels[0] = FILT121(ui4_a, ui4_b, ui4_c);\n    predicted_pixels[1] = FILT121(ui4_b, ui4_c, ui4_d);\n    predicted_pixels[2] = FILT121(ui4_c, ui4_d, ui4_e);\n    predicted_pixels[3] = FILT121(ui4_d, ui4_e, ui4_f);\n    predicted_pixels[9] = FILT11(ui4_e, ui4_f);\n    predicted_pixels[4] = FILT121(ui4_e, ui4_f, ui4_g);\n\n    memcpy(pu1_dst, predicted_pixels + 5, 4);\n    memcpy(pu1_dst + dst_strd, predicted_pixels, 4);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 6, 4);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels + 1, 4);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_4x4_mode_horz_u\n *\n * @brief\n *     Perform Intra prediction for  luma_4x4 mode:Horizontal_Up\n *\n * @par Description:\n *    Perform Intra prediction for  luma_4x4 mode:Horizontal_Up ,described in sec 8.3.1.2.9\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_4x4_mode_horz_u(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD32 ui4_i, ui4_j, ui4_k, ui4_l;\n    UWORD8 predicted_pixels[10];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_left = pu1_src + BLK_SIZE - 1;\n\n    ui4_i = *pu1_left--;\n    ui4_j = *pu1_left--;\n    ui4_k = *pu1_left--;\n    ui4_l = *pu1_left--;\n\n    predicted_pixels[0] = FILT11(ui4_j, ui4_i);\n    predicted_pixels[1] = FILT121(ui4_k, ui4_j, ui4_i);\n    predicted_pixels[2] = FILT11(ui4_k, ui4_j);\n    predicted_pixels[3] = FILT121(ui4_l, ui4_k, ui4_j);\n    predicted_pixels[4] = FILT11(ui4_l, ui4_k);\n    predicted_pixels[5] = FILT121(ui4_l, ui4_l, ui4_k);\n    predicted_pixels[6] = ui4_l;\n    predicted_pixels[7] = ui4_l;\n    predicted_pixels[8] = ui4_l;\n    predicted_pixels[9] = ui4_l;\n\n    memcpy(pu1_dst, predicted_pixels, 4);\n    memcpy(pu1_dst + dst_strd, predicted_pixels + 2, 4);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 4, 4);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels + 6, 4);\n}\n\n/*******************    8x8 Modes    *******************/\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_8x8_mode_ref_filtering\n *\n * @brief\n *     Reference sample filtering process for Intra_8x8 sample prediction\n *\n * @par Description:\n *    Perform Reference sample filtering process for Intra_8x8 sample prediction ,described in sec 8.3.2.2.1\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride[Not Used]\n *\n * @param[in] dst_strd\n *  integer destination stride[Not Used]\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_8x8_mode_ref_filtering(UWORD8 *pu1_left,\n                                                  UWORD8 *pu1_topleft,\n                                                  UWORD8 *pu1_top,\n                                                  UWORD8 *pu1_dst,\n                                                  WORD32 left_strd,\n                                                  WORD32 ngbr_avail)\n{\n    WORD32 top_avail, left_avail, top_left_avail, top_right_avail;\n\n    left_avail = BOOLEAN(ngbr_avail & LEFT_MB_AVAILABLE_MASK);\n    top_avail = BOOLEAN(ngbr_avail & TOP_MB_AVAILABLE_MASK);\n    top_left_avail = BOOLEAN(ngbr_avail & TOP_LEFT_MB_AVAILABLE_MASK);\n    top_right_avail = BOOLEAN(ngbr_avail & TOP_RIGHT_MB_AVAILABLE_MASK);\n\n    if(top_avail)\n    {\n        WORD32 i;\n        UWORD32 u4_xm1;\n\n        if(!top_right_avail)\n        {\n            memset(pu1_dst + 8 + 1 + 8, pu1_top[7], 8);\n            top_right_avail = 1;\n        }\n        else\n        {\n            memcpy(pu1_dst + 8 + 1 + 8, pu1_top + 8, 8);\n        }\n\n        if(top_left_avail)\n        {\n            pu1_dst[8 + 1 + 0] = FILT121((*pu1_topleft), pu1_top[0],\n                                         pu1_top[1]);\n\n        }\n        else\n        {\n            pu1_dst[8 + 1] = ((3 * pu1_top[0]) + pu1_top[1] + 2) >> 2;\n        }\n\n        for(i = 1; i <= 6; i++)\n        {\n            pu1_dst[8 + 1 + i] = FILT121(pu1_top[i - 1], pu1_top[i],\n                                         pu1_top[i + 1]);\n\n        }\n        /* First byte of Top Right input is in pu1_dst[8 + 1 + 8]*/\n        pu1_dst[8 + 1 + 7] = FILT121(pu1_top[6], pu1_top[7],\n                                     pu1_dst[8 + 1 + 8]);\n\n        /* filtered output and source in same buf, to prevent output(x - 1)\n         being over written in process */\n        u4_xm1 = pu1_top[7];\n\n        for(i = 8; i <= 14; i++)\n        {\n            UWORD32 u4_x;\n            u4_x = (u4_xm1 + (pu1_dst[8 + 1 + i] << 1) + pu1_dst[8 + 1 + i + 1]\n                            + 2) >> 2;\n            /* assigning u4_xm1 from the un-filtered values for the next iteration */\n            u4_xm1 = pu1_dst[8 + 1 + i];\n            pu1_dst[8 + 1 + i] = u4_x;\n        }\n\n        pu1_dst[8 + 1 + 15] = (u4_xm1 + (3 * pu1_dst[8 + 1 + 15]) + 2) >> 2;\n\n    }\n\n    /* pu1_topleft is overloaded. It is both: */\n    /* a. A pointer for the top left pixel */\n    /* b. An indicator of availability of top left. */\n    /*    If it is null then top left not available */\n    if(top_left_avail)\n    {\n        if((!top_avail) || (!left_avail))\n        {\n            if(top_avail)\n                pu1_dst[8] = (3 * pu1_topleft[0] + pu1_top[0] + 2) >> 2;\n            else if(left_avail)\n                pu1_dst[8] = (3 * pu1_topleft[0] + pu1_left[0] + 2) >> 2;\n        }\n        else\n        {\n            pu1_dst[8] = FILT121(pu1_top[0], (*pu1_topleft), pu1_left[0]);\n        }\n    }\n\n    if(left_avail)\n    {\n        UWORD32 idx;\n        if(0 != pu1_topleft)\n        {\n            pu1_dst[7] = FILT121((*pu1_topleft), pu1_left[0],\n                                 pu1_left[left_strd]);\n        }\n        else\n        {\n            pu1_dst[7] = ((3 * pu1_left[0]) + pu1_left[left_strd] + 2) >> 2;\n        }\n\n        for(idx = 1; idx <= 6; idx++)\n        {\n            pu1_dst[7 - idx] = FILT121(pu1_left[(idx - 1) * left_strd],\n                                       pu1_left[idx * left_strd],\n                                       pu1_left[(idx + 1) * left_strd]);\n\n        }\n        pu1_dst[0] = (pu1_left[6 * left_strd] + 3 * pu1_left[7 * left_strd] + 2)\n                        >> 2;\n\n    }\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_8x8_mode_vert\n *\n * @brief\n *  Perform Intra prediction for  luma_8x8 mode:vertical\n *\n * @par Description:\n *  Perform Intra prediction for  luma_8x8 mode:vertical ,described in sec 8.3.2.2.2\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nvoid ih264_intra_pred_luma_8x8_mode_vert(UWORD8 *pu1_src,\n                                         UWORD8 *pu1_dst,\n                                         WORD32 src_strd,\n                                         WORD32 dst_strd,\n                                         WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n\n    memcpy(pu1_dst, pu1_top, 8);\n    memcpy(pu1_dst + dst_strd, pu1_top, 8);\n    memcpy(pu1_dst + 2 * dst_strd, pu1_top, 8);\n    memcpy(pu1_dst + 3 * dst_strd, pu1_top, 8);\n    memcpy(pu1_dst + 4 * dst_strd, pu1_top, 8);\n    memcpy(pu1_dst + 5 * dst_strd, pu1_top, 8);\n    memcpy(pu1_dst + 6 * dst_strd, pu1_top, 8);\n    memcpy(pu1_dst + 7 * dst_strd, pu1_top, 8);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_8x8_mode_horz\n *\n * @brief\n *  Perform Intra prediction for  luma_8x8 mode:horizontal\n *\n * @par Description:\n *  Perform Intra prediction for  luma_8x8 mode:horizontal ,described in sec 8.3.2.2.2\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\nvoid ih264_intra_pred_luma_8x8_mode_horz(UWORD8 *pu1_src,\n                                         UWORD8 *pu1_dst,\n                                         WORD32 src_strd,\n                                         WORD32 dst_strd,\n                                         WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = pu1_src + BLK8x8SIZE - 1;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    memset(pu1_dst, *pu1_left, 8);\n    memset(pu1_dst + dst_strd, *(pu1_left - 1), 8);\n    memset(pu1_dst + 2 * dst_strd, *(pu1_left - 2), 8);\n    memset(pu1_dst + 3 * dst_strd, *(pu1_left - 3), 8);\n    memset(pu1_dst + 4 * dst_strd, *(pu1_left - 4), 8);\n    memset(pu1_dst + 5 * dst_strd, *(pu1_left - 5), 8);\n    memset(pu1_dst + 6 * dst_strd, *(pu1_left - 6), 8);\n    memset(pu1_dst + 7 * dst_strd, *(pu1_left - 7), 8);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_8x8_mode_dc\n *\n * @brief\n *     Perform Intra prediction for  luma_8x8 mode:DC\n *\n * @par Description:\n *    Perform Intra prediction for  luma_8x8 mode:DC ,described in sec 8.3.2.2.4\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n *  availability of neighbouring pixels\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_8x8_mode_dc(UWORD8 *pu1_src,\n                                       UWORD8 *pu1_dst,\n                                       WORD32 src_strd,\n                                       WORD32 dst_strd,\n                                       WORD32 ngbr_avail)\n{\n    UWORD8 u1_useleft; /* availability of left predictors (only for DC) */\n    UWORD8 u1_usetop; /* availability of top predictors (only for DC) */\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    WORD32 row;\n    WORD32 val = 0;\n    UNUSED(src_strd);\n\n    u1_useleft = BOOLEAN(ngbr_avail & LEFT_MB_AVAILABLE_MASK);\n    u1_usetop = BOOLEAN(ngbr_avail & TOP_MB_AVAILABLE_MASK);\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n\n    if(u1_useleft)\n    {\n        for(row = 0; row < BLK8x8SIZE; row++)\n            val += *(pu1_left - row);\n        val += 4;\n    }\n    if(u1_usetop)\n    {\n        for(row = 0; row < BLK8x8SIZE; row++)\n            val += *(pu1_top + row);\n        val += 4;\n    }\n\n    /* Since 4 is added if either left/top pred is there,\n     val still being zero implies both preds are not there */\n    val = (val) ? (val >> (2 + u1_useleft + u1_usetop)) : 128;\n\n    memset(pu1_dst, val, 8);\n    memset(pu1_dst + dst_strd, val, 8);\n    memset(pu1_dst + 2 * dst_strd, val, 8);\n    memset(pu1_dst + 3 * dst_strd, val, 8);\n    memset(pu1_dst + 4 * dst_strd, val, 8);\n    memset(pu1_dst + 5 * dst_strd, val, 8);\n    memset(pu1_dst + 6 * dst_strd, val, 8);\n    memset(pu1_dst + 7 * dst_strd, val, 8);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_8x8_mode_diag_dl\n *\n * @brief\n *     Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Left\n *\n * @par Description:\n *    Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Left ,described in sec 8.3.2.2.5\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_8x8_mode_diag_dl(UWORD8 *pu1_src,\n                                            UWORD8 *pu1_dst,\n                                            WORD32 src_strd,\n                                            WORD32 dst_strd,\n                                            WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD32 ui4_a, ui4_b, ui4_c, ui4_d, ui4_e, ui4_f, ui4_g, ui4_h;\n    UWORD32 ui4_i, ui4_j, ui4_k, ui4_l, ui4_m, ui4_n, ui4_o, ui4_p;\n    UWORD8 predicted_pixels[15];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n\n    ui4_a = *pu1_top++;\n    ui4_b = *pu1_top++;\n    ui4_c = *pu1_top++;\n    ui4_d = *pu1_top++;\n    ui4_e = *pu1_top++;\n    ui4_f = *pu1_top++;\n    ui4_g = *pu1_top++;\n    ui4_h = *pu1_top++;\n    ui4_i = *pu1_top++;\n    ui4_j = *pu1_top++;\n    ui4_k = *pu1_top++;\n    ui4_l = *pu1_top++;\n    ui4_m = *pu1_top++;\n    ui4_n = *pu1_top++;\n    ui4_o = *pu1_top++;\n    ui4_p = *pu1_top;\n\n    predicted_pixels[0] = FILT121(ui4_a, ui4_b, ui4_c);\n    predicted_pixels[1] = FILT121(ui4_b, ui4_c, ui4_d);\n    predicted_pixels[2] = FILT121(ui4_c, ui4_d, ui4_e);\n    predicted_pixels[3] = FILT121(ui4_d, ui4_e, ui4_f);\n    predicted_pixels[4] = FILT121(ui4_e, ui4_f, ui4_g);\n    predicted_pixels[5] = FILT121(ui4_f, ui4_g, ui4_h);\n    predicted_pixels[6] = FILT121(ui4_g, ui4_h, ui4_i);\n    predicted_pixels[7] = FILT121(ui4_h, ui4_i, ui4_j);\n    predicted_pixels[8] = FILT121(ui4_i, ui4_j, ui4_k);\n    predicted_pixels[9] = FILT121(ui4_j, ui4_k, ui4_l);\n    predicted_pixels[10] = FILT121(ui4_k, ui4_l, ui4_m);\n    predicted_pixels[11] = FILT121(ui4_l, ui4_m, ui4_n);\n    predicted_pixels[12] = FILT121(ui4_m, ui4_n, ui4_o);\n    predicted_pixels[13] = FILT121(ui4_n, ui4_o, ui4_p);\n    predicted_pixels[14] = FILT121(ui4_o, ui4_p, ui4_p);\n\n    memcpy(pu1_dst, predicted_pixels, 8);\n    memcpy(pu1_dst + dst_strd, predicted_pixels + 1, 8);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 2, 8);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels + 3, 8);\n    memcpy(pu1_dst + 4 * dst_strd, predicted_pixels + 4, 8);\n    memcpy(pu1_dst + 5 * dst_strd, predicted_pixels + 5, 8);\n    memcpy(pu1_dst + 6 * dst_strd, predicted_pixels + 6, 8);\n    memcpy(pu1_dst + 7 * dst_strd, predicted_pixels + 7, 8);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_8x8_mode_diag_dr\n *\n * @brief\n *     Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Right\n *\n * @par Description:\n *    Perform Intra prediction for  luma_8x8 mode:Diagonal_Down_Right ,described in sec 8.3.2.2.6\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_8x8_mode_diag_dr(UWORD8 *pu1_src,\n                                            UWORD8 *pu1_dst,\n                                            WORD32 src_strd,\n                                            WORD32 dst_strd,\n                                            WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD8 *pu1_topleft = NULL; /* Pointer to start of top left predictors */\n    UWORD32 ui4_a;\n    UWORD32 ui4_b, ui4_c, ui4_d, ui4_e, ui4_f, ui4_g, ui4_h, ui4_i;\n    UWORD32 ui4_j, ui4_k, ui4_l, ui4_m, ui4_n, ui4_o, ui4_p, ui4_q;\n    UWORD8 predicted_pixels[15];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n    pu1_topleft = pu1_src + BLK8x8SIZE;\n\n    ui4_a = *pu1_topleft;\n    ui4_b = *pu1_top++;\n    ui4_c = *pu1_top++;\n    ui4_d = *pu1_top++;\n    ui4_e = *pu1_top++;\n    ui4_f = *pu1_top++;\n    ui4_g = *pu1_top++;\n    ui4_h = *pu1_top++;\n    ui4_i = *pu1_top;\n    ui4_j = *pu1_left--;\n    ui4_k = *pu1_left--;\n    ui4_l = *pu1_left--;\n    ui4_m = *pu1_left--;\n    ui4_n = *pu1_left--;\n    ui4_o = *pu1_left--;\n    ui4_p = *pu1_left--;\n    ui4_q = *pu1_left;\n\n    predicted_pixels[6] = FILT121(ui4_a, ui4_j, ui4_k);\n    predicted_pixels[5] = FILT121(ui4_j, ui4_k, ui4_l);\n    predicted_pixels[4] = FILT121(ui4_k, ui4_l, ui4_m);\n    predicted_pixels[3] = FILT121(ui4_l, ui4_m, ui4_n);\n    predicted_pixels[2] = FILT121(ui4_m, ui4_n, ui4_o);\n    predicted_pixels[1] = FILT121(ui4_n, ui4_o, ui4_p);\n    predicted_pixels[0] = FILT121(ui4_o, ui4_p, ui4_q);\n    predicted_pixels[7] = FILT121(ui4_b, ui4_a, ui4_j);\n    predicted_pixels[8] = FILT121(ui4_a, ui4_b, ui4_c);\n    predicted_pixels[9] = FILT121(ui4_b, ui4_c, ui4_d);\n    predicted_pixels[10] = FILT121(ui4_c, ui4_d, ui4_e);\n    predicted_pixels[11] = FILT121(ui4_d, ui4_e, ui4_f);\n    predicted_pixels[12] = FILT121(ui4_e, ui4_f, ui4_g);\n    predicted_pixels[13] = FILT121(ui4_f, ui4_g, ui4_h);\n    predicted_pixels[14] = FILT121(ui4_g, ui4_h, ui4_i);\n\n    memcpy(pu1_dst, predicted_pixels + 7, 8);\n    memcpy(pu1_dst + dst_strd, predicted_pixels + 6, 8);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 5, 8);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels + 4, 8);\n    memcpy(pu1_dst + 4 * dst_strd, predicted_pixels + 3, 8);\n    memcpy(pu1_dst + 5 * dst_strd, predicted_pixels + 2, 8);\n    memcpy(pu1_dst + 6 * dst_strd, predicted_pixels + 1, 8);\n    memcpy(pu1_dst + 7 * dst_strd, predicted_pixels, 8);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_8x8_mode_vert_r\n *\n * @brief\n *     Perform Intra prediction for  luma_8x8 mode:Vertical_Right\n *\n * @par Description:\n *    Perform Intra prediction for  luma_8x8 mode:Vertical_Right ,described in sec 8.3.2.2.7\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nvoid ih264_intra_pred_luma_8x8_mode_vert_r(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD8 *pu1_topleft = NULL; /* Pointer to start of top left predictors */\n    UWORD32 ui4_a;\n    UWORD32 ui4_b, ui4_c, ui4_d, ui4_e, ui4_f, ui4_g, ui4_h, ui4_i;\n    UWORD32 ui4_j, ui4_k, ui4_l, ui4_m, ui4_n, ui4_o, ui4_p;\n    UWORD8 predicted_pixels[22];\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n    pu1_topleft = pu1_src + BLK8x8SIZE;\n\n    ui4_a = *pu1_topleft;\n\n    ui4_b = *pu1_top++;\n    ui4_c = *pu1_top++;\n    ui4_d = *pu1_top++;\n    ui4_e = *pu1_top++;\n    ui4_f = *pu1_top++;\n    ui4_g = *pu1_top++;\n    ui4_h = *pu1_top++;\n    ui4_i = *pu1_top;\n    ui4_j = *pu1_left--;\n    ui4_k = *pu1_left--;\n    ui4_l = *pu1_left--;\n    ui4_m = *pu1_left--;\n    ui4_n = *pu1_left--;\n    ui4_o = *pu1_left--;\n    ui4_p = *pu1_left--;\n\n    predicted_pixels[0] = FILT121(ui4_o, ui4_n, ui4_m);\n    predicted_pixels[1] = FILT121(ui4_m, ui4_l, ui4_k);\n    predicted_pixels[2] = FILT121(ui4_k, ui4_j, ui4_a);\n    predicted_pixels[3] = FILT11(ui4_a, ui4_b);\n    predicted_pixels[4] = FILT11(ui4_b, ui4_c);\n    predicted_pixels[5] = FILT11(ui4_c, ui4_d);\n    predicted_pixels[6] = FILT11(ui4_d, ui4_e);\n    predicted_pixels[7] = FILT11(ui4_e, ui4_f);\n    predicted_pixels[8] = FILT11(ui4_f, ui4_g);\n    predicted_pixels[9] = FILT11(ui4_g, ui4_h);\n    predicted_pixels[10] = FILT11(ui4_h, ui4_i);\n    predicted_pixels[11] = FILT121(ui4_p, ui4_o, ui4_n);\n    predicted_pixels[12] = FILT121(ui4_n, ui4_m, ui4_l);\n    predicted_pixels[13] = FILT121(ui4_l, ui4_k, ui4_j);\n    predicted_pixels[14] = FILT121(ui4_b, ui4_a, ui4_j);\n    predicted_pixels[15] = FILT121(ui4_a, ui4_b, ui4_c);\n    predicted_pixels[16] = FILT121(ui4_b, ui4_c, ui4_d);\n    predicted_pixels[17] = FILT121(ui4_c, ui4_d, ui4_e);\n    predicted_pixels[18] = FILT121(ui4_d, ui4_e, ui4_f);\n    predicted_pixels[19] = FILT121(ui4_e, ui4_f, ui4_g);\n    predicted_pixels[20] = FILT121(ui4_f, ui4_g, ui4_h);\n    predicted_pixels[21] = FILT121(ui4_g, ui4_h, ui4_i);\n\n    memcpy(pu1_dst, predicted_pixels + 3, 8);\n    memcpy(pu1_dst + 1 * dst_strd, predicted_pixels + 14, 8);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 2, 8);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels + 13, 8);\n    memcpy(pu1_dst + 4 * dst_strd, predicted_pixels + 1, 8);\n    memcpy(pu1_dst + 5 * dst_strd, predicted_pixels + 12, 8);\n    memcpy(pu1_dst + 6 * dst_strd, predicted_pixels, 8);\n    memcpy(pu1_dst + 7 * dst_strd, predicted_pixels + 11, 8);\n\n}\n\n/*\n *******************************************************************************\n *\n *ih264_intra_pred_luma_8x8_mode_horz_d\n *\n * @brief\n *     Perform Intra prediction for  luma_8x8 mode:Horizontal_Down\n *\n * @par Description:\n *    Perform Intra prediction for  luma_8x8 mode:Horizontal_Down ,described in sec 8.3.2.2.8\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\n\nvoid ih264_intra_pred_luma_8x8_mode_horz_d(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD8 *pu1_topleft = NULL; /* Pointer to start of top left predictors */\n    UWORD32 ui4_a;\n    UWORD32 ui4_b, ui4_c, ui4_d, ui4_e, ui4_f, ui4_g, ui4_h, ui4_i;\n    UWORD32 ui4_j, ui4_k, ui4_l, ui4_m, ui4_n, ui4_o, ui4_p;\n    UWORD8 predicted_pixels[22];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n    pu1_topleft = pu1_src + BLK8x8SIZE;\n\n    ui4_a = *pu1_topleft;\n    ui4_j = *pu1_top++;\n    ui4_k = *pu1_top++;\n    ui4_l = *pu1_top++;\n    ui4_m = *pu1_top++;\n    ui4_n = *pu1_top++;\n    ui4_o = *pu1_top++;\n    ui4_p = *pu1_top++;\n    ui4_b = *pu1_left--;\n    ui4_c = *pu1_left--;\n    ui4_d = *pu1_left--;\n    ui4_e = *pu1_left--;\n    ui4_f = *pu1_left--;\n    ui4_g = *pu1_left--;\n    ui4_h = *pu1_left--;\n    ui4_i = *pu1_left;\n\n    predicted_pixels[0] = FILT11(ui4_h, ui4_i);\n    predicted_pixels[1] = FILT121(ui4_g, ui4_h, ui4_i);\n    predicted_pixels[2] = FILT11(ui4_g, ui4_h);\n    predicted_pixels[3] = FILT121(ui4_f, ui4_g, ui4_h);\n    predicted_pixels[4] = FILT11(ui4_f, ui4_g);\n    predicted_pixels[5] = FILT121(ui4_e, ui4_f, ui4_g);\n    predicted_pixels[6] = FILT11(ui4_e, ui4_f);\n    predicted_pixels[7] = FILT121(ui4_d, ui4_e, ui4_f);\n    predicted_pixels[8] = FILT11(ui4_d, ui4_e);\n    predicted_pixels[9] = FILT121(ui4_c, ui4_d, ui4_e);\n    predicted_pixels[10] = FILT11(ui4_c, ui4_d);\n    predicted_pixels[11] = FILT121(ui4_b, ui4_c, ui4_d);\n    predicted_pixels[12] = FILT11(ui4_b, ui4_c);\n    predicted_pixels[13] = FILT121(ui4_a, ui4_b, ui4_c);\n    predicted_pixels[14] = FILT11(ui4_a, ui4_b);\n    predicted_pixels[15] = FILT121(ui4_j, ui4_a, ui4_b);\n    predicted_pixels[16] = FILT121(ui4_k, ui4_j, ui4_a);\n    predicted_pixels[17] = FILT121(ui4_l, ui4_k, ui4_j);\n    predicted_pixels[18] = FILT121(ui4_m, ui4_l, ui4_k);\n    predicted_pixels[19] = FILT121(ui4_n, ui4_m, ui4_l);\n    predicted_pixels[20] = FILT121(ui4_o, ui4_n, ui4_m);\n    predicted_pixels[21] = FILT121(ui4_p, ui4_o, ui4_n);\n\n    memcpy(pu1_dst, predicted_pixels + 14, 8);\n    memcpy(pu1_dst + dst_strd, predicted_pixels + 12, 8);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 10, 8);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels + 8, 8);\n    memcpy(pu1_dst + 4 * dst_strd, predicted_pixels + 6, 8);\n    memcpy(pu1_dst + 5 * dst_strd, predicted_pixels + 4, 8);\n    memcpy(pu1_dst + 6 * dst_strd, predicted_pixels + 2, 8);\n    memcpy(pu1_dst + 7 * dst_strd, predicted_pixels, 8);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_8x8_mode_vert_l\n *\n * @brief\n *     Perform Intra prediction for  luma_8x8 mode:Vertical_Left\n *\n * @par Description:\n *    Perform Intra prediction for  luma_8x8 mode:Vertical_Left ,described in sec 8.3.2.2.9\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\n\nvoid ih264_intra_pred_luma_8x8_mode_vert_l(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD32 ui4_a, ui4_b, ui4_c, ui4_d, ui4_e, ui4_f, ui4_g, ui4_h;\n    UWORD32 ui4_i, ui4_j, ui4_k, ui4_l, ui4_m;\n    UWORD8 predicted_pixels[22];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n\n    ui4_a = *pu1_top++;\n    ui4_b = *pu1_top++;\n    ui4_c = *pu1_top++;\n    ui4_d = *pu1_top++;\n    ui4_e = *pu1_top++;\n    ui4_f = *pu1_top++;\n    ui4_g = *pu1_top++;\n    ui4_h = *pu1_top++;\n    ui4_i = *pu1_top++;\n    ui4_j = *pu1_top++;\n    ui4_k = *pu1_top++;\n    ui4_l = *pu1_top++;\n    ui4_m = *pu1_top++;\n\n    predicted_pixels[0] = FILT11(ui4_a, ui4_b);\n    predicted_pixels[1] = FILT11(ui4_b, ui4_c);\n    predicted_pixels[2] = FILT11(ui4_c, ui4_d);\n    predicted_pixels[3] = FILT11(ui4_d, ui4_e);\n    predicted_pixels[4] = FILT11(ui4_e, ui4_f);\n    predicted_pixels[5] = FILT11(ui4_f, ui4_g);\n    predicted_pixels[6] = FILT11(ui4_g, ui4_h);\n    predicted_pixels[7] = FILT11(ui4_h, ui4_i);\n    predicted_pixels[8] = FILT11(ui4_i, ui4_j);\n    predicted_pixels[9] = FILT11(ui4_j, ui4_k);\n    predicted_pixels[10] = FILT11(ui4_k, ui4_l);\n    predicted_pixels[11] = FILT121(ui4_a, ui4_b, ui4_c);\n    predicted_pixels[12] = FILT121(ui4_b, ui4_c, ui4_d);\n    predicted_pixels[13] = FILT121(ui4_c, ui4_d, ui4_e);\n    predicted_pixels[14] = FILT121(ui4_d, ui4_e, ui4_f);\n    predicted_pixels[15] = FILT121(ui4_e, ui4_f, ui4_g);\n    predicted_pixels[16] = FILT121(ui4_f, ui4_g, ui4_h);\n    predicted_pixels[17] = FILT121(ui4_g, ui4_h, ui4_i);\n    predicted_pixels[18] = FILT121(ui4_h, ui4_i, ui4_j);\n    predicted_pixels[19] = FILT121(ui4_i, ui4_j, ui4_k);\n    predicted_pixels[20] = FILT121(ui4_j, ui4_k, ui4_l);\n    predicted_pixels[21] = FILT121(ui4_k, ui4_l, ui4_m);\n\n    memcpy(pu1_dst, predicted_pixels, 8);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 1, 8);\n    memcpy(pu1_dst + 4 * dst_strd, predicted_pixels + 2, 8);\n    memcpy(pu1_dst + 6 * dst_strd, predicted_pixels + 3, 8);\n    memcpy(pu1_dst + 1 * dst_strd, predicted_pixels + 11, 8);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels + 12, 8);\n    memcpy(pu1_dst + 5 * dst_strd, predicted_pixels + 13, 8);\n    memcpy(pu1_dst + 7 * dst_strd, predicted_pixels + 14, 8);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_8x8_mode_horz_u\n *\n * @brief\n *     Perform Intra prediction for  luma_8x8 mode:Horizontal_Up\n *\n * @par Description:\n *    Perform Intra prediction for  luma_8x8 mode:Horizontal_Up ,described in sec 8.3.2.2.10\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\n\nvoid ih264_intra_pred_luma_8x8_mode_horz_u(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD32 ui4_j, ui4_k, ui4_l, ui4_m, ui4_n, ui4_o, ui4_p, ui4_q;\n    UWORD8 predicted_pixels[22];\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n\n    ui4_j = *pu1_left--;\n    ui4_k = *pu1_left--;\n    ui4_l = *pu1_left--;\n    ui4_m = *pu1_left--;\n    ui4_n = *pu1_left--;\n    ui4_o = *pu1_left--;\n    ui4_p = *pu1_left--;\n    ui4_q = *pu1_left;\n\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n\n    predicted_pixels[0] = FILT11(ui4_j, ui4_k);\n    predicted_pixels[1] = FILT121(ui4_j, ui4_k, ui4_l);\n    predicted_pixels[2] = FILT11(ui4_k, ui4_l);\n    predicted_pixels[3] = FILT121(ui4_k, ui4_l, ui4_m);\n    predicted_pixels[4] = FILT11(ui4_l, ui4_m);\n    predicted_pixels[5] = FILT121(ui4_l, ui4_m, ui4_n);\n    predicted_pixels[6] = FILT11(ui4_m, ui4_n);\n    predicted_pixels[7] = FILT121(ui4_m, ui4_n, ui4_o);\n    predicted_pixels[8] = FILT11(ui4_n, ui4_o);\n    predicted_pixels[9] = FILT121(ui4_n, ui4_o, ui4_p);\n    predicted_pixels[10] = FILT11(ui4_o, ui4_p);\n    predicted_pixels[11] = FILT121(ui4_o, ui4_p, ui4_q);\n    predicted_pixels[12] = FILT11(ui4_p, ui4_q);\n    predicted_pixels[13] = FILT121(ui4_p, ui4_q, ui4_q);\n    memset(predicted_pixels+14,ui4_q,8);\n\n    memcpy(pu1_dst, predicted_pixels, 8);\n    memcpy(pu1_dst + 1 * dst_strd, predicted_pixels + 2, 8);\n    memcpy(pu1_dst + 2 * dst_strd, predicted_pixels + 4, 8);\n    memcpy(pu1_dst + 3 * dst_strd, predicted_pixels + 6, 8);\n    memcpy(pu1_dst + 4 * dst_strd, predicted_pixels + 8, 8);\n    memcpy(pu1_dst + 5 * dst_strd, predicted_pixels + 10, 8);\n    memcpy(pu1_dst + 6 * dst_strd, predicted_pixels + 12, 8);\n    memcpy(pu1_dst + 7 * dst_strd, predicted_pixels + 14, 8);\n}\n\n\n/*******************    16x16 Modes    *******************/\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_16x16_mode_vert\n *\n * @brief\n *  Perform Intra prediction for  luma_16x16 mode:Vertical\n *\n * @par Description:\n *  Perform Intra prediction for  luma_16x16 mode:Vertical, described in sec 8.3.3.1\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n *  availability of neighbouring pixels (Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\n\nvoid ih264_intra_pred_luma_16x16_mode_vert(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    WORD32 rows; /* loop variables*/\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + MB_SIZE + 1;\n\n    for(rows = 0; rows < 16; rows += 4, pu1_dst += dst_strd)\n    {\n        memcpy(pu1_dst, pu1_top, 16);\n        pu1_dst += dst_strd;\n        memcpy(pu1_dst, pu1_top, 16);\n        pu1_dst += dst_strd;\n        memcpy(pu1_dst, pu1_top, 16);\n        pu1_dst += dst_strd;\n        memcpy(pu1_dst, pu1_top, 16);\n    }\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_16x16_mode_horz\n *\n * @brief\n *  Perform Intra prediction for  luma_16x16 mode:Horizontal\n *\n * @par Description:\n *  Perform Intra prediction for  luma_16x16 mode:Horizontal, described in sec 8.3.3.2\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\n\nvoid ih264_intra_pred_luma_16x16_mode_horz(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of top predictors */\n    WORD32 rows;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_left = pu1_src + MB_SIZE - 1;\n\n    for(rows = 0; rows < 16; rows += 4, pu1_dst += dst_strd, pu1_left --)\n    {\n        memset(pu1_dst, *pu1_left, 16); /* copy the left value to the entire row*/\n        pu1_left --;\n        pu1_dst += dst_strd;\n        memset(pu1_dst, *pu1_left, 16);\n        pu1_left --;\n        pu1_dst += dst_strd;\n        memset(pu1_dst, *pu1_left, 16);\n        pu1_left --;\n        pu1_dst += dst_strd;\n        memset(pu1_dst, *pu1_left, 16);\n    }\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_16x16_mode_dc\n *\n * @brief\n *  Perform Intra prediction for  luma_16x16 mode:DC\n *\n * @par Description:\n *  Perform Intra prediction for  luma_16x16 mode:DC, described in sec 8.3.3.3\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n ** @param[in] ngbr_avail\n *  availability of neighbouring pixels\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\n\nvoid ih264_intra_pred_luma_16x16_mode_dc(UWORD8 *pu1_src,\n                                         UWORD8 *pu1_dst,\n                                         WORD32 src_strd,\n                                         WORD32 dst_strd,\n                                         WORD32 ngbr_avail)\n{\n    WORD8 u1_useleft; /* availability of left predictors (only for DC) */\n    UWORD8 u1_usetop; /* availability of top predictors (only for DC) */\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    WORD32 rows; /* loop variables*/\n    WORD32 val = 0;\n    UNUSED(src_strd);\n\n    u1_useleft = BOOLEAN(ngbr_avail & LEFT_MB_AVAILABLE_MASK);\n    u1_usetop = BOOLEAN(ngbr_avail & TOP_MB_AVAILABLE_MASK);\n    pu1_top = pu1_src + MB_SIZE + 1;\n    pu1_left = pu1_src + MB_SIZE - 1;\n    if(u1_useleft)\n    {\n        for(rows = 0; rows < 16; rows++)\n            val += *(pu1_left - rows);\n        val += 8;\n    }\n    if(u1_usetop)\n    {\n        for(rows = 0; rows < 16; rows++)\n            val += *(pu1_top + rows);\n        val += 8;\n    }\n    /* Since 8 is added if either left/top pred is there,\n     val still being zero implies both preds are not there */\n    val = (val) ? (val >> (3 + u1_useleft + u1_usetop)) : 128;\n\n    for(rows = 0; rows < 16; rows += 4, pu1_dst += dst_strd)\n    {\n        memset(pu1_dst, val, 16);\n        pu1_dst += dst_strd;\n        memset(pu1_dst, val, 16);\n        pu1_dst += dst_strd;\n        memset(pu1_dst, val, 16);\n        pu1_dst += dst_strd;\n        memset(pu1_dst, val, 16);\n    }\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_16x16_mode_plane\n *\n * @brief\n *  Perform Intra prediction for  luma_16x16 mode:PLANE\n *\n * @par Description:\n *  Perform Intra prediction for  luma_16x16 mode:PLANE, described in sec 8.3.3.4\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\n\nvoid ih264_intra_pred_luma_16x16_mode_plane(UWORD8 *pu1_src,\n                                            UWORD8 *pu1_dst,\n                                            WORD32 src_strd,\n                                            WORD32 dst_strd,\n                                            WORD32 ngbr_avail)\n{\n    /*! Written with no multiplications */\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    UWORD8 *pu1_topleft = NULL;\n    WORD32 a, b, c, tmp;\n    UWORD8 *pu1_tmp1, *pu1_tmp2;\n    WORD32 shift;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + MB_SIZE + 1;\n    pu1_left = pu1_src + MB_SIZE - 1;\n    pu1_topleft = pu1_src + MB_SIZE;\n\n    {\n        a = (*(pu1_top + 15) + *(pu1_left - 15)) << 4;\n\n        /*! Implement Sum(x*(P((x+7),-1) - P((x-7),-1))) x=1...8 */\n        pu1_tmp1 = pu1_top + 8;\n        pu1_tmp2 = pu1_tmp1 - 2;\n\n        /* Pixel diffs are only 9 bits;\n         so sign extension allows shifts to be used even for signed */\n        b = ((*pu1_tmp1++) - (*pu1_tmp2--)); /* x=1 */\n        b += ((*pu1_tmp1++) - (*pu1_tmp2--)) << 1; /* x=2 */\n        tmp = ((*pu1_tmp1++) - (*pu1_tmp2--));\n        b += (tmp << 1) + tmp; /* x=3 */\n        b += ((*pu1_tmp1++) - (*pu1_tmp2--)) << 2; /* x=4 */\n\n        tmp = ((*pu1_tmp1++) - (*pu1_tmp2--));\n        b += (tmp << 2) + tmp; /* x=5 */\n        tmp = ((*pu1_tmp1++) - (*pu1_tmp2--));\n        b += (tmp << 2) + (tmp << 1); /* x=6 */\n        tmp = ((*pu1_tmp1++) - (*pu1_tmp2--));\n        b += (tmp << 3) - tmp; /* x=7 */\n        b += ((*pu1_tmp1) - (*pu1_topleft)) << 3; /* x=8 */\n\n        b = ((b << 2) + b + 32) >> 6; /*! (5*H + 32)>>6 */\n\n        /*! Implement Sum(y*(P(-1,(y+7)) - P(-1,(y-7)))) y=1...8 */\n        pu1_tmp1 = pu1_left - 8;\n        pu1_tmp2 = pu1_tmp1 + 2;\n\n        c = ((*pu1_tmp1) - (*pu1_tmp2)); /* y=1 */\n        pu1_tmp1--;\n        pu1_tmp2++;\n        c += ((*pu1_tmp1) - (*pu1_tmp2)) << 1; /* y=2 */\n        pu1_tmp1--;\n        pu1_tmp2++;\n        tmp = ((*pu1_tmp1) - (*pu1_tmp2));\n        c += (tmp << 1) + tmp; /* y=3 */\n        pu1_tmp1--;\n        pu1_tmp2++;\n        c += ((*pu1_tmp1) - (*pu1_tmp2)) << 2; /* y=4 */\n        pu1_tmp1--;\n        pu1_tmp2++;\n\n        tmp = ((*pu1_tmp1) - (*pu1_tmp2));\n        c += (tmp << 2) + tmp; /* y=5 */\n        pu1_tmp1--;\n        pu1_tmp2++;\n        tmp = ((*pu1_tmp1) - (*pu1_tmp2));\n        c += (tmp << 2) + (tmp << 1); /* y=6 */\n        pu1_tmp1--;\n        pu1_tmp2++;\n        tmp = ((*pu1_tmp1) - (*pu1_tmp2));\n        c += (tmp << 3) - tmp; /* y=7 */\n        pu1_tmp1--; //pu1_tmp2 ++;\n        /* Modified to get (-1,-1) location as *(pu1_top - 1) instead of (pu1_left - ui4_stride) */\n        //c += ((*pu1_tmp1) - (*(pu1_top - 1)))<<3;      /* y=8 */\n        c += ((*pu1_tmp1) - (*pu1_topleft)) << 3; /* y=8 */\n\n        c = ((c << 2) + c + 32) >> 6; /*! (5*V + 32)>>32 */\n        shift = 3;\n    }\n\n    /*! Now from the plane parameters a, b, and c,\n     compute the fitted plane values over the block */\n    {\n        WORD32 tmp1, tmpx, tmpx_init, j, i;\n\n        tmpx_init = -(b << shift); /* -8b */\n        tmp = a - (c << shift) + 16; /* a-((4or8)*c)+16 */\n        for(i = 0; i < 16; i++)\n        {\n            tmp += c; /*increment every time by c to get c*(y-7or3)*/\n            tmpx = tmpx_init; /* Init to -8b */\n            for(j = 0; j < 16; j++)\n            {\n                tmpx += b; /* increment every time by b to get b*(x-7or3) */\n                tmp1 = (tmp + tmpx) >> 5;\n                *pu1_dst++ = CLIP_U8(tmp1);\n            }\n            pu1_dst += (dst_strd - 16);\n        }\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_macros.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*********************************************************************************\n* @file\n*  ih264_macros.h\n*\n* @brief\n*  Macro definitions used in the codec\n*\n* @author\n*  Ittiam\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n#ifndef _IH264_MACROS_H_\n#define _IH264_MACROS_H_\n\n/*****************************************************************************/\n/* Function Macros                                                           */\n/*****************************************************************************/\n#define RETURN_IF(cond, retval) if(cond) {return (retval);}\n#define UNUSED(x) ((void)(x))\n\n#define ALIGN128(x) ((((x) + 127) >> 7) << 7)\n#define ALIGN64(x)  ((((x) + 63) >> 6) << 6)\n#define ALIGN32(x)  ((((x) + 31) >> 5) << 5)\n#define ALIGN16(x)  ((((x) + 15) >> 4) << 4)\n#define ALIGN8(x)   ((((x) + 7) >> 3) << 3)\n#define ALIGN4(x)   ((((x) + 3) >> 2) << 2)\n#define ALIGN2(x)   ((((x) + 1) >> 1) << 1)\n\n/**\n******************************************************************************\n *  @brief      Min, Max\n******************************************************************************\n */\n#define MAX(a,b) ((a > b)?(a):(b))\n#define MIN(a,b) ((a < b)?(a):(b))\n#define MIN3(a,b,c) ((a) < (b)) ? (((a) < (c)) ? (a) : (c)) : (((b) < (c)) ? (b) : (c))\n#define MAX3(a,b,c) ((a) > (b)) ? (((a) > (c)) ? (a) : (c)) : (((b) > (c)) ? (b) : (c))\n/**\n******************************************************************************\n *  @brief      Div, Mod\n******************************************************************************\n */\n#define MOD(x,y) ((x)%(y))\n#define DIV(x,y) ((x)/(y))\n\n/**\n******************************************************************************\n *  @brief      Clip\n******************************************************************************\n */\n#define CLIP3(miny, maxy, y) (((y) < (miny))?(miny):(((y) > (maxy))?(maxy):(y)))\n\n/**\n******************************************************************************\n *  @brief      True, False\n******************************************************************************\n */\n#define BOOLEAN(x) (!!(x))\n\n/**\n******************************************************************************\n *  @brief      Frequently used multiplications x2. x3, and x4\n******************************************************************************\n */\n#define X2(a)   ((a) << 1)\n#define X3(a)   (((a) << 1) + (a))\n#define X4(a)   ((a) << 2)\n\n/**\n******************************************************************************\n *  @brief      Misc\n******************************************************************************\n */\n#define ABS(x)          ((x) < 0 ? (-(x)) : (x))\n#define SIGNXY(x,y)     (((y) < 0) ? (-1 * (x)) : (x))\n\n#define SIGN(x)     (((x) >= 0) ? (((x) > 0) ? 1 : 0) : -1)\n\n#define RESET_BIT(x, pos) (x) = (x) & ~(1 << pos);\n#define SET_BIT(x, pos) (x) = (x) | (1 << pos);\n#define GET_BIT(x, pos) ((x) >> (pos)) & 0x1\n\n#define INSERT_BIT(x, pos, bit) { RESET_BIT(x, pos); (x) = (x) | (bit << pos); }\n#endif /*_IH264_MACROS_H_*/\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_mem_fns.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_mem_fns.c\n *\n * @brief\n *  Functions used for memory operations\n *\n * @author\n *  Ittiam\n *\n * @par List of Functions:\n *  ih264_memcpy()\n *  ih264_memcpy_mul_8()\n *  ih264_memset()\n *  ih264_memset_mul_8()\n *  ih264_memset_16bit()\n *  ih264_memset_16bit_mul_8()\n *\n * @remarks\n *  None\n *\n ******************************************************************************\n */\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n/* System include files */\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_mem_fns.h\"\n\n/**\n *******************************************************************************\n *\n * @brief\n *   memcpy of a 8,16 or 32 bytes\n *\n * @par Description:\n *   Does memcpy of 8bit data from source to destination for 8,16 or 32 number of bytes\n *\n * @param[in] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[in] num_bytes\n *  number of bytes to copy\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\nvoid ih264_memcpy(UWORD8 *pu1_dst, UWORD8 *pu1_src, UWORD32 num_bytes)\n{\n    memcpy(pu1_dst, pu1_src, num_bytes);\n}\n\n\nvoid ih264_memcpy_mul_8(UWORD8 *pu1_dst, UWORD8 *pu1_src, UWORD32 num_bytes)\n{\n    memcpy(pu1_dst, pu1_src, num_bytes);\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *   memset of a 8,16 or 32 bytes\n *\n * @par Description:\n *   Does memset of 8bit data for 8,16 or 32 number of bytes\n *\n * @param[in] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] value\n *  UWORD8 value used for memset\n *\n * @param[in] num_bytes\n *  number of bytes to set\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\nvoid ih264_memset(UWORD8 *pu1_dst, UWORD8 value, UWORD32 num_bytes)\n{\n    memset(pu1_dst, value, num_bytes);\n}\n\n\nvoid ih264_memset_mul_8(UWORD8 *pu1_dst, UWORD8 value, UWORD32 num_bytes)\n{\n    memset(pu1_dst, value, num_bytes);\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *   memset of 16bit data of a 8,16 or 32 bytes\n *\n * @par Description:\n *   Does memset of 16bit data for 8,16 or 32 number of bytes\n *\n * @param[in] pu2_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] value\n *  UWORD16 value used for memset\n *\n * @param[in] num_words\n *  number of words to set\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\nvoid ih264_memset_16bit(UWORD16 *pu2_dst, UWORD16 value, UWORD32 num_words)\n{\n    UWORD32 i;\n    for(i = 0; i < num_words; i++)\n    {\n        *pu2_dst++ = value;\n    }\n}\n\nvoid ih264_memset_16bit_mul_8(UWORD16 *pu2_dst,\n                              UWORD16 value,\n                              UWORD32 num_words)\n{\n    UWORD32 i;\n    for(i = 0; i < num_words; i++)\n    {\n        *pu2_dst++ = value;\n    }\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_mem_fns.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_mem_fns.h\n*\n* @brief\n*  Function declarations used for memory functions\n*\n* @author\n*  Ittiam\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n#ifndef _IH264_MEM_FNS_H_\n#define _IH264_MEM_FNS_H_\n\ntypedef void ih264_memcpy_ft(UWORD8 *pu1_dst, UWORD8 *pu1_src, UWORD32 num_bytes);\n\ntypedef void ih264_memcpy_mul_8_ft(UWORD8 *pu1_dst, UWORD8 *pu1_src, UWORD32 num_bytes);\n/**\n *******************************************************************************\n *\n * @brief\n *   memset of a 8,16 or 32 bytes\n *\n * @par Description:\n *   Does memset of 8bit data for 8,16 or 32 number of bytes\n *\n * @param[in] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] value\n *  UWORD8 value used for memset\n *\n * @param[in] num_bytes\n *  number of bytes to set\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\ntypedef void ih264_memset_ft(UWORD8 *pu1_dst, UWORD8 value, UWORD32 num_bytes);\n\ntypedef void ih264_memset_mul_8_ft(UWORD8 *pu1_dst, UWORD8 value, UWORD32 num_bytes);\n\n/**\n *******************************************************************************\n *\n * @brief\n *   memset of 16bit data of a 8,16 or 32 bytes\n *\n * @par Description:\n *   Does memset of 16bit data for 8,16 or 32 number of bytes\n *\n * @param[in] pu2_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] value\n *  UWORD16 value used for memset\n *\n * @param[in] num_words\n *  number of words to set\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\ntypedef void ih264_memset_16bit_ft(UWORD16 *pu2_dst, UWORD16 value, UWORD32 num_words);\n\ntypedef void ih264_memset_16bit_mul_8_ft(UWORD16 *pu2_dst, UWORD16 value, UWORD32 num_words);\n\n/* C function declarations */\nih264_memcpy_ft ih264_memcpy;\nih264_memcpy_mul_8_ft ih264_memcpy_mul_8;\nih264_memset_ft ih264_memset;\nih264_memset_mul_8_ft ih264_memset_mul_8;\nih264_memset_16bit_ft ih264_memset_16bit;\nih264_memset_16bit_mul_8_ft ih264_memset_16bit_mul_8;\n\n/* A9 Q function declarations */\nih264_memcpy_ft ih264_memcpy_a9q;\nih264_memcpy_mul_8_ft ih264_memcpy_mul_8_a9q;\nih264_memset_ft ih264_memset_a9q;\nih264_memset_mul_8_ft ih264_memset_mul_8_a9q;\nih264_memset_16bit_ft ih264_memset_16bit_a9q;\nih264_memset_16bit_mul_8_ft ih264_memset_16bit_mul_8_a9q;\n\n/* AV8 function declarations */\nih264_memcpy_ft ih264_memcpy_av8;\nih264_memcpy_mul_8_ft ih264_memcpy_mul_8_av8;\nih264_memset_ft ih264_memset_av8;\nih264_memset_mul_8_ft ih264_memset_mul_8_av8;\nih264_memset_16bit_ft ih264_memset_16bit_av8;\nih264_memset_16bit_mul_8_ft ih264_memset_16bit_mul_8_av8;\n\n\nih264_memcpy_mul_8_ft ih264_memcpy_mul_8_ssse3;\nih264_memset_mul_8_ft ih264_memset_mul_8_ssse3;\nih264_memset_16bit_mul_8_ft ih264_memset_16bit_mul_8_ssse3;\n#endif  //_MEM_FNS_H_\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_padding.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/**\n*******************************************************************************\n* @file\n*  ih264_padding.c\n*\n* @brief\n*  Contains function definitions for Padding\n*\n* @author\n*  Ittiam\n*\n* @par List of Functions:\n*   - ih264_pad_top()\n*   - ih264_pad_bottom()\n*   - ih264_pad_left_luma()\n*   - ih264_pad_left_chroma()\n*   - ih264_pad_right_luma()\n*   - ih264_pad_right_chroma()\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System include files */\n#include <stddef.h>\n#include <string.h>\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_padding.h\"\n\n\n/*****************************************************************************/\n/* Function Definitions                                                      */\n/*****************************************************************************/\n\n/**\n*******************************************************************************\n*\n* @brief pad at the top of a 2d array\n*\n* @par Description:\n*  The top row of a 2d array is replicated for pad_size times at the top\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] wd\n*  integer width of the array\n*\n* @param[in] pad_size\n*  integer -padding size of the array\n*\n* @returns none\n*\n* @remarks none\n*\n*******************************************************************************\n*/\nvoid ih264_pad_top(UWORD8 *pu1_src,\n                   WORD32 src_strd,\n                   WORD32 wd,\n                   WORD32 pad_size)\n{\n    WORD32 row;\n\n    for(row = 1; row <= pad_size; row++)\n    {\n        memcpy(pu1_src - row * src_strd, pu1_src, wd);\n    }\n}\n\n\n\n/**\n*******************************************************************************\n*\n* @brief pad at the bottom of a 2d array\n*\n* @par Description:\n*  The bottom row of a 2d array is replicated for pad_size times at the bottom\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] wd\n*  integer width of the array\n*\n* @param[in] pad_size\n*  integer -padding size of the array\n*\n* @returns none\n*\n* @remarks none\n*\n*******************************************************************************\n*/\nvoid ih264_pad_bottom(UWORD8 *pu1_src,\n                      WORD32 src_strd,\n                      WORD32 wd,\n                      WORD32 pad_size)\n{\n    WORD32 row;\n\n    for(row = 1; row <= pad_size; row++)\n    {\n        memcpy(pu1_src + (row - 1) * src_strd, pu1_src - 1 * src_strd, wd);\n    }\n}\n\n/**\n*******************************************************************************\n*\n* @brief pad (luma block) at the left of a 2d array\n*\n* @par Description:\n*   The left column of a 2d array is replicated for pad_size times to the left\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] pad_size\n*  integer -padding size of the array\n*\n* @returns none\n*\n* @remarks none\n*\n*******************************************************************************\n */\nvoid ih264_pad_left_luma(UWORD8 *pu1_src,\n                         WORD32 src_strd,\n                         WORD32 ht,\n                         WORD32 pad_size)\n{\n    WORD32 row;\n\n    for(row = 0; row < ht; row++)\n    {\n\n        memset(pu1_src - pad_size, *pu1_src, pad_size);\n\n        pu1_src += src_strd;\n    }\n}\n\n/**\n*******************************************************************************\n*\n* @brief pad (chroma block) at the left of a 2d array\n*\n* @par Description:\n*   The left column of a 2d array is replicated for pad_size times to the left\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] pad_size\n*  integer -padding size of the array\n*\n* @returns none\n*\n* @remarks none\n*\n*******************************************************************************\n*/\nvoid ih264_pad_left_chroma(UWORD8 *pu1_src,\n                           WORD32 src_strd,\n                           WORD32 ht,\n                           WORD32 pad_size)\n{\n    /* temp var */\n    WORD32 row, col;\n    UWORD16 u2_uv_val;\n\n    /* pointer to src */\n    UWORD16 *pu2_src = (UWORD16 *)pu1_src;\n\n    src_strd >>= 1;\n    pad_size >>= 1;\n\n    for(row = 0; row < ht; row++)\n    {\n        u2_uv_val = pu2_src[0];\n\n        for (col = -pad_size; col < 0; col++)\n        {\n            pu2_src[col] = u2_uv_val;\n        }\n\n        pu2_src += src_strd;\n    }\n}\n\n/**\n*******************************************************************************\n*\n* @brief pad (luma block) at the right of a 2d array\n*\n* @par Description:\n*  The right column of a 2d array is replicated for pad_size times at the right\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] pad_size\n*  integer -padding size of the array\n*\n* @returns none\n*\n* @remarks none\n*\n*******************************************************************************\n*/\nvoid ih264_pad_right_luma(UWORD8 *pu1_src,\n                          WORD32 src_strd,\n                          WORD32 ht,\n                          WORD32 pad_size)\n{\n    WORD32 row;\n\n    for(row = 0; row < ht; row++)\n    {\n        memset(pu1_src, *(pu1_src -1), pad_size);\n\n        pu1_src += src_strd;\n    }\n}\n\n/**\n*******************************************************************************\n*\n* @brief pad (chroma block) at the right of a 2d array\n*\n* @par Description:\n*  The right column of a 2d array is replicated for pad_size times at the right\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] pad_size\n*  integer -padding size of the array\n*\n* @returns none\n*\n* @remarks none\n*\n*******************************************************************************\n*/\nvoid ih264_pad_right_chroma(UWORD8 *pu1_src,\n                            WORD32 src_strd,\n                            WORD32 ht,\n                            WORD32 pad_size)\n{\n    WORD32 row, col;\n    UWORD16 u2_uv_val;\n    UWORD16 *pu2_src = (UWORD16 *)pu1_src;\n\n    src_strd >>= 1;\n    pad_size >>= 1;\n\n    for(row = 0; row < ht; row++)\n    {\n        u2_uv_val = pu2_src[-1];\n\n        for (col = 0; col < pad_size; col++)\n        {\n            pu2_src[col] = u2_uv_val;\n        }\n\n        pu2_src += src_strd;\n    }\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_padding.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/**\n*******************************************************************************\n* @file\n*  ih264_padding.h\n*\n* @brief\n*  Declarations for padding functions\n*\n* @author\n*  Ittiam\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n#ifndef _IH264_PADDING_H_\n#define _IH264_PADDING_H_\n\n/*****************************************************************************/\n/* Function Declarations                                                     */\n/*****************************************************************************/\n\ntypedef void ih264_pad(UWORD8 *, WORD32, WORD32, WORD32);\n\n/* C function declarations */\nih264_pad ih264_pad_top;\nih264_pad ih264_pad_bottom;\nih264_pad ih264_pad_left_luma;\nih264_pad ih264_pad_left_chroma;\nih264_pad ih264_pad_right_luma;\nih264_pad ih264_pad_right_chroma;\n\n/* A9 Q function declarations */\nih264_pad ih264_pad_top_a9q;\nih264_pad ih264_pad_left_luma_a9q;\nih264_pad ih264_pad_left_chroma_a9q;\nih264_pad ih264_pad_right_luma_a9q;\nih264_pad ih264_pad_right_chroma_a9q;\n\n/* AV8 function declarations */\nih264_pad ih264_pad_top_av8;\nih264_pad ih264_pad_left_luma_av8;\nih264_pad ih264_pad_left_chroma_av8;\nih264_pad ih264_pad_right_luma_av8;\nih264_pad ih264_pad_right_chroma_av8;\n\n\nih264_pad ih264_pad_left_luma_ssse3;\nih264_pad ih264_pad_left_chroma_ssse3;\nih264_pad ih264_pad_right_luma_ssse3;\nih264_pad ih264_pad_right_chroma_ssse3;\n\n#endif /*_IH264_PADDING_H_*/\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_resi_trans.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_resi_trans.h\n*\n* @brief\n*  Functions declarations for residue and forward transform\n*\n* @par List of Functions:\n*  - ih264_resi_trans_ft\n*  - ih264_resi_trans_4x4\n*  - ih264_resi_trans_4x4\n*  - ih264_resi_trans_4x4_a9\n*  - ih264_resi_trans_4x4_a9\n*\n* @author\n*  Ittiam\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n#ifndef IH264_RESI_TRANS_H_\n#define IH264_RESI_TRANS_H_\n\n/*****************************************************************************/\n/* Extern Function Declarations                                              */\n/*****************************************************************************/\n\ntypedef void ih264_resi_trans_ft(UWORD8 *pu1_src,\n                                 UWORD8 *pu1_pred,\n                                 WORD32 *pi4_out,\n                                 WORD32 src_strd,\n                                 WORD32 pred_strd,\n                                 WORD32 out_strd);\n\n/*C functions*/\n\nih264_resi_trans_ft ih264_resi_trans_4x4;\n\nih264_resi_trans_ft ih264_resi_trans_8x8;\n\n/*A9 functions*/\n\nih264_resi_trans_ft ih264_resi_trans_4x4_a9;\n\nih264_resi_trans_ft ih264_resi_trans_8x8_a9;\n\n#endif /* IH264_RESI_TRANS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_resi_trans_quant.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_resi_trans_quant.c\n *\n * @brief\n *  Contains function definitions single stage  forward transform for H.264\n *  It will calculate the residue, do the cf and then do quantization\n *\n * @author\n *  Ittiam\n *\n * @par List of Functions:\n *  - ih264_resi_trans_quant_4x4()\n *  - ih264_resi_trans_quant_chroma_4x4\n *  - ih264_hadamard_quant_4x4\n *  - ih264_hadamard_quant_2x2_uv\n *  - ih264_resi_trans_quant_8x8\n *\n * @remarks\n *******************************************************************************\n */\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System include files */\n#include <stddef.h>\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_trans_macros.h\"\n#include \"ih264_trans_data.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n\n/**\n *******************************************************************************\n *\n * @brief\n *   This function performs forward transform and quantization on a 4*4 block\n *\n * @par Description:\n *   The function accepts source buffer and estimation buffer. From these, it\n *   computes the residue. This is residue is then transformed and quantized.\n *   The transform and quantization are in placed computed. They use the residue\n *   buffer for this.\n *\n * @param[in] pu1_src\n *   Pointer to source sub-block\n *\n * @param[in] pu1_pred\n *   Pointer to prediction sub-block\n *\n * @param[in] pi2_out\n *   Pointer to residual sub-block\n *\n * @param[in] src_strd\n *   Source stride\n *\n * @param[in] pred_strd\n *   Prediction stride\n *\n * @param[in] dst_strd\n *   Destination stride\n *\n * @param[in] u4_qbits\n *    QP_BITS_h264_4x4 + floor(QP/6)\n *\n * @param[in] pu2_threshold_matrix\n *   Pointer to Forward Quant Threshold Matrix\n *\n * @param[in] pu2_scale_matrix\n *   Pointer to Forward Quant Scale Matrix\n *\n * @param[in] u4_round_factor\n *   Quantization Round factor\n *\n * @param[out] pu1_nnz\n *   Total non-zero coefficients in the current sub-block\n *\n * @returns\n *\n * @remarks\n *   None\n *\n *******************************************************************************\n */\nvoid ih264_resi_trans_quant_4x4(UWORD8 *pu1_src,\n                                UWORD8 *pu1_pred,\n                                WORD16 *pi2_out,\n                                WORD32 src_strd,\n                                WORD32 pred_strd,\n                                const UWORD16 *pu2_scale_matrix,\n                                const UWORD16 *pu2_threshold_matrix,\n                                UWORD32 u4_qbits,\n                                UWORD32 u4_round_factor,\n                                UWORD8 *pu1_nnz,\n                                WORD16 *pi2_alt_dc_addr)\n{\n    UWORD32 i;\n    WORD32  x0, x1, x2, x3, x4, x5, x6, x7;\n    WORD32  i4_value, i4_sign;\n    UWORD32 u4_abs_value;\n    WORD16  *pi2_out_tmp = pi2_out;\n    UWORD32 u4_nonzero_coeff = 0;\n\n    for (i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        /* computing prediction error (residue) */\n        x4 = pu1_src[0] - pu1_pred[0];\n        x5 = pu1_src[1] - pu1_pred[1];\n        x6 = pu1_src[2] - pu1_pred[2];\n        x7 = pu1_src[3] - pu1_pred[3];\n\n        /* Horizontal transform */\n        x0 = x4 + x7;\n        x1 = x5 + x6;\n        x2 = x5 - x6;\n        x3 = x4 - x7;\n\n        pi2_out_tmp[0] = x0 + x1;\n        pi2_out_tmp[1] = (x3 <<1) + x2;\n        pi2_out_tmp[2] = x0 - x1;\n        pi2_out_tmp[3] = x3 - (x2<<1);\n\n        /* pointing to next row; */\n        pu1_src += src_strd;\n        pu1_pred += pred_strd;\n        pi2_out_tmp += 4;\n\n    }\n    pi2_out_tmp = pi2_out;\n    for (i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n\n        /* Vertical transform and quantization */\n        x4 = pi2_out_tmp[0];\n        x5 = pi2_out_tmp[4];\n        x6 = pi2_out_tmp[8];\n        x7 = pi2_out_tmp[12];\n\n\n        x0 = x4 + x7;\n        x1 = x5 + x6;\n        x2 = x5 - x6;\n        x3 = x4 - x7;\n\n        /* quantization is done in place */\n\n        i4_value = x0 + x1;\n\n        if(i==0)\n        {\n          (*pi2_alt_dc_addr) = i4_value;\n        }\n\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[0], pu2_scale_matrix[0], u4_round_factor, u4_qbits, u4_nonzero_coeff);\n        pi2_out_tmp[0] = i4_value;\n\n\n        i4_value = (x3 << 1) + x2;\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[4], pu2_scale_matrix[4], u4_round_factor, u4_qbits, u4_nonzero_coeff);\n        pi2_out_tmp[4] = i4_value;\n\n\n        i4_value = x0 - x1;\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[8], pu2_scale_matrix[8], u4_round_factor, u4_qbits, u4_nonzero_coeff);\n        pi2_out_tmp[8] = i4_value;\n\n\n        i4_value = x3 - (x2 << 1);\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[12], pu2_scale_matrix[12], u4_round_factor, u4_qbits, u4_nonzero_coeff);\n        pi2_out_tmp[12] = i4_value;\n\n        pi2_out_tmp ++;\n        pu2_scale_matrix++;\n        pu2_threshold_matrix++;\n    }\n\n    /* Return total nonzero coefficients in the current sub block */\n    *pu1_nnz =  u4_nonzero_coeff;\n}\n/**\n *******************************************************************************\n *\n * @brief\n *   This function performs forward transform and quantization on a 4*4 chroma block\n *   with interleaved values\n *\n * @par Description:\n *   The function accepts source buffer and estimation buffer. From these, it\n *   computes the residue. This is residue is then transformed and quantized.\n *   The transform and quantization are in placed computed. They use the residue\n *   buffer for this.\n *\n * @param[in] pu1_src\n *   Pointer to source sub-block\n *\n * @param[in] pu1_pred\n *   Pointer to prediction sub-block\n *\n * @param[in] pi2_out\n *   Pointer to residual sub-block\n *\n * @param[in] src_strd\n *   Source stride\n *\n * @param[in] pred_strd\n *   Prediction stride\n *\n * @param[in] dst_strd\n *   Destination stride\n *\n * @param[in] u4_qbits\n *    QP_BITS_h264_4x4 + floor(QP/6)\n *\n * @param[in] pu2_threshold_matrix\n *   Pointer to Forward Quant Threshold Matrix\n *\n * @param[in] pu2_scale_matrix\n *   Pointer to Forward Quant Scale Matrix\n *\n * @param[in] u4_round_factor\n *   Quantization Round factor\n *\n * @param[out] pu1_nnz\n *   Total non-zero coefficients in the current sub-block\n *\n * @returns\n *\n * @remarks\n *   None\n *\n *******************************************************************************\n */\nvoid ih264_resi_trans_quant_chroma_4x4(UWORD8 *pu1_src,\n                                       UWORD8 *pu1_pred,\n                                       WORD16 *pi2_out,\n                                       WORD32 src_strd,\n                                       WORD32 pred_strd,\n                                       const UWORD16 *pu2_scale_matrix,\n                                       const UWORD16 *pu2_threshold_matrix,\n                                       UWORD32 u4_qbits,\n                                       UWORD32 u4_round_factor,\n                                       UWORD8 *pu1_nnz,\n                                       WORD16 *pu1_dc_alt_addr)\n{\n    UWORD32 i;\n    WORD32  x0, x1, x2, x3, x4, x5, x6, x7;\n    WORD32  i4_value, i4_sign;\n    UWORD32 u4_abs_value;\n    WORD16  *pi2_out_tmp = pi2_out;\n    UWORD32 u4_nonzero_coeff = 0;\n\n    for (i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        /* computing prediction error (residue) */\n        x4 = pu1_src[0] - pu1_pred[0];\n        x5 = pu1_src[2] - pu1_pred[2];\n        x6 = pu1_src[4] - pu1_pred[4];\n        x7 = pu1_src[6] - pu1_pred[6];\n\n        /* Horizontal transform */\n        x0 = x4 + x7;\n        x1 = x5 + x6;\n        x2 = x5 - x6;\n        x3 = x4 - x7;\n\n        pi2_out_tmp[0] = x0 + x1;\n        pi2_out_tmp[1] = (x3 <<1) + x2;\n        pi2_out_tmp[2] = x0 - x1;\n        pi2_out_tmp[3] = x3 - (x2<<1);\n\n        /* pointing to next row; */\n        pu1_src += src_strd;\n        pu1_pred += pred_strd;\n        pi2_out_tmp += 4;\n\n    }\n    pi2_out_tmp = pi2_out;\n    for (i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n\n        /* Vertical transform and quantization */\n        x4 = pi2_out_tmp[0];\n        x5 = pi2_out_tmp[4];\n        x6 = pi2_out_tmp[8];\n        x7 = pi2_out_tmp[12];\n\n\n        x0 = x4 + x7;\n        x1 = x5 + x6;\n        x2 = x5 - x6;\n        x3 = x4 - x7;\n\n        /* quantization is done in place */\n\n        i4_value = x0 + x1;\n\n        if(i==0)\n        {\n          *pu1_dc_alt_addr = i4_value;\n        }\n\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[0],\n                  pu2_scale_matrix[0], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[0] = i4_value;\n\n        i4_value = (x3 << 1) + x2;\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[4],\n                  pu2_scale_matrix[4], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[4] = i4_value;\n\n        i4_value = x0 - x1;\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[8],\n                  pu2_scale_matrix[8], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[8] = i4_value;\n\n        i4_value = x3 - (x2 << 1);\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[12],\n                  pu2_scale_matrix[12], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[12] = i4_value;\n\n        pi2_out_tmp ++;\n        pu2_scale_matrix++;\n        pu2_threshold_matrix++;\n    }\n\n    /* Return total nonzero coefficients in the current sub block */\n    *pu1_nnz =  u4_nonzero_coeff;\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *   This function performs forward hadamard transform and quantization on a 4*4 block\n *\n * @par Description:\n *   The function accepts source buffer and estimation buffer. From these, it\n *   computes the residue. This is residue is then transformed and quantized.\n *   The transform and quantization are in placed computed. They use the residue\n *   buffer for this.\n *\n * @param[in] pu1_src\n *   Pointer to source sub-block\n *\n * @param[in] pu1_pred\n *   Pointer to prediction sub-block\n *\n * @param[in] pi2_out\n *   Pointer to residual sub-block\n *\n * @param[in] src_strd\n *   Source stride\n *\n * @param[in] pred_strd\n *   Prediction stride\n *\n * @param[in] dst_strd\n *   Destination stride\n *\n * @param[in] u4_qbits\n *    QP_BITS_h264_4x4 + floor(QP/6)\n *\n * @param[in] pu2_threshold_matrix\n *   Pointer to Forward Quant Threshold Matrix\n *\n * @param[in] pu2_scale_matrix\n *   Pointer to Forward Quant Scale Matrix\n *\n * @param[in] u4_round_factor\n *   Quantization Round factor\n *\n * @param[out] pu1_nnz\n *   Total non-zero coefficients in the current sub-block\n *\n * @returns\n *\n * @remarks\n *   None\n *\n */\n\nvoid ih264_hadamard_quant_4x4(WORD16 *pi2_src,\n                              WORD16 *pi2_dst,\n                              const UWORD16 *pu2_scale_matrix,\n                              const UWORD16 *pu2_threshold_matrix,\n                              UWORD32 u4_qbits,\n                              UWORD32 u4_round_factor,\n                              UWORD8 *pu1_nnz)\n{\n  WORD32 i;\n  WORD32 x0,x1,x2,x3,x4,x5,x6,x7,i4_value;\n  UWORD32 u4_abs_value;\n  WORD32 i4_sign;\n\n  *pu1_nnz = 0;\n\n  for (i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        x4 = pi2_src[0];\n        x5 = pi2_src[1];\n        x6 = pi2_src[2];\n        x7 = pi2_src[3];\n\n        x0 = x4 + x7;\n        x1 = x5 + x6;\n        x2 = x5 - x6;\n        x3 = x4 - x7;\n\n        pi2_dst[0] = x0 + x1;\n        pi2_dst[1] = x3 + x2;\n        pi2_dst[2] = x0 - x1;\n        pi2_dst[3] = x3 - x2;\n\n        pi2_src += 4;\n        pi2_dst += 4;\n    }\n\n    /* Vertical transform and quantization */\n    pi2_dst -= SUB_BLK_WIDTH_4x4<<2;\n\n    for (i = 0; i < SUB_BLK_WIDTH_4x4; i++)\n    {\n        x4 = pi2_dst[0];\n        x5 = pi2_dst[4];\n        x6 = pi2_dst[8];\n        x7 = pi2_dst[12] ;\n\n        x0 = x4 + x7;\n        x1 = x5 + x6;\n        x2 = x5 - x6;\n        x3 = x4 - x7;\n\n\n        i4_value = (x0 + x1) >> 1;\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[0],\n                  pu2_scale_matrix[0], u4_round_factor, u4_qbits, pu1_nnz[0]);\n        pi2_dst[0] = i4_value;\n\n        i4_value = (x3 + x2) >> 1;\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[0],\n                  pu2_scale_matrix[0], u4_round_factor, u4_qbits, pu1_nnz[0]);\n        pi2_dst[4] = i4_value;\n\n        i4_value = (x0 - x1) >> 1;\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[0],\n                  pu2_scale_matrix[0], u4_round_factor, u4_qbits, pu1_nnz[0]);\n        pi2_dst[8] = i4_value;\n\n        i4_value = (x3 - x2) >> 1;\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[0],\n                  pu2_scale_matrix[0], u4_round_factor, u4_qbits, pu1_nnz[0]);\n        pi2_dst[12] = i4_value;\n\n        pi2_dst ++;\n    }\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *   This function performs forward hadamard transform and quantization on a 2*2 block\n *   for both U and V planes\n *\n * @par Description:\n *   The function accepts source buffer and estimation buffer. From these, it\n *   computes the residue. This is residue is then transformed and quantized.\n *   The transform and quantization are in placed computed. They use the residue\n *   buffer for this.\n *\n * @param[in] pu1_src\n *   Pointer to source sub-block\n *\n * @param[in] pu1_pred\n *   Pointer to prediction sub-block\n *\n * @param[in] pi2_out\n *   Pointer to residual sub-block\n *\n * @param[in] src_strd\n *   Source stride\n *\n * @param[in] pred_strd\n *   Prediction stride\n *\n * @param[in] dst_strd\n *   Destination stride\n *\n * @param[in] u4_qbits\n *    QP_BITS_h264_4x4 + floor(QP/6)\n *\n * @param[in] pu2_threshold_matrix\n *   Pointer to Forward Quant Threshold Matrix\n *\n * @param[in] pu2_scale_matrix\n *   Pointer to Forward Quant Scale Matrix\n *\n * @param[in] u4_round_factor\n *   Quantization Round factor\n *\n * @param[out] pu1_nnz\n *   Total non-zero coefficients in the current sub-block\n *\n * @returns\n *\n * @remarks\n *   NNZ for dc is populated at 0 and 5th position of pu1_nnz\n *\n */\n\nvoid ih264_hadamard_quant_2x2_uv(WORD16 *pi2_src,\n                                 WORD16 *pi2_dst,\n                                 const UWORD16 *pu2_scale_matrix,\n                                 const UWORD16 *pu2_threshold_matrix,\n                                 UWORD32 u4_qbits,\n                                 UWORD32 u4_round_factor,\n                                 UWORD8 *pu1_nnz)\n{\n    WORD32 x0, x1, x2, x3, x4, x5, x6, x7;\n    WORD32 i4_value, i4_sign, plane;\n    UWORD32 u4_abs_value;\n\n    for(plane = 0; plane < 2; plane++)\n    {\n        pu1_nnz[plane] = 0;\n\n        /* Horizontal transform */\n        x4 = pi2_src[0];\n        x5 = pi2_src[1];\n        x6 = pi2_src[2];\n        x7 = pi2_src[3];\n\n        x0 = x4 + x5;\n        x1 = x4 - x5;\n        x2 = x6 + x7;\n        x3 = x6 - x7;\n\n        /* Vertical transform and quantization */\n        i4_value = (x0 + x2);\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[0],\n                  pu2_scale_matrix[0], u4_round_factor, u4_qbits,\n                  pu1_nnz[plane]);\n        pi2_dst[0] = i4_value;\n\n        i4_value = (x0 - x2);\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[0],\n                  pu2_scale_matrix[0], u4_round_factor, u4_qbits,\n                  pu1_nnz[plane]);\n        pi2_dst[2] = i4_value;\n\n        i4_value = (x1 - x3);\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[0],\n                  pu2_scale_matrix[0], u4_round_factor, u4_qbits,\n                  pu1_nnz[plane]);\n        pi2_dst[3] = i4_value;\n\n        i4_value = (x1 + x3);\n        FWD_QUANT(i4_value, u4_abs_value, i4_sign, pu2_threshold_matrix[0],\n                  pu2_scale_matrix[0], u4_round_factor, u4_qbits,\n                  pu1_nnz[plane]);\n        pi2_dst[1] = i4_value;\n\n        pi2_dst += 4;\n        pi2_src += 4;\n\n    }\n}\n\n/*\n *******************************************************************************\n *\n * @brief\n *  This function performs Single stage forward transform CF8 and quantization on 8*8 blocks\n *  for h.264\n *\n * @par Description:\n *  Performs single stage 8x8 forward transform CF8 after calculating the residue\n *  The result is then quantized\n *\n * @param[in] pu1_src\n *  Input 8x8 pixels\n *\n * @param[in] pu1_pred\n *  Input 8x8 pixels\n *\n * @param[in] pi1_out\n * Output 8x8 pixels\n *\n * @param[in] u4_thresh\n *  Threshold under which the coeffs are not quantized\n *\n *  @param[in] u4_qp_div\n *  QP/6\n *\n *  @param[in] u4_qp_rem\n *  QP%6\n *\n * @param[in] u2_src_stride\n *  Source stride\n *\n * @param[in] pred_strd\n * stride for prediciton buffer\n *\n *  @param[in] dst_strd\n *  stride for destination buffer\n *\n *  @param[in] pu4_quant_mat\n *  Pointer to the 4x4 quantization matrix\n *\n * @returns  Void\n *\n *\n *******************************************************************************\n */\nvoid ih264_resi_trans_quant_8x8(UWORD8 *pu1_src,\n                                UWORD8 *pu1_pred,\n                                WORD16 *pi2_out,\n                                WORD32 src_strd,\n                                WORD32 pred_strd,\n                                const UWORD16 *pu2_scale_matrix,\n                                const UWORD16 *pu2_threshold_matrix,\n                                UWORD32 u4_qbits,\n                                UWORD32 u4_round_factor,\n                                UWORD8 *pu1_nnz,\n                                WORD16 *pu1_dc_alt_addr)\n\n{\n    WORD16 *pi2_out_tmp = pi2_out;\n    UWORD32 i;\n    WORD32 a0, a1, a2, a3, a4, a5, a6, a7;\n    WORD32 r0, r1, r2, r3, r4, r5, r6, r7;\n    WORD32 i4_sign;\n    UWORD32 u4_abs_value;\n    UWORD32 u4_nonzero_coeff = 0;\n\n    UNUSED(pu1_dc_alt_addr);\n\n    /*Horizontal transform */\n    /* we are going to use the a's and r's in a twisted way since */\n    /*i dont want to declare more variables */\n    for(i = 0; i < SUB_BLK_WIDTH_8x8; ++i)\n    {\n        r0 = pu1_src[0];\n        r0 -= pu1_pred[0];\n        r1 = pu1_src[1];\n        r1 -= pu1_pred[1];\n        r2 = pu1_src[2];r2 -= pu1_pred[2];\n        r3 = pu1_src[3];r3 -= pu1_pred[3];\n        r4 = pu1_src[4];r4 -= pu1_pred[4];\n        r5 = pu1_src[5];r5 -= pu1_pred[5];\n        r6 = pu1_src[6];r6 -= pu1_pred[6];\n        r7 = pu1_src[7];r7 -= pu1_pred[7];\n\n\n        a0 = r0 + r7;\n        a1 = r1 + r6;\n        a2 = r2 + r5;\n        a3 = r3 + r4;\n\n        a4 = a0 + a3;\n        a5 = a1 + a2;\n        a6 = a0 - a3;\n        a7 = a1 - a2;\n\n        pi2_out_tmp[0] = a4 + a5;\n\n        pi2_out_tmp[2] = a6 + (a7>>1);\n        pi2_out_tmp[4] = a4 - a5;\n        pi2_out_tmp[6] = (a6>>1) - a7;\n\n        a0 = r0 - r7;\n        a1 = r1 - r6;\n        a2 = r2 - r5;\n        a3 = r3 - r4;\n\n        a4 = a1 + a2 + ((a0>>1) + a0);\n        a5 = a0 - a3 - ((a2>>1) + a2);\n        a6 = a0 + a3 - ((a1>>1) + a1);\n        a7 = a1 - a2 + ((a3>>1) + a3);\n\n        pi2_out_tmp[1] = a4 + (a7>>2);\n        pi2_out_tmp[3] = a5 + (a6>>2);\n        pi2_out_tmp[5] = a6 - (a5>>2);\n        pi2_out_tmp[7] = (a4>>2) - a7;\n\n        pu1_src += src_strd;\n        pu1_pred += pred_strd;\n        pi2_out_tmp += 8;\n    }\n\n    /*vertical transform and quant */\n\n    pi2_out_tmp = pi2_out;\n\n    for (i = 0; i < SUB_BLK_WIDTH_8x8; ++i)\n    {\n\n        r0 = pi2_out_tmp[0];\n        r1 = pi2_out_tmp[8];\n        r2 = pi2_out_tmp[16];\n        r3 = pi2_out_tmp[24];\n        r4 = pi2_out_tmp[32];\n        r5 = pi2_out_tmp[40];\n        r6 = pi2_out_tmp[48];\n        r7 = pi2_out_tmp[56];\n\n        a0 = r0 + r7;\n        a1 = r1 + r6;\n        a2 = r2 + r5;\n        a3 = r3 + r4;\n\n        a4 = a0 + a3;\n        a5 = a1 + a2;\n        a6 = a0 - a3;\n        a7 = a1 - a2;\n\n        a0 = r0 - r7;\n        a1 = r1 - r6;\n        a2 = r2 - r5;\n        a3 = r3 - r4;\n\n        r0 = a4 + a5;\n        r2 = a6 + (a7>>1);\n        r4 = a4 - a5;\n        r6 = (a6>>1) - a7;\n\n        a4 = a1 + a2 + ((a0>>1) + a0);\n        a5 = a0 - a3 - ((a2>>1) + a2);\n        a6 = a0 + a3 - ((a1>>1) + a1);\n        a7 = a1 - a2 + ((a3>>1) + a3);\n\n        r1 = a4 + (a7>>2);\n        r3 = a5 + (a6>>2);\n        r5 = a6 - (a5>>2);\n        r7 = (a4>>2) - a7;\n\n        FWD_QUANT(r0, u4_abs_value, i4_sign, pu2_threshold_matrix[0],\n                  pu2_scale_matrix[0], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[0] = r0;\n\n        FWD_QUANT(r1, u4_abs_value, i4_sign, pu2_threshold_matrix[8],\n                  pu2_scale_matrix[8], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[8] = r1;\n\n        FWD_QUANT(r2, u4_abs_value, i4_sign, pu2_threshold_matrix[16],\n                  pu2_scale_matrix[16], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[16] = r2;\n\n        FWD_QUANT(r3, u4_abs_value, i4_sign, pu2_threshold_matrix[24],\n                  pu2_scale_matrix[24], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[24] = r3;\n\n        FWD_QUANT(r4, u4_abs_value, i4_sign, pu2_threshold_matrix[32],\n                  pu2_scale_matrix[32], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[32] = r4;\n\n        FWD_QUANT(r5, u4_abs_value, i4_sign, pu2_threshold_matrix[40],\n                  pu2_scale_matrix[40], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[40] = r5;\n\n        FWD_QUANT(r6, u4_abs_value, i4_sign, pu2_threshold_matrix[48],\n                  pu2_scale_matrix[48], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[48] = r6;\n\n        FWD_QUANT(r7, u4_abs_value, i4_sign, pu2_threshold_matrix[56],\n                  pu2_scale_matrix[56], u4_round_factor, u4_qbits,\n                  u4_nonzero_coeff);\n        pi2_out_tmp[56] = r7;\n\n        pi2_out_tmp++;\n        pu2_scale_matrix++;\n        pu2_threshold_matrix++;\n    }\n       /* Return total nonzero coefficients in the current sub block */\n        *pu1_nnz =  u4_nonzero_coeff;\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_size_defs.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_size_defs.h\n *\n * @brief\n *  Contains declaration of global variables for H264 transform , quant and inverse quant\n *\n * @author\n *  Ittiam\n *\n * @remarks\n *\n ********************************************************************************/\n\n#ifndef IH264_SIZE_DEFS_H_\n#define IH264_SIZE_DEFS_H_\n\n/*****************************************************************************/\n/* Constant Macros                                                           */\n/*****************************************************************************/\n\n/*-----------------------Primary defs--------------------------*/\n\n/*Width of a 4x4 block*/\n#define SUB_BLK_WIDTH_4x4                   4\n\n/*Width of an 8x8 block*/\n#define SUB_BLK_WIDTH_8x8                   8\n\n/*Number of chroma blocks in a row of coffs*/\n#define SUB_BLK_COUNT_CHROMA_4x4_420        2\n\n/*Number of luma blocks in a row of coffs*/\n#define SUB_BLK_COUNT_LUMA_4x4              4\n\n/*Numbr of chroma planes*/\n#define NUM_CHROMA_PLANES                   2\n\n/*Constant bit shifts*/\n#define QP_BITS_h264_4x4                    15\n#define QP_BITS_h264_8x8                    16\n\n\n/*---------------------------Derived defs------------------------*/\n\n/*Number of coefficients ina 4x4 block*/\n#define COFF_CNT_SUB_BLK_4x4                SUB_BLK_WIDTH_4x4*SUB_BLK_WIDTH_4x4;\n\n/*Number of luma blocks in a row of coffs*/\n#define SUB_BLK_LUMA_4X4_CNT_MB             SUB_BLK_COUNT_LUMA_4x4 * SUB_BLK_COUNT_LUMA_4x4\n\n/*Number of chroma coffs in an MB*/\n#define SUB_BLK_CHROMA_4X4_CNT_MB           SUB_BLK_COUNT_CHROMA_4x4_420 * SUB_BLK_COUNT_CHROMA_4x4_420\n#define SUB_BLK_CHROMA_4X4_CNT_MB_BIPLANE   SUB_BLK_CHROMA_4X4_CNT_MB*NUM_CHROMA_PLANES\n\n/*Size of trans buff = 4x4 for DC block +  4x4 * coffs for 4x4 ac blocks*/\n#define SIZE_TRANS_BUFF                     (SUB_BLK_WIDTH_4x4*SUB_BLK_WIDTH_4x4*+ \\\n                                            SUB_BLK_WIDTH_4x4*SUB_BLK_WIDTH_4x4*   \\\n                                            SUB_BLK_COUNT_LUMA_4x4*SUB_BLK_COUNT_LUMA_4x4)\n\n/*memory size = memory size of 4x4 block of resi coff + 4x4 for DC coff block                          */\n#define SIZE_TMP_BUFF_ITRANS                ((SUB_BLK_WIDTH_4x4*SUB_BLK_WIDTH_4x4) +\\\n                                             (SUB_BLK_WIDTH_4x4*SUB_BLK_WIDTH_4x4))\n\n#endif /* IH264_DEFS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_structs.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/**\n *******************************************************************************\n * @file\n *  ih264_structs.h\n *\n * @brief\n *  Structure definitions used in the code\n *\n * @author\n *  Ittiam\n *\n * @par List of Functions:\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n#ifndef _IH264_STRUCTS_H_\n#define _IH264_STRUCTS_H_\n\n/** MB Type info for Intra MBs */\ntypedef struct\n{\n    UWORD32             u4_num_mbpart;\n    MBPART_PREDMODE_T   e_mbpart_predmode;\n    MBMODES_I16x16      e_intra_predmode;\n    UWORD32             u4_cpb_chroma;\n    UWORD32             u4_cpb_luma;\n}intra_mbtype_info_t;\n\n/** MB Type info for Inter MBs */\ntypedef struct\n{\n    UWORD32                 u4_num_mbpart;\n    MBPART_PREDMODE_T       e_mbpart_predmode_0;\n    MBPART_PREDMODE_T       e_mbpart_predmode_1;\n    UWORD32                 u4_mbpart_wd;\n    UWORD32                 u4_mbpart_ht;\n}inter_mbtype_info_t;\n\n\n/** Sub MB Type info for Inter MBs */\ntypedef struct\n{\n    UWORD32                 u4_num_mbpart;\n    MBPART_PREDMODE_T       e_mbpart_predmode;\n    UWORD32                 u4_mbpart_wd;\n    UWORD32                 u4_mbpart_ht;\n}submbtype_info_t;\n\n/**\n * Picture buffer\n */\ntypedef struct\n{\n    UWORD8* pu1_luma;\n    UWORD8* pu1_chroma;\n\n    WORD32 i4_abs_poc;\n    WORD32 i4_poc_lsb;\n\n\n    /** Lower 32 bit of time stamp */\n    UWORD32 u4_timestamp_low;\n\n    /** Upper 32 bit of time stamp */\n    UWORD32 u4_timestamp_high;\n\n    WORD32 i4_used_as_ref;\n\n    /**\n     * frame_num in the slice header\n     */\n    WORD32 i4_frame_num;\n\n    /**\n     * Long-term frame idx\n     * TODO: store in frame_num\n     */\n    WORD32 i4_long_term_frame_idx;\n\n    /*\n     *  0: Top Field\n     *  1: Bottom Field\n     */\n    WORD8   i1_field_type;\n\n    /**\n     * buffer ID from frame buffer manager\n     */\n    WORD32 i4_buf_id;\n\n} pic_buf_t;\n\n\n/**\n * Reference List\n */\ntypedef struct\n{\n    void *pv_pic_buf;\n\n    void *pv_mv_buf;\n\n} ref_list_t;\n\n\n/**\n * Motion vector\n */\ntypedef struct\n{\n    /**\n     * Horizontal Motion Vector\n     */\n    WORD16 i2_mvx;\n\n    /**\n     * Vertical Motion Vector\n     */\n    WORD16 i2_mvy;\n} mv_t;\n\n/*****************************************************************************/\n/* Following results in packed 48 bit structure. If mv_t included            */\n/*  ref_pic_buf_id, then 8 bits will be wasted for each mv for aligning.     */\n/*  Also using mv_t as elements directly instead of a pointer to l0 and l1   */\n/*  mvs. Since pointer takes 4 bytes and MV itself is 4 bytes. It does not   */\n/*  really help using pointers.                                              */\n/*****************************************************************************/\n\n/**\n * PU Motion Vector info\n */\ntypedef struct\n{\n    /**\n     *  L0 Motion Vector\n     */\n    mv_t s_l0_mv;\n\n    /**\n     *  L1 Motion Vector\n     */\n    mv_t s_l1_mv;\n\n    /**\n     *  L0 Ref index\n     */\n    WORD8   i1_l0_ref_idx;\n\n    /**\n     *  L1 Ref index\n     */\n    WORD8   i1_l1_ref_idx;\n\n    /**\n     *  L0 Ref Pic Buf ID\n     */\n    WORD8 i1_l0_ref_pic_buf_id;\n\n    /**\n     *  L1 Ref Pic Buf ID\n     */\n    WORD8 i1_l1_ref_pic_buf_id;\n\n} pu_mv_t;\n\n/**\n * PU information\n */\ntypedef struct\n{\n\n    /**\n     *  Motion Vectors\n     */\n    pu_mv_t     s_mv;\n\n    /**\n     *  PU X position in terms of min PU (4x4) units\n     */\n    UWORD32     b2_pos_x        : 2;\n\n    /**\n     *  PU Y position in terms of min PU (4x4) units\n     */\n    UWORD32     b2_pos_y        : 2;\n\n    /**\n     *  PU width in pixels = (b2_wd + 1) << 2\n     */\n    UWORD32     b2_wd           : 2;\n\n    /**\n     *  PU height in pixels = (b2_ht + 1) << 2\n     */\n    UWORD32     b2_ht           : 2;\n\n    /**\n     *  Intra or Inter flag for each partition - 0 or 1\n     */\n    UWORD32     b1_intra_flag   : 1;\n\n    /**\n     *  PRED_L0, PRED_L1, PRED_BI\n     */\n    UWORD32     b2_pred_mode    : 2;\n\n} pu_t;\n\n\n/**\n * MB information to be stored for entire frame\n */\ntypedef struct\n{\n    /**\n     * Transform sizes 0: 4x4, 1: 8x8,\n     */\n    UWORD32     b1_trans_size : 1;\n\n    /**\n     * CBP - 4 bits for Y, 1 for U and 1 for V\n     */\n    UWORD32     b6_cbp: 6;\n\n    /**\n     * Intra pred sizes  0: 4x4, 1: 8x8, 2: 16x16\n     */\n    UWORD32     b2_intra_pred_size : 2;\n\n    /**\n     * Flag to signal if the current MB is IPCM\n     */\n    UWORD32     b1_ipcm : 1;\n\n}mb_t;\n\n/*****************************************************************************/\n/* Info from last TU row of MB is stored in a row level neighbour buffer    */\n/* , which will be used for Boundary Strength computation                    */\n/*****************************************************************************/\n/**\n *  MB neighbor info\n */\ntypedef struct\n{\n    /**\n     *  Slice index of the mb\n     */\n    UWORD16 u2_slice_idx;\n\n    /*************************************************************************/\n    /* CBF of bottom TU row (replicated in 4 pixel boundary)                 */\n    /* MSB contains CBF of first TU in the last row and LSB contains CBF     */\n    /* of last TU in the last row                                            */\n    /*************************************************************************/\n    /**\n     * CBF of bottom TU row\n     */\n    UWORD16 u2_packed_cbf;\n\n    /*************************************************************************/\n    /* QP of bottom TU row (replicated at 8 pixel boundary (Since QP can     */\n    /* not change at less than min CU granularity)                           */\n    /*************************************************************************/\n    /**\n     * QP of bottom TU row\n     */\n    UWORD8 u1_qp;\n\n} mb_top_ny_info_t;\n\n/**\n *  MB level context\n */\ntypedef struct _mb_ctxt_t\n{\n    /*************************************************************************/\n    /* Tile boundary can be detected by looking at tile start x and tile     */\n    /* start y.  And based on the tile, slice and frame boundary the         */\n    /* following will be initialized.                                        */\n    /*************************************************************************/\n    /**\n     *  Pointer to left MB\n     */\n    /*  If not available, this will be set to NULL   */\n    struct _mb_ctxt_t *ps_mb_left;\n\n    /**\n     *  Pointer to top-left MB\n     */\n    /* If not available, this will be set to NULL   */\n    mb_top_ny_info_t *ps_mb_ny_topleft;\n\n    /**\n     *  Pointer to top MB\n     */\n    /* If not available, this will be set to NULL  */\n    mb_top_ny_info_t *ps_mb_ny_top;\n\n    /**\n     *  Pointer to top-right MB\n     */\n    /* If not available, this will be set to NULL */\n    mb_top_ny_info_t *ps_mb_ny_topright;\n\n    /*************************************************************************/\n    /* Pointer to PU data.                                                   */\n    /* This points to a MV Bank stored at frame level. Though this           */\n    /* pointer can be derived by reading offset at frame level, it is        */\n    /* stored here for faster access. Can be removed if storage of MB       */\n    /* structure is critical                                                 */\n    /*************************************************************************/\n    /**\n     * Pointer to PU data\n     */\n    pu_t *ps_pu;\n\n    /*************************************************************************/\n    /* Pointer to a PU map stored at frame level,                            */\n    /* Though this pointer can be derived by multiplying MB address with    */\n    /* number of minTUs in a MB, it is stored here for faster access.       */\n    /* Can be removed if storage of MB structure is critical                */\n    /*************************************************************************/\n    /**\n     * Pointer to a PU map stored at frame level\n     */\n    UWORD8 *pu1_pu_map;\n\n    /**\n     *  Number of TUs filled in as_tu\n     */\n    /*************************************************************************/\n    /* Having the first entry as 32 bit data, helps in keeping each of       */\n    /* the structures aligned to 32 bits at MB level                        */\n    /*************************************************************************/\n    WORD32 i4_tu_cnt;\n\n    /**\n     *  Pointer to transform coeff data\n     */\n    /*************************************************************************/\n    /* Following format is repeated for every coded TU                       */\n    /* Luma Block                                                            */\n    /* num_coeffs      : 16 bits                                             */\n    /* zero_cols       : 8 bits ( 1 bit per 4 columns)                       */\n    /* sig_coeff_map   : ((TU Size * TU Size) + 31) >> 5 number of WORD32s   */\n    /* coeff_data      : Non zero coefficients                               */\n    /* Cb Block (only for last TU in 4x4 case else for every luma TU)        */\n    /* num_coeffs      : 16 bits                                             */\n    /* zero_cols       : 8 bits ( 1 bit per 4 columns)                       */\n    /* sig_coeff_map   : ((TU Size * TU Size) + 31) >> 5 number of WORD32s   */\n    /* coeff_data      : Non zero coefficients                               */\n    /* Cr Block (only for last TU in 4x4 case else for every luma TU)        */\n    /* num_coeffs      : 16 bits                                             */\n    /* zero_cols       : 8 bits ( 1 bit per 4 columns)                       */\n    /* sig_coeff_map   : ((TU Size * TU Size) + 31) >> 5 number of WORD32s   */\n    /* coeff_data      : Non zero coefficients                               */\n    /*************************************************************************/\n    void            *pv_coeff_data;\n\n    /**\n     *  Slice to which the MB belongs to\n     */\n    WORD32 i4_slice_idx;\n\n    /**\n     *  MB column position\n     */\n    WORD32 i4_pos_x;\n\n    /**\n     *  MB row position\n     */\n    WORD32 i4_pos_y;\n\n    /**\n     *  Number of PUs filled in ps_pu\n     */\n    WORD32 i4_pu_cnt;\n\n    /**\n     *  Index of current PU being processed in ps_pu\n     */\n    /*  Scratch variable set to 0 at the start of any PU processing function */\n    WORD32 i4_pu_idx;\n\n    /**\n     * Vertical Boundary strength\n     */\n    /* Two bits per edge.\n    Stored in format. BS[15] | BS[14] | .. |BS[0]*/\n    UWORD32 *pu4_vert_bs;\n\n    /**\n     * Horizontal Boundary strength\n     */\n\n    /* Two bits per edge.\n    Stored in format. BS[15] | BS[14] | .. |BS[0]*/\n    UWORD32 *pu4_horz_bs;\n\n    /**\n     *  Qp array stored for each 8x8 pixels\n     */\n    UWORD8 *pu1_qp;\n\n    /**\n     *  Pointer to current frame's pu_t array\n     */\n    pu_t *ps_frm_pu;\n\n    /**\n     * Pointer to current frame's pu_t index array, which stores starting index\n     * of pu_t for every MB\n     */\n    UWORD32 *pu4_frm_pu_idx;\n\n    /**\n     *  Pointer to current frame's pu map array\n     */\n    UWORD8 *pu1_frm_pu_map;\n\n    /*************************************************************************/\n    /* Need to add encoder specific elements for identifying the order of    */\n    /* coding for CU, TU and PU if any                                       */\n    /*************************************************************************/\n} mb_ctxt_t;\n\n/*************************************************************************/\n/* The following describes how each of the CU cases are handled          */\n/*************************************************************************/\n\n/*************************************************************************/\n/* For SKIP MB                                                           */\n/* One Inter PU with appropriate MV                                      */\n/* One TU which says CBP is zero and size is 16x16                       */\n/*************************************************************************/\n\n/*************************************************************************/\n/* For Inter MB                                                          */\n/* M Inter PU with appropriate MVs (M between 1 to 4)                    */\n/* Number of TUs derived based on transform size                         */\n/*************************************************************************/\n\n/*************************************************************************/\n/* For Intra MB                                                          */\n/* Number of TUs derived based on transform size                         */\n/* N Intra Modes are signaled along with coeff data at the start        */\n/*************************************************************************/\n\n/*************************************************************************/\n/* For Intra PCM MB                                                      */\n/* One TU which says ipcm is 1                                           */\n/*************************************************************************/\n\n\n\n/**\n * Structure to hold quantization parameters of an mb\n */\ntypedef struct\n{\n\n    /*\n     * mb qp\n     */\n    UWORD8 u1_mb_qp;\n\n    /*\n     * mb qp / 6\n     */\n    UWORD8 u1_qp_div;\n\n    /*\n     * mb qp mod 6\n     */\n    UWORD8 u1_qp_rem;\n\n    /*\n     * QP bits\n     */\n    UWORD8  u1_qbits;\n\n    /*\n     * forward scale matrix\n     */\n    const UWORD16 *pu2_scale_mat;\n\n    /*\n     * threshold matrix for quantization\n     */\n    UWORD16 *pu2_thres_mat;\n\n    /*\n     * Threshold to compare the sad with\n     */\n    UWORD16 *pu2_sad_thrsh;\n\n    /*\n     * qp dependent rounding constant\n     */\n    UWORD32 u4_dead_zone;\n\n    /*\n     *  inverse scale matrix\n     */\n    const UWORD16 *pu2_iscale_mat;\n\n    /*\n     * Weight matrix in iquant\n     */\n    UWORD16 *pu2_weigh_mat;\n\n}quant_params_t;\n\n/**\n * Structure to hold Profile tier level info for a given layer\n */\n\ntypedef struct\n{\n    /**\n     *  NAL unit type\n     */\n    WORD8 i1_nal_unit_type;\n\n    /**\n     * NAL ref idc\n     */\n    WORD8 i1_nal_ref_idc;\n\n\n} nal_header_t;\n\n/**\n * HRD parameters Info\n */\ntypedef struct\n{\n    /**\n     * Specifies the number of alternative CPB specifications in the\n     * bitstream\n     */\n    UWORD8 u1_cpb_cnt_minus1;\n\n    /**\n    * (together with bit_rate_value_minus1) specifies the\n    * maximum input bit rate of the i-th CPB\n    */\n    UWORD32 u4_bit_rate_scale;\n\n    /**\n    * (together with cpb_size_du_value_minus1) specifies\n    * CPB size of the i-th CPB when the CPB operates\n    * at the access unit level\n    */\n    UWORD32 u4_cpb_size_scale;\n\n    /**\n     *  (together with bit_rate_scale) specifies the\n     *  maximum input bit rate for the i-th CPB\n     */\n    UWORD32 au4_bit_rate_value_minus1[32];\n    /**\n     *  together with cpb_size_scale to specify the\n     *  CPB size when the CPB operates at the access unit level.\n     */\n    UWORD32 au4_cpb_size_value_minus1[32];\n\n    /**\n     * if 1, specifies that the HSS operates in a constant bit rate (CBR) mode\n     * if 0, specifies that the HSS operates in a intermittent bit rate (CBR) mode\n     */\n    UWORD8  au1_cbr_flag[32];\n\n\n    /**\n    * specifies the length, in bits for initial cpb delay (nal/vcl)syntax in bp sei\n    */\n    UWORD8  u1_initial_cpb_removal_delay_length_minus1;\n\n    /**\n    * specifies the length, in bits for the cpb delay syntax in pt_sei\n    */\n    UWORD8  u1_cpb_removal_delay_length_minus1;\n\n    /**\n    * specifies the length, in bits, of the pic_dpb_output_delay syntax element in the pt SEI message\n    */\n    UWORD8  u1_dpb_output_delay_length_minus1;\n\n    /**\n     * Specifies length of the time offset parameter\n     */\n    UWORD8  u1_time_offset_length;\n\n}hrd_params_t;\n\n\n/**\n * Structure to hold VUI parameters Info\n */\ntypedef struct\n{\n    /**\n    *  indicates the presence of aspect_ratio\n    */\n    UWORD8 u1_aspect_ratio_info_present_flag;\n\n    /**\n    *  specifies the aspect ratio of the luma samples\n    */\n    UWORD8 u1_aspect_ratio_idc;\n\n    /**\n    *  width of the luma samples. user dependent\n    */\n    UWORD16 u2_sar_width;\n\n    /**\n    *  Height of the luma samples. user dependent\n    */\n    UWORD16 u2_sar_height;\n\n    /**\n    * if 1, specifies that the overscan_appropriate_flag is present\n    * if 0, the preferred display method for the video signal is unspecified\n    */\n    UWORD8 u1_overscan_info_present_flag;\n\n    /**\n    * if 1,indicates that the cropped decoded pictures output\n    * are suitable for display using overscan\n    */\n    UWORD8 u1_overscan_appropriate_flag;\n\n    /**\n    * if 1 specifies that video_format, video_full_range_flag and\n    * colour_description_present_flag are present\n    */\n    UWORD8 u1_video_signal_type_present_flag;\n\n    /**\n    * pal, secam, ntsc, ...\n    */\n    UWORD8 u1_video_format;\n\n    /**\n    * indicates the black level and range of the luma and chroma signals\n    */\n    UWORD8 u1_video_full_range_flag;\n\n    /**\n    * if 1,to 1 specifies that colour_primaries, transfer_characteristics\n    * and matrix_coefficients are present\n    */\n    UWORD8 u1_colour_description_present_flag;\n\n    /**\n    * indicates the chromaticity coordinates of the source primaries\n    */\n    UWORD8 u1_colour_primaries;\n\n    /**\n    * indicates the opto-electronic transfer characteristic of the source picture\n    */\n    UWORD8 u1_transfer_characteristics;\n\n    /**\n    * the matrix coefficients used in deriving luma and chroma signals\n    * from the green, blue, and red primaries\n    */\n    UWORD8 u1_matrix_coefficients;\n\n    /**\n    * if 1, specifies that chroma_sample_loc_type_top_field and\n    * chroma_sample_loc_type_bottom_field are present\n    */\n    UWORD8 u1_chroma_loc_info_present_flag;\n\n    /**\n    * location of chroma samples\n    */\n    UWORD8 u1_chroma_sample_loc_type_top_field;\n\n    UWORD8 u1_chroma_sample_loc_type_bottom_field;\n\n    /**\n    *   Indicates the presence of the\n    *   num_units_in_ticks, time_scale flag\n    */\n    UWORD8 u1_vui_timing_info_present_flag;\n\n    /**\n    *   Number of units that\n    *   correspond to one increment of the\n    *   clock. Indicates the  resolution\n    */\n    UWORD32 u4_vui_num_units_in_tick;\n\n    /**\n    *   The number of time units that pass in one second\n    */\n    UWORD32 u4_vui_time_scale;\n\n    /**\n     *   Flag indicating that time difference between two frames is a constant\n     */\n    UWORD8 u1_fixed_frame_rate_flag;\n\n    /**\n     *   Indicates the presence of NAL HRD parameters\n     */\n    UWORD8 u1_nal_hrd_parameters_present_flag;\n\n    /**\n     *   NAL level HRD parameters\n     */\n    hrd_params_t s_nal_hrd_parameters;\n\n    /**\n     *   Indicates the presence of VCL HRD parameters\n     */\n    UWORD8 u1_vcl_hrd_parameters_present_flag;\n\n    /**\n     *   VCL level HRD parameters\n     */\n    hrd_params_t s_vcl_hrd_parameters;\n\n    /**\n     *  Specifies the HRD operational mode\n     */\n    UWORD8 u1_low_delay_hrd_flag;\n\n    /**\n     * Indicates presence of SEI messages which include pic_struct syntax element\n     */\n    UWORD8 u1_pic_struct_present_flag;\n\n    /**\n    * 1, specifies that the following cvs bitstream restriction parameters are present\n    */\n    UWORD8 u1_bitstream_restriction_flag;\n\n    /**\n    * if 0, indicates that no pel outside the pic boundaries and\n    * no sub-pels derived using pels outside the pic boundaries is used for inter prediction\n    */\n    UWORD8 u1_motion_vectors_over_pic_boundaries_flag;\n\n    /**\n    * Indicates a number of bytes not exceeded by the sum of the sizes of the VCL NAL units\n    * associated with any coded picture\n    */\n    UWORD8 u1_max_bytes_per_pic_denom;\n\n    /**\n    *  Indicates an upper bound for the number of bits of coding_unit() data\n    */\n    UWORD8 u1_max_bits_per_mb_denom;\n\n    /**\n    * Indicate the maximum absolute value of a decoded horizontal MV component\n    * in quarter-pel luma units\n    */\n    UWORD8 u1_log2_max_mv_length_horizontal;\n\n    /**\n    * Indicate the maximum absolute value of a decoded vertical MV component\n    * in quarter-pel luma units\n    */\n    UWORD8 u1_log2_max_mv_length_vertical;\n\n    /**\n     *  Max number of frames that are not synchronized in display and decode order\n     */\n    UWORD8 u1_num_reorder_frames;\n\n    /**\n     * specifies required size of the HRD DPB in units of frame buffers.\n     */\n     UWORD8 u1_max_dec_frame_buffering;\n\n} vui_t;\n\n\n/**\n * Structure to hold SPS info\n */\ntypedef struct\n{\n    /**\n     *  profile_idc\n     */\n    UWORD8 u1_profile_idc;\n\n    /** constraint_set0_flag */\n    UWORD8 u1_constraint_set0_flag;\n\n    /** constraint_set1_flag */\n    UWORD8 u1_constraint_set1_flag;\n\n    /** constraint_set2_flag */\n    UWORD8 u1_constraint_set2_flag;\n\n    /** constraint_set3_flag */\n    UWORD8 u1_constraint_set3_flag;\n\n    /**\n     *  level_idc\n     */\n    UWORD8 u1_level_idc;\n\n    /**\n     *  seq_parameter_set_id\n     */\n    UWORD8 u1_sps_id;\n\n\n    /**\n     *  chroma_format_idc\n     */\n    UWORD8 u1_chroma_format_idc;\n\n    /**\n     *  residual_colour_transform_flag\n     */\n    WORD8 i1_residual_colour_transform_flag;\n\n    /**\n     *  bit_depth_luma_minus8\n     */\n    WORD8 i1_bit_depth_luma;\n\n    /**\n     *  bit_depth_chroma_minus8\n     */\n    WORD8 i1_bit_depth_chroma;\n\n    /**\n     *  qpprime_y_zero_transform_bypass_flag\n     */\n    WORD8 i1_qpprime_y_zero_transform_bypass_flag;\n\n    /**\n     *  seq_scaling_matrix_present_flag\n     */\n    WORD8 i1_seq_scaling_matrix_present_flag;\n\n    /**\n     *  seq_scaling_list_present_flag\n     */\n    WORD8 ai1_seq_scaling_list_present_flag[8];\n\n    /**\n     *  log2_max_frame_num_minus4\n     */\n    WORD8 i1_log2_max_frame_num;\n\n    /**\n     *  MaxFrameNum in the standard\n     *  1 << i1_log2_max_frame_num\n     */\n    WORD32 i4_max_frame_num;\n\n    /**\n     *  pic_order_cnt_type\n     */\n    WORD8 i1_pic_order_cnt_type;\n\n    /**\n     *  log2_max_pic_order_cnt_lsb_minus4\n     */\n    WORD8 i1_log2_max_pic_order_cnt_lsb;\n\n    /**\n     * MaxPicOrderCntLsb in the standard.\n     * 1 << log2_max_pic_order_cnt_lsb_minus4\n     */\n    WORD32 i4_max_pic_order_cnt_lsb;\n\n    /**\n     *  delta_pic_order_always_zero_flag\n     */\n    WORD8 i1_delta_pic_order_always_zero_flag;\n\n    /**\n     *  offset_for_non_ref_pic\n     */\n    WORD32 i4_offset_for_non_ref_pic;\n\n    /**\n     *  offset_for_top_to_bottom_field\n     */\n    WORD32 i4_offset_for_top_to_bottom_field;\n\n    /**\n     *  num_ref_frames_in_pic_order_cnt_cycle\n     */\n    UWORD8 u1_num_ref_frames_in_pic_order_cnt_cycle;\n\n    /**\n     * Offset_for_ref_frame\n     */\n    WORD32 ai4_offset_for_ref_frame[256];\n\n    /**\n     *  max_num_ref_frames\n     */\n    UWORD8 u1_max_num_ref_frames;\n\n    /**\n     *  gaps_in_frame_num_value_allowed_flag\n     */\n    WORD8 i1_gaps_in_frame_num_value_allowed_flag;\n\n    /**\n     *  pic_width_in_mbs_minus1\n     */\n    WORD16 i2_pic_width_in_mbs_minus1;\n\n    /**\n     *  pic_height_in_map_units_minus1\n     */\n    WORD16 i2_pic_height_in_map_units_minus1;\n\n    /**\n     *  frame_mbs_only_flag\n     */\n    WORD8 i1_frame_mbs_only_flag;\n\n    /**\n     *  mb_adaptive_frame_field_flag\n     */\n    WORD8 i1_mb_adaptive_frame_field_flag;\n\n    /**\n     *  direct_8x8_inference_flag\n     */\n    WORD8 i1_direct_8x8_inference_flag;\n\n    /**\n     *  frame_cropping_flag\n     */\n    WORD8 i1_frame_cropping_flag;\n\n    /**\n     *  frame_crop_left_offset\n     */\n    WORD16 i2_frame_crop_left_offset;\n\n    /**\n     *  frame_crop_right_offset\n     */\n    WORD16 i2_frame_crop_right_offset;\n\n    /**\n     *  frame_crop_top_offset\n     */\n    WORD16 i2_frame_crop_top_offset;\n\n    /**\n     *  frame_crop_bottom_offset\n     */\n    WORD16 i2_frame_crop_bottom_offset;\n\n    /**\n     *  vui_parameters_present_flag\n     */\n    WORD8 i1_vui_parameters_present_flag;\n\n    /**\n     * vui_parameters_Structure_info\n     */\n    vui_t s_vui_parameters;\n\n    /**\n     * Flag to give status of SPS structure\n     */\n    WORD8 i1_sps_valid;\n\n    /**\n     * Coded Picture width\n     */\n    WORD32 i2_pic_wd;\n\n    /**\n     * Coded Picture height\n     */\n    WORD32 i2_pic_ht;\n\n    /**\n     *  Picture width in MB units\n     */\n\n    WORD16 i2_pic_wd_in_mb;\n\n    /**\n     *  Picture height in MB units\n     */\n\n    WORD16 i2_pic_ht_in_mb;\n\n    /**\n     * useDefaultScalingMatrixFlag\n     */\n    WORD8 ai1_use_default_scaling_matrix_flag[8];\n\n    /**\n     * 4x4 Scaling lists after inverse zig zag scan\n     */\n    UWORD16 au2_4x4_weight_scale[6][16];\n\n    /**\n     * 4x4 Scaling lists after inverse zig zag scan\n     */\n    UWORD16 au2_8x8_weight_scale[2][64];\n\n} sps_t;\n\n\n/**\n * Structure to hold PPS info\n */\ntypedef struct\n{\n    /**\n     *  pic_parameter_set_id\n     */\n    UWORD8 u1_pps_id;\n\n    /**\n     *  seq_parameter_set_id\n     */\n    UWORD8 u1_sps_id;\n\n    /**\n     *   Entropy coding : 0-VLC; 1 - CABAC\n     */\n    UWORD8 u1_entropy_coding_mode_flag;\n\n    /*\n     * Pic order present flag\n     */\n    UWORD8 u1_pic_order_present_flag;\n\n    /*\n     * Number of slice groups\n     */\n    UWORD8 u1_num_slice_groups;\n\n    /*\n     * Slice group map type\n     */\n    UWORD8 u1_slice_group_map_type;\n\n    /*\n     * Maximum reference picture index in the reference list 0 : range [0 - 31]\n     */\n    WORD8 i1_num_ref_idx_l0_default_active;\n\n    /*\n     * Maximum reference picture index in the reference list 1 : range [0 - 31]\n     */\n    WORD8 i1_num_ref_idx_l1_default_active;\n\n    /**\n     *  weighted_pred_flag\n     */\n    WORD8 i1_weighted_pred_flag;\n\n    /**\n     *  weighted_bipred_flag\n     */\n    WORD8 i1_weighted_bipred_idc;\n\n    /**\n     *  pic_init_qp_minus26\n     */\n    WORD8 i1_pic_init_qp;\n\n    /**\n     *  pic_init_qs_minus26\n     */\n    WORD8 i1_pic_init_qs;\n\n    /*\n     * Chroma QP offset w.r.t QPY {-12,12}\n     */\n    WORD8  i1_chroma_qp_index_offset;\n\n    /**\n     *  deblocking_filter_control_present_flag\n     */\n    WORD8 i1_deblocking_filter_control_present_flag;\n\n    /**\n     *  constrained_intra_pred_flag\n     */\n    WORD8 i1_constrained_intra_pred_flag;\n\n    /**\n     *  redundant_pic_cnt_present_flag\n     */\n    WORD8 i1_redundant_pic_cnt_present_flag;\n\n    /**\n     *  transform_8x8_mode_flag\n     */\n    WORD8 i1_transform_8x8_mode_flag;\n\n    /**\n     *  pic_scaling_matrix_present_flag\n     */\n    WORD8 i1_pic_scaling_matrix_present_flag;\n\n    /*\n     *  Second chroma QP offset\n     */\n    WORD8  i1_second_chroma_qp_index_offset;\n\n\n    /**\n     * useDefaultScalingMatrixFlag\n     */\n    WORD8 ai1_use_default_scaling_matrix_flag[8];\n\n    /**\n     * 4x4 Scaling lists after inverse zig zag scan\n     */\n    UWORD16 au2_4x4_weight_scale[6][16];\n\n    /**\n     * 4x4 Scaling lists after inverse zig zag scan\n     */\n    UWORD16 au2_8x8_weight_scale[2][64];\n\n\n    /**\n     *  pic_scaling_list_present_flag\n     */\n    WORD8 ai1_pic_scaling_list_present_flag[8];\n\n    /**\n     * Flag to give status of PPS structure\n     */\n    WORD8   i1_pps_valid;\n\n\n} pps_t;\n\n/**\n * MMCO commands and params.\n */\ntypedef struct\n{\n    /* memory management control operation command */\n    UWORD8 u1_memory_management_control_operation;\n\n    /*\n     * Contains difference of pic nums of short-term pic/frame\n     * 1. To signal it as \"unused for reference\" if mmco = 1\n     * 2. To signal it as \"used for long-term reference\" if mmco = 3\n     */\n    UWORD32 u4_difference_of_pic_nums_minus1;\n\n    /* Long-term pic num to be set as \"unused for reference\" */\n    UWORD8 u1_long_term_pic_num;\n\n    /*\n     * Assign a long-term idx to a picture as follows\n     * 1. Assign to a short-term pic if mmco = 3\n     * 2. Assign to the current pic if mmco = 6\n     */\n    UWORD8 u1_long_term_frame_idx;\n\n    /*\n     * The max long-term idx. The long-term pics having idx above\n     * are set as \"unused for reference\n     */\n    UWORD8 u1_max_long_term_frame_idx_plus1;\n\n}mmco_prms_t;\n\n/**\n * Structure to hold Reference picture list modification info\n */\ntypedef struct\n{\n    /* ref_pic_list_modification_flag_l0 */\n    WORD8 i1_ref_pic_list_modification_flag_l0;\n\n    /* Modification required in list0 */\n    WORD8 i1_modification_of_pic_nums_idc_l0[MAX_MODICATION_IDC];\n\n    /*\n     * The absolute difference between the picture number of\n     * the picture being moved to the current index in\n     * list0 and the picture number prediction value\n     */\n    UWORD32 u4_abs_diff_pic_num_minus1_l0[MAX_MODICATION_IDC];\n\n    /*\n     * The long-term picture number of the picture being moved\n     * to the current index in list0\n     */\n    UWORD8 u1_long_term_pic_num_l0[MAX_MODICATION_IDC];\n\n    /* ref_pic_list_modification_flag_l1 */\n    WORD8 i1_ref_pic_list_modification_flag_l1;\n\n    /* Modification required in list1 */\n    WORD8 i1_modification_of_pic_nums_idc_l1[MAX_MODICATION_IDC];\n\n    /*\n     * The absolute difference between the picture number of\n     * the picture being moved to the current index in\n     * list1 and the picture number prediction value\n     */\n    UWORD32 u4_abs_diff_pic_num_minus1_l1[MAX_MODICATION_IDC];\n\n    /*\n     * The long-term picture number of the picture being moved\n     * to the current index in list1\n     */\n   UWORD8 u1_long_term_pic_num_l1[MAX_MODICATION_IDC];\n}rplm_t;\n\n/**\n * Structure to hold Slice Header info\n */\ntypedef struct\n{\n\n    /*\n     *  nal_unit_type\n     */\n    WORD8  i1_nal_unit_type;\n\n    /*\n     *  nal_unit_idc\n     */\n    WORD8  i1_nal_unit_idc;\n\n    /*\n     *  first_mb_in_slice\n     */\n    UWORD16   u2_first_mb_in_slice;\n\n    /*\n     *  slice_type\n     */\n    UWORD8   u1_slice_type;\n\n    /*\n     *  pic_parameter_set_id\n     */\n    UWORD8   u1_pps_id;\n\n    /*\n     *  frame_num\n     */\n    WORD32 i4_frame_num;\n\n    /*\n     *  field_pic_flag\n     */\n    WORD8   i1_field_pic_flag;\n\n    /*\n     *  bottom_field_flag\n     */\n    WORD8   i1_bottom_field_flag;\n\n    /*\n     *  second_field\n     */\n    WORD8   i1_second_field_flag;\n\n    /*\n     *  idr_pic_id\n     */\n    UWORD16 u2_idr_pic_id ;\n\n    /*\n     *  pic_order_cnt_lsb\n     */\n    UWORD16 i4_pic_order_cnt_lsb;\n\n    /*\n     *  delta_pic_order_cnt_bottom\n     */\n    WORD32  i4_delta_pic_order_cnt_bottom;\n\n    /*\n     *  delta_pic_order_cnt\n     */\n    WORD32   ai4_delta_pic_order_cnt[2];\n\n    /*\n     *  redundant_pic_cnt\n     */\n    UWORD8   u1_redundant_pic_cnt;\n\n    /*\n     *  direct_spatial_mv_pred_flag\n     */\n    UWORD8   u1_direct_spatial_mv_pred_flag;\n\n    /*\n     *  num_ref_idx_active_override_flag\n     */\n    UWORD8   u1_num_ref_idx_active_override_flag;\n\n    /*\n     *  num_ref_idx_l0_active\n     */\n    WORD8   i1_num_ref_idx_l0_active;\n\n    /*\n     *  num_ref_idx_l1_active_minus1\n     */\n    WORD8   i1_num_ref_idx_l1_active;\n\n    /*\n     * ref_pic_list_reordering_flag_l0\n     */\n    UWORD8  u1_ref_idx_reordering_flag_l0;\n\n    /*\n     * ref_pic_list_reordering_flag_l1\n     */\n    UWORD8  u1_ref_idx_reordering_flag_l1;\n\n    /**\n     *  Reference prediction list modification\n     */\n    rplm_t s_rplm;\n\n    /**\n     * L0 Reference pic lists\n     */\n    ref_list_t as_ref_pic_list0[MAX_DPB_SIZE];\n\n    /**\n     * L1 Reference pic lists\n     */\n    ref_list_t as_ref_pic_list1[MAX_DPB_SIZE];\n\n    /*\n     * no_output_of_prior_pics_flag\n     */\n    UWORD8   u1_no_output_of_prior_pics_flag;\n\n    /*\n     * long_term_reference_flag\n     */\n    UWORD8   u1_long_term_reference_flag;\n\n    /*\n     * adaptive_ref_pic_marking_mode_flag\n     */\n    UWORD8   u1_adaptive_ref_pic_marking_mode_flag;\n\n    /*\n     * Array to structures to store mmco commands\n     * and parameters.\n     */\n    mmco_prms_t as_mmco_prms[MAX_MMCO_COMMANDS];\n\n    /*\n     *  entropy_coding_mode_flag\n     */\n    WORD8   u1_entropy_coding_mode_flag;\n\n    /*\n     *  cabac_init_idc\n     */\n    WORD8   i1_cabac_init_idc;\n\n    /*\n     *  i1_slice_qp\n     */\n    WORD8   i1_slice_qp;\n\n    /*\n     *  sp_for_switch_flag\n     */\n    UWORD8   u1_sp_for_switch_flag;\n\n    /*\n     *  slice_qs_delta\n     */\n    UWORD8   u1_slice_qs;\n\n    /*\n     *  disable_deblocking_filter_idc\n     */\n    WORD8   u1_disable_deblocking_filter_idc;\n\n    /*\n     *  slice_alpha_c0_offset_div2\n     */\n    WORD8   i1_slice_alpha_c0_offset_div2;\n\n    /*\n     *  slice_beta_offset_div2\n     */\n    WORD8   i1_slice_beta_offset_div2;\n\n    /*\n     *  num_slice_groups_minus1\n     */\n    WORD8   u1_num_slice_groups_minus1;\n\n    /*\n     *  slice_group_change_cycle\n     */\n    WORD8   u1_slice_group_change_cycle;\n\n    /**\n     * Start MB X\n     */\n    UWORD16 i2_mb_x;\n\n    /**\n     * Start MB Y\n     */\n    UWORD16 i2_mb_y;\n\n    /**\n     * Absolute POC. Contains minimum of top and bottom POC.\n     */\n    WORD32 i4_abs_pic_order_cnt;\n\n    /**\n     *  Absolute top POC. Contains top poc for frame or top\n     *  field. Invalid for bottom field.\n     */\n    WORD32 i4_abs_top_pic_order_cnt;\n\n    /**\n     *  Absolute top POC. Contains bottom poc for frame or bottom\n     *  field. Invalid for top field.\n     */\n    WORD32 i4_abs_bottom_pic_order_cnt;\n\n    /** Flag signaling if the current slice is ref slice */\n    UWORD8 i1_nal_ref_idc;\n\n    /** Flag to indicate if the current slice is MBAFF Frame */\n    UWORD8 u1_mbaff_frame_flag;\n\n    /** luma_log2_weight_denom */\n    UWORD8 u1_luma_log2_weight_denom;\n\n    /** chroma_log2_weight_denom */\n    UWORD8 u1_chroma_log2_weight_denom;\n\n    /** luma_weight_l0_flag */\n    UWORD8 au1_luma_weight_l0_flag[MAX_DPB_SIZE];\n\n    /** luma_weight_l0 : (-128, 127 )is the range of weights\n     * when weighted pred is enabled, 128 is default value */\n    WORD16 ai2_luma_weight_l0[MAX_DPB_SIZE];\n\n    /** luma_offset_l0 : (-128, 127 )is the range of offset\n     * when weighted pred is enabled, 0 is default value */\n    WORD8 ai1_luma_offset_l0[MAX_DPB_SIZE];\n\n    /** chroma_weight_l0_flag */\n    UWORD8 au1_chroma_weight_l0_flag[MAX_DPB_SIZE];\n\n    /** chroma_weight_l0 : (-128, 127 )is the range of weights\n     * when weighted pred is enabled, 128 is default value*/\n    WORD16 ai2_chroma_weight_l0[MAX_DPB_SIZE][2];\n\n    /** chroma_offset_l0 : (-128, 127 )is the range of offset\n     * when weighted pred is enabled, 0 is default value*/\n    WORD8 ai1_chroma_offset_l0[MAX_DPB_SIZE][2];\n\n    /** luma_weight_l0_flag */\n    UWORD8 au1_luma_weight_l1_flag[MAX_DPB_SIZE];\n\n    /** luma_weight_l1 : (-128, 127 )is the range of weights\n     * when weighted pred is enabled, 128 is default value */\n    WORD16 ai2_luma_weight_l1[MAX_DPB_SIZE];\n\n    /** luma_offset_l1 : (-128, 127 )is the range of offset\n     * when weighted pred is enabled, 0 is default value */\n    WORD8 ai1_luma_offset_l1[MAX_DPB_SIZE];\n\n    /** chroma_weight_l1_flag */\n    UWORD8 au1_chroma_weight_l1_flag[MAX_DPB_SIZE];\n\n    /** chroma_weight_l1 : (-128, 127 )is the range of weights\n     * when weighted pred is enabled, 128 is default value */\n    WORD16 ai2_chroma_weight_l1[MAX_DPB_SIZE][2];\n\n    /** chroma_offset_l1 :(-128, 127 )is the range of offset\n     * when weighted pred is enabled, 0 is default value */\n    WORD8 ai1_chroma_offset_l1[MAX_DPB_SIZE][2];\n}slice_header_t;\n\n\n/*****************************************************************************/\n/* The following can be used to type cast coefficient data that is stored    */\n/*  per subblock. Note that though i2_level is shown as an array that        */\n/*  holds 16 coefficients, only the first few entries will be valid. Next    */\n/*  subblocks data starts after the valid number of coefficients. Number     */\n/*  of non-zero coefficients will be derived using number of non-zero bits   */\n/*  in sig coeff map                                                         */\n/*****************************************************************************/\n\n/**\n * Structure to hold coefficient info for a 2x2 chroma DC transform\n */\ntypedef struct\n{\n    /**\n     * significant coefficient map\n     */\n    UWORD8 u1_sig_coeff_map;\n\n    /**\n     * sub block position\n     */\n    UWORD8 u1_subblk_pos;\n\n    /**\n     * holds coefficients\n     */\n    WORD16  ai2_level[2 * 2];\n}tu_sblk2x2_coeff_data_t;\n\n/**\n * Structure to hold coefficient info for a 4x4 transform\n */\ntypedef struct\n{\n    /**\n     * significant coefficient map\n     */\n    UWORD16 u2_sig_coeff_map;\n\n    /**\n     * sub block position\n     */\n    UWORD16 u2_subblk_pos;\n\n    /**\n     * holds coefficients\n     */\n    WORD16  ai2_level[SUBBLK_COEFF_CNT];\n}tu_sblk4x4_coeff_data_t;\n\n/**\n * Structure to hold coefficient info for a 8x8 transform\n */\ntypedef struct\n{\n\n    /**\n     * significant coefficient map\n     */\n    UWORD32 au4_sig_coeff_map[2];\n\n    /**\n     * sub block position\n     */\n    UWORD16 u2_subblk_pos;\n\n    /**\n     * holds coefficients\n     */\n    WORD16  ai2_level[TRANS_SIZE_8 * TRANS_SIZE_8];\n}tu_blk8x8_coeff_data_t;\n\n\n/**\n * Structure to hold coefficient info for a 16x16 IPCM MB\n */\ntypedef struct\n{\n    /**\n     * holds coefficients\n     */\n    UWORD8  au1_level[MB_SIZE * MB_SIZE * 3 / 2];\n}tu_ipcm_coeff_data_t;\n\n\ntypedef struct\n{\n    /**\n     * Transform sizes 0: 4x4, 1: 8x8,\n     */\n    UWORD32     b1_trans_size : 1;\n\n    /**\n     * Flag to signal if the current MB is IPCM\n     */\n    UWORD32     b1_ipcm : 1;\n\n    /**\n     * Intra pred sizes  0: 4x4, 1: 8x8, 2: 16x16\n     */\n    UWORD32     b2_intra_pred_size : 2;\n\n    /**\n     * Chroma intra mode\n     */\n    UWORD32     b2_intra_chroma_pred_mode: 2;\n\n    /**\n     * Number of coded subblocks in the current MB, for which\n     * tu data is sent. Maximum of 27 subblocks in the following\n     * order.\n     * 1 4x4 luma DC(for intra16x16),\n     * 16 4x4 luma,\n     * 2 2x2 chroma DC,\n     * 8 4x4 chroma,\n     */\n    WORD32      b5_num_coded_sblks: 5;\n\n    /**\n     * Flag to signal if 4x4 subblock for DC values (in INTRA 16x16 MB)\n     * is coded\n     */\n    UWORD32     b1_luma_dc_coded: 1;\n\n    /**\n     * Flag to signal if 4x4 subblock for DC values (in INTRA 16x16 MB)\n     * is coded\n     */\n    UWORD32     b1_chroma_dc_coded: 1;\n\n    /**\n     * CSBP - 16 bits, 1 bit for each 4x4\n     * for intra16x16 mb_type only ac coefficients are\n     */\n    UWORD32     b16_luma_csbp: 16;\n\n    /**\n     * CSBP - 16 bits, 1 bit for each 4x4\n     * for intra16x16 mb_type only ac coefficients are\n     */\n    UWORD32     b8_chroma_csbp: 8;\n\n    /**\n     * Luma Intra pred modes,\n     * Based on intra pred size either 16, 4 or 1 entry will be\n     * populated below.\n     */\n    UWORD8     au1_luma_intra_modes[16];\n\n}intra_mb_t;\n\n\ntypedef struct\n{\n    /**\n     * Transform sizes 0: 4x4, 1: 8x8,\n     */\n    UWORD8     b1_trans_size : 1;\n\n\n    /**\n     * Skip flag\n     */\n    UWORD8     b1_skip : 1;\n\n\n    /**\n     * Number of coded subblocks in the current MB, for which\n     * tu data is sent. Maximum of 26 subblocks in the following\n     * order.\n     * 16 4x4 luma,\n     * 2 2x2 chroma DC,\n     * 8 4x4 chroma,\n     */\n    WORD32      b5_num_coded_sblks: 5;\n\n    /**\n     * CSBP - 16 bits, 1 bit for each 4x4\n     * for intra16x16 mb_type only ac coefficients are\n     */\n    UWORD32     b16_luma_csbp: 16;\n\n    /**\n     * CSBP - 16 bits, 1 bit for each 4x4\n     * for intra16x16 mb_type only ac coefficients are\n     */\n    UWORD32     b16_chroma_csbp: 8;\n}inter_mb_t;\n\n/**\n * Structure to hold Mastering Display Color Volume SEI\n */\ntypedef struct\n{\n    /**\n     * Array to store the display_primaries_x values\n     */\n    UWORD16 au2_display_primaries_x[NUM_SEI_MDCV_PRIMARIES];\n\n    /**\n     * Array to store the display_primaries_y values\n     */\n    UWORD16 au2_display_primaries_y[NUM_SEI_MDCV_PRIMARIES];\n\n    /**\n     * Variable to store the white point x value\n     */\n    UWORD16 u2_white_point_x;\n\n    /**\n     * Variable to store the white point y value\n     */\n    UWORD16 u2_white_point_y;\n\n    /**\n     * Variable to store the max display mastering luminance value\n     */\n    UWORD32 u4_max_display_mastering_luminance;\n\n    /**\n     * Variable to store the min display mastering luminance value\n     */\n    UWORD32 u4_min_display_mastering_luminance;\n}sei_mdcv_params_t;\n\n\n/**\n *  Structure for Content Light Level Info\n *\n */\ntypedef struct\n{\n    /**\n     * The maximum pixel intensity of all samples\n     */\n    UWORD16 u2_max_content_light_level;\n\n    /**\n     * The average pixel intensity of all samples\n     */\n    UWORD16 u2_max_pic_average_light_level;\n}sei_cll_params_t;\n\n\n/**\n * Structure to hold Ambient viewing environment SEI\n */\ntypedef struct\n{\n    /**\n     * specifies the environmental illluminance of the ambient viewing environment\n     */\n    UWORD32 u4_ambient_illuminance;\n\n    /*\n     * specify the normalized x chromaticity coordinates of the\n     * environmental ambient light in the nominal viewing environment\n     */\n    UWORD16 u2_ambient_light_x;\n\n    /*\n    * specify the normalized y chromaticity coordinates of the\n    * environmental ambient light in the nominal viewing environment\n    */\n    UWORD16 u2_ambient_light_y;\n}sei_ave_params_t;\n\n\n/**\n * Structure to hold Content color volume SEI\n */\ntypedef struct\n{\n    /*\n     * Flag used to control persistence of CCV SEI messages\n     */\n    UWORD8 u1_ccv_cancel_flag;\n\n    /*\n     * specifies the persistence of the CCV SEI message for the current layer\n     */\n    UWORD8 u1_ccv_persistence_flag;\n\n    /*\n     * specifies the presence of syntax elements ccv_primaries_x and ccv_primaries_y\n     */\n    UWORD8 u1_ccv_primaries_present_flag;\n\n    /*\n     * specifies that the syntax element ccv_min_luminance_value is present\n     */\n    UWORD8 u1_ccv_min_luminance_value_present_flag;\n\n    /*\n     * specifies that the syntax element ccv_max_luminance_value is present\n     */\n    UWORD8 u1_ccv_max_luminance_value_present_flag;\n\n    /*\n     * specifies that the syntax element ccv_avg_luminance_value is present\n     */\n    UWORD8 u1_ccv_avg_luminance_value_present_flag;\n\n    /*\n     * shall be equal to 0 in bitstreams conforming to this version. Other values\n     * for reserved_zero_2bits are reserved for future use\n     */\n    UWORD8 u1_ccv_reserved_zero_2bits;\n\n    /*\n     * specify the normalized x chromaticity coordinates of the colour\n     * primary component c of the nominal content colour volume\n     */\n    WORD32 ai4_ccv_primaries_x[NUM_SEI_CCV_PRIMARIES];\n\n    /*\n     * specify the normalized y chromaticity coordinates of the colour\n     * primary component c of the nominal content colour volume\n     */\n    WORD32 ai4_ccv_primaries_y[NUM_SEI_CCV_PRIMARIES];\n\n    /*\n     * specifies the normalized minimum luminance value\n     */\n    UWORD32 u4_ccv_min_luminance_value;\n\n    /*\n     * specifies the normalized maximum luminance value\n     */\n    UWORD32 u4_ccv_max_luminance_value;\n\n    /*\n     * specifies the normalized average luminance value\n     */\n    UWORD32 u4_ccv_avg_luminance_value;\n}sei_ccv_params_t;\n\n\n/**\n * Structure to hold SEI parameters Info\n */\ntypedef struct\n{\n    /**\n     *  mastering display color volume info present flag\n     */\n    UWORD8 u1_sei_mdcv_params_present_flag;\n\n    /*\n     * MDCV parameters\n     */\n    sei_mdcv_params_t s_sei_mdcv_params;\n\n    /**\n     * content light level info present flag\n     */\n    UWORD8 u1_sei_cll_params_present_flag;\n\n    /*\n     * CLL parameters\n     */\n    sei_cll_params_t s_sei_cll_params;\n\n    /**\n     * ambient viewing environment info present flag\n     */\n    UWORD8 u1_sei_ave_params_present_flag;\n\n    /*\n     * AVE parameters\n     */\n    sei_ave_params_t s_sei_ave_params;\n\n    /**\n     * content color volume info present flag\n     */\n    UWORD8 u1_sei_ccv_params_present_flag;\n\n    /*\n     * CCV parameters\n     */\n    sei_ccv_params_t s_sei_ccv_params;\n} sei_params_t;\n\n\n#endif /* _IH264_STRUCTS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_trans_data.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_trans_data.c\n *\n * @brief\n *  Contains definition of global variables for H264 encoder\n *\n * @author\n *  Ittiam\n *\n * @remarks\n *\n *******************************************************************************\n */\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_trans_data.h\"\n\n/*****************************************************************************/\n/* Extern global definitions                                                 */\n/*****************************************************************************/\n\n/*\n * Since we don't have a division operation in neon\n * we will multiply by LCM of 16,6,10 and scale accordingly\n * so care that to get the actual transform you need to divide by LCM\n * LCM = 240\n */\n\nconst UWORD16 g_scal_coff_h264_4x4[16] ={\n        15,40,40,40,\n        40,24,40,24,\n        15,40,40,15,\n        40,24,40,24};\n\n\n\nconst UWORD16 g_scal_coff_h264_8x8[16]=\n        {\n                16,  15,   20,   15,\n                15,  14,   19,   14,\n                20,  19,   25,   19,\n                15,  14,   19,   14\n        };\n/*\n * The scaling is by an 8x8 matrix, but due its 4x4 symmetry we can use\n * a 4x4 matrix for scaling\n * now since divide is to be avoided, we will compute 1/ values and scale it up\n * to preserve information since our data is max 10 bit +1 sign bit we can shift a maximum of 21 bits up\n * hence multiply the matrix as such\n{16.000   15.059   20.227   15.059\n15.059   14.173   19.051   14.173\n20.227   19.051   25.600   19.051\n15.059   14.173   19.051   14.173};\n{512,   544,    405,    544,\n544,    578,    430,    578,\n405,    430,    320,    430,\n544,    578,    430,    578};*/\n\n\n/**\n ******************************************************************************\n * @brief  Scale Table for quantizing 4x4 subblock. To quantize a given 4x4 DCT\n * transformed block, the coefficient at index location (i,j) is scaled by one of\n * the constants in this table and right shift the result by (QP_BITS_h264_4x4 +\n * floor(qp/6)), here qp is the quantization parameter used to quantize the mb.\n *\n * input   : qp%6, index location (i,j)\n * output  : scale constant.\n *\n * @remarks 16 constants for each index position of the subblock and 6 for each\n * qp%6 in the range 0-5 inclusive.\n ******************************************************************************\n */\nconst UWORD16 gu2_quant_scale_matrix_4x4[96] =\n{\n     13107,   8066,  13107,   8066,\n      8066,   5243,   8066,   5243,\n     13107,   8066,  13107,   8066,\n      8066,   5243,   8066,   5243,\n\n     11916,   7490,  11916,   7490,\n      7490,   4660,   7490,   4660,\n     11916,   7490,  11916,   7490,\n      7490,   4660,   7490,   4660,\n\n     10082,   6554,  10082,   6554,\n      6554,   4194,   6554,   4194,\n     10082,   6554,  10082,   6554,\n      6554,   4194,   6554,   4194,\n\n      9362,   5825,   9362,   5825,\n      5825,   3647,   5825,   3647,\n      9362,   5825,   9362,   5825,\n      5825,   3647,   5825,   3647,\n\n      8192,   5243,   8192,   5243,\n      5243,   3355,   5243,   3355,\n      8192,   5243,   8192,   5243,\n      5243,   3355,   5243,   3355,\n\n      7282,   4559,   7282,   4559,\n      4559,   2893,   4559,   2893,\n      7282,   4559,   7282,   4559,\n      4559,   2893,   4559,   2893,\n\n};\n\n/**\n ******************************************************************************\n * @brief  Round Factor for quantizing subblock. While quantizing a given 4x4 DCT\n * transformed block, the coefficient at index location (i,j) is scaled by one of\n * the constants in the table gu2_forward_quant_scalar_4x4 and then right shift\n * the result by (QP_BITS_h264_4x4 + floor(qp/6)).\n * Before right shifting a round factor is added.\n * The round factor can be any value [a * (1 << (QP_BITS_h264_4x4 + floor(qp/6)))]\n * for 'a' lies in the range 0-0.5.\n * Here qp is the quantization parameter used to quantize the mb.\n *\n * input   : qp/6\n * output  : round factor.\n *\n * @remarks The round factor is constructed by setting a = 1/3\n *\n * round factor constructed by setting a = 1/3\n {\n      10922,     21845,     43690,     87381,\n      174762,    349525,    699050,   1398101,\n      2796202,\n }\n *\n * round factor constructed by setting a = 0.49\n *{\n         16056,     32112,     64225,\n         128450,    256901,    513802,\n         1027604,   2055208,   4110417,\n };\n\n  * round factor constructed by setting a = 0.5\n      16384,     32768,     65536,\n      131072,    262144,    524288,\n     1048576,   2097152,   4194304,\n\n ******************************************************************************\n */\nconst UWORD32 gu4_forward_quant_round_factor_4x4[9] =\n{\n        10922,     21845,     43690,     87381,\n        174762,    349525,    699050,   1398101,\n        2796202,\n};\n\n\n\n/**\n ******************************************************************************\n * @brief  Threshold Table. Quantizing the given DCT coefficient is done only if\n * it exceeds the threshold value presented in this table.\n *\n * input   : qp/6, qp%6, index location (i,j)\n * output  : Threshold constant.\n *\n * @remarks 16 constants for each index position of the subblock and 6 for each\n * qp%6 in the range 0-5 inclusive and 9 for each qp/6 in the range 0-51.\n ******************************************************************************\n */\nconst UWORD16 gu2_forward_quant_threshold_4x4[96] =\n{\n        426,    693,    426,    693,\n        693,   1066,    693,   1066,\n        426,    693,    426,    693,\n        693,   1066,    693,   1066,\n\n        469,    746,    469,    746,\n        746,   1200,    746,   1200,\n        469,    746,    469,    746,\n        746,   1200,    746,   1200,\n\n        554,    853,    554,    853,\n        853,   1333,    853,   1333,\n        554,    853,    554,    853,\n        853,   1333,    853,   1333,\n\n        597,    960,    597,    960,\n        960,   1533,    960,   1533,\n        597,    960,    597,    960,\n        960,   1533,    960,   1533,\n\n        682,   1066,    682,   1066,\n       1066,   1666,   1066,   1666,\n        682,   1066,    682,   1066,\n       1066,   1666,   1066,   1666,\n\n        767,   1226,    767,   1226,\n       1226,   1933,   1226,   1933,\n        767,   1226,    767,   1226,\n       1226,   1933,   1226,   1933,\n};\n\n/**\n ******************************************************************************\n * @brief  Scale Table for quantizing 8x8 subblock. To quantize a given 8x8 DCT\n * transformed block, the coefficient at index location (i,j) is scaled by one of\n * the constants in this table and right shift the result by (QP_BITS_h264_8x8 +\n * floor(qp/6)), here qp is the quantization parameter used to quantize the mb.\n *\n * input   : qp%6, index location (i,j)\n * output  : scale constant.\n *\n * @remarks 64 constants for each index position of the subblock and 6 for each\n * qp%6 in the range 0-5 inclusive.\n ******************************************************************************\n */\nconst UWORD16 gu2_quant_scale_matrix_8x8 [384] =\n{\n      13107,  12222,  16777,  12222,  13107,  12222,  16777,  12222,\n      12222,  11428,  15481,  11428,  12222,  11428,  15481,  11428,\n      16777,  15481,  20972,  15481,  16777,  15481,  20972,  15481,\n      12222,  11428,  15481,  11428,  12222,  11428,  15481,  11428,\n      13107,  12222,  16777,  12222,  13107,  12222,  16777,  12222,\n      12222,  11428,  15481,  11428,  12222,  11428,  15481,  11428,\n      16777,  15481,  20972,  15481,  16777,  15481,  20972,  15481,\n      12222,  11428,  15481,  11428,  12222,  11428,  15481,  11428,\n\n      11916,  11058,  14980,  11058,  11916,  11058,  14980,  11058,\n      11058,  10826,  14290,  10826,  11058,  10826,  14290,  10826,\n      14980,  14290,  19174,  14290,  14980,  14290,  19174,  14290,\n      11058,  10826,  14290,  10826,  11058,  10826,  14290,  10826,\n      11916,  11058,  14980,  11058,  11916,  11058,  14980,  11058,\n      11058,  10826,  14290,  10826,  11058,  10826,  14290,  10826,\n      14980,  14290,  19174,  14290,  14980,  14290,  19174,  14290,\n      11058,  10826,  14290,  10826,  11058,  10826,  14290,  10826,\n\n      10082,   9675,  12710,   9675,  10082,   9675,  12710,   9675,\n       9675,   8943,  11985,   8943,   9675,   8943,  11985,   8943,\n      12710,  11985,  15978,  11985,  12710,  11985,  15978,  11985,\n       9675,   8943,  11985,   8943,   9675,   8943,  11985,   8943,\n      10082,   9675,  12710,   9675,  10082,   9675,  12710,   9675,\n       9675,   8943,  11985,   8943,   9675,   8943,  11985,   8943,\n      12710,  11985,  15978,  11985,  12710,  11985,  15978,  11985,\n       9675,   8943,  11985,   8943,   9675,   8943,  11985,   8943,\n\n       9362,   8931,  11984,   8931,   9362,   8931,  11984,   8931,\n       8931,   8228,  11259,   8228,   8931,   8228,  11259,   8228,\n      11984,  11259,  14913,  11259,  11984,  11259,  14913,  11259,\n       8931,   8228,  11259,   8228,   8931,   8228,  11259,   8228,\n       9362,   8931,  11984,   8931,   9362,   8931,  11984,   8931,\n       8931,   8228,  11259,   8228,   8931,   8228,  11259,   8228,\n      11984,  11259,  14913,  11259,  11984,  11259,  14913,  11259,\n       8931,   8228,  11259,   8228,   8931,   8228,  11259,   8228,\n\n       8192,   7740,  10486,   7740,   8192,   7740,  10486,   7740,\n       7740,   7346,   9777,   7346,   7740,   7346,   9777,   7346,\n      10486,   9777,  13159,   9777,  10486,   9777,  13159,   9777,\n       7740,   7346,   9777,   7346,   7740,   7346,   9777,   7346,\n       8192,   7740,  10486,   7740,   8192,   7740,  10486,   7740,\n       7740,   7346,   9777,   7346,   7740,   7346,   9777,   7346,\n      10486,   9777,  13159,   9777,  10486,   9777,  13159,   9777,\n       7740,   7346,   9777,   7346,   7740,   7346,   9777,   7346,\n\n       7282,   6830,   9118,   6830,   7282,   6830,   9118,   6830,\n       6830,   6428,   8640,   6428,   6830,   6428,   8640,   6428,\n       9118,   8640,  11570,   8640,   9118,   8640,  11570,   8640,\n       6830,   6428,   8640,   6428,   6830,   6428,   8640,   6428,\n       7282,   6830,   9118,   6830,   7282,   6830,   9118,   6830,\n       6830,   6428,   8640,   6428,   6830,   6428,   8640,   6428,\n       9118,   8640,  11570,   8640,   9118,   8640,  11570,   8640,\n       6830,   6428,   8640,   6428,   6830,   6428,   8640,   6428,\n\n};\n\n\n/**\n ******************************************************************************\n * @brief  Specification of QPc as a function of qPi\n *\n * input   : qp luma\n * output  : qp chroma.\n *\n * @remarks Refer Table 8-15 of h264 specification.\n ******************************************************************************\n */\nconst UWORD8 gu1_qpc_fqpi[52] =\n{\n     0,     1,     2,     3,     4,     5,     6,     7,\n     8,     9,    10,    11,    12,    13,    14,    15,\n    16,    17,    18,    19,    20,    21,    22,    23,\n    24,    25,    26,    27,    28,    29,    29,    30,\n    31,    32,    32,    33,    34,    34,    35,    35,\n    36,    36,    37,    37,    37,    38,    38,    38,\n    39,    39,    39,    39,\n};\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_trans_data.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_trans_data.h\n *\n * @brief\n *  Contains declaration of global variables for H264 transform , qnat and inverse quant\n *\n * @author\n *  Ittiam\n *\n * @remarks\n *\n *******************************************************************************\n */\n#ifndef IH264_GLOBAL_DATA_H_\n#define IH264_GLOBAL_DATA_H_\n\n/*****************************************************************************/\n/* Extern global declarations                                                */\n/*****************************************************************************/\n\n/* Scaling matrices for h264 quantization */\nextern const UWORD16 g_scal_coff_h264_4x4[16];\nextern const UWORD16 g_scal_coff_h264_8x8[16];\n\n\n/**\n ******************************************************************************\n * @brief  Scale Table for quantizing 4x4 subblock. To quantize a given 4x4 DCT\n * transformed block, the coefficient at index location (i,j) is scaled by one of\n * the constants in this table and right shift the result by (QP_BITS_h264_4x4 +\n * floor(qp/6)), here qp is the quantization parameter used to quantize the mb.\n *\n * input   : qp%6, index location (i,j)\n * output  : scale constant.\n *\n * @remarks 16 constants for each index position of the subblock and 6 for each\n * qp%6 in the range 0-5 inclusive.\n ******************************************************************************\n */\nextern const UWORD16 gu2_quant_scale_matrix_4x4[96];\n\n/**\n ******************************************************************************\n * @brief  Round Factor for quantizing subblock. While quantizing a given 4x4 DCT\n * transformed block, the coefficient at index location (i,j) is scaled by one of\n * the constants in the table gu2_forward_quant_scalar_4x4 and then right shift\n * the result by (QP_BITS_h264_4x4 + floor(qp/6)).\n * Before right shifting a round factor is added.\n * The round factor can be any value [a * (1 << (QP_BITS_h264_4x4 + floor(qp/6)))]\n * for 'a' lies in the range 0-0.5.\n * Here qp is the quantization parameter used to quantize the mb.\n *\n * input   : qp/6\n * output  : round factor.\n *\n * @remarks The round factor is constructed by setting a = 1/3\n ******************************************************************************\n */\nextern const UWORD32 gu4_forward_quant_round_factor_4x4[9];\n\n/**\n ******************************************************************************\n * @brief  Threshold Table. Quantizing the given DCT coefficient is done only if\n * it exceeds the threshold value presented in this table.\n *\n * input   : qp/6, qp%6, index location (i,j)\n * output  : Threshold constant.\n *\n * @remarks 16 constants for each index position of the subblock and 6 for each\n * qp%6 in the range 0-5 inclusive and 9 for each qp/6 in the range 0-51.\n ******************************************************************************\n */\nextern const UWORD16 gu2_forward_quant_threshold_4x4[96];\n\n/**\n ******************************************************************************\n * @brief  Scale Table for quantizing 8x8 subblock. To quantize a given 8x8 DCT\n * transformed block, the coefficient at index location (i,j) is scaled by one of\n * the constants in this table and right shift the result by (QP_BITS_h264_8x8 +\n * floor(qp/6)), here qp is the quantization parameter used to quantize the mb.\n *\n * input   : qp%6, index location (i,j)\n * output  : scale constant.\n *\n * @remarks 64 constants for each index position of the subblock and 6 for each\n * qp%6 in the range 0-5 inclusive.\n ******************************************************************************\n */\nextern const UWORD16 gu2_quant_scale_matrix_8x8 [384];\n\n/**\n ******************************************************************************\n * @brief  Specification of QPc as a function of qPi\n *\n * input   : qp luma\n * output  : qp chroma.\n *\n * @remarks Refer Table 8-15 of h264 specification.\n ******************************************************************************\n */\nextern const UWORD8 gu1_qpc_fqpi[52];\n\n\n#endif /* IH264_GLOBAL_DATA_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_trans_macros.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_trans_macros.h\n*\n* @brief\n*  The file contains definitions of macros that perform forward and inverse\n*  quantization\n*\n* @author\n*  Ittiam\n*\n* @remark\n*  None\n*\n*******************************************************************************\n*/\n\n#ifndef IH264_TRANS_MACROS_H_\n#define IH264_TRANS_MACROS_H_\n\n/*****************************************************************************/\n/* Function Macros                                                           */\n/*****************************************************************************/\n\n/**\n******************************************************************************\n *  @brief   Macro to perform forward quantization.\n *  @description The value to be quantized is first compared with a threshold.\n *  If the value is less than the threshold, the quantization value is returned\n *  as zero else the value is quantized traditionally as per the rules of\n *  h264 specification\n******************************************************************************\n */\n#define FWD_QUANT(i4_value, u4_abs_value, i4_sign, threshold, scale, rndfactor, qbits, u4_nnz)      \\\n                {\\\n                        if (i4_value < 0)\\\n                        {\\\n                            u4_abs_value = -i4_value;\\\n                            i4_sign = -1;\\\n                        }\\\n                        else\\\n                        {\\\n                            u4_abs_value = i4_value;\\\n                            i4_sign = 1;\\\n                        }\\\n                        if (u4_abs_value < threshold)\\\n                        {\\\n                            i4_value = 0;\\\n                        }\\\n                        else\\\n                        {\\\n                            u4_abs_value *= scale;\\\n                            u4_abs_value += rndfactor;\\\n                            u4_abs_value >>= qbits;\\\n                            i4_value = u4_abs_value * i4_sign;\\\n                            if (i4_value)\\\n                            {\\\n                                u4_nnz++;\\\n                            }\\\n                        }\\\n                }\n\n/**\n******************************************************************************\n *  @brief   Macro to perform inverse quantization.\n *  @remarks The value can also be de-quantized as\n *  if (u4_qp_div_6 < 4)\n *  {\n *      i4_value = (quant_scale * weight_scale * i4_value + (1 << (3-u4_qp_div_6)))\n *      i4_value >>= (4 - u4_qp_div_6)\n *  }\n *  else\n *  {\n *      i4_value = (quant_scale * weight_scale * i4_value) << (u4_qp_div_6 -4)\n *  }\n******************************************************************************\n */\n#define INV_QUANT(i4_value, quant_scale, weight_scale, u4_qp_div_6, rndfactor, qbits)\\\n                {\\\n                    i4_value *= quant_scale;\\\n                    i4_value *= weight_scale;\\\n                    i4_value += rndfactor;\\\n                    i4_value <<= u4_qp_div_6;\\\n                    i4_value >>= qbits;\\\n                }\n\n#define QUANT_H264(x,y,w,z,shft) (shft = ABS(x),\\\n                shft *= y,\\\n                shft += z,\\\n                shft = shft>>w,\\\n                shft = SIGNXY(shft,x))\n\n#define IQUANT_H264(x,y,wscal,w,shft) (shft = x, \\\n                shft *=y, \\\n                shft *=wscal, \\\n                shft = shft<<w)\n\n#define IQUANT_lev_H264(x,y,wscal,add_f,w,shft) (shft = x, \\\n                shft *=y, \\\n                shft *=wscal, \\\n                shft+= add_f, \\\n                shft = shft>>w)\n\n#endif /* IH264_TRANS_MACROS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_trans_quant_itrans_iquant.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_trans_quant.h\n *\n * @brief\n *  Contains declarations for forward and inverse transform paths for H264\n *\n * @author\n *  Ittiam\n *\n * @remarks\n *\n *******************************************************************************\n */\n\n#ifndef IH264_TRANS_QUANT_H_\n#define IH264_TRANS_QUANT_H_\n\n/*****************************************************************************/\n/* Extern Function Declarations                                              */\n/*****************************************************************************/\n\n\ntypedef void ih264_resi_trans_dctrans_quant_ft(UWORD8*pu1_src,\n                                       UWORD8 *pu1_pred,\n                                       WORD16 *pi2_out,\n                                       WORD32 src_strd,\n                                       WORD32 pred_strd,\n                                       WORD32 dst_strd,\n                                       const UWORD16 *pu2_scale_mat,\n                                       const UWORD16 *pu2_thresh_mat,\n                                       UWORD32 u4_qbit,\n                                       UWORD32 u4_round_fact,\n                                       UWORD8 *pu1_nnz);\n\ntypedef void ih264_idctrans_iquant_itrans_recon_ft(WORD16 *pi2_src,\n                                          UWORD8 *pu1_pred,\n                                          UWORD8 *pu1_out,\n                                          WORD32 src_strd,\n                                          WORD32 pred_strd,\n                                          WORD32 out_strd,\n                                          const UWORD16 *pu2_iscale_mat,\n                                          const UWORD16 *pu2_weigh_mat,\n                                          UWORD32 qp_div,\n                                          UWORD32 pi4_cntrl,\n                                          WORD32 *pi4_tmp);\n\n\n/*Function prototype declarations*/\ntypedef void ih264_resi_trans_quant_ft(UWORD8*pu1_src,\n                                       UWORD8 *pu1_pred,\n                                       WORD16 *pi2_out,\n                                       WORD32 src_strd,\n                                       WORD32 pred_strd,\n                                       const UWORD16 *pu2_scale_mat,\n                                       const UWORD16 *pu2_thresh_mat,\n                                       UWORD32 u4_qbit,\n                                       UWORD32 u4_round_fact,\n                                       UWORD8 *pu1_nnz,\n                                       WORD16 *pi2_alt_dc_addr);\n\ntypedef void ih264_luma_16x16_resi_trans_dctrans_quant_ft(UWORD8 *pu1_src,\n                                                          UWORD8 *pu1_pred,\n                                                          WORD16 *pi2_out,\n                                                          WORD32 src_strd,\n                                                          WORD32 pred_strd,\n                                                          WORD32 dst_strd,\n                                                          const UWORD16 *pu2_scale_matrix,\n                                                          const UWORD16 *pu2_threshold_matrix,\n                                                          UWORD32 u4_qbits,\n                                                          UWORD32 u4_round_factor,\n                                                          UWORD8 *pu1_nnz,\n                                                          UWORD32 u4_dc_flag);\n\ntypedef void ih264_chroma_8x8_resi_trans_dctrans_quant_ft(UWORD8 *pu1_src,\n                                                          UWORD8 *pu1_pred,\n                                                          WORD16 *pi2_out,\n                                                          WORD32 src_strd,\n                                                          WORD32 pred_strd,\n                                                          WORD32 dst_strd,\n                                                          const UWORD16 *pu2_scale_matrix,\n                                                          const UWORD16 *pu2_threshold_matrix,\n                                                          UWORD32 u4_qbits,\n                                                          UWORD32 u4_round_factor,\n                                                          UWORD8 *pu1_nnz);\n\ntypedef void ih264_iquant_itrans_recon_ft(WORD16 *pi2_src,\n                                          UWORD8 *pu1_pred,\n                                          UWORD8 *pu1_out,\n                                          WORD32 pred_strd,\n                                          WORD32 out_strd,\n                                          const UWORD16 *pu2_iscale_mat,\n                                          const UWORD16 *pu2_weigh_mat,\n                                          UWORD32 qp_div,\n                                          WORD16 *pi2_tmp,\n                                          WORD32 iq_start_idx,\n                                          WORD16 *pi2_dc_ld_addr);\n\n\ntypedef void ih264_iquant_itrans_recon_chroma_ft(WORD16 *pi2_src,\n                                                 UWORD8 *pu1_pred,\n                                                 UWORD8 *pu1_out,\n                                                 WORD32 pred_strd,\n                                                 WORD32 out_strd,\n                                                 const UWORD16 *pu2_iscal_mat,\n                                                 const UWORD16 *pu2_weigh_mat,\n                                                 UWORD32 u4_qp_div_6,\n                                                 WORD16 *pi2_tmp,\n                                                 WORD16 *pi2_dc_src);\n\n\ntypedef void ih264_luma_16x16_idctrans_iquant_itrans_recon_ft(WORD16 *pi2_src,\n                                                              UWORD8 *pu1_pred,\n                                                              UWORD8 *pu1_out,\n                                                              WORD32 src_strd,\n                                                              WORD32 pred_strd,\n                                                              WORD32 out_strd,\n                                                              const UWORD16 *pu2_iscale_mat,\n                                                              const UWORD16 *pu2_weigh_mat,\n                                                              UWORD32 qp_div,\n                                                              UWORD32 pi4_cntrl,\n                                                              UWORD32 u4_dc_trans_flag,\n                                                              WORD32 *pi4_tmp);\n\ntypedef void ih264_chroma_8x8_idctrans_iquant_itrans_recon_ft(WORD16 *pi2_src,\n                                                              UWORD8 *pu1_pred,\n                                                              UWORD8 *pu1_out,\n                                                              WORD32 src_strd,\n                                                              WORD32 pred_strd,\n                                                              WORD32 out_strd,\n                                                              const UWORD16 *pu2_iscale_mat,\n                                                              const UWORD16 *pu2_weigh_mat,\n                                                              UWORD32 qp_div,\n                                                              UWORD32 pi4_cntrl,\n                                                              WORD32 *pi4_tmp);\n\ntypedef void ih264_ihadamard_scaling_ft(WORD16* pi2_src,\n                                        WORD16* pi2_out,\n                                        const UWORD16 *pu2_iscal_mat,\n                                        const UWORD16 *pu2_weigh_mat,\n                                        UWORD32 u4_qp_div_6,\n                                        WORD32* pi4_tmp);\n\ntypedef void ih264_hadamard_quant_ft(WORD16 *pi2_src, WORD16 *pi2_dst,\n                                    const UWORD16 *pu2_scale_matrix,\n                                    const UWORD16 *pu2_threshold_matrix, UWORD32 u4_qbits,\n                                    UWORD32 u4_round_factor,UWORD8  *pu1_nnz);\n\nih264_resi_trans_quant_ft ih264_resi_trans_quant_4x4;\nih264_resi_trans_quant_ft ih264_resi_trans_quant_chroma_4x4;\nih264_resi_trans_quant_ft ih264_resi_trans_quant_8x8;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_4x4;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_8x8;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_4x4_dc;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_8x8_dc;\nih264_iquant_itrans_recon_chroma_ft ih264_iquant_itrans_recon_chroma_4x4;\nih264_iquant_itrans_recon_chroma_ft ih264_iquant_itrans_recon_chroma_4x4_dc;\nih264_ihadamard_scaling_ft ih264_ihadamard_scaling_4x4;\nih264_ihadamard_scaling_ft ih264_ihadamard_scaling_2x2_uv;\nih264_hadamard_quant_ft ih264_hadamard_quant_4x4;\nih264_hadamard_quant_ft ih264_hadamard_quant_2x2_uv;\n\n/*A9 Declarations*/\nih264_resi_trans_quant_ft ih264_resi_trans_quant_4x4_a9;\nih264_resi_trans_quant_ft ih264_resi_trans_quant_chroma_4x4_a9;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_4x4_a9;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_8x8_a9;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_4x4_dc_a9;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_8x8_dc_a9;\nih264_iquant_itrans_recon_chroma_ft ih264_iquant_itrans_recon_chroma_4x4_a9;\nih264_iquant_itrans_recon_chroma_ft ih264_iquant_itrans_recon_chroma_4x4_dc_a9;\nih264_luma_16x16_resi_trans_dctrans_quant_ft ih264_luma_16x16_resi_trans_dctrans_quant_a9;\nih264_chroma_8x8_resi_trans_dctrans_quant_ft ih264_chroma_8x8_resi_trans_dctrans_quant_a9;\nih264_luma_16x16_idctrans_iquant_itrans_recon_ft ih264_luma_16x16_idctrans_iquant_itrans_recon_a9;\nih264_chroma_8x8_idctrans_iquant_itrans_recon_ft ih264_chroma_8x8_idctrans_iquant_itrans_recon_a9;\nih264_ihadamard_scaling_ft ih264_ihadamard_scaling_4x4_a9;\nih264_ihadamard_scaling_ft ih264_ihadamard_scaling_2x2_uv_a9;\nih264_hadamard_quant_ft ih264_hadamard_quant_4x4_a9;\nih264_hadamard_quant_ft ih264_hadamard_quant_2x2_uv_a9;\n\n/*Av8 Declarations*/\nih264_resi_trans_quant_ft ih264_resi_trans_quant_4x4_av8;\nih264_resi_trans_quant_ft ih264_resi_trans_quant_chroma_4x4_av8;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_4x4_av8;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_8x8_av8;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_4x4_dc_av8;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_8x8_dc_av8;\nih264_iquant_itrans_recon_chroma_ft ih264_iquant_itrans_recon_chroma_4x4_av8;\nih264_iquant_itrans_recon_chroma_ft ih264_iquant_itrans_recon_chroma_4x4_dc_av8;\nih264_ihadamard_scaling_ft ih264_ihadamard_scaling_4x4_av8;\nih264_ihadamard_scaling_ft ih264_ihadamard_scaling_2x2_uv_av8;\nih264_hadamard_quant_ft ih264_hadamard_quant_4x4_av8;\nih264_hadamard_quant_ft ih264_hadamard_quant_2x2_uv_av8;\n\n/*SSSE3 Declarations*/\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_4x4_ssse3;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_8x8_ssse3;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_4x4_dc_ssse3;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_8x8_dc_ssse3;\nih264_iquant_itrans_recon_chroma_ft ih264_iquant_itrans_recon_chroma_4x4_dc_ssse3;\nih264_ihadamard_scaling_ft ih264_ihadamard_scaling_4x4_ssse3;\nih264_ihadamard_scaling_ft ih264_ihadamard_scaling_2x2_uv_ssse3;\n/*SSSE42 Declarations*/\nih264_resi_trans_quant_ft ih264_resi_trans_quant_4x4_sse42;\nih264_resi_trans_quant_ft ih264_resi_trans_quant_chroma_4x4_sse42;\nih264_iquant_itrans_recon_ft ih264_iquant_itrans_recon_4x4_sse42;\nih264_iquant_itrans_recon_chroma_ft ih264_iquant_itrans_recon_chroma_4x4_sse42;\nih264_ihadamard_scaling_ft ih264_ihadamard_scaling_4x4_sse42;\nih264_hadamard_quant_ft ih264_hadamard_quant_4x4_sse42;\nih264_hadamard_quant_ft ih264_hadamard_quant_2x2_uv_sse42;\n\n#endif /* IH264_TRANS_QUANT_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_typedefs.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_typedefs.h\n*\n* @brief\n*  Type definitions used in the code\n*\n* @author\n*  Ittiam\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n#ifndef _IH264_TYPEDEFS_H_\n#define _IH264_TYPEDEFS_H_\n\n#include <stdint.h>\n/*****************************************************************************/\n/* Unsigned data types                                                       */\n/*****************************************************************************/\ntypedef uint8_t   UWORD8;\ntypedef uint16_t  UWORD16;\ntypedef uint32_t  UWORD32;\ntypedef uint64_t  UWORD64;\n\n\n/*****************************************************************************/\n/* Signed data types                                                         */\n/*****************************************************************************/\ntypedef int8_t     WORD8;\ntypedef int16_t    WORD16;\ntypedef int32_t    WORD32;\ntypedef int64_t    WORD64;\n\n/*****************************************************************************/\n/* Miscellaneous data types                                                  */\n/*****************************************************************************/\ntypedef char            CHAR;\ntypedef double          DOUBLE;\n\n#endif /*   _IH264_TYPEDEFS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_weighted_pred.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264_weighted_pred.c                                */\n/*                                                                           */\n/*  Description       : Contains function definitions for weighted           */\n/*                      prediction functions                                 */\n/*                                                                           */\n/*  List of Functions : ih264_default_weighted_pred_luma()                   */\n/*                      ih264_default_weighted_pred_chroma()                 */\n/*                      ih264_weighted_pred_luma()                           */\n/*                      ih264_weighted_pred_chroma()                         */\n/*                      ih264_weighted_bipred_luma()                         */\n/*                      ih264_weighted_bipred_chroma()                       */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         07 01 2015   Kaushik         Initial version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_weighted_pred.h\"\n\n/*****************************************************************************/\n/*  Function definitions .                                                   */\n/*****************************************************************************/\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_default_weighted_pred_luma                         */\n/*                                                                           */\n/*  Description   : This function performs the default weighted prediction   */\n/*                  as described in sec 8.4.2.3.1 titled \"Default weighted   */\n/*                  sample prediction process\" for luma. The function gets   */\n/*                  two ht x wd blocks, calculates their rounded-average and */\n/*                  stores it in the destination block. (ht,wd) can be       */\n/*                  (4,4), (8,4), (4,8), (8,8), (16,8), (8,16) or (16,16).   */\n/*                                                                           */\n/*  Inputs        : puc_src1  - Pointer to source 1                          */\n/*                  puc_src2  - Pointer to source 2                          */\n/*                  puc_dst   - Pointer to destination                       */\n/*                  src_strd1 - stride for source 1                          */\n/*                  src_strd1 - stride for source 2                          */\n/*                  dst_strd  - stride for destination                       */\n/*                  ht        - height of the block                          */\n/*                  wd        - width of the block                           */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         07 01 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_default_weighted_pred_luma(UWORD8 *pu1_src1,\n                                      UWORD8 *pu1_src2,\n                                      UWORD8 *pu1_dst,\n                                      WORD32 src_strd1,\n                                      WORD32 src_strd2,\n                                      WORD32 dst_strd,\n                                      WORD32 ht,\n                                      WORD32 wd)\n{\n    WORD32 i, j;\n\n    src_strd1 -= wd;\n    src_strd2 -= wd;\n    dst_strd -= wd;\n\n    for(i = 0; i < ht; i++)\n    {\n        for(j = 0; j < wd; j++, pu1_src1++, pu1_src2++, pu1_dst++)\n            *pu1_dst = (*pu1_src1 + *pu1_src2 + 1) >> 1;\n\n        pu1_src1 += src_strd1;\n        pu1_src2 += src_strd2;\n        pu1_dst += dst_strd;\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_default_weighted_pred_chroma                       */\n/*                                                                           */\n/*  Description   : This function performs the default weighted prediction   */\n/*                  as described in sec 8.4.2.3.1 titled \"Default weighted   */\n/*                  sample prediction process\" for chroma. The function gets */\n/*                  two ht x wd blocks, calculates their rounded-average and */\n/*                  stores it in the destination block. (ht,wd) can be       */\n/*                  (2,2), (4,2) , (2,4), (4,4), (8,4), (4,8) or (8,8).      */\n/*                                                                           */\n/*  Inputs        : puc_src1  - Pointer to source 1                          */\n/*                  puc_src2  - Pointer to source 2                          */\n/*                  puc_dst   - Pointer to destination                       */\n/*                  src_strd1 - stride for source 1                          */\n/*                  src_strd1 - stride for source 2                          */\n/*                  dst_strd  - stride for destination                       */\n/*                  ht        - height of the block                          */\n/*                  wd        - width of the block                           */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         07 01 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_default_weighted_pred_chroma(UWORD8 *pu1_src1,\n                                        UWORD8 *pu1_src2,\n                                        UWORD8 *pu1_dst,\n                                        WORD32 src_strd1,\n                                        WORD32 src_strd2,\n                                        WORD32 dst_strd,\n                                        WORD32 ht,\n                                        WORD32 wd)\n{\n    WORD32 i, j;\n\n    wd = wd << 1;\n\n    src_strd1 -= wd;\n    src_strd2 -= wd;\n    dst_strd -= wd;\n\n    for(i = 0; i < ht; i++)\n    {\n        for(j = 0; j < wd; j++, pu1_src1++, pu1_src2++, pu1_dst++)\n            *pu1_dst = (*pu1_src1 + *pu1_src2 + 1) >> 1;\n\n        pu1_src1 += src_strd1;\n        pu1_src2 += src_strd2;\n        pu1_dst += dst_strd;\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_weighted_pred_luma                                 */\n/*                                                                           */\n/*  Description   : This function performs the weighted prediction as        */\n/*                  described in sec 8.4.2.3.2 titled \"Weighted sample       */\n/*                  prediction process\" for luma. The function gets one      */\n/*                  ht x wd block, weights it, rounds it off, offsets it,    */\n/*                  saturates it to unsigned 8-bit and stores it in the      */\n/*                  destination block. (ht,wd) can be (4,4), (8,4), (4,8),   */\n/*                  (8,8), (16,8), (8,16) or (16,16).                        */\n/*                                                                           */\n/*  Inputs        : puc_src  - Pointer to source                             */\n/*                  puc_dst  - Pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  log_wd   - number of bits to be rounded off              */\n/*                  wt       - weight value                                  */\n/*                  ofst     - offset value                                  */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         07 01 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_weighted_pred_luma(UWORD8 *pu1_src,\n                              UWORD8 *pu1_dst,\n                              WORD32 src_strd,\n                              WORD32 dst_strd,\n                              WORD32 log_wd,\n                              WORD32 wt,\n                              WORD32 ofst,\n                              WORD32 ht,\n                              WORD32 wd)\n{\n    WORD32 i, j;\n\n    wt = (WORD16)(wt & 0xffff);\n    ofst = (WORD8)(ofst & 0xff);\n\n    src_strd -= wd;\n    dst_strd -= wd;\n\n    if(log_wd >= 1)\n    {\n        WORD32 i_ofst = (1 << (log_wd - 1)) + (ofst << log_wd);\n        for(i = 0; i < ht; i++)\n        {\n            for(j = 0; j < wd; j++, pu1_src++, pu1_dst++)\n                *pu1_dst = CLIP_U8((wt * (*pu1_src) + i_ofst) >> log_wd);\n\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n        }\n    }\n    else\n    {\n        for(i = 0; i < ht; i++)\n        {\n            for(j = 0; j < wd; j++, pu1_src++, pu1_dst++)\n                *pu1_dst = CLIP_U8(wt * (*pu1_src) + ofst);\n\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_weighted_pred_chroma                               */\n/*                                                                           */\n/*  Description   : This function performs the weighted prediction as        */\n/*                  described in sec 8.4.2.3.2 titled \"Weighted sample       */\n/*                  prediction process\" for chroma. The function gets one    */\n/*                  ht x wd block, weights it, rounds it off, offsets it,    */\n/*                  saturates it to unsigned 8-bit and stores it in the      */\n/*                  destination block. (ht,wd) can be (2,2), (4,2), (2,4),   */\n/*                  (4,4), (8,4), (4,8) or (8,8).                            */\n/*                                                                           */\n/*  Inputs        : puc_src  - Pointer to source                             */\n/*                  puc_dst  - Pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  log_wd   - number of bits to be rounded off              */\n/*                  wt       - weight values for u and v                     */\n/*                  ofst     - offset values for u and v                     */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         07 01 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_weighted_pred_chroma(UWORD8 *pu1_src,\n                                UWORD8 *pu1_dst,\n                                WORD32 src_strd,\n                                WORD32 dst_strd,\n                                WORD32 log_wd,\n                                WORD32 wt,\n                                WORD32 ofst,\n                                WORD32 ht,\n                                WORD32 wd)\n{\n    WORD32 i, j;\n    WORD32 wt_u, wt_v;\n    WORD32 ofst_u, ofst_v;\n\n    wt_u = (WORD16)(wt & 0xffff);\n    wt_v = (WORD16)(wt >> 16);\n\n    ofst_u = (WORD8)(ofst & 0xff);\n    ofst_v = (WORD8)(ofst >> 8);\n\n    src_strd -= wd << 1;\n    dst_strd -= wd << 1;\n\n    if(log_wd >= 1)\n    {\n        ofst_u = (1 << (log_wd - 1)) + (ofst_u << log_wd);\n        ofst_v = (1 << (log_wd - 1)) + (ofst_v << log_wd);\n\n        for(i = 0; i < ht; i++)\n        {\n            for(j = 0; j < wd; j++, pu1_src++, pu1_dst++)\n            {\n                *pu1_dst = CLIP_U8((wt_u * (*pu1_src) + ofst_u) >> log_wd);\n                pu1_src++;\n                pu1_dst++;\n                *pu1_dst = CLIP_U8((wt_v * (*pu1_src) + ofst_v) >> log_wd);\n            }\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n        }\n    }\n    else\n    {\n        for(i = 0; i < ht; i++)\n        {\n            for(j = 0; j < wd; j++, pu1_src++, pu1_dst++)\n            {\n                *pu1_dst = CLIP_U8(wt_u * (*pu1_src) + ofst_u);\n                pu1_src++;\n                pu1_dst++;\n                *pu1_dst = CLIP_U8(wt_v * (*pu1_src) + ofst_v);\n            }\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_weighted_bi_pred_luma                              */\n/*                                                                           */\n/*  Description   : This function performs the weighted biprediction as      */\n/*                  described in sec 8.4.2.3.2 titled \"Weighted sample       */\n/*                  prediction process\" for luma. The function gets two      */\n/*                  ht x wd blocks, weights them, adds them, rounds off the  */\n/*                  sum, offsets it, saturates it to unsigned 8-bit and      */\n/*                  stores it in the destination block. (ht,wd) can be       */\n/*                  (4,4), (8,4), (4,8), (8,8), (16,8), (8,16) or (16,16).   */\n/*                                                                           */\n/*  Inputs        : puc_src1  - Pointer to source 1                          */\n/*                  puc_src2  - Pointer to source 2                          */\n/*                  puc_dst   - Pointer to destination                       */\n/*                  src_strd1 - stride for source 1                          */\n/*                  src_strd2 - stride for source 2                          */\n/*                  dst_strd2 - stride for destination                       */\n/*                  log_wd    - number of bits to be rounded off             */\n/*                  wt1       - weight value for source 1                    */\n/*                  wt2       - weight value for source 2                    */\n/*                  ofst1     - offset value for source 1                    */\n/*                  ofst2     - offset value for source 2                    */\n/*                  ht        - height of the block                          */\n/*                  wd        - width of the block                           */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         07 01 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_weighted_bi_pred_luma(UWORD8 *pu1_src1,\n                                 UWORD8 *pu1_src2,\n                                 UWORD8 *pu1_dst,\n                                 WORD32 src_strd1,\n                                 WORD32 src_strd2,\n                                 WORD32 dst_strd,\n                                 WORD32 log_wd,\n                                 WORD32 wt1,\n                                 WORD32 wt2,\n                                 WORD32 ofst1,\n                                 WORD32 ofst2,\n                                 WORD32 ht,\n                                 WORD32 wd)\n{\n    WORD32 i, j;\n    WORD32 shft, ofst;\n\n    ofst1 = (WORD8)(ofst1 & 0xff);\n    ofst2 = (WORD8)(ofst2 & 0xff);\n    wt1 = (WORD16)(wt1 & 0xffff);\n    wt2 = (WORD16)(wt2 & 0xffff);\n    ofst = (ofst1 + ofst2 + 1) >> 1;\n\n    shft = log_wd + 1;\n    ofst = (1 << log_wd) + (ofst << shft);\n\n    src_strd1 -= wd;\n    src_strd2 -= wd;\n    dst_strd -= wd;\n\n    for(i = 0; i < ht; i++)\n    {\n        for(j = 0; j < wd; j++, pu1_src1++, pu1_src2++, pu1_dst++)\n            *pu1_dst = CLIP_U8((wt1 * (*pu1_src1) + wt2 * (*pu1_src2) + ofst) >> shft);\n\n        pu1_src1 += src_strd1;\n        pu1_src2 += src_strd2;\n        pu1_dst += dst_strd;\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_weighted_bi_pred_chroma                            */\n/*                                                                           */\n/*  Description   : This function performs the weighted biprediction as      */\n/*                  described in sec 8.4.2.3.2 titled \"Weighted sample       */\n/*                  prediction process\" for chroma. The function gets two    */\n/*                  ht x wd blocks, weights them, adds them, rounds off the  */\n/*                  sum, offsets it, saturates it to unsigned 8-bit and      */\n/*                  stores it in the destination block. (ht,wd) can be       */\n/*                  (2,2), (4,2), (2,4), (4,4), (8,4), (4,8) or (8,8).       */\n/*                                                                           */\n/*  Inputs        : puc_src1  - Pointer to source 1                          */\n/*                  puc_src2  - Pointer to source 2                          */\n/*                  puc_dst   - Pointer to destination                       */\n/*                  src_strd1 - stride for source 1                          */\n/*                  src_strd2 - stride for source 2                          */\n/*                  dst_strd2 - stride for destination                       */\n/*                  log_wd    - number of bits to be rounded off             */\n/*                  wt1       - weight values for u and v in source 1        */\n/*                  wt2       - weight values for u and v in source 2        */\n/*                  ofst1     - offset value for u and v in source 1         */\n/*                  ofst2     - offset value for u and v in source 2         */\n/*                  ht        - height of the block                          */\n/*                  wd        - width of the block                           */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         07 01 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264_weighted_bi_pred_chroma(UWORD8 *pu1_src1,\n                                   UWORD8 *pu1_src2,\n                                   UWORD8 *pu1_dst,\n                                   WORD32 src_strd1,\n                                   WORD32 src_strd2,\n                                   WORD32 dst_strd,\n                                   WORD32 log_wd,\n                                   WORD32 wt1,\n                                   WORD32 wt2,\n                                   WORD32 ofst1,\n                                   WORD32 ofst2,\n                                   WORD32 ht,\n                                   WORD32 wd)\n{\n    WORD32 i, j;\n    WORD32 wt1_u, wt1_v, wt2_u, wt2_v;\n    WORD32 ofst1_u, ofst1_v, ofst2_u, ofst2_v;\n    WORD32 ofst_u, ofst_v;\n    WORD32 shft;\n\n    ofst1_u = (WORD8)(ofst1 & 0xff);\n    ofst1_v = (WORD8)(ofst1 >> 8);\n    ofst2_u = (WORD8)(ofst2 & 0xff);\n    ofst2_v = (WORD8)(ofst2 >> 8);\n    wt1_u = (WORD16)(wt1 & 0xffff);\n    wt1_v = (WORD16)(wt1 >> 16);\n    wt2_u = (WORD16)(wt2 & 0xffff);\n    wt2_v = (WORD16)(wt2 >> 16);\n    ofst_u = (ofst1_u + ofst2_u + 1) >> 1;\n    ofst_v = (ofst1_v + ofst2_v + 1) >> 1;\n\n    src_strd1 -= wd << 1;\n    src_strd2 -= wd << 1;\n    dst_strd -= wd << 1;\n\n    shft = log_wd + 1;\n    ofst_u = (1 << log_wd) + (ofst_u << shft);\n    ofst_v = (1 << log_wd) + (ofst_v << shft);\n\n    for(i = 0; i < ht; i++)\n    {\n        for(j = 0; j < wd; j++, pu1_src1++, pu1_src2++, pu1_dst++)\n        {\n            *pu1_dst = CLIP_U8((wt1_u * (*pu1_src1) + wt2_u * (*pu1_src2) + ofst_u) >> shft);\n            pu1_src1++;\n            pu1_src2++;\n            pu1_dst++;\n            *pu1_dst = CLIP_U8((wt1_v * (*pu1_src1) + wt2_v * (*pu1_src2) + ofst_v) >> shft);\n        }\n        pu1_src1 += src_strd1;\n        pu1_src2 += src_strd2;\n        pu1_dst += dst_strd;\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/ih264_weighted_pred.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/**\n*******************************************************************************\n* @file\n*  ih264_weighted_pred.h\n*\n* @brief\n*  Declarations of functions used for weighted prediction\n*\n* @author\n*  Ittiam\n*\n* @par List of Functions:\n*  -ih264_default_weighted_pred_luma\n*  -ih264_default_weighted_pred_chroma\n*  -ih264_weighted_pred_luma\n*  -ih264_weighted_pred_chroma\n*  -ih264_weighted_bi_pred_luma\n*  -ih264_weighted_bi_pred_chroma\n*  -ih264_default_weighted_pred_luma_a9q\n*  -ih264_default_weighted_pred_chroma_a9q\n*  -ih264_weighted_pred_luma_a9q\n*  -ih264_weighted_pred_luma_a9q\n*  -ih264_weighted_bi_pred_luma_a9q\n*  -ih264_weighted_bi_pred_chroma_a9q\n*  -ih264_default_weighted_pred_luma_av8\n*  -ih264_default_weighted_pred_chroma_av8\n*  -ih264_weighted_pred_luma_av8\n*  -ih264_weighted_pred_chroma_av8\n*  -ih264_weighted_bi_pred_luma_av8\n*  -ih264_weighted_bi_pred_chroma_av8\n*  -ih264_default_weighted_pred_luma_sse42\n*  -ih264_default_weighted_pred_chroma_sse42\n*  -ih264_weighted_pred_luma_sse42\n*  -ih264_weighted_pred_chroma_sse42\n*  -ih264_weighted_bi_pred_luma_sse42\n*  -ih264_weighted_bi_pred_chroma_sse42\n*\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n#ifndef IH264_WEIGHTED_PRED_H_\n#define IH264_WEIGHTED_PRED_H_\n\n/*****************************************************************************/\n/* Extern Function Declarations                                              */\n/*****************************************************************************/\ntypedef void ih264_default_weighted_pred_ft(UWORD8 *puc_src1,\n                                            UWORD8 *puc_src2,\n                                            UWORD8 *puc_dst,\n                                            WORD32 src_strd1,\n                                            WORD32 src_strd2,\n                                            WORD32 dst_strd,\n                                            WORD32 ht,\n                                            WORD32 wd);\n\ntypedef void ih264_weighted_pred_ft(UWORD8 *puc_src,\n                                    UWORD8 *puc_dst,\n                                    WORD32 src_strd,\n                                    WORD32 dst_strd,\n                                    WORD32 log_wd,\n                                    WORD32 wt,\n                                    WORD32 ofst,\n                                    WORD32 ht,\n                                    WORD32 wd);\n\ntypedef void ih264_weighted_bi_pred_ft(UWORD8 *puc_src1,\n                                       UWORD8 *puc_src2,\n                                       UWORD8 *puc_dst,\n                                       WORD32 src_strd1,\n                                       WORD32 src_strd2,\n                                       WORD32 dst_strd,\n                                       WORD32 log_wd,\n                                       WORD32 wt1,\n                                       WORD32 wt2,\n                                       WORD32 ofst1,\n                                       WORD32 ofst2,\n                                       WORD32 ht,\n                                       WORD32 wd);\n\n/* No NEON Declarations */\n\nih264_default_weighted_pred_ft ih264_default_weighted_pred_luma;\n\nih264_default_weighted_pred_ft ih264_default_weighted_pred_chroma;\n\nih264_weighted_pred_ft ih264_weighted_pred_luma;\n\nih264_weighted_pred_ft ih264_weighted_pred_chroma;\n\nih264_weighted_bi_pred_ft ih264_weighted_bi_pred_luma;\n\nih264_weighted_bi_pred_ft ih264_weighted_bi_pred_chroma;\n\n/* A9 NEON Declarations */\n\nih264_default_weighted_pred_ft ih264_default_weighted_pred_luma_a9q;\n\nih264_default_weighted_pred_ft ih264_default_weighted_pred_chroma_a9q;\n\nih264_weighted_pred_ft ih264_weighted_pred_luma_a9q;\n\nih264_weighted_pred_ft ih264_weighted_pred_chroma_a9q;\n\nih264_weighted_bi_pred_ft ih264_weighted_bi_pred_luma_a9q;\n\nih264_weighted_bi_pred_ft ih264_weighted_bi_pred_chroma_a9q;\n\n\n/* AV8 NEON Declarations */\n\nih264_default_weighted_pred_ft ih264_default_weighted_pred_luma_av8;\n\nih264_default_weighted_pred_ft ih264_default_weighted_pred_chroma_av8;\n\nih264_weighted_pred_ft ih264_weighted_pred_luma_av8;\n\nih264_weighted_pred_ft ih264_weighted_pred_chroma_av8;\n\nih264_weighted_bi_pred_ft ih264_weighted_bi_pred_luma_av8;\n\nih264_weighted_bi_pred_ft ih264_weighted_bi_pred_chroma_av8;\n\n\n/* SSE42 Intrinsic Declarations */\n\nih264_default_weighted_pred_ft ih264_default_weighted_pred_luma_sse42;\n\nih264_default_weighted_pred_ft ih264_default_weighted_pred_chroma_sse42;\n\nih264_weighted_pred_ft ih264_weighted_pred_luma_sse42;\n\nih264_weighted_pred_ft ih264_weighted_pred_chroma_sse42;\n\nih264_weighted_bi_pred_ft ih264_weighted_bi_pred_luma_sse42;\n\nih264_weighted_bi_pred_ft ih264_weighted_bi_pred_chroma_sse42;\n\n#endif /* IH264_WEIGHTED_PRED_H_ */\n\n/** Nothing past this point */\n"
  },
  {
    "path": "dependencies/ih264d/common/ithread.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n * Modified for use with Cemu emulator project\n*/\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ithread.c                                            */\n/*                                                                           */\n/*  Description       : Contains abstraction for threads, mutex and semaphores*/\n/*                                                                           */\n/*  List of Functions :                                                      */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         07 09 2012   Harish          Initial Version                      */\n/*****************************************************************************/\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n#include <string.h>\n#include \"ih264_typedefs.h\"\n\n\n\n#include \"ithread.h\"\n#include <sys/types.h>\n\n\n#define UNUSED(x) ((void)(x))\n\n//#define PTHREAD_AFFINITY\n//#define SYSCALL_AFFINITY\n\n#ifdef PTHREAD_AFFINITY\n#define _GNU_SOURCE\n#define __USE_GNU\n#endif\n\n#ifdef _WIN32\n\n#include <Windows.h>\n\n#else\n\n#include <pthread.h>\n#include <sched.h>\n#include <semaphore.h>\n#include <unistd.h>\n\n#endif\n\n#ifdef PTHREAD_AFFINITY\n#include <sys/prctl.h>\n#endif\n\n\n#ifdef _WIN32\n\nUWORD32 ithread_get_handle_size(void)\n{\n\treturn sizeof(HANDLE);\n}\n\nUWORD32 ithread_get_mutex_lock_size(void)\n{\n\treturn sizeof(CRITICAL_SECTION);\n}\n\nstruct _ithread_launch_param\n{\n\tvoid (*startFunc)(void* argument);\n\tvoid* argument;\n};\n\nDWORD WINAPI _ithread_WinThreadStartRoutine(LPVOID lpThreadParameter)\n{\n\tstruct _ithread_launch_param* param = (struct _ithread_launch_param*)lpThreadParameter;\n\ttypedef void *(*ThreadStartRoutineType)(void *);\n\tThreadStartRoutineType pfnThreadRoutine = (ThreadStartRoutineType)param->startFunc;\n\tvoid* arg = param->argument;\n\tfree(param);\n\tpfnThreadRoutine(arg);\n\treturn 0;\n}\n\nWORD32 ithread_create(void* thread_handle, void* attribute, void* strt, void* argument)\n{\n\tUNUSED(attribute);\n\tstruct _ithread_launch_param* param = malloc(sizeof(struct _ithread_launch_param));\n\tparam->startFunc = (void (*)(void*))strt;\n\tparam->argument = argument;\n\tHANDLE *handle = (HANDLE*)thread_handle;\n\t*handle = CreateThread(NULL, 0, _ithread_WinThreadStartRoutine, param, 0, NULL);\n\tif(*handle == NULL)\n\t{\n\t\treturn -1;\n\t}\n\treturn 0;\n}\n\nWORD32 ithread_join(void* thread_handle, void** val_ptr)\n{\n\t//UNUSED(val_ptr);\n\tHANDLE *handle = (HANDLE*)thread_handle;\n\tDWORD result = WaitForSingleObject(*handle, INFINITE);\n\tif(result == WAIT_OBJECT_0)\n\t{\n\t\tCloseHandle(*handle);\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\treturn -1;\n\t}\n}\n\nWORD32 ithread_get_mutex_struct_size(void)\n{\n\treturn sizeof(CRITICAL_SECTION);\n}\n\nWORD32 ithread_mutex_init(void* mutex)\n{\n\tInitializeCriticalSection((LPCRITICAL_SECTION)mutex);\n\treturn 0;\n}\n\nWORD32 ithread_mutex_destroy(void* mutex)\n{\n\treturn 0;\n}\n\nWORD32 ithread_mutex_lock(void* mutex)\n{\n\tEnterCriticalSection((LPCRITICAL_SECTION)mutex);\n\treturn 0;\n}\n\nWORD32 ithread_mutex_unlock(void* mutex)\n{\n\tLeaveCriticalSection((LPCRITICAL_SECTION)mutex);\n\treturn 0;\n}\n\nvoid ithread_yield(void)\n{\n\tSleep(0);\n}\n\nvoid ithread_msleep(UWORD32 u4_time_ms)\n{\n\tSleep(u4_time_ms);\n}\n\nvoid ithread_usleep(UWORD32 u4_time_us)\n{\n\t__debugbreak();\n\t//usleep(u4_time_us);\n}\n\nUWORD32 ithread_get_sem_struct_size(void)\n{\n\t__debugbreak();\n\treturn 0;\n\t//return(sizeof(sem_t));\n}\n\nWORD32 ithread_sem_init(void* sem, WORD32 pshared, UWORD32 value)\n{\n\t__debugbreak();\n\treturn 0;\n\t//return sem_init((sem_t*)sem, pshared, value);\n}\n\nWORD32 ithread_sem_post(void* sem)\n{\n\t__debugbreak();\n\treturn 0;\n\t//return sem_post((sem_t*)sem);\n}\n\nWORD32 ithread_sem_wait(void* sem)\n{\n\t__debugbreak();\n\treturn 0;\n\t//return sem_wait((sem_t*)sem);\n}\n\nWORD32 ithread_sem_destroy(void* sem)\n{\n\t__debugbreak();\n\treturn 0;\n\t//return sem_destroy((sem_t*)sem);\n}\n\nvoid ithread_set_name(CHAR* pc_thread_name)\n{\n\n}\n\nWORD32 ithread_set_affinity(WORD32 core_id)\n{\n#ifdef PTHREAD_AFFINITY\n\tcpu_set_t cpuset;\n\tint num_cores = sysconf(_SC_NPROCESSORS_ONLN);\n\tpthread_t cur_thread = pthread_self();\n\n\tif (core_id >= num_cores)\n\t\treturn -1;\n\n\tCPU_ZERO(&cpuset);\n\tCPU_SET(core_id, &cpuset);\n\n\treturn pthread_setaffinity_np(cur_thread, sizeof(cpu_set_t), &cpuset);\n\n#elif SYSCALL_AFFINITY\n\tWORD32 i4_sys_res;\n\tUNUSED(core_id);\n\n\tpid_t pid = gettid();\n\n\n\ti4_sys_res = syscall(__NR_sched_setaffinity, pid, sizeof(i4_mask), &i4_mask);\n\tif (i4_sys_res)\n\t{\n\t\t//WORD32 err;\n\t\t//err = errno;\n\t\t//perror(\"Error in setaffinity syscall PERROR : \");\n\t\t//LOG_ERROR(\"Error in the syscall setaffinity: mask=0x%x err=0x%x\", i4_mask, i4_sys_res);\n\t\treturn -1;\n\t}\n#else\n\tUNUSED(core_id);\n#endif\n\treturn 1;\n}\n\n#else\n\nUWORD32 ithread_get_handle_size(void)\n{\n\treturn sizeof(pthread_t);\n}\n\nUWORD32 ithread_get_mutex_lock_size(void)\n{\n\treturn sizeof(pthread_mutex_t);\n}\n\nWORD32 ithread_create(void* thread_handle, void* attribute, void* strt, void* argument)\n{\n\tUNUSED(attribute);\n\treturn pthread_create((pthread_t*)thread_handle, NULL, (void* (*)(void*)) strt, argument);\n}\n\nWORD32 ithread_join(void* thread_handle, void** val_ptr)\n{\n\tUNUSED(val_ptr);\n\tpthread_t* pthread_handle = (pthread_t*)thread_handle;\n\treturn pthread_join(*pthread_handle, NULL);\n}\n\nWORD32 ithread_get_mutex_struct_size(void)\n{\n\treturn(sizeof(pthread_mutex_t));\n}\nWORD32 ithread_mutex_init(void* mutex)\n{\n\treturn pthread_mutex_init((pthread_mutex_t*)mutex, NULL);\n}\n\nWORD32 ithread_mutex_destroy(void* mutex)\n{\n\treturn pthread_mutex_destroy((pthread_mutex_t*)mutex);\n}\n\nWORD32 ithread_mutex_lock(void* mutex)\n{\n\treturn pthread_mutex_lock((pthread_mutex_t*)mutex);\n}\n\nWORD32 ithread_mutex_unlock(void* mutex)\n{\n\treturn pthread_mutex_unlock((pthread_mutex_t*)mutex);\n}\n\nvoid ithread_yield(void)\n{\n\tsched_yield();\n}\n\nvoid ithread_msleep(UWORD32 u4_time_ms)\n{\n\tusleep(u4_time_ms * 1000);\n}\n\nUWORD32 ithread_get_sem_struct_size(void)\n{\n\treturn(sizeof(sem_t));\n}\n\n\nWORD32 ithread_sem_init(void* sem, WORD32 pshared, UWORD32 value)\n{\n\treturn sem_init((sem_t*)sem, pshared, value);\n}\n\nWORD32 ithread_sem_post(void* sem)\n{\n\treturn sem_post((sem_t*)sem);\n}\n\n\nWORD32 ithread_sem_wait(void* sem)\n{\n\treturn sem_wait((sem_t*)sem);\n}\n\n\nWORD32 ithread_sem_destroy(void* sem)\n{\n\treturn sem_destroy((sem_t*)sem);\n}\n\nvoid ithread_set_name(CHAR* pc_thread_name)\n{\n\tUNUSED(pc_thread_name);\n}\n\nWORD32 ithread_set_affinity(WORD32 core_id)\n{\n#ifdef PTHREAD_AFFINITY\n\tcpu_set_t cpuset;\n\tint num_cores = sysconf(_SC_NPROCESSORS_ONLN);\n\tpthread_t cur_thread = pthread_self();\n\n\tif (core_id >= num_cores)\n\t\treturn -1;\n\n\tCPU_ZERO(&cpuset);\n\tCPU_SET(core_id, &cpuset);\n\n\treturn pthread_setaffinity_np(cur_thread, sizeof(cpu_set_t), &cpuset);\n\n#elif SYSCALL_AFFINITY\n\tWORD32 i4_sys_res;\n\tUNUSED(core_id);\n\n\tpid_t pid = gettid();\n\n\n\ti4_sys_res = syscall(__NR_sched_setaffinity, pid, sizeof(i4_mask), &i4_mask);\n\tif (i4_sys_res)\n\t{\n\t\t//WORD32 err;\n\t\t//err = errno;\n\t\t//perror(\"Error in setaffinity syscall PERROR : \");\n\t\t//LOG_ERROR(\"Error in the syscall setaffinity: mask=0x%x err=0x%x\", i4_mask, i4_sys_res);\n\t\treturn -1;\n\t}\n#else\n\tUNUSED(core_id);\n#endif\n\treturn 1;\n\n}\n\n#endif"
  },
  {
    "path": "dependencies/ih264d/common/ithread.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ithread.h                                            */\n/*                                                                           */\n/*  Description       : This file contains all the necessary structure and   */\n/*                      enumeration definitions needed for the Application   */\n/*                      Program Interface(API) of the                        */\n/*                      Thread Abstraction Layer                             */\n/*                                                                           */\n/*  List of Functions :     ithread_get_handle_size                          */\n/*                          ithread_get_mutex_lock_size                      */\n/*                          ithread_create                                   */\n/*                          ithread_join                                     */\n/*                          ithread_get_mutex_struct_size                    */\n/*                          ithread_mutex_init                               */\n/*                          ithread_mutex_destroy                            */\n/*                          ithread_mutex_lock                               */\n/*                          ithread_mutex_unlock                             */\n/*                          ithread_yield                                    */\n/*                          ithread_sleep                                    */\n/*                          ithread_msleep                                   */\n/*                          ithread_usleep                                   */\n/*                          ithread_get_sem_struct_size                      */\n/*                          ithread_sem_init                                 */\n/*                          ithread_sem_post                                 */\n/*                          ithread_sem_wait                                 */\n/*                          ithread_sem_destroy                              */\n/*                          ithread_set_affinity                             */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         06 09 2012   Harish          Initial Version                      */\n/*                                                                           */\n/*****************************************************************************/\n\n#ifndef _ITHREAD_H_\n#define _ITHREAD_H_\n\nUWORD32 ithread_get_handle_size(void);\n\nUWORD32 ithread_get_mutex_lock_size(void);\n\nWORD32  ithread_create(void *thread_handle, void *attribute, void *strt, void *argument);\n\nWORD32  ithread_join(void *thread_id, void ** val_ptr);\n\nWORD32  ithread_get_mutex_struct_size(void);\n\nWORD32  ithread_mutex_init(void *mutex);\n\nWORD32  ithread_mutex_destroy(void *mutex);\n\nWORD32  ithread_mutex_lock(void *mutex);\n\nWORD32  ithread_mutex_unlock(void *mutex);\n\nvoid    ithread_yield(void);\n\nvoid    ithread_msleep(UWORD32 u4_time_ms);\n\nvoid    ithread_usleep(UWORD32 u4_time_us);\n\nUWORD32 ithread_get_sem_struct_size(void);\n\nWORD32  ithread_sem_init(void *sem,WORD32 pshared,UWORD32 value);\n\nWORD32  ithread_sem_post(void *sem);\n\nWORD32  ithread_sem_wait(void *sem);\n\nWORD32  ithread_sem_destroy(void *sem);\n\nWORD32  ithread_set_affinity(WORD32 core_id);\n\nvoid    ithread_set_name(CHAR *pc_thread_name);\n\n#endif /* _ITHREAD_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/mips/ih264_platform_macros.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_platform_macros.h\n*\n* @brief\n*  Platform specific Macro definitions used in the codec\n*\n* @author\n*  Ittiam\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n\n#ifndef _IH264_PLATFORM_MACROS_H_\n#define _IH264_PLATFORM_MACROS_H_\n\n#include <stdint.h>\n\n#define CLIP_U8(x) CLIP3(0, UINT8_MAX, (x))\n#define CLIP_S8(x) CLIP3(INT8_MIN, INT8_MAX, (x))\n\n#define CLIP_U10(x) CLIP3(0, 1023, (x))\n#define CLIP_S10(x) CLIP3(-512, 511, (x))\n\n#define CLIP_U11(x) CLIP3(0, 2047, (x))\n#define CLIP_S11(x) CLIP3(-1024, 1023, (x))\n\n#define CLIP_U12(x) CLIP3(0, 4095, (x))\n#define CLIP_S12(x) CLIP3(-2048, 2047, (x))\n\n#define CLIP_U16(x) CLIP3(0, UINT16_MAX, (x))\n#define CLIP_S16(x) CLIP3(INT16_MIN, INT16_MAX, (x))\n\n#define CLIP_U32(x) CLIP3(0, UINT32_MAX, (x))\n#define CLIP_S32(x) CLIP3(INT32_MIN, INT32_MAX, (x))\n\n#define MEM_ALIGN16 __attribute__ ((aligned (16)))\n\n#define SHL(x,y) (((y) < 32) ? ((x) << (y)) : 0)\n#define SHR(x,y) (((y) < 32) ? ((x) >> (y)) : 0)\n\n#define SHR_NEG(val,shift)  ((shift>0)?(val>>shift):(val<<(-shift)))\n#define SHL_NEG(val,shift)  ((shift<0)?(val>>(-shift)):(val<<shift))\n\n\n#define ITT_BIG_ENDIAN(x)       ((x << 24))                |   \\\n                            ((x & 0x0000ff00) << 8)    |   \\\n                            ((x & 0x00ff0000) >> 8)    |   \\\n                            ((UWORD32)x >> 24);\n\n\n#define NOP(nop_cnt)    {UWORD32 nop_i; for (nop_i = 0; nop_i < nop_cnt; nop_i++);}\n\n#define PLD(a)\n\n/* In normal cases, 0 will not be passed as an argument to CLZ and CTZ.\nAs CLZ and CTZ outputs are used as a shift value in few places, these return\n31 for u4_word == 0 case, just to handle error cases gracefully without any\nundefined behaviour */\n\nstatic __inline UWORD32 CLZ(UWORD32 u4_word)\n{\n    if(u4_word)\n    return(__builtin_clz(u4_word));\n    else\n        return 31;\n}\n\nstatic __inline UWORD32 CTZ(UWORD32 u4_word)\n{\n    if(0 == u4_word)\n        return 31;\n    else\n    {\n        unsigned int index;\n        index = __builtin_ctz(u4_word);\n        return (UWORD32)index;\n    }\n}\n\n#define DATA_SYNC()\n\n#define INLINE\n\n#define PREFETCH(ptr, type)\n\n#define MEM_ALIGN8 __attribute__ ((aligned (8)))\n#define MEM_ALIGN16 __attribute__ ((aligned (16)))\n#define MEM_ALIGN32 __attribute__ ((aligned (32)))\n\n#endif /* _IH264_PLATFORM_MACROS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_chroma_intra_pred_filters_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_chroma_intra_pred_filters_ssse3.c\n*\n* @brief\n*  Contains function definitions for chroma intra prediction filters in x86\n*  intrinsics\n*\n* @author\n*  Ittiam\n*\n* @par List of Functions:\n*  -ih264_intra_pred_chroma_8x8_mode_horz_ssse3\n*  -ih264_intra_pred_chroma_8x8_mode_vert_ssse3\n*  -ih264_intra_pred_chroma_8x8_mode_plane_ssse3\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System include files */\n#include <stdio.h>\n#include <stddef.h>\n#include <string.h>\n\n/* User include files */\n#include \"ih264_defs.h\"\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_intra_pred_filters.h\"\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n/*****************************************************************************/\n/* Chroma Intra prediction 8x8 filters                                       */\n/*****************************************************************************/\n/**\n*******************************************************************************\n*\n* ih264_intra_pred_chroma_8x8_mode_horz_ssse3\n*\n* @brief\n*  Perform Intra prediction for chroma_8x8 mode:Horizontal\n*\n* @par Description:\n*  Perform Intra prediction for chroma_8x8 mode:Horizontal ,described in sec 8.3.4.2\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source containing alternate U and V samples\n*\n* @param[out] pu1_dst\n*  UWORD8 pointer to the destination with alternate U and V samples\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] dst_strd\n*  integer destination stride\n*\n* @param[in] ngbr_avail\n* availability of neighbouring pixels(Not used in this function)\n*\n* @returns\n*\n* @remarks\n*  None\n*\n******************************************************************************\n*/\n\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_chroma_8x8_mode_horz_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n\n    UWORD8 *pu1_left; /* Pointer to start of top predictors */\n    WORD32 dst_strd2;\n\n    __m128i row1_16x8b, row2_16x8b;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_left = pu1_src + 2 * BLK8x8SIZE - 2;\n\n\n    dst_strd2 = dst_strd << 1;\n    row1_16x8b = _mm_set1_epi16(*((WORD16 *)(pu1_left)));\n    row2_16x8b = _mm_set1_epi16(*((WORD16 *)(pu1_left - 2)));\n    _mm_storeu_si128((__m128i *)pu1_dst, row1_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), row2_16x8b);\n\n    pu1_dst += dst_strd2;\n    row1_16x8b = _mm_set1_epi16(*((WORD16 *)(pu1_left - 4)));\n    row2_16x8b = _mm_set1_epi16(*((WORD16 *)(pu1_left - 6)));\n    _mm_storeu_si128((__m128i *)pu1_dst, row1_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), row2_16x8b);\n\n    pu1_dst += dst_strd2;\n    row1_16x8b = _mm_set1_epi16(*((WORD16 *)(pu1_left - 8)));\n    row2_16x8b = _mm_set1_epi16(*((WORD16 *)(pu1_left - 10)));\n    _mm_storeu_si128((__m128i *)pu1_dst, row1_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), row2_16x8b);\n\n    pu1_dst += dst_strd2;\n    row1_16x8b = _mm_set1_epi16(*((WORD16 *)(pu1_left - 12)));\n    row2_16x8b = _mm_set1_epi16(*((WORD16 *)(pu1_left - 14)));\n    _mm_storeu_si128((__m128i *)pu1_dst, row1_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), row2_16x8b);\n}\n\n/**\n*******************************************************************************\n*\n* ih264_intra_pred_chroma_8x8_mode_vert_ssse3\n*\n* @brief\n*  Perform Intra prediction for  chroma_8x8 mode:vertical\n*\n* @par Description:\n*  Perform Intra prediction for  chroma_8x8 mode:vertical ,described in sec 8.3.4.3\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source containing alternate U and V samples\n*\n* @param[out] pu1_dst\n*  UWORD8 pointer to the destination with alternate U and V samples\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] dst_strd\n*  integer destination stride\n*\n* @param[in] ngbr_avail\n* availability of neighbouring pixels(Not used in this function)\n*\n* @returns\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_chroma_8x8_mode_vert_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top; /* Pointer to start of top predictors */\n    WORD32 dst_strd2;\n\n    __m128i top_16x8b;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_top = pu1_src + 2 * BLK8x8SIZE + 2;\n\n    top_16x8b = _mm_loadu_si128((__m128i *)pu1_top);\n\n    dst_strd2 = dst_strd << 1;\n    _mm_storeu_si128((__m128i *)pu1_dst, top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), top_16x8b);\n\n    pu1_dst += dst_strd2;\n    _mm_storeu_si128((__m128i *)pu1_dst, top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), top_16x8b);\n\n    pu1_dst += dst_strd2;\n    _mm_storeu_si128((__m128i *)pu1_dst, top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), top_16x8b);\n\n    pu1_dst += dst_strd2;\n    _mm_storeu_si128((__m128i *)pu1_dst, top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), top_16x8b);\n}\n\n/**\n*******************************************************************************\n*\n* ih264_intra_pred_chroma_8x8_mode_plane_ssse3\n*\n* @brief\n*  Perform Intra prediction for chroma_8x8 mode:PLANE\n*\n* @par Description:\n*  Perform Intra prediction for chroma_8x8 mode:PLANE ,described in sec 8.3.4.4\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source containing alternate U and V samples\n*\n* @param[out] pu1_dst\n*  UWORD8 pointer to the destination with alternate U and V samples\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] dst_strd\n*  integer destination stride\n*\n* @param[in] ngbr_avail\n* availability of neighbouring pixels(Not used in this function)\n*\n* @returns\n*\n* @remarks\n*  None\n*\n******************************************************************************\n*/\n\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_chroma_8x8_mode_plane_ssse3(UWORD8 *pu1_src,\n                                                  UWORD8 *pu1_dst,\n                                                  WORD32 src_strd,\n                                                  WORD32 dst_strd,\n                                                  WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left, *pu1_top;\n    WORD32 a_u, a_v, b_u, b_v, c_u, c_v;\n\n    __m128i mul_8x16b, shuffle_8x16b;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_top = pu1_src + MB_SIZE + 2;\n    pu1_left = pu1_src + MB_SIZE - 2;\n\n    mul_8x16b = _mm_setr_epi16(1, 2, 3, 4, 1, 2, 3, 4);\n    shuffle_8x16b = _mm_setr_epi16(0xff00, 0xff02, 0xff04, 0xff06,\n                                   0xff01, 0xff03, 0xff05, 0xff07);\n\n    //calculating a, b and c\n    {\n        WORD32 h_u, h_v, v_u, v_v;\n\n        __m128i h_val1_16x8b, h_val2_16x8b;\n        __m128i h_val1_8x16b, h_val2_8x16b, h_val_4x32b;\n        __m128i v_val1_16x8b, v_val2_16x8b;\n        __m128i v_val1_8x16b, v_val2_8x16b, v_val_4x32b;\n        __m128i hv_val_4x32b;\n\n        h_val1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_top + 8));\n        h_val2_16x8b = _mm_loadl_epi64((__m128i *)(pu1_top - 2));\n        v_val1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_left - 14));\n        v_val2_16x8b = _mm_loadl_epi64((__m128i *)(pu1_left - 4));\n\n        // reversing the order\n        h_val2_16x8b = _mm_shufflelo_epi16(h_val2_16x8b, 0x1b);\n        v_val1_16x8b = _mm_shufflelo_epi16(v_val1_16x8b, 0x1b);\n\n        // separating u and v and 8-bit to 16-bit conversion\n        h_val1_8x16b = _mm_shuffle_epi8(h_val1_16x8b, shuffle_8x16b);\n        h_val2_8x16b = _mm_shuffle_epi8(h_val2_16x8b, shuffle_8x16b);\n        v_val1_8x16b = _mm_shuffle_epi8(v_val1_16x8b, shuffle_8x16b);\n        v_val2_8x16b = _mm_shuffle_epi8(v_val2_16x8b, shuffle_8x16b);\n\n        h_val1_8x16b = _mm_sub_epi16(h_val1_8x16b, h_val2_8x16b);\n        v_val1_8x16b = _mm_sub_epi16(v_val1_8x16b, v_val2_8x16b);\n\n        h_val_4x32b = _mm_madd_epi16(mul_8x16b, h_val1_8x16b);\n        v_val_4x32b = _mm_madd_epi16(mul_8x16b, v_val1_8x16b);\n\n        hv_val_4x32b = _mm_hadd_epi32(h_val_4x32b, v_val_4x32b);\n\n        a_u = (pu1_left[7 * (-2)] + pu1_top[14]) << 4;\n        a_v = (pu1_left[7 * (-2) + 1] + pu1_top[15]) << 4;\n\n        h_u = _mm_extract_epi16(hv_val_4x32b, 0);\n        h_v = _mm_extract_epi16(hv_val_4x32b, 2);\n        v_u = _mm_extract_epi16(hv_val_4x32b, 4);\n        v_v = _mm_extract_epi16(hv_val_4x32b, 6);\n\n        h_u = (h_u << 16) >> 15; // sign-extension and multiplication by 2\n        h_v = (h_v << 16) >> 15;\n        v_u = (v_u << 16) >> 15;\n        v_v = (v_v << 16) >> 15;\n\n        b_u = ((h_u << 4) + h_u + 32) >> 6;\n        b_v = ((h_v << 4) + h_v + 32) >> 6;\n        c_u = ((v_u << 4) + v_u + 32) >> 6;\n        c_v = ((v_v << 4) + v_v + 32) >> 6;\n    }\n    //using a, b and c to compute the fitted plane values\n    {\n        __m128i const_8x16b, c2_8x16b;\n        __m128i res1_l_8x16b, res1_h_8x16b;\n        __m128i res2_l_8x16b, res2_h_8x16b;\n        __m128i res1_sh_l_8x16b, res1_sh_h_8x16b, res1_16x8b;\n        __m128i res2_sh_l_8x16b, res2_sh_h_8x16b, res2_16x8b;\n\n        WORD32 b_u2, b_v2, b_u3, b_v3;\n        WORD32 const_u, const_v;\n        WORD32 dst_strd2;\n\n        const_u = a_u - (c_u << 1) - c_u + 16;\n        const_v = a_v - (c_v << 1) - c_v + 16;\n\n        b_u2 = b_u << 1;\n        b_v2 = b_v << 1;\n        b_u3 = b_u + b_u2;\n        b_v3 = b_v + b_v2;\n\n        const_8x16b = _mm_setr_epi16(const_u, const_v, const_u, const_v, const_u, const_v, const_u, const_v);\n        res1_l_8x16b = _mm_setr_epi16(-b_u3, -b_v3, -b_u2, -b_v2, -b_u, -b_v, 0, 0);\n        //contains {-b*3, -b*2, -b*1, b*0}\n        res1_h_8x16b = _mm_setr_epi16(b_u, b_v, b_u2, b_v2, b_u3, b_v3, b_u << 2, b_v << 2);\n        //contains {b*1, b*2, b*3, b*4}\n        c2_8x16b = _mm_setr_epi16(c_u, c_v, c_u, c_v, c_u, c_v, c_u, c_v);\n\n        // rows 1, 2\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, const_8x16b);\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, const_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n\n        dst_strd2 = dst_strd << 1;\n        c2_8x16b = _mm_slli_epi16(c2_8x16b, 1);\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n        // rows 3, 4\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res2_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res2_h_8x16b, c2_8x16b);\n\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n\n        pu1_dst += dst_strd2;\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n        // rows 5, 6\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res2_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res2_h_8x16b, c2_8x16b);\n\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n\n        pu1_dst += dst_strd2;\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n        // rows 7, 8\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res2_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res2_h_8x16b, c2_8x16b);\n\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n\n        pu1_dst += dst_strd2;\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_deblk_chroma_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264_deblk_chroma_ssse3.c                           */\n/*                                                                           */\n/*  Description       : Contains function definitions for deblocking         */\n/*                                                                           */\n/*  List of Functions : ih264_deblk_chroma_vert_bs4_ssse3()                  */\n/*                      ih264_deblk_chroma_horz_bs4_ssse3()                  */\n/*                      ih264_deblk_chroma_vert_bslt4_ssse3()                */\n/*                      ih264_deblk_chroma_horz_bslt4_ssse3()                */\n/*                      ih264_deblk_chroma_vert_bs4_mbaff_ssse3()            */\n/*                      ih264_deblk_chroma_vert_bslt4_mbaff_ssse3()          */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Added chrom deblocking ssse3         */\n/*                                      intrinsics                           */\n/*                                                                           */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System include files */\n#include <stdio.h>\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_deblk_edge_filters.h\"\n#include \"ih264_macros.h\"\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n/*****************************************************************************/\n/* Function Definitions                                                      */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bs4_ssse3()                      */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when the boundary strength is set to 4 in  */\n/*                  high profile.                                            */\n/*                                                                           */\n/*  Inputs        : pu1_src    - pointer to the src sample q0 of U           */\n/*                  src_strd   - source stride                               */\n/*                  alpha_cb   - alpha value for the boundary in U           */\n/*                  beta_cb    - beta value for the boundary in U            */\n/*                  alpha_cr   - alpha value for the boundary in V           */\n/*                  beta_cr    - beta value for the boundary in V            */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.4 under the    */\n/*                  title \"Filtering process for edges for bS equal to 4\" in */\n/*                  ITU T Rec H.264 with alpha and beta values different in  */\n/*                  U and V.                                                 */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\n\nATTRIBUTE_SSSE3\nvoid ih264_deblk_chroma_vert_bs4_ssse3(UWORD8 *pu1_src,\n                                       WORD32 src_strd,\n                                       WORD32 alpha_cb,\n                                       WORD32 beta_cb,\n                                       WORD32 alpha_cr,\n                                       WORD32 beta_cr)\n{\n    UWORD8 *pu1_src_uv = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    WORD32 alpha_cbcr = (alpha_cr << 16) + alpha_cb;\n    WORD32 beta_cbcr = (beta_cr << 16) + beta_cb;\n    __m128i linea, lineb, linec, lined, linee, linef, lineg, lineh;\n    __m128i temp1, temp2, temp3, temp4;\n\n    __m128i q0_uv_16x8, p0_uv_16x8, q1_uv_16x8, p1_uv_16x8;\n    __m128i q0_uv_8x16, p0_uv_8x16, q1_uv_8x16, p1_uv_8x16;\n    __m128i flag1, flag2;\n    __m128i diff, alpha_cbcr_16x8, beta_cbcr_16x8;\n    __m128i zero = _mm_setzero_si128();\n    __m128i p0_uv_8x16_1, p0_uv_8x16_2, q0_uv_8x16_1, q0_uv_8x16_2;\n\n    /* Load and transpose the pixel values */\n    linea = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4));\n    lineb = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + src_strd));\n    linec = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 2 * src_strd));\n    lined = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 3 * src_strd));\n    linee = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 4 * src_strd));\n    linef = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 5 * src_strd));\n    lineg = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 6 * src_strd));\n    lineh = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 7 * src_strd));\n\n    temp1 = _mm_unpacklo_epi16(linea, lineb);\n    temp2 = _mm_unpacklo_epi16(linec, lined);\n    temp3 = _mm_unpacklo_epi16(linee, linef);\n    temp4 = _mm_unpacklo_epi16(lineg, lineh);\n\n    p1_uv_8x16 = _mm_unpacklo_epi32(temp1, temp2);\n    p0_uv_8x16 = _mm_unpacklo_epi32(temp3, temp4);\n    q0_uv_8x16 = _mm_unpackhi_epi32(temp1, temp2);\n    q1_uv_8x16 = _mm_unpackhi_epi32(temp3, temp4);\n\n    p1_uv_16x8 = _mm_unpacklo_epi64(p1_uv_8x16, p0_uv_8x16);\n    p0_uv_16x8 = _mm_unpackhi_epi64(p1_uv_8x16, p0_uv_8x16);\n    q0_uv_16x8 = _mm_unpacklo_epi64(q0_uv_8x16, q1_uv_8x16);\n    q1_uv_16x8 = _mm_unpackhi_epi64(q0_uv_8x16, q1_uv_8x16);\n    /* End of transpose */\n\n    q0_uv_8x16 = _mm_unpacklo_epi8(q0_uv_16x8, zero);\n    q1_uv_8x16 = _mm_unpacklo_epi8(q1_uv_16x8, zero);\n    p1_uv_8x16 = _mm_unpacklo_epi8(p1_uv_16x8, zero);\n    p0_uv_8x16 = _mm_unpacklo_epi8(p0_uv_16x8, zero);\n\n    diff = _mm_subs_epi16(p0_uv_8x16, q0_uv_8x16); //Condn 1\n    diff = _mm_abs_epi16(diff);\n    alpha_cbcr_16x8 = _mm_set1_epi32(alpha_cbcr);\n    flag1 = _mm_cmpgt_epi16(alpha_cbcr_16x8, diff);\n\n    diff = _mm_subs_epi16(q1_uv_8x16, q0_uv_8x16); //Condtn 2\n    diff = _mm_abs_epi16(diff);\n    beta_cbcr_16x8 = _mm_set1_epi32(beta_cbcr);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(p1_uv_8x16, p0_uv_8x16); //Condtn 3\n    diff = _mm_abs_epi16(diff);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    temp1 = _mm_slli_epi16(p1_uv_8x16, 1);\n    temp2 = _mm_add_epi16(p0_uv_8x16, q1_uv_8x16);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(2));\n    temp1 = _mm_add_epi16(temp1, temp2);\n    p0_uv_8x16_1 = _mm_srai_epi16(temp1, 2);\n\n    temp1 = _mm_slli_epi16(q1_uv_8x16, 1);\n    temp2 = _mm_add_epi16(p1_uv_8x16, q0_uv_8x16);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(2));\n    temp1 = _mm_add_epi16(temp1, temp2);\n    q0_uv_8x16_1 = _mm_srai_epi16(temp1, 2);\n\n    q0_uv_8x16 = _mm_unpackhi_epi8(q0_uv_16x8, zero);\n    q1_uv_8x16 = _mm_unpackhi_epi8(q1_uv_16x8, zero);\n    p1_uv_8x16 = _mm_unpackhi_epi8(p1_uv_16x8, zero);\n    p0_uv_8x16 = _mm_unpackhi_epi8(p0_uv_16x8, zero);\n\n    diff = _mm_subs_epi16(p0_uv_8x16, q0_uv_8x16); //Condn 1\n    diff = _mm_abs_epi16(diff);\n    alpha_cbcr_16x8 = _mm_set1_epi32(alpha_cbcr);\n    flag2 = _mm_cmpgt_epi16(alpha_cbcr_16x8, diff);\n\n    diff = _mm_subs_epi16(q1_uv_8x16, q0_uv_8x16); //Condtn 2\n    diff = _mm_abs_epi16(diff);\n    beta_cbcr_16x8 = _mm_set1_epi32(beta_cbcr);\n    flag2 = _mm_and_si128(flag2, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(p1_uv_8x16, p0_uv_8x16); //Condtn 3\n    diff = _mm_abs_epi16(diff);\n    flag2 = _mm_and_si128(flag2, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    temp1 = _mm_slli_epi16(p1_uv_8x16, 1);\n    temp2 = _mm_add_epi16(p0_uv_8x16, q1_uv_8x16);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(2));\n    temp1 = _mm_add_epi16(temp1, temp2);\n    p0_uv_8x16_2 = _mm_srai_epi16(temp1, 2);\n\n    temp1 = _mm_slli_epi16(q1_uv_8x16, 1);\n    temp2 = _mm_add_epi16(p1_uv_8x16, q0_uv_8x16);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(2));\n    temp1 = _mm_add_epi16(temp1, temp2);\n    q0_uv_8x16_2 = _mm_srai_epi16(temp1, 2);\n\n    p0_uv_8x16_2 = _mm_packus_epi16(p0_uv_8x16_1, p0_uv_8x16_2);\n    q0_uv_8x16_2 = _mm_packus_epi16(q0_uv_8x16_1, q0_uv_8x16_2);\n\n    flag1 = _mm_packs_epi16(flag1, flag2);\n\n    p0_uv_8x16_1 = _mm_and_si128(p0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    p0_uv_8x16_2 = _mm_and_si128(p0_uv_8x16_2, flag1);\n    p0_uv_16x8 = _mm_add_epi8(p0_uv_8x16_1, p0_uv_8x16_2);\n\n    q0_uv_8x16_1 = _mm_and_si128(q0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    q0_uv_8x16_2 = _mm_and_si128(q0_uv_8x16_2, flag1);\n    q0_uv_16x8 = _mm_add_epi8(q0_uv_8x16_1, q0_uv_8x16_2);\n\n    /* Inverse-transpose and store back */\n    temp1 = _mm_unpacklo_epi16(p1_uv_16x8, p0_uv_16x8);\n    temp2 = _mm_unpackhi_epi16(p1_uv_16x8, p0_uv_16x8);\n    temp3 = _mm_unpacklo_epi16(q0_uv_16x8, q1_uv_16x8);\n    temp4 = _mm_unpackhi_epi16(q0_uv_16x8, q1_uv_16x8);\n\n    linea = _mm_unpacklo_epi32(temp1, temp3);\n    lineb = _mm_srli_si128(linea, 8);\n    linec = _mm_unpackhi_epi32(temp1, temp3);\n    lined = _mm_srli_si128(linec, 8);\n    linee = _mm_unpacklo_epi32(temp2, temp4);\n    linef = _mm_srli_si128(linee, 8);\n    lineg = _mm_unpackhi_epi32(temp2, temp4);\n    lineh = _mm_srli_si128(lineg, 8);\n\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4), linea);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + src_strd), lineb);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 2 * src_strd), linec);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 3 * src_strd), lined);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 4 * src_strd), linee);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 5 * src_strd), linef);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 6 * src_strd), lineg);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 7 * src_strd), lineh);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_horz_bs4_ssse3()                      */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  horizontal edge when the boundary strength is set to 4   */\n/*                  in high profile.                                         */\n/*                                                                           */\n/*  Inputs        : pu1_src    - pointer to the src sample q0 of U           */\n/*                  src_strd   - source stride                               */\n/*                  alpha_cb   - alpha value for the boundary in U           */\n/*                  beta_cb    - beta value for the boundary in U            */\n/*                  alpha_cr   - alpha value for the boundary in V           */\n/*                  beta_cr    - beta value for the boundary in V            */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.4 under the    */\n/*                  title \"Filtering process for edges for bS equal to 4\" in */\n/*                  ITU T Rec H.264 with alpha and beta values different in  */\n/*                  U and V.                                                 */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\n\nATTRIBUTE_SSSE3\nvoid ih264_deblk_chroma_horz_bs4_ssse3(UWORD8 *pu1_src,\n                                       WORD32 src_strd,\n                                       WORD32 alpha_cb,\n                                       WORD32 beta_cb,\n                                       WORD32 alpha_cr,\n                                       WORD32 beta_cr)\n{\n    UWORD8 *pu1_src_uv = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    WORD16 i16_posP1, i16_posP0, i16_posQ1;\n\n    UWORD8 *pu1_HorzPixelUV; /*! < Pointer to the first pixel of the boundary */\n    WORD32 alpha_cbcr = (alpha_cr << 16) + alpha_cb;\n    WORD32 beta_cbcr = (beta_cr << 16) + beta_cb;\n    __m128i q0_uv_16x8, p0_uv_16x8, q1_uv_16x8, p1_uv_16x8;\n    __m128i q0_uv_8x16, p0_uv_8x16, q1_uv_8x16, p1_uv_8x16;\n    __m128i flag1, flag2;\n    __m128i diff, alpha_cbcr_16x8, beta_cbcr_16x8;\n    __m128i zero = _mm_setzero_si128();\n    __m128i p0_uv_8x16_1, p0_uv_8x16_2, q0_uv_8x16_1, q0_uv_8x16_2;\n    __m128i temp1, temp2;\n\n    pu1_HorzPixelUV = pu1_src_uv - (src_strd << 1);\n\n    i16_posQ1 = src_strd;\n    i16_posP0 = src_strd;\n    i16_posP1 = 0;\n\n    q0_uv_16x8 = _mm_loadu_si128((__m128i *)(pu1_src_uv));\n    q1_uv_16x8 = _mm_loadu_si128((__m128i *)(pu1_src_uv + i16_posQ1));\n    p1_uv_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixelUV + i16_posP1));\n    p0_uv_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixelUV + i16_posP0));\n\n    q0_uv_8x16 = _mm_unpacklo_epi8(q0_uv_16x8, zero);\n    q1_uv_8x16 = _mm_unpacklo_epi8(q1_uv_16x8, zero);\n    p1_uv_8x16 = _mm_unpacklo_epi8(p1_uv_16x8, zero);\n    p0_uv_8x16 = _mm_unpacklo_epi8(p0_uv_16x8, zero);\n\n    diff = _mm_subs_epi16(p0_uv_8x16, q0_uv_8x16); //Condn 1\n    diff = _mm_abs_epi16(diff);\n    alpha_cbcr_16x8 = _mm_set1_epi32(alpha_cbcr);\n    flag1 = _mm_cmpgt_epi16(alpha_cbcr_16x8, diff);\n\n    diff = _mm_subs_epi16(q1_uv_8x16, q0_uv_8x16); //Condtn 2\n    diff = _mm_abs_epi16(diff);\n    beta_cbcr_16x8 = _mm_set1_epi32(beta_cbcr);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(p1_uv_8x16, p0_uv_8x16); //Condtn 3\n    diff = _mm_abs_epi16(diff);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    temp1 = _mm_slli_epi16(p1_uv_8x16, 1);\n    temp2 = _mm_add_epi16(p0_uv_8x16, q1_uv_8x16);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(2));\n    temp1 = _mm_add_epi16(temp1, temp2);\n    p0_uv_8x16_1 = _mm_srai_epi16(temp1, 2);\n\n    temp1 = _mm_slli_epi16(q1_uv_8x16, 1);\n    temp2 = _mm_add_epi16(p1_uv_8x16, q0_uv_8x16);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(2));\n    temp1 = _mm_add_epi16(temp1, temp2);\n    q0_uv_8x16_1 = _mm_srai_epi16(temp1, 2);\n\n    q0_uv_8x16 = _mm_unpackhi_epi8(q0_uv_16x8, zero);\n    q1_uv_8x16 = _mm_unpackhi_epi8(q1_uv_16x8, zero);\n    p1_uv_8x16 = _mm_unpackhi_epi8(p1_uv_16x8, zero);\n    p0_uv_8x16 = _mm_unpackhi_epi8(p0_uv_16x8, zero);\n\n    diff = _mm_subs_epi16(p0_uv_8x16, q0_uv_8x16); //Condn 1\n    diff = _mm_abs_epi16(diff);\n    alpha_cbcr_16x8 = _mm_set1_epi32(alpha_cbcr);\n    flag2 = _mm_cmpgt_epi16(alpha_cbcr_16x8, diff);\n\n    diff = _mm_subs_epi16(q1_uv_8x16, q0_uv_8x16); //Condtn 2\n    diff = _mm_abs_epi16(diff);\n    beta_cbcr_16x8 = _mm_set1_epi32(beta_cbcr);\n    flag2 = _mm_and_si128(flag2, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(p1_uv_8x16, p0_uv_8x16); //Condtn 3\n    diff = _mm_abs_epi16(diff);\n    flag2 = _mm_and_si128(flag2, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    temp1 = _mm_slli_epi16(p1_uv_8x16, 1);\n    temp2 = _mm_add_epi16(p0_uv_8x16, q1_uv_8x16);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(2));\n    temp1 = _mm_add_epi16(temp1, temp2);\n    p0_uv_8x16_2 = _mm_srai_epi16(temp1, 2);\n\n    temp1 = _mm_slli_epi16(q1_uv_8x16, 1);\n    temp2 = _mm_add_epi16(p1_uv_8x16, q0_uv_8x16);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(2));\n    temp1 = _mm_add_epi16(temp1, temp2);\n    q0_uv_8x16_2 = _mm_srai_epi16(temp1, 2);\n\n    p0_uv_8x16_2 = _mm_packus_epi16(p0_uv_8x16_1, p0_uv_8x16_2);\n    q0_uv_8x16_2 = _mm_packus_epi16(q0_uv_8x16_1, q0_uv_8x16_2);\n\n    flag1 = _mm_packs_epi16(flag1, flag2);\n\n    p0_uv_8x16_1 = _mm_and_si128(p0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    p0_uv_8x16_2 = _mm_and_si128(p0_uv_8x16_2, flag1);\n    p0_uv_8x16_1 = _mm_add_epi8(p0_uv_8x16_1, p0_uv_8x16_2);\n    _mm_storeu_si128((__m128i *)(pu1_HorzPixelUV + i16_posP0), p0_uv_8x16_1);\n\n    q0_uv_8x16_1 = _mm_and_si128(q0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    q0_uv_8x16_2 = _mm_and_si128(q0_uv_8x16_2, flag1);\n    q0_uv_8x16_1 = _mm_add_epi8(q0_uv_8x16_1, q0_uv_8x16_2);\n    _mm_storeu_si128((__m128i *)(pu1_src_uv), q0_uv_8x16_1);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bslt4_ssse3()                    */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when the boundary strength is less than 4  */\n/*                  in high profile.                                         */\n/*                                                                           */\n/*  Inputs        : pu1_src          - pointer to the src sample q0 of U     */\n/*                  src_strd         - source stride                         */\n/*                  alpha_cb         - alpha value for the boundary in U     */\n/*                  beta_cb          - beta value for the boundary in U      */\n/*                  alpha_cr         - alpha value for the boundary in V     */\n/*                  beta_cr          - beta value for the boundary in V      */\n/*                  u4_bs            - packed Boundary strength array        */\n/*                  pu1_cliptab_cb   - tc0_table for U                       */\n/*                  pu1_cliptab_cr   - tc0_table for V                       */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.3 under the    */\n/*                  title \"Filtering process for edges for bS less than 4\"   */\n/*                  in ITU T Rec H.264 with alpha and beta values different  */\n/*                  in U and V.                                              */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\n\nATTRIBUTE_SSSE3\nvoid ih264_deblk_chroma_vert_bslt4_ssse3(UWORD8 *pu1_src,\n                                         WORD32 src_strd,\n                                         WORD32 alpha_cb,\n                                         WORD32 beta_cb,\n                                         WORD32 alpha_cr,\n                                         WORD32 beta_cr,\n                                         UWORD32 u4_bs,\n                                         const UWORD8 *pu1_cliptab_cb,\n                                         const UWORD8 *pu1_cliptab_cr)\n{\n    UWORD8 *pu1_src_uv = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    UWORD8 u1_Bs0, u1_Bs1, u1_Bs2, u1_Bs3;\n    WORD32 alpha_cbcr = (alpha_cr << 16) + alpha_cb;\n    WORD32 beta_cbcr = (beta_cr << 16) + beta_cb;\n    __m128i linea, lineb, linec, lined, linee, linef, lineg, lineh;\n    __m128i temp1, temp2, temp3, temp4;\n\n    __m128i q0_uv_16x8, p0_uv_16x8, q1_uv_16x8, p1_uv_16x8;\n    __m128i q0_uv_8x16, p0_uv_8x16, q1_uv_8x16, p1_uv_8x16;\n    __m128i flag_bs, flag1, flag2;\n    __m128i diff, diff1, alpha_cbcr_16x8, beta_cbcr_16x8, in_macro;\n    __m128i zero = _mm_setzero_si128();\n    __m128i C0_uv_8x16;\n    __m128i p0_uv_8x16_1, p0_uv_8x16_2, q0_uv_8x16_1, q0_uv_8x16_2;\n\n    u1_Bs0 = (u4_bs >> 24) & 0xff;\n    u1_Bs1 = (u4_bs >> 16) & 0xff;\n    u1_Bs2 = (u4_bs >> 8) & 0xff;\n    u1_Bs3 = (u4_bs >> 0) & 0xff;\n\n    flag_bs = _mm_set_epi8(u1_Bs3, u1_Bs3, u1_Bs3, u1_Bs3, u1_Bs2, u1_Bs2,\n                           u1_Bs2, u1_Bs2, u1_Bs1, u1_Bs1, u1_Bs1, u1_Bs1,\n                           u1_Bs0, u1_Bs0, u1_Bs0, u1_Bs0);\n    flag_bs = _mm_cmpeq_epi8(flag_bs, zero); //Set flag to 1s and 0s\n    flag_bs = _mm_xor_si128(flag_bs, _mm_set1_epi8(0xFF)); //Invert for required mask\n\n    /* Load and transpose the pixel values */\n    linea = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4));\n    lineb = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + src_strd));\n    linec = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 2 * src_strd));\n    lined = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 3 * src_strd));\n    linee = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 4 * src_strd));\n    linef = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 5 * src_strd));\n    lineg = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 6 * src_strd));\n    lineh = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 7 * src_strd));\n\n    temp1 = _mm_unpacklo_epi16(linea, lineb);\n    temp2 = _mm_unpacklo_epi16(linec, lined);\n    temp3 = _mm_unpacklo_epi16(linee, linef);\n    temp4 = _mm_unpacklo_epi16(lineg, lineh);\n\n    p1_uv_8x16 = _mm_unpacklo_epi32(temp1, temp2);\n    p0_uv_8x16 = _mm_unpacklo_epi32(temp3, temp4);\n    q0_uv_8x16 = _mm_unpackhi_epi32(temp1, temp2);\n    q1_uv_8x16 = _mm_unpackhi_epi32(temp3, temp4);\n\n    p1_uv_16x8 = _mm_unpacklo_epi64(p1_uv_8x16, p0_uv_8x16);\n    p0_uv_16x8 = _mm_unpackhi_epi64(p1_uv_8x16, p0_uv_8x16);\n    q0_uv_16x8 = _mm_unpacklo_epi64(q0_uv_8x16, q1_uv_8x16);\n    q1_uv_16x8 = _mm_unpackhi_epi64(q0_uv_8x16, q1_uv_8x16);\n    /* End of transpose */\n\n    q0_uv_8x16 = _mm_unpacklo_epi8(q0_uv_16x8, zero);\n    q1_uv_8x16 = _mm_unpacklo_epi8(q1_uv_16x8, zero);\n    p1_uv_8x16 = _mm_unpacklo_epi8(p1_uv_16x8, zero);\n    p0_uv_8x16 = _mm_unpacklo_epi8(p0_uv_16x8, zero);\n\n    diff = _mm_subs_epi16(p0_uv_8x16, q0_uv_8x16); //Condn 1\n    diff = _mm_abs_epi16(diff);\n    alpha_cbcr_16x8 = _mm_set1_epi32(alpha_cbcr);\n    flag1 = _mm_cmpgt_epi16(alpha_cbcr_16x8, diff);\n\n    diff = _mm_subs_epi16(q1_uv_8x16, q0_uv_8x16); //Condtn 2\n    diff = _mm_abs_epi16(diff);\n    beta_cbcr_16x8 = _mm_set1_epi32(beta_cbcr);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(p1_uv_8x16, p0_uv_8x16); //Condtn 3\n    diff = _mm_abs_epi16(diff);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(q0_uv_8x16, p0_uv_8x16);\n    diff = _mm_slli_epi16(diff, 2);\n    diff1 = _mm_subs_epi16(p1_uv_8x16, q1_uv_8x16);\n    diff = _mm_add_epi16(diff, diff1);\n    diff = _mm_add_epi16(diff, _mm_set1_epi16(4));\n    in_macro = _mm_srai_epi16(diff, 3);\n\n    C0_uv_8x16 = _mm_set_epi16(pu1_cliptab_cr[u1_Bs1], pu1_cliptab_cb[u1_Bs1],\n                               pu1_cliptab_cr[u1_Bs1], pu1_cliptab_cb[u1_Bs1],\n                               pu1_cliptab_cr[u1_Bs0], pu1_cliptab_cb[u1_Bs0],\n                               pu1_cliptab_cr[u1_Bs0], pu1_cliptab_cb[u1_Bs0]);\n\n    C0_uv_8x16 = _mm_add_epi16(C0_uv_8x16, _mm_set1_epi16(1));\n\n    in_macro = _mm_min_epi16(C0_uv_8x16, in_macro); //CLIP3\n    C0_uv_8x16 = _mm_subs_epi16(zero, C0_uv_8x16);\n    in_macro = _mm_max_epi16(C0_uv_8x16, in_macro);\n\n    p0_uv_8x16_1 = _mm_add_epi16(p0_uv_8x16, in_macro);\n    q0_uv_8x16_1 = _mm_sub_epi16(q0_uv_8x16, in_macro);\n\n    q0_uv_8x16 = _mm_unpackhi_epi8(q0_uv_16x8, zero);\n    q1_uv_8x16 = _mm_unpackhi_epi8(q1_uv_16x8, zero);\n    p1_uv_8x16 = _mm_unpackhi_epi8(p1_uv_16x8, zero);\n    p0_uv_8x16 = _mm_unpackhi_epi8(p0_uv_16x8, zero);\n\n    diff = _mm_subs_epi16(p0_uv_8x16, q0_uv_8x16); //Condn 1\n    diff = _mm_abs_epi16(diff);\n    alpha_cbcr_16x8 = _mm_set1_epi32(alpha_cbcr);\n    flag2 = _mm_cmpgt_epi16(alpha_cbcr_16x8, diff);\n\n    diff = _mm_subs_epi16(q1_uv_8x16, q0_uv_8x16); //Condtn 2\n    diff = _mm_abs_epi16(diff);\n    beta_cbcr_16x8 = _mm_set1_epi32(beta_cbcr);\n    flag2 = _mm_and_si128(flag2, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(p1_uv_8x16, p0_uv_8x16); //Condtn 3\n    diff = _mm_abs_epi16(diff);\n    flag2 = _mm_and_si128(flag2, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(q0_uv_8x16, p0_uv_8x16);\n    diff = _mm_slli_epi16(diff, 2);\n    diff1 = _mm_subs_epi16(p1_uv_8x16, q1_uv_8x16);\n    diff = _mm_add_epi16(diff, diff1);\n    diff = _mm_add_epi16(diff, _mm_set1_epi16(4));\n    in_macro = _mm_srai_epi16(diff, 3);\n\n    C0_uv_8x16 = _mm_set_epi16(pu1_cliptab_cr[u1_Bs3], pu1_cliptab_cb[u1_Bs3],\n                               pu1_cliptab_cr[u1_Bs3], pu1_cliptab_cb[u1_Bs3],\n                               pu1_cliptab_cr[u1_Bs2], pu1_cliptab_cb[u1_Bs2],\n                               pu1_cliptab_cr[u1_Bs2], pu1_cliptab_cb[u1_Bs2]);\n\n    C0_uv_8x16 = _mm_add_epi16(C0_uv_8x16, _mm_set1_epi16(1));\n\n    in_macro = _mm_min_epi16(C0_uv_8x16, in_macro); //CLIP3\n    C0_uv_8x16 = _mm_subs_epi16(zero, C0_uv_8x16);\n    in_macro = _mm_max_epi16(C0_uv_8x16, in_macro);\n\n    p0_uv_8x16_2 = _mm_add_epi16(p0_uv_8x16, in_macro);\n    q0_uv_8x16_2 = _mm_sub_epi16(q0_uv_8x16, in_macro);\n\n    p0_uv_8x16_2 = _mm_packus_epi16(p0_uv_8x16_1, p0_uv_8x16_2);\n    q0_uv_8x16_2 = _mm_packus_epi16(q0_uv_8x16_1, q0_uv_8x16_2);\n\n    flag1 = _mm_packs_epi16(flag1, flag2);\n    flag1 = _mm_and_si128(flag1, flag_bs); //Final flag (BS condition + other 3 conditions)\n\n    p0_uv_8x16_1 = _mm_and_si128(p0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    p0_uv_8x16_2 = _mm_and_si128(p0_uv_8x16_2, flag1);\n    p0_uv_16x8 = _mm_add_epi8(p0_uv_8x16_1, p0_uv_8x16_2);\n\n    q0_uv_8x16_1 = _mm_and_si128(q0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    q0_uv_8x16_2 = _mm_and_si128(q0_uv_8x16_2, flag1);\n    q0_uv_16x8 = _mm_add_epi8(q0_uv_8x16_1, q0_uv_8x16_2);\n\n    /* Inverse-transpose and store back */\n    temp1 = _mm_unpacklo_epi16(p1_uv_16x8, p0_uv_16x8);\n    temp2 = _mm_unpackhi_epi16(p1_uv_16x8, p0_uv_16x8);\n    temp3 = _mm_unpacklo_epi16(q0_uv_16x8, q1_uv_16x8);\n    temp4 = _mm_unpackhi_epi16(q0_uv_16x8, q1_uv_16x8);\n\n    linea = _mm_unpacklo_epi32(temp1, temp3);\n    lineb = _mm_srli_si128(linea, 8);\n    linec = _mm_unpackhi_epi32(temp1, temp3);\n    lined = _mm_srli_si128(linec, 8);\n    linee = _mm_unpacklo_epi32(temp2, temp4);\n    linef = _mm_srli_si128(linee, 8);\n    lineg = _mm_unpackhi_epi32(temp2, temp4);\n    lineh = _mm_srli_si128(lineg, 8);\n\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4), linea);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + src_strd), lineb);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 2 * src_strd), linec);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 3 * src_strd), lined);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 4 * src_strd), linee);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 5 * src_strd), linef);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 6 * src_strd), lineg);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 7 * src_strd), lineh);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_horz_bslt4_ssse3()                    */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  horizontal edge when the boundary strength is less than  */\n/*                  4 in high profile.                                       */\n/*                                                                           */\n/*  Inputs        : pu1_src          - pointer to the src sample q0 of U     */\n/*                  src_strd         - source stride                         */\n/*                  alpha_cb         - alpha value for the boundary in U     */\n/*                  beta_cb          - beta value for the boundary in U      */\n/*                  alpha_cr         - alpha value for the boundary in V     */\n/*                  beta_cr          - beta value for the boundary in V      */\n/*                  u4_bs            - packed Boundary strength array        */\n/*                  pu1_cliptab_cb   - tc0_table for U                       */\n/*                  pu1_cliptab_cr   - tc0_table for V                       */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.3 under the    */\n/*                  title \"Filtering process for edges for bS less than 4\"   */\n/*                  in ITU T Rec H.264 with alpha and beta values different  */\n/*                  in U and V.                                              */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\n\nATTRIBUTE_SSSE3\nvoid ih264_deblk_chroma_horz_bslt4_ssse3(UWORD8 *pu1_src,\n                                         WORD32 src_strd,\n                                         WORD32 alpha_cb,\n                                         WORD32 beta_cb,\n                                         WORD32 alpha_cr,\n                                         WORD32 beta_cr,\n                                         UWORD32 u4_bs,\n                                         const UWORD8 *pu1_cliptab_cb,\n                                         const UWORD8 *pu1_cliptab_cr)\n{\n    UWORD8 *pu1_src_uv = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    WORD16 i16_posP1, i16_posP0, i16_posQ1;\n    UWORD8 u1_Bs0, u1_Bs1, u1_Bs2, u1_Bs3;\n\n    UWORD8 *pu1_HorzPixelUV; /*! < Pointer to the first pixel of the boundary */\n    WORD32 alpha_cbcr = (alpha_cr << 16) + alpha_cb;\n    WORD32 beta_cbcr = (beta_cr << 16) + beta_cb;\n    __m128i q0_uv_16x8, p0_uv_16x8, q1_uv_16x8, p1_uv_16x8;\n    __m128i q0_uv_8x16, p0_uv_8x16, q1_uv_8x16, p1_uv_8x16;\n    __m128i flag_bs, flag1, flag2;\n    __m128i diff, diff1, alpha_cbcr_16x8, beta_cbcr_16x8, in_macro;\n    __m128i zero = _mm_setzero_si128();\n    __m128i C0_uv_8x16;\n    __m128i p0_uv_8x16_1, p0_uv_8x16_2, q0_uv_8x16_1, q0_uv_8x16_2;\n\n    pu1_HorzPixelUV = pu1_src_uv - (src_strd << 1);\n\n    i16_posQ1 = src_strd;\n    i16_posP0 = src_strd;\n    i16_posP1 = 0;\n\n    u1_Bs0 = (u4_bs >> 24) & 0xff;\n    u1_Bs1 = (u4_bs >> 16) & 0xff;\n    u1_Bs2 = (u4_bs >> 8) & 0xff;\n    u1_Bs3 = (u4_bs >> 0) & 0xff;\n\n    flag_bs = _mm_set_epi8(u1_Bs3, u1_Bs3, u1_Bs3, u1_Bs3, u1_Bs2, u1_Bs2,\n                           u1_Bs2, u1_Bs2, u1_Bs1, u1_Bs1, u1_Bs1, u1_Bs1,\n                           u1_Bs0, u1_Bs0, u1_Bs0, u1_Bs0);\n    flag_bs = _mm_cmpeq_epi8(flag_bs, zero); //Set flag to 1s and 0s\n    flag_bs = _mm_xor_si128(flag_bs, _mm_set1_epi8(0xFF)); //Invert for required mask\n\n    q0_uv_16x8 = _mm_loadu_si128((__m128i *)(pu1_src_uv));\n    q1_uv_16x8 = _mm_loadu_si128((__m128i *)(pu1_src_uv + i16_posQ1));\n    p1_uv_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixelUV + i16_posP1));\n    p0_uv_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixelUV + i16_posP0));\n\n    q0_uv_8x16 = _mm_unpacklo_epi8(q0_uv_16x8, zero);\n    q1_uv_8x16 = _mm_unpacklo_epi8(q1_uv_16x8, zero);\n    p1_uv_8x16 = _mm_unpacklo_epi8(p1_uv_16x8, zero);\n    p0_uv_8x16 = _mm_unpacklo_epi8(p0_uv_16x8, zero);\n\n    diff = _mm_subs_epi16(p0_uv_8x16, q0_uv_8x16); //Condn 1\n    diff = _mm_abs_epi16(diff);\n    alpha_cbcr_16x8 = _mm_set1_epi32(alpha_cbcr);\n    flag1 = _mm_cmpgt_epi16(alpha_cbcr_16x8, diff);\n\n    diff = _mm_subs_epi16(q1_uv_8x16, q0_uv_8x16); //Condtn 2\n    diff = _mm_abs_epi16(diff);\n    beta_cbcr_16x8 = _mm_set1_epi32(beta_cbcr);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(p1_uv_8x16, p0_uv_8x16); //Condtn 3\n    diff = _mm_abs_epi16(diff);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(q0_uv_8x16, p0_uv_8x16);\n    diff = _mm_slli_epi16(diff, 2);\n    diff1 = _mm_subs_epi16(p1_uv_8x16, q1_uv_8x16);\n    diff = _mm_add_epi16(diff, diff1);\n    diff = _mm_add_epi16(diff, _mm_set1_epi16(4));\n    in_macro = _mm_srai_epi16(diff, 3);\n\n    C0_uv_8x16 = _mm_set_epi16(pu1_cliptab_cr[u1_Bs1], pu1_cliptab_cb[u1_Bs1],\n                               pu1_cliptab_cr[u1_Bs1], pu1_cliptab_cb[u1_Bs1],\n                               pu1_cliptab_cr[u1_Bs0], pu1_cliptab_cb[u1_Bs0],\n                               pu1_cliptab_cr[u1_Bs0], pu1_cliptab_cb[u1_Bs0]);\n\n    C0_uv_8x16 = _mm_add_epi16(C0_uv_8x16, _mm_set1_epi16(1));\n\n    in_macro = _mm_min_epi16(C0_uv_8x16, in_macro); //CLIP3\n    C0_uv_8x16 = _mm_subs_epi16(zero, C0_uv_8x16);\n    in_macro = _mm_max_epi16(C0_uv_8x16, in_macro);\n\n    p0_uv_8x16_1 = _mm_add_epi16(p0_uv_8x16, in_macro);\n    q0_uv_8x16_1 = _mm_sub_epi16(q0_uv_8x16, in_macro);\n\n    q0_uv_8x16 = _mm_unpackhi_epi8(q0_uv_16x8, zero);\n    q1_uv_8x16 = _mm_unpackhi_epi8(q1_uv_16x8, zero);\n    p1_uv_8x16 = _mm_unpackhi_epi8(p1_uv_16x8, zero);\n    p0_uv_8x16 = _mm_unpackhi_epi8(p0_uv_16x8, zero);\n\n    diff = _mm_subs_epi16(p0_uv_8x16, q0_uv_8x16); //Condn 1\n    diff = _mm_abs_epi16(diff);\n    alpha_cbcr_16x8 = _mm_set1_epi32(alpha_cbcr);\n    flag2 = _mm_cmpgt_epi16(alpha_cbcr_16x8, diff);\n\n    diff = _mm_subs_epi16(q1_uv_8x16, q0_uv_8x16); //Condtn 2\n    diff = _mm_abs_epi16(diff);\n    beta_cbcr_16x8 = _mm_set1_epi32(beta_cbcr);\n    flag2 = _mm_and_si128(flag2, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(p1_uv_8x16, p0_uv_8x16); //Condtn 3\n    diff = _mm_abs_epi16(diff);\n    flag2 = _mm_and_si128(flag2, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(q0_uv_8x16, p0_uv_8x16);\n    diff = _mm_slli_epi16(diff, 2);\n    diff1 = _mm_subs_epi16(p1_uv_8x16, q1_uv_8x16);\n    diff = _mm_add_epi16(diff, diff1);\n    diff = _mm_add_epi16(diff, _mm_set1_epi16(4));\n    in_macro = _mm_srai_epi16(diff, 3);\n\n    C0_uv_8x16 = _mm_set_epi16(pu1_cliptab_cr[u1_Bs3], pu1_cliptab_cb[u1_Bs3],\n                               pu1_cliptab_cr[u1_Bs3], pu1_cliptab_cb[u1_Bs3],\n                               pu1_cliptab_cr[u1_Bs2], pu1_cliptab_cb[u1_Bs2],\n                               pu1_cliptab_cr[u1_Bs2], pu1_cliptab_cb[u1_Bs2]);\n\n    C0_uv_8x16 = _mm_add_epi16(C0_uv_8x16, _mm_set1_epi16(1));\n\n    in_macro = _mm_min_epi16(C0_uv_8x16, in_macro); //CLIP3\n    C0_uv_8x16 = _mm_subs_epi16(zero, C0_uv_8x16);\n    in_macro = _mm_max_epi16(C0_uv_8x16, in_macro);\n\n    p0_uv_8x16_2 = _mm_add_epi16(p0_uv_8x16, in_macro);\n    q0_uv_8x16_2 = _mm_sub_epi16(q0_uv_8x16, in_macro);\n\n    p0_uv_8x16_2 = _mm_packus_epi16(p0_uv_8x16_1, p0_uv_8x16_2);\n    q0_uv_8x16_2 = _mm_packus_epi16(q0_uv_8x16_1, q0_uv_8x16_2);\n\n    flag1 = _mm_packs_epi16(flag1, flag2);\n    flag1 = _mm_and_si128(flag1, flag_bs); //Final flag (BS condition + other 3 conditions)\n\n    p0_uv_8x16_1 = _mm_and_si128(p0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    p0_uv_8x16_2 = _mm_and_si128(p0_uv_8x16_2, flag1);\n    p0_uv_8x16_1 = _mm_add_epi8(p0_uv_8x16_1, p0_uv_8x16_2);\n    _mm_storeu_si128((__m128i *)(pu1_HorzPixelUV + i16_posP0), p0_uv_8x16_1);\n\n    q0_uv_8x16_1 = _mm_and_si128(q0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    q0_uv_8x16_2 = _mm_and_si128(q0_uv_8x16_2, flag1);\n    q0_uv_8x16_1 = _mm_add_epi8(q0_uv_8x16_1, q0_uv_8x16_2);\n    _mm_storeu_si128((__m128i *)(pu1_src_uv), q0_uv_8x16_1);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bs4_mbaff_ssse3()                */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when boundary strength is set to 4 in high */\n/*                  profile.                                                 */\n/*                                                                           */\n/*  Inputs        : pu1_src          - pointer to the src sample q0 of U     */\n/*                  src_strd         - source stride                         */\n/*                  alpha_cb         - alpha value for the boundary in U     */\n/*                  beta_cb          - beta value for the boundary in U      */\n/*                  alpha_cr         - alpha value for the boundary in V     */\n/*                  beta_cr          - beta value for the boundary in V      */\n/*                  u4_bs            - packed Boundary strength array        */\n/*                  pu1_cliptab_cb   - tc0_table for U                       */\n/*                  pu1_cliptab_cr   - tc0_table for V                       */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : When the function is called twice, this operation is as  */\n/*                  described in Sec. 8.7.2.4 under the title \"Filtering     */\n/*                  process for edges for bS equal to 4\" in ITU T Rec H.264  */\n/*                  with alpha and beta values different in U and V.         */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\n\nATTRIBUTE_SSSE3\nvoid ih264_deblk_chroma_vert_bs4_mbaff_ssse3(UWORD8 *pu1_src,\n                                             WORD32 src_strd,\n                                             WORD32 alpha_cb,\n                                             WORD32 beta_cb,\n                                             WORD32 alpha_cr,\n                                             WORD32 beta_cr)\n{\n    UWORD8 *pu1_src_uv = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    WORD32 alpha_cbcr = (alpha_cr << 16) + alpha_cb;\n    WORD32 beta_cbcr = (beta_cr << 16) + beta_cb;\n    __m128i linea, lineb, linec, lined;\n    __m128i temp1, temp2;\n\n    __m128i q0_uv_16x8, p0_uv_16x8, q1_uv_16x8, p1_uv_16x8;\n    __m128i q0_uv_8x16, p0_uv_8x16, q1_uv_8x16, p1_uv_8x16;\n    __m128i flag1;\n    __m128i diff, alpha_cbcr_16x8, beta_cbcr_16x8;\n    __m128i zero = _mm_setzero_si128();\n    __m128i p0_uv_8x16_1, p0_uv_8x16_2, q0_uv_8x16_1, q0_uv_8x16_2;\n\n    /* Load and transpose the pixel values */\n    linea = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4));\n    lineb = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + src_strd));\n    linec = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 2 * src_strd));\n    lined = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 3 * src_strd));\n\n    temp1 = _mm_unpacklo_epi16(linea, lineb);\n    temp2 = _mm_unpacklo_epi16(linec, lined);\n\n    p1_uv_16x8 = _mm_unpacklo_epi32(temp1, temp2);\n    p0_uv_16x8 = _mm_srli_si128(p1_uv_16x8, 8);\n    q0_uv_16x8 = _mm_unpackhi_epi32(temp1, temp2);\n    q1_uv_16x8 = _mm_srli_si128(q0_uv_16x8, 8);\n    /* End of transpose */\n\n    q0_uv_8x16 = _mm_unpacklo_epi8(q0_uv_16x8, zero);\n    q1_uv_8x16 = _mm_unpacklo_epi8(q1_uv_16x8, zero);\n    p1_uv_8x16 = _mm_unpacklo_epi8(p1_uv_16x8, zero);\n    p0_uv_8x16 = _mm_unpacklo_epi8(p0_uv_16x8, zero);\n\n    diff = _mm_subs_epi16(p0_uv_8x16, q0_uv_8x16); //Condn 1\n    diff = _mm_abs_epi16(diff);\n    alpha_cbcr_16x8 = _mm_set1_epi32(alpha_cbcr);\n    flag1 = _mm_cmpgt_epi16(alpha_cbcr_16x8, diff);\n\n    diff = _mm_subs_epi16(q1_uv_8x16, q0_uv_8x16); //Condtn 2\n    diff = _mm_abs_epi16(diff);\n    beta_cbcr_16x8 = _mm_set1_epi32(beta_cbcr);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(p1_uv_8x16, p0_uv_8x16); //Condtn 3\n    diff = _mm_abs_epi16(diff);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    temp1 = _mm_slli_epi16(p1_uv_8x16, 1);\n    temp2 = _mm_add_epi16(p0_uv_8x16, q1_uv_8x16);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(2));\n    temp1 = _mm_add_epi16(temp1, temp2);\n    p0_uv_8x16_1 = _mm_srai_epi16(temp1, 2);\n\n    temp1 = _mm_slli_epi16(q1_uv_8x16, 1);\n    temp2 = _mm_add_epi16(p1_uv_8x16, q0_uv_8x16);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(2));\n    temp1 = _mm_add_epi16(temp1, temp2);\n    q0_uv_8x16_1 = _mm_srai_epi16(temp1, 2);\n\n    p0_uv_8x16_2 = _mm_packus_epi16(p0_uv_8x16_1, p0_uv_8x16_1);\n    q0_uv_8x16_2 = _mm_packus_epi16(q0_uv_8x16_1, q0_uv_8x16_1);\n\n    flag1 = _mm_packs_epi16(flag1, flag1);\n\n    p0_uv_8x16_1 = _mm_and_si128(p0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    p0_uv_8x16_2 = _mm_and_si128(p0_uv_8x16_2, flag1);\n    p0_uv_16x8 = _mm_add_epi8(p0_uv_8x16_1, p0_uv_8x16_2);\n\n    q0_uv_8x16_1 = _mm_and_si128(q0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    q0_uv_8x16_2 = _mm_and_si128(q0_uv_8x16_2, flag1);\n    q0_uv_16x8 = _mm_add_epi8(q0_uv_8x16_1, q0_uv_8x16_2);\n\n    /* Inverse-transpose and store back */\n    temp1 = _mm_unpacklo_epi16(p1_uv_16x8, p0_uv_16x8);\n    temp2 = _mm_unpacklo_epi16(q0_uv_16x8, q1_uv_16x8);\n\n    linea = _mm_unpacklo_epi32(temp1, temp2);\n    lineb = _mm_srli_si128(linea, 8);\n    linec = _mm_unpackhi_epi32(temp1, temp2);\n    lined = _mm_srli_si128(linec, 8);\n\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4), linea);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + src_strd), lineb);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 2 * src_strd), linec);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 3 * src_strd), lined);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_chroma_vert_bslt4_mbaff_ssse3()              */\n/*                                                                           */\n/*  Description   : This function performs filtering of a chroma block       */\n/*                  vertical edge when boundary strength is less than 4 in   */\n/*                  high profile.                                            */\n/*                                                                           */\n/*  Inputs        : pu1_src          - pointer to the src sample q0 of U     */\n/*                  src_strd         - source stride                         */\n/*                  alpha_cb         - alpha value for the boundary in U     */\n/*                  beta_cb          - beta value for the boundary in U      */\n/*                  alpha_cr         - alpha value for the boundary in V     */\n/*                  beta_cr          - beta value for the boundary in V      */\n/*                  u4_bs            - packed Boundary strength array        */\n/*                  pu1_cliptab_cb   - tc0_table for U                       */\n/*                  pu1_cliptab_cr   - tc0_table for V                       */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : When the function is called twice, this operation is as  */\n/*                  described in Sec. 8.7.2.4 under the title \"Filtering     */\n/*                  process for edges for bS less than 4\" in ITU T Rec H.264 */\n/*                  with alpha and beta values different in U and V.         */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\n\nATTRIBUTE_SSSE3\nvoid ih264_deblk_chroma_vert_bslt4_mbaff_ssse3(UWORD8 *pu1_src,\n                                               WORD32 src_strd,\n                                               WORD32 alpha_cb,\n                                               WORD32 beta_cb,\n                                               WORD32 alpha_cr,\n                                               WORD32 beta_cr,\n                                               UWORD32 u4_bs,\n                                               const UWORD8 *pu1_cliptab_cb,\n                                               const UWORD8 *pu1_cliptab_cr)\n{\n    UWORD8 *pu1_src_uv = pu1_src; /* Pointer to the src sample q0 of plane U*/\n    UWORD8 u1_Bs0, u1_Bs1, u1_Bs2, u1_Bs3;\n    WORD32 alpha_cbcr = (alpha_cr << 16) + alpha_cb;\n    WORD32 beta_cbcr = (beta_cr << 16) + beta_cb;\n    __m128i linea, lineb, linec, lined;\n    __m128i temp1, temp2;\n\n    __m128i q0_uv_16x8, p0_uv_16x8, q1_uv_16x8, p1_uv_16x8;\n    __m128i q0_uv_8x16, p0_uv_8x16, q1_uv_8x16, p1_uv_8x16;\n    __m128i flag_bs, flag1;\n    __m128i diff, diff1, alpha_cbcr_16x8, beta_cbcr_16x8, in_macro;\n    __m128i zero = _mm_setzero_si128();\n    __m128i C0_uv_8x16;\n    __m128i p0_uv_8x16_1, p0_uv_8x16_2, q0_uv_8x16_1, q0_uv_8x16_2;\n\n    u1_Bs0 = (u4_bs >> 24) & 0xff;\n    u1_Bs1 = (u4_bs >> 16) & 0xff;\n    u1_Bs2 = (u4_bs >> 8) & 0xff;\n    u1_Bs3 = (u4_bs >> 0) & 0xff;\n\n    flag_bs = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, u1_Bs3, u1_Bs3, u1_Bs2,\n                           u1_Bs2, u1_Bs1, u1_Bs1, u1_Bs0, u1_Bs0);\n    flag_bs = _mm_cmpeq_epi8(flag_bs, zero); //Set flag to 1s and 0s\n    flag_bs = _mm_xor_si128(flag_bs, _mm_set1_epi8(0xFF)); //Invert for required mask\n\n    /* Load and transpose the pixel values */\n    linea = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4));\n    lineb = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + src_strd));\n    linec = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 2 * src_strd));\n    lined = _mm_loadl_epi64((__m128i *)(pu1_src_uv - 4 + 3 * src_strd));\n\n    temp1 = _mm_unpacklo_epi16(linea, lineb);\n    temp2 = _mm_unpacklo_epi16(linec, lined);\n\n    p1_uv_16x8 = _mm_unpacklo_epi32(temp1, temp2);\n    p0_uv_16x8 = _mm_srli_si128(p1_uv_16x8, 8);\n    q0_uv_16x8 = _mm_unpackhi_epi32(temp1, temp2);\n    q1_uv_16x8 = _mm_srli_si128(q0_uv_16x8, 8);\n    /* End of transpose */\n\n    q0_uv_8x16 = _mm_unpacklo_epi8(q0_uv_16x8, zero);\n    q1_uv_8x16 = _mm_unpacklo_epi8(q1_uv_16x8, zero);\n    p1_uv_8x16 = _mm_unpacklo_epi8(p1_uv_16x8, zero);\n    p0_uv_8x16 = _mm_unpacklo_epi8(p0_uv_16x8, zero);\n\n    diff = _mm_subs_epi16(p0_uv_8x16, q0_uv_8x16); //Condn 1\n    diff = _mm_abs_epi16(diff);\n    alpha_cbcr_16x8 = _mm_set1_epi32(alpha_cbcr);\n    flag1 = _mm_cmpgt_epi16(alpha_cbcr_16x8, diff);\n\n    diff = _mm_subs_epi16(q1_uv_8x16, q0_uv_8x16); //Condtn 2\n    diff = _mm_abs_epi16(diff);\n    beta_cbcr_16x8 = _mm_set1_epi32(beta_cbcr);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(p1_uv_8x16, p0_uv_8x16); //Condtn 3\n    diff = _mm_abs_epi16(diff);\n    flag1 = _mm_and_si128(flag1, _mm_cmpgt_epi16(beta_cbcr_16x8, diff));\n\n    diff = _mm_subs_epi16(q0_uv_8x16, p0_uv_8x16);\n    diff = _mm_slli_epi16(diff, 2);\n    diff1 = _mm_subs_epi16(p1_uv_8x16, q1_uv_8x16);\n    diff = _mm_add_epi16(diff, diff1);\n    diff = _mm_add_epi16(diff, _mm_set1_epi16(4));\n    in_macro = _mm_srai_epi16(diff, 3);\n\n    C0_uv_8x16 = _mm_set_epi16(pu1_cliptab_cr[u1_Bs3], pu1_cliptab_cb[u1_Bs3],\n                               pu1_cliptab_cr[u1_Bs2], pu1_cliptab_cb[u1_Bs2],\n                               pu1_cliptab_cr[u1_Bs1], pu1_cliptab_cb[u1_Bs1],\n                               pu1_cliptab_cr[u1_Bs0], pu1_cliptab_cb[u1_Bs0]);\n\n    C0_uv_8x16 = _mm_add_epi16(C0_uv_8x16, _mm_set1_epi16(1));\n\n    in_macro = _mm_min_epi16(C0_uv_8x16, in_macro); //CLIP3\n    C0_uv_8x16 = _mm_subs_epi16(zero, C0_uv_8x16);\n    in_macro = _mm_max_epi16(C0_uv_8x16, in_macro);\n\n    p0_uv_8x16_1 = _mm_add_epi16(p0_uv_8x16, in_macro);\n    q0_uv_8x16_1 = _mm_sub_epi16(q0_uv_8x16, in_macro);\n\n    p0_uv_8x16_2 = _mm_packus_epi16(p0_uv_8x16_1, p0_uv_8x16_1);\n    q0_uv_8x16_2 = _mm_packus_epi16(q0_uv_8x16_1, q0_uv_8x16_1);\n\n    flag1 = _mm_packs_epi16(flag1, flag1);\n    flag1 = _mm_and_si128(flag1, flag_bs); //Final flag (BS condition + other 3 conditions)\n\n    p0_uv_8x16_1 = _mm_and_si128(p0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    p0_uv_8x16_2 = _mm_and_si128(p0_uv_8x16_2, flag1);\n    p0_uv_16x8 = _mm_add_epi8(p0_uv_8x16_1, p0_uv_8x16_2);\n\n    q0_uv_8x16_1 = _mm_and_si128(q0_uv_16x8,\n                                 _mm_xor_si128(flag1, _mm_set1_epi8(0xFF)));\n    q0_uv_8x16_2 = _mm_and_si128(q0_uv_8x16_2, flag1);\n    q0_uv_16x8 = _mm_add_epi8(q0_uv_8x16_1, q0_uv_8x16_2);\n\n    /* Inverse-transpose and store back */\n    temp1 = _mm_unpacklo_epi16(p1_uv_16x8, p0_uv_16x8);\n    temp2 = _mm_unpacklo_epi16(q0_uv_16x8, q1_uv_16x8);\n\n    linea = _mm_unpacklo_epi32(temp1, temp2);\n    lineb = _mm_srli_si128(linea, 8);\n    linec = _mm_unpackhi_epi32(temp1, temp2);\n    lined = _mm_srli_si128(linec, 8);\n\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4), linea);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + src_strd), lineb);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 2 * src_strd), linec);\n    _mm_storel_epi64((__m128i *)(pu1_src_uv - 4 + 3 * src_strd), lined);\n\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_deblk_luma_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264_deblk_luma_ssse3.c                             */\n/*                                                                           */\n/*  Description       : Contains function definitions for deblocking         */\n/*                                                                           */\n/*  List of Functions : ih264_deblk_luma_vert_bs4_ssse3()                    */\n/*                      ih264_deblk_luma_horz_bs4_ssse3()                    */\n/*                      ih264_deblk_luma_vert_bslt4_ssse3()                  */\n/*                      ih264_deblk_luma_horz_bslt4_ssse3()                  */\n/*                      ih264_deblk_luma_vert_bs4_mbaff_ssse3()              */\n/*                      ih264_deblk_luma_vert_bslt4_mbaff_ssse3()            */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Added luma deblocking ssse3          */\n/*                                      intrinsics                           */\n/*                                                                           */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System include files */\n#include <stdio.h>\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_deblk_edge_filters.h\"\n#include \"ih264_macros.h\"\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n/*****************************************************************************/\n/* Function Definitions                                                      */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_vert_bs4_ssse3()                        */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  vertical edge when the boundary strength is set to 4.    */\n/*                                                                           */\n/*  Inputs        : pu1_src    - pointer to the src sample q0                */\n/*                  src_strd   - source stride                               */\n/*                  alpha      - alpha value for the boundary                */\n/*                  beta       - beta value for the boundary                 */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.4 under the    */\n/*                  title \"Filtering process for edges for bS equal to 4\" in */\n/*                  ITU T Rec H.264.                                         */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_deblk_luma_vert_bs4_ssse3(UWORD8 *pu1_src,\n                                     WORD32 src_strd,\n                                     WORD32 alpha,\n                                     WORD32 beta)\n{\n    __m128i zero = _mm_setzero_si128();\n    __m128i q0_16x8, q1_16x8, q2_16x8, q3_16x8;\n    __m128i p0_16x8, p1_16x8, p2_16x8, p3_16x8;\n    __m128i q0_8x16, q1_8x16, q2_8x16, q3_8x16;\n    __m128i p0_8x16, p1_8x16, p2_8x16, p3_8x16;\n    __m128i q0_16x8_1;\n    __m128i p0_16x8_1;\n    __m128i q0_16x8_2, q1_16x8_2, q2_16x8_2;\n    __m128i p0_16x8_2, p1_16x8_2, p2_16x8_2;\n    __m128i temp1, temp2, temp3, temp4, temp5, temp6;\n    __m128i Alpha_8x16, Beta_8x16;\n    __m128i flag1_16x8, flag2_16x8, flag3_16x8, flag4_16x8;\n    __m128i const_val2_16x8 = _mm_set1_epi16(2);\n    __m128i line1, line2, line3, line4, line5, line6, line7, line8;\n\n    Alpha_8x16 = _mm_set1_epi16(alpha);\n    Beta_8x16 = _mm_set1_epi16(beta);\n\n    line1 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 0 * src_strd));\n    line2 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 1 * src_strd));\n    line3 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 2 * src_strd));\n    line4 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 3 * src_strd));\n    line5 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 4 * src_strd));\n    line6 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 5 * src_strd));\n    line7 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 6 * src_strd));\n    line8 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 7 * src_strd));\n\n    temp1 = _mm_unpacklo_epi8(line1, line2);\n    temp2 = _mm_unpacklo_epi8(line3, line4);\n    temp3 = _mm_unpacklo_epi8(line5, line6);\n    temp4 = _mm_unpacklo_epi8(line7, line8);\n\n    line1 = _mm_unpacklo_epi16(temp1, temp2);\n    line2 = _mm_unpackhi_epi16(temp1, temp2);\n    line3 = _mm_unpacklo_epi16(temp3, temp4);\n    line4 = _mm_unpackhi_epi16(temp3, temp4);\n\n    p1_8x16 = _mm_unpacklo_epi32(line1, line3);\n    p0_8x16 = _mm_unpackhi_epi32(line1, line3);\n    q0_8x16 = _mm_unpacklo_epi32(line2, line4);\n    q1_8x16 = _mm_unpackhi_epi32(line2, line4);\n\n    line1 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 8 * src_strd));\n    line2 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 9 * src_strd));\n    line3 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 10 * src_strd));\n    line4 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 11 * src_strd));\n    line5 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 12 * src_strd));\n    line6 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 13 * src_strd));\n    line7 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 14 * src_strd));\n    line8 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 15 * src_strd));\n\n    temp1 = _mm_unpacklo_epi8(line1, line2);\n    temp2 = _mm_unpacklo_epi8(line3, line4);\n    temp3 = _mm_unpacklo_epi8(line5, line6);\n    temp4 = _mm_unpacklo_epi8(line7, line8);\n\n    line1 = _mm_unpacklo_epi16(temp1, temp2);\n    line2 = _mm_unpackhi_epi16(temp1, temp2);\n    line3 = _mm_unpacklo_epi16(temp3, temp4);\n    line4 = _mm_unpackhi_epi16(temp3, temp4);\n\n    temp1 = _mm_unpacklo_epi32(line1, line3);\n    temp2 = _mm_unpackhi_epi32(line1, line3);\n    temp3 = _mm_unpacklo_epi32(line2, line4);\n    temp4 = _mm_unpackhi_epi32(line2, line4);\n\n    p3_16x8 = _mm_unpacklo_epi64(p1_8x16, temp1);\n    p2_16x8 = _mm_unpackhi_epi64(p1_8x16, temp1);\n    q2_16x8 = _mm_unpacklo_epi64(q1_8x16, temp4);\n    q3_16x8 = _mm_unpackhi_epi64(q1_8x16, temp4);\n    p1_16x8 = _mm_unpacklo_epi64(p0_8x16, temp2);\n    p0_16x8 = _mm_unpackhi_epi64(p0_8x16, temp2);\n    q0_16x8 = _mm_unpacklo_epi64(q0_8x16, temp3);\n    q1_16x8 = _mm_unpackhi_epi64(q0_8x16, temp3);\n\n    //Cond1 (ABS(p0 - q0) < alpha)\n    temp1 = _mm_subs_epu8(q0_16x8, p0_16x8);\n    temp2 = _mm_subs_epu8(p0_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Alpha_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Alpha_8x16, temp1);\n\n    flag1_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    //Cond2 (ABS(q1 - q0) < beta)\n    temp1 = _mm_subs_epu8(q0_16x8, q1_16x8);\n    temp2 = _mm_subs_epu8(q1_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    flag1_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    //Cond3 (ABS(p1 - p0) < beta)\n    temp1 = _mm_subs_epu8(p0_16x8, p1_16x8);\n    temp2 = _mm_subs_epu8(p1_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    // !((ABS(p0 - q0) < alpha) || (ABS(q1 - q0) < beta) || (ABS(p1 - p0) < beta))\n    flag1_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    // (ABS(p0 - q0) < ((alpha >> 2) + 2))\n    temp1 = _mm_subs_epu8(p0_16x8, q0_16x8);\n    temp2 = _mm_subs_epu8(q0_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n    Alpha_8x16 = _mm_srai_epi16(Alpha_8x16, 2);\n    Alpha_8x16 = _mm_add_epi16(Alpha_8x16, const_val2_16x8);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Alpha_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Alpha_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag2_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    // (ABS(p2 - p0) < beta)\n    temp1 = _mm_subs_epu8(p0_16x8, p2_16x8);\n    temp2 = _mm_subs_epu8(p2_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag3_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag3_16x8 = _mm_and_si128(flag3_16x8, flag2_16x8);\n\n    // (ABS(q2 - q0) < beta)\n    temp1 = _mm_subs_epu8(q0_16x8, q2_16x8);\n    temp2 = _mm_subs_epu8(q2_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag4_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag4_16x8 = _mm_and_si128(flag4_16x8, flag2_16x8);\n\n    // First 8 pixels\n    p3_8x16 = _mm_unpacklo_epi8(p3_16x8, zero);\n    p2_8x16 = _mm_unpacklo_epi8(p2_16x8, zero);\n    p1_8x16 = _mm_unpacklo_epi8(p1_16x8, zero);\n    p0_8x16 = _mm_unpacklo_epi8(p0_16x8, zero);\n    q0_8x16 = _mm_unpacklo_epi8(q0_16x8, zero);\n    q1_8x16 = _mm_unpacklo_epi8(q1_16x8, zero);\n    q2_8x16 = _mm_unpacklo_epi8(q2_16x8, zero);\n    q3_8x16 = _mm_unpacklo_epi8(q3_16x8, zero);\n\n    // p0_1 and q0_1\n    temp1 = _mm_add_epi16(p0_8x16, q1_8x16);\n    temp2 = _mm_add_epi16(p1_8x16, q0_8x16);\n    temp5 = _mm_add_epi16(temp1, const_val2_16x8);\n    temp6 = _mm_add_epi16(temp2, const_val2_16x8);\n    temp3 = _mm_slli_epi16(p1_8x16, 1);\n    temp4 = _mm_slli_epi16(q1_8x16, 1);\n    temp1 = _mm_add_epi16(temp5, temp3);\n    temp2 = _mm_add_epi16(temp6, temp4);\n    p0_16x8_1 = _mm_srai_epi16(temp1, 2);\n    q0_16x8_1 = _mm_srai_epi16(temp2, 2);\n\n    // p1_2 and q1_2\n    temp6 = _mm_add_epi16(temp6, p0_8x16);\n    temp5 = _mm_add_epi16(temp5, q0_8x16);\n    temp1 = _mm_add_epi16(temp6, p2_8x16);\n    temp2 = _mm_add_epi16(temp5, q2_8x16);\n    p1_16x8_2 = _mm_srai_epi16(temp1, 2);\n    q1_16x8_2 = _mm_srai_epi16(temp2, 2);\n\n    // p0_2 and q0_2\n    temp1 = _mm_add_epi16(temp3, p2_8x16);\n    temp2 = _mm_add_epi16(temp4, q2_8x16);\n    temp1 = _mm_add_epi16(temp1, q1_8x16);\n    temp2 = _mm_add_epi16(temp2, p1_8x16);\n    temp3 = _mm_add_epi16(p0_8x16, q0_8x16);\n    temp3 = _mm_slli_epi16(temp3, 1);\n    temp1 = _mm_add_epi16(temp1, temp3);\n    temp2 = _mm_add_epi16(temp2, temp3);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(4));\n    temp2 = _mm_add_epi16(temp2, _mm_set1_epi16(4));\n    p0_16x8_2 = _mm_srai_epi16(temp1, 3);\n    q0_16x8_2 = _mm_srai_epi16(temp2, 3);\n\n    // p2_2 and q2_2\n    temp1 = _mm_add_epi16(temp6, const_val2_16x8);\n    temp2 = _mm_add_epi16(temp5, const_val2_16x8);\n    temp3 = _mm_slli_epi16(p2_8x16, 1);\n    temp4 = _mm_slli_epi16(q2_8x16, 1);\n    temp3 = _mm_add_epi16(p2_8x16, temp3);\n    temp4 = _mm_add_epi16(q2_8x16, temp4);\n    temp5 = _mm_slli_epi16(p3_8x16, 1);\n    temp6 = _mm_slli_epi16(q3_8x16, 1);\n    temp1 = _mm_add_epi16(temp1, temp3);\n    temp2 = _mm_add_epi16(temp2, temp4);\n    temp1 = _mm_add_epi16(temp1, temp5);\n    temp2 = _mm_add_epi16(temp2, temp6);\n    p2_16x8_2 = _mm_srai_epi16(temp1, 3);\n    q2_16x8_2 = _mm_srai_epi16(temp2, 3);\n\n    // Second 8 pixels and packing with first 8 pixels\n    p3_8x16 = _mm_unpackhi_epi8(p3_16x8, zero);\n    p2_8x16 = _mm_unpackhi_epi8(p2_16x8, zero);\n    p1_8x16 = _mm_unpackhi_epi8(p1_16x8, zero);\n    p0_8x16 = _mm_unpackhi_epi8(p0_16x8, zero);\n    q0_8x16 = _mm_unpackhi_epi8(q0_16x8, zero);\n    q1_8x16 = _mm_unpackhi_epi8(q1_16x8, zero);\n    q2_8x16 = _mm_unpackhi_epi8(q2_16x8, zero);\n    q3_8x16 = _mm_unpackhi_epi8(q3_16x8, zero);\n\n    // p0_1 and q0_1\n    temp1 = _mm_add_epi16(p0_8x16, q1_8x16);\n    temp2 = _mm_add_epi16(p1_8x16, q0_8x16);\n    temp5 = _mm_add_epi16(temp1, const_val2_16x8);\n    temp6 = _mm_add_epi16(temp2, const_val2_16x8);\n    temp3 = _mm_slli_epi16(p1_8x16, 1);\n    temp4 = _mm_slli_epi16(q1_8x16, 1);\n    temp1 = _mm_add_epi16(temp5, temp3);\n    temp2 = _mm_add_epi16(temp6, temp4);\n    temp1 = _mm_srai_epi16(temp1, 2);\n    temp2 = _mm_srai_epi16(temp2, 2);\n    p0_16x8_1 = _mm_packus_epi16(p0_16x8_1, temp1);\n    q0_16x8_1 = _mm_packus_epi16(q0_16x8_1, temp2);\n\n    // p1_2 and q1_2\n    temp6 = _mm_add_epi16(temp6, p0_8x16);\n    temp5 = _mm_add_epi16(temp5, q0_8x16);\n    temp1 = _mm_add_epi16(temp6, p2_8x16);\n    temp2 = _mm_add_epi16(temp5, q2_8x16);\n    temp1 = _mm_srai_epi16(temp1, 2);\n    temp2 = _mm_srai_epi16(temp2, 2);\n    p1_16x8_2 = _mm_packus_epi16(p1_16x8_2, temp1);\n    q1_16x8_2 = _mm_packus_epi16(q1_16x8_2, temp2);\n\n    // p0_2 and q0_2\n    temp1 = _mm_add_epi16(temp3, p2_8x16);\n    temp2 = _mm_add_epi16(temp4, q2_8x16);\n    temp1 = _mm_add_epi16(temp1, q1_8x16);\n    temp2 = _mm_add_epi16(temp2, p1_8x16);\n    temp3 = _mm_add_epi16(p0_8x16, q0_8x16);\n    temp3 = _mm_slli_epi16(temp3, 1);\n    temp1 = _mm_add_epi16(temp1, temp3);\n    temp2 = _mm_add_epi16(temp2, temp3);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(4));\n    temp2 = _mm_add_epi16(temp2, _mm_set1_epi16(4));\n    temp1 = _mm_srai_epi16(temp1, 3);\n    temp2 = _mm_srai_epi16(temp2, 3);\n    p0_16x8_2 = _mm_packus_epi16(p0_16x8_2, temp1);\n    q0_16x8_2 = _mm_packus_epi16(q0_16x8_2, temp2);\n\n    // p2_2 and q2_2\n    temp1 = _mm_add_epi16(temp6, const_val2_16x8);\n    temp2 = _mm_add_epi16(temp5, const_val2_16x8);\n    temp3 = _mm_slli_epi16(p2_8x16, 1);\n    temp4 = _mm_slli_epi16(q2_8x16, 1);\n    temp3 = _mm_add_epi16(p2_8x16, temp3);\n    temp4 = _mm_add_epi16(q2_8x16, temp4);\n    temp5 = _mm_slli_epi16(p3_8x16, 1);\n    temp6 = _mm_slli_epi16(q3_8x16, 1);\n    temp1 = _mm_add_epi16(temp1, temp3);\n    temp2 = _mm_add_epi16(temp2, temp4);\n    temp1 = _mm_add_epi16(temp1, temp5);\n    temp2 = _mm_add_epi16(temp2, temp6);\n    temp1 = _mm_srai_epi16(temp1, 3);\n    temp2 = _mm_srai_epi16(temp2, 3);\n    p2_16x8_2 = _mm_packus_epi16(p2_16x8_2, temp1);\n    q2_16x8_2 = _mm_packus_epi16(q2_16x8_2, temp2);\n\n    // p0 and q0\n    p0_16x8 = _mm_and_si128(p0_16x8,\n                            _mm_xor_si128(flag1_16x8, _mm_set1_epi8(0xFF)));\n    p0_16x8_1 = _mm_and_si128(p0_16x8_1, flag1_16x8);\n    p0_16x8 = _mm_add_epi8(p0_16x8, p0_16x8_1);\n    q0_16x8 = _mm_and_si128(q0_16x8,\n                            _mm_xor_si128(flag1_16x8, _mm_set1_epi8(0xFF)));\n    q0_16x8_1 = _mm_and_si128(q0_16x8_1, flag1_16x8);\n    q0_16x8 = _mm_add_epi8(q0_16x8, q0_16x8_1);\n\n    // p0 and q0\n    p0_16x8 = _mm_and_si128(p0_16x8,\n                            _mm_xor_si128(flag3_16x8, _mm_set1_epi8(0xFF)));\n    p0_16x8_2 = _mm_and_si128(p0_16x8_2, flag3_16x8);\n    p0_16x8 = _mm_add_epi8(p0_16x8, p0_16x8_2);\n    q0_16x8 = _mm_and_si128(q0_16x8,\n                            _mm_xor_si128(flag4_16x8, _mm_set1_epi8(0xFF)));\n    q0_16x8_2 = _mm_and_si128(q0_16x8_2, flag4_16x8);\n    q0_16x8 = _mm_add_epi8(q0_16x8, q0_16x8_2);\n\n    // p1 and q1\n    p1_16x8 = _mm_and_si128(p1_16x8,\n                            _mm_xor_si128(flag3_16x8, _mm_set1_epi8(0xFF)));\n    p1_16x8_2 = _mm_and_si128(p1_16x8_2, flag3_16x8);\n    p1_16x8 = _mm_add_epi8(p1_16x8, p1_16x8_2);\n    q1_16x8 = _mm_and_si128(q1_16x8,\n                            _mm_xor_si128(flag4_16x8, _mm_set1_epi8(0xFF)));\n    q1_16x8_2 = _mm_and_si128(q1_16x8_2, flag4_16x8);\n    q1_16x8 = _mm_add_epi8(q1_16x8, q1_16x8_2);\n\n    // p2 and q2\n    p2_16x8 = _mm_and_si128(p2_16x8,\n                            _mm_xor_si128(flag3_16x8, _mm_set1_epi8(0xFF)));\n    p2_16x8_2 = _mm_and_si128(p2_16x8_2, flag3_16x8);\n    p2_16x8 = _mm_add_epi8(p2_16x8, p2_16x8_2);\n    q2_16x8 = _mm_and_si128(q2_16x8,\n                            _mm_xor_si128(flag4_16x8, _mm_set1_epi8(0xFF)));\n    q2_16x8_2 = _mm_and_si128(q2_16x8_2, flag4_16x8);\n    q2_16x8 = _mm_add_epi8(q2_16x8, q2_16x8_2);\n\n    temp1 = _mm_unpacklo_epi8(p3_16x8, p2_16x8);\n    temp2 = _mm_unpacklo_epi8(p1_16x8, p0_16x8);\n    temp3 = _mm_unpacklo_epi8(q0_16x8, q1_16x8);\n    temp4 = _mm_unpacklo_epi8(q2_16x8, q3_16x8);\n\n    p3_8x16 = _mm_unpacklo_epi16(temp1, temp2);\n    p2_8x16 = _mm_unpackhi_epi16(temp1, temp2);\n    q2_8x16 = _mm_unpacklo_epi16(temp3, temp4);\n    q3_8x16 = _mm_unpackhi_epi16(temp3, temp4);\n\n    line1 = _mm_unpacklo_epi32(p3_8x16, q2_8x16);\n    line2 = _mm_srli_si128(line1, 8);\n    line3 = _mm_unpackhi_epi32(p3_8x16, q2_8x16);\n    line4 = _mm_srli_si128(line3, 8);\n    line5 = _mm_unpacklo_epi32(p2_8x16, q3_8x16);\n    line6 = _mm_srli_si128(line5, 8);\n    line7 = _mm_unpackhi_epi32(p2_8x16, q3_8x16);\n    line8 = _mm_srli_si128(line7, 8);\n\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 0 * src_strd), line1);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 1 * src_strd), line2);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 2 * src_strd), line3);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 3 * src_strd), line4);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 4 * src_strd), line5);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 5 * src_strd), line6);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 6 * src_strd), line7);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 7 * src_strd), line8);\n\n    temp1 = _mm_unpackhi_epi8(p3_16x8, p2_16x8);\n    temp2 = _mm_unpackhi_epi8(p1_16x8, p0_16x8);\n    temp3 = _mm_unpackhi_epi8(q0_16x8, q1_16x8);\n    temp4 = _mm_unpackhi_epi8(q2_16x8, q3_16x8);\n\n    p3_8x16 = _mm_unpacklo_epi16(temp1, temp2);\n    p2_8x16 = _mm_unpackhi_epi16(temp1, temp2);\n    q2_8x16 = _mm_unpacklo_epi16(temp3, temp4);\n    q3_8x16 = _mm_unpackhi_epi16(temp3, temp4);\n\n    line1 = _mm_unpacklo_epi32(p3_8x16, q2_8x16);\n    line2 = _mm_srli_si128(line1, 8);\n    line3 = _mm_unpackhi_epi32(p3_8x16, q2_8x16);\n    line4 = _mm_srli_si128(line3, 8);\n    line5 = _mm_unpacklo_epi32(p2_8x16, q3_8x16);\n    line6 = _mm_srli_si128(line5, 8);\n    line7 = _mm_unpackhi_epi32(p2_8x16, q3_8x16);\n    line8 = _mm_srli_si128(line7, 8);\n\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 8 * src_strd), line1);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 9 * src_strd), line2);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 10 * src_strd), line3);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 11 * src_strd), line4);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 12 * src_strd), line5);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 13 * src_strd), line6);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 14 * src_strd), line7);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 15 * src_strd), line8);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_horz_bs4_ssse3()                        */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  horizontal edge when the boundary strength is set to 4.  */\n/*                                                                           */\n/*  Inputs        : pu1_src    - pointer to the src sample q0                */\n/*                  src_strd   - source stride                               */\n/*                  alpha      - alpha value for the boundary                */\n/*                  beta       - beta value for the boundary                 */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.4 under the    */\n/*                  title \"Filtering process for edges for bS equal to 4\" in */\n/*                  ITU T Rec H.264.                                         */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_deblk_luma_horz_bs4_ssse3(UWORD8 *pu1_src,\n                                     WORD32 src_strd,\n                                     WORD32 alpha,\n                                     WORD32 beta)\n{\n    WORD16 i16_posP3, i16_posP2, i16_posP1, i16_posP0;\n    WORD16 i16_posQ1, i16_posQ2, i16_posQ3;\n    UWORD8 *pu1_HorzPixel;\n    __m128i zero = _mm_setzero_si128();\n    __m128i q0_16x8, q1_16x8, q2_16x8, q3_16x8;\n    __m128i p0_16x8, p1_16x8, p2_16x8, p3_16x8;\n    __m128i q0_8x16, q1_8x16, q2_8x16, q3_8x16;\n    __m128i p0_8x16, p1_8x16, p2_8x16, p3_8x16;\n    __m128i q0_16x8_1;\n    __m128i p0_16x8_1;\n    __m128i q0_16x8_2, q1_16x8_2, q2_16x8_2;\n    __m128i p0_16x8_2, p1_16x8_2, p2_16x8_2;\n    __m128i temp1, temp2, temp3, temp4, temp5, temp6;\n    __m128i Alpha_8x16, Beta_8x16;\n    __m128i flag1_16x8, flag2_16x8, flag3_16x8, flag4_16x8;\n    __m128i const_val2_16x8 = _mm_set1_epi16(2);\n\n    pu1_HorzPixel = pu1_src - (src_strd << 2);\n\n    i16_posQ1 = src_strd;\n    i16_posQ2 = X2(src_strd);\n    i16_posQ3 = X3(src_strd);\n    i16_posP0 = X3(src_strd);\n    i16_posP1 = X2(src_strd);\n    i16_posP2 = src_strd;\n    i16_posP3 = 0;\n\n    Alpha_8x16 = _mm_set1_epi16(alpha);\n    Beta_8x16 = _mm_set1_epi16(beta);\n\n    p3_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixel + i16_posP3));\n    p2_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixel + i16_posP2));\n    p1_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixel + i16_posP1));\n    p0_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixel + i16_posP0));\n    q0_16x8 = _mm_loadu_si128((__m128i *)(pu1_src));\n    q1_16x8 = _mm_loadu_si128((__m128i *)(pu1_src + i16_posQ1));\n    q2_16x8 = _mm_loadu_si128((__m128i *)(pu1_src + i16_posQ2));\n    q3_16x8 = _mm_loadu_si128((__m128i *)(pu1_src + i16_posQ3));\n\n    //Cond1 (ABS(p0 - q0) < alpha)\n    temp1 = _mm_subs_epu8(q0_16x8, p0_16x8);\n    temp2 = _mm_subs_epu8(p0_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Alpha_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Alpha_8x16, temp1);\n\n    flag1_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    //Cond2 (ABS(q1 - q0) < beta)\n    temp1 = _mm_subs_epu8(q0_16x8, q1_16x8);\n    temp2 = _mm_subs_epu8(q1_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    flag1_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    //Cond3 (ABS(p1 - p0) < beta)\n    temp1 = _mm_subs_epu8(p0_16x8, p1_16x8);\n    temp2 = _mm_subs_epu8(p1_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    // !((ABS(p0 - q0) < alpha) || (ABS(q1 - q0) < beta) || (ABS(p1 - p0) < beta))\n    flag1_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    // (ABS(p0 - q0) < ((alpha >> 2) + 2))\n    temp1 = _mm_subs_epu8(p0_16x8, q0_16x8);\n    temp2 = _mm_subs_epu8(q0_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n    Alpha_8x16 = _mm_srai_epi16(Alpha_8x16, 2);\n    Alpha_8x16 = _mm_add_epi16(Alpha_8x16, const_val2_16x8);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Alpha_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Alpha_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag2_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    // (ABS(p2 - p0) < beta)\n    temp1 = _mm_subs_epu8(p0_16x8, p2_16x8);\n    temp2 = _mm_subs_epu8(p2_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag3_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag3_16x8 = _mm_and_si128(flag3_16x8, flag2_16x8);\n\n    // (ABS(q2 - q0) < beta)\n    temp1 = _mm_subs_epu8(q0_16x8, q2_16x8);\n    temp2 = _mm_subs_epu8(q2_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag4_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag4_16x8 = _mm_and_si128(flag4_16x8, flag2_16x8);\n\n    // First 8 pixels\n    p3_8x16 = _mm_unpacklo_epi8(p3_16x8, zero);\n    p2_8x16 = _mm_unpacklo_epi8(p2_16x8, zero);\n    p1_8x16 = _mm_unpacklo_epi8(p1_16x8, zero);\n    p0_8x16 = _mm_unpacklo_epi8(p0_16x8, zero);\n    q0_8x16 = _mm_unpacklo_epi8(q0_16x8, zero);\n    q1_8x16 = _mm_unpacklo_epi8(q1_16x8, zero);\n    q2_8x16 = _mm_unpacklo_epi8(q2_16x8, zero);\n    q3_8x16 = _mm_unpacklo_epi8(q3_16x8, zero);\n\n    // p0_1 and q0_1\n    temp1 = _mm_add_epi16(p0_8x16, q1_8x16);\n    temp2 = _mm_add_epi16(p1_8x16, q0_8x16);\n    temp5 = _mm_add_epi16(temp1, const_val2_16x8);\n    temp6 = _mm_add_epi16(temp2, const_val2_16x8);\n    temp3 = _mm_slli_epi16(p1_8x16, 1);\n    temp4 = _mm_slli_epi16(q1_8x16, 1);\n    temp1 = _mm_add_epi16(temp5, temp3);\n    temp2 = _mm_add_epi16(temp6, temp4);\n    p0_16x8_1 = _mm_srai_epi16(temp1, 2);\n    q0_16x8_1 = _mm_srai_epi16(temp2, 2);\n\n    // p1_2 and q1_2\n    temp6 = _mm_add_epi16(temp6, p0_8x16);\n    temp5 = _mm_add_epi16(temp5, q0_8x16);\n    temp1 = _mm_add_epi16(temp6, p2_8x16);\n    temp2 = _mm_add_epi16(temp5, q2_8x16);\n    p1_16x8_2 = _mm_srai_epi16(temp1, 2);\n    q1_16x8_2 = _mm_srai_epi16(temp2, 2);\n\n    // p0_2 and q0_2\n    temp1 = _mm_add_epi16(temp3, p2_8x16);\n    temp2 = _mm_add_epi16(temp4, q2_8x16);\n    temp1 = _mm_add_epi16(temp1, q1_8x16);\n    temp2 = _mm_add_epi16(temp2, p1_8x16);\n    temp3 = _mm_add_epi16(p0_8x16, q0_8x16);\n    temp3 = _mm_slli_epi16(temp3, 1);\n    temp1 = _mm_add_epi16(temp1, temp3);\n    temp2 = _mm_add_epi16(temp2, temp3);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(4));\n    temp2 = _mm_add_epi16(temp2, _mm_set1_epi16(4));\n    p0_16x8_2 = _mm_srai_epi16(temp1, 3);\n    q0_16x8_2 = _mm_srai_epi16(temp2, 3);\n\n    // p2_2 and q2_2\n    temp1 = _mm_add_epi16(temp6, const_val2_16x8);\n    temp2 = _mm_add_epi16(temp5, const_val2_16x8);\n    temp3 = _mm_slli_epi16(p2_8x16, 1);\n    temp4 = _mm_slli_epi16(q2_8x16, 1);\n    temp3 = _mm_add_epi16(p2_8x16, temp3);\n    temp4 = _mm_add_epi16(q2_8x16, temp4);\n    temp5 = _mm_slli_epi16(p3_8x16, 1);\n    temp6 = _mm_slli_epi16(q3_8x16, 1);\n    temp1 = _mm_add_epi16(temp1, temp3);\n    temp2 = _mm_add_epi16(temp2, temp4);\n    temp1 = _mm_add_epi16(temp1, temp5);\n    temp2 = _mm_add_epi16(temp2, temp6);\n    p2_16x8_2 = _mm_srai_epi16(temp1, 3);\n    q2_16x8_2 = _mm_srai_epi16(temp2, 3);\n\n    // Second 8 pixels and packing with first 8 pixels\n    p3_8x16 = _mm_unpackhi_epi8(p3_16x8, zero);\n    p2_8x16 = _mm_unpackhi_epi8(p2_16x8, zero);\n    p1_8x16 = _mm_unpackhi_epi8(p1_16x8, zero);\n    p0_8x16 = _mm_unpackhi_epi8(p0_16x8, zero);\n    q0_8x16 = _mm_unpackhi_epi8(q0_16x8, zero);\n    q1_8x16 = _mm_unpackhi_epi8(q1_16x8, zero);\n    q2_8x16 = _mm_unpackhi_epi8(q2_16x8, zero);\n    q3_8x16 = _mm_unpackhi_epi8(q3_16x8, zero);\n\n    // p0_1 and q0_1\n    temp1 = _mm_add_epi16(p0_8x16, q1_8x16);\n    temp2 = _mm_add_epi16(p1_8x16, q0_8x16);\n    temp5 = _mm_add_epi16(temp1, const_val2_16x8);\n    temp6 = _mm_add_epi16(temp2, const_val2_16x8);\n    temp3 = _mm_slli_epi16(p1_8x16, 1);\n    temp4 = _mm_slli_epi16(q1_8x16, 1);\n    temp1 = _mm_add_epi16(temp5, temp3);\n    temp2 = _mm_add_epi16(temp6, temp4);\n    temp1 = _mm_srai_epi16(temp1, 2);\n    temp2 = _mm_srai_epi16(temp2, 2);\n    p0_16x8_1 = _mm_packus_epi16(p0_16x8_1, temp1);\n    q0_16x8_1 = _mm_packus_epi16(q0_16x8_1, temp2);\n\n    // p1_2 and q1_2\n    temp6 = _mm_add_epi16(temp6, p0_8x16);\n    temp5 = _mm_add_epi16(temp5, q0_8x16);\n    temp1 = _mm_add_epi16(temp6, p2_8x16);\n    temp2 = _mm_add_epi16(temp5, q2_8x16);\n    temp1 = _mm_srai_epi16(temp1, 2);\n    temp2 = _mm_srai_epi16(temp2, 2);\n    p1_16x8_2 = _mm_packus_epi16(p1_16x8_2, temp1);\n    q1_16x8_2 = _mm_packus_epi16(q1_16x8_2, temp2);\n\n    // p0_2 and q0_2\n    temp1 = _mm_add_epi16(temp3, p2_8x16);\n    temp2 = _mm_add_epi16(temp4, q2_8x16);\n    temp1 = _mm_add_epi16(temp1, q1_8x16);\n    temp2 = _mm_add_epi16(temp2, p1_8x16);\n    temp3 = _mm_add_epi16(p0_8x16, q0_8x16);\n    temp3 = _mm_slli_epi16(temp3, 1);\n    temp1 = _mm_add_epi16(temp1, temp3);\n    temp2 = _mm_add_epi16(temp2, temp3);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(4));\n    temp2 = _mm_add_epi16(temp2, _mm_set1_epi16(4));\n    temp1 = _mm_srai_epi16(temp1, 3);\n    temp2 = _mm_srai_epi16(temp2, 3);\n    p0_16x8_2 = _mm_packus_epi16(p0_16x8_2, temp1);\n    q0_16x8_2 = _mm_packus_epi16(q0_16x8_2, temp2);\n\n    // p2_2 and q2_2\n    temp1 = _mm_add_epi16(temp6, const_val2_16x8);\n    temp2 = _mm_add_epi16(temp5, const_val2_16x8);\n    temp3 = _mm_slli_epi16(p2_8x16, 1);\n    temp4 = _mm_slli_epi16(q2_8x16, 1);\n    temp3 = _mm_add_epi16(p2_8x16, temp3);\n    temp4 = _mm_add_epi16(q2_8x16, temp4);\n    temp5 = _mm_slli_epi16(p3_8x16, 1);\n    temp6 = _mm_slli_epi16(q3_8x16, 1);\n    temp1 = _mm_add_epi16(temp1, temp3);\n    temp2 = _mm_add_epi16(temp2, temp4);\n    temp1 = _mm_add_epi16(temp1, temp5);\n    temp2 = _mm_add_epi16(temp2, temp6);\n    temp1 = _mm_srai_epi16(temp1, 3);\n    temp2 = _mm_srai_epi16(temp2, 3);\n    p2_16x8_2 = _mm_packus_epi16(p2_16x8_2, temp1);\n    q2_16x8_2 = _mm_packus_epi16(q2_16x8_2, temp2);\n\n    // p0 and q0\n    p0_16x8 = _mm_and_si128(p0_16x8,\n                            _mm_xor_si128(flag1_16x8, _mm_set1_epi8(0xFF)));\n    p0_16x8_1 = _mm_and_si128(p0_16x8_1, flag1_16x8);\n    p0_16x8 = _mm_add_epi8(p0_16x8, p0_16x8_1);\n    q0_16x8 = _mm_and_si128(q0_16x8,\n                            _mm_xor_si128(flag1_16x8, _mm_set1_epi8(0xFF)));\n    q0_16x8_1 = _mm_and_si128(q0_16x8_1, flag1_16x8);\n    q0_16x8 = _mm_add_epi8(q0_16x8, q0_16x8_1);\n\n    // p0 and q0\n    p0_16x8 = _mm_and_si128(p0_16x8,\n                            _mm_xor_si128(flag3_16x8, _mm_set1_epi8(0xFF)));\n    p0_16x8_2 = _mm_and_si128(p0_16x8_2, flag3_16x8);\n    p0_16x8 = _mm_add_epi8(p0_16x8, p0_16x8_2);\n    q0_16x8 = _mm_and_si128(q0_16x8,\n                            _mm_xor_si128(flag4_16x8, _mm_set1_epi8(0xFF)));\n    q0_16x8_2 = _mm_and_si128(q0_16x8_2, flag4_16x8);\n    q0_16x8 = _mm_add_epi8(q0_16x8, q0_16x8_2);\n\n    // p1 and q1\n    p1_16x8 = _mm_and_si128(p1_16x8,\n                            _mm_xor_si128(flag3_16x8, _mm_set1_epi8(0xFF)));\n    p1_16x8_2 = _mm_and_si128(p1_16x8_2, flag3_16x8);\n    p1_16x8 = _mm_add_epi8(p1_16x8, p1_16x8_2);\n    q1_16x8 = _mm_and_si128(q1_16x8,\n                            _mm_xor_si128(flag4_16x8, _mm_set1_epi8(0xFF)));\n    q1_16x8_2 = _mm_and_si128(q1_16x8_2, flag4_16x8);\n    q1_16x8 = _mm_add_epi8(q1_16x8, q1_16x8_2);\n\n    // p2 and q2\n    p2_16x8 = _mm_and_si128(p2_16x8,\n                            _mm_xor_si128(flag3_16x8, _mm_set1_epi8(0xFF)));\n    p2_16x8_2 = _mm_and_si128(p2_16x8_2, flag3_16x8);\n    p2_16x8 = _mm_add_epi8(p2_16x8, p2_16x8_2);\n    q2_16x8 = _mm_and_si128(q2_16x8,\n                            _mm_xor_si128(flag4_16x8, _mm_set1_epi8(0xFF)));\n    q2_16x8_2 = _mm_and_si128(q2_16x8_2, flag4_16x8);\n    q2_16x8 = _mm_add_epi8(q2_16x8, q2_16x8_2);\n\n    _mm_storeu_si128((__m128i *)(pu1_HorzPixel + i16_posP2), p2_16x8);\n    _mm_storeu_si128((__m128i *)(pu1_HorzPixel + i16_posP1), p1_16x8);\n    _mm_storeu_si128((__m128i *)(pu1_HorzPixel + i16_posP0), p0_16x8);\n\n    _mm_storeu_si128((__m128i *)(pu1_src), q0_16x8);\n    _mm_storeu_si128((__m128i *)(pu1_src + i16_posQ1), q1_16x8);\n    _mm_storeu_si128((__m128i *)(pu1_src + i16_posQ2), q2_16x8);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_vert_bslt4_ssse3()                      */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  vertical edge when the boundary strength is less than 4. */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0             */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                  u4_bs         - packed Boundary strength array           */\n/*                  pu1_cliptab   - tc0_table                                */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.3 under the    */\n/*                  title \"Filtering process for edges for bS less than 4\"   */\n/*                  in ITU T Rec H.264.                                      */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_deblk_luma_vert_bslt4_ssse3(UWORD8 *pu1_src,\n                                       WORD32 src_strd,\n                                       WORD32 alpha,\n                                       WORD32 beta,\n                                       UWORD32 u4_bs,\n                                       const UWORD8 *pu1_cliptab)\n{\n    UWORD8 u1_Bs, u1_Bs1;\n\n    WORD32 j = 0;\n\n    __m128i linea, lineb, linec, lined, linee, linef, lineg, lineh;\n    __m128i int1, int2, int3, int4, high1, high2;\n    __m128i flag, flag1, i_C, i_C0;\n    __m128i i_Ap, i_Aq, diff, const1, const2, in_macro, in_macrotemp, temp,\n                    temp1;\n    __m128i zero = _mm_setzero_si128();\n\n    for(j = 0; j <= 8 * src_strd; j += 8 * src_strd)\n    {\n        //Transpose\n        linea = _mm_loadl_epi64((__m128i *)(pu1_src - 3 + j));\n        lineb = _mm_loadl_epi64((__m128i *)(pu1_src - 3 + src_strd + j));\n        linec = _mm_loadl_epi64((__m128i *)(pu1_src - 3 + 2 * src_strd + j));\n        lined = _mm_loadl_epi64((__m128i *)(pu1_src - 3 + 3 * src_strd + j));\n\n        linea = _mm_unpacklo_epi8(linea, zero);\n        lineb = _mm_unpacklo_epi8(lineb, zero);\n        linec = _mm_unpacklo_epi8(linec, zero);\n        lined = _mm_unpacklo_epi8(lined, zero);\n\n        int1 = _mm_unpacklo_epi16(linea, lineb);\n        lineb = _mm_unpackhi_epi16(linea, lineb);\n\n        int2 = _mm_unpacklo_epi16(linec, lined);\n        lined = _mm_unpackhi_epi16(linec, lined);\n\n        linea = _mm_unpacklo_epi16(int1, int2);\n        int1 = _mm_unpackhi_epi16(int1, int2);\n\n        linec = _mm_unpacklo_epi16(lineb, lined);\n        high1 = _mm_unpackhi_epi16(lineb, lined);\n\n        linee = _mm_loadl_epi64((__m128i *)(pu1_src - 3 + 4 * src_strd + j));\n        linef = _mm_loadl_epi64((__m128i *)(pu1_src - 3 + 5 * src_strd + j));\n        lineg = _mm_loadl_epi64((__m128i *)(pu1_src - 3 + 6 * src_strd + j));\n        lineh = _mm_loadl_epi64((__m128i *)(pu1_src - 3 + 7 * src_strd + j));\n\n        linee = _mm_unpacklo_epi8(linee, zero);\n        linef = _mm_unpacklo_epi8(linef, zero);\n        lineg = _mm_unpacklo_epi8(lineg, zero);\n        lineh = _mm_unpacklo_epi8(lineh, zero);\n\n        int2 = _mm_unpacklo_epi16(linee, linef);\n        linef = _mm_unpackhi_epi16(linee, linef);\n\n        int3 = _mm_unpacklo_epi16(lineg, lineh);\n        lineh = _mm_unpackhi_epi16(lineg, lineh);\n\n        linee = _mm_unpacklo_epi16(int2, int3);\n        int2 = _mm_unpackhi_epi16(int2, int3);\n\n        lineg = _mm_unpacklo_epi16(linef, lineh);\n        high2 = _mm_unpackhi_epi16(linef, lineh);\n\n        int4 = _mm_unpacklo_epi16(linea, linee);\n        lineb = _mm_unpackhi_epi16(linea, linee);\n\n        int3 = _mm_unpacklo_epi16(int1, int2);\n        lined = _mm_unpackhi_epi16(int1, int2);\n\n        int2 = _mm_unpacklo_epi16(linec, lineg);\n        linef = _mm_unpackhi_epi16(linec, lineg);\n\n        linea = int4;\n        linec = int3;\n        linee = int2;\n\n        lineg = _mm_unpacklo_epi16(high1, high2);\n        lineh = _mm_unpackhi_epi16(high1, high2);\n\n        //end of transpose\n\n        u1_Bs = (u4_bs >> 24) & 0xff;\n        u1_Bs1 = (u4_bs >> 16) & 0xff;\n        u4_bs <<= 16;\n\n        flag1 = _mm_set_epi16(u1_Bs1, u1_Bs, u1_Bs1, u1_Bs, u1_Bs1, u1_Bs,\n                              u1_Bs1, u1_Bs);\n        flag1 = _mm_cmpeq_epi16(flag1, zero); //Set flag to 1s and 0s\n        flag1 = _mm_xor_si128(flag1, _mm_set1_epi16(0xFFFF)); //Invert for required mask\n\n        i_C0 = _mm_set_epi16(pu1_cliptab[u1_Bs1], pu1_cliptab[u1_Bs],\n                             pu1_cliptab[u1_Bs1], pu1_cliptab[u1_Bs],\n                             pu1_cliptab[u1_Bs1], pu1_cliptab[u1_Bs],\n                             pu1_cliptab[u1_Bs1], pu1_cliptab[u1_Bs]);\n\n        diff = _mm_subs_epi16(linec, lined); //Condn 1\n        diff = _mm_abs_epi16(diff);\n        const1 = _mm_set1_epi16(alpha);\n        flag = _mm_cmpgt_epi16(const1, diff);\n\n        diff = _mm_subs_epi16(linee, lined); //Condtn 2\n        diff = _mm_abs_epi16(diff);\n        const1 = _mm_set1_epi16(beta);\n        flag = _mm_and_si128(flag, _mm_cmpgt_epi16(const1, diff));\n\n        diff = _mm_subs_epi16(lineb, linec); //Condtn 3\n        diff = _mm_abs_epi16(diff);\n        flag = _mm_and_si128(flag, _mm_cmpgt_epi16(const1, diff)); //Const 1= Beta from now on\n\n        flag = _mm_and_si128(flag, flag1); //Final flag (ui_B condition + other 3 conditions)\n\n        //Adding Ap<Beta and Aq<Beta\n        i_Ap = _mm_subs_epi16(linea, linec);\n        i_Ap = _mm_abs_epi16(i_Ap);\n        const2 = _mm_cmpgt_epi16(const1, i_Ap);\n        const2 = _mm_subs_epi16(zero, const2); //Make FFFF=1 and 0000=0\n        i_C = _mm_add_epi16(i_C0, const2);\n\n        i_Aq = _mm_subs_epi16(linef, lined);\n        i_Aq = _mm_abs_epi16(i_Aq);\n        const2 = _mm_cmpgt_epi16(const1, i_Aq);\n        const2 = _mm_subs_epi16(zero, const2);\n        i_C = _mm_add_epi16(i_C, const2);\n\n        //Calculate in_macro\n        diff = _mm_subs_epi16(lined, linec);\n        diff = _mm_slli_epi16(diff, 2);\n        const2 = _mm_subs_epi16(lineb, linee);\n        diff = _mm_add_epi16(diff, const2);\n        const2 = _mm_set1_epi16(4);\n        diff = _mm_add_epi16(diff, const2);\n        in_macro = _mm_srai_epi16(diff, 3);\n\n        in_macro = _mm_min_epi16(i_C, in_macro); //CLIP3\n        i_C = _mm_subs_epi16(zero, i_C);\n        in_macro = _mm_max_epi16(i_C, in_macro);\n\n        //Compute and store\n        in_macrotemp = _mm_add_epi16(linec, in_macro);\n        in_macrotemp = _mm_and_si128(in_macrotemp, flag);\n        temp = _mm_and_si128(linec,\n                             _mm_xor_si128(flag, _mm_set1_epi16(0xFFFF)));\n        temp = _mm_add_epi16(temp, in_macrotemp);\n        //temp= _mm_packus_epi16 (temp, zero);\n        //_mm_storel_epi64(uc_HorzPixel+i16_posP0+i, in_macrotemp);\n\n        in_macrotemp = _mm_subs_epi16(lined, in_macro);\n        in_macrotemp = _mm_and_si128(in_macrotemp, flag);\n        temp1 = _mm_and_si128(lined,\n                              _mm_xor_si128(flag, _mm_set1_epi16(0xFFFF)));\n        temp1 = _mm_add_epi16(temp1, in_macrotemp);\n        //temp1= _mm_packus_epi16 (temp1, zero);\n        //_mm_storel_epi64(pu1_src+i, in_macrotemp);\n\n        //If Ap<Beta\n        flag1 = _mm_cmpgt_epi16(const1, i_Ap);\n        flag1 = _mm_and_si128(flag, flag1);\n        in_macrotemp = _mm_add_epi16(linec, lined);\n        in_macrotemp = _mm_add_epi16(in_macrotemp, _mm_set1_epi16(1));\n        in_macrotemp = _mm_srai_epi16(in_macrotemp, 1);\n        in_macro = _mm_add_epi16(in_macrotemp, linea);\n        in_macro = _mm_subs_epi16(in_macro, _mm_slli_epi16(lineb, 1));\n        in_macro = _mm_srai_epi16(in_macro, 1);\n\n        in_macro = _mm_min_epi16(i_C0, in_macro); //CLIP3\n        i_C0 = _mm_subs_epi16(zero, i_C0);\n        in_macro = _mm_max_epi16(i_C0, in_macro);\n\n        in_macro = _mm_and_si128(in_macro, flag1);\n        lineb = _mm_add_epi16(lineb, in_macro);\n        //in_macro= _mm_packus_epi16 (i_p1, zero);\n        //_mm_storel_epi64(uc_HorzPixel+i16_posP1+i, in_macro);\n\n        flag1 = _mm_cmpgt_epi16(const1, i_Aq);\n        flag1 = _mm_and_si128(flag, flag1);\n        in_macro = _mm_add_epi16(in_macrotemp, linef);\n        in_macro = _mm_subs_epi16(in_macro, _mm_slli_epi16(linee, 1));\n        in_macro = _mm_srai_epi16(in_macro, 1);\n\n        i_C0 = _mm_abs_epi16(i_C0);\n        in_macro = _mm_min_epi16(i_C0, in_macro); //CLIP3\n        i_C0 = _mm_subs_epi16(zero, i_C0);\n        in_macro = _mm_max_epi16(i_C0, in_macro);\n\n        in_macro = _mm_and_si128(in_macro, flag1);\n        linee = _mm_add_epi16(linee, in_macro);\n        //in_macro= _mm_packus_epi16 (i_q1, zero);\n        //_mm_storel_epi64(pu1_src+i16_posQ1+i, in_macro);\n        linec = temp;\n        lined = temp1;\n        //End of filtering\n\n        int1 = _mm_unpacklo_epi16(linea, linee);\n        linee = _mm_unpackhi_epi16(linea, linee);\n\n        int2 = _mm_unpacklo_epi16(linec, lineg);\n        lineg = _mm_unpackhi_epi16(linec, lineg);\n\n        linea = _mm_unpacklo_epi16(int1, int2);\n        int3 = _mm_unpackhi_epi16(int1, int2);\n\n        linec = _mm_unpacklo_epi16(linee, lineg);\n        lineg = _mm_unpackhi_epi16(linee, lineg);\n\n        int1 = _mm_unpacklo_epi16(lineb, linef);\n        linef = _mm_unpackhi_epi16(lineb, linef);\n\n        int2 = _mm_unpacklo_epi16(lined, lineh);\n        lineh = _mm_unpackhi_epi16(lined, lineh);\n\n        lineb = _mm_unpacklo_epi16(int1, int2);\n        int4 = _mm_unpackhi_epi16(int1, int2);\n\n        lined = _mm_unpacklo_epi16(linef, lineh);\n        lineh = _mm_unpackhi_epi16(linef, lineh);\n\n        int1 = _mm_unpackhi_epi16(linea, lineb);\n        linea = _mm_unpacklo_epi16(linea, lineb);\n\n        int2 = _mm_unpacklo_epi16(int3, int4);\n        high1 = _mm_unpackhi_epi16(int3, int4);\n\n        lineb = _mm_unpacklo_epi16(linec, lined);\n        linef = _mm_unpackhi_epi16(linec, lined);\n\n        lined = _mm_unpacklo_epi16(lineg, lineh);\n        lineh = _mm_unpackhi_epi16(lineg, lineh);\n\n        linee = int1;\n        lineg = high1;\n        linec = int2;\n        //End of inverse transpose\n\n        //Packs and stores\n        linea = _mm_packus_epi16(linea, zero);\n        _mm_storel_epi64((__m128i *)(pu1_src - 3 + j), linea);\n\n        lineb = _mm_packus_epi16(lineb, zero);\n        _mm_storel_epi64((__m128i *)(pu1_src - 3 + src_strd + j), lineb);\n\n        linec = _mm_packus_epi16(linec, zero);\n        _mm_storel_epi64((__m128i *)(pu1_src - 3 + 2 * src_strd + j), linec);\n\n        lined = _mm_packus_epi16(lined, zero);\n        _mm_storel_epi64((__m128i *)(pu1_src - 3 + 3 * src_strd + j), lined);\n\n        linee = _mm_packus_epi16(linee, zero);\n        _mm_storel_epi64((__m128i *)(pu1_src - 3 + 4 * src_strd + j), linee);\n\n        linef = _mm_packus_epi16(linef, zero);\n        _mm_storel_epi64((__m128i *)(pu1_src - 3 + 5 * src_strd + j), linef);\n\n        lineg = _mm_packus_epi16(lineg, zero);\n        _mm_storel_epi64((__m128i *)(pu1_src - 3 + 6 * src_strd + j), lineg);\n\n        lineh = _mm_packus_epi16(lineh, zero);\n        _mm_storel_epi64((__m128i *)(pu1_src - 3 + 7 * src_strd + j), lineh);\n\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_horz_bslt4_ssse3()                      */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  horizontal edge when boundary strength is less than 4.   */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0             */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                  u4_bs         - packed Boundary strength array           */\n/*                  pu1_cliptab   - tc0_table                                */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : This operation is described in Sec. 8.7.2.3 under the    */\n/*                  title \"Filtering process for edges for bS less than 4\"   */\n/*                  in ITU T Rec H.264.                                      */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_deblk_luma_horz_bslt4_ssse3(UWORD8 *pu1_src,\n                                       WORD32 src_strd,\n                                       WORD32 alpha,\n                                       WORD32 beta,\n                                       UWORD32 u4_bs,\n                                       const UWORD8 *pu1_cliptab)\n{\n    WORD16 i16_posP2, i16_posP1, i16_posP0, i16_posQ1, i16_posQ2;\n    UWORD8 *pu1_HorzPixel;\n    __m128i zero = _mm_setzero_si128();\n    __m128i bs_flag_16x8b, C0_16x8, C0_8x16, C0_hi_8x16, C_8x16, C_hi_8x16;\n    __m128i q0_16x8, q1_16x8, q2_16x8, p0_16x8, p1_16x8, p2_16x8;\n    __m128i temp1, temp2;\n    __m128i Alpha_8x16, Beta_8x16, flag1_16x8, flag2_16x8, flag3_16x8;\n    __m128i in_macro_16x8, in_macro_hi_16x8;\n    __m128i const_val4_8x16;\n    UWORD8 u1_Bs0, u1_Bs1, u1_Bs2, u1_Bs3;\n    UWORD8 clip0, clip1, clip2, clip3;\n\n    pu1_HorzPixel = pu1_src - (src_strd << 2);\n\n    i16_posQ1 = src_strd;\n    i16_posQ2 = X2(src_strd);\n    i16_posP0 = X3(src_strd);\n    i16_posP1 = X2(src_strd);\n    i16_posP2 = src_strd;\n\n    q0_16x8 = _mm_loadu_si128((__m128i *)(pu1_src));\n    q1_16x8 = _mm_loadu_si128((__m128i *)(pu1_src + i16_posQ1));\n\n    u1_Bs0 = (u4_bs >> 24) & 0xff;\n    u1_Bs1 = (u4_bs >> 16) & 0xff;\n    u1_Bs2 = (u4_bs >> 8) & 0xff;\n    u1_Bs3 = (u4_bs >> 0) & 0xff;\n    clip0 = pu1_cliptab[u1_Bs0];\n    clip1 = pu1_cliptab[u1_Bs1];\n    clip2 = pu1_cliptab[u1_Bs2];\n    clip3 = pu1_cliptab[u1_Bs3];\n\n    Alpha_8x16 = _mm_set1_epi16(alpha);\n    Beta_8x16 = _mm_set1_epi16(beta);\n\n    bs_flag_16x8b = _mm_set_epi8(u1_Bs3, u1_Bs3, u1_Bs3, u1_Bs3, u1_Bs2, u1_Bs2,\n                                 u1_Bs2, u1_Bs2, u1_Bs1, u1_Bs1, u1_Bs1, u1_Bs1,\n                                 u1_Bs0, u1_Bs0, u1_Bs0, u1_Bs0);\n\n    C0_16x8 = _mm_set_epi8(clip3, clip3, clip3, clip3, clip2, clip2, clip2,\n                           clip2, clip1, clip1, clip1, clip1, clip0, clip0,\n                           clip0, clip0);\n\n    bs_flag_16x8b = _mm_cmpeq_epi8(bs_flag_16x8b, zero);\n    bs_flag_16x8b = _mm_xor_si128(bs_flag_16x8b, _mm_set1_epi8(0xFF)); //Invert for required mask\n    C0_8x16 = _mm_unpacklo_epi8(C0_16x8, zero);\n    C0_hi_8x16 = _mm_unpackhi_epi8(C0_16x8, zero);\n\n    p1_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixel + i16_posP1));\n    p0_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixel + i16_posP0));\n    p2_16x8 = _mm_loadu_si128((__m128i *)(pu1_HorzPixel + i16_posP2));\n    q2_16x8 = _mm_loadu_si128((__m128i *)(pu1_src + i16_posQ2));\n\n    //Cond1 (ABS(p0 - q0) < alpha)\n    temp1 = _mm_subs_epu8(q0_16x8, p0_16x8);\n    temp2 = _mm_subs_epu8(p0_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Alpha_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Alpha_8x16, temp1);\n\n    flag1_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag1_16x8 = _mm_and_si128(flag1_16x8, bs_flag_16x8b);\n\n    //Cond2 (ABS(q1 - q0) < beta)\n    temp1 = _mm_subs_epu8(q0_16x8, q1_16x8);\n    temp2 = _mm_subs_epu8(q1_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    flag1_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    //Cond3 (ABS(p1 - p0) < beta)\n    temp1 = _mm_subs_epu8(p0_16x8, p1_16x8);\n    temp2 = _mm_subs_epu8(p1_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    // !((ABS(p0 - q0) < alpha) || (ABS(q1 - q0) < beta) || (ABS(p1 - p0) < beta))\n    flag1_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    // (ABS(p2 - p0) < beta)\n    temp1 = _mm_subs_epu8(p0_16x8, p2_16x8);\n    temp2 = _mm_subs_epu8(p2_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag2_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    temp2 = _mm_subs_epi16(zero, temp2);\n    temp1 = _mm_subs_epi16(zero, temp1);\n\n    C_8x16 = _mm_add_epi16(C0_8x16, temp2);\n    C_hi_8x16 = _mm_add_epi16(C0_hi_8x16, temp1);\n\n    // (ABS(q2 - q0) < beta)\n    temp1 = _mm_subs_epu8(q0_16x8, q2_16x8);\n    temp2 = _mm_subs_epu8(q2_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag3_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag3_16x8 = _mm_and_si128(flag1_16x8, flag3_16x8);\n\n    temp2 = _mm_subs_epi16(zero, temp2);\n    temp1 = _mm_subs_epi16(zero, temp1);\n\n    C_8x16 = _mm_add_epi16(C_8x16, temp2);\n    C_hi_8x16 = _mm_add_epi16(C_hi_8x16, temp1);\n\n    const_val4_8x16 = _mm_set1_epi16(4);\n    temp1 = _mm_subs_epi16(_mm_unpacklo_epi8(q0_16x8, zero),\n                           _mm_unpacklo_epi8(p0_16x8, zero));\n    temp2 = _mm_subs_epi16(_mm_unpacklo_epi8(p1_16x8, zero),\n                           _mm_unpacklo_epi8(q1_16x8, zero));\n    temp1 = _mm_slli_epi16(temp1, 2);\n    temp1 = _mm_add_epi16(temp1, temp2);\n    temp1 = _mm_add_epi16(temp1, const_val4_8x16);\n    in_macro_16x8 = _mm_srai_epi16(temp1, 3);\n\n    temp1 = _mm_subs_epi16(_mm_unpackhi_epi8(q0_16x8, zero),\n                           _mm_unpackhi_epi8(p0_16x8, zero));\n    temp2 = _mm_subs_epi16(_mm_unpackhi_epi8(p1_16x8, zero),\n                           _mm_unpackhi_epi8(q1_16x8, zero));\n    temp1 = _mm_slli_epi16(temp1, 2);\n    temp1 = _mm_add_epi16(temp1, temp2);\n    temp1 = _mm_add_epi16(temp1, const_val4_8x16);\n    in_macro_hi_16x8 = _mm_srai_epi16(temp1, 3);\n\n    in_macro_16x8 = _mm_min_epi16(C_8x16, in_macro_16x8); //CLIP3\n    in_macro_hi_16x8 = _mm_min_epi16(C_hi_8x16, in_macro_hi_16x8); //CLIP3\n    C_8x16 = _mm_subs_epi16(zero, C_8x16);\n    C_hi_8x16 = _mm_subs_epi16(zero, C_hi_8x16);\n    in_macro_16x8 = _mm_max_epi16(C_8x16, in_macro_16x8); //CLIP3\n    in_macro_hi_16x8 = _mm_max_epi16(C_hi_8x16, in_macro_hi_16x8); //CLIP3\n\n    temp1 = _mm_add_epi16(_mm_unpacklo_epi8(p0_16x8, zero), in_macro_16x8);\n    temp2 = _mm_add_epi16(_mm_unpackhi_epi8(p0_16x8, zero), in_macro_hi_16x8);\n\n    temp1 = _mm_packus_epi16(temp1, temp2);\n\n    temp1 = _mm_and_si128(temp1, flag1_16x8);\n    temp2 = _mm_and_si128(p0_16x8,\n                          _mm_xor_si128(flag1_16x8, _mm_set1_epi16(0xFFFF)));\n\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    _mm_storeu_si128((__m128i *)(pu1_HorzPixel + i16_posP0), temp1);\n\n    temp1 = _mm_sub_epi16(_mm_unpacklo_epi8(q0_16x8, zero), in_macro_16x8);\n    temp2 = _mm_sub_epi16(_mm_unpackhi_epi8(q0_16x8, zero), in_macro_hi_16x8);\n\n    temp1 = _mm_packus_epi16(temp1, temp2);\n\n    temp1 = _mm_and_si128(temp1, flag1_16x8);\n    temp2 = _mm_and_si128(q0_16x8,\n                          _mm_xor_si128(flag1_16x8, _mm_set1_epi16(0xFFFF)));\n\n    temp1 = _mm_add_epi8(temp1, temp2);\n    _mm_storeu_si128((__m128i *)(pu1_src), temp1);\n\n    //if(Ap < Beta)\n    temp1 = _mm_avg_epu16(_mm_unpacklo_epi8(q0_16x8, zero),\n                          _mm_unpacklo_epi8(p0_16x8, zero));\n    temp2 = _mm_slli_epi16(_mm_unpacklo_epi8(p1_16x8, zero), 1);\n    //temp2 = _mm_subs_epi16(zero,temp2);\n    temp2 = _mm_subs_epi16(_mm_unpacklo_epi8(p2_16x8, zero), temp2);\n    temp2 = _mm_add_epi16(temp1, temp2);\n    in_macro_16x8 = _mm_srai_epi16(temp2, 1);\n\n    temp1 = _mm_avg_epu16(_mm_unpackhi_epi8(q0_16x8, zero),\n                          _mm_unpackhi_epi8(p0_16x8, zero));\n    temp2 = _mm_slli_epi16(_mm_unpackhi_epi8(p1_16x8, zero), 1);\n    //temp2 = _mm_subs_epi16(zero,temp2);\n    temp2 = _mm_subs_epi16(_mm_unpackhi_epi8(p2_16x8, zero), temp2);\n    temp2 = _mm_add_epi16(temp1, temp2);\n    in_macro_hi_16x8 = _mm_srai_epi16(temp2, 1);\n\n    in_macro_16x8 = _mm_min_epi16(C0_8x16, in_macro_16x8); //CLIP3\n    in_macro_hi_16x8 = _mm_min_epi16(C0_hi_8x16, in_macro_hi_16x8); //CLIP3\n    C0_8x16 = _mm_subs_epi16(zero, C0_8x16);\n    C0_hi_8x16 = _mm_subs_epi16(zero, C0_hi_8x16);\n    in_macro_16x8 = _mm_max_epi16(C0_8x16, in_macro_16x8); //CLIP3\n    in_macro_hi_16x8 = _mm_max_epi16(C0_hi_8x16, in_macro_hi_16x8); //CLIP3\n\n    temp1 = _mm_add_epi16(_mm_unpacklo_epi8(p1_16x8, zero), in_macro_16x8);\n    temp2 = _mm_add_epi16(_mm_unpackhi_epi8(p1_16x8, zero), in_macro_hi_16x8);\n\n    temp1 = _mm_packus_epi16(temp1, temp2);\n\n    temp1 = _mm_and_si128(temp1, flag2_16x8);\n    temp2 = _mm_and_si128(p1_16x8,\n                          _mm_xor_si128(flag2_16x8, _mm_set1_epi16(0xFFFF)));\n    temp1 = _mm_add_epi8(temp1, temp2);\n    _mm_storeu_si128((__m128i *)(pu1_HorzPixel + i16_posP1), temp1);\n\n    //if(Aq < Beta)\n    temp1 = _mm_avg_epu16(_mm_unpacklo_epi8(q0_16x8, zero),\n                          _mm_unpacklo_epi8(p0_16x8, zero));\n    temp2 = _mm_slli_epi16(_mm_unpacklo_epi8(q1_16x8, zero), 1);\n    //temp2 = _mm_slli_epi16 (temp2, 1);\n    temp2 = _mm_subs_epi16(_mm_unpacklo_epi8(q2_16x8, zero), temp2);\n    temp2 = _mm_add_epi16(temp1, temp2);\n    in_macro_16x8 = _mm_srai_epi16(temp2, 1);\n\n    temp1 = _mm_avg_epu16(_mm_unpackhi_epi8(q0_16x8, zero),\n                          _mm_unpackhi_epi8(p0_16x8, zero));\n    temp2 = _mm_slli_epi16(_mm_unpackhi_epi8(q1_16x8, zero), 1);\n    //temp2 = _mm_slli_epi16 (temp2, 1);\n    temp2 = _mm_subs_epi16(_mm_unpackhi_epi8(q2_16x8, zero), temp2);\n    temp2 = _mm_add_epi16(temp1, temp2);\n    in_macro_hi_16x8 = _mm_srai_epi16(temp2, 1);\n\n    in_macro_16x8 = _mm_max_epi16(C0_8x16, in_macro_16x8); //CLIP3\n    in_macro_hi_16x8 = _mm_max_epi16(C0_hi_8x16, in_macro_hi_16x8); //CLIP3\n    C0_8x16 = _mm_subs_epi16(zero, C0_8x16);\n    C0_hi_8x16 = _mm_subs_epi16(zero, C0_hi_8x16);\n    in_macro_16x8 = _mm_min_epi16(C0_8x16, in_macro_16x8); //CLIP3\n    in_macro_hi_16x8 = _mm_min_epi16(C0_hi_8x16, in_macro_hi_16x8); //CLIP3\n\n    temp1 = _mm_add_epi16(_mm_unpacklo_epi8(q1_16x8, zero), in_macro_16x8);\n    temp2 = _mm_add_epi16(_mm_unpackhi_epi8(q1_16x8, zero), in_macro_hi_16x8);\n\n    temp1 = _mm_packus_epi16(temp1, temp2);\n\n    temp1 = _mm_and_si128(temp1, flag3_16x8);\n    temp2 = _mm_and_si128(q1_16x8,\n                          _mm_xor_si128(flag3_16x8, _mm_set1_epi16(0xFFFF)));\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    _mm_storeu_si128((__m128i *)(pu1_src + i16_posQ1), temp1);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_vert_bs4_mbaff_ssse3()                  */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  vertical edge when boundary strength is set to 4.        */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0             */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : When the function is called twice, this operation is as  */\n/*                  described in Sec. 8.7.2.3 under the title \"Filtering     */\n/*                  process for edges for bS equal to 4\" in ITU T Rec H.264. */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_deblk_luma_vert_bs4_mbaff_ssse3(UWORD8 *pu1_src,\n                                           WORD32 src_strd,\n                                           WORD32 alpha,\n                                           WORD32 beta)\n{\n    __m128i zero = _mm_setzero_si128();\n    __m128i q0_16x8, q1_16x8, q2_16x8, q3_16x8;\n    __m128i p0_16x8, p1_16x8, p2_16x8, p3_16x8;\n    __m128i q0_8x16, q1_8x16, q2_8x16, q3_8x16;\n    __m128i p0_8x16, p1_8x16, p2_8x16, p3_8x16;\n    __m128i q0_16x8_1;\n    __m128i p0_16x8_1;\n    __m128i q0_16x8_2, q1_16x8_2, q2_16x8_2;\n    __m128i p0_16x8_2, p1_16x8_2, p2_16x8_2;\n    __m128i temp1, temp2, temp3, temp4, temp5, temp6;\n    __m128i Alpha_8x16, Beta_8x16;\n    __m128i flag1_16x8, flag2_16x8, flag3_16x8, flag4_16x8;\n    __m128i const_val2_16x8 = _mm_set1_epi16(2);\n    __m128i line1, line2, line3, line4, line5, line6, line7, line8;\n\n    Alpha_8x16 = _mm_set1_epi16(alpha);\n    Beta_8x16 = _mm_set1_epi16(beta);\n\n    line1 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 0 * src_strd));\n    line2 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 1 * src_strd));\n    line3 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 2 * src_strd));\n    line4 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 3 * src_strd));\n    line5 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 4 * src_strd));\n    line6 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 5 * src_strd));\n    line7 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 6 * src_strd));\n    line8 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 7 * src_strd));\n\n    temp1 = _mm_unpacklo_epi8(line1, line2);\n    temp2 = _mm_unpacklo_epi8(line3, line4);\n    temp3 = _mm_unpacklo_epi8(line5, line6);\n    temp4 = _mm_unpacklo_epi8(line7, line8);\n\n    line1 = _mm_unpacklo_epi16(temp1, temp2);\n    line2 = _mm_unpackhi_epi16(temp1, temp2);\n    line3 = _mm_unpacklo_epi16(temp3, temp4);\n    line4 = _mm_unpackhi_epi16(temp3, temp4);\n\n    p1_8x16 = _mm_unpacklo_epi32(line1, line3);\n    p0_8x16 = _mm_unpackhi_epi32(line1, line3);\n    q0_8x16 = _mm_unpacklo_epi32(line2, line4);\n    q1_8x16 = _mm_unpackhi_epi32(line2, line4);\n\n    p3_16x8 = _mm_unpacklo_epi64(p1_8x16, zero);\n    p2_16x8 = _mm_unpackhi_epi64(p1_8x16, zero);\n    q2_16x8 = _mm_unpacklo_epi64(q1_8x16, zero);\n    q3_16x8 = _mm_unpackhi_epi64(q1_8x16, zero);\n    p1_16x8 = _mm_unpacklo_epi64(p0_8x16, zero);\n    p0_16x8 = _mm_unpackhi_epi64(p0_8x16, zero);\n    q0_16x8 = _mm_unpacklo_epi64(q0_8x16, zero);\n    q1_16x8 = _mm_unpackhi_epi64(q0_8x16, zero);\n\n    //Cond1 (ABS(p0 - q0) < alpha)\n    temp1 = _mm_subs_epu8(q0_16x8, p0_16x8);\n    temp2 = _mm_subs_epu8(p0_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Alpha_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Alpha_8x16, temp1);\n\n    flag1_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    //Cond2 (ABS(q1 - q0) < beta)\n    temp1 = _mm_subs_epu8(q0_16x8, q1_16x8);\n    temp2 = _mm_subs_epu8(q1_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    flag1_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    //Cond3 (ABS(p1 - p0) < beta)\n    temp1 = _mm_subs_epu8(p0_16x8, p1_16x8);\n    temp2 = _mm_subs_epu8(p1_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n\n    // !((ABS(p0 - q0) < alpha) || (ABS(q1 - q0) < beta) || (ABS(p1 - p0) < beta))\n    flag1_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    // (ABS(p0 - q0) < ((alpha >> 2) + 2))\n    temp1 = _mm_subs_epu8(p0_16x8, q0_16x8);\n    temp2 = _mm_subs_epu8(q0_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n    Alpha_8x16 = _mm_srai_epi16(Alpha_8x16, 2);\n    Alpha_8x16 = _mm_add_epi16(Alpha_8x16, const_val2_16x8);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Alpha_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Alpha_8x16, temp1);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag2_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    // (ABS(p2 - p0) < beta)\n    temp1 = _mm_subs_epu8(p0_16x8, p2_16x8);\n    temp2 = _mm_subs_epu8(p2_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag3_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag3_16x8 = _mm_and_si128(flag3_16x8, flag2_16x8);\n\n    // (ABS(q2 - q0) < beta)\n    temp1 = _mm_subs_epu8(q0_16x8, q2_16x8);\n    temp2 = _mm_subs_epu8(q2_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp1 = _mm_unpackhi_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n    temp1 = _mm_cmpgt_epi16(Beta_8x16, temp1);\n\n    flag4_16x8 = _mm_packs_epi16(temp2, temp1);\n    flag4_16x8 = _mm_and_si128(flag4_16x8, flag2_16x8);\n\n    // First 8 pixels\n    p3_8x16 = _mm_unpacklo_epi8(p3_16x8, zero);\n    p2_8x16 = _mm_unpacklo_epi8(p2_16x8, zero);\n    p1_8x16 = _mm_unpacklo_epi8(p1_16x8, zero);\n    p0_8x16 = _mm_unpacklo_epi8(p0_16x8, zero);\n    q0_8x16 = _mm_unpacklo_epi8(q0_16x8, zero);\n    q1_8x16 = _mm_unpacklo_epi8(q1_16x8, zero);\n    q2_8x16 = _mm_unpacklo_epi8(q2_16x8, zero);\n    q3_8x16 = _mm_unpacklo_epi8(q3_16x8, zero);\n\n    // p0_1 and q0_1\n    temp1 = _mm_add_epi16(p0_8x16, q1_8x16);\n    temp2 = _mm_add_epi16(p1_8x16, q0_8x16);\n    temp5 = _mm_add_epi16(temp1, const_val2_16x8);\n    temp6 = _mm_add_epi16(temp2, const_val2_16x8);\n    temp3 = _mm_slli_epi16(p1_8x16, 1);\n    temp4 = _mm_slli_epi16(q1_8x16, 1);\n    temp1 = _mm_add_epi16(temp5, temp3);\n    temp2 = _mm_add_epi16(temp6, temp4);\n    p0_16x8_1 = _mm_srai_epi16(temp1, 2);\n    q0_16x8_1 = _mm_srai_epi16(temp2, 2);\n\n    // p1_2 and q1_2\n    temp6 = _mm_add_epi16(temp6, p0_8x16);\n    temp5 = _mm_add_epi16(temp5, q0_8x16);\n    temp1 = _mm_add_epi16(temp6, p2_8x16);\n    temp2 = _mm_add_epi16(temp5, q2_8x16);\n    p1_16x8_2 = _mm_srai_epi16(temp1, 2);\n    q1_16x8_2 = _mm_srai_epi16(temp2, 2);\n\n    // p0_2 and q0_2\n    temp1 = _mm_add_epi16(temp3, p2_8x16);\n    temp2 = _mm_add_epi16(temp4, q2_8x16);\n    temp1 = _mm_add_epi16(temp1, q1_8x16);\n    temp2 = _mm_add_epi16(temp2, p1_8x16);\n    temp3 = _mm_add_epi16(p0_8x16, q0_8x16);\n    temp3 = _mm_slli_epi16(temp3, 1);\n    temp1 = _mm_add_epi16(temp1, temp3);\n    temp2 = _mm_add_epi16(temp2, temp3);\n    temp1 = _mm_add_epi16(temp1, _mm_set1_epi16(4));\n    temp2 = _mm_add_epi16(temp2, _mm_set1_epi16(4));\n    p0_16x8_2 = _mm_srai_epi16(temp1, 3);\n    q0_16x8_2 = _mm_srai_epi16(temp2, 3);\n\n    // p2_2 and q2_2\n    temp1 = _mm_add_epi16(temp6, const_val2_16x8);\n    temp2 = _mm_add_epi16(temp5, const_val2_16x8);\n    temp3 = _mm_slli_epi16(p2_8x16, 1);\n    temp4 = _mm_slli_epi16(q2_8x16, 1);\n    temp3 = _mm_add_epi16(p2_8x16, temp3);\n    temp4 = _mm_add_epi16(q2_8x16, temp4);\n    temp5 = _mm_slli_epi16(p3_8x16, 1);\n    temp6 = _mm_slli_epi16(q3_8x16, 1);\n    temp1 = _mm_add_epi16(temp1, temp3);\n    temp2 = _mm_add_epi16(temp2, temp4);\n    temp1 = _mm_add_epi16(temp1, temp5);\n    temp2 = _mm_add_epi16(temp2, temp6);\n    p2_16x8_2 = _mm_srai_epi16(temp1, 3);\n    q2_16x8_2 = _mm_srai_epi16(temp2, 3);\n\n    // p0_1 and q0_1\n    p0_16x8_1 = _mm_packus_epi16(p0_16x8_1, zero);\n    q0_16x8_1 = _mm_packus_epi16(q0_16x8_1, zero);\n\n    // p1_2 and q1_2\n    p1_16x8_2 = _mm_packus_epi16(p1_16x8_2, zero);\n    q1_16x8_2 = _mm_packus_epi16(q1_16x8_2, zero);\n\n    // p0_2 and q0_2\n    p0_16x8_2 = _mm_packus_epi16(p0_16x8_2, zero);\n    q0_16x8_2 = _mm_packus_epi16(q0_16x8_2, zero);\n\n    // p2_2 and q2_2\n    p2_16x8_2 = _mm_packus_epi16(p2_16x8_2, zero);\n    q2_16x8_2 = _mm_packus_epi16(q2_16x8_2, zero);\n\n    // p0 and q0\n    p0_16x8 = _mm_and_si128(p0_16x8,\n                            _mm_xor_si128(flag1_16x8, _mm_set1_epi8(0xFF)));\n    p0_16x8_1 = _mm_and_si128(p0_16x8_1, flag1_16x8);\n    p0_16x8 = _mm_add_epi8(p0_16x8, p0_16x8_1);\n    q0_16x8 = _mm_and_si128(q0_16x8,\n                            _mm_xor_si128(flag1_16x8, _mm_set1_epi8(0xFF)));\n    q0_16x8_1 = _mm_and_si128(q0_16x8_1, flag1_16x8);\n    q0_16x8 = _mm_add_epi8(q0_16x8, q0_16x8_1);\n\n    // p0 and q0\n    p0_16x8 = _mm_and_si128(p0_16x8,\n                            _mm_xor_si128(flag3_16x8, _mm_set1_epi8(0xFF)));\n    p0_16x8_2 = _mm_and_si128(p0_16x8_2, flag3_16x8);\n    p0_16x8 = _mm_add_epi8(p0_16x8, p0_16x8_2);\n    q0_16x8 = _mm_and_si128(q0_16x8,\n                            _mm_xor_si128(flag4_16x8, _mm_set1_epi8(0xFF)));\n    q0_16x8_2 = _mm_and_si128(q0_16x8_2, flag4_16x8);\n    q0_16x8 = _mm_add_epi8(q0_16x8, q0_16x8_2);\n\n    // p1 and q1\n    p1_16x8 = _mm_and_si128(p1_16x8,\n                            _mm_xor_si128(flag3_16x8, _mm_set1_epi8(0xFF)));\n    p1_16x8_2 = _mm_and_si128(p1_16x8_2, flag3_16x8);\n    p1_16x8 = _mm_add_epi8(p1_16x8, p1_16x8_2);\n    q1_16x8 = _mm_and_si128(q1_16x8,\n                            _mm_xor_si128(flag4_16x8, _mm_set1_epi8(0xFF)));\n    q1_16x8_2 = _mm_and_si128(q1_16x8_2, flag4_16x8);\n    q1_16x8 = _mm_add_epi8(q1_16x8, q1_16x8_2);\n\n    // p2 and q2\n    p2_16x8 = _mm_and_si128(p2_16x8,\n                            _mm_xor_si128(flag3_16x8, _mm_set1_epi8(0xFF)));\n    p2_16x8_2 = _mm_and_si128(p2_16x8_2, flag3_16x8);\n    p2_16x8 = _mm_add_epi8(p2_16x8, p2_16x8_2);\n    q2_16x8 = _mm_and_si128(q2_16x8,\n                            _mm_xor_si128(flag4_16x8, _mm_set1_epi8(0xFF)));\n    q2_16x8_2 = _mm_and_si128(q2_16x8_2, flag4_16x8);\n    q2_16x8 = _mm_add_epi8(q2_16x8, q2_16x8_2);\n\n    temp1 = _mm_unpacklo_epi8(p3_16x8, p2_16x8);\n    temp2 = _mm_unpacklo_epi8(p1_16x8, p0_16x8);\n    temp3 = _mm_unpacklo_epi8(q0_16x8, q1_16x8);\n    temp4 = _mm_unpacklo_epi8(q2_16x8, q3_16x8);\n\n    p3_8x16 = _mm_unpacklo_epi16(temp1, temp2);\n    p2_8x16 = _mm_unpackhi_epi16(temp1, temp2);\n    q2_8x16 = _mm_unpacklo_epi16(temp3, temp4);\n    q3_8x16 = _mm_unpackhi_epi16(temp3, temp4);\n\n    line1 = _mm_unpacklo_epi32(p3_8x16, q2_8x16);\n    line2 = _mm_srli_si128(line1, 8);\n    line3 = _mm_unpackhi_epi32(p3_8x16, q2_8x16);\n    line4 = _mm_srli_si128(line3, 8);\n    line5 = _mm_unpacklo_epi32(p2_8x16, q3_8x16);\n    line6 = _mm_srli_si128(line5, 8);\n    line7 = _mm_unpackhi_epi32(p2_8x16, q3_8x16);\n    line8 = _mm_srli_si128(line7, 8);\n\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 0 * src_strd), line1);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 1 * src_strd), line2);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 2 * src_strd), line3);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 3 * src_strd), line4);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 4 * src_strd), line5);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 5 * src_strd), line6);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 6 * src_strd), line7);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 7 * src_strd), line8);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_deblk_luma_vert_bslt4_mbaff_ssse3()                */\n/*                                                                           */\n/*  Description   : This function performs filtering of a luma block         */\n/*                  vertical edge when boundary strength is less than 4.     */\n/*                                                                           */\n/*  Inputs        : pu1_src       - pointer to the src sample q0             */\n/*                  src_strd      - source stride                            */\n/*                  alpha         - alpha value for the boundary             */\n/*                  beta          - beta value for the boundary              */\n/*                  u4_bs         - packed Boundary strength array           */\n/*                  pu1_cliptab   - tc0_table                                */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Processing    : When the function is called twice, this operation is as  */\n/*                  described in Sec. 8.7.2.3 under the title \"Filtering     */\n/*                  process for edges for bS less than 4\" in ITU T Rec H.264.*/\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         12 02 2015   Naveen Kumar P  Initial version                      */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_deblk_luma_vert_bslt4_mbaff_ssse3(UWORD8 *pu1_src,\n                                             WORD32 src_strd,\n                                             WORD32 alpha,\n                                             WORD32 beta,\n                                             UWORD32 u4_bs,\n                                             const UWORD8 *pu1_cliptab)\n{\n    __m128i zero = _mm_setzero_si128();\n    __m128i bs_flag_16x8b, C0_16x8, C0_8x16, C_8x16;\n    __m128i q0_16x8, q1_16x8, q2_16x8, q3_16x8;\n    __m128i p0_16x8, p1_16x8, p2_16x8, p3_16x8;\n    __m128i temp1, temp2, temp3, temp4;\n    __m128i Alpha_8x16, Beta_8x16, flag1_16x8, flag2_16x8, flag3_16x8;\n    __m128i in_macro_16x8;\n    __m128i const_val4_8x16;\n    UWORD8 u1_Bs0, u1_Bs1, u1_Bs2, u1_Bs3;\n    UWORD8 clip0, clip1, clip2, clip3;\n    __m128i line1, line2, line3, line4, line5, line6, line7, line8;\n    __m128i q0_16x8_1, q1_16x8_1, q0_16x8_2;\n    __m128i p0_16x8_1, p1_16x8_1, p0_16x8_2;\n\n    line1 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 0 * src_strd));\n    line2 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 1 * src_strd));\n    line3 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 2 * src_strd));\n    line4 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 3 * src_strd));\n    line5 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 4 * src_strd));\n    line6 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 5 * src_strd));\n    line7 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 6 * src_strd));\n    line8 = _mm_loadl_epi64((__m128i *)(pu1_src - 4 + 7 * src_strd));\n\n    temp1 = _mm_unpacklo_epi8(line1, line2);\n    temp2 = _mm_unpacklo_epi8(line3, line4);\n    temp3 = _mm_unpacklo_epi8(line5, line6);\n    temp4 = _mm_unpacklo_epi8(line7, line8);\n\n    line1 = _mm_unpacklo_epi16(temp1, temp2);\n    line2 = _mm_unpackhi_epi16(temp1, temp2);\n    line3 = _mm_unpacklo_epi16(temp3, temp4);\n    line4 = _mm_unpackhi_epi16(temp3, temp4);\n\n    temp1 = _mm_unpacklo_epi32(line1, line3);\n    temp2 = _mm_unpackhi_epi32(line1, line3);\n    temp3 = _mm_unpacklo_epi32(line2, line4);\n    temp4 = _mm_unpackhi_epi32(line2, line4);\n\n    p3_16x8 = _mm_unpacklo_epi64(temp1, zero);\n    p2_16x8 = _mm_unpackhi_epi64(temp1, zero);\n    q2_16x8 = _mm_unpacklo_epi64(temp4, zero);\n    q3_16x8 = _mm_unpackhi_epi64(temp4, zero);\n    p1_16x8 = _mm_unpacklo_epi64(temp2, zero);\n    p0_16x8 = _mm_unpackhi_epi64(temp2, zero);\n    q0_16x8 = _mm_unpacklo_epi64(temp3, zero);\n    q1_16x8 = _mm_unpackhi_epi64(temp3, zero);\n\n    u1_Bs0 = (u4_bs >> 24) & 0xff;\n    u1_Bs1 = (u4_bs >> 16) & 0xff;\n    u1_Bs2 = (u4_bs >> 8) & 0xff;\n    u1_Bs3 = (u4_bs >> 0) & 0xff;\n    clip0 = pu1_cliptab[u1_Bs0];\n    clip1 = pu1_cliptab[u1_Bs1];\n    clip2 = pu1_cliptab[u1_Bs2];\n    clip3 = pu1_cliptab[u1_Bs3];\n\n    Alpha_8x16 = _mm_set1_epi16(alpha);\n    Beta_8x16 = _mm_set1_epi16(beta);\n\n    bs_flag_16x8b = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, u1_Bs3, u1_Bs3, u1_Bs2,\n                                 u1_Bs2, u1_Bs1, u1_Bs1, u1_Bs0, u1_Bs0);\n\n    C0_16x8 = _mm_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, clip3, clip3, clip2, clip2,\n                           clip1, clip1, clip0, clip0);\n\n    bs_flag_16x8b = _mm_cmpeq_epi8(bs_flag_16x8b, zero);\n    bs_flag_16x8b = _mm_xor_si128(bs_flag_16x8b, _mm_set1_epi8(0xFF)); //Invert for required mask\n    C0_8x16 = _mm_unpacklo_epi8(C0_16x8, zero);\n\n    //Cond1 (ABS(p0 - q0) < alpha)\n    temp1 = _mm_subs_epu8(q0_16x8, p0_16x8);\n    temp2 = _mm_subs_epu8(p0_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Alpha_8x16, temp2);\n\n    flag1_16x8 = _mm_packs_epi16(temp2, zero);\n    flag1_16x8 = _mm_and_si128(flag1_16x8, bs_flag_16x8b);\n\n    //Cond2 (ABS(q1 - q0) < beta)\n    temp1 = _mm_subs_epu8(q0_16x8, q1_16x8);\n    temp2 = _mm_subs_epu8(q1_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, zero);\n    flag1_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    //Cond3 (ABS(p1 - p0) < beta)\n    temp1 = _mm_subs_epu8(p0_16x8, p1_16x8);\n    temp2 = _mm_subs_epu8(p1_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, zero);\n\n    // !((ABS(p0 - q0) < alpha) || (ABS(q1 - q0) < beta) || (ABS(p1 - p0) < beta))\n    flag1_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    // (ABS(p2 - p0) < beta)\n    temp1 = _mm_subs_epu8(p0_16x8, p2_16x8);\n    temp2 = _mm_subs_epu8(p2_16x8, p0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n\n    flag2_16x8 = _mm_packs_epi16(temp2, zero);\n    flag2_16x8 = _mm_and_si128(flag1_16x8, flag2_16x8);\n\n    temp2 = _mm_subs_epi16(zero, temp2);\n\n    C_8x16 = _mm_add_epi16(C0_8x16, temp2);\n\n    // (ABS(q2 - q0) < beta)\n    temp1 = _mm_subs_epu8(q0_16x8, q2_16x8);\n    temp2 = _mm_subs_epu8(q2_16x8, q0_16x8);\n    temp1 = _mm_add_epi8(temp1, temp2);\n\n    temp2 = _mm_unpacklo_epi8(temp1, zero);\n    temp2 = _mm_cmpgt_epi16(Beta_8x16, temp2);\n\n    flag3_16x8 = _mm_packs_epi16(temp2, zero);\n    flag3_16x8 = _mm_and_si128(flag1_16x8, flag3_16x8);\n\n    temp2 = _mm_subs_epi16(zero, temp2);\n\n    C_8x16 = _mm_add_epi16(C_8x16, temp2);\n\n    const_val4_8x16 = _mm_set1_epi16(4);\n    temp1 = _mm_subs_epi16(_mm_unpacklo_epi8(q0_16x8, zero),\n                           _mm_unpacklo_epi8(p0_16x8, zero));\n    temp2 = _mm_subs_epi16(_mm_unpacklo_epi8(p1_16x8, zero),\n                           _mm_unpacklo_epi8(q1_16x8, zero));\n    temp1 = _mm_slli_epi16(temp1, 2);\n    temp1 = _mm_add_epi16(temp1, temp2);\n    temp1 = _mm_add_epi16(temp1, const_val4_8x16);\n    in_macro_16x8 = _mm_srai_epi16(temp1, 3);\n\n    in_macro_16x8 = _mm_min_epi16(C_8x16, in_macro_16x8); //CLIP3\n    C_8x16 = _mm_subs_epi16(zero, C_8x16);\n    in_macro_16x8 = _mm_max_epi16(C_8x16, in_macro_16x8); //CLIP3\n\n    // p0\n    temp1 = _mm_add_epi16(_mm_unpacklo_epi8(p0_16x8, zero), in_macro_16x8);\n\n    temp1 = _mm_packus_epi16(temp1, zero);\n\n    p0_16x8_1 = _mm_and_si128(temp1, flag1_16x8);\n    p0_16x8_2 = _mm_and_si128(\n                    p0_16x8, _mm_xor_si128(flag1_16x8, _mm_set1_epi16(0xFFFF)));\n\n    p0_16x8_1 = _mm_add_epi8(p0_16x8_1, p0_16x8_2);\n\n    // q0\n    temp1 = _mm_sub_epi16(_mm_unpacklo_epi8(q0_16x8, zero), in_macro_16x8);\n\n    temp1 = _mm_packus_epi16(temp1, zero);\n\n    q0_16x8_1 = _mm_and_si128(temp1, flag1_16x8);\n    q0_16x8_2 = _mm_and_si128(\n                    q0_16x8, _mm_xor_si128(flag1_16x8, _mm_set1_epi16(0xFFFF)));\n\n    q0_16x8_1 = _mm_add_epi8(q0_16x8_1, q0_16x8_2);\n\n    //if(Ap < Beta)\n    temp1 = _mm_avg_epu16(_mm_unpacklo_epi8(q0_16x8, zero),\n                          _mm_unpacklo_epi8(p0_16x8, zero));\n    temp2 = _mm_slli_epi16(_mm_unpacklo_epi8(p1_16x8, zero), 1);\n    //temp2 = _mm_subs_epi16(zero,temp2);\n    temp2 = _mm_subs_epi16(_mm_unpacklo_epi8(p2_16x8, zero), temp2);\n    temp2 = _mm_add_epi16(temp1, temp2);\n    in_macro_16x8 = _mm_srai_epi16(temp2, 1);\n\n    in_macro_16x8 = _mm_min_epi16(C0_8x16, in_macro_16x8); //CLIP3\n    C0_8x16 = _mm_subs_epi16(zero, C0_8x16);\n    in_macro_16x8 = _mm_max_epi16(C0_8x16, in_macro_16x8); //CLIP3\n\n    // p1\n    temp1 = _mm_add_epi16(_mm_unpacklo_epi8(p1_16x8, zero), in_macro_16x8);\n\n    temp1 = _mm_packus_epi16(temp1, zero);\n\n    p1_16x8_1 = _mm_and_si128(temp1, flag2_16x8);\n    p1_16x8 = _mm_and_si128(p1_16x8,\n                            _mm_xor_si128(flag2_16x8, _mm_set1_epi16(0xFFFF)));\n    p1_16x8 = _mm_add_epi8(p1_16x8, p1_16x8_1);\n\n    //if(Aq < Beta)\n    temp1 = _mm_avg_epu16(_mm_unpacklo_epi8(q0_16x8, zero),\n                          _mm_unpacklo_epi8(p0_16x8, zero));\n    temp2 = _mm_slli_epi16(_mm_unpacklo_epi8(q1_16x8, zero), 1);\n    //temp2 = _mm_slli_epi16 (temp2, 1);\n    temp2 = _mm_subs_epi16(_mm_unpacklo_epi8(q2_16x8, zero), temp2);\n    temp2 = _mm_add_epi16(temp1, temp2);\n    in_macro_16x8 = _mm_srai_epi16(temp2, 1);\n\n    in_macro_16x8 = _mm_max_epi16(C0_8x16, in_macro_16x8); //CLIP3\n    C0_8x16 = _mm_subs_epi16(zero, C0_8x16);\n    in_macro_16x8 = _mm_min_epi16(C0_8x16, in_macro_16x8); //CLIP3\n\n    temp1 = _mm_add_epi16(_mm_unpacklo_epi8(q1_16x8, zero), in_macro_16x8);\n\n    // q1\n    temp1 = _mm_packus_epi16(temp1, zero);\n\n    q1_16x8_1 = _mm_and_si128(temp1, flag3_16x8);\n    q1_16x8 = _mm_and_si128(q1_16x8,\n                            _mm_xor_si128(flag3_16x8, _mm_set1_epi16(0xFFFF)));\n    q1_16x8 = _mm_add_epi8(q1_16x8, q1_16x8_1);\n\n    temp1 = _mm_unpacklo_epi8(p3_16x8, p2_16x8);\n    temp2 = _mm_unpacklo_epi8(p1_16x8, p0_16x8_1);\n    temp3 = _mm_unpacklo_epi8(q0_16x8_1, q1_16x8);\n    temp4 = _mm_unpacklo_epi8(q2_16x8, q3_16x8);\n\n    line7 = _mm_unpacklo_epi16(temp1, temp2);\n    temp1 = _mm_unpackhi_epi16(temp1, temp2);\n    line8 = _mm_unpacklo_epi16(temp3, temp4);\n    temp2 = _mm_unpackhi_epi16(temp3, temp4);\n\n    line1 = _mm_unpacklo_epi32(line7, line8);\n    line2 = _mm_srli_si128(line1, 8);\n    line3 = _mm_unpackhi_epi32(line7, line8);\n    line4 = _mm_srli_si128(line3, 8);\n    line5 = _mm_unpacklo_epi32(temp1, temp2);\n    line6 = _mm_srli_si128(line5, 8);\n    line7 = _mm_unpackhi_epi32(temp1, temp2);\n    line8 = _mm_srli_si128(line7, 8);\n\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 0 * src_strd), line1);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 1 * src_strd), line2);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 2 * src_strd), line3);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 3 * src_strd), line4);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 4 * src_strd), line5);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 5 * src_strd), line6);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 6 * src_strd), line7);\n    _mm_storel_epi64((__m128i *)(pu1_src - 4 + 7 * src_strd), line8);\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_ihadamard_scaling_sse42.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_ihadamard_scaling_sse42.c\n *\n * @brief\n *  Contains definition of functions for h264 inverse hadamard 4x4 transform and scaling\n *\n * @author\n *  Mohit\n *\n *  @par List of Functions:\n *  - ih264_ihadamard_scaling_4x4_sse42()\n *  - ih264_ihadamard_scaling_2x2_uv_ssse42()\n *\n * @remarks\n *\n *******************************************************************************\n */\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_trans_macros.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_trans_data.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include <immintrin.h>\n#include <smmintrin.h>\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSE42 __attribute__((target(\"sse4.2\")))\n#else\n#define ATTRIBUTE_SSE42\n#endif\n\n/*\n ********************************************************************************\n *\n * @brief This function performs a 4x4 inverse hadamard transform on the 4x4 DC coefficients\n * of a 16x16 intra prediction macroblock, and then performs scaling.\n * prediction buffer\n *\n * @par Description:\n *  The DC coefficients pass through a 2-stage inverse hadamard transform.\n *  This inverse transformed content is scaled to based on Qp value.\n *\n * @param[in] pi2_src\n *  input 4x4 block of DC coefficients\n *\n * @param[out] pi2_out\n *  output 4x4 block\n *\n * @param[in] pu2_iscal_mat\n *  pointer to scaling list\n *\n * @param[in] pu2_weigh_mat\n *  pointer to weight matrix\n *\n * @param[in] u4_qp_div_6\n *  Floor (qp/6)\n *\n * @param[in] pi4_tmp\n * temporary buffer of size 1*16\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nATTRIBUTE_SSE42\nvoid ih264_ihadamard_scaling_4x4_sse42(WORD16* pi2_src,\n                                       WORD16* pi2_out,\n                                       const UWORD16 *pu2_iscal_mat,\n                                       const UWORD16 *pu2_weigh_mat,\n                                       UWORD32 u4_qp_div_6,\n                                       WORD32* pi4_tmp)\n{\n    __m128i src_r0_r1, src_r2_r3;\n    __m128i src_r0, src_r1, src_r2, src_r3;\n    __m128i temp0, temp1, temp2, temp3;\n    __m128i add_rshift = _mm_set1_epi32((u4_qp_div_6 < 6) ? (1 << (5 - u4_qp_div_6)) : 0);\n    __m128i mult_val = _mm_set1_epi32(pu2_iscal_mat[0] * pu2_weigh_mat[0]);\n    UNUSED (pi4_tmp);\n\n    src_r0_r1 = _mm_loadu_si128((__m128i *) (pi2_src)); //a00 a01 a02 a03 a10 a11 a12 a13 -- the source matrix 0th,1st row\n    src_r2_r3 = _mm_loadu_si128((__m128i *) (pi2_src + 8)); //a20 a21 a22 a23 a30 a31 a32 a33 -- the source matrix 2nd,3rd row\n    //sign_reg = _mm_cmpgt_epi16(zero_8x16b, src_r0_r1);\n    src_r0 = _mm_cvtepi16_epi32(src_r0_r1);\n    src_r0_r1 = _mm_srli_si128(src_r0_r1, 8);\n    src_r1 = _mm_cvtepi16_epi32(src_r0_r1);\n\n    src_r2 = _mm_cvtepi16_epi32(src_r2_r3);\n    src_r2_r3 = _mm_srli_si128(src_r2_r3, 8);\n    src_r3 = _mm_cvtepi16_epi32(src_r2_r3);\n\n    /* Perform Inverse transform */\n    /*-------------------------------------------------------------*/\n    /* IDCT [ Horizontal transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 a1 a2 a3\n     *  b0 b1 b2 b3\n     *  c0 c1 c2 c3\n     *  d0 d1 d2 d3\n     */\n    temp0 = _mm_unpacklo_epi32(src_r0, src_r1);                  //a0 b0 a1 b1\n    temp2 = _mm_unpacklo_epi32(src_r2, src_r3);                  //c0 d0 c1 d1\n    temp1 = _mm_unpackhi_epi32(src_r0, src_r1);                  //a2 b2 a3 b3\n    temp3 = _mm_unpackhi_epi32(src_r2, src_r3);                  //c2 d2 c3 d3\n    src_r0 = _mm_unpacklo_epi64(temp0, temp2);                    //a0 b0 c0 d0\n    src_r1 = _mm_unpackhi_epi64(temp0, temp2);                    //a1 b1 c1 d1\n    src_r2 = _mm_unpacklo_epi64(temp1, temp3);                    //a2 b2 c2 d2\n    src_r3 = _mm_unpackhi_epi64(temp1, temp3);                    //a3 b3 c3 d3\n\n    temp0 = _mm_add_epi32(src_r0, src_r3);\n    temp1 = _mm_add_epi32(src_r1, src_r2);\n    temp2 = _mm_sub_epi32(src_r1, src_r2);\n    temp3 = _mm_sub_epi32(src_r0, src_r3);\n\n    src_r0 = _mm_add_epi32(temp0, temp1);\n    src_r1 = _mm_add_epi32(temp2, temp3);\n    src_r2 = _mm_sub_epi32(temp0, temp1);\n    src_r3 = _mm_sub_epi32(temp3, temp2);\n\n    /*-------------------------------------------------------------*/\n    /* IDCT [ Vertical transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 b0 c0 d0\n     *  a1 b1 c1 d1\n     *  a2 b2 c2 d2\n     *  a3 b3 c3 d3\n     */\n    temp0 = _mm_unpacklo_epi32(src_r0, src_r1);                  //a0 a1 b0 b1\n    temp2 = _mm_unpacklo_epi32(src_r2, src_r3);                  //a2 a3 b2 b3\n    temp1 = _mm_unpackhi_epi32(src_r0, src_r1);                  //c0 c1 d0 d1\n    temp3 = _mm_unpackhi_epi32(src_r2, src_r3);                  //c2 c3 d2 d3\n    src_r0 = _mm_unpacklo_epi64(temp0, temp2);                   //a0 a1 a2 a3\n    src_r1 = _mm_unpackhi_epi64(temp0, temp2);                   //b0 b1 b2 b3\n    src_r2 = _mm_unpacklo_epi64(temp1, temp3);                   //c0 c1 c2 c3\n    src_r3 = _mm_unpackhi_epi64(temp1, temp3);                   //d0 d1 d2 d3\n\n    temp0 = _mm_add_epi32(src_r0, src_r3);\n    temp1 = _mm_add_epi32(src_r1, src_r2);\n    temp2 = _mm_sub_epi32(src_r1, src_r2);\n    temp3 = _mm_sub_epi32(src_r0, src_r3);\n\n    src_r0 = _mm_add_epi32(temp0, temp1);\n    src_r1 = _mm_add_epi32(temp2, temp3);\n    src_r2 = _mm_sub_epi32(temp0, temp1);\n    src_r3 = _mm_sub_epi32(temp3, temp2);\n\n    src_r0 = _mm_mullo_epi32(src_r0, mult_val);\n    src_r1 = _mm_mullo_epi32(src_r1, mult_val);\n    src_r2 = _mm_mullo_epi32(src_r2, mult_val);\n    src_r3 = _mm_mullo_epi32(src_r3, mult_val);\n\n    //Scaling\n    if(u4_qp_div_6 >= 6)\n    {\n        src_r0 = _mm_slli_epi32(src_r0, u4_qp_div_6 - 6);\n        src_r1 = _mm_slli_epi32(src_r1, u4_qp_div_6 - 6);\n        src_r2 = _mm_slli_epi32(src_r2, u4_qp_div_6 - 6);\n        src_r3 = _mm_slli_epi32(src_r3, u4_qp_div_6 - 6);\n    }\n    else\n    {\n        temp0 = _mm_add_epi32(src_r0, add_rshift);\n        temp1 = _mm_add_epi32(src_r1, add_rshift);\n        temp2 = _mm_add_epi32(src_r2, add_rshift);\n        temp3 = _mm_add_epi32(src_r3, add_rshift);\n        src_r0 = _mm_srai_epi32(temp0, 6 - u4_qp_div_6);\n        src_r1 = _mm_srai_epi32(temp1, 6 - u4_qp_div_6);\n        src_r2 = _mm_srai_epi32(temp2, 6 - u4_qp_div_6);\n        src_r3 = _mm_srai_epi32(temp3, 6 - u4_qp_div_6);\n    }\n    src_r0_r1 = _mm_packs_epi32(src_r0, src_r1);\n    src_r2_r3 = _mm_packs_epi32(src_r2, src_r3);\n\n    _mm_storeu_si128((__m128i *) (&pi2_out[0]), src_r0_r1);\n    _mm_storeu_si128((__m128i *) (&pi2_out[8]), src_r2_r3);\n}\n\nATTRIBUTE_SSE42\nvoid ih264_ihadamard_scaling_2x2_uv_sse42(WORD16* pi2_src,\n                                          WORD16* pi2_out,\n                                          const UWORD16 *pu2_iscal_mat,\n                                          const UWORD16 *pu2_weigh_mat,\n                                          UWORD32 u4_qp_div_6,\n                                          WORD32* pi4_tmp)\n{\n    __m128i src, plane_0, plane_1, temp0, temp1, sign_reg;\n    __m128i zero_8x16b = _mm_setzero_si128();\n    __m128i scale_val = _mm_set1_epi32((WORD32)(pu2_iscal_mat[0] * pu2_weigh_mat[0]));\n    UNUSED(pi4_tmp);\n\n    src = _mm_loadu_si128((__m128i *) pi2_src);         //a0 a1 a2 a3 b0 b1 b2 b3\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, src);\n    plane_0 = _mm_unpacklo_epi16(src, sign_reg);        //a0 a1 a2 a3 -- 32 bits\n    plane_1 = _mm_unpackhi_epi16(src, sign_reg);        //b0 b1 b2 b3 -- 32 bits\n\n    temp0 = _mm_hadd_epi32(plane_0, plane_1);           //a0+a1 a2+a3 b0+b1 b2+b3\n    temp1 = _mm_hsub_epi32(plane_0, plane_1);           //a0-a1 a2-a3 b0-b1 b2-b3\n    plane_0 = _mm_hadd_epi32(temp0, temp1);             //a0+a1+a2+a3 b0+b1+b2+b3 a0-a1+a2-a3 b0-b1+b2-b3\n    plane_1 = _mm_hsub_epi32(temp0, temp1);             //a0+a1-a2-a3 b0+b1-b2-b3 a0-a1-a2+a3 b0-b1-b2+b3\n    temp0 = _mm_unpacklo_epi32(plane_0, plane_1);       //a0+a1+a2+a3 a0+a1-a2-a3 b0+b1+b2+b3 b0+b1-b2-b3\n    temp1 = _mm_unpackhi_epi32(plane_0, plane_1);       //a0-a1+a2-a3 a0-a1-a2+a3 b0-b1+b2-b3 b0-b1-b2+b3\n\n    plane_0 = _mm_unpacklo_epi64(temp0, temp1);         //a0+a1+a2+a3 a0+a1-a2-a3 a0-a1+a2-a3 a0-a1-a2+a3\n    plane_1 = _mm_unpackhi_epi64(temp0, temp1);         //b0+b1+b2+b3 b0+b1-b2-b3 b0-b1+b2-b3 b0-b1-b2+b3\n\n    plane_0 = _mm_shuffle_epi32(plane_0, 0xd8);         //a0+a1+a2+a3 a0-a1+a2-a3 a0+a1-a2-a3 a0-a1-a2+a3\n    plane_1 = _mm_shuffle_epi32(plane_1, 0xd8);         //b0+b1+b2+b3 b0-b1+b2-b3 b0+b1-b2-b3 b0-b1-b2+b3\n\n    temp0 = _mm_mullo_epi32(scale_val, plane_0);        //multiply by pu2_iscal_mat[0] * pu2_weigh_mat[0]\n    temp1 = _mm_mullo_epi32(scale_val, plane_1);        //multiply by pu2_iscal_mat[0] * pu2_weigh_mat[0]\n\n    temp0 = _mm_slli_epi32(temp0, u4_qp_div_6);\n    temp1 = _mm_slli_epi32(temp1, u4_qp_div_6);\n\n    temp0 = _mm_srai_epi32(temp0, 5);\n    temp1 = _mm_srai_epi32(temp1, 5);\n\n    temp0 = _mm_packs_epi32(temp0, temp1);              //Final values are 16-bits only.\n\n    _mm_storeu_si128((__m128i *) (&pi2_out[0]), temp0);\n\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_ihadamard_scaling_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_ihadamard_scaling_ssse3.c\n *\n * @brief\n *  Contains definition of functions for h264 inverse hadamard 4x4 transform and scaling\n *\n * @author\n *  Mohit\n *\n *  @par List of Functions:\n *  - ih264_ihadamard_scaling_4x4_ssse3()\n *\n * @remarks\n *\n *******************************************************************************\n */\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_trans_macros.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_trans_data.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include <immintrin.h>\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n/*\n ********************************************************************************\n *\n * @brief This function performs a 4x4 inverse hadamard transform on the 4x4 DC coefficients\n * of a 16x16 intra prediction macroblock, and then performs scaling.\n * prediction buffer\n *\n * @par Description:\n *  The DC coefficients pass through a 2-stage inverse hadamard transform.\n *  This inverse transformed content is scaled to based on Qp value.\n *\n * @param[in] pi2_src\n *  input 4x4 block of DC coefficients\n *\n * @param[out] pi2_out\n *  output 4x4 block\n *\n * @param[in] pu2_iscal_mat\n *  pointer to scaling list\n *\n * @param[in] pu2_weigh_mat\n *  pointer to weight matrix\n *\n * @param[in] u4_qp_div_6\n *  Floor (qp/6)\n *\n * @param[in] pi4_tmp\n * temporary buffer of size 1*16\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nATTRIBUTE_SSSE3\nvoid ih264_ihadamard_scaling_4x4_ssse3(WORD16* pi2_src,\n                                       WORD16* pi2_out,\n                                       const UWORD16 *pu2_iscal_mat,\n                                       const UWORD16 *pu2_weigh_mat,\n                                       UWORD32 u4_qp_div_6,\n                                       WORD32* pi4_tmp)\n{\n    int val = 0xFFFF;\n    __m128i src_r0_r1, src_r2_r3, sign_reg, zero_8x16b = _mm_setzero_si128();\n    __m128i src_r0, src_r1, src_r2, src_r3;\n    __m128i temp0, temp1, temp2, temp3;\n    __m128i add_rshift = _mm_set1_epi32((u4_qp_div_6 < 6) ? (1 << (5 - u4_qp_div_6)) : 0);\n    __m128i mult_val = _mm_set1_epi32(pu2_iscal_mat[0] * pu2_weigh_mat[0]);\n\n    __m128i mask = _mm_set1_epi32(val);\n    UNUSED (pi4_tmp);\n\n    mult_val = _mm_and_si128(mult_val, mask);\n\n    src_r0_r1 = _mm_loadu_si128((__m128i *) (pi2_src)); //a00 a01 a02 a03 a10 a11 a12 a13 -- the source matrix 0th,1st row\n    src_r2_r3 = _mm_loadu_si128((__m128i *) (pi2_src + 8)); //a20 a21 a22 a23 a30 a31 a32 a33 -- the source matrix 2nd,3rd row\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, src_r0_r1);\n    src_r0 = _mm_unpacklo_epi16(src_r0_r1, sign_reg);\n    src_r1 = _mm_unpackhi_epi16(src_r0_r1, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, src_r2_r3);\n    src_r2 = _mm_unpacklo_epi16(src_r2_r3, sign_reg);\n    src_r3 = _mm_unpackhi_epi16(src_r2_r3, sign_reg);\n\n    /* Perform Inverse transform */\n    /*-------------------------------------------------------------*/\n    /* IDCT [ Horizontal transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 a1 a2 a3\n     *  b0 b1 b2 b3\n     *  c0 c1 c2 c3\n     *  d0 d1 d2 d3\n     */\n    temp0 = _mm_unpacklo_epi32(src_r0, src_r1);                  //a0 b0 a1 b1\n    temp2 = _mm_unpacklo_epi32(src_r2, src_r3);                  //c0 d0 c1 d1\n    temp1 = _mm_unpackhi_epi32(src_r0, src_r1);                  //a2 b2 a3 b3\n    temp3 = _mm_unpackhi_epi32(src_r2, src_r3);                  //c2 d2 c3 d3\n    src_r0 = _mm_unpacklo_epi64(temp0, temp2);                    //a0 b0 c0 d0\n    src_r1 = _mm_unpackhi_epi64(temp0, temp2);                    //a1 b1 c1 d1\n    src_r2 = _mm_unpacklo_epi64(temp1, temp3);                    //a2 b2 c2 d2\n    src_r3 = _mm_unpackhi_epi64(temp1, temp3);                    //a3 b3 c3 d3\n\n    temp0 = _mm_add_epi32(src_r0, src_r3);\n    temp1 = _mm_add_epi32(src_r1, src_r2);\n    temp2 = _mm_sub_epi32(src_r1, src_r2);\n    temp3 = _mm_sub_epi32(src_r0, src_r3);\n\n    src_r0 = _mm_add_epi32(temp0, temp1);\n    src_r1 = _mm_add_epi32(temp2, temp3);\n    src_r2 = _mm_sub_epi32(temp0, temp1);\n    src_r3 = _mm_sub_epi32(temp3, temp2);\n\n    /*-------------------------------------------------------------*/\n    /* IDCT [ Vertical transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 b0 c0 d0\n     *  a1 b1 c1 d1\n     *  a2 b2 c2 d2\n     *  a3 b3 c3 d3\n     */\n    temp0 = _mm_unpacklo_epi32(src_r0, src_r1);                  //a0 a1 b0 b1\n    temp2 = _mm_unpacklo_epi32(src_r2, src_r3);                  //a2 a3 b2 b3\n    temp1 = _mm_unpackhi_epi32(src_r0, src_r1);                  //c0 c1 d0 d1\n    temp3 = _mm_unpackhi_epi32(src_r2, src_r3);                  //c2 c3 d2 d3\n    src_r0 = _mm_unpacklo_epi64(temp0, temp2);                   //a0 a1 a2 a3\n    src_r1 = _mm_unpackhi_epi64(temp0, temp2);                   //b0 b1 b2 b3\n    src_r2 = _mm_unpacklo_epi64(temp1, temp3);                   //c0 c1 c2 c3\n    src_r3 = _mm_unpackhi_epi64(temp1, temp3);                   //d0 d1 d2 d3\n\n    temp0 = _mm_add_epi32(src_r0, src_r3);\n    temp1 = _mm_add_epi32(src_r1, src_r2);\n    temp2 = _mm_sub_epi32(src_r1, src_r2);\n    temp3 = _mm_sub_epi32(src_r0, src_r3);\n\n    src_r0 = _mm_add_epi32(temp0, temp1);\n    src_r1 = _mm_add_epi32(temp2, temp3);\n    src_r2 = _mm_sub_epi32(temp0, temp1);\n    src_r3 = _mm_sub_epi32(temp3, temp2);\n\n    src_r0 = _mm_and_si128(src_r0, mask);\n    src_r1 = _mm_and_si128(src_r1, mask);\n    src_r2 = _mm_and_si128(src_r2, mask);\n    src_r3 = _mm_and_si128(src_r3, mask);\n\n    src_r0 = _mm_madd_epi16(src_r0, mult_val);\n    src_r1 = _mm_madd_epi16(src_r1, mult_val);\n    src_r2 = _mm_madd_epi16(src_r2, mult_val);\n    src_r3 = _mm_madd_epi16(src_r3, mult_val);\n\n    //Scaling\n    if(u4_qp_div_6 >= 6)\n    {\n        src_r0 = _mm_slli_epi32(src_r0, u4_qp_div_6 - 6);\n        src_r1 = _mm_slli_epi32(src_r1, u4_qp_div_6 - 6);\n        src_r2 = _mm_slli_epi32(src_r2, u4_qp_div_6 - 6);\n        src_r3 = _mm_slli_epi32(src_r3, u4_qp_div_6 - 6);\n    }\n    else\n    {\n        temp0 = _mm_add_epi32(src_r0, add_rshift);\n        temp1 = _mm_add_epi32(src_r1, add_rshift);\n        temp2 = _mm_add_epi32(src_r2, add_rshift);\n        temp3 = _mm_add_epi32(src_r3, add_rshift);\n        src_r0 = _mm_srai_epi32(temp0, 6 - u4_qp_div_6);\n        src_r1 = _mm_srai_epi32(temp1, 6 - u4_qp_div_6);\n        src_r2 = _mm_srai_epi32(temp2, 6 - u4_qp_div_6);\n        src_r3 = _mm_srai_epi32(temp3, 6 - u4_qp_div_6);\n    }\n    src_r0_r1 = _mm_packs_epi32(src_r0, src_r1);\n    src_r2_r3 = _mm_packs_epi32(src_r2, src_r3);\n\n    _mm_storeu_si128((__m128i *) (&pi2_out[0]), src_r0_r1);\n    _mm_storeu_si128((__m128i *) (&pi2_out[8]), src_r2_r3);\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_inter_pred_filters_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264_inter_pred_filters_intr_ssse3.c                */\n/*                                                                           */\n/*  Description       : Contains function definitions for weighted           */\n/*                      prediction functions in x86 sse4 intrinsics          */\n/*                                                                           */\n/*  List of Functions : ih264_inter_pred_luma_copy_ssse3()                   */\n/*                      ih264_inter_pred_luma_horz_ssse3()                   */\n/*                      ih264_inter_pred_luma_vert_ssse3()                   */\n/*                      ih264_inter_pred_luma_horz_hpel_vert_hpel_ssse3()    */\n/*                      ih264_inter_pred_luma_horz_qpel_ssse3()              */\n/*                      ih264_inter_pred_luma_vert_qpel_ssse3()              */\n/*                      ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3()    */\n/*                      ih264_inter_pred_luma_horz_hpel_vert_qpel_ssse3()    */\n/*                      ih264_inter_pred_luma_horz_qpel_vert_hpel_ssse3()    */\n/*                      ih264_inter_pred_chroma_ssse3()                      */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n#include <immintrin.h>\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_inter_pred_filters.h\"\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n/*****************************************************************************/\n/* Constant Data variables                                                   */\n/*****************************************************************************/\n\n/* coefficients for 6 tap filtering*/\n//const WORD32 ih264_g_six_tap[3] ={1,-5,20};\n/*****************************************************************************/\n/*  Function definitions .                                                   */\n/*****************************************************************************/\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_inter_pred_luma_copy_ssse3                         */\n/*                                                                           */\n/*  Description   : This function copies the contents of ht x wd block from  */\n/*                  source to destination. (ht,wd) can be (4,4), (8,4),      */\n/*                  (4,8), (8,8), (16,8), (8,16) or (16,16).                 */\n/*                                                                           */\n/*  Inputs        : puc_src  - pointer to source                             */\n/*                  puc_dst  - pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_inter_pred_luma_copy_ssse3(UWORD8 *pu1_src,\n                                      UWORD8 *pu1_dst,\n                                      WORD32 src_strd,\n                                      WORD32 dst_strd,\n                                      WORD32 ht,\n                                      WORD32 wd,\n                                      UWORD8* pu1_tmp,\n                                      WORD32 dydx)\n{\n    __m128i y_0_16x8b, y_1_16x8b, y_2_16x8b, y_3_16x8b;\n\n    WORD32 src_strd2, src_strd3, src_strd4, dst_strd2, dst_strd3, dst_strd4;\n    UNUSED(pu1_tmp);\n    UNUSED(dydx);\n\n    src_strd2 = src_strd << 1;\n    dst_strd2 = dst_strd << 1;\n    src_strd4 = src_strd << 2;\n    dst_strd4 = dst_strd << 2;\n    src_strd3 = src_strd2 + src_strd;\n    dst_strd3 = dst_strd2 + dst_strd;\n\n    if(wd == 4)\n    {\n        do\n        {\n            *((WORD32 *)(pu1_dst)) =  *((WORD32 *)(pu1_src));\n            *((WORD32 *)(pu1_dst + dst_strd)) = *((WORD32 *)(pu1_src + src_strd));\n            *((WORD32 *)(pu1_dst + dst_strd2)) = *((WORD32 *)(pu1_src + src_strd2));\n            *((WORD32 *)(pu1_dst + dst_strd3)) = *((WORD32 *)(pu1_src + src_strd3));\n\n            ht -= 4;\n            pu1_src += src_strd4;\n            pu1_dst += dst_strd4;\n        }\n        while(ht > 0);\n    }\n    else if(wd == 8)\n    {\n        do\n        {\n            y_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n            y_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd));\n            y_2_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd2));\n            y_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd3));\n\n            _mm_storel_epi64((__m128i *)pu1_dst, y_0_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), y_1_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd2), y_2_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd3), y_3_16x8b);\n\n            ht -= 4;\n            pu1_src += src_strd4;\n            pu1_dst += dst_strd4;\n        }\n        while(ht > 0);\n    }\n    else // wd == 16\n    {\n        WORD32 src_strd5, src_strd6, src_strd7, src_strd8;\n        WORD32 dst_strd5, dst_strd6, dst_strd7, dst_strd8;\n\n        __m128i y_4_16x8b, y_5_16x8b, y_6_16x8b, y_7_16x8b;\n\n        src_strd5 = src_strd2 + src_strd3;\n        dst_strd5 = dst_strd2 + dst_strd3;\n        src_strd6 = src_strd3 << 1;\n        dst_strd6 = dst_strd3 << 1;\n        src_strd7 = src_strd3 + src_strd4;\n        dst_strd7 = dst_strd3 + dst_strd4;\n        src_strd8 = src_strd << 3;\n        dst_strd8 = dst_strd << 3;\n\n        do\n        {\n            y_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n            y_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));\n            y_2_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd2));\n            y_3_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd3));\n            y_4_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd4));\n            y_5_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd5));\n            y_6_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd6));\n            y_7_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd7));\n\n            _mm_storeu_si128((__m128i *)pu1_dst, y_0_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), y_1_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), y_2_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), y_3_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd4), y_4_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd5), y_5_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd6), y_6_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd7), y_7_16x8b);\n\n            ht -= 8;\n            pu1_src += src_strd8;\n            pu1_dst += dst_strd8;\n        }\n        while(ht > 0);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_inter_pred_luma_horz_ssse3                         */\n/*                                                                           */\n/*  Description   : This function applies a horizontal 6-tap filter on       */\n/*                  ht x wd block as mentioned in sec. 8.4.2.2.1 titled      */\n/*                  \"Luma sample interpolation process\". (ht,wd) can be      */\n/*                  (4,4), (8,4), (4,8), (8,8), (16,8), (8,16) or (16,16).   */\n/*                                                                           */\n/*  Inputs        : puc_src  - pointer to source                             */\n/*                  puc_dst  - pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_inter_pred_luma_horz_ssse3(UWORD8 *pu1_src,\n                                      UWORD8 *pu1_dst,\n                                      WORD32 src_strd,\n                                      WORD32 dst_strd,\n                                      WORD32 ht,\n                                      WORD32 wd,\n                                      UWORD8* pu1_tmp,\n                                      WORD32 dydx)\n{\n    __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n    __m128i const_val16_8x16b;\n\n    UNUSED(pu1_tmp);\n    UNUSED(dydx);\n\n    pu1_src -= 2; // the filter input starts from x[-2] (till x[3])\n\n    coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01); //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n    coeff2_3_16x8b = _mm_set1_epi32(0x14141414); //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n    coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB); //c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5\n                                                 //c0 = c5 = 1, c1 = c4 = -5, c2 = c3 = 20\n    const_val16_8x16b = _mm_set1_epi16(16);\n\n    if(wd == 4)\n    {\n        __m128i src_r0_16x8b, src_r1_16x8b, src_r0r1_16x8b;\n        __m128i src_r0_sht_16x8b, src_r1_sht_16x8b;\n\n        __m128i res_r0r1_t1_8x16b, res_r0r1_t2_8x16b, res_r0r1_t3_8x16b;\n        __m128i res_r0r1_16x8b;\n\n        //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n        //Row1 : b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n\n        do\n        {\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                     //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n            src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));        //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                     //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                     //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n            src_r0_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);       //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n            src_r1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);       //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n            src_r0r1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);        //a0 a1 a1 a2 a2 a3 a3 a4 b0 b1 b1 b2 b2 b3 b3 b4\n            res_r0r1_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);  //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                    //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 4);                         //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 4);                         //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8  0  0  0  0\n\n            src_r0r1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);        //a2 a3 a3 a4 a4 a5 a5 a6 b2 b3 b3 b4 b4 b5 b5 b6\n            res_r0r1_t2_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff2_3_16x8b);  //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                    //b2*c2+b3*c3 b3*c2+b4*c3 b4*c2+b5*c3 b5*c2+b6*c3\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 4);                         //a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0  0  0  0  0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 4);                         //b4 b5 b5 b6 b6 b7 b7 b8  0  0  0  0  0  0  0  0\n\n            src_r0r1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);        //a4 a5 a5 a6 a6 a7 a7 a8 b4 b5 b5 b6 b6 b7 b7 b8\n            res_r0r1_t3_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff4_5_16x8b);  //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                    //b4*c4+b5*c5 b5*c4+b6*c5 b4*c6+b7*c5 b7*c4+b8*c5\n\n            res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t1_8x16b, res_r0r1_t2_8x16b);\n            res_r0r1_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_r0r1_t3_8x16b);\n            res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t1_8x16b, res_r0r1_t3_8x16b); //a0*c0+a1*c1+a2*c2+a3*c3+a4*a4+a5*c5 + 16;\n                                                                                     //a1*c0+a2*c1+a2*c2+a3*c3+a5*a4+a6*c5 + 16;\n                                                                                     //a2*c0+a3*c1+a4*c2+a5*c3+a6*a4+a7*c5 + 16;\n                                                                                     //a3*c0+a4*c1+a5*c2+a6*c3+a6*a4+a8*c5 + 16;\n                                                                                     //b0*c0+b1*c1+b2*c2+b3*c3+b4*b4+b5*c5 + 16;\n                                                                                     //b1*c0+b2*c1+b2*c2+b3*c3+b5*b4+b6*c5 + 16;\n                                                                                     //b2*c0+b3*c1+b4*c2+b5*c3+b6*b4+b7*c5 + 16;\n                                                                                     //b3*c0+b4*c1+b5*c2+b6*c3+b6*b4+b8*c5 + 16;\n\n            res_r0r1_t1_8x16b = _mm_srai_epi16(res_r0r1_t1_8x16b, 5);                //shifting right by 5 bits.\n\n            res_r0r1_16x8b = _mm_packus_epi16(res_r0r1_t1_8x16b, res_r0r1_t1_8x16b);\n\n            *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(res_r0r1_16x8b);\n            res_r0r1_16x8b = _mm_srli_si128(res_r0r1_16x8b, 4);\n            *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(res_r0r1_16x8b);\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else if(wd == 8)\n    {\n        __m128i src_r0_16x8b, src_r1_16x8b, src_r0_sht_16x8b, src_r1_sht_16x8b;\n        __m128i src_r0_t1_16x8b, src_r1_t1_16x8b;\n\n        __m128i res_r0_t1_8x16b, res_r0_t2_8x16b, res_r0_t3_8x16b;\n        __m128i res_r1_t1_8x16b, res_r1_t2_8x16b, res_r1_t3_8x16b;\n\n        //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n        //Row1 : b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n\n        do\n        {\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                   //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n            src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));      //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                   //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                   //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);  //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);  //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n            res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff0_1_16x8b); //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                  //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n            res_r1_t1_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff0_1_16x8b); //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n                                                                                  //b4*c0+b5*c1 b5*c0+b6*c1 b6*c0+b7*c1 b7*c0+b8*c1\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                       //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                       //b2 b3 b4 b5 b6 b7 b8 b9....b15 0 0\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);               //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);               //b3 b4 b5 b6 b7 b8 b9....b15 0  0  0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);  //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);  //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8 a8 a9 a9 a10\n\n            res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b); //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                  //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n            res_r1_t2_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff2_3_16x8b); //b2*c2+b3*c3 b3*c2+b4*c3 b2*c4+b5*c3 b5*c2+b6*c3\n                                                                                  //b6*c2+b7*c3 b7*c2+b8*c3 b8*c2+b9*c3 b9*c2+b10*c3\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                       //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                       //b4 b5 b6 b7 b8 b9....b15 0  0  0  0\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);               //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);               //b5 b6 b7 b8 b9....b15 0  0  0  0  0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);  //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);  //b4 b5 b5 b6 b6 b7 b7 b8 b8 b9 b9 b10 b10 b11 b11 b12\n\n            res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b); //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                  //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n            res_r1_t3_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff4_5_16x8b); //b4*c4+b5*c5 b5*c4+b6*c5 b6*c4+b7*c5 b7*c4+b8*c5\n                                                                                  //b8*c4+b9*c5 b9*c4+b10*c5 b10*c4+b11*c5 b11*c4+b12*c5\n            res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n            res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t2_8x16b);\n            res_r0_t3_8x16b = _mm_add_epi16(res_r0_t3_8x16b, const_val16_8x16b);\n            res_r1_t3_8x16b = _mm_add_epi16(res_r1_t3_8x16b, const_val16_8x16b);\n            res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n            res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t3_8x16b);\n\n            res_r0_t1_8x16b = _mm_srai_epi16(res_r0_t1_8x16b, 5);                 //shifting right by 5 bits.\n            res_r1_t1_8x16b = _mm_srai_epi16(res_r1_t1_8x16b, 5);\n\n            src_r0_16x8b = _mm_packus_epi16(res_r0_t1_8x16b, res_r0_t1_8x16b);\n            src_r1_16x8b = _mm_packus_epi16(res_r1_t1_8x16b, res_r1_t1_8x16b);\n\n            _mm_storel_epi64((__m128i *)pu1_dst, src_r0_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), src_r1_16x8b);\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else // wd == 16\n    {\n        __m128i src_r0_16x8b, src_r1_16x8b, src_r0_sht_16x8b, src_r1_sht_16x8b;\n        __m128i src_r0_t1_16x8b, src_r1_t1_16x8b;\n\n        __m128i res_r0_t1_8x16b, res_r0_t2_8x16b, res_r0_t3_8x16b;\n        __m128i res_r1_t1_8x16b, res_r1_t2_8x16b, res_r1_t3_8x16b;\n\n        //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n        //Row0 :                         b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n        //b0 is same a8. Similarly other bn pixels are same as a(n+8) pixels.\n\n        do\n        {\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                  //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n            src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 8));            //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                   //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                   //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);  //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);  //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n            res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff0_1_16x8b); //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                  //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n            res_r1_t1_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff0_1_16x8b); //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n                                                                                  //b4*c0+b5*c1 b5*c0+b6*c1 b6*c0+b7*c1 b7*c0+b8*c1\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                       //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                       //b2 b3 b4 b5 b6 b7 b8 b9....b15 0 0\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);               //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);               //b3 b4 b5 b6 b7 b8 b9....b15 0  0  0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);  //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);  //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8 a8 a9 a9 a10\n\n            res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b); //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                  //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n            res_r1_t2_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff2_3_16x8b); //b2*c2+b3*c3 b3*c2+b4*c3 b2*c4+b5*c3 b5*c2+b6*c3\n                                                                                  //b6*c2+b7*c3 b7*c2+b8*c3 b8*c2+b9*c3 b9*c2+b10*c3\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                       //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                       //b4 b5 b6 b7 b8 b9....b15 0  0  0  0\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);               //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);               //b5 b6 b7 b8 b9....b15 0  0  0  0  0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);  //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);  //b4 b5 b5 b6 b6 b7 b7 b8 b8 b9 b9 b10 b10 b11 b11 b12\n\n            res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b); //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                  //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n            res_r1_t3_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff4_5_16x8b); //b4*c4+b5*c5 b5*c4+b6*c5 b6*c4+b7*c5 b7*c4+b8*c5\n                                                                                  //b8*c4+b9*c5 b9*c4+b10*c5 b10*c4+b11*c5 b11*c4+b12*c5\n            res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n            res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t2_8x16b);\n            res_r0_t3_8x16b = _mm_add_epi16(res_r0_t3_8x16b, const_val16_8x16b);\n            res_r1_t3_8x16b = _mm_add_epi16(res_r1_t3_8x16b, const_val16_8x16b);\n            res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n            res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t3_8x16b);\n\n            res_r0_t1_8x16b = _mm_srai_epi16(res_r0_t1_8x16b, 5);                 //shifting right by 5 bits.\n            res_r1_t1_8x16b = _mm_srai_epi16(res_r1_t1_8x16b, 5);\n\n            src_r0_16x8b = _mm_packus_epi16(res_r0_t1_8x16b, res_r1_t1_8x16b);\n            _mm_storeu_si128((__m128i *)pu1_dst, src_r0_16x8b);\n\n            ht--;\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n        }\n        while(ht > 0);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_inter_pred_luma_vert_ssse3                         */\n/*                                                                           */\n/*  Description   : This function applies a vertical 6-tap filter on         */\n/*                  ht x wd block as mentioned in sec. 8.4.2.2.1 titled      */\n/*                  \"Luma sample interpolation process\". (ht,wd) can be      */\n/*                  (4,4), (8,4), (4,8), (8,8), (16,8), (8,16) or (16,16).   */\n/*                                                                           */\n/*  Inputs        : puc_src  - pointer to source                             */\n/*                  puc_dst  - pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_inter_pred_luma_vert_ssse3(UWORD8 *pu1_src,\n                                      UWORD8 *pu1_dst,\n                                      WORD32 src_strd,\n                                      WORD32 dst_strd,\n                                      WORD32 ht,\n                                      WORD32 wd,\n                                      UWORD8* pu1_tmp,\n                                      WORD32 dydx)\n{\n    __m128i src_r0_16x8b, src_r1_16x8b, src_r2_16x8b, src_r3_16x8b, src_r4_16x8b;\n    __m128i src_r5_16x8b, src_r6_16x8b;\n    __m128i src_r0r1_16x8b, src_r2r3_16x8b, src_r4r5_16x8b;\n\n    __m128i res_16x8b, res_t1_8x16b, res_t2_8x16b, res_t3_8x16b;\n\n    __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n    __m128i const_val16_8x16b;\n\n    UNUSED(pu1_tmp);\n    UNUSED(dydx);\n\n    coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01); //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n    coeff2_3_16x8b = _mm_set1_epi32(0x14141414); //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n    coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB); //c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5\n                                                 //c0 = c5 = 1, c1 = c4 = -5, c2 = c3 = 20\n    const_val16_8x16b = _mm_set1_epi16(16);\n\n    pu1_src -= src_strd << 1; // the filter input starts from x[-2] (till x[3])\n\n    if(wd == 4)\n    {\n        //Epilogue: Load all the pred rows except sixth and seventh row\n        //          for the first and second row processing.\n        src_r0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r1_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r2_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r3_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r4_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n\n        src_r0_16x8b = _mm_unpacklo_epi32(src_r0_16x8b, src_r1_16x8b);\n        src_r1_16x8b = _mm_unpacklo_epi32(src_r1_16x8b, src_r2_16x8b);\n        src_r2_16x8b = _mm_unpacklo_epi32(src_r2_16x8b, src_r3_16x8b);\n        src_r3_16x8b = _mm_unpacklo_epi32(src_r3_16x8b, src_r4_16x8b);\n\n        do\n        {\n            src_r5_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n            src_r6_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd));\n\n            src_r4_16x8b = _mm_unpacklo_epi32(src_r4_16x8b, src_r5_16x8b);\n            src_r5_16x8b = _mm_unpacklo_epi32(src_r5_16x8b, src_r6_16x8b);\n\n            src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n            src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n            src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(res_t3_8x16b, const_val16_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n\n            res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n            res_16x8b = _mm_packus_epi16(res_t1_8x16b, res_t1_8x16b);\n\n            *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(res_16x8b);\n            res_16x8b = _mm_srli_si128(res_16x8b, 4);\n            *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(res_16x8b);\n\n            src_r0_16x8b = src_r2_16x8b;\n            src_r1_16x8b = src_r3_16x8b;\n            src_r2_16x8b = src_r4_16x8b;\n            src_r3_16x8b = src_r5_16x8b;\n            src_r4_16x8b = src_r6_16x8b;\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n\n    else if(wd == 8)\n    {\n        //Epilogue: Load all the pred rows except sixth and seventh row\n        //          for the first and second row processing.\n        src_r0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r1_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r2_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r3_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r4_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n\n        src_r0_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);\n        src_r1_16x8b = _mm_unpacklo_epi64(src_r1_16x8b, src_r2_16x8b);\n        src_r2_16x8b = _mm_unpacklo_epi64(src_r2_16x8b, src_r3_16x8b);\n        src_r3_16x8b = _mm_unpacklo_epi64(src_r3_16x8b, src_r4_16x8b);\n\n        do\n        {\n            src_r5_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n            src_r6_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd));\n\n            src_r4_16x8b = _mm_unpacklo_epi64(src_r4_16x8b, src_r5_16x8b);\n            src_r5_16x8b = _mm_unpacklo_epi64(src_r5_16x8b, src_r6_16x8b);\n\n            src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n            src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n            src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(res_t3_8x16b, const_val16_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n\n            res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n            res_16x8b = _mm_packus_epi16(res_t1_8x16b, res_t1_8x16b);\n\n            _mm_storel_epi64((__m128i *)pu1_dst, res_16x8b);\n\n            src_r0r1_16x8b = _mm_unpackhi_epi8(src_r0_16x8b, src_r1_16x8b);\n            src_r2r3_16x8b = _mm_unpackhi_epi8(src_r2_16x8b, src_r3_16x8b);\n            src_r4r5_16x8b = _mm_unpackhi_epi8(src_r4_16x8b, src_r5_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(res_t3_8x16b, const_val16_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n\n            res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n            res_16x8b = _mm_packus_epi16(res_t1_8x16b, res_t1_8x16b);\n\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), res_16x8b);\n\n            src_r0_16x8b = src_r2_16x8b;\n            src_r1_16x8b = src_r3_16x8b;\n            src_r2_16x8b = src_r4_16x8b;\n            src_r3_16x8b = src_r5_16x8b;\n            src_r4_16x8b = src_r6_16x8b;\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else // wd == 16\n    {\n        __m128i res_t0_8x16b;\n\n        //Epilogue: Load all the pred rows except sixth and seventh row\n        //          for the first and second row processing.\n        src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r1_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r2_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r3_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r4_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        pu1_src += src_strd;\n\n        do\n        {\n            src_r5_16x8b  = _mm_loadu_si128((__m128i *)pu1_src);\n            src_r6_16x8b  = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));\n\n            src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n            src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n            src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(res_t3_8x16b, const_val16_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n            res_t0_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            src_r0r1_16x8b = _mm_unpackhi_epi8(src_r0_16x8b, src_r1_16x8b);\n            src_r2r3_16x8b = _mm_unpackhi_epi8(src_r2_16x8b, src_r3_16x8b);\n            src_r4r5_16x8b = _mm_unpackhi_epi8(src_r4_16x8b, src_r5_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(res_t3_8x16b, const_val16_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n            res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            res_16x8b = _mm_packus_epi16(res_t0_8x16b, res_t1_8x16b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, res_16x8b);\n\n            src_r0r1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r2_16x8b);\n            src_r2r3_16x8b = _mm_unpacklo_epi8(src_r3_16x8b, src_r4_16x8b);\n            src_r4r5_16x8b = _mm_unpacklo_epi8(src_r5_16x8b, src_r6_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(res_t3_8x16b, const_val16_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n            res_t0_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            src_r0r1_16x8b = _mm_unpackhi_epi8(src_r1_16x8b, src_r2_16x8b);\n            src_r2r3_16x8b = _mm_unpackhi_epi8(src_r3_16x8b, src_r4_16x8b);\n            src_r4r5_16x8b = _mm_unpackhi_epi8(src_r5_16x8b, src_r6_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(res_t3_8x16b, const_val16_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n            res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            res_16x8b = _mm_packus_epi16(res_t0_8x16b, res_t1_8x16b);\n\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res_16x8b);\n\n            src_r0_16x8b = src_r2_16x8b;\n            src_r1_16x8b = src_r3_16x8b;\n            src_r2_16x8b = src_r4_16x8b;\n            src_r3_16x8b = src_r5_16x8b;\n            src_r4_16x8b = src_r6_16x8b;\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_inter_pred_luma_horz_hpel_vert_hpel_ssse3          */\n/*                                                                           */\n/*  Description   : This function implements a two stage cascaded six tap    */\n/*                  filter, horizontally and then vertically on ht x wd      */\n/*                  block as mentioned in sec. 8.4.2.2.1 titled \"Luma sample */\n/*                  interpolation process\". (ht,wd) can be (4,4), (8,4),     */\n/*                  (4,8), (8,8), (16,8), (8,16) or (16,16).                 */\n/*                                                                           */\n/*  Inputs        : puc_src  - pointer to source                             */\n/*                  puc_dst  - pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                  pu1_tmp  - pointer to temporary buffer                   */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_inter_pred_luma_horz_hpel_vert_hpel_ssse3(UWORD8 *pu1_src,\n                                                     UWORD8 *pu1_dst,\n                                                     WORD32 src_strd,\n                                                     WORD32 dst_strd,\n                                                     WORD32 ht,\n                                                     WORD32 wd,\n                                                     UWORD8* pu1_tmp,\n                                                     WORD32 dydx)\n{\n    UNUSED(dydx);\n\n    if(wd == 4)\n    {\n        WORD16 *pi2_temp;\n\n        pu1_tmp += 4;\n        pu1_src -= src_strd << 1;\n        pi2_temp = (WORD16 *)pu1_tmp;\n        pu1_src -= 2; // the filter input starts from x[-2] (till x[3])\n\n        // Horizontal 6-tap filtering\n        {\n            WORD32 ht_tmp = ht + 4;\n\n            __m128i src_r0_16x8b, src_r1_16x8b;\n            __m128i src_r0_sht_16x8b, src_r1_sht_16x8b;\n            __m128i src_r0r1_t1_16x8b;\n            __m128i res_r0r1_t1_8x16b, res_r0r1_t2_8x16b, res_r0r1_t3_8x16b;\n            __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n\n            coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01);  //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n            coeff2_3_16x8b = _mm_set1_epi32(0x14141414);  //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n            coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB);  //c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5\n                                                          //c0 = c5 = 1, c1 = c4 = -5, c2 = c3 = 20\n            //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n            //Row1 : b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n\n            do\n            {\n                src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                       //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n                src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));          //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                       //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                       //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n                src_r0_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);         //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n                src_r1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);         //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n                src_r0r1_t1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);       //a0 a1 a1 a2 a2 a3 a3 a4 b0 b1 b1 b2 b2 b3 b3 b4\n                res_r0r1_t1_8x16b = _mm_maddubs_epi16(src_r0r1_t1_16x8b, coeff0_1_16x8b); //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                          //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 4);                           //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 4);                           //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8  0  0  0  0\n\n                src_r0r1_t1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);       //a2 a3 a3 a4 a4 a5 a5 a6 b2 b3 b3 b4 b4 b5 b5 b6\n                res_r0r1_t2_8x16b = _mm_maddubs_epi16(src_r0r1_t1_16x8b, coeff2_3_16x8b); //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                          //b2*c2+b3*c3 b3*c2+b4*c3 b4*c2+b5*c3 b5*c2+b6*c3\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 4);                           //a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0  0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 4);                           //b4 b5 b5 b6 b6 b7 b7 b8  0  0  0  0  0  0  0  0\n\n                src_r0r1_t1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);       //a4 a5 a5 a6 a6 a7 a7 a8 b4 b5 b5 b6 b6 b7 b7 b8\n                res_r0r1_t3_8x16b = _mm_maddubs_epi16(src_r0r1_t1_16x8b, coeff4_5_16x8b); //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                          //b4*c4+b5*c5 b5*c4+b6*c5 b4*c6+b7*c5 b7*c4+b8*c5\n                res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t1_8x16b, res_r0r1_t2_8x16b);\n                res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t3_8x16b, res_r0r1_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)pi2_temp, res_r0r1_t1_8x16b);\n\n                ht_tmp -= 2;\n                pu1_src += src_strd << 1;\n                pi2_temp += 8;\n            }\n            while(ht_tmp > 0);\n\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                           //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                           //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n\n            src_r0_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);             //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n            res_r0r1_t1_8x16b = _mm_maddubs_epi16(src_r0_16x8b, coeff0_1_16x8b);          //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b,4);                                //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0\n            res_r0r1_t2_8x16b = _mm_maddubs_epi16(src_r0_16x8b, coeff2_3_16x8b);          //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b,4);                                //a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0  0  0  0  0\n            res_r0r1_t3_8x16b = _mm_maddubs_epi16(src_r0_16x8b, coeff4_5_16x8b);          //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n\n            res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t1_8x16b, res_r0r1_t2_8x16b);\n            res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t3_8x16b, res_r0r1_t1_8x16b);\n\n            _mm_storel_epi64((__m128i *)pi2_temp, res_r0r1_t1_8x16b);\n        }\n\n        pi2_temp = (WORD16 *)pu1_tmp;\n\n        // Vertical 6-tap filtering\n        {\n            __m128i src_r0_8x16b, src_r1_8x16b, src_r2_8x16b, src_r3_8x16b,\n                            src_r4_8x16b;\n            __m128i src_r5_8x16b, src_r6_8x16b;\n            __m128i src_t1_8x16b, src_t2_8x16b;\n\n            __m128i res_t0_4x32b, res_t1_4x32b, res_t2_4x32b, res_t3_4x32b;\n            __m128i res_8x16b, res_16x8b;\n\n            __m128i coeff0_1_8x16b, coeff2_3_8x16b, coeff4_5_8x16b;\n            __m128i const_val512_4x32b;\n\n            coeff0_1_8x16b = _mm_set1_epi32(0xFFFB0001);\n            coeff2_3_8x16b = _mm_set1_epi32(0x00140014);\n            coeff4_5_8x16b = _mm_set1_epi32(0x0001FFFB);\n\n            const_val512_4x32b = _mm_set1_epi32(512);\n\n            src_r0_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp));\n            src_r1_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp + 4));\n            src_r2_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp + 8));\n            src_r3_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp + 12));\n            src_r4_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp + 16));\n            pi2_temp += 20;\n\n            do\n            {\n                src_r5_8x16b = _mm_loadl_epi64((__m128i *)pi2_temp);\n                src_r6_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp + 4));\n\n                src_r0_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_t1_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_t2_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_t1_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_t2_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r1_8x16b = _mm_unpacklo_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_t1_8x16b = _mm_unpacklo_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_t2_8x16b = _mm_unpacklo_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_t1_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_t2_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(res_16x8b);\n                res_16x8b = _mm_srli_si128(res_16x8b, 4);\n                *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(res_16x8b);\n\n                src_r0_8x16b = src_r2_8x16b;\n                src_r1_8x16b = src_r3_8x16b;\n                src_r2_8x16b = src_r4_8x16b;\n                src_r3_8x16b = src_r5_8x16b;\n                src_r4_8x16b = src_r6_8x16b;\n\n                ht -= 2;\n                pi2_temp += 8;\n                pu1_dst += dst_strd << 1;\n            }\n            while(ht > 0);\n        }\n    }\n    else if(wd == 8)\n    {\n        WORD16 *pi2_temp;\n\n        pu1_tmp += 4;\n        pu1_src -= src_strd << 1;\n        pi2_temp = (WORD16 *)pu1_tmp;\n        pu1_src -= 2; // the filter input starts from x[-2] (till x[3])\n\n        // Horizontal 6-tap filtering\n        {\n            WORD32 ht_tmp = ht + 4;\n\n            __m128i src_r0_16x8b, src_r1_16x8b;\n            __m128i src_r0_sht_16x8b, src_r1_sht_16x8b;\n            __m128i src_r0_t1_16x8b, src_r1_t1_16x8b;\n            __m128i res_r0_t1_8x16b, res_r0_t2_8x16b, res_r0_t3_8x16b;\n            __m128i res_r1_t1_8x16b, res_r1_t2_8x16b, res_r1_t3_8x16b;\n            __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n\n            coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01);  //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n            coeff2_3_16x8b = _mm_set1_epi32(0x14141414);  //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n            coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB);  //c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5\n                                                          //c0 = c5 = 1, c1 = c4 = -5, c2 = c3 = 20\n            //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n            //Row1 : b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n\n            do\n            {\n                src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                      //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15\n                src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));         //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                      //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                      //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n                res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff0_1_16x8b);    //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                         //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n                res_r1_t1_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff0_1_16x8b);    //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n                                                                                         //b4*c0+b5*c1 b5*c0+b6*c1 b6*c0+b7*c1 b7*c0+b8*c1\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                          //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                          //b2 b3 b4 b5 b6 b7 b8 b9....b15 0 0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                  //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                  //b3 b4 b5 b6 b7 b8 b9....b15 0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8 a8 a9 a9 a10\n\n                res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b);    //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                         //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n                res_r1_t2_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff2_3_16x8b);    //b2*c2+b3*c3 b3*c2+b4*c3 b2*c4+b5*c3 b5*c2+b6*c3\n                                                                                         //b6*c2+b7*c3 b7*c2+b8*c3 b8*c2+b9*c3 b9*c2+b10*c3\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                          //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                          //b4 b5 b6 b7 b8 b9....b15 0  0  0  0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                  //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                  //b5 b6 b7 b8 b9....b15 0  0  0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b4 b5 b5 b6 b6 b7 b7 b8 b8 b9 b9 b10 b10 b11 b11 b12\n\n                res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b);    //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                         //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n                res_r1_t3_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff4_5_16x8b);    //b4*c4+b5*c5 b5*c4+b6*c5 b6*c4+b7*c5 b7*c4+b8*c5\n                                                                                         //b8*c4+b9*c5 b9*c4+b10*c5 b10*c4+b11*c5 b11*c4+b12*c5\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t2_8x16b);\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t3_8x16b);\n\n                _mm_storeu_si128((__m128i *)pi2_temp, res_r0_t1_8x16b);\n                _mm_storeu_si128((__m128i *)(pi2_temp + 8), res_r1_t1_8x16b);\n\n                ht_tmp -= 2;\n                pu1_src += src_strd << 1;\n                pi2_temp += 16;\n            }\n            while(ht_tmp > 0);\n\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                          //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                          //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b,src_r0_sht_16x8b);          //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n            res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b,coeff0_1_16x8b);         //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                         //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                              //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                      //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);         //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n            res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b);        //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                         //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                              //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                      //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);         //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n            res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b);        //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                         //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n            res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n            res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n\n            _mm_storeu_si128((__m128i *)pi2_temp, res_r0_t1_8x16b);\n        }\n\n        pi2_temp = (WORD16 *)pu1_tmp;\n\n        // Vertical 6-tap filtering\n        {\n            __m128i src_r0_8x16b, src_r1_8x16b, src_r2_8x16b, src_r3_8x16b,\n                            src_r4_8x16b;\n            __m128i src_r5_8x16b, src_r6_8x16b;\n            __m128i src_r0r1_8x16b, src_r2r3_8x16b, src_r4r5_8x16b;\n\n            __m128i res_t1_4x32b, res_t2_4x32b, res_t3_4x32b;\n            __m128i res_c0_4x32b, res_c1_4x32b;\n            __m128i res_8x16b, res_16x8b;\n\n            __m128i coeff0_1_8x16b, coeff2_3_8x16b, coeff4_5_8x16b;\n            __m128i const_val512_4x32b;\n\n            coeff0_1_8x16b = _mm_set1_epi32(0xFFFB0001);\n            coeff2_3_8x16b = _mm_set1_epi32(0x00140014);\n            coeff4_5_8x16b = _mm_set1_epi32(0x0001FFFB);\n\n            const_val512_4x32b = _mm_set1_epi32(512);\n\n            src_r0_8x16b = _mm_loadu_si128((__m128i *)pi2_temp);\n            src_r1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp + 8));\n            src_r2_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp + 16));\n            src_r3_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp + 24));\n            src_r4_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp + 32));\n            pi2_temp += 40;\n\n            do\n            {\n                src_r5_8x16b = _mm_loadu_si128((__m128i *)pi2_temp);\n                src_r6_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp + 8));\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_c0_4x32b, res_c1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                _mm_storel_epi64((__m128i *)pu1_dst, res_16x8b);\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_c0_4x32b, res_c1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), res_16x8b);\n\n                src_r0_8x16b = src_r2_8x16b;\n                src_r1_8x16b = src_r3_8x16b;\n                src_r2_8x16b = src_r4_8x16b;\n                src_r3_8x16b = src_r5_8x16b;\n                src_r4_8x16b = src_r6_8x16b;\n\n                ht -= 2;\n                pi2_temp += 16;\n                pu1_dst += dst_strd << 1;\n            }\n            while(ht > 0);\n        }\n    }\n    else // wd == 16\n    {\n        WORD16 *pi2_temp;\n        WORD32 ht_tmp;\n\n        pu1_tmp += 4;\n        pu1_src -= src_strd << 1;\n        pi2_temp = (WORD16 *)pu1_tmp;\n        pu1_src -= 2; // the filter input starts from x[-2] (till x[3])\n\n        // Horizontal 6-tap filtering\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r0_sht_16x8b, src_r1_sht_16x8b;\n            __m128i src_r0_t1_16x8b, src_r1_t1_16x8b;\n\n            __m128i res_r0_t1_8x16b, res_r0_t2_8x16b, res_r0_t3_8x16b;\n            __m128i res_r1_t1_8x16b, res_r1_t2_8x16b, res_r1_t3_8x16b;\n\n            __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n\n            ht_tmp = ht + 5;\n\n            coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01);  //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n            coeff2_3_16x8b = _mm_set1_epi32(0x14141414);  //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n            coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB);  //c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5\n                                                          //c0 = c5 = 1, c1 = c4 = -5, c2 = c3 = 20\n            //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n            //Row0 :                         b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n            //b0 is same a8. Similarly other bn pixels are same as a(n+8) pixels.\n\n            do\n            {\n                src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                      //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n                src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 8));                //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                      //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                      //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n                res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff0_1_16x8b);    //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                         //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n                res_r1_t1_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff0_1_16x8b);    //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n                                                                                         //b4*c0+b5*c1 b5*c0+b6*c1 b6*c0+b7*c1 b7*c0+b8*c1\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                          //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                          //b2 b3 b4 b5 b6 b7 b8 b9....b15 0 0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                  //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                  //b3 b4 b5 b6 b7 b8 b9....b15 0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8 a8 a9 a9 a10\n\n                res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b);    //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                         //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n                res_r1_t2_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff2_3_16x8b);    //b2*c2+b3*c3 b3*c2+b4*c3 b2*c4+b5*c3 b5*c2+b6*c3\n                                                                                         //b6*c2+b7*c3 b7*c2+b8*c3 b8*c2+b9*c3 b9*c2+b10*c3\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                          //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                          //b4 b5 b6 b7 b8 b9....b15 0  0  0  0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                  //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                  //b5 b6 b7 b8 b9....b15 0  0  0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b4 b5 b5 b6 b6 b7 b7 b8 b8 b9 b9 b10 b10 b11 b11 b12\n\n                res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b);    //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                         //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n                res_r1_t3_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff4_5_16x8b);    //b4*c4+b5*c5 b5*c4+b6*c5 b6*c4+b7*c5 b7*c4+b8*c5\n                                                                                         //b8*c4+b9*c5 b9*c4+b10*c5 b10*c4+b11*c5 b11*c4+b12*c5\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t2_8x16b);\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t3_8x16b);\n\n                _mm_storeu_si128((__m128i *)pi2_temp, res_r0_t1_8x16b);\n                _mm_storeu_si128((__m128i *)(pi2_temp + 8), res_r1_t1_8x16b);\n\n                ht_tmp--;\n                pu1_src += src_strd;\n                pi2_temp += 16;\n            }\n            while(ht_tmp > 0);\n        }\n\n        pi2_temp = (WORD16 *)pu1_tmp;\n\n        // Vertical 6-tap filtering\n        {\n            WORD16 *pi2_temp2;\n            UWORD8 *pu1_dst2;\n            WORD32 ht_tmp;\n\n            __m128i src_r0_8x16b, src_r1_8x16b, src_r2_8x16b, src_r3_8x16b, src_r4_8x16b;\n            __m128i src_r5_8x16b, src_r6_8x16b;\n            __m128i src_r0r1_8x16b, src_r2r3_8x16b, src_r4r5_8x16b;\n\n            __m128i res_t1_4x32b, res_t2_4x32b, res_t3_4x32b;\n            __m128i res_c0_4x32b, res_c1_4x32b;\n            __m128i res_8x16b, res_16x8b;\n\n            __m128i coeff0_1_8x16b, coeff2_3_8x16b, coeff4_5_8x16b;\n            __m128i const_val512_4x32b;\n\n            coeff0_1_8x16b = _mm_set1_epi32(0xFFFB0001);\n            coeff2_3_8x16b = _mm_set1_epi32(0x00140014);\n            coeff4_5_8x16b = _mm_set1_epi32(0x0001FFFB);\n\n            const_val512_4x32b = _mm_set1_epi32(512);\n\n            pi2_temp2 = pi2_temp + 8;\n            pu1_dst2 = pu1_dst + 8;\n            ht_tmp = ht;\n\n            /**********************************************************/\n            /*     Do first height x 8 block                          */\n            /**********************************************************/\n            src_r0_8x16b = _mm_loadu_si128((__m128i *)pi2_temp);\n            src_r1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp + 16));\n            src_r2_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp + 32));\n            src_r3_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp + 48));\n            src_r4_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp + 64));\n            pi2_temp += 80;\n\n            do\n            {\n                src_r5_8x16b = _mm_loadu_si128((__m128i *)pi2_temp);\n                src_r6_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp + 16));\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_c0_4x32b, res_c1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                _mm_storel_epi64((__m128i *)pu1_dst, res_16x8b);\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_c0_4x32b, res_c1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), res_16x8b);\n\n                src_r0_8x16b = src_r2_8x16b;\n                src_r1_8x16b = src_r3_8x16b;\n                src_r2_8x16b = src_r4_8x16b;\n                src_r3_8x16b = src_r5_8x16b;\n                src_r4_8x16b = src_r6_8x16b;\n\n                ht_tmp -= 2;\n                pi2_temp += 32;\n                pu1_dst += dst_strd << 1;\n            }\n            while(ht_tmp > 0);\n\n            /**********************************************************/\n            /*     Do second ht x 8 block                          */\n            /**********************************************************/\n            src_r0_8x16b = _mm_loadu_si128((__m128i *)pi2_temp2);\n            src_r1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 16));\n            src_r2_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 32));\n            src_r3_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 48));\n            src_r4_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 64));\n            pi2_temp2 += 80;\n\n            do\n            {\n                src_r5_8x16b = _mm_loadu_si128((__m128i *)pi2_temp2);\n                src_r6_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 16));\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_c0_4x32b, res_c1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                _mm_storel_epi64((__m128i *)pu1_dst2, res_16x8b);\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_c1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_c0_4x32b, res_c1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                _mm_storel_epi64((__m128i *)(pu1_dst2 + dst_strd), res_16x8b);\n\n                src_r0_8x16b = src_r2_8x16b;\n                src_r1_8x16b = src_r3_8x16b;\n                src_r2_8x16b = src_r4_8x16b;\n                src_r3_8x16b = src_r5_8x16b;\n                src_r4_8x16b = src_r6_8x16b;\n\n                ht -= 2;\n                pi2_temp2 += 32;\n                pu1_dst2 += dst_strd << 1;\n            }\n            while(ht > 0);\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_inter_pred_luma_horz_qpel_ssse3                    */\n/*                                                                           */\n/*  Description   : This function implements a six-tap filter horizontally   */\n/*                  on ht x wd block and averages the values with the source */\n/*                  pixels to calculate horizontal quarter-pel as mentioned  */\n/*                  in sec. 8.4.2.2.1 titled \"Luma sample interpolation      */\n/*                  process\". (ht,wd) can be (4,4), (8,4), (4,8), (8,8),     */\n/*                  (16,8), (8,16) or (16,16).                               */\n/*                                                                           */\n/*  Inputs        : puc_src  - pointer to source                             */\n/*                  puc_dst  - pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                  pu1_tmp  - pointer to temporary buffer                   */\n/*                  dydx     - x and y reference offset for q-pel            */\n/*                             calculations                                  */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_inter_pred_luma_horz_qpel_ssse3(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ht,\n                                           WORD32 wd,\n                                           UWORD8* pu1_tmp,\n                                           WORD32 dydx)\n{\n    WORD32 x_offset;\n    UWORD8 *pu1_pred1;\n\n    __m128i src_r0_16x8b, src_r1_16x8b;\n    __m128i src_r0_sht_16x8b, src_r1_sht_16x8b;\n    __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n    __m128i const_val16_8x16b;\n\n    UNUSED(pu1_tmp);\n\n    x_offset = dydx & 3;\n\n    coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01); //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n    coeff2_3_16x8b = _mm_set1_epi32(0x14141414); //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n    coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB); //c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5\n                                                 //c0 = c5 = 1, c1 = c4 = -5, c2 = c3 = 20\n    pu1_pred1 = pu1_src + (x_offset >> 1);\n\n    const_val16_8x16b = _mm_set1_epi16(16);\n\n    pu1_src -= 2; // the filter input starts from x[-2] (till x[3])\n\n    if(wd == 4)\n    {\n        __m128i src_r0r1_16x8b;\n\n        __m128i res_r0r1_t1_8x16b, res_r0r1_t2_8x16b, res_r0r1_t3_8x16b;\n        __m128i res_r0r1_16x8b;\n\n        //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n        //Row1 : b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n\n        do\n        {\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                         //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n            src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));            //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                         //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                         //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n            src_r0_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);           //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n            src_r1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);           //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n            src_r0r1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);            //a0 a1 a1 a2 a2 a3 a3 a4 b0 b1 b1 b2 b2 b3 b3 b4\n            res_r0r1_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);      //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                        //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 4);                             //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 4);                             //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8  0  0  0  0\n\n            src_r0r1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);            //a2 a3 a3 a4 a4 a5 a5 a6 b2 b3 b3 b4 b4 b5 b5 b6\n            res_r0r1_t2_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff2_3_16x8b);      //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                        //b2*c2+b3*c3 b3*c2+b4*c3 b4*c2+b5*c3 b5*c2+b6*c3\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 4);                             //a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0  0  0  0  0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 4);                             //b4 b5 b5 b6 b6 b7 b7 b8  0  0  0  0  0  0  0  0\n\n            src_r0r1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);            //a4 a5 a5 a6 a6 a7 a7 a8 b4 b5 b5 b6 b6 b7 b7 b8\n            res_r0r1_t3_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff4_5_16x8b);      //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                        //b4*c4+b5*c5 b5*c4+b6*c5 b4*c6+b7*c5 b7*c4+b8*c5\n            src_r0_16x8b = _mm_loadl_epi64((__m128i *)pu1_pred1);\n            src_r1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred1 + src_strd));\n\n            res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t1_8x16b, res_r0r1_t2_8x16b);\n            res_r0r1_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_r0r1_t3_8x16b);\n            res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t1_8x16b, res_r0r1_t3_8x16b);    //a0*c0+a1*c1+a2*c2+a3*c3+a4*a4+a5*c5 + 16;\n                                                                                        //a1*c0+a2*c1+a2*c2+a3*c3+a5*a4+a6*c5 + 16;\n                                                                                        //a2*c0+a3*c1+a4*c2+a5*c3+a6*a4+a7*c5 + 16;\n                                                                                        //a3*c0+a4*c1+a5*c2+a6*c3+a6*a4+a8*c5 + 16;\n                                                                                        //b0*c0+b1*c1+b2*c2+b3*c3+b4*b4+b5*c5 + 16;\n                                                                                        //b1*c0+b2*c1+b2*c2+b3*c3+b5*b4+b6*c5 + 16;\n                                                                                        //b2*c0+b3*c1+b4*c2+b5*c3+b6*b4+b7*c5 + 16;\n                                                                                        //b3*c0+b4*c1+b5*c2+b6*c3+b6*b4+b8*c5 + 16;\n            src_r0r1_16x8b = _mm_unpacklo_epi32(src_r0_16x8b,src_r1_16x8b);\n\n            res_r0r1_t1_8x16b = _mm_srai_epi16(res_r0r1_t1_8x16b, 5);                   //shifting right by 5 bits.\n\n            res_r0r1_16x8b = _mm_packus_epi16(res_r0r1_t1_8x16b, res_r0r1_t1_8x16b);\n            res_r0r1_16x8b = _mm_avg_epu8(src_r0r1_16x8b, res_r0r1_16x8b);              //computing q-pel\n\n            *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(res_r0r1_16x8b);\n            res_r0r1_16x8b = _mm_srli_si128(res_r0r1_16x8b, 4);\n            *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(res_r0r1_16x8b);\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_pred1 += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else if(wd == 8)\n    {\n        __m128i src_r0_t1_16x8b, src_r1_t1_16x8b;\n\n        __m128i res_r0_t1_8x16b, res_r0_t2_8x16b, res_r0_t3_8x16b;\n        __m128i res_r1_t1_8x16b, res_r1_t2_8x16b, res_r1_t3_8x16b;\n        __m128i res_r0_16x8b, res_r1_16x8b;\n\n        //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n        //Row1 : b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n\n        do\n        {\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                      //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n            src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));         //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                      //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                      //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n            res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff0_1_16x8b);    //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                     //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n            res_r1_t1_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff0_1_16x8b);    //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n                                                                                     //b4*c0+b5*c1 b5*c0+b6*c1 b6*c0+b7*c1 b7*c0+b8*c1\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                          //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                          //b2 b3 b4 b5 b6 b7 b8 b9....b15 0 0\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                  //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                  //b3 b4 b5 b6 b7 b8 b9....b15 0  0  0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8 a8 a9 a9 a10\n\n            res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b);    //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                     //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n            res_r1_t2_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff2_3_16x8b);    //b2*c2+b3*c3 b3*c2+b4*c3 b2*c4+b5*c3 b5*c2+b6*c3\n                                                                                     //b6*c2+b7*c3 b7*c2+b8*c3 b8*c2+b9*c3 b9*c2+b10*c3\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                          //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                          //b4 b5 b6 b7 b8 b9....b15 0  0  0  0\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                  //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                  //b5 b6 b7 b8 b9....b15 0  0  0  0  0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b4 b5 b5 b6 b6 b7 b7 b8 b8 b9 b9 b10 b10 b11 b11 b12\n\n            res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b);    //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                     //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n            res_r1_t3_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff4_5_16x8b);    //b4*c4+b5*c5 b5*c4+b6*c5 b6*c4+b7*c5 b7*c4+b8*c5\n                                                                                     //b8*c4+b9*c5 b9*c4+b10*c5 b10*c4+b11*c5 b11*c4+b12*c5\n            src_r0_16x8b = _mm_loadl_epi64((__m128i *)pu1_pred1);\n            src_r1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred1 + src_strd));\n\n            res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n            res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t2_8x16b);\n            res_r0_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_r0_t3_8x16b);\n            res_r1_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_r1_t3_8x16b);\n            res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n            res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t3_8x16b);\n\n            res_r0_t1_8x16b = _mm_srai_epi16(res_r0_t1_8x16b, 5);\n            res_r1_t1_8x16b = _mm_srai_epi16(res_r1_t1_8x16b, 5);                    //shifting right by 5 bits.\n\n            res_r0_16x8b = _mm_packus_epi16(res_r0_t1_8x16b, res_r0_t1_8x16b);\n            res_r1_16x8b = _mm_packus_epi16(res_r1_t1_8x16b, res_r1_t1_8x16b);\n\n            res_r0_16x8b = _mm_avg_epu8(src_r0_16x8b, res_r0_16x8b);\n            res_r1_16x8b = _mm_avg_epu8(src_r1_16x8b, res_r1_16x8b);                 //computing q-pel\n\n            _mm_storel_epi64((__m128i *)pu1_dst, res_r0_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), res_r1_16x8b);\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_pred1 += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else // wd == 16\n    {\n        __m128i src_r0_t1_16x8b, src_r1_t1_16x8b;\n\n        __m128i res_r0_t1_8x16b, res_r0_t2_8x16b, res_r0_t3_8x16b;\n        __m128i res_r1_t1_8x16b, res_r1_t2_8x16b, res_r1_t3_8x16b;\n        __m128i res_16x8b;\n\n        //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n        //Row0 :                         b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n        //b0 is same a8. Similarly other bn pixels are same as a(n+8) pixels.\n\n        do\n        {\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                      //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n            src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 8));                //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                      //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                      //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n            res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff0_1_16x8b);    //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                     //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n            res_r1_t1_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff0_1_16x8b);    //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n                                                                                     //b4*c0+b5*c1 b5*c0+b6*c1 b6*c0+b7*c1 b7*c0+b8*c1\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                          //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                          //b2 b3 b4 b5 b6 b7 b8 b9....b15 0 0\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                  //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                  //b3 b4 b5 b6 b7 b8 b9....b15 0  0  0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8 a8 a9 a9 a10\n\n            res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b);    //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                     //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n            res_r1_t2_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff2_3_16x8b);    //b2*c2+b3*c3 b3*c2+b4*c3 b2*c4+b5*c3 b5*c2+b6*c3\n                                                                                     //b6*c2+b7*c3 b7*c2+b8*c3 b8*c2+b9*c3 b9*c2+b10*c3\n\n            src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                          //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n            src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                          //b4 b5 b6 b7 b8 b9....b15 0  0  0  0\n\n            src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                  //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n            src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                  //b5 b6 b7 b8 b9....b15 0  0  0  0  0\n\n            src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n            src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b4 b5 b5 b6 b6 b7 b7 b8 b8 b9 b9 b10 b10 b11 b11 b12\n\n            res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b);    //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                     //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n            res_r1_t3_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff4_5_16x8b);    //b4*c4+b5*c5 b5*c4+b6*c5 b6*c4+b7*c5 b7*c4+b8*c5\n                                                                                     //b8*c4+b9*c5 b9*c4+b10*c5 b10*c4+b11*c5 b11*c4+b12*c5\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_pred1);\n\n            res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n            res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t2_8x16b);\n            res_r0_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_r0_t3_8x16b);\n            res_r1_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_r1_t3_8x16b);\n            res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n            res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t3_8x16b);\n\n            res_r0_t1_8x16b = _mm_srai_epi16(res_r0_t1_8x16b, 5);\n            res_r1_t1_8x16b = _mm_srai_epi16(res_r1_t1_8x16b, 5);                    //shifting right by 5 bits\n\n            res_16x8b = _mm_packus_epi16(res_r0_t1_8x16b, res_r1_t1_8x16b);\n            res_16x8b = _mm_avg_epu8(src_r0_16x8b, res_16x8b);                       //computing q-pel\n\n            _mm_storeu_si128((__m128i *)pu1_dst, res_16x8b);\n\n            ht--;\n            pu1_src += src_strd;\n            pu1_pred1 += src_strd;\n            pu1_dst += dst_strd;\n        }\n        while(ht > 0);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_inter_pred_luma_vert_qpel_ssse3                    */\n/*                                                                           */\n/*  Description   : This function implements a six-tap filter vertically on  */\n/*                  ht x wd block and averages the values with the source    */\n/*                  pixels to calculate vertical quarter-pel as mentioned in */\n/*                  sec. 8.4.2.2.1 titled \"Luma sample interpolation         */\n/*                  process\". (ht,wd) can be (4,4), (8,4), (4,8), (8,8),     */\n/*                  (16,8), (8,16) or (16,16).                               */\n/*                                                                           */\n/*  Inputs        : puc_src  - pointer to source                             */\n/*                  puc_dst  - pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                  pu1_tmp  - pointer to temporary buffer                   */\n/*                  dydx     - x and y reference offset for q-pel            */\n/*                             calculations                                  */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_inter_pred_luma_vert_qpel_ssse3(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ht,\n                                           WORD32 wd,\n                                           UWORD8* pu1_tmp,\n                                           WORD32 dydx)\n{\n    WORD32 y_offset;\n    UWORD8 *pu1_pred1;\n\n\n    __m128i src_r0_16x8b, src_r1_16x8b, src_r2_16x8b, src_r3_16x8b, src_r4_16x8b;\n    __m128i src_r5_16x8b, src_r6_16x8b;\n    __m128i src_r0r1_16x8b, src_r2r3_16x8b, src_r4r5_16x8b;\n    __m128i res_16x8b, res_t1_8x16b, res_t2_8x16b, res_t3_8x16b;\n\n    __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n    __m128i const_val16_8x16b;\n\n    UNUSED(pu1_tmp);\n    y_offset = dydx & 0xf;\n\n    coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01); //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n    coeff2_3_16x8b = _mm_set1_epi32(0x14141414); //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n    coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB); //c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5 c4 c5\n                                                 //c0 = c5 = 1, c1 = c4 = -5, c2 = c3 = 20\n\n    pu1_pred1 = pu1_src + (y_offset >> 3) * src_strd;\n\n    const_val16_8x16b = _mm_set1_epi16(16);\n\n    pu1_src -= src_strd << 1; // the filter input starts from x[-2] (till x[3])\n\n    if(wd == 4)\n    {\n        //Epilogue: Load all the pred rows except sixth and seventh row\n        //          for the first and second row processing.\n        src_r0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r1_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r2_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r3_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r4_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n\n        src_r0_16x8b = _mm_unpacklo_epi32(src_r0_16x8b, src_r1_16x8b);\n        src_r1_16x8b = _mm_unpacklo_epi32(src_r1_16x8b, src_r2_16x8b);\n        src_r2_16x8b = _mm_unpacklo_epi32(src_r2_16x8b, src_r3_16x8b);\n        src_r3_16x8b = _mm_unpacklo_epi32(src_r3_16x8b, src_r4_16x8b);\n\n        do\n        {\n            src_r5_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n            src_r6_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd));\n\n            src_r4_16x8b = _mm_unpacklo_epi32(src_r4_16x8b, src_r5_16x8b);\n            src_r5_16x8b = _mm_unpacklo_epi32(src_r5_16x8b, src_r6_16x8b);\n\n            src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n            src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n            src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            src_r0_16x8b = _mm_loadl_epi64((__m128i *)pu1_pred1);\n            src_r1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred1 + src_strd));\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n\n            src_r0r1_16x8b = _mm_unpacklo_epi32(src_r0_16x8b,src_r1_16x8b);\n\n            res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            res_16x8b = _mm_packus_epi16(res_t1_8x16b, res_t1_8x16b);\n\n            res_16x8b = _mm_avg_epu8(src_r0r1_16x8b, res_16x8b); //computing q-pel\n\n            *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(res_16x8b);\n            res_16x8b = _mm_srli_si128(res_16x8b, 4);\n            *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(res_16x8b);\n\n            src_r0_16x8b = src_r2_16x8b;\n            src_r1_16x8b = src_r3_16x8b;\n            src_r2_16x8b = src_r4_16x8b;\n            src_r3_16x8b = src_r5_16x8b;\n            src_r4_16x8b = src_r6_16x8b;\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_pred1 += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n\n    else if(wd == 8)\n    {\n        //Epilogue: Load all the pred rows except sixth and seventh row\n        //          for the first and second row processing.\n        src_r0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r1_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r2_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r3_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r4_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n        pu1_src += src_strd;\n\n        src_r0_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);\n        src_r1_16x8b = _mm_unpacklo_epi64(src_r1_16x8b, src_r2_16x8b);\n        src_r2_16x8b = _mm_unpacklo_epi64(src_r2_16x8b, src_r3_16x8b);\n        src_r3_16x8b = _mm_unpacklo_epi64(src_r3_16x8b, src_r4_16x8b);\n\n        do\n        {\n            src_r5_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n            src_r6_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd));\n\n            src_r4_16x8b = _mm_unpacklo_epi64(src_r4_16x8b, src_r5_16x8b);\n            src_r5_16x8b = _mm_unpacklo_epi64(src_r5_16x8b, src_r6_16x8b);\n\n            src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n            src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n            src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            src_r0r1_16x8b = _mm_loadl_epi64((__m128i *)pu1_pred1);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n\n            res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            res_16x8b = _mm_packus_epi16(res_t1_8x16b, res_t1_8x16b);\n            res_16x8b = _mm_avg_epu8(src_r0r1_16x8b, res_16x8b); //computing q-pel\n\n            _mm_storel_epi64((__m128i *)pu1_dst, res_16x8b);\n\n            src_r0r1_16x8b = _mm_unpackhi_epi8(src_r0_16x8b, src_r1_16x8b);\n            src_r2r3_16x8b = _mm_unpackhi_epi8(src_r2_16x8b, src_r3_16x8b);\n            src_r4r5_16x8b = _mm_unpackhi_epi8(src_r4_16x8b, src_r5_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            src_r0r1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred1 + src_strd));\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n\n            res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            res_16x8b = _mm_packus_epi16(res_t1_8x16b, res_t1_8x16b);\n            res_16x8b = _mm_avg_epu8(src_r0r1_16x8b, res_16x8b); //computing q-pel\n\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), res_16x8b);\n\n            src_r0_16x8b = src_r2_16x8b;\n            src_r1_16x8b = src_r3_16x8b;\n            src_r2_16x8b = src_r4_16x8b;\n            src_r3_16x8b = src_r5_16x8b;\n            src_r4_16x8b = src_r6_16x8b;\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_pred1 += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else // wd == 16\n    {\n        __m128i res_t0_8x16b;\n\n        //Epilogue: Load all the pred rows except sixth and seventh row\n        //          for the first and second row processing.\n        src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r1_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r2_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r3_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        pu1_src += src_strd;\n        src_r4_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        pu1_src += src_strd;\n\n        do\n        {\n            src_r5_16x8b  = _mm_loadu_si128((__m128i *)pu1_src);\n            src_r6_16x8b  = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));\n\n            src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n            src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n            src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n\n            res_t0_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            src_r0r1_16x8b = _mm_unpackhi_epi8(src_r0_16x8b, src_r1_16x8b);\n            src_r2r3_16x8b = _mm_unpackhi_epi8(src_r2_16x8b, src_r3_16x8b);\n            src_r4r5_16x8b = _mm_unpackhi_epi8(src_r4_16x8b, src_r5_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            src_r0r1_16x8b = _mm_loadu_si128((__m128i *)pu1_pred1);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n\n            res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            res_16x8b = _mm_packus_epi16(res_t0_8x16b, res_t1_8x16b);\n            res_16x8b = _mm_avg_epu8(src_r0r1_16x8b, res_16x8b); //computing q-pel\n\n            _mm_storeu_si128((__m128i *)pu1_dst, res_16x8b);\n\n            src_r0r1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r2_16x8b);\n            src_r2r3_16x8b = _mm_unpacklo_epi8(src_r3_16x8b, src_r4_16x8b);\n            src_r4r5_16x8b = _mm_unpacklo_epi8(src_r5_16x8b, src_r6_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n\n            res_t0_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            src_r0r1_16x8b = _mm_unpackhi_epi8(src_r1_16x8b, src_r2_16x8b);\n            src_r2r3_16x8b = _mm_unpackhi_epi8(src_r3_16x8b, src_r4_16x8b);\n            src_r4r5_16x8b = _mm_unpackhi_epi8(src_r5_16x8b, src_r6_16x8b);\n\n            res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n            res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n            res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n            src_r0r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred1 + src_strd));\n\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n            res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n            res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n\n            res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n            res_16x8b = _mm_packus_epi16(res_t0_8x16b, res_t1_8x16b);\n            res_16x8b = _mm_avg_epu8(src_r0r1_16x8b, res_16x8b); //computing q-pel\n\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res_16x8b);\n\n            src_r0_16x8b = src_r2_16x8b;\n            src_r1_16x8b = src_r3_16x8b;\n            src_r2_16x8b = src_r4_16x8b;\n            src_r3_16x8b = src_r5_16x8b;\n            src_r4_16x8b = src_r6_16x8b;\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_pred1 += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3          */\n/*                                                                           */\n/*  Description   : This function implements a six-tap filter vertically and */\n/*                  horizontally on ht x wd block separately and averages    */\n/*                  the two sets of values to calculate values at (1/4,1/4), */\n/*                  (1/4, 3/4), (3/4, 1/4) or (3/4, 3/4) as mentioned in     */\n/*                  sec. 8.4.2.2.1 titled \"Luma sample interpolation         */\n/*                  process\". (ht,wd) can be (4,4), (8,4), (4,8), (8,8),     */\n/*                  (16,8), (8,16) or (16,16).                               */\n/*                                                                           */\n/*  Inputs        : puc_src  - pointer to source                             */\n/*                  puc_dst  - pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                  pu1_tmp  - pointer to temporary buffer                   */\n/*                  dydx     - x and y reference offset for q-pel            */\n/*                             calculations                                  */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3(UWORD8 *pu1_src,\n                                                     UWORD8 *pu1_dst,\n                                                     WORD32 src_strd,\n                                                     WORD32 dst_strd,\n                                                     WORD32 ht,\n                                                     WORD32 wd,\n                                                     UWORD8* pu1_tmp,\n                                                     WORD32 dydx)\n{\n    WORD32 ht_temp;\n    UWORD8 *pu1_pred_vert,*pu1_pred_horiz;\n    UWORD8 *pu1_tmp1, *pu1_tmp2;\n    WORD32 x_offset, y_offset;\n\n    __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n    __m128i const_val16_8x16b;\n\n    pu1_tmp1 = pu1_tmp;\n\n    dydx &= 0xf;\n    ht_temp = ht;\n    x_offset = dydx & 0x3;\n    y_offset = dydx >> 2;\n    pu1_tmp2 = pu1_tmp1;\n\n    pu1_pred_vert  = pu1_src + (x_offset >> 1) - 2*src_strd;\n    pu1_pred_horiz = pu1_src + (y_offset >> 1) * src_strd - 2;\n    //the filter input starts from x[-2] (till x[3])\n\n    coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01);  //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n    coeff2_3_16x8b = _mm_set1_epi32(0x14141414);  //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n    coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB);  //c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5\n                                                  //c0 = c5 = 1, c1 = c4 = -5, c2 = c3 = 20\n    const_val16_8x16b = _mm_set1_epi16(16);\n\n    if(wd == 4)\n    {\n        //vertical q-pel filter\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r2_16x8b, src_r3_16x8b, src_r4_16x8b;\n            __m128i src_r5_16x8b, src_r6_16x8b;\n            __m128i src_r0r1_16x8b, src_r2r3_16x8b, src_r4r5_16x8b;\n\n            __m128i res_r0r1_16x8b, res_t1_8x16b, res_t2_8x16b, res_t3_8x16b;\n\n            //epilogue: Load all the pred rows except sixth  and seventh row for the\n            //first and second row processing.\n            src_r0_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert = pu1_pred_vert + src_strd;\n\n            src_r1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert = pu1_pred_vert + src_strd;\n            src_r0_16x8b = _mm_unpacklo_epi32(src_r0_16x8b, src_r1_16x8b);\n\n            src_r2_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert = pu1_pred_vert + src_strd;\n            src_r1_16x8b = _mm_unpacklo_epi32(src_r1_16x8b, src_r2_16x8b);\n\n            src_r3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert = pu1_pred_vert + src_strd;\n            src_r2_16x8b = _mm_unpacklo_epi32(src_r2_16x8b, src_r3_16x8b);\n\n            src_r4_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert = pu1_pred_vert + src_strd;\n            src_r3_16x8b = _mm_unpacklo_epi32(src_r3_16x8b, src_r4_16x8b);\n\n            //Core Loop: Process all the rows.\n            do\n            {\n                src_r5_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n                src_r4_16x8b = _mm_unpacklo_epi32(src_r4_16x8b, src_r5_16x8b);\n\n                src_r6_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert + src_strd));\n                src_r5_16x8b = _mm_unpacklo_epi32(src_r5_16x8b, src_r6_16x8b);\n\n                src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n                src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n                src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n                res_r0r1_16x8b = _mm_packus_epi16(res_t1_8x16b, res_t1_8x16b);\n\n                _mm_storel_epi64((__m128i *)pu1_tmp1, res_r0r1_16x8b);\n\n                src_r0_16x8b = src_r2_16x8b;\n                src_r1_16x8b = src_r3_16x8b;\n                src_r2_16x8b = src_r4_16x8b;\n                src_r3_16x8b = src_r5_16x8b;\n                src_r4_16x8b = src_r6_16x8b;\n\n                ht_temp -= 2;\n                pu1_pred_vert += src_strd << 1;\n                pu1_tmp1 += 8;\n            }\n            while(ht_temp > 0);\n        }\n\n        //horizontal q-pel filter\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b;\n            __m128i src_r0_sht_16x8b, src_r1_sht_16x8b;\n            __m128i src_r0r1_vpel_16x8b, src_r0r1_t1_16x8b;\n\n            __m128i res_r0r1_t1_8x16b, res_r0r1_t2_8x16b, res_r0r1_t3_8x16b;\n            __m128i res_r0r1_16x8b;\n\n            //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n            //Row1 : b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n\n            do\n            {\n                src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_pred_horiz);                  //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n                src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_horiz + src_strd));     //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n                src_r0r1_vpel_16x8b = _mm_loadl_epi64((__m128i *)pu1_tmp2);\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                          //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                          //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n                src_r0_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);            //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n                src_r1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);            //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n                src_r0r1_t1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);          //a0 a1 a1 a2 a2 a3 a3 a4 b0 b1 b1 b2 b2 b3 b3 b4\n                res_r0r1_t1_8x16b = _mm_maddubs_epi16(src_r0r1_t1_16x8b, coeff0_1_16x8b);    //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                             //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 4);                              //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 4);                              //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8  0  0  0  0\n\n                src_r0r1_t1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);          //a2 a3 a3 a4 a4 a5 a5 a6 b2 b3 b3 b4 b4 b5 b5 b6\n                res_r0r1_t2_8x16b = _mm_maddubs_epi16(src_r0r1_t1_16x8b, coeff2_3_16x8b);    //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                             //b2*c2+b3*c3 b3*c2+b4*c3 b4*c2+b5*c3 b5*c2+b6*c3\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 4);                              //a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0  0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 4);                              //b4 b5 b5 b6 b6 b7 b7 b8  0  0  0  0  0  0  0  0\n\n                src_r0r1_t1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);          //a4 a5 a5 a6 a6 a7 a7 a8 b4 b5 b5 b6 b6 b7 b7 b8\n                res_r0r1_t3_8x16b = _mm_maddubs_epi16(src_r0r1_t1_16x8b, coeff4_5_16x8b);    //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                             //b4*c4+b5*c5 b5*c4+b6*c5 b4*c6+b7*c5 b7*c4+b8*c5\n\n                res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t1_8x16b, res_r0r1_t2_8x16b);\n                res_r0r1_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_r0r1_t3_8x16b);\n                res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t1_8x16b, res_r0r1_t3_8x16b);     //a0*c0+a1*c1+a2*c2+a3*c3+a4*a4+a5*c5 + 15;\n                                                                                             //a1*c0+a2*c1+a2*c2+a3*c3+a5*a4+a6*c5 + 15;\n                                                                                             //a2*c0+a3*c1+a4*c2+a5*c3+a6*a4+a7*c5 + 15;\n                                                                                             //a3*c0+a4*c1+a5*c2+a6*c3+a6*a4+a8*c5 + 15;\n                                                                                             //b0*c0+b1*c1+b2*c2+b3*c3+b4*b4+b5*c5 + 15;\n                                                                                             //b1*c0+b2*c1+b2*c2+b3*c3+b5*b4+b6*c5 + 15;\n                                                                                             //b2*c0+b3*c1+b4*c2+b5*c3+b6*b4+b7*c5 + 15;\n                                                                                             //b3*c0+b4*c1+b5*c2+b6*c3+b6*b4+b8*c5 + 15;\n\n                res_r0r1_t1_8x16b = _mm_srai_epi16(res_r0r1_t1_8x16b, 5);                    //shifting right by 5 bits.\n\n                res_r0r1_16x8b = _mm_packus_epi16(res_r0r1_t1_8x16b,res_r0r1_t1_8x16b);\n\n                res_r0r1_16x8b = _mm_avg_epu8(res_r0r1_16x8b,src_r0r1_vpel_16x8b);\n\n                *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(res_r0r1_16x8b);\n                res_r0r1_16x8b = _mm_srli_si128(res_r0r1_16x8b, 4);\n                *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(res_r0r1_16x8b);\n\n                ht -= 2;\n                pu1_pred_horiz += src_strd << 1;\n                pu1_tmp2 += 8;\n                pu1_dst += dst_strd << 1;\n            }\n            while(ht > 0);\n        }\n    }\n    else if(wd == 8)\n    {\n        //vertical q-pel filter\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r2_16x8b, src_r3_16x8b;\n            __m128i src_r4_16x8b, src_r5_16x8b, src_r6_16x8b;\n            __m128i src_r0r1_16x8b, src_r2r3_16x8b, src_r4r5_16x8b;\n\n            __m128i res_16x8b, res_t1_8x16b, res_t2_8x16b, res_t3_8x16b;\n\n            //epilogue: Load all the pred rows except sixth  and seventh row for the\n            //first and second row processing.\n            src_r0_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert = pu1_pred_vert + src_strd;\n\n            src_r1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert = pu1_pred_vert + src_strd;\n            src_r0_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);\n\n            src_r2_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert = pu1_pred_vert + src_strd;\n            src_r1_16x8b = _mm_unpacklo_epi64(src_r1_16x8b, src_r2_16x8b);\n\n            src_r3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert = pu1_pred_vert + src_strd;\n            src_r2_16x8b = _mm_unpacklo_epi64(src_r2_16x8b, src_r3_16x8b);\n\n            src_r4_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert = pu1_pred_vert + src_strd;\n            src_r3_16x8b = _mm_unpacklo_epi64(src_r3_16x8b, src_r4_16x8b);\n\n            //Core Loop: Process all the rows.\n            do\n            {\n                src_r5_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert));\n                src_r4_16x8b = _mm_unpacklo_epi64(src_r4_16x8b, src_r5_16x8b);\n\n                src_r6_16x8b = _mm_loadl_epi64((__m128i *)(pu1_pred_vert + src_strd));\n                src_r5_16x8b = _mm_unpacklo_epi64(src_r5_16x8b, src_r6_16x8b);\n\n                src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n                src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n                src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n                res_16x8b = _mm_packus_epi16(res_t1_8x16b, res_t1_8x16b);\n\n                _mm_storel_epi64((__m128i *)(pu1_tmp1), res_16x8b);\n\n                src_r0r1_16x8b = _mm_unpackhi_epi8(src_r0_16x8b, src_r1_16x8b);\n                src_r2r3_16x8b = _mm_unpackhi_epi8(src_r2_16x8b, src_r3_16x8b);\n                src_r4r5_16x8b = _mm_unpackhi_epi8(src_r4_16x8b, src_r5_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n                res_16x8b = _mm_packus_epi16(res_t1_8x16b, res_t1_8x16b);\n\n                _mm_storel_epi64((__m128i *)(pu1_tmp1 + 8), res_16x8b);\n\n                src_r0_16x8b = src_r2_16x8b;\n                src_r1_16x8b = src_r3_16x8b;\n                src_r2_16x8b = src_r4_16x8b;\n                src_r3_16x8b = src_r5_16x8b;\n                src_r4_16x8b = src_r6_16x8b;\n\n                ht_temp -= 2;\n                pu1_pred_vert += src_strd << 1;\n                pu1_tmp1 += 16;\n            }\n            while(ht_temp > 0);\n        }\n\n        //horizontal q-pel filter\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r0_sht_16x8b, src_r1_sht_16x8b;\n            __m128i src_r0_t1_16x8b, src_r1_t1_16x8b;\n            __m128i src_r0_vpel_16x8b, src_r1_vpel_16x8b;\n\n            __m128i res_r0_t1_8x16b, res_r0_t2_8x16b, res_r0_t3_8x16b;\n            __m128i res_r1_t1_8x16b, res_r1_t2_8x16b, res_r1_t3_8x16b, res_16x8b;\n\n            //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n            //Row1 : b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n\n            do\n            {\n                src_r0_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_horiz));               //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n                src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_horiz + src_strd));    //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n                src_r0_vpel_16x8b = _mm_loadl_epi64((__m128i *)(pu1_tmp2));                //a2 a3 a4 a5 a6 a7 a8....a15 0 or\n                                                                                           //a3 a4 a5 a6 a7 a8 a9....a15 0\n                src_r1_vpel_16x8b = _mm_loadl_epi64((__m128i *)(pu1_tmp2 + 8));\n                                                                                           //b2 b3 b4 b5 b6 b7 b8....b15 0 or\n                                                                                           //b3 b4 b5 b6 b7 b8 b9....b15 0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                        //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                        //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);       //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);       //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n                res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff0_1_16x8b);      //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                           //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n                res_r1_t1_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff0_1_16x8b);      //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n                                                                                           //b4*c0+b5*c1 b5*c0+b6*c1 b6*c0+b7*c1 b7*c0+b8*c1\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                            //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                            //b2 b3 b4 b5 b6 b7 b8 b9....b15 0 0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                    //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                    //b3 b4 b5 b6 b7 b8 b9....b15 0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);       //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);       //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8 a8 a9 a9 a10\n\n                res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b);      //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                           //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n                res_r1_t2_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff2_3_16x8b);      //b2*c2+b3*c3 b3*c2+b4*c3 b2*c4+b5*c3 b5*c2+b6*c3\n                                                                                           //b6*c2+b7*c3 b7*c2+b8*c3 b8*c2+b9*c3 b9*c2+b10*c3\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                            //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                            //b4 b5 b6 b7 b8 b9....b15 0  0  0  0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                    //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                    //b5 b6 b7 b8 b9....b15 0  0  0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);       //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);       //b4 b5 b5 b6 b6 b7 b7 b8 b8 b9 b9 b10 b10 b11 b11 b12\n\n                res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b);      //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                           //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n                res_r1_t3_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff4_5_16x8b);      //b4*c4+b5*c5 b5*c4+b6*c5 b6*c4+b7*c5 b7*c4+b8*c5\n                                                                                           //b8*c4+b9*c5 b9*c4+b10*c5 b10*c4+b11*c5 b11*c4+b12*c5\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n                res_r0_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_r0_t3_8x16b);\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n                res_r0_t1_8x16b = _mm_srai_epi16(res_r0_t1_8x16b, 5);                      //shifting right by 5 bits.\n\n                res_16x8b = _mm_packus_epi16(res_r0_t1_8x16b, res_r0_t1_8x16b);\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_r0_vpel_16x8b);\n\n                _mm_storel_epi64((__m128i *)(pu1_dst), res_16x8b);\n\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t2_8x16b);\n                res_r1_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_r1_t3_8x16b);\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t3_8x16b);\n                res_r1_t1_8x16b = _mm_srai_epi16(res_r1_t1_8x16b, 5);                      //shifting right by 5 bits.\n\n                res_16x8b = _mm_packus_epi16(res_r1_t1_8x16b, res_r1_t1_8x16b);\n                res_16x8b = _mm_avg_epu8(res_16x8b,src_r1_vpel_16x8b);\n\n                _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), res_16x8b);\n\n                ht -= 2;\n                pu1_pred_horiz += src_strd << 1;\n                pu1_dst += dst_strd << 1;\n                pu1_tmp2 += 16;\n            }\n            while(ht > 0);\n        }\n    }\n    else // wd == 16\n    {\n        //vertical q-pel filter\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r2_16x8b, src_r3_16x8b;\n            __m128i src_r4_16x8b, src_r5_16x8b, src_r6_16x8b;\n            __m128i src_r0r1_16x8b, src_r2r3_16x8b, src_r4r5_16x8b;\n\n            __m128i res_t0_8x16b, res_t1_8x16b, res_t2_8x16b, res_t3_8x16b;\n            __m128i res_16x8b;\n\n            //epilogue: Load all the pred rows except sixth  and seventh row for the\n            //first and second row processing.\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert =  pu1_pred_vert + src_strd;\n            src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert =  pu1_pred_vert + src_strd;\n            src_r2_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert =  pu1_pred_vert + src_strd;\n            src_r3_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert =  pu1_pred_vert + src_strd;\n            src_r4_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_vert));\n            pu1_pred_vert =  pu1_pred_vert + src_strd;\n\n            //Core Loop: Process all the rows.\n            do\n            {\n                src_r5_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_vert));\n                src_r6_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_vert + src_strd));\n\n                src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n                src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n                src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n                res_t0_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n                src_r0r1_16x8b = _mm_unpackhi_epi8(src_r0_16x8b, src_r1_16x8b);\n                src_r2r3_16x8b = _mm_unpackhi_epi8(src_r2_16x8b, src_r3_16x8b);\n                src_r4r5_16x8b = _mm_unpackhi_epi8(src_r4_16x8b, src_r5_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n                res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n                res_16x8b = _mm_packus_epi16(res_t0_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pu1_tmp1), res_16x8b);\n\n                src_r0r1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r2_16x8b);\n                src_r2r3_16x8b = _mm_unpacklo_epi8(src_r3_16x8b, src_r4_16x8b);\n                src_r4r5_16x8b = _mm_unpacklo_epi8(src_r5_16x8b, src_r6_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n                res_t0_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n                src_r0r1_16x8b = _mm_unpackhi_epi8(src_r1_16x8b, src_r2_16x8b);\n                src_r2r3_16x8b = _mm_unpackhi_epi8(src_r3_16x8b, src_r4_16x8b);\n                src_r4r5_16x8b = _mm_unpackhi_epi8(src_r5_16x8b, src_r6_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_t3_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t3_8x16b);\n                res_t1_8x16b = _mm_srai_epi16(res_t1_8x16b, 5); //shifting right by 5 bits.\n\n                res_16x8b = _mm_packus_epi16(res_t0_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pu1_tmp1 + 16), res_16x8b);\n\n                src_r0_16x8b = src_r2_16x8b;\n                src_r1_16x8b = src_r3_16x8b;\n                src_r2_16x8b = src_r4_16x8b;\n                src_r3_16x8b = src_r5_16x8b;\n                src_r4_16x8b = src_r6_16x8b;\n\n                ht_temp -= 2;\n                pu1_pred_vert += src_strd << 1;\n                pu1_tmp1 += 32;\n            }\n            while(ht_temp > 0);\n        }\n        //horizontal q-pel filter\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r0_sht_16x8b, src_r1_sht_16x8b;\n            __m128i src_r0_t1_16x8b, src_r1_t1_16x8b;\n            __m128i src_vpel_16x8b;\n\n            __m128i res_r0_t1_8x16b, res_r0_t2_8x16b, res_r0_t3_8x16b;\n            __m128i res_r1_t1_8x16b, res_r1_t2_8x16b, res_r1_t3_8x16b;\n            __m128i res_16x8b;\n\n            //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n            //Row0 :                         b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n            //b0 is same a8. Similarly other bn pixels are same as a(n+8) pixels.\n\n            do\n            {\n                src_r0_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_horiz));             //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n                src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_pred_horiz + 8));         //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n                src_vpel_16x8b = _mm_loadu_si128((__m128i *)(pu1_tmp2));\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                      //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                      //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n                res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff0_1_16x8b);    //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                         //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n                res_r1_t1_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff0_1_16x8b);    //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n                                                                                         //b4*c0+b5*c1 b5*c0+b6*c1 b6*c0+b7*c1 b7*c0+b8*c1\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                          //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                          //b2 b3 b4 b5 b6 b7 b8 b9....b15 0 0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                  //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                  //b3 b4 b5 b6 b7 b8 b9....b15 0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8 a8 a9 a9 a10\n\n                res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b);    //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                         //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n                res_r1_t2_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff2_3_16x8b);    //b2*c2+b3*c3 b3*c2+b4*c3 b2*c4+b5*c3 b5*c2+b6*c3\n                                                                                         //b6*c2+b7*c3 b7*c2+b8*c3 b8*c2+b9*c3 b9*c2+b10*c3\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                          //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                          //b4 b5 b6 b7 b8 b9....b15 0  0  0  0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                  //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                  //b5 b6 b7 b8 b9....b15 0  0  0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);     //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);     //b4 b5 b5 b6 b6 b7 b7 b8 b8 b9 b9 b10 b10 b11 b11 b12\n\n                res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b);    //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                         //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n                res_r1_t3_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff4_5_16x8b);    //b4*c4+b5*c5 b5*c4+b6*c5 b6*c4+b7*c5 b7*c4+b8*c5\n                                                                                         //b8*c4+b9*c5 b9*c4+b10*c5 b10*c4+b11*c5 b11*c4+b12*c5\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n                res_r0_t3_8x16b = _mm_add_epi16(const_val16_8x16b, res_r0_t3_8x16b);\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n                res_r0_t1_8x16b = _mm_srai_epi16(res_r0_t1_8x16b, 5);                    //shifting right by 5 bits.\n\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t2_8x16b);\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t3_8x16b);\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, const_val16_8x16b);\n                res_r1_t1_8x16b = _mm_srai_epi16(res_r1_t1_8x16b, 5);                    //shifting right by 5 bits.\n\n                res_16x8b = _mm_packus_epi16(res_r0_t1_8x16b, res_r1_t1_8x16b);\n\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_vpel_16x8b);\n                _mm_storeu_si128((__m128i *)(pu1_dst), res_16x8b);\n\n                ht --;\n                pu1_pred_horiz  += src_strd;\n                pu1_dst += dst_strd;\n                pu1_tmp2 += 16;\n            }\n            while(ht > 0);\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_inter_pred_luma_horz_qpel_vert_hpel_ssse3          */\n/*                                                                           */\n/*  Description   : This function implements a six-tap filter vertically and */\n/*                  horizontally on ht x wd block separately and averages    */\n/*                  the two sets of values to calculate values at (1/4,1/2), */\n/*                  or (3/4, 1/2) as mentioned in sec. 8.4.2.2.1 titled      */\n/*                  \"Luma sample interpolation process\". (ht,wd) can be      */\n/*                  (4,4), (8,4), (4,8), (8,8), (16,8), (8,16) or (16,16).   */\n/*                                                                           */\n/*  Inputs        : puc_src  - pointer to source                             */\n/*                  puc_dst  - pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                  pu1_tmp  - pointer to temporary buffer                   */\n/*                  dydx     - x and y reference offset for q-pel            */\n/*                             calculations                                  */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_inter_pred_luma_horz_qpel_vert_hpel_ssse3(UWORD8 *pu1_src,\n                                                     UWORD8 *pu1_dst,\n                                                     WORD32 src_strd,\n                                                     WORD32 dst_strd,\n                                                     WORD32 ht,\n                                                     WORD32 wd,\n                                                     UWORD8* pu1_tmp,\n                                                     WORD32 dydx)\n{\n    WORD32 ht_temp;\n    WORD32 x_offset;\n    WORD32 off0,off1, off2, off3, off4, off5;\n    WORD16 *pi2_temp1,*pi2_temp2,*pi2_temp3;\n\n    ht_temp = ht;\n    x_offset = dydx & 0x3;\n    pi2_temp1 = (WORD16 *)pu1_tmp;\n    pi2_temp2 = pi2_temp1;\n    pi2_temp3 = pi2_temp1 + (x_offset >> 1);\n\n    pu1_src -= 2 * src_strd;\n    pu1_src -= 2;\n    pi2_temp3 += 2;\n    //the filter input starts from x[-2] (till x[3])\n\n    if(wd == 4)\n    {\n        //vertical half-pel\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r2_16x8b, src_r3_16x8b, src_r4_16x8b;\n            __m128i src_r5_16x8b, src_r6_16x8b;\n            __m128i src_r0r1_16x8b, src_r2r3_16x8b, src_r4r5_16x8b;\n\n            __m128i res_t1_8x16b, res_t2_8x16b, res_t3_8x16b;\n\n            __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n\n            coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01);  //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n            coeff2_3_16x8b = _mm_set1_epi32(0x14141414);  //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n            coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB);  //c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5\n                                                          //c0 = c5 = 1, c1 = c4 = -5, c2 = c3 = 20\n            off0 = -((src_strd << 2) + src_strd) + 8;\n            off1 = -(src_strd << 2) + 8;\n            off2 = -((src_strd << 1) + src_strd) + 8;\n            off3 = -(src_strd << 1) + 8;\n            off4 = -src_strd + 8;\n            off5 = 8;\n\n            //epilogue: Load all the pred rows except sixth  and seventh row for the\n            //first and second row processing.\n            src_r0_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src));\n            pu1_src =  pu1_src + src_strd;\n\n            src_r1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src));\n            pu1_src =  pu1_src + src_strd;\n\n            src_r2_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src));\n            pu1_src =  pu1_src + src_strd;\n\n            src_r3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src));\n            pu1_src =  pu1_src + src_strd;\n\n            src_r4_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src));\n            pu1_src =  pu1_src + src_strd;\n\n            //Core Loop: Process all the rows.\n            do\n            {\n                src_r5_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src));\n\n                src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n                src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n                src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t2_8x16b, res_t1_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1), res_t1_8x16b);\n\n                pi2_temp1[8] = pu1_src[off0] + pu1_src[off5]\n                                   - (pu1_src[off1] + pu1_src[off4])\n                                   + ((pu1_src[off2] + pu1_src[off3] - pu1_src[off1] - pu1_src[off4]) << 2)\n                                   + ((pu1_src[off2] + pu1_src[off3]) << 4);\n\n                pu1_src = pu1_src + src_strd;\n                pi2_temp1 = pi2_temp1 + 9;\n\n                src_r6_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src));\n\n                src_r0r1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r2_16x8b);\n                src_r2r3_16x8b = _mm_unpacklo_epi8(src_r3_16x8b, src_r4_16x8b);\n                src_r4r5_16x8b = _mm_unpacklo_epi8(src_r5_16x8b, src_r6_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t2_8x16b, res_t1_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1), res_t1_8x16b);\n\n                pi2_temp1[8] = pu1_src[off0] + pu1_src[off5]\n                                   - (pu1_src[off1] + pu1_src[off4])\n                                   + ((pu1_src[off2] + pu1_src[off3] - pu1_src[off1] - pu1_src[off4]) << 2)\n                                   + ((pu1_src[off2] + pu1_src[off3]) << 4);\n\n                ht_temp -= 2;\n                pu1_src = pu1_src + src_strd;\n                pi2_temp1 = pi2_temp1 + 9;\n\n                src_r0_16x8b = src_r2_16x8b;\n                src_r1_16x8b = src_r3_16x8b;\n                src_r2_16x8b = src_r4_16x8b;\n                src_r3_16x8b = src_r5_16x8b;\n                src_r4_16x8b = src_r6_16x8b;\n            }\n            while(ht_temp > 0);\n        }\n\n        //horizontal q-pel\n        {\n            __m128i src_r0_8x16b, src_r1_8x16b, src_r2_8x16b;\n            __m128i src_r3_8x16b, src_r4_8x16b, src_r5_8x16b;\n            __m128i src_r0r1_c0_8x16b, src_r2r3_c0_8x16b, src_r4r5_c0_8x16b;\n            __m128i src_hpel_16x8b, src_hpel_8x16b;\n\n            __m128i res_t1_4x32b, res_t2_4x32b, res_t3_4x32b;\n            __m128i res_8x16b, res_16x8b;\n\n            __m128i coeff0_1_8x16b, coeff2_3_8x16b, coeff4_5_8x16b;\n            __m128i const_val512_4x32b, const_val16_8x16b;\n\n            coeff0_1_8x16b = _mm_set1_epi32(0xFFFB0001);\n            coeff2_3_8x16b = _mm_set1_epi32(0x00140014);\n            coeff4_5_8x16b = _mm_set1_epi32(0x0001FFFB);\n\n            const_val512_4x32b = _mm_set1_epi32(512);\n            const_val16_8x16b = _mm_set1_epi16(16);\n\n            do\n            {\n                src_r0_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp2));\n                src_r1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 1));\n                src_r2_8x16b = _mm_srli_si128(src_r1_8x16b, 2);\n                src_r3_8x16b = _mm_srli_si128(src_r1_8x16b, 4);\n                src_r4_8x16b = _mm_srli_si128(src_r1_8x16b, 6);\n                src_r5_8x16b = _mm_srli_si128(src_r1_8x16b, 8);\n\n                src_r0r1_c0_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_c0_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_c0_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_c0_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_c0_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_c0_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(const_val512_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_t1_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                src_hpel_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp3));\n                src_hpel_8x16b = _mm_add_epi16(src_hpel_8x16b, const_val16_8x16b);\n                src_hpel_8x16b = _mm_srai_epi16(src_hpel_8x16b, 5); //shifting right by 5 bits.\n                src_hpel_16x8b = _mm_packus_epi16(src_hpel_8x16b, src_hpel_8x16b);\n\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_hpel_16x8b);\n\n                *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(res_16x8b);\n\n                ht--;\n                pi2_temp2 = pi2_temp2 + 4 + 5;\n                pi2_temp3 = pi2_temp3 + 4 + 5;\n                pu1_dst = pu1_dst + dst_strd;\n            }\n            while(ht > 0);\n        }\n    }\n    else if(wd == 8)\n    {\n        // vertical half-pel\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r2_16x8b, src_r3_16x8b, src_r4_16x8b;\n            __m128i src_r5_16x8b, src_r6_16x8b;\n            __m128i src_r0r1_16x8b, src_r2r3_16x8b, src_r4r5_16x8b;\n\n            __m128i res_t1_8x16b, res_t2_8x16b, res_t3_8x16b;\n\n            __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n\n            coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01);  //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n            coeff2_3_16x8b = _mm_set1_epi32(0x14141414);  //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n            coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB);  //c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5\n\n            //epilogue: Load all the pred rows except sixth  and seventh row for the\n            //first and second row processing.\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n            pu1_src =  pu1_src + src_strd;\n\n            src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n            pu1_src =  pu1_src + src_strd;\n\n            src_r2_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n            pu1_src =  pu1_src + src_strd;\n\n            src_r3_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n            pu1_src =  pu1_src + src_strd;\n\n            src_r4_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n            pu1_src =  pu1_src + src_strd;\n\n            //Core Loop: Process all the rows.\n            do\n            {\n                src_r5_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n                src_r6_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));\n\n                src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n                src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n                src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1), res_t1_8x16b);\n\n                src_r0r1_16x8b = _mm_unpackhi_epi8(src_r0_16x8b, src_r1_16x8b);\n                src_r2r3_16x8b = _mm_unpackhi_epi8(src_r2_16x8b, src_r3_16x8b);\n                src_r4r5_16x8b = _mm_unpackhi_epi8(src_r4_16x8b, src_r5_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1 + 8), res_t1_8x16b);\n\n                src_r0r1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r2_16x8b);\n                src_r2r3_16x8b = _mm_unpacklo_epi8(src_r3_16x8b, src_r4_16x8b);\n                src_r4r5_16x8b = _mm_unpacklo_epi8(src_r5_16x8b, src_r6_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1 + 8 + 5), res_t1_8x16b);\n\n                src_r0r1_16x8b = _mm_unpackhi_epi8(src_r1_16x8b, src_r2_16x8b);\n                src_r2r3_16x8b = _mm_unpackhi_epi8(src_r3_16x8b, src_r4_16x8b);\n                src_r4r5_16x8b = _mm_unpackhi_epi8(src_r5_16x8b, src_r6_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1 + 8 + 5 + 8), res_t1_8x16b);\n\n                src_r0_16x8b = src_r2_16x8b;\n                src_r1_16x8b = src_r3_16x8b;\n                src_r2_16x8b = src_r4_16x8b;\n                src_r3_16x8b = src_r5_16x8b;\n                src_r4_16x8b = src_r6_16x8b;\n\n                ht_temp -= 2;\n                pu1_src =  pu1_src + (src_strd << 1);\n                pi2_temp1 = pi2_temp1 + (13 << 1);\n            }\n            while(ht_temp > 0);\n        }\n        // horizontal q-pel\n        {\n            __m128i src_r0_8x16b, src_r1_8x16b, src_r2_8x16b, src_r3_8x16b;\n            __m128i src_r4_8x16b, src_r5_8x16b;\n            __m128i src_r0r1_c0_8x16b, src_r2r3_c0_8x16b, src_r4r5_c0_8x16b;\n            __m128i src_r0r1_c1_8x16b, src_r2r3_c1_8x16b, src_r4r5_c1_8x16b;\n            __m128i src_hpel_8x16b, src_hpel_16x8b;\n\n            __m128i res_t0_4x32b, res_t1_4x32b, res_t2_4x32b, res_t3_4x32b;\n            __m128i res_8x16b, res_16x8b;\n\n            __m128i coeff0_1_8x16b, coeff2_3_8x16b, coeff4_5_8x16b;\n            __m128i const_val512_4x32b, const_val16_8x16b;\n\n            coeff0_1_8x16b = _mm_set1_epi32(0xFFFB0001);\n            coeff2_3_8x16b = _mm_set1_epi32(0x00140014);\n            coeff4_5_8x16b = _mm_set1_epi32(0x0001FFFB);\n\n            const_val512_4x32b = _mm_set1_epi32(512);\n            const_val16_8x16b = _mm_set1_epi16(16);\n\n            do\n            {\n                src_r0_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2));\n                src_r1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 1));\n                src_r2_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 2));\n                src_r3_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 3));\n                src_r4_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 4));\n                src_r5_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 5));\n\n                src_r0r1_c0_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_c0_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_c0_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                src_r0r1_c1_8x16b = _mm_unpackhi_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_c1_8x16b = _mm_unpackhi_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_c1_8x16b = _mm_unpackhi_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_c0_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_c0_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_c0_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_c1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_c1_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_c1_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                src_hpel_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp3));\n                src_hpel_8x16b = _mm_add_epi16(src_hpel_8x16b, const_val16_8x16b);\n                src_hpel_8x16b = _mm_srai_epi16(src_hpel_8x16b, 5); //shifting right by 5 bits.\n                src_hpel_16x8b = _mm_packus_epi16(src_hpel_8x16b, src_hpel_8x16b);\n\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_hpel_16x8b);\n\n                _mm_storel_epi64((__m128i *)(pu1_dst), res_16x8b);\n\n                ht--;\n                pi2_temp2 = pi2_temp2 + 8 + 5;\n                pi2_temp3 = pi2_temp3 + 8 + 5;\n                pu1_dst = pu1_dst + dst_strd;\n            }\n            while(ht > 0);\n        }\n    }\n    else // wd == 16\n    {\n        // vertical half-pel\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r2_16x8b, src_r3_16x8b;\n            __m128i src_r4_16x8b, src_r5_16x8b;\n            __m128i src_r0_c2_16x8b, src_r1_c2_16x8b, src_r2_c2_16x8b, src_r3_c2_16x8b;\n            __m128i src_r4_c2_16x8b, src_r5_c2_16x8b;\n            __m128i src_r0r1_16x8b, src_r2r3_16x8b, src_r4r5_16x8b;\n\n            __m128i res_t1_8x16b, res_t2_8x16b, res_t3_8x16b;\n\n            __m128i coeff0_1_16x8b,coeff2_3_16x8b,coeff4_5_16x8b;\n\n            coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01);  //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n            coeff2_3_16x8b = _mm_set1_epi32(0x14141414);  //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n            coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB);  //c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5\n\n            src_r0_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n            src_r0_c2_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 16));\n            pu1_src =  pu1_src + src_strd;\n            src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n            src_r1_c2_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 16));\n            pu1_src =  pu1_src + src_strd;\n            src_r2_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n            src_r2_c2_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 16));\n            pu1_src =  pu1_src + src_strd;\n            src_r3_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n            src_r3_c2_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 16));\n            pu1_src =  pu1_src + src_strd;\n            src_r4_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));\n            src_r4_c2_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 16));\n            pu1_src =  pu1_src + src_strd;\n\n            //Core Loop: Process all the rows.\n            do\n            {\n                src_r5_16x8b  = _mm_loadu_si128((__m128i *)(pu1_src));\n                src_r5_c2_16x8b  = _mm_loadu_si128((__m128i *)(pu1_src + 16));\n\n                src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r1_16x8b);\n                src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_16x8b, src_r3_16x8b);\n                src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_16x8b, src_r5_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1), res_t1_8x16b);\n\n                src_r0r1_16x8b = _mm_unpackhi_epi8(src_r0_16x8b, src_r1_16x8b);\n                src_r2r3_16x8b = _mm_unpackhi_epi8(src_r2_16x8b, src_r3_16x8b);\n                src_r4r5_16x8b = _mm_unpackhi_epi8(src_r4_16x8b, src_r5_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1 + 8), res_t1_8x16b);\n\n                src_r0r1_16x8b = _mm_unpacklo_epi8(src_r0_c2_16x8b, src_r1_c2_16x8b);\n                src_r2r3_16x8b = _mm_unpacklo_epi8(src_r2_c2_16x8b, src_r3_c2_16x8b);\n                src_r4r5_16x8b = _mm_unpacklo_epi8(src_r4_c2_16x8b, src_r5_c2_16x8b);\n\n                res_t1_8x16b = _mm_maddubs_epi16(src_r0r1_16x8b, coeff0_1_16x8b);\n                res_t2_8x16b = _mm_maddubs_epi16(src_r2r3_16x8b, coeff2_3_16x8b);\n                res_t3_8x16b = _mm_maddubs_epi16(src_r4r5_16x8b, coeff4_5_16x8b);\n\n                res_t1_8x16b = _mm_add_epi16(res_t1_8x16b, res_t2_8x16b);\n                res_t1_8x16b = _mm_add_epi16(res_t3_8x16b, res_t1_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1 + 16), res_t1_8x16b);\n\n                src_r0_16x8b = src_r1_16x8b;\n                src_r1_16x8b = src_r2_16x8b;\n                src_r2_16x8b = src_r3_16x8b;\n                src_r3_16x8b = src_r4_16x8b;\n                src_r4_16x8b = src_r5_16x8b;\n\n                src_r0_c2_16x8b = src_r1_c2_16x8b;\n                src_r1_c2_16x8b = src_r2_c2_16x8b;\n                src_r2_c2_16x8b = src_r3_c2_16x8b;\n                src_r3_c2_16x8b = src_r4_c2_16x8b;\n                src_r4_c2_16x8b = src_r5_c2_16x8b;\n\n                ht_temp--;\n                pu1_src =  pu1_src + src_strd;\n                pi2_temp1 =  pi2_temp1 + 16 + 5;\n            }\n            while(ht_temp > 0);\n        }\n        // horizontal q-pel\n        {\n            __m128i src_r0_8x16b, src_r1_8x16b, src_r2_8x16b, src_r3_8x16b;\n            __m128i src_r4_8x16b, src_r5_8x16b;\n            __m128i src_r0r1_8x16b, src_r2r3_8x16b, src_r4r5_8x16b;\n            __m128i src_hpel1_8x16b, src_hpel2_8x16b, src_hpel_16x8b;\n\n            __m128i res_t0_4x32b, res_t1_4x32b, res_t2_4x32b, res_t3_4x32b;\n            __m128i res_c0_8x16b, res_c1_8x16b, res_16x8b;\n\n            __m128i coeff0_1_8x16b, coeff2_3_8x16b, coeff4_5_8x16b;\n            __m128i const_val512_4x32b, const_val16_8x16b;\n\n            coeff0_1_8x16b = _mm_set1_epi32(0xFFFB0001);\n            coeff2_3_8x16b = _mm_set1_epi32(0x00140014);\n            coeff4_5_8x16b = _mm_set1_epi32(0x0001FFFB);\n\n            const_val512_4x32b = _mm_set1_epi32(512);\n            const_val16_8x16b = _mm_set1_epi16(16);\n\n            do\n            {\n                src_r0_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2));\n                src_r1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 1));\n                src_r2_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 2));\n                src_r3_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 3));\n                src_r4_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 4));\n                src_r5_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 5));\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(const_val512_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_c0_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n\n                src_r0_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 8));\n                src_r1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 8 + 1));\n                src_r2_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 8 + 2));\n                src_r3_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 8 + 3));\n                src_r4_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 8 + 4));\n                src_r5_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 8 + 5));\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(const_val512_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b ,10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(const_val512_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_c1_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_c0_8x16b, res_c1_8x16b);\n\n                src_hpel1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp3));\n                src_hpel1_8x16b = _mm_add_epi16(src_hpel1_8x16b, const_val16_8x16b);\n                src_hpel1_8x16b = _mm_srai_epi16(src_hpel1_8x16b, 5); //shifting right by 5 bits.\n\n                src_hpel2_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp3 + 8));\n                src_hpel2_8x16b = _mm_add_epi16(src_hpel2_8x16b, const_val16_8x16b);\n                src_hpel2_8x16b = _mm_srai_epi16(src_hpel2_8x16b, 5); //shifting right by 5 bits.\n\n                src_hpel_16x8b = _mm_packus_epi16(src_hpel1_8x16b, src_hpel2_8x16b);\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_hpel_16x8b);\n\n                _mm_storeu_si128((__m128i *)(pu1_dst), res_16x8b);\n\n                ht--;\n                pi2_temp2 = pi2_temp2 + 16 + 5;\n                pi2_temp3 = pi2_temp3 + 16 + 5;\n                pu1_dst = pu1_dst + dst_strd;\n            }\n            while(ht > 0);\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_inter_pred_luma_horz_hpel_vert_qpel_ssse3          */\n/*                                                                           */\n/*  Description   : This function implements a six-tap filter vertically and */\n/*                  horizontally on ht x wd block separately and averages    */\n/*                  the two sets of values to calculate values at (1/2,1/4), */\n/*                  or (1/2, 3/4) as mentioned in sec. 8.4.2.2.1 titled      */\n/*                  \"Luma sample interpolation process\". (ht,wd) can be      */\n/*                  (4,4), (8,4), (4,8), (8,8), (16,8), (8,16) or (16,16).   */\n/*                                                                           */\n/*  Inputs        : puc_src  - pointer to source                             */\n/*                  puc_dst  - pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                  pu1_tmp  - pointer to temporary buffer                   */\n/*                  dydx     - x and y reference offset for q-pel            */\n/*                             calculations                                  */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_inter_pred_luma_horz_hpel_vert_qpel_ssse3(UWORD8 *pu1_src,\n                                                     UWORD8 *pu1_dst,\n                                                     WORD32 src_strd,\n                                                     WORD32 dst_strd,\n                                                     WORD32 ht,\n                                                     WORD32 wd,\n                                                     UWORD8* pu1_tmp,\n                                                     WORD32 dydx)\n{\n    WORD32 ht_temp;\n    WORD32 y_offset;\n    WORD16 *pi2_temp1,*pi2_temp2,*pi2_temp3;\n\n    y_offset = (dydx & 0xf) >> 2;\n    pi2_temp1 = (WORD16 *)pu1_tmp;\n    pi2_temp2 = pi2_temp1;\n    pi2_temp3 = pi2_temp1 + (y_offset >> 1) * wd;\n\n    ht_temp = ht + 5;\n    pu1_src -= src_strd << 1;\n    pu1_src -= 2;\n    pi2_temp3 += wd << 1;\n    //the filter input starts from x[-2] (till x[3])\n\n    if(wd == 4)\n    {\n        // horizontal half-pel\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r0r1_t1_16x8b;\n            __m128i src_r0_sht_16x8b, src_r1_sht_16x8b;\n            __m128i res_r0r1_t1_8x16b, res_r0r1_t2_8x16b, res_r0r1_t3_8x16b;\n            __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n\n            coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01);  //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n            coeff2_3_16x8b = _mm_set1_epi32(0x14141414);  //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n            coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB);  //c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5\n\n            //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n            //Row1 : b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n\n            do\n            {\n                src_r0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);                         //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n                src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));            //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                         //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                         //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n                src_r0_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);           //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n                src_r1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);           //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n                src_r0r1_t1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);         //a0 a1 a1 a2 a2 a3 a3 a4 b0 b1 b1 b2 b2 b3 b3 b4\n                res_r0r1_t1_8x16b = _mm_maddubs_epi16(src_r0r1_t1_16x8b, coeff0_1_16x8b);   //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                            //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 4);                             //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 4);                             //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8  0  0  0  0\n\n                src_r0r1_t1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);         //a2 a3 a3 a4 a4 a5 a5 a6 b2 b3 b3 b4 b4 b5 b5 b6\n                res_r0r1_t2_8x16b = _mm_maddubs_epi16(src_r0r1_t1_16x8b, coeff2_3_16x8b);   //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                            //b2*c2+b3*c3 b3*c2+b4*c3 b4*c2+b5*c3 b5*c2+b6*c3\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 4);                             //a4 a5 a5 a6 a6 a7 a7 a8  0  0  0  0  0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 4);                             //b4 b5 b5 b6 b6 b7 b7 b8  0  0  0  0  0  0  0  0\n\n                src_r0r1_t1_16x8b = _mm_unpacklo_epi64(src_r0_16x8b, src_r1_16x8b);         //a4 a5 a5 a6 a6 a7 a7 a8 b4 b5 b5 b6 b6 b7 b7 b8\n                res_r0r1_t3_8x16b = _mm_maddubs_epi16(src_r0r1_t1_16x8b, coeff4_5_16x8b);   //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                            //b4*c4+b5*c5 b5*c4+b6*c5 b4*c6+b7*c5 b7*c4+b8*c5\n\n                res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t1_8x16b, res_r0r1_t2_8x16b);\n                res_r0r1_t1_8x16b = _mm_add_epi16(res_r0r1_t1_8x16b, res_r0r1_t3_8x16b);\n\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1), res_r0r1_t1_8x16b);\n\n                ht_temp -= 2;\n                pu1_src =  pu1_src + (src_strd << 1);\n                pi2_temp1 =  pi2_temp1 + (4 << 1);\n            }\n            while(ht_temp > 0);\n        }\n        // vertical q-pel\n        {\n            __m128i src_r0_8x16b, src_r1_8x16b, src_r2_8x16b, src_r3_8x16b;\n            __m128i src_r4_8x16b, src_r5_8x16b, src_r6_8x16b;\n            __m128i src_r0r1_c0_8x16b, src_r2r3_c0_8x16b, src_r4r5_c0_8x16b;\n            __m128i src_hpel_16x8b, src_hpel_8x16b;\n\n            __m128i res_t0_4x32b, res_t1_4x32b, res_t2_4x32b, res_t3_4x32b;\n            __m128i res_8x16b, res_16x8b;\n\n            __m128i coeff0_1_8x16b, coeff2_3_8x16b, coeff4_5_8x16b;\n            __m128i const_val512_4x32b, const_val16_8x16b;\n\n            const_val512_4x32b = _mm_set1_epi32(512);\n            const_val16_8x16b = _mm_set1_epi16(16);\n\n            coeff0_1_8x16b = _mm_set1_epi32(0xFFFB0001);\n            coeff2_3_8x16b = _mm_set1_epi32(0x00140014);\n            coeff4_5_8x16b = _mm_set1_epi32(0x0001FFFB);\n\n            src_r0_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp2));\n            src_r1_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp2 + 4));\n            src_r2_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp2 + 8));\n            src_r3_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp2 + 12));\n            src_r4_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp2 + 16));\n            pi2_temp2 += 20;\n\n            do\n            {\n                src_r5_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp2));\n                src_r6_8x16b = _mm_loadl_epi64((__m128i *)(pi2_temp2 + 4));\n\n                src_r0r1_c0_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_c0_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_c0_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_c0_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_c0_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_c0_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_c0_8x16b = _mm_unpacklo_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_c0_8x16b = _mm_unpacklo_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_c0_8x16b = _mm_unpacklo_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_c0_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_c0_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_c0_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                src_hpel_8x16b = _mm_loadu_si128((__m128i *)pi2_temp3);\n                src_hpel_8x16b = _mm_add_epi16(src_hpel_8x16b, const_val16_8x16b);\n                src_hpel_8x16b = _mm_srai_epi16(src_hpel_8x16b, 5); //shifting right by 5 bits.\n                src_hpel_16x8b = _mm_packus_epi16(src_hpel_8x16b, src_hpel_8x16b);\n\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_hpel_16x8b);\n\n                *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(res_16x8b);\n                res_16x8b = _mm_srli_si128(res_16x8b, 4);\n                *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(res_16x8b);\n\n                src_r0_8x16b = src_r2_8x16b;\n                src_r1_8x16b = src_r3_8x16b;\n                src_r2_8x16b = src_r4_8x16b;\n                src_r3_8x16b = src_r5_8x16b;\n                src_r4_8x16b = src_r6_8x16b;\n\n                ht -= 2;\n                pi2_temp2 =  pi2_temp2 + (4 << 1);\n                pi2_temp3 =  pi2_temp3 + (4 << 1);\n                pu1_dst = pu1_dst + (dst_strd << 1);\n            }\n            while(ht > 0);\n        }\n    }\n    else if(wd == 8)\n    {\n        // horizontal half-pel\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r0_sht_16x8b, src_r1_sht_16x8b;\n            __m128i src_r0_t1_16x8b, src_r1_t1_16x8b;\n\n            __m128i res_r0_t1_8x16b, res_r0_t2_8x16b, res_r0_t3_8x16b;\n            __m128i res_r1_t1_8x16b, res_r1_t2_8x16b, res_r1_t3_8x16b;\n\n            __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n\n            coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01);  //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n            coeff2_3_16x8b = _mm_set1_epi32(0x14141414);  //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n            coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB);  //c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5\n\n            //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n            //Row1 : b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n\n            do\n            {\n                src_r0_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));                   //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n                src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));        //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                     //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                     //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);    //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);    //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n                res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff0_1_16x8b);   //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                        //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n                res_r1_t1_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff0_1_16x8b);   //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n                                                                                        //b4*c0+b5*c1 b5*c0+b6*c1 b6*c0+b7*c1 b7*c0+b8*c1\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                         //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                         //b2 b3 b4 b5 b6 b7 b8 b9....b15 0 0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                 //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                 //b3 b4 b5 b6 b7 b8 b9....b15 0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);    //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);    //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8 a8 a9 a9 a10\n\n                res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b);   //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                        //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n                res_r1_t2_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff2_3_16x8b);   //b2*c2+b3*c3 b3*c2+b4*c3 b2*c4+b5*c3 b5*c2+b6*c3\n                                                                                        //b6*c2+b7*c3 b7*c2+b8*c3 b8*c2+b9*c3 b9*c2+b10*c3\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                         //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                         //b4 b5 b6 b7 b8 b9....b15 0  0  0  0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                 //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                 //b5 b6 b7 b8 b9....b15 0  0  0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);    //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);    //b4 b5 b5 b6 b6 b7 b7 b8 b8 b9 b9 b10 b10 b11 b11 b12\n\n                res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b);   //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                        //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n                res_r1_t3_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff4_5_16x8b);   //b4*c4+b5*c5 b5*c4+b6*c5 b6*c4+b7*c5 b7*c4+b8*c5\n                                                                                        //b8*c4+b9*c5 b9*c4+b10*c5 b10*c4+b11*c5 b11*c4+b12*c5\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t2_8x16b);\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t3_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1), res_r0_t1_8x16b);\n                _mm_storeu_si128((__m128i *)(pi2_temp1 + 8), res_r1_t1_8x16b);\n\n                ht_temp -= 2;\n                pu1_src =  pu1_src + (src_strd << 1);\n                pi2_temp1 =  pi2_temp1 + (8 << 1);\n            }\n            while(ht_temp > 0);\n        }\n        // vertical q-pel\n        {\n            __m128i src_r0_8x16b, src_r1_8x16b, src_r2_8x16b, src_r3_8x16b;\n            __m128i src_r4_8x16b, src_r5_8x16b, src_r6_8x16b;\n            __m128i src_r0r1_8x16b, src_r2r3_8x16b, src_r4r5_8x16b;\n            __m128i src_hpel_8x16b, src_hpel_16x8b;\n\n            __m128i res_t0_4x32b, res_t1_4x32b, res_t2_4x32b, res_t3_4x32b;\n            __m128i res_8x16b, res_16x8b;\n\n            __m128i coeff0_1_8x16b, coeff2_3_8x16b, coeff4_5_8x16b;\n            __m128i const_val512_4x32b, const_val16_8x16b;\n\n            coeff0_1_8x16b = _mm_set1_epi32(0xFFFB0001);\n            coeff2_3_8x16b = _mm_set1_epi32(0x00140014);\n            coeff4_5_8x16b = _mm_set1_epi32(0x0001FFFB);\n\n            const_val512_4x32b = _mm_set1_epi32(512);\n            const_val16_8x16b = _mm_set1_epi16(16);\n\n            src_r0_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2));\n            src_r1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 8));\n            src_r2_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 16));\n            src_r3_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 24));\n            src_r4_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 32));\n            pi2_temp2 += 40;\n\n            do\n            {\n                src_r5_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2));\n                src_r6_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 8));\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                src_hpel_8x16b = _mm_loadu_si128((__m128i *)pi2_temp3);\n                src_hpel_8x16b = _mm_add_epi16(const_val16_8x16b, src_hpel_8x16b);\n                src_hpel_8x16b = _mm_srai_epi16(src_hpel_8x16b, 5); //shifting right by 5 bits.\n                src_hpel_16x8b = _mm_packus_epi16(src_hpel_8x16b, src_hpel_8x16b);\n\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_hpel_16x8b);\n\n                _mm_storel_epi64((__m128i *)(pu1_dst), res_16x8b);\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                src_hpel_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp3 + 8));\n                src_hpel_8x16b = _mm_add_epi16(const_val16_8x16b, src_hpel_8x16b);\n                src_hpel_8x16b = _mm_srai_epi16(src_hpel_8x16b, 5); //shifting right by 5 bits.\n                src_hpel_16x8b = _mm_packus_epi16(src_hpel_8x16b, src_hpel_8x16b);\n\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_hpel_16x8b);\n\n                _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), res_16x8b);\n\n                src_r0_8x16b = src_r2_8x16b;\n                src_r1_8x16b = src_r3_8x16b;\n                src_r2_8x16b = src_r4_8x16b;\n                src_r3_8x16b = src_r5_8x16b;\n                src_r4_8x16b = src_r6_8x16b;\n\n                ht -= 2;\n                pi2_temp2 = pi2_temp2 + (8 << 1);\n                pi2_temp3 = pi2_temp3 + (8 << 1);\n                pu1_dst = pu1_dst + (dst_strd << 1);\n            }\n            while(ht > 0);\n        }\n    }\n    else // wd == 16\n    {\n        UWORD8 *pu1_dst1;\n        WORD16 *pi2_temp4,*pi2_temp5;\n\n        pu1_dst1 = pu1_dst + 8;\n        pi2_temp4 = pi2_temp2 + 8;\n        pi2_temp5 = pi2_temp3 + 8;\n\n        // horizontal half-pel\n        {\n            __m128i src_r0_16x8b, src_r1_16x8b, src_r0_sht_16x8b, src_r1_sht_16x8b;\n            __m128i src_r0_t1_16x8b, src_r1_t1_16x8b;\n\n            __m128i res_r0_t1_8x16b, res_r0_t2_8x16b, res_r0_t3_8x16b;\n            __m128i res_r1_t1_8x16b, res_r1_t2_8x16b, res_r1_t3_8x16b;\n\n            __m128i coeff0_1_16x8b, coeff2_3_16x8b, coeff4_5_16x8b;\n\n            coeff0_1_16x8b = _mm_set1_epi32(0xFB01FB01);  //c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1 c0 c1\n            coeff2_3_16x8b = _mm_set1_epi32(0x14141414);  //c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3 c2 c3\n            coeff4_5_16x8b = _mm_set1_epi32(0x01FB01FB);  //c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5 c4 c5 c5 c5\n\n            //Row0 : a0 a1 a2 a3 a4 a5 a6 a7 a8 a9.....\n            //Row0 :                         b0 b1 b2 b3 b4 b5 b6 b7 b8 b9.....\n            //b0 is same a8. Similarly other bn pixels are same as a(n+8) pixels.\n\n            do\n            {\n                src_r0_16x8b = _mm_loadu_si128((__m128i *)(pu1_src));                  //a0 a1 a2 a3 a4 a5 a6 a7 a8 a9....a15\n                src_r1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 8));              //b0 b1 b2 b3 b4 b5 b6 b7 b8 b9....b15\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_16x8b, 1);                    //a1 a2 a3 a4 a5 a6 a7 a8 a9....a15 0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_16x8b, 1);                    //b1 b2 b3 b4 b5 b6 b7 b8 b9....b15 0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);   //a0 a1 a1 a2 a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);   //b0 b1 b1 b2 b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8\n\n                res_r0_t1_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff0_1_16x8b);   //a0*c0+a1*c1 a1*c0+a2*c1 a2*c0+a3*c1 a3*c0+a4*c1\n                                                                                        //a4*c0+a5*c1 a5*c0+a6*c1 a6*c0+a7*c1 a7*c0+a8*c1\n                res_r1_t1_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff0_1_16x8b);   //b0*c0+b1*c1 b1*c0+b2*c1 b2*c0+b3*c1 b3*c0+b4*c1\n                                                                                        //b4*c0+b5*c1 b5*c0+b6*c1 b6*c0+b7*c1 b7*c0+b8*c1\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                         //a2 a3 a4 a5 a6 a7 a8 a9....a15 0 0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                         //b2 b3 b4 b5 b6 b7 b8 b9....b15 0 0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                 //a3 a4 a5 a6 a7 a8 a9....a15 0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                 //b3 b4 b5 b6 b7 b8 b9....b15 0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);    //a2 a3 a3 a4 a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);    //b2 b3 b3 b4 b4 b5 b5 b6 b6 b7 b7 b8 a8 a9 a9 a10\n\n                res_r0_t2_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff2_3_16x8b);   //a2*c2+a3*c3 a3*c2+a4*c3 a4*c2+a5*c3 a5*c2+a6*c3\n                                                                                        //a6*c2+a7*c3 a7*c2+a8*c3 a8*c2+a9*c3 a9*c2+a10*c3\n                res_r1_t2_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff2_3_16x8b);   //b2*c2+b3*c3 b3*c2+b4*c3 b2*c4+b5*c3 b5*c2+b6*c3\n                                                                                        //b6*c2+b7*c3 b7*c2+b8*c3 b8*c2+b9*c3 b9*c2+b10*c3\n\n                src_r0_16x8b = _mm_srli_si128(src_r0_16x8b, 2);                         //a4 a5 a6 a7 a8 a9....a15 0  0  0  0\n                src_r1_16x8b = _mm_srli_si128(src_r1_16x8b, 2);                         //b4 b5 b6 b7 b8 b9....b15 0  0  0  0\n\n                src_r0_sht_16x8b = _mm_srli_si128(src_r0_sht_16x8b, 2);                 //a5 a6 a7 a8 a9....a15 0  0  0  0  0\n                src_r1_sht_16x8b = _mm_srli_si128(src_r1_sht_16x8b, 2);                 //b5 b6 b7 b8 b9....b15 0  0  0  0  0\n\n                src_r0_t1_16x8b = _mm_unpacklo_epi8(src_r0_16x8b, src_r0_sht_16x8b);    //a4 a5 a5 a6 a6 a7 a7 a8 a8 a9 a9 a10 a10 a11 a11 a12\n                src_r1_t1_16x8b = _mm_unpacklo_epi8(src_r1_16x8b, src_r1_sht_16x8b);    //b4 b5 b5 b6 b6 b7 b7 b8 b8 b9 b9 b10 b10 b11 b11 b12\n\n                res_r0_t3_8x16b = _mm_maddubs_epi16(src_r0_t1_16x8b, coeff4_5_16x8b);   //a4*c4+a5*c5 a5*c4+a6*c5 a6*c4+a7*c5 a7*c4+a8*c5\n                                                                                        //a8*c4+a9*c5 a9*c4+a10*c5 a10*c4+a11*c5 a11*c4+a12*c5\n                res_r1_t3_8x16b = _mm_maddubs_epi16(src_r1_t1_16x8b, coeff4_5_16x8b);   //b4*c4+b5*c5 b5*c4+b6*c5 b6*c4+b7*c5 b7*c4+b8*c5\n                                                                                        //b8*c4+b9*c5 b9*c4+b10*c5 b10*c4+b11*c5 b11*c4+b12*c5\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t2_8x16b);\n                res_r0_t1_8x16b = _mm_add_epi16(res_r0_t1_8x16b, res_r0_t3_8x16b);\n\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t2_8x16b);\n                res_r1_t1_8x16b = _mm_add_epi16(res_r1_t1_8x16b, res_r1_t3_8x16b);\n\n                _mm_storeu_si128((__m128i *)(pi2_temp1), res_r0_t1_8x16b);\n                _mm_storeu_si128((__m128i *)(pi2_temp1 + 8), res_r1_t1_8x16b);\n\n                ht_temp--;\n                pu1_src =  pu1_src + src_strd;\n                pi2_temp1 =  pi2_temp1 + 16;\n            }\n            while(ht_temp > 0);\n        }\n        // vertical q-pel\n        {\n            __m128i src_r0_8x16b, src_r1_8x16b, src_r2_8x16b, src_r3_8x16b, src_r4_8x16b;\n            __m128i src_r5_8x16b, src_r6_8x16b;\n            __m128i src_r0r1_8x16b, src_r2r3_8x16b, src_r4r5_8x16b;\n            __m128i src_hpel_8x16b, src_hpel_16x8b;\n\n            __m128i res_t0_4x32b, res_t1_4x32b, res_t2_4x32b, res_t3_4x32b;\n            __m128i res_8x16b, res_16x8b;\n\n            __m128i coeff0_1_8x16b, coeff2_3_8x16b, coeff4_5_8x16b;\n            __m128i const_val512_4x32b, const_val16_8x16b;\n\n            coeff0_1_8x16b = _mm_set1_epi32(0xFFFB0001);\n            coeff2_3_8x16b = _mm_set1_epi32(0x00140014);\n            coeff4_5_8x16b = _mm_set1_epi32(0x0001FFFB);\n\n            const_val512_4x32b = _mm_set1_epi32(512);\n            const_val16_8x16b = _mm_set1_epi16(16);\n\n            /**********************************************************/\n            /*     Do first height x 8 block                          */\n            /**********************************************************/\n            src_r0_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2));\n            src_r1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 16));\n            src_r2_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 32));\n            src_r3_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 48));\n            src_r4_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 64));\n            pi2_temp2 += 80;\n\n            ht_temp = ht;\n            do\n            {\n                src_r5_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2));\n                src_r6_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp2 + 16));\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                src_hpel_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp3));\n                src_hpel_8x16b = _mm_add_epi16(src_hpel_8x16b, const_val16_8x16b);\n                src_hpel_8x16b = _mm_srai_epi16(src_hpel_8x16b, 5); //shifting right by 5 bits.\n                src_hpel_16x8b = _mm_packus_epi16(src_hpel_8x16b, src_hpel_8x16b);\n\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_hpel_16x8b);\n                _mm_storel_epi64((__m128i *)(pu1_dst), res_16x8b);\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                src_hpel_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp3 + 16));\n                src_hpel_8x16b = _mm_add_epi16(src_hpel_8x16b, const_val16_8x16b);\n                src_hpel_8x16b = _mm_srai_epi16(src_hpel_8x16b, 5); //shifting right by 5 bits.\n                src_hpel_16x8b = _mm_packus_epi16(src_hpel_8x16b, src_hpel_8x16b);\n\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_hpel_16x8b);\n                _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), res_16x8b);\n\n                src_r0_8x16b = src_r2_8x16b;\n                src_r1_8x16b = src_r3_8x16b;\n                src_r2_8x16b = src_r4_8x16b;\n                src_r3_8x16b = src_r5_8x16b;\n                src_r4_8x16b = src_r6_8x16b;\n\n                ht_temp -= 2;\n                pi2_temp3 = pi2_temp3 + (16 << 1);\n                pi2_temp2 = pi2_temp2 + (16 << 1);\n                pu1_dst = pu1_dst + (dst_strd << 1);\n            }\n            while(ht_temp > 0);\n\n            /**********************************************************/\n            /*     Do second height * 8 block                         */\n            /**********************************************************/\n            src_r0_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp4));\n            src_r1_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp4 + 16));\n            src_r2_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp4 + 32));\n            src_r3_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp4 + 48));\n            src_r4_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp4 + 64));\n            pi2_temp4 += 80;\n\n            do\n            {\n                src_r5_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp4));\n                src_r6_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp4 + 16));\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r0_8x16b, src_r1_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r2_8x16b, src_r3_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r4_8x16b, src_r5_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                src_hpel_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp5));\n                src_hpel_8x16b = _mm_add_epi16(src_hpel_8x16b, const_val16_8x16b);\n                src_hpel_8x16b = _mm_srai_epi16(src_hpel_8x16b, 5); //shifting right by 5 bits.\n                src_hpel_16x8b = _mm_packus_epi16(src_hpel_8x16b, src_hpel_8x16b);\n\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_hpel_16x8b);\n                _mm_storel_epi64((__m128i *)(pu1_dst1), res_16x8b);\n\n                src_r0r1_8x16b = _mm_unpacklo_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpacklo_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpacklo_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t0_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                src_r0r1_8x16b = _mm_unpackhi_epi16(src_r1_8x16b, src_r2_8x16b);\n                src_r2r3_8x16b = _mm_unpackhi_epi16(src_r3_8x16b, src_r4_8x16b);\n                src_r4r5_8x16b = _mm_unpackhi_epi16(src_r5_8x16b, src_r6_8x16b);\n\n                res_t1_4x32b = _mm_madd_epi16(src_r0r1_8x16b, coeff0_1_8x16b);\n                res_t2_4x32b = _mm_madd_epi16(src_r2r3_8x16b, coeff2_3_8x16b);\n                res_t3_4x32b = _mm_madd_epi16(src_r4r5_8x16b, coeff4_5_8x16b);\n\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t2_4x32b);\n                res_t3_4x32b = _mm_add_epi32(res_t3_4x32b, const_val512_4x32b);\n                res_t1_4x32b = _mm_add_epi32(res_t1_4x32b, res_t3_4x32b);\n                res_t1_4x32b = _mm_srai_epi32(res_t1_4x32b, 10);\n\n                res_8x16b = _mm_packs_epi32(res_t0_4x32b, res_t1_4x32b);\n                res_16x8b = _mm_packus_epi16(res_8x16b, res_8x16b);\n\n                src_hpel_8x16b = _mm_loadu_si128((__m128i *)(pi2_temp5 + 16));\n                src_hpel_8x16b = _mm_add_epi16(src_hpel_8x16b, const_val16_8x16b);\n                src_hpel_8x16b = _mm_srai_epi16(src_hpel_8x16b, 5); //shifting right by 5 bits.\n                src_hpel_16x8b = _mm_packus_epi16(src_hpel_8x16b, src_hpel_8x16b);\n\n                res_16x8b = _mm_avg_epu8(res_16x8b, src_hpel_16x8b);\n                _mm_storel_epi64((__m128i *)(pu1_dst1 + dst_strd), res_16x8b);\n\n                src_r0_8x16b = src_r2_8x16b;\n                src_r1_8x16b = src_r3_8x16b;\n                src_r2_8x16b = src_r4_8x16b;\n                src_r3_8x16b = src_r5_8x16b;\n                src_r4_8x16b = src_r6_8x16b;\n\n                ht -= 2;\n                pi2_temp5 = pi2_temp5 + (16 << 1);\n                pi2_temp4 = pi2_temp4 + (16 << 1);\n                pu1_dst1 = pu1_dst1 + (dst_strd << 1);\n            }\n            while(ht > 0);\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_inter_pred_chroma_ssse3                            */\n/*                                                                           */\n/*  Description   : This function implements a four-tap 2D filter as         */\n/*                  mentioned in sec. 8.4.2.2.2 titled \"Chroma sample        */\n/*                  \"interpolation process\". (ht,wd) can be (2,2), (4,2),    */\n/*                  (2,4), (4,4), (8,4), (4,8) or (8,8).                     */\n/*                                                                           */\n/*  Inputs        : puc_src  - pointer to source                             */\n/*                  puc_dst  - pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  dx       - x position of destination value               */\n/*                  dy       - y position of destination value               */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         13 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_inter_pred_chroma_ssse3(UWORD8 *pu1_src,\n                                   UWORD8 *pu1_dst,\n                                   WORD32 src_strd,\n                                   WORD32 dst_strd,\n                                   WORD32 dx,\n                                   WORD32 dy,\n                                   WORD32 ht,\n                                   WORD32 wd)\n{\n    WORD32 i, j, A, B, C, D;\n\n    i = 8 - dx;\n    j = 8 - dy;\n\n    A = i * j;\n    B = dx * j;\n    C = i * dy;\n    D = dx * dy;\n\n    if(wd == 2)\n    {\n        WORD32 tmp1, tmp2, tmp3, tmp4;\n\n        do\n        {\n            //U\n            tmp1 = A * pu1_src[0] + B * pu1_src[2] + C * pu1_src[src_strd] + D * pu1_src[src_strd + 2];\n            tmp2 = A * pu1_src[2] + B * pu1_src[4] + C * pu1_src[src_strd + 2] + D * pu1_src[src_strd + 4];\n            //V\n            tmp3 = A * pu1_src[1] + B * pu1_src[3] + C * pu1_src[src_strd + 1] + D * pu1_src[src_strd + 3];\n            tmp4 = A * pu1_src[3] + B * pu1_src[5] + C * pu1_src[src_strd + 3] + D * pu1_src[src_strd + 5];\n\n            tmp1 = (tmp1 + 32) >> 6;\n            tmp2 = (tmp2 + 32) >> 6;\n            tmp3 = (tmp3 + 32) >> 6;\n            tmp4 = (tmp4 + 32) >> 6;\n\n            pu1_dst[0] = CLIP_U8(tmp1);\n            pu1_dst[2] = CLIP_U8(tmp2);\n            pu1_dst[1] = CLIP_U8(tmp3);\n            pu1_dst[3] = CLIP_U8(tmp4);\n\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n\n            tmp1 = A * pu1_src[0] + B * pu1_src[2] + C * pu1_src[src_strd] + D * pu1_src[src_strd + 2];\n            tmp2 = A * pu1_src[2] + B * pu1_src[4] + C * pu1_src[src_strd + 2] + D * pu1_src[src_strd + 4];\n            tmp3 = A * pu1_src[1] + B * pu1_src[3] + C * pu1_src[src_strd + 1] + D * pu1_src[src_strd + 3];\n            tmp4 = A * pu1_src[3] + B * pu1_src[5] + C * pu1_src[src_strd + 3] + D * pu1_src[src_strd + 5];\n\n            tmp1 = (tmp1 + 32) >> 6;\n            tmp2 = (tmp2 + 32) >> 6;\n            tmp3 = (tmp3 + 32) >> 6;\n            tmp4 = (tmp4 + 32) >> 6;\n\n            pu1_dst[0] = CLIP_U8(tmp1);\n            pu1_dst[2] = CLIP_U8(tmp2);\n            pu1_dst[1] = CLIP_U8(tmp3);\n            pu1_dst[3] = CLIP_U8(tmp4);\n\n            ht -= 2;\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n        }\n        while(ht > 0);\n\n    }\n    else if(wd == 4)\n    {\n        WORD32 AB, CD;\n\n        __m128i src_r1_16x8b, src_r2_16x8b, src_r3_16x8b;\n        __m128i res1_AB_8x16b, res1_CD_8x16b, res1_8x16b, res1_16x8b;\n        __m128i res2_AB_8x16b, res2_CD_8x16b, res2_8x16b, res2_16x8b;\n\n        __m128i coeffAB_16x8b, coeffCD_16x8b, round_add32_8x16b;\n        __m128i const_shuff_16x8b;\n\n        AB = (B << 8) + A;\n        CD = (D << 8) + C;\n\n        coeffAB_16x8b = _mm_set1_epi16(AB);\n        coeffCD_16x8b = _mm_set1_epi16(CD);\n\n        round_add32_8x16b = _mm_set1_epi16(32);\n\n        const_shuff_16x8b = _mm_setr_epi32(0x03010200, 0x05030402, 0x07050604, 0x09070806);\n\n        src_r1_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        src_r1_16x8b = _mm_shuffle_epi8(src_r1_16x8b, const_shuff_16x8b);\n        pu1_src += src_strd;\n\n        do\n        {\n            src_r2_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n            src_r3_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));\n\n            src_r2_16x8b = _mm_shuffle_epi8(src_r2_16x8b, const_shuff_16x8b);\n            src_r3_16x8b = _mm_shuffle_epi8(src_r3_16x8b, const_shuff_16x8b);\n\n            res1_AB_8x16b = _mm_maddubs_epi16(src_r1_16x8b, coeffAB_16x8b);\n            res1_CD_8x16b = _mm_maddubs_epi16(src_r2_16x8b, coeffCD_16x8b);\n            res2_AB_8x16b = _mm_maddubs_epi16(src_r2_16x8b, coeffAB_16x8b);\n            res2_CD_8x16b = _mm_maddubs_epi16(src_r3_16x8b, coeffCD_16x8b);\n\n            res1_8x16b = _mm_add_epi16(res1_AB_8x16b, res1_CD_8x16b);\n            res2_8x16b = _mm_add_epi16(res2_AB_8x16b, res2_CD_8x16b);\n            res1_8x16b = _mm_add_epi16(res1_8x16b, round_add32_8x16b);\n            res2_8x16b = _mm_add_epi16(res2_8x16b, round_add32_8x16b);\n\n            res1_8x16b = _mm_srai_epi16(res1_8x16b, 6);\n            res2_8x16b = _mm_srai_epi16(res2_8x16b, 6);\n\n            res1_16x8b = _mm_packus_epi16(res1_8x16b, res1_8x16b);\n            res2_16x8b = _mm_packus_epi16(res2_8x16b, res2_8x16b);\n\n            _mm_storel_epi64((__m128i *)pu1_dst, res1_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n            src_r1_16x8b = src_r3_16x8b;\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else // wd == 8\n    {\n        WORD32 AB, CD;\n\n        __m128i src_r1l_16x8b, src_r2l_16x8b;\n        __m128i src_r1h_16x8b, src_r2h_16x8b;\n\n        __m128i res_l_AB_8x16b, res_l_CD_8x16b;\n        __m128i res_h_AB_8x16b, res_h_CD_8x16b;\n        __m128i res_l_8x16b, res_h_8x16b, res_16x8b;\n\n        __m128i coeffAB_16x8b, coeffCD_16x8b, round_add32_8x16b;\n        __m128i const_shuff_16x8b;\n\n        AB = (B << 8) + A;\n        CD = (D << 8) + C;\n\n        coeffAB_16x8b = _mm_set1_epi16(AB);\n        coeffCD_16x8b = _mm_set1_epi16(CD);\n\n        round_add32_8x16b = _mm_set1_epi16(32);\n\n        const_shuff_16x8b = _mm_setr_epi32(0x03010200, 0x05030402, 0x07050604, 0x09070806);\n\n        src_r1l_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n        src_r1h_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 8));\n\n        src_r1l_16x8b = _mm_shuffle_epi8(src_r1l_16x8b, const_shuff_16x8b);\n        src_r1h_16x8b = _mm_shuffle_epi8(src_r1h_16x8b, const_shuff_16x8b);\n\n        pu1_src += src_strd;\n\n        do\n        {\n            //row 1\n            src_r2l_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n            src_r2h_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 8));\n\n            src_r2l_16x8b = _mm_shuffle_epi8(src_r2l_16x8b, const_shuff_16x8b);\n            src_r2h_16x8b = _mm_shuffle_epi8(src_r2h_16x8b, const_shuff_16x8b);\n\n            res_l_AB_8x16b = _mm_maddubs_epi16(src_r1l_16x8b, coeffAB_16x8b);\n            res_h_AB_8x16b = _mm_maddubs_epi16(src_r1h_16x8b, coeffAB_16x8b);\n            res_l_CD_8x16b = _mm_maddubs_epi16(src_r2l_16x8b, coeffCD_16x8b);\n            res_h_CD_8x16b = _mm_maddubs_epi16(src_r2h_16x8b, coeffCD_16x8b);\n\n            res_l_8x16b = _mm_add_epi16(res_l_AB_8x16b, round_add32_8x16b);\n            res_h_8x16b = _mm_add_epi16(res_h_AB_8x16b, round_add32_8x16b);\n            res_l_8x16b = _mm_add_epi16(res_l_8x16b, res_l_CD_8x16b);\n            res_h_8x16b = _mm_add_epi16(res_h_8x16b, res_h_CD_8x16b);\n\n            res_l_8x16b = _mm_srai_epi16(res_l_8x16b, 6);\n            res_h_8x16b = _mm_srai_epi16(res_h_8x16b, 6);\n\n            res_16x8b = _mm_packus_epi16(res_l_8x16b, res_h_8x16b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, res_16x8b);\n\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n\n            //row 2\n            src_r1l_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n            src_r1h_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 8));\n\n            src_r1l_16x8b = _mm_shuffle_epi8(src_r1l_16x8b, const_shuff_16x8b);\n            src_r1h_16x8b = _mm_shuffle_epi8(src_r1h_16x8b, const_shuff_16x8b);\n\n            res_l_AB_8x16b = _mm_maddubs_epi16(src_r2l_16x8b, coeffAB_16x8b);\n            res_h_AB_8x16b = _mm_maddubs_epi16(src_r2h_16x8b, coeffAB_16x8b);\n            res_l_CD_8x16b = _mm_maddubs_epi16(src_r1l_16x8b, coeffCD_16x8b);\n            res_h_CD_8x16b = _mm_maddubs_epi16(src_r1h_16x8b, coeffCD_16x8b);\n\n            res_l_8x16b = _mm_add_epi16(res_l_AB_8x16b, round_add32_8x16b);\n            res_h_8x16b = _mm_add_epi16(res_h_AB_8x16b, round_add32_8x16b);\n            res_l_8x16b = _mm_add_epi16(res_l_8x16b, res_l_CD_8x16b);\n            res_h_8x16b = _mm_add_epi16(res_h_8x16b, res_h_CD_8x16b);\n\n            res_l_8x16b = _mm_srai_epi16(res_l_8x16b, 6);\n            res_h_8x16b = _mm_srai_epi16(res_h_8x16b, 6);\n\n            res_16x8b = _mm_packus_epi16(res_l_8x16b, res_h_8x16b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, res_16x8b);\n\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n\n            //row 3\n            src_r2l_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n            src_r2h_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 8));\n\n            src_r2l_16x8b = _mm_shuffle_epi8(src_r2l_16x8b, const_shuff_16x8b);\n            src_r2h_16x8b = _mm_shuffle_epi8(src_r2h_16x8b, const_shuff_16x8b);\n\n            res_l_AB_8x16b = _mm_maddubs_epi16(src_r1l_16x8b, coeffAB_16x8b);\n            res_h_AB_8x16b = _mm_maddubs_epi16(src_r1h_16x8b, coeffAB_16x8b);\n            res_l_CD_8x16b = _mm_maddubs_epi16(src_r2l_16x8b, coeffCD_16x8b);\n            res_h_CD_8x16b = _mm_maddubs_epi16(src_r2h_16x8b, coeffCD_16x8b);\n\n            res_l_8x16b = _mm_add_epi16(res_l_AB_8x16b, round_add32_8x16b);\n            res_h_8x16b = _mm_add_epi16(res_h_AB_8x16b, round_add32_8x16b);\n            res_l_8x16b = _mm_add_epi16(res_l_8x16b, res_l_CD_8x16b);\n            res_h_8x16b = _mm_add_epi16(res_h_8x16b, res_h_CD_8x16b);\n\n            res_l_8x16b = _mm_srai_epi16(res_l_8x16b, 6);\n            res_h_8x16b = _mm_srai_epi16(res_h_8x16b, 6);\n\n            res_16x8b = _mm_packus_epi16(res_l_8x16b, res_h_8x16b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, res_16x8b);\n\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n\n            //row 1\n            src_r1l_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n            src_r1h_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + 8));\n\n            src_r1l_16x8b = _mm_shuffle_epi8(src_r1l_16x8b, const_shuff_16x8b);\n            src_r1h_16x8b = _mm_shuffle_epi8(src_r1h_16x8b, const_shuff_16x8b);\n\n            res_l_AB_8x16b = _mm_maddubs_epi16(src_r2l_16x8b, coeffAB_16x8b);\n            res_h_AB_8x16b = _mm_maddubs_epi16(src_r2h_16x8b, coeffAB_16x8b);\n            res_l_CD_8x16b = _mm_maddubs_epi16(src_r1l_16x8b, coeffCD_16x8b);\n            res_h_CD_8x16b = _mm_maddubs_epi16(src_r1h_16x8b, coeffCD_16x8b);\n\n            res_l_8x16b = _mm_add_epi16(res_l_AB_8x16b, round_add32_8x16b);\n            res_h_8x16b = _mm_add_epi16(res_h_AB_8x16b, round_add32_8x16b);\n            res_l_8x16b = _mm_add_epi16(res_l_8x16b, res_l_CD_8x16b);\n            res_h_8x16b = _mm_add_epi16(res_h_8x16b, res_h_CD_8x16b);\n\n            res_l_8x16b = _mm_srai_epi16(res_l_8x16b, 6);\n            res_h_8x16b = _mm_srai_epi16(res_h_8x16b, 6);\n\n            res_16x8b = _mm_packus_epi16(res_l_8x16b, res_h_8x16b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, res_16x8b);\n\n            ht -= 4;\n            pu1_src += src_strd;\n            pu1_dst += dst_strd;\n        }\n        while(ht > 0);\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_dc_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_iquant_itrans_recon_dc_ssse3.c\n *\n * @brief\n *  Contains function definitions for inverse  quantization, inverse\n * transform and reconstruction\n *\n * @author\n *  Mohit [100664]\n *\n * @par List of Functions:\n *  - ih264_iquant_itrans_recon_4x4_dc_ssse3()\n *  - ih264_iquant_itrans_recon_8x8_dc_ssse3()\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_trans_macros.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_trans_data.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include <immintrin.h>\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n/*\n ********************************************************************************\n *\n * @brief This function reconstructs a 4x4 sub block from quantized resiude and\n * prediction buffer for dc input pattern only, i.e. only the (0,0) element of the input\n * 4x4 block is non-zero. For complete function, refer ih264_iquant_itrans_recon_ssse3.c\n *\n * @par Description:\n *  The quantized residue is first inverse quantized, then inverse transformed.\n *  This inverse transformed content is added to the prediction buffer to recon-\n *  struct the end output\n *\n * @param[in] pi2_src\n *  quantized 4x4 block\n *\n * @param[in] pu1_pred\n *  prediction 4x4 block\n *\n * @param[out] pu1_out\n *  reconstructed 4x4 block\n *\n * @param[in] src_strd\n *  quantization buffer stride\n *\n * @param[in] pred_strd,\n *  Prediction buffer stride\n *\n * @param[in] out_strd\n *  recon buffer Stride\n *\n * @param[in] pu2_scaling_list\n *  pointer to scaling list\n *\n * @param[in] pu2_norm_adjust\n *  pointer to inverse scale matrix\n *\n * @param[in] u4_qp_div_6\n *  Floor (qp/6)\n *\n * @param[in] pi4_tmp\n * temporary buffer of size 1*16\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nATTRIBUTE_SSSE3\nvoid ih264_iquant_itrans_recon_4x4_dc_ssse3(WORD16 *pi2_src,\n                                   UWORD8 *pu1_pred,\n                                   UWORD8 *pu1_out,\n                                   WORD32 pred_strd,\n                                   WORD32 out_strd,\n                                   const UWORD16 *pu2_iscal_mat,\n                                   const UWORD16 *pu2_weigh_mat,\n                                   UWORD32 u4_qp_div_6,\n                                   WORD16 *pi2_tmp,\n                                   WORD32 iq_start_idx,\n                                   WORD16 *pi2_dc_ld_addr)\n{\n    UWORD32 *pu4_out = (UWORD32 *)pu1_out;\n    WORD32 q0 = pi2_src[0];\n    WORD16 i_macro, rnd_fact = (u4_qp_div_6 < 4) ? 1 << (3 - u4_qp_div_6) : 0;\n\n    __m128i predload_r,pred_r0, pred_r1, pred_r2, pred_r3;\n    __m128i sign_reg;\n    __m128i zero_8x16b = _mm_setzero_si128();          // all bits reset to zero\n    __m128i temp4, temp5, temp6, temp7;\n    __m128i value_add;\n\n    UNUSED (pi2_tmp);\n\n    INV_QUANT(q0, pu2_iscal_mat[0], pu2_weigh_mat[0], u4_qp_div_6, rnd_fact, 4);\n\n    if (iq_start_idx != 0 )\n        q0 = pi2_dc_ld_addr[0];     // Restoring dc value for intra case\n\n    i_macro = ((q0 + 32) >> 6);\n\n    value_add = _mm_set1_epi16(i_macro);\n\n    zero_8x16b = _mm_setzero_si128();                  // all bits reset to zero\n    //Load pred buffer\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[0])); //p00 p01 p02 p03 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r0 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p00 p01 p02 p03 0 0 0 0 -- all 16 bits\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[pred_strd])); //p10 p11 p12 p13 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p10 p11 p12 p13 0 0 0 0 -- all 16 bits\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[2*pred_strd])); //p20 p21 p22 p23 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r2 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p20 p21 p22 p23 0 0 0 0 -- all 16 bits\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[3*pred_strd])); //p30 p31 p32 p33 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r3 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p30 p31 p32 p33 0 0 0 0 -- all 16 bits\n\n    pred_r0 = _mm_unpacklo_epi64(pred_r0, pred_r1); //p00 p01 p02 p03 p10 p11 p12 p13\n    pred_r2 = _mm_unpacklo_epi64(pred_r2, pred_r3); //p20 p21 p22p p23 p30 p31 p32 p33\n\n    temp4 = _mm_add_epi16(value_add, pred_r0);\n    temp5 = _mm_add_epi16(value_add, pred_r2);\n    /*------------------------------------------------------------------*/\n    //Clipping the results to 8 bits\n    sign_reg = _mm_cmpgt_epi16(temp4, zero_8x16b);                 // sign check\n    temp4 = _mm_and_si128(temp4, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp5, zero_8x16b);                 // sign check\n    temp5 = _mm_and_si128(temp5, sign_reg);\n\n    temp4 = _mm_packus_epi16(temp4,temp5);\n    temp5 = _mm_srli_si128(temp4,4);\n    temp6 = _mm_srli_si128(temp5,4);\n    temp7 = _mm_srli_si128(temp6,4);\n\n    *pu4_out = _mm_cvtsi128_si32(temp4);\n    pu1_out += out_strd;\n    pu4_out = (UWORD32 *)(pu1_out);\n    *(pu4_out) = _mm_cvtsi128_si32(temp5);\n    pu1_out += out_strd;\n    pu4_out = (UWORD32 *)(pu1_out);\n    *(pu4_out) = _mm_cvtsi128_si32(temp6);\n    pu1_out += out_strd;\n    pu4_out = (UWORD32 *)(pu1_out);\n    *(pu4_out) = _mm_cvtsi128_si32(temp7);\n}\n/**\n *******************************************************************************\n *\n * @brief\n *  This function performs inverse quant and Inverse transform type Ci4 for 8x8 block\n *  for dc input pattern only, i.e. only the (0,0) element of the input 8x8 block is\n *  non-zero. For complete function, refer ih264_iquant_itrans_recon_ssse3.c\n *\n * @par Description:\n *  Performs inverse transform Ci8 and adds the residue to get the\n *  reconstructed block\n *\n * @param[in] pi2_src\n *  Input 8x8coefficients\n *\n * @param[in] pu1_pred\n *  Prediction 8x8 block\n *\n * @param[out] pu1_recon\n *  Output 8x8 block\n *\n * @param[in] q_div\n *  QP/6\n *\n * @param[in] q_rem\n *  QP%6\n *\n * @param[in] q_lev\n *  Quantizer level\n *\n * @param[in] u4_src_stride\n *  Input stride\n *\n * @param[in] u4_pred_stride,\n *  Prediction stride\n *\n * @param[in] u4_out_stride\n *  Output Stride\n *\n * @param[in] pi4_tmp\n *  temporary buffer of size 1*64\n *  the tmp for each block\n *\n * @param[in] pu4_iquant_mat\n *  Pointer to the inverse quantization matrix\n *\n * @returns  Void\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\nATTRIBUTE_SSSE3\nvoid ih264_iquant_itrans_recon_8x8_dc_ssse3 (WORD16 *pi2_src,\n                                         UWORD8 *pu1_pred,\n                                         UWORD8 *pu1_out,\n                                         WORD32 pred_strd,\n                                         WORD32 out_strd,\n                                         const UWORD16 *pu2_iscale_mat,\n                                         const UWORD16 *pu2_weigh_mat,\n                                         UWORD32 qp_div,\n                                         WORD16 *pi2_tmp,\n                                         WORD32 iq_start_idx,\n                                         WORD16 *pi2_dc_ld_addr)\n{\n    WORD32 q0 = pi2_src[0];\n    WORD16 i_macro, rnd_fact = (qp_div < 6) ? 1 << (5 - qp_div) : 0;\n\n    __m128i predload_r,pred_r0, pred_r1, pred_r2, pred_r3,pred_r4,pred_r5,pred_r6,pred_r7;\n    __m128i sign_reg;\n    __m128i zero_8x16b = _mm_setzero_si128();          // all bits reset to zero\n    __m128i temp1,temp2,temp3,temp4, temp5, temp6, temp7,temp8;\n    __m128i value_add;\n\n    UNUSED (pi2_tmp);\n    UNUSED (iq_start_idx);\n    UNUSED (pi2_dc_ld_addr);\n\n    INV_QUANT(q0, pu2_iscale_mat[0], pu2_weigh_mat[0], qp_div, rnd_fact, 6);\n    i_macro = ((q0 + 32) >> 6);\n\n    value_add = _mm_set1_epi16(i_macro);\n\n    //Load pred buffer row 0\n    predload_r = _mm_loadl_epi64((__m128i *)(&pu1_pred[0])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r0 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 1\n    predload_r = _mm_loadl_epi64((__m128i *)(&pu1_pred[pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 2\n    predload_r = _mm_loadl_epi64(\n                    (__m128i *)(&pu1_pred[2 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r2 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 3\n    predload_r = _mm_loadl_epi64(\n                    (__m128i *)(&pu1_pred[3 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r3 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 4\n    predload_r = _mm_loadl_epi64(\n                    (__m128i *)(&pu1_pred[4 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r4 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 5\n    predload_r = _mm_loadl_epi64(\n                    (__m128i *)(&pu1_pred[5 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bit\n    pred_r5 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 6\n    predload_r = _mm_loadl_epi64(\n                    (__m128i *)(&pu1_pred[6 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r6 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 7\n    predload_r = _mm_loadl_epi64(\n                    (__m128i *)(&pu1_pred[7 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r7 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n\n    temp1 = _mm_add_epi16(value_add, pred_r0);\n\n    temp2 = _mm_add_epi16(value_add, pred_r1);\n\n    temp3 = _mm_add_epi16(value_add, pred_r2);\n\n    temp4 = _mm_add_epi16(value_add, pred_r3);\n\n    temp5 = _mm_add_epi16(value_add, pred_r4);\n\n    temp6 = _mm_add_epi16(value_add, pred_r5);\n\n    temp7 = _mm_add_epi16(value_add, pred_r6);\n\n    temp8 = _mm_add_epi16(value_add, pred_r7);\n    /*------------------------------------------------------------------*/\n    //Clipping the results to 8 bits\n    sign_reg = _mm_cmpgt_epi16(temp1, zero_8x16b); // sign check\n    temp1 = _mm_and_si128(temp1, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp2, zero_8x16b); // sign check\n    temp2 = _mm_and_si128(temp2, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp3, zero_8x16b); // sign check\n    temp3 = _mm_and_si128(temp3, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp4, zero_8x16b); // sign check\n    temp4 = _mm_and_si128(temp4, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp5, zero_8x16b); // sign check\n    temp5 = _mm_and_si128(temp5, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp6, zero_8x16b); // sign check\n    temp6 = _mm_and_si128(temp6, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp7, zero_8x16b); // sign check\n    temp7 = _mm_and_si128(temp7, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp8, zero_8x16b); // sign check\n    temp8 = _mm_and_si128(temp8, sign_reg);\n\n    temp1 = _mm_packus_epi16(temp1, zero_8x16b);\n    temp2 = _mm_packus_epi16(temp2, zero_8x16b);\n    temp3 = _mm_packus_epi16(temp3, zero_8x16b);\n    temp4 = _mm_packus_epi16(temp4, zero_8x16b);\n    temp5 = _mm_packus_epi16(temp5, zero_8x16b);\n    temp6 = _mm_packus_epi16(temp6, zero_8x16b);\n    temp7 = _mm_packus_epi16(temp7, zero_8x16b);\n    temp8 = _mm_packus_epi16(temp8, zero_8x16b);\n\n    _mm_storel_epi64((__m128i *)(&pu1_out[0]), temp1);\n    _mm_storel_epi64((__m128i *)(&pu1_out[out_strd]), temp2);\n    _mm_storel_epi64((__m128i *)(&pu1_out[2 * out_strd]), temp3);\n    _mm_storel_epi64((__m128i *)(&pu1_out[3 * out_strd]), temp4);\n    _mm_storel_epi64((__m128i *)(&pu1_out[4 * out_strd]), temp5);\n    _mm_storel_epi64((__m128i *)(&pu1_out[5 * out_strd]), temp6);\n    _mm_storel_epi64((__m128i *)(&pu1_out[6 * out_strd]), temp7);\n    _mm_storel_epi64((__m128i *)(&pu1_out[7 * out_strd]), temp8);\n}\n\n/*\n ********************************************************************************\n *\n * @brief This function reconstructs a 4x4 sub block from quantized chroma resiude and\n * prediction buffer\n *\n * @par Description:\n *  The quantized residue is first inverse quantized, then inverse transformed.\n *  This inverse transformed content is added to the prediction buffer to recon-\n *  struct the end output\n *\n * @param[in] pi2_src\n *  quantized 4x4 block\n *\n * @param[in] pu1_pred\n *  prediction 4x4 block\n *\n * @param[out] pu1_out\n *  reconstructed 4x4 block\n *\n * @param[in] src_strd\n *  quantization buffer stride\n *\n * @param[in] pred_strd,\n *  Prediction buffer stride\n *\n * @param[in] out_strd\n *  recon buffer Stride\n *\n * @param[in] pu2_scaling_list\n *  pointer to scaling list\n *\n * @param[in] pu2_norm_adjust\n *  pointer to inverse scale matrix\n *\n * @param[in] u4_qp_div_6\n *  Floor (qp/6)\n *\n * @param[in] pi4_tmp\n * temporary buffer of size 1*16\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nATTRIBUTE_SSSE3\nvoid ih264_iquant_itrans_recon_chroma_4x4_dc_ssse3(WORD16 *pi2_src,\n                                   UWORD8 *pu1_pred,\n                                   UWORD8 *pu1_out,\n                                   WORD32 pred_strd,\n                                   WORD32 out_strd,\n                                   const UWORD16 *pu2_iscal_mat,\n                                   const UWORD16 *pu2_weigh_mat,\n                                   UWORD32 u4_qp_div_6,\n                                   WORD16 *pi2_tmp,\n                                   WORD16 *pi2_dc_src)\n {\n    WORD16 q0 = pi2_dc_src[0];      // DC value won't be dequantized for chroma inverse transform\n    WORD16 i_macro = ((q0 + 32) >> 6);\n\n    __m128i pred_r0, pred_r1, pred_r2, pred_r3, sign_reg;\n    __m128i zero_8x16b = _mm_setzero_si128();          // all bits reset to zero\n    __m128i chroma_mask = _mm_set1_epi16 (0xFF);\n    __m128i value_add = _mm_set1_epi16(i_macro);\n    __m128i out_r0, out_r1, out_r2, out_r3;\n\n    UNUSED (pi2_src);\n    UNUSED (pu2_iscal_mat);\n    UNUSED (pu2_weigh_mat);\n    UNUSED (u4_qp_div_6);\n    UNUSED (pi2_tmp);\n\n    //Load pred buffer\n    pred_r0 = _mm_loadl_epi64((__m128i *) (&pu1_pred[0])); //p00 p01 p02 p03 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r1 = _mm_loadl_epi64((__m128i *) (&pu1_pred[pred_strd])); //p10 p11 p12 p13 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r2 = _mm_loadl_epi64((__m128i *) (&pu1_pred[2 * pred_strd])); //p20 p21 p22 p23 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r3 = _mm_loadl_epi64((__m128i *) (&pu1_pred[3 * pred_strd])); //p30 p31 p32 p33 0 0 0 0 0 0 0 0 -- all 8 bits\n\n    pred_r0 = _mm_and_si128(pred_r0, chroma_mask);\n    pred_r1 = _mm_and_si128(pred_r1, chroma_mask);\n    pred_r2 = _mm_and_si128(pred_r2, chroma_mask);\n    pred_r3 = _mm_and_si128(pred_r3, chroma_mask);\n\n    pred_r0 = _mm_unpacklo_epi64(pred_r0, pred_r1); //p00 p01 p02 p03 p10 p11 p12 p13\n    pred_r2 = _mm_unpacklo_epi64(pred_r2, pred_r3); //p20 p21 p22p p23 p30 p31 p32 p33\n\n    pred_r0 = _mm_add_epi16(value_add, pred_r0);\n    pred_r2 = _mm_add_epi16(value_add, pred_r2);\n\n    /*------------------------------------------------------------------*/\n    //Clipping the results to 8 bits\n    sign_reg = _mm_cmpgt_epi16(pred_r0, zero_8x16b);        // sign check\n    pred_r0 = _mm_and_si128(pred_r0, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(pred_r2, zero_8x16b);\n    pred_r2 = _mm_and_si128(pred_r2, sign_reg);\n\n    pred_r0 = _mm_packus_epi16(pred_r0, pred_r2);\n    pred_r1 = _mm_srli_si128(pred_r0, 4);\n    pred_r2 = _mm_srli_si128(pred_r1, 4);\n    pred_r3 = _mm_srli_si128(pred_r2, 4);\n\n    pred_r0 = _mm_unpacklo_epi8(pred_r0, zero_8x16b); //p00 p01 p02 p03 -- all 16 bits\n    pred_r1 = _mm_unpacklo_epi8(pred_r1, zero_8x16b); //p10 p11 p12 p13 -- all 16 bits\n    pred_r2 = _mm_unpacklo_epi8(pred_r2, zero_8x16b); //p20 p21 p22 p23 -- all 16 bits\n    pred_r3 = _mm_unpacklo_epi8(pred_r3, zero_8x16b); //p30 p31 p32 p33 -- all 16 bits\n\n    chroma_mask = _mm_set1_epi16 (0xFF00);\n    out_r0 = _mm_loadl_epi64((__m128i *) (&pu1_out[0]));\n    out_r1 = _mm_loadl_epi64((__m128i *) (&pu1_out[out_strd]));\n    out_r2 = _mm_loadl_epi64((__m128i *) (&pu1_out[2 * out_strd]));\n    out_r3 = _mm_loadl_epi64((__m128i *) (&pu1_out[3 * out_strd]));\n\n    out_r0 = _mm_and_si128(out_r0, chroma_mask);\n    out_r1 = _mm_and_si128(out_r1, chroma_mask);\n    out_r2 = _mm_and_si128(out_r2, chroma_mask);\n    out_r3 = _mm_and_si128(out_r3, chroma_mask);\n\n    out_r0 = _mm_add_epi8(out_r0, pred_r0);\n    out_r1 = _mm_add_epi8(out_r1, pred_r1);\n    out_r2 = _mm_add_epi8(out_r2, pred_r2);\n    out_r3 = _mm_add_epi8(out_r3, pred_r3);\n\n    _mm_storel_epi64((__m128i *)(&pu1_out[0]), out_r0);\n    _mm_storel_epi64((__m128i *)(&pu1_out[out_strd]), out_r1);\n    _mm_storel_epi64((__m128i *)(&pu1_out[2 * out_strd]), out_r2);\n    _mm_storel_epi64((__m128i *)(&pu1_out[3 * out_strd]), out_r3);\n}\n\n\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_sse42.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_iquant_itrans_recon_sse42.c\n *\n * @brief\n *  Contains function definitions for inverse  quantization, inverse\n * transform and reconstruction\n *\n * @author\n *  Mohit [100664]\n *\n * @par List of Functions:\n *  - ih264_iquant_itrans_recon_4x4_sse42()\n *  - ih264_iquant_itrans_recon_chroma_4x4_sse42()\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_trans_macros.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_trans_data.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include <immintrin.h>\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSE42 __attribute__((target(\"sse4.2\")))\n#else\n#define ATTRIBUTE_SSE42\n#endif\n\n/*\n ********************************************************************************\n *\n * @brief This function reconstructs a 4x4 sub block from quantized resiude and\n * prediction buffer\n *\n * @par Description:\n *  The quantized residue is first inverse quantized, then inverse transformed.\n *  This inverse transformed content is added to the prediction buffer to recon-\n *  struct the end output\n *\n * @param[in] pi2_src\n *  quantized 4x4 block\n *\n * @param[in] pu1_pred\n *  prediction 4x4 block\n *\n * @param[out] pu1_out\n *  reconstructed 4x4 block\n *\n * @param[in] src_strd\n *  quantization buffer stride\n *\n * @param[in] pred_strd,\n *  Prediction buffer stride\n *\n * @param[in] out_strd\n *  recon buffer Stride\n *\n * @param[in] pu2_scaling_list\n *  pointer to scaling list\n *\n * @param[in] pu2_norm_adjust\n *  pointer to inverse scale matrix\n *\n * @param[in] u4_qp_div_6\n *  Floor (qp/6)\n *\n * @param[in] pi4_tmp\n * temporary buffer of size 1*16\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nATTRIBUTE_SSE42\nvoid ih264_iquant_itrans_recon_4x4_sse42(WORD16 *pi2_src,\n                                   UWORD8 *pu1_pred,\n                                   UWORD8 *pu1_out,\n                                   WORD32 pred_strd,\n                                   WORD32 out_strd,\n                                   const UWORD16 *pu2_iscal_mat,\n                                   const UWORD16 *pu2_weigh_mat,\n                                   UWORD32 u4_qp_div_6,\n                                   WORD16 *pi2_tmp,\n                                   WORD32 iq_start_idx,\n                                   WORD16 *pi2_dc_ld_addr)\n {\n    UWORD32 *pu4_out = (UWORD32 *) pu1_out;\n    __m128i src_r0_r1, src_r2_r3;\n    __m128i src_r0, src_r1, src_r2, src_r3;\n    __m128i scalemat_r0_r1, scalemat_r2_r3;\n    __m128i pred_r0, pred_r1, pred_r2, pred_r3;\n    __m128i sign_reg, dequant_r0_r1, dequant_r2_r3;\n    __m128i zero_8x16b = _mm_setzero_si128();          // all bits reset to zero\n    __m128i temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;\n    __m128i resq_r0, resq_r1, resq_r2, resq_r3;\n    __m128i add_rshift = _mm_set1_epi32((u4_qp_div_6 < 4) ? (1 << (3 - u4_qp_div_6)) : 0);\n    __m128i value_32 = _mm_set1_epi32(32);\n    UNUSED (pi2_tmp);\n\n    /*************************************************************/\n    /* Dequantization of coefficients. Will be replaced by SIMD  */\n    /* operations on platform                                    */\n    /*************************************************************/\n    src_r0_r1 = _mm_loadu_si128((__m128i *) (pi2_src)); //a00 a01 a02 a03 a10 a11 a12 a13 -- the source matrix 0th,1st row\n    src_r2_r3 = _mm_loadu_si128((__m128i *) (pi2_src + 8)); //a20 a21 a22 a23 a30 a31 a32 a33 -- the source matrix 2nd,3rd row\n    scalemat_r0_r1 = _mm_loadu_si128((__m128i *) (pu2_iscal_mat)); //b00 b01 b02 b03 b10 b11 b12 b13 -- the scaling matrix 0th,1st row\n    scalemat_r2_r3 = _mm_loadu_si128((__m128i *) (pu2_iscal_mat + 8)); //b20 b21 b22 b23 b30 b31 b32 b33 -- the scaling matrix 2nd,3rd row\n    dequant_r0_r1 = _mm_loadu_si128((__m128i *) (pu2_weigh_mat)); //q00 q01 q02 q03 q10 q11 q12 q13 -- all 16 bits\n    dequant_r2_r3 = _mm_loadu_si128((__m128i *) (pu2_weigh_mat + 8)); //q20 q21 q22 q23 q30 q31 q32 q33 -- all 16 bits\n\n    temp0 = _mm_mullo_epi16(scalemat_r0_r1, dequant_r0_r1); //b00*q00 b01*q01 b02*q02 b03*q03 b10*q10 b11*q11 b12*q12 b13*q13 -- 16 bit result\n    temp1 = _mm_mullo_epi16(scalemat_r2_r3, dequant_r2_r3); //b00*q00 b01*q01 b02*q02 b03*q03 b10*q10 b11*q11 b12*q12 b13*q13 -- 16 bit result\n\n    temp4 = _mm_unpacklo_epi16(temp0, zero_8x16b); // b00*q00 0 b01*q01 0 b02*q02 0 b03*q03 0 -- 16 bit long\n    temp5 = _mm_unpackhi_epi16(temp0, zero_8x16b); // b10*q10 0 b11*q11 0 b12*q12 0 b13*q13 0 -- 16 bit long\n    temp6 = _mm_unpacklo_epi16(temp1, zero_8x16b); // b00*q00 0 b01*q01 0 b02*q02 0 b03*q03 0 -- 16 bit long\n    temp7 = _mm_unpackhi_epi16(temp1, zero_8x16b); // b10*q10 0 b11*q11 0 b12*q12 0 b13*q13 0 -- 16 bit long\n\n    src_r0 = _mm_unpacklo_epi16(src_r0_r1, zero_8x16b); // a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r1 = _mm_unpackhi_epi16(src_r0_r1, zero_8x16b); // a10 0 a11 0 a12 0 a13 0 -- 16 bit long\n    src_r2 = _mm_unpacklo_epi16(src_r2_r3, zero_8x16b); // a20 0 a21 0 a22 0 a23 0 -- 16 bit long\n    src_r3 = _mm_unpackhi_epi16(src_r2_r3, zero_8x16b); // a30 0 a31 0 a32 0 a33 0 -- 16 bit long\n\n    temp4 = _mm_madd_epi16(src_r0, temp4); //a00*b00*q00 a10*b10*q10 a20*b20*q20 a30*b30 q30 -- 32 bits long\n    temp5 = _mm_madd_epi16(src_r1, temp5);\n    temp6 = _mm_madd_epi16(src_r2, temp6);\n    temp7 = _mm_madd_epi16(src_r3, temp7);\n\n    if (u4_qp_div_6 >= 4) {\n        resq_r0 = _mm_slli_epi32(temp4, u4_qp_div_6 - 4);\n        resq_r1 = _mm_slli_epi32(temp5, u4_qp_div_6 - 4);\n        resq_r2 = _mm_slli_epi32(temp6, u4_qp_div_6 - 4);\n        resq_r3 = _mm_slli_epi32(temp7, u4_qp_div_6 - 4);\n    } else {\n        temp4 = _mm_add_epi32(temp4, add_rshift);\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp6 = _mm_add_epi32(temp6, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r0 = _mm_srai_epi32(temp4, 4 - u4_qp_div_6);\n        resq_r1 = _mm_srai_epi32(temp5, 4 - u4_qp_div_6);\n        resq_r2 = _mm_srai_epi32(temp6, 4 - u4_qp_div_6);\n        resq_r3 = _mm_srai_epi32(temp7, 4 - u4_qp_div_6);\n    }\n\n    if (iq_start_idx == 1)\n        resq_r0 = _mm_insert_epi32(resq_r0,(WORD32)pi2_dc_ld_addr[0],0);\n    /* Perform Inverse transform */\n    /*-------------------------------------------------------------*/\n    /* IDCT [ Horizontal transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 a1 a2 a3\n     *  b0 b1 b2 b3\n     *  c0 c1 c2 c3\n     *  d0 d1 d2 d3\n     */\n    temp1 = _mm_unpacklo_epi32(resq_r0, resq_r1);                  //a0 b0 a1 b1\n    temp3 = _mm_unpacklo_epi32(resq_r2, resq_r3);                  //c0 d0 c1 d1\n    temp2 = _mm_unpackhi_epi32(resq_r0, resq_r1);                  //a2 b2 a3 b3\n    temp4 = _mm_unpackhi_epi32(resq_r2, resq_r3);                  //c2 d2 c3 d3\n    resq_r0 = _mm_unpacklo_epi64(temp1, temp3);                    //a0 b0 c0 d0\n    resq_r1 = _mm_unpackhi_epi64(temp1, temp3);                    //a1 b1 c1 d1\n    resq_r2 = _mm_unpacklo_epi64(temp2, temp4);                    //a2 b2 c2 d2\n    resq_r3 = _mm_unpackhi_epi64(temp2, temp4);                    //a3 b3 c3 d3\n    //Transform starts -- horizontal transform\n    /*------------------------------------------------------------------*/\n    /* z0 = w0 + w2                                             */\n    temp0 = _mm_add_epi32(resq_r0, resq_r2);\n    /* z1 = w0 - w2                                             */\n    temp1 = _mm_sub_epi32(resq_r0, resq_r2);\n    /* z2 = (w1 >> 1) - w3                                      */\n    temp2 = _mm_srai_epi32(resq_r1, 1);                         //(w1>>1)\n    temp2 = _mm_sub_epi32(temp2, resq_r3);                      //(w1>>1) - w3\n    /* z3 = w1 + (w3 >> 1)                                      */\n    temp3 = _mm_srai_epi32(resq_r3, 1);                         //(w3>>1) + w1\n    temp3 = _mm_add_epi32(temp3, resq_r1);\n    /*----------------------------------------------------------*/\n    /* x0 = z0 + z3                                             */\n    resq_r0 = _mm_add_epi32(temp0, temp3);\n    /* x1 = z1 + z2                                             */\n    resq_r1 = _mm_add_epi32(temp1, temp2);\n    /* x2 = z1 - z2                                             */\n    resq_r2 = _mm_sub_epi32(temp1, temp2);\n    /* x3 = z0 - z3                                             */\n    resq_r3 = _mm_sub_epi32(temp0, temp3);\n    // Matrix transpose\n    /*\n     *  a0 b0 c0 d0\n     *  a1 b1 c1 d1\n     *  a2 b2 c2 d2\n     *  a3 b3 c3 d3\n     */\n    temp1 = _mm_unpacklo_epi32(resq_r0, resq_r1);                  //a0 a1 b0 b1\n    temp3 = _mm_unpacklo_epi32(resq_r2, resq_r3);                  //a2 a3 b2 b3\n    temp2 = _mm_unpackhi_epi32(resq_r0, resq_r1);                  //c0 c1 d0 d1\n    temp4 = _mm_unpackhi_epi32(resq_r2, resq_r3);                  //c2 c3 d2 d3\n    resq_r0 = _mm_unpacklo_epi64(temp1, temp3);                    //a0 a1 a2 a3\n    resq_r1 = _mm_unpackhi_epi64(temp1, temp3);                    //b0 b1 b2 b3\n    resq_r2 = _mm_unpacklo_epi64(temp2, temp4);                    //c0 c1 c2 c3\n    resq_r3 = _mm_unpackhi_epi64(temp2, temp4);                    //d0 d1 d2 d3\n    //Transform ends -- horizontal transform\n\n    //Load pred buffer\n    pred_r0 = _mm_loadl_epi64((__m128i *) (&pu1_pred[0])); //p00 p01 p02 p03 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r1 = _mm_loadl_epi64((__m128i *) (&pu1_pred[pred_strd])); //p10 p11 p12 p13 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r2 = _mm_loadl_epi64((__m128i *) (&pu1_pred[2 * pred_strd])); //p20 p21 p22 p23 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r3 = _mm_loadl_epi64((__m128i *) (&pu1_pred[3 * pred_strd])); //p30 p31 p32 p33 0 0 0 0 0 0 0 0 -- all 8 bits\n\n    pred_r0 = _mm_cvtepu8_epi32(pred_r0); //p00 p01 p02 p03 -- all 32 bits\n    pred_r1 = _mm_cvtepu8_epi32(pred_r1); //p10 p11 p12 p13 -- all 32 bits\n    pred_r2 = _mm_cvtepu8_epi32(pred_r2); //p20 p21 p22 p23 -- all 32 bits\n    pred_r3 = _mm_cvtepu8_epi32(pred_r3); //p30 p31 p32 p33 -- all 32 bits\n\n    /*--------------------------------------------------------------*/\n    /* IDCT [ Vertical transformation] and Xij = (xij + 32)>>6      */\n    /*                                                              */\n    /* Add the prediction and store it back to same buffer          */\n    /*--------------------------------------------------------------*/\n    /* z0j = y0j + y2j                                                        */\n    temp0 = _mm_add_epi32(resq_r0, resq_r2);\n    /* z1j = y0j - y2j                                                        */\n    temp1 = _mm_sub_epi32(resq_r0, resq_r2);\n    /* z2j = (y1j>>1) - y3j                                                        */\n    temp2 = _mm_srai_epi32(resq_r1, 1);                             //(y1j>>1)\n    temp2 = _mm_sub_epi32(temp2, resq_r3);\n    /* z3j = y1j + (y3j>>1)                                                        */\n    temp3 = _mm_srai_epi32(resq_r3, 1);                             //(y3j>>1)\n    temp3 = _mm_add_epi32(temp3, resq_r1);\n\n    /* x0j = z0j + z3j                                                        */\n    temp4 = _mm_add_epi32(temp0, temp3);\n    temp4 = _mm_add_epi32(temp4, value_32);\n    temp4 = _mm_srai_epi32(temp4, 6);\n    temp4 = _mm_add_epi32(temp4, pred_r0);\n    /* x1j = z1j + z2j                                                        */\n    temp5 = _mm_add_epi32(temp1, temp2);\n    temp5 = _mm_add_epi32(temp5, value_32);\n    temp5 = _mm_srai_epi32(temp5, 6);\n    temp5 = _mm_add_epi32(temp5, pred_r1);\n    /* x2j = z1j - z2j                                                        */\n    temp6 = _mm_sub_epi32(temp1, temp2);\n    temp6 = _mm_add_epi32(temp6, value_32);\n    temp6 = _mm_srai_epi32(temp6, 6);\n    temp6 = _mm_add_epi32(temp6, pred_r2);\n    /* x3j = z0j - z3j                                                        */\n    temp7 = _mm_sub_epi32(temp0, temp3);\n    temp7 = _mm_add_epi32(temp7, value_32);\n    temp7 = _mm_srai_epi32(temp7, 6);\n    temp7 = _mm_add_epi32(temp7, pred_r3);\n\n    // 32-bit to 16-bit conversion\n    temp0 = _mm_packs_epi32(temp4, temp5);\n    temp1 = _mm_packs_epi32(temp6, temp7);\n    /*------------------------------------------------------------------*/\n    //Clipping the results to 8 bits\n    sign_reg = _mm_cmpgt_epi16(temp0, zero_8x16b);      // sign check\n    temp0 = _mm_and_si128(temp0, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp1, zero_8x16b);\n    temp1 = _mm_and_si128(temp1, sign_reg);\n\n    resq_r0 = _mm_packus_epi16(temp0, temp1);\n    resq_r1 = _mm_srli_si128(resq_r0, 4);\n    resq_r2 = _mm_srli_si128(resq_r1, 4);\n    resq_r3 = _mm_srli_si128(resq_r2, 4);\n\n    *pu4_out = _mm_cvtsi128_si32(resq_r0);\n    pu1_out += out_strd;\n    pu4_out = (UWORD32 *) (pu1_out);\n    *(pu4_out) = _mm_cvtsi128_si32(resq_r1);\n    pu1_out += out_strd;\n    pu4_out = (UWORD32 *) (pu1_out);\n    *(pu4_out) = _mm_cvtsi128_si32(resq_r2);\n    pu1_out += out_strd;\n    pu4_out = (UWORD32 *) (pu1_out);\n    *(pu4_out) = _mm_cvtsi128_si32(resq_r3);\n}\n\n/*\n ********************************************************************************\n *\n * @brief This function reconstructs a 4x4 sub block from quantized chroma resiude and\n * prediction buffer\n *\n * @par Description:\n *  The quantized residue is first inverse quantized, then inverse transformed.\n *  This inverse transformed content is added to the prediction buffer to recon-\n *  struct the end output\n *\n * @param[in] pi2_src\n *  quantized 4x4 block\n *\n * @param[in] pu1_pred\n *  prediction 4x4 block\n *\n * @param[out] pu1_out\n *  reconstructed 4x4 block\n *\n * @param[in] src_strd\n *  quantization buffer stride\n *\n * @param[in] pred_strd,\n *  Prediction buffer stride\n *\n * @param[in] out_strd\n *  recon buffer Stride\n *\n * @param[in] pu2_scaling_list\n *  pointer to scaling list\n *\n * @param[in] pu2_norm_adjust\n *  pointer to inverse scale matrix\n *\n * @param[in] u4_qp_div_6\n *  Floor (qp/6)\n *\n * @param[in] pi4_tmp\n * temporary buffer of size 1*16\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nATTRIBUTE_SSE42\nvoid ih264_iquant_itrans_recon_chroma_4x4_sse42(WORD16 *pi2_src,\n                                   UWORD8 *pu1_pred,\n                                   UWORD8 *pu1_out,\n                                   WORD32 pred_strd,\n                                   WORD32 out_strd,\n                                   const UWORD16 *pu2_iscal_mat,\n                                   const UWORD16 *pu2_weigh_mat,\n                                   UWORD32 u4_qp_div_6,\n                                   WORD16 *pi2_tmp,\n                                   WORD16 *pi2_dc_ld_addr)\n {\n    __m128i src_r0_r1, src_r2_r3;\n    __m128i src_r0, src_r1, src_r2, src_r3;\n    __m128i scalemat_r0_r1, scalemat_r2_r3;\n    __m128i pred_r0, pred_r1, pred_r2, pred_r3;\n    __m128i sign_reg, dequant_r0_r1, dequant_r2_r3;\n    __m128i zero_8x16b = _mm_setzero_si128();          // all bits reset to zero\n    __m128i temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;\n    __m128i resq_r0, resq_r1, resq_r2, resq_r3;\n    __m128i add_rshift = _mm_set1_epi32((u4_qp_div_6 < 4) ? (1 << (3 - u4_qp_div_6)) : 0);\n    __m128i value_32 = _mm_set1_epi32(32);\n    __m128i chroma_mask = _mm_set1_epi16 (0xFF);\n    __m128i out_r0, out_r1, out_r2, out_r3;\n    UNUSED (pi2_tmp);\n\n    /*************************************************************/\n    /* Dequantization of coefficients. Will be replaced by SIMD  */\n    /* operations on platform                                    */\n    /*************************************************************/\n    src_r0_r1 = _mm_loadu_si128((__m128i *) (pi2_src)); //a00 a01 a02 a03 a10 a11 a12 a13 -- the source matrix 0th,1st row\n    src_r2_r3 = _mm_loadu_si128((__m128i *) (pi2_src + 8)); //a20 a21 a22 a23 a30 a31 a32 a33 -- the source matrix 2nd,3rd row\n    scalemat_r0_r1 = _mm_loadu_si128((__m128i *) (pu2_iscal_mat)); //b00 b01 b02 b03 b10 b11 b12 b13 -- the scaling matrix 0th,1st row\n    scalemat_r2_r3 = _mm_loadu_si128((__m128i *) (pu2_iscal_mat + 8)); //b20 b21 b22 b23 b30 b31 b32 b33 -- the scaling matrix 2nd,3rd row\n    dequant_r0_r1 = _mm_loadu_si128((__m128i *) (pu2_weigh_mat)); //q00 q01 q02 q03 q10 q11 q12 q13 -- all 16 bits\n    dequant_r2_r3 = _mm_loadu_si128((__m128i *) (pu2_weigh_mat + 8)); //q20 q21 q22 q23 q30 q31 q32 q33 -- all 16 bits\n\n    temp0 = _mm_mullo_epi16(scalemat_r0_r1, dequant_r0_r1); //b00*q00 b01*q01 b02*q02 b03*q03 b10*q10 b11*q11 b12*q12 b13*q13 -- 16 bit result\n    temp1 = _mm_mullo_epi16(scalemat_r2_r3, dequant_r2_r3); //b00*q00 b01*q01 b02*q02 b03*q03 b10*q10 b11*q11 b12*q12 b13*q13 -- 16 bit result\n\n    temp4 = _mm_unpacklo_epi16(temp0, zero_8x16b); // b00*q00 0 b01*q01 0 b02*q02 0 b03*q03 0 -- 16 bit long\n    temp5 = _mm_unpackhi_epi16(temp0, zero_8x16b); // b10*q10 0 b11*q11 0 b12*q12 0 b13*q13 0 -- 16 bit long\n    temp6 = _mm_unpacklo_epi16(temp1, zero_8x16b); // b00*q00 0 b01*q01 0 b02*q02 0 b03*q03 0 -- 16 bit long\n    temp7 = _mm_unpackhi_epi16(temp1, zero_8x16b); // b10*q10 0 b11*q11 0 b12*q12 0 b13*q13 0 -- 16 bit long\n\n    src_r0 = _mm_unpacklo_epi16(src_r0_r1, zero_8x16b); // a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r1 = _mm_unpackhi_epi16(src_r0_r1, zero_8x16b); // a10 0 a11 0 a12 0 a13 0 -- 16 bit long\n    src_r2 = _mm_unpacklo_epi16(src_r2_r3, zero_8x16b); // a20 0 a21 0 a22 0 a23 0 -- 16 bit long\n    src_r3 = _mm_unpackhi_epi16(src_r2_r3, zero_8x16b); // a30 0 a31 0 a32 0 a33 0 -- 16 bit long\n\n    temp4 = _mm_madd_epi16(src_r0, temp4); //a00*b00*q00 a10*b10*q10 a20*b20*q20 a30*b30 q30 -- 32 bits long\n    temp5 = _mm_madd_epi16(src_r1, temp5);\n    temp6 = _mm_madd_epi16(src_r2, temp6);\n    temp7 = _mm_madd_epi16(src_r3, temp7);\n\n    if (u4_qp_div_6 >= 4) {\n        resq_r0 = _mm_slli_epi32(temp4, u4_qp_div_6 - 4);\n        resq_r1 = _mm_slli_epi32(temp5, u4_qp_div_6 - 4);\n        resq_r2 = _mm_slli_epi32(temp6, u4_qp_div_6 - 4);\n        resq_r3 = _mm_slli_epi32(temp7, u4_qp_div_6 - 4);\n    } else {\n        temp4 = _mm_add_epi32(temp4, add_rshift);\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp6 = _mm_add_epi32(temp6, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r0 = _mm_srai_epi32(temp4, 4 - u4_qp_div_6);\n        resq_r1 = _mm_srai_epi32(temp5, 4 - u4_qp_div_6);\n        resq_r2 = _mm_srai_epi32(temp6, 4 - u4_qp_div_6);\n        resq_r3 = _mm_srai_epi32(temp7, 4 - u4_qp_div_6);\n    }\n\n    resq_r0 = _mm_insert_epi32(resq_r0,(WORD32)pi2_dc_ld_addr[0],0);\n    /* Perform Inverse transform */\n    /*-------------------------------------------------------------*/\n    /* IDCT [ Horizontal transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 a1 a2 a3\n     *  b0 b1 b2 b3\n     *  c0 c1 c2 c3\n     *  d0 d1 d2 d3\n     */\n    temp1 = _mm_unpacklo_epi32(resq_r0, resq_r1);                  //a0 b0 a1 b1\n    temp3 = _mm_unpacklo_epi32(resq_r2, resq_r3);                  //c0 d0 c1 d1\n    temp2 = _mm_unpackhi_epi32(resq_r0, resq_r1);                  //a2 b2 a3 b3\n    temp4 = _mm_unpackhi_epi32(resq_r2, resq_r3);                  //c2 d2 c3 d3\n    resq_r0 = _mm_unpacklo_epi64(temp1, temp3);                    //a0 b0 c0 d0\n    resq_r1 = _mm_unpackhi_epi64(temp1, temp3);                    //a1 b1 c1 d1\n    resq_r2 = _mm_unpacklo_epi64(temp2, temp4);                    //a2 b2 c2 d2\n    resq_r3 = _mm_unpackhi_epi64(temp2, temp4);                    //a3 b3 c3 d3\n    //Transform starts -- horizontal transform\n    /*------------------------------------------------------------------*/\n    /* z0 = w0 + w2                                             */\n    temp0 = _mm_add_epi32(resq_r0, resq_r2);\n    /* z1 = w0 - w2                                             */\n    temp1 = _mm_sub_epi32(resq_r0, resq_r2);\n    /* z2 = (w1 >> 1) - w3                                      */\n    temp2 = _mm_srai_epi32(resq_r1, 1);                         //(w1>>1)\n    temp2 = _mm_sub_epi32(temp2, resq_r3);                      //(w1>>1) - w3\n    /* z3 = w1 + (w3 >> 1)                                      */\n    temp3 = _mm_srai_epi32(resq_r3, 1);                         //(w3>>1) + w1\n    temp3 = _mm_add_epi32(temp3, resq_r1);\n    /*----------------------------------------------------------*/\n    /* x0 = z0 + z3                                             */\n    resq_r0 = _mm_add_epi32(temp0, temp3);\n    /* x1 = z1 + z2                                             */\n    resq_r1 = _mm_add_epi32(temp1, temp2);\n    /* x2 = z1 - z2                                             */\n    resq_r2 = _mm_sub_epi32(temp1, temp2);\n    /* x3 = z0 - z3                                             */\n    resq_r3 = _mm_sub_epi32(temp0, temp3);\n    // Matrix transpose\n    /*\n     *  a0 b0 c0 d0\n     *  a1 b1 c1 d1\n     *  a2 b2 c2 d2\n     *  a3 b3 c3 d3\n     */\n    temp1 = _mm_unpacklo_epi32(resq_r0, resq_r1);                  //a0 a1 b0 b1\n    temp3 = _mm_unpacklo_epi32(resq_r2, resq_r3);                  //a2 a3 b2 b3\n    temp2 = _mm_unpackhi_epi32(resq_r0, resq_r1);                  //c0 c1 d0 d1\n    temp4 = _mm_unpackhi_epi32(resq_r2, resq_r3);                  //c2 c3 d2 d3\n    resq_r0 = _mm_unpacklo_epi64(temp1, temp3);                    //a0 a1 a2 a3\n    resq_r1 = _mm_unpackhi_epi64(temp1, temp3);                    //b0 b1 b2 b3\n    resq_r2 = _mm_unpacklo_epi64(temp2, temp4);                    //c0 c1 c2 c3\n    resq_r3 = _mm_unpackhi_epi64(temp2, temp4);                    //d0 d1 d2 d3\n    //Transform ends -- horizontal transform\n\n    //Load pred buffer\n    pred_r0 = _mm_loadl_epi64((__m128i *) (&pu1_pred[0])); //p00 p01 p02 p03 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r1 = _mm_loadl_epi64((__m128i *) (&pu1_pred[pred_strd])); //p10 p11 p12 p13 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r2 = _mm_loadl_epi64((__m128i *) (&pu1_pred[2 * pred_strd])); //p20 p21 p22 p23 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r3 = _mm_loadl_epi64((__m128i *) (&pu1_pred[3 * pred_strd])); //p30 p31 p32 p33 0 0 0 0 0 0 0 0 -- all 8 bits\n\n    pred_r0 = _mm_and_si128(pred_r0, chroma_mask);\n    pred_r1 = _mm_and_si128(pred_r1, chroma_mask);\n    pred_r2 = _mm_and_si128(pred_r2, chroma_mask);\n    pred_r3 = _mm_and_si128(pred_r3, chroma_mask);\n\n    pred_r0 = _mm_cvtepu16_epi32(pred_r0); //p00 p01 p02 p03 -- all 32 bits\n    pred_r1 = _mm_cvtepu16_epi32(pred_r1); //p10 p11 p12 p13 -- all 32 bits\n    pred_r2 = _mm_cvtepu16_epi32(pred_r2); //p20 p21 p22 p23 -- all 32 bits\n    pred_r3 = _mm_cvtepu16_epi32(pred_r3); //p30 p31 p32 p33 -- all 32 bits\n\n    /*--------------------------------------------------------------*/\n    /* IDCT [ Vertical transformation] and Xij = (xij + 32)>>6      */\n    /*                                                              */\n    /* Add the prediction and store it back to same buffer          */\n    /*--------------------------------------------------------------*/\n    /* z0j = y0j + y2j                                                        */\n    temp0 = _mm_add_epi32(resq_r0, resq_r2);\n    /* z1j = y0j - y2j                                                        */\n    temp1 = _mm_sub_epi32(resq_r0, resq_r2);\n    /* z2j = (y1j>>1) - y3j                                                        */\n    temp2 = _mm_srai_epi32(resq_r1, 1);                             //(y1j>>1)\n    temp2 = _mm_sub_epi32(temp2, resq_r3);\n    /* z3j = y1j + (y3j>>1)                                                        */\n    temp3 = _mm_srai_epi32(resq_r3, 1);                             //(y3j>>1)\n    temp3 = _mm_add_epi32(temp3, resq_r1);\n\n    /* x0j = z0j + z3j                                                        */\n    temp4 = _mm_add_epi32(temp0, temp3);\n    temp4 = _mm_add_epi32(temp4, value_32);\n    temp4 = _mm_srai_epi32(temp4, 6);\n    temp4 = _mm_add_epi32(temp4, pred_r0);\n    /* x1j = z1j + z2j                                                        */\n    temp5 = _mm_add_epi32(temp1, temp2);\n    temp5 = _mm_add_epi32(temp5, value_32);\n    temp5 = _mm_srai_epi32(temp5, 6);\n    temp5 = _mm_add_epi32(temp5, pred_r1);\n    /* x2j = z1j - z2j                                                        */\n    temp6 = _mm_sub_epi32(temp1, temp2);\n    temp6 = _mm_add_epi32(temp6, value_32);\n    temp6 = _mm_srai_epi32(temp6, 6);\n    temp6 = _mm_add_epi32(temp6, pred_r2);\n    /* x3j = z0j - z3j                                                        */\n    temp7 = _mm_sub_epi32(temp0, temp3);\n    temp7 = _mm_add_epi32(temp7, value_32);\n    temp7 = _mm_srai_epi32(temp7, 6);\n    temp7 = _mm_add_epi32(temp7, pred_r3);\n\n    // 32-bit to 16-bit conversion\n    temp0 = _mm_packs_epi32(temp4, temp5);\n    temp1 = _mm_packs_epi32(temp6, temp7);\n    /*------------------------------------------------------------------*/\n    //Clipping the results to 8 bits\n    sign_reg = _mm_cmpgt_epi16(temp0, zero_8x16b);      // sign check\n    temp0 = _mm_and_si128(temp0, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp1, zero_8x16b);\n    temp1 = _mm_and_si128(temp1, sign_reg);\n\n    resq_r0 = _mm_packus_epi16(temp0, temp1);\n    resq_r1 = _mm_srli_si128(resq_r0, 4);\n    resq_r2 = _mm_srli_si128(resq_r1, 4);\n    resq_r3 = _mm_srli_si128(resq_r2, 4);\n\n    resq_r0 = _mm_cvtepu8_epi16(resq_r0); //p00 p01 p02 p03 -- all 16 bits\n    resq_r1 = _mm_cvtepu8_epi16(resq_r1); //p10 p11 p12 p13 -- all 16 bits\n    resq_r2 = _mm_cvtepu8_epi16(resq_r2); //p20 p21 p22 p23 -- all 16 bits\n    resq_r3 = _mm_cvtepu8_epi16(resq_r3); //p30 p31 p32 p33 -- all 16 bits\n\n    chroma_mask = _mm_set1_epi16 (0xFF00);\n    out_r0 = _mm_loadl_epi64((__m128i *) (&pu1_out[0]));\n    out_r1 = _mm_loadl_epi64((__m128i *) (&pu1_out[out_strd]));\n    out_r2 = _mm_loadl_epi64((__m128i *) (&pu1_out[2 * out_strd]));\n    out_r3 = _mm_loadl_epi64((__m128i *) (&pu1_out[3 * out_strd]));\n\n    out_r0 = _mm_and_si128(out_r0, chroma_mask);\n    out_r1 = _mm_and_si128(out_r1, chroma_mask);\n    out_r2 = _mm_and_si128(out_r2, chroma_mask);\n    out_r3 = _mm_and_si128(out_r3, chroma_mask);\n\n    out_r0 = _mm_add_epi8(out_r0, resq_r0);\n    out_r1 = _mm_add_epi8(out_r1, resq_r1);\n    out_r2 = _mm_add_epi8(out_r2, resq_r2);\n    out_r3 = _mm_add_epi8(out_r3, resq_r3);\n\n    _mm_storel_epi64((__m128i *)(&pu1_out[0]), out_r0);\n    _mm_storel_epi64((__m128i *)(&pu1_out[out_strd]), out_r1);\n    _mm_storel_epi64((__m128i *)(&pu1_out[2 * out_strd]), out_r2);\n    _mm_storel_epi64((__m128i *)(&pu1_out[3 * out_strd]), out_r3);\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_iquant_itrans_recon_ssse3.c\n *\n * @brief\n *  Contains function definitions for inverse  quantization, inverse\n * transform and reconstruction\n *\n * @author\n *  Mohit [100664]\n *\n * @par List of Functions:\n *  - ih264_iquant_itrans_recon_4x4_ssse3()\n *  - ih264_iquant_itrans_recon_8x8_ssse3()\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_trans_macros.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_trans_data.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include <immintrin.h>\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n/*\n ********************************************************************************\n *\n * @brief This function reconstructs a 4x4 sub block from quantized resiude and\n * prediction buffer\n *\n * @par Description:\n *  The quantized residue is first inverse quantized, then inverse transformed.\n *  This inverse transformed content is added to the prediction buffer to recon-\n *  struct the end output\n *\n * @param[in] pi2_src\n *  quantized 4x4 block\n *\n * @param[in] pu1_pred\n *  prediction 4x4 block\n *\n * @param[out] pu1_out\n *  reconstructed 4x4 block\n *\n * @param[in] src_strd\n *  quantization buffer stride\n *\n * @param[in] pred_strd,\n *  Prediction buffer stride\n *\n * @param[in] out_strd\n *  recon buffer Stride\n *\n * @param[in] pu2_scaling_list\n *  pointer to scaling list\n *\n * @param[in] pu2_norm_adjust\n *  pointer to inverse scale matrix\n *\n * @param[in] u4_qp_div_6\n *  Floor (qp/6)\n *\n * @param[in] pi4_tmp\n * temporary buffer of size 1*16\n *\n * @returns none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nATTRIBUTE_SSSE3\nvoid ih264_iquant_itrans_recon_4x4_ssse3(WORD16 *pi2_src,\n                                         UWORD8 *pu1_pred,\n                                         UWORD8 *pu1_out,\n                                         WORD32 pred_strd,\n                                         WORD32 out_strd,\n                                         const UWORD16 *pu2_iscal_mat,\n                                         const UWORD16 *pu2_weigh_mat,\n                                         UWORD32 u4_qp_div_6,\n                                         WORD16 *pi2_tmp,\n                                         WORD32 iq_start_idx,\n                                         WORD16 *pi2_dc_ld_addr)\n{\n    UWORD32 *pu4_out = (UWORD32 *) pu1_out;\n    __m128i src_r0_r1, src_r2_r3;\n    __m128i src_r0, src_r1, src_r2, src_r3;\n    __m128i scalemat_r0_r1, scalemat_r2_r3, predload_r;\n    __m128i pred_r0, pred_r1, pred_r2, pred_r3;\n    __m128i sign_reg, dequant_r0_r1, dequant_r2_r3;\n    __m128i zero_8x16b = _mm_setzero_si128();          // all bits reset to zero\n    __m128i temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;\n    __m128i resq_r0, resq_r1, resq_r2, resq_r3;\n    __m128i add_rshift = _mm_set1_epi32((u4_qp_div_6 < 4) ? (1 << (3 - u4_qp_div_6)) : 0);\n    __m128i value_32 = _mm_set1_epi32(32);\n    UNUSED (pi2_tmp);\n    UNUSED (pi2_dc_ld_addr);\n\n    /*************************************************************/\n    /* Dequantization of coefficients. Will be replaced by SIMD  */\n    /* operations on platform                                    */\n    /*************************************************************/\n    src_r0_r1 = _mm_loadu_si128((__m128i *) (pi2_src)); //a00 a01 a02 a03 a10 a11 a12 a13 -- the source matrix 0th,1st row\n    src_r2_r3 = _mm_loadu_si128((__m128i *) (pi2_src + 8)); //a20 a21 a22 a23 a30 a31 a32 a33 -- the source matrix 2nd,3rd row\n    scalemat_r0_r1 = _mm_loadu_si128((__m128i *) (pu2_iscal_mat)); //b00 b01 b02 b03 b10 b11 b12 b13 -- the scaling matrix 0th,1st row\n    scalemat_r2_r3 = _mm_loadu_si128((__m128i *) (pu2_iscal_mat + 8)); //b20 b21 b22 b23 b30 b31 b32 b33 -- the scaling matrix 2nd,3rd row\n    dequant_r0_r1 = _mm_loadu_si128((__m128i *) (pu2_weigh_mat)); //q00 q01 q02 q03 q10 q11 q12 q13 -- all 16 bits\n    dequant_r2_r3 = _mm_loadu_si128((__m128i *) (pu2_weigh_mat + 8)); //q20 q21 q22 q23 q30 q31 q32 q33 -- all 16 bits\n\n    temp0 = _mm_mullo_epi16(scalemat_r0_r1, dequant_r0_r1); //b00*q00 b01*q01 b02*q02 b03*q03 b10*q10 b11*q11 b12*q12 b13*q13 -- 16 bit result\n    temp1 = _mm_mullo_epi16(scalemat_r2_r3, dequant_r2_r3); //b00*q00 b01*q01 b02*q02 b03*q03 b10*q10 b11*q11 b12*q12 b13*q13 -- 16 bit result\n\n    temp4 = _mm_unpacklo_epi16(temp0, zero_8x16b); // b00*q00 0 b01*q01 0 b02*q02 0 b03*q03 0 -- 16 bit long\n    temp5 = _mm_unpackhi_epi16(temp0, zero_8x16b); // b10*q10 0 b11*q11 0 b12*q12 0 b13*q13 0 -- 16 bit long\n    temp6 = _mm_unpacklo_epi16(temp1, zero_8x16b); // b00*q00 0 b01*q01 0 b02*q02 0 b03*q03 0 -- 16 bit long\n    temp7 = _mm_unpackhi_epi16(temp1, zero_8x16b); // b10*q10 0 b11*q11 0 b12*q12 0 b13*q13 0 -- 16 bit long\n\n    src_r0 = _mm_unpacklo_epi16(src_r0_r1, zero_8x16b); // a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r1 = _mm_unpackhi_epi16(src_r0_r1, zero_8x16b); // a10 0 a11 0 a12 0 a13 0 -- 16 bit long\n    src_r2 = _mm_unpacklo_epi16(src_r2_r3, zero_8x16b); // a20 0 a21 0 a22 0 a23 0 -- 16 bit long\n    src_r3 = _mm_unpackhi_epi16(src_r2_r3, zero_8x16b); // a30 0 a31 0 a32 0 a33 0 -- 16 bit long\n\n    temp4 = _mm_madd_epi16(src_r0, temp4); //a00*b00*q00 a10*b10*q10 a20*b20*q20 a30*b30 q30 -- 32 bits long\n    temp5 = _mm_madd_epi16(src_r1, temp5);\n    temp6 = _mm_madd_epi16(src_r2, temp6);\n    temp7 = _mm_madd_epi16(src_r3, temp7);\n\n    if (u4_qp_div_6 >= 4) {\n        resq_r0 = _mm_slli_epi32(temp4, u4_qp_div_6 - 4);\n        resq_r1 = _mm_slli_epi32(temp5, u4_qp_div_6 - 4);\n        resq_r2 = _mm_slli_epi32(temp6, u4_qp_div_6 - 4);\n        resq_r3 = _mm_slli_epi32(temp7, u4_qp_div_6 - 4);\n    } else {\n        temp4 = _mm_add_epi32(temp4, add_rshift);\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp6 = _mm_add_epi32(temp6, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r0 = _mm_srai_epi32(temp4, 4 - u4_qp_div_6);\n        resq_r1 = _mm_srai_epi32(temp5, 4 - u4_qp_div_6);\n        resq_r2 = _mm_srai_epi32(temp6, 4 - u4_qp_div_6);\n        resq_r3 = _mm_srai_epi32(temp7, 4 - u4_qp_div_6);\n    }\n\n    if (iq_start_idx == 1)\n    {\n        resq_r0 = _mm_insert_epi16(resq_r0,(WORD32)pi2_src[0],0);\n        if (pi2_src[0] >= 0)\n            resq_r0 = _mm_insert_epi16(resq_r0,0,1);\n        else\n            resq_r0 = _mm_insert_epi16(resq_r0,-1,1);\n    }\n    /* Perform Inverse transform */\n    /*-------------------------------------------------------------*/\n    /* IDCT [ Horizontal transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 a1 a2 a3\n     *  b0 b1 b2 b3\n     *  c0 c1 c2 c3\n     *  d0 d1 d2 d3\n     */\n    temp1 = _mm_unpacklo_epi32(resq_r0, resq_r1);                  //a0 b0 a1 b1\n    temp3 = _mm_unpacklo_epi32(resq_r2, resq_r3);                  //c0 d0 c1 d1\n    temp2 = _mm_unpackhi_epi32(resq_r0, resq_r1);                  //a2 b2 a3 b3\n    temp4 = _mm_unpackhi_epi32(resq_r2, resq_r3);                  //c2 d2 c3 d3\n    resq_r0 = _mm_unpacklo_epi64(temp1, temp3);                    //a0 b0 c0 d0\n    resq_r1 = _mm_unpackhi_epi64(temp1, temp3);                    //a1 b1 c1 d1\n    resq_r2 = _mm_unpacklo_epi64(temp2, temp4);                    //a2 b2 c2 d2\n    resq_r3 = _mm_unpackhi_epi64(temp2, temp4);                    //a3 b3 c3 d3\n    //Transform starts -- horizontal transform\n    /*------------------------------------------------------------------*/\n    /* z0 = w0 + w2                                             */\n    temp0 = _mm_add_epi32(resq_r0, resq_r2);\n    /* z1 = w0 - w2                                             */\n    temp1 = _mm_sub_epi32(resq_r0, resq_r2);\n    /* z2 = (w1 >> 1) - w3                                      */\n    temp2 = _mm_srai_epi32(resq_r1, 1);                         //(w1>>1)\n    temp2 = _mm_sub_epi32(temp2, resq_r3);                      //(w1>>1) - w3\n    /* z3 = w1 + (w3 >> 1)                                      */\n    temp3 = _mm_srai_epi32(resq_r3, 1);                         //(w3>>1) + w1\n    temp3 = _mm_add_epi32(temp3, resq_r1);\n    /*----------------------------------------------------------*/\n    /* x0 = z0 + z3                                             */\n    resq_r0 = _mm_add_epi32(temp0, temp3);\n    /* x1 = z1 + z2                                             */\n    resq_r1 = _mm_add_epi32(temp1, temp2);\n    /* x2 = z1 - z2                                             */\n    resq_r2 = _mm_sub_epi32(temp1, temp2);\n    /* x3 = z0 - z3                                             */\n    resq_r3 = _mm_sub_epi32(temp0, temp3);\n    // Matrix transpose\n    /*\n     *  a0 b0 c0 d0\n     *  a1 b1 c1 d1\n     *  a2 b2 c2 d2\n     *  a3 b3 c3 d3\n     */\n    temp1 = _mm_unpacklo_epi32(resq_r0, resq_r1);                  //a0 a1 b0 b1\n    temp3 = _mm_unpacklo_epi32(resq_r2, resq_r3);                  //a2 a3 b2 b3\n    temp2 = _mm_unpackhi_epi32(resq_r0, resq_r1);                  //c0 c1 d0 d1\n    temp4 = _mm_unpackhi_epi32(resq_r2, resq_r3);                  //c2 c3 d2 d3\n    resq_r0 = _mm_unpacklo_epi64(temp1, temp3);                    //a0 a1 a2 a3\n    resq_r1 = _mm_unpackhi_epi64(temp1, temp3);                    //b0 b1 b2 b3\n    resq_r2 = _mm_unpacklo_epi64(temp2, temp4);                    //c0 c1 c2 c3\n    resq_r3 = _mm_unpackhi_epi64(temp2, temp4);                    //d0 d1 d2 d3\n    //Transform ends -- horizontal transform\n\n    zero_8x16b = _mm_setzero_si128();                  // all bits reset to zero\n    //Load pred buffer\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[0])); //p00 p01 p02 p03 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r0 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p00 p01 p02 p03 0 0 0 0 -- all 16 bits\n\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[pred_strd])); //p10 p11 p12 p13 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p10 p11 p12 p13 0 0 0 0 -- all 16 bits\n\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[2 * pred_strd])); //p20 p21 p22 p23 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r2 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p20 p21 p22 p23 0 0 0 0 -- all 16 bits\n\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[3 * pred_strd])); //p30 p31 p32 p33 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r3 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p30 p31 p32 p33 0 0 0 0 -- all 16 bits\n    pred_r0 = _mm_unpacklo_epi16(pred_r0, zero_8x16b); //p00 p01 p02 p03 -- 32 bits sign extended\n    pred_r1 = _mm_unpacklo_epi16(pred_r1, zero_8x16b); //p10 p11 p12 p13 -- 32 bits sign extended\n    pred_r2 = _mm_unpacklo_epi16(pred_r2, zero_8x16b); //p20 p21 p22 p23 -- 32 bits sign extended\n    pred_r3 = _mm_unpacklo_epi16(pred_r3, zero_8x16b); //p30 p31 p32 p33 -- 32 bits sign extended\n\n    /*--------------------------------------------------------------*/\n    /* IDCT [ Vertical transformation] and Xij = (xij + 32)>>6      */\n    /*                                                              */\n    /* Add the prediction and store it back to same buffer          */\n    /*--------------------------------------------------------------*/\n    /* z0j = y0j + y2j                                                        */\n    temp0 = _mm_add_epi32(resq_r0, resq_r2);\n    /* z1j = y0j - y2j                                                        */\n    temp1 = _mm_sub_epi32(resq_r0, resq_r2);\n    /* z2j = (y1j>>1) - y3j                                                        */\n    temp2 = _mm_srai_epi32(resq_r1, 1);                             //(y1j>>1)\n    temp2 = _mm_sub_epi32(temp2, resq_r3);\n    /* z3j = y1j + (y3j>>1)                                                        */\n    temp3 = _mm_srai_epi32(resq_r3, 1);                             //(y3j>>1)\n    temp3 = _mm_add_epi32(temp3, resq_r1);\n\n    /* x0j = z0j + z3j                                                        */\n    temp4 = _mm_add_epi32(temp0, temp3);\n    temp4 = _mm_add_epi32(temp4, value_32);\n    temp4 = _mm_srai_epi32(temp4, 6);\n    temp4 = _mm_add_epi32(temp4, pred_r0);\n    /* x1j = z1j + z2j                                                        */\n    temp5 = _mm_add_epi32(temp1, temp2);\n    temp5 = _mm_add_epi32(temp5, value_32);\n    temp5 = _mm_srai_epi32(temp5, 6);\n    temp5 = _mm_add_epi32(temp5, pred_r1);\n    /* x2j = z1j - z2j                                                        */\n    temp6 = _mm_sub_epi32(temp1, temp2);\n    temp6 = _mm_add_epi32(temp6, value_32);\n    temp6 = _mm_srai_epi32(temp6, 6);\n    temp6 = _mm_add_epi32(temp6, pred_r2);\n    /* x3j = z0j - z3j                                                        */\n    temp7 = _mm_sub_epi32(temp0, temp3);\n    temp7 = _mm_add_epi32(temp7, value_32);\n    temp7 = _mm_srai_epi32(temp7, 6);\n    temp7 = _mm_add_epi32(temp7, pred_r3);\n\n    // 32-bit to 16-bit conversion\n    temp0 = _mm_packs_epi32(temp4, temp5);\n    temp1 = _mm_packs_epi32(temp6, temp7);\n    /*------------------------------------------------------------------*/\n    //Clipping the results to 8 bits\n    sign_reg = _mm_cmpgt_epi16(temp0, zero_8x16b);      // sign check\n    temp0 = _mm_and_si128(temp0, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp1, zero_8x16b);\n    temp1 = _mm_and_si128(temp1, sign_reg);\n\n    resq_r0 = _mm_packus_epi16(temp0, temp1);\n    resq_r1 = _mm_srli_si128(resq_r0, 4);\n    resq_r2 = _mm_srli_si128(resq_r1, 4);\n    resq_r3 = _mm_srli_si128(resq_r2, 4);\n\n    *pu4_out = _mm_cvtsi128_si32(resq_r0);\n    pu1_out += out_strd;\n    pu4_out = (UWORD32 *) (pu1_out);\n    *(pu4_out) = _mm_cvtsi128_si32(resq_r1);\n    pu1_out += out_strd;\n    pu4_out = (UWORD32 *) (pu1_out);\n    *(pu4_out) = _mm_cvtsi128_si32(resq_r2);\n    pu1_out += out_strd;\n    pu4_out = (UWORD32 *) (pu1_out);\n    *(pu4_out) = _mm_cvtsi128_si32(resq_r3);\n}\n/**\n *******************************************************************************\n *\n * @brief\n *  This function performs inverse quant and Inverse transform type Ci4 for 8x8 block\n *\n * @par Description:\n *  Performs inverse transform Ci8 and adds the residue to get the\n *  reconstructed block\n *\n * @param[in] pi2_src\n *  Input 8x8coefficients\n *\n * @param[in] pu1_pred\n *  Prediction 8x8 block\n *\n * @param[out] pu1_recon\n *  Output 8x8 block\n *\n * @param[in] q_div\n *  QP/6\n *\n * @param[in] q_rem\n *  QP%6\n *\n * @param[in] q_lev\n *  Quantizer level\n *\n * @param[in] u4_src_stride\n *  Input stride\n *\n * @param[in] u4_pred_stride,\n *  Prediction stride\n *\n * @param[in] u4_out_stride\n *  Output Stride\n *\n * @param[in] pi4_tmp\n *  temporary buffer of size 1*64\n *  the tmp for each block\n *\n * @param[in] pu4_iquant_mat\n *  Pointer to the inverse quantization matrix\n *\n * @returns  Void\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\nATTRIBUTE_SSSE3\nvoid ih264_iquant_itrans_recon_8x8_ssse3(WORD16 *pi2_src,\n                                         UWORD8 *pu1_pred,\n                                         UWORD8 *pu1_out,\n                                         WORD32 pred_strd,\n                                         WORD32 out_strd,\n                                         const UWORD16 *pu2_iscale_mat,\n                                         const UWORD16 *pu2_weigh_mat,\n                                         UWORD32 qp_div,\n                                         WORD16 *pi2_tmp,\n                                         WORD32 iq_start_idx,\n                                         WORD16 *pi2_dc_ld_addr)\n{\n    __m128i src_r0;\n    __m128i scalemat_r0;\n    __m128i zero_8x16b = _mm_setzero_si128(); // all bits reset to zero\n    // __m128i one_8x16b = _mm_set1_epi8(255); // all bits set to 1\n    // __m128i one_zero_mask = _mm_unpacklo_epi16(one_8x16b, zero_8x16b); // 1 0 1 0 1 0 1 0 --- 16 bits size\n    __m128i value_32 = _mm_set1_epi32(32);\n    __m128i add_rshift = _mm_set1_epi32((qp_div < 6) ? (1 << (5 - qp_div)) : 0);\n    __m128i dequant_r0;\n    __m128i predload_r;\n    __m128i pred_r0_1, pred_r1_1, pred_r2_1, pred_r3_1, pred_r4_1, pred_r5_1,\n            pred_r6_1, pred_r7_1;\n    __m128i sign_reg;\n    __m128i src_r0_1, src_r0_2;\n    __m128i scalemat_r0_1, scalemat_r0_2;\n    __m128i temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;\n    __m128i temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17,\n            temp18, temp19, temp20;\n    // To store dequantization results\n    __m128i resq_r0_1, resq_r0_2, resq_r1_1, resq_r1_2, resq_r2_1, resq_r2_2,\n            resq_r3_1, resq_r3_2, resq_r4_1, resq_r4_2, resq_r5_1, resq_r5_2,\n            resq_r6_1, resq_r6_2, resq_r7_1, resq_r7_2;\n    UNUSED (pi2_tmp);\n    UNUSED (iq_start_idx);\n    UNUSED (pi2_dc_ld_addr);\n\n    /*************************************************************/\n    /* Dequantization of coefficients. Will be replaced by SIMD  */\n    /* operations on platform. Note : DC coeff is not scaled     */\n    /*************************************************************/\n\n    // Row 0 processing\n    src_r0 = _mm_loadu_si128((__m128i *) (pi2_src)); //a00 a01 a02 a03 a04 a05 a06 a07 -- the source matrix 0th row\n    scalemat_r0 = _mm_loadu_si128((__m128i *) (pu2_iscale_mat)); //b00 b01 b02 b03 b04 b05 b06 b07 -- the scaling matrix 0th row\n    dequant_r0 = _mm_loadu_si128((__m128i *) (&pu2_weigh_mat[0])); //q0 q1 q2 q3 q4 q5 q6 q7 -- all 16 bits\n    src_r0_1 = _mm_unpacklo_epi16(src_r0, zero_8x16b); //a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r0_2 = _mm_unpackhi_epi16(src_r0, zero_8x16b); // a04 0 a05 0 a06 0 a07 0 -- 16 bit long\n    temp10 = _mm_mullo_epi16(scalemat_r0, dequant_r0); //b00*q0 b01*q1 b02*q2 b03*q3 b04*q4 b05*q5 b06*q6 b07*q7 -- 16 bit result\n    scalemat_r0_1 = _mm_unpacklo_epi16(temp10, zero_8x16b); // b00*q0 0 b01*q1 0 b02*q2 0 b03*q3 0 -- 16 bit long\n    scalemat_r0_2 = _mm_unpackhi_epi16(temp10, zero_8x16b); // b04*q4 0 b05*q5 0 b06*q6 0 b07*q7 0 -- 16 bit long\n\n    temp5 = _mm_madd_epi16(src_r0_1, scalemat_r0_1); // a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 -- 32 bits long\n    temp7 = _mm_madd_epi16(src_r0_2, scalemat_r0_2); // a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 32 bits long\n\n    if (qp_div >= 6) {\n        resq_r0_1 = _mm_slli_epi32(temp5, qp_div - 6);\n        resq_r0_2 = _mm_slli_epi32(temp7, qp_div - 6);\n    } else {\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r0_1 = _mm_srai_epi32(temp5, 6 - qp_div);\n        resq_r0_2 = _mm_srai_epi32(temp7, 6 - qp_div);\n    }\n    resq_r0_1 = _mm_packs_epi32(resq_r0_1, resq_r0_2); //a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 16 bit long\n    // Row 1 processing\n    src_r0 = _mm_loadu_si128((__m128i *) (pi2_src + 8)); //a00 a01 a02 a03 a04 a05 a06 a07 a08 -- the source matrix 1st row\n    scalemat_r0 = _mm_loadu_si128((__m128i *) (pu2_iscale_mat + 8)); //b00 b01 b02 b03 b04 b05 b06 b07 b08 -- the scaling matrix 1st row\n    dequant_r0 = _mm_loadu_si128((__m128i *) (&pu2_weigh_mat[8])); //q0 q1 q2 q3 q4 q5 q6 q7 -- all 16 bits\n    src_r0_1 = _mm_unpacklo_epi16(src_r0, zero_8x16b); //a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r0_2 = _mm_unpackhi_epi16(src_r0, zero_8x16b); // a04 0 a05 0 a06 0 a07 0 -- 16 bit long\n    temp10 = _mm_mullo_epi16(scalemat_r0, dequant_r0); //b00*q0 b01*q1 b02*q2 b03*q3 b04*q4 b05*q5 b06*q6 b07*q7 -- 16 bit result\n    scalemat_r0_1 = _mm_unpacklo_epi16(temp10, zero_8x16b); // b00*q0 0 b01*q1 0 b02*q2 0 b03*q3 0 -- 16 bit long\n    scalemat_r0_2 = _mm_unpackhi_epi16(temp10, zero_8x16b); // b04*q4 0 b05*q5 0 b06*q6 0 b07*q7 0 -- 16 bit long\n    temp5 = _mm_madd_epi16(src_r0_1, scalemat_r0_1); // a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 -- 32 bits long\n    temp7 = _mm_madd_epi16(src_r0_2, scalemat_r0_2); // a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 32 bits long\n    if (qp_div >= 6) {\n        resq_r1_1 = _mm_slli_epi32(temp5, qp_div - 6);\n        resq_r1_2 = _mm_slli_epi32(temp7, qp_div - 6);\n    } else {\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r1_1 = _mm_srai_epi32(temp5, 6 - qp_div);\n        resq_r1_2 = _mm_srai_epi32(temp7, 6 - qp_div);\n    }\n    resq_r1_1 = _mm_packs_epi32(resq_r1_1, resq_r1_2); //a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 16 bit long\n    // Row 2 processing\n    src_r0 = _mm_loadu_si128((__m128i *) (pi2_src + 16)); //a00 a01 a02 a03 a04 a05 a06 a07 a08 -- the source matrix 2nd row\n    scalemat_r0 = _mm_loadu_si128((__m128i *) (pu2_iscale_mat + 16)); //b00 b01 b02 b03 b04 b05 b06 b07 b08 -- the scaling matrix 2nd row\n    dequant_r0 = _mm_loadu_si128((__m128i *) (&pu2_weigh_mat[16])); //q0 q1 q2 q3 q4 q5 q6 q7 -- all 16 bits\n    src_r0_1 = _mm_unpacklo_epi16(src_r0, zero_8x16b); //a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r0_2 = _mm_unpackhi_epi16(src_r0, zero_8x16b); // a04 0 a05 0 a06 0 a07 0 -- 16 bit long\n    temp10 = _mm_mullo_epi16(scalemat_r0, dequant_r0); //b00*q0 b01*q1 b02*q2 b03*q3 b04*q4 b05*q5 b06*q6 b07*q7 -- 16 bit result\n    scalemat_r0_1 = _mm_unpacklo_epi16(temp10, zero_8x16b); // b00*q0 0 b01*q1 0 b02*q2 0 b03*q3 0 -- 16 bit long\n    scalemat_r0_2 = _mm_unpackhi_epi16(temp10, zero_8x16b); // b04*q4 0 b05*q5 0 b06*q6 0 b07*q7 0 -- 16 bit long\n    temp5 = _mm_madd_epi16(src_r0_1, scalemat_r0_1); // a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 -- 32 bits long\n    temp7 = _mm_madd_epi16(src_r0_2, scalemat_r0_2); // a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 32 bits long\n    if (qp_div >= 6) {\n        resq_r2_1 = _mm_slli_epi32(temp5, qp_div - 6);\n        resq_r2_2 = _mm_slli_epi32(temp7, qp_div - 6);\n    } else {\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r2_1 = _mm_srai_epi32(temp5, 6 - qp_div);\n        resq_r2_2 = _mm_srai_epi32(temp7, 6 - qp_div);\n    }\n    resq_r2_1 = _mm_packs_epi32(resq_r2_1, resq_r2_2); //a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 16 bit long\n    // Row 3 processing\n    src_r0 = _mm_loadu_si128((__m128i *) (pi2_src + 24)); //a00 a01 a02 a03 a04 a05 a06 a07 a08 -- the source matrix 3rd row\n    scalemat_r0 = _mm_loadu_si128((__m128i *) (pu2_iscale_mat + 24)); //b00 b01 b02 b03 b04 b05 b06 b07 b08 -- the scaling matrix 3rd row\n    dequant_r0 = _mm_loadu_si128((__m128i *) (&pu2_weigh_mat[24])); //q0 q1 q2 q3 q4 q5 q6 q7 -- all 16 bits\n    src_r0_1 = _mm_unpacklo_epi16(src_r0, zero_8x16b); //a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r0_2 = _mm_unpackhi_epi16(src_r0, zero_8x16b); // a04 0 a05 0 a06 0 a07 0 -- 16 bit long\n    temp10 = _mm_mullo_epi16(scalemat_r0, dequant_r0); //b00*q0 b01*q1 b02*q2 b03*q3 b04*q4 b05*q5 b06*q6 b07*q7 -- 16 bit result\n    scalemat_r0_1 = _mm_unpacklo_epi16(temp10, zero_8x16b); // b00*q0 0 b01*q1 0 b02*q2 0 b03*q3 0 -- 16 bit long\n    scalemat_r0_2 = _mm_unpackhi_epi16(temp10, zero_8x16b); // b04*q4 0 b05*q5 0 b06*q6 0 b07*q7 0 -- 16 bit long\n    temp5 = _mm_madd_epi16(src_r0_1, scalemat_r0_1); // a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 - 32 bits long\n    temp7 = _mm_madd_epi16(src_r0_2, scalemat_r0_2); // a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 32 bits long\n    if (qp_div >= 6) {\n        resq_r3_1 = _mm_slli_epi32(temp5, qp_div - 6);\n        resq_r3_2 = _mm_slli_epi32(temp7, qp_div - 6);\n    } else {\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r3_1 = _mm_srai_epi32(temp5, 6 - qp_div);\n        resq_r3_2 = _mm_srai_epi32(temp7, 6 - qp_div);\n    }\n    resq_r3_1 = _mm_packs_epi32(resq_r3_1, resq_r3_2); //a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 16 bit long\n    // Row 4 processing\n    src_r0 = _mm_loadu_si128((__m128i *) (pi2_src + 32)); //a00 a01 a02 a03 a04 a05 a06 a07 a08 -- the source matrix 4th row\n    scalemat_r0 = _mm_loadu_si128((__m128i *) (pu2_iscale_mat + 32)); //b00 b01 b02 b03 b04 b05 b06 b07 b08 -- the scaling matrix 4th row\n    dequant_r0 = _mm_loadu_si128((__m128i *) (&pu2_weigh_mat[32])); //q0 q1 q2 q3 q4 q5 q6 q7 -- all 16 bits\n    src_r0_1 = _mm_unpacklo_epi16(src_r0, zero_8x16b); //a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r0_2 = _mm_unpackhi_epi16(src_r0, zero_8x16b); // a04 0 a05 0 a06 0 a07 0 -- 16 bit long\n    temp10 = _mm_mullo_epi16(scalemat_r0, dequant_r0); //b00*q0 b01*q1 b02*q2 b03*q3 b04*q4 b05*q5 b06*q6 b07*q7 -- 16 bit result\n    scalemat_r0_1 = _mm_unpacklo_epi16(temp10, zero_8x16b); // b00*q0 0 b01*q1 0 b02*q2 0 b03*q3 0 -- 16 bit long\n    scalemat_r0_2 = _mm_unpackhi_epi16(temp10, zero_8x16b); // b04*q4 0 b05*q5 0 b06*q6 0 b07*q7 0 -- 16 bit long\n    temp5 = _mm_madd_epi16(src_r0_1, scalemat_r0_1); // a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 -- 32 bits long\n    temp7 = _mm_madd_epi16(src_r0_2, scalemat_r0_2); // a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 32 bits long\n    if (qp_div >= 6) {\n        resq_r4_1 = _mm_slli_epi32(temp5, qp_div - 6);\n        resq_r4_2 = _mm_slli_epi32(temp7, qp_div - 6);\n\n    } else {\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r4_1 = _mm_srai_epi32(temp5, 6 - qp_div);\n        resq_r4_2 = _mm_srai_epi32(temp7, 6 - qp_div);\n    }\n    resq_r4_1 = _mm_packs_epi32(resq_r4_1, resq_r4_2); //a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 16 bit long\n    // Row 5 processing\n    src_r0 = _mm_loadu_si128((__m128i *) (pi2_src + 40)); //a00 a01 a02 a03 a04 a05 a06 a07 a08 -- the source matrix 5th row\n    scalemat_r0 = _mm_loadu_si128((__m128i *) (pu2_iscale_mat + 40)); //b00 b01 b02 b03 b04 b05 b06 b07 b08 -- the scaling matrix 5th row\n    dequant_r0 = _mm_loadu_si128((__m128i *) (&pu2_weigh_mat[40])); //q0 q1 q2 q3 q4 q5 q6 q7 -- all 16 bits\n    src_r0_1 = _mm_unpacklo_epi16(src_r0, zero_8x16b); //a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r0_2 = _mm_unpackhi_epi16(src_r0, zero_8x16b); // a04 0 a05 0 a06 0 a07 0 -- 16 bit long\n    temp10 = _mm_mullo_epi16(scalemat_r0, dequant_r0); //b00*q0 b01*q1 b02*q2 b03*q3 b04*q4 b05*q5 b06*q6 b07*q7 -- 16 bit result\n    scalemat_r0_1 = _mm_unpacklo_epi16(temp10, zero_8x16b); // b00*q0 0 b01*q1 0 b02*q2 0 b03*q3 0 -- 16 bit long\n    scalemat_r0_2 = _mm_unpackhi_epi16(temp10, zero_8x16b); // b04*q4 0 b05*q5 0 b06*q6 0 b07*q7 0 -- 16 bit long\n    temp5 = _mm_madd_epi16(src_r0_1, scalemat_r0_1); // a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 -- 32 bits long\n    temp7 = _mm_madd_epi16(src_r0_2, scalemat_r0_2); // a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 32 bits long\n    if (qp_div >= 6) {\n        resq_r5_1 = _mm_slli_epi32(temp5, qp_div - 6);\n        resq_r5_2 = _mm_slli_epi32(temp7, qp_div - 6);\n        //resq_r5_1 = _mm_and_si128(resq_r5_1,one_zero_mask);\n        //resq_r5_2 = _mm_and_si128(resq_r5_2,one_zero_mask);\n    } else {\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r5_1 = _mm_srai_epi32(temp5, 6 - qp_div);\n        resq_r5_2 = _mm_srai_epi32(temp7, 6 - qp_div);\n    }\n    resq_r5_1 = _mm_packs_epi32(resq_r5_1, resq_r5_2); //a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 16 bit long\n    // Row 6 processing\n    src_r0 = _mm_loadu_si128((__m128i *) (pi2_src + 48)); //a00 a01 a02 a03 a04 a05 a06 a07 a08 -- the source matrix 6th row\n    scalemat_r0 = _mm_loadu_si128((__m128i *) (pu2_iscale_mat + 48)); //b00 b01 b02 b03 b04 b05 b06 b07 b08 -- the scaling matrix 6th row\n    dequant_r0 = _mm_loadu_si128((__m128i *) (&pu2_weigh_mat[48])); //q0 q1 q2 q3 q4 q5 q6 q7 -- all 16 bits\n    src_r0_1 = _mm_unpacklo_epi16(src_r0, zero_8x16b); //a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r0_2 = _mm_unpackhi_epi16(src_r0, zero_8x16b); // a04 0 a05 0 a06 0 a07 0 -- 16 bit long\n    temp10 = _mm_mullo_epi16(scalemat_r0, dequant_r0); //b00*q0 b01*q1 b02*q2 b03*q3 b04*q4 b05*q5 b06*q6 b07*q7 -- 16 bit result\n    scalemat_r0_1 = _mm_unpacklo_epi16(temp10, zero_8x16b); // b00*q0 0 b01*q1 0 b02*q2 0 b03*q3 0 -- 16 bit long\n    scalemat_r0_2 = _mm_unpackhi_epi16(temp10, zero_8x16b); // b04*q4 0 b05*q5 0 b06*q6 0 b07*q7 0 -- 16 bit long\n    temp5 = _mm_madd_epi16(src_r0_1, scalemat_r0_1); // a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 -- 32 bits long\n    temp7 = _mm_madd_epi16(src_r0_2, scalemat_r0_2); // a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 32 bits long\n    if (qp_div >= 6) {\n        resq_r6_1 = _mm_slli_epi32(temp5, qp_div - 6);\n        resq_r6_2 = _mm_slli_epi32(temp7, qp_div - 6);\n        //resq_r6_1 = _mm_and_si128(resq_r6_1,one_zero_mask);\n        //resq_r6_2 = _mm_and_si128(resq_r6_2,one_zero_mask);\n    } else {\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r6_1 = _mm_srai_epi32(temp5, 6 - qp_div);\n        resq_r6_2 = _mm_srai_epi32(temp7, 6 - qp_div);\n        //resq_r6_1 = _mm_and_si128(resq_r6_1,one_zero_mask);\n        //resq_r6_2 = _mm_and_si128(resq_r6_2,one_zero_mask);\n    }\n    resq_r6_1 = _mm_packs_epi32(resq_r6_1, resq_r6_2); //a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 16 bit long\n    // Row 7 processing\n    src_r0 = _mm_loadu_si128((__m128i *) (pi2_src + 56)); //a00 a01 a02 a03 a04 a05 a06 a07 a08 -- the source matrix 7th row\n    scalemat_r0 = _mm_loadu_si128((__m128i *) (pu2_iscale_mat + 56)); //b00 b01 b02 b03 b04 b05 b06 b07 b08 -- the scaling matrix 7th row\n    dequant_r0 = _mm_loadu_si128((__m128i *) (&pu2_weigh_mat[56])); //q0 q1 q2 q3 q4 q5 q6 q7 -- all 16 bits\n    src_r0_1 = _mm_unpacklo_epi16(src_r0, zero_8x16b); //a00 0 a01 0 a02 0 a03 0 -- 16 bit long\n    src_r0_2 = _mm_unpackhi_epi16(src_r0, zero_8x16b); // a04 0 a05 0 a06 0 a07 0 -- 16 bit long\n    temp10 = _mm_mullo_epi16(scalemat_r0, dequant_r0); //b00*q0 b01*q1 b02*q2 b03*q3 b04*q4 b05*q5 b06*q6 b07*q7 -- 16 bit result\n    scalemat_r0_1 = _mm_unpacklo_epi16(temp10, zero_8x16b); // b00*q0 0 b01*q1 0 b02*q2 0 b03*q3 0 -- 16 bit long\n    scalemat_r0_2 = _mm_unpackhi_epi16(temp10, zero_8x16b); // b04*q4 0 b05*q5 0 b06*q6 0 b07*q7 0 -- 16 bit long\n    temp5 = _mm_madd_epi16(src_r0_1, scalemat_r0_1); // a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 -- 32 bits long\n    temp7 = _mm_madd_epi16(src_r0_2, scalemat_r0_2); // a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 32 bits long\n    if (qp_div >= 6) {\n        resq_r7_1 = _mm_slli_epi32(temp5, qp_div - 6);\n        resq_r7_2 = _mm_slli_epi32(temp7, qp_div - 6);\n    } else {\n        temp5 = _mm_add_epi32(temp5, add_rshift);\n        temp7 = _mm_add_epi32(temp7, add_rshift);\n        resq_r7_1 = _mm_srai_epi32(temp5, 6 - qp_div);\n        resq_r7_2 = _mm_srai_epi32(temp7, 6 - qp_div);\n    }\n    resq_r7_1 = _mm_packs_epi32(resq_r7_1, resq_r7_2); //a00*b00*q0 a01*b01*q1 a02*b02*q2 a03*b03*q3 a04*b04*q4 a05*b05*q5 a06*b06*q6 a07*b07*q7 -- 16 bit long\n    /* Perform Inverse transform */\n    /*--------------------------------------------------------------------*/\n    /* IDCT [ Horizontal transformation ]                                 */\n    /*--------------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 a1 a2 a3 a4 a5 a6 a7\n     *  b0 b1 b2 b3 b4 b5 b6 b7\n     *  c0 c1 c2 c3 c4 c5 c6 c7\n     *  d0 d1 d2 d3 d4 d5 d6 d7\n     */\n    temp1 = _mm_unpacklo_epi16(resq_r0_1, resq_r1_1); //a0 b0 a1 b1 a2 b2 a3 b3\n    temp3 = _mm_unpacklo_epi16(resq_r2_1, resq_r3_1); //c0 d0 c1 d1 c2 d2 c3 d3\n    temp2 = _mm_unpackhi_epi16(resq_r0_1, resq_r1_1); //a4 b4 a5 b5 a6 b6 a7 b7\n    temp4 = _mm_unpackhi_epi16(resq_r2_1, resq_r3_1); //c4 d4 c5 d5 c6 d6 c7 d7\n    resq_r0_1 = _mm_unpacklo_epi32(temp1, temp3); //a0 b0 c0 d0 a1 b1 c1 d1\n    resq_r1_1 = _mm_unpackhi_epi32(temp1, temp3); //a2 b2 c2 d2 a3 b3 c3 d3\n    resq_r2_1 = _mm_unpacklo_epi32(temp2, temp4); //a4 b4 c4 d4 a5 b5 c5 d5\n    resq_r3_1 = _mm_unpackhi_epi32(temp2, temp4); //a6 b6 c6 d6 a7 b7 c7 d7\n    /*\n     * e0 e1 e2 e3 e4 e5 e6 e7\n     * f0 f1 f2 f3 f4 f5 f6 f7\n     * g0 g1 g2 g3 g4 g5 g6 g7\n     * h0 h1 h2 h3 h4 h5 h6 h7\n     */\n    temp1 = _mm_unpacklo_epi16(resq_r4_1, resq_r5_1); //e0 f0 e1 f1 e2 f2 e2 f3\n    temp3 = _mm_unpacklo_epi16(resq_r6_1, resq_r7_1); //g0 h0 g1 h1 g2 h2 g3 h3\n    temp2 = _mm_unpackhi_epi16(resq_r4_1, resq_r5_1); //e4 f4 e5 f5 e6 f6 e7 f7\n    temp4 = _mm_unpackhi_epi16(resq_r6_1, resq_r7_1); //g4 h4 g5 h5 g6 h6 g7 h7\n    resq_r4_1 = _mm_unpacklo_epi32(temp1, temp3); //e0 f0 g0 h0 e1 f1 g1 h1\n    resq_r5_1 = _mm_unpackhi_epi32(temp1, temp3); //e2 f2 g2 h2 e3 f3 g3 h3\n    resq_r6_1 = _mm_unpacklo_epi32(temp2, temp4); //e4 f4 g4 h4 e5 f5 g5 h5\n    resq_r7_1 = _mm_unpackhi_epi32(temp2, temp4); //e6 f6 g6 h6 e7 f7 g7 h7\n    /*\n     * a0 b0 c0 d0 a1 b1 c1 d1\n     * a2 b2 c2 d2 a3 b3 c3 d3\n     * a4 b4 c4 d4 a5 b5 c5 d5\n     * a6 b6 c6 d6 a7 b7 c7 d7\n     * e0 f0 g0 h0 e1 f1 g1 h1\n     * e2 f2 g2 h2 e3 f3 g3 h3\n     * e4 f4 g4 h4 e5 f5 g5 h5\n     * e6 f6 g6 h6 e7 f7 g7 h7\n     */\n    resq_r0_2 = _mm_unpacklo_epi64(resq_r0_1, resq_r4_1); //a0 b0 c0 d0 e0 f0 g0 h0\n    resq_r1_2 = _mm_unpackhi_epi64(resq_r0_1, resq_r4_1); //a1 b1 c1 d1 e1 f1 g1 h1\n    resq_r2_2 = _mm_unpacklo_epi64(resq_r1_1, resq_r5_1); //a2 b2 c2 d2 e2 f2 g2 h2\n    resq_r3_2 = _mm_unpackhi_epi64(resq_r1_1, resq_r5_1); //a3 b3 c3 d3 e3 f3 g3 h3\n    resq_r4_2 = _mm_unpacklo_epi64(resq_r2_1, resq_r6_1); //a4 b4 c4 d4 e4 f4 g4 h4\n    resq_r5_2 = _mm_unpackhi_epi64(resq_r2_1, resq_r6_1); //a5 b5 c5 d5 e5 f5 g5 h5\n    resq_r6_2 = _mm_unpacklo_epi64(resq_r3_1, resq_r7_1); //a6 b6 c6 d6 e6 f6 g6 h6\n    resq_r7_2 = _mm_unpackhi_epi64(resq_r3_1, resq_r7_1); //a7 b7 c7 d7 e7 f7 g7 h7\n\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, resq_r1_2);\n    resq_r1_1 = _mm_unpacklo_epi16(resq_r1_2, sign_reg); //a1 b1 c1 d1 -- 32 bit\n    resq_r1_2 = _mm_unpackhi_epi16(resq_r1_2, sign_reg); //e1 f1 g1 h1 -- 32 bit\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, resq_r3_2);\n    resq_r3_1 = _mm_unpacklo_epi16(resq_r3_2, sign_reg); //a3 b3 c3 d3 -- 32 bit\n    resq_r3_2 = _mm_unpackhi_epi16(resq_r3_2, sign_reg); //e3 f3 g3 h3 -- 32 bit\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, resq_r5_2);\n    resq_r5_1 = _mm_unpacklo_epi16(resq_r5_2, sign_reg); //a5 b5 c5 d5 -- 32 bit\n    resq_r5_2 = _mm_unpackhi_epi16(resq_r5_2, sign_reg); //e5 f5 g5 h5 -- 32 bit\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, resq_r7_2);\n    resq_r7_1 = _mm_unpacklo_epi16(resq_r7_2, sign_reg); //a7 b7 c7 d7 -- 32 bit\n    resq_r7_2 = _mm_unpackhi_epi16(resq_r7_2, sign_reg); //e7 f7 g7 h7 -- 32 bit\n    //Transform starts -- horizontal transform\n    /*------------------------------------------------------------------*/\n    /* y0 = w0 + w4                                                     */\n    temp1 = _mm_add_epi16(resq_r0_2, resq_r4_2);\n    /* y2 = w0 - w4                                                      */\n    temp3 = _mm_sub_epi16(resq_r0_2, resq_r4_2);\n    /* y1 = -w3 + w5 - w7 - (w7 >> 1)                                   */\n    temp2 = _mm_sub_epi32(resq_r5_1, resq_r3_1); //-w3+w5\n    temp10 = _mm_sub_epi32(resq_r5_2, resq_r3_2);\n    temp4 = _mm_sub_epi32(temp2, resq_r7_1); //-w3+w5-w7\n    temp12 = _mm_sub_epi32(temp10, resq_r7_2);\n    temp5 = _mm_srai_epi32(resq_r7_1, 1); //w7>>1\n    temp13 = _mm_srai_epi32(resq_r7_2, 1);\n    temp2 = _mm_sub_epi32(temp4, temp5); //-w3+w5-w7 -(w7>>1)\n    temp10 = _mm_sub_epi32(temp12, temp13);\n    temp2 = _mm_packs_epi32(temp2, temp10);\n    /* y3 = w1 + w7 - w3 - (w3 >> 1)                                    */\n    temp4 = _mm_add_epi32(resq_r1_1, resq_r7_1); //w1+w7\n    temp12 = _mm_add_epi32(resq_r1_2, resq_r7_2);\n    temp4 = _mm_sub_epi32(temp4, resq_r3_1); //w1+w7-w3\n    temp12 = _mm_sub_epi32(temp12, resq_r3_2);\n    temp5 = _mm_srai_epi32(resq_r3_1, 1); //w3>>1\n    temp13 = _mm_srai_epi32(resq_r3_2, 1);\n    temp4 = _mm_sub_epi32(temp4, temp5); //w1+w7-w3-(w3>>1)\n    temp12 = _mm_sub_epi32(temp12, temp13);\n    temp4 = _mm_packs_epi32(temp4, temp12);\n    /* y4 = (w2 >> 1) - w6                                              */\n    temp5 = _mm_srai_epi16(resq_r2_2, 1); //w2>>1\n    temp5 = _mm_sub_epi16(temp5, resq_r6_2); //(w2>>1)-w6\n    /* y5 = -w1 + w7 + w5 + (w5 >> 1)                                   */\n    temp6 = _mm_sub_epi32(resq_r7_1, resq_r1_1); //w7-w1\n    temp14 = _mm_sub_epi32(resq_r7_2, resq_r1_2);\n    temp6 = _mm_add_epi32(temp6, resq_r5_1); //w7-w1+w5\n    temp14 = _mm_add_epi32(temp14, resq_r5_2);\n    temp7 = _mm_srai_epi32(resq_r5_1, 1); //w5>>1\n    temp15 = _mm_srai_epi32(resq_r5_2, 1);\n    temp6 = _mm_add_epi32(temp6, temp7); //w7-w1_w5+(w5>>1)\n    temp14 = _mm_add_epi32(temp14, temp15);\n    temp6 = _mm_packs_epi32(temp6, temp14);\n    /* y6 = w2 + (w6 >> 1)                                              */\n    temp7 = _mm_srai_epi16(resq_r6_2, 1); //w6>>1\n    temp7 = _mm_add_epi16(temp7, resq_r2_2); //(w6>>1)+w2\n    /* y7 = w3 + w5 + w1 + (w1 >> 1)                                    */\n    temp8 = _mm_add_epi32(resq_r3_1, resq_r5_1); //w3+w5\n    temp16 = _mm_add_epi32(resq_r3_2, resq_r5_2);\n    temp8 = _mm_add_epi32(temp8, resq_r1_1); //w3+w5+w1\n    temp16 = _mm_add_epi32(temp16, resq_r1_2);\n    temp17 = _mm_srai_epi32(resq_r1_1, 1); //w1>>1\n    temp18 = _mm_srai_epi32(resq_r1_2, 1);\n    temp8 = _mm_add_epi32(temp8, temp17); //w3+w5+w1+(w1>>1)\n    temp16 = _mm_add_epi32(temp16, temp18);\n    temp8 = _mm_packs_epi32(temp8, temp16);\n    /*------------------------------------------------------------------*/\n    /*------------------------------------------------------------------*/\n    /* z0 = y0 + y6                                                        */\n    resq_r0_1 = _mm_add_epi16(temp1, temp7);\n    /* z1 = y1 + (y7 >> 2)                                                */\n    resq_r1_1 = _mm_srai_epi16(temp8, 2);\n    resq_r1_1 = _mm_add_epi16(resq_r1_1, temp2);\n    /* z2 = y2 + y4                                                        */\n    resq_r2_1 = _mm_add_epi16(temp3, temp5);\n    /* z3 = y3 + (y5 >> 2)                                                */\n    resq_r3_1 = _mm_srai_epi16(temp6, 2);\n    resq_r3_1 = _mm_add_epi16(resq_r3_1, temp4);\n    /* z4 = y2 - y4                                                        */\n    resq_r4_1 = _mm_sub_epi16(temp3, temp5);\n    /* z5 = (y3 >> 2) - y5                                                 */\n    resq_r5_1 = _mm_srai_epi16(temp4, 2);\n    resq_r5_1 = _mm_sub_epi16(resq_r5_1, temp6);\n    /* z6 = y0 - y6                                                     */\n    resq_r6_1 = _mm_sub_epi16(temp1, temp7);\n    /* z7 = y7 - (y1 >> 2)                                                 */\n    resq_r7_1 = _mm_srai_epi16(temp2, 2);\n    resq_r7_1 = _mm_sub_epi16(temp8, resq_r7_1);\n    /*------------------------------------------------------------------*/\n    /*------------------------------------------------------------------*/\n    /* x0 = z0 + z7                                                        */\n    temp1 = _mm_add_epi16(resq_r0_1, resq_r7_1);\n    /* x1 = z2 + z5                                                        */\n    temp2 = _mm_add_epi16(resq_r2_1, resq_r5_1);\n    /* x2 = z4 + z3                                                        */\n    temp3 = _mm_add_epi16(resq_r4_1, resq_r3_1);\n    /* x3 = z6 + z1                                                        */\n    temp4 = _mm_add_epi16(resq_r6_1, resq_r1_1);\n    /* x4 = z6 - z1                                                        */\n    temp5 = _mm_sub_epi16(resq_r6_1, resq_r1_1);\n    /* x5 = z4 - z3                                                        */\n    temp6 = _mm_sub_epi16(resq_r4_1, resq_r3_1);\n    /* x6 = z2 - z5                                                        */\n    temp7 = _mm_sub_epi16(resq_r2_1, resq_r5_1);\n    /* x7 = z0 - z7                                                        */\n    temp8 = _mm_sub_epi16(resq_r0_1, resq_r7_1);\n    /*------------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 b0 c0 d0 e0 f0 g0 h0\n     *  a1 b1 c1 d1 e1 f1 g1 h1\n     *  a2 b2 c2 d2 e2 f2 g2 h2\n     *  a3 b3 c3 d3 e3 f3 g3 h3\n     */\n    temp17 = _mm_unpacklo_epi16(temp1, temp2); //a0 a1 b0 b1 c0 c1 d0 d1\n    temp19 = _mm_unpacklo_epi16(temp3, temp4); //a2 a3 b2 b3 c2 c3 d2 d3\n    temp18 = _mm_unpackhi_epi16(temp1, temp2); //e0 e1 f0 f1 g0 g1 h0 h1\n    temp20 = _mm_unpackhi_epi16(temp3, temp4); //e2 e3 f2 f3 g2 g3 h2 h3\n\n    resq_r0_1 = _mm_unpacklo_epi32(temp17, temp19); //a0 a1 a2 a3 b0 b1 b2 b3\n    resq_r1_1 = _mm_unpackhi_epi32(temp17, temp19); //c0 c1 c2 c3 d0 d1 d2 d3\n    resq_r2_1 = _mm_unpacklo_epi32(temp18, temp20); //e0 e1 e2 e3 f0 f1 f2 f3\n    resq_r3_1 = _mm_unpackhi_epi32(temp18, temp20); //g0 g2 g2 g3 h0 h1 h2 h3\n    /*\n     *  a4 b4 c4 d4 e4 f4 g4 h4\n     *  a5 b5 c5 d5 e5 f5 g5 h5\n     *  a6 b6 c6 d6 e6 f6 g6 h6\n     *  a7 b7 c7 d7 e7 f7 g7 h7\n     */\n    temp17 = _mm_unpacklo_epi16(temp5, temp6); //a4 a5 b4 b5 c4 c5 d4 d5\n    temp19 = _mm_unpacklo_epi16(temp7, temp8); //a6 a7 b6 b7 c6 c7 d6 d7\n    temp18 = _mm_unpackhi_epi16(temp5, temp6); //e4 e5 f4 f5 g4 g5 h4 h5\n    temp20 = _mm_unpackhi_epi16(temp7, temp8); //e6 e7 f6 f7 g6 g7 h6 h7\n\n    resq_r4_1 = _mm_unpacklo_epi32(temp17, temp19); //a4 a5 a6 a7 b4 b5 b6 b7\n    resq_r5_1 = _mm_unpackhi_epi32(temp17, temp19); //c4 c5 c6 c7 d4 d5 d6 d7\n    resq_r6_1 = _mm_unpacklo_epi32(temp18, temp20); //e4 e5 e6 e7 f4 f5 f6 f7\n    resq_r7_1 = _mm_unpackhi_epi32(temp18, temp20); //g4 g5 g6 g7 h4 h5 h6 h7\n    /*  a0 a1 a2 a3 b0 b1 b2 b3\n     *  c0 c1 c2 c3 d0 d1 d2 d3\n     *  e0 e1 e2 e3 f0 f1 f2 f3\n     *  g0 g2 g2 g3 h0 h1 h2 h3\n     *  a4 a5 a6 a7 b4 b5 b6 b7\n     *  c4 c5 c6 c7 d4 d5 d6 d7\n     *  e4 e5 e6 e7 f4 f5 f6 f7\n     *  g4 g5 g6 g7 h4 h5 h6 h7\n     */\n    resq_r0_2 = _mm_unpacklo_epi64(resq_r0_1, resq_r4_1); //a0 a1 a2 a3 a4 a5 a6 a7\n    resq_r1_2 = _mm_unpackhi_epi64(resq_r0_1, resq_r4_1); //b0 b1 b2 b3 b4 b5 b6 b7\n    resq_r2_2 = _mm_unpacklo_epi64(resq_r1_1, resq_r5_1); //c0 c1 c2 c3 c4 c5 c6 c7\n    resq_r3_2 = _mm_unpackhi_epi64(resq_r1_1, resq_r5_1); //d0 d1 d2 d3 d4 d5 d6 d7\n    resq_r4_2 = _mm_unpacklo_epi64(resq_r2_1, resq_r6_1); //e0 e1 e2 e3 e4 e5 e6 e7\n    resq_r5_2 = _mm_unpackhi_epi64(resq_r2_1, resq_r6_1); //f0 f1 f2 f3 f4 f5 f6 f7\n    resq_r6_2 = _mm_unpacklo_epi64(resq_r3_1, resq_r7_1); //g0 g1 g2 g3 g4 g5 g6 g7\n    resq_r7_2 = _mm_unpackhi_epi64(resq_r3_1, resq_r7_1); //h0 h1 h2 h3 h4 h5 h6 h7\n\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, resq_r1_2);\n    resq_r1_1 = _mm_unpacklo_epi16(resq_r1_2, sign_reg); //a1 b1 c1 d1 -- 32 bit\n    resq_r1_2 = _mm_unpackhi_epi16(resq_r1_2, sign_reg); //e1 f1 g1 h1 -- 32 bit\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, resq_r3_2);\n    resq_r3_1 = _mm_unpacklo_epi16(resq_r3_2, sign_reg); //a3 b3 c3 d3 -- 32 bit\n    resq_r3_2 = _mm_unpackhi_epi16(resq_r3_2, sign_reg); //e3 f3 g3 h3 -- 32 bit\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, resq_r5_2);\n    resq_r5_1 = _mm_unpacklo_epi16(resq_r5_2, sign_reg); //a5 b5 c5 d5 -- 32 bit\n    resq_r5_2 = _mm_unpackhi_epi16(resq_r5_2, sign_reg); //e5 f5 g5 h5 -- 32 bit\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, resq_r7_2);\n    resq_r7_1 = _mm_unpacklo_epi16(resq_r7_2, sign_reg); //a7 b7 c7 d7 -- 32 bit\n    resq_r7_2 = _mm_unpackhi_epi16(resq_r7_2, sign_reg); //e7 f7 g7 h7 -- 32 bit\n\n    zero_8x16b = _mm_setzero_si128(); // all bits reset to zero\n    //Load pred buffer row 0\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[0])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r0_1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 1\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r1_1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 2\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[2 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r2_1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 3\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[3 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r3_1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 4\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[4 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r4_1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 5\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[5 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bit\n    pred_r5_1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 6\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[6 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r6_1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n    //Load pred buffer row 7\n    predload_r = _mm_loadl_epi64((__m128i *) (&pu1_pred[7 * pred_strd])); //p0 p1 p2 p3 p4 p5 p6 p7 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r7_1 = _mm_unpacklo_epi8(predload_r, zero_8x16b); //p0 p1 p2 p3 p4 p5 p6 p7 -- all 16 bits\n\n    /*--------------------------------------------------------------------*/\n    /* IDCT [ Vertical transformation] and Xij = (xij + 32)>>6            */\n    /*                                                                    */\n    /* Add the prediction and store it back to reconstructed frame buffer */\n    /* [Prediction buffer itself in this case]                            */\n    /*--------------------------------------------------------------------*/\n\n    /* y0j = w0j + w4j                                                     */\n    temp1 = _mm_add_epi16(resq_r0_2, resq_r4_2);\n    /* y2j = w0j - w4j                                                      */\n    temp3 = _mm_sub_epi16(resq_r0_2, resq_r4_2);\n    /* y1j = -w3j + w5j - w7j - (w7j >> 1)                                   */\n    temp2 = _mm_sub_epi32(resq_r5_1, resq_r3_1); //-w3+w5\n    temp10 = _mm_sub_epi32(resq_r5_2, resq_r3_2);\n    temp4 = _mm_sub_epi32(temp2, resq_r7_1); //-w3+w5-w7\n    temp12 = _mm_sub_epi32(temp10, resq_r7_2);\n    temp5 = _mm_srai_epi32(resq_r7_1, 1); //w7>>1\n    temp13 = _mm_srai_epi32(resq_r7_2, 1);\n    temp2 = _mm_sub_epi32(temp4, temp5); //-w3+w5-w7 -(w7>>1)\n    temp10 = _mm_sub_epi32(temp12, temp13);\n    temp2 = _mm_packs_epi32(temp2, temp10);\n    /* y3j = w1j + w7j - w3j - (w3j >> 1)                                    */\n    temp4 = _mm_add_epi32(resq_r1_1, resq_r7_1); //w1+w7\n    temp12 = _mm_add_epi32(resq_r1_2, resq_r7_2);\n    temp4 = _mm_sub_epi32(temp4, resq_r3_1); //w1+w7-w3\n    temp12 = _mm_sub_epi32(temp12, resq_r3_2);\n    temp5 = _mm_srai_epi32(resq_r3_1, 1); //w3>>1\n    temp13 = _mm_srai_epi32(resq_r3_2, 1);\n    temp4 = _mm_sub_epi32(temp4, temp5); //w1+w7-w3-(w3>>1)\n    temp12 = _mm_sub_epi32(temp12, temp13);\n    temp4 = _mm_packs_epi32(temp4, temp12);\n    /* y4j = (w2j >> 1) - w6j                                              */\n    temp5 = _mm_srai_epi16(resq_r2_2, 1); //w2>>1\n    temp5 = _mm_sub_epi16(temp5, resq_r6_2); //(w2>>1)-w6\n    /* y5j = -w1j + w7j + w5j + (w5j >> 1)                                   */\n    temp6 = _mm_sub_epi32(resq_r7_1, resq_r1_1); //w7-w1\n    temp14 = _mm_sub_epi32(resq_r7_2, resq_r1_2);\n    temp6 = _mm_add_epi32(temp6, resq_r5_1); //w7-w1+w5\n    temp14 = _mm_add_epi32(temp14, resq_r5_2);\n    temp7 = _mm_srai_epi32(resq_r5_1, 1); //w5>>1\n    temp15 = _mm_srai_epi32(resq_r5_2, 1);\n    temp6 = _mm_add_epi32(temp6, temp7); //w7-w1_w5+(w5>>1)\n    temp14 = _mm_add_epi32(temp14, temp15);\n    temp6 = _mm_packs_epi32(temp6, temp14);\n    /* y6j = w2j + (w6j >> 1)                                              */\n    temp7 = _mm_srai_epi16(resq_r6_2, 1); //w6>>1\n    temp7 = _mm_add_epi16(temp7, resq_r2_2); //(w6>>1)+w2\n    /* y7j = w3j + w5j + w1j + (w1j >> 1)                                    */\n    temp8 = _mm_add_epi32(resq_r3_1, resq_r5_1); //w3+w5\n    temp16 = _mm_add_epi32(resq_r3_2, resq_r5_2);\n    temp8 = _mm_add_epi32(temp8, resq_r1_1); //w3+w5+w1\n    temp16 = _mm_add_epi32(temp16, resq_r1_2);\n    temp17 = _mm_srai_epi32(resq_r1_1, 1); //w1>>1\n    temp18 = _mm_srai_epi32(resq_r1_2, 1);\n    temp8 = _mm_add_epi32(temp8, temp17); //w3+w5+w1+(w1>>1)\n    temp16 = _mm_add_epi32(temp16, temp18);\n    temp8 = _mm_packs_epi32(temp8, temp16);\n    /*------------------------------------------------------------------*/\n    /*------------------------------------------------------------------*/\n    /* z0j = y0j + y6j                                                        */\n    resq_r0_1 = _mm_add_epi16(temp1, temp7);\n    /* z1j = y1j + (y7j >> 2)                                                */\n    resq_r1_1 = _mm_srai_epi16(temp8, 2);\n    resq_r1_1 = _mm_add_epi16(resq_r1_1, temp2);\n    /* z2j = y2j + y4j                                                        */\n    resq_r2_1 = _mm_add_epi16(temp3, temp5);\n    /* z3j = y3j + (y5j >> 2)                                                */\n    resq_r3_1 = _mm_srai_epi16(temp6, 2);\n    resq_r3_1 = _mm_add_epi16(resq_r3_1, temp4);\n    /* z4j = y2j - y4j                                                        */\n    resq_r4_1 = _mm_sub_epi16(temp3, temp5);\n    /* z5j = (y3j >> 2) - y5j                                                 */\n    resq_r5_1 = _mm_srai_epi16(temp4, 2);\n    resq_r5_1 = _mm_sub_epi16(resq_r5_1, temp6);\n    /* z6j = y0j - y6j                                                     */\n    resq_r6_1 = _mm_sub_epi16(temp1, temp7);\n    /* z7j = y7j - (y1j >> 2)                                                 */\n    resq_r7_1 = _mm_srai_epi16(temp2, 2);\n    resq_r7_1 = _mm_sub_epi16(temp8, resq_r7_1);\n    /*------------------------------------------------------------------*/\n\n    /*------------------------------------------------------------------*/\n    /* x0j = z0j + z7j                                                        */\n    temp1 = _mm_add_epi16(resq_r0_1, resq_r7_1);\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, temp1);\n    temp10 = _mm_unpacklo_epi16(temp1, sign_reg);\n    temp11 = _mm_unpackhi_epi16(temp1, sign_reg);\n    temp10 = _mm_add_epi32(temp10, value_32);\n    temp11 = _mm_add_epi32(temp11, value_32);\n    temp10 = _mm_srai_epi32(temp10, 6);\n    temp11 = _mm_srai_epi32(temp11, 6);\n    temp10 = _mm_packs_epi32(temp10, temp11);\n    temp1 = _mm_add_epi16(temp10, pred_r0_1);\n    /* x1j = z2j + z5j                                                        */\n    temp2 = _mm_add_epi16(resq_r2_1, resq_r5_1);\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, temp2);\n    temp10 = _mm_unpacklo_epi16(temp2, sign_reg);\n    temp11 = _mm_unpackhi_epi16(temp2, sign_reg);\n    temp10 = _mm_add_epi32(temp10, value_32);\n    temp11 = _mm_add_epi32(temp11, value_32);\n    temp10 = _mm_srai_epi32(temp10, 6);\n    temp11 = _mm_srai_epi32(temp11, 6);\n    temp10 = _mm_packs_epi32(temp10, temp11);\n    temp2 = _mm_add_epi16(temp10, pred_r1_1);\n    /* x2j = z4j + z3j                                                        */\n    temp3 = _mm_add_epi16(resq_r4_1, resq_r3_1);\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, temp3);\n    temp10 = _mm_unpacklo_epi16(temp3, sign_reg);\n    temp11 = _mm_unpackhi_epi16(temp3, sign_reg);\n    temp10 = _mm_add_epi32(temp10, value_32);\n    temp11 = _mm_add_epi32(temp11, value_32);\n    temp10 = _mm_srai_epi32(temp10, 6);\n    temp11 = _mm_srai_epi32(temp11, 6);\n    temp10 = _mm_packs_epi32(temp10, temp11);\n    temp3 = _mm_add_epi16(temp10, pred_r2_1);\n    /* x3j = z6j + z1j                                                        */\n    temp4 = _mm_add_epi16(resq_r6_1, resq_r1_1);\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, temp4);\n    temp10 = _mm_unpacklo_epi16(temp4, sign_reg);\n    temp11 = _mm_unpackhi_epi16(temp4, sign_reg);\n    temp10 = _mm_add_epi32(temp10, value_32);\n    temp11 = _mm_add_epi32(temp11, value_32);\n    temp10 = _mm_srai_epi32(temp10, 6);\n    temp11 = _mm_srai_epi32(temp11, 6);\n    temp10 = _mm_packs_epi32(temp10, temp11);\n    temp4 = _mm_add_epi16(temp10, pred_r3_1);\n    /* x4j = z6j - z1j                                                        */\n    temp5 = _mm_sub_epi16(resq_r6_1, resq_r1_1);\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, temp5);\n    temp10 = _mm_unpacklo_epi16(temp5, sign_reg);\n    temp11 = _mm_unpackhi_epi16(temp5, sign_reg);\n    temp10 = _mm_add_epi32(temp10, value_32);\n    temp11 = _mm_add_epi32(temp11, value_32);\n    temp10 = _mm_srai_epi32(temp10, 6);\n    temp11 = _mm_srai_epi32(temp11, 6);\n    temp10 = _mm_packs_epi32(temp10, temp11);\n    temp5 = _mm_add_epi16(temp10, pred_r4_1);\n    /* x5j = z4j - z3j                                                        */\n    temp6 = _mm_sub_epi16(resq_r4_1, resq_r3_1);\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, temp6);\n    temp10 = _mm_unpacklo_epi16(temp6, sign_reg);\n    temp11 = _mm_unpackhi_epi16(temp6, sign_reg);\n    temp10 = _mm_add_epi32(temp10, value_32);\n    temp11 = _mm_add_epi32(temp11, value_32);\n    temp10 = _mm_srai_epi32(temp10, 6);\n    temp11 = _mm_srai_epi32(temp11, 6);\n    temp10 = _mm_packs_epi32(temp10, temp11);\n    temp6 = _mm_add_epi16(temp10, pred_r5_1);\n    /* x6j = z2j - z5j                                                        */\n    temp7 = _mm_sub_epi16(resq_r2_1, resq_r5_1);\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, temp7);\n    temp10 = _mm_unpacklo_epi16(temp7, sign_reg);\n    temp11 = _mm_unpackhi_epi16(temp7, sign_reg);\n    temp10 = _mm_add_epi32(temp10, value_32);\n    temp11 = _mm_add_epi32(temp11, value_32);\n    temp10 = _mm_srai_epi32(temp10, 6);\n    temp11 = _mm_srai_epi32(temp11, 6);\n    temp10 = _mm_packs_epi32(temp10, temp11);\n    temp7 = _mm_add_epi16(temp10, pred_r6_1);\n    /* x7j = z0j - z7j                                                        */\n    temp8 = _mm_sub_epi16(resq_r0_1, resq_r7_1);\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, temp8);\n    temp10 = _mm_unpacklo_epi16(temp8, sign_reg);\n    temp11 = _mm_unpackhi_epi16(temp8, sign_reg);\n    temp10 = _mm_add_epi32(temp10, value_32);\n    temp11 = _mm_add_epi32(temp11, value_32);\n    temp10 = _mm_srai_epi32(temp10, 6);\n    temp11 = _mm_srai_epi32(temp11, 6);\n    temp10 = _mm_packs_epi32(temp10, temp11);\n    temp8 = _mm_add_epi16(temp10, pred_r7_1);\n    /*------------------------------------------------------------------*/\n    //Clipping the results to 8 bits\n    sign_reg = _mm_cmpgt_epi16(temp1, zero_8x16b); // sign check\n    temp1 = _mm_and_si128(temp1, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp2, zero_8x16b); // sign check\n    temp2 = _mm_and_si128(temp2, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp3, zero_8x16b); // sign check\n    temp3 = _mm_and_si128(temp3, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp4, zero_8x16b); // sign check\n    temp4 = _mm_and_si128(temp4, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp5, zero_8x16b); // sign check\n    temp5 = _mm_and_si128(temp5, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp6, zero_8x16b); // sign check\n    temp6 = _mm_and_si128(temp6, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp7, zero_8x16b); // sign check\n    temp7 = _mm_and_si128(temp7, sign_reg);\n    sign_reg = _mm_cmpgt_epi16(temp8, zero_8x16b); // sign check\n    temp8 = _mm_and_si128(temp8, sign_reg);\n\n    resq_r0_2 = _mm_packus_epi16(temp1, zero_8x16b);\n    resq_r1_2 = _mm_packus_epi16(temp2, zero_8x16b);\n    resq_r2_2 = _mm_packus_epi16(temp3, zero_8x16b);\n    resq_r3_2 = _mm_packus_epi16(temp4, zero_8x16b);\n    resq_r4_2 = _mm_packus_epi16(temp5, zero_8x16b);\n    resq_r5_2 = _mm_packus_epi16(temp6, zero_8x16b);\n    resq_r6_2 = _mm_packus_epi16(temp7, zero_8x16b);\n    resq_r7_2 = _mm_packus_epi16(temp8, zero_8x16b);\n\n    _mm_storel_epi64((__m128i *) (&pu1_out[0]), resq_r0_2);\n    _mm_storel_epi64((__m128i *) (&pu1_out[out_strd]), resq_r1_2);\n    _mm_storel_epi64((__m128i *) (&pu1_out[2 * out_strd]), resq_r2_2);\n    _mm_storel_epi64((__m128i *) (&pu1_out[3 * out_strd]), resq_r3_2);\n    _mm_storel_epi64((__m128i *) (&pu1_out[4 * out_strd]), resq_r4_2);\n    _mm_storel_epi64((__m128i *) (&pu1_out[5 * out_strd]), resq_r5_2);\n    _mm_storel_epi64((__m128i *) (&pu1_out[6 * out_strd]), resq_r6_2);\n    _mm_storel_epi64((__m128i *) (&pu1_out[7 * out_strd]), resq_r7_2);\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_luma_intra_pred_filters_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_luma_intra_pred_filters_ssse3.c\n *\n * @brief\n *  Contains function definitions for luma intra prediction filters in x86\n *  intrinsics\n *\n * @author\n *  Ittiam\n *\n * @par List of Functions:\n *  - ih264_intra_pred_luma_4x4_mode_vert_ssse3\n *  - ih264_intra_pred_luma_4x4_mode_horz_ssse3\n *  - ih264_intra_pred_luma_4x4_mode_dc_ssse3\n *  - ih264_intra_pred_luma_4x4_mode_diag_dl_ssse3\n *  - ih264_intra_pred_luma_4x4_mode_diag_dr_ssse3\n *  - ih264_intra_pred_luma_4x4_mode_vert_r_ssse3\n *  - ih264_intra_pred_luma_4x4_mode_horz_d_ssse3\n *  - ih264_intra_pred_luma_4x4_mode_vert_l_ssse3\n *  - ih264_intra_pred_luma_4x4_mode_horz_u_ssse3\n *  - ih264_intra_pred_luma_8x8_mode_vert_ssse3\n *  - ih264_intra_pred_luma_8x8_mode_horz_ssse3\n *  - ih264_intra_pred_luma_8x8_mode_dc_ssse3\n *  - ih264_intra_pred_luma_8x8_mode_diag_dl_ssse3\n *  - ih264_intra_pred_luma_8x8_mode_diag_dr_ssse3\n *  - ih264_intra_pred_luma_8x8_mode_vert_r_ssse3\n *  - ih264_intra_pred_luma_8x8_mode_horz_d_ssse3\n *  - ih264_intra_pred_luma_8x8_mode_vert_l_ssse3\n *  - ih264_intra_pred_luma_8x8_mode_horz_u_ssse3\n *  - ih264_intra_pred_luma_16x16_mode_vert_ssse3\n *  - ih264_intra_pred_luma_16x16_mode_horz_ssse3\n *  - ih264_intra_pred_luma_16x16_mode_dc_ssse3\n *  - ih264_intra_pred_luma_16x16_mode_plane_ssse3\n *\n * @remarks\n *  None\n *\n ******************************************************************************\n */\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n/* System include files */\n#include <stdio.h>\n#include <stddef.h>\n#include <string.h>\n#include <immintrin.h>\n\n/* User include files */\n#include \"ih264_defs.h\"\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_intra_pred_filters.h\"\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n\n\n/*******************    LUMA INTRAPREDICTION    *******************/\n\n/*******************    4x4 Modes    *******************/\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_4x4_mode_vert_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_4x4 mode:vertical\n *\n * @par Description:\n *  Perform Intra prediction for luma_4x4 mode:vertical ,described in sec 8.3.1.2.1\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_4x4_mode_vert_ssse3(UWORD8 *pu1_src,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 src_strd,\n                                               WORD32 dst_strd,\n                                               WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top;\n    WORD32 dst_strd2, dst_strd3;\n    WORD32 i4_top;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_top = pu1_src + BLK_SIZE + 1;\n\n    i4_top = *((WORD32 *)pu1_top);\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd3 = dst_strd + dst_strd2;\n\n    *((WORD32 *)(pu1_dst)) = i4_top;\n    *((WORD32 *)(pu1_dst + dst_strd)) = i4_top;\n    *((WORD32 *)(pu1_dst + dst_strd2)) = i4_top;\n    *((WORD32 *)(pu1_dst + dst_strd3)) = i4_top;\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_4x4_mode_horz_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_4x4 mode:horizontal\n *\n * @par Description:\n *  Perform Intra prediction for luma_4x4 mode:horizontal ,described in sec 8.3.1.2.2\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_4x4_mode_horz_ssse3(UWORD8 *pu1_src,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 src_strd,\n                                               WORD32 dst_strd,\n                                               WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    WORD32 row1,row2,row3,row4;\n    UWORD8 val;\n    WORD32 dst_strd2, dst_strd3;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_left = pu1_src + BLK_SIZE - 1;\n\n    val  = *pu1_left;\n    row1 = val + (val << 8) + (val << 16) + (val << 24);\n    val  = *(pu1_left - 1);\n    row2 = val + (val << 8) + (val << 16) + (val << 24);\n    val  = *(pu1_left - 2);\n    row3 = val + (val << 8) + (val << 16) + (val << 24);\n    val  = *(pu1_left - 3);\n    row4 = val + (val << 8) + (val << 16) + (val << 24);\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd3 = dst_strd + dst_strd2;\n\n    *((WORD32 *)(pu1_dst)) = row1;\n    *((WORD32 *)(pu1_dst + dst_strd)) = row2;\n    *((WORD32 *)(pu1_dst + dst_strd2)) = row3;\n    *((WORD32 *)(pu1_dst + dst_strd3)) = row4;\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_4x4_mode_dc_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_4x4 mode:DC\n *\n * @par Description:\n *  Perform Intra prediction for luma_4x4 mode:DC ,described in sec 8.3.1.2.3\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n *  availability of neighbouring pixels\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_4x4_mode_dc_ssse3(UWORD8 *pu1_src,\n                                             UWORD8 *pu1_dst,\n                                             WORD32 src_strd,\n                                             WORD32 dst_strd,\n                                             WORD32 ngbr_avail)\n{\n    UWORD8 u1_useleft; /* availability of left predictors (only for DC) */\n    UWORD8 u1_usetop; /* availability of top predictors (only for DC) */\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    WORD32 dst_strd2, dst_strd3;\n    WORD32 val = 0;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    u1_useleft = BOOLEAN(ngbr_avail & LEFT_MB_AVAILABLE_MASK);\n    u1_usetop = BOOLEAN(ngbr_avail & TOP_MB_AVAILABLE_MASK);\n    pu1_top = pu1_src + BLK_SIZE + 1;\n    pu1_left = pu1_src + BLK_SIZE - 1;\n\n    if(u1_useleft)\n    {\n        val += *pu1_left--;\n        val += *pu1_left--;\n        val += *pu1_left--;\n        val += *pu1_left + 2;\n    }\n    if(u1_usetop)\n    {\n        val += *pu1_top + *(pu1_top + 1) + *(pu1_top + 2) + *(pu1_top + 3)\n                        + 2;\n    }\n    /* Since 2 is added if either left/top pred is there,\n     val still being zero implies both preds are not there */\n    val = (val) ? (val >> (1 + u1_useleft + u1_usetop)) : 128;\n\n    val = val + (val << 8) + (val << 16) + (val << 24);\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd3 = dst_strd + dst_strd2;\n\n    *((WORD32 *)(pu1_dst)) = val;\n    *((WORD32 *)(pu1_dst + dst_strd)) = val;\n    *((WORD32 *)(pu1_dst + dst_strd2)) = val;\n    *((WORD32 *)(pu1_dst + dst_strd3)) = val;\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_4x4_mode_diag_dl_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_4x4 mode:Diagonal_Down_Left\n *\n * @par Description:\n *  Perform Intra prediction for luma_4x4 mode:Diagonal_Down_Left ,described in sec 8.3.1.2.4\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_4x4_mode_diag_dl_ssse3(UWORD8 *pu1_src,\n                                                  UWORD8 *pu1_dst,\n                                                  WORD32 src_strd,\n                                                  WORD32 dst_strd,\n                                                  WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top;\n    WORD32 dst_strd2, dst_strd3;\n\n    __m128i top_16x8b, top_8x16b, top_sh_8x16b;\n    __m128i res1_8x16b, res2_8x16b, res_16x8b;\n    __m128i zero_vector, const_2_8x16b;\n    WORD32 row1,row2,row3,row4;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_top = pu1_src + BLK_SIZE + 1;\n\n    top_16x8b = _mm_loadl_epi64((__m128i *)pu1_top);\n    zero_vector = _mm_setzero_si128();\n    top_8x16b = _mm_unpacklo_epi8(top_16x8b, zero_vector);    //t0 t1 t2 t3 t4 t5 t6 t7\n\n    top_sh_8x16b = _mm_srli_si128(top_8x16b, 2);              //t1 t2 t3 t4 t5 t6 t7 0\n    const_2_8x16b = _mm_set1_epi16(2);\n\n    top_sh_8x16b = _mm_shufflehi_epi16(top_sh_8x16b, 0xa4);   //t1 t2 t3 t4 t5 t6 t7 t7\n    res1_8x16b = _mm_add_epi16(top_8x16b, top_sh_8x16b);\n    res2_8x16b = _mm_srli_si128(res1_8x16b, 2);\n\n    res1_8x16b = _mm_add_epi16(res1_8x16b, const_2_8x16b);\n    res1_8x16b = _mm_add_epi16(res2_8x16b, res1_8x16b);\n    res1_8x16b = _mm_srai_epi16(res1_8x16b, 2);\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd3 = dst_strd + dst_strd2;\n\n    res_16x8b = _mm_packus_epi16(res1_8x16b, res1_8x16b);\n    row1 = _mm_cvtsi128_si32(res_16x8b);\n    res_16x8b = _mm_srli_si128(res_16x8b, 1);\n    row2 = _mm_cvtsi128_si32(res_16x8b);\n    res_16x8b = _mm_srli_si128(res_16x8b, 1);\n    row3 = _mm_cvtsi128_si32(res_16x8b);\n    res_16x8b = _mm_srli_si128(res_16x8b, 1);\n    row4 = _mm_cvtsi128_si32(res_16x8b);\n\n    *((WORD32 *)(pu1_dst)) = row1;\n    *((WORD32 *)(pu1_dst + dst_strd)) = row2;\n    *((WORD32 *)(pu1_dst + dst_strd2)) = row3;\n    *((WORD32 *)(pu1_dst + dst_strd3)) = row4;\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_4x4_mode_diag_dr_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_4x4 mode:Diagonal_Down_Right\n *\n * @par Description:\n *  Perform Intra prediction for luma_4x4 mode:Diagonal_Down_Right ,described in sec 8.3.1.2.5\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_4x4_mode_diag_dr_ssse3(UWORD8 *pu1_src,\n                                                  UWORD8 *pu1_dst,\n                                                  WORD32 src_strd,\n                                                  WORD32 dst_strd,\n                                                  WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left;\n    WORD32 dst_strd2, dst_strd3;\n\n    __m128i top_left_16x8b, top_left_8x16b;\n    __m128i top_left_sh_16x8b, top_left_sh_8x16b;\n    __m128i res1_8x16b, res2_8x16b;\n    __m128i res1_16x8b, res2_16x8b;\n    __m128i zero_vector, const_2_8x16b;\n    WORD32 row1,row2,row3,row4;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_left = pu1_src + BLK_SIZE - 1;\n\n    top_left_16x8b = _mm_loadu_si128((__m128i *)(pu1_left - 3));             //l3 l2 l1 l0 tl t0 t1 t2...\n    zero_vector = _mm_setzero_si128();\n    top_left_sh_16x8b = _mm_srli_si128(top_left_16x8b, 1);                   //l2 l1 l0 tl t0 t1 t2 t3...\n\n    top_left_8x16b = _mm_unpacklo_epi8(top_left_16x8b, zero_vector);\n    top_left_sh_8x16b = _mm_unpacklo_epi8(top_left_sh_16x8b, zero_vector);\n\n    res1_8x16b = _mm_add_epi16(top_left_8x16b, top_left_sh_8x16b);           //l3+l2 l2+l1 l1+l0 l0+tl tl+t0 t0+t1 t1+t2 t2+t3...\n    const_2_8x16b = _mm_set1_epi16(2);\n    res2_8x16b = _mm_srli_si128(res1_8x16b, 2);                              //l2+l1 l1+l0 l0+tl tl+t0 t0+t1 t1+t2 t2+t3...\n\n    res1_8x16b = _mm_add_epi16(res1_8x16b, const_2_8x16b);\n    res1_8x16b = _mm_add_epi16(res2_8x16b, res1_8x16b);                      //l3+2*l2+l1+2 l2+2*l1+l0+2...\n    res1_8x16b = _mm_srai_epi16(res1_8x16b, 2);\n    res1_16x8b = _mm_packus_epi16(res1_8x16b, res1_8x16b);\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd3 = dst_strd + dst_strd2;\n\n    res2_16x8b = _mm_srli_si128(res1_16x8b, 3);\n\n    row1 = _mm_cvtsi128_si32(res2_16x8b);\n    res2_16x8b = _mm_srli_si128(res1_16x8b, 2);\n    row2 = _mm_cvtsi128_si32(res2_16x8b);\n    res2_16x8b = _mm_srli_si128(res1_16x8b, 1);\n    row3 = _mm_cvtsi128_si32(res2_16x8b);\n    row4 = _mm_cvtsi128_si32(res1_16x8b);\n\n    *((WORD32 *)(pu1_dst)) = row1;\n    *((WORD32 *)(pu1_dst + dst_strd)) = row2;\n    *((WORD32 *)(pu1_dst + dst_strd2)) = row3;\n    *((WORD32 *)(pu1_dst + dst_strd3)) = row4;\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_4x4_mode_vert_r_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_4x4 mode:Vertical_Right\n *\n * @par Description:\n *  Perform Intra prediction for luma_4x4 mode:Vertical_Right ,described in sec 8.3.1.2.6\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_4x4_mode_vert_r_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left;\n    WORD32 dst_strd2, dst_strd3;\n\n    __m128i val_16x8b, temp_16x8b;\n    __m128i w11_a1_16x8b, w11_a2_16x8b;\n    __m128i w121_a1_8x16b, w121_a2_8x16b, w121_sh_8x16b;\n    __m128i row1_16x8b, row2_16x8b, row3_16x8b, row4_16x8b;\n    __m128i zero_vector, const_2_8x16b;\n    WORD32 row1,row2,row3,row4;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_left = pu1_src + BLK_SIZE - 1;\n\n    val_16x8b = _mm_loadl_epi64((__m128i *)(pu1_left - 2));\n    zero_vector = _mm_setzero_si128();\n\n    w121_a1_8x16b = _mm_unpacklo_epi8(val_16x8b, zero_vector);        //l2 l1 l0 tl t0 t1 t2 t3\n    w11_a1_16x8b = _mm_srli_si128(val_16x8b, 3);\n    w121_a2_8x16b = _mm_srli_si128(w121_a1_8x16b, 2);                 //l1 l0 tl t0 t1 t2 t3 0\n    w11_a2_16x8b = _mm_srli_si128(val_16x8b, 4);\n\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, w121_a2_8x16b);      //l2+l1 l1+l0 l0+tl tl+t0 t0+t1 t1+t2 t2+t3 t3\n    row1_16x8b = _mm_avg_epu8(w11_a1_16x8b, w11_a2_16x8b);\n    w121_a2_8x16b = _mm_srli_si128(w121_a1_8x16b, 2);                 //l1+l0 l0+tl tl+t0 t0+t1 t1+t2 t2+t3 t3    0\n\n    const_2_8x16b = _mm_set1_epi16(2);\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, w121_a2_8x16b);      //l2+2*l1+l0 l1+2*l0+tl ...\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, const_2_8x16b);\n    w121_a1_8x16b = _mm_srai_epi16(w121_a1_8x16b, 2);\n\n    w121_sh_8x16b = _mm_shufflelo_epi16(w121_a1_8x16b, 0xe1);\n    w121_sh_8x16b = _mm_srli_si128(w121_sh_8x16b, 2);\n\n    row4_16x8b = _mm_packus_epi16(w121_sh_8x16b, w121_sh_8x16b);\n    temp_16x8b = _mm_slli_si128(w121_a1_8x16b, 13);\n    row2_16x8b = _mm_srli_si128(row4_16x8b, 1);\n    row3_16x8b = _mm_alignr_epi8(row1_16x8b, temp_16x8b, 15);\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd3 = dst_strd + dst_strd2;\n\n    row1 = _mm_cvtsi128_si32(row1_16x8b);\n    row2 = _mm_cvtsi128_si32(row2_16x8b);\n    row3 = _mm_cvtsi128_si32(row3_16x8b);\n    row4 = _mm_cvtsi128_si32(row4_16x8b);\n\n    *((WORD32 *)(pu1_dst)) = row1;\n    *((WORD32 *)(pu1_dst + dst_strd)) = row2;\n    *((WORD32 *)(pu1_dst + dst_strd2)) = row3;\n    *((WORD32 *)(pu1_dst + dst_strd3)) = row4;\n}\n\n/*\n *******************************************************************************\n *\n * ih264_intra_pred_luma_4x4_mode_horz_d_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_4x4 mode:Horizontal_Down\n *\n * @par Description:\n *  Perform Intra prediction for luma_4x4 mode:Horizontal_Down ,described in sec 8.3.1.2.7\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_4x4_mode_horz_d_ssse3(UWORD8 *pu1_src,\n                                           UWORD8 *pu1_dst,\n                                           WORD32 src_strd,\n                                           WORD32 dst_strd,\n                                           WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left;\n    WORD32 dst_strd2, dst_strd3;\n    WORD32 val_121_t0t1;\n\n    __m128i val_16x8b, val_sh_16x8b;\n    __m128i w11_16x8b;\n    __m128i w121_a1_8x16b, w121_a2_8x16b, w121_16x8b;\n    __m128i row1_16x8b, row2_16x8b, row3_16x8b, row4_16x8b;\n\n    __m128i zero_vector, const_2_8x16b;\n    WORD32 row1,row2,row3,row4;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_left = pu1_src + BLK_SIZE - 1;\n\n    val_16x8b = _mm_loadl_epi64((__m128i *)(pu1_left - 3));\n    zero_vector = _mm_setzero_si128();\n    val_sh_16x8b = _mm_srli_si128(val_16x8b, 1);\n    w11_16x8b = _mm_avg_epu8(val_16x8b, val_sh_16x8b);\n\n    w121_a1_8x16b = _mm_unpacklo_epi8(val_16x8b, zero_vector);        //l3 l2 l1 l0 tl t0 t1 t2\n    w121_a2_8x16b = _mm_srli_si128(w121_a1_8x16b, 2);                 //l2 l1 l0 tl t0 t1 t2 0\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, w121_a2_8x16b);      //l3+l2 l2+l1 l1+l0 l0+tl tl+t0 t0+t1 t1+t2 t2\n    w121_a2_8x16b = _mm_srli_si128(w121_a1_8x16b, 2);                 //l2+l1 l1+l0 l0+tl tl+t0 t0+t1 t1+t2 t2    0\n\n    zero_vector = _mm_setzero_si128();\n    const_2_8x16b = _mm_set1_epi16(2);\n\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, w121_a2_8x16b);      //l3+2*l2+l1 l2+2*l1+l0 l1+2*l0+tl ...\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, const_2_8x16b);\n    w121_a1_8x16b = _mm_srai_epi16(w121_a1_8x16b, 2);\n\n    w121_16x8b = _mm_packus_epi16(w121_a1_8x16b, w121_a1_8x16b);\n\n    row4_16x8b = _mm_unpacklo_epi8(w11_16x8b, w121_16x8b);\n    val_121_t0t1 = _mm_extract_epi16(w121_16x8b, 2);\n    row4_16x8b = _mm_insert_epi16(row4_16x8b, val_121_t0t1, 4);\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd3 = dst_strd + dst_strd2;\n\n    row1_16x8b = _mm_srli_si128(row4_16x8b, 6);\n    row2_16x8b = _mm_srli_si128(row4_16x8b, 4);\n    row3_16x8b = _mm_srli_si128(row4_16x8b, 2);\n\n    row1 = _mm_cvtsi128_si32(row1_16x8b);\n    row2 = _mm_cvtsi128_si32(row2_16x8b);\n    row3 = _mm_cvtsi128_si32(row3_16x8b);\n    row4 = _mm_cvtsi128_si32(row4_16x8b);\n\n    *((WORD32 *)(pu1_dst)) = row1;\n    *((WORD32 *)(pu1_dst + dst_strd)) = row2;\n    *((WORD32 *)(pu1_dst + dst_strd2)) = row3;\n    *((WORD32 *)(pu1_dst + dst_strd3)) = row4;\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_4x4_mode_vert_l_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_4x4 mode:Vertical_Left\n *\n * @par Description:\n *  Perform Intra prediction for luma_4x4 mode:Vertical_Left ,described in sec 8.3.1.2.8\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_4x4_mode_vert_l_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top;\n    WORD32 dst_strd2, dst_strd3;\n\n    __m128i val_16x8b, val_sh_16x8b;\n    __m128i w121_a1_8x16b, w121_a2_8x16b;\n    __m128i row1_16x8b, row2_16x8b, row3_16x8b, row4_16x8b;\n\n    __m128i zero_vector, const_2_8x16b;\n    WORD32 row1,row2,row3,row4;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_top = pu1_src +BLK_SIZE + 1;\n\n    val_16x8b = _mm_loadl_epi64((__m128i *)pu1_top);\n    zero_vector = _mm_setzero_si128();\n    val_sh_16x8b = _mm_srli_si128(val_16x8b, 1);\n    row1_16x8b = _mm_avg_epu8(val_16x8b, val_sh_16x8b);\n\n    w121_a1_8x16b = _mm_unpacklo_epi8(val_16x8b, zero_vector);        //t0 t1 t2 t3 t4 t5...\n    w121_a2_8x16b = _mm_srli_si128(w121_a1_8x16b, 2);                 //t1 t2 t3 t4 t5 t6...\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, w121_a2_8x16b);      //t0+t1 t1+t2 t2+t3 t3+t4 t4+t5...\n    w121_a2_8x16b = _mm_srli_si128(w121_a1_8x16b, 2);                 //t1+t2 t2+t3 t3+t4 t4+t5 t5+t6...\n\n    zero_vector = _mm_setzero_si128();\n    const_2_8x16b = _mm_set1_epi16(2);\n\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, w121_a2_8x16b);      //t0+2*t1+t2 t1+2*t2+t3 t2+2*t3+t4...\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, const_2_8x16b);\n    w121_a1_8x16b = _mm_srai_epi16(w121_a1_8x16b, 2);\n\n    row2_16x8b = _mm_packus_epi16(w121_a1_8x16b, w121_a1_8x16b);\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd3 = dst_strd + dst_strd2;\n\n    row3_16x8b = _mm_srli_si128(row1_16x8b, 1);\n    row4_16x8b = _mm_srli_si128(row2_16x8b, 1);\n\n    row1 = _mm_cvtsi128_si32(row1_16x8b);\n    row2 = _mm_cvtsi128_si32(row2_16x8b);\n    row3 = _mm_cvtsi128_si32(row3_16x8b);\n    row4 = _mm_cvtsi128_si32(row4_16x8b);\n\n    *((WORD32 *)(pu1_dst)) = row1;\n    *((WORD32 *)(pu1_dst + dst_strd)) = row2;\n    *((WORD32 *)(pu1_dst + dst_strd2)) = row3;\n    *((WORD32 *)(pu1_dst + dst_strd3)) = row4;\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_4x4_mode_horz_u_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_4x4 mode:Horizontal_Up\n *\n * @par Description:\n *  Perform Intra prediction for luma_4x4 mode:Horizontal_Up ,described in sec 8.3.1.2.9\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_4x4_mode_horz_u_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left;\n    WORD32 dst_strd2, dst_strd3;\n\n    __m128i val_16x8b, val_sh_16x8b;\n    __m128i w11_16x8b;\n    __m128i w121_a1_8x16b, w121_a2_8x16b, w121_16x8b;\n    __m128i row1_16x8b, row2_16x8b, row3_16x8b, row4_16x8b;\n\n    __m128i zero_vector, const_2_8x16b, rev_16x8b;\n    WORD32 row1,row2,row3,row4;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_left = pu1_src + BLK_SIZE - 1;\n\n    zero_vector = _mm_setzero_si128();\n    rev_16x8b = _mm_setr_epi8(3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n\n    val_16x8b = _mm_loadl_epi64((__m128i *)(pu1_left - 3));           //l3 l2 l1 l0 0  0  0...\n    val_16x8b = _mm_shuffle_epi8(val_16x8b, rev_16x8b);                //l0 l1 l2 l3 l3 l3 l3...\n\n    val_sh_16x8b = _mm_srli_si128(val_16x8b, 1);\n    w11_16x8b = _mm_avg_epu8(val_16x8b, val_sh_16x8b);\n\n    w121_a1_8x16b = _mm_unpacklo_epi8(val_16x8b, zero_vector);        //l0 l1 l2 l3 l3 l3...\n    w121_a2_8x16b = _mm_srli_si128(w121_a1_8x16b, 2);                 //l1 l2 l3 l3 l3 l3...\n\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, w121_a2_8x16b);      //l0+t1 l1+l2 l2+l3 2*l3 2*l3...\n    w121_a2_8x16b = _mm_srli_si128(w121_a1_8x16b, 2);                 //l1+t2 l2+l3 2*l3  2*l3 2*l3...\n\n    zero_vector = _mm_setzero_si128();\n    const_2_8x16b = _mm_set1_epi16(2);\n\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, w121_a2_8x16b);      //l0+2*l1+l2 l1+2*l2+l3 l2+3*l3 4*l3 4*l3...\n    w121_a1_8x16b = _mm_add_epi16(w121_a1_8x16b, const_2_8x16b);\n    w121_a1_8x16b = _mm_srai_epi16(w121_a1_8x16b, 2);\n\n    w121_16x8b = _mm_packus_epi16(w121_a1_8x16b, w121_a1_8x16b);\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd3 = dst_strd + dst_strd2;\n\n    row1_16x8b = _mm_unpacklo_epi8(w11_16x8b, w121_16x8b);\n    row2_16x8b = _mm_srli_si128(row1_16x8b, 2);\n    row3_16x8b = _mm_srli_si128(row1_16x8b, 4);\n    row4_16x8b = _mm_srli_si128(row1_16x8b, 6);\n\n    row1 = _mm_cvtsi128_si32(row1_16x8b);\n    row2 = _mm_cvtsi128_si32(row2_16x8b);\n    row3 = _mm_cvtsi128_si32(row3_16x8b);\n    row4 = _mm_cvtsi128_si32(row4_16x8b);\n\n    *((WORD32 *)(pu1_dst)) = row1;\n    *((WORD32 *)(pu1_dst + dst_strd)) = row2;\n    *((WORD32 *)(pu1_dst + dst_strd2)) = row3;\n    *((WORD32 *)(pu1_dst + dst_strd3)) = row4;\n}\n\n/*******************    8x8 Modes    *******************/\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_8x8_mode_vert_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_8x8 mode:vertical\n *\n * @par Description:\n *  Perform Intra prediction for luma_8x8 mode:vertical ,described in sec 8.3.2.2.2\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_8x8_mode_vert_ssse3(UWORD8 *pu1_src,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 src_strd,\n                                               WORD32 dst_strd,\n                                               WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL;\n    __m128i top_8x8b;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n\n    top_8x8b = _mm_loadl_epi64((__m128i *)pu1_top);\n\n    _mm_storel_epi64((__m128i *)(pu1_dst + 0 * dst_strd), top_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 1 * dst_strd), top_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 2 * dst_strd), top_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 3 * dst_strd), top_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 4 * dst_strd), top_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 5 * dst_strd), top_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 6 * dst_strd), top_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 7 * dst_strd), top_8x8b);\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_8x8_mode_horz_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_8x8 mode:horizontal\n *\n * @par Description:\n *  Perform Intra prediction for  uma_8x8 mode:horizontal ,described in sec 8.3.2.2.2\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_8x8_mode_horz_ssse3(UWORD8 *pu1_src,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 src_strd,\n                                               WORD32 dst_strd,\n                                               WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = pu1_src + BLK8x8SIZE - 1;\n    __m128i row1_8x8b, row2_8x8b, row3_8x8b, row4_8x8b;\n    __m128i row5_8x8b, row6_8x8b, row7_8x8b, row8_8x8b;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    row1_8x8b = _mm_set1_epi8(pu1_left[0]);\n    row2_8x8b = _mm_set1_epi8(pu1_left[-1]);\n    row3_8x8b = _mm_set1_epi8(pu1_left[-2]);\n    row4_8x8b = _mm_set1_epi8(pu1_left[-3]);\n    row5_8x8b = _mm_set1_epi8(pu1_left[-4]);\n    row6_8x8b = _mm_set1_epi8(pu1_left[-5]);\n    row7_8x8b = _mm_set1_epi8(pu1_left[-6]);\n    row8_8x8b = _mm_set1_epi8(pu1_left[-7]);\n\n    _mm_storel_epi64((__m128i *)(pu1_dst + 0 * dst_strd), row1_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 1 * dst_strd), row2_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 2 * dst_strd), row3_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 3 * dst_strd), row4_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 4 * dst_strd), row5_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 5 * dst_strd), row6_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 6 * dst_strd), row7_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 7 * dst_strd), row8_8x8b);\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_8x8_mode_dc_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_8x8 mode:DC\n *\n * @par Description:\n *  Perform Intra prediction for luma_8x8 mode:DC ,described in sec 8.3.2.2.4\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n *  availability of neighbouring pixels\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_8x8_mode_dc_ssse3(UWORD8 *pu1_src,\n                                             UWORD8 *pu1_dst,\n                                             WORD32 src_strd,\n                                             WORD32 dst_strd,\n                                             WORD32 ngbr_avail)\n{\n    UWORD8 u1_useleft; /* availability of left predictors (only for DC) */\n    UWORD8 u1_usetop; /* availability of top predictors (only for DC) */\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    __m128i dc_val_8x8b;\n    WORD32 dc_val = 0;\n    UNUSED(src_strd);\n\n    u1_useleft = BOOLEAN(ngbr_avail & LEFT_MB_AVAILABLE_MASK);\n    u1_usetop = BOOLEAN(ngbr_avail & TOP_MB_AVAILABLE_MASK);\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n\n    if(u1_useleft || u1_usetop)\n    {\n        WORD32 shft = 2;\n        __m128i val_8x8b, zero_8x8b, sum_8x16b;\n\n        zero_8x8b = _mm_setzero_si128();\n\n        if(u1_useleft)\n        {\n            val_8x8b = _mm_loadl_epi64((__m128i *)(pu1_left - 7));\n            sum_8x16b = _mm_sad_epu8(zero_8x8b, val_8x8b);\n\n            shft++;\n            dc_val += 4;\n            dc_val += _mm_extract_epi16(sum_8x16b, 0);\n        }\n        if(u1_usetop)\n        {\n            val_8x8b = _mm_loadl_epi64((__m128i *)pu1_top);\n            sum_8x16b = _mm_sad_epu8(zero_8x8b, val_8x8b);\n\n            shft++;\n            dc_val += 4;\n            dc_val += _mm_extract_epi16(sum_8x16b, 0);\n        }\n        dc_val = dc_val >> shft;\n    }\n    else\n        dc_val = 128;\n\n    dc_val_8x8b = _mm_set1_epi8(dc_val);\n\n    _mm_storel_epi64((__m128i *)(pu1_dst + 0 * dst_strd), dc_val_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 1 * dst_strd), dc_val_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 2 * dst_strd), dc_val_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 3 * dst_strd), dc_val_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 4 * dst_strd), dc_val_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 5 * dst_strd), dc_val_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 6 * dst_strd), dc_val_8x8b);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 7 * dst_strd), dc_val_8x8b);\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_8x8_mode_diag_dl_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_8x8 mode:Diagonal_Down_Left\n *\n * @par Description:\n *  Perform Intra prediction for luma_8x8 mode:Diagonal_Down_Left ,described in sec 8.3.2.2.5\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_8x8_mode_diag_dl_ssse3(UWORD8 *pu1_src,\n                                                  UWORD8 *pu1_dst,\n                                                  WORD32 src_strd,\n                                                  WORD32 dst_strd,\n                                                  WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    __m128i top_16x8;\n    __m128i out_15x16;\n    __m128i a0_8x16, a1_8x16, a2_8x16;\n    __m128i temp1, temp2;\n    __m128i res1_8x16, res2_8x16;\n    __m128i zero = _mm_setzero_si128();\n    __m128i const_val2_8x16 = _mm_set1_epi16(2);\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n\n    top_16x8 = _mm_loadu_si128((__m128i *)(pu1_top));\n\n    temp1 = _mm_srli_si128(top_16x8, 1);\n    temp2 = _mm_srli_si128(top_16x8, 2);\n    a0_8x16 = _mm_unpacklo_epi8(top_16x8, zero);\n    a1_8x16 = _mm_unpacklo_epi8(temp1, zero);\n    a2_8x16 = _mm_unpacklo_epi8(temp2, zero);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res1_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    temp2 = _mm_srli_si128(top_16x8, 2);\n    temp1 = _mm_srli_si128(top_16x8, 1);\n    a2_8x16 = _mm_unpackhi_epi8(temp2, zero);\n    a0_8x16 = _mm_unpackhi_epi8(top_16x8, zero);\n    a2_8x16 = _mm_shufflehi_epi16(a2_8x16, 0x14);\n    a1_8x16 = _mm_unpackhi_epi8(temp1, zero);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res2_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    out_15x16 = _mm_packus_epi16(res1_8x16, res2_8x16);\n\n    _mm_storel_epi64((__m128i *)(pu1_dst + 0 * dst_strd), out_15x16);\n    out_15x16 = _mm_srli_si128(out_15x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 1 * dst_strd), out_15x16);\n    out_15x16 = _mm_srli_si128(out_15x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 2 * dst_strd), out_15x16);\n    out_15x16 = _mm_srli_si128(out_15x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 3 * dst_strd), out_15x16);\n    out_15x16 = _mm_srli_si128(out_15x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 4 * dst_strd), out_15x16);\n    out_15x16 = _mm_srli_si128(out_15x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 5 * dst_strd), out_15x16);\n    out_15x16 = _mm_srli_si128(out_15x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 6 * dst_strd), out_15x16);\n    out_15x16 = _mm_srli_si128(out_15x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 7 * dst_strd), out_15x16);\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_8x8_mode_diag_dr_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_8x8 mode:Diagonal_Down_Right\n *\n * @par Description:\n *  Perform Intra prediction for luma_8x8 mode:Diagonal_Down_Right ,described in sec 8.3.2.2.6\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_8x8_mode_diag_dr_ssse3(UWORD8 *pu1_src,\n                                                  UWORD8 *pu1_dst,\n                                                  WORD32 src_strd,\n                                                  WORD32 dst_strd,\n                                                  WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    __m128i top_8x8, left_16x8;\n    __m128i out_15x16;\n    __m128i a0_8x16, a1_8x16, a2_8x16;\n    __m128i temp1, temp2;\n    __m128i res1_8x16, res2_8x16;\n    __m128i zero = _mm_setzero_si128();\n    __m128i const_val2_8x16 = _mm_set1_epi16(2);\n    __m128i str_8x8;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n\n    left_16x8 = _mm_loadu_si128((__m128i *)(pu1_left - 7));\n\n    temp1 = _mm_srli_si128(left_16x8, 1);\n    temp2 = _mm_srli_si128(left_16x8, 2);\n    a0_8x16 = _mm_unpacklo_epi8(left_16x8, zero);\n    a1_8x16 = _mm_unpacklo_epi8(temp1, zero);\n    a2_8x16 = _mm_unpacklo_epi8(temp2, zero);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res1_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    top_8x8 = _mm_loadu_si128((__m128i *)(pu1_top - 1));\n\n    temp1 = _mm_srli_si128(top_8x8, 1);\n    temp2 = _mm_srli_si128(top_8x8, 2);\n    a0_8x16 = _mm_unpacklo_epi8(top_8x8, zero);\n    a1_8x16 = _mm_unpacklo_epi8(temp1, zero);\n    a2_8x16 = _mm_unpacklo_epi8(temp2, zero);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res2_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    out_15x16 = _mm_packus_epi16(res1_8x16, res2_8x16);\n\n    str_8x8 = _mm_srli_si128(out_15x16, 7);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 0 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out_15x16, 6);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 1 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out_15x16, 5);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 2 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out_15x16, 4);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 3 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out_15x16, 3);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 4 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out_15x16, 2);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 5 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out_15x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 6 * dst_strd), str_8x8);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 7 * dst_strd), out_15x16);\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_8x8_mode_vert_r_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_8x8 mode:Vertical_Right\n *\n * @par Description:\n *  Perform Intra prediction for luma_8x8 mode:Vertical_Right ,described in sec 8.3.2.2.7\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_8x8_mode_vert_r_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    __m128i top_8x8, left_16x8;\n    __m128i out1_16x16, out2_16x16;\n    __m128i a0_8x16, a1_8x16, a2_8x16;\n    __m128i temp1, temp2;\n    __m128i res1_8x16, res2_8x16, res3_8x16;\n    __m128i zero = _mm_setzero_si128();\n    __m128i const_val2_8x16 = _mm_set1_epi16(2);\n    __m128i str_8x8;\n    __m128i mask = _mm_set1_epi32(0xFFFF);\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n\n    left_16x8 = _mm_loadu_si128((__m128i *)(pu1_left - 6));\n\n    temp1 = _mm_srli_si128(left_16x8, 1);\n    temp2 = _mm_srli_si128(left_16x8, 2);\n    a0_8x16 = _mm_unpacklo_epi8(left_16x8, zero);\n    a1_8x16 = _mm_unpacklo_epi8(temp1, zero);\n    a2_8x16 = _mm_unpacklo_epi8(temp2, zero);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res1_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    top_8x8 = _mm_loadu_si128((__m128i *)(pu1_top - 1));\n\n    temp1 = _mm_srli_si128(top_8x8, 1);\n    temp2 = _mm_srli_si128(top_8x8, 2);\n    a0_8x16 = _mm_unpacklo_epi8(top_8x8, zero);\n    a1_8x16 = _mm_unpacklo_epi8(temp1, zero);\n    a2_8x16 = _mm_unpacklo_epi8(temp2, zero);\n\n    res3_8x16 = _mm_avg_epu16(a0_8x16, a1_8x16);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res2_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    str_8x8 = _mm_packus_epi16(res3_8x16, zero);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 0 * dst_strd), str_8x8);\n\n    temp1 = _mm_and_si128(res1_8x16, mask);\n    temp1 = _mm_packs_epi32(temp1, temp1);\n    out1_16x16 = _mm_packus_epi16(temp1, res2_8x16);\n\n    res1_8x16 = _mm_slli_si128(res1_8x16, 2);\n    temp1 = _mm_and_si128(res1_8x16, mask);\n    temp1 = _mm_packs_epi32(temp1, temp1);\n    out2_16x16 = _mm_packus_epi16(temp1, res3_8x16);\n\n    str_8x8 = _mm_srli_si128(out1_16x16, 7);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 1 * dst_strd), str_8x8);\n\n    str_8x8 = _mm_srli_si128(out2_16x16, 7);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 2 * dst_strd), str_8x8);\n\n    str_8x8 = _mm_srli_si128(out1_16x16, 6);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 3 * dst_strd), str_8x8);\n\n    str_8x8 = _mm_srli_si128(out2_16x16, 6);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 4 * dst_strd), str_8x8);\n\n    str_8x8 = _mm_srli_si128(out1_16x16, 5);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 5 * dst_strd), str_8x8);\n\n    str_8x8 = _mm_srli_si128(out2_16x16, 5);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 6 * dst_strd), str_8x8);\n\n    str_8x8 = _mm_srli_si128(out1_16x16, 4);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 7 * dst_strd), str_8x8);\n}\n\n/*\n *******************************************************************************\n *\n * ih264_intra_pred_luma_8x8_mode_horz_d_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_8x8 mode:Horizontal_Down\n *\n * @par Description:\n *  Perform Intra prediction for luma_8x8 mode:Horizontal_Down ,described in sec 8.3.2.2.8\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_8x8_mode_horz_d_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    __m128i pels_16x16;\n    __m128i temp1, temp2, temp3, temp4;\n    __m128i a0_8x16, a1_8x16, a2_8x16;\n    __m128i zero = _mm_setzero_si128();\n    __m128i const_val2_8x16 = _mm_set1_epi16(2);\n    __m128i res1_8x16, res2_8x16;\n    __m128i out1_16x16, out2_16x16;\n    __m128i str_8x8;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n\n    pels_16x16 = _mm_loadu_si128((__m128i *)(pu1_left - 7));\n\n    temp1 = _mm_srli_si128(pels_16x16, 1);\n    temp2 = _mm_srli_si128(pels_16x16, 2);\n    a0_8x16 = _mm_unpacklo_epi8(pels_16x16, zero);\n    a1_8x16 = _mm_unpacklo_epi8(temp1, zero);\n    a2_8x16 = _mm_unpacklo_epi8(temp2, zero);\n\n    res1_8x16 = _mm_avg_epu16(a0_8x16, a1_8x16);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res2_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    temp3 = _mm_unpacklo_epi16(res1_8x16, res2_8x16);\n    temp4 = _mm_unpackhi_epi16(res1_8x16, res2_8x16);\n    out2_16x16 = _mm_packus_epi16(temp3, temp4);\n\n    a0_8x16 = _mm_unpackhi_epi8(pels_16x16, zero);\n    a1_8x16 = _mm_unpackhi_epi8(temp1, zero);\n    a2_8x16 = _mm_unpackhi_epi8(temp2, zero);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res2_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    out1_16x16 = _mm_packus_epi16(res2_8x16, zero);\n    temp1 = _mm_srli_si128(out2_16x16, 8);\n    out1_16x16 = _mm_unpacklo_epi64(temp1, out1_16x16);\n\n    str_8x8 = _mm_srli_si128(out1_16x16, 6);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 0 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out1_16x16, 4);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 1 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out1_16x16, 2);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 2 * dst_strd), str_8x8);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 3 * dst_strd), out1_16x16);\n\n    str_8x8 = _mm_srli_si128(out2_16x16, 6);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 4 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out2_16x16, 4);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 5 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out2_16x16, 2);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 6 * dst_strd), str_8x8);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 7 * dst_strd), out2_16x16);\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_8x8_mode_vert_l_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_8x8 mode:Vertical_Left\n *\n * @par Description:\n *  Perform Intra prediction for luma_8x8 mode:Vertical_Left ,described in sec 8.3.2.2.9\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\n\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_8x8_mode_vert_l_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top = NULL; /* Pointer to start of top predictors */\n    __m128i top_16x16;\n    __m128i temp1, temp2;\n    __m128i a0_8x16, a1_8x16, a2_8x16;\n    __m128i zero = _mm_setzero_si128();\n    __m128i const_val2_8x16 = _mm_set1_epi16(2);\n    __m128i res1_8x16, res2_8x16, res3_8x16, res4_8x16;\n    __m128i out1_16x16, out2_16x16;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n    pu1_top = pu1_src + BLK8x8SIZE + 1;\n\n    top_16x16 = _mm_loadu_si128((__m128i *)(pu1_top));\n    temp1 = _mm_srli_si128(top_16x16, 1);\n    temp2 = _mm_srli_si128(top_16x16, 2);\n    a0_8x16 = _mm_unpacklo_epi8(top_16x16, zero);\n    a1_8x16 = _mm_unpacklo_epi8(temp1, zero);\n    a2_8x16 = _mm_unpacklo_epi8(temp2, zero);\n\n    res1_8x16 = _mm_avg_epu16(a0_8x16, a1_8x16);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res2_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    a0_8x16 = _mm_unpackhi_epi8(top_16x16, zero);\n    a1_8x16 = _mm_unpackhi_epi8(temp1, zero);\n    a2_8x16 = _mm_unpackhi_epi8(temp2, zero);\n\n    res3_8x16 = _mm_avg_epu16(a0_8x16, a1_8x16);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res4_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    out1_16x16 = _mm_packus_epi16(res1_8x16, res3_8x16);\n    out2_16x16 = _mm_packus_epi16(res2_8x16, res4_8x16);\n\n    _mm_storel_epi64((__m128i *)(pu1_dst + 0 * dst_strd), out1_16x16);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 1 * dst_strd), out2_16x16);\n    out1_16x16 = _mm_srli_si128(out1_16x16, 1);\n    out2_16x16 = _mm_srli_si128(out2_16x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 2 * dst_strd), out1_16x16);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 3 * dst_strd), out2_16x16);\n    out1_16x16 = _mm_srli_si128(out1_16x16, 1);\n    out2_16x16 = _mm_srli_si128(out2_16x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 4 * dst_strd), out1_16x16);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 5 * dst_strd), out2_16x16);\n    out1_16x16 = _mm_srli_si128(out1_16x16, 1);\n    out2_16x16 = _mm_srli_si128(out2_16x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 6 * dst_strd), out1_16x16);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 7 * dst_strd), out2_16x16);\n}\n\n/**\n *******************************************************************************\n *\n * ih264_intra_pred_luma_8x8_mode_horz_u_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_8x8 mode:Horizontal_Up\n *\n * @par Description:\n *  Perform Intra prediction for luma_8x8 mode:Horizontal_Up ,described in sec 8.3.2.2.10\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_8x8_mode_horz_u_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left = NULL; /* Pointer to start of left predictors */\n    __m128i left_16x16;\n    __m128i temp1, temp2;\n    __m128i a0_8x16, a1_8x16, a2_8x16;\n    __m128i zero = _mm_setzero_si128();\n    __m128i const_val2_8x16 = _mm_set1_epi16(2);\n    __m128i res1_8x16, res2_8x16;\n    __m128i out1_16x16;\n    __m128i str_8x8;\n    __m128i shuffle_16x16;\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_left = pu1_src + BLK8x8SIZE - 1;\n    shuffle_16x16 = _mm_set_epi8(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n                                 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,\n                                 0x0F);\n\n    left_16x16 = _mm_loadu_si128((__m128i *)(pu1_left - 7));\n    temp1 = _mm_srli_si128(left_16x16, 1);\n    a0_8x16 = _mm_unpacklo_epi8(left_16x16, zero);\n    a0_8x16 = _mm_slli_si128(a0_8x16, 2);\n    a1_8x16 = _mm_unpacklo_epi8(left_16x16, zero);\n    a0_8x16 = _mm_shufflelo_epi16(a0_8x16, 0xE5);\n    a2_8x16 = _mm_unpacklo_epi8(temp1, zero);\n\n    res1_8x16 = _mm_avg_epu16(a0_8x16, a1_8x16);\n\n    a0_8x16 = _mm_add_epi16(a0_8x16, a2_8x16);\n    a1_8x16 = _mm_add_epi16(a1_8x16, a1_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, const_val2_8x16);\n    a0_8x16 = _mm_add_epi16(a0_8x16, a1_8x16);\n    res2_8x16 = _mm_srai_epi16(a0_8x16, 2);\n\n    temp1 = _mm_unpacklo_epi16(res1_8x16, res2_8x16);\n    temp2 = _mm_unpackhi_epi16(res1_8x16, res2_8x16);\n    out1_16x16 = _mm_packus_epi16(temp1, temp2);\n    out1_16x16 = _mm_shuffle_epi8(out1_16x16, shuffle_16x16);\n\n    str_8x8 = _mm_srli_si128(out1_16x16, 1);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 0 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out1_16x16, 3);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 1 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out1_16x16, 5);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 2 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(out1_16x16, 7);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 3 * dst_strd), str_8x8);\n    temp1 = _mm_set1_epi8(pu1_left[-7]);\n    str_8x8 = _mm_unpacklo_epi64(str_8x8, temp1);\n    str_8x8 = _mm_srli_si128(str_8x8, 2);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 4 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(str_8x8, 2);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 5 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(str_8x8, 2);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 6 * dst_strd), str_8x8);\n    str_8x8 = _mm_srli_si128(str_8x8, 2);\n    _mm_storel_epi64((__m128i *)(pu1_dst + 7 * dst_strd), str_8x8);\n\n}\n\n\n/*******************    16x16 Modes    *******************/\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_16x16_mode_vert_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_16x16 mode:Vertical\n *\n * @par Description:\n *  Perform Intra prediction for luma_16x16 mode:Vertical, described in sec 8.3.3.1\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n *  availability of neighbouring pixels (Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_16x16_mode_vert_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_top;\n    WORD32 dst_strd2, dst_strd3, dst_strd4;\n\n    __m128i top_16x8b;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_top = pu1_src + MB_SIZE + 1;\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd4 = dst_strd << 2;\n\n    top_16x8b = _mm_loadu_si128((__m128i *)pu1_top);\n\n    dst_strd3 = dst_strd + dst_strd2;\n\n    _mm_storeu_si128((__m128i *)pu1_dst, top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), top_16x8b);\n    pu1_dst += dst_strd4;\n\n    _mm_storeu_si128((__m128i *)pu1_dst, top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), top_16x8b);\n    pu1_dst += dst_strd4;\n\n    _mm_storeu_si128((__m128i *)pu1_dst, top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), top_16x8b);\n    pu1_dst += dst_strd4;\n\n    _mm_storeu_si128((__m128i *)pu1_dst, top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), top_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), top_16x8b);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_16x16_mode_horz_ssse3\n *\n * @brief\n *  Perform Intra prediction for luma_16x16 mode:Horizontal\n *\n * @par Description:\n *  Perform Intra prediction for luma_16x16 mode:Horizontal, described in sec 8.3.3.2\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_16x16_mode_horz_ssse3(UWORD8 *pu1_src,\n                                                 UWORD8 *pu1_dst,\n                                                 WORD32 src_strd,\n                                                 WORD32 dst_strd,\n                                                 WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left;\n    WORD32 dst_strd2, dst_strd3, dst_strd4;\n\n    __m128i row1_16x8b, row2_16x8b, row3_16x8b, row4_16x8b;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_left = pu1_src + MB_SIZE - 1;\n\n    dst_strd4 = dst_strd << 2;\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd3 = dst_strd4 - dst_strd;\n\n    row1_16x8b = _mm_set1_epi8(*(pu1_left));\n    row2_16x8b = _mm_set1_epi8(*(pu1_left - 1));\n    row3_16x8b = _mm_set1_epi8(*(pu1_left - 2));\n    row4_16x8b = _mm_set1_epi8(*(pu1_left - 3));\n\n    _mm_storeu_si128((__m128i *)pu1_dst, row1_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), row2_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), row3_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), row4_16x8b);\n\n    pu1_dst += dst_strd4;\n    row1_16x8b = _mm_set1_epi8(*(pu1_left - 4));\n    row2_16x8b = _mm_set1_epi8(*(pu1_left - 5));\n    row3_16x8b = _mm_set1_epi8(*(pu1_left - 6));\n    row4_16x8b = _mm_set1_epi8(*(pu1_left - 7));\n\n    _mm_storeu_si128((__m128i *)pu1_dst, row1_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), row2_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), row3_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), row4_16x8b);\n\n    pu1_dst += dst_strd4;\n    row1_16x8b = _mm_set1_epi8(*(pu1_left - 8));\n    row2_16x8b = _mm_set1_epi8(*(pu1_left - 9));\n    row3_16x8b = _mm_set1_epi8(*(pu1_left - 10));\n    row4_16x8b = _mm_set1_epi8(*(pu1_left - 11));\n\n    _mm_storeu_si128((__m128i *)pu1_dst, row1_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), row2_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), row3_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), row4_16x8b);\n\n    pu1_dst += dst_strd4;\n    row1_16x8b = _mm_set1_epi8(*(pu1_left - 12));\n    row2_16x8b = _mm_set1_epi8(*(pu1_left - 13));\n    row3_16x8b = _mm_set1_epi8(*(pu1_left - 14));\n    row4_16x8b = _mm_set1_epi8(*(pu1_left - 15));\n\n    _mm_storeu_si128((__m128i *)pu1_dst, row1_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), row2_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), row3_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), row4_16x8b);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_16x16_mode_dc_ssse3\n *\n * @brief\n *  Perform Intra prediction for  luma_16x16 mode:DC\n *\n * @par Description:\n *  Perform Intra prediction for  luma_16x16 mode:DC, described in sec 8.3.3.3\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n ** @param[in] ngbr_avail\n *  availability of neighbouring pixels\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_16x16_mode_dc_ssse3(UWORD8 *pu1_src,\n                                               UWORD8 *pu1_dst,\n                                               WORD32 src_strd,\n                                               WORD32 dst_strd,\n                                               WORD32 ngbr_avail)\n{\n    WORD8 u1_useleft, u1_usetop;\n    WORD32 dc_val;\n\n    WORD32 dst_strd2, dst_strd3, dst_strd4;\n\n    __m128i dc_val_16x8b;\n\n    UNUSED(src_strd);\n\n    u1_useleft = BOOLEAN(ngbr_avail & LEFT_MB_AVAILABLE_MASK);\n    u1_usetop = BOOLEAN(ngbr_avail & TOP_MB_AVAILABLE_MASK);\n\n    if(u1_useleft || u1_usetop)\n    {\n        WORD32 shft;\n        __m128i val_16x8b, zero_16x8b, sum_8x16b;\n\n        dc_val = 0;\n        shft = 3;\n\n        zero_16x8b = _mm_setzero_si128();\n\n        if(u1_useleft)\n        {\n            UWORD8 *pu1_left;\n\n            pu1_left = pu1_src + MB_SIZE - 1;\n\n            val_16x8b = _mm_loadu_si128((__m128i *)(pu1_left - 15));\n            sum_8x16b = _mm_sad_epu8(zero_16x8b, val_16x8b);\n\n            shft++;\n            dc_val += 8;\n            dc_val += _mm_extract_epi16(sum_8x16b, 0);\n            dc_val += _mm_extract_epi16(sum_8x16b, 4);\n        }\n        if(u1_usetop)\n        {\n            UWORD8 *pu1_top;\n\n            pu1_top = pu1_src + MB_SIZE + 1;\n\n            val_16x8b = _mm_loadu_si128((__m128i *)pu1_top);\n            sum_8x16b = _mm_sad_epu8(zero_16x8b, val_16x8b);\n\n            shft++;\n            dc_val += 8;\n            dc_val += _mm_extract_epi16(sum_8x16b, 0);\n            dc_val += _mm_extract_epi16(sum_8x16b, 4);\n        }\n        dc_val = dc_val >> shft;\n    }\n    else\n        dc_val = 128;\n\n    dc_val_16x8b =  _mm_set1_epi8(dc_val);\n\n    dst_strd2 = dst_strd << 1;\n    dst_strd4 = dst_strd << 2;\n    dst_strd3 = dst_strd + dst_strd2;\n\n    _mm_storeu_si128((__m128i *)pu1_dst, dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), dc_val_16x8b);\n    pu1_dst += dst_strd4;\n\n    _mm_storeu_si128((__m128i *)pu1_dst, dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), dc_val_16x8b);\n    pu1_dst += dst_strd4;\n\n    _mm_storeu_si128((__m128i *)pu1_dst, dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), dc_val_16x8b);\n    pu1_dst += dst_strd4;\n\n    _mm_storeu_si128((__m128i *)pu1_dst, dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd2), dc_val_16x8b);\n    _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd3), dc_val_16x8b);\n}\n\n/**\n *******************************************************************************\n *\n *ih264_intra_pred_luma_16x16_mode_plane_ssse3\n *\n * @brief\n *  Perform Intra prediction for  luma_16x16 mode:PLANE\n *\n * @par Description:\n *  Perform Intra prediction for  luma_16x16 mode:PLANE, described in sec 8.3.3.4\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[out] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] src_strd\n *  integer source stride\n *\n * @param[in] dst_strd\n *  integer destination stride\n *\n * @param[in] ngbr_avail\n * availability of neighbouring pixels(Not used in this function)\n *\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************/\nATTRIBUTE_SSSE3\nvoid ih264_intra_pred_luma_16x16_mode_plane_ssse3(UWORD8 *pu1_src,\n                                                  UWORD8 *pu1_dst,\n                                                  WORD32 src_strd,\n                                                  WORD32 dst_strd,\n                                                  WORD32 ngbr_avail)\n{\n    UWORD8 *pu1_left, *pu1_top;\n    WORD32 a, b, c;\n\n    __m128i rev_8x16b, mul_8x16b, zero_16x8b;\n\n    UNUSED(src_strd);\n    UNUSED(ngbr_avail);\n\n    pu1_top = pu1_src + MB_SIZE + 1;\n    pu1_left = pu1_src + MB_SIZE - 1;\n\n    rev_8x16b = _mm_setr_epi16(0x0f0e, 0x0d0c, 0x0b0a, 0x0908, 0x0706, 0x0504, 0x0302, 0x0100);\n    //used to reverse the order of 16-bit values in a vector\n\n    mul_8x16b = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8);\n    zero_16x8b = _mm_setzero_si128();\n\n    //calculating a, b and c\n    {\n        WORD32 h, v;\n\n        __m128i h_val1_16x8b, h_val2_16x8b;\n        __m128i h_val1_8x16b, h_val2_8x16b, h_val_4x32b;\n        __m128i v_val1_16x8b, v_val2_16x8b;\n        __m128i v_val1_8x16b, v_val2_8x16b, v_val_4x32b;\n        __m128i hv_val_4x32b;\n\n        a = (pu1_top[15] + pu1_left[-15]) << 4;\n\n        h_val1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_top + 8));\n        h_val2_16x8b = _mm_loadl_epi64((__m128i *)(pu1_top - 1));\n        v_val1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_left - 15));\n        v_val2_16x8b = _mm_loadl_epi64((__m128i *)(pu1_left - 6));\n\n        h_val1_8x16b = _mm_unpacklo_epi8(h_val1_16x8b, zero_16x8b);\n        h_val2_8x16b = _mm_unpacklo_epi8(h_val2_16x8b, zero_16x8b);\n        v_val1_8x16b = _mm_unpacklo_epi8(v_val1_16x8b, zero_16x8b);\n        v_val2_8x16b = _mm_unpacklo_epi8(v_val2_16x8b, zero_16x8b);\n\n        h_val2_8x16b = _mm_shuffle_epi8(h_val2_8x16b, rev_8x16b);\n        v_val1_8x16b = _mm_shuffle_epi8(v_val1_8x16b, rev_8x16b);\n\n        h_val1_8x16b = _mm_sub_epi16(h_val1_8x16b, h_val2_8x16b);\n        v_val1_8x16b = _mm_sub_epi16(v_val1_8x16b, v_val2_8x16b);\n\n        h_val_4x32b = _mm_madd_epi16(mul_8x16b, h_val1_8x16b);\n        v_val_4x32b = _mm_madd_epi16(mul_8x16b, v_val1_8x16b);\n\n        hv_val_4x32b = _mm_hadd_epi32(h_val_4x32b, v_val_4x32b);\n        hv_val_4x32b = _mm_hadd_epi32(hv_val_4x32b, hv_val_4x32b);\n\n        h = _mm_extract_epi16(hv_val_4x32b, 0);\n        v = _mm_extract_epi16(hv_val_4x32b, 2);\n        h = (h << 16) >> 16;\n        v = (v << 16) >> 16;\n\n        b = ((h << 2) + h + 32) >> 6;\n        c = ((v << 2) + v + 32) >> 6;\n    }\n\n    //using a, b and c to compute the fitted plane values\n    {\n        __m128i const_8x16b, b_8x16b, c_8x16b, c2_8x16b;\n        __m128i res1_l_8x16b, res1_h_8x16b;\n        __m128i res2_l_8x16b, res2_h_8x16b;\n        __m128i res1_sh_l_8x16b, res1_sh_h_8x16b, res1_16x8b;\n        __m128i res2_sh_l_8x16b, res2_sh_h_8x16b, res2_16x8b;\n\n        b_8x16b = _mm_set1_epi16(b);\n        c_8x16b = _mm_set1_epi16(c);\n        c2_8x16b = _mm_set1_epi16(c << 1);\n        const_8x16b = _mm_set1_epi16(a - c*7 + 16);\n\n        res1_h_8x16b = _mm_mullo_epi16(mul_8x16b, b_8x16b);\n        //contains {b*1, b*2, b*3,... b*8}\n\n        res1_l_8x16b = _mm_shuffle_epi8(res1_h_8x16b, rev_8x16b);\n        res1_l_8x16b = _mm_srli_si128(res1_l_8x16b, 2);\n        res1_l_8x16b = _mm_sub_epi16(zero_16x8b, res1_l_8x16b);\n        //contains {-b*7, -b*6,... -b*1, b*0}\n\n        // rows 1, 2\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, const_8x16b);\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, const_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res1_h_8x16b, c_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res1_l_8x16b, c_8x16b);\n\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n        // rows 3, 4\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res2_h_8x16b, c2_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res2_l_8x16b, c2_8x16b);\n\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n\n        pu1_dst += dst_strd << 1;\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n        // rows 5, 6\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res2_h_8x16b, c2_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res2_l_8x16b, c2_8x16b);\n\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n\n        pu1_dst += dst_strd << 1;\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n        // rows 7, 8\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res2_h_8x16b, c2_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res2_l_8x16b, c2_8x16b);\n\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n\n        pu1_dst += dst_strd << 1;\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n        // rows 9, 10\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res2_h_8x16b, c2_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res2_l_8x16b, c2_8x16b);\n\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n\n        pu1_dst += dst_strd << 1;\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n        // rows 11, 12\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res2_h_8x16b, c2_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res2_l_8x16b, c2_8x16b);\n\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n\n        pu1_dst += dst_strd << 1;\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n        // rows 13, 14\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res2_h_8x16b, c2_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res2_l_8x16b, c2_8x16b);\n\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n\n        pu1_dst += dst_strd << 1;\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n\n        // rows 15, 16\n        res1_h_8x16b = _mm_add_epi16(res1_h_8x16b, c2_8x16b);\n        res1_l_8x16b = _mm_add_epi16(res1_l_8x16b, c2_8x16b);\n        res2_h_8x16b = _mm_add_epi16(res2_h_8x16b, c2_8x16b);\n        res2_l_8x16b = _mm_add_epi16(res2_l_8x16b, c2_8x16b);\n\n        res1_sh_h_8x16b = _mm_srai_epi16(res1_h_8x16b, 5);\n        res1_sh_l_8x16b = _mm_srai_epi16(res1_l_8x16b, 5);\n        res2_sh_h_8x16b = _mm_srai_epi16(res2_h_8x16b, 5);\n        res2_sh_l_8x16b = _mm_srai_epi16(res2_l_8x16b, 5);\n\n        pu1_dst += dst_strd << 1;\n\n        res1_16x8b = _mm_packus_epi16(res1_sh_l_8x16b, res1_sh_h_8x16b);\n        res2_16x8b = _mm_packus_epi16(res2_sh_l_8x16b, res2_sh_h_8x16b);\n\n        _mm_storeu_si128((__m128i *)pu1_dst, res1_16x8b);\n        _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), res2_16x8b);\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_mem_fns_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_mem_fns_atom_intr.c\n *\n * @brief\n *  Functions used for memory operations\n *\n * @author\n *  Ittiam\n *\n * @par List of Functions:\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_mem_fns.h\"\n\n#include <immintrin.h>\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n/**\n *******************************************************************************\n *\n * @brief\n *   memcpy of a 8,16 or 32 bytes\n *\n * @par Description:\n *   Does memcpy of 8bit data from source to destination for 8,16 or 32 number of bytes\n *\n * @param[in] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] pu1_src\n *  UWORD8 pointer to the source\n *\n * @param[in] num_bytes\n *  number of bytes to copy\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n\n\n\nATTRIBUTE_SSSE3\nvoid ih264_memcpy_mul_8_ssse3(UWORD8 *pu1_dst, UWORD8 *pu1_src, UWORD32 num_bytes)\n{\n    int col;\n    for(col = num_bytes; col >= 8; col -= 8)\n    {\n        __m128i src_temp16x8b;\n        src_temp16x8b = _mm_loadl_epi64((__m128i *)(pu1_src));\n        pu1_src += 8;\n        _mm_storel_epi64((__m128i *)(pu1_dst), src_temp16x8b);\n        pu1_dst += 8;\n    }\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *   memset of a 8,16 or 32 bytes\n *\n * @par Description:\n *   Does memset of 8bit data for 8,16 or 32 number of bytes\n *\n * @param[in] pu1_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] value\n *  UWORD8 value used for memset\n *\n * @param[in] num_bytes\n *  number of bytes to set\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n\nATTRIBUTE_SSSE3\nvoid ih264_memset_mul_8_ssse3(UWORD8 *pu1_dst, UWORD8 value, UWORD32 num_bytes)\n{\n    int col;\n    __m128i src_temp16x8b;\n    src_temp16x8b = _mm_set1_epi8(value);\n    for(col = num_bytes; col >= 8; col -= 8)\n    {\n        _mm_storel_epi64((__m128i *)(pu1_dst), src_temp16x8b);\n        pu1_dst += 8;\n    }\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *   memset of 16bit data of a 8,16 or 32 bytes\n *\n * @par Description:\n *   Does memset of 16bit data for 8,16 or 32 number of bytes\n *\n * @param[in] pu2_dst\n *  UWORD8 pointer to the destination\n *\n * @param[in] value\n *  UWORD16 value used for memset\n *\n * @param[in] num_words\n *  number of words to set\n * @returns\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n\nvoid ih264_memset_16bit_mul_8_ssse3(UWORD16 *pu2_dst, UWORD16 value, UWORD32 num_words)\n{\n    int col;\n    __m128i src_temp16x8b;\n    src_temp16x8b = _mm_set1_epi16(value);\n    for(col = num_words; col >= 8; col -= 8)\n    {\n        _mm_storeu_si128((__m128i *)(pu2_dst), src_temp16x8b);\n        pu2_dst += 8;\n    }\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_padding_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_padding_atom_intr.c\n*\n* @brief\n*  Contains function definitions for Padding\n*\n* @author\n*  Srinivas T\n*\n* @par List of Functions:\n*   - ih264_pad_left_luma_ssse3()\n*   - ih264_pad_left_chroma_ssse3()\n*   - ih264_pad_right_luma_ssse3()\n*   - ih264_pad_right_chroma_ssse3()\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n#include <string.h>\n#include <assert.h>\n#include \"ih264_typedefs.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_mem_fns.h\"\n#include \"ih264_debug.h\"\n\n#include <immintrin.h>\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*   Padding (luma block) at the left of a 2d array\n*\n* @par Description:\n*   The left column of a 2d array is replicated for pad_size times at the left\n*\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] wd\n*  integer width of the array\n*\n* @param[in] pad_size\n*  integer -padding size of the array\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] wd\n*  integer width of the array\n*\n* @returns\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\nATTRIBUTE_SSSE3\nvoid ih264_pad_left_luma_ssse3(UWORD8 *pu1_src,\n                               WORD32 src_strd,\n                               WORD32 ht,\n                               WORD32 pad_size)\n{\n    WORD32 row;\n    WORD32 i;\n    UWORD8 *pu1_dst;\n\n    ASSERT(pad_size % 8 == 0);\n\n    for(row = 0; row < ht; row++)\n    {\n        __m128i src_temp0_16x8b;\n\n        pu1_dst = pu1_src - pad_size;\n        src_temp0_16x8b = _mm_set1_epi8(*pu1_src);\n        for(i = 0; i < pad_size; i += 8)\n        {\n            _mm_storel_epi64((__m128i *)(pu1_dst + i), src_temp0_16x8b);\n        }\n        pu1_src += src_strd;\n    }\n\n}\n\n\n\n/**\n*******************************************************************************\n*\n* @brief\n*   Padding (chroma block) at the left of a 2d array\n*\n* @par Description:\n*   The left column of a 2d array is replicated for pad_size times at the left\n*\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] wd\n*  integer width of the array (each colour component)\n*\n* @param[in] pad_size\n*  integer -padding size of the array\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] wd\n*  integer width of the array\n*\n* @returns\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\nATTRIBUTE_SSSE3\nvoid ih264_pad_left_chroma_ssse3(UWORD8 *pu1_src,\n                                 WORD32 src_strd,\n                                 WORD32 ht,\n                                 WORD32 pad_size)\n{\n    WORD32 row;\n    WORD32 col;\n    UWORD8 *pu1_dst;\n\n    ASSERT(pad_size % 8 == 0);\n    for(row = 0; row < ht; row++)\n    {\n        __m128i src_temp0_16x8b;\n\n        pu1_dst = pu1_src - pad_size;\n        src_temp0_16x8b = _mm_set1_epi16(*((UWORD16 *)pu1_src));\n        for(col = 0; col < pad_size; col += 8)\n        {\n            _mm_storel_epi64((__m128i *)(pu1_dst + col), src_temp0_16x8b);\n        }\n        pu1_src += src_strd;\n    }\n\n}\n\n\n\n/**\n*******************************************************************************\n*\n* @brief\n* Padding (luma block) at the right of a 2d array\n*\n* @par Description:\n* The right column of a 2d array is replicated for pad_size times at the right\n*\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] wd\n*  integer width of the array\n*\n* @param[in] pad_size\n*  integer -padding size of the array\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] wd\n*  integer width of the array\n*\n* @returns\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\nATTRIBUTE_SSSE3\nvoid ih264_pad_right_luma_ssse3(UWORD8 *pu1_src,\n                                WORD32 src_strd,\n                                WORD32 ht,\n                                WORD32 pad_size)\n{\n    WORD32 row;\n    WORD32 col;\n    UWORD8 *pu1_dst;\n\n    ASSERT(pad_size % 8 == 0);\n\n    for(row = 0; row < ht; row++)\n    {\n        __m128i src_temp0_16x8b;\n\n        pu1_dst = pu1_src;\n        src_temp0_16x8b = _mm_set1_epi8(*(pu1_src - 1));\n        for(col = 0; col < pad_size; col += 8)\n        {\n            _mm_storel_epi64((__m128i *)(pu1_dst + col), src_temp0_16x8b);\n        }\n        pu1_src += src_strd;\n    }\n\n}\n\n\n\n/**\n*******************************************************************************\n*\n* @brief\n* Padding (chroma block) at the right of a 2d array\n*\n* @par Description:\n* The right column of a 2d array is replicated for pad_size times at the right\n*\n*\n* @param[in] pu1_src\n*  UWORD8 pointer to the source\n*\n* @param[in] src_strd\n*  integer source stride\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] wd\n*  integer width of the array (each colour component)\n*\n* @param[in] pad_size\n*  integer -padding size of the array\n*\n* @param[in] ht\n*  integer height of the array\n*\n* @param[in] wd\n*  integer width of the array\n*\n* @returns\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\nATTRIBUTE_SSSE3\nvoid ih264_pad_right_chroma_ssse3(UWORD8 *pu1_src,\n                                  WORD32 src_strd,\n                                  WORD32 ht,\n                                  WORD32 pad_size)\n{\n    WORD32 row;\n    WORD32 col;\n    UWORD8 *pu1_dst;\n\n    ASSERT(pad_size % 8 == 0);\n\n    for(row = 0; row < ht; row++)\n    {\n        __m128i src_temp0_16x8b;\n\n        pu1_dst = pu1_src;\n        src_temp0_16x8b = _mm_set1_epi16(*((UWORD16 *)(pu1_src - 2)));\n        for(col = 0; col < pad_size; col += 8)\n        {\n            _mm_storel_epi64((__m128i *)(pu1_dst + col), src_temp0_16x8b);\n        }\n\n        pu1_src += src_strd;\n    }\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_platform_macros.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264_platform_macros.h\n*\n* @brief\n*  Platform specific Macro definitions used in the codec\n*\n* @author\n*  Ittiam\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n\n#ifndef _IH264_PLATFORM_MACROS_H_\n#define _IH264_PLATFORM_MACROS_H_\n\n#include <stdint.h>\n#include <immintrin.h>\n#if defined(_MSC_VER) && defined(__clang__)\n#include <intrin.h>\n#endif\n\n#define CLIP_U8(x) CLIP3(0, UINT8_MAX, (x))\n#define CLIP_S8(x) CLIP3(INT8_MIN, INT8_MAX, (x))\n\n#define CLIP_U10(x) CLIP3(0, 1023, (x))\n#define CLIP_S10(x) CLIP3(-512, 511, (x))\n\n#define CLIP_U11(x) CLIP3(0, 2047, (x))\n#define CLIP_S11(x) CLIP3(-1024, 1023, (x))\n\n#define CLIP_U12(x) CLIP3(0, 4095, (x))\n#define CLIP_S12(x) CLIP3(-2048, 2047, (x))\n\n#define CLIP_U16(x) CLIP3(0, UINT16_MAX, (x))\n#define CLIP_S16(x) CLIP3(INT16_MIN, INT16_MAX, (x))\n\n#define CLIP_U32(x) CLIP3(0, UINT32_MAX, (x))\n#define CLIP_S32(x) CLIP3(INT32_MIN, INT32_MAX, (x))\n\n#define MEM_ALIGN16 __attribute__ ((aligned (16)))\n\n#define SHL(x,y) (((y) < 32) ? ((x) << (y)) : 0)\n#define SHR(x,y) (((y) < 32) ? ((x) >> (y)) : 0)\n\n#define SHR_NEG(val,shift)  ((shift>0)?(val>>shift):(val<<(-shift)))\n#define SHL_NEG(val,shift)  ((shift<0)?(val>>(-shift)):(val<<shift))\n\n#define PLD(a)\n\n/* For MSVC x64 */\n\n#if defined(_MSC_VER) && !defined(__clang__)\n\nstatic inline int __builtin_clz(unsigned x)\n{\n\tunsigned long n;\n\t_BitScanReverse(&n, x);\n\treturn n ^ 31;\n}\n\nstatic inline int __builtin_ctz(unsigned x) {\n\tunsigned long ret;\n\t_BitScanForward(&ret, x);\n\treturn (int)ret;\n}\n\nstatic inline void __sync_synchronize() {\n\t__faststorefence();\n}\n\n#define NOP(nop_cnt) {UWORD32 nop_i; for (nop_i = 0; nop_i < nop_cnt; nop_i++) __nop();}\n\n#else\n\n#define NOP(nop_cnt) {UWORD32 nop_i; for (nop_i = 0; nop_i < nop_cnt; nop_i++) asm(\"nop\");}\n\n#endif\n\n/* In normal cases, 0 will not be passed as an argument to CLZ and CTZ.\nAs CLZ and CTZ outputs are used as a shift value in few places, these return\n31 for u4_word == 0 case, just to handle error cases gracefully without any\nundefined behaviour */\n\nstatic __inline UWORD32 CLZ(UWORD32 u4_word)\n{\n    if(u4_word || 1)\n        return(__builtin_clz(u4_word));\n    else\n        return 31;\n}\n\nstatic __inline UWORD32 CTZ(UWORD32 u4_word)\n{\n    if(0 == u4_word && 0)\n        return 31;\n    else\n    {\n        unsigned int index;\n        index = __builtin_ctz(u4_word);\n        return (UWORD32)index;\n    }\n}\n\n#define DATA_SYNC()  __sync_synchronize()\n\n//#define INLINE __inline\n#define INLINE inline\n\n#define PREFETCH_ENABLE 1\n\n#if PREFETCH_ENABLE\n#define PREFETCH(ptr, type) _mm_prefetch(ptr, type);\n#else\n#define PREFETCH(ptr, type)\n#endif\n\n#define MEM_ALIGN8 __attribute__ ((aligned (8)))\n#define MEM_ALIGN16 __attribute__ ((aligned (16)))\n#define MEM_ALIGN32 __attribute__ ((aligned (32)))\n\n#endif /* _IH264_PLATFORM_MACROS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_resi_trans_quant_sse42.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264_resi_trans_quant_sse42.c\n *\n * @brief\n *  Contains function definitions single stage  forward transform for H.264\n *  It will calculate the residue, do the cf and then do quantization\n *\n * @author\n *  Mohit [100664]\n *\n * @par List of Functions:\n *  - ih264_resi_trans_quant_4x4_sse42()\n *  - ih264_resi_trans_quant_chroma_4x4_sse42()\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n/* System include files */\n#include <stddef.h>\n\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_trans_macros.h\"\n#include \"ih264_trans_data.h\"\n#include \"ih264_structs.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include <immintrin.h>\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSE42 __attribute__((target(\"sse4.2\")))\n#else\n#define ATTRIBUTE_SSE42\n#endif\n/**\n *******************************************************************************\n *\n * @brief\n *   This function performs forward transform and quantization on a 4*4 block\n *\n * @par Description:\n *   The function accepts source buffer and estimation buffer. From these, it\n *   computes the residue. This is residue is then transformed and quantized.\n *   The transform and quantization are in placed computed. They use the residue\n *   buffer for this.\n *\n * @param[in] pu1_src\n *   Pointer to source sub-block\n *\n * @param[in] pu1_pred\n *   Pointer to prediction sub-block\n *\n * @param[in] pi2_out\n *   Pointer to residual sub-block\n *\n * @param[in] src_strd\n *   Source stride\n *\n * @param[in] pred_strd\n *   Prediction stride\n *\n * @param[in] dst_strd\n *   Destination stride\n *\n * @param[in] u4_qbits\n *    QP_BITS_h264_4x4 + floor(QP/6)\n *\n * @param[in] pu2_threshold_matrix\n *   Pointer to Forward Quant Threshold Matrix\n *\n * @param[in] pu2_scale_matrix\n *   Pointer to Forward Quant Scale Matrix\n *\n * @param[in] u4_round_factor\n *   Quantization Round factor\n *\n * @param[out] pu1_nnz\n *   Total non-zero coefficients in the current sub-block\n *\n * @returns\n *\n * @remarks\n *   None\n *\n *******************************************************************************\n */\nATTRIBUTE_SSE42\nvoid ih264_resi_trans_quant_4x4_sse42(UWORD8 *pu1_src, UWORD8 *pu1_pred,\n                                      WORD16 *pi2_out, WORD32 src_strd, WORD32 pred_strd,\n                                      const UWORD16 *pu2_scale_matrix, const UWORD16 *pu2_threshold_matrix,\n                                      UWORD32 u4_qbits, UWORD32 u4_round_factor, UWORD8 *pu1_nnz,\n                                      WORD16 *pi2_alt_dc_addr)\n{\n    WORD32 tmp_dc, u4_zero_coeff, u4_nonzero_coeff = 0;\n    WORD32 mask0, mask1;\n    __m128i sum0, sum1, sum2, cmp0, cmp1;\n    __m128i rnd_fact = _mm_set1_epi32(u4_round_factor);\n    __m128i temp_2 = _mm_set1_epi16(2);\n    __m128i temp_1 = _mm_set1_epi16(1);\n    __m128i src_r0, src_r1, src_r2, src_r3;\n    __m128i pred_r0, pred_r1, pred_r2, pred_r3;\n    __m128i temp0, temp1, temp2, temp3;\n    __m128i zero_8x16b = _mm_setzero_si128();          // all bits reset to zero\n    __m128i sign_reg0, sign_reg2;\n    __m128i scalemat_r0_r1, scalemat_r2_r3;\n\n    UNUSED (pu2_threshold_matrix);\n\n    scalemat_r0_r1 = _mm_loadu_si128((__m128i *) (pu2_scale_matrix)); //b00 b01 b02 b03 b10 b11 b12 b13 -- the scaling matrix 0th,1st row\n    scalemat_r2_r3 = _mm_loadu_si128((__m128i *) (pu2_scale_matrix + 8)); //b20 b21 b22 b23 b30 b31 b32 b33 -- the scaling matrix 2nd,3rd row\n    src_r0 = _mm_loadl_epi64((__m128i *) (&pu1_src[0])); //a00 a01 a02 a03 0 0 0 0 0 0 0 0 -- all 8 bits\n    src_r1 = _mm_loadl_epi64((__m128i *) (&pu1_src[src_strd])); //a10 a11 a12 a13 0 0 0 0 0 0 0 0 -- all 8 bits\n    src_r2 = _mm_loadl_epi64((__m128i *) (&pu1_src[2 * src_strd])); //a20 a21 a22 a23 0 0 0 0 0 0 0 0 -- all 8 bits\n    src_r3 = _mm_loadl_epi64((__m128i *) (&pu1_src[3 * src_strd])); //a30 a31 a32 a33 0 0 0 0 0 0 0 0 -- all 8 bits\n\n    src_r0 = _mm_cvtepu8_epi16(src_r0);\n    src_r1 = _mm_cvtepu8_epi16(src_r1);\n    src_r2 = _mm_cvtepu8_epi16(src_r2);\n    src_r3 = _mm_cvtepu8_epi16(src_r3);\n\n    pred_r0 = _mm_loadl_epi64((__m128i *) (&pu1_pred[0])); //p00 p01 p02 p03 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r1 = _mm_loadl_epi64((__m128i *) (&pu1_pred[pred_strd])); //p10 p11 p12 p13 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r2 = _mm_loadl_epi64((__m128i *) (&pu1_pred[2 * pred_strd])); //p20 p21 p22 p23 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r3 = _mm_loadl_epi64((__m128i *) (&pu1_pred[3 * pred_strd])); //p30 p31 p32 p33 0 0 0 0 0 0 0 0 -- all 8 bits\n\n    pred_r0 = _mm_cvtepu8_epi16(pred_r0); //p00 p01 p02 p03 -- all 16 bits\n    pred_r1 = _mm_cvtepu8_epi16(pred_r1); //p10 p11 p12 p13 -- all 16 bits\n    pred_r2 = _mm_cvtepu8_epi16(pred_r2); //p20 p21 p22 p23 -- all 16 bits\n    pred_r3 = _mm_cvtepu8_epi16(pred_r3); //p30 p31 p32 p33 -- all 16 bits\n\n    src_r0 = _mm_sub_epi16(src_r0, pred_r0);\n    src_r1 = _mm_sub_epi16(src_r1, pred_r1);\n    src_r2 = _mm_sub_epi16(src_r2, pred_r2);\n    src_r3 = _mm_sub_epi16(src_r3, pred_r3);\n\n    /* Perform Forward transform */\n    /*-------------------------------------------------------------*/\n    /* DCT [ Horizontal transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 a1 a2 a3\n     *  b0 b1 b2 b3\n     *  c0 c1 c2 c3\n     *  d0 d1 d2 d3\n     */\n    temp0 = _mm_unpacklo_epi16(src_r0, src_r1);                 //a0 b0 a1 b1 a2 b2 a3 b3\n    temp2 = _mm_unpacklo_epi16(src_r2, src_r3);                 //c0 d0 c1 d1 c2 d2 c3 d3\n    temp1 = _mm_unpacklo_epi32(temp0, temp2);                   //a0 b0 c0 d0 a1 b1 c1 d1\n    temp3 = _mm_unpackhi_epi32(temp0, temp2);                   //a2 b2 c2 d2 a3 b3 c3 d3\n\n    src_r0 = _mm_unpacklo_epi64(temp1, zero_8x16b);             //a0 b0 c0 d0\n    src_r1 = _mm_unpackhi_epi64(temp1, zero_8x16b);             //a1 b1 c1 d1\n    src_r2 = _mm_unpacklo_epi64(temp3, zero_8x16b);             //a2 b2 c2 d2\n    src_r3 = _mm_unpackhi_epi64(temp3, zero_8x16b);             //a3 b3 c3 d3\n\n    /*----------------------------------------------------------*/\n    /* x0 = z0 + z3                                             */\n    temp0 = _mm_add_epi16(src_r0, src_r3);\n    /* x1 = z1 + z2                                             */\n    temp1 = _mm_add_epi16(src_r1, src_r2);\n    /* x2 = z1 - z2                                             */\n    temp2 = _mm_sub_epi16(src_r1, src_r2);\n    /* x3 = z0 - z3                                             */\n    temp3 = _mm_sub_epi16(src_r0, src_r3);\n\n    /* z0 = x0 + x1                                             */\n    src_r0 = _mm_add_epi16(temp0, temp1);\n    /* z1 = (x3 << 1) + x2                                      */\n    src_r1 = _mm_slli_epi16(temp3, 1);                          //(x3<<1)\n    src_r1 = _mm_add_epi16(src_r1, temp2);\n    /* z2 = x0 - x1                                             */\n    src_r2 = _mm_sub_epi16(temp0, temp1);\n    /* z3 = x3 - (x2 << 1)                                      */\n    src_r3 = _mm_slli_epi16(temp2, 1);                          //(x2<<1)\n    src_r3 = _mm_sub_epi16(temp3, src_r3);\n\n    // Matrix transpose\n    /*\n     *  a0 b0 c0 d0\n     *  a1 b1 c1 d1\n     *  a2 b2 c2 d2\n     *  a3 b3 c3 d3\n     */\n    temp0 = _mm_unpacklo_epi16(src_r0, src_r1);                 //a0 a1 b0 b1 c0 c1 d0 d1\n    temp2 = _mm_unpacklo_epi16(src_r2, src_r3);                 //a2 a3 b2 b3 c2 c3 d2 d3\n    temp1 = _mm_unpacklo_epi32(temp0, temp2);                   //a0 a1 a2 a3 b0 b1 b2 b3\n    temp3 = _mm_unpackhi_epi32(temp0, temp2);                   //c0 c1 c2 c3 d0 d1 d2 d3\n\n    src_r0 = _mm_unpacklo_epi64(temp1, zero_8x16b);             //a0 a1 a2 a3\n    src_r1 = _mm_unpackhi_epi64(temp1, zero_8x16b);             //b0 b1 b2 b3\n    src_r2 = _mm_unpacklo_epi64(temp3, zero_8x16b);             //c0 c1 c2 c3\n    src_r3 = _mm_unpackhi_epi64(temp3, zero_8x16b);             //d0 d1 d2 d3\n\n    /*----------------------------------------------------------*/\n    /* x0 = z0 + z3                                             */\n    temp0 = _mm_add_epi16(src_r0, src_r3);\n    /* x1 = z1 + z2                                             */\n    temp1 = _mm_add_epi16(src_r1, src_r2);\n    /* x2 = z1 - z2                                             */\n    temp2 = _mm_sub_epi16(src_r1, src_r2);\n    /* x3 = z0 - z3                                             */\n    temp3 = _mm_sub_epi16(src_r0, src_r3);\n\n    /* z0 = x0 + x1                                             */\n    src_r0 = _mm_add_epi16(temp0, temp1);\n    /* z1 = (x3 << 1) + x2                                      */\n    src_r1 = _mm_slli_epi16(temp3, 1);                          //(x3<<1)\n    src_r1 = _mm_add_epi16(src_r1, temp2);\n    /* z2 = x0 - x1                                             */\n    src_r2 = _mm_sub_epi16(temp0, temp1);\n    /* z3 = x3 - (x2 << 1)                                      */\n    src_r3 = _mm_slli_epi16(temp2, 1);                          //(x2<<1)\n    src_r3 = _mm_sub_epi16(temp3, src_r3);\n\n    tmp_dc = _mm_extract_epi16(src_r0,0);                       //a0\n    *pi2_alt_dc_addr = tmp_dc;\n\n    src_r0 = _mm_unpacklo_epi64(src_r0, src_r1);                //a0 a1 a2 a3 b0 b1 b2 b3\n    src_r2 = _mm_unpacklo_epi64(src_r2, src_r3);                //c0 c1 c2 c3 d0 d1 d2 d3\n    sign_reg0 = _mm_cmpgt_epi16(zero_8x16b,src_r0);\n    sign_reg2 = _mm_cmpgt_epi16(zero_8x16b,src_r2);\n\n    sign_reg0 = _mm_mullo_epi16(temp_2,sign_reg0);\n    sign_reg2 = _mm_mullo_epi16(temp_2,sign_reg2);\n\n    sign_reg0 = _mm_add_epi16(temp_1,sign_reg0);\n    sign_reg2 = _mm_add_epi16(temp_1,sign_reg2);\n\n    src_r0 = _mm_abs_epi16(src_r0);\n    src_r2 = _mm_abs_epi16(src_r2);\n\n    src_r1 = _mm_srli_si128(src_r0, 8);\n    src_r0 = _mm_cvtepu16_epi32(src_r0);\n    src_r1 = _mm_cvtepu16_epi32(src_r1);\n    src_r3 = _mm_srli_si128(src_r2, 8);\n    src_r2 = _mm_cvtepu16_epi32(src_r2);\n    src_r3 = _mm_cvtepu16_epi32(src_r3);\n\n    temp0 = _mm_cvtepu16_epi32(scalemat_r0_r1);\n    scalemat_r0_r1 = _mm_srli_si128(scalemat_r0_r1, 8);\n    temp2 = _mm_cvtepu16_epi32(scalemat_r2_r3);\n    scalemat_r2_r3 = _mm_srli_si128(scalemat_r2_r3, 8);\n    temp1 = _mm_cvtepu16_epi32(scalemat_r0_r1);\n    temp3 = _mm_cvtepu16_epi32(scalemat_r2_r3);\n\n    temp0 = _mm_mullo_epi32(temp0, src_r0);\n    temp1 = _mm_mullo_epi32(temp1, src_r1);\n    temp2 = _mm_mullo_epi32(temp2, src_r2);\n    temp3 = _mm_mullo_epi32(temp3, src_r3);\n\n    temp0 = _mm_add_epi32(temp0,rnd_fact);\n    temp1 = _mm_add_epi32(temp1,rnd_fact);\n    temp2 = _mm_add_epi32(temp2,rnd_fact);\n    temp3 = _mm_add_epi32(temp3,rnd_fact);\n\n    temp0 = _mm_srli_epi32(temp0,u4_qbits);\n    temp1 = _mm_srli_epi32(temp1,u4_qbits);\n    temp2 = _mm_srli_epi32(temp2,u4_qbits);\n    temp3 = _mm_srli_epi32(temp3,u4_qbits);\n\n    temp0 =  _mm_packs_epi32 (temp0,temp1);\n    temp2 =  _mm_packs_epi32 (temp2,temp3);\n\n    temp0 =  _mm_sign_epi16(temp0, sign_reg0);\n    temp2 =  _mm_sign_epi16(temp2, sign_reg2);\n\n    _mm_storeu_si128((__m128i *) (&pi2_out[0]), temp0);\n    _mm_storeu_si128((__m128i *) (&pi2_out[8]), temp2);\n\n    cmp0 = _mm_cmpeq_epi16(temp0, zero_8x16b);\n    cmp1 = _mm_cmpeq_epi16(temp2, zero_8x16b);\n\n    mask0 = _mm_movemask_epi8(cmp0);\n    mask1 = _mm_movemask_epi8(cmp1);\n    u4_zero_coeff = 0;\n    if(mask0)\n    {\n        if(mask0 == 0xffff)\n            u4_zero_coeff+=8;\n        else\n        {\n            cmp0 = _mm_and_si128(temp_1, cmp0);\n            sum0 = _mm_hadd_epi16(cmp0, zero_8x16b);\n            sum1 = _mm_hadd_epi16(sum0, zero_8x16b);\n            sum2 = _mm_hadd_epi16(sum1, zero_8x16b);\n            u4_zero_coeff += _mm_cvtsi128_si32(sum2);\n        }\n    }\n    if(mask1)\n    {\n        if(mask1 == 0xffff)\n            u4_zero_coeff+=8;\n        else\n        {\n            cmp1 = _mm_and_si128(temp_1, cmp1);\n            sum0 = _mm_hadd_epi16(cmp1, zero_8x16b);\n            sum1 = _mm_hadd_epi16(sum0, zero_8x16b);\n            sum2 = _mm_hadd_epi16(sum1, zero_8x16b);\n            u4_zero_coeff += _mm_cvtsi128_si32(sum2);\n        }\n    }\n\n    /* Return total nonzero coefficients in the current sub block */\n    u4_nonzero_coeff = 16 - u4_zero_coeff;\n    *pu1_nnz =  u4_nonzero_coeff;\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *   This function performs forward transform and quantization on a 4*4 chroma block\n *\n * @par Description:\n *   The function accepts source buffer and estimation buffer. From these, it\n *   computes the residue. This is residue is then transformed and quantized.\n *   The transform and quantization are in placed computed. They use the residue\n *   buffer for this.\n *\n * @param[in] pu1_src\n *   Pointer to source sub-block\n *\n * @param[in] pu1_pred\n *   Pointer to prediction sub-block\n *\n * @param[in] pi2_out\n *   Pointer to residual sub-block\n *\n * @param[in] src_strd\n *   Source stride\n *\n * @param[in] pred_strd\n *   Prediction stride\n *\n * @param[in] dst_strd\n *   Destination stride\n *\n * @param[in] u4_qbits\n *    QP_BITS_h264_4x4 + floor(QP/6)\n *\n * @param[in] pu2_threshold_matrix\n *   Pointer to Forward Quant Threshold Matrix\n *\n * @param[in] pu2_scale_matrix\n *   Pointer to Forward Quant Scale Matrix\n *\n * @param[in] u4_round_factor\n *   Quantization Round factor\n *\n * @param[out] pu1_nnz\n *   Total non-zero coefficients in the current sub-block\n *\n * @returns\n *\n * @remarks\n *   None\n *\n *******************************************************************************\n */\nATTRIBUTE_SSE42\nvoid ih264_resi_trans_quant_chroma_4x4_sse42(UWORD8 *pu1_src,UWORD8 *pu1_pred,WORD16 *pi2_out,\n                                            WORD32 src_strd,WORD32 pred_strd,\n                                            const UWORD16 *pu2_scale_matrix,\n                                            const UWORD16 *pu2_threshold_matrix,\n                                            UWORD32 u4_qbits,UWORD32 u4_round_factor,\n                                            UWORD8  *pu1_nnz, WORD16 *pi2_alt_dc_addr)\n{\n    WORD32 tmp_dc, u4_zero_coeff, u4_nonzero_coeff = 0;\n    WORD32 mask0, mask1;\n    __m128i cmp0, cmp1, sum0, sum1, sum2;\n    __m128i rnd_fact = _mm_set1_epi32(u4_round_factor);\n    __m128i temp_2 = _mm_set1_epi16(2);\n    __m128i temp_1 = _mm_set1_epi16(1);\n    __m128i src_r0, src_r1, src_r2, src_r3;\n    __m128i pred_r0, pred_r1, pred_r2, pred_r3;\n    __m128i temp0, temp1, temp2, temp3;\n    __m128i zero_8x16b = _mm_setzero_si128();          // all bits reset to zero\n    __m128i sign_reg0, sign_reg2;\n    __m128i scalemat_r0_r1, scalemat_r2_r3;\n    __m128i chroma_mask = _mm_set1_epi16 (0xFF);\n\n    UNUSED (pu2_threshold_matrix);\n\n    scalemat_r0_r1 = _mm_loadu_si128((__m128i *) (pu2_scale_matrix)); //b00 b01 b02 b03 b10 b11 b12 b13 -- the scaling matrix 0th,1st row\n    scalemat_r2_r3 = _mm_loadu_si128((__m128i *) (pu2_scale_matrix + 8)); //b20 b21 b22 b23 b30 b31 b32 b33 -- the scaling matrix 2nd,3rd row\n    src_r0 = _mm_loadl_epi64((__m128i *) (&pu1_src[0])); //a00 a01 a02 a03 0 0 0 0 0 0 0 0 -- all 8 bits\n    src_r1 = _mm_loadl_epi64((__m128i *) (&pu1_src[src_strd])); //a10 a11 a12 a13 0 0 0 0 0 0 0 0 -- all 8 bits\n    src_r2 = _mm_loadl_epi64((__m128i *) (&pu1_src[2 * src_strd])); //a20 a21 a22 a23 0 0 0 0 0 0 0 0 -- all 8 bits\n    src_r3 = _mm_loadl_epi64((__m128i *) (&pu1_src[3 * src_strd])); //a30 a31 a32 a33 0 0 0 0 0 0 0 0 -- all 8 bits\n\n    src_r0 = _mm_and_si128(src_r0, chroma_mask);\n    src_r1 = _mm_and_si128(src_r1, chroma_mask);\n    src_r2 = _mm_and_si128(src_r2, chroma_mask);\n    src_r3 = _mm_and_si128(src_r3, chroma_mask);\n//  src_r0 = _mm_cvtepu8_epi16(src_r0);\n//  src_r1 = _mm_cvtepu8_epi16(src_r1);\n//  src_r2 = _mm_cvtepu8_epi16(src_r2);\n//  src_r3 = _mm_cvtepu8_epi16(src_r3);\n\n    pred_r0 = _mm_loadl_epi64((__m128i *) (&pu1_pred[0])); //p00 p01 p02 p03 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r1 = _mm_loadl_epi64((__m128i *) (&pu1_pred[pred_strd])); //p10 p11 p12 p13 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r2 = _mm_loadl_epi64((__m128i *) (&pu1_pred[2 * pred_strd])); //p20 p21 p22 p23 0 0 0 0 0 0 0 0 -- all 8 bits\n    pred_r3 = _mm_loadl_epi64((__m128i *) (&pu1_pred[3 * pred_strd])); //p30 p31 p32 p33 0 0 0 0 0 0 0 0 -- all 8 bits\n\n    pred_r0 = _mm_and_si128(pred_r0, chroma_mask);\n    pred_r1 = _mm_and_si128(pred_r1, chroma_mask);\n    pred_r2 = _mm_and_si128(pred_r2, chroma_mask);\n    pred_r3 = _mm_and_si128(pred_r3, chroma_mask);\n//  pred_r0 = _mm_cvtepu8_epi16(pred_r0); //p00 p01 p02 p03 -- all 16 bits\n//  pred_r1 = _mm_cvtepu8_epi16(pred_r1); //p10 p11 p12 p13 -- all 16 bits\n//  pred_r2 = _mm_cvtepu8_epi16(pred_r2); //p20 p21 p22 p23 -- all 16 bits\n//  pred_r3 = _mm_cvtepu8_epi16(pred_r3); //p30 p31 p32 p33 -- all 16 bits\n\n    src_r0 = _mm_sub_epi16(src_r0, pred_r0);\n    src_r1 = _mm_sub_epi16(src_r1, pred_r1);\n    src_r2 = _mm_sub_epi16(src_r2, pred_r2);\n    src_r3 = _mm_sub_epi16(src_r3, pred_r3);\n\n    /* Perform Forward transform */\n    /*-------------------------------------------------------------*/\n    /* DCT [ Horizontal transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 a1 a2 a3\n     *  b0 b1 b2 b3\n     *  c0 c1 c2 c3\n     *  d0 d1 d2 d3\n     */\n    temp0 = _mm_unpacklo_epi16(src_r0, src_r1);                 //a0 b0 a1 b1 a2 b2 a3 b3\n    temp2 = _mm_unpacklo_epi16(src_r2, src_r3);                 //c0 d0 c1 d1 c2 d2 c3 d3\n    temp1 = _mm_unpacklo_epi32(temp0, temp2);                   //a0 b0 c0 d0 a1 b1 c1 d1\n    temp3 = _mm_unpackhi_epi32(temp0, temp2);                   //a2 b2 c2 d2 a3 b3 c3 d3\n\n    src_r0 = _mm_unpacklo_epi64(temp1, zero_8x16b);             //a0 b0 c0 d0\n    src_r1 = _mm_unpackhi_epi64(temp1, zero_8x16b);             //a1 b1 c1 d1\n    src_r2 = _mm_unpacklo_epi64(temp3, zero_8x16b);             //a2 b2 c2 d2\n    src_r3 = _mm_unpackhi_epi64(temp3, zero_8x16b);             //a3 b3 c3 d3\n\n    /*----------------------------------------------------------*/\n    /* x0 = z0 + z3                                             */\n    temp0 = _mm_add_epi16(src_r0, src_r3);\n    /* x1 = z1 + z2                                             */\n    temp1 = _mm_add_epi16(src_r1, src_r2);\n    /* x2 = z1 - z2                                             */\n    temp2 = _mm_sub_epi16(src_r1, src_r2);\n    /* x3 = z0 - z3                                             */\n    temp3 = _mm_sub_epi16(src_r0, src_r3);\n\n    /* z0 = x0 + x1                                             */\n    src_r0 = _mm_add_epi16(temp0, temp1);\n    /* z1 = (x3 << 1) + x2                                      */\n    src_r1 = _mm_slli_epi16(temp3, 1);                          //(x3<<1)\n    src_r1 = _mm_add_epi16(src_r1, temp2);\n    /* z2 = x0 - x1                                             */\n    src_r2 = _mm_sub_epi16(temp0, temp1);\n    /* z3 = x3 - (x2 << 1)                                      */\n    src_r3 = _mm_slli_epi16(temp2, 1);                          //(x2<<1)\n    src_r3 = _mm_sub_epi16(temp3, src_r3);\n\n    // Matrix transpose\n    /*\n     *  a0 b0 c0 d0\n     *  a1 b1 c1 d1\n     *  a2 b2 c2 d2\n     *  a3 b3 c3 d3\n     */\n    temp0 = _mm_unpacklo_epi16(src_r0, src_r1);                 //a0 a1 b0 b1 c0 c1 d0 d1\n    temp2 = _mm_unpacklo_epi16(src_r2, src_r3);                 //a2 a3 b2 b3 c2 c3 d2 d3\n    temp1 = _mm_unpacklo_epi32(temp0, temp2);                   //a0 a1 a2 a3 b0 b1 b2 b3\n    temp3 = _mm_unpackhi_epi32(temp0, temp2);                   //c0 c1 c2 c3 d0 d1 d2 d3\n\n    src_r0 = _mm_unpacklo_epi64(temp1, zero_8x16b);             //a0 a1 a2 a3\n    src_r1 = _mm_unpackhi_epi64(temp1, zero_8x16b);             //b0 b1 b2 b3\n    src_r2 = _mm_unpacklo_epi64(temp3, zero_8x16b);             //c0 c1 c2 c3\n    src_r3 = _mm_unpackhi_epi64(temp3, zero_8x16b);             //d0 d1 d2 d3\n\n    /*----------------------------------------------------------*/\n    /* x0 = z0 + z3                                             */\n    temp0 = _mm_add_epi16(src_r0, src_r3);\n    /* x1 = z1 + z2                                             */\n    temp1 = _mm_add_epi16(src_r1, src_r2);\n    /* x2 = z1 - z2                                             */\n    temp2 = _mm_sub_epi16(src_r1, src_r2);\n    /* x3 = z0 - z3                                             */\n    temp3 = _mm_sub_epi16(src_r0, src_r3);\n\n    /* z0 = x0 + x1                                             */\n    src_r0 = _mm_add_epi16(temp0, temp1);\n    /* z1 = (x3 << 1) + x2                                      */\n    src_r1 = _mm_slli_epi16(temp3, 1);                          //(x3<<1)\n    src_r1 = _mm_add_epi16(src_r1, temp2);\n    /* z2 = x0 - x1                                             */\n    src_r2 = _mm_sub_epi16(temp0, temp1);\n    /* z3 = x3 - (x2 << 1)                                      */\n    src_r3 = _mm_slli_epi16(temp2, 1);                          //(x2<<1)\n    src_r3 = _mm_sub_epi16(temp3, src_r3);\n\n    tmp_dc = _mm_extract_epi16(src_r0,0);                       //a0\n    *pi2_alt_dc_addr = tmp_dc;\n\n    src_r0 = _mm_unpacklo_epi64(src_r0, src_r1);                //a0 a1 a2 a3 b0 b1 b2 b3\n    src_r2 = _mm_unpacklo_epi64(src_r2, src_r3);                //c0 c1 c2 c3 d0 d1 d2 d3\n    sign_reg0 = _mm_cmpgt_epi16(zero_8x16b,src_r0);\n    sign_reg2 = _mm_cmpgt_epi16(zero_8x16b,src_r2);\n\n    sign_reg0 = _mm_mullo_epi16(temp_2,sign_reg0);\n    sign_reg2 = _mm_mullo_epi16(temp_2,sign_reg2);\n\n    sign_reg0 = _mm_add_epi16(temp_1,sign_reg0);\n    sign_reg2 = _mm_add_epi16(temp_1,sign_reg2);\n\n    src_r0 = _mm_abs_epi16(src_r0);\n    src_r2 = _mm_abs_epi16(src_r2);\n\n    src_r1 = _mm_srli_si128(src_r0, 8);\n    src_r0 = _mm_cvtepu16_epi32(src_r0);\n    src_r1 = _mm_cvtepu16_epi32(src_r1);\n    src_r3 = _mm_srli_si128(src_r2, 8);\n    src_r2 = _mm_cvtepu16_epi32(src_r2);\n    src_r3 = _mm_cvtepu16_epi32(src_r3);\n\n    temp0 = _mm_cvtepu16_epi32(scalemat_r0_r1);\n    scalemat_r0_r1 = _mm_srli_si128(scalemat_r0_r1, 8);\n    temp2 = _mm_cvtepu16_epi32(scalemat_r2_r3);\n    scalemat_r2_r3 = _mm_srli_si128(scalemat_r2_r3, 8);\n    temp1 = _mm_cvtepu16_epi32(scalemat_r0_r1);\n    temp3 = _mm_cvtepu16_epi32(scalemat_r2_r3);\n\n    temp0 = _mm_mullo_epi32(temp0, src_r0);\n    temp1 = _mm_mullo_epi32(temp1, src_r1);\n    temp2 = _mm_mullo_epi32(temp2, src_r2);\n    temp3 = _mm_mullo_epi32(temp3, src_r3);\n\n    temp0 = _mm_add_epi32(temp0,rnd_fact);\n    temp1 = _mm_add_epi32(temp1,rnd_fact);\n    temp2 = _mm_add_epi32(temp2,rnd_fact);\n    temp3 = _mm_add_epi32(temp3,rnd_fact);\n\n    temp0 = _mm_srli_epi32(temp0,u4_qbits);\n    temp1 = _mm_srli_epi32(temp1,u4_qbits);\n    temp2 = _mm_srli_epi32(temp2,u4_qbits);\n    temp3 = _mm_srli_epi32(temp3,u4_qbits);\n\n    temp0 =  _mm_packs_epi32 (temp0,temp1);\n    temp2 =  _mm_packs_epi32 (temp2,temp3);\n\n    temp0 =  _mm_sign_epi16(temp0, sign_reg0);\n    temp2 =  _mm_sign_epi16(temp2, sign_reg2);\n\n    //temp0 = _mm_insert_epi16(temp0, tmp_dc, 0);\n\n    _mm_storeu_si128((__m128i *) (&pi2_out[0]), temp0);\n    _mm_storeu_si128((__m128i *) (&pi2_out[8]), temp2);\n\n    cmp0 = _mm_cmpeq_epi16(temp0, zero_8x16b);\n    cmp1 = _mm_cmpeq_epi16(temp2, zero_8x16b);\n\n    mask0 = _mm_movemask_epi8(cmp0);\n    mask1 = _mm_movemask_epi8(cmp1);\n    u4_zero_coeff = 0;\n    if(mask0)\n    {\n        if(mask0 == 0xffff)\n            u4_zero_coeff+=8;\n        else\n        {\n            cmp0 = _mm_and_si128(temp_1, cmp0);\n            sum0 = _mm_hadd_epi16(cmp0, zero_8x16b);\n            sum1 = _mm_hadd_epi16(sum0, zero_8x16b);\n            sum2 = _mm_hadd_epi16(sum1, zero_8x16b);\n            u4_zero_coeff += _mm_cvtsi128_si32(sum2);\n        }\n    }\n    if(mask1)\n    {\n        if(mask1 == 0xffff)\n            u4_zero_coeff+=8;\n        else\n        {\n            cmp1 = _mm_and_si128(temp_1, cmp1);\n            sum0 = _mm_hadd_epi16(cmp1, zero_8x16b);\n            sum1 = _mm_hadd_epi16(sum0, zero_8x16b);\n            sum2 = _mm_hadd_epi16(sum1, zero_8x16b);\n            u4_zero_coeff += _mm_cvtsi128_si32(sum2);\n        }\n    }\n\n    /* Return total nonzero coefficients in the current sub block */\n    u4_nonzero_coeff = 16 - u4_zero_coeff;\n    *pu1_nnz =  u4_nonzero_coeff;\n\n}\n\n\n/**\n *******************************************************************************\n *\n * @brief\n *   This function performs forward hadamard transform and quantization on a 4*4 block\n *\n * @par Description:\n *   The function accepts source buffer and estimation buffer. From these, it\n *   computes the residue. This is residue is then transformed and quantized.\n *   The transform and quantization are in placed computed. They use the residue\n *   buffer for this.\n *\n * @param[in] pu1_src\n *   Pointer to source sub-block\n *\n * @param[in] pu1_pred\n *   Pointer to prediction sub-block\n *\n * @param[in] pi2_out\n *   Pointer to residual sub-block\n *\n * @param[in] src_strd\n *   Source stride\n *\n * @param[in] pred_strd\n *   Prediction stride\n *\n * @param[in] dst_strd\n *   Destination stride\n *\n * @param[in] u4_qbits\n *    QP_BITS_h264_4x4 + floor(QP/6)\n *\n * @param[in] pu2_threshold_matrix\n *   Pointer to Forward Quant Threshold Matrix\n *\n * @param[in] pu2_scale_matrix\n *   Pointer to Forward Quant Scale Matrix\n *\n * @param[in] u4_round_factor\n *   Quantization Round factor\n *\n * @param[out] pu1_nnz\n *   Total non-zero coefficients in the current sub-block\n *\n * @returns\n *\n * @remarks\n *   None\n *\n */\n\nATTRIBUTE_SSE42\nvoid ih264_hadamard_quant_4x4_sse42(WORD16 *pi2_src, WORD16 *pi2_dst,\n                          const UWORD16 *pu2_scale_matrix,\n                          const UWORD16 *pu2_threshold_matrix, UWORD32 u4_qbits,\n                          UWORD32 u4_round_factor,UWORD8  *pu1_nnz\n                          )\n{\n    WORD32 u4_zero_coeff,u4_nonzero_coeff=0;\n    __m128i cmp0, cmp1, sum0, sum1, sum2;\n    WORD32 mask0, mask1;\n    __m128i src_r0_r1, src_r2_r3, sign_reg;\n    __m128i src_r0, src_r1, src_r2, src_r3;\n    __m128i zero_8x16b = _mm_setzero_si128();\n    __m128i temp0, temp1, temp2, temp3;\n    __m128i sign_reg0, sign_reg1, sign_reg2, sign_reg3;\n    __m128i temp_1 = _mm_set1_epi16(1);\n    __m128i rnd_fact = _mm_set1_epi32(u4_round_factor);\n    __m128i scale_val = _mm_set1_epi32(pu2_scale_matrix[0]);\n\n    UNUSED (pu2_threshold_matrix);\n\n    src_r0_r1 = _mm_loadu_si128((__m128i *) (pi2_src)); //a00 a01 a02 a03 a10 a11 a12 a13 -- the source matrix 0th,1st row\n    src_r2_r3 = _mm_loadu_si128((__m128i *) (pi2_src + 8)); //a20 a21 a22 a23 a30 a31 a32 a33 -- the source matrix 2nd,3rd row\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, src_r0_r1);\n    src_r0 = _mm_unpacklo_epi16(src_r0_r1, sign_reg);   //a0 a1 a2 a3\n    src_r1 = _mm_unpackhi_epi16(src_r0_r1, sign_reg);   //b0 b1 b2 b3\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, src_r2_r3);\n    src_r2 = _mm_unpacklo_epi16(src_r2_r3, sign_reg);   //c0 c1 c2 c3\n    src_r3 = _mm_unpackhi_epi16(src_r2_r3, sign_reg);   //d0 d1 d2 d3\n\n    /* Perform Inverse transform */\n    /*-------------------------------------------------------------*/\n    /* Forward DC transform [ Horizontal transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 a1 a2 a3\n     *  b0 b1 b2 b3\n     *  c0 c1 c2 c3\n     *  d0 d1 d2 d3\n     */\n    temp0 = _mm_unpacklo_epi32(src_r0, src_r1);                  //a0 b0 a1 b1\n    temp2 = _mm_unpacklo_epi32(src_r2, src_r3);                  //c0 d0 c1 d1\n    temp1 = _mm_unpackhi_epi32(src_r0, src_r1);                  //a2 b2 a3 b3\n    temp3 = _mm_unpackhi_epi32(src_r2, src_r3);                  //c2 d2 c3 d3\n    src_r0 = _mm_unpacklo_epi64(temp0, temp2);                    //a0 b0 c0 d0\n    src_r1 = _mm_unpackhi_epi64(temp0, temp2);                    //a1 b1 c1 d1\n    src_r2 = _mm_unpacklo_epi64(temp1, temp3);                    //a2 b2 c2 d2\n    src_r3 = _mm_unpackhi_epi64(temp1, temp3);                    //a3 b3 c3 d3\n\n    temp0 = _mm_add_epi32(src_r0, src_r3);\n    temp1 = _mm_add_epi32(src_r1, src_r2);\n    temp2 = _mm_sub_epi32(src_r1, src_r2);\n    temp3 = _mm_sub_epi32(src_r0, src_r3);\n\n    src_r0 = _mm_add_epi32(temp0, temp1);\n    src_r1 = _mm_add_epi32(temp2, temp3);\n    src_r2 = _mm_sub_epi32(temp0, temp1);\n    src_r3 = _mm_sub_epi32(temp3, temp2);\n\n    /*-------------------------------------------------------------*/\n    /* Forward DC transform [ Vertical transformation ]                          */\n    /*-------------------------------------------------------------*/\n    // Matrix transpose\n    /*\n     *  a0 b0 c0 d0\n     *  a1 b1 c1 d1\n     *  a2 b2 c2 d2\n     *  a3 b3 c3 d3\n     */\n    temp0 = _mm_unpacklo_epi32(src_r0, src_r1);                  //a0 a1 b0 b1\n    temp2 = _mm_unpacklo_epi32(src_r2, src_r3);                  //a2 a3 b2 b3\n    temp1 = _mm_unpackhi_epi32(src_r0, src_r1);                  //c0 c1 d0 d1\n    temp3 = _mm_unpackhi_epi32(src_r2, src_r3);                  //c2 c3 d2 d3\n    src_r0 = _mm_unpacklo_epi64(temp0, temp2);                   //a0 a1 a2 a3\n    src_r1 = _mm_unpackhi_epi64(temp0, temp2);                   //b0 b1 b2 b3\n    src_r2 = _mm_unpacklo_epi64(temp1, temp3);                   //c0 c1 c2 c3\n    src_r3 = _mm_unpackhi_epi64(temp1, temp3);                   //d0 d1 d2 d3\n\n    temp0 = _mm_add_epi32(src_r0, src_r3);\n    temp1 = _mm_add_epi32(src_r1, src_r2);\n    temp2 = _mm_sub_epi32(src_r1, src_r2);\n    temp3 = _mm_sub_epi32(src_r0, src_r3);\n\n    src_r0 = _mm_add_epi32(temp0, temp1);\n    src_r1 = _mm_add_epi32(temp2, temp3);\n    src_r2 = _mm_sub_epi32(temp0, temp1);\n    src_r3 = _mm_sub_epi32(temp3, temp2);\n\n    src_r0 = _mm_srai_epi32(src_r0, 1);\n    src_r1 = _mm_srai_epi32(src_r1, 1);\n    src_r2 = _mm_srai_epi32(src_r2, 1);\n    src_r3 = _mm_srai_epi32(src_r3, 1);\n\n    // Quantization\n    sign_reg0 = _mm_cmpgt_epi32(zero_8x16b, src_r0);        //Find sign of each value for later restoration\n    sign_reg1 = _mm_cmpgt_epi32(zero_8x16b, src_r1);\n    sign_reg2 = _mm_cmpgt_epi32(zero_8x16b, src_r2);\n    sign_reg3 = _mm_cmpgt_epi32(zero_8x16b, src_r3);\n\n    sign_reg0 = _mm_packs_epi32(sign_reg0, sign_reg1);      //Sign = -1 or 0 depending on <0 or >0 respectively\n    sign_reg2 = _mm_packs_epi32(sign_reg2, sign_reg3);\n\n    sign_reg0 = _mm_slli_epi16(sign_reg0, 1);               //Sign = -2 or 0 depending on <0 or >0 respectively\n    sign_reg2 = _mm_slli_epi16(sign_reg2, 1);\n\n    sign_reg0 = _mm_add_epi16(temp_1,sign_reg0);            //Sign = -1 or 1 depending on <0 or >0 respectively\n    sign_reg2 = _mm_add_epi16(temp_1,sign_reg2);\n\n    src_r0 = _mm_abs_epi32(src_r0);                         //Absolute values\n    src_r1 = _mm_abs_epi32(src_r1);\n    src_r2 = _mm_abs_epi32(src_r2);\n    src_r3 = _mm_abs_epi32(src_r3);\n\n    temp0 = _mm_mullo_epi32(scale_val, src_r0);             //multiply by pu2_scale_matrix[0]\n    temp1 = _mm_mullo_epi32(scale_val, src_r1);\n    temp2 = _mm_mullo_epi32(scale_val, src_r2);\n    temp3 = _mm_mullo_epi32(scale_val, src_r3);\n\n    temp0 = _mm_add_epi32(temp0,rnd_fact);                  //Add round factor\n    temp1 = _mm_add_epi32(temp1,rnd_fact);\n    temp2 = _mm_add_epi32(temp2,rnd_fact);\n    temp3 = _mm_add_epi32(temp3,rnd_fact);\n\n    temp0 = _mm_srli_epi32(temp0,u4_qbits);                 //RIght shift by qbits, unsigned variable, so shift right immediate works\n    temp1 = _mm_srli_epi32(temp1,u4_qbits);\n    temp2 = _mm_srli_epi32(temp2,u4_qbits);\n    temp3 = _mm_srli_epi32(temp3,u4_qbits);\n\n    temp0 =  _mm_packs_epi32 (temp0,temp1);                 //Final values are 16-bits only.\n    temp2 =  _mm_packs_epi32 (temp2,temp3);\n\n    temp0 =  _mm_sign_epi16(temp0, sign_reg0);              //Sign restoration\n    temp2 =  _mm_sign_epi16(temp2, sign_reg2);\n\n    _mm_storeu_si128((__m128i *) (&pi2_dst[0]), temp0);\n    _mm_storeu_si128((__m128i *) (&pi2_dst[8]), temp2);\n\n    cmp0 = _mm_cmpeq_epi16(temp0, zero_8x16b);\n    cmp1 = _mm_cmpeq_epi16(temp2, zero_8x16b);\n\n    mask0 = _mm_movemask_epi8(cmp0);\n    mask1 = _mm_movemask_epi8(cmp1);\n    u4_zero_coeff = 0;\n    if(mask0)\n    {\n        if(mask0 == 0xffff)\n            u4_zero_coeff+=8;\n        else\n        {\n            cmp0 = _mm_and_si128(temp_1, cmp0);\n            sum0 = _mm_hadd_epi16(cmp0, zero_8x16b);\n            sum1 = _mm_hadd_epi16(sum0, zero_8x16b);\n            sum2 = _mm_hadd_epi16(sum1, zero_8x16b);\n            u4_zero_coeff += _mm_cvtsi128_si32(sum2);\n        }\n    }\n    if(mask1)\n    {\n        if(mask1 == 0xffff)\n            u4_zero_coeff+=8;\n        else\n        {\n            cmp1 = _mm_and_si128(temp_1, cmp1);\n            sum0 = _mm_hadd_epi16(cmp1, zero_8x16b);\n            sum1 = _mm_hadd_epi16(sum0, zero_8x16b);\n            sum2 = _mm_hadd_epi16(sum1, zero_8x16b);\n            u4_zero_coeff += _mm_cvtsi128_si32(sum2);\n        }\n    }\n\n    /* Return total nonzero coefficients in the current sub block */\n    u4_nonzero_coeff = 16 - u4_zero_coeff;\n    pu1_nnz[0] =  u4_nonzero_coeff;\n}\n\n\n/**\n *******************************************************************************\n *\n * @brief\n *   This function performs forward hadamard transform and quantization on a 2*2 block\n *   for both U and V planes\n *\n * @par Description:\n *   The function accepts source buffer and estimation buffer. From these, it\n *   computes the residue. This is residue is then transformed and quantized.\n *   The transform and quantization are in placed computed. They use the residue\n *   buffer for this.\n *\n * @param[in] pu1_src\n *   Pointer to source sub-block\n *\n * @param[in] pu1_pred\n *   Pointer to prediction sub-block\n *\n * @param[in] pi2_out\n *   Pointer to residual sub-block\n *\n * @param[in] src_strd\n *   Source stride\n *\n * @param[in] pred_strd\n *   Prediction stride\n *\n * @param[in] dst_strd\n *   Destination stride\n *\n * @param[in] u4_qbits\n *    QP_BITS_h264_4x4 + floor(QP/6)\n *\n * @param[in] pu2_threshold_matrix\n *   Pointer to Forward Quant Threshold Matrix\n *\n * @param[in] pu2_scale_matrix\n *   Pointer to Forward Quant Scale Matrix\n *\n * @param[in] u4_round_factor\n *   Quantization Round factor\n *\n * @param[out] pu1_nnz\n *   Total non-zero coefficients in the current sub-block\n *\n * @returns\n *\n * @remarks\n *   NNZ for dc is populated at 0 and 5th position of pu1_nnz\n *\n */\n\nATTRIBUTE_SSE42\nvoid ih264_hadamard_quant_2x2_uv_sse42(WORD16 *pi2_src, WORD16 *pi2_dst,\n                            const UWORD16 *pu2_scale_matrix,\n                            const UWORD16 *pu2_threshold_matrix, UWORD32 u4_qbits,\n                            UWORD32 u4_round_factor,UWORD8  *pu1_nnz)\n{\n    WORD32 val, nonzero_coeff_0=0, nonzero_coeff_1=0;\n    __m128i cmp, cmp0, cmp1;\n    __m128i sum0, sum1;\n    WORD32 mask, mask0, mask1;\n    __m128i src, plane_0, plane_1, temp0, temp1, sign_reg;\n    __m128i zero_8x16b = _mm_setzero_si128();\n    __m128i scale_val = _mm_set1_epi32(pu2_scale_matrix[0]);\n    __m128i sign_reg0, sign_reg1;\n    __m128i temp_1 = _mm_set1_epi16(1);\n    __m128i rnd_fact = _mm_set1_epi32(u4_round_factor);\n\n    UNUSED (pu2_threshold_matrix);\n\n    src = _mm_loadu_si128((__m128i *)pi2_src);          //a0 a1 a2 a3 b0 b1 b2 b3\n    sign_reg = _mm_cmpgt_epi16(zero_8x16b, src);\n    plane_0 = _mm_unpacklo_epi16(src, sign_reg);        //a0 a1 a2 a3 -- 32 bits\n    plane_1 = _mm_unpackhi_epi16(src, sign_reg);        //b0 b1 b2 b3 -- 32 bits\n\n    temp0 = _mm_hadd_epi32(plane_0, plane_1);           //a0+a1 a2+a3 b0+b1 b2+b3\n    temp1 = _mm_hsub_epi32(plane_0, plane_1);           //a0-a1 a2-a3 b0-b1 b2-b3\n\n    plane_0 = _mm_hadd_epi32(temp0, temp1);             //a0+a1+a2+a3 b0+b1+b2+b3 a0-a1+a2-a3 b0-b1+b2-b3\n    plane_1 = _mm_hsub_epi32(temp0, temp1);             //a0+a1-a2-a3 b0+b1-b2-b3 a0-a1-a2+a3 b0-b1-b2+b3\n\n    temp0 = _mm_unpacklo_epi32(plane_0, plane_1);       //a0+a1+a2+a3 a0+a1-a2-a3 b0+b1+b2+b3 b0+b1-b2-b3\n    temp1 = _mm_unpackhi_epi32(plane_0, plane_1);       //a0-a1+a2-a3 a0-a1-a2+a3 b0-b1+b2-b3 b0-b1-b2+b3\n\n    plane_0 = _mm_unpacklo_epi64(temp0, temp1);         //a0+a1+a2+a3 a0+a1-a2-a3 a0-a1+a2-a3 a0-a1-a2+a3\n    plane_1 = _mm_unpackhi_epi64(temp0, temp1);         //b0+b1+b2+b3 b0+b1-b2-b3 b0-b1+b2-b3 b0-b1-b2+b3\n\n    plane_0 = _mm_shuffle_epi32(plane_0, 0xd8);         //a0+a1+a2+a3 a0-a1+a2-a3 a0+a1-a2-a3 a0-a1-a2+a3\n    plane_1 = _mm_shuffle_epi32(plane_1, 0xd8);         //b0+b1+b2+b3 b0-b1+b2-b3 b0+b1-b2-b3 b0-b1-b2+b3\n    // Quantization\n    sign_reg0 = _mm_cmpgt_epi32(zero_8x16b, plane_0);       //Find sign of each value for later restoration\n    sign_reg1 = _mm_cmpgt_epi32(zero_8x16b, plane_1);\n\n    sign_reg0 = _mm_packs_epi32(sign_reg0, sign_reg1);      //Sign = -1 or 0 depending on <0 or >0 respectively\n    sign_reg0 = _mm_slli_epi16(sign_reg0, 1);               //Sign = -2 or 0 depending on <0 or >0 respectively\n    sign_reg0 = _mm_add_epi16(temp_1,sign_reg0);            //Sign = -1 or 1 depending on <0 or >0 respectively\n\n    plane_0 = _mm_abs_epi32(plane_0);                           //Absolute values\n    plane_1 = _mm_abs_epi32(plane_1);\n\n    temp0 = _mm_mullo_epi32(scale_val, plane_0);                //multiply by pu2_scale_matrix[0]\n    temp1 = _mm_mullo_epi32(scale_val, plane_1);                //multiply by pu2_scale_matrix[0]\n\n    temp0 = _mm_add_epi32(temp0,rnd_fact);                  //Add round factor\n    temp1 = _mm_add_epi32(temp1,rnd_fact);\n\n    temp0 = _mm_srli_epi32(temp0,u4_qbits);                 //RIght shift by qbits, unsigned variable, so shift right immediate works\n    temp1 = _mm_srli_epi32(temp1,u4_qbits);\n\n    temp0 =  _mm_packs_epi32 (temp0,temp1);                 //Final values are 16-bits only.\n    temp0 =  _mm_sign_epi16(temp0, sign_reg0);              //Sign restoration\n\n    _mm_storeu_si128((__m128i *) (&pi2_dst[0]), temp0);\n\n    cmp = _mm_cmpeq_epi16(temp0, zero_8x16b);\n    mask = _mm_movemask_epi8(cmp);\n    mask0 = mask & 0xff;\n    mask1 = mask>>8;\n    if(mask0)\n    {\n        if(mask0 == 0xff)\n            nonzero_coeff_0 += 4;\n        else\n        {\n            cmp0 = _mm_and_si128(temp_1, cmp);\n            sum0 = _mm_hadd_epi16(cmp0, zero_8x16b);\n            sum1 = _mm_hadd_epi16(sum0, zero_8x16b);\n            val = _mm_cvtsi128_si32(sum1);\n            val = val & 0xffff;\n            nonzero_coeff_0 += val;\n        }\n    }\n    if(mask1)\n    {\n        if(mask1 == 0xff)\n            nonzero_coeff_1 += 4;\n        else\n        {\n            cmp1 = _mm_srli_si128(cmp, 8);\n            cmp1 = _mm_and_si128(temp_1, cmp1);\n            sum0 = _mm_hadd_epi16(cmp1, zero_8x16b);\n            sum1 = _mm_hadd_epi16(sum0, zero_8x16b);\n            nonzero_coeff_1 += _mm_cvtsi128_si32(sum1);\n        }\n    }\n\n    pu1_nnz[0] = 4 - nonzero_coeff_0;\n    pu1_nnz[1] = 4 - nonzero_coeff_1;\n\n}\n"
  },
  {
    "path": "dependencies/ih264d/common/x86/ih264_weighted_pred_sse42.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264_weighted_pred_intr_sse42.c                     */\n/*                                                                           */\n/*  Description       : Contains function definitions for weighted           */\n/*                      prediction functions in x86 sse4 intrinsics          */\n/*                                                                           */\n/*  List of Functions : ih264_default_weighted_pred_luma_sse42()             */\n/*                      ih264_default_weighted_pred_chroma_sse42()           */\n/*                      ih264_weighted_pred_luma_sse42()                     */\n/*                      ih264_weighted_pred_chroma_sse42()                   */\n/*                      ih264_weighted_bipred_luma_sse42()                   */\n/*                      ih264_weighted_bipred_chroma_sse42()                 */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         30 01 2015   Kaushik         Initial version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n#include <immintrin.h>\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_weighted_pred.h\"\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSE42 __attribute__((target(\"sse4.2\")))\n#else\n#define ATTRIBUTE_SSE42\n#endif\n\n/*****************************************************************************/\n/*  Function definitions .                                                   */\n/*****************************************************************************/\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_default_weighted_pred_luma_sse42                   */\n/*                                                                           */\n/*  Description   : This function performs the default weighted prediction   */\n/*                  as described in sec 8.4.2.3.1 titled \"Default weighted   */\n/*                  sample prediction process\" for luma. The function gets   */\n/*                  two ht x wd blocks, calculates their rounded-average and */\n/*                  stores it in the destination block. (ht,wd) can be       */\n/*                  (4,4), (8,4), (4,8), (8,8), (16,8), (8,16) or (16,16).   */\n/*                                                                           */\n/*  Inputs        : pu1_src1  - Pointer to source 1                          */\n/*                  pu1_src2  - Pointer to source 2                          */\n/*                  pu1_dst   - Pointer to destination                       */\n/*                  src_strd1 - stride for source 1                          */\n/*                  src_strd1 - stride for source 2                          */\n/*                  dst_strd  - stride for destination                       */\n/*                  ht        - height of the block                          */\n/*                  wd        - width of the block                           */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         04 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSE42\nvoid ih264_default_weighted_pred_luma_sse42(UWORD8 *pu1_src1,\n                                            UWORD8 *pu1_src2,\n                                            UWORD8 *pu1_dst,\n                                            WORD32 src_strd1,\n                                            WORD32 src_strd2,\n                                            WORD32 dst_strd,\n                                            WORD32 ht,\n                                            WORD32 wd)\n{\n    __m128i y0_0_16x8b, y0_1_16x8b, y0_2_16x8b, y0_3_16x8b;\n    __m128i y1_0_16x8b, y1_1_16x8b, y1_2_16x8b, y1_3_16x8b;\n\n    if(wd == 4)\n    {\n        do\n        {\n            y0_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src1);\n            y0_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1));\n            y0_2_16x8b = _mm_loadl_epi64(\n                            (__m128i *)(pu1_src1 + (src_strd1 << 1)));\n            y0_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1 * 3));\n\n            y1_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src2);\n            y1_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2));\n            y1_2_16x8b = _mm_loadl_epi64(\n                            (__m128i *)(pu1_src2 + (src_strd2 << 1)));\n            y1_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2 * 3));\n\n            y0_0_16x8b = _mm_avg_epu8(y0_0_16x8b, y1_0_16x8b);\n            y0_1_16x8b = _mm_avg_epu8(y0_1_16x8b, y1_1_16x8b);\n            y0_2_16x8b = _mm_avg_epu8(y0_2_16x8b, y1_2_16x8b);\n            y0_3_16x8b = _mm_avg_epu8(y0_3_16x8b, y1_3_16x8b);\n\n            *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(y0_0_16x8b);\n            *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(y0_1_16x8b);\n            *((WORD32 *)(pu1_dst + (dst_strd << 1))) = _mm_cvtsi128_si32(y0_2_16x8b);\n            *((WORD32 *)(pu1_dst + dst_strd * 3)) = _mm_cvtsi128_si32(y0_3_16x8b);\n\n            ht -= 4;\n            pu1_src1 += src_strd1 << 2;\n            pu1_src2 += src_strd2 << 2;\n            pu1_dst += dst_strd << 2;\n        }\n        while(ht > 0);\n    }\n    else if(wd == 8)\n    {\n        do\n        {\n            y0_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src1);\n            y0_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1));\n            y0_2_16x8b = _mm_loadl_epi64(\n                            (__m128i *)(pu1_src1 + (src_strd1 << 1)));\n            y0_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1 * 3));\n\n            y1_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src2);\n            y1_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2));\n            y1_2_16x8b = _mm_loadl_epi64(\n                            (__m128i *)(pu1_src2 + (src_strd2 << 1)));\n            y1_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2 * 3));\n\n            y0_0_16x8b = _mm_avg_epu8(y0_0_16x8b, y1_0_16x8b);\n            y0_1_16x8b = _mm_avg_epu8(y0_1_16x8b, y1_1_16x8b);\n            y0_2_16x8b = _mm_avg_epu8(y0_2_16x8b, y1_2_16x8b);\n            y0_3_16x8b = _mm_avg_epu8(y0_3_16x8b, y1_3_16x8b);\n\n            _mm_storel_epi64((__m128i *)pu1_dst, y0_0_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), y0_1_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + (dst_strd << 1)), y0_2_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd * 3), y0_3_16x8b);\n\n            ht -= 4;\n            pu1_src1 += src_strd1 << 2;\n            pu1_src2 += src_strd2 << 2;\n            pu1_dst += dst_strd << 2;\n        }\n        while(ht > 0);\n    }\n    else // wd == 16\n    {\n        __m128i y0_4_16x8b, y0_5_16x8b, y0_6_16x8b, y0_7_16x8b;\n        __m128i y1_4_16x8b, y1_5_16x8b, y1_6_16x8b, y1_7_16x8b;\n\n        do\n        {\n            y0_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src1);\n            y0_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src1 + src_strd1));\n            y0_2_16x8b = _mm_loadu_si128(\n                            (__m128i *)(pu1_src1 + (src_strd1 << 1)));\n            y0_3_16x8b = _mm_loadu_si128((__m128i *)(pu1_src1 + src_strd1 * 3));\n            y0_4_16x8b = _mm_loadu_si128(\n                            (__m128i *)(pu1_src1 + (src_strd1 << 2)));\n            y0_5_16x8b = _mm_loadu_si128((__m128i *)(pu1_src1 + src_strd1 * 5));\n            y0_6_16x8b = _mm_loadu_si128((__m128i *)(pu1_src1 + src_strd1 * 6));\n            y0_7_16x8b = _mm_loadu_si128((__m128i *)(pu1_src1 + src_strd1 * 7));\n\n            y1_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src2);\n            y1_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src2 + src_strd2));\n            y1_2_16x8b = _mm_loadu_si128(\n                            (__m128i *)(pu1_src2 + (src_strd2 << 1)));\n            y1_3_16x8b = _mm_loadu_si128((__m128i *)(pu1_src2 + src_strd2 * 3));\n            y1_4_16x8b = _mm_loadu_si128(\n                            (__m128i *)(pu1_src2 + (src_strd2 << 2)));\n            y1_5_16x8b = _mm_loadu_si128((__m128i *)(pu1_src2 + src_strd2 * 5));\n            y1_6_16x8b = _mm_loadu_si128((__m128i *)(pu1_src2 + src_strd2 * 6));\n            y1_7_16x8b = _mm_loadu_si128((__m128i *)(pu1_src2 + src_strd2 * 7));\n\n            y0_0_16x8b = _mm_avg_epu8(y0_0_16x8b, y1_0_16x8b);\n            y0_1_16x8b = _mm_avg_epu8(y0_1_16x8b, y1_1_16x8b);\n            y0_2_16x8b = _mm_avg_epu8(y0_2_16x8b, y1_2_16x8b);\n            y0_3_16x8b = _mm_avg_epu8(y0_3_16x8b, y1_3_16x8b);\n            y0_4_16x8b = _mm_avg_epu8(y0_4_16x8b, y1_4_16x8b);\n            y0_5_16x8b = _mm_avg_epu8(y0_5_16x8b, y1_5_16x8b);\n            y0_6_16x8b = _mm_avg_epu8(y0_6_16x8b, y1_6_16x8b);\n            y0_7_16x8b = _mm_avg_epu8(y0_7_16x8b, y1_7_16x8b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, y0_0_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), y0_1_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + (dst_strd << 1)), y0_2_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd * 3), y0_3_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + (dst_strd << 2)), y0_4_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd * 5), y0_5_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd * 6), y0_6_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd * 7), y0_7_16x8b);\n\n            ht -= 8;\n            pu1_src1 += src_strd1 << 3;\n            pu1_src2 += src_strd2 << 3;\n            pu1_dst += dst_strd << 3;\n        }\n        while(ht > 0);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_default_weighted_pred_chroma_sse42                 */\n/*                                                                           */\n/*  Description   : This function performs the default weighted prediction   */\n/*                  as described in sec 8.4.2.3.1 titled \"Default weighted   */\n/*                  sample prediction process\" for chroma. The function gets */\n/*                  two ht x wd blocks, calculates their rounded-average and */\n/*                  stores it in the destination block. (ht,wd) can be       */\n/*                  (2,2), (4,2) , (2,4), (4,4), (8,4), (4,8) or (8,8).      */\n/*                                                                           */\n/*  Inputs        : pu1_src1  - Pointer to source 1                          */\n/*                  pu1_src2  - Pointer to source 2                          */\n/*                  pu1_dst   - Pointer to destination                       */\n/*                  src_strd1 - stride for source 1                          */\n/*                  src_strd1 - stride for source 2                          */\n/*                  dst_strd  - stride for destination                       */\n/*                  ht        - height of the block                          */\n/*                  wd        - width of the block                           */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         04 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSE42\nvoid ih264_default_weighted_pred_chroma_sse42(UWORD8 *pu1_src1,\n                                              UWORD8 *pu1_src2,\n                                              UWORD8 *pu1_dst,\n                                              WORD32 src_strd1,\n                                              WORD32 src_strd2,\n                                              WORD32 dst_strd,\n                                              WORD32 ht,\n                                              WORD32 wd)\n{\n    __m128i uv0_0_16x8b, uv0_1_16x8b;\n    __m128i uv1_0_16x8b, uv1_1_16x8b;\n\n    if(wd == 2)\n    {\n        do\n        {\n            uv0_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src1);\n            uv0_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1));\n\n            uv1_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src2);\n            uv1_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2));\n\n            uv0_0_16x8b = _mm_avg_epu8(uv0_0_16x8b, uv1_0_16x8b);\n            uv0_1_16x8b = _mm_avg_epu8(uv0_1_16x8b, uv1_1_16x8b);\n\n            *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(uv0_0_16x8b);\n            *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(uv0_1_16x8b);\n\n            ht -= 2;\n            pu1_src1 += src_strd1 << 1;\n            pu1_src2 += src_strd2 << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else if(wd == 4)\n    {\n        do\n        {\n            uv0_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src1);\n            uv0_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1));\n\n            uv1_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src2);\n            uv1_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2));\n\n            uv0_0_16x8b = _mm_avg_epu8(uv0_0_16x8b, uv1_0_16x8b);\n            uv0_1_16x8b = _mm_avg_epu8(uv0_1_16x8b, uv1_1_16x8b);\n\n            _mm_storel_epi64((__m128i *)pu1_dst, uv0_0_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), uv0_1_16x8b);\n\n            ht -= 2;\n            pu1_src1 += src_strd1 << 1;\n            pu1_src2 += src_strd2 << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else // wd == 8\n    {\n        __m128i uv0_2_16x8b, uv0_3_16x8b;\n        __m128i uv1_2_16x8b, uv1_3_16x8b;\n\n        do\n        {\n            uv0_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src1);\n            uv0_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src1 + src_strd1));\n            uv0_2_16x8b = _mm_loadu_si128(\n                            (__m128i *)(pu1_src1 + (src_strd1 << 1)));\n            uv0_3_16x8b = _mm_loadu_si128(\n                            (__m128i *)(pu1_src1 + src_strd1 * 3));\n\n            uv1_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src2);\n            uv1_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src2 + src_strd2));\n            uv1_2_16x8b = _mm_loadu_si128(\n                            (__m128i *)(pu1_src2 + (src_strd2 << 1)));\n            uv1_3_16x8b = _mm_loadu_si128(\n                            (__m128i *)(pu1_src2 + src_strd2 * 3));\n\n            uv0_0_16x8b = _mm_avg_epu8(uv0_0_16x8b, uv1_0_16x8b);\n            uv0_1_16x8b = _mm_avg_epu8(uv0_1_16x8b, uv1_1_16x8b);\n            uv0_2_16x8b = _mm_avg_epu8(uv0_2_16x8b, uv1_2_16x8b);\n            uv0_3_16x8b = _mm_avg_epu8(uv0_3_16x8b, uv1_3_16x8b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, uv0_0_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), uv0_1_16x8b);\n            _mm_storeu_si128(\n                            (__m128i *)(pu1_dst + (dst_strd << 1)), uv0_2_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd * 3), uv0_3_16x8b);\n\n            ht -= 4;\n            pu1_src1 += src_strd1 << 2;\n            pu1_src2 += src_strd2 << 2;\n            pu1_dst += dst_strd << 2;\n        }\n        while(ht > 0);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_weighted_pred_luma_sse42                           */\n/*                                                                           */\n/*  Description   : This function performs the weighted prediction as        */\n/*                  described in sec 8.4.2.3.2 titled \"Weighted sample       */\n/*                  prediction process\" for luma. The function gets one      */\n/*                  ht x wd block, weights it, rounds it off, offsets it,    */\n/*                  saturates it to unsigned 8-bit and stores it in the      */\n/*                  destination block. (ht,wd) can be (4,4), (8,4), (4,8),   */\n/*                  (8,8), (16,8), (8,16) or (16,16).                        */\n/*                                                                           */\n/*  Inputs        : pu1_src  - Pointer to source                             */\n/*                  pu1_dst  - Pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  log_wd   - number of bits to be rounded off              */\n/*                  wt       - weight value                                  */\n/*                  ofst     - offset value                                  */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         04 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSE42\nvoid ih264_weighted_pred_luma_sse42(UWORD8 *pu1_src,\n                                    UWORD8 *pu1_dst,\n                                    WORD32 src_strd,\n                                    WORD32 dst_strd,\n                                    WORD32 log_wd,\n                                    WORD32 wt,\n                                    WORD32 ofst,\n                                    WORD32 ht,\n                                    WORD32 wd)\n{\n    __m128i y_0_16x8b, y_1_16x8b, y_2_16x8b, y_3_16x8b;\n\n    __m128i wt_8x16b, round_8x16b, ofst_8x16b;\n\n    WORD32 round_val;\n\n    wt = (WORD16)(wt & 0xffff);\n    round_val = 1 << (log_wd - 1);\n    ofst = (WORD8)(ofst & 0xff);\n\n    wt_8x16b = _mm_set1_epi16(wt);\n    round_8x16b = _mm_set1_epi16(round_val);\n    ofst_8x16b = _mm_set1_epi16(ofst);\n\n    if(wd == 4)\n    {\n        __m128i y_0_8x16b, y_2_8x16b;\n\n        do\n        {\n            y_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n            y_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd));\n            y_2_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + (src_strd << 1)));\n            y_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd * 3));\n\n            y_0_16x8b = _mm_unpacklo_epi32(y_0_16x8b, y_1_16x8b);\n            y_2_16x8b = _mm_unpacklo_epi32(y_2_16x8b, y_3_16x8b);\n\n            y_0_8x16b = _mm_cvtepu8_epi16(y_0_16x8b);\n            y_2_8x16b = _mm_cvtepu8_epi16(y_2_16x8b);\n\n            y_0_8x16b = _mm_mullo_epi16(y_0_8x16b, wt_8x16b);\n            y_2_8x16b = _mm_mullo_epi16(y_2_8x16b, wt_8x16b);\n\n            y_0_8x16b = _mm_adds_epi16(round_8x16b, y_0_8x16b);\n            y_2_8x16b = _mm_adds_epi16(round_8x16b, y_2_8x16b);\n\n            y_0_8x16b = _mm_srai_epi16(y_0_8x16b, log_wd);\n            y_2_8x16b = _mm_srai_epi16(y_2_8x16b, log_wd);\n\n            y_0_8x16b = _mm_adds_epi16(ofst_8x16b, y_0_8x16b);\n            y_2_8x16b = _mm_adds_epi16(ofst_8x16b, y_2_8x16b);\n\n            y_0_16x8b = _mm_packus_epi16(y_0_8x16b, y_2_8x16b);\n            y_1_16x8b = _mm_srli_si128(y_0_16x8b, 4);\n            y_2_16x8b = _mm_srli_si128(y_0_16x8b, 8);\n            y_3_16x8b = _mm_srli_si128(y_0_16x8b, 12);\n\n            *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(y_0_16x8b);\n            *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(y_1_16x8b);\n            *((WORD32 *)(pu1_dst + (dst_strd << 1))) = _mm_cvtsi128_si32(y_2_16x8b);\n            *((WORD32 *)(pu1_dst + dst_strd * 3)) = _mm_cvtsi128_si32(y_3_16x8b);\n\n            ht -= 4;\n            pu1_src += src_strd << 2;\n            pu1_dst += dst_strd << 2;\n        }\n        while(ht > 0);\n    }\n    else if(wd == 8)\n    {\n        __m128i y_0_8x16b, y_1_8x16b, y_2_8x16b, y_3_8x16b;\n\n        do\n        {\n            y_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n            y_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd));\n            y_2_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + (src_strd << 1)));\n            y_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd * 3));\n\n            y_0_8x16b = _mm_cvtepu8_epi16(y_0_16x8b);\n            y_1_8x16b = _mm_cvtepu8_epi16(y_1_16x8b);\n            y_2_8x16b = _mm_cvtepu8_epi16(y_2_16x8b);\n            y_3_8x16b = _mm_cvtepu8_epi16(y_3_16x8b);\n\n            y_0_8x16b = _mm_mullo_epi16(y_0_8x16b, wt_8x16b);\n            y_1_8x16b = _mm_mullo_epi16(y_1_8x16b, wt_8x16b);\n            y_2_8x16b = _mm_mullo_epi16(y_2_8x16b, wt_8x16b);\n            y_3_8x16b = _mm_mullo_epi16(y_3_8x16b, wt_8x16b);\n\n            y_0_8x16b = _mm_adds_epi16(round_8x16b, y_0_8x16b);\n            y_1_8x16b = _mm_adds_epi16(round_8x16b, y_1_8x16b);\n            y_2_8x16b = _mm_adds_epi16(round_8x16b, y_2_8x16b);\n            y_3_8x16b = _mm_adds_epi16(round_8x16b, y_3_8x16b);\n\n            y_0_8x16b = _mm_srai_epi16(y_0_8x16b, log_wd);\n            y_1_8x16b = _mm_srai_epi16(y_1_8x16b, log_wd);\n            y_2_8x16b = _mm_srai_epi16(y_2_8x16b, log_wd);\n            y_3_8x16b = _mm_srai_epi16(y_3_8x16b, log_wd);\n\n            y_0_8x16b = _mm_adds_epi16(ofst_8x16b, y_0_8x16b);\n            y_1_8x16b = _mm_adds_epi16(ofst_8x16b, y_1_8x16b);\n            y_2_8x16b = _mm_adds_epi16(ofst_8x16b, y_2_8x16b);\n            y_3_8x16b = _mm_adds_epi16(ofst_8x16b, y_3_8x16b);\n\n            y_0_16x8b = _mm_packus_epi16(y_0_8x16b, y_1_8x16b);\n            y_2_16x8b = _mm_packus_epi16(y_2_8x16b, y_3_8x16b);\n            y_1_16x8b = _mm_srli_si128(y_0_16x8b, 8);\n            y_3_16x8b = _mm_srli_si128(y_2_16x8b, 8);\n\n            _mm_storel_epi64((__m128i *)pu1_dst, y_0_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), y_1_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + (dst_strd << 1)), y_2_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd * 3), y_3_16x8b);\n\n            ht -= 4;\n            pu1_src += src_strd << 2;\n            pu1_dst += dst_strd << 2;\n        }\n        while(ht > 0);\n    }\n    else // wd == 16\n    {\n        __m128i y_0L_8x16b, y_1L_8x16b, y_2L_8x16b, y_3L_8x16b;\n        __m128i y_0H_8x16b, y_1H_8x16b, y_2H_8x16b, y_3H_8x16b;\n\n        __m128i zero_16x8b;\n        zero_16x8b = _mm_set1_epi8(0);\n\n        do\n        {\n            y_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n            y_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));\n            y_2_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + (src_strd << 1)));\n            y_3_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd * 3));\n\n            y_0L_8x16b = _mm_cvtepu8_epi16(y_0_16x8b);\n            y_0H_8x16b = _mm_unpackhi_epi8(y_0_16x8b, zero_16x8b);\n            y_1L_8x16b = _mm_cvtepu8_epi16(y_1_16x8b);\n            y_1H_8x16b = _mm_unpackhi_epi8(y_1_16x8b, zero_16x8b);\n            y_2L_8x16b = _mm_cvtepu8_epi16(y_2_16x8b);\n            y_2H_8x16b = _mm_unpackhi_epi8(y_2_16x8b, zero_16x8b);\n            y_3L_8x16b = _mm_cvtepu8_epi16(y_3_16x8b);\n            y_3H_8x16b = _mm_unpackhi_epi8(y_3_16x8b, zero_16x8b);\n\n            y_0L_8x16b = _mm_mullo_epi16(y_0L_8x16b, wt_8x16b);\n            y_0H_8x16b = _mm_mullo_epi16(y_0H_8x16b, wt_8x16b);\n            y_1L_8x16b = _mm_mullo_epi16(y_1L_8x16b, wt_8x16b);\n            y_1H_8x16b = _mm_mullo_epi16(y_1H_8x16b, wt_8x16b);\n            y_2L_8x16b = _mm_mullo_epi16(y_2L_8x16b, wt_8x16b);\n            y_2H_8x16b = _mm_mullo_epi16(y_2H_8x16b, wt_8x16b);\n            y_3L_8x16b = _mm_mullo_epi16(y_3L_8x16b, wt_8x16b);\n            y_3H_8x16b = _mm_mullo_epi16(y_3H_8x16b, wt_8x16b);\n\n            y_0L_8x16b = _mm_adds_epi16(round_8x16b, y_0L_8x16b);\n            y_0H_8x16b = _mm_adds_epi16(round_8x16b, y_0H_8x16b);\n            y_1L_8x16b = _mm_adds_epi16(round_8x16b, y_1L_8x16b);\n            y_1H_8x16b = _mm_adds_epi16(round_8x16b, y_1H_8x16b);\n            y_2L_8x16b = _mm_adds_epi16(round_8x16b, y_2L_8x16b);\n            y_2H_8x16b = _mm_adds_epi16(round_8x16b, y_2H_8x16b);\n            y_3L_8x16b = _mm_adds_epi16(round_8x16b, y_3L_8x16b);\n            y_3H_8x16b = _mm_adds_epi16(round_8x16b, y_3H_8x16b);\n\n            y_0L_8x16b = _mm_srai_epi16(y_0L_8x16b, log_wd);\n            y_0H_8x16b = _mm_srai_epi16(y_0H_8x16b, log_wd);\n            y_1L_8x16b = _mm_srai_epi16(y_1L_8x16b, log_wd);\n            y_1H_8x16b = _mm_srai_epi16(y_1H_8x16b, log_wd);\n            y_2L_8x16b = _mm_srai_epi16(y_2L_8x16b, log_wd);\n            y_2H_8x16b = _mm_srai_epi16(y_2H_8x16b, log_wd);\n            y_3L_8x16b = _mm_srai_epi16(y_3L_8x16b, log_wd);\n            y_3H_8x16b = _mm_srai_epi16(y_3H_8x16b, log_wd);\n\n            y_0L_8x16b = _mm_adds_epi16(ofst_8x16b, y_0L_8x16b);\n            y_0H_8x16b = _mm_adds_epi16(ofst_8x16b, y_0H_8x16b);\n            y_1L_8x16b = _mm_adds_epi16(ofst_8x16b, y_1L_8x16b);\n            y_1H_8x16b = _mm_adds_epi16(ofst_8x16b, y_1H_8x16b);\n            y_2L_8x16b = _mm_adds_epi16(ofst_8x16b, y_2L_8x16b);\n            y_2H_8x16b = _mm_adds_epi16(ofst_8x16b, y_2H_8x16b);\n            y_3L_8x16b = _mm_adds_epi16(ofst_8x16b, y_3L_8x16b);\n            y_3H_8x16b = _mm_adds_epi16(ofst_8x16b, y_3H_8x16b);\n\n            y_0_16x8b = _mm_packus_epi16(y_0L_8x16b, y_0H_8x16b);\n            y_1_16x8b = _mm_packus_epi16(y_1L_8x16b, y_1H_8x16b);\n            y_2_16x8b = _mm_packus_epi16(y_2L_8x16b, y_2H_8x16b);\n            y_3_16x8b = _mm_packus_epi16(y_3L_8x16b, y_3H_8x16b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, y_0_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), y_1_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + (dst_strd << 1)), y_2_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd * 3), y_3_16x8b);\n\n            ht -= 4;\n            pu1_src += src_strd << 2;\n            pu1_dst += dst_strd << 2;\n        }\n        while(ht > 0);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_weighted_pred_chroma_sse42                         */\n/*                                                                           */\n/*  Description   : This function performs the weighted prediction as        */\n/*                  described in sec 8.4.2.3.2 titled \"Weighted sample       */\n/*                  prediction process\" for chroma. The function gets one    */\n/*                  ht x wd block, weights it, rounds it off, offsets it,    */\n/*                  saturates it to unsigned 8-bit and stores it in the      */\n/*                  destination block. (ht,wd) can be (2,2), (4,2), (2,4),   */\n/*                  (4,4), (8,4), (4,8) or (8,8).                            */\n/*                                                                           */\n/*  Inputs        : pu1_src  - Pointer to source                             */\n/*                  pu1_dst  - Pointer to destination                        */\n/*                  src_strd - stride for source                             */\n/*                  dst_strd - stride for destination                        */\n/*                  log_wd   - number of bits to be rounded off              */\n/*                  wt       - weight values for u and v                     */\n/*                  ofst     - offset values for u and v                     */\n/*                  ht       - height of the block                           */\n/*                  wd       - width of the block                            */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         04 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSE42\nvoid ih264_weighted_pred_chroma_sse42(UWORD8 *pu1_src,\n                                      UWORD8 *pu1_dst,\n                                      WORD32 src_strd,\n                                      WORD32 dst_strd,\n                                      WORD32 log_wd,\n                                      WORD32 wt,\n                                      WORD32 ofst,\n                                      WORD32 ht,\n                                      WORD32 wd)\n{\n    __m128i y_0_16x8b, y_1_16x8b;\n\n    __m128i wt_8x16b, round_8x16b, ofst_8x16b;\n\n    WORD32 ofst_u, ofst_v;\n    WORD32 round_val;\n\n    ofst_u = (WORD8)(ofst & 0xff);\n    ofst_v = (WORD8)(ofst >> 8);\n    round_val = 1 << (log_wd - 1);\n    ofst = (ofst_u & 0xffff) | (ofst_v << 16);\n\n    wt_8x16b = _mm_set1_epi32(wt);\n    round_8x16b = _mm_set1_epi16(round_val);\n    ofst_8x16b = _mm_set1_epi32(ofst);\n\n    if(wd == 2)\n    {\n        __m128i y_0_8x16b;\n\n        do\n        {\n            y_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n            y_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd));\n\n            y_0_16x8b = _mm_unpacklo_epi32(y_0_16x8b, y_1_16x8b);\n\n            y_0_8x16b = _mm_cvtepu8_epi16(y_0_16x8b);\n\n            y_0_8x16b = _mm_mullo_epi16(y_0_8x16b, wt_8x16b);\n\n            y_0_8x16b = _mm_adds_epi16(round_8x16b, y_0_8x16b);\n\n            y_0_8x16b = _mm_srai_epi16(y_0_8x16b, log_wd);\n\n            y_0_8x16b = _mm_adds_epi16(ofst_8x16b, y_0_8x16b);\n\n            y_0_16x8b = _mm_packus_epi16(y_0_8x16b, y_0_8x16b);\n            y_1_16x8b = _mm_srli_si128(y_0_16x8b, 4);\n\n            *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(y_0_16x8b);\n            *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(y_1_16x8b);\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else if(wd == 4)\n    {\n        __m128i y_0_8x16b, y_1_8x16b;\n\n        do\n        {\n            y_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src);\n            y_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src + src_strd));\n\n            y_0_8x16b = _mm_cvtepu8_epi16(y_0_16x8b);\n            y_1_8x16b = _mm_cvtepu8_epi16(y_1_16x8b);\n\n            y_0_8x16b = _mm_mullo_epi16(y_0_8x16b, wt_8x16b);\n            y_1_8x16b = _mm_mullo_epi16(y_1_8x16b, wt_8x16b);\n\n            y_0_8x16b = _mm_adds_epi16(round_8x16b, y_0_8x16b);\n            y_1_8x16b = _mm_adds_epi16(round_8x16b, y_1_8x16b);\n\n            y_0_8x16b = _mm_srai_epi16(y_0_8x16b, log_wd);\n            y_1_8x16b = _mm_srai_epi16(y_1_8x16b, log_wd);\n\n            y_0_8x16b = _mm_adds_epi16(ofst_8x16b, y_0_8x16b);\n            y_1_8x16b = _mm_adds_epi16(ofst_8x16b, y_1_8x16b);\n\n            y_0_16x8b = _mm_packus_epi16(y_0_8x16b, y_1_8x16b);\n            y_1_16x8b = _mm_srli_si128(y_0_16x8b, 8);\n\n            _mm_storel_epi64((__m128i *)pu1_dst, y_0_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), y_1_16x8b);\n\n            ht -= 2;\n            pu1_src += src_strd << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else // wd == 16\n    {\n        __m128i y_2_16x8b, y_3_16x8b;\n        __m128i y_0L_8x16b, y_1L_8x16b, y_2L_8x16b, y_3L_8x16b;\n        __m128i y_0H_8x16b, y_1H_8x16b, y_2H_8x16b, y_3H_8x16b;\n\n        __m128i zero_16x8b;\n        zero_16x8b = _mm_set1_epi8(0);\n\n        do\n        {\n            y_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src);\n            y_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd));\n            y_2_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + (src_strd << 1)));\n            y_3_16x8b = _mm_loadu_si128((__m128i *)(pu1_src + src_strd * 3));\n\n            y_0L_8x16b = _mm_cvtepu8_epi16(y_0_16x8b);\n            y_0H_8x16b = _mm_unpackhi_epi8(y_0_16x8b, zero_16x8b);\n            y_1L_8x16b = _mm_cvtepu8_epi16(y_1_16x8b);\n            y_1H_8x16b = _mm_unpackhi_epi8(y_1_16x8b, zero_16x8b);\n            y_2L_8x16b = _mm_cvtepu8_epi16(y_2_16x8b);\n            y_2H_8x16b = _mm_unpackhi_epi8(y_2_16x8b, zero_16x8b);\n            y_3L_8x16b = _mm_cvtepu8_epi16(y_3_16x8b);\n            y_3H_8x16b = _mm_unpackhi_epi8(y_3_16x8b, zero_16x8b);\n\n            y_0L_8x16b = _mm_mullo_epi16(y_0L_8x16b, wt_8x16b);\n            y_0H_8x16b = _mm_mullo_epi16(y_0H_8x16b, wt_8x16b);\n            y_1L_8x16b = _mm_mullo_epi16(y_1L_8x16b, wt_8x16b);\n            y_1H_8x16b = _mm_mullo_epi16(y_1H_8x16b, wt_8x16b);\n            y_2L_8x16b = _mm_mullo_epi16(y_2L_8x16b, wt_8x16b);\n            y_2H_8x16b = _mm_mullo_epi16(y_2H_8x16b, wt_8x16b);\n            y_3L_8x16b = _mm_mullo_epi16(y_3L_8x16b, wt_8x16b);\n            y_3H_8x16b = _mm_mullo_epi16(y_3H_8x16b, wt_8x16b);\n\n            y_0L_8x16b = _mm_adds_epi16(round_8x16b, y_0L_8x16b);\n            y_0H_8x16b = _mm_adds_epi16(round_8x16b, y_0H_8x16b);\n            y_1L_8x16b = _mm_adds_epi16(round_8x16b, y_1L_8x16b);\n            y_1H_8x16b = _mm_adds_epi16(round_8x16b, y_1H_8x16b);\n            y_2L_8x16b = _mm_adds_epi16(round_8x16b, y_2L_8x16b);\n            y_2H_8x16b = _mm_adds_epi16(round_8x16b, y_2H_8x16b);\n            y_3L_8x16b = _mm_adds_epi16(round_8x16b, y_3L_8x16b);\n            y_3H_8x16b = _mm_adds_epi16(round_8x16b, y_3H_8x16b);\n\n            y_0L_8x16b = _mm_srai_epi16(y_0L_8x16b, log_wd);\n            y_0H_8x16b = _mm_srai_epi16(y_0H_8x16b, log_wd);\n            y_1L_8x16b = _mm_srai_epi16(y_1L_8x16b, log_wd);\n            y_1H_8x16b = _mm_srai_epi16(y_1H_8x16b, log_wd);\n            y_2L_8x16b = _mm_srai_epi16(y_2L_8x16b, log_wd);\n            y_2H_8x16b = _mm_srai_epi16(y_2H_8x16b, log_wd);\n            y_3L_8x16b = _mm_srai_epi16(y_3L_8x16b, log_wd);\n            y_3H_8x16b = _mm_srai_epi16(y_3H_8x16b, log_wd);\n\n            y_0L_8x16b = _mm_adds_epi16(ofst_8x16b, y_0L_8x16b);\n            y_0H_8x16b = _mm_adds_epi16(ofst_8x16b, y_0H_8x16b);\n            y_1L_8x16b = _mm_adds_epi16(ofst_8x16b, y_1L_8x16b);\n            y_1H_8x16b = _mm_adds_epi16(ofst_8x16b, y_1H_8x16b);\n            y_2L_8x16b = _mm_adds_epi16(ofst_8x16b, y_2L_8x16b);\n            y_2H_8x16b = _mm_adds_epi16(ofst_8x16b, y_2H_8x16b);\n            y_3L_8x16b = _mm_adds_epi16(ofst_8x16b, y_3L_8x16b);\n            y_3H_8x16b = _mm_adds_epi16(ofst_8x16b, y_3H_8x16b);\n\n            y_0_16x8b = _mm_packus_epi16(y_0L_8x16b, y_0H_8x16b);\n            y_1_16x8b = _mm_packus_epi16(y_1L_8x16b, y_1H_8x16b);\n            y_2_16x8b = _mm_packus_epi16(y_2L_8x16b, y_2H_8x16b);\n            y_3_16x8b = _mm_packus_epi16(y_3L_8x16b, y_3H_8x16b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, y_0_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), y_1_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + (dst_strd << 1)), y_2_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd * 3), y_3_16x8b);\n\n            ht -= 4;\n            pu1_src += src_strd << 2;\n            pu1_dst += dst_strd << 2;\n        }\n        while(ht > 0);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_weighted_bi_pred_luma_sse42                        */\n/*                                                                           */\n/*  Description   : This function performs the weighted biprediction as      */\n/*                  described in sec 8.4.2.3.2 titled \"Weighted sample       */\n/*                  prediction process\" for luma. The function gets two      */\n/*                  ht x wd blocks, weights them, adds them, rounds off the  */\n/*                  sum, offsets it, saturates it to unsigned 8-bit and      */\n/*                  stores it in the destination block. (ht,wd) can be       */\n/*                  (4,4), (8,4), (4,8), (8,8), (16,8), (8,16) or (16,16).   */\n/*                                                                           */\n/*  Inputs        : pu1_src1  - Pointer to source 1                          */\n/*                  pu1_src2  - Pointer to source 2                          */\n/*                  pu1_dst   - Pointer to destination                       */\n/*                  src_strd1 - stride for source 1                          */\n/*                  src_strd2 - stride for source 2                          */\n/*                  dst_strd2 - stride for destination                       */\n/*                  log_wd    - number of bits to be rounded off             */\n/*                  wt1       - weight value for source 1                    */\n/*                  wt2       - weight value for source 2                    */\n/*                  ofst1     - offset value for source 1                    */\n/*                  ofst2     - offset value for source 2                    */\n/*                  ht        - height of the block                          */\n/*                  wd        - width of the block                           */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         04 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSE42\nvoid ih264_weighted_bi_pred_luma_sse42(UWORD8 *pu1_src1,\n                                       UWORD8 *pu1_src2,\n                                       UWORD8 *pu1_dst,\n                                       WORD32 src_strd1,\n                                       WORD32 src_strd2,\n                                       WORD32 dst_strd,\n                                       WORD32 log_wd,\n                                       WORD32 wt1,\n                                       WORD32 wt2,\n                                       WORD32 ofst1,\n                                       WORD32 ofst2,\n                                       WORD32 ht,\n                                       WORD32 wd)\n{\n    __m128i y1_0_16x8b, y1_1_16x8b;\n    __m128i y2_0_16x8b, y2_1_16x8b;\n\n    __m128i wt1_8x16b, wt2_8x16b;\n    __m128i ofst_8x16b, round_8x16b;\n\n    WORD32 ofst;\n    WORD32 round_val, shft;\n\n    wt1 = (WORD16)(wt1 & 0xffff);\n    wt2 = (WORD16)(wt2 & 0xffff);\n    round_val = 1 << log_wd;\n    shft = log_wd + 1;\n    ofst1 = (WORD8)(ofst1 & 0xff);\n    ofst2 = (WORD8)(ofst2 & 0xff);\n    ofst = (ofst1 + ofst2 + 1) >> 1;\n\n    wt1_8x16b = _mm_set1_epi16(wt1);\n    wt2_8x16b = _mm_set1_epi16(wt2);\n    round_8x16b = _mm_set1_epi16(round_val);\n    ofst_8x16b = _mm_set1_epi16(ofst);\n\n    if(wd == 4)\n    {\n        __m128i y1_2_16x8b, y1_3_16x8b;\n        __m128i y2_2_16x8b, y2_3_16x8b;\n\n        __m128i y1_0_8x16b, y1_2_8x16b;\n        __m128i y2_0_8x16b, y2_2_8x16b;\n\n        do\n        {\n            y1_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src1);\n            y1_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1));\n            y1_2_16x8b = _mm_loadl_epi64(\n                            (__m128i *)(pu1_src1 + (src_strd1 << 1)));\n            y1_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1 * 3));\n\n            y2_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src2);\n            y2_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2));\n            y2_2_16x8b = _mm_loadl_epi64(\n                            (__m128i *)(pu1_src2 + (src_strd2 << 1)));\n            y2_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2 * 3));\n\n            y1_0_16x8b = _mm_unpacklo_epi32(y1_0_16x8b, y1_1_16x8b);\n            y1_2_16x8b = _mm_unpacklo_epi32(y1_2_16x8b, y1_3_16x8b);\n            y2_0_16x8b = _mm_unpacklo_epi32(y2_0_16x8b, y2_1_16x8b);\n            y2_2_16x8b = _mm_unpacklo_epi32(y2_2_16x8b, y2_3_16x8b);\n\n            y1_0_8x16b = _mm_cvtepu8_epi16(y1_0_16x8b);\n            y1_2_8x16b = _mm_cvtepu8_epi16(y1_2_16x8b);\n            y2_0_8x16b = _mm_cvtepu8_epi16(y2_0_16x8b);\n            y2_2_8x16b = _mm_cvtepu8_epi16(y2_2_16x8b);\n\n            y1_0_8x16b = _mm_mullo_epi16(y1_0_8x16b, wt1_8x16b);\n            y2_0_8x16b = _mm_mullo_epi16(y2_0_8x16b, wt2_8x16b);\n            y1_2_8x16b = _mm_mullo_epi16(y1_2_8x16b, wt1_8x16b);\n            y2_2_8x16b = _mm_mullo_epi16(y2_2_8x16b, wt2_8x16b);\n\n            y1_0_8x16b = _mm_adds_epi16(y1_0_8x16b, y2_0_8x16b);\n            y1_2_8x16b = _mm_adds_epi16(y1_2_8x16b, y2_2_8x16b);\n\n            y1_0_8x16b = _mm_adds_epi16(round_8x16b, y1_0_8x16b);\n            y1_2_8x16b = _mm_adds_epi16(round_8x16b, y1_2_8x16b);\n\n            y1_0_8x16b = _mm_srai_epi16(y1_0_8x16b, shft);\n            y1_2_8x16b = _mm_srai_epi16(y1_2_8x16b, shft);\n\n            y1_0_8x16b = _mm_adds_epi16(ofst_8x16b, y1_0_8x16b);\n            y1_2_8x16b = _mm_adds_epi16(ofst_8x16b, y1_2_8x16b);\n\n            y1_0_16x8b = _mm_packus_epi16(y1_0_8x16b, y1_2_8x16b);\n            y1_1_16x8b = _mm_srli_si128(y1_0_16x8b, 4);\n            y1_2_16x8b = _mm_srli_si128(y1_0_16x8b, 8);\n            y1_3_16x8b = _mm_srli_si128(y1_0_16x8b, 12);\n\n            *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(y1_0_16x8b);\n            *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(y1_1_16x8b);\n            *((WORD32 *)(pu1_dst + (dst_strd << 1))) = _mm_cvtsi128_si32(y1_2_16x8b);\n            *((WORD32 *)(pu1_dst + dst_strd * 3)) = _mm_cvtsi128_si32(y1_3_16x8b);\n\n\n            ht -= 4;\n            pu1_src1 += src_strd1 << 2;\n            pu1_src2 += src_strd2 << 2;\n            pu1_dst += dst_strd << 2;\n        }\n        while(ht > 0);\n    }\n    else if(wd == 8)\n    {\n        __m128i y1_2_16x8b, y1_3_16x8b;\n        __m128i y2_2_16x8b, y2_3_16x8b;\n\n        __m128i y1_0_8x16b, y1_1_8x16b, y1_2_8x16b, y1_3_8x16b;\n        __m128i y2_0_8x16b, y2_1_8x16b, y2_2_8x16b, y2_3_8x16b;\n\n        do\n        {\n            y1_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src1);\n            y1_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1));\n            y1_2_16x8b = _mm_loadl_epi64(\n                            (__m128i *)(pu1_src1 + (src_strd1 << 1)));\n            y1_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1 * 3));\n\n            y2_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src2);\n            y2_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2));\n            y2_2_16x8b = _mm_loadl_epi64(\n                            (__m128i *)(pu1_src2 + (src_strd2 << 1)));\n            y2_3_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2 * 3));\n\n            y1_0_8x16b = _mm_cvtepu8_epi16(y1_0_16x8b);\n            y1_1_8x16b = _mm_cvtepu8_epi16(y1_1_16x8b);\n            y1_2_8x16b = _mm_cvtepu8_epi16(y1_2_16x8b);\n            y1_3_8x16b = _mm_cvtepu8_epi16(y1_3_16x8b);\n\n            y2_0_8x16b = _mm_cvtepu8_epi16(y2_0_16x8b);\n            y2_1_8x16b = _mm_cvtepu8_epi16(y2_1_16x8b);\n            y2_2_8x16b = _mm_cvtepu8_epi16(y2_2_16x8b);\n            y2_3_8x16b = _mm_cvtepu8_epi16(y2_3_16x8b);\n\n            y1_0_8x16b = _mm_mullo_epi16(y1_0_8x16b, wt1_8x16b);\n            y2_0_8x16b = _mm_mullo_epi16(y2_0_8x16b, wt2_8x16b);\n            y1_1_8x16b = _mm_mullo_epi16(y1_1_8x16b, wt1_8x16b);\n            y2_1_8x16b = _mm_mullo_epi16(y2_1_8x16b, wt2_8x16b);\n\n            y1_2_8x16b = _mm_mullo_epi16(y1_2_8x16b, wt1_8x16b);\n            y2_2_8x16b = _mm_mullo_epi16(y2_2_8x16b, wt2_8x16b);\n            y1_3_8x16b = _mm_mullo_epi16(y1_3_8x16b, wt1_8x16b);\n            y2_3_8x16b = _mm_mullo_epi16(y2_3_8x16b, wt2_8x16b);\n\n            y1_0_8x16b = _mm_adds_epi16(y1_0_8x16b, y2_0_8x16b);\n            y1_1_8x16b = _mm_adds_epi16(y1_1_8x16b, y2_1_8x16b);\n            y1_2_8x16b = _mm_adds_epi16(y1_2_8x16b, y2_2_8x16b);\n            y1_3_8x16b = _mm_adds_epi16(y1_3_8x16b, y2_3_8x16b);\n\n            y1_0_8x16b = _mm_adds_epi16(round_8x16b, y1_0_8x16b);\n            y1_1_8x16b = _mm_adds_epi16(round_8x16b, y1_1_8x16b);\n            y1_2_8x16b = _mm_adds_epi16(round_8x16b, y1_2_8x16b);\n            y1_3_8x16b = _mm_adds_epi16(round_8x16b, y1_3_8x16b);\n\n            y1_0_8x16b = _mm_srai_epi16(y1_0_8x16b, shft);\n            y1_1_8x16b = _mm_srai_epi16(y1_1_8x16b, shft);\n            y1_2_8x16b = _mm_srai_epi16(y1_2_8x16b, shft);\n            y1_3_8x16b = _mm_srai_epi16(y1_3_8x16b, shft);\n\n            y1_0_8x16b = _mm_adds_epi16(ofst_8x16b, y1_0_8x16b);\n            y1_1_8x16b = _mm_adds_epi16(ofst_8x16b, y1_1_8x16b);\n            y1_2_8x16b = _mm_adds_epi16(ofst_8x16b, y1_2_8x16b);\n            y1_3_8x16b = _mm_adds_epi16(ofst_8x16b, y1_3_8x16b);\n\n            y1_0_16x8b = _mm_packus_epi16(y1_0_8x16b, y1_1_8x16b);\n            y1_2_16x8b = _mm_packus_epi16(y1_2_8x16b, y1_3_8x16b);\n            y1_1_16x8b = _mm_srli_si128(y1_0_16x8b, 8);\n            y1_3_16x8b = _mm_srli_si128(y1_2_16x8b, 8);\n\n            _mm_storel_epi64((__m128i *)pu1_dst, y1_0_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), y1_1_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + (dst_strd << 1)), y1_2_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd * 3), y1_3_16x8b);\n\n            ht -= 4;\n            pu1_src1 += src_strd1 << 2;\n            pu1_src2 += src_strd2 << 2;\n            pu1_dst += dst_strd << 2;\n        }\n        while(ht > 0);\n    }\n    else // wd == 16\n    {\n        __m128i y1_0L_8x16b, y1_0H_8x16b, y1_1L_8x16b, y1_1H_8x16b;\n        __m128i y2_0L_8x16b, y2_0H_8x16b, y2_1L_8x16b, y2_1H_8x16b;\n\n        __m128i zero_16x8b;\n        zero_16x8b = _mm_set1_epi8(0);\n\n        do\n        {\n            y1_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src1);\n            y1_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src1 + src_strd1));\n            y2_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src2);\n            y2_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src2 + src_strd2));\n\n            y1_0L_8x16b = _mm_cvtepu8_epi16(y1_0_16x8b);\n            y1_0H_8x16b = _mm_unpackhi_epi8(y1_0_16x8b, zero_16x8b);\n            y1_1L_8x16b = _mm_cvtepu8_epi16(y1_1_16x8b);\n            y1_1H_8x16b = _mm_unpackhi_epi8(y1_1_16x8b, zero_16x8b);\n\n            y2_0L_8x16b = _mm_cvtepu8_epi16(y2_0_16x8b);\n            y2_0H_8x16b = _mm_unpackhi_epi8(y2_0_16x8b, zero_16x8b);\n            y2_1L_8x16b = _mm_cvtepu8_epi16(y2_1_16x8b);\n            y2_1H_8x16b = _mm_unpackhi_epi8(y2_1_16x8b, zero_16x8b);\n\n            y1_0L_8x16b = _mm_mullo_epi16(y1_0L_8x16b, wt1_8x16b);\n            y1_0H_8x16b = _mm_mullo_epi16(y1_0H_8x16b, wt1_8x16b);\n            y1_1L_8x16b = _mm_mullo_epi16(y1_1L_8x16b, wt1_8x16b);\n            y1_1H_8x16b = _mm_mullo_epi16(y1_1H_8x16b, wt1_8x16b);\n\n            y2_0L_8x16b = _mm_mullo_epi16(y2_0L_8x16b, wt2_8x16b);\n            y2_0H_8x16b = _mm_mullo_epi16(y2_0H_8x16b, wt2_8x16b);\n            y2_1L_8x16b = _mm_mullo_epi16(y2_1L_8x16b, wt2_8x16b);\n            y2_1H_8x16b = _mm_mullo_epi16(y2_1H_8x16b, wt2_8x16b);\n\n            y1_0L_8x16b = _mm_adds_epi16(y1_0L_8x16b, y2_0L_8x16b);\n            y1_0H_8x16b = _mm_adds_epi16(y1_0H_8x16b, y2_0H_8x16b);\n            y1_1L_8x16b = _mm_adds_epi16(y1_1L_8x16b, y2_1L_8x16b);\n            y1_1H_8x16b = _mm_adds_epi16(y1_1H_8x16b, y2_1H_8x16b);\n\n            y1_0L_8x16b = _mm_adds_epi16(round_8x16b, y1_0L_8x16b);\n            y1_0H_8x16b = _mm_adds_epi16(round_8x16b, y1_0H_8x16b);\n            y1_1L_8x16b = _mm_adds_epi16(round_8x16b, y1_1L_8x16b);\n            y1_1H_8x16b = _mm_adds_epi16(round_8x16b, y1_1H_8x16b);\n\n            y1_0L_8x16b = _mm_srai_epi16(y1_0L_8x16b, shft);\n            y1_0H_8x16b = _mm_srai_epi16(y1_0H_8x16b, shft);\n            y1_1L_8x16b = _mm_srai_epi16(y1_1L_8x16b, shft);\n            y1_1H_8x16b = _mm_srai_epi16(y1_1H_8x16b, shft);\n\n            y1_0L_8x16b = _mm_adds_epi16(ofst_8x16b, y1_0L_8x16b);\n            y1_0H_8x16b = _mm_adds_epi16(ofst_8x16b, y1_0H_8x16b);\n            y1_1L_8x16b = _mm_adds_epi16(ofst_8x16b, y1_1L_8x16b);\n            y1_1H_8x16b = _mm_adds_epi16(ofst_8x16b, y1_1H_8x16b);\n\n            y1_0_16x8b = _mm_packus_epi16(y1_0L_8x16b, y1_0H_8x16b);\n            y1_1_16x8b = _mm_packus_epi16(y1_1L_8x16b, y1_1H_8x16b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, y1_0_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), y1_1_16x8b);\n\n            ht -= 2;\n            pu1_src1 += src_strd1 << 1;\n            pu1_src2 += src_strd2 << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264_weighted_bi_pred_chroma_sse42                      */\n/*                                                                           */\n/*  Description   : This function performs the weighted biprediction as      */\n/*                  described in sec 8.4.2.3.2 titled \"Weighted sample       */\n/*                  prediction process\" for chroma. The function gets two    */\n/*                  ht x wd blocks, weights them, adds them, rounds off the  */\n/*                  sum, offsets it, saturates it to unsigned 8-bit and      */\n/*                  stores it in the destination block. (ht,wd) can be       */\n/*                  (2,2), (4,2), (2,4), (4,4), (8,4), (4,8) or (8,8).       */\n/*                                                                           */\n/*  Inputs        : pu1_src1  - Pointer to source 1                          */\n/*                  pu1_src2  - Pointer to source 2                          */\n/*                  pu1_dst   - Pointer to destination                       */\n/*                  src_strd1 - stride for source 1                          */\n/*                  src_strd2 - stride for source 2                          */\n/*                  dst_strd2 - stride for destination                       */\n/*                  log_wd    - number of bits to be rounded off             */\n/*                  wt1       - weight values for u and v in source 1        */\n/*                  wt2       - weight values for u and v in source 2        */\n/*                  ofst1     - offset value for u and v in source 1         */\n/*                  ofst2     - offset value for u and v in source 2         */\n/*                  ht        - height of the block                          */\n/*                  wd        - width of the block                           */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes                              */\n/*         04 02 2015   Kaushik         Initial Version                      */\n/*                      Senthoor                                             */\n/*                                                                           */\n/*****************************************************************************/\nATTRIBUTE_SSE42\nvoid ih264_weighted_bi_pred_chroma_sse42(UWORD8 *pu1_src1,\n                                         UWORD8 *pu1_src2,\n                                         UWORD8 *pu1_dst,\n                                         WORD32 src_strd1,\n                                         WORD32 src_strd2,\n                                         WORD32 dst_strd,\n                                         WORD32 log_wd,\n                                         WORD32 wt1,\n                                         WORD32 wt2,\n                                         WORD32 ofst1,\n                                         WORD32 ofst2,\n                                         WORD32 ht,\n                                         WORD32 wd)\n{\n    __m128i y1_0_16x8b, y1_1_16x8b;\n    __m128i y2_0_16x8b, y2_1_16x8b;\n\n    __m128i wt1_8x16b, wt2_8x16b;\n    __m128i ofst_8x16b, round_8x16b;\n\n    WORD32 ofst1_u, ofst2_u, ofst_u;\n    WORD32 ofst1_v, ofst2_v, ofst_v;\n    WORD32 round_val, shft, ofst_val;\n\n    round_val = 1 << log_wd;\n    shft = log_wd + 1;\n\n    ofst1_u = (WORD8)(ofst1 & 0xff);\n    ofst1_v = (WORD8)(ofst1 >> 8);\n    ofst2_u = (WORD8)(ofst2 & 0xff);\n    ofst2_v = (WORD8)(ofst2 >> 8);\n\n    wt1_8x16b = _mm_set1_epi32(wt1);\n    wt2_8x16b = _mm_set1_epi32(wt2);\n\n    ofst_u = (ofst1_u + ofst2_u + 1) >> 1;\n    ofst_v = (ofst1_v + ofst2_v + 1) >> 1;\n    ofst_val = (ofst_u & 0xffff) | (ofst_v << 16);\n\n    round_8x16b = _mm_set1_epi16(round_val);\n    ofst_8x16b = _mm_set1_epi32(ofst_val);\n\n    if(wd == 2)\n    {\n        __m128i y1_0_8x16b, y2_0_8x16b;\n\n        do\n        {\n            y1_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src1);\n            y1_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1));\n\n            y2_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src2);\n            y2_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2));\n\n            y1_0_16x8b = _mm_unpacklo_epi32(y1_0_16x8b, y1_1_16x8b);\n            y2_0_16x8b = _mm_unpacklo_epi32(y2_0_16x8b, y2_1_16x8b);\n\n            y1_0_8x16b = _mm_cvtepu8_epi16(y1_0_16x8b);\n            y2_0_8x16b = _mm_cvtepu8_epi16(y2_0_16x8b);\n\n            y1_0_8x16b = _mm_mullo_epi16(y1_0_8x16b, wt1_8x16b);\n            y2_0_8x16b = _mm_mullo_epi16(y2_0_8x16b, wt2_8x16b);\n\n            y1_0_8x16b = _mm_adds_epi16(y1_0_8x16b, y2_0_8x16b);\n            y1_0_8x16b = _mm_adds_epi16(round_8x16b, y1_0_8x16b);\n\n            y1_0_8x16b = _mm_srai_epi16(y1_0_8x16b, shft);\n            y1_0_8x16b = _mm_adds_epi16(ofst_8x16b, y1_0_8x16b);\n\n            y1_0_16x8b = _mm_packus_epi16(y1_0_8x16b, y1_0_8x16b);\n            y1_1_16x8b = _mm_srli_si128(y1_0_16x8b, 4);\n\n            *((WORD32 *)(pu1_dst)) = _mm_cvtsi128_si32(y1_0_16x8b);\n            *((WORD32 *)(pu1_dst + dst_strd)) = _mm_cvtsi128_si32(y1_1_16x8b);\n\n            ht -= 2;\n            pu1_src1 += src_strd1 << 1;\n            pu1_src2 += src_strd2 << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else if(wd == 4)\n    {\n        __m128i y1_0_8x16b, y1_1_8x16b;\n        __m128i y2_0_8x16b, y2_1_8x16b;\n\n        do\n        {\n            y1_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src1);\n            y1_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src1 + src_strd1));\n\n            y2_0_16x8b = _mm_loadl_epi64((__m128i *)pu1_src2);\n            y2_1_16x8b = _mm_loadl_epi64((__m128i *)(pu1_src2 + src_strd2));\n\n            y1_0_8x16b = _mm_cvtepu8_epi16(y1_0_16x8b);\n            y1_1_8x16b = _mm_cvtepu8_epi16(y1_1_16x8b);\n\n            y2_0_8x16b = _mm_cvtepu8_epi16(y2_0_16x8b);\n            y2_1_8x16b = _mm_cvtepu8_epi16(y2_1_16x8b);\n\n            y1_0_8x16b = _mm_mullo_epi16(y1_0_8x16b, wt1_8x16b);\n            y2_0_8x16b = _mm_mullo_epi16(y2_0_8x16b, wt2_8x16b);\n            y1_1_8x16b = _mm_mullo_epi16(y1_1_8x16b, wt1_8x16b);\n            y2_1_8x16b = _mm_mullo_epi16(y2_1_8x16b, wt2_8x16b);\n\n            y1_0_8x16b = _mm_adds_epi16(y1_0_8x16b, y2_0_8x16b);\n            y1_1_8x16b = _mm_adds_epi16(y1_1_8x16b, y2_1_8x16b);\n\n            y1_0_8x16b = _mm_adds_epi16(round_8x16b, y1_0_8x16b);\n            y1_1_8x16b = _mm_adds_epi16(round_8x16b, y1_1_8x16b);\n\n            y1_0_8x16b = _mm_srai_epi16(y1_0_8x16b, shft);\n            y1_1_8x16b = _mm_srai_epi16(y1_1_8x16b, shft);\n\n            y1_0_8x16b = _mm_adds_epi16(ofst_8x16b, y1_0_8x16b);\n            y1_1_8x16b = _mm_adds_epi16(ofst_8x16b, y1_1_8x16b);\n\n            y1_0_16x8b = _mm_packus_epi16(y1_0_8x16b, y1_1_8x16b);\n            y1_1_16x8b = _mm_srli_si128(y1_0_16x8b, 8);\n\n            _mm_storel_epi64((__m128i *)pu1_dst, y1_0_16x8b);\n            _mm_storel_epi64((__m128i *)(pu1_dst + dst_strd), y1_1_16x8b);\n\n            ht -= 2;\n            pu1_src1 += src_strd1 << 1;\n            pu1_src2 += src_strd2 << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n    else // wd == 8\n    {\n        __m128i y1_0L_8x16b, y1_0H_8x16b, y1_1L_8x16b, y1_1H_8x16b;\n        __m128i y2_0L_8x16b, y2_0H_8x16b, y2_1L_8x16b, y2_1H_8x16b;\n\n        __m128i zero_16x8b;\n        zero_16x8b = _mm_set1_epi8(0);\n\n        do\n        {\n            y1_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src1);\n            y1_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src1 + src_strd1));\n            y2_0_16x8b = _mm_loadu_si128((__m128i *)pu1_src2);\n            y2_1_16x8b = _mm_loadu_si128((__m128i *)(pu1_src2 + src_strd2));\n\n            y1_0L_8x16b = _mm_cvtepu8_epi16(y1_0_16x8b);\n            y1_0H_8x16b = _mm_unpackhi_epi8(y1_0_16x8b, zero_16x8b);\n            y1_1L_8x16b = _mm_cvtepu8_epi16(y1_1_16x8b);\n            y1_1H_8x16b = _mm_unpackhi_epi8(y1_1_16x8b, zero_16x8b);\n\n            y2_0L_8x16b = _mm_cvtepu8_epi16(y2_0_16x8b);\n            y2_0H_8x16b = _mm_unpackhi_epi8(y2_0_16x8b, zero_16x8b);\n            y2_1L_8x16b = _mm_cvtepu8_epi16(y2_1_16x8b);\n            y2_1H_8x16b = _mm_unpackhi_epi8(y2_1_16x8b, zero_16x8b);\n\n            y1_0L_8x16b = _mm_mullo_epi16(y1_0L_8x16b, wt1_8x16b);\n            y1_0H_8x16b = _mm_mullo_epi16(y1_0H_8x16b, wt1_8x16b);\n            y1_1L_8x16b = _mm_mullo_epi16(y1_1L_8x16b, wt1_8x16b);\n            y1_1H_8x16b = _mm_mullo_epi16(y1_1H_8x16b, wt1_8x16b);\n\n            y2_0L_8x16b = _mm_mullo_epi16(y2_0L_8x16b, wt2_8x16b);\n            y2_0H_8x16b = _mm_mullo_epi16(y2_0H_8x16b, wt2_8x16b);\n            y2_1L_8x16b = _mm_mullo_epi16(y2_1L_8x16b, wt2_8x16b);\n            y2_1H_8x16b = _mm_mullo_epi16(y2_1H_8x16b, wt2_8x16b);\n\n            y1_0L_8x16b = _mm_adds_epi16(y1_0L_8x16b, y2_0L_8x16b);\n            y1_0H_8x16b = _mm_adds_epi16(y1_0H_8x16b, y2_0H_8x16b);\n            y1_1L_8x16b = _mm_adds_epi16(y1_1L_8x16b, y2_1L_8x16b);\n            y1_1H_8x16b = _mm_adds_epi16(y1_1H_8x16b, y2_1H_8x16b);\n\n            y1_0L_8x16b = _mm_adds_epi16(round_8x16b, y1_0L_8x16b);\n            y1_0H_8x16b = _mm_adds_epi16(round_8x16b, y1_0H_8x16b);\n            y1_1L_8x16b = _mm_adds_epi16(round_8x16b, y1_1L_8x16b);\n            y1_1H_8x16b = _mm_adds_epi16(round_8x16b, y1_1H_8x16b);\n\n            y1_0L_8x16b = _mm_srai_epi16(y1_0L_8x16b, shft);\n            y1_0H_8x16b = _mm_srai_epi16(y1_0H_8x16b, shft);\n            y1_1L_8x16b = _mm_srai_epi16(y1_1L_8x16b, shft);\n            y1_1H_8x16b = _mm_srai_epi16(y1_1H_8x16b, shft);\n\n            y1_0L_8x16b = _mm_adds_epi16(ofst_8x16b, y1_0L_8x16b);\n            y1_0H_8x16b = _mm_adds_epi16(ofst_8x16b, y1_0H_8x16b);\n            y1_1L_8x16b = _mm_adds_epi16(ofst_8x16b, y1_1L_8x16b);\n            y1_1H_8x16b = _mm_adds_epi16(ofst_8x16b, y1_1H_8x16b);\n\n            y1_0_16x8b = _mm_packus_epi16(y1_0L_8x16b, y1_0H_8x16b);\n            y1_1_16x8b = _mm_packus_epi16(y1_1L_8x16b, y1_1H_8x16b);\n\n            _mm_storeu_si128((__m128i *)pu1_dst, y1_0_16x8b);\n            _mm_storeu_si128((__m128i *)(pu1_dst + dst_strd), y1_1_16x8b);\n\n            ht -= 2;\n            pu1_src1 += src_strd1 << 1;\n            pu1_src2 += src_strd2 << 1;\n            pu1_dst += dst_strd << 1;\n        }\n        while(ht > 0);\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/arm/ih264d_function_selector.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ihevcd_function_selector.c\n*\n* @brief\n*  Contains functions to initialize function pointers used in hevc\n*\n* @author\n*  Naveen\n*\n* @par List of Functions:\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"ih264_typedefs.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_error.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include \"ih264_inter_pred_filters.h\"\n\n#include \"ih264d_structs.h\"\n#include \"ih264d_function_selector.h\"\n\nvoid ih264d_init_function_ptr(dec_struct_t *ps_codec)\n{\n\n    IVD_ARCH_T e_proc_arch  = ps_codec->e_processor_arch;\n    ih264d_init_function_ptr_generic(ps_codec);\n    switch(e_proc_arch)\n    {\n#if defined(ARMV8)\n        case ARCH_ARMV8_GENERIC:\n        default:\n            ih264d_init_function_ptr_av8(ps_codec);\n            break;\n#elif !defined(DISABLE_NEON)\n        case ARCH_ARM_A5:\n        case ARCH_ARM_A7:\n        case ARCH_ARM_A9:\n        case ARCH_ARM_A15:\n        case ARCH_ARM_A9Q:\n        default:\n            ih264d_init_function_ptr_a9q(ps_codec);\n            break;\n#else\n        default:\n#endif\n        case ARCH_ARM_NONEON:\n            break;\n    }\n}\n\nvoid ih264d_init_arch(dec_struct_t *ps_codec)\n{\n#ifdef DEFAULT_ARCH\n#if DEFAULT_ARCH == D_ARCH_ARM_NONEON\n    ps_codec->e_processor_arch = ARCH_ARM_NONEON;\n#elif DEFAULT_ARCH == D_ARCH_ARMV8_GENERIC\n    ps_codec->e_processor_arch = ARCH_ARMV8_GENERIC;\n#elif DEFAULT_ARCH == D_ARCH_ARM_NEONINTR\n    ps_codec->e_processor_arch = ARCH_ARM_NEONINTR;\n#else\n    ps_codec->e_processor_arch = ARCH_ARM_A9Q;\n#endif\n#else\n    ps_codec->e_processor_arch = ARCH_ARM_A9Q;\n#endif\n\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/arm/ih264d_function_selector_a9q.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264e_function_selector_a9q.c\n*\n* @brief\n*  Contains functions to initialize function pointers of codec context\n*\n* @author\n*  Ittiam\n*\n* @par List of Functions:\n*  - ih264e_init_function_ptr_a9q\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System Include files */\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* User Include files */\n#include \"ih264_typedefs.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_error.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include \"ih264_inter_pred_filters.h\"\n\n#include \"ih264d_structs.h\"\n\n\n/**\n*******************************************************************************\n*\n* @brief Initialize the intra/inter/transform/deblk function pointers of\n* codec context\n*\n* @par Description: the current routine initializes the function pointers of\n* codec context basing on the architecture in use\n*\n* @param[in] ps_codec\n*  Codec context pointer\n*\n* @returns  none\n*\n* @remarks none\n*\n*******************************************************************************\n*/\nvoid ih264d_init_function_ptr_a9q(dec_struct_t *ps_codec)\n{\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 16x16 */\n    ps_codec->apf_intra_pred_luma_16x16[0] = ih264_intra_pred_luma_16x16_mode_vert_a9q;\n    ps_codec->apf_intra_pred_luma_16x16[1] = ih264_intra_pred_luma_16x16_mode_horz_a9q;\n    ps_codec->apf_intra_pred_luma_16x16[2] = ih264_intra_pred_luma_16x16_mode_dc_a9q;\n    ps_codec->apf_intra_pred_luma_16x16[3] = ih264_intra_pred_luma_16x16_mode_plane_a9q;\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 4x4 */\n    ps_codec->apf_intra_pred_luma_4x4[0] = ih264_intra_pred_luma_4x4_mode_vert_a9q;\n    ps_codec->apf_intra_pred_luma_4x4[1] = ih264_intra_pred_luma_4x4_mode_horz_a9q;\n    ps_codec->apf_intra_pred_luma_4x4[2] = ih264_intra_pred_luma_4x4_mode_dc_a9q;\n    ps_codec->apf_intra_pred_luma_4x4[3] = ih264_intra_pred_luma_4x4_mode_diag_dl_a9q;\n    ps_codec->apf_intra_pred_luma_4x4[4] = ih264_intra_pred_luma_4x4_mode_diag_dr_a9q;\n    ps_codec->apf_intra_pred_luma_4x4[5] = ih264_intra_pred_luma_4x4_mode_vert_r_a9q;\n    ps_codec->apf_intra_pred_luma_4x4[6] = ih264_intra_pred_luma_4x4_mode_horz_d_a9q;\n    ps_codec->apf_intra_pred_luma_4x4[7] = ih264_intra_pred_luma_4x4_mode_vert_l_a9q;\n    ps_codec->apf_intra_pred_luma_4x4[8] = ih264_intra_pred_luma_4x4_mode_horz_u_a9q;\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 8x8 */\n    ps_codec->apf_intra_pred_luma_8x8[0] = ih264_intra_pred_luma_8x8_mode_vert_a9q;\n    ps_codec->apf_intra_pred_luma_8x8[1] = ih264_intra_pred_luma_8x8_mode_horz_a9q;\n    ps_codec->apf_intra_pred_luma_8x8[2] = ih264_intra_pred_luma_8x8_mode_dc_a9q;\n    ps_codec->apf_intra_pred_luma_8x8[3] = ih264_intra_pred_luma_8x8_mode_diag_dl_a9q;\n    ps_codec->apf_intra_pred_luma_8x8[4] = ih264_intra_pred_luma_8x8_mode_diag_dr_a9q;\n    ps_codec->apf_intra_pred_luma_8x8[5] = ih264_intra_pred_luma_8x8_mode_vert_r_a9q;\n    ps_codec->apf_intra_pred_luma_8x8[6] = ih264_intra_pred_luma_8x8_mode_horz_d_a9q;\n    ps_codec->apf_intra_pred_luma_8x8[7] = ih264_intra_pred_luma_8x8_mode_vert_l_a9q;\n    ps_codec->apf_intra_pred_luma_8x8[8] = ih264_intra_pred_luma_8x8_mode_horz_u_a9q;\n\n    /* ih264_intra_pred_luma_8x8_mode_ref_filtering_a9q does not handle all availibilities */\n    ps_codec->pf_intra_pred_ref_filtering = ih264_intra_pred_luma_8x8_mode_ref_filtering;\n\n    /* Init function pointers for intra pred leaf level functions chroma\n     * Intra 8x8 */\n    ps_codec->apf_intra_pred_chroma[0] = ih264_intra_pred_chroma_8x8_mode_vert_a9q;\n    ps_codec->apf_intra_pred_chroma[1] = ih264_intra_pred_chroma_8x8_mode_horz_a9q;\n    /* ih264_intra_pred_chroma_8x8_mode_dc_a9q does not support interlaced clips, hence using C */\n    ps_codec->apf_intra_pred_chroma[2] = ih264_intra_pred_chroma_8x8_mode_dc;\n    ps_codec->apf_intra_pred_chroma[3] = ih264_intra_pred_chroma_8x8_mode_plane_a9q;\n\n\n    ps_codec->pf_default_weighted_pred_luma = ih264_default_weighted_pred_luma_a9q;\n    ps_codec->pf_default_weighted_pred_chroma = ih264_default_weighted_pred_chroma_a9q;\n    ps_codec->pf_weighted_pred_luma = ih264_weighted_pred_luma_a9q;\n    ps_codec->pf_weighted_pred_chroma = ih264_weighted_pred_chroma_a9q;\n    ps_codec->pf_weighted_bi_pred_luma = ih264_weighted_bi_pred_luma_a9q;\n    ps_codec->pf_weighted_bi_pred_chroma = ih264_weighted_bi_pred_chroma_a9q;\n\n    /* Padding Functions */\n    ps_codec->pf_pad_top = ih264_pad_top_a9q;\n    ps_codec->pf_pad_bottom = ih264_pad_bottom;\n\n    ps_codec->pf_pad_left_luma = ih264_pad_left_luma_a9q;\n    ps_codec->pf_pad_right_luma = ih264_pad_right_luma_a9q;\n    ps_codec->pf_pad_left_chroma = ih264_pad_left_chroma_a9q;\n    ps_codec->pf_pad_right_chroma = ih264_pad_right_chroma_a9q;\n\n    ps_codec->pf_iquant_itrans_recon_luma_4x4 = ih264_iquant_itrans_recon_4x4_a9;\n    ps_codec->pf_iquant_itrans_recon_luma_4x4_dc = ih264_iquant_itrans_recon_4x4_dc_a9;\n    ps_codec->pf_iquant_itrans_recon_luma_8x8 = ih264_iquant_itrans_recon_8x8_a9;\n    ps_codec->pf_iquant_itrans_recon_luma_8x8_dc = ih264_iquant_itrans_recon_8x8_dc_a9;\n    ps_codec->pf_ihadamard_scaling_4x4 = ih264_ihadamard_scaling_4x4_a9;\n\n\n    ps_codec->pf_iquant_itrans_recon_chroma_4x4 = ih264_iquant_itrans_recon_chroma_4x4_a9;\n    ps_codec->pf_iquant_itrans_recon_chroma_4x4_dc = ih264_iquant_itrans_recon_chroma_4x4_dc_a9;\n\n    /* Init fn ptr luma deblocking */\n     ps_codec->pf_deblk_luma_vert_bs4 = ih264_deblk_luma_vert_bs4_a9;\n     ps_codec->pf_deblk_luma_vert_bslt4 = ih264_deblk_luma_vert_bslt4_a9;\n     ps_codec->pf_deblk_luma_vert_bs4_mbaff = ih264_deblk_luma_vert_bs4_mbaff_a9;\n     ps_codec->pf_deblk_luma_vert_bslt4_mbaff = ih264_deblk_luma_vert_bslt4_mbaff_a9;\n\n     ps_codec->pf_deblk_luma_horz_bs4 = ih264_deblk_luma_horz_bs4_a9;\n     ps_codec->pf_deblk_luma_horz_bslt4 = ih264_deblk_luma_horz_bslt4_a9;\n\n     /* Init fn ptr chroma deblocking */\n     ps_codec->pf_deblk_chroma_vert_bs4 = ih264_deblk_chroma_vert_bs4_a9;\n     ps_codec->pf_deblk_chroma_vert_bslt4 = ih264_deblk_chroma_vert_bslt4_a9;\n     ps_codec->pf_deblk_chroma_vert_bs4_mbaff = ih264_deblk_chroma_vert_bs4_mbaff_a9;\n     ps_codec->pf_deblk_chroma_vert_bslt4_mbaff = ih264_deblk_chroma_vert_bslt4_mbaff_a9;\n\n     ps_codec->pf_deblk_chroma_horz_bs4 = ih264_deblk_chroma_horz_bs4_a9;\n     ps_codec->pf_deblk_chroma_horz_bslt4 = ih264_deblk_chroma_horz_bslt4_a9;\n\n\n    /* Inter pred leaf level functions */\n    ps_codec->apf_inter_pred_luma[0] = ih264_inter_pred_luma_copy_a9q;\n\n    ps_codec->apf_inter_pred_luma[1] = ih264_inter_pred_luma_horz_qpel_a9q;\n    ps_codec->apf_inter_pred_luma[2] = ih264_inter_pred_luma_horz_a9q;\n    ps_codec->apf_inter_pred_luma[3] = ih264_inter_pred_luma_horz_qpel_a9q;\n    ps_codec->apf_inter_pred_luma[4] = ih264_inter_pred_luma_vert_qpel_a9q;\n\n    ps_codec->apf_inter_pred_luma[5] = ih264_inter_pred_luma_horz_qpel_vert_qpel_a9q;\n\n    ps_codec->apf_inter_pred_luma[6] = ih264_inter_pred_luma_horz_hpel_vert_qpel_a9q;\n\n    ps_codec->apf_inter_pred_luma[7] = ih264_inter_pred_luma_horz_qpel_vert_qpel_a9q;\n\n    ps_codec->apf_inter_pred_luma[8] = ih264_inter_pred_luma_vert_a9q;\n    ps_codec->apf_inter_pred_luma[9] = ih264_inter_pred_luma_horz_qpel_vert_hpel_a9q;\n    ps_codec->apf_inter_pred_luma[10] = ih264_inter_pred_luma_horz_hpel_vert_hpel_a9q;\n    ps_codec->apf_inter_pred_luma[11] = ih264_inter_pred_luma_horz_qpel_vert_hpel_a9q;\n    ps_codec->apf_inter_pred_luma[12] = ih264_inter_pred_luma_vert_qpel_a9q;\n    ps_codec->apf_inter_pred_luma[13] = ih264_inter_pred_luma_horz_qpel_vert_qpel_a9q;\n    ps_codec->apf_inter_pred_luma[14] = ih264_inter_pred_luma_horz_hpel_vert_qpel_a9q;\n    ps_codec->apf_inter_pred_luma[15] = ih264_inter_pred_luma_horz_qpel_vert_qpel_a9q;\n\n    ps_codec->pf_inter_pred_chroma = ih264_inter_pred_chroma_a9q;\n\n\n    return;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/arm/ih264d_function_selector_av8.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264e_function_selector_av8.c\n*\n* @brief\n*  Contains functions to initialize function pointers of codec context\n*\n* @author\n*  Ittiam\n*\n* @par List of Functions:\n*  - ih264e_init_function_ptr_av8\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System Include files */\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* User Include files */\n#include \"ih264_typedefs.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_error.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include \"ih264_inter_pred_filters.h\"\n\n#include \"ih264d_structs.h\"\n#include \"ih264d_function_selector.h\"\n\n\n/**\n*******************************************************************************\n*\n* @brief Initialize the intra/inter/transform/deblk function pointers of\n* codec context\n*\n* @par Description: the current routine initializes the function pointers of\n* codec context basing on the architecture in use\n*\n* @param[in] ps_codec\n*  Codec context pointer\n*\n* @returns  none\n*\n* @remarks none\n*\n*******************************************************************************\n*/\nvoid ih264d_init_function_ptr_av8(dec_struct_t *ps_codec)\n{\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 16x16 */\n    ps_codec->apf_intra_pred_luma_16x16[0] = ih264_intra_pred_luma_16x16_mode_vert_av8;\n    ps_codec->apf_intra_pred_luma_16x16[1] = ih264_intra_pred_luma_16x16_mode_horz_av8;\n    ps_codec->apf_intra_pred_luma_16x16[2] = ih264_intra_pred_luma_16x16_mode_dc_av8;\n    ps_codec->apf_intra_pred_luma_16x16[3] = ih264_intra_pred_luma_16x16_mode_plane_av8;\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 4x4 */\n    ps_codec->apf_intra_pred_luma_4x4[0] = ih264_intra_pred_luma_4x4_mode_vert_av8;\n    ps_codec->apf_intra_pred_luma_4x4[1] = ih264_intra_pred_luma_4x4_mode_horz_av8;\n    ps_codec->apf_intra_pred_luma_4x4[2] = ih264_intra_pred_luma_4x4_mode_dc_av8;\n    ps_codec->apf_intra_pred_luma_4x4[3] = ih264_intra_pred_luma_4x4_mode_diag_dl_av8;\n    ps_codec->apf_intra_pred_luma_4x4[4] = ih264_intra_pred_luma_4x4_mode_diag_dr_av8;\n    ps_codec->apf_intra_pred_luma_4x4[5] = ih264_intra_pred_luma_4x4_mode_vert_r_av8;\n    ps_codec->apf_intra_pred_luma_4x4[6] = ih264_intra_pred_luma_4x4_mode_horz_d_av8;\n    ps_codec->apf_intra_pred_luma_4x4[7] = ih264_intra_pred_luma_4x4_mode_vert_l_av8;\n    ps_codec->apf_intra_pred_luma_4x4[8] = ih264_intra_pred_luma_4x4_mode_horz_u_av8;\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 8x8 */\n    ps_codec->apf_intra_pred_luma_8x8[0] = ih264_intra_pred_luma_8x8_mode_vert_av8;\n    ps_codec->apf_intra_pred_luma_8x8[1] = ih264_intra_pred_luma_8x8_mode_horz_av8;\n    ps_codec->apf_intra_pred_luma_8x8[2] = ih264_intra_pred_luma_8x8_mode_dc_av8;\n    ps_codec->apf_intra_pred_luma_8x8[3] = ih264_intra_pred_luma_8x8_mode_diag_dl_av8;\n    ps_codec->apf_intra_pred_luma_8x8[4] = ih264_intra_pred_luma_8x8_mode_diag_dr_av8;\n    ps_codec->apf_intra_pred_luma_8x8[5] = ih264_intra_pred_luma_8x8_mode_vert_r_av8;\n    ps_codec->apf_intra_pred_luma_8x8[6] = ih264_intra_pred_luma_8x8_mode_horz_d_av8;\n    ps_codec->apf_intra_pred_luma_8x8[7] = ih264_intra_pred_luma_8x8_mode_vert_l_av8;\n    ps_codec->apf_intra_pred_luma_8x8[8] = ih264_intra_pred_luma_8x8_mode_horz_u_av8;\n\n    ps_codec->pf_intra_pred_ref_filtering = ih264_intra_pred_luma_8x8_mode_ref_filtering;\n\n    /* Init function pointers for intra pred leaf level functions chroma\n     * Intra 8x8 */\n    ps_codec->apf_intra_pred_chroma[0] = ih264_intra_pred_chroma_8x8_mode_vert_av8;\n    ps_codec->apf_intra_pred_chroma[1] = ih264_intra_pred_chroma_8x8_mode_horz_av8;\n    /* ih264_intra_pred_chroma_8x8_mode_dc_av8 does not support interlaced clips, hence using C */\n    ps_codec->apf_intra_pred_chroma[2] = ih264_intra_pred_chroma_8x8_mode_dc;\n    ps_codec->apf_intra_pred_chroma[3] = ih264_intra_pred_chroma_8x8_mode_plane_av8;\n\n    ps_codec->pf_default_weighted_pred_luma = ih264_default_weighted_pred_luma_av8;\n    ps_codec->pf_default_weighted_pred_chroma = ih264_default_weighted_pred_chroma_av8;\n    ps_codec->pf_weighted_pred_luma = ih264_weighted_pred_luma_av8;\n    ps_codec->pf_weighted_pred_chroma = ih264_weighted_pred_chroma_av8;\n    ps_codec->pf_weighted_bi_pred_luma = ih264_weighted_bi_pred_luma_av8;\n    ps_codec->pf_weighted_bi_pred_chroma = ih264_weighted_bi_pred_chroma_av8;\n\n    /* Padding Functions */\n    ps_codec->pf_pad_top = ih264_pad_top_av8;\n    ps_codec->pf_pad_bottom = ih264_pad_bottom;\n    ps_codec->pf_pad_left_luma = ih264_pad_left_luma_av8;\n    ps_codec->pf_pad_left_chroma = ih264_pad_left_chroma_av8;\n    ps_codec->pf_pad_right_luma = ih264_pad_right_luma_av8;\n    ps_codec->pf_pad_right_chroma = ih264_pad_right_chroma_av8;\n\n\n    ps_codec->pf_iquant_itrans_recon_luma_4x4 = ih264_iquant_itrans_recon_4x4_av8;\n    ps_codec->pf_iquant_itrans_recon_luma_4x4_dc = ih264_iquant_itrans_recon_4x4_dc_av8;\n    ps_codec->pf_iquant_itrans_recon_luma_8x8 = ih264_iquant_itrans_recon_8x8_av8;\n    ps_codec->pf_iquant_itrans_recon_luma_8x8_dc = ih264_iquant_itrans_recon_8x8_dc_av8;\n    ps_codec->pf_iquant_itrans_recon_chroma_4x4 = ih264_iquant_itrans_recon_chroma_4x4_av8;\n    ps_codec->pf_iquant_itrans_recon_chroma_4x4_dc = ih264_iquant_itrans_recon_chroma_4x4_dc_av8;\n    ps_codec->pf_ihadamard_scaling_4x4 = ih264_ihadamard_scaling_4x4_av8;\n\n\n    /* Init fn ptr luma deblocking */\n    ps_codec->pf_deblk_luma_vert_bs4 = ih264_deblk_luma_vert_bs4_av8;\n    ps_codec->pf_deblk_luma_vert_bslt4 = ih264_deblk_luma_vert_bslt4_av8;\n    ps_codec->pf_deblk_luma_vert_bs4_mbaff = ih264_deblk_luma_vert_bs4_mbaff;\n    ps_codec->pf_deblk_luma_vert_bslt4_mbaff = ih264_deblk_luma_vert_bslt4_mbaff;\n\n    ps_codec->pf_deblk_luma_horz_bs4 = ih264_deblk_luma_horz_bs4_av8;\n    ps_codec->pf_deblk_luma_horz_bslt4 = ih264_deblk_luma_horz_bslt4_av8;\n\n    /* Init fn ptr chroma deblocking */\n    ps_codec->pf_deblk_chroma_vert_bs4 = ih264_deblk_chroma_vert_bs4_av8;\n    ps_codec->pf_deblk_chroma_vert_bslt4 = ih264_deblk_chroma_vert_bslt4_av8;\n    ps_codec->pf_deblk_chroma_vert_bs4_mbaff = ih264_deblk_chroma_vert_bs4_mbaff;\n    ps_codec->pf_deblk_chroma_vert_bslt4_mbaff = ih264_deblk_chroma_vert_bslt4_mbaff;\n\n    ps_codec->pf_deblk_chroma_horz_bs4 = ih264_deblk_chroma_horz_bs4_av8;\n    ps_codec->pf_deblk_chroma_horz_bslt4 = ih264_deblk_chroma_horz_bslt4_av8;\n\n    /* Inter pred leaf level functions */\n    ps_codec->apf_inter_pred_luma[0] = ih264_inter_pred_luma_copy_av8;\n    ps_codec->apf_inter_pred_luma[1] = ih264_inter_pred_luma_horz_qpel_av8;\n    ps_codec->apf_inter_pred_luma[2] = ih264_inter_pred_luma_horz_av8;\n    ps_codec->apf_inter_pred_luma[3] = ih264_inter_pred_luma_horz_qpel_av8;\n    ps_codec->apf_inter_pred_luma[4] = ih264_inter_pred_luma_vert_qpel_av8;\n    ps_codec->apf_inter_pred_luma[5] = ih264_inter_pred_luma_horz_qpel_vert_qpel_av8;\n    ps_codec->apf_inter_pred_luma[6] = ih264_inter_pred_luma_horz_hpel_vert_qpel_av8;\n    ps_codec->apf_inter_pred_luma[7] = ih264_inter_pred_luma_horz_qpel_vert_qpel_av8;\n    ps_codec->apf_inter_pred_luma[8] = ih264_inter_pred_luma_vert_av8;\n    ps_codec->apf_inter_pred_luma[9] = ih264_inter_pred_luma_horz_qpel_vert_hpel_av8;\n    ps_codec->apf_inter_pred_luma[10] = ih264_inter_pred_luma_horz_hpel_vert_hpel_av8;\n    ps_codec->apf_inter_pred_luma[11] = ih264_inter_pred_luma_horz_qpel_vert_hpel_av8;\n    ps_codec->apf_inter_pred_luma[12] = ih264_inter_pred_luma_vert_qpel_av8;\n    ps_codec->apf_inter_pred_luma[13] = ih264_inter_pred_luma_horz_qpel_vert_qpel_av8;\n    ps_codec->apf_inter_pred_luma[14] = ih264_inter_pred_luma_horz_hpel_vert_qpel_av8;\n    ps_codec->apf_inter_pred_luma[15] = ih264_inter_pred_luma_horz_qpel_vert_qpel_av8;\n\n    ps_codec->pf_inter_pred_chroma = ih264_inter_pred_chroma_av8;\n\n\n    return;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264d.h                                             */\n/*                                                                           */\n/*  Description       : This file contains all the necessary structure and   */\n/*                      enumeration definitions needed for the Application   */\n/*                      Program Interface(API) of the Ittiam H264 ASP       */\n/*                      Decoder on Cortex A8 - Neon platform                 */\n/*                                                                           */\n/*  List of Functions : ih264d_api_function                              */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         26 08 2010   100239(RCY)     Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\n#ifndef _IH264D_H_\n#define _IH264D_H_\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"iv.h\"\n#include \"ivd.h\"\n\n\n/*****************************************************************************/\n/* Constant Macros                                                           */\n/*****************************************************************************/\n#define IVD_ERROR_MASK 0xFF\n\n/*****************************************************************************/\n/* Function Macros                                                           */\n/*****************************************************************************/\n#define IS_IVD_CONCEALMENT_APPLIED(x)       (x & (1 << IVD_APPLIEDCONCEALMENT))\n#define IS_IVD_INSUFFICIENTDATA_ERROR(x)    (x & (1 << IVD_INSUFFICIENTDATA))\n#define IS_IVD_CORRUPTEDDATA_ERROR(x)       (x & (1 << IVD_CORRUPTEDDATA))\n#define IS_IVD_CORRUPTEDHEADER_ERROR(x)     (x & (1 << IVD_CORRUPTEDHEADER))\n#define IS_IVD_UNSUPPORTEDINPUT_ERROR(x)    (x & (1 << IVD_UNSUPPORTEDINPUT))\n#define IS_IVD_UNSUPPORTEDPARAM_ERROR(x)    (x & (1 << IVD_UNSUPPORTEDPARAM))\n#define IS_IVD_FATAL_ERROR(x)               (x & (1 << IVD_FATALERROR))\n#define IS_IVD_INVALID_BITSTREAM_ERROR(x)   (x & (1 << IVD_INVALID_BITSTREAM))\n#define IS_IVD_INCOMPLETE_BITSTREAM_ERROR(x) (x & (1 << IVD_INCOMPLETE_BITSTREAM))\n\n\n/*****************************************************************************/\n/* API Function Prototype                                                    */\n/*****************************************************************************/\nIV_API_CALL_STATUS_T ih264d_api_function(iv_obj_t *ps_handle, void *pv_api_ip,void *pv_api_op);\n\n/*****************************************************************************/\n/* Enums                                                                     */\n/*****************************************************************************/\n/* Codec Error codes for H264 ASP Decoder                                   */\n\ntypedef enum {\n\n    IH264D_VID_HDR_DEC_NUM_FRM_BUF_NOT_SUFFICIENT   = IVD_DUMMY_ELEMENT_FOR_CODEC_EXTENSIONS + 1,\n\n}IH264D_ERROR_CODES_T;\n\n/*****************************************************************************/\n/* Extended Structures                                                       */\n/*****************************************************************************/\n\n\n/*****************************************************************************/\n/*  Delete Codec                                                             */\n/*****************************************************************************/\n\n\ntypedef struct {\n    ivd_delete_ip_t               s_ivd_delete_ip_t;\n}ih264d_delete_ip_t;\n\n\ntypedef struct{\n    ivd_delete_op_t               s_ivd_delete_op_t;\n}ih264d_delete_op_t;\n\n\n/*****************************************************************************/\n/*   Initialize decoder                                                      */\n/*****************************************************************************/\n\n\ntypedef struct {\n    ivd_create_ip_t                         s_ivd_create_ip_t;\n}ih264d_create_ip_t;\n\n\ntypedef struct{\n    ivd_create_op_t                         s_ivd_create_op_t;\n}ih264d_create_op_t;\n\n\n/*****************************************************************************/\n/*   Video Decode                                                            */\n/*****************************************************************************/\n\n\ntypedef struct {\n    ivd_video_decode_ip_t                   s_ivd_video_decode_ip_t;\n}ih264d_video_decode_ip_t;\n\n\ntypedef struct{\n    ivd_video_decode_op_t                   s_ivd_video_decode_op_t;\n}ih264d_video_decode_op_t;\n\n\n/*****************************************************************************/\n/*   Get Display Frame                                                       */\n/*****************************************************************************/\n\n\ntypedef struct\n{\n    ivd_get_display_frame_ip_t              s_ivd_get_display_frame_ip_t;\n}ih264d_get_display_frame_ip_t;\n\n\ntypedef struct\n{\n    ivd_get_display_frame_op_t              s_ivd_get_display_frame_op_t;\n}ih264d_get_display_frame_op_t;\n\n/*****************************************************************************/\n/*   Set Display Frame                                                       */\n/*****************************************************************************/\n\n\ntypedef struct\n{\n    ivd_set_display_frame_ip_t              s_ivd_set_display_frame_ip_t;\n}ih264d_set_display_frame_ip_t;\n\n\ntypedef struct\n{\n    ivd_set_display_frame_op_t              s_ivd_set_display_frame_op_t;\n}ih264d_set_display_frame_op_t;\n\n/*****************************************************************************/\n/*   Release Display Buffers                                                 */\n/*****************************************************************************/\n\n\ntypedef struct\n{\n    ivd_rel_display_frame_ip_t                  s_ivd_rel_display_frame_ip_t;\n}ih264d_rel_display_frame_ip_t;\n\n\ntypedef struct\n{\n    ivd_rel_display_frame_op_t                  s_ivd_rel_display_frame_op_t;\n}ih264d_rel_display_frame_op_t;\n\n\ntypedef enum {\n    /** Set number of cores/threads to be used */\n    IH264D_CMD_CTL_SET_NUM_CORES         = IVD_CMD_CTL_CODEC_SUBCMD_START,\n\n    /** Set processor details */\n    IH264D_CMD_CTL_SET_PROCESSOR         = IVD_CMD_CTL_CODEC_SUBCMD_START + 0x001,\n\n    /** Get display buffer dimensions */\n    IH264D_CMD_CTL_GET_BUFFER_DIMENSIONS = IVD_CMD_CTL_CODEC_SUBCMD_START + 0x100,\n\n    /** Get VUI parameters */\n    IH264D_CMD_CTL_GET_VUI_PARAMS        = IVD_CMD_CTL_CODEC_SUBCMD_START + 0x101,\n\n    /** Enable/disable GPU, supported on select platforms */\n    IH264D_CMD_CTL_GPU_ENABLE_DISABLE    = IVD_CMD_CTL_CODEC_SUBCMD_START + 0x200,\n\n    /** Set degrade level */\n    IH264D_CMD_CTL_DEGRADE               = IVD_CMD_CTL_CODEC_SUBCMD_START + 0x300,\n\n    /** Get SEI MDCV parameters */\n    IH264D_CMD_CTL_GET_SEI_MDCV_PARAMS   = IVD_CMD_CTL_CODEC_SUBCMD_START + 0x301,\n\n    /** Get SEI CLL parameters */\n    IH264D_CMD_CTL_GET_SEI_CLL_PARAMS    = IVD_CMD_CTL_CODEC_SUBCMD_START + 0x302,\n\n    /** Get SEI AVE parameters */\n    IH264D_CMD_CTL_GET_SEI_AVE_PARAMS    = IVD_CMD_CTL_CODEC_SUBCMD_START + 0x303,\n\n    /** Get SEI CCV parameters */\n    IH264D_CMD_CTL_GET_SEI_CCV_PARAMS    = IVD_CMD_CTL_CODEC_SUBCMD_START + 0x304\n\n}IH264D_CMD_CTL_SUB_CMDS;\n/*****************************************************************************/\n/*   Video control  Flush                                                    */\n/*****************************************************************************/\n\n\ntypedef struct{\n    ivd_ctl_flush_ip_t                      s_ivd_ctl_flush_ip_t;\n}ih264d_ctl_flush_ip_t;\n\n\ntypedef struct{\n    ivd_ctl_flush_op_t                      s_ivd_ctl_flush_op_t;\n}ih264d_ctl_flush_op_t;\n\n/*****************************************************************************/\n/*   Video control reset                                                     */\n/*****************************************************************************/\n\n\ntypedef struct{\n    ivd_ctl_reset_ip_t                      s_ivd_ctl_reset_ip_t;\n}ih264d_ctl_reset_ip_t;\n\n\ntypedef struct{\n    ivd_ctl_reset_op_t                      s_ivd_ctl_reset_op_t;\n}ih264d_ctl_reset_op_t;\n\n\n/*****************************************************************************/\n/*   Video control  Set Params                                               */\n/*****************************************************************************/\n\n\ntypedef struct {\n    ivd_ctl_set_config_ip_t             s_ivd_ctl_set_config_ip_t;\n}ih264d_ctl_set_config_ip_t;\n\n\ntypedef struct{\n    ivd_ctl_set_config_op_t             s_ivd_ctl_set_config_op_t;\n}ih264d_ctl_set_config_op_t;\n\n/*****************************************************************************/\n/*   Video control:Get Buf Info                                              */\n/*****************************************************************************/\n\n\ntypedef struct{\n    ivd_ctl_getbufinfo_ip_t             s_ivd_ctl_getbufinfo_ip_t;\n}ih264d_ctl_getbufinfo_ip_t;\n\n\n\ntypedef struct{\n    ivd_ctl_getbufinfo_op_t             s_ivd_ctl_getbufinfo_op_t;\n}ih264d_ctl_getbufinfo_op_t;\n\n\n/*****************************************************************************/\n/*   Video control:Getstatus Call                                            */\n/*****************************************************************************/\n\n\ntypedef struct{\n    ivd_ctl_getstatus_ip_t                  s_ivd_ctl_getstatus_ip_t;\n}ih264d_ctl_getstatus_ip_t;\n\n\n\ntypedef struct{\n    ivd_ctl_getstatus_op_t                  s_ivd_ctl_getstatus_op_t;\n}ih264d_ctl_getstatus_op_t;\n\n\n/*****************************************************************************/\n/*   Video control:Get Version Info                                          */\n/*****************************************************************************/\n\n\ntypedef struct{\n    ivd_ctl_getversioninfo_ip_t         s_ivd_ctl_getversioninfo_ip_t;\n}ih264d_ctl_getversioninfo_ip_t;\n\n\n\ntypedef struct{\n    ivd_ctl_getversioninfo_op_t         s_ivd_ctl_getversioninfo_op_t;\n}ih264d_ctl_getversioninfo_op_t;\n\ntypedef struct{\n\n    /**\n     * u4_size\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n\n    /**\n     * sub_cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n\n    /**\n     * Pictures that are are degraded\n     * 0 : No degrade\n     * 1 : Only on non-reference frames\n     * 2 : Use interval specified by u4_nondegrade_interval\n     * 3 : All non-key frames\n     * 4 : All frames\n     */\n    WORD32                                     i4_degrade_pics;\n\n    /**\n     * Interval for pictures which are completely decoded without any degradation\n     */\n    WORD32                                     i4_nondegrade_interval;\n\n    /**\n     * bit position (lsb is zero): Type of degradation\n     * 1 : Disable deblocking\n     * 2 : Faster inter prediction filters\n     * 3 : Fastest inter prediction filters\n     */\n    WORD32                                     i4_degrade_type;\n\n}ih264d_ctl_degrade_ip_t;\n\ntypedef struct\n{\n    /**\n     * u4_size\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * error_code\n     */\n    UWORD32                                     u4_error_code;\n}ih264d_ctl_degrade_op_t;\n\ntypedef struct{\n    UWORD32                                     u4_size;\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n    UWORD32                                     u4_disable_deblk_level;\n}ih264d_ctl_disable_deblock_ip_t;\n\ntypedef struct{\n    UWORD32                                     u4_size;\n    UWORD32                                     u4_error_code;\n}ih264d_ctl_disable_deblock_op_t;\n\n\ntypedef struct{\n    UWORD32                                     u4_size;\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n    UWORD32                                     u4_num_cores;\n}ih264d_ctl_set_num_cores_ip_t;\n\ntypedef struct{\n    UWORD32                                     u4_size;\n    UWORD32                                     u4_error_code;\n}ih264d_ctl_set_num_cores_op_t;\n\ntypedef struct\n{\n     /**\n      * i4_size\n      */\n    UWORD32                                     u4_size;\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n    /**\n     * sub cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n    /**\n     * Processor type\n     */\n    UWORD32                                     u4_arch;\n    /**\n     * SOC type\n     */\n    UWORD32                                     u4_soc;\n\n    /**\n     * num_cores\n     */\n    UWORD32                                     u4_num_cores;\n\n}ih264d_ctl_set_processor_ip_t;\n\ntypedef struct\n{\n    /**\n     * i4_size\n     */\n    UWORD32                                     u4_size;\n    /**\n     * error_code\n     */\n    UWORD32                                     u4_error_code;\n}ih264d_ctl_set_processor_op_t;\n\ntypedef struct{\n    UWORD32                                     u4_size;\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n}ih264d_ctl_get_frame_dimensions_ip_t;\n\n\ntypedef struct{\n    UWORD32                                     u4_size;\n    UWORD32                                     u4_error_code;\n    UWORD32                                     u4_x_offset[3];\n    UWORD32                                     u4_y_offset[3];\n    UWORD32                                     u4_disp_wd[3];\n    UWORD32                                     u4_disp_ht[3];\n    UWORD32                                     u4_buffer_wd[3];\n    UWORD32                                     u4_buffer_ht[3];\n}ih264d_ctl_get_frame_dimensions_op_t;\n\ntypedef struct\n{\n    UWORD32                                     u4_size;\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n}ih264d_ctl_get_vui_params_ip_t;\n\ntypedef struct\n{\n    UWORD32                                     u4_size;\n    UWORD32                                     u4_error_code;\n    UWORD8                                      u1_aspect_ratio_idc;\n    UWORD16                                     u2_sar_width;\n    UWORD16                                     u2_sar_height;\n    UWORD8                                      u1_overscan_appropriate_flag;\n    UWORD8                                      u1_video_format;\n    UWORD8                                      u1_video_full_range_flag;\n    UWORD8                                      u1_colour_primaries;\n    UWORD8                                      u1_tfr_chars;\n    UWORD8                                      u1_matrix_coeffs;\n    UWORD8                                      u1_cr_top_field;\n    UWORD8                                      u1_cr_bottom_field;\n    UWORD32                                     u4_num_units_in_tick;\n    UWORD32                                     u4_time_scale;\n    UWORD8                                      u1_fixed_frame_rate_flag;\n    UWORD8                                      u1_nal_hrd_params_present;\n    UWORD8                                      u1_vcl_hrd_params_present;\n    UWORD8                                      u1_low_delay_hrd_flag;\n    UWORD8                                      u1_pic_struct_present_flag;\n    UWORD8                                      u1_bitstream_restriction_flag;\n    UWORD8                                      u1_mv_over_pic_boundaries_flag;\n    UWORD32                                     u4_max_bytes_per_pic_denom;\n    UWORD32                                     u4_max_bits_per_mb_denom;\n    UWORD32                                     u4_log2_max_mv_length_horz;\n    UWORD32                                     u4_log2_max_mv_length_vert;\n    UWORD32                                     u4_num_reorder_frames;\n    UWORD32                                     u4_max_dec_frame_buffering;\n}ih264d_ctl_get_vui_params_op_t;\n\n\ntypedef struct\n{\n    /**\n     * u4_size\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n\n    /**\n     * sub_cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n}ih264d_ctl_get_sei_mdcv_params_ip_t;\n\ntypedef struct\n{\n    /**\n     * u4_size\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * error_code\n     */\n    UWORD32                                     u4_error_code;\n\n    /**\n     * Array to store the display_primaries_x values\n     */\n    UWORD16                                     au2_display_primaries_x[NUM_SEI_MDCV_PRIMARIES];\n\n    /**\n     * Array to store the display_primaries_y values\n     */\n    UWORD16                                     au2_display_primaries_y[NUM_SEI_MDCV_PRIMARIES];\n\n    /**\n     * Variable to store the white point x value\n     */\n    UWORD16                                     u2_white_point_x;\n\n    /**\n     * Variable to store the white point y value\n     */\n    UWORD16                                     u2_white_point_y;\n\n    /**\n     * Variable to store the max display mastering luminance value\n     */\n    UWORD32                                     u4_max_display_mastering_luminance;\n\n    /**\n     * Variable to store the min display mastering luminance value\n     */\n    UWORD32                                     u4_min_display_mastering_luminance;\n}ih264d_ctl_get_sei_mdcv_params_op_t;\n\ntypedef struct\n{\n    /**\n     * u4_size\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n\n    /**\n     * sub_cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n}ih264d_ctl_get_sei_cll_params_ip_t;\n\ntypedef struct\n{\n    /**\n     * u4_size\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * error_code\n     */\n    UWORD32                                     u4_error_code;\n\n    /**\n     * The maximum pixel intensity of all samples\n     */\n    UWORD16                                     u2_max_content_light_level;\n\n    /**\n     * The average pixel intensity of all samples\n     */\n    UWORD16                                     u2_max_pic_average_light_level;\n} ih264d_ctl_get_sei_cll_params_op_t;\n\ntypedef struct\n{\n    /**\n     * u4_size\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n\n    /**\n     * sub_cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n}ih264d_ctl_get_sei_ave_params_ip_t;\n\ntypedef struct\n{\n    /**\n     * u4_size\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * error_code\n     */\n    UWORD32                                     u4_error_code;\n\n    /**\n     * specifies the environmental illluminance of the ambient viewing environment\n     */\n    UWORD32                                     u4_ambient_illuminance;\n\n    /*\n     * specify the normalized x chromaticity coordinates of the\n     * environmental ambient light in the nominal viewing environment\n     */\n    UWORD16                                     u2_ambient_light_x;\n\n    /*\n     * specify the normalized y chromaticity coordinates of the\n     * environmental ambient light in the nominal viewing environment\n     */\n    UWORD16                                     u2_ambient_light_y;\n} ih264d_ctl_get_sei_ave_params_op_t;\n\ntypedef struct\n{\n    /**\n     * u4_size\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n\n    /**\n     * sub_cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n}ih264d_ctl_get_sei_ccv_params_ip_t;\n\ntypedef struct\n{\n    /**\n     * u4_size\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * error_code\n     */\n    UWORD32                                     u4_error_code;\n\n    /*\n     * Flag used to control persistence of CCV SEI messages\n     */\n    UWORD8                                      u1_ccv_cancel_flag;\n\n    /*\n     * specifies the persistence of the CCV SEI message for the current layer\n     */\n    UWORD8                                      u1_ccv_persistence_flag;\n\n    /*\n     * specifies the presence of syntax elements ccv_primaries_x and ccv_primaries_y\n     */\n    UWORD8                                      u1_ccv_primaries_present_flag;\n\n    /*\n     * specifies that the syntax element ccv_min_luminance_value is present\n     */\n    UWORD8                                      u1_ccv_min_luminance_value_present_flag;\n\n    /*\n     * specifies that the syntax element ccv_max_luminance_value is present\n     */\n    UWORD8                                      u1_ccv_max_luminance_value_present_flag;\n\n    /*\n     * specifies that the syntax element ccv_avg_luminance_value is present\n     */\n    UWORD8                                      u1_ccv_avg_luminance_value_present_flag;\n\n    /*\n     * shall be equal to 0 in bitstreams conforming to this version. Other values\n     * for reserved_zero_2bits are reserved for future use\n     */\n    UWORD8                                      u1_ccv_reserved_zero_2bits;\n\n    /*\n     * specify the normalized x chromaticity coordinates of the colour\n     * primary component c of the nominal content colour volume\n     */\n    WORD32                                      ai4_ccv_primaries_x[NUM_SEI_CCV_PRIMARIES];\n\n    /*\n     * specify the normalized y chromaticity coordinates of the colour\n     * primary component c of the nominal content colour volume\n     */\n    WORD32                                      ai4_ccv_primaries_y[NUM_SEI_CCV_PRIMARIES];\n\n    /*\n     * specifies the normalized minimum luminance value\n     */\n    UWORD32                                     u4_ccv_min_luminance_value;\n\n    /*\n     * specifies the normalized maximum luminance value\n     */\n    UWORD32                                     u4_ccv_max_luminance_value;\n\n    /*\n     * specifies the normalized average luminance value\n     */\n    UWORD32                                     u4_ccv_avg_luminance_value;\n} ih264d_ctl_get_sei_ccv_params_op_t;\n\n\n#ifdef __cplusplus\n} /* closing brace for extern \"C\" */\n#endif\n#endif /* _IH264D_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_api.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n * Modified for use with Cemu emulator project\n */\n\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264d_api.c                                         */\n/*                                                                           */\n/*  Description       : Has all  API related functions                       */\n/*                                                                           */\n/*                                                                           */\n/*  List of Functions : api_check_struct_sanity                              */\n/*          ih264d_set_processor                                             */\n/*          ih264d_create                                                    */\n/*          ih264d_delete                                                    */\n/*          ih264d_init                                                      */\n/*          ih264d_map_error                                                 */\n/*          ih264d_video_decode                                              */\n/*          ih264d_get_version                                               */\n/*          ih264d_get_display_frame                                         */\n/*          ih264d_set_display_frame                                         */\n/*          ih264d_set_flush_mode                                            */\n/*          ih264d_get_status                                                */\n/*          ih264d_get_buf_info                                              */\n/*          ih264d_set_params                                                */\n/*          ih264d_set_default_params                                        */\n/*          ih264d_reset                                                     */\n/*          ih264d_ctl                                                       */\n/*          ih264d_rel_display_frame                                         */\n/*          ih264d_set_degrade                                               */\n/*          ih264d_get_frame_dimensions                                      */\n/*          ih264d_set_num_cores                                             */\n/*          ih264d_fill_output_struct_from_context                           */\n/*          ih264d_api_function                                              */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         14 10 2008   100356(SKV)     Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_tables.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264d.h\"\n#include \"ih264d_defs.h\"\n\n#include <string.h>\n#include <limits.h>\n#include <stddef.h>\n\n#include \"ih264d_inter_pred.h\"\n\n#include \"ih264d_structs.h\"\n#include \"ih264d_nal.h\"\n#include \"ih264d_error_handler.h\"\n\n#include \"ih264d_defs.h\"\n\n#include \"ithread.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_function_selector.h\"\n#include \"ih264_error.h\"\n#include \"ih264_disp_mgr.h\"\n#include \"ih264_buf_mgr.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_parse_cabac.h\"\n#include \"ih264d_utils.h\"\n#include \"ih264d_format_conv.h\"\n#include \"ih264d_parse_headers.h\"\n#include \"ih264d_thread_compute_bs.h\"\n#include <assert.h>\n\n\n/*********************/\n/* Codec Versioning  */\n/*********************/\n//Move this to where it is used\n#define CODEC_NAME              \"H264VDEC\"\n#define CODEC_RELEASE_TYPE      \"production\"\n#define CODEC_RELEASE_VER       \"05.00\"\n#define CODEC_VENDOR            \"ITTIAM\"\n#define MAXVERSION_STRLEN       511\n#ifdef ANDROID\n#define VERSION(version_string, codec_name, codec_release_type, codec_release_ver, codec_vendor)    \\\n    snprintf(version_string, MAXVERSION_STRLEN,                                                     \\\n             \"@(#)Id:%s_%s Ver:%s Released by %s\",                                                  \\\n             codec_name, codec_release_type, codec_release_ver, codec_vendor)\n#else\n#define VERSION(version_string, codec_name, codec_release_type, codec_release_ver, codec_vendor)    \\\n    snprintf(version_string, MAXVERSION_STRLEN,                                                     \\\n             \"@(#)Id:%s_%s Ver:%s Released by %s Build: %s @ %s\",                                   \\\n             codec_name, codec_release_type, codec_release_ver, codec_vendor, __DATE__, __TIME__)\n#endif\n\n\n#define MIN_IN_BUFS             1\n#define MIN_OUT_BUFS_420        3\n#define MIN_OUT_BUFS_422ILE     1\n#define MIN_OUT_BUFS_RGB565     1\n#define MIN_OUT_BUFS_420SP      2\n\n#define NUM_FRAMES_LIMIT_ENABLED 0\n\n#if NUM_FRAMES_LIMIT_ENABLED\n#define NUM_FRAMES_LIMIT 10000\n#else\n#define NUM_FRAMES_LIMIT 0x7FFFFFFF\n#endif\n\n\nUWORD32 ih264d_get_extra_mem_external(UWORD32 width, UWORD32 height);\nWORD32 ih264d_get_frame_dimensions(iv_obj_t *dec_hdl,\n                                   void *pv_api_ip,\n                                   void *pv_api_op);\nWORD32 ih264d_get_vui_params(iv_obj_t *dec_hdl,\n                             void *pv_api_ip,\n                             void *pv_api_op);\n\nWORD32 ih264d_get_sei_mdcv_params(iv_obj_t *dec_hdl,\n                                  void *pv_api_ip,\n                                  void *pv_api_op);\n\nWORD32 ih264d_get_sei_cll_params(iv_obj_t *dec_hdl,\n                                 void *pv_api_ip,\n                                 void *pv_api_op);\n\nWORD32 ih264d_get_sei_ave_params(iv_obj_t *dec_hdl,\n                                 void *pv_api_ip,\n                                 void *pv_api_op);\n\nWORD32 ih264d_get_sei_ccv_params(iv_obj_t *dec_hdl,\n                                 void *pv_api_ip,\n                                 void *pv_api_op);\n\nWORD32 ih264d_set_num_cores(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op);\n\nWORD32 ih264d_deblock_display(dec_struct_t *ps_dec);\n\nvoid ih264d_signal_decode_thread(dec_struct_t *ps_dec);\n\nvoid ih264d_signal_bs_deblk_thread(dec_struct_t *ps_dec);\nvoid ih264d_decode_picture_thread(dec_struct_t *ps_dec);\n\nWORD32 ih264d_set_degrade(iv_obj_t *ps_codec_obj,\n                          void *pv_api_ip,\n                          void *pv_api_op);\n\nvoid ih264d_fill_output_struct_from_context(dec_struct_t *ps_dec,\n                                            ivd_video_decode_op_t *ps_dec_op);\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_export_sei_params \\endif\n *\n * \\brief\n *    Exports sei params from decoder to application.\n *\n * \\return\n *    0 on Success and error code otherwise\n **************************************************************************\n */\n\nvoid ih264d_export_sei_params(ivd_sei_decode_op_t *ps_sei_decode_op, dec_struct_t *ps_dec)\n{\n    WORD32 i4_status = IV_SUCCESS;\n    sei *ps_sei = (sei *)ps_dec->pv_disp_sei_params;\n\n    i4_status = ih264d_export_sei_mdcv_params(ps_sei_decode_op, ps_sei, &ps_dec->s_sei_export);\n    i4_status = ih264d_export_sei_cll_params(ps_sei_decode_op, ps_sei, &ps_dec->s_sei_export);\n    i4_status = ih264d_export_sei_ave_params(ps_sei_decode_op, ps_sei, &ps_dec->s_sei_export);\n    i4_status = ih264d_export_sei_ccv_params(ps_sei_decode_op, ps_sei, &ps_dec->s_sei_export);\n\n    UNUSED(i4_status);\n}\n\nstatic IV_API_CALL_STATUS_T api_check_struct_sanity(iv_obj_t *ps_handle,\n                                                    void *pv_api_ip,\n                                                    void *pv_api_op)\n{\n    IVD_API_COMMAND_TYPE_T e_cmd;\n    UWORD32 *pu4_api_ip;\n    UWORD32 *pu4_api_op;\n    UWORD32 i, j;\n\n    if(NULL == pv_api_op)\n        return (IV_FAIL);\n\n    if(NULL == pv_api_ip)\n        return (IV_FAIL);\n\n    pu4_api_ip = (UWORD32 *)pv_api_ip;\n    pu4_api_op = (UWORD32 *)pv_api_op;\n    e_cmd = *(pu4_api_ip + 1);\n\n    /* error checks on handle */\n    switch((WORD32)e_cmd)\n    {\n        case IVD_CMD_CREATE:\n            break;\n\n        case IVD_CMD_REL_DISPLAY_FRAME:\n        case IVD_CMD_SET_DISPLAY_FRAME:\n        case IVD_CMD_GET_DISPLAY_FRAME:\n        case IVD_CMD_VIDEO_DECODE:\n        case IVD_CMD_DELETE:\n        case IVD_CMD_VIDEO_CTL:\n            if(ps_handle == NULL)\n            {\n                *(pu4_api_op + 1) |= 1 << IVD_UNSUPPORTEDPARAM;\n                *(pu4_api_op + 1) |= IVD_HANDLE_NULL;\n                return IV_FAIL;\n            }\n\n            if(ps_handle->u4_size != sizeof(iv_obj_t))\n            {\n                *(pu4_api_op + 1) |= 1 << IVD_UNSUPPORTEDPARAM;\n                *(pu4_api_op + 1) |= IVD_HANDLE_STRUCT_SIZE_INCORRECT;\n                return IV_FAIL;\n            }\n\n            if(ps_handle->pv_fxns != ih264d_api_function)\n            {\n                *(pu4_api_op + 1) |= 1 << IVD_UNSUPPORTEDPARAM;\n                *(pu4_api_op + 1) |= IVD_INVALID_HANDLE_NULL;\n                return IV_FAIL;\n            }\n\n            if(ps_handle->pv_codec_handle == NULL)\n            {\n                *(pu4_api_op + 1) |= 1 << IVD_UNSUPPORTEDPARAM;\n                *(pu4_api_op + 1) |= IVD_INVALID_HANDLE_NULL;\n                return IV_FAIL;\n            }\n            break;\n        default:\n            *(pu4_api_op + 1) |= 1 << IVD_UNSUPPORTEDPARAM;\n            *(pu4_api_op + 1) |= IVD_INVALID_API_CMD;\n            return IV_FAIL;\n    }\n\n    switch((WORD32)e_cmd)\n    {\n        case IVD_CMD_CREATE:\n        {\n            ih264d_create_ip_t *ps_ip = (ih264d_create_ip_t *)pv_api_ip;\n            ih264d_create_op_t *ps_op = (ih264d_create_op_t *)pv_api_op;\n\n\n            ps_op->s_ivd_create_op_t.u4_error_code = 0;\n\n            if((ps_ip->s_ivd_create_ip_t.u4_size > sizeof(ih264d_create_ip_t))\n                            || (ps_ip->s_ivd_create_ip_t.u4_size\n                                            < sizeof(ivd_create_ip_t)))\n            {\n                ps_op->s_ivd_create_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_create_op_t.u4_error_code |=\n                                IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                H264_DEC_DEBUG_PRINT(\"\\n\");\n                return (IV_FAIL);\n            }\n\n            if((ps_op->s_ivd_create_op_t.u4_size != sizeof(ih264d_create_op_t))\n                            && (ps_op->s_ivd_create_op_t.u4_size\n                                            != sizeof(ivd_create_op_t)))\n            {\n                ps_op->s_ivd_create_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_create_op_t.u4_error_code |=\n                                IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                H264_DEC_DEBUG_PRINT(\"\\n\");\n                return (IV_FAIL);\n            }\n\n\n            if((ps_ip->s_ivd_create_ip_t.e_output_format != IV_YUV_420P)\n                            && (ps_ip->s_ivd_create_ip_t.e_output_format\n                                            != IV_YUV_422ILE)\n                            && (ps_ip->s_ivd_create_ip_t.e_output_format\n                                            != IV_RGB_565)\n                            && (ps_ip->s_ivd_create_ip_t.e_output_format\n                                            != IV_YUV_420SP_UV)\n                            && (ps_ip->s_ivd_create_ip_t.e_output_format\n                                            != IV_YUV_420SP_VU))\n            {\n                ps_op->s_ivd_create_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_create_op_t.u4_error_code |=\n                                IVD_INIT_DEC_COL_FMT_NOT_SUPPORTED;\n                H264_DEC_DEBUG_PRINT(\"\\n\");\n                return (IV_FAIL);\n            }\n\n        }\n            break;\n\n        case IVD_CMD_GET_DISPLAY_FRAME:\n        {\n            ih264d_get_display_frame_ip_t *ps_ip =\n                            (ih264d_get_display_frame_ip_t *)pv_api_ip;\n            ih264d_get_display_frame_op_t *ps_op =\n                            (ih264d_get_display_frame_op_t *)pv_api_op;\n\n            ps_op->s_ivd_get_display_frame_op_t.u4_error_code = 0;\n\n            if((ps_ip->s_ivd_get_display_frame_ip_t.u4_size\n                            != sizeof(ih264d_get_display_frame_ip_t))\n                            && (ps_ip->s_ivd_get_display_frame_ip_t.u4_size\n                                            != sizeof(ivd_get_display_frame_ip_t)))\n            {\n                ps_op->s_ivd_get_display_frame_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_get_display_frame_op_t.u4_error_code |=\n                                IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                return (IV_FAIL);\n            }\n\n            if((ps_op->s_ivd_get_display_frame_op_t.u4_size\n                            != sizeof(ih264d_get_display_frame_op_t))\n                            && (ps_op->s_ivd_get_display_frame_op_t.u4_size\n                                            != sizeof(ivd_get_display_frame_op_t)))\n            {\n                ps_op->s_ivd_get_display_frame_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_get_display_frame_op_t.u4_error_code |=\n                                IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                return (IV_FAIL);\n            }\n        }\n            break;\n\n        case IVD_CMD_REL_DISPLAY_FRAME:\n        {\n            ih264d_rel_display_frame_ip_t *ps_ip =\n                            (ih264d_rel_display_frame_ip_t *)pv_api_ip;\n            ih264d_rel_display_frame_op_t *ps_op =\n                            (ih264d_rel_display_frame_op_t *)pv_api_op;\n\n            ps_op->s_ivd_rel_display_frame_op_t.u4_error_code = 0;\n\n            if((ps_ip->s_ivd_rel_display_frame_ip_t.u4_size\n                            != sizeof(ih264d_rel_display_frame_ip_t))\n                            && (ps_ip->s_ivd_rel_display_frame_ip_t.u4_size\n                                            != sizeof(ivd_rel_display_frame_ip_t)))\n            {\n                ps_op->s_ivd_rel_display_frame_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_rel_display_frame_op_t.u4_error_code |=\n                                IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                return (IV_FAIL);\n            }\n\n            if((ps_op->s_ivd_rel_display_frame_op_t.u4_size\n                            != sizeof(ih264d_rel_display_frame_op_t))\n                            && (ps_op->s_ivd_rel_display_frame_op_t.u4_size\n                                            != sizeof(ivd_rel_display_frame_op_t)))\n            {\n                ps_op->s_ivd_rel_display_frame_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_rel_display_frame_op_t.u4_error_code |=\n                                IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                return (IV_FAIL);\n            }\n\n        }\n            break;\n\n        case IVD_CMD_SET_DISPLAY_FRAME:\n        {\n            ih264d_set_display_frame_ip_t *ps_ip =\n                            (ih264d_set_display_frame_ip_t *)pv_api_ip;\n            ih264d_set_display_frame_op_t *ps_op =\n                            (ih264d_set_display_frame_op_t *)pv_api_op;\n            UWORD32 j;\n\n            ps_op->s_ivd_set_display_frame_op_t.u4_error_code = 0;\n\n            if((ps_ip->s_ivd_set_display_frame_ip_t.u4_size\n                            != sizeof(ih264d_set_display_frame_ip_t))\n                            && (ps_ip->s_ivd_set_display_frame_ip_t.u4_size\n                                            != sizeof(ivd_set_display_frame_ip_t)))\n            {\n                ps_op->s_ivd_set_display_frame_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_set_display_frame_op_t.u4_error_code |=\n                                IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                return (IV_FAIL);\n            }\n\n            if((ps_op->s_ivd_set_display_frame_op_t.u4_size\n                            != sizeof(ih264d_set_display_frame_op_t))\n                            && (ps_op->s_ivd_set_display_frame_op_t.u4_size\n                                            != sizeof(ivd_set_display_frame_op_t)))\n            {\n                ps_op->s_ivd_set_display_frame_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_set_display_frame_op_t.u4_error_code |=\n                                IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                return (IV_FAIL);\n            }\n\n            if(ps_ip->s_ivd_set_display_frame_ip_t.num_disp_bufs == 0)\n            {\n                ps_op->s_ivd_set_display_frame_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_set_display_frame_op_t.u4_error_code |=\n                                IVD_DISP_FRM_ZERO_OP_BUFS;\n                return IV_FAIL;\n            }\n\n            for(j = 0; j < ps_ip->s_ivd_set_display_frame_ip_t.num_disp_bufs;\n                            j++)\n            {\n                if(ps_ip->s_ivd_set_display_frame_ip_t.s_disp_buffer[j].u4_num_bufs\n                                == 0)\n                {\n                    ps_op->s_ivd_set_display_frame_op_t.u4_error_code |= 1\n                                    << IVD_UNSUPPORTEDPARAM;\n                    ps_op->s_ivd_set_display_frame_op_t.u4_error_code |=\n                                    IVD_DISP_FRM_ZERO_OP_BUFS;\n                    return IV_FAIL;\n                }\n\n                for(i = 0;\n                                i\n                                                < ps_ip->s_ivd_set_display_frame_ip_t.s_disp_buffer[j].u4_num_bufs;\n                                i++)\n                {\n                    if(ps_ip->s_ivd_set_display_frame_ip_t.s_disp_buffer[j].pu1_bufs[i]\n                                    == NULL)\n                    {\n                        ps_op->s_ivd_set_display_frame_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_set_display_frame_op_t.u4_error_code |=\n                                        IVD_DISP_FRM_OP_BUF_NULL;\n                        return IV_FAIL;\n                    }\n\n                    if(ps_ip->s_ivd_set_display_frame_ip_t.s_disp_buffer[j].u4_min_out_buf_size[i]\n                                    == 0)\n                    {\n                        ps_op->s_ivd_set_display_frame_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_set_display_frame_op_t.u4_error_code |=\n                                        IVD_DISP_FRM_ZERO_OP_BUF_SIZE;\n                        return IV_FAIL;\n                    }\n                }\n            }\n        }\n            break;\n\n        case IVD_CMD_VIDEO_DECODE:\n        {\n            ih264d_video_decode_ip_t *ps_ip =\n                            (ih264d_video_decode_ip_t *)pv_api_ip;\n            ih264d_video_decode_op_t *ps_op =\n                            (ih264d_video_decode_op_t *)pv_api_op;\n\n            H264_DEC_DEBUG_PRINT(\"The input bytes is: %d\",\n                                 ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes);\n            ps_op->s_ivd_video_decode_op_t.u4_error_code = 0;\n\n            if(ps_ip->s_ivd_video_decode_ip_t.u4_size\n                            != sizeof(ih264d_video_decode_ip_t)&&\n                            ps_ip->s_ivd_video_decode_ip_t.u4_size != offsetof(ivd_video_decode_ip_t, s_out_buffer))\n            {\n                ps_op->s_ivd_video_decode_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_video_decode_op_t.u4_error_code |=\n                                IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                return (IV_FAIL);\n            }\n\n            if(ps_op->s_ivd_video_decode_op_t.u4_size\n                            != sizeof(ih264d_video_decode_op_t)&&\n                            ps_op->s_ivd_video_decode_op_t.u4_size != offsetof(ivd_video_decode_op_t, u4_output_present))\n            {\n                ps_op->s_ivd_video_decode_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_video_decode_op_t.u4_error_code |=\n                                IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                return (IV_FAIL);\n            }\n\n        }\n            break;\n\n        case IVD_CMD_DELETE:\n        {\n            ih264d_delete_ip_t *ps_ip =\n                            (ih264d_delete_ip_t *)pv_api_ip;\n            ih264d_delete_op_t *ps_op =\n                            (ih264d_delete_op_t *)pv_api_op;\n\n            ps_op->s_ivd_delete_op_t.u4_error_code = 0;\n\n            if(ps_ip->s_ivd_delete_ip_t.u4_size\n                            != sizeof(ih264d_delete_ip_t))\n            {\n                ps_op->s_ivd_delete_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_delete_op_t.u4_error_code |=\n                                IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                return (IV_FAIL);\n            }\n\n            if(ps_op->s_ivd_delete_op_t.u4_size\n                            != sizeof(ih264d_delete_op_t))\n            {\n                ps_op->s_ivd_delete_op_t.u4_error_code |= 1\n                                << IVD_UNSUPPORTEDPARAM;\n                ps_op->s_ivd_delete_op_t.u4_error_code |=\n                                IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                return (IV_FAIL);\n            }\n\n        }\n            break;\n\n        case IVD_CMD_VIDEO_CTL:\n        {\n            UWORD32 *pu4_ptr_cmd;\n            UWORD32 sub_command;\n\n            pu4_ptr_cmd = (UWORD32 *)pv_api_ip;\n            pu4_ptr_cmd += 2;\n            sub_command = *pu4_ptr_cmd;\n\n            switch(sub_command)\n            {\n                case IVD_CMD_CTL_SETPARAMS:\n                {\n                    ih264d_ctl_set_config_ip_t *ps_ip;\n                    ih264d_ctl_set_config_op_t *ps_op;\n                    ps_ip = (ih264d_ctl_set_config_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_set_config_op_t *)pv_api_op;\n\n                    if(ps_ip->s_ivd_ctl_set_config_ip_t.u4_size\n                                    != sizeof(ih264d_ctl_set_config_ip_t))\n                    {\n                        ps_op->s_ivd_ctl_set_config_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_set_config_op_t.u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                }\n                    //no break; is needed here\n                case IVD_CMD_CTL_SETDEFAULT:\n                {\n                    ih264d_ctl_set_config_op_t *ps_op;\n                    ps_op = (ih264d_ctl_set_config_op_t *)pv_api_op;\n                    if(ps_op->s_ivd_ctl_set_config_op_t.u4_size\n                                    != sizeof(ih264d_ctl_set_config_op_t))\n                    {\n                        ps_op->s_ivd_ctl_set_config_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_set_config_op_t.u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                }\n                    break;\n\n                case IVD_CMD_CTL_GETPARAMS:\n                {\n                    ih264d_ctl_getstatus_ip_t *ps_ip;\n                    ih264d_ctl_getstatus_op_t *ps_op;\n\n                    ps_ip = (ih264d_ctl_getstatus_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_getstatus_op_t *)pv_api_op;\n                    if(ps_ip->s_ivd_ctl_getstatus_ip_t.u4_size\n                                    != sizeof(ih264d_ctl_getstatus_ip_t))\n                    {\n                        ps_op->s_ivd_ctl_getstatus_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_getstatus_op_t.u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                    if(ps_op->s_ivd_ctl_getstatus_op_t.u4_size\n                                    != sizeof(ih264d_ctl_getstatus_op_t))\n                    {\n                        ps_op->s_ivd_ctl_getstatus_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_getstatus_op_t.u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                }\n                    break;\n\n                case IVD_CMD_CTL_GETBUFINFO:\n                {\n                    ih264d_ctl_getbufinfo_ip_t *ps_ip;\n                    ih264d_ctl_getbufinfo_op_t *ps_op;\n                    ps_ip = (ih264d_ctl_getbufinfo_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_getbufinfo_op_t *)pv_api_op;\n\n                    if(ps_ip->s_ivd_ctl_getbufinfo_ip_t.u4_size\n                                    != sizeof(ih264d_ctl_getbufinfo_ip_t))\n                    {\n                        ps_op->s_ivd_ctl_getbufinfo_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_getbufinfo_op_t.u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                    if(ps_op->s_ivd_ctl_getbufinfo_op_t.u4_size\n                                    != sizeof(ih264d_ctl_getbufinfo_op_t))\n                    {\n                        ps_op->s_ivd_ctl_getbufinfo_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_getbufinfo_op_t.u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                }\n                    break;\n\n                case IVD_CMD_CTL_GETVERSION:\n                {\n                    ih264d_ctl_getversioninfo_ip_t *ps_ip;\n                    ih264d_ctl_getversioninfo_op_t *ps_op;\n                    ps_ip = (ih264d_ctl_getversioninfo_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_getversioninfo_op_t *)pv_api_op;\n                    if(ps_ip->s_ivd_ctl_getversioninfo_ip_t.u4_size\n                                    != sizeof(ih264d_ctl_getversioninfo_ip_t))\n                    {\n                        ps_op->s_ivd_ctl_getversioninfo_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_getversioninfo_op_t.u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                    if(ps_op->s_ivd_ctl_getversioninfo_op_t.u4_size\n                                    != sizeof(ih264d_ctl_getversioninfo_op_t))\n                    {\n                        ps_op->s_ivd_ctl_getversioninfo_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_getversioninfo_op_t.u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                }\n                    break;\n\n                case IVD_CMD_CTL_FLUSH:\n                {\n                    ih264d_ctl_flush_ip_t *ps_ip;\n                    ih264d_ctl_flush_op_t *ps_op;\n                    ps_ip = (ih264d_ctl_flush_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_flush_op_t *)pv_api_op;\n                    if(ps_ip->s_ivd_ctl_flush_ip_t.u4_size\n                                    != sizeof(ih264d_ctl_flush_ip_t))\n                    {\n                        ps_op->s_ivd_ctl_flush_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_flush_op_t.u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                    if(ps_op->s_ivd_ctl_flush_op_t.u4_size\n                                    != sizeof(ih264d_ctl_flush_op_t))\n                    {\n                        ps_op->s_ivd_ctl_flush_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_flush_op_t.u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                }\n                    break;\n\n                case IVD_CMD_CTL_RESET:\n                {\n                    ih264d_ctl_reset_ip_t *ps_ip;\n                    ih264d_ctl_reset_op_t *ps_op;\n                    ps_ip = (ih264d_ctl_reset_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_reset_op_t *)pv_api_op;\n                    if(ps_ip->s_ivd_ctl_reset_ip_t.u4_size\n                                    != sizeof(ih264d_ctl_reset_ip_t))\n                    {\n                        ps_op->s_ivd_ctl_reset_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_reset_op_t.u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                    if(ps_op->s_ivd_ctl_reset_op_t.u4_size\n                                    != sizeof(ih264d_ctl_reset_op_t))\n                    {\n                        ps_op->s_ivd_ctl_reset_op_t.u4_error_code |= 1\n                                        << IVD_UNSUPPORTEDPARAM;\n                        ps_op->s_ivd_ctl_reset_op_t.u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n                }\n                    break;\n\n                case IH264D_CMD_CTL_DEGRADE:\n                {\n                    ih264d_ctl_degrade_ip_t *ps_ip;\n                    ih264d_ctl_degrade_op_t *ps_op;\n\n                    ps_ip = (ih264d_ctl_degrade_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_degrade_op_t *)pv_api_op;\n\n                    if(ps_ip->u4_size != sizeof(ih264d_ctl_degrade_ip_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if(ps_op->u4_size != sizeof(ih264d_ctl_degrade_op_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if((ps_ip->i4_degrade_pics < 0)\n                                    || (ps_ip->i4_degrade_pics > 4)\n                                    || (ps_ip->i4_nondegrade_interval < 0)\n                                    || (ps_ip->i4_degrade_type < 0)\n                                    || (ps_ip->i4_degrade_type > 15))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        return IV_FAIL;\n                    }\n\n                    break;\n                }\n\n                case IH264D_CMD_CTL_GET_BUFFER_DIMENSIONS:\n                {\n                    ih264d_ctl_get_frame_dimensions_ip_t *ps_ip;\n                    ih264d_ctl_get_frame_dimensions_op_t *ps_op;\n\n                    ps_ip = (ih264d_ctl_get_frame_dimensions_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_get_frame_dimensions_op_t *)pv_api_op;\n\n                    if(ps_ip->u4_size\n                                    != sizeof(ih264d_ctl_get_frame_dimensions_ip_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if(ps_op->u4_size\n                                    != sizeof(ih264d_ctl_get_frame_dimensions_op_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    break;\n                }\n                case IH264D_CMD_CTL_GET_VUI_PARAMS:\n                {\n                    ih264d_ctl_get_vui_params_ip_t *ps_ip;\n                    ih264d_ctl_get_vui_params_op_t *ps_op;\n\n                    ps_ip =\n                                    (ih264d_ctl_get_vui_params_ip_t *)pv_api_ip;\n                    ps_op =\n                                    (ih264d_ctl_get_vui_params_op_t *)pv_api_op;\n\n                    if(ps_ip->u4_size\n                                    != sizeof(ih264d_ctl_get_vui_params_ip_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if(ps_op->u4_size\n                                    != sizeof(ih264d_ctl_get_vui_params_op_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    break;\n                }\n                case IH264D_CMD_CTL_GET_SEI_MDCV_PARAMS:\n                {\n                    ih264d_ctl_get_sei_mdcv_params_ip_t *ps_ip;\n                    ih264d_ctl_get_sei_mdcv_params_op_t *ps_op;\n\n                    ps_ip = (ih264d_ctl_get_sei_mdcv_params_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_get_sei_mdcv_params_op_t *)pv_api_op;\n\n                    if(ps_ip->u4_size != sizeof(ih264d_ctl_get_sei_mdcv_params_ip_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if(ps_op->u4_size != sizeof(ih264d_ctl_get_sei_mdcv_params_op_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    break;\n                }\n\n                case IH264D_CMD_CTL_GET_SEI_CLL_PARAMS:\n                {\n                    ih264d_ctl_get_sei_cll_params_ip_t *ps_ip;\n                    ih264d_ctl_get_sei_cll_params_op_t *ps_op;\n\n                    ps_ip = (ih264d_ctl_get_sei_cll_params_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_get_sei_cll_params_op_t *)pv_api_op;\n\n                    if(ps_ip->u4_size != sizeof(ih264d_ctl_get_sei_cll_params_ip_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if(ps_op->u4_size != sizeof(ih264d_ctl_get_sei_cll_params_op_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    break;\n                }\n\n                case IH264D_CMD_CTL_GET_SEI_AVE_PARAMS:\n                {\n                    ih264d_ctl_get_sei_ave_params_ip_t *ps_ip;\n                    ih264d_ctl_get_sei_ave_params_op_t *ps_op;\n\n                    ps_ip = (ih264d_ctl_get_sei_ave_params_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_get_sei_ave_params_op_t *)pv_api_op;\n\n                    if(ps_ip->u4_size != sizeof(ih264d_ctl_get_sei_ave_params_ip_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if(ps_op->u4_size != sizeof(ih264d_ctl_get_sei_ave_params_op_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    break;\n                }\n\n                case IH264D_CMD_CTL_GET_SEI_CCV_PARAMS:\n                {\n                    ih264d_ctl_get_sei_ccv_params_ip_t *ps_ip;\n                    ih264d_ctl_get_sei_ccv_params_op_t *ps_op;\n\n                    ps_ip = (ih264d_ctl_get_sei_ccv_params_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_get_sei_ccv_params_op_t *)pv_api_op;\n\n                    if(ps_ip->u4_size != sizeof(ih264d_ctl_get_sei_ccv_params_ip_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if(ps_op->u4_size != sizeof(ih264d_ctl_get_sei_ccv_params_op_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    break;\n                }\n\n                case IH264D_CMD_CTL_SET_NUM_CORES:\n                {\n                    ih264d_ctl_set_num_cores_ip_t *ps_ip;\n                    ih264d_ctl_set_num_cores_op_t *ps_op;\n\n                    ps_ip = (ih264d_ctl_set_num_cores_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_set_num_cores_op_t *)pv_api_op;\n\n                    if(ps_ip->u4_size != sizeof(ih264d_ctl_set_num_cores_ip_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if(ps_op->u4_size != sizeof(ih264d_ctl_set_num_cores_op_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if((ps_ip->u4_num_cores != 1) && (ps_ip->u4_num_cores != 2)\n                                    && (ps_ip->u4_num_cores != 3)\n                                    && (ps_ip->u4_num_cores != 4))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        return IV_FAIL;\n                    }\n                    break;\n                }\n                case IH264D_CMD_CTL_SET_PROCESSOR:\n                {\n                    ih264d_ctl_set_processor_ip_t *ps_ip;\n                    ih264d_ctl_set_processor_op_t *ps_op;\n\n                    ps_ip = (ih264d_ctl_set_processor_ip_t *)pv_api_ip;\n                    ps_op = (ih264d_ctl_set_processor_op_t *)pv_api_op;\n\n                    if(ps_ip->u4_size != sizeof(ih264d_ctl_set_processor_ip_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_IP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    if(ps_op->u4_size != sizeof(ih264d_ctl_set_processor_op_t))\n                    {\n                        ps_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                        ps_op->u4_error_code |=\n                                        IVD_OP_API_STRUCT_SIZE_INCORRECT;\n                        return IV_FAIL;\n                    }\n\n                    break;\n                }\n                default:\n                    *(pu4_api_op + 1) |= 1 << IVD_UNSUPPORTEDPARAM;\n                    *(pu4_api_op + 1) |= IVD_UNSUPPORTED_API_CMD;\n                    return IV_FAIL;\n                    break;\n            }\n        }\n            break;\n    }\n\n    return IV_SUCCESS;\n}\n\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Sets Processor type\n *\n * @par Description:\n *  Sets Processor type\n *\n * @param[in] ps_codec_obj\n *  Pointer to codec object at API level\n *\n * @param[in] pv_api_ip\n *  Pointer to input argument structure\n *\n * @param[out] pv_api_op\n *  Pointer to output argument structure\n *\n * @returns  Status\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\n\nWORD32 ih264d_set_processor(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n    ih264d_ctl_set_processor_ip_t *ps_ip;\n    ih264d_ctl_set_processor_op_t *ps_op;\n    dec_struct_t *ps_codec = (dec_struct_t *)dec_hdl->pv_codec_handle;\n\n    ps_ip = (ih264d_ctl_set_processor_ip_t *)pv_api_ip;\n    ps_op = (ih264d_ctl_set_processor_op_t *)pv_api_op;\n\n    ps_codec->e_processor_arch = (IVD_ARCH_T)ps_ip->u4_arch;\n    ps_codec->e_processor_soc = (IVD_SOC_T)ps_ip->u4_soc;\n\n    ih264d_init_function_ptr(ps_codec);\n\n    ps_op->u4_error_code = 0;\n    return IV_SUCCESS;\n}\n\n\n/**************************************************************************\n * \\if Function name : ih264d_init_decoder \\endif\n *\n *\n * \\brief\n *    Initializes the decoder\n *\n * \\param apiVersion               : Version of the api being used.\n * \\param errorHandlingMechanism   : Mechanism to be used for errror handling.\n * \\param postFilteringType: Type of post filtering operation to be used.\n * \\param uc_outputFormat: Format of the decoded picture [default 4:2:0].\n * \\param uc_dispBufs: Number of Display Buffers.\n * \\param p_NALBufAPI: Pointer to NAL Buffer API.\n * \\param p_DispBufAPI: Pointer to Display Buffer API.\n * \\param ih264d_dec_mem_manager  :Pointer to the function that will be called by decoder\n *                        for memory allocation and freeing.\n *\n * \\return\n *    0 on Success and -1 on error\n *\n **************************************************************************\n */\nvoid ih264d_init_decoder(void * ps_dec_params)\n{\n    dec_struct_t * ps_dec = (dec_struct_t *)ps_dec_params;\n    dec_slice_params_t *ps_cur_slice;\n    pocstruct_t *ps_prev_poc, *ps_cur_poc;\n    WORD32 size;\n\n    size = sizeof(pred_info_t) * 2 * 32;\n    memset(ps_dec->ps_pred, 0 , size);\n\n    size = sizeof(disp_mgr_t);\n    memset(ps_dec->pv_disp_buf_mgr, 0 , size);\n\n    size = sizeof(buf_mgr_t) + ithread_get_mutex_lock_size();\n    memset(ps_dec->pv_pic_buf_mgr, 0, size);\n\n    size = sizeof(dec_err_status_t);\n    memset(ps_dec->ps_dec_err_status, 0, size);\n\n    size = sizeof(sei);\n    memset(ps_dec->ps_sei, 0, size);\n\n    size = sizeof(sei);\n    memset(ps_dec->ps_sei_parse, 0, size);\n\n    size = sizeof(dpb_commands_t);\n    memset(ps_dec->ps_dpb_cmds, 0, size);\n\n    size = sizeof(dec_bit_stream_t);\n    memset(ps_dec->ps_bitstrm, 0, size);\n\n    size = sizeof(dec_slice_params_t);\n    memset(ps_dec->ps_cur_slice, 0, size);\n\n    size = MAX(sizeof(dec_seq_params_t), sizeof(dec_pic_params_t));\n    memset(ps_dec->pv_scratch_sps_pps, 0, size);\n\n    size = sizeof(ctxt_inc_mb_info_t);\n    memset(ps_dec->ps_left_mb_ctxt_info, 0, size);\n\n    size = (sizeof(neighbouradd_t) << 2);\n    memset(ps_dec->ps_left_mvpred_addr, 0 ,size);\n\n    size = sizeof(buf_mgr_t) + ithread_get_mutex_lock_size();\n    memset(ps_dec->pv_mv_buf_mgr, 0, size);\n\n    /* Free any dynamic buffers that are allocated */\n    ih264d_free_dynamic_bufs(ps_dec);\n\n    {\n        UWORD8 i;\n        struct pic_buffer_t *ps_init_dpb;\n        ps_init_dpb = ps_dec->ps_dpb_mgr->ps_init_dpb[0][0];\n        for(i = 0; i < 2 * MAX_REF_BUFS; i++)\n        {\n            ps_init_dpb->pu1_buf1 = NULL;\n            ps_init_dpb->u1_long_term_frm_idx = MAX_REF_BUFS + 1;\n            ps_dec->ps_dpb_mgr->ps_init_dpb[0][i] = ps_init_dpb;\n            ps_dec->ps_dpb_mgr->ps_mod_dpb[0][i] = ps_init_dpb;\n            ps_init_dpb++;\n        }\n\n        ps_init_dpb = ps_dec->ps_dpb_mgr->ps_init_dpb[1][0];\n        for(i = 0; i < 2 * MAX_REF_BUFS; i++)\n        {\n            ps_init_dpb->pu1_buf1 = NULL;\n            ps_init_dpb->u1_long_term_frm_idx = MAX_REF_BUFS + 1;\n            ps_dec->ps_dpb_mgr->ps_init_dpb[1][i] = ps_init_dpb;\n            ps_dec->ps_dpb_mgr->ps_mod_dpb[1][i] = ps_init_dpb;\n            ps_init_dpb++;\n        }\n    }\n\n    ps_cur_slice = ps_dec->ps_cur_slice;\n    ps_dec->init_done = 0;\n\n    ps_dec->u4_num_cores = 1;\n\n    ps_dec->u2_pic_ht = ps_dec->u2_pic_wd = 0;\n\n    ps_dec->u1_separate_parse = DEFAULT_SEPARATE_PARSE;\n    ps_dec->u4_app_disable_deblk_frm = 0;\n    ps_dec->i4_degrade_type = 0;\n    ps_dec->i4_degrade_pics = 0;\n\n    memset(ps_dec->ps_pps, 0,\n           ((sizeof(dec_pic_params_t)) * MAX_NUM_PIC_PARAMS));\n    memset(ps_dec->ps_sps, 0,\n           ((sizeof(dec_seq_params_t)) * MAX_NUM_SEQ_PARAMS));\n\n    /* Initialization of function pointers ih264d_deblock_picture function*/\n\n    ps_dec->p_DeblockPicture[0] = ih264d_deblock_picture_non_mbaff;\n    ps_dec->p_DeblockPicture[1] = ih264d_deblock_picture_mbaff;\n\n    ps_dec->s_cab_dec_env.pv_codec_handle = ps_dec;\n\n    ps_dec->u4_num_fld_in_frm = 0;\n\n    ps_dec->ps_dpb_mgr->pv_codec_handle = ps_dec;\n\n    /* Initialize the sei validity u4_flag with zero indiacting sei is not valid*/\n    ps_dec->ps_sei->u1_is_valid = 0;\n\n    /* decParams Initializations */\n    ps_dec->ps_cur_pps = NULL;\n    ps_dec->ps_cur_sps = NULL;\n    ps_dec->u1_init_dec_flag = 0;\n    ps_dec->u1_first_slice_in_stream = 1;\n    ps_dec->u1_last_pic_not_decoded = 0;\n    ps_dec->u4_app_disp_width = 0;\n    ps_dec->i4_header_decoded = 0;\n    ps_dec->u4_total_frames_decoded = 0;\n\n    ps_dec->i4_error_code = 0;\n    ps_dec->i4_content_type = IV_CONTENTTYPE_NA;\n    ps_dec->ps_cur_slice->u1_mbaff_frame_flag = 0;\n\n    ps_dec->ps_dec_err_status->u1_err_flag = ACCEPT_ALL_PICS; //REJECT_PB_PICS;\n    ps_dec->ps_dec_err_status->u1_cur_pic_type = PIC_TYPE_UNKNOWN;\n    ps_dec->ps_dec_err_status->u4_frm_sei_sync = SYNC_FRM_DEFAULT;\n    ps_dec->ps_dec_err_status->u4_cur_frm = INIT_FRAME;\n    ps_dec->ps_dec_err_status->u1_pic_aud_i = PIC_TYPE_UNKNOWN;\n\n    ps_dec->u1_pr_sl_type = 0xFF;\n    ps_dec->u2_mbx = 0xffff;\n    ps_dec->u2_mby = 0;\n    ps_dec->u2_total_mbs_coded = 0;\n\n    /* POC initializations */\n    ps_prev_poc = &ps_dec->s_prev_pic_poc;\n    ps_cur_poc = &ps_dec->s_cur_pic_poc;\n    ps_prev_poc->i4_pic_order_cnt_lsb = ps_cur_poc->i4_pic_order_cnt_lsb = 0;\n    ps_prev_poc->i4_pic_order_cnt_msb = ps_cur_poc->i4_pic_order_cnt_msb = 0;\n    ps_prev_poc->i4_delta_pic_order_cnt_bottom =\n                    ps_cur_poc->i4_delta_pic_order_cnt_bottom = 0;\n    ps_prev_poc->i4_delta_pic_order_cnt[0] =\n                    ps_cur_poc->i4_delta_pic_order_cnt[0] = 0;\n    ps_prev_poc->i4_delta_pic_order_cnt[1] =\n                    ps_cur_poc->i4_delta_pic_order_cnt[1] = 0;\n    ps_prev_poc->u1_mmco_equalto5 = ps_cur_poc->u1_mmco_equalto5 = 0;\n    ps_prev_poc->i4_top_field_order_count = ps_cur_poc->i4_top_field_order_count =\n                    0;\n    ps_prev_poc->i4_bottom_field_order_count =\n                    ps_cur_poc->i4_bottom_field_order_count = 0;\n    ps_prev_poc->u1_bot_field = ps_cur_poc->u1_bot_field = 0;\n    ps_prev_poc->u1_mmco_equalto5 = ps_cur_poc->u1_mmco_equalto5 = 0;\n    ps_prev_poc->i4_prev_frame_num_ofst = ps_cur_poc->i4_prev_frame_num_ofst = 0;\n    ps_cur_slice->u1_mmco_equalto5 = 0;\n    ps_cur_slice->u2_frame_num = 0;\n\n    ps_dec->i4_max_poc = 0;\n    ps_dec->i4_prev_max_display_seq = 0;\n    ps_dec->u1_recon_mb_grp = 4;\n    ps_dec->i4_reorder_depth = -1;\n\n    /* Field PIC initializations */\n    ps_dec->u1_second_field = 0;\n    ps_dec->s_prev_seq_params.u1_eoseq_pending = 0;\n\n    /* Set the cropping parameters as zero */\n    ps_dec->u2_crop_offset_y = 0;\n    ps_dec->u2_crop_offset_uv = 0;\n\n\tps_dec->u1_frame_cropping_flag = 0;\n\tps_dec->u1_frame_cropping_rect_left_ofst = 0;\n\tps_dec->u1_frame_cropping_rect_right_ofst = 0;\n\tps_dec->u1_frame_cropping_rect_top_ofst = 0;\n\tps_dec->u1_frame_cropping_rect_bottom_ofst = 0;\n\n    /* The Initial Frame Rate Info is not Present */\n    ps_dec->i4_vui_frame_rate = -1;\n    ps_dec->i4_pic_type = NA_SLICE;\n    ps_dec->i4_frametype = IV_NA_FRAME;\n    ps_dec->i4_content_type = IV_CONTENTTYPE_NA;\n\n    ps_dec->u1_res_changed = 0;\n\n\n    ps_dec->u1_frame_decoded_flag = 0;\n\n    /* Set the default frame seek mask mode */\n    ps_dec->u4_skip_frm_mask = SKIP_NONE;\n\n    /********************************************************/\n    /* Initialize CAVLC residual decoding function pointers */\n    /********************************************************/\n    ps_dec->pf_cavlc_4x4res_block[0] = ih264d_cavlc_4x4res_block_totalcoeff_1;\n    ps_dec->pf_cavlc_4x4res_block[1] =\n                    ih264d_cavlc_4x4res_block_totalcoeff_2to10;\n    ps_dec->pf_cavlc_4x4res_block[2] =\n                    ih264d_cavlc_4x4res_block_totalcoeff_11to16;\n\n    ps_dec->pf_cavlc_parse4x4coeff[0] = ih264d_cavlc_parse4x4coeff_n0to7;\n    ps_dec->pf_cavlc_parse4x4coeff[1] = ih264d_cavlc_parse4x4coeff_n8;\n\n    ps_dec->pf_cavlc_parse_8x8block[0] =\n                    ih264d_cavlc_parse_8x8block_none_available;\n    ps_dec->pf_cavlc_parse_8x8block[1] =\n                    ih264d_cavlc_parse_8x8block_left_available;\n    ps_dec->pf_cavlc_parse_8x8block[2] =\n                    ih264d_cavlc_parse_8x8block_top_available;\n    ps_dec->pf_cavlc_parse_8x8block[3] =\n                    ih264d_cavlc_parse_8x8block_both_available;\n\n    /***************************************************************************/\n    /* Initialize Bs calculation function pointers for P and B, 16x16/non16x16 */\n    /***************************************************************************/\n    ps_dec->pf_fill_bs1[0][0] = ih264d_fill_bs1_16x16mb_pslice;\n    ps_dec->pf_fill_bs1[0][1] = ih264d_fill_bs1_non16x16mb_pslice;\n\n    ps_dec->pf_fill_bs1[1][0] = ih264d_fill_bs1_16x16mb_bslice;\n    ps_dec->pf_fill_bs1[1][1] = ih264d_fill_bs1_non16x16mb_bslice;\n\n    ps_dec->pf_fill_bs_xtra_left_edge[0] =\n                    ih264d_fill_bs_xtra_left_edge_cur_frm;\n    ps_dec->pf_fill_bs_xtra_left_edge[1] =\n                    ih264d_fill_bs_xtra_left_edge_cur_fld;\n\n    /* Initialize Reference Pic Buffers */\n    ih264d_init_ref_bufs(ps_dec->ps_dpb_mgr);\n\n    ps_dec->u2_prv_frame_num = 0;\n    ps_dec->u1_top_bottom_decoded = 0;\n    ps_dec->u1_dangling_field = 0;\n\n    ps_dec->s_cab_dec_env.cabac_table = gau4_ih264d_cabac_table;\n\n    ps_dec->pu1_left_mv_ctxt_inc = ps_dec->u1_left_mv_ctxt_inc_arr[0];\n    ps_dec->pi1_left_ref_idx_ctxt_inc =\n                    &ps_dec->i1_left_ref_idx_ctx_inc_arr[0][0];\n    ps_dec->pu1_left_yuv_dc_csbp = &ps_dec->u1_yuv_dc_csbp_topmb;\n\n    /* ! */\n    /* Initializing flush frame u4_flag */\n    ps_dec->u1_flushfrm = 0;\n\n    {\n        ps_dec->s_cab_dec_env.pv_codec_handle = (void*)ps_dec;\n        ps_dec->ps_bitstrm->pv_codec_handle = (void*)ps_dec;\n        ps_dec->ps_cur_slice->pv_codec_handle = (void*)ps_dec;\n        ps_dec->ps_dpb_mgr->pv_codec_handle = (void*)ps_dec;\n    }\n\n    memset(ps_dec->disp_bufs, 0, (MAX_DISP_BUFS_NEW) * sizeof(disp_buf_t));\n    memset(ps_dec->u4_disp_buf_mapping, 0,\n           (MAX_DISP_BUFS_NEW) * sizeof(UWORD32));\n    memset(ps_dec->u4_disp_buf_to_be_freed, 0,\n           (MAX_DISP_BUFS_NEW) * sizeof(UWORD32));\n    memset(ps_dec->ps_cur_slice, 0, sizeof(dec_slice_params_t));\n\n    ih264d_init_arch(ps_dec);\n    ih264d_init_function_ptr(ps_dec);\n    ps_dec->e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;\n    ps_dec->init_done = 1;\n\n}\nWORD32 ih264d_free_static_bufs(iv_obj_t *dec_hdl)\n{\n    dec_struct_t *ps_dec;\n\n    void (*pf_aligned_free)(void *pv_mem_ctxt, void *pv_buf);\n    void *pv_mem_ctxt;\n\n    ps_dec = (dec_struct_t *)dec_hdl->pv_codec_handle;\n    pf_aligned_free = ps_dec->pf_aligned_free;\n    pv_mem_ctxt = ps_dec->pv_mem_ctxt;\n\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_sps);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_pps);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pv_dec_thread_handle);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pv_bs_deblk_thread_handle);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_dpb_mgr);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_pred);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pv_disp_buf_mgr);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pv_pic_buf_mgr);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_pic_buf_base);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_dec_err_status);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_sei);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_sei_parse);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_dpb_cmds);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_bitstrm);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_cur_slice);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pv_scratch_sps_pps);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_bits_buf_static);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ppv_map_ref_idx_to_poc_base);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->p_cabac_ctxt_table_t);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_left_mb_ctxt_info);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_ref_buff_base);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pi2_pred1);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_temp_mc_buffer);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_init_dpb_base);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu4_mbaff_wt_mat);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu4_wts_ofsts_mat);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_left_mvpred_addr);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pv_mv_buf_mgr);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_col_mv_base);\n    PS_DEC_ALIGNED_FREE(ps_dec, dec_hdl->pv_codec_handle);\n\n    if(dec_hdl)\n    {\n        pf_aligned_free(pv_mem_ctxt, dec_hdl);\n    }\n    return IV_SUCCESS;\n}\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_create                                              */\n/*                                                                           */\n/*  Description   : creates decoder                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_allocate_static_bufs(iv_obj_t **dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n    ih264d_create_ip_t *ps_create_ip;\n    ih264d_create_op_t *ps_create_op;\n    void *pv_buf;\n    UWORD8 *pu1_buf;\n    dec_struct_t *ps_dec;\n    void *(*pf_aligned_alloc)(void *pv_mem_ctxt, WORD32 alignment, WORD32 size);\n    void (*pf_aligned_free)(void *pv_mem_ctxt, void *pv_buf);\n    void *pv_mem_ctxt;\n    WORD32 size;\n\n    ps_create_ip = (ih264d_create_ip_t *)pv_api_ip;\n    ps_create_op = (ih264d_create_op_t *)pv_api_op;\n\n    ps_create_op->s_ivd_create_op_t.u4_error_code = 0;\n\n    pf_aligned_alloc = ps_create_ip->s_ivd_create_ip_t.pf_aligned_alloc;\n    pf_aligned_free = ps_create_ip->s_ivd_create_ip_t.pf_aligned_free;\n    pv_mem_ctxt  = ps_create_ip->s_ivd_create_ip_t.pv_mem_ctxt;\n\n    /* Initialize return handle to NULL */\n    ps_create_op->s_ivd_create_op_t.pv_handle = NULL;\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, sizeof(iv_obj_t));\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, sizeof(iv_obj_t));\n    *dec_hdl = (iv_obj_t *)pv_buf;\n    ps_create_op->s_ivd_create_op_t.pv_handle = *dec_hdl;\n\n    (*dec_hdl)->pv_codec_handle = NULL;\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, sizeof(dec_struct_t));\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    (*dec_hdl)->pv_codec_handle = (dec_struct_t *)pv_buf;\n    ps_dec = (dec_struct_t *)pv_buf;\n\n    memset(ps_dec, 0, sizeof(dec_struct_t));\n\n#ifndef LOGO_EN\n    ps_dec->u4_share_disp_buf = ps_create_ip->s_ivd_create_ip_t.u4_share_disp_buf;\n#else\n    ps_dec->u4_share_disp_buf = 0;\n#endif\n\n    ps_dec->u1_chroma_format =\n                    (UWORD8)(ps_create_ip->s_ivd_create_ip_t.e_output_format);\n\n    if((ps_dec->u1_chroma_format != IV_YUV_420P)\n                    && (ps_dec->u1_chroma_format\n                                    != IV_YUV_420SP_UV)\n                    && (ps_dec->u1_chroma_format\n                                    != IV_YUV_420SP_VU))\n    {\n        ps_dec->u4_share_disp_buf = 0;\n    }\n\n    ps_dec->pf_aligned_alloc = pf_aligned_alloc;\n    ps_dec->pf_aligned_free = pf_aligned_free;\n    ps_dec->pv_mem_ctxt = pv_mem_ctxt;\n\n\n    size = ((sizeof(dec_seq_params_t)) * MAX_NUM_SEQ_PARAMS);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_sps = pv_buf;\n\n    size = (sizeof(dec_pic_params_t)) * MAX_NUM_PIC_PARAMS;\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_pps = pv_buf;\n\n    size = ithread_get_handle_size();\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pv_dec_thread_handle = pv_buf;\n\n    size = ithread_get_handle_size();\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pv_bs_deblk_thread_handle = pv_buf;\n\n    size = sizeof(dpb_manager_t);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_dpb_mgr = pv_buf;\n\n    size = sizeof(pred_info_t) * 2 * 32;\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_pred = pv_buf;\n\n    size = sizeof(disp_mgr_t);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pv_disp_buf_mgr = pv_buf;\n\n    size = sizeof(buf_mgr_t) + ithread_get_mutex_lock_size();\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pv_pic_buf_mgr = pv_buf;\n\n    size = sizeof(struct pic_buffer_t) * (H264_MAX_REF_PICS * 2);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_pic_buf_base = pv_buf;\n\n    size = sizeof(dec_err_status_t);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_dec_err_status = (dec_err_status_t *)pv_buf;\n\n    size = sizeof(sei);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_sei = (sei *)pv_buf;\n\n    size = sizeof(sei);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_sei_parse = (sei *)pv_buf;\n\n    size = sizeof(dpb_commands_t);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_dpb_cmds = (dpb_commands_t *)pv_buf;\n\n    size = sizeof(dec_bit_stream_t);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_bitstrm = (dec_bit_stream_t *)pv_buf;\n\n    size = sizeof(dec_slice_params_t);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_cur_slice = (dec_slice_params_t *)pv_buf;\n\n    size = MAX(sizeof(dec_seq_params_t), sizeof(dec_pic_params_t));\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pv_scratch_sps_pps = pv_buf;\n\n\n    ps_dec->u4_static_bits_buf_size = 256000;\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, ps_dec->u4_static_bits_buf_size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, ps_dec->u4_static_bits_buf_size);\n    ps_dec->pu1_bits_buf_static = pv_buf;\n\n\n    size = ((TOTAL_LIST_ENTRIES + PAD_MAP_IDX_POC)\n                        * sizeof(void *));\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    ps_dec->ppv_map_ref_idx_to_poc_base = pv_buf;\n    memset(ps_dec->ppv_map_ref_idx_to_poc_base, 0, size);\n\n    ps_dec->ppv_map_ref_idx_to_poc = ps_dec->ppv_map_ref_idx_to_poc_base + OFFSET_MAP_IDX_POC;\n\n\n    size = (sizeof(bin_ctxt_model_t) * NUM_CABAC_CTXTS);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->p_cabac_ctxt_table_t = pv_buf;\n\n\n\n    size = sizeof(ctxt_inc_mb_info_t);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_left_mb_ctxt_info = pv_buf;\n\n\n\n    size = MAX_REF_BUF_SIZE * 2;\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pu1_ref_buff_base = pv_buf;\n    ps_dec->pu1_ref_buff = ps_dec->pu1_ref_buff_base + MAX_REF_BUF_SIZE;\n\n\n    size = ((sizeof(WORD16)) * PRED_BUFFER_WIDTH\n                        * PRED_BUFFER_HEIGHT * 2);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pi2_pred1 = pv_buf;\n\n\n    size = sizeof(UWORD8) * (MB_LUM_SIZE);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pu1_temp_mc_buffer = pv_buf;\n\n\n\n\n    size = 8 * MAX_REF_BUFS * sizeof(struct pic_buffer_t);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n\n    ps_dec->pu1_init_dpb_base = pv_buf;\n    pu1_buf = pv_buf;\n    ps_dec->ps_dpb_mgr->ps_init_dpb[0][0] = (struct pic_buffer_t *)pu1_buf;\n\n    pu1_buf += size / 2;\n    ps_dec->ps_dpb_mgr->ps_init_dpb[1][0] = (struct pic_buffer_t *)pu1_buf;\n\n    size = (sizeof(UWORD32) * 2 * 3\n                        * ((MAX_FRAMES << 1) * (MAX_FRAMES << 1)) * 2);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pu4_mbaff_wt_mat = pv_buf;\n\n    size = sizeof(UWORD32) * 2 * 3\n                        * ((MAX_FRAMES << 1) * (MAX_FRAMES << 1));\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pu4_wts_ofsts_mat = pv_buf;\n\n\n    size = (sizeof(neighbouradd_t) << 2);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_left_mvpred_addr = pv_buf;\n\n\n    size = sizeof(buf_mgr_t) + ithread_get_mutex_lock_size();\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pv_mv_buf_mgr = pv_buf;\n\n\n    size =  sizeof(col_mv_buf_t) * (H264_MAX_REF_PICS * 2);\n    pv_buf = pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    ps_dec->ps_col_mv_base = pv_buf;\n    memset(ps_dec->ps_col_mv_base, 0, size);\n\n    ih264d_init_decoder(ps_dec);\n\n    return IV_SUCCESS;\n}\n\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_create                                              */\n/*                                                                           */\n/*  Description   : creates decoder                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_create(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n    ih264d_create_ip_t *ps_create_ip;\n    ih264d_create_op_t *ps_create_op;\n\n    WORD32 ret;\n\n    ps_create_ip = (ih264d_create_ip_t *)pv_api_ip;\n    ps_create_op = (ih264d_create_op_t *)pv_api_op;\n\n    ps_create_op->s_ivd_create_op_t.u4_error_code = 0;\n    dec_hdl = NULL;\n    ret = ih264d_allocate_static_bufs(&dec_hdl, pv_api_ip, pv_api_op);\n\n    /* If allocation of some buffer fails, then free buffers allocated till then */\n    if(IV_FAIL == ret)\n    {\n        if(dec_hdl)\n        {\n            if(dec_hdl->pv_codec_handle)\n            {\n                ih264d_free_static_bufs(dec_hdl);\n            }\n            else\n            {\n                void (*pf_aligned_free)(void *pv_mem_ctxt, void *pv_buf);\n                void *pv_mem_ctxt;\n\n                pf_aligned_free = ps_create_ip->s_ivd_create_ip_t.pf_aligned_free;\n                pv_mem_ctxt  = ps_create_ip->s_ivd_create_ip_t.pv_mem_ctxt;\n                pf_aligned_free(pv_mem_ctxt, dec_hdl);\n            }\n        }\n        ps_create_op->s_ivd_create_op_t.u4_error_code = IVD_MEM_ALLOC_FAILED;\n        ps_create_op->s_ivd_create_op_t.u4_error_code |= 1 << IVD_FATALERROR;\n\n        return IV_FAIL;\n    }\n\n    return IV_SUCCESS;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name :  ih264d_map_error                                        */\n/*                                                                           */\n/*  Description   :  Maps error codes to IVD error groups                    */\n/*                                                                           */\n/*  Inputs        :                                                          */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nUWORD32 ih264d_map_error(UWORD32 i4_err_status)\n{\n    UWORD32 temp = 0;\n\n    switch(i4_err_status)\n    {\n        case ERROR_MEM_ALLOC_ISRAM_T:\n        case ERROR_MEM_ALLOC_SDRAM_T:\n        case ERROR_BUF_MGR:\n        case ERROR_MB_GROUP_ASSGN_T:\n        case ERROR_FRAME_LIMIT_OVER:\n        case ERROR_ACTUAL_RESOLUTION_GREATER_THAN_INIT:\n        case ERROR_PROFILE_NOT_SUPPORTED:\n        case ERROR_INIT_NOT_DONE:\n        case IVD_MEM_ALLOC_FAILED:\n        case ERROR_FEATURE_UNAVAIL:\n        case IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED:\n            temp = 1 << IVD_FATALERROR;\n            H264_DEC_DEBUG_PRINT(\"\\nFatal Error\\n\");\n            break;\n\n        case ERROR_DBP_MANAGER_T:\n        case ERROR_GAPS_IN_FRM_NUM:\n        case ERROR_UNKNOWN_NAL:\n        case ERROR_INV_MB_SLC_GRP_T:\n        case ERROR_MULTIPLE_SLC_GRP_T:\n        case ERROR_UNKNOWN_LEVEL:\n        case ERROR_UNAVAIL_PICBUF_T:\n        case ERROR_UNAVAIL_MVBUF_T:\n        case ERROR_UNAVAIL_DISPBUF_T:\n        case ERROR_NUM_REF:\n        case ERROR_REFIDX_ORDER_T:\n        case ERROR_PIC0_NOT_FOUND_T:\n        case ERROR_MB_TYPE:\n        case ERROR_SUB_MB_TYPE:\n        case ERROR_CBP:\n        case ERROR_REF_IDX:\n        case ERROR_NUM_MV:\n        case ERROR_CHROMA_PRED_MODE:\n        case ERROR_INTRAPRED:\n        case ERROR_NEXT_MB_ADDRESS_T:\n        case ERROR_MB_ADDRESS_T:\n        case ERROR_PIC1_NOT_FOUND_T:\n        case ERROR_CAVLC_NUM_COEFF_T:\n        case ERROR_CAVLC_SCAN_POS_T:\n        case ERROR_PRED_WEIGHT_TABLE_T:\n        case ERROR_CORRUPTED_SLICE:\n            temp = 1 << IVD_CORRUPTEDDATA;\n            break;\n\n        case ERROR_NOT_SUPP_RESOLUTION:\n        case ERROR_ACTUAL_LEVEL_GREATER_THAN_INIT:\n            temp = 1 << IVD_UNSUPPORTEDINPUT;\n            break;\n\n        case ERROR_INVALID_PIC_PARAM:\n        case ERROR_INVALID_SEQ_PARAM:\n        case ERROR_EGC_EXCEED_32_1_T:\n        case ERROR_EGC_EXCEED_32_2_T:\n        case ERROR_INV_RANGE_TEV_T:\n        case ERROR_INV_SLC_TYPE_T:\n        case ERROR_INV_POC_TYPE_T:\n        case ERROR_INV_RANGE_QP_T:\n        case ERROR_INV_SPS_PPS_T:\n        case ERROR_INV_SLICE_HDR_T:\n        case ERROR_INV_SEI_MDCV_PARAMS:\n        case ERROR_INV_SEI_CLL_PARAMS:\n        case ERROR_INV_SEI_AVE_PARAMS:\n        case ERROR_INV_SEI_CCV_PARAMS:\n            temp = 1 << IVD_CORRUPTEDHEADER;\n            break;\n\n        case ERROR_EOB_FLUSHBITS_T:\n        case ERROR_EOB_GETBITS_T:\n        case ERROR_EOB_GETBIT_T:\n        case ERROR_EOB_BYPASS_T:\n        case ERROR_EOB_DECISION_T:\n        case ERROR_EOB_TERMINATE_T:\n        case ERROR_EOB_READCOEFF4X4CAB_T:\n            temp = 1 << IVD_INSUFFICIENTDATA;\n            break;\n        case ERROR_DYNAMIC_RESOLUTION_NOT_SUPPORTED:\n        case ERROR_DISP_WIDTH_RESET_TO_PIC_WIDTH:\n            temp = 1 << IVD_UNSUPPORTEDPARAM | 1 << IVD_FATALERROR;\n            break;\n\n        case ERROR_DANGLING_FIELD_IN_PIC:\n            temp = 1 << IVD_APPLIEDCONCEALMENT;\n            break;\n\n    }\n\n    return temp;\n\n}\n\nUWORD32 ih264d_get_outbuf_size(WORD32 pic_wd,\n                               UWORD32 pic_ht,\n                               UWORD8 u1_chroma_format,\n                               UWORD32 *p_buf_size)\n{\n    UWORD32 u4_min_num_out_bufs = 0;\n\n    if(u1_chroma_format == IV_YUV_420P)\n        u4_min_num_out_bufs = MIN_OUT_BUFS_420;\n    else if(u1_chroma_format == IV_YUV_422ILE)\n        u4_min_num_out_bufs = MIN_OUT_BUFS_422ILE;\n    else if(u1_chroma_format == IV_RGB_565)\n        u4_min_num_out_bufs = MIN_OUT_BUFS_RGB565;\n    else if((u1_chroma_format == IV_YUV_420SP_UV)\n                    || (u1_chroma_format == IV_YUV_420SP_VU))\n        u4_min_num_out_bufs = MIN_OUT_BUFS_420SP;\n\n    if(u1_chroma_format == IV_YUV_420P)\n    {\n        p_buf_size[0] = (pic_wd * pic_ht);\n        p_buf_size[1] = (pic_wd * pic_ht) >> 2;\n        p_buf_size[2] = (pic_wd * pic_ht) >> 2;\n    }\n    else if(u1_chroma_format == IV_YUV_422ILE)\n    {\n        p_buf_size[0] = (pic_wd * pic_ht) * 2;\n        p_buf_size[1] = p_buf_size[2] = 0;\n    }\n    else if(u1_chroma_format == IV_RGB_565)\n    {\n        p_buf_size[0] = (pic_wd * pic_ht) * 2;\n        p_buf_size[1] = p_buf_size[2] = 0;\n    }\n    else if((u1_chroma_format == IV_YUV_420SP_UV)\n                    || (u1_chroma_format == IV_YUV_420SP_VU))\n    {\n        p_buf_size[0] = (pic_wd * pic_ht);\n        p_buf_size[1] = (pic_wd * pic_ht) >> 1;\n        p_buf_size[2] = 0;\n    }\n\n    return u4_min_num_out_bufs;\n}\n\nWORD32 check_app_out_buf_size(dec_struct_t *ps_dec)\n{\n    UWORD32 au4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];\n    UWORD32 u4_min_num_out_bufs, i;\n    UWORD32 pic_wd, pic_ht;\n\n    if(0 == ps_dec->u4_share_disp_buf)\n    {\n        pic_wd = ps_dec->u2_disp_width;\n        pic_ht = ps_dec->u2_disp_height;\n\n    }\n    else\n    {\n        pic_wd = ps_dec->u2_frm_wd_y;\n        pic_ht = ps_dec->u2_frm_ht_y;\n    }\n\n    if(ps_dec->u4_app_disp_width > pic_wd)\n        pic_wd = ps_dec->u4_app_disp_width;\n\n    u4_min_num_out_bufs = ih264d_get_outbuf_size(pic_wd, pic_ht,\n                                                 ps_dec->u1_chroma_format,\n                                                 &au4_min_out_buf_size[0]);\n\n\n    if(0 == ps_dec->u4_share_disp_buf)\n    {\n        if(ps_dec->ps_out_buffer->u4_num_bufs < u4_min_num_out_bufs)\n            return IV_FAIL;\n\n        for(i = 0; i < u4_min_num_out_bufs; i++)\n        {\n            if(ps_dec->ps_out_buffer->u4_min_out_buf_size[i]\n                            < au4_min_out_buf_size[i])\n                return (IV_FAIL);\n        }\n    }\n    else\n    {\n        if(ps_dec->disp_bufs[0].u4_num_bufs < u4_min_num_out_bufs)\n            return IV_FAIL;\n\n        for(i = 0; i < u4_min_num_out_bufs; i++)\n        {\n            /* We need to check only with the disp_buffer[0], because we have\n             * already ensured that all the buffers are of the same size in\n             * ih264d_set_display_frame.\n             */\n            if(ps_dec->disp_bufs[0].u4_bufsize[i] < au4_min_out_buf_size[i])\n                return (IV_FAIL);\n        }\n\n    }\n\n    return (IV_SUCCESS);\n}\n\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name :  ih264d_video_decode                                     */\n/*                                                                           */\n/*  Description   :  handle video decode API command                         */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_video_decode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n    /* ! */\n\n    dec_struct_t * ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);\n\n    WORD32 i4_err_status = 0;\n    UWORD8 *pu1_buf = NULL;\n    WORD32 buflen;\n    UWORD32 u4_max_ofst, u4_length_of_start_code = 0;\n\n    UWORD32 bytes_consumed = 0;\n    UWORD32 cur_slice_is_nonref = 0;\n    UWORD32 u4_next_is_aud;\n    UWORD32 u4_first_start_code_found = 0;\n    WORD32 ret = 0,api_ret_value = IV_SUCCESS;\n    WORD32 header_data_left = 0,frame_data_left = 0;\n    UWORD8 *pu1_bitstrm_buf;\n    ih264d_video_decode_ip_t *ps_h264d_dec_ip;\n    ih264d_video_decode_op_t *ps_h264d_dec_op;\n    ivd_video_decode_ip_t *ps_dec_ip;\n    ivd_video_decode_op_t *ps_dec_op;\n\n    ithread_set_name((void*)\"Parse_thread\");\n\n    ps_h264d_dec_ip = (ih264d_video_decode_ip_t *)pv_api_ip;\n    ps_h264d_dec_op = (ih264d_video_decode_op_t *)pv_api_op;\n    ps_dec_ip = &ps_h264d_dec_ip->s_ivd_video_decode_ip_t;\n    ps_dec_op = &ps_h264d_dec_op->s_ivd_video_decode_op_t;\n\n    {\n        UWORD32 u4_size;\n        u4_size = ps_dec_op->u4_size;\n        memset(ps_h264d_dec_op, 0, sizeof(ih264d_video_decode_op_t));\n        ps_dec_op->u4_size = u4_size;\n    }\n\n    ps_dec->pv_dec_out = ps_dec_op;\n    if(ps_dec->init_done != 1)\n    {\n        return IV_FAIL;\n    }\n\n    /*Data memory barries instruction,so that bitstream write by the application is complete*/\n    DATA_SYNC();\n\n    if(0 == ps_dec->u1_flushfrm)\n    {\n        if(ps_dec_ip->pv_stream_buffer == NULL)\n        {\n            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n            ps_dec_op->u4_error_code |= IVD_DEC_FRM_BS_BUF_NULL;\n            return IV_FAIL;\n        }\n        if(ps_dec_ip->u4_num_Bytes <= 0)\n        {\n            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n            ps_dec_op->u4_error_code |= IVD_DEC_NUMBYTES_INV;\n            return IV_FAIL;\n\n        }\n    }\n    ps_dec->u1_pic_decode_done = 0;\n\n    ps_dec_op->u4_num_bytes_consumed = 0;\n    ps_dec_op->i4_reorder_depth = -1;\n    ps_dec_op->i4_display_index = DEFAULT_POC;\n    ps_dec->ps_out_buffer = NULL;\n\n    if(ps_dec_ip->u4_size\n                    >= offsetof(ivd_video_decode_ip_t, s_out_buffer))\n        ps_dec->ps_out_buffer = &ps_dec_ip->s_out_buffer;\n\n    ps_dec->u4_fmt_conv_cur_row = 0;\n\n    ps_dec->u4_output_present = 0;\n    ps_dec->s_disp_op.u4_error_code = 1;\n    ps_dec->u4_fmt_conv_num_rows = FMT_CONV_NUM_ROWS;\n    if(0 == ps_dec->u4_share_disp_buf\n                    && ps_dec->i4_decode_header == 0)\n    {\n        UWORD32 i;\n        if((ps_dec->ps_out_buffer->u4_num_bufs == 0) ||\n           (ps_dec->ps_out_buffer->u4_num_bufs > IVD_VIDDEC_MAX_IO_BUFFERS))\n        {\n            ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n            ps_dec_op->u4_error_code |= IVD_DISP_FRM_ZERO_OP_BUFS;\n            return IV_FAIL;\n        }\n\n        for(i = 0; i < ps_dec->ps_out_buffer->u4_num_bufs; i++)\n        {\n            if(ps_dec->ps_out_buffer->pu1_bufs[i] == NULL)\n            {\n                ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                ps_dec_op->u4_error_code |= IVD_DISP_FRM_OP_BUF_NULL;\n                return IV_FAIL;\n            }\n\n            if(ps_dec->ps_out_buffer->u4_min_out_buf_size[i] == 0)\n            {\n                ps_dec_op->u4_error_code |= 1 << IVD_UNSUPPORTEDPARAM;\n                ps_dec_op->u4_error_code |=\n                                IVD_DISP_FRM_ZERO_OP_BUF_SIZE;\n                return IV_FAIL;\n            }\n        }\n    }\n\n    if(ps_dec->u4_total_frames_decoded >= NUM_FRAMES_LIMIT)\n    {\n        ps_dec_op->u4_error_code = ERROR_FRAME_LIMIT_OVER;\n        return IV_FAIL;\n    }\n\n    /* ! */\n    ps_dec->u4_ts = ps_dec_ip->u4_ts;\n\n    ps_dec_op->u4_error_code = 0;\n    ps_dec_op->e_pic_type = IV_NA_FRAME;\n    ps_dec_op->u4_output_present = 0;\n    ps_dec_op->u4_frame_decoded_flag = 0;\n\n    ps_dec->i4_frametype = IV_NA_FRAME;\n    ps_dec->i4_content_type = IV_CONTENTTYPE_NA;\n\n    ps_dec->u4_slice_start_code_found = 0;\n\n    /* In case the deocder is not in flush mode(in shared mode),\n     then decoder has to pick up a buffer to write current frame.\n     Check if a frame is available in such cases */\n\n    if(ps_dec->u1_init_dec_flag == 1 && ps_dec->u4_share_disp_buf == 1\n                    && ps_dec->u1_flushfrm == 0)\n    {\n        UWORD32 i;\n\n        WORD32 disp_avail = 0, free_id;\n\n        /* Check if at least one buffer is available with the codec */\n        /* If not then return to application with error */\n        for(i = 0; i < ps_dec->u1_pic_bufs; i++)\n        {\n            if(0 == ps_dec->u4_disp_buf_mapping[i]\n                            || 1 == ps_dec->u4_disp_buf_to_be_freed[i])\n            {\n                disp_avail = 1;\n                break;\n            }\n\n        }\n\n        if(0 == disp_avail)\n        {\n            /* If something is queued for display wait for that buffer to be returned */\n\n            ps_dec_op->u4_error_code = IVD_DEC_REF_BUF_NULL;\n            ps_dec_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);\n            return (IV_FAIL);\n        }\n\n        while(1)\n        {\n            pic_buffer_t *ps_pic_buf;\n            ps_pic_buf = (pic_buffer_t *)ih264_buf_mgr_get_next_free(\n                            (buf_mgr_t *)ps_dec->pv_pic_buf_mgr, &free_id);\n\n            if(ps_pic_buf == NULL)\n            {\n                UWORD32 i, display_queued = 0;\n\n                /* check if any buffer was given for display which is not returned yet */\n                for(i = 0; i < (MAX_DISP_BUFS_NEW); i++)\n                {\n                    if(0 != ps_dec->u4_disp_buf_mapping[i])\n                    {\n                        display_queued = 1;\n                        break;\n                    }\n                }\n                /* If some buffer is queued for display, then codec has to singal an error and wait\n                 for that buffer to be returned.\n                 If nothing is queued for display then codec has ownership of all display buffers\n                 and it can reuse any of the existing buffers and continue decoding */\n\n                if(1 == display_queued)\n                {\n                    /* If something is queued for display wait for that buffer to be returned */\n                    ps_dec_op->u4_error_code = IVD_DEC_REF_BUF_NULL;\n                    ps_dec_op->u4_error_code |= (1\n                                    << IVD_UNSUPPORTEDPARAM);\n                    return (IV_FAIL);\n                }\n            }\n            else\n            {\n                /* If the buffer is with display, then mark it as in use and then look for a buffer again */\n                if(1 == ps_dec->u4_disp_buf_mapping[free_id])\n                {\n                    ih264_buf_mgr_set_status(\n                                    (buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                    free_id,\n                                    BUF_MGR_IO);\n                }\n                else\n                {\n                    /**\n                     *  Found a free buffer for present call. Release it now.\n                     *  Will be again obtained later.\n                     */\n                    ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                          free_id,\n                                          BUF_MGR_IO);\n                    break;\n                }\n            }\n        }\n\n    }\n\n    if(ps_dec->u1_flushfrm)\n    {\n        if(ps_dec->u1_init_dec_flag == 0)\n        {\n            /*Come out of flush mode and return*/\n            ps_dec->u1_flushfrm = 0;\n            return (IV_FAIL);\n        }\n\n\n\n        ih264d_get_next_display_field(ps_dec, ps_dec->ps_out_buffer,\n                                      &(ps_dec->s_disp_op));\n        if(0 == ps_dec->s_disp_op.u4_error_code)\n        {\n            /* check output buffer size given by the application */\n            if(check_app_out_buf_size(ps_dec) != IV_SUCCESS)\n            {\n                ps_dec_op->u4_error_code= IVD_DISP_FRM_ZERO_OP_BUF_SIZE;\n                return (IV_FAIL);\n            }\n\n            ps_dec->u4_fmt_conv_cur_row = 0;\n            ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht;\n            ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),\n                                  ps_dec->u4_fmt_conv_cur_row,\n                                  ps_dec->u4_fmt_conv_num_rows);\n            ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;\n            ps_dec->u4_output_present = 1;\n\n        }\n        ih264d_export_sei_params(&ps_dec_op->s_sei_decode_op, ps_dec);\n\n        ih264d_release_display_field(ps_dec, &(ps_dec->s_disp_op));\n\n        ps_dec_op->u4_pic_wd = (UWORD32)ps_dec->u2_disp_width;\n        ps_dec_op->u4_pic_ht = (UWORD32)ps_dec->u2_disp_height;\n        ps_dec_op->i4_reorder_depth = ps_dec->i4_reorder_depth;\n        ps_dec_op->i4_display_index = ps_dec->i4_display_index;\n\n        ps_dec_op->u4_new_seq = 0;\n\n        ps_dec_op->u4_output_present = ps_dec->u4_output_present;\n        ps_dec_op->u4_progressive_frame_flag =\n                        ps_dec->s_disp_op.u4_progressive_frame_flag;\n        ps_dec_op->e_output_format =\n                        ps_dec->s_disp_op.e_output_format;\n        ps_dec_op->s_disp_frm_buf = ps_dec->s_disp_op.s_disp_frm_buf;\n        ps_dec_op->e4_fld_type = ps_dec->s_disp_op.e4_fld_type;\n        ps_dec_op->u4_ts = ps_dec->s_disp_op.u4_ts;\n        ps_dec_op->u4_disp_buf_id = ps_dec->s_disp_op.u4_disp_buf_id;\n\n        /*In the case of flush ,since no frame is decoded set pic type as invalid*/\n        ps_dec_op->u4_is_ref_flag = -1;\n        ps_dec_op->e_pic_type = IV_NA_FRAME;\n        ps_dec_op->u4_frame_decoded_flag = 0;\n\n        if(0 == ps_dec->s_disp_op.u4_error_code)\n        {\n            return (IV_SUCCESS);\n        }\n        else\n            return (IV_FAIL);\n\n    }\n    if(ps_dec->u1_res_changed == 1)\n    {\n        /*if resolution has changed and all buffers have been flushed, reset decoder*/\n        ih264d_init_decoder(ps_dec);\n    }\n\n    ps_dec->u2_cur_mb_addr = 0;\n    ps_dec->u2_total_mbs_coded = 0;\n    ps_dec->u2_cur_slice_num = 0;\n    ps_dec->cur_dec_mb_num = 0;\n    ps_dec->cur_recon_mb_num = 0;\n    ps_dec->u4_first_slice_in_pic = 1;\n    ps_dec->u1_slice_header_done = 0;\n    ps_dec->u1_dangling_field = 0;\n\n    ps_dec->u4_dec_thread_created = 0;\n    ps_dec->u4_bs_deblk_thread_created = 0;\n    ps_dec->u4_cur_bs_mb_num = 0;\n    ps_dec->u4_start_recon_deblk  = 0;\n    ps_dec->u4_sps_cnt_in_process = 0;\n\n    DEBUG_THREADS_PRINTF(\" Starting process call\\n\");\n\n\n    ps_dec->u4_pic_buf_got = 0;\n\n    do\n    {\n        WORD32 buf_size;\n\n        pu1_buf = (UWORD8*)ps_dec_ip->pv_stream_buffer\n                        + ps_dec_op->u4_num_bytes_consumed;\n\n        u4_max_ofst = ps_dec_ip->u4_num_Bytes\n                        - ps_dec_op->u4_num_bytes_consumed;\n\n        /* If dynamic bitstream buffer is not allocated and\n         * header decode is done, then allocate dynamic bitstream buffer\n         */\n        if((NULL == ps_dec->pu1_bits_buf_dynamic) &&\n           (ps_dec->i4_header_decoded & 1))\n        {\n            WORD32 size;\n\n            void *pv_buf;\n            void *pv_mem_ctxt = ps_dec->pv_mem_ctxt;\n            size = MAX(256000, ps_dec->u2_pic_wd * ps_dec->u2_pic_ht * 3 / 2);\n            pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128,\n                                              size + EXTRA_BS_OFFSET);\n            RETURN_IF((NULL == pv_buf), IV_FAIL);\n            memset(pv_buf, 0, size + EXTRA_BS_OFFSET);\n            ps_dec->pu1_bits_buf_dynamic = pv_buf;\n            ps_dec->u4_dynamic_bits_buf_size = size;\n        }\n\n        if(ps_dec->pu1_bits_buf_dynamic)\n        {\n            pu1_bitstrm_buf = ps_dec->pu1_bits_buf_dynamic;\n            buf_size = ps_dec->u4_dynamic_bits_buf_size;\n        }\n        else\n        {\n            pu1_bitstrm_buf = ps_dec->pu1_bits_buf_static;\n            buf_size = ps_dec->u4_static_bits_buf_size;\n        }\n\n        u4_next_is_aud = 0;\n\n        buflen = ih264d_find_start_code(pu1_buf, 0, u4_max_ofst,\n                                               &u4_length_of_start_code,\n                                               &u4_next_is_aud);\n\n        if(buflen == -1)\n            buflen = 0;\n        /* Ignore bytes beyond the allocated size of intermediate buffer */\n        /* Since 8 bytes are read ahead, ensure 8 bytes are free at the\n        end of the buffer, which will be memset to 0 after emulation prevention */\n        buflen = MIN(buflen, buf_size - 8);\n\n        bytes_consumed = buflen + u4_length_of_start_code;\n        ps_dec_op->u4_num_bytes_consumed += bytes_consumed;\n\n        if(buflen)\n        {\n            memcpy(pu1_bitstrm_buf, pu1_buf + u4_length_of_start_code,\n                   buflen);\n            /* Decoder may read extra 8 bytes near end of the frame */\n            if((buflen + 8) < buf_size)\n            {\n                memset(pu1_bitstrm_buf + buflen, 0, 8);\n            }\n            u4_first_start_code_found = 1;\n\n        }\n        else\n        {\n            /*start code not found*/\n\n            if(u4_first_start_code_found == 0)\n            {\n                /*no start codes found in current process call*/\n\n                ps_dec->i4_error_code = ERROR_START_CODE_NOT_FOUND;\n                ps_dec_op->u4_error_code |= 1 << IVD_INSUFFICIENTDATA;\n\n                if(ps_dec->u4_pic_buf_got == 0)\n                {\n\n                    ih264d_fill_output_struct_from_context(ps_dec,\n                                                           ps_dec_op);\n\n                    ps_dec_op->u4_error_code = ps_dec->i4_error_code;\n                    ps_dec_op->u4_frame_decoded_flag = 0;\n\n                    return (IV_FAIL);\n                }\n                else\n                {\n                    ps_dec->u1_pic_decode_done = 1;\n                    continue;\n                }\n            }\n            else\n            {\n                /* a start code has already been found earlier in the same process call*/\n                frame_data_left = 0;\n                header_data_left = 0;\n                continue;\n            }\n\n        }\n\n        ret = ih264d_parse_nal_unit(dec_hdl, ps_dec_op,\n                              pu1_bitstrm_buf, buflen);\n        if(ret != OK)\n        {\n            UWORD32 error =  ih264d_map_error(ret);\n            ps_dec_op->u4_error_code = error | ret;\n            api_ret_value = IV_FAIL;\n\n            if((ret == IVD_RES_CHANGED)\n                            || (ret == IVD_MEM_ALLOC_FAILED)\n                            || (ret == ERROR_UNAVAIL_PICBUF_T)\n                            || (ret == ERROR_UNAVAIL_MVBUF_T)\n                            || (ret == ERROR_INV_SPS_PPS_T)\n                            || (ret == ERROR_FEATURE_UNAVAIL)\n                            || (ret == IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED)\n                            || (ret == IVD_DISP_FRM_ZERO_OP_BUF_SIZE))\n            {\n                ps_dec->u4_slice_start_code_found = 0;\n                break;\n            }\n\n            if((ret == ERROR_INCOMPLETE_FRAME) || (ret == ERROR_DANGLING_FIELD_IN_PIC))\n            {\n                ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;\n                api_ret_value = IV_FAIL;\n                break;\n            }\n\n            if(ret == ERROR_IN_LAST_SLICE_OF_PIC)\n            {\n                api_ret_value = IV_FAIL;\n                break;\n            }\n\n        }\n\n        header_data_left = ((ps_dec->i4_decode_header == 1)\n                        && (ps_dec->i4_header_decoded != 3)\n                        && (ps_dec_op->u4_num_bytes_consumed\n                                        < ps_dec_ip->u4_num_Bytes));\n        frame_data_left = (((ps_dec->i4_decode_header == 0)\n                        && ((ps_dec->u1_pic_decode_done == 0)\n                                        || (u4_next_is_aud == 1)))\n                        && (ps_dec_op->u4_num_bytes_consumed\n                                        < ps_dec_ip->u4_num_Bytes));\n    }\n    while(( header_data_left == 1)||(frame_data_left == 1));\n\n    if((ps_dec->u4_pic_buf_got == 1)\n            && (ret != IVD_MEM_ALLOC_FAILED)\n            && ps_dec->u2_total_mbs_coded < ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)\n    {\n        // last slice - missing/corruption\n        WORD32 num_mb_skipped;\n        WORD32 prev_slice_err;\n        pocstruct_t temp_poc;\n        WORD32 ret1;\n        WORD32 ht_in_mbs;\n        ht_in_mbs = ps_dec->u2_pic_ht >> (4 + ps_dec->ps_cur_slice->u1_field_pic_flag);\n        num_mb_skipped = (ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)\n                            - ps_dec->u2_total_mbs_coded;\n\n        if(ps_dec->u4_first_slice_in_pic && (ps_dec->u4_pic_buf_got == 0))\n            prev_slice_err = 1;\n        else\n            prev_slice_err = 2;\n\n        if(ps_dec->u4_first_slice_in_pic && (ps_dec->u2_total_mbs_coded == 0))\n            prev_slice_err = 1;\n\n        ret1 = ih264d_mark_err_slice_skip(ps_dec, num_mb_skipped, ps_dec->u1_nal_unit_type == IDR_SLICE_NAL, ps_dec->ps_cur_slice->u2_frame_num,\n                                   &temp_poc, prev_slice_err);\n\n        if((ret1 == ERROR_UNAVAIL_PICBUF_T) || (ret1 == ERROR_UNAVAIL_MVBUF_T) ||\n                       (ret1 == ERROR_INV_SPS_PPS_T))\n        {\n            ret = ret1;\n        }\n    }\n\n    if((ret == IVD_RES_CHANGED)\n                    || (ret == IVD_MEM_ALLOC_FAILED)\n                    || (ret == ERROR_UNAVAIL_PICBUF_T)\n                    || (ret == ERROR_UNAVAIL_MVBUF_T)\n                    || (ret == ERROR_INV_SPS_PPS_T))\n    {\n\n        /* signal the decode thread */\n        ih264d_signal_decode_thread(ps_dec);\n        /* close deblock thread if it is not closed yet */\n        if(ps_dec->u4_num_cores == 3)\n        {\n            ih264d_signal_bs_deblk_thread(ps_dec);\n        }\n        /* dont consume bitstream for change in resolution case */\n        if(ret == IVD_RES_CHANGED)\n        {\n            ps_dec_op->u4_num_bytes_consumed -= bytes_consumed;\n        }\n        return IV_FAIL;\n    }\n\n\t/* Mirror some raw state info to output */\n\tps_dec_op->u1_frame_cropping_flag = ps_dec->u1_frame_cropping_flag;\n\tps_dec_op->u1_frame_cropping_rect_left_ofst = ps_dec->u1_frame_cropping_rect_left_ofst;\n\tps_dec_op->u1_frame_cropping_rect_right_ofst = ps_dec->u1_frame_cropping_rect_right_ofst;\n\tps_dec_op->u1_frame_cropping_rect_top_ofst = ps_dec->u1_frame_cropping_rect_top_ofst;\n\tps_dec_op->u1_frame_cropping_rect_bottom_ofst = ps_dec->u1_frame_cropping_rect_bottom_ofst;\n\n\tps_dec_op->u4_raw_wd = ps_dec->u2_pic_wd;\n\tps_dec_op->u4_raw_ht = ps_dec->u2_pic_ht;\n\n\n    if(ps_dec->u1_separate_parse)\n    {\n        /* If Format conversion is not complete,\n         complete it here */\n        if(ps_dec->u4_num_cores == 2)\n        {\n\n            /*do deblocking of all mbs*/\n            if((ps_dec->u4_nmb_deblk == 0) &&(ps_dec->u4_start_recon_deblk == 1) && (ps_dec->ps_cur_sps->u1_mb_aff_flag == 0))\n            {\n                UWORD32 u4_num_mbs,u4_max_addr;\n                tfr_ctxt_t s_tfr_ctxt;\n                tfr_ctxt_t *ps_tfr_cxt = &s_tfr_ctxt;\n                pad_mgr_t *ps_pad_mgr = &ps_dec->s_pad_mgr;\n\n                /*BS is done for all mbs while parsing*/\n                u4_max_addr = (ps_dec->u2_frm_wd_in_mbs * ps_dec->u2_frm_ht_in_mbs) - 1;\n                ps_dec->u4_cur_bs_mb_num = u4_max_addr + 1;\n\n\n                ih264d_init_deblk_tfr_ctxt(ps_dec, ps_pad_mgr, ps_tfr_cxt,\n                                           ps_dec->u2_frm_wd_in_mbs, 0);\n\n\n                u4_num_mbs = u4_max_addr\n                                - ps_dec->u4_cur_deblk_mb_num + 1;\n\n                DEBUG_PERF_PRINTF(\"mbs left for deblocking= %d \\n\",u4_num_mbs);\n\n                if(u4_num_mbs != 0)\n                    ih264d_check_mb_map_deblk(ps_dec, u4_num_mbs,\n                                                   ps_tfr_cxt,1);\n\n                ps_dec->u4_start_recon_deblk  = 0;\n\n            }\n\n        }\n\n        /*signal the decode thread*/\n        ih264d_signal_decode_thread(ps_dec);\n        /* close deblock thread if it is not closed yet*/\n        if(ps_dec->u4_num_cores == 3)\n        {\n            ih264d_signal_bs_deblk_thread(ps_dec);\n        }\n    }\n\n\n    DATA_SYNC();\n\n\n    if((ps_dec_op->u4_error_code & 0xff)\n                    != ERROR_DYNAMIC_RESOLUTION_NOT_SUPPORTED)\n    {\n        ps_dec_op->u4_pic_wd = (UWORD32)ps_dec->u2_disp_width;\n        ps_dec_op->u4_pic_ht = (UWORD32)ps_dec->u2_disp_height;\n        ps_dec_op->i4_reorder_depth = ps_dec->i4_reorder_depth;\n    }\n\n//Report if header (sps and pps) has not been decoded yet\n    if(ps_dec->i4_decode_header == 1 && ps_dec->i4_header_decoded != 3)\n    {\n        ps_dec_op->u4_error_code |= (1 << IVD_INSUFFICIENTDATA);\n        api_ret_value = IV_FAIL;\n    }\n\n    if((ps_dec->u4_pic_buf_got == 1)\n                    && (ERROR_DANGLING_FIELD_IN_PIC != i4_err_status))\n    {\n        /*\n         * For field pictures, set the bottom and top picture decoded u4_flag correctly.\n         */\n\n        if(ps_dec->ps_cur_slice->u1_field_pic_flag)\n        {\n            if(1 == ps_dec->ps_cur_slice->u1_bottom_field_flag)\n            {\n                ps_dec->u1_top_bottom_decoded |= BOT_FIELD_ONLY;\n            }\n            else\n            {\n                ps_dec->u1_top_bottom_decoded |= TOP_FIELD_ONLY;\n            }\n        }\n        else\n        {\n                ps_dec->u1_top_bottom_decoded = TOP_FIELD_ONLY | BOT_FIELD_ONLY;\n        }\n\n        /* if new frame in not found (if we are still getting slices from previous frame)\n         * ih264d_deblock_display is not called. Such frames will not be added to reference /display\n         */\n        if ((ps_dec->ps_dec_err_status->u1_err_flag & REJECT_CUR_PIC) == 0)\n        {\n            /* Calling Function to deblock Picture and Display */\n            ret = ih264d_deblock_display(ps_dec);\n        }\n\n\n        /*set to complete ,as we dont support partial frame decode*/\n        if(ps_dec->i4_header_decoded == 3)\n        {\n            ps_dec->u2_total_mbs_coded = ps_dec->ps_cur_sps->u2_max_mb_addr + 1;\n        }\n\n        /*Update the i4_frametype at the end of picture*/\n        if(ps_dec->ps_cur_slice->u1_nal_unit_type == IDR_SLICE_NAL)\n        {\n            ps_dec->i4_frametype = IV_IDR_FRAME;\n        }\n        else if(ps_dec->i4_pic_type == B_SLICE)\n        {\n            ps_dec->i4_frametype = IV_B_FRAME;\n        }\n        else if(ps_dec->i4_pic_type == P_SLICE)\n        {\n            ps_dec->i4_frametype = IV_P_FRAME;\n        }\n        else if(ps_dec->i4_pic_type == I_SLICE)\n        {\n            ps_dec->i4_frametype = IV_I_FRAME;\n        }\n        else\n        {\n            H264_DEC_DEBUG_PRINT(\"Shouldn't come here\\n\");\n        }\n\n        //Update the content type\n        ps_dec->i4_content_type = ps_dec->ps_cur_slice->u1_field_pic_flag;\n\n        ps_dec->u4_total_frames_decoded = ps_dec->u4_total_frames_decoded + 2;\n        ps_dec->u4_total_frames_decoded = ps_dec->u4_total_frames_decoded\n                        - ps_dec->ps_cur_slice->u1_field_pic_flag;\n\n    }\n\n    /* close deblock thread if it is not closed yet*/\n    if(ps_dec->u4_num_cores == 3)\n    {\n        ih264d_signal_bs_deblk_thread(ps_dec);\n    }\n\n\n    {\n        /* In case the decoder is configured to run in low delay mode,\n         * then get display buffer and then format convert.\n         * Note in this mode, format conversion does not run paralelly in a thread and adds to the codec cycles\n         */\n\n        if((IVD_DECODE_FRAME_OUT == ps_dec->e_frm_out_mode)\n                        && ps_dec->u1_init_dec_flag)\n        {\n\n            ih264d_get_next_display_field(ps_dec, ps_dec->ps_out_buffer,\n                                          &(ps_dec->s_disp_op));\n            if(0 == ps_dec->s_disp_op.u4_error_code)\n            {\n                ps_dec->u4_fmt_conv_cur_row = 0;\n                ps_dec->u4_output_present = 1;\n            }\n        }\n\n        ih264d_fill_output_struct_from_context(ps_dec, ps_dec_op);\n\n        /* If Format conversion is not complete,\n         complete it here */\n        if(ps_dec->u4_output_present &&\n          (ps_dec->u4_fmt_conv_cur_row < ps_dec->s_disp_frame_info.u4_y_ht))\n        {\n            ps_dec->u4_fmt_conv_num_rows = ps_dec->s_disp_frame_info.u4_y_ht\n                            - ps_dec->u4_fmt_conv_cur_row;\n            ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),\n                                  ps_dec->u4_fmt_conv_cur_row,\n                                  ps_dec->u4_fmt_conv_num_rows);\n            ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;\n        }\n\n        ih264d_release_display_field(ps_dec, &(ps_dec->s_disp_op));\n    }\n\n    if(ps_dec->i4_decode_header == 1 && (ps_dec->i4_header_decoded & 1) == 1)\n    {\n        ps_dec_op->u4_progressive_frame_flag = 1;\n        if((NULL != ps_dec->ps_cur_sps) && (1 == (ps_dec->ps_cur_sps->u1_is_valid)))\n        {\n            if((0 == ps_dec->ps_sps->u1_frame_mbs_only_flag)\n                            && (0 == ps_dec->ps_sps->u1_mb_aff_flag))\n                ps_dec_op->u4_progressive_frame_flag = 0;\n\n        }\n    }\n\n    if((TOP_FIELD_ONLY | BOT_FIELD_ONLY) == ps_dec->u1_top_bottom_decoded)\n    {\n        ps_dec->u1_top_bottom_decoded = 0;\n    }\n    /*--------------------------------------------------------------------*/\n    /* Do End of Pic processing.                                          */\n    /* Should be called only if frame was decoded in previous process call*/\n    /*--------------------------------------------------------------------*/\n    if(ps_dec->u4_pic_buf_got == 1)\n    {\n        if(1 == ps_dec->u1_last_pic_not_decoded)\n        {\n            ret = ih264d_end_of_pic_dispbuf_mgr(ps_dec);\n\n            if(ret != OK)\n                return ret;\n\n            ret = ih264d_end_of_pic(ps_dec);\n            if(ret != OK)\n                return ret;\n        }\n        else\n        {\n            ret = ih264d_end_of_pic(ps_dec);\n            if(ret != OK)\n                return ret;\n        }\n\n    }\n\n\n    /*Data memory barrier instruction,so that yuv write by the library is complete*/\n    DATA_SYNC();\n\n    H264_DEC_DEBUG_PRINT(\"The num bytes consumed: %d\\n\",\n                         ps_dec_op->u4_num_bytes_consumed);\n    return api_ret_value;\n}\n\nWORD32 ih264d_get_version(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n    char version_string[MAXVERSION_STRLEN + 1];\n    UWORD32 version_string_len;\n\n    ivd_ctl_getversioninfo_ip_t *ps_ip;\n    ivd_ctl_getversioninfo_op_t *ps_op;\n\n    ps_ip = (ivd_ctl_getversioninfo_ip_t *)pv_api_ip;\n    ps_op = (ivd_ctl_getversioninfo_op_t *)pv_api_op;\n    UNUSED(dec_hdl);\n    ps_op->u4_error_code = IV_SUCCESS;\n\n    VERSION(version_string, CODEC_NAME, CODEC_RELEASE_TYPE, CODEC_RELEASE_VER,\n            CODEC_VENDOR);\n\n    if((WORD32)ps_ip->u4_version_buffer_size <= 0)\n    {\n        ps_op->u4_error_code = IH264D_VERS_BUF_INSUFFICIENT;\n        return (IV_FAIL);\n    }\n\n    version_string_len = strnlen(version_string, MAXVERSION_STRLEN) + 1;\n\n    if(ps_ip->u4_version_buffer_size >= version_string_len) //(WORD32)sizeof(sizeof(version_string)))\n    {\n        memcpy(ps_ip->pv_version_buffer, version_string, version_string_len);\n        ps_op->u4_error_code = IV_SUCCESS;\n    }\n    else\n    {\n        ps_op->u4_error_code = IH264D_VERS_BUF_INSUFFICIENT;\n        return IV_FAIL;\n    }\n    return (IV_SUCCESS);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name :   ih264d_get_display_frame                               */\n/*                                                                           */\n/*  Description   :                                                          */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_get_display_frame(iv_obj_t *dec_hdl,\n                                void *pv_api_ip,\n                                void *pv_api_op)\n{\n\n    UNUSED(dec_hdl);\n    UNUSED(pv_api_ip);\n    UNUSED(pv_api_op);\n    // This function is no longer needed, output is returned in the process()\n    return IV_FAIL;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name :  ih264d_set_display_frame                                */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_set_display_frame(iv_obj_t *dec_hdl,\n                                void *pv_api_ip,\n                                void *pv_api_op)\n{\n\n    UWORD32 u4_disp_buf_size[3], u4_num_disp_bufs;\n    ivd_set_display_frame_ip_t *dec_disp_ip;\n    ivd_set_display_frame_op_t *dec_disp_op;\n\n    UWORD32 i;\n    dec_struct_t * ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);\n\n    dec_disp_ip = (ivd_set_display_frame_ip_t *)pv_api_ip;\n    dec_disp_op = (ivd_set_display_frame_op_t *)pv_api_op;\n    dec_disp_op->u4_error_code = 0;\n\n\n    ps_dec->u4_num_disp_bufs = 0;\n    if(ps_dec->u4_share_disp_buf)\n    {\n        UWORD32 u4_num_bufs = dec_disp_ip->num_disp_bufs;\n\n        u4_num_bufs = MIN(u4_num_bufs, MAX_DISP_BUFS_NEW);\n\n        ps_dec->u4_num_disp_bufs = u4_num_bufs;\n\n        /* Get the number and sizes of the first buffer. Compare this with the\n         * rest to make sure all the buffers are of the same size.\n         */\n        u4_num_disp_bufs = dec_disp_ip->s_disp_buffer[0].u4_num_bufs;\n\n        u4_disp_buf_size[0] =\n          dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[0];\n        u4_disp_buf_size[1] =\n          dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[1];\n        u4_disp_buf_size[2] =\n          dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[2];\n\n        for(i = 0; i < u4_num_bufs; i++)\n        {\n            if(dec_disp_ip->s_disp_buffer[i].u4_num_bufs != u4_num_disp_bufs)\n            {\n                return IV_FAIL;\n            }\n\n            if((dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[0]\n                != u4_disp_buf_size[0])\n                || (dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[1]\n                    != u4_disp_buf_size[1])\n                || (dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[2]\n                    != u4_disp_buf_size[2]))\n            {\n                return IV_FAIL;\n            }\n\n            ps_dec->disp_bufs[i].u4_num_bufs =\n                            dec_disp_ip->s_disp_buffer[i].u4_num_bufs;\n\n            ps_dec->disp_bufs[i].buf[0] =\n                            dec_disp_ip->s_disp_buffer[i].pu1_bufs[0];\n            ps_dec->disp_bufs[i].buf[1] =\n                            dec_disp_ip->s_disp_buffer[i].pu1_bufs[1];\n            ps_dec->disp_bufs[i].buf[2] =\n                            dec_disp_ip->s_disp_buffer[i].pu1_bufs[2];\n\n            ps_dec->disp_bufs[i].u4_bufsize[0] =\n                            dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[0];\n            ps_dec->disp_bufs[i].u4_bufsize[1] =\n                            dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[1];\n            ps_dec->disp_bufs[i].u4_bufsize[2] =\n                            dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[2];\n\n        }\n    }\n    return IV_SUCCESS;\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_set_flush_mode                                    */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_set_flush_mode(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n    dec_struct_t * ps_dec;\n    ivd_ctl_flush_op_t *ps_ctl_op = (ivd_ctl_flush_op_t*)pv_api_op;\n    ps_ctl_op->u4_error_code = 0;\n\n    ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);\n    UNUSED(pv_api_ip);\n    /* ! */\n    /* Signal flush frame control call */\n    ps_dec->u1_flushfrm = 1;\n\n    if(ps_dec->u1_init_dec_flag == 1)\n    {\n        ih264d_release_pics_in_dpb((void *)ps_dec, ps_dec->u1_pic_bufs);\n        ih264d_release_display_bufs(ps_dec);\n    }\n\n    ps_ctl_op->u4_error_code = 0;\n\n    /* Ignore dangling fields during flush */\n    ps_dec->u1_top_bottom_decoded = 0;\n\n    return IV_SUCCESS;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_get_status                                        */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_get_status(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n\n    UWORD32 i;\n    dec_struct_t * ps_dec;\n    UWORD32 pic_wd, pic_ht;\n    ivd_ctl_getstatus_op_t *ps_ctl_op = (ivd_ctl_getstatus_op_t*)pv_api_op;\n    UNUSED(pv_api_ip);\n    ps_ctl_op->u4_error_code = 0;\n\n    ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);\n\n\n    if((NULL != ps_dec->ps_cur_sps) && (1 == (ps_dec->ps_cur_sps->u1_is_valid)))\n    {\n        ps_ctl_op->u4_pic_ht = ps_dec->u2_disp_height;\n        ps_ctl_op->u4_pic_wd = ps_dec->u2_disp_width;\n\n        if(0 == ps_dec->u4_share_disp_buf)\n        {\n            pic_wd = ps_dec->u2_disp_width;\n            pic_ht = ps_dec->u2_disp_height;\n\n        }\n        else\n        {\n            pic_wd = ps_dec->u2_frm_wd_y;\n            pic_ht = ps_dec->u2_frm_ht_y;\n        }\n    }\n    else\n    {\n        pic_wd = 0;\n        pic_ht = 0;\n\n        ps_ctl_op->u4_pic_ht = pic_wd;\n        ps_ctl_op->u4_pic_wd = pic_ht;\n\n        if(1 == ps_dec->u4_share_disp_buf)\n        {\n            pic_wd += (PAD_LEN_Y_H << 1);\n            pic_ht += (PAD_LEN_Y_V << 2);\n\n        }\n\n    }\n\n    if(ps_dec->u4_app_disp_width > pic_wd)\n        pic_wd = ps_dec->u4_app_disp_width;\n    if(0 == ps_dec->u4_share_disp_buf)\n        ps_ctl_op->u4_num_disp_bufs = 1;\n    else\n    {\n        if((NULL != ps_dec->ps_cur_sps) && (1 == (ps_dec->ps_cur_sps->u1_is_valid)))\n        {\n            if((ps_dec->ps_cur_sps->u1_vui_parameters_present_flag == 1) &&\n               (1 == ps_dec->ps_cur_sps->s_vui.u1_bitstream_restriction_flag))\n            {\n                ps_ctl_op->u4_num_disp_bufs =\n                                ps_dec->ps_cur_sps->s_vui.u4_num_reorder_frames + 1;\n            }\n            else\n            {\n                /*if VUI is not present assume maximum possible refrence frames for the level,\n                 * as max reorder frames*/\n                ps_ctl_op->u4_num_disp_bufs = ih264d_get_dpb_size(ps_dec->ps_cur_sps);\n            }\n\n            ps_ctl_op->u4_num_disp_bufs +=\n                            ps_dec->ps_cur_sps->u1_num_ref_frames + 1;\n        }\n        else\n        {\n            ps_ctl_op->u4_num_disp_bufs = 32;\n        }\n        ps_ctl_op->u4_num_disp_bufs = MAX(\n                        ps_ctl_op->u4_num_disp_bufs, 6);\n        ps_ctl_op->u4_num_disp_bufs = MIN(\n                        ps_ctl_op->u4_num_disp_bufs, 32);\n    }\n\n    ps_ctl_op->u4_error_code = ps_dec->i4_error_code;\n\n    ps_ctl_op->u4_frame_rate = 0; //make it proper\n    ps_ctl_op->u4_bit_rate = 0; //make it proper\n    ps_ctl_op->e_content_type = ps_dec->i4_content_type;\n    ps_ctl_op->e_output_chroma_format = ps_dec->u1_chroma_format;\n    ps_ctl_op->u4_min_num_in_bufs = MIN_IN_BUFS;\n\n    if(ps_dec->u1_chroma_format == IV_YUV_420P)\n    {\n        ps_ctl_op->u4_min_num_out_bufs = MIN_OUT_BUFS_420;\n    }\n    else if(ps_dec->u1_chroma_format == IV_YUV_422ILE)\n    {\n        ps_ctl_op->u4_min_num_out_bufs = MIN_OUT_BUFS_422ILE;\n    }\n    else if(ps_dec->u1_chroma_format == IV_RGB_565)\n    {\n        ps_ctl_op->u4_min_num_out_bufs = MIN_OUT_BUFS_RGB565;\n    }\n    else if((ps_dec->u1_chroma_format == IV_YUV_420SP_UV)\n                    || (ps_dec->u1_chroma_format == IV_YUV_420SP_VU))\n    {\n        ps_ctl_op->u4_min_num_out_bufs = MIN_OUT_BUFS_420SP;\n    }\n\n    else\n    {\n        //Invalid chroma format; Error code may be updated, verify in testing if needed\n        ps_ctl_op->u4_error_code = ERROR_FEATURE_UNAVAIL;\n        return IV_FAIL;\n    }\n\n    for(i = 0; i < ps_ctl_op->u4_min_num_in_bufs; i++)\n    {\n        ps_ctl_op->u4_min_in_buf_size[i] = MAX(256000, pic_wd * pic_ht * 3 / 2);\n    }\n\n    /*!*/\n    if(ps_dec->u1_chroma_format == IV_YUV_420P)\n    {\n        ps_ctl_op->u4_min_out_buf_size[0] = (pic_wd * pic_ht);\n        ps_ctl_op->u4_min_out_buf_size[1] = (pic_wd * pic_ht)\n                        >> 2;\n        ps_ctl_op->u4_min_out_buf_size[2] = (pic_wd * pic_ht)\n                        >> 2;\n    }\n    else if(ps_dec->u1_chroma_format == IV_YUV_422ILE)\n    {\n        ps_ctl_op->u4_min_out_buf_size[0] = (pic_wd * pic_ht)\n                        * 2;\n        ps_ctl_op->u4_min_out_buf_size[1] =\n                        ps_ctl_op->u4_min_out_buf_size[2] = 0;\n    }\n    else if(ps_dec->u1_chroma_format == IV_RGB_565)\n    {\n        ps_ctl_op->u4_min_out_buf_size[0] = (pic_wd * pic_ht)\n                        * 2;\n        ps_ctl_op->u4_min_out_buf_size[1] =\n                        ps_ctl_op->u4_min_out_buf_size[2] = 0;\n    }\n    else if((ps_dec->u1_chroma_format == IV_YUV_420SP_UV)\n                    || (ps_dec->u1_chroma_format == IV_YUV_420SP_VU))\n    {\n        ps_ctl_op->u4_min_out_buf_size[0] = (pic_wd * pic_ht);\n        ps_ctl_op->u4_min_out_buf_size[1] = (pic_wd * pic_ht)\n                        >> 1;\n        ps_ctl_op->u4_min_out_buf_size[2] = 0;\n    }\n\n    ps_dec->u4_num_disp_bufs_requested = ps_ctl_op->u4_num_disp_bufs;\n    return IV_SUCCESS;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name :    ih264d_get_buf_info                                   */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_get_buf_info(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n\n    dec_struct_t * ps_dec;\n    UWORD8 i = 0; // Default for 420P format\n    UWORD16 pic_wd, pic_ht;\n    ivd_ctl_getbufinfo_op_t *ps_ctl_op =\n                    (ivd_ctl_getbufinfo_op_t*)pv_api_op;\n    UWORD32 au4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];\n    UNUSED(pv_api_ip);\n\n    ps_ctl_op->u4_error_code = 0;\n\n    ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);\n\n    ps_ctl_op->u4_min_num_in_bufs = MIN_IN_BUFS;\n\n\n    ps_ctl_op->u4_num_disp_bufs = 1;\n\n\n    pic_wd = 0;\n    pic_ht = 0;\n\n    if(ps_dec->i4_header_decoded == 3)\n    {\n\n        if(0 == ps_dec->u4_share_disp_buf)\n        {\n            pic_wd = ps_dec->u2_disp_width;\n            pic_ht = ps_dec->u2_disp_height;\n\n        }\n        else\n        {\n            pic_wd = ps_dec->u2_frm_wd_y;\n            pic_ht = ps_dec->u2_frm_ht_y;\n        }\n\n    }\n\n    for(i = 0; i < ps_ctl_op->u4_min_num_in_bufs; i++)\n    {\n        ps_ctl_op->u4_min_in_buf_size[i] = MAX(256000, pic_wd * pic_ht * 3 / 2);\n    }\n    if((WORD32)ps_dec->u4_app_disp_width > pic_wd)\n        pic_wd = ps_dec->u4_app_disp_width;\n\n    if(0 == ps_dec->u4_share_disp_buf)\n        ps_ctl_op->u4_num_disp_bufs = 1;\n    else\n    {\n        if((NULL != ps_dec->ps_cur_sps) && (1 == (ps_dec->ps_cur_sps->u1_is_valid)))\n        {\n            if((ps_dec->ps_cur_sps->u1_vui_parameters_present_flag == 1) &&\n               (1 == ps_dec->ps_cur_sps->s_vui.u1_bitstream_restriction_flag))\n            {\n                ps_ctl_op->u4_num_disp_bufs =\n                                ps_dec->ps_cur_sps->s_vui.u4_num_reorder_frames + 1;\n            }\n            else\n            {\n                /*if VUI is not present assume maximum possible refrence frames for the level,\n                 * as max reorder frames*/\n                ps_ctl_op->u4_num_disp_bufs = ih264d_get_dpb_size(ps_dec->ps_cur_sps);\n            }\n\n            ps_ctl_op->u4_num_disp_bufs +=\n                            ps_dec->ps_cur_sps->u1_num_ref_frames + 1;\n\n        }\n        else\n        {\n            ps_ctl_op->u4_num_disp_bufs = 32;\n\n        }\n\n        ps_ctl_op->u4_num_disp_bufs = MAX(\n                        ps_ctl_op->u4_num_disp_bufs, 6);\n        ps_ctl_op->u4_num_disp_bufs = MIN(\n                        ps_ctl_op->u4_num_disp_bufs, 32);\n    }\n\n    ps_ctl_op->u4_min_num_out_bufs = ih264d_get_outbuf_size(\n                    pic_wd, pic_ht, ps_dec->u1_chroma_format,\n                    &au4_min_out_buf_size[0]);\n\n    for(i = 0; i < ps_ctl_op->u4_min_num_out_bufs; i++)\n    {\n        ps_ctl_op->u4_min_out_buf_size[i] = au4_min_out_buf_size[i];\n    }\n\n    ps_dec->u4_num_disp_bufs_requested = ps_ctl_op->u4_num_disp_bufs;\n\n    return IV_SUCCESS;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_set_params                                        */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_set_params(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n\n    dec_struct_t * ps_dec;\n    WORD32 ret = IV_SUCCESS;\n\n    ih264d_ctl_set_config_ip_t *ps_h264d_ctl_ip =\n                    (ih264d_ctl_set_config_ip_t *)pv_api_ip;\n    ih264d_ctl_set_config_op_t *ps_h264d_ctl_op =\n                    (ih264d_ctl_set_config_op_t *)pv_api_op;;\n    ivd_ctl_set_config_ip_t *ps_ctl_ip =\n                    &ps_h264d_ctl_ip->s_ivd_ctl_set_config_ip_t;\n    ivd_ctl_set_config_op_t *ps_ctl_op =\n                    &ps_h264d_ctl_op->s_ivd_ctl_set_config_op_t;\n\n    ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);\n\n    ps_dec->u4_skip_frm_mask = 0;\n\n    ps_ctl_op->u4_error_code = 0;\n\n    if(ps_ctl_ip->e_frm_skip_mode != IVD_SKIP_NONE)\n    {\n        ps_ctl_op->u4_error_code = (1 << IVD_UNSUPPORTEDPARAM);\n        ret = IV_FAIL;\n    }\n\n    if(ps_ctl_ip->u4_disp_wd >= ps_dec->u2_disp_width)\n    {\n        ps_dec->u4_app_disp_width = ps_ctl_ip->u4_disp_wd;\n    }\n    else if(0 == ps_dec->i4_header_decoded)\n    {\n        ps_dec->u4_app_disp_width = ps_ctl_ip->u4_disp_wd;\n    }\n    else if(ps_ctl_ip->u4_disp_wd == 0)\n    {\n        ps_dec->u4_app_disp_width = 0;\n    }\n    else\n    {\n        /*\n         * Set the display width to zero. This will ensure that the wrong value we had stored (0xFFFFFFFF)\n         * does not propogate.\n         */\n        ps_dec->u4_app_disp_width = 0;\n        ps_ctl_op->u4_error_code |= (1 << IVD_UNSUPPORTEDPARAM);\n        ps_ctl_op->u4_error_code |= ERROR_DISP_WIDTH_INVALID;\n        ret = IV_FAIL;\n    }\n\n    if(ps_ctl_ip->e_vid_dec_mode == IVD_DECODE_FRAME)\n        ps_dec->i4_decode_header = 0;\n    else if(ps_ctl_ip->e_vid_dec_mode == IVD_DECODE_HEADER)\n        ps_dec->i4_decode_header = 1;\n    else\n    {\n        ps_ctl_op->u4_error_code = (1 << IVD_UNSUPPORTEDPARAM);\n        ps_dec->i4_decode_header = 1;\n        ret = IV_FAIL;\n    }\n    ps_dec->e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;\n\n    if((ps_ctl_ip->e_frm_out_mode != IVD_DECODE_FRAME_OUT) &&\n       (ps_ctl_ip->e_frm_out_mode != IVD_DISPLAY_FRAME_OUT))\n    {\n        ps_ctl_op->u4_error_code = (1 << IVD_UNSUPPORTEDPARAM);\n        ret = IV_FAIL;\n    }\n    ps_dec->e_frm_out_mode = ps_ctl_ip->e_frm_out_mode;\n    return ret;\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_set_default_params                                */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         08 08 2011   100421          Copied from set_params               */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_set_default_params(iv_obj_t *dec_hdl,\n                                 void *pv_api_ip,\n                                 void *pv_api_op)\n{\n\n    dec_struct_t * ps_dec;\n    WORD32 ret = IV_SUCCESS;\n\n    ivd_ctl_set_config_op_t *ps_ctl_op =\n                    (ivd_ctl_set_config_op_t *)pv_api_op;\n    ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);\n    UNUSED(pv_api_ip);\n\n\n    {\n        ps_dec->u4_app_disp_width = 0;\n        ps_dec->u4_skip_frm_mask = 0;\n        ps_dec->i4_decode_header = 1;\n\n        ps_ctl_op->u4_error_code = 0;\n    }\n\n\n    return ret;\n}\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name :  ih264d_reset                                            */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_delete(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n    dec_struct_t *ps_dec;\n    ih264d_delete_ip_t *ps_ip = (ih264d_delete_ip_t *)pv_api_ip;\n    ih264d_delete_op_t *ps_op = (ih264d_delete_op_t *)pv_api_op;\n\n    ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);\n    UNUSED(ps_ip);\n    ps_op->s_ivd_delete_op_t.u4_error_code = 0;\n    ih264d_free_dynamic_bufs(ps_dec);\n    ih264d_free_static_bufs(dec_hdl);\n    return IV_SUCCESS;\n}\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name :  ih264d_reset                                            */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_reset(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n    dec_struct_t * ps_dec;\n    ivd_ctl_reset_op_t *ps_ctl_op = (ivd_ctl_reset_op_t *)pv_api_op;\n    UNUSED(pv_api_ip);\n    ps_ctl_op->u4_error_code = 0;\n\n    ps_dec = (dec_struct_t *)(dec_hdl->pv_codec_handle);\n\n    if(ps_dec != NULL)\n    {\n        ih264d_init_decoder(ps_dec);\n    }\n    else\n    {\n        H264_DEC_DEBUG_PRINT(\n                        \"\\nReset called without Initializing the decoder\\n\");\n        ps_ctl_op->u4_error_code = ERROR_INIT_NOT_DONE;\n    }\n\n    return IV_SUCCESS;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name :  ih264d_ctl                                              */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_ctl(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n    ivd_ctl_set_config_ip_t *ps_ctl_ip;\n    ivd_ctl_set_config_op_t *ps_ctl_op;\n    WORD32 ret = IV_SUCCESS;\n    UWORD32 subcommand;\n    dec_struct_t *ps_dec = dec_hdl->pv_codec_handle;\n\n    if(ps_dec->init_done != 1)\n    {\n        //Return proper Error Code\n        return IV_FAIL;\n    }\n    ps_ctl_ip = (ivd_ctl_set_config_ip_t*)pv_api_ip;\n    ps_ctl_op = (ivd_ctl_set_config_op_t*)pv_api_op;\n    ps_ctl_op->u4_error_code = 0;\n    subcommand = ps_ctl_ip->e_sub_cmd;\n\n    switch(subcommand)\n    {\n        case IVD_CMD_CTL_GETPARAMS:\n            ret = ih264d_get_status(dec_hdl, (void *)pv_api_ip,\n                                    (void *)pv_api_op);\n            break;\n        case IVD_CMD_CTL_SETPARAMS:\n            ret = ih264d_set_params(dec_hdl, (void *)pv_api_ip,\n                                    (void *)pv_api_op);\n            break;\n        case IVD_CMD_CTL_RESET:\n            ret = ih264d_reset(dec_hdl, (void *)pv_api_ip, (void *)pv_api_op);\n            break;\n        case IVD_CMD_CTL_SETDEFAULT:\n            ret = ih264d_set_default_params(dec_hdl, (void *)pv_api_ip,\n                                            (void *)pv_api_op);\n            break;\n        case IVD_CMD_CTL_FLUSH:\n            ret = ih264d_set_flush_mode(dec_hdl, (void *)pv_api_ip,\n                                        (void *)pv_api_op);\n            break;\n        case IVD_CMD_CTL_GETBUFINFO:\n            ret = ih264d_get_buf_info(dec_hdl, (void *)pv_api_ip,\n                                      (void *)pv_api_op);\n            break;\n        case IVD_CMD_CTL_GETVERSION:\n            ret = ih264d_get_version(dec_hdl, (void *)pv_api_ip,\n                                     (void *)pv_api_op);\n            break;\n        case IH264D_CMD_CTL_DEGRADE:\n            ret = ih264d_set_degrade(dec_hdl, (void *)pv_api_ip,\n                                     (void *)pv_api_op);\n            break;\n\n        case IH264D_CMD_CTL_SET_NUM_CORES:\n            ret = ih264d_set_num_cores(dec_hdl, (void *)pv_api_ip,\n                                       (void *)pv_api_op);\n            break;\n        case IH264D_CMD_CTL_GET_BUFFER_DIMENSIONS:\n            ret = ih264d_get_frame_dimensions(dec_hdl, (void *)pv_api_ip,\n                                              (void *)pv_api_op);\n            break;\n        case IH264D_CMD_CTL_GET_VUI_PARAMS:\n            ret = ih264d_get_vui_params(dec_hdl, (void *)pv_api_ip,\n                                        (void *)pv_api_op);\n            break;\n        case IH264D_CMD_CTL_GET_SEI_MDCV_PARAMS:\n            ret = ih264d_get_sei_mdcv_params(dec_hdl, (void *)pv_api_ip,\n                                             (void *)pv_api_op);\n            break;\n        case IH264D_CMD_CTL_GET_SEI_CLL_PARAMS:\n            ret = ih264d_get_sei_cll_params(dec_hdl, (void *)pv_api_ip,\n                                            (void *)pv_api_op);\n            break;\n        case IH264D_CMD_CTL_GET_SEI_AVE_PARAMS:\n            ret = ih264d_get_sei_ave_params(dec_hdl, (void *)pv_api_ip,\n                                            (void *)pv_api_op);\n            break;\n        case IH264D_CMD_CTL_GET_SEI_CCV_PARAMS:\n            ret = ih264d_get_sei_ccv_params(dec_hdl, (void *)pv_api_ip,\n                                            (void *)pv_api_op);\n            break;\n        case IH264D_CMD_CTL_SET_PROCESSOR:\n            ret = ih264d_set_processor(dec_hdl, (void *)pv_api_ip,\n                                       (void *)pv_api_op);\n            break;\n        default:\n            H264_DEC_DEBUG_PRINT(\"\\ndo nothing\\n\")\n            ;\n            break;\n    }\n\n    return ret;\n}\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name :   ih264d_rel_display_frame                               */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_rel_display_frame(iv_obj_t *dec_hdl,\n                                void *pv_api_ip,\n                                void *pv_api_op)\n{\n\n    ivd_rel_display_frame_ip_t *ps_rel_ip;\n    ivd_rel_display_frame_op_t *ps_rel_op;\n    UWORD32 buf_released = 0;\n\n    UWORD32 u4_ts = 0;\n    dec_struct_t *ps_dec = dec_hdl->pv_codec_handle;\n\n    ps_rel_ip = (ivd_rel_display_frame_ip_t *)pv_api_ip;\n    ps_rel_op = (ivd_rel_display_frame_op_t *)pv_api_op;\n    ps_rel_op->u4_error_code = 0;\n    u4_ts = ps_rel_ip->u4_disp_buf_id;\n\n    if(0 == ps_dec->u4_share_disp_buf)\n    {\n        ps_dec->u4_disp_buf_mapping[u4_ts] = 0;\n        ps_dec->u4_disp_buf_to_be_freed[u4_ts] = 0;\n        return IV_SUCCESS;\n    }\n\n    if(ps_dec->pv_pic_buf_mgr != NULL)\n    {\n        if(1 == ps_dec->u4_disp_buf_mapping[u4_ts])\n        {\n            ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                  ps_rel_ip->u4_disp_buf_id,\n                                  BUF_MGR_IO);\n            ps_dec->u4_disp_buf_mapping[u4_ts] = 0;\n            buf_released = 1;\n        }\n    }\n\n    if((1 == ps_dec->u4_share_disp_buf) && (0 == buf_released))\n        ps_dec->u4_disp_buf_to_be_freed[u4_ts] = 1;\n\n    return IV_SUCCESS;\n}\n\n/**\n *******************************************************************************\n *\n * @brief\n *  Sets degrade params\n *\n * @par Description:\n *  Sets degrade params.\n *  Refer to ih264d_ctl_degrade_ip_t definition for details\n *\n * @param[in] ps_codec_obj\n *  Pointer to codec object at API level\n *\n * @param[in] pv_api_ip\n *  Pointer to input argument structure\n *\n * @param[out] pv_api_op\n *  Pointer to output argument structure\n *\n * @returns  Status\n *\n * @remarks\n *\n *\n *******************************************************************************\n */\n\nWORD32 ih264d_set_degrade(iv_obj_t *ps_codec_obj,\n                          void *pv_api_ip,\n                          void *pv_api_op)\n{\n    ih264d_ctl_degrade_ip_t *ps_ip;\n    ih264d_ctl_degrade_op_t *ps_op;\n    dec_struct_t *ps_codec = (dec_struct_t *)ps_codec_obj->pv_codec_handle;\n\n    ps_ip = (ih264d_ctl_degrade_ip_t *)pv_api_ip;\n    ps_op = (ih264d_ctl_degrade_op_t *)pv_api_op;\n\n    ps_codec->i4_degrade_type = ps_ip->i4_degrade_type;\n    ps_codec->i4_nondegrade_interval = ps_ip->i4_nondegrade_interval;\n    ps_codec->i4_degrade_pics = ps_ip->i4_degrade_pics;\n\n    ps_op->u4_error_code = 0;\n    ps_codec->i4_degrade_pic_cnt = 0;\n\n    return IV_SUCCESS;\n}\n\nWORD32 ih264d_get_frame_dimensions(iv_obj_t *dec_hdl,\n                                   void *pv_api_ip,\n                                   void *pv_api_op)\n{\n    ih264d_ctl_get_frame_dimensions_ip_t *ps_ip;\n    ih264d_ctl_get_frame_dimensions_op_t *ps_op;\n    dec_struct_t *ps_dec = dec_hdl->pv_codec_handle;\n    UWORD32 disp_wd, disp_ht, buffer_wd, buffer_ht, x_offset, y_offset;\n\n    ps_ip = (ih264d_ctl_get_frame_dimensions_ip_t *)pv_api_ip;\n\n    ps_op = (ih264d_ctl_get_frame_dimensions_op_t *)pv_api_op;\n    UNUSED(ps_ip);\n    if((NULL != ps_dec->ps_cur_sps) && (1 == (ps_dec->ps_cur_sps->u1_is_valid)))\n    {\n        disp_wd = ps_dec->u2_disp_width;\n        disp_ht = ps_dec->u2_disp_height;\n\n        if(0 == ps_dec->u4_share_disp_buf)\n        {\n            buffer_wd = disp_wd;\n            buffer_ht = disp_ht;\n        }\n        else\n        {\n            buffer_wd = ps_dec->u2_frm_wd_y;\n            buffer_ht = ps_dec->u2_frm_ht_y;\n        }\n    }\n    else\n    {\n        disp_wd = 0;\n        disp_ht = 0;\n\n        if(0 == ps_dec->u4_share_disp_buf)\n        {\n            buffer_wd = disp_wd;\n            buffer_ht = disp_ht;\n        }\n        else\n        {\n            buffer_wd = ALIGN16(disp_wd) + (PAD_LEN_Y_H << 1);\n            buffer_ht = ALIGN16(disp_ht) + (PAD_LEN_Y_V << 2);\n        }\n    }\n    if(ps_dec->u4_app_disp_width > buffer_wd)\n        buffer_wd = ps_dec->u4_app_disp_width;\n\n    if(0 == ps_dec->u4_share_disp_buf)\n    {\n        x_offset = 0;\n        y_offset = 0;\n    }\n    else\n    {\n        y_offset = (PAD_LEN_Y_V << 1);\n        x_offset = PAD_LEN_Y_H;\n\n        if((NULL != ps_dec->ps_sps) && (1 == (ps_dec->ps_sps->u1_is_valid))\n                        && (0 != ps_dec->u2_crop_offset_y))\n        {\n            y_offset += ps_dec->u2_crop_offset_y / ps_dec->u2_frm_wd_y;\n            x_offset += ps_dec->u2_crop_offset_y % ps_dec->u2_frm_wd_y;\n        }\n    }\n\n    ps_op->u4_disp_wd[0] = disp_wd;\n    ps_op->u4_disp_ht[0] = disp_ht;\n    ps_op->u4_buffer_wd[0] = buffer_wd;\n    ps_op->u4_buffer_ht[0] = buffer_ht;\n    ps_op->u4_x_offset[0] = x_offset;\n    ps_op->u4_y_offset[0] = y_offset;\n\n    ps_op->u4_disp_wd[1] = ps_op->u4_disp_wd[2] = ((ps_op->u4_disp_wd[0] + 1)\n                    >> 1);\n    ps_op->u4_disp_ht[1] = ps_op->u4_disp_ht[2] = ((ps_op->u4_disp_ht[0] + 1)\n                    >> 1);\n    ps_op->u4_buffer_wd[1] = ps_op->u4_buffer_wd[2] = (ps_op->u4_buffer_wd[0]\n                    >> 1);\n    ps_op->u4_buffer_ht[1] = ps_op->u4_buffer_ht[2] = (ps_op->u4_buffer_ht[0]\n                    >> 1);\n    ps_op->u4_x_offset[1] = ps_op->u4_x_offset[2] =\n                    (ps_op->u4_x_offset[0] >> 1);\n    ps_op->u4_y_offset[1] = ps_op->u4_y_offset[2] =\n                    (ps_op->u4_y_offset[0] >> 1);\n\n    if((ps_dec->u1_chroma_format == IV_YUV_420SP_UV)\n                    || (ps_dec->u1_chroma_format == IV_YUV_420SP_VU))\n    {\n        ps_op->u4_disp_wd[2] = 0;\n        ps_op->u4_disp_ht[2] = 0;\n        ps_op->u4_buffer_wd[2] = 0;\n        ps_op->u4_buffer_ht[2] = 0;\n        ps_op->u4_x_offset[2] = 0;\n        ps_op->u4_y_offset[2] = 0;\n\n        ps_op->u4_disp_wd[1] <<= 1;\n        ps_op->u4_buffer_wd[1] <<= 1;\n        ps_op->u4_x_offset[1] <<= 1;\n    }\n\n    return IV_SUCCESS;\n\n}\n\nWORD32 ih264d_get_vui_params(iv_obj_t *dec_hdl,\n                             void *pv_api_ip,\n                             void *pv_api_op)\n{\n    ih264d_ctl_get_vui_params_ip_t *ps_ip;\n    ih264d_ctl_get_vui_params_op_t *ps_op;\n    dec_struct_t *ps_dec = dec_hdl->pv_codec_handle;\n    dec_seq_params_t *ps_sps;\n    vui_t *ps_vui;\n    WORD32 i;\n    UWORD32 u4_size;\n\n    ps_ip = (ih264d_ctl_get_vui_params_ip_t *)pv_api_ip;\n    ps_op = (ih264d_ctl_get_vui_params_op_t *)pv_api_op;\n    UNUSED(ps_ip);\n\n    u4_size = ps_op->u4_size;\n    memset(ps_op, 0, sizeof(ih264d_ctl_get_vui_params_op_t));\n    ps_op->u4_size = u4_size;\n\n    if(NULL == ps_dec->ps_cur_sps)\n    {\n        ps_op->u4_error_code = ERROR_VUI_PARAMS_NOT_FOUND;\n        return IV_FAIL;\n    }\n\n    ps_sps = ps_dec->ps_cur_sps;\n    if((0 == ps_sps->u1_is_valid)\n                    || (0 == ps_sps->u1_vui_parameters_present_flag))\n    {\n        ps_op->u4_error_code = ERROR_VUI_PARAMS_NOT_FOUND;\n        return IV_FAIL;\n    }\n\n    ps_vui = &ps_sps->s_vui;\n\n    ps_op->u1_aspect_ratio_idc              = ps_vui->u1_aspect_ratio_idc;\n    ps_op->u2_sar_width                     = ps_vui->u2_sar_width;\n    ps_op->u2_sar_height                    = ps_vui->u2_sar_height;\n    ps_op->u1_overscan_appropriate_flag     = ps_vui->u1_overscan_appropriate_flag;\n    ps_op->u1_video_format                  = ps_vui->u1_video_format;\n    ps_op->u1_video_full_range_flag         = ps_vui->u1_video_full_range_flag;\n    ps_op->u1_colour_primaries              = ps_vui->u1_colour_primaries;\n    ps_op->u1_tfr_chars                     = ps_vui->u1_tfr_chars;\n    ps_op->u1_matrix_coeffs                 = ps_vui->u1_matrix_coeffs;\n    ps_op->u1_cr_top_field                  = ps_vui->u1_cr_top_field;\n    ps_op->u1_cr_bottom_field               = ps_vui->u1_cr_bottom_field;\n    ps_op->u4_num_units_in_tick             = ps_vui->u4_num_units_in_tick;\n    ps_op->u4_time_scale                    = ps_vui->u4_time_scale;\n    ps_op->u1_fixed_frame_rate_flag         = ps_vui->u1_fixed_frame_rate_flag;\n    ps_op->u1_nal_hrd_params_present        = ps_vui->u1_nal_hrd_params_present;\n    ps_op->u1_vcl_hrd_params_present        = ps_vui->u1_vcl_hrd_params_present;\n    ps_op->u1_low_delay_hrd_flag            = ps_vui->u1_low_delay_hrd_flag;\n    ps_op->u1_pic_struct_present_flag       = ps_vui->u1_pic_struct_present_flag;\n    ps_op->u1_bitstream_restriction_flag    = ps_vui->u1_bitstream_restriction_flag;\n    ps_op->u1_mv_over_pic_boundaries_flag   = ps_vui->u1_mv_over_pic_boundaries_flag;\n    ps_op->u4_max_bytes_per_pic_denom       = ps_vui->u4_max_bytes_per_pic_denom;\n    ps_op->u4_max_bits_per_mb_denom         = ps_vui->u4_max_bits_per_mb_denom;\n    ps_op->u4_log2_max_mv_length_horz       = ps_vui->u4_log2_max_mv_length_horz;\n    ps_op->u4_log2_max_mv_length_vert       = ps_vui->u4_log2_max_mv_length_vert;\n    ps_op->u4_num_reorder_frames            = ps_vui->u4_num_reorder_frames;\n    ps_op->u4_max_dec_frame_buffering       = ps_vui->u4_max_dec_frame_buffering;\n\n    return IV_SUCCESS;\n}\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_get_sei_mdcv_params                               */\n/*                                                                           */\n/*  Description   : This function populates SEI mdcv message in              */\n/*                     output structure                                      */\n/*  Inputs        : iv_obj_t decoder handle                                  */\n/*                : pv_api_ip pointer to input structure                     */\n/*                : pv_api_op pointer to output structure                    */\n/*  Outputs       :                                                          */\n/*  Returns       : returns 0; 1 with error code when MDCV is not present    */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                                                           */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_get_sei_mdcv_params(iv_obj_t *dec_hdl,\n                                  void *pv_api_ip,\n                                  void *pv_api_op)\n{\n    ih264d_ctl_get_sei_mdcv_params_ip_t *ps_ip;\n    ih264d_ctl_get_sei_mdcv_params_op_t *ps_op;\n    dec_struct_t *ps_dec = dec_hdl->pv_codec_handle;\n    sei_mdcv_params_t *ps_sei_mdcv;\n    WORD32 i4_count;\n\n    ps_ip = (ih264d_ctl_get_sei_mdcv_params_ip_t *)pv_api_ip;\n    ps_op = (ih264d_ctl_get_sei_mdcv_params_op_t *)pv_api_op;\n    UNUSED(ps_ip);\n\n    if(0 == ps_dec->s_sei_export.u1_sei_mdcv_params_present_flag)\n    {\n        ps_op->u4_error_code = ERROR_SEI_MDCV_PARAMS_NOT_FOUND;\n        return IV_FAIL;\n    }\n\n    ps_sei_mdcv = &ps_dec->s_sei_export.s_sei_mdcv_params;\n\n    for(i4_count = 0; i4_count < NUM_SEI_MDCV_PRIMARIES; i4_count++)\n    {\n        ps_op->au2_display_primaries_x[i4_count] = ps_sei_mdcv->au2_display_primaries_x[i4_count];\n        ps_op->au2_display_primaries_y[i4_count] = ps_sei_mdcv->au2_display_primaries_y[i4_count];\n    }\n\n    ps_op->u2_white_point_x = ps_sei_mdcv->u2_white_point_x;\n    ps_op->u2_white_point_y = ps_sei_mdcv->u2_white_point_y;\n    ps_op->u4_max_display_mastering_luminance = ps_sei_mdcv->u4_max_display_mastering_luminance;\n    ps_op->u4_min_display_mastering_luminance = ps_sei_mdcv->u4_min_display_mastering_luminance;\n\n    return IV_SUCCESS;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_get_sei_cll_params                                */\n/*                                                                           */\n/*  Description   : This function populates SEI cll message in               */\n/*                     output structure                                      */\n/*  Inputs        : iv_obj_t decoder handle                                  */\n/*                : pv_api_ip pointer to input structure                     */\n/*                : pv_api_op pointer to output structure                    */\n/*  Outputs       :                                                          */\n/*  Returns       : returns 0; 1 with error code when CLL is not present     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                                                           */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_get_sei_cll_params(iv_obj_t *dec_hdl,\n                                 void *pv_api_ip,\n                                 void *pv_api_op)\n{\n    ih264d_ctl_get_sei_cll_params_ip_t *ps_ip;\n    ih264d_ctl_get_sei_cll_params_op_t *ps_op;\n    dec_struct_t *ps_dec = dec_hdl->pv_codec_handle;\n    sei_cll_params_t *ps_sei_cll;\n\n    ps_ip = (ih264d_ctl_get_sei_cll_params_ip_t *)pv_api_ip;\n    ps_op = (ih264d_ctl_get_sei_cll_params_op_t *)pv_api_op;\n    UNUSED(ps_ip);\n\n    if(0 == ps_dec->s_sei_export.u1_sei_cll_params_present_flag)\n    {\n        ps_op->u4_error_code = ERROR_SEI_CLL_PARAMS_NOT_FOUND;\n        return IV_FAIL;\n    }\n\n    ps_sei_cll = &ps_dec->s_sei_export.s_sei_cll_params;\n\n    ps_op->u2_max_content_light_level = ps_sei_cll->u2_max_content_light_level;\n    ps_op->u2_max_pic_average_light_level = ps_sei_cll->u2_max_pic_average_light_level;\n\n    return IV_SUCCESS;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_get_sei_ave_params                                */\n/*                                                                           */\n/*  Description   : This function populates SEI ave message in               */\n/*                     output structure                                      */\n/*  Inputs        : iv_obj_t decoder handle                                  */\n/*                : pv_api_ip pointer to input structure                     */\n/*                : pv_api_op pointer to output structure                    */\n/*  Outputs       :                                                          */\n/*  Returns       : returns 0; 1 with error code when AVE is not present     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                                                           */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_get_sei_ave_params(iv_obj_t *dec_hdl,\n                                 void *pv_api_ip,\n                                 void *pv_api_op)\n{\n    ih264d_ctl_get_sei_ave_params_ip_t *ps_ip;\n    ih264d_ctl_get_sei_ave_params_op_t *ps_op;\n    dec_struct_t *ps_dec = dec_hdl->pv_codec_handle;\n    sei_ave_params_t *ps_sei_ave;\n\n    ps_ip = (ih264d_ctl_get_sei_ave_params_ip_t *)pv_api_ip;\n    ps_op = (ih264d_ctl_get_sei_ave_params_op_t *)pv_api_op;\n    UNUSED(ps_ip);\n\n    if(0 == ps_dec->s_sei_export.u1_sei_ave_params_present_flag)\n    {\n        ps_op->u4_error_code = ERROR_SEI_AVE_PARAMS_NOT_FOUND;\n        return IV_FAIL;\n    }\n\n    ps_sei_ave = &ps_dec->s_sei_export.s_sei_ave_params;\n\n    ps_op->u4_ambient_illuminance = ps_sei_ave->u4_ambient_illuminance;\n    ps_op->u2_ambient_light_x = ps_sei_ave->u2_ambient_light_x;\n    ps_op->u2_ambient_light_y = ps_sei_ave->u2_ambient_light_y;\n\n    return IV_SUCCESS;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_get_sei_ccv_params                                */\n/*                                                                           */\n/*  Description   : This function populates SEI mdcv message in              */\n/*                     output structure                                      */\n/*  Inputs        : iv_obj_t decoder handle                                  */\n/*                : pv_api_ip pointer to input structure                     */\n/*                : pv_api_op pointer to output structure                    */\n/*  Outputs       :                                                          */\n/*  Returns       : returns 0; 1 with error code when CCV is not present    */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                                                           */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_get_sei_ccv_params(iv_obj_t *dec_hdl,\n                                 void *pv_api_ip,\n                                 void *pv_api_op)\n{\n    ih264d_ctl_get_sei_ccv_params_ip_t *ps_ip;\n    ih264d_ctl_get_sei_ccv_params_op_t *ps_op;\n    dec_struct_t *ps_dec = dec_hdl->pv_codec_handle;\n    sei_ccv_params_t *ps_sei_ccv;\n    WORD32 i4_count;\n\n    ps_ip = (ih264d_ctl_get_sei_ccv_params_ip_t *)pv_api_ip;\n    ps_op = (ih264d_ctl_get_sei_ccv_params_op_t *)pv_api_op;\n    UNUSED(ps_ip);\n\n    if(0 == ps_dec->s_sei_export.u1_sei_ccv_params_present_flag)\n    {\n        ps_op->u4_error_code = ERROR_SEI_CCV_PARAMS_NOT_FOUND;\n        return IV_FAIL;\n    }\n\n    ps_sei_ccv = &ps_dec->s_sei_export.s_sei_ccv_params;\n\n    ps_op->u1_ccv_cancel_flag = ps_sei_ccv->u1_ccv_cancel_flag;\n\n    if(0 == ps_op->u1_ccv_cancel_flag)\n    {\n        ps_op->u1_ccv_persistence_flag = ps_sei_ccv->u1_ccv_persistence_flag;\n        ps_op->u1_ccv_primaries_present_flag = ps_sei_ccv->u1_ccv_primaries_present_flag;\n        ps_op->u1_ccv_min_luminance_value_present_flag =\n                    ps_sei_ccv->u1_ccv_min_luminance_value_present_flag;\n        ps_op->u1_ccv_max_luminance_value_present_flag =\n                    ps_sei_ccv->u1_ccv_max_luminance_value_present_flag;\n        ps_op->u1_ccv_avg_luminance_value_present_flag =\n                    ps_sei_ccv->u1_ccv_avg_luminance_value_present_flag;\n        ps_op->u1_ccv_reserved_zero_2bits = ps_sei_ccv->u1_ccv_reserved_zero_2bits;\n\n        if(1 == ps_sei_ccv->u1_ccv_primaries_present_flag)\n        {\n            for(i4_count = 0; i4_count < NUM_SEI_CCV_PRIMARIES; i4_count++)\n            {\n                ps_op->ai4_ccv_primaries_x[i4_count] = ps_sei_ccv->ai4_ccv_primaries_x[i4_count];\n                ps_op->ai4_ccv_primaries_y[i4_count] = ps_sei_ccv->ai4_ccv_primaries_y[i4_count];\n            }\n        }\n\n        if(1 == ps_sei_ccv->u1_ccv_min_luminance_value_present_flag)\n        {\n            ps_op->u4_ccv_min_luminance_value = ps_sei_ccv->u4_ccv_min_luminance_value;\n        }\n        if(1 == ps_sei_ccv->u1_ccv_max_luminance_value_present_flag)\n        {\n            ps_op->u4_ccv_max_luminance_value = ps_sei_ccv->u4_ccv_max_luminance_value;\n        }\n        if(1 == ps_sei_ccv->u1_ccv_avg_luminance_value_present_flag)\n        {\n            ps_op->u4_ccv_avg_luminance_value = ps_sei_ccv->u4_ccv_avg_luminance_value;\n        }\n    }\n\n    return IV_SUCCESS;\n}\n\nWORD32 ih264d_set_num_cores(iv_obj_t *dec_hdl, void *pv_api_ip, void *pv_api_op)\n{\n    ih264d_ctl_set_num_cores_ip_t *ps_ip;\n    ih264d_ctl_set_num_cores_op_t *ps_op;\n    dec_struct_t *ps_dec = dec_hdl->pv_codec_handle;\n\n    ps_ip = (ih264d_ctl_set_num_cores_ip_t *)pv_api_ip;\n    ps_op = (ih264d_ctl_set_num_cores_op_t *)pv_api_op;\n    ps_op->u4_error_code = 0;\n    ps_dec->u4_num_cores = ps_ip->u4_num_cores;\n    if(ps_dec->u4_num_cores == 1)\n    {\n        ps_dec->u1_separate_parse = 0;\n    }\n    else\n    {\n        ps_dec->u1_separate_parse = 1;\n    }\n\n    /*using only upto three threads currently*/\n    if(ps_dec->u4_num_cores > 3)\n        ps_dec->u4_num_cores = 3;\n\n    return IV_SUCCESS;\n}\n\nvoid ih264d_fill_output_struct_from_context(dec_struct_t *ps_dec,\n                                            ivd_video_decode_op_t *ps_dec_op)\n{\n    if((ps_dec_op->u4_error_code & 0xff)\n                    != ERROR_DYNAMIC_RESOLUTION_NOT_SUPPORTED)\n    {\n        ps_dec_op->u4_pic_wd = (UWORD32)ps_dec->u2_disp_width;\n        ps_dec_op->u4_pic_ht = (UWORD32)ps_dec->u2_disp_height;\n    }\n    ps_dec_op->i4_reorder_depth = ps_dec->i4_reorder_depth;\n    ps_dec_op->i4_display_index = ps_dec->i4_display_index;\n    ps_dec_op->e_pic_type = ps_dec->i4_frametype;\n\n    ps_dec_op->u4_new_seq = 0;\n    ps_dec_op->u4_output_present = ps_dec->u4_output_present;\n    ps_dec_op->u4_progressive_frame_flag =\n                    ps_dec->s_disp_op.u4_progressive_frame_flag;\n\n    ps_dec_op->u4_is_ref_flag = 1;\n    if(ps_dec_op->u4_frame_decoded_flag)\n    {\n        if(ps_dec->ps_cur_slice->u1_nal_ref_idc == 0)\n            ps_dec_op->u4_is_ref_flag = 0;\n    }\n\n    ps_dec_op->e_output_format = ps_dec->s_disp_op.e_output_format;\n    ps_dec_op->s_disp_frm_buf = ps_dec->s_disp_op.s_disp_frm_buf;\n    ps_dec_op->e4_fld_type = ps_dec->s_disp_op.e4_fld_type;\n    ps_dec_op->u4_ts = ps_dec->s_disp_op.u4_ts;\n    ps_dec_op->u4_disp_buf_id = ps_dec->s_disp_op.u4_disp_buf_id;\n\n    ih264d_export_sei_params(&ps_dec_op->s_sei_decode_op, ps_dec);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_api_function                                      */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*  Inputs        :iv_obj_t decoder handle                                   */\n/*                :pv_api_ip pointer to input structure                      */\n/*                :pv_api_op pointer to output structure                     */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 10 2008    100356         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nIV_API_CALL_STATUS_T ih264d_api_function(iv_obj_t *dec_hdl,\n                                              void *pv_api_ip,\n                                              void *pv_api_op)\n{\n    UWORD32 command;\n    UWORD32 *pu2_ptr_cmd;\n    UWORD32 u4_api_ret;\n    IV_API_CALL_STATUS_T e_status;\n    e_status = api_check_struct_sanity(dec_hdl, pv_api_ip, pv_api_op);\n\n    if(e_status != IV_SUCCESS)\n    {\n        UWORD32 *ptr_err;\n\n        ptr_err = (UWORD32 *)pv_api_op;\n        UNUSED(ptr_err);\n        H264_DEC_DEBUG_PRINT(\"error code = %d\\n\", *(ptr_err + 1));\n        return IV_FAIL;\n    }\n\n    pu2_ptr_cmd = (UWORD32 *)pv_api_ip;\n    pu2_ptr_cmd++;\n\n    command = *pu2_ptr_cmd;\n//    H264_DEC_DEBUG_PRINT(\"inside lib = %d\\n\",command);\n    switch(command)\n    {\n\n        case IVD_CMD_CREATE:\n            u4_api_ret = ih264d_create(dec_hdl, (void *)pv_api_ip,\n                                     (void *)pv_api_op);\n            break;\n        case IVD_CMD_DELETE:\n            u4_api_ret = ih264d_delete(dec_hdl, (void *)pv_api_ip,\n                                     (void *)pv_api_op);\n            break;\n\n        case IVD_CMD_VIDEO_DECODE:\n            u4_api_ret = ih264d_video_decode(dec_hdl, (void *)pv_api_ip,\n                                             (void *)pv_api_op);\n            break;\n\n        case IVD_CMD_GET_DISPLAY_FRAME:\n            u4_api_ret = ih264d_get_display_frame(dec_hdl, (void *)pv_api_ip,\n                                                  (void *)pv_api_op);\n\n            break;\n\n        case IVD_CMD_SET_DISPLAY_FRAME:\n            u4_api_ret = ih264d_set_display_frame(dec_hdl, (void *)pv_api_ip,\n                                                  (void *)pv_api_op);\n\n            break;\n\n        case IVD_CMD_REL_DISPLAY_FRAME:\n            u4_api_ret = ih264d_rel_display_frame(dec_hdl, (void *)pv_api_ip,\n                                                  (void *)pv_api_op);\n            break;\n\n        case IVD_CMD_VIDEO_CTL:\n            u4_api_ret = ih264d_ctl(dec_hdl, (void *)pv_api_ip,\n                                    (void *)pv_api_op);\n            break;\n        default:\n            u4_api_ret = IV_FAIL;\n            break;\n    }\n\n    return u4_api_ret;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_bitstrm.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*!\n **************************************************************************\n * \\file ih264d_bitstrm.c\n *\n * \\brief\n *    Bitstream parsing routines\n *\n * \\date\n *    20/11/2002\n *\n * \\author  AI\n **************************************************************************\n */\n\n#include <stdlib.h>\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_error_handler.h\"\n\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_structs.h\"\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_get_bit_h264 \\endif\n *\n * \\brief\n *    Read one bit from the bitstream.\n *\n *   This is a Bitstream processing function. It reads the\n *   bit currently pointed by the bit pointer in the\n *   buffer and advances the pointer by one. It returns\n *   the bit (0 or 1) in the form of an unsigned integer.\n *\n * \\return\n *    Returns the next bit (0 or 1) in the bitstream.\n *\n **************************************************************************\n */\nUWORD8 ih264d_get_bit_h264(dec_bit_stream_t *ps_stream)\n{\n    UWORD32 u4_code;\n\n    GETBIT(u4_code, ps_stream->u4_ofst, ps_stream->pu4_buffer);\n    return (u4_code);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_get_bits_h264 \\endif\n *\n * \\brief\n *    Read specified number of bits from the bitstream.\n *\n *   This is a Bitstream processing function. It reads the\n *   number specified number of bits from the current bit\n *   position and advances the bit and byte pointers\n *   appropriately.\n *\n * \\return\n *    An unsigned 32 bit integer with its least significant bits\n *    containing the bits in order of their occurence in the bitstream.\n *\n **************************************************************************\n */\n\nUWORD32 ih264d_get_bits_h264(dec_bit_stream_t *ps_bitstrm, UWORD32 u4_num_bits)\n{\n    UWORD32 u4_code = 0;\n    if(u4_num_bits)\n        GETBITS(u4_code, ps_bitstrm->u4_ofst, ps_bitstrm->pu4_buffer, u4_num_bits);\n    return (u4_code);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_next_bits_h264 \\endif\n *\n * \\brief\n *    Peek specified number of bits from the bitstream.\n *\n *   This is a Bitstream processing function. It gets the\n *   specified number of bits from the buffer without\n *   altering the current pointers. It is equivalent to\n *   next_bits() function in the standard.\n *\n * \\return\n *    An unsigned 32 bit integer with its least significant bits\n *    containing the bits in order of their occurence in the bitstream.\n **************************************************************************\n */\nUWORD32 ih264d_next_bits_h264(dec_bit_stream_t *ps_bitstrm, UWORD32 u4_num_bits)\n{\n    UWORD32 u4_word_off = (ps_bitstrm->u4_ofst >> 5);\n    UWORD32 u4_bit_off = ps_bitstrm->u4_ofst & 0x1F;\n    UWORD32 *pu4_bitstream = ps_bitstrm->pu4_buffer;\n    UWORD32 u4_bits = pu4_bitstream[u4_word_off++] << u4_bit_off;\n\n    /*************************************************************************/\n    /* Test if number of bits to be read exceeds the number of bits in the   */\n    /* current word. If yes, read from the next word of the buffer, The bits */\n    /* from both the words are concatenated to get next 32 bits in 'u4_bits' */\n    /*************************************************************************/\n    if(u4_bit_off > (INT_IN_BITS - u4_num_bits))\n        u4_bits |= (pu4_bitstream[u4_word_off] >> (INT_IN_BITS - u4_bit_off));\n\n    return ((u4_bits >> (INT_IN_BITS - u4_num_bits)));\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_flush_bits_h264 \\endif\n *\n * \\brief\n *    Flush specified number of bits from the bitstream.\n *\n *   This function flushes the specified number of bits (marks\n *   as read) from the buffer.\n *\n * \\return\n *     A 8 bit unsigned integer with value\n *    '1' on successful flush\n *    '0' on failure.\n *\n **************************************************************************\n */\nWORD32 ih264d_flush_bits_h264(dec_bit_stream_t *ps_bitstrm, WORD32 u4_num_bits)\n{\n    ps_bitstrm->u4_ofst += u4_num_bits;\n\n    if(ps_bitstrm->u4_ofst > ps_bitstrm->u4_max_ofst)\n    {\n        return ERROR_EOB_FLUSHBITS_T;\n    }\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_check_byte_aligned \\endif\n *\n * \\brief\n *    Checks whether the bit ps_bitstrm u4_ofst is at byte boundary.\n *\n * \\param ps_bitstrm : Pointer to bitstream\n *\n * \\return\n *    Returns 1 if bit ps_bitstrm u4_ofst is at byte alligned position else zero.\n **************************************************************************\n */\n\nUWORD8 ih264d_check_byte_aligned(dec_bit_stream_t * ps_bitstrm)\n{\n    if(ps_bitstrm->u4_ofst & 0x07)\n        return (0);\n    else\n        return (1);\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_bitstrm.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n#ifndef _IH264D_BITSTRM_H_\n#define _IH264D_BITSTRM_H_\n/*!\n *************************************************************************\n * \\file ih264d_bitstrm.h\n *\n * \\brief\n *  Contains all the declarations of bitstream reading routines\n *\n * \\date\n *    20/11/2002\n *\n * \\author  AI\n *************************************************************************\n */\n\n/* Includes */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n\n#define INT_IN_BYTES        4\n#define INT_IN_BITS         32\n\n/* Based on level 1.2 of baseline profile */\n/* 396[MAX_FS] * 128 * 1.5 [ChromaFormatParameter] / sizeof(UWORD32)\n i.e  396 * 128 * 1.5 / 4 = 19008 */\n/* Based on level 3 of main profile */\n/* 1620[MAX_FS] * 128 * 1.5 [ChromaFormatParameter] / sizeof(UWORD32)\n i.e  1620 * 128 * 1.5 / 4= 77760 */\n#define SIZE_OF_BUFFER      77760\n\n/* Structure for the ps_bitstrm */\ntypedef struct\n{\n    UWORD32 u4_ofst; /* Offset in the buffer for the current bit */\n    UWORD32 *pu4_buffer; /* Bitstream Buffer  */\n    UWORD32 u4_max_ofst; /* points to first bit beyond the buffer */\n    void * pv_codec_handle; /* For Error Handling */\n} dec_bit_stream_t;\n\n/* To read the next bit */\nUWORD8 ih264d_get_bit_h264(dec_bit_stream_t *);\n\n/* To read the next specified number of bits */\nUWORD32 ih264d_get_bits_h264(dec_bit_stream_t *, UWORD32);\n\n/* To see the next specified number of bits */\nUWORD32 ih264d_next_bits_h264(dec_bit_stream_t *, UWORD32);\n\n/* To flush a specified number of bits*/\nWORD32 ih264d_flush_bits_h264(dec_bit_stream_t *, WORD32);\n\n/*!\n **************************************************************************\n * \\if Function name : MoreRbspData \\endif\n *\n * \\brief\n *    Determines whether there is more data in RBSP or not.\n *\n * \\param ps_bitstrm : Pointer to bitstream\n *\n * \\return\n *    Returns 1 if there is more data in RBSP before rbsp_trailing_bits().\n *    Otherwise it returns FALSE.\n **************************************************************************\n */\n\n\n#define EXCEED_OFFSET(ps_bitstrm) \\\n  (ps_bitstrm->u4_ofst > ps_bitstrm->u4_max_ofst)\n#define CHECK_BITS_SUFFICIENT(ps_bitstrm, bits_to_read) \\\n  (ps_bitstrm->u4_ofst + bits_to_read <= ps_bitstrm->u4_max_ofst)\n#define MORE_RBSP_DATA(ps_bitstrm) \\\n    CHECK_BITS_SUFFICIENT(ps_bitstrm, 1)\n\nvoid GoToByteBoundary(dec_bit_stream_t * ps_bitstrm);\nUWORD8 ih264d_check_byte_aligned(dec_bit_stream_t * ps_bitstrm);\n\n/*****************************************************************************/\n/* Define a macro for inlining of GETBIT:                                    */\n/*****************************************************************************/\n#define   GETBIT(u4_code, u4_offset, pu4_bitstream)                         \\\n{                                                                           \\\n    UWORD32 *pu4_buf =  (pu4_bitstream);                                    \\\n    UWORD32 u4_word_off = ((u4_offset) >> 5);                               \\\n    UWORD32 u4_bit_off = (u4_offset) & 0x1F;                                \\\n    u4_code = pu4_buf[u4_word_off] << u4_bit_off;                           \\\n    (u4_offset)++;                                                          \\\n    u4_code = (u4_code >> 31);                                              \\\n}\n\n\n\n/*****************************************************************************/\n/* Define a macro for inlining of GETBITS: u4_no_bits shall not exceed 32    */\n/*****************************************************************************/\n#define     GETBITS(u4_code, u4_offset, pu4_bitstream, u4_no_bits)          \\\n{                                                                           \\\n    UWORD32 *pu4_buf =  (pu4_bitstream);                                    \\\n    UWORD32 u4_word_off = ((u4_offset) >> 5);                               \\\n    UWORD32 u4_bit_off = (u4_offset) & 0x1F;                                \\\n    u4_code = pu4_buf[u4_word_off++] << u4_bit_off;                         \\\n                                                                            \\\n    if(u4_bit_off)                                                          \\\n        u4_code |= (pu4_buf[u4_word_off] >> (INT_IN_BITS - u4_bit_off));    \\\n    u4_code = u4_code >> (INT_IN_BITS - u4_no_bits);                        \\\n    (u4_offset) += u4_no_bits;                                              \\\n}                                                                           \\\n                                                                            \\\n\n/*****************************************************************************/\n/* Define a macro for inlining of NEXTBITS                                   */\n/*****************************************************************************/\n#define     NEXTBITS(u4_word, u4_offset, pu4_bitstream, u4_no_bits)         \\\n{                                                                           \\\n    UWORD32 *pu4_buf =  (pu4_bitstream);                                    \\\n    UWORD32 u4_word_off = ((u4_offset) >> 5);                               \\\n    UWORD32 u4_bit_off = (u4_offset) & 0x1F;                                \\\n    u4_word = pu4_buf[u4_word_off++] << u4_bit_off;                         \\\n    if(u4_bit_off)                                                          \\\n        u4_word |= (pu4_buf[u4_word_off] >> (INT_IN_BITS - u4_bit_off));    \\\n    u4_word = u4_word >> (INT_IN_BITS - u4_no_bits);                        \\\n}\n/*****************************************************************************/\n/* Define a macro for inlining of NEXTBITS_32                                */\n/*****************************************************************************/\n#define     NEXTBITS_32(u4_word, u4_offset, pu4_bitstream)                  \\\n{                                                                           \\\n    UWORD32 *pu4_buf =  (pu4_bitstream);                                    \\\n    UWORD32 u4_word_off = ((u4_offset) >> 5);                               \\\n    UWORD32 u4_bit_off = (u4_offset) & 0x1F;                                \\\n                                                                            \\\n    u4_word = pu4_buf[u4_word_off++] << u4_bit_off;                         \\\n    if(u4_bit_off)                                                          \\\n    u4_word |= (pu4_buf[u4_word_off] >> (INT_IN_BITS - u4_bit_off));        \\\n}\n\n\n/*****************************************************************************/\n/* Define a macro for inlining of FIND_ONE_IN_STREAM_32                      */\n/*****************************************************************************/\n#define   FIND_ONE_IN_STREAM_32(u4_ldz, u4_offset, pu4_bitstream)           \\\n{                                                                           \\\n    UWORD32 u4_word;                                                        \\\n    NEXTBITS_32(u4_word, u4_offset, pu4_bitstream);                         \\\n    u4_ldz = CLZ(u4_word);                                     \\\n    (u4_offset) += (u4_ldz + 1);                                            \\\n}\n\n/*****************************************************************************/\n/* Define a macro for inlining of FIND_ONE_IN_STREAM_LEN                     */\n/*****************************************************************************/\n#define   FIND_ONE_IN_STREAM_LEN(u4_ldz, u4_offset, pu4_bitstream, u4_len)  \\\n{                                                                           \\\n    UWORD32 u4_word;                                                        \\\n    NEXTBITS_32(u4_word, u4_offset, pu4_bitstream);                         \\\n    u4_ldz = CLZ(u4_word);                                     \\\n    if(u4_ldz < u4_len)                                                     \\\n    (u4_offset) += (u4_ldz + 1);                                            \\\n    else                                                                    \\\n    {                                                                       \\\n        u4_ldz = u4_len;                                                    \\\n        (u4_offset) += u4_ldz;                                              \\\n    }                                                                       \\\n}\n\n/*****************************************************************************/\n/* Define a macro for inlining of FLUSHBITS                                  */\n/*****************************************************************************/\n#define   FLUSHBITS(u4_offset, u4_no_bits)                                  \\\n{                                                                           \\\n        (u4_offset) += (u4_no_bits);                                        \\\n}\n\n#endif  /* _BITSTREAM_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_cabac.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n ***************************************************************************\n * \\file ih264d_cabac.c\n *\n * \\brief\n *    This file contains Binary decoding routines.\n *\n * \\date\n *    04/02/2003\n *\n * \\author  NS\n ***************************************************************************\n */\n#include <string.h>\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_cabac.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_parse_cabac.h\"\n#include \"ih264d_tables.h\"\n\n\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_init_cabac_dec_envirnoment \\endif\n *\n * \\brief\n *    This function initializes CABAC decoding envirnoment. This function\n *    implements 9.3.3.2.3.1 of ISO/IEC14496-10.\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\nWORD32 ih264d_init_cabac_dec_envirnoment(decoding_envirnoment_t * ps_cab_env,\n                                       dec_bit_stream_t *ps_bitstrm)\n{\n    UWORD32 u4_code_int_val_ofst;\n\n    ps_cab_env->u4_code_int_range = (HALF - 2) << 23;\n    NEXTBITS(u4_code_int_val_ofst, ps_bitstrm->u4_ofst, ps_bitstrm->pu4_buffer,\n             32);\n    FLUSHBITS(ps_bitstrm->u4_ofst, 9)\n\n    if(EXCEED_OFFSET(ps_bitstrm))\n        return ERROR_EOB_FLUSHBITS_T;\n\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n\n    /*brief description of the design adopted for CABAC*/\n    /*according to the standard the u4_code_int_range needs to be initialized 0x 1FE(10 bits) and\n     9 bits from the bit stream need to be read and into the u4_code_int_val_ofst.As and when the\n     u4_code_int_range becomes less than 10 bits we need to renormalize and read from the bitstream*\n\n     In the implemented design\n     initially\n\n     range_new = range <<23\n     valOffset_new = valOffset << 23 + 23 bits(read from the bit stream)\n\n     Thus we have read 23 more bits ahead of time.\n\n     It can be mathematical proved that even with the modified range and u4_ofst the operations\n     like comparison and subtraction needed for a bin decode are still valid(both in the regular case and the bypass case)\n\n     As bins are decoded..we consume the bits that we have already read into the valOffset.The clz of Range\n     gives us the number of bits we consumed of the 23 bits that we have read ahead of time.\n\n     when the number bits we have consumed exceeds 23 ,we renormalize..and  we read from the bitstream again*/\n\nRESET_BIN_COUNTS(ps_cab_env)\n\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_init_cabac_contexts                                      */\n/*                                                                           */\n/*  Description   : This function initializes the cabac contexts             */\n/*                  depending upon slice type and Init_Idc value.            */\n/*  Inputs        : ps_dec, slice type                                       */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Outputs       :                                                          */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         03 05 2005   100153)         Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nvoid ih264d_init_cabac_contexts(UWORD8 u1_slice_type, dec_struct_t * ps_dec)\n{\n\n    bin_ctxt_model_t *p_cabac_ctxt_table_t = ps_dec->p_cabac_ctxt_table_t;\n    UWORD8 u1_qp_y = ps_dec->ps_cur_slice->u1_slice_qp;\n    UWORD8 u1_cabac_init_Idc = 0;\n\n    if(I_SLICE != u1_slice_type)\n    {\n        u1_cabac_init_Idc = ps_dec->ps_cur_slice->u1_cabac_init_idc;\n    }\n\n    {\n        /* MAKING ps_dec->p_ctxt_inc_mb_map a scratch buffer */\n        /* 0th entry of CtxtIncMbMap will be always be containing default values\n         for CABAC context representing MB not available */\n        ctxt_inc_mb_info_t *p_DefCtxt = ps_dec->p_ctxt_inc_mb_map - 1;\n        UWORD8 *pu1_temp;\n        WORD8 i;\n        p_DefCtxt->u1_mb_type = CAB_SKIP;\n\n        p_DefCtxt->u1_cbp = 0x0f;\n        p_DefCtxt->u1_intra_chroma_pred_mode = 0;\n\n        p_DefCtxt->u1_yuv_dc_csbp = 0x7;\n\n        p_DefCtxt->u1_transform8x8_ctxt = 0;\n\n        pu1_temp = (UWORD8*)p_DefCtxt->i1_ref_idx;\n        for(i = 0; i < 4; i++, pu1_temp++)\n            (*pu1_temp) = 0;\n        pu1_temp = (UWORD8*)p_DefCtxt->u1_mv;\n        for(i = 0; i < 16; i++, pu1_temp++)\n            (*pu1_temp) = 0;\n        ps_dec->ps_def_ctxt_mb_info = p_DefCtxt;\n    }\n\n    if(u1_slice_type == I_SLICE)\n    {\n        u1_cabac_init_Idc = 3;\n        ps_dec->p_mb_type_t = p_cabac_ctxt_table_t + MB_TYPE_I_SLICE;\n    }\n    else if(u1_slice_type == P_SLICE)\n    {\n        ps_dec->p_mb_type_t = p_cabac_ctxt_table_t + MB_TYPE_P_SLICE;\n        ps_dec->p_mb_skip_flag_t = p_cabac_ctxt_table_t + MB_SKIP_FLAG_P_SLICE;\n        ps_dec->p_sub_mb_type_t = p_cabac_ctxt_table_t + SUB_MB_TYPE_P_SLICE;\n    }\n    else if(u1_slice_type == B_SLICE)\n    {\n        ps_dec->p_mb_type_t = p_cabac_ctxt_table_t + MB_TYPE_B_SLICE;\n        ps_dec->p_mb_skip_flag_t = p_cabac_ctxt_table_t + MB_SKIP_FLAG_B_SLICE;\n        ps_dec->p_sub_mb_type_t = p_cabac_ctxt_table_t + SUB_MB_TYPE_B_SLICE;\n    }\n    {\n        bin_ctxt_model_t *p_cabac_ctxt_table_t_tmp = p_cabac_ctxt_table_t;\n        if(ps_dec->ps_cur_slice->u1_field_pic_flag)\n        {\n            p_cabac_ctxt_table_t_tmp += SIGNIFICANT_COEFF_FLAG_FLD;\n\n        }\n        else\n        {\n            p_cabac_ctxt_table_t_tmp += SIGNIFICANT_COEFF_FLAG_FRAME;\n        }\n        {\n            bin_ctxt_model_t * * p_significant_coeff_flag_t =\n                            ps_dec->p_significant_coeff_flag_t;\n            p_significant_coeff_flag_t[0] = p_cabac_ctxt_table_t_tmp\n                            + SIG_COEFF_CTXT_CAT_0_OFFSET;\n            p_significant_coeff_flag_t[1] = p_cabac_ctxt_table_t_tmp\n                            + SIG_COEFF_CTXT_CAT_1_OFFSET;\n            p_significant_coeff_flag_t[2] = p_cabac_ctxt_table_t_tmp\n                            + SIG_COEFF_CTXT_CAT_2_OFFSET;\n            p_significant_coeff_flag_t[3] = p_cabac_ctxt_table_t_tmp\n                            + SIG_COEFF_CTXT_CAT_3_OFFSET;\n            p_significant_coeff_flag_t[4] = p_cabac_ctxt_table_t_tmp\n                            + SIG_COEFF_CTXT_CAT_4_OFFSET;\n\n            p_significant_coeff_flag_t[5] = p_cabac_ctxt_table_t_tmp\n                            + SIG_COEFF_CTXT_CAT_5_OFFSET;\n\n        }\n    }\n\n    memcpy(p_cabac_ctxt_table_t,\n           gau1_ih264d_cabac_ctxt_init_table[u1_cabac_init_Idc][u1_qp_y],\n           NUM_CABAC_CTXTS * sizeof(bin_ctxt_model_t));\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_decode_bin \\endif\n *\n * \\brief\n *    This function implements decoding process of a decision as defined\n *    in 9.3.3.2.2.\n *\n * \\return\n *    Returns symbol decoded.\n *\n * \\note\n *    It is specified in 9.3.3.2.3.2 that, one of the input to this function\n *    is CtxIdx. CtxIdx is used to identify state and MPS of that context\n *    (Refer Fig 9.11 - Flowchart for encoding a decision). To suffice that\n *    here we pass a pointer bin_ctxt_model_t which contains these values.\n *\n **************************************************************************\n */\n\nUWORD32 ih264d_decode_bin(UWORD32 u4_ctx_inc,\n                          bin_ctxt_model_t *ps_src_bin_ctxt,\n                          dec_bit_stream_t *ps_bitstrm,\n                          decoding_envirnoment_t *ps_cab_env)\n\n{\n\n    UWORD32 u4_qnt_int_range, u4_code_int_range, u4_code_int_val_ofst,\n                    u4_int_range_lps;\n\n    UWORD32 u4_symbol, u4_mps_state;\n\n    bin_ctxt_model_t *ps_bin_ctxt;\n\n    UWORD32 table_lookup;\n    const UWORD32 *pu4_table = (const UWORD32 *)ps_cab_env->cabac_table;\n    UWORD32 u4_clz;\n\n    ps_bin_ctxt = ps_src_bin_ctxt + u4_ctx_inc;\n\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n\n    u4_mps_state = (ps_bin_ctxt->u1_mps_state);\n    u4_clz = CLZ(u4_code_int_range);\n\n    u4_qnt_int_range = u4_code_int_range << u4_clz;\n    u4_qnt_int_range = (u4_qnt_int_range >> 29) & 0x3;\n\n    table_lookup = pu4_table[(u4_mps_state << 2) + u4_qnt_int_range];\n    u4_int_range_lps = table_lookup & 0xff;\n\n    u4_int_range_lps = u4_int_range_lps << (23 - u4_clz);\n    u4_code_int_range = u4_code_int_range - u4_int_range_lps;\n\n    u4_symbol = ((u4_mps_state >> 6) & 0x1);\n\n    u4_mps_state = (table_lookup >> 8) & 0x7F;\n\n    CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst, u4_symbol,\n                 u4_int_range_lps, u4_mps_state, table_lookup)\n\n    if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_8)\n    {\n        UWORD32 *pu4_buffer, u4_offset;\n\n        pu4_buffer = ps_bitstrm->pu4_buffer;\n        u4_offset = ps_bitstrm->u4_ofst;\n\n        RENORM_RANGE_OFFSET(u4_code_int_range, u4_code_int_val_ofst, u4_offset,\n                            pu4_buffer)\n\n        ps_bitstrm->u4_ofst = u4_offset;\n    }\n\n    INC_BIN_COUNT(ps_cab_env)\n\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n    ps_cab_env->u4_code_int_range = u4_code_int_range;\n    ps_bin_ctxt->u1_mps_state = u4_mps_state;\n\n    return (u4_symbol);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_decode_terminate \\endif\n *\n * \\brief\n *    This function implements decoding process of a termination as defined\n *    9.3.3.2.2.3 of ISO/IEC14496-10.\n *\n * \\return\n *    Returns symbol decoded.\n *\n * \\note\n *    This routine is called while decoding \"end_of_skice_flag\" and of the\n *    bin indicating PCM mode in MBType.\n *\n **************************************************************************\n */\nUWORD8 ih264d_decode_terminate(decoding_envirnoment_t * ps_cab_env,\n                               dec_bit_stream_t * ps_stream)\n{\n    UWORD32 u4_symbol;\n    UWORD32 u4_code_int_val_ofst, u4_code_int_range;\n    UWORD32 u4_clz;\n\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n\n    u4_clz = CLZ(u4_code_int_range);\n    u4_code_int_range -= (2 << (23 - u4_clz));\n\n    if(u4_code_int_val_ofst >= u4_code_int_range)\n    {\n        /* S=1 */\n        u4_symbol = 1;\n\n        {\n\n            /*the u4_ofst needs to be updated before termination*/\n            ps_stream->u4_ofst += u4_clz;\n\n        }\n\n    }\n    else\n    {\n        /* S=0 */\n        u4_symbol = 0;\n\n        if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_8)\n        {\n            UWORD32 *pu4_buffer, u4_offset;\n\n            pu4_buffer = ps_stream->pu4_buffer;\n            u4_offset = ps_stream->u4_ofst;\n\n            RENORM_RANGE_OFFSET(u4_code_int_range, u4_code_int_val_ofst, u4_offset,\n                                pu4_buffer)\n            ps_stream->u4_ofst = u4_offset;\n        }\n    }\n\n    ps_cab_env->u4_code_int_range = u4_code_int_range;\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n\n    INC_BIN_COUNT(ps_cab_env)\n\n    return (u4_symbol);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_decode_bins_tunary                                */\n/*                                                                           */\n/*  Description   : This function decodes bins in the case of TUNARY         */\n/*                  binarization technique.valid_length is assumed  equal to 3 */\n/*                  and u1_max_bins <= 4 in this functon.                                              */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        :                                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         20 11 2008   SH          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\n\nUWORD32 ih264d_decode_bins_tunary(UWORD8 u1_max_bins,\n                                  UWORD32 u4_ctx_inc,\n                                  bin_ctxt_model_t *ps_src_bin_ctxt,\n                                  dec_bit_stream_t *ps_bitstrm,\n                                  decoding_envirnoment_t *ps_cab_env)\n\n{\n    UWORD32 u4_value;\n    UWORD32 u4_symbol;\n    UWORD8 u4_ctx_Inc;\n    bin_ctxt_model_t *ps_bin_ctxt;\n    UWORD32 u4_code_int_range, u4_code_int_val_ofst;\n    const UWORD32 *pu4_table = (const UWORD32 *)ps_cab_env->cabac_table;\n\n    u4_value = 0;\n\n    /*u1_max_bins has to be less than or equal to 4, u1_max_bins <= 4 for  this function*/\n\n    /*here the valid length is assumed to be equal to 3 ,so the calling function is expected\n     to duplicate CtxInc if valid lenth is 2 and cmaxbin is greater than2*/\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n\n    do\n    {\n        u4_ctx_Inc = u4_ctx_inc & 0xF;\n        u4_ctx_inc = u4_ctx_inc >> 4;\n\n        ps_bin_ctxt = ps_src_bin_ctxt + u4_ctx_Inc;\n\n        DECODE_ONE_BIN_MACRO(ps_bin_ctxt, u4_code_int_range, u4_code_int_val_ofst,\n                             pu4_table, ps_bitstrm, u4_symbol)\n\n        INC_BIN_COUNT(ps_cab_env);INC_DECISION_BINS(ps_cab_env);\n\n        u4_value++;\n    }\n    while((u4_value < u1_max_bins) & (u4_symbol));\n\n    u4_value = u4_value - 1 + u4_symbol;\n\n    ps_cab_env->u4_code_int_range = u4_code_int_range;\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n\n    return (u4_value);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_decode_bins                                */\n/*                                                                           */\n/*  Description   : This function decodes bins in the case of MSB_FIRST_FLC  */\n/*                  binarization technique.valid_length is always equal max_bins */\n/*                  for MSB_FIRST_FLC. assumes  u1_max_bins <= 4               */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         20 11 2008   SH          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\n\nUWORD32 ih264d_decode_bins(UWORD8 u1_max_bins,\n                           UWORD32 u4_ctx_inc,\n                           bin_ctxt_model_t *ps_src_bin_ctxt,\n                           dec_bit_stream_t *ps_bitstrm,\n                           decoding_envirnoment_t *ps_cab_env)\n\n{\n    UWORD32 u4_value;\n    UWORD32 u4_symbol, i;\n    UWORD32 u4_ctxt_inc;\n    bin_ctxt_model_t *ps_bin_ctxt;\n    UWORD32 u4_code_int_range, u4_code_int_val_ofst;\n    const UWORD32 *pu4_table = (const UWORD32 *)ps_cab_env->cabac_table;\n\n    i = 0;\n\n    u4_value = 0;\n\n    /*u1_max_bins has to be less than or equal to 4, u1_max_bins <= 4 for  this fucntion*/\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n\n    do\n    {\n        u4_ctxt_inc = u4_ctx_inc & 0xf;\n        u4_ctx_inc = u4_ctx_inc >> 4;\n\n        ps_bin_ctxt = ps_src_bin_ctxt + u4_ctxt_inc;\n\n        DECODE_ONE_BIN_MACRO(ps_bin_ctxt, u4_code_int_range, u4_code_int_val_ofst,\n                             pu4_table, ps_bitstrm, u4_symbol)\n\n        INC_BIN_COUNT(ps_cab_env);INC_DECISION_BINS(ps_cab_env);\n\n        u4_value = (u4_value << 1) | (u4_symbol);\n\n        i++;\n    }\n    while(i < u1_max_bins);\n\n    ps_cab_env->u4_code_int_range = u4_code_int_range;\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n\n    return (u4_value);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_decode_bins_unary                                */\n/*                                                                           */\n/*  Description   : This function decodes bins in the case of UNARY         */\n/*                  binarization technique.here the valid length is taken to 5*/\n/*                  and cmax is always greater than 9                       */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         20 11 2008   SH          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nUWORD32 ih264d_decode_bins_unary(UWORD8 u1_max_bins,\n                                 UWORD32 u4_ctx_inc,\n                                 bin_ctxt_model_t *ps_src_bin_ctxt,\n                                 dec_bit_stream_t *ps_bitstrm,\n                                 decoding_envirnoment_t *ps_cab_env)\n{\n    UWORD32 u4_value;\n    UWORD32 u4_symbol;\n    bin_ctxt_model_t *ps_bin_ctxt;\n    UWORD32 u4_ctx_Inc;\n    UWORD32 u4_code_int_range, u4_code_int_val_ofst;\n    const UWORD32 *pu4_table = (const UWORD32 *)ps_cab_env->cabac_table;\n\n    /* in this function the valid length for u4_ctx_inc is always taken to be,so if the\n     the valid length is lessthan 5 the caller need to duplicate accordingly*/\n\n    /*u1_max_bins is always greater or equal to 9 we have the check for u1_max_bins only after the 2 loop*/\n    u4_value = 0;\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n\n    do\n    {\n        u4_ctx_Inc = u4_ctx_inc & 0xf;\n        u4_ctx_inc = u4_ctx_inc >> 4;\n\n        ps_bin_ctxt = ps_src_bin_ctxt + u4_ctx_Inc;\n\n        DECODE_ONE_BIN_MACRO(ps_bin_ctxt, u4_code_int_range, u4_code_int_val_ofst,\n                             pu4_table, ps_bitstrm, u4_symbol)\n\n        INC_BIN_COUNT(ps_cab_env);INC_DECISION_BINS(ps_cab_env);\n\n        u4_value++;\n\n    }\n    while(u4_symbol && u4_value < 4);\n\n    if(u4_symbol && (u4_value < u1_max_bins))\n    {\n\n        u4_ctx_Inc = u4_ctx_inc & 0xf;\n\n        ps_bin_ctxt = ps_src_bin_ctxt + u4_ctx_Inc;\n\n        do\n        {\n\n            DECODE_ONE_BIN_MACRO(ps_bin_ctxt, u4_code_int_range, u4_code_int_val_ofst,\n                                 pu4_table, ps_bitstrm, u4_symbol)\n\n            INC_BIN_COUNT(ps_cab_env);INC_DECISION_BINS(ps_cab_env);\n\n            u4_value++;\n\n        }\n        while(u4_symbol && (u4_value < u1_max_bins));\n\n    }\n\n    ps_cab_env->u4_code_int_range = u4_code_int_range;\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n\n    u4_value = u4_value - 1 + u4_symbol;\n\n    return (u4_value);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_decode_bypass_bins_unary                                     */\n/*                                                                           */\n/*  Description   : This function is used in the case of UNARY coding       */\n/*                                                                           */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 10 2005   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nUWORD32 ih264d_decode_bypass_bins_unary(decoding_envirnoment_t *ps_cab_env,\n                                        dec_bit_stream_t *ps_bitstrm)\n{\n    UWORD32 u4_value;\n    UWORD32 u4_bin;\n    UWORD32 u4_code_int_val_ofst, u4_code_int_range;\n\n    UWORD32 u1_max_bins;\n\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n\n    if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_9)\n    {\n        UWORD32 *pu4_buffer, u4_offset;\n\n        pu4_buffer = ps_bitstrm->pu4_buffer;\n        u4_offset = ps_bitstrm->u4_ofst;\n\n        RENORM_RANGE_OFFSET(u4_code_int_range, u4_code_int_val_ofst, u4_offset,\n                            pu4_buffer)\n        ps_bitstrm->u4_ofst = u4_offset;\n    }\n\n    /*as it is called only form mvd*/\n    u1_max_bins = 32;\n    u4_value = 0;\n\n    do\n    {\n        u4_value++;\n\n        u4_code_int_range = u4_code_int_range >> 1;\n        if(u4_code_int_val_ofst >= u4_code_int_range)\n        {\n            /* S=1 */\n            u4_bin = 1;\n            u4_code_int_val_ofst -= u4_code_int_range;\n        }\n        else\n        {\n            /* S=0 */\n            u4_bin = 0;\n        }\n\n        INC_BIN_COUNT(ps_cab_env);INC_BYPASS_BINS(ps_cab_env);\n\n        if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_9)\n        {\n            UWORD32 *pu4_buffer, u4_offset;\n\n            pu4_buffer = ps_bitstrm->pu4_buffer;\n            u4_offset = ps_bitstrm->u4_ofst;\n\n            RENORM_RANGE_OFFSET(u4_code_int_range, u4_code_int_val_ofst, u4_offset,\n                                pu4_buffer)\n\n            ps_bitstrm->u4_ofst = u4_offset;\n        }\n\n    }\n    while(u4_bin && (u4_value < u1_max_bins));\n\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n    ps_cab_env->u4_code_int_range = u4_code_int_range;\n    u4_value = (u4_value - 1 + u4_bin);\n\nreturn (u4_value);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_decode_bypass_bins                                     */\n/*                                                                           */\n/*  Description   : This function is used in the case of FLC coding       */\n/*                                                                           */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 10 2005   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nUWORD32 ih264d_decode_bypass_bins(decoding_envirnoment_t *ps_cab_env,\n                                  UWORD8 u1_max_bins,\n                                  dec_bit_stream_t *ps_bitstrm)\n{\n    UWORD32 u4_bins;\n    UWORD32 u4_bin;\n    UWORD32 u4_code_int_val_ofst, u4_code_int_range;\n\n    u4_bins = 0;\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n\n    if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_9)\n    {\n        UWORD32 *pu4_buffer, u4_offset;\n\n        pu4_buffer = ps_bitstrm->pu4_buffer;\n        u4_offset = ps_bitstrm->u4_ofst;\n\n        RENORM_RANGE_OFFSET(u4_code_int_range, u4_code_int_val_ofst, u4_offset,\n                            pu4_buffer)\n        ps_bitstrm->u4_ofst = u4_offset;\n    }\n\n    do\n    {\n\n        u4_code_int_range = u4_code_int_range >> 1;\n\n        if(u4_code_int_val_ofst >= u4_code_int_range)\n        {\n            /* S=1 */\n            u4_bin = 1;\n            u4_code_int_val_ofst -= u4_code_int_range;\n        }\n        else\n        {\n            /* S=0 */\n            u4_bin = 0;\n        }\n\n        INC_BIN_COUNT(ps_cab_env);INC_BYPASS_BINS(ps_cab_env);\n\n        u4_bins = ((u4_bins << 1) | u4_bin);\n        u1_max_bins--;\n\n        if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_9)\n        {\n            UWORD32 *pu4_buffer, u4_offset;\n\n            pu4_buffer = ps_bitstrm->pu4_buffer;\n            u4_offset = ps_bitstrm->u4_ofst;\n\n            RENORM_RANGE_OFFSET(u4_code_int_range, u4_code_int_val_ofst, u4_offset,\n                                pu4_buffer)\n            ps_bitstrm->u4_ofst = u4_offset;\n        }\n\n    }\n    while(u1_max_bins);\n\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n    ps_cab_env->u4_code_int_range = u4_code_int_range;\n\n    return (u4_bins);\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_cabac.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n ***************************************************************************\n * \\file ih264d_cabac.h\n *\n * \\brief\n *    This file contains declarations of Binary decoding routines and tables.\n *\n * \\date\n *    04/02/2003\n *\n * \\author  NS\n ***************************************************************************\n */\n\n#ifndef _IH264D_CABAC_H_\n#define _IH264D_CABAC_H_\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_defs.h\"\n\n#define   B_BITS    10\n\n#define   HALF      (1 << (B_BITS-1))\n#define   QUARTER   (1 << (B_BITS-2))\n\n#define CTXT_UNUSED   {0,64}\n#define NUM_MB_SKIP_CTXT  6\n#define NUM_MB_TYPE_CTXT  9\n#define NUM_SUBMB_TYPE_CTXT 7\n#define NUM_REF_IDX_CTXT  6\n#define NUM_MB_QP_DELTA 4\n#define NUM_PRED_MODE 6\n#define NUM_MB_FIELD    3\n#define NUM_CBP 12\n#define NUM_CTX_MVD 14\n\n/* Residual block cabac context parameters */\n#define NUM_CTX_CAT 6\n#define NUM_LUMA_CTX_CAT 3\n#define NUM_CTX_CODED_BLOCK 4\n/* Luma CtxSigCoeff + CtxLastCoeff = 15 + 15 = 30 */\n#define NUM_LUMA_CTX_SIG_COEF 30\n/* Chroma DC CtxSigCoeff + CtxLastCoeff = 3 + 3 = 6 */\n#define NUM_CTX_CHROMA_DC_SIG_COEF 6\n/* Chroma AC CtxSigCoeff + CtxLastCoeff = 14 + 14 = 28 */\n#define NUM_CTX_CHROMA_AC_SIG_COEF 28\n#define NUM_CTX_ABS_LEVEL 10\n\n#define LUMA_DC_CTXCAT    0\n#define LUMA_AC_CTXCAT    1\n#define LUMA_4X4_CTXCAT   2\n#define CHROMA_DC_CTXCAT  3\n#define CHROMA_AC_CTXCAT  4\n#define LUMA_8X8_CTXCAT   5\n\n/*****************************************************************************/\n/* Constant Macros                                                           */\n/*****************************************************************************/\n#define NUM_CABAC_CTXTS 460\n#define QP_RANGE        52\n#define NUM_CAB_INIT_IDC_PLUS_ONE 4\n#define LAST_COEFF_CTXT_MINUS_SIG_COEFF_CTXT 61\n#define LAST_COEFF_CTXT_MINUS_SIG_COEFF_CTXT_8X8 15\n\n/*bits 0 to 5 :state\n bit 6:mps*/\ntypedef struct\n{\n    UWORD8 u1_mps_state; /* state number */\n} bin_ctxt_model_t;\n\ntypedef struct\n\n{\n    /* Neighbour availability Variables needed to get CtxtInc, for CABAC */\n    UWORD8 u1_mb_type; /** macroblock type: I/P/B/SI/SP */\n    UWORD8 u1_cbp; /** Coded Block Pattern */\n    UWORD8 u1_intra_chroma_pred_mode;\n\n    /*************************************************************************/\n    /*               Arrangnment of DC CSBP                                  */\n    /*        bits:  b7  b6  b5  b4  b3  b2  b1  b0                          */\n    /*        CSBP:   x   x   x   x   x  Vdc Udc Ydc                         */\n    /*************************************************************************/\n    UWORD8 u1_yuv_dc_csbp;\n    WORD8 i1_ref_idx[4];\n    UWORD8 u1_mv[4][4];\n    UWORD8 u1_transform8x8_ctxt;\n} ctxt_inc_mb_info_t;\n\n#define ONE_RIGHT_SHIFTED_BY_8 1<<8\n#define ONE_RIGHT_SHIFTED_BY_9    1<<9\n#define ONE_RIGHT_SHIFTED_BY_14 1<<14\ntypedef struct\n{\n    UWORD32 u4_code_int_range;\n    UWORD32 u4_code_int_val_ofst;\n    const void *cabac_table;\n    void * pv_codec_handle; /* For Error Handling */\n} decoding_envirnoment_t;\n\nWORD32 ih264d_init_cabac_dec_envirnoment(decoding_envirnoment_t * ps_cab_env,\n                                       dec_bit_stream_t *ps_bitstrm);\n\nUWORD32 ih264d_decode_bin(UWORD32 u4_ctx_inc,\n                          bin_ctxt_model_t *ps_bin_ctxt,\n                          dec_bit_stream_t *ps_bitstrm,\n                          decoding_envirnoment_t *ps_cab_env);\nUWORD8 ih264d_decode_terminate(decoding_envirnoment_t * ps_cab_env,\n                               dec_bit_stream_t * ps_bitstrm);\n\nUWORD32 ih264d_decode_bins_tunary(UWORD8 u1_max_bins,\n                                  UWORD32 u4_ctx_inc,\n                                  bin_ctxt_model_t *ps_src_bin_ctxt,\n                                  dec_bit_stream_t *ps_bitstrm,\n                                  decoding_envirnoment_t *ps_cab_env);\n\nUWORD32 ih264d_decode_bins(UWORD8 u1_max_bins,\n                           UWORD32 u4_ctx_inc,\n                           bin_ctxt_model_t *ps_src_bin_ctxt,\n                           dec_bit_stream_t *ps_bitstrm,\n                           decoding_envirnoment_t *ps_cab_env);\nUWORD32 ih264d_decode_bins_unary(UWORD8 u1_max_bins,\n                                 UWORD32 u4_ctx_inc,\n                                 bin_ctxt_model_t *ps_src_bin_ctxt,\n                                 dec_bit_stream_t *ps_bitstrm,\n                                 decoding_envirnoment_t *ps_cab_env);\n\nUWORD32 ih264d_decode_bypass_bins_unary(decoding_envirnoment_t *ps_cab_env,\n                                        dec_bit_stream_t *ps_bitstrm);\n\nUWORD32 ih264d_decode_bypass_bins(decoding_envirnoment_t *ps_cab_env,\n                                  UWORD8 u1_max_bins,\n                                  dec_bit_stream_t *ps_bitstrm);\n\n/*****************************************************************************/\n/* Function Macros                                                           */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/* Defining a macro for renormalization*/\n/*****************************************************************************/\n\n/*we renormalize every time the number bits(which are read ahead of time) we have\n consumed in the u4_ofst exceeds 23*/\n\n#define RENORM_RANGE_OFFSET(u4_codeIntRange_m,u4_codeIntValOffset_m,u4_offset_m,pu4_buffer_m) \\\n  {                                                                                         \\\n    UWORD32 read_bits_m,u4_clz_m  ;                                                         \\\n    u4_clz_m = CLZ(u4_codeIntRange_m);                                                  \\\n    NEXTBITS(read_bits_m,(u4_offset_m+23),pu4_buffer_m,u4_clz_m)                            \\\n    FLUSHBITS(u4_offset_m,(u4_clz_m))                                                       \\\n    u4_codeIntRange_m = u4_codeIntRange_m << u4_clz_m;                                      \\\n    u4_codeIntValOffset_m = (u4_codeIntValOffset_m << u4_clz_m) | read_bits_m;              \\\n  }\n\n/*****************************************************************************/\n/* Defining a macro for checking if the symbol is MPS*/\n/*****************************************************************************/\n\n#define CHECK_IF_LPS(u4_codeIntRange_m,u4_codeIntValOffset_m,u4_symbol_m,                   \\\n                    u4_codeIntRangeLPS_m,u1_mps_state_m,table_lookup_m)                     \\\n{                                                                                         \\\n  if(u4_codeIntValOffset_m >= u4_codeIntRange_m)                                            \\\n  {                                                                                         \\\n      u4_symbol_m = 1 - u4_symbol_m;                                                        \\\n      u4_codeIntValOffset_m -= u4_codeIntRange_m;                                           \\\n      u4_codeIntRange_m = u4_codeIntRangeLPS_m;                                             \\\n      u1_mps_state_m = (table_lookup_m >> 15) & 0x7F;                                       \\\n  }                                                                                         \\\n}\n\n/*!\n **************************************************************************\n * \\if Function name : DECODE_ONE_BIN_MACRO \\endif\n *\n * \\brief\n *    This function implements decoding process of a decision as defined\n *    in 9.3.3.2.2.\n *\n * \\return\n *    Returns symbol decoded.\n *\n * \\note\n *    It is specified in 9.3.3.2.3.2 that, one of the input to this function\n *    is CtxIdx. CtxIdx is used to identify state and MPS of that context\n *    (Refer Fig 9.11 - Flowchart for encoding a decision). To suffice that\n *    here we pass a pointer bin_ctxt_model_t which contains these values.\n *\n **************************************************************************\n */\n\n#define DECODE_ONE_BIN_MACRO(p_binCtxt_arg ,u4_code_int_range,u4_code_int_val_ofst,       \\\n                     pu4_table_arg,                                                \\\n                     p_DecBitStream_arg,u4_symbol)                                           \\\n{                                                                                       \\\n    bin_ctxt_model_t *p_binCtxt_m = (bin_ctxt_model_t *) p_binCtxt_arg;                           \\\n    dec_bit_stream_t *p_DecBitStream_m = (dec_bit_stream_t *) p_DecBitStream_arg;                 \\\n    const UWORD32 *pu4_table_m = (const UWORD32 *) pu4_table_arg;                         \\\n                                                                                        \\\n    UWORD32 u4_quantCodeIntRange_m,u4_codeIntRangeLPS_m;                                    \\\n    UWORD32 u1_mps_state_m;                                                               \\\n    UWORD32 table_lookup_m;                                                               \\\n    UWORD32 u4_clz_m;                                                                     \\\n                                                                                        \\\n    u1_mps_state_m = (p_binCtxt_m->u1_mps_state);                                           \\\n    u4_clz_m = CLZ(u4_code_int_range);                                                  \\\n    u4_quantCodeIntRange_m = u4_code_int_range << u4_clz_m;                                   \\\n    u4_quantCodeIntRange_m = (u4_quantCodeIntRange_m >> 29) & 0x3;                          \\\n    table_lookup_m = pu4_table_m[(u1_mps_state_m << 2)+u4_quantCodeIntRange_m];                 \\\n    u4_codeIntRangeLPS_m = table_lookup_m & 0xff;                                           \\\n                                                                                        \\\n    u4_codeIntRangeLPS_m = u4_codeIntRangeLPS_m << (23 - u4_clz_m);                           \\\n    u4_code_int_range = u4_code_int_range - u4_codeIntRangeLPS_m;                             \\\n    u4_symbol = ((u1_mps_state_m>> 6) & 0x1);                                             \\\n    /*if mps*/                                                                          \\\n    u1_mps_state_m = (table_lookup_m >> 8) & 0x7F;                                          \\\n    if(u4_code_int_val_ofst >= u4_code_int_range)                                          \\\n  {                                                                                     \\\n                                                                                        \\\n    u4_symbol = 1 - u4_symbol;                                                          \\\n    u4_code_int_val_ofst -= u4_code_int_range;                                             \\\n    u4_code_int_range = u4_codeIntRangeLPS_m;                                               \\\n    u1_mps_state_m = (table_lookup_m >> 15) & 0x7F;                                         \\\n  }                                                                                     \\\n    if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_8)                                        \\\n    {                                                                                   \\\n        UWORD32 *pu4_buffer,u4_offset;                                                  \\\n        UWORD32 read_bits,u4_clz_m  ;                                                     \\\n                                                                                        \\\n        pu4_buffer = p_DecBitStream_m->pu4_buffer;                                         \\\n        u4_offset = p_DecBitStream_m->u4_ofst;                                          \\\n        u4_clz_m = CLZ(u4_code_int_range);                                              \\\n        NEXTBITS(read_bits,(u4_offset+23),pu4_buffer,u4_clz_m)                            \\\n        FLUSHBITS(u4_offset,(u4_clz_m))                                                   \\\n        u4_code_int_range = u4_code_int_range << u4_clz_m;                                    \\\n        u4_code_int_val_ofst= (u4_code_int_val_ofst << u4_clz_m) | read_bits;               \\\n                                                                                        \\\n                                                                                        \\\n        p_DecBitStream_m->u4_ofst = u4_offset;                                          \\\n    }                                                                                   \\\n    p_binCtxt_m->u1_mps_state = u1_mps_state_m;                                             \\\n}\n\n#endif  /*  _IH264D_CABAC_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_cabac_init_tables.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _CABAC_INIT_TABLES_H_\n#define _CABAC_INIT_TABLES_H_\n\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264d_cabac_init_tables.c                                  */\n/*                                                                           */\n/*  Description       : This file contains the initialized cabac context     */\n/*                      structures for all possible values of  Qp (0 - 51)   */\n/*                      Cabac_init Idc (0 - 2) and I slice. The contexts     */\n/*                      are initialized and stored as per tables 9-11 to     */\n/*                      9 -23                                                */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         10 01 2005    SH                                                  */\n/*                                                                           */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_cabac.h\"\n#include \"ih264d_tables.h\"\n\n/*combined table :guc_RTAB,NextStateLPS,NextStateMPS\n input(combined_state):\n bits 0-5: state\n bits 6:mps\n output\n bits 0-7:rangeTabLPS\n bits 8-14 :combined_next_state_if_mps\n bits 15 -21:combined_next_state_if_lps\n\n */\n\nconst UWORD32 gau4_ih264d_cabac_table[128][4] =\n    {\n        { 2097536, 2097584, 2097616, 2097648 },\n\n          { 640, 679, 709, 739 },\n\n          { 33664, 33694, 33723, 33752 },\n\n          { 66683, 66710, 66738, 66765 },\n\n          { 66932, 66958, 66985, 67011 },\n\n          { 132719, 132743, 132768, 132793 },\n\n          { 132969, 132992, 133016, 133039 },\n\n          { 165988, 166010, 166032, 166054 },\n\n          { 199007, 199028, 199049, 199070 },\n\n          { 232026, 232046, 232066, 232086 },\n\n          { 265045, 265064, 265083, 265102 },\n\n          { 298065, 298083, 298101, 298119 },\n\n          { 298317, 298334, 298351, 298368 },\n\n          { 364105, 364121, 364137, 364154 },\n\n          { 364357, 364373, 364388, 364404 },\n\n          { 397378, 397392, 397407, 397422 },\n\n          { 430398, 430412, 430426, 430440 },\n\n          { 430651, 430664, 430678, 430691 },\n\n          { 496440, 496453, 496465, 496478 },\n\n          { 496693, 496705, 496717, 496729 },\n\n          { 529715, 529726, 529737, 529749 },\n\n          { 529968, 529979, 529989, 530000 },\n\n          { 595758, 595768, 595778, 595788 },\n\n          { 596011, 596021, 596031, 596040 },\n\n          { 629033, 629042, 629051, 629061 },\n\n          { 629287, 629296, 629304, 629313 },\n\n          { 695077, 695085, 695094, 695102 },\n\n          { 695331, 695339, 695347, 695355 },\n\n          { 728353, 728361, 728368, 728376 },\n\n          { 728608, 728615, 728622, 728629 },\n\n          { 761630, 761637, 761643, 761650 },\n\n          { 794653, 794659, 794665, 794672 },\n\n          { 794907, 794913, 794919, 794925 },\n\n          { 827930, 827935, 827941, 827947 },\n\n          { 860952, 860958, 860963, 860969 },\n\n          { 861207, 861212, 861217, 861223 },\n\n          { 894230, 894235, 894240, 894245 },\n\n          { 894485, 894490, 894494, 894499 },\n\n          { 927508, 927512, 927517, 927521 },\n\n          { 960531, 960535, 960539, 960543 },\n\n          { 960786, 960790, 960794, 960798 },\n\n          { 993809, 993813, 993817, 993820 },\n\n          { 994064, 994068, 994071, 994075 },\n\n          { 994319, 994323, 994326, 994329 },\n\n          { 1027342, 1027346, 1027349, 1027352 },\n\n          { 1060366, 1060369, 1060372, 1060375 },\n\n          { 1060621, 1060624, 1060627, 1060630 },\n\n          { 1093644, 1093647, 1093650, 1093653 },\n\n          { 1093900, 1093902, 1093905, 1093908 },\n\n          { 1094155, 1094158, 1094160, 1094163 },\n\n          { 1127179, 1127181, 1127183, 1127186 },\n\n          { 1127434, 1127436, 1127439, 1127441 },\n\n          { 1160458, 1160460, 1160462, 1160464 },\n\n          { 1160713, 1160715, 1160717, 1160719 },\n\n          { 1160969, 1160971, 1160972, 1160974 },\n\n          { 1193992, 1193994, 1193996, 1193998 },\n\n          { 1194248, 1194249, 1194251, 1194253 },\n\n          { 1194503, 1194505, 1194507, 1194508 },\n\n          { 1227527, 1227529, 1227530, 1227532 },\n\n          { 1227783, 1227784, 1227786, 1227787 },\n\n          { 1228038, 1228040, 1228041, 1228043 },\n\n          { 1261062, 1261063, 1261065, 1261066 },\n\n          { 1261062, 1261063, 1261064, 1261065 },\n\n          { 2080514, 2080514, 2080514, 2080514 },\n\n          { 16768, 16816, 16848, 16880 },\n\n          { 2114176, 2114215, 2114245, 2114275 },\n\n          { 2147200, 2147230, 2147259, 2147288 },\n\n          { 2180219, 2180246, 2180274, 2180301 },\n\n          { 2180468, 2180494, 2180521, 2180547 },\n\n          { 2246255, 2246279, 2246304, 2246329 },\n\n          { 2246505, 2246528, 2246552, 2246575 },\n\n          { 2279524, 2279546, 2279568, 2279590 },\n\n          { 2312543, 2312564, 2312585, 2312606 },\n\n          { 2345562, 2345582, 2345602, 2345622 },\n\n          { 2378581, 2378600, 2378619, 2378638 },\n\n          { 2411601, 2411619, 2411637, 2411655 },\n\n          { 2411853, 2411870, 2411887, 2411904 },\n\n          { 2477641, 2477657, 2477673, 2477690 },\n\n          { 2477893, 2477909, 2477924, 2477940 },\n\n          { 2510914, 2510928, 2510943, 2510958 },\n\n          { 2543934, 2543948, 2543962, 2543976 },\n\n          { 2544187, 2544200, 2544214, 2544227 },\n\n          { 2609976, 2609989, 2610001, 2610014 },\n\n          { 2610229, 2610241, 2610253, 2610265 },\n\n          { 2643251, 2643262, 2643273, 2643285 },\n\n          { 2643504, 2643515, 2643525, 2643536 },\n\n          { 2709294, 2709304, 2709314, 2709324 },\n\n          { 2709547, 2709557, 2709567, 2709576 },\n\n          { 2742569, 2742578, 2742587, 2742597 },\n\n          { 2742823, 2742832, 2742840, 2742849 },\n\n          { 2808613, 2808621, 2808630, 2808638 },\n\n          { 2808867, 2808875, 2808883, 2808891 },\n\n          { 2841889, 2841897, 2841904, 2841912 },\n\n          { 2842144, 2842151, 2842158, 2842165 },\n\n          { 2875166, 2875173, 2875179, 2875186 },\n\n          { 2908189, 2908195, 2908201, 2908208 },\n\n          { 2908443, 2908449, 2908455, 2908461 },\n\n          { 2941466, 2941471, 2941477, 2941483 },\n\n          { 2974488, 2974494, 2974499, 2974505 },\n\n          { 2974743, 2974748, 2974753, 2974759 },\n\n          { 3007766, 3007771, 3007776, 3007781 },\n\n          { 3008021, 3008026, 3008030, 3008035 },\n\n          { 3041044, 3041048, 3041053, 3041057 },\n\n          { 3074067, 3074071, 3074075, 3074079 },\n\n          { 3074322, 3074326, 3074330, 3074334 },\n\n          { 3107345, 3107349, 3107353, 3107356 },\n\n          { 3107600, 3107604, 3107607, 3107611 },\n\n          { 3107855, 3107859, 3107862, 3107865 },\n\n          { 3140878, 3140882, 3140885, 3140888 },\n\n          { 3173902, 3173905, 3173908, 3173911 },\n\n          { 3174157, 3174160, 3174163, 3174166 },\n\n          { 3207180, 3207183, 3207186, 3207189 },\n\n          { 3207436, 3207438, 3207441, 3207444 },\n\n          { 3207691, 3207694, 3207696, 3207699 },\n\n          { 3240715, 3240717, 3240719, 3240722 },\n\n          { 3240970, 3240972, 3240975, 3240977 },\n\n          { 3273994, 3273996, 3273998, 3274000 },\n\n          { 3274249, 3274251, 3274253, 3274255 },\n\n          { 3274505, 3274507, 3274508, 3274510 },\n\n          { 3307528, 3307530, 3307532, 3307534 },\n\n          { 3307784, 3307785, 3307787, 3307789 },\n\n          { 3308039, 3308041, 3308043, 3308044 },\n\n          { 3341063, 3341065, 3341066, 3341068 },\n\n          { 3341319, 3341320, 3341322, 3341323 },\n\n          { 3341574, 3341576, 3341577, 3341579 },\n\n          { 3374598, 3374599, 3374601, 3374602 },\n\n          { 3374598, 3374599, 3374600, 3374601 },\n\n          { 4194050, 4194050, 4194050, 4194050 },\n\n    };\n\n/*****************************************************************************/\n/* Global Variable Initialization                                            */\n/*****************************************************************************/\nconst UWORD8 gau1_ih264d_cabac_ctxt_init_table[NUM_CAB_INIT_IDC_PLUS_ONE][QP_RANGE][NUM_CABAC_CTXTS] =\n\n                    {\n\n                        {\n\n                            {\n\n                            62,\n                              9, 74, 62, 9, 74, 126, 104, 10, 9, 12, 30, 61, 62,\n                              54, 14, 118, 6, 78, 65, 1, 14, 73, 13, 64, 20, 62,\n                              67, 90, 104, 126, 104, 67, 78, 65, 1, 86, 95, 2,\n                              18, 69, 81, 96, 8, 67, 86, 88, 5, 76, 94, 9, 69,\n                              81, 88, 67, 74, 74, 80, 72, 5, 22, 0, 0, 0, 83,\n                              86, 97, 72, 22, 1, 18, 78, 96, 126, 98, 101, 67,\n                              82, 94, 83, 110, 91, 102, 93, 126, 92, 89, 96,\n                              108, 17, 65, 6, 93, 74, 92, 87, 126, 9, 3, 4, 69,\n                              15, 68, 69, 88, 85, 78, 75, 77, 9, 13, 68, 13, 21,\n                              81, 0, 70, 67, 6, 76, 28, 64, 2, 28, 38, 39, 34,\n                              27, 93, 73, 73, 17, 14, 100, 10, 10, 10, 2, 7, 7,\n                              0, 3, 1, 6, 69, 6, 24, 12, 68, 64, 2, 0, 13, 24,\n                              19, 11, 15, 3, 4, 4, 30, 19, 20, 78, 3, 69, 35,\n                              23, 19, 14, 17, 19, 12, 16, 24, 1, 17, 9, 9, 5, 0,\n                              12, 6, 10, 11, 8, 18, 27, 10, 82, 8, 78, 17, 32,\n                              84, 56, 62, 60, 59, 62, 62, 57, 57, 54, 44, 36,\n                              33, 43, 29, 70, 67, 4, 67, 33, 31, 28, 34, 32, 25,\n                              20, 22, 0, 4, 64, 94, 89, 108, 76, 19, 18, 11, 64,\n                              4, 70, 75, 82, 102, 77, 39, 21, 15, 8, 4, 71, 83,\n                              87, 119, 5, 34, 27, 25, 20, 8, 5, 64, 74, 90, 70,\n                              34, 32, 21, 4, 5, 72, 81, 97, 5, 58, 49, 45, 36,\n                              23, 5, 70, 79, 85, 62, 106, 106, 87, 114, 110, 98,\n                              110, 106, 103, 107, 108, 112, 96, 95, 91, 93, 94,\n                              86, 67, 80, 85, 70, 3, 5, 2, 13, 13, 14, 9, 22,\n                              17, 12, 14, 11, 22, 16, 8, 22, 19, 13, 10, 14, 0,\n                              64, 69, 4, 70, 19, 32, 20, 10, 29, 25, 11, 23, 31,\n                              19, 25, 13, 6, 20, 52, 49, 52, 52, 54, 62, 62, 62,\n                              62, 62, 62, 62, 62, 62, 34, 62, 62, 62, 62, 62,\n                              62, 54, 37, 36, 6, 82, 75, 97, 125, 62, 62, 62,\n                              57, 55, 53, 41, 44, 31, 32, 22, 19, 16, 65, 71, 3,\n                              0, 65, 39, 43, 40, 31, 40, 39, 23, 31, 34, 21, 6,\n                              10, 2, 86, 23, 12, 4, 79, 71, 69, 70, 66, 68, 73,\n                              69, 70, 67, 1, 70, 66, 65, 0, 62, 62, 62, 62, 62,\n                              60, 54, 36, 4, 66, 28, 21, 18, 15, 7, 3, 1, 66,\n                              76, 85, 81, 77, 81, 80, 73, 74, 83, 71, 67, 2, 66,\n                              66, 4, 4, 62, 62, 62, 62, 61, 57, 46, 29, 1 },\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 125, 102, 11, 10, 12, 29, 60,\n                                62, 54, 14, 115, 6, 77, 64, 1, 14, 72, 12, 65,\n                                20, 62, 68, 91, 104, 124, 102, 67, 77, 64, 1,\n                                85, 93, 3, 18, 68, 80, 95, 8, 67, 85, 88, 5, 75,\n                                93, 9, 69, 80, 88, 66, 73, 73, 79, 71, 5, 22, 0,\n                                0, 0, 82, 86, 97, 71, 22, 1, 18, 77, 95, 124,\n                                96, 99, 65, 80, 92, 82, 108, 89, 100, 92, 125,\n                                91, 88, 95, 107, 18, 64, 7, 92, 73, 91, 86, 124,\n                                9, 3, 4, 69, 16, 68, 68, 87, 84, 77, 74, 76, 9,\n                                13, 67, 13, 21, 80, 0, 69, 67, 6, 75, 28, 64, 2,\n                                28, 37, 39, 34, 27, 92, 72, 72, 17, 14, 99, 10,\n                                10, 10, 3, 7, 7, 1, 4, 2, 6, 68, 6, 24, 12, 68,\n                                64, 2, 0, 13, 23, 19, 11, 15, 4, 5, 4, 29, 19,\n                                20, 77, 3, 69, 35, 23, 19, 14, 17, 19, 12, 16,\n                                24, 1, 17, 9, 9, 5, 0, 12, 6, 10, 11, 8, 18, 27,\n                                10, 81, 8, 77, 17, 31, 83, 55, 62, 59, 58, 61,\n                                62, 56, 56, 52, 43, 35, 32, 41, 28, 71, 67, 4,\n                                67, 32, 30, 27, 33, 31, 24, 19, 21, 0, 4, 64,\n                                93, 88, 107, 75, 20, 18, 11, 0, 5, 69, 74, 81,\n                                100, 76, 39, 21, 15, 8, 5, 70, 82, 86, 117, 5,\n                                35, 28, 25, 20, 9, 5, 64, 73, 89, 70, 35, 32,\n                                21, 4, 6, 71, 80, 96, 5, 58, 49, 45, 36, 23, 5,\n                                69, 78, 84, 62, 105, 105, 86, 112, 108, 97, 108,\n                                104, 101, 105, 106, 110, 95, 94, 90, 92, 92, 85,\n                                67, 79, 84, 69, 3, 5, 2, 13, 13, 13, 8, 22, 17,\n                                13, 14, 11, 22, 16, 8, 22, 19, 13, 10, 14, 0,\n                                64, 68, 5, 70, 19, 32, 20, 10, 29, 25, 12, 23,\n                                30, 19, 25, 13, 6, 19, 52, 49, 52, 51, 53, 62,\n                                62, 62, 62, 62, 62, 62, 62, 62, 33, 62, 62, 62,\n                                62, 62, 62, 53, 36, 35, 6, 81, 74, 95, 122, 62,\n                                62, 62, 56, 53, 52, 40, 42, 30, 31, 21, 18, 15,\n                                66, 71, 3, 0, 66, 38, 42, 39, 30, 39, 38, 22,\n                                30, 33, 20, 5, 9, 1, 86, 23, 12, 4, 78, 70, 68,\n                                69, 65, 67, 71, 68, 69, 66, 3, 68, 65, 0, 2, 62,\n                                62, 62, 62, 62, 58, 51, 34, 2, 65, 29, 22, 19,\n                                16, 8, 4, 2, 65, 75, 84, 80, 76, 80, 78, 71, 73,\n                                82, 70, 66, 3, 65, 65, 4, 4, 62, 62, 62, 62, 58,\n                                54, 43, 26, 64 },\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 123, 101, 11, 10, 12, 28, 59,\n                                61, 54, 14, 113, 6, 76, 0, 1, 13, 72, 11, 66,\n                                19, 60, 70, 92, 105, 121, 101, 67, 76, 0, 1, 85,\n                                92, 3, 17, 68, 80, 94, 8, 67, 85, 88, 5, 75, 92,\n                                9, 69, 80, 88, 66, 73, 73, 79, 71, 5, 22, 0, 0,\n                                0, 81, 86, 97, 71, 21, 1, 18, 77, 95, 122, 94,\n                                97, 64, 78, 91, 81, 107, 88, 99, 91, 123, 91,\n                                88, 95, 106, 18, 64, 7, 91, 73, 90, 86, 123, 9,\n                                3, 4, 69, 16, 68, 68, 87, 84, 77, 74, 76, 9, 13,\n                                67, 13, 21, 80, 0, 69, 67, 6, 75, 27, 64, 2, 27,\n                                36, 38, 33, 26, 91, 72, 72, 16, 13, 99, 9, 10,\n                                10, 3, 7, 7, 2, 4, 2, 6, 68, 6, 23, 12, 69, 64,\n                                2, 64, 13, 22, 19, 11, 14, 4, 5, 4, 28, 19, 19,\n                                77, 3, 70, 34, 23, 19, 14, 17, 19, 12, 16, 24,\n                                1, 17, 9, 9, 5, 0, 12, 6, 10, 11, 8, 17, 26, 9,\n                                81, 8, 77, 16, 30, 83, 53, 62, 57, 56, 59, 60,\n                                54, 54, 50, 41, 33, 30, 39, 26, 72, 67, 4, 68,\n                                31, 29, 26, 32, 29, 23, 18, 20, 64, 3, 65, 93,\n                                88, 106, 75, 20, 18, 11, 0, 5, 69, 74, 81, 99,\n                                75, 39, 21, 15, 8, 5, 70, 81, 85, 115, 5, 35,\n                                28, 25, 20, 9, 5, 64, 73, 88, 70, 35, 32, 21, 4,\n                                6, 71, 80, 95, 5, 57, 48, 44, 35, 23, 5, 69, 78,\n                                84, 62, 104, 104, 85, 111, 107, 96, 107, 103,\n                                100, 104, 105, 108, 94, 93, 90, 91, 91, 85, 68,\n                                79, 83, 69, 3, 4, 2, 12, 12, 12, 7, 21, 17, 13,\n                                14, 10, 21, 16, 8, 21, 18, 13, 10, 13, 0, 64,\n                                68, 5, 70, 18, 31, 19, 10, 28, 24, 12, 22, 29,\n                                19, 25, 12, 5, 17, 51, 48, 51, 50, 52, 62, 62,\n                                62, 62, 62, 62, 62, 62, 62, 32, 62, 62, 62, 62,\n                                62, 62, 51, 35, 34, 6, 80, 74, 94, 120, 60, 60,\n                                62, 54, 51, 50, 38, 40, 29, 29, 20, 16, 14, 67,\n                                72, 2, 0, 67, 37, 41, 37, 28, 37, 36, 21, 28,\n                                31, 19, 4, 8, 0, 87, 22, 11, 3, 78, 70, 68, 68,\n                                65, 66, 70, 67, 68, 65, 4, 67, 64, 1, 3, 62, 62,\n                                62, 62, 60, 55, 48, 31, 0, 65, 29, 22, 19, 16,\n                                9, 4, 2, 65, 75, 84, 80, 75, 80, 77, 70, 73, 81,\n                                69, 65, 3, 65, 64, 4, 4, 62, 62, 62, 60, 55, 50,\n                                39, 23, 67 },\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 121, 99, 12, 10, 11, 26, 57,\n                                60, 54, 14, 111, 6, 75, 1, 1, 12, 72, 10, 67,\n                                19, 58, 71, 93, 105, 118, 100, 67, 75, 1, 1, 84,\n                                91, 4, 17, 68, 79, 93, 7, 68, 85, 88, 5, 75, 92,\n                                9, 69, 80, 88, 65, 73, 73, 79, 70, 5, 22, 0, 0,\n                                0, 81, 86, 97, 70, 20, 1, 18, 77, 95, 120, 92,\n                                96, 1, 76, 90, 80, 105, 87, 98, 90, 121, 90, 88,\n                                94, 105, 18, 64, 7, 91, 73, 90, 85, 121, 9, 2,\n                                3, 70, 16, 68, 68, 86, 84, 76, 74, 75, 9, 13,\n                                67, 13, 20, 80, 0, 69, 67, 6, 75, 26, 64, 2, 26,\n                                35, 37, 32, 25, 91, 71, 72, 15, 13, 98, 9, 10,\n                                10, 3, 7, 7, 3, 4, 2, 6, 67, 6, 22, 12, 70, 64,\n                                2, 64, 12, 21, 19, 11, 13, 4, 5, 4, 26, 19, 18,\n                                77, 3, 70, 33, 23, 19, 14, 17, 19, 12, 16, 24,\n                                1, 16, 9, 9, 5, 0, 11, 5, 9, 10, 7, 16, 25, 9,\n                                81, 7, 77, 15, 28, 83, 52, 62, 55, 54, 57, 58,\n                                52, 52, 48, 39, 32, 29, 37, 24, 73, 67, 4, 68,\n                                30, 28, 25, 30, 28, 21, 17, 19, 65, 3, 65, 93,\n                                88, 106, 74, 20, 18, 11, 0, 5, 69, 74, 80, 98,\n                                75, 39, 21, 15, 8, 6, 69, 80, 84, 113, 5, 35,\n                                28, 25, 20, 10, 5, 64, 73, 88, 70, 35, 32, 20,\n                                4, 6, 71, 80, 94, 5, 57, 48, 43, 34, 23, 5, 69,\n                                77, 83, 62, 103, 103, 85, 110, 106, 95, 105,\n                                102, 99, 103, 103, 107, 94, 92, 90, 91, 89, 85,\n                                68, 79, 83, 69, 2, 4, 2, 11, 11, 11, 6, 21, 16,\n                                13, 13, 10, 21, 15, 8, 20, 18, 12, 10, 12, 0,\n                                65, 68, 5, 71, 18, 31, 18, 10, 27, 24, 12, 21,\n                                28, 18, 24, 11, 5, 16, 50, 47, 51, 49, 51, 61,\n                                62, 62, 62, 62, 62, 62, 62, 62, 31, 62, 62, 62,\n                                62, 62, 62, 49, 34, 33, 6, 79, 74, 93, 118, 58,\n                                58, 62, 52, 49, 48, 37, 38, 27, 28, 19, 15, 12,\n                                68, 73, 2, 64, 68, 36, 39, 36, 26, 35, 34, 19,\n                                27, 29, 17, 3, 6, 65, 88, 21, 10, 2, 78, 69, 68,\n                                68, 64, 66, 69, 66, 67, 64, 5, 66, 0, 3, 4, 62,\n                                62, 62, 62, 58, 52, 45, 28, 65, 64, 30, 23, 20,\n                                16, 10, 5, 2, 64, 74, 84, 79, 75, 79, 76, 69,\n                                73, 81, 69, 65, 3, 64, 0, 4, 4, 62, 62, 62, 57,\n                                52, 46, 35, 19, 69 },\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 120, 98, 12, 10, 11, 25, 56,\n                                58, 54, 14, 108, 5, 74, 1, 1, 11, 72, 9, 68, 18,\n                                56, 73, 94, 106, 115, 99, 67, 74, 1, 1, 84, 90,\n                                4, 16, 68, 79, 93, 7, 68, 84, 88, 5, 75, 91, 8,\n                                70, 80, 88, 65, 72, 73, 78, 70, 5, 22, 0, 0, 0,\n                                80, 87, 97, 70, 19, 1, 18, 77, 95, 119, 91, 94,\n                                2, 75, 89, 79, 104, 85, 97, 89, 119, 90, 87, 94,\n                                104, 18, 64, 7, 90, 73, 89, 85, 120, 8, 2, 3,\n                                70, 16, 68, 68, 86, 84, 76, 74, 75, 9, 12, 67,\n                                13, 20, 80, 0, 69, 67, 6, 75, 26, 65, 2, 26, 34,\n                                36, 31, 24, 90, 71, 72, 14, 12, 98, 8, 10, 9, 3,\n                                7, 7, 4, 5, 2, 5, 67, 5, 21, 11, 71, 64, 2, 65,\n                                12, 20, 18, 10, 13, 5, 5, 4, 25, 18, 17, 77, 3,\n                                71, 33, 23, 19, 14, 17, 19, 12, 16, 23, 1, 16,\n                                9, 9, 5, 64, 11, 5, 9, 10, 7, 16, 24, 8, 81, 7,\n                                77, 14, 27, 83, 50, 62, 53, 52, 55, 56, 50, 50,\n                                46, 37, 30, 27, 34, 22, 74, 67, 3, 69, 29, 27,\n                                24, 29, 26, 20, 16, 17, 65, 2, 66, 93, 88, 105,\n                                74, 20, 18, 11, 0, 5, 69, 74, 80, 97, 74, 39,\n                                21, 15, 8, 6, 69, 80, 84, 111, 5, 35, 28, 25,\n                                20, 10, 5, 64, 73, 87, 70, 35, 31, 20, 4, 6, 71,\n                                80, 94, 5, 56, 47, 42, 33, 23, 5, 69, 77, 83,\n                                62, 102, 102, 84, 108, 105, 94, 104, 100, 98,\n                                101, 102, 105, 93, 92, 89, 90, 88, 84, 69, 79,\n                                82, 69, 2, 3, 1, 10, 10, 10, 5, 20, 16, 13, 13,\n                                9, 20, 15, 8, 19, 17, 12, 9, 11, 64, 65, 68, 5,\n                                71, 17, 30, 17, 10, 26, 23, 12, 20, 27, 18, 24,\n                                10, 4, 14, 49, 47, 50, 48, 49, 60, 62, 62, 62,\n                                62, 62, 62, 62, 62, 29, 62, 62, 62, 62, 62, 62,\n                                47, 33, 31, 6, 78, 73, 92, 116, 57, 56, 60, 51,\n                                47, 46, 35, 36, 26, 26, 17, 13, 11, 69, 74, 1,\n                                64, 69, 34, 38, 34, 25, 33, 32, 18, 25, 27, 16,\n                                2, 5, 66, 88, 20, 10, 1, 78, 69, 67, 67, 64, 65,\n                                68, 66, 66, 0, 6, 65, 1, 4, 5, 62, 62, 62, 61,\n                                55, 49, 42, 25, 68, 64, 30, 23, 20, 17, 10, 5,\n                                3, 64, 74, 83, 79, 74, 79, 75, 68, 73, 80, 68,\n                                64, 3, 64, 1, 4, 4, 62, 62, 61, 54, 49, 42, 31,\n                                16, 72 },\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 118, 96, 12, 10, 10, 23, 54,\n                                57, 54, 14, 106, 5, 73, 2, 1, 11, 71, 8, 69, 18,\n                                54, 75, 95, 106, 112, 97, 67, 73, 2, 1, 84, 89,\n                                4, 16, 68, 79, 92, 7, 69, 84, 88, 5, 75, 90, 8,\n                                70, 80, 88, 64, 72, 72, 78, 69, 5, 22, 0, 0, 0,\n                                80, 87, 97, 69, 18, 1, 18, 76, 95, 117, 89, 93,\n                                4, 73, 87, 78, 103, 84, 96, 88, 117, 89, 87, 93,\n                                103, 18, 64, 7, 90, 73, 89, 84, 118, 8, 2, 3,\n                                70, 16, 68, 67, 85, 84, 76, 74, 74, 9, 12, 67,\n                                13, 20, 79, 0, 68, 67, 6, 75, 25, 65, 2, 25, 33,\n                                36, 30, 23, 89, 70, 72, 13, 12, 97, 8, 10, 9, 3,\n                                7, 7, 5, 5, 2, 5, 67, 5, 20, 11, 72, 64, 2, 65,\n                                11, 19, 18, 10, 12, 5, 5, 4, 24, 18, 16, 77, 3,\n                                71, 32, 23, 19, 14, 17, 19, 12, 16, 23, 1, 16,\n                                9, 9, 5, 64, 11, 5, 8, 10, 7, 15, 23, 8, 81, 6,\n                                77, 13, 26, 83, 49, 61, 52, 51, 53, 54, 48, 48,\n                                44, 35, 28, 25, 32, 21, 75, 67, 3, 69, 28, 26,\n                                23, 28, 25, 18, 15, 16, 66, 2, 66, 93, 88, 105,\n                                74, 20, 18, 11, 0, 5, 68, 73, 79, 96, 74, 39,\n                                21, 15, 8, 6, 68, 79, 83, 109, 5, 35, 28, 25,\n                                20, 10, 5, 64, 73, 86, 70, 36, 31, 19, 4, 6, 71,\n                                80, 93, 5, 56, 46, 41, 32, 23, 5, 69, 77, 82,\n                                62, 101, 101, 83, 107, 104, 93, 103, 99, 97,\n                                100, 100, 103, 92, 91, 89, 90, 87, 84, 69, 78,\n                                81, 69, 1, 3, 1, 10, 9, 9, 4, 19, 15, 13, 12, 9,\n                                20, 15, 8, 18, 16, 12, 9, 10, 64, 65, 68, 5, 71,\n                                16, 30, 17, 10, 25, 22, 12, 19, 26, 17, 23, 9,\n                                3, 12, 48, 46, 50, 47, 48, 58, 62, 62, 62, 62,\n                                62, 62, 62, 62, 28, 62, 62, 62, 62, 62, 61, 45,\n                                32, 30, 6, 77, 73, 91, 114, 55, 55, 58, 49, 45,\n                                44, 34, 34, 25, 24, 16, 11, 9, 70, 75, 1, 64,\n                                70, 33, 36, 32, 23, 32, 31, 16, 24, 26, 14, 1,\n                                4, 67, 89, 20, 9, 0, 77, 68, 67, 67, 0, 64, 67,\n                                65, 65, 1, 8, 64, 2, 5, 7, 62, 62, 62, 58, 53,\n                                46, 39, 22, 70, 64, 31, 24, 21, 17, 11, 5, 3, 0,\n                                73, 83, 79, 73, 78, 74, 67, 72, 79, 68, 64, 3,\n                                0, 2, 4, 4, 62, 62, 58, 51, 46, 39, 27, 12, 75 },\n\n                              {\n\n                              62,\n                                9, 75, 62, 9, 75, 116, 95, 13, 10, 10, 22, 53,\n                                56, 54, 14, 104, 5, 73, 3, 1, 10, 71, 7, 70, 17,\n                                53, 76, 96, 107, 109, 96, 67, 73, 3, 1, 83, 88,\n                                5, 15, 67, 78, 91, 6, 69, 84, 88, 5, 74, 90, 8,\n                                70, 79, 88, 64, 72, 72, 78, 69, 5, 22, 0, 0, 0,\n                                79, 87, 97, 69, 18, 0, 18, 76, 94, 115, 87, 91,\n                                5, 71, 86, 77, 101, 83, 95, 88, 116, 89, 87, 93,\n                                103, 19, 64, 7, 89, 72, 88, 84, 117, 8, 1, 2,\n                                71, 16, 68, 67, 85, 84, 75, 74, 74, 9, 12, 66,\n                                13, 19, 79, 0, 68, 67, 6, 75, 24, 65, 2, 24, 32,\n                                35, 30, 23, 89, 70, 72, 13, 11, 97, 7, 10, 9, 3,\n                                7, 7, 5, 5, 2, 5, 66, 5, 19, 11, 72, 65, 2, 66,\n                                11, 18, 18, 10, 11, 5, 5, 4, 22, 18, 15, 77, 3,\n                                72, 31, 23, 18, 14, 17, 19, 12, 16, 23, 1, 15,\n                                9, 8, 5, 64, 10, 4, 8, 9, 6, 14, 22, 7, 81, 6,\n                                76, 12, 24, 83, 47, 59, 50, 49, 51, 52, 46, 46,\n                                42, 33, 27, 24, 30, 19, 76, 67, 3, 70, 27, 25,\n                                22, 26, 23, 17, 14, 15, 67, 1, 67, 93, 88, 104,\n                                73, 20, 18, 11, 1, 5, 68, 73, 79, 95, 73, 38,\n                                21, 15, 8, 7, 68, 78, 82, 107, 5, 36, 28, 25,\n                                20, 11, 5, 64, 72, 86, 70, 36, 31, 19, 4, 6, 70,\n                                79, 92, 5, 55, 46, 40, 32, 23, 5, 68, 76, 82,\n                                62, 101, 100, 83, 106, 103, 92, 101, 98, 96, 99,\n                                99, 102, 92, 90, 89, 89, 85, 84, 70, 78, 81, 69,\n                                1, 2, 1, 9, 8, 8, 3, 19, 15, 13, 12, 8, 19, 14,\n                                8, 18, 16, 11, 9, 10, 64, 66, 68, 5, 72, 16, 29,\n                                16, 9, 24, 22, 13, 19, 25, 17, 23, 9, 3, 11, 47,\n                                45, 49, 46, 47, 57, 62, 62, 62, 62, 62, 62, 62,\n                                61, 27, 62, 62, 62, 62, 62, 59, 43, 31, 29, 6,\n                                76, 73, 89, 111, 53, 53, 56, 47, 43, 42, 32, 32,\n                                23, 23, 15, 10, 8, 71, 76, 0, 65, 71, 32, 35,\n                                31, 21, 30, 29, 15, 22, 24, 13, 64, 2, 69, 90,\n                                19, 8, 64, 77, 68, 67, 66, 0, 64, 65, 64, 64, 2,\n                                9, 1, 3, 7, 8, 62, 62, 60, 56, 50, 44, 36, 20,\n                                72, 0, 31, 24, 21, 17, 12, 6, 3, 0, 73, 83, 78,\n                                73, 78, 73, 66, 72, 79, 67, 0, 3, 0, 3, 4, 4,\n                                62, 62, 56, 48, 42, 35, 24, 9, 77 },\n\n                              {\n\n                              62,\n                                9, 75, 62, 9, 75, 114, 93, 13, 10, 9, 20, 51,\n                                54, 54, 14, 101, 4, 72, 3, 1, 9, 71, 6, 71, 17,\n                                51, 78, 97, 107, 106, 95, 67, 72, 3, 1, 83, 87,\n                                5, 15, 67, 78, 91, 6, 70, 83, 88, 5, 74, 89, 7,\n                                70, 79, 88, 0, 71, 72, 77, 68, 5, 22, 0, 0, 0,\n                                79, 87, 97, 68, 17, 0, 18, 76, 94, 114, 85, 90,\n                                7, 69, 85, 76, 100, 81, 94, 87, 114, 88, 86, 92,\n                                102, 19, 64, 7, 89, 72, 88, 83, 115, 7, 1, 2,\n                                71, 16, 68, 67, 84, 84, 75, 74, 73, 9, 11, 66,\n                                13, 19, 79, 0, 68, 67, 6, 75, 24, 65, 2, 24, 31,\n                                34, 29, 22, 88, 69, 72, 12, 11, 96, 7, 10, 8, 3,\n                                7, 7, 6, 6, 2, 5, 66, 5, 18, 11, 73, 65, 2, 66,\n                                10, 17, 17, 10, 11, 6, 5, 4, 21, 17, 14, 77, 3,\n                                72, 31, 23, 18, 14, 17, 19, 12, 16, 23, 1, 15,\n                                9, 8, 5, 64, 10, 4, 7, 9, 6, 14, 21, 7, 81, 5,\n                                76, 11, 23, 83, 46, 57, 48, 47, 49, 50, 44, 44,\n                                40, 31, 25, 22, 27, 17, 77, 67, 2, 70, 26, 24,\n                                21, 25, 22, 15, 13, 14, 67, 1, 67, 93, 88, 104,\n                                73, 20, 18, 11, 1, 5, 68, 73, 78, 94, 73, 38,\n                                21, 15, 8, 7, 67, 77, 82, 105, 5, 36, 28, 25,\n                                20, 11, 5, 64, 72, 85, 70, 36, 30, 18, 4, 6, 70,\n                                79, 92, 5, 55, 45, 39, 31, 23, 5, 68, 76, 81,\n                                62, 100, 99, 82, 104, 102, 91, 100, 96, 95, 97,\n                                97, 100, 91, 89, 88, 89, 84, 83, 70, 78, 80, 69,\n                                0, 2, 0, 8, 7, 7, 2, 18, 14, 13, 11, 8, 19, 14,\n                                8, 17, 15, 11, 8, 9, 64, 66, 68, 5, 72, 15, 29,\n                                15, 9, 23, 21, 13, 18, 24, 16, 22, 8, 2, 9, 46,\n                                45, 49, 45, 45, 55, 62, 62, 62, 62, 62, 62, 62,\n                                59, 25, 62, 62, 62, 62, 62, 56, 41, 30, 28, 6,\n                                75, 72, 88, 109, 52, 51, 54, 46, 41, 40, 31, 30,\n                                22, 21, 13, 8, 6, 72, 77, 0, 65, 72, 30, 33, 29,\n                                20, 28, 27, 13, 21, 22, 11, 65, 1, 70, 90, 18,\n                                8, 65, 77, 67, 66, 66, 1, 0, 64, 0, 0, 3, 10, 2,\n                                4, 8, 9, 62, 61, 58, 53, 48, 41, 33, 17, 74, 0,\n                                32, 25, 22, 18, 13, 6, 4, 1, 72, 82, 78, 72, 77,\n                                72, 65, 72, 78, 67, 0, 3, 1, 4, 4, 4, 62, 62,\n                                53, 45, 39, 31, 20, 5, 80 },\n\n                              {\n\n                              62,\n                                8, 75, 62, 8, 75, 113, 92, 13, 10, 9, 19, 50,\n                                53, 54, 14, 99, 4, 71, 4, 1, 8, 71, 5, 73, 16,\n                                49, 80, 98, 108, 104, 94, 67, 71, 4, 1, 83, 86,\n                                5, 14, 67, 78, 90, 5, 70, 83, 89, 5, 74, 89, 7,\n                                71, 79, 88, 0, 71, 72, 77, 68, 5, 22, 0, 0, 0,\n                                78, 88, 97, 68, 16, 0, 18, 76, 94, 112, 84, 88,\n                                8, 68, 84, 75, 99, 80, 93, 86, 112, 88, 86, 92,\n                                101, 19, 64, 7, 88, 72, 87, 83, 114, 7, 0, 1,\n                                72, 16, 68, 67, 84, 84, 75, 74, 73, 8, 11, 66,\n                                13, 18, 79, 0, 68, 67, 5, 75, 23, 66, 2, 23, 29,\n                                33, 28, 21, 88, 69, 72, 11, 10, 96, 6, 9, 8, 3,\n                                7, 7, 7, 6, 2, 4, 66, 4, 17, 10, 74, 65, 2, 67,\n                                10, 16, 17, 9, 10, 6, 5, 4, 19, 17, 13, 77, 3,\n                                73, 30, 22, 18, 14, 17, 18, 11, 16, 22, 0, 14,\n                                9, 8, 4, 65, 9, 3, 7, 8, 5, 13, 20, 6, 81, 5,\n                                76, 10, 21, 83, 44, 55, 46, 45, 47, 47, 42, 42,\n                                38, 29, 23, 20, 25, 15, 78, 67, 2, 71, 25, 22,\n                                19, 23, 20, 14, 11, 12, 68, 0, 68, 93, 88, 103,\n                                73, 20, 18, 11, 1, 5, 68, 73, 78, 93, 72, 38,\n                                21, 15, 8, 7, 67, 77, 81, 104, 5, 36, 28, 25,\n                                19, 11, 5, 64, 72, 85, 70, 36, 30, 18, 4, 6, 70,\n                                79, 91, 5, 54, 44, 38, 30, 22, 5, 68, 76, 81,\n                                62, 99, 98, 82, 103, 101, 91, 99, 95, 94, 96,\n                                96, 99, 91, 89, 88, 88, 83, 83, 71, 78, 80, 69,\n                                0, 1, 0, 7, 6, 5, 1, 17, 14, 13, 11, 7, 18, 13,\n                                7, 16, 14, 10, 8, 8, 65, 67, 68, 5, 73, 14, 28,\n                                14, 9, 22, 20, 13, 17, 23, 16, 22, 7, 1, 7, 45,\n                                44, 48, 43, 44, 54, 62, 62, 62, 62, 62, 62, 62,\n                                56, 24, 62, 62, 62, 62, 61, 54, 39, 28, 26, 6,\n                                75, 72, 87, 107, 50, 49, 52, 44, 38, 38, 29, 28,\n                                20, 19, 12, 6, 5, 73, 78, 64, 66, 73, 29, 32,\n                                27, 18, 26, 25, 12, 19, 20, 10, 66, 64, 72, 91,\n                                17, 7, 66, 77, 67, 66, 65, 1, 0, 0, 0, 1, 4, 11,\n                                3, 5, 9, 10, 61, 59, 56, 51, 45, 38, 30, 14, 77,\n                                0, 32, 25, 22, 18, 13, 6, 4, 1, 72, 82, 78, 72,\n                                77, 71, 64, 72, 78, 66, 1, 3, 1, 4, 4, 3, 62,\n                                61, 51, 42, 36, 27, 16, 2, 83 },\n\n                              {\n\n                              62,\n                                8, 75, 62, 8, 75, 111, 91, 14, 10, 9, 18, 49,\n                                52, 54, 14, 97, 4, 70, 5, 1, 8, 70, 4, 74, 15,\n                                47, 81, 99, 109, 101, 92, 67, 70, 5, 1, 82, 85,\n                                6, 13, 67, 77, 89, 5, 70, 83, 89, 5, 74, 88, 7,\n                                71, 79, 88, 0, 71, 71, 77, 68, 5, 22, 0, 0, 0,\n                                77, 88, 97, 68, 15, 0, 18, 75, 94, 110, 82, 86,\n                                9, 66, 82, 74, 97, 79, 91, 85, 110, 88, 86, 92,\n                                100, 19, 64, 7, 87, 72, 86, 82, 113, 7, 0, 1,\n                                72, 16, 68, 66, 83, 83, 74, 74, 73, 8, 11, 66,\n                                13, 18, 78, 0, 67, 67, 5, 74, 22, 66, 2, 22, 28,\n                                33, 27, 20, 87, 69, 71, 10, 9, 96, 5, 9, 8, 4,\n                                7, 7, 8, 6, 2, 4, 65, 4, 17, 10, 75, 65, 2, 68,\n                                10, 15, 17, 9, 9, 6, 5, 4, 18, 17, 13, 77, 3,\n                                74, 29, 22, 18, 14, 17, 18, 11, 16, 22, 0, 14,\n                                9, 8, 4, 65, 9, 3, 7, 8, 5, 12, 20, 6, 81, 5,\n                                76, 9, 20, 83, 42, 54, 45, 44, 45, 45, 41, 41,\n                                36, 27, 22, 19, 23, 14, 79, 67, 2, 72, 24, 21,\n                                18, 22, 19, 13, 10, 11, 69, 64, 69, 93, 87, 102,\n                                72, 21, 18, 11, 1, 6, 67, 72, 77, 92, 71, 38,\n                                21, 15, 8, 8, 67, 76, 80, 102, 5, 36, 28, 25,\n                                19, 12, 5, 64, 72, 84, 70, 37, 30, 18, 4, 7, 70,\n                                79, 90, 5, 54, 44, 38, 29, 22, 5, 68, 75, 80,\n                                62, 98, 97, 81, 102, 99, 90, 97, 94, 92, 95, 95,\n                                97, 90, 88, 88, 87, 81, 83, 72, 77, 79, 69, 0,\n                                0, 0, 7, 5, 4, 0, 17, 14, 13, 11, 7, 17, 13, 7,\n                                15, 14, 10, 8, 7, 65, 67, 67, 6, 73, 14, 27, 14,\n                                9, 22, 20, 13, 16, 22, 16, 22, 6, 1, 6, 45, 43,\n                                47, 42, 43, 53, 60, 60, 62, 62, 62, 62, 62, 54,\n                                23, 62, 62, 62, 62, 58, 52, 38, 27, 25, 6, 74,\n                                72, 86, 105, 48, 48, 50, 42, 36, 37, 28, 26, 19,\n                                18, 11, 5, 4, 74, 78, 64, 66, 74, 28, 31, 26,\n                                16, 25, 24, 11, 18, 19, 9, 67, 65, 73, 92, 17,\n                                6, 66, 76, 67, 66, 64, 2, 1, 1, 1, 2, 5, 13, 4,\n                                6, 11, 12, 60, 58, 54, 49, 42, 35, 27, 11, 79,\n                                1, 32, 25, 23, 18, 14, 7, 4, 2, 71, 82, 77, 71,\n                                77, 70, 1, 71, 77, 65, 2, 3, 2, 5, 4, 3, 62, 59,\n                                49, 40, 33, 24, 12, 64, 85 },\n\n                              {\n\n                              62,\n                                8, 75, 62, 8, 75, 109, 89, 14, 10, 8, 16, 47,\n                                50, 54, 14, 94, 3, 69, 5, 1, 7, 70, 3, 75, 15,\n                                45, 83, 100, 109, 98, 91, 67, 69, 5, 1, 82, 84,\n                                6, 13, 67, 77, 89, 5, 71, 82, 89, 5, 74, 87, 6,\n                                71, 79, 88, 1, 70, 71, 76, 67, 5, 22, 0, 0, 0,\n                                77, 88, 97, 67, 14, 0, 18, 75, 94, 109, 80, 85,\n                                11, 64, 81, 73, 96, 77, 90, 84, 108, 87, 85, 91,\n                                99, 19, 64, 7, 87, 72, 86, 82, 111, 6, 0, 1, 72,\n                                16, 68, 66, 83, 83, 74, 74, 72, 8, 10, 66, 13,\n                                18, 78, 0, 67, 67, 5, 74, 22, 66, 2, 22, 27, 32,\n                                26, 19, 86, 68, 71, 9, 9, 95, 5, 9, 7, 4, 7, 7,\n                                9, 7, 2, 4, 65, 4, 16, 10, 76, 65, 2, 68, 9, 14,\n                                16, 9, 9, 7, 5, 4, 17, 16, 12, 77, 3, 74, 29,\n                                22, 18, 14, 17, 18, 11, 16, 22, 0, 14, 9, 8, 4,\n                                65, 9, 3, 6, 8, 5, 12, 19, 5, 81, 4, 76, 8, 19,\n                                83, 41, 52, 43, 42, 43, 43, 39, 39, 34, 25, 20,\n                                17, 20, 12, 80, 67, 1, 72, 23, 20, 17, 21, 17,\n                                11, 9, 10, 69, 64, 69, 93, 87, 102, 72, 21, 18,\n                                11, 1, 6, 67, 72, 77, 91, 71, 38, 21, 15, 8, 8,\n                                66, 75, 80, 100, 5, 36, 28, 25, 19, 12, 5, 64,\n                                72, 83, 70, 37, 29, 17, 4, 7, 70, 79, 90, 5, 53,\n                                43, 37, 28, 22, 5, 68, 75, 80, 62, 97, 96, 80,\n                                100, 98, 89, 96, 92, 91, 93, 93, 95, 89, 87, 87,\n                                87, 80, 82, 72, 77, 78, 69, 64, 0, 64, 6, 4, 3,\n                                64, 16, 13, 13, 10, 6, 17, 13, 7, 14, 13, 10, 7,\n                                6, 65, 67, 67, 6, 73, 13, 27, 13, 9, 21, 19, 13,\n                                15, 21, 15, 21, 5, 0, 4, 44, 43, 47, 41, 41, 51,\n                                58, 58, 62, 62, 62, 62, 62, 52, 21, 59, 62, 59,\n                                62, 56, 49, 36, 26, 24, 6, 73, 71, 85, 103, 47,\n                                46, 48, 41, 34, 35, 26, 24, 18, 16, 9, 3, 2, 75,\n                                79, 65, 66, 75, 26, 29, 24, 15, 23, 22, 9, 16,\n                                17, 7, 68, 66, 74, 92, 16, 6, 67, 76, 66, 65,\n                                64, 2, 2, 2, 2, 3, 6, 14, 5, 7, 12, 13, 60, 56,\n                                52, 46, 40, 32, 24, 8, 81, 1, 33, 26, 23, 19,\n                                15, 7, 5, 2, 71, 81, 77, 70, 76, 69, 2, 71, 76,\n                                65, 2, 3, 2, 6, 4, 3, 62, 57, 46, 37, 30, 20, 8,\n                                68, 88 },\n\n                              {\n\n                              62,\n                                8, 76, 62, 8, 76, 107, 88, 15, 10, 8, 15, 46,\n                                49, 54, 14, 92, 3, 69, 6, 1, 6, 70, 2, 76, 14,\n                                44, 84, 101, 110, 95, 90, 67, 69, 6, 1, 81, 83,\n                                7, 12, 66, 76, 88, 4, 71, 82, 89, 5, 73, 87, 6,\n                                71, 78, 88, 1, 70, 71, 76, 67, 5, 22, 0, 0, 0,\n                                76, 88, 97, 67, 14, 64, 18, 75, 93, 107, 78, 83,\n                                12, 1, 80, 72, 94, 76, 89, 84, 107, 87, 85, 91,\n                                99, 20, 64, 7, 86, 71, 85, 81, 110, 6, 64, 0,\n                                73, 16, 68, 66, 82, 83, 73, 74, 72, 8, 10, 65,\n                                13, 17, 78, 0, 67, 67, 5, 74, 21, 66, 2, 21, 26,\n                                31, 26, 19, 86, 68, 71, 9, 8, 95, 4, 9, 7, 4, 7,\n                                7, 9, 7, 2, 4, 64, 4, 15, 10, 76, 66, 2, 69, 9,\n                                13, 16, 9, 8, 7, 5, 4, 15, 16, 11, 77, 3, 75,\n                                28, 22, 17, 14, 17, 18, 11, 16, 22, 0, 13, 9, 7,\n                                4, 65, 8, 2, 6, 7, 4, 11, 18, 5, 81, 4, 75, 7,\n                                17, 83, 39, 50, 41, 40, 41, 41, 37, 37, 32, 23,\n                                19, 16, 18, 10, 81, 67, 1, 73, 22, 19, 16, 19,\n                                16, 10, 8, 9, 70, 65, 70, 93, 87, 101, 71, 21,\n                                18, 11, 2, 6, 67, 72, 76, 90, 70, 37, 21, 15, 8,\n                                9, 66, 74, 79, 98, 5, 37, 28, 25, 19, 13, 5, 64,\n                                71, 83, 70, 37, 29, 17, 4, 7, 69, 78, 89, 5, 53,\n                                43, 36, 28, 22, 5, 67, 74, 79, 62, 97, 95, 80,\n                                99, 97, 88, 94, 91, 90, 92, 92, 94, 89, 86, 87,\n                                86, 78, 82, 73, 77, 78, 69, 64, 64, 64, 5, 3, 2,\n                                65, 16, 13, 13, 10, 6, 16, 12, 7, 14, 13, 9, 7,\n                                6, 65, 68, 67, 6, 74, 13, 26, 12, 8, 20, 19, 14,\n                                15, 20, 15, 21, 5, 0, 3, 43, 42, 46, 40, 40, 50,\n                                56, 56, 61, 60, 62, 62, 60, 49, 20, 57, 62, 56,\n                                62, 53, 47, 34, 25, 23, 6, 72, 71, 83, 100, 45,\n                                44, 46, 39, 32, 33, 25, 22, 16, 15, 8, 2, 1, 76,\n                                80, 65, 67, 76, 25, 28, 23, 13, 21, 20, 8, 15,\n                                15, 6, 70, 68, 76, 93, 15, 5, 68, 76, 66, 65, 0,\n                                3, 2, 4, 3, 4, 7, 15, 7, 8, 14, 14, 59, 55, 50,\n                                44, 37, 30, 21, 6, 83, 2, 33, 26, 24, 19, 16, 8,\n                                5, 3, 70, 81, 76, 70, 76, 68, 3, 71, 76, 64, 3,\n                                3, 3, 7, 4, 3, 62, 55, 44, 34, 26, 16, 5, 71, 90 },\n\n                              {\n\n                              62,\n                                8, 76, 62, 8, 76, 106, 86, 15, 10, 7, 13, 44,\n                                48, 54, 14, 90, 3, 68, 7, 1, 5, 70, 1, 77, 14,\n                                42, 86, 102, 110, 92, 89, 67, 68, 7, 1, 81, 82,\n                                7, 12, 66, 76, 87, 4, 72, 82, 89, 5, 73, 86, 6,\n                                72, 78, 88, 2, 70, 71, 76, 66, 5, 22, 0, 0, 0,\n                                76, 89, 97, 66, 13, 64, 18, 75, 93, 105, 77, 82,\n                                14, 2, 79, 71, 93, 75, 88, 83, 105, 86, 85, 90,\n                                98, 20, 64, 7, 86, 71, 85, 81, 108, 6, 64, 0,\n                                73, 16, 68, 66, 82, 83, 73, 74, 71, 8, 10, 65,\n                                13, 17, 78, 0, 67, 67, 5, 74, 20, 67, 2, 20, 25,\n                                30, 25, 18, 85, 67, 71, 8, 8, 94, 4, 9, 7, 4, 7,\n                                7, 10, 7, 2, 3, 64, 3, 14, 9, 77, 66, 2, 69, 8,\n                                12, 16, 8, 7, 7, 5, 4, 14, 16, 10, 77, 3, 75,\n                                27, 22, 17, 14, 17, 18, 11, 16, 21, 0, 13, 9, 7,\n                                4, 66, 8, 2, 5, 7, 4, 10, 17, 4, 81, 3, 75, 6,\n                                16, 83, 38, 48, 39, 38, 39, 39, 35, 35, 30, 21,\n                                17, 14, 16, 8, 82, 67, 1, 73, 21, 18, 15, 18,\n                                14, 8, 7, 7, 71, 65, 70, 93, 87, 101, 71, 21,\n                                18, 11, 2, 6, 67, 72, 76, 89, 70, 37, 21, 15, 8,\n                                9, 65, 74, 78, 96, 5, 37, 28, 25, 19, 13, 5, 64,\n                                71, 82, 70, 37, 29, 16, 4, 7, 69, 78, 88, 5, 52,\n                                42, 35, 27, 22, 5, 67, 74, 79, 62, 96, 94, 79,\n                                98, 96, 87, 93, 90, 89, 91, 90, 92, 88, 86, 87,\n                                86, 77, 82, 73, 77, 77, 69, 65, 64, 64, 4, 2, 1,\n                                66, 15, 12, 13, 9, 5, 16, 12, 7, 13, 12, 9, 7,\n                                5, 66, 68, 67, 6, 74, 12, 26, 11, 8, 19, 18, 14,\n                                14, 19, 14, 20, 4, 64, 1, 42, 41, 46, 39, 39,\n                                48, 54, 54, 59, 57, 62, 62, 57, 47, 19, 54, 62,\n                                53, 58, 50, 44, 32, 24, 21, 6, 71, 71, 82, 98,\n                                43, 42, 44, 37, 30, 31, 23, 20, 15, 13, 7, 0,\n                                64, 77, 81, 66, 67, 77, 24, 26, 21, 11, 19, 18,\n                                6, 13, 13, 4, 71, 69, 77, 94, 14, 4, 69, 76, 65,\n                                65, 0, 3, 3, 5, 3, 5, 8, 16, 8, 9, 15, 15, 59,\n                                53, 48, 41, 35, 27, 18, 3, 86, 2, 34, 27, 24,\n                                19, 16, 8, 5, 3, 70, 81, 76, 69, 75, 67, 4, 71,\n                                75, 64, 3, 3, 3, 8, 4, 3, 61, 53, 41, 31, 23,\n                                12, 1, 75, 93 },\n\n                              {\n\n                              62,\n                                8, 76, 62, 8, 76, 104, 85, 15, 10, 7, 12, 43,\n                                46, 54, 14, 87, 2, 67, 7, 1, 5, 69, 0, 78, 13,\n                                40, 88, 103, 111, 89, 87, 67, 67, 7, 1, 81, 81,\n                                7, 11, 66, 76, 87, 4, 72, 81, 89, 5, 73, 85, 5,\n                                72, 78, 88, 2, 69, 70, 75, 66, 5, 22, 0, 0, 0,\n                                75, 89, 97, 66, 12, 64, 18, 74, 93, 104, 75, 80,\n                                15, 4, 77, 70, 92, 73, 87, 82, 103, 86, 84, 90,\n                                97, 20, 64, 7, 85, 71, 84, 80, 107, 5, 64, 0,\n                                73, 16, 68, 65, 81, 83, 73, 74, 71, 8, 9, 65,\n                                13, 17, 77, 0, 66, 67, 5, 74, 20, 67, 2, 20, 24,\n                                30, 24, 17, 84, 67, 71, 7, 7, 94, 3, 9, 6, 4, 7,\n                                7, 11, 8, 2, 3, 64, 3, 13, 9, 78, 66, 2, 70, 8,\n                                11, 15, 8, 7, 8, 5, 4, 13, 15, 9, 77, 3, 76, 27,\n                                22, 17, 14, 17, 18, 11, 16, 21, 0, 13, 9, 7, 4,\n                                66, 8, 2, 5, 7, 4, 10, 16, 4, 81, 3, 75, 5, 15,\n                                83, 36, 46, 38, 37, 37, 37, 33, 33, 28, 19, 15,\n                                12, 13, 7, 83, 67, 0, 74, 20, 17, 14, 17, 13, 7,\n                                6, 6, 71, 66, 71, 93, 87, 100, 71, 21, 18, 11,\n                                2, 6, 66, 71, 75, 88, 69, 37, 21, 15, 8, 9, 65,\n                                73, 78, 94, 5, 37, 28, 25, 19, 13, 5, 64, 71,\n                                81, 70, 38, 28, 16, 4, 7, 69, 78, 88, 5, 52, 41,\n                                34, 26, 22, 5, 67, 74, 78, 62, 95, 93, 78, 96,\n                                95, 86, 92, 88, 88, 89, 89, 90, 87, 85, 86, 85,\n                                76, 81, 74, 76, 76, 69, 65, 65, 65, 4, 1, 0, 67,\n                                14, 12, 13, 9, 5, 15, 12, 7, 12, 11, 9, 6, 4,\n                                66, 68, 67, 6, 74, 11, 25, 11, 8, 18, 17, 14,\n                                13, 18, 14, 20, 3, 65, 64, 41, 41, 45, 38, 37,\n                                47, 52, 52, 57, 55, 62, 61, 54, 45, 17, 51, 62,\n                                50, 54, 48, 42, 30, 23, 20, 6, 70, 70, 81, 96,\n                                42, 41, 42, 36, 28, 29, 22, 18, 14, 11, 5, 65,\n                                65, 78, 82, 66, 67, 78, 22, 25, 19, 10, 18, 17,\n                                5, 12, 12, 3, 72, 70, 78, 94, 14, 4, 70, 75, 65,\n                                64, 1, 4, 4, 6, 4, 6, 9, 18, 9, 10, 16, 17, 58,\n                                51, 46, 39, 32, 24, 15, 0, 88, 2, 34, 27, 25,\n                                20, 17, 8, 6, 4, 69, 80, 76, 68, 75, 66, 5, 70,\n                                74, 0, 4, 3, 4, 9, 4, 3, 59, 51, 39, 28, 20, 9,\n                                66, 78, 96 },\n\n                              {\n\n                              61,\n                                8, 76, 61, 8, 76, 102, 83, 16, 10, 6, 10, 41,\n                                45, 54, 14, 85, 2, 66, 8, 1, 4, 69, 64, 79, 13,\n                                38, 89, 104, 111, 86, 86, 67, 66, 8, 1, 80, 80,\n                                8, 11, 66, 75, 86, 3, 73, 81, 89, 5, 73, 85, 5,\n                                72, 78, 88, 3, 69, 70, 75, 65, 5, 22, 0, 0, 0,\n                                75, 89, 97, 65, 11, 64, 18, 74, 93, 102, 73, 79,\n                                17, 6, 76, 69, 90, 72, 86, 81, 101, 85, 84, 89,\n                                96, 20, 64, 7, 85, 71, 84, 80, 105, 5, 65, 64,\n                                74, 16, 68, 65, 81, 83, 72, 74, 70, 8, 9, 65,\n                                13, 16, 77, 0, 66, 67, 5, 74, 19, 67, 2, 19, 23,\n                                29, 23, 16, 84, 66, 71, 6, 7, 93, 3, 9, 6, 4, 7,\n                                7, 12, 8, 2, 3, 0, 3, 12, 9, 79, 66, 2, 70, 7,\n                                10, 15, 8, 6, 8, 5, 4, 11, 15, 8, 77, 3, 76, 26,\n                                22, 17, 14, 17, 18, 11, 16, 21, 0, 12, 9, 7, 4,\n                                66, 7, 1, 4, 6, 3, 9, 15, 3, 81, 2, 75, 4, 13,\n                                83, 35, 44, 36, 35, 35, 35, 31, 31, 26, 17, 14,\n                                11, 11, 5, 84, 67, 0, 74, 19, 16, 13, 15, 11, 5,\n                                5, 5, 72, 66, 71, 93, 87, 100, 70, 21, 18, 11,\n                                2, 6, 66, 71, 75, 87, 69, 37, 21, 15, 8, 10, 64,\n                                72, 77, 92, 5, 37, 28, 25, 19, 14, 5, 64, 71,\n                                81, 70, 38, 28, 15, 4, 7, 69, 78, 87, 5, 51, 41,\n                                33, 25, 22, 5, 67, 73, 78, 62, 94, 92, 78, 95,\n                                94, 85, 90, 87, 87, 88, 87, 89, 87, 84, 86, 85,\n                                74, 81, 74, 76, 76, 69, 66, 65, 65, 3, 0, 64,\n                                68, 14, 11, 13, 8, 4, 15, 11, 7, 11, 11, 8, 6,\n                                3, 66, 69, 67, 6, 75, 11, 25, 10, 8, 17, 17, 14,\n                                12, 17, 13, 19, 2, 65, 65, 40, 40, 45, 37, 36,\n                                45, 50, 50, 55, 52, 60, 59, 51, 42, 16, 48, 62,\n                                47, 50, 45, 39, 28, 22, 19, 6, 69, 70, 80, 94,\n                                40, 39, 40, 34, 26, 27, 20, 16, 12, 10, 4, 66,\n                                67, 79, 83, 67, 68, 79, 21, 23, 18, 8, 16, 15,\n                                3, 10, 10, 1, 73, 72, 80, 95, 13, 3, 71, 75, 64,\n                                64, 1, 4, 4, 7, 5, 7, 10, 19, 10, 11, 18, 18,\n                                58, 50, 44, 36, 30, 21, 12, 66, 90, 3, 35, 28,\n                                25, 20, 18, 9, 6, 4, 69, 80, 75, 68, 74, 65, 6,\n                                70, 74, 0, 4, 3, 4, 10, 4, 3, 58, 49, 36, 25,\n                                17, 5, 70, 82, 98 },\n\n                              {\n\n                              60,\n                                8, 76, 60, 8, 76, 100, 82, 16, 10, 6, 9, 40, 44,\n                                54, 14, 83, 2, 65, 9, 1, 3, 69, 65, 80, 12, 36,\n                                91, 105, 112, 83, 85, 67, 65, 9, 1, 80, 79, 8,\n                                10, 66, 75, 85, 3, 73, 81, 89, 5, 73, 84, 5, 72,\n                                78, 88, 3, 69, 70, 75, 65, 5, 22, 0, 0, 0, 74,\n                                89, 97, 65, 10, 64, 18, 74, 93, 100, 71, 77, 18,\n                                8, 75, 68, 89, 71, 85, 80, 99, 85, 84, 89, 95,\n                                20, 64, 7, 84, 71, 83, 79, 104, 5, 65, 64, 74,\n                                16, 68, 65, 80, 83, 72, 74, 70, 8, 9, 65, 13,\n                                16, 77, 0, 66, 67, 5, 74, 18, 67, 2, 18, 22, 28,\n                                22, 15, 83, 66, 71, 5, 6, 93, 2, 9, 6, 4, 7, 7,\n                                13, 8, 2, 3, 0, 3, 11, 9, 80, 66, 2, 71, 7, 9,\n                                15, 8, 5, 8, 5, 4, 10, 15, 7, 77, 3, 77, 25, 22,\n                                17, 14, 17, 18, 11, 16, 21, 0, 12, 9, 7, 4, 66,\n                                7, 1, 4, 6, 3, 8, 14, 3, 81, 2, 75, 3, 12, 83,\n                                33, 42, 34, 33, 33, 33, 29, 29, 24, 15, 12, 9,\n                                9, 3, 85, 67, 0, 75, 18, 15, 12, 14, 10, 4, 4,\n                                4, 73, 67, 72, 93, 87, 99, 70, 21, 18, 11, 2, 6,\n                                66, 71, 74, 86, 68, 37, 21, 15, 8, 10, 64, 71,\n                                76, 90, 5, 37, 28, 25, 19, 14, 5, 64, 71, 80,\n                                70, 38, 28, 15, 4, 7, 69, 78, 86, 5, 51, 40, 32,\n                                24, 22, 5, 67, 73, 77, 62, 93, 91, 77, 94, 93,\n                                84, 89, 86, 86, 87, 86, 87, 86, 83, 86, 84, 73,\n                                81, 75, 76, 75, 69, 66, 66, 65, 2, 64, 65, 69,\n                                13, 11, 13, 8, 4, 14, 11, 7, 10, 10, 8, 6, 2,\n                                66, 69, 67, 6, 75, 10, 24, 9, 8, 16, 16, 14, 11,\n                                16, 13, 19, 1, 66, 67, 39, 39, 44, 36, 35, 44,\n                                48, 48, 53, 50, 57, 56, 48, 40, 15, 45, 59, 44,\n                                46, 42, 37, 26, 21, 18, 6, 68, 70, 79, 92, 38,\n                                37, 38, 32, 24, 25, 19, 14, 11, 8, 3, 68, 68,\n                                80, 84, 67, 68, 80, 20, 22, 16, 6, 14, 13, 2, 9,\n                                8, 0, 74, 73, 81, 96, 12, 2, 72, 75, 64, 64, 2,\n                                5, 5, 8, 6, 8, 11, 20, 11, 12, 19, 19, 57, 48,\n                                42, 34, 27, 18, 9, 69, 92, 3, 35, 28, 26, 20,\n                                19, 9, 6, 5, 68, 80, 75, 67, 74, 64, 7, 70, 73,\n                                1, 5, 3, 5, 11, 4, 3, 57, 47, 34, 22, 14, 1, 74,\n                                85, 101 },\n\n                              {\n\n                              58,\n                                7, 77, 58, 7, 77, 99, 81, 16, 10, 5, 7, 38, 42,\n                                53, 14, 81, 1, 65, 9, 0, 2, 69, 67, 82, 11, 34,\n                                93, 106, 113, 81, 84, 68, 65, 9, 0, 80, 78, 8,\n                                9, 66, 75, 85, 2, 74, 81, 90, 5, 73, 84, 4, 73,\n                                78, 88, 3, 69, 70, 75, 65, 4, 22, 0, 0, 0, 74,\n                                90, 97, 65, 9, 65, 18, 74, 93, 99, 70, 76, 19,\n                                9, 74, 67, 88, 70, 84, 80, 98, 85, 84, 89, 95,\n                                20, 64, 7, 84, 71, 83, 79, 103, 4, 66, 65, 75,\n                                16, 68, 65, 80, 83, 72, 74, 70, 7, 8, 65, 12,\n                                15, 77, 64, 66, 67, 4, 74, 17, 68, 1, 17, 20,\n                                27, 21, 14, 83, 66, 71, 4, 5, 93, 1, 8, 5, 4, 7,\n                                7, 13, 8, 2, 2, 0, 2, 10, 8, 81, 67, 1, 72, 6,\n                                8, 14, 7, 4, 8, 5, 4, 8, 14, 6, 77, 3, 78, 24,\n                                21, 16, 14, 17, 17, 10, 16, 20, 64, 11, 9, 6, 3,\n                                67, 6, 0, 3, 5, 2, 7, 13, 2, 81, 1, 75, 2, 10,\n                                83, 31, 40, 32, 31, 31, 30, 27, 27, 22, 13, 10,\n                                7, 6, 1, 87, 68, 64, 76, 17, 13, 10, 12, 8, 2,\n                                2, 2, 74, 68, 73, 93, 87, 99, 70, 21, 18, 11, 2,\n                                6, 66, 71, 74, 85, 68, 36, 21, 15, 8, 10, 64,\n                                71, 76, 89, 4, 37, 28, 24, 18, 14, 5, 64, 71,\n                                80, 70, 38, 27, 14, 3, 7, 69, 78, 86, 5, 50, 39,\n                                31, 23, 21, 5, 67, 73, 77, 62, 93, 90, 77, 93,\n                                92, 84, 88, 85, 85, 86, 85, 86, 86, 83, 86, 84,\n                                72, 81, 76, 76, 75, 69, 67, 67, 66, 1, 65, 67,\n                                71, 12, 10, 13, 7, 3, 13, 10, 6, 9, 9, 7, 5, 1,\n                                67, 70, 67, 6, 76, 9, 23, 8, 7, 15, 15, 14, 10,\n                                14, 12, 18, 0, 67, 69, 38, 38, 43, 34, 33, 42,\n                                46, 46, 50, 47, 54, 53, 45, 37, 13, 42, 55, 41,\n                                41, 39, 34, 24, 19, 16, 6, 68, 70, 78, 90, 36,\n                                35, 36, 30, 21, 23, 17, 11, 9, 6, 1, 70, 70, 81,\n                                85, 68, 69, 82, 18, 20, 14, 4, 12, 11, 0, 7, 6,\n                                65, 76, 75, 83, 97, 11, 1, 73, 75, 64, 64, 2, 5,\n                                5, 9, 6, 9, 11, 21, 12, 13, 20, 20, 56, 46, 39,\n                                31, 24, 15, 5, 72, 95, 3, 35, 28, 26, 20, 19, 9,\n                                6, 5, 68, 80, 75, 67, 74, 0, 8, 70, 73, 1, 5, 3,\n                                5, 11, 4, 2, 55, 44, 31, 19, 10, 66, 78, 89, 104 },\n\n                              {\n\n                              57,\n                                7, 77, 57, 7, 77, 97, 79, 17, 11, 5, 6, 37, 41,\n                                53, 14, 78, 1, 64, 10, 0, 2, 68, 68, 83, 11, 33,\n                                94, 107, 113, 78, 82, 68, 64, 10, 0, 79, 76, 9,\n                                9, 65, 74, 84, 2, 74, 80, 90, 5, 72, 83, 4, 73,\n                                77, 88, 4, 68, 69, 74, 64, 4, 22, 0, 0, 0, 73,\n                                90, 97, 64, 9, 65, 18, 73, 92, 97, 68, 74, 21,\n                                11, 72, 66, 86, 68, 82, 79, 96, 84, 83, 88, 94,\n                                21, 0, 8, 83, 70, 82, 78, 101, 4, 66, 65, 75,\n                                17, 68, 64, 79, 82, 71, 73, 69, 7, 8, 64, 12,\n                                15, 76, 64, 65, 67, 4, 73, 17, 68, 1, 17, 19,\n                                27, 21, 14, 82, 65, 70, 4, 5, 92, 1, 8, 5, 5, 7,\n                                7, 14, 9, 3, 2, 1, 2, 10, 8, 81, 67, 1, 72, 6,\n                                7, 14, 7, 4, 9, 6, 4, 7, 14, 6, 76, 3, 78, 24,\n                                21, 16, 14, 17, 17, 10, 16, 20, 64, 11, 9, 6, 3,\n                                67, 6, 0, 3, 5, 2, 7, 13, 2, 80, 1, 74, 2, 9,\n                                82, 30, 39, 31, 30, 29, 28, 26, 26, 20, 12, 9,\n                                6, 4, 0, 88, 68, 64, 76, 16, 12, 9, 11, 7, 1, 1,\n                                1, 74, 68, 73, 92, 86, 98, 69, 22, 18, 11, 3, 7,\n                                65, 70, 73, 83, 67, 36, 21, 15, 8, 11, 0, 70,\n                                75, 87, 4, 38, 29, 24, 18, 15, 5, 64, 70, 79,\n                                70, 39, 27, 14, 3, 8, 68, 77, 85, 5, 50, 39, 31,\n                                23, 21, 5, 66, 72, 76, 62, 92, 89, 76, 91, 90,\n                                83, 86, 83, 83, 84, 83, 84, 85, 82, 85, 83, 70,\n                                80, 76, 75, 74, 68, 67, 67, 66, 1, 65, 68, 72,\n                                12, 10, 14, 7, 3, 13, 10, 6, 9, 9, 7, 5, 1, 67,\n                                70, 66, 7, 76, 9, 23, 8, 7, 15, 15, 15, 10, 13,\n                                12, 18, 0, 67, 70, 38, 38, 43, 33, 32, 41, 44,\n                                44, 48, 45, 52, 51, 43, 35, 12, 40, 52, 38, 37,\n                                37, 32, 23, 18, 15, 6, 67, 69, 76, 87, 35, 34,\n                                35, 29, 19, 22, 16, 9, 8, 5, 0, 71, 71, 82, 85,\n                                68, 69, 83, 17, 19, 13, 3, 11, 10, 64, 6, 5, 66,\n                                77, 76, 84, 97, 11, 1, 73, 74, 0, 0, 3, 6, 6,\n                                11, 7, 10, 12, 23, 14, 14, 22, 22, 56, 45, 37,\n                                29, 22, 13, 2, 74, 97, 4, 36, 29, 27, 21, 20,\n                                10, 7, 6, 67, 79, 74, 66, 73, 2, 10, 69, 72, 2,\n                                6, 4, 6, 12, 4, 2, 54, 42, 29, 17, 7, 69, 81,\n                                92, 106 },\n\n                              {\n\n                              56,\n                                7, 77, 56, 7, 77, 95, 78, 17, 11, 5, 5, 36, 40,\n                                53, 14, 76, 1, 0, 11, 0, 1, 68, 69, 84, 10, 31,\n                                96, 108, 114, 75, 81, 68, 0, 11, 0, 79, 75, 9,\n                                8, 65, 74, 83, 2, 74, 80, 90, 5, 72, 82, 4, 73,\n                                77, 88, 4, 68, 69, 74, 64, 4, 22, 0, 0, 0, 72,\n                                90, 97, 64, 8, 65, 18, 73, 92, 95, 66, 72, 22,\n                                13, 71, 65, 85, 67, 81, 78, 94, 84, 83, 88, 93,\n                                21, 0, 8, 82, 70, 81, 78, 100, 4, 66, 65, 75,\n                                17, 68, 64, 79, 82, 71, 73, 69, 7, 8, 64, 12,\n                                15, 76, 64, 65, 67, 4, 73, 16, 68, 1, 16, 18,\n                                26, 20, 13, 81, 65, 70, 3, 4, 92, 0, 8, 5, 5, 7,\n                                7, 15, 9, 3, 2, 1, 2, 9, 8, 82, 67, 1, 73, 6, 6,\n                                14, 7, 3, 9, 6, 4, 6, 14, 5, 76, 3, 79, 23, 21,\n                                16, 14, 17, 17, 10, 16, 20, 64, 11, 9, 6, 3, 67,\n                                6, 0, 3, 5, 2, 6, 12, 1, 80, 1, 74, 1, 8, 82,\n                                28, 37, 29, 28, 27, 26, 24, 24, 18, 10, 7, 4, 2,\n                                65, 89, 68, 64, 77, 15, 11, 8, 10, 5, 0, 0, 0,\n                                75, 69, 74, 92, 86, 97, 69, 22, 18, 11, 3, 7,\n                                65, 70, 73, 82, 66, 36, 21, 15, 8, 11, 0, 69,\n                                74, 85, 4, 38, 29, 24, 18, 15, 5, 64, 70, 78,\n                                70, 39, 27, 14, 3, 8, 68, 77, 84, 5, 49, 38, 30,\n                                22, 21, 5, 66, 72, 76, 62, 91, 88, 75, 90, 89,\n                                82, 85, 82, 82, 83, 82, 82, 84, 81, 85, 82, 69,\n                                80, 77, 75, 73, 68, 67, 68, 66, 0, 66, 69, 73,\n                                11, 10, 14, 7, 2, 12, 10, 6, 8, 8, 7, 5, 0, 67,\n                                70, 66, 7, 76, 8, 22, 7, 7, 14, 14, 15, 9, 12,\n                                12, 18, 64, 68, 72, 37, 37, 42, 32, 31, 40, 42,\n                                42, 46, 43, 49, 48, 40, 33, 11, 37, 49, 35, 33,\n                                34, 30, 21, 17, 14, 6, 66, 69, 75, 85, 33, 32,\n                                33, 27, 17, 20, 14, 7, 7, 3, 64, 73, 72, 83, 86,\n                                69, 69, 84, 16, 18, 11, 1, 9, 8, 65, 4, 3, 67,\n                                78, 77, 85, 98, 10, 0, 74, 74, 0, 0, 4, 6, 7,\n                                12, 8, 11, 13, 24, 15, 15, 23, 23, 55, 43, 35,\n                                27, 19, 10, 64, 77, 99, 4, 36, 29, 27, 21, 21,\n                                10, 7, 6, 67, 79, 74, 65, 73, 3, 11, 69, 71, 3,\n                                7, 4, 6, 13, 4, 2, 53, 40, 27, 14, 4, 73, 85,\n                                95, 109 },\n\n                              {\n\n                              55,\n                                7, 77, 55, 7, 77, 93, 76, 18, 11, 4, 3, 34, 39,\n                                53, 14, 74, 1, 1, 12, 0, 0, 68, 70, 85, 10, 29,\n                                97, 109, 114, 72, 80, 68, 1, 12, 0, 78, 74, 10,\n                                8, 65, 73, 82, 1, 75, 80, 90, 5, 72, 82, 4, 73,\n                                77, 88, 5, 68, 69, 74, 0, 4, 22, 0, 0, 0, 72,\n                                90, 97, 0, 7, 65, 18, 73, 92, 93, 64, 71, 24,\n                                15, 70, 64, 83, 66, 80, 77, 92, 83, 83, 87, 92,\n                                21, 0, 8, 82, 70, 81, 77, 98, 4, 67, 66, 76, 17,\n                                68, 64, 78, 82, 70, 73, 68, 7, 8, 64, 12, 14,\n                                76, 64, 65, 67, 4, 73, 15, 68, 1, 15, 17, 25,\n                                19, 12, 81, 64, 70, 2, 4, 91, 0, 8, 5, 5, 7, 7,\n                                16, 9, 3, 2, 2, 2, 8, 8, 83, 67, 1, 73, 5, 5,\n                                14, 7, 2, 9, 6, 4, 4, 14, 4, 76, 3, 79, 22, 21,\n                                16, 14, 17, 17, 10, 16, 20, 64, 10, 9, 6, 3, 67,\n                                5, 64, 2, 4, 1, 5, 11, 1, 80, 0, 74, 0, 6, 82,\n                                27, 35, 27, 26, 25, 24, 22, 22, 16, 8, 6, 3, 0,\n                                67, 90, 68, 64, 77, 14, 10, 7, 8, 4, 65, 64, 64,\n                                76, 69, 74, 92, 86, 97, 68, 22, 18, 11, 3, 7,\n                                65, 70, 72, 81, 66, 36, 21, 15, 8, 12, 1, 68,\n                                73, 83, 4, 38, 29, 24, 18, 16, 5, 64, 70, 78,\n                                70, 39, 27, 13, 3, 8, 68, 77, 83, 5, 49, 38, 29,\n                                21, 21, 5, 66, 71, 75, 62, 90, 87, 75, 89, 88,\n                                81, 83, 81, 81, 82, 80, 81, 84, 80, 85, 82, 67,\n                                80, 77, 75, 73, 68, 68, 68, 66, 64, 67, 70, 74,\n                                11, 9, 14, 6, 2, 12, 9, 6, 7, 8, 6, 5, 64, 67,\n                                71, 66, 7, 77, 8, 22, 6, 7, 13, 14, 15, 8, 11,\n                                11, 17, 65, 68, 73, 36, 36, 42, 31, 30, 38, 40,\n                                40, 44, 40, 47, 46, 37, 30, 10, 34, 46, 32, 29,\n                                31, 27, 19, 16, 13, 6, 65, 69, 74, 83, 31, 30,\n                                31, 25, 15, 18, 13, 5, 5, 2, 65, 74, 74, 84, 87,\n                                69, 70, 85, 15, 16, 10, 64, 7, 6, 67, 3, 1, 69,\n                                79, 79, 87, 99, 9, 64, 75, 74, 1, 0, 4, 7, 7,\n                                13, 9, 12, 14, 25, 16, 16, 25, 24, 55, 42, 33,\n                                24, 17, 7, 67, 80, 101, 5, 37, 30, 28, 21, 22,\n                                11, 7, 7, 66, 79, 73, 65, 72, 4, 12, 69, 71, 3,\n                                7, 4, 7, 14, 4, 2, 52, 38, 24, 11, 1, 77, 89,\n                                99, 111 },\n\n                              {\n\n                              53,\n                                7, 77, 53, 7, 77, 92, 75, 18, 11, 4, 2, 33, 37,\n                                53, 14, 71, 0, 2, 12, 0, 64, 68, 71, 86, 9, 27,\n                                99, 110, 115, 69, 79, 68, 2, 12, 0, 78, 73, 10,\n                                7, 65, 73, 82, 1, 75, 79, 90, 5, 72, 81, 3, 74,\n                                77, 88, 5, 67, 69, 73, 0, 4, 22, 0, 0, 0, 71,\n                                91, 97, 0, 6, 65, 18, 73, 92, 92, 0, 69, 25, 16,\n                                69, 0, 82, 64, 79, 76, 90, 83, 82, 87, 91, 21,\n                                0, 8, 81, 70, 80, 77, 97, 3, 67, 66, 76, 17, 68,\n                                64, 78, 82, 70, 73, 68, 7, 7, 64, 12, 14, 76,\n                                64, 65, 67, 4, 73, 15, 69, 1, 15, 16, 24, 18,\n                                11, 80, 64, 70, 1, 3, 91, 64, 8, 4, 5, 7, 7, 17,\n                                10, 3, 1, 2, 1, 7, 7, 84, 67, 1, 74, 5, 4, 13,\n                                6, 2, 10, 6, 4, 3, 13, 3, 76, 3, 80, 22, 21, 16,\n                                14, 17, 17, 10, 16, 19, 64, 10, 9, 6, 3, 68, 5,\n                                64, 2, 4, 1, 5, 10, 0, 80, 0, 74, 64, 5, 82, 25,\n                                33, 25, 24, 23, 22, 20, 20, 14, 6, 4, 1, 66, 69,\n                                91, 68, 65, 78, 13, 9, 6, 7, 2, 66, 65, 66, 76,\n                                70, 75, 92, 86, 96, 68, 22, 18, 11, 3, 7, 65,\n                                70, 72, 80, 65, 36, 21, 15, 8, 12, 1, 68, 73,\n                                81, 4, 38, 29, 24, 18, 16, 5, 64, 70, 77, 70,\n                                39, 26, 13, 3, 8, 68, 77, 83, 5, 48, 37, 28, 20,\n                                21, 5, 66, 71, 75, 62, 89, 86, 74, 87, 87, 80,\n                                82, 79, 80, 80, 79, 79, 83, 80, 84, 81, 66, 79,\n                                78, 75, 72, 68, 68, 69, 67, 65, 68, 71, 75, 10,\n                                9, 14, 6, 1, 11, 9, 6, 6, 7, 6, 4, 65, 68, 71,\n                                66, 7, 77, 7, 21, 5, 7, 12, 13, 15, 7, 10, 11,\n                                17, 66, 69, 75, 35, 36, 41, 30, 28, 37, 38, 38,\n                                42, 38, 44, 43, 34, 28, 8, 31, 42, 29, 25, 29,\n                                25, 17, 15, 11, 6, 64, 68, 73, 81, 30, 28, 29,\n                                24, 13, 16, 11, 3, 4, 0, 67, 76, 75, 85, 88, 70,\n                                70, 86, 13, 15, 8, 65, 5, 4, 68, 1, 64, 70, 80,\n                                80, 88, 99, 8, 64, 76, 74, 1, 1, 5, 7, 8, 14, 9,\n                                13, 15, 26, 17, 17, 26, 25, 54, 40, 31, 22, 14,\n                                4, 70, 83, 104, 5, 37, 30, 28, 22, 22, 11, 8, 7,\n                                66, 78, 73, 64, 72, 5, 13, 69, 70, 4, 8, 4, 7,\n                                15, 4, 2, 50, 36, 22, 8, 65, 81, 93, 102, 114 },\n\n                              {\n\n                              52,\n                                7, 77, 52, 7, 77, 90, 73, 18, 11, 3, 0, 31, 36,\n                                53, 14, 69, 0, 3, 13, 0, 64, 67, 72, 87, 9, 25,\n                                101, 111, 115, 66, 77, 68, 3, 13, 0, 78, 72, 10,\n                                7, 65, 73, 81, 1, 76, 79, 90, 5, 72, 80, 3, 74,\n                                77, 88, 6, 67, 68, 73, 1, 4, 22, 0, 0, 0, 71,\n                                91, 97, 1, 5, 65, 18, 72, 92, 90, 2, 68, 27, 18,\n                                67, 1, 81, 0, 78, 75, 88, 82, 82, 86, 90, 21, 0,\n                                8, 81, 70, 80, 76, 95, 3, 67, 66, 76, 17, 68, 0,\n                                77, 82, 70, 73, 67, 7, 7, 64, 12, 14, 75, 64,\n                                64, 67, 4, 73, 14, 69, 1, 14, 15, 24, 17, 10,\n                                79, 0, 70, 0, 3, 90, 64, 8, 4, 5, 7, 7, 18, 10,\n                                3, 1, 2, 1, 6, 7, 85, 67, 1, 74, 4, 3, 13, 6, 1,\n                                10, 6, 4, 2, 13, 2, 76, 3, 80, 21, 21, 16, 14,\n                                17, 17, 10, 16, 19, 64, 10, 9, 6, 3, 68, 5, 64,\n                                1, 4, 1, 4, 9, 0, 80, 64, 74, 65, 4, 82, 24, 31,\n                                24, 23, 21, 20, 18, 18, 12, 4, 2, 64, 68, 70,\n                                92, 68, 65, 78, 12, 8, 5, 6, 1, 68, 66, 67, 77,\n                                70, 75, 92, 86, 96, 68, 22, 18, 11, 3, 7, 64,\n                                69, 71, 79, 65, 36, 21, 15, 8, 12, 2, 67, 72,\n                                79, 4, 38, 29, 24, 18, 16, 5, 64, 70, 76, 70,\n                                40, 26, 12, 3, 8, 68, 77, 82, 5, 48, 36, 27, 19,\n                                21, 5, 66, 71, 74, 62, 88, 85, 73, 86, 86, 79,\n                                81, 78, 79, 79, 77, 77, 82, 79, 84, 81, 65, 79,\n                                78, 74, 71, 68, 69, 69, 67, 65, 69, 72, 76, 9,\n                                8, 14, 5, 1, 11, 9, 6, 5, 6, 6, 4, 66, 68, 71,\n                                66, 7, 77, 6, 21, 5, 7, 11, 12, 15, 6, 9, 10,\n                                16, 67, 70, 77, 34, 35, 41, 29, 27, 35, 36, 36,\n                                40, 35, 41, 41, 31, 26, 7, 28, 39, 26, 21, 26,\n                                22, 15, 14, 10, 6, 0, 68, 72, 79, 28, 27, 27,\n                                22, 11, 14, 10, 1, 3, 65, 68, 78, 77, 86, 89,\n                                70, 70, 87, 12, 13, 6, 67, 4, 3, 70, 0, 65, 72,\n                                81, 81, 89, 100, 8, 65, 77, 73, 2, 1, 5, 8, 9,\n                                15, 10, 14, 16, 28, 18, 18, 27, 27, 54, 38, 29,\n                                19, 12, 1, 73, 86, 106, 5, 38, 31, 29, 22, 23,\n                                11, 8, 8, 65, 78, 73, 0, 71, 6, 14, 68, 69, 4,\n                                8, 4, 8, 16, 4, 2, 49, 34, 19, 5, 68, 84, 97,\n                                106, 117 },\n\n                              {\n\n                              51,\n                                7, 78, 51, 7, 78, 88, 72, 19, 11, 3, 64, 30, 35,\n                                53, 14, 67, 0, 3, 14, 0, 65, 67, 73, 88, 8, 24,\n                                102, 112, 116, 0, 76, 68, 3, 14, 0, 77, 71, 11,\n                                6, 64, 72, 80, 0, 76, 79, 90, 5, 71, 80, 3, 74,\n                                76, 88, 6, 67, 68, 73, 1, 4, 22, 0, 0, 0, 70,\n                                91, 97, 1, 5, 66, 18, 72, 91, 88, 4, 66, 28, 20,\n                                66, 2, 79, 1, 77, 75, 87, 82, 82, 86, 90, 22, 0,\n                                8, 80, 69, 79, 76, 94, 3, 68, 67, 77, 17, 68, 0,\n                                77, 82, 69, 73, 67, 7, 7, 0, 12, 13, 75, 64, 64,\n                                67, 4, 73, 13, 69, 1, 13, 14, 23, 17, 10, 79, 0,\n                                70, 0, 2, 90, 65, 8, 4, 5, 7, 7, 18, 10, 3, 1,\n                                3, 1, 5, 7, 85, 68, 1, 75, 4, 2, 13, 6, 0, 10,\n                                6, 4, 0, 13, 1, 76, 3, 81, 20, 21, 15, 14, 17,\n                                17, 10, 16, 19, 64, 9, 9, 5, 3, 68, 4, 65, 1, 3,\n                                0, 3, 8, 64, 80, 64, 73, 66, 2, 82, 22, 29, 22,\n                                21, 19, 18, 16, 16, 10, 2, 1, 65, 70, 72, 93,\n                                68, 65, 79, 11, 7, 4, 4, 64, 69, 67, 68, 78, 71,\n                                76, 92, 86, 95, 67, 22, 18, 11, 4, 7, 64, 69,\n                                71, 78, 64, 35, 21, 15, 8, 13, 2, 66, 71, 77, 4,\n                                39, 29, 24, 18, 17, 5, 64, 69, 76, 70, 40, 26,\n                                12, 3, 8, 67, 76, 81, 5, 47, 36, 26, 19, 21, 5,\n                                65, 70, 74, 62, 88, 84, 73, 85, 85, 78, 79, 77,\n                                78, 78, 76, 76, 82, 78, 84, 80, 0, 79, 79, 74,\n                                71, 68, 69, 70, 67, 66, 70, 73, 77, 9, 8, 14, 5,\n                                0, 10, 8, 6, 5, 6, 5, 4, 66, 68, 72, 66, 7, 78,\n                                6, 20, 4, 6, 10, 12, 16, 6, 8, 10, 16, 67, 70,\n                                78, 33, 34, 40, 28, 26, 34, 34, 34, 38, 33, 39,\n                                38, 28, 23, 6, 26, 36, 23, 17, 23, 20, 13, 13,\n                                9, 6, 1, 68, 70, 76, 26, 25, 25, 20, 9, 12, 8,\n                                64, 1, 66, 69, 79, 78, 87, 90, 71, 71, 88, 11,\n                                12, 5, 69, 2, 1, 71, 65, 67, 73, 83, 83, 91,\n                                101, 7, 66, 78, 73, 2, 1, 6, 8, 9, 17, 11, 15,\n                                17, 29, 20, 19, 29, 28, 53, 37, 27, 17, 9, 64,\n                                76, 88, 108, 6, 38, 31, 29, 22, 24, 12, 8, 8,\n                                65, 78, 72, 0, 71, 7, 15, 68, 69, 5, 9, 4, 8,\n                                17, 4, 2, 48, 32, 17, 2, 72, 88, 100, 109, 119 },\n\n                              {\n\n                              50,\n                                7, 78, 50, 7, 78, 86, 70, 19, 11, 2, 66, 28, 33,\n                                53, 14, 64, 64, 4, 14, 0, 66, 67, 74, 89, 8, 22,\n                                104, 113, 116, 3, 75, 68, 4, 14, 0, 77, 70, 11,\n                                6, 64, 72, 80, 0, 77, 78, 90, 5, 71, 79, 2, 74,\n                                76, 88, 7, 66, 68, 72, 2, 4, 22, 0, 0, 0, 70,\n                                91, 97, 2, 4, 66, 18, 72, 91, 87, 6, 65, 30, 22,\n                                65, 3, 78, 3, 76, 74, 85, 81, 81, 85, 89, 22, 0,\n                                8, 80, 69, 79, 75, 92, 2, 68, 67, 77, 17, 68, 0,\n                                76, 82, 69, 73, 66, 7, 6, 0, 12, 13, 75, 64, 64,\n                                67, 4, 73, 13, 69, 1, 13, 13, 22, 16, 9, 78, 1,\n                                70, 64, 2, 89, 65, 8, 3, 5, 7, 7, 19, 11, 3, 1,\n                                3, 1, 4, 7, 86, 68, 1, 75, 3, 1, 12, 6, 0, 11,\n                                6, 4, 64, 12, 0, 76, 3, 81, 20, 21, 15, 14, 17,\n                                17, 10, 16, 19, 64, 9, 9, 5, 3, 68, 4, 65, 0, 3,\n                                0, 3, 7, 64, 80, 65, 73, 67, 1, 82, 21, 27, 20,\n                                19, 17, 16, 14, 14, 8, 0, 64, 67, 73, 74, 94,\n                                68, 66, 79, 10, 6, 3, 3, 65, 71, 68, 69, 78, 71,\n                                76, 92, 86, 95, 67, 22, 18, 11, 4, 7, 64, 69,\n                                70, 77, 64, 35, 21, 15, 8, 13, 3, 65, 71, 75, 4,\n                                39, 29, 24, 18, 17, 5, 64, 69, 75, 70, 40, 25,\n                                11, 3, 8, 67, 76, 81, 5, 47, 35, 25, 18, 21, 5,\n                                65, 70, 73, 62, 87, 83, 72, 83, 84, 77, 78, 75,\n                                77, 76, 74, 74, 81, 77, 83, 80, 1, 78, 79, 74,\n                                70, 68, 70, 70, 68, 67, 71, 74, 78, 8, 7, 14, 4,\n                                0, 10, 8, 6, 4, 5, 5, 3, 67, 68, 72, 66, 7, 78,\n                                5, 20, 3, 6, 9, 11, 16, 5, 7, 9, 15, 68, 71, 80,\n                                32, 34, 40, 27, 24, 32, 32, 32, 36, 30, 36, 36,\n                                25, 21, 4, 23, 32, 20, 13, 21, 17, 11, 12, 8, 6,\n                                2, 67, 69, 74, 25, 23, 23, 19, 7, 10, 7, 66, 0,\n                                68, 71, 81, 80, 88, 91, 71, 71, 89, 9, 10, 3,\n                                70, 0, 64, 73, 66, 69, 75, 84, 84, 92, 101, 6,\n                                66, 79, 73, 3, 2, 6, 9, 10, 18, 12, 16, 18, 30,\n                                21, 20, 30, 29, 53, 35, 25, 14, 7, 67, 79, 91,\n                                110, 6, 39, 32, 30, 23, 25, 12, 9, 9, 64, 77,\n                                72, 1, 70, 8, 16, 68, 68, 5, 9, 4, 9, 18, 4, 2,\n                                46, 30, 14, 64, 75, 92, 104, 113, 122 },\n\n                              {\n\n                              48,\n                                6, 78, 48, 6, 78, 85, 69, 19, 11, 2, 67, 27, 32,\n                                53, 14, 1, 64, 5, 15, 0, 67, 67, 75, 91, 7, 20,\n                                106, 114, 117, 5, 74, 68, 5, 15, 0, 77, 69, 11,\n                                5, 64, 72, 79, 64, 77, 78, 91, 5, 71, 79, 2, 75,\n                                76, 88, 7, 66, 68, 72, 2, 4, 22, 0, 0, 0, 69,\n                                92, 97, 2, 3, 66, 18, 72, 91, 85, 7, 0, 31, 23,\n                                64, 4, 77, 4, 75, 73, 83, 81, 81, 85, 88, 22, 0,\n                                8, 79, 69, 78, 75, 91, 2, 69, 68, 78, 17, 68, 0,\n                                76, 82, 69, 73, 66, 6, 6, 0, 12, 12, 75, 64, 64,\n                                67, 3, 73, 12, 70, 1, 12, 11, 21, 15, 8, 78, 1,\n                                70, 65, 1, 89, 66, 7, 3, 5, 7, 7, 20, 11, 3, 0,\n                                3, 0, 3, 6, 87, 68, 1, 76, 3, 0, 12, 5, 64, 11,\n                                6, 4, 66, 12, 64, 76, 3, 82, 19, 20, 15, 14, 17,\n                                16, 9, 16, 18, 65, 8, 9, 5, 2, 69, 3, 66, 0, 2,\n                                64, 2, 6, 65, 80, 65, 73, 68, 64, 82, 19, 25,\n                                18, 17, 15, 13, 12, 12, 6, 65, 66, 69, 75, 76,\n                                95, 68, 66, 80, 9, 4, 1, 1, 67, 72, 70, 71, 79,\n                                72, 77, 92, 86, 94, 67, 22, 18, 11, 4, 7, 64,\n                                69, 70, 76, 0, 35, 21, 15, 8, 13, 3, 65, 70, 74,\n                                4, 39, 29, 24, 17, 17, 5, 64, 69, 75, 70, 40,\n                                25, 11, 3, 8, 67, 76, 80, 5, 46, 34, 24, 17, 20,\n                                5, 65, 70, 73, 62, 86, 82, 72, 82, 83, 77, 77,\n                                74, 76, 75, 73, 73, 81, 77, 83, 79, 2, 78, 80,\n                                74, 70, 68, 70, 71, 68, 68, 72, 76, 79, 7, 7,\n                                14, 4, 64, 9, 7, 5, 3, 4, 4, 3, 68, 69, 73, 66,\n                                7, 79, 4, 19, 2, 6, 8, 10, 16, 4, 6, 9, 15, 69,\n                                72, 82, 31, 33, 39, 25, 23, 31, 30, 30, 33, 28,\n                                33, 33, 22, 18, 3, 20, 29, 17, 9, 18, 15, 9, 10,\n                                6, 6, 2, 67, 68, 72, 23, 21, 21, 17, 4, 8, 5,\n                                68, 65, 70, 72, 83, 81, 89, 92, 72, 72, 90, 8,\n                                9, 1, 72, 65, 66, 74, 68, 71, 76, 85, 86, 94,\n                                102, 5, 67, 80, 73, 3, 2, 7, 9, 10, 19, 12, 17,\n                                19, 31, 22, 21, 31, 30, 52, 33, 23, 12, 4, 70,\n                                82, 94, 113, 6, 39, 32, 30, 23, 25, 12, 9, 9,\n                                64, 77, 72, 1, 70, 9, 17, 68, 68, 6, 10, 4, 9,\n                                18, 4, 1, 45, 28, 12, 67, 78, 96, 108, 116, 125 },\n\n                              {\n\n                              47,\n                                6, 78, 47, 6, 78, 83, 68, 20, 11, 2, 68, 26, 31,\n                                53, 14, 3, 64, 6, 16, 0, 67, 66, 76, 92, 6, 18,\n                                107, 115, 118, 8, 72, 68, 6, 16, 0, 76, 68, 12,\n                                4, 64, 71, 78, 64, 77, 78, 91, 5, 71, 78, 2, 75,\n                                76, 88, 7, 66, 67, 72, 2, 4, 22, 0, 0, 0, 68,\n                                92, 97, 2, 2, 66, 18, 71, 91, 83, 9, 2, 32, 25,\n                                1, 5, 75, 5, 73, 72, 81, 81, 81, 85, 87, 22, 0,\n                                8, 78, 69, 77, 74, 90, 2, 69, 68, 78, 17, 68, 1,\n                                75, 81, 68, 73, 66, 6, 6, 0, 12, 12, 74, 64, 0,\n                                67, 3, 72, 11, 70, 1, 11, 10, 21, 14, 7, 77, 1,\n                                69, 66, 0, 89, 67, 7, 3, 6, 7, 7, 21, 11, 3, 0,\n                                4, 0, 3, 6, 88, 68, 1, 77, 3, 64, 12, 5, 65, 11,\n                                6, 4, 67, 12, 64, 76, 3, 83, 18, 20, 15, 14, 17,\n                                16, 9, 16, 18, 65, 8, 9, 5, 2, 69, 3, 66, 0, 2,\n                                64, 1, 6, 65, 80, 65, 73, 69, 65, 82, 17, 24,\n                                17, 16, 13, 11, 11, 11, 4, 67, 67, 70, 77, 77,\n                                96, 68, 66, 81, 8, 3, 0, 0, 68, 73, 71, 72, 80,\n                                73, 78, 92, 85, 93, 66, 23, 18, 11, 4, 8, 0, 68,\n                                69, 75, 1, 35, 21, 15, 8, 14, 3, 64, 69, 72, 4,\n                                39, 29, 24, 17, 18, 5, 64, 69, 74, 70, 41, 25,\n                                11, 3, 9, 67, 76, 79, 5, 46, 34, 24, 16, 20, 5,\n                                65, 69, 72, 62, 85, 81, 71, 81, 81, 76, 75, 73,\n                                74, 74, 72, 71, 80, 76, 83, 78, 4, 78, 81, 73,\n                                69, 68, 70, 72, 68, 68, 73, 77, 80, 7, 7, 14, 4,\n                                64, 8, 7, 5, 2, 4, 4, 3, 69, 69, 73, 65, 8, 79,\n                                4, 18, 2, 6, 8, 10, 16, 3, 5, 9, 15, 70, 72, 83,\n                                31, 32, 38, 24, 22, 30, 28, 28, 31, 26, 31, 30,\n                                20, 16, 2, 17, 26, 14, 5, 15, 13, 8, 9, 5, 6, 3,\n                                67, 67, 70, 21, 20, 19, 15, 2, 7, 4, 70, 66, 71,\n                                73, 84, 82, 90, 92, 72, 72, 91, 7, 8, 0, 74, 66,\n                                67, 75, 69, 72, 77, 86, 87, 95, 103, 5, 68, 80,\n                                72, 3, 2, 8, 10, 11, 20, 13, 18, 20, 33, 23, 22,\n                                33, 32, 51, 32, 21, 10, 1, 73, 85, 97, 115, 7,\n                                39, 32, 31, 23, 26, 13, 9, 10, 0, 77, 71, 2, 70,\n                                10, 19, 67, 67, 7, 11, 4, 10, 19, 4, 1, 44, 26,\n                                10, 69, 81, 99, 112, 119, 126 },\n\n                              {\n\n                              46,\n                                6, 78, 46, 6, 78, 81, 66, 20, 11, 1, 70, 24, 29,\n                                53, 14, 6, 65, 7, 16, 0, 68, 66, 77, 93, 6, 16,\n                                109, 116, 118, 11, 71, 68, 7, 16, 0, 76, 67, 12,\n                                4, 64, 71, 78, 64, 78, 77, 91, 5, 71, 77, 1, 75,\n                                76, 88, 8, 65, 67, 71, 3, 4, 22, 0, 0, 0, 68,\n                                92, 97, 3, 1, 66, 18, 71, 91, 82, 11, 3, 34, 27,\n                                2, 6, 74, 7, 72, 71, 79, 80, 80, 84, 86, 22, 0,\n                                8, 78, 69, 77, 74, 88, 1, 69, 68, 78, 17, 68, 1,\n                                75, 81, 68, 73, 65, 6, 5, 0, 12, 12, 74, 64, 0,\n                                67, 3, 72, 11, 70, 1, 11, 9, 20, 13, 6, 76, 2,\n                                69, 67, 0, 88, 67, 7, 2, 6, 7, 7, 22, 12, 3, 0,\n                                4, 0, 2, 6, 89, 68, 1, 77, 2, 65, 11, 5, 65, 12,\n                                6, 4, 68, 11, 65, 76, 3, 83, 18, 20, 15, 14, 17,\n                                16, 9, 16, 18, 65, 8, 9, 5, 2, 69, 3, 66, 64, 2,\n                                64, 1, 5, 66, 80, 66, 73, 70, 66, 82, 16, 22,\n                                15, 14, 11, 9, 9, 9, 2, 69, 69, 72, 80, 79, 97,\n                                68, 67, 81, 7, 2, 64, 64, 70, 75, 72, 73, 80,\n                                73, 78, 92, 85, 93, 66, 23, 18, 11, 4, 8, 0, 68,\n                                69, 74, 1, 35, 21, 15, 8, 14, 4, 0, 69, 70, 4,\n                                39, 29, 24, 17, 18, 5, 64, 69, 73, 70, 41, 24,\n                                10, 3, 9, 67, 76, 79, 5, 45, 33, 23, 15, 20, 5,\n                                65, 69, 72, 62, 84, 80, 70, 79, 80, 75, 74, 71,\n                                73, 72, 70, 69, 79, 75, 82, 78, 5, 77, 81, 73,\n                                68, 68, 71, 72, 69, 69, 74, 78, 81, 6, 6, 14, 3,\n                                65, 8, 7, 5, 1, 3, 4, 2, 70, 69, 73, 65, 8, 79,\n                                3, 18, 1, 6, 7, 9, 16, 2, 4, 8, 14, 71, 73, 85,\n                                30, 32, 38, 23, 20, 28, 26, 26, 29, 23, 28, 28,\n                                17, 14, 0, 14, 22, 11, 1, 13, 10, 6, 8, 4, 6, 4,\n                                66, 66, 68, 20, 18, 17, 14, 0, 5, 2, 72, 67, 73,\n                                75, 86, 84, 91, 93, 73, 72, 92, 5, 6, 65, 75,\n                                68, 69, 77, 71, 74, 79, 87, 88, 96, 103, 4, 68,\n                                81, 72, 4, 3, 8, 10, 12, 21, 14, 19, 21, 34, 24,\n                                23, 34, 33, 51, 30, 19, 7, 64, 76, 88, 100, 117,\n                                7, 40, 33, 31, 24, 27, 13, 10, 10, 0, 76, 71, 3,\n                                69, 11, 20, 67, 66, 7, 11, 4, 10, 20, 4, 1, 42,\n                                24, 7, 72, 84, 103, 116, 123, 126 },\n\n                              {\n\n                              45,\n                                6, 79, 45, 6, 79, 79, 65, 21, 11, 1, 71, 23, 28,\n                                53, 14, 8, 65, 7, 17, 0, 69, 66, 78, 94, 5, 15,\n                                110, 117, 119, 14, 70, 68, 7, 17, 0, 75, 66, 13,\n                                3, 0, 70, 77, 65, 78, 77, 91, 5, 70, 77, 1, 75,\n                                75, 88, 8, 65, 67, 71, 3, 4, 22, 0, 0, 0, 67,\n                                92, 97, 3, 1, 67, 18, 71, 90, 80, 13, 5, 35, 29,\n                                3, 7, 72, 8, 71, 71, 78, 80, 80, 84, 86, 23, 0,\n                                8, 77, 68, 76, 73, 87, 1, 70, 69, 79, 17, 68, 1,\n                                74, 81, 67, 73, 65, 6, 5, 1, 12, 11, 74, 64, 0,\n                                67, 3, 72, 10, 70, 1, 10, 8, 19, 13, 6, 76, 2,\n                                69, 67, 64, 88, 68, 7, 2, 6, 7, 7, 22, 12, 3, 0,\n                                5, 0, 1, 6, 89, 69, 1, 78, 2, 66, 11, 5, 66, 12,\n                                6, 4, 70, 11, 66, 76, 3, 84, 17, 20, 14, 14, 17,\n                                16, 9, 16, 18, 65, 7, 9, 4, 2, 69, 2, 67, 64, 1,\n                                65, 0, 4, 66, 80, 66, 72, 71, 68, 82, 14, 20,\n                                13, 12, 9, 7, 7, 7, 0, 71, 70, 73, 82, 81, 98,\n                                68, 67, 82, 6, 1, 65, 66, 71, 76, 73, 74, 81,\n                                74, 79, 92, 85, 92, 65, 23, 18, 11, 5, 8, 0, 68,\n                                68, 73, 2, 34, 21, 15, 8, 15, 4, 1, 68, 68, 4,\n                                40, 29, 24, 17, 19, 5, 64, 68, 73, 70, 41, 24,\n                                10, 3, 9, 66, 75, 78, 5, 45, 33, 22, 15, 20, 5,\n                                64, 68, 71, 62, 84, 79, 70, 78, 79, 74, 72, 70,\n                                72, 71, 69, 68, 79, 74, 82, 77, 7, 77, 82, 73,\n                                68, 68, 71, 73, 69, 70, 75, 79, 82, 6, 6, 14, 3,\n                                65, 7, 6, 5, 1, 3, 3, 2, 70, 69, 74, 65, 8, 80,\n                                3, 17, 0, 5, 6, 9, 17, 2, 3, 8, 14, 71, 73, 86,\n                                29, 31, 37, 22, 19, 27, 24, 24, 27, 21, 26, 25,\n                                14, 11, 64, 12, 19, 8, 66, 10, 8, 4, 7, 3, 6, 5,\n                                66, 64, 65, 18, 16, 15, 12, 65, 3, 1, 74, 69,\n                                74, 76, 87, 85, 92, 94, 73, 73, 93, 4, 5, 66,\n                                77, 70, 71, 78, 72, 76, 80, 89, 90, 98, 104, 3,\n                                69, 82, 72, 4, 3, 9, 11, 12, 23, 15, 20, 22, 35,\n                                26, 24, 36, 34, 50, 29, 17, 5, 67, 78, 91, 102,\n                                119, 8, 40, 33, 32, 24, 28, 14, 10, 11, 1, 76,\n                                70, 3, 69, 12, 21, 67, 66, 8, 12, 4, 11, 21, 4,\n                                1, 41, 22, 5, 75, 88, 107, 119, 126, 126 },\n\n                              {\n\n                              43,\n                                6, 79, 43, 6, 79, 78, 0, 21, 11, 0, 73, 21, 27,\n                                53, 14, 10, 65, 8, 18, 0, 70, 66, 79, 95, 5, 13,\n                                112, 118, 119, 17, 69, 68, 8, 18, 0, 75, 65, 13,\n                                3, 0, 70, 76, 65, 79, 77, 91, 5, 70, 76, 1, 76,\n                                75, 88, 9, 65, 67, 71, 4, 4, 22, 0, 0, 0, 67,\n                                93, 97, 4, 0, 67, 18, 71, 90, 78, 14, 6, 37, 30,\n                                4, 8, 71, 9, 70, 70, 76, 79, 80, 83, 85, 23, 0,\n                                8, 77, 68, 76, 73, 85, 1, 70, 69, 79, 17, 68, 1,\n                                74, 81, 67, 73, 64, 6, 5, 1, 12, 11, 74, 64, 0,\n                                67, 3, 72, 9, 71, 1, 9, 7, 18, 12, 5, 75, 3, 69,\n                                68, 64, 87, 68, 7, 2, 6, 7, 7, 23, 12, 3, 64, 5,\n                                64, 0, 5, 90, 69, 1, 78, 1, 67, 11, 4, 67, 12,\n                                6, 4, 71, 11, 67, 76, 3, 84, 16, 20, 14, 14, 17,\n                                16, 9, 16, 17, 65, 7, 9, 4, 2, 70, 2, 67, 65, 1,\n                                65, 64, 3, 67, 80, 67, 72, 72, 69, 82, 13, 18,\n                                11, 10, 7, 5, 5, 5, 65, 73, 72, 75, 84, 83, 99,\n                                68, 67, 82, 5, 0, 66, 67, 73, 78, 74, 76, 82,\n                                74, 79, 92, 85, 92, 65, 23, 18, 11, 5, 8, 0, 68,\n                                68, 72, 2, 34, 21, 15, 8, 15, 5, 1, 67, 66, 4,\n                                40, 29, 24, 17, 19, 5, 64, 68, 72, 70, 41, 24,\n                                9, 3, 9, 66, 75, 77, 5, 44, 32, 21, 14, 20, 5,\n                                64, 68, 71, 62, 83, 78, 69, 77, 78, 73, 71, 69,\n                                71, 70, 67, 66, 78, 74, 82, 77, 8, 77, 82, 73,\n                                67, 68, 72, 73, 69, 71, 76, 80, 83, 5, 5, 14, 2,\n                                66, 7, 6, 5, 0, 2, 3, 2, 71, 70, 74, 65, 8, 80,\n                                2, 17, 64, 5, 5, 8, 17, 1, 2, 7, 13, 72, 74, 88,\n                                28, 30, 37, 21, 18, 25, 22, 22, 25, 18, 23, 23,\n                                11, 9, 65, 9, 16, 5, 70, 7, 5, 2, 6, 1, 6, 6,\n                                66, 0, 0, 16, 14, 13, 10, 67, 1, 64, 76, 70, 76,\n                                77, 89, 87, 93, 95, 74, 73, 94, 3, 3, 68, 79,\n                                72, 73, 80, 74, 78, 82, 90, 91, 99, 105, 2, 70,\n                                83, 72, 5, 3, 9, 11, 13, 24, 15, 21, 23, 36, 27,\n                                25, 37, 35, 50, 27, 15, 2, 69, 81, 94, 105, 122,\n                                8, 41, 34, 32, 24, 28, 14, 10, 11, 1, 76, 70, 4,\n                                68, 13, 22, 67, 65, 8, 12, 4, 11, 22, 4, 1, 40,\n                                20, 2, 78, 91, 111, 123, 126, 126 },\n\n                              {\n\n                              42,\n                                6, 79, 42, 6, 79, 76, 1, 21, 11, 0, 74, 20, 25,\n                                53, 14, 13, 66, 9, 18, 0, 70, 65, 80, 96, 4, 11,\n                                114, 119, 120, 20, 67, 68, 9, 18, 0, 75, 64, 13,\n                                2, 0, 70, 76, 65, 79, 76, 91, 5, 70, 75, 0, 76,\n                                75, 88, 9, 64, 66, 70, 4, 4, 22, 0, 0, 0, 66,\n                                93, 97, 4, 64, 67, 18, 70, 90, 77, 16, 8, 38,\n                                32, 6, 9, 70, 11, 69, 69, 74, 79, 79, 83, 84,\n                                23, 0, 8, 76, 68, 75, 72, 84, 0, 70, 69, 79, 17,\n                                68, 2, 73, 81, 67, 73, 64, 6, 4, 1, 12, 11, 73,\n                                64, 1, 67, 3, 72, 9, 71, 1, 9, 6, 18, 11, 4, 74,\n                                3, 69, 69, 65, 87, 69, 7, 1, 6, 7, 7, 24, 13, 3,\n                                64, 5, 64, 64, 5, 91, 69, 1, 79, 1, 68, 10, 4,\n                                67, 13, 6, 4, 72, 10, 68, 76, 3, 85, 16, 20, 14,\n                                14, 17, 16, 9, 16, 17, 65, 7, 9, 4, 2, 70, 2,\n                                67, 65, 1, 65, 64, 2, 67, 80, 67, 72, 73, 70,\n                                82, 11, 16, 10, 9, 5, 3, 3, 3, 67, 75, 74, 77,\n                                87, 84, 100, 68, 68, 83, 4, 64, 67, 68, 74, 79,\n                                75, 77, 82, 75, 80, 92, 85, 91, 65, 23, 18, 11,\n                                5, 8, 1, 67, 67, 71, 3, 34, 21, 15, 8, 15, 5, 2,\n                                67, 64, 4, 40, 29, 24, 17, 19, 5, 64, 68, 71,\n                                70, 42, 23, 9, 3, 9, 66, 75, 77, 5, 44, 31, 20,\n                                13, 20, 5, 64, 68, 70, 62, 82, 77, 68, 75, 77,\n                                72, 70, 67, 70, 68, 66, 64, 77, 73, 81, 76, 9,\n                                76, 83, 72, 66, 68, 72, 74, 70, 71, 77, 81, 84,\n                                4, 5, 14, 2, 66, 6, 6, 5, 64, 1, 3, 1, 72, 70,\n                                74, 65, 8, 80, 1, 16, 64, 5, 4, 7, 17, 0, 1, 7,\n                                13, 73, 75, 90, 27, 30, 36, 20, 16, 24, 20, 20,\n                                23, 16, 20, 20, 8, 7, 67, 6, 12, 2, 74, 5, 3, 0,\n                                5, 0, 6, 7, 65, 1, 2, 15, 13, 11, 9, 69, 64, 65,\n                                78, 71, 78, 79, 91, 88, 94, 96, 74, 73, 95, 1,\n                                2, 70, 80, 73, 74, 81, 75, 79, 83, 91, 92, 100,\n                                105, 2, 70, 84, 71, 5, 4, 10, 12, 14, 25, 16,\n                                22, 24, 38, 28, 26, 38, 37, 49, 25, 13, 0, 72,\n                                84, 97, 108, 124, 8, 41, 34, 33, 25, 29, 14, 11,\n                                12, 2, 75, 70, 5, 68, 14, 23, 66, 64, 9, 13, 4,\n                                12, 23, 4, 1, 38, 18, 0, 81, 94, 114, 126, 126,\n                                126 },\n\n                              {\n\n                              41,\n                                6, 79, 41, 6, 79, 74, 3, 22, 11, 64, 76, 18, 24,\n                                53, 14, 15, 66, 10, 19, 0, 71, 65, 81, 97, 4, 9,\n                                115, 120, 120, 23, 66, 68, 10, 19, 0, 74, 0, 14,\n                                2, 0, 69, 75, 66, 80, 76, 91, 5, 70, 75, 0, 76,\n                                75, 88, 10, 64, 66, 70, 5, 4, 22, 0, 0, 0, 66,\n                                93, 97, 5, 65, 67, 18, 70, 90, 75, 18, 9, 40,\n                                34, 7, 10, 68, 12, 68, 68, 72, 78, 79, 82, 83,\n                                23, 0, 8, 76, 68, 75, 72, 82, 0, 71, 70, 80, 17,\n                                68, 2, 73, 81, 66, 73, 0, 6, 4, 1, 12, 10, 73,\n                                64, 1, 67, 3, 72, 8, 71, 1, 8, 5, 17, 10, 3, 74,\n                                4, 69, 70, 65, 86, 69, 7, 1, 6, 7, 7, 25, 13, 3,\n                                64, 6, 64, 65, 5, 92, 69, 1, 79, 0, 69, 10, 4,\n                                68, 13, 6, 4, 74, 10, 69, 76, 3, 85, 15, 20, 14,\n                                14, 17, 16, 9, 16, 17, 65, 6, 9, 4, 2, 70, 1,\n                                68, 66, 0, 66, 65, 1, 68, 80, 68, 72, 74, 72,\n                                82, 10, 14, 8, 7, 3, 1, 1, 1, 69, 77, 75, 78,\n                                89, 86, 101, 68, 68, 83, 3, 65, 68, 70, 76, 81,\n                                76, 78, 83, 75, 80, 92, 85, 91, 64, 23, 18, 11,\n                                5, 8, 1, 67, 67, 70, 3, 34, 21, 15, 8, 16, 6, 3,\n                                66, 1, 4, 40, 29, 24, 17, 20, 5, 64, 68, 71, 70,\n                                42, 23, 8, 3, 9, 66, 75, 76, 5, 43, 31, 19, 12,\n                                20, 5, 64, 67, 70, 62, 81, 76, 68, 74, 76, 71,\n                                68, 66, 69, 67, 64, 0, 77, 72, 81, 76, 11, 76,\n                                83, 72, 66, 68, 73, 74, 70, 72, 78, 82, 85, 4,\n                                4, 14, 1, 67, 6, 5, 5, 65, 1, 2, 1, 73, 70, 75,\n                                65, 8, 81, 1, 16, 65, 5, 3, 7, 17, 64, 0, 6, 12,\n                                74, 75, 91, 26, 29, 36, 19, 15, 22, 18, 18, 21,\n                                13, 18, 18, 5, 4, 68, 3, 9, 64, 78, 2, 0, 65, 4,\n                                64, 6, 8, 65, 2, 4, 13, 11, 9, 7, 71, 66, 67,\n                                80, 73, 79, 80, 92, 90, 95, 97, 75, 74, 96, 0,\n                                0, 71, 82, 75, 76, 83, 77, 81, 85, 92, 94, 102,\n                                106, 1, 71, 85, 71, 6, 4, 10, 12, 14, 26, 17,\n                                23, 25, 39, 29, 27, 40, 38, 49, 24, 11, 66, 74,\n                                87, 100, 111, 126, 9, 42, 35, 33, 25, 30, 15,\n                                11, 12, 2, 75, 69, 5, 67, 15, 24, 66, 64, 9, 13,\n                                4, 12, 24, 4, 1, 37, 16, 66, 84, 97, 118, 126,\n                                126, 126 },\n\n                              {\n\n                              40,\n                                6, 79, 40, 6, 79, 72, 4, 22, 11, 64, 77, 17, 23,\n                                53, 14, 17, 66, 11, 20, 0, 72, 65, 82, 98, 3, 7,\n                                117, 121, 121, 26, 65, 68, 11, 20, 0, 74, 1, 14,\n                                1, 0, 69, 74, 66, 80, 76, 91, 5, 70, 74, 0, 76,\n                                75, 88, 10, 64, 66, 70, 5, 4, 22, 0, 0, 0, 65,\n                                93, 97, 5, 66, 67, 18, 70, 90, 73, 20, 11, 41,\n                                36, 8, 11, 67, 13, 67, 67, 70, 78, 79, 82, 82,\n                                23, 0, 8, 75, 68, 74, 71, 81, 0, 71, 70, 80, 17,\n                                68, 2, 72, 81, 66, 73, 0, 6, 4, 1, 12, 10, 73,\n                                64, 1, 67, 3, 72, 7, 71, 1, 7, 4, 16, 9, 2, 73,\n                                4, 69, 71, 66, 86, 70, 7, 1, 6, 7, 7, 26, 13, 3,\n                                64, 6, 64, 66, 5, 93, 69, 1, 80, 0, 70, 10, 4,\n                                69, 13, 6, 4, 75, 10, 70, 76, 3, 86, 14, 20, 14,\n                                14, 17, 16, 9, 16, 17, 65, 6, 9, 4, 2, 70, 1,\n                                68, 66, 0, 66, 66, 0, 68, 80, 68, 72, 75, 73,\n                                82, 8, 12, 6, 5, 1, 64, 64, 64, 71, 79, 77, 80,\n                                91, 88, 102, 68, 68, 84, 2, 66, 69, 71, 77, 82,\n                                77, 79, 84, 76, 81, 92, 85, 90, 64, 23, 18, 11,\n                                5, 8, 1, 67, 66, 69, 4, 34, 21, 15, 8, 16, 6, 4,\n                                65, 3, 4, 40, 29, 24, 17, 20, 5, 64, 68, 70, 70,\n                                42, 23, 8, 3, 9, 66, 75, 75, 5, 43, 30, 18, 11,\n                                20, 5, 64, 67, 69, 62, 80, 75, 67, 73, 75, 70,\n                                67, 65, 68, 66, 0, 2, 76, 71, 81, 75, 12, 76,\n                                84, 72, 65, 68, 73, 75, 70, 73, 79, 83, 86, 3,\n                                4, 14, 1, 67, 5, 5, 5, 66, 0, 2, 1, 74, 70, 75,\n                                65, 8, 81, 0, 15, 66, 5, 2, 6, 17, 65, 64, 6,\n                                12, 75, 76, 93, 25, 28, 35, 18, 14, 21, 16, 16,\n                                19, 11, 15, 15, 2, 2, 69, 0, 6, 67, 82, 64, 65,\n                                67, 3, 65, 6, 9, 65, 3, 6, 11, 9, 7, 5, 73, 68,\n                                68, 82, 74, 81, 81, 94, 91, 96, 98, 75, 74, 97,\n                                64, 64, 73, 84, 77, 78, 84, 78, 83, 86, 93, 95,\n                                103, 107, 0, 72, 86, 71, 6, 4, 11, 13, 15, 27,\n                                18, 24, 26, 40, 30, 28, 41, 39, 48, 22, 9, 68,\n                                77, 90, 103, 114, 126, 9, 42, 35, 34, 25, 31,\n                                15, 11, 13, 3, 75, 69, 6, 67, 16, 25, 66, 0, 10,\n                                14, 4, 13, 25, 4, 1, 36, 14, 68, 87, 100, 122,\n                                126, 126, 126 },\n\n                              {\n\n                              38,\n                                5, 80, 38, 5, 80, 71, 5, 22, 11, 65, 79, 15, 21,\n                                52, 14, 19, 67, 11, 20, 64, 73, 65, 84, 100, 2,\n                                5, 119, 122, 122, 28, 64, 69, 11, 20, 64, 74, 2,\n                                14, 0, 0, 69, 74, 67, 81, 76, 92, 5, 70, 74, 64,\n                                77, 75, 88, 10, 64, 66, 70, 5, 3, 22, 0, 0, 0,\n                                65, 94, 97, 5, 67, 68, 18, 70, 90, 72, 21, 12,\n                                42, 37, 9, 12, 66, 14, 66, 67, 69, 78, 79, 82,\n                                82, 23, 0, 8, 75, 68, 74, 71, 80, 64, 72, 71,\n                                81, 17, 68, 2, 72, 81, 66, 73, 0, 5, 3, 1, 11,\n                                9, 73, 65, 1, 67, 2, 72, 6, 72, 0, 6, 2, 15, 8,\n                                1, 73, 4, 69, 72, 67, 86, 71, 6, 0, 6, 7, 7, 26,\n                                13, 3, 65, 6, 65, 67, 4, 94, 70, 0, 81, 64, 71,\n                                9, 3, 70, 13, 6, 4, 77, 9, 71, 76, 3, 87, 13,\n                                19, 13, 14, 17, 15, 8, 16, 16, 66, 5, 9, 3, 1,\n                                71, 0, 69, 67, 64, 67, 67, 64, 69, 80, 69, 72,\n                                76, 75, 82, 6, 10, 4, 3, 64, 67, 66, 66, 73, 81,\n                                79, 82, 94, 90, 104, 69, 69, 85, 1, 68, 71, 73,\n                                79, 84, 79, 81, 85, 77, 82, 92, 85, 90, 64, 23,\n                                18, 11, 5, 8, 1, 67, 66, 68, 4, 33, 21, 15, 8,\n                                16, 6, 4, 65, 4, 3, 40, 29, 23, 16, 20, 5, 64,\n                                68, 70, 70, 42, 22, 7, 2, 9, 66, 75, 75, 5, 42,\n                                29, 17, 10, 19, 5, 64, 67, 69, 62, 80, 74, 67,\n                                72, 74, 70, 66, 64, 67, 65, 1, 3, 76, 71, 81,\n                                75, 13, 76, 85, 72, 65, 68, 74, 76, 71, 74, 80,\n                                85, 88, 2, 3, 14, 0, 68, 4, 4, 4, 67, 64, 1, 0,\n                                75, 71, 76, 65, 8, 82, 64, 14, 67, 4, 1, 5, 17,\n                                66, 66, 5, 11, 76, 77, 95, 24, 27, 34, 16, 12,\n                                19, 14, 14, 16, 8, 12, 12, 64, 64, 71, 66, 2,\n                                70, 87, 67, 68, 69, 1, 67, 6, 9, 65, 4, 8, 9, 7,\n                                5, 3, 76, 70, 70, 85, 76, 83, 83, 96, 93, 97,\n                                99, 76, 75, 99, 66, 66, 75, 86, 79, 80, 86, 80,\n                                85, 88, 95, 97, 105, 108, 64, 73, 87, 71, 6, 4,\n                                11, 13, 15, 28, 18, 25, 26, 41, 31, 29, 42, 40,\n                                47, 20, 6, 71, 80, 93, 107, 117, 126, 9, 42, 35,\n                                34, 25, 31, 15, 11, 13, 3, 75, 69, 6, 67, 17,\n                                26, 66, 0, 10, 14, 4, 13, 25, 4, 0, 34, 11, 71,\n                                90, 104, 126, 126, 126, 126 },\n\n                              {\n\n                              37,\n                                5, 80, 37, 5, 80, 69, 7, 23, 12, 65, 80, 14, 20,\n                                52, 14, 22, 67, 12, 21, 64, 73, 64, 85, 101, 2,\n                                4, 120, 123, 122, 31, 1, 69, 12, 21, 64, 73, 4,\n                                15, 0, 1, 68, 73, 67, 81, 75, 92, 5, 69, 73, 64,\n                                77, 74, 88, 11, 0, 65, 69, 6, 3, 22, 0, 0, 0,\n                                64, 94, 97, 6, 67, 68, 18, 69, 89, 70, 23, 14,\n                                44, 39, 11, 13, 64, 16, 64, 66, 67, 77, 78, 81,\n                                81, 24, 1, 9, 74, 67, 73, 70, 78, 64, 72, 71,\n                                81, 18, 68, 3, 71, 80, 65, 72, 1, 5, 3, 2, 11,\n                                9, 72, 65, 2, 67, 2, 71, 6, 72, 0, 6, 1, 15, 8,\n                                1, 72, 5, 68, 72, 67, 85, 71, 6, 0, 7, 7, 7, 27,\n                                14, 4, 65, 7, 65, 67, 4, 94, 70, 0, 81, 64, 72,\n                                9, 3, 70, 14, 7, 4, 78, 9, 71, 75, 3, 87, 13,\n                                19, 13, 14, 17, 15, 8, 16, 16, 66, 5, 9, 3, 1,\n                                71, 0, 69, 67, 64, 67, 67, 64, 69, 79, 69, 71,\n                                76, 76, 81, 5, 9, 3, 2, 66, 69, 67, 67, 75, 82,\n                                80, 83, 96, 91, 105, 69, 69, 85, 0, 69, 72, 74,\n                                80, 85, 80, 82, 85, 77, 82, 91, 84, 89, 0, 24,\n                                18, 11, 6, 9, 2, 66, 65, 66, 5, 33, 21, 15, 8,\n                                17, 7, 5, 64, 6, 3, 41, 30, 23, 16, 21, 5, 64,\n                                67, 69, 70, 43, 22, 7, 2, 10, 65, 74, 74, 5, 42,\n                                29, 17, 10, 19, 5, 0, 66, 68, 62, 79, 73, 66,\n                                70, 72, 69, 64, 1, 65, 0, 3, 5, 75, 70, 80, 74,\n                                15, 75, 85, 71, 64, 67, 74, 76, 71, 74, 80, 86,\n                                89, 2, 3, 15, 0, 68, 4, 4, 4, 67, 64, 1, 0, 75,\n                                71, 76, 64, 9, 82, 64, 14, 67, 4, 1, 5, 18, 66,\n                                67, 5, 11, 76, 77, 96, 24, 27, 34, 15, 11, 18,\n                                12, 12, 14, 6, 10, 10, 66, 66, 72, 68, 64, 73,\n                                91, 69, 70, 70, 0, 68, 6, 10, 64, 6, 11, 8, 6,\n                                4, 2, 78, 71, 71, 87, 77, 84, 84, 97, 94, 98,\n                                99, 76, 75, 100, 67, 67, 76, 87, 80, 81, 87, 81,\n                                86, 89, 96, 98, 106, 108, 64, 73, 87, 70, 7, 5,\n                                12, 14, 16, 30, 19, 26, 27, 43, 33, 30, 44, 42,\n                                47, 19, 4, 73, 82, 95, 110, 119, 126, 10, 43,\n                                36, 35, 26, 32, 16, 12, 14, 4, 74, 68, 7, 66,\n                                19, 28, 65, 1, 11, 15, 5, 14, 26, 4, 0, 33, 9,\n                                73, 92, 107, 126, 126, 126, 126 },\n\n                              {\n\n                              36,\n                                5, 80, 36, 5, 80, 67, 8, 23, 12, 65, 81, 13, 19,\n                                52, 14, 24, 67, 13, 22, 64, 74, 64, 86, 102, 1,\n                                2, 122, 124, 123, 34, 2, 69, 13, 22, 64, 73, 5,\n                                15, 64, 1, 68, 72, 67, 81, 75, 92, 5, 69, 72,\n                                64, 77, 74, 88, 11, 0, 65, 69, 6, 3, 22, 0, 0,\n                                0, 0, 94, 97, 6, 68, 68, 18, 69, 89, 68, 25, 16,\n                                45, 41, 12, 14, 0, 17, 0, 65, 65, 77, 78, 81,\n                                80, 24, 1, 9, 73, 67, 72, 70, 77, 64, 72, 71,\n                                81, 18, 68, 3, 71, 80, 65, 72, 1, 5, 3, 2, 11,\n                                9, 72, 65, 2, 67, 2, 71, 5, 72, 0, 5, 0, 14, 7,\n                                0, 71, 5, 68, 73, 68, 85, 72, 6, 0, 7, 7, 7, 28,\n                                14, 4, 65, 7, 65, 68, 4, 95, 70, 0, 82, 64, 73,\n                                9, 3, 71, 14, 7, 4, 79, 9, 72, 75, 3, 88, 12,\n                                19, 13, 14, 17, 15, 8, 16, 16, 66, 5, 9, 3, 1,\n                                71, 0, 69, 67, 64, 67, 68, 65, 70, 79, 69, 71,\n                                77, 77, 81, 3, 7, 1, 0, 68, 71, 69, 69, 77, 84,\n                                82, 85, 98, 93, 106, 69, 69, 86, 64, 70, 73, 75,\n                                82, 86, 81, 83, 86, 78, 83, 91, 84, 88, 0, 24,\n                                18, 11, 6, 9, 2, 66, 65, 65, 6, 33, 21, 15, 8,\n                                17, 7, 6, 0, 8, 3, 41, 30, 23, 16, 21, 5, 64,\n                                67, 68, 70, 43, 22, 7, 2, 10, 65, 74, 73, 5, 41,\n                                28, 16, 9, 19, 5, 0, 66, 68, 62, 78, 72, 65, 69,\n                                71, 68, 0, 2, 64, 1, 4, 7, 74, 69, 80, 73, 16,\n                                75, 86, 71, 0, 67, 74, 77, 71, 75, 81, 87, 90,\n                                1, 3, 15, 0, 69, 3, 4, 4, 68, 65, 1, 0, 76, 71,\n                                76, 64, 9, 82, 65, 13, 68, 4, 0, 4, 18, 67, 68,\n                                5, 11, 77, 78, 98, 23, 26, 33, 14, 10, 17, 10,\n                                10, 12, 4, 7, 7, 69, 68, 73, 71, 67, 76, 95, 72,\n                                72, 72, 64, 69, 6, 11, 64, 7, 13, 6, 4, 2, 0,\n                                80, 73, 73, 89, 78, 86, 85, 99, 95, 99, 100, 77,\n                                75, 101, 68, 68, 78, 89, 82, 83, 88, 83, 88, 90,\n                                97, 99, 107, 109, 65, 74, 88, 70, 7, 5, 13, 14,\n                                17, 31, 20, 27, 28, 44, 34, 31, 45, 43, 46, 17,\n                                2, 75, 85, 98, 113, 122, 126, 10, 43, 36, 35,\n                                26, 33, 16, 12, 14, 4, 74, 68, 8, 66, 20, 29,\n                                65, 2, 12, 16, 5, 14, 27, 4, 0, 32, 7, 75, 95,\n                                110, 126, 126, 126, 126 },\n\n                              {\n\n                              35,\n                                5, 80, 35, 5, 80, 65, 10, 24, 12, 66, 83, 11,\n                                18, 52, 14, 26, 67, 14, 23, 64, 75, 64, 87, 103,\n                                1, 0, 123, 125, 123, 37, 3, 69, 14, 23, 64, 72,\n                                6, 16, 64, 1, 67, 71, 68, 82, 75, 92, 5, 69, 72,\n                                64, 77, 74, 88, 12, 0, 65, 69, 7, 3, 22, 0, 0,\n                                0, 0, 94, 97, 7, 69, 68, 18, 69, 89, 66, 27, 17,\n                                47, 43, 13, 15, 2, 18, 1, 64, 0, 76, 78, 80, 79,\n                                24, 1, 9, 73, 67, 72, 69, 75, 64, 73, 72, 82,\n                                18, 68, 3, 70, 80, 64, 72, 2, 5, 3, 2, 11, 8,\n                                72, 65, 2, 67, 2, 71, 4, 72, 0, 4, 64, 13, 6,\n                                64, 71, 6, 68, 74, 68, 84, 72, 6, 0, 7, 7, 7,\n                                29, 14, 4, 65, 8, 65, 69, 4, 96, 70, 0, 82, 65,\n                                74, 9, 3, 72, 14, 7, 4, 81, 9, 73, 75, 3, 88,\n                                11, 19, 13, 14, 17, 15, 8, 16, 16, 66, 4, 9, 3,\n                                1, 71, 64, 70, 68, 65, 68, 69, 66, 70, 79, 70,\n                                71, 78, 79, 81, 2, 5, 64, 65, 70, 73, 71, 71,\n                                79, 86, 83, 86, 100, 95, 107, 69, 69, 86, 65,\n                                71, 74, 77, 83, 88, 82, 84, 87, 78, 83, 91, 84,\n                                88, 1, 24, 18, 11, 6, 9, 2, 66, 64, 64, 6, 33,\n                                21, 15, 8, 18, 8, 7, 1, 10, 3, 41, 30, 23, 16,\n                                22, 5, 64, 67, 68, 70, 43, 22, 6, 2, 10, 65, 74,\n                                72, 5, 41, 28, 15, 8, 19, 5, 0, 65, 67, 62, 77,\n                                71, 65, 68, 70, 67, 2, 3, 0, 2, 6, 8, 74, 68,\n                                80, 73, 18, 75, 86, 71, 0, 67, 75, 77, 71, 76,\n                                82, 88, 91, 1, 2, 15, 64, 69, 3, 3, 4, 69, 65,\n                                0, 0, 77, 71, 77, 64, 9, 83, 65, 13, 69, 4, 64,\n                                4, 18, 68, 69, 4, 10, 78, 78, 99, 22, 25, 33,\n                                13, 9, 15, 8, 8, 10, 1, 5, 5, 72, 71, 74, 74,\n                                70, 79, 99, 75, 75, 74, 65, 70, 6, 12, 64, 8,\n                                15, 4, 2, 0, 65, 82, 75, 74, 91, 80, 87, 86,\n                                100, 97, 100, 101, 77, 76, 102, 69, 70, 79, 91,\n                                84, 85, 90, 84, 90, 92, 98, 101, 109, 110, 66,\n                                75, 89, 70, 8, 5, 13, 15, 17, 32, 21, 28, 29,\n                                45, 35, 32, 47, 44, 46, 16, 0, 78, 87, 101, 116,\n                                125, 126, 11, 44, 37, 36, 26, 34, 17, 12, 15, 5,\n                                74, 67, 8, 65, 21, 30, 65, 2, 12, 16, 5, 15, 28,\n                                4, 0, 31, 5, 78, 98, 113, 126, 126, 126, 126 },\n\n                              {\n\n                              33,\n                                5, 80, 33, 5, 80, 64, 11, 24, 12, 66, 84, 10,\n                                16, 52, 14, 29, 68, 15, 23, 64, 76, 64, 88, 104,\n                                0, 65, 125, 126, 124, 40, 4, 69, 15, 23, 64, 72,\n                                7, 16, 65, 1, 67, 71, 68, 82, 74, 92, 5, 69, 71,\n                                65, 78, 74, 88, 12, 1, 65, 68, 7, 3, 22, 0, 0,\n                                0, 1, 95, 97, 7, 70, 68, 18, 69, 89, 65, 28, 19,\n                                48, 44, 14, 16, 3, 20, 2, 0, 2, 76, 77, 80, 78,\n                                24, 1, 9, 72, 67, 71, 69, 74, 65, 73, 72, 82,\n                                18, 68, 3, 70, 80, 64, 72, 2, 5, 2, 2, 11, 8,\n                                72, 65, 2, 67, 2, 71, 4, 73, 0, 4, 65, 12, 5,\n                                65, 70, 6, 68, 75, 69, 84, 73, 6, 64, 7, 7, 7,\n                                30, 15, 4, 66, 8, 66, 70, 3, 97, 70, 0, 83, 65,\n                                75, 8, 2, 72, 15, 7, 4, 82, 8, 74, 75, 3, 89,\n                                11, 19, 13, 14, 17, 15, 8, 16, 15, 66, 4, 9, 3,\n                                1, 72, 64, 70, 68, 65, 68, 69, 67, 71, 79, 70,\n                                71, 79, 80, 81, 0, 3, 66, 67, 72, 75, 73, 73,\n                                81, 88, 85, 88, 103, 97, 108, 69, 70, 87, 66,\n                                72, 75, 78, 85, 89, 83, 86, 87, 79, 84, 91, 84,\n                                87, 1, 24, 18, 11, 6, 9, 2, 66, 64, 0, 7, 33,\n                                21, 15, 8, 18, 8, 7, 1, 12, 3, 41, 30, 23, 16,\n                                22, 5, 64, 67, 67, 70, 43, 21, 6, 2, 10, 65, 74,\n                                72, 5, 40, 27, 14, 7, 19, 5, 0, 65, 67, 62, 76,\n                                70, 64, 66, 69, 66, 3, 5, 1, 4, 7, 10, 73, 68,\n                                79, 72, 19, 74, 87, 71, 1, 67, 75, 78, 72, 77,\n                                83, 89, 92, 0, 2, 15, 64, 70, 2, 3, 4, 70, 66,\n                                0, 64, 78, 72, 77, 64, 9, 83, 66, 12, 70, 4, 65,\n                                3, 18, 69, 70, 4, 10, 79, 79, 101, 21, 25, 32,\n                                12, 7, 14, 6, 6, 8, 64, 2, 2, 75, 73, 76, 77,\n                                74, 82, 103, 77, 77, 76, 66, 72, 6, 13, 0, 9,\n                                17, 3, 0, 65, 66, 84, 77, 76, 93, 81, 89, 88,\n                                102, 98, 101, 102, 78, 76, 103, 71, 71, 81, 92,\n                                86, 87, 91, 86, 92, 93, 99, 102, 110, 110, 67,\n                                75, 90, 70, 8, 6, 14, 15, 18, 33, 21, 29, 30,\n                                46, 36, 33, 48, 45, 45, 14, 65, 80, 90, 104,\n                                119, 126, 126, 11, 44, 37, 36, 27, 34, 17, 13,\n                                15, 5, 73, 67, 9, 65, 22, 31, 65, 3, 13, 17, 5,\n                                15, 29, 4, 0, 29, 3, 80, 101, 116, 126, 126,\n                                126, 126 },\n\n                              {\n\n                              32,\n                                5, 80, 32, 5, 80, 1, 13, 24, 12, 67, 86, 8, 15,\n                                52, 14, 31, 68, 16, 24, 64, 76, 0, 89, 105, 0,\n                                67, 126, 126, 124, 43, 6, 69, 16, 24, 64, 72, 8,\n                                16, 65, 1, 67, 70, 68, 83, 74, 92, 5, 69, 70,\n                                65, 78, 74, 88, 13, 1, 64, 68, 8, 3, 22, 0, 0,\n                                0, 1, 95, 97, 8, 71, 68, 18, 68, 89, 0, 30, 20,\n                                50, 46, 16, 17, 4, 21, 3, 1, 4, 75, 77, 79, 77,\n                                24, 1, 9, 72, 67, 71, 68, 72, 65, 73, 72, 82,\n                                18, 68, 4, 69, 80, 64, 72, 3, 5, 2, 2, 11, 8,\n                                71, 65, 3, 67, 2, 71, 3, 73, 0, 3, 66, 12, 4,\n                                66, 69, 7, 68, 76, 69, 83, 73, 6, 64, 7, 7, 7,\n                                31, 15, 4, 66, 8, 66, 71, 3, 98, 70, 0, 83, 66,\n                                76, 8, 2, 73, 15, 7, 4, 83, 8, 75, 75, 3, 89,\n                                10, 19, 13, 14, 17, 15, 8, 16, 15, 66, 4, 9, 3,\n                                1, 72, 64, 70, 69, 65, 68, 70, 68, 71, 79, 71,\n                                71, 80, 81, 81, 64, 1, 67, 68, 74, 77, 75, 75,\n                                83, 90, 87, 90, 105, 98, 109, 69, 70, 87, 67,\n                                73, 76, 79, 86, 91, 84, 87, 88, 79, 84, 91, 84,\n                                87, 1, 24, 18, 11, 6, 9, 3, 65, 0, 1, 7, 33, 21,\n                                15, 8, 18, 9, 8, 2, 14, 3, 41, 30, 23, 16, 22,\n                                5, 64, 67, 66, 70, 44, 21, 5, 2, 10, 65, 74, 71,\n                                5, 40, 26, 13, 6, 19, 5, 0, 65, 66, 62, 75, 69,\n                                0, 65, 68, 65, 4, 6, 2, 5, 9, 12, 72, 67, 79,\n                                72, 20, 74, 87, 70, 2, 67, 76, 78, 72, 77, 84,\n                                90, 93, 64, 1, 15, 65, 70, 2, 3, 4, 71, 67, 0,\n                                64, 79, 72, 77, 64, 9, 83, 67, 12, 70, 4, 66, 2,\n                                18, 70, 71, 3, 9, 80, 80, 103, 20, 24, 32, 11,\n                                6, 12, 4, 4, 6, 67, 64, 0, 78, 75, 77, 80, 77,\n                                85, 107, 80, 80, 78, 67, 73, 6, 14, 0, 10, 19,\n                                1, 64, 67, 68, 86, 79, 77, 95, 82, 91, 89, 104,\n                                100, 102, 103, 78, 76, 104, 72, 73, 83, 94, 87,\n                                88, 93, 87, 93, 95, 100, 103, 111, 111, 67, 76,\n                                91, 69, 9, 6, 14, 16, 19, 34, 22, 30, 31, 48,\n                                37, 34, 49, 47, 45, 12, 67, 83, 92, 107, 122,\n                                126, 126, 11, 45, 38, 37, 27, 35, 17, 13, 16, 6,\n                                73, 67, 10, 64, 23, 32, 64, 4, 13, 17, 5, 16,\n                                30, 4, 0, 28, 1, 83, 104, 119, 126, 126, 126,\n                                126 },\n\n                              {\n\n                              31,\n                                5, 81, 31, 5, 81, 3, 14, 25, 12, 67, 87, 7, 14,\n                                52, 14, 33, 68, 16, 25, 64, 77, 0, 90, 106, 64,\n                                68, 126, 126, 125, 46, 7, 69, 16, 25, 64, 71, 9,\n                                17, 66, 2, 66, 69, 69, 83, 74, 92, 5, 68, 70,\n                                65, 78, 73, 88, 13, 1, 64, 68, 8, 3, 22, 0, 0,\n                                0, 2, 95, 97, 8, 71, 69, 18, 68, 88, 2, 32, 22,\n                                51, 48, 17, 18, 6, 22, 4, 1, 5, 75, 77, 79, 77,\n                                25, 1, 9, 71, 66, 70, 68, 71, 65, 74, 73, 83,\n                                18, 68, 4, 69, 80, 0, 72, 3, 5, 2, 3, 11, 7, 71,\n                                65, 3, 67, 2, 71, 2, 73, 0, 2, 67, 11, 4, 66,\n                                69, 7, 68, 76, 70, 83, 74, 6, 64, 7, 7, 7, 31,\n                                15, 4, 66, 9, 66, 72, 3, 98, 71, 0, 84, 66, 77,\n                                8, 2, 74, 15, 7, 4, 85, 8, 76, 75, 3, 90, 9, 19,\n                                12, 14, 17, 15, 8, 16, 15, 66, 3, 9, 2, 1, 72,\n                                65, 71, 69, 66, 69, 71, 69, 72, 79, 71, 70, 81,\n                                83, 81, 66, 64, 69, 70, 76, 79, 77, 77, 85, 92,\n                                88, 91, 107, 100, 110, 69, 70, 88, 68, 74, 77,\n                                81, 88, 92, 85, 88, 89, 80, 85, 91, 84, 86, 2,\n                                24, 18, 11, 7, 9, 3, 65, 0, 2, 8, 32, 21, 15, 8,\n                                19, 9, 9, 3, 16, 3, 42, 30, 23, 16, 23, 5, 64,\n                                66, 66, 70, 44, 21, 5, 2, 10, 64, 73, 70, 5, 39,\n                                26, 12, 6, 19, 5, 1, 64, 66, 62, 75, 68, 0, 64,\n                                67, 64, 6, 7, 3, 6, 10, 13, 72, 66, 79, 71, 22,\n                                74, 88, 70, 2, 67, 76, 79, 72, 78, 85, 91, 94,\n                                64, 1, 15, 65, 71, 1, 2, 4, 71, 67, 64, 64, 79,\n                                72, 78, 64, 9, 84, 67, 11, 71, 3, 67, 2, 19, 70,\n                                72, 3, 9, 80, 80, 104, 19, 23, 31, 10, 5, 11, 2,\n                                2, 4, 69, 66, 66, 81, 78, 78, 82, 80, 88, 111,\n                                83, 82, 80, 68, 74, 6, 15, 0, 12, 22, 64, 66,\n                                69, 70, 88, 81, 79, 97, 84, 92, 90, 105, 101,\n                                103, 104, 79, 77, 105, 73, 74, 84, 96, 89, 90,\n                                94, 89, 95, 96, 102, 105, 113, 112, 68, 77, 92,\n                                69, 9, 6, 15, 16, 19, 36, 23, 31, 32, 49, 39,\n                                35, 51, 48, 44, 11, 69, 85, 95, 109, 125, 126,\n                                126, 12, 45, 38, 37, 27, 36, 18, 13, 16, 6, 73,\n                                66, 10, 64, 24, 33, 64, 4, 14, 18, 5, 16, 31, 4,\n                                0, 27, 64, 85, 107, 123, 126, 126, 126, 126 },\n\n                              {\n\n                              30,\n                                5, 81, 30, 5, 81, 5, 16, 25, 12, 68, 89, 5, 12,\n                                52, 14, 36, 69, 17, 25, 64, 78, 0, 91, 107, 64,\n                                70, 126, 126, 125, 49, 8, 69, 17, 25, 64, 71,\n                                10, 17, 66, 2, 66, 69, 69, 84, 73, 92, 5, 68,\n                                69, 66, 78, 73, 88, 14, 2, 64, 67, 9, 3, 22, 0,\n                                0, 0, 2, 95, 97, 9, 72, 69, 18, 68, 88, 3, 34,\n                                23, 53, 50, 18, 19, 7, 24, 5, 2, 7, 74, 76, 78,\n                                76, 25, 1, 9, 71, 66, 70, 67, 69, 66, 74, 73,\n                                83, 18, 68, 4, 68, 80, 0, 72, 4, 5, 1, 3, 11, 7,\n                                71, 65, 3, 67, 2, 71, 2, 73, 0, 2, 68, 10, 3,\n                                67, 68, 8, 68, 77, 70, 82, 74, 6, 65, 7, 7, 7,\n                                32, 16, 4, 66, 9, 66, 73, 3, 99, 71, 0, 84, 67,\n                                78, 7, 2, 74, 16, 7, 4, 86, 7, 77, 75, 3, 90, 9,\n                                19, 12, 14, 17, 15, 8, 16, 15, 66, 3, 9, 2, 1,\n                                72, 65, 71, 70, 66, 69, 71, 70, 72, 79, 72, 70,\n                                82, 84, 81, 67, 66, 71, 72, 78, 81, 79, 79, 87,\n                                94, 90, 93, 110, 102, 111, 69, 71, 88, 69, 75,\n                                78, 82, 89, 94, 86, 89, 89, 80, 85, 91, 84, 86,\n                                2, 24, 18, 11, 7, 9, 3, 65, 1, 3, 8, 32, 21, 15,\n                                8, 19, 10, 10, 3, 18, 3, 42, 30, 23, 16, 23, 5,\n                                64, 66, 65, 70, 44, 20, 4, 2, 10, 64, 73, 70, 5,\n                                39, 25, 11, 5, 19, 5, 1, 64, 65, 62, 74, 67, 1,\n                                1, 66, 0, 7, 9, 4, 8, 12, 15, 71, 65, 78, 71,\n                                23, 73, 88, 70, 3, 67, 77, 79, 73, 79, 86, 92,\n                                95, 65, 0, 15, 66, 71, 1, 2, 4, 72, 68, 64, 65,\n                                80, 72, 78, 64, 9, 84, 68, 11, 72, 3, 68, 1, 19,\n                                71, 73, 2, 8, 81, 81, 106, 18, 23, 31, 9, 3, 9,\n                                0, 0, 2, 72, 69, 68, 84, 80, 80, 85, 84, 91,\n                                115, 85, 85, 82, 69, 75, 6, 16, 1, 13, 24, 65,\n                                68, 71, 71, 90, 83, 80, 99, 85, 94, 92, 107,\n                                103, 104, 105, 79, 77, 106, 75, 76, 86, 97, 91,\n                                92, 96, 90, 97, 98, 103, 106, 114, 112, 69, 77,\n                                93, 69, 10, 7, 15, 17, 20, 37, 24, 32, 33, 50,\n                                40, 36, 52, 49, 44, 9, 71, 88, 97, 112, 126,\n                                126, 126, 12, 46, 39, 38, 28, 37, 18, 14, 17, 7,\n                                72, 66, 11, 0, 25, 34, 64, 5, 14, 18, 5, 17, 32,\n                                4, 0, 25, 66, 88, 110, 126, 126, 126, 126, 126 },\n\n                              {\n\n                              28,\n                                4, 81, 28, 4, 81, 6, 17, 25, 12, 68, 90, 4, 11,\n                                52, 14, 38, 69, 18, 26, 64, 79, 0, 92, 109, 65,\n                                72, 126, 126, 126, 51, 9, 69, 18, 26, 64, 71,\n                                11, 17, 67, 2, 66, 68, 70, 84, 73, 93, 5, 68,\n                                69, 66, 79, 73, 88, 14, 2, 64, 67, 9, 3, 22, 0,\n                                0, 0, 3, 96, 97, 9, 73, 69, 18, 68, 88, 5, 35,\n                                25, 54, 51, 19, 20, 8, 25, 6, 3, 9, 74, 76, 78,\n                                75, 25, 1, 9, 70, 66, 69, 67, 68, 66, 75, 74,\n                                84, 18, 68, 4, 68, 80, 0, 72, 4, 4, 1, 3, 11, 6,\n                                71, 65, 3, 67, 1, 71, 1, 74, 0, 1, 70, 9, 2, 68,\n                                68, 8, 68, 78, 71, 82, 75, 5, 65, 7, 7, 7, 33,\n                                16, 4, 67, 9, 67, 74, 2, 100, 71, 0, 85, 67, 79,\n                                7, 1, 75, 16, 7, 4, 88, 7, 78, 75, 3, 91, 8, 18,\n                                12, 14, 17, 14, 7, 16, 14, 67, 2, 9, 2, 0, 73,\n                                66, 72, 70, 67, 70, 72, 71, 73, 79, 72, 70, 83,\n                                86, 81, 69, 68, 73, 74, 80, 84, 81, 81, 89, 96,\n                                92, 95, 112, 104, 112, 69, 71, 89, 70, 77, 80,\n                                84, 91, 95, 88, 91, 90, 81, 86, 91, 84, 85, 2,\n                                24, 18, 11, 7, 9, 3, 65, 1, 4, 9, 32, 21, 15, 8,\n                                19, 10, 10, 4, 19, 3, 42, 30, 23, 15, 23, 5, 64,\n                                66, 65, 70, 44, 20, 4, 2, 10, 64, 73, 69, 5, 38,\n                                24, 10, 4, 18, 5, 1, 64, 65, 62, 73, 66, 1, 2,\n                                65, 0, 8, 10, 5, 9, 13, 16, 71, 65, 78, 70, 24,\n                                73, 89, 70, 3, 67, 77, 80, 73, 80, 87, 94, 96,\n                                66, 0, 15, 66, 72, 0, 1, 3, 73, 69, 65, 65, 81,\n                                73, 79, 64, 9, 85, 69, 10, 73, 3, 69, 0, 19, 72,\n                                74, 2, 8, 82, 82, 108, 17, 22, 30, 7, 2, 8, 65,\n                                65, 64, 74, 72, 71, 87, 83, 81, 88, 87, 94, 119,\n                                88, 87, 84, 71, 77, 6, 16, 1, 14, 26, 67, 70,\n                                73, 73, 93, 85, 82, 101, 87, 96, 93, 109, 104,\n                                105, 106, 80, 78, 107, 76, 77, 88, 99, 93, 94,\n                                97, 92, 99, 99, 104, 108, 116, 113, 70, 78, 94,\n                                69, 10, 7, 16, 17, 20, 38, 24, 33, 34, 51, 41,\n                                37, 53, 50, 43, 7, 73, 90, 100, 115, 126, 126,\n                                126, 12, 46, 39, 38, 28, 37, 18, 14, 17, 7, 72,\n                                66, 11, 0, 26, 35, 64, 5, 15, 19, 5, 17, 32, 4,\n                                64, 24, 68, 90, 113, 126, 126, 126, 126, 126 },\n\n                              {\n\n                              27,\n                                4, 81, 27, 4, 81, 8, 18, 26, 12, 68, 91, 3, 10,\n                                52, 14, 40, 69, 19, 27, 64, 79, 1, 93, 110, 66,\n                                74, 126, 126, 126, 54, 11, 69, 19, 27, 64, 70,\n                                12, 18, 68, 2, 65, 67, 70, 84, 73, 93, 5, 68,\n                                68, 66, 79, 73, 88, 14, 2, 0, 67, 9, 3, 22, 0,\n                                0, 0, 4, 96, 97, 9, 74, 69, 18, 67, 88, 7, 37,\n                                27, 55, 53, 21, 21, 10, 26, 8, 4, 11, 74, 76,\n                                78, 74, 25, 1, 9, 69, 66, 68, 66, 67, 66, 75,\n                                74, 84, 18, 68, 5, 67, 79, 1, 72, 4, 4, 1, 3,\n                                11, 6, 70, 65, 4, 67, 1, 70, 0, 74, 0, 0, 71, 9,\n                                1, 69, 67, 8, 67, 79, 72, 82, 76, 5, 65, 8, 7,\n                                7, 34, 16, 4, 67, 10, 67, 74, 2, 101, 71, 0, 86,\n                                67, 80, 7, 1, 76, 16, 7, 4, 89, 7, 78, 75, 3,\n                                92, 7, 18, 12, 14, 17, 14, 7, 16, 14, 67, 2, 9,\n                                2, 0, 73, 66, 72, 70, 67, 70, 73, 71, 73, 79,\n                                72, 70, 84, 87, 81, 71, 69, 74, 75, 82, 86, 82,\n                                82, 91, 98, 93, 96, 114, 105, 113, 69, 71, 90,\n                                71, 78, 81, 85, 92, 96, 89, 92, 91, 82, 87, 91,\n                                83, 84, 3, 25, 18, 11, 7, 10, 4, 64, 2, 5, 10,\n                                32, 21, 15, 8, 20, 10, 11, 5, 21, 3, 42, 30, 23,\n                                15, 24, 5, 64, 66, 64, 70, 45, 20, 4, 2, 11, 64,\n                                73, 68, 5, 38, 24, 10, 3, 18, 5, 1, 0, 64, 62,\n                                72, 65, 2, 3, 0, 1, 10, 11, 7, 10, 14, 18, 70,\n                                64, 78, 69, 26, 73, 90, 69, 4, 67, 77, 81, 73,\n                                80, 88, 95, 97, 66, 0, 15, 66, 72, 64, 1, 3, 74,\n                                69, 65, 65, 82, 73, 79, 0, 10, 85, 69, 9, 73, 3,\n                                69, 0, 19, 73, 75, 2, 8, 83, 82, 109, 17, 21,\n                                29, 6, 1, 7, 67, 67, 66, 76, 74, 74, 89, 85, 82,\n                                91, 90, 97, 123, 91, 89, 85, 72, 78, 6, 17, 1,\n                                15, 28, 69, 71, 75, 75, 95, 86, 83, 103, 88, 97,\n                                94, 110, 105, 106, 106, 80, 78, 108, 77, 78, 89,\n                                101, 94, 95, 98, 93, 100, 100, 105, 109, 117,\n                                114, 70, 79, 94, 68, 10, 7, 17, 18, 21, 39, 25,\n                                34, 35, 53, 42, 38, 55, 52, 42, 6, 75, 92, 103,\n                                118, 126, 126, 126, 13, 46, 39, 39, 28, 38, 19,\n                                14, 18, 8, 72, 65, 12, 0, 27, 37, 0, 6, 16, 20,\n                                5, 18, 33, 4, 64, 23, 70, 92, 115, 126, 126,\n                                126, 126, 126 },\n\n                              {\n\n                              26,\n                                4, 81, 26, 4, 81, 10, 20, 26, 12, 69, 93, 1, 8,\n                                52, 14, 43, 70, 20, 27, 64, 80, 1, 94, 111, 66,\n                                76, 126, 126, 126, 57, 12, 69, 20, 27, 64, 70,\n                                13, 18, 68, 2, 65, 67, 70, 85, 72, 93, 5, 68,\n                                67, 67, 79, 73, 88, 15, 3, 0, 66, 10, 3, 22, 0,\n                                0, 0, 4, 96, 97, 10, 75, 69, 18, 67, 88, 8, 39,\n                                28, 57, 55, 22, 22, 11, 28, 9, 5, 13, 73, 75,\n                                77, 73, 25, 1, 9, 69, 66, 68, 66, 65, 67, 75,\n                                74, 84, 18, 68, 5, 67, 79, 1, 72, 5, 4, 0, 3,\n                                11, 6, 70, 65, 4, 67, 1, 70, 0, 74, 0, 0, 72, 8,\n                                0, 70, 66, 9, 67, 80, 72, 81, 76, 5, 66, 8, 7,\n                                7, 35, 17, 4, 67, 10, 67, 75, 2, 102, 71, 0, 86,\n                                68, 81, 6, 1, 76, 17, 7, 4, 90, 6, 79, 75, 3,\n                                92, 7, 18, 12, 14, 17, 14, 7, 16, 14, 67, 2, 9,\n                                2, 0, 73, 66, 72, 71, 67, 70, 73, 72, 74, 79,\n                                73, 70, 85, 88, 81, 72, 71, 76, 77, 84, 88, 84,\n                                84, 93, 100, 95, 98, 117, 107, 114, 69, 72, 90,\n                                72, 79, 82, 86, 94, 98, 90, 93, 91, 82, 87, 91,\n                                83, 84, 3, 25, 18, 11, 7, 10, 4, 64, 2, 6, 10,\n                                32, 21, 15, 8, 20, 11, 12, 5, 23, 3, 42, 30, 23,\n                                15, 24, 5, 64, 66, 0, 70, 45, 19, 3, 2, 11, 64,\n                                73, 68, 5, 37, 23, 9, 2, 18, 5, 1, 0, 64, 62,\n                                71, 64, 3, 5, 1, 2, 11, 13, 8, 12, 16, 20, 69,\n                                0, 77, 69, 27, 72, 90, 69, 5, 67, 78, 81, 74,\n                                81, 89, 96, 98, 67, 64, 15, 67, 73, 64, 1, 3,\n                                75, 70, 65, 66, 83, 73, 79, 0, 10, 85, 70, 9,\n                                74, 3, 70, 64, 19, 74, 76, 1, 7, 84, 83, 111,\n                                16, 21, 29, 5, 64, 5, 69, 69, 68, 79, 77, 76,\n                                92, 87, 84, 94, 94, 100, 126, 93, 92, 87, 73,\n                                79, 6, 18, 2, 16, 30, 70, 73, 77, 76, 97, 88,\n                                85, 105, 89, 99, 96, 112, 107, 107, 107, 81, 78,\n                                109, 79, 80, 91, 102, 96, 97, 100, 95, 102, 102,\n                                106, 110, 118, 114, 71, 79, 95, 68, 11, 8, 17,\n                                18, 22, 40, 26, 35, 36, 54, 43, 39, 56, 53, 42,\n                                4, 77, 95, 105, 121, 126, 126, 126, 13, 47, 40,\n                                39, 29, 39, 19, 15, 18, 8, 71, 65, 13, 1, 28,\n                                38, 0, 7, 16, 20, 5, 18, 34, 4, 64, 21, 72, 95,\n                                118, 126, 126, 126, 126, 126 },\n\n                              {\n\n                              25,\n                                4, 82, 25, 4, 82, 12, 21, 27, 12, 69, 94, 0, 7,\n                                52, 14, 45, 70, 20, 28, 64, 81, 1, 95, 112, 67,\n                                77, 126, 126, 126, 60, 13, 69, 20, 28, 64, 69,\n                                14, 19, 69, 3, 64, 66, 71, 85, 72, 93, 5, 67,\n                                67, 67, 79, 72, 88, 15, 3, 0, 66, 10, 3, 22, 0,\n                                0, 0, 5, 96, 97, 10, 75, 70, 18, 67, 87, 10, 41,\n                                30, 58, 57, 23, 23, 13, 29, 10, 5, 14, 73, 75,\n                                77, 73, 26, 1, 9, 68, 65, 67, 65, 64, 67, 76,\n                                75, 85, 18, 68, 5, 66, 79, 2, 72, 5, 4, 0, 4,\n                                11, 5, 70, 65, 4, 67, 1, 70, 64, 74, 0, 64, 73,\n                                7, 0, 70, 66, 9, 67, 80, 73, 81, 77, 5, 66, 8,\n                                7, 7, 35, 17, 4, 67, 11, 67, 76, 2, 102, 72, 0,\n                                87, 68, 82, 6, 1, 77, 17, 7, 4, 92, 6, 80, 75,\n                                3, 93, 6, 18, 11, 14, 17, 14, 7, 16, 14, 67, 1,\n                                9, 1, 0, 73, 67, 73, 71, 68, 71, 74, 73, 74, 79,\n                                73, 69, 86, 90, 81, 74, 73, 78, 79, 86, 90, 86,\n                                86, 95, 102, 96, 99, 119, 109, 115, 69, 72, 91,\n                                73, 80, 83, 88, 95, 99, 91, 94, 92, 83, 88, 91,\n                                83, 83, 4, 25, 18, 11, 8, 10, 4, 64, 3, 7, 11,\n                                31, 21, 15, 8, 21, 11, 13, 6, 25, 3, 43, 30, 23,\n                                15, 25, 5, 64, 65, 0, 70, 45, 19, 3, 2, 11, 0,\n                                72, 67, 5, 37, 23, 8, 2, 18, 5, 2, 1, 0, 62, 71,\n                                0, 3, 6, 2, 3, 13, 14, 9, 13, 17, 21, 69, 1, 77,\n                                68, 29, 72, 91, 69, 5, 67, 78, 82, 74, 82, 90,\n                                97, 99, 67, 64, 15, 67, 73, 65, 0, 3, 75, 70,\n                                66, 66, 83, 73, 80, 0, 10, 86, 70, 8, 75, 2, 71,\n                                64, 20, 74, 77, 1, 7, 84, 83, 112, 15, 20, 28,\n                                4, 65, 4, 71, 71, 70, 81, 79, 79, 95, 90, 85,\n                                96, 97, 103, 126, 96, 94, 89, 74, 80, 6, 19, 2,\n                                18, 33, 72, 75, 79, 78, 99, 90, 86, 107, 91,\n                                100, 97, 113, 108, 108, 108, 81, 79, 110, 80,\n                                81, 92, 104, 98, 99, 101, 96, 104, 103, 108,\n                                112, 120, 115, 72, 80, 96, 68, 11, 8, 18, 19,\n                                22, 42, 27, 36, 37, 55, 45, 40, 58, 54, 41, 3,\n                                79, 97, 108, 123, 126, 126, 126, 14, 47, 40, 40,\n                                29, 40, 20, 15, 19, 9, 71, 64, 13, 1, 29, 39, 0,\n                                7, 17, 21, 5, 19, 35, 4, 64, 20, 74, 97, 121,\n                                126, 126, 126, 126, 126 },\n\n                              {\n\n                              23,\n                                4, 82, 23, 4, 82, 13, 23, 27, 12, 70, 96, 65, 6,\n                                52, 14, 47, 70, 21, 29, 64, 82, 1, 96, 113, 67,\n                                79, 126, 126, 126, 62, 14, 69, 21, 29, 64, 69,\n                                15, 19, 69, 3, 64, 65, 71, 86, 72, 93, 5, 67,\n                                66, 67, 80, 72, 88, 16, 3, 0, 66, 11, 3, 22, 0,\n                                0, 0, 5, 97, 97, 11, 76, 70, 18, 67, 87, 12, 42,\n                                31, 60, 58, 24, 24, 14, 30, 11, 6, 16, 72, 75,\n                                76, 72, 26, 1, 9, 68, 65, 67, 65, 1, 67, 76, 75,\n                                85, 18, 68, 5, 66, 79, 2, 72, 6, 4, 0, 4, 11, 5,\n                                70, 65, 4, 67, 1, 70, 65, 75, 0, 65, 74, 6, 64,\n                                71, 65, 10, 67, 81, 73, 80, 77, 5, 66, 8, 7, 7,\n                                36, 17, 4, 68, 11, 68, 77, 1, 103, 72, 0, 87,\n                                69, 83, 6, 0, 78, 17, 7, 4, 93, 6, 81, 75, 3,\n                                93, 5, 18, 11, 14, 17, 14, 7, 16, 13, 67, 1, 9,\n                                1, 0, 74, 67, 73, 72, 68, 71, 75, 74, 75, 79,\n                                74, 69, 87, 91, 81, 75, 75, 80, 81, 88, 92, 88,\n                                88, 97, 104, 98, 101, 121, 111, 116, 69, 72, 91,\n                                74, 81, 84, 89, 97, 101, 92, 96, 93, 83, 88, 91,\n                                83, 83, 4, 25, 18, 11, 8, 10, 4, 64, 3, 8, 11,\n                                31, 21, 15, 8, 21, 12, 13, 7, 27, 3, 43, 30, 23,\n                                15, 25, 5, 64, 65, 1, 70, 45, 19, 2, 2, 11, 0,\n                                72, 66, 5, 36, 22, 7, 1, 18, 5, 2, 1, 0, 62, 70,\n                                1, 4, 7, 3, 4, 14, 15, 10, 14, 19, 23, 68, 1,\n                                77, 68, 30, 72, 91, 69, 6, 67, 79, 82, 74, 83,\n                                91, 98, 100, 68, 65, 15, 68, 74, 65, 0, 3, 76,\n                                71, 66, 66, 84, 74, 80, 0, 10, 86, 71, 8, 76, 2,\n                                72, 65, 20, 75, 78, 0, 6, 85, 84, 114, 14, 19,\n                                28, 3, 66, 2, 73, 73, 72, 84, 82, 81, 98, 92,\n                                86, 99, 100, 106, 126, 99, 97, 91, 75, 82, 6,\n                                20, 2, 19, 35, 74, 77, 81, 80, 101, 92, 88, 109,\n                                92, 102, 98, 115, 110, 109, 109, 82, 79, 111,\n                                81, 83, 94, 106, 100, 101, 103, 98, 106, 105,\n                                109, 113, 121, 116, 73, 81, 97, 68, 12, 8, 18,\n                                19, 23, 43, 27, 37, 38, 56, 46, 41, 59, 55, 41,\n                                1, 81, 100, 110, 126, 126, 126, 126, 14, 48, 41,\n                                40, 29, 40, 20, 15, 19, 9, 71, 64, 14, 2, 30,\n                                40, 0, 8, 17, 21, 5, 19, 36, 4, 64, 19, 76, 100,\n                                124, 126, 126, 126, 126, 126 },\n\n                              {\n\n                              22,\n                                4, 82, 22, 4, 82, 15, 24, 27, 12, 70, 97, 66, 4,\n                                52, 14, 50, 71, 22, 29, 64, 82, 2, 97, 114, 68,\n                                81, 126, 126, 126, 62, 16, 69, 22, 29, 64, 69,\n                                16, 19, 70, 3, 64, 65, 71, 86, 71, 93, 5, 67,\n                                65, 68, 80, 72, 88, 16, 4, 1, 65, 11, 3, 22, 0,\n                                0, 0, 6, 97, 97, 11, 77, 70, 18, 66, 87, 13, 44,\n                                33, 61, 60, 26, 25, 15, 32, 12, 7, 18, 72, 74,\n                                76, 71, 26, 1, 9, 67, 65, 66, 64, 2, 68, 76, 75,\n                                85, 18, 68, 6, 65, 79, 2, 72, 6, 4, 64, 4, 11,\n                                5, 69, 65, 5, 67, 1, 70, 65, 75, 0, 65, 75, 6,\n                                65, 72, 64, 10, 67, 82, 74, 80, 78, 5, 67, 8, 7,\n                                7, 37, 18, 4, 68, 11, 68, 78, 1, 104, 72, 0, 88,\n                                69, 84, 5, 0, 78, 18, 7, 4, 94, 5, 82, 75, 3,\n                                94, 5, 18, 11, 14, 17, 14, 7, 16, 13, 67, 1, 9,\n                                1, 0, 74, 67, 73, 72, 68, 71, 75, 75, 75, 79,\n                                74, 69, 88, 92, 81, 77, 77, 81, 82, 90, 94, 90,\n                                90, 99, 106, 100, 103, 124, 112, 117, 69, 73,\n                                92, 75, 82, 85, 90, 98, 102, 93, 97, 93, 84, 89,\n                                91, 83, 82, 4, 25, 18, 11, 8, 10, 5, 0, 4, 9,\n                                12, 31, 21, 15, 8, 21, 12, 14, 7, 29, 3, 43, 30,\n                                23, 15, 25, 5, 64, 65, 2, 70, 46, 18, 2, 2, 11,\n                                0, 72, 66, 5, 36, 21, 6, 0, 18, 5, 2, 1, 1, 62,\n                                69, 2, 5, 9, 4, 5, 15, 17, 11, 16, 20, 25, 67,\n                                2, 76, 67, 31, 71, 92, 68, 7, 67, 79, 83, 75,\n                                83, 92, 99, 101, 69, 65, 15, 68, 74, 66, 0, 3,\n                                77, 72, 66, 67, 85, 74, 80, 0, 10, 86, 72, 7,\n                                76, 2, 73, 66, 20, 76, 79, 0, 6, 86, 85, 116,\n                                13, 19, 27, 2, 68, 1, 75, 75, 74, 86, 85, 84,\n                                101, 94, 88, 102, 104, 109, 126, 101, 99, 93,\n                                76, 83, 6, 21, 3, 20, 37, 75, 78, 83, 81, 103,\n                                94, 89, 111, 93, 104, 100, 117, 111, 110, 110,\n                                82, 79, 112, 83, 84, 96, 107, 101, 102, 104, 99,\n                                107, 106, 110, 114, 122, 116, 73, 81, 98, 67,\n                                12, 9, 19, 20, 24, 44, 28, 38, 39, 58, 47, 42,\n                                60, 57, 40, 64, 83, 102, 113, 126, 126, 126,\n                                126, 14, 48, 41, 41, 30, 41, 20, 16, 20, 10, 70,\n                                64, 15, 2, 31, 41, 1, 9, 18, 22, 5, 20, 37, 4,\n                                64, 17, 78, 102, 126, 126, 126, 126, 126, 126 },\n\n                              {\n\n                              21,\n                                4, 82, 21, 4, 82, 17, 26, 28, 12, 71, 99, 68, 3,\n                                52, 14, 52, 71, 23, 30, 64, 83, 2, 98, 115, 68,\n                                83, 126, 126, 126, 62, 17, 69, 23, 30, 64, 68,\n                                17, 20, 70, 3, 0, 64, 72, 87, 71, 93, 5, 67, 65,\n                                68, 80, 72, 88, 17, 4, 1, 65, 12, 3, 22, 0, 0,\n                                0, 6, 97, 97, 12, 78, 70, 18, 66, 87, 15, 46,\n                                34, 62, 62, 27, 26, 17, 33, 13, 8, 20, 71, 74,\n                                75, 70, 26, 1, 9, 67, 65, 66, 64, 4, 68, 77, 76,\n                                86, 18, 68, 6, 65, 79, 3, 72, 7, 4, 64, 4, 11,\n                                4, 69, 65, 5, 67, 1, 70, 66, 75, 0, 66, 76, 5,\n                                66, 73, 64, 11, 67, 83, 74, 79, 78, 5, 67, 8, 7,\n                                7, 38, 18, 4, 68, 12, 68, 79, 1, 105, 72, 0, 88,\n                                70, 85, 5, 0, 79, 18, 7, 4, 96, 5, 83, 75, 3,\n                                94, 4, 18, 11, 14, 17, 14, 7, 16, 13, 67, 0, 9,\n                                1, 0, 74, 68, 74, 73, 69, 72, 76, 76, 76, 79,\n                                75, 69, 89, 94, 81, 78, 79, 83, 84, 92, 96, 92,\n                                92, 101, 108, 101, 104, 126, 114, 118, 69, 73,\n                                92, 76, 83, 86, 92, 100, 104, 94, 98, 94, 84,\n                                89, 91, 83, 82, 5, 25, 18, 11, 8, 10, 5, 0, 4,\n                                10, 12, 31, 21, 15, 8, 22, 13, 15, 8, 31, 3, 43,\n                                30, 23, 15, 26, 5, 64, 65, 2, 70, 46, 18, 1, 2,\n                                11, 0, 72, 65, 5, 35, 21, 5, 64, 18, 5, 2, 2, 1,\n                                62, 68, 3, 5, 10, 5, 6, 17, 18, 12, 17, 22, 26,\n                                67, 3, 76, 67, 33, 71, 92, 68, 7, 67, 80, 83,\n                                75, 84, 93, 100, 102, 69, 66, 15, 69, 75, 66,\n                                64, 3, 78, 72, 67, 67, 86, 74, 81, 0, 10, 87,\n                                72, 7, 77, 2, 74, 66, 20, 77, 80, 64, 5, 87, 85,\n                                117, 12, 18, 27, 1, 69, 64, 77, 77, 76, 89, 87,\n                                86, 104, 97, 89, 105, 107, 112, 126, 104, 102,\n                                95, 77, 84, 6, 22, 3, 21, 39, 77, 80, 85, 83,\n                                105, 96, 91, 113, 95, 105, 101, 118, 113, 111,\n                                111, 83, 80, 113, 84, 86, 97, 109, 103, 104,\n                                106, 101, 109, 108, 111, 116, 124, 117, 74, 82,\n                                99, 67, 13, 9, 19, 20, 24, 45, 29, 39, 40, 59,\n                                48, 43, 62, 58, 40, 65, 85, 105, 115, 126, 126,\n                                126, 126, 15, 49, 42, 41, 30, 42, 21, 16, 20,\n                                10, 70, 0, 15, 3, 32, 42, 1, 9, 18, 22, 5, 20,\n                                38, 4, 64, 16, 80, 105, 126, 126, 126, 126, 126,\n                                126 },\n\n                              {\n\n                              20,\n                                4, 82, 20, 4, 82, 19, 27, 28, 12, 71, 100, 69,\n                                2, 52, 14, 54, 71, 24, 31, 64, 84, 2, 99, 116,\n                                69, 85, 126, 126, 126, 62, 18, 69, 24, 31, 64,\n                                68, 18, 20, 71, 3, 0, 0, 72, 87, 71, 93, 5, 67,\n                                64, 68, 80, 72, 88, 17, 4, 1, 65, 12, 3, 22, 0,\n                                0, 0, 7, 97, 97, 12, 79, 70, 18, 66, 87, 17, 48,\n                                36, 62, 62, 28, 27, 18, 34, 14, 9, 22, 71, 74,\n                                75, 69, 26, 1, 9, 66, 65, 65, 0, 5, 68, 77, 76,\n                                86, 18, 68, 6, 64, 79, 3, 72, 7, 4, 64, 4, 11,\n                                4, 69, 65, 5, 67, 1, 70, 67, 75, 0, 67, 77, 4,\n                                67, 74, 0, 11, 67, 84, 75, 79, 79, 5, 67, 8, 7,\n                                7, 39, 18, 4, 68, 12, 68, 80, 1, 106, 72, 0, 89,\n                                70, 86, 5, 0, 80, 18, 7, 4, 97, 5, 84, 75, 3,\n                                95, 3, 18, 11, 14, 17, 14, 7, 16, 13, 67, 0, 9,\n                                1, 0, 74, 68, 74, 73, 69, 72, 77, 77, 76, 79,\n                                75, 69, 90, 95, 81, 80, 81, 85, 86, 94, 98, 94,\n                                94, 103, 110, 103, 106, 126, 116, 119, 69, 73,\n                                93, 77, 84, 87, 93, 101, 105, 95, 99, 95, 85,\n                                90, 91, 83, 81, 5, 25, 18, 11, 8, 10, 5, 0, 5,\n                                11, 13, 31, 21, 15, 8, 22, 13, 16, 9, 33, 3, 43,\n                                30, 23, 15, 26, 5, 64, 65, 3, 70, 46, 18, 1, 2,\n                                11, 0, 72, 64, 5, 35, 20, 4, 65, 18, 5, 2, 2, 2,\n                                62, 67, 4, 6, 11, 6, 7, 18, 19, 13, 18, 23, 28,\n                                66, 4, 76, 66, 34, 71, 93, 68, 8, 67, 80, 84,\n                                75, 85, 94, 101, 103, 70, 66, 15, 69, 75, 67,\n                                64, 3, 79, 73, 67, 67, 87, 74, 81, 0, 10, 87,\n                                73, 6, 78, 2, 75, 67, 20, 78, 81, 64, 5, 88, 86,\n                                119, 11, 17, 26, 0, 70, 65, 79, 79, 78, 91, 90,\n                                89, 107, 99, 90, 108, 110, 115, 126, 107, 104,\n                                97, 78, 85, 6, 23, 3, 22, 41, 79, 82, 87, 85,\n                                107, 98, 92, 115, 96, 107, 102, 120, 114, 112,\n                                112, 83, 80, 114, 85, 87, 99, 111, 105, 106,\n                                107, 102, 111, 109, 112, 117, 125, 118, 75, 83,\n                                100, 67, 13, 9, 20, 21, 25, 46, 30, 40, 41, 60,\n                                49, 44, 62, 59, 39, 67, 87, 107, 118, 126, 126,\n                                126, 126, 15, 49, 42, 42, 30, 43, 21, 16, 21,\n                                11, 70, 0, 16, 3, 33, 43, 1, 10, 19, 23, 5, 21,\n                                39, 4, 64, 15, 82, 107, 126, 126, 126, 126, 126,\n                                126 },\n\n                              {\n\n                              18,\n                                3, 83, 18, 3, 83, 20, 28, 28, 12, 72, 102, 71,\n                                0, 51, 14, 56, 72, 24, 31, 65, 85, 2, 101, 118,\n                                70, 87, 126, 126, 126, 62, 19, 70, 24, 31, 65,\n                                68, 19, 20, 72, 3, 0, 0, 73, 88, 71, 94, 5, 67,\n                                64, 69, 81, 72, 88, 17, 4, 1, 65, 12, 2, 22, 0,\n                                0, 0, 7, 98, 97, 12, 80, 71, 18, 66, 87, 18, 49,\n                                37, 62, 62, 29, 28, 19, 35, 15, 9, 23, 71, 74,\n                                75, 69, 26, 1, 9, 66, 65, 65, 0, 6, 69, 78, 77,\n                                87, 18, 68, 6, 64, 79, 3, 72, 7, 3, 65, 4, 10,\n                                3, 69, 66, 5, 67, 0, 70, 68, 76, 64, 68, 79, 3,\n                                68, 75, 0, 11, 67, 85, 76, 79, 80, 4, 68, 8, 7,\n                                7, 39, 18, 4, 69, 12, 69, 81, 0, 107, 73, 64,\n                                90, 71, 87, 4, 64, 81, 18, 7, 4, 99, 4, 85, 75,\n                                3, 96, 2, 17, 10, 14, 17, 13, 6, 16, 12, 68, 64,\n                                9, 0, 64, 75, 69, 75, 74, 70, 73, 78, 78, 77,\n                                79, 76, 69, 91, 97, 81, 82, 83, 87, 88, 96, 101,\n                                96, 96, 105, 112, 105, 108, 126, 118, 121, 70,\n                                74, 94, 78, 86, 89, 95, 103, 107, 97, 101, 96,\n                                86, 91, 91, 83, 81, 5, 25, 18, 11, 8, 10, 5, 0,\n                                5, 12, 13, 30, 21, 15, 8, 22, 13, 16, 9, 34, 2,\n                                43, 30, 22, 14, 26, 5, 64, 65, 3, 70, 46, 17, 0,\n                                1, 11, 0, 72, 64, 5, 34, 19, 3, 66, 17, 5, 2, 2,\n                                2, 62, 67, 5, 6, 12, 7, 7, 19, 20, 14, 19, 24,\n                                29, 66, 4, 76, 66, 35, 71, 94, 68, 8, 67, 81,\n                                85, 76, 86, 95, 103, 105, 71, 67, 15, 70, 76,\n                                68, 65, 2, 80, 74, 68, 68, 88, 75, 82, 0, 10,\n                                88, 74, 5, 79, 1, 76, 68, 20, 79, 83, 65, 4, 89,\n                                87, 121, 10, 16, 25, 65, 72, 67, 81, 81, 81, 94,\n                                93, 92, 110, 102, 92, 111, 114, 118, 126, 110,\n                                107, 99, 80, 87, 6, 23, 3, 23, 43, 81, 84, 89,\n                                87, 110, 100, 94, 118, 98, 109, 104, 122, 116,\n                                113, 113, 84, 81, 116, 87, 89, 101, 113, 107,\n                                108, 109, 104, 113, 111, 114, 119, 126, 119, 76,\n                                84, 101, 67, 13, 9, 20, 21, 25, 47, 30, 41, 41,\n                                61, 50, 45, 62, 60, 38, 69, 90, 110, 121, 126,\n                                126, 126, 126, 15, 49, 42, 42, 30, 43, 21, 16,\n                                21, 11, 70, 0, 16, 3, 34, 44, 1, 10, 19, 23, 5,\n                                21, 39, 4, 65, 13, 85, 110, 126, 126, 126, 126,\n                                126, 126 },\n\n                              {\n\n                              17,\n                                3, 83, 17, 3, 83, 22, 30, 29, 13, 72, 103, 72,\n                                64, 51, 14, 59, 72, 25, 32, 65, 85, 3, 102, 119,\n                                70, 88, 126, 126, 126, 62, 21, 70, 25, 32, 65,\n                                67, 21, 21, 72, 4, 1, 1, 73, 88, 70, 94, 5, 66,\n                                0, 69, 81, 71, 88, 18, 5, 2, 64, 13, 2, 22, 0,\n                                0, 0, 8, 98, 97, 13, 80, 71, 18, 65, 86, 20, 51,\n                                39, 62, 62, 31, 29, 21, 37, 17, 10, 25, 70, 73,\n                                74, 68, 27, 2, 10, 65, 64, 64, 1, 8, 69, 78, 77,\n                                87, 19, 68, 7, 0, 78, 4, 71, 8, 3, 65, 5, 10, 3,\n                                68, 66, 6, 67, 0, 69, 68, 76, 64, 68, 80, 3, 68,\n                                75, 1, 12, 66, 85, 76, 78, 80, 4, 68, 9, 7, 7,\n                                40, 19, 5, 69, 13, 69, 81, 0, 107, 73, 64, 90,\n                                71, 88, 4, 64, 81, 19, 8, 4, 100, 4, 85, 74, 3,\n                                96, 2, 17, 10, 14, 17, 13, 6, 16, 12, 68, 64, 9,\n                                0, 64, 75, 69, 75, 74, 70, 73, 78, 78, 77, 78,\n                                76, 68, 91, 98, 80, 83, 84, 88, 89, 98, 103, 97,\n                                97, 107, 113, 106, 109, 126, 119, 122, 70, 74,\n                                94, 79, 87, 90, 96, 104, 108, 98, 102, 96, 86,\n                                91, 90, 82, 80, 6, 26, 18, 11, 9, 11, 6, 1, 6,\n                                14, 14, 30, 21, 15, 8, 23, 14, 17, 10, 36, 2,\n                                44, 31, 22, 14, 27, 5, 64, 64, 4, 70, 47, 17, 0,\n                                1, 12, 1, 71, 0, 5, 34, 19, 3, 66, 17, 5, 3, 3,\n                                3, 62, 66, 6, 7, 14, 9, 8, 21, 22, 16, 21, 26,\n                                31, 65, 5, 75, 65, 37, 70, 94, 67, 9, 66, 81,\n                                85, 76, 86, 95, 104, 106, 71, 67, 16, 70, 76,\n                                68, 65, 2, 80, 74, 68, 68, 88, 75, 82, 1, 11,\n                                88, 74, 5, 79, 1, 76, 68, 21, 79, 84, 65, 4, 89,\n                                87, 122, 10, 16, 25, 66, 73, 68, 83, 83, 83, 96,\n                                95, 94, 112, 104, 93, 113, 117, 121, 126, 112,\n                                109, 100, 81, 88, 6, 24, 4, 25, 46, 82, 85, 90,\n                                88, 112, 101, 95, 120, 99, 110, 105, 123, 117,\n                                114, 113, 84, 81, 117, 88, 90, 102, 114, 108,\n                                109, 110, 105, 114, 112, 115, 120, 126, 119, 76,\n                                84, 101, 66, 14, 10, 21, 22, 26, 49, 31, 42, 42,\n                                62, 52, 46, 62, 62, 38, 70, 92, 112, 123, 126,\n                                126, 126, 126, 16, 50, 43, 43, 31, 44, 22, 17,\n                                22, 12, 69, 1, 17, 4, 36, 46, 2, 11, 20, 24, 6,\n                                22, 40, 4, 65, 12, 87, 112, 126, 126, 126, 126,\n                                126, 126 },\n\n                              {\n\n                              16,\n                                3, 83, 16, 3, 83, 24, 31, 29, 13, 72, 104, 73,\n                                65, 51, 14, 61, 72, 26, 33, 65, 86, 3, 103, 120,\n                                71, 90, 126, 126, 126, 62, 22, 70, 26, 33, 65,\n                                67, 22, 21, 73, 4, 1, 2, 73, 88, 70, 94, 5, 66,\n                                1, 69, 81, 71, 88, 18, 5, 2, 64, 13, 2, 22, 0,\n                                0, 0, 9, 98, 97, 13, 81, 71, 18, 65, 86, 22, 53,\n                                41, 62, 62, 32, 30, 22, 38, 18, 11, 27, 70, 73,\n                                74, 67, 27, 2, 10, 64, 64, 0, 1, 9, 69, 78, 77,\n                                87, 19, 68, 7, 0, 78, 4, 71, 8, 3, 65, 5, 10, 3,\n                                68, 66, 6, 67, 0, 69, 69, 76, 64, 69, 81, 2, 69,\n                                76, 2, 12, 66, 86, 77, 78, 81, 4, 68, 9, 7, 7,\n                                41, 19, 5, 69, 13, 69, 82, 0, 108, 73, 64, 91,\n                                71, 89, 4, 64, 82, 19, 8, 4, 101, 4, 86, 74, 3,\n                                97, 1, 17, 10, 14, 17, 13, 6, 16, 12, 68, 64, 9,\n                                0, 64, 75, 69, 75, 74, 70, 73, 79, 79, 78, 78,\n                                76, 68, 92, 99, 80, 85, 86, 90, 91, 100, 105,\n                                99, 99, 109, 115, 108, 111, 126, 121, 123, 70,\n                                74, 95, 80, 88, 91, 97, 106, 109, 99, 103, 97,\n                                87, 92, 90, 82, 79, 6, 26, 18, 11, 9, 11, 6, 1,\n                                6, 15, 15, 30, 21, 15, 8, 23, 14, 18, 11, 38, 2,\n                                44, 31, 22, 14, 27, 5, 64, 64, 5, 70, 47, 17, 0,\n                                1, 12, 1, 71, 1, 5, 33, 18, 2, 67, 17, 5, 3, 3,\n                                3, 62, 65, 7, 8, 15, 10, 9, 22, 23, 17, 22, 27,\n                                33, 64, 6, 75, 64, 38, 70, 95, 67, 10, 66, 81,\n                                86, 76, 87, 96, 105, 107, 72, 67, 16, 70, 77,\n                                69, 65, 2, 81, 75, 68, 68, 89, 75, 82, 1, 11,\n                                88, 75, 4, 80, 1, 77, 69, 21, 80, 85, 65, 4, 90,\n                                88, 124, 9, 15, 24, 67, 74, 69, 85, 85, 85, 98,\n                                98, 97, 115, 106, 94, 116, 120, 124, 126, 115,\n                                111, 102, 82, 89, 6, 25, 4, 26, 48, 84, 87, 92,\n                                90, 114, 103, 97, 122, 100, 112, 106, 125, 118,\n                                115, 114, 85, 81, 118, 89, 91, 104, 116, 110,\n                                111, 111, 107, 116, 113, 116, 121, 126, 120, 77,\n                                85, 102, 66, 14, 10, 22, 22, 27, 50, 32, 43, 43,\n                                62, 53, 47, 62, 62, 37, 72, 94, 114, 126, 126,\n                                126, 126, 126, 16, 50, 43, 43, 31, 45, 22, 17,\n                                22, 12, 69, 1, 18, 4, 37, 47, 2, 12, 21, 25, 6,\n                                22, 41, 4, 65, 11, 89, 114, 126, 126, 126, 126,\n                                126, 126 },\n\n                              {\n\n                              15,\n                                3, 83, 15, 3, 83, 26, 33, 30, 13, 73, 106, 75,\n                                66, 51, 14, 62, 72, 27, 34, 65, 87, 3, 104, 121,\n                                71, 92, 126, 126, 126, 62, 23, 70, 27, 34, 65,\n                                66, 23, 22, 73, 4, 2, 3, 74, 89, 70, 94, 5, 66,\n                                1, 69, 81, 71, 88, 19, 5, 2, 64, 14, 2, 22, 0,\n                                0, 0, 9, 98, 97, 14, 82, 71, 18, 65, 86, 24, 55,\n                                42, 62, 62, 33, 31, 24, 39, 19, 12, 29, 69, 73,\n                                73, 66, 27, 2, 10, 64, 64, 0, 2, 11, 69, 79, 78,\n                                88, 19, 68, 7, 1, 78, 5, 71, 9, 3, 65, 5, 10, 2,\n                                68, 66, 6, 67, 0, 69, 70, 76, 64, 70, 82, 1, 70,\n                                77, 2, 13, 66, 87, 77, 77, 81, 4, 68, 9, 7, 7,\n                                42, 19, 5, 69, 14, 69, 83, 0, 109, 73, 64, 91,\n                                72, 90, 4, 64, 83, 19, 8, 4, 103, 4, 87, 74, 3,\n                                97, 0, 17, 10, 14, 17, 13, 6, 16, 12, 68, 65, 9,\n                                0, 64, 75, 70, 76, 75, 71, 74, 80, 80, 78, 78,\n                                77, 68, 93, 101, 80, 86, 88, 92, 93, 102, 107,\n                                101, 101, 111, 117, 109, 112, 126, 123, 124, 70,\n                                74, 95, 81, 89, 92, 99, 107, 111, 100, 104, 98,\n                                87, 92, 90, 82, 79, 7, 26, 18, 11, 9, 11, 6, 1,\n                                7, 16, 15, 30, 21, 15, 8, 24, 15, 19, 12, 40, 2,\n                                44, 31, 22, 14, 28, 5, 64, 64, 5, 70, 47, 17,\n                                64, 1, 12, 1, 71, 2, 5, 33, 18, 1, 68, 17, 5, 3,\n                                4, 4, 62, 64, 8, 8, 16, 11, 10, 24, 24, 18, 23,\n                                29, 34, 64, 7, 75, 64, 40, 70, 95, 67, 10, 66,\n                                82, 86, 76, 88, 97, 106, 108, 72, 68, 16, 71,\n                                77, 69, 66, 2, 82, 75, 69, 68, 90, 75, 83, 1,\n                                11, 89, 75, 4, 81, 1, 78, 69, 21, 81, 86, 66, 3,\n                                91, 88, 125, 8, 14, 24, 68, 75, 71, 87, 87, 87,\n                                101, 100, 99, 118, 109, 95, 119, 123, 126, 126,\n                                118, 114, 104, 83, 90, 6, 26, 4, 27, 50, 86, 89,\n                                94, 92, 116, 105, 98, 124, 102, 113, 107, 126,\n                                120, 116, 115, 85, 82, 119, 90, 93, 105, 118,\n                                112, 113, 113, 108, 118, 115, 117, 123, 126,\n                                121, 78, 86, 103, 66, 15, 10, 22, 23, 27, 51,\n                                33, 44, 44, 62, 54, 48, 62, 62, 37, 73, 96, 117,\n                                126, 126, 126, 126, 126, 17, 51, 44, 44, 31, 46,\n                                23, 17, 23, 13, 69, 2, 18, 5, 38, 48, 2, 12, 21,\n                                25, 6, 23, 42, 4, 65, 10, 91, 117, 126, 126,\n                                126, 126, 126, 126 },\n\n                        },\n\n                          {\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 126, 104, 10, 9, 12, 38, 62,\n                                62, 54, 22, 118, 65, 71, 79, 11, 13, 70, 9, 29,\n                                41, 62, 61, 27, 69, 126, 101, 76, 71, 79, 11,\n                                69, 90, 11, 20, 69, 82, 96, 4, 75, 87, 100, 7,\n                                74, 85, 4, 81, 86, 95, 66, 77, 70, 86, 72, 2,\n                                22, 0, 0, 0, 83, 86, 97, 72, 22, 1, 48, 12, 80,\n                                126, 91, 96, 81, 98, 102, 97, 119, 99, 110, 102,\n                                126, 80, 89, 94, 92, 24, 65, 84, 126, 73, 104,\n                                91, 126, 8, 7, 8, 2, 10, 68, 74, 88, 103, 91,\n                                89, 92, 76, 87, 110, 105, 78, 112, 99, 126, 126,\n                                126, 126, 66, 78, 71, 72, 4, 8, 70, 75, 89, 119,\n                                75, 43, 41, 126, 9, 2, 5, 3, 2, 67, 84, 74, 65,\n                                11, 6, 2, 69, 70, 8, 71, 5, 2, 22, 38, 31, 20,\n                                16, 19, 12, 17, 25, 66, 25, 21, 29, 89, 18, 35,\n                                32, 62, 62, 48, 62, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 53, 62, 62, 62, 62, 62, 62, 62, 56, 62,\n                                62, 62, 27, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 53, 45, 38, 22, 75, 72, 77, 28, 32, 28,\n                                33, 18, 21, 18, 37, 9, 66, 7, 73, 67, 116, 112,\n                                71, 2, 10, 66, 77, 80, 84, 87, 126, 101, 24, 10,\n                                2, 75, 77, 91, 107, 111, 122, 76, 19, 11, 6, 5,\n                                72, 69, 69, 74, 86, 66, 29, 31, 32, 11, 8, 67,\n                                73, 89, 11, 59, 55, 55, 44, 26, 2, 73, 70, 78,\n                                62, 126, 124, 110, 126, 124, 105, 121, 117, 102,\n                                117, 116, 122, 95, 100, 95, 111, 114, 89, 80,\n                                82, 85, 81, 72, 64, 67, 7, 69, 69, 69, 69, 67,\n                                77, 64, 2, 67, 64, 6, 65, 66, 1, 12, 66, 71, 75,\n                                70, 72, 3, 26, 16, 28, 26, 22, 22, 15, 22, 22,\n                                4, 13, 23, 66, 13, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 62, 62, 62, 62, 62, 54, 62, 62, 62, 62,\n                                62, 62, 62, 62, 62, 49, 37, 26, 8, 65, 62, 62,\n                                62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 43, 33,\n                                19, 15, 14, 18, 41, 41, 42, 43, 35, 39, 29, 21,\n                                24, 13, 70, 9, 71, 83, 31, 14, 9, 85, 81, 77,\n                                81, 80, 73, 74, 83, 71, 67, 2, 66, 66, 4, 4, 62,\n                                62, 62, 62, 62, 60, 53, 36, 6, 71, 39, 27, 21,\n                                11, 6, 0, 65, 67, 82, 81, 76, 72, 78, 72, 68,\n                                70, 76, 66, 1, 6, 2, 3, 9, 5, 62, 62, 62, 62,\n                                62, 60, 53, 36, 6 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 125, 102, 11, 10, 12, 37,\n                                  61, 62, 55, 22, 116, 65, 70, 78, 11, 13, 69,\n                                  9, 28, 40, 61, 58, 25, 70, 124, 100, 75, 70,\n                                  78, 11, 69, 89, 11, 20, 68, 81, 95, 4, 75, 86,\n                                  99, 7, 73, 84, 4, 80, 85, 94, 65, 76, 70, 85,\n                                  71, 2, 22, 0, 0, 0, 82, 86, 97, 71, 22, 1, 48,\n                                  12, 80, 124, 89, 94, 79, 95, 100, 95, 117, 97,\n                                  108, 100, 124, 80, 88, 93, 91, 24, 65, 83,\n                                  124, 72, 103, 90, 125, 8, 7, 8, 2, 11, 68, 73,\n                                  87, 102, 90, 88, 91, 75, 86, 108, 103, 77,\n                                  110, 97, 122, 122, 123, 124, 65, 77, 70, 71,\n                                  4, 9, 69, 74, 88, 116, 74, 41, 40, 124, 9, 3,\n                                  5, 4, 3, 66, 82, 73, 64, 11, 6, 2, 68, 69, 7,\n                                  70, 5, 2, 22, 37, 31, 20, 16, 19, 12, 17, 24,\n                                  65, 25, 21, 29, 89, 18, 35, 32, 62, 62, 47,\n                                  62, 62, 62, 61, 62, 62, 62, 62, 62, 62, 52,\n                                  62, 62, 62, 62, 62, 62, 62, 54, 62, 60, 62,\n                                  26, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  61, 52, 44, 37, 21, 75, 72, 77, 28, 31, 27,\n                                  32, 17, 20, 17, 36, 8, 66, 6, 73, 67, 115,\n                                  110, 70, 3, 10, 65, 76, 79, 83, 86, 124, 99,\n                                  25, 11, 3, 74, 76, 89, 105, 109, 120, 75, 20,\n                                  12, 7, 6, 71, 68, 68, 73, 85, 66, 30, 31, 32,\n                                  11, 9, 66, 73, 88, 11, 59, 55, 54, 43, 26, 3,\n                                  72, 69, 77, 62, 124, 122, 108, 124, 122, 103,\n                                  119, 115, 100, 115, 114, 119, 94, 99, 94, 109,\n                                  112, 88, 79, 81, 84, 80, 71, 64, 67, 7, 69,\n                                  69, 69, 68, 66, 76, 0, 2, 66, 0, 6, 64, 65, 1,\n                                  12, 65, 70, 74, 69, 71, 3, 25, 16, 27, 26, 22,\n                                  22, 15, 22, 22, 4, 13, 22, 66, 12, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  52, 62, 62, 62, 62, 62, 62, 62, 61, 62, 48,\n                                  36, 25, 8, 65, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 42, 32, 18, 15, 14, 17, 40,\n                                  40, 41, 41, 34, 38, 28, 20, 23, 12, 70, 8, 71,\n                                  83, 30, 13, 8, 84, 80, 76, 80, 78, 71, 73, 82,\n                                  70, 66, 3, 65, 65, 4, 4, 62, 62, 62, 62, 60,\n                                  56, 49, 32, 4, 70, 39, 28, 22, 12, 7, 1, 64,\n                                  66, 81, 80, 75, 71, 77, 71, 67, 69, 75, 65, 2,\n                                  6, 3, 4, 9, 5, 62, 62, 62, 62, 60, 56, 49, 32,\n                                  4 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 123, 101, 11, 10, 12, 36,\n                                  59, 61, 55, 22, 114, 65, 70, 77, 11, 12, 69,\n                                  8, 26, 39, 58, 54, 22, 72, 121, 99, 75, 70,\n                                  77, 11, 69, 88, 11, 19, 68, 81, 94, 4, 75, 86,\n                                  99, 7, 73, 84, 4, 80, 85, 94, 65, 76, 70, 85,\n                                  71, 2, 22, 0, 0, 0, 81, 86, 97, 71, 21, 1, 47,\n                                  12, 80, 122, 88, 93, 77, 93, 99, 94, 115, 96,\n                                  107, 99, 122, 80, 88, 93, 91, 24, 65, 82, 122,\n                                  72, 102, 89, 123, 8, 7, 8, 1, 11, 68, 73, 86,\n                                  101, 89, 87, 90, 75, 85, 107, 102, 76, 109,\n                                  96, 117, 118, 120, 121, 65, 77, 70, 71, 4, 9,\n                                  69, 74, 88, 114, 74, 39, 38, 121, 9, 3, 5, 4,\n                                  3, 66, 80, 72, 64, 11, 6, 2, 67, 68, 6, 70, 5,\n                                  2, 21, 36, 30, 20, 15, 19, 12, 17, 23, 65, 24,\n                                  20, 28, 89, 18, 34, 31, 62, 62, 46, 60, 62,\n                                  62, 59, 62, 62, 62, 62, 62, 62, 50, 62, 62,\n                                  62, 62, 62, 62, 62, 52, 62, 58, 62, 24, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 59, 50,\n                                  42, 35, 19, 75, 72, 78, 27, 30, 26, 31, 16,\n                                  19, 16, 34, 7, 66, 5, 74, 68, 114, 109, 69, 3,\n                                  10, 65, 75, 78, 82, 85, 122, 98, 25, 11, 3,\n                                  73, 75, 88, 103, 107, 118, 74, 21, 13, 8, 7,\n                                  70, 68, 68, 73, 84, 66, 31, 31, 31, 11, 9, 66,\n                                  73, 88, 11, 59, 54, 53, 42, 26, 3, 72, 69, 77,\n                                  62, 123, 121, 107, 122, 120, 102, 117, 113,\n                                  99, 113, 112, 117, 93, 98, 94, 108, 110, 88,\n                                  79, 81, 83, 80, 71, 64, 67, 6, 69, 69, 69, 68,\n                                  66, 75, 0, 2, 66, 0, 6, 64, 65, 1, 11, 65, 70,\n                                  74, 69, 70, 2, 24, 16, 26, 25, 21, 21, 15, 21,\n                                  21, 4, 13, 21, 66, 11, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 50, 62, 62,\n                                  62, 62, 62, 62, 62, 59, 59, 46, 34, 24, 7, 66,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 40, 30, 16, 14, 13, 15, 39, 39, 39, 39,\n                                  32, 36, 26, 19, 21, 11, 71, 7, 72, 84, 28, 12,\n                                  7, 84, 80, 75, 80, 77, 70, 73, 81, 69, 65, 3,\n                                  65, 64, 4, 4, 62, 62, 62, 62, 57, 52, 45, 28,\n                                  1, 70, 39, 28, 22, 12, 8, 1, 64, 66, 81, 80,\n                                  75, 71, 77, 70, 66, 69, 75, 65, 2, 6, 3, 5, 9,\n                                  5, 62, 62, 62, 62, 57, 52, 45, 28, 1 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 121, 99, 12, 10, 11, 34, 57,\n                                  60, 55, 22, 112, 65, 69, 76, 11, 12, 69, 8,\n                                  25, 38, 56, 51, 20, 73, 118, 98, 75, 69, 76,\n                                  11, 70, 87, 11, 19, 68, 81, 94, 4, 75, 86, 99,\n                                  7, 73, 83, 4, 80, 84, 94, 65, 76, 70, 85, 71,\n                                  2, 22, 0, 0, 0, 81, 86, 97, 70, 20, 1, 46, 11,\n                                  80, 119, 87, 92, 76, 91, 97, 92, 113, 94, 106,\n                                  98, 120, 80, 88, 92, 91, 24, 65, 81, 120, 72,\n                                  101, 89, 121, 8, 6, 7, 1, 11, 68, 72, 86, 100,\n                                  88, 87, 89, 74, 84, 105, 100, 76, 108, 95,\n                                  112, 113, 117, 118, 65, 77, 70, 70, 4, 9, 68,\n                                  73, 87, 112, 74, 37, 36, 118, 9, 3, 5, 4, 3,\n                                  65, 79, 71, 64, 11, 6, 2, 67, 67, 5, 70, 5, 1,\n                                  21, 35, 30, 20, 15, 19, 12, 17, 22, 65, 23,\n                                  19, 28, 89, 18, 34, 31, 62, 62, 45, 58, 62,\n                                  62, 57, 62, 62, 62, 62, 62, 61, 48, 62, 62,\n                                  62, 62, 62, 62, 60, 50, 62, 56, 62, 22, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 57, 48,\n                                  40, 34, 17, 75, 72, 78, 26, 29, 25, 30, 15,\n                                  18, 15, 32, 6, 67, 4, 75, 68, 114, 107, 68, 4,\n                                  10, 65, 74, 78, 82, 85, 120, 97, 25, 11, 4,\n                                  72, 74, 87, 102, 106, 116, 73, 21, 13, 8, 7,\n                                  69, 67, 68, 73, 84, 66, 31, 31, 30, 11, 9, 66,\n                                  73, 87, 11, 58, 54, 52, 41, 26, 3, 72, 69, 77,\n                                  62, 122, 119, 106, 121, 119, 101, 115, 111,\n                                  98, 112, 110, 115, 93, 97, 93, 107, 108, 87,\n                                  79, 81, 83, 79, 71, 64, 67, 6, 69, 69, 70, 67,\n                                  65, 74, 0, 2, 65, 0, 6, 64, 65, 1, 11, 65, 70,\n                                  74, 69, 70, 1, 23, 16, 25, 24, 20, 21, 15, 20,\n                                  20, 4, 13, 20, 66, 10, 62, 62, 61, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 48, 62, 62,\n                                  62, 62, 62, 62, 62, 57, 57, 44, 32, 22, 6, 67,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 59,\n                                  60, 38, 28, 15, 13, 12, 14, 37, 37, 37, 37,\n                                  31, 34, 24, 18, 20, 10, 72, 6, 73, 85, 27, 11,\n                                  6, 84, 79, 75, 79, 76, 69, 73, 81, 69, 65, 3,\n                                  64, 0, 4, 4, 62, 62, 62, 59, 54, 48, 41, 24,\n                                  65, 70, 39, 28, 22, 12, 8, 2, 64, 66, 80, 80,\n                                  75, 70, 76, 69, 65, 69, 74, 65, 2, 6, 3, 5, 9,\n                                  5, 62, 62, 62, 59, 54, 48, 41, 24, 65 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 120, 98, 12, 10, 11, 33, 55,\n                                  59, 55, 21, 110, 65, 69, 75, 10, 11, 69, 7,\n                                  23, 37, 53, 47, 17, 75, 115, 97, 75, 69, 75,\n                                  10, 70, 86, 11, 18, 68, 80, 93, 4, 75, 86, 99,\n                                  7, 73, 83, 4, 80, 84, 93, 65, 76, 70, 85, 70,\n                                  2, 22, 0, 0, 0, 80, 87, 97, 70, 19, 1, 45, 11,\n                                  80, 117, 86, 91, 74, 89, 96, 91, 112, 93, 104,\n                                  97, 118, 80, 87, 92, 91, 24, 65, 80, 118, 72,\n                                  101, 88, 119, 8, 6, 7, 0, 11, 68, 72, 85, 99,\n                                  87, 86, 88, 74, 84, 104, 99, 75, 107, 94, 107,\n                                  109, 114, 115, 65, 76, 70, 70, 4, 9, 68, 73,\n                                  87, 110, 74, 35, 34, 116, 9, 4, 5, 4, 3, 65,\n                                  77, 70, 0, 10, 6, 2, 66, 67, 4, 70, 5, 1, 20,\n                                  34, 29, 19, 14, 19, 12, 17, 21, 65, 22, 18,\n                                  27, 89, 17, 33, 30, 62, 62, 44, 56, 62, 62,\n                                  55, 62, 62, 62, 62, 62, 59, 46, 59, 62, 62,\n                                  62, 62, 62, 57, 48, 62, 54, 62, 21, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 60, 55, 46, 38,\n                                  32, 15, 75, 72, 79, 25, 28, 24, 28, 14, 16,\n                                  14, 31, 5, 67, 3, 75, 69, 113, 106, 67, 4, 10,\n                                  64, 74, 77, 81, 84, 118, 95, 25, 12, 4, 72,\n                                  73, 86, 100, 104, 115, 73, 22, 14, 9, 8, 68,\n                                  67, 68, 72, 83, 66, 32, 31, 30, 10, 9, 66, 73,\n                                  87, 11, 58, 53, 51, 40, 26, 3, 71, 69, 77, 62,\n                                  120, 118, 105, 119, 117, 100, 114, 110, 97,\n                                  110, 109, 113, 92, 96, 93, 106, 107, 87, 79,\n                                  81, 82, 79, 71, 65, 67, 5, 69, 69, 70, 67, 65,\n                                  73, 0, 2, 65, 0, 6, 64, 65, 1, 10, 65, 70, 74,\n                                  69, 69, 0, 22, 16, 24, 24, 19, 20, 15, 19, 19,\n                                  4, 13, 19, 66, 9, 62, 62, 60, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 46, 62, 62, 62,\n                                  62, 62, 62, 62, 54, 54, 42, 30, 21, 5, 67, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 57, 57,\n                                  36, 26, 13, 12, 12, 12, 36, 36, 36, 35, 29,\n                                  32, 23, 17, 18, 9, 73, 4, 74, 85, 25, 9, 4,\n                                  83, 79, 74, 79, 75, 68, 73, 80, 68, 64, 3, 64,\n                                  1, 4, 4, 62, 62, 62, 56, 50, 44, 36, 20, 68,\n                                  69, 39, 28, 22, 12, 9, 2, 64, 66, 80, 80, 75,\n                                  70, 76, 69, 64, 69, 74, 64, 3, 6, 3, 6, 9, 5,\n                                  62, 62, 62, 56, 50, 44, 36, 20, 68 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 118, 96, 12, 10, 10, 32, 53,\n                                  58, 55, 21, 108, 65, 69, 74, 10, 11, 69, 6,\n                                  21, 36, 51, 44, 15, 77, 112, 96, 74, 69, 74,\n                                  10, 70, 85, 11, 18, 68, 80, 92, 4, 75, 86, 99,\n                                  7, 73, 83, 4, 80, 83, 93, 65, 76, 70, 85, 70,\n                                  2, 22, 0, 0, 0, 80, 87, 97, 69, 18, 1, 44, 10,\n                                  80, 114, 85, 90, 72, 87, 94, 89, 110, 91, 103,\n                                  96, 115, 80, 87, 91, 90, 24, 65, 79, 116, 72,\n                                  100, 88, 117, 8, 5, 6, 0, 11, 68, 71, 85, 98,\n                                  86, 86, 87, 73, 83, 102, 97, 74, 105, 93, 102,\n                                  105, 111, 112, 64, 76, 69, 69, 4, 9, 67, 73,\n                                  86, 108, 74, 33, 32, 113, 9, 4, 5, 4, 3, 64,\n                                  76, 69, 0, 10, 6, 2, 66, 66, 3, 69, 5, 0, 20,\n                                  33, 29, 19, 14, 19, 12, 17, 20, 64, 21, 18,\n                                  27, 89, 17, 32, 29, 62, 62, 43, 55, 62, 62,\n                                  53, 62, 62, 62, 62, 61, 57, 44, 57, 62, 60,\n                                  62, 62, 62, 55, 46, 62, 52, 62, 19, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 61, 58, 53, 44, 37,\n                                  30, 13, 75, 72, 79, 24, 27, 23, 27, 13, 15,\n                                  13, 29, 4, 68, 2, 76, 70, 112, 104, 66, 5, 10,\n                                  64, 73, 77, 81, 83, 116, 94, 25, 12, 5, 71,\n                                  72, 85, 99, 103, 113, 72, 23, 15, 10, 8, 67,\n                                  66, 67, 72, 83, 66, 32, 31, 29, 10, 9, 66, 73,\n                                  86, 11, 57, 52, 50, 39, 26, 3, 71, 69, 76, 62,\n                                  119, 116, 103, 117, 116, 99, 112, 108, 96,\n                                  108, 107, 111, 91, 95, 92, 105, 105, 87, 79,\n                                  80, 82, 78, 71, 65, 67, 5, 69, 69, 71, 66, 65,\n                                  72, 0, 2, 65, 0, 6, 64, 65, 1, 10, 65, 70, 74,\n                                  69, 69, 64, 21, 16, 23, 23, 19, 19, 15, 19,\n                                  18, 4, 13, 18, 66, 8, 62, 62, 59, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 44, 62, 62,\n                                  62, 62, 62, 62, 61, 52, 52, 40, 29, 19, 5, 68,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 61, 55,\n                                  54, 34, 24, 12, 12, 11, 10, 35, 34, 34, 33,\n                                  27, 30, 21, 16, 17, 8, 73, 3, 75, 86, 24, 8,\n                                  3, 83, 79, 73, 78, 74, 67, 72, 79, 68, 64, 3,\n                                  0, 2, 4, 4, 62, 62, 59, 53, 47, 40, 32, 16,\n                                  71, 69, 39, 28, 22, 12, 9, 2, 0, 65, 79, 80,\n                                  75, 69, 76, 68, 0, 69, 74, 64, 3, 6, 4, 6, 9,\n                                  5, 62, 62, 59, 53, 47, 40, 32, 16, 71 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 116, 95, 13, 10, 10, 30, 51,\n                                  57, 55, 21, 107, 65, 68, 74, 10, 10, 68, 6,\n                                  20, 34, 48, 40, 12, 78, 110, 95, 74, 68, 74,\n                                  10, 71, 85, 11, 17, 68, 80, 92, 4, 75, 85, 98,\n                                  7, 72, 82, 4, 79, 83, 93, 65, 76, 70, 85, 70,\n                                  2, 22, 0, 0, 0, 79, 87, 97, 69, 18, 0, 44, 10,\n                                  80, 112, 84, 89, 71, 84, 93, 88, 108, 90, 102,\n                                  95, 113, 80, 87, 91, 90, 24, 65, 78, 113, 72,\n                                  99, 87, 115, 7, 5, 6, 64, 12, 68, 71, 84, 98,\n                                  86, 85, 86, 73, 82, 101, 96, 74, 104, 92, 97,\n                                  100, 108, 109, 64, 76, 69, 69, 4, 9, 67, 72,\n                                  86, 106, 73, 31, 30, 110, 9, 4, 5, 4, 4, 64,\n                                  74, 68, 0, 10, 6, 2, 65, 65, 2, 69, 5, 0, 19,\n                                  32, 28, 19, 13, 19, 12, 17, 18, 64, 20, 17,\n                                  26, 89, 17, 32, 29, 62, 62, 42, 53, 62, 62,\n                                  51, 62, 62, 62, 62, 57, 55, 43, 55, 62, 58,\n                                  62, 62, 62, 52, 44, 62, 50, 62, 17, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 59, 56, 50, 42, 35,\n                                  29, 12, 75, 72, 80, 23, 26, 22, 26, 12, 14,\n                                  12, 27, 3, 68, 1, 77, 70, 112, 103, 65, 5, 10,\n                                  64, 72, 76, 80, 83, 114, 93, 26, 12, 5, 70,\n                                  71, 84, 97, 101, 111, 71, 23, 15, 10, 9, 66,\n                                  66, 67, 72, 82, 66, 33, 31, 28, 10, 9, 66, 73,\n                                  86, 10, 57, 52, 49, 38, 25, 3, 71, 69, 76, 62,\n                                  118, 115, 102, 116, 114, 98, 110, 106, 95,\n                                  107, 105, 109, 91, 94, 92, 104, 103, 86, 79,\n                                  80, 81, 78, 71, 65, 67, 4, 69, 69, 71, 66, 64,\n                                  71, 0, 2, 64, 1, 6, 0, 64, 1, 9, 65, 70, 74,\n                                  69, 68, 65, 20, 16, 22, 22, 18, 19, 15, 18,\n                                  18, 4, 12, 16, 67, 7, 62, 62, 58, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 42, 62, 62,\n                                  62, 62, 62, 62, 58, 50, 49, 38, 27, 18, 4, 69,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 61, 58, 52,\n                                  51, 32, 23, 10, 11, 10, 9, 33, 33, 32, 31, 26,\n                                  28, 19, 15, 15, 7, 74, 2, 76, 87, 22, 7, 2,\n                                  83, 78, 73, 78, 73, 66, 72, 79, 67, 0, 3, 0,\n                                  3, 4, 4, 62, 62, 57, 50, 44, 36, 28, 12, 74,\n                                  69, 39, 28, 22, 12, 10, 3, 0, 65, 79, 79, 74,\n                                  69, 75, 67, 1, 68, 73, 64, 3, 6, 4, 7, 9, 5,\n                                  62, 62, 57, 50, 44, 36, 28, 12, 74 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 114, 93, 13, 10, 9, 29, 49,\n                                  56, 55, 21, 105, 65, 68, 73, 9, 10, 68, 5, 18,\n                                  33, 46, 37, 10, 80, 107, 94, 74, 68, 73, 9,\n                                  71, 84, 11, 17, 68, 79, 91, 4, 75, 85, 98, 7,\n                                  72, 82, 4, 79, 82, 92, 65, 76, 70, 85, 69, 2,\n                                  22, 0, 0, 0, 79, 87, 97, 68, 17, 0, 43, 9, 80,\n                                  109, 83, 88, 69, 82, 91, 86, 107, 88, 100, 94,\n                                  111, 80, 86, 90, 90, 24, 65, 77, 111, 72, 98,\n                                  87, 113, 7, 4, 5, 64, 12, 68, 70, 84, 97, 85,\n                                  85, 85, 72, 81, 99, 94, 73, 103, 91, 92, 96,\n                                  105, 106, 64, 75, 69, 68, 4, 9, 66, 72, 85,\n                                  104, 73, 29, 28, 107, 9, 5, 5, 4, 4, 0, 73,\n                                  67, 1, 9, 6, 2, 65, 65, 1, 69, 5, 64, 19, 31,\n                                  28, 18, 13, 19, 12, 17, 17, 64, 19, 16, 26,\n                                  89, 17, 31, 28, 60, 62, 41, 51, 62, 62, 49,\n                                  62, 61, 62, 62, 54, 53, 41, 52, 62, 55, 62,\n                                  62, 62, 49, 42, 62, 48, 62, 16, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 57, 53, 48, 40, 33, 27,\n                                  10, 75, 72, 80, 22, 25, 21, 24, 11, 13, 11,\n                                  26, 2, 69, 0, 77, 71, 111, 101, 64, 6, 10, 0,\n                                  72, 76, 80, 82, 112, 91, 26, 13, 6, 70, 70,\n                                  83, 96, 100, 109, 71, 24, 16, 11, 9, 65, 65,\n                                  67, 71, 82, 66, 33, 31, 28, 9, 9, 66, 73, 85,\n                                  10, 56, 51, 48, 37, 25, 3, 70, 69, 76, 62,\n                                  116, 113, 101, 114, 113, 97, 109, 105, 94,\n                                  105, 104, 107, 90, 93, 91, 103, 101, 86, 79,\n                                  80, 81, 77, 71, 66, 67, 4, 69, 69, 72, 65, 64,\n                                  70, 0, 2, 64, 1, 6, 0, 64, 1, 9, 65, 70, 74,\n                                  69, 68, 66, 19, 16, 21, 22, 17, 18, 15, 17,\n                                  17, 4, 12, 15, 67, 6, 61, 62, 57, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 40, 62, 62,\n                                  62, 62, 62, 62, 56, 48, 47, 36, 25, 16, 3, 69,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 59, 56, 50,\n                                  48, 30, 21, 9, 10, 10, 7, 32, 31, 31, 29, 24,\n                                  26, 18, 14, 14, 6, 75, 0, 77, 87, 21, 5, 0,\n                                  82, 78, 72, 77, 72, 65, 72, 78, 67, 0, 3, 1,\n                                  4, 4, 4, 62, 62, 54, 47, 40, 32, 24, 8, 77,\n                                  68, 39, 28, 22, 12, 10, 3, 0, 65, 78, 79, 74,\n                                  68, 75, 66, 2, 68, 73, 0, 4, 6, 4, 7, 9, 5,\n                                  62, 62, 54, 47, 40, 32, 24, 8, 77 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 113, 92, 13, 10, 9, 27, 46,\n                                  55, 55, 20, 103, 66, 68, 72, 9, 9, 68, 4, 16,\n                                  32, 43, 33, 7, 82, 104, 93, 74, 68, 72, 9, 72,\n                                  83, 11, 16, 68, 79, 91, 3, 76, 85, 98, 7, 72,\n                                  82, 4, 79, 82, 92, 65, 76, 70, 85, 69, 2, 22,\n                                  0, 0, 0, 78, 88, 97, 68, 16, 0, 42, 9, 81,\n                                  107, 82, 87, 68, 80, 90, 85, 105, 87, 99, 93,\n                                  109, 80, 86, 90, 90, 24, 65, 76, 109, 72, 98,\n                                  86, 111, 7, 4, 5, 65, 12, 68, 70, 83, 96, 84,\n                                  84, 85, 72, 81, 98, 93, 73, 102, 90, 88, 92,\n                                  102, 104, 64, 75, 69, 68, 3, 9, 66, 72, 85,\n                                  102, 73, 27, 26, 105, 9, 5, 5, 4, 4, 0, 71,\n                                  67, 1, 9, 5, 2, 64, 64, 64, 69, 5, 64, 18, 29,\n                                  27, 18, 12, 19, 12, 16, 16, 64, 18, 15, 25,\n                                  89, 16, 30, 27, 58, 62, 39, 49, 62, 62, 46,\n                                  62, 59, 62, 62, 50, 51, 39, 50, 62, 53, 62,\n                                  62, 62, 46, 40, 62, 46, 62, 14, 62, 62, 62,\n                                  62, 62, 62, 62, 60, 55, 51, 46, 38, 31, 25, 8,\n                                  75, 73, 81, 21, 23, 20, 23, 10, 11, 9, 24, 1,\n                                  69, 64, 78, 72, 111, 100, 0, 6, 10, 0, 71, 75,\n                                  79, 82, 110, 90, 26, 13, 6, 69, 69, 82, 94,\n                                  98, 108, 70, 24, 16, 11, 10, 64, 65, 67, 71,\n                                  81, 67, 34, 31, 27, 9, 9, 66, 73, 85, 10, 56,\n                                  50, 47, 36, 25, 3, 70, 69, 76, 62, 115, 112,\n                                  100, 113, 111, 96, 107, 103, 93, 104, 102,\n                                  105, 90, 93, 91, 102, 100, 86, 79, 80, 80, 77,\n                                  71, 66, 67, 3, 69, 69, 72, 65, 64, 69, 0, 1,\n                                  64, 1, 5, 0, 64, 1, 8, 65, 70, 74, 69, 67, 67,\n                                  18, 16, 19, 21, 16, 17, 14, 16, 16, 4, 12, 14,\n                                  67, 4, 60, 60, 56, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 60, 38, 62, 62, 62, 62, 62, 62,\n                                  53, 45, 44, 34, 23, 15, 2, 70, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 56, 53, 47, 45, 28, 19, 7, 9,\n                                  9, 5, 30, 30, 29, 27, 22, 24, 16, 12, 12, 4,\n                                  76, 64, 78, 88, 19, 4, 64, 82, 78, 72, 77, 71,\n                                  64, 72, 78, 66, 1, 3, 1, 4, 4, 3, 62, 60, 51,\n                                  44, 37, 28, 19, 3, 80, 68, 39, 28, 22, 12, 11,\n                                  3, 0, 65, 78, 79, 74, 68, 75, 66, 2, 68, 73,\n                                  0, 4, 6, 4, 8, 9, 4, 62, 60, 51, 44, 37, 28,\n                                  19, 3, 80 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 111, 91, 14, 10, 9, 26, 44,\n                                  54, 56, 20, 101, 66, 67, 71, 9, 8, 68, 4, 15,\n                                  31, 41, 29, 4, 83, 101, 92, 73, 67, 71, 9, 72,\n                                  82, 11, 16, 67, 79, 90, 3, 76, 85, 98, 7, 72,\n                                  81, 4, 79, 82, 92, 65, 76, 70, 84, 69, 2, 22,\n                                  0, 0, 0, 77, 88, 97, 68, 15, 0, 41, 9, 81,\n                                  105, 80, 86, 66, 78, 88, 84, 103, 85, 98, 91,\n                                  106, 80, 86, 90, 89, 24, 65, 75, 107, 71, 97,\n                                  85, 109, 7, 4, 5, 65, 12, 68, 70, 82, 95, 83,\n                                  83, 84, 71, 80, 97, 91, 72, 100, 89, 83, 87,\n                                  98, 101, 0, 75, 68, 67, 3, 9, 66, 71, 84, 99,\n                                  73, 25, 25, 102, 9, 5, 5, 4, 4, 1, 69, 66, 1,\n                                  9, 5, 2, 0, 0, 65, 68, 5, 64, 17, 28, 26, 18,\n                                  11, 19, 12, 16, 15, 0, 17, 15, 24, 89, 16, 30,\n                                  27, 56, 62, 38, 48, 62, 62, 44, 60, 57, 62,\n                                  62, 47, 49, 37, 48, 62, 51, 62, 62, 62, 44,\n                                  38, 62, 44, 62, 12, 62, 62, 62, 62, 62, 62,\n                                  60, 58, 53, 49, 44, 37, 30, 24, 6, 75, 73, 81,\n                                  21, 22, 19, 22, 9, 10, 8, 22, 0, 69, 65, 79,\n                                  72, 110, 99, 1, 6, 10, 0, 70, 74, 78, 81, 107,\n                                  89, 26, 13, 6, 68, 68, 81, 92, 96, 106, 69,\n                                  25, 17, 12, 11, 0, 65, 66, 71, 80, 67, 35, 31,\n                                  26, 9, 10, 65, 73, 84, 10, 56, 50, 46, 35, 25,\n                                  3, 70, 69, 75, 62, 114, 111, 98, 111, 109, 95,\n                                  105, 101, 92, 102, 100, 103, 89, 92, 90, 101,\n                                  98, 85, 78, 79, 79, 76, 71, 66, 67, 2, 69, 69,\n                                  72, 65, 0, 68, 1, 1, 0, 1, 5, 0, 64, 1, 7, 65,\n                                  69, 73, 69, 66, 67, 17, 16, 18, 20, 16, 17,\n                                  14, 16, 15, 4, 12, 13, 67, 3, 59, 59, 56, 61,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 57, 36,\n                                  62, 62, 62, 62, 62, 62, 50, 43, 42, 33, 22,\n                                  14, 2, 71, 62, 62, 62, 62, 62, 62, 62, 62, 54,\n                                  51, 45, 43, 26, 17, 5, 9, 8, 4, 29, 29, 27,\n                                  25, 21, 23, 14, 11, 10, 3, 76, 65, 78, 89, 17,\n                                  3, 65, 82, 77, 71, 77, 70, 1, 71, 77, 65, 2,\n                                  3, 2, 5, 4, 3, 62, 58, 49, 41, 34, 24, 15, 64,\n                                  83, 68, 39, 28, 23, 13, 12, 4, 1, 64, 78, 79,\n                                  74, 68, 74, 65, 3, 68, 72, 0, 4, 6, 5, 9, 9,\n                                  4, 62, 58, 49, 41, 34, 24, 15, 64, 83 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 109, 89, 14, 10, 8, 25, 42,\n                                  53, 56, 20, 99, 66, 67, 70, 8, 8, 68, 3, 13,\n                                  30, 38, 26, 2, 85, 98, 91, 73, 67, 70, 8, 72,\n                                  81, 11, 15, 67, 78, 89, 3, 76, 85, 98, 7, 72,\n                                  81, 4, 79, 81, 91, 65, 76, 70, 84, 68, 2, 22,\n                                  0, 0, 0, 77, 88, 97, 67, 14, 0, 40, 8, 81,\n                                  102, 79, 85, 64, 76, 87, 82, 102, 84, 96, 90,\n                                  104, 80, 85, 89, 89, 24, 65, 74, 105, 71, 96,\n                                  85, 107, 7, 3, 4, 66, 12, 68, 69, 82, 94, 82,\n                                  83, 83, 71, 79, 95, 90, 71, 99, 88, 78, 83,\n                                  95, 98, 0, 74, 68, 67, 3, 9, 65, 71, 84, 97,\n                                  73, 23, 23, 99, 9, 6, 5, 4, 4, 1, 68, 65, 2,\n                                  8, 5, 2, 0, 0, 66, 68, 5, 65, 17, 27, 26, 17,\n                                  11, 19, 12, 16, 14, 0, 16, 14, 24, 89, 16, 29,\n                                  26, 54, 62, 37, 46, 62, 62, 42, 57, 55, 62,\n                                  62, 43, 47, 35, 45, 61, 48, 62, 62, 62, 41,\n                                  36, 58, 42, 62, 11, 62, 62, 62, 62, 62, 60,\n                                  58, 56, 51, 46, 42, 35, 28, 22, 4, 75, 73, 82,\n                                  20, 21, 18, 20, 8, 9, 7, 21, 64, 70, 66, 79,\n                                  73, 109, 97, 2, 7, 10, 1, 70, 74, 78, 80, 105,\n                                  87, 26, 14, 7, 68, 67, 80, 91, 95, 104, 69,\n                                  26, 18, 13, 11, 1, 64, 66, 70, 80, 67, 35, 31,\n                                  26, 8, 10, 65, 73, 84, 10, 55, 49, 45, 34, 25,\n                                  3, 69, 69, 75, 62, 112, 109, 97, 109, 108, 94,\n                                  104, 100, 91, 100, 99, 101, 88, 91, 90, 100,\n                                  96, 85, 78, 79, 79, 76, 71, 67, 67, 2, 69, 69,\n                                  73, 64, 0, 67, 1, 1, 0, 1, 5, 0, 64, 1, 7, 65,\n                                  69, 73, 69, 66, 68, 16, 16, 17, 20, 15, 16,\n                                  14, 15, 14, 4, 12, 12, 67, 2, 58, 58, 55, 59,\n                                  60, 62, 62, 62, 62, 62, 62, 62, 62, 55, 34,\n                                  62, 62, 62, 62, 62, 62, 48, 41, 39, 31, 20,\n                                  12, 1, 71, 62, 62, 62, 62, 62, 62, 62, 62, 52,\n                                  48, 43, 40, 24, 15, 4, 8, 8, 2, 28, 27, 26,\n                                  23, 19, 21, 13, 10, 9, 2, 77, 67, 79, 89, 16,\n                                  1, 67, 81, 77, 70, 76, 69, 2, 71, 76, 65, 2,\n                                  3, 2, 6, 4, 3, 62, 56, 46, 38, 30, 20, 11, 68,\n                                  86, 67, 39, 28, 23, 13, 12, 4, 1, 64, 77, 79,\n                                  74, 67, 74, 64, 4, 68, 72, 1, 5, 6, 5, 9, 9,\n                                  4, 62, 56, 46, 38, 30, 20, 11, 68, 86 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 107, 88, 15, 10, 8, 23, 40,\n                                  52, 56, 20, 98, 66, 66, 70, 8, 7, 67, 3, 12,\n                                  28, 36, 22, 64, 86, 96, 90, 73, 66, 70, 8, 73,\n                                  81, 11, 15, 67, 78, 89, 3, 76, 84, 97, 7, 71,\n                                  80, 4, 78, 81, 91, 65, 76, 70, 84, 68, 2, 22,\n                                  0, 0, 0, 76, 88, 97, 67, 14, 64, 40, 8, 81,\n                                  100, 78, 84, 0, 73, 85, 81, 100, 82, 95, 89,\n                                  102, 80, 85, 89, 89, 24, 65, 73, 102, 71, 95,\n                                  84, 105, 6, 3, 4, 66, 13, 68, 69, 81, 94, 82,\n                                  82, 82, 70, 78, 94, 88, 71, 98, 87, 73, 78,\n                                  92, 95, 0, 74, 68, 66, 3, 9, 65, 70, 83, 95,\n                                  72, 21, 21, 96, 9, 6, 5, 4, 5, 2, 66, 64, 2,\n                                  8, 5, 2, 1, 1, 67, 68, 5, 65, 16, 26, 25, 17,\n                                  10, 19, 12, 16, 12, 0, 15, 13, 23, 89, 16, 29,\n                                  26, 52, 62, 36, 44, 61, 62, 40, 55, 53, 62,\n                                  62, 40, 45, 34, 43, 57, 46, 62, 62, 62, 38,\n                                  34, 55, 40, 62, 9, 62, 62, 62, 62, 62, 58, 55,\n                                  54, 49, 44, 39, 33, 26, 21, 3, 75, 73, 82, 19,\n                                  20, 17, 19, 7, 8, 6, 19, 65, 70, 67, 80, 73,\n                                  109, 96, 3, 7, 10, 1, 69, 73, 77, 80, 103, 86,\n                                  27, 14, 7, 67, 66, 79, 89, 93, 102, 68, 26,\n                                  18, 13, 12, 2, 64, 66, 70, 79, 67, 36, 31, 25,\n                                  8, 10, 65, 73, 83, 9, 55, 49, 44, 33, 24, 3,\n                                  69, 69, 75, 62, 111, 108, 96, 108, 106, 93,\n                                  102, 98, 90, 99, 97, 99, 88, 90, 89, 99, 94,\n                                  84, 78, 79, 78, 75, 71, 67, 67, 1, 69, 69, 73,\n                                  64, 1, 66, 1, 1, 1, 2, 5, 1, 0, 1, 6, 65, 69,\n                                  73, 69, 65, 69, 15, 16, 16, 19, 14, 16, 14,\n                                  14, 14, 4, 11, 10, 68, 1, 56, 57, 54, 58, 58,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 52, 32, 62,\n                                  62, 62, 62, 62, 62, 45, 39, 37, 29, 18, 11, 0,\n                                  72, 62, 62, 62, 62, 62, 62, 60, 59, 49, 46,\n                                  40, 37, 22, 14, 2, 7, 7, 1, 26, 26, 24, 21,\n                                  18, 19, 11, 9, 7, 1, 78, 68, 80, 90, 14, 0,\n                                  68, 81, 76, 70, 76, 68, 3, 71, 76, 64, 3, 3,\n                                  3, 7, 4, 3, 62, 54, 44, 35, 27, 16, 7, 72, 89,\n                                  67, 39, 28, 23, 13, 13, 5, 1, 64, 77, 78, 73,\n                                  67, 73, 0, 5, 67, 71, 1, 5, 6, 5, 10, 9, 4,\n                                  62, 54, 44, 35, 27, 16, 7, 72, 89 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 106, 86, 15, 10, 7, 22, 38,\n                                  51, 56, 19, 96, 66, 66, 69, 8, 7, 67, 2, 10,\n                                  27, 33, 19, 66, 88, 93, 89, 73, 66, 69, 8, 73,\n                                  80, 11, 14, 67, 78, 88, 3, 76, 84, 97, 7, 71,\n                                  80, 4, 78, 80, 91, 65, 76, 70, 84, 68, 2, 22,\n                                  0, 0, 0, 76, 89, 97, 66, 13, 64, 39, 7, 81,\n                                  97, 77, 83, 2, 71, 84, 79, 98, 81, 94, 88,\n                                  100, 80, 85, 88, 89, 24, 65, 72, 100, 71, 95,\n                                  84, 103, 6, 2, 3, 67, 13, 68, 68, 81, 93, 81,\n                                  82, 81, 70, 78, 92, 87, 70, 97, 86, 68, 74,\n                                  89, 92, 0, 74, 68, 66, 3, 9, 64, 70, 83, 93,\n                                  72, 19, 19, 94, 9, 6, 5, 4, 5, 2, 65, 0, 2, 8,\n                                  5, 2, 1, 2, 68, 68, 5, 66, 16, 25, 25, 17, 10,\n                                  19, 12, 16, 11, 0, 14, 12, 23, 89, 15, 28, 25,\n                                  50, 62, 35, 42, 59, 60, 38, 52, 51, 62, 62,\n                                  36, 43, 32, 41, 54, 43, 58, 62, 62, 35, 32,\n                                  51, 38, 62, 7, 62, 62, 62, 62, 62, 56, 53, 52,\n                                  47, 42, 37, 31, 24, 19, 1, 75, 73, 83, 18, 19,\n                                  16, 18, 6, 6, 5, 17, 66, 71, 68, 81, 74, 108,\n                                  94, 4, 8, 10, 1, 68, 73, 77, 79, 101, 85, 27,\n                                  14, 8, 66, 65, 78, 88, 92, 101, 67, 27, 19,\n                                  14, 12, 3, 0, 66, 70, 79, 67, 36, 31, 24, 8,\n                                  10, 65, 73, 83, 9, 54, 48, 43, 32, 24, 3, 69,\n                                  69, 75, 62, 110, 106, 95, 106, 105, 92, 100,\n                                  96, 89, 97, 95, 97, 87, 89, 89, 98, 93, 84,\n                                  78, 79, 78, 75, 71, 67, 67, 1, 69, 69, 74, 0,\n                                  1, 65, 1, 1, 1, 2, 5, 1, 0, 1, 6, 65, 69, 73,\n                                  69, 65, 70, 14, 16, 15, 18, 13, 15, 14, 13,\n                                  13, 4, 11, 9, 68, 0, 55, 56, 53, 56, 56, 62,\n                                  61, 62, 62, 62, 62, 62, 61, 50, 30, 62, 62,\n                                  62, 62, 62, 59, 43, 36, 34, 27, 16, 9, 64, 73,\n                                  62, 62, 62, 62, 62, 62, 57, 56, 47, 43, 38,\n                                  34, 20, 12, 1, 6, 6, 64, 25, 24, 22, 19, 16,\n                                  17, 9, 8, 6, 0, 79, 69, 81, 91, 13, 64, 69,\n                                  81, 76, 69, 75, 67, 4, 71, 75, 64, 3, 3, 3, 8,\n                                  4, 3, 61, 52, 41, 32, 24, 12, 2, 76, 92, 67,\n                                  39, 28, 23, 13, 13, 5, 1, 64, 76, 78, 73, 66,\n                                  73, 0, 6, 67, 71, 1, 5, 6, 5, 10, 9, 4, 61,\n                                  52, 41, 32, 24, 12, 2, 76, 92 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 104, 85, 15, 10, 7, 21, 36,\n                                  50, 56, 19, 94, 66, 66, 68, 7, 6, 67, 1, 8,\n                                  26, 31, 15, 69, 90, 90, 88, 72, 66, 68, 7, 73,\n                                  79, 11, 14, 67, 77, 87, 3, 76, 84, 97, 7, 71,\n                                  80, 4, 78, 80, 90, 65, 76, 70, 84, 67, 2, 22,\n                                  0, 0, 0, 75, 89, 97, 66, 12, 64, 38, 7, 81,\n                                  95, 76, 82, 4, 69, 82, 78, 97, 79, 92, 87, 97,\n                                  80, 84, 88, 88, 24, 65, 71, 98, 71, 94, 83,\n                                  101, 6, 2, 3, 67, 13, 68, 68, 80, 92, 80, 81,\n                                  80, 69, 77, 91, 85, 69, 95, 85, 0, 70, 86, 89,\n                                  1, 73, 67, 65, 3, 9, 64, 70, 82, 91, 72, 17,\n                                  17, 91, 9, 7, 5, 4, 5, 3, 0, 1, 3, 7, 5, 2, 2,\n                                  2, 69, 67, 5, 66, 15, 24, 24, 16, 9, 19, 12,\n                                  16, 10, 1, 13, 12, 22, 89, 15, 27, 24, 48, 62,\n                                  34, 41, 57, 58, 36, 50, 49, 62, 62, 33, 41,\n                                  30, 38, 51, 41, 55, 62, 62, 33, 30, 48, 36,\n                                  62, 6, 62, 62, 62, 61, 60, 54, 51, 50, 45, 39,\n                                  35, 29, 23, 17, 64, 75, 73, 83, 17, 18, 15,\n                                  16, 5, 5, 4, 16, 67, 71, 69, 81, 75, 107, 93,\n                                  5, 8, 10, 2, 68, 72, 76, 78, 99, 83, 27, 15,\n                                  8, 66, 64, 77, 86, 90, 99, 67, 28, 20, 15, 13,\n                                  4, 0, 65, 69, 78, 67, 37, 31, 24, 7, 10, 65,\n                                  73, 82, 9, 54, 47, 42, 31, 24, 3, 68, 69, 74,\n                                  62, 108, 105, 93, 104, 103, 91, 99, 95, 88,\n                                  95, 94, 95, 86, 88, 88, 97, 91, 84, 78, 78,\n                                  77, 74, 71, 68, 67, 0, 69, 69, 74, 0, 1, 64,\n                                  1, 1, 1, 2, 5, 1, 0, 1, 5, 65, 69, 73, 69, 64,\n                                  71, 13, 16, 14, 18, 13, 14, 14, 13, 12, 4, 11,\n                                  8, 68, 64, 54, 55, 52, 54, 54, 62, 59, 61, 62,\n                                  59, 62, 62, 58, 47, 28, 62, 62, 62, 62, 59,\n                                  56, 40, 34, 32, 25, 15, 8, 64, 73, 62, 62, 62,\n                                  62, 59, 59, 55, 53, 45, 41, 36, 31, 18, 10,\n                                  64, 6, 6, 66, 24, 23, 21, 17, 14, 15, 8, 7, 4,\n                                  64, 79, 71, 82, 91, 11, 66, 71, 80, 76, 68,\n                                  75, 66, 5, 70, 74, 0, 4, 3, 4, 9, 4, 3, 60,\n                                  50, 38, 29, 20, 8, 65, 80, 95, 66, 39, 28, 23,\n                                  13, 14, 5, 2, 0, 76, 78, 73, 66, 73, 1, 7, 67,\n                                  71, 2, 6, 6, 6, 11, 9, 4, 60, 50, 38, 29, 20,\n                                  8, 65, 80, 95 },\n\n                                {\n\n                                61,\n                                  8, 76, 61, 8, 76, 102, 83, 16, 10, 6, 19, 34,\n                                  49, 56, 19, 92, 66, 65, 67, 7, 6, 67, 1, 7,\n                                  25, 28, 12, 71, 91, 87, 87, 72, 65, 67, 7, 74,\n                                  78, 11, 13, 67, 77, 87, 3, 76, 84, 97, 7, 71,\n                                  79, 4, 78, 79, 90, 65, 76, 70, 84, 67, 2, 22,\n                                  0, 0, 0, 75, 89, 97, 65, 11, 64, 37, 6, 81,\n                                  92, 75, 81, 5, 67, 81, 76, 95, 78, 91, 86, 95,\n                                  80, 84, 87, 88, 24, 65, 70, 96, 71, 93, 83,\n                                  99, 6, 1, 2, 68, 13, 68, 67, 80, 91, 79, 81,\n                                  79, 69, 76, 89, 84, 69, 94, 84, 5, 65, 83, 86,\n                                  1, 73, 67, 65, 3, 9, 0, 69, 82, 89, 72, 15,\n                                  15, 88, 9, 7, 5, 4, 5, 3, 1, 2, 3, 7, 5, 2, 2,\n                                  3, 70, 67, 5, 67, 15, 23, 24, 16, 9, 19, 12,\n                                  16, 9, 1, 12, 11, 22, 89, 15, 27, 24, 46, 61,\n                                  33, 39, 55, 55, 34, 47, 47, 62, 62, 29, 39,\n                                  28, 36, 48, 38, 52, 61, 62, 30, 28, 44, 34,\n                                  62, 4, 60, 62, 60, 58, 57, 52, 49, 48, 43, 37,\n                                  33, 27, 21, 16, 66, 75, 73, 84, 16, 17, 14,\n                                  15, 4, 4, 3, 14, 68, 72, 70, 82, 75, 107, 91,\n                                  6, 9, 10, 2, 67, 72, 76, 78, 97, 82, 27, 15,\n                                  9, 65, 0, 76, 85, 89, 97, 66, 28, 20, 15, 13,\n                                  5, 1, 65, 69, 78, 67, 37, 31, 23, 7, 10, 65,\n                                  73, 82, 9, 53, 47, 41, 30, 24, 3, 68, 69, 74,\n                                  62, 107, 103, 92, 103, 102, 90, 97, 93, 87,\n                                  94, 92, 93, 86, 87, 88, 96, 89, 83, 78, 78,\n                                  77, 74, 71, 68, 67, 0, 69, 69, 75, 1, 2, 0, 1,\n                                  1, 2, 2, 5, 1, 0, 1, 5, 65, 69, 73, 69, 64,\n                                  72, 12, 16, 13, 17, 12, 14, 14, 12, 11, 4, 11,\n                                  7, 68, 65, 53, 54, 51, 53, 52, 60, 57, 59, 59,\n                                  57, 62, 60, 55, 45, 26, 62, 62, 62, 62, 55,\n                                  53, 38, 32, 29, 23, 13, 6, 65, 74, 62, 62, 62,\n                                  60, 56, 57, 52, 50, 42, 38, 33, 28, 16, 8, 65,\n                                  5, 5, 67, 22, 21, 19, 15, 13, 13, 6, 6, 3, 65,\n                                  80, 72, 83, 92, 10, 67, 72, 80, 75, 68, 74,\n                                  65, 6, 70, 74, 0, 4, 3, 4, 10, 4, 3, 59, 48,\n                                  36, 26, 17, 4, 69, 84, 98, 66, 39, 28, 23, 13,\n                                  14, 6, 2, 0, 75, 78, 73, 65, 72, 2, 8, 67, 70,\n                                  2, 6, 6, 6, 11, 9, 4, 59, 48, 36, 26, 17, 4,\n                                  69, 84, 98 },\n\n                                {\n\n                                60,\n                                  8, 76, 60, 8, 76, 100, 82, 16, 10, 6, 18, 32,\n                                  48, 56, 19, 90, 66, 65, 66, 7, 5, 67, 0, 5,\n                                  24, 26, 8, 74, 93, 84, 86, 72, 65, 66, 7, 74,\n                                  77, 11, 13, 67, 77, 86, 3, 76, 84, 97, 7, 71,\n                                  79, 4, 78, 79, 90, 65, 76, 70, 84, 67, 2, 22,\n                                  0, 0, 0, 74, 89, 97, 65, 10, 64, 36, 6, 81,\n                                  90, 74, 80, 7, 65, 79, 75, 93, 76, 90, 85, 93,\n                                  80, 84, 87, 88, 24, 65, 69, 94, 71, 92, 82,\n                                  97, 6, 1, 2, 68, 13, 68, 67, 79, 90, 78, 80,\n                                  78, 68, 75, 88, 82, 68, 93, 83, 10, 2, 80, 83,\n                                  1, 73, 67, 64, 3, 9, 0, 69, 81, 87, 72, 13,\n                                  13, 85, 9, 7, 5, 4, 5, 4, 3, 3, 3, 7, 5, 2, 3,\n                                  4, 71, 67, 5, 67, 14, 22, 23, 16, 8, 19, 12,\n                                  16, 8, 1, 11, 10, 21, 89, 15, 26, 23, 44, 58,\n                                  32, 37, 53, 53, 32, 45, 45, 62, 62, 26, 37,\n                                  26, 34, 45, 36, 49, 57, 62, 27, 26, 41, 32,\n                                  62, 2, 58, 62, 58, 56, 55, 50, 47, 46, 41, 35,\n                                  31, 25, 19, 14, 68, 75, 73, 84, 15, 16, 13,\n                                  14, 3, 3, 2, 12, 69, 72, 71, 83, 76, 106, 90,\n                                  7, 9, 10, 2, 66, 71, 75, 77, 95, 81, 27, 15,\n                                  9, 64, 1, 75, 83, 87, 95, 65, 29, 21, 16, 14,\n                                  6, 1, 65, 69, 77, 67, 38, 31, 22, 7, 10, 65,\n                                  73, 81, 9, 53, 46, 40, 29, 24, 3, 68, 69, 74,\n                                  62, 106, 102, 91, 101, 100, 89, 95, 91, 86,\n                                  92, 90, 91, 85, 86, 87, 95, 87, 83, 78, 78,\n                                  76, 73, 71, 68, 67, 64, 69, 69, 75, 1, 2, 1,\n                                  1, 1, 2, 2, 5, 1, 0, 1, 4, 65, 69, 73, 69, 0,\n                                  73, 11, 16, 12, 16, 11, 13, 14, 11, 10, 4, 11,\n                                  6, 68, 66, 52, 53, 50, 51, 50, 58, 55, 57, 57,\n                                  54, 61, 57, 52, 42, 24, 62, 62, 62, 62, 52,\n                                  50, 35, 30, 27, 21, 11, 5, 66, 75, 62, 62, 62,\n                                  58, 53, 54, 50, 47, 40, 36, 31, 25, 14, 6, 67,\n                                  4, 4, 69, 21, 20, 17, 13, 11, 11, 4, 5, 1, 66,\n                                  81, 73, 84, 93, 8, 68, 73, 80, 75, 67, 74, 64,\n                                  7, 70, 73, 1, 5, 3, 5, 11, 4, 3, 58, 46, 33,\n                                  23, 14, 0, 73, 88, 101, 66, 39, 28, 23, 13,\n                                  15, 6, 2, 0, 75, 78, 73, 65, 72, 3, 9, 67, 70,\n                                  2, 6, 6, 6, 12, 9, 4, 58, 46, 33, 23, 14, 0,\n                                  73, 88, 101 },\n\n                                {\n\n                                58,\n                                  7, 77, 58, 7, 77, 99, 81, 16, 10, 5, 16, 29,\n                                  47, 56, 18, 89, 67, 65, 66, 6, 4, 67, 64, 3,\n                                  22, 23, 4, 77, 95, 82, 86, 72, 65, 66, 6, 75,\n                                  77, 11, 12, 67, 77, 86, 2, 77, 84, 97, 6, 71,\n                                  79, 4, 78, 79, 90, 65, 76, 71, 84, 67, 2, 22,\n                                  0, 0, 0, 74, 90, 97, 65, 9, 65, 35, 5, 82, 88,\n                                  73, 79, 8, 0, 78, 74, 92, 75, 89, 84, 91, 80,\n                                  84, 87, 88, 24, 65, 69, 92, 71, 92, 82, 96, 5,\n                                  0, 1, 69, 13, 68, 67, 79, 90, 78, 80, 78, 68,\n                                  75, 87, 81, 68, 92, 82, 14, 6, 77, 81, 1, 73,\n                                  67, 64, 2, 9, 0, 69, 81, 85, 72, 11, 11, 83,\n                                  9, 7, 5, 4, 5, 4, 4, 3, 3, 6, 4, 2, 3, 4, 73,\n                                  67, 5, 68, 13, 20, 22, 15, 7, 19, 12, 15, 6,\n                                  1, 10, 9, 20, 89, 14, 25, 22, 41, 54, 30, 35,\n                                  50, 50, 29, 42, 43, 55, 62, 22, 34, 24, 31,\n                                  41, 33, 45, 52, 59, 24, 24, 37, 30, 62, 0, 55,\n                                  59, 55, 53, 52, 47, 44, 43, 39, 32, 28, 23,\n                                  17, 12, 70, 75, 74, 85, 14, 14, 11, 12, 1, 1,\n                                  0, 10, 70, 73, 72, 84, 77, 106, 89, 7, 9, 10,\n                                  2, 66, 71, 75, 77, 93, 80, 27, 15, 9, 64, 1,\n                                  74, 82, 86, 94, 65, 29, 21, 16, 14, 7, 1, 65,\n                                  69, 77, 68, 38, 30, 21, 6, 10, 65, 73, 81, 8,\n                                  52, 45, 38, 28, 23, 3, 68, 69, 74, 62, 105,\n                                  101, 90, 100, 99, 88, 94, 90, 85, 91, 89, 89,\n                                  85, 86, 87, 94, 86, 83, 78, 78, 76, 73, 71,\n                                  69, 68, 65, 69, 70, 76, 1, 2, 2, 1, 0, 2, 2,\n                                  4, 1, 0, 1, 3, 65, 69, 73, 69, 0, 74, 10, 16,\n                                  10, 15, 10, 12, 13, 10, 9, 4, 10, 4, 69, 68,\n                                  50, 51, 49, 49, 48, 55, 52, 54, 54, 51, 58,\n                                  54, 48, 39, 22, 62, 62, 61, 60, 48, 46, 32,\n                                  27, 24, 19, 9, 3, 67, 76, 59, 60, 60, 55, 50,\n                                  51, 47, 43, 37, 33, 28, 22, 12, 4, 69, 3, 3,\n                                  71, 19, 18, 15, 10, 9, 9, 2, 3, 64, 68, 82,\n                                  75, 85, 94, 6, 70, 75, 80, 75, 67, 74, 0, 8,\n                                  70, 73, 1, 5, 3, 5, 11, 4, 2, 56, 44, 30, 19,\n                                  10, 67, 78, 93, 104, 66, 39, 28, 23, 13, 15,\n                                  6, 2, 0, 75, 78, 73, 65, 72, 3, 9, 67, 70, 2,\n                                  6, 6, 6, 12, 8, 3, 56, 44, 30, 19, 10, 67, 78,\n                                  93, 104 },\n\n                                {\n\n                                57,\n                                  7, 77, 57, 7, 77, 97, 79, 17, 11, 5, 15, 27,\n                                  46, 57, 18, 87, 67, 64, 65, 6, 4, 66, 64, 2,\n                                  21, 21, 1, 79, 96, 79, 85, 71, 64, 65, 6, 75,\n                                  76, 11, 12, 66, 76, 85, 2, 77, 83, 96, 6, 70,\n                                  78, 4, 77, 78, 89, 64, 75, 71, 83, 66, 2, 22,\n                                  0, 0, 0, 73, 90, 97, 64, 9, 65, 35, 5, 82, 85,\n                                  71, 77, 10, 3, 76, 72, 90, 73, 87, 82, 88, 80,\n                                  83, 86, 87, 24, 65, 68, 89, 70, 91, 81, 94, 5,\n                                  0, 1, 69, 14, 68, 66, 78, 89, 77, 79, 77, 67,\n                                  74, 85, 79, 67, 90, 80, 19, 11, 73, 78, 2, 72,\n                                  66, 0, 2, 10, 1, 68, 80, 82, 71, 9, 10, 80, 9,\n                                  8, 5, 5, 6, 5, 6, 4, 4, 6, 4, 2, 4, 5, 74, 66,\n                                  5, 68, 13, 19, 22, 15, 7, 19, 12, 15, 5, 2,\n                                  10, 9, 20, 89, 14, 25, 22, 39, 51, 29, 34, 48,\n                                  48, 27, 40, 41, 49, 62, 19, 32, 23, 29, 38,\n                                  31, 42, 48, 55, 22, 22, 34, 28, 62, 64, 53,\n                                  57, 53, 51, 50, 45, 42, 41, 37, 30, 26, 22,\n                                  16, 11, 71, 75, 74, 85, 14, 13, 10, 11, 0, 0,\n                                  64, 9, 71, 73, 73, 84, 77, 105, 87, 8, 10, 10,\n                                  3, 65, 70, 74, 76, 90, 78, 28, 16, 10, 0, 2,\n                                  72, 80, 84, 92, 64, 30, 22, 17, 15, 8, 2, 64,\n                                  68, 76, 68, 39, 30, 21, 6, 11, 64, 73, 80, 8,\n                                  52, 45, 37, 27, 23, 4, 67, 68, 73, 62, 103,\n                                  99, 88, 98, 97, 86, 92, 88, 83, 89, 87, 86,\n                                  84, 85, 86, 92, 84, 82, 77, 77, 75, 72, 70,\n                                  69, 68, 65, 69, 70, 76, 2, 3, 3, 2, 0, 3, 3,\n                                  4, 2, 1, 1, 3, 64, 68, 72, 68, 1, 74, 9, 16,\n                                  9, 15, 10, 12, 13, 10, 9, 4, 10, 3, 69, 69,\n                                  49, 50, 49, 48, 47, 53, 50, 52, 52, 49, 56,\n                                  52, 45, 37, 20, 61, 60, 57, 56, 45, 43, 30,\n                                  25, 22, 18, 8, 2, 67, 76, 57, 58, 58, 53, 48,\n                                  49, 45, 40, 35, 31, 26, 20, 11, 3, 70, 3, 3,\n                                  72, 18, 17, 14, 8, 8, 8, 1, 2, 65, 69, 82, 76,\n                                  85, 94, 5, 71, 76, 79, 74, 66, 73, 2, 10, 69,\n                                  72, 2, 6, 4, 6, 12, 4, 2, 55, 42, 28, 16, 7,\n                                  71, 82, 97, 106, 65, 39, 29, 24, 14, 16, 7, 3,\n                                  1, 74, 77, 72, 64, 71, 4, 10, 66, 69, 3, 7, 6,\n                                  7, 13, 8, 3, 55, 42, 28, 16, 7, 71, 82, 97,\n                                  106 },\n\n                                {\n\n                                56,\n                                  7, 77, 56, 7, 77, 95, 78, 17, 11, 5, 14, 25,\n                                  45, 57, 18, 85, 67, 64, 64, 6, 3, 66, 65, 0,\n                                  20, 18, 66, 82, 98, 76, 84, 71, 64, 64, 6, 75,\n                                  75, 11, 11, 66, 76, 84, 2, 77, 83, 96, 6, 70,\n                                  78, 4, 77, 78, 89, 64, 75, 71, 83, 66, 2, 22,\n                                  0, 0, 0, 72, 90, 97, 64, 8, 65, 34, 5, 82, 83,\n                                  70, 76, 12, 5, 75, 71, 88, 72, 86, 81, 86, 80,\n                                  83, 86, 87, 24, 65, 67, 87, 70, 90, 80, 92, 5,\n                                  0, 1, 70, 14, 68, 66, 77, 88, 76, 78, 76, 67,\n                                  73, 84, 78, 66, 89, 79, 24, 15, 70, 75, 2, 72,\n                                  66, 0, 2, 10, 1, 68, 80, 80, 71, 7, 8, 77, 9,\n                                  8, 5, 5, 6, 5, 8, 5, 4, 6, 4, 2, 5, 6, 75, 66,\n                                  5, 68, 12, 18, 21, 15, 6, 19, 12, 15, 4, 2, 9,\n                                  8, 19, 89, 14, 24, 21, 37, 48, 28, 32, 46, 46,\n                                  25, 38, 39, 43, 62, 15, 30, 21, 27, 35, 29,\n                                  39, 44, 51, 19, 20, 31, 26, 62, 66, 51, 55,\n                                  51, 49, 48, 43, 40, 39, 35, 28, 24, 20, 14, 9,\n                                  73, 75, 74, 86, 13, 12, 9, 10, 64, 64, 65, 7,\n                                  72, 73, 74, 85, 78, 104, 86, 9, 10, 10, 3, 64,\n                                  69, 73, 75, 88, 77, 28, 16, 10, 1, 3, 71, 78,\n                                  82, 90, 0, 31, 23, 18, 16, 9, 2, 64, 68, 75,\n                                  68, 40, 30, 20, 6, 11, 64, 73, 80, 8, 52, 44,\n                                  36, 26, 23, 4, 67, 68, 73, 62, 102, 98, 87,\n                                  96, 95, 85, 90, 86, 82, 87, 85, 84, 83, 84,\n                                  86, 91, 82, 82, 77, 77, 74, 72, 70, 69, 68,\n                                  66, 69, 70, 76, 2, 3, 4, 2, 0, 3, 3, 4, 2, 1,\n                                  1, 2, 64, 68, 72, 68, 2, 75, 8, 16, 8, 14, 9,\n                                  11, 13, 9, 8, 4, 10, 2, 69, 70, 48, 49, 48,\n                                  46, 45, 51, 48, 50, 50, 46, 53, 49, 42, 34,\n                                  18, 57, 56, 53, 51, 42, 40, 27, 23, 19, 16, 6,\n                                  1, 68, 77, 55, 56, 55, 51, 45, 46, 42, 37, 33,\n                                  28, 24, 17, 9, 1, 72, 2, 2, 74, 17, 16, 12, 6,\n                                  6, 6, 64, 1, 67, 70, 83, 77, 86, 95, 3, 72,\n                                  77, 79, 74, 65, 73, 3, 11, 69, 71, 3, 7, 4, 6,\n                                  13, 4, 2, 54, 40, 25, 13, 4, 75, 86, 101, 109,\n                                  65, 39, 29, 24, 14, 17, 7, 3, 1, 74, 77, 72,\n                                  64, 71, 5, 11, 66, 69, 3, 7, 6, 7, 14, 8, 3,\n                                  54, 40, 25, 13, 4, 75, 86, 101, 109 },\n\n                                {\n\n                                55,\n                                  7, 77, 55, 7, 77, 93, 76, 18, 11, 4, 12, 23,\n                                  44, 57, 18, 83, 67, 0, 0, 6, 3, 66, 65, 64,\n                                  19, 16, 69, 84, 99, 73, 83, 71, 0, 0, 6, 76,\n                                  74, 11, 11, 66, 76, 84, 2, 77, 83, 96, 6, 70,\n                                  77, 4, 77, 77, 89, 64, 75, 71, 83, 66, 2, 22,\n                                  0, 0, 0, 72, 90, 97, 0, 7, 65, 33, 4, 82, 80,\n                                  69, 75, 13, 7, 73, 69, 86, 70, 85, 80, 84, 80,\n                                  83, 85, 87, 24, 65, 66, 85, 70, 89, 80, 90, 5,\n                                  64, 0, 70, 14, 68, 65, 77, 87, 75, 78, 75, 66,\n                                  72, 82, 76, 66, 88, 78, 29, 20, 67, 72, 2, 72,\n                                  66, 1, 2, 10, 2, 67, 79, 78, 71, 5, 6, 74, 9,\n                                  8, 5, 5, 6, 6, 9, 6, 4, 6, 4, 2, 5, 7, 76, 66,\n                                  5, 69, 12, 17, 21, 15, 6, 19, 12, 15, 3, 2, 8,\n                                  7, 19, 89, 14, 24, 21, 35, 45, 27, 30, 44, 43,\n                                  23, 35, 37, 36, 62, 12, 28, 19, 25, 32, 26,\n                                  36, 40, 47, 16, 18, 27, 24, 62, 68, 49, 53,\n                                  49, 46, 45, 41, 38, 37, 33, 26, 22, 18, 12, 8,\n                                  75, 75, 74, 86, 12, 11, 8, 9, 65, 65, 66, 5,\n                                  73, 74, 75, 86, 78, 104, 84, 10, 11, 10, 3, 0,\n                                  69, 73, 75, 86, 76, 28, 16, 11, 2, 4, 70, 77,\n                                  81, 88, 1, 31, 23, 18, 16, 10, 3, 64, 68, 75,\n                                  68, 40, 30, 19, 6, 11, 64, 73, 79, 8, 51, 44,\n                                  35, 25, 23, 4, 67, 68, 73, 62, 101, 96, 86,\n                                  95, 94, 84, 88, 84, 81, 86, 83, 82, 83, 83,\n                                  85, 90, 80, 81, 77, 77, 74, 71, 70, 69, 68,\n                                  66, 69, 70, 77, 3, 4, 5, 2, 0, 4, 3, 4, 2, 1,\n                                  1, 2, 64, 68, 72, 68, 2, 76, 7, 16, 7, 13, 8,\n                                  11, 13, 8, 7, 4, 10, 1, 69, 71, 47, 48, 47,\n                                  45, 43, 49, 46, 48, 47, 44, 50, 46, 39, 32,\n                                  16, 53, 52, 49, 46, 38, 37, 25, 21, 17, 14, 4,\n                                  64, 69, 78, 53, 53, 53, 48, 42, 44, 40, 34,\n                                  30, 26, 21, 14, 7, 64, 73, 1, 1, 75, 15, 14,\n                                  10, 4, 5, 4, 66, 0, 68, 71, 84, 78, 87, 96, 2,\n                                  73, 78, 79, 73, 65, 72, 4, 12, 69, 71, 3, 7,\n                                  4, 7, 14, 4, 2, 53, 38, 23, 10, 1, 79, 90,\n                                  105, 112, 65, 39, 29, 24, 14, 17, 8, 3, 1, 73,\n                                  77, 72, 0, 70, 6, 12, 66, 68, 3, 7, 6, 7, 14,\n                                  8, 3, 53, 38, 23, 10, 1, 79, 90, 105, 112 },\n\n                                {\n\n                                53,\n                                  7, 77, 53, 7, 77, 92, 75, 18, 11, 4, 11, 21,\n                                  43, 57, 17, 81, 67, 0, 1, 5, 2, 66, 66, 66,\n                                  18, 13, 73, 87, 101, 70, 82, 71, 0, 1, 5, 76,\n                                  73, 11, 10, 66, 75, 83, 2, 77, 83, 96, 6, 70,\n                                  77, 4, 77, 77, 88, 64, 75, 71, 83, 65, 2, 22,\n                                  0, 0, 0, 71, 91, 97, 0, 6, 65, 32, 4, 82, 78,\n                                  68, 74, 15, 9, 72, 68, 85, 69, 83, 79, 82, 80,\n                                  82, 85, 87, 24, 65, 65, 83, 70, 89, 79, 88, 5,\n                                  64, 0, 71, 14, 68, 65, 76, 86, 74, 77, 74, 66,\n                                  72, 81, 75, 65, 87, 77, 34, 24, 64, 69, 2, 71,\n                                  66, 1, 2, 10, 2, 67, 79, 76, 71, 3, 4, 72, 9,\n                                  9, 5, 5, 6, 6, 11, 7, 5, 5, 4, 2, 6, 7, 77,\n                                  66, 5, 69, 11, 16, 20, 14, 5, 19, 12, 15, 2,\n                                  2, 7, 6, 18, 89, 13, 23, 20, 33, 41, 26, 28,\n                                  42, 41, 21, 33, 35, 30, 62, 8, 26, 17, 22, 29,\n                                  24, 32, 35, 43, 13, 16, 24, 22, 62, 69, 47,\n                                  51, 46, 44, 43, 39, 36, 35, 31, 23, 20, 16,\n                                  10, 6, 77, 75, 74, 87, 11, 10, 7, 7, 66, 67,\n                                  67, 4, 74, 74, 76, 86, 79, 103, 83, 11, 11,\n                                  10, 4, 0, 68, 72, 74, 84, 74, 28, 17, 11, 2,\n                                  5, 69, 75, 79, 87, 1, 32, 24, 19, 17, 11, 3,\n                                  64, 67, 74, 68, 41, 30, 19, 5, 11, 64, 73, 79,\n                                  8, 51, 43, 34, 24, 23, 4, 66, 68, 73, 62, 99,\n                                  95, 85, 93, 92, 83, 87, 83, 80, 84, 82, 80,\n                                  82, 82, 85, 89, 79, 81, 77, 77, 73, 71, 70,\n                                  70, 68, 67, 69, 70, 77, 3, 4, 6, 2, 0, 4, 3,\n                                  4, 2, 1, 1, 1, 64, 68, 72, 68, 3, 77, 6, 16,\n                                  6, 13, 7, 10, 13, 7, 6, 4, 10, 0, 69, 72, 46,\n                                  47, 46, 43, 41, 47, 44, 45, 45, 41, 47, 43,\n                                  36, 29, 14, 48, 48, 45, 41, 35, 33, 22, 18,\n                                  14, 12, 2, 65, 70, 78, 50, 51, 50, 46, 39, 41,\n                                  37, 31, 28, 23, 19, 11, 5, 66, 75, 0, 1, 77,\n                                  14, 13, 9, 2, 3, 2, 67, 64, 70, 72, 85, 80,\n                                  88, 96, 0, 75, 80, 78, 73, 64, 72, 5, 13, 69,\n                                  70, 4, 8, 4, 7, 15, 4, 2, 52, 36, 20, 7, 66,\n                                  83, 95, 109, 115, 64, 39, 29, 24, 14, 18, 8,\n                                  3, 1, 73, 77, 72, 0, 70, 6, 13, 66, 68, 4, 8,\n                                  6, 7, 15, 8, 3, 52, 36, 20, 7, 66, 83, 95,\n                                  109, 115 },\n\n                                {\n\n                                52,\n                                  7, 77, 52, 7, 77, 90, 73, 18, 11, 3, 10, 19,\n                                  42, 57, 17, 79, 67, 0, 2, 5, 2, 66, 67, 68,\n                                  17, 11, 76, 89, 103, 67, 81, 70, 0, 2, 5, 76,\n                                  72, 11, 10, 66, 75, 82, 2, 77, 83, 96, 6, 70,\n                                  77, 4, 77, 76, 88, 64, 75, 71, 83, 65, 2, 22,\n                                  0, 0, 0, 71, 91, 97, 1, 5, 65, 31, 3, 82, 75,\n                                  67, 73, 17, 11, 70, 66, 83, 67, 82, 78, 79,\n                                  80, 82, 84, 86, 24, 65, 64, 81, 70, 88, 79,\n                                  86, 5, 65, 64, 71, 14, 68, 64, 76, 85, 73, 77,\n                                  73, 65, 71, 79, 73, 64, 85, 76, 39, 28, 2, 66,\n                                  3, 71, 65, 2, 2, 10, 3, 67, 78, 74, 71, 1, 2,\n                                  69, 9, 9, 5, 5, 6, 7, 12, 8, 5, 5, 4, 2, 6, 8,\n                                  78, 65, 5, 70, 11, 15, 20, 14, 5, 19, 12, 15,\n                                  1, 3, 6, 6, 18, 89, 13, 22, 19, 31, 38, 25,\n                                  27, 40, 39, 19, 30, 33, 24, 62, 5, 24, 15, 20,\n                                  26, 21, 29, 31, 39, 11, 14, 20, 20, 62, 71,\n                                  45, 49, 44, 42, 41, 37, 34, 33, 29, 21, 18,\n                                  14, 9, 4, 79, 75, 74, 87, 10, 9, 6, 6, 67, 68,\n                                  68, 2, 75, 75, 77, 87, 80, 102, 81, 12, 12,\n                                  10, 4, 1, 68, 72, 73, 82, 73, 28, 17, 12, 3,\n                                  6, 68, 74, 78, 85, 2, 33, 25, 20, 17, 12, 4,\n                                  0, 67, 74, 68, 41, 30, 18, 5, 11, 64, 73, 78,\n                                  8, 50, 42, 33, 23, 23, 4, 66, 68, 72, 62, 98,\n                                  93, 83, 91, 91, 82, 85, 81, 79, 82, 80, 78,\n                                  81, 81, 84, 88, 77, 81, 77, 76, 73, 70, 70,\n                                  70, 68, 67, 69, 70, 78, 4, 4, 7, 2, 0, 4, 3,\n                                  4, 2, 1, 1, 1, 64, 68, 72, 68, 3, 78, 5, 16,\n                                  5, 12, 7, 9, 13, 7, 5, 4, 10, 64, 69, 73, 45,\n                                  46, 45, 41, 39, 45, 42, 43, 42, 38, 44, 40,\n                                  33, 27, 12, 44, 44, 41, 36, 32, 30, 20, 16,\n                                  12, 10, 1, 67, 70, 79, 48, 48, 48, 44, 36, 38,\n                                  35, 28, 26, 21, 17, 8, 3, 68, 76, 0, 0, 79,\n                                  13, 11, 7, 0, 1, 0, 69, 65, 71, 73, 85, 81,\n                                  89, 97, 64, 76, 81, 78, 73, 0, 71, 6, 14, 68,\n                                  69, 4, 8, 4, 8, 16, 4, 2, 51, 34, 17, 4, 69,\n                                  87, 99, 113, 118, 64, 39, 29, 24, 14, 18, 8,\n                                  4, 2, 72, 77, 72, 1, 70, 7, 14, 66, 68, 4, 8,\n                                  6, 8, 15, 8, 3, 51, 34, 17, 4, 69, 87, 99,\n                                  113, 118 },\n\n                                {\n\n                                51,\n                                  7, 78, 51, 7, 78, 88, 72, 19, 11, 3, 8, 17,\n                                  41, 57, 17, 78, 67, 1, 2, 5, 1, 65, 67, 69,\n                                  15, 8, 80, 92, 104, 65, 80, 70, 1, 2, 5, 77,\n                                  72, 11, 9, 66, 75, 82, 2, 77, 82, 95, 6, 69,\n                                  76, 4, 76, 76, 88, 64, 75, 71, 83, 65, 2, 22,\n                                  0, 0, 0, 70, 91, 97, 1, 5, 66, 31, 3, 82, 73,\n                                  66, 72, 18, 14, 69, 65, 81, 66, 81, 77, 77,\n                                  80, 82, 84, 86, 24, 65, 0, 78, 70, 87, 78, 84,\n                                  4, 65, 64, 72, 15, 68, 64, 75, 85, 73, 76, 72,\n                                  65, 70, 78, 72, 64, 84, 75, 44, 33, 5, 0, 3,\n                                  71, 65, 2, 2, 10, 3, 66, 78, 72, 70, 64, 0,\n                                  66, 9, 9, 5, 5, 7, 7, 14, 9, 5, 5, 4, 2, 7, 9,\n                                  79, 65, 5, 70, 10, 14, 19, 14, 4, 19, 12, 15,\n                                  64, 3, 5, 5, 17, 89, 13, 22, 19, 29, 35, 24,\n                                  25, 37, 36, 17, 28, 31, 17, 62, 1, 22, 14, 18,\n                                  22, 19, 26, 27, 34, 8, 12, 17, 18, 62, 73, 43,\n                                  47, 42, 39, 38, 35, 31, 31, 27, 19, 15, 12, 7,\n                                  3, 80, 75, 74, 88, 9, 8, 5, 5, 68, 69, 69, 0,\n                                  76, 75, 78, 88, 80, 102, 80, 13, 12, 10, 4, 2,\n                                  67, 71, 73, 80, 72, 29, 17, 12, 4, 7, 67, 72,\n                                  76, 83, 3, 33, 25, 20, 18, 13, 4, 0, 67, 73,\n                                  68, 42, 30, 17, 5, 11, 64, 73, 78, 7, 50, 42,\n                                  32, 22, 22, 4, 66, 68, 72, 62, 97, 92, 82, 90,\n                                  89, 81, 83, 79, 78, 81, 78, 76, 81, 80, 84,\n                                  87, 75, 80, 77, 76, 72, 70, 70, 70, 68, 68,\n                                  69, 70, 78, 4, 5, 8, 2, 0, 5, 4, 4, 3, 2, 1,\n                                  0, 64, 68, 72, 68, 4, 79, 4, 16, 4, 11, 6, 9,\n                                  13, 6, 5, 4, 9, 66, 70, 74, 43, 45, 44, 40,\n                                  37, 43, 40, 41, 40, 36, 41, 38, 30, 24, 10,\n                                  40, 40, 37, 32, 28, 27, 17, 14, 9, 8, 64, 68,\n                                  71, 80, 46, 46, 45, 41, 33, 36, 32, 25, 23,\n                                  18, 14, 5, 1, 69, 78, 64, 64, 80, 11, 10, 5,\n                                  65, 0, 65, 71, 66, 73, 74, 86, 82, 90, 98, 66,\n                                  77, 82, 78, 72, 0, 71, 7, 15, 68, 69, 5, 9, 4,\n                                  8, 17, 4, 2, 50, 32, 15, 1, 72, 91, 103, 117,\n                                  121, 64, 39, 29, 24, 14, 19, 9, 4, 2, 72, 76,\n                                  71, 1, 69, 8, 15, 65, 67, 4, 8, 6, 8, 16, 8,\n                                  3, 50, 32, 15, 1, 72, 91, 103, 117, 121 },\n\n                                {\n\n                                50,\n                                  7, 78, 50, 7, 78, 86, 70, 19, 11, 2, 7, 15,\n                                  40, 57, 17, 76, 67, 1, 3, 4, 1, 65, 68, 71,\n                                  14, 6, 83, 94, 106, 1, 79, 70, 1, 3, 4, 77,\n                                  71, 11, 9, 66, 74, 81, 2, 77, 82, 95, 6, 69,\n                                  76, 4, 76, 75, 87, 64, 75, 71, 83, 64, 2, 22,\n                                  0, 0, 0, 70, 91, 97, 2, 4, 66, 30, 2, 82, 70,\n                                  65, 71, 20, 16, 67, 0, 80, 64, 79, 76, 75, 80,\n                                  81, 83, 86, 24, 65, 1, 76, 70, 86, 78, 82, 4,\n                                  66, 65, 72, 15, 68, 0, 75, 84, 72, 76, 71, 64,\n                                  69, 76, 70, 0, 83, 74, 49, 37, 8, 3, 3, 70,\n                                  65, 3, 2, 10, 4, 66, 77, 70, 70, 66, 65, 0, 9,\n                                  10, 5, 5, 7, 8, 15, 10, 6, 4, 4, 2, 7, 9, 80,\n                                  65, 5, 71, 10, 13, 19, 13, 4, 19, 12, 15, 65,\n                                  3, 4, 4, 17, 89, 13, 21, 18, 27, 32, 23, 23,\n                                  35, 34, 15, 25, 29, 11, 62, 65, 20, 12, 15,\n                                  19, 16, 23, 22, 30, 5, 10, 13, 16, 62, 74, 41,\n                                  45, 40, 37, 36, 33, 29, 29, 25, 16, 13, 10, 5,\n                                  1, 82, 75, 74, 88, 8, 7, 4, 3, 69, 70, 70, 64,\n                                  77, 76, 79, 88, 81, 101, 78, 14, 13, 10, 5, 2,\n                                  67, 71, 72, 78, 70, 29, 18, 13, 4, 8, 66, 71,\n                                  75, 81, 3, 34, 26, 21, 18, 14, 5, 0, 66, 73,\n                                  68, 42, 30, 17, 4, 11, 64, 73, 77, 7, 49, 41,\n                                  31, 21, 22, 4, 65, 68, 72, 62, 95, 90, 81, 88,\n                                  88, 80, 82, 78, 77, 79, 77, 74, 80, 79, 83,\n                                  86, 73, 80, 77, 76, 72, 69, 70, 71, 68, 68,\n                                  69, 70, 79, 5, 5, 9, 2, 0, 5, 4, 4, 3, 2, 1,\n                                  0, 64, 68, 72, 68, 4, 80, 3, 16, 3, 11, 5, 8,\n                                  13, 5, 4, 4, 9, 67, 70, 75, 42, 44, 43, 38,\n                                  35, 41, 38, 38, 37, 33, 38, 35, 27, 22, 8, 35,\n                                  36, 33, 27, 25, 24, 15, 12, 7, 6, 66, 70, 72,\n                                  80, 43, 43, 43, 39, 30, 33, 30, 22, 21, 16,\n                                  12, 2, 64, 71, 79, 65, 64, 82, 10, 8, 4, 67,\n                                  65, 67, 72, 67, 74, 75, 87, 84, 91, 98, 67,\n                                  79, 84, 77, 72, 1, 70, 8, 16, 68, 68, 5, 9, 4,\n                                  9, 18, 4, 2, 49, 30, 12, 65, 76, 95, 107, 121,\n                                  124, 0, 39, 29, 24, 14, 19, 9, 4, 2, 71, 76,\n                                  71, 2, 69, 9, 16, 65, 67, 5, 9, 6, 8, 16, 8,\n                                  3, 49, 30, 12, 65, 76, 95, 107, 121, 124 },\n\n                                {\n\n                                48,\n                                  6, 78, 48, 6, 78, 85, 69, 19, 11, 2, 5, 12,\n                                  39, 57, 16, 74, 68, 1, 4, 4, 0, 65, 69, 73,\n                                  13, 3, 87, 97, 108, 4, 78, 70, 1, 4, 4, 78,\n                                  70, 11, 8, 66, 74, 81, 1, 78, 82, 95, 6, 69,\n                                  76, 4, 76, 75, 87, 64, 75, 71, 83, 64, 2, 22,\n                                  0, 0, 0, 69, 92, 97, 2, 3, 66, 29, 2, 83, 68,\n                                  64, 70, 21, 18, 66, 1, 78, 0, 78, 75, 73, 80,\n                                  81, 83, 86, 24, 65, 2, 74, 70, 86, 77, 80, 4,\n                                  66, 65, 73, 15, 68, 0, 74, 83, 71, 75, 71, 64,\n                                  69, 75, 69, 0, 82, 73, 53, 41, 11, 5, 3, 70,\n                                  65, 3, 1, 10, 4, 66, 77, 68, 70, 68, 67, 2, 9,\n                                  10, 5, 5, 7, 8, 17, 10, 6, 4, 3, 2, 8, 10, 82,\n                                  65, 5, 71, 9, 11, 18, 13, 3, 19, 12, 14, 66,\n                                  3, 3, 3, 16, 89, 12, 20, 17, 25, 28, 21, 21,\n                                  33, 31, 12, 23, 27, 4, 62, 69, 18, 10, 13, 16,\n                                  14, 19, 18, 26, 2, 8, 10, 14, 62, 76, 39, 42,\n                                  37, 34, 33, 30, 27, 26, 23, 14, 11, 8, 3, 64,\n                                  84, 75, 75, 89, 7, 5, 3, 2, 70, 72, 72, 66,\n                                  78, 76, 80, 89, 82, 101, 77, 15, 13, 10, 5, 3,\n                                  66, 70, 72, 76, 69, 29, 18, 13, 5, 9, 65, 69,\n                                  73, 80, 4, 34, 26, 21, 19, 15, 5, 0, 66, 72,\n                                  69, 43, 30, 16, 4, 11, 64, 73, 77, 7, 49, 40,\n                                  30, 20, 22, 4, 65, 68, 72, 62, 94, 89, 80, 87,\n                                  86, 79, 80, 76, 76, 78, 75, 72, 80, 79, 83,\n                                  85, 72, 80, 77, 76, 71, 69, 70, 71, 68, 69,\n                                  69, 70, 79, 5, 5, 10, 2, 64, 5, 4, 3, 3, 2, 1,\n                                  64, 64, 68, 72, 68, 5, 81, 2, 16, 1, 10, 4, 7,\n                                  12, 4, 3, 4, 9, 68, 70, 77, 41, 42, 42, 36,\n                                  33, 39, 36, 36, 35, 30, 35, 32, 24, 19, 6, 31,\n                                  32, 28, 22, 21, 20, 12, 9, 4, 4, 68, 71, 73,\n                                  81, 41, 41, 40, 36, 27, 30, 27, 19, 18, 13, 9,\n                                  64, 66, 73, 81, 66, 65, 84, 8, 7, 2, 69, 67,\n                                  69, 74, 69, 76, 77, 88, 85, 92, 99, 69, 80,\n                                  85, 77, 72, 1, 70, 9, 17, 68, 68, 6, 10, 4, 9,\n                                  18, 4, 1, 48, 28, 9, 68, 79, 99, 112, 126,\n                                  126, 0, 39, 29, 24, 14, 20, 9, 4, 2, 71, 76,\n                                  71, 2, 69, 9, 16, 65, 67, 5, 9, 6, 8, 17, 8,\n                                  2, 48, 28, 9, 68, 79, 99, 112, 126, 126 },\n\n                                {\n\n                                47,\n                                  6, 78, 47, 6, 78, 83, 68, 20, 11, 2, 4, 10,\n                                  38, 58, 16, 72, 68, 2, 5, 4, 64, 65, 69, 74,\n                                  12, 1, 91, 100, 109, 7, 77, 69, 2, 5, 4, 78,\n                                  69, 11, 8, 65, 74, 80, 1, 78, 82, 95, 6, 69,\n                                  75, 4, 76, 75, 87, 64, 75, 71, 82, 64, 2, 22,\n                                  0, 0, 0, 68, 92, 97, 2, 2, 66, 28, 2, 83, 66,\n                                  1, 69, 23, 20, 64, 2, 76, 2, 77, 73, 70, 80,\n                                  81, 83, 85, 24, 65, 3, 72, 69, 85, 76, 78, 4,\n                                  66, 65, 73, 15, 68, 0, 73, 82, 70, 74, 70, 0,\n                                  68, 74, 67, 1, 80, 72, 58, 46, 15, 8, 4, 70,\n                                  64, 4, 1, 10, 4, 65, 76, 65, 70, 70, 68, 5, 9,\n                                  10, 5, 5, 7, 9, 19, 11, 6, 4, 3, 2, 9, 11, 83,\n                                  64, 5, 71, 8, 10, 17, 13, 2, 19, 12, 14, 67,\n                                  4, 2, 3, 15, 89, 12, 20, 17, 23, 25, 20, 20,\n                                  31, 29, 10, 21, 25, 65, 62, 72, 16, 8, 11, 13,\n                                  12, 16, 14, 22, 0, 6, 7, 12, 62, 78, 37, 40,\n                                  35, 32, 31, 28, 25, 24, 21, 12, 9, 7, 2, 65,\n                                  86, 75, 75, 89, 7, 4, 2, 1, 71, 73, 73, 68,\n                                  79, 76, 81, 90, 82, 100, 76, 16, 13, 10, 5, 4,\n                                  65, 69, 71, 73, 68, 29, 18, 13, 6, 10, 64, 67,\n                                  71, 78, 5, 35, 27, 22, 20, 16, 5, 1, 66, 71,\n                                  69, 44, 30, 15, 4, 12, 0, 73, 76, 7, 49, 40,\n                                  29, 19, 22, 4, 65, 68, 71, 62, 93, 88, 78, 85,\n                                  84, 78, 78, 74, 75, 76, 73, 70, 79, 78, 82,\n                                  84, 70, 79, 76, 75, 70, 68, 70, 71, 68, 70,\n                                  69, 70, 79, 5, 6, 11, 3, 64, 6, 4, 3, 3, 2, 1,\n                                  65, 64, 67, 71, 68, 6, 81, 1, 16, 0, 9, 4, 7,\n                                  12, 4, 2, 4, 9, 69, 70, 78, 40, 41, 42, 35,\n                                  31, 37, 34, 34, 33, 28, 32, 29, 21, 16, 4, 27,\n                                  28, 24, 17, 18, 17, 9, 7, 2, 3, 69, 72, 73,\n                                  82, 39, 39, 38, 34, 25, 28, 25, 16, 16, 11, 7,\n                                  66, 68, 75, 83, 66, 66, 85, 7, 6, 0, 71, 68,\n                                  70, 76, 70, 78, 78, 88, 86, 92, 100, 71, 81,\n                                  86, 77, 71, 2, 70, 10, 19, 67, 67, 7, 11, 4,\n                                  10, 19, 4, 1, 47, 26, 7, 71, 82, 103, 116,\n                                  126, 126, 0, 39, 29, 25, 15, 21, 10, 5, 3, 71,\n                                  76, 71, 2, 68, 10, 17, 65, 66, 5, 9, 6, 9, 18,\n                                  8, 2, 47, 26, 7, 71, 82, 103, 116, 126, 126 },\n\n                                {\n\n                                46,\n                                  6, 78, 46, 6, 78, 81, 66, 20, 11, 1, 3, 8, 37,\n                                  58, 16, 70, 68, 2, 6, 3, 64, 65, 70, 76, 11,\n                                  65, 94, 102, 111, 10, 76, 69, 2, 6, 3, 78, 68,\n                                  11, 7, 65, 73, 79, 1, 78, 82, 95, 6, 69, 75,\n                                  4, 76, 74, 86, 64, 75, 71, 82, 0, 2, 22, 0, 0,\n                                  0, 68, 92, 97, 3, 1, 66, 27, 1, 83, 0, 2, 68,\n                                  25, 22, 0, 4, 75, 3, 75, 72, 68, 80, 80, 82,\n                                  85, 24, 65, 4, 70, 69, 84, 76, 76, 4, 67, 66,\n                                  74, 15, 68, 1, 73, 81, 69, 74, 69, 0, 67, 72,\n                                  66, 2, 79, 71, 62, 50, 18, 11, 4, 69, 64, 4,\n                                  1, 10, 5, 65, 76, 0, 70, 72, 70, 8, 9, 11, 5,\n                                  5, 7, 9, 20, 12, 7, 3, 3, 2, 9, 11, 84, 64, 5,\n                                  72, 8, 9, 17, 12, 2, 19, 12, 14, 68, 4, 1, 2,\n                                  15, 89, 12, 19, 16, 21, 22, 19, 18, 29, 27, 8,\n                                  18, 23, 71, 62, 76, 14, 6, 8, 10, 9, 13, 9,\n                                  18, 66, 4, 3, 10, 62, 79, 35, 38, 33, 30, 29,\n                                  26, 23, 22, 19, 9, 7, 5, 0, 67, 88, 75, 75,\n                                  90, 6, 3, 1, 64, 72, 74, 74, 69, 80, 77, 82,\n                                  90, 83, 99, 74, 17, 14, 10, 6, 4, 65, 69, 70,\n                                  71, 66, 29, 19, 14, 6, 11, 0, 66, 70, 76, 5,\n                                  36, 28, 23, 20, 17, 6, 1, 65, 71, 69, 44, 30,\n                                  15, 3, 12, 0, 73, 76, 7, 48, 39, 28, 18, 22,\n                                  4, 64, 68, 71, 62, 91, 86, 77, 83, 83, 77, 77,\n                                  73, 74, 74, 72, 68, 78, 77, 82, 83, 68, 79,\n                                  76, 75, 70, 68, 70, 72, 68, 70, 69, 70, 80, 6,\n                                  6, 12, 3, 64, 6, 4, 3, 3, 2, 1, 65, 64, 67,\n                                  71, 68, 6, 82, 0, 16, 64, 9, 3, 6, 12, 3, 1,\n                                  4, 9, 70, 70, 79, 39, 40, 41, 33, 29, 35, 32,\n                                  31, 30, 25, 29, 26, 18, 14, 2, 22, 24, 20, 12,\n                                  15, 14, 7, 5, 64, 1, 71, 74, 74, 82, 36, 36,\n                                  35, 32, 22, 25, 22, 13, 14, 8, 5, 69, 70, 77,\n                                  84, 67, 66, 87, 6, 4, 64, 73, 70, 72, 77, 71,\n                                  79, 79, 89, 88, 93, 100, 72, 83, 88, 76, 71,\n                                  3, 69, 11, 20, 67, 66, 7, 11, 4, 10, 20, 4, 1,\n                                  46, 24, 4, 74, 86, 107, 120, 126, 126, 1, 39,\n                                  29, 25, 15, 21, 10, 5, 3, 70, 76, 71, 3, 68,\n                                  11, 18, 65, 66, 6, 10, 6, 9, 18, 8, 2, 46, 24,\n                                  4, 74, 86, 107, 120, 126, 126 },\n\n                                {\n\n                                45,\n                                  6, 79, 45, 6, 79, 79, 65, 21, 11, 1, 1, 6, 36,\n                                  58, 16, 69, 68, 3, 6, 3, 65, 64, 70, 77, 9,\n                                  67, 98, 105, 112, 12, 75, 69, 3, 6, 3, 79, 68,\n                                  11, 7, 65, 73, 79, 1, 78, 81, 94, 6, 68, 74,\n                                  4, 75, 74, 86, 64, 75, 71, 82, 0, 2, 22, 0, 0,\n                                  0, 67, 92, 97, 3, 1, 67, 27, 1, 83, 2, 3, 67,\n                                  26, 25, 2, 5, 73, 5, 74, 71, 66, 80, 80, 82,\n                                  85, 24, 65, 5, 67, 69, 83, 75, 74, 3, 67, 66,\n                                  74, 16, 68, 1, 72, 81, 69, 73, 68, 1, 66, 71,\n                                  64, 2, 78, 70, 62, 55, 21, 14, 4, 69, 64, 5,\n                                  1, 10, 5, 64, 75, 2, 69, 74, 72, 11, 9, 11, 5,\n                                  5, 8, 10, 22, 13, 7, 3, 3, 2, 10, 12, 85, 64,\n                                  5, 72, 7, 8, 16, 12, 1, 19, 12, 14, 70, 4, 0,\n                                  1, 14, 89, 12, 19, 16, 19, 19, 18, 16, 26, 24,\n                                  6, 16, 21, 78, 62, 79, 12, 5, 6, 6, 7, 10, 5,\n                                  13, 69, 2, 0, 8, 62, 81, 33, 36, 31, 27, 26,\n                                  24, 20, 20, 17, 7, 4, 3, 65, 68, 89, 75, 75,\n                                  90, 5, 2, 0, 65, 73, 75, 75, 71, 81, 77, 83,\n                                  91, 83, 99, 73, 18, 14, 10, 6, 5, 64, 68, 70,\n                                  69, 65, 30, 19, 14, 7, 12, 1, 64, 68, 74, 6,\n                                  36, 28, 23, 21, 18, 6, 1, 65, 70, 69, 45, 30,\n                                  14, 3, 12, 0, 73, 75, 6, 48, 39, 27, 17, 21,\n                                  4, 64, 68, 71, 62, 90, 85, 76, 82, 81, 76, 75,\n                                  71, 73, 73, 70, 66, 78, 76, 81, 82, 66, 78,\n                                  76, 75, 69, 67, 70, 72, 68, 71, 69, 70, 80, 6,\n                                  7, 13, 3, 64, 7, 5, 3, 4, 3, 1, 66, 64, 67,\n                                  71, 68, 7, 83, 64, 16, 65, 8, 2, 6, 12, 2, 1,\n                                  4, 8, 72, 71, 80, 37, 39, 40, 32, 27, 33, 30,\n                                  29, 28, 23, 26, 24, 15, 11, 0, 18, 20, 16, 8,\n                                  11, 11, 4, 3, 66, 64, 73, 75, 75, 83, 34, 34,\n                                  33, 29, 19, 23, 20, 10, 11, 6, 2, 72, 72, 78,\n                                  86, 68, 67, 88, 4, 3, 66, 75, 71, 74, 79, 72,\n                                  81, 80, 90, 89, 94, 101, 74, 84, 89, 76, 70,\n                                  3, 69, 12, 21, 67, 66, 8, 12, 4, 11, 21, 4, 1,\n                                  45, 22, 2, 77, 89, 111, 124, 126, 126, 1, 39,\n                                  29, 25, 15, 22, 11, 5, 3, 70, 75, 70, 3, 67,\n                                  12, 19, 64, 65, 6, 10, 6, 9, 19, 8, 2, 45, 22,\n                                  2, 77, 89, 111, 124, 126, 126 },\n\n                                {\n\n                                43,\n                                  6, 79, 43, 6, 79, 78, 0, 21, 11, 0, 0, 4, 35,\n                                  58, 15, 67, 68, 3, 7, 3, 65, 64, 71, 79, 8,\n                                  70, 101, 107, 114, 15, 74, 69, 3, 7, 3, 79,\n                                  67, 11, 6, 65, 73, 78, 1, 78, 81, 94, 6, 68,\n                                  74, 4, 75, 73, 86, 64, 75, 71, 82, 0, 2, 22,\n                                  0, 0, 0, 67, 93, 97, 4, 0, 67, 26, 0, 83, 5,\n                                  4, 66, 28, 27, 3, 7, 71, 6, 73, 70, 64, 80,\n                                  80, 81, 85, 24, 65, 6, 65, 69, 83, 75, 72, 3,\n                                  68, 67, 75, 16, 68, 2, 72, 80, 68, 73, 67, 1,\n                                  66, 69, 0, 3, 77, 69, 62, 59, 24, 17, 4, 69,\n                                  64, 5, 1, 10, 6, 64, 75, 4, 69, 76, 74, 13, 9,\n                                  11, 5, 5, 8, 10, 23, 14, 7, 3, 3, 2, 10, 13,\n                                  86, 64, 5, 73, 7, 7, 16, 12, 1, 19, 12, 14,\n                                  71, 4, 64, 0, 14, 89, 11, 18, 15, 17, 15, 17,\n                                  14, 24, 22, 4, 13, 19, 84, 62, 83, 10, 3, 4,\n                                  3, 4, 6, 1, 9, 72, 0, 67, 6, 62, 83, 31, 34,\n                                  28, 25, 24, 22, 18, 18, 15, 5, 2, 1, 67, 70,\n                                  91, 75, 75, 91, 4, 1, 64, 66, 74, 77, 76, 73,\n                                  82, 78, 84, 92, 84, 98, 71, 19, 15, 10, 6, 6,\n                                  64, 68, 69, 67, 64, 30, 19, 15, 8, 13, 2, 0,\n                                  67, 73, 7, 37, 29, 24, 21, 19, 7, 1, 65, 70,\n                                  69, 45, 30, 13, 3, 12, 0, 73, 75, 6, 47, 38,\n                                  26, 16, 21, 4, 64, 68, 71, 62, 89, 83, 75, 80,\n                                  80, 75, 73, 69, 72, 71, 68, 64, 77, 75, 81,\n                                  81, 65, 78, 76, 75, 69, 67, 70, 72, 68, 71,\n                                  69, 70, 81, 7, 7, 14, 3, 64, 7, 5, 3, 4, 3, 1,\n                                  66, 64, 67, 71, 68, 7, 84, 65, 16, 66, 7, 1,\n                                  5, 12, 1, 0, 4, 8, 73, 71, 81, 36, 38, 39, 30,\n                                  25, 31, 28, 27, 25, 20, 23, 21, 12, 9, 65, 14,\n                                  16, 12, 3, 8, 7, 2, 0, 69, 66, 75, 77, 76, 84,\n                                  32, 31, 30, 27, 16, 20, 17, 7, 9, 3, 0, 75,\n                                  74, 80, 87, 69, 68, 90, 3, 1, 68, 77, 73, 76,\n                                  81, 73, 82, 81, 91, 90, 95, 102, 75, 85, 90,\n                                  76, 70, 4, 68, 13, 22, 67, 65, 8, 12, 4, 11,\n                                  22, 4, 1, 44, 20, 64, 80, 92, 115, 126, 126,\n                                  126, 1, 39, 29, 25, 15, 22, 11, 5, 3, 69, 75,\n                                  70, 4, 67, 12, 20, 64, 65, 6, 10, 6, 9, 19, 8,\n                                  2, 44, 20, 64, 80, 92, 115, 126, 126, 126 },\n\n                                {\n\n                                42,\n                                  6, 79, 42, 6, 79, 76, 1, 21, 11, 0, 64, 2, 34,\n                                  58, 15, 65, 68, 3, 8, 2, 66, 64, 72, 81, 7,\n                                  72, 105, 110, 116, 18, 73, 68, 3, 8, 2, 79,\n                                  66, 11, 6, 65, 72, 77, 1, 78, 81, 94, 6, 68,\n                                  74, 4, 75, 73, 85, 64, 75, 71, 82, 1, 2, 22,\n                                  0, 0, 0, 66, 93, 97, 4, 64, 67, 25, 0, 83, 7,\n                                  5, 65, 30, 29, 5, 8, 70, 8, 71, 69, 2, 80, 79,\n                                  81, 84, 24, 65, 7, 0, 69, 82, 74, 70, 3, 68,\n                                  67, 75, 16, 68, 2, 71, 79, 67, 72, 66, 2, 65,\n                                  68, 2, 4, 75, 68, 62, 62, 27, 20, 5, 68, 0, 6,\n                                  1, 10, 6, 64, 74, 6, 69, 78, 76, 16, 9, 12, 5,\n                                  5, 8, 11, 25, 15, 8, 2, 3, 2, 11, 13, 87, 0,\n                                  5, 73, 6, 6, 15, 11, 0, 19, 12, 14, 72, 5, 65,\n                                  0, 13, 89, 11, 17, 14, 15, 12, 16, 13, 22, 20,\n                                  2, 11, 17, 90, 62, 86, 8, 1, 1, 0, 2, 3, 67,\n                                  5, 74, 65, 70, 4, 62, 84, 29, 32, 26, 23, 22,\n                                  20, 16, 16, 13, 2, 0, 64, 68, 72, 93, 75, 75,\n                                  91, 3, 0, 65, 68, 75, 78, 77, 74, 83, 78, 85,\n                                  92, 85, 97, 70, 20, 15, 10, 7, 6, 0, 67, 68,\n                                  65, 1, 30, 20, 15, 8, 14, 3, 2, 65, 71, 7, 38,\n                                  30, 25, 22, 20, 7, 2, 64, 69, 69, 46, 30, 13,\n                                  2, 12, 0, 73, 74, 6, 47, 37, 25, 15, 21, 4, 0,\n                                  68, 70, 62, 87, 82, 73, 78, 78, 74, 72, 68,\n                                  71, 69, 67, 1, 76, 74, 80, 80, 0, 78, 76, 74,\n                                  68, 66, 70, 73, 68, 72, 69, 70, 81, 7, 7, 15,\n                                  3, 64, 7, 5, 3, 4, 3, 1, 67, 64, 67, 71, 68,\n                                  8, 85, 66, 16, 67, 7, 1, 4, 12, 1, 64, 4, 8,\n                                  74, 71, 82, 35, 37, 38, 28, 23, 29, 26, 24,\n                                  23, 17, 20, 18, 9, 6, 67, 9, 12, 8, 65, 5, 4,\n                                  64, 65, 71, 68, 76, 78, 76, 84, 29, 29, 28,\n                                  25, 13, 17, 15, 4, 7, 1, 65, 78, 76, 82, 89,\n                                  69, 68, 92, 2, 0, 69, 79, 75, 78, 82, 74, 84,\n                                  82, 91, 92, 96, 102, 77, 87, 92, 75, 70, 5,\n                                  68, 14, 23, 66, 64, 9, 13, 4, 12, 23, 4, 1,\n                                  43, 18, 67, 83, 96, 119, 126, 126, 126, 2, 39,\n                                  29, 25, 15, 23, 11, 6, 4, 69, 75, 70, 4, 67,\n                                  13, 21, 64, 65, 7, 11, 6, 10, 20, 8, 2, 43,\n                                  18, 67, 83, 96, 119, 126, 126, 126 },\n\n                                {\n\n                                41,\n                                  6, 79, 41, 6, 79, 74, 3, 22, 11, 64, 66, 0,\n                                  33, 58, 15, 0, 68, 4, 9, 2, 66, 64, 72, 82, 6,\n                                  75, 108, 112, 117, 21, 72, 68, 4, 9, 2, 80,\n                                  65, 11, 5, 65, 72, 77, 1, 78, 81, 94, 6, 68,\n                                  73, 4, 75, 72, 85, 64, 75, 71, 82, 1, 2, 22,\n                                  0, 0, 0, 66, 93, 97, 5, 65, 67, 24, 64, 83,\n                                  10, 6, 64, 31, 31, 6, 10, 68, 9, 70, 68, 4,\n                                  80, 79, 80, 84, 24, 65, 8, 2, 69, 81, 74, 68,\n                                  3, 69, 68, 76, 16, 68, 3, 71, 78, 66, 72, 65,\n                                  2, 64, 66, 3, 4, 74, 67, 62, 62, 30, 23, 5,\n                                  68, 0, 6, 1, 10, 7, 0, 74, 8, 69, 80, 78, 19,\n                                  9, 12, 5, 5, 8, 11, 26, 16, 8, 2, 3, 2, 11,\n                                  14, 88, 0, 5, 74, 6, 5, 15, 11, 0, 19, 12, 14,\n                                  73, 5, 66, 64, 13, 89, 11, 17, 14, 13, 9, 15,\n                                  11, 20, 17, 0, 8, 15, 97, 62, 90, 6, 64, 64,\n                                  66, 64, 0, 71, 1, 77, 67, 74, 2, 62, 86, 27,\n                                  30, 24, 20, 19, 18, 14, 14, 11, 0, 65, 66, 70,\n                                  73, 95, 75, 75, 92, 2, 64, 66, 69, 76, 79, 78,\n                                  76, 84, 79, 86, 93, 85, 97, 68, 21, 16, 10, 7,\n                                  7, 0, 67, 68, 0, 2, 30, 20, 16, 9, 15, 4, 3,\n                                  64, 69, 8, 38, 30, 25, 22, 21, 8, 2, 64, 69,\n                                  69, 46, 30, 12, 2, 12, 0, 73, 74, 6, 46, 37,\n                                  24, 14, 21, 4, 0, 68, 70, 62, 86, 80, 72, 77,\n                                  77, 73, 70, 66, 70, 68, 65, 3, 76, 73, 80, 79,\n                                  2, 77, 76, 74, 68, 66, 70, 73, 68, 72, 69, 70,\n                                  82, 8, 8, 16, 3, 64, 8, 5, 3, 4, 3, 1, 67, 64,\n                                  67, 71, 68, 8, 86, 67, 16, 68, 6, 0, 4, 12, 0,\n                                  65, 4, 8, 75, 71, 83, 34, 36, 37, 27, 21, 27,\n                                  24, 22, 20, 15, 17, 15, 6, 4, 69, 5, 8, 4, 70,\n                                  1, 1, 66, 67, 74, 70, 78, 80, 77, 85, 27, 26,\n                                  25, 22, 10, 15, 12, 1, 4, 65, 68, 81, 78, 84,\n                                  90, 70, 69, 93, 0, 65, 71, 81, 76, 80, 84, 75,\n                                  85, 83, 92, 93, 97, 103, 78, 88, 93, 75, 69,\n                                  5, 67, 15, 24, 66, 64, 9, 13, 4, 12, 24, 4, 1,\n                                  42, 16, 69, 86, 99, 123, 126, 126, 126, 2, 39,\n                                  29, 25, 15, 23, 12, 6, 4, 68, 75, 70, 5, 66,\n                                  14, 22, 64, 64, 7, 11, 6, 10, 20, 8, 2, 42,\n                                  16, 69, 86, 99, 123, 126, 126, 126 },\n\n                                {\n\n                                40,\n                                  6, 79, 40, 6, 79, 72, 4, 22, 11, 64, 67, 65,\n                                  32, 58, 15, 2, 68, 4, 10, 2, 67, 64, 73, 84,\n                                  5, 77, 112, 115, 119, 24, 71, 68, 4, 10, 2,\n                                  80, 64, 11, 5, 65, 72, 76, 1, 78, 81, 94, 6,\n                                  68, 73, 4, 75, 72, 85, 64, 75, 71, 82, 1, 2,\n                                  22, 0, 0, 0, 65, 93, 97, 5, 66, 67, 23, 64,\n                                  83, 12, 7, 0, 33, 33, 8, 11, 66, 11, 69, 67,\n                                  6, 80, 79, 80, 84, 24, 65, 9, 4, 69, 80, 73,\n                                  66, 3, 69, 68, 76, 16, 68, 3, 70, 77, 65, 71,\n                                  64, 3, 0, 65, 5, 5, 73, 66, 62, 62, 33, 26, 5,\n                                  68, 0, 7, 1, 10, 7, 0, 73, 10, 69, 82, 80, 22,\n                                  9, 12, 5, 5, 8, 12, 28, 17, 8, 2, 3, 2, 12,\n                                  15, 89, 0, 5, 74, 5, 4, 14, 11, 64, 19, 12,\n                                  14, 74, 5, 67, 65, 12, 89, 11, 16, 13, 11, 6,\n                                  14, 9, 18, 15, 65, 6, 13, 103, 62, 93, 4, 66,\n                                  66, 69, 66, 66, 75, 66, 80, 69, 77, 0, 62, 88,\n                                  25, 28, 22, 18, 17, 16, 12, 12, 9, 65, 67, 68,\n                                  72, 75, 97, 75, 75, 92, 1, 65, 67, 70, 77, 80,\n                                  79, 78, 85, 79, 87, 94, 86, 96, 67, 22, 16,\n                                  10, 7, 8, 1, 66, 67, 2, 3, 30, 20, 16, 10, 16,\n                                  5, 5, 1, 67, 9, 39, 31, 26, 23, 22, 8, 2, 64,\n                                  68, 69, 47, 30, 11, 2, 12, 0, 73, 73, 6, 46,\n                                  36, 23, 13, 21, 4, 0, 68, 70, 62, 85, 79, 71,\n                                  75, 75, 72, 68, 64, 69, 66, 0, 5, 75, 72, 79,\n                                  78, 4, 77, 76, 74, 67, 65, 70, 73, 68, 73, 69,\n                                  70, 82, 8, 8, 17, 3, 64, 8, 5, 3, 4, 3, 1, 68,\n                                  64, 67, 71, 68, 9, 87, 68, 16, 69, 5, 64, 3,\n                                  12, 64, 66, 4, 8, 76, 71, 84, 33, 35, 36, 25,\n                                  19, 25, 22, 20, 18, 12, 14, 12, 3, 1, 71, 1,\n                                  4, 0, 75, 65, 65, 69, 69, 76, 72, 80, 81, 78,\n                                  86, 25, 24, 23, 20, 7, 12, 10, 65, 2, 67, 70,\n                                  84, 80, 86, 92, 71, 70, 95, 64, 66, 73, 83,\n                                  78, 82, 86, 76, 87, 84, 93, 94, 98, 104, 80,\n                                  89, 94, 75, 69, 6, 67, 16, 25, 66, 0, 10, 14,\n                                  4, 13, 25, 4, 1, 41, 14, 72, 89, 102, 126,\n                                  126, 126, 126, 2, 39, 29, 25, 15, 24, 12, 6,\n                                  4, 68, 75, 70, 5, 66, 15, 23, 64, 64, 7, 11,\n                                  6, 10, 21, 8, 2, 41, 14, 72, 89, 102, 126,\n                                  126, 126, 126 },\n\n                                {\n\n                                38,\n                                  5, 80, 38, 5, 80, 71, 5, 22, 11, 65, 69, 68,\n                                  31, 58, 14, 3, 69, 4, 10, 1, 68, 64, 74, 86,\n                                  3, 80, 116, 118, 121, 26, 71, 68, 4, 10, 1,\n                                  81, 64, 11, 4, 65, 72, 76, 0, 79, 81, 94, 5,\n                                  68, 73, 4, 75, 72, 85, 64, 75, 72, 82, 1, 2,\n                                  22, 0, 0, 0, 65, 94, 97, 5, 67, 68, 22, 65,\n                                  84, 14, 8, 1, 34, 35, 9, 12, 65, 12, 68, 66,\n                                  8, 80, 79, 80, 84, 24, 65, 9, 6, 69, 80, 73,\n                                  65, 2, 70, 69, 77, 16, 68, 3, 70, 77, 65, 71,\n                                  64, 3, 0, 64, 6, 5, 72, 65, 62, 62, 36, 28, 5,\n                                  68, 0, 7, 0, 10, 7, 0, 73, 12, 69, 84, 82, 24,\n                                  9, 12, 5, 5, 8, 12, 29, 17, 8, 1, 2, 2, 12,\n                                  15, 91, 0, 5, 75, 4, 2, 13, 10, 65, 19, 12,\n                                  13, 76, 5, 68, 66, 11, 89, 10, 15, 12, 8, 2,\n                                  12, 7, 15, 12, 68, 3, 11, 110, 62, 97, 1, 68,\n                                  69, 73, 69, 70, 80, 71, 83, 71, 81, 65, 62,\n                                  90, 22, 25, 19, 15, 14, 13, 9, 9, 7, 68, 70,\n                                  70, 74, 77, 99, 75, 76, 93, 0, 67, 69, 72, 79,\n                                  82, 81, 80, 86, 80, 88, 95, 87, 96, 66, 22,\n                                  16, 10, 7, 8, 1, 66, 67, 4, 4, 30, 20, 16, 10,\n                                  16, 6, 6, 2, 66, 9, 39, 31, 26, 23, 23, 8, 2,\n                                  64, 68, 70, 47, 29, 10, 1, 12, 0, 73, 73, 5,\n                                  45, 35, 21, 12, 20, 4, 0, 68, 70, 62, 84, 78,\n                                  70, 74, 74, 71, 67, 0, 68, 65, 1, 7, 75, 72,\n                                  79, 77, 5, 77, 76, 74, 67, 65, 70, 74, 69, 74,\n                                  69, 71, 83, 8, 8, 18, 3, 65, 8, 5, 2, 4, 3, 1,\n                                  69, 64, 67, 71, 68, 9, 88, 69, 16, 71, 4, 65,\n                                  2, 11, 65, 67, 4, 7, 78, 72, 86, 31, 33, 35,\n                                  23, 17, 22, 19, 17, 15, 9, 11, 9, 64, 65, 73,\n                                  67, 0, 68, 80, 69, 69, 72, 72, 79, 74, 82, 83,\n                                  79, 87, 22, 21, 20, 17, 4, 9, 7, 69, 64, 70,\n                                  73, 87, 82, 88, 94, 72, 71, 97, 66, 68, 75,\n                                  86, 80, 84, 88, 78, 89, 86, 94, 96, 99, 105,\n                                  82, 91, 96, 75, 69, 6, 67, 17, 26, 66, 0, 10,\n                                  14, 4, 13, 25, 4, 0, 39, 12, 75, 93, 106, 126,\n                                  126, 126, 126, 2, 39, 29, 25, 15, 24, 12, 6,\n                                  4, 68, 75, 70, 5, 66, 15, 23, 64, 64, 7, 11,\n                                  6, 10, 21, 7, 1, 39, 12, 75, 93, 106, 126,\n                                  126, 126, 126 },\n\n                                {\n\n                                37,\n                                  5, 80, 37, 5, 80, 69, 7, 23, 12, 65, 70, 70,\n                                  30, 59, 14, 5, 69, 5, 11, 1, 68, 0, 74, 87, 2,\n                                  82, 119, 120, 122, 29, 70, 67, 5, 11, 1, 81,\n                                  0, 11, 4, 64, 71, 75, 0, 79, 80, 93, 5, 67,\n                                  72, 4, 74, 71, 84, 0, 74, 72, 81, 2, 2, 22, 0,\n                                  0, 0, 64, 94, 97, 6, 67, 68, 22, 65, 84, 17,\n                                  10, 3, 36, 38, 11, 14, 0, 14, 66, 64, 11, 80,\n                                  78, 79, 83, 24, 65, 10, 9, 68, 79, 72, 0, 2,\n                                  70, 69, 77, 17, 68, 4, 69, 76, 64, 70, 0, 4,\n                                  1, 1, 8, 6, 70, 0, 62, 62, 40, 31, 6, 67, 1,\n                                  8, 0, 11, 8, 1, 72, 15, 68, 86, 83, 27, 9, 13,\n                                  5, 6, 9, 13, 31, 18, 9, 1, 2, 2, 13, 16, 92,\n                                  1, 5, 75, 4, 1, 13, 10, 65, 19, 12, 13, 77, 6,\n                                  68, 66, 11, 89, 10, 15, 12, 6, 64, 11, 6, 13,\n                                  10, 70, 1, 9, 116, 62, 100, 64, 69, 71, 76,\n                                  71, 73, 84, 75, 85, 73, 84, 67, 62, 91, 20,\n                                  23, 17, 13, 12, 11, 7, 7, 5, 70, 72, 71, 75,\n                                  78, 100, 75, 76, 93, 0, 68, 70, 73, 80, 83,\n                                  82, 81, 87, 80, 89, 95, 87, 95, 64, 23, 17,\n                                  10, 8, 9, 2, 65, 66, 7, 6, 31, 21, 17, 11, 17,\n                                  8, 8, 4, 64, 10, 40, 32, 27, 24, 24, 9, 3, 0,\n                                  67, 70, 48, 29, 10, 1, 13, 1, 73, 72, 5, 45,\n                                  35, 20, 11, 20, 5, 1, 67, 69, 62, 82, 76, 68,\n                                  72, 72, 69, 65, 2, 66, 0, 3, 10, 74, 71, 78,\n                                  75, 7, 76, 75, 73, 66, 64, 69, 74, 69, 74, 69,\n                                  71, 83, 9, 9, 19, 4, 65, 9, 6, 2, 5, 4, 1, 69,\n                                  0, 66, 70, 67, 10, 88, 70, 16, 72, 4, 65, 2,\n                                  11, 65, 67, 4, 7, 79, 72, 87, 30, 32, 35, 22,\n                                  16, 20, 17, 15, 13, 7, 9, 7, 67, 67, 75, 71,\n                                  66, 72, 84, 72, 72, 74, 74, 81, 75, 83, 84,\n                                  79, 87, 20, 19, 18, 15, 2, 7, 5, 72, 66, 72,\n                                  75, 89, 83, 89, 95, 72, 71, 98, 67, 69, 76,\n                                  88, 81, 85, 89, 79, 90, 87, 94, 97, 99, 105,\n                                  83, 92, 97, 74, 68, 7, 66, 19, 28, 65, 1, 11,\n                                  15, 5, 14, 26, 4, 0, 38, 10, 77, 96, 109, 126,\n                                  126, 126, 126, 3, 39, 30, 26, 16, 25, 13, 7,\n                                  5, 67, 74, 69, 6, 65, 16, 24, 0, 0, 8, 12, 6,\n                                  11, 22, 7, 1, 38, 10, 77, 96, 109, 126, 126,\n                                  126, 126 },\n\n                                {\n\n                                36,\n                                  5, 80, 36, 5, 80, 67, 8, 23, 12, 65, 71, 72,\n                                  29, 59, 14, 7, 69, 5, 12, 1, 69, 0, 75, 89, 1,\n                                  85, 123, 123, 124, 32, 69, 67, 5, 12, 1, 81,\n                                  1, 11, 3, 64, 71, 74, 0, 79, 80, 93, 5, 67,\n                                  72, 4, 74, 71, 84, 0, 74, 72, 81, 2, 2, 22, 0,\n                                  0, 0, 0, 94, 97, 6, 68, 68, 21, 65, 84, 19,\n                                  11, 4, 38, 40, 12, 15, 2, 15, 65, 0, 13, 80,\n                                  78, 79, 83, 24, 65, 11, 11, 68, 78, 71, 2, 2,\n                                  70, 69, 78, 17, 68, 4, 68, 75, 0, 69, 1, 4, 2,\n                                  2, 9, 7, 69, 1, 62, 62, 43, 34, 6, 67, 1, 8,\n                                  0, 11, 8, 1, 72, 17, 68, 88, 85, 30, 9, 13, 5,\n                                  6, 9, 13, 33, 19, 9, 1, 2, 2, 14, 17, 93, 1,\n                                  5, 75, 3, 0, 12, 10, 66, 19, 12, 13, 78, 6,\n                                  69, 67, 10, 89, 10, 14, 11, 4, 67, 10, 4, 11,\n                                  8, 72, 64, 7, 122, 62, 104, 66, 71, 73, 79,\n                                  73, 76, 88, 79, 88, 75, 87, 69, 62, 93, 18,\n                                  21, 15, 11, 10, 9, 5, 5, 3, 72, 74, 73, 77,\n                                  80, 102, 75, 76, 94, 64, 69, 71, 74, 81, 84,\n                                  83, 83, 88, 80, 90, 96, 88, 94, 0, 24, 17, 10,\n                                  8, 10, 3, 64, 65, 9, 7, 31, 21, 17, 12, 18, 9,\n                                  10, 6, 1, 11, 41, 33, 28, 25, 25, 9, 3, 0, 66,\n                                  70, 49, 29, 9, 1, 13, 1, 73, 72, 5, 45, 34,\n                                  19, 10, 20, 5, 1, 67, 69, 62, 81, 75, 67, 70,\n                                  70, 68, 0, 4, 65, 2, 5, 12, 73, 70, 78, 74, 9,\n                                  76, 75, 73, 65, 64, 69, 74, 69, 75, 69, 71,\n                                  83, 9, 9, 20, 4, 65, 9, 6, 2, 5, 4, 1, 70, 0,\n                                  66, 70, 67, 11, 89, 71, 16, 73, 3, 66, 1, 11,\n                                  66, 68, 4, 7, 80, 72, 88, 29, 31, 34, 20, 14,\n                                  18, 15, 13, 11, 4, 6, 4, 70, 70, 77, 75, 70,\n                                  76, 89, 75, 75, 77, 76, 84, 77, 85, 85, 80,\n                                  88, 18, 17, 15, 13, 64, 4, 2, 75, 68, 75, 77,\n                                  92, 85, 91, 97, 73, 72, 100, 68, 70, 78, 90,\n                                  83, 87, 91, 80, 92, 88, 95, 98, 100, 106, 85,\n                                  93, 98, 74, 68, 8, 66, 20, 29, 65, 2, 12, 16,\n                                  5, 14, 27, 4, 0, 37, 8, 80, 99, 112, 126, 126,\n                                  126, 126, 3, 39, 30, 26, 16, 26, 13, 7, 5, 67,\n                                  74, 69, 6, 65, 17, 25, 0, 0, 8, 12, 6, 11, 23,\n                                  7, 1, 37, 8, 80, 99, 112, 126, 126, 126, 126 },\n\n                                {\n\n                                35,\n                                  5, 80, 35, 5, 80, 65, 10, 24, 12, 66, 73, 74,\n                                  28, 59, 14, 9, 69, 6, 13, 1, 69, 0, 75, 90, 0,\n                                  87, 126, 125, 125, 35, 68, 67, 6, 13, 1, 82,\n                                  2, 11, 3, 64, 71, 74, 0, 79, 80, 93, 5, 67,\n                                  71, 4, 74, 70, 84, 0, 74, 72, 81, 2, 2, 22, 0,\n                                  0, 0, 0, 94, 97, 7, 69, 68, 20, 66, 84, 22,\n                                  12, 5, 39, 42, 14, 17, 4, 17, 64, 1, 15, 80,\n                                  78, 78, 83, 24, 65, 12, 13, 68, 77, 71, 4, 2,\n                                  71, 70, 78, 17, 68, 5, 68, 74, 1, 69, 2, 5, 3,\n                                  4, 11, 7, 68, 2, 62, 62, 46, 37, 6, 67, 1, 9,\n                                  0, 11, 9, 2, 71, 19, 68, 90, 87, 33, 9, 13, 5,\n                                  6, 9, 14, 34, 20, 9, 1, 2, 2, 14, 18, 94, 1,\n                                  5, 76, 3, 64, 12, 10, 66, 19, 12, 13, 79, 6,\n                                  70, 68, 10, 89, 10, 14, 11, 2, 70, 9, 2, 9, 5,\n                                  74, 67, 5, 126, 62, 107, 68, 73, 75, 82, 76,\n                                  79, 92, 83, 91, 77, 91, 71, 62, 95, 16, 19,\n                                  13, 8, 7, 7, 3, 3, 1, 74, 76, 75, 79, 81, 104,\n                                  75, 76, 94, 65, 70, 72, 75, 82, 85, 84, 85,\n                                  89, 81, 91, 97, 88, 94, 2, 25, 18, 10, 8, 11,\n                                  3, 64, 65, 11, 8, 31, 21, 18, 13, 19, 10, 11,\n                                  7, 3, 12, 41, 33, 28, 25, 26, 10, 3, 0, 66,\n                                  70, 49, 29, 8, 1, 13, 1, 73, 71, 5, 44, 34,\n                                  18, 9, 20, 5, 1, 67, 69, 62, 80, 73, 66, 69,\n                                  69, 67, 2, 6, 64, 3, 7, 14, 73, 69, 77, 73,\n                                  11, 75, 75, 73, 65, 0, 69, 74, 69, 75, 69, 71,\n                                  84, 10, 10, 21, 4, 65, 10, 6, 2, 5, 4, 1, 70,\n                                  0, 66, 70, 67, 11, 90, 72, 16, 74, 2, 67, 1,\n                                  11, 67, 69, 4, 7, 81, 72, 89, 28, 30, 33, 19,\n                                  12, 16, 13, 11, 8, 2, 3, 1, 73, 72, 79, 79,\n                                  74, 80, 94, 79, 78, 79, 78, 86, 79, 87, 87,\n                                  81, 89, 16, 14, 13, 10, 67, 2, 0, 78, 71, 77,\n                                  80, 95, 87, 93, 98, 74, 73, 101, 70, 72, 80,\n                                  92, 84, 89, 93, 81, 93, 89, 96, 99, 101, 107,\n                                  86, 94, 99, 74, 67, 8, 65, 21, 30, 65, 2, 12,\n                                  16, 5, 15, 28, 4, 0, 36, 6, 82, 102, 115, 126,\n                                  126, 126, 126, 3, 39, 30, 26, 16, 26, 14, 7,\n                                  5, 66, 74, 69, 7, 64, 18, 26, 0, 1, 8, 12, 6,\n                                  11, 23, 7, 1, 36, 6, 82, 102, 115, 126, 126,\n                                  126, 126 },\n\n                                {\n\n                                33,\n                                  5, 80, 33, 5, 80, 64, 11, 24, 12, 66, 74, 76,\n                                  27, 59, 13, 11, 69, 6, 14, 0, 70, 0, 76, 92,\n                                  64, 90, 126, 126, 126, 38, 67, 67, 6, 14, 0,\n                                  82, 3, 11, 2, 64, 70, 73, 0, 79, 80, 93, 5,\n                                  67, 71, 4, 74, 70, 83, 0, 74, 72, 81, 3, 2,\n                                  22, 0, 0, 0, 1, 95, 97, 7, 70, 68, 19, 66, 84,\n                                  24, 13, 6, 41, 44, 15, 18, 5, 18, 1, 2, 17,\n                                  80, 77, 78, 83, 24, 65, 13, 15, 68, 77, 70, 6,\n                                  2, 71, 70, 79, 17, 68, 5, 67, 73, 2, 68, 3, 5,\n                                  3, 5, 12, 8, 67, 3, 62, 62, 49, 40, 6, 66, 1,\n                                  9, 0, 11, 9, 2, 71, 21, 68, 92, 89, 35, 9, 14,\n                                  5, 6, 9, 14, 36, 21, 10, 0, 2, 2, 15, 18, 95,\n                                  1, 5, 76, 2, 65, 11, 9, 67, 19, 12, 13, 80, 6,\n                                  71, 69, 9, 89, 9, 13, 10, 0, 74, 8, 0, 7, 3,\n                                  76, 69, 3, 126, 62, 111, 70, 75, 78, 85, 78,\n                                  83, 97, 87, 94, 79, 94, 73, 62, 96, 14, 17,\n                                  10, 6, 5, 5, 1, 1, 64, 77, 78, 77, 81, 83,\n                                  106, 75, 76, 95, 66, 71, 73, 77, 83, 87, 85,\n                                  86, 90, 81, 92, 97, 89, 93, 3, 26, 18, 10, 9,\n                                  11, 4, 0, 64, 13, 10, 31, 22, 18, 13, 20, 11,\n                                  13, 9, 4, 12, 42, 34, 29, 26, 27, 10, 3, 1,\n                                  65, 70, 50, 29, 8, 0, 13, 1, 73, 71, 5, 44,\n                                  33, 17, 8, 20, 5, 2, 67, 69, 62, 78, 72, 65,\n                                  67, 67, 66, 3, 7, 0, 5, 8, 16, 72, 68, 77, 72,\n                                  12, 75, 75, 73, 64, 0, 69, 75, 69, 76, 69, 71,\n                                  84, 10, 10, 22, 4, 65, 10, 6, 2, 5, 4, 1, 71,\n                                  0, 66, 70, 67, 12, 91, 73, 16, 75, 2, 68, 0,\n                                  11, 68, 70, 4, 7, 82, 72, 90, 27, 29, 32, 17,\n                                  10, 14, 11, 8, 6, 64, 0, 65, 76, 75, 81, 84,\n                                  78, 84, 99, 82, 82, 82, 81, 89, 81, 89, 88,\n                                  82, 89, 13, 12, 10, 8, 70, 64, 66, 81, 73, 80,\n                                  82, 98, 89, 95, 100, 75, 73, 103, 71, 73, 81,\n                                  94, 86, 91, 94, 82, 95, 90, 97, 101, 102, 107,\n                                  88, 96, 101, 73, 67, 9, 65, 22, 31, 65, 3, 13,\n                                  17, 5, 15, 29, 4, 0, 35, 4, 85, 105, 119, 126,\n                                  126, 126, 126, 4, 39, 30, 26, 16, 27, 14, 7,\n                                  5, 66, 74, 69, 7, 64, 18, 27, 0, 1, 9, 13, 6,\n                                  11, 24, 7, 1, 35, 4, 85, 105, 119, 126, 126,\n                                  126, 126 },\n\n                                {\n\n                                32,\n                                  5, 80, 32, 5, 80, 1, 13, 24, 12, 67, 75, 78,\n                                  26, 59, 13, 13, 69, 6, 15, 0, 70, 0, 77, 94,\n                                  65, 92, 126, 126, 126, 41, 66, 66, 6, 15, 0,\n                                  82, 4, 11, 2, 64, 70, 72, 0, 79, 80, 93, 5,\n                                  67, 71, 4, 74, 69, 83, 0, 74, 72, 81, 3, 2,\n                                  22, 0, 0, 0, 1, 95, 97, 8, 71, 68, 18, 67, 84,\n                                  27, 14, 7, 43, 46, 17, 20, 7, 20, 2, 3, 20,\n                                  80, 77, 77, 82, 24, 65, 14, 17, 68, 76, 70, 8,\n                                  2, 72, 71, 79, 17, 68, 6, 67, 72, 3, 68, 4, 6,\n                                  4, 7, 14, 9, 65, 4, 62, 62, 52, 43, 7, 66, 2,\n                                  10, 0, 11, 10, 2, 70, 23, 68, 94, 91, 38, 9,\n                                  14, 5, 6, 9, 15, 37, 22, 10, 0, 2, 2, 15, 19,\n                                  96, 2, 5, 77, 2, 66, 11, 9, 67, 19, 12, 13,\n                                  81, 7, 72, 69, 9, 89, 9, 12, 9, 65, 77, 7, 64,\n                                  5, 1, 78, 72, 1, 126, 62, 114, 72, 77, 80, 88,\n                                  81, 86, 101, 91, 96, 81, 98, 75, 62, 98, 12,\n                                  15, 8, 4, 3, 3, 64, 64, 66, 79, 80, 79, 82,\n                                  85, 108, 75, 76, 95, 67, 72, 74, 78, 84, 88,\n                                  86, 88, 91, 82, 93, 98, 90, 92, 5, 27, 19, 10,\n                                  9, 12, 4, 0, 0, 15, 11, 31, 22, 19, 14, 21,\n                                  12, 14, 10, 6, 13, 43, 35, 30, 26, 28, 11, 4,\n                                  1, 65, 70, 50, 29, 7, 0, 13, 1, 73, 70, 5, 43,\n                                  32, 16, 7, 20, 5, 2, 67, 68, 62, 77, 70, 0,\n                                  65, 66, 65, 5, 9, 1, 7, 10, 18, 71, 67, 76,\n                                  71, 14, 75, 75, 72, 64, 1, 69, 75, 69, 76, 69,\n                                  71, 85, 11, 10, 23, 4, 65, 10, 6, 2, 5, 4, 1,\n                                  71, 0, 66, 70, 67, 12, 92, 74, 16, 76, 1, 68,\n                                  64, 11, 68, 71, 4, 7, 83, 72, 91, 26, 28, 31,\n                                  15, 8, 12, 9, 6, 3, 67, 66, 68, 79, 77, 83,\n                                  88, 82, 88, 104, 85, 85, 84, 83, 91, 83, 90,\n                                  90, 82, 90, 11, 9, 8, 6, 73, 67, 68, 84, 75,\n                                  82, 84, 101, 91, 97, 101, 75, 74, 105, 72, 75,\n                                  83, 96, 88, 93, 96, 83, 96, 91, 97, 102, 103,\n                                  108, 89, 97, 102, 73, 67, 10, 64, 23, 32, 64,\n                                  4, 13, 17, 5, 16, 30, 4, 0, 34, 2, 88, 108,\n                                  122, 126, 126, 126, 126, 4, 39, 30, 26, 16,\n                                  27, 14, 8, 6, 65, 74, 69, 8, 64, 19, 28, 0, 1,\n                                  9, 13, 6, 12, 24, 7, 1, 34, 2, 88, 108, 122,\n                                  126, 126, 126, 126 },\n\n                                {\n\n                                31,\n                                  5, 81, 31, 5, 81, 3, 14, 25, 12, 67, 77, 80,\n                                  25, 59, 13, 14, 69, 7, 15, 0, 71, 1, 77, 95,\n                                  67, 95, 126, 126, 126, 43, 65, 66, 7, 15, 0,\n                                  83, 4, 11, 1, 64, 70, 72, 0, 79, 79, 92, 5,\n                                  66, 70, 4, 73, 69, 83, 0, 74, 72, 81, 3, 2,\n                                  22, 0, 0, 0, 2, 95, 97, 8, 71, 69, 18, 67, 84,\n                                  29, 15, 8, 44, 49, 18, 21, 9, 21, 3, 4, 22,\n                                  80, 77, 77, 82, 24, 65, 15, 20, 68, 75, 69,\n                                  10, 1, 72, 71, 80, 18, 68, 6, 66, 72, 3, 67,\n                                  5, 6, 5, 8, 15, 9, 64, 5, 62, 62, 55, 46, 7,\n                                  66, 2, 10, 0, 11, 10, 3, 70, 25, 67, 96, 93,\n                                  41, 9, 14, 5, 6, 10, 15, 39, 23, 10, 0, 2, 2,\n                                  16, 20, 97, 2, 5, 77, 1, 67, 10, 9, 68, 19,\n                                  12, 13, 83, 7, 73, 70, 8, 89, 9, 12, 9, 67,\n                                  80, 6, 66, 2, 65, 80, 74, 64, 126, 62, 118,\n                                  74, 78, 82, 92, 83, 89, 105, 96, 99, 83, 101,\n                                  77, 62, 100, 10, 13, 6, 1, 0, 1, 67, 66, 68,\n                                  81, 83, 81, 84, 86, 109, 75, 76, 96, 68, 73,\n                                  75, 79, 85, 89, 87, 90, 92, 82, 94, 99, 90,\n                                  92, 6, 28, 19, 10, 9, 13, 5, 1, 0, 17, 12, 32,\n                                  22, 19, 15, 22, 13, 16, 12, 8, 14, 43, 35, 30,\n                                  27, 29, 11, 4, 1, 64, 70, 51, 29, 6, 0, 13, 1,\n                                  73, 70, 4, 43, 32, 15, 6, 19, 5, 2, 67, 68,\n                                  62, 76, 69, 1, 64, 64, 64, 7, 11, 2, 8, 12,\n                                  20, 71, 66, 76, 70, 16, 74, 75, 72, 0, 1, 69,\n                                  75, 69, 77, 69, 71, 85, 11, 11, 24, 4, 65, 11,\n                                  7, 2, 6, 5, 1, 72, 0, 66, 70, 67, 13, 93, 75,\n                                  16, 77, 0, 69, 64, 11, 69, 71, 4, 6, 85, 73,\n                                  92, 24, 27, 30, 14, 6, 10, 7, 4, 1, 69, 69,\n                                  70, 82, 80, 85, 92, 86, 92, 108, 89, 88, 87,\n                                  85, 94, 85, 92, 91, 83, 91, 9, 7, 5, 3, 76,\n                                  69, 71, 87, 78, 85, 87, 104, 93, 98, 103, 76,\n                                  75, 106, 74, 76, 85, 98, 89, 95, 98, 84, 98,\n                                  92, 98, 103, 104, 109, 91, 98, 103, 73, 66,\n                                  10, 64, 24, 33, 64, 4, 14, 18, 5, 16, 31, 4,\n                                  0, 33, 0, 90, 111, 125, 126, 126, 126, 126, 4,\n                                  39, 30, 26, 16, 28, 15, 8, 6, 65, 73, 68, 8,\n                                  0, 20, 29, 1, 2, 9, 13, 6, 12, 25, 7, 1, 33,\n                                  0, 90, 111, 125, 126, 126, 126, 126 },\n\n                                {\n\n                                30,\n                                  5, 81, 30, 5, 81, 5, 16, 25, 12, 68, 78, 82,\n                                  24, 59, 13, 16, 69, 7, 16, 64, 71, 1, 78, 97,\n                                  68, 97, 126, 126, 126, 46, 64, 66, 7, 16, 64,\n                                  83, 5, 11, 1, 64, 69, 71, 0, 79, 79, 92, 5,\n                                  66, 70, 4, 73, 68, 82, 0, 74, 72, 81, 4, 2,\n                                  22, 0, 0, 0, 2, 95, 97, 9, 72, 69, 17, 68, 84,\n                                  32, 16, 9, 46, 51, 20, 23, 10, 23, 5, 5, 24,\n                                  80, 76, 76, 82, 24, 65, 16, 22, 68, 74, 69,\n                                  12, 1, 73, 72, 80, 18, 68, 7, 66, 71, 4, 67,\n                                  6, 7, 6, 10, 17, 10, 0, 6, 62, 62, 58, 49, 7,\n                                  65, 2, 11, 0, 11, 11, 3, 69, 27, 67, 98, 95,\n                                  44, 9, 15, 5, 6, 10, 16, 40, 24, 11, 64, 2, 2,\n                                  16, 20, 98, 2, 5, 78, 1, 68, 10, 8, 68, 19,\n                                  12, 13, 84, 7, 74, 71, 8, 89, 9, 11, 8, 69,\n                                  83, 5, 68, 0, 67, 82, 77, 66, 126, 62, 121,\n                                  76, 80, 85, 95, 86, 92, 110, 100, 102, 85,\n                                  105, 79, 62, 101, 8, 11, 4, 64, 65, 64, 69,\n                                  68, 70, 84, 85, 83, 86, 88, 111, 75, 76, 96,\n                                  69, 74, 76, 81, 86, 90, 88, 91, 93, 83, 95,\n                                  99, 91, 91, 8, 29, 20, 10, 10, 13, 5, 1, 1,\n                                  19, 14, 32, 23, 20, 15, 23, 14, 17, 13, 10,\n                                  14, 44, 36, 31, 27, 30, 12, 4, 2, 64, 70, 51,\n                                  29, 6, 64, 13, 1, 73, 69, 4, 42, 31, 14, 5,\n                                  19, 5, 3, 67, 68, 62, 74, 67, 2, 1, 0, 0, 8,\n                                  12, 3, 10, 13, 22, 70, 65, 75, 69, 18, 74, 75,\n                                  72, 0, 2, 69, 76, 69, 77, 69, 71, 86, 12, 11,\n                                  25, 4, 65, 11, 7, 2, 6, 5, 1, 72, 0, 66, 70,\n                                  67, 13, 94, 76, 16, 78, 0, 70, 65, 11, 70, 72,\n                                  4, 6, 86, 73, 93, 23, 26, 29, 12, 4, 8, 5, 1,\n                                  65, 72, 72, 73, 85, 82, 87, 97, 90, 96, 113,\n                                  92, 91, 89, 87, 96, 87, 94, 93, 84, 91, 6, 4,\n                                  3, 1, 79, 72, 73, 90, 80, 87, 89, 107, 95,\n                                  100, 104, 77, 75, 108, 75, 78, 86, 100, 91,\n                                  97, 99, 85, 99, 93, 99, 105, 105, 109, 92,\n                                  100, 105, 72, 66, 11, 0, 25, 34, 64, 5, 14,\n                                  18, 5, 17, 32, 4, 0, 32, 65, 93, 114, 126,\n                                  126, 126, 126, 126, 5, 39, 30, 26, 16, 28, 15,\n                                  8, 6, 64, 73, 68, 9, 0, 21, 30, 1, 2, 10, 14,\n                                  6, 12, 25, 7, 1, 32, 65, 93, 114, 126, 126,\n                                  126, 126, 126 },\n\n                                {\n\n                                28,\n                                  4, 81, 28, 4, 81, 6, 17, 25, 12, 68, 80, 85,\n                                  23, 59, 12, 18, 70, 7, 17, 64, 72, 1, 79, 99,\n                                  69, 100, 126, 126, 126, 49, 0, 66, 7, 17, 64,\n                                  84, 6, 11, 0, 64, 69, 71, 64, 80, 79, 92, 5,\n                                  66, 70, 4, 73, 68, 82, 0, 74, 72, 81, 4, 2,\n                                  22, 0, 0, 0, 3, 96, 97, 9, 73, 69, 16, 68, 85,\n                                  34, 17, 10, 47, 53, 21, 24, 12, 24, 6, 6, 26,\n                                  80, 76, 76, 82, 24, 65, 17, 24, 68, 74, 68,\n                                  14, 1, 73, 72, 81, 18, 68, 7, 65, 70, 5, 66,\n                                  6, 7, 6, 11, 18, 10, 1, 7, 62, 62, 61, 51, 7,\n                                  65, 2, 11, 64, 11, 11, 3, 69, 29, 67, 100, 97,\n                                  46, 9, 15, 5, 6, 10, 16, 42, 24, 11, 64, 1, 2,\n                                  17, 21, 100, 2, 5, 78, 0, 70, 9, 8, 69, 19,\n                                  12, 12, 85, 7, 75, 72, 7, 89, 8, 10, 7, 71,\n                                  87, 3, 70, 65, 70, 85, 79, 68, 126, 62, 125,\n                                  78, 82, 87, 98, 88, 96, 114, 104, 105, 87,\n                                  108, 81, 62, 103, 6, 8, 1, 67, 68, 67, 71, 71,\n                                  72, 86, 87, 85, 88, 90, 113, 75, 77, 97, 70,\n                                  76, 77, 82, 87, 92, 90, 93, 94, 83, 96, 100,\n                                  92, 91, 9, 30, 20, 10, 10, 14, 6, 2, 1, 21,\n                                  15, 32, 23, 20, 16, 24, 15, 19, 15, 11, 15,\n                                  44, 36, 31, 28, 31, 12, 4, 2, 0, 71, 52, 29,\n                                  5, 64, 13, 1, 73, 69, 4, 42, 30, 13, 4, 19, 5,\n                                  3, 67, 68, 62, 73, 66, 3, 2, 2, 1, 10, 14, 4,\n                                  11, 15, 24, 70, 65, 75, 68, 19, 74, 75, 72, 1,\n                                  2, 69, 76, 69, 78, 69, 71, 86, 12, 11, 26, 4,\n                                  66, 11, 7, 1, 6, 5, 1, 73, 0, 66, 70, 67, 14,\n                                  95, 77, 16, 80, 64, 71, 66, 10, 71, 73, 4, 6,\n                                  87, 73, 95, 22, 24, 28, 10, 2, 6, 3, 64, 67,\n                                  75, 75, 76, 88, 85, 89, 101, 94, 101, 118, 96,\n                                  95, 92, 90, 99, 89, 96, 94, 85, 92, 4, 2, 0,\n                                  65, 82, 75, 76, 93, 83, 90, 92, 110, 97, 102,\n                                  106, 78, 76, 110, 77, 79, 88, 102, 93, 99,\n                                  101, 87, 101, 95, 100, 106, 106, 110, 94, 101,\n                                  106, 72, 66, 11, 0, 26, 35, 64, 5, 15, 19, 5,\n                                  17, 32, 4, 64, 31, 67, 96, 117, 126, 126, 126,\n                                  126, 126, 5, 39, 30, 26, 16, 29, 15, 8, 6, 64,\n                                  73, 68, 9, 0, 21, 30, 1, 2, 10, 14, 6, 12, 26,\n                                  7, 0, 31, 67, 96, 117, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                27,\n                                  4, 81, 27, 4, 81, 8, 18, 26, 12, 68, 81, 87,\n                                  22, 60, 12, 20, 70, 8, 18, 64, 73, 1, 79, 100,\n                                  70, 102, 126, 126, 126, 52, 1, 65, 8, 18, 64,\n                                  84, 7, 11, 0, 0, 69, 70, 64, 80, 79, 92, 5,\n                                  66, 69, 4, 73, 68, 82, 0, 74, 72, 80, 4, 2,\n                                  22, 0, 0, 0, 4, 96, 97, 9, 74, 69, 15, 68, 85,\n                                  36, 19, 11, 49, 55, 23, 25, 14, 26, 7, 8, 29,\n                                  80, 76, 76, 81, 24, 65, 18, 26, 67, 73, 67,\n                                  16, 1, 73, 72, 81, 18, 68, 7, 64, 69, 6, 65,\n                                  7, 8, 7, 12, 20, 11, 3, 8, 62, 62, 62, 54, 8,\n                                  65, 3, 12, 64, 11, 11, 4, 68, 32, 67, 102, 98,\n                                  49, 9, 15, 5, 6, 10, 17, 44, 25, 11, 64, 1, 2,\n                                  18, 22, 101, 3, 5, 78, 64, 71, 8, 8, 70, 19,\n                                  12, 12, 86, 8, 76, 72, 6, 89, 8, 10, 7, 73,\n                                  90, 2, 71, 67, 72, 87, 81, 70, 126, 62, 126,\n                                  80, 84, 89, 101, 90, 99, 118, 108, 107, 89,\n                                  111, 83, 62, 105, 4, 6, 64, 69, 70, 69, 73,\n                                  73, 74, 88, 89, 86, 89, 91, 115, 75, 77, 97,\n                                  70, 77, 78, 83, 88, 93, 91, 95, 95, 83, 97,\n                                  101, 92, 90, 10, 31, 20, 10, 10, 15, 7, 3, 2,\n                                  24, 16, 32, 23, 20, 17, 25, 16, 21, 17, 13,\n                                  16, 45, 37, 32, 29, 32, 12, 5, 2, 1, 71, 53,\n                                  29, 4, 64, 14, 2, 73, 68, 4, 42, 30, 12, 3,\n                                  19, 5, 3, 67, 67, 62, 72, 65, 5, 4, 4, 2, 12,\n                                  16, 5, 13, 17, 26, 69, 64, 74, 67, 21, 73, 74,\n                                  71, 2, 3, 69, 76, 69, 79, 69, 71, 86, 12, 12,\n                                  27, 5, 66, 12, 7, 1, 6, 5, 1, 74, 0, 65, 69,\n                                  67, 15, 95, 78, 16, 81, 65, 71, 66, 10, 71,\n                                  74, 4, 6, 88, 73, 96, 21, 23, 28, 9, 0, 4, 1,\n                                  66, 69, 77, 78, 79, 91, 88, 91, 105, 98, 105,\n                                  123, 99, 98, 95, 92, 101, 90, 97, 95, 85, 93,\n                                  2, 0, 65, 67, 84, 77, 78, 96, 85, 92, 94, 112,\n                                  99, 104, 108, 78, 77, 111, 78, 80, 90, 104,\n                                  94, 100, 103, 88, 103, 96, 100, 107, 106, 111,\n                                  96, 102, 107, 72, 65, 12, 0, 27, 37, 0, 6, 16,\n                                  20, 5, 18, 33, 4, 64, 30, 69, 98, 120, 126,\n                                  126, 126, 126, 126, 5, 39, 30, 27, 17, 30, 16,\n                                  9, 7, 64, 73, 68, 9, 1, 22, 31, 1, 3, 10, 14,\n                                  6, 13, 27, 7, 0, 30, 69, 98, 120, 126, 126,\n                                  126, 126, 126 },\n\n                                {\n\n                                26,\n                                  4, 81, 26, 4, 81, 10, 20, 26, 12, 69, 82, 89,\n                                  21, 60, 12, 22, 70, 8, 19, 65, 73, 1, 80, 102,\n                                  71, 105, 126, 126, 126, 55, 2, 65, 8, 19, 65,\n                                  84, 8, 11, 64, 0, 68, 69, 64, 80, 79, 92, 5,\n                                  66, 69, 4, 73, 67, 81, 0, 74, 72, 80, 5, 2,\n                                  22, 0, 0, 0, 4, 96, 97, 10, 75, 69, 14, 69,\n                                  85, 39, 20, 12, 51, 57, 24, 27, 15, 27, 9, 9,\n                                  31, 80, 75, 75, 81, 24, 65, 19, 28, 67, 72,\n                                  67, 18, 1, 74, 73, 82, 18, 68, 8, 64, 68, 7,\n                                  65, 8, 8, 8, 14, 21, 12, 4, 9, 62, 62, 62, 57,\n                                  8, 64, 3, 12, 64, 11, 12, 4, 68, 34, 67, 104,\n                                  100, 52, 9, 16, 5, 6, 10, 17, 45, 26, 12, 65,\n                                  1, 2, 18, 22, 102, 3, 5, 79, 64, 72, 8, 7, 70,\n                                  19, 12, 12, 87, 8, 77, 73, 6, 89, 8, 9, 6, 75,\n                                  93, 1, 73, 69, 74, 89, 84, 72, 126, 62, 126,\n                                  82, 86, 92, 104, 93, 102, 123, 112, 110, 91,\n                                  115, 85, 62, 106, 2, 4, 66, 71, 72, 71, 75,\n                                  75, 76, 91, 91, 88, 91, 93, 117, 75, 77, 98,\n                                  71, 78, 79, 85, 89, 94, 92, 96, 96, 84, 98,\n                                  101, 93, 89, 12, 32, 21, 10, 11, 15, 7, 3, 3,\n                                  26, 18, 32, 24, 21, 17, 26, 17, 22, 18, 15,\n                                  16, 46, 38, 33, 29, 33, 13, 5, 3, 1, 71, 53,\n                                  29, 4, 65, 14, 2, 73, 68, 4, 41, 29, 11, 2,\n                                  19, 5, 4, 67, 67, 62, 70, 0, 6, 6, 5, 3, 13,\n                                  17, 6, 15, 18, 28, 68, 0, 74, 66, 23, 73, 74,\n                                  71, 2, 3, 69, 77, 69, 79, 69, 71, 87, 13, 12,\n                                  28, 5, 66, 12, 7, 1, 6, 5, 1, 74, 0, 65, 69,\n                                  67, 15, 96, 79, 16, 82, 65, 72, 67, 10, 72,\n                                  75, 4, 6, 89, 73, 97, 20, 22, 27, 7, 65, 2,\n                                  64, 69, 72, 80, 81, 82, 94, 90, 93, 110, 102,\n                                  109, 126, 102, 101, 97, 94, 104, 92, 99, 97,\n                                  86, 93, 64, 66, 68, 69, 87, 80, 81, 99, 87,\n                                  95, 96, 115, 101, 106, 109, 79, 77, 113, 79,\n                                  82, 91, 106, 96, 102, 104, 89, 104, 97, 101,\n                                  109, 107, 111, 97, 104, 109, 71, 65, 13, 1,\n                                  28, 38, 0, 7, 16, 20, 5, 18, 34, 4, 64, 29,\n                                  71, 101, 123, 126, 126, 126, 126, 126, 6, 39,\n                                  30, 27, 17, 30, 16, 9, 7, 0, 73, 68, 10, 1,\n                                  23, 32, 1, 3, 11, 15, 6, 13, 27, 7, 0, 29, 71,\n                                  101, 123, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                25,\n                                  4, 82, 25, 4, 82, 12, 21, 27, 12, 69, 84, 91,\n                                  20, 60, 12, 23, 70, 9, 19, 65, 74, 2, 80, 103,\n                                  73, 107, 126, 126, 126, 57, 3, 65, 9, 19, 65,\n                                  85, 8, 11, 64, 0, 68, 69, 64, 80, 78, 91, 5,\n                                  65, 68, 4, 72, 67, 81, 0, 74, 72, 80, 5, 2,\n                                  22, 0, 0, 0, 5, 96, 97, 10, 75, 70, 14, 69,\n                                  85, 41, 21, 13, 52, 60, 26, 28, 17, 29, 10,\n                                  10, 33, 80, 75, 75, 81, 24, 65, 20, 31, 67,\n                                  71, 66, 20, 0, 74, 73, 82, 19, 68, 8, 0, 68,\n                                  7, 64, 9, 9, 9, 15, 23, 12, 5, 10, 62, 62, 62,\n                                  60, 8, 64, 3, 13, 64, 11, 12, 5, 67, 36, 66,\n                                  106, 102, 55, 9, 16, 5, 6, 11, 18, 47, 27, 12,\n                                  65, 1, 2, 19, 23, 103, 3, 5, 79, 65, 73, 7, 7,\n                                  71, 19, 12, 12, 89, 8, 78, 74, 5, 89, 8, 9, 6,\n                                  77, 96, 0, 75, 72, 77, 91, 86, 74, 126, 62,\n                                  126, 84, 87, 94, 108, 95, 105, 126, 117, 113,\n                                  93, 118, 87, 62, 108, 0, 2, 68, 74, 75, 73,\n                                  78, 77, 78, 93, 94, 90, 93, 94, 118, 75, 77,\n                                  98, 72, 79, 80, 86, 90, 95, 93, 98, 97, 84,\n                                  99, 102, 93, 89, 13, 33, 21, 10, 11, 16, 8, 4,\n                                  3, 28, 19, 33, 24, 21, 18, 27, 18, 24, 20, 17,\n                                  17, 46, 38, 33, 30, 34, 13, 5, 3, 2, 71, 54,\n                                  29, 3, 65, 14, 2, 73, 67, 3, 41, 29, 10, 1,\n                                  18, 5, 4, 67, 67, 62, 69, 1, 7, 7, 7, 4, 15,\n                                  19, 7, 16, 20, 30, 68, 1, 73, 65, 25, 72, 74,\n                                  71, 3, 4, 69, 77, 69, 80, 69, 71, 87, 13, 13,\n                                  29, 5, 66, 13, 8, 1, 7, 6, 1, 75, 0, 65, 69,\n                                  67, 16, 97, 80, 16, 83, 66, 73, 67, 10, 73,\n                                  75, 4, 5, 91, 74, 98, 18, 21, 26, 6, 67, 0,\n                                  66, 71, 74, 82, 84, 84, 97, 93, 95, 114, 106,\n                                  113, 126, 106, 104, 100, 96, 106, 94, 101, 98,\n                                  87, 94, 66, 68, 70, 72, 90, 82, 83, 102, 90,\n                                  97, 99, 118, 103, 107, 111, 80, 78, 114, 81,\n                                  83, 93, 108, 97, 104, 106, 90, 106, 98, 102,\n                                  110, 108, 112, 99, 105, 110, 71, 64, 13, 1,\n                                  29, 39, 0, 7, 17, 21, 5, 19, 35, 4, 64, 28,\n                                  73, 103, 126, 126, 126, 126, 126, 126, 6, 39,\n                                  30, 27, 17, 31, 17, 9, 7, 0, 72, 67, 10, 2,\n                                  24, 33, 2, 4, 11, 15, 6, 13, 28, 7, 0, 28, 73,\n                                  103, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                23,\n                                  4, 82, 23, 4, 82, 13, 23, 27, 12, 70, 85, 93,\n                                  19, 60, 11, 25, 70, 9, 20, 65, 74, 2, 81, 105,\n                                  74, 110, 126, 126, 126, 60, 4, 65, 9, 20, 65,\n                                  85, 9, 11, 65, 0, 68, 68, 64, 80, 78, 91, 5,\n                                  65, 68, 4, 72, 66, 81, 0, 74, 72, 80, 5, 2,\n                                  22, 0, 0, 0, 5, 97, 97, 11, 76, 70, 13, 70,\n                                  85, 44, 22, 14, 54, 62, 27, 30, 19, 30, 11,\n                                  11, 35, 80, 75, 74, 81, 24, 65, 21, 33, 67,\n                                  71, 66, 22, 0, 75, 74, 83, 19, 68, 9, 0, 67,\n                                  8, 64, 10, 9, 9, 17, 24, 13, 6, 11, 62, 62,\n                                  62, 62, 8, 64, 3, 13, 64, 11, 13, 5, 67, 38,\n                                  66, 108, 104, 57, 9, 16, 5, 6, 11, 18, 48, 28,\n                                  12, 65, 1, 2, 19, 24, 104, 3, 5, 80, 65, 74,\n                                  7, 7, 71, 19, 12, 12, 90, 8, 79, 75, 5, 89, 7,\n                                  8, 5, 79, 100, 64, 77, 74, 79, 93, 89, 76,\n                                  126, 62, 126, 86, 89, 96, 111, 98, 109, 126,\n                                  121, 116, 95, 122, 89, 62, 110, 65, 0, 71, 76,\n                                  77, 75, 80, 79, 80, 95, 96, 92, 95, 96, 120,\n                                  75, 77, 99, 73, 80, 81, 87, 91, 97, 94, 100,\n                                  98, 85, 100, 103, 94, 88, 15, 34, 22, 10, 11,\n                                  17, 8, 4, 4, 30, 20, 33, 24, 22, 19, 28, 19,\n                                  25, 21, 18, 18, 47, 39, 34, 30, 35, 14, 5, 3,\n                                  2, 71, 54, 29, 2, 65, 14, 2, 73, 67, 3, 40,\n                                  28, 9, 0, 18, 5, 4, 67, 67, 62, 68, 3, 8, 9,\n                                  8, 5, 17, 21, 8, 18, 22, 32, 67, 2, 73, 64,\n                                  26, 72, 74, 71, 3, 4, 69, 77, 69, 80, 69, 71,\n                                  88, 14, 13, 30, 5, 66, 13, 8, 1, 7, 6, 1, 75,\n                                  0, 65, 69, 67, 16, 98, 81, 16, 84, 67, 74, 68,\n                                  10, 74, 76, 4, 5, 92, 74, 99, 17, 20, 25, 4,\n                                  69, 65, 68, 73, 77, 85, 87, 87, 100, 95, 97,\n                                  118, 110, 117, 126, 109, 108, 102, 99, 109,\n                                  96, 103, 100, 88, 95, 68, 71, 73, 74, 93, 85,\n                                  86, 105, 92, 100, 101, 121, 105, 109, 112, 81,\n                                  79, 116, 82, 85, 95, 110, 99, 106, 108, 91,\n                                  107, 99, 103, 111, 109, 113, 100, 106, 111,\n                                  71, 64, 14, 2, 30, 40, 0, 8, 17, 21, 5, 19,\n                                  36, 4, 64, 27, 75, 106, 126, 126, 126, 126,\n                                  126, 126, 6, 39, 30, 27, 17, 31, 17, 9, 7, 1,\n                                  72, 67, 11, 2, 24, 34, 2, 4, 11, 15, 6, 13,\n                                  28, 7, 0, 27, 75, 106, 126, 126, 126, 126,\n                                  126, 126 },\n\n                                {\n\n                                22,\n                                  4, 82, 22, 4, 82, 15, 24, 27, 12, 70, 86, 95,\n                                  18, 60, 11, 27, 70, 9, 21, 66, 75, 2, 82, 107,\n                                  75, 112, 126, 126, 126, 62, 5, 64, 9, 21, 66,\n                                  85, 10, 11, 65, 0, 67, 67, 64, 80, 78, 91, 5,\n                                  65, 68, 4, 72, 66, 80, 0, 74, 72, 80, 6, 2,\n                                  22, 0, 0, 0, 6, 97, 97, 11, 77, 70, 12, 70,\n                                  85, 46, 23, 15, 56, 62, 29, 31, 20, 32, 13,\n                                  12, 38, 80, 74, 74, 80, 24, 65, 22, 35, 67,\n                                  70, 65, 24, 0, 75, 74, 83, 19, 68, 9, 1, 66,\n                                  9, 0, 11, 10, 10, 18, 26, 14, 8, 12, 62, 62,\n                                  62, 62, 9, 0, 4, 14, 64, 11, 13, 5, 66, 40,\n                                  66, 110, 106, 60, 9, 17, 5, 6, 11, 19, 50, 29,\n                                  13, 66, 1, 2, 20, 24, 105, 4, 5, 80, 66, 75,\n                                  6, 6, 72, 19, 12, 12, 91, 9, 80, 75, 4, 89, 7,\n                                  7, 4, 81, 103, 65, 78, 76, 81, 95, 91, 78,\n                                  126, 62, 126, 88, 91, 99, 114, 100, 112, 126,\n                                  125, 118, 97, 125, 91, 62, 111, 67, 65, 73,\n                                  78, 79, 77, 82, 81, 82, 98, 98, 94, 96, 98,\n                                  122, 75, 77, 99, 74, 81, 82, 89, 92, 98, 95,\n                                  101, 99, 85, 101, 103, 95, 87, 16, 35, 22, 10,\n                                  12, 17, 9, 5, 5, 32, 22, 33, 25, 22, 19, 29,\n                                  20, 27, 23, 20, 18, 48, 40, 35, 31, 36, 14, 6,\n                                  4, 3, 71, 55, 29, 2, 66, 14, 2, 73, 66, 3, 40,\n                                  27, 8, 64, 18, 5, 5, 67, 66, 62, 66, 4, 10,\n                                  11, 10, 6, 18, 22, 9, 20, 23, 34, 66, 3, 72,\n                                  0, 28, 72, 74, 70, 4, 5, 69, 78, 69, 81, 69,\n                                  71, 88, 14, 13, 31, 5, 66, 13, 8, 1, 7, 6, 1,\n                                  76, 0, 65, 69, 67, 17, 99, 82, 16, 85, 67, 74,\n                                  69, 10, 74, 77, 4, 5, 93, 74, 100, 16, 19, 24,\n                                  2, 71, 67, 70, 76, 79, 88, 90, 90, 103, 98,\n                                  99, 123, 114, 121, 126, 112, 111, 105, 101,\n                                  111, 98, 104, 101, 88, 95, 71, 73, 75, 76, 96,\n                                  88, 88, 108, 94, 102, 103, 124, 107, 111, 114,\n                                  81, 79, 118, 83, 86, 96, 112, 101, 108, 109,\n                                  92, 109, 100, 103, 113, 110, 113, 102, 108,\n                                  113, 70, 64, 15, 2, 31, 41, 1, 9, 18, 22, 5,\n                                  20, 37, 4, 64, 26, 77, 109, 126, 126, 126,\n                                  126, 126, 126, 7, 39, 30, 27, 17, 32, 17, 10,\n                                  8, 1, 72, 67, 11, 2, 25, 35, 2, 4, 12, 16, 6,\n                                  14, 29, 7, 0, 26, 77, 109, 126, 126, 126, 126,\n                                  126, 126 },\n\n                                {\n\n                                21,\n                                  4, 82, 21, 4, 82, 17, 26, 28, 12, 71, 88, 97,\n                                  17, 60, 11, 29, 70, 10, 22, 66, 75, 2, 82,\n                                  108, 76, 115, 126, 126, 126, 62, 6, 64, 10,\n                                  22, 66, 86, 11, 11, 66, 0, 67, 67, 64, 80, 78,\n                                  91, 5, 65, 67, 4, 72, 65, 80, 0, 74, 72, 80,\n                                  6, 2, 22, 0, 0, 0, 6, 97, 97, 12, 78, 70, 11,\n                                  71, 85, 49, 24, 16, 57, 62, 30, 33, 22, 33,\n                                  14, 13, 40, 80, 74, 73, 80, 24, 65, 23, 37,\n                                  67, 69, 65, 26, 0, 76, 75, 84, 19, 68, 10, 1,\n                                  65, 10, 0, 12, 10, 11, 20, 27, 14, 9, 13, 62,\n                                  62, 62, 62, 9, 0, 4, 14, 64, 11, 14, 6, 66,\n                                  42, 66, 112, 108, 62, 9, 17, 5, 6, 11, 19, 51,\n                                  30, 13, 66, 1, 2, 20, 25, 106, 4, 5, 81, 66,\n                                  76, 6, 6, 72, 19, 12, 12, 92, 9, 81, 76, 4,\n                                  89, 7, 7, 4, 83, 106, 66, 80, 78, 84, 97, 94,\n                                  80, 126, 62, 126, 90, 93, 101, 117, 103, 115,\n                                  126, 126, 121, 99, 126, 93, 62, 113, 69, 67,\n                                  75, 81, 82, 79, 84, 83, 84, 100, 100, 96, 98,\n                                  99, 124, 75, 77, 100, 75, 82, 83, 90, 93, 99,\n                                  96, 103, 100, 86, 102, 104, 95, 87, 18, 36,\n                                  23, 10, 12, 18, 9, 5, 5, 34, 23, 33, 25, 23,\n                                  20, 30, 21, 28, 24, 22, 19, 48, 40, 35, 31,\n                                  37, 15, 6, 4, 3, 71, 55, 29, 1, 66, 14, 2, 73,\n                                  66, 3, 39, 27, 7, 65, 18, 5, 5, 67, 66, 62,\n                                  65, 6, 11, 12, 11, 7, 20, 24, 10, 21, 25, 36,\n                                  66, 4, 72, 1, 30, 71, 74, 70, 4, 5, 69, 78,\n                                  69, 81, 69, 71, 89, 15, 14, 32, 5, 66, 14, 8,\n                                  1, 7, 6, 1, 76, 0, 65, 69, 67, 17, 100, 83,\n                                  16, 86, 68, 75, 69, 10, 75, 78, 4, 5, 94, 74,\n                                  101, 15, 18, 23, 1, 73, 69, 72, 78, 82, 90,\n                                  93, 93, 106, 100, 101, 126, 118, 125, 126,\n                                  116, 114, 107, 103, 114, 100, 106, 103, 89,\n                                  96, 73, 76, 78, 79, 99, 90, 91, 111, 97, 105,\n                                  106, 126, 109, 113, 115, 82, 80, 119, 85, 88,\n                                  98, 114, 102, 110, 111, 93, 110, 101, 104,\n                                  114, 111, 114, 103, 109, 114, 70, 0, 15, 3,\n                                  32, 42, 1, 9, 18, 22, 5, 20, 38, 4, 64, 25,\n                                  79, 111, 126, 126, 126, 126, 126, 126, 7, 39,\n                                  30, 27, 17, 32, 18, 10, 8, 2, 72, 67, 12, 3,\n                                  26, 36, 2, 5, 12, 16, 6, 14, 29, 7, 0, 25, 79,\n                                  111, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                20,\n                                  4, 82, 20, 4, 82, 19, 27, 28, 12, 71, 89, 99,\n                                  16, 60, 11, 31, 70, 10, 23, 66, 76, 2, 83,\n                                  110, 77, 117, 126, 126, 126, 62, 7, 64, 10,\n                                  23, 66, 86, 12, 11, 66, 0, 67, 66, 64, 80, 78,\n                                  91, 5, 65, 67, 4, 72, 65, 80, 0, 74, 72, 80,\n                                  6, 2, 22, 0, 0, 0, 7, 97, 97, 12, 79, 70, 10,\n                                  71, 85, 51, 25, 17, 59, 62, 32, 34, 24, 35,\n                                  15, 14, 42, 80, 74, 73, 80, 24, 65, 24, 39,\n                                  67, 68, 64, 28, 0, 76, 75, 84, 19, 68, 10, 2,\n                                  64, 11, 1, 13, 11, 12, 21, 29, 15, 10, 14, 62,\n                                  62, 62, 62, 9, 0, 4, 15, 64, 11, 14, 6, 65,\n                                  44, 66, 114, 110, 62, 9, 17, 5, 6, 11, 20, 53,\n                                  31, 13, 66, 1, 2, 21, 26, 107, 4, 5, 81, 67,\n                                  77, 5, 6, 73, 19, 12, 12, 93, 9, 82, 77, 3,\n                                  89, 7, 6, 3, 85, 109, 67, 82, 80, 86, 99, 96,\n                                  82, 126, 62, 126, 92, 95, 103, 120, 105, 118,\n                                  126, 126, 124, 101, 126, 95, 62, 115, 71, 69,\n                                  77, 83, 84, 81, 86, 85, 86, 102, 102, 98, 100,\n                                  101, 126, 75, 77, 100, 76, 83, 84, 91, 94,\n                                  100, 97, 105, 101, 86, 103, 105, 96, 86, 19,\n                                  37, 23, 10, 12, 19, 10, 6, 6, 36, 24, 33, 25,\n                                  23, 21, 31, 22, 30, 26, 24, 20, 49, 41, 36,\n                                  32, 38, 15, 6, 4, 4, 71, 56, 29, 0, 66, 14, 2,\n                                  73, 65, 3, 39, 26, 6, 66, 18, 5, 5, 67, 66,\n                                  62, 64, 7, 12, 14, 13, 8, 22, 26, 11, 23, 27,\n                                  38, 65, 5, 71, 2, 32, 71, 74, 70, 5, 6, 69,\n                                  78, 69, 82, 69, 71, 89, 15, 14, 33, 5, 66, 14,\n                                  8, 1, 7, 6, 1, 77, 0, 65, 69, 67, 18, 101, 84,\n                                  16, 87, 69, 76, 70, 10, 76, 79, 4, 5, 95, 74,\n                                  102, 14, 17, 22, 64, 75, 71, 74, 80, 84, 93,\n                                  96, 96, 109, 103, 103, 126, 122, 126, 126,\n                                  119, 117, 110, 105, 116, 102, 108, 104, 90,\n                                  97, 75, 78, 80, 81, 102, 93, 93, 114, 99, 107,\n                                  108, 126, 111, 115, 117, 83, 81, 121, 86, 89,\n                                  100, 116, 104, 112, 113, 94, 112, 102, 105,\n                                  115, 112, 115, 105, 110, 115, 70, 0, 16, 3,\n                                  33, 43, 1, 10, 19, 23, 5, 21, 39, 4, 64, 24,\n                                  81, 114, 126, 126, 126, 126, 126, 126, 7, 39,\n                                  30, 27, 17, 33, 18, 10, 8, 2, 72, 67, 12, 3,\n                                  27, 37, 2, 5, 12, 16, 6, 14, 30, 7, 0, 24, 81,\n                                  114, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                18,\n                                  3, 83, 18, 3, 83, 20, 28, 28, 12, 72, 91, 102,\n                                  15, 60, 10, 32, 71, 10, 23, 67, 77, 2, 84,\n                                  112, 79, 120, 126, 126, 126, 62, 7, 64, 10,\n                                  23, 67, 87, 12, 11, 67, 0, 67, 66, 65, 81, 78,\n                                  91, 4, 65, 67, 4, 72, 65, 80, 0, 74, 73, 80,\n                                  6, 2, 22, 0, 0, 0, 7, 98, 97, 12, 80, 71, 9,\n                                  72, 86, 53, 26, 18, 60, 62, 33, 35, 25, 36,\n                                  16, 15, 44, 80, 74, 73, 80, 24, 65, 24, 41,\n                                  67, 68, 64, 29, 64, 77, 76, 85, 19, 68, 10, 2,\n                                  64, 11, 1, 13, 11, 12, 22, 30, 15, 11, 15, 62,\n                                  62, 62, 62, 9, 0, 4, 15, 65, 11, 14, 6, 65,\n                                  46, 66, 116, 112, 62, 9, 17, 5, 6, 11, 20, 54,\n                                  31, 13, 67, 0, 2, 21, 26, 109, 4, 5, 82, 68,\n                                  79, 4, 5, 74, 19, 12, 11, 95, 9, 83, 78, 2,\n                                  89, 6, 5, 2, 88, 113, 69, 84, 83, 89, 102, 99,\n                                  84, 126, 62, 126, 95, 97, 106, 124, 108, 122,\n                                  126, 126, 126, 103, 126, 97, 62, 117, 74, 72,\n                                  80, 86, 87, 84, 89, 88, 88, 105, 105, 100,\n                                  102, 103, 126, 75, 78, 101, 77, 85, 86, 93,\n                                  96, 102, 99, 107, 102, 87, 104, 106, 97, 86,\n                                  20, 37, 23, 10, 12, 19, 10, 6, 6, 38, 25, 33,\n                                  25, 23, 21, 31, 23, 31, 27, 25, 20, 49, 41,\n                                  36, 32, 39, 15, 6, 4, 4, 72, 56, 28, 64, 67,\n                                  14, 2, 73, 65, 2, 38, 25, 4, 67, 17, 5, 5, 67,\n                                  66, 62, 0, 8, 13, 15, 14, 9, 23, 27, 12, 24,\n                                  28, 40, 65, 5, 71, 3, 33, 71, 74, 70, 5, 6,\n                                  69, 79, 70, 83, 69, 72, 90, 15, 14, 34, 5, 67,\n                                  14, 8, 0, 7, 6, 1, 78, 0, 65, 69, 67, 18, 102,\n                                  85, 16, 89, 70, 77, 71, 9, 77, 80, 4, 4, 97,\n                                  75, 104, 12, 15, 21, 66, 77, 74, 77, 83, 87,\n                                  96, 99, 99, 113, 106, 105, 126, 126, 126, 126,\n                                  123, 121, 113, 108, 119, 104, 110, 106, 91,\n                                  98, 78, 81, 83, 84, 105, 96, 96, 118, 102,\n                                  110, 111, 126, 113, 117, 119, 84, 82, 123, 88,\n                                  91, 102, 119, 106, 114, 115, 96, 114, 104,\n                                  106, 117, 113, 116, 107, 112, 117, 70, 0, 16,\n                                  3, 34, 44, 1, 10, 19, 23, 5, 21, 39, 4, 65,\n                                  22, 83, 117, 126, 126, 126, 126, 126, 126, 7,\n                                  39, 30, 27, 17, 33, 18, 10, 8, 2, 72, 67, 12,\n                                  3, 27, 37, 2, 5, 12, 16, 6, 14, 30, 6, 64, 22,\n                                  83, 117, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                17,\n                                  3, 83, 17, 3, 83, 22, 30, 29, 13, 72, 92, 104,\n                                  14, 61, 10, 34, 71, 11, 24, 67, 77, 3, 84,\n                                  113, 80, 122, 126, 126, 126, 62, 8, 0, 11, 24,\n                                  67, 87, 13, 11, 67, 1, 66, 65, 65, 81, 77, 90,\n                                  4, 64, 66, 4, 71, 64, 79, 1, 73, 73, 79, 7, 2,\n                                  22, 0, 0, 0, 8, 98, 97, 13, 80, 71, 9, 72, 86,\n                                  56, 28, 20, 62, 62, 35, 37, 27, 38, 18, 17,\n                                  47, 80, 73, 72, 79, 24, 65, 25, 44, 66, 67, 0,\n                                  31, 64, 77, 76, 85, 20, 68, 11, 3, 0, 12, 2,\n                                  14, 12, 13, 24, 32, 16, 13, 17, 62, 62, 62,\n                                  62, 10, 1, 5, 16, 65, 12, 15, 7, 64, 49, 65,\n                                  118, 113, 62, 9, 18, 5, 7, 12, 21, 56, 32, 14,\n                                  67, 0, 2, 22, 27, 110, 5, 5, 82, 68, 80, 4, 5,\n                                  74, 19, 12, 11, 96, 10, 83, 78, 2, 89, 6, 5,\n                                  2, 90, 116, 70, 85, 85, 91, 104, 101, 86, 126,\n                                  62, 126, 97, 98, 108, 126, 110, 125, 126, 126,\n                                  126, 105, 126, 99, 62, 118, 76, 74, 82, 88,\n                                  89, 86, 91, 90, 90, 107, 107, 101, 103, 104,\n                                  126, 75, 78, 101, 77, 86, 87, 94, 97, 103,\n                                  100, 108, 103, 87, 105, 106, 97, 85, 22, 38,\n                                  24, 10, 13, 20, 11, 7, 7, 41, 27, 34, 26, 24,\n                                  22, 32, 25, 33, 29, 27, 21, 50, 42, 37, 33,\n                                  40, 16, 7, 5, 5, 72, 57, 28, 64, 67, 15, 3,\n                                  73, 64, 2, 38, 25, 3, 68, 17, 6, 6, 66, 65,\n                                  62, 2, 10, 15, 17, 16, 11, 25, 29, 14, 26, 30,\n                                  43, 64, 6, 70, 5, 35, 70, 73, 69, 6, 7, 68,\n                                  79, 70, 83, 69, 72, 90, 16, 15, 35, 6, 67, 15,\n                                  9, 0, 8, 7, 1, 78, 1, 64, 68, 66, 19, 102, 86,\n                                  16, 90, 70, 77, 71, 9, 77, 80, 4, 4, 98, 75,\n                                  105, 11, 14, 21, 67, 78, 76, 79, 85, 89, 98,\n                                  101, 101, 116, 108, 107, 126, 126, 126, 126,\n                                  126, 124, 115, 110, 121, 105, 111, 107, 91,\n                                  98, 80, 83, 85, 86, 107, 98, 98, 121, 104,\n                                  112, 113, 126, 114, 118, 120, 84, 82, 124, 89,\n                                  92, 103, 121, 107, 115, 116, 97, 115, 105,\n                                  106, 118, 113, 116, 108, 113, 118, 69, 1, 17,\n                                  4, 36, 46, 2, 11, 20, 24, 6, 22, 40, 4, 65,\n                                  21, 85, 119, 126, 126, 126, 126, 126, 126, 8,\n                                  39, 31, 28, 18, 34, 19, 11, 9, 3, 71, 66, 13,\n                                  4, 28, 38, 3, 6, 13, 17, 6, 15, 31, 6, 64, 21,\n                                  85, 119, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                16,\n                                  3, 83, 16, 3, 83, 24, 31, 29, 13, 72, 93, 106,\n                                  13, 61, 10, 36, 71, 11, 25, 67, 78, 3, 85,\n                                  115, 81, 125, 126, 126, 126, 62, 9, 0, 11, 25,\n                                  67, 87, 14, 11, 68, 1, 66, 64, 65, 81, 77, 90,\n                                  4, 64, 66, 4, 71, 64, 79, 1, 73, 73, 79, 7, 2,\n                                  22, 0, 0, 0, 9, 98, 97, 13, 81, 71, 8, 72, 86,\n                                  58, 29, 21, 62, 62, 36, 38, 29, 39, 19, 18,\n                                  49, 80, 73, 72, 79, 24, 65, 26, 46, 66, 66, 1,\n                                  33, 64, 77, 76, 86, 20, 68, 11, 4, 1, 13, 3,\n                                  15, 12, 14, 25, 33, 17, 14, 18, 62, 62, 62,\n                                  62, 10, 1, 5, 16, 65, 12, 15, 7, 64, 51, 65,\n                                  120, 115, 62, 9, 18, 5, 7, 12, 21, 58, 33, 14,\n                                  67, 0, 2, 23, 28, 111, 5, 5, 82, 69, 81, 3, 5,\n                                  75, 19, 12, 11, 97, 10, 84, 79, 1, 89, 6, 4,\n                                  1, 92, 119, 71, 87, 87, 93, 106, 103, 88, 126,\n                                  62, 126, 99, 100, 110, 126, 112, 126, 126,\n                                  126, 126, 107, 126, 101, 62, 120, 78, 76, 84,\n                                  90, 91, 88, 93, 92, 92, 109, 109, 103, 105,\n                                  106, 126, 75, 78, 102, 78, 87, 88, 95, 98,\n                                  104, 101, 110, 104, 87, 106, 107, 98, 84, 23,\n                                  39, 24, 10, 13, 21, 12, 8, 8, 43, 28, 34, 26,\n                                  24, 23, 33, 26, 35, 31, 29, 22, 51, 43, 38,\n                                  34, 41, 16, 7, 5, 6, 72, 58, 28, 65, 67, 15,\n                                  3, 73, 64, 2, 38, 24, 2, 69, 17, 6, 6, 66, 65,\n                                  62, 3, 11, 16, 19, 18, 12, 27, 31, 15, 28, 32,\n                                  45, 0, 7, 70, 6, 37, 70, 73, 69, 7, 7, 68, 79,\n                                  70, 84, 69, 72, 90, 16, 15, 36, 6, 67, 15, 9,\n                                  0, 8, 7, 1, 79, 1, 64, 68, 66, 20, 103, 87,\n                                  16, 91, 71, 78, 72, 9, 78, 81, 4, 4, 99, 75,\n                                  106, 10, 13, 20, 69, 80, 78, 81, 87, 91, 101,\n                                  104, 104, 119, 111, 109, 126, 126, 126, 126,\n                                  126, 126, 118, 112, 124, 107, 113, 108, 92,\n                                  99, 82, 85, 88, 88, 110, 101, 101, 124, 106,\n                                  115, 115, 126, 116, 120, 122, 85, 83, 126, 90,\n                                  93, 105, 123, 109, 117, 118, 98, 117, 106,\n                                  107, 119, 114, 117, 110, 114, 119, 69, 1, 18,\n                                  4, 37, 47, 2, 12, 21, 25, 6, 22, 41, 4, 65,\n                                  20, 87, 122, 126, 126, 126, 126, 126, 126, 8,\n                                  39, 31, 28, 18, 35, 19, 11, 9, 3, 71, 66, 13,\n                                  4, 29, 39, 3, 6, 13, 17, 6, 15, 32, 6, 64, 20,\n                                  87, 122, 126, 126, 126, 126, 126, 126 },\n\n                                {\n\n                                15,\n                                  3, 83, 15, 3, 83, 26, 33, 30, 13, 73, 95, 108,\n                                  12, 61, 10, 38, 71, 12, 26, 67, 78, 3, 85,\n                                  116, 82, 126, 126, 126, 126, 62, 10, 0, 12,\n                                  26, 67, 88, 15, 11, 68, 1, 66, 64, 65, 81, 77,\n                                  90, 4, 64, 65, 4, 71, 0, 79, 1, 73, 73, 79, 7,\n                                  2, 22, 0, 0, 0, 9, 98, 97, 14, 82, 71, 7, 73,\n                                  86, 61, 30, 22, 62, 62, 38, 40, 31, 41, 20,\n                                  19, 51, 80, 73, 71, 79, 24, 65, 27, 48, 66,\n                                  65, 1, 35, 64, 78, 77, 86, 20, 68, 12, 4, 2,\n                                  14, 3, 16, 13, 15, 27, 35, 17, 15, 19, 62, 62,\n                                  62, 62, 10, 1, 5, 17, 65, 12, 16, 8, 0, 53,\n                                  65, 122, 117, 62, 9, 18, 5, 7, 12, 22, 59, 34,\n                                  14, 67, 0, 2, 23, 29, 112, 5, 5, 83, 69, 82,\n                                  3, 5, 75, 19, 12, 11, 98, 10, 85, 80, 1, 89,\n                                  6, 4, 1, 94, 122, 72, 89, 89, 96, 108, 106,\n                                  90, 126, 62, 126, 101, 102, 112, 126, 115,\n                                  126, 126, 126, 126, 109, 126, 103, 62, 122,\n                                  80, 78, 86, 93, 94, 90, 95, 94, 94, 111, 111,\n                                  105, 107, 107, 126, 75, 78, 102, 79, 88, 89,\n                                  96, 99, 105, 102, 112, 105, 88, 107, 108, 98,\n                                  84, 25, 40, 25, 10, 13, 22, 12, 8, 8, 45, 29,\n                                  34, 26, 25, 24, 34, 27, 36, 32, 31, 23, 51,\n                                  43, 38, 34, 42, 17, 7, 5, 6, 72, 58, 28, 66,\n                                  67, 15, 3, 73, 0, 2, 37, 24, 1, 70, 17, 6, 6,\n                                  66, 65, 62, 4, 13, 17, 20, 19, 13, 29, 33, 16,\n                                  29, 34, 47, 0, 8, 69, 7, 39, 69, 73, 69, 7, 8,\n                                  68, 79, 70, 84, 69, 72, 91, 17, 16, 37, 6, 67,\n                                  16, 9, 0, 8, 7, 1, 79, 1, 64, 68, 66, 20, 104,\n                                  88, 16, 92, 72, 79, 72, 9, 79, 82, 4, 4, 100,\n                                  75, 107, 9, 12, 19, 70, 82, 80, 83, 89, 94,\n                                  103, 107, 107, 122, 113, 111, 126, 126, 126,\n                                  126, 126, 126, 120, 114, 126, 109, 115, 110,\n                                  93, 100, 84, 88, 90, 91, 113, 103, 103, 126,\n                                  109, 117, 118, 126, 118, 122, 123, 86, 84,\n                                  126, 92, 95, 107, 125, 110, 119, 120, 99, 118,\n                                  107, 108, 120, 115, 118, 111, 115, 120, 69, 2,\n                                  18, 5, 38, 48, 2, 12, 21, 25, 6, 23, 42, 4,\n                                  65, 19, 89, 124, 126, 126, 126, 126, 126, 126,\n                                  8, 39, 31, 28, 18, 35, 20, 11, 9, 4, 71, 66,\n                                  14, 5, 30, 40, 3, 7, 13, 17, 6, 15, 32, 6, 64,\n                                  19, 89, 124, 126, 126, 126, 126, 126, 126 },\n\n                          },\n\n                          {\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 126, 104, 10, 9, 12, 47, 62,\n                                62, 12, 1, 99, 47, 85, 102, 6, 6, 73, 6, 23, 53,\n                                62, 62, 21, 97, 126, 117, 74, 85, 102, 6, 93,\n                                88, 19, 8, 89, 103, 116, 6, 5, 84, 96, 0, 85,\n                                106, 0, 75, 90, 101, 8, 79, 75, 97, 13, 3, 22,\n                                0, 0, 0, 83, 86, 97, 72, 22, 1, 29, 88, 126,\n                                126, 91, 95, 84, 86, 89, 91, 126, 76, 103, 90,\n                                126, 80, 76, 84, 78, 8, 2, 83, 126, 79, 104, 91,\n                                126, 65, 79, 72, 92, 7, 68, 71, 98, 86, 88, 82,\n                                72, 67, 72, 89, 69, 4, 66, 6, 71, 71, 5, 74, 19,\n                                69, 1, 12, 16, 21, 22, 10, 76, 78, 83, 11, 67,\n                                90, 67, 72, 75, 80, 83, 64, 32, 64, 94, 75, 0,\n                                74, 28, 36, 91, 65, 69, 77, 66, 1, 68, 81, 33,\n                                56, 40, 74, 66, 124, 26, 62, 62, 126, 24, 21,\n                                29, 34, 32, 26, 21, 23, 30, 20, 27, 16, 8, 5, 3,\n                                19, 19, 21, 15, 7, 11, 26, 14, 5, 15, 18, 69,\n                                30, 0, 62, 62, 62, 53, 62, 62, 62, 62, 46, 38,\n                                34, 30, 48, 43, 73, 29, 32, 19, 47, 27, 27, 35,\n                                42, 43, 51, 47, 21, 93, 7, 6, 25, 126, 115, 82,\n                                1, 10, 4, 85, 89, 94, 92, 126, 100, 6, 67, 71,\n                                77, 85, 88, 104, 98, 126, 82, 15, 2, 66, 70, 75,\n                                79, 83, 92, 108, 79, 69, 75, 5, 5, 78, 83, 81,\n                                99, 81, 25, 1, 5, 4, 73, 76, 86, 83, 87, 62,\n                                126, 126, 120, 126, 114, 117, 118, 117, 113,\n                                118, 120, 124, 94, 102, 99, 106, 126, 92, 6, 86,\n                                94, 91, 77, 71, 73, 64, 81, 64, 6, 67, 68, 67,\n                                68, 77, 64, 68, 78, 8, 4, 65, 9, 19, 3, 70, 76,\n                                86, 70, 64, 70, 8, 7, 69, 65, 74, 9, 9, 76, 82,\n                                77, 77, 21, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 62, 62, 62, 52, 62, 62, 62, 62, 62, 62,\n                                48, 62, 62, 46, 25, 18, 9, 79, 62, 62, 62, 62,\n                                48, 48, 38, 41, 47, 45, 35, 22, 35, 16, 1, 32,\n                                37, 39, 40, 47, 33, 34, 22, 21, 3, 11, 3, 78,\n                                123, 10, 7, 2, 30, 13, 2, 78, 74, 72, 72, 75,\n                                71, 0, 70, 75, 72, 67, 10, 4, 11, 68, 62, 62,\n                                62, 62, 56, 51, 40, 25, 64, 71, 26, 19, 14, 7,\n                                4, 0, 67, 68, 79, 78, 74, 72, 72, 75, 71, 0, 70,\n                                75, 72, 67, 10, 4, 11, 68, 62, 62, 62, 62, 56,\n                                51, 40, 25, 64 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 125, 102, 11, 10, 12, 46,\n                                  62, 62, 13, 2, 97, 46, 84, 100, 6, 6, 71, 6,\n                                  22, 52, 62, 60, 19, 97, 125, 115, 73, 84, 100,\n                                  6, 92, 87, 20, 8, 88, 102, 114, 5, 4, 84, 96,\n                                  0, 84, 105, 0, 75, 89, 100, 8, 78, 74, 96, 14,\n                                  3, 22, 0, 0, 0, 82, 86, 97, 71, 22, 1, 29, 87,\n                                  125, 124, 89, 94, 82, 84, 88, 89, 125, 75,\n                                  101, 89, 124, 80, 76, 84, 78, 9, 2, 82, 124,\n                                  78, 103, 90, 125, 65, 78, 72, 91, 8, 68, 70,\n                                  97, 85, 87, 81, 71, 66, 71, 88, 68, 5, 66, 6,\n                                  70, 70, 5, 73, 20, 68, 1, 13, 17, 22, 23, 11,\n                                  76, 77, 82, 11, 67, 89, 67, 71, 74, 79, 81, 1,\n                                  33, 1, 92, 75, 64, 73, 29, 37, 91, 65, 68, 77,\n                                  65, 1, 67, 79, 33, 56, 41, 72, 67, 122, 25,\n                                  62, 62, 125, 24, 21, 29, 34, 32, 26, 21, 23,\n                                  30, 20, 27, 16, 8, 5, 3, 19, 19, 21, 15, 7,\n                                  11, 26, 14, 4, 15, 18, 69, 29, 0, 62, 62, 62,\n                                  52, 62, 62, 62, 62, 45, 37, 32, 29, 46, 42,\n                                  74, 28, 31, 18, 46, 27, 27, 34, 41, 42, 50,\n                                  46, 20, 93, 7, 6, 24, 125, 113, 80, 2, 10, 4,\n                                  84, 88, 93, 91, 125, 98, 7, 66, 70, 76, 83,\n                                  87, 102, 97, 124, 81, 16, 3, 65, 69, 74, 78,\n                                  82, 91, 106, 78, 67, 74, 6, 5, 77, 82, 80, 98,\n                                  80, 26, 2, 6, 5, 72, 75, 85, 82, 86, 62, 125,\n                                  125, 118, 125, 112, 115, 116, 115, 111, 116,\n                                  118, 121, 93, 101, 98, 105, 123, 91, 5, 85,\n                                  93, 90, 76, 71, 72, 64, 80, 64, 6, 67, 68, 66,\n                                  68, 77, 64, 68, 77, 8, 4, 65, 9, 19, 3, 70,\n                                  75, 84, 70, 64, 69, 8, 7, 69, 65, 73, 9, 9,\n                                  75, 81, 76, 76, 20, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 50, 62, 62,\n                                  62, 62, 62, 62, 47, 60, 60, 45, 24, 17, 9, 79,\n                                  62, 62, 62, 60, 46, 47, 37, 39, 46, 43, 34,\n                                  20, 33, 15, 0, 31, 36, 37, 39, 46, 32, 33, 21,\n                                  20, 2, 11, 3, 78, 122, 9, 6, 1, 29, 12, 1, 77,\n                                  73, 71, 71, 73, 70, 1, 69, 73, 71, 66, 11, 5,\n                                  12, 67, 62, 62, 62, 62, 54, 50, 38, 24, 65,\n                                  70, 27, 20, 15, 8, 5, 1, 66, 67, 78, 77, 73,\n                                  71, 71, 73, 70, 1, 69, 73, 71, 66, 11, 5, 12,\n                                  67, 62, 62, 62, 62, 54, 50, 38, 24, 65 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 123, 101, 11, 10, 12, 44,\n                                  60, 62, 14, 2, 95, 44, 84, 99, 6, 6, 70, 5,\n                                  21, 51, 60, 57, 17, 98, 123, 114, 73, 84, 99,\n                                  6, 92, 86, 20, 8, 87, 101, 113, 4, 3, 84, 96,\n                                  0, 84, 104, 0, 75, 89, 100, 8, 78, 74, 95, 14,\n                                  3, 22, 0, 0, 0, 81, 86, 97, 71, 21, 1, 29, 86,\n                                  124, 122, 88, 93, 80, 82, 87, 88, 123, 74,\n                                  100, 88, 122, 81, 76, 84, 78, 9, 2, 81, 122,\n                                  78, 102, 89, 123, 65, 78, 72, 91, 8, 68, 70,\n                                  96, 85, 86, 81, 71, 66, 71, 87, 67, 5, 66, 6,\n                                  70, 70, 5, 73, 20, 68, 1, 13, 17, 22, 23, 11,\n                                  77, 76, 81, 10, 67, 89, 67, 70, 74, 79, 80, 2,\n                                  34, 3, 90, 76, 65, 73, 29, 37, 92, 65, 68, 78,\n                                  64, 1, 67, 78, 33, 56, 41, 71, 68, 121, 24,\n                                  62, 62, 124, 24, 21, 29, 33, 31, 26, 21, 23,\n                                  29, 19, 26, 16, 8, 5, 3, 18, 18, 20, 15, 7,\n                                  11, 25, 13, 3, 14, 17, 69, 28, 64, 62, 62, 62,\n                                  50, 60, 62, 62, 62, 44, 35, 30, 27, 44, 40,\n                                  75, 27, 30, 16, 45, 26, 26, 33, 39, 40, 48,\n                                  44, 18, 93, 6, 5, 22, 124, 112, 79, 3, 10, 4,\n                                  83, 87, 92, 90, 123, 97, 8, 65, 69, 75, 82,\n                                  86, 101, 96, 122, 80, 16, 3, 65, 69, 73, 77,\n                                  81, 90, 105, 78, 66, 73, 6, 5, 76, 81, 80, 97,\n                                  79, 26, 3, 6, 5, 71, 74, 84, 81, 85, 62, 124,\n                                  123, 116, 123, 111, 114, 114, 113, 110, 114,\n                                  116, 119, 92, 100, 97, 104, 120, 91, 4, 85,\n                                  92, 89, 76, 71, 72, 64, 80, 64, 5, 67, 68, 65,\n                                  68, 77, 64, 68, 77, 8, 4, 65, 8, 18, 3, 70,\n                                  75, 83, 71, 64, 68, 7, 7, 69, 65, 73, 9, 9,\n                                  75, 80, 76, 76, 18, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 48, 62, 62,\n                                  62, 62, 62, 61, 45, 58, 58, 43, 23, 16, 8, 79,\n                                  62, 62, 62, 58, 44, 45, 35, 37, 44, 41, 32,\n                                  18, 31, 13, 64, 30, 35, 35, 37, 44, 30, 31,\n                                  20, 19, 1, 10, 2, 78, 121, 8, 5, 64, 28, 11,\n                                  0, 77, 73, 70, 70, 72, 69, 2, 69, 72, 70, 65,\n                                  11, 6, 13, 66, 62, 62, 62, 60, 52, 48, 36, 22,\n                                  66, 69, 27, 20, 16, 9, 6, 1, 65, 67, 77, 77,\n                                  73, 70, 70, 72, 69, 2, 69, 72, 70, 65, 11, 6,\n                                  13, 66, 62, 62, 62, 60, 52, 48, 36, 22, 66 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 121, 99, 12, 10, 11, 42, 59,\n                                  61, 14, 2, 93, 43, 84, 97, 6, 5, 69, 4, 20,\n                                  50, 58, 53, 15, 99, 121, 112, 73, 84, 97, 6,\n                                  91, 85, 21, 8, 86, 100, 112, 3, 2, 84, 97, 0,\n                                  84, 103, 0, 76, 89, 100, 8, 78, 74, 94, 15, 3,\n                                  22, 0, 0, 0, 81, 86, 97, 70, 20, 1, 28, 86,\n                                  123, 120, 87, 92, 79, 81, 86, 87, 121, 73, 99,\n                                  87, 120, 82, 76, 84, 78, 10, 2, 80, 120, 78,\n                                  101, 88, 121, 65, 78, 72, 91, 9, 68, 69, 95,\n                                  85, 85, 81, 71, 66, 70, 86, 67, 5, 66, 6, 70,\n                                  70, 5, 73, 20, 68, 1, 14, 17, 23, 23, 12, 77,\n                                  76, 80, 10, 67, 89, 67, 69, 74, 78, 79, 3, 35,\n                                  4, 88, 76, 66, 72, 29, 37, 93, 65, 67, 78, 64,\n                                  1, 67, 77, 33, 56, 41, 70, 69, 119, 23, 62,\n                                  62, 122, 24, 21, 28, 32, 31, 25, 20, 23, 29,\n                                  18, 25, 16, 8, 5, 2, 18, 17, 19, 14, 7, 11,\n                                  24, 13, 2, 14, 16, 69, 27, 64, 62, 62, 61, 49,\n                                  58, 62, 62, 62, 43, 33, 28, 26, 42, 38, 77,\n                                  26, 29, 14, 44, 25, 25, 32, 38, 38, 46, 42,\n                                  17, 93, 5, 4, 21, 122, 110, 77, 3, 10, 4, 82,\n                                  86, 91, 89, 121, 96, 9, 64, 68, 75, 81, 85,\n                                  99, 95, 120, 80, 17, 4, 64, 68, 72, 77, 81,\n                                  89, 104, 78, 64, 72, 6, 5, 75, 81, 80, 96, 78,\n                                  27, 4, 7, 5, 70, 74, 83, 81, 85, 62, 122, 122,\n                                  115, 121, 110, 112, 113, 112, 108, 112, 114,\n                                  117, 92, 99, 97, 103, 117, 91, 3, 85, 91, 88,\n                                  76, 71, 72, 64, 79, 64, 4, 67, 68, 65, 68, 77,\n                                  64, 68, 77, 7, 4, 65, 7, 17, 3, 70, 75, 82,\n                                  72, 64, 67, 6, 7, 69, 65, 72, 9, 8, 74, 79,\n                                  76, 76, 17, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 46, 62, 62, 62, 62,\n                                  62, 59, 43, 56, 55, 41, 22, 15, 7, 79, 62, 62,\n                                  62, 56, 42, 43, 34, 35, 42, 39, 30, 16, 29,\n                                  11, 65, 29, 34, 33, 36, 42, 29, 29, 18, 17, 0,\n                                  9, 1, 78, 120, 7, 3, 65, 27, 10, 64, 77, 72,\n                                  70, 70, 71, 68, 3, 69, 71, 69, 64, 12, 7, 13,\n                                  65, 62, 62, 62, 58, 50, 46, 34, 20, 67, 69,\n                                  28, 21, 17, 9, 7, 2, 65, 66, 77, 77, 72, 70,\n                                  70, 71, 68, 3, 69, 71, 69, 64, 12, 7, 13, 65,\n                                  62, 62, 62, 58, 50, 46, 34, 20, 67 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 120, 98, 12, 10, 11, 40, 57,\n                                  60, 15, 2, 92, 41, 84, 96, 5, 5, 68, 3, 18,\n                                  48, 56, 50, 12, 100, 119, 111, 73, 84, 96, 5,\n                                  91, 84, 21, 7, 86, 99, 110, 2, 0, 85, 97, 0,\n                                  83, 102, 64, 76, 89, 100, 8, 78, 74, 94, 15,\n                                  3, 22, 0, 0, 0, 80, 87, 97, 70, 19, 1, 28, 85,\n                                  122, 118, 86, 91, 77, 79, 86, 86, 119, 72, 98,\n                                  86, 117, 82, 77, 84, 79, 10, 1, 79, 117, 77,\n                                  101, 88, 119, 65, 78, 72, 91, 9, 68, 69, 94,\n                                  85, 85, 80, 71, 66, 70, 85, 66, 5, 67, 5, 70,\n                                  70, 5, 73, 20, 68, 1, 14, 17, 23, 23, 12, 78,\n                                  75, 80, 9, 67, 88, 67, 68, 73, 78, 77, 5, 36,\n                                  6, 86, 77, 67, 72, 30, 37, 94, 65, 67, 79, 0,\n                                  1, 67, 76, 33, 56, 41, 68, 70, 118, 22, 62,\n                                  62, 121, 23, 21, 28, 32, 30, 25, 20, 23, 28,\n                                  17, 24, 15, 8, 5, 2, 17, 17, 18, 14, 6, 10,\n                                  23, 12, 1, 13, 15, 69, 25, 65, 62, 62, 59, 47,\n                                  57, 62, 62, 62, 42, 31, 25, 24, 40, 36, 78,\n                                  24, 28, 13, 43, 24, 24, 30, 36, 36, 44, 41,\n                                  15, 93, 4, 3, 19, 121, 109, 76, 4, 10, 4, 81,\n                                  85, 90, 89, 119, 94, 10, 64, 68, 74, 79, 84,\n                                  98, 94, 117, 79, 17, 4, 64, 68, 71, 76, 80,\n                                  89, 103, 78, 0, 71, 6, 5, 74, 80, 80, 95, 77,\n                                  27, 5, 7, 5, 69, 73, 82, 80, 84, 62, 121, 120,\n                                  113, 120, 109, 111, 111, 110, 107, 111, 112,\n                                  114, 91, 98, 96, 102, 114, 90, 2, 84, 90, 88,\n                                  76, 71, 72, 65, 79, 65, 3, 67, 68, 64, 68, 77,\n                                  64, 68, 76, 7, 3, 65, 6, 16, 2, 70, 75, 81,\n                                  73, 65, 67, 6, 6, 69, 65, 72, 8, 8, 74, 79,\n                                  76, 76, 15, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 44, 62, 62, 62, 62,\n                                  62, 57, 41, 54, 53, 39, 20, 14, 6, 79, 62, 62,\n                                  62, 54, 40, 41, 32, 33, 40, 37, 28, 14, 26,\n                                  10, 67, 28, 33, 30, 34, 41, 27, 27, 17, 16,\n                                  64, 8, 0, 78, 119, 5, 2, 67, 25, 9, 65, 77,\n                                  72, 69, 69, 70, 68, 3, 68, 70, 68, 0, 12, 8,\n                                  14, 65, 62, 62, 60, 56, 48, 44, 31, 18, 69,\n                                  68, 28, 21, 17, 10, 7, 2, 64, 66, 76, 77, 72,\n                                  69, 69, 70, 68, 3, 68, 70, 68, 0, 12, 8, 14,\n                                  65, 62, 62, 60, 56, 48, 44, 31, 18, 69 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 118, 96, 12, 10, 10, 38, 56,\n                                  59, 16, 2, 90, 39, 83, 94, 5, 5, 67, 2, 17,\n                                  47, 54, 47, 10, 100, 117, 110, 73, 83, 94, 5,\n                                  91, 83, 21, 7, 85, 98, 109, 1, 64, 85, 97, 0,\n                                  83, 101, 64, 76, 89, 100, 8, 77, 74, 93, 16,\n                                  3, 22, 0, 0, 0, 80, 87, 97, 69, 18, 1, 27, 85,\n                                  120, 115, 85, 90, 76, 78, 85, 85, 117, 71, 97,\n                                  85, 115, 83, 77, 84, 79, 10, 1, 78, 115, 77,\n                                  100, 87, 117, 65, 78, 72, 90, 9, 68, 68, 93,\n                                  84, 84, 80, 71, 65, 69, 84, 66, 5, 67, 5, 69,\n                                  70, 5, 73, 21, 68, 1, 15, 18, 23, 23, 12, 78,\n                                  75, 79, 9, 67, 88, 67, 67, 73, 77, 76, 6, 37,\n                                  7, 84, 77, 68, 71, 30, 37, 95, 65, 66, 79, 1,\n                                  1, 67, 74, 33, 56, 41, 67, 71, 116, 21, 62,\n                                  62, 120, 23, 21, 27, 31, 30, 25, 19, 23, 28,\n                                  16, 23, 15, 8, 5, 2, 17, 16, 17, 13, 6, 10,\n                                  22, 12, 0, 12, 15, 69, 24, 65, 62, 62, 58, 46,\n                                  55, 62, 62, 62, 41, 29, 23, 23, 38, 34, 79,\n                                  23, 27, 11, 42, 23, 23, 29, 35, 34, 42, 39,\n                                  14, 93, 3, 2, 17, 119, 107, 75, 4, 10, 4, 80,\n                                  84, 89, 88, 117, 93, 11, 0, 67, 73, 78, 83,\n                                  96, 93, 115, 78, 18, 5, 0, 67, 70, 75, 80, 88,\n                                  102, 77, 1, 70, 6, 5, 73, 80, 79, 94, 76, 27,\n                                  6, 7, 5, 68, 72, 81, 80, 83, 62, 120, 119,\n                                  112, 118, 108, 109, 110, 108, 105, 109, 110,\n                                  112, 90, 97, 95, 101, 111, 90, 1, 84, 89, 87,\n                                  76, 71, 72, 65, 78, 65, 2, 67, 68, 0, 68, 77,\n                                  64, 68, 76, 6, 3, 65, 5, 15, 2, 70, 75, 80,\n                                  73, 65, 66, 5, 6, 69, 65, 72, 8, 7, 74, 78,\n                                  76, 76, 14, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 42, 62, 62, 62, 62,\n                                  62, 55, 40, 52, 50, 37, 19, 13, 5, 79, 62, 62,\n                                  62, 52, 38, 39, 31, 31, 38, 35, 26, 12, 24, 8,\n                                  68, 27, 32, 28, 33, 39, 26, 25, 16, 15, 65, 7,\n                                  64, 78, 118, 4, 1, 68, 24, 8, 66, 77, 71, 69,\n                                  68, 69, 67, 4, 68, 69, 67, 1, 13, 9, 14, 64,\n                                  62, 62, 58, 54, 46, 42, 29, 16, 70, 68, 29,\n                                  22, 18, 11, 8, 3, 64, 66, 75, 77, 71, 69, 68,\n                                  69, 67, 4, 68, 69, 67, 1, 13, 9, 14, 64, 62,\n                                  62, 58, 54, 46, 42, 29, 16, 70 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 116, 95, 13, 10, 10, 37, 54,\n                                  58, 16, 3, 88, 38, 83, 93, 5, 4, 66, 1, 16,\n                                  46, 53, 43, 8, 101, 115, 108, 73, 83, 93, 5,\n                                  90, 82, 22, 7, 84, 97, 108, 64, 65, 85, 98, 0,\n                                  83, 101, 64, 77, 88, 100, 7, 77, 74, 92, 16,\n                                  3, 22, 0, 0, 0, 79, 87, 97, 69, 18, 0, 27, 84,\n                                  119, 113, 84, 89, 74, 76, 84, 84, 115, 70, 96,\n                                  85, 113, 84, 77, 84, 79, 11, 1, 77, 113, 77,\n                                  99, 86, 115, 65, 78, 72, 90, 10, 69, 68, 93,\n                                  84, 83, 80, 70, 65, 69, 83, 65, 5, 67, 5, 69,\n                                  70, 5, 73, 21, 68, 1, 15, 18, 24, 24, 13, 79,\n                                  74, 78, 8, 67, 88, 67, 66, 73, 77, 75, 7, 37,\n                                  9, 83, 78, 69, 71, 30, 37, 95, 66, 66, 80, 1,\n                                  0, 66, 73, 33, 56, 42, 66, 72, 115, 20, 62,\n                                  62, 118, 23, 21, 27, 30, 29, 24, 19, 22, 27,\n                                  16, 23, 15, 7, 5, 1, 16, 15, 16, 13, 6, 10,\n                                  22, 11, 65, 12, 14, 69, 23, 66, 62, 62, 56,\n                                  44, 53, 62, 62, 62, 39, 27, 21, 21, 36, 32,\n                                  81, 22, 25, 9, 40, 22, 22, 28, 33, 32, 40, 37,\n                                  12, 93, 2, 1, 16, 118, 106, 73, 5, 10, 4, 79,\n                                  84, 89, 87, 116, 92, 12, 1, 66, 73, 77, 82,\n                                  95, 92, 113, 78, 18, 5, 0, 67, 69, 75, 79, 87,\n                                  101, 77, 3, 69, 6, 5, 73, 79, 79, 94, 76, 28,\n                                  6, 8, 5, 67, 72, 81, 79, 83, 62, 118, 117,\n                                  110, 116, 106, 108, 108, 107, 104, 107, 108,\n                                  110, 90, 96, 95, 101, 108, 90, 0, 84, 89, 86,\n                                  76, 71, 72, 65, 78, 65, 1, 67, 68, 0, 68, 77,\n                                  64, 68, 76, 6, 3, 65, 4, 14, 2, 70, 75, 79,\n                                  74, 65, 65, 4, 6, 69, 65, 71, 8, 7, 73, 77,\n                                  76, 76, 12, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 40, 62, 62, 62, 62,\n                                  62, 52, 38, 50, 48, 35, 18, 12, 4, 79, 62, 62,\n                                  62, 50, 36, 38, 29, 29, 36, 32, 24, 10, 22, 6,\n                                  69, 26, 30, 26, 31, 37, 24, 23, 14, 13, 66, 6,\n                                  65, 79, 117, 3, 64, 70, 23, 6, 67, 76, 71, 68,\n                                  68, 68, 66, 5, 68, 68, 66, 2, 13, 10, 15, 0,\n                                  62, 62, 56, 52, 44, 40, 27, 14, 71, 67, 29,\n                                  22, 19, 11, 9, 3, 0, 65, 75, 76, 71, 68, 68,\n                                  68, 66, 5, 68, 68, 66, 2, 13, 10, 15, 0, 62,\n                                  62, 56, 52, 44, 40, 27, 14, 71 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 114, 93, 13, 10, 9, 35, 53,\n                                  57, 17, 3, 87, 36, 83, 91, 4, 4, 65, 0, 15,\n                                  45, 51, 40, 5, 102, 113, 107, 73, 83, 91, 4,\n                                  90, 81, 22, 7, 84, 96, 106, 65, 66, 85, 98, 0,\n                                  82, 100, 65, 77, 88, 100, 7, 77, 74, 91, 17,\n                                  3, 22, 0, 0, 0, 79, 87, 97, 68, 17, 0, 26, 84,\n                                  118, 111, 83, 88, 73, 75, 83, 83, 113, 69, 95,\n                                  84, 110, 84, 78, 84, 80, 11, 1, 76, 110, 76,\n                                  99, 86, 113, 65, 78, 72, 90, 10, 69, 67, 92,\n                                  84, 82, 79, 70, 65, 68, 82, 65, 5, 68, 5, 69,\n                                  70, 5, 73, 21, 68, 1, 16, 18, 24, 24, 13, 79,\n                                  74, 78, 8, 67, 87, 67, 65, 72, 76, 73, 9, 38,\n                                  10, 81, 78, 70, 70, 31, 37, 96, 66, 65, 80, 2,\n                                  0, 66, 72, 33, 56, 42, 64, 73, 113, 19, 62,\n                                  62, 117, 23, 21, 26, 30, 29, 24, 18, 22, 27,\n                                  15, 22, 15, 7, 5, 1, 16, 15, 15, 12, 6, 10,\n                                  21, 11, 66, 11, 13, 69, 22, 66, 62, 62, 54,\n                                  43, 52, 62, 62, 62, 38, 25, 19, 20, 34, 30,\n                                  82, 21, 24, 8, 39, 21, 21, 26, 32, 30, 38, 36,\n                                  11, 93, 1, 0, 14, 116, 104, 72, 5, 10, 4, 78,\n                                  83, 88, 87, 114, 90, 13, 2, 66, 72, 75, 81,\n                                  93, 91, 110, 77, 19, 6, 1, 66, 68, 74, 79, 86,\n                                  100, 77, 4, 68, 6, 5, 72, 79, 79, 93, 75, 28,\n                                  7, 8, 5, 66, 71, 80, 79, 82, 62, 117, 116,\n                                  109, 115, 105, 106, 107, 105, 102, 105, 106,\n                                  107, 89, 95, 94, 100, 105, 89, 64, 83, 88, 85,\n                                  76, 71, 72, 65, 77, 66, 0, 67, 68, 1, 68, 77,\n                                  64, 68, 75, 5, 2, 65, 3, 13, 1, 70, 75, 78,\n                                  75, 66, 64, 4, 5, 69, 65, 71, 7, 6, 73, 77,\n                                  76, 76, 11, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 38, 62, 62, 62, 62,\n                                  62, 50, 36, 48, 45, 33, 17, 11, 3, 79, 62, 61,\n                                  62, 48, 34, 36, 28, 27, 34, 30, 22, 8, 20, 5,\n                                  71, 25, 29, 24, 30, 36, 23, 21, 13, 12, 67, 5,\n                                  66, 79, 116, 1, 65, 71, 21, 5, 68, 76, 70, 68,\n                                  67, 67, 65, 5, 67, 67, 65, 3, 14, 11, 15, 0,\n                                  62, 60, 54, 50, 42, 38, 24, 12, 72, 67, 30,\n                                  23, 19, 12, 10, 4, 0, 65, 74, 76, 70, 68, 67,\n                                  67, 65, 5, 67, 67, 65, 3, 14, 11, 15, 0, 62,\n                                  60, 54, 50, 42, 38, 24, 12, 72 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 113, 92, 13, 10, 9, 33, 51,\n                                  56, 17, 3, 85, 34, 83, 90, 4, 3, 64, 64, 13,\n                                  43, 49, 36, 3, 103, 111, 106, 73, 83, 90, 4,\n                                  90, 81, 22, 6, 83, 95, 105, 66, 68, 86, 99, 0,\n                                  82, 99, 65, 78, 88, 100, 7, 77, 74, 91, 17, 3,\n                                  22, 0, 0, 0, 78, 88, 97, 68, 16, 0, 26, 83,\n                                  117, 109, 82, 88, 71, 73, 83, 82, 111, 69, 94,\n                                  83, 108, 85, 78, 85, 80, 11, 0, 76, 108, 76,\n                                  98, 85, 112, 65, 78, 72, 90, 10, 69, 67, 91,\n                                  84, 82, 79, 70, 65, 68, 81, 64, 5, 68, 4, 69,\n                                  70, 4, 73, 21, 68, 1, 16, 18, 24, 24, 13, 80,\n                                  73, 77, 7, 67, 87, 67, 64, 72, 76, 72, 10, 39,\n                                  12, 79, 79, 71, 70, 31, 37, 97, 66, 65, 81, 2,\n                                  0, 66, 71, 33, 56, 42, 0, 74, 112, 18, 59, 62,\n                                  116, 22, 21, 26, 29, 28, 23, 18, 22, 26, 14,\n                                  21, 14, 7, 4, 0, 15, 14, 14, 12, 5, 9, 20, 10,\n                                  67, 10, 12, 69, 20, 67, 62, 62, 52, 41, 50,\n                                  60, 62, 62, 37, 23, 16, 18, 31, 28, 84, 19,\n                                  23, 6, 38, 20, 20, 25, 30, 28, 36, 34, 9, 93,\n                                  0, 64, 12, 115, 103, 71, 6, 10, 4, 78, 82, 87,\n                                  86, 112, 89, 13, 2, 65, 72, 74, 80, 92, 90,\n                                  108, 77, 19, 6, 1, 66, 68, 74, 78, 86, 99, 77,\n                                  5, 67, 6, 5, 71, 78, 79, 92, 74, 28, 8, 8, 5,\n                                  65, 71, 79, 78, 82, 62, 116, 114, 107, 113,\n                                  104, 105, 105, 104, 101, 104, 104, 105, 89,\n                                  94, 94, 99, 102, 89, 65, 83, 87, 85, 76, 71,\n                                  72, 66, 77, 66, 64, 67, 68, 1, 68, 77, 65, 68,\n                                  75, 5, 2, 66, 2, 12, 1, 71, 75, 77, 76, 66,\n                                  64, 3, 5, 69, 66, 71, 7, 6, 73, 76, 76, 76, 9,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 61, 36, 62, 62, 62, 62, 61, 48, 34,\n                                  45, 43, 31, 15, 9, 2, 79, 61, 59, 62, 46, 31,\n                                  34, 26, 24, 32, 28, 20, 6, 17, 3, 72, 23, 28,\n                                  21, 28, 34, 21, 19, 11, 10, 68, 4, 67, 79,\n                                  115, 0, 67, 73, 20, 4, 69, 76, 70, 67, 67, 66,\n                                  65, 6, 67, 66, 65, 4, 14, 11, 16, 1, 61, 58,\n                                  52, 48, 40, 36, 22, 10, 74, 66, 30, 23, 20,\n                                  12, 10, 4, 1, 65, 74, 76, 70, 67, 67, 66, 65,\n                                  6, 67, 66, 65, 4, 14, 11, 16, 1, 61, 58, 52,\n                                  48, 40, 36, 22, 10, 74 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 111, 91, 14, 10, 9, 31, 49,\n                                  56, 18, 3, 83, 33, 82, 88, 4, 3, 0, 64, 12,\n                                  42, 47, 33, 1, 103, 109, 104, 72, 82, 88, 4,\n                                  89, 80, 23, 6, 82, 94, 104, 67, 69, 86, 99, 0,\n                                  82, 98, 65, 78, 88, 100, 7, 76, 73, 90, 17, 3,\n                                  22, 0, 0, 0, 77, 88, 97, 68, 15, 0, 26, 82,\n                                  115, 106, 81, 87, 69, 71, 82, 81, 109, 68, 92,\n                                  82, 106, 86, 78, 85, 80, 12, 0, 75, 106, 76,\n                                  97, 84, 110, 65, 77, 72, 89, 11, 69, 66, 90,\n                                  83, 81, 79, 70, 64, 67, 80, 0, 5, 68, 4, 68,\n                                  69, 4, 73, 22, 68, 1, 16, 19, 25, 24, 14, 80,\n                                  72, 76, 6, 67, 87, 67, 0, 72, 75, 71, 11, 40,\n                                  14, 77, 80, 72, 69, 31, 38, 98, 66, 65, 81, 3,\n                                  0, 66, 69, 33, 56, 42, 1, 75, 111, 17, 57, 62,\n                                  114, 22, 21, 26, 28, 28, 23, 18, 22, 26, 13,\n                                  20, 14, 7, 4, 0, 15, 13, 14, 12, 5, 9, 19, 9,\n                                  68, 10, 12, 69, 19, 67, 62, 62, 51, 40, 48,\n                                  58, 62, 62, 36, 21, 14, 17, 29, 27, 85, 18,\n                                  22, 4, 37, 19, 19, 24, 28, 27, 34, 32, 8, 93,\n                                  0, 65, 11, 113, 101, 69, 7, 10, 4, 77, 81, 86,\n                                  85, 110, 88, 14, 3, 64, 71, 73, 79, 91, 89,\n                                  106, 76, 20, 7, 2, 66, 67, 73, 77, 85, 97, 76,\n                                  7, 66, 7, 5, 70, 77, 78, 91, 73, 29, 9, 9, 6,\n                                  64, 70, 78, 77, 81, 62, 114, 112, 105, 111,\n                                  103, 104, 103, 102, 99, 102, 102, 103, 88, 93,\n                                  93, 98, 98, 89, 66, 83, 86, 84, 75, 71, 72,\n                                  66, 77, 66, 65, 67, 68, 2, 68, 77, 65, 68, 75,\n                                  5, 2, 66, 2, 11, 1, 71, 74, 75, 76, 66, 0, 2,\n                                  5, 69, 66, 70, 7, 6, 72, 75, 75, 75, 7, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 58, 34, 62, 62, 62, 62, 58, 46, 33, 43,\n                                  41, 30, 14, 8, 1, 79, 59, 57, 60, 44, 29, 32,\n                                  25, 22, 30, 26, 18, 4, 15, 1, 73, 22, 27, 19,\n                                  27, 32, 20, 17, 10, 9, 69, 3, 67, 79, 114, 64,\n                                  68, 75, 19, 3, 70, 76, 69, 66, 66, 64, 64, 7,\n                                  67, 65, 64, 5, 15, 12, 17, 2, 60, 57, 50, 46,\n                                  38, 34, 20, 8, 75, 65, 30, 24, 21, 13, 11, 5,\n                                  2, 64, 73, 76, 69, 66, 66, 64, 64, 7, 67, 65,\n                                  64, 5, 15, 12, 17, 2, 60, 57, 50, 46, 38, 34,\n                                  20, 8, 75 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 109, 89, 14, 10, 8, 29, 48,\n                                  55, 19, 3, 82, 31, 82, 87, 3, 3, 1, 65, 11,\n                                  41, 45, 30, 65, 104, 107, 103, 72, 82, 87, 3,\n                                  89, 79, 23, 6, 82, 93, 102, 68, 70, 86, 99, 0,\n                                  81, 97, 66, 78, 88, 100, 7, 76, 73, 89, 18, 3,\n                                  22, 0, 0, 0, 77, 88, 97, 67, 14, 0, 25, 82,\n                                  114, 104, 80, 86, 68, 70, 81, 80, 107, 67, 91,\n                                  81, 103, 86, 79, 85, 81, 12, 0, 74, 103, 75,\n                                  97, 84, 108, 65, 77, 72, 89, 11, 69, 66, 89,\n                                  83, 80, 78, 70, 64, 67, 79, 0, 5, 69, 4, 68,\n                                  69, 4, 73, 22, 68, 1, 17, 19, 25, 24, 14, 81,\n                                  72, 76, 6, 67, 86, 67, 1, 71, 75, 69, 13, 41,\n                                  15, 75, 80, 73, 69, 32, 38, 99, 66, 64, 82, 4,\n                                  0, 66, 68, 33, 56, 42, 3, 76, 109, 16, 54, 62,\n                                  113, 22, 21, 25, 28, 27, 23, 17, 22, 25, 12,\n                                  19, 14, 7, 4, 0, 14, 13, 13, 11, 5, 9, 18, 9,\n                                  69, 9, 11, 69, 18, 68, 60, 62, 49, 38, 47, 56,\n                                  62, 62, 35, 19, 12, 15, 27, 25, 86, 17, 21, 3,\n                                  36, 18, 18, 22, 27, 25, 32, 31, 6, 93, 64, 66,\n                                  9, 112, 100, 68, 7, 10, 4, 76, 80, 85, 85,\n                                  108, 86, 15, 4, 64, 70, 71, 78, 89, 88, 103,\n                                  75, 20, 7, 2, 65, 66, 72, 77, 84, 96, 76, 8,\n                                  65, 7, 5, 69, 77, 78, 90, 72, 29, 10, 9, 6, 0,\n                                  69, 77, 77, 80, 62, 113, 111, 104, 110, 102,\n                                  102, 102, 100, 98, 100, 100, 100, 87, 92, 92,\n                                  97, 95, 88, 67, 82, 85, 83, 75, 71, 72, 66,\n                                  76, 67, 66, 67, 68, 3, 68, 77, 65, 68, 74, 4,\n                                  1, 66, 1, 10, 0, 71, 74, 74, 77, 67, 1, 2, 4,\n                                  69, 66, 70, 6, 5, 72, 75, 75, 75, 6, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  56, 32, 62, 62, 62, 62, 55, 44, 31, 41, 38,\n                                  28, 13, 7, 0, 79, 57, 54, 57, 42, 27, 30, 23,\n                                  20, 28, 24, 16, 2, 13, 0, 75, 21, 26, 17, 25,\n                                  31, 18, 15, 9, 8, 70, 2, 68, 79, 113, 66, 69,\n                                  76, 17, 2, 71, 76, 69, 66, 65, 0, 0, 7, 66,\n                                  64, 0, 6, 15, 13, 17, 2, 60, 55, 48, 44, 36,\n                                  32, 17, 6, 76, 65, 31, 24, 21, 14, 12, 5, 2,\n                                  64, 72, 76, 69, 66, 65, 0, 0, 7, 66, 64, 0, 6,\n                                  15, 13, 17, 2, 60, 55, 48, 44, 36, 32, 17, 6,\n                                  76 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 107, 88, 15, 10, 8, 28, 46,\n                                  54, 19, 4, 80, 30, 82, 85, 3, 2, 2, 66, 10,\n                                  40, 44, 26, 67, 105, 105, 101, 72, 82, 85, 3,\n                                  88, 78, 24, 6, 81, 92, 101, 70, 71, 86, 100,\n                                  0, 81, 97, 66, 79, 87, 100, 6, 76, 73, 88, 18,\n                                  3, 22, 0, 0, 0, 76, 88, 97, 67, 14, 64, 25,\n                                  81, 113, 102, 79, 85, 66, 68, 80, 79, 105, 66,\n                                  90, 81, 101, 87, 79, 85, 81, 13, 0, 73, 101,\n                                  75, 96, 83, 106, 65, 77, 72, 89, 12, 70, 65,\n                                  89, 83, 79, 78, 69, 64, 66, 78, 1, 5, 69, 4,\n                                  68, 69, 4, 73, 22, 68, 1, 17, 19, 26, 25, 15,\n                                  81, 71, 75, 5, 67, 86, 67, 2, 71, 74, 68, 14,\n                                  41, 17, 74, 81, 74, 68, 32, 38, 99, 67, 64,\n                                  82, 4, 64, 65, 67, 33, 56, 43, 4, 77, 108, 15,\n                                  51, 62, 111, 22, 21, 25, 27, 27, 22, 17, 21,\n                                  25, 12, 19, 14, 6, 4, 64, 14, 12, 12, 11, 5,\n                                  9, 18, 8, 71, 9, 10, 69, 17, 68, 57, 62, 47,\n                                  37, 45, 54, 62, 61, 33, 17, 10, 14, 25, 23,\n                                  88, 16, 19, 1, 34, 17, 17, 21, 25, 23, 30, 29,\n                                  5, 93, 65, 67, 8, 110, 98, 66, 8, 10, 4, 75,\n                                  80, 85, 84, 107, 85, 16, 5, 0, 70, 70, 77, 88,\n                                  87, 101, 75, 21, 8, 3, 65, 65, 72, 76, 83, 95,\n                                  76, 10, 64, 7, 5, 69, 76, 78, 90, 72, 30, 10,\n                                  10, 6, 1, 69, 77, 76, 80, 62, 111, 109, 102,\n                                  108, 100, 101, 100, 99, 96, 98, 98, 98, 87,\n                                  91, 92, 97, 92, 88, 68, 82, 85, 82, 75, 71,\n                                  72, 66, 76, 67, 67, 67, 68, 3, 68, 77, 65, 68,\n                                  74, 4, 1, 66, 0, 9, 0, 71, 74, 73, 78, 67, 2,\n                                  1, 4, 69, 66, 69, 6, 5, 71, 74, 75, 75, 4, 62,\n                                  61, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 53, 30, 62, 62, 62, 62, 53, 41, 29, 39,\n                                  36, 26, 12, 6, 64, 79, 55, 52, 55, 40, 25, 29,\n                                  22, 18, 26, 21, 14, 0, 11, 65, 76, 20, 24, 15,\n                                  24, 29, 17, 13, 7, 6, 71, 1, 69, 80, 112, 67,\n                                  71, 78, 16, 0, 72, 75, 68, 65, 65, 1, 1, 8,\n                                  66, 0, 1, 7, 16, 14, 18, 3, 59, 53, 46, 42,\n                                  34, 30, 15, 4, 77, 64, 31, 25, 22, 14, 13, 6,\n                                  3, 0, 72, 75, 68, 65, 65, 1, 1, 8, 66, 0, 1,\n                                  7, 16, 14, 18, 3, 59, 53, 46, 42, 34, 30, 15,\n                                  4, 77 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 106, 86, 15, 10, 7, 26, 45,\n                                  53, 20, 4, 78, 28, 82, 84, 3, 2, 3, 67, 8, 38,\n                                  42, 23, 69, 106, 103, 100, 72, 82, 84, 3, 88,\n                                  77, 24, 5, 80, 91, 100, 71, 73, 87, 100, 0,\n                                  81, 96, 66, 79, 87, 100, 6, 76, 73, 88, 19, 3,\n                                  22, 0, 0, 0, 76, 89, 97, 66, 13, 64, 24, 81,\n                                  112, 100, 78, 84, 65, 67, 80, 78, 103, 65, 89,\n                                  80, 99, 88, 79, 85, 81, 13, 64, 72, 99, 75,\n                                  95, 82, 104, 65, 77, 72, 89, 12, 70, 65, 88,\n                                  83, 79, 78, 69, 64, 66, 77, 1, 5, 69, 3, 68,\n                                  69, 4, 73, 22, 68, 1, 18, 19, 26, 25, 15, 82,\n                                  71, 74, 5, 67, 86, 67, 3, 71, 74, 67, 15, 42,\n                                  18, 72, 81, 75, 68, 32, 38, 100, 67, 0, 83, 5,\n                                  64, 65, 66, 33, 56, 43, 5, 78, 106, 14, 48,\n                                  60, 110, 21, 21, 24, 26, 26, 22, 16, 21, 24,\n                                  11, 18, 13, 6, 4, 64, 13, 11, 11, 10, 4, 8,\n                                  17, 8, 72, 8, 9, 69, 15, 69, 55, 62, 45, 35,\n                                  43, 52, 62, 58, 32, 15, 7, 12, 23, 21, 89, 14,\n                                  18, 64, 33, 16, 16, 20, 24, 21, 28, 27, 3, 93,\n                                  66, 68, 6, 109, 97, 65, 8, 10, 4, 74, 79, 84,\n                                  83, 105, 84, 17, 5, 1, 69, 69, 76, 86, 86, 99,\n                                  74, 21, 8, 3, 64, 64, 71, 76, 83, 94, 76, 11,\n                                  0, 7, 5, 68, 76, 78, 89, 71, 30, 11, 10, 6, 2,\n                                  68, 76, 76, 79, 62, 110, 108, 101, 106, 99,\n                                  99, 99, 97, 95, 97, 96, 96, 86, 90, 91, 96,\n                                  89, 88, 69, 82, 84, 82, 75, 71, 72, 67, 75,\n                                  67, 68, 67, 68, 4, 68, 77, 65, 68, 74, 3, 1,\n                                  66, 64, 8, 0, 71, 74, 72, 79, 67, 2, 0, 4, 69,\n                                  66, 69, 6, 4, 71, 73, 75, 75, 3, 62, 60, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 50,\n                                  28, 62, 62, 62, 62, 50, 39, 27, 37, 33, 24,\n                                  10, 5, 65, 79, 52, 50, 53, 38, 23, 27, 20, 16,\n                                  24, 19, 12, 65, 8, 67, 77, 19, 23, 12, 22, 27,\n                                  15, 11, 6, 5, 72, 0, 70, 80, 111, 68, 72, 79,\n                                  15, 64, 73, 75, 68, 65, 64, 2, 1, 9, 66, 1, 2,\n                                  8, 16, 15, 18, 4, 59, 51, 44, 40, 32, 28, 13,\n                                  2, 79, 64, 32, 25, 23, 15, 13, 6, 3, 0, 71,\n                                  75, 68, 65, 64, 2, 1, 9, 66, 1, 2, 8, 16, 15,\n                                  18, 4, 59, 51, 44, 40, 32, 28, 13, 2, 79 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 104, 85, 15, 10, 7, 24, 43,\n                                  52, 21, 4, 77, 26, 81, 82, 2, 2, 4, 68, 7, 37,\n                                  40, 20, 72, 106, 101, 99, 72, 81, 82, 2, 88,\n                                  76, 24, 5, 80, 90, 98, 72, 74, 87, 100, 0, 80,\n                                  95, 67, 79, 87, 100, 6, 75, 73, 87, 19, 3, 22,\n                                  0, 0, 0, 75, 89, 97, 66, 12, 64, 24, 80, 110,\n                                  97, 77, 83, 0, 65, 79, 77, 101, 64, 88, 79,\n                                  96, 88, 80, 85, 82, 13, 64, 71, 96, 74, 95,\n                                  82, 102, 65, 77, 72, 88, 12, 70, 64, 87, 82,\n                                  78, 77, 69, 0, 65, 76, 2, 5, 70, 3, 67, 69, 4,\n                                  73, 23, 68, 1, 18, 20, 26, 25, 15, 82, 70, 74,\n                                  4, 67, 85, 67, 4, 70, 73, 65, 17, 43, 20, 70,\n                                  82, 76, 67, 33, 38, 101, 67, 0, 83, 6, 64, 65,\n                                  64, 33, 56, 43, 7, 79, 105, 13, 46, 57, 109,\n                                  21, 21, 24, 26, 26, 22, 16, 21, 24, 10, 17,\n                                  13, 6, 4, 64, 13, 11, 10, 10, 4, 8, 16, 7, 73,\n                                  7, 9, 69, 14, 69, 53, 62, 44, 34, 42, 50, 62,\n                                  56, 31, 13, 5, 11, 21, 19, 90, 13, 17, 65, 32,\n                                  15, 15, 18, 22, 19, 26, 26, 2, 93, 67, 69, 4,\n                                  107, 95, 64, 9, 10, 4, 73, 78, 83, 83, 103,\n                                  82, 18, 6, 1, 68, 67, 75, 85, 85, 96, 73, 22,\n                                  9, 4, 64, 0, 70, 75, 82, 93, 75, 12, 1, 7, 5,\n                                  67, 75, 77, 88, 70, 30, 12, 10, 6, 3, 67, 75,\n                                  75, 78, 62, 109, 106, 99, 105, 98, 98, 97, 95,\n                                  93, 95, 94, 93, 85, 89, 90, 95, 86, 87, 70,\n                                  81, 83, 81, 75, 71, 72, 67, 75, 68, 69, 67,\n                                  68, 5, 68, 77, 65, 68, 73, 3, 0, 66, 65, 7,\n                                  64, 71, 74, 71, 79, 68, 3, 0, 3, 69, 66, 69,\n                                  5, 4, 71, 73, 75, 75, 1, 62, 59, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 60, 48, 26, 62,\n                                  62, 62, 62, 47, 37, 26, 35, 31, 22, 9, 4, 66,\n                                  79, 50, 47, 50, 36, 21, 25, 19, 14, 22, 17,\n                                  10, 67, 6, 68, 79, 18, 22, 10, 21, 26, 14, 9,\n                                  5, 4, 73, 64, 71, 80, 110, 70, 73, 81, 13, 65,\n                                  74, 75, 67, 64, 0, 3, 2, 9, 65, 2, 3, 9, 17,\n                                  16, 19, 4, 58, 49, 42, 38, 30, 26, 10, 0, 80,\n                                  0, 32, 26, 23, 16, 14, 7, 4, 0, 70, 75, 67,\n                                  64, 0, 3, 2, 9, 65, 2, 3, 9, 17, 16, 19, 4,\n                                  58, 49, 42, 38, 30, 26, 10, 0, 80 },\n\n                                {\n\n                                61,\n                                  8, 76, 61, 8, 76, 102, 83, 16, 10, 6, 22, 42,\n                                  51, 21, 4, 75, 25, 81, 81, 2, 1, 5, 69, 6, 36,\n                                  38, 16, 74, 107, 99, 97, 72, 81, 81, 2, 87,\n                                  75, 25, 5, 79, 89, 97, 73, 75, 87, 101, 0, 80,\n                                  94, 67, 80, 87, 100, 6, 75, 73, 86, 20, 3, 22,\n                                  0, 0, 0, 75, 89, 97, 65, 11, 64, 23, 80, 109,\n                                  95, 76, 82, 1, 64, 78, 76, 99, 0, 87, 78, 94,\n                                  89, 80, 85, 82, 14, 64, 70, 94, 74, 94, 81,\n                                  100, 65, 77, 72, 88, 13, 70, 64, 86, 82, 77,\n                                  77, 69, 0, 65, 75, 2, 5, 70, 3, 67, 69, 4, 73,\n                                  23, 68, 1, 19, 20, 27, 25, 16, 83, 70, 73, 4,\n                                  67, 85, 67, 5, 70, 73, 64, 18, 44, 21, 68, 82,\n                                  77, 67, 33, 38, 102, 67, 1, 84, 6, 64, 65, 0,\n                                  33, 56, 43, 8, 80, 103, 12, 43, 54, 107, 21,\n                                  21, 23, 25, 25, 21, 15, 21, 23, 9, 16, 13, 6,\n                                  4, 65, 12, 10, 9, 9, 4, 8, 15, 7, 74, 7, 8,\n                                  69, 13, 70, 51, 60, 42, 32, 40, 48, 62, 53,\n                                  30, 11, 3, 9, 19, 17, 92, 12, 16, 67, 31, 14,\n                                  14, 17, 21, 17, 24, 24, 0, 93, 68, 70, 3, 106,\n                                  94, 1, 9, 10, 4, 72, 77, 82, 82, 101, 81, 19,\n                                  7, 2, 68, 66, 74, 83, 84, 94, 73, 22, 9, 4, 0,\n                                  1, 70, 75, 81, 92, 75, 14, 2, 7, 5, 66, 75,\n                                  77, 87, 69, 31, 13, 11, 6, 4, 67, 74, 75, 78,\n                                  62, 107, 105, 98, 103, 97, 96, 96, 94, 92, 93,\n                                  92, 91, 85, 88, 90, 94, 83, 87, 71, 81, 82,\n                                  80, 75, 71, 72, 67, 74, 68, 70, 67, 68, 5, 68,\n                                  77, 65, 68, 73, 2, 0, 66, 66, 6, 64, 71, 74,\n                                  70, 80, 68, 4, 64, 3, 69, 66, 68, 5, 3, 70,\n                                  72, 75, 75, 0, 62, 58, 61, 61, 61, 62, 62, 62,\n                                  61, 62, 62, 62, 57, 45, 24, 62, 60, 59, 60,\n                                  44, 35, 24, 33, 28, 20, 8, 3, 67, 79, 48, 45,\n                                  48, 34, 19, 23, 17, 12, 20, 15, 8, 69, 4, 70,\n                                  80, 17, 21, 8, 19, 24, 12, 7, 3, 2, 74, 65,\n                                  72, 80, 109, 71, 75, 82, 12, 66, 75, 75, 67,\n                                  64, 0, 4, 3, 10, 65, 3, 4, 10, 17, 17, 19, 5,\n                                  58, 47, 40, 36, 28, 24, 8, 65, 81, 0, 33, 26,\n                                  24, 16, 15, 7, 4, 1, 70, 75, 67, 64, 0, 4, 3,\n                                  10, 65, 3, 4, 10, 17, 17, 19, 5, 58, 47, 40,\n                                  36, 28, 24, 8, 65, 81 },\n\n                                {\n\n                                60,\n                                  8, 76, 60, 8, 76, 100, 82, 16, 10, 6, 20, 40,\n                                  50, 22, 4, 73, 23, 81, 79, 2, 1, 6, 70, 5, 35,\n                                  36, 13, 76, 108, 97, 96, 72, 81, 79, 2, 87,\n                                  74, 25, 5, 78, 88, 96, 74, 76, 87, 101, 0, 80,\n                                  93, 67, 80, 87, 100, 6, 75, 73, 85, 20, 3, 22,\n                                  0, 0, 0, 74, 89, 97, 65, 10, 64, 23, 79, 108,\n                                  93, 75, 81, 3, 1, 77, 75, 97, 1, 86, 77, 92,\n                                  90, 80, 85, 82, 14, 64, 69, 92, 74, 93, 80,\n                                  98, 65, 77, 72, 88, 13, 70, 0, 85, 82, 76, 77,\n                                  69, 0, 64, 74, 3, 5, 70, 3, 67, 69, 4, 73, 23,\n                                  68, 1, 19, 20, 27, 25, 16, 83, 69, 72, 3, 67,\n                                  85, 67, 6, 70, 72, 0, 19, 45, 23, 66, 83, 78,\n                                  66, 33, 38, 103, 67, 1, 84, 7, 64, 65, 1, 33,\n                                  56, 43, 9, 81, 102, 11, 40, 51, 106, 21, 21,\n                                  23, 24, 25, 21, 15, 21, 23, 8, 15, 13, 6, 4,\n                                  65, 12, 9, 8, 9, 4, 8, 14, 6, 75, 6, 7, 69,\n                                  12, 70, 49, 58, 40, 31, 38, 46, 59, 51, 29, 9,\n                                  1, 8, 17, 15, 93, 11, 15, 69, 30, 13, 13, 16,\n                                  19, 15, 22, 22, 64, 93, 69, 71, 1, 104, 92, 2,\n                                  10, 10, 4, 71, 76, 81, 81, 99, 80, 20, 8, 3,\n                                  67, 65, 73, 82, 83, 92, 72, 23, 10, 5, 0, 2,\n                                  69, 74, 80, 91, 75, 15, 3, 7, 5, 65, 74, 77,\n                                  86, 68, 31, 14, 11, 6, 5, 66, 73, 74, 77, 62,\n                                  106, 103, 96, 101, 96, 95, 94, 92, 90, 91, 90,\n                                  89, 84, 87, 89, 93, 80, 87, 72, 81, 81, 79,\n                                  75, 71, 72, 67, 74, 68, 71, 67, 68, 6, 68, 77,\n                                  65, 68, 73, 2, 0, 66, 67, 5, 64, 71, 74, 69,\n                                  81, 68, 5, 65, 3, 69, 66, 68, 5, 3, 70, 71,\n                                  75, 75, 65, 61, 57, 60, 59, 59, 62, 62, 62,\n                                  59, 60, 62, 61, 54, 42, 22, 61, 57, 55, 55,\n                                  41, 33, 22, 31, 26, 18, 7, 2, 68, 79, 46, 43,\n                                  46, 32, 17, 21, 16, 10, 18, 13, 6, 71, 2, 72,\n                                  81, 16, 20, 6, 18, 22, 11, 5, 2, 1, 75, 66,\n                                  73, 80, 108, 72, 76, 84, 11, 67, 76, 75, 66,\n                                  0, 1, 5, 4, 11, 65, 4, 5, 11, 18, 18, 20, 6,\n                                  57, 45, 38, 34, 26, 22, 6, 67, 82, 1, 33, 27,\n                                  25, 17, 16, 8, 5, 1, 69, 75, 66, 0, 1, 5, 4,\n                                  11, 65, 4, 5, 11, 18, 18, 20, 6, 57, 45, 38,\n                                  34, 26, 22, 6, 67, 82 },\n\n                                {\n\n                                58,\n                                  7, 77, 58, 7, 77, 99, 81, 16, 10, 5, 18, 38,\n                                  49, 22, 4, 72, 21, 81, 78, 1, 0, 7, 71, 3, 33,\n                                  34, 9, 79, 109, 95, 95, 72, 81, 78, 1, 87, 74,\n                                  25, 4, 78, 88, 95, 76, 78, 88, 102, 64, 80,\n                                  93, 68, 81, 87, 100, 5, 75, 73, 85, 20, 2, 22,\n                                  0, 0, 0, 74, 90, 97, 65, 9, 65, 22, 79, 107,\n                                  91, 74, 81, 4, 2, 77, 74, 96, 1, 85, 77, 90,\n                                  91, 81, 86, 83, 14, 65, 69, 90, 74, 93, 80,\n                                  97, 65, 77, 72, 88, 13, 71, 0, 85, 82, 76, 77,\n                                  69, 0, 64, 73, 3, 5, 71, 2, 67, 69, 3, 73, 23,\n                                  68, 1, 19, 20, 27, 25, 16, 84, 69, 72, 2, 67,\n                                  85, 68, 6, 70, 72, 1, 20, 45, 24, 65, 84, 80,\n                                  66, 33, 38, 104, 68, 1, 85, 7, 65, 65, 2, 33,\n                                  55, 43, 10, 82, 101, 9, 37, 47, 105, 20, 21,\n                                  22, 23, 24, 20, 14, 20, 22, 7, 14, 12, 5, 3,\n                                  66, 11, 8, 7, 8, 3, 7, 13, 5, 77, 5, 6, 69,\n                                  10, 71, 46, 55, 38, 29, 36, 43, 55, 48, 27, 7,\n                                  65, 6, 14, 13, 95, 9, 13, 71, 28, 12, 12, 14,\n                                  17, 13, 20, 20, 66, 93, 70, 72, 64, 103, 91,\n                                  3, 10, 10, 4, 71, 76, 81, 81, 98, 79, 20, 8,\n                                  3, 67, 64, 72, 81, 83, 90, 72, 23, 10, 5, 0,\n                                  2, 69, 74, 80, 90, 75, 16, 4, 7, 4, 65, 74,\n                                  77, 86, 68, 31, 14, 11, 6, 6, 66, 73, 74, 77,\n                                  62, 105, 102, 95, 100, 95, 94, 93, 91, 89, 90,\n                                  89, 87, 84, 87, 89, 93, 77, 87, 74, 81, 81,\n                                  79, 75, 71, 72, 68, 74, 69, 72, 68, 68, 6, 69,\n                                  77, 66, 68, 73, 1, 64, 67, 68, 4, 65, 72, 74,\n                                  68, 82, 69, 5, 66, 2, 69, 67, 68, 4, 2, 70,\n                                  71, 75, 75, 67, 59, 56, 58, 57, 56, 62, 62,\n                                  62, 56, 57, 62, 58, 50, 39, 20, 57, 53, 51,\n                                  49, 38, 30, 20, 28, 23, 16, 5, 0, 69, 79, 43,\n                                  40, 43, 30, 14, 19, 14, 7, 16, 10, 4, 74, 64,\n                                  74, 83, 14, 18, 3, 16, 20, 9, 3, 0, 64, 76,\n                                  67, 74, 81, 107, 74, 78, 86, 9, 69, 78, 75,\n                                  66, 0, 1, 6, 4, 11, 65, 5, 5, 12, 18, 18, 20,\n                                  6, 56, 43, 36, 31, 23, 20, 3, 69, 84, 1, 33,\n                                  27, 25, 17, 16, 8, 5, 1, 69, 75, 66, 0, 1, 6,\n                                  4, 11, 65, 5, 5, 12, 18, 18, 20, 6, 56, 43,\n                                  36, 31, 23, 20, 3, 69, 84 },\n\n                                {\n\n                                57,\n                                  7, 77, 57, 7, 77, 97, 79, 17, 11, 5, 17, 37,\n                                  49, 23, 5, 70, 20, 80, 76, 1, 0, 9, 71, 2, 32,\n                                  33, 6, 81, 109, 93, 93, 71, 80, 76, 1, 86, 73,\n                                  26, 4, 77, 87, 93, 77, 79, 88, 102, 64, 79,\n                                  92, 68, 81, 86, 99, 5, 74, 72, 84, 21, 2, 22,\n                                  0, 0, 0, 73, 90, 97, 64, 9, 65, 22, 78, 105,\n                                  88, 72, 80, 6, 4, 76, 72, 94, 2, 83, 76, 87,\n                                  91, 81, 86, 83, 15, 65, 68, 87, 73, 92, 79,\n                                  95, 65, 76, 72, 87, 14, 71, 1, 84, 81, 75, 76,\n                                  68, 1, 0, 72, 4, 6, 71, 2, 66, 68, 3, 72, 24,\n                                  67, 1, 20, 21, 28, 26, 17, 84, 68, 71, 2, 67,\n                                  84, 68, 7, 69, 71, 3, 22, 46, 26, 0, 84, 81,\n                                  65, 34, 39, 104, 68, 2, 85, 8, 65, 64, 4, 33,\n                                  55, 44, 12, 83, 99, 8, 35, 44, 103, 20, 21,\n                                  22, 23, 24, 20, 14, 20, 22, 7, 14, 12, 5, 3,\n                                  66, 11, 8, 7, 8, 3, 7, 13, 5, 78, 5, 6, 69, 9,\n                                  71, 44, 53, 37, 28, 35, 41, 52, 46, 26, 6, 67,\n                                  5, 12, 12, 96, 8, 12, 72, 27, 12, 12, 13, 16,\n                                  12, 19, 19, 67, 93, 70, 72, 65, 101, 89, 5,\n                                  11, 10, 4, 70, 75, 80, 80, 96, 77, 21, 9, 4,\n                                  66, 1, 71, 79, 82, 87, 71, 24, 11, 6, 1, 3,\n                                  68, 73, 79, 88, 74, 18, 5, 8, 4, 64, 73, 76,\n                                  85, 67, 32, 15, 12, 7, 7, 65, 72, 73, 76, 62,\n                                  103, 100, 93, 98, 93, 92, 91, 89, 87, 88, 87,\n                                  84, 83, 86, 88, 92, 73, 86, 75, 80, 80, 78,\n                                  74, 71, 71, 68, 73, 69, 72, 68, 68, 7, 69, 77,\n                                  66, 68, 72, 1, 64, 67, 68, 4, 65, 72, 73, 66,\n                                  82, 69, 6, 66, 2, 69, 67, 67, 4, 2, 69, 70,\n                                  74, 74, 68, 58, 55, 57, 56, 54, 60, 60, 59,\n                                  54, 55, 59, 56, 47, 37, 18, 54, 50, 48, 44,\n                                  36, 28, 19, 26, 21, 15, 4, 64, 69, 79, 41, 38,\n                                  41, 28, 12, 18, 13, 5, 15, 8, 3, 76, 66, 75,\n                                  84, 13, 17, 1, 15, 19, 8, 2, 64, 65, 77, 67,\n                                  74, 81, 106, 75, 79, 87, 8, 70, 79, 74, 65, 1,\n                                  2, 8, 5, 12, 64, 7, 6, 13, 19, 19, 21, 7, 56,\n                                  42, 35, 29, 21, 19, 1, 70, 85, 2, 34, 28, 26,\n                                  18, 17, 9, 6, 2, 68, 74, 65, 1, 2, 8, 5, 12,\n                                  64, 7, 6, 13, 19, 19, 21, 7, 56, 42, 35, 29,\n                                  21, 19, 1, 70, 85 },\n\n                                {\n\n                                56,\n                                  7, 77, 56, 7, 77, 95, 78, 17, 11, 5, 15, 35,\n                                  48, 24, 5, 68, 18, 80, 75, 1, 0, 10, 72, 1,\n                                  31, 31, 3, 83, 110, 91, 92, 71, 80, 75, 1, 86,\n                                  72, 26, 4, 76, 86, 92, 78, 80, 88, 102, 64,\n                                  79, 91, 68, 81, 86, 99, 5, 74, 72, 83, 21, 2,\n                                  22, 0, 0, 0, 72, 90, 97, 64, 8, 65, 22, 77,\n                                  104, 86, 71, 79, 8, 6, 75, 71, 92, 3, 82, 75,\n                                  85, 92, 81, 86, 83, 15, 65, 67, 85, 73, 91,\n                                  78, 93, 65, 76, 72, 87, 14, 71, 1, 83, 81, 74,\n                                  76, 68, 1, 0, 71, 5, 6, 71, 2, 66, 68, 3, 72,\n                                  24, 67, 1, 20, 21, 28, 26, 17, 85, 67, 70, 1,\n                                  67, 84, 68, 8, 69, 71, 4, 23, 47, 28, 2, 85,\n                                  82, 65, 34, 39, 105, 68, 2, 86, 9, 65, 64, 5,\n                                  33, 55, 44, 13, 84, 98, 7, 32, 41, 102, 20,\n                                  21, 22, 22, 23, 20, 14, 20, 21, 6, 13, 12, 5,\n                                  3, 66, 10, 7, 6, 8, 3, 7, 12, 4, 79, 4, 5, 69,\n                                  8, 72, 42, 51, 35, 26, 33, 39, 49, 44, 25, 4,\n                                  69, 3, 10, 10, 97, 7, 11, 74, 26, 11, 11, 12,\n                                  14, 10, 17, 17, 69, 93, 71, 73, 67, 100, 88,\n                                  6, 12, 10, 4, 69, 74, 79, 79, 94, 76, 22, 10,\n                                  5, 65, 2, 70, 78, 81, 85, 70, 24, 11, 6, 1, 4,\n                                  67, 72, 78, 87, 74, 19, 6, 8, 4, 0, 72, 76,\n                                  84, 66, 32, 16, 12, 7, 8, 64, 71, 72, 75, 62,\n                                  102, 98, 91, 96, 92, 91, 89, 87, 86, 86, 85,\n                                  82, 82, 85, 87, 91, 70, 86, 76, 80, 79, 77,\n                                  74, 71, 71, 68, 73, 69, 73, 68, 68, 8, 69, 77,\n                                  66, 68, 72, 1, 64, 67, 69, 3, 65, 72, 73, 65,\n                                  83, 69, 7, 67, 2, 69, 67, 67, 4, 2, 69, 69,\n                                  74, 74, 70, 57, 54, 56, 54, 52, 57, 57, 56,\n                                  52, 52, 56, 53, 44, 34, 16, 50, 46, 44, 39,\n                                  33, 26, 17, 24, 19, 13, 3, 65, 70, 79, 39, 36,\n                                  39, 26, 10, 16, 11, 3, 13, 6, 1, 78, 68, 77,\n                                  85, 12, 16, 64, 13, 17, 6, 0, 65, 66, 78, 68,\n                                  75, 81, 105, 76, 80, 89, 7, 71, 80, 74, 65, 2,\n                                  3, 9, 6, 13, 64, 8, 7, 14, 19, 20, 22, 8, 55,\n                                  40, 33, 27, 19, 17, 64, 72, 86, 3, 34, 28, 27,\n                                  19, 18, 9, 7, 2, 67, 74, 65, 2, 3, 9, 6, 13,\n                                  64, 8, 7, 14, 19, 20, 22, 8, 55, 40, 33, 27,\n                                  19, 17, 64, 72, 86 },\n\n                                {\n\n                                55,\n                                  7, 77, 55, 7, 77, 93, 76, 18, 11, 4, 13, 34,\n                                  47, 24, 5, 66, 17, 80, 73, 1, 64, 11, 73, 0,\n                                  30, 29, 64, 85, 111, 89, 90, 71, 80, 73, 1,\n                                  85, 71, 27, 4, 75, 85, 91, 79, 81, 88, 103,\n                                  64, 79, 90, 68, 82, 86, 99, 5, 74, 72, 82, 22,\n                                  2, 22, 0, 0, 0, 72, 90, 97, 0, 7, 65, 21, 77,\n                                  103, 84, 70, 78, 9, 7, 74, 70, 90, 4, 81, 74,\n                                  83, 93, 81, 86, 83, 16, 65, 66, 83, 73, 90,\n                                  77, 91, 65, 76, 72, 87, 15, 71, 2, 82, 81, 73,\n                                  76, 68, 1, 1, 70, 5, 6, 71, 2, 66, 68, 3, 72,\n                                  24, 67, 1, 21, 21, 29, 26, 18, 85, 67, 69, 1,\n                                  67, 84, 68, 9, 69, 70, 5, 24, 48, 29, 4, 85,\n                                  83, 64, 34, 39, 106, 68, 3, 86, 9, 65, 64, 6,\n                                  33, 55, 44, 14, 85, 96, 6, 29, 38, 100, 20,\n                                  21, 21, 21, 23, 19, 13, 20, 21, 5, 12, 12, 5,\n                                  3, 67, 10, 6, 5, 7, 3, 7, 11, 4, 80, 4, 4, 69,\n                                  7, 72, 40, 49, 33, 25, 31, 37, 46, 41, 24, 2,\n                                  71, 2, 8, 8, 99, 6, 10, 76, 25, 10, 10, 11,\n                                  13, 8, 15, 15, 70, 93, 72, 74, 68, 98, 86, 8,\n                                  12, 10, 4, 68, 73, 78, 78, 92, 75, 23, 11, 6,\n                                  65, 3, 69, 76, 80, 83, 70, 25, 12, 7, 2, 5,\n                                  67, 72, 77, 86, 74, 21, 7, 8, 4, 1, 72, 76,\n                                  83, 65, 33, 17, 13, 7, 9, 64, 70, 72, 75, 62,\n                                  100, 97, 90, 94, 91, 89, 88, 86, 84, 84, 83,\n                                  80, 82, 84, 87, 90, 67, 86, 77, 80, 78, 76,\n                                  74, 71, 71, 68, 72, 69, 74, 68, 68, 8, 69, 77,\n                                  66, 68, 72, 0, 64, 67, 70, 2, 65, 72, 73, 64,\n                                  84, 69, 8, 68, 2, 69, 67, 66, 4, 1, 68, 68,\n                                  74, 74, 71, 56, 53, 55, 52, 50, 55, 55, 53,\n                                  49, 49, 53, 50, 41, 31, 14, 46, 43, 40, 34,\n                                  30, 24, 15, 22, 16, 11, 2, 66, 71, 79, 37, 34,\n                                  37, 24, 8, 14, 10, 1, 11, 4, 64, 80, 70, 79,\n                                  86, 11, 15, 66, 12, 15, 5, 65, 67, 68, 79, 69,\n                                  76, 81, 104, 77, 82, 90, 6, 72, 81, 74, 64, 2,\n                                  3, 10, 7, 14, 64, 9, 8, 15, 20, 21, 22, 9, 55,\n                                  38, 31, 25, 17, 15, 66, 74, 87, 3, 35, 29, 28,\n                                  19, 19, 10, 7, 3, 67, 74, 64, 2, 3, 10, 7, 14,\n                                  64, 9, 8, 15, 20, 21, 22, 9, 55, 38, 31, 25,\n                                  17, 15, 66, 74, 87 },\n\n                                {\n\n                                53,\n                                  7, 77, 53, 7, 77, 92, 75, 18, 11, 4, 11, 32,\n                                  46, 25, 5, 65, 15, 80, 72, 0, 64, 12, 74, 65,\n                                  28, 27, 67, 88, 112, 87, 89, 71, 80, 72, 0,\n                                  85, 70, 27, 3, 75, 84, 89, 80, 83, 89, 103,\n                                  64, 78, 89, 69, 82, 86, 99, 5, 74, 72, 82, 22,\n                                  2, 22, 0, 0, 0, 71, 91, 97, 0, 6, 65, 21, 76,\n                                  102, 82, 69, 77, 11, 9, 74, 69, 88, 5, 80, 73,\n                                  80, 93, 82, 86, 84, 16, 66, 65, 80, 72, 90,\n                                  77, 89, 65, 76, 72, 87, 15, 71, 2, 81, 81, 73,\n                                  75, 68, 1, 1, 69, 6, 6, 72, 1, 66, 68, 3, 72,\n                                  24, 67, 1, 21, 21, 29, 26, 18, 86, 66, 69, 0,\n                                  67, 83, 68, 10, 68, 70, 7, 26, 49, 31, 6, 86,\n                                  84, 64, 35, 39, 107, 68, 3, 87, 10, 65, 64, 7,\n                                  33, 55, 44, 16, 86, 95, 5, 26, 35, 99, 19, 21,\n                                  21, 21, 22, 19, 13, 20, 20, 4, 11, 11, 5, 3,\n                                  67, 9, 6, 4, 7, 2, 6, 10, 3, 81, 3, 3, 69, 5,\n                                  73, 38, 47, 31, 23, 30, 35, 42, 39, 23, 0, 74,\n                                  0, 6, 6, 100, 4, 9, 77, 24, 9, 9, 9, 11, 6,\n                                  13, 14, 72, 93, 73, 75, 70, 97, 85, 9, 13, 10,\n                                  4, 67, 72, 77, 78, 90, 73, 24, 11, 6, 64, 5,\n                                  68, 75, 79, 80, 69, 25, 12, 7, 2, 6, 66, 71,\n                                  77, 85, 74, 22, 8, 8, 4, 2, 71, 76, 82, 64,\n                                  33, 18, 13, 7, 10, 0, 69, 71, 74, 62, 99, 95,\n                                  88, 93, 90, 88, 86, 84, 83, 83, 81, 77, 81,\n                                  83, 86, 89, 64, 85, 78, 79, 77, 76, 74, 71,\n                                  71, 69, 72, 70, 75, 68, 68, 9, 69, 77, 66, 68,\n                                  71, 0, 65, 67, 71, 1, 66, 72, 73, 0, 85, 70,\n                                  8, 68, 1, 69, 67, 66, 3, 1, 68, 68, 74, 74,\n                                  73, 55, 52, 54, 51, 47, 52, 52, 50, 47, 46,\n                                  49, 47, 37, 29, 12, 42, 39, 36, 29, 27, 22,\n                                  13, 20, 14, 9, 0, 67, 72, 79, 34, 31, 34, 22,\n                                  6, 12, 8, 64, 9, 2, 66, 82, 73, 80, 88, 10,\n                                  14, 69, 10, 14, 3, 67, 68, 69, 80, 70, 77, 81,\n                                  103, 79, 83, 92, 4, 73, 82, 74, 64, 3, 4, 11,\n                                  7, 14, 0, 10, 9, 16, 20, 22, 23, 9, 54, 36,\n                                  29, 23, 15, 13, 69, 76, 89, 4, 35, 29, 28, 20,\n                                  19, 10, 8, 3, 66, 74, 64, 3, 4, 11, 7, 14, 0,\n                                  10, 9, 16, 20, 22, 23, 9, 54, 36, 29, 23, 15,\n                                  13, 69, 76, 89 },\n\n                                {\n\n                                52,\n                                  7, 77, 52, 7, 77, 90, 73, 18, 11, 3, 9, 31,\n                                  45, 26, 5, 0, 13, 79, 70, 0, 64, 13, 75, 66,\n                                  27, 25, 70, 90, 112, 85, 88, 71, 79, 70, 0,\n                                  85, 69, 27, 3, 74, 83, 88, 81, 84, 89, 103,\n                                  64, 78, 88, 69, 82, 86, 99, 5, 73, 72, 81, 23,\n                                  2, 22, 0, 0, 0, 71, 91, 97, 1, 5, 65, 20, 76,\n                                  100, 79, 68, 76, 12, 10, 73, 68, 86, 6, 79,\n                                  72, 78, 94, 82, 86, 84, 16, 66, 64, 78, 72,\n                                  89, 76, 87, 65, 76, 72, 86, 15, 71, 3, 80, 80,\n                                  72, 75, 68, 2, 2, 68, 6, 6, 72, 1, 65, 68, 3,\n                                  72, 25, 67, 1, 22, 22, 29, 26, 18, 86, 66, 68,\n                                  0, 67, 83, 68, 11, 68, 69, 8, 27, 50, 32, 8,\n                                  86, 85, 0, 35, 39, 108, 68, 4, 87, 11, 65, 64,\n                                  9, 33, 55, 44, 17, 87, 93, 4, 24, 32, 98, 19,\n                                  21, 20, 20, 22, 19, 12, 20, 20, 3, 10, 11, 5,\n                                  3, 67, 9, 5, 3, 6, 2, 6, 9, 3, 82, 2, 3, 69,\n                                  4, 73, 36, 45, 30, 22, 28, 33, 39, 36, 22, 65,\n                                  76, 64, 4, 4, 101, 3, 8, 79, 23, 8, 8, 8, 10,\n                                  4, 11, 12, 73, 93, 74, 76, 72, 95, 83, 10, 13,\n                                  10, 4, 66, 71, 76, 77, 88, 72, 25, 12, 7, 0,\n                                  6, 67, 73, 78, 78, 68, 26, 13, 8, 3, 7, 65,\n                                  71, 76, 84, 73, 23, 9, 8, 4, 3, 71, 75, 81, 0,\n                                  33, 19, 13, 7, 11, 1, 68, 71, 73, 62, 98, 94,\n                                  87, 91, 89, 86, 85, 82, 81, 81, 79, 75, 80,\n                                  82, 85, 88, 2, 85, 79, 79, 76, 75, 74, 71, 71,\n                                  69, 71, 70, 76, 68, 68, 10, 69, 77, 66, 68,\n                                  71, 64, 65, 67, 72, 0, 66, 72, 73, 1, 85, 70,\n                                  9, 69, 1, 69, 67, 66, 3, 0, 68, 67, 74, 74,\n                                  74, 54, 51, 53, 49, 45, 50, 49, 47, 44, 43,\n                                  46, 44, 34, 26, 10, 38, 36, 32, 24, 24, 20,\n                                  12, 18, 11, 7, 64, 68, 73, 79, 32, 29, 32, 20,\n                                  4, 10, 7, 66, 7, 0, 68, 84, 75, 82, 89, 9, 13,\n                                  71, 9, 12, 2, 69, 69, 70, 81, 71, 78, 81, 102,\n                                  80, 84, 93, 3, 74, 83, 74, 0, 3, 5, 12, 8, 15,\n                                  0, 11, 10, 17, 21, 23, 23, 10, 54, 34, 27, 21,\n                                  13, 11, 71, 78, 90, 4, 36, 30, 29, 21, 20, 11,\n                                  8, 3, 65, 74, 0, 3, 5, 12, 8, 15, 0, 11, 10,\n                                  17, 21, 23, 23, 10, 54, 34, 27, 21, 13, 11,\n                                  71, 78, 90 },\n\n                                {\n\n                                51,\n                                  7, 78, 51, 7, 78, 88, 72, 19, 11, 3, 8, 29,\n                                  44, 26, 6, 2, 12, 79, 69, 0, 65, 14, 76, 67,\n                                  26, 24, 74, 92, 113, 83, 86, 71, 79, 69, 0,\n                                  84, 68, 28, 3, 73, 82, 87, 83, 85, 89, 104,\n                                  64, 78, 88, 69, 83, 85, 99, 4, 73, 72, 80, 23,\n                                  2, 22, 0, 0, 0, 70, 91, 97, 1, 5, 66, 20, 75,\n                                  99, 77, 67, 75, 14, 12, 72, 67, 84, 7, 78, 72,\n                                  76, 95, 82, 86, 84, 17, 66, 0, 76, 72, 88, 75,\n                                  85, 65, 76, 72, 86, 16, 72, 3, 80, 80, 71, 75,\n                                  67, 2, 2, 67, 7, 6, 72, 1, 65, 68, 3, 72, 25,\n                                  67, 1, 22, 22, 30, 27, 19, 87, 65, 67, 64, 67,\n                                  83, 68, 12, 68, 69, 9, 28, 50, 34, 9, 87, 86,\n                                  0, 35, 39, 108, 69, 4, 88, 11, 66, 0, 10, 33,\n                                  55, 45, 18, 88, 92, 3, 21, 29, 96, 19, 21, 20,\n                                  19, 21, 18, 12, 19, 19, 3, 10, 11, 4, 3, 68,\n                                  8, 4, 2, 6, 2, 6, 9, 2, 84, 2, 2, 69, 3, 74,\n                                  33, 43, 28, 20, 26, 31, 36, 34, 20, 67, 78,\n                                  66, 2, 2, 103, 2, 6, 81, 21, 7, 7, 7, 8, 2, 9,\n                                  10, 75, 93, 75, 77, 73, 94, 82, 12, 14, 10, 4,\n                                  65, 71, 76, 76, 87, 71, 26, 13, 8, 0, 7, 66,\n                                  72, 77, 76, 68, 26, 13, 8, 3, 8, 65, 70, 75,\n                                  83, 73, 25, 10, 8, 4, 3, 70, 75, 81, 0, 34,\n                                  19, 14, 7, 12, 1, 68, 70, 73, 62, 96, 92, 85,\n                                  89, 87, 85, 83, 81, 80, 79, 77, 73, 80, 81,\n                                  85, 88, 5, 85, 80, 79, 76, 74, 74, 71, 71, 69,\n                                  71, 70, 77, 68, 68, 10, 69, 77, 66, 68, 71,\n                                  64, 65, 67, 73, 64, 66, 72, 73, 2, 86, 70, 10,\n                                  70, 1, 69, 67, 65, 3, 0, 67, 66, 74, 74, 76,\n                                  53, 50, 52, 47, 43, 47, 47, 44, 42, 40, 43,\n                                  41, 31, 23, 8, 35, 32, 28, 19, 22, 17, 10, 16,\n                                  9, 5, 65, 69, 74, 79, 30, 27, 30, 18, 2, 9, 5,\n                                  68, 5, 66, 70, 86, 77, 84, 90, 8, 11, 73, 7,\n                                  10, 0, 71, 71, 72, 82, 72, 79, 82, 101, 81,\n                                  86, 95, 2, 76, 84, 73, 0, 4, 5, 13, 9, 16, 0,\n                                  12, 11, 18, 21, 24, 24, 11, 53, 32, 25, 19,\n                                  11, 9, 73, 80, 91, 5, 36, 30, 30, 21, 21, 11,\n                                  9, 4, 65, 73, 0, 4, 5, 13, 9, 16, 0, 12, 11,\n                                  18, 21, 24, 24, 11, 53, 32, 25, 19, 11, 9, 73,\n                                  80, 91 },\n\n                                {\n\n                                50,\n                                  7, 78, 50, 7, 78, 86, 70, 19, 11, 2, 6, 28,\n                                  43, 27, 6, 3, 10, 79, 67, 64, 65, 15, 77, 68,\n                                  25, 22, 77, 95, 114, 81, 85, 71, 79, 67, 64,\n                                  84, 67, 28, 3, 73, 81, 85, 84, 86, 89, 104,\n                                  64, 77, 87, 70, 83, 85, 99, 4, 73, 72, 79, 24,\n                                  2, 22, 0, 0, 0, 70, 91, 97, 2, 4, 66, 19, 75,\n                                  98, 75, 66, 74, 15, 13, 71, 66, 82, 8, 77, 71,\n                                  73, 95, 83, 86, 85, 17, 66, 1, 73, 71, 88, 75,\n                                  83, 65, 76, 72, 86, 16, 72, 4, 79, 80, 70, 74,\n                                  67, 2, 3, 66, 7, 6, 73, 1, 65, 68, 3, 72, 25,\n                                  67, 1, 23, 22, 30, 27, 19, 87, 65, 67, 64, 67,\n                                  82, 68, 13, 67, 68, 11, 30, 51, 35, 11, 87,\n                                  87, 1, 36, 39, 109, 69, 5, 88, 12, 66, 0, 11,\n                                  33, 55, 45, 20, 89, 90, 2, 18, 26, 95, 19, 21,\n                                  19, 19, 21, 18, 11, 19, 19, 2, 9, 11, 4, 3,\n                                  68, 8, 4, 1, 5, 2, 6, 8, 2, 85, 1, 1, 69, 2,\n                                  74, 31, 41, 26, 19, 25, 29, 33, 31, 19, 69,\n                                  80, 67, 0, 0, 104, 1, 5, 82, 20, 6, 6, 5, 7,\n                                  0, 7, 9, 76, 93, 76, 78, 75, 92, 80, 13, 14,\n                                  10, 4, 64, 70, 75, 76, 85, 69, 27, 14, 8, 1,\n                                  9, 65, 70, 76, 73, 67, 27, 14, 9, 4, 9, 64,\n                                  70, 74, 82, 73, 26, 11, 8, 4, 4, 70, 75, 80,\n                                  1, 34, 20, 14, 7, 13, 2, 67, 70, 72, 62, 95,\n                                  91, 84, 88, 86, 83, 82, 79, 78, 77, 75, 70,\n                                  79, 80, 84, 87, 8, 84, 81, 78, 75, 73, 74, 71,\n                                  71, 69, 70, 71, 78, 68, 68, 11, 69, 77, 66,\n                                  68, 70, 65, 66, 67, 74, 65, 67, 72, 73, 3, 87,\n                                  71, 11, 70, 0, 69, 67, 65, 2, 64, 67, 66, 74,\n                                  74, 77, 52, 49, 51, 46, 40, 45, 44, 41, 39,\n                                  37, 40, 38, 28, 21, 6, 31, 29, 24, 14, 19, 15,\n                                  8, 14, 6, 3, 66, 70, 75, 79, 28, 24, 27, 16,\n                                  0, 7, 4, 70, 3, 68, 72, 88, 79, 85, 92, 7, 10,\n                                  75, 6, 9, 64, 73, 72, 73, 83, 73, 80, 82, 100,\n                                  83, 87, 96, 0, 77, 85, 73, 1, 4, 6, 14, 10,\n                                  16, 1, 13, 12, 19, 22, 25, 24, 11, 53, 30, 23,\n                                  17, 9, 7, 76, 82, 92, 5, 37, 31, 30, 22, 22,\n                                  12, 9, 4, 64, 73, 1, 4, 6, 14, 10, 16, 1, 13,\n                                  12, 19, 22, 25, 24, 11, 53, 30, 23, 17, 9, 7,\n                                  76, 82, 92 },\n\n                                {\n\n                                48,\n                                  6, 78, 48, 6, 78, 85, 69, 19, 11, 2, 4, 26,\n                                  42, 27, 6, 5, 8, 79, 66, 64, 66, 16, 78, 70,\n                                  23, 20, 81, 97, 115, 79, 84, 71, 79, 66, 64,\n                                  84, 67, 28, 2, 72, 80, 84, 85, 88, 90, 105,\n                                  64, 77, 86, 70, 84, 85, 99, 4, 73, 72, 79, 24,\n                                  2, 22, 0, 0, 0, 69, 92, 97, 2, 3, 66, 19, 74,\n                                  97, 73, 65, 74, 17, 15, 71, 65, 80, 8, 76, 70,\n                                  71, 96, 83, 87, 85, 17, 67, 1, 71, 71, 87, 74,\n                                  82, 65, 76, 72, 86, 16, 72, 4, 78, 80, 70, 74,\n                                  67, 2, 3, 65, 8, 6, 73, 0, 65, 68, 2, 72, 25,\n                                  67, 1, 23, 22, 30, 27, 19, 88, 64, 66, 65, 67,\n                                  82, 68, 14, 67, 68, 12, 31, 52, 37, 13, 88,\n                                  88, 1, 36, 39, 110, 69, 5, 89, 12, 66, 0, 12,\n                                  33, 55, 45, 21, 90, 89, 1, 15, 22, 94, 18, 21,\n                                  19, 18, 20, 17, 11, 19, 18, 1, 8, 10, 4, 2,\n                                  69, 7, 3, 0, 5, 1, 5, 7, 1, 86, 0, 0, 69, 0,\n                                  75, 29, 39, 24, 17, 23, 26, 29, 29, 18, 71,\n                                  83, 69, 66, 65, 106, 64, 4, 84, 19, 5, 5, 4,\n                                  5, 65, 5, 7, 78, 93, 77, 79, 77, 91, 79, 14,\n                                  15, 10, 4, 64, 69, 74, 75, 83, 68, 27, 14, 9,\n                                  1, 10, 64, 69, 75, 71, 67, 27, 14, 9, 4, 9,\n                                  64, 69, 74, 81, 73, 27, 12, 8, 4, 5, 69, 75,\n                                  79, 2, 34, 21, 14, 7, 14, 2, 66, 69, 72, 62,\n                                  94, 89, 82, 86, 85, 82, 80, 78, 77, 76, 73,\n                                  68, 79, 79, 84, 86, 11, 84, 82, 78, 74, 73,\n                                  74, 71, 71, 70, 70, 71, 79, 68, 68, 11, 69,\n                                  77, 67, 68, 70, 65, 66, 68, 75, 66, 67, 73,\n                                  73, 4, 88, 71, 11, 71, 0, 69, 68, 65, 2, 64,\n                                  67, 65, 74, 74, 79, 51, 48, 50, 44, 38, 42,\n                                  41, 38, 37, 34, 36, 35, 24, 18, 4, 27, 25, 20,\n                                  9, 16, 13, 6, 11, 4, 1, 68, 72, 76, 79, 25,\n                                  22, 25, 14, 66, 5, 2, 73, 1, 70, 74, 90, 82,\n                                  87, 93, 5, 9, 78, 4, 7, 66, 75, 74, 75, 84,\n                                  74, 81, 82, 99, 84, 89, 98, 64, 78, 86, 73, 1,\n                                  5, 6, 15, 10, 17, 1, 14, 12, 20, 22, 25, 25,\n                                  12, 52, 28, 21, 15, 7, 5, 78, 84, 94, 6, 37,\n                                  31, 31, 22, 22, 12, 10, 4, 64, 73, 1, 5, 6,\n                                  15, 10, 17, 1, 14, 12, 20, 22, 25, 25, 12, 52,\n                                  28, 21, 15, 7, 5, 78, 84, 94 },\n\n                                {\n\n                                47,\n                                  6, 78, 47, 6, 78, 83, 68, 20, 11, 2, 2, 24,\n                                  42, 28, 6, 7, 7, 78, 64, 64, 66, 17, 78, 71,\n                                  22, 18, 84, 99, 115, 77, 82, 70, 78, 64, 64,\n                                  83, 66, 29, 2, 71, 79, 83, 86, 89, 90, 105,\n                                  64, 77, 85, 70, 84, 85, 99, 4, 72, 71, 78, 24,\n                                  2, 22, 0, 0, 0, 68, 92, 97, 2, 2, 66, 19, 73,\n                                  95, 70, 64, 73, 19, 17, 70, 64, 78, 9, 74, 69,\n                                  69, 97, 83, 87, 85, 18, 67, 2, 69, 71, 86, 73,\n                                  80, 65, 75, 72, 85, 17, 72, 5, 77, 79, 69, 74,\n                                  67, 3, 4, 64, 9, 6, 73, 0, 64, 67, 2, 72, 26,\n                                  67, 1, 23, 23, 31, 27, 20, 88, 0, 65, 66, 67,\n                                  82, 68, 15, 67, 67, 13, 32, 53, 39, 15, 89,\n                                  89, 2, 36, 40, 111, 69, 5, 89, 13, 66, 0, 14,\n                                  33, 55, 45, 22, 91, 88, 0, 13, 19, 92, 18, 21,\n                                  19, 17, 20, 17, 11, 19, 18, 0, 7, 10, 4, 2,\n                                  69, 7, 2, 0, 5, 1, 5, 6, 0, 87, 0, 0, 69, 64,\n                                  75, 27, 37, 23, 16, 21, 24, 26, 27, 17, 73,\n                                  85, 70, 68, 66, 107, 65, 3, 86, 18, 4, 4, 3,\n                                  3, 66, 3, 5, 79, 93, 77, 80, 78, 89, 77, 16,\n                                  16, 10, 4, 0, 68, 73, 74, 81, 67, 28, 15, 10,\n                                  2, 11, 0, 68, 74, 69, 66, 28, 15, 10, 4, 10,\n                                  0, 68, 73, 79, 72, 29, 13, 9, 4, 6, 68, 74,\n                                  78, 3, 35, 22, 15, 8, 15, 3, 65, 68, 71, 62,\n                                  92, 87, 80, 84, 84, 81, 78, 76, 75, 74, 71,\n                                  66, 78, 78, 83, 85, 15, 84, 83, 78, 73, 72,\n                                  73, 71, 71, 70, 70, 71, 80, 68, 68, 12, 69,\n                                  77, 67, 68, 70, 65, 66, 68, 75, 67, 67, 73,\n                                  72, 6, 88, 71, 12, 72, 0, 69, 68, 64, 2, 64,\n                                  66, 64, 73, 73, 81, 50, 47, 49, 42, 36, 39,\n                                  39, 35, 35, 32, 33, 33, 21, 15, 2, 23, 22, 17,\n                                  4, 13, 11, 5, 9, 2, 0, 69, 73, 77, 79, 23, 20,\n                                  23, 12, 68, 3, 1, 75, 64, 72, 76, 92, 84, 89,\n                                  94, 4, 8, 80, 3, 5, 67, 77, 75, 76, 85, 75,\n                                  81, 82, 98, 85, 90, 100, 65, 79, 87, 73, 2, 6,\n                                  7, 17, 11, 18, 1, 15, 13, 21, 23, 26, 26, 13,\n                                  51, 27, 19, 13, 5, 3, 80, 86, 95, 7, 37, 32,\n                                  32, 23, 23, 13, 11, 5, 0, 73, 2, 6, 7, 17, 11,\n                                  18, 1, 15, 13, 21, 23, 26, 26, 13, 51, 27, 19,\n                                  13, 5, 3, 80, 86, 95 },\n\n                                {\n\n                                46,\n                                  6, 78, 46, 6, 78, 81, 66, 20, 11, 1, 0, 23,\n                                  41, 29, 6, 8, 5, 78, 0, 65, 66, 18, 79, 72,\n                                  21, 16, 87, 102, 116, 75, 81, 70, 78, 0, 65,\n                                  83, 65, 29, 2, 71, 78, 81, 87, 90, 90, 105,\n                                  64, 76, 84, 71, 84, 85, 99, 4, 72, 71, 77, 25,\n                                  2, 22, 0, 0, 0, 68, 92, 97, 3, 1, 66, 18, 73,\n                                  94, 68, 0, 72, 20, 18, 69, 0, 76, 10, 73, 68,\n                                  66, 97, 84, 87, 86, 18, 67, 3, 66, 70, 86, 73,\n                                  78, 65, 75, 72, 85, 17, 72, 5, 76, 79, 68, 73,\n                                  67, 3, 4, 0, 9, 6, 74, 0, 64, 67, 2, 72, 26,\n                                  67, 1, 24, 23, 31, 27, 20, 89, 0, 65, 66, 67,\n                                  81, 68, 16, 66, 67, 15, 34, 54, 40, 17, 89,\n                                  90, 2, 37, 40, 112, 69, 6, 90, 14, 66, 0, 15,\n                                  33, 55, 45, 24, 92, 86, 64, 10, 16, 91, 18,\n                                  21, 18, 17, 19, 17, 10, 19, 17, 64, 6, 10, 4,\n                                  2, 69, 6, 2, 64, 4, 1, 5, 5, 0, 88, 64, 64,\n                                  69, 65, 76, 25, 35, 21, 14, 20, 22, 23, 24,\n                                  16, 75, 87, 72, 70, 68, 108, 66, 2, 87, 17, 3,\n                                  3, 1, 2, 68, 1, 4, 81, 93, 78, 81, 80, 88, 76,\n                                  17, 16, 10, 4, 1, 67, 72, 74, 79, 65, 29, 16,\n                                  10, 3, 13, 1, 66, 73, 66, 65, 28, 15, 10, 5,\n                                  11, 1, 68, 72, 78, 72, 30, 14, 9, 4, 7, 68,\n                                  74, 77, 4, 35, 23, 15, 8, 16, 4, 64, 68, 70,\n                                  62, 91, 86, 79, 83, 83, 79, 77, 74, 74, 72,\n                                  69, 0, 77, 77, 82, 84, 18, 83, 84, 77, 72, 71,\n                                  73, 71, 71, 70, 69, 72, 81, 68, 68, 13, 69,\n                                  77, 67, 68, 69, 66, 67, 68, 76, 68, 68, 73,\n                                  72, 7, 89, 72, 13, 72, 64, 69, 68, 64, 1, 65,\n                                  66, 64, 73, 73, 82, 49, 46, 48, 41, 33, 37,\n                                  36, 32, 32, 29, 30, 30, 18, 13, 0, 19, 18, 13,\n                                  64, 10, 9, 3, 7, 64, 65, 70, 74, 78, 79, 21,\n                                  17, 20, 10, 70, 1, 64, 77, 66, 74, 78, 94, 86,\n                                  90, 96, 3, 7, 82, 1, 4, 69, 79, 76, 77, 86,\n                                  76, 82, 82, 97, 87, 91, 101, 67, 80, 88, 73,\n                                  2, 6, 8, 18, 12, 18, 2, 16, 14, 22, 23, 27,\n                                  26, 13, 51, 25, 17, 11, 3, 1, 83, 88, 96, 7,\n                                  38, 32, 32, 24, 24, 13, 11, 5, 1, 73, 2, 6, 8,\n                                  18, 12, 18, 2, 16, 14, 22, 23, 27, 26, 13, 51,\n                                  25, 17, 11, 3, 1, 83, 88, 96 },\n\n                                {\n\n                                45,\n                                  6, 79, 45, 6, 79, 79, 65, 21, 11, 1, 64, 21,\n                                  40, 29, 7, 10, 4, 78, 2, 65, 67, 19, 80, 73,\n                                  20, 15, 91, 104, 117, 73, 79, 70, 78, 2, 65,\n                                  82, 64, 30, 2, 70, 77, 80, 89, 91, 90, 106,\n                                  64, 76, 84, 71, 85, 84, 99, 3, 72, 71, 76, 25,\n                                  2, 22, 0, 0, 0, 67, 92, 97, 3, 1, 67, 18, 72,\n                                  93, 66, 1, 71, 22, 20, 68, 1, 74, 11, 72, 68,\n                                  64, 98, 84, 87, 86, 19, 67, 4, 64, 70, 85, 72,\n                                  76, 65, 75, 72, 85, 18, 73, 6, 76, 79, 67, 73,\n                                  66, 3, 5, 1, 10, 6, 74, 0, 64, 67, 2, 72, 26,\n                                  67, 1, 24, 23, 32, 28, 21, 89, 1, 64, 67, 67,\n                                  81, 68, 17, 66, 66, 16, 35, 54, 42, 18, 90,\n                                  91, 3, 37, 40, 112, 70, 6, 90, 14, 67, 1, 16,\n                                  33, 55, 46, 25, 93, 85, 65, 7, 13, 89, 18, 21,\n                                  18, 16, 19, 16, 10, 18, 17, 64, 6, 10, 3, 2,\n                                  70, 6, 1, 65, 4, 1, 5, 5, 64, 90, 64, 65, 69,\n                                  66, 76, 22, 33, 19, 13, 18, 20, 20, 22, 14,\n                                  77, 89, 73, 72, 70, 110, 67, 0, 89, 15, 2, 2,\n                                  0, 0, 70, 64, 2, 82, 93, 79, 82, 81, 86, 74,\n                                  19, 17, 10, 4, 2, 67, 72, 73, 78, 64, 30, 17,\n                                  11, 3, 14, 2, 65, 72, 64, 65, 29, 16, 11, 5,\n                                  12, 1, 67, 71, 77, 72, 32, 15, 9, 4, 7, 67,\n                                  74, 77, 4, 36, 23, 16, 8, 17, 4, 64, 67, 70,\n                                  62, 89, 84, 77, 81, 81, 78, 75, 73, 72, 70,\n                                  67, 2, 77, 76, 82, 84, 21, 83, 85, 77, 72, 70,\n                                  73, 71, 71, 70, 69, 72, 82, 68, 68, 13, 69,\n                                  77, 67, 68, 69, 66, 67, 68, 77, 69, 68, 73,\n                                  72, 8, 90, 72, 14, 73, 64, 69, 68, 0, 1, 65,\n                                  65, 0, 73, 73, 84, 48, 45, 47, 39, 31, 34, 34,\n                                  29, 30, 26, 27, 27, 15, 10, 65, 16, 15, 9, 69,\n                                  8, 6, 1, 5, 66, 67, 71, 75, 79, 79, 19, 15,\n                                  18, 8, 72, 0, 65, 79, 68, 77, 80, 96, 88, 92,\n                                  97, 2, 5, 84, 0, 2, 70, 81, 78, 79, 87, 77,\n                                  83, 83, 96, 88, 93, 103, 68, 82, 89, 72, 3, 7,\n                                  8, 19, 13, 19, 2, 17, 15, 23, 24, 28, 27, 14,\n                                  50, 23, 15, 9, 1, 64, 85, 90, 97, 8, 38, 33,\n                                  33, 24, 25, 14, 12, 6, 1, 72, 3, 7, 8, 19, 13,\n                                  19, 2, 17, 15, 23, 24, 28, 27, 14, 50, 23, 15,\n                                  9, 1, 64, 85, 90, 97 },\n\n                                {\n\n                                43,\n                                  6, 79, 43, 6, 79, 78, 0, 21, 11, 0, 66, 20,\n                                  39, 30, 7, 12, 2, 78, 3, 65, 67, 20, 81, 75,\n                                  18, 13, 94, 106, 118, 71, 78, 70, 78, 3, 65,\n                                  82, 0, 30, 1, 69, 76, 79, 90, 93, 91, 106, 64,\n                                  76, 83, 71, 85, 84, 99, 3, 72, 71, 76, 26, 2,\n                                  22, 0, 0, 0, 67, 93, 97, 4, 0, 67, 17, 72, 92,\n                                  64, 2, 70, 23, 21, 68, 2, 72, 12, 71, 67, 1,\n                                  99, 84, 87, 86, 19, 68, 5, 1, 70, 84, 71, 74,\n                                  65, 75, 72, 85, 18, 73, 6, 75, 79, 67, 73, 66,\n                                  3, 5, 2, 10, 6, 74, 64, 64, 67, 2, 72, 26, 67,\n                                  1, 25, 23, 32, 28, 21, 90, 1, 0, 67, 67, 81,\n                                  68, 18, 66, 66, 17, 36, 55, 43, 20, 90, 92, 3,\n                                  37, 40, 113, 70, 7, 91, 15, 67, 1, 17, 33, 55,\n                                  46, 26, 94, 83, 66, 4, 10, 88, 17, 21, 17, 15,\n                                  18, 16, 9, 18, 16, 65, 5, 9, 3, 2, 70, 5, 0,\n                                  66, 3, 0, 4, 4, 64, 91, 65, 66, 69, 68, 77,\n                                  20, 31, 17, 11, 16, 18, 16, 19, 13, 79, 92,\n                                  75, 74, 72, 111, 69, 64, 91, 14, 1, 1, 64, 64,\n                                  72, 66, 0, 84, 93, 80, 83, 83, 85, 73, 20, 17,\n                                  10, 4, 3, 66, 71, 72, 76, 0, 31, 17, 12, 4,\n                                  15, 3, 0, 71, 1, 64, 29, 16, 11, 6, 13, 2, 67,\n                                  71, 76, 72, 33, 16, 9, 4, 8, 67, 74, 76, 5,\n                                  36, 24, 16, 8, 18, 5, 0, 67, 69, 62, 88, 83,\n                                  76, 79, 80, 76, 74, 71, 71, 69, 65, 4, 76, 75,\n                                  81, 83, 24, 83, 86, 77, 71, 70, 73, 71, 71,\n                                  71, 68, 72, 83, 68, 68, 14, 69, 77, 67, 68,\n                                  69, 67, 67, 68, 78, 70, 68, 73, 72, 9, 91, 72,\n                                  14, 74, 64, 69, 68, 0, 1, 66, 65, 1, 73, 73,\n                                  85, 47, 44, 46, 37, 29, 32, 31, 26, 27, 23,\n                                  23, 24, 11, 7, 67, 12, 11, 5, 74, 5, 4, 64, 3,\n                                  69, 69, 73, 76, 80, 79, 16, 13, 16, 6, 74, 65,\n                                  67, 81, 70, 79, 82, 98, 91, 94, 98, 1, 4, 87,\n                                  65, 0, 72, 83, 79, 80, 88, 78, 84, 83, 95, 89,\n                                  94, 104, 69, 83, 90, 72, 3, 7, 9, 20, 13, 20,\n                                  2, 18, 16, 24, 24, 29, 27, 15, 50, 21, 13, 7,\n                                  64, 66, 87, 92, 99, 8, 39, 33, 34, 25, 25, 14,\n                                  12, 6, 2, 72, 3, 7, 9, 20, 13, 20, 2, 18, 16,\n                                  24, 24, 29, 27, 15, 50, 21, 13, 7, 64, 66, 87,\n                                  92, 99 },\n\n                                {\n\n                                42,\n                                  6, 79, 42, 6, 79, 76, 1, 21, 11, 0, 68, 18,\n                                  38, 31, 7, 13, 0, 77, 5, 66, 67, 21, 82, 76,\n                                  17, 11, 97, 109, 118, 69, 77, 70, 77, 5, 66,\n                                  82, 1, 30, 1, 69, 75, 77, 91, 94, 91, 106, 64,\n                                  75, 82, 72, 85, 84, 99, 3, 71, 71, 75, 26, 2,\n                                  22, 0, 0, 0, 66, 93, 97, 4, 64, 67, 17, 71,\n                                  90, 2, 3, 69, 25, 23, 67, 3, 70, 13, 70, 66,\n                                  4, 99, 85, 87, 87, 19, 68, 6, 4, 69, 84, 71,\n                                  72, 65, 75, 72, 84, 18, 73, 7, 74, 78, 66, 72,\n                                  66, 4, 6, 3, 11, 6, 75, 64, 0, 67, 2, 72, 27,\n                                  67, 1, 25, 24, 32, 28, 21, 90, 2, 0, 68, 67,\n                                  80, 68, 19, 65, 65, 19, 38, 56, 45, 22, 91,\n                                  93, 4, 38, 40, 114, 70, 7, 91, 16, 67, 1, 19,\n                                  33, 55, 46, 28, 95, 82, 67, 2, 7, 87, 17, 21,\n                                  17, 15, 18, 16, 9, 18, 16, 66, 4, 9, 3, 2, 70,\n                                  5, 0, 67, 3, 0, 4, 3, 65, 92, 66, 66, 69, 69,\n                                  77, 18, 29, 16, 10, 15, 16, 13, 17, 12, 81,\n                                  94, 76, 76, 74, 112, 70, 65, 92, 13, 0, 0, 66,\n                                  66, 74, 68, 64, 85, 93, 81, 84, 85, 83, 71,\n                                  21, 18, 10, 4, 4, 65, 70, 72, 74, 2, 32, 18,\n                                  12, 5, 17, 4, 1, 70, 4, 0, 30, 17, 12, 6, 14,\n                                  3, 66, 70, 75, 71, 34, 17, 9, 4, 9, 66, 73,\n                                  75, 6, 36, 25, 16, 8, 19, 6, 1, 66, 68, 62,\n                                  87, 81, 74, 78, 79, 75, 72, 69, 69, 67, 0, 7,\n                                  75, 74, 80, 82, 27, 82, 87, 76, 70, 69, 73,\n                                  71, 71, 71, 68, 73, 84, 68, 68, 15, 69, 77,\n                                  67, 68, 68, 67, 68, 68, 79, 71, 69, 73, 72,\n                                  10, 91, 73, 15, 74, 65, 69, 68, 0, 0, 66, 65,\n                                  1, 73, 73, 87, 46, 43, 45, 36, 26, 29, 28, 23,\n                                  25, 20, 20, 21, 8, 5, 69, 8, 8, 1, 79, 2, 2,\n                                  65, 1, 71, 71, 74, 77, 81, 79, 14, 10, 13, 4,\n                                  76, 67, 68, 83, 72, 81, 84, 100, 93, 95, 100,\n                                  0, 3, 89, 66, 64, 73, 85, 80, 81, 89, 79, 85,\n                                  83, 94, 91, 95, 106, 71, 84, 91, 72, 4, 8, 10,\n                                  21, 14, 20, 3, 19, 17, 25, 25, 30, 28, 15, 49,\n                                  19, 11, 5, 66, 68, 90, 94, 100, 9, 39, 34, 34,\n                                  26, 26, 15, 13, 6, 3, 72, 4, 8, 10, 21, 14,\n                                  20, 3, 19, 17, 25, 25, 30, 28, 15, 49, 19, 11,\n                                  5, 66, 68, 90, 94, 100 },\n\n                                {\n\n                                41,\n                                  6, 79, 41, 6, 79, 74, 3, 22, 11, 64, 70, 17,\n                                  37, 31, 7, 15, 64, 77, 6, 66, 68, 22, 83, 77,\n                                  16, 9, 101, 111, 119, 67, 75, 70, 77, 6, 66,\n                                  81, 2, 31, 1, 68, 74, 76, 92, 95, 91, 107, 64,\n                                  75, 81, 72, 86, 84, 99, 3, 71, 71, 74, 27, 2,\n                                  22, 0, 0, 0, 66, 93, 97, 5, 65, 67, 16, 71,\n                                  89, 4, 4, 68, 26, 24, 66, 4, 68, 14, 69, 65,\n                                  6, 100, 85, 87, 87, 20, 68, 7, 6, 69, 83, 70,\n                                  70, 65, 75, 72, 84, 19, 73, 7, 73, 78, 65, 72,\n                                  66, 4, 6, 4, 11, 6, 75, 64, 0, 67, 2, 72, 27,\n                                  67, 1, 26, 24, 33, 28, 22, 91, 2, 1, 68, 67,\n                                  80, 68, 20, 65, 65, 20, 39, 57, 46, 24, 91,\n                                  94, 4, 38, 40, 115, 70, 8, 92, 16, 67, 1, 20,\n                                  33, 55, 46, 29, 96, 80, 68, 64, 4, 85, 17, 21,\n                                  16, 14, 17, 15, 8, 18, 15, 67, 3, 9, 3, 2, 71,\n                                  4, 64, 68, 2, 0, 4, 2, 65, 93, 66, 67, 69, 70,\n                                  78, 16, 27, 14, 8, 13, 14, 10, 14, 11, 83, 96,\n                                  78, 78, 76, 114, 71, 66, 94, 12, 64, 64, 67,\n                                  67, 76, 70, 66, 87, 93, 82, 85, 86, 82, 70,\n                                  23, 18, 10, 4, 5, 64, 69, 71, 72, 3, 33, 19,\n                                  13, 5, 18, 5, 3, 69, 6, 0, 30, 17, 12, 7, 15,\n                                  3, 66, 69, 74, 71, 36, 18, 9, 4, 10, 66, 73,\n                                  74, 7, 37, 26, 17, 8, 20, 6, 2, 66, 68, 62,\n                                  85, 80, 73, 76, 78, 73, 71, 68, 68, 65, 2, 9,\n                                  75, 73, 80, 81, 30, 82, 88, 76, 69, 68, 73,\n                                  71, 71, 71, 67, 73, 85, 68, 68, 15, 69, 77,\n                                  67, 68, 68, 68, 68, 68, 80, 72, 69, 73, 72,\n                                  11, 92, 73, 16, 75, 65, 69, 68, 1, 0, 67, 64,\n                                  2, 73, 73, 88, 45, 42, 44, 34, 24, 27, 26, 20,\n                                  22, 17, 17, 18, 5, 2, 71, 4, 4, 66, 84, 64, 0,\n                                  67, 64, 74, 73, 75, 78, 82, 79, 12, 8, 11, 2,\n                                  78, 69, 70, 85, 74, 83, 86, 102, 95, 97, 101,\n                                  64, 2, 91, 68, 66, 75, 87, 82, 83, 90, 80, 86,\n                                  83, 93, 92, 97, 107, 72, 85, 92, 72, 4, 8, 10,\n                                  22, 15, 21, 3, 20, 18, 26, 25, 31, 28, 16, 49,\n                                  17, 9, 3, 68, 70, 92, 96, 101, 9, 40, 34, 35,\n                                  26, 27, 15, 13, 7, 3, 72, 4, 8, 10, 22, 15,\n                                  21, 3, 20, 18, 26, 25, 31, 28, 16, 49, 17, 9,\n                                  3, 68, 70, 92, 96, 101 },\n\n                                {\n\n                                40,\n                                  6, 79, 40, 6, 79, 72, 4, 22, 11, 64, 72, 15,\n                                  36, 32, 7, 17, 66, 77, 8, 66, 68, 23, 84, 78,\n                                  15, 7, 104, 113, 120, 65, 74, 70, 77, 8, 66,\n                                  81, 3, 31, 1, 67, 73, 75, 93, 96, 91, 107, 64,\n                                  75, 80, 72, 86, 84, 99, 3, 71, 71, 73, 27, 2,\n                                  22, 0, 0, 0, 65, 93, 97, 5, 66, 67, 16, 70,\n                                  88, 6, 5, 67, 28, 26, 65, 5, 66, 15, 68, 64,\n                                  8, 101, 85, 87, 87, 20, 68, 8, 8, 69, 82, 69,\n                                  68, 65, 75, 72, 84, 19, 73, 8, 72, 78, 64, 72,\n                                  66, 4, 7, 5, 12, 6, 75, 64, 0, 67, 2, 72, 27,\n                                  67, 1, 26, 24, 33, 28, 22, 91, 3, 2, 69, 67,\n                                  80, 68, 21, 65, 64, 21, 40, 58, 48, 26, 92,\n                                  95, 5, 38, 40, 116, 70, 8, 92, 17, 67, 1, 21,\n                                  33, 55, 46, 30, 97, 79, 69, 67, 1, 84, 17, 21,\n                                  16, 13, 17, 15, 8, 18, 15, 68, 2, 9, 3, 2, 71,\n                                  4, 65, 69, 2, 0, 4, 1, 66, 94, 67, 68, 69, 71,\n                                  78, 14, 25, 12, 7, 11, 12, 7, 12, 10, 85, 98,\n                                  79, 80, 78, 115, 72, 67, 96, 11, 65, 65, 68,\n                                  69, 78, 72, 68, 88, 93, 83, 86, 88, 80, 68,\n                                  24, 19, 10, 4, 6, 0, 68, 70, 70, 4, 34, 20,\n                                  14, 6, 19, 6, 4, 68, 8, 1, 31, 18, 13, 7, 16,\n                                  4, 65, 68, 73, 71, 37, 19, 9, 4, 11, 65, 73,\n                                  73, 8, 37, 27, 17, 8, 21, 7, 3, 65, 67, 62,\n                                  84, 78, 71, 74, 77, 72, 69, 66, 66, 0, 4, 11,\n                                  74, 72, 79, 80, 33, 82, 89, 76, 68, 67, 73,\n                                  71, 71, 71, 67, 73, 86, 68, 68, 16, 69, 77,\n                                  67, 68, 68, 68, 68, 68, 81, 73, 69, 73, 72,\n                                  12, 93, 73, 17, 76, 65, 69, 68, 1, 0, 67, 64,\n                                  3, 73, 73, 90, 44, 41, 43, 32, 22, 24, 23, 17,\n                                  20, 14, 14, 15, 2, 64, 73, 0, 1, 70, 89, 67,\n                                  65, 69, 66, 76, 75, 76, 79, 83, 79, 10, 6, 9,\n                                  0, 80, 71, 71, 87, 76, 85, 88, 104, 97, 99,\n                                  102, 65, 1, 93, 69, 68, 76, 89, 83, 84, 91,\n                                  81, 87, 83, 92, 93, 98, 109, 73, 86, 93, 72,\n                                  5, 9, 11, 23, 16, 22, 3, 21, 19, 27, 26, 32,\n                                  29, 17, 48, 15, 7, 1, 70, 72, 94, 98, 102, 10,\n                                  40, 35, 36, 27, 28, 16, 14, 7, 4, 72, 5, 9,\n                                  11, 23, 16, 22, 3, 21, 19, 27, 26, 32, 29, 17,\n                                  48, 15, 7, 1, 70, 72, 94, 98, 102 },\n\n                                {\n\n                                38,\n                                  5, 80, 38, 5, 80, 71, 5, 22, 11, 65, 74, 13,\n                                  35, 32, 7, 18, 68, 77, 9, 67, 69, 24, 85, 80,\n                                  13, 5, 108, 116, 121, 0, 73, 70, 77, 9, 67,\n                                  81, 3, 31, 0, 67, 73, 74, 95, 98, 92, 108, 65,\n                                  75, 80, 73, 87, 84, 99, 2, 71, 71, 73, 27, 1,\n                                  22, 0, 0, 0, 65, 94, 97, 5, 67, 68, 15, 70,\n                                  87, 8, 6, 67, 29, 27, 65, 6, 65, 15, 67, 64,\n                                  10, 102, 86, 88, 88, 20, 69, 8, 10, 69, 82,\n                                  69, 67, 65, 75, 72, 84, 19, 74, 8, 72, 78, 64,\n                                  72, 66, 4, 7, 6, 12, 6, 76, 65, 0, 67, 1, 72,\n                                  27, 67, 1, 26, 24, 33, 28, 22, 92, 3, 2, 70,\n                                  67, 80, 69, 21, 65, 64, 22, 41, 58, 49, 27,\n                                  93, 97, 5, 38, 40, 117, 71, 8, 93, 17, 68, 1,\n                                  22, 33, 54, 46, 31, 98, 78, 71, 70, 66, 83,\n                                  16, 21, 15, 12, 16, 14, 7, 17, 14, 69, 1, 8,\n                                  2, 1, 72, 3, 66, 70, 1, 64, 3, 0, 67, 96, 68,\n                                  69, 69, 73, 79, 11, 22, 10, 5, 9, 9, 3, 9, 8,\n                                  87, 101, 81, 83, 80, 117, 74, 69, 98, 9, 66,\n                                  66, 70, 71, 80, 74, 70, 90, 93, 84, 87, 90,\n                                  79, 67, 25, 19, 10, 4, 6, 0, 68, 70, 69, 5,\n                                  34, 20, 14, 6, 20, 7, 5, 68, 10, 1, 31, 18,\n                                  13, 7, 16, 4, 65, 68, 72, 71, 38, 20, 9, 3,\n                                  11, 65, 73, 73, 8, 37, 27, 17, 8, 22, 7, 3,\n                                  65, 67, 62, 83, 77, 70, 73, 76, 71, 68, 65,\n                                  65, 1, 5, 13, 74, 72, 79, 80, 36, 82, 91, 76,\n                                  68, 67, 73, 71, 71, 72, 67, 74, 87, 69, 68,\n                                  16, 70, 77, 68, 68, 68, 69, 69, 69, 82, 74,\n                                  70, 74, 72, 13, 94, 74, 17, 77, 66, 69, 69, 1,\n                                  64, 68, 64, 3, 73, 73, 92, 42, 40, 41, 30, 19,\n                                  21, 20, 14, 17, 11, 10, 12, 65, 67, 75, 67,\n                                  66, 74, 95, 70, 68, 71, 69, 79, 77, 78, 81,\n                                  84, 79, 7, 3, 6, 65, 83, 73, 73, 90, 78, 88,\n                                  90, 107, 100, 101, 104, 67, 64, 96, 71, 70,\n                                  78, 91, 85, 86, 92, 82, 88, 84, 91, 95, 100,\n                                  111, 75, 88, 95, 72, 5, 9, 11, 24, 16, 22, 3,\n                                  22, 19, 28, 26, 32, 29, 17, 47, 13, 5, 65, 73,\n                                  74, 97, 100, 104, 10, 40, 35, 36, 27, 28, 16,\n                                  14, 7, 4, 72, 5, 9, 11, 24, 16, 22, 3, 22, 19,\n                                  28, 26, 32, 29, 17, 47, 13, 5, 65, 73, 74, 97,\n                                  100, 104 },\n\n                                {\n\n                                37,\n                                  5, 80, 37, 5, 80, 69, 7, 23, 12, 65, 75, 12,\n                                  35, 33, 8, 20, 69, 76, 11, 67, 69, 26, 85, 81,\n                                  12, 4, 111, 118, 121, 2, 71, 69, 76, 11, 67,\n                                  80, 4, 32, 0, 66, 72, 72, 96, 99, 92, 108, 65,\n                                  74, 79, 73, 87, 83, 98, 2, 70, 70, 72, 28, 1,\n                                  22, 0, 0, 0, 64, 94, 97, 6, 67, 68, 15, 69,\n                                  85, 11, 8, 66, 31, 29, 64, 8, 0, 16, 65, 0,\n                                  13, 102, 86, 88, 88, 21, 69, 9, 13, 68, 81,\n                                  68, 65, 65, 74, 72, 83, 20, 74, 9, 71, 77, 0,\n                                  71, 65, 5, 8, 7, 13, 7, 76, 65, 1, 66, 1, 71,\n                                  28, 66, 1, 27, 25, 34, 29, 23, 92, 4, 3, 70,\n                                  67, 79, 69, 22, 64, 0, 24, 43, 59, 51, 29, 93,\n                                  98, 6, 39, 41, 117, 71, 9, 93, 18, 68, 2, 24,\n                                  33, 54, 47, 33, 99, 76, 72, 72, 69, 81, 16,\n                                  21, 15, 12, 16, 14, 7, 17, 14, 69, 1, 8, 2, 1,\n                                  72, 3, 66, 70, 1, 64, 3, 0, 67, 97, 68, 69,\n                                  69, 74, 79, 9, 20, 9, 4, 8, 7, 0, 7, 7, 88,\n                                  103, 82, 85, 81, 118, 75, 70, 99, 8, 66, 66,\n                                  71, 72, 81, 75, 71, 91, 93, 84, 87, 91, 77,\n                                  65, 27, 20, 10, 4, 7, 1, 67, 69, 67, 7, 35,\n                                  21, 15, 7, 22, 8, 7, 67, 13, 2, 32, 19, 14, 8,\n                                  17, 5, 64, 67, 70, 70, 40, 21, 10, 3, 12, 64,\n                                  72, 72, 9, 38, 28, 18, 9, 23, 8, 4, 64, 66,\n                                  62, 81, 75, 68, 71, 74, 69, 66, 0, 0, 3, 7,\n                                  16, 73, 71, 78, 79, 40, 81, 92, 75, 67, 66,\n                                  72, 71, 70, 72, 66, 74, 87, 69, 68, 17, 70,\n                                  77, 68, 68, 67, 69, 69, 69, 82, 74, 70, 74,\n                                  71, 15, 94, 74, 18, 77, 66, 69, 69, 2, 64, 68,\n                                  0, 4, 72, 72, 93, 41, 39, 40, 29, 17, 19, 18,\n                                  11, 15, 9, 7, 10, 68, 69, 77, 70, 69, 77, 100,\n                                  72, 70, 72, 71, 81, 78, 79, 82, 84, 79, 5, 1,\n                                  4, 67, 85, 74, 74, 92, 79, 90, 91, 109, 102,\n                                  102, 105, 68, 65, 98, 72, 71, 79, 92, 86, 87,\n                                  93, 82, 88, 84, 90, 96, 101, 112, 76, 89, 96,\n                                  71, 6, 10, 12, 26, 17, 23, 4, 24, 20, 29, 27,\n                                  33, 30, 18, 47, 12, 4, 67, 75, 75, 99, 101,\n                                  105, 11, 41, 36, 37, 28, 29, 17, 15, 8, 5, 71,\n                                  6, 10, 12, 26, 17, 23, 4, 24, 20, 29, 27, 33,\n                                  30, 18, 47, 12, 4, 67, 75, 75, 99, 101, 105 },\n\n                                {\n\n                                36,\n                                  5, 80, 36, 5, 80, 67, 8, 23, 12, 65, 77, 10,\n                                  34, 34, 8, 22, 71, 76, 12, 67, 69, 27, 86, 82,\n                                  11, 2, 114, 120, 122, 4, 70, 69, 76, 12, 67,\n                                  80, 5, 32, 0, 65, 71, 71, 97, 100, 92, 108,\n                                  65, 74, 78, 73, 87, 83, 98, 2, 70, 70, 71, 28,\n                                  1, 22, 0, 0, 0, 0, 94, 97, 6, 68, 68, 15, 68,\n                                  84, 13, 9, 65, 33, 31, 0, 9, 2, 17, 64, 1, 15,\n                                  103, 86, 88, 88, 21, 69, 10, 15, 68, 80, 67,\n                                  0, 65, 74, 72, 83, 20, 74, 9, 70, 77, 1, 71,\n                                  65, 5, 8, 8, 14, 7, 76, 65, 1, 66, 1, 71, 28,\n                                  66, 1, 27, 25, 34, 29, 23, 93, 5, 4, 71, 67,\n                                  79, 69, 23, 64, 0, 25, 44, 60, 53, 31, 94, 99,\n                                  6, 39, 41, 118, 71, 9, 94, 19, 68, 2, 25, 33,\n                                  54, 47, 34, 100, 75, 73, 75, 72, 80, 16, 21,\n                                  15, 11, 15, 14, 7, 17, 13, 70, 0, 8, 2, 1, 72,\n                                  2, 67, 71, 1, 64, 3, 64, 68, 98, 69, 70, 69,\n                                  75, 80, 7, 18, 7, 2, 6, 5, 66, 5, 6, 90, 105,\n                                  84, 87, 83, 119, 76, 71, 101, 7, 67, 67, 72,\n                                  74, 83, 77, 73, 93, 93, 85, 88, 93, 76, 64,\n                                  28, 21, 10, 4, 8, 2, 66, 68, 65, 8, 36, 22,\n                                  16, 8, 23, 9, 8, 66, 15, 3, 32, 19, 14, 8, 18,\n                                  6, 0, 66, 69, 70, 41, 22, 10, 3, 13, 0, 72,\n                                  71, 10, 38, 29, 18, 9, 24, 9, 5, 0, 65, 62,\n                                  80, 73, 66, 69, 73, 68, 64, 2, 1, 5, 9, 18,\n                                  72, 70, 77, 78, 43, 81, 93, 75, 66, 65, 72,\n                                  71, 70, 72, 66, 74, 88, 69, 68, 18, 70, 77,\n                                  68, 68, 67, 69, 69, 69, 83, 75, 70, 74, 71,\n                                  16, 95, 74, 19, 78, 66, 69, 69, 2, 64, 68, 0,\n                                  5, 72, 72, 95, 40, 38, 39, 27, 15, 16, 15, 8,\n                                  13, 6, 4, 7, 71, 72, 79, 74, 73, 81, 105, 75,\n                                  72, 74, 73, 83, 80, 80, 83, 85, 79, 3, 64, 2,\n                                  69, 87, 76, 76, 94, 81, 92, 93, 111, 104, 104,\n                                  106, 69, 66, 100, 74, 73, 81, 94, 87, 88, 94,\n                                  83, 89, 84, 89, 97, 102, 114, 77, 90, 97, 71,\n                                  6, 11, 13, 27, 18, 24, 4, 25, 21, 30, 27, 34,\n                                  31, 19, 46, 10, 2, 69, 77, 77, 101, 103, 106,\n                                  12, 41, 36, 38, 29, 30, 17, 16, 8, 6, 71, 6,\n                                  11, 13, 27, 18, 24, 4, 25, 21, 30, 27, 34, 31,\n                                  19, 46, 10, 2, 69, 77, 77, 101, 103, 106 },\n\n                                {\n\n                                35,\n                                  5, 80, 35, 5, 80, 65, 10, 24, 12, 66, 79, 9,\n                                  33, 34, 8, 24, 72, 76, 14, 67, 70, 28, 87, 83,\n                                  10, 0, 118, 122, 123, 6, 68, 69, 76, 14, 67,\n                                  79, 6, 33, 0, 64, 70, 70, 98, 101, 92, 109,\n                                  65, 74, 77, 73, 88, 83, 98, 2, 70, 70, 70, 29,\n                                  1, 22, 0, 0, 0, 0, 94, 97, 7, 69, 68, 14, 68,\n                                  83, 15, 10, 64, 34, 32, 1, 10, 4, 18, 0, 2,\n                                  17, 104, 86, 88, 88, 22, 69, 11, 17, 68, 79,\n                                  66, 2, 65, 74, 72, 83, 21, 74, 10, 69, 77, 2,\n                                  71, 65, 5, 9, 9, 14, 7, 76, 65, 1, 66, 1, 71,\n                                  28, 66, 1, 28, 25, 35, 29, 24, 93, 5, 5, 71,\n                                  67, 79, 69, 24, 64, 1, 26, 45, 61, 54, 33, 94,\n                                  100, 7, 39, 41, 119, 71, 10, 94, 19, 68, 2,\n                                  26, 33, 54, 47, 35, 101, 73, 74, 78, 75, 78,\n                                  16, 21, 14, 10, 15, 13, 6, 17, 13, 71, 64, 8,\n                                  2, 1, 73, 2, 68, 72, 0, 64, 3, 65, 68, 99, 69,\n                                  71, 69, 76, 80, 5, 16, 5, 1, 4, 3, 69, 2, 5,\n                                  92, 107, 85, 89, 85, 121, 77, 72, 103, 6, 68,\n                                  68, 73, 75, 85, 79, 75, 94, 93, 86, 89, 94,\n                                  74, 1, 30, 21, 10, 4, 9, 3, 65, 67, 0, 9, 37,\n                                  23, 17, 8, 24, 10, 10, 65, 17, 3, 33, 20, 15,\n                                  9, 19, 6, 0, 65, 68, 70, 43, 23, 10, 3, 14, 0,\n                                  72, 70, 11, 39, 30, 19, 9, 25, 9, 6, 0, 65,\n                                  62, 78, 72, 65, 67, 72, 66, 0, 3, 3, 7, 11,\n                                  20, 72, 69, 77, 77, 46, 81, 94, 75, 65, 64,\n                                  72, 71, 70, 72, 65, 74, 89, 69, 68, 18, 70,\n                                  77, 68, 68, 67, 70, 69, 69, 84, 76, 70, 74,\n                                  71, 17, 96, 74, 20, 79, 66, 69, 69, 3, 64, 69,\n                                  1, 6, 72, 72, 96, 39, 37, 38, 25, 13, 14, 13,\n                                  5, 10, 3, 1, 4, 74, 75, 81, 78, 76, 85, 110,\n                                  78, 74, 76, 75, 86, 82, 81, 84, 86, 79, 1, 66,\n                                  0, 71, 89, 78, 77, 96, 83, 94, 95, 113, 106,\n                                  106, 107, 70, 67, 102, 75, 75, 82, 96, 89, 90,\n                                  95, 84, 90, 84, 88, 98, 104, 115, 78, 91, 98,\n                                  71, 7, 11, 13, 28, 19, 25, 4, 26, 22, 31, 28,\n                                  35, 31, 20, 46, 8, 0, 71, 79, 79, 103, 105,\n                                  107, 12, 42, 37, 39, 29, 31, 18, 16, 9, 6, 71,\n                                  7, 11, 13, 28, 19, 25, 4, 26, 22, 31, 28, 35,\n                                  31, 20, 46, 8, 0, 71, 79, 79, 103, 105, 107 },\n\n                                {\n\n                                33,\n                                  5, 80, 33, 5, 80, 64, 11, 24, 12, 66, 81, 7,\n                                  32, 35, 8, 25, 74, 76, 15, 68, 70, 29, 88, 85,\n                                  8, 65, 121, 125, 124, 8, 67, 69, 76, 15, 68,\n                                  79, 7, 33, 64, 64, 69, 68, 99, 103, 93, 109,\n                                  65, 73, 76, 74, 88, 83, 98, 2, 70, 70, 70, 29,\n                                  1, 22, 0, 0, 0, 1, 95, 97, 7, 70, 68, 14, 67,\n                                  82, 17, 11, 0, 36, 34, 1, 11, 6, 19, 1, 3, 20,\n                                  104, 87, 88, 89, 22, 70, 12, 20, 67, 79, 66,\n                                  4, 65, 74, 72, 83, 21, 74, 10, 68, 77, 2, 70,\n                                  65, 5, 9, 10, 15, 7, 77, 66, 1, 66, 1, 71, 28,\n                                  66, 1, 28, 25, 35, 29, 24, 94, 6, 5, 72, 67,\n                                  78, 69, 25, 0, 1, 28, 47, 62, 56, 35, 95, 101,\n                                  7, 40, 41, 120, 71, 10, 95, 20, 68, 2, 27, 33,\n                                  54, 47, 37, 102, 72, 75, 81, 78, 77, 15, 21,\n                                  14, 10, 14, 13, 6, 17, 12, 72, 65, 7, 2, 1,\n                                  73, 1, 68, 73, 0, 65, 2, 66, 69, 100, 70, 72,\n                                  69, 78, 81, 3, 14, 3, 64, 3, 1, 73, 0, 4, 94,\n                                  110, 87, 91, 87, 122, 79, 73, 104, 5, 69, 69,\n                                  75, 77, 87, 81, 76, 96, 93, 87, 90, 96, 73, 2,\n                                  31, 22, 10, 4, 10, 4, 64, 67, 2, 11, 38, 23,\n                                  17, 9, 26, 11, 11, 64, 20, 4, 33, 20, 15, 9,\n                                  20, 7, 1, 65, 67, 70, 44, 24, 10, 3, 15, 1,\n                                  72, 69, 12, 39, 31, 19, 9, 26, 10, 7, 1, 64,\n                                  62, 77, 70, 0, 66, 71, 65, 2, 5, 4, 8, 13, 23,\n                                  71, 68, 76, 76, 49, 80, 95, 74, 64, 64, 72,\n                                  71, 70, 73, 65, 75, 90, 69, 68, 19, 70, 77,\n                                  68, 68, 66, 70, 70, 69, 85, 77, 71, 74, 71,\n                                  18, 97, 75, 20, 79, 67, 69, 69, 3, 65, 69, 1,\n                                  6, 72, 72, 98, 38, 36, 37, 24, 10, 11, 10, 2,\n                                  8, 0, 66, 1, 78, 77, 83, 82, 80, 89, 115, 81,\n                                  76, 78, 77, 88, 84, 83, 85, 87, 79, 65, 69,\n                                  66, 73, 91, 80, 79, 98, 85, 96, 97, 115, 109,\n                                  107, 109, 71, 68, 105, 77, 76, 84, 98, 90, 91,\n                                  96, 85, 91, 84, 87, 100, 105, 117, 80, 92, 99,\n                                  71, 7, 12, 14, 29, 19, 25, 5, 27, 23, 32, 28,\n                                  36, 32, 20, 45, 6, 65, 73, 81, 81, 106, 107,\n                                  109, 13, 42, 37, 39, 30, 31, 18, 17, 9, 7, 71,\n                                  7, 12, 14, 29, 19, 25, 5, 27, 23, 32, 28, 36,\n                                  32, 20, 45, 6, 65, 73, 81, 81, 106, 107, 109 },\n\n                                {\n\n                                32,\n                                  5, 80, 32, 5, 80, 1, 13, 24, 12, 67, 83, 6,\n                                  31, 36, 8, 27, 76, 75, 17, 68, 70, 30, 89, 86,\n                                  7, 67, 124, 126, 124, 10, 66, 69, 75, 17, 68,\n                                  79, 8, 33, 64, 0, 68, 67, 100, 104, 93, 109,\n                                  65, 73, 75, 74, 88, 83, 98, 2, 69, 70, 69, 30,\n                                  1, 22, 0, 0, 0, 1, 95, 97, 8, 71, 68, 13, 67,\n                                  80, 20, 12, 1, 37, 35, 2, 12, 8, 20, 2, 4, 22,\n                                  105, 87, 88, 89, 22, 70, 13, 22, 67, 78, 65,\n                                  6, 65, 74, 72, 82, 21, 74, 11, 67, 76, 3, 70,\n                                  65, 6, 10, 11, 15, 7, 77, 66, 2, 66, 1, 71,\n                                  29, 66, 1, 29, 26, 35, 29, 24, 94, 6, 6, 72,\n                                  67, 78, 69, 26, 0, 2, 29, 48, 62, 57, 37, 95,\n                                  102, 8, 40, 41, 121, 71, 11, 95, 21, 68, 2,\n                                  29, 33, 54, 47, 38, 103, 70, 76, 83, 81, 76,\n                                  15, 21, 13, 9, 14, 13, 5, 17, 12, 73, 66, 7,\n                                  2, 1, 73, 1, 69, 74, 64, 65, 2, 67, 69, 101,\n                                  71, 72, 69, 79, 81, 1, 12, 2, 65, 1, 64, 76,\n                                  66, 3, 96, 112, 88, 93, 89, 123, 80, 74, 106,\n                                  4, 70, 70, 76, 78, 89, 83, 78, 97, 93, 88, 91,\n                                  98, 71, 4, 32, 22, 10, 4, 11, 5, 0, 66, 4, 12,\n                                  39, 24, 18, 10, 27, 12, 13, 0, 22, 5, 34, 21,\n                                  16, 10, 21, 8, 1, 64, 66, 69, 45, 25, 10, 3,\n                                  16, 1, 71, 68, 13, 39, 32, 19, 9, 27, 11, 8,\n                                  1, 0, 62, 76, 69, 1, 64, 70, 0, 3, 7, 6, 10,\n                                  15, 25, 70, 67, 75, 75, 52, 80, 96, 74, 0, 0,\n                                  72, 71, 70, 73, 64, 75, 91, 69, 68, 20, 70,\n                                  77, 68, 68, 66, 71, 70, 69, 86, 78, 71, 74,\n                                  71, 19, 97, 75, 21, 80, 67, 69, 69, 3, 65, 70,\n                                  1, 7, 72, 72, 99, 37, 35, 36, 22, 8, 9, 7, 64,\n                                  5, 66, 69, 65, 81, 80, 85, 86, 83, 93, 120,\n                                  84, 78, 79, 79, 91, 86, 84, 86, 88, 79, 67,\n                                  71, 68, 75, 93, 82, 80, 100, 87, 98, 99, 117,\n                                  111, 109, 110, 72, 69, 107, 78, 78, 85, 100,\n                                  91, 92, 97, 86, 92, 84, 86, 101, 106, 118, 81,\n                                  93, 100, 71, 8, 12, 15, 30, 20, 26, 5, 28, 24,\n                                  33, 29, 37, 32, 21, 45, 4, 67, 75, 83, 83,\n                                  108, 109, 110, 13, 43, 38, 40, 31, 32, 19, 17,\n                                  9, 8, 71, 8, 12, 15, 30, 20, 26, 5, 28, 24,\n                                  33, 29, 37, 32, 21, 45, 4, 67, 75, 83, 83,\n                                  108, 109, 110 },\n\n                                {\n\n                                31,\n                                  5, 81, 31, 5, 81, 3, 14, 25, 12, 67, 84, 4,\n                                  30, 36, 9, 29, 77, 75, 18, 68, 71, 31, 90, 87,\n                                  6, 68, 126, 126, 125, 12, 64, 69, 75, 18, 68,\n                                  78, 9, 34, 64, 1, 67, 66, 102, 105, 93, 110,\n                                  65, 73, 75, 74, 89, 82, 98, 1, 69, 70, 68, 30,\n                                  1, 22, 0, 0, 0, 2, 95, 97, 8, 71, 69, 13, 66,\n                                  79, 22, 13, 2, 39, 37, 3, 13, 10, 21, 3, 4,\n                                  24, 106, 87, 88, 89, 23, 70, 14, 24, 67, 77,\n                                  64, 8, 65, 74, 72, 82, 22, 75, 11, 67, 76, 4,\n                                  70, 64, 6, 10, 12, 16, 7, 77, 66, 2, 66, 1,\n                                  71, 29, 66, 1, 29, 26, 36, 30, 25, 95, 7, 7,\n                                  73, 67, 78, 69, 27, 0, 2, 30, 49, 62, 59, 38,\n                                  96, 103, 8, 40, 41, 121, 72, 11, 96, 21, 69,\n                                  3, 30, 33, 54, 48, 39, 104, 69, 77, 86, 84,\n                                  74, 15, 21, 13, 8, 13, 12, 5, 16, 11, 73, 66,\n                                  7, 1, 1, 74, 0, 70, 75, 64, 65, 2, 67, 70,\n                                  103, 71, 73, 69, 80, 82, 65, 10, 0, 67, 64,\n                                  66, 79, 68, 1, 98, 114, 90, 95, 91, 125, 81,\n                                  76, 108, 2, 71, 71, 77, 80, 91, 85, 80, 99,\n                                  93, 89, 92, 99, 70, 5, 34, 23, 10, 4, 12, 5,\n                                  0, 65, 5, 13, 40, 25, 19, 10, 28, 13, 14, 1,\n                                  24, 5, 34, 21, 16, 10, 22, 8, 2, 0, 65, 69,\n                                  47, 26, 10, 3, 16, 2, 71, 68, 13, 40, 32, 20,\n                                  9, 28, 11, 8, 2, 0, 62, 74, 67, 3, 1, 68, 1,\n                                  5, 8, 7, 12, 17, 27, 70, 66, 75, 75, 55, 80,\n                                  97, 74, 0, 1, 72, 71, 70, 73, 64, 75, 92, 69,\n                                  68, 20, 70, 77, 68, 68, 66, 71, 70, 69, 87,\n                                  79, 71, 74, 71, 20, 98, 75, 22, 81, 67, 69,\n                                  69, 4, 65, 70, 2, 8, 72, 72, 101, 36, 34, 35,\n                                  20, 6, 6, 5, 67, 3, 69, 72, 68, 84, 83, 87,\n                                  89, 87, 97, 125, 86, 81, 81, 81, 93, 88, 85,\n                                  87, 89, 79, 69, 73, 70, 77, 95, 83, 82, 102,\n                                  89, 101, 101, 119, 113, 111, 111, 73, 71, 109,\n                                  80, 80, 87, 102, 93, 94, 98, 87, 93, 85, 85,\n                                  102, 108, 120, 82, 95, 101, 70, 8, 13, 15, 31,\n                                  21, 27, 5, 29, 25, 34, 29, 38, 33, 22, 44, 2,\n                                  69, 77, 85, 85, 110, 111, 111, 14, 43, 38, 41,\n                                  31, 33, 19, 18, 10, 8, 70, 8, 13, 15, 31, 21,\n                                  27, 5, 29, 25, 34, 29, 38, 33, 22, 44, 2, 69,\n                                  77, 85, 85, 110, 111, 111 },\n\n                                {\n\n                                30,\n                                  5, 81, 30, 5, 81, 5, 16, 25, 12, 68, 86, 3,\n                                  29, 37, 9, 30, 79, 75, 20, 69, 71, 32, 91, 88,\n                                  5, 70, 126, 126, 126, 14, 0, 69, 75, 20, 69,\n                                  78, 10, 34, 64, 1, 66, 64, 103, 106, 93, 110,\n                                  65, 72, 74, 75, 89, 82, 98, 1, 69, 70, 67, 31,\n                                  1, 22, 0, 0, 0, 2, 95, 97, 9, 72, 69, 12, 66,\n                                  78, 24, 14, 3, 40, 38, 4, 14, 12, 22, 4, 5,\n                                  27, 106, 88, 88, 90, 23, 70, 15, 27, 66, 77,\n                                  64, 10, 65, 74, 72, 82, 22, 75, 12, 66, 76, 5,\n                                  69, 64, 6, 11, 13, 16, 7, 78, 66, 2, 66, 1,\n                                  71, 29, 66, 1, 30, 26, 36, 30, 25, 95, 7, 7,\n                                  73, 67, 77, 69, 28, 1, 3, 32, 51, 62, 60, 40,\n                                  96, 104, 9, 41, 41, 122, 72, 12, 96, 22, 69,\n                                  3, 31, 33, 54, 48, 41, 105, 67, 78, 89, 87,\n                                  73, 15, 21, 12, 8, 13, 12, 4, 16, 11, 74, 67,\n                                  7, 1, 1, 74, 0, 70, 76, 65, 65, 2, 68, 70,\n                                  104, 72, 74, 69, 81, 82, 67, 8, 65, 68, 65,\n                                  68, 82, 71, 0, 100, 116, 91, 97, 93, 126, 82,\n                                  77, 109, 1, 72, 72, 79, 81, 93, 87, 81, 100,\n                                  93, 90, 93, 101, 68, 7, 35, 23, 10, 4, 13, 6,\n                                  1, 65, 7, 15, 41, 26, 19, 11, 30, 14, 16, 2,\n                                  27, 6, 35, 22, 17, 11, 23, 9, 2, 1, 64, 69,\n                                  48, 27, 10, 3, 17, 2, 71, 67, 14, 40, 33, 20,\n                                  9, 29, 12, 9, 2, 1, 62, 73, 66, 4, 2, 67, 3,\n                                  6, 10, 9, 14, 19, 30, 69, 65, 74, 74, 58, 79,\n                                  98, 73, 1, 2, 72, 71, 70, 73, 0, 76, 93, 69,\n                                  68, 21, 70, 77, 68, 68, 65, 72, 71, 69, 88,\n                                  80, 72, 74, 71, 21, 99, 76, 23, 81, 68, 69,\n                                  69, 4, 66, 71, 2, 8, 72, 72, 102, 35, 33, 34,\n                                  19, 3, 4, 2, 70, 0, 72, 75, 71, 87, 85, 89,\n                                  93, 90, 101, 126, 89, 83, 83, 83, 96, 90, 86,\n                                  88, 90, 79, 71, 76, 73, 79, 97, 85, 83, 104,\n                                  91, 103, 103, 121, 115, 112, 113, 74, 72, 111,\n                                  81, 81, 88, 104, 94, 95, 99, 88, 94, 85, 84,\n                                  104, 109, 121, 84, 96, 102, 70, 9, 13, 16, 32,\n                                  22, 27, 6, 30, 26, 35, 30, 39, 33, 22, 44, 0,\n                                  71, 79, 87, 87, 113, 113, 112, 14, 44, 39, 41,\n                                  32, 34, 20, 18, 10, 9, 70, 9, 13, 16, 32, 22,\n                                  27, 6, 30, 26, 35, 30, 39, 33, 22, 44, 0, 71,\n                                  79, 87, 87, 113, 113, 112 },\n\n                                {\n\n                                28,\n                                  4, 81, 28, 4, 81, 6, 17, 25, 12, 68, 88, 1,\n                                  28, 37, 9, 32, 81, 75, 21, 69, 72, 33, 92, 90,\n                                  3, 72, 126, 126, 126, 16, 1, 69, 75, 21, 69,\n                                  78, 10, 34, 65, 2, 65, 0, 104, 108, 94, 111,\n                                  65, 72, 73, 75, 90, 82, 98, 1, 69, 70, 67, 31,\n                                  1, 22, 0, 0, 0, 3, 96, 97, 9, 73, 69, 12, 65,\n                                  77, 26, 15, 3, 42, 40, 4, 15, 14, 22, 5, 6,\n                                  29, 107, 88, 89, 90, 23, 71, 15, 29, 66, 76,\n                                  0, 11, 65, 74, 72, 82, 22, 75, 12, 65, 76, 5,\n                                  69, 64, 6, 11, 14, 17, 7, 78, 67, 2, 66, 0,\n                                  71, 29, 66, 1, 30, 26, 36, 30, 25, 96, 8, 8,\n                                  74, 67, 77, 69, 29, 1, 3, 33, 52, 62, 62, 42,\n                                  97, 105, 9, 41, 41, 123, 72, 12, 97, 22, 69,\n                                  3, 32, 33, 54, 48, 42, 106, 66, 79, 92, 91,\n                                  72, 14, 21, 12, 7, 12, 11, 4, 16, 10, 75, 68,\n                                  6, 1, 0, 75, 64, 71, 77, 65, 66, 1, 69, 71,\n                                  105, 73, 75, 69, 83, 83, 69, 6, 67, 70, 67,\n                                  71, 86, 73, 64, 102, 119, 93, 100, 95, 126,\n                                  84, 78, 111, 0, 73, 73, 80, 83, 95, 89, 83,\n                                  102, 93, 91, 94, 103, 67, 8, 36, 24, 10, 4,\n                                  13, 7, 2, 64, 9, 16, 41, 26, 20, 11, 31, 15,\n                                  17, 3, 29, 6, 35, 22, 17, 11, 23, 9, 3, 1, 0,\n                                  69, 49, 28, 10, 3, 18, 3, 71, 66, 15, 40, 34,\n                                  20, 9, 30, 12, 10, 3, 1, 62, 72, 64, 6, 4, 66,\n                                  4, 8, 11, 10, 15, 21, 32, 69, 64, 74, 73, 61,\n                                  79, 99, 73, 2, 2, 72, 71, 70, 74, 0, 76, 94,\n                                  69, 68, 21, 70, 77, 69, 68, 65, 72, 71, 70,\n                                  89, 81, 72, 75, 71, 22, 100, 76, 23, 82, 68,\n                                  69, 70, 4, 66, 71, 2, 9, 72, 72, 104, 34, 32,\n                                  33, 17, 1, 1, 64, 73, 65, 75, 79, 74, 91, 88,\n                                  91, 97, 94, 105, 126, 92, 85, 85, 86, 98, 92,\n                                  88, 90, 91, 79, 74, 78, 75, 81, 100, 87, 85,\n                                  107, 93, 105, 105, 123, 118, 114, 114, 76, 73,\n                                  114, 83, 83, 90, 106, 96, 97, 100, 89, 95, 85,\n                                  83, 105, 111, 123, 85, 97, 103, 70, 9, 14, 16,\n                                  33, 22, 28, 6, 31, 26, 36, 30, 39, 34, 23, 43,\n                                  65, 73, 81, 89, 89, 115, 115, 114, 15, 44, 39,\n                                  42, 32, 34, 20, 19, 10, 9, 70, 9, 14, 16, 33,\n                                  22, 28, 6, 31, 26, 36, 30, 39, 34, 23, 43, 65,\n                                  73, 81, 89, 89, 115, 115, 114 },\n\n                                {\n\n                                27,\n                                  4, 81, 27, 4, 81, 8, 18, 26, 12, 68, 90, 64,\n                                  28, 38, 9, 34, 82, 74, 23, 69, 72, 34, 92, 91,\n                                  2, 74, 126, 126, 126, 18, 3, 68, 74, 23, 69,\n                                  77, 11, 35, 65, 3, 64, 1, 105, 109, 94, 111,\n                                  65, 72, 72, 75, 90, 82, 98, 1, 68, 69, 66, 31,\n                                  1, 22, 0, 0, 0, 4, 96, 97, 9, 74, 69, 12, 64,\n                                  75, 29, 16, 4, 44, 42, 5, 16, 16, 23, 7, 7,\n                                  31, 108, 88, 89, 90, 24, 71, 16, 31, 66, 75,\n                                  1, 13, 65, 73, 72, 81, 23, 75, 13, 64, 75, 6,\n                                  69, 64, 7, 12, 15, 18, 7, 78, 67, 3, 65, 0,\n                                  71, 30, 66, 1, 30, 27, 37, 30, 26, 96, 9, 9,\n                                  75, 67, 77, 69, 30, 1, 4, 34, 53, 62, 62, 44,\n                                  98, 106, 10, 41, 42, 124, 72, 12, 97, 23, 69,\n                                  3, 34, 33, 54, 48, 43, 107, 65, 80, 94, 94,\n                                  70, 14, 21, 12, 6, 12, 11, 4, 16, 10, 76, 69,\n                                  6, 1, 0, 75, 64, 72, 77, 65, 66, 1, 70, 72,\n                                  106, 73, 75, 69, 84, 83, 71, 4, 68, 71, 69,\n                                  73, 89, 75, 65, 104, 121, 94, 102, 96, 126,\n                                  85, 79, 113, 64, 74, 74, 81, 85, 96, 91, 85,\n                                  103, 93, 91, 95, 104, 65, 10, 38, 25, 10, 4,\n                                  14, 8, 3, 0, 11, 17, 42, 27, 21, 12, 32, 16,\n                                  18, 4, 31, 7, 36, 23, 18, 11, 24, 10, 4, 2, 2,\n                                  68, 51, 29, 11, 3, 19, 4, 70, 65, 16, 41, 35,\n                                  21, 10, 31, 13, 11, 4, 2, 62, 70, 1, 8, 6, 65,\n                                  5, 10, 13, 12, 17, 23, 34, 68, 0, 73, 72, 62,\n                                  79, 100, 73, 3, 3, 71, 71, 70, 74, 0, 76, 95,\n                                  69, 68, 22, 70, 77, 69, 68, 65, 72, 71, 70,\n                                  89, 82, 72, 75, 70, 24, 100, 76, 24, 83, 68,\n                                  69, 70, 5, 66, 71, 3, 10, 71, 71, 106, 33, 31,\n                                  32, 15, 64, 65, 66, 76, 67, 77, 82, 76, 94,\n                                  91, 93, 101, 97, 108, 126, 95, 87, 86, 88,\n                                  100, 93, 89, 91, 92, 79, 76, 80, 77, 83, 102,\n                                  89, 86, 109, 95, 107, 107, 125, 120, 116, 115,\n                                  77, 74, 116, 84, 85, 91, 108, 97, 98, 101, 90,\n                                  95, 85, 82, 106, 112, 125, 86, 98, 104, 70,\n                                  10, 15, 17, 35, 23, 29, 6, 32, 27, 37, 31, 40,\n                                  35, 24, 42, 66, 75, 83, 91, 91, 117, 117, 115,\n                                  16, 44, 40, 43, 33, 35, 21, 20, 11, 10, 70,\n                                  10, 15, 17, 35, 23, 29, 6, 32, 27, 37, 31, 40,\n                                  35, 24, 42, 66, 75, 83, 91, 91, 117, 117, 115 },\n\n                                {\n\n                                26,\n                                  4, 81, 26, 4, 81, 10, 20, 26, 12, 69, 92, 65,\n                                  27, 39, 9, 35, 84, 74, 24, 70, 72, 35, 93, 92,\n                                  1, 76, 126, 126, 126, 20, 4, 68, 74, 24, 70,\n                                  77, 12, 35, 65, 3, 0, 3, 106, 110, 94, 111,\n                                  65, 71, 71, 76, 90, 82, 98, 1, 68, 69, 65, 32,\n                                  1, 22, 0, 0, 0, 4, 96, 97, 10, 75, 69, 11, 64,\n                                  74, 31, 17, 5, 45, 43, 6, 17, 18, 24, 8, 8,\n                                  34, 108, 89, 89, 91, 24, 71, 17, 34, 65, 75,\n                                  1, 15, 65, 73, 72, 81, 23, 75, 13, 0, 75, 7,\n                                  68, 64, 7, 12, 16, 18, 7, 79, 67, 3, 65, 0,\n                                  71, 30, 66, 1, 31, 27, 37, 30, 26, 97, 9, 9,\n                                  75, 67, 76, 69, 31, 2, 4, 36, 55, 62, 62, 46,\n                                  98, 107, 10, 42, 42, 125, 72, 13, 98, 24, 69,\n                                  3, 35, 33, 54, 48, 45, 108, 0, 81, 97, 97, 69,\n                                  14, 21, 11, 6, 11, 11, 3, 16, 9, 77, 70, 6, 1,\n                                  0, 75, 65, 72, 78, 66, 66, 1, 71, 72, 107, 74,\n                                  76, 69, 85, 84, 73, 2, 70, 73, 70, 75, 92, 78,\n                                  66, 106, 123, 96, 104, 98, 126, 86, 80, 114,\n                                  65, 75, 75, 83, 86, 98, 93, 86, 105, 93, 92,\n                                  96, 106, 64, 11, 39, 25, 10, 4, 15, 9, 4, 0,\n                                  13, 19, 43, 28, 21, 13, 34, 17, 20, 5, 34, 8,\n                                  36, 23, 18, 12, 25, 11, 4, 3, 3, 68, 52, 30,\n                                  11, 3, 20, 4, 70, 64, 17, 41, 36, 21, 10, 32,\n                                  14, 12, 4, 3, 62, 69, 2, 9, 7, 64, 7, 11, 15,\n                                  13, 19, 25, 37, 67, 1, 72, 71, 62, 78, 101,\n                                  72, 4, 4, 71, 71, 70, 74, 1, 77, 96, 69, 68,\n                                  23, 70, 77, 69, 68, 64, 73, 72, 70, 90, 83,\n                                  73, 75, 70, 25, 101, 77, 25, 83, 69, 69, 70,\n                                  5, 67, 72, 3, 10, 71, 71, 107, 32, 30, 31, 14,\n                                  67, 67, 69, 79, 70, 80, 85, 79, 97, 93, 95,\n                                  105, 101, 112, 126, 98, 89, 88, 90, 103, 95,\n                                  90, 92, 93, 79, 78, 83, 80, 85, 104, 91, 88,\n                                  111, 97, 109, 109, 126, 122, 117, 117, 78, 75,\n                                  118, 86, 86, 93, 110, 98, 99, 102, 91, 96, 85,\n                                  81, 108, 113, 126, 88, 99, 105, 70, 10, 15,\n                                  18, 36, 24, 29, 7, 33, 28, 38, 31, 41, 35, 24,\n                                  42, 68, 77, 85, 93, 93, 120, 119, 116, 16, 45,\n                                  40, 43, 34, 36, 21, 20, 11, 11, 70, 10, 15,\n                                  18, 36, 24, 29, 7, 33, 28, 38, 31, 41, 35, 24,\n                                  42, 68, 77, 85, 93, 93, 120, 119, 116 },\n\n                                {\n\n                                25,\n                                  4, 82, 25, 4, 82, 12, 21, 27, 12, 69, 93, 67,\n                                  26, 39, 10, 37, 85, 74, 26, 70, 73, 36, 94,\n                                  93, 0, 77, 126, 126, 126, 22, 6, 68, 74, 26,\n                                  70, 76, 13, 36, 65, 4, 1, 4, 108, 111, 94,\n                                  112, 65, 71, 71, 76, 91, 81, 98, 0, 68, 69,\n                                  64, 32, 1, 22, 0, 0, 0, 5, 96, 97, 10, 75, 70,\n                                  11, 0, 73, 33, 18, 6, 47, 45, 7, 18, 20, 25,\n                                  9, 8, 36, 109, 89, 89, 91, 25, 71, 18, 36, 65,\n                                  74, 2, 17, 65, 73, 72, 81, 24, 76, 14, 0, 75,\n                                  8, 68, 0, 7, 13, 17, 19, 7, 79, 67, 3, 65, 0,\n                                  71, 30, 66, 1, 31, 27, 38, 31, 27, 97, 10, 10,\n                                  76, 67, 76, 69, 32, 2, 5, 37, 56, 62, 62, 47,\n                                  99, 108, 11, 42, 42, 125, 73, 13, 98, 24, 70,\n                                  4, 36, 33, 54, 49, 46, 109, 1, 82, 100, 100,\n                                  67, 14, 21, 11, 5, 11, 10, 3, 15, 9, 77, 70,\n                                  6, 0, 0, 76, 65, 73, 79, 66, 66, 1, 71, 73,\n                                  109, 74, 77, 69, 86, 84, 76, 0, 72, 74, 72,\n                                  77, 95, 80, 68, 108, 125, 97, 106, 100, 126,\n                                  87, 82, 116, 67, 76, 76, 84, 88, 100, 95, 88,\n                                  106, 93, 93, 97, 107, 1, 13, 41, 26, 10, 4,\n                                  16, 9, 4, 1, 14, 20, 44, 29, 22, 13, 35, 18,\n                                  21, 6, 36, 8, 37, 24, 19, 12, 26, 11, 5, 4, 4,\n                                  68, 54, 31, 11, 3, 20, 5, 70, 64, 17, 42, 36,\n                                  22, 10, 33, 14, 12, 5, 3, 62, 67, 4, 11, 9, 1,\n                                  8, 13, 16, 15, 21, 27, 39, 67, 2, 72, 71, 62,\n                                  78, 102, 72, 4, 5, 71, 71, 70, 74, 1, 77, 97,\n                                  69, 68, 23, 70, 77, 69, 68, 64, 73, 72, 70,\n                                  91, 84, 73, 75, 70, 26, 102, 77, 26, 84, 69,\n                                  69, 70, 6, 67, 72, 4, 11, 71, 71, 109, 31, 29,\n                                  30, 12, 69, 70, 71, 82, 72, 83, 88, 82, 100,\n                                  96, 97, 108, 104, 116, 126, 100, 92, 90, 92,\n                                  105, 97, 91, 93, 94, 79, 80, 85, 82, 87, 106,\n                                  92, 89, 113, 99, 112, 111, 126, 124, 119, 118,\n                                  79, 77, 120, 87, 88, 94, 112, 100, 101, 103,\n                                  92, 97, 86, 80, 109, 115, 126, 89, 101, 106,\n                                  69, 11, 16, 18, 37, 25, 30, 7, 34, 29, 39, 32,\n                                  42, 36, 25, 41, 70, 79, 87, 95, 95, 122, 121,\n                                  117, 17, 45, 41, 44, 34, 37, 22, 21, 12, 11,\n                                  69, 11, 16, 18, 37, 25, 30, 7, 34, 29, 39, 32,\n                                  42, 36, 25, 41, 70, 79, 87, 95, 95, 122, 121,\n                                  117 },\n\n                                {\n\n                                23,\n                                  4, 82, 23, 4, 82, 13, 23, 27, 12, 70, 95, 68,\n                                  25, 40, 10, 39, 87, 74, 27, 70, 73, 37, 95,\n                                  95, 65, 79, 126, 126, 126, 24, 7, 68, 74, 27,\n                                  70, 76, 14, 36, 66, 5, 2, 5, 109, 113, 95,\n                                  112, 65, 71, 70, 76, 91, 81, 98, 0, 68, 69,\n                                  64, 33, 1, 22, 0, 0, 0, 5, 97, 97, 11, 76, 70,\n                                  10, 0, 72, 35, 19, 7, 48, 46, 7, 19, 22, 26,\n                                  10, 9, 38, 110, 89, 89, 91, 25, 72, 19, 38,\n                                  65, 73, 3, 19, 65, 73, 72, 81, 24, 76, 14, 1,\n                                  75, 8, 68, 0, 7, 13, 18, 19, 7, 79, 68, 3, 65,\n                                  0, 71, 30, 66, 1, 32, 27, 38, 31, 27, 98, 10,\n                                  11, 76, 67, 76, 69, 33, 2, 5, 38, 57, 62, 62,\n                                  49, 99, 109, 11, 42, 42, 126, 73, 14, 99, 25,\n                                  70, 4, 37, 33, 54, 49, 47, 110, 3, 83, 103,\n                                  103, 66, 13, 21, 10, 4, 10, 10, 2, 15, 8, 78,\n                                  71, 5, 0, 0, 76, 66, 74, 80, 67, 67, 0, 72,\n                                  73, 110, 75, 78, 69, 88, 85, 78, 65, 74, 76,\n                                  74, 79, 99, 83, 69, 110, 126, 99, 108, 102,\n                                  126, 89, 83, 118, 68, 77, 77, 85, 89, 102, 97,\n                                  90, 108, 93, 94, 98, 109, 2, 14, 42, 26, 10,\n                                  4, 17, 10, 5, 2, 16, 21, 45, 29, 23, 14, 36,\n                                  19, 23, 7, 38, 9, 37, 24, 19, 13, 27, 12, 5,\n                                  4, 5, 68, 55, 32, 11, 3, 21, 5, 70, 0, 18, 42,\n                                  37, 22, 10, 34, 15, 13, 5, 4, 62, 66, 5, 12,\n                                  11, 2, 10, 14, 18, 16, 22, 29, 41, 66, 3, 71,\n                                  70, 62, 78, 103, 72, 5, 5, 71, 71, 70, 75, 2,\n                                  77, 98, 69, 68, 24, 70, 77, 69, 68, 64, 74,\n                                  72, 70, 92, 85, 73, 75, 70, 27, 103, 77, 26,\n                                  85, 69, 69, 70, 6, 67, 73, 4, 12, 71, 71, 110,\n                                  30, 28, 29, 10, 71, 72, 74, 85, 75, 86, 92,\n                                  85, 104, 99, 99, 112, 108, 120, 126, 103, 94,\n                                  92, 94, 108, 99, 93, 94, 95, 79, 83, 87, 84,\n                                  89, 108, 94, 91, 115, 101, 114, 113, 126, 126,\n                                  121, 119, 80, 78, 123, 89, 90, 96, 114, 101,\n                                  102, 104, 93, 98, 86, 79, 110, 116, 126, 90,\n                                  102, 107, 69, 11, 16, 19, 38, 25, 31, 7, 35,\n                                  30, 40, 32, 43, 36, 26, 41, 72, 81, 89, 97,\n                                  97, 124, 123, 119, 17, 46, 41, 45, 35, 37, 22,\n                                  21, 12, 12, 69, 11, 16, 19, 38, 25, 31, 7, 35,\n                                  30, 40, 32, 43, 36, 26, 41, 72, 81, 89, 97,\n                                  97, 124, 123, 119 },\n\n                                {\n\n                                22,\n                                  4, 82, 22, 4, 82, 15, 24, 27, 12, 70, 97, 70,\n                                  24, 41, 10, 40, 89, 73, 29, 71, 73, 38, 96,\n                                  96, 66, 81, 126, 126, 126, 26, 8, 68, 73, 29,\n                                  71, 76, 15, 36, 66, 5, 3, 7, 110, 114, 95,\n                                  112, 65, 70, 69, 77, 91, 81, 98, 0, 67, 69, 0,\n                                  33, 1, 22, 0, 0, 0, 6, 97, 97, 11, 77, 70, 10,\n                                  1, 70, 38, 20, 8, 50, 48, 8, 20, 24, 27, 11,\n                                  10, 41, 110, 90, 89, 92, 25, 72, 20, 41, 64,\n                                  73, 3, 21, 65, 73, 72, 80, 24, 76, 15, 2, 74,\n                                  9, 67, 0, 8, 14, 19, 20, 7, 80, 68, 4, 65, 0,\n                                  71, 31, 66, 1, 32, 28, 38, 31, 27, 98, 11, 11,\n                                  77, 67, 75, 69, 34, 3, 6, 40, 59, 62, 62, 51,\n                                  100, 110, 12, 43, 42, 126, 73, 14, 99, 26, 70,\n                                  4, 39, 33, 54, 49, 49, 111, 4, 84, 105, 106,\n                                  65, 13, 21, 10, 4, 10, 10, 2, 15, 8, 79, 72,\n                                  5, 0, 0, 76, 66, 74, 81, 67, 67, 0, 73, 74,\n                                  111, 76, 78, 69, 89, 85, 80, 67, 75, 77, 75,\n                                  81, 102, 85, 70, 112, 126, 100, 110, 104, 126,\n                                  90, 84, 119, 69, 78, 78, 87, 91, 104, 99, 91,\n                                  109, 93, 95, 99, 111, 4, 16, 43, 27, 10, 4,\n                                  18, 11, 6, 2, 18, 23, 46, 30, 23, 15, 38, 20,\n                                  24, 8, 41, 10, 38, 25, 20, 13, 28, 13, 6, 5,\n                                  6, 67, 56, 33, 11, 3, 22, 6, 69, 1, 19, 42,\n                                  38, 22, 10, 35, 16, 14, 6, 5, 62, 65, 7, 14,\n                                  12, 3, 11, 16, 20, 18, 24, 31, 44, 65, 4, 70,\n                                  69, 62, 77, 104, 71, 6, 6, 71, 71, 70, 75, 2,\n                                  78, 99, 69, 68, 25, 70, 77, 69, 68, 0, 74, 73,\n                                  70, 93, 86, 74, 75, 70, 28, 103, 78, 27, 85,\n                                  70, 69, 70, 6, 68, 73, 4, 12, 71, 71, 112, 29,\n                                  27, 28, 9, 74, 75, 77, 88, 77, 89, 95, 88,\n                                  107, 101, 101, 116, 111, 124, 126, 106, 96,\n                                  93, 96, 110, 101, 94, 95, 96, 79, 85, 90, 87,\n                                  91, 110, 96, 92, 117, 103, 116, 115, 126, 126,\n                                  122, 121, 81, 79, 125, 90, 91, 97, 116, 102,\n                                  103, 105, 94, 99, 86, 78, 112, 117, 126, 92,\n                                  103, 108, 69, 12, 17, 20, 39, 26, 31, 8, 36,\n                                  31, 41, 33, 44, 37, 26, 40, 74, 83, 91, 99,\n                                  99, 126, 125, 120, 18, 46, 42, 45, 36, 38, 23,\n                                  22, 12, 13, 69, 12, 17, 20, 39, 26, 31, 8, 36,\n                                  31, 41, 33, 44, 37, 26, 40, 74, 83, 91, 99,\n                                  99, 126, 125, 120 },\n\n                                {\n\n                                21,\n                                  4, 82, 21, 4, 82, 17, 26, 28, 12, 71, 99, 71,\n                                  23, 41, 10, 42, 90, 73, 30, 71, 74, 39, 97,\n                                  97, 67, 83, 126, 126, 126, 28, 10, 68, 73, 30,\n                                  71, 75, 16, 37, 66, 6, 4, 8, 111, 115, 95,\n                                  113, 65, 70, 68, 77, 92, 81, 98, 0, 67, 69, 1,\n                                  34, 1, 22, 0, 0, 0, 6, 97, 97, 12, 78, 70, 9,\n                                  1, 69, 40, 21, 9, 51, 49, 9, 21, 26, 28, 12,\n                                  11, 43, 111, 90, 89, 92, 26, 72, 21, 43, 64,\n                                  72, 4, 23, 65, 73, 72, 80, 25, 76, 15, 3, 74,\n                                  10, 67, 0, 8, 14, 20, 20, 7, 80, 68, 4, 65, 0,\n                                  71, 31, 66, 1, 33, 28, 39, 31, 28, 99, 11, 12,\n                                  77, 67, 75, 69, 35, 3, 6, 41, 60, 62, 62, 53,\n                                  100, 111, 12, 43, 42, 126, 73, 15, 100, 26,\n                                  70, 4, 40, 33, 54, 49, 50, 112, 6, 85, 108,\n                                  109, 0, 13, 21, 9, 3, 9, 9, 1, 15, 7, 80, 73,\n                                  5, 0, 0, 77, 67, 75, 82, 68, 67, 0, 74, 74,\n                                  112, 76, 79, 69, 90, 86, 82, 69, 77, 79, 77,\n                                  83, 105, 88, 71, 114, 126, 102, 112, 106, 126,\n                                  91, 85, 121, 70, 79, 79, 88, 92, 106, 101, 93,\n                                  111, 93, 96, 100, 112, 5, 17, 45, 27, 10, 4,\n                                  19, 12, 7, 3, 20, 24, 47, 31, 24, 15, 39, 21,\n                                  26, 9, 43, 10, 38, 25, 20, 14, 29, 13, 6, 6,\n                                  7, 67, 58, 34, 11, 3, 23, 6, 69, 2, 20, 43,\n                                  39, 23, 10, 36, 16, 15, 6, 5, 62, 0, 8, 15,\n                                  14, 4, 13, 17, 21, 19, 26, 33, 46, 65, 5, 70,\n                                  68, 62, 77, 105, 71, 7, 7, 71, 71, 70, 75, 3,\n                                  78, 100, 69, 68, 25, 70, 77, 69, 68, 0, 75,\n                                  73, 70, 94, 87, 74, 75, 70, 29, 104, 78, 28,\n                                  86, 70, 69, 70, 7, 68, 74, 5, 13, 71, 71, 113,\n                                  28, 26, 27, 7, 76, 77, 79, 91, 80, 92, 98, 91,\n                                  110, 104, 103, 120, 115, 126, 126, 109, 98,\n                                  95, 98, 113, 103, 95, 96, 97, 79, 87, 92, 89,\n                                  93, 112, 98, 94, 119, 105, 118, 117, 126, 126,\n                                  124, 122, 82, 80, 126, 92, 93, 99, 118, 104,\n                                  105, 106, 95, 100, 86, 77, 113, 119, 126, 93,\n                                  104, 109, 69, 12, 17, 20, 40, 27, 32, 8, 37,\n                                  32, 42, 33, 45, 37, 27, 40, 76, 85, 93, 101,\n                                  101, 126, 126, 121, 18, 47, 42, 46, 36, 39,\n                                  23, 22, 13, 13, 69, 12, 17, 20, 40, 27, 32, 8,\n                                  37, 32, 42, 33, 45, 37, 27, 40, 76, 85, 93,\n                                  101, 101, 126, 126, 121 },\n\n                                {\n\n                                20,\n                                  4, 82, 20, 4, 82, 19, 27, 28, 12, 71, 101, 73,\n                                  22, 42, 10, 44, 92, 73, 32, 71, 74, 40, 98,\n                                  98, 68, 85, 126, 126, 126, 30, 11, 68, 73, 32,\n                                  71, 75, 17, 37, 66, 7, 5, 9, 112, 116, 95,\n                                  113, 65, 70, 67, 77, 92, 81, 98, 0, 67, 69, 2,\n                                  34, 1, 22, 0, 0, 0, 7, 97, 97, 12, 79, 70, 9,\n                                  2, 68, 42, 22, 10, 53, 51, 10, 22, 28, 29, 13,\n                                  12, 45, 112, 90, 89, 92, 26, 72, 22, 45, 64,\n                                  71, 5, 25, 65, 73, 72, 80, 25, 76, 16, 4, 74,\n                                  11, 67, 0, 8, 15, 21, 21, 7, 80, 68, 4, 65, 0,\n                                  71, 31, 66, 1, 33, 28, 39, 31, 28, 99, 12, 13,\n                                  78, 67, 75, 69, 36, 3, 7, 42, 61, 62, 62, 55,\n                                  101, 112, 13, 43, 42, 126, 73, 15, 100, 27,\n                                  70, 4, 41, 33, 54, 49, 51, 113, 7, 86, 111,\n                                  112, 1, 13, 21, 9, 2, 9, 9, 1, 15, 7, 81, 74,\n                                  5, 0, 0, 77, 67, 76, 83, 68, 67, 0, 75, 75,\n                                  113, 77, 80, 69, 91, 86, 84, 71, 79, 80, 79,\n                                  85, 108, 90, 72, 116, 126, 103, 114, 108, 126,\n                                  92, 86, 123, 71, 80, 80, 89, 94, 108, 103, 95,\n                                  112, 93, 97, 101, 114, 7, 19, 46, 28, 10, 4,\n                                  20, 13, 8, 4, 22, 25, 48, 32, 25, 16, 40, 22,\n                                  27, 10, 45, 11, 39, 26, 21, 14, 30, 14, 7, 7,\n                                  8, 67, 59, 35, 11, 3, 24, 7, 69, 3, 21, 43,\n                                  40, 23, 10, 37, 17, 16, 7, 6, 62, 1, 10, 17,\n                                  16, 5, 14, 19, 23, 21, 28, 35, 48, 64, 6, 69,\n                                  67, 62, 77, 106, 71, 8, 8, 71, 71, 70, 75, 3,\n                                  78, 101, 69, 68, 26, 70, 77, 69, 68, 0, 75,\n                                  73, 70, 95, 88, 74, 75, 70, 30, 105, 78, 29,\n                                  87, 70, 69, 70, 7, 68, 74, 5, 14, 71, 71, 115,\n                                  27, 25, 26, 5, 78, 80, 82, 94, 82, 95, 101,\n                                  94, 113, 107, 105, 124, 118, 126, 126, 112,\n                                  100, 97, 100, 115, 105, 96, 97, 98, 79, 89,\n                                  94, 91, 95, 114, 100, 95, 121, 107, 120, 119,\n                                  126, 126, 126, 123, 83, 81, 126, 93, 95, 100,\n                                  120, 105, 106, 107, 96, 101, 86, 76, 114, 120,\n                                  126, 94, 105, 110, 69, 13, 18, 21, 41, 28, 33,\n                                  8, 38, 33, 43, 34, 46, 38, 28, 39, 78, 87, 95,\n                                  103, 103, 126, 126, 122, 19, 47, 43, 47, 37,\n                                  40, 24, 23, 13, 14, 69, 13, 18, 21, 41, 28,\n                                  33, 8, 38, 33, 43, 34, 46, 38, 28, 39, 78, 87,\n                                  95, 103, 103, 126, 126, 122 },\n\n                                {\n\n                                18,\n                                  3, 83, 18, 3, 83, 20, 28, 28, 12, 72, 103, 75,\n                                  21, 42, 10, 45, 94, 73, 33, 72, 75, 41, 99,\n                                  100, 70, 87, 126, 126, 126, 32, 12, 68, 73,\n                                  33, 72, 75, 17, 37, 67, 7, 5, 10, 114, 118,\n                                  96, 114, 66, 70, 67, 78, 93, 81, 98, 64, 67,\n                                  69, 2, 34, 0, 22, 0, 0, 0, 7, 98, 97, 12, 80,\n                                  71, 8, 2, 67, 44, 23, 10, 54, 52, 10, 23, 29,\n                                  29, 14, 12, 47, 113, 91, 90, 93, 26, 73, 22,\n                                  47, 64, 71, 5, 26, 65, 73, 72, 80, 25, 77, 16,\n                                  4, 74, 11, 67, 0, 8, 15, 22, 21, 7, 81, 69, 4,\n                                  65, 64, 71, 31, 66, 1, 33, 28, 39, 31, 28,\n                                  100, 12, 13, 79, 67, 75, 70, 36, 3, 7, 43, 62,\n                                  62, 62, 56, 102, 114, 13, 43, 42, 126, 74, 15,\n                                  101, 27, 71, 4, 42, 33, 53, 49, 52, 114, 8,\n                                  88, 114, 116, 2, 12, 21, 8, 1, 8, 8, 0, 14, 6,\n                                  82, 75, 4, 64, 64, 78, 68, 77, 84, 69, 68, 64,\n                                  76, 76, 115, 78, 81, 69, 93, 87, 87, 74, 81,\n                                  82, 81, 88, 112, 93, 74, 118, 126, 105, 117,\n                                  110, 126, 94, 88, 125, 73, 81, 81, 91, 96,\n                                  110, 105, 97, 114, 93, 98, 102, 116, 8, 20,\n                                  47, 28, 10, 4, 20, 13, 8, 4, 23, 26, 48, 32,\n                                  25, 16, 41, 23, 28, 10, 47, 11, 39, 26, 21,\n                                  14, 30, 14, 7, 7, 9, 67, 60, 36, 11, 2, 24, 7,\n                                  69, 3, 21, 43, 40, 23, 10, 38, 17, 16, 7, 6,\n                                  62, 2, 11, 18, 17, 6, 15, 20, 24, 22, 29, 36,\n                                  50, 64, 6, 69, 67, 62, 77, 108, 71, 8, 8, 71,\n                                  71, 70, 76, 3, 79, 102, 70, 68, 26, 71, 77,\n                                  70, 68, 0, 76, 74, 71, 96, 89, 75, 76, 70, 31,\n                                  106, 79, 29, 88, 71, 69, 71, 7, 69, 75, 5, 14,\n                                  71, 71, 117, 25, 24, 24, 3, 81, 83, 85, 97,\n                                  85, 98, 105, 97, 117, 110, 107, 126, 122, 126,\n                                  126, 115, 103, 99, 103, 118, 107, 98, 99, 99,\n                                  79, 92, 97, 94, 97, 117, 102, 97, 124, 109,\n                                  123, 121, 126, 126, 126, 125, 85, 83, 126, 95,\n                                  97, 102, 122, 107, 108, 108, 97, 102, 87, 75,\n                                  116, 122, 126, 96, 107, 112, 69, 13, 18, 21,\n                                  42, 28, 33, 8, 39, 33, 44, 34, 46, 38, 28, 38,\n                                  80, 89, 98, 106, 105, 126, 126, 124, 19, 47,\n                                  43, 47, 37, 40, 24, 23, 13, 14, 69, 13, 18,\n                                  21, 42, 28, 33, 8, 39, 33, 44, 34, 46, 38, 28,\n                                  38, 80, 89, 98, 106, 105, 126, 126, 124 },\n\n                                {\n\n                                17,\n                                  3, 83, 17, 3, 83, 22, 30, 29, 13, 72, 104, 76,\n                                  21, 43, 11, 47, 95, 72, 35, 72, 75, 43, 99,\n                                  101, 71, 88, 126, 126, 126, 34, 14, 67, 72,\n                                  35, 72, 74, 18, 38, 67, 8, 6, 12, 115, 119,\n                                  96, 114, 66, 69, 66, 78, 93, 80, 97, 64, 66,\n                                  68, 3, 35, 0, 22, 0, 0, 0, 8, 98, 97, 13, 80,\n                                  71, 8, 3, 65, 47, 25, 11, 56, 54, 11, 25, 31,\n                                  30, 16, 13, 50, 113, 91, 90, 93, 27, 73, 23,\n                                  50, 0, 70, 6, 28, 65, 72, 72, 79, 26, 77, 17,\n                                  5, 73, 12, 66, 1, 9, 16, 23, 22, 8, 81, 69, 5,\n                                  64, 64, 70, 32, 65, 1, 34, 29, 40, 32, 29,\n                                  100, 13, 14, 79, 67, 74, 70, 37, 4, 8, 45, 62,\n                                  62, 62, 58, 102, 115, 14, 44, 43, 126, 74, 16,\n                                  101, 28, 71, 5, 44, 33, 53, 50, 54, 115, 10,\n                                  89, 116, 119, 4, 12, 21, 8, 1, 8, 8, 0, 14, 6,\n                                  82, 75, 4, 64, 64, 78, 68, 77, 84, 69, 68, 64,\n                                  76, 76, 116, 78, 81, 69, 94, 87, 89, 76, 82,\n                                  83, 82, 90, 115, 95, 75, 119, 126, 106, 119,\n                                  111, 126, 95, 89, 126, 74, 81, 81, 92, 97,\n                                  111, 106, 98, 115, 93, 98, 102, 117, 10, 22,\n                                  49, 29, 10, 4, 21, 14, 9, 5, 25, 28, 49, 33,\n                                  26, 17, 43, 24, 30, 11, 50, 12, 40, 27, 22,\n                                  15, 31, 15, 8, 8, 11, 66, 62, 37, 12, 2, 25,\n                                  8, 68, 4, 22, 44, 41, 24, 11, 39, 18, 17, 8,\n                                  7, 62, 4, 13, 20, 19, 8, 17, 22, 26, 24, 31,\n                                  38, 53, 0, 7, 68, 66, 62, 76, 109, 70, 9, 9,\n                                  70, 71, 69, 76, 4, 79, 102, 70, 68, 27, 71,\n                                  77, 70, 68, 1, 76, 74, 71, 96, 89, 75, 76, 69,\n                                  33, 106, 79, 30, 88, 71, 69, 71, 8, 69, 75, 6,\n                                  15, 70, 70, 118, 24, 23, 23, 2, 83, 85, 87,\n                                  100, 87, 100, 108, 99, 120, 112, 109, 126,\n                                  125, 126, 126, 117, 105, 100, 105, 120, 108,\n                                  99, 100, 99, 79, 94, 99, 96, 99, 119, 103, 98,\n                                  126, 110, 125, 122, 126, 126, 126, 126, 86,\n                                  84, 126, 96, 98, 103, 123, 108, 109, 109, 97,\n                                  102, 87, 74, 117, 123, 126, 97, 108, 113, 68,\n                                  14, 19, 22, 44, 29, 34, 9, 41, 34, 45, 35, 47,\n                                  39, 29, 38, 81, 90, 100, 108, 106, 126, 126,\n                                  125, 20, 48, 44, 48, 38, 41, 25, 24, 14, 15,\n                                  68, 14, 19, 22, 44, 29, 34, 9, 41, 34, 45, 35,\n                                  47, 39, 29, 38, 81, 90, 100, 108, 106, 126,\n                                  126, 125 },\n\n                                {\n\n                                16,\n                                  3, 83, 16, 3, 83, 24, 31, 29, 13, 72, 106, 78,\n                                  20, 44, 11, 49, 97, 72, 36, 72, 75, 44, 100,\n                                  102, 72, 90, 126, 126, 126, 36, 15, 67, 72,\n                                  36, 72, 74, 19, 38, 67, 9, 7, 13, 116, 120,\n                                  96, 114, 66, 69, 65, 78, 93, 80, 97, 64, 66,\n                                  68, 4, 35, 0, 22, 0, 0, 0, 9, 98, 97, 13, 81,\n                                  71, 8, 4, 64, 49, 26, 12, 58, 56, 12, 26, 33,\n                                  31, 17, 14, 52, 114, 91, 90, 93, 27, 73, 24,\n                                  52, 0, 69, 7, 30, 65, 72, 72, 79, 26, 77, 17,\n                                  6, 73, 13, 66, 1, 9, 16, 24, 23, 8, 81, 69, 5,\n                                  64, 64, 70, 32, 65, 1, 34, 29, 40, 32, 29,\n                                  101, 14, 15, 80, 67, 74, 70, 38, 4, 8, 46, 62,\n                                  62, 62, 60, 103, 116, 14, 44, 43, 126, 74, 16,\n                                  102, 29, 71, 5, 45, 33, 53, 50, 55, 116, 11,\n                                  90, 119, 122, 5, 12, 21, 8, 0, 7, 8, 0, 14, 5,\n                                  83, 76, 4, 64, 64, 78, 69, 78, 85, 69, 68, 64,\n                                  77, 77, 117, 79, 82, 69, 95, 88, 91, 78, 84,\n                                  85, 84, 92, 118, 97, 76, 121, 126, 108, 121,\n                                  113, 126, 96, 90, 126, 75, 82, 82, 93, 99,\n                                  113, 108, 100, 117, 93, 99, 103, 119, 11, 23,\n                                  50, 30, 10, 4, 22, 15, 10, 6, 27, 29, 50, 34,\n                                  27, 18, 44, 25, 31, 12, 52, 13, 40, 27, 22,\n                                  15, 32, 16, 9, 9, 12, 66, 62, 38, 12, 2, 26,\n                                  9, 68, 5, 23, 44, 42, 24, 11, 40, 19, 18, 9,\n                                  8, 62, 5, 15, 22, 21, 9, 18, 24, 28, 25, 33,\n                                  40, 55, 1, 8, 67, 65, 62, 76, 110, 70, 10, 10,\n                                  70, 71, 69, 76, 4, 79, 103, 70, 68, 28, 71,\n                                  77, 70, 68, 1, 76, 74, 71, 97, 90, 75, 76, 69,\n                                  34, 107, 79, 31, 89, 71, 69, 71, 8, 69, 75, 6,\n                                  16, 70, 70, 120, 23, 22, 22, 0, 85, 88, 90,\n                                  103, 89, 103, 111, 102, 123, 115, 111, 126,\n                                  126, 126, 126, 120, 107, 102, 107, 122, 110,\n                                  100, 101, 100, 79, 96, 101, 98, 101, 121, 105,\n                                  100, 126, 112, 126, 124, 126, 126, 126, 126,\n                                  87, 85, 126, 98, 100, 105, 125, 109, 110, 110,\n                                  98, 103, 87, 73, 118, 124, 126, 98, 109, 114,\n                                  68, 14, 20, 23, 45, 30, 35, 9, 42, 35, 46, 35,\n                                  48, 40, 30, 37, 83, 92, 102, 110, 108, 126,\n                                  126, 126, 21, 48, 44, 49, 39, 42, 25, 25, 14,\n                                  16, 68, 14, 20, 23, 45, 30, 35, 9, 42, 35, 46,\n                                  35, 48, 40, 30, 37, 83, 92, 102, 110, 108,\n                                  126, 126, 126 },\n\n                                {\n\n                                15,\n                                  3, 83, 15, 3, 83, 26, 33, 30, 13, 73, 108, 79,\n                                  19, 44, 11, 51, 98, 72, 38, 72, 76, 45, 101,\n                                  103, 73, 92, 126, 126, 126, 38, 17, 67, 72,\n                                  38, 72, 73, 20, 39, 67, 10, 8, 14, 117, 121,\n                                  96, 115, 66, 69, 64, 78, 94, 80, 97, 64, 66,\n                                  68, 5, 36, 0, 22, 0, 0, 0, 9, 98, 97, 14, 82,\n                                  71, 7, 4, 0, 51, 27, 13, 59, 57, 13, 27, 35,\n                                  32, 18, 15, 54, 115, 91, 90, 93, 28, 73, 25,\n                                  54, 0, 68, 8, 32, 65, 72, 72, 79, 27, 77, 18,\n                                  7, 73, 14, 66, 1, 9, 17, 25, 23, 8, 81, 69, 5,\n                                  64, 64, 70, 32, 65, 1, 35, 29, 41, 32, 30,\n                                  101, 14, 16, 80, 67, 74, 70, 39, 4, 9, 47, 62,\n                                  62, 62, 62, 103, 117, 15, 44, 43, 126, 74, 17,\n                                  102, 29, 71, 5, 46, 33, 53, 50, 56, 117, 13,\n                                  91, 122, 125, 7, 12, 21, 7, 64, 7, 7, 64, 14,\n                                  5, 84, 77, 4, 64, 64, 79, 69, 79, 86, 70, 68,\n                                  64, 78, 77, 118, 79, 83, 69, 96, 88, 93, 80,\n                                  86, 86, 86, 94, 121, 100, 77, 123, 126, 109,\n                                  123, 115, 126, 97, 91, 126, 76, 83, 83, 94,\n                                  100, 115, 110, 102, 118, 93, 100, 104, 120,\n                                  13, 25, 52, 30, 10, 4, 23, 16, 11, 7, 29, 30,\n                                  51, 35, 28, 18, 45, 26, 33, 13, 54, 13, 41,\n                                  28, 23, 16, 33, 16, 9, 10, 13, 66, 62, 39, 12,\n                                  2, 27, 9, 68, 6, 24, 45, 43, 25, 11, 41, 19,\n                                  19, 9, 8, 62, 7, 16, 23, 23, 10, 20, 25, 29,\n                                  27, 35, 42, 57, 1, 9, 67, 64, 62, 76, 111, 70,\n                                  11, 11, 70, 71, 69, 76, 5, 79, 104, 70, 68,\n                                  28, 71, 77, 70, 68, 1, 77, 74, 71, 98, 91, 75,\n                                  76, 69, 35, 108, 79, 32, 90, 71, 69, 71, 9,\n                                  69, 76, 7, 17, 70, 70, 121, 22, 21, 21, 65,\n                                  87, 90, 92, 106, 92, 106, 114, 105, 126, 118,\n                                  113, 126, 126, 126, 126, 123, 109, 104, 109,\n                                  125, 112, 101, 102, 101, 79, 98, 103, 100,\n                                  103, 123, 107, 101, 126, 114, 126, 126, 126,\n                                  126, 126, 126, 88, 86, 126, 99, 102, 106, 126,\n                                  111, 112, 111, 99, 104, 87, 72, 119, 126, 126,\n                                  99, 110, 115, 68, 15, 20, 23, 46, 31, 36, 9,\n                                  43, 36, 47, 36, 49, 40, 31, 37, 85, 94, 104,\n                                  112, 110, 126, 126, 126, 21, 49, 45, 50, 39,\n                                  43, 26, 25, 15, 16, 68, 15, 20, 23, 46, 31,\n                                  36, 9, 43, 36, 47, 36, 49, 40, 31, 37, 85, 94,\n                                  104, 112, 110, 126, 126, 126 },\n\n                          },\n\n                          {\n\n                              {\n\n                              62,\n                                9, 74, 62, 9, 74, 126, 104, 10, 9, 12, 30, 61,\n                                62, 54, 14, 118, 6, 78, 65, 1, 14, 73, 13, 64,\n                                20, 62, 67, 90, 104, 126, 104, 67, 78, 65, 1,\n                                86, 95, 2, 18, 69, 81, 96, 8, 67, 86, 88, 5, 76,\n                                94, 9, 69, 81, 88, 67, 74, 74, 80, 72, 5, 22, 0,\n                                0, 0, 83, 86, 97, 72, 22, 1, 52, 8, 69, 126,\n                                102, 82, 74, 107, 126, 126, 126, 95, 126, 114,\n                                126, 123, 115, 122, 115, 0, 68, 84, 104, 70, 93,\n                                90, 126, 74, 97, 91, 126, 7, 82, 76, 125, 93,\n                                87, 77, 71, 0, 68, 84, 1, 65, 2, 7, 66, 64, 2,\n                                78, 13, 11, 28, 19, 25, 18, 17, 19, 46, 12, 13,\n                                44, 30, 1, 108, 100, 101, 91, 94, 88, 84, 86,\n                                83, 87, 94, 70, 72, 74, 4, 102, 100, 95, 75, 72,\n                                75, 71, 17, 69, 1, 65, 26, 72, 6, 9, 1, 72, 62,\n                                54, 38, 45, 54, 44, 26, 45, 34, 30, 33, 18, 5,\n                                1, 2, 25, 18, 24, 21, 19, 18, 22, 14, 29, 21, 8,\n                                12, 17, 89, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 62, 62, 62, 46, 62, 60, 41, 62, 62, 62,\n                                62, 60, 58, 62, 47, 41, 15, 26, 3, 68, 97, 71,\n                                21, 13, 9, 1, 5, 0, 72, 74, 91, 67, 36, 24, 19,\n                                17, 64, 68, 78, 77, 86, 92, 8, 3, 1, 65, 73, 76,\n                                80, 88, 110, 97, 84, 79, 73, 74, 86, 96, 97,\n                                117, 78, 30, 15, 10, 1, 71, 79, 86, 90, 97, 62,\n                                93, 84, 79, 66, 71, 1, 3, 4, 75, 1, 5, 66, 79,\n                                71, 68, 19, 1, 27, 23, 36, 34, 19, 27, 31, 21,\n                                15, 1, 17, 64, 104, 97, 96, 88, 85, 85, 85, 88,\n                                66, 77, 76, 76, 5, 76, 83, 99, 95, 95, 76, 74,\n                                70, 75, 68, 65, 73, 1, 1, 68, 75, 8, 64, 70, 57,\n                                44, 47, 49, 50, 52, 48, 47, 40, 40, 43, 37, 19,\n                                23, 16, 46, 42, 41, 36, 34, 28, 13, 6, 0, 77,\n                                82, 94, 69, 109, 62, 62, 62, 62, 62, 62, 62, 62,\n                                62, 62, 62, 61, 50, 28, 5, 62, 62, 33, 62, 62,\n                                62, 60, 62, 58, 52, 58, 51, 52, 34, 37, 24, 66,\n                                42, 32, 13, 120, 112, 114, 85, 92, 89, 71, 81,\n                                80, 68, 70, 7, 68, 13, 74, 62, 62, 62, 62, 60,\n                                57, 29, 9, 82, 75, 40, 29, 20, 9, 8, 2, 64, 68,\n                                92, 106, 97, 90, 90, 88, 73, 79, 86, 73, 70, 69,\n                                66, 64, 5, 4, 62, 62, 62, 62, 60, 54, 43, 27, 67 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 125, 102, 11, 10, 12, 29,\n                                  60, 62, 54, 14, 115, 6, 77, 64, 1, 14, 72, 12,\n                                  65, 20, 62, 68, 91, 104, 124, 102, 67, 77, 64,\n                                  1, 85, 93, 3, 18, 68, 80, 95, 8, 67, 85, 88,\n                                  5, 75, 93, 9, 69, 80, 88, 66, 73, 73, 79, 71,\n                                  5, 22, 0, 0, 0, 82, 86, 97, 71, 22, 1, 52, 8,\n                                  69, 125, 101, 82, 73, 105, 125, 125, 125, 93,\n                                  125, 112, 125, 121, 114, 121, 114, 1, 67, 83,\n                                  103, 69, 92, 89, 125, 73, 96, 90, 125, 8, 81,\n                                  75, 123, 92, 86, 76, 70, 1, 67, 83, 2, 64, 2,\n                                  7, 65, 64, 2, 77, 13, 11, 28, 19, 25, 18, 17,\n                                  19, 45, 12, 13, 43, 29, 1, 107, 99, 100, 90,\n                                  93, 87, 83, 85, 82, 86, 92, 70, 72, 73, 3,\n                                  101, 99, 95, 74, 72, 74, 70, 17, 68, 1, 65,\n                                  25, 71, 6, 8, 1, 72, 62, 54, 38, 45, 54, 44,\n                                  26, 45, 34, 29, 33, 18, 5, 1, 2, 25, 18, 24,\n                                  21, 19, 17, 22, 14, 28, 20, 8, 11, 16, 89, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 60, 44, 62, 59, 40, 62, 62, 62, 62, 58,\n                                  56, 61, 45, 39, 15, 25, 2, 68, 97, 70, 22, 14,\n                                  10, 2, 5, 0, 71, 73, 90, 66, 37, 25, 20, 17,\n                                  0, 67, 77, 76, 85, 91, 9, 4, 2, 64, 72, 75,\n                                  79, 87, 108, 96, 82, 78, 72, 73, 85, 95, 96,\n                                  115, 77, 31, 16, 11, 2, 70, 78, 85, 89, 96,\n                                  62, 92, 83, 78, 66, 70, 1, 4, 5, 74, 2, 6, 65,\n                                  78, 71, 68, 19, 2, 27, 23, 35, 34, 19, 26, 30,\n                                  21, 15, 1, 16, 64, 103, 96, 95, 87, 84, 84,\n                                  84, 87, 66, 76, 75, 75, 5, 75, 82, 98, 94, 95,\n                                  76, 73, 70, 74, 68, 65, 72, 1, 1, 67, 74, 8,\n                                  64, 70, 57, 44, 47, 49, 49, 52, 48, 47, 40,\n                                  40, 43, 37, 19, 22, 15, 45, 41, 40, 35, 33,\n                                  27, 13, 6, 0, 76, 81, 93, 69, 108, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 61, 59, 48, 27, 5,\n                                  62, 62, 32, 62, 62, 62, 58, 62, 56, 50, 56,\n                                  49, 50, 33, 35, 23, 67, 41, 31, 12, 118, 110,\n                                  112, 84, 91, 88, 69, 80, 79, 68, 69, 9, 66,\n                                  15, 73, 62, 62, 62, 62, 58, 55, 27, 7, 83, 74,\n                                  41, 29, 20, 9, 9, 2, 64, 68, 91, 105, 96, 89,\n                                  89, 86, 72, 78, 85, 72, 69, 68, 65, 0, 6, 4,\n                                  62, 62, 62, 62, 59, 53, 41, 26, 67 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 123, 101, 11, 10, 12, 28,\n                                  59, 61, 54, 14, 113, 6, 76, 0, 1, 13, 72, 11,\n                                  66, 19, 60, 70, 92, 105, 121, 101, 67, 76, 0,\n                                  1, 85, 92, 3, 17, 68, 80, 94, 8, 67, 85, 88,\n                                  5, 75, 92, 9, 69, 80, 88, 66, 73, 73, 79, 71,\n                                  5, 22, 0, 0, 0, 81, 86, 97, 71, 21, 1, 52, 8,\n                                  69, 124, 100, 82, 73, 104, 123, 123, 124, 92,\n                                  123, 111, 123, 120, 113, 120, 113, 2, 67, 82,\n                                  102, 69, 92, 88, 123, 73, 96, 90, 124, 8, 81,\n                                  75, 122, 92, 85, 76, 70, 1, 67, 82, 2, 64, 1,\n                                  7, 65, 64, 2, 77, 13, 11, 27, 19, 24, 18, 17,\n                                  19, 43, 12, 13, 41, 28, 0, 106, 98, 99, 89,\n                                  92, 86, 82, 84, 82, 85, 91, 70, 72, 73, 2,\n                                  101, 98, 95, 74, 72, 73, 70, 16, 67, 1, 65,\n                                  24, 70, 5, 7, 1, 73, 60, 53, 37, 44, 53, 43,\n                                  25, 44, 34, 28, 32, 18, 5, 1, 2, 24, 17, 23,\n                                  20, 18, 16, 21, 13, 26, 19, 7, 10, 15, 89, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,\n                                  62, 58, 41, 62, 57, 38, 62, 62, 62, 62, 56,\n                                  54, 58, 43, 37, 14, 23, 1, 69, 97, 70, 22, 14,\n                                  10, 2, 5, 0, 71, 73, 89, 66, 37, 25, 20, 17,\n                                  1, 67, 76, 76, 84, 90, 10, 5, 2, 64, 71, 75,\n                                  79, 86, 107, 95, 81, 77, 72, 73, 84, 94, 95,\n                                  114, 77, 31, 16, 11, 2, 69, 77, 84, 88, 95,\n                                  62, 92, 83, 78, 66, 70, 1, 4, 5, 74, 2, 6, 64,\n                                  78, 71, 68, 18, 2, 26, 22, 34, 33, 19, 25, 29,\n                                  21, 15, 0, 15, 65, 102, 95, 94, 87, 84, 84,\n                                  83, 86, 66, 76, 75, 75, 4, 75, 82, 98, 93, 95,\n                                  76, 73, 70, 73, 68, 65, 71, 1, 1, 67, 73, 7,\n                                  64, 71, 56, 44, 47, 48, 48, 51, 47, 46, 39,\n                                  39, 42, 36, 18, 21, 14, 43, 40, 38, 33, 32,\n                                  26, 12, 5, 0, 76, 81, 93, 70, 107, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 59, 57, 46, 26, 4,\n                                  62, 60, 31, 62, 62, 62, 56, 60, 54, 48, 54,\n                                  47, 48, 31, 33, 21, 68, 39, 29, 10, 117, 109,\n                                  111, 83, 90, 87, 67, 79, 78, 68, 68, 10, 65,\n                                  16, 72, 62, 62, 62, 62, 55, 52, 24, 5, 84, 74,\n                                  41, 29, 20, 9, 9, 2, 64, 68, 90, 104, 95, 88,\n                                  88, 85, 71, 77, 84, 71, 68, 67, 65, 1, 6, 4,\n                                  62, 62, 62, 61, 57, 51, 39, 24, 68 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 121, 99, 12, 10, 11, 26, 57,\n                                  60, 54, 14, 111, 6, 75, 1, 1, 12, 72, 10, 67,\n                                  19, 58, 71, 93, 105, 118, 100, 67, 75, 1, 1,\n                                  84, 91, 4, 17, 68, 79, 93, 7, 68, 85, 88, 5,\n                                  75, 92, 9, 69, 80, 88, 65, 73, 73, 79, 70, 5,\n                                  22, 0, 0, 0, 81, 86, 97, 70, 20, 1, 52, 8, 69,\n                                  123, 99, 82, 72, 103, 121, 121, 122, 91, 121,\n                                  110, 121, 119, 112, 119, 112, 3, 67, 81, 101,\n                                  69, 91, 88, 121, 73, 95, 89, 123, 8, 81, 74,\n                                  120, 91, 84, 76, 70, 1, 67, 81, 3, 0, 1, 7,\n                                  65, 64, 2, 77, 13, 10, 27, 19, 23, 18, 17, 19,\n                                  41, 12, 12, 39, 27, 64, 105, 97, 98, 88, 91,\n                                  86, 81, 84, 81, 84, 90, 70, 72, 73, 1, 100,\n                                  97, 95, 74, 72, 72, 70, 15, 66, 1, 65, 23, 69,\n                                  5, 6, 1, 74, 59, 52, 37, 43, 52, 42, 25, 43,\n                                  33, 27, 31, 18, 5, 1, 1, 23, 16, 22, 19, 17,\n                                  15, 20, 13, 24, 18, 7, 9, 14, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 55,\n                                  39, 62, 55, 37, 62, 61, 62, 59, 54, 51, 56,\n                                  41, 34, 13, 21, 0, 70, 97, 70, 23, 14, 10, 2,\n                                  5, 0, 71, 73, 89, 66, 37, 25, 20, 17, 2, 66,\n                                  76, 75, 84, 89, 11, 5, 3, 64, 70, 74, 78, 86,\n                                  106, 94, 80, 76, 71, 73, 83, 93, 94, 113, 76,\n                                  31, 16, 11, 2, 68, 77, 83, 87, 94, 62, 91, 82,\n                                  77, 66, 70, 1, 4, 5, 74, 2, 6, 64, 78, 71, 68,\n                                  18, 3, 25, 21, 33, 32, 19, 24, 28, 21, 15, 0,\n                                  14, 65, 101, 94, 93, 86, 83, 83, 83, 85, 66,\n                                  76, 75, 74, 4, 75, 82, 97, 92, 95, 76, 73, 70,\n                                  72, 68, 65, 70, 1, 1, 67, 72, 6, 64, 72, 55,\n                                  43, 46, 47, 47, 50, 46, 45, 38, 38, 41, 35,\n                                  17, 20, 13, 42, 39, 37, 31, 30, 25, 11, 5, 64,\n                                  76, 81, 93, 70, 106, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 57, 54, 44, 24, 3, 61, 59, 29,\n                                  62, 62, 60, 54, 58, 52, 46, 52, 45, 45, 29,\n                                  31, 19, 69, 37, 27, 9, 116, 108, 110, 82, 89,\n                                  86, 66, 78, 77, 68, 67, 12, 0, 18, 71, 62, 62,\n                                  62, 62, 52, 49, 21, 3, 85, 74, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 90, 103, 94, 87, 87, 84, 71, 77,\n                                  83, 71, 68, 67, 65, 1, 6, 4, 62, 62, 62, 59,\n                                  55, 49, 37, 22, 69 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 120, 98, 12, 10, 11, 25, 56,\n                                  58, 54, 14, 108, 5, 74, 1, 1, 11, 72, 9, 68,\n                                  18, 56, 73, 94, 106, 115, 99, 67, 74, 1, 1,\n                                  84, 90, 4, 16, 68, 79, 93, 7, 68, 84, 88, 5,\n                                  75, 91, 8, 70, 80, 88, 65, 72, 73, 78, 70, 5,\n                                  22, 0, 0, 0, 80, 87, 97, 70, 19, 1, 52, 8, 69,\n                                  122, 98, 82, 72, 101, 120, 119, 121, 90, 120,\n                                  108, 119, 118, 112, 118, 112, 3, 67, 80, 100,\n                                  69, 91, 87, 119, 73, 95, 89, 122, 8, 80, 74,\n                                  119, 91, 84, 76, 69, 1, 67, 81, 3, 0, 0, 6,\n                                  65, 64, 2, 77, 13, 10, 26, 19, 23, 18, 17, 18,\n                                  39, 12, 12, 37, 26, 65, 104, 96, 97, 87, 91,\n                                  85, 80, 83, 81, 83, 89, 70, 72, 72, 0, 100,\n                                  96, 95, 74, 72, 72, 70, 14, 65, 1, 65, 21, 68,\n                                  4, 5, 1, 75, 57, 51, 36, 42, 51, 41, 24, 42,\n                                  33, 25, 30, 17, 5, 1, 1, 22, 16, 21, 19, 16,\n                                  14, 19, 12, 22, 17, 6, 8, 13, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 59, 53,\n                                  36, 62, 54, 35, 62, 59, 62, 57, 51, 49, 53,\n                                  39, 32, 12, 20, 65, 71, 97, 70, 23, 15, 10, 2,\n                                  5, 0, 71, 73, 88, 65, 38, 25, 20, 17, 3, 66,\n                                  75, 75, 83, 89, 12, 6, 3, 64, 70, 74, 78, 85,\n                                  105, 94, 79, 76, 71, 73, 82, 92, 94, 112, 76,\n                                  32, 16, 11, 2, 67, 76, 83, 86, 93, 62, 91, 82,\n                                  77, 66, 70, 1, 4, 5, 73, 2, 6, 0, 78, 71, 68,\n                                  17, 3, 24, 20, 32, 31, 19, 22, 27, 20, 15, 64,\n                                  13, 66, 101, 94, 92, 86, 83, 83, 82, 84, 67,\n                                  76, 75, 74, 3, 75, 82, 97, 91, 95, 76, 72, 70,\n                                  72, 68, 65, 69, 1, 0, 67, 71, 6, 65, 73, 54,\n                                  43, 46, 46, 46, 49, 45, 44, 37, 37, 40, 34,\n                                  16, 19, 12, 40, 37, 35, 29, 29, 24, 10, 4, 64,\n                                  76, 81, 93, 71, 106, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 60, 55, 52, 42, 23, 2, 59, 57, 28,\n                                  62, 62, 58, 52, 55, 50, 44, 50, 43, 43, 27,\n                                  29, 17, 70, 35, 25, 7, 115, 107, 109, 82, 88,\n                                  85, 64, 77, 76, 68, 66, 13, 1, 19, 71, 62, 62,\n                                  62, 62, 49, 46, 18, 1, 86, 74, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 89, 102, 93, 86, 87, 83, 70, 76,\n                                  82, 70, 67, 66, 64, 2, 7, 4, 62, 62, 62, 57,\n                                  53, 47, 35, 20, 70 },\n\n                                {\n\n                                62,\n                                  9, 74, 62, 9, 74, 118, 96, 12, 10, 10, 23, 54,\n                                  57, 54, 14, 106, 5, 73, 2, 1, 11, 71, 8, 69,\n                                  18, 54, 75, 95, 106, 112, 97, 67, 73, 2, 1,\n                                  84, 89, 4, 16, 68, 79, 92, 7, 69, 84, 88, 5,\n                                  75, 90, 8, 70, 80, 88, 64, 72, 72, 78, 69, 5,\n                                  22, 0, 0, 0, 80, 87, 97, 69, 18, 1, 52, 8, 69,\n                                  121, 97, 82, 71, 100, 118, 117, 119, 89, 118,\n                                  107, 117, 117, 111, 117, 111, 4, 67, 79, 99,\n                                  69, 90, 86, 117, 73, 95, 88, 120, 9, 80, 73,\n                                  118, 90, 83, 76, 69, 2, 66, 80, 4, 1, 0, 6,\n                                  65, 64, 2, 77, 13, 9, 25, 19, 22, 18, 17, 18,\n                                  37, 12, 11, 36, 25, 66, 103, 95, 96, 86, 90,\n                                  84, 79, 82, 80, 82, 88, 70, 72, 72, 64, 99,\n                                  95, 95, 73, 72, 71, 70, 13, 64, 1, 65, 20, 67,\n                                  4, 4, 1, 75, 56, 50, 36, 41, 50, 40, 23, 42,\n                                  33, 24, 29, 17, 5, 1, 0, 22, 15, 20, 18, 15,\n                                  13, 19, 11, 20, 16, 5, 7, 12, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 57, 51,\n                                  34, 60, 52, 33, 62, 57, 60, 55, 49, 47, 50,\n                                  37, 29, 11, 18, 66, 71, 97, 70, 23, 15, 10, 2,\n                                  5, 0, 71, 73, 88, 65, 38, 25, 20, 17, 4, 65,\n                                  74, 75, 82, 88, 13, 7, 3, 0, 69, 73, 77, 85,\n                                  104, 93, 77, 75, 71, 72, 81, 91, 93, 111, 75,\n                                  32, 17, 11, 2, 66, 75, 82, 85, 92, 62, 91, 82,\n                                  76, 66, 70, 1, 4, 5, 73, 2, 7, 0, 78, 71, 68,\n                                  16, 4, 23, 19, 31, 31, 19, 21, 26, 20, 15, 65,\n                                  12, 66, 100, 93, 91, 85, 82, 82, 82, 83, 67,\n                                  76, 75, 74, 2, 75, 82, 96, 90, 95, 76, 72, 70,\n                                  71, 68, 65, 68, 1, 0, 67, 70, 5, 65, 73, 53,\n                                  43, 45, 46, 45, 48, 44, 43, 37, 36, 39, 33,\n                                  15, 18, 11, 39, 36, 34, 27, 28, 23, 9, 3, 65,\n                                  76, 80, 93, 71, 105, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 60, 58, 53, 50, 40, 21, 1, 57, 55, 27,\n                                  61, 62, 56, 50, 53, 48, 42, 48, 41, 40, 25,\n                                  27, 15, 71, 33, 23, 6, 114, 105, 108, 81, 87,\n                                  84, 1, 76, 75, 68, 65, 15, 3, 21, 70, 62, 62,\n                                  62, 62, 47, 43, 16, 64, 87, 74, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 89, 101, 92, 85, 86, 82, 69, 76,\n                                  81, 69, 66, 65, 64, 2, 7, 4, 62, 62, 62, 56,\n                                  51, 45, 33, 18, 71 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 116, 95, 13, 10, 10, 22, 53,\n                                  56, 54, 14, 104, 5, 73, 3, 1, 10, 71, 7, 70,\n                                  17, 53, 76, 96, 107, 109, 96, 67, 73, 3, 1,\n                                  83, 88, 5, 15, 67, 78, 91, 6, 69, 84, 88, 5,\n                                  74, 90, 8, 70, 79, 88, 64, 72, 72, 78, 69, 5,\n                                  22, 0, 0, 0, 79, 87, 97, 69, 18, 0, 52, 8, 69,\n                                  120, 97, 82, 71, 99, 116, 115, 118, 88, 116,\n                                  106, 115, 116, 110, 116, 110, 5, 67, 78, 99,\n                                  68, 90, 86, 115, 73, 94, 88, 119, 9, 80, 73,\n                                  116, 90, 82, 75, 69, 2, 66, 79, 4, 1, 64, 6,\n                                  65, 64, 2, 77, 13, 9, 25, 19, 21, 18, 17, 18,\n                                  35, 12, 11, 34, 24, 67, 103, 94, 96, 86, 89,\n                                  84, 78, 82, 80, 82, 86, 70, 72, 72, 65, 99,\n                                  94, 95, 73, 72, 70, 69, 12, 64, 1, 65, 19, 66,\n                                  3, 3, 1, 76, 54, 49, 35, 41, 49, 40, 23, 41,\n                                  32, 23, 28, 17, 5, 1, 0, 21, 14, 19, 17, 15,\n                                  12, 18, 11, 18, 15, 5, 6, 11, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 62, 62, 54, 48,\n                                  31, 58, 50, 32, 62, 54, 57, 52, 47, 44, 48,\n                                  34, 27, 10, 16, 67, 72, 97, 69, 24, 15, 11, 2,\n                                  5, 0, 71, 73, 87, 65, 38, 26, 20, 17, 5, 65,\n                                  74, 74, 82, 87, 14, 7, 4, 0, 68, 73, 77, 84,\n                                  103, 92, 76, 74, 70, 72, 81, 91, 92, 109, 75,\n                                  32, 17, 11, 3, 66, 75, 81, 85, 91, 62, 90, 81,\n                                  76, 66, 70, 1, 4, 5, 73, 3, 7, 1, 78, 71, 69,\n                                  16, 4, 22, 18, 30, 30, 19, 20, 25, 20, 15, 65,\n                                  11, 67, 99, 92, 90, 85, 82, 82, 81, 83, 67,\n                                  75, 74, 73, 2, 75, 82, 96, 89, 95, 76, 72, 70,\n                                  70, 68, 65, 67, 0, 0, 67, 70, 4, 65, 74, 52,\n                                  42, 45, 45, 44, 48, 44, 42, 36, 36, 38, 32,\n                                  14, 17, 10, 37, 35, 32, 25, 26, 21, 8, 3, 65,\n                                  76, 80, 92, 72, 104, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 58, 55, 51, 47, 38, 20, 1, 56, 54, 25,\n                                  59, 62, 54, 48, 51, 46, 40, 45, 39, 38, 23,\n                                  25, 14, 73, 31, 21, 4, 113, 104, 107, 80, 86,\n                                  83, 2, 75, 74, 68, 64, 16, 4, 22, 69, 62, 62,\n                                  62, 59, 44, 41, 13, 66, 89, 73, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 88, 100, 92, 84, 85, 81, 69, 75,\n                                  80, 69, 66, 65, 64, 3, 7, 4, 62, 62, 61, 54,\n                                  50, 44, 30, 17, 72 },\n\n                                {\n\n                                62,\n                                  9, 75, 62, 9, 75, 114, 93, 13, 10, 9, 20, 51,\n                                  54, 54, 14, 101, 4, 72, 3, 1, 9, 71, 6, 71,\n                                  17, 51, 78, 97, 107, 106, 95, 67, 72, 3, 1,\n                                  83, 87, 5, 15, 67, 78, 91, 6, 70, 83, 88, 5,\n                                  74, 89, 7, 70, 79, 88, 0, 71, 72, 77, 68, 5,\n                                  22, 0, 0, 0, 79, 87, 97, 68, 17, 0, 52, 8, 69,\n                                  119, 96, 82, 70, 97, 115, 113, 116, 87, 115,\n                                  104, 113, 115, 109, 115, 110, 6, 67, 77, 98,\n                                  68, 89, 85, 113, 73, 94, 87, 118, 9, 79, 72,\n                                  115, 89, 82, 75, 68, 2, 66, 78, 5, 2, 64, 5,\n                                  65, 64, 2, 77, 13, 8, 24, 19, 21, 18, 17, 17,\n                                  33, 12, 10, 32, 23, 68, 102, 93, 95, 85, 88,\n                                  83, 77, 81, 79, 81, 85, 70, 72, 71, 66, 98,\n                                  93, 95, 73, 72, 70, 69, 11, 0, 1, 65, 17, 65,\n                                  3, 2, 1, 77, 53, 48, 35, 40, 48, 39, 22, 40,\n                                  32, 22, 27, 17, 5, 1, 64, 20, 14, 18, 17, 14,\n                                  11, 17, 10, 16, 14, 4, 5, 10, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 62, 60, 61, 52, 46,\n                                  29, 56, 49, 30, 62, 52, 55, 50, 44, 42, 45,\n                                  32, 24, 9, 15, 69, 73, 97, 69, 24, 16, 11, 2,\n                                  5, 0, 71, 73, 87, 64, 39, 26, 20, 17, 6, 64,\n                                  73, 74, 81, 86, 15, 8, 4, 0, 67, 72, 76, 84,\n                                  102, 92, 75, 74, 70, 72, 80, 90, 92, 108, 74,\n                                  33, 17, 11, 3, 65, 74, 80, 84, 90, 62, 90, 81,\n                                  75, 66, 70, 1, 4, 5, 72, 3, 7, 1, 78, 71, 69,\n                                  15, 5, 21, 17, 29, 29, 19, 19, 24, 19, 15, 66,\n                                  10, 67, 98, 92, 89, 84, 81, 81, 81, 82, 67,\n                                  75, 74, 73, 1, 75, 82, 95, 88, 95, 76, 71, 70,\n                                  70, 68, 65, 66, 0, 0, 67, 69, 4, 66, 75, 51,\n                                  42, 44, 44, 43, 47, 43, 41, 35, 35, 37, 31,\n                                  13, 16, 9, 36, 33, 31, 23, 25, 20, 7, 2, 66,\n                                  76, 80, 92, 72, 103, 62, 62, 62, 62, 62, 62,\n                                  62, 61, 56, 53, 49, 45, 36, 18, 0, 54, 52, 24,\n                                  57, 62, 52, 46, 49, 44, 38, 43, 37, 35, 21,\n                                  23, 12, 74, 29, 19, 3, 112, 103, 106, 80, 85,\n                                  82, 4, 74, 73, 68, 0, 18, 6, 24, 69, 62, 62,\n                                  61, 56, 41, 38, 10, 68, 90, 73, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 88, 99, 91, 83, 84, 80, 68, 75,\n                                  79, 68, 65, 64, 0, 3, 8, 4, 62, 62, 59, 52,\n                                  48, 42, 28, 15, 73 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 113, 92, 13, 10, 9, 19, 50,\n                                  53, 54, 14, 99, 4, 71, 4, 1, 8, 71, 5, 73, 16,\n                                  49, 80, 98, 108, 104, 94, 67, 71, 4, 1, 83,\n                                  86, 5, 14, 67, 78, 90, 5, 70, 83, 89, 5, 74,\n                                  89, 7, 71, 79, 88, 0, 71, 72, 77, 68, 5, 22,\n                                  0, 0, 0, 78, 88, 97, 68, 16, 0, 52, 8, 69,\n                                  118, 95, 82, 70, 96, 113, 111, 115, 86, 113,\n                                  103, 112, 114, 109, 114, 109, 6, 67, 76, 97,\n                                  68, 89, 85, 112, 73, 94, 87, 117, 9, 79, 72,\n                                  114, 89, 81, 75, 68, 2, 66, 78, 5, 2, 65, 5,\n                                  65, 64, 2, 77, 13, 8, 23, 19, 20, 18, 17, 17,\n                                  31, 12, 10, 30, 22, 69, 101, 92, 94, 84, 88,\n                                  83, 76, 81, 79, 80, 84, 70, 72, 71, 68, 98,\n                                  92, 95, 73, 73, 69, 69, 10, 1, 1, 65, 16, 64,\n                                  2, 1, 1, 78, 51, 47, 34, 39, 47, 38, 21, 39,\n                                  31, 20, 26, 16, 5, 1, 64, 19, 13, 17, 16, 13,\n                                  10, 16, 9, 14, 12, 3, 4, 9, 89, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 62, 61, 58, 58, 49, 43,\n                                  26, 54, 47, 28, 61, 50, 52, 47, 42, 39, 42,\n                                  30, 22, 8, 13, 70, 74, 98, 69, 24, 16, 11, 2,\n                                  5, 0, 71, 73, 86, 64, 39, 26, 20, 17, 7, 64,\n                                  73, 74, 81, 86, 16, 8, 4, 0, 67, 72, 76, 83,\n                                  101, 91, 74, 73, 70, 72, 79, 89, 91, 107, 74,\n                                  33, 17, 11, 3, 64, 74, 80, 83, 90, 62, 90, 81,\n                                  75, 66, 70, 1, 4, 5, 72, 3, 7, 2, 78, 71, 69,\n                                  14, 5, 20, 16, 28, 28, 19, 17, 22, 19, 15, 67,\n                                  9, 68, 98, 91, 88, 84, 81, 81, 80, 81, 68, 75,\n                                  74, 73, 0, 75, 82, 95, 88, 96, 76, 71, 70, 69,\n                                  68, 65, 66, 0, 64, 67, 68, 3, 66, 76, 50, 41,\n                                  44, 43, 41, 46, 42, 40, 34, 34, 36, 30, 12,\n                                  15, 8, 34, 32, 29, 21, 23, 19, 6, 1, 66, 76,\n                                  80, 92, 73, 103, 62, 62, 62, 62, 62, 62, 61,\n                                  58, 54, 51, 47, 42, 34, 17, 64, 52, 50, 22,\n                                  55, 61, 49, 43, 46, 41, 36, 41, 34, 33, 19,\n                                  20, 10, 75, 27, 17, 1, 111, 102, 105, 79, 84,\n                                  82, 5, 73, 73, 68, 0, 19, 7, 25, 68, 62, 62,\n                                  58, 53, 38, 35, 7, 70, 91, 73, 41, 29, 20, 9,\n                                  9, 2, 64, 68, 87, 99, 90, 82, 84, 79, 68, 74,\n                                  79, 68, 65, 64, 0, 4, 8, 3, 62, 62, 57, 50,\n                                  46, 40, 26, 13, 74 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 111, 91, 14, 10, 9, 18, 49,\n                                  52, 54, 14, 97, 4, 70, 5, 1, 8, 70, 4, 74, 15,\n                                  47, 81, 99, 109, 101, 92, 67, 70, 5, 1, 82,\n                                  85, 6, 13, 67, 77, 89, 5, 70, 83, 89, 5, 74,\n                                  88, 7, 71, 79, 88, 0, 71, 71, 77, 68, 5, 22,\n                                  0, 0, 0, 77, 88, 97, 68, 15, 0, 52, 8, 69,\n                                  117, 94, 82, 70, 95, 111, 109, 113, 84, 111,\n                                  102, 110, 113, 108, 113, 108, 7, 66, 75, 96,\n                                  68, 88, 84, 110, 73, 93, 87, 115, 10, 79, 72,\n                                  112, 89, 80, 75, 68, 3, 65, 77, 5, 2, 65, 5,\n                                  64, 64, 2, 76, 13, 8, 23, 19, 19, 18, 17, 17,\n                                  29, 12, 10, 29, 21, 69, 100, 91, 93, 83, 87,\n                                  82, 75, 80, 79, 79, 83, 70, 72, 71, 69, 97,\n                                  91, 95, 72, 73, 68, 69, 9, 2, 1, 65, 15, 0, 1,\n                                  0, 1, 78, 50, 46, 34, 38, 46, 37, 21, 39, 31,\n                                  19, 25, 16, 5, 1, 64, 19, 12, 16, 15, 12, 9,\n                                  16, 9, 13, 11, 3, 3, 8, 89, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 62, 59, 56, 56, 46, 41, 23,\n                                  53, 45, 27, 59, 48, 50, 45, 40, 37, 40, 28,\n                                  20, 8, 11, 71, 74, 98, 69, 25, 16, 11, 3, 5,\n                                  0, 70, 73, 85, 64, 39, 26, 21, 17, 8, 0, 72,\n                                  73, 80, 85, 17, 9, 5, 1, 66, 71, 76, 82, 100,\n                                  90, 72, 72, 69, 71, 78, 88, 90, 106, 73, 33,\n                                  18, 12, 3, 0, 73, 79, 82, 89, 62, 89, 80, 74,\n                                  66, 70, 1, 5, 6, 72, 3, 8, 3, 78, 71, 69, 14,\n                                  5, 19, 16, 27, 28, 19, 16, 21, 19, 15, 67, 8,\n                                  69, 97, 90, 87, 84, 80, 81, 79, 80, 68, 75,\n                                  74, 72, 0, 75, 82, 95, 87, 96, 76, 71, 70, 68,\n                                  68, 65, 65, 0, 64, 67, 67, 2, 66, 76, 49, 41,\n                                  44, 43, 40, 45, 41, 39, 34, 33, 35, 30, 12,\n                                  14, 7, 33, 31, 27, 19, 22, 18, 6, 1, 66, 75,\n                                  79, 92, 74, 102, 62, 62, 62, 62, 62, 62, 59,\n                                  56, 52, 49, 45, 40, 32, 16, 65, 50, 49, 21,\n                                  53, 59, 47, 41, 44, 39, 34, 39, 32, 31, 18,\n                                  18, 8, 76, 25, 15, 64, 110, 100, 103, 78, 83,\n                                  81, 7, 72, 72, 68, 1, 21, 8, 27, 67, 62, 62,\n                                  56, 50, 36, 32, 5, 72, 92, 73, 41, 29, 20, 9,\n                                  10, 2, 64, 68, 86, 98, 89, 81, 83, 77, 67, 73,\n                                  78, 67, 64, 0, 0, 5, 8, 3, 62, 61, 56, 49, 44,\n                                  38, 24, 11, 74 },\n\n                                {\n\n                                62,\n                                  8, 75, 62, 8, 75, 109, 89, 14, 10, 8, 16, 47,\n                                  50, 54, 14, 94, 3, 69, 5, 1, 7, 70, 3, 75, 15,\n                                  45, 83, 100, 109, 98, 91, 67, 69, 5, 1, 82,\n                                  84, 6, 13, 67, 77, 89, 5, 71, 82, 89, 5, 74,\n                                  87, 6, 71, 79, 88, 1, 70, 71, 76, 67, 5, 22,\n                                  0, 0, 0, 77, 88, 97, 67, 14, 0, 52, 8, 69,\n                                  116, 93, 82, 69, 93, 110, 107, 112, 83, 110,\n                                  100, 108, 112, 107, 112, 108, 8, 66, 74, 95,\n                                  68, 88, 83, 108, 73, 93, 86, 114, 10, 78, 71,\n                                  111, 88, 80, 75, 67, 3, 65, 76, 6, 3, 66, 4,\n                                  64, 64, 2, 76, 13, 7, 22, 19, 19, 18, 17, 16,\n                                  27, 12, 9, 27, 20, 70, 99, 90, 92, 82, 86, 81,\n                                  74, 79, 78, 78, 82, 70, 72, 70, 70, 97, 90,\n                                  95, 72, 73, 68, 69, 8, 3, 1, 65, 13, 1, 1, 64,\n                                  1, 79, 48, 45, 33, 37, 45, 36, 20, 38, 31, 18,\n                                  24, 16, 5, 1, 65, 18, 12, 15, 15, 11, 8, 15,\n                                  8, 11, 10, 2, 2, 7, 89, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 62, 57, 54, 53, 44, 39, 21, 51,\n                                  44, 25, 56, 46, 48, 43, 37, 35, 37, 26, 17, 7,\n                                  10, 73, 75, 98, 69, 25, 17, 11, 3, 5, 0, 70,\n                                  73, 85, 0, 40, 26, 21, 17, 9, 0, 71, 73, 79,\n                                  84, 18, 10, 5, 1, 65, 71, 75, 82, 99, 90, 71,\n                                  72, 69, 71, 77, 87, 90, 105, 73, 34, 18, 12,\n                                  3, 1, 72, 78, 81, 88, 62, 89, 80, 74, 66, 70,\n                                  1, 5, 6, 71, 3, 8, 3, 78, 71, 69, 13, 6, 18,\n                                  15, 26, 27, 19, 15, 20, 18, 15, 68, 7, 69, 96,\n                                  90, 86, 83, 80, 80, 79, 79, 68, 75, 74, 72,\n                                  64, 75, 82, 94, 86, 96, 76, 70, 70, 68, 68,\n                                  65, 64, 0, 64, 67, 66, 2, 67, 77, 48, 41, 43,\n                                  42, 39, 44, 40, 38, 33, 32, 34, 29, 11, 13, 6,\n                                  31, 29, 26, 17, 21, 17, 5, 0, 67, 75, 79, 92,\n                                  74, 101, 62, 62, 62, 62, 62, 60, 57, 53, 50,\n                                  47, 43, 38, 30, 14, 66, 48, 47, 20, 51, 57,\n                                  45, 39, 42, 37, 32, 37, 30, 28, 16, 16, 6, 77,\n                                  23, 13, 65, 109, 99, 102, 78, 82, 80, 9, 71,\n                                  71, 68, 2, 22, 10, 28, 67, 62, 60, 53, 47, 33,\n                                  29, 2, 74, 93, 73, 41, 29, 20, 9, 10, 2, 64,\n                                  68, 86, 97, 88, 80, 82, 76, 66, 73, 77, 66, 0,\n                                  1, 1, 5, 9, 3, 60, 59, 54, 47, 42, 36, 22, 9,\n                                  75 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 107, 88, 15, 10, 8, 15, 46,\n                                  49, 54, 14, 92, 3, 69, 6, 1, 6, 70, 2, 76, 14,\n                                  44, 84, 101, 110, 95, 90, 67, 69, 6, 1, 81,\n                                  83, 7, 12, 66, 76, 88, 4, 71, 82, 89, 5, 73,\n                                  87, 6, 71, 78, 88, 1, 70, 71, 76, 67, 5, 22,\n                                  0, 0, 0, 76, 88, 97, 67, 14, 64, 52, 8, 69,\n                                  115, 93, 82, 69, 92, 108, 105, 110, 82, 108,\n                                  99, 106, 111, 106, 111, 107, 9, 66, 73, 95,\n                                  67, 87, 83, 106, 73, 92, 86, 113, 10, 78, 71,\n                                  109, 88, 79, 74, 67, 3, 65, 75, 6, 3, 66, 4,\n                                  64, 64, 2, 76, 13, 7, 22, 19, 18, 18, 17, 16,\n                                  25, 12, 9, 25, 19, 71, 99, 89, 92, 82, 85, 81,\n                                  73, 79, 78, 78, 80, 70, 72, 70, 71, 96, 89,\n                                  95, 72, 73, 67, 68, 7, 3, 1, 65, 12, 2, 0, 65,\n                                  1, 80, 47, 44, 33, 37, 44, 36, 20, 37, 30, 17,\n                                  23, 16, 5, 1, 65, 17, 11, 14, 14, 11, 7, 14,\n                                  8, 9, 9, 2, 1, 6, 89, 62, 62, 62, 62, 62, 62,\n                                  62, 62, 62, 54, 52, 51, 41, 36, 18, 49, 42,\n                                  24, 54, 43, 45, 40, 35, 32, 35, 23, 15, 6, 8,\n                                  74, 76, 98, 68, 26, 17, 12, 3, 5, 0, 70, 73,\n                                  84, 0, 40, 27, 21, 17, 10, 1, 71, 72, 79, 83,\n                                  19, 10, 6, 1, 64, 70, 75, 81, 98, 89, 70, 71,\n                                  68, 71, 77, 87, 89, 103, 72, 34, 18, 12, 4, 1,\n                                  72, 77, 81, 87, 62, 88, 79, 73, 66, 70, 1, 5,\n                                  6, 71, 4, 8, 4, 78, 71, 70, 13, 6, 17, 14, 25,\n                                  26, 19, 14, 19, 18, 15, 68, 6, 70, 95, 89, 85,\n                                  83, 79, 80, 78, 79, 68, 74, 73, 71, 64, 75,\n                                  82, 94, 85, 96, 76, 70, 70, 67, 68, 65, 0, 64,\n                                  64, 67, 66, 1, 67, 78, 47, 40, 43, 41, 38, 44,\n                                  40, 37, 32, 32, 33, 28, 10, 12, 5, 30, 28, 24,\n                                  15, 19, 15, 4, 0, 67, 75, 79, 91, 75, 100, 62,\n                                  62, 62, 62, 62, 58, 55, 51, 48, 44, 41, 35,\n                                  28, 13, 66, 47, 46, 18, 49, 54, 43, 37, 40,\n                                  35, 30, 34, 28, 26, 14, 14, 5, 79, 21, 11, 67,\n                                  108, 98, 101, 77, 81, 79, 10, 70, 70, 68, 3,\n                                  24, 11, 30, 66, 61, 59, 51, 44, 30, 27, 64,\n                                  76, 95, 72, 41, 29, 20, 9, 10, 2, 64, 68, 85,\n                                  96, 88, 79, 81, 75, 66, 72, 76, 66, 0, 1, 1,\n                                  6, 9, 3, 59, 58, 52, 45, 41, 35, 19, 8, 76 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 106, 86, 15, 10, 7, 13, 44,\n                                  48, 54, 14, 90, 3, 68, 7, 1, 5, 70, 1, 77, 14,\n                                  42, 86, 102, 110, 92, 89, 67, 68, 7, 1, 81,\n                                  82, 7, 12, 66, 76, 87, 4, 72, 82, 89, 5, 73,\n                                  86, 6, 72, 78, 88, 2, 70, 71, 76, 66, 5, 22,\n                                  0, 0, 0, 76, 89, 97, 66, 13, 64, 52, 8, 69,\n                                  114, 92, 82, 68, 91, 106, 103, 109, 81, 106,\n                                  98, 104, 110, 106, 110, 106, 9, 66, 72, 94,\n                                  67, 87, 82, 104, 73, 92, 85, 112, 10, 78, 70,\n                                  108, 87, 78, 74, 67, 3, 65, 75, 7, 4, 67, 4,\n                                  64, 64, 2, 76, 13, 6, 21, 19, 17, 18, 17, 16,\n                                  23, 12, 8, 23, 18, 72, 98, 88, 91, 81, 85, 80,\n                                  72, 78, 77, 77, 79, 70, 72, 70, 72, 96, 88,\n                                  95, 72, 73, 66, 68, 6, 4, 1, 65, 11, 3, 0, 66,\n                                  1, 81, 45, 43, 32, 36, 43, 35, 19, 36, 30, 15,\n                                  22, 15, 5, 1, 66, 16, 10, 13, 13, 10, 6, 13,\n                                  7, 7, 8, 1, 0, 5, 89, 62, 62, 61, 62, 62, 62,\n                                  62, 62, 61, 52, 50, 48, 39, 34, 16, 47, 40,\n                                  22, 52, 41, 43, 38, 33, 30, 32, 21, 12, 5, 6,\n                                  75, 77, 98, 68, 26, 17, 12, 3, 5, 0, 70, 73,\n                                  84, 0, 40, 27, 21, 17, 11, 1, 70, 72, 78, 83,\n                                  20, 11, 6, 1, 64, 70, 74, 81, 97, 88, 69, 70,\n                                  68, 71, 76, 86, 88, 102, 72, 34, 18, 12, 4, 2,\n                                  71, 77, 80, 86, 62, 88, 79, 73, 66, 70, 1, 5,\n                                  6, 71, 4, 8, 4, 78, 71, 70, 12, 7, 16, 13, 24,\n                                  25, 19, 12, 18, 18, 15, 69, 5, 70, 95, 88, 84,\n                                  82, 79, 79, 78, 78, 69, 74, 73, 71, 65, 75,\n                                  82, 93, 84, 96, 76, 70, 70, 66, 68, 65, 1, 64,\n                                  65, 67, 65, 0, 67, 79, 46, 40, 42, 40, 37, 43,\n                                  39, 36, 31, 31, 32, 27, 9, 11, 4, 28, 27, 23,\n                                  13, 18, 14, 3, 64, 68, 75, 79, 91, 75, 100,\n                                  62, 62, 62, 62, 62, 56, 53, 48, 46, 42, 39,\n                                  33, 26, 11, 67, 45, 44, 17, 47, 52, 41, 35,\n                                  37, 33, 28, 32, 26, 23, 12, 12, 3, 80, 19, 9,\n                                  68, 107, 97, 100, 76, 80, 78, 12, 69, 69, 68,\n                                  4, 25, 13, 31, 65, 59, 57, 48, 41, 27, 24, 67,\n                                  78, 96, 72, 41, 29, 20, 9, 10, 2, 64, 68, 85,\n                                  95, 87, 78, 81, 74, 65, 72, 75, 65, 1, 2, 1,\n                                  6, 9, 3, 58, 56, 50, 43, 39, 33, 17, 6, 77 },\n\n                                {\n\n                                62,\n                                  8, 76, 62, 8, 76, 104, 85, 15, 10, 7, 12, 43,\n                                  46, 54, 14, 87, 2, 67, 7, 1, 5, 69, 0, 78, 13,\n                                  40, 88, 103, 111, 89, 87, 67, 67, 7, 1, 81,\n                                  81, 7, 11, 66, 76, 87, 4, 72, 81, 89, 5, 73,\n                                  85, 5, 72, 78, 88, 2, 69, 70, 75, 66, 5, 22,\n                                  0, 0, 0, 75, 89, 97, 66, 12, 64, 52, 8, 69,\n                                  113, 91, 82, 68, 89, 105, 101, 107, 80, 105,\n                                  96, 102, 109, 105, 109, 106, 10, 66, 71, 93,\n                                  67, 86, 81, 102, 73, 92, 85, 110, 11, 77, 70,\n                                  107, 87, 78, 74, 66, 4, 64, 74, 7, 4, 67, 3,\n                                  64, 64, 2, 76, 13, 6, 20, 19, 17, 18, 17, 15,\n                                  21, 12, 8, 22, 17, 73, 97, 87, 90, 80, 84, 79,\n                                  71, 77, 77, 76, 78, 70, 72, 69, 73, 95, 87,\n                                  95, 71, 73, 66, 68, 5, 5, 1, 65, 9, 4, 64, 67,\n                                  1, 81, 44, 42, 32, 35, 42, 34, 18, 36, 30, 14,\n                                  21, 15, 5, 1, 66, 16, 10, 12, 13, 9, 5, 13, 6,\n                                  5, 7, 0, 64, 4, 89, 61, 62, 59, 62, 61, 60,\n                                  60, 60, 59, 50, 48, 46, 36, 32, 13, 45, 39,\n                                  20, 49, 39, 41, 36, 30, 28, 29, 19, 10, 4, 5,\n                                  77, 77, 98, 68, 26, 18, 12, 3, 5, 0, 70, 73,\n                                  83, 1, 41, 27, 21, 17, 12, 2, 69, 72, 77, 82,\n                                  21, 12, 6, 2, 0, 69, 74, 80, 96, 88, 67, 70,\n                                  68, 70, 75, 85, 88, 101, 71, 35, 19, 12, 4, 3,\n                                  70, 76, 79, 85, 62, 88, 79, 72, 66, 70, 1, 5,\n                                  6, 70, 4, 9, 5, 78, 71, 70, 11, 7, 15, 12, 23,\n                                  25, 19, 11, 17, 17, 15, 70, 4, 71, 94, 88, 83,\n                                  82, 78, 79, 77, 77, 69, 74, 73, 71, 66, 75,\n                                  82, 93, 83, 96, 76, 69, 70, 66, 68, 65, 2, 64,\n                                  65, 67, 64, 0, 68, 79, 45, 40, 42, 40, 36, 42,\n                                  38, 35, 31, 30, 31, 26, 8, 10, 3, 27, 25, 21,\n                                  11, 17, 13, 2, 65, 68, 75, 78, 91, 76, 99, 62,\n                                  62, 62, 62, 60, 54, 51, 46, 44, 40, 37, 31,\n                                  24, 10, 68, 43, 42, 16, 45, 50, 39, 33, 35,\n                                  31, 26, 30, 24, 21, 10, 10, 1, 81, 17, 7, 70,\n                                  106, 95, 99, 76, 79, 77, 14, 68, 68, 68, 5,\n                                  27, 14, 33, 65, 58, 55, 46, 38, 25, 21, 69,\n                                  80, 97, 72, 41, 29, 20, 9, 10, 2, 64, 68, 84,\n                                  94, 86, 77, 80, 73, 64, 71, 74, 64, 2, 3, 2,\n                                  7, 10, 3, 56, 55, 49, 42, 37, 31, 15, 4, 78 },\n\n                                {\n\n                                61,\n                                  8, 76, 61, 8, 76, 102, 83, 16, 10, 6, 10, 41,\n                                  45, 54, 14, 85, 2, 66, 8, 1, 4, 69, 64, 79,\n                                  13, 38, 89, 104, 111, 86, 86, 67, 66, 8, 1,\n                                  80, 80, 8, 11, 66, 75, 86, 3, 73, 81, 89, 5,\n                                  73, 85, 5, 72, 78, 88, 3, 69, 70, 75, 65, 5,\n                                  22, 0, 0, 0, 75, 89, 97, 65, 11, 64, 52, 8,\n                                  69, 112, 90, 82, 67, 88, 103, 99, 106, 79,\n                                  103, 95, 100, 108, 104, 108, 105, 11, 66, 70,\n                                  92, 67, 86, 81, 100, 73, 91, 84, 109, 11, 77,\n                                  69, 105, 86, 77, 74, 66, 4, 64, 73, 8, 5, 68,\n                                  3, 64, 64, 2, 76, 13, 5, 20, 19, 16, 18, 17,\n                                  15, 19, 12, 7, 20, 16, 74, 96, 86, 89, 79, 83,\n                                  79, 70, 77, 76, 75, 77, 70, 72, 69, 74, 95,\n                                  86, 95, 71, 73, 65, 68, 4, 6, 1, 65, 8, 5, 64,\n                                  68, 1, 82, 42, 41, 31, 34, 41, 33, 18, 35, 29,\n                                  13, 20, 15, 5, 1, 67, 15, 9, 11, 12, 8, 4, 12,\n                                  6, 3, 6, 0, 65, 3, 89, 60, 61, 58, 62, 59, 58,\n                                  58, 58, 56, 47, 46, 43, 34, 29, 11, 43, 37,\n                                  19, 47, 37, 38, 33, 28, 25, 27, 17, 7, 3, 3,\n                                  78, 78, 98, 68, 27, 18, 12, 3, 5, 0, 70, 73,\n                                  83, 1, 41, 27, 21, 17, 13, 2, 69, 71, 77, 81,\n                                  22, 12, 7, 2, 1, 69, 73, 80, 95, 87, 66, 69,\n                                  67, 70, 74, 84, 87, 100, 71, 35, 19, 12, 4, 4,\n                                  70, 75, 78, 84, 62, 87, 78, 72, 66, 70, 1, 5,\n                                  6, 70, 4, 9, 5, 78, 71, 70, 11, 8, 14, 11, 22,\n                                  24, 19, 10, 16, 17, 15, 70, 3, 71, 93, 87, 82,\n                                  81, 78, 78, 77, 76, 69, 74, 73, 70, 66, 75,\n                                  82, 92, 82, 96, 76, 69, 70, 65, 68, 65, 3, 64,\n                                  65, 67, 0, 64, 68, 80, 44, 39, 41, 39, 35, 41,\n                                  37, 34, 30, 29, 30, 25, 7, 9, 2, 25, 24, 20,\n                                  9, 15, 12, 1, 65, 69, 75, 78, 91, 76, 98, 62,\n                                  62, 61, 61, 57, 52, 49, 43, 42, 38, 35, 28,\n                                  22, 8, 69, 41, 41, 14, 43, 48, 37, 31, 33, 29,\n                                  24, 28, 22, 18, 8, 8, 64, 82, 15, 5, 71, 105,\n                                  94, 98, 75, 78, 76, 15, 67, 67, 68, 6, 28, 16,\n                                  34, 64, 56, 54, 43, 35, 22, 18, 72, 82, 98,\n                                  72, 41, 29, 20, 9, 10, 2, 64, 68, 84, 93, 85,\n                                  76, 79, 72, 64, 71, 73, 64, 2, 3, 2, 7, 10, 3,\n                                  55, 53, 47, 40, 35, 29, 13, 2, 79 },\n\n                                {\n\n                                60,\n                                  8, 76, 60, 8, 76, 100, 82, 16, 10, 6, 9, 40,\n                                  44, 54, 14, 83, 2, 65, 9, 1, 3, 69, 65, 80,\n                                  12, 36, 91, 105, 112, 83, 85, 67, 65, 9, 1,\n                                  80, 79, 8, 10, 66, 75, 85, 3, 73, 81, 89, 5,\n                                  73, 84, 5, 72, 78, 88, 3, 69, 70, 75, 65, 5,\n                                  22, 0, 0, 0, 74, 89, 97, 65, 10, 64, 52, 8,\n                                  69, 111, 89, 82, 67, 87, 101, 97, 104, 78,\n                                  101, 94, 98, 107, 103, 107, 104, 12, 66, 69,\n                                  91, 67, 85, 80, 98, 73, 91, 84, 108, 11, 77,\n                                  69, 104, 86, 76, 74, 66, 4, 64, 72, 8, 5, 68,\n                                  3, 64, 64, 2, 76, 13, 5, 19, 19, 15, 18, 17,\n                                  15, 17, 12, 7, 18, 15, 75, 95, 85, 88, 78, 82,\n                                  78, 69, 76, 76, 74, 76, 70, 72, 69, 75, 94,\n                                  85, 95, 71, 73, 64, 68, 3, 7, 1, 65, 7, 6, 65,\n                                  69, 1, 83, 41, 40, 31, 33, 40, 32, 17, 34, 29,\n                                  12, 19, 15, 5, 1, 67, 14, 8, 10, 11, 7, 3, 11,\n                                  5, 1, 5, 64, 66, 2, 89, 58, 60, 56, 60, 57,\n                                  56, 56, 56, 54, 45, 44, 41, 31, 27, 8, 41, 35,\n                                  17, 45, 35, 36, 31, 26, 23, 24, 15, 5, 2, 1,\n                                  79, 79, 98, 68, 27, 18, 12, 3, 5, 0, 70, 73,\n                                  82, 1, 41, 27, 21, 17, 14, 3, 68, 71, 76, 80,\n                                  23, 13, 7, 2, 2, 68, 73, 79, 94, 86, 65, 68,\n                                  67, 70, 73, 83, 86, 99, 70, 35, 19, 12, 4, 5,\n                                  69, 74, 77, 83, 62, 87, 78, 71, 66, 70, 1, 5,\n                                  6, 70, 4, 9, 6, 78, 71, 70, 10, 8, 13, 10, 21,\n                                  23, 19, 9, 15, 17, 15, 71, 2, 72, 92, 86, 81,\n                                  81, 77, 78, 76, 75, 69, 74, 73, 70, 67, 75,\n                                  82, 92, 81, 96, 76, 69, 70, 64, 68, 65, 4, 64,\n                                  65, 67, 1, 65, 68, 81, 43, 39, 41, 38, 34, 40,\n                                  36, 33, 29, 28, 29, 24, 6, 8, 1, 24, 23, 18,\n                                  7, 14, 11, 0, 66, 69, 75, 78, 91, 77, 97, 62,\n                                  62, 59, 59, 54, 50, 47, 41, 40, 36, 33, 26,\n                                  20, 7, 70, 39, 39, 13, 41, 46, 35, 29, 31, 27,\n                                  22, 26, 20, 16, 6, 6, 66, 83, 13, 3, 73, 104,\n                                  93, 97, 74, 77, 75, 17, 66, 66, 68, 7, 30, 17,\n                                  36, 0, 55, 52, 41, 32, 19, 15, 75, 84, 99, 72,\n                                  41, 29, 20, 9, 10, 2, 64, 68, 83, 92, 84, 75,\n                                  78, 71, 0, 70, 72, 0, 3, 4, 2, 8, 10, 3, 54,\n                                  52, 45, 38, 33, 27, 11, 0, 80 },\n\n                                {\n\n                                58,\n                                  7, 77, 58, 7, 77, 99, 81, 16, 10, 5, 7, 38,\n                                  42, 53, 14, 81, 1, 65, 9, 0, 2, 69, 67, 82,\n                                  11, 34, 93, 106, 113, 81, 84, 68, 65, 9, 0,\n                                  80, 78, 8, 9, 66, 75, 85, 2, 74, 81, 90, 5,\n                                  73, 84, 4, 73, 78, 88, 3, 69, 70, 75, 65, 4,\n                                  22, 0, 0, 0, 74, 90, 97, 65, 9, 65, 52, 7, 69,\n                                  110, 89, 82, 67, 86, 100, 96, 103, 77, 100,\n                                  93, 97, 106, 103, 106, 104, 12, 66, 69, 91,\n                                  67, 85, 80, 97, 73, 91, 84, 107, 11, 77, 69,\n                                  103, 86, 76, 74, 66, 4, 64, 72, 8, 5, 69, 2,\n                                  64, 65, 2, 76, 12, 4, 18, 19, 14, 17, 17, 14,\n                                  15, 11, 6, 16, 14, 76, 95, 85, 88, 78, 82, 78,\n                                  68, 76, 76, 74, 75, 71, 72, 69, 77, 94, 85,\n                                  95, 71, 74, 64, 68, 2, 7, 1, 65, 5, 6, 66, 70,\n                                  1, 84, 39, 39, 30, 32, 39, 31, 16, 33, 28, 10,\n                                  18, 14, 4, 1, 68, 13, 7, 9, 10, 6, 2, 10, 4,\n                                  64, 3, 65, 68, 0, 89, 56, 58, 54, 58, 55, 53,\n                                  53, 53, 51, 42, 41, 38, 28, 24, 5, 39, 33, 15,\n                                  42, 32, 33, 28, 23, 20, 21, 12, 2, 1, 64, 81,\n                                  80, 99, 68, 27, 18, 12, 3, 5, 64, 70, 73, 82,\n                                  1, 41, 27, 21, 17, 15, 3, 68, 71, 76, 80, 23,\n                                  13, 7, 2, 2, 68, 73, 79, 93, 86, 64, 68, 67,\n                                  70, 73, 83, 86, 98, 70, 35, 19, 12, 4, 5, 69,\n                                  74, 77, 83, 62, 87, 78, 71, 66, 70, 1, 5, 6,\n                                  70, 4, 9, 6, 78, 71, 71, 9, 8, 12, 9, 20, 22,\n                                  18, 7, 13, 16, 14, 72, 0, 73, 92, 86, 80, 81,\n                                  77, 78, 76, 75, 70, 74, 73, 70, 68, 75, 82,\n                                  92, 81, 97, 76, 69, 70, 64, 69, 65, 4, 65, 66,\n                                  67, 1, 66, 69, 82, 42, 38, 40, 37, 32, 39, 35,\n                                  32, 28, 27, 28, 23, 5, 6, 64, 22, 21, 16, 5,\n                                  12, 9, 64, 67, 70, 75, 78, 91, 78, 97, 62, 61,\n                                  57, 56, 51, 47, 44, 38, 37, 33, 30, 23, 17, 5,\n                                  71, 37, 37, 11, 39, 43, 32, 26, 28, 24, 20,\n                                  23, 17, 13, 4, 3, 68, 85, 11, 1, 75, 103, 92,\n                                  96, 74, 77, 75, 18, 66, 66, 68, 7, 31, 18, 37,\n                                  0, 53, 50, 38, 28, 16, 12, 78, 87, 101, 72,\n                                  41, 28, 19, 9, 10, 2, 65, 68, 83, 92, 84, 75,\n                                  78, 70, 0, 70, 72, 0, 3, 4, 2, 8, 10, 2, 52,\n                                  50, 43, 36, 31, 25, 8, 65, 81 },\n\n                                {\n\n                                57,\n                                  7, 77, 57, 7, 77, 97, 79, 17, 11, 5, 6, 37,\n                                  41, 53, 14, 78, 1, 64, 10, 0, 2, 68, 68, 83,\n                                  11, 33, 94, 107, 113, 78, 82, 68, 64, 10, 0,\n                                  79, 76, 9, 9, 65, 74, 84, 2, 74, 80, 90, 5,\n                                  72, 83, 4, 73, 77, 88, 4, 68, 69, 74, 64, 4,\n                                  22, 0, 0, 0, 73, 90, 97, 64, 9, 65, 52, 7, 69,\n                                  108, 88, 82, 66, 84, 98, 94, 101, 75, 98, 91,\n                                  95, 104, 102, 105, 103, 13, 65, 68, 90, 66,\n                                  84, 79, 95, 72, 90, 83, 105, 12, 76, 68, 101,\n                                  85, 75, 73, 65, 5, 0, 71, 9, 6, 69, 2, 0, 65,\n                                  2, 75, 12, 4, 18, 19, 14, 17, 17, 14, 14, 11,\n                                  6, 15, 13, 76, 94, 84, 87, 77, 81, 77, 67, 75,\n                                  75, 73, 73, 71, 72, 68, 78, 93, 84, 95, 70,\n                                  74, 0, 67, 2, 8, 1, 65, 4, 7, 66, 71, 1, 84,\n                                  38, 39, 30, 32, 39, 31, 16, 33, 28, 9, 18, 14,\n                                  4, 1, 68, 13, 7, 9, 10, 6, 1, 10, 4, 65, 2,\n                                  65, 69, 64, 89, 55, 57, 53, 57, 54, 51, 51,\n                                  51, 49, 40, 39, 36, 26, 22, 3, 38, 32, 14, 40,\n                                  30, 31, 26, 21, 18, 19, 10, 0, 1, 65, 82, 80,\n                                  99, 67, 28, 19, 13, 4, 5, 64, 69, 72, 81, 2,\n                                  42, 28, 22, 17, 16, 4, 67, 70, 75, 79, 24, 14,\n                                  8, 3, 3, 67, 72, 78, 91, 85, 1, 67, 66, 69,\n                                  72, 82, 85, 96, 69, 36, 20, 13, 5, 6, 68, 73,\n                                  76, 82, 62, 86, 77, 70, 66, 69, 1, 6, 7, 69,\n                                  5, 10, 7, 77, 71, 71, 9, 9, 12, 9, 19, 22, 18,\n                                  6, 12, 16, 14, 72, 64, 73, 91, 85, 79, 80, 76,\n                                  77, 75, 74, 70, 73, 72, 69, 68, 74, 81, 91,\n                                  80, 97, 76, 68, 70, 0, 69, 65, 5, 65, 66, 66,\n                                  2, 66, 69, 82, 42, 38, 40, 37, 31, 39, 35, 32,\n                                  28, 27, 28, 23, 5, 5, 65, 21, 20, 15, 4, 11,\n                                  8, 64, 67, 70, 74, 77, 90, 78, 96, 60, 59, 55,\n                                  54, 49, 45, 42, 36, 35, 31, 28, 21, 15, 4, 71,\n                                  36, 36, 10, 38, 41, 30, 24, 26, 22, 18, 21,\n                                  15, 11, 3, 1, 69, 86, 10, 0, 76, 101, 90, 94,\n                                  73, 76, 74, 20, 65, 65, 68, 8, 33, 20, 39, 1,\n                                  52, 49, 36, 25, 14, 10, 80, 89, 102, 71, 42,\n                                  28, 19, 9, 11, 2, 65, 68, 82, 91, 83, 74, 77,\n                                  68, 1, 69, 71, 1, 4, 5, 3, 9, 11, 2, 51, 49,\n                                  42, 35, 30, 24, 6, 66, 81 },\n\n                                {\n\n                                56,\n                                  7, 77, 56, 7, 77, 95, 78, 17, 11, 5, 5, 36,\n                                  40, 53, 14, 76, 1, 0, 11, 0, 1, 68, 69, 84,\n                                  10, 31, 96, 108, 114, 75, 81, 68, 0, 11, 0,\n                                  79, 75, 9, 8, 65, 74, 83, 2, 74, 80, 90, 5,\n                                  72, 82, 4, 73, 77, 88, 4, 68, 69, 74, 64, 4,\n                                  22, 0, 0, 0, 72, 90, 97, 64, 8, 65, 52, 7, 69,\n                                  107, 87, 82, 66, 83, 96, 92, 100, 74, 96, 90,\n                                  93, 103, 101, 104, 102, 14, 65, 67, 89, 66,\n                                  84, 78, 93, 72, 90, 83, 104, 12, 76, 68, 100,\n                                  85, 74, 73, 65, 5, 0, 70, 9, 6, 70, 2, 0, 65,\n                                  2, 75, 12, 4, 17, 19, 13, 17, 17, 14, 12, 11,\n                                  6, 13, 12, 77, 93, 83, 86, 76, 80, 76, 66, 74,\n                                  75, 72, 72, 71, 72, 68, 79, 93, 83, 95, 70,\n                                  74, 1, 67, 1, 9, 1, 65, 3, 8, 67, 72, 1, 85,\n                                  36, 38, 29, 31, 38, 30, 15, 32, 28, 8, 17, 14,\n                                  4, 1, 68, 12, 6, 8, 9, 5, 0, 9, 3, 67, 1, 66,\n                                  70, 65, 89, 53, 56, 51, 55, 52, 49, 49, 49,\n                                  46, 38, 37, 33, 23, 20, 0, 36, 30, 12, 38, 28,\n                                  29, 24, 19, 16, 16, 8, 65, 0, 67, 83, 81, 99,\n                                  67, 28, 19, 13, 4, 5, 64, 69, 72, 80, 2, 42,\n                                  28, 22, 17, 17, 4, 66, 70, 74, 78, 25, 15, 8,\n                                  3, 4, 67, 72, 77, 90, 84, 2, 66, 66, 69, 71,\n                                  81, 84, 95, 69, 36, 20, 13, 5, 7, 67, 72, 75,\n                                  81, 62, 86, 77, 70, 66, 69, 1, 6, 7, 69, 5,\n                                  10, 8, 77, 71, 71, 8, 9, 11, 8, 18, 21, 18, 5,\n                                  11, 16, 14, 73, 65, 74, 90, 84, 78, 80, 76,\n                                  77, 74, 73, 70, 73, 72, 69, 69, 74, 81, 91,\n                                  79, 97, 76, 68, 70, 1, 69, 65, 6, 65, 66, 66,\n                                  3, 67, 69, 83, 41, 38, 40, 36, 30, 38, 34, 31,\n                                  27, 26, 27, 22, 4, 4, 66, 19, 19, 13, 2, 10,\n                                  7, 65, 68, 70, 74, 77, 90, 79, 95, 58, 57, 53,\n                                  52, 46, 43, 40, 33, 33, 29, 26, 19, 13, 3, 72,\n                                  34, 34, 9, 36, 39, 28, 22, 24, 20, 16, 19, 13,\n                                  9, 1, 64, 71, 87, 8, 65, 78, 100, 89, 93, 72,\n                                  75, 73, 22, 64, 64, 68, 9, 34, 21, 40, 2, 51,\n                                  47, 33, 22, 11, 7, 83, 91, 103, 71, 42, 28,\n                                  19, 9, 11, 2, 65, 68, 81, 90, 82, 73, 76, 67,\n                                  2, 68, 70, 2, 5, 6, 3, 10, 11, 2, 50, 47, 40,\n                                  33, 28, 22, 4, 68, 82 },\n\n                                {\n\n                                55,\n                                  7, 77, 55, 7, 77, 93, 76, 18, 11, 4, 3, 34,\n                                  39, 53, 14, 74, 1, 1, 12, 0, 0, 68, 70, 85,\n                                  10, 29, 97, 109, 114, 72, 80, 68, 1, 12, 0,\n                                  78, 74, 10, 8, 65, 73, 82, 1, 75, 80, 90, 5,\n                                  72, 82, 4, 73, 77, 88, 5, 68, 69, 74, 0, 4,\n                                  22, 0, 0, 0, 72, 90, 97, 0, 7, 65, 52, 7, 69,\n                                  106, 86, 82, 65, 82, 94, 90, 98, 73, 94, 89,\n                                  91, 102, 100, 103, 101, 15, 65, 66, 88, 66,\n                                  83, 78, 91, 72, 89, 82, 103, 12, 76, 67, 98,\n                                  84, 73, 73, 65, 5, 0, 69, 10, 7, 70, 2, 0, 65,\n                                  2, 75, 12, 3, 17, 19, 12, 17, 17, 14, 10, 11,\n                                  5, 11, 11, 78, 92, 82, 85, 75, 79, 76, 65, 74,\n                                  74, 71, 71, 71, 72, 68, 80, 92, 82, 95, 70,\n                                  74, 2, 67, 0, 10, 1, 65, 2, 9, 67, 73, 1, 86,\n                                  35, 37, 29, 30, 37, 29, 15, 31, 27, 7, 16, 14,\n                                  4, 1, 69, 11, 5, 7, 8, 4, 64, 8, 3, 69, 0, 66,\n                                  71, 66, 89, 52, 54, 50, 53, 50, 47, 47, 47,\n                                  44, 35, 35, 31, 21, 17, 65, 34, 28, 11, 36,\n                                  26, 26, 21, 17, 13, 14, 6, 68, 64, 69, 84, 82,\n                                  99, 67, 29, 19, 13, 4, 5, 64, 69, 72, 80, 2,\n                                  42, 28, 22, 17, 18, 5, 66, 69, 74, 77, 26, 15,\n                                  9, 3, 5, 66, 71, 77, 89, 83, 3, 65, 65, 69,\n                                  70, 80, 83, 94, 68, 36, 20, 13, 5, 8, 67, 71,\n                                  74, 80, 62, 85, 76, 69, 66, 69, 1, 6, 7, 69,\n                                  5, 10, 8, 77, 71, 71, 8, 10, 10, 7, 17, 20,\n                                  18, 4, 10, 16, 14, 73, 66, 74, 89, 83, 77, 79,\n                                  75, 76, 74, 72, 70, 73, 72, 68, 69, 74, 81,\n                                  90, 78, 97, 76, 68, 70, 2, 69, 65, 7, 65, 66,\n                                  66, 4, 68, 69, 84, 40, 37, 39, 35, 29, 37, 33,\n                                  30, 26, 25, 26, 21, 3, 3, 67, 18, 18, 12, 0,\n                                  8, 6, 66, 68, 71, 74, 77, 90, 79, 94, 56, 55,\n                                  51, 50, 43, 41, 38, 31, 31, 27, 24, 16, 11, 1,\n                                  73, 32, 33, 7, 34, 37, 26, 20, 22, 18, 14, 17,\n                                  11, 6, 64, 66, 73, 88, 6, 67, 79, 99, 88, 92,\n                                  71, 74, 72, 23, 0, 0, 68, 10, 36, 23, 42, 3,\n                                  49, 46, 31, 19, 8, 4, 86, 93, 104, 71, 42, 28,\n                                  19, 9, 11, 2, 65, 68, 81, 89, 81, 72, 75, 66,\n                                  2, 68, 69, 2, 5, 6, 3, 10, 11, 2, 49, 46, 38,\n                                  31, 26, 20, 2, 70, 83 },\n\n                                {\n\n                                53,\n                                  7, 77, 53, 7, 77, 92, 75, 18, 11, 4, 2, 33,\n                                  37, 53, 14, 71, 0, 2, 12, 0, 64, 68, 71, 86,\n                                  9, 27, 99, 110, 115, 69, 79, 68, 2, 12, 0, 78,\n                                  73, 10, 7, 65, 73, 82, 1, 75, 79, 90, 5, 72,\n                                  81, 3, 74, 77, 88, 5, 67, 69, 73, 0, 4, 22, 0,\n                                  0, 0, 71, 91, 97, 0, 6, 65, 52, 7, 69, 105,\n                                  85, 82, 65, 80, 93, 88, 97, 72, 93, 87, 89,\n                                  101, 100, 102, 101, 15, 65, 65, 87, 66, 83,\n                                  77, 89, 72, 89, 82, 102, 12, 75, 67, 97, 84,\n                                  73, 73, 64, 5, 0, 69, 10, 7, 71, 1, 0, 65, 2,\n                                  75, 12, 3, 16, 19, 12, 17, 17, 13, 8, 11, 5,\n                                  9, 10, 79, 91, 81, 84, 74, 79, 75, 64, 73, 74,\n                                  70, 70, 71, 72, 67, 81, 92, 81, 95, 70, 74, 2,\n                                  67, 64, 11, 1, 65, 0, 10, 68, 74, 1, 87, 33,\n                                  36, 28, 29, 36, 28, 14, 30, 27, 5, 15, 13, 4,\n                                  1, 69, 10, 5, 6, 8, 3, 65, 7, 2, 71, 64, 67,\n                                  72, 67, 89, 50, 53, 48, 51, 48, 45, 44, 45,\n                                  41, 33, 33, 28, 18, 15, 68, 32, 27, 9, 33, 24,\n                                  24, 19, 14, 11, 11, 4, 70, 65, 70, 86, 83, 99,\n                                  67, 29, 20, 13, 4, 5, 64, 69, 72, 79, 3, 43,\n                                  28, 22, 17, 19, 5, 65, 69, 73, 77, 27, 16, 9,\n                                  3, 5, 66, 71, 76, 88, 83, 4, 65, 65, 69, 69,\n                                  79, 83, 93, 68, 37, 20, 13, 5, 9, 66, 71, 73,\n                                  79, 62, 85, 76, 69, 66, 69, 1, 6, 7, 68, 5,\n                                  10, 9, 77, 71, 71, 7, 10, 9, 6, 16, 19, 18, 2,\n                                  9, 15, 14, 74, 67, 75, 89, 83, 76, 79, 75, 76,\n                                  73, 71, 71, 73, 72, 68, 70, 74, 81, 90, 77,\n                                  97, 76, 67, 70, 2, 69, 65, 8, 65, 67, 66, 5,\n                                  68, 70, 85, 39, 37, 39, 34, 28, 36, 32, 29,\n                                  25, 24, 25, 20, 2, 2, 68, 16, 16, 10, 65, 7,\n                                  5, 67, 69, 71, 74, 77, 90, 80, 94, 53, 52, 49,\n                                  47, 40, 39, 36, 28, 29, 25, 22, 14, 9, 0, 74,\n                                  30, 31, 6, 32, 35, 24, 18, 19, 16, 12, 15, 9,\n                                  4, 66, 68, 75, 89, 4, 69, 81, 98, 87, 91, 71,\n                                  73, 71, 25, 1, 1, 68, 11, 37, 24, 43, 3, 48,\n                                  44, 28, 16, 5, 1, 89, 95, 105, 71, 42, 28, 19,\n                                  9, 11, 2, 65, 68, 80, 88, 80, 71, 75, 65, 3,\n                                  67, 68, 3, 6, 7, 4, 11, 12, 2, 47, 44, 36, 29,\n                                  24, 18, 0, 72, 84 },\n\n                                {\n\n                                52,\n                                  7, 77, 52, 7, 77, 90, 73, 18, 11, 3, 0, 31,\n                                  36, 53, 14, 69, 0, 3, 13, 0, 64, 67, 72, 87,\n                                  9, 25, 101, 111, 115, 66, 77, 68, 3, 13, 0,\n                                  78, 72, 10, 7, 65, 73, 81, 1, 76, 79, 90, 5,\n                                  72, 80, 3, 74, 77, 88, 6, 67, 68, 73, 1, 4,\n                                  22, 0, 0, 0, 71, 91, 97, 1, 5, 65, 52, 7, 69,\n                                  104, 84, 82, 64, 79, 91, 86, 95, 71, 91, 86,\n                                  87, 100, 99, 101, 100, 16, 65, 64, 86, 66, 82,\n                                  76, 87, 72, 89, 81, 100, 13, 75, 66, 96, 83,\n                                  72, 73, 64, 6, 1, 68, 11, 8, 71, 1, 0, 65, 2,\n                                  75, 12, 2, 15, 19, 11, 17, 17, 13, 6, 11, 4,\n                                  8, 9, 80, 90, 80, 83, 73, 78, 74, 0, 72, 73,\n                                  69, 69, 71, 72, 67, 82, 91, 80, 95, 69, 74, 3,\n                                  67, 65, 12, 1, 65, 64, 11, 68, 75, 1, 87, 32,\n                                  35, 28, 28, 35, 27, 13, 30, 27, 4, 14, 13, 4,\n                                  1, 70, 10, 4, 5, 7, 2, 66, 7, 1, 73, 65, 68,\n                                  73, 68, 89, 48, 52, 46, 49, 47, 43, 42, 43,\n                                  39, 31, 31, 26, 16, 13, 70, 30, 25, 7, 31, 22,\n                                  22, 17, 12, 9, 8, 2, 73, 66, 72, 87, 83, 99,\n                                  67, 29, 20, 13, 4, 5, 64, 69, 72, 79, 3, 43,\n                                  28, 22, 17, 20, 6, 64, 69, 72, 76, 28, 17, 9,\n                                  4, 6, 65, 70, 76, 87, 82, 6, 64, 65, 68, 68,\n                                  78, 82, 92, 67, 37, 21, 13, 5, 10, 65, 70, 72,\n                                  78, 62, 85, 76, 68, 66, 69, 1, 6, 7, 68, 5,\n                                  11, 9, 77, 71, 71, 6, 11, 8, 5, 15, 19, 18, 1,\n                                  8, 15, 14, 75, 68, 75, 88, 82, 75, 78, 74, 75,\n                                  73, 70, 71, 73, 72, 68, 71, 74, 81, 89, 76,\n                                  97, 76, 67, 70, 3, 69, 65, 9, 65, 67, 66, 6,\n                                  69, 70, 85, 38, 37, 38, 34, 27, 35, 31, 28,\n                                  25, 23, 24, 19, 1, 1, 69, 15, 15, 9, 67, 6, 4,\n                                  68, 70, 72, 74, 76, 90, 80, 93, 51, 50, 47,\n                                  45, 38, 37, 34, 26, 27, 23, 20, 12, 7, 65, 75,\n                                  28, 29, 5, 30, 33, 22, 16, 17, 14, 10, 13, 7,\n                                  1, 68, 70, 77, 90, 2, 71, 82, 97, 85, 90, 70,\n                                  72, 70, 27, 2, 2, 68, 12, 39, 26, 45, 4, 46,\n                                  42, 26, 13, 3, 65, 91, 97, 106, 71, 42, 28,\n                                  19, 9, 11, 2, 65, 68, 80, 87, 79, 70, 74, 64,\n                                  4, 67, 67, 4, 7, 8, 4, 11, 12, 2, 46, 43, 35,\n                                  28, 22, 16, 65, 74, 85 },\n\n                                {\n\n                                51,\n                                  7, 78, 51, 7, 78, 88, 72, 19, 11, 3, 64, 30,\n                                  35, 53, 14, 67, 0, 3, 14, 0, 65, 67, 73, 88,\n                                  8, 24, 102, 112, 116, 0, 76, 68, 3, 14, 0, 77,\n                                  71, 11, 6, 64, 72, 80, 0, 76, 79, 90, 5, 71,\n                                  80, 3, 74, 76, 88, 6, 67, 68, 73, 1, 4, 22, 0,\n                                  0, 0, 70, 91, 97, 1, 5, 66, 52, 7, 69, 103,\n                                  84, 82, 64, 78, 89, 84, 94, 70, 89, 85, 85,\n                                  99, 98, 100, 99, 17, 65, 0, 86, 65, 82, 76,\n                                  85, 72, 88, 81, 99, 13, 75, 66, 94, 83, 71,\n                                  72, 64, 6, 1, 67, 11, 8, 72, 1, 0, 65, 2, 75,\n                                  12, 2, 15, 19, 10, 17, 17, 13, 4, 11, 4, 6, 8,\n                                  81, 90, 79, 83, 73, 77, 74, 1, 72, 73, 69, 67,\n                                  71, 72, 67, 83, 91, 79, 95, 69, 74, 4, 66, 66,\n                                  12, 1, 65, 65, 12, 69, 76, 1, 88, 30, 34, 27,\n                                  28, 34, 27, 13, 29, 26, 3, 13, 13, 4, 1, 70,\n                                  9, 3, 4, 6, 2, 67, 6, 1, 75, 66, 68, 74, 69,\n                                  89, 47, 50, 45, 47, 45, 41, 40, 41, 36, 28,\n                                  29, 23, 13, 10, 73, 28, 23, 6, 29, 19, 19, 14,\n                                  10, 6, 6, 64, 75, 67, 74, 88, 84, 99, 66, 30,\n                                  20, 14, 4, 5, 64, 69, 72, 78, 3, 43, 29, 22,\n                                  17, 21, 6, 64, 68, 72, 75, 29, 17, 10, 4, 7,\n                                  65, 70, 75, 86, 81, 7, 0, 64, 68, 68, 78, 81,\n                                  90, 67, 37, 21, 13, 6, 10, 65, 69, 72, 77, 62,\n                                  84, 75, 68, 66, 69, 1, 6, 7, 68, 6, 11, 10,\n                                  77, 71, 72, 6, 11, 7, 4, 14, 18, 18, 0, 7, 15,\n                                  14, 75, 69, 76, 87, 81, 74, 78, 74, 75, 72,\n                                  70, 71, 72, 71, 67, 71, 74, 81, 89, 75, 97,\n                                  76, 67, 70, 4, 69, 65, 10, 66, 67, 66, 6, 70,\n                                  70, 86, 37, 36, 38, 33, 26, 35, 31, 27, 24,\n                                  23, 23, 18, 0, 0, 70, 13, 14, 7, 69, 4, 2, 69,\n                                  70, 72, 74, 76, 89, 81, 92, 49, 48, 45, 43,\n                                  35, 35, 32, 23, 25, 20, 18, 9, 5, 66, 75, 27,\n                                  28, 3, 28, 30, 20, 14, 15, 12, 8, 10, 5, 64,\n                                  70, 72, 78, 92, 0, 73, 84, 96, 84, 89, 69, 71,\n                                  69, 28, 3, 3, 68, 13, 40, 27, 46, 5, 45, 41,\n                                  23, 10, 0, 67, 94, 99, 108, 70, 42, 28, 19, 9,\n                                  11, 2, 65, 68, 79, 86, 79, 69, 73, 0, 4, 66,\n                                  66, 4, 7, 8, 4, 12, 12, 2, 45, 41, 33, 26, 21,\n                                  15, 68, 75, 86 },\n\n                                {\n\n                                50,\n                                  7, 78, 50, 7, 78, 86, 70, 19, 11, 2, 66, 28,\n                                  33, 53, 14, 64, 64, 4, 14, 0, 66, 67, 74, 89,\n                                  8, 22, 104, 113, 116, 3, 75, 68, 4, 14, 0, 77,\n                                  70, 11, 6, 64, 72, 80, 0, 77, 78, 90, 5, 71,\n                                  79, 2, 74, 76, 88, 7, 66, 68, 72, 2, 4, 22, 0,\n                                  0, 0, 70, 91, 97, 2, 4, 66, 52, 7, 69, 102,\n                                  83, 82, 0, 76, 88, 82, 92, 69, 88, 83, 83, 98,\n                                  97, 99, 99, 18, 65, 1, 85, 65, 81, 75, 83, 72,\n                                  88, 80, 98, 13, 74, 65, 93, 82, 71, 72, 0, 6,\n                                  1, 66, 12, 9, 72, 0, 0, 65, 2, 75, 12, 1, 14,\n                                  19, 10, 17, 17, 12, 2, 11, 3, 4, 7, 82, 89,\n                                  78, 82, 72, 76, 73, 2, 71, 72, 68, 66, 71, 72,\n                                  66, 84, 90, 78, 95, 69, 74, 4, 66, 67, 13, 1,\n                                  65, 67, 13, 69, 77, 1, 89, 29, 33, 27, 27, 33,\n                                  26, 12, 28, 26, 2, 12, 13, 4, 1, 71, 8, 3, 3,\n                                  6, 1, 68, 5, 0, 77, 67, 69, 75, 70, 89, 45,\n                                  49, 43, 45, 43, 39, 37, 39, 34, 26, 27, 21,\n                                  11, 8, 75, 26, 22, 4, 26, 17, 17, 12, 7, 4, 3,\n                                  66, 78, 68, 75, 90, 85, 99, 66, 30, 21, 14, 4,\n                                  5, 64, 69, 72, 78, 4, 44, 29, 22, 17, 22, 7,\n                                  0, 68, 71, 74, 30, 18, 10, 4, 8, 64, 69, 75,\n                                  85, 81, 8, 0, 64, 68, 67, 77, 81, 89, 66, 38,\n                                  21, 13, 6, 11, 64, 68, 71, 76, 62, 84, 75, 67,\n                                  66, 69, 1, 6, 7, 67, 6, 11, 10, 77, 71, 72, 5,\n                                  12, 6, 3, 13, 17, 18, 64, 6, 14, 14, 76, 70,\n                                  76, 86, 81, 73, 77, 73, 74, 72, 69, 71, 72,\n                                  71, 67, 72, 74, 81, 88, 74, 97, 76, 66, 70, 4,\n                                  69, 65, 11, 66, 67, 66, 7, 70, 71, 87, 36, 36,\n                                  37, 32, 25, 34, 30, 26, 23, 22, 22, 17, 64,\n                                  64, 71, 12, 12, 6, 71, 3, 1, 70, 71, 73, 74,\n                                  76, 89, 81, 91, 47, 46, 43, 40, 32, 33, 30,\n                                  21, 23, 18, 16, 7, 3, 68, 76, 25, 26, 2, 26,\n                                  28, 18, 12, 13, 10, 6, 8, 3, 67, 72, 74, 80,\n                                  93, 65, 75, 85, 95, 83, 88, 69, 70, 68, 30, 4,\n                                  4, 68, 14, 42, 29, 48, 5, 43, 39, 21, 7, 66,\n                                  70, 97, 101, 109, 70, 42, 28, 19, 9, 11, 2,\n                                  65, 68, 79, 85, 78, 68, 72, 1, 5, 66, 65, 5,\n                                  8, 9, 5, 12, 13, 2, 43, 40, 31, 24, 19, 13,\n                                  70, 77, 87 },\n\n                                {\n\n                                48,\n                                  6, 78, 48, 6, 78, 85, 69, 19, 11, 2, 67, 27,\n                                  32, 53, 14, 1, 64, 5, 15, 0, 67, 67, 75, 91,\n                                  7, 20, 106, 114, 117, 5, 74, 68, 5, 15, 0, 77,\n                                  69, 11, 5, 64, 72, 79, 64, 77, 78, 91, 5, 71,\n                                  79, 2, 75, 76, 88, 7, 66, 68, 72, 2, 4, 22, 0,\n                                  0, 0, 69, 92, 97, 2, 3, 66, 52, 7, 69, 101,\n                                  82, 82, 0, 75, 86, 80, 91, 68, 86, 82, 82, 97,\n                                  97, 98, 98, 18, 65, 2, 84, 65, 81, 75, 82, 72,\n                                  88, 80, 97, 13, 74, 65, 92, 82, 70, 72, 0, 6,\n                                  1, 66, 12, 9, 73, 0, 0, 65, 2, 75, 12, 1, 13,\n                                  19, 9, 17, 17, 12, 0, 11, 3, 2, 6, 83, 88, 77,\n                                  81, 71, 76, 73, 3, 71, 72, 67, 65, 71, 72, 66,\n                                  86, 90, 77, 95, 69, 75, 5, 66, 68, 14, 1, 65,\n                                  68, 14, 70, 78, 1, 90, 27, 32, 26, 26, 32, 25,\n                                  11, 27, 25, 0, 11, 12, 4, 1, 71, 7, 2, 2, 5,\n                                  0, 69, 4, 64, 79, 69, 70, 76, 71, 89, 43, 47,\n                                  41, 43, 41, 37, 35, 37, 31, 23, 25, 18, 8, 5,\n                                  78, 24, 20, 2, 24, 15, 14, 9, 5, 1, 0, 68, 80,\n                                  69, 77, 91, 86, 100, 66, 30, 21, 14, 4, 5, 64,\n                                  69, 72, 77, 4, 44, 29, 22, 17, 23, 7, 0, 68,\n                                  71, 74, 31, 18, 10, 4, 8, 64, 69, 74, 84, 80,\n                                  9, 1, 64, 68, 66, 76, 80, 88, 66, 38, 21, 13,\n                                  6, 12, 64, 68, 70, 76, 62, 84, 75, 67, 66, 69,\n                                  1, 6, 7, 67, 6, 11, 11, 77, 71, 72, 4, 12, 5,\n                                  2, 12, 16, 18, 66, 4, 14, 14, 77, 71, 77, 86,\n                                  80, 72, 77, 73, 74, 71, 68, 72, 72, 71, 67,\n                                  73, 74, 81, 88, 74, 98, 76, 66, 70, 5, 69, 65,\n                                  11, 66, 68, 66, 8, 71, 71, 88, 35, 35, 37, 31,\n                                  23, 33, 29, 25, 22, 21, 21, 16, 65, 65, 72,\n                                  10, 11, 4, 73, 1, 0, 71, 72, 73, 74, 76, 89,\n                                  82, 91, 44, 43, 41, 38, 29, 30, 27, 18, 21,\n                                  16, 14, 4, 1, 69, 77, 23, 24, 0, 24, 26, 15,\n                                  9, 10, 7, 4, 6, 0, 69, 74, 77, 82, 94, 67, 77,\n                                  87, 94, 82, 87, 68, 69, 68, 31, 5, 4, 68, 14,\n                                  43, 30, 49, 6, 42, 37, 18, 4, 69, 73, 100,\n                                  103, 110, 70, 42, 28, 19, 9, 11, 2, 65, 68,\n                                  78, 85, 77, 67, 72, 2, 5, 65, 65, 5, 8, 9, 5,\n                                  13, 13, 1, 42, 38, 29, 22, 17, 11, 72, 79, 88 },\n\n                                {\n\n                                47,\n                                  6, 78, 47, 6, 78, 83, 68, 20, 11, 2, 68, 26,\n                                  31, 53, 14, 3, 64, 6, 16, 0, 67, 66, 76, 92,\n                                  6, 18, 107, 115, 118, 8, 72, 68, 6, 16, 0, 76,\n                                  68, 12, 4, 64, 71, 78, 64, 77, 78, 91, 5, 71,\n                                  78, 2, 75, 76, 88, 7, 66, 67, 72, 2, 4, 22, 0,\n                                  0, 0, 68, 92, 97, 2, 2, 66, 52, 7, 69, 100,\n                                  81, 82, 0, 74, 84, 78, 89, 66, 84, 81, 80, 96,\n                                  96, 97, 97, 19, 64, 3, 83, 65, 80, 74, 80, 72,\n                                  87, 80, 95, 14, 74, 65, 90, 82, 69, 72, 0, 7,\n                                  2, 65, 12, 9, 73, 0, 1, 65, 2, 74, 12, 1, 13,\n                                  19, 8, 17, 17, 12, 65, 11, 3, 1, 5, 83, 87,\n                                  76, 80, 70, 75, 72, 4, 70, 72, 66, 64, 71, 72,\n                                  66, 87, 89, 76, 95, 68, 75, 6, 66, 69, 15, 1,\n                                  65, 69, 15, 71, 79, 1, 90, 26, 31, 26, 25, 31,\n                                  24, 11, 27, 25, 64, 10, 12, 4, 1, 71, 7, 1, 1,\n                                  4, 64, 70, 4, 64, 80, 70, 70, 77, 72, 89, 42,\n                                  46, 40, 42, 40, 35, 33, 35, 29, 21, 23, 16, 5,\n                                  3, 81, 23, 18, 1, 22, 13, 12, 7, 3, 64, 65,\n                                  70, 82, 69, 79, 92, 86, 100, 66, 31, 21, 14,\n                                  5, 5, 64, 68, 72, 76, 4, 44, 29, 23, 17, 24,\n                                  8, 1, 67, 70, 73, 32, 19, 11, 5, 9, 0, 69, 73,\n                                  83, 79, 11, 2, 0, 67, 65, 75, 79, 87, 65, 38,\n                                  22, 14, 6, 13, 0, 67, 69, 75, 62, 83, 74, 66,\n                                  66, 69, 1, 7, 8, 67, 6, 12, 12, 77, 71, 72, 4,\n                                  12, 4, 2, 11, 16, 18, 67, 3, 14, 14, 77, 72,\n                                  78, 85, 79, 71, 77, 72, 74, 70, 67, 72, 72,\n                                  71, 66, 73, 74, 81, 88, 73, 98, 76, 66, 70, 6,\n                                  69, 65, 12, 66, 68, 66, 9, 72, 71, 88, 34, 35,\n                                  37, 31, 22, 32, 28, 24, 22, 20, 20, 16, 65,\n                                  66, 73, 9, 10, 2, 75, 0, 64, 71, 72, 73, 73,\n                                  75, 89, 83, 90, 42, 41, 39, 36, 27, 28, 25,\n                                  16, 19, 14, 12, 2, 64, 70, 78, 21, 23, 64, 22,\n                                  24, 13, 7, 8, 5, 2, 4, 65, 71, 75, 79, 84, 95,\n                                  69, 79, 89, 93, 80, 85, 67, 68, 67, 33, 6, 5,\n                                  68, 15, 45, 31, 51, 7, 41, 36, 16, 1, 71, 76,\n                                  102, 105, 111, 70, 42, 28, 19, 9, 12, 2, 65,\n                                  68, 77, 84, 76, 66, 71, 4, 6, 64, 64, 6, 9,\n                                  10, 5, 14, 13, 1, 41, 37, 28, 21, 15, 9, 74,\n                                  81, 88 },\n\n                                {\n\n                                46,\n                                  6, 78, 46, 6, 78, 81, 66, 20, 11, 1, 70, 24,\n                                  29, 53, 14, 6, 65, 7, 16, 0, 68, 66, 77, 93,\n                                  6, 16, 109, 116, 118, 11, 71, 68, 7, 16, 0,\n                                  76, 67, 12, 4, 64, 71, 78, 64, 78, 77, 91, 5,\n                                  71, 77, 1, 75, 76, 88, 8, 65, 67, 71, 3, 4,\n                                  22, 0, 0, 0, 68, 92, 97, 3, 1, 66, 52, 7, 69,\n                                  99, 80, 82, 1, 72, 83, 76, 88, 65, 83, 79, 78,\n                                  95, 95, 96, 97, 20, 64, 4, 82, 65, 80, 73, 78,\n                                  72, 87, 79, 94, 14, 73, 64, 89, 81, 69, 72, 1,\n                                  7, 2, 64, 13, 10, 74, 64, 1, 65, 2, 74, 12, 0,\n                                  12, 19, 8, 17, 17, 11, 67, 11, 2, 64, 4, 84,\n                                  86, 75, 79, 69, 74, 71, 5, 69, 71, 65, 0, 71,\n                                  72, 65, 88, 89, 75, 95, 68, 75, 6, 66, 70, 16,\n                                  1, 65, 71, 16, 71, 80, 1, 91, 24, 30, 25, 24,\n                                  30, 23, 10, 26, 25, 65, 9, 12, 4, 1, 72, 6, 1,\n                                  0, 4, 65, 71, 3, 65, 82, 71, 71, 78, 73, 89,\n                                  40, 45, 38, 40, 38, 33, 30, 33, 26, 19, 21,\n                                  13, 3, 1, 83, 21, 17, 64, 19, 11, 10, 5, 0,\n                                  66, 68, 72, 85, 70, 80, 94, 87, 100, 66, 31,\n                                  22, 14, 5, 5, 64, 68, 72, 76, 5, 45, 29, 23,\n                                  17, 25, 8, 2, 67, 69, 72, 33, 20, 11, 5, 10,\n                                  0, 68, 73, 82, 79, 12, 2, 0, 67, 64, 74, 79,\n                                  86, 65, 39, 22, 14, 6, 14, 1, 66, 68, 74, 62,\n                                  83, 74, 66, 66, 69, 1, 7, 8, 66, 6, 12, 12,\n                                  77, 71, 72, 3, 13, 3, 1, 10, 15, 18, 68, 2,\n                                  13, 14, 78, 73, 78, 84, 79, 70, 76, 72, 73,\n                                  70, 66, 72, 72, 71, 66, 74, 74, 81, 87, 72,\n                                  98, 76, 65, 70, 6, 69, 65, 13, 66, 68, 66, 10,\n                                  72, 72, 89, 33, 35, 36, 30, 21, 31, 27, 23,\n                                  21, 19, 19, 15, 66, 67, 74, 7, 8, 1, 77, 64,\n                                  65, 72, 73, 74, 73, 75, 89, 83, 89, 40, 39,\n                                  37, 33, 24, 26, 23, 13, 17, 12, 10, 0, 66, 72,\n                                  79, 19, 21, 65, 20, 22, 11, 5, 6, 3, 0, 2, 67,\n                                  74, 77, 81, 86, 96, 71, 81, 90, 92, 79, 84,\n                                  67, 67, 66, 35, 7, 6, 68, 16, 46, 33, 52, 7,\n                                  39, 34, 13, 65, 74, 79, 105, 107, 112, 70, 42,\n                                  28, 19, 9, 12, 2, 65, 68, 77, 83, 75, 65, 70,\n                                  5, 7, 64, 0, 7, 10, 11, 6, 14, 14, 1, 39, 35,\n                                  26, 19, 13, 7, 76, 83, 89 },\n\n                                {\n\n                                45,\n                                  6, 79, 45, 6, 79, 79, 65, 21, 11, 1, 71, 23,\n                                  28, 53, 14, 8, 65, 7, 17, 0, 69, 66, 78, 94,\n                                  5, 15, 110, 117, 119, 14, 70, 68, 7, 17, 0,\n                                  75, 66, 13, 3, 0, 70, 77, 65, 78, 77, 91, 5,\n                                  70, 77, 1, 75, 75, 88, 8, 65, 67, 71, 3, 4,\n                                  22, 0, 0, 0, 67, 92, 97, 3, 1, 67, 52, 7, 69,\n                                  98, 80, 82, 1, 71, 81, 74, 86, 64, 81, 78, 76,\n                                  94, 94, 95, 96, 21, 64, 5, 82, 64, 79, 73, 76,\n                                  72, 86, 79, 93, 14, 73, 64, 87, 81, 68, 71, 1,\n                                  7, 2, 0, 13, 10, 74, 64, 1, 65, 2, 74, 12, 0,\n                                  12, 19, 7, 17, 17, 11, 69, 11, 2, 66, 3, 85,\n                                  86, 74, 79, 69, 73, 71, 6, 69, 71, 65, 2, 71,\n                                  72, 65, 89, 88, 74, 95, 68, 75, 7, 65, 71, 16,\n                                  1, 65, 72, 17, 72, 81, 1, 92, 23, 29, 25, 24,\n                                  29, 23, 10, 25, 24, 66, 8, 12, 4, 1, 72, 5, 0,\n                                  64, 3, 65, 72, 2, 65, 84, 72, 71, 79, 74, 89,\n                                  39, 43, 37, 38, 36, 31, 28, 31, 24, 16, 19,\n                                  11, 0, 65, 86, 19, 15, 65, 17, 8, 7, 2, 65,\n                                  69, 70, 75, 87, 71, 82, 95, 88, 100, 65, 32,\n                                  22, 15, 5, 5, 64, 68, 72, 75, 5, 45, 30, 23,\n                                  17, 26, 9, 2, 66, 69, 71, 34, 20, 12, 5, 11,\n                                  1, 68, 72, 81, 78, 13, 3, 1, 67, 64, 74, 78,\n                                  84, 64, 39, 22, 14, 7, 14, 1, 65, 68, 73, 62,\n                                  82, 73, 65, 66, 69, 1, 7, 8, 66, 7, 12, 13,\n                                  77, 71, 73, 3, 13, 2, 0, 9, 14, 18, 69, 1, 13,\n                                  14, 78, 74, 79, 83, 78, 69, 76, 71, 73, 69,\n                                  66, 72, 71, 70, 65, 74, 74, 81, 87, 71, 98,\n                                  76, 65, 70, 7, 69, 65, 14, 67, 68, 66, 10, 73,\n                                  72, 90, 32, 34, 36, 29, 20, 31, 27, 22, 20,\n                                  19, 18, 14, 67, 68, 75, 6, 7, 64, 79, 66, 67,\n                                  73, 73, 74, 73, 75, 88, 84, 88, 38, 37, 35,\n                                  31, 21, 24, 21, 11, 15, 9, 8, 66, 68, 73, 79,\n                                  18, 20, 67, 18, 19, 9, 3, 4, 1, 65, 64, 69,\n                                  76, 79, 83, 87, 98, 73, 83, 92, 91, 78, 83,\n                                  66, 66, 65, 36, 8, 7, 68, 17, 48, 34, 54, 8,\n                                  38, 33, 11, 68, 77, 81, 108, 109, 114, 69, 42,\n                                  28, 19, 9, 12, 2, 65, 68, 76, 82, 75, 64, 69,\n                                  6, 7, 0, 1, 7, 10, 11, 6, 15, 14, 1, 38, 34,\n                                  24, 17, 12, 6, 79, 84, 90 },\n\n                                {\n\n                                43,\n                                  6, 79, 43, 6, 79, 78, 0, 21, 11, 0, 73, 21,\n                                  27, 53, 14, 10, 65, 8, 18, 0, 70, 66, 79, 95,\n                                  5, 13, 112, 118, 119, 17, 69, 68, 8, 18, 0,\n                                  75, 65, 13, 3, 0, 70, 76, 65, 79, 77, 91, 5,\n                                  70, 76, 1, 76, 75, 88, 9, 65, 67, 71, 4, 4,\n                                  22, 0, 0, 0, 67, 93, 97, 4, 0, 67, 52, 7, 69,\n                                  97, 79, 82, 2, 70, 79, 72, 85, 0, 79, 77, 74,\n                                  93, 94, 94, 95, 21, 64, 6, 81, 64, 79, 72, 74,\n                                  72, 86, 78, 92, 14, 73, 0, 86, 80, 67, 71, 1,\n                                  7, 2, 0, 14, 11, 75, 64, 1, 65, 2, 74, 12, 64,\n                                  11, 19, 6, 17, 17, 11, 71, 11, 1, 68, 2, 86,\n                                  85, 73, 78, 68, 73, 70, 7, 68, 70, 64, 3, 71,\n                                  72, 65, 90, 88, 73, 95, 68, 75, 8, 65, 72, 17,\n                                  1, 65, 73, 18, 72, 82, 1, 93, 21, 28, 24, 23,\n                                  28, 22, 9, 24, 24, 68, 7, 11, 4, 1, 73, 4, 64,\n                                  65, 2, 66, 73, 1, 66, 86, 73, 72, 80, 75, 89,\n                                  37, 42, 35, 36, 34, 29, 26, 29, 21, 14, 17, 8,\n                                  65, 67, 88, 17, 13, 67, 15, 6, 5, 0, 67, 71,\n                                  73, 77, 90, 72, 84, 96, 89, 100, 65, 32, 22,\n                                  15, 5, 5, 64, 68, 72, 75, 5, 45, 30, 23, 17,\n                                  27, 9, 3, 66, 68, 71, 35, 21, 12, 5, 11, 1,\n                                  67, 72, 80, 77, 14, 4, 1, 67, 0, 73, 77, 83,\n                                  64, 39, 22, 14, 7, 15, 2, 65, 67, 72, 62, 82,\n                                  73, 65, 66, 69, 1, 7, 8, 66, 7, 12, 13, 77,\n                                  71, 73, 2, 14, 1, 64, 8, 13, 18, 71, 0, 13,\n                                  14, 79, 75, 79, 83, 77, 68, 75, 71, 72, 69,\n                                  65, 73, 71, 70, 65, 75, 74, 81, 86, 70, 98,\n                                  76, 65, 70, 8, 69, 65, 15, 67, 69, 66, 11, 74,\n                                  72, 91, 31, 34, 35, 28, 19, 30, 26, 21, 19,\n                                  18, 17, 13, 68, 69, 76, 4, 6, 65, 81, 67, 68,\n                                  74, 74, 75, 73, 75, 88, 84, 88, 35, 34, 33,\n                                  29, 18, 22, 19, 8, 13, 7, 6, 68, 70, 75, 80,\n                                  16, 18, 68, 16, 17, 7, 1, 1, 64, 67, 66, 71,\n                                  79, 81, 85, 89, 99, 75, 85, 93, 90, 77, 82,\n                                  65, 65, 64, 38, 9, 8, 68, 18, 49, 36, 55, 9,\n                                  36, 31, 8, 71, 80, 84, 111, 111, 115, 69, 42,\n                                  28, 19, 9, 12, 2, 65, 68, 76, 81, 74, 0, 69,\n                                  7, 8, 0, 2, 8, 11, 12, 6, 15, 14, 1, 37, 32,\n                                  22, 15, 10, 4, 81, 86, 91 },\n\n                                {\n\n                                42,\n                                  6, 79, 42, 6, 79, 76, 1, 21, 11, 0, 74, 20,\n                                  25, 53, 14, 13, 66, 9, 18, 0, 70, 65, 80, 96,\n                                  4, 11, 114, 119, 120, 20, 67, 68, 9, 18, 0,\n                                  75, 64, 13, 2, 0, 70, 76, 65, 79, 76, 91, 5,\n                                  70, 75, 0, 76, 75, 88, 9, 64, 66, 70, 4, 4,\n                                  22, 0, 0, 0, 66, 93, 97, 4, 64, 67, 52, 7, 69,\n                                  96, 78, 82, 2, 68, 78, 70, 83, 1, 78, 75, 72,\n                                  92, 93, 93, 95, 22, 64, 7, 80, 64, 78, 71, 72,\n                                  72, 86, 78, 90, 15, 72, 0, 85, 80, 67, 71, 2,\n                                  8, 3, 1, 14, 11, 75, 65, 1, 65, 2, 74, 12, 64,\n                                  10, 19, 6, 17, 17, 10, 73, 11, 1, 69, 1, 87,\n                                  84, 72, 77, 67, 72, 69, 8, 67, 70, 0, 4, 71,\n                                  72, 64, 91, 87, 72, 95, 67, 75, 8, 65, 73, 18,\n                                  1, 65, 75, 19, 73, 83, 1, 93, 20, 27, 24, 22,\n                                  27, 21, 8, 24, 24, 69, 6, 11, 4, 1, 73, 4, 64,\n                                  66, 2, 67, 74, 1, 67, 88, 74, 73, 81, 76, 89,\n                                  35, 41, 33, 34, 33, 27, 23, 27, 19, 12, 15, 6,\n                                  68, 69, 91, 15, 12, 69, 12, 4, 3, 65, 70, 73,\n                                  76, 79, 92, 73, 85, 98, 89, 100, 65, 32, 23,\n                                  15, 5, 5, 64, 68, 72, 74, 6, 46, 30, 23, 17,\n                                  28, 10, 4, 66, 67, 70, 36, 22, 12, 6, 12, 2,\n                                  67, 71, 79, 77, 16, 4, 1, 66, 1, 72, 77, 82,\n                                  0, 40, 23, 14, 7, 16, 3, 64, 66, 71, 62, 82,\n                                  73, 64, 66, 69, 1, 7, 8, 65, 7, 13, 14, 77,\n                                  71, 73, 1, 14, 0, 65, 7, 13, 18, 72, 64, 12,\n                                  14, 80, 76, 80, 82, 77, 67, 75, 70, 72, 68,\n                                  64, 73, 71, 70, 65, 76, 74, 81, 86, 69, 98,\n                                  76, 64, 70, 8, 69, 65, 16, 67, 69, 66, 12, 74,\n                                  73, 91, 30, 34, 35, 28, 18, 29, 25, 20, 19,\n                                  17, 16, 12, 69, 70, 77, 3, 4, 67, 83, 68, 69,\n                                  75, 75, 75, 73, 74, 88, 85, 87, 33, 32, 31,\n                                  26, 16, 20, 17, 6, 11, 5, 4, 70, 72, 76, 81,\n                                  14, 16, 69, 14, 15, 5, 64, 64, 66, 69, 68, 73,\n                                  81, 83, 87, 91, 100, 77, 87, 95, 89, 75, 81,\n                                  65, 64, 0, 40, 10, 9, 68, 19, 51, 37, 57, 9,\n                                  35, 29, 6, 74, 82, 87, 113, 113, 116, 69, 42,\n                                  28, 19, 9, 12, 2, 65, 68, 75, 80, 73, 1, 68,\n                                  8, 9, 1, 3, 9, 12, 13, 7, 16, 15, 1, 35, 31,\n                                  21, 14, 8, 2, 83, 88, 92 },\n\n                                {\n\n                                41,\n                                  6, 79, 41, 6, 79, 74, 3, 22, 11, 64, 76, 18,\n                                  24, 53, 14, 15, 66, 10, 19, 0, 71, 65, 81, 97,\n                                  4, 9, 115, 120, 120, 23, 66, 68, 10, 19, 0,\n                                  74, 0, 14, 2, 0, 69, 75, 66, 80, 76, 91, 5,\n                                  70, 75, 0, 76, 75, 88, 10, 64, 66, 70, 5, 4,\n                                  22, 0, 0, 0, 66, 93, 97, 5, 65, 67, 52, 7, 69,\n                                  95, 77, 82, 3, 67, 76, 68, 82, 2, 76, 74, 70,\n                                  91, 92, 92, 94, 23, 64, 8, 79, 64, 78, 71, 70,\n                                  72, 85, 77, 89, 15, 72, 1, 83, 79, 66, 71, 2,\n                                  8, 3, 2, 15, 12, 76, 65, 1, 65, 2, 74, 12, 65,\n                                  10, 19, 5, 17, 17, 10, 75, 11, 0, 71, 0, 88,\n                                  83, 71, 76, 66, 71, 69, 9, 67, 69, 1, 5, 71,\n                                  72, 64, 92, 87, 71, 95, 67, 75, 9, 65, 74, 19,\n                                  1, 65, 76, 20, 73, 84, 1, 94, 18, 26, 23, 21,\n                                  26, 20, 8, 23, 23, 70, 5, 11, 4, 1, 74, 3, 65,\n                                  67, 1, 68, 75, 0, 67, 90, 75, 73, 82, 77, 89,\n                                  34, 39, 32, 32, 31, 25, 21, 25, 16, 9, 13, 3,\n                                  70, 72, 93, 13, 10, 70, 10, 2, 0, 68, 72, 76,\n                                  78, 81, 95, 74, 87, 99, 90, 100, 65, 33, 23,\n                                  15, 5, 5, 64, 68, 72, 74, 6, 46, 30, 23, 17,\n                                  29, 10, 4, 65, 67, 69, 37, 22, 13, 6, 13, 2,\n                                  66, 71, 78, 76, 17, 5, 2, 66, 2, 71, 76, 81,\n                                  0, 40, 23, 14, 7, 17, 3, 0, 65, 70, 62, 81,\n                                  72, 64, 66, 69, 1, 7, 8, 65, 7, 13, 14, 77,\n                                  71, 73, 1, 15, 64, 66, 6, 12, 18, 73, 65, 12,\n                                  14, 80, 77, 80, 81, 76, 66, 74, 70, 71, 68, 0,\n                                  73, 71, 70, 64, 76, 74, 81, 85, 68, 98, 76,\n                                  64, 70, 9, 69, 65, 17, 67, 69, 66, 13, 75, 73,\n                                  92, 29, 33, 34, 27, 17, 28, 24, 19, 18, 16,\n                                  15, 11, 70, 71, 78, 1, 3, 68, 85, 70, 70, 76,\n                                  75, 76, 73, 74, 88, 85, 86, 31, 30, 29, 24,\n                                  13, 18, 15, 3, 9, 3, 2, 73, 74, 78, 82, 12,\n                                  15, 71, 12, 13, 3, 66, 66, 68, 71, 70, 75, 84,\n                                  85, 89, 93, 101, 79, 89, 96, 88, 74, 80, 64,\n                                  0, 1, 41, 11, 10, 68, 20, 52, 39, 58, 10, 33,\n                                  28, 3, 77, 85, 90, 116, 115, 117, 69, 42, 28,\n                                  19, 9, 12, 2, 65, 68, 75, 79, 72, 2, 67, 9, 9,\n                                  1, 4, 9, 12, 13, 7, 16, 15, 1, 34, 29, 19, 12,\n                                  6, 0, 85, 90, 93 },\n\n                                {\n\n                                40,\n                                  6, 79, 40, 6, 79, 72, 4, 22, 11, 64, 77, 17,\n                                  23, 53, 14, 17, 66, 11, 20, 0, 72, 65, 82, 98,\n                                  3, 7, 117, 121, 121, 26, 65, 68, 11, 20, 0,\n                                  74, 1, 14, 1, 0, 69, 74, 66, 80, 76, 91, 5,\n                                  70, 74, 0, 76, 75, 88, 10, 64, 66, 70, 5, 4,\n                                  22, 0, 0, 0, 65, 93, 97, 5, 66, 67, 52, 7, 69,\n                                  94, 76, 82, 3, 66, 74, 66, 80, 3, 74, 73, 68,\n                                  90, 91, 91, 93, 24, 64, 9, 78, 64, 77, 70, 68,\n                                  72, 85, 77, 88, 15, 72, 1, 82, 79, 65, 71, 2,\n                                  8, 3, 3, 15, 12, 76, 65, 1, 65, 2, 74, 12, 65,\n                                  9, 19, 4, 17, 17, 10, 77, 11, 0, 73, 64, 89,\n                                  82, 70, 75, 65, 70, 68, 10, 66, 69, 2, 6, 71,\n                                  72, 64, 93, 86, 70, 95, 67, 75, 10, 65, 75,\n                                  20, 1, 65, 77, 21, 74, 85, 1, 95, 17, 25, 23,\n                                  20, 25, 19, 7, 22, 23, 71, 4, 11, 4, 1, 74, 2,\n                                  66, 68, 0, 69, 76, 64, 68, 92, 76, 74, 83, 78,\n                                  89, 32, 38, 30, 30, 29, 23, 19, 23, 14, 7, 11,\n                                  1, 73, 74, 96, 11, 8, 72, 8, 0, 65, 70, 74,\n                                  78, 81, 83, 97, 75, 89, 100, 91, 100, 65, 33,\n                                  23, 15, 5, 5, 64, 68, 72, 73, 6, 46, 30, 23,\n                                  17, 30, 11, 5, 65, 66, 68, 38, 23, 13, 6, 14,\n                                  3, 66, 70, 77, 75, 18, 6, 2, 66, 3, 70, 75,\n                                  80, 1, 40, 23, 14, 7, 18, 4, 1, 64, 69, 62,\n                                  81, 72, 0, 66, 69, 1, 7, 8, 65, 7, 13, 15, 77,\n                                  71, 73, 0, 15, 65, 67, 5, 11, 18, 74, 66, 12,\n                                  14, 81, 78, 81, 80, 75, 65, 74, 69, 71, 67, 1,\n                                  73, 71, 70, 64, 77, 74, 81, 85, 67, 98, 76,\n                                  64, 70, 10, 69, 65, 18, 67, 69, 66, 14, 76,\n                                  73, 93, 28, 33, 34, 26, 16, 27, 23, 18, 17,\n                                  15, 14, 10, 71, 72, 79, 0, 2, 70, 87, 71, 71,\n                                  77, 76, 76, 73, 74, 88, 86, 85, 29, 28, 27,\n                                  22, 10, 16, 13, 1, 7, 1, 0, 75, 76, 79, 83,\n                                  10, 13, 72, 10, 11, 1, 68, 68, 70, 73, 72, 77,\n                                  86, 87, 91, 95, 102, 81, 91, 98, 87, 73, 79,\n                                  0, 1, 2, 43, 12, 11, 68, 21, 54, 40, 60, 11,\n                                  32, 26, 1, 80, 88, 93, 119, 117, 118, 69, 42,\n                                  28, 19, 9, 12, 2, 65, 68, 74, 78, 71, 3, 66,\n                                  10, 10, 2, 5, 10, 13, 14, 7, 17, 15, 1, 33,\n                                  28, 17, 10, 4, 65, 87, 92, 94 },\n\n                                {\n\n                                38,\n                                  5, 80, 38, 5, 80, 71, 5, 22, 11, 65, 79, 15,\n                                  21, 52, 14, 19, 67, 11, 20, 64, 73, 65, 84,\n                                  100, 2, 5, 119, 122, 122, 28, 64, 69, 11, 20,\n                                  64, 74, 2, 14, 0, 0, 69, 74, 67, 81, 76, 92,\n                                  5, 70, 74, 64, 77, 75, 88, 10, 64, 66, 70, 5,\n                                  3, 22, 0, 0, 0, 65, 94, 97, 5, 67, 68, 52, 6,\n                                  69, 93, 76, 82, 3, 65, 73, 65, 79, 4, 73, 72,\n                                  67, 89, 91, 90, 93, 24, 64, 9, 78, 64, 77, 70,\n                                  67, 72, 85, 77, 87, 15, 72, 1, 81, 79, 65, 71,\n                                  2, 8, 3, 3, 15, 12, 77, 66, 1, 66, 2, 74, 11,\n                                  66, 8, 19, 3, 16, 17, 9, 79, 10, 64, 75, 65,\n                                  90, 82, 70, 75, 65, 70, 68, 11, 66, 69, 2, 7,\n                                  72, 72, 64, 95, 86, 70, 95, 67, 76, 10, 65,\n                                  76, 20, 1, 65, 79, 21, 75, 86, 1, 96, 15, 24,\n                                  22, 19, 24, 18, 6, 21, 22, 73, 3, 10, 3, 1,\n                                  75, 1, 67, 69, 64, 70, 77, 65, 69, 94, 78, 75,\n                                  85, 80, 89, 30, 36, 28, 28, 27, 20, 16, 20,\n                                  11, 4, 8, 65, 76, 77, 99, 9, 6, 74, 5, 66, 68,\n                                  73, 77, 81, 84, 86, 100, 76, 91, 102, 92, 101,\n                                  65, 33, 23, 15, 5, 5, 65, 68, 72, 73, 6, 46,\n                                  30, 23, 17, 31, 11, 5, 65, 66, 68, 38, 23, 13,\n                                  6, 14, 3, 66, 70, 76, 75, 19, 6, 2, 66, 3, 70,\n                                  75, 79, 1, 40, 23, 14, 7, 18, 4, 1, 64, 69,\n                                  62, 81, 72, 0, 66, 69, 1, 7, 8, 65, 7, 13, 15,\n                                  77, 71, 74, 64, 15, 66, 68, 4, 10, 17, 76, 68,\n                                  11, 13, 82, 80, 82, 80, 75, 64, 74, 69, 71,\n                                  67, 1, 74, 71, 70, 64, 78, 74, 81, 85, 67, 99,\n                                  76, 64, 70, 10, 70, 65, 18, 68, 70, 66, 14,\n                                  77, 74, 94, 27, 32, 33, 25, 14, 26, 22, 17,\n                                  16, 14, 13, 9, 72, 74, 81, 65, 0, 72, 89, 73,\n                                  73, 78, 77, 77, 73, 74, 88, 87, 85, 26, 25,\n                                  25, 19, 7, 13, 10, 65, 4, 65, 66, 78, 79, 81,\n                                  84, 8, 11, 74, 8, 8, 65, 71, 71, 73, 75, 75,\n                                  80, 89, 89, 94, 97, 104, 83, 93, 100, 86, 72,\n                                  78, 0, 1, 2, 44, 12, 11, 68, 21, 55, 41, 61,\n                                  11, 30, 24, 65, 84, 91, 96, 122, 120, 120, 69,\n                                  42, 27, 18, 9, 12, 2, 66, 68, 74, 78, 71, 3,\n                                  66, 11, 10, 2, 5, 10, 13, 14, 7, 17, 15, 0,\n                                  31, 26, 15, 8, 2, 67, 90, 94, 95 },\n\n                                {\n\n                                37,\n                                  5, 80, 37, 5, 80, 69, 7, 23, 12, 65, 80, 14,\n                                  20, 52, 14, 22, 67, 12, 21, 64, 73, 64, 85,\n                                  101, 2, 4, 120, 123, 122, 31, 1, 69, 12, 21,\n                                  64, 73, 4, 15, 0, 1, 68, 73, 67, 81, 75, 92,\n                                  5, 69, 73, 64, 77, 74, 88, 11, 0, 65, 69, 6,\n                                  3, 22, 0, 0, 0, 64, 94, 97, 6, 67, 68, 52, 6,\n                                  69, 91, 75, 82, 4, 0, 71, 0, 77, 6, 71, 70,\n                                  65, 87, 90, 89, 92, 25, 0, 10, 77, 0, 76, 69,\n                                  65, 71, 84, 76, 85, 16, 71, 2, 79, 78, 64, 70,\n                                  3, 9, 4, 4, 16, 13, 77, 66, 2, 66, 2, 73, 11,\n                                  66, 8, 19, 3, 16, 17, 9, 80, 10, 64, 76, 66,\n                                  90, 81, 69, 74, 64, 69, 67, 12, 65, 68, 3, 9,\n                                  72, 72, 0, 96, 85, 69, 95, 66, 76, 11, 64, 76,\n                                  21, 1, 65, 80, 22, 75, 87, 1, 96, 14, 24, 22,\n                                  19, 24, 18, 6, 21, 22, 74, 3, 10, 3, 1, 75, 1,\n                                  67, 69, 64, 70, 78, 65, 69, 95, 79, 75, 86,\n                                  81, 89, 29, 35, 27, 27, 26, 18, 14, 18, 9, 2,\n                                  6, 67, 78, 79, 101, 8, 5, 75, 3, 68, 70, 75,\n                                  79, 83, 86, 88, 102, 76, 92, 103, 92, 101, 64,\n                                  34, 24, 16, 6, 5, 65, 67, 71, 72, 7, 47, 31,\n                                  24, 17, 32, 12, 6, 64, 65, 67, 39, 24, 14, 7,\n                                  15, 4, 65, 69, 74, 74, 21, 7, 3, 65, 4, 69,\n                                  74, 77, 2, 41, 24, 15, 8, 19, 5, 2, 0, 68, 62,\n                                  80, 71, 1, 66, 68, 1, 8, 9, 64, 8, 14, 16, 76,\n                                  71, 74, 64, 16, 66, 68, 3, 10, 17, 77, 69, 11,\n                                  13, 82, 81, 82, 79, 74, 0, 73, 68, 70, 66, 2,\n                                  74, 70, 69, 0, 78, 73, 80, 84, 66, 99, 76, 0,\n                                  70, 11, 70, 65, 19, 68, 70, 65, 15, 77, 74,\n                                  94, 27, 32, 33, 25, 13, 26, 22, 17, 16, 14,\n                                  13, 9, 72, 75, 82, 66, 64, 73, 90, 74, 74, 78,\n                                  77, 77, 72, 73, 87, 87, 84, 24, 23, 23, 17, 5,\n                                  11, 8, 67, 2, 67, 68, 80, 81, 82, 84, 7, 10,\n                                  75, 7, 6, 67, 73, 73, 75, 77, 77, 82, 91, 90,\n                                  96, 98, 105, 84, 94, 101, 84, 70, 76, 1, 2, 3,\n                                  46, 13, 12, 68, 22, 57, 43, 62, 12, 29, 23,\n                                  67, 87, 93, 98, 124, 122, 121, 68, 43, 27, 18,\n                                  9, 13, 2, 66, 68, 73, 77, 70, 4, 65, 13, 11,\n                                  3, 6, 11, 14, 15, 8, 18, 16, 0, 30, 25, 14, 7,\n                                  1, 68, 92, 95, 95 },\n\n                                {\n\n                                36,\n                                  5, 80, 36, 5, 80, 67, 8, 23, 12, 65, 81, 13,\n                                  19, 52, 14, 24, 67, 13, 22, 64, 74, 64, 86,\n                                  102, 1, 2, 122, 124, 123, 34, 2, 69, 13, 22,\n                                  64, 73, 5, 15, 64, 1, 68, 72, 67, 81, 75, 92,\n                                  5, 69, 72, 64, 77, 74, 88, 11, 0, 65, 69, 6,\n                                  3, 22, 0, 0, 0, 0, 94, 97, 6, 68, 68, 52, 6,\n                                  69, 90, 74, 82, 4, 1, 69, 2, 76, 7, 69, 69, 0,\n                                  86, 89, 88, 91, 26, 0, 11, 76, 0, 76, 68, 0,\n                                  71, 84, 76, 84, 16, 71, 2, 78, 78, 0, 70, 3,\n                                  9, 4, 5, 16, 13, 78, 66, 2, 66, 2, 73, 11, 66,\n                                  7, 19, 2, 16, 17, 9, 82, 10, 64, 78, 67, 91,\n                                  80, 68, 73, 0, 68, 66, 13, 64, 68, 4, 10, 72,\n                                  72, 0, 97, 85, 68, 95, 66, 76, 12, 64, 77, 22,\n                                  1, 65, 81, 23, 76, 88, 1, 97, 12, 23, 21, 18,\n                                  23, 17, 5, 20, 22, 75, 2, 10, 3, 1, 75, 0, 68,\n                                  70, 65, 71, 79, 66, 70, 97, 80, 76, 87, 82,\n                                  89, 27, 34, 25, 25, 24, 16, 12, 16, 6, 0, 4,\n                                  70, 81, 81, 104, 6, 3, 77, 1, 70, 72, 77, 81,\n                                  85, 89, 90, 104, 77, 94, 104, 93, 101, 64, 34,\n                                  24, 16, 6, 5, 65, 67, 71, 71, 7, 47, 31, 24,\n                                  17, 33, 12, 7, 64, 64, 66, 40, 25, 14, 7, 16,\n                                  4, 65, 68, 73, 73, 22, 8, 3, 65, 5, 68, 73,\n                                  76, 2, 41, 24, 15, 8, 20, 6, 3, 1, 67, 62, 80,\n                                  71, 1, 66, 68, 1, 8, 9, 64, 8, 14, 17, 76, 71,\n                                  74, 65, 16, 67, 69, 2, 9, 17, 78, 70, 11, 13,\n                                  83, 82, 83, 78, 73, 1, 73, 68, 70, 65, 3, 74,\n                                  70, 69, 0, 79, 73, 80, 84, 65, 99, 76, 0, 70,\n                                  12, 70, 65, 20, 68, 70, 65, 16, 78, 74, 95,\n                                  26, 32, 33, 24, 12, 25, 21, 16, 15, 13, 12, 8,\n                                  73, 76, 83, 68, 65, 75, 92, 75, 75, 79, 78,\n                                  77, 72, 73, 87, 88, 83, 22, 21, 21, 15, 2, 9,\n                                  6, 70, 0, 69, 70, 82, 83, 83, 85, 5, 8, 76, 5,\n                                  4, 69, 75, 75, 77, 79, 79, 84, 93, 92, 98,\n                                  100, 106, 86, 96, 103, 83, 69, 75, 2, 3, 4,\n                                  48, 14, 13, 68, 23, 58, 44, 62, 13, 28, 21,\n                                  70, 90, 96, 101, 126, 124, 122, 68, 43, 27,\n                                  18, 9, 13, 2, 66, 68, 72, 76, 69, 5, 64, 14,\n                                  12, 4, 7, 12, 15, 16, 8, 19, 16, 0, 29, 23,\n                                  12, 5, 64, 70, 94, 97, 96 },\n\n                                {\n\n                                35,\n                                  5, 80, 35, 5, 80, 65, 10, 24, 12, 66, 83, 11,\n                                  18, 52, 14, 26, 67, 14, 23, 64, 75, 64, 87,\n                                  103, 1, 0, 123, 125, 123, 37, 3, 69, 14, 23,\n                                  64, 72, 6, 16, 64, 1, 67, 71, 68, 82, 75, 92,\n                                  5, 69, 72, 64, 77, 74, 88, 12, 0, 65, 69, 7,\n                                  3, 22, 0, 0, 0, 0, 94, 97, 7, 69, 68, 52, 6,\n                                  69, 89, 73, 82, 5, 2, 67, 4, 74, 8, 67, 68, 2,\n                                  85, 88, 87, 90, 27, 0, 12, 75, 0, 75, 68, 2,\n                                  71, 83, 75, 83, 16, 71, 3, 76, 77, 1, 70, 3,\n                                  9, 4, 6, 17, 14, 78, 66, 2, 66, 2, 73, 11, 67,\n                                  7, 19, 1, 16, 17, 9, 84, 10, 65, 80, 68, 92,\n                                  79, 67, 72, 1, 67, 66, 14, 64, 67, 5, 11, 72,\n                                  72, 0, 98, 84, 67, 95, 66, 76, 13, 64, 78, 23,\n                                  1, 65, 82, 24, 76, 89, 1, 98, 11, 22, 21, 17,\n                                  22, 16, 5, 19, 21, 76, 1, 10, 3, 1, 76, 64,\n                                  69, 71, 66, 72, 80, 67, 70, 99, 81, 76, 88,\n                                  83, 89, 26, 32, 24, 23, 22, 14, 10, 14, 4, 66,\n                                  2, 72, 83, 84, 106, 4, 1, 78, 64, 72, 75, 80,\n                                  83, 88, 91, 92, 107, 78, 96, 105, 94, 101, 64,\n                                  35, 24, 16, 6, 5, 65, 67, 71, 71, 7, 47, 31,\n                                  24, 17, 34, 13, 7, 0, 64, 65, 41, 25, 15, 7,\n                                  17, 5, 64, 68, 72, 72, 23, 9, 4, 65, 6, 67,\n                                  72, 75, 3, 41, 24, 15, 8, 21, 6, 4, 2, 66, 62,\n                                  79, 70, 2, 66, 68, 1, 8, 9, 64, 8, 14, 17, 76,\n                                  71, 74, 65, 17, 68, 70, 1, 8, 17, 79, 71, 11,\n                                  13, 83, 83, 83, 77, 72, 2, 72, 67, 69, 65, 4,\n                                  74, 70, 69, 1, 79, 73, 80, 83, 64, 99, 76, 0,\n                                  70, 13, 70, 65, 21, 68, 70, 65, 17, 79, 74,\n                                  96, 25, 31, 32, 23, 11, 24, 20, 15, 14, 12,\n                                  11, 7, 74, 77, 84, 69, 66, 76, 94, 77, 76, 80,\n                                  78, 78, 72, 73, 87, 88, 82, 20, 19, 19, 13,\n                                  64, 7, 4, 72, 65, 71, 72, 85, 85, 85, 86, 3,\n                                  7, 78, 3, 2, 71, 77, 77, 79, 81, 81, 86, 96,\n                                  94, 100, 102, 107, 88, 98, 104, 82, 68, 74, 3,\n                                  4, 5, 49, 15, 14, 68, 24, 60, 46, 62, 14, 26,\n                                  20, 72, 93, 99, 104, 126, 126, 123, 68, 43,\n                                  27, 18, 9, 13, 2, 66, 68, 72, 75, 68, 6, 0,\n                                  15, 12, 4, 8, 12, 15, 16, 8, 19, 16, 0, 28,\n                                  22, 10, 3, 66, 72, 96, 99, 97 },\n\n                                {\n\n                                33,\n                                  5, 80, 33, 5, 80, 64, 11, 24, 12, 66, 84, 10,\n                                  16, 52, 14, 29, 68, 15, 23, 64, 76, 64, 88,\n                                  104, 0, 65, 125, 126, 124, 40, 4, 69, 15, 23,\n                                  64, 72, 7, 16, 65, 1, 67, 71, 68, 82, 74, 92,\n                                  5, 69, 71, 65, 78, 74, 88, 12, 1, 65, 68, 7,\n                                  3, 22, 0, 0, 0, 1, 95, 97, 7, 70, 68, 52, 6,\n                                  69, 88, 72, 82, 5, 4, 66, 6, 73, 9, 66, 66, 4,\n                                  84, 88, 86, 90, 27, 0, 13, 74, 0, 75, 67, 4,\n                                  71, 83, 75, 82, 16, 70, 3, 75, 77, 1, 70, 4,\n                                  9, 4, 6, 17, 14, 79, 67, 2, 66, 2, 73, 11, 67,\n                                  6, 19, 1, 16, 17, 8, 86, 10, 65, 82, 69, 93,\n                                  78, 66, 71, 2, 67, 65, 15, 0, 67, 6, 12, 72,\n                                  72, 1, 99, 84, 66, 95, 66, 76, 13, 64, 79, 24,\n                                  1, 65, 84, 25, 77, 90, 1, 99, 9, 21, 20, 16,\n                                  21, 15, 4, 18, 21, 78, 0, 9, 3, 1, 76, 65, 69,\n                                  72, 66, 73, 81, 68, 71, 101, 82, 77, 89, 84,\n                                  89, 24, 31, 22, 21, 20, 12, 7, 12, 1, 68, 0,\n                                  75, 86, 86, 109, 2, 0, 80, 67, 74, 77, 82, 86,\n                                  90, 94, 94, 109, 79, 97, 107, 95, 101, 64, 35,\n                                  25, 16, 6, 5, 65, 67, 71, 70, 8, 48, 31, 24,\n                                  17, 35, 13, 8, 0, 0, 65, 42, 26, 15, 7, 17, 5,\n                                  64, 67, 71, 72, 24, 9, 4, 65, 7, 66, 72, 74,\n                                  3, 42, 24, 15, 8, 22, 7, 4, 3, 65, 62, 79, 70,\n                                  2, 66, 68, 1, 8, 9, 0, 8, 14, 18, 76, 71, 74,\n                                  66, 17, 69, 71, 0, 7, 17, 81, 72, 10, 13, 84,\n                                  84, 84, 77, 72, 3, 72, 67, 69, 64, 5, 75, 70,\n                                  69, 1, 80, 73, 80, 83, 0, 99, 76, 1, 70, 13,\n                                  70, 65, 22, 68, 71, 65, 18, 79, 75, 97, 24,\n                                  31, 32, 22, 10, 23, 19, 14, 13, 11, 10, 6, 75,\n                                  78, 85, 71, 68, 78, 96, 78, 77, 81, 79, 78,\n                                  72, 73, 87, 89, 82, 17, 16, 17, 10, 67, 5, 2,\n                                  75, 67, 73, 74, 87, 87, 86, 87, 1, 5, 79, 1,\n                                  0, 73, 79, 80, 81, 83, 83, 88, 98, 96, 102,\n                                  104, 108, 90, 100, 106, 81, 67, 73, 3, 5, 6,\n                                  51, 16, 15, 68, 25, 61, 47, 62, 14, 25, 18,\n                                  75, 96, 102, 107, 126, 126, 124, 68, 43, 27,\n                                  18, 9, 13, 2, 66, 68, 71, 74, 67, 7, 0, 16,\n                                  13, 5, 9, 13, 16, 17, 9, 20, 17, 0, 26, 20, 8,\n                                  1, 68, 74, 98, 101, 98 },\n\n                                {\n\n                                32,\n                                  5, 80, 32, 5, 80, 1, 13, 24, 12, 67, 86, 8,\n                                  15, 52, 14, 31, 68, 16, 24, 64, 76, 0, 89,\n                                  105, 0, 67, 126, 126, 124, 43, 6, 69, 16, 24,\n                                  64, 72, 8, 16, 65, 1, 67, 70, 68, 83, 74, 92,\n                                  5, 69, 70, 65, 78, 74, 88, 13, 1, 64, 68, 8,\n                                  3, 22, 0, 0, 0, 1, 95, 97, 8, 71, 68, 52, 6,\n                                  69, 87, 71, 82, 6, 5, 64, 8, 71, 10, 64, 65,\n                                  6, 83, 87, 85, 89, 28, 0, 14, 73, 0, 74, 66,\n                                  6, 71, 83, 74, 80, 17, 70, 4, 74, 76, 2, 70,\n                                  4, 10, 5, 7, 18, 15, 79, 67, 2, 66, 2, 73, 11,\n                                  68, 5, 19, 0, 16, 17, 8, 88, 10, 66, 83, 70,\n                                  94, 77, 65, 70, 3, 66, 64, 16, 1, 66, 7, 13,\n                                  72, 72, 1, 100, 83, 65, 95, 65, 76, 14, 64,\n                                  80, 25, 1, 65, 85, 26, 77, 91, 1, 99, 8, 20,\n                                  20, 15, 20, 14, 3, 18, 21, 79, 64, 9, 3, 1,\n                                  77, 65, 70, 73, 67, 74, 82, 68, 72, 103, 83,\n                                  78, 90, 85, 89, 22, 30, 20, 19, 19, 10, 5, 10,\n                                  64, 70, 65, 77, 88, 88, 111, 0, 65, 82, 69,\n                                  76, 79, 84, 88, 92, 97, 96, 112, 80, 99, 108,\n                                  95, 101, 64, 35, 25, 16, 6, 5, 65, 67, 71, 70,\n                                  8, 48, 31, 24, 17, 36, 14, 9, 0, 1, 64, 43,\n                                  27, 15, 8, 18, 6, 0, 67, 70, 71, 26, 10, 4,\n                                  64, 8, 65, 71, 73, 4, 42, 25, 15, 8, 23, 8, 5,\n                                  4, 64, 62, 79, 70, 3, 66, 68, 1, 8, 9, 0, 8,\n                                  15, 18, 76, 71, 74, 67, 18, 70, 72, 64, 7, 17,\n                                  82, 73, 10, 13, 85, 85, 84, 76, 71, 4, 71, 66,\n                                  68, 64, 6, 75, 70, 69, 1, 81, 73, 80, 82, 1,\n                                  99, 76, 1, 70, 14, 70, 65, 23, 68, 71, 65, 19,\n                                  80, 75, 97, 23, 31, 31, 22, 9, 22, 18, 13, 13,\n                                  10, 9, 5, 76, 79, 86, 72, 69, 79, 98, 79, 78,\n                                  82, 80, 79, 72, 72, 87, 89, 81, 15, 14, 15, 8,\n                                  69, 3, 0, 77, 69, 75, 76, 89, 89, 88, 88, 64,\n                                  3, 80, 64, 65, 75, 81, 82, 83, 85, 85, 90,\n                                  101, 98, 104, 106, 109, 92, 102, 107, 80, 65,\n                                  72, 4, 6, 7, 53, 17, 16, 68, 26, 62, 49, 62,\n                                  15, 23, 16, 77, 99, 104, 110, 126, 126, 125,\n                                  68, 43, 27, 18, 9, 13, 2, 66, 68, 71, 73, 66,\n                                  8, 1, 17, 14, 5, 10, 14, 17, 18, 9, 20, 17, 0,\n                                  25, 19, 7, 0, 70, 76, 100, 103, 99 },\n\n                                {\n\n                                31,\n                                  5, 81, 31, 5, 81, 3, 14, 25, 12, 67, 87, 7,\n                                  14, 52, 14, 33, 68, 16, 25, 64, 77, 0, 90,\n                                  106, 64, 68, 126, 126, 125, 46, 7, 69, 16, 25,\n                                  64, 71, 9, 17, 66, 2, 66, 69, 69, 83, 74, 92,\n                                  5, 68, 70, 65, 78, 73, 88, 13, 1, 64, 68, 8,\n                                  3, 22, 0, 0, 0, 2, 95, 97, 8, 71, 69, 52, 6,\n                                  69, 86, 71, 82, 6, 6, 1, 10, 70, 11, 1, 64, 8,\n                                  82, 86, 84, 88, 29, 0, 15, 73, 1, 74, 66, 8,\n                                  71, 82, 74, 79, 17, 70, 4, 72, 76, 3, 69, 4,\n                                  10, 5, 8, 18, 15, 80, 67, 2, 66, 2, 73, 11,\n                                  68, 5, 19, 64, 16, 17, 8, 90, 10, 66, 85, 71,\n                                  95, 77, 64, 70, 3, 65, 64, 17, 1, 66, 7, 15,\n                                  72, 72, 1, 101, 83, 64, 95, 65, 76, 15, 0, 81,\n                                  25, 1, 65, 86, 27, 78, 92, 1, 100, 6, 19, 19,\n                                  15, 19, 14, 3, 17, 20, 80, 65, 9, 3, 1, 77,\n                                  66, 71, 74, 68, 74, 83, 69, 72, 105, 84, 78,\n                                  91, 86, 89, 21, 28, 19, 17, 17, 8, 3, 8, 67,\n                                  73, 67, 80, 91, 91, 114, 65, 67, 83, 71, 79,\n                                  82, 87, 90, 95, 99, 99, 114, 81, 101, 109, 96,\n                                  101, 0, 36, 25, 17, 6, 5, 65, 67, 71, 69, 8,\n                                  48, 32, 24, 17, 37, 14, 9, 1, 1, 0, 44, 27,\n                                  16, 8, 19, 6, 0, 66, 69, 70, 27, 11, 5, 64, 8,\n                                  65, 70, 71, 4, 42, 25, 15, 9, 23, 8, 6, 4, 0,\n                                  62, 78, 69, 3, 66, 68, 1, 8, 9, 0, 9, 15, 19,\n                                  76, 71, 75, 67, 18, 71, 73, 65, 6, 17, 83, 74,\n                                  10, 13, 85, 86, 85, 75, 70, 5, 71, 66, 68, 0,\n                                  6, 75, 69, 68, 2, 81, 73, 80, 82, 2, 99, 76,\n                                  1, 70, 15, 70, 65, 24, 69, 71, 65, 19, 81, 75,\n                                  98, 22, 30, 31, 21, 8, 22, 18, 12, 12, 10, 8,\n                                  4, 77, 80, 87, 74, 70, 81, 100, 81, 80, 83,\n                                  80, 79, 72, 72, 86, 90, 80, 13, 12, 13, 6, 72,\n                                  1, 65, 80, 71, 78, 78, 92, 91, 89, 88, 65, 2,\n                                  82, 66, 68, 77, 83, 84, 85, 87, 88, 92, 103,\n                                  100, 106, 107, 111, 94, 104, 109, 79, 64, 71,\n                                  5, 7, 8, 54, 18, 17, 68, 27, 62, 50, 62, 16,\n                                  22, 15, 80, 102, 107, 112, 126, 126, 126, 67,\n                                  43, 27, 18, 9, 13, 2, 66, 68, 70, 72, 66, 9,\n                                  2, 18, 14, 6, 11, 14, 17, 18, 9, 21, 17, 0,\n                                  24, 17, 5, 65, 71, 77, 103, 104, 100 },\n\n                                {\n\n                                30,\n                                  5, 81, 30, 5, 81, 5, 16, 25, 12, 68, 89, 5,\n                                  12, 52, 14, 36, 69, 17, 25, 64, 78, 0, 91,\n                                  107, 64, 70, 126, 126, 125, 49, 8, 69, 17, 25,\n                                  64, 71, 10, 17, 66, 2, 66, 69, 69, 84, 73, 92,\n                                  5, 68, 69, 66, 78, 73, 88, 14, 2, 64, 67, 9,\n                                  3, 22, 0, 0, 0, 2, 95, 97, 9, 72, 69, 52, 6,\n                                  69, 85, 70, 82, 7, 8, 2, 12, 68, 12, 2, 1, 10,\n                                  81, 85, 83, 88, 30, 0, 16, 72, 1, 73, 65, 10,\n                                  71, 82, 73, 78, 17, 69, 5, 71, 75, 3, 69, 5,\n                                  10, 5, 9, 19, 16, 80, 68, 2, 66, 2, 73, 11,\n                                  69, 4, 19, 64, 16, 17, 7, 92, 10, 67, 87, 72,\n                                  96, 76, 0, 69, 4, 64, 0, 18, 2, 65, 8, 16, 72,\n                                  72, 2, 102, 82, 0, 95, 65, 76, 15, 0, 82, 26,\n                                  1, 65, 88, 28, 78, 93, 1, 101, 5, 18, 19, 14,\n                                  18, 13, 2, 16, 20, 81, 66, 9, 3, 1, 78, 67,\n                                  71, 75, 68, 75, 84, 70, 73, 107, 85, 79, 92,\n                                  87, 89, 19, 27, 17, 15, 15, 6, 0, 6, 69, 75,\n                                  69, 82, 93, 93, 116, 67, 68, 85, 74, 81, 84,\n                                  89, 93, 97, 102, 101, 117, 82, 102, 111, 97,\n                                  101, 0, 36, 26, 17, 6, 5, 65, 67, 71, 69, 9,\n                                  49, 32, 24, 17, 38, 15, 10, 1, 2, 1, 45, 28,\n                                  16, 8, 20, 7, 1, 66, 68, 70, 28, 11, 5, 64, 9,\n                                  64, 70, 70, 5, 43, 25, 15, 9, 24, 9, 7, 5, 1,\n                                  62, 78, 69, 4, 66, 68, 1, 8, 9, 1, 9, 15, 19,\n                                  76, 71, 75, 68, 19, 72, 74, 66, 5, 17, 84, 75,\n                                  9, 13, 86, 87, 85, 74, 70, 6, 70, 65, 67, 0,\n                                  7, 75, 69, 68, 2, 82, 73, 80, 81, 3, 99, 76,\n                                  2, 70, 15, 70, 65, 25, 69, 71, 65, 20, 81, 76,\n                                  99, 21, 30, 30, 20, 7, 21, 17, 11, 11, 9, 7,\n                                  3, 78, 81, 88, 75, 72, 82, 102, 82, 81, 84,\n                                  81, 80, 72, 72, 86, 90, 79, 11, 10, 11, 3, 75,\n                                  64, 67, 82, 73, 80, 80, 94, 93, 91, 89, 67, 0,\n                                  83, 68, 70, 79, 85, 86, 87, 89, 90, 94, 106,\n                                  102, 108, 109, 112, 96, 106, 110, 78, 0, 70,\n                                  5, 8, 9, 56, 19, 18, 68, 28, 62, 52, 62, 16,\n                                  20, 13, 82, 105, 110, 115, 126, 126, 126, 67,\n                                  43, 27, 18, 9, 13, 2, 66, 68, 70, 71, 65, 10,\n                                  3, 19, 15, 6, 12, 15, 18, 19, 10, 21, 18, 0,\n                                  22, 16, 3, 67, 73, 79, 105, 106, 101 },\n\n                                {\n\n                                28,\n                                  4, 81, 28, 4, 81, 6, 17, 25, 12, 68, 90, 4,\n                                  11, 52, 14, 38, 69, 18, 26, 64, 79, 0, 92,\n                                  109, 65, 72, 126, 126, 126, 51, 9, 69, 18, 26,\n                                  64, 71, 11, 17, 67, 2, 66, 68, 70, 84, 73, 93,\n                                  5, 68, 69, 66, 79, 73, 88, 14, 2, 64, 67, 9,\n                                  3, 22, 0, 0, 0, 3, 96, 97, 9, 73, 69, 52, 6,\n                                  69, 84, 69, 82, 7, 9, 4, 14, 67, 13, 4, 2, 11,\n                                  80, 85, 82, 87, 30, 0, 17, 71, 1, 73, 65, 11,\n                                  71, 82, 73, 77, 17, 69, 5, 70, 75, 4, 69, 5,\n                                  10, 5, 9, 19, 16, 81, 68, 2, 66, 2, 73, 11,\n                                  69, 3, 19, 65, 16, 17, 7, 94, 10, 67, 89, 73,\n                                  97, 75, 1, 68, 5, 64, 0, 19, 2, 65, 9, 17, 72,\n                                  72, 2, 104, 82, 1, 95, 65, 77, 16, 0, 83, 27,\n                                  1, 65, 89, 29, 79, 94, 1, 102, 3, 17, 18, 13,\n                                  17, 12, 1, 15, 19, 83, 67, 8, 3, 1, 78, 68,\n                                  72, 76, 69, 76, 85, 71, 74, 109, 87, 80, 93,\n                                  88, 89, 17, 25, 15, 13, 13, 4, 65, 4, 72, 78,\n                                  71, 85, 96, 96, 119, 69, 70, 87, 76, 83, 87,\n                                  92, 95, 100, 105, 103, 119, 83, 104, 112, 98,\n                                  102, 0, 36, 26, 17, 6, 5, 65, 67, 71, 68, 9,\n                                  49, 32, 24, 17, 39, 15, 10, 1, 2, 1, 46, 28,\n                                  16, 8, 20, 7, 1, 65, 67, 69, 29, 12, 5, 64,\n                                  10, 0, 69, 69, 5, 43, 25, 15, 9, 25, 9, 7, 6,\n                                  1, 62, 78, 69, 4, 66, 68, 1, 8, 9, 1, 9, 15,\n                                  20, 76, 71, 75, 69, 19, 73, 75, 67, 4, 17, 86,\n                                  77, 9, 13, 87, 88, 86, 74, 69, 7, 70, 65, 67,\n                                  1, 8, 76, 69, 68, 2, 83, 73, 80, 81, 3, 100,\n                                  76, 2, 70, 16, 70, 65, 25, 69, 72, 65, 21, 82,\n                                  76, 100, 20, 29, 30, 19, 5, 20, 16, 10, 10, 8,\n                                  6, 2, 79, 82, 89, 77, 73, 84, 104, 84, 82, 85,\n                                  82, 80, 72, 72, 86, 91, 79, 8, 7, 9, 1, 78,\n                                  67, 70, 85, 75, 82, 82, 97, 95, 92, 90, 69,\n                                  65, 85, 70, 72, 82, 88, 89, 90, 91, 92, 97,\n                                  108, 104, 111, 111, 113, 98, 108, 112, 77, 1,\n                                  69, 6, 9, 9, 57, 20, 18, 68, 28, 62, 53, 62,\n                                  17, 19, 11, 85, 108, 113, 118, 126, 126, 126,\n                                  67, 43, 27, 18, 9, 13, 2, 66, 68, 69, 71, 64,\n                                  11, 3, 20, 15, 7, 12, 15, 18, 19, 10, 22, 18,\n                                  64, 21, 14, 1, 69, 75, 81, 107, 108, 102 },\n\n                                {\n\n                                27,\n                                  4, 81, 27, 4, 81, 8, 18, 26, 12, 68, 91, 3,\n                                  10, 52, 14, 40, 69, 19, 27, 64, 79, 1, 93,\n                                  110, 66, 74, 126, 126, 126, 54, 11, 69, 19,\n                                  27, 64, 70, 12, 18, 68, 2, 65, 67, 70, 84, 73,\n                                  93, 5, 68, 68, 66, 79, 73, 88, 14, 2, 0, 67,\n                                  9, 3, 22, 0, 0, 0, 4, 96, 97, 9, 74, 69, 52,\n                                  6, 69, 83, 68, 82, 7, 10, 6, 16, 65, 15, 6, 3,\n                                  13, 79, 84, 81, 86, 31, 1, 18, 70, 1, 72, 64,\n                                  13, 71, 81, 73, 75, 18, 69, 5, 68, 75, 5, 69,\n                                  5, 11, 6, 10, 19, 16, 81, 68, 3, 66, 2, 72,\n                                  11, 69, 3, 19, 66, 16, 17, 7, 96, 10, 67, 90,\n                                  74, 97, 74, 2, 67, 6, 0, 1, 20, 3, 65, 10, 18,\n                                  72, 72, 2, 105, 81, 2, 95, 64, 77, 17, 0, 84,\n                                  28, 1, 65, 90, 30, 80, 95, 1, 102, 2, 16, 18,\n                                  12, 16, 11, 1, 15, 19, 84, 68, 8, 3, 1, 78,\n                                  68, 73, 77, 70, 77, 86, 71, 74, 110, 88, 80,\n                                  94, 89, 89, 16, 24, 14, 12, 12, 2, 67, 2, 74,\n                                  80, 73, 87, 99, 98, 122, 70, 72, 88, 78, 85,\n                                  89, 94, 97, 102, 107, 105, 121, 83, 106, 113,\n                                  98, 102, 0, 37, 26, 17, 7, 5, 65, 66, 71, 67,\n                                  9, 49, 32, 25, 17, 40, 16, 11, 2, 3, 2, 47,\n                                  29, 17, 9, 21, 8, 1, 64, 66, 68, 31, 13, 6, 0,\n                                  11, 1, 68, 68, 6, 43, 26, 16, 9, 26, 10, 8, 7,\n                                  2, 62, 77, 68, 5, 66, 68, 1, 9, 10, 1, 9, 16,\n                                  21, 76, 71, 75, 69, 19, 74, 75, 68, 4, 17, 87,\n                                  78, 9, 13, 87, 89, 87, 73, 68, 8, 70, 64, 67,\n                                  2, 9, 76, 69, 68, 3, 83, 73, 80, 81, 4, 100,\n                                  76, 2, 70, 17, 70, 65, 26, 69, 72, 65, 22, 83,\n                                  76, 100, 19, 29, 30, 19, 4, 19, 15, 9, 10, 7,\n                                  5, 2, 79, 83, 90, 78, 74, 86, 106, 85, 83, 85,\n                                  82, 80, 71, 71, 86, 92, 78, 6, 5, 7, 64, 80,\n                                  69, 72, 87, 77, 84, 84, 99, 97, 93, 91, 71,\n                                  66, 86, 72, 74, 84, 90, 91, 92, 93, 94, 99,\n                                  110, 105, 113, 113, 114, 100, 110, 114, 76, 3,\n                                  67, 7, 10, 10, 59, 21, 19, 68, 29, 62, 54, 62,\n                                  18, 18, 10, 87, 111, 115, 121, 126, 126, 126,\n                                  67, 43, 27, 18, 9, 14, 2, 66, 68, 68, 70, 0,\n                                  12, 4, 22, 16, 8, 13, 16, 19, 20, 10, 23, 18,\n                                  64, 20, 13, 0, 70, 77, 83, 109, 110, 102 },\n\n                                {\n\n                                26,\n                                  4, 81, 26, 4, 81, 10, 20, 26, 12, 69, 93, 1,\n                                  8, 52, 14, 43, 70, 20, 27, 64, 80, 1, 94, 111,\n                                  66, 76, 126, 126, 126, 57, 12, 69, 20, 27, 64,\n                                  70, 13, 18, 68, 2, 65, 67, 70, 85, 72, 93, 5,\n                                  68, 67, 67, 79, 73, 88, 15, 3, 0, 66, 10, 3,\n                                  22, 0, 0, 0, 4, 96, 97, 10, 75, 69, 52, 6, 69,\n                                  82, 67, 82, 8, 12, 7, 18, 64, 16, 7, 5, 15,\n                                  78, 83, 80, 86, 32, 1, 19, 69, 1, 72, 0, 15,\n                                  71, 81, 72, 74, 18, 68, 6, 67, 74, 5, 69, 6,\n                                  11, 6, 11, 20, 17, 82, 69, 3, 66, 2, 72, 11,\n                                  70, 2, 19, 66, 16, 17, 6, 98, 10, 68, 92, 75,\n                                  98, 73, 3, 66, 7, 1, 2, 21, 4, 64, 11, 19, 72,\n                                  72, 3, 106, 81, 3, 95, 64, 77, 17, 0, 85, 29,\n                                  1, 65, 92, 31, 80, 96, 1, 103, 0, 15, 17, 11,\n                                  15, 10, 0, 14, 19, 85, 69, 8, 3, 1, 79, 69,\n                                  73, 78, 70, 78, 87, 72, 75, 112, 89, 81, 95,\n                                  90, 89, 14, 23, 12, 10, 10, 0, 70, 0, 77, 82,\n                                  75, 90, 101, 100, 124, 72, 73, 90, 81, 87, 91,\n                                  96, 100, 104, 110, 107, 124, 84, 107, 115, 99,\n                                  102, 0, 37, 27, 17, 7, 5, 65, 66, 71, 67, 10,\n                                  50, 32, 25, 17, 41, 16, 12, 2, 4, 3, 48, 30,\n                                  17, 9, 22, 8, 2, 64, 65, 68, 32, 13, 6, 0, 12,\n                                  2, 68, 67, 6, 44, 26, 16, 9, 27, 11, 9, 8, 3,\n                                  62, 77, 68, 5, 66, 68, 1, 9, 10, 2, 9, 16, 21,\n                                  76, 71, 75, 70, 20, 75, 76, 69, 3, 17, 88, 79,\n                                  8, 13, 88, 90, 87, 72, 68, 9, 69, 64, 66, 2,\n                                  10, 76, 69, 68, 3, 84, 73, 80, 80, 5, 100, 76,\n                                  3, 70, 17, 70, 65, 27, 69, 72, 65, 23, 83, 77,\n                                  101, 18, 29, 29, 18, 3, 18, 14, 8, 9, 6, 4, 1,\n                                  80, 84, 91, 80, 76, 87, 108, 86, 84, 86, 83,\n                                  81, 71, 71, 86, 92, 77, 4, 3, 5, 67, 83, 71,\n                                  74, 90, 79, 86, 86, 101, 99, 95, 92, 73, 68,\n                                  87, 74, 76, 86, 92, 93, 94, 95, 96, 101, 113,\n                                  107, 115, 115, 115, 102, 112, 115, 75, 4, 66,\n                                  7, 11, 11, 61, 22, 20, 68, 30, 62, 56, 62, 18,\n                                  16, 8, 90, 114, 118, 124, 126, 126, 126, 67,\n                                  43, 27, 18, 9, 14, 2, 66, 68, 68, 69, 1, 13,\n                                  5, 23, 17, 8, 14, 17, 20, 21, 11, 23, 19, 64,\n                                  18, 11, 65, 72, 79, 85, 111, 112, 103 },\n\n                                {\n\n                                25,\n                                  4, 82, 25, 4, 82, 12, 21, 27, 12, 69, 94, 0,\n                                  7, 52, 14, 45, 70, 20, 28, 64, 81, 1, 95, 112,\n                                  67, 77, 126, 126, 126, 60, 13, 69, 20, 28, 64,\n                                  69, 14, 19, 69, 3, 64, 66, 71, 85, 72, 93, 5,\n                                  67, 67, 67, 79, 72, 88, 15, 3, 0, 66, 10, 3,\n                                  22, 0, 0, 0, 5, 96, 97, 10, 75, 70, 52, 6, 69,\n                                  81, 67, 82, 8, 13, 9, 20, 1, 17, 9, 6, 17, 77,\n                                  82, 79, 85, 33, 1, 20, 69, 2, 71, 0, 17, 71,\n                                  80, 72, 73, 18, 68, 6, 65, 74, 6, 68, 6, 11,\n                                  6, 12, 20, 17, 82, 69, 3, 66, 2, 72, 11, 70,\n                                  2, 19, 67, 16, 17, 6, 100, 10, 68, 94, 76, 99,\n                                  73, 4, 66, 7, 2, 2, 22, 4, 64, 11, 21, 72, 72,\n                                  3, 107, 80, 4, 95, 64, 77, 18, 1, 86, 29, 1,\n                                  65, 93, 32, 81, 97, 1, 104, 64, 14, 17, 11,\n                                  14, 10, 0, 13, 18, 86, 70, 8, 3, 1, 79, 70,\n                                  74, 79, 71, 78, 88, 73, 75, 114, 90, 81, 96,\n                                  91, 89, 13, 21, 11, 8, 8, 65, 72, 65, 79, 85,\n                                  77, 92, 104, 103, 126, 74, 75, 91, 83, 90, 94,\n                                  99, 102, 107, 112, 110, 126, 85, 109, 116,\n                                  100, 102, 1, 38, 27, 18, 7, 5, 65, 66, 71, 66,\n                                  10, 50, 33, 25, 17, 42, 17, 12, 3, 4, 4, 49,\n                                  30, 18, 9, 23, 9, 2, 0, 64, 67, 33, 14, 7, 0,\n                                  12, 2, 67, 65, 7, 44, 26, 16, 10, 27, 11, 10,\n                                  8, 4, 62, 76, 67, 6, 66, 68, 1, 9, 10, 2, 10,\n                                  16, 22, 76, 71, 76, 70, 20, 76, 77, 70, 2, 17,\n                                  89, 80, 8, 13, 88, 91, 88, 71, 67, 10, 69, 0,\n                                  66, 3, 10, 76, 68, 67, 4, 84, 73, 80, 80, 6,\n                                  100, 76, 3, 70, 18, 70, 65, 28, 70, 72, 65,\n                                  23, 84, 77, 102, 17, 28, 29, 17, 2, 18, 14, 7,\n                                  8, 6, 3, 0, 81, 85, 92, 81, 77, 89, 110, 88,\n                                  86, 87, 83, 81, 71, 71, 85, 93, 76, 2, 1, 3,\n                                  69, 86, 73, 76, 92, 81, 89, 88, 104, 101, 96,\n                                  92, 74, 69, 89, 76, 79, 88, 94, 95, 96, 97,\n                                  99, 103, 115, 109, 117, 116, 117, 104, 114,\n                                  117, 74, 5, 65, 8, 12, 12, 62, 23, 21, 68, 31,\n                                  62, 57, 62, 19, 15, 7, 92, 117, 121, 126, 126,\n                                  126, 126, 66, 43, 27, 18, 9, 14, 2, 66, 68,\n                                  67, 68, 1, 14, 6, 24, 17, 9, 15, 17, 20, 21,\n                                  11, 24, 19, 64, 17, 10, 67, 74, 80, 86, 114,\n                                  113, 104 },\n\n                                {\n\n                                23,\n                                  4, 82, 23, 4, 82, 13, 23, 27, 12, 70, 96, 65,\n                                  6, 52, 14, 47, 70, 21, 29, 64, 82, 1, 96, 113,\n                                  67, 79, 126, 126, 126, 62, 14, 69, 21, 29, 64,\n                                  69, 15, 19, 69, 3, 64, 65, 71, 86, 72, 93, 5,\n                                  67, 66, 67, 80, 72, 88, 16, 3, 0, 66, 11, 3,\n                                  22, 0, 0, 0, 5, 97, 97, 11, 76, 70, 52, 6, 69,\n                                  80, 66, 82, 9, 14, 11, 22, 2, 18, 11, 7, 19,\n                                  76, 82, 78, 84, 33, 1, 21, 68, 2, 71, 1, 19,\n                                  71, 80, 71, 72, 18, 68, 7, 64, 73, 7, 68, 6,\n                                  11, 6, 12, 21, 18, 83, 69, 3, 66, 2, 72, 11,\n                                  71, 1, 19, 68, 16, 17, 6, 102, 10, 69, 96, 77,\n                                  100, 72, 5, 65, 8, 2, 3, 23, 5, 0, 12, 22, 72,\n                                  72, 3, 108, 80, 5, 95, 64, 77, 19, 1, 87, 30,\n                                  1, 65, 94, 33, 81, 98, 1, 105, 66, 13, 16, 10,\n                                  13, 9, 64, 12, 18, 88, 71, 7, 3, 1, 80, 71,\n                                  75, 80, 72, 79, 89, 74, 76, 116, 91, 82, 97,\n                                  92, 89, 11, 20, 9, 6, 6, 67, 74, 67, 82, 87,\n                                  79, 95, 106, 105, 126, 76, 77, 93, 85, 92, 96,\n                                  101, 104, 109, 115, 112, 126, 86, 111, 117,\n                                  101, 102, 1, 38, 27, 18, 7, 5, 65, 66, 71, 66,\n                                  10, 50, 33, 25, 17, 43, 17, 13, 3, 5, 4, 50,\n                                  31, 18, 9, 23, 9, 3, 0, 0, 66, 34, 15, 7, 0,\n                                  13, 3, 66, 64, 7, 44, 26, 16, 10, 28, 12, 10,\n                                  9, 5, 62, 76, 67, 6, 66, 68, 1, 9, 10, 2, 10,\n                                  16, 22, 76, 71, 76, 71, 21, 77, 78, 71, 1, 17,\n                                  91, 81, 8, 13, 89, 92, 88, 71, 66, 11, 68, 0,\n                                  65, 3, 11, 77, 68, 67, 4, 85, 73, 80, 79, 7,\n                                  100, 76, 3, 70, 19, 70, 65, 29, 70, 73, 65,\n                                  24, 85, 77, 103, 16, 28, 28, 16, 1, 17, 13, 6,\n                                  7, 5, 2, 64, 82, 86, 93, 83, 78, 90, 112, 89,\n                                  87, 88, 84, 82, 71, 71, 85, 93, 76, 64, 65, 1,\n                                  71, 89, 75, 78, 95, 83, 91, 90, 106, 103, 98,\n                                  93, 76, 71, 90, 78, 81, 90, 96, 98, 98, 99,\n                                  101, 105, 118, 111, 119, 118, 118, 106, 116,\n                                  118, 73, 6, 64, 9, 13, 13, 62, 24, 22, 68, 32,\n                                  62, 59, 62, 20, 13, 5, 95, 120, 124, 126, 126,\n                                  126, 126, 66, 43, 27, 18, 9, 14, 2, 66, 68,\n                                  67, 67, 2, 15, 6, 25, 18, 9, 16, 18, 21, 22,\n                                  11, 24, 19, 64, 16, 8, 69, 76, 82, 88, 116,\n                                  115, 105 },\n\n                                {\n\n                                22,\n                                  4, 82, 22, 4, 82, 15, 24, 27, 12, 70, 97, 66,\n                                  4, 52, 14, 50, 71, 22, 29, 64, 82, 2, 97, 114,\n                                  68, 81, 126, 126, 126, 62, 16, 69, 22, 29, 64,\n                                  69, 16, 19, 70, 3, 64, 65, 71, 86, 71, 93, 5,\n                                  67, 65, 68, 80, 72, 88, 16, 4, 1, 65, 11, 3,\n                                  22, 0, 0, 0, 6, 97, 97, 11, 77, 70, 52, 6, 69,\n                                  79, 65, 82, 9, 16, 12, 24, 4, 19, 12, 9, 21,\n                                  75, 81, 77, 84, 34, 1, 22, 67, 2, 70, 2, 21,\n                                  71, 80, 71, 70, 19, 67, 7, 0, 73, 7, 68, 7,\n                                  12, 7, 13, 21, 18, 83, 70, 3, 66, 2, 72, 11,\n                                  71, 0, 19, 68, 16, 17, 5, 104, 10, 69, 97, 78,\n                                  101, 71, 6, 64, 9, 3, 4, 24, 6, 0, 13, 23, 72,\n                                  72, 4, 109, 79, 6, 95, 0, 77, 19, 1, 88, 31,\n                                  1, 65, 96, 34, 82, 99, 1, 105, 67, 12, 16, 9,\n                                  12, 8, 65, 12, 18, 89, 72, 7, 3, 1, 80, 71,\n                                  75, 81, 72, 80, 90, 74, 77, 118, 92, 83, 98,\n                                  93, 89, 9, 19, 7, 4, 5, 69, 77, 69, 84, 89,\n                                  81, 97, 109, 107, 126, 78, 78, 95, 88, 94, 98,\n                                  103, 107, 111, 118, 114, 126, 87, 112, 119,\n                                  101, 102, 1, 38, 28, 18, 7, 5, 65, 66, 71, 65,\n                                  11, 51, 33, 25, 17, 44, 18, 14, 3, 6, 5, 51,\n                                  32, 18, 10, 24, 10, 3, 1, 1, 66, 36, 15, 7, 1,\n                                  14, 4, 66, 0, 8, 45, 27, 16, 10, 29, 13, 11,\n                                  10, 6, 62, 76, 67, 7, 66, 68, 1, 9, 10, 3, 10,\n                                  17, 23, 76, 71, 76, 72, 21, 78, 79, 72, 1, 17,\n                                  92, 82, 7, 13, 90, 93, 89, 70, 66, 12, 68, 1,\n                                  65, 4, 12, 77, 68, 67, 4, 86, 73, 80, 79, 8,\n                                  100, 76, 4, 70, 19, 70, 65, 30, 70, 73, 65,\n                                  25, 85, 78, 103, 15, 28, 28, 16, 0, 16, 12, 5,\n                                  7, 4, 1, 65, 83, 87, 94, 84, 80, 92, 114, 90,\n                                  88, 89, 85, 82, 71, 70, 85, 94, 75, 66, 67,\n                                  64, 74, 91, 77, 80, 97, 85, 93, 92, 108, 105,\n                                  99, 94, 78, 73, 91, 80, 83, 92, 98, 100, 100,\n                                  101, 103, 107, 120, 113, 121, 120, 119, 108,\n                                  118, 120, 72, 8, 0, 9, 14, 14, 62, 25, 23, 68,\n                                  33, 62, 60, 62, 20, 12, 3, 97, 123, 126, 126,\n                                  126, 126, 126, 66, 43, 27, 18, 9, 14, 2, 66,\n                                  68, 66, 66, 3, 16, 7, 26, 19, 10, 17, 19, 22,\n                                  23, 12, 25, 20, 64, 14, 7, 70, 77, 84, 90,\n                                  118, 117, 106 },\n\n                                {\n\n                                21,\n                                  4, 82, 21, 4, 82, 17, 26, 28, 12, 71, 99, 68,\n                                  3, 52, 14, 52, 71, 23, 30, 64, 83, 2, 98, 115,\n                                  68, 83, 126, 126, 126, 62, 17, 69, 23, 30, 64,\n                                  68, 17, 20, 70, 3, 0, 64, 72, 87, 71, 93, 5,\n                                  67, 65, 68, 80, 72, 88, 17, 4, 1, 65, 12, 3,\n                                  22, 0, 0, 0, 6, 97, 97, 12, 78, 70, 52, 6, 69,\n                                  78, 64, 82, 10, 17, 14, 26, 5, 20, 14, 10, 23,\n                                  74, 80, 76, 83, 35, 1, 23, 66, 2, 70, 2, 23,\n                                  71, 79, 70, 69, 19, 67, 8, 2, 72, 8, 68, 7,\n                                  12, 7, 14, 22, 19, 84, 70, 3, 66, 2, 72, 11,\n                                  72, 0, 19, 69, 16, 17, 5, 106, 10, 70, 99, 79,\n                                  102, 70, 7, 0, 10, 4, 4, 25, 6, 1, 14, 24, 72,\n                                  72, 4, 110, 79, 7, 95, 0, 77, 20, 1, 89, 32,\n                                  1, 65, 97, 35, 82, 100, 1, 106, 69, 11, 15, 8,\n                                  11, 7, 65, 11, 17, 90, 73, 7, 3, 1, 81, 72,\n                                  76, 82, 73, 81, 91, 75, 77, 120, 93, 83, 99,\n                                  94, 89, 8, 17, 6, 2, 3, 71, 79, 71, 87, 92,\n                                  83, 100, 111, 110, 126, 80, 80, 96, 90, 96,\n                                  101, 106, 109, 114, 120, 116, 126, 88, 114,\n                                  120, 102, 102, 1, 39, 28, 18, 7, 5, 65, 66,\n                                  71, 65, 11, 51, 33, 25, 17, 45, 18, 14, 4, 6,\n                                  6, 52, 32, 19, 10, 25, 10, 4, 1, 2, 65, 37,\n                                  16, 8, 1, 15, 5, 65, 1, 8, 45, 27, 16, 10, 30,\n                                  13, 12, 11, 7, 62, 75, 66, 7, 66, 68, 1, 9,\n                                  10, 3, 10, 17, 23, 76, 71, 76, 72, 22, 79, 80,\n                                  73, 0, 17, 93, 83, 7, 13, 90, 94, 89, 69, 65,\n                                  13, 67, 1, 64, 4, 13, 77, 68, 67, 5, 86, 73,\n                                  80, 78, 9, 100, 76, 4, 70, 20, 70, 65, 31, 70,\n                                  73, 65, 26, 86, 78, 104, 14, 27, 27, 15, 64,\n                                  15, 11, 4, 6, 3, 0, 66, 84, 88, 95, 86, 81,\n                                  93, 116, 92, 89, 90, 85, 83, 71, 70, 85, 94,\n                                  74, 68, 69, 66, 76, 94, 79, 82, 100, 87, 95,\n                                  94, 111, 107, 101, 95, 80, 74, 93, 82, 85, 94,\n                                  100, 102, 102, 103, 105, 109, 123, 115, 123,\n                                  122, 120, 110, 120, 121, 71, 9, 1, 10, 15, 15,\n                                  62, 26, 24, 68, 34, 62, 62, 62, 21, 10, 2,\n                                  100, 126, 126, 126, 126, 126, 126, 66, 43, 27,\n                                  18, 9, 14, 2, 66, 68, 66, 65, 4, 17, 8, 27,\n                                  19, 10, 18, 19, 22, 23, 12, 25, 20, 64, 13, 5,\n                                  72, 79, 86, 92, 120, 119, 107 },\n\n                                {\n\n                                20,\n                                  4, 82, 20, 4, 82, 19, 27, 28, 12, 71, 100, 69,\n                                  2, 52, 14, 54, 71, 24, 31, 64, 84, 2, 99, 116,\n                                  69, 85, 126, 126, 126, 62, 18, 69, 24, 31, 64,\n                                  68, 18, 20, 71, 3, 0, 0, 72, 87, 71, 93, 5,\n                                  67, 64, 68, 80, 72, 88, 17, 4, 1, 65, 12, 3,\n                                  22, 0, 0, 0, 7, 97, 97, 12, 79, 70, 52, 6, 69,\n                                  77, 0, 82, 10, 18, 16, 28, 7, 21, 16, 11, 25,\n                                  73, 79, 75, 82, 36, 1, 24, 65, 2, 69, 3, 25,\n                                  71, 79, 70, 68, 19, 67, 8, 3, 72, 9, 68, 7,\n                                  12, 7, 15, 22, 19, 84, 70, 3, 66, 2, 72, 11,\n                                  72, 64, 19, 70, 16, 17, 5, 108, 10, 70, 101,\n                                  80, 103, 69, 8, 1, 11, 5, 5, 26, 7, 1, 15, 25,\n                                  72, 72, 4, 111, 78, 8, 95, 0, 77, 21, 1, 90,\n                                  33, 1, 65, 98, 36, 83, 101, 1, 107, 70, 10,\n                                  15, 7, 10, 6, 66, 10, 17, 91, 74, 7, 3, 1, 81,\n                                  73, 77, 83, 74, 82, 92, 76, 78, 122, 94, 84,\n                                  100, 95, 89, 6, 16, 4, 0, 1, 73, 81, 73, 89,\n                                  94, 85, 102, 114, 112, 126, 82, 82, 98, 92,\n                                  98, 103, 108, 111, 116, 123, 118, 126, 89,\n                                  116, 121, 103, 102, 1, 39, 28, 18, 7, 5, 65,\n                                  66, 71, 64, 11, 51, 33, 25, 17, 46, 19, 15, 4,\n                                  7, 7, 53, 33, 19, 10, 26, 11, 4, 2, 3, 64, 38,\n                                  17, 8, 1, 16, 6, 64, 2, 9, 45, 27, 16, 10, 31,\n                                  14, 13, 12, 8, 62, 75, 66, 8, 66, 68, 1, 9,\n                                  10, 3, 10, 17, 24, 76, 71, 76, 73, 22, 80, 81,\n                                  74, 64, 17, 94, 84, 7, 13, 91, 95, 90, 68, 64,\n                                  14, 67, 2, 64, 5, 14, 77, 68, 67, 5, 87, 73,\n                                  80, 78, 10, 100, 76, 4, 70, 21, 70, 65, 32,\n                                  70, 73, 65, 27, 87, 78, 105, 13, 27, 27, 14,\n                                  65, 14, 10, 3, 5, 2, 64, 67, 85, 89, 96, 87,\n                                  82, 95, 118, 93, 90, 91, 86, 83, 71, 70, 85,\n                                  95, 73, 70, 71, 68, 78, 97, 81, 84, 102, 89,\n                                  97, 96, 113, 109, 102, 96, 82, 76, 94, 84, 87,\n                                  96, 102, 104, 104, 105, 107, 111, 125, 117,\n                                  125, 124, 121, 112, 122, 123, 70, 10, 2, 11,\n                                  16, 16, 62, 27, 25, 68, 35, 62, 62, 62, 22, 9,\n                                  0, 102, 126, 126, 126, 126, 126, 126, 66, 43,\n                                  27, 18, 9, 14, 2, 66, 68, 65, 64, 5, 18, 9,\n                                  28, 20, 11, 19, 20, 23, 24, 12, 26, 20, 64,\n                                  12, 4, 74, 81, 88, 94, 122, 121, 108 },\n\n                                {\n\n                                18,\n                                  3, 83, 18, 3, 83, 20, 28, 28, 12, 72, 102, 71,\n                                  0, 51, 14, 56, 72, 24, 31, 65, 85, 2, 101,\n                                  118, 70, 87, 126, 126, 126, 62, 19, 70, 24,\n                                  31, 65, 68, 19, 20, 72, 3, 0, 0, 73, 88, 71,\n                                  94, 5, 67, 64, 69, 81, 72, 88, 17, 4, 1, 65,\n                                  12, 2, 22, 0, 0, 0, 7, 98, 97, 12, 80, 71, 52,\n                                  5, 69, 76, 0, 82, 10, 19, 17, 29, 8, 22, 17,\n                                  12, 26, 72, 79, 74, 82, 36, 1, 24, 65, 2, 69,\n                                  3, 26, 71, 79, 70, 67, 19, 67, 8, 4, 72, 9,\n                                  68, 7, 12, 7, 15, 22, 19, 85, 71, 3, 67, 2,\n                                  72, 10, 73, 65, 19, 71, 15, 17, 4, 110, 9, 71,\n                                  103, 81, 104, 69, 8, 1, 11, 5, 5, 27, 7, 1,\n                                  15, 26, 73, 72, 4, 113, 78, 8, 95, 0, 78, 21,\n                                  1, 91, 33, 1, 65, 100, 36, 84, 102, 1, 108,\n                                  72, 9, 14, 6, 9, 5, 67, 9, 16, 93, 75, 6, 2,\n                                  1, 82, 74, 78, 84, 75, 83, 93, 77, 79, 124,\n                                  96, 85, 102, 97, 89, 4, 14, 2, 65, 64, 76, 84,\n                                  76, 92, 97, 88, 105, 117, 115, 126, 84, 84,\n                                  100, 95, 101, 106, 111, 114, 119, 126, 121,\n                                  126, 90, 118, 123, 104, 103, 1, 39, 28, 18, 7,\n                                  5, 66, 66, 71, 64, 11, 51, 33, 25, 17, 47, 19,\n                                  15, 4, 7, 7, 53, 33, 19, 10, 26, 11, 4, 2, 4,\n                                  64, 39, 17, 8, 1, 16, 6, 64, 3, 9, 45, 27, 16,\n                                  10, 31, 14, 13, 12, 8, 62, 75, 66, 8, 66, 68,\n                                  1, 9, 10, 3, 10, 17, 24, 76, 71, 77, 74, 22,\n                                  81, 82, 75, 65, 16, 96, 86, 6, 12, 92, 97, 91,\n                                  68, 64, 15, 67, 2, 64, 5, 14, 78, 68, 67, 5,\n                                  88, 73, 80, 78, 10, 101, 76, 4, 70, 21, 71,\n                                  65, 32, 71, 74, 65, 27, 88, 79, 106, 12, 26,\n                                  26, 13, 67, 13, 9, 2, 4, 1, 65, 68, 86, 91,\n                                  98, 89, 84, 97, 120, 95, 92, 92, 87, 84, 71,\n                                  70, 85, 96, 73, 73, 74, 70, 81, 100, 84, 87,\n                                  105, 92, 100, 99, 116, 112, 104, 97, 84, 78,\n                                  96, 86, 90, 99, 105, 107, 107, 107, 110, 114,\n                                  126, 119, 126, 126, 123, 114, 124, 125, 69,\n                                  11, 3, 11, 16, 16, 62, 27, 25, 68, 35, 62, 62,\n                                  62, 22, 7, 65, 105, 126, 126, 126, 126, 126,\n                                  126, 66, 43, 26, 17, 9, 14, 2, 67, 68, 65, 64,\n                                  5, 18, 9, 29, 20, 11, 19, 20, 23, 24, 12, 26,\n                                  20, 65, 10, 2, 76, 83, 90, 96, 125, 123, 109 },\n\n                                {\n\n                                17,\n                                  3, 83, 17, 3, 83, 22, 30, 29, 13, 72, 103, 72,\n                                  64, 51, 14, 59, 72, 25, 32, 65, 85, 3, 102,\n                                  119, 70, 88, 126, 126, 126, 62, 21, 70, 25,\n                                  32, 65, 67, 21, 21, 72, 4, 1, 1, 73, 88, 70,\n                                  94, 5, 66, 0, 69, 81, 71, 88, 18, 5, 2, 64,\n                                  13, 2, 22, 0, 0, 0, 8, 98, 97, 13, 80, 71, 52,\n                                  5, 69, 74, 1, 82, 11, 21, 19, 31, 10, 24, 19,\n                                  14, 28, 70, 78, 73, 81, 37, 2, 25, 64, 3, 68,\n                                  4, 28, 70, 78, 69, 65, 20, 66, 9, 6, 71, 10,\n                                  67, 8, 13, 8, 16, 23, 20, 85, 71, 4, 67, 2,\n                                  71, 10, 73, 65, 19, 71, 15, 17, 4, 111, 9, 71,\n                                  104, 82, 104, 68, 9, 2, 12, 6, 6, 28, 8, 2,\n                                  16, 28, 73, 72, 5, 114, 77, 9, 95, 1, 78, 22,\n                                  2, 91, 34, 1, 65, 101, 37, 84, 103, 1, 108,\n                                  73, 9, 14, 6, 9, 5, 67, 9, 16, 94, 75, 6, 2,\n                                  1, 82, 74, 78, 84, 75, 83, 94, 77, 79, 125,\n                                  97, 85, 103, 98, 89, 3, 13, 1, 66, 65, 78, 86,\n                                  78, 94, 99, 90, 107, 119, 117, 126, 85, 85,\n                                  101, 97, 103, 108, 113, 116, 121, 126, 123,\n                                  126, 90, 119, 124, 104, 103, 2, 40, 29, 19, 8,\n                                  5, 66, 65, 70, 0, 12, 52, 34, 26, 17, 48, 20,\n                                  16, 5, 8, 8, 54, 34, 20, 11, 27, 12, 5, 3, 6,\n                                  0, 41, 18, 9, 2, 17, 7, 0, 5, 10, 46, 28, 17,\n                                  11, 32, 15, 14, 13, 9, 62, 74, 65, 9, 66, 67,\n                                  1, 10, 11, 4, 11, 18, 25, 75, 71, 77, 74, 23,\n                                  81, 82, 76, 65, 16, 97, 87, 6, 12, 92, 98, 91,\n                                  67, 0, 16, 66, 3, 0, 6, 15, 78, 67, 66, 6, 88,\n                                  72, 79, 77, 11, 101, 76, 5, 70, 22, 71, 65,\n                                  33, 71, 74, 64, 28, 88, 79, 106, 12, 26, 26,\n                                  13, 68, 13, 9, 2, 4, 1, 65, 68, 86, 92, 99,\n                                  90, 85, 98, 121, 96, 93, 92, 87, 84, 70, 69,\n                                  84, 96, 72, 75, 76, 72, 83, 102, 86, 89, 107,\n                                  94, 102, 101, 118, 114, 105, 97, 85, 79, 97,\n                                  87, 92, 101, 107, 109, 109, 109, 112, 116,\n                                  126, 120, 126, 126, 124, 115, 125, 126, 67,\n                                  13, 5, 12, 17, 17, 62, 28, 26, 68, 36, 62, 62,\n                                  62, 23, 6, 66, 107, 126, 126, 126, 126, 126,\n                                  126, 65, 44, 26, 17, 9, 15, 2, 67, 68, 64, 0,\n                                  6, 19, 10, 31, 21, 12, 20, 21, 24, 25, 13, 27,\n                                  21, 65, 9, 1, 77, 84, 91, 97, 126, 124, 109 },\n\n                                {\n\n                                16,\n                                  3, 83, 16, 3, 83, 24, 31, 29, 13, 72, 104, 73,\n                                  65, 51, 14, 61, 72, 26, 33, 65, 86, 3, 103,\n                                  120, 71, 90, 126, 126, 126, 62, 22, 70, 26,\n                                  33, 65, 67, 22, 21, 73, 4, 1, 2, 73, 88, 70,\n                                  94, 5, 66, 1, 69, 81, 71, 88, 18, 5, 2, 64,\n                                  13, 2, 22, 0, 0, 0, 9, 98, 97, 13, 81, 71, 52,\n                                  5, 69, 73, 2, 82, 11, 22, 21, 33, 11, 25, 21,\n                                  15, 30, 69, 77, 72, 80, 38, 2, 26, 0, 3, 68,\n                                  5, 30, 70, 78, 69, 64, 20, 66, 9, 7, 71, 11,\n                                  67, 8, 13, 8, 17, 23, 20, 86, 71, 4, 67, 2,\n                                  71, 10, 73, 66, 19, 72, 15, 17, 4, 113, 9, 71,\n                                  106, 83, 105, 67, 10, 3, 13, 7, 7, 29, 9, 2,\n                                  17, 29, 73, 72, 5, 115, 77, 10, 95, 1, 78, 23,\n                                  2, 92, 35, 1, 65, 102, 38, 85, 104, 1, 109,\n                                  75, 8, 13, 5, 8, 4, 68, 8, 16, 95, 76, 6, 2,\n                                  1, 82, 75, 79, 85, 76, 84, 95, 78, 80, 126,\n                                  98, 86, 104, 99, 89, 1, 12, 64, 68, 67, 80,\n                                  88, 80, 97, 101, 92, 110, 122, 119, 126, 87,\n                                  87, 103, 99, 105, 110, 115, 118, 123, 126,\n                                  125, 126, 91, 121, 125, 105, 103, 2, 40, 29,\n                                  19, 8, 5, 66, 65, 70, 1, 12, 52, 34, 26, 17,\n                                  49, 20, 17, 5, 9, 9, 55, 35, 20, 11, 28, 12,\n                                  5, 4, 7, 1, 42, 19, 9, 2, 18, 8, 1, 6, 10, 46,\n                                  28, 17, 11, 33, 16, 15, 14, 10, 62, 74, 65, 9,\n                                  66, 67, 1, 10, 11, 4, 11, 18, 26, 75, 71, 77,\n                                  75, 23, 82, 83, 77, 66, 16, 98, 88, 6, 12, 93,\n                                  99, 92, 66, 1, 17, 66, 3, 0, 7, 16, 78, 67,\n                                  66, 6, 89, 72, 79, 77, 12, 101, 76, 5, 70, 23,\n                                  71, 65, 34, 71, 74, 64, 29, 89, 79, 107, 11,\n                                  26, 26, 12, 69, 12, 8, 1, 3, 0, 66, 69, 87,\n                                  93, 100, 92, 86, 100, 123, 97, 94, 93, 88, 84,\n                                  70, 69, 84, 97, 71, 77, 78, 74, 85, 105, 88,\n                                  91, 110, 96, 104, 103, 120, 116, 106, 98, 87,\n                                  81, 98, 89, 94, 103, 109, 111, 111, 111, 114,\n                                  118, 126, 122, 126, 126, 125, 117, 126, 126,\n                                  66, 14, 6, 13, 18, 18, 62, 29, 27, 68, 37, 62,\n                                  62, 62, 24, 5, 68, 110, 126, 126, 126, 126,\n                                  126, 126, 65, 44, 26, 17, 9, 15, 2, 67, 68, 0,\n                                  1, 7, 20, 11, 32, 22, 13, 21, 22, 25, 26, 13,\n                                  28, 21, 65, 8, 64, 79, 86, 93, 99, 126, 126,\n                                  110 },\n\n                                {\n\n                                15,\n                                  3, 83, 15, 3, 83, 26, 33, 30, 13, 73, 106, 75,\n                                  66, 51, 14, 62, 72, 27, 34, 65, 87, 3, 104,\n                                  121, 71, 92, 126, 126, 126, 62, 23, 70, 27,\n                                  34, 65, 66, 23, 22, 73, 4, 2, 3, 74, 89, 70,\n                                  94, 5, 66, 1, 69, 81, 71, 88, 19, 5, 2, 64,\n                                  14, 2, 22, 0, 0, 0, 9, 98, 97, 14, 82, 71, 52,\n                                  5, 69, 72, 3, 82, 12, 23, 23, 35, 13, 26, 23,\n                                  16, 32, 68, 76, 71, 79, 39, 2, 27, 1, 3, 67,\n                                  5, 32, 70, 77, 68, 0, 20, 66, 10, 9, 70, 12,\n                                  67, 8, 13, 8, 18, 24, 21, 86, 71, 4, 67, 2,\n                                  71, 10, 74, 66, 19, 73, 15, 17, 4, 115, 9, 72,\n                                  108, 84, 106, 66, 11, 4, 14, 8, 7, 30, 9, 3,\n                                  18, 30, 73, 72, 5, 116, 76, 11, 95, 1, 78, 24,\n                                  2, 93, 36, 1, 65, 103, 39, 85, 105, 1, 110,\n                                  76, 7, 13, 4, 7, 3, 68, 7, 15, 96, 77, 6, 2,\n                                  1, 83, 76, 80, 86, 77, 85, 96, 79, 80, 126,\n                                  99, 86, 105, 100, 89, 0, 10, 65, 70, 69, 82,\n                                  90, 82, 99, 104, 94, 112, 124, 122, 126, 89,\n                                  89, 104, 101, 107, 113, 118, 120, 126, 126,\n                                  126, 126, 92, 123, 126, 106, 103, 2, 41, 29,\n                                  19, 8, 5, 66, 65, 70, 1, 12, 52, 34, 26, 17,\n                                  50, 21, 17, 6, 9, 10, 56, 35, 21, 11, 29, 13,\n                                  6, 4, 8, 2, 43, 20, 10, 2, 19, 9, 2, 7, 11,\n                                  46, 28, 17, 11, 34, 16, 16, 15, 11, 62, 73,\n                                  64, 10, 66, 67, 1, 10, 11, 4, 11, 18, 26, 75,\n                                  71, 77, 75, 24, 83, 84, 78, 67, 16, 99, 89, 6,\n                                  12, 93, 100, 92, 65, 2, 18, 65, 4, 1, 7, 17,\n                                  78, 67, 66, 7, 89, 72, 79, 76, 13, 101, 76, 5,\n                                  70, 24, 71, 65, 35, 71, 74, 64, 30, 90, 79,\n                                  108, 10, 25, 25, 11, 70, 11, 7, 0, 2, 64, 67,\n                                  70, 88, 94, 101, 93, 87, 101, 125, 99, 95, 94,\n                                  88, 85, 70, 69, 84, 97, 70, 79, 80, 76, 87,\n                                  108, 90, 93, 112, 98, 106, 105, 123, 118, 108,\n                                  99, 89, 82, 100, 91, 96, 105, 111, 113, 113,\n                                  113, 116, 120, 126, 124, 126, 126, 126, 119,\n                                  126, 126, 65, 15, 7, 14, 19, 19, 62, 30, 28,\n                                  68, 38, 62, 62, 62, 25, 3, 69, 112, 126, 126,\n                                  126, 126, 126, 126, 65, 44, 26, 17, 9, 15, 2,\n                                  67, 68, 0, 2, 8, 21, 12, 33, 22, 13, 22, 22,\n                                  25, 26, 13, 28, 21, 65, 7, 65, 81, 88, 95,\n                                  101, 126, 126, 111 },\n\n                          },\n\n                    };\n\n#endif\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_compute_bs.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_deblocking.h\"\n#include \"string.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n\nUWORD16 ih264d_update_csbp_8x8(UWORD16 u2_luma_csbp)\n{\n    UWORD16 u2_mod_csbp;\n\n    u2_mod_csbp = u2_luma_csbp;\n\n    if(u2_mod_csbp & 0x0033)\n    {\n        u2_mod_csbp |= 0x0033;\n    }\n\n    if(u2_mod_csbp & 0x00CC)\n    {\n        u2_mod_csbp |= 0x00CC;\n    }\n\n    if(u2_mod_csbp & 0x3300)\n    {\n        u2_mod_csbp |= 0x3300;\n    }\n\n    if(u2_mod_csbp & 0xCC00)\n    {\n        u2_mod_csbp |= 0xCC00;\n    }\n\n    return u2_mod_csbp;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_fill_bs2_horz_vert                                       */\n/*                                                                           */\n/*  Description   : This function fills boundray strength (=2) for all horz  */\n/*                  and vert edges of current mb based on coded sub block    */\n/*                  pattern of current, top and left mb                      */\n/*  Inputs        :                                                          */\n/*                  pu4_bs : Base pointer of  BS table which gets updated    */\n/*                  u4_left_mb_csbp : left mb's coded sub block pattern      */\n/*                  u4_top_mb_csbp : top mb's coded sub block pattern        */\n/*                  u4_cur_mb_csbp : current mb's coded sub block pattern    */\n/*                                                                           */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    :                                                          */\n/*                                                                           */\n/*              csbp for each 4x4 block in a mb is bit packet in reverse     */\n/*              raster scan order for each mb as shown below:                */\n/*              15|14|13|12|11|10|9|8|7|6|5|4|3|2|1|0.                       */\n/*                                                                           */\n/*              BS=2 for a 4x4 edge if any of adjacent blocks forming edge   */\n/*              are coded. Keeping this in mind, bs=2 for all horz and vert  */\n/*              edges can be derived using  a lookup table for each edge     */\n/*              after \"ORing\" the csbp values as follows:                    */\n/*              (C means current Mb, T means top mb and L means left mb)     */\n/*                                                                           */\n/*              All Horz edges:                                              */\n/*              15C|14C|13C|12C|11C|10C|9C|8C|7C|6C|5C|4C|3C |2C |1C |0C     */\n/*  (or with)   11C|10C| 9C| 8C| 7C|6C |5C|4C|3C|2C|1C|0C|15T|14T|13T|12T    */\n/*              -----BS[3]-----|----BS[2]----|---BS[1]---|----BS[0]-----|    */\n/*                                                                           */\n/*              All Vert edges:                                              */\n/*              15C|14C|13C|12C|11C|10C|9C| 8C|7C|6C|5C|4C|3C |2C |1C |0C    */\n/*  (or with)   14C|13C|12C|15L|10C| 9C|8C|11L|6C|5C|4C|7L|2C |1C |0C |3L    */\n/*              Do 4x4 transpose of resulting pattern to get vertBS[4]-BS[7] */\n/*                                                                           */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         16 10 2008   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n#define CSBP_LEFT_BLOCK_MASK 0x1111\n#define CSBP_RIGHT_BLOCK_MASK 0x8888\n\nvoid ih264d_fill_bs2_horz_vert(UWORD32 *pu4_bs, /* Base pointer of BS table */\n                               WORD32 u4_left_mb_csbp, /* csbp of left mb */\n                               WORD32 u4_top_mb_csbp, /* csbp of top mb */\n                               WORD32 u4_cur_mb_csbp, /* csbp of current mb */\n                               const UWORD32 *pu4_packed_bs2, const UWORD16 *pu2_4x4_v2h_reorder)\n{\n    /*************************************************************************/\n    /*u4_nbr_horz_csbp=11C|10C|9C|8C|7C|6C|5C|4C|3C|2C|1C|0C|15T|14T|13T|12T */\n    /*************************************************************************/\n    UWORD32 u4_nbr_horz_csbp = (u4_cur_mb_csbp << 4) | (u4_top_mb_csbp >> 12);\n    UWORD32 u4_horz_bs2_dec = u4_cur_mb_csbp | u4_nbr_horz_csbp;\n\n    /*************************************************************************/\n    /*u4_left_mb_masked_csbp = 15L|0|0|0|11L|0|0|0|7L|0|0|0|3L|0|0|0         */\n    /*************************************************************************/\n    UWORD32 u4_left_mb_masked_csbp = u4_left_mb_csbp & CSBP_RIGHT_BLOCK_MASK;\n\n    /*************************************************************************/\n    /*u4_cur_mb_masked_csbp =14C|13C|12C|x|10C|9C|8C|x|6C|5C|4C|x|2C|1C|0C|x */\n    /*************************************************************************/\n    UWORD32 u4_cur_mb_masked_csbp = (u4_cur_mb_csbp << 1)\n                    & (~CSBP_LEFT_BLOCK_MASK);\n\n    /*************************************************************************/\n    /*u4_nbr_vert_csbp=14C|13C|12C|15L|10C|9C|8C|11L|6C|5C|4C|7L|2C|1C|0C|3L */\n    /*************************************************************************/\n    UWORD32 u4_nbr_vert_csbp = (u4_cur_mb_masked_csbp)\n                    | (u4_left_mb_masked_csbp >> 3);\n\n    UWORD32 u4_vert_bs2_dec = u4_cur_mb_csbp | u4_nbr_vert_csbp;\n\n    UWORD32 u4_reordered_vert_bs2_dec, u4_temp;\n\n    PROFILE_DISABLE_BOUNDARY_STRENGTH()\n\n    /*************************************************************************/\n    /* Fill horz edges (0,1,2,3) boundary strengths 2 using look up table    */\n    /*************************************************************************/\n    pu4_bs[0] = pu4_packed_bs2[u4_horz_bs2_dec & 0xF];\n    pu4_bs[1] = pu4_packed_bs2[(u4_horz_bs2_dec >> 4) & 0xF];\n    pu4_bs[2] = pu4_packed_bs2[(u4_horz_bs2_dec >> 8) & 0xF];\n    pu4_bs[3] = pu4_packed_bs2[(u4_horz_bs2_dec >> 12) & 0xF];\n\n    /*************************************************************************/\n    /* Do 4x4 tranpose of u4_vert_bs2_dec by using look up table for reorder */\n    /*************************************************************************/\n    u4_reordered_vert_bs2_dec = pu2_4x4_v2h_reorder[u4_vert_bs2_dec & 0xF];\n    u4_temp = pu2_4x4_v2h_reorder[(u4_vert_bs2_dec >> 4) & 0xF];\n    u4_reordered_vert_bs2_dec |= (u4_temp << 1);\n    u4_temp = pu2_4x4_v2h_reorder[(u4_vert_bs2_dec >> 8) & 0xF];\n    u4_reordered_vert_bs2_dec |= (u4_temp << 2);\n    u4_temp = pu2_4x4_v2h_reorder[(u4_vert_bs2_dec >> 12) & 0xF];\n    u4_reordered_vert_bs2_dec |= (u4_temp << 3);\n\n    /*************************************************************************/\n    /* Fill vert edges (4,5,6,7) boundary strengths 2 using look up table    */\n    /*************************************************************************/\n    pu4_bs[4] = pu4_packed_bs2[u4_reordered_vert_bs2_dec & 0xF];\n    pu4_bs[5] = pu4_packed_bs2[(u4_reordered_vert_bs2_dec >> 4) & 0xF];\n    pu4_bs[6] = pu4_packed_bs2[(u4_reordered_vert_bs2_dec >> 8) & 0xF];\n    pu4_bs[7] = pu4_packed_bs2[(u4_reordered_vert_bs2_dec >> 12) & 0xF];\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_fill_bs1_16x16mb_pslice                                  */\n/*                                                                           */\n/*  Description   : This function fills boundray strength (=1) for those     */\n/*                  horz and vert mb edges of 16x16mb which are set to 0 by  */\n/*                  ih264d_fill_bs2_horz_vert. This function is used for p slices   */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : If any motion vector component of adjacent 4x4 blocks    */\n/*                  differs by more than 1 integer pel or if reference       */\n/*                  pictures are different, Bs is set to 1.                  */\n/*                                                                           */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         16 10 2008   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_fill_bs1_16x16mb_pslice(mv_pred_t *ps_cur_mv_pred,\n                                    mv_pred_t *ps_top_mv_pred,\n                                    void **ppv_map_ref_idx_to_poc,\n                                    UWORD32 *pu4_bs_table, /* pointer to the BsTable array */\n                                    mv_pred_t *ps_leftmost_mv_pred,\n                                    neighbouradd_t *ps_left_addr,\n                                    void **u4_pic_addrress, /* picture address for BS calc */\n                                    WORD32 i4_ver_mvlimit)\n{\n    WORD16 i2_q_mv0, i2_q_mv1;\n    WORD16 i2_p_mv0, i2_p_mv1;\n    void *pv_cur_pic_addr0, *pv_cur_pic_addr1;\n    void *pv_nbr_pic_addr0, *pv_nbr_pic_addr1;\n    void **ppv_map_ref_idx_to_poc_l0; //,*ppv_map_ref_idx_to_poc_l1;\n    UWORD32 i;\n    UWORD32 u4_bs_horz = pu4_bs_table[0];\n    UWORD32 u4_bs_vert = pu4_bs_table[4];\n\n    PROFILE_DISABLE_BOUNDARY_STRENGTH()\n\n    ppv_map_ref_idx_to_poc_l0 = ppv_map_ref_idx_to_poc;\n\n    i2_q_mv0 = ps_cur_mv_pred->i2_mv[0];\n    i2_q_mv1 = ps_cur_mv_pred->i2_mv[1];\n    pv_cur_pic_addr0 = ppv_map_ref_idx_to_poc_l0[ps_cur_mv_pred->i1_ref_frame[0]];\n    pv_cur_pic_addr1 = 0;\n\n    /*********************************/\n    /* Computing Bs for the top edge */\n    /*********************************/\n    for(i = 0; i < 4; i++, ps_top_mv_pred++)\n    {\n        UWORD32 u4_idx = 24 - (i << 3);\n\n        /*********************************/\n        /* check if Bs is already set    */\n        /*********************************/\n        if(!((u4_bs_horz >> u4_idx) & 0xf))\n        {\n            /************************************************************/\n            /* If Bs is not set, use left edge and current edge mvs and */\n            /* reference pictures addresses to evaluate Bs==1           */\n            /************************************************************/\n            UWORD32 u4_bs_temp1;\n            UWORD32 u4_bs;\n\n            /*********************************************************/\n            /* If any motion vector component differs by more than 1 */\n            /* integer pel or if reference pictures are different Bs */\n            /* is set to 1. Note that this condition shall be met for*/\n            /* both (fwd-fwd,bwd-bwd) and (fwd-bwd,bwd-fwd) direction*/\n            /*********************************************************/\n            i2_p_mv0 = ps_top_mv_pred->i2_mv[0];\n            i2_p_mv1 = ps_top_mv_pred->i2_mv[1];\n            pv_nbr_pic_addr0 = u4_pic_addrress[i & 2];\n            pv_nbr_pic_addr1 = u4_pic_addrress[1 + (i & 2)];\n\n            u4_bs_temp1 = ((ABS((i2_p_mv0 - i2_q_mv0)) >= 4) ||\n                           (ABS((i2_p_mv1 - i2_q_mv1)) >= i4_ver_mvlimit));\n\n            u4_bs = ((pv_cur_pic_addr0 != pv_nbr_pic_addr0)\n                            || (pv_cur_pic_addr1 != pv_nbr_pic_addr1)\n                            || u4_bs_temp1);\n\n            u4_bs_horz |= (u4_bs << u4_idx);\n        }\n    }\n    pu4_bs_table[0] = u4_bs_horz;\n\n    /***********************************/\n    /* Computing Bs for the left edge  */\n    /***********************************/\n    for(i = 0; i < 4; i++, ps_leftmost_mv_pred += 4)\n    {\n        UWORD32 u4_idx = 24 - (i << 3);\n\n        /*********************************/\n        /* check if Bs is already set    */\n        /*********************************/\n        if(!((u4_bs_vert >> u4_idx) & 0xf))\n        {\n            /****************************************************/\n            /* If Bs is not set, evalaute conditions for Bs=1   */\n            /****************************************************/\n            UWORD32 u4_bs_temp1;\n            UWORD32 u4_bs;\n            /*********************************************************/\n            /* If any motion vector component differs by more than 1 */\n            /* integer pel or if reference pictures are different Bs */\n            /* is set to 1. Note that this condition shall be met for*/\n            /* both (fwd-fwd,bwd-bwd) and (fwd-bwd,bwd-fwd) direction*/\n            /*********************************************************/\n\n            i2_p_mv0 = ps_leftmost_mv_pred->i2_mv[0];\n            i2_p_mv1 = ps_leftmost_mv_pred->i2_mv[1];\n            pv_nbr_pic_addr0 = ps_left_addr->u4_add[i & 2];\n            pv_nbr_pic_addr1 = ps_left_addr->u4_add[1 + (i & 2)];\n\n            u4_bs_temp1 =\n                            ((ABS((i2_p_mv0 - i2_q_mv0))\n                                            >= 4)\n                                            | (ABS((i2_p_mv1 - i2_q_mv1))\n                                                            >= i4_ver_mvlimit));\n\n            u4_bs = ((pv_cur_pic_addr0 != pv_nbr_pic_addr0)\n                            || (pv_cur_pic_addr1 != pv_nbr_pic_addr1)\n                            || u4_bs_temp1);\n\n            u4_bs_vert |= (u4_bs << u4_idx);\n        }\n    }\n    pu4_bs_table[4] = u4_bs_vert;\n\n    return;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_fill_bs1_non16x16mb_pslice                               */\n/*                                                                           */\n/*  Description   : This function fills boundray strength (=1) for those     */\n/*                  horz and vert edges of non16x16mb which are set to 0 by  */\n/*                  ih264d_fill_bs2_horz_vert. This function is used for p slices   */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : If any motion vector component of adjacent 4x4 blocks    */\n/*                  differs by more than 1 integer pel or if reference       */\n/*                  pictures are different, Bs is set to 1.                  */\n/*                                                                           */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         16 10 2008   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_fill_bs1_non16x16mb_pslice(mv_pred_t *ps_cur_mv_pred,\n                                       mv_pred_t *ps_top_mv_pred,\n                                       void **ppv_map_ref_idx_to_poc,\n                                       UWORD32 *pu4_bs_table, /* pointer to the BsTable array */\n                                       mv_pred_t *ps_leftmost_mv_pred,\n                                       neighbouradd_t *ps_left_addr,\n                                       void **u4_pic_addrress,\n                                       WORD32 i4_ver_mvlimit)\n{\n    UWORD32 edge;\n    void **ppv_map_ref_idx_to_poc_l0; //,*ppv_map_ref_idx_to_poc_l1;\n\n    PROFILE_DISABLE_BOUNDARY_STRENGTH()\n\n    ppv_map_ref_idx_to_poc_l0 = ppv_map_ref_idx_to_poc;\n\n\n    for(edge = 0; edge < 4; edge++, ps_top_mv_pred = ps_cur_mv_pred - 4)\n    {\n        /*********************************************************************/\n        /* Each iteration of this loop fills the four BS values of one HORIZ */\n        /* edge and one BS value for each of the four VERT edges.            */\n        /*********************************************************************/\n        WORD32 i;\n        UWORD32 u4_vert_idx = 24 - (edge << 3);\n        UWORD32 u4_bs_horz = pu4_bs_table[edge];\n        mv_pred_t *ps_left_mv_pred = ps_leftmost_mv_pred + (edge << 2);\n\n        for(i = 0; i < 4; i++, ps_top_mv_pred++, ps_cur_mv_pred++)\n        {\n            WORD16 i2_cur_mv0, i2_cur_mv1;\n            WORD8 i1_cur_ref0;\n            void *pv_cur_pic_addr0, *pv_cur_pic_addr1 = 0;\n            void *pv_nbr_pic_addr0, *pv_nbr_pic_addr1;\n\n            /******************************************************/\n            /* Each iteration of this inner loop computes a HORIZ */\n            /* and a VERT BS value for a 4x4 block                */\n            /******************************************************/\n            UWORD32 u4_bs_vert = (pu4_bs_table[i + 4] >> u4_vert_idx) & 0xf;\n            UWORD32 u4_horz_idx = 24 - (i << 3);\n\n            /*****************************************************/\n            /* check if vert Bs for this block is already set    */\n            /*****************************************************/\n            if(!u4_bs_vert)\n            {\n                WORD16 i2_left_mv0, i2_left_mv1;\n                /************************************************************/\n                /* If Bs is not set, use left edge and current edge mvs and */\n                /* reference pictures addresses to evaluate Bs==1           */\n                /************************************************************/\n                i2_left_mv0 = ps_left_mv_pred->i2_mv[0];\n                i2_left_mv1 = ps_left_mv_pred->i2_mv[1];\n\n                i2_cur_mv0 = ps_cur_mv_pred->i2_mv[0];\n                i2_cur_mv1 = ps_cur_mv_pred->i2_mv[1];\n\n                i1_cur_ref0 = ps_cur_mv_pred->i1_ref_frame[0];\n\n                pv_cur_pic_addr0 = ppv_map_ref_idx_to_poc_l0[i1_cur_ref0];\n                if(i)\n                {\n                    WORD8 i1_left_ref0 = ps_left_mv_pred->i1_ref_frame[0];\n                    pv_nbr_pic_addr0 = ppv_map_ref_idx_to_poc_l0[i1_left_ref0];\n                    pv_nbr_pic_addr1 = 0;\n                }\n                else\n                {\n                    pv_nbr_pic_addr0 = ps_left_addr->u4_add[edge & 2];\n                    pv_nbr_pic_addr1 = ps_left_addr->u4_add[1 + (edge & 2)];\n                }\n\n                {\n                    UWORD32 u4_bs_temp1;\n                    /*********************************************************/\n                    /* If any motion vector component differs by more than 1 */\n                    /* integer pel or if reference pictures are different Bs */\n                    /* is set to 1. Note that this condition shall be met for*/\n                    /* both (fwd-fwd,bwd-bwd) and (fwd-bwd,bwd-fwd) direction*/\n                    /*********************************************************/\n\n                    u4_bs_temp1 =\n                                    ((ABS((i2_left_mv0 - i2_cur_mv0))\n                                                    >= 4)\n                                                    | (ABS((i2_left_mv1\n                                                                    - i2_cur_mv1))\n                                                                    >= i4_ver_mvlimit));\n\n                    u4_bs_vert = ((pv_nbr_pic_addr0 != pv_cur_pic_addr0)\n                                    || (pv_nbr_pic_addr1 != pv_cur_pic_addr1)\n                                    || u4_bs_temp1);\n\n                    pu4_bs_table[i + 4] |= (u4_bs_vert << u4_vert_idx);\n                }\n            }\n\n            /*****************************************************/\n            /* check if horz Bs for this block is already set    */\n            /*****************************************************/\n            if(!((u4_bs_horz >> u4_horz_idx) & 0xf))\n            {\n                WORD16 i2_top_mv0, i2_top_mv1;\n                /************************************************************/\n                /* If Bs is not set, use top edge and current edge mvs and  */\n                /* reference pictures addresses to evaluate Bs==1           */\n                /************************************************************/\n                i2_cur_mv0 = ps_cur_mv_pred->i2_mv[0];\n                i2_cur_mv1 = ps_cur_mv_pred->i2_mv[1];\n\n                i1_cur_ref0 = ps_cur_mv_pred->i1_ref_frame[0];\n\n                i2_top_mv0 = ps_top_mv_pred->i2_mv[0];\n                i2_top_mv1 = ps_top_mv_pred->i2_mv[1];\n\n                pv_cur_pic_addr0 = ppv_map_ref_idx_to_poc_l0[i1_cur_ref0];\n                if(edge)\n                {\n                    WORD8 i1_top_ref0 = ps_top_mv_pred->i1_ref_frame[0];\n                    pv_nbr_pic_addr0 = ppv_map_ref_idx_to_poc_l0[i1_top_ref0];\n                    pv_nbr_pic_addr1 = 0;\n                }\n                else\n                {\n                    pv_nbr_pic_addr0 = u4_pic_addrress[i & 2];\n                    pv_nbr_pic_addr1 = u4_pic_addrress[1 + (i & 2)];\n                }\n\n                {\n                    UWORD32 u4_bs_temp1;\n                    UWORD32 u4_bs;\n                    /*********************************************************/\n                    /* If any motion vector component differs by more than 1 */\n                    /* integer pel or if reference pictures are different Bs */\n                    /* is set to 1. Note that this condition shall be met for*/\n                    /* both (fwd-fwd,bwd-bwd) and (fwd-bwd,bwd-fwd) direction*/\n                    /*********************************************************/\n\n                    u4_bs_temp1 =\n                                    ((ABS((i2_top_mv0 - i2_cur_mv0))\n                                                    >= 4)\n                                                    | (ABS((i2_top_mv1\n                                                                    - i2_cur_mv1))\n                                                                    >= i4_ver_mvlimit));\n\n                    u4_bs = ((pv_nbr_pic_addr0 != pv_cur_pic_addr0)\n                                    || (pv_nbr_pic_addr1 != pv_cur_pic_addr1)\n                                    || u4_bs_temp1);\n\n                    u4_bs_horz |= (u4_bs << u4_horz_idx);\n                }\n            }\n\n            ps_left_mv_pred = ps_cur_mv_pred;\n        }\n\n        pu4_bs_table[edge] = u4_bs_horz;\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_fill_bs1_16x16mb_bslice                                  */\n/*                                                                           */\n/*  Description   : This function fills boundray strength (=1) for those     */\n/*                  horz and vert mb edges of 16x16mb which are set to 0 by  */\n/*                  ih264d_fill_bs2_horz_vert. This function is used for b slices   */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : If any motion vector component of adjacent 4x4 blocks    */\n/*                  differs by more than 1 integer pel or if reference       */\n/*                  pictures are different, Bs is set to 1.                  */\n/*                                                                           */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         16 10 2008   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_fill_bs1_16x16mb_bslice(mv_pred_t *ps_cur_mv_pred,\n                                    mv_pred_t *ps_top_mv_pred,\n                                    void **ppv_map_ref_idx_to_poc,\n                                    UWORD32 *pu4_bs_table, /* pointer to the BsTable array */\n                                    mv_pred_t *ps_leftmost_mv_pred,\n                                    neighbouradd_t *ps_left_addr,\n                                    void **u4_pic_addrress,\n                                    WORD32 i4_ver_mvlimit)\n{\n    WORD16 i2_q_mv0, i2_q_mv1, i2_q_mv2, i2_q_mv3;\n    WORD16 i2_p_mv0, i2_p_mv1, i2_p_mv2, i2_p_mv3;\n    void *pv_cur_pic_addr0, *pv_cur_pic_addr1;\n    void *pv_nbr_pic_addr0, *pv_nbr_pic_addr1;\n    void **ppv_map_ref_idx_to_poc_l0, **ppv_map_ref_idx_to_poc_l1;\n    UWORD32 i;\n    UWORD32 u4_bs_horz = pu4_bs_table[0];\n    UWORD32 u4_bs_vert = pu4_bs_table[4];\n\n    PROFILE_DISABLE_BOUNDARY_STRENGTH()\n\n    ppv_map_ref_idx_to_poc_l0 = ppv_map_ref_idx_to_poc;\n    ppv_map_ref_idx_to_poc_l1 = ppv_map_ref_idx_to_poc + POC_LIST_L0_TO_L1_DIFF;\n    i2_q_mv0 = ps_cur_mv_pred->i2_mv[0];\n    i2_q_mv1 = ps_cur_mv_pred->i2_mv[1];\n    i2_q_mv2 = ps_cur_mv_pred->i2_mv[2];\n    i2_q_mv3 = ps_cur_mv_pred->i2_mv[3];\n    pv_cur_pic_addr0 = ppv_map_ref_idx_to_poc_l0[ps_cur_mv_pred->i1_ref_frame[0]];\n    pv_cur_pic_addr1 = ppv_map_ref_idx_to_poc_l1[ps_cur_mv_pred->i1_ref_frame[1]];\n\n    /*********************************/\n    /* Computing Bs for the top edge */\n    /*********************************/\n    for(i = 0; i < 4; i++, ps_top_mv_pred++)\n    {\n        UWORD32 u4_idx = 24 - (i << 3);\n\n        /*********************************/\n        /* check if Bs is already set    */\n        /*********************************/\n        if(!((u4_bs_horz >> u4_idx) & 0xf))\n        {\n            /************************************************************/\n            /* If Bs is not set, use left edge and current edge mvs and */\n            /* reference pictures addresses to evaluate Bs==1           */\n            /************************************************************/\n            UWORD32 u4_bs_temp1, u4_bs_temp2;\n            UWORD32 u4_bs;\n\n            /*********************************************************/\n            /* If any motion vector component differs by more than 1 */\n            /* integer pel or if reference pictures are different Bs */\n            /* is set to 1. Note that this condition shall be met for*/\n            /* both (fwd-fwd,bwd-bwd) and (fwd-bwd,bwd-fwd) direction*/\n            /*********************************************************/\n            i2_p_mv0 = ps_top_mv_pred->i2_mv[0];\n            i2_p_mv1 = ps_top_mv_pred->i2_mv[1];\n            i2_p_mv2 = ps_top_mv_pred->i2_mv[2];\n            i2_p_mv3 = ps_top_mv_pred->i2_mv[3];\n            pv_nbr_pic_addr0 = u4_pic_addrress[i & 2];\n            pv_nbr_pic_addr1 = u4_pic_addrress[1 + (i & 2)];\n\n            u4_bs_temp1 =\n                            ((ABS((i2_p_mv0 - i2_q_mv0))\n                                            >= 4)\n                                            | (ABS((i2_p_mv1 - i2_q_mv1))\n                                                            >= i4_ver_mvlimit)\n                                            | (ABS((i2_p_mv2 - i2_q_mv2))\n                                                            >= 4)\n                                            | (ABS((i2_p_mv3 - i2_q_mv3))\n                                                            >= i4_ver_mvlimit));\n\n            u4_bs_temp2 =\n                            ((ABS((i2_p_mv0 - i2_q_mv2))\n                                            >= 4)\n                                            | (ABS((i2_p_mv1 - i2_q_mv3))\n                                                            >= i4_ver_mvlimit)\n                                            | (ABS((i2_p_mv2 - i2_q_mv0))\n                                                            >= 4)\n                                            | (ABS((i2_p_mv3 - i2_q_mv1))\n                                                            >= i4_ver_mvlimit));\n\n            u4_bs = ((pv_cur_pic_addr0 != pv_nbr_pic_addr0)\n                            || (pv_cur_pic_addr1 != pv_nbr_pic_addr1)\n                            || u4_bs_temp1)\n                            && ((pv_cur_pic_addr0 != pv_nbr_pic_addr1)\n                                            || (pv_cur_pic_addr1\n                                                            != pv_nbr_pic_addr0)\n                                            || u4_bs_temp2);\n\n            u4_bs_horz |= (u4_bs << u4_idx);\n        }\n    }\n    pu4_bs_table[0] = u4_bs_horz;\n\n    /***********************************/\n    /* Computing Bs for the left edge  */\n    /***********************************/\n    for(i = 0; i < 4; i++, ps_leftmost_mv_pred += 4)\n    {\n        UWORD32 u4_idx = 24 - (i << 3);\n\n        /*********************************/\n        /* check if Bs is already set    */\n        /*********************************/\n        if(!((u4_bs_vert >> u4_idx) & 0xf))\n        {\n            /****************************************************/\n            /* If Bs is not set, evalaute conditions for Bs=1   */\n            /****************************************************/\n            UWORD32 u4_bs_temp1, u4_bs_temp2;\n            UWORD32 u4_bs;\n            /*********************************************************/\n            /* If any motion vector component differs by more than 1 */\n            /* integer pel or if reference pictures are different Bs */\n            /* is set to 1. Note that this condition shall be met for*/\n            /* both (fwd-fwd,bwd-bwd) and (fwd-bwd,bwd-fwd) direction*/\n            /*********************************************************/\n\n            i2_p_mv0 = ps_leftmost_mv_pred->i2_mv[0];\n            i2_p_mv1 = ps_leftmost_mv_pred->i2_mv[1];\n            i2_p_mv2 = ps_leftmost_mv_pred->i2_mv[2];\n            i2_p_mv3 = ps_leftmost_mv_pred->i2_mv[3];\n            pv_nbr_pic_addr0 = ps_left_addr->u4_add[i & 2];\n            pv_nbr_pic_addr1 = ps_left_addr->u4_add[1 + (i & 2)];\n\n            u4_bs_temp1 =\n                            ((ABS((i2_p_mv0 - i2_q_mv0))\n                                            >= 4)\n                                            | (ABS((i2_p_mv1 - i2_q_mv1))\n                                                            >= i4_ver_mvlimit)\n                                            | (ABS((i2_p_mv2 - i2_q_mv2))\n                                                            >= 4)\n                                            | (ABS((i2_p_mv3 - i2_q_mv3))\n                                                            >= i4_ver_mvlimit));\n\n            u4_bs_temp2 =\n                            ((ABS((i2_p_mv0 - i2_q_mv2))\n                                            >= 4)\n                                            | (ABS((i2_p_mv1 - i2_q_mv3))\n                                                            >= i4_ver_mvlimit)\n                                            | (ABS((i2_p_mv2 - i2_q_mv0))\n                                                            >= 4)\n                                            | (ABS((i2_p_mv3 - i2_q_mv1))\n                                                            >= i4_ver_mvlimit));\n\n            u4_bs = ((pv_cur_pic_addr0 != pv_nbr_pic_addr0)\n                            || (pv_cur_pic_addr1 != pv_nbr_pic_addr1)\n                            || u4_bs_temp1)\n                            && ((pv_cur_pic_addr0 != pv_nbr_pic_addr1)\n                                            || (pv_cur_pic_addr1\n                                                            != pv_nbr_pic_addr0)\n                                            || u4_bs_temp2);\n\n            u4_bs_vert |= (u4_bs << u4_idx);\n        }\n    }\n    pu4_bs_table[4] = u4_bs_vert;\n\n    return;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_fill_bs1_non16x16mb_bslice                               */\n/*                                                                           */\n/*  Description   : This function fills boundray strength (=1) for those     */\n/*                  horz and vert edges of non16x16mb which are set to 0 by  */\n/*                  ih264d_fill_bs2_horz_vert. This function is used for b slices   */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : If any motion vector component of adjacent 4x4 blocks    */\n/*                  differs by more than 1 integer pel or if reference       */\n/*                  pictures are different, Bs is set to 1.                  */\n/*                                                                           */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         16 10 2008   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_fill_bs1_non16x16mb_bslice(mv_pred_t *ps_cur_mv_pred,\n                                       mv_pred_t *ps_top_mv_pred,\n                                       void **ppv_map_ref_idx_to_poc,\n                                       UWORD32 *pu4_bs_table, /* pointer to the BsTable array */\n                                       mv_pred_t *ps_leftmost_mv_pred,\n                                       neighbouradd_t *ps_left_addr,\n                                       void **u4_pic_addrress,\n                                       WORD32 i4_ver_mvlimit)\n{\n    UWORD32 edge;\n    void **ppv_map_ref_idx_to_poc_l0, **ppv_map_ref_idx_to_poc_l1;\n    ppv_map_ref_idx_to_poc_l0 = ppv_map_ref_idx_to_poc;\n    ppv_map_ref_idx_to_poc_l1 = ppv_map_ref_idx_to_poc + POC_LIST_L0_TO_L1_DIFF;\n\n    PROFILE_DISABLE_BOUNDARY_STRENGTH()\n\n    for(edge = 0; edge < 4; edge++, ps_top_mv_pred = ps_cur_mv_pred - 4)\n    {\n        /*********************************************************************/\n        /* Each iteration of this loop fills the four BS values of one HORIZ */\n        /* edge and one BS value for each of the four VERT edges.            */\n        /*********************************************************************/\n        WORD32 i;\n        UWORD32 u4_vert_idx = 24 - (edge << 3);\n        UWORD32 u4_bs_horz = pu4_bs_table[edge];\n        mv_pred_t *ps_left_mv_pred = ps_leftmost_mv_pred + (edge << 2);\n\n        for(i = 0; i < 4; i++, ps_top_mv_pred++, ps_cur_mv_pred++)\n        {\n            WORD16 i2_cur_mv0, i2_cur_mv1, i16_curMv2, i16_curMv3;\n            WORD8 i1_cur_ref0, i1_cur_ref1;\n            void *pv_cur_pic_addr0, *pv_cur_pic_addr1;\n            void *pv_nbr_pic_addr0, *pv_nbr_pic_addr1;\n\n            /******************************************************/\n            /* Each iteration of this inner loop computes a HORIZ */\n            /* and a VERT BS value for a 4x4 block                */\n            /******************************************************/\n            UWORD32 u4_bs_vert = (pu4_bs_table[i + 4] >> u4_vert_idx) & 0xf;\n            UWORD32 u4_horz_idx = 24 - (i << 3);\n\n            /*****************************************************/\n            /* check if vert Bs for this block is already set    */\n            /*****************************************************/\n            if(!u4_bs_vert)\n            {\n                WORD16 i2_left_mv0, i2_left_mv1, i2_left_mv2, i2_left_mv3;\n                /************************************************************/\n                /* If Bs is not set, use left edge and current edge mvs and */\n                /* reference pictures addresses to evaluate Bs==1           */\n                /************************************************************/\n                i2_left_mv0 = ps_left_mv_pred->i2_mv[0];\n                i2_left_mv1 = ps_left_mv_pred->i2_mv[1];\n                i2_left_mv2 = ps_left_mv_pred->i2_mv[2];\n                i2_left_mv3 = ps_left_mv_pred->i2_mv[3];\n\n                i2_cur_mv0 = ps_cur_mv_pred->i2_mv[0];\n                i2_cur_mv1 = ps_cur_mv_pred->i2_mv[1];\n                i16_curMv2 = ps_cur_mv_pred->i2_mv[2];\n                i16_curMv3 = ps_cur_mv_pred->i2_mv[3];\n                i1_cur_ref0 = ps_cur_mv_pred->i1_ref_frame[0];\n                i1_cur_ref1 = ps_cur_mv_pred->i1_ref_frame[1];\n                pv_cur_pic_addr0 = ppv_map_ref_idx_to_poc_l0[i1_cur_ref0];\n                pv_cur_pic_addr1 = ppv_map_ref_idx_to_poc_l1[i1_cur_ref1];\n\n                if(i)\n                {\n                    WORD8 i1_left_ref0, i1_left_ref1;\n                    i1_left_ref0 = ps_left_mv_pred->i1_ref_frame[0];\n                    i1_left_ref1 = ps_left_mv_pred->i1_ref_frame[1];\n                    pv_nbr_pic_addr0 = ppv_map_ref_idx_to_poc_l0[i1_left_ref0];\n                    pv_nbr_pic_addr1 = ppv_map_ref_idx_to_poc_l1[i1_left_ref1];\n                }\n                else\n                {\n                    pv_nbr_pic_addr0 = ps_left_addr->u4_add[edge & 2];\n                    pv_nbr_pic_addr1 = ps_left_addr->u4_add[1 + (edge & 2)];\n                }\n\n                {\n                    UWORD32 u4_bs_temp1, u4_bs_temp2;\n                    /*********************************************************/\n                    /* If any motion vector component differs by more than 1 */\n                    /* integer pel or if reference pictures are different Bs */\n                    /* is set to 1. Note that this condition shall be met for*/\n                    /* both (fwd-fwd,bwd-bwd) and (fwd-bwd,bwd-fwd) direction*/\n                    /*********************************************************/\n\n                    u4_bs_temp1 =\n                                    ((ABS((i2_left_mv0 - i2_cur_mv0))\n                                                    >= 4)\n                                                    | (ABS((i2_left_mv1\n                                                                    - i2_cur_mv1))\n                                                                    >= i4_ver_mvlimit)\n                                                    | (ABS((i2_left_mv2\n                                                                    - i16_curMv2))\n                                                                    >= 4)\n                                                    | (ABS((i2_left_mv3\n                                                                    - i16_curMv3))\n                                                                    >= i4_ver_mvlimit));\n\n                    u4_bs_temp2 =\n                                    ((ABS((i2_left_mv0 - i16_curMv2))\n                                                    >= 4)\n                                                    | (ABS((i2_left_mv1\n                                                                    - i16_curMv3))\n                                                                    >= i4_ver_mvlimit)\n                                                    | (ABS((i2_left_mv2\n                                                                    - i2_cur_mv0))\n                                                                    >= 4)\n                                                    | (ABS((i2_left_mv3\n                                                                    - i2_cur_mv1))\n                                                                    >= i4_ver_mvlimit));\n\n                    u4_bs_vert =\n                                    ((pv_nbr_pic_addr0 != pv_cur_pic_addr0)\n                                                    || (pv_nbr_pic_addr1\n                                                                    != pv_cur_pic_addr1)\n                                                    || u4_bs_temp1)\n                                                    && ((pv_nbr_pic_addr0\n                                                                    != pv_cur_pic_addr1)\n                                                                    || (pv_nbr_pic_addr1\n                                                                                    != pv_cur_pic_addr0)\n                                                                    || u4_bs_temp2);\n\n                    pu4_bs_table[i + 4] |= (u4_bs_vert << u4_vert_idx);\n                }\n            }\n\n            /*****************************************************/\n            /* check if horz Bs for this block is already set    */\n            /*****************************************************/\n            if(!((u4_bs_horz >> u4_horz_idx) & 0xf))\n            {\n                WORD16 i2_top_mv0, i2_top_mv1, i16_topMv2, i16_topMv3;\n                /************************************************************/\n                /* If Bs is not set, use top edge and current edge mvs and  */\n                /* reference pictures addresses to evaluate Bs==1           */\n                /************************************************************/\n                i2_cur_mv0 = ps_cur_mv_pred->i2_mv[0];\n                i2_cur_mv1 = ps_cur_mv_pred->i2_mv[1];\n                i16_curMv2 = ps_cur_mv_pred->i2_mv[2];\n                i16_curMv3 = ps_cur_mv_pred->i2_mv[3];\n                i1_cur_ref0 = ps_cur_mv_pred->i1_ref_frame[0];\n                i1_cur_ref1 = ps_cur_mv_pred->i1_ref_frame[1];\n\n                i2_top_mv0 = ps_top_mv_pred->i2_mv[0];\n                i2_top_mv1 = ps_top_mv_pred->i2_mv[1];\n                i16_topMv2 = ps_top_mv_pred->i2_mv[2];\n                i16_topMv3 = ps_top_mv_pred->i2_mv[3];\n                pv_cur_pic_addr0 = ppv_map_ref_idx_to_poc_l0[i1_cur_ref0];\n                pv_cur_pic_addr1 = ppv_map_ref_idx_to_poc_l1[i1_cur_ref1];\n                if(edge)\n                {\n                    WORD8 i1_top_ref0, i1_top_ref1;\n                    i1_top_ref0 = ps_top_mv_pred->i1_ref_frame[0];\n                    i1_top_ref1 = ps_top_mv_pred->i1_ref_frame[1];\n                    pv_nbr_pic_addr0 = ppv_map_ref_idx_to_poc_l0[i1_top_ref0];\n                    pv_nbr_pic_addr1 = ppv_map_ref_idx_to_poc_l1[i1_top_ref1];\n                }\n                else\n                {\n                    pv_nbr_pic_addr0 = u4_pic_addrress[i & 2];\n                    pv_nbr_pic_addr1 = u4_pic_addrress[1 + (i & 2)];\n                }\n\n                {\n                    UWORD32 u4_bs_temp1, u4_bs_temp2;\n                    UWORD32 u4_bs;\n                    /*********************************************************/\n                    /* If any motion vector component differs by more than 1 */\n                    /* integer pel or if reference pictures are different Bs */\n                    /* is set to 1. Note that this condition shall be met for*/\n                    /* both (fwd-fwd,bwd-bwd) and (fwd-bwd,bwd-fwd) direction*/\n                    /*********************************************************/\n\n                    u4_bs_temp1 =\n                                    ((ABS((i2_top_mv0 - i2_cur_mv0))\n                                                    >= 4)\n                                                    | (ABS((i2_top_mv1\n                                                                    - i2_cur_mv1))\n                                                                    >= i4_ver_mvlimit)\n                                                    | (ABS((i16_topMv2\n                                                                    - i16_curMv2))\n                                                                    >= 4)\n                                                    | (ABS((i16_topMv3\n                                                                    - i16_curMv3))\n                                                                    >= i4_ver_mvlimit));\n\n                    u4_bs_temp2 =\n                                    ((ABS((i2_top_mv0 - i16_curMv2))\n                                                    >= 4)\n                                                    | (ABS((i2_top_mv1\n                                                                    - i16_curMv3))\n                                                                    >= i4_ver_mvlimit)\n                                                    | (ABS((i16_topMv2\n                                                                    - i2_cur_mv0))\n                                                                    >= 4)\n                                                    | (ABS((i16_topMv3\n                                                                    - i2_cur_mv1))\n                                                                    >= i4_ver_mvlimit));\n\n                    u4_bs =\n                                    ((pv_nbr_pic_addr0 != pv_cur_pic_addr0)\n                                                    || (pv_nbr_pic_addr1\n                                                                    != pv_cur_pic_addr1)\n                                                    || u4_bs_temp1)\n                                                    && ((pv_nbr_pic_addr0\n                                                                    != pv_cur_pic_addr1)\n                                                                    || (pv_nbr_pic_addr1\n                                                                                    != pv_cur_pic_addr0)\n                                                                    || u4_bs_temp2);\n\n                    u4_bs_horz |= (u4_bs << u4_horz_idx);\n                }\n            }\n\n            ps_left_mv_pred = ps_cur_mv_pred;\n        }\n\n        pu4_bs_table[edge] = u4_bs_horz;\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_fill_bs_xtra_left_edge_cur_fld                           */\n/*                                                                           */\n/*  Description   : This function fills boundray strength (= 2 or 1) for     */\n/*                  xtra left mb edge when cur mb is field and left mb is    */\n/*                  frame.                                                   */\n/*  Inputs        :                                                          */\n/*                                                                           */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    :                                                          */\n/*                                                                           */\n/*                                                                           */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         16 10 2008   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_fill_bs_xtra_left_edge_cur_fld(UWORD32 *pu4_bs, /* Base pointer of BS table */\n                                           WORD32 u4_left_mb_t_csbp, /* left mbpair's top csbp   */\n                                           WORD32 u4_left_mb_b_csbp, /* left mbpair's bottom csbp*/\n                                           WORD32 u4_cur_mb_csbp, /* csbp of current mb */\n                                           UWORD32 u4_cur_mb_top /* is top or bottom mb */\n\n                                           )\n{\n    const UWORD32 *pu4_packed_bs = (const UWORD32 *)gau4_ih264d_packed_bs2;\n    UWORD32 u4_cur, u4_left, u4_or;\n    UNUSED(u4_cur_mb_top);\n\n    PROFILE_DISABLE_BOUNDARY_STRENGTH()\n\n    u4_left_mb_t_csbp = ((u4_left_mb_t_csbp & 0x0008) >> 3)\n                    + ((u4_left_mb_t_csbp & 0x0080) >> 6)\n                    + ((u4_left_mb_t_csbp & 0x0800) >> 9)\n                    + ((u4_left_mb_t_csbp & 0x8000) >> 12);\n\n    u4_left_mb_b_csbp = ((u4_left_mb_b_csbp & 0x0008) << 1)\n                    + ((u4_left_mb_b_csbp & 0x0080) >> 2)\n                    + ((u4_left_mb_b_csbp & 0x0800) >> 5)\n                    + ((u4_left_mb_b_csbp & 0x8000) >> 8);\n\n    /*********************************************************************/\n    /* u4_cur = 0|0|0|0|0|0|0|0|12C|12C|8C|8C|4C|4C|0C|0C                */\n    /*********************************************************************/\n    u4_cur = (u4_cur_mb_csbp & 0x0001) + ((u4_cur_mb_csbp & 0x0001) << 1)\n                    + ((u4_cur_mb_csbp & 0x0010) >> 2)\n                    + ((u4_cur_mb_csbp & 0x0010) >> 1)\n                    + ((u4_cur_mb_csbp & 0x0100) >> 4)\n                    + ((u4_cur_mb_csbp & 0x0100) >> 3)\n                    + ((u4_cur_mb_csbp & 0x1000) >> 6)\n                    + ((u4_cur_mb_csbp & 0x1000) >> 5);\n\n    /*********************************************************************/\n    /* u4_left =0|0|0|0|0|0|0|0|15Lb|11Lb|7Lb|3Lb|15Lt|11Lt|7Lt|3Lt      */\n    /*********************************************************************/\n    u4_left = u4_left_mb_t_csbp + u4_left_mb_b_csbp;\n\n    u4_or = (u4_cur | u4_left);\n    /*********************************************************************/\n    /* Fill vert edges (4,9) boundary strengths  using look up table     */\n    /*********************************************************************/\n    pu4_packed_bs += 16;\n    pu4_bs[4] = pu4_packed_bs[u4_or & 0xF];\n    pu4_bs[9] = pu4_packed_bs[(u4_or >> 4)];\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_fill_bs_xtra_left_edge_cur_frm                           */\n/*                                                                           */\n/*  Description   : This function fills boundray strength (= 2 or 1) for     */\n/*                  xtra left mb edge when cur mb is frame and left mb is    */\n/*                  field.                                                   */\n/*  Inputs        :                                                          */\n/*                                                                           */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    :                                                          */\n/*                                                                           */\n/*                                                                           */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         16 10 2008   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_fill_bs_xtra_left_edge_cur_frm(UWORD32 *pu4_bs, /* Base pointer of BS table */\n                                           WORD32 u4_left_mb_t_csbp, /* left mbpair's top csbp   */\n                                           WORD32 u4_left_mb_b_csbp, /* left mbpair's bottom csbp*/\n                                           WORD32 u4_cur_mb_csbp, /* csbp of current mb */\n                                           UWORD32 u4_cur_mb_bot /* is top or bottom mb */\n\n                                           )\n{\n    const UWORD32 *pu4_packed_bs = (const UWORD32 *)gau4_ih264d_packed_bs2;\n    UWORD32 u4_cur, u4_left, u4_or;\n    UWORD32 u4_right_shift = (u4_cur_mb_bot << 3);\n\n    PROFILE_DISABLE_BOUNDARY_STRENGTH()\n\n    u4_left_mb_t_csbp >>= u4_right_shift;\n    u4_left_mb_b_csbp >>= u4_right_shift;\n\n    u4_left_mb_t_csbp = ((u4_left_mb_t_csbp & 0x08) >> 3)\n                    + ((u4_left_mb_t_csbp & 0x08) >> 2)\n                    + ((u4_left_mb_t_csbp & 0x80) >> 5)\n                    + ((u4_left_mb_t_csbp & 0x80) >> 4);\n\n    u4_left_mb_b_csbp = ((u4_left_mb_b_csbp & 0x08) << 1)\n                    + ((u4_left_mb_b_csbp & 0x08) << 2)\n                    + ((u4_left_mb_b_csbp & 0x80) >> 1)\n                    + ((u4_left_mb_b_csbp & 0x80));\n\n    u4_cur = ((u4_cur_mb_csbp & 0x0001)) + ((u4_cur_mb_csbp & 0x0010) >> 3)\n                    + ((u4_cur_mb_csbp & 0x0100) >> 6)\n                    + ((u4_cur_mb_csbp & 0x1000) >> 9);\n\n    u4_cur += (u4_cur << 4);\n\n    u4_left = u4_left_mb_t_csbp + u4_left_mb_b_csbp;\n\n    u4_or = (u4_cur | u4_left);\n    /*********************************************************************/\n    /* Fill vert edges (4,9) boundary strengths  using look up table     */\n    /*********************************************************************/\n    pu4_packed_bs += 16;\n    pu4_bs[4] = pu4_packed_bs[u4_or & 0xF];\n    pu4_bs[9] = pu4_packed_bs[(u4_or >> 4)];\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_fill_bs_xtra_top_edge                                    */\n/*                                                                           */\n/*  Description   : This function fills boundray strength (= 2 or 1) for     */\n/*                  xtra top mb edge when cur mb is top mb of frame mb pair  */\n/*                  and top mbpair is field coded.                           */\n/*  Inputs        :                                                          */\n/*                                                                           */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    :                                                          */\n/*                                                                           */\n/*                                                                           */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         16 10 2008   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_fill_bs_xtra_top_edge(UWORD32 *pu4_bs, /* Base pointer of BS table */\n                                  WORD32 u4_topmb_t_csbp, /* top mbpair's top csbp   */\n                                  WORD32 u4_topmb_b_csbp, /* top mbpair's bottom csbp*/\n                                  WORD32 u4_cur_mb_csbp /* csbp of current mb */\n\n                                  )\n{\n    const UWORD32 *pu4_packed_bs = (const UWORD32 *)gau4_ih264d_packed_bs2;\n    UWORD32 u4_or;\n\n    u4_cur_mb_csbp &= 0xf;\n    u4_topmb_t_csbp >>= 12;\n    u4_topmb_b_csbp >>= 12;\n\n    u4_or = (u4_cur_mb_csbp | u4_topmb_t_csbp);\n    /*********************************************************************/\n    /* Fill vert edges (0,8) boundary strengths  using look up table     */\n    /*********************************************************************/\n    pu4_packed_bs += 16;\n    pu4_bs[8] = pu4_packed_bs[u4_or];\n\n    u4_or = (u4_cur_mb_csbp | u4_topmb_b_csbp);\n    pu4_bs[0] = pu4_packed_bs[u4_or];\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_compute_bs_non_mbaff                                        */\n/*                                                                           */\n/*  Description   : This function computes the pointers of left,top & current*/\n/*                : Nnz, MvPred & deblk_mb_t and supplies to FillBs function for*/\n/*                : Boundary Strength Calculation                            */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Processing    : This functions calls deblock MB in the MB increment order*/\n/*                                                                           */\n/*  Outputs       : Produces the Boundary Strength for Current Mb            */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                      ITTIAM                                               */\n/*****************************************************************************/\n\nvoid ih264d_compute_bs_non_mbaff(dec_struct_t * ps_dec,\n                                 dec_mb_info_t * ps_cur_mb_info,\n                                 const UWORD16 u2_mbxn_mb)\n{\n    /* Mvpred and Nnz for top and Courrent */\n    mv_pred_t *ps_cur_mv_pred, *ps_top_mv_pred = NULL, *ps_left_mv_pred;\n    /* deblk_mb_t Params */\n    deblk_mb_t *ps_cur_mb_params; /*< Parameters of current MacroBlock */\n    deblkmb_neighbour_t *ps_deblk_top_mb;\n\n    /* Reference Index to POC mapping*/\n    void ** apv_map_ref_idx_to_poc;\n    UWORD32 u4_leftmbtype;\n\n    UWORD16 u2_left_csbp, u2_top_csbp, u2_cur_csbp;\n\n    /* Set of flags */\n    UWORD32 u4_cur_mb_intra, u1_top_mb_typ, u4_cur_mb_fld;\n    UWORD32 u1_cur_mb_type;\n    UWORD32 * pu4_bs_table;\n\n    /* Neighbour availability */\n    /* Initialization */\n    const UWORD32 u2_mbx = ps_cur_mb_info->u2_mbx;\n    const UWORD32 u2_mby = ps_cur_mb_info->u2_mby;\n    const UWORD32 u1_pingpong = u2_mbx & 0x01;\n\n    PROFILE_DISABLE_BOUNDARY_STRENGTH()\n\n    ps_deblk_top_mb = ps_dec->ps_deblk_top_mb + u2_mbx;\n\n\n    /* Pointer assignment for Current DeblkMB, Current Mv Pred  */\n    ps_cur_mb_params = ps_dec->ps_deblk_mbn + u2_mbxn_mb;\n    ps_cur_mv_pred = ps_dec->ps_mv_cur + (u2_mbxn_mb << 4);\n\n    apv_map_ref_idx_to_poc = ps_dec->ppv_map_ref_idx_to_poc + 1;\n    u1_cur_mb_type = ps_cur_mb_params->u1_mb_type;\n    u1_top_mb_typ = ps_deblk_top_mb->u1_mb_type;\n    ps_deblk_top_mb->u1_mb_type = u1_cur_mb_type;\n\n    {\n        UWORD8 mb_qp_temp;\n\n        ps_cur_mb_params->u1_topmb_qp = ps_deblk_top_mb->u1_mb_qp;\n        ps_deblk_top_mb->u1_mb_qp = ps_cur_mb_params->u1_mb_qp;\n\n        ps_cur_mb_params->u1_left_mb_qp = ps_dec->deblk_left_mb[1].u1_mb_qp;\n        ps_dec->deblk_left_mb[1].u1_mb_qp = ps_cur_mb_params->u1_mb_qp;\n\n    }\n\n    /* if no deblocking required for current Mb then continue */\n    /* Check next Mbs   in Mb group                           */\n    if(ps_cur_mb_params->u1_deblocking_mode & MB_DISABLE_FILTERING)\n    {\n        void ** pu4_map_ref_idx_to_poc_l1 = apv_map_ref_idx_to_poc +\n        POC_LIST_L0_TO_L1_DIFF;\n        {\n            /* Store Parameter for Top MvPred refernce frame Address */\n\n            void ** ppv_top_mv_pred_addr = ps_cur_mb_info->ps_curmb->u4_pic_addrress;\n            WORD8 * p1_refTop0 = (ps_cur_mv_pred + 12)->i1_ref_frame;\n            WORD8 * p1_refTop1 = (ps_cur_mv_pred + 14)->i1_ref_frame;\n\n            /* Store Left addresses for Next Mb   */\n            void ** ppv_left_mv_pred_addr =\n                            ps_dec->ps_left_mvpred_addr[!u1_pingpong][1].u4_add;\n            WORD8 * p1_refleft0 = (ps_cur_mv_pred + 3)->i1_ref_frame;\n\n\n            ppv_top_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refTop0[0]];\n            ppv_top_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refTop0[1]];\n\n            ppv_left_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_top_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_left_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n            ppv_top_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n\n            ppv_left_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refleft0[0]];\n            ppv_left_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refleft0[1]];\n            //}\n            /* Storing the leftMbtype for next Mb */\n            ps_dec->deblk_left_mb[1].u1_mb_type = ps_cur_mb_params->u1_mb_type;\n        }\n\n        return;\n    }\n\n    /* Flag for extra left Edge */\n    ps_cur_mb_params->u1_single_call = 1;\n\n    /* Update the Left deblk_mb_t and Left MvPred Parameters           */\n    if(!u2_mbx)\n    {\n        u4_leftmbtype = 0;\n\n        /* Initialize the ps_left_mv_pred with Junk but Valid Location */\n        /* to avoid invalid memory access                           */\n        /* this is read only pointer                                */\n        ps_left_mv_pred = ps_dec->ps_mv_cur + 3;\n    }\n    else\n    {\n        u4_leftmbtype = ps_dec->deblk_left_mb[1].u1_mb_type;\n\n        /* Come to Left Most Edge of the MB */\n        ps_left_mv_pred = (u2_mbxn_mb) ?\n                        ps_dec->ps_mv_cur + ((u2_mbxn_mb - 1) << 4) + 3 :\n                        ps_dec->ps_mv_left + 3;\n    }\n\n    if(!u2_mby)\n        u1_top_mb_typ = 0;\n\n    /* MvPred Pointer Calculation */\n    /* CHANGED CODE */\n    ps_top_mv_pred = ps_cur_mv_pred - (ps_dec->u2_frm_wd_in_mbs << 4) + 12;\n\n    u4_cur_mb_intra = u1_cur_mb_type & D_INTRA_MB;\n    u4_cur_mb_fld = !!(u1_cur_mb_type & D_FLD_MB);\n    /* Compute BS function */\n    pu4_bs_table = ps_cur_mb_params->u4_bs_table;\n\n    u2_cur_csbp = ps_cur_mb_info->ps_curmb->u2_luma_csbp;\n    u2_left_csbp = ps_cur_mb_info->ps_left_mb->u2_luma_csbp;\n    u2_top_csbp = ps_cur_mb_info->ps_top_mb->u2_luma_csbp;\n    /* Compute BS function */\n    if(ps_dec->ps_cur_sps->u1_profile_idc == HIGH_PROFILE_IDC)\n    {\n        if(ps_cur_mb_info->u1_tran_form8x8 == 1)\n        {\n            u2_cur_csbp = ih264d_update_csbp_8x8(\n                            ps_cur_mb_info->ps_curmb->u2_luma_csbp);\n        }\n\n        if(ps_cur_mb_info->ps_left_mb->u1_tran_form8x8 == 1)\n        {\n            u2_left_csbp = ih264d_update_csbp_8x8(\n                            ps_cur_mb_info->ps_left_mb->u2_luma_csbp);\n        }\n\n        if(ps_cur_mb_info->ps_top_mb->u1_tran_form8x8 == 1)\n        {\n            u2_top_csbp = ih264d_update_csbp_8x8(\n                            ps_cur_mb_info->ps_top_mb->u2_luma_csbp);\n        }\n    }\n    if(u4_cur_mb_intra)\n    {\n\n        pu4_bs_table[4] = 0x04040404;\n        pu4_bs_table[0] = u4_cur_mb_fld ? 0x03030303 : 0x04040404;\n        pu4_bs_table[1] = 0x03030303;\n        pu4_bs_table[2] = 0x03030303;\n        pu4_bs_table[3] = 0x03030303;\n        pu4_bs_table[5] = 0x03030303;\n        pu4_bs_table[6] = 0x03030303;\n        pu4_bs_table[7] = 0x03030303;\n    }\n    else\n    {\n        UWORD32 u4_is_non16x16 = !!(u1_cur_mb_type & D_PRED_NON_16x16);\n        UWORD32 u4_is_b = ps_dec->u1_B;\n\n        ih264d_fill_bs2_horz_vert(\n                        pu4_bs_table, u2_left_csbp, u2_top_csbp, u2_cur_csbp,\n                        (const UWORD32 *)(gau4_ih264d_packed_bs2),\n                        (const UWORD16 *)(gau2_ih264d_4x4_v2h_reorder));\n\n        if(u4_leftmbtype & D_INTRA_MB)\n            pu4_bs_table[4] = 0x04040404;\n\n        if(u1_top_mb_typ & D_INTRA_MB)\n            pu4_bs_table[0] = u4_cur_mb_fld ? 0x03030303 : 0x04040404;\n\n        ps_dec->pf_fill_bs1[u4_is_b][u4_is_non16x16](\n                        ps_cur_mv_pred, ps_top_mv_pred, apv_map_ref_idx_to_poc,\n                        pu4_bs_table, ps_left_mv_pred,\n                        &(ps_dec->ps_left_mvpred_addr[u1_pingpong][1]),\n                        ps_cur_mb_info->ps_top_mb->u4_pic_addrress,\n                        (4 >> u4_cur_mb_fld));\n    }\n\n    {\n        void ** pu4_map_ref_idx_to_poc_l1 = apv_map_ref_idx_to_poc +\n        POC_LIST_L0_TO_L1_DIFF;\n        {\n            /* Store Parameter for Top MvPred refernce frame Address */\n\n            void ** ppv_top_mv_pred_addr = ps_cur_mb_info->ps_curmb->u4_pic_addrress;\n            WORD8 * p1_refTop0 = (ps_cur_mv_pred + 12)->i1_ref_frame;\n            WORD8 * p1_refTop1 = (ps_cur_mv_pred + 14)->i1_ref_frame;\n\n            /* Store Left addresses for Next Mb   */\n            void ** ppv_left_mv_pred_addr =\n                            ps_dec->ps_left_mvpred_addr[!u1_pingpong][1].u4_add;\n            WORD8 * p1_refleft0 = (ps_cur_mv_pred + 3)->i1_ref_frame;\n\n            ppv_top_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refTop0[0]];\n            ppv_top_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refTop0[1]];\n\n            ppv_left_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_top_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_left_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n            ppv_top_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n\n            ppv_left_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refleft0[0]];\n            ppv_left_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refleft0[1]];\n\n            /* Storing the leftMbtype for next Mb */\n            ps_dec->deblk_left_mb[1].u1_mb_type = ps_cur_mb_params->u1_mb_type;\n\n        }\n    }\n\n    /* For transform 8x8 disable deblocking of the intrernal edges of a 8x8 block */\n    if(ps_cur_mb_info->u1_tran_form8x8)\n    {\n        pu4_bs_table[1] = 0;\n        pu4_bs_table[3] = 0;\n        pu4_bs_table[5] = 0;\n        pu4_bs_table[7] = 0;\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_compute_bs_mbaff                                           */\n/*                                                                           */\n/*  Description   : This function computes the pointers of left,top & current*/\n/*                : Nnz, MvPred & deblk_mb_t and supplies to FillBs function for*/\n/*                : Boundary Strength Calculation                            */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Processing    : This functions calls deblock MB in the MB increment order*/\n/*                                                                           */\n/*  Outputs       : Produces the Boundary Strength for Current Mb            */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                      ITTIAM                                               */\n/*****************************************************************************/\n\nvoid ih264d_compute_bs_mbaff(dec_struct_t * ps_dec,\n                             dec_mb_info_t * ps_cur_mb_info,\n                             const UWORD16 u2_mbxn_mb)\n{\n    /* Mvpred and Nnz for top and Courrent */\n    mv_pred_t *ps_cur_mv_pred, *ps_top_mv_pred = NULL, *ps_left_mv_pred;\n    /* deblk_mb_t Params */\n    deblk_mb_t *ps_cur_mb_params; /*< Parameters of current MacroBlock */\n    neighbouradd_t * ps_left_ngbr;\n    deblkmb_neighbour_t *ps_deblk_top_mb;\n    /* Reference Index to POC mapping*/\n    void ** apv_map_ref_idx_to_poc;\n\n    UWORD32 u4_leftmbtype;\n\n\n    UWORD16 u2_left_csbp, u2_top_csbp, u2_cur_csbp;\n\n    /* Set of flags */\n    UWORD32 u4_cur_mb_intra, u4_cur_mb_fld, u4_top_mb_fld, u1_top_mb_typ, u4_left_mb_fld;\n    UWORD32 u1_cur_mb_type;\n    UWORD32 * pu4_bs_table;\n    const UWORD32 u4_bot_mb = (1 - ps_cur_mb_info->u1_topmb);\n    /* Initialization */\n    const UWORD32 u2_mbx = ps_cur_mb_info->u2_mbx;\n    const UWORD32 u2_mby = ps_cur_mb_info->u2_mby;\n    /* Load From u1_pingpong and Store in !u1_pingpong */\n    const UWORD32 u1_pingpong = u2_mbx & 0x01;\n\n    PROFILE_DISABLE_BOUNDARY_STRENGTH()\n\n    ps_deblk_top_mb = ps_dec->ps_deblk_top_mb + (u2_mbx << 1);\n\n\n    /************************************************/\n    /* Initialize the left Mb type                  */\n    /* Left MvPred                                  */\n    /************************************************/\n\n    if(!u2_mbx)\n    {\n        /************************************************************/\n        /* Initialize the ps_left_mv_pred with Junk but Valid Location */\n        /* to avoid invalid memory access                       */\n        /* this is read only pointer                                */\n        /************************************************************/\n        ps_left_mv_pred = ps_dec->ps_mv_cur + 16;\n    }\n    else\n    {\n        /* Come to Left Most Edge of the MB */\n        ps_left_mv_pred = (u2_mbxn_mb) ?\n                        ps_dec->ps_mv_cur + ((u2_mbxn_mb - 1) << 5) + 3 :\n                        ps_dec->ps_mv_left + 3;\n\n        ps_left_mv_pred += (u4_bot_mb << 4);\n    }\n\n    u4_leftmbtype = ps_dec->deblk_left_mb[u4_bot_mb].u1_mb_type;\n\n    ps_left_ngbr = &(ps_dec->ps_left_mvpred_addr[u1_pingpong][u4_bot_mb]);\n\n    /************************************************/\n    /* Pointer Assignment for Current Mb Parameters */\n    /* Pointer Assignment for Current MvPred        */\n    /************************************************/\n    ps_cur_mb_params = ps_dec->ps_deblk_mbn + (u2_mbxn_mb << 1) + u4_bot_mb;\n    u1_cur_mb_type = ps_cur_mb_params->u1_mb_type;\n\n    ps_cur_mv_pred = ps_dec->ps_mv_cur + (u2_mbxn_mb << 5);\n    ps_cur_mv_pred += (u4_bot_mb << 4);\n\n    /********************************************/\n    /* Pointer Assignment for Top Mb Parameters */\n    /* Pointer Assignment for Top MvPred and    */\n    /* Pointer Assignment for Top Nnz           */\n    /********************************************/\n\n    /* CHANGED CODE */\n    ps_top_mv_pred = ps_cur_mv_pred - (ps_dec->u2_frm_wd_in_mbs << 5) + 12;\n\n    u4_cur_mb_fld = !!(u1_cur_mb_type & D_FLD_MB);\n    u4_left_mb_fld = !!(ps_dec->deblk_left_mb[0].u1_mb_type & D_FLD_MB);\n\n    if(u4_left_mb_fld != u4_cur_mb_fld)\n    {\n        /* Flag for extra left Edge */\n        ps_cur_mb_params->u1_single_call = 0;\n\n        if(u4_bot_mb)\n        {\n            ps_left_ngbr--;\n            ps_left_mv_pred -= 16;\n        }\n    }\n    else\n        ps_cur_mb_params->u1_single_call = 1;\n\n    apv_map_ref_idx_to_poc = ps_dec->ppv_map_ref_idx_to_poc + 1;\n    if(u4_cur_mb_fld)\n    {\n        if(u4_bot_mb)\n        {\n            apv_map_ref_idx_to_poc += BOT_LIST_FLD_L0;\n        }\n        else\n        {\n            apv_map_ref_idx_to_poc += TOP_LIST_FLD_L0;\n        }\n    }\n\n    /**********************************************************/\n    /* if no deblocking required for current Mb then continue */\n    /**********************************************************/\n    if(ps_cur_mb_params->u1_deblocking_mode & MB_DISABLE_FILTERING)\n    {\n        void ** pu4_map_ref_idx_to_poc_l1 = apv_map_ref_idx_to_poc +\n        POC_LIST_L0_TO_L1_DIFF;\n\n        {\n            /* Store Parameter for Top MvPred refernce frame Address */\n\n            void ** ppv_top_mv_pred_addr = ps_cur_mb_info->ps_curmb->u4_pic_addrress;\n            void ** ppv_left_mv_pred_addr =\n                            ps_dec->ps_left_mvpred_addr[!u1_pingpong][u4_bot_mb].u4_add;\n            WORD8 * p1_refTop0 = (ps_cur_mv_pred + 12)->i1_ref_frame;\n            WORD8 * p1_refTop1 = (ps_cur_mv_pred + 14)->i1_ref_frame;\n            WORD8 * p1_refLeft0 = (ps_cur_mv_pred + 3)->i1_ref_frame;\n            ppv_top_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refTop0[0]];\n            ppv_top_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refTop0[1]];\n            ppv_left_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_top_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_left_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n            ppv_top_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n            ppv_left_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refLeft0[0]];\n            ppv_left_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refLeft0[1]];\n        }\n        if(u4_bot_mb)\n        {\n            /* store The Left Mb Type*/\n            ps_dec->deblk_left_mb[0].u1_mb_type =\n                            (ps_cur_mb_params - 1)->u1_mb_type;\n            ps_dec->deblk_left_mb[1].u1_mb_type = ps_cur_mb_params->u1_mb_type;\n\n        }\n        ps_deblk_top_mb[u4_bot_mb].u1_mb_type = u1_cur_mb_type;\n        return;\n    }\n\n    if(u2_mby)\n    {\n        u1_top_mb_typ = ps_deblk_top_mb[1].u1_mb_type;\n        u4_top_mb_fld = !!(u1_top_mb_typ & D_FLD_MB);\n\n        if(!u4_bot_mb)\n        {\n            if(u4_top_mb_fld & u4_cur_mb_fld)\n                u1_top_mb_typ = ps_deblk_top_mb[0].u1_mb_type;\n            else\n            {\n                ps_top_mv_pred += 16;\n            }\n        }\n    }\n    else\n    {\n        u4_top_mb_fld = u4_cur_mb_fld;\n        u1_top_mb_typ = 0;\n    }\n\n    if(u4_bot_mb & !u4_cur_mb_fld)\n    {\n        u1_top_mb_typ = ps_deblk_top_mb[0].u1_mb_type;\n        u4_top_mb_fld = u4_cur_mb_fld;\n        ps_top_mv_pred = ps_cur_mv_pred - 4;\n    }\n\n    pu4_bs_table = ps_cur_mb_params->u4_bs_table;\n    u4_cur_mb_intra = u1_cur_mb_type & D_INTRA_MB;\n\n    u2_cur_csbp = ps_cur_mb_info->ps_curmb->u2_luma_csbp;\n    u2_left_csbp = ps_cur_mb_info->ps_left_mb->u2_luma_csbp;\n    u2_top_csbp = ps_cur_mb_info->ps_top_mb->u2_luma_csbp;\n    /* Compute BS function */\n    if(ps_dec->ps_cur_sps->u1_profile_idc == HIGH_PROFILE_IDC)\n    {\n\n        if(ps_cur_mb_info->u1_tran_form8x8 == 1)\n        {\n            u2_cur_csbp = ih264d_update_csbp_8x8(\n                            ps_cur_mb_info->ps_curmb->u2_luma_csbp);\n        }\n\n        if(ps_cur_mb_info->ps_left_mb->u1_tran_form8x8 == 1)\n        {\n            u2_left_csbp = ih264d_update_csbp_8x8(\n                            ps_cur_mb_info->ps_left_mb->u2_luma_csbp);\n        }\n\n        if(ps_cur_mb_info->ps_top_mb->u1_tran_form8x8 == 1)\n        {\n            u2_top_csbp = ih264d_update_csbp_8x8(\n                            ps_cur_mb_info->ps_top_mb->u2_luma_csbp);\n        }\n    }\n    if(u4_cur_mb_intra)\n    {\n\n        pu4_bs_table[4] = 0x04040404;\n        if((0 == u4_cur_mb_fld) && (0 == u4_top_mb_fld))\n        {\n            pu4_bs_table[0] = 0x04040404;\n        }\n        else\n        {\n            pu4_bs_table[0] = 0x03030303;\n        }\n\n        pu4_bs_table[1] = 0x03030303;\n        pu4_bs_table[2] = 0x03030303;\n        pu4_bs_table[3] = 0x03030303;\n        pu4_bs_table[5] = 0x03030303;\n        pu4_bs_table[6] = 0x03030303;\n        pu4_bs_table[7] = 0x03030303;\n\n        /*********************************************************************/\n        /* Fill Bs of xtra top and left edge unconditionally to avoid checks */\n        /*********************************************************************/\n        pu4_bs_table[8] = 0x03030303;\n        pu4_bs_table[9] = 0x04040404;\n    }\n    else\n    {\n        UWORD32 u4_is_non16x16 = !!(u1_cur_mb_type & D_PRED_NON_16x16);\n        UWORD32 u4_is_b = ps_dec->u1_B;\n\n        ih264d_fill_bs2_horz_vert(\n                        pu4_bs_table, u2_left_csbp, u2_top_csbp, u2_cur_csbp,\n                        (const UWORD32 *)(gau4_ih264d_packed_bs2),\n                        (const UWORD16 *)(gau2_ih264d_4x4_v2h_reorder));\n\n        if(u4_leftmbtype & D_INTRA_MB)\n            pu4_bs_table[4] = 0x04040404;\n\n        if(u1_top_mb_typ & D_INTRA_MB)\n            pu4_bs_table[0] = u4_cur_mb_fld ? 0x03030303 : 0x04040404;\n        else if(u4_cur_mb_fld != u4_top_mb_fld)\n        {\n            /****************************************************/\n            /* Setting BS for mixed mode edge=1 when (Bs!=2)    */\n            /****************************************************/\n            pu4_bs_table[0] = (pu4_bs_table[0] >> 1) + 0x01010101;\n        }\n\n        {\n            /* Call to Compute Boundary Strength for Extra Left Edge */\n            if(u2_mbx\n                            && !(ps_cur_mb_params->u1_deblocking_mode\n                                            & MB_DISABLE_LEFT_EDGE))\n            {\n                if(u4_cur_mb_fld != u4_left_mb_fld)\n                {\n                    UWORD32 u4_left_mb_t_csbp =\n                                    ps_cur_mb_info->ps_left_mb[0].u2_luma_csbp;\n                    UWORD32 u4_left_mb_b_csbp =\n                                    ps_cur_mb_info->ps_left_mb[1].u2_luma_csbp;\n                    if(1 == ps_cur_mb_info->ps_left_mb[0].u1_tran_form8x8)\n                    {\n                        u4_left_mb_t_csbp = (UWORD32)ih264d_update_csbp_8x8(\n                                        (UWORD16)u4_left_mb_t_csbp);\n                    }\n\n                    if(1 == ps_cur_mb_info->ps_left_mb[1].u1_tran_form8x8)\n                    {\n                        u4_left_mb_b_csbp = (UWORD32)ih264d_update_csbp_8x8(\n                                        (UWORD16)u4_left_mb_b_csbp);\n                    }\n                    ps_dec->pf_fill_bs_xtra_left_edge[u4_cur_mb_fld](\n                                    pu4_bs_table, u4_left_mb_t_csbp,\n                                    u4_left_mb_b_csbp, u2_cur_csbp, u4_bot_mb);\n\n                    if(ps_dec->deblk_left_mb[0].u1_mb_type & D_INTRA_MB)\n                        pu4_bs_table[4] = 0x04040404;\n\n                    if(ps_dec->deblk_left_mb[1].u1_mb_type & D_INTRA_MB)\n                        pu4_bs_table[9] = 0x04040404;\n\n                }\n            }\n            /* Call to Compute Boundary Strength for Extra Top Edge */\n            if(u2_mby\n                            && !(ps_cur_mb_params->u1_deblocking_mode\n                                            & MB_DISABLE_TOP_EDGE))\n            {\n                if((((!u4_bot_mb) & (!u4_cur_mb_fld)) && u4_top_mb_fld))\n                {\n                    UWORD32 u4_topmb_t_csbp =\n                                    ps_cur_mb_info->ps_top_mb[-1].u2_luma_csbp;\n                    UWORD32 u4_topmb_b_csbp =\n                                    ps_cur_mb_info->ps_top_mb[0].u2_luma_csbp;\n                    if(1 == ps_cur_mb_info->ps_top_mb[-1].u1_tran_form8x8)\n                    {\n                        u4_topmb_t_csbp = (UWORD32)ih264d_update_csbp_8x8(\n                                        (UWORD16)u4_topmb_t_csbp);\n                    }\n\n                    if(1 == ps_cur_mb_info->ps_top_mb[0].u1_tran_form8x8)\n                    {\n                        u4_topmb_b_csbp = (UWORD32)ih264d_update_csbp_8x8(\n                                        (UWORD16)u4_topmb_b_csbp);\n                    }\n                    ih264d_fill_bs_xtra_top_edge(pu4_bs_table, u4_topmb_t_csbp,\n                                                 u4_topmb_b_csbp, u2_cur_csbp);\n\n                    if(ps_deblk_top_mb[0].u1_mb_type & D_INTRA_MB)\n                        pu4_bs_table[8] = 0x03030303;\n\n                    if(ps_deblk_top_mb[1].u1_mb_type & D_INTRA_MB)\n                        pu4_bs_table[0] = 0x03030303;\n                }\n            }\n        }\n\n        ps_dec->pf_fill_bs1[u4_is_b][u4_is_non16x16](\n                        ps_cur_mv_pred, ps_top_mv_pred, apv_map_ref_idx_to_poc,\n                        pu4_bs_table, ps_left_mv_pred, ps_left_ngbr,\n                        ps_cur_mb_info->ps_top_mb->u4_pic_addrress,\n                        (4 >> u4_cur_mb_fld));\n    }\n\n    {\n        void ** pu4_map_ref_idx_to_poc_l1 = apv_map_ref_idx_to_poc +\n        POC_LIST_L0_TO_L1_DIFF;\n\n        {\n            /* Store Parameter for Top MvPred refernce frame Address */\n            void ** ppv_top_mv_pred_addr = ps_cur_mb_info->ps_curmb->u4_pic_addrress;\n            void ** ppv_left_mv_pred_addr =\n                            ps_dec->ps_left_mvpred_addr[!u1_pingpong][u4_bot_mb].u4_add;\n            WORD8 * p1_refTop0 = (ps_cur_mv_pred + 12)->i1_ref_frame;\n            WORD8 * p1_refTop1 = (ps_cur_mv_pred + 14)->i1_ref_frame;\n            WORD8 * p1_refLeft0 = (ps_cur_mv_pred + 3)->i1_ref_frame;\n            ppv_top_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refTop0[0]];\n            ppv_top_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refTop0[1]];\n            ppv_left_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_top_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_left_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n            ppv_top_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n            ppv_left_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refLeft0[0]];\n            ppv_left_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refLeft0[1]];\n        }\n        if(u4_bot_mb)\n        {\n            /* store The Left Mb Type*/\n            ps_dec->deblk_left_mb[0].u1_mb_type =\n                            (ps_cur_mb_params - 1)->u1_mb_type;\n            ps_dec->deblk_left_mb[1].u1_mb_type = ps_cur_mb_params->u1_mb_type;\n\n        }\n        ps_deblk_top_mb[u4_bot_mb].u1_mb_type = u1_cur_mb_type;\n    }\n    /* For transform 8x8 disable deblocking of the intrernal edges of a 8x8 block */\n    if(ps_cur_mb_info->u1_tran_form8x8)\n    {\n        pu4_bs_table[1] = 0;\n        pu4_bs_table[3] = 0;\n        pu4_bs_table[5] = 0;\n        pu4_bs_table[7] = 0;\n    }\n\n}\n\n\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_fill_bs_for_mb \\endif\n *\n * \\brief\n *    Determines the boundary strength (Bs), for the complete MB. Bs is\n *    determined for each block boundary between two neighbouring 4x4\n *    luma blocks, then packed in a UWORD32, first Bs placed in MSB and\n *    so on.  Such packed Bs values for all 8 edges are kept in an array.\n *\n * \\return\n *    Returns the packed boundary strength(Bs)  MSB -> LSB Bs0|Bs1|Bs2|Bs3\n *\n **************************************************************************\n */\n\nvoid ih264d_fill_bs_for_mb(deblk_mb_t * ps_cur_mb_params,\n                           deblk_mb_t * ps_top_mb_params,\n                           deblk_mb_t * ps_left_mb_params,\n                           mv_pred_t *ps_cur_mv_pred,\n                           mv_pred_t *ps_top_mv_pred,\n                           UWORD8 *puc_cur_nnz,\n                           UWORD8 *puc_top_nnz,\n                           void **ppv_map_ref_idx_to_poc,\n                           UWORD32 ui_mbAff,\n                           UWORD32 ui_bs_table[], /* pointer to the BsTable array */\n                           mv_pred_t *ps_leftmost_mv_pred,\n                           neighbouradd_t *ps_left_addr,\n                           neighbouradd_t *ps_top_add)\n{\n    UWORD32 u4_bs_horz = 0;\n    UWORD8 edge, u1_top_intra = 0, u1_left_intra = 0;\n    mv_pred_t *ps_left_mv_pred;\n    WORD16 i2_cur_mv0, i2_cur_mv1, i16_curMv2, i16_curMv3;\n    WORD16 i2_left_mv0, i2_left_mv1, i2_left_mv2, i2_left_mv3;\n    WORD16 i2_top_mv0, i2_top_mv1, i16_topMv2, i16_topMv3;\n    WORD8 i1_cur_ref0, i1_cur_ref1, i1_left_ref0, i1_left_ref1, i1_top_ref0, i1_top_ref1;\n    UWORD8 uc_cur_nnz, uc_left_nnz, uc_top_nnz, u1_mb_type, uc_Bslice;\n    void **ppv_map_ref_idx_to_poc_l0, **ppv_map_ref_idx_to_poc_l1;\n    UWORD8 uc_temp;\n    UWORD8 uc_cur_mb_fld, uc_top_mb_fld;\n    UWORD32 c_mv_limit;\n\n    u1_mb_type = ps_cur_mb_params->u1_mb_type;\n    uc_Bslice = u1_mb_type & D_B_SLICE;\n    ppv_map_ref_idx_to_poc_l0 = ppv_map_ref_idx_to_poc;\n    ppv_map_ref_idx_to_poc_l1 = ppv_map_ref_idx_to_poc + POC_LIST_L0_TO_L1_DIFF;\n\n    ps_top_mb_params = ps_top_mb_params ? ps_top_mb_params : ps_cur_mb_params;\n    u1_top_intra = ps_top_mb_params->u1_mb_type & D_INTRA_MB;\n    u1_left_intra = ps_left_mb_params->u1_mb_type & D_INTRA_MB;\n\n    ui_bs_table[4] = 0x04040404; //Default for INTRA MB Boundary edges.\n    uc_cur_mb_fld = (ps_cur_mb_params->u1_mb_type & D_FLD_MB) >> 7;\n    uc_top_mb_fld = (ps_top_mb_params->u1_mb_type & D_FLD_MB) >> 7;\n\n    c_mv_limit = 4 >> uc_cur_mb_fld;\n    if((0 == uc_cur_mb_fld) && (0 == uc_top_mb_fld))\n    {\n        ui_bs_table[0] = 0x04040404;\n    }\n    else\n    {\n        ui_bs_table[0] = 0x03030303;\n    }\n\n    for(edge = 0; edge < 4;\n                    edge++, ps_top_mv_pred = ps_cur_mv_pred - 4, puc_top_nnz =\n                                    puc_cur_nnz - 4)\n    {\n        //Each iteration of this loop fills the four BS values of one HORIZ edge and\n        //one BS value for each of the four VERT edges.\n        WORD8 i = 0;\n        UWORD8 uc_bs_horiz, uc_bs_vert;\n        UWORD32 ui_cnd;\n        void *ui_ref_pic_addr[4];\n        UWORD8 uc_mixed_mode_edge;\n\n        uc_mixed_mode_edge = 0;\n\n        uc_temp = (ui_mbAff << 4) + 13;\n\n        uc_cur_nnz = *(puc_cur_nnz - uc_temp);\n        ps_left_mv_pred = ps_leftmost_mv_pred + (edge << 2);\n\n        for(i = 0; i < 4; i++, ps_top_mv_pred++, ps_cur_mv_pred++)\n        {\n            //Each iteration of this inner loop computes a HORIZ\n            //and a VERT BS value for a 4x4 block\n\n            uc_left_nnz = uc_cur_nnz;\n            uc_cur_nnz = *puc_cur_nnz++;\n            uc_top_nnz = *puc_top_nnz++;\n\n            //VERT edge is assigned BS values first\n            ui_cnd = !(uc_left_nnz || uc_cur_nnz);\n            uc_bs_vert = 2;\n\n            if(ui_cnd)\n            {\n                i2_left_mv0 = ps_left_mv_pred->i2_mv[0];\n                i2_left_mv1 = ps_left_mv_pred->i2_mv[1];\n                i2_left_mv2 = ps_left_mv_pred->i2_mv[2];\n                i2_left_mv3 = ps_left_mv_pred->i2_mv[3];\n\n                i2_cur_mv0 = ps_cur_mv_pred->i2_mv[0];\n                i2_cur_mv1 = ps_cur_mv_pred->i2_mv[1];\n                i16_curMv2 = ps_cur_mv_pred->i2_mv[2];\n                i16_curMv3 = ps_cur_mv_pred->i2_mv[3];\n                i1_cur_ref0 = ps_cur_mv_pred->i1_ref_frame[0];\n                i1_cur_ref1 = ps_cur_mv_pred->i1_ref_frame[1];\n                ui_ref_pic_addr[2] = ppv_map_ref_idx_to_poc_l0[i1_cur_ref0];\n                ui_ref_pic_addr[3] = ppv_map_ref_idx_to_poc_l1[i1_cur_ref1];\n\n                if(i)\n                {\n                    i1_left_ref0 = ps_left_mv_pred->i1_ref_frame[0];\n                    i1_left_ref1 = ps_left_mv_pred->i1_ref_frame[1];\n                    ui_ref_pic_addr[0] = ppv_map_ref_idx_to_poc_l0[i1_left_ref0];\n                    ui_ref_pic_addr[1] = ppv_map_ref_idx_to_poc_l1[i1_left_ref1];\n                }\n                else\n                {\n                    ui_ref_pic_addr[0] = ps_left_addr->u4_add[edge & 2];\n                    ui_ref_pic_addr[1] = ps_left_addr->u4_add[1 + (edge & 2)];\n                }\n                if(!uc_Bslice)\n                {\n                    uc_bs_vert =\n                                    (ui_ref_pic_addr[0] != ui_ref_pic_addr[2])\n                                                    | (ABS((i2_left_mv0\n                                                                    - i2_cur_mv0))\n                                                                    >= 4)\n                                                    | (ABS((i2_left_mv1\n                                                                    - i2_cur_mv1))\n                                                                    >= (UWORD8)c_mv_limit);\n                }\n                else\n                {\n                    UWORD8 uc_bs_temp1, uc_bs_temp2;\n\n                    uc_bs_vert = 1;\n\n                    uc_bs_temp1 =\n                                    ((ABS((i2_left_mv0 - i2_cur_mv0))\n                                                    >= 4)\n                                                    | (ABS((i2_left_mv1\n                                                                    - i2_cur_mv1))\n                                                                    >= (UWORD8)c_mv_limit)\n                                                    | (ABS((i2_left_mv2\n                                                                    - i16_curMv2))\n                                                                    >= 4)\n                                                    | (ABS((i2_left_mv3\n                                                                    - i16_curMv3))\n                                                                    >= (UWORD8)c_mv_limit));\n\n                    uc_bs_temp2 =\n                                    ((ABS((i2_left_mv0 - i16_curMv2))\n                                                    >= 4)\n                                                    | (ABS((i2_left_mv1\n                                                                    - i16_curMv3))\n                                                                    >= (UWORD8)c_mv_limit)\n                                                    | (ABS((i2_left_mv2\n                                                                    - i2_cur_mv0))\n                                                                    >= 4)\n                                                    | (ABS((i2_left_mv3\n                                                                    - i2_cur_mv1))\n                                                                    >= (UWORD8)c_mv_limit));\n\n                    uc_bs_vert =\n                                    (((ui_ref_pic_addr[0] != ui_ref_pic_addr[2])\n                                                    || (ui_ref_pic_addr[1]\n                                                                    != ui_ref_pic_addr[3]))\n                                                    || (uc_bs_temp1))\n                                                    && (((ui_ref_pic_addr[0]\n                                                                    != ui_ref_pic_addr[3])\n                                                                    || (ui_ref_pic_addr[1]\n                                                                                    != ui_ref_pic_addr[2]))\n                                                                    || (uc_bs_temp2));\n\n                }\n            }\n            //Fill the VERT BS, only if valid i.e.,\n            //if it is a non-edge OR it is an edge, which is not yet filled\n            uc_bs_vert = (!i && u1_left_intra) ? 4 : uc_bs_vert;\n            ui_bs_table[i + 4] = (ui_bs_table[i + 4] << 8) | uc_bs_vert;\n\n            //HORIZ edge is assigned BS values next\n            ui_cnd = !(uc_top_nnz || uc_cur_nnz);\n            uc_bs_horiz = 2;\n\n            if(ui_cnd)\n            {\n                uc_mixed_mode_edge =\n                                (0 == edge) ? (uc_top_mb_fld != uc_cur_mb_fld) : 0;\n                ui_cnd = 1 - uc_mixed_mode_edge;\n                uc_bs_horiz = uc_mixed_mode_edge;\n            }\n\n            if(ui_cnd)\n            {\n                i2_cur_mv0 = ps_cur_mv_pred->i2_mv[0];\n                i2_cur_mv1 = ps_cur_mv_pred->i2_mv[1];\n                i16_curMv2 = ps_cur_mv_pred->i2_mv[2];\n                i16_curMv3 = ps_cur_mv_pred->i2_mv[3];\n                i1_cur_ref0 = ps_cur_mv_pred->i1_ref_frame[0];\n                i1_cur_ref1 = ps_cur_mv_pred->i1_ref_frame[1];\n\n                i2_top_mv0 = ps_top_mv_pred->i2_mv[0];\n                i2_top_mv1 = ps_top_mv_pred->i2_mv[1];\n                i16_topMv2 = ps_top_mv_pred->i2_mv[2];\n                i16_topMv3 = ps_top_mv_pred->i2_mv[3];\n                ui_ref_pic_addr[2] = ppv_map_ref_idx_to_poc_l0[i1_cur_ref0];\n                ui_ref_pic_addr[3] = ppv_map_ref_idx_to_poc_l1[i1_cur_ref1];\n                if(edge)\n                {\n                    i1_top_ref0 = ps_top_mv_pred->i1_ref_frame[0];\n                    i1_top_ref1 = ps_top_mv_pred->i1_ref_frame[1];\n                    ui_ref_pic_addr[0] = ppv_map_ref_idx_to_poc_l0[i1_top_ref0];\n                    ui_ref_pic_addr[1] = ppv_map_ref_idx_to_poc_l1[i1_top_ref1];\n                }\n                else\n                {\n                    ui_ref_pic_addr[0] = ps_top_add->u4_add[i & 2];\n                    ui_ref_pic_addr[1] = ps_top_add->u4_add[1 + (i & 2)];\n                }\n                if(!uc_Bslice)\n                {\n                    uc_bs_horiz =\n                                    (ui_ref_pic_addr[0] != ui_ref_pic_addr[2])\n                                                    | (ABS((i2_top_mv0\n                                                                    - i2_cur_mv0))\n                                                                    >= 4)\n                                                    | (ABS((i2_top_mv1\n                                                                    - i2_cur_mv1))\n                                                                    >= (UWORD8)c_mv_limit);\n                }\n                else\n                {\n                    UWORD8 uc_bs_temp1, uc_bs_temp2;\n\n                    uc_bs_horiz = 1;\n\n                    uc_bs_temp1 =\n                                    ((ABS((i2_top_mv0 - i2_cur_mv0))\n                                                    >= 4)\n                                                    | (ABS((i2_top_mv1\n                                                                    - i2_cur_mv1))\n                                                                    >= (UWORD8)c_mv_limit)\n                                                    | (ABS((i16_topMv2\n                                                                    - i16_curMv2))\n                                                                    >= 4)\n                                                    | (ABS((i16_topMv3\n                                                                    - i16_curMv3))\n                                                                    >= (UWORD8)c_mv_limit));\n\n                    uc_bs_temp2 =\n                                    ((ABS((i2_top_mv0 - i16_curMv2))\n                                                    >= 4)\n                                                    | (ABS((i2_top_mv1\n                                                                    - i16_curMv3))\n                                                                    >= (UWORD8)c_mv_limit)\n                                                    | (ABS((i16_topMv2\n                                                                    - i2_cur_mv0))\n                                                                    >= 4)\n                                                    | (ABS((i16_topMv3\n                                                                    - i2_cur_mv1))\n                                                                    >= (UWORD8)c_mv_limit));\n\n                    uc_bs_horiz =\n                                    (((ui_ref_pic_addr[0] != ui_ref_pic_addr[2])\n                                                    || (ui_ref_pic_addr[1]\n                                                                    != ui_ref_pic_addr[3]))\n                                                    || (uc_bs_temp1))\n                                                    && (((ui_ref_pic_addr[0]\n                                                                    != ui_ref_pic_addr[3])\n                                                                    || (ui_ref_pic_addr[1]\n                                                                                    != ui_ref_pic_addr[2]))\n                                                                    || (uc_bs_temp2));\n\n                }\n            }\n            ps_left_mv_pred = ps_cur_mv_pred;\n            u4_bs_horz = (u4_bs_horz << 8) + uc_bs_horiz;\n        }\n        //Fill the HORIZ BS, only if valid i.e.,\n        //if it is a non-edge OR it is an edge, which is not yet filled\n        if(edge || (!edge && !u1_top_intra))\n            ui_bs_table[edge] = u4_bs_horz;\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_fill_bs_for_extra_left_edge \\endif\n *\n * \\brief\n *    Fills the boundary strength (Bs), for the top extra edge. ock\n *\n * \\return\n *    Returns the packed boundary strength(Bs)  MSB -> LSB Bs0|Bs1|Bs2|Bs3\n *\n **************************************************************************\n */\nvoid ih264d_fill_bs_for_extra_left_edge(deblk_mb_t *ps_cur_deblk_mb,\n                                        deblk_mb_t *ps_leftDeblkMb,\n                                        UWORD8* puc_cur_nnz,\n                                        UWORD8 uc_botMb)\n{\n    /* Set the Flag in uc_deblocking_mode variable of current MB*/\n    /* for mixed mode edge*/\n    ps_cur_deblk_mb->u1_single_call = 0;\n\n    if(ps_cur_deblk_mb->u1_mb_type & D_INTRA_MB)\n    {\n        ps_cur_deblk_mb->u4_bs_table[4] = 0x04040404;\n        ps_cur_deblk_mb->u4_bs_table[9] = 0x04040404;\n    }\n    else if((ps_leftDeblkMb->u1_mb_type & D_INTRA_MB)\n                    && ((ps_leftDeblkMb + 1)->u1_mb_type & D_INTRA_MB))\n    {\n        ps_cur_deblk_mb->u4_bs_table[4] = 0x04040404;\n        ps_cur_deblk_mb->u4_bs_table[9] = 0x04040404;\n    }\n    else\n    {\n        /* Get strengths of left MB edge */\n        UWORD32 u4_bs;\n        UWORD8 uc_Bs;\n        WORD32 i;\n        UWORD32 ui_curMbFld;\n        UWORD8 *puc_left_nnz;\n        UWORD32 ui_bs_left_edge[2];\n\n        ui_curMbFld = (ps_cur_deblk_mb->u1_mb_type & D_FLD_MB) >> 7;\n\n        puc_left_nnz = puc_cur_nnz - 29;\n        if((ui_curMbFld == 0) && uc_botMb)\n        {\n            puc_left_nnz -= 8;\n        }\n        else if(ui_curMbFld && uc_botMb)\n        {\n            puc_left_nnz -= 16;\n        }\n\n        if(ui_curMbFld)\n        {\n            if(ps_leftDeblkMb->u1_mb_type & D_INTRA_MB)\n            {\n                ui_bs_left_edge[0] = 0x04040404;\n                puc_left_nnz += 16;\n                puc_cur_nnz += 8;\n            }\n            else\n            {\n                u4_bs = 0;\n                for(i = 4; i > 0; i--)\n                {\n                    uc_Bs = ((*puc_cur_nnz || *puc_left_nnz)) ? 2 : 1;\n                    u4_bs = (u4_bs << 8) | uc_Bs;\n                    puc_left_nnz += 4;\n                    if(i & 0x01)\n                        puc_cur_nnz += 4;\n                }\n                ui_bs_left_edge[0] = u4_bs;\n            }\n\n            if((ps_leftDeblkMb + 1)->u1_mb_type & D_INTRA_MB)\n            {\n                ui_bs_left_edge[1] = 0x04040404;\n            }\n            else\n            {\n                u4_bs = 0;\n                for(i = 4; i > 0; i--)\n                {\n                    uc_Bs = ((*puc_cur_nnz || *puc_left_nnz)) ? 2 : 1;\n                    u4_bs = (u4_bs << 8) | uc_Bs;\n                    puc_left_nnz += 4;\n                    if(i & 0x01)\n                        puc_cur_nnz += 4;\n                }\n                ui_bs_left_edge[1] = u4_bs;\n            }\n        }\n        else\n        {\n            UWORD8 *puc_curNnzB, *puc_leftNnzB;\n            puc_curNnzB = puc_cur_nnz;\n            puc_leftNnzB = puc_left_nnz + 16;\n            if(ps_leftDeblkMb->u1_mb_type & D_INTRA_MB)\n            {\n                ui_bs_left_edge[0] = 0x04040404;\n            }\n            else\n            {\n                u4_bs = 0;\n                for(i = 4; i > 0; i--, puc_cur_nnz += 4)\n                {\n                    uc_Bs = ((*puc_cur_nnz || *puc_left_nnz)) ? 2 : 1;\n                    u4_bs = (u4_bs << 8) | uc_Bs;\n                    if(i & 0x01)\n                        puc_left_nnz += 4;\n                }\n                ui_bs_left_edge[0] = u4_bs;\n            }\n\n            if((ps_leftDeblkMb + 1)->u1_mb_type & D_INTRA_MB)\n            {\n                ui_bs_left_edge[1] = 0x04040404;\n            }\n            else\n            {\n                u4_bs = 0;\n                for(i = 4; i > 0; i--, puc_curNnzB += 4)\n                {\n                    uc_Bs = ((*puc_curNnzB || *puc_leftNnzB)) ? 2 : 1;\n                    u4_bs = (u4_bs << 8) | uc_Bs;\n                    if(i & 0x01)\n                        puc_leftNnzB += 4;\n                }\n                ui_bs_left_edge[1] = u4_bs;\n            }\n        }\n        /* Copy The Values in Cur Deblk Mb Parameters */\n        ps_cur_deblk_mb->u4_bs_table[4] = ui_bs_left_edge[0];\n        ps_cur_deblk_mb->u4_bs_table[9] = ui_bs_left_edge[1];\n    }\n\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_fill_bs_for_extra_top_edge \\endif\n *\n * \\brief\n *    Fills the boundary strength (Bs), for the top extra edge. ock\n *\n * \\return\n *    Returns the packed boundary strength(Bs)  MSB -> LSB Bs0|Bs1|Bs2|Bs3\n *\n **************************************************************************\n */\nvoid ih264d_fill_bs_for_extra_top_edge(deblk_mb_t *ps_cur_mb_params,\n                                       UWORD8 u1_Edge0_mb_typ,\n                                       UWORD8 u1_Edge1_mb_typ,\n                                       UWORD8 *pu1_curNnz,\n                                       UWORD8 *pu1_topNnz)\n{\n    UWORD32 u4_bs;\n    UWORD8 uc_Bs;\n    WORD32 i;\n    UWORD8 *pu1_cur_nnz_tmp;\n    UWORD8 *pu1_top_nnz_tmp;\n    UWORD8 u1_top_edge;\n    UWORD8 u1_top_mb_type;\n    for(u1_top_edge = 0; u1_top_edge < 2; u1_top_edge++)\n    {\n        u1_top_mb_type = u1_top_edge ? u1_Edge1_mb_typ : u1_Edge0_mb_typ;\n        pu1_cur_nnz_tmp = pu1_curNnz;\n        pu1_top_nnz_tmp = pu1_topNnz + (u1_top_edge << 2);\n\n        if((ps_cur_mb_params->u1_mb_type & D_INTRA_MB)\n                        + (u1_top_mb_type & D_INTRA_MB))\n        {\n            u4_bs = 0x03030303;\n        }\n        else\n        {\n            u4_bs = 0;\n            for(i = 4; i > 0; i--, pu1_cur_nnz_tmp += 1, pu1_top_nnz_tmp += 1)\n            {\n                uc_Bs = ((*pu1_cur_nnz_tmp || *pu1_top_nnz_tmp)) ? 2 : 1;\n                u4_bs = (u4_bs << 8) | uc_Bs;\n            }\n        }\n        if(u1_top_edge)\n            ps_cur_mb_params->u4_bs_table[0] = u4_bs;\n        else\n            ps_cur_mb_params->u4_bs_table[8] = u4_bs;\n    }\n}\n\n\nvoid ih264d_fill_bs_mbedge_4(dec_struct_t * ps_dec,\n                             dec_mb_info_t * ps_cur_mb_info,\n                             const UWORD16 u2_mbxn_mb)\n{\n\n    /* deblk_mb_t Params */\n    deblk_mb_t *ps_cur_mb_params; /*< Parameters of current MacroBlock */\n    deblkmb_neighbour_t *ps_deblk_top_mb;\n    UWORD32 * pu4_bs_table;\n    UWORD8 u1_cur_mb_type;\n\n    /* Neighbour availability */\n    /* Initialization */\n    const UWORD32 u2_mbx = ps_cur_mb_info->u2_mbx;\n    const UWORD32 u2_mby = ps_cur_mb_info->u2_mby;\n    const UWORD32 u1_pingpong = u2_mbx & 0x01;\n    ps_deblk_top_mb = ps_dec->ps_deblk_top_mb + u2_mbx;\n\n\n    /* Pointer assignment for Current DeblkMB, Current Mv Pred  */\n    ps_cur_mb_params = ps_dec->ps_deblk_mbn + u2_mbxn_mb;\n\n    u1_cur_mb_type = ps_cur_mb_params->u1_mb_type;\n\n    ps_deblk_top_mb->u1_mb_type = u1_cur_mb_type;\n\n    {\n        UWORD8 mb_qp_temp;\n\n        ps_cur_mb_params->u1_topmb_qp = ps_deblk_top_mb->u1_mb_qp;\n        ps_deblk_top_mb->u1_mb_qp = ps_cur_mb_params->u1_mb_qp;\n\n        ps_cur_mb_params->u1_left_mb_qp = ps_dec->deblk_left_mb[1].u1_mb_qp;\n        ps_dec->deblk_left_mb[1].u1_mb_qp = ps_cur_mb_params->u1_mb_qp;\n\n    }\n\n    ps_cur_mb_params->u1_single_call = 1;\n\n    ps_dec->deblk_left_mb[1].u1_mb_type = ps_cur_mb_params->u1_mb_type;\n    /* if no deblocking required for current Mb then continue */\n    /* Check next Mbs   in Mb group                           */\n    if(ps_cur_mb_params->u1_deblocking_mode & MB_DISABLE_FILTERING)\n    {\n        /* Storing the leftMbtype for next Mb */\n        return;\n    }\n\n    /* Compute BS function */\n    pu4_bs_table = ps_cur_mb_params->u4_bs_table;\n\n    pu4_bs_table[4] = 0x04040404;\n    pu4_bs_table[0] = 0x04040404;\n    pu4_bs_table[1] = 0;\n    pu4_bs_table[2] = 0;\n    pu4_bs_table[3] = 0;\n    pu4_bs_table[5] = 0;\n    pu4_bs_table[6] = 0;\n    pu4_bs_table[7] = 0;\n\n}\n\nvoid ih264d_fill_bs_mbedge_2(dec_struct_t * ps_dec,\n                             dec_mb_info_t * ps_cur_mb_info,\n                             const UWORD16 u2_mbxn_mb)\n{\n\n    /* deblk_mb_t Params */\n    deblk_mb_t *ps_cur_mb_params; /*< Parameters of current MacroBlock */\n    deblkmb_neighbour_t *ps_deblk_top_mb;\n    UWORD32 * pu4_bs_table;\n    UWORD8 u1_cur_mb_type;\n\n    /* Neighbour availability */\n    /* Initialization */\n    const UWORD32 u2_mbx = ps_cur_mb_info->u2_mbx;\n    const UWORD32 u2_mby = ps_cur_mb_info->u2_mby;\n    const UWORD32 u1_pingpong = u2_mbx & 0x01;\n    ps_deblk_top_mb = ps_dec->ps_deblk_top_mb + u2_mbx;\n\n\n    /* Pointer assignment for Current DeblkMB, Current Mv Pred  */\n    ps_cur_mb_params = ps_dec->ps_deblk_mbn + u2_mbxn_mb;\n\n    u1_cur_mb_type = ps_cur_mb_params->u1_mb_type;\n\n    ps_deblk_top_mb->u1_mb_type = u1_cur_mb_type;\n\n    {\n        UWORD8 mb_qp_temp;\n\n        ps_cur_mb_params->u1_topmb_qp = ps_deblk_top_mb->u1_mb_qp;\n        ps_deblk_top_mb->u1_mb_qp = ps_cur_mb_params->u1_mb_qp;\n\n        ps_cur_mb_params->u1_left_mb_qp = ps_dec->deblk_left_mb[1].u1_mb_qp;\n        ps_dec->deblk_left_mb[1].u1_mb_qp = ps_cur_mb_params->u1_mb_qp;\n\n    }\n\n    ps_cur_mb_params->u1_single_call = 1;\n\n    ps_dec->deblk_left_mb[1].u1_mb_type = ps_cur_mb_params->u1_mb_type;\n    /* if no deblocking required for current Mb then continue */\n    /* Check next Mbs   in Mb group                           */\n    if(ps_cur_mb_params->u1_deblocking_mode & MB_DISABLE_FILTERING)\n    {\n        /* Storing the leftMbtype for next Mb */\n        return;\n    }\n\n    /* Compute BS function */\n    pu4_bs_table = ps_cur_mb_params->u4_bs_table;\n\n    {\n        UWORD32 top_mb_csbp, left_mb_csbp, cur_mb_csbp;\n        UWORD32 top_edge, left_edge;\n\n        top_mb_csbp = ps_cur_mb_info->ps_top_mb->u2_luma_csbp;\n        left_mb_csbp = ps_cur_mb_info->ps_left_mb->u2_luma_csbp;\n        cur_mb_csbp = ps_cur_mb_info->ps_curmb->u2_luma_csbp;\n\n        top_mb_csbp = top_mb_csbp >> 12;\n        top_edge = top_mb_csbp | (cur_mb_csbp & 0xf);\n\n        if(top_edge)\n            pu4_bs_table[0] = 0x02020202;\n        else\n            pu4_bs_table[0] = 0;\n\n        cur_mb_csbp = cur_mb_csbp & CSBP_LEFT_BLOCK_MASK;\n        left_mb_csbp = left_mb_csbp & CSBP_RIGHT_BLOCK_MASK;\n\n        left_edge = cur_mb_csbp | left_mb_csbp;\n\n        if(left_edge)\n            pu4_bs_table[4] = 0x02020202;\n        else\n            pu4_bs_table[4] = 0;\n\n        pu4_bs_table[1] = 0;\n        pu4_bs_table[2] = 0;\n        pu4_bs_table[3] = 0;\n        pu4_bs_table[5] = 0;\n        pu4_bs_table[6] = 0;\n        pu4_bs_table[7] = 0;\n    }\n\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_deblocking.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n#include <string.h>\n\n#include \"ih264_typedefs.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_utils.h\"\n\n\n#include \"ih264d_defs.h\"\n#include \"ih264d_format_conv.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_tables.h\"\n\n/*!\n *************************************************************************\n * \\file ih264d_deblocking.c\n *\n * \\brief\n *    Decoder specific deblocking routines\n *\n * \\author AI\n *************************************************************************\n */\n\n/*!\n **************************************************************************\n * \\if Function name : HorizonPad \\endif\n *\n * \\brief\n *    Does the Horizontal padding on a whole pic.\n *\n * \\return\n *    None\n **************************************************************************\n */\n\n/*!\n **************************************************************************\n * \\if Function name : FilterBoundaryLeft \\endif\n *\n * \\brief\n *    Filters MacroBlock Left Boundary egdes.\n *\n * \\return\n *    None\n **************************************************************************\n */\nvoid ih264d_filter_boundary_left_nonmbaff(dec_struct_t *ps_dec,\n                                          tfr_ctxt_t * ps_tfr_cxt,\n                                          WORD8 i1_cb_qp_idx_ofst,\n                                          WORD8 i1_cr_qp_idx_ofst,\n                                          deblk_mb_t * ps_cur_mb,\n                                          WORD32 i4_strd_y,\n                                          WORD32 i4_strd_uv,\n                                          deblk_mb_t * ps_left_mb,\n                                          UWORD32 pu4_bs_tab[],\n                                          UWORD8 u1_cur_fld)\n{\n    UWORD8 *pu1_y, *pu1_u, *pu1_v;\n    WORD32 uc_tmp, qp_avg;\n    WORD32 alpha_u = 0, beta_u = 0, alpha_v = 0, beta_v = 0;\n    WORD32 alpha_y = 0, beta_y = 0;\n\n    WORD32 idx_b_u, idx_a_u, idx_b_v, idx_a_v;\n    WORD32 idx_b_y, idx_a_y;\n\n    UWORD32 u4_bs_val;\n\n    UWORD8 *pu1_cliptab_u, *pu1_cliptab_v, *pu1_cliptab_y;\n\n    UWORD8 u1_double_cl = !ps_cur_mb->u1_single_call;\n    WORD32 ofst_a = ps_cur_mb->i1_slice_alpha_c0_offset;\n    WORD32 ofst_b = ps_cur_mb->i1_slice_beta_offset;\n\n    PROFILE_DISABLE_DEBLK()\n\n    pu1_y = ps_tfr_cxt->pu1_mb_y;\n    pu1_u = ps_tfr_cxt->pu1_mb_u;\n    pu1_v = ps_tfr_cxt->pu1_mb_v;\n\n    /* LUMA values */\n    /* Deblock rounding change */\n    qp_avg =\n                    (UWORD8)((ps_cur_mb->u1_left_mb_qp + ps_cur_mb->u1_mb_qp + 1)\n                                    >> 1);\n\n    idx_a_y = qp_avg + ofst_a;\n    alpha_y = gau1_ih264d_alpha_table[12 + idx_a_y];\n    idx_b_y = qp_avg + ofst_b;\n    beta_y = gau1_ih264d_beta_table[12 + idx_b_y];\n\n    /* Chroma cb values */\n    {\n        WORD32 mb_qp1, mb_qp2;\n        mb_qp1 = (ps_cur_mb->u1_left_mb_qp + i1_cb_qp_idx_ofst);\n        mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cb_qp_idx_ofst);\n        qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                        + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n    }\n    idx_a_u = qp_avg + ofst_a;\n    alpha_u = gau1_ih264d_alpha_table[12 + idx_a_u];\n    idx_b_u = qp_avg + ofst_b;\n    beta_u = gau1_ih264d_beta_table[12 + idx_b_u];\n    /* Chroma cr values */\n    {\n        WORD32 mb_qp1, mb_qp2;\n        mb_qp1 = (ps_cur_mb->u1_left_mb_qp + i1_cr_qp_idx_ofst);\n        mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cr_qp_idx_ofst);\n        qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                        + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n    }\n    idx_a_v = qp_avg + ofst_a;\n    alpha_v = gau1_ih264d_alpha_table[12 + idx_a_v];\n    idx_b_v = qp_avg + ofst_b;\n    beta_v = gau1_ih264d_beta_table[12 + idx_b_v];\n\n    if(u1_double_cl == 0)\n    {\n        u4_bs_val = pu4_bs_tab[4];\n\n        if(0x04040404 == u4_bs_val)\n        {\n            ps_dec->pf_deblk_luma_vert_bs4(pu1_y, i4_strd_y, alpha_y, beta_y);\n            ps_dec->pf_deblk_chroma_vert_bs4(pu1_u, i4_strd_uv, alpha_u,\n                                             beta_u, alpha_v, beta_v);\n        }\n        else\n        {\n            if(u4_bs_val)\n            {\n\n                pu1_cliptab_y = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_y];\n                pu1_cliptab_u = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_u];\n                pu1_cliptab_v = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_v];\n                ps_dec->pf_deblk_luma_vert_bslt4(pu1_y, i4_strd_y, alpha_y,\n                                                 beta_y, u4_bs_val,\n                                                 pu1_cliptab_y);\n                ps_dec->pf_deblk_chroma_vert_bslt4(pu1_u, i4_strd_uv, alpha_u,\n                                                   beta_u, alpha_v, beta_v,\n                                                   u4_bs_val, pu1_cliptab_u,\n                                                   pu1_cliptab_v);\n\n            }\n        }\n\n    }\n    else\n    {\n\n        i4_strd_y <<= (!u1_cur_fld);\n        u4_bs_val = pu4_bs_tab[4];\n        i4_strd_uv <<= (!u1_cur_fld);\n\n        if(0x04040404 == u4_bs_val)\n        {\n\n            ps_dec->pf_deblk_luma_vert_bs4_mbaff(pu1_y, i4_strd_y, alpha_y,\n                                                 beta_y);\n            ps_dec->pf_deblk_chroma_vert_bs4_mbaff(pu1_u, i4_strd_uv, alpha_u,\n                                                   beta_u, alpha_v, beta_v);\n\n        }\n        else\n        {\n            if(u4_bs_val)\n            {\n\n                pu1_cliptab_y = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_y];\n                pu1_cliptab_u = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_u];\n                pu1_cliptab_v = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_v];\n\n                ps_dec->pf_deblk_luma_vert_bslt4_mbaff(pu1_y, i4_strd_y,\n                                                       alpha_y, beta_y,\n                                                       u4_bs_val,\n                                                       pu1_cliptab_y);\n                ps_dec->pf_deblk_chroma_vert_bslt4_mbaff(pu1_u, i4_strd_uv,\n                                                         alpha_u, beta_u,\n                                                         alpha_v, beta_v,\n                                                         u4_bs_val,\n                                                         pu1_cliptab_u,\n                                                         pu1_cliptab_v);\n            }\n        }\n\n        {\n\n            UWORD16 u2_shift = (i4_strd_y >> 1) << (u1_cur_fld ? 4 : 0);\n            pu1_y += u2_shift;\n            u2_shift = (i4_strd_uv >> 1) << (u1_cur_fld ? 3 : 0);\n            pu1_u += u2_shift;\n            pu1_v += u2_shift;\n        }\n\n        qp_avg = (((ps_left_mb + 1)->u1_mb_qp + ps_cur_mb->u1_mb_qp + 1) >> 1);\n\n        idx_a_y = qp_avg + ofst_a;\n        alpha_y = gau1_ih264d_alpha_table[12 + idx_a_y];\n        idx_b_y = qp_avg + ofst_b;\n        beta_y = gau1_ih264d_beta_table[12 + idx_b_y];\n        u4_bs_val = pu4_bs_tab[9];\n\n        {\n            WORD32 mb_qp1, mb_qp2;\n            mb_qp1 = ((ps_left_mb + 1)->u1_mb_qp + i1_cb_qp_idx_ofst);\n            mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cb_qp_idx_ofst);\n            qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                            + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n        }\n        idx_a_u = qp_avg + ofst_a;\n        alpha_u = gau1_ih264d_alpha_table[12 + idx_a_u];\n        idx_b_u = qp_avg + ofst_b;\n        beta_u = gau1_ih264d_beta_table[12 + idx_b_u];\n        u4_bs_val = pu4_bs_tab[9];\n        {\n            WORD32 mb_qp1, mb_qp2;\n            mb_qp1 = ((ps_left_mb + 1)->u1_mb_qp + i1_cr_qp_idx_ofst);\n            mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cr_qp_idx_ofst);\n            qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                            + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n        }\n        idx_a_v = qp_avg + ofst_a;\n        alpha_v = gau1_ih264d_alpha_table[12 + idx_a_v];\n        idx_b_v = qp_avg + ofst_b;\n        beta_v = gau1_ih264d_beta_table[12 + idx_b_v];\n\n        if(0x04040404 == u4_bs_val)\n        {\n            ps_dec->pf_deblk_luma_vert_bs4_mbaff(pu1_y, i4_strd_y, alpha_y,\n                                                 beta_y);\n            ps_dec->pf_deblk_chroma_vert_bs4_mbaff(pu1_u, i4_strd_uv, alpha_u,\n                                                   beta_u, alpha_v, beta_v);\n\n        }\n        else\n        {\n            if(u4_bs_val)\n            {\n\n                pu1_cliptab_y = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_y];\n                pu1_cliptab_u = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_u];\n                pu1_cliptab_v = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_v];\n\n                ps_dec->pf_deblk_luma_vert_bslt4_mbaff(pu1_y, i4_strd_y,\n                                                       alpha_y, beta_y,\n                                                       u4_bs_val,\n                                                       pu1_cliptab_y);\n                ps_dec->pf_deblk_chroma_vert_bslt4_mbaff(pu1_u, i4_strd_uv,\n                                                         alpha_u, beta_u,\n                                                         alpha_v, beta_v,\n                                                         u4_bs_val,\n                                                         pu1_cliptab_u,\n                                                         pu1_cliptab_v);\n\n            }\n        }\n    }\n\n}\n\n/*!\n **************************************************************************\n * \\if Function name : FilterBoundaryTop \\endif\n *\n * \\brief\n *    Filters MacroBlock Top Boundary egdes.\n *\n * \\return\n *    None\n **************************************************************************\n */\n\nvoid ih264d_filter_boundary_top_nonmbaff(dec_struct_t *ps_dec,\n                                         tfr_ctxt_t * ps_tfr_cxt,\n                                         WORD8 i1_cb_qp_idx_ofst,\n                                         WORD8 i1_cr_qp_idx_ofst,\n                                         deblk_mb_t * ps_cur_mb,\n                                         WORD32 i4_strd_y,\n                                         WORD32 i4_strd_uv,\n                                         deblk_mb_t * ps_top_mb,\n                                         UWORD32 u4_bs)\n{\n    UWORD8 *pu1_y, *pu1_u;\n    WORD32 alpha_u = 0, beta_u = 0, alpha_v = 0, beta_v = 0;\n    WORD32 alpha_y = 0, beta_y = 0;\n    WORD32 qp_avg;\n    WORD32 idx_b_u, idx_a_u, idx_b_v, idx_a_v;\n    WORD32 idx_b_y, idx_a_y;\n    UWORD16 uc_tmp;\n\n    UWORD8 *pu1_cliptab_u, *pu1_cliptab_v, *pu1_cliptab_y;\n    WORD32 ofst_a = ps_cur_mb->i1_slice_alpha_c0_offset;\n    WORD32 ofst_b = ps_cur_mb->i1_slice_beta_offset;\n\n    UNUSED(ps_top_mb);\n    /* LUMA values */\n    /* Deblock rounding change */\n    uc_tmp = ((ps_cur_mb->u1_topmb_qp + ps_cur_mb->u1_mb_qp + 1) >> 1);\n    qp_avg = (UWORD8)uc_tmp;\n    idx_a_y = qp_avg + ofst_a;\n    alpha_y = gau1_ih264d_alpha_table[12 + idx_a_y];\n    idx_b_y = qp_avg + ofst_b;\n    beta_y = gau1_ih264d_beta_table[12 + idx_b_y];\n    pu1_y = ps_tfr_cxt->pu1_mb_y;\n\n    /* CHROMA cb values */\n    {\n        WORD32 mb_qp1, mb_qp2;\n        mb_qp1 = (ps_cur_mb->u1_topmb_qp + i1_cb_qp_idx_ofst);\n        mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cb_qp_idx_ofst);\n        qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                        + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n    }\n\n    idx_a_u = qp_avg + ofst_a;\n    alpha_u = gau1_ih264d_alpha_table[12 + idx_a_u];\n    idx_b_u = qp_avg + ofst_b;\n    beta_u = gau1_ih264d_beta_table[12 + idx_b_u];\n    /* CHROMA cr values */\n    {\n        WORD32 mb_qp1, mb_qp2;\n        mb_qp1 = (ps_cur_mb->u1_topmb_qp + i1_cr_qp_idx_ofst);\n        mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cr_qp_idx_ofst);\n        qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                        + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n    }\n\n    idx_a_v = qp_avg + ofst_a;\n    alpha_v = gau1_ih264d_alpha_table[12 + idx_a_v];\n    idx_b_v = qp_avg + ofst_b;\n    beta_v = gau1_ih264d_beta_table[12 + idx_b_v];\n    pu1_u = ps_tfr_cxt->pu1_mb_u;\n\n    if(u4_bs == 0x04040404)\n    {\n        /* Code specific to the assembly module */\n\n        ps_dec->pf_deblk_luma_horz_bs4(pu1_y, i4_strd_y, alpha_y, beta_y);\n        ps_dec->pf_deblk_chroma_horz_bs4(pu1_u, i4_strd_uv, alpha_u, beta_u,\n                                         alpha_v, beta_v);\n    }\n    else\n    {\n        if(u4_bs)\n        {\n\n            pu1_cliptab_y = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_y];\n            pu1_cliptab_u =\n                            (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_u];\n            pu1_cliptab_v =\n                            (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_v];\n\n            ps_dec->pf_deblk_luma_horz_bslt4(pu1_y, i4_strd_y, alpha_y, beta_y,\n                                             u4_bs, pu1_cliptab_y);\n            ps_dec->pf_deblk_chroma_horz_bslt4(pu1_u, i4_strd_uv, alpha_u,\n                                               beta_u, alpha_v, beta_v,\n                                               u4_bs, pu1_cliptab_u,\n                                               pu1_cliptab_v);\n\n        }\n    }\n\n}\n\nvoid ih264d_deblock_mb_nonmbaff(dec_struct_t *ps_dec,\n                                tfr_ctxt_t * ps_tfr_cxt,\n                                WORD8 i1_cb_qp_idx_ofst,\n                                WORD8 i1_cr_qp_idx_ofst,\n                                WORD32 i4_strd_y,\n                                WORD32 i4_strd_uv )\n{\n    UWORD8 *pu1_y, *pu1_u;\n    UWORD32 u4_bs;\n\n    WORD32 alpha, beta, alpha_u, beta_u, alpha_v, beta_v;\n\n    UWORD8 *pu1_cliptab_u;\n    UWORD8 *pu1_cliptab_v;\n    UWORD8 *pu1_cliptab_y;\n\n    UWORD32 * pu4_bs_tab;\n    WORD32 idx_a_y, idx_a_u, idx_a_v;\n    UWORD32 u4_deb_mode, u4_mbs_next;\n    UWORD32 u4_image_wd_mb;\n    deblk_mb_t *ps_top_mb,*ps_left_mb,*ps_cur_mb;\n\n    PROFILE_DISABLE_DEBLK()\n    /* Return from here to switch off deblocking */\n\n    u4_image_wd_mb = ps_dec->u2_frm_wd_in_mbs;\n\n    ps_cur_mb = ps_dec->ps_cur_deblk_mb;\n    pu4_bs_tab = ps_cur_mb->u4_bs_table;\n    u4_deb_mode = ps_cur_mb->u1_deblocking_mode;\n     if(!(u4_deb_mode & MB_DISABLE_FILTERING))\n     {\n\n         if(ps_dec->u4_deblk_mb_x)\n         {\n             ps_left_mb = ps_cur_mb - 1;\n\n         }\n         else\n         {\n             ps_left_mb = NULL;\n\n         }\n         if(ps_dec->u4_deblk_mb_y != 0)\n         {\n             ps_top_mb = ps_cur_mb - (u4_image_wd_mb);\n         }\n         else\n         {\n             ps_top_mb = NULL;\n         }\n\n         if(u4_deb_mode & MB_DISABLE_LEFT_EDGE)\n             ps_left_mb = NULL;\n         if(u4_deb_mode & MB_DISABLE_TOP_EDGE)\n             ps_top_mb = NULL;\n\n        /*---------------------------------------------------------------------*/\n        /* Filter wrt Left edge                                                */\n        /* except                                                              */\n        /*      - Left Egde is Picture Boundary                                */\n        /*      - Left Egde is part of Slice Boundary and Deblocking           */\n        /*        parameters of slice disable Filtering of Slice Boundary Edges*/\n        /*---------------------------------------------------------------------*/\n        if(ps_left_mb)\n            ih264d_filter_boundary_left_nonmbaff(ps_dec, ps_tfr_cxt,\n                                                 i1_cb_qp_idx_ofst,\n                                                 i1_cr_qp_idx_ofst, ps_cur_mb,\n                                                 i4_strd_y, i4_strd_uv, ps_left_mb,\n                                                 pu4_bs_tab, 0);\n\n        /*--------------------------------------------------------------------*/\n        /* Filter wrt Other Vertical Edges                                    */\n        /*--------------------------------------------------------------------*/\n        {\n            WORD32 ofst_a, ofst_b, idx_b_y, idx_b_u,\n                            idx_b_v;\n            WORD32 qp_avg, qp_avg_u, qp_avg_v;\n            ofst_a = ps_cur_mb->i1_slice_alpha_c0_offset;\n            ofst_b = ps_cur_mb->i1_slice_beta_offset;\n\n            qp_avg = ps_cur_mb->u1_mb_qp;\n\n            idx_a_y = qp_avg + ofst_a;\n            alpha = gau1_ih264d_alpha_table[12 + idx_a_y];\n            idx_b_y = qp_avg + ofst_b;\n            beta = gau1_ih264d_beta_table[12 + idx_b_y];\n\n            /* CHROMA values */\n            /* CHROMA Cb values */\n            qp_avg_u = (qp_avg + i1_cb_qp_idx_ofst);\n            qp_avg_u = gau1_ih264d_qp_scale_cr[12 + qp_avg_u];\n            idx_a_u = qp_avg_u + ofst_a;\n            alpha_u = gau1_ih264d_alpha_table[12 + idx_a_u];\n            idx_b_u = qp_avg_u + ofst_b;\n            beta_u = gau1_ih264d_beta_table[12 + idx_b_u];\n            /* CHROMA Cr values */\n            qp_avg_v = (qp_avg + i1_cr_qp_idx_ofst);\n            qp_avg_v = gau1_ih264d_qp_scale_cr[12 + qp_avg_v];\n            idx_a_v = qp_avg_v + ofst_a;\n            alpha_v = gau1_ih264d_alpha_table[12 + idx_a_v];\n            idx_b_v = qp_avg_v + ofst_b;\n            beta_v = gau1_ih264d_beta_table[12 + idx_b_v];\n        }\n\n        pu1_cliptab_y = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_y]; //this for Luma\n        pu1_cliptab_u = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_u]; //this for chroma\n        pu1_cliptab_v = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_v]; //this for chroma\n\n        //edge=1\n\n\n        u4_bs = pu4_bs_tab[5];\n        pu1_y = ps_tfr_cxt->pu1_mb_y;\n        pu1_u = ps_tfr_cxt->pu1_mb_u;\n\n        if(u4_bs)\n        {\n\n            ps_dec->pf_deblk_luma_vert_bslt4(pu1_y + 4, i4_strd_y, alpha, beta,\n                                             u4_bs, pu1_cliptab_y);\n\n        }\n        //edge=2\n\n        u4_bs = pu4_bs_tab[6];\n        if(u4_bs)\n        {\n            ps_dec->pf_deblk_luma_vert_bslt4(pu1_y + 8, i4_strd_y, alpha, beta,\n                                             u4_bs, pu1_cliptab_y);\n            ps_dec->pf_deblk_chroma_vert_bslt4(pu1_u + 4 * YUV420SP_FACTOR,\n                                               i4_strd_uv, alpha_u, beta_u,\n                                               alpha_v, beta_v, u4_bs,\n                                               pu1_cliptab_u, pu1_cliptab_v);\n\n        }\n        //edge=3\n\n        u4_bs = pu4_bs_tab[7];\n        if(u4_bs)\n        {\n            ps_dec->pf_deblk_luma_vert_bslt4(pu1_y + 12, i4_strd_y, alpha, beta,\n                                             u4_bs, pu1_cliptab_y);\n\n        }\n\n        /*--------------------------------------------------------------------*/\n        /* Filter wrt Top edge                                                */\n        /* except                                                             */\n        /*      - Top Egde is Picture Boundary                                */\n        /*      - Top Egde is part of Slice Boundary and Deblocking           */\n        /*        parameters of slice disable Filtering of Slice Boundary Edges*/\n        /*--------------------------------------------------------------------*/\n        if(ps_top_mb)\n        {\n            /** if top MB and MB AFF and cur MB is frame and top is field then  */\n            /*  one extra top edge needs to be deblocked                        */\n\n            ih264d_filter_boundary_top_nonmbaff(ps_dec, ps_tfr_cxt,\n                                                i1_cb_qp_idx_ofst,\n                                                i1_cr_qp_idx_ofst, ps_cur_mb,\n                                                i4_strd_y, i4_strd_uv, ps_top_mb,\n                                                pu4_bs_tab[0]);\n\n        }\n\n        /*--------------------------------------------------------------------*/\n        /* Filter wrt Other Horizontal Edges                                  */\n        /*--------------------------------------------------------------------*/\n\n        //edge1\n        u4_bs = pu4_bs_tab[1];\n\n        if(u4_bs)\n        {\n            ps_dec->pf_deblk_luma_horz_bslt4(pu1_y + (i4_strd_y << 2), i4_strd_y,\n                                             alpha, beta, u4_bs, pu1_cliptab_y);\n\n        }\n        //edge2\n        u4_bs = pu4_bs_tab[2];\n\n        if(u4_bs)\n        {\n\n            ps_dec->pf_deblk_luma_horz_bslt4(pu1_y + (i4_strd_y << 3), i4_strd_y,\n                                             alpha, beta, u4_bs, pu1_cliptab_y);\n            ps_dec->pf_deblk_chroma_horz_bslt4(pu1_u + (i4_strd_uv << 2),\n                                               i4_strd_uv, alpha_u, beta_u,\n                                               alpha_v, beta_v, u4_bs,\n                                               pu1_cliptab_u, pu1_cliptab_v);\n\n        }\n        //edge3\n        u4_bs = pu4_bs_tab[3];\n        if(u4_bs)\n        {\n            ps_dec->pf_deblk_luma_horz_bslt4(\n                            (pu1_y + (i4_strd_y << 3) + (i4_strd_y << 2)),\n                            i4_strd_y, alpha, beta, u4_bs, pu1_cliptab_y);\n\n        }\n     }\n\n     ps_dec->u4_deblk_mb_x++;\n     ps_dec->ps_cur_deblk_mb++;\n     ps_dec->u4_cur_deblk_mb_num++;\n     u4_mbs_next = u4_image_wd_mb - ps_dec->u4_deblk_mb_x;\n\n     ps_tfr_cxt->pu1_mb_y += 16;\n     ps_tfr_cxt->pu1_mb_u += 8 * YUV420SP_FACTOR;\n     ps_tfr_cxt->pu1_mb_v += 8;\n\n     if(!u4_mbs_next)\n     {\n         ps_tfr_cxt->pu1_mb_y += ps_tfr_cxt->u4_y_inc;\n         ps_tfr_cxt->pu1_mb_u += ps_tfr_cxt->u4_uv_inc;\n         ps_tfr_cxt->pu1_mb_v += ps_tfr_cxt->u4_uv_inc;\n         ps_dec->u4_deblk_mb_y++;\n         ps_dec->u4_deblk_mb_x = 0;\n     }\n\n}\n\n/**************************************************************************\n *\n *  Function Name : ih264d_init_deblk_tfr_ctxt\n *\n *  Description   : This function is called once per deblockpicture call\n *                  This sets up the transfer address contexts\n *\n *  Revision History:\n *\n *         DD MM YYYY   Author(s)       Changes (Describe the changes made)\n *         14 06 2005   SWRN            Draft\n **************************************************************************/\nvoid ih264d_init_deblk_tfr_ctxt(dec_struct_t * ps_dec,\n                                pad_mgr_t *ps_pad_mgr,\n                                tfr_ctxt_t *ps_tfr_cxt,\n                                UWORD16 u2_image_wd_mb,\n                                UWORD8 u1_mbaff)\n{\n\n    UWORD32 i4_wd_y;\n    UWORD32 i4_wd_uv;\n    UWORD8 u1_field_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag; /*< Field u4_flag  */\n    UNUSED(u2_image_wd_mb);\n    ps_tfr_cxt->pu1_src_y = ps_dec->s_cur_pic.pu1_buf1 - 4;\n    ps_tfr_cxt->pu1_src_u = ps_dec->s_cur_pic.pu1_buf2 - 4;\n    ps_tfr_cxt->pu1_src_v = ps_dec->s_cur_pic.pu1_buf3 - 4;\n    ps_tfr_cxt->pu1_dest_y = ps_tfr_cxt->pu1_src_y;\n    ps_tfr_cxt->pu1_dest_u = ps_tfr_cxt->pu1_src_u;\n    ps_tfr_cxt->pu1_dest_v = ps_tfr_cxt->pu1_src_v;\n\n    ps_tfr_cxt->pu1_mb_y = ps_tfr_cxt->pu1_src_y + 4;\n    ps_tfr_cxt->pu1_mb_u = ps_tfr_cxt->pu1_src_u + 4;\n    ps_tfr_cxt->pu1_mb_v = ps_tfr_cxt->pu1_src_v + 4;\n\n    i4_wd_y = ps_dec->u2_frm_wd_y << u1_field_pic_flag;\n    i4_wd_uv = ps_dec->u2_frm_wd_uv << u1_field_pic_flag;\n    ps_tfr_cxt->u4_y_inc = ((i4_wd_y << u1_mbaff) * 16\n                    - (ps_dec->u2_frm_wd_in_mbs << 4));\n\n    ps_tfr_cxt->u4_uv_inc = (i4_wd_uv << u1_mbaff) * 8\n                    - (ps_dec->u2_frm_wd_in_mbs << 4);\n\n    /* padding related initialisations */\n    if(ps_dec->ps_cur_slice->u1_nal_ref_idc)\n    {\n        ps_pad_mgr->u1_vert_pad_top = !(ps_dec->ps_cur_slice->u1_field_pic_flag\n                        && ps_dec->ps_cur_slice->u1_bottom_field_flag);\n        ps_pad_mgr->u1_vert_pad_bot =\n                        ((!ps_dec->ps_cur_slice->u1_field_pic_flag)\n                                        || ps_dec->ps_cur_slice->u1_bottom_field_flag);\n        ps_pad_mgr->u1_horz_pad = 1;\n    }\n    else\n    {\n        ps_pad_mgr->u1_horz_pad = 0;\n        ps_pad_mgr->u1_vert_pad_top = 0;\n        ps_pad_mgr->u1_vert_pad_bot = 0;\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_deblock_picture_mbaff                                     */\n/*                                                                           */\n/*  Description   : This function carries out deblocking on a whole picture  */\n/*                  with MBAFF                                               */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Processing    : This functions calls deblock MB in the MB increment order*/\n/*                                                                           */\n/*  Outputs       : Produces the deblocked picture                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         17 02 2005   NS              Creation                             */\n/*         14 06 2005   SWRN            clean-up                             */\n/*****************************************************************************/\n\nvoid ih264d_deblock_picture_mbaff(dec_struct_t * ps_dec)\n{\n    WORD16 i2_mb_x, i2_mb_y;\n    deblk_mb_t *ps_cur_mb;\n    deblk_mb_t *ps_top_mb;\n    deblk_mb_t *ps_left_mb;\n\n    UWORD8 u1_vert_pad_top = 1;\n    UWORD8 u1_cur_fld, u1_top_fld, u1_left_fld;\n    UWORD8 u1_first_row;\n\n    UWORD8 * pu1_deb_y, *pu1_deb_u, *pu1_deb_v;\n    UWORD8 u1_deb_mode, u1_extra_top_edge;\n    WORD32 i4_wd_y, i4_wd_uv;\n\n    UWORD8 u1_field_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag; /*< Field u4_flag                       */\n    UWORD8 u1_bottom_field_flag = ps_dec->ps_cur_slice->u1_bottom_field_flag; /*< Bottom field u4_flag*/\n\n    /**************************************************/\n    /* one time loads from ps_dec which will be used  */\n    /* frequently throughout the deblocking procedure */\n    /**************************************************/\n    pad_mgr_t * ps_pad_mgr = &ps_dec->s_pad_mgr;\n    tfr_ctxt_t s_tfr_ctxt;\n    tfr_ctxt_t * ps_tfr_cxt = &s_tfr_ctxt;\n\n    UWORD16 u2_image_wd_mb = ps_dec->u2_frm_wd_in_mbs;\n    UWORD16 u2_image_ht_mb = ps_dec->u2_frm_ht_in_mbs;\n    UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    WORD8 i1_cb_qp_idx_ofst = ps_dec->ps_cur_pps->i1_chroma_qp_index_offset;\n    WORD8 i1_cr_qp_idx_ofst =\n                    ps_dec->ps_cur_pps->i1_second_chroma_qp_index_offset;\n\n    /* Set up Parameter for  DMA transfer */\n    ih264d_init_deblk_tfr_ctxt(ps_dec, ps_pad_mgr, ps_tfr_cxt, u2_image_wd_mb,\n                               u1_mbaff);\n\n    /* Pic level Initialisations */\n    i2_mb_y = u2_image_ht_mb;\n    i2_mb_x = 0;\n    u1_extra_top_edge = 0;\n\n    u1_first_row = 1;\n\n    i4_wd_y = ps_dec->u2_frm_wd_y << u1_field_pic_flag;\n    i4_wd_uv = ps_dec->u2_frm_wd_uv << u1_field_pic_flag;\n    /* Initial filling of the buffers with deblocking data */\n\n    pu1_deb_y = ps_tfr_cxt->pu1_mb_y;\n    pu1_deb_u = ps_tfr_cxt->pu1_mb_u;\n    pu1_deb_v = ps_tfr_cxt->pu1_mb_v;\n    ps_cur_mb = ps_dec->ps_deblk_pic;\n\n    if(ps_dec->u4_app_disable_deblk_frm == 0)\n    {\n        {\n\n            while(i2_mb_y > 0)\n            {\n                do\n                {\n\n                    u1_deb_mode = ps_cur_mb->u1_deblocking_mode;\n                    if(!(u1_deb_mode & MB_DISABLE_FILTERING))\n                    {\n                        ps_tfr_cxt->pu1_mb_y = pu1_deb_y;\n                        ps_tfr_cxt->pu1_mb_u = pu1_deb_u;\n                        ps_tfr_cxt->pu1_mb_v = pu1_deb_v;\n\n                        u1_cur_fld = (ps_cur_mb->u1_mb_type & D_FLD_MB) >> 7;\n                        u1_cur_fld &= 1;\n                        if(i2_mb_x)\n                        {\n                            ps_left_mb = ps_cur_mb - 2;\n                        }\n                        else\n                        {\n                            ps_left_mb = NULL;\n                        }\n                        if(!u1_first_row)\n                        {\n                            ps_top_mb = ps_cur_mb - (u2_image_wd_mb << 1) + 1;\n                            u1_top_fld = (ps_top_mb->u1_mb_type & D_FLD_MB)\n                                            >> 7;\n                        }\n                        else\n                        {\n                            ps_top_mb = NULL;\n                            u1_top_fld = 0;\n                        }\n\n                        if((!u1_first_row) & u1_top_fld & u1_cur_fld)\n                            ps_top_mb--;\n\n                        /********************************************************/\n                        /* if top MB and MB AFF and cur MB is frame and top is  */\n                        /* field, then one extra top edge needs to be deblocked */\n                        /********************************************************/\n                        u1_extra_top_edge = (!u1_cur_fld) & u1_top_fld;\n\n                        if(u1_deb_mode & MB_DISABLE_LEFT_EDGE)\n                            ps_left_mb = NULL;\n                        if(u1_deb_mode & MB_DISABLE_TOP_EDGE)\n                            ps_top_mb = NULL;\n\n                        ih264d_deblock_mb_mbaff(ps_dec, ps_tfr_cxt,\n                                                i1_cb_qp_idx_ofst,\n                                                i1_cr_qp_idx_ofst, ps_cur_mb,\n                                                i4_wd_y, i4_wd_uv, ps_top_mb,\n                                                ps_left_mb, u1_cur_fld,\n                                                u1_extra_top_edge);\n                    }\n\n                    ps_cur_mb++;\n\n                    u1_deb_mode = ps_cur_mb->u1_deblocking_mode;\n                    if(!(u1_deb_mode & MB_DISABLE_FILTERING))\n                    {\n                        ps_tfr_cxt->pu1_mb_y = pu1_deb_y;\n                        ps_tfr_cxt->pu1_mb_u = pu1_deb_u;\n                        ps_tfr_cxt->pu1_mb_v = pu1_deb_v;\n\n                        u1_cur_fld = (ps_cur_mb->u1_mb_type & D_FLD_MB) >> 7;\n                        u1_cur_fld &= 1;\n                        if(i2_mb_x)\n                        {\n                            ps_left_mb = ps_cur_mb - 2;\n                            u1_left_fld = (ps_left_mb->u1_mb_type & D_FLD_MB)\n                                            >> 7;\n                        }\n                        else\n                        {\n                            ps_left_mb = NULL;\n                            u1_left_fld = u1_cur_fld;\n                        }\n                        if(!u1_first_row)\n                        {\n                            ps_top_mb = ps_cur_mb - (u2_image_wd_mb << 1);\n                        }\n                        else\n                        {\n                            ps_top_mb = NULL;\n                        }\n\n                        {\n                            UWORD8 u1_row_shift_y = 0, u1_row_shift_uv = 0;\n                            if(!u1_cur_fld)\n                            {\n                                ps_top_mb = ps_cur_mb - 1;\n                                u1_top_fld = (ps_top_mb->u1_mb_type & D_FLD_MB)\n                                                >> 7;\n                                u1_row_shift_y = 4;\n                                u1_row_shift_uv = 3;\n                            }\n                            ps_tfr_cxt->pu1_mb_y += i4_wd_y << u1_row_shift_y;\n                            ps_tfr_cxt->pu1_mb_u +=\n                                            (i4_wd_uv << u1_row_shift_uv);\n                            ps_tfr_cxt->pu1_mb_v += i4_wd_uv << u1_row_shift_uv;\n                        }\n\n                        /* point to A if top else A+1 */\n                        if(u1_left_fld ^ u1_cur_fld)\n                            ps_left_mb--;\n\n                        /********************************************************/\n                        /* if top MB and MB AFF and cur MB is frame and top is  */\n                        /* field, then one extra top edge needs to be deblocked */\n                        /********************************************************/\n                        u1_extra_top_edge = 0;\n\n                        if(u1_deb_mode & MB_DISABLE_LEFT_EDGE)\n                            ps_left_mb = NULL;\n                        if(u1_deb_mode & MB_DISABLE_TOP_EDGE)\n                            ps_top_mb = NULL;\n\n                        ih264d_deblock_mb_mbaff(ps_dec, ps_tfr_cxt,\n                                                i1_cb_qp_idx_ofst,\n                                                i1_cr_qp_idx_ofst, ps_cur_mb,\n                                                i4_wd_y, i4_wd_uv, ps_top_mb,\n                                                ps_left_mb, u1_cur_fld,\n                                                u1_extra_top_edge);\n                    }\n\n                    ps_cur_mb++;\n                    i2_mb_x++;\n\n                    pu1_deb_y += 16;\n                    pu1_deb_u += 8 * YUV420SP_FACTOR;\n                    pu1_deb_v += 8;\n\n                }\n                while(u2_image_wd_mb > i2_mb_x);\n\n                pu1_deb_y += ps_tfr_cxt->u4_y_inc;\n                pu1_deb_u += ps_tfr_cxt->u4_uv_inc;\n                pu1_deb_v += ps_tfr_cxt->u4_uv_inc;\n\n                i2_mb_x = 0;\n                i2_mb_y -= 2;\n\n                u1_first_row = 0;\n\n            }\n        }\n\n    }\n    //Padd the Picture\n    //Horizontal Padd\n\n    if(ps_pad_mgr->u1_horz_pad)\n    {\n        UWORD32 u1_field_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag;\n        ps_dec->pf_pad_left_luma(ps_tfr_cxt->pu1_src_y + 4,\n                                 ps_dec->u2_frm_wd_y << u1_field_pic_flag,\n                                 ps_dec->u2_pic_ht >> u1_field_pic_flag,\n                                 PAD_LEN_Y_H);\n        ps_dec->pf_pad_right_luma(\n                        ps_tfr_cxt->pu1_src_y + 4\n                                        + (ps_dec->u2_frm_wd_in_mbs << 4),\n                        ps_dec->u2_frm_wd_y << u1_field_pic_flag,\n                        ps_dec->u2_pic_ht >> u1_field_pic_flag, PAD_LEN_Y_H);\n\n        ps_dec->pf_pad_left_chroma(ps_tfr_cxt->pu1_src_u + 4,\n                                   ps_dec->u2_frm_wd_uv << u1_field_pic_flag,\n                                   (ps_dec->u2_pic_ht / 2) >> u1_field_pic_flag,\n                                   PAD_LEN_UV_H * YUV420SP_FACTOR);\n        ps_dec->pf_pad_right_chroma(\n                        ps_tfr_cxt->pu1_src_u + 4\n                                        + (ps_dec->u2_frm_wd_in_mbs << 4),\n                        ps_dec->u2_frm_wd_uv << u1_field_pic_flag,\n                        (ps_dec->u2_pic_ht / 2) >> u1_field_pic_flag,\n                        PAD_LEN_UV_H * YUV420SP_FACTOR);\n\n    }\n\n//Vertical Padd Top\n    if(ps_pad_mgr->u1_vert_pad_top)\n    {\n        ps_dec->pf_pad_top(ps_dec->ps_cur_pic->pu1_buf1 - PAD_LEN_Y_H,\n                           ps_dec->u2_frm_wd_y, ps_dec->u2_frm_wd_y,\n                           ps_pad_mgr->u1_pad_len_y_v);\n        ps_dec->pf_pad_top(\n                        ps_dec->ps_cur_pic->pu1_buf2\n                                        - PAD_LEN_UV_H * YUV420SP_FACTOR,\n                        ps_dec->u2_frm_wd_uv, ps_dec->u2_frm_wd_uv,\n                        ps_pad_mgr->u1_pad_len_cr_v);\n        ps_pad_mgr->u1_vert_pad_top = 0;\n    }\n\n//Vertical Padd Bottom\n    if(ps_pad_mgr->u1_vert_pad_bot)\n    {\n\n        UWORD8 *pu1_buf;\n        pu1_buf = ps_dec->ps_cur_pic->pu1_buf1 - PAD_LEN_Y_H;\n        pu1_buf += ps_dec->u2_pic_ht * ps_dec->u2_frm_wd_y;\n        ps_dec->pf_pad_bottom(pu1_buf, ps_dec->u2_frm_wd_y, ps_dec->u2_frm_wd_y,\n                              ps_pad_mgr->u1_pad_len_y_v);\n        pu1_buf = ps_dec->ps_cur_pic->pu1_buf2 - PAD_LEN_UV_H * YUV420SP_FACTOR;\n        pu1_buf += (ps_dec->u2_pic_ht >> 1) * ps_dec->u2_frm_wd_uv;\n\n        ps_dec->pf_pad_bottom(pu1_buf, ps_dec->u2_frm_wd_uv,\n                              ps_dec->u2_frm_wd_uv,\n                              ps_pad_mgr->u1_pad_len_cr_v);\n\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_deblock_picture_non_mbaff                                  */\n/*                                                                           */\n/*  Description   : This function carries out deblocking on a whole picture  */\n/*                  without MBAFF                                            */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Processing    : This functions calls deblock MB in the MB increment order*/\n/*                                                                           */\n/*  Outputs       : Produces the deblocked picture                           */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         17 02 2005   NS              Creation                             */\n/*         14 06 2005   SWRN            clean-up                             */\n/*****************************************************************************/\n\nvoid ih264d_deblock_picture_non_mbaff(dec_struct_t * ps_dec)\n{\n    deblk_mb_t *ps_cur_mb;\n\n    UWORD8 u1_vert_pad_top = 1;\n\n    UWORD8 u1_deb_mode;\n    WORD32 i4_wd_y, i4_wd_uv;\n\n    UWORD8 u1_field_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag; /*< Field u4_flag                       */\n    UWORD8 u1_bottom_field_flag = ps_dec->ps_cur_slice->u1_bottom_field_flag; /*< Bottom field u4_flag */\n\n    /**************************************************/\n    /* one time loads from ps_dec which will be used  */\n    /* frequently throughout the deblocking procedure */\n    /**************************************************/\n    pad_mgr_t * ps_pad_mgr = &ps_dec->s_pad_mgr;\n    tfr_ctxt_t s_tfr_ctxt;\n    tfr_ctxt_t * ps_tfr_cxt = &s_tfr_ctxt; // = &ps_dec->s_tran_addrecon;\n\n    UWORD16 u2_image_wd_mb = ps_dec->u2_frm_wd_in_mbs;\n    UWORD16 u2_image_ht_mb = ps_dec->u2_frm_ht_in_mbs;\n    WORD8 i1_cb_qp_idx_ofst = ps_dec->ps_cur_pps->i1_chroma_qp_index_offset;\n    WORD8 i1_cr_qp_idx_ofst =\n                    ps_dec->ps_cur_pps->i1_second_chroma_qp_index_offset;\n\n    /* Set up Parameter for  DMA transfer */\n    ih264d_init_deblk_tfr_ctxt(ps_dec, ps_pad_mgr, ps_tfr_cxt, u2_image_wd_mb,\n                               0);\n\n    /* Pic level Initialisations */\n\n\n\n    i4_wd_y = ps_dec->u2_frm_wd_y << u1_field_pic_flag;\n    i4_wd_uv = ps_dec->u2_frm_wd_uv << u1_field_pic_flag;\n    /* Initial filling of the buffers with deblocking data */\n\n    ps_cur_mb = ps_dec->ps_deblk_pic;\n\n    if(ps_dec->u4_app_disable_deblk_frm == 0)\n    {\n        if(ps_dec->ps_cur_sps->u1_mb_aff_flag == 1)\n        {\n            while( ps_dec->u4_deblk_mb_y < u2_image_ht_mb)\n            {\n                ih264d_deblock_mb_nonmbaff(ps_dec, ps_tfr_cxt,\n                                           i1_cb_qp_idx_ofst,\n                                           i1_cr_qp_idx_ofst,\n                                           i4_wd_y, i4_wd_uv);\n                ps_cur_mb++;\n            }\n        }\n\n    }\n\n    //Padd the Picture\n    //Horizontal Padd\n    if(ps_pad_mgr->u1_horz_pad)\n    {\n        UWORD32 u1_field_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag;\n        ps_dec->pf_pad_left_luma(ps_tfr_cxt->pu1_src_y + 4,\n                                 ps_dec->u2_frm_wd_y << u1_field_pic_flag,\n                                 ps_dec->u2_pic_ht >> u1_field_pic_flag,\n                                 PAD_LEN_Y_H);\n        ps_dec->pf_pad_right_luma(\n                        ps_tfr_cxt->pu1_src_y + 4\n                                        + (ps_dec->u2_frm_wd_in_mbs << 4),\n                        ps_dec->u2_frm_wd_y << u1_field_pic_flag,\n                        ps_dec->u2_pic_ht >> u1_field_pic_flag, PAD_LEN_Y_H);\n\n        ps_dec->pf_pad_left_chroma(ps_tfr_cxt->pu1_src_u + 4,\n                                   ps_dec->u2_frm_wd_uv << u1_field_pic_flag,\n                                   (ps_dec->u2_pic_ht / 2) >> u1_field_pic_flag,\n                                   PAD_LEN_UV_H * YUV420SP_FACTOR);\n        ps_dec->pf_pad_right_chroma(\n                        ps_tfr_cxt->pu1_src_u + 4\n                                        + (ps_dec->u2_frm_wd_in_mbs << 4),\n                        ps_dec->u2_frm_wd_uv << u1_field_pic_flag,\n                        (ps_dec->u2_pic_ht / 2) >> u1_field_pic_flag,\n                        PAD_LEN_UV_H * YUV420SP_FACTOR);\n\n    }\n\n//Vertical Padd Top\n    if(ps_pad_mgr->u1_vert_pad_top)\n    {\n        ps_dec->pf_pad_top(ps_dec->ps_cur_pic->pu1_buf1 - PAD_LEN_Y_H,\n                           ps_dec->u2_frm_wd_y, ps_dec->u2_frm_wd_y,\n                           ps_pad_mgr->u1_pad_len_y_v);\n        ps_dec->pf_pad_top(\n                        ps_dec->ps_cur_pic->pu1_buf2\n                                        - PAD_LEN_UV_H * YUV420SP_FACTOR,\n                        ps_dec->u2_frm_wd_uv, ps_dec->u2_frm_wd_uv,\n                        ps_pad_mgr->u1_pad_len_cr_v);\n        ps_pad_mgr->u1_vert_pad_top = 0;\n    }\n\n//Vertical Padd Bottom\n    if(ps_pad_mgr->u1_vert_pad_bot)\n    {\n\n        UWORD8 *pu1_buf;\n        pu1_buf = ps_dec->ps_cur_pic->pu1_buf1 - PAD_LEN_Y_H;\n        pu1_buf += ps_dec->u2_pic_ht * ps_dec->u2_frm_wd_y;\n        ps_dec->pf_pad_bottom(pu1_buf, ps_dec->u2_frm_wd_y, ps_dec->u2_frm_wd_y,\n                              ps_pad_mgr->u1_pad_len_y_v);\n        pu1_buf = ps_dec->ps_cur_pic->pu1_buf2 - PAD_LEN_UV_H * YUV420SP_FACTOR;\n        pu1_buf += (ps_dec->u2_pic_ht >> 1) * ps_dec->u2_frm_wd_uv;\n\n        ps_dec->pf_pad_bottom(pu1_buf, ps_dec->u2_frm_wd_uv,\n                              ps_dec->u2_frm_wd_uv,\n                              ps_pad_mgr->u1_pad_len_cr_v);\n\n    }\n}\n\nvoid ih264d_deblock_picture_progressive(dec_struct_t * ps_dec)\n{\n    deblk_mb_t *ps_cur_mb;\n\n    UWORD8 u1_vert_pad_top = 1;\n    UWORD8 u1_mbs_next;\n    UWORD8 u1_deb_mode;\n    WORD32 i4_wd_y, i4_wd_uv;\n\n\n    /**************************************************/\n    /* one time loads from ps_dec which will be used  */\n    /* frequently throughout the deblocking procedure */\n    /**************************************************/\n    pad_mgr_t * ps_pad_mgr = &ps_dec->s_pad_mgr;\n\n    tfr_ctxt_t s_tfr_ctxt;\n    tfr_ctxt_t * ps_tfr_cxt = &s_tfr_ctxt; // = &ps_dec->s_tran_addrecon;\n    UWORD16 u2_image_wd_mb = ps_dec->u2_frm_wd_in_mbs;\n    UWORD16 u2_image_ht_mb = ps_dec->u2_frm_ht_in_mbs;\n    UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n\n    WORD8 i1_cb_qp_idx_ofst = ps_dec->ps_cur_pps->i1_chroma_qp_index_offset;\n    WORD8 i1_cr_qp_idx_ofst =\n                    ps_dec->ps_cur_pps->i1_second_chroma_qp_index_offset;\n\n    /* Set up Parameter for  deblocking */\n    ih264d_init_deblk_tfr_ctxt(ps_dec, ps_pad_mgr, ps_tfr_cxt, u2_image_wd_mb,\n                               0);\n\n    /* Pic level Initialisations */\n\n    i4_wd_y = ps_dec->u2_frm_wd_y;\n    i4_wd_uv = ps_dec->u2_frm_wd_uv;\n    /* Initial filling of the buffers with deblocking data */\n    ps_cur_mb = ps_dec->ps_deblk_pic;\n\n    if(ps_dec->u4_app_disable_deblk_frm == 0)\n    {\n        if(ps_dec->ps_cur_sps->u1_mb_aff_flag == 1)\n        {\n            while( ps_dec->u4_deblk_mb_y < u2_image_ht_mb)\n            {\n                ih264d_deblock_mb_nonmbaff(ps_dec, ps_tfr_cxt,\n                                           i1_cb_qp_idx_ofst,\n                                           i1_cr_qp_idx_ofst,\n                                           i4_wd_y, i4_wd_uv);\n                ps_cur_mb++;\n            }\n        }\n\n    }\n\n    //Padd the Picture\n    //Horizontal Padd\n    if(ps_pad_mgr->u1_horz_pad)\n    {\n        UWORD32 u1_field_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag;\n        ps_dec->pf_pad_left_luma(ps_tfr_cxt->pu1_src_y + 4,\n                                 ps_dec->u2_frm_wd_y << u1_field_pic_flag,\n                                 ps_dec->u2_pic_ht >> u1_field_pic_flag,\n                                 PAD_LEN_Y_H);\n        ps_dec->pf_pad_right_luma(\n                        ps_tfr_cxt->pu1_src_y + 4\n                                        + (ps_dec->u2_frm_wd_in_mbs << 4),\n                        ps_dec->u2_frm_wd_y << u1_field_pic_flag,\n                        ps_dec->u2_pic_ht >> u1_field_pic_flag, PAD_LEN_Y_H);\n\n        ps_dec->pf_pad_left_chroma(ps_tfr_cxt->pu1_src_u + 4,\n                                   ps_dec->u2_frm_wd_uv << u1_field_pic_flag,\n                                   (ps_dec->u2_pic_ht / 2) >> u1_field_pic_flag,\n                                   PAD_LEN_UV_H * YUV420SP_FACTOR);\n        ps_dec->pf_pad_right_chroma(\n                        ps_tfr_cxt->pu1_src_u + 4\n                                        + (ps_dec->u2_frm_wd_in_mbs << 4),\n                        ps_dec->u2_frm_wd_uv << u1_field_pic_flag,\n                        (ps_dec->u2_pic_ht / 2) >> u1_field_pic_flag,\n                        PAD_LEN_UV_H * YUV420SP_FACTOR);\n\n    }\n\n//Vertical Padd Top\n    if(ps_pad_mgr->u1_vert_pad_top)\n    {\n        ps_dec->pf_pad_top(ps_dec->ps_cur_pic->pu1_buf1 - PAD_LEN_Y_H,\n                           ps_dec->u2_frm_wd_y, ps_dec->u2_frm_wd_y,\n                           ps_pad_mgr->u1_pad_len_y_v);\n        ps_dec->pf_pad_top(\n                        ps_dec->ps_cur_pic->pu1_buf2\n                                        - PAD_LEN_UV_H * YUV420SP_FACTOR,\n                        ps_dec->u2_frm_wd_uv, ps_dec->u2_frm_wd_uv,\n                        ps_pad_mgr->u1_pad_len_cr_v);\n\n    }\n\n//Vertical Padd Bottom\n    if(ps_pad_mgr->u1_vert_pad_bot)\n    {\n\n        UWORD8 *pu1_buf;\n        pu1_buf = ps_dec->ps_cur_pic->pu1_buf1 - PAD_LEN_Y_H;\n        pu1_buf += ps_dec->u2_pic_ht * ps_dec->u2_frm_wd_y;\n        ps_dec->pf_pad_bottom(pu1_buf, ps_dec->u2_frm_wd_y, ps_dec->u2_frm_wd_y,\n                              ps_pad_mgr->u1_pad_len_y_v);\n        pu1_buf = ps_dec->ps_cur_pic->pu1_buf2 - PAD_LEN_UV_H * YUV420SP_FACTOR;\n        pu1_buf += (ps_dec->u2_pic_ht >> 1) * ps_dec->u2_frm_wd_uv;\n\n        ps_dec->pf_pad_bottom(pu1_buf, ps_dec->u2_frm_wd_uv,\n                              ps_dec->u2_frm_wd_uv,\n                              ps_pad_mgr->u1_pad_len_cr_v);\n\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_set_deblocking_parameters \\endif\n *\n * \\brief\n *    Sets the deblocking parameters of the macroblock\n *\n * \\return\n *    0 on Success and Error code otherwise\n *\n * \\note\n *   Given the neighbour availablity information, and the deblocking\n *   parameters of the slice,this function will set the deblocking\n *   mode of the macroblock.\n **************************************************************************\n */\n\nWORD8 ih264d_set_deblocking_parameters(deblk_mb_t * ps_cur_mb,\n                                       dec_slice_params_t * ps_slice,\n                                       UWORD8 u1_mb_ngbr_availablity,\n                                       UWORD8 u1_mb_field_decoding_flag)\n{\n    /*------------------------------------------------------------------*/\n    /* Set the deblocking parameters                                  */\n    /*------------------------------------------------------------------*/\n    ps_cur_mb->i1_slice_alpha_c0_offset = ps_slice->i1_slice_alpha_c0_offset;\n    ps_cur_mb->i1_slice_beta_offset = ps_slice->i1_slice_beta_offset;\n    ps_cur_mb->u1_mb_type = (u1_mb_field_decoding_flag << 7);\n\n    switch(ps_slice->u1_disable_dblk_filter_idc)\n    {\n        case DBLK_ENABLED:\n            ps_cur_mb->u1_deblocking_mode = MB_ENABLE_FILTERING;\n            break;\n        case DBLK_DISABLED:\n            ps_cur_mb->u1_deblocking_mode = MB_DISABLE_FILTERING;\n            break;\n        case SLICE_BOUNDARY_DBLK_DISABLED:\n        {\n            ps_cur_mb->u1_deblocking_mode = MB_ENABLE_FILTERING;\n            if(!(u1_mb_ngbr_availablity & LEFT_MB_AVAILABLE_MASK))\n                ps_cur_mb->u1_deblocking_mode |= MB_DISABLE_LEFT_EDGE;\n            if(!(u1_mb_ngbr_availablity & TOP_MB_AVAILABLE_MASK))\n                ps_cur_mb->u1_deblocking_mode |= MB_DISABLE_TOP_EDGE;\n            break;\n        }\n    }\n\n    return (0);\n}\n\nvoid ih264d_copy_intra_pred_line(dec_struct_t *ps_dec,\n                                 dec_mb_info_t *ps_cur_mb_info,\n                                 UWORD32 nmb_index)\n{\n    UWORD8 *pu1_mb_last_row, u1_mb_field_decoding_flag;\n    UWORD32 u4_recWidth, u4_recwidth_cr;\n\n    u1_mb_field_decoding_flag = ps_cur_mb_info->u1_mb_field_decodingflag;\n\n    u4_recWidth = ps_dec->u2_frm_wd_y << u1_mb_field_decoding_flag;\n    u4_recwidth_cr = ps_dec->u2_frm_wd_uv << u1_mb_field_decoding_flag;\n\n    pu1_mb_last_row = ps_dec->ps_frame_buf_ip_recon->pu1_dest_y\n                    + (u4_recWidth * (MB_SIZE - 1));\n    pu1_mb_last_row += MB_SIZE * nmb_index;\n    MEMCPY_16BYTES(ps_dec->pu1_cur_y_intra_pred_line, pu1_mb_last_row);\n\n    pu1_mb_last_row = ps_dec->ps_frame_buf_ip_recon->pu1_dest_u\n                    + (u4_recwidth_cr * (BLK8x8SIZE - 1));\n    pu1_mb_last_row += BLK8x8SIZE * nmb_index * YUV420SP_FACTOR;\n\n    MEMCPY_16BYTES(ps_dec->pu1_cur_u_intra_pred_line, pu1_mb_last_row);\n\n    ps_dec->pu1_cur_y_intra_pred_line = ps_dec->pu1_cur_y_intra_pred_line_base\n                    + (MB_SIZE * (ps_cur_mb_info->u2_mbx + 1));\n    ps_dec->pu1_cur_u_intra_pred_line = ps_dec->pu1_cur_u_intra_pred_line_base\n                    + (BLK8x8SIZE * (ps_cur_mb_info->u2_mbx + 1))\n                                    * YUV420SP_FACTOR;\n    ps_dec->pu1_cur_v_intra_pred_line = ps_dec->pu1_cur_v_intra_pred_line_base\n                    + (BLK8x8SIZE * (ps_cur_mb_info->u2_mbx + 1));\n\n    if(ps_cur_mb_info->u2_mbx == (ps_dec->u2_frm_wd_in_mbs - 1))\n    {\n        UWORD8* pu1_temp;\n\n        ps_dec->pu1_cur_y_intra_pred_line =\n                        ps_dec->pu1_cur_y_intra_pred_line_base;\n        ps_dec->pu1_cur_u_intra_pred_line =\n                        ps_dec->pu1_cur_u_intra_pred_line_base;\n        ps_dec->pu1_cur_v_intra_pred_line =\n                        ps_dec->pu1_cur_v_intra_pred_line_base;\n\n        /*swap current and previous rows*/\n        pu1_temp = ps_dec->pu1_cur_y_intra_pred_line;\n        ps_dec->pu1_cur_y_intra_pred_line = ps_dec->pu1_prev_y_intra_pred_line;\n        ps_dec->pu1_prev_y_intra_pred_line = pu1_temp;\n\n        pu1_temp = ps_dec->pu1_cur_u_intra_pred_line;\n        ps_dec->pu1_cur_u_intra_pred_line = ps_dec->pu1_prev_u_intra_pred_line;\n        ps_dec->pu1_prev_u_intra_pred_line = pu1_temp;\n\n        pu1_temp = ps_dec->pu1_cur_v_intra_pred_line;\n        ps_dec->pu1_cur_v_intra_pred_line = ps_dec->pu1_prev_v_intra_pred_line;\n        ps_dec->pu1_prev_v_intra_pred_line = pu1_temp;\n\n        ps_dec->pu1_cur_y_intra_pred_line_base =\n                        ps_dec->pu1_cur_y_intra_pred_line;\n        ps_dec->pu1_cur_u_intra_pred_line_base =\n                        ps_dec->pu1_cur_u_intra_pred_line;\n        ps_dec->pu1_cur_v_intra_pred_line_base =\n                        ps_dec->pu1_cur_v_intra_pred_line;\n\n\n\n\n\n    }\n\n}\n\n\nvoid ih264d_filter_boundary_left_mbaff(dec_struct_t *ps_dec,\n                                       tfr_ctxt_t * ps_tfr_cxt,\n                                       WORD8 i1_cb_qp_idx_ofst,\n                                       WORD8 i1_cr_qp_idx_ofst,\n                                       deblk_mb_t * ps_cur_mb,\n                                       WORD32 i4_strd_y,\n                                       WORD32 i4_strd_uv,\n                                       deblk_mb_t * ps_left_mb, /* Neighbouring MB parameters   */\n                                       UWORD32 pu4_bs_tab[], /* pointer to the BsTable array */\n                                       UWORD8 u1_cur_fld)\n{\n    UWORD8 *pu1_y, *pu1_u, *pu1_v;\n    UWORD8 uc_tmp, qp_avg;\n    WORD32 alpha_u = 0, beta_u = 0, alpha_v = 0, beta_v = 0;\n    WORD32 alpha_y = 0, beta_y = 0;\n\n    WORD32 idx_b_u, idx_a_u, idx_b_v, idx_a_v;\n    WORD32 idx_b_y, idx_a_y;\n\n    UWORD32 u4_bs_val;\n\n    UWORD8 *pu1_cliptab_u, *pu1_cliptab_v, *pu1_cliptab_y;\n\n    UWORD8 u1_double_cl = !ps_cur_mb->u1_single_call;\n    WORD32 ofst_a = ps_cur_mb->i1_slice_alpha_c0_offset;\n    WORD32 ofst_b = ps_cur_mb->i1_slice_beta_offset;\n\n    PROFILE_DISABLE_DEBLK()\n\n    pu1_y = ps_tfr_cxt->pu1_mb_y;\n    pu1_u = ps_tfr_cxt->pu1_mb_u;\n    pu1_v = ps_tfr_cxt->pu1_mb_v;\n\n    /* LUMA values */\n    /* Deblock rounding change */\n    uc_tmp = (UWORD8)((ps_left_mb->u1_mb_qp + ps_cur_mb->u1_mb_qp + 1) >> 1);\n    qp_avg = uc_tmp;\n    idx_a_y = qp_avg + ofst_a;\n    alpha_y = gau1_ih264d_alpha_table[12 + idx_a_y];\n    idx_b_y = qp_avg + ofst_b;\n    beta_y = gau1_ih264d_beta_table[12 + idx_b_y];\n\n    /* Chroma cb values */\n    {\n        WORD32 mb_qp1, mb_qp2;\n        mb_qp1 = (ps_left_mb->u1_mb_qp + i1_cb_qp_idx_ofst);\n        mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cb_qp_idx_ofst);\n        qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                        + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n    }\n    idx_a_u = qp_avg + ofst_a;\n    alpha_u = gau1_ih264d_alpha_table[12 + idx_a_u];\n    idx_b_u = qp_avg + ofst_b;\n    beta_u = gau1_ih264d_beta_table[12 + idx_b_u];\n\n    /* Chroma cr values */\n    {\n        WORD32 mb_qp1, mb_qp2;\n        mb_qp1 = (ps_left_mb->u1_mb_qp + i1_cr_qp_idx_ofst);\n        mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cr_qp_idx_ofst);\n        qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                        + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n    }\n    idx_a_v = qp_avg + ofst_a;\n    alpha_v = gau1_ih264d_alpha_table[12 + idx_a_v];\n    idx_b_v = qp_avg + ofst_b;\n    beta_v = gau1_ih264d_beta_table[12 + idx_b_v];\n\n    if(u1_double_cl == 0)\n    {\n        u4_bs_val = pu4_bs_tab[4];\n\n        if(0x04040404 == u4_bs_val)\n        {\n            ps_dec->pf_deblk_luma_vert_bs4(pu1_y, i4_strd_y, alpha_y, beta_y);\n            ps_dec->pf_deblk_chroma_vert_bs4(pu1_u, i4_strd_uv, alpha_u,\n                                             beta_u, alpha_v, beta_v);\n\n        }\n        else\n        {\n            if(u4_bs_val)\n            {\n\n                pu1_cliptab_y = (UWORD8 *)&gau1_ih264d_clip_table[12\n                                + idx_a_y];\n                pu1_cliptab_u = (UWORD8 *)&gau1_ih264d_clip_table[12\n                                + idx_a_u];\n                pu1_cliptab_v = (UWORD8 *)&gau1_ih264d_clip_table[12\n                                + idx_a_v];\n\n                ps_dec->pf_deblk_luma_vert_bslt4(pu1_y, i4_strd_y, alpha_y,\n                                                 beta_y, u4_bs_val,\n                                                 pu1_cliptab_y);\n                ps_dec->pf_deblk_chroma_vert_bslt4(pu1_u, i4_strd_uv, alpha_u,\n                                                   beta_u, alpha_v, beta_v,\n                                                   u4_bs_val, pu1_cliptab_u,\n                                                   pu1_cliptab_v);\n\n            }\n        }\n\n    }\n    else\n    {\n\n        i4_strd_y <<= (!u1_cur_fld);\n        u4_bs_val = pu4_bs_tab[4];\n        i4_strd_uv <<= (!u1_cur_fld);\n\n        if(0x04040404 == u4_bs_val)\n        {\n            ps_dec->pf_deblk_luma_vert_bs4_mbaff(pu1_y, i4_strd_y, alpha_y,\n                                                 beta_y);\n            ps_dec->pf_deblk_chroma_vert_bs4_mbaff(pu1_u, i4_strd_uv, alpha_u,\n                                                   beta_u, alpha_v, beta_v);\n        }\n        else\n        {\n            if(u4_bs_val)\n            {\n\n                pu1_cliptab_y = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_y];\n                pu1_cliptab_u = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_u];\n                pu1_cliptab_v = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_v];\n                ps_dec->pf_deblk_luma_vert_bslt4_mbaff(pu1_y, i4_strd_y,\n                                                       alpha_y, beta_y,\n                                                       u4_bs_val,\n                                                       pu1_cliptab_y);\n                ps_dec->pf_deblk_chroma_vert_bslt4_mbaff(pu1_u, i4_strd_uv,\n                                                         alpha_u, beta_u,\n                                                         alpha_v, beta_v,\n                                                         u4_bs_val,\n                                                         pu1_cliptab_u,\n                                                         pu1_cliptab_v);\n\n            }\n        }\n\n        {\n\n            UWORD16 u2_shift = (i4_strd_y >> 1) << (u1_cur_fld ? 4 : 0);\n            pu1_y += u2_shift;\n            u2_shift = (i4_strd_uv >> 1) << (u1_cur_fld ? 3 : 0);\n            pu1_u += u2_shift;\n            pu1_v += u2_shift;\n        }\n\n        uc_tmp = (((ps_left_mb + 1)->u1_mb_qp + ps_cur_mb->u1_mb_qp + 1) >> 1);\n        qp_avg = uc_tmp;\n        idx_a_y = qp_avg + ofst_a;\n        alpha_y = gau1_ih264d_alpha_table[12 + idx_a_y];\n        idx_b_y = qp_avg + ofst_b;\n        beta_y = gau1_ih264d_beta_table[12 + idx_b_y];\n        u4_bs_val = pu4_bs_tab[9];\n\n        {\n            WORD32 mb_qp1, mb_qp2;\n            mb_qp1 = ((ps_left_mb + 1)->u1_mb_qp + i1_cb_qp_idx_ofst);\n            mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cb_qp_idx_ofst);\n            qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                            + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n        }\n        idx_a_u = qp_avg + ofst_a;\n        alpha_u = gau1_ih264d_alpha_table[12 + idx_a_u];\n        idx_b_u = qp_avg + ofst_b;\n        beta_u = gau1_ih264d_beta_table[12 + idx_b_u];\n        u4_bs_val = pu4_bs_tab[9];\n        {\n            WORD32 mb_qp1, mb_qp2;\n            mb_qp1 = ((ps_left_mb + 1)->u1_mb_qp + i1_cr_qp_idx_ofst);\n            mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cr_qp_idx_ofst);\n            qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                            + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n        }\n        idx_a_v = qp_avg + ofst_a;\n        alpha_v = gau1_ih264d_alpha_table[12 + idx_a_v];\n        idx_b_v = qp_avg + ofst_b;\n        beta_v = gau1_ih264d_beta_table[12 + idx_b_v];\n\n        if(0x04040404 == u4_bs_val)\n        {\n            ps_dec->pf_deblk_luma_vert_bs4_mbaff(pu1_y, i4_strd_y, alpha_y,\n                                                 beta_y);\n            ps_dec->pf_deblk_chroma_vert_bs4_mbaff(pu1_u, i4_strd_uv, alpha_u,\n                                                   beta_u, alpha_v, beta_v);\n\n        }\n        else\n        {\n            if(u4_bs_val)\n            {\n\n                pu1_cliptab_y = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_y];\n                pu1_cliptab_u = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_u];\n                pu1_cliptab_v = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_v];\n\n                ps_dec->pf_deblk_luma_vert_bslt4_mbaff(pu1_y, i4_strd_y,\n                                                       alpha_y, beta_y,\n                                                       u4_bs_val,\n                                                       pu1_cliptab_y);\n                ps_dec->pf_deblk_chroma_vert_bslt4_mbaff(pu1_u, i4_strd_uv,\n                                                         alpha_u, beta_u,\n                                                         alpha_v, beta_v,\n                                                         u4_bs_val,\n                                                         pu1_cliptab_u,\n                                                         pu1_cliptab_v);\n\n            }\n        }\n    }\n\n}\n\nvoid ih264d_filter_boundary_topmbaff(dec_struct_t *ps_dec,\n                                     tfr_ctxt_t * ps_tfr_cxt,\n                                     WORD8 i1_cb_qp_idx_ofst,\n                                     WORD8 i1_cr_qp_idx_ofst,\n                                     deblk_mb_t * ps_cur_mb,\n                                     WORD32 i4_strd_y,\n                                     WORD32 i4_strd_uv,\n                                     deblk_mb_t * ps_top_mb,\n                                     UWORD32 u4_bs)\n{\n    UWORD8 *pu1_y, *pu1_u;\n    WORD32 alpha_u = 0, beta_u = 0, alpha_v = 0, beta_v = 0;\n    WORD32 alpha_y = 0, beta_y = 0;\n    WORD32 qp_avg;\n    WORD32 idx_b_u, idx_a_u, idx_b_v, idx_a_v;\n    WORD32 idx_b_y, idx_a_y;\n    UWORD16 uc_tmp;\n\n    UWORD8 *pu1_cliptab_u, *pu1_cliptab_v, *pu1_cliptab_y;\n    WORD32 ofst_a = ps_cur_mb->i1_slice_alpha_c0_offset;\n    WORD32 ofst_b = ps_cur_mb->i1_slice_beta_offset;\n\n    /* LUMA values */\n    /* Deblock rounding change */\n    uc_tmp = ((ps_top_mb->u1_mb_qp + ps_cur_mb->u1_mb_qp + 1) >> 1);\n    qp_avg = (UWORD8)uc_tmp;\n    idx_a_y = qp_avg + ofst_a;\n    alpha_y = gau1_ih264d_alpha_table[12 + idx_a_y];\n    idx_b_y = qp_avg + ofst_b;\n    beta_y = gau1_ih264d_beta_table[12 + idx_b_y];\n    pu1_y = ps_tfr_cxt->pu1_mb_y;\n\n    /* CHROMA cb values */\n    {\n        WORD32 mb_qp1, mb_qp2;\n        mb_qp1 = (ps_top_mb->u1_mb_qp + i1_cb_qp_idx_ofst);\n        mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cb_qp_idx_ofst);\n        qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                        + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n    }\n\n    idx_a_u = qp_avg + ofst_a;\n    alpha_u = gau1_ih264d_alpha_table[12 + idx_a_u];\n    idx_b_u = qp_avg + ofst_b;\n    beta_u = gau1_ih264d_beta_table[12 + idx_b_u];\n    /* CHROMA cr values */\n    {\n        WORD32 mb_qp1, mb_qp2;\n        mb_qp1 = (ps_top_mb->u1_mb_qp + i1_cr_qp_idx_ofst);\n        mb_qp2 = (ps_cur_mb->u1_mb_qp + i1_cr_qp_idx_ofst);\n        qp_avg = (UWORD8)((gau1_ih264d_qp_scale_cr[12 + mb_qp1]\n                        + gau1_ih264d_qp_scale_cr[12 + mb_qp2] + 1) >> 1);\n    }\n\n    idx_a_v = qp_avg + ofst_a;\n    alpha_v = gau1_ih264d_alpha_table[12 + idx_a_v];\n    idx_b_v = qp_avg + ofst_b;\n    beta_v = gau1_ih264d_beta_table[12 + idx_b_v];\n    pu1_u = ps_tfr_cxt->pu1_mb_u;\n\n    if(u4_bs == 0x04040404)\n    {\n        /* Code specific to the assembly module */\n        ps_dec->pf_deblk_luma_horz_bs4(pu1_y, i4_strd_y, alpha_y, beta_y);\n        ps_dec->pf_deblk_chroma_horz_bs4(pu1_u, i4_strd_uv, alpha_u, beta_u,\n                                         alpha_v, beta_v);\n\n    }\n    else\n    {\n        if(u4_bs)\n        {\n\n            pu1_cliptab_y = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_y];\n            pu1_cliptab_u =\n                            (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_u];\n            pu1_cliptab_v =\n                            (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_v];\n\n            ps_dec->pf_deblk_luma_horz_bslt4(pu1_y, i4_strd_y, alpha_y, beta_y,\n                                             u4_bs, pu1_cliptab_y);\n            ps_dec->pf_deblk_chroma_horz_bslt4(pu1_u, i4_strd_uv, alpha_u,\n                                               beta_u, alpha_v, beta_v,\n                                               u4_bs, pu1_cliptab_u,\n                                               pu1_cliptab_v);\n\n        }\n    }\n\n}\n\nvoid ih264d_deblock_mb_mbaff(dec_struct_t *ps_dec,\n                             tfr_ctxt_t * ps_tfr_cxt,\n                             WORD8 i1_cb_qp_idx_ofst,\n                             WORD8 i1_cr_qp_idx_ofst,\n                             deblk_mb_t * ps_cur_mb,\n                             WORD32 i4_strd_y,\n                             WORD32 i4_strd_uv,\n                             deblk_mb_t * ps_top_mb,\n                             deblk_mb_t * ps_left_mb,\n                             UWORD8 u1_cur_fld,\n                             UWORD8 u1_extra_top_edge)\n{\n    UWORD8 *pu1_y, *pu1_u;\n    UWORD32 u4_bs;\n//  WORD8  edge;\n    WORD32 alpha, beta, alpha_u, beta_u, alpha_v, beta_v;\n\n    UWORD8 *pu1_cliptab_u;\n    UWORD8 *pu1_cliptab_v;\n    UWORD8 *pu1_cliptab_y;\n\n    UWORD32 * pu4_bs_tab = ps_cur_mb->u4_bs_table;\n    WORD32 idx_a_y, idx_a_u, idx_a_v;\n    /* Return from here to switch off deblocking */\n    PROFILE_DISABLE_DEBLK()\n\n    i4_strd_y <<= u1_cur_fld;\n    i4_strd_uv <<= u1_cur_fld;\n    /*--------------------------------------------------------------------*/\n    /* Filter wrt Left edge                                               */\n    /* except                                                             */\n    /*      - Left Egde is Picture Boundary                               */\n    /*      - Left Egde is part of Slice Boundary and Deblocking          */\n    /*        parameters of slice disable Filtering of Slice Boundary Edges*/\n    /*--------------------------------------------------------------------*/\n    if(ps_left_mb)\n        ih264d_filter_boundary_left_mbaff(ps_dec, ps_tfr_cxt, i1_cb_qp_idx_ofst,\n                                          i1_cr_qp_idx_ofst, ps_cur_mb,\n                                          i4_strd_y, i4_strd_uv, ps_left_mb,\n                                          pu4_bs_tab, u1_cur_fld);\n\n    /*--------------------------------------------------------------------*/\n    /* Filter wrt Other Vertical Edges                                    */\n    /*--------------------------------------------------------------------*/\n    {\n        WORD32 ofst_a, ofst_b, idx_b_y, idx_b_u,\n                        idx_b_v;\n        WORD32 qp_avg, qp_avg_u, qp_avg_v;\n        ofst_a = ps_cur_mb->i1_slice_alpha_c0_offset;\n        ofst_b = ps_cur_mb->i1_slice_beta_offset;\n        qp_avg = ps_cur_mb->u1_mb_qp;\n        idx_a_y = qp_avg + ofst_a;\n        alpha = gau1_ih264d_alpha_table[12 + idx_a_y];\n        idx_b_y = qp_avg + ofst_b;\n        beta = gau1_ih264d_beta_table[12 + idx_b_y];\n\n        /* CHROMA Cb values */\n        qp_avg_u = (qp_avg + i1_cb_qp_idx_ofst);\n        qp_avg_u = gau1_ih264d_qp_scale_cr[12 + qp_avg_u];\n        idx_a_u = qp_avg_u + ofst_a;\n        alpha_u = gau1_ih264d_alpha_table[12 + idx_a_u];\n        idx_b_u = qp_avg_u + ofst_b;\n        beta_u = gau1_ih264d_beta_table[12 + idx_b_u];\n        /* CHROMA Cr values */\n        qp_avg_v = (qp_avg + i1_cr_qp_idx_ofst);\n        qp_avg_v = gau1_ih264d_qp_scale_cr[12 + qp_avg_v];\n        idx_a_v = qp_avg_v + ofst_a;\n        alpha_v = gau1_ih264d_alpha_table[12 + idx_a_v];\n        idx_b_v = qp_avg_v + ofst_b;\n        beta_v = gau1_ih264d_beta_table[12 + idx_b_v];\n    }\n\n    //STARTL4_FILTER_VERT;\n\n    pu1_cliptab_y = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_y]; //this for Luma\n    pu1_cliptab_u = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_u]; //this for chroma\n    pu1_cliptab_v = (UWORD8 *)&gau1_ih264d_clip_table[12 + idx_a_v]; //this for chroma\n\n    //edge=1\n\n\n    u4_bs = pu4_bs_tab[5];\n    pu1_y = ps_tfr_cxt->pu1_mb_y;\n    pu1_u = ps_tfr_cxt->pu1_mb_u;\n\n    if(u4_bs)\n    {\n\n        ps_dec->pf_deblk_luma_vert_bslt4(pu1_y + 4, i4_strd_y, alpha, beta,\n                                         u4_bs, pu1_cliptab_y);\n\n    }\n    //edge=2\n\n    u4_bs = pu4_bs_tab[6];\n    if(u4_bs)\n    {\n\n        ps_dec->pf_deblk_luma_vert_bslt4(pu1_y + 8, i4_strd_y, alpha, beta,\n                                         u4_bs, pu1_cliptab_y);\n        ps_dec->pf_deblk_chroma_vert_bslt4(pu1_u + 4 * YUV420SP_FACTOR,\n                                           i4_strd_uv, alpha_u, beta_u,\n                                           alpha_v, beta_v, u4_bs,\n                                           pu1_cliptab_u, pu1_cliptab_v);\n    }\n    //edge=3\n\n    u4_bs = pu4_bs_tab[7];\n    if(u4_bs)\n    {\n\n        ps_dec->pf_deblk_luma_vert_bslt4(pu1_y + 12, i4_strd_y, alpha, beta,\n                                         u4_bs, pu1_cliptab_y);\n\n    }\n\n    /*--------------------------------------------------------------------*/\n    /* Filter wrt Top edge                                                */\n    /* except                                                             */\n    /*      - Top Egde is Picture Boundary                                */\n    /*      - Top Egde is part of Slice Boundary and Deblocking           */\n    /*        parameters of slice disable Filtering of Slice Boundary Edges*/\n    /*--------------------------------------------------------------------*/\n    if(ps_top_mb)\n    {\n        /** if top MB and MB AFF and cur MB is frame and top is field then  */\n        /*  one extra top edge needs to be deblocked                        */\n        if(u1_extra_top_edge)\n        {\n            ih264d_filter_boundary_topmbaff(ps_dec, ps_tfr_cxt,\n                                            i1_cb_qp_idx_ofst,\n                                            i1_cr_qp_idx_ofst, ps_cur_mb,\n                                            (UWORD16)(i4_strd_y << 1),\n                                            (UWORD16)(i4_strd_uv << 1),\n                                            ps_top_mb - 1, pu4_bs_tab[8]);\n            ps_tfr_cxt->pu1_mb_y += i4_strd_y;\n            ps_tfr_cxt->pu1_mb_u += i4_strd_uv;\n            ps_tfr_cxt->pu1_mb_v += i4_strd_uv;\n\n            ih264d_filter_boundary_topmbaff(ps_dec, ps_tfr_cxt,\n                                            i1_cb_qp_idx_ofst,\n                                            i1_cr_qp_idx_ofst, ps_cur_mb,\n                                            (UWORD16)(i4_strd_y << 1),\n                                            (UWORD16)(i4_strd_uv << 1),\n                                            ps_top_mb, pu4_bs_tab[0]);\n            ps_tfr_cxt->pu1_mb_y -= i4_strd_y;\n            ps_tfr_cxt->pu1_mb_u -= i4_strd_uv;\n            ps_tfr_cxt->pu1_mb_v -= i4_strd_uv;\n        }\n        else\n        {\n            ih264d_filter_boundary_topmbaff(ps_dec, ps_tfr_cxt,\n                                            i1_cb_qp_idx_ofst,\n                                            i1_cr_qp_idx_ofst, ps_cur_mb,\n                                            i4_strd_y, i4_strd_uv, ps_top_mb,\n                                            pu4_bs_tab[0]);\n        }\n    }\n\n    /*--------------------------------------------------------------------*/\n    /* Filter wrt Other Horizontal Edges                                  */\n    /*--------------------------------------------------------------------*/\n\n    //edge1\n    u4_bs = pu4_bs_tab[1];\n\n    if(u4_bs)\n    {\n        ps_dec->pf_deblk_luma_horz_bslt4(pu1_y + (i4_strd_y << 2), i4_strd_y,\n                                         alpha, beta, u4_bs, pu1_cliptab_y);\n\n    }\n    //edge2\n    u4_bs = pu4_bs_tab[2];\n\n    if(u4_bs)\n    {\n\n        ps_dec->pf_deblk_luma_horz_bslt4(pu1_y + (i4_strd_y << 3), i4_strd_y,\n                                         alpha, beta, u4_bs, pu1_cliptab_y);\n        ps_dec->pf_deblk_chroma_horz_bslt4(pu1_u + (i4_strd_uv << 2),\n                                           i4_strd_uv, alpha_u, beta_u,\n                                           alpha_v, beta_v, u4_bs,\n                                           pu1_cliptab_u, pu1_cliptab_v);\n\n    }\n    //edge3\n    u4_bs = pu4_bs_tab[3];\n    if(u4_bs)\n    {\n\n        ps_dec->pf_deblk_luma_horz_bslt4(\n                        (pu1_y + (i4_strd_y << 3) + (i4_strd_y << 2)),\n                        i4_strd_y, alpha, beta, u4_bs, pu1_cliptab_y);\n\n    }\n\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_deblocking.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef  _IH264D_DEBLOCKING_H_\n#define  _IH264D_DEBLOCKING_H_\n/*!\n **************************************************************************\n * \\file ih264d_deblocking.h\n *\n * \\brief\n *    Declarations of deblocking functions\n *\n * \\date\n *    23/11/2002\n *\n * \\author  AI\n **************************************************************************\n */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\n\nWORD8 ih264d_set_deblocking_parameters(deblk_mb_t * ps_cur_deblk_mb,\n                                       dec_slice_params_t * ps_slice,\n                                       UWORD8 u1_mb_ngbr_availablity,\n                                       UWORD8 u1_mb_field_decoding_flag);\n\nvoid ih264d_copy_intra_pred_line(dec_struct_t *ps_dec,\n                                 dec_mb_info_t *ps_cur_mb_info,\n                                 UWORD32 nmb_index);\n\nvoid FilterBoundaryLeft(tfr_ctxt_t * const ps_tfr_cxt,\n                        const WORD8 i1_cb_qp_idx_ofst,\n                        const WORD8 i1_cr_qp_idx_ofst,\n                        deblk_mb_t * const ps_cur_mb,\n                        UWORD16 u2_strd_y,\n                        UWORD16 u2_strd_uv,\n                        deblk_mb_t * const ps_left_mb,\n                        const UWORD32 pu4_bs_tab[],\n                        const UWORD8 u1_cur_fld);\nvoid FilterBoundaryTop(tfr_ctxt_t * const ps_tfr_cxt,\n                       const WORD8 i1_cb_qp_idx_ofst,\n                       const WORD8 i1_cr_qp_idx_ofst,\n                       deblk_mb_t * const ps_cur_mb,\n                       const UWORD16 u2_strd_y,\n                       const UWORD16 u2_strd_uv,\n                       deblk_mb_t * const ps_top_mb,\n                       const UWORD32 u4_bs);\nvoid deblock_mb(tfr_ctxt_t * const ps_tfr_cxt,\n                const WORD8 i1_cb_qp_idx_ofst,\n                const WORD8 i1_cr_qp_idx_ofst,\n                deblk_mb_t * const ps_cur_mb,\n                WORD32 i4_strd_y,\n                WORD32 i4_strd_uv,\n                deblk_mb_t * const ps_top_mb,\n                deblk_mb_t * const ps_left_mb,\n                const UWORD8 u1_cur_fld,\n                const UWORD8 u1_extra_top_edge);\nvoid ih264d_deblock_mb_mbaff(dec_struct_t *ps_dec,\n                             tfr_ctxt_t * const ps_tfr_cxt,\n                             const WORD8 i1_cb_qp_idx_ofst,\n                             const WORD8 i1_cr_qp_idx_ofst,\n                             deblk_mb_t * const ps_cur_mb,\n                             WORD32 i4_strd_y,\n                             WORD32 i4_strd_uv,\n                             deblk_mb_t * const ps_top_mb,\n                             deblk_mb_t * const ps_left_mb,\n                             const UWORD8 u1_cur_fld,\n                             const UWORD8 u1_extra_top_edge);\n\nvoid ih264d_deblock_picture_mbaff(dec_struct_t * const ps_dec);\n\nvoid ih264d_deblock_picture_non_mbaff(dec_struct_t * const ps_dec);\n\nvoid ih264d_deblock_picture_progressive(dec_struct_t * const ps_dec);\n\nvoid ih264d_compute_bs_mbaff(dec_struct_t * ps_dec,\n                             dec_mb_info_t * ps_cur_mb_info,\n                             const UWORD16 u2_mbxn_mb);\nvoid ih264d_compute_bs_non_mbaff(dec_struct_t * ps_dec,\n                                 dec_mb_info_t * ps_cur_mb_info,\n                                 const UWORD16 u2_mbxn_mb);\n\nvoid ih264d_fill_bs_mbedge_2(dec_struct_t * ps_dec,\n                             dec_mb_info_t * ps_cur_mb_info,\n                             const UWORD16 u2_mbxn_mb);\n\nvoid ih264d_fill_bs_mbedge_4(dec_struct_t * ps_dec,\n                             dec_mb_info_t * ps_cur_mb_info,\n                             const UWORD16 u2_mbxn_mb);\n\nvoid ih264d_fill_bs1_16x16mb_pslice(mv_pred_t *ps_cur_mv_pred,\n                                    mv_pred_t *ps_top_mv_pred,\n                                    void **ppv_map_ref_idx_to_poc,\n                                    UWORD32 *pu4_bs_table,\n                                    mv_pred_t *ps_leftmost_mv_pred,\n                                    neighbouradd_t *ps_left_addr,\n                                    void **u4_pic_addrress,\n                                    WORD32 i4_ver_mvlimit);\n\nvoid ih264d_fill_bs1_non16x16mb_pslice(mv_pred_t *ps_cur_mv_pred,\n                                       mv_pred_t *ps_top_mv_pred,\n                                       void **ppv_map_ref_idx_to_poc,\n                                       UWORD32 *pu4_bs_table,\n                                       mv_pred_t *ps_leftmost_mv_pred,\n                                       neighbouradd_t *ps_left_addr,\n                                       void **u4_pic_addrress,\n                                       WORD32 i4_ver_mvlimit);\n\nvoid ih264d_fill_bs1_16x16mb_bslice(mv_pred_t *ps_cur_mv_pred,\n                                    mv_pred_t *ps_top_mv_pred,\n                                    void **ppv_map_ref_idx_to_poc,\n                                    UWORD32 *pu4_bs_table,\n                                    mv_pred_t *ps_leftmost_mv_pred,\n                                    neighbouradd_t *ps_left_addr,\n                                    void **u4_pic_addrress,\n                                    WORD32 i4_ver_mvlimit);\n\nvoid ih264d_fill_bs1_non16x16mb_bslice(mv_pred_t *ps_cur_mv_pred,\n                                       mv_pred_t *ps_top_mv_pred,\n                                       void **ppv_map_ref_idx_to_poc,\n                                       UWORD32 *pu4_bs_table,\n                                       mv_pred_t *ps_leftmost_mv_pred,\n                                       neighbouradd_t *ps_left_addr,\n                                       void **u4_pic_addrress,\n                                       WORD32 i4_ver_mvlimit);\n\nvoid ih264d_fill_bs_xtra_left_edge_cur_fld(UWORD32 *pu4_bs,\n                                           WORD32 u4_left_mb_t_csbp,\n                                           WORD32 u4_left_mb_b_csbp,\n                                           WORD32 u4_cur_mb_csbp,\n                                           UWORD32 u4_cur_mb_top);\n\nvoid ih264d_fill_bs_xtra_left_edge_cur_frm(UWORD32 *pu4_bs,\n                                           WORD32 u4_left_mb_t_csbp,\n                                           WORD32 u4_left_mb_b_csbp,\n                                           WORD32 u4_cur_mb_csbp,\n                                           UWORD32 u4_cur_mb_top);\n\nvoid ih264d_deblock_mb_nonmbaff(dec_struct_t *ps_dec,\n                                tfr_ctxt_t * const ps_tfr_cxt,\n                                const WORD8 i1_cb_qp_idx_ofst,\n                                const WORD8 i1_cr_qp_idx_ofst,\n                                WORD32 i4_strd_y,\n                                WORD32 i4_strd_uv);\n\nvoid ih264d_init_deblk_tfr_ctxt(dec_struct_t * ps_dec,\n                                pad_mgr_t *ps_pad_mgr,\n                                tfr_ctxt_t *ps_tfr_cxt,\n                                UWORD16 u2_image_wd_mb,\n                                UWORD8 u1_mbaff);\n\nvoid ih264d_deblock_mb_level(dec_struct_t *ps_dec,\n                             dec_mb_info_t *ps_cur_mb_info,\n                             UWORD32 nmb_index);\n\n#endif /* _IH264D_DEBLOCKING_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_debug.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_DEBUG_H_\n#define _IH264D_DEBUG_H_\n\n/*!\n **************************************************************************\n * \\file ih264d_debug.h\n *\n * \\brief\n *    Contains declarations used for debugging\n *\n * \\date\n *    2/12/2002\n *\n * \\author  AI\n **************************************************************************\n */\n#ifdef DEBUG_DEC\n#define H264_DEC_DEBUG_PRINT(...) printf(\"\\n[H264_DEBUG] %s/%d:: \", __FUNCTION__, __LINE__);printf(__VA_ARGS__)\n#else //DEBUG_DEC\n#define H264_DEC_DEBUG_PRINT(...) {}\n#endif //DEBUG_DEC\n#define   STRENGTH_DEBLOCKING         0 //sanjeev\n#define DEBUG_RECONSTRUCT_LUMA    0\n#define DEBUG_RECONSTRUCT_CHROMA  0\n\n#define DEBUG_IDCT                0\n#define DEBUG_LUMA_IDCT           0\n#define DEBUG_REF_IDCT            0\n\n#define BIN_BIT_RATIO             0\n#define MB_PART_HIST              0\n\n#define MB_INTRA_PREDICTION       1\n\n#ifdef WIN32\n#define CHK_PURIFY                0\n#else\n#define CHK_PURIFY                0\n#endif\n\n#if MB_INTRA_PREDICTION\n#define MB_INTRA_CHROMA_PREDICTION_ON 1\n#define MB_INTRA_4x4_PREDICTION_ON    1\n#define MB_INTRA_16x16_PREDICTION_ON  1\n#endif\n\n#define   TRACE                   0\n#define   DEBUG_CABAC             0\n#define   DEBUG_ABS_MVD           0\n#define   DEBUG_INTRA_PRED_MODES  0\n#define   DEBUG_DEBLOCKING        0\n\n#define COPYTHECONTEXT(s,val)\n#define PRINT_TRACE\n#define PRINT_TRACE_CAB\n#define SWITCHOFFTRACE\n#define SWITCHONTRACE\n#define SWITCHOFFTRACECABAC\n#define SWITCHONTRACECABAC\n\n#define INC_BIN_COUNT(ps_cab_env)\n#define INC_DECISION_BINS(ps_cab_env)\n#define INC_BYPASS_BINS(ps_cab_env)\n#define INC_SYM_COUNT(ps_cab_env)\n#define PRINT_BIN_BIT_RATIO(ps_dec)\n#define RESET_BIN_COUNTS(ps_cab_env)\n\n\n#ifdef PROFILE_DIS_DEBLK\n#define PROFILE_DISABLE_DEBLK() return;\n#else\n#define PROFILE_DISABLE_DEBLK() ;\n#endif\n\n#ifdef PROFILE_DIS_IQ_IT_RECON\n#define PROFILE_DISABLE_IQ_IT_RECON()   if (0)\n#define PROFILE_DISABLE_IQ_IT_RECON_RETURN()   return;\n#else\n#define PROFILE_DISABLE_IQ_IT_RECON() ;\n#define PROFILE_DISABLE_IQ_IT_RECON_RETURN() ;\n#endif\n\n#ifdef PROFILE_DIS_INTRA_PRED\n#define PROFILE_DISABLE_INTRA_PRED() if (0)\n#else\n#define PROFILE_DISABLE_INTRA_PRED() ;\n#endif\n\n#ifdef PROFILE_DIS_UNPACK\n#define PROFILE_DISABLE_UNPACK_LUMA() return 0;\n#define PROFILE_DISABLE_UNPACK_CHROMA() return ;\n#else\n#define PROFILE_DISABLE_UNPACK_LUMA() ;\n#define PROFILE_DISABLE_UNPACK_CHROMA() ;\n#endif\n\n#ifdef PROFILE_DIS_INTER_PRED\n#define PROFILE_DISABLE_INTER_PRED() return;\n#else\n#define PROFILE_DISABLE_INTER_PRED() ;\n#endif\n\n#ifdef PROFILE_DIS_BOUNDARY_STRENGTH\n#define PROFILE_DISABLE_BOUNDARY_STRENGTH() return;\n#else\n#define PROFILE_DISABLE_BOUNDARY_STRENGTH() ;\n#endif\n\n#ifdef PROFILE_DIS_MB_PART_INFO\n#define PROFILE_DISABLE_MB_PART_INFO() return 0;\n#else\n#define PROFILE_DISABLE_MB_PART_INFO() ;\n#endif\n\n#endif /* _IH264D_DEBUG_H_ */\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_defs.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_DEFS_H_\n#define _IH264D_DEFS_H_\n\n/**\n ************************************************************************\n * \\file ih264d_defs.h\n *\n * \\brief\n *    Type definitions used in the code\n *\n * \\date\n *    19/11/2002\n *\n * \\author  Sriram Sethuraman\n *\n ************************************************************************\n */\n#include <stdint.h>\n\n#define H264_MAX_FRAME_WIDTH                4080\n#define H264_MAX_FRAME_HEIGHT               4080\n#define H264_MAX_FRAME_SIZE                 (4096 * 2048)\n\n#define H264_MIN_FRAME_WIDTH                16\n#define H264_MIN_FRAME_HEIGHT               16\n\n#define FMT_CONV_NUM_ROWS       16\n\n/** Decoder currently has an additional latency of 2 pictures when\n  * returning output for display\n  */\n#define DISPLAY_LATENCY         2\n\n/** Bit manipulation macros */\n#define CHECKBIT(a,i) ((a) &  (1 << i))\n#define CLEARBIT(a,i) ((a) &= ~(1 << i))\n\n/** Macro to check if a number lies in the valid integer range */\n#define IS_OUT_OF_RANGE_S32(a) (((a) < INT32_MIN) || ((a) > INT32_MAX))\n\n/** Macro to convert a integer to a boolean value */\n#define BOOLEAN(x) (!!(x))\n\n/** Arithmetic operations */\n#define MOD(x,y) ((x)%(y))\n#define DIV(x,y) ((x)/(y))\n#define MUL(x,y) ((x)*(y))\n#define SIGN_POW2_DIV(x, y) (((x) < 0) ? (-((-(x)) >> (y))) : ((x) >> (y)))\n\n#define MB_ENABLE_FILTERING           0x00\n#define MB_DISABLE_FILTERING          0x01\n#define MB_DISABLE_TOP_EDGE           0x02\n#define MB_DISABLE_LEFT_EDGE          0x04\n\n/** Maximum number of reference pics */\n#define MAX_REF_BUFS    32\n#define MAX_DISP_BUFS_NEW 64\n#define MAX_FRAMES              16\n\n#define INVALID_FRAME_NUM       0x0fffffff\n#define GAP_FRAME_NUM           0x1fffffff\n\n/** macros for reference picture lists, refIdx to POC mapping */\n// 1 extra entry into reference picture lists for refIdx = -1.\n// this entry is always 0. this saves conditional checks in\n// FillBs modules.\n#define POC_LIST_L0_TO_L1_DIFF  (( 2*MAX_FRAMES) + 1)\n#define POC_LIST_L0_TO_L1_DIFF_1  ((MAX_FRAMES) + 1)\n\n#define FRM_LIST_L0             0                                               //0\n#define FRM_LIST_L1             1 * POC_LIST_L0_TO_L1_DIFF//FRM_LIST_L0 + POC_LIST_L0_TO_L1_DIFF        //0+33                  //(1 * POC_LIST_L0_TO_L1_DIFF)\n#define TOP_LIST_FLD_L0         2 * POC_LIST_L0_TO_L1_DIFF//FRM_LIST_L1 + POC_LIST_L0_TO_L1_DIFF        //0+33+33                   //(2 * POC_LIST_L0_TO_L1_DIFF)\n#define TOP_LIST_FLD_L1         3 * POC_LIST_L0_TO_L1_DIFF//TOP_LIST_FLD_L0 + POC_LIST_L0_TO_L1_DIFF_1  //0+33+33+17                //(3 * POC_LIST_L0_TO_L1_DIFF)\n#define BOT_LIST_FLD_L0         4 * POC_LIST_L0_TO_L1_DIFF//TOP_LIST_FLD_L1 + POC_LIST_L0_TO_L1_DIFF_1  //0+33+33+17+17\n#define BOT_LIST_FLD_L1         5 * POC_LIST_L0_TO_L1_DIFF//BOT_LIST_FLD_L0 + POC_LIST_L0_TO_L1_DIFF_1  //0+33+33+17+17+17\n#define TOTAL_LIST_ENTRIES      6 * POC_LIST_L0_TO_L1_DIFF//BOT_LIST_FLD_L1 + POC_LIST_L0_TO_L1_DIFF_1  //0+33+33+17+17+17+17\n#define PAD_MV_BANK_ROW             64\n#define OFFSET_MV_BANK_ROW          ((PAD_MV_BANK_ROW)>>1)\n#define PAD_PUC_CURNNZ              32\n#define OFFSET_PUC_CURNNZ           (PAD_PUC_CURNNZ)\n#define PAD_MAP_IDX_POC             (1)\n#define OFFSET_MAP_IDX_POC          (1)\n\n#define OFFSET_MAP_IDX_POC          (1)\n\n#define NAL_REF_IDC(nal_first_byte)       ((nal_first_byte >> 5) & 0x3)\n#define NAL_FORBIDDEN_BIT(nal_first_byte) (nal_first_byte>>7)\n#define NAL_UNIT_TYPE(nal_first_byte)     (nal_first_byte & 0x1F)\n\n#define INT_PIC_TYPE_I        (0x00)\n\n#define YIELD_CNT_THRESHOLD  8\n\n\n#define OK        0\n#define END       1\n#define NOT_OK    -1\n\n/* For 420SP */\n#define YUV420SP_FACTOR 2\n\n/*To prevent buffer overflow access; in case the size of nal unit is\n *  greater than the allocated buffer size*/\n#define EXTRA_BS_OFFSET 16*16*2\n\n/**\n ***************************************************************************\n * Enum to hold various mem records being request\n ****************************************************************************\n */\nenum\n{\n    /**\n     * Codec Object at API level\n     */\n    MEM_REC_IV_OBJ,\n\n    /**\n     * Codec context\n     */\n    MEM_REC_CODEC,\n\n    /**\n     * Bitstream buffer which holds emulation prevention removed bytes\n     */\n    MEM_REC_BITSBUF,\n\n    /**\n     * Buffer to hold  coeff data\n     */\n    MEM_REC_COEFF_DATA,\n\n    /**\n     * Motion vector bank\n     */\n    MEM_REC_MVBANK,\n\n    /**\n     * Holds mem records passed to the codec.\n     */\n    MEM_REC_BACKUP,\n\n    /**\n     * Holds SPS\n     */\n    MEM_REC_SPS,\n\n    /**\n     * Holds PPS\n     */\n    MEM_REC_PPS,\n\n    /**\n     * Holds Slice Headers\n     */\n    MEM_REC_SLICE_HDR,\n\n    /**\n     * Holds thread handles\n     */\n    MEM_REC_THREAD_HANDLE,\n\n    /**\n     * Contains i4_status map indicating parse i4_status per MB basis\n     */\n    MEM_REC_PARSE_MAP,\n\n    /**\n     * Contains i4_status map indicating processing i4_status per MB basis\n     */\n    MEM_REC_PROC_MAP,\n\n    /**\n     * Contains slice number info for each MB\n     */\n\n    MEM_REC_SLICE_NUM_MAP,\n\n    /**\n     * Holds dpb manager context\n     */\n    MEM_REC_DPB_MGR,\n\n    /**\n     * Holds neighbors' info\n     */\n    MEM_REC_NEIGHBOR_INFO,\n\n    /**\n     * Holds neighbors' info\n     */\n    MEM_REC_PRED_INFO,\n\n\n    /**\n     * Holds inter pred inforamation on packed format info\n     */\n    MEM_REC_PRED_INFO_PKD,\n    /**\n     * Holds neighbors' info\n     */\n    MEM_REC_MB_INFO,\n\n    /**\n     * Holds deblock Mb info structure frame level)\n     */\n    MEM_REC_DEBLK_MB_INFO,\n\n    /**\n     * Holds  reference picture buffers in non-shared mode\n     */\n    MEM_REC_REF_PIC,\n\n    /**\n     * Holds  some misc intermediate_buffers\n     */\n    MEM_REC_EXTRA_MEM,\n\n    /**\n     * Holds  some misc intermediate_buffers\n     */\n    MEM_REC_INTERNAL_SCRATCH,\n\n    /**\n     * Holds  some misc intermediate_buffers\n     */\n    MEM_REC_INTERNAL_PERSIST,\n\n    /* holds structures related to picture buffer manager*/\n    MEM_REC_PIC_BUF_MGR,\n\n    /*holds structure related to MV buffer manager*/\n    MEM_REC_MV_BUF_MGR,\n\n    /**\n     * Place holder to compute number of memory records.\n     */\n    MEM_REC_CNT\n/* Do not add anything below */\n};\n\n#ifdef DEBLOCK_THREAD\n#define H264_MUTEX_LOCK(lock) ithread_mutex_lock(lock)\n#define H264_MUTEX_UNLOCK(lock) ithread_mutex_unlock(lock)\n#else //DEBLOCK_THREAD\n#define H264_MUTEX_LOCK(lock)\n#define H264_MUTEX_UNLOCK(lock)\n\n#define DEBUG_THREADS_PRINTF(...)\n#define DEBUG_PERF_PRINTF(...)\n\n/** Profile Types*/\n#define BASE_PROFILE_IDC    66\n#define MAIN_PROFILE_IDC    77\n#define EXTENDED_PROFILE_IDC    88\n#define HIGH_PROFILE_IDC   100\n\n\n#define MB_SIZE             16\n#define BLK8x8SIZE           8\n#define BLK_SIZE             4\n#define NUM_BLKS_PER_MB     24\n#define NUM_LUM_BLKS_PER_MB 16\n#define LUM_BLK              0\n#define CHROM_BLK            1\n#define NUM_PELS_IN_MB      64\n\n/* Level Types */\n#define H264_LEVEL_1_0     10\n#define H264_LEVEL_1_1     11\n#define H264_LEVEL_1_2     12\n#define H264_LEVEL_1_3     13\n#define H264_LEVEL_2_0     20\n#define H264_LEVEL_2_1     21\n#define H264_LEVEL_2_2     22\n#define H264_LEVEL_3_0     30\n#define H264_LEVEL_3_1     31\n#define H264_LEVEL_3_2     32\n#define H264_LEVEL_4_0     40\n#define H264_LEVEL_4_1     41\n#define H264_LEVEL_4_2     42\n#define H264_LEVEL_5_0     50\n#define H264_LEVEL_5_1     51\n\n#define MAX_MBS_LEVEL_51 36864\n#define MAX_MBS_LEVEL_50 22080\n#define MAX_MBS_LEVEL_42 8704\n#define MAX_MBS_LEVEL_41 8192\n#define MAX_MBS_LEVEL_40 8192\n#define MAX_MBS_LEVEL_32 5120\n#define MAX_MBS_LEVEL_31 3600\n#define MAX_MBS_LEVEL_30 1620\n#define MAX_MBS_LEVEL_22 1620\n#define MAX_MBS_LEVEL_21 792\n#define MAX_MBS_LEVEL_20 396\n#define MAX_MBS_LEVEL_13 396\n#define MAX_MBS_LEVEL_12 396\n#define MAX_MBS_LEVEL_11 396\n#define MAX_MBS_LEVEL_10 99\n\n/** NAL Types */\n#define SLICE_NAL                       1\n#define SLICE_DATA_PARTITION_A_NAL      2\n#define SLICE_DATA_PARTITION_B_NAL      3\n#define SLICE_DATA_PARTITION_C_NAL      4\n#define IDR_SLICE_NAL                   5\n#define SEI_NAL                         6\n#define SEQ_PARAM_NAL                   7\n#define PIC_PARAM_NAL                   8\n#define ACCESS_UNIT_DELIMITER_RBSP      9\n#define END_OF_SEQ_RBSP                 10\n#define END_OF_STREAM_RBSP              11\n#define FILLER_DATA_NAL                 12\n\n/** Entropy coding modes */\n#define CAVLC  0\n#define CABAC  1\n\n/** Picture Types */\n#define I_PIC       0\n#define IP_PIC      1\n#define IPB_PIC     2\n#define SI_PIC      3\n#define SIP_PIC     4\n#define ISI_PIC     5\n#define ISI_PSP_PIC 6\n#define ALL_PIC     7\n\n/* Frame or field picture type */\n#define FRM_PIC         0x00\n#define TOP_FLD         0x01\n#define BOT_FLD         0x02\n#define COMP_FLD_PAIR   0x03 /* TOP_FLD | BOT_FLD */\n#define AFRM_PIC        0x04\n#define TOP_REF         0x08\n#define BOT_REF         0x10\n#define PIC_MASK        0x03\n#define NON_EXISTING    0xff\n\n/* field picture type for display */\n#define DISP_TOP_FLD    0x00\n#define DISP_BOT_FLD    0x01\n\n/** Slice Types */\n#define NA_SLICE -1\n#define P_SLICE  0\n#define B_SLICE  1\n#define I_SLICE  2\n#define SP_SLICE 3\n#define SI_SLICE 4\n\n/* Definition for picture skip */\n#define SKIP_NONE  (0x0)\n#define I_SLC_BIT  (0x1)\n#define P_SLC_BIT  (0x2)\n#define B_SLC_BIT  (0x4)\n\n/** Macros used for Deblocking */\n#define D_INTER_MB        0\n#define D_INTRA_MB        1\n#define D_PRED_NON_16x16  2\n#define D_B_SLICE         4\n#define D_B_SUBMB         6 //D_B_SLICE | D_PRED_NON_16x16 | D_INTER_MB\n#define D_FLD_MB          0x80\n\n/** Macros for Cabac checks */\n/** MbType */\n/** |x|x|I_PCM|SKIP|\n |S|Inter/Intra|P/B|NON-BD16x16/BD16x16,I16x16/I4x4| */\n#define CAB_INTRA         0x00 /* 0000 00xx */\n#define CAB_INTER         0x04 /* 0000 01xx */\n#define CAB_I4x4          0x00 /* 0000 00x0 */\n#define CAB_I16x16        0x01 /* 0000 00x1 */\n#define CAB_BD16x16       0x04 /* 0000 0100 */\n#define CAB_NON_BD16x16   0x05 /* 0000 0101 */\n#define CAB_P             0x07 /* 0000 0111 */\n#define CAB_SI4x4         0x08 /* 0000 10x0 */\n#define CAB_SI16x16       0x09 /* 0000 10x1 */\n#define CAB_SKIP_MASK     0x10 /* 0001 0000 */\n#define CAB_SKIP          0x10 /* 0001 0000 */\n#define CAB_P_SKIP        0x16 /* 0001 x11x */\n#define CAB_B_SKIP        0x14 /* 0001 x100 */\n#define CAB_BD16x16_MASK  0x07 /* 0000 0111 */\n#define CAB_INTRA_MASK    0x04 /* 0000 0100 */\n#define CAB_I_PCM         0x20 /* 001x xxxx */\n\n/**< Binarization types for CABAC */\n/* |x|x|x|x|MSB_FIRST_FLC|FLC|TUNARY|UNARY| */\n#define UNARY           1\n#define TUNARY          2\n#define FLC             4\n#define MSB_FIRST_FLC   12\n\n/** Macroblock Types */\n#define I_4x4_MB    0\n#define I_16x16_MB  1\n#define P_MB        2\n#define B_MB        3\n#define SI_MB       4\n#define SP_MB       5\n#define I_PCM_MB    6\n\n#define SI4x4_MB 0xFF\n\n/** Intra luma 16x16 and chroma 8x8 prediction modes */\n#define NUM_INTRA_PRED_MODES  4\n#define VERT    0\n#define HORIZ   1\n#define DC      2\n#define PLANE   3\n#define NOT_VALID -1\n#define DC_DC_DC_DC   0x02020202 /*packed 4 bytes used in Decode Intra Mb*/\n\n/** Intra luma 4x4 prediction modes */\n#define NUM_INTRA4x4_PRED_MODES 9\n\n/** VERT, HORIZ, DC are applicable to 4x4 as well */\n/** D - Down; U - Up; L - Left; R - Right */\n#define DIAG_DL   3\n#define DIAG_DR   4\n#define VERT_R    5\n#define HORIZ_D   6\n#define VERT_L    7\n#define HORIZ_U   8\n\n/** P_MB prediction modes */\n#define NUM_INTER_MB_PRED_MODES 5\n#define PRED_16x16  0\n#define PRED_16x8   1\n#define PRED_8x16   2\n#define PRED_8x8    3\n#define PRED_8x8R0  4\n#define MAGIC_16x16 5\n#define MB_SKIP     255\n\n/* P_MB submb modes */\n#define P_L0_8x8    0\n#define P_L0_8x4    1\n#define P_L0_4x8    2\n#define P_L0_4x4    3\n\n/* B_MB submb modes */\n#define B_DIRECT_8x8    0\n#define B_L0_8x8        1\n#define B_L1_8x8        2\n#define B_BI_8x8        3\n#define B_L0_8x4        4\n#define B_L0_4x8        5\n#define B_L1_8x4        6\n#define B_L1_4x8        7\n#define B_BI_8x4        8\n#define B_BI_4x8        9\n#define B_L0_4x4        10\n#define B_L1_4x4        11\n#define B_BI_4x4        12\n\n/** B_MB prediction modes */\n#define B_8x8    22\n#define PRED_INVALID  -1\n#define B_DIRECT  0\n#define PRED_L0   1\n#define PRED_L1   2\n#define BI_PRED   3\n#define B_DIRECT_BI_PRED  23\n#define B_DIRECT_PRED_L0  24\n#define B_DIRECT_PRED_L1  25\n#define B_DIRECT_SPATIAL  26\n\n#define B_DIRECT8x8_BI_PRED  13\n#define B_DIRECT8x8_PRED_L0  14\n#define B_DIRECT8x8_PRED_L1  15\n\n#define ONE_TO_ONE  0\n#define FRM_TO_FLD  1\n#define FLD_TO_FRM  2\n\n/** Inter Sub MB Pred modes */\n#define NUM_INTER_SUBMB_PRED_MODES 4\n#define SUBMB_8x8    0\n#define SUBMB_8x4    1\n#define SUBMB_4x8    2\n#define SUBMB_4x4    3\n\n/** Coded Block Pattern - Chroma */\n#define CBPC_ALLZERO    0\n#define CBPC_ACZERO     1\n#define CBPC_NONZERO    2\n\n/** Index for accessing the left MB in the MV predictor array */\n#define LEFT  0\n/** Index for accessing the top MB in the MV predictor array */\n#define TOP   1\n/** Index for accessing the top right MB in the MV predictor array */\n#define TOP_R 2\n/** Index for accessing the top Left MB in the MV predictor array */\n#define TOP_L 3\n\n/** Maximum number of Sequence Parameter sets */\n#define MAX_NUM_SEQ_PARAMS 32\n\n/** Maximum number of Picture Parameter sets */\n#define MAX_NUM_PIC_PARAMS 256\n\n#define MASK_ERR_SEQ_SET_ID   (0xFFFFFFE0)\n#define MASK_ERR_PIC_SET_ID   (0xFFFFFF00)\n\n#define MAX_PIC_ORDER_CNT_TYPE    2\n\n#define MAX_BITS_IN_FRAME_NUM     16\n#define MAX_BITS_IN_POC_LSB       16\n\n#define H264_MAX_REF_PICS         16\n#define H264_MAX_REF_IDX          32\n#define MAX_WEIGHT_BIPRED_IDC     2\n#define MAX_CABAC_INIT_IDC        2\n\n#define H264_DEFAULT_NUM_CORES 1\n#define DEFAULT_SEPARATE_PARSE (H264_DEFAULT_NUM_CORES == 2)? 1 :0\n\n/** Maximum number of Slice groups */\n#define MAX_NUM_SLICE_GROUPS 8\n#define MAX_NUM_REF_FRAMES_OFFSET 255\n\n/** Deblocking modes for a slice */\n#define SLICE_BOUNDARY_DBLK_DISABLED  2\n#define DBLK_DISABLED                 1\n#define DBLK_ENABLED                  0\n#define MIN_DBLK_FIL_OFF              -12\n#define MAX_DBLK_FIL_OFF              12\n\n/** Width of the predictor buffers used for MC */\n#define MB_SIZE             16\n#define BLK8x8SIZE          8\n#define BLK_SIZE             4\n#define NUM_BLKS_PER_MB     24\n#define NUM_LUM_BLKS_PER_MB 16\n\n#define SUB_BLK_WIDTH                 4\n#define SUB_SUB_BLK_SIZE              4 /* 2x2 pixel i4_size */\n#define SUB_BLK_SIZE                  ((SUB_BLK_WIDTH) * (SUB_BLK_WIDTH))\n#define MB_LUM_SIZE                   256\n#define MB_CHROM_SIZE                 64\n\n/**< Width to pad the luminance frame buff    */\n/**< Height to pad the luminance frame buff   */\n/**< Width to pad the chrominance frame buff  */\n/**< Height to pad the chrominance frame buff */\n\n#define PAD_LEN_Y_H                   32\n#define PAD_LEN_Y_V                   20\n#define PAD_LEN_UV_H                  16\n#define PAD_LEN_UV_V                  8\n\n#define PAD_MV_BANK_ROW             64\n\n/**< Maimum u4_ofst by which the Mvs could point outside the frame buffers\n horizontally in the left and vertically in the top direction */\n#define MAX_OFFSET_OUTSIDE_X_FRM      -20\n#define MAX_OFFSET_OUTSIDE_Y_FRM      -20\n#define MAX_OFFSET_OUTSIDE_UV_FRM     -8\n\n/** UVLC parsing macros */\n#define   UEV     1\n#define   SEV     2\n#define   TEV     3\n\n/** Defines for Boolean values */\n#ifndef TRUE\n#define TRUE    1\n#define FALSE   0\n#endif\n\n#define UNUSED_FOR_REF 0\n#define IS_SHORT_TERM  1\n#define IS_LONG_TERM   2\n\n/** Defines for which field gets displayed first */\n#define MAX_FRAMES              16\n#define INVALID_FRAME_NUM       0x0fffffff\n#define DO_NOT_DISP             254\n#define DISP_FLD_FIRST_UNDEF  0\n#define DISP_TOP_FLD_FIRST   1\n#define DISP_BOT_FLD_FIRST   2\n\n/** Misc error resilience requirements*/\n#define MAX_LOG2_WEIGHT_DENOM       7\n#define PRED_WEIGHT_MIN             (-128)\n#define PRED_WEIGHT_MAX             127\n#define MAX_REDUNDANT_PIC_CNT       127\n\n\n\n#endif //DEBLOCK_THREAD\n\n#define NUM_COEFFS_IN_4x4BLK 16\n#define CABAC_BITS_TO_READ 23\n\n#define DISPLAY_PRIMARIES_X_UPPER_LIMIT                37000\n#define DISPLAY_PRIMARIES_X_LOWER_LIMIT                5\n#define DISPLAY_PRIMARIES_X_DIVISION_FACTOR            5\n\n#define DISPLAY_PRIMARIES_Y_UPPER_LIMIT                42000\n#define DISPLAY_PRIMARIES_Y_LOWER_LIMIT                5\n#define DISPLAY_PRIMARIES_Y_DIVISION_FACTOR            5\n\n#define WHITE_POINT_X_UPPER_LIMIT                      37000\n#define WHITE_POINT_X_LOWER_LIMIT                      5\n#define WHITE_POINT_X_DIVISION_FACTOR                  5\n\n#define WHITE_POINT_Y_UPPER_LIMIT                      42000\n#define WHITE_POINT_Y_LOWER_LIMIT                      5\n#define WHITE_POINT_Y_DIVISION_FACTOR                  5\n\n#define MAX_DISPLAY_MASTERING_LUMINANCE_UPPER_LIMIT        100000000\n#define MAX_DISPLAY_MASTERING_LUMINANCE_LOWER_LIMIT        50000\n#define MAX_DISPLAY_MASTERING_LUMINANCE_DIVISION_FACTOR    10000\n\n#define MIN_DISPLAY_MASTERING_LUMINANCE_UPPER_LIMIT        50000\n#define MIN_DISPLAY_MASTERING_LUMINANCE_LOWER_LIMIT        1\n\n#define AMBIENT_LIGHT_X_UPPER_LIMIT        50000\n#define AMBIENT_LIGHT_Y_UPPER_LIMIT        50000\n\n#define CCV_PRIMARIES_X_UPPER_LIMIT        5000000\n#define CCV_PRIMARIES_X_LOWER_LIMIT        -5000000\n#define CCV_PRIMARIES_Y_UPPER_LIMIT        5000000\n#define CCV_PRIMARIES_Y_LOWER_LIMIT        -5000000\n\n\n#define MEMSET_16BYTES(pu4_start,value)                         \\\n{                                                               \\\n    memset(pu4_start,value,16);                                 \\\n}\n\n#define MEMCPY_16BYTES(dst,src)                                 \\\n{                                                               \\\n    memcpy(dst,src,16);                                         \\\n}\n\n\n#endif /*_IH264D_DEFS_H_*/\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_dpb_manager.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_DPB_MANAGER_H_\n#define _IH264D_DPB_MANAGER_H_\n/*!\n***************************************************************************\n* \\file ih264d_dpb_manager.h\n*\n* \\brief\n*    Decoded Picture Buffer Manager Include File\n*\n* Detailed_description\n*\n* \\date\n*    19-12-2002\n*\n* \\author  Sriram Sethuraman\n***************************************************************************\n*/\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_defs.h\"\n\n#define END_OF_MMCO                 0\n#define MARK_ST_PICNUM_AS_NONREF    1\n#define MARK_LT_INDEX_AS_NONREF     2\n#define MARK_ST_PICNUM_AS_LT_INDEX  3\n#define SET_MAX_LT_INDEX            4\n#define RESET_REF_PICTURES          5\n#define SET_LT_INDEX                6\n#define RESET_NONREF_PICTURES       7\n#define RESET_ALL_PICTURES          8\n\n#define NO_LONG_TERM_INDICIES      255\nstruct field_t\n{\n    /* picNum of tbe reference field              */\n    WORD32 i4_pic_num;\n\n    /*  assigned when used for long term reference */\n    /* else MAX_REF_BUFS+1 */\n    UWORD8 u1_long_term_frame_idx;\n\n    /* 0 : unused for reference                   */\n    /* 1 : used for short term reference          */\n    /* 2 : used for long term reference           */\n    UWORD8 u1_reference_info;\n};\n\n\nstruct dpb_info_t\n{\n  struct pic_buffer_t *ps_pic_buf;       /** Pointer to picture buffer structure */\n  WORD32 i4_frame_num;      /** frame number of picture - unique for each ref*/\n  struct dpb_info_t *ps_prev_short;/** Link to the DPB with previous picNum */\n  struct dpb_info_t *ps_prev_long;     /** Link to the DPB with previous long term frame*/\n  struct field_t s_top_field;       /** Contains information of the top_field\n                                     reference info, pic num and longt term frame idx */\n  struct field_t s_bot_field;       /** Contains information of the bot_field\n                                     reference info, pic num and longt term frame idx */\n  UWORD8 u1_buf_id;     /** bufID from bufAPI */\n  UWORD8 u1_used_as_ref;        /** whether buffer is used as ref for frame or\n                                     complementary reference field pair */\n  UWORD8 u1_lt_idx;     /** If buf is assigned long-term index; else MAX_REF_BUFS+1 */\n\n};\n\ntypedef struct\n{\n  struct pic_buffer_t *ps_def_dpb[MAX_REF_BUFS];/** DPB in default index order */\n  struct pic_buffer_t *ps_mod_dpb[2][2 * MAX_REF_BUFS];/** DPB in reordered index order, 0-fwd,1-bwd */\n  struct pic_buffer_t *ps_init_dpb[2][2 * MAX_REF_BUFS];/** DPB in reordered index order, 0-fwd,1-bwd */\n  struct dpb_info_t *ps_dpb_st_head;     /** Pointer to the most recent picNum */\n  struct dpb_info_t *ps_dpb_ht_head;     /** Pointer to the smallest LT index */\n  struct dpb_info_t as_dpb_info[MAX_REF_BUFS];       /** Physical storage for dpbInfo for ref bufs */\n  UWORD8 u1_num_st_ref_bufs;        /** Number of short term ref. buffers */\n  UWORD8 u1_num_lt_ref_bufs;        /** Number of long term ref. buffer */\n  UWORD8 u1_max_lt_frame_idx;       /** Maximum long term frame index */\n  UWORD8 u1_num_gaps;       /** Total number of outstanding gaps */\n  void * pv_codec_handle;             /* For Error Handling */\n  WORD32 i4_max_frm_num;        /** Max frame number */\n  WORD32 ai4_gaps_start_frm_num[MAX_FRAMES];/** start frame number for a gap seqn */\n  WORD32 ai4_gaps_end_frm_num[MAX_FRAMES];       /** start frame number for a gap seqn */\n  WORD8  ai1_gaps_per_seq[MAX_FRAMES];      /** number of gaps with each gap seqn */\n  WORD32 ai4_poc_buf_id_map[MAX_FRAMES][3];\n  WORD8 i1_poc_buf_id_entries;\n  WORD8 i1_gaps_deleted;\n  UWORD16 u2_pic_wd;\n  UWORD16 u2_pic_ht;\n  UWORD8 u1_mmco_error_in_seq;\n}dpb_manager_t;\n\n/** Structure store the MMC Commands */\nstruct MMCParams\n{\n  UWORD32 u4_mmco;      /** memory managemet control operation */\n  UWORD32 u4_diff_pic_num;      /** diff Of Pic Nums Minus1 */\n  UWORD32 u4_lt_idx;        /** Long Term Pic Idx */\n  UWORD32 u4_max_lt_idx_plus1;      /** MaxLongTermPicIdxPlus1 */\n};\n\ntypedef struct\n{\n  UWORD8  u1_dpb_commands_read;     /** Flag to indicate that DBP commands are read */\n  UWORD8  u1_buf_mode;      /** decoder Pic bugffering mode*/\n  UWORD8  u1_num_of_commands;       /** Number of MMC commands */\n  /* These variables are ised in case of IDR pictures only */\n  UWORD8  u1_idr_pic;       /** = 1 ,IDR pic */\n  UWORD8  u1_no_output_of_prior_pics_flag;\n  UWORD8  u1_long_term_reference_flag;\n  struct MMCParams  as_mmc_params[MAX_REF_BUFS];      /* < Buffer to store MMC commands */\n  UWORD8 u1_dpb_commands_read_slc;\n}dpb_commands_t;\n\nvoid ih264d_init_ref_bufs(dpb_manager_t *ps_dpb_mgr);\n\nWORD32 ih264d_insert_st_node(dpb_manager_t *ps_dpb_mgr,\n                          struct pic_buffer_t *ps_pic_buf,\n                          UWORD8 u1_buf_id,\n                          UWORD32 u2_cur_pic_num);\nWORD32 ih264d_update_default_index_list(dpb_manager_t *ps_dpb_mgr);\nWORD32 ih264d_do_mmco_buffer(dpb_commands_t *ps_dpb_cmds,\n                          dpb_manager_t *ps_dpb_mgr,\n                          UWORD8 u1_numRef_frames_for_seq,\n                          UWORD32 u4_cur_pic_num,\n                          UWORD32 u2_u4_max_pic_num_minus1,\n                          UWORD8 u1_nal_unit_type,\n                          struct pic_buffer_t *ps_pic_buf,\n                          UWORD8 u1_buf_id,\n                          UWORD8 u1_fld_pic_flag,\n                          UWORD8 u1_curr_pic_in_err);\nvoid ih264d_release_pics_in_dpb(void *pv_dec,\n                                UWORD8 u1_disp_bufs);\nvoid ih264d_reset_ref_bufs(dpb_manager_t *ps_dpb_mgr);\nWORD32 ih264d_delete_st_node_or_make_lt(dpb_manager_t *ps_dpb_mgr,\n                                      WORD32 u4_pic_num,\n                                      UWORD32 u4_lt_idx,\n                                      UWORD8 u1_fld_pic_flag);\n\nWORD32 ih264d_delete_gap_frm_mmco(dpb_manager_t *ps_dpb_mgr,\n                                  WORD32 i4_frame_num,\n                                  UWORD8 *pu1_del_node);\n\nWORD32 ih264d_delete_gap_frm_sliding(dpb_manager_t *ps_dpb_mgr,\n                                     WORD32 i4_frame_num,\n                                     UWORD8 *pu1_del_node);\n\nWORD32 ih264d_do_mmco_for_gaps(dpb_manager_t *ps_dpb_mgr,\n                             UWORD8 u1_num_ref_frames);\n\nWORD32 ih264d_insert_pic_in_display_list(dpb_manager_t *ps_dpb_mgr,\n                                         UWORD8 u1_buf_id,\n                                         WORD32 i4_display_poc,\n                                         UWORD32 u4_frame_num);\nvoid ih264d_delete_nonref_nondisplay_pics(dpb_manager_t *ps_dpb_mgr);\n#endif /*  _IH264D_DPB_MANAGER_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_dpb_mgr.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifdef __ANDROID__\n#include <log/log.h>\n#endif\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"iv.h\"\n#include \"ih264d_dpb_manager.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_process_bslice.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_error_handler.h\"\n#include \"string.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264_error.h\"\n#include \"ih264_buf_mgr.h\"\n#include \"assert.h\"\n\n/*!\n ***************************************************************************\n * \\file ih264d_dpb_mgr.c\n *\n * \\brief\n *    Functions for managing the decoded picture buffer\n *\n * Detailed_description\n *\n * \\date\n *    19-12-2002\n *\n * \\author  Sriram Sethuraman\n ***************************************************************************\n */\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_init_ref_bufs \\endif\n *\n * \\brief\n *    Called at the start for initialization.\n *\n * \\return\n *    none\n **************************************************************************\n */\nvoid ih264d_init_ref_bufs(dpb_manager_t *ps_dpb_mgr)\n{\n    UWORD32 i;\n    struct dpb_info_t *ps_dpb_info = ps_dpb_mgr->as_dpb_info;\n    for(i = 0; i < MAX_REF_BUFS; i++)\n    {\n        ps_dpb_info[i].u1_used_as_ref = UNUSED_FOR_REF;\n        ps_dpb_info[i].u1_lt_idx = MAX_REF_BUFS + 1;\n        ps_dpb_info[i].ps_prev_short = NULL;\n        ps_dpb_info[i].ps_prev_long = NULL;\n        ps_dpb_info[i].ps_pic_buf = NULL;\n        ps_dpb_info[i].s_top_field.u1_reference_info = UNUSED_FOR_REF;\n        ps_dpb_info[i].s_bot_field.u1_reference_info = UNUSED_FOR_REF;\n        ps_dpb_info[i].s_top_field.u1_long_term_frame_idx = MAX_REF_BUFS + 1;\n        ps_dpb_info[i].s_bot_field.u1_long_term_frame_idx = MAX_REF_BUFS + 1;\n\n    }\n    ps_dpb_mgr->u1_num_st_ref_bufs = ps_dpb_mgr->u1_num_lt_ref_bufs = 0;\n    ps_dpb_mgr->ps_dpb_st_head = NULL;\n    ps_dpb_mgr->ps_dpb_ht_head = NULL;\n    ps_dpb_mgr->i1_gaps_deleted = 0;\n    ps_dpb_mgr->i1_poc_buf_id_entries = 0;\n    ps_dpb_mgr->u1_mmco_error_in_seq = 0;\n\n    ps_dpb_mgr->u1_num_gaps = 0;\n    for(i = 0; i < MAX_FRAMES; i++)\n    {\n        ps_dpb_mgr->ai4_gaps_start_frm_num[i] = INVALID_FRAME_NUM;\n        ps_dpb_mgr->ai4_gaps_end_frm_num[i] = 0;\n        ps_dpb_mgr->ai1_gaps_per_seq[i] = 0;\n        ps_dpb_mgr->ai4_poc_buf_id_map[i][0] = -1;\n        ps_dpb_mgr->ai4_poc_buf_id_map[i][1] = 0x7fffffff;\n        ps_dpb_mgr->ai4_poc_buf_id_map[i][2] = 0;\n    }\n\n}\n\nvoid ih264d_free_ref_pic_mv_bufs(void* pv_dec, UWORD8 pic_buf_id)\n{\n    dec_struct_t *ps_dec = (dec_struct_t *)pv_dec;\n\n    if((pic_buf_id == ps_dec->u1_pic_buf_id) &&\n                    ps_dec->ps_cur_slice->u1_field_pic_flag &&\n                    (ps_dec->u1_top_bottom_decoded == 0))\n    {\n        return;\n    }\n\n    ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                          pic_buf_id,\n                          BUF_MGR_REF);\n    ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_mv_buf_mgr,\n                          ps_dec->au1_pic_buf_id_mv_buf_id_map[pic_buf_id],\n                          BUF_MGR_REF);\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_delete_lt_node \\endif\n *\n * \\brief\n *    Delete a buffer with a long term index from the LT linked list\n *\n * \\return\n *    none\n **************************************************************************\n */\nWORD32 ih264d_delete_lt_node(dpb_manager_t *ps_dpb_mgr,\n                             UWORD32 u4_lt_idx,\n                             UWORD8 u1_fld_pic_flag,\n                             struct dpb_info_t *ps_lt_node_to_insert,\n                             WORD32 *pi4_status)\n{\n    *pi4_status = 0;\n    if(ps_dpb_mgr->u1_num_lt_ref_bufs > 0)\n    {\n        WORD32 i;\n        struct dpb_info_t *ps_next_dpb;\n        /* ps_unmark_node points to the node to be removed */\n        /* from long term list.                            */\n        struct dpb_info_t *ps_unmark_node;\n        //Find the node with matching LTIndex\n        ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;\n        if(ps_next_dpb->u1_lt_idx == u4_lt_idx)\n        {\n            ps_unmark_node = ps_next_dpb;\n        }\n        else\n        {\n            for(i = 1; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)\n            {\n                if(ps_next_dpb->ps_prev_long->u1_lt_idx == u4_lt_idx)\n                    break;\n                ps_next_dpb = ps_next_dpb->ps_prev_long;\n            }\n            if(i == ps_dpb_mgr->u1_num_lt_ref_bufs)\n                *pi4_status = 1;\n            else\n                ps_unmark_node = ps_next_dpb->ps_prev_long;\n        }\n\n        if(*pi4_status == 0)\n        {\n            if(u1_fld_pic_flag)\n            {\n                if(ps_lt_node_to_insert != ps_unmark_node)\n                {\n                    UWORD8 u1_deleted = 0;\n                    /* for the ps_unmark_node mark the corresponding field */\n                    /* field as unused for reference                       */\n\n                    if(ps_unmark_node->s_top_field.u1_long_term_frame_idx\n                                    == u4_lt_idx)\n                    {\n                        ps_unmark_node->s_top_field.u1_reference_info =\n                                        UNUSED_FOR_REF;\n                        ps_unmark_node->s_top_field.u1_long_term_frame_idx =\n                        MAX_REF_BUFS + 1;\n                        u1_deleted = 1;\n                    }\n                    if(ps_unmark_node->s_bot_field.u1_long_term_frame_idx\n                                    == u4_lt_idx)\n                    {\n                        ps_unmark_node->s_bot_field.u1_reference_info =\n                                        UNUSED_FOR_REF;\n                        ps_unmark_node->s_bot_field.u1_long_term_frame_idx =\n                        MAX_REF_BUFS + 1;\n                        u1_deleted = 1;\n                    }\n\n                    if(!u1_deleted)\n                    {\n\n                        UWORD32 i4_error_code;\n                        i4_error_code = ERROR_DBP_MANAGER_T;\n\n                        return i4_error_code;\n                    }\n                }\n\n                ps_unmark_node->u1_used_as_ref =\n                                ps_unmark_node->s_top_field.u1_reference_info\n                                                | ps_unmark_node->s_bot_field.u1_reference_info;\n            }\n            else\n                ps_unmark_node->u1_used_as_ref = UNUSED_FOR_REF;\n\n            if(UNUSED_FOR_REF == ps_unmark_node->u1_used_as_ref)\n            {\n                if(ps_unmark_node == ps_dpb_mgr->ps_dpb_ht_head)\n                    ps_dpb_mgr->ps_dpb_ht_head = ps_next_dpb->ps_prev_long;\n\n                ps_unmark_node->u1_lt_idx = MAX_REF_BUFS + 1;\n                ps_unmark_node->s_top_field.u1_reference_info =\n                UNUSED_FOR_REF;\n                ps_unmark_node->s_bot_field.u1_reference_info =\n                UNUSED_FOR_REF;\n                // Release the physical buffer\n                ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                            ps_unmark_node->u1_buf_id);\n                ps_next_dpb->ps_prev_long = ps_unmark_node->ps_prev_long; //update link\n                ps_unmark_node->ps_prev_long = NULL;\n                ps_dpb_mgr->u1_num_lt_ref_bufs--; //decrement LT buf count\n            }\n        }\n    }\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_insert_lt_node \\endif\n *\n * \\brief\n *    Insert a buffer into the LT linked list at a given LT index\n *\n * \\return\n *    none\n **************************************************************************\n */\nWORD32 ih264d_insert_lt_node(dpb_manager_t *ps_dpb_mgr,\n                           struct dpb_info_t *ps_mov_node,\n                           UWORD32 u4_lt_idx,\n                           UWORD8 u1_fld_pic_flag)\n{\n    UWORD8 u1_mark_top_field_long_term = 0;\n    UWORD8 u1_mark_bot_field_long_term = 0;\n\n    {\n        if(u1_fld_pic_flag)\n        {\n            /* Assign corresponding field (top or bottom) long_term_frame_idx */\n\n            if((ps_mov_node->s_top_field.u1_reference_info == IS_LONG_TERM)\n                            && (ps_mov_node->s_bot_field.u1_reference_info\n                                            == IS_LONG_TERM))\n            {\n                if(ps_mov_node->u1_lt_idx == u4_lt_idx)\n                    u1_mark_bot_field_long_term = 1;\n                else\n                {\n\n                    UWORD32 i4_error_code;\n                    i4_error_code = ERROR_DBP_MANAGER_T;\n\n                    return i4_error_code;\n\n                }\n            }\n            else if(ps_mov_node->s_top_field.u1_reference_info == IS_LONG_TERM)\n            {\n                u1_mark_top_field_long_term = 1;\n            }\n\n            if(!(u1_mark_top_field_long_term || u1_mark_bot_field_long_term))\n            {\n                UWORD32 i4_error_code;\n                i4_error_code = ERROR_DBP_MANAGER_T;\n                return i4_error_code;\n            }\n        }\n        else\n        {\n            ps_mov_node->s_top_field.u1_reference_info = IS_LONG_TERM;\n            ps_mov_node->s_bot_field.u1_reference_info = IS_LONG_TERM;\n            ps_mov_node->s_top_field.u1_long_term_frame_idx = u4_lt_idx;\n            ps_mov_node->s_bot_field.u1_long_term_frame_idx = u4_lt_idx;\n            u1_mark_bot_field_long_term = 1;\n            u1_mark_top_field_long_term = 1;\n        }\n\n        ps_mov_node->u1_lt_idx = u4_lt_idx; //Assign the LT index to the node\n        ps_mov_node->ps_pic_buf->u1_long_term_frm_idx = u4_lt_idx;\n        ps_mov_node->u1_used_as_ref = IS_LONG_TERM;\n\n        /* Insert the new long term in the LT list with  u4_lt_idx    */\n        /* in ascending order.                                         */\n        if(ps_dpb_mgr->u1_num_lt_ref_bufs > 0)\n        {\n            struct dpb_info_t *ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;\n            if(u4_lt_idx < ps_next_dpb->u1_lt_idx)\n            {\n                //LTIndex to be inserted is the smallest LT index\n                //Update head and point prev to the next higher index\n                ps_mov_node->ps_prev_long = ps_next_dpb;\n                ps_dpb_mgr->ps_dpb_ht_head = ps_mov_node;\n            }\n            else\n            {\n                WORD32 i;\n                struct dpb_info_t *ps_nxtDPB = ps_next_dpb;\n                ps_next_dpb = ps_next_dpb->ps_prev_long;\n                for(i = 1; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)\n                {\n                    if(ps_next_dpb->u1_lt_idx > u4_lt_idx)\n                        break;\n                    ps_nxtDPB = ps_next_dpb;\n                    ps_next_dpb = ps_next_dpb->ps_prev_long;\n                }\n\n                ps_nxtDPB->ps_prev_long = ps_mov_node;\n                ps_mov_node->ps_prev_long = ps_next_dpb;\n            }\n        }\n        else\n        {\n            ps_dpb_mgr->ps_dpb_ht_head = ps_mov_node;\n            ps_mov_node->ps_prev_long = NULL;\n        }\n        /* Identify the picture buffer as a long term picture buffer */\n        ps_mov_node->ps_pic_buf->u1_is_short = 0;\n\n        /* Increment LT buf count only if new LT node inserted    */\n        /* If Increment during top_field is done, don't increment */\n        /* for bottom field, as both them are part of same pic.   */\n        if(u1_mark_bot_field_long_term)\n            ps_dpb_mgr->u1_num_lt_ref_bufs++;\n\n    }\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_insert_st_node \\endif\n *\n * \\brief\n *    Adds a short term reference picture into the ST linked list\n *\n * \\return\n *    None\n *\n * \\note\n *    Called only for a new coded picture with nal_ref_idc!=0\n **************************************************************************\n */\nWORD32 ih264d_insert_st_node(dpb_manager_t *ps_dpb_mgr,\n                          struct pic_buffer_t *ps_pic_buf,\n                          UWORD8 u1_buf_id,\n                          UWORD32 u4_cur_pic_num)\n{\n    WORD32 i;\n    struct dpb_info_t *ps_dpb_info = ps_dpb_mgr->as_dpb_info;\n    UWORD8 u1_picture_type = ps_pic_buf->u1_picturetype;\n    /* Find an unused dpb location */\n    for(i = 0; i < MAX_REF_BUFS; i++)\n    {\n        if((ps_dpb_info[i].ps_pic_buf == ps_pic_buf)\n                        && ps_dpb_info[i].u1_used_as_ref)\n        {\n            /*signal an error in the case of frame pic*/\n            if(ps_dpb_info[i].ps_pic_buf->u1_pic_type == FRM_PIC)\n            {\n                return ERROR_DBP_MANAGER_T;\n            }\n            else\n            {\n                /* Can occur only for field bottom pictures */\n                ps_dpb_info[i].s_bot_field.u1_reference_info = IS_SHORT_TERM;\n                return OK;\n            }\n        }\n\n        if((ps_dpb_info[i].u1_used_as_ref == UNUSED_FOR_REF)\n                        && (ps_dpb_info[i].s_top_field.u1_reference_info\n                                        == UNUSED_FOR_REF)\n                        && (ps_dpb_info[i].s_bot_field.u1_reference_info\n                                        == UNUSED_FOR_REF))\n            break;\n    }\n    if(i == MAX_REF_BUFS)\n    {\n        UWORD32 i4_error_code;\n        i4_error_code = ERROR_DBP_MANAGER_T;\n        return i4_error_code;\n    }\n\n    /* Create dpb info */\n    ps_dpb_info[i].ps_pic_buf = ps_pic_buf;\n    ps_dpb_info[i].ps_prev_short = ps_dpb_mgr->ps_dpb_st_head;\n    ps_dpb_info[i].u1_buf_id = u1_buf_id;\n    ps_dpb_info[i].u1_used_as_ref = TRUE;\n    ps_dpb_info[i].u1_lt_idx = MAX_REF_BUFS + 1;\n    ps_dpb_info[i].i4_frame_num = u4_cur_pic_num;\n    ps_dpb_info[i].ps_pic_buf->i4_frame_num = u4_cur_pic_num;\n\n    /* update the head node of linked list to point to the cur Pic */\n    ps_dpb_mgr->ps_dpb_st_head = ps_dpb_info + i;\n\n    // Increment Short term bufCount\n    ps_dpb_mgr->u1_num_st_ref_bufs++;\n    /* Identify the picture as a short term picture buffer */\n    ps_pic_buf->u1_is_short = IS_SHORT_TERM;\n\n    if((u1_picture_type & 0x03) == FRM_PIC)\n    {\n        ps_dpb_info[i].u1_used_as_ref = IS_SHORT_TERM;\n        ps_dpb_info[i].s_top_field.u1_reference_info = IS_SHORT_TERM;\n        ps_dpb_info[i].s_bot_field.u1_reference_info = IS_SHORT_TERM;\n    }\n\n    if((u1_picture_type & 0x03) == TOP_FLD)\n        ps_dpb_info[i].s_top_field.u1_reference_info = IS_SHORT_TERM;\n\n    if((u1_picture_type & 0x03) == BOT_FLD)\n        ps_dpb_info[i].s_bot_field.u1_reference_info = IS_SHORT_TERM;\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_delete_st_node_or_make_lt \\endif\n *\n * \\brief\n *    Delete short term ref with a given picNum from the ST linked list or\n *     make it an LT node\n *\n * \\return\n *    0 - if successful; -1 - otherwise\n *\n * \\note\n *    Common parts to MMCO==1 and MMCO==3 have been combined here\n **************************************************************************\n */\nWORD32 ih264d_delete_st_node_or_make_lt(dpb_manager_t *ps_dpb_mgr,\n                                      WORD32 i4_pic_num,\n                                      UWORD32 u4_lt_idx,\n                                      UWORD8 u1_fld_pic_flag)\n{\n    WORD32 i;\n    struct dpb_info_t *ps_next_dpb;\n    WORD32 i4_frame_num = i4_pic_num;\n    struct dpb_info_t *ps_unmark_node = NULL;\n    UWORD8 u1_del_node = 0, u1_del_st = 0;\n    UWORD8 u1_reference_type = UNUSED_FOR_REF;\n    WORD32 ret;\n\n    if(u1_fld_pic_flag)\n    {\n        i4_frame_num = i4_frame_num >> 1;\n\n        if(u4_lt_idx == (MAX_REF_BUFS + 1))\n            u1_reference_type = UNUSED_FOR_REF;\n        else\n            u1_reference_type = IS_LONG_TERM;\n    }\n\n    //Find the node with matching picNum\n    ps_next_dpb = ps_dpb_mgr->ps_dpb_st_head;\n    if((WORD32)ps_next_dpb->i4_frame_num == i4_frame_num)\n    {\n        ps_unmark_node = ps_next_dpb;\n    }\n    else\n    {\n        for(i = 1; i < ps_dpb_mgr->u1_num_st_ref_bufs; i++)\n        {\n            if((WORD32)ps_next_dpb->ps_prev_short->i4_frame_num == i4_frame_num)\n                break;\n            ps_next_dpb = ps_next_dpb->ps_prev_short;\n        }\n\n        if(i == ps_dpb_mgr->u1_num_st_ref_bufs)\n        {\n            if(ps_dpb_mgr->u1_num_gaps)\n            {\n                ret = ih264d_delete_gap_frm_mmco(ps_dpb_mgr, i4_frame_num, &u1_del_st);\n                if(ret != OK)\n                    return ret;\n            }\n            else\n            {\n                UWORD32 i4_error_code;\n                i4_error_code = ERROR_DBP_MANAGER_T;\n\n                return i4_error_code;\n            }\n\n            if(u1_del_st)\n            {\n                UWORD32 i4_error_code;\n                i4_error_code = ERROR_DBP_MANAGER_T;\n                return i4_error_code;\n            }\n            else\n            {\n                return 0;\n            }\n        }\n        else\n            ps_unmark_node = ps_next_dpb->ps_prev_short;\n    }\n\n    if(u1_fld_pic_flag)\n    {\n        /* Mark the corresponding field ( top or bot) as  */\n        /* UNUSED_FOR_REF or IS_LONG_TERM depending on    */\n        /* u1_reference_type.                             */\n        if(ps_unmark_node->s_top_field.i4_pic_num == i4_pic_num)\n        {\n            ps_unmark_node->s_top_field.u1_reference_info = u1_reference_type;\n            ps_unmark_node->s_top_field.u1_long_term_frame_idx = u4_lt_idx;\n            {\n                UWORD8 *pu1_src = ps_unmark_node->ps_pic_buf->pu1_col_zero_flag;\n                WORD32 i4_size = ((ps_dpb_mgr->u2_pic_wd\n                                * ps_dpb_mgr->u2_pic_ht) >> 5);\n                /* memset the colocated zero u4_flag buffer */\n                memset(pu1_src, 0, i4_size);\n            }\n        }\n\n        else if(ps_unmark_node->s_bot_field.i4_pic_num == i4_pic_num)\n        {\n\n            ps_unmark_node->s_bot_field.u1_reference_info = u1_reference_type;\n            ps_unmark_node->s_bot_field.u1_long_term_frame_idx = u4_lt_idx;\n            {\n                UWORD8 *pu1_src =\n                                ps_unmark_node->ps_pic_buf->pu1_col_zero_flag\n                                                + ((ps_dpb_mgr->u2_pic_wd\n                                                                * ps_dpb_mgr->u2_pic_ht)\n                                                                >> 5);\n                WORD32 i4_size = ((ps_dpb_mgr->u2_pic_wd\n                                * ps_dpb_mgr->u2_pic_ht) >> 5);\n                /* memset the colocated zero u4_flag buffer */\n                memset(pu1_src, 0, i4_size);\n            }\n        }\n        ps_unmark_node->u1_used_as_ref =\n                        ps_unmark_node->s_top_field.u1_reference_info\n                                        | ps_unmark_node->s_bot_field.u1_reference_info;\n    }\n    else\n    {\n        ps_unmark_node->u1_used_as_ref = UNUSED_FOR_REF;\n        ps_unmark_node->s_top_field.u1_reference_info = UNUSED_FOR_REF;\n        ps_unmark_node->s_bot_field.u1_reference_info = UNUSED_FOR_REF;\n\n        {\n            UWORD8 *pu1_src = ps_unmark_node->ps_pic_buf->pu1_col_zero_flag;\n\n            WORD32 i4_size = ((ps_dpb_mgr->u2_pic_wd\n                            * ps_dpb_mgr->u2_pic_ht) >> 4);\n            /* memset the colocated zero u4_flag buffer */\n            memset(pu1_src, 0, i4_size);\n        }\n    }\n\n    if(!(ps_unmark_node->u1_used_as_ref & IS_SHORT_TERM))\n    {\n        if(ps_unmark_node == ps_dpb_mgr->ps_dpb_st_head)\n            ps_dpb_mgr->ps_dpb_st_head = ps_next_dpb->ps_prev_short;\n        else\n            ps_next_dpb->ps_prev_short = ps_unmark_node->ps_prev_short; //update link\n        ps_dpb_mgr->u1_num_st_ref_bufs--; //decrement ST buf count\n        u1_del_node = 1;\n    }\n\n    if(u4_lt_idx == MAX_REF_BUFS + 1)\n    {\n        if(u1_del_node)\n        {\n            // Release the physical buffer\n            ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                        ps_unmark_node->u1_buf_id);\n            ps_unmark_node->ps_prev_short = NULL;\n        }\n    }\n    else\n    {\n        WORD32 i4_status;\n        //If another node has the same LT index, delete that node\n        ret = ih264d_delete_lt_node(ps_dpb_mgr, u4_lt_idx,\n                              u1_fld_pic_flag, ps_unmark_node, &i4_status);\n        if(ret != OK)\n            return ret;\n        // Now insert the short term node as a long term node\n        ret = ih264d_insert_lt_node(ps_dpb_mgr, ps_unmark_node, u4_lt_idx,\n                              u1_fld_pic_flag);\n        if(ret != OK)\n            return ret;\n    }\n    return OK;\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_reset_ref_bufs \\endif\n *\n * \\brief\n *    Called if MMCO==5/7 or on the first slice of an IDR picture\n *\n * \\return\n *    none\n **************************************************************************\n */\nvoid ih264d_reset_ref_bufs(dpb_manager_t *ps_dpb_mgr)\n{\n    WORD32 i;\n    struct dpb_info_t *ps_dpb_info = ps_dpb_mgr->as_dpb_info;\n\n    for(i = 0; i < MAX_REF_BUFS; i++)\n    {\n        if(ps_dpb_info[i].u1_used_as_ref)\n        {\n            ps_dpb_info[i].u1_used_as_ref = UNUSED_FOR_REF;\n            ps_dpb_info[i].u1_lt_idx = MAX_REF_BUFS + 1;\n            ps_dpb_info[i].ps_prev_short = NULL;\n            ps_dpb_info[i].ps_prev_long = NULL;\n            ps_dpb_info[i].ps_pic_buf = NULL;\n            ps_dpb_info[i].s_top_field.u1_reference_info = UNUSED_FOR_REF;\n            ps_dpb_info[i].s_bot_field.u1_reference_info = UNUSED_FOR_REF;\n            ps_dpb_info[i].s_top_field.u1_long_term_frame_idx = MAX_REF_BUFS + 1;\n            ps_dpb_info[i].s_bot_field.u1_long_term_frame_idx = MAX_REF_BUFS + 1;\n\n            //Release physical buffer\n            ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                        ps_dpb_info[i].u1_buf_id);\n        }\n    }\n    ps_dpb_mgr->u1_num_st_ref_bufs = ps_dpb_mgr->u1_num_lt_ref_bufs = 0;\n    ps_dpb_mgr->ps_dpb_st_head = NULL;\n    ps_dpb_mgr->ps_dpb_ht_head = NULL;\n    ps_dpb_mgr->u1_mmco_error_in_seq = 0;\n\n    /* release all gaps */\n    ps_dpb_mgr->u1_num_gaps = 0;\n    for(i = 0; i < MAX_FRAMES; i++)\n    {\n        ps_dpb_mgr->ai4_gaps_start_frm_num[i] = INVALID_FRAME_NUM;\n        ps_dpb_mgr->ai4_gaps_end_frm_num[i] = 0;\n        ps_dpb_mgr->ai1_gaps_per_seq[i] = 0;\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : Name \\endif\n *\n * \\brief\n *     create the default index list after an MMCO\n *\n * \\return\n *    0 - if no_error; -1 - error\n *\n **************************************************************************\n */\nWORD32 ih264d_update_default_index_list(dpb_manager_t *ps_dpb_mgr)\n{\n    WORD32 i;\n    struct dpb_info_t *ps_next_dpb = ps_dpb_mgr->ps_dpb_st_head;\n\n    for(i = 0; i < ps_dpb_mgr->u1_num_st_ref_bufs; i++)\n    {\n        ps_dpb_mgr->ps_def_dpb[i] = ps_next_dpb->ps_pic_buf;\n        ps_next_dpb = ps_next_dpb->ps_prev_short;\n    }\n\n    ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;\n    for(;i< ps_dpb_mgr->u1_num_st_ref_bufs + ps_dpb_mgr->u1_num_lt_ref_bufs; i++)\n    {\n        ps_dpb_mgr->ps_def_dpb[i] = ps_next_dpb->ps_pic_buf;\n        ps_next_dpb = ps_next_dpb->ps_prev_long;\n    }\n    return 0;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ref_idx_reordering \\endif\n *\n * \\brief\n *     Parse the bitstream and reorder indices for the current slice\n *\n * \\return\n *    0 - if no_error; -1 - error\n *\n * \\note\n *    Called only if ref_idx_reordering_flag_l0 is decoded as 1\n *    Remove error checking for unmatching picNum or LTIndex later (if not needed)\n * \\para\n *    This section implements 7.3.3.1 and 8.2.6.4\n *    Uses the default index list as the starting point and\n *    remaps the picNums sent to the next higher index in the\n *    modified list. The unmodified ones are copied from the\n *    default to modified list retaining their order in the default list.\n *\n **************************************************************************\n */\nWORD32 ih264d_ref_idx_reordering(dec_struct_t *ps_dec, UWORD8 uc_lx)\n{\n    dpb_manager_t *ps_dpb_mgr = ps_dec->ps_dpb_mgr;\n    UWORD16 u4_cur_pic_num = ps_dec->ps_cur_slice->u2_frame_num;\n    /*< Maximum Picture Number Minus 1 */\n    UWORD16 ui_max_frame_num =\n                    ps_dec->ps_cur_sps->u2_u4_max_pic_num_minus1 + 1;\n\n    WORD32 i, count = 0;\n    UWORD32 ui_remapIdc, ui_nextUev;\n    WORD16 u2_pred_frame_num = u4_cur_pic_num;\n    WORD32 i_temp;\n    UWORD16 u2_def_mod_flag = 0; /* Flag to keep track of which indices have been remapped */\n    UWORD8 modCount = 0;\n    UWORD32 *pu4_bitstrm_buf = ps_dec->ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_dec->ps_bitstrm->u4_ofst;\n    dec_slice_params_t *ps_cur_slice = ps_dec->ps_cur_slice;\n    UWORD8 u1_field_pic_flag = ps_cur_slice->u1_field_pic_flag;\n\n    if(u1_field_pic_flag)\n    {\n        u4_cur_pic_num = u4_cur_pic_num * 2 + 1;\n        ui_max_frame_num = ui_max_frame_num * 2;\n    }\n\n    u2_pred_frame_num = u4_cur_pic_num;\n\n    ui_remapIdc = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n\n    while((ui_remapIdc != 3)\n                    && (count < ps_cur_slice->u1_num_ref_idx_lx_active[uc_lx]))\n    {\n        ui_nextUev = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        if(ui_remapIdc != 2)\n        {\n            if(ui_nextUev > ui_max_frame_num)\n                return ERROR_DBP_MANAGER_T;\n\n            ui_nextUev = ui_nextUev + 1;\n\n            if(ui_remapIdc == 0)\n            {\n                // diffPicNum is -ve\n                i_temp = (WORD32)u2_pred_frame_num - (WORD32)ui_nextUev;\n                if(i_temp < 0)\n                    i_temp += ui_max_frame_num;\n            }\n            else\n            {\n                // diffPicNum is +ve\n                i_temp = (WORD32)u2_pred_frame_num + (WORD32)ui_nextUev;\n                if(i_temp >= ui_max_frame_num)\n                    i_temp -= ui_max_frame_num;\n            }\n            /* Find the dpb with the matching picNum (picNum==frameNum for framePic) */\n\n            if(i_temp > u4_cur_pic_num)\n                i_temp = i_temp - ui_max_frame_num;\n\n            for(i = 0; i < (ps_cur_slice->u1_initial_list_size[uc_lx]); i++)\n            {\n                if(ps_dpb_mgr->ps_init_dpb[uc_lx][i]->i4_pic_num == i_temp)\n                    break;\n            }\n            if(i == (ps_cur_slice->u1_initial_list_size[uc_lx]))\n            {\n                UWORD32 i4_error_code;\n                i4_error_code = ERROR_DBP_MANAGER_T;\n                return i4_error_code;\n            }\n\n            u2_def_mod_flag |= (1 << i);\n            ps_dpb_mgr->ps_mod_dpb[uc_lx][modCount++] =\n                            ps_dpb_mgr->ps_init_dpb[uc_lx][i];\n            u2_pred_frame_num = i_temp; //update predictor to be the picNum just obtained\n        }\n        else //2\n        {\n            UWORD8 u1_lt_idx;\n\n            if(ui_nextUev > (MAX_REF_BUFS + 1))\n                return ERROR_DBP_MANAGER_T;\n\n            u1_lt_idx = (UWORD8)ui_nextUev;\n\n            for(i = 0; i < (ps_cur_slice->u1_initial_list_size[uc_lx]); i++)\n            {\n                if(!ps_dpb_mgr->ps_init_dpb[uc_lx][i]->u1_is_short)\n                {\n                    if(ps_dpb_mgr->ps_init_dpb[uc_lx][i]->u1_long_term_pic_num\n                                    == u1_lt_idx)\n                        break;\n                }\n            }\n            if(i == (ps_cur_slice->u1_initial_list_size[uc_lx]))\n            {\n                UWORD32 i4_error_code;\n                i4_error_code = ERROR_DBP_MANAGER_T;\n                return i4_error_code;\n            }\n\n            u2_def_mod_flag |= (1 << i);\n            ps_dpb_mgr->ps_mod_dpb[uc_lx][modCount++] =\n                            ps_dpb_mgr->ps_init_dpb[uc_lx][i];\n        }\n\n        ui_remapIdc = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        /* Get the remapping_idc - 0/1/2/3 */\n        count++;\n    }\n\n    //Handle the ref indices that were not remapped\n    for(i = 0; i < (ps_cur_slice->u1_num_ref_idx_lx_active[uc_lx]); i++)\n    {\n        if(!(u2_def_mod_flag & (1 << i)))\n            ps_dpb_mgr->ps_mod_dpb[uc_lx][modCount++] =\n                            ps_dpb_mgr->ps_init_dpb[uc_lx][i];\n    }\n    return OK;\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_read_mmco_commands \\endif\n *\n * \\brief\n *    Parses MMCO commands and stores them in a structure for later use.\n *\n * \\return\n *    0 - No error; -1 - Error\n *\n * \\note\n *    This function stores MMCO commands in structure only for the first time.\n *    In case of MMCO commands being issued for same Picture Number, they are\n *    just parsed and not stored them in the structure.\n *\n **************************************************************************\n */\nWORD32 ih264d_read_mmco_commands(struct _DecStruct * ps_dec)\n{\n    dec_pic_params_t *ps_pps = ps_dec->ps_cur_pps;\n    dec_seq_params_t *ps_sps = ps_pps->ps_sps;\n    dec_bit_stream_t *ps_bitstrm = ps_dec->ps_bitstrm;\n    dpb_commands_t *ps_dpb_cmds = &(ps_dec->s_dpb_cmds_scratch);\n    dec_slice_params_t * ps_slice = ps_dec->ps_cur_slice;\n    WORD32 j;\n    UWORD8 u1_buf_mode;\n    struct MMCParams *ps_mmc_params;\n    UWORD32 *pu4_bitstrm_buf = ps_dec->ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD32 u4_bit_ofst = ps_dec->ps_bitstrm->u4_ofst;\n\n    ps_slice->u1_mmco_equalto5 = 0;\n    {\n        if(ps_dec->u1_nal_unit_type == IDR_SLICE_NAL)\n        {\n            ps_slice->u1_no_output_of_prior_pics_flag =\n                            ih264d_get_bit_h264(ps_bitstrm);\n            COPYTHECONTEXT(\"SH: no_output_of_prior_pics_flag\",\n                            ps_slice->u1_no_output_of_prior_pics_flag);\n            ps_slice->u1_long_term_reference_flag = ih264d_get_bit_h264(\n                            ps_bitstrm);\n            COPYTHECONTEXT(\"SH: long_term_reference_flag\",\n                            ps_slice->u1_long_term_reference_flag);\n            ps_dpb_cmds->u1_idr_pic = 1;\n            ps_dpb_cmds->u1_no_output_of_prior_pics_flag =\n                            ps_slice->u1_no_output_of_prior_pics_flag;\n            ps_dpb_cmds->u1_long_term_reference_flag =\n                            ps_slice->u1_long_term_reference_flag;\n        }\n        else\n        {\n            u1_buf_mode = ih264d_get_bit_h264(ps_bitstrm); //0 - sliding window; 1 - arbitrary\n            COPYTHECONTEXT(\"SH: adaptive_ref_pic_buffering_flag\", u1_buf_mode);\n            ps_dpb_cmds->u1_buf_mode = u1_buf_mode;\n            j = 0;\n\n            if(u1_buf_mode == 1)\n            {\n                UWORD32 u4_mmco;\n                UWORD32 u4_diff_pic_num;\n                UWORD32 u4_lt_idx, u4_max_lt_idx_plus1;\n\n                u4_mmco = ih264d_uev(pu4_bitstrm_ofst,\n                                     pu4_bitstrm_buf);\n                while(u4_mmco != END_OF_MMCO)\n                {\n                    if (j >= MAX_REF_BUFS)\n                    {\n#ifdef __ANDROID__\n                        ALOGE(\"b/25818142\");\n                        android_errorWriteLog(0x534e4554, \"25818142\");\n#endif\n                        ps_dpb_cmds->u1_num_of_commands = 0;\n                        return -1;\n                    }\n                    ps_mmc_params = &ps_dpb_cmds->as_mmc_params[j];\n                    ps_mmc_params->u4_mmco = u4_mmco;\n                    switch(u4_mmco)\n                    {\n                        case MARK_ST_PICNUM_AS_NONREF:\n                            u4_diff_pic_num = ih264d_uev(pu4_bitstrm_ofst,\n                                                         pu4_bitstrm_buf);\n                            //Get absDiffPicnumMinus1\n                            ps_mmc_params->u4_diff_pic_num = u4_diff_pic_num;\n                            break;\n\n                        case MARK_LT_INDEX_AS_NONREF:\n                            u4_lt_idx = ih264d_uev(pu4_bitstrm_ofst,\n                                                   pu4_bitstrm_buf);\n                            ps_mmc_params->u4_lt_idx = u4_lt_idx;\n                            break;\n\n                        case MARK_ST_PICNUM_AS_LT_INDEX:\n                            u4_diff_pic_num = ih264d_uev(pu4_bitstrm_ofst,\n                                                         pu4_bitstrm_buf);\n                            ps_mmc_params->u4_diff_pic_num = u4_diff_pic_num;\n                            u4_lt_idx = ih264d_uev(pu4_bitstrm_ofst,\n                                                   pu4_bitstrm_buf);\n                            ps_mmc_params->u4_lt_idx = u4_lt_idx;\n                            break;\n\n                        case SET_MAX_LT_INDEX:\n                        {\n                            u4_max_lt_idx_plus1 = ih264d_uev(pu4_bitstrm_ofst,\n                                                             pu4_bitstrm_buf);\n                            if (u4_max_lt_idx_plus1 > ps_sps->u1_num_ref_frames)\n                            {\n                                /* Invalid max LT ref index */\n                                return -1;\n                            }\n                            ps_mmc_params->u4_max_lt_idx_plus1 = u4_max_lt_idx_plus1;\n                            break;\n                        }\n                        case RESET_REF_PICTURES:\n                        {\n                            ps_slice->u1_mmco_equalto5 = 1;\n                            break;\n                        }\n\n                        case SET_LT_INDEX:\n                            u4_lt_idx = ih264d_uev(pu4_bitstrm_ofst,\n                                                   pu4_bitstrm_buf);\n                            ps_mmc_params->u4_lt_idx = u4_lt_idx;\n                            break;\n\n                        default:\n                            break;\n                    }\n                    u4_mmco = ih264d_uev(pu4_bitstrm_ofst,\n                                         pu4_bitstrm_buf);\n\n                    j++;\n                }\n                ps_dpb_cmds->u1_num_of_commands = j;\n            }\n        }\n        ps_dpb_cmds->u1_dpb_commands_read = 1;\n        ps_dpb_cmds->u1_dpb_commands_read_slc = 1;\n\n    }\n    u4_bit_ofst = ps_dec->ps_bitstrm->u4_ofst - u4_bit_ofst;\n    return u4_bit_ofst;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_do_mmco_buffer \\endif\n *\n * \\brief\n *    Perform decoded picture buffer memory management control operations\n *\n * \\return\n *    0 - No error; -1 - Error\n *\n * \\note\n *    Bitstream is also parsed here to get the MMCOs\n *\n **************************************************************************\n */\nWORD32 ih264d_do_mmco_buffer(dpb_commands_t *ps_dpb_cmds,\n                          dpb_manager_t *ps_dpb_mgr,\n                          UWORD8 u1_numRef_frames_for_seq, /*!< num_ref_frames from active SeqParSet*/\n                          UWORD32 u4_cur_pic_num,\n                          UWORD32 u2_u4_max_pic_num_minus1,\n                          UWORD8 u1_nal_unit_type,\n                          struct pic_buffer_t *ps_pic_buf,\n                          UWORD8 u1_buf_id,\n                          UWORD8 u1_fld_pic_flag,\n                          UWORD8 u1_curr_pic_in_err)\n{\n    WORD32 i;\n    UWORD8 u1_buf_mode, u1_marked_lt;\n    struct dpb_info_t *ps_next_dpb;\n    UWORD8 u1_num_gaps;\n    UWORD8 u1_del_node = 1;\n    UWORD8 u1_insert_st_pic = 1;\n    WORD32 ret;\n    UNUSED(u1_nal_unit_type);\n    UNUSED(u2_u4_max_pic_num_minus1);\n    u1_buf_mode = ps_dpb_cmds->u1_buf_mode; //0 - sliding window; 1 - Adaptive\n    u1_marked_lt = 0;\n    u1_num_gaps = ps_dpb_mgr->u1_num_gaps;\n\n    if(!u1_buf_mode)\n    {\n        //Sliding window - implements 8.2.5.3\n        if((ps_dpb_mgr->u1_num_st_ref_bufs\n                        + ps_dpb_mgr->u1_num_lt_ref_bufs + u1_num_gaps)\n                        == u1_numRef_frames_for_seq)\n        {\n            UWORD8 u1_new_node_flag = 1;\n            if((0 == ps_dpb_mgr->u1_num_st_ref_bufs) && (0 == u1_num_gaps))\n            {\n                UWORD32 i4_error_code;\n                i4_error_code = ERROR_DBP_MANAGER_T;\n                return i4_error_code;\n            }\n\n            // Chase the links to reach the last but one picNum, if available\n            ps_next_dpb = ps_dpb_mgr->ps_dpb_st_head;\n\n            if(ps_dpb_mgr->u1_num_st_ref_bufs > 1)\n            {\n                if(ps_next_dpb->i4_frame_num == (WORD32)u4_cur_pic_num)\n                {\n                    /* Incase of  filed pictures top_field has been allocated   */\n                    /* picture buffer and complementary bottom field pair comes */\n                    /* then the sliding window mechanism should not allocate a  */\n                    /* new node                                                 */\n                    u1_new_node_flag = 0;\n                }\n\n                for(i = 1; i < (ps_dpb_mgr->u1_num_st_ref_bufs - 1); i++)\n                {\n                    if(ps_next_dpb == NULL)\n                    {\n                        UWORD32 i4_error_code;\n                        i4_error_code = ERROR_DBP_MANAGER_T;\n                        return i4_error_code;\n                    }\n                    if(ps_next_dpb->i4_frame_num == (WORD32)u4_cur_pic_num)\n                    {\n                        /* Incase of  field pictures top_field has been allocated   */\n                        /* picture buffer and complementary bottom field pair comes */\n                        /* then the sliding window mechanism should not allocate a  */\n                        /* new node                                                 */\n                        u1_new_node_flag = 0;\n                    }\n                    ps_next_dpb = ps_next_dpb->ps_prev_short;\n                }\n\n                if(ps_next_dpb->ps_prev_short->ps_prev_short != NULL)\n                {\n                    UWORD32 i4_error_code;\n                    i4_error_code = ERROR_DBP_MANAGER_T;\n                    return i4_error_code;\n                }\n\n                if(u1_new_node_flag)\n                {\n                    if(u1_num_gaps)\n                    {\n                        ret = ih264d_delete_gap_frm_sliding(ps_dpb_mgr,\n                                                            ps_next_dpb->ps_prev_short->i4_frame_num,\n                                                            &u1_del_node);\n                        if(ret != OK)\n                            return ret;\n                    }\n\n                    if(u1_del_node)\n                    {\n                        ps_dpb_mgr->u1_num_st_ref_bufs--;\n                        ps_next_dpb->ps_prev_short->u1_used_as_ref =\n                                        UNUSED_FOR_REF;\n                        ps_next_dpb->ps_prev_short->s_top_field.u1_reference_info =\n                                        UNUSED_FOR_REF;\n                        ps_next_dpb->ps_prev_short->s_bot_field.u1_reference_info =\n                                        UNUSED_FOR_REF;\n                        ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                                    ps_next_dpb->ps_prev_short->u1_buf_id);\n                        ps_next_dpb->ps_prev_short->ps_pic_buf = NULL;\n                        ps_next_dpb->ps_prev_short = NULL;\n                    }\n                }\n            }\n            else\n            {\n                if(ps_dpb_mgr->u1_num_st_ref_bufs)\n                {\n                    ret = ih264d_delete_gap_frm_sliding(ps_dpb_mgr,\n                                                       ps_next_dpb->i4_frame_num,\n                                                       &u1_del_node);\n                    if(ret != OK)\n                        return ret;\n                    if((ps_next_dpb->i4_frame_num != (WORD32)u4_cur_pic_num)\n                                    && u1_del_node)\n                    {\n                        ps_dpb_mgr->u1_num_st_ref_bufs--;\n                        ps_next_dpb->u1_used_as_ref = FALSE;\n                        ps_next_dpb->s_top_field.u1_reference_info =\n                                        UNUSED_FOR_REF;\n                        ps_next_dpb->s_bot_field.u1_reference_info =\n                                        UNUSED_FOR_REF;\n                        ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                                    ps_next_dpb->u1_buf_id);\n                        ps_next_dpb->ps_pic_buf = NULL;\n                        ps_next_dpb->ps_prev_short = NULL;\n                        ps_dpb_mgr->ps_dpb_st_head = NULL;\n                        ps_next_dpb = NULL;\n                    }\n                    else if(ps_next_dpb->i4_frame_num == (WORD32)u4_cur_pic_num)\n                    {\n                        if(u1_curr_pic_in_err)\n                        {\n                            u1_insert_st_pic = 0;\n                        }\n                        else if(ps_dpb_mgr->u1_num_st_ref_bufs > 0)\n                        {\n                            ps_dpb_mgr->u1_num_st_ref_bufs--;\n                            ps_next_dpb->u1_used_as_ref = FALSE;\n                            ps_next_dpb->s_top_field.u1_reference_info =\n                                            UNUSED_FOR_REF;\n                            ps_next_dpb->s_bot_field.u1_reference_info =\n                                            UNUSED_FOR_REF;\n                            ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                                        ps_next_dpb->u1_buf_id);\n                            ps_next_dpb->ps_pic_buf = NULL;\n                            ps_next_dpb = NULL;\n                        }\n                    }\n                }\n                else\n                {\n                    ret = ih264d_delete_gap_frm_sliding(ps_dpb_mgr,\n                                                        INVALID_FRAME_NUM,\n                                                        &u1_del_node);\n                    if(ret != OK)\n                        return ret;\n                    if(u1_del_node)\n                    {\n                        UWORD32 i4_error_code;\n                        i4_error_code = ERROR_DBP_MANAGER_T;\n                        return i4_error_code;\n                    }\n                }\n            }\n        }\n    }\n    else\n    {\n        //Adaptive memory control - implements 8.2.5.4\n        UWORD32 u4_mmco;\n        UWORD32 u4_diff_pic_num;\n        WORD32 i4_pic_num;\n        UWORD32 u4_lt_idx;\n        WORD32 j;\n        struct MMCParams *ps_mmc_params;\n\n        for(j = 0; j < ps_dpb_cmds->u1_num_of_commands; j++)\n        {\n            ps_mmc_params = &ps_dpb_cmds->as_mmc_params[j];\n            u4_mmco = ps_mmc_params->u4_mmco; //Get MMCO\n\n            switch(u4_mmco)\n            {\n                case MARK_ST_PICNUM_AS_NONREF:\n                {\n\n                    {\n                        UWORD32 i4_cur_pic_num = u4_cur_pic_num;\n                        WORD64 i8_pic_num;\n                        u4_diff_pic_num = ps_mmc_params->u4_diff_pic_num; //Get absDiffPicnumMinus1\n                        if(u1_fld_pic_flag)\n                            i4_cur_pic_num = i4_cur_pic_num * 2 + 1;\n                        i8_pic_num = ((WORD64)i4_cur_pic_num - ((WORD64)u4_diff_pic_num + 1));\n                        if(IS_OUT_OF_RANGE_S32(i8_pic_num))\n                        {\n                            return ERROR_DBP_MANAGER_T;\n                        }\n                        i4_pic_num = i8_pic_num;\n                    }\n\n                    if(ps_dpb_mgr->u1_num_st_ref_bufs > 0)\n                    {\n                        ret = ih264d_delete_st_node_or_make_lt(ps_dpb_mgr,\n                                                               i4_pic_num,\n                                                               MAX_REF_BUFS + 1,\n                                                               u1_fld_pic_flag);\n                        if(ret != OK)\n                            return ret;\n                    }\n                    else\n                    {\n                        UWORD8 u1_dummy;\n                        ret = ih264d_delete_gap_frm_mmco(ps_dpb_mgr, i4_pic_num, &u1_dummy);\n                        if(ret != OK)\n                            return ret;\n                    }\n                    break;\n                }\n                case MARK_LT_INDEX_AS_NONREF:\n                {\n                    WORD32 i4_status;\n                    u4_lt_idx = ps_mmc_params->u4_lt_idx; //Get long term index\n                    ret = ih264d_delete_lt_node(ps_dpb_mgr,\n                                                u4_lt_idx,\n                                                u1_fld_pic_flag,\n                                                0, &i4_status);\n                    if(ret != OK)\n                        return ret;\n                    if(i4_status)\n                    {\n                        UWORD32 i4_error_code;\n                        i4_error_code = ERROR_DBP_MANAGER_T;\n                        return i4_error_code;\n                    }\n                    break;\n                }\n\n                case MARK_ST_PICNUM_AS_LT_INDEX:\n                {\n                    {\n                        UWORD32 i4_cur_pic_num = u4_cur_pic_num;\n                        WORD64 i8_pic_num;\n                        u4_diff_pic_num = ps_mmc_params->u4_diff_pic_num; //Get absDiffPicnumMinus1\n                        if(u1_fld_pic_flag)\n                            i4_cur_pic_num = i4_cur_pic_num * 2 + 1;\n\n                        i8_pic_num = (WORD64)i4_cur_pic_num - ((WORD64)u4_diff_pic_num + 1);\n                        if(IS_OUT_OF_RANGE_S32(i8_pic_num))\n                        {\n                            return ERROR_DBP_MANAGER_T;\n                        }\n                        i4_pic_num = i8_pic_num;\n                    }\n\n                    u4_lt_idx = ps_mmc_params->u4_lt_idx; //Get long term index\n\n                    if((ps_dpb_mgr->u1_max_lt_frame_idx == NO_LONG_TERM_INDICIES) ||\n                        (u4_lt_idx > ps_dpb_mgr->u1_max_lt_frame_idx))\n                    {\n                        return ERROR_DBP_MANAGER_T;\n                    }\n\n                    if(ps_dpb_mgr->u1_num_st_ref_bufs > 0)\n                    {\n                        ret = ih264d_delete_st_node_or_make_lt(ps_dpb_mgr,\n                                                               i4_pic_num, u4_lt_idx,\n                                                               u1_fld_pic_flag);\n                        if(ret != OK)\n                            return ret;\n                    }\n                    break;\n                }\n                case SET_MAX_LT_INDEX:\n                {\n                    UWORD8 uc_numLT = ps_dpb_mgr->u1_num_lt_ref_bufs;\n                    u4_lt_idx = ps_mmc_params->u4_max_lt_idx_plus1; //Get Max_long_term_index_plus1\n                    if(u4_lt_idx <= ps_dpb_mgr->u1_max_lt_frame_idx\n                                    && uc_numLT > 0)\n                    {\n                        struct dpb_info_t *ps_nxtDPB;\n                        //Set all LT buffers with index >= u4_lt_idx to nonreference\n                        ps_nxtDPB = ps_dpb_mgr->ps_dpb_ht_head;\n                        ps_next_dpb = ps_nxtDPB->ps_prev_long;\n                        if(ps_nxtDPB->u1_lt_idx >= u4_lt_idx)\n                        {\n                            i = 0;\n                            ps_dpb_mgr->ps_dpb_ht_head = NULL;\n                        }\n                        else\n                        {\n                            for(i = 1; i < uc_numLT; i++)\n                            {\n                                if(ps_next_dpb->u1_lt_idx >= u4_lt_idx)\n                                    break;\n                                ps_nxtDPB = ps_next_dpb;\n                                ps_next_dpb = ps_next_dpb->ps_prev_long;\n                            }\n                            ps_nxtDPB->ps_prev_long = NULL; //Terminate the link of the closest LTIndex that is <=Max\n                        }\n                        ps_dpb_mgr->u1_num_lt_ref_bufs = i;\n                        if(i == 0)\n                            ps_next_dpb = ps_nxtDPB;\n\n                        for(; i < uc_numLT; i++)\n                        {\n                            ps_nxtDPB = ps_next_dpb;\n                            ps_nxtDPB->u1_lt_idx = MAX_REF_BUFS + 1;\n                            ps_nxtDPB->u1_used_as_ref = UNUSED_FOR_REF;\n                            ps_nxtDPB->s_top_field.u1_reference_info =\n                                            UNUSED_FOR_REF;\n                            ps_nxtDPB->s_bot_field.u1_reference_info =\n                                            UNUSED_FOR_REF;\n\n                            ps_nxtDPB->ps_pic_buf = NULL;\n                            //Release buffer\n                            ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                                        ps_nxtDPB->u1_buf_id);\n                            ps_next_dpb = ps_nxtDPB->ps_prev_long;\n                            ps_nxtDPB->ps_prev_long = NULL;\n                        }\n                    }\n                    if(u4_lt_idx == 0)\n                    {\n                        ps_dpb_mgr->u1_max_lt_frame_idx = NO_LONG_TERM_INDICIES;\n                    }\n                    else\n                    {\n                        ps_dpb_mgr->u1_max_lt_frame_idx = u4_lt_idx - 1;\n                    }\n\n                    break;\n                }\n                case SET_LT_INDEX:\n                {\n                    u4_lt_idx = ps_mmc_params->u4_lt_idx; //Get long term index\n                    if((ps_dpb_mgr->u1_max_lt_frame_idx == NO_LONG_TERM_INDICIES) ||\n                        (u4_lt_idx > ps_dpb_mgr->u1_max_lt_frame_idx))\n                    {\n                        return ERROR_DBP_MANAGER_T;\n                    }\n                    ret = ih264d_insert_st_node(ps_dpb_mgr, ps_pic_buf, u1_buf_id,\n                                          u4_cur_pic_num);\n                    if(ret != OK)\n                        return ret;\n\n                    if(ps_dpb_mgr->u1_num_st_ref_bufs > 0)\n\n                    {\n                        ret = ih264d_delete_st_node_or_make_lt(ps_dpb_mgr,\n                                                               u4_cur_pic_num,\n                                                               u4_lt_idx,\n                                                               u1_fld_pic_flag);\n                        if(ret != OK)\n                            return ret;\n                    }\n                    else\n                    {\n                        return ERROR_DBP_MANAGER_T;\n                    }\n\n                    u1_marked_lt = 1;\n                    break;\n                }\n\n                default:\n                    break;\n            }\n            if(u4_mmco == RESET_REF_PICTURES || u4_mmco == RESET_ALL_PICTURES)\n            {\n                ih264d_reset_ref_bufs(ps_dpb_mgr);\n                u4_cur_pic_num = 0;\n            }\n        }\n    }\n    if(!u1_marked_lt && u1_insert_st_pic)\n    {\n        ret = ih264d_insert_st_node(ps_dpb_mgr, ps_pic_buf, u1_buf_id,\n                              u4_cur_pic_num);\n        if(ret != OK)\n            return ret;\n    }\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_release_pics_in_dpb                                         */\n/*                                                                           */\n/*  Description   : This function deletes all pictures from DPB              */\n/*                                                                           */\n/*  Inputs        : h_pic_buf_api: pointer to picture buffer API               */\n/*                  u1_disp_bufs: number pictures ready for display           */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 06 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_release_pics_in_dpb(void *pv_dec,\n                                UWORD8 u1_disp_bufs)\n{\n    WORD8 i;\n    dec_struct_t *ps_dec = (dec_struct_t *)pv_dec;\n\n    for(i = 0; i < u1_disp_bufs; i++)\n    {\n        ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                              i,\n                              BUF_MGR_REF);\n        ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_mv_buf_mgr,\n                              ps_dec->au1_pic_buf_id_mv_buf_id_map[i],\n                              BUF_MGR_REF);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_delete_gap_frm_sliding                            */\n/*                                                                           */\n/*  Description   : This function deletes a picture from the list of gaps,   */\n/*                  if the frame number of gap frame is lesser than the one  */\n/*                  to be deleted by sliding window                          */\n/*  Inputs        : ps_dpb_mgr: pointer to dpb manager                       */\n/*                  i4_frame_num:  frame number of picture that's going to   */\n/*                  be deleted by sliding window                             */\n/*                  pu1_del_node: holds 0 if a gap is deleted else 1         */\n/*  Globals       : None                                                     */\n/*  Processing    : Function searches for frame number lesser than           */\n/*                  i4_frame_num in the gaps list                            */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 06 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_delete_gap_frm_sliding(dpb_manager_t *ps_dpb_mgr,\n                                    WORD32 i4_frame_num,\n                                    UWORD8 *pu1_del_node)\n{\n    WORD8 i1_gap_idx, i, j, j_min;\n    WORD32 *pi4_gaps_start_frm_num, *pi4_gaps_end_frm_num, i4_gap_frame_num;\n    WORD32 i4_start_frm_num, i4_end_frm_num;\n    WORD32 i4_max_frm_num;\n    WORD32 i4_frm_num, i4_gap_frm_num_min;\n\n    /* find the least frame num from gaps and current DPB node    */\n    /* Delete the least one                                       */\n    *pu1_del_node = 1;\n    if(0 == ps_dpb_mgr->u1_num_gaps)\n        return OK;\n    pi4_gaps_start_frm_num = ps_dpb_mgr->ai4_gaps_start_frm_num;\n    pi4_gaps_end_frm_num = ps_dpb_mgr->ai4_gaps_end_frm_num;\n    i4_gap_frame_num = INVALID_FRAME_NUM;\n    i4_max_frm_num = ps_dpb_mgr->i4_max_frm_num;\n\n    i1_gap_idx = -1;\n    if(INVALID_FRAME_NUM != i4_frame_num)\n    {\n        i4_gap_frame_num = i4_frame_num;\n        for(i = 0; i < MAX_FRAMES; i++)\n        {\n            i4_start_frm_num = pi4_gaps_start_frm_num[i];\n            if(INVALID_FRAME_NUM != i4_start_frm_num)\n            {\n                i4_end_frm_num = pi4_gaps_end_frm_num[i];\n                if(i4_end_frm_num < i4_max_frm_num)\n                {\n                    if(i4_start_frm_num <= i4_gap_frame_num)\n                    {\n                        i4_gap_frame_num = i4_start_frm_num;\n                        i1_gap_idx = i;\n                    }\n                }\n                else\n                {\n                    if(((i4_start_frm_num <= i4_gap_frame_num)\n                                    && (i4_gap_frame_num <= i4_max_frm_num))\n                                    || ((i4_start_frm_num >= i4_gap_frame_num)\n                                                    && ((i4_gap_frame_num\n                                                                    + i4_max_frm_num)\n                                                                    >= i4_end_frm_num)))\n                    {\n                        i4_gap_frame_num = i4_start_frm_num;\n                        i1_gap_idx = i;\n                    }\n                }\n            }\n        }\n    }\n    else\n    {\n        /* no valid short term buffers, delete one gap from the least start */\n        /* of gap sequence                                                  */\n        i4_gap_frame_num = pi4_gaps_start_frm_num[0];\n        i1_gap_idx = 0;\n        for(i = 1; i < MAX_FRAMES; i++)\n        {\n            if(INVALID_FRAME_NUM != pi4_gaps_start_frm_num[i])\n            {\n                if(pi4_gaps_start_frm_num[i] < i4_gap_frame_num)\n                {\n                    i4_gap_frame_num = pi4_gaps_start_frm_num[i];\n                    i1_gap_idx = i;\n                }\n            }\n        }\n        if(INVALID_FRAME_NUM == i4_gap_frame_num)\n        {\n            UWORD32 i4_error_code;\n            i4_error_code = ERROR_DBP_MANAGER_T;\n            return i4_error_code;\n        }\n    }\n\n    if(-1 != i1_gap_idx)\n    {\n        /* find least frame_num in the poc_map, which is in this range */\n        i4_start_frm_num = pi4_gaps_start_frm_num[i1_gap_idx];\n        if(i4_start_frm_num < 0)\n            i4_start_frm_num += i4_max_frm_num;\n        i4_end_frm_num = pi4_gaps_end_frm_num[i1_gap_idx];\n        if(i4_end_frm_num < 0)\n            i4_end_frm_num += i4_max_frm_num;\n\n        i4_gap_frm_num_min = 0xfffffff;\n        j_min = MAX_FRAMES;\n        for(j = 0; j < MAX_FRAMES; j++)\n        {\n            i4_frm_num = ps_dpb_mgr->ai4_poc_buf_id_map[j][2];\n            if((i4_start_frm_num <= i4_frm_num)\n                            && (i4_end_frm_num >= i4_frm_num))\n            {\n                if(i4_frm_num < i4_gap_frm_num_min)\n                {\n                    j_min = j;\n                    i4_gap_frm_num_min = i4_frm_num;\n                }\n            }\n        }\n\n        if(j_min != MAX_FRAMES)\n        {\n\n            ps_dpb_mgr->ai4_poc_buf_id_map[j_min][0] = -1;\n            ps_dpb_mgr->ai4_poc_buf_id_map[j_min][1] = 0x7fffffff;\n            ps_dpb_mgr->ai4_poc_buf_id_map[j_min][2] = GAP_FRAME_NUM;\n            ps_dpb_mgr->i1_gaps_deleted++;\n\n            ps_dpb_mgr->ai1_gaps_per_seq[i1_gap_idx]--;\n            ps_dpb_mgr->u1_num_gaps--;\n            *pu1_del_node = 0;\n            if(0 == ps_dpb_mgr->ai1_gaps_per_seq[i1_gap_idx])\n            {\n                ps_dpb_mgr->ai4_gaps_start_frm_num[i1_gap_idx] =\n                INVALID_FRAME_NUM;\n                ps_dpb_mgr->ai4_gaps_end_frm_num[i1_gap_idx] = 0;\n            }\n        }\n    }\n\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_delete_gap_frm_mmco                               */\n/*                                                                           */\n/*  Description   : This function deletes a picture from the list of gaps,   */\n/*                  if the frame number (specified by mmco commands) to be   */\n/*                  deleted is in the range by gap sequence.                 */\n/*                                                                           */\n/*  Inputs        : ps_dpb_mgr: pointer to dpb manager                       */\n/*                  i4_frame_num:  frame number of picture that's going to   */\n/*                  be deleted by mmco                                       */\n/*                  pu1_del_node: holds 0 if a gap is deleted else 1         */\n/*  Globals       : None                                                     */\n/*  Processing    : Function searches for frame number lesser in the range   */\n/*                  specified by gap sequence                                */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         22 06 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_delete_gap_frm_mmco(dpb_manager_t *ps_dpb_mgr,\n                                  WORD32 i4_frame_num,\n                                  UWORD8 *pu1_del_node)\n{\n    WORD8 i, j;\n    WORD32 *pi4_start, *pi4_end;\n    WORD32 i4_start_frm_num, i4_end_frm_num, i4_max_frm_num;\n\n    /* find the least frame num from gaps and current DPB node    */\n    /* Delete the gaps                                            */\n    *pu1_del_node = 1;\n    pi4_start = ps_dpb_mgr->ai4_gaps_start_frm_num;\n    pi4_end = ps_dpb_mgr->ai4_gaps_end_frm_num;\n    i4_max_frm_num = ps_dpb_mgr->i4_max_frm_num;\n\n    if(0 == ps_dpb_mgr->u1_num_gaps)\n        return OK;\n\n    if(i4_frame_num < 0)\n        i4_frame_num += i4_max_frm_num;\n    for(i = 0; i < MAX_FRAMES; i++)\n    {\n        i4_start_frm_num = pi4_start[i];\n        if(i4_start_frm_num < 0)\n            i4_start_frm_num += i4_max_frm_num;\n        if(INVALID_FRAME_NUM != i4_start_frm_num)\n        {\n            i4_end_frm_num = pi4_end[i];\n            if(i4_end_frm_num < 0)\n                i4_end_frm_num += i4_max_frm_num;\n\n            if((i4_frame_num >= i4_start_frm_num)\n                            && (i4_frame_num <= i4_end_frm_num))\n            {\n                break;\n            }\n            else\n            {\n                if(((i4_frame_num + i4_max_frm_num) >= i4_start_frm_num)\n                                && ((i4_frame_num + i4_max_frm_num)\n                                                <= i4_end_frm_num))\n                {\n                    UWORD32 i4_error_code;\n                    i4_error_code = ERROR_DBP_MANAGER_T;\n                    return i4_error_code;\n                }\n            }\n        }\n    }\n\n    /* find frame_num index, in the poc_map which needs to be deleted */\n    for(j = 0; j < MAX_FRAMES; j++)\n    {\n        if(i4_frame_num == ps_dpb_mgr->ai4_poc_buf_id_map[j][2])\n            break;\n    }\n\n    if(MAX_FRAMES != i)\n    {\n        if(j == MAX_FRAMES)\n        {\n            UWORD32 i4_error_code;\n            i4_error_code = ERROR_DBP_MANAGER_T;\n            return i4_error_code;\n        }\n\n        ps_dpb_mgr->ai4_poc_buf_id_map[j][0] = -1;\n        ps_dpb_mgr->ai4_poc_buf_id_map[j][1] = 0x7fffffff;\n        ps_dpb_mgr->ai4_poc_buf_id_map[j][2] = GAP_FRAME_NUM;\n        ps_dpb_mgr->i1_gaps_deleted++;\n\n        ps_dpb_mgr->ai1_gaps_per_seq[i]--;\n        ps_dpb_mgr->u1_num_gaps--;\n        *pu1_del_node = 0;\n        if(0 == ps_dpb_mgr->ai1_gaps_per_seq[i])\n        {\n            ps_dpb_mgr->ai4_gaps_start_frm_num[i] = INVALID_FRAME_NUM;\n            ps_dpb_mgr->ai4_gaps_end_frm_num[i] = 0;\n        }\n    }\n    else\n    {\n        UWORD32 i4_error_code;\n        i4_error_code = ERROR_DBP_MANAGER_T;\n        return i4_error_code;\n    }\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_do_mmco_for_gaps \\endif\n *\n * \\brief\n *    Perform decoded picture buffer memory management control operations\n *\n * \\return\n *    0 - No error; -1 - Error\n *\n * \\note\n *    Bitstream is also parsed here to get the MMCOs\n *\n **************************************************************************\n */\nWORD32 ih264d_do_mmco_for_gaps(dpb_manager_t *ps_dpb_mgr,\n                             UWORD8 u1_num_ref_frames /*!< num_ref_frames from active SeqParSet*/\n                             )\n{\n    struct dpb_info_t *ps_next_dpb;\n    UWORD8 u1_num_gaps;\n    UWORD8 u1_st_ref_bufs, u1_lt_ref_bufs, u1_del_node;\n    WORD8 i;\n    WORD32 i4_frame_gaps = 1;\n    WORD32 ret;\n\n    //Sliding window - implements 8.2.5.3, flush out buffers\n    u1_st_ref_bufs = ps_dpb_mgr->u1_num_st_ref_bufs;\n    u1_lt_ref_bufs = ps_dpb_mgr->u1_num_lt_ref_bufs;\n\n    while(1)\n    {\n        u1_num_gaps = ps_dpb_mgr->u1_num_gaps;\n        if((u1_st_ref_bufs + u1_lt_ref_bufs + u1_num_gaps + i4_frame_gaps)\n                        > u1_num_ref_frames)\n        {\n            if(0 == (u1_st_ref_bufs + u1_num_gaps))\n            {\n                i4_frame_gaps = 0;\n                ps_dpb_mgr->u1_num_gaps = (u1_num_ref_frames\n                                - u1_lt_ref_bufs);\n            }\n            else\n            {\n                u1_del_node = 1;\n                ps_next_dpb = ps_dpb_mgr->ps_dpb_st_head;\n\n                if(u1_st_ref_bufs > 1)\n                {\n                    for(i = 1; i < (u1_st_ref_bufs - 1); i++)\n                    {\n                        if(ps_next_dpb == NULL)\n                        {\n                            UWORD32 i4_error_code;\n                            i4_error_code = ERROR_DBP_MANAGER_T;\n                            return i4_error_code;\n                        }\n                        ps_next_dpb = ps_next_dpb->ps_prev_short;\n                    }\n\n                    if(ps_next_dpb->ps_prev_short->ps_prev_short != NULL)\n                    {\n                        return ERROR_DBP_MANAGER_T;\n                    }\n\n                    if(u1_num_gaps)\n                    {\n                        ret = ih264d_delete_gap_frm_sliding(ps_dpb_mgr,\n                                                            ps_next_dpb->ps_prev_short->i4_frame_num,\n                                                            &u1_del_node);\n                        if(ret != OK)\n                            return ret;\n                    }\n\n                    if(u1_del_node)\n                    {\n                        u1_st_ref_bufs--;\n                        ps_next_dpb->ps_prev_short->u1_used_as_ref =\n                                        UNUSED_FOR_REF;\n                        ps_next_dpb->ps_prev_short->s_top_field.u1_reference_info =\n                                        UNUSED_FOR_REF;\n                        ps_next_dpb->ps_prev_short->s_bot_field.u1_reference_info =\n                                        UNUSED_FOR_REF;\n                        ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                                    ps_next_dpb->ps_prev_short->u1_buf_id);\n                        ps_next_dpb->ps_prev_short->ps_pic_buf = NULL;\n                        ps_next_dpb->ps_prev_short = NULL;\n                    }\n                }\n                else\n                {\n                    if(u1_st_ref_bufs)\n                    {\n                        if(u1_num_gaps)\n                        {\n                            ret = ih264d_delete_gap_frm_sliding(ps_dpb_mgr,\n                                                                ps_next_dpb->i4_frame_num,\n                                                                &u1_del_node);\n                            if(ret != OK)\n                                return ret;\n                        }\n\n                        if(u1_del_node)\n                        {\n                            u1_st_ref_bufs--;\n                            ps_next_dpb->u1_used_as_ref = FALSE;\n                            ps_next_dpb->s_top_field.u1_reference_info =\n                                            UNUSED_FOR_REF;\n                            ps_next_dpb->s_bot_field.u1_reference_info =\n                                            UNUSED_FOR_REF;\n                            ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                                        ps_next_dpb->u1_buf_id);\n                            ps_next_dpb->ps_pic_buf = NULL;\n                            ps_next_dpb = NULL;\n                            ps_dpb_mgr->ps_dpb_st_head = NULL;\n                            ps_dpb_mgr->u1_num_st_ref_bufs = u1_st_ref_bufs;\n                        }\n                    }\n                    else\n                    {\n                        ret = ih264d_delete_gap_frm_sliding(ps_dpb_mgr,\n                                                            INVALID_FRAME_NUM,\n                                                            &u1_del_node);\n                        if(ret != OK)\n                            return ret;\n                        if(u1_del_node)\n                        {\n                            return ERROR_DBP_MANAGER_T;\n                        }\n                    }\n                }\n            }\n        }\n        else\n        {\n            ps_dpb_mgr->u1_num_gaps += i4_frame_gaps;\n            break;\n        }\n    }\n\n    ps_dpb_mgr->u1_num_st_ref_bufs = u1_st_ref_bufs;\n\n    return OK;\n}\n/****************************************************************************/\n/*                                                                          */\n/* Function Name  : ih264d_free_node_from_dpb                                      */\n/*                                                                          */\n/* Description    :                                                         */\n/*                                                                          */\n/* Inputs         :                                                         */\n/*                                                                          */\n/* Globals        :                                                         */\n/*                                                                          */\n/* Processing     :                                                         */\n/*                                                                          */\n/* Outputs        :                                                         */\n/*                                                                          */\n/* Returns        :                                                         */\n/*                                                                          */\n/* Known Issues   :                                                         */\n/*                                                                          */\n/* Revision History                                                         */\n/*                                                                          */\n/*      DD MM YY            Author        Changes                           */\n/*                          Sarat                                           */\n/****************************************************************************/\n/**** Function Added for Error Resilience *****/\nWORD32 ih264d_free_node_from_dpb(dpb_manager_t *ps_dpb_mgr,\n                               UWORD32 u4_cur_pic_num,\n                               UWORD8 u1_numRef_frames_for_seq)\n{\n    WORD32 i;\n    UWORD8 u1_num_gaps = ps_dpb_mgr->u1_num_gaps;\n    struct dpb_info_t *ps_next_dpb;\n    UWORD8 u1_del_node = 1;\n    WORD32 ret;\n\n    //Sliding window - implements 8.2.5.3\n    if((ps_dpb_mgr->u1_num_st_ref_bufs + ps_dpb_mgr->u1_num_lt_ref_bufs\n                    + u1_num_gaps) == u1_numRef_frames_for_seq)\n    {\n        UWORD8 u1_new_node_flag = 1;\n        if((0 == ps_dpb_mgr->u1_num_st_ref_bufs) && (0 == u1_num_gaps))\n        {\n            return ERROR_DBP_MANAGER_T;\n        }\n\n        // Chase the links to reach the last but one picNum, if available\n        ps_next_dpb = ps_dpb_mgr->ps_dpb_st_head;\n\n        if(ps_dpb_mgr->u1_num_st_ref_bufs > 1)\n        {\n            if(ps_next_dpb->i4_frame_num == (WORD32)u4_cur_pic_num)\n            {\n                /* Incase of  filed pictures top_field has been allocated   */\n                /* picture buffer and complementary bottom field pair comes */\n                /* then the sliding window mechanism should not allocate a  */\n                /* new node                                                 */\n                u1_new_node_flag = 0;\n            }\n\n            for(i = 1; i < (ps_dpb_mgr->u1_num_st_ref_bufs - 1); i++)\n            {\n                if(ps_next_dpb == NULL)\n                    return ERROR_DBP_MANAGER_T;\n\n                if(ps_next_dpb->i4_frame_num == (WORD32)u4_cur_pic_num)\n                {\n                    /* Incase of  field pictures top_field has been allocated   */\n                    /* picture buffer and complementary bottom field pair comes */\n                    /* then the sliding window mechanism should not allocate a  */\n                    /* new node                                                 */\n                    u1_new_node_flag = 0;\n                }\n                ps_next_dpb = ps_next_dpb->ps_prev_short;\n            }\n\n            if(ps_next_dpb->ps_prev_short->ps_prev_short != NULL)\n                return ERROR_DBP_MANAGER_T;\n\n            if(u1_new_node_flag)\n            {\n                if(u1_num_gaps)\n                {\n                    ret = ih264d_delete_gap_frm_sliding(ps_dpb_mgr,\n                                                        ps_next_dpb->ps_prev_short->i4_frame_num,\n                                                        &u1_del_node);\n                    if(ret != OK)\n                        return ret;\n                }\n\n                if(u1_del_node)\n                {\n                    ps_dpb_mgr->u1_num_st_ref_bufs--;\n                    ps_next_dpb->ps_prev_short->u1_used_as_ref = UNUSED_FOR_REF;\n                    ps_next_dpb->ps_prev_short->s_top_field.u1_reference_info =\n                                    UNUSED_FOR_REF;\n                    ps_next_dpb->ps_prev_short->s_bot_field.u1_reference_info =\n                                    UNUSED_FOR_REF;\n                    ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                                ps_next_dpb->ps_prev_short->u1_buf_id);\n                    ps_next_dpb->ps_prev_short->ps_pic_buf = NULL;\n                    ps_next_dpb->ps_prev_short = NULL;\n                }\n            }\n        }\n        else\n        {\n            if(ps_dpb_mgr->u1_num_st_ref_bufs)\n            {\n                ret = ih264d_delete_gap_frm_sliding(ps_dpb_mgr,\n                                                    ps_next_dpb->i4_frame_num,\n                                                    &u1_del_node);\n                if(ret != OK)\n                    return ret;\n                if((ps_next_dpb->i4_frame_num != (WORD32)u4_cur_pic_num)\n                                && u1_del_node)\n                {\n                    ps_dpb_mgr->u1_num_st_ref_bufs--;\n                    ps_next_dpb->u1_used_as_ref = FALSE;\n                    ps_next_dpb->s_top_field.u1_reference_info = UNUSED_FOR_REF;\n                    ps_next_dpb->s_bot_field.u1_reference_info = UNUSED_FOR_REF;\n                    ih264d_free_ref_pic_mv_bufs(ps_dpb_mgr->pv_codec_handle,\n                                                ps_next_dpb->u1_buf_id);\n                    ps_next_dpb->ps_pic_buf = NULL;\n                    ps_next_dpb = NULL;\n                }\n            }\n            else\n            {\n                ret = ih264d_delete_gap_frm_sliding(ps_dpb_mgr, INVALID_FRAME_NUM, &u1_del_node);\n                if(ret != OK)\n                    return ret;\n                if(u1_del_node)\n                    return ERROR_DBP_MANAGER_T;\n            }\n        }\n    }\n    return OK;\n}\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_delete_nonref_nondisplay_pics                            */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*                                                                           */\n/*  Inputs        :                                                          */\n/*  Globals       :                                                          */\n/*  Processing    :                                                          */\n/*                                                                           */\n/*  Outputs       :                                                          */\n/*  Returns       :                                                          */\n/*                                                                           */\n/*  Issues        :                                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         05 06 2007   Varun           Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nvoid ih264d_delete_nonref_nondisplay_pics(dpb_manager_t *ps_dpb_mgr)\n{\n    WORD8 i;\n    WORD32 (*i4_poc_buf_id_map)[3] = ps_dpb_mgr->ai4_poc_buf_id_map;\n\n    /* remove all gaps marked as unused for ref */\n    for(i = 0; (i < MAX_FRAMES) && ps_dpb_mgr->i1_gaps_deleted; i++)\n    {\n        if(GAP_FRAME_NUM == i4_poc_buf_id_map[i][2])\n        {\n            ps_dpb_mgr->i1_gaps_deleted--;\n            ps_dpb_mgr->i1_poc_buf_id_entries--;\n            i4_poc_buf_id_map[i][0] = -1;\n            i4_poc_buf_id_map[i][1] = 0x7fffffff;\n            i4_poc_buf_id_map[i][2] = 0;\n        }\n    }\n}\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_insert_pic_in_display_list                               */\n/*                                                                           */\n/*  Description   :                                                          */\n/*                                                                           */\n/*                                                                           */\n/*  Inputs        :                                                          */\n/*  Globals       :                                                          */\n/*  Processing    :                                                          */\n/*                                                                           */\n/*  Outputs       :                                                          */\n/*  Returns       :                                                          */\n/*                                                                           */\n/*  Issues        :                                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         05 06 2007   Varun           Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_insert_pic_in_display_list(dpb_manager_t *ps_dpb_mgr,\n                                         UWORD8 u1_buf_id,\n                                         WORD32 i4_display_poc,\n                                         UWORD32 u4_frame_num)\n{\n    WORD8 i;\n    WORD32 (*i4_poc_buf_id_map)[3] = ps_dpb_mgr->ai4_poc_buf_id_map;\n\n    for(i = 0; i < MAX_FRAMES; i++)\n    {\n        /* Find an empty slot */\n        if(i4_poc_buf_id_map[i][0] == -1)\n        {\n            if(GAP_FRAME_NUM == i4_poc_buf_id_map[i][2])\n                ps_dpb_mgr->i1_gaps_deleted--;\n            else\n                ps_dpb_mgr->i1_poc_buf_id_entries++;\n\n            i4_poc_buf_id_map[i][0] = u1_buf_id;\n            i4_poc_buf_id_map[i][1] = i4_display_poc;\n            i4_poc_buf_id_map[i][2] = u4_frame_num;\n\n            break;\n        }\n    }\n\n    if(MAX_FRAMES == i)\n    {\n\n        UWORD32 i4_error_code;\n        i4_error_code = ERROR_GAPS_IN_FRM_NUM;\n        return i4_error_code;\n    }\n    return OK;\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_error_handler.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n#ifndef _IH264D_ERROR_HANDLER_H_\n#define _IH264D_ERROR_HANDLER_H_\n\n/*!\n *************************************************************************\n * \\file ih264d_error_handler.h\n *\n * \\brief\n *    Contains declaration of ih264d_global_error_handler function\n *\n * \\date\n *    21/11/2002\n *\n * \\author  AI\n *************************************************************************\n */\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\n\ntypedef enum\n{\n\n    ERROR_MEM_ALLOC_ISRAM_T = 0x50,\n    ERROR_MEM_ALLOC_SDRAM_T = 0x51,\n    ERROR_BUF_MGR = 0x52,\n    ERROR_DBP_MANAGER_T = 0x53,\n    ERROR_GAPS_IN_FRM_NUM = 0x54,\n    ERROR_UNKNOWN_NAL = 0x55,\n    ERROR_INV_MB_SLC_GRP_T = 0x56,\n    ERROR_MULTIPLE_SLC_GRP_T = 0x57,\n    ERROR_UNKNOWN_LEVEL = 0x58,\n    ERROR_FEATURE_UNAVAIL = 0x59,\n    ERROR_NOT_SUPP_RESOLUTION = 0x5A,\n    ERROR_INVALID_PIC_PARAM = 0x5B,\n    ERROR_INVALID_SEQ_PARAM = 0x5C,\n    ERROR_EGC_EXCEED_32_1_T = 0x5D,\n    ERROR_EGC_EXCEED_32_2_T = 0x5E,\n    ERROR_INV_RANGE_TEV_T = 0x5F,\n    ERROR_INV_SLC_TYPE_T = 0x60,\n    ERROR_UNAVAIL_PICBUF_T = 0x61,\n    ERROR_UNAVAIL_MVBUF_T = 0x62,\n    ERROR_UNAVAIL_DISPBUF_T = 0x63,\n    ERROR_INV_POC_TYPE_T = 0x64,\n    ERROR_PIC1_NOT_FOUND_T = 0x65,\n    ERROR_PIC0_NOT_FOUND_T = 0x66,\n    ERROR_NUM_REF = 0x67,\n    ERROR_REFIDX_ORDER_T = 0x68,\n    ERROR_EOB_FLUSHBITS_T = 0x69,\n    ERROR_EOB_GETBITS_T = 0x6A,\n    ERROR_EOB_GETBIT_T = 0x6B,\n    ERROR_EOB_BYPASS_T = 0x6C,\n    ERROR_EOB_DECISION_T = 0x6D,\n    ERROR_EOB_TERMINATE_T = 0x6E,\n    ERROR_EOB_READCOEFF4X4CAB_T = 0x6F,\n    ERROR_INV_RANGE_QP_T = 0x70,\n    ERROR_END_OF_FRAME_EXPECTED_T = 0x71,\n    ERROR_MB_TYPE = 0x72,\n    ERROR_SUB_MB_TYPE = 0x73,\n    ERROR_CBP = 0x74,\n    ERROR_REF_IDX = 0x75,\n    ERROR_NUM_MV = 0x76,\n    ERROR_CHROMA_PRED_MODE = 0x77,\n    ERROR_INTRAPRED = 0x78,\n    ERROR_NEXT_MB_ADDRESS_T = 0x79,\n    ERROR_MB_ADDRESS_T = 0x7A,\n    ERROR_MB_GROUP_ASSGN_T = 0x7B,\n    ERROR_CAVLC_NUM_COEFF_T = 0x7C,\n    ERROR_CAVLC_SCAN_POS_T = 0x7D,\n    ERROR_CABAC_RENORM_T = 0x7E,\n    ERROR_CABAC_SIG_COEFF1_T = 0x7F,\n    ERROR_CABAC_SIG_COEFF2_T = 0x80,\n    ERROR_CABAC_ENCODE_COEFF_T = 0x81,\n    ERROR_INV_SPS_PPS_T = 0x82,\n    ERROR_INV_SLICE_HDR_T = 0x83,\n    ERROR_PRED_WEIGHT_TABLE_T = 0x84,\n    IH264D_VERS_BUF_INSUFFICIENT = 0x85,\n    ERROR_ACTUAL_LEVEL_GREATER_THAN_INIT = 0x86,\n    ERROR_CORRUPTED_SLICE = 0x87,\n    ERROR_FRAME_LIMIT_OVER = 0x88,\n    ERROR_ACTUAL_RESOLUTION_GREATER_THAN_INIT = 0x89,\n    ERROR_PROFILE_NOT_SUPPORTED = 0x8A,\n    ERROR_DISP_WIDTH_RESET_TO_PIC_WIDTH = 0x8B,\n    ERROR_DISP_WIDTH_INVALID = 0x8C,\n    ERROR_DANGLING_FIELD_IN_PIC = 0x8D,\n    ERROR_DYNAMIC_RESOLUTION_NOT_SUPPORTED = 0x8E,\n    ERROR_INIT_NOT_DONE = 0x8F,\n    ERROR_LEVEL_UNSUPPORTED = 0x90,\n    ERROR_START_CODE_NOT_FOUND = 0x91,\n    ERROR_PIC_NUM_IS_REPEATED = 0x92,\n    ERROR_IN_LAST_SLICE_OF_PIC = 0x93,\n    ERROR_NEW_FRAME_EXPECTED = 0x94,\n    ERROR_INCOMPLETE_FRAME = 0x95,\n    ERROR_VUI_PARAMS_NOT_FOUND = 0x96,\n    ERROR_INV_POC = 0x97,\n    ERROR_SEI_MDCV_PARAMS_NOT_FOUND = 0x98,\n    ERROR_SEI_CLL_PARAMS_NOT_FOUND = 0x99,\n    ERROR_SEI_AVE_PARAMS_NOT_FOUND = 0x9A,\n    ERROR_SEI_CCV_PARAMS_NOT_FOUND = 0x9B,\n    ERROR_INV_SEI_MDCV_PARAMS = 0x9C,\n    ERROR_INV_SEI_CLL_PARAMS = 0x9D,\n    ERROR_INV_SEI_AVE_PARAMS = 0x9E,\n    ERROR_INV_SEI_CCV_PARAMS = 0x9F,\n    ERROR_INV_FRAME_NUM = 0xA0\n\n} h264_decoder_error_code_t;\n\nWORD32 ih264d_mark_err_slice_skip(dec_struct_t * ps_dec,\n                                  WORD32 num_mb_skip,\n                                  UWORD8 u1_is_idr_slice,\n                                  UWORD16 u2_frame_num,\n                                  pocstruct_t *ps_cur_poc,\n                                  WORD32 prev_slice_err);\n\nvoid ih264d_err_pic_dispbuf_mgr(dec_struct_t *ps_dec);\n#endif /* _IH264D_ERROR_HANDLER_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_format_conv.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264d_format_conv.c                                */\n/*                                                                           */\n/*  Description       : Contains functions needed to convert the images in   */\n/*                      different color spaces to yuv 422i color space       */\n/*                                                                           */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         28 08 2007  Naveen Kumar T        Draft                           */\n/*                                                                           */\n/*****************************************************************************/\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System include files */\n#include <string.h>\n/* User include files */\n#include \"ih264_typedefs.h\"\n#include \"iv.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_format_conv.h\"\n#include \"ih264d_defs.h\"\n\n\n\n#ifdef LOGO_EN\n#include \"ih264d_ittiam_logo.h\"\n#define INSERT_LOGO(pu1_buf_y,pu1_buf_u,pu1_buf_v, u4_stride, u4_x_pos, u4_y_pos, u4_yuv_fmt, u4_disp_wd, u4_disp_ht) \\\n                    ih264d_insert_logo(pu1_buf_y,pu1_buf_u,pu1_buf_v, u4_stride,\\\n                          u4_x_pos, u4_y_pos, u4_yuv_fmt, u4_disp_wd, u4_disp_ht)\n#else\n#define INSERT_LOGO(pu1_buf_y,pu1_buf_u,pu1_buf_v, u4_stride, u4_x_pos, u4_y_pos, u4_yuv_fmt, u4_disp_wd, u4_disp_ht)\n#endif\n\n/**\n *******************************************************************************\n *\n * @brief Function used from copying a 420SP buffer\n *\n * @par   Description\n * Function used from copying a 420SP buffer\n *\n * @param[in] pu1_y_src\n *   Input Y pointer\n *\n * @param[in] pu1_uv_src\n *   Input UV pointer (UV is interleaved either in UV or VU format)\n *\n * @param[in] pu1_y_dst\n *   Output Y pointer\n *\n * @param[in] pu1_uv_dst\n *   Output UV pointer (UV is interleaved in the same format as that of input)\n *\n * @param[in] wd\n *   Width\n *\n * @param[in] ht\n *   Height\n *\n * @param[in] src_y_strd\n *   Input Y Stride\n *\n * @param[in] src_uv_strd\n *   Input UV stride\n *\n * @param[in] dst_y_strd\n *   Output Y stride\n *\n * @param[in] dst_uv_strd\n *   Output UV stride\n *\n * @returns None\n *\n * @remarks In case there is a need to perform partial frame copy then\n * by passion appropriate source and destination pointers and appropriate\n * values for wd and ht it can be done\n *\n *******************************************************************************\n */\nvoid ih264d_fmt_conv_420sp_to_rgb565(UWORD8 *pu1_y_src,\n                                     UWORD8 *pu1_uv_src,\n                                     UWORD16 *pu2_rgb_dst,\n                                     WORD32 wd,\n                                     WORD32 ht,\n                                     WORD32 src_y_strd,\n                                     WORD32 src_uv_strd,\n                                     WORD32 dst_strd,\n                                     WORD32 is_u_first)\n{\n\n    WORD16 i2_r, i2_g, i2_b;\n    UWORD32 u4_r, u4_g, u4_b;\n    WORD16 i2_i, i2_j;\n    UWORD8 *pu1_y_src_nxt;\n    UWORD16 *pu2_rgb_dst_next_row;\n\n    UWORD8 *pu1_u_src, *pu1_v_src;\n\n    if(is_u_first)\n    {\n        pu1_u_src = (UWORD8 *)pu1_uv_src;\n        pu1_v_src = (UWORD8 *)pu1_uv_src + 1;\n    }\n    else\n    {\n        pu1_u_src = (UWORD8 *)pu1_uv_src + 1;\n        pu1_v_src = (UWORD8 *)pu1_uv_src;\n    }\n\n    pu1_y_src_nxt = pu1_y_src + src_y_strd;\n    pu2_rgb_dst_next_row = pu2_rgb_dst + dst_strd;\n\n    for(i2_i = 0; i2_i < (ht >> 1); i2_i++)\n    {\n        for(i2_j = (wd >> 1); i2_j > 0; i2_j--)\n        {\n            i2_b = ((*pu1_u_src - 128) * COEFF4 >> 13);\n            i2_g = ((*pu1_u_src - 128) * COEFF2 + (*pu1_v_src - 128) * COEFF3)\n                            >> 13;\n            i2_r = ((*pu1_v_src - 128) * COEFF1) >> 13;\n\n            pu1_u_src += 2;\n            pu1_v_src += 2;\n            /* pixel 0 */\n            /* B */\n            u4_b = CLIP_U8(*pu1_y_src + i2_b);\n            u4_b >>= 3;\n            /* G */\n            u4_g = CLIP_U8(*pu1_y_src + i2_g);\n            u4_g >>= 2;\n            /* R */\n            u4_r = CLIP_U8(*pu1_y_src + i2_r);\n            u4_r >>= 3;\n\n            pu1_y_src++;\n            *pu2_rgb_dst++ = ((u4_r << 11) | (u4_g << 5) | u4_b);\n\n            /* pixel 1 */\n            /* B */\n            u4_b = CLIP_U8(*pu1_y_src + i2_b);\n            u4_b >>= 3;\n            /* G */\n            u4_g = CLIP_U8(*pu1_y_src + i2_g);\n            u4_g >>= 2;\n            /* R */\n            u4_r = CLIP_U8(*pu1_y_src + i2_r);\n            u4_r >>= 3;\n\n            pu1_y_src++;\n            *pu2_rgb_dst++ = ((u4_r << 11) | (u4_g << 5) | u4_b);\n\n            /* pixel 2 */\n            /* B */\n            u4_b = CLIP_U8(*pu1_y_src_nxt + i2_b);\n            u4_b >>= 3;\n            /* G */\n            u4_g = CLIP_U8(*pu1_y_src_nxt + i2_g);\n            u4_g >>= 2;\n            /* R */\n            u4_r = CLIP_U8(*pu1_y_src_nxt + i2_r);\n            u4_r >>= 3;\n\n            pu1_y_src_nxt++;\n            *pu2_rgb_dst_next_row++ = ((u4_r << 11) | (u4_g << 5) | u4_b);\n\n            /* pixel 3 */\n            /* B */\n            u4_b = CLIP_U8(*pu1_y_src_nxt + i2_b);\n            u4_b >>= 3;\n            /* G */\n            u4_g = CLIP_U8(*pu1_y_src_nxt + i2_g);\n            u4_g >>= 2;\n            /* R */\n            u4_r = CLIP_U8(*pu1_y_src_nxt + i2_r);\n            u4_r >>= 3;\n\n            pu1_y_src_nxt++;\n            *pu2_rgb_dst_next_row++ = ((u4_r << 11) | (u4_g << 5) | u4_b);\n\n        }\n\n        pu1_u_src = pu1_u_src + src_uv_strd - wd;\n        pu1_v_src = pu1_v_src + src_uv_strd - wd;\n\n        pu1_y_src = pu1_y_src + (src_y_strd << 1) - wd;\n        pu1_y_src_nxt = pu1_y_src_nxt + (src_y_strd << 1) - wd;\n\n        pu2_rgb_dst = pu2_rgb_dst_next_row - wd + dst_strd;\n        pu2_rgb_dst_next_row = pu2_rgb_dst_next_row + (dst_strd << 1) - wd;\n    }\n\n}\n\nvoid ih264d_fmt_conv_420sp_to_rgba8888(UWORD8 *pu1_y_src,\n                                       UWORD8 *pu1_uv_src,\n                                       UWORD32 *pu4_rgba_dst,\n                                       WORD32 wd,\n                                       WORD32 ht,\n                                       WORD32 src_y_strd,\n                                       WORD32 src_uv_strd,\n                                       WORD32 dst_strd,\n                                       WORD32 is_u_first)\n{\n\n    WORD16 i2_r, i2_g, i2_b;\n    UWORD32 u4_r, u4_g, u4_b;\n    WORD16 i2_i, i2_j;\n    UWORD8 *pu1_y_src_nxt;\n    UWORD32 *pu4_rgba_dst_next_row;\n\n    UWORD8 *pu1_u_src, *pu1_v_src;\n\n    if(is_u_first)\n    {\n        pu1_u_src = (UWORD8 *)pu1_uv_src;\n        pu1_v_src = (UWORD8 *)pu1_uv_src + 1;\n    }\n    else\n    {\n        pu1_u_src = (UWORD8 *)pu1_uv_src + 1;\n        pu1_v_src = (UWORD8 *)pu1_uv_src;\n    }\n\n    pu1_y_src_nxt = pu1_y_src + src_y_strd;\n    pu4_rgba_dst_next_row = pu4_rgba_dst + dst_strd;\n\n    for(i2_i = 0; i2_i < (ht >> 1); i2_i++)\n    {\n        for(i2_j = (wd >> 1); i2_j > 0; i2_j--)\n        {\n            i2_b = ((*pu1_u_src - 128) * COEFF4 >> 13);\n            i2_g = ((*pu1_u_src - 128) * COEFF2 + (*pu1_v_src - 128) * COEFF3)\n                            >> 13;\n            i2_r = ((*pu1_v_src - 128) * COEFF1) >> 13;\n\n            pu1_u_src += 2;\n            pu1_v_src += 2;\n            /* pixel 0 */\n            /* B */\n            u4_b = CLIP_U8(*pu1_y_src + i2_b);\n            /* G */\n            u4_g = CLIP_U8(*pu1_y_src + i2_g);\n            /* R */\n            u4_r = CLIP_U8(*pu1_y_src + i2_r);\n\n            pu1_y_src++;\n            *pu4_rgba_dst++ = ((u4_r << 16) | (u4_g << 8) | (u4_b << 0));\n\n            /* pixel 1 */\n            /* B */\n            u4_b = CLIP_U8(*pu1_y_src + i2_b);\n            /* G */\n            u4_g = CLIP_U8(*pu1_y_src + i2_g);\n            /* R */\n            u4_r = CLIP_U8(*pu1_y_src + i2_r);\n\n            pu1_y_src++;\n            *pu4_rgba_dst++ = ((u4_r << 16) | (u4_g << 8) | (u4_b << 0));\n\n            /* pixel 2 */\n            /* B */\n            u4_b = CLIP_U8(*pu1_y_src_nxt + i2_b);\n            /* G */\n            u4_g = CLIP_U8(*pu1_y_src_nxt + i2_g);\n            /* R */\n            u4_r = CLIP_U8(*pu1_y_src_nxt + i2_r);\n\n            pu1_y_src_nxt++;\n            *pu4_rgba_dst_next_row++ =\n                            ((u4_r << 16) | (u4_g << 8) | (u4_b << 0));\n\n            /* pixel 3 */\n            /* B */\n            u4_b = CLIP_U8(*pu1_y_src_nxt + i2_b);\n            /* G */\n            u4_g = CLIP_U8(*pu1_y_src_nxt + i2_g);\n            /* R */\n            u4_r = CLIP_U8(*pu1_y_src_nxt + i2_r);\n\n            pu1_y_src_nxt++;\n            *pu4_rgba_dst_next_row++ =\n                            ((u4_r << 16) | (u4_g << 8) | (u4_b << 0));\n\n        }\n\n        pu1_u_src = pu1_u_src + src_uv_strd - wd;\n        pu1_v_src = pu1_v_src + src_uv_strd - wd;\n\n        pu1_y_src = pu1_y_src + (src_y_strd << 1) - wd;\n        pu1_y_src_nxt = pu1_y_src_nxt + (src_y_strd << 1) - wd;\n\n        pu4_rgba_dst = pu4_rgba_dst_next_row - wd + dst_strd;\n        pu4_rgba_dst_next_row = pu4_rgba_dst_next_row + (dst_strd << 1) - wd;\n    }\n\n}\n\n/**\n *******************************************************************************\n *\n * @brief Function used from copying a 420SP buffer\n *\n * @par   Description\n * Function used from copying a 420SP buffer\n *\n * @param[in] pu1_y_src\n *   Input Y pointer\n *\n * @param[in] pu1_uv_src\n *   Input UV pointer (UV is interleaved either in UV or VU format)\n *\n * @param[in] pu1_y_dst\n *   Output Y pointer\n *\n * @param[in] pu1_uv_dst\n *   Output UV pointer (UV is interleaved in the same format as that of input)\n *\n * @param[in] wd\n *   Width\n *\n * @param[in] ht\n *   Height\n *\n * @param[in] src_y_strd\n *   Input Y Stride\n *\n * @param[in] src_uv_strd\n *   Input UV stride\n *\n * @param[in] dst_y_strd\n *   Output Y stride\n *\n * @param[in] dst_uv_strd\n *   Output UV stride\n *\n * @returns None\n *\n * @remarks In case there is a need to perform partial frame copy then\n * by passion appropriate source and destination pointers and appropriate\n * values for wd and ht it can be done\n *\n *******************************************************************************\n */\n\nvoid ih264d_fmt_conv_420sp_to_420sp(UWORD8 *pu1_y_src,\n                                    UWORD8 *pu1_uv_src,\n                                    UWORD8 *pu1_y_dst,\n                                    UWORD8 *pu1_uv_dst,\n                                    WORD32 wd,\n                                    WORD32 ht,\n                                    WORD32 src_y_strd,\n                                    WORD32 src_uv_strd,\n                                    WORD32 dst_y_strd,\n                                    WORD32 dst_uv_strd)\n{\n    UWORD8 *pu1_src, *pu1_dst;\n    WORD32 num_rows, num_cols, src_strd, dst_strd;\n    WORD32 i;\n\n    /* copy luma */\n    pu1_src = (UWORD8 *)pu1_y_src;\n    pu1_dst = (UWORD8 *)pu1_y_dst;\n\n    num_rows = ht;\n    num_cols = wd;\n\n    src_strd = src_y_strd;\n    dst_strd = dst_y_strd;\n\n    for(i = 0; i < num_rows; i++)\n    {\n        memcpy(pu1_dst, pu1_src, num_cols);\n        pu1_dst += dst_strd;\n        pu1_src += src_strd;\n    }\n\n    /* copy U and V */\n    pu1_src = (UWORD8 *)pu1_uv_src;\n    pu1_dst = (UWORD8 *)pu1_uv_dst;\n\n    num_rows = ht >> 1;\n    num_cols = wd;\n\n    src_strd = src_uv_strd;\n    dst_strd = dst_uv_strd;\n\n    for(i = 0; i < num_rows; i++)\n    {\n        memcpy(pu1_dst, pu1_src, num_cols);\n        pu1_dst += dst_strd;\n        pu1_src += src_strd;\n    }\n    return;\n}\n\n/**\n *******************************************************************************\n *\n * @brief Function used from copying a 420SP buffer\n *\n * @par   Description\n * Function used from copying a 420SP buffer\n *\n * @param[in] pu1_y_src\n *   Input Y pointer\n *\n * @param[in] pu1_uv_src\n *   Input UV pointer (UV is interleaved either in UV or VU format)\n *\n * @param[in] pu1_y_dst\n *   Output Y pointer\n *\n * @param[in] pu1_uv_dst\n *   Output UV pointer (UV is interleaved in the same format as that of input)\n *\n * @param[in] wd\n *   Width\n *\n * @param[in] ht\n *   Height\n *\n * @param[in] src_y_strd\n *   Input Y Stride\n *\n * @param[in] src_uv_strd\n *   Input UV stride\n *\n * @param[in] dst_y_strd\n *   Output Y stride\n *\n * @param[in] dst_uv_strd\n *   Output UV stride\n *\n * @returns None\n *\n * @remarks In case there is a need to perform partial frame copy then\n * by passion appropriate source and destination pointers and appropriate\n * values for wd and ht it can be done\n *\n *******************************************************************************\n */\nvoid ih264d_fmt_conv_420sp_to_420sp_swap_uv(UWORD8 *pu1_y_src,\n                                            UWORD8 *pu1_uv_src,\n                                            UWORD8 *pu1_y_dst,\n                                            UWORD8 *pu1_uv_dst,\n                                            WORD32 wd,\n                                            WORD32 ht,\n                                            WORD32 src_y_strd,\n                                            WORD32 src_uv_strd,\n                                            WORD32 dst_y_strd,\n                                            WORD32 dst_uv_strd)\n{\n    UWORD8 *pu1_src, *pu1_dst;\n    WORD32 num_rows, num_cols, src_strd, dst_strd;\n    WORD32 i;\n\n    /* copy luma */\n    pu1_src = (UWORD8 *)pu1_y_src;\n    pu1_dst = (UWORD8 *)pu1_y_dst;\n\n    num_rows = ht;\n    num_cols = wd;\n\n    src_strd = src_y_strd;\n    dst_strd = dst_y_strd;\n\n    for(i = 0; i < num_rows; i++)\n    {\n        memcpy(pu1_dst, pu1_src, num_cols);\n        pu1_dst += dst_strd;\n        pu1_src += src_strd;\n    }\n\n    /* copy U and V */\n    pu1_src = (UWORD8 *)pu1_uv_src;\n    pu1_dst = (UWORD8 *)pu1_uv_dst;\n\n    num_rows = ht >> 1;\n    num_cols = wd;\n\n    src_strd = src_uv_strd;\n    dst_strd = dst_uv_strd;\n\n    for(i = 0; i < num_rows; i++)\n    {\n        WORD32 j;\n        for(j = 0; j < num_cols; j += 2)\n        {\n            pu1_dst[j + 0] = pu1_src[j + 1];\n            pu1_dst[j + 1] = pu1_src[j + 0];\n        }\n        pu1_dst += dst_strd;\n        pu1_src += src_strd;\n    }\n    return;\n}\n/**\n *******************************************************************************\n *\n * @brief Function used from copying a 420SP buffer\n *\n * @par   Description\n * Function used from copying a 420SP buffer\n *\n * @param[in] pu1_y_src\n *   Input Y pointer\n *\n * @param[in] pu1_uv_src\n *   Input UV pointer (UV is interleaved either in UV or VU format)\n *\n * @param[in] pu1_y_dst\n *   Output Y pointer\n *\n * @param[in] pu1_u_dst\n *   Output U pointer\n *\n * @param[in] pu1_v_dst\n *   Output V pointer\n *\n * @param[in] wd\n *   Width\n *\n * @param[in] ht\n *   Height\n *\n * @param[in] src_y_strd\n *   Input Y Stride\n *\n * @param[in] src_uv_strd\n *   Input UV stride\n *\n * @param[in] dst_y_strd\n *   Output Y stride\n *\n * @param[in] dst_uv_strd\n *   Output UV stride\n *\n * @param[in] is_u_first\n *   Flag to indicate if U is the first byte in input chroma part\n *\n * @returns none\n *\n * @remarks In case there is a need to perform partial frame copy then\n * by passion appropriate source and destination pointers and appropriate\n * values for wd and ht it can be done\n *\n *******************************************************************************\n */\n\nvoid ih264d_fmt_conv_420sp_to_420p(UWORD8 *pu1_y_src,\n                                   UWORD8 *pu1_uv_src,\n                                   UWORD8 *pu1_y_dst,\n                                   UWORD8 *pu1_u_dst,\n                                   UWORD8 *pu1_v_dst,\n                                   WORD32 wd,\n                                   WORD32 ht,\n                                   WORD32 src_y_strd,\n                                   WORD32 src_uv_strd,\n                                   WORD32 dst_y_strd,\n                                   WORD32 dst_uv_strd,\n                                   WORD32 is_u_first,\n                                   WORD32 disable_luma_copy)\n{\n    UWORD8 *pu1_src, *pu1_dst;\n    UWORD8 *pu1_u_src, *pu1_v_src;\n    WORD32 num_rows, num_cols, src_strd, dst_strd;\n    WORD32 i, j;\n\n    if(0 == disable_luma_copy)\n    {\n        /* copy luma */\n        pu1_src = (UWORD8 *)pu1_y_src;\n        pu1_dst = (UWORD8 *)pu1_y_dst;\n\n        num_rows = ht;\n        num_cols = wd;\n\n        src_strd = src_y_strd;\n        dst_strd = dst_y_strd;\n\n        for(i = 0; i < num_rows; i++)\n        {\n            memcpy(pu1_dst, pu1_src, num_cols);\n            pu1_dst += dst_strd;\n            pu1_src += src_strd;\n        }\n    }\n    /* de-interleave U and V and copy to destination */\n    if(is_u_first)\n    {\n        pu1_u_src = (UWORD8 *)pu1_uv_src;\n        pu1_v_src = (UWORD8 *)pu1_uv_src + 1;\n    }\n    else\n    {\n        pu1_u_src = (UWORD8 *)pu1_uv_src + 1;\n        pu1_v_src = (UWORD8 *)pu1_uv_src;\n    }\n\n    num_rows = ht >> 1;\n    num_cols = wd >> 1;\n\n    src_strd = src_uv_strd;\n    dst_strd = dst_uv_strd;\n\n    for(i = 0; i < num_rows; i++)\n    {\n        for(j = 0; j < num_cols; j++)\n        {\n            pu1_u_dst[j] = pu1_u_src[j * 2];\n            pu1_v_dst[j] = pu1_v_src[j * 2];\n        }\n\n        pu1_u_dst += dst_strd;\n        pu1_v_dst += dst_strd;\n        pu1_u_src += src_strd;\n        pu1_v_src += src_strd;\n    }\n    return;\n}\n\n/*****************************************************************************/\n/*  Function Name : ih264d_format_convert                                    */\n/*                                                                           */\n/*  Description   : Implements format conversion/frame copy                  */\n/*  Inputs        : ps_dec - Decoder parameters                              */\n/*  Globals       : None                                                     */\n/*  Processing    : Refer bumping process in the standard                    */\n/*  Outputs       : Assigns display sequence number.                         */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         27 04 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_format_convert(dec_struct_t *ps_dec,\n                           ivd_get_display_frame_op_t *pv_disp_op,\n                           UWORD32 u4_start_y,\n                           UWORD32 u4_num_rows_y)\n{\n    UWORD32 convert_uv_only = 0;\n    iv_yuv_buf_t *ps_op_frm;\n    UWORD8 *pu1_y_src, *pu1_uv_src;\n    UWORD32 start_uv = u4_start_y >> 1;\n\n    if(1 == pv_disp_op->u4_error_code)\n        return;\n\n    ps_op_frm = &(ps_dec->s_disp_frame_info);\n\n    /* Requires u4_start_y and u4_num_rows_y to be even */\n    if(u4_start_y & 1)\n    {\n        return;\n    }\n\n    if((1 == ps_dec->u4_share_disp_buf) &&\n       (pv_disp_op->e_output_format == IV_YUV_420SP_UV))\n    {\n        return;\n    }\n\n    pu1_y_src = (UWORD8 *)ps_op_frm->pv_y_buf;\n    pu1_y_src += u4_start_y * ps_op_frm->u4_y_strd,\n\n    pu1_uv_src = (UWORD8 *)ps_op_frm->pv_u_buf;\n    pu1_uv_src += start_uv * ps_op_frm->u4_u_strd;\n\n    if(pv_disp_op->e_output_format == IV_YUV_420P)\n    {\n        UWORD8 *pu1_y_dst, *pu1_u_dst, *pu1_v_dst;\n        IV_COLOR_FORMAT_T e_output_format = pv_disp_op->e_output_format;\n\n        if(0 == ps_dec->u4_share_disp_buf)\n        {\n            convert_uv_only = 0;\n        }\n        else\n        {\n            convert_uv_only = 1;\n        }\n\n        pu1_y_dst = (UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_y_buf;\n        pu1_y_dst += u4_start_y * pv_disp_op->s_disp_frm_buf.u4_y_strd;\n\n        pu1_u_dst = (UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_u_buf;\n        pu1_u_dst += start_uv * pv_disp_op->s_disp_frm_buf.u4_u_strd;\n\n        pu1_v_dst = (UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_v_buf;\n        pu1_v_dst += start_uv * pv_disp_op->s_disp_frm_buf.u4_v_strd;\n\n        ih264d_fmt_conv_420sp_to_420p(pu1_y_src,\n                                      pu1_uv_src,\n                                      pu1_y_dst,\n                                      pu1_u_dst,\n                                      pu1_v_dst,\n                                      ps_op_frm->u4_y_wd,\n                                      u4_num_rows_y,\n                                      ps_op_frm->u4_y_strd,\n                                      ps_op_frm->u4_u_strd,\n                                      pv_disp_op->s_disp_frm_buf.u4_y_strd,\n                                      pv_disp_op->s_disp_frm_buf.u4_u_strd,\n                                      1,\n                                      convert_uv_only);\n\n    }\n    else if((pv_disp_op->e_output_format == IV_YUV_420SP_UV) ||\n            (pv_disp_op->e_output_format == IV_YUV_420SP_VU))\n    {\n        UWORD8* pu1_y_dst, *pu1_uv_dst;\n\n        pu1_y_dst = (UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_y_buf;\n        pu1_y_dst +=  u4_start_y * pv_disp_op->s_disp_frm_buf.u4_y_strd;\n\n        pu1_uv_dst = (UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_u_buf;\n        pu1_uv_dst += start_uv * pv_disp_op->s_disp_frm_buf.u4_u_strd;\n\n        if(pv_disp_op->e_output_format == IV_YUV_420SP_UV)\n        {\n            ih264d_fmt_conv_420sp_to_420sp(pu1_y_src,\n                                           pu1_uv_src,\n                                           pu1_y_dst,\n                                           pu1_uv_dst,\n                                           ps_op_frm->u4_y_wd,\n                                           u4_num_rows_y,\n                                           ps_op_frm->u4_y_strd,\n                                           ps_op_frm->u4_u_strd,\n                                           pv_disp_op->s_disp_frm_buf.u4_y_strd,\n                                           pv_disp_op->s_disp_frm_buf.u4_u_strd);\n        }\n        else\n        {\n            ih264d_fmt_conv_420sp_to_420sp_swap_uv(pu1_y_src,\n                                                   pu1_uv_src,\n                                                   pu1_y_dst,\n                                                   pu1_uv_dst,\n                                                   ps_op_frm->u4_y_wd,\n                                                   u4_num_rows_y,\n                                                   ps_op_frm->u4_y_strd,\n                                                   ps_op_frm->u4_u_strd,\n                                                   pv_disp_op->s_disp_frm_buf.u4_y_strd,\n                                                   pv_disp_op->s_disp_frm_buf.u4_u_strd);\n        }\n    }\n    else if(pv_disp_op->e_output_format == IV_RGB_565)\n    {\n        UWORD16 *pu2_rgb_dst;\n\n        pu2_rgb_dst = (UWORD16 *)pv_disp_op->s_disp_frm_buf.pv_y_buf;\n        pu2_rgb_dst += u4_start_y * pv_disp_op->s_disp_frm_buf.u4_y_strd;\n\n        ih264d_fmt_conv_420sp_to_rgb565(pu1_y_src,\n                                        pu1_uv_src,\n                                        pu2_rgb_dst,\n                                        ps_op_frm->u4_y_wd,\n                                        u4_num_rows_y,\n                                        ps_op_frm->u4_y_strd,\n                                        ps_op_frm->u4_u_strd,\n                                        pv_disp_op->s_disp_frm_buf.u4_y_strd,\n                                        1);\n    }\n\n    if((u4_start_y + u4_num_rows_y) >= ps_dec->s_disp_frame_info.u4_y_ht)\n    {\n\n        INSERT_LOGO(pv_disp_op->s_disp_frm_buf.pv_y_buf,\n                        pv_disp_op->s_disp_frm_buf.pv_u_buf,\n                        pv_disp_op->s_disp_frm_buf.pv_v_buf,\n                        pv_disp_op->s_disp_frm_buf.u4_y_strd,\n                        ps_dec->u2_disp_width,\n                        ps_dec->u2_disp_height,\n                        pv_disp_op->e_output_format,\n                        ps_op_frm->u4_y_wd,\n                        ps_op_frm->u4_y_ht);\n    }\n\n    return;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_format_conv.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264d_format_conv.h                                */\n/*                                                                           */\n/*  Description       : Contains coefficients and constant reqquired for     */\n/*                      converting from rgb and gray color spaces to yuv422i */\n/*                      color space                                          */\n/*                                                                           */\n/*  List of Functions : None                                                 */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         27 08 2007  Naveen Kumar T        Draft                           */\n/*                                                                           */\n/*****************************************************************************/\n\n#ifndef _IH264D_FORMAT_CONV_H_\n#define _IH264D_FORMAT_CONV_H_\n\n/*****************************************************************************/\n/* Typedefs                                                                  */\n/*****************************************************************************/\n\n#define COEFF_0_Y       66\n#define COEFF_1_Y       129\n#define COEFF_2_Y       25\n#define COEFF_0_U       -38\n#define COEFF_1_U       -75\n#define COEFF_2_U       112\n#define COEFF_0_V       112\n#define COEFF_1_V       -94\n#define COEFF_2_V       -18\n#define CONST_RGB_YUV1  4096\n#define CONST_RGB_YUV2  32768\n#define CONST_GRAY_YUV  128\n#define COEF_2_V2_U  0xFFEE0070\n\n#define COF_2Y_0Y          0X00190042\n#define COF_1U_0U          0XFFB5FFDA\n#define COF_1V_0V          0XFFA20070\n\nvoid ih264d_fmt_conv_420sp_to_420p(UWORD8 *pu1_y_src,\n                                   UWORD8 *pu1_uv_src,\n                                   UWORD8 *pu1_y_dst,\n                                   UWORD8 *pu1_u_dst,\n                                   UWORD8 *pu1_v_dst,\n                                   WORD32 wd,\n                                   WORD32 ht,\n                                   WORD32 src_y_strd,\n                                   WORD32 src_uv_strd,\n                                   WORD32 dst_y_strd,\n                                   WORD32 dst_uv_strd,\n                                   WORD32 is_u_first,\n                                   WORD32 disable_luma_copy);\n\nvoid ih264d_fmt_conv_420sp_to_420sp_swap_uv(UWORD8 *pu1_y_src,\n                                            UWORD8 *pu1_uv_src,\n                                            UWORD8 *pu1_y_dst,\n                                            UWORD8 *pu1_uv_dst,\n                                            WORD32 wd,\n                                            WORD32 ht,\n                                            WORD32 src_y_strd,\n                                            WORD32 src_uv_strd,\n                                            WORD32 dst_y_strd,\n                                            WORD32 dst_uv_strd);\n\nvoid ih264d_fmt_conv_420sp_to_420sp(UWORD8 *pu1_y_src,\n                                    UWORD8 *pu1_uv_src,\n                                    UWORD8 *pu1_y_dst,\n                                    UWORD8 *pu1_uv_dst,\n                                    WORD32 wd,\n                                    WORD32 ht,\n                                    WORD32 src_y_strd,\n                                    WORD32 src_uv_strd,\n                                    WORD32 dst_y_strd,\n                                    WORD32 dst_uv_strd);\n\nvoid ih264d_fmt_conv_420sp_to_rgb565(UWORD8 *pu1_y_src,\n                                     UWORD8 *pu1_uv_src,\n                                     UWORD16 *pu2_rgb_dst,\n                                     WORD32 wd,\n                                     WORD32 ht,\n                                     WORD32 src_y_strd,\n                                     WORD32 src_uv_strd,\n                                     WORD32 dst_strd,\n                                     WORD32 is_u_first);\n#define COEFF1          13073\n#define COEFF2          -3207\n#define COEFF3          -6664\n#define COEFF4          16530\n\nvoid ih264d_format_convert(dec_struct_t *ps_dec,\n                           ivd_get_display_frame_op_t *pv_disp_op,\n                           UWORD32 u4_start_y,\n                           UWORD32 u4_num_rows_y);\n\n\n#endif /* _IH264D_FORMAT_CONV_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_function_selector.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/**\n *******************************************************************************\n * @file\n *  ih264d_function_selector.h\n *\n * @brief\n *  Structure definitions used in the decoder\n *\n * @author\n *  Harish\n *\n * @par List of Functions:\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n#ifndef _IH264D_FUNCTION_SELECTOR_H_\n#define _IH264D_FUNCTION_SELECTOR_H_\n\n#define D_ARCH_NA                   1\n#define D_ARCH_ARM_NONEON           2\n#define D_ARCH_ARM_A9Q              3\n#define D_ARCH_ARM_A9A              4\n#define D_ARCH_ARM_A9               5\n#define D_ARCH_ARM_A7               6\n#define D_ARCH_ARM_A5               7\n#define D_ARCH_ARM_A15              8\n#define D_ARCH_ARM_NEONINTR         9\n#define D_ARCH_ARMV8_GENERIC        10\n#define D_ARCH_X86_GENERIC          11\n#define D_ARCH_X86_SSSE3            12\n#define D_ARCH_X86_SSE42            13\n#define D_ARCH_X86_AVX2             14\n#define D_ARCH_MIPS_GENERIC         15\n#define D_ARCH_MIPS_32              16\n\nvoid ih264d_init_arch(dec_struct_t *ps_codec);\n\nvoid ih264d_init_function_ptr(dec_struct_t *ps_codec);\n\nvoid ih264d_init_function_ptr_generic(dec_struct_t *ps_codec);\nvoid ih264d_init_function_ptr_ssse3(dec_struct_t *ps_codec);\nvoid ih264d_init_function_ptr_sse42(dec_struct_t *ps_codec);\n\nvoid ih264d_init_function_ptr_a9q(dec_struct_t *ps_codec);\nvoid ih264d_init_function_ptr_av8(dec_struct_t *ps_codec);\n\n#endif /* _IH264D_FUNCTION_SELECTOR_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_function_selector_generic.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n *******************************************************************************\n * @file\n *  ih264e_function_selector_generic.c\n *\n * @brief\n *  Contains functions to initialize function pointers of codec context\n *\n * @author\n *  Ittiam\n *\n * @par List of Functions:\n *  - ih264e_init_function_ptr_generic\n *\n * @remarks\n *  None\n *\n *******************************************************************************\n */\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System Include files */\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* User Include files */\n#include \"ih264_typedefs.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_error.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include \"ih264_inter_pred_filters.h\"\n\n#include \"ih264d_structs.h\"\n#include \"ih264d_function_selector.h\"\n\n/**\n *******************************************************************************\n *\n * @brief Initialize the intra/inter/transform/deblk function pointers of\n * codec context\n *\n * @par Description: the current routine initializes the function pointers of\n * codec context basing on the architecture in use\n *\n * @param[in] ps_codec\n *  Codec context pointer\n *\n * @returns  none\n *\n * @remarks none\n *\n *******************************************************************************\n */\nvoid ih264d_init_function_ptr_generic(dec_struct_t *ps_codec)\n{\n\n    WORD32 i = 0;\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 16x16 */\n    ps_codec->apf_intra_pred_luma_16x16[0] =\n                    ih264_intra_pred_luma_16x16_mode_vert;\n    ps_codec->apf_intra_pred_luma_16x16[1] =\n                    ih264_intra_pred_luma_16x16_mode_horz;\n    ps_codec->apf_intra_pred_luma_16x16[2] =\n                    ih264_intra_pred_luma_16x16_mode_dc;\n    ps_codec->apf_intra_pred_luma_16x16[3] =\n                    ih264_intra_pred_luma_16x16_mode_plane;\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 4x4 */\n    ps_codec->apf_intra_pred_luma_4x4[0] = ih264_intra_pred_luma_4x4_mode_vert;\n    ps_codec->apf_intra_pred_luma_4x4[1] = ih264_intra_pred_luma_4x4_mode_horz;\n    ps_codec->apf_intra_pred_luma_4x4[2] = ih264_intra_pred_luma_4x4_mode_dc;\n    ps_codec->apf_intra_pred_luma_4x4[3] =\n                    ih264_intra_pred_luma_4x4_mode_diag_dl;\n    ps_codec->apf_intra_pred_luma_4x4[4] =\n                    ih264_intra_pred_luma_4x4_mode_diag_dr;\n    ps_codec->apf_intra_pred_luma_4x4[5] =\n                    ih264_intra_pred_luma_4x4_mode_vert_r;\n    ps_codec->apf_intra_pred_luma_4x4[6] =\n                    ih264_intra_pred_luma_4x4_mode_horz_d;\n    ps_codec->apf_intra_pred_luma_4x4[7] =\n                    ih264_intra_pred_luma_4x4_mode_vert_l;\n    ps_codec->apf_intra_pred_luma_4x4[8] =\n                    ih264_intra_pred_luma_4x4_mode_horz_u;\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 8x8 */\n    ps_codec->apf_intra_pred_luma_8x8[0] = ih264_intra_pred_luma_8x8_mode_vert;\n    ps_codec->apf_intra_pred_luma_8x8[1] = ih264_intra_pred_luma_8x8_mode_horz;\n    ps_codec->apf_intra_pred_luma_8x8[2] = ih264_intra_pred_luma_8x8_mode_dc;\n    ps_codec->apf_intra_pred_luma_8x8[3] =\n                    ih264_intra_pred_luma_8x8_mode_diag_dl;\n    ps_codec->apf_intra_pred_luma_8x8[4] =\n                    ih264_intra_pred_luma_8x8_mode_diag_dr;\n    ps_codec->apf_intra_pred_luma_8x8[5] =\n                    ih264_intra_pred_luma_8x8_mode_vert_r;\n    ps_codec->apf_intra_pred_luma_8x8[6] =\n                    ih264_intra_pred_luma_8x8_mode_horz_d;\n    ps_codec->apf_intra_pred_luma_8x8[7] =\n                    ih264_intra_pred_luma_8x8_mode_vert_l;\n    ps_codec->apf_intra_pred_luma_8x8[8] =\n                    ih264_intra_pred_luma_8x8_mode_horz_u;\n\n    ps_codec->pf_intra_pred_ref_filtering =\n                    ih264_intra_pred_luma_8x8_mode_ref_filtering;\n\n    /* Init function pointers for intra pred leaf level functions chroma\n     * Intra 8x8 */\n    ps_codec->apf_intra_pred_chroma[0] = ih264_intra_pred_chroma_8x8_mode_vert;\n    ps_codec->apf_intra_pred_chroma[1] = ih264_intra_pred_chroma_8x8_mode_horz;\n    ps_codec->apf_intra_pred_chroma[2] = ih264_intra_pred_chroma_8x8_mode_dc;\n    ps_codec->apf_intra_pred_chroma[3] = ih264_intra_pred_chroma_8x8_mode_plane;\n\n    ps_codec->pf_default_weighted_pred_luma = ih264_default_weighted_pred_luma;\n    ps_codec->pf_default_weighted_pred_chroma =\n                    ih264_default_weighted_pred_chroma;\n    ps_codec->pf_weighted_pred_luma = ih264_weighted_pred_luma;\n    ps_codec->pf_weighted_pred_chroma = ih264_weighted_pred_chroma;\n    ps_codec->pf_weighted_bi_pred_luma = ih264_weighted_bi_pred_luma;\n    ps_codec->pf_weighted_bi_pred_chroma = ih264_weighted_bi_pred_chroma;\n\n    /* Padding Functions */\n    ps_codec->pf_pad_top = ih264_pad_top;\n    ps_codec->pf_pad_bottom = ih264_pad_bottom;\n    ps_codec->pf_pad_left_luma = ih264_pad_left_luma;\n    ps_codec->pf_pad_left_chroma = ih264_pad_left_chroma;\n    ps_codec->pf_pad_right_luma = ih264_pad_right_luma;\n    ps_codec->pf_pad_right_chroma = ih264_pad_right_chroma;\n\n    ps_codec->pf_iquant_itrans_recon_luma_4x4 = ih264_iquant_itrans_recon_4x4;\n    ps_codec->pf_iquant_itrans_recon_luma_4x4_dc =\n                    ih264_iquant_itrans_recon_4x4_dc;\n    ps_codec->pf_iquant_itrans_recon_luma_8x8 = ih264_iquant_itrans_recon_8x8;\n    ps_codec->pf_iquant_itrans_recon_luma_8x8_dc =\n                    ih264_iquant_itrans_recon_8x8_dc;\n    ps_codec->pf_iquant_itrans_recon_chroma_4x4 =\n                    ih264_iquant_itrans_recon_chroma_4x4;\n    ps_codec->pf_iquant_itrans_recon_chroma_4x4_dc =\n                    ih264_iquant_itrans_recon_chroma_4x4_dc;\n    ps_codec->pf_ihadamard_scaling_4x4 = ih264_ihadamard_scaling_4x4;\n\n    /* Init fn ptr luma deblocking */\n    ps_codec->pf_deblk_luma_vert_bs4 = ih264_deblk_luma_vert_bs4;\n    ps_codec->pf_deblk_luma_vert_bslt4 = ih264_deblk_luma_vert_bslt4;\n    ps_codec->pf_deblk_luma_vert_bs4_mbaff = ih264_deblk_luma_vert_bs4_mbaff;\n    ps_codec->pf_deblk_luma_vert_bslt4_mbaff =\n                    ih264_deblk_luma_vert_bslt4_mbaff;\n\n    ps_codec->pf_deblk_luma_horz_bs4 = ih264_deblk_luma_horz_bs4;\n    ps_codec->pf_deblk_luma_horz_bslt4 = ih264_deblk_luma_horz_bslt4;\n\n    /* Init fn ptr chroma deblocking */\n    ps_codec->pf_deblk_chroma_vert_bs4 = ih264_deblk_chroma_vert_bs4;\n    ps_codec->pf_deblk_chroma_vert_bslt4 = ih264_deblk_chroma_vert_bslt4;\n    ps_codec->pf_deblk_chroma_vert_bs4_mbaff =\n                    ih264_deblk_chroma_vert_bs4_mbaff;\n    ps_codec->pf_deblk_chroma_vert_bslt4_mbaff =\n                    ih264_deblk_chroma_vert_bslt4_mbaff;\n\n    ps_codec->pf_deblk_chroma_horz_bs4 = ih264_deblk_chroma_horz_bs4;\n    ps_codec->pf_deblk_chroma_horz_bslt4 = ih264_deblk_chroma_horz_bslt4;\n\n    /* Inter pred leaf level functions */\n    ps_codec->apf_inter_pred_luma[0] = ih264_inter_pred_luma_copy;\n    ps_codec->apf_inter_pred_luma[1] = ih264_inter_pred_luma_horz_qpel;\n    ps_codec->apf_inter_pred_luma[2] = ih264_inter_pred_luma_horz;\n    ps_codec->apf_inter_pred_luma[3] = ih264_inter_pred_luma_horz_qpel;\n    ps_codec->apf_inter_pred_luma[4] = ih264_inter_pred_luma_vert_qpel;\n    ps_codec->apf_inter_pred_luma[5] =\n                    ih264_inter_pred_luma_horz_qpel_vert_qpel;\n    ps_codec->apf_inter_pred_luma[6] =\n                    ih264_inter_pred_luma_horz_hpel_vert_qpel;\n    ps_codec->apf_inter_pred_luma[7] =\n                    ih264_inter_pred_luma_horz_qpel_vert_qpel;\n    ps_codec->apf_inter_pred_luma[8] = ih264_inter_pred_luma_vert;\n    ps_codec->apf_inter_pred_luma[9] =\n                    ih264_inter_pred_luma_horz_qpel_vert_hpel;\n    ps_codec->apf_inter_pred_luma[10] =\n                    ih264_inter_pred_luma_horz_hpel_vert_hpel;\n    ps_codec->apf_inter_pred_luma[11] =\n                    ih264_inter_pred_luma_horz_qpel_vert_hpel;\n    ps_codec->apf_inter_pred_luma[12] = ih264_inter_pred_luma_vert_qpel;\n    ps_codec->apf_inter_pred_luma[13] =\n                    ih264_inter_pred_luma_horz_qpel_vert_qpel;\n    ps_codec->apf_inter_pred_luma[14] =\n                    ih264_inter_pred_luma_horz_hpel_vert_qpel;\n    ps_codec->apf_inter_pred_luma[15] =\n                    ih264_inter_pred_luma_horz_qpel_vert_qpel;\n\n    ps_codec->pf_inter_pred_chroma = ih264_inter_pred_chroma;\n\n    return;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_inter_pred.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n * \\file ih264d_inter_pred.c\n *\n * \\brief\n *    This file contains routines to perform MotionCompensation tasks\n *\n * Detailed_description\n *\n * \\date\n *    20/11/2002\n *\n * \\author  Arvind Raman\n **************************************************************************\n */\n\n#include <string.h>\n#include \"ih264d_defs.h\"\n#include \"ih264d_mvpred.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_inter_pred.h\"\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_mb_utils.h\"\n\n\nvoid ih264d_pad_on_demand(pred_info_t *ps_pred, UWORD8 lum_chrom_blk);\n\n\n\nvoid ih264d_copy_multiplex_data(UWORD8 *puc_Source,\n                                UWORD8 *puc_To,\n                                UWORD32 uc_w,\n                                UWORD32 uc_h,\n                                UWORD32 ui16_sourceWidth,\n                                UWORD32 ui16_toWidth)\n{\n    UWORD8 uc_i, uc_j;\n\n    for(uc_i = 0; uc_i < uc_h; uc_i++)\n    {\n        memcpy(puc_To, puc_Source, uc_w);\n        puc_To += ui16_toWidth;\n        puc_Source += ui16_sourceWidth;\n    }\n}\n\n\n/*!\n **************************************************************************\n * \\if Function name : dma_2d1d \\endif\n *\n * \\brief\n *    2D -> 1D linear DMA into the reference buffers\n *\n * \\return\n *    None\n **************************************************************************\n */\nvoid ih264d_copy_2d1d(UWORD8 *puc_src,\n                      UWORD8 *puc_dest,\n                      UWORD16 ui16_srcWidth,\n                      UWORD16 ui16_widthToFill,\n                      UWORD16 ui16_heightToFill)\n{\n    UWORD32 uc_w, uc_h;\n    for(uc_h = ui16_heightToFill; uc_h != 0; uc_h--)\n    {\n        memcpy(puc_dest, puc_src, ui16_widthToFill);\n        puc_dest += ui16_widthToFill;\n        puc_src += ui16_srcWidth;\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_fill_pred_info \\endif\n *\n * \\brief\n *    Fills inter prediction related info\n *\n * \\return\n *    None\n **************************************************************************\n */\nvoid ih264d_fill_pred_info(WORD16 *pi2_mv,WORD32 part_width,WORD32 part_height, WORD32 sub_mb_num,\n                           WORD32 pred_dir,pred_info_pkd_t *ps_pred_pkd,WORD8 i1_buf_id,\n                           WORD8 i1_ref_idx,UWORD32 *pu4_wt_offset,UWORD8 u1_pic_type)\n{\n    WORD32 insert_bits;\n\n    ps_pred_pkd->i2_mv[0] = pi2_mv[0];\n    ps_pred_pkd->i2_mv[1] = pi2_mv[1];\n\n    insert_bits = sub_mb_num & 3; /*sub mb x*/\n    ps_pred_pkd->i1_size_pos_info = insert_bits;\n    insert_bits = sub_mb_num >> 2;/*sub mb y*/\n    ps_pred_pkd->i1_size_pos_info |= insert_bits << 2;\n    insert_bits = part_width >> 1;\n    ps_pred_pkd->i1_size_pos_info |= insert_bits << 4;\n    insert_bits = part_height >> 1;\n    ps_pred_pkd->i1_size_pos_info |= insert_bits << 6;\n\n    ps_pred_pkd->i1_ref_idx_info = i1_ref_idx;\n    ps_pred_pkd->i1_ref_idx_info |= (pred_dir << 6);\n    ps_pred_pkd->i1_buf_id = i1_buf_id;\n    ps_pred_pkd->pu4_wt_offst = pu4_wt_offset;\n    ps_pred_pkd->u1_pic_type = u1_pic_type;\n\n\n}\n\n\n\n\n\n\n\n/*****************************************************************************/\n/* \\if Function name : formMbPartInfo \\endif                                 */\n/*                                                                           */\n/* \\brief                                                                    */\n/*    Form the Mb partition information structure, to be used by the MC      */\n/*    routine                                                                */\n/*                                                                           */\n/* \\return                                                                   */\n/*    None                                                                   */\n/* \\note                                                                     */\n/*    c_bufx is used to select PredBuffer,                                   */\n/*    if it's only Forward/Backward prediction always buffer used is         */\n/*    puc_MbLumaPredBuffer[0 to X1],pu1_mb_cb_pred_buffer[0 to X1] and          */\n/*    pu1_mb_cr_pred_buffer[0 to X1]                                            */\n/*                                                                           */\n/*    if it's bidirect for forward ..PredBuffer[0 to X1] buffer is used and  */\n/*    ..PredBuffer[X2 to X3] for backward prediction. and                    */\n/*                                                                           */\n/*    Final predicted samples values are the average of ..PredBuffer[0 to X1]*/\n/*    and ..PredBuffer[X2 to X3]                                             */\n/*                                                                           */\n/*    X1 is 255 for Luma and 63 for Chroma                                   */\n/*    X2 is 256 for Luma and 64 for Chroma                                   */\n/*    X3 is 511 for Luma and 127 for Chroma                                  */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         11 05 2005   SWRN            Modified to handle pod               */\n/*****************************************************************************/\n\nWORD32 ih264d_form_mb_part_info_bp(pred_info_pkd_t *ps_pred_pkd,\n                                 dec_struct_t * ps_dec,\n                                 UWORD16 u2_mb_x,\n                                 UWORD16 u2_mb_y,\n                                 WORD32 mb_index,\n                                 dec_mb_info_t *ps_cur_mb_info)\n{\n    /* The reference buffer pointer */\n    WORD32 i2_frm_x, i2_frm_y;\n    WORD32 i2_tmp_mv_x, i2_tmp_mv_y;\n    WORD32 i2_rec_x, i2_rec_y;\n\n    WORD32 u2_pic_ht;\n    WORD32 u2_frm_wd;\n    WORD32 u2_rec_wd;\n    UWORD8 u1_sub_x = 0,u1_sub_y=0 ;\n    UWORD8  u1_part_wd = 0,u1_part_ht = 0;\n    WORD16 i2_mv_x,i2_mv_y;\n\n    /********************************************/\n    /* i1_mc_wd       width reqd for mcomp      */\n    /* u1_dma_ht      height reqd for mcomp     */\n    /* u1_dma_wd      width aligned to 4 bytes  */\n    /* u1_dx          fractional part of width  */\n    /* u1_dx          fractional part of height */\n    /********************************************/\n    UWORD32 i1_mc_wd;\n\n    WORD32 u1_dma_ht;\n\n    UWORD32 u1_dma_wd;\n    UWORD32 u1_dx;\n    UWORD32 u1_dy;\n    pred_info_t * ps_pred = ps_dec->ps_pred + ps_dec->u4_pred_info_idx;\n    dec_slice_params_t * const ps_cur_slice = ps_dec->ps_cur_slice;\n    tfr_ctxt_t *ps_frame_buf;\n    struct pic_buffer_t *ps_ref_frm;\n    UWORD8 u1_scale_ref,u1_mbaff,u1_field;\n    pic_buffer_t  **pps_ref_frame;\n    WORD8 i1_size_pos_info,i1_buf_id;\n\n    PROFILE_DISABLE_MB_PART_INFO()\n\n     UNUSED(ps_cur_mb_info);\n     i1_size_pos_info = ps_pred_pkd->i1_size_pos_info;\n     GET_XPOS_PRED(u1_sub_x,i1_size_pos_info);\n     GET_YPOS_PRED(u1_sub_y,i1_size_pos_info);\n     GET_WIDTH_PRED(u1_part_wd,i1_size_pos_info);\n     GET_HEIGHT_PRED(u1_part_ht,i1_size_pos_info);\n     i2_mv_x = ps_pred_pkd->i2_mv[0];\n     i2_mv_y = ps_pred_pkd->i2_mv[1];\n     i1_buf_id = ps_pred_pkd->i1_buf_id;\n\n\n     ps_ref_frm = ps_dec->apv_buf_id_pic_buf_map[i1_buf_id];\n\n\n    {\n        ps_frame_buf = &ps_dec->s_tran_addrecon;\n    }\n\n\n    /* Transfer Setup Y */\n    {\n        UWORD8 *pu1_pred, *pu1_rec;\n\n        /* calculating rounded motion vectors and fractional components */\n        i2_tmp_mv_x = i2_mv_x;\n        i2_tmp_mv_y = i2_mv_y;\n        u1_dx = i2_tmp_mv_x & 0x3;\n        u1_dy = i2_tmp_mv_y & 0x3;\n        i2_tmp_mv_x >>= 2;\n        i2_tmp_mv_y >>= 2;\n        i1_mc_wd = u1_part_wd << 2;\n        u1_dma_ht = u1_part_ht << 2;\n        if(u1_dx)\n        {\n            i2_tmp_mv_x -= 2;\n            i1_mc_wd += 5;\n        }\n        if(u1_dy)\n        {\n            i2_tmp_mv_y -= 2;\n            u1_dma_ht += 5;\n        }\n\n        /********************************************************************/\n        /* Calulating the horizontal and the vertical u4_ofst from top left  */\n        /* edge of the reference frame, and subsequent clipping             */\n        /********************************************************************/\n        u2_pic_ht = ps_dec->u2_pic_ht;\n        u2_frm_wd = ps_dec->u2_frm_wd_y;\n        i2_rec_x = u1_sub_x << 2;\n        i2_rec_y = u1_sub_y << 2;\n\n        i2_frm_x = (u2_mb_x << 4) + i2_rec_x + i2_tmp_mv_x;\n        i2_frm_y = (u2_mb_y << 4) + i2_rec_y + i2_tmp_mv_y;\n\n        i2_frm_x = CLIP3(MAX_OFFSET_OUTSIDE_X_FRM, (ps_dec->u2_pic_wd - 1),\n                         i2_frm_x);\n        i2_frm_y = CLIP3(((1 - u1_dma_ht)), (u2_pic_ht - (1)), i2_frm_y);\n\n        pu1_pred = ps_ref_frm->pu1_buf1 + i2_frm_y * u2_frm_wd + i2_frm_x;\n\n        u1_dma_wd = (i1_mc_wd + 3) & 0xFC;\n\n        /********************************************************************/\n        /* Calulating the horizontal and the vertical u4_ofst from top left  */\n        /* edge of the recon buffer                                         */\n        /********************************************************************/\n        u2_rec_wd = MB_SIZE;\n        {\n            u2_rec_wd = ps_dec->u2_frm_wd_y;\n            i2_rec_x += (mb_index << 4);\n            pu1_rec = ps_frame_buf->pu1_dest_y + i2_rec_y * u2_rec_wd\n                            + i2_rec_x;\n        }\n\n        /* filling the pred and dma structures for Y */\n        u2_frm_wd = ps_dec->u2_frm_wd_y;\n\n        ps_pred->u2_u1_ref_buf_wd = u1_dma_wd;\n        ps_pred->i1_dma_ht = u1_dma_ht;\n        ps_pred->i1_mc_wd = i1_mc_wd;\n        ps_pred->u2_frm_wd = u2_frm_wd;\n        ps_pred->pu1_rec_y_u = pu1_rec;\n        ps_pred->u2_dst_stride = u2_rec_wd;\n\n        ps_pred->i1_mb_partwidth = u1_part_wd << 2;\n        ps_pred->i1_mb_partheight = u1_part_ht << 2;\n        ps_pred->u1_dydx = (u1_dy << 2) + u1_dx;\n\n        ps_pred->pu1_y_ref = pu1_pred;\n\n    }\n\n    /* Increment ps_pred index */\n    ps_pred++;\n\n    /* Transfer Setup U & V */\n    {\n        WORD32 i4_ref_offset, i4_rec_offset;\n        UWORD8 *pu1_pred_u, *pu1_pred_v;\n\n\n        /* calculating rounded motion vectors and fractional components */\n        i2_tmp_mv_x = i2_mv_x;\n        i2_tmp_mv_y = i2_mv_y;\n\n        /************************************************************************/\n        /* Table 8-9: Derivation of the vertical component of the chroma vector */\n        /* in field coding mode                                                 */\n        /************************************************************************/\n\n        /* Eighth sample of the chroma MV */\n        u1_dx = i2_tmp_mv_x & 0x7;\n        u1_dy = i2_tmp_mv_y & 0x7;\n\n        /********************************************************************/\n        /* Calculating the full pel MV for chroma which is 1/2 of the Luma  */\n        /* MV in full pel units                                             */\n        /********************************************************************/\n        i2_mv_x = i2_tmp_mv_x;\n        i2_mv_y = i2_tmp_mv_y;\n        i2_tmp_mv_x = SIGN_POW2_DIV(i2_tmp_mv_x, 3);\n        i2_tmp_mv_y = SIGN_POW2_DIV(i2_tmp_mv_y, 3);\n        i1_mc_wd = u1_part_wd << 1;\n        u1_dma_ht = u1_part_ht << 1;\n        if(u1_dx)\n        {\n            i2_tmp_mv_x -= (i2_mv_x < 0);\n            i1_mc_wd++;\n        }\n        if(u1_dy != 0)\n        {\n            i2_tmp_mv_y -= (i2_mv_y < 0);\n            u1_dma_ht++;\n        }\n\n        /********************************************************************/\n        /* Calulating the horizontal and the vertical u4_ofst from top left  */\n        /* edge of the reference frame, and subsequent clipping             */\n        /********************************************************************/\n        u2_pic_ht >>= 1;\n        u2_frm_wd = ps_dec->u2_frm_wd_uv;\n        i2_rec_x = u1_sub_x << 1;\n        i2_rec_y = u1_sub_y << 1;\n\n        i2_frm_x = (u2_mb_x << 3) + i2_rec_x + i2_tmp_mv_x;\n        i2_frm_y = (u2_mb_y << 3) + i2_rec_y + i2_tmp_mv_y;\n\n        i2_frm_x = CLIP3(MAX_OFFSET_OUTSIDE_UV_FRM,\n                         ((ps_dec->u2_pic_wd >> 1) - 1), i2_frm_x);\n        i2_frm_y = CLIP3(((1 - u1_dma_ht)), (u2_pic_ht - (1)), i2_frm_y);\n\n        i4_ref_offset = i2_frm_y * u2_frm_wd + i2_frm_x * YUV420SP_FACTOR;\n        u1_dma_wd = (i1_mc_wd + 3) & 0xFC;\n\n        /********************************************************************/\n        /* Calulating the horizontal and the vertical u4_ofst from top left  */\n        /* edge of the recon buffer                                         */\n        /********************************************************************/\n        /* CHANGED CODE */\n        u2_rec_wd = BLK8x8SIZE * YUV420SP_FACTOR;\n        i4_rec_offset = i2_rec_y * u2_rec_wd + i2_rec_x * YUV420SP_FACTOR;\n\n        {\n            u2_rec_wd = ps_dec->u2_frm_wd_uv;\n            i2_rec_x += (mb_index << 3);\n            i4_rec_offset = i2_rec_y * u2_rec_wd + i2_rec_x * YUV420SP_FACTOR;\n            ps_pred->pu1_rec_y_u = ps_frame_buf->pu1_dest_u + i4_rec_offset;\n            ps_pred->u1_pi1_wt_ofst_rec_v = ps_frame_buf->pu1_dest_v\n                            + i4_rec_offset;\n        }\n\n        /* CHANGED CODE */\n\n        /* filling the common pred structures for U */\n        u2_frm_wd = ps_dec->u2_frm_wd_uv;\n\n        ps_pred->u2_u1_ref_buf_wd = u1_dma_wd;\n        ps_pred->i1_dma_ht = u1_dma_ht;\n        ps_pred->i1_mc_wd = i1_mc_wd;\n\n        ps_pred->u2_frm_wd = u2_frm_wd;\n        ps_pred->u2_dst_stride = u2_rec_wd;\n\n        ps_pred->i1_mb_partwidth = u1_part_wd << 1;\n        ps_pred->i1_mb_partheight = u1_part_ht << 1;\n        ps_pred->u1_dydx = (u1_dy << 3) + u1_dx;\n\n        pu1_pred_u = ps_ref_frm->pu1_buf2 + i4_ref_offset;\n        pu1_pred_v = ps_ref_frm->pu1_buf3 + i4_ref_offset;\n\n        /* Copy U & V partitions */\n        ps_pred->pu1_u_ref = pu1_pred_u;\n\n        /* Increment the reference buffer Index */\n        ps_pred->pu1_v_ref = pu1_pred_v;\n    }\n\n    /* Increment ps_pred index */\n    ps_dec->u4_pred_info_idx += 2;\n\n    return OK;\n\n}\n\n\n/*****************************************************************************/\n/* \\if Function name : formMbPartInfo \\endif                                 */\n/*                                                                           */\n/* \\brief                                                                    */\n/*    Form the Mb partition information structure, to be used by the MC      */\n/*    routine                                                                */\n/*                                                                           */\n/* \\return                                                                   */\n/*    None                                                                   */\n/* \\note                                                                     */\n/*    c_bufx is used to select PredBuffer,                                   */\n/*    if it's only Forward/Backward prediction always buffer used is         */\n/*    puc_MbLumaPredBuffer[0 to X1],pu1_mb_cb_pred_buffer[0 to X1] and          */\n/*    pu1_mb_cr_pred_buffer[0 to X1]                                            */\n/*                                                                           */\n/*    if it's bidirect for forward ..PredBuffer[0 to X1] buffer is used and  */\n/*    ..PredBuffer[X2 to X3] for backward prediction. and                    */\n/*                                                                           */\n/*    Final predicted samples values are the average of ..PredBuffer[0 to X1]*/\n/*    and ..PredBuffer[X2 to X3]                                             */\n/*                                                                           */\n/*    X1 is 255 for Luma and 63 for Chroma                                   */\n/*    X2 is 256 for Luma and 64 for Chroma                                   */\n/*    X3 is 511 for Luma and 127 for Chroma                                  */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         11 05 2005   SWRN            Modified to handle pod               */\n/*****************************************************************************/\nWORD32 ih264d_form_mb_part_info_mp(pred_info_pkd_t *ps_pred_pkd,\n                                 dec_struct_t * ps_dec,\n                                 UWORD16 u2_mb_x,\n                                 UWORD16 u2_mb_y,\n                                 WORD32 mb_index,\n                                 dec_mb_info_t *ps_cur_mb_info)\n{\n    /* The reference buffer pointer */\n    UWORD8 *pu1_ref_buf;\n    WORD16 i2_frm_x, i2_frm_y, i2_tmp_mv_x, i2_tmp_mv_y, i2_pod_ht;\n    WORD16 i2_rec_x, i2_rec_y;\n    UWORD16 u2_pic_ht, u2_frm_wd, u2_rec_wd;\n    UWORD8 u1_wght_pred_type, u1_wted_bipred_idc;\n    UWORD16 u2_tot_ref_scratch_size;\n    UWORD8 u1_sub_x = 0;\n    UWORD8 u1_sub_y = 0;\n    UWORD8 u1_is_bi_dir = 0;\n\n    /********************************************/\n    /* i1_mc_wd       width reqd for mcomp      */\n    /* u1_dma_ht      height reqd for mcomp     */\n    /* u1_dma_wd      width aligned to 4 bytes  */\n    /* u1_dx          fractional part of width  */\n    /* u1_dx          fractional part of height */\n    /********************************************/\n    UWORD8 i1_mc_wd, u1_dma_ht, u1_dma_wd, u1_dx, u1_dy;\n    pred_info_t * ps_pred ;\n    dec_slice_params_t * const ps_cur_slice = ps_dec->ps_cur_slice;\n    const UWORD8 u1_slice_type = ps_dec->ps_decode_cur_slice->slice_type;\n    UWORD8 u1_pod_bot, u1_pod_top;\n\n    /* load the pictype for pod u4_flag & chroma motion vector derivation */\n    UWORD8 u1_ref_pic_type ;\n\n    /* set default value to flags specifying field nature of picture & mb */\n    UWORD32 u1_mb_fld = 0, u1_mb_or_pic_fld;\n    UWORD32 u1_mb_bot = 0, u1_pic_bot = 0, u1_mb_or_pic_bot;\n    tfr_ctxt_t *ps_frame_buf;\n    /* calculate flags specifying field nature of picture & mb */\n    const UWORD32 u1_pic_fld = ps_cur_slice->u1_field_pic_flag;\n    WORD8 i1_pred;\n    WORD8 i1_size_pos_info,i1_buf_id,i1_ref_idx;\n    UWORD8 u1_part_wd,u1_part_ht;\n    WORD16 i2_mv_x,i2_mv_y;\n    struct pic_buffer_t *ps_ref_frm;\n    UWORD32 *pu4_wt_offset;\n    UWORD8 *pu1_buf1,*pu1_buf2,*pu1_buf3;\n\n\n    PROFILE_DISABLE_MB_PART_INFO()\n\n    ps_pred = ps_dec->ps_pred + ps_dec->u4_pred_info_idx;\n\n\n     i1_size_pos_info = ps_pred_pkd->i1_size_pos_info;\n     GET_XPOS_PRED(u1_sub_x,i1_size_pos_info);\n     GET_YPOS_PRED(u1_sub_y,i1_size_pos_info);\n     GET_WIDTH_PRED(u1_part_wd,i1_size_pos_info);\n     GET_HEIGHT_PRED(u1_part_ht,i1_size_pos_info);\n     i2_mv_x = ps_pred_pkd->i2_mv[0];\n     i2_mv_y = ps_pred_pkd->i2_mv[1];\n     i1_ref_idx = ps_pred_pkd->i1_ref_idx_info & 0x3f;\n     i1_buf_id = ps_pred_pkd->i1_buf_id;\n     ps_ref_frm = ps_dec->apv_buf_id_pic_buf_map[i1_buf_id];\n\n     i1_pred = (ps_pred_pkd->i1_ref_idx_info & 0xC0) >> 6;\n     u1_is_bi_dir = (i1_pred == BI_PRED);\n\n\n    u1_ref_pic_type = ps_pred_pkd->u1_pic_type & PIC_MASK;\n\n    pu1_buf1  = ps_ref_frm->pu1_buf1;\n    pu1_buf2  = ps_ref_frm->pu1_buf2;\n    pu1_buf3  = ps_ref_frm->pu1_buf3;\n\n    if(u1_ref_pic_type == BOT_FLD)\n    {\n        pu1_buf1 += ps_ref_frm->u2_frm_wd_y;\n        pu1_buf2 += ps_ref_frm->u2_frm_wd_uv;\n        pu1_buf3 += ps_ref_frm->u2_frm_wd_uv;\n\n    }\n\n\n\n    if(ps_dec->ps_cur_pps->u1_wted_pred_flag)\n    {\n            pu4_wt_offset = (UWORD32*)&ps_dec->pu4_wt_ofsts[2\n                            * X3(i1_ref_idx)];\n    }\n\n\n    pu4_wt_offset = ps_pred_pkd->pu4_wt_offst;\n\n\n    /* Pointer to the frame buffer */\n    {\n        ps_frame_buf = &ps_dec->s_tran_addrecon;\n        /* CHANGED CODE */\n    }\n\n    if(!u1_pic_fld)\n    {\n        u1_mb_fld = ps_cur_mb_info->u1_mb_field_decodingflag;\n        u1_mb_bot = 1 - ps_cur_mb_info->u1_topmb;\n    }\n    else\n        u1_pic_bot = ps_cur_slice->u1_bottom_field_flag;\n\n    /****************************************************************/\n    /* calculating the flags the tell whether to use frame-padding  */\n    /* or use software pad-on-demand                                */\n    /****************************************************************/\n    u1_mb_or_pic_bot = u1_mb_bot | u1_pic_bot;\n    u1_mb_or_pic_fld = u1_mb_fld | u1_pic_fld;\n    u1_pod_bot = u1_mb_or_pic_fld && (u1_ref_pic_type == TOP_FLD);\n    u1_pod_top = u1_mb_or_pic_fld && (u1_ref_pic_type == BOT_FLD);\n\n    /* Weighted Pred additions */\n    u1_wted_bipred_idc = ps_dec->ps_cur_pps->u1_wted_bipred_idc;\n\n    if((u1_slice_type == P_SLICE) || (u1_slice_type == SP_SLICE))\n    {\n        /* P Slice only */\n        u1_wght_pred_type = ps_dec->ps_cur_pps->u1_wted_pred_flag;\n\n    }\n    else\n    {\n        /* B Slice only */\n        u1_wght_pred_type = 1 + u1_is_bi_dir;\n        if(u1_wted_bipred_idc == 0)\n            u1_wght_pred_type = 0;\n        if((u1_wted_bipred_idc == 2) && (!u1_is_bi_dir))\n            u1_wght_pred_type = 0;\n    }\n    /* load the scratch reference buffer index */\n    pu1_ref_buf = ps_dec->pu1_ref_buff + ps_dec->u4_dma_buf_idx;\n    u2_tot_ref_scratch_size = 0;\n\n\n    /* Transfer Setup Y */\n    {\n        UWORD8 *pu1_pred, *pu1_rec;\n        /* calculating rounded motion vectors and fractional components */\n        i2_tmp_mv_x = i2_mv_x;\n        i2_tmp_mv_y = i2_mv_y;\n\n        u1_dx = i2_tmp_mv_x & 0x3;\n        u1_dy = i2_tmp_mv_y & 0x3;\n        i2_tmp_mv_x >>= 2;\n        i2_tmp_mv_y >>= 2;\n        i1_mc_wd = u1_part_wd << 2;\n        u1_dma_ht = u1_part_ht << 2;\n        if(u1_dx)\n        {\n            i2_tmp_mv_x -= 2;\n            i1_mc_wd += 5;\n        }\n        if(u1_dy)\n        {\n            i2_tmp_mv_y -= 2;\n            u1_dma_ht += 5;\n        }\n\n        /********************************************************************/\n        /* Calulating the horizontal and the vertical u4_ofst from top left  */\n        /* edge of the reference frame, and subsequent clipping             */\n        /********************************************************************/\n        u2_pic_ht = ps_dec->u2_pic_ht >> u1_pic_fld;\n        u2_frm_wd = ps_dec->u2_frm_wd_y << u1_pic_fld;\n        i2_frm_x = (u2_mb_x << 4) + (u1_sub_x << 2) + i2_tmp_mv_x;\n        i2_frm_y = ((u2_mb_y + (u1_mb_bot && !u1_mb_fld)) << 4)\n                        + (((u1_sub_y << 2) + i2_tmp_mv_y) << u1_mb_fld);\n\n        i2_frm_x = CLIP3(MAX_OFFSET_OUTSIDE_X_FRM, (ps_dec->u2_pic_wd - 1),\n                         i2_frm_x);\n        i2_frm_y = CLIP3(((1 - u1_dma_ht) << u1_mb_fld),\n                         (u2_pic_ht - (1 << u1_mb_fld)), i2_frm_y);\n\n        pu1_pred = pu1_buf1 + i2_frm_y * u2_frm_wd + i2_frm_x;\n        u1_dma_wd = (i1_mc_wd + 3) & 0xFC;\n        /********************************************************************/\n        /* Calulating the horizontal and the vertical u4_ofst from top left  */\n        /* edge of the recon buffer                                         */\n        /********************************************************************/\n        /* CHANGED CODE */\n        u2_rec_wd = MB_SIZE;\n        i2_rec_x = u1_sub_x << 2;\n        i2_rec_y = u1_sub_y << 2;\n        {\n            u2_rec_wd = ps_dec->u2_frm_wd_y << u1_mb_or_pic_fld;\n            i2_rec_x += (mb_index << 4);\n            pu1_rec = ps_frame_buf->pu1_dest_y + i2_rec_y * u2_rec_wd\n                            + i2_rec_x;\n            if(u1_mb_bot)\n                pu1_rec += ps_dec->u2_frm_wd_y << ((u1_mb_fld) ? 0 : 4);\n        }\n\n        /* CHANGED CODE */\n\n        /* filling the pred and dma structures for Y */\n        u2_frm_wd = ps_dec->u2_frm_wd_y << u1_mb_or_pic_fld;\n\n        ps_pred->pu1_dma_dest_addr = pu1_ref_buf;\n        ps_pred->u2_u1_ref_buf_wd = u1_dma_wd;\n        ps_pred->u2_frm_wd = u2_frm_wd;\n        ps_pred->i1_dma_ht = u1_dma_ht;\n        ps_pred->i1_mc_wd = i1_mc_wd;\n        ps_pred->pu1_rec_y_u = pu1_rec;\n        ps_pred->u2_dst_stride = u2_rec_wd;\n\n        ps_pred->i1_mb_partwidth = u1_part_wd << 2;\n        ps_pred->i1_mb_partheight = u1_part_ht << 2;\n        ps_pred->u1_dydx = (u1_dy << 2) + u1_dx;\n        ps_pred->u1_is_bi_direct = u1_is_bi_dir;\n        ps_pred->u1_pi1_wt_ofst_rec_v = (UWORD8 *)pu4_wt_offset;\n        ps_pred->u1_wght_pred_type = u1_wght_pred_type;\n        ps_pred->i1_pod_ht = 0;\n\n        /* Increment the Reference buffer Indices */\n        pu1_ref_buf += u1_dma_wd * u1_dma_ht;\n        u2_tot_ref_scratch_size += u1_dma_wd * u1_dma_ht;\n\n        /* unrestricted field motion comp for top region outside frame */\n        i2_pod_ht = (-i2_frm_y) >> u1_mb_fld;\n        if((i2_pod_ht > 0) && u1_pod_top)\n        {\n            ps_pred->i1_pod_ht = (WORD8)(-i2_pod_ht);\n            u1_dma_ht -= i2_pod_ht;\n            pu1_pred += i2_pod_ht * u2_frm_wd;\n        }\n        /* unrestricted field motion comp for bottom region outside frame */\n        else if(u1_pod_bot)\n        {\n            i2_pod_ht = u1_dma_ht + ((i2_frm_y - u2_pic_ht) >> u1_mb_fld);\n            if(i2_pod_ht > 0)\n            {\n                u1_dma_ht -= i2_pod_ht;\n                ps_pred->i1_pod_ht = (WORD8)i2_pod_ht;\n            }\n        }\n\n        /* Copy Y partition */\n\n        /*\n         * ps_pred->i1_pod_ht is non zero when MBAFF is present. In case of MBAFF the reference data\n         * is copied in the Scrath buffer so that the padding_on_demand doesnot corrupt the frame data\n         */\n        if(ps_pred->i1_pod_ht)\n        {\n            ps_pred->pu1_pred = pu1_pred;\n            ps_pred->u1_dma_ht_y = u1_dma_ht;\n            ps_pred->u1_dma_wd_y = u1_dma_wd;\n        }\n        ps_pred->pu1_y_ref = pu1_pred;\n    }\n\n\n\n    /* Increment ps_pred index */\n    ps_pred++;\n\n    /* Transfer Setup U & V */\n    {\n        WORD32 i4_ref_offset, i4_rec_offset;\n        UWORD8 *pu1_pred_u, *pu1_pred_v, u1_tmp_dma_ht;\n        /* CHANGED CODE */\n        UWORD8 u1_chroma_cbp = (UWORD8)(ps_cur_mb_info->u1_cbp >> 4);\n        /* CHANGED CODE */\n\n        /* calculating rounded motion vectors and fractional components */\n        i2_tmp_mv_x = i2_mv_x;\n        i2_tmp_mv_y = i2_mv_y;\n\n        /************************************************************************/\n        /* Table 8-9: Derivation of the vertical component of the chroma vector */\n        /* in field coding mode                                                 */\n        /************************************************************************/\n        if(u1_pod_bot && u1_mb_or_pic_bot)\n            i2_tmp_mv_y += 2;\n        if(u1_pod_top && !u1_mb_or_pic_bot)\n            i2_tmp_mv_y -= 2;\n\n        /* Eighth sample of the chroma MV */\n        u1_dx = i2_tmp_mv_x & 0x7;\n        u1_dy = i2_tmp_mv_y & 0x7;\n\n        /********************************************************************/\n        /* Calculating the full pel MV for chroma which is 1/2 of the Luma  */\n        /* MV in full pel units                                             */\n        /********************************************************************/\n        i2_mv_x = i2_tmp_mv_x;\n        i2_mv_y = i2_tmp_mv_y;\n        i2_tmp_mv_x = SIGN_POW2_DIV(i2_tmp_mv_x, 3);\n        i2_tmp_mv_y = SIGN_POW2_DIV(i2_tmp_mv_y, 3);\n        i1_mc_wd = u1_part_wd << 1;\n        u1_dma_ht = u1_part_ht << 1;\n        if(u1_dx)\n        {\n            if(i2_mv_x < 0)\n                i2_tmp_mv_x -= 1;\n            i1_mc_wd++;\n        }\n        if(u1_dy != 0)\n        {\n            if(i2_mv_y < 0)\n                i2_tmp_mv_y -= 1;\n            u1_dma_ht++;\n        }\n\n        /********************************************************************/\n        /* Calulating the horizontal and the vertical u4_ofst from top left  */\n        /* edge of the reference frame, and subsequent clipping             */\n        /********************************************************************/\n        u2_pic_ht >>= 1;\n        u2_frm_wd = ps_dec->u2_frm_wd_uv << u1_pic_fld;\n        i2_frm_x = (u2_mb_x << 3) + (u1_sub_x << 1) + i2_tmp_mv_x;\n        i2_frm_y = ((u2_mb_y + (u1_mb_bot && !u1_mb_fld)) << 3)\n                        + (((u1_sub_y << 1) + i2_tmp_mv_y) << u1_mb_fld);\n\n        i2_frm_x = CLIP3(MAX_OFFSET_OUTSIDE_UV_FRM,\n                         ((ps_dec->u2_pic_wd >> 1) - 1), i2_frm_x);\n        i2_frm_y = CLIP3(((1 - u1_dma_ht) << u1_mb_fld),\n                         (u2_pic_ht - (1 << u1_mb_fld)), i2_frm_y);\n\n        i4_ref_offset = i2_frm_y * u2_frm_wd + i2_frm_x * YUV420SP_FACTOR;\n        u1_dma_wd = (i1_mc_wd + 3) & 0xFC;\n\n        /********************************************************************/\n        /* Calulating the horizontal and the vertical u4_ofst from top left  */\n        /* edge of the recon buffer                                         */\n        /********************************************************************/\n        /* CHANGED CODE */\n        u2_rec_wd = BLK8x8SIZE * YUV420SP_FACTOR;\n        i2_rec_x = u1_sub_x << 1;\n        i2_rec_y = u1_sub_y << 1;\n        i4_rec_offset = i2_rec_y * u2_rec_wd + i2_rec_x * YUV420SP_FACTOR;\n        {\n            u2_rec_wd = ps_dec->u2_frm_wd_uv << u1_mb_or_pic_fld;\n\n            i2_rec_x += (mb_index << 3);\n            i4_rec_offset = i2_rec_y * u2_rec_wd + i2_rec_x * YUV420SP_FACTOR;\n            if(u1_mb_bot)\n                i4_rec_offset += ps_dec->u2_frm_wd_uv << ((u1_mb_fld) ? 0 : 3);\n            ps_pred->pu1_rec_y_u = ps_frame_buf->pu1_dest_u + i4_rec_offset;\n            ps_pred->u1_pi1_wt_ofst_rec_v = ps_frame_buf->pu1_dest_v\n                            + i4_rec_offset;\n\n        }\n\n        /* CHANGED CODE */\n\n        /* filling the common pred structures for U */\n        u2_frm_wd = ps_dec->u2_frm_wd_uv << u1_mb_or_pic_fld;\n        u1_tmp_dma_ht = u1_dma_ht;\n        ps_pred->u2_u1_ref_buf_wd = u1_dma_wd;\n        ps_pred->u2_frm_wd = u2_frm_wd;\n        ps_pred->i1_dma_ht = u1_dma_ht;\n        ps_pred->i1_mc_wd = i1_mc_wd;\n        ps_pred->u2_dst_stride = u2_rec_wd;\n\n        ps_pred->i1_mb_partwidth = u1_part_wd << 1;\n        ps_pred->i1_mb_partheight = u1_part_ht << 1;\n        ps_pred->u1_dydx = (u1_dy << 3) + u1_dx;\n        ps_pred->u1_is_bi_direct = u1_is_bi_dir;\n        ps_pred->u1_wght_pred_type = u1_wght_pred_type;\n        ps_pred->i1_pod_ht = 0;\n\n        ps_pred->pu1_dma_dest_addr = pu1_ref_buf;\n\n        /* unrestricted field motion comp for top region outside frame */\n        i2_pod_ht = (-i2_frm_y) >> u1_mb_fld;\n        if((i2_pod_ht > 0) && u1_pod_top)\n        {\n            i4_ref_offset += i2_pod_ht * u2_frm_wd;\n            u1_dma_ht -= i2_pod_ht;\n            ps_pred->i1_pod_ht = (WORD8)(-i2_pod_ht);\n        }\n        /* unrestricted field motion comp for bottom region outside frame */\n        else if(u1_pod_bot)\n        {\n            i2_pod_ht = u1_dma_ht + ((i2_frm_y - u2_pic_ht) >> u1_mb_fld);\n            if(i2_pod_ht > 0)\n            {\n                u1_dma_ht -= i2_pod_ht;\n                ps_pred->i1_pod_ht = (WORD8)i2_pod_ht;\n            }\n        }\n\n        pu1_pred_u = pu1_buf2 + i4_ref_offset;\n        pu1_pred_v = pu1_buf3 + i4_ref_offset;\n\n        /* Copy U & V partitions */\n        if(ps_pred->i1_pod_ht)\n        {\n            ps_pred->pu1_pred_u = pu1_pred_u;\n            ps_pred->u1_dma_ht_uv = u1_dma_ht;\n            ps_pred->u1_dma_wd_uv = u1_dma_wd;\n\n        }\n        ps_pred->pu1_u_ref = pu1_pred_u;\n\n        /* Increment the reference buffer Index */\n        u2_tot_ref_scratch_size += (u1_dma_wd * u1_tmp_dma_ht) << 1;\n\n        if(ps_pred->i1_pod_ht)\n        {\n            ps_pred->pu1_pred_v = pu1_pred_v;\n            ps_pred->u1_dma_ht_uv = u1_dma_ht;\n            ps_pred->u1_dma_wd_uv = u1_dma_wd;\n        }\n\n        ps_pred->pu1_v_ref = pu1_pred_v;\n    }\n\n    /* Increment ps_pred index */\n    ps_dec->u4_pred_info_idx += 2;\n\n\n    /* Increment the reference buffer Index */\n    ps_dec->u4_dma_buf_idx += u2_tot_ref_scratch_size;\n\n    if(ps_dec->u4_dma_buf_idx > MAX_REF_BUF_SIZE)\n        return ERROR_NUM_MV;\n\n    return OK;\n\n\n\n}\n\n\n/*!\n **************************************************************************\n * \\if Function name : MotionCompensate \\endif\n *\n * \\brief\n *    The routine forms predictor blocks for the entire MB and stores it in\n *    predictor buffers.This function works only for BASELINE profile\n *\n * \\param ps_dec: Pointer to the structure decStruct. This is used to get\n *     pointers to the current and the reference frame and to the MbParams\n *     structure.\n *\n * \\return\n *    None\n *\n * \\note\n *    The routine forms predictors for all the luma and the chroma MB\n *    partitions.\n **************************************************************************\n */\n\nvoid ih264d_motion_compensate_bp(dec_struct_t * ps_dec, dec_mb_info_t *ps_cur_mb_info)\n{\n    pred_info_t *ps_pred ;\n    UWORD8 *puc_ref, *pu1_dest_y;\n    UWORD8 *pu1_dest_u;\n    UWORD32 u2_num_pels, u2_ref_wd_y, u2_ref_wd_uv, u2_dst_wd;\n\n    UWORD32 u4_wd_y, u4_ht_y, u4_wd_uv;\n    UWORD32 u4_ht_uv;\n    UWORD8 *puc_pred0 = (UWORD8 *)(ps_dec->pi2_pred1);\n\n\n    PROFILE_DISABLE_INTER_PRED()\n    UNUSED(ps_cur_mb_info);\n    ps_pred = ps_dec->ps_pred ;\n\n    for(u2_num_pels = 0; u2_num_pels < 256;)\n    {\n        UWORD32 uc_dx, uc_dy;\n        /* Pointer to the destination buffer. If the CBPs of all 8x8 blocks in\n         the MB partition are zero then it would be better to copy the\n         predictor valus directly to the current frame buffer */\n        /*\n         * ps_pred->i1_pod_ht is non zero when MBAFF is present. In case of MBAFF the reference data\n         * is copied in the Scrath buffer so that the padding_on_demand doesnot corrupt the frame data\n         */\n\n        u2_ref_wd_y = ps_pred->u2_frm_wd;\n        puc_ref = ps_pred->pu1_y_ref;\n        if(ps_pred->u1_dydx & 0x3)\n            puc_ref += 2;\n        if(ps_pred->u1_dydx >> 2)\n            puc_ref += 2 * u2_ref_wd_y;\n\n        u4_wd_y = ps_pred->i1_mb_partwidth;\n        u4_ht_y = ps_pred->i1_mb_partheight;\n        uc_dx = ps_pred->u1_dydx;\n        uc_dy = uc_dx >> 2;\n        uc_dx &= 0x3;\n\n        pu1_dest_y = ps_pred->pu1_rec_y_u;\n        u2_dst_wd = ps_pred->u2_dst_stride;\n\n        ps_dec->apf_inter_pred_luma[ps_pred->u1_dydx](puc_ref, pu1_dest_y,\n                                                      u2_ref_wd_y,\n                                                      u2_dst_wd,\n                                                      u4_ht_y,\n                                                      u4_wd_y, puc_pred0,\n                                                      ps_pred->u1_dydx);\n\n        ps_pred++;\n\n        /* Interpolate samples for the chroma components */\n        {\n            UWORD8 *pu1_ref_u;\n\n            u2_ref_wd_uv = ps_pred->u2_frm_wd;\n            pu1_ref_u = ps_pred->pu1_u_ref;\n\n            u4_wd_uv = ps_pred->i1_mb_partwidth;\n            u4_ht_uv = ps_pred->i1_mb_partheight;\n            uc_dx = ps_pred->u1_dydx; /* 8*dy + dx */\n            uc_dy = uc_dx >> 3;\n            uc_dx &= 0x7;\n\n            pu1_dest_u = ps_pred->pu1_rec_y_u;\n            u2_dst_wd = ps_pred->u2_dst_stride;\n\n            ps_pred++;\n            ps_dec->pf_inter_pred_chroma(pu1_ref_u, pu1_dest_u, u2_ref_wd_uv,\n                                         u2_dst_wd, uc_dx, uc_dy,\n                                         u4_ht_uv, u4_wd_uv);\n\n        }\n\n        u2_num_pels += (UWORD8)u4_wd_y * (UWORD8)u4_ht_y;\n\n    }\n}\n\n\n/*\n **************************************************************************\n * \\if Function name : MotionCompensateB \\endif\n *\n * \\brief\n *    The routine forms predictor blocks for the entire MB and stores it in\n *    predictor buffers.\n *\n * \\param ps_dec: Pointer to the structure decStruct. This is used to get\n *     pointers to the current and the reference frame and to the MbParams\n *     structure.\n *\n * \\return\n *    None\n *\n * \\note\n *    The routine forms predictors for all the luma and the chroma MB\n *    partitions.\n **************************************************************************\n */\n\nvoid ih264d_motion_compensate_mp(dec_struct_t * ps_dec, dec_mb_info_t *ps_cur_mb_info)\n{\n    pred_info_t *ps_pred ;\n    pred_info_t *ps_pred_y_forw, *ps_pred_y_back, *ps_pred_cr_forw;\n    UWORD8 *puc_ref, *pu1_dest_y, *puc_pred0, *puc_pred1;\n    UWORD8 *pu1_dest_u, *pu1_dest_v;\n    WORD16 *pi16_intm;\n    UWORD32 u2_num_pels, u2_ref_wd_y, u2_ref_wd_uv, u2_dst_wd;\n    UWORD32 u2_dest_wd_y, u2_dest_wd_uv;\n    UWORD32 u2_row_buf_wd_y = 0;\n    UWORD32 u2_row_buf_wd_uv = 0;\n    UWORD32 u2_log2Y_crwd;\n    UWORD32 u4_wd_y, u4_ht_y, u1_dir, u4_wd_uv;\n    UWORD32 u4_ht_uv;\n    UWORD8 *pu1_temp_mc_buffer = ps_dec->pu1_temp_mc_buffer;\n    WORD32 i2_pod_ht;\n    UWORD32 u2_pic_ht, u2_frm_wd, u2_rec_wd;\n    UWORD32 u1_pod_bot, u1_pod_top;\n    UWORD8 *pu1_pred, *pu1_dma_dst;\n    UWORD32 u1_dma_wd, u1_dma_ht;\n\n    dec_slice_params_t * const ps_cur_slice = ps_dec->ps_cur_slice;\n\n    /* set default value to flags specifying field nature of picture & mb */\n    UWORD32 u1_mb_fld = 0, u1_mb_or_pic_fld;\n    UWORD32 u1_mb_or_pic_bot;\n    /* calculate flags specifying field nature of picture & mb */\n    const UWORD8 u1_pic_fld = ps_cur_slice->u1_field_pic_flag;\n\n    PROFILE_DISABLE_INTER_PRED()\n    ps_pred = ps_dec->ps_pred ;\n    /* Initialize both ps_pred_y_forw, ps_pred_cr_forw and ps_pred_y_back\n     * to avoid static analysis warnings */\n    ps_pred_y_forw = ps_pred;\n    ps_pred_y_back = ps_pred;\n    ps_pred_cr_forw = ps_pred;\n\n    u2_log2Y_crwd = ps_dec->ps_decode_cur_slice->u2_log2Y_crwd;\n\n    if(!u1_pic_fld)\n    {\n        u1_mb_fld = ps_cur_mb_info->u1_mb_field_decodingflag;\n    }\n\n    u1_mb_or_pic_fld = u1_mb_fld | u1_pic_fld;\n\n    pi16_intm = ps_dec->pi2_pred1;\n    puc_pred0 = (UWORD8 *)pi16_intm;\n    puc_pred1 = puc_pred0 + PRED_BUFFER_WIDTH * PRED_BUFFER_HEIGHT * sizeof(WORD16);\n\n    for(u2_num_pels = 0; u2_num_pels < 256;)\n    {\n        UWORD8 uc_dx, uc_dy;\n        const UWORD8 u1_is_bi_direct = ps_pred->u1_is_bi_direct;\n        for(u1_dir = 0; u1_dir <= u1_is_bi_direct; u1_dir++)\n        {\n            /* Pointer to the destination buffer. If the CBPs of all 8x8 blocks in\n             the MB partition are zero then it would be better to copy the\n             predictor valus directly to the current frame buffer */\n            /*\n             * ps_pred->i1_pod_ht is non zero when MBAFF is present. In case of MBAFF the reference data\n             * is copied in the Scrath buffer so that the padding_on_demand doesnot corrupt the frame data\n             */\n\n            if(ps_pred->i1_pod_ht)\n            {\n                u2_ref_wd_y = ps_pred->u2_u1_ref_buf_wd;\n                puc_ref = ps_pred->pu1_dma_dest_addr;\n            }\n            else\n            {\n                u2_ref_wd_y = ps_pred->u2_frm_wd;\n                puc_ref = ps_pred->pu1_y_ref;\n\n            }\n\n            if(ps_pred->u1_dydx & 0x3)\n                puc_ref += 2;\n            if(ps_pred->u1_dydx >> 2)\n                puc_ref += 2 * u2_ref_wd_y;\n            u4_wd_y = ps_pred->i1_mb_partwidth;\n            u4_ht_y = ps_pred->i1_mb_partheight;\n\n            uc_dx = ps_pred->u1_dydx;\n            uc_dy = uc_dx >> 2;\n            uc_dx &= 0x3;\n            if(u1_dir == 0)\n            {\n                pu1_dest_y = ps_pred->pu1_rec_y_u;\n                u2_row_buf_wd_y = ps_pred->u2_dst_stride;\n                u2_dst_wd = ps_pred->u2_dst_stride;\n                u2_dest_wd_y = u2_dst_wd;\n                ps_pred_y_forw = ps_pred;\n            }\n            else\n            {\n                pu1_dest_y = pu1_temp_mc_buffer;\n                u2_dst_wd = MB_SIZE;\n                u2_dest_wd_y = u2_dst_wd;\n                ps_pred_y_back = ps_pred;\n                ps_pred_y_back->pu1_rec_y_u = pu1_dest_y;\n            }\n\n            /* padding on demand (POD) for y done here */\n\n            if(ps_pred->i1_pod_ht)\n            {\n                pu1_pred = ps_pred->pu1_pred;\n                pu1_dma_dst = ps_pred->pu1_dma_dest_addr;\n                u1_dma_wd = ps_pred->u1_dma_wd_y;\n                u1_dma_ht = ps_pred->u1_dma_ht_y;\n                u2_frm_wd = ps_dec->u2_frm_wd_y << u1_mb_or_pic_fld;\n                if(ps_pred->i1_pod_ht < 0)\n                {\n                    pu1_dma_dst = pu1_dma_dst - (ps_pred->i1_pod_ht * ps_pred->u2_u1_ref_buf_wd);\n                }\n                ih264d_copy_2d1d(pu1_pred, pu1_dma_dst, u2_frm_wd, u1_dma_wd,\n                                 u1_dma_ht);\n                ih264d_pad_on_demand(ps_pred, LUM_BLK);\n            }\n            ps_dec->apf_inter_pred_luma[ps_pred->u1_dydx](puc_ref, pu1_dest_y,\n                                                          u2_ref_wd_y,\n                                                          u2_dst_wd,\n                                                          u4_ht_y,\n                                                          u4_wd_y,\n                                                          puc_pred0,\n                                                          ps_pred->u1_dydx);\n            ps_pred++;\n\n            /* Interpolate samples for the chroma components */\n            {\n                UWORD8 *pu1_ref_u;\n                UWORD32 u1_dma_ht;\n\n                /* padding on demand (POD) for U and V done here */\n                u1_dma_ht = ps_pred->i1_dma_ht;\n\n                if(ps_pred->i1_pod_ht)\n                {\n                    pu1_pred = ps_pred->pu1_pred_u;\n                    pu1_dma_dst = ps_pred->pu1_dma_dest_addr;\n                    u1_dma_ht = ps_pred->u1_dma_ht_uv;\n                    u1_dma_wd = ps_pred->u1_dma_wd_uv * YUV420SP_FACTOR;\n                    u2_frm_wd = ps_dec->u2_frm_wd_uv << u1_mb_or_pic_fld;\n                    if(ps_pred->i1_pod_ht < 0)\n                    {\n                        /*Top POD*/\n                        pu1_dma_dst -= (ps_pred->i1_pod_ht\n                                        * ps_pred->u2_u1_ref_buf_wd\n                                        * YUV420SP_FACTOR);\n                    }\n\n                    ih264d_copy_2d1d(pu1_pred, pu1_dma_dst, u2_frm_wd,\n                                     u1_dma_wd, u1_dma_ht);\n\n                    pu1_dma_dst += (ps_pred->i1_dma_ht\n                                    * ps_pred->u2_u1_ref_buf_wd);\n                    pu1_pred = ps_pred->pu1_pred_v;\n\n                    ih264d_pad_on_demand(ps_pred, CHROM_BLK);\n                }\n\n                if(ps_pred->i1_pod_ht)\n                {\n                    pu1_ref_u = ps_pred->pu1_dma_dest_addr;\n\n                    u2_ref_wd_uv = ps_pred->u2_u1_ref_buf_wd\n                                    * YUV420SP_FACTOR;\n                }\n                else\n                {\n                    u2_ref_wd_uv = ps_pred->u2_frm_wd;\n                    pu1_ref_u = ps_pred->pu1_u_ref;\n\n                }\n\n                u4_wd_uv = ps_pred->i1_mb_partwidth;\n                u4_ht_uv = ps_pred->i1_mb_partheight;\n                uc_dx = ps_pred->u1_dydx; /* 8*dy + dx */\n                uc_dy = uc_dx >> 3;\n                uc_dx &= 0x7;\n                if(u1_dir == 0)\n                {\n                    pu1_dest_u = ps_pred->pu1_rec_y_u;\n\n                    pu1_dest_v = ps_pred->u1_pi1_wt_ofst_rec_v;\n                    u2_row_buf_wd_uv = ps_pred->u2_dst_stride;\n                    u2_dst_wd = ps_pred->u2_dst_stride;\n                    u2_dest_wd_uv = u2_dst_wd;\n                    ps_pred_cr_forw = ps_pred;\n                }\n                else\n                {\n                    pu1_dest_u = puc_pred0;\n\n                    pu1_dest_v = puc_pred1;\n                    u2_dest_wd_uv = BUFFER_WIDTH;\n                    u2_dst_wd = BUFFER_WIDTH;\n                    ps_pred->pu1_rec_y_u = pu1_dest_u;\n                    ps_pred->u1_pi1_wt_ofst_rec_v = pu1_dest_v;\n                }\n\n                ps_pred++;\n                ps_dec->pf_inter_pred_chroma(pu1_ref_u, pu1_dest_u,\n                                             u2_ref_wd_uv, u2_dst_wd,\n                                             uc_dx, uc_dy, u4_ht_uv,\n                                             u4_wd_uv);\n\n                if(ps_cur_mb_info->u1_Mux == 1)\n                {\n                    /******************************************************************/\n                    /* padding on demand (POD) for U and V done here                  */\n                    /* ps_pred now points to the Y entry of the 0,0 component         */\n                    /* Y need not be checked for POD because Y lies within            */\n                    /* the picture((0,0) mv for Y doesnot get changed. But (0,0) for  */\n                    /* U and V can need POD beacause of cross-field mv adjustments    */\n                    /* (Table 8-9 of standard)                                        */\n                    /******************************************************************/\n                    if((ps_pred + 1)->i1_pod_ht)\n                    {\n                        pu1_pred = (ps_pred + 1)->pu1_pred_u;\n                        pu1_dma_dst = (ps_pred + 1)->pu1_dma_dest_addr;\n                        u1_dma_ht = (ps_pred + 1)->u1_dma_ht_uv;\n                        u1_dma_wd = (ps_pred + 1)->u1_dma_wd_uv\n                                        * YUV420SP_FACTOR;\n                        u2_frm_wd = ps_dec->u2_frm_wd_uv << u1_mb_or_pic_fld;\n                        if((ps_pred + 1)->i1_pod_ht < 0)\n                        {\n                            /*Top POD*/\n                            pu1_dma_dst -= ((ps_pred + 1)->i1_pod_ht\n                                            * (ps_pred + 1)->u2_u1_ref_buf_wd\n                                            * YUV420SP_FACTOR);\n                        }\n                        ih264d_copy_2d1d(pu1_pred, pu1_dma_dst, u2_frm_wd,\n                                         u1_dma_wd, u1_dma_ht);\n                        pu1_dma_dst += ((ps_pred + 1)->i1_dma_ht\n                                        * (ps_pred + 1)->u2_u1_ref_buf_wd); //(u1_dma_ht * u1_dma_wd);//\n                        pu1_pred = (ps_pred + 1)->pu1_pred_v;\n                        ih264d_pad_on_demand(ps_pred + 1, CHROM_BLK);\n\n                    }\n\n                    ih264d_multiplex_ref_data(ps_dec, ps_pred, pu1_dest_y,\n                                              pu1_dest_u, ps_cur_mb_info,\n                                              u2_dest_wd_y, u2_dest_wd_uv,\n                                              u1_dir);\n                    ps_pred += 2;\n                }\n            }\n        }\n        if(u1_dir != 0)\n            u2_ref_wd_y = MB_SIZE;\n\n        u2_num_pels += u4_wd_y * u4_ht_y;\n        /* if BI_DIRECT, average the two pred's, and put in ..PredBuffer[0] */\n        if((u1_is_bi_direct != 0) || (ps_pred_y_forw->u1_wght_pred_type != 0))\n        {\n\n            switch(ps_pred_y_forw->u1_wght_pred_type)\n            {\n                case 0:\n                    ps_dec->pf_default_weighted_pred_luma(\n                                    ps_pred_y_forw->pu1_rec_y_u, pu1_dest_y,\n                                    ps_pred_y_forw->pu1_rec_y_u,\n                                    u2_row_buf_wd_y, u2_ref_wd_y,\n                                    u2_row_buf_wd_y, u4_ht_uv * 2,\n                                    u4_wd_uv * 2);\n\n                    ps_dec->pf_default_weighted_pred_chroma(\n                                    ps_pred_cr_forw->pu1_rec_y_u, pu1_dest_u,\n                                    ps_pred_cr_forw->pu1_rec_y_u,\n                                    u2_row_buf_wd_uv, u2_dst_wd,\n                                    u2_row_buf_wd_uv, u4_ht_uv,\n                                    u4_wd_uv);\n\n                    break;\n                case 1:\n                {\n                    UWORD32 *pu4_weight_ofst =\n                                    (UWORD32*)ps_pred_y_forw->u1_pi1_wt_ofst_rec_v;\n                    UWORD32 u4_wt_ofst_u, u4_wt_ofst_v;\n                    UWORD32 u4_wt_ofst_y =\n                                    (UWORD32)(pu4_weight_ofst[0]);\n                    WORD32 weight = (WORD16)(u4_wt_ofst_y & 0xffff);\n                    WORD32 ofst = (WORD8)(u4_wt_ofst_y >> 16);\n\n                    ps_dec->pf_weighted_pred_luma(ps_pred_y_forw->pu1_rec_y_u,\n                                                  ps_pred_y_forw->pu1_rec_y_u,\n                                                  u2_row_buf_wd_y,\n                                                  u2_row_buf_wd_y,\n                                                  (u2_log2Y_crwd & 0x0ff),\n                                                  weight, ofst, u4_ht_y,\n                                                  u4_wd_y);\n\n                    u4_wt_ofst_u = (UWORD32)(pu4_weight_ofst[2]);\n                    u4_wt_ofst_v = (UWORD32)(pu4_weight_ofst[4]);\n                    weight = ((u4_wt_ofst_v & 0xffff) << 16)\n                                    | (u4_wt_ofst_u & 0xffff);\n                    ofst = ((u4_wt_ofst_v >> 16) << 8)\n                                    | ((u4_wt_ofst_u >> 16) & 0xFF);\n\n                    ps_dec->pf_weighted_pred_chroma(\n                                    ps_pred_cr_forw->pu1_rec_y_u,\n                                    ps_pred_cr_forw->pu1_rec_y_u,\n                                    u2_row_buf_wd_uv, u2_row_buf_wd_uv,\n                                    (u2_log2Y_crwd >> 8), weight, ofst,\n                                    u4_ht_y >> 1, u4_wd_y >> 1);\n                }\n\n                    break;\n                case 2:\n                {\n                    UWORD32 *pu4_weight_ofst =\n                                    (UWORD32*)ps_pred_y_forw->u1_pi1_wt_ofst_rec_v;\n                    UWORD32 u4_wt_ofst_u, u4_wt_ofst_v;\n                    UWORD32 u4_wt_ofst_y;\n                    WORD32 weight1, weight2;\n                    WORD32 ofst1, ofst2;\n\n                    u4_wt_ofst_y = (UWORD32)(pu4_weight_ofst[0]);\n\n                    weight1 = (WORD16)(u4_wt_ofst_y & 0xffff);\n                    ofst1 = (WORD8)(u4_wt_ofst_y >> 16);\n\n                    u4_wt_ofst_y = (UWORD32)(pu4_weight_ofst[1]);\n                    weight2 = (WORD16)(u4_wt_ofst_y & 0xffff);\n                    ofst2 = (WORD8)(u4_wt_ofst_y >> 16);\n\n                    ps_dec->pf_weighted_bi_pred_luma(ps_pred_y_forw->pu1_rec_y_u,\n                                                     ps_pred_y_back->pu1_rec_y_u,\n                                                     ps_pred_y_forw->pu1_rec_y_u,\n                                                     u2_row_buf_wd_y,\n                                                     u2_ref_wd_y,\n                                                     u2_row_buf_wd_y,\n                                                     (u2_log2Y_crwd & 0x0ff),\n                                                     weight1, weight2, ofst1,\n                                                     ofst2, u4_ht_y,\n                                                     u4_wd_y);\n\n                    u4_wt_ofst_u = (UWORD32)(pu4_weight_ofst[2]);\n                    u4_wt_ofst_v = (UWORD32)(pu4_weight_ofst[4]);\n                    weight1 = ((u4_wt_ofst_v & 0xffff) << 16)\n                                    | (u4_wt_ofst_u & 0xffff);\n                    ofst1 = ((u4_wt_ofst_v >> 16) << 8)\n                                    | ((u4_wt_ofst_u >> 16) & 0xFF);\n\n                    u4_wt_ofst_u = (UWORD32)(pu4_weight_ofst[3]);\n                    u4_wt_ofst_v = (UWORD32)(pu4_weight_ofst[5]);\n                    weight2 = ((u4_wt_ofst_v & 0xffff) << 16)\n                                    | (u4_wt_ofst_u & 0xffff);\n                    ofst2 = ((u4_wt_ofst_v >> 16) << 8)\n                                    | ((u4_wt_ofst_u >> 16) & 0xFF);\n\n                    ps_dec->pf_weighted_bi_pred_chroma(\n                                    (ps_pred_y_forw + 1)->pu1_rec_y_u,\n                                    (ps_pred_y_back + 1)->pu1_rec_y_u,\n                                    (ps_pred_y_forw + 1)->pu1_rec_y_u,\n                                    u2_row_buf_wd_uv, u2_dst_wd,\n                                    u2_row_buf_wd_uv, (u2_log2Y_crwd >> 8),\n                                    weight1, weight2, ofst1, ofst2,\n                                    u4_ht_y >> 1, u4_wd_y >> 1);\n                }\n\n                    break;\n            }\n\n        }\n    }\n}\n\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_multiplex_ref_data \\endif\n *\n * \\brief\n *    Initializes forward and backward refernce lists for B slice decoding.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\n\nvoid ih264d_multiplex_ref_data(dec_struct_t * ps_dec,\n                               pred_info_t *ps_pred,\n                               UWORD8* pu1_dest_y,\n                               UWORD8* pu1_dest_u,\n                               dec_mb_info_t *ps_cur_mb_info,\n                               UWORD16 u2_dest_wd_y,\n                               UWORD16 u2_dest_wd_uv,\n                               UWORD8 u1_dir)\n{\n    UWORD16 u2_mask = ps_cur_mb_info->u2_mask[u1_dir];\n    UWORD8 *pu1_ref_y, *pu1_ref_u;\n    UWORD8 uc_cond, i, j, u1_dydx;\n    UWORD16 u2_ref_wd_y, u2_ref_wd_uv;\n\n    PROFILE_DISABLE_INTER_PRED()\n\n    if(ps_pred->i1_pod_ht)\n    {\n        pu1_ref_y = ps_pred->pu1_dma_dest_addr;\n\n        u2_ref_wd_y = ps_pred->u2_u1_ref_buf_wd;\n    }\n    else\n    {\n        pu1_ref_y = ps_pred->pu1_y_ref;\n        u2_ref_wd_y = ps_pred->u2_frm_wd;\n    }\n\n    ps_pred++;\n    if(ps_pred->i1_pod_ht)\n    {\n        pu1_ref_u = ps_pred->pu1_dma_dest_addr;\n        u2_ref_wd_uv = ps_pred->u2_u1_ref_buf_wd * YUV420SP_FACTOR;\n\n    }\n    else\n    {\n        pu1_ref_u = ps_pred->pu1_u_ref;\n        u2_ref_wd_uv = ps_pred->u2_frm_wd;\n\n    }\n\n    u1_dydx = ps_pred->u1_dydx;\n\n    {\n        UWORD8 uc_dx, uc_dy;\n        UWORD8 *pu1_scratch_u;\n\n        uc_dx = u1_dydx & 0x3;\n        uc_dy = u1_dydx >> 3;\n        if(u1_dydx != 0)\n        {\n            pred_info_t * ps_prv_pred = ps_pred - 2;\n            pu1_scratch_u = ps_prv_pred->pu1_dma_dest_addr;\n            ps_dec->pf_inter_pred_chroma(pu1_ref_u, pu1_scratch_u,\n                                         u2_ref_wd_uv, 16, uc_dx, uc_dy, 8,\n                                         8);\n\n            /* Modify ref pointer and refWidth to point to scratch    */\n            /* buffer to be used below in ih264d_copy_multiplex_data functions */\n            /* CHANGED CODE */\n            pu1_ref_u = pu1_scratch_u;\n            u2_ref_wd_uv = 8 * YUV420SP_FACTOR;\n        }\n    }\n    {\n        for(i = 0; i < 4; i++)\n        {\n            for(j = 0; j < 4; j++)\n            {\n                uc_cond = u2_mask & 1;\n                u2_mask >>= 1;\n                if(uc_cond)\n                {\n                    *(UWORD32 *)(pu1_dest_y + u2_dest_wd_y) =\n                                    *(UWORD32 *)(pu1_ref_y + u2_ref_wd_y);\n                    *(UWORD32 *)(pu1_dest_y + 2 * u2_dest_wd_y) =\n                                    *(UWORD32 *)(pu1_ref_y + 2 * u2_ref_wd_y);\n                    *(UWORD32 *)(pu1_dest_y + 3 * u2_dest_wd_y) =\n                                    *(UWORD32 *)(pu1_ref_y + 3 * u2_ref_wd_y);\n                    {\n                        UWORD32 *dst, *src;\n                        dst = (UWORD32 *)pu1_dest_y;\n                        src = (UWORD32 *)pu1_ref_y;\n                        *dst = *src;\n                        dst++;\n                        src++;\n                        pu1_dest_y = (UWORD8 *)dst;\n                        pu1_ref_y = (UWORD8 *)src;\n                    }\n                    *(UWORD32 *)(pu1_dest_u + u2_dest_wd_uv) =\n                                    *(UWORD32 *)(pu1_ref_u + u2_ref_wd_uv);\n                    {\n                        UWORD32 *dst, *src;\n                        dst = (UWORD32 *)pu1_dest_u;\n                        src = (UWORD32 *)pu1_ref_u;\n                        *dst = *src;\n                        dst++;\n                        src++;\n                        pu1_dest_u = (UWORD8 *)dst;\n                        pu1_ref_u = (UWORD8 *)src;\n                    }\n\n                }\n                else\n                {\n                    pu1_dest_y += 4;\n                    pu1_ref_y += 4;\n                    pu1_dest_u += 2 * YUV420SP_FACTOR;\n                    pu1_ref_u += 2 * YUV420SP_FACTOR;\n                }\n            }\n            pu1_ref_y += 4 * (u2_ref_wd_y - 4);\n            pu1_ref_u += 2 * (u2_ref_wd_uv - 4 * YUV420SP_FACTOR);\n            pu1_dest_y += 4 * (u2_dest_wd_y - 4);\n            pu1_dest_u += 2 * (u2_dest_wd_uv - 4 * YUV420SP_FACTOR);\n        }\n    }\n}\n\nvoid ih264d_pad_on_demand(pred_info_t *ps_pred, UWORD8 lum_chrom_blk)\n{\n    if(CHROM_BLK == lum_chrom_blk)\n    {\n        UWORD32 *pu4_pod_src_u, *pu4_pod_dst_u;\n        UWORD32 *pu4_pod_src_v, *pu4_pod_dst_v;\n        WORD32 j, u1_wd_stride;\n        WORD32 i, u1_dma_ht, i1_ht;\n        UWORD32 u2_dma_size;\n        u1_wd_stride = (ps_pred->u2_u1_ref_buf_wd >> 2) * YUV420SP_FACTOR;\n        u1_dma_ht = ps_pred->i1_dma_ht;\n        u2_dma_size = u1_wd_stride * u1_dma_ht;\n        pu4_pod_src_u = (UWORD32 *)ps_pred->pu1_dma_dest_addr;\n        pu4_pod_dst_u = pu4_pod_src_u;\n\n        pu4_pod_src_v = pu4_pod_src_u + u2_dma_size;\n        pu4_pod_dst_v = pu4_pod_src_v;\n\n        i1_ht = ps_pred->i1_pod_ht;\n        pu4_pod_src_u -= u1_wd_stride * i1_ht;\n        pu4_pod_src_v -= u1_wd_stride * i1_ht;\n        if(i1_ht < 0)\n            /* Top POD */\n            i1_ht = -i1_ht;\n        else\n        {\n            /* Bottom POD */\n            pu4_pod_src_u += (u1_dma_ht - 1) * u1_wd_stride;\n            pu4_pod_dst_u += (u1_dma_ht - i1_ht) * u1_wd_stride;\n            pu4_pod_src_v += (u1_dma_ht - 1) * u1_wd_stride;\n            pu4_pod_dst_v += (u1_dma_ht - i1_ht) * u1_wd_stride;\n        }\n\n        for(i = 0; i < i1_ht; i++)\n            for(j = 0; j < u1_wd_stride; j++)\n            {\n                *pu4_pod_dst_u++ = *(pu4_pod_src_u + j);\n\n            }\n    }\n    else\n    {\n        UWORD32 *pu4_pod_src, *pu4_pod_dst;\n        WORD32 j, u1_wd_stride;\n        WORD32 i, i1_ht;\n        pu4_pod_src = (UWORD32 *)ps_pred->pu1_dma_dest_addr;\n        pu4_pod_dst = pu4_pod_src;\n        u1_wd_stride = ps_pred->u2_u1_ref_buf_wd >> 2;\n        i1_ht = ps_pred->i1_pod_ht;\n        pu4_pod_src -= u1_wd_stride * i1_ht;\n        if(i1_ht < 0)\n            /* Top POD */\n            i1_ht = -i1_ht;\n        else\n        {\n            /* Bottom POD */\n            pu4_pod_src += (ps_pred->i1_dma_ht - 1) * u1_wd_stride;\n            pu4_pod_dst += (ps_pred->i1_dma_ht - i1_ht) * u1_wd_stride;\n        }\n\n        for(i = 0; i < i1_ht; i++)\n            for(j = 0; j < u1_wd_stride; j++)\n                *pu4_pod_dst++ = *(pu4_pod_src + j);\n    }\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_inter_pred.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n#ifndef _IH264D_INTER_PRED_H_\n#define _IH264D_INTER_PRED_H_\n\n/*!\n **************************************************************************\n * \\file ih264d_inter_pred.h\n *\n * \\brief\n *    Decalaration for routines defined in MorionCompensate.c\n *\n * Detailed_description\n *\n * \\date\n *    creation_date\n *\n * \\author  Arvind Raman\n **************************************************************************\n */\n\n#include \"ih264d_structs.h\"\n\n#define BUFFER_WIDTH        16\n/*!\n **************************************************************************\n *   \\brief   PRED_BUFFER_WIDTH / HEIGHT\n *\n *   Width and height of the 16 bit (also reused a 2 8 bits buffers). The\n *   required dimensions for these buffers are 21x21, however to align the\n *   start of every row to a WORD aligned boundary the width has been increased\n *   to 24.\n **************************************************************************\n */\n//#define PRED_BUFFER_WIDTH   24\n//#define PRED_BUFFER_HEIGHT  21\n#define PRED_BUFFER_WIDTH   24*2\n#define PRED_BUFFER_HEIGHT  24*2\n\nvoid ih264d_fill_pred_info(WORD16 *pi2_mv,WORD32 part_width,WORD32 part_height, WORD32 sub_mb_num,\n                           WORD32 pred_dir,pred_info_pkd_t *ps_pred_pkd,WORD8 i1_buf_id,\n                           WORD8 i1_ref_idx,UWORD32 *pu4_wt_offset,UWORD8 u1_pic_type);\n\nWORD32 ih264d_form_mb_part_info_bp(pred_info_pkd_t *ps_pred_pkd,\n                                 dec_struct_t * ps_dec,\n                                 UWORD16 u2_mb_x,\n                                 UWORD16 u2_mb_y,\n                                 WORD32 mb_index,\n                                 dec_mb_info_t *ps_cur_mb_info);\n\nWORD32 ih264d_form_mb_part_info_mp(pred_info_pkd_t *ps_pred_pkd,\n                                 dec_struct_t * ps_dec,\n                                 UWORD16 u2_mb_x,\n                                 UWORD16 u2_mb_y,\n                                 WORD32 mb_index,\n                                 dec_mb_info_t *ps_cur_mb_info);\n\n\nvoid ih264d_motion_compensate_bp(dec_struct_t * ps_dec, dec_mb_info_t *ps_cur_mb_info);\nvoid ih264d_motion_compensate_mp(dec_struct_t * ps_dec, dec_mb_info_t *ps_cur_mb_info);\n\n\nvoid TransferRefBuffs(dec_struct_t *ps_dec);\n\nvoid ih264d_multiplex_ref_data(dec_struct_t * ps_dec,\n                               pred_info_t *ps_pred,\n                               UWORD8* pu1_dest_y,\n                               UWORD8* pu1_dest_u,\n                               dec_mb_info_t *ps_cur_mb_info,\n                               UWORD16 u2_dest_wd_y,\n                               UWORD16 u2_dest_wd_uv,\n                               UWORD8 u1_dir);\n#endif /* _IH264D_INTER_PRED_H_ */\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_mb_utils.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n * \\file ih264d_mb_utils.c\n *\n * \\brief\n *    Contains utitlity functions needed for Macroblock decoding\n *\n * \\date\n *    18/12/2002\n *\n * \\author  AI\n **************************************************************************\n */\n#include <string.h>\n#include <stdlib.h>\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_parse_mb_header.h\"\n#include \"ih264d_cabac.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_tables.h\"\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : get_mb_info_cavlc                                        */\n/*                                                                           */\n/*  Description   : This function sets the following information of cur MB   */\n/*                  (a) mb_x and mb_y                                        */\n/*                  (b) Neighbour availablity                                */\n/*                  (c) Macroblock location in the frame buffer              */\n/*                  (e) For mbaff predicts field/frame u4_flag for topMb        */\n/*                      and sets the field/frame for botMb. This is          */\n/*                      written in ps_dec->u1_cur_mb_fld_dec_flag            */\n/*                                                                           */\n/*  Inputs        : pointer to decstruct                                     */\n/*                  pointer to current mb info                               */\n/*                  currentMbaddress                                         */\n/*                                                                           */\n/*  Processing    : leftMb and TopMb params are used by DecMbskip and        */\n/*                  DecCtxMbfield  modules so that these modules do not      */\n/*                  check for neigbour availability and then find the        */\n/*                  neigbours for context increments                         */\n/*                                                                           */\n/*  Returns       : OK                                                       */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 07 2002   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nUWORD32 ih264d_get_mb_info_cavlc_nonmbaff(dec_struct_t *ps_dec,\n                                          const UWORD16 u2_cur_mb_address,\n                                          dec_mb_info_t * ps_cur_mb_info,\n                                          UWORD32 u4_mbskip_run)\n{\n    WORD32 mb_x;\n    WORD32 mb_y;\n    UWORD8 u1_mb_ngbr_avail = 0;\n    UWORD16 u2_frm_width_in_mb = ps_dec->u2_frm_wd_in_mbs;\n    WORD16 i2_prev_slice_mbx = ps_dec->i2_prev_slice_mbx;\n    UWORD16 u2_top_right_mask = TOP_RIGHT_DEFAULT_AVAILABLE;\n    UWORD16 u2_top_left_mask = TOP_LEFT_DEFAULT_AVAILABLE;\n    UNUSED(u4_mbskip_run);\n    /*--------------------------------------------------------------------*/\n    /* Calculate values of mb_x and mb_y                                  */\n    /*--------------------------------------------------------------------*/\n    mb_x = (WORD16)ps_dec->u2_mbx;\n    mb_y = (WORD16)ps_dec->u2_mby;\n\n    ps_dec->u2_cur_mb_addr = u2_cur_mb_address;\n\n    mb_x++;\n\n    if(mb_x == u2_frm_width_in_mb)\n    {\n        mb_x = 0;\n        mb_y++;\n    }\n    if(mb_y > ps_dec->i2_prev_slice_mby)\n    {\n        /* if not in the immemdiate row of prev slice end then top\n         will be available */\n        if(mb_y > (ps_dec->i2_prev_slice_mby + 1))\n            i2_prev_slice_mbx = -1;\n\n        if(mb_x > i2_prev_slice_mbx)\n        {\n            u1_mb_ngbr_avail |= TOP_MB_AVAILABLE_MASK;\n            u2_top_right_mask |= TOP_RIGHT_TOP_AVAILABLE;\n            u2_top_left_mask |= TOP_LEFT_TOP_AVAILABLE;\n        }\n\n        if((mb_x > (i2_prev_slice_mbx - 1))\n                        && (mb_x != (u2_frm_width_in_mb - 1)))\n        {\n            u1_mb_ngbr_avail |= TOP_RIGHT_MB_AVAILABLE_MASK;\n            u2_top_right_mask |= TOP_RIGHT_TOPR_AVAILABLE;\n        }\n\n        if(mb_x > (i2_prev_slice_mbx + 1))\n        {\n            u1_mb_ngbr_avail |= TOP_LEFT_MB_AVAILABLE_MASK;\n            u2_top_left_mask |= TOP_LEFT_TOPL_AVAILABLE;\n        }\n\n        /* Next row  Left will be available*/\n        i2_prev_slice_mbx = -1;\n    }\n\n    /* Same row */\n    if(mb_x > (i2_prev_slice_mbx + 1))\n    {\n        u1_mb_ngbr_avail |= LEFT_MB_AVAILABLE_MASK;\n        u2_top_left_mask |= TOP_LEFT_LEFT_AVAILABLE;\n    }\n\n    {\n        mb_neigbour_params_t *ps_cur_mb_row = ps_dec->ps_cur_mb_row;\n        mb_neigbour_params_t *ps_top_mb_row = ps_dec->ps_top_mb_row;\n\n        /* copy the parameters of topleft Mb */\n        ps_cur_mb_info->u1_topleft_mbtype = ps_dec->u1_topleft_mbtype;\n        /* Neighbour pointer assignments*/\n        ps_cur_mb_info->ps_curmb = ps_cur_mb_row + mb_x;\n        ps_cur_mb_info->ps_left_mb = ps_cur_mb_row + mb_x - 1;\n        ps_cur_mb_info->ps_top_mb = ps_top_mb_row + mb_x;\n        ps_cur_mb_info->ps_top_right_mb = ps_top_mb_row + mb_x + 1;\n\n        /* Update the parameters of topleftmb*/\n        ps_dec->u1_topleft_mbtype = ps_cur_mb_info->ps_top_mb->u1_mb_type;\n    }\n\n    ps_dec->u2_mby = mb_y;\n    ps_dec->u2_mbx = mb_x;\n    ps_cur_mb_info->u2_mbx = mb_x;\n    ps_cur_mb_info->u2_mby = mb_y;\n    ps_cur_mb_info->u1_topmb = 1;\n    ps_dec->i4_submb_ofst += SUB_BLK_SIZE;\n    ps_dec->u1_mb_ngbr_availablity = u1_mb_ngbr_avail;\n    ps_cur_mb_info->u1_mb_ngbr_availablity = u1_mb_ngbr_avail;\n    ps_cur_mb_info->ps_curmb->u1_mb_fld = ps_dec->u1_cur_mb_fld_dec_flag;\n    ps_cur_mb_info->u1_mb_field_decodingflag = ps_dec->u1_cur_mb_fld_dec_flag;\n    ps_cur_mb_info->u2_top_left_avail_mask = u2_top_left_mask;\n    ps_cur_mb_info->u2_top_right_avail_mask = u2_top_right_mask;\n    return (OK);\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : get_mb_info_cavlc                                        */\n/*                                                                           */\n/*  Description   : This function sets the following information of cur MB   */\n/*                  (a) mb_x and mb_y                                        */\n/*                  (b) Neighbour availablity                                */\n/*                  (c) Macroblock location in the frame buffer              */\n/*                  (e) For mbaff predicts field/frame u4_flag for topMb        */\n/*                      and sets the field/frame for botMb. This is          */\n/*                      written in ps_dec->u1_cur_mb_fld_dec_flag            */\n/*                                                                           */\n/*  Inputs        : pointer to decstruct                                     */\n/*                  pointer to current mb info                               */\n/*                  currentMbaddress                                         */\n/*                                                                           */\n/*  Processing    : leftMb and TopMb params are used by DecMbskip and        */\n/*                  DecCtxMbfield  modules so that these modules do not      */\n/*                  check for neigbour availability and then find the        */\n/*                  neigbours for context increments                         */\n/*                                                                           */\n/*  Returns       : OK                                                       */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 07 2002   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nUWORD32 ih264d_get_mb_info_cavlc_mbaff(dec_struct_t *ps_dec,\n                                       const UWORD16 u2_cur_mb_address,\n                                       dec_mb_info_t * ps_cur_mb_info,\n                                       UWORD32 u4_mbskip_run)\n{\n    UWORD16 u2_mb_x;\n    UWORD16 u2_mb_y;\n    UWORD8 u1_mb_ngbr_avail = 0;\n    UWORD16 u2_frm_width_in_mb = ps_dec->u2_frm_wd_in_mbs;\n\n    UWORD8 u1_top_mb = 1 - (u2_cur_mb_address & 0x01);\n    WORD16 i2_prev_slice_mbx = ps_dec->i2_prev_slice_mbx;\n    UWORD8 u1_cur_mb_field = 0;\n    UWORD16 u2_top_right_mask = TOP_RIGHT_DEFAULT_AVAILABLE;\n    UWORD16 u2_top_left_mask = TOP_LEFT_DEFAULT_AVAILABLE;\n\n    /*--------------------------------------------------------------------*/\n    /* Calculate values of mb_x and mb_y                                  */\n    /*--------------------------------------------------------------------*/\n    u2_mb_x = ps_dec->u2_mbx;\n    u2_mb_y = ps_dec->u2_mby;\n\n    ps_dec->u2_cur_mb_addr = u2_cur_mb_address;\n\n\n    if(u1_top_mb)\n    {\n        u2_mb_x++;\n        if(u2_mb_x == u2_frm_width_in_mb)\n        {\n            u2_mb_x = 0;\n            u2_mb_y += 2;\n        }\n        if(u2_mb_y > ps_dec->i2_prev_slice_mby)\n        {\n            /* if not in the immemdiate row of prev slice end then top\n             will be available */\n            if(u2_mb_y > (ps_dec->i2_prev_slice_mby + 2))\n                i2_prev_slice_mbx = -1;\n            if(u2_mb_x > i2_prev_slice_mbx)\n            {\n                u1_mb_ngbr_avail |= TOP_MB_AVAILABLE_MASK;\n                u1_cur_mb_field = ps_dec->ps_top_mb_row[u2_mb_x << 1].u1_mb_fld;\n                u2_top_right_mask |= TOP_RIGHT_TOP_AVAILABLE;\n                u2_top_left_mask |= TOP_LEFT_TOP_AVAILABLE;\n            }\n            if((u2_mb_x > (i2_prev_slice_mbx - 1))\n                            && (u2_mb_x != (u2_frm_width_in_mb - 1)))\n            {\n                u1_mb_ngbr_avail |= TOP_RIGHT_MB_AVAILABLE_MASK;\n                u2_top_right_mask |= TOP_RIGHT_TOPR_AVAILABLE;\n            }\n\n            if(u2_mb_x > (i2_prev_slice_mbx + 1))\n            {\n                u1_mb_ngbr_avail |= TOP_LEFT_MB_AVAILABLE_MASK;\n                u2_top_left_mask |= TOP_LEFT_TOPL_AVAILABLE;\n            }\n\n            i2_prev_slice_mbx = -1;\n        }\n        /* Same row */\n        if(u2_mb_x > (i2_prev_slice_mbx + 1))\n        {\n            u1_mb_ngbr_avail |= LEFT_MB_AVAILABLE_MASK;\n            u1_cur_mb_field =\n                            ps_dec->ps_cur_mb_row[(u2_mb_x << 1) - 1].u1_mb_fld;\n            u2_top_left_mask |= TOP_LEFT_LEFT_AVAILABLE;\n        }\n        /* Read u1_cur_mb_field from the bitstream if u4_mbskip_run <= 1*/\n        if(u4_mbskip_run <= 1)\n            u1_cur_mb_field = (UWORD8)ih264d_get_bit_h264(ps_dec->ps_bitstrm);\n\n        ps_dec->u1_cur_mb_fld_dec_flag = u1_cur_mb_field;\n        ps_dec->u2_top_left_mask = u2_top_left_mask;\n        ps_dec->u2_top_right_mask = u2_top_right_mask;\n    }\n    else\n    {\n        u1_mb_ngbr_avail = ps_dec->u1_mb_ngbr_availablity;\n        u1_cur_mb_field = ps_dec->u1_cur_mb_fld_dec_flag;\n        u2_top_left_mask = ps_dec->u2_top_left_mask;\n        u2_top_right_mask = ps_dec->u2_top_right_mask;\n\n        if(!u1_cur_mb_field)\n        {\n            /* Top is available */\n            u1_mb_ngbr_avail |= TOP_MB_AVAILABLE_MASK;\n            u2_top_right_mask |= TOP_RIGHT_TOP_AVAILABLE;\n            u2_top_left_mask |= TOP_LEFT_TOP_AVAILABLE;\n            /* Top Right not available */\n            u1_mb_ngbr_avail &= TOP_RT_SUBBLOCK_MASK_MOD;\n            u2_top_right_mask &= (~TOP_RIGHT_TOPR_AVAILABLE);\n\n            if(u1_mb_ngbr_avail & LEFT_MB_AVAILABLE_MASK)\n            {\n                u1_mb_ngbr_avail |= TOP_LEFT_MB_AVAILABLE_MASK;\n                u2_top_left_mask |= TOP_LEFT_LEFT_AVAILABLE;\n                u2_top_left_mask |= TOP_LEFT_TOPL_AVAILABLE;\n            }\n        }\n    }\n\n    ps_dec->u2_mby = u2_mb_y;\n    ps_dec->u2_mbx = u2_mb_x;\n    ps_cur_mb_info->u2_mbx = u2_mb_x;\n    ps_cur_mb_info->u2_mby = u2_mb_y;\n    ps_cur_mb_info->u1_topmb = u1_top_mb;\n    ps_dec->i4_submb_ofst += SUB_BLK_SIZE;\n    ps_dec->u1_mb_ngbr_availablity = u1_mb_ngbr_avail;\n    ps_cur_mb_info->u1_mb_ngbr_availablity = u1_mb_ngbr_avail;\n    ps_cur_mb_info->u1_mb_field_decodingflag = u1_cur_mb_field;\n    ps_cur_mb_info->u2_top_left_avail_mask = u2_top_left_mask;\n    ps_cur_mb_info->u2_top_right_avail_mask = u2_top_right_mask;\n    ih264d_get_mbaff_neighbours(ps_dec, ps_cur_mb_info, u1_cur_mb_field);\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : get_mb_info_cabac                                        */\n/*                                                                           */\n/*  Description   : This function sets the following information of cur MB   */\n/*                  (a) mb_x and mb_y                                        */\n/*                  (b) Neighbour availablity                                */\n/*                  (c) Macroblock location in the frame buffer              */\n/*                  (e) leftMb parama and TopMb params of curMB              */\n/*                  (f) For Mbaff case leftMb params and TopMb params of     */\n/*                      bottomMb are also set if curMB is top                */\n/*                  (g) For mbaff predicts field/frame u4_flag for topMb        */\n/*                      and sets the field/frame for botMb. This is          */\n/*                      written in ps_dec->u1_cur_mb_fld_dec_flag            */\n/*                                                                           */\n/*  Inputs        : pointer to decstruct                                     */\n/*                  pointer to current mb info                               */\n/*                  currentMbaddress                                         */\n/*                                                                           */\n/*  Processing    : leftMb and TopMb params are used by DecMbskip and        */\n/*                  DecCtxMbfield  modules so that these modules do not      */\n/*                  check for neigbour availability and then find the        */\n/*                  neigbours for context increments                         */\n/*                                                                           */\n/*  Returns       : OK                                                       */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 07 2002   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nUWORD32 ih264d_get_mb_info_cabac_nonmbaff(dec_struct_t *ps_dec,\n                                          const UWORD16 u2_cur_mb_address,\n                                          dec_mb_info_t * ps_cur_mb_info,\n                                          UWORD32 u4_mbskip)\n{\n    WORD32 mb_x;\n    WORD32 mb_y;\n    UWORD32 u1_mb_ngbr_avail = 0;\n    UWORD32 u2_frm_width_in_mb = ps_dec->u2_frm_wd_in_mbs;\n    UWORD32 u1_top_mb = 1;\n    WORD32 i2_prev_slice_mbx = ps_dec->i2_prev_slice_mbx;\n    UWORD32 u2_top_right_mask = TOP_RIGHT_DEFAULT_AVAILABLE;\n    UWORD32 u2_top_left_mask = TOP_LEFT_DEFAULT_AVAILABLE;\n    ctxt_inc_mb_info_t * const p_ctx_inc_mb_map = ps_dec->p_ctxt_inc_mb_map;\n\n    /*--------------------------------------------------------------------*/\n    /* Calculate values of mb_x and mb_y                                  */\n    /*--------------------------------------------------------------------*/\n    mb_x = (WORD16)ps_dec->u2_mbx;\n    mb_y = (WORD16)ps_dec->u2_mby;\n\n    ps_dec->u2_cur_mb_addr = u2_cur_mb_address;\n\n    mb_x++;\n    if((UWORD32)mb_x == u2_frm_width_in_mb)\n    {\n        mb_x = 0;\n        mb_y++;\n    }\n    /*********************************************************************/\n    /* Cabac Context Initialisations                                     */\n    /*********************************************************************/\n    ps_dec->ps_curr_ctxt_mb_info = p_ctx_inc_mb_map + mb_x;\n    ps_dec->p_left_ctxt_mb_info = p_ctx_inc_mb_map - 1;\n    ps_dec->p_top_ctxt_mb_info = p_ctx_inc_mb_map - 1;\n\n    /********************************************************************/\n    /* neighbour availablility                                          */\n    /********************************************************************/\n    if(mb_y > ps_dec->i2_prev_slice_mby)\n    {\n        /* if not in the immemdiate row of prev slice end then top\n         will be available */\n        if(mb_y > (ps_dec->i2_prev_slice_mby + 1))\n            i2_prev_slice_mbx = -1;\n\n        if(mb_x > i2_prev_slice_mbx)\n        {\n            u1_mb_ngbr_avail |= TOP_MB_AVAILABLE_MASK;\n            u2_top_right_mask |= TOP_RIGHT_TOP_AVAILABLE;\n            u2_top_left_mask |= TOP_LEFT_TOP_AVAILABLE;\n            ps_dec->p_top_ctxt_mb_info = ps_dec->ps_curr_ctxt_mb_info;\n        }\n        if((mb_x > (i2_prev_slice_mbx - 1))\n                        && ((UWORD32)mb_x != (u2_frm_width_in_mb - 1)))\n        {\n            u1_mb_ngbr_avail |= TOP_RIGHT_MB_AVAILABLE_MASK;\n            u2_top_right_mask |= TOP_RIGHT_TOPR_AVAILABLE;\n        }\n\n        if(mb_x > (i2_prev_slice_mbx + 1))\n        {\n            u1_mb_ngbr_avail |= TOP_LEFT_MB_AVAILABLE_MASK;\n            u2_top_left_mask |= TOP_LEFT_TOPL_AVAILABLE;\n        }\n        /* Next row */\n        i2_prev_slice_mbx = -1;\n    }\n    /* Same row */\n    if(mb_x > (i2_prev_slice_mbx + 1))\n    {\n        u1_mb_ngbr_avail |= LEFT_MB_AVAILABLE_MASK;\n        u2_top_left_mask |= TOP_LEFT_LEFT_AVAILABLE;\n        ps_dec->p_left_ctxt_mb_info = ps_dec->ps_curr_ctxt_mb_info - 1;\n    }\n    {\n        mb_neigbour_params_t *ps_cur_mb_row = ps_dec->ps_cur_mb_row;\n        mb_neigbour_params_t *ps_top_mb_row = ps_dec->ps_top_mb_row;\n        /* copy the parameters of topleft Mb */\n        ps_cur_mb_info->u1_topleft_mbtype = ps_dec->u1_topleft_mbtype;\n        /* Neighbour pointer assignments*/\n        ps_cur_mb_info->ps_curmb = ps_cur_mb_row + mb_x;\n        ps_cur_mb_info->ps_left_mb = ps_cur_mb_row + mb_x - 1;\n        ps_cur_mb_info->ps_top_mb = ps_top_mb_row + mb_x;\n        ps_cur_mb_info->ps_top_right_mb = ps_top_mb_row + mb_x + 1;\n\n        /* Update the parameters of topleftmb*/\n        ps_dec->u1_topleft_mbtype = ps_cur_mb_info->ps_top_mb->u1_mb_type;\n    }\n\n    ps_dec->u2_mby = mb_y;\n    ps_dec->u2_mbx = mb_x;\n    ps_cur_mb_info->u2_mbx = mb_x;\n    ps_cur_mb_info->u2_mby = mb_y;\n    ps_cur_mb_info->u1_topmb = u1_top_mb;\n    ps_dec->i4_submb_ofst += SUB_BLK_SIZE;\n    ps_dec->u1_mb_ngbr_availablity = u1_mb_ngbr_avail;\n    ps_cur_mb_info->u1_mb_ngbr_availablity = u1_mb_ngbr_avail;\n    ps_cur_mb_info->ps_curmb->u1_mb_fld = ps_dec->u1_cur_mb_fld_dec_flag;\n    ps_cur_mb_info->u1_mb_field_decodingflag = ps_dec->u1_cur_mb_fld_dec_flag;\n    ps_cur_mb_info->u2_top_left_avail_mask = u2_top_left_mask;\n    ps_cur_mb_info->u2_top_right_avail_mask = u2_top_right_mask;\n\n    /*********************************************************************/\n    /*                  Assign the neigbours                             */\n    /*********************************************************************/\n    if(u4_mbskip)\n    {\n        UWORD32 u4_ctx_inc =\n                        2\n                                        - ((!!(ps_dec->p_top_ctxt_mb_info->u1_mb_type\n                                                        & CAB_SKIP_MASK))\n                                                        + (!!(ps_dec->p_left_ctxt_mb_info->u1_mb_type\n                                                                        & CAB_SKIP_MASK)));\n\n        u4_mbskip = ih264d_decode_bin(u4_ctx_inc, ps_dec->p_mb_skip_flag_t,\n                                      ps_dec->ps_bitstrm, &ps_dec->s_cab_dec_env);\n\n        if(!u4_mbskip)\n        {\n            if(!(u1_mb_ngbr_avail & LEFT_MB_AVAILABLE_MASK))\n            {\n                UWORD32 *pu4_buf;\n                UWORD8 *pu1_buf;\n\n                pu1_buf = ps_dec->pu1_left_nnz_y;\n                pu4_buf = (UWORD32 *)pu1_buf;\n                *pu4_buf = 0;\n                pu1_buf = ps_dec->pu1_left_nnz_uv;\n                pu4_buf = (UWORD32 *)pu1_buf;\n                *pu4_buf = 0;\n\n\n                *(ps_dec->pu1_left_yuv_dc_csbp) = 0;\n                MEMSET_16BYTES(&ps_dec->pu1_left_mv_ctxt_inc[0][0], 0);\n                *(UWORD32 *)ps_dec->pi1_left_ref_idx_ctxt_inc = 0;\n            }\n            if(!(u1_mb_ngbr_avail & TOP_MB_AVAILABLE_MASK))\n            {\n                MEMSET_16BYTES(ps_dec->ps_curr_ctxt_mb_info->u1_mv, 0);\n                memset(ps_dec->ps_curr_ctxt_mb_info->i1_ref_idx, 0, 4);\n            }\n        }\n    }\n    return (u4_mbskip);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : get_mb_info_cabac                                        */\n/*                                                                           */\n/*  Description   : This function sets the following information of cur MB   */\n/*                  (a) mb_x and mb_y                                        */\n/*                  (b) Neighbour availablity                                */\n/*                  (c) Macroblock location in the frame buffer              */\n/*                  (e) leftMb parama and TopMb params of curMB              */\n/*                  (f) For Mbaff case leftMb params and TopMb params of     */\n/*                      bottomMb are also set if curMB is top                */\n/*                  (g) For mbaff predicts field/frame u4_flag for topMb        */\n/*                      and sets the field/frame for botMb. This is          */\n/*                      written in ps_dec->u1_cur_mb_fld_dec_flag            */\n/*                                                                           */\n/*  Inputs        : pointer to decstruct                                     */\n/*                  pointer to current mb info                               */\n/*                  currentMbaddress                                         */\n/*                                                                           */\n/*  Processing    : leftMb and TopMb params are used by DecMbskip and        */\n/*                  DecCtxMbfield  modules so that these modules do not      */\n/*                  check for neigbour availability and then find the        */\n/*                  neigbours for context increments                         */\n/*                                                                           */\n/*  Returns       : OK                                                       */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 07 2002   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nUWORD32 ih264d_get_mb_info_cabac_mbaff(dec_struct_t *ps_dec,\n                                       const UWORD16 u2_cur_mb_address,\n                                       dec_mb_info_t * ps_cur_mb_info,\n                                       UWORD32 u4_mbskip)\n{\n    WORD32 mb_x;\n    WORD32 mb_y;\n    UWORD8 u1_mb_ngbr_avail = 0;\n    UWORD16 u2_frm_width_in_mb = ps_dec->u2_frm_wd_in_mbs;\n    ctxt_inc_mb_info_t * const p_ctx_inc_mb_map = ps_dec->p_ctxt_inc_mb_map;\n    ctxt_inc_mb_info_t *ps_curr_ctxt, *ps_top_ctxt, *ps_left_ctxt;\n    mb_neigbour_params_t *ps_cur_mb_row = ps_dec->ps_cur_mb_row;\n    mb_neigbour_params_t *ps_top_mb_row = ps_dec->ps_top_mb_row;\n    UWORD32 u4_left_mb_pair_fld = 0;\n    UWORD32 u4_top_mb_pair_fld = 0;\n    UWORD8 u1_cur_mb_field = 0;\n    UWORD8 u1_top_mb = 1 - (u2_cur_mb_address & 0x01);\n    WORD16 i2_prev_slice_mbx = ps_dec->i2_prev_slice_mbx;\n    UWORD16 u2_top_right_mask = TOP_RIGHT_DEFAULT_AVAILABLE;\n    UWORD16 u2_top_left_mask = TOP_LEFT_DEFAULT_AVAILABLE;\n\n    /*--------------------------------------------------------------------*/\n    /* Calculate values of mb_x and mb_y                                  */\n    /*--------------------------------------------------------------------*/\n    mb_x = (WORD16)ps_dec->u2_mbx;\n    mb_y = (WORD16)ps_dec->u2_mby;\n\n    ps_dec->u2_cur_mb_addr = u2_cur_mb_address;\n\n    ps_top_ctxt = ps_left_ctxt = p_ctx_inc_mb_map - 1;\n\n    if(u1_top_mb)\n    {\n        ctxt_inc_mb_info_t *ps_left_mb_of_bot = ps_left_ctxt;\n        ctxt_inc_mb_info_t *ps_top_mb_of_bot = ps_top_ctxt;\n\n        mb_x++;\n\n        if(mb_x == u2_frm_width_in_mb)\n        {\n            mb_x = 0;\n            mb_y += 2;\n        }\n\n        ps_curr_ctxt = p_ctx_inc_mb_map + (mb_x << 1);\n        if(mb_y > ps_dec->i2_prev_slice_mby)\n        {\n            UWORD8 u1_cur_mb_fld_flag_known = 0;\n            /* Next row */\n            if(mb_x > 0)\n            {\n                /***********************************************************************/\n                /*                    Left Mb is avialable                             */\n                /***********************************************************************/\n                u1_mb_ngbr_avail |= LEFT_MB_AVAILABLE_MASK;\n                ps_left_ctxt = ps_curr_ctxt - 2;\n                ps_left_mb_of_bot = ps_curr_ctxt - 1;\n                u1_cur_mb_field = u4_left_mb_pair_fld = ps_cur_mb_row[(mb_x\n                                << 1) - 1].u1_mb_fld;\n                u1_cur_mb_fld_flag_known = 1;\n                u2_top_left_mask |= TOP_LEFT_LEFT_AVAILABLE;\n            }\n            /* if not in the immemdiate row of prev slice end then top\n             will be available */\n            if(mb_y > (ps_dec->i2_prev_slice_mby + 2))\n                i2_prev_slice_mbx = -1;\n            if(mb_x > i2_prev_slice_mbx)\n            {\n                /*********************************************************************/\n                /*                    Top Mb is avialable                            */\n                /*********************************************************************/\n                u1_mb_ngbr_avail |= TOP_MB_AVAILABLE_MASK;\n                u2_top_right_mask |= TOP_RIGHT_TOP_AVAILABLE;\n                u2_top_left_mask |= TOP_LEFT_TOP_AVAILABLE;\n\n                /* point to MbAddrB + 1 */\n                ps_top_ctxt = ps_curr_ctxt + 1;\n                u4_top_mb_pair_fld = ps_top_mb_row[(mb_x << 1)].u1_mb_fld;\n\n                u1_cur_mb_field =\n                                u1_cur_mb_fld_flag_known ?\n                                                u1_cur_mb_field :\n                                                u4_top_mb_pair_fld;\n                ps_top_mb_of_bot = u1_cur_mb_field ? ps_top_ctxt : ps_curr_ctxt;\n\n                /* MbAddrB */\n                ps_top_ctxt -= (u1_cur_mb_field && u4_top_mb_pair_fld);\n            }\n\n            if((mb_x > (i2_prev_slice_mbx - 1))\n                            && (mb_x != (u2_frm_width_in_mb - 1)))\n            {\n                u1_mb_ngbr_avail |= TOP_RIGHT_MB_AVAILABLE_MASK;\n                u2_top_right_mask |= TOP_RIGHT_TOPR_AVAILABLE;\n            }\n\n            if(mb_x > (i2_prev_slice_mbx + 1))\n            {\n                u1_mb_ngbr_avail |= TOP_LEFT_MB_AVAILABLE_MASK;\n                u2_top_left_mask |= TOP_LEFT_TOPL_AVAILABLE;\n            }\n        }\n        else\n        {\n            /* Same row */\n            if(mb_x > (i2_prev_slice_mbx + 1))\n            {\n                /***************************************************************/\n                /*                    Left Mb is avialable                     */\n                /***************************************************************/\n                u1_mb_ngbr_avail |= LEFT_MB_AVAILABLE_MASK;\n\n                u1_cur_mb_field = u4_left_mb_pair_fld = ps_cur_mb_row[(mb_x\n                                << 1) - 1].u1_mb_fld;\n                ps_left_ctxt = ps_curr_ctxt - 2;\n                ps_left_mb_of_bot = ps_curr_ctxt - 1;\n                u2_top_left_mask |= TOP_LEFT_LEFT_AVAILABLE;\n            }\n        }\n        /*********************************************************/\n        /* Check whether the call is from I slice or Inter slice */\n        /*********************************************************/\n        if(u4_mbskip)\n        {\n            UWORD32 u4_ctx_inc = 2\n                            - ((!!(ps_top_ctxt->u1_mb_type & CAB_SKIP_MASK))\n                                            + (!!(ps_left_ctxt->u1_mb_type\n                                                            & CAB_SKIP_MASK)));\n            dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n            decoding_envirnoment_t *ps_cab_dec_env = &ps_dec->s_cab_dec_env;\n            bin_ctxt_model_t *p_mb_skip_flag_t = ps_dec->p_mb_skip_flag_t;\n\n            ps_dec->u4_next_mb_skip = 0;\n            u4_mbskip = ih264d_decode_bin(u4_ctx_inc, p_mb_skip_flag_t,\n                                          ps_bitstrm, ps_cab_dec_env);\n\n            if(u4_mbskip)\n            {\n                UWORD32 u4_next_mbskip;\n                ps_curr_ctxt->u1_mb_type = CAB_SKIP;\n\n                u4_ctx_inc =\n                                2\n                                                - ((!!(ps_top_mb_of_bot->u1_mb_type\n                                                                & CAB_SKIP_MASK))\n                                                                + (!!(ps_left_mb_of_bot->u1_mb_type\n                                                                                & CAB_SKIP_MASK)));\n\n                /* Decode the skip u4_flag of bottom Mb */\n                u4_next_mbskip = ih264d_decode_bin(u4_ctx_inc, p_mb_skip_flag_t,\n                                                   ps_bitstrm,\n                                                   ps_cab_dec_env);\n\n                ps_dec->u4_next_mb_skip = u4_next_mbskip;\n\n                if(!u4_next_mbskip)\n                {\n                    u4_ctx_inc = u4_top_mb_pair_fld + u4_left_mb_pair_fld;\n\n                    u1_cur_mb_field = ih264d_decode_bin(\n                                    u4_ctx_inc, ps_dec->p_mb_field_dec_flag_t,\n                                    ps_bitstrm, ps_cab_dec_env);\n                }\n            }\n        }\n\n        if(!u4_mbskip)\n        {\n            UWORD32 u4_ctx_inc = u4_top_mb_pair_fld + u4_left_mb_pair_fld;\n            u1_cur_mb_field = ih264d_decode_bin(u4_ctx_inc,\n                                                ps_dec->p_mb_field_dec_flag_t,\n                                                ps_dec->ps_bitstrm,\n                                                &ps_dec->s_cab_dec_env);\n        }\n\n        ps_dec->u1_cur_mb_fld_dec_flag = u1_cur_mb_field;\n        ps_dec->u2_top_left_mask = u2_top_left_mask;\n        ps_dec->u2_top_right_mask = u2_top_right_mask;\n        ps_dec->u2_mby = mb_y;\n        ps_dec->u2_mbx = mb_x;\n    }\n    else\n    {\n        u1_cur_mb_field = ps_dec->u1_cur_mb_fld_dec_flag;\n        u1_mb_ngbr_avail = ps_dec->u1_mb_ngbr_availablity;\n        u2_top_left_mask = ps_dec->u2_top_left_mask;\n        u2_top_right_mask = ps_dec->u2_top_right_mask;\n        ps_curr_ctxt = p_ctx_inc_mb_map + (mb_x << 1) + 1;\n\n        if(u1_mb_ngbr_avail & LEFT_MB_AVAILABLE_MASK)\n        {\n            u4_left_mb_pair_fld = ps_cur_mb_row[(mb_x << 1) - 1].u1_mb_fld;\n\n            /* point to A if top else A+1 */\n            ps_left_ctxt = ps_curr_ctxt - 2\n                            - (u4_left_mb_pair_fld != u1_cur_mb_field);\n        }\n\n        if(u1_cur_mb_field)\n        {\n            if(u1_mb_ngbr_avail & TOP_MB_AVAILABLE_MASK)\n            {\n                /* point to MbAddrB + 1 */\n                ps_top_ctxt = ps_curr_ctxt;\n            }\n        }\n        else\n        {\n            /* Top is available */\n            u1_mb_ngbr_avail |= TOP_MB_AVAILABLE_MASK;\n            u2_top_right_mask |= TOP_RIGHT_TOP_AVAILABLE;\n            u2_top_left_mask |= TOP_LEFT_TOP_AVAILABLE;\n            /* Top Right not available */\n            u1_mb_ngbr_avail &= TOP_RT_SUBBLOCK_MASK_MOD;\n            u2_top_right_mask &= (~TOP_RIGHT_TOPR_AVAILABLE);\n\n            if(u1_mb_ngbr_avail & LEFT_MB_AVAILABLE_MASK)\n            {\n                u1_mb_ngbr_avail |= TOP_LEFT_MB_AVAILABLE_MASK;\n                u2_top_left_mask |= TOP_LEFT_LEFT_AVAILABLE;\n                u2_top_left_mask |= TOP_LEFT_TOPL_AVAILABLE;\n            }\n\n            /* CurMbAddr - 1 */\n            ps_top_ctxt = ps_curr_ctxt - 1;\n        }\n\n        if(u4_mbskip)\n        {\n            if(ps_curr_ctxt[-1].u1_mb_type & CAB_SKIP_MASK)\n            {\n                /* If previous mb is skipped, return value of next mb skip */\n                u4_mbskip = ps_dec->u4_next_mb_skip;\n\n            }\n            else\n            {\n                /* If previous mb is not skipped then call DecMbSkip */\n                UWORD32 u4_ctx_inc =\n                                2\n                                                - ((!!(ps_top_ctxt->u1_mb_type\n                                                                & CAB_SKIP_MASK))\n                                                                + (!!(ps_left_ctxt->u1_mb_type\n                                                                                & CAB_SKIP_MASK)));\n\n                u4_mbskip = ih264d_decode_bin(u4_ctx_inc,\n                                              ps_dec->p_mb_skip_flag_t,\n                                              ps_dec->ps_bitstrm,\n                                              &ps_dec->s_cab_dec_env);\n            }\n        }\n    }\n\n    ps_cur_mb_info->u2_mbx = mb_x;\n    ps_cur_mb_info->u2_mby = mb_y;\n    ps_cur_mb_info->u1_topmb = u1_top_mb;\n    ps_dec->i4_submb_ofst += SUB_BLK_SIZE;\n    ps_dec->u1_mb_ngbr_availablity = u1_mb_ngbr_avail;\n    ps_cur_mb_info->u1_mb_ngbr_availablity = u1_mb_ngbr_avail;\n    ps_cur_mb_info->u1_mb_field_decodingflag = u1_cur_mb_field;\n    ps_cur_mb_info->u2_top_left_avail_mask = u2_top_left_mask;\n    ps_cur_mb_info->u2_top_right_avail_mask = u2_top_right_mask;\n\n    ih264d_get_mbaff_neighbours(ps_dec, ps_cur_mb_info, u1_cur_mb_field);\n    {\n        ih264d_get_cabac_context_mbaff(ps_dec, ps_cur_mb_info, u4_mbskip);\n    }\n\n    {\n        bin_ctxt_model_t *p_cabac_ctxt_table_t = ps_dec->p_cabac_ctxt_table_t;\n\n        if(u1_cur_mb_field)\n        {\n            p_cabac_ctxt_table_t += SIGNIFICANT_COEFF_FLAG_FLD;\n        }\n        else\n        {\n            p_cabac_ctxt_table_t += SIGNIFICANT_COEFF_FLAG_FRAME;\n        }\n        {\n            bin_ctxt_model_t * * p_significant_coeff_flag_t =\n                            ps_dec->p_significant_coeff_flag_t;\n            p_significant_coeff_flag_t[0] = p_cabac_ctxt_table_t\n                            + SIG_COEFF_CTXT_CAT_0_OFFSET;\n            p_significant_coeff_flag_t[1] = p_cabac_ctxt_table_t\n                            + SIG_COEFF_CTXT_CAT_1_OFFSET;\n            p_significant_coeff_flag_t[2] = p_cabac_ctxt_table_t\n                            + SIG_COEFF_CTXT_CAT_2_OFFSET;\n            p_significant_coeff_flag_t[3] = p_cabac_ctxt_table_t\n                            + SIG_COEFF_CTXT_CAT_3_OFFSET;\n            p_significant_coeff_flag_t[4] = p_cabac_ctxt_table_t\n                            + SIG_COEFF_CTXT_CAT_4_OFFSET;\n            p_significant_coeff_flag_t[5] = p_cabac_ctxt_table_t\n                            + SIG_COEFF_CTXT_CAT_5_OFFSET;\n\n        }\n    }\n    return (u4_mbskip);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_get_cabac_context_mbaff                                  */\n/*                                                                           */\n/*  Description   : Gets the current macroblock Cabac Context and sets the   */\n/*                  top and left cabac context ptrs in CtxIncMbMap           */\n/*                  1. For Coss field left neigbours it alters coded block   */\n/*                     u4_flag , motion vectors, reference indices, cbp of      */\n/*                     the left neigbours which increases the code i4_size      */\n/*                  2. For Coss field top neigbours it alters motion         */\n/*                     vectors reference indices of the top neigbours        */\n/*                     which further increases the code i4_size                 */\n/*                                                                           */\n/*  Inputs        : 1. dec_struct_t                                             */\n/*                  2. CurMbAddr used for Mbaff (only to see if curMB        */\n/*                  is top or bottom)                                        */\n/*                  3. uc_curMbFldDecFlag only for Mbaff                     */\n/*                                                                           */\n/*  Returns       : 0                                                        */\n/*                                                                           */\n/*  Issues        : code i4_size can be reduced if ui_CodedBlockFlag storage    */\n/*                  structure in context is changed. This change however     */\n/*                  would break the parseResidual4x4Cabac asm routine.       */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         18 06 2005   Jay                                                  */\n/*                                                                           */\n/*****************************************************************************/\nUWORD32 ih264d_get_cabac_context_mbaff(dec_struct_t * ps_dec,\n                                       dec_mb_info_t *ps_cur_mb_info,\n                                       UWORD32 u4_mbskip)\n{\n    const UWORD8 u1_mb_ngbr_availablity = ps_dec->u1_mb_ngbr_availablity;\n    ctxt_inc_mb_info_t * const p_ctx_inc_mb_map = ps_dec->p_ctxt_inc_mb_map;\n\n    UWORD8 (*pu1_left_mv_ctxt_inc_2d)[4] = &ps_dec->pu1_left_mv_ctxt_inc[0];\n    WORD8 (*pi1_left_ref_idx_ctxt_inc) = ps_dec->pi1_left_ref_idx_ctxt_inc;\n    const UWORD8 u1_cur_mb_fld_flag = ps_cur_mb_info->u1_mb_field_decodingflag;\n    const UWORD8 u1_topmb = ps_cur_mb_info->u1_topmb;\n    const UWORD8 uc_botMb = 1 - ps_cur_mb_info->u1_topmb;\n\n    ctxt_inc_mb_info_t * ps_leftMB;\n\n    ps_dec->ps_curr_ctxt_mb_info = p_ctx_inc_mb_map + (ps_dec->u2_mbx << 1);\n    ps_dec->p_top_ctxt_mb_info = ps_dec->ps_curr_ctxt_mb_info;\n\n    if(u1_topmb)\n    {\n        pu1_left_mv_ctxt_inc_2d = ps_dec->u1_left_mv_ctxt_inc_arr[0];\n        pi1_left_ref_idx_ctxt_inc = &ps_dec->i1_left_ref_idx_ctx_inc_arr[0][0];\n        ps_dec->pu1_left_yuv_dc_csbp = &ps_dec->u1_yuv_dc_csbp_topmb;\n    }\n    else\n    {\n        /* uc_botMb */\n        pu1_left_mv_ctxt_inc_2d = ps_dec->u1_left_mv_ctxt_inc_arr[1];\n        pi1_left_ref_idx_ctxt_inc = &ps_dec->i1_left_ref_idx_ctx_inc_arr[1][0];\n        ps_dec->pu1_left_yuv_dc_csbp = &ps_dec->u1_yuv_dc_csbp_bot_mb;\n        ps_dec->ps_curr_ctxt_mb_info += 1;\n    }\n\n    ps_dec->pu1_left_mv_ctxt_inc = pu1_left_mv_ctxt_inc_2d;\n    ps_dec->pi1_left_ref_idx_ctxt_inc = pi1_left_ref_idx_ctxt_inc;\n\n    if(u1_mb_ngbr_availablity & LEFT_MB_AVAILABLE_MASK)\n    {\n        const UWORD8 u1_left_mb_fld_flag = ps_cur_mb_info->ps_left_mb->u1_mb_fld;\n\n        ps_leftMB = ps_dec->ps_curr_ctxt_mb_info - 2;\n        if(u1_left_mb_fld_flag != u1_cur_mb_fld_flag)\n        {\n            ctxt_inc_mb_info_t *ps_tempLeft;\n            UWORD8 u1_cbp_t, u1_cbp_b;\n            UWORD8 u1_cr_cpb;\n\n            ps_leftMB -= uc_botMb;\n            ps_tempLeft = ps_dec->ps_left_mb_ctxt_info;\n            ps_tempLeft->u1_mb_type = ps_leftMB->u1_mb_type;\n            ps_tempLeft->u1_intra_chroma_pred_mode =\n                            ps_leftMB->u1_intra_chroma_pred_mode;\n\n            ps_tempLeft->u1_transform8x8_ctxt = ps_leftMB->u1_transform8x8_ctxt;\n\n            u1_cr_cpb = ps_leftMB->u1_cbp;\n            /*****************************************************************/\n            /* reform RefIdx, CBP, MV and CBF ctxInc taking care of A and A+1*/\n            /*****************************************************************/\n            if(u1_cur_mb_fld_flag)\n            {\n                /* current MB is a FLD and left a FRM */\n                UWORD8 (* const pu1_left_mv_ctxt_inc_2d_arr_top)[4] =\n                                ps_dec->u1_left_mv_ctxt_inc_arr[0];\n                UWORD8 (* const pu1_left_mv_ctxt_inc_2d_arr_bot)[4] =\n                                ps_dec->u1_left_mv_ctxt_inc_arr[1];\n                WORD8 (* const i1_left_ref_idx_ctxt_inc_arr_top) =\n                                &ps_dec->i1_left_ref_idx_ctx_inc_arr[0][0];\n                WORD8 (* const i1_left_ref_idx_ctxt_inc_arr_bot) =\n                                &ps_dec->i1_left_ref_idx_ctx_inc_arr[1][0];\n\n                u1_cbp_t = ps_leftMB->u1_cbp;\n                u1_cbp_b = (ps_leftMB + 1)->u1_cbp;\n                ps_tempLeft->u1_cbp = (u1_cbp_t & 0x02)\n                                | ((u1_cbp_b & 0x02) << 2);\n\n                // set motionvectors as\n                // 0T = 0T  0B = 0T\n                // 1T = 2T  1B = 2T\n                // 2T = 0B  2B = 0B\n                // 3T = 2B  3B = 2B\n                if(u1_topmb)\n                {\n                    /********************************************/\n                    /*    Bottoms  DC CBF = Top DC CBF          */\n                    /********************************************/\n                    ps_dec->u1_yuv_dc_csbp_bot_mb =\n                                    ps_dec->u1_yuv_dc_csbp_topmb;\n\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[3] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d_arr_bot[2];\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[1] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d_arr_top[2];\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[2] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d_arr_bot[0];\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[0] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d_arr_top[0];\n\n                    i1_left_ref_idx_ctxt_inc_arr_top[1] =\n                                    i1_left_ref_idx_ctxt_inc_arr_bot[0];\n                    i1_left_ref_idx_ctxt_inc_arr_top[3] =\n                                    i1_left_ref_idx_ctxt_inc_arr_bot[2];\n\n                    *(UWORD32 *)(i1_left_ref_idx_ctxt_inc_arr_bot) =\n                                    *(UWORD32 *)(i1_left_ref_idx_ctxt_inc_arr_top);\n\n                    memcpy(pu1_left_mv_ctxt_inc_2d_arr_bot,\n                           pu1_left_mv_ctxt_inc_2d_arr_top, 16);\n                }\n\n                {\n                    UWORD8 i;\n                    for(i = 0; i < 4; i++)\n                    {\n                        pu1_left_mv_ctxt_inc_2d[i][1] >>= 1;\n                        pu1_left_mv_ctxt_inc_2d[i][3] >>= 1;\n                    }\n                }\n            }\n            else\n            {\n                /* current MB is a FRM and left FLD */\n                if(u1_topmb)\n                {\n                    u1_cbp_t = ps_leftMB->u1_cbp;\n                    u1_cbp_t = (u1_cbp_t & 0x02);\n                    ps_tempLeft->u1_cbp = (u1_cbp_t | (u1_cbp_t << 2));\n\n                    /********************************************/\n                    /*    Bottoms  DC CBF = Top DC CBF          */\n                    /********************************************/\n                    ps_dec->u1_yuv_dc_csbp_bot_mb =\n                                    ps_dec->u1_yuv_dc_csbp_topmb;\n\n                    // set motionvectors as\n                    // 3B = 2B = 3T\n                    // 1B = 0B = 2T\n                    // 3T = 2T = 1T\n                    // 1T = 0T = 0T\n\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[7] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[3];\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[6] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[3];\n\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[5] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[2];\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[4] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[2];\n\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[3] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[1];\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[2] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[1];\n\n                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[1] =\n                                    *(UWORD32 *)pu1_left_mv_ctxt_inc_2d[0];\n\n                    pi1_left_ref_idx_ctxt_inc[7] = (pi1_left_ref_idx_ctxt_inc[3]\n                                    - 1);\n                    pi1_left_ref_idx_ctxt_inc[6] = (pi1_left_ref_idx_ctxt_inc[3]\n                                    - 1);\n\n                    pi1_left_ref_idx_ctxt_inc[5] = (pi1_left_ref_idx_ctxt_inc[1]\n                                    - 1);\n                    pi1_left_ref_idx_ctxt_inc[4] = (pi1_left_ref_idx_ctxt_inc[1]\n                                    - 1);\n\n                    pi1_left_ref_idx_ctxt_inc[3] = (pi1_left_ref_idx_ctxt_inc[2]\n                                    - 1);\n                    pi1_left_ref_idx_ctxt_inc[2] = (pi1_left_ref_idx_ctxt_inc[2]\n                                    - 1);\n\n                    pi1_left_ref_idx_ctxt_inc[1] = (pi1_left_ref_idx_ctxt_inc[0]\n                                    - 1);\n                    pi1_left_ref_idx_ctxt_inc[0] = (pi1_left_ref_idx_ctxt_inc[0]\n                                    - 1);\n                }\n                else\n                {\n                    u1_cbp_t = ps_leftMB->u1_cbp;\n                    u1_cbp_t = (u1_cbp_t & 0x08);\n                    ps_tempLeft->u1_cbp = (u1_cbp_t | (u1_cbp_t >> 2));\n                }\n\n                {\n                    UWORD8 i;\n                    for(i = 0; i < 4; i++)\n                    {\n                        pu1_left_mv_ctxt_inc_2d[i][1] <<= 1;\n                        pu1_left_mv_ctxt_inc_2d[i][3] <<= 1;\n                    }\n                }\n\n            }\n\n            ps_tempLeft->u1_cbp = ps_tempLeft->u1_cbp + ((u1_cr_cpb >> 4) << 4);\n            ps_leftMB = ps_tempLeft;\n        }\n\n        ps_dec->p_left_ctxt_mb_info = ps_leftMB;\n    }\n    else\n    {\n        ps_dec->p_left_ctxt_mb_info = p_ctx_inc_mb_map - 1;\n        if(!u4_mbskip)\n        {\n            *(ps_dec->pu1_left_yuv_dc_csbp) = 0;\n\n            MEMSET_16BYTES(&pu1_left_mv_ctxt_inc_2d[0][0], 0);\n            *(UWORD32 *)pi1_left_ref_idx_ctxt_inc = 0;\n        }\n    }\n\n    /*************************************************************************/\n    /*                Now get the top context mb info                        */\n    /*************************************************************************/\n    {\n        UWORD8 (*u1_top_mv_ctxt_inc_arr_2d)[4] =\n                        ps_dec->ps_curr_ctxt_mb_info->u1_mv;\n        WORD8 (*pi1_top_ref_idx_ctxt_inc) =\n                        ps_dec->ps_curr_ctxt_mb_info->i1_ref_idx;\n        UWORD8 uc_topMbFldDecFlag = ps_cur_mb_info->ps_top_mb->u1_mb_fld;\n\n        if(u1_mb_ngbr_availablity & TOP_MB_AVAILABLE_MASK)\n        {\n            if(ps_cur_mb_info->i1_offset)\n                ps_dec->p_top_ctxt_mb_info += 1;\n\n            if(!u4_mbskip)\n            {\n                memcpy(u1_top_mv_ctxt_inc_arr_2d,\n                       &ps_dec->p_top_ctxt_mb_info->u1_mv, 16);\n                memcpy(pi1_top_ref_idx_ctxt_inc,\n                       &ps_dec->p_top_ctxt_mb_info->i1_ref_idx, 4);\n                if(uc_topMbFldDecFlag ^ u1_cur_mb_fld_flag)\n                {\n                    UWORD8 i;\n                    if(u1_cur_mb_fld_flag)\n                    {\n                        for(i = 0; i < 4; i++)\n                        {\n                            u1_top_mv_ctxt_inc_arr_2d[i][1] >>= 1;\n                            u1_top_mv_ctxt_inc_arr_2d[i][3] >>= 1;\n                        }\n                    }\n                    else\n                    {\n                        for(i = 0; i < 4; i++)\n                        {\n                            u1_top_mv_ctxt_inc_arr_2d[i][1] <<= 1;\n                            u1_top_mv_ctxt_inc_arr_2d[i][3] <<= 1;\n                            pi1_top_ref_idx_ctxt_inc[i] -= 1;\n                        }\n                    }\n                }\n            }\n        }\n        else\n        {\n            ps_dec->p_top_ctxt_mb_info = p_ctx_inc_mb_map - 1;\n            if(!u4_mbskip)\n            {\n\n                MEMSET_16BYTES(&u1_top_mv_ctxt_inc_arr_2d[0][0], 0);\n                memset(pi1_top_ref_idx_ctxt_inc, 0, 4);\n            }\n        }\n    }\n\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_update_mbaff_left_nnz                                    */\n/*                                                                           */\n/*  Description   : This function updates the left luma and chroma nnz for   */\n/*                  mbaff cases.                                             */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 07 2002   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_update_mbaff_left_nnz(dec_struct_t * ps_dec,\n                                  dec_mb_info_t * ps_cur_mb_info)\n{\n    UWORD32 *pu4_buf;\n    UWORD8 *pu1_buf;\n    if(ps_cur_mb_info->u1_topmb)\n    {\n        pu1_buf = ps_dec->pu1_left_nnz_y;\n        pu4_buf = (UWORD32 *)pu1_buf;\n        ps_dec->u4_n_left_temp_y = *pu4_buf;\n\n        pu1_buf = ps_dec->pu1_left_nnz_uv;\n        pu4_buf = (UWORD32 *)pu1_buf;\n        ps_dec->u4_n_left_temp_uv = *pu4_buf;\n    }\n    else\n    {\n\n        ps_dec->u4_n_leftY[0] = ps_dec->u4_n_left_temp_y;\n        pu1_buf = ps_dec->pu1_left_nnz_y;\n        pu4_buf = (UWORD32 *)pu1_buf;\n        ps_dec->u4_n_leftY[1] = *pu4_buf;\n        ps_dec->u4_n_left_cr[0] = ps_dec->u4_n_left_temp_uv;\n        pu1_buf = ps_dec->pu1_left_nnz_uv;\n        pu4_buf = (UWORD32 *)pu1_buf;\n        ps_dec->u4_n_left_cr[1] = *pu4_buf;\n\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_get_mbaff_neighbours \\endif\n *\n * \\brief\n *    Gets the neighbors for the current MB if it is of type MB-AFF\n *  frame.\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\nvoid ih264d_get_mbaff_neighbours(dec_struct_t * ps_dec,\n                                 dec_mb_info_t * ps_cur_mb_info,\n                                 UWORD8 uc_curMbFldDecFlag)\n{\n\n    mb_neigbour_params_t *ps_left_mb;\n    mb_neigbour_params_t *ps_top_mb;\n    mb_neigbour_params_t *ps_top_right_mb = NULL;\n    mb_neigbour_params_t *ps_curmb;\n    const UWORD8 u1_topmb = ps_cur_mb_info->u1_topmb;\n    const UWORD8 uc_botMb = 1 - u1_topmb;\n    const UWORD32 u4_mb_x = ps_cur_mb_info->u2_mbx;\n\n    /* Current MbParams location in top row buffer */\n    ps_curmb = ps_dec->ps_cur_mb_row + (u4_mb_x << 1) + uc_botMb;\n    ps_left_mb = ps_curmb - 2;\n    /* point to A if top else A+1 */\n    if(uc_botMb && (ps_left_mb->u1_mb_fld != uc_curMbFldDecFlag))\n    {\n        /* move from A + 1 to A */\n        ps_left_mb--;\n    }\n    ps_cur_mb_info->i1_offset = 0;\n    if((uc_curMbFldDecFlag == 0) && uc_botMb)\n    {\n        mb_neigbour_params_t *ps_topleft_mb;\n        /* CurMbAddr - 1 */\n        ps_top_mb = ps_curmb - 1;\n\n        /* Mark Top right Not available */\n        /* point to A */\n        ps_topleft_mb = ps_curmb - 3;\n\n        if(ps_topleft_mb->u1_mb_fld)\n        {\n            /* point to A + 1 */\n            ps_topleft_mb++;\n        }\n        ps_cur_mb_info->u1_topleft_mb_fld = ps_topleft_mb->u1_mb_fld;\n        ps_cur_mb_info->u1_topleft_mbtype = ps_topleft_mb->u1_mb_type;\n    }\n    else\n    {\n        /* Top = B + 1 */\n        ps_top_mb = ps_dec->ps_top_mb_row + (u4_mb_x << 1) + 1;\n        ps_top_right_mb = ps_top_mb + 2;\n        ps_cur_mb_info->i1_offset = 4;\n        /* TopRight =  C + 1 */\n\n        /* TopLeft = D+1 */\n        ps_cur_mb_info->u1_topleft_mb_fld = ps_dec->u1_topleft_mb_fld_bot;\n        ps_cur_mb_info->u1_topleft_mbtype = ps_dec->u1_topleft_mbtype_bot;\n\n        if(uc_curMbFldDecFlag && u1_topmb)\n        {\n            if(ps_top_mb->u1_mb_fld)\n            {\n                /* MbAddrB */\n                ps_top_mb--;\n                ps_cur_mb_info->i1_offset = 0;\n            }\n            /* If topright is field then point to C */\n            ps_top_right_mb -= ps_top_right_mb->u1_mb_fld ? 1 : 0;\n            if(ps_cur_mb_info->u1_topleft_mb_fld)\n            {\n                /* TopLeft = D */\n                ps_cur_mb_info->u1_topleft_mb_fld = ps_dec->u1_topleft_mb_fld;\n                ps_cur_mb_info->u1_topleft_mbtype = ps_dec->u1_topleft_mbtype;\n            }\n        }\n    }\n    if(u1_topmb)\n    {\n        /* Update the parameters of topleftmb*/\n        ps_dec->u1_topleft_mb_fld = ps_top_mb->u1_mb_fld;\n        ps_dec->u1_topleft_mbtype = ps_top_mb->u1_mb_type;\n        /* Set invscan and dequantMatrixScan*/\n        if(uc_curMbFldDecFlag)\n        {\n            ps_dec->pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan_fld;\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan;\n        }\n        ps_dec->pu2_quant_scale_y =\n                        gau2_ih264_iquant_scale_4x4[ps_dec->u1_qp_y_rem6];\n        ps_dec->pu2_quant_scale_u =\n                        gau2_ih264_iquant_scale_4x4[ps_dec->u1_qp_u_rem6];\n        ps_dec->pu2_quant_scale_v =\n                        gau2_ih264_iquant_scale_4x4[ps_dec->u1_qp_v_rem6];\n\n    }\n    else\n    {\n        /* Update the parameters of topleftmb*/\n        mb_neigbour_params_t *ps_top_mb_temp = ps_dec->ps_top_mb_row\n                        + (u4_mb_x << 1) + 1;\n        ps_dec->u1_topleft_mb_fld_bot = ps_top_mb_temp->u1_mb_fld;\n        ps_dec->u1_topleft_mbtype_bot = ps_top_mb_temp->u1_mb_type;\n    }\n\n    ps_cur_mb_info->ps_left_mb = ps_left_mb;\n    ps_cur_mb_info->ps_top_mb = ps_top_mb;\n    ps_cur_mb_info->ps_top_right_mb = ps_top_right_mb;\n    ps_cur_mb_info->ps_curmb = ps_curmb;\n    ps_curmb->u1_mb_fld = uc_curMbFldDecFlag;\n\n    {\n        /* Form Left NNZ */\n        UWORD8 u1_is_left_mb_fld = ps_left_mb->u1_mb_fld;\n        UWORD8 *pu1_left_mb_pair_nnz_y = (UWORD8 *)&ps_dec->u4_n_leftY[0];\n        UWORD8 *pu1_left_mb_pair_nnz_uv = (UWORD8 *)&ps_dec->u4_n_left_cr[0];\n        UWORD8 *pu1_left_nnz_y = ps_dec->pu1_left_nnz_y;\n        UWORD8 *pu1_left_nnz_uv = ps_dec->pu1_left_nnz_uv;\n\n        if(uc_curMbFldDecFlag == u1_is_left_mb_fld)\n        {\n            *(UWORD32 *)pu1_left_nnz_y = *(UWORD32 *)(pu1_left_mb_pair_nnz_y\n                            + (uc_botMb << 2));\n            *(UWORD32 *)pu1_left_nnz_uv = *(UWORD32 *)(pu1_left_mb_pair_nnz_uv\n                            + (uc_botMb << 2));\n        }\n        else if((uc_curMbFldDecFlag == 0) && u1_topmb && u1_is_left_mb_fld)\n        {\n            /* 0 0 1 1 of u4_n_leftY[0], 0 0 2 2 of u4_n_left_cr[0] */\n            pu1_left_nnz_y[0] = pu1_left_nnz_y[1] = pu1_left_mb_pair_nnz_y[0];\n            pu1_left_nnz_y[2] = pu1_left_nnz_y[3] = pu1_left_mb_pair_nnz_y[1];\n            pu1_left_nnz_uv[0] = pu1_left_nnz_uv[1] =\n                            pu1_left_mb_pair_nnz_uv[0];\n            pu1_left_nnz_uv[2] = pu1_left_nnz_uv[3] =\n                            pu1_left_mb_pair_nnz_uv[2];\n        }\n        else if((uc_curMbFldDecFlag == 0) && uc_botMb && u1_is_left_mb_fld)\n        {\n            /* 2 2 3 3 of u4_n_leftY[0] , 1 1 3 3 of u4_n_left_cr[0] */\n            pu1_left_nnz_y[0] = pu1_left_nnz_y[1] = pu1_left_mb_pair_nnz_y[2];\n            pu1_left_nnz_y[2] = pu1_left_nnz_y[3] = pu1_left_mb_pair_nnz_y[3];\n            pu1_left_nnz_uv[0] = pu1_left_nnz_uv[1] =\n                            pu1_left_mb_pair_nnz_uv[1];\n            pu1_left_nnz_uv[2] = pu1_left_nnz_uv[3] =\n                            pu1_left_mb_pair_nnz_uv[3];\n        }\n        else\n        {\n            /* 0 2 0 2 of u4_n_leftY[0], u4_n_leftY[1] */\n            pu1_left_nnz_y[0] = pu1_left_mb_pair_nnz_y[0];\n            pu1_left_nnz_y[1] = pu1_left_mb_pair_nnz_y[2];\n            pu1_left_nnz_y[2] = pu1_left_mb_pair_nnz_y[4 + 0];\n            pu1_left_nnz_y[3] = pu1_left_mb_pair_nnz_y[4 + 2];\n\n            /* 0 of u4_n_left_cr[0] and 0 u4_n_left_cr[1]\n             2 of u4_n_left_cr[0] and 2 u4_n_left_cr[1] */\n            pu1_left_nnz_uv[0] = pu1_left_mb_pair_nnz_uv[0];\n            pu1_left_nnz_uv[1] = pu1_left_mb_pair_nnz_uv[4 + 0];\n            pu1_left_nnz_uv[2] = pu1_left_mb_pair_nnz_uv[2];\n            pu1_left_nnz_uv[3] = pu1_left_mb_pair_nnz_uv[4 + 2];\n        }\n    }\n}\n\n/*\n **************************************************************************\n * \\if Function name : ih264d_transfer_mb_group_data \\endif\n *\n * \\brief\n *     Transfer the Following things\n *     N-Mb DeblkParams Data    ( To Ext DeblkParams Buffer )\n *     N-Mb Recon Data          ( To Ext Frame Buffer )\n *     N-Mb Intrapredline Data  ( Updated Internally)\n *     N-Mb MV Data             ( To Ext MV Buffer )\n *     N-Mb MVTop/TopRight Data ( To Int MV Top Scratch Buffers)\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\nvoid ih264d_transfer_mb_group_data(dec_struct_t * ps_dec,\n                                   const UWORD8 u1_num_mbs,\n                                   const UWORD8 u1_end_of_row, /* Cur n-Mb End of Row Flag */\n                                   const UWORD8 u1_end_of_row_next /* Next n-Mb End of Row Flag */\n                                   )\n{\n    dec_mb_info_t *ps_cur_mb_info = ps_dec->ps_nmb_info;\n    tfr_ctxt_t *ps_trns_addr = &ps_dec->s_tran_addrecon;\n    UWORD16 u2_mb_y;\n    UWORD32 y_offset;\n    UWORD32 u4_frame_stride;\n    mb_neigbour_params_t *ps_temp;\n    const UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    UNUSED(u1_end_of_row_next);\n\n    ps_trns_addr->pu1_dest_y += ps_trns_addr->u4_inc_y[u1_end_of_row];\n    ps_trns_addr->pu1_dest_u += ps_trns_addr->u4_inc_uv[u1_end_of_row];\n    ps_trns_addr->pu1_dest_v += ps_trns_addr->u4_inc_uv[u1_end_of_row];\n\n    /* Swap top and current pointers */\n    if(u1_end_of_row)\n    {\n\n        if(ps_dec->u1_separate_parse)\n        {\n            u2_mb_y = ps_dec->i2_dec_thread_mb_y;\n        }\n        else\n        {\n            ps_temp = ps_dec->ps_cur_mb_row;\n            ps_dec->ps_cur_mb_row = ps_dec->ps_top_mb_row;\n            ps_dec->ps_top_mb_row = ps_temp;\n\n            u2_mb_y = ps_dec->u2_mby + (1 + u1_mbaff);\n        }\n\n        u4_frame_stride = ps_dec->u2_frm_wd_y\n                        << ps_dec->ps_cur_slice->u1_field_pic_flag;\n        y_offset = (u2_mb_y * u4_frame_stride) << 4;\n        ps_trns_addr->pu1_dest_y = ps_dec->s_cur_pic.pu1_buf1 + y_offset;\n\n        u4_frame_stride = ps_dec->u2_frm_wd_uv\n                        << ps_dec->ps_cur_slice->u1_field_pic_flag;\n        y_offset = (u2_mb_y * u4_frame_stride) << 3;\n        ps_trns_addr->pu1_dest_u = ps_dec->s_cur_pic.pu1_buf2 + y_offset;\n        ps_trns_addr->pu1_dest_v = ps_dec->s_cur_pic.pu1_buf3 + y_offset;\n\n        ps_trns_addr->pu1_mb_y = ps_trns_addr->pu1_dest_y;\n        ps_trns_addr->pu1_mb_u = ps_trns_addr->pu1_dest_u;\n        ps_trns_addr->pu1_mb_v = ps_trns_addr->pu1_dest_v;\n    }\n\n    /*\n     * The Slice boundary is also a valid condition to transfer. So recalculate\n     * the Left increment, in case the number of MBs is lesser than the\n     * N MB value. u1_num_mbs will be equal to N of N MB if the entire N Mb is\n     * decoded.\n     */\n    ps_dec->s_tran_addrecon.u2_mv_left_inc = ((u1_num_mbs >> u1_mbaff) - 1)\n                    << (4 + u1_mbaff);\n    ps_dec->s_tran_addrecon.u2_mv_top_left_inc = (u1_num_mbs << 2) - 1\n                    - (u1_mbaff << 2);\n\n    if(ps_dec->u1_separate_parse == 0)\n    {\n        /* reassign left MV and cur MV pointers */\n        ps_dec->ps_mv_left = ps_dec->ps_mv_cur\n                        + ps_dec->s_tran_addrecon.u2_mv_left_inc;\n\n        ps_dec->ps_mv_cur += (u1_num_mbs << 4);\n    }\n\n    /* Increment deblock parameters pointer in external memory */\n\n    if(ps_dec->u1_separate_parse == 0)\n    {\n        ps_dec->ps_deblk_mbn += u1_num_mbs;\n    }\n\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_mb_utils.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_MB_UTILS_H_\n#define _IH264D_MB_UTILS_H_\n/*!\n **************************************************************************\n * \\file ih264d_mb_utils.h\n *\n * \\brief\n *    Contains declarations of the utility functions needed to decode MB\n *\n * \\date\n *    18/12/2002\n *\n * \\author  AI\n **************************************************************************\n */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\n\n/*--------------------------------------------------------------------*/\n/* Macros to get raster scan position of a block[8x8] / sub block[4x4]*/\n/*--------------------------------------------------------------------*/\n\n#define GET_BLK_RASTER_POS_X(x)     ((x & 0x01) << 1)\n#define GET_BLK_RASTER_POS_Y(y)     ((y >> 1)   << 1)\n#define GET_SUB_BLK_RASTER_POS_X(x) ((x & 0x01))\n#define GET_SUB_BLK_RASTER_POS_Y(y) ((y >> 1))\n\n/*--------------------------------------------------------------------*/\n/* Masks used in decoding of Macroblock                               */\n/*--------------------------------------------------------------------*/\n\n#define LEFT_MB_AVAILABLE_MASK      0x01\n#define TOP_LEFT_MB_AVAILABLE_MASK  0x02\n#define TOP_MB_AVAILABLE_MASK       0x04\n#define TOP_RIGHT_MB_AVAILABLE_MASK 0x08\n\n#define TOP_RT_SUBBLOCK_MASK_MOD               0xFFF7\n\n#define TOP_RIGHT_DEFAULT_AVAILABLE            0x5750\n#define TOP_RIGHT_TOPR_AVAILABLE               0x0008\n#define TOP_RIGHT_TOP_AVAILABLE                0x0007\n\n#define TOP_LEFT_DEFAULT_AVAILABLE            0xEEE0\n#define TOP_LEFT_TOPL_AVAILABLE               0x0001\n#define TOP_LEFT_TOP_AVAILABLE                0x000E\n#define TOP_LEFT_LEFT_AVAILABLE               0x1110\n\n#define CHECK_MB_MAP(u4_mb_num, mb_map, u4_cond)                                                    \\\n{                                                                                                   \\\n        UWORD32 u4_bit_number;                                                                      \\\n        volatile UWORD8 *pu1_mb_flag;                                                                       \\\n                                                                                                    \\\n        u4_bit_number = u4_mb_num & 0x07;                                                           \\\n        pu1_mb_flag    = (UWORD8 *)mb_map + (u4_mb_num >> 3);                                                       \\\n                                                                                                    \\\n        u4_cond = CHECKBIT((*pu1_mb_flag), u4_bit_number);                                              \\\n}\n\n#define CHECK_MB_MAP_BYTE(u4_mb_num, mb_map, u4_cond)                                               \\\n{                                                                                                   \\\n        volatile UWORD8 *pu1_mb_flag;                                                               \\\n                                                                                                    \\\n        pu1_mb_flag    = (UWORD8 *)mb_map + (u4_mb_num );                                           \\\n                                                                                                    \\\n        u4_cond = (*pu1_mb_flag);                                                                   \\\n}\n\n#define UPDATE_MB_MAP(u2_frm_wd_in_mbs, u2_mbx, u2_mby, mb_map, mb_count)                     \\\n{                                                                                                   \\\n        UWORD32 u4_bit_number;                                                                      \\\n        UWORD32 u4_mb_number;                                                                       \\\n                                                                                                    \\\n        u4_mb_number    = u2_frm_wd_in_mbs * (u2_mby >> u1_mbaff) + u2_mbx;                   \\\n                                                                                                    \\\n        u4_bit_number = u4_mb_number & 0x07;                                                        \\\n        /*                                                                                          \\\n         * In case of MbAff, update the mb_map only if the entire MB is done. We can check that     \\\n         * by checking if Y is odd, implying that this is the second row in the MbAff MB            \\\n         */                                                                                         \\\n        SET_BIT(mb_map[u4_mb_number >> 3], u4_bit_number);                                           \\\n                                                                                                    \\\n        if (1 == u1_mbaff)                                                                          \\\n        {                                                                                           \\\n            /*                                                                                      \\\n             * If MBAFF u4_flag is set, set this MB and the MB just below this.                        \\\n             * So, add frame width to the MB number and set that bit.                               \\\n             */                                                                                     \\\n            /*                                                                                      \\\n            u4_mb_number    += u2_frm_wd_in_mbs;                                                  \\\n                                                                                                    \\\n            u4_bit_number = u4_mb_number & 0x07;                                                    \\\n                                                                                                    \\\n            SET_BIT(mb_map[u4_mb_number >> 3], u4_bit_number);                                       \\\n            */                                                                                      \\\n        }                                                                                           \\\n                                                                                                    \\\n        /*H264_DEC_DEBUG_PRINT(\"SETBIT: %d\\n\", u4_mb_number);*/                                     \\\n        mb_count++;                                                                                 \\\n}\n\n#define UPDATE_MB_MAP_MBNUM(mb_map, u4_mb_number)                                                   \\\n{                                                                                                   \\\n        UWORD32 u4_bit_number;                                                                      \\\n        volatile UWORD8 *pu1_mb_flag;                                                                       \\\n                                                                                                    \\\n        u4_bit_number = u4_mb_number & 0x07;                                                        \\\n        pu1_mb_flag    = (UWORD8 *)mb_map + (u4_mb_number >> 3);                                                        \\\n        /*                                                                                          \\\n         * In case of MbAff, update the mb_map only if the entire MB is done. We can check that     \\\n         * by checking if Y is odd, implying that this is the second row in the MbAff MB            \\\n         */                                                                                         \\\n        SET_BIT((*pu1_mb_flag), u4_bit_number);                                                          \\\n}\n\n#define UPDATE_MB_MAP_MBNUM_BYTE(mb_map, u4_mb_number)                                                  \\\n{                                                                                                   \\\n        volatile UWORD8 *pu1_mb_flag;                                                                       \\\n                                                                                                    \\\n        pu1_mb_flag    = (UWORD8 *)mb_map + (u4_mb_number);                                                     \\\n        /*                                                                                          \\\n         * In case of MbAff, update the mb_map only if the entire MB is done. We can check that     \\\n         * by checking if Y is odd, implying that this is the second row in the MbAff MB            \\\n         */                                                                                         \\\n        (*pu1_mb_flag) = 1;                                                             \\\n}\n\n#define UPDATE_SLICE_NUM_MAP(slice_map, u4_mb_number,u2_slice_num)                                                  \\\n{                                                                                                   \\\n        volatile UWORD16 *pu2_slice_map;                                                               \\\n                                                                                                    \\\n        pu2_slice_map    = (UWORD16 *)slice_map + (u4_mb_number);                                         \\\n        (*pu2_slice_map) = u2_slice_num;                                                              \\\n}\n\n#define GET_SLICE_NUM_MAP(slice_map, mb_number,u2_slice_num)                                                  \\\n{                                                                                                   \\\n        volatile UWORD16 *pu2_slice_map;                                                               \\\n                                                                                                    \\\n        pu2_slice_map    = (UWORD16 *)slice_map + (mb_number);                                         \\\n        u2_slice_num = (*pu2_slice_map) ;                                                               \\\n}\n\n\n#define GET_XPOS_PRED(u1_out,pkd_info)                        \\\n{                                                               \\\n    WORD32 bit_field;                                           \\\n    bit_field = pkd_info & 0x3;                                 \\\n    u1_out = bit_field;                                       \\\n}\n\n\n#define GET_YPOS_PRED(u1_out,pkd_info)                        \\\n{                                                               \\\n    WORD32 bit_field;                                           \\\n    bit_field = pkd_info >> 2;                                  \\\n    u1_out = bit_field & 0x3;                                  \\\n}\n\n\n\n#define GET_WIDTH_PRED(u1_out,pkd_info)                        \\\n{                                                               \\\n    WORD32 bit_field;                                           \\\n    bit_field = pkd_info >> 4;                                  \\\n    bit_field = (bit_field & 0x3) << 1 ;                        \\\n    u1_out = (bit_field == 0)?1:bit_field;                       \\\n    }\n\n#define GET_HEIGHT_PRED(u1_out,pkd_info)                        \\\n{                                                               \\\n    WORD32 bit_field;                                           \\\n    bit_field = pkd_info >> 6;                                  \\\n    bit_field = (bit_field & 0x3) << 1 ;                        \\\n    u1_out = (bit_field == 0)?1:bit_field;                      \\\n}\n\n/*!\n **************************************************************************\n *   \\brief   Masks for elements present in the first column but not on the\n *   first row.\n **************************************************************************\n */\n#define FIRST_COL_NOT_FIRST_ROW             0xFAFB\n#define FIRST_ROW_MASK                      0xFFCC\n/*!\n **************************************************************************\n *   \\brief   Mask for elements presen in the first row but not in the\n *   last column.\n **************************************************************************\n */\n#define FIRST_ROW_NOT_LAST_COL             0xFFEC\n/*!\n **************************************************************************\n *   \\brief   Mask for elements presen in the first row but not in the\n *   first column.\n **************************************************************************\n */\n#define FIRST_ROW_NOT_FIRST_COL            0xFFCD\n/*!\n **************************************************************************\n *   \\brief   Masks for the top right subMB of a 4x4 block\n **************************************************************************\n */\n#define TOP_RT_SUBBLOCK_MASK                0xFFDF\n/*!\n **************************************************************************\n *   \\brief   Masks for the top left subMB of a 4x4 block\n **************************************************************************\n */\n#define TOP_LT_SUBBLOCK_MASK                0xFFFE\n/*!\n **************************************************************************\n *   \\brief   Indicates if a subMB has a top right subMB available\n **************************************************************************\n */\n#define TOP_RT_SUBBLOCK_MB_MASK  0x5F4C\n\n#define FIRST_COL_MASK           0xFAFA\n\n/*--------------------------------------------------------------------*/\n/* Macros to calculate the current position of a MB wrt picture       */\n/*--------------------------------------------------------------------*/\n#define MB_LUMA_PIC_OFFSET(mb_x,mb_y,frmWidthY)   (((mb_y)*(frmWidthY) + (mb_x))<<4)\n#define MB_CHROMA_PIC_OFFSET(mb_x,mb_y,frmWidthUV) (((mb_y)*(frmWidthUV) + (mb_x))<<3)\n\n/*--------------------------------------------------------------------*/\n/* Macros to calculate the current position of a MB wrt N[ Num coeff] Array */\n/*--------------------------------------------------------------------*/\n#define MB_PARAM_OFFSET(mb_x,mb_y,frmWidthInMbs,u1_mbaff,u1_topmb)  \\\n        ((mb_x << u1_mbaff) + (1 - u1_topmb) + (mb_y * frmWidthInMbs))\n\nUWORD32 ih264d_get_mb_info_cavlc_mbaff(dec_struct_t * ps_dec,\n                                       const UWORD16 ui16_curMbAddress,\n                                       dec_mb_info_t * ps_cur_mb_info,\n                                       UWORD32 u4_mbskip_run);\nUWORD32 ih264d_get_mb_info_cavlc_nonmbaff(dec_struct_t * ps_dec,\n                                          const UWORD16 ui16_curMbAddress,\n                                          dec_mb_info_t * ps_cur_mb_info,\n                                          UWORD32 u4_mbskip_run);\n\nUWORD32 ih264d_get_mb_info_cabac_mbaff(dec_struct_t * ps_dec,\n                                       const UWORD16 ui16_curMbAddress,\n                                       dec_mb_info_t * ps_cur_mb_info,\n                                       UWORD32 u4_mbskip_run);\n\nUWORD32 ih264d_get_mb_info_cabac_nonmbaff(dec_struct_t * ps_dec,\n                                          const UWORD16 ui16_curMbAddress,\n                                          dec_mb_info_t * ps_cur_mb_info,\n                                          UWORD32 u4_mbskip_run);\n\nUWORD8 get_cabac_context_non_mbaff(dec_struct_t * ps_dec, UWORD16 u2_mbskip);\n\nUWORD32 ih264d_get_cabac_context_mbaff(dec_struct_t * ps_dec,\n                                       dec_mb_info_t * ps_cur_mb_info,\n                                       UWORD32 u4_mbskip);\n\nWORD32 PutMbToFrame(dec_struct_t * ps_dec);\nvoid ih264d_get_mbaff_neighbours(dec_struct_t * ps_dec,\n                                 dec_mb_info_t * ps_cur_mb_info,\n                                 UWORD8 uc_curMbFldDecFlag);\n\nvoid ih264d_update_mbaff_left_nnz(dec_struct_t * ps_dec,\n                                  dec_mb_info_t * ps_cur_mb_info);\nvoid ih264d_transfer_mb_group_data(dec_struct_t * ps_dec,\n                                   const UWORD8 u1_num_mbs,\n                                   const UWORD8 u1_end_of_row, /* Cur n-Mb End of Row Flag */\n                                   const UWORD8 u1_end_of_row_next /* Next n-Mb End of Row Flag */\n                                   );\n\n//void FillRandomData(UWORD8 *pu1_buf, WORD32 u4_bufSize);\n\n#endif /* _MB_UTILS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_mem_request.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n#ifndef _IH264D_MEM_REQUEST_H_\n#define _IH264D_MEM_REQUEST_H_\n/*!\n ***************************************************************************\n * \\file ih264d_mem_request.h\n *\n * \\brief\n *    This file contains declarations and data structures of the API's which\n *    required to interact with Picture Buffer.\n *\n *\n * \\date\n *    11/12/2002\n *\n * \\author  NS\n ***************************************************************************/\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_structs.h\"\n\n#define MAX_MEM_BLOCKS      64 + 8\n\nstruct MemBlock\n{\n    void ** v_memLocation; /** memory location where address of allocated memory should be stored*/\n    UWORD32 u4_mem_size; /** Size of the memory block */\n};\n\nstruct MemReq\n{\n    UWORD32 u4_num_memBlocks; /** Number of memory blocks */\n    struct MemBlock s_memBlock[MAX_MEM_BLOCKS]; /** Pointer to the first memory block */\n};\n\nstruct PicMemBlock\n{\n    void * buf1; /** memory location for buf1 */\n    void * buf2; /** memory location for buf2 */\n    void * buf3; /** memory location for buf3 */\n};\n\nstruct PicMemReq\n{\n    WORD32 i4_num_pic_memBlocks; /** Number of memory blocks */\n    UWORD32 u4_size1; /** Size of the buf1 in PicMemBlock */\n    UWORD32 u4_size2; /** Size of the buf2 in PicMemBlock */\n    UWORD32 u4_size3; /** Size of the buf3 in PicMemBlock */\n    struct PicMemBlock s_PicMemBlock[MAX_DISP_BUFS_NEW];\n};\n\nWORD32 ih264d_create_pic_buffers(UWORD8 u1_num_of_buf,\n                               dec_struct_t *ps_dec);\n\nWORD32 ih264d_create_mv_bank(void * pv_codec_handle,\n                             UWORD32 u4_wd,\n                             UWORD32 u4_ht);\nWORD16 ih264d_allocate_dynamic_bufs(dec_struct_t * ps_dec);\n\n\n#endif  /* _IH264D_MEM_REQUEST_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_mvpred.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n * \\file ih264d_mvpred.c\n *\n * \\brief\n *    This file contains function specific to decoding Motion vector.\n *\n * Detailed_description\n *\n * \\date\n *    10-12-2002\n *\n * \\author  Arvind Raman\n **************************************************************************\n */\n#include <string.h>\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_process_bslice.h\"\n#include \"ih264d_mvpred.h\"\n#include \"ih264d_inter_pred.h\"\n#include \"ih264d_tables.h\"\n\n/*!\n **************************************************************************\n * \\if ih264d_get_motion_vector_predictor name : Name \\endif\n *\n * \\brief\n *    The routine calculates the motion vector predictor for a given block,\n *    given the candidate MV predictors.\n *\n * \\param ps_mv_pred: Candidate predictors for the current block\n * \\param ps_currMv: Pointer to the left top edge of the current block in\n *     the MV bank\n *\n * \\return\n *    _mvPred: The x & y components of the MV predictor.\n *\n * \\note\n *    The code implements the logic as described in sec 8.4.1.2.1. Given\n *    the candidate predictors and the pointer to the top left edge of the\n *    block in the MV bank.\n *\n **************************************************************************\n */\n\nvoid ih264d_get_motion_vector_predictor(mv_pred_t * ps_result,\n                                        mv_pred_t **ps_mv_pred,\n                                        UWORD8 u1_ref_idx,\n                                        UWORD8 u1_B,\n                                        const UWORD8 *pu1_mv_pred_condition)\n{\n    WORD8 c_temp;\n    UWORD8 uc_B2 = (u1_B << 1);\n\n    /* If only one of the candidate blocks has a reference frame equal to\n     the current block then use the same block as the final predictor */\n    c_temp =\n                    (ps_mv_pred[LEFT]->i1_ref_frame[u1_B] == u1_ref_idx)\n                                    | ((ps_mv_pred[TOP]->i1_ref_frame[u1_B]\n                                                    == u1_ref_idx) << 1)\n                                    | ((ps_mv_pred[TOP_R]->i1_ref_frame[u1_B]\n                                                    == u1_ref_idx) << 2);\n    c_temp = pu1_mv_pred_condition[c_temp];\n\n    if(c_temp != -1)\n    {\n        /* Case when only when one of the cadidate block has the same\n         reference frame as the current block */\n        ps_result->i2_mv[uc_B2 + 0] = ps_mv_pred[c_temp]->i2_mv[uc_B2 + 0];\n        ps_result->i2_mv[uc_B2 + 1] = ps_mv_pred[c_temp]->i2_mv[uc_B2 + 1];\n    }\n    else\n    {\n        WORD32 D0, D1;\n        D0 = MIN(ps_mv_pred[0]->i2_mv[uc_B2 + 0],\n                 ps_mv_pred[1]->i2_mv[uc_B2 + 0]);\n        D1 = MAX(ps_mv_pred[0]->i2_mv[uc_B2 + 0],\n                 ps_mv_pred[1]->i2_mv[uc_B2 + 0]);\n        D1 = MIN(D1, ps_mv_pred[2]->i2_mv[uc_B2 + 0]);\n        ps_result->i2_mv[uc_B2 + 0] = (WORD16)(MAX(D0, D1));\n\n        D0 = MIN(ps_mv_pred[0]->i2_mv[uc_B2 + 1],\n                 ps_mv_pred[1]->i2_mv[uc_B2 + 1]);\n        D1 = MAX(ps_mv_pred[0]->i2_mv[uc_B2 + 1],\n                 ps_mv_pred[1]->i2_mv[uc_B2 + 1]);\n        D1 = MIN(D1, ps_mv_pred[2]->i2_mv[uc_B2 + 1]);\n        ps_result->i2_mv[uc_B2 + 1] = (WORD16)(MAX(D0, D1));\n\n    }\n}\n\n/*!\n **************************************************************************\n * \\if ih264d_mbaff_mv_pred name : Name \\endif\n *\n * \\brief\n *    The routine calculates the motion vector predictor for a given block,\n *    given the candidate MV predictors.\n *\n * \\param ps_mv_pred: Candidate predictors for the current block\n * \\param ps_currMv: Pointer to the left top edge of the current block in\n *     the MV bank\n *\n * \\return\n *    _mvPred: The x & y components of the MV predictor.\n *\n * \\note\n *    The code implements the logic as described in sec 8.4.1.2.1. Given\n *    the candidate predictors and the pointer to the top left edge of the\n *    block in the MV bank.\n *\n **************************************************************************\n */\n\nvoid ih264d_mbaff_mv_pred(mv_pred_t **ps_mv_pred,\n                          UWORD8 u1_sub_mb_num,\n                          mv_pred_t *ps_mv_nmb,\n                          mv_pred_t *ps_mv_ntop,\n                          dec_struct_t *ps_dec,\n                          UWORD8 uc_mb_part_width,\n                          dec_mb_info_t *ps_cur_mb_info,\n                          UWORD8* pu0_scale)\n{\n    UWORD16 u2_a_in = 0, u2_b_in = 0, u2_c_in = 0, u2_d_in = 0;\n    mv_pred_t *ps_mvpred_l, *ps_mvpred_tmp;\n    UWORD8 u1_sub_mb_x = (u1_sub_mb_num & 3), uc_sub_mb_y = (u1_sub_mb_num >> 2);\n    UWORD8 u1_is_cur_mb_fld, u1_is_left_mb_fld, u1_is_top_mb_fld;\n    UWORD8 u1_is_cur_mb_top;\n\n    u1_is_cur_mb_fld = ps_cur_mb_info->u1_mb_field_decodingflag;\n    u1_is_cur_mb_top = ps_cur_mb_info->u1_topmb;\n\n    u1_is_left_mb_fld = ps_cur_mb_info->ps_left_mb->u1_mb_fld;\n    u1_is_top_mb_fld = ps_cur_mb_info->ps_top_mb->u1_mb_fld;\n\n    /* Checking in the subMB exists, calculating their motion vectors to be\n     used as predictors and the reference frames of those subMBs */\n    ps_mv_pred[LEFT] = &ps_dec->s_default_mv_pred;\n    ps_mv_pred[TOP] = &(ps_dec->s_default_mv_pred);\n    ps_mv_pred[TOP_R] = &(ps_dec->s_default_mv_pred);\n\n    /* Check if the left subMb is available */\n    if(u1_sub_mb_x)\n    {\n        u2_a_in = 1;\n        ps_mv_pred[LEFT] = (ps_mv_nmb - 1);\n    }\n    else\n    {\n        UWORD8 uc_temp;\n        u2_a_in = (ps_cur_mb_info->u1_mb_ngbr_availablity & LEFT_MB_AVAILABLE_MASK);\n        if(u2_a_in)\n        {\n            ps_mvpred_l = (ps_dec->u4_num_pmbair) ?\n                            ps_mv_nmb :\n                            (ps_dec->ps_mv_left + (uc_sub_mb_y << 2) + 48\n                                            - (u1_is_cur_mb_top << 4));\n            uc_temp = 29;\n            if(u1_is_cur_mb_fld ^ u1_is_left_mb_fld)\n            {\n                if(u1_is_left_mb_fld)\n                {\n                    uc_temp +=\n                                    (((uc_sub_mb_y & 1) << 2)\n                                                    + ((uc_sub_mb_y & 2) << 1));\n                    uc_temp += ((u1_is_cur_mb_top) ? 0 : 8);\n                }\n                else\n                {\n                    uc_temp = uc_temp - (uc_sub_mb_y << 2);\n                    uc_temp += ((u1_is_cur_mb_top) ? 0 : 16);\n                }\n            }\n            ps_mv_pred[LEFT] = (ps_mvpred_l - uc_temp);\n            pu0_scale[LEFT] = u1_is_cur_mb_fld - u1_is_left_mb_fld;\n        }\n    }\n\n    /* Check if the top subMB is available */\n    if((uc_sub_mb_y > 0) || ((u1_is_cur_mb_top | u1_is_cur_mb_fld) == 0))\n    {\n        u2_b_in = 1;\n        ps_mv_pred[TOP] = ps_mv_nmb - 4;\n    }\n    else\n    {\n        u2_b_in = (ps_cur_mb_info->u1_mb_ngbr_availablity & TOP_MB_AVAILABLE_MASK);\n        if(u2_b_in)\n        {\n            /* CHANGED CODE */\n\n            if(u1_is_top_mb_fld && u1_is_cur_mb_fld)\n                ps_mvpred_tmp = ps_mv_ntop;\n            else\n            {\n                ps_mvpred_tmp = ps_mv_ntop;\n                if(u1_is_cur_mb_top)\n                    ps_mvpred_tmp += 16;\n            }\n\n            ps_mv_pred[TOP] = ps_mvpred_tmp;\n            pu0_scale[TOP] = u1_is_cur_mb_fld - u1_is_top_mb_fld;\n        }\n    }\n\n    /* Check if the top right subMb is available. The top right subMb is\n     defined as the top right subMb at the top right corner of the MB\n     partition. The top right subMb index starting from the top left\n     corner of the MB partition is given by\n     TopRightSubMbIndx = TopLeftSubMbIndx + (WidthOfMbPartition - 6) / 2\n     */\n    u2_c_in = CHECKBIT(ps_cur_mb_info->u2_top_right_avail_mask,\n                        (u1_sub_mb_num + uc_mb_part_width - 1));\n    if(u2_c_in)\n    {\n        ps_mv_pred[TOP_R] = ps_mv_pred[TOP] + uc_mb_part_width;\n        pu0_scale[TOP_R] = pu0_scale[TOP];\n        if((uc_sub_mb_y == 0) && ((u1_sub_mb_x + uc_mb_part_width) > 3))\n        {\n            UWORD8 uc_isTopRtMbFld;\n            uc_isTopRtMbFld = ps_cur_mb_info->ps_top_right_mb->u1_mb_fld;\n            /* CHANGED CODE */\n            ps_mvpred_tmp = ps_mv_ntop + uc_mb_part_width + 12;\n            ps_mvpred_tmp += (u1_is_cur_mb_top) ? 16 : 0;\n            ps_mvpred_tmp += (u1_is_cur_mb_fld && u1_is_cur_mb_top && uc_isTopRtMbFld) ?\n                            0 : 16;\n            ps_mv_pred[TOP_R] = ps_mvpred_tmp;\n            pu0_scale[TOP_R] = u1_is_cur_mb_fld - uc_isTopRtMbFld;\n        }\n    }\n    else\n    {\n        u2_d_in = CHECKBIT(ps_cur_mb_info->u2_top_left_avail_mask, u1_sub_mb_num);\n\n        /* Check if the the top left subMB is available */\n        if(u2_d_in)\n        {\n            UWORD8 uc_isTopLtMbFld;\n\n            ps_mv_pred[TOP_R] = ps_mv_pred[TOP] - 1;\n            pu0_scale[TOP_R] = pu0_scale[TOP];\n\n            if(u1_sub_mb_x == 0)\n            {\n                if((uc_sub_mb_y > 0) || ((u1_is_cur_mb_top | u1_is_cur_mb_fld) == 0))\n                {\n                    uc_isTopLtMbFld = u1_is_left_mb_fld;\n                    ps_mvpred_tmp = ps_mv_pred[LEFT] - 4;\n\n                    if((u1_is_cur_mb_fld == 0) && uc_isTopLtMbFld)\n                    {\n                        ps_mvpred_tmp = ps_mv_pred[LEFT] + 16;\n                        ps_mvpred_tmp -= (uc_sub_mb_y & 1) ? 0 : 4;\n                    }\n                }\n                else\n                {\n                    UWORD32 u4_cond = ps_dec->u4_num_pmbair;\n                    uc_isTopLtMbFld = ps_cur_mb_info->u1_topleft_mb_fld;\n\n                    /* CHANGED CODE */\n                    ps_mvpred_tmp = ps_mv_ntop - 29;\n                    ps_mvpred_tmp += (u1_is_cur_mb_top) ? 16 : 0;\n                    if(u1_is_cur_mb_fld && u1_is_cur_mb_top)\n                        ps_mvpred_tmp -= (uc_isTopLtMbFld) ? 16 : 0;\n                }\n                ps_mv_pred[TOP_R] = ps_mvpred_tmp;\n                pu0_scale[TOP_R] = u1_is_cur_mb_fld - uc_isTopLtMbFld;\n            }\n        }\n        else if(u2_b_in == 0)\n        {\n            /* If all the subMBs B, C, D are all out of the frame then their MV\n             and their reference picture is equal to that of A */\n            ps_mv_pred[TOP] = ps_mv_pred[LEFT];\n            ps_mv_pred[TOP_R] = ps_mv_pred[LEFT];\n            pu0_scale[TOP] = pu0_scale[LEFT];\n            pu0_scale[TOP_R] = pu0_scale[LEFT];\n        }\n    }\n}\n\n/*!\n **************************************************************************\n * \\if ih264d_non_mbaff_mv_pred name : Name \\endif\n *\n * \\brief\n *    The routine calculates the motion vector predictor for a given block,\n *    given the candidate MV predictors.\n *\n * \\param ps_mv_pred: Candidate predictors for the current block\n * \\param ps_currMv: Pointer to the left top edge of the current block in\n *     the MV bank\n *\n * \\return\n *    _mvPred: The x & y components of the MV predictor.\n *\n * \\note\n *    The code implements the logic as described in sec 8.4.1.2.1. Given\n *    the candidate predictors and the pointer to the top left edge of the\n *    block in the MV bank.\n *\n **************************************************************************\n */\n#if(!MVPRED_NONMBAFF)\nvoid ih264d_non_mbaff_mv_pred(mv_pred_t **ps_mv_pred,\n                              UWORD8 u1_sub_mb_num,\n                              mv_pred_t *ps_mv_nmb,\n                              mv_pred_t *ps_mv_ntop,\n                              dec_struct_t *ps_dec,\n                              UWORD8 uc_mb_part_width,\n                              dec_mb_info_t *ps_cur_mb_info)\n{\n    UWORD16 u2_b_in = 0, u2_c_in = 0, u2_d_in = 0;\n    UWORD8 u1_sub_mb_x = (u1_sub_mb_num & 3), uc_sub_mb_y = (u1_sub_mb_num >> 2);\n\n    /* Checking in the subMB exists, calculating their motion vectors to be\n     used as predictors and the reference frames of those subMBs */\n\n    ps_mv_pred[LEFT] = &ps_dec->s_default_mv_pred;\n    ps_mv_pred[TOP] = &(ps_dec->s_default_mv_pred);\n    ps_mv_pred[TOP_R] = &(ps_dec->s_default_mv_pred);\n    /* Check if the left subMb is available */\n\n    if(u1_sub_mb_x)\n    {\n        ps_mv_pred[LEFT] = (ps_mv_nmb - 1);\n    }\n    else\n    {\n        if(ps_cur_mb_info->u1_mb_ngbr_availablity & LEFT_MB_AVAILABLE_MASK)\n        {\n            ps_mv_pred[LEFT] = (ps_mv_nmb - 13);\n        }\n    }\n\n    /* Check if the top subMB is available */\n    if(uc_sub_mb_y)\n    {\n        u2_b_in = 1;\n        ps_mv_ntop = ps_mv_nmb - 4;\n        ps_mv_pred[TOP] = ps_mv_ntop;\n\n    }\n    else\n    {\n        u2_b_in = (ps_cur_mb_info->u1_mb_ngbr_availablity & TOP_MB_AVAILABLE_MASK);\n        if(u2_b_in)\n        {\n            ps_mv_pred[TOP] = ps_mv_ntop;\n        }\n    }\n\n    /* Check if the top right subMb is available. The top right subMb is\n     defined as the top right subMb at the top right corner of the MB\n     partition. The top right subMb index starting from the top left\n     corner of the MB partition is given by\n     TopRightSubMbIndx = TopLeftSubMbIndx + (WidthOfMbPartition - 6) / 2\n     */\n    u2_c_in = CHECKBIT(ps_cur_mb_info->u2_top_right_avail_mask,\n                        (u1_sub_mb_num + uc_mb_part_width - 1));\n    if(u2_c_in)\n    {\n        ps_mv_pred[TOP_R] = (ps_mv_ntop + uc_mb_part_width);\n\n        if(uc_sub_mb_y == 0)\n        {\n            /* CHANGED CODE */\n            if((u1_sub_mb_x + uc_mb_part_width) > 3)\n                ps_mv_pred[TOP_R] += 12;\n        }\n    }\n    else\n    {\n        u2_d_in = CHECKBIT(ps_cur_mb_info->u2_top_left_avail_mask, u1_sub_mb_num);\n        /* Check if the the top left subMB is available */\n        if(u2_d_in)\n        {\n            /* CHANGED CODE */\n            ps_mv_pred[TOP_R] = (ps_mv_ntop - 1);\n            if(u1_sub_mb_x == 0)\n            {\n                if(uc_sub_mb_y)\n                {\n                    ps_mv_pred[TOP_R] = (ps_mv_nmb - 17);\n                }\n                else\n                {\n                    /* CHANGED CODE */\n                    ps_mv_pred[TOP_R] -= 12;\n                }\n            }\n        }\n        else if(u2_b_in == 0)\n        {\n            /* If all the subMBs B, C, D are all out of the frame then their MV\n             and their reference picture is equal to that of A */\n            ps_mv_pred[TOP] = ps_mv_pred[LEFT];\n            ps_mv_pred[TOP_R] = ps_mv_pred[LEFT];\n        }\n    }\n}\n#endif\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_mvpred_nonmbaffB                                         */\n/*                                                                           */\n/*  Description   : This function calculates the motion vector predictor,    */\n/*                  for B-Slices                                             */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : None                                                     */\n/*  Processing    : The neighbours A(Left),B(Top),C(TopRight) are calculated */\n/*                  and based on the type of Mb the prediction is            */\n/*                  appropriately done                                       */\n/*  Outputs       : populates ps_mv_final_pred structure                       */\n/*  Returns       : u1_direct_zero_pred_flag which is used only in              */\n/*                    decodeSpatialdirect()                                  */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         03 05 2005   TA              First Draft                          */\n/*                                                                           */\n/*****************************************************************************/\n#if(!MVPRED_NONMBAFF)\nUWORD8 ih264d_mvpred_nonmbaffB(dec_struct_t *ps_dec,\n                               dec_mb_info_t *ps_cur_mb_info,\n                               mv_pred_t *ps_mv_nmb,\n                               mv_pred_t *ps_mv_ntop,\n                               mv_pred_t *ps_mv_final_pred,\n                               UWORD8 u1_sub_mb_num,\n                               UWORD8 uc_mb_part_width,\n                               UWORD8 u1_lx_start,\n                               UWORD8 u1_lxend,\n                               UWORD8 u1_mb_mc_mode)\n{\n    UWORD8 u1_a_in, u1_b_in, uc_temp1, uc_temp2, uc_temp3;\n    mv_pred_t *ps_mv_pred[3];\n    UWORD8 uc_B2, uc_lx, u1_ref_idx;\n    UWORD8 u1_direct_zero_pred_flag = 0;\n\n    ih264d_non_mbaff_mv_pred(ps_mv_pred, u1_sub_mb_num, ps_mv_nmb, ps_mv_ntop,\n                             ps_dec, uc_mb_part_width, ps_cur_mb_info);\n\n    for(uc_lx = u1_lx_start; uc_lx < u1_lxend; uc_lx++)\n    {\n        u1_ref_idx = ps_mv_final_pred->i1_ref_frame[uc_lx];\n        uc_B2 = (uc_lx << 1);\n        switch(u1_mb_mc_mode)\n        {\n            case PRED_16x8:\n                /* Directional prediction for a 16x8 MB partition */\n                if(u1_sub_mb_num == 0)\n                {\n                    /* Calculating the MV pred for the top 16x8 block */\n                    if(ps_mv_pred[TOP]->i1_ref_frame[uc_lx] == u1_ref_idx)\n                    {\n                        /* If the reference frame used by the top subMB is same as the\n                         reference frame used by the current block then MV predictor to\n                         be used for the current block is same as the MV of the top\n                         subMB */\n                        ps_mv_final_pred->i2_mv[uc_B2 + 0] =\n                                        ps_mv_pred[TOP]->i2_mv[uc_B2 + 0];\n                        ps_mv_final_pred->i2_mv[uc_B2 + 1] =\n                                        ps_mv_pred[TOP]->i2_mv[uc_B2 + 1];\n                    }\n                    else\n                    {\n                        /* The MV predictor is calculated according to the process\n                         defined in 8.4.1.2.1 */\n                        ih264d_get_motion_vector_predictor(\n                                        ps_mv_final_pred,\n                                        ps_mv_pred,\n                                        u1_ref_idx,\n                                        uc_lx,\n                                        (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                    }\n                }\n                else\n                {\n                    if(ps_mv_pred[LEFT]->i1_ref_frame[uc_lx] == u1_ref_idx)\n                    {\n                        /* If the reference frame used by the left subMB is same as the\n                         reference frame used by the current block then MV predictor to\n                         be used for the current block is same as the MV of the left\n                         subMB */\n                        ps_mv_final_pred->i2_mv[uc_B2 + 0] =\n                                        ps_mv_pred[LEFT]->i2_mv[uc_B2 + 0];\n                        ps_mv_final_pred->i2_mv[uc_B2 + 1] =\n                                        ps_mv_pred[LEFT]->i2_mv[uc_B2 + 1];\n                    }\n                    else\n                    {\n                        /* The MV predictor is calculated according to the process\n                         defined in 8.4.1.2.1 */\n                        ih264d_get_motion_vector_predictor(\n                                        ps_mv_final_pred,\n                                        ps_mv_pred,\n                                        u1_ref_idx,\n                                        uc_lx,\n                                        (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                    }\n                }\n                break;\n            case PRED_8x16:\n                /* Directional prediction for a 8x16 MB partition */\n                if(u1_sub_mb_num == 0)\n                {\n                    if(ps_mv_pred[LEFT]->i1_ref_frame[uc_lx] == u1_ref_idx)\n                    {\n                        /* If the reference frame used by the left subMB is same as the\n                         reference frame used by the current block then MV predictor to\n                         be used for the current block is same as the MV of the left\n                         subMB */\n                        ps_mv_final_pred->i2_mv[uc_B2 + 0] =\n                                        ps_mv_pred[LEFT]->i2_mv[uc_B2 + 0];\n                        ps_mv_final_pred->i2_mv[uc_B2 + 1] =\n                                        ps_mv_pred[LEFT]->i2_mv[uc_B2 + 1];\n                    }\n                    else\n                    {\n                        /* The MV predictor is calculated according to the process\n                         defined in 8.4.1.2.1 */\n                        ih264d_get_motion_vector_predictor(\n                                        ps_mv_final_pred,\n                                        ps_mv_pred,\n                                        u1_ref_idx,\n                                        uc_lx,\n                                        (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                    }\n                }\n                else\n                {\n                    if(ps_mv_pred[TOP_R]->i1_ref_frame[uc_lx] == u1_ref_idx)\n                    {\n                        /* If the reference frame used by the top right subMB is same as\n                         the reference frame used by the current block then MV\n                         predictor to be used for the current block is same as the MV\n                         of the left subMB */\n                        ps_mv_final_pred->i2_mv[uc_B2 + 0] =\n                                        ps_mv_pred[TOP_R]->i2_mv[uc_B2 + 0];\n                        ps_mv_final_pred->i2_mv[uc_B2 + 1] =\n                                        ps_mv_pred[TOP_R]->i2_mv[uc_B2 + 1];\n                    }\n                    else\n                    {\n                        /* The MV predictor is calculated according to the process\n                         defined in 8.4.1.2.1 */\n                        ih264d_get_motion_vector_predictor(\n                                        ps_mv_final_pred,\n                                        ps_mv_pred,\n                                        u1_ref_idx,\n                                        uc_lx,\n                                        (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                    }\n                }\n                break;\n            case B_DIRECT_SPATIAL:\n                /* Case when the MB has been skipped */\n                /* If either of left or the top subMB is not present\n                 OR\n                 If both the MV components of either the left or the top subMB are\n                 zero and their reference frame pointer pointing to 0\n                 then MV for the skipped MB is zero\n                 else the Median of the mv_pred_t is used */\n                uc_temp1 = (UWORD8)ps_mv_pred[LEFT]->i1_ref_frame[0];\n                uc_temp2 = (UWORD8)ps_mv_pred[TOP]->i1_ref_frame[0];\n                uc_temp3 = (UWORD8)ps_mv_pred[TOP_R]->i1_ref_frame[0];\n\n                ps_mv_final_pred->i1_ref_frame[0] = MIN(uc_temp1,\n                                                      MIN(uc_temp2, uc_temp3));\n\n                uc_temp1 = (UWORD8)ps_mv_pred[LEFT]->i1_ref_frame[1];\n                uc_temp2 = (UWORD8)ps_mv_pred[TOP]->i1_ref_frame[1];\n                uc_temp3 = (UWORD8)ps_mv_pred[TOP_R]->i1_ref_frame[1];\n\n                ps_mv_final_pred->i1_ref_frame[1] = MIN(uc_temp1,\n                                                      MIN(uc_temp2, uc_temp3));\n\n                if((ps_mv_final_pred->i1_ref_frame[0] < 0)\n                                && (ps_mv_final_pred->i1_ref_frame[1] < 0))\n                {\n                    u1_direct_zero_pred_flag = 1;\n                    ps_mv_final_pred->i1_ref_frame[0] = 0;\n                    ps_mv_final_pred->i1_ref_frame[1] = 0;\n                }\n                ih264d_get_motion_vector_predictor(\n                                ps_mv_final_pred, ps_mv_pred,\n                                ps_mv_final_pred->i1_ref_frame[0], 0,\n                                (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n\n                ih264d_get_motion_vector_predictor(\n                                ps_mv_final_pred, ps_mv_pred,\n                                ps_mv_final_pred->i1_ref_frame[1], 1,\n                                (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n\n                break;\n            case MB_SKIP:\n                /* Case when the MB has been skipped */\n                /* If either of left or the top subMB is not present\n                 OR\n                 If both the MV components of either the left or the top subMB are\n                 zero and their reference frame pointer pointing to 0\n                 then MV for the skipped MB is zero\n                 else the Median of the mv_pred_t is used */\n                u1_a_in = (ps_cur_mb_info->u1_mb_ngbr_availablity &\n                LEFT_MB_AVAILABLE_MASK);\n                u1_b_in = (ps_cur_mb_info->u1_mb_ngbr_availablity &\n                TOP_MB_AVAILABLE_MASK);\n                if(((u1_a_in * u1_b_in) == 0)\n                                || ((ps_mv_pred[LEFT]->i2_mv[0]\n                                                | ps_mv_pred[LEFT]->i2_mv[1]\n                                                | ps_mv_pred[LEFT]->i1_ref_frame[0])\n                                                == 0)\n                                || ((ps_mv_pred[TOP]->i2_mv[0]\n                                                | ps_mv_pred[TOP]->i2_mv[1]\n                                                | ps_mv_pred[TOP]->i1_ref_frame[0])\n                                                == 0))\n                {\n                    ps_mv_final_pred->i2_mv[0] = 0;\n                    ps_mv_final_pred->i2_mv[1] = 0;\n                    break;\n                }\n                /* If the condition above is not true calculate the MV predictor\n                 according to the process defined in sec 8.4.1.2.1 */\n            default:\n                ih264d_get_motion_vector_predictor(\n                                ps_mv_final_pred, ps_mv_pred, u1_ref_idx, uc_lx,\n                                (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                break;\n        }\n    }\n    return (u1_direct_zero_pred_flag);\n}\n#endif\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_mvpred_nonmbaff                                          */\n/*                                                                           */\n/*  Description   : This function calculates the motion vector predictor,    */\n/*                  for all the slice types other than B_SLICE               */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : None                                                     */\n/*  Processing    : The neighbours A(Left),B(Top),C(TopRight) are calculated */\n/*                  and based on the type of Mb the prediction is            */\n/*                  appropriately done                                       */\n/*  Outputs       : populates ps_mv_final_pred structure                       */\n/*  Returns       : u1_direct_zero_pred_flag which is used only in              */\n/*                    decodeSpatialdirect()                                  */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         03 05 2005   TA              First Draft                          */\n/*                                                                           */\n/*****************************************************************************/\n#if(!MVPRED_NONMBAFF)\nUWORD8 ih264d_mvpred_nonmbaff(dec_struct_t *ps_dec,\n                              dec_mb_info_t *ps_cur_mb_info,\n                              mv_pred_t *ps_mv_nmb,\n                              mv_pred_t *ps_mv_ntop,\n                              mv_pred_t *ps_mv_final_pred,\n                              UWORD8 u1_sub_mb_num,\n                              UWORD8 uc_mb_part_width,\n                              UWORD8 u1_lx_start,\n                              UWORD8 u1_lxend,\n                              UWORD8 u1_mb_mc_mode)\n{\n    UWORD8 u1_a_in, u1_b_in, uc_temp1, uc_temp2, uc_temp3;\n    mv_pred_t *ps_mv_pred[3];\n    UWORD8 u1_ref_idx;\n    UWORD8 u1_direct_zero_pred_flag = 0;\n    UNUSED(u1_lx_start);\n    UNUSED(u1_lxend);\n    ih264d_non_mbaff_mv_pred(ps_mv_pred, u1_sub_mb_num, ps_mv_nmb, ps_mv_ntop,\n                             ps_dec, uc_mb_part_width, ps_cur_mb_info);\n\n    u1_ref_idx = ps_mv_final_pred->i1_ref_frame[0];\n\n    switch(u1_mb_mc_mode)\n    {\n        case PRED_16x8:\n            /* Directional prediction for a 16x8 MB partition */\n            if(u1_sub_mb_num == 0)\n            {\n                /* Calculating the MV pred for the top 16x8 block */\n                if(ps_mv_pred[TOP]->i1_ref_frame[0] == u1_ref_idx)\n                {\n                    /* If the reference frame used by the top subMB is same as the\n                     reference frame used by the current block then MV predictor to\n                     be used for the current block is same as the MV of the top\n                     subMB */\n\n                    ps_mv_final_pred->i2_mv[0] = ps_mv_pred[TOP]->i2_mv[0];\n                    ps_mv_final_pred->i2_mv[1] = ps_mv_pred[TOP]->i2_mv[1];\n                }\n                else\n                {\n                    /* The MV predictor is calculated according to the process\n                     defined in 8.4.1.2.1 */\n                    ih264d_get_motion_vector_predictor(\n                                    ps_mv_final_pred,\n                                    ps_mv_pred,\n                                    u1_ref_idx,\n                                    0,\n                                    (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                }\n            }\n            else\n            {\n                if(ps_mv_pred[LEFT]->i1_ref_frame[0] == u1_ref_idx)\n                {\n                    /* If the reference frame used by the left subMB is same as the\n                     reference frame used by the current block then MV predictor to\n                     be used for the current block is same as the MV of the left\n                     subMB */\n\n                    ps_mv_final_pred->i2_mv[0] = ps_mv_pred[LEFT]->i2_mv[0];\n                    ps_mv_final_pred->i2_mv[1] = ps_mv_pred[LEFT]->i2_mv[1];\n                }\n                else\n                {\n                    /* The MV predictor is calculated according to the process\n                     defined in 8.4.1.2.1 */\n                    ih264d_get_motion_vector_predictor(\n                                    ps_mv_final_pred,\n                                    ps_mv_pred,\n                                    u1_ref_idx,\n                                    0,\n                                    (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                }\n            }\n            break;\n        case PRED_8x16:\n            /* Directional prediction for a 8x16 MB partition */\n            if(u1_sub_mb_num == 0)\n            {\n                if(ps_mv_pred[LEFT]->i1_ref_frame[0] == u1_ref_idx)\n                {\n                    /* If the reference frame used by the left subMB is same as the\n                     reference frame used by the current block then MV predictor to\n                     be used for the current block is same as the MV of the left\n                     subMB */\n\n                    ps_mv_final_pred->i2_mv[0] = ps_mv_pred[LEFT]->i2_mv[0];\n                    ps_mv_final_pred->i2_mv[1] = ps_mv_pred[LEFT]->i2_mv[1];\n                }\n                else\n                {\n                    /* The MV predictor is calculated according to the process\n                     defined in 8.4.1.2.1 */\n                    ih264d_get_motion_vector_predictor(\n                                    ps_mv_final_pred,\n                                    ps_mv_pred,\n                                    u1_ref_idx,\n                                    0,\n                                    (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                }\n            }\n            else\n            {\n                if(ps_mv_pred[TOP_R]->i1_ref_frame[0] == u1_ref_idx)\n                {\n                    /* If the reference frame used by the top right subMB is same as\n                     the reference frame used by the current block then MV\n                     predictor to be used for the current block is same as the MV\n                     of the left subMB */\n\n                    ps_mv_final_pred->i2_mv[0] = ps_mv_pred[TOP_R]->i2_mv[0];\n                    ps_mv_final_pred->i2_mv[1] = ps_mv_pred[TOP_R]->i2_mv[1];\n                }\n                else\n                {\n                    /* The MV predictor is calculated according to the process\n                     defined in 8.4.1.2.1 */\n                    ih264d_get_motion_vector_predictor(\n                                    ps_mv_final_pred,\n                                    ps_mv_pred,\n                                    u1_ref_idx,\n                                    0,\n                                    (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                }\n            }\n            break;\n        case B_DIRECT_SPATIAL:\n            /* Case when the MB has been skipped */\n            /* If either of left or the top subMB is not present\n             OR\n             If both the MV components of either the left or the top subMB are\n             zero and their reference frame pointer pointing to 0\n             then MV for the skipped MB is zero\n             else the Median of the mv_pred_t is used */\n            uc_temp1 = (UWORD8)ps_mv_pred[LEFT]->i1_ref_frame[0];\n            uc_temp2 = (UWORD8)ps_mv_pred[TOP]->i1_ref_frame[0];\n            uc_temp3 = (UWORD8)ps_mv_pred[TOP_R]->i1_ref_frame[0];\n\n            ps_mv_final_pred->i1_ref_frame[0] = MIN(uc_temp1,\n                                                  MIN(uc_temp2, uc_temp3));\n\n            uc_temp1 = (UWORD8)ps_mv_pred[LEFT]->i1_ref_frame[1];\n            uc_temp2 = (UWORD8)ps_mv_pred[TOP]->i1_ref_frame[1];\n            uc_temp3 = (UWORD8)ps_mv_pred[TOP_R]->i1_ref_frame[1];\n\n            ps_mv_final_pred->i1_ref_frame[1] = MIN(uc_temp1,\n                                                  MIN(uc_temp2, uc_temp3));\n\n            if((ps_mv_final_pred->i1_ref_frame[0] < 0)\n                            && (ps_mv_final_pred->i1_ref_frame[1] < 0))\n            {\n                u1_direct_zero_pred_flag = 1;\n                ps_mv_final_pred->i1_ref_frame[0] = 0;\n                ps_mv_final_pred->i1_ref_frame[1] = 0;\n            }\n            ih264d_get_motion_vector_predictor(\n                            ps_mv_final_pred, ps_mv_pred,\n                            ps_mv_final_pred->i1_ref_frame[0], 0,\n                            (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n\n            ih264d_get_motion_vector_predictor(\n                            ps_mv_final_pred, ps_mv_pred,\n                            ps_mv_final_pred->i1_ref_frame[1], 1,\n                            (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n\n            break;\n        case MB_SKIP:\n            /* Case when the MB has been skipped */\n            /* If either of left or the top subMB is not present\n             OR\n             If both the MV components of either the left or the top subMB are\n             zero and their reference frame pointer pointing to 0\n             then MV for the skipped MB is zero\n             else the Median of the mv_pred_t is used */\n            u1_a_in = (ps_cur_mb_info->u1_mb_ngbr_availablity &\n            LEFT_MB_AVAILABLE_MASK);\n            u1_b_in = (ps_cur_mb_info->u1_mb_ngbr_availablity &\n            TOP_MB_AVAILABLE_MASK);\n            if(((u1_a_in * u1_b_in) == 0)\n                            || ((ps_mv_pred[LEFT]->i2_mv[0]\n                                            | ps_mv_pred[LEFT]->i2_mv[1]\n                                            | ps_mv_pred[LEFT]->i1_ref_frame[0])\n                                            == 0)\n                            || ((ps_mv_pred[TOP]->i2_mv[0]\n                                            | ps_mv_pred[TOP]->i2_mv[1]\n                                            | ps_mv_pred[TOP]->i1_ref_frame[0])\n                                            == 0))\n            {\n\n                ps_mv_final_pred->i2_mv[0] = 0;\n                ps_mv_final_pred->i2_mv[1] = 0;\n                break;\n            }\n            /* If the condition above is not true calculate the MV predictor\n             according to the process defined in sec 8.4.1.2.1 */\n        default:\n            ih264d_get_motion_vector_predictor(\n                            ps_mv_final_pred, ps_mv_pred, u1_ref_idx, 0,\n                            (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n            break;\n    }\n\n    return (u1_direct_zero_pred_flag);\n}\n#endif\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_mvpred_mbaff                                             */\n/*                                                                           */\n/*  Description   : This function calculates the motion vector predictor,    */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : None                                                     */\n/*  Processing    : The neighbours A(Left),B(Top),C(TopRight) are calculated */\n/*                  and based on the type of Mb the prediction is            */\n/*                  appropriately done                                       */\n/*  Outputs       : populates ps_mv_final_pred structure                       */\n/*  Returns       : u1_direct_zero_pred_flag which is used only in              */\n/*                    decodeSpatialdirect()                                  */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         03 05 2005   TA              First Draft                          */\n/*                                                                           */\n/*****************************************************************************/\n\nUWORD8 ih264d_mvpred_mbaff(dec_struct_t *ps_dec,\n                           dec_mb_info_t *ps_cur_mb_info,\n                           mv_pred_t *ps_mv_nmb,\n                           mv_pred_t *ps_mv_ntop,\n                           mv_pred_t *ps_mv_final_pred,\n                           UWORD8 u1_sub_mb_num,\n                           UWORD8 uc_mb_part_width,\n                           UWORD8 u1_lx_start,\n                           UWORD8 u1_lxend,\n                           UWORD8 u1_mb_mc_mode)\n{\n    UWORD8 u1_a_in, u1_b_in, uc_temp1, uc_temp2, uc_temp3;\n    mv_pred_t *ps_mv_pred[3], s_mvPred[3];\n    UWORD8 uc_B2, pu0_scale[3], i, uc_lx, u1_ref_idx;\n    UWORD8 u1_direct_zero_pred_flag = 0;\n\n    pu0_scale[0] = pu0_scale[1] = pu0_scale[2] = 0;\n    ih264d_mbaff_mv_pred(ps_mv_pred, u1_sub_mb_num, ps_mv_nmb, ps_mv_ntop, ps_dec,\n                         uc_mb_part_width, ps_cur_mb_info, pu0_scale);\n    for(i = 0; i < 3; i++)\n    {\n        if(pu0_scale[i] != 0)\n        {\n            memcpy(&s_mvPred[i], ps_mv_pred[i], sizeof(mv_pred_t));\n            if(pu0_scale[i] == 1)\n            {\n                s_mvPred[i].i1_ref_frame[0] = s_mvPred[i].i1_ref_frame[0] << 1;\n                s_mvPred[i].i1_ref_frame[1] = s_mvPred[i].i1_ref_frame[1] << 1;\n                s_mvPred[i].i2_mv[1] = SIGN_POW2_DIV(s_mvPred[i].i2_mv[1], 1);\n                s_mvPred[i].i2_mv[3] = SIGN_POW2_DIV(s_mvPred[i].i2_mv[3], 1);\n            }\n            else\n            {\n                s_mvPred[i].i1_ref_frame[0] = s_mvPred[i].i1_ref_frame[0] >> 1;\n                s_mvPred[i].i1_ref_frame[1] = s_mvPred[i].i1_ref_frame[1] >> 1;\n                s_mvPred[i].i2_mv[1] = s_mvPred[i].i2_mv[1] << 1;\n                s_mvPred[i].i2_mv[3] = s_mvPred[i].i2_mv[3] << 1;\n            }\n            ps_mv_pred[i] = &s_mvPred[i];\n        }\n    }\n\n    for(uc_lx = u1_lx_start; uc_lx < u1_lxend; uc_lx++)\n    {\n        u1_ref_idx = ps_mv_final_pred->i1_ref_frame[uc_lx];\n        uc_B2 = (uc_lx << 1);\n        switch(u1_mb_mc_mode)\n        {\n            case PRED_16x8:\n                /* Directional prediction for a 16x8 MB partition */\n                if(u1_sub_mb_num == 0)\n                {\n                    /* Calculating the MV pred for the top 16x8 block */\n                    if(ps_mv_pred[TOP]->i1_ref_frame[uc_lx] == u1_ref_idx)\n                    {\n                        /* If the reference frame used by the top subMB is same as the\n                         reference frame used by the current block then MV predictor to\n                         be used for the current block is same as the MV of the top\n                         subMB */\n                        ps_mv_final_pred->i2_mv[uc_B2 + 0] =\n                                        ps_mv_pred[TOP]->i2_mv[uc_B2 + 0];\n                        ps_mv_final_pred->i2_mv[uc_B2 + 1] =\n                                        ps_mv_pred[TOP]->i2_mv[uc_B2 + 1];\n                    }\n                    else\n                    {\n                        /* The MV predictor is calculated according to the process\n                         defined in 8.4.1.2.1 */\n                        ih264d_get_motion_vector_predictor(\n                                        ps_mv_final_pred,\n                                        ps_mv_pred,\n                                        u1_ref_idx,\n                                        uc_lx,\n                                        (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                    }\n                }\n                else\n                {\n                    if(ps_mv_pred[LEFT]->i1_ref_frame[uc_lx] == u1_ref_idx)\n                    {\n                        /* If the reference frame used by the left subMB is same as the\n                         reference frame used by the current block then MV predictor to\n                         be used for the current block is same as the MV of the left\n                         subMB */\n                        ps_mv_final_pred->i2_mv[uc_B2 + 0] =\n                                        ps_mv_pred[LEFT]->i2_mv[uc_B2 + 0];\n                        ps_mv_final_pred->i2_mv[uc_B2 + 1] =\n                                        ps_mv_pred[LEFT]->i2_mv[uc_B2 + 1];\n                    }\n                    else\n                    {\n                        /* The MV predictor is calculated according to the process\n                         defined in 8.4.1.2.1 */\n                        ih264d_get_motion_vector_predictor(\n                                        ps_mv_final_pred,\n                                        ps_mv_pred,\n                                        u1_ref_idx,\n                                        uc_lx,\n                                        (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                    }\n                }\n                break;\n            case PRED_8x16:\n                /* Directional prediction for a 8x16 MB partition */\n                if(u1_sub_mb_num == 0)\n                {\n                    if(ps_mv_pred[LEFT]->i1_ref_frame[uc_lx] == u1_ref_idx)\n                    {\n                        /* If the reference frame used by the left subMB is same as the\n                         reference frame used by the current block then MV predictor to\n                         be used for the current block is same as the MV of the left\n                         subMB */\n                        ps_mv_final_pred->i2_mv[uc_B2 + 0] =\n                                        ps_mv_pred[LEFT]->i2_mv[uc_B2 + 0];\n                        ps_mv_final_pred->i2_mv[uc_B2 + 1] =\n                                        ps_mv_pred[LEFT]->i2_mv[uc_B2 + 1];\n                    }\n                    else\n                    {\n                        /* The MV predictor is calculated according to the process\n                         defined in 8.4.1.2.1 */\n                        ih264d_get_motion_vector_predictor(\n                                        ps_mv_final_pred,\n                                        ps_mv_pred,\n                                        u1_ref_idx,\n                                        uc_lx,\n                                        (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                    }\n                }\n                else\n                {\n                    if(ps_mv_pred[TOP_R]->i1_ref_frame[uc_lx] == u1_ref_idx)\n                    {\n                        /* If the reference frame used by the top right subMB is same as\n                         the reference frame used by the current block then MV\n                         predictor to be used for the current block is same as the MV\n                         of the left subMB */\n                        ps_mv_final_pred->i2_mv[uc_B2 + 0] =\n                                        ps_mv_pred[TOP_R]->i2_mv[uc_B2 + 0];\n                        ps_mv_final_pred->i2_mv[uc_B2 + 1] =\n                                        ps_mv_pred[TOP_R]->i2_mv[uc_B2 + 1];\n                    }\n                    else\n                    {\n                        /* The MV predictor is calculated according to the process\n                         defined in 8.4.1.2.1 */\n                        ih264d_get_motion_vector_predictor(\n                                        ps_mv_final_pred,\n                                        ps_mv_pred,\n                                        u1_ref_idx,\n                                        uc_lx,\n                                        (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                    }\n                }\n                break;\n            case B_DIRECT_SPATIAL:\n                /* Case when the MB has been skipped */\n                /* If either of left or the top subMB is not present\n                 OR\n                 If both the MV components of either the left or the top subMB are\n                 zero and their reference frame pointer pointing to 0\n                 then MV for the skipped MB is zero\n                 else the Median of the mv_pred_t is used */\n                uc_temp1 = (UWORD8)ps_mv_pred[LEFT]->i1_ref_frame[0];\n                uc_temp2 = (UWORD8)ps_mv_pred[TOP]->i1_ref_frame[0];\n                uc_temp3 = (UWORD8)ps_mv_pred[TOP_R]->i1_ref_frame[0];\n\n                ps_mv_final_pred->i1_ref_frame[0] = MIN(uc_temp1,\n                                                      MIN(uc_temp2, uc_temp3));\n\n                uc_temp1 = (UWORD8)ps_mv_pred[LEFT]->i1_ref_frame[1];\n                uc_temp2 = (UWORD8)ps_mv_pred[TOP]->i1_ref_frame[1];\n                uc_temp3 = (UWORD8)ps_mv_pred[TOP_R]->i1_ref_frame[1];\n\n                ps_mv_final_pred->i1_ref_frame[1] = MIN(uc_temp1,\n                                                      MIN(uc_temp2, uc_temp3));\n\n                /* If the reference indices are negative clip the scaled reference indices to -1 */\n                /* i.e invalid reference index */\n\n                /*if(ps_mv_final_pred->i1_ref_frame[0] < 0)\n                 ps_mv_final_pred->i1_ref_frame[0] = -1;\n\n                 if(ps_mv_final_pred->i1_ref_frame[1] < 0)\n                 ps_mv_final_pred->i1_ref_frame[1] = -1; */\n\n                if((ps_mv_final_pred->i1_ref_frame[0] < 0)\n                                && (ps_mv_final_pred->i1_ref_frame[1] < 0))\n                {\n                    u1_direct_zero_pred_flag = 1;\n                    ps_mv_final_pred->i1_ref_frame[0] = 0;\n                    ps_mv_final_pred->i1_ref_frame[1] = 0;\n                }\n                ih264d_get_motion_vector_predictor(\n                                ps_mv_final_pred, ps_mv_pred,\n                                ps_mv_final_pred->i1_ref_frame[0], 0,\n                                (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n\n                ih264d_get_motion_vector_predictor(\n                                ps_mv_final_pred, ps_mv_pred,\n                                ps_mv_final_pred->i1_ref_frame[1], 1,\n                                (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n\n                break;\n            case MB_SKIP:\n                /* Case when the MB has been skipped */\n                /* If either of left or the top subMB is not present\n                 OR\n                 If both the MV components of either the left or the top subMB are\n                 zero and their reference frame pointer pointing to 0\n                 then MV for the skipped MB is zero\n                 else the Median of the mv_pred_t is used */\n                u1_a_in = (ps_cur_mb_info->u1_mb_ngbr_availablity &\n                LEFT_MB_AVAILABLE_MASK);\n                u1_b_in = (ps_cur_mb_info->u1_mb_ngbr_availablity &\n                TOP_MB_AVAILABLE_MASK);\n                if(((u1_a_in * u1_b_in) == 0)\n                                || ((ps_mv_pred[LEFT]->i2_mv[0]\n                                                | ps_mv_pred[LEFT]->i2_mv[1]\n                                                | ps_mv_pred[LEFT]->i1_ref_frame[0])\n                                                == 0)\n                                || ((ps_mv_pred[TOP]->i2_mv[0]\n                                                | ps_mv_pred[TOP]->i2_mv[1]\n                                                | ps_mv_pred[TOP]->i1_ref_frame[0])\n                                                == 0))\n                {\n                    ps_mv_final_pred->i2_mv[0] = 0;\n                    ps_mv_final_pred->i2_mv[1] = 0;\n                    break;\n                }\n                /* If the condition above is not true calculate the MV predictor\n                 according to the process defined in sec 8.4.1.2.1 */\n            default:\n                ih264d_get_motion_vector_predictor(\n                                ps_mv_final_pred, ps_mv_pred, u1_ref_idx, uc_lx,\n                                (const UWORD8 *)gau1_ih264d_mv_pred_condition);\n                break;\n        }\n    }\n    return (u1_direct_zero_pred_flag);\n}\n\n\n\n\nvoid ih264d_rep_mv_colz(dec_struct_t *ps_dec,\n                        mv_pred_t *ps_mv_pred_src,\n                        mv_pred_t *ps_mv_pred_dst,\n                        UWORD8 u1_sub_mb_num,\n                        UWORD8 u1_colz,\n                        UWORD8 u1_ht,\n                        UWORD8 u1_wd)\n{\n\n    UWORD8 k, m;\n    UWORD8 *pu1_colz = ps_dec->pu1_col_zero_flag + ps_dec->i4_submb_ofst\n                    + u1_sub_mb_num;\n\n    for(k = 0; k < u1_ht; k++)\n    {\n        for(m = 0; m < u1_wd; m++)\n        {\n            *(ps_mv_pred_dst + m) = *(ps_mv_pred_src);\n            *(pu1_colz + m) = u1_colz;\n\n        }\n        pu1_colz += SUB_BLK_WIDTH;\n        ps_mv_pred_dst += SUB_BLK_WIDTH;\n    }\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_mvpred.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n#ifndef _IH264D_MVPRED_H_\n#define _IH264D_MVPRED_H_\n\n/**\n**************************************************************************\n* \\file ih264d_mvpred.h\n*\n* \\brief\n*    This file contains declarations of functions specific to decoding\n*    Motion vector.\n*\n* Detailed_description\n*\n* \\date\n*    10-12-2002\n*\n* \\author  Arvind Raman\n**************************************************************************\n*/\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n//#include \"structs.h\"\n\n/** Reference number that is not valid */\n#define OUT_OF_RANGE_REF  -1\n\n#define ONE_TO_ONE    0\n#define FRM_TO_FLD    1\n#define FLD_TO_FRM    2\n\n/**\n**************************************************************************\n*   \\brief   POSITION_IN_MVBANK\n*\n*   a: Pointer to the top left subMb of the MB in the MV bank array\n*   b: Horiz posn in terms of subMbs\n*   c: Vert posn in terms of subMbs\n*   d: subMb number\n**************************************************************************\n*/\n#define POSITION_IN_MVBANK(a, b, c, d) (a) + (c) * (d) + (b)\n\n\n\n/**\n**************************************************************************\n*   \\brief   col4x4_t\n*\n*   Container to return the information related to the co-located 4x4\n*   sub-macroblock.\n**************************************************************************\n*/\ntypedef struct\n{\n  mv_pred_t *ps_mv;     /** Ptr to the Mv bank */\n  UWORD16 u2_mb_addr_col;       /** Addr of the co-located MB */\n  WORD16 i2_mv[2];      /** Mv of the colocated MB */\n  WORD8 i1_ref_idx_col;     /** Ref idx of the co-located picture */\n  UWORD8 u1_col_pic;        /** Idx of the colocated pic */\n  UWORD8 u1_yM;     /** \"y\" coord of the colocated MB addr */\n  UWORD8 u1_vert_mv_scale;      /** as defined in sec 8.4.1.2.1 */\n} col4x4_t;\n\n\n\n\n\nvoid ih264d_update_nnz_for_skipmb(dec_struct_t * ps_dec,\n                                  dec_mb_info_t * ps_cur_mb_info,\n                                  UWORD8 u1_entrpy);\n\nvoid ih264d_get_motion_vector_predictor(mv_pred_t * ps_result,\n                                        mv_pred_t **ps_mv_pred,\n                                        UWORD8 u1_ref_idx,\n                                        UWORD8 u1_B,\n                                        const UWORD8 *pu1_mv_pred_condition);\nvoid ih264d_mbaff_mv_pred(mv_pred_t **ps_mv_pred,\n                          UWORD8 u1_sub_mb_num,\n                          mv_pred_t *ps_mv_nmb,\n                          mv_pred_t *ps_mv_ntop,\n                          dec_struct_t *ps_dec,\n                          UWORD8 uc_mb_part_width,\n                          dec_mb_info_t *ps_cur_mb_info,\n                          UWORD8* pu0_scale);\nvoid ih264d_non_mbaff_mv_pred(mv_pred_t **ps_mv_pred,\n                              UWORD8 u1_sub_mb_num,\n                              mv_pred_t *ps_mv_nmb,\n                              mv_pred_t *ps_mv_ntop,\n                              dec_struct_t *ps_dec,\n                              UWORD8 uc_mb_part_width,\n                              dec_mb_info_t *ps_cur_mb_info);\nUWORD8 ih264d_mvpred_nonmbaff(dec_struct_t *ps_dec,\n                              dec_mb_info_t *ps_cur_mb_info,\n                              mv_pred_t *ps_mv_nmb,\n                              mv_pred_t *ps_mv_ntop,\n                              mv_pred_t *ps_mv_final_pred,\n                              UWORD8 u1_sub_mb_num,\n                              UWORD8 uc_mb_part_width,\n                              UWORD8 u1_lx_start,\n                              UWORD8 u1_lxend,\n                              UWORD8 u1_mb_mc_mode);\n\nUWORD8 ih264d_mvpred_nonmbaffB(dec_struct_t *ps_dec,\n                               dec_mb_info_t *ps_cur_mb_info,\n                               mv_pred_t *ps_mv_nmb,\n                               mv_pred_t *ps_mv_ntop,\n                               mv_pred_t *ps_mv_final_pred,\n                               UWORD8 u1_sub_mb_num,\n                               UWORD8 uc_mb_part_width,\n                               UWORD8 u1_lx_start,\n                               UWORD8 u1_lxend,\n                               UWORD8 u1_mb_mc_mode);\n\nUWORD8 ih264d_mvpred_mbaff(dec_struct_t *ps_dec,\n                           dec_mb_info_t *ps_cur_mb_info,\n                           mv_pred_t *ps_mv_nmb,\n                           mv_pred_t *ps_mv_ntop,\n                           mv_pred_t *ps_mv_final_pred,\n                           UWORD8 u1_sub_mb_num,\n                           UWORD8 uc_mb_part_width,\n                           UWORD8 u1_lx_start,\n                           UWORD8 u1_lxend,\n                           UWORD8 u1_mb_mc_mode);\n\nvoid ih264d_rep_mv_colz(dec_struct_t *ps_dec,\n                        mv_pred_t *ps_mv_pred_src,\n                        mv_pred_t *ps_mv_pred_dst,\n                        UWORD8 u1_sub_mb_num,\n                        UWORD8 u1_colz,\n                        UWORD8 u1_ht,\n                        UWORD8 u1_wd);\n\n#endif  /* _IH264D_MVPRED_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_nal.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n *  \\file   ih264d_nal.c\n *\n *  \\brief  NAL parsing routines\n *\n *  Detailed_description\n *\n *  \\author\n *         - AI  19 11 2002  Creation\n **************************************************************************\n */\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_defs.h\"\n#define NUM_OF_ZERO_BYTES_BEFORE_START_CODE 2\n#define EMULATION_PREVENTION_BYTE           0x03\n\n#define NAL_FIRST_BYTE_SIZE 1\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_find_start_code \\endif\n *\n * \\brief\n *    This function searches for the Start Code Prefix.\n *\n * \\param pu1_buf : Pointer to char buffer which contains bitstream.\n * \\param u4_cur_pos : Current position in the buffer.\n * \\param u4_max_ofst : Number of bytes in Buffer.\n * \\param pu4_length_of_start_code  : Poiter to length of Start Code.\n *\n * \\return\n *    Returns 0 on success and -1 on error.\n *\n **************************************************************************\n */\n#define START_CODE_NOT_FOUND    -1\n#define END_OF_STREAM_BUFFER    -2\n#define END_OF_STREAM           -1\n\nvoid ih264d_check_if_aud(UWORD8 *pu1_buf,\n                         UWORD32 u4_cur_pos,\n                         UWORD32 u4_max_ofst,\n                         UWORD32 *pu4_next_is_aud)\n{\n    UWORD8 u1_first_byte, u1_nal_unit_type;\n    if(u4_cur_pos + 1 < u4_max_ofst)\n    {\n        u1_first_byte = pu1_buf[u4_cur_pos + 1];\n        u1_nal_unit_type = NAL_UNIT_TYPE(u1_first_byte);\n\n        if(u1_nal_unit_type == ACCESS_UNIT_DELIMITER_RBSP)\n        {\n            *pu4_next_is_aud = 1;\n        }\n    }\n\n}\nWORD32 ih264d_find_start_code(UWORD8 *pu1_buf,\n                              UWORD32 u4_cur_pos,\n                              UWORD32 u4_max_ofst,\n                              UWORD32 *pu4_length_of_start_code,\n                              UWORD32 *pu4_next_is_aud)\n{\n    WORD32 zero_byte_cnt = 0;\n    UWORD32 ui_curPosTemp;\n\n    *pu4_length_of_start_code = 0;\n    /*Find first start code */\n    while(u4_cur_pos < u4_max_ofst)\n    {\n        if(pu1_buf[u4_cur_pos] == 0)\n            zero_byte_cnt++;\n        else if(pu1_buf[u4_cur_pos]\n                        == 0x01 && zero_byte_cnt >= NUM_OF_ZERO_BYTES_BEFORE_START_CODE)\n        {\n            /* Found the start code */\n            u4_cur_pos++;\n            break;\n        }\n        else\n        {\n            zero_byte_cnt = 0;\n        }\n        u4_cur_pos++;\n    }\n    /*Find Next Start Code */\n    *pu4_length_of_start_code = u4_cur_pos;\n    zero_byte_cnt = 0;\n    ui_curPosTemp = u4_cur_pos;\n    while(u4_cur_pos < u4_max_ofst)\n    {\n\n        if(pu1_buf[u4_cur_pos] == 0)\n            zero_byte_cnt++;\n        else if(pu1_buf[u4_cur_pos]\n                        == 0x01 && zero_byte_cnt >= NUM_OF_ZERO_BYTES_BEFORE_START_CODE)\n        {\n            /* Found the start code */\n            ih264d_check_if_aud(pu1_buf, u4_cur_pos, u4_max_ofst,\n                                pu4_next_is_aud);\n            return (u4_cur_pos - zero_byte_cnt - ui_curPosTemp);\n        }\n        else\n        {\n            zero_byte_cnt = 0;\n        }\n        u4_cur_pos++;\n    }\n\n    return (u4_cur_pos - zero_byte_cnt - ui_curPosTemp); //(START_CODE_NOT_FOUND);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_get_next_nal_unit \\endif\n *\n * \\brief\n *    This function reads one NAl unit.\n *\n * \\param ps_nalStream : Poiter to NalUnitStream structure.\n * \\param ps_nalUnit : Pointer to NalUnit.\n *\n * \\return\n *    Returns 0 on success and -1 on error.\n *\n **************************************************************************\n */\nWORD32 ih264d_get_next_nal_unit(UWORD8 *pu1_buf,\n                                UWORD32 u4_cur_pos,\n                                UWORD32 u4_max_ofst,\n                                UWORD32 *pu4_length_of_start_code)\n{\n\n    WORD32 i_length_of_nal_unit = 0;\n    UWORD32 u4_next_is_aud;\n\n    /* NAL Thread starts */\n\n    ih264d_find_start_code(pu1_buf, u4_cur_pos, u4_max_ofst,\n                           pu4_length_of_start_code, &u4_next_is_aud);\n\n    return (i_length_of_nal_unit);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_process_nal_unit \\endif\n *\n * \\brief\n *    This function removes emulation byte \"0x03\" from bitstream (EBSP to RBSP).\n *    It also converts bytestream format into 32 bit little-endian format.\n *\n * \\param ps_bitstrm : Poiter to dec_bit_stream_t structure.\n * \\param pu1_nal_unit  : Pointer to char buffer of NalUnit.\n * \\param u4_numbytes_in_nal_unit : Number bytes in NalUnit buffer.\n *\n * \\return\n *    Returns number of bytes in RBSP ps_bitstrm.\n *\n * \\note\n *    This function is same as nal_unit() of 7.3.1. Apart from nal_unit()\n *    implementation it converts char buffer into 32 bit Buffer. This\n *    facilitates efficient access of bitstream. This has been done taking\n *    into account present processor architectures.\n *\n **************************************************************************\n */\nWORD32 ih264d_process_nal_unit(dec_bit_stream_t *ps_bitstrm,\n                            UWORD8 *pu1_nal_unit,\n                            UWORD32 u4_numbytes_in_nal_unit)\n{\n    UWORD32 u4_num_bytes_in_rbsp;\n    UWORD8 u1_cur_byte;\n    WORD32 i = 0;\n    WORD8 c_count;\n    UWORD32 ui_word;\n    UWORD32 *puc_bitstream_buffer = (UWORD32*)pu1_nal_unit;\n    ps_bitstrm->pu4_buffer = puc_bitstream_buffer;\n\n    /*--------------------------------------------------------------------*/\n    /* First Byte of the NAL Unit                                         */\n    /*--------------------------------------------------------------------*/\n\n    ui_word = *pu1_nal_unit++;\n\n    /*--------------------------------------------------------------------*/\n    /* Convertion of the EBSP to RBSP                                     */\n    /* ie Remove the emulation_prevention_byte [equal to 0x03]            */\n    /*--------------------------------------------------------------------*/\n    u4_num_bytes_in_rbsp = 0;\n    c_count = 0;\n\n//first iteration\n\n    u1_cur_byte = *pu1_nal_unit++;\n\n    ui_word = ((ui_word << 8) | u1_cur_byte);\n\n    c_count++;\n    if(u1_cur_byte != 0x00)\n        c_count = 0;\n\n//second iteration\n\n    u1_cur_byte = *pu1_nal_unit++;\n\n    ui_word = ((ui_word << 8) | u1_cur_byte);\n    u4_num_bytes_in_rbsp = 2;\n\n    c_count++;\n    if(u1_cur_byte != 0x00)\n        c_count = 0;\n\n    if(u4_numbytes_in_nal_unit > 2)\n    {\n        i = ((u4_numbytes_in_nal_unit - 3));\n    }\n\n    for(; i > 8; i -= 4)\n    {\n\n// loop 0\n        u1_cur_byte = *pu1_nal_unit++;\n\n        if(c_count == NUM_OF_ZERO_BYTES_BEFORE_START_CODE\n                        && u1_cur_byte == EMULATION_PREVENTION_BYTE)\n        {\n            c_count = 0;\n            u1_cur_byte = *pu1_nal_unit++;\n            i--;\n        }\n\n        ui_word = ((ui_word << 8) | u1_cur_byte);\n        *puc_bitstream_buffer = ui_word;\n        puc_bitstream_buffer++;\n        c_count++;\n        if(u1_cur_byte != 0x00)\n            c_count = 0;\n\n// loop 1\n        u1_cur_byte = *pu1_nal_unit++;\n\n        if(c_count == NUM_OF_ZERO_BYTES_BEFORE_START_CODE\n                        && u1_cur_byte == EMULATION_PREVENTION_BYTE)\n        {\n            c_count = 0;\n            u1_cur_byte = *pu1_nal_unit++;\n            i--;\n        }\n        ui_word = ((ui_word << 8) | u1_cur_byte);\n\n        c_count++;\n        if(u1_cur_byte != 0x00)\n            c_count = 0;\n\n// loop 2\n        u1_cur_byte = *pu1_nal_unit++;\n\n        if(c_count == NUM_OF_ZERO_BYTES_BEFORE_START_CODE\n                        && u1_cur_byte == EMULATION_PREVENTION_BYTE)\n        {\n            c_count = 0;\n            u1_cur_byte = *pu1_nal_unit++;\n            i--;\n        }\n\n        ui_word = ((ui_word << 8) | u1_cur_byte);\n\n        c_count++;\n        if(u1_cur_byte != 0x00)\n            c_count = 0;\n\n// loop 3\n        u1_cur_byte = *pu1_nal_unit++;\n\n        if(c_count == NUM_OF_ZERO_BYTES_BEFORE_START_CODE\n                        && u1_cur_byte == EMULATION_PREVENTION_BYTE)\n        {\n            c_count = 0;\n            u1_cur_byte = *pu1_nal_unit++;\n            i--;\n        }\n\n        ui_word = ((ui_word << 8) | u1_cur_byte);\n\n        c_count++;\n        if(u1_cur_byte != 0x00)\n            c_count = 0;\n\n        u4_num_bytes_in_rbsp += 4;\n\n    }\n\n    for(; i > 0; i--)\n    {\n        u1_cur_byte = *pu1_nal_unit++;\n\n        if(c_count == NUM_OF_ZERO_BYTES_BEFORE_START_CODE\n                        && u1_cur_byte == EMULATION_PREVENTION_BYTE)\n        {\n            c_count = 0;\n            i--;\n            u1_cur_byte = *pu1_nal_unit++;\n        }\n\n        ui_word = ((ui_word << 8) | u1_cur_byte);\n        u4_num_bytes_in_rbsp++;\n\n        if((u4_num_bytes_in_rbsp & 0x03) == 0x03)\n        {\n            *puc_bitstream_buffer = ui_word;\n            puc_bitstream_buffer++;\n        }\n        c_count++;\n        if(u1_cur_byte != 0x00)\n            c_count = 0;\n\n    }\n\n    *puc_bitstream_buffer = (ui_word\n                    << ((3 - (((u4_num_bytes_in_rbsp << 30) >> 30))) << 3));\n    ps_bitstrm->u4_ofst = 0;\n    ps_bitstrm->u4_max_ofst = ((u4_num_bytes_in_rbsp + NAL_FIRST_BYTE_SIZE) << 3);\n\n    return (u4_num_bytes_in_rbsp);\n}\n\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_rbsp_to_sodb \\endif\n *\n * \\brief\n *    This function converts RBSP to SODB.\n *\n * \\param ps_bitstrm : Poiter to dec_bit_stream_t structure.\n *\n * \\return\n *    None.\n *\n **************************************************************************\n */\nvoid ih264d_rbsp_to_sodb(dec_bit_stream_t *ps_bitstrm)\n{\n    UWORD32 ui_lastWord;\n    UWORD32 ui_word;\n    UWORD8 uc_lastByte;\n    WORD8 i;\n\n    ui_lastWord = (ps_bitstrm->u4_max_ofst >> 5);\n    i = (ps_bitstrm->u4_max_ofst >> 3) & 0x03;\n\n    if(i)\n    {\n        ui_word = ps_bitstrm->pu4_buffer[ui_lastWord];\n        uc_lastByte = ((ui_word << ((i - 1) << 3)) >> 24);\n    }\n    else\n    {\n        ui_word = ps_bitstrm->pu4_buffer[ui_lastWord - 1];\n        uc_lastByte = ((ui_word << 24) >> 24);\n    }\n    /*--------------------------------------------------------------------*/\n    /* Find out the rbsp_stop_bit position in the last byte of rbsp       */\n    /*--------------------------------------------------------------------*/\n    for(i = 0; (i < 8) && !CHECKBIT(uc_lastByte, i); ++i)\n        ;\n    ps_bitstrm->u4_max_ofst = ps_bitstrm->u4_max_ofst - (i + 1);\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_nal.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n#ifndef _IH264D_NAL_H_\n#define _IH264D_NAL_H_\n\n/*!\n*************************************************************************\n* \\file ih264d_nal.h\n*\n* \\brief\n*    short_description\n*\n* Detailed_description\n*\n* \\date\n*    21/11/2002\n*\n* \\author  AI\n*************************************************************************\n*/\n#include <stdio.h>\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_bitstrm.h\"\n\nWORD32 ih264d_process_nal_unit(dec_bit_stream_t *ps_bitstrm,\n                            UWORD8 *pu1_nal_unit,\n                            UWORD32 u4_numbytes_in_nal_unit);\nvoid ih264d_rbsp_to_sodb(dec_bit_stream_t *ps_bitstrm);\nWORD32 ih264d_find_start_code(UWORD8 *pu1_buf,\n                              UWORD32 u4_cur_pos,\n                              UWORD32 u4_max_ofst,\n                              UWORD32 *pu4_length_of_start_code,\n                              UWORD32 *pu4_next_is_aud);\n\n\n#endif /* _IH264D_NAL_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_bslice.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n * \\file ih264d_parse_bslice.c\n *\n * \\brief\n *    Contains routines that decode a I slice type\n *\n * Detailed_description\n *\n * \\date\n *    07/07/2003\n *\n * \\author  NS\n **************************************************************************\n */\n\n#include <string.h>\n#include \"ih264_defs.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_process_intra_mb.h\"\n#include \"ih264d_mvpred.h\"\n#include \"ih264d_parse_islice.h\"\n#include \"ih264d_inter_pred.h\"\n#include \"ih264d_process_pslice.h\"\n#include \"ih264d_process_bslice.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_cabac.h\"\n#include \"ih264d_parse_mb_header.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_mvpred.h\"\n#include \"ih264d_cabac.h\"\n#include \"ih264d_utils.h\"\n\nvoid ih264d_init_cabac_contexts(UWORD8 u1_slice_type, dec_struct_t * ps_dec);\n\n/*!\n **************************************************************************\n * \\if Function name : ParseMb_SubMb_PredBCav\\endif\n *\n * \\brief\n *    Implements sub_mb_pred() of 7.3.5.2. & mb_pred() of 7.3.5.1\n *\n * \\return\n *    None.\n *\n **************************************************************************\n */\nWORD32 ih264d_parse_bmb_non_direct_cavlc(dec_struct_t * ps_dec,\n                                       dec_mb_info_t * ps_cur_mb_info,\n                                       UWORD8 u1_mb_num,\n                                       UWORD8 u1_num_mbsNby2)\n{\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD8 * pu1_sub_mb_pred_modes = (UWORD8 *)(gau1_ih264d_submb_pred_modes) + 4;\n    const UWORD8 (*pu1_mb_pred_modes)[32] =\n                    (const UWORD8 (*)[32])gau1_ih264d_mb_pred_modes;\n    const UWORD8 * pu1_num_mb_part = (const UWORD8 *)gau1_ih264d_num_mb_part;\n    const UWORD8 * pu1_sub_mb_mc_mode = (const UWORD8 *)(gau1_ih264d_submb_mc_mode)\n                    + 4;\n\n    parse_pmbarams_t * ps_parse_mb_data = ps_dec->ps_parse_mb_data\n                    + u1_num_mbsNby2;\n    UWORD8 * pu1_col_info = ps_parse_mb_data->u1_col_info;\n    WORD8 (*pi1_ref_idx)[MAX_REFIDX_INFO_PER_MB] = ps_parse_mb_data->i1_ref_idx;\n    UWORD8 u1_mb_type = ps_cur_mb_info->u1_mb_type;\n    UWORD8 u1_mb_mc_mode, u1_num_mb_part, u1_sub_mb = !(u1_mb_type ^ B_8x8);\n    UWORD32 u4_mb_mc_mode = 0, u4_mb_pred_mode = 0;\n    WORD32 ret;\n\n    if(u1_sub_mb)\n    {\n        UWORD8 uc_i;\n        u1_mb_mc_mode = 0;\n        u1_num_mb_part = 4;\n        /* Reading the subMB type */\n        for(uc_i = 0; uc_i < 4; uc_i++)\n        {\n\n            UWORD32 ui_sub_mb_mode;\n\n//Inlined ih264d_uev\n            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n            UWORD32 u4_word, u4_ldz;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n            u4_ldz = CLZ(u4_word);\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_ldz);\n            *pu4_bitstrm_ofst = u4_bitstream_offset;\n            ui_sub_mb_mode = ((1 << u4_ldz) + u4_word - 1);\n//Inlined ih264d_uev\n\n            if(ui_sub_mb_mode > 12)\n                return ERROR_SUB_MB_TYPE;\n            else\n            {\n                UWORD8 u1_subMbPredMode = pu1_sub_mb_pred_modes[ui_sub_mb_mode];\n                u4_mb_mc_mode = (u4_mb_mc_mode << 8)\n                                | pu1_sub_mb_mc_mode[ui_sub_mb_mode];\n                u4_mb_pred_mode = (u4_mb_pred_mode << 8) | u1_subMbPredMode;\n                pi1_ref_idx[0][uc_i] = ((u1_subMbPredMode & PRED_L0) - 1) >> 1;\n                pi1_ref_idx[1][uc_i] = ((u1_subMbPredMode & PRED_L1) - 1) >> 1;\n                COPYTHECONTEXT(\"sub_mb_type\", u1_subMbPredMode);\n            }\n            /* Storing collocated Mb and SubMb mode information */\n            *pu1_col_info++ = ((PRED_8x8) << 6)\n                            | ((pu1_sub_mb_mc_mode[ui_sub_mb_mode] << 4));\n            if(ui_sub_mb_mode != B_DIRECT_8x8)\n            {\n                if(ui_sub_mb_mode > B_BI_8x8)\n                {\n                    ps_dec->s_high_profile.u1_no_submb_part_size_lt8x8_flag = 0;\n                }\n            }\n            else if(!ps_dec->s_high_profile.u1_direct_8x8_inference_flag)\n            {\n                ps_dec->s_high_profile.u1_no_submb_part_size_lt8x8_flag = 0;\n            }\n        }\n    }\n    else\n    {\n        UWORD8 u1_mb_pred_mode_idx = 5 + u1_mb_type;\n        UWORD8 u1_mb_pred_mode_part0 = pu1_mb_pred_modes[0][u1_mb_pred_mode_idx];\n        UWORD8 u1_mb_pred_mode_part1 = pu1_mb_pred_modes[1][u1_mb_pred_mode_idx];\n        u1_mb_mc_mode = ps_cur_mb_info->u1_mb_mc_mode;\n        u1_num_mb_part = pu1_num_mb_part[u1_mb_mc_mode];\n\n        pi1_ref_idx[0][0] = ((u1_mb_pred_mode_part0 & PRED_L0) - 1) >> 1;\n        pi1_ref_idx[1][0] = ((u1_mb_pred_mode_part0 & PRED_L1) - 1) >> 1;\n        pi1_ref_idx[0][1] = ((u1_mb_pred_mode_part1 & PRED_L0) - 1) >> 1;\n        pi1_ref_idx[1][1] = ((u1_mb_pred_mode_part1 & PRED_L1) - 1) >> 1;\n\n        u4_mb_pred_mode = (u1_mb_pred_mode_part0 << 8) | u1_mb_pred_mode_part1;\n        u4_mb_mc_mode = u1_mb_mc_mode | (u1_mb_mc_mode << 8);\n        u4_mb_mc_mode <<= 16;\n        u4_mb_pred_mode <<= 16;\n\n        /* Storing collocated Mb and SubMb mode information */\n        *pu1_col_info++ = (u1_mb_mc_mode << 6);\n        if(u1_mb_mc_mode)\n            *pu1_col_info++ = (u1_mb_mc_mode << 6);\n    }\n\n    {\n        UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n        UWORD8 uc_field = ps_cur_mb_info->u1_mb_field_decodingflag;\n        UWORD8 *pu1_num_ref_idx_lx_active =\n                        ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active;\n        const UWORD8 u1_mbaff_field = (u1_mbaff & uc_field);\n        UWORD8 u4_num_ref_idx_lx_active;\n\n        u4_num_ref_idx_lx_active = (pu1_num_ref_idx_lx_active[0]\n                        << u1_mbaff_field) - 1;\n\n        if(u4_num_ref_idx_lx_active)\n        {\n            if(1 == u4_num_ref_idx_lx_active)\n                ih264d_parse_bmb_ref_index_cavlc_range1(\n                                u1_num_mb_part, ps_bitstrm, pi1_ref_idx[0],\n                                u4_num_ref_idx_lx_active);\n            else\n            {\n                ret = ih264d_parse_bmb_ref_index_cavlc(u1_num_mb_part, ps_bitstrm,\n                                                 pi1_ref_idx[0],\n                                                 u4_num_ref_idx_lx_active);\n                if(ret != OK)\n                    return ret;\n            }\n        }\n\n        u4_num_ref_idx_lx_active = (pu1_num_ref_idx_lx_active[1]\n                        << u1_mbaff_field) - 1;\n\n        if(u4_num_ref_idx_lx_active)\n        {\n            if(1 == u4_num_ref_idx_lx_active)\n                ih264d_parse_bmb_ref_index_cavlc_range1(\n                                u1_num_mb_part, ps_bitstrm, pi1_ref_idx[1],\n                                u4_num_ref_idx_lx_active);\n            else\n            {\n                ret = ih264d_parse_bmb_ref_index_cavlc(u1_num_mb_part, ps_bitstrm,\n                                                 pi1_ref_idx[1],\n                                                 u4_num_ref_idx_lx_active);\n                if(ret != OK)\n                    return ret;\n            }\n        }\n    }\n\n    /* Read MotionVectors */\n    {\n        const UWORD8 * pu1_top_left_sub_mb_indx;\n\n        const UWORD8 * pu1_sub_mb_indx_mod =\n                        (const UWORD8 *)(gau1_ih264d_submb_indx_mod)\n                                        + (u1_sub_mb * 6);\n        const UWORD8 * pu1_sub_mb_partw = (const UWORD8 *)gau1_ih264d_submb_partw;\n        const UWORD8 * pu1_sub_mb_parth = (const UWORD8 *)gau1_ih264d_submb_parth;\n        const UWORD8 * pu1_num_sub_mb_part =\n                        (const UWORD8 *)gau1_ih264d_num_submb_part;\n        const UWORD8 * pu1_mb_partw = (const UWORD8 *)gau1_ih264d_mb_partw;\n        const UWORD8 * pu1_mb_parth = (const UWORD8 *)gau1_ih264d_mb_parth;\n        UWORD8 u1_p_idx = 0, u1_num_submb_part, uc_lx;\n        parse_part_params_t * ps_part;\n        mv_pred_t *ps_mv_start = ps_dec->ps_mv_cur + (u1_mb_num << 4);\n        UWORD8 u1_mb_part_wd, u1_mb_part_ht;\n\n        /* Initialisations */\n        ps_part = ps_dec->ps_part;\n        /* Default Initialization for Non subMb Case Mode */\n        u1_mb_part_wd = pu1_mb_partw[u1_mb_mc_mode];\n        u1_mb_part_ht = pu1_mb_parth[u1_mb_mc_mode];\n        u1_num_submb_part = 1;\n\n        /* Decoding the MV for the subMB */\n        for(uc_lx = 0; uc_lx < 2; uc_lx++)\n        {\n            UWORD8 u1_sub_mb_num = 0, u1_pred_mode, uc_i;\n            UWORD32 u4_mb_mc_mode_tmp = u4_mb_mc_mode;\n            UWORD32 u4_mb_pred_mode_tmp = u4_mb_pred_mode;\n            UWORD16 u2_sub_mb_num = 0x028A; // for sub mb case\n            UWORD8 u1_b2 = uc_lx << 1;\n            u1_pred_mode = (uc_lx) ? PRED_L1 : PRED_L0;\n            pu1_top_left_sub_mb_indx = pu1_sub_mb_indx_mod + (u1_mb_mc_mode << 1);\n\n            for(uc_i = 0; uc_i < u1_num_mb_part; uc_i++)\n            {\n                UWORD8 u1_mb_mc_mode, uc_j;\n                UWORD8 i1_pred = u4_mb_pred_mode_tmp >> 24;\n                u1_mb_mc_mode = u4_mb_mc_mode_tmp >> 24;\n                u4_mb_pred_mode_tmp <<= 8;\n                u4_mb_mc_mode_tmp <<= 8;\n                /* subMb prediction mode */\n                if(u1_sub_mb)\n                {\n\n                    u1_mb_part_wd = pu1_sub_mb_partw[u1_mb_mc_mode];\n                    u1_mb_part_ht = pu1_sub_mb_parth[u1_mb_mc_mode];\n                    u1_sub_mb_num = u2_sub_mb_num >> 12;\n                    u1_num_submb_part = pu1_num_sub_mb_part[u1_mb_mc_mode];\n                    pu1_top_left_sub_mb_indx = pu1_sub_mb_indx_mod\n                                    + (u1_mb_mc_mode << 1);\n                    u2_sub_mb_num <<= 4;\n                }\n                for(uc_j = 0; uc_j < u1_num_submb_part;\n                                uc_j++, pu1_top_left_sub_mb_indx++)\n                {\n                    mv_pred_t * ps_mv;\n                    u1_sub_mb_num = u1_sub_mb_num + *pu1_top_left_sub_mb_indx;\n                    ps_mv = ps_mv_start + u1_sub_mb_num;\n\n                    /* Storing Info for partitions, writing only once */\n                    if(uc_lx)\n                    {\n                        ps_part->u1_is_direct = (!i1_pred);\n                        ps_part->u1_pred_mode = i1_pred;\n                        ps_part->u1_sub_mb_num = u1_sub_mb_num;\n                        ps_part->u1_partheight = u1_mb_part_ht;\n                        ps_part->u1_partwidth = u1_mb_part_wd;\n                        /* Increment partition Index */\n                        u1_p_idx++;\n                        ps_part++;\n                    }\n\n                    if(i1_pred & u1_pred_mode)\n                    {\n                        WORD16 i2_mvx, i2_mvy;\n\n//inlining ih264d_sev\n                        {\n                            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n                            UWORD32 u4_word, u4_ldz, u4_abs_val;\n\n                            /***************************************************************/\n                            /* Find leading zeros in next 32 bits                          */\n                            /***************************************************************/\n                            NEXTBITS_32(u4_word, u4_bitstream_offset,\n                                        pu4_bitstrm_buf);\n                            u4_ldz = CLZ(u4_word);\n\n                            /* Flush the ps_bitstrm */\n                            u4_bitstream_offset += (u4_ldz + 1);\n\n                            /* Read the suffix from the ps_bitstrm */\n                            u4_word = 0;\n                            if(u4_ldz)\n                                GETBITS(u4_word, u4_bitstream_offset,\n                                        pu4_bitstrm_buf, u4_ldz);\n\n                            *pu4_bitstrm_ofst = u4_bitstream_offset;\n                            u4_abs_val = ((1 << u4_ldz) + u4_word) >> 1;\n\n                            if(u4_word & 0x1)\n                                i2_mvx = (-(WORD32)u4_abs_val);\n                            else\n                                i2_mvx = (u4_abs_val);\n                        }\n//inlinined ih264d_sev\n\n//inlining ih264d_sev\n                        {\n                            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n                            UWORD32 u4_word, u4_ldz, u4_abs_val;\n\n                            /***************************************************************/\n                            /* Find leading zeros in next 32 bits                          */\n                            /***************************************************************/\n                            NEXTBITS_32(u4_word, u4_bitstream_offset,\n                                        pu4_bitstrm_buf);\n                            u4_ldz = CLZ(u4_word);\n\n                            /* Flush the ps_bitstrm */\n                            u4_bitstream_offset += (u4_ldz + 1);\n\n                            /* Read the suffix from the ps_bitstrm */\n                            u4_word = 0;\n                            if(u4_ldz)\n                                GETBITS(u4_word, u4_bitstream_offset,\n                                        pu4_bitstrm_buf, u4_ldz);\n\n                            *pu4_bitstrm_ofst = u4_bitstream_offset;\n                            u4_abs_val = ((1 << u4_ldz) + u4_word) >> 1;\n\n                            if(u4_word & 0x1)\n                                i2_mvy = (-(WORD32)u4_abs_val);\n                            else\n                                i2_mvy = (u4_abs_val);\n                        }\n//inlinined ih264d_sev\n\n                        /* Storing Mv residuals */\n                        ps_mv->i2_mv[u1_b2] = i2_mvx;\n                        ps_mv->i2_mv[u1_b2 + 1] = i2_mvy;\n                    }\n                }\n            }\n        }\n        /* write back to the scratch partition info */\n        ps_dec->ps_part = ps_part;\n        ps_parse_mb_data->u1_num_part = u1_sub_mb ? u1_p_idx : u1_num_mb_part;\n\n    }\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ParseMb_SubMb_PredBCab\\endif\n *\n * \\brief\n *    Implements sub_mb_pred() of 7.3.5.2. & mb_pred() of 7.3.5.1\n *\n * \\return\n *    None.\n *\n **************************************************************************\n */\n\nWORD32 ih264d_parse_bmb_non_direct_cabac(dec_struct_t * ps_dec,\n                                       dec_mb_info_t * ps_cur_mb_info,\n                                       UWORD8 u1_mb_num,\n                                       UWORD8 u1_num_mbsNby2)\n{\n    /* Loads from ps_dec */\n    decoding_envirnoment_t * ps_cab_env = &ps_dec->s_cab_dec_env;\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n    ctxt_inc_mb_info_t *p_curr_ctxt = ps_dec->ps_curr_ctxt_mb_info;\n    parse_pmbarams_t * ps_parse_mb_data = ps_dec->ps_parse_mb_data\n                    + u1_num_mbsNby2;\n\n    /* table pointer loads */\n    const UWORD8 * pu1_sub_mb_pred_modes = (UWORD8 *)(gau1_ih264d_submb_pred_modes)\n                    + 4;\n    const UWORD8 (*pu1_mb_pred_modes)[32] =\n                    (const UWORD8 (*)[32])gau1_ih264d_mb_pred_modes;\n    const UWORD8 *pu1_num_mb_part = (const UWORD8 *)gau1_ih264d_num_mb_part;\n    const UWORD8 *pu1_sub_mb_mc_mode = (UWORD8 *)(gau1_ih264d_submb_mc_mode) + 4;\n\n    const UWORD8 u1_mb_type = ps_cur_mb_info->u1_mb_type;\n    UWORD8 * pu1_col_info = ps_parse_mb_data->u1_col_info;\n    WORD8 *pi1_ref_idx_l0 = &ps_parse_mb_data->i1_ref_idx[0][0];\n    WORD8 *pi1_ref_idx_l1 = &ps_parse_mb_data->i1_ref_idx[1][0];\n    UWORD8 u1_dec_ref_l0, u1_dec_ref_l1;\n\n    UWORD8 u1_num_mb_part, u1_mb_mc_mode, u1_sub_mb, u1_mbpred_mode = 5\n                    + u1_mb_type;\n    UWORD32 u4_mb_mc_mode = 0, u4_mb_pred_mode = 0;\n    WORD32 ret;\n\n    p_curr_ctxt->u1_mb_type = CAB_NON_BD16x16;\n    u1_sub_mb = !(u1_mb_type ^ B_8x8);\n\n    {\n        UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n        UWORD8 *pu1_num_ref_idx_lx_active =\n                        ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active;\n        UWORD8 uc_field = ps_cur_mb_info->u1_mb_field_decodingflag;\n        UWORD8 u1_mbaff_field = (u1_mbaff & uc_field);\n        u1_dec_ref_l0 = (pu1_num_ref_idx_lx_active[0] << u1_mbaff_field) - 1;\n        u1_dec_ref_l1 = (pu1_num_ref_idx_lx_active[1] << u1_mbaff_field) - 1;\n    }\n\n    if(u1_sub_mb)\n    {\n        const UWORD8 u1_colz = ((PRED_8x8) << 6);\n        UWORD8 uc_i;\n        u1_mb_mc_mode = 0;\n        u1_num_mb_part = 4;\n        /* Reading the subMB type */\n        for(uc_i = 0; uc_i < 4; uc_i++)\n        {\n            UWORD8 u1_sub_mb_mode, u1_subMbPredModes;\n            u1_sub_mb_mode = ih264d_parse_submb_type_cabac(\n                            1, ps_cab_env, ps_bitstrm,\n                            ps_dec->p_sub_mb_type_t);\n\n            if(u1_sub_mb_mode > 12)\n                return ERROR_SUB_MB_TYPE;\n\n            u1_subMbPredModes = pu1_sub_mb_pred_modes[u1_sub_mb_mode];\n            u4_mb_mc_mode = (u4_mb_mc_mode << 8) | pu1_sub_mb_mc_mode[u1_sub_mb_mode];\n            u4_mb_pred_mode = (u4_mb_pred_mode << 8) | u1_subMbPredModes;\n            *pi1_ref_idx_l0++ =\n                            (u1_subMbPredModes & PRED_L0) ? u1_dec_ref_l0 : -1;\n            *pi1_ref_idx_l1++ =\n                            (u1_subMbPredModes & PRED_L1) ? u1_dec_ref_l1 : -1;\n            COPYTHECONTEXT(\"sub_mb_type\", u1_sub_mb_mode);\n            /* Storing collocated Mb and SubMb mode information */\n            *pu1_col_info++ =\n                            (u1_colz | (pu1_sub_mb_mc_mode[u1_sub_mb_mode] << 4));\n            if(u1_sub_mb_mode != B_DIRECT_8x8)\n            {\n                if(u1_sub_mb_mode > B_BI_8x8)\n                {\n                    ps_dec->s_high_profile.u1_no_submb_part_size_lt8x8_flag = 0;\n                }\n            }\n            else if(!ps_dec->s_high_profile.u1_direct_8x8_inference_flag)\n            {\n                ps_dec->s_high_profile.u1_no_submb_part_size_lt8x8_flag = 0;\n            }\n        }\n        pi1_ref_idx_l0 -= 4;\n        pi1_ref_idx_l1 -= 4;\n    }\n    else\n    {\n        UWORD8 u1_mb_pred_mode_part0 = pu1_mb_pred_modes[0][u1_mbpred_mode];\n        UWORD8 u1_mb_pred_mode_part1 = pu1_mb_pred_modes[1][u1_mbpred_mode];\n        u1_mb_mc_mode = ps_cur_mb_info->u1_mb_mc_mode;\n        u1_num_mb_part = pu1_num_mb_part[u1_mb_mc_mode];\n        /* Storing collocated Mb and SubMb mode information */\n        *pu1_col_info++ = (u1_mb_mc_mode << 6);\n        if(u1_mb_mc_mode)\n            *pu1_col_info++ = (u1_mb_mc_mode << 6);\n        u4_mb_mc_mode = u1_mb_mc_mode | (u1_mb_mc_mode << 8);\n        u4_mb_mc_mode <<= 16;\n        u4_mb_pred_mode = ((u1_mb_pred_mode_part0 << 8) | u1_mb_pred_mode_part1) << 16;\n\n        *pi1_ref_idx_l0++ = (u1_mb_pred_mode_part0 & PRED_L0) ? u1_dec_ref_l0 : -1;\n        *pi1_ref_idx_l0-- = (u1_mb_pred_mode_part1 & PRED_L0) ? u1_dec_ref_l0 : -1;\n        *pi1_ref_idx_l1++ = (u1_mb_pred_mode_part0 & PRED_L1) ? u1_dec_ref_l1 : -1;\n        *pi1_ref_idx_l1-- = (u1_mb_pred_mode_part1 & PRED_L1) ? u1_dec_ref_l1 : -1;\n    }\n    {\n        WORD8 *pi1_lft_cxt = ps_dec->pi1_left_ref_idx_ctxt_inc;\n        WORD8 *pi1_top_cxt = p_curr_ctxt->i1_ref_idx;\n\n        ret = ih264d_parse_ref_idx_cabac(u1_num_mb_part, 0, u1_dec_ref_l0,\n                                   u1_mb_mc_mode, pi1_ref_idx_l0, pi1_lft_cxt,\n                                   pi1_top_cxt, ps_cab_env, ps_bitstrm,\n                                   ps_dec->p_ref_idx_t);\n        if(ret != OK)\n            return ret;\n\n        ret = ih264d_parse_ref_idx_cabac(u1_num_mb_part, 2, u1_dec_ref_l1,\n                                   u1_mb_mc_mode, pi1_ref_idx_l1, pi1_lft_cxt,\n                                   pi1_top_cxt, ps_cab_env, ps_bitstrm,\n                                   ps_dec->p_ref_idx_t);\n        if(ret != OK)\n            return ret;\n    }\n    /* Read MotionVectors */\n    {\n        const UWORD8 *pu1_top_left_sub_mb_indx;\n        UWORD8 uc_j, uc_lx;\n        UWORD8 u1_mb_part_wd, u1_mb_part_ht;\n\n        const UWORD8 *pu1_sub_mb_indx_mod =\n                        (const UWORD8 *)gau1_ih264d_submb_indx_mod\n                                        + (u1_sub_mb * 6);\n        const UWORD8 *pu1_sub_mb_partw = (const UWORD8 *)gau1_ih264d_submb_partw;\n        const UWORD8 *pu1_sub_mb_parth = (const UWORD8 *)gau1_ih264d_submb_parth;\n        const UWORD8 *pu1_num_sub_mb_part =\n                        (const UWORD8 *)gau1_ih264d_num_submb_part;\n        const UWORD8 *pu1_mb_partw = (const UWORD8 *)gau1_ih264d_mb_partw;\n        const UWORD8 *pu1_mb_parth = (const UWORD8 *)gau1_ih264d_mb_parth;\n\n        UWORD8 u1_p_idx = 0;\n        UWORD8 u1_num_submb_part;\n        parse_part_params_t *ps_part;\n        /* Initialisations */\n        mv_pred_t *ps_mv_start = ps_dec->ps_mv_cur + (u1_mb_num << 4);\n        ps_part = ps_dec->ps_part;\n\n        /* Default initialization for non subMb case */\n        u1_mb_part_wd = pu1_mb_partw[u1_mb_mc_mode];\n        u1_mb_part_ht = pu1_mb_parth[u1_mb_mc_mode];\n        u1_num_submb_part = 1;\n\n        /* Decoding the MV for the subMB */\n        for(uc_lx = 0; uc_lx < 2; uc_lx++)\n        {\n            UWORD8 u1_sub_mb_num = 0;\n            UWORD32 u4_mb_pred_mode_tmp = u4_mb_pred_mode;\n            UWORD32 u4_mb_mc_mode_tmp = u4_mb_mc_mode;\n            UWORD8 u1_mb_mc_mode_1, u1_pred_mode, uc_i;\n            UWORD16 u2_sub_mb_num = 0x028A;\n            UWORD8 u1_b2 = uc_lx << 1;\n            u1_pred_mode = (uc_lx) ? PRED_L1 : PRED_L0;\n            /* Default for Cabac */\n            pu1_top_left_sub_mb_indx = pu1_sub_mb_indx_mod + (u1_mb_mc_mode << 1);\n            for(uc_i = 0; uc_i < u1_num_mb_part; uc_i++)\n            {\n\n                WORD8 i1_pred = (UWORD8)(u4_mb_pred_mode_tmp >> 24);\n                u1_mb_mc_mode_1 = (UWORD8)(u4_mb_mc_mode_tmp >> 24);\n                u4_mb_pred_mode_tmp <<= 8;\n                u4_mb_mc_mode_tmp <<= 8;\n\n                /* subMb prediction mode */\n                if(u1_sub_mb)\n                {\n                    u1_mb_part_wd = pu1_sub_mb_partw[u1_mb_mc_mode_1];\n                    u1_mb_part_ht = pu1_sub_mb_parth[u1_mb_mc_mode_1];\n                    u1_sub_mb_num = u2_sub_mb_num >> 12;\n                    pu1_top_left_sub_mb_indx = pu1_sub_mb_indx_mod + (u1_mb_mc_mode_1 << 1);\n                    u1_num_submb_part = pu1_num_sub_mb_part[u1_mb_mc_mode_1];\n                    u2_sub_mb_num = u2_sub_mb_num << 4;\n                }\n\n                for(uc_j = 0; uc_j < u1_num_submb_part;\n                                uc_j++, pu1_top_left_sub_mb_indx++)\n                {\n                    mv_pred_t *ps_mv;\n                    u1_sub_mb_num = u1_sub_mb_num + *pu1_top_left_sub_mb_indx;\n                    ps_mv = ps_mv_start + u1_sub_mb_num;\n\n                    /* Storing Info for partitions, writing only once */\n                    if(uc_lx)\n                    {\n                        ps_part->u1_is_direct = (!i1_pred);\n                        ps_part->u1_pred_mode = i1_pred;\n                        ps_part->u1_sub_mb_num = u1_sub_mb_num;\n                        ps_part->u1_partheight = u1_mb_part_ht;\n                        ps_part->u1_partwidth = u1_mb_part_wd;\n\n                        /* Increment partition Index */\n                        u1_p_idx++;\n                        ps_part++;\n                    }\n\n                    ih264d_get_mvd_cabac(u1_sub_mb_num, u1_b2, u1_mb_part_wd,\n                                         u1_mb_part_ht,\n                                         (UWORD8)(i1_pred & u1_pred_mode), ps_dec,\n                                         ps_mv);\n                }\n            }\n        }\n        /* write back to the scratch partition info */\n\n        ps_dec->ps_part = ps_part;\n        ps_parse_mb_data->u1_num_part = u1_sub_mb ? u1_p_idx : u1_num_mb_part;\n\n    }\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_bmb_cabac \\endif\n *\n * \\brief\n *    This function parses CABAC syntax of a B MB.\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_bmb_cabac(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_num,\n                              UWORD8 u1_num_mbsNby2)\n{\n    UWORD8 u1_cbp;\n    deblk_mb_t * ps_cur_deblk_mb = ps_dec->ps_deblk_mbn + u1_mb_num;\n    const UWORD8 *puc_mb_mc_mode = (const UWORD8 *)gau1_ih264d_mb_mc_mode;\n    UWORD8 u1_mb_type = ps_cur_mb_info->u1_mb_type;\n    ctxt_inc_mb_info_t *p_curr_ctxt = ps_dec->ps_curr_ctxt_mb_info;\n\n    WORD32 ret;\n    UWORD8 u1_Bdirect_tranform_read = 1;\n    ps_dec->s_high_profile.u1_no_submb_part_size_lt8x8_flag = 1;\n\n    ps_cur_mb_info->u1_mb_mc_mode = puc_mb_mc_mode[5 + u1_mb_type];\n\n    ps_cur_mb_info->u1_yuv_dc_block_flag = 0;\n\n    ps_cur_deblk_mb->u1_mb_type |= D_B_SLICE;\n    if(u1_mb_type != B_DIRECT)\n    {\n        ret = ih264d_parse_bmb_non_direct_cabac(ps_dec, ps_cur_mb_info, u1_mb_num,\n                                          u1_num_mbsNby2);\n        if(ret != OK)\n            return ret;\n    }\n    else\n    {\n\n        /************ STORING PARTITION INFO ***********/\n        parse_part_params_t * ps_part_info;\n        ps_part_info = ps_dec->ps_part;\n        ps_part_info->u1_is_direct = PART_DIRECT_16x16;\n        ps_part_info->u1_sub_mb_num = 0;\n        ps_dec->ps_part++;\n        p_curr_ctxt->u1_mb_type = CAB_BD16x16;\n\n        MEMSET_16BYTES(&ps_dec->pu1_left_mv_ctxt_inc[0][0], 0);\n        memset(ps_dec->pi1_left_ref_idx_ctxt_inc, 0, 4);\n        MEMSET_16BYTES(p_curr_ctxt->u1_mv, 0);\n        memset(p_curr_ctxt->i1_ref_idx, 0, 4);\n\n        /* check whether transform8x8 u4_flag to be read or not */\n        u1_Bdirect_tranform_read =\n                        ps_dec->s_high_profile.u1_direct_8x8_inference_flag;\n    }\n\n    /* Read the Coded block pattern */\n    u1_cbp = (WORD8)ih264d_parse_ctx_cbp_cabac(ps_dec);\n    p_curr_ctxt->u1_cbp = u1_cbp;\n    ps_cur_mb_info->u1_cbp = u1_cbp;\n\n    if(u1_cbp > 47)\n        return ERROR_CBP;\n\n    COPYTHECONTEXT(\"coded_block_pattern\", u1_cbp);\n\n    ps_cur_mb_info->u1_tran_form8x8 = 0;\n    ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n\n    if((ps_dec->s_high_profile.u1_transform8x8_present) && (u1_cbp & (0xf))\n                    && (ps_dec->s_high_profile.u1_no_submb_part_size_lt8x8_flag)\n                    && (u1_Bdirect_tranform_read))\n    {\n        ps_cur_mb_info->u1_tran_form8x8 = ih264d_parse_transform8x8flag_cabac(\n                        ps_dec, ps_cur_mb_info);\n        COPYTHECONTEXT(\"transform_size_8x8_flag\", ps_cur_mb_info->u1_tran_form8x8);\n\n        ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = ps_cur_mb_info->u1_tran_form8x8;\n        p_curr_ctxt->u1_transform8x8_ctxt = ps_cur_mb_info->u1_tran_form8x8;\n    }\n    else\n    {\n        p_curr_ctxt->u1_transform8x8_ctxt = 0;\n    }\n\n    p_curr_ctxt->u1_intra_chroma_pred_mode = 0;\n    p_curr_ctxt->u1_yuv_dc_csbp &= 0xFE;\n    ps_dec->pu1_left_yuv_dc_csbp[0] &= 0x6;\n\n    /* Read mb_qp_delta */\n    if(u1_cbp)\n    {\n        WORD8 c_temp;\n        ret = ih264d_parse_mb_qp_delta_cabac(ps_dec, &c_temp);\n        if(ret != OK)\n            return ret;\n        COPYTHECONTEXT(\"mb_qp_delta\", c_temp);\n        if(c_temp)\n        {\n            ret = ih264d_update_qp(ps_dec, c_temp);\n            if(ret != OK)\n                return ret;\n        }\n    }\n    else\n        ps_dec->i1_prev_mb_qp_delta = 0;\n\n    ih264d_parse_residual4x4_cabac(ps_dec, ps_cur_mb_info, 0);\n    if(EXCEED_OFFSET(ps_dec->ps_bitstrm))\n        return ERROR_EOB_TERMINATE_T;\n    return OK;\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_bmb_cavlc \\endif\n *\n * \\brief\n *    This function parses CAVLC syntax of a B MB.\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_bmb_cavlc(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_num,\n                              UWORD8 u1_num_mbsNby2)\n{\n    UWORD32 u4_cbp;\n    deblk_mb_t * ps_cur_deblk_mb = ps_dec->ps_deblk_mbn + u1_mb_num;\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 * pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    const UWORD8 *puc_mb_mc_mode = (const UWORD8 *)gau1_ih264d_mb_mc_mode;\n    UWORD8 u1_mb_type = ps_cur_mb_info->u1_mb_type;\n\n    WORD32 ret;\n    UWORD8 u1_Bdirect_tranform_read = 1;\n    ps_dec->s_high_profile.u1_no_submb_part_size_lt8x8_flag = 1;\n    ps_cur_mb_info->u1_tran_form8x8 = 0;\n    ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n\n    ps_cur_mb_info->u1_yuv_dc_block_flag = 0;\n\n    ps_cur_mb_info->u1_mb_mc_mode = puc_mb_mc_mode[5 + u1_mb_type];\n\n    ps_cur_deblk_mb->u1_mb_type |= D_B_SLICE;\n    if(u1_mb_type != B_DIRECT)\n    {\n        ret = ih264d_parse_bmb_non_direct_cavlc(ps_dec, ps_cur_mb_info, u1_mb_num,\n                                          u1_num_mbsNby2);\n        if(ret != OK)\n            return ret;\n    }\n    else\n    {\n        /************ STORING PARTITION INFO ***********/\n        parse_part_params_t * ps_part_info;\n        ps_part_info = ps_dec->ps_part;\n        ps_part_info->u1_is_direct = PART_DIRECT_16x16;\n        ps_part_info->u1_sub_mb_num = 0;\n        ps_dec->ps_part++;\n        /* check whether transform8x8 u4_flag to be read or not */\n        u1_Bdirect_tranform_read =\n                        ps_dec->s_high_profile.u1_direct_8x8_inference_flag;\n    }\n\n    /* Read the Coded block pattern */\n    {\n        const UWORD8 * puc_CbpInter = gau1_ih264d_cbp_inter;\n//Inlined ih264d_uev\n        UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n        UWORD32 u4_word, u4_ldz;\n\n        /***************************************************************/\n        /* Find leading zeros in next 32 bits                          */\n        /***************************************************************/\n        NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n        u4_ldz = CLZ(u4_word);\n        /* Flush the ps_bitstrm */\n        u4_bitstream_offset += (u4_ldz + 1);\n        /* Read the suffix from the ps_bitstrm */\n        u4_word = 0;\n        if(u4_ldz)\n            GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf, u4_ldz);\n        *pu4_bitstrm_ofst = u4_bitstream_offset;\n        u4_cbp = ((1 << u4_ldz) + u4_word - 1);\n//Inlined ih264d_uev\n        if(u4_cbp > 47)\n            return ERROR_CBP;\n        u4_cbp = puc_CbpInter[u4_cbp];\n\n        if((ps_dec->s_high_profile.u1_transform8x8_present) && (u4_cbp & (0xf))\n                        && (ps_dec->s_high_profile.u1_no_submb_part_size_lt8x8_flag)\n                        && (u1_Bdirect_tranform_read))\n        {\n            ps_cur_mb_info->u1_tran_form8x8 = ih264d_get_bit_h264(ps_bitstrm);\n            COPYTHECONTEXT(\"transform_size_8x8_flag\", ps_cur_mb_info->u1_tran_form8x8);\n            ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = ps_cur_mb_info->u1_tran_form8x8;\n        }\n\n    }\n\n    COPYTHECONTEXT(\"coded_block_pattern\", u4_cbp);\n    ps_cur_mb_info->u1_cbp = u4_cbp;\n\n    /* Read mb_qp_delta */\n    if(u4_cbp)\n    {\n        WORD32 i_temp;\n//inlining ih264d_sev\n\n        UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n        UWORD32 u4_word, u4_ldz, u4_abs_val;\n\n        /***************************************************************/\n        /* Find leading zeros in next 32 bits                          */\n        /***************************************************************/\n        NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n        u4_ldz = CLZ(u4_word);\n\n        /* Flush the ps_bitstrm */\n        u4_bitstream_offset += (u4_ldz + 1);\n\n        /* Read the suffix from the ps_bitstrm */\n        u4_word = 0;\n        if(u4_ldz)\n            GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf, u4_ldz);\n\n        *pu4_bitstrm_ofst = u4_bitstream_offset;\n        u4_abs_val = ((1 << u4_ldz) + u4_word) >> 1;\n\n        if(u4_word & 0x1)\n            i_temp = (-(WORD32)u4_abs_val);\n        else\n            i_temp = (u4_abs_val);\n\n        if(i_temp < -26 || i_temp > 25)\n            return ERROR_INV_RANGE_QP_T;\n//inlinined ih264d_sev\n        COPYTHECONTEXT(\"mb_qp_delta\", i_temp);\n        if(i_temp)\n        {\n            ret = ih264d_update_qp(ps_dec, (WORD8)i_temp);\n            if(ret != OK)\n                return ret;\n        }\n\n        ret = ih264d_parse_residual4x4_cavlc(ps_dec, ps_cur_mb_info, 0);\n        if(ret != OK)\n            return ret;\n        if(EXCEED_OFFSET(ps_bitstrm))\n            return ERROR_EOB_TERMINATE_T;\n    }\n    else\n    {\n        ps_dec->i1_prev_mb_qp_delta = 0;\n        ih264d_update_nnz_for_skipmb(ps_dec, ps_cur_mb_info, CAVLC);\n    }\n\n    return OK;\n}\n\nWORD32 ih264d_mv_pred_ref_tfr_nby2_bmb(dec_struct_t * ps_dec,\n                                     UWORD8 u1_mb_idx,\n                                     UWORD8 u1_num_mbs)\n{\n    parse_pmbarams_t * ps_mb_part_info;\n    parse_part_params_t * ps_part;\n    mv_pred_t *ps_mv_nmb, *ps_mv_nmb_start, *ps_mv_ntop, *ps_mv_ntop_start;\n    pic_buffer_t * ps_ref_frame;\n    UWORD8 u1_direct_mode_width;\n    UWORD8 i, j;\n    dec_mb_info_t * ps_cur_mb_info;\n    const UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    UWORD8 u1_field;\n    WORD32 ret = 0;\n\n    ps_dec->i4_submb_ofst -= (u1_num_mbs - u1_mb_idx) << 4;\n    ps_mb_part_info = ps_dec->ps_parse_mb_data;\n    ps_part = ps_dec->ps_parse_part_params;\n\n    /* N/2 Mb MvPred and Transfer Setup Loop */\n    for(i = u1_mb_idx; i < u1_num_mbs; i++, ps_mb_part_info++)\n    {\n        UWORD8 u1_colz = 0;\n        ps_dec->i4_submb_ofst += SUB_BLK_SIZE;\n        /* Restore the slice scratch MbX and MbY context */\n        ps_cur_mb_info = ps_dec->ps_nmb_info + i;\n\n\n        u1_field = ps_cur_mb_info->u1_mb_field_decodingflag;\n\n        ps_mv_nmb_start = ps_dec->ps_mv_cur + (i << 4);\n        ps_dec->u2_mbx = ps_cur_mb_info->u2_mbx;\n        ps_dec->u2_mby = ps_cur_mb_info->u2_mby;\n        ps_dec->u1_currB_type = 0;\n        ps_dec->u2_mv_2mb[i & 0x1] = 0;\n\n        /* Look for MV Prediction and Reference Transfer in Non-I Mbs */\n        if(!ps_mb_part_info->u1_isI_mb)\n        {\n            UWORD8 u1_blk_no;\n            WORD16 i1_ref_idx, i1_ref_idx1;\n            UWORD8 u1_pred_mode;\n            UWORD8 u1_sub_mb_x, u1_sub_mb_y, u1_sub_mb_num;\n            UWORD8 u1_lx, u1_lx_start, u1_lxend, u1_tmp_lx;\n            UWORD8 u1_num_part, u1_num_ref, u1_wd, u1_ht;\n            UWORD32 *pu4_wt_offst;\n            UWORD8 u1_scale_ref, u4_bot_mb;\n            deblk_mb_t * ps_cur_deblk_mb = ps_dec->ps_deblk_mbn + i;\n            WORD8 (*pi1_ref_idx)[MAX_REFIDX_INFO_PER_MB] =\n                            ps_mb_part_info->i1_ref_idx;\n            WORD8 *pi1_ref_idx0 = pi1_ref_idx[0],\n                            *pi1_ref_idx1 = pi1_ref_idx[1];\n            UWORD32 **ppu4_wt_ofst = ps_mb_part_info->pu4_wt_offst;\n\n            /* MB Level initialisations */\n            ps_dec->u4_num_pmbair = i >> u1_mbaff;\n            ps_dec->u1_mb_idx_mv = i;\n\n            /* CHANGED CODE */\n            ps_mv_ntop_start = ps_mv_nmb_start\n                            - (ps_dec->u2_frm_wd_in_mbs << (4 + u1_mbaff)) + 12;\n\n            u1_num_part = ps_mb_part_info->u1_num_part;\n            ps_cur_deblk_mb->u1_mb_type |= (u1_num_part > 1) << 1;\n            u1_direct_mode_width = (1 == ps_mb_part_info->u1_num_part) ? 16 : 8;\n\n\n            ps_cur_mb_info->u4_pred_info_pkd_idx = ps_dec->u4_pred_info_pkd_idx;\n            ps_cur_mb_info->u1_num_pred_parts = 0;\n\n            /****************************************************/\n            /* weighted u4_ofst pointer calculations, this loop  */\n            /* runs maximum 4 times, even in direct cases       */\n            /****************************************************/\n            u1_scale_ref = u1_mbaff & ps_cur_mb_info->u1_mb_field_decodingflag;\n            u4_bot_mb = 1 - ps_cur_mb_info->u1_topmb;\n            if(ps_dec->ps_cur_pps->u1_wted_bipred_idc)\n            {\n                u1_num_ref = MIN(u1_num_part, 4);\n                if(PART_DIRECT_16x16 != ps_part->u1_is_direct)\n                {\n                    for(u1_blk_no = 0; u1_blk_no < u1_num_ref; u1_blk_no++)\n                    {\n                        i1_ref_idx = MAX(pi1_ref_idx0[u1_blk_no], 0);\n                        if(u1_scale_ref)\n                            i1_ref_idx >>= 1;\n                        i1_ref_idx *=\n                                        ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1];\n                        if(u1_scale_ref)\n                            i1_ref_idx +=\n                                            (MAX(pi1_ref_idx1[u1_blk_no], 0)\n                                                            >> 1);\n                        else\n                            i1_ref_idx += MAX(pi1_ref_idx1[u1_blk_no], 0);\n                        pu4_wt_offst = (UWORD32*)&ps_dec->pu4_wt_ofsts[2\n                                        * X3(i1_ref_idx)];\n\n                        if(pi1_ref_idx0[u1_blk_no] < 0)\n                            pu4_wt_offst += 1;\n\n                        ppu4_wt_ofst[u1_blk_no] = pu4_wt_offst;\n                        if(u1_scale_ref\n                                        && (ps_dec->ps_cur_pps->u1_wted_bipred_idc\n                                                        == 2))\n                        {\n                            i1_ref_idx = MAX(pi1_ref_idx0[u1_blk_no], 0);\n                            i1_ref_idx *=\n                                            (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1]\n                                                            << 1);\n                            i1_ref_idx += MAX(pi1_ref_idx1[u1_blk_no], 0);\n                            if(u4_bot_mb)\n                            {\n                                i1_ref_idx +=\n                                                (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0]\n                                                                << 1)\n                                                                * (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1]\n                                                                                << 1);\n                            }\n                            pu4_wt_offst = (UWORD32*)&ps_dec->pu4_mbaff_wt_mat[2\n                                            * X3(i1_ref_idx)];\n                            ppu4_wt_ofst[u1_blk_no] = pu4_wt_offst;\n                        }\n                    }\n                }\n            }\n\n            /**************************************************/\n            /* Loop on Partitions                             */\n            /* direct mode is reflected as a single partition */\n            /**************************************************/\n            for(j = 0; j < u1_num_part; j++, ps_part++)\n            {\n                u1_sub_mb_num = ps_part->u1_sub_mb_num;\n                ps_dec->u1_sub_mb_num = u1_sub_mb_num;\n\n                if(PART_NOT_DIRECT != ps_part->u1_is_direct)\n                {\n                    /**************************************************/\n                    /* Direct Mode, Call DecodeSpatial/TemporalDirect */\n                    /* only (those will in turn call FormMbPartInfo)  */\n                    /**************************************************/\n                    ret = ps_dec->ps_cur_slice->pf_decodeDirect(ps_dec,\n                                                                u1_direct_mode_width,\n                                                                ps_cur_mb_info, i);\n                    if(ret != OK)\n                        return ret;\n                    ps_cur_deblk_mb->u1_mb_type |= (ps_dec->u1_currB_type << 1);\n\n                }\n                else\n                {\n                    mv_pred_t s_mvPred;\n                    /**************************************************/\n                    /* Non Direct Mode, Call Motion Vector Predictor  */\n                    /* and FormMbpartInfo                             */\n                    /**************************************************/\n                    u1_sub_mb_x = u1_sub_mb_num & 0x03;\n                    u1_sub_mb_y = u1_sub_mb_num >> 2;\n                    u1_blk_no =\n                                    (u1_num_part < 4) ?\n                                                    j :\n                                                    (((u1_sub_mb_y >> 1) << 1)\n                                                                    + (u1_sub_mb_x\n                                                                                    >> 1));\n\n                    ps_mv_ntop = ps_mv_ntop_start + u1_sub_mb_x;\n                    ps_mv_nmb = ps_mv_nmb_start + u1_sub_mb_num;\n\n                    u1_pred_mode = ps_part->u1_pred_mode;\n                    u1_wd = ps_part->u1_partwidth;\n                    u1_ht = ps_part->u1_partheight;\n\n                    u1_lx_start = 0;\n                    u1_lxend = 2;\n                    if( PRED_L0 == u1_pred_mode)\n                    {\n                        s_mvPred.i2_mv[2] = 0;\n                        s_mvPred.i2_mv[3] = 0;\n                        u1_lxend = 1;\n                    }\n                    if( PRED_L1 == u1_pred_mode)\n                    {\n                        s_mvPred.i2_mv[0] = 0;\n                        s_mvPred.i2_mv[1] = 0;\n                        u1_lx_start = 1;\n                    }\n\n                    /* Populate the colpic info and reference frames */\n                    s_mvPred.i1_ref_frame[0] = pi1_ref_idx0[u1_blk_no];\n                    s_mvPred.i1_ref_frame[1] = pi1_ref_idx1[u1_blk_no];\n\n                    ps_dec->pf_mvpred(ps_dec, ps_cur_mb_info, ps_mv_nmb, ps_mv_ntop,\n                                      &s_mvPred, u1_sub_mb_num, u1_wd,\n                                      u1_lx_start, u1_lxend,\n                                      ps_cur_mb_info->u1_mb_mc_mode);\n\n                    /**********************************************************/\n                    /* Loop on number of predictors, 1 Each for Forw Backw    */\n                    /* Loop 2 times for BiDirect mode                         */\n                    /**********************************************************/\n                    for(u1_lx = u1_lx_start; u1_lx < u1_lxend; u1_lx++)\n                    {\n                        WORD16 i2_mv_x, i2_mv_y;\n\n                        /********************************************************/\n                        /* Predict Mv                                           */\n                        /* Add Mv Residuals and store back                      */\n                        /********************************************************/\n                        i1_ref_idx = s_mvPred.i1_ref_frame[u1_lx];\n                        u1_tmp_lx = (u1_lx << 1);\n\n                        i2_mv_x = ps_mv_nmb->i2_mv[u1_tmp_lx];\n                        i2_mv_y = ps_mv_nmb->i2_mv[u1_tmp_lx + 1];\n\n                        i2_mv_x += s_mvPred.i2_mv[u1_tmp_lx];\n                        i2_mv_y += s_mvPred.i2_mv[u1_tmp_lx + 1];\n                        s_mvPred.i2_mv[u1_tmp_lx] = i2_mv_x;\n                        s_mvPred.i2_mv[u1_tmp_lx + 1] = i2_mv_y;\n\n                        /********************************************************/\n                        /* Transfer setup call                                  */\n                        /* convert RefIdx if it is MbAff                        */\n                        /* Pass Weight Offset and refFrame                      */\n                        /********************************************************/\n                        i1_ref_idx1 = i1_ref_idx >> u1_scale_ref;\n                        if(u1_scale_ref && ((i1_ref_idx & 0x01) != u4_bot_mb))\n                            i1_ref_idx1 += MAX_REF_BUFS;\n                        ps_ref_frame =\n                                        ps_dec->ps_ref_pic_buf_lx[u1_lx][i1_ref_idx1];\n\n                        /* Storing Colocated-Zero u4_flag */\n                        if(u1_lx == u1_lx_start)\n                        {\n                            /* Fill colocated info in MvPred structure */\n                            s_mvPred.u1_col_ref_pic_idx =\n                                            ps_ref_frame->u1_mv_buf_id;\n                            s_mvPred.u1_pic_type = ps_ref_frame->u1_pic_type;\n\n                            /* Calculating colocated zero information */\n                            u1_colz =\n                                            (u1_field << 1)\n                                                            | ((i1_ref_idx == 0)\n                                                                            && (ABS(i2_mv_x)\n                                                                                            <= 1)\n                                                                            && (ABS(i2_mv_y)\n                                                                                            <= 1));\n                            u1_colz |= ps_mb_part_info->u1_col_info[u1_blk_no];\n                        }\n\n                        pu4_wt_offst = ppu4_wt_ofst[u1_blk_no];\n                        {\n                            pred_info_pkd_t *ps_pred_pkd;\n                           WORD16 i2_mv[2];\n\n                           i2_mv[0] = i2_mv_x;\n                           i2_mv[1] = i2_mv_y;\n\n                           ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n                        ih264d_fill_pred_info(i2_mv,u1_wd,u1_ht,u1_sub_mb_num,u1_pred_mode,\n                                        ps_pred_pkd,ps_ref_frame->u1_pic_buf_id,i1_ref_idx,pu4_wt_offst,\n                                        ps_ref_frame->u1_pic_type);\n                        ps_dec->u4_pred_info_pkd_idx++;\n                        ps_cur_mb_info->u1_num_pred_parts++;\n\n\n                        }\n\n                    }\n                    ih264d_rep_mv_colz(ps_dec, &s_mvPred, ps_mv_nmb,\n                                       u1_sub_mb_num, u1_colz, u1_ht,\n                                       u1_wd);\n                }\n            }\n\n        }\n        else\n        {\n            /* Set zero values in case of Intra Mbs */\n            mv_pred_t s_mvPred =\n                {\n                    { 0, 0, 0, 0 },\n                      { -1, -1 }, 0, 0};\n            /* Storing colocated zero information */\n            ih264d_rep_mv_colz(ps_dec, &s_mvPred, ps_mv_nmb_start, 0,\n                               (UWORD8)(u1_field << 1), 4, 4);\n        }\n\n        /*if num _cores is set to 3 ,compute bs will be done in another thread*/\n        if(ps_dec->u4_num_cores < 3)\n        {\n            if(ps_dec->u4_app_disable_deblk_frm == 0)\n                ps_dec->pf_compute_bs(ps_dec, ps_cur_mb_info,\n                                     (UWORD16)(i >> u1_mbaff));\n        }\n    }\n    return OK;\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_get_implicit_weights \\endif\n *\n * \\brief\n *    Calculates Implicit Weights.\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\nvoid ih264d_get_implicit_weights(dec_struct_t *ps_dec)\n{\n    UWORD32 *pu4_iwt_ofst;\n    UWORD8 i, j;\n    struct pic_buffer_t *ps_pic_buff0, *ps_pic_buff1;\n    WORD16 i2_dist_scale_factor;\n    WORD16 i2_tb, i2_td, i2_tx;\n    WORD64 i8_tb, i8_td;\n    WORD32 i4_poc0, i4_poc1;\n    UWORD32 ui_temp0, ui_temp1;\n    UWORD8 uc_num_ref_idx_l0_active, uc_num_ref_idx_l1_active;\n\n    pu4_iwt_ofst = ps_dec->pu4_wts_ofsts_mat;\n    uc_num_ref_idx_l0_active =\n                    ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0];\n    uc_num_ref_idx_l1_active =\n                    ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1];\n\n    for(i = 0; i < uc_num_ref_idx_l0_active; i++)\n    {\n        ps_pic_buff0 = ps_dec->ps_ref_pic_buf_lx[0][i];\n        i4_poc0 = ps_pic_buff0->i4_avg_poc;\n        for(j = 0; j < uc_num_ref_idx_l1_active; j++)\n        {\n            ps_pic_buff1 = ps_dec->ps_ref_pic_buf_lx[1][j];\n            i4_poc1 = ps_pic_buff1->i4_avg_poc;\n\n            if(i4_poc1 != i4_poc0)\n            {\n                i8_tb = (WORD64)ps_dec->ps_cur_pic->i4_poc - i4_poc0;\n                i2_tb = CLIP_S8(i8_tb);\n                i8_td = (WORD64)i4_poc1 - i4_poc0;\n                i2_td = CLIP_S8(i8_td);\n                i2_tx = (16384 + ABS(SIGN_POW2_DIV(i2_td, 1))) / i2_td;\n                i2_dist_scale_factor = CLIP_S11(\n                                            (((i2_tb * i2_tx) + 32) >> 6));\n\n                if(/*((u4_poc1 - u4_poc0) == 0) ||*/\n                (!(ps_pic_buff1->u1_is_short && ps_pic_buff0->u1_is_short))\n                                || ((i2_dist_scale_factor >> 2) < -64)\n                                || ((i2_dist_scale_factor >> 2) > 128))\n                {\n                    /* same for forward and backward, wt=32 and Offset = 0 */\n                    ui_temp0 = 0x00000020;\n                    ui_temp1 = 0x00000020;\n                }\n                else\n                {\n                    ui_temp0 = 64 - (i2_dist_scale_factor >> 2);\n                    ui_temp1 = (i2_dist_scale_factor >> 2);\n                }\n            }\n            else\n            {\n                ui_temp0 = 0x00000020;\n                ui_temp1 = 0x00000020;\n            }\n            pu4_iwt_ofst[0] = pu4_iwt_ofst[2] = pu4_iwt_ofst[4] = ui_temp0;\n            pu4_iwt_ofst[1] = pu4_iwt_ofst[3] = pu4_iwt_ofst[5] = ui_temp1;\n            pu4_iwt_ofst += 6;\n        }\n    }\n    if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag)\n    {\n        UWORD8 k;\n        WORD32 i4_cur_poc = ps_dec->ps_cur_pic->i4_top_field_order_cnt;\n        UWORD32* pu4_wt_mat = ps_dec->pu4_mbaff_wt_mat;\n        /* Form the Implicit Weighted prediction matrix for field MBs also */\n        for(k = 0; k < 2; k++)\n        {\n            for(i = 0; i < (uc_num_ref_idx_l0_active << 1); i++)\n            {\n                UWORD16 u2_l0_idx;\n\n                /*u2_l0_idx = (i >= uc_num_ref_idx_l0_active)\n                 ?(MAX_REF_BUFS + i - uc_num_ref_idx_l0_active) : (i) ;*/\n\n                u2_l0_idx = i >> 1;\n                if((i & 0x01) != k)\n                {\n                    u2_l0_idx += MAX_REF_BUFS;\n                }\n                ps_pic_buff0 = ps_dec->ps_ref_pic_buf_lx[0][u2_l0_idx];\n                i4_poc0 = ps_pic_buff0->i4_poc;\n                for(j = 0; j < (uc_num_ref_idx_l1_active << 1); j++)\n                {\n                    UWORD16 u2_l1_idx;\n                    /*u2_l1_idx = (j >= uc_num_ref_idx_l1_active)\n                     ? (MAX_REF_BUFS + j - uc_num_ref_idx_l1_active ) : (j) ;*/\n\n                    u2_l1_idx = j >> 1;\n                    if((j & 0x01) != k)\n                    {\n                        u2_l1_idx += MAX_REF_BUFS;\n                    }\n                    ps_pic_buff1 = ps_dec->ps_ref_pic_buf_lx[1][u2_l1_idx];\n                    i4_poc1 = ps_pic_buff1->i4_poc;\n                    if(i4_poc1 != i4_poc0)\n                    {\n                        i8_tb = (WORD64)i4_cur_poc - i4_poc0;\n                        i2_tb = CLIP_S8(i8_tb);\n                        i8_td = (WORD64)i4_poc1 - i4_poc0;\n                        i2_td = CLIP_S8(i8_td);\n                        i2_tx = (16384 + ABS(SIGN_POW2_DIV(i2_td, 1)))\n                                        / i2_td;\n                        i2_dist_scale_factor = CLIP_S11(\n                                                    (((i2_tb * i2_tx) + 32) >> 6));\n\n                        if(/*((u4_poc1 - u4_poc0) == 0) ||*/\n                        (!(ps_pic_buff1->u1_is_short && ps_pic_buff0->u1_is_short))\n                                        || ((i2_dist_scale_factor >> 2) < -64)\n                                        || ((i2_dist_scale_factor >> 2) > 128))\n                        {\n                            /* same for forward and backward, wt=32 and Offset = 0 */\n                            ui_temp0 = 0x00000020;\n                            ui_temp1 = 0x00000020;\n                        }\n                        else\n                        {\n                            ui_temp0 = 64 - (i2_dist_scale_factor >> 2);\n                            ui_temp1 = (i2_dist_scale_factor >> 2);\n                        }\n                    }\n                    else\n                    {\n                        ui_temp0 = 0x00000020;\n                        ui_temp1 = 0x00000020;\n                    }\n                    /* Store in the weight matrix */\n                    *pu4_wt_mat++ = ui_temp0;\n                    *pu4_wt_mat++ = ui_temp1;\n                    *pu4_wt_mat++ = ui_temp0;\n                    *pu4_wt_mat++ = ui_temp1;\n                    *pu4_wt_mat++ = ui_temp0;\n                    *pu4_wt_mat++ = ui_temp1;\n\n                }\n            }\n            i4_cur_poc = ps_dec->ps_cur_pic->i4_bottom_field_order_cnt;\n        }\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_decode_bslice \\endif\n *\n * \\brief\n *    Decodes a B Slice\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_bslice(dec_struct_t * ps_dec, UWORD16 u2_first_mb_in_slice)\n{\n    dec_pic_params_t * ps_pps = ps_dec->ps_cur_pps;\n    dec_slice_params_t * ps_slice = ps_dec->ps_cur_slice;\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD8 u1_ref_idx_re_flag_lx;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n\n    UWORD64 u8_ref_idx_l0, u8_ref_idx_l1;\n    UWORD32 u4_temp, ui_temp1;\n    WORD32 i_temp;\n    WORD32 ret;\n\n    /*--------------------------------------------------------------------*/\n    /* Read remaining contents of the slice header                        */\n    /*--------------------------------------------------------------------*/\n    {\n        WORD8 *pi1_buf;\n        WORD16 *pi2_mv = ps_dec->s_default_mv_pred.i2_mv;\n        WORD32 *pi4_mv = (WORD32*)pi2_mv;\n        WORD16 *pi16_refFrame;\n        pi1_buf = ps_dec->s_default_mv_pred.i1_ref_frame;\n        pi16_refFrame = (WORD16*)pi1_buf;\n        *pi4_mv = 0;\n        *(pi4_mv + 1) = 0;\n        *pi16_refFrame = OUT_OF_RANGE_REF;\n        ps_dec->s_default_mv_pred.u1_col_ref_pic_idx = (UWORD8)-1;\n        ps_dec->s_default_mv_pred.u1_pic_type = (UWORD8)-1;\n    }\n\n    ps_slice->u1_num_ref_idx_active_override_flag = ih264d_get_bit_h264(\n                    ps_bitstrm);\n    COPYTHECONTEXT(\"SH: num_ref_idx_override_flag\",\n                    ps_slice->u1_num_ref_idx_active_override_flag);\n\n    u8_ref_idx_l0 = ps_dec->ps_cur_pps->u1_num_ref_idx_lx_active[0];\n    u8_ref_idx_l1 = ps_dec->ps_cur_pps->u1_num_ref_idx_lx_active[1];\n    if(ps_slice->u1_num_ref_idx_active_override_flag)\n    {\n        u8_ref_idx_l0 = (UWORD64)1 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        COPYTHECONTEXT(\"SH: num_ref_idx_l0_active_minus1\",\n                        u8_ref_idx_l0 - 1);\n\n        u8_ref_idx_l1 = (UWORD64)1 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        COPYTHECONTEXT(\"SH: num_ref_idx_l1_active_minus1\",\n                        u8_ref_idx_l1 - 1);\n    }\n\n    {\n        UWORD8 u1_max_ref_idx = H264_MAX_REF_PICS;\n        if(ps_slice->u1_field_pic_flag)\n        {\n            u1_max_ref_idx = H264_MAX_REF_PICS << 1;\n        }\n        if((u8_ref_idx_l0 > u1_max_ref_idx) || (u8_ref_idx_l1 > u1_max_ref_idx))\n        {\n            return ERROR_NUM_REF;\n        }\n        ps_slice->u1_num_ref_idx_lx_active[0] = u8_ref_idx_l0;\n        ps_slice->u1_num_ref_idx_lx_active[1] = u8_ref_idx_l1;\n    }\n\n\n    ih264d_init_ref_idx_lx_b(ps_dec);\n    /* Store the value for future slices in the same picture */\n    ps_dec->u1_num_ref_idx_lx_active_prev =\n                    ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0];\n\n    u1_ref_idx_re_flag_lx = ih264d_get_bit_h264(ps_bitstrm);\n    COPYTHECONTEXT(\"SH: ref_pic_list_reordering_flag_l0\",u1_ref_idx_re_flag_lx);\n\n    /* Modified temporarily */\n    if(u1_ref_idx_re_flag_lx)\n    {\n        WORD8 ret;\n        ps_dec->ps_ref_pic_buf_lx[0] = ps_dec->ps_dpb_mgr->ps_mod_dpb[0];\n        ret = ih264d_ref_idx_reordering(ps_dec, 0);\n        if(ret == -1)\n            return ERROR_REFIDX_ORDER_T;\n    }\n    else\n        ps_dec->ps_ref_pic_buf_lx[0] = ps_dec->ps_dpb_mgr->ps_init_dpb[0];\n\n    u1_ref_idx_re_flag_lx = ih264d_get_bit_h264(ps_bitstrm);\n    COPYTHECONTEXT(\"SH: ref_pic_list_reordering_flag_l1\",u1_ref_idx_re_flag_lx);\n\n    /* Modified temporarily */\n    if(u1_ref_idx_re_flag_lx)\n    {\n        WORD8 ret;\n        ps_dec->ps_ref_pic_buf_lx[1] = ps_dec->ps_dpb_mgr->ps_mod_dpb[1];\n        ret = ih264d_ref_idx_reordering(ps_dec, 1);\n        if(ret == -1)\n            return ERROR_REFIDX_ORDER_T;\n    }\n    else\n        ps_dec->ps_ref_pic_buf_lx[1] = ps_dec->ps_dpb_mgr->ps_init_dpb[1];\n\n    /* Create refIdx to POC mapping */\n    {\n        void **ppv_map_ref_idx_to_poc_lx;\n        WORD8 idx;\n        struct pic_buffer_t *ps_pic;\n\n        ppv_map_ref_idx_to_poc_lx = ps_dec->ppv_map_ref_idx_to_poc + FRM_LIST_L0;\n        ppv_map_ref_idx_to_poc_lx[0] = 0;\n        ppv_map_ref_idx_to_poc_lx++;\n        for(idx = 0; idx < ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0];\n                        idx++)\n        {\n            ps_pic = ps_dec->ps_ref_pic_buf_lx[0][idx];\n            ppv_map_ref_idx_to_poc_lx[idx] = (ps_pic->pu1_buf1);\n        }\n\n        ppv_map_ref_idx_to_poc_lx = ps_dec->ppv_map_ref_idx_to_poc + FRM_LIST_L1;\n\n        ppv_map_ref_idx_to_poc_lx[0] = 0;\n        ppv_map_ref_idx_to_poc_lx++;\n        for(idx = 0; idx < ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1];\n                        idx++)\n        {\n            ps_pic = ps_dec->ps_ref_pic_buf_lx[1][idx];\n            ppv_map_ref_idx_to_poc_lx[idx] = (ps_pic->pu1_buf1);\n        }\n\n        if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag)\n        {\n            void **ppv_map_ref_idx_to_poc_lx_t, **ppv_map_ref_idx_to_poc_lx_b;\n\n            ppv_map_ref_idx_to_poc_lx_t = ps_dec->ppv_map_ref_idx_to_poc\n                            + TOP_LIST_FLD_L0;\n            ppv_map_ref_idx_to_poc_lx_b = ps_dec->ppv_map_ref_idx_to_poc\n                            + BOT_LIST_FLD_L0;\n\n            ppv_map_ref_idx_to_poc_lx_t[0] = 0;\n            ppv_map_ref_idx_to_poc_lx_t++;\n            ppv_map_ref_idx_to_poc_lx_b[0] = 0;\n            ppv_map_ref_idx_to_poc_lx_b++;\n            for(idx = 0; idx < ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0];\n                            idx++)\n            {\n                ps_pic = ps_dec->ps_ref_pic_buf_lx[0][idx];\n                ppv_map_ref_idx_to_poc_lx_t[0] = (ps_pic->pu1_buf1);\n                ppv_map_ref_idx_to_poc_lx_b[1] = (ps_pic->pu1_buf1);\n\n                ppv_map_ref_idx_to_poc_lx_b[0] = (ps_pic->pu1_buf1) + 1;\n                ppv_map_ref_idx_to_poc_lx_t[1] = (ps_pic->pu1_buf1) + 1;\n\n                ppv_map_ref_idx_to_poc_lx_t += 2;\n                ppv_map_ref_idx_to_poc_lx_b += 2;\n            }\n\n            ppv_map_ref_idx_to_poc_lx_t = ps_dec->ppv_map_ref_idx_to_poc\n                            + TOP_LIST_FLD_L1;\n            ppv_map_ref_idx_to_poc_lx_b = ps_dec->ppv_map_ref_idx_to_poc\n                            + BOT_LIST_FLD_L1;\n\n            ppv_map_ref_idx_to_poc_lx_t[0] = 0;\n            ppv_map_ref_idx_to_poc_lx_t++;\n            ppv_map_ref_idx_to_poc_lx_b[0] = 0;\n            ppv_map_ref_idx_to_poc_lx_b++;\n            for(idx = 0; idx < ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1];\n                            idx++)\n            {\n                UWORD8 u1_tmp_idx = idx << 1;\n                ps_pic = ps_dec->ps_ref_pic_buf_lx[1][idx];\n                ppv_map_ref_idx_to_poc_lx_t[u1_tmp_idx] = (ps_pic->pu1_buf1);\n                ppv_map_ref_idx_to_poc_lx_b[u1_tmp_idx + 1] = (ps_pic->pu1_buf1);\n\n                ppv_map_ref_idx_to_poc_lx_b[u1_tmp_idx] = (ps_pic->pu1_buf1) + 1;\n                ppv_map_ref_idx_to_poc_lx_t[u1_tmp_idx + 1] = (ps_pic->pu1_buf1) + 1;\n\n            }\n        }\n\n        if(ps_dec->u4_num_cores >= 3)\n        {\n            WORD32 num_entries;\n            WORD32 size;\n            num_entries = MAX_FRAMES;\n            if((1 >= ps_dec->ps_cur_sps->u1_num_ref_frames) &&\n                (0 == ps_dec->i4_display_delay))\n            {\n                num_entries = 1;\n            }\n\n            num_entries = ((2 * num_entries) + 1);\n            num_entries *= 2;\n\n            size = num_entries * sizeof(void *);\n            size += PAD_MAP_IDX_POC * sizeof(void *);\n\n            memcpy((void *)ps_dec->ps_parse_cur_slice->ppv_map_ref_idx_to_poc,\n               ps_dec->ppv_map_ref_idx_to_poc,\n               size);\n        }\n\n    }\n\n    if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag\n                    && (ps_dec->ps_cur_slice->u1_field_pic_flag == 0))\n    {\n        ih264d_convert_frm_mbaff_list(ps_dec);\n    }\n\n    if(ps_pps->u1_wted_bipred_idc == 1)\n    {\n        ret = ih264d_parse_pred_weight_table(ps_slice, ps_bitstrm);\n        if(ret != OK)\n            return ret;\n        ih264d_form_pred_weight_matrix(ps_dec);\n        ps_dec->pu4_wt_ofsts = ps_dec->pu4_wts_ofsts_mat;\n    }\n    else if(ps_pps->u1_wted_bipred_idc == 2)\n    {\n        /* Implicit Weighted prediction */\n        ps_slice->u2_log2Y_crwd = 0x0505;\n        ps_dec->pu4_wt_ofsts = ps_dec->pu4_wts_ofsts_mat;\n        ih264d_get_implicit_weights(ps_dec);\n    }\n    else\n        ps_dec->ps_cur_slice->u2_log2Y_crwd = 0;\n\n    ps_dec->ps_parse_cur_slice->u2_log2Y_crwd =\n                    ps_dec->ps_cur_slice->u2_log2Y_crwd;\n\n    /* G050 */\n    if(ps_slice->u1_nal_ref_idc != 0)\n    {\n        if(!ps_dec->ps_dpb_cmds->u1_dpb_commands_read)\n        {\n            i_temp = ih264d_read_mmco_commands(ps_dec);\n            if (i_temp < 0)\n            {\n                return ERROR_DBP_MANAGER_T;\n            }\n            ps_dec->u4_bitoffset = i_temp;\n        }\n        else\n            ps_bitstrm->u4_ofst += ps_dec->u4_bitoffset;\n    }\n    /* G050 */\n\n    if(ps_pps->u1_entropy_coding_mode == CABAC)\n    {\n        u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        if(u4_temp > MAX_CABAC_INIT_IDC)\n        {\n            return ERROR_INV_SLICE_HDR_T;\n        }\n        ps_slice->u1_cabac_init_idc = u4_temp;\n        COPYTHECONTEXT(\"SH: cabac_init_idc\",ps_slice->u1_cabac_init_idc);\n    }\n\n    /* Read slice_qp_delta */\n    WORD64 i8_temp = (WORD64)ps_pps->u1_pic_init_qp\n                        + ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if((i8_temp < MIN_H264_QP) || (i8_temp > MAX_H264_QP))\n    {\n        return ERROR_INV_RANGE_QP_T;\n    }\n    ps_slice->u1_slice_qp = i8_temp;\n    COPYTHECONTEXT(\"SH: slice_qp_delta\",\n                    (WORD8)(ps_slice->u1_slice_qp - ps_pps->u1_pic_init_qp));\n\n    if(ps_pps->u1_deblocking_filter_parameters_present_flag == 1)\n    {\n        u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        if(u4_temp > SLICE_BOUNDARY_DBLK_DISABLED)\n        {\n            return ERROR_INV_SLICE_HDR_T;\n        } COPYTHECONTEXT(\"SH: disable_deblocking_filter_idc\", u4_temp);\n        ps_slice->u1_disable_dblk_filter_idc = u4_temp;\n        if(u4_temp != 1)\n        {\n            i_temp = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf)\n                            << 1;\n            if((MIN_DBLK_FIL_OFF > i_temp) || (i_temp > MAX_DBLK_FIL_OFF))\n            {\n                return ERROR_INV_SLICE_HDR_T;\n            }\n            ps_slice->i1_slice_alpha_c0_offset = i_temp;\n            COPYTHECONTEXT(\"SH: slice_alpha_c0_offset_div2\",\n                            ps_slice->i1_slice_alpha_c0_offset >> 1);\n\n            i_temp = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf)\n                            << 1;\n            if((MIN_DBLK_FIL_OFF > i_temp) || (i_temp > MAX_DBLK_FIL_OFF))\n            {\n                return ERROR_INV_SLICE_HDR_T;\n            }\n            ps_slice->i1_slice_beta_offset = i_temp;\n            COPYTHECONTEXT(\"SH: slice_beta_offset_div2\",\n                            ps_slice->i1_slice_beta_offset >> 1);\n\n        }\n        else\n        {\n            ps_slice->i1_slice_alpha_c0_offset = 0;\n            ps_slice->i1_slice_beta_offset = 0;\n        }\n    }\n    else\n    {\n        ps_slice->u1_disable_dblk_filter_idc = 0;\n        ps_slice->i1_slice_alpha_c0_offset = 0;\n        ps_slice->i1_slice_beta_offset = 0;\n    }\n\n    ps_dec->u1_slice_header_done = 2;\n\n    if(ps_pps->u1_entropy_coding_mode)\n    {\n        SWITCHOFFTRACE; SWITCHONTRACECABAC;\n        ps_dec->pf_parse_inter_slice = ih264d_parse_inter_slice_data_cabac;\n        ps_dec->pf_parse_inter_mb = ih264d_parse_bmb_cabac;\n        ih264d_init_cabac_contexts(B_SLICE, ps_dec);\n\n        if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag)\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cabac_mbaff;\n        else\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cabac_nonmbaff;\n    }\n    else\n    {\n        SWITCHONTRACE; SWITCHOFFTRACECABAC;\n        ps_dec->pf_parse_inter_slice = ih264d_parse_inter_slice_data_cavlc;\n        ps_dec->pf_parse_inter_mb = ih264d_parse_bmb_cavlc;\n        if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag)\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cavlc_mbaff;\n        else\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cavlc_nonmbaff;\n    }\n\n    ret = ih264d_cal_col_pic(ps_dec);\n    if(ret != OK)\n        return ret;\n    ps_dec->u1_B = 1;\n    ps_dec->pf_mvpred_ref_tfr_nby2mb = ih264d_mv_pred_ref_tfr_nby2_bmb;\n    ret = ps_dec->pf_parse_inter_slice(ps_dec, ps_slice, u2_first_mb_in_slice);\n    if(ret != OK)\n        return ret;\n    return OK;\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_cabac.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n ***************************************************************************\n * \\file ih264d_parse_cabac.c\n *\n * \\brief\n *    This file contains cabac Residual decoding routines.\n *\n * \\date\n *    20/03/2003\n *\n * \\author  NS\n ***************************************************************************\n */\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_structs.h\"\n\n#include \"ih264d_cabac.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_parse_mb_header.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_parse_cabac.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_utils.h\"\n\n/*!\n ********************************************************************************\n *   \\if Function name : ih264d_read_coeff4x4_cabac \\endif\n *\n *   \\brief  This function encodes residual_block_cabac as defined in 7.3.5.3.2.\n *\n *   \\return\n *       Returns the index of last significant coeff.\n *\n ********************************************************************************\n */\n\nUWORD8 ih264d_read_coeff4x4_cabac(dec_bit_stream_t *ps_bitstrm,\n                                  UWORD32 u4_ctxcat,\n                                  bin_ctxt_model_t *ps_ctxt_sig_coeff,\n                                  dec_struct_t *ps_dec, /*!< pointer to access global variables*/\n                                  bin_ctxt_model_t *ps_ctxt_coded)\n{\n\n    decoding_envirnoment_t *ps_cab_env = &ps_dec->s_cab_dec_env;\n    UWORD32 u4_coded_flag;\n    UWORD32 u4_offset, *pu4_buffer;\n    UWORD32 u4_code_int_range, u4_code_int_val_ofst;\n    tu_sblk4x4_coeff_data_t *ps_tu_4x4;\n    WORD16 *pi2_coeff_data;\n    WORD32 num_sig_coeffs = 0;\n\n    /*loading from strcuctures*/\n\n    ps_tu_4x4 = (tu_sblk4x4_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n    ps_tu_4x4->u2_sig_coeff_map = 0;\n    pi2_coeff_data = &ps_tu_4x4->ai2_level[0];\n\n    u4_offset = ps_bitstrm->u4_ofst;\n    pu4_buffer = ps_bitstrm->pu4_buffer;\n\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n\n    {\n\n        /*inilined DecodeDecision_onebin begins*/\n\n        {\n\n            UWORD32 u4_qnt_int_range, u4_int_range_lps;\n            UWORD32 u4_symbol, u1_mps_state;\n\n            UWORD32 table_lookup;\n            const UWORD32 *pu4_table = (const UWORD32 *)ps_cab_env->cabac_table;\n            UWORD32 u4_clz;\n\n            u1_mps_state = (ps_ctxt_coded->u1_mps_state);\n            u4_clz = CLZ(u4_code_int_range);\n            u4_qnt_int_range = u4_code_int_range << u4_clz;\n            u4_qnt_int_range = (u4_qnt_int_range >> 29) & 0x3;\n            table_lookup =\n                            pu4_table[(u1_mps_state << 2) + u4_qnt_int_range];\n            u4_int_range_lps = table_lookup & 0xff;\n            u4_int_range_lps = u4_int_range_lps << (23 - u4_clz);\n            u4_code_int_range = u4_code_int_range - u4_int_range_lps;\n            u4_symbol = ((u1_mps_state >> 6) & 0x1);\n            u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n            CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst, u4_symbol,\n                         u4_int_range_lps, u1_mps_state, table_lookup)\n\n            if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_8)\n            {\n\n                RENORM_RANGE_OFFSET(u4_code_int_range, u4_code_int_val_ofst,\n                                    u4_offset, pu4_buffer)\n            }\n\n            ps_ctxt_coded->u1_mps_state = u1_mps_state;\n            u4_coded_flag = u4_symbol;\n\n            /*inilined DecodeDecision_onebin ends*/\n\n        }\n\n    }\n\n    if(u4_coded_flag)\n    {\n\n        {\n            bin_ctxt_model_t *p_binCtxt_last, *p_binCtxt_last_org;\n            UWORD32 uc_last_coeff_idx;\n            UWORD32 uc_bin;\n            UWORD32 i;\n            WORD32 first_coeff_offset = 0;\n\n            if((u4_ctxcat == CHROMA_AC_CTXCAT) || (u4_ctxcat == LUMA_AC_CTXCAT))\n            {\n                first_coeff_offset = 1;\n            }\n\n            i = 0;\n            if(u4_ctxcat == CHROMA_DC_CTXCAT)\n            {\n                uc_last_coeff_idx = 3;\n            }\n            else\n            {\n                UWORD32 u4_start;\n                u4_start = (u4_ctxcat & 1) + (u4_ctxcat >> 2);\n                uc_last_coeff_idx = 15 - u4_start;\n            }\n            p_binCtxt_last_org = ps_ctxt_sig_coeff\n                            + LAST_COEFF_CTXT_MINUS_SIG_COEFF_CTXT;\n\n            do\n            {\n\n                /*inilined DecodeDecision_onebin begins*/\n                {\n\n                    UWORD32 u4_qnt_int_range, u4_int_range_lps;\n                    UWORD32 u4_symbol, u1_mps_state;\n                    UWORD32 table_lookup;\n                    const UWORD32 *pu4_table =\n                                    (const UWORD32 *)ps_cab_env->cabac_table;\n                    UWORD32 u4_clz;\n\n                    u1_mps_state = (ps_ctxt_sig_coeff->u1_mps_state);\n\n                    u4_clz = CLZ(u4_code_int_range);\n\n                    u4_qnt_int_range = u4_code_int_range << u4_clz;\n                    u4_qnt_int_range = (u4_qnt_int_range >> 29) & 0x3;\n\n                    table_lookup = pu4_table[(u1_mps_state << 2)\n                                    + u4_qnt_int_range];\n\n                    u4_int_range_lps = table_lookup & 0xff;\n\n                    u4_int_range_lps = u4_int_range_lps << (23 - u4_clz);\n                    u4_code_int_range = u4_code_int_range - u4_int_range_lps;\n                    u4_symbol = ((u1_mps_state >> 6) & 0x1);\n                    u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n                    CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst,\n                                 u4_symbol, u4_int_range_lps, u1_mps_state,\n                                 table_lookup)\n\n                    if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_14)\n                    {\n\n                        UWORD32 read_bits, u4_clz;\n                        u4_clz = CLZ(u4_code_int_range);\n                        NEXTBITS(read_bits, (u4_offset + 23), pu4_buffer,\n                                 u4_clz)\n                        FLUSHBITS(u4_offset, (u4_clz))\n                        u4_code_int_range = u4_code_int_range << u4_clz;\n                        u4_code_int_val_ofst = (u4_code_int_val_ofst << u4_clz)\n                                        | read_bits;\n                    }\n\n                    INC_BIN_COUNT(\n                                    ps_cab_env)\n\n                    ps_ctxt_sig_coeff->u1_mps_state = u1_mps_state;\n                    uc_bin = u4_symbol;\n\n                }\n                /*incrementing pointer to point to the context of the next bin*/\n                ps_ctxt_sig_coeff++;\n\n                /*inilined DecodeDecision_onebin ends*/\n\n                if(uc_bin)\n                {\n                    num_sig_coeffs++;\n                    SET_BIT(ps_tu_4x4->u2_sig_coeff_map, (i + first_coeff_offset));\n\n                    p_binCtxt_last = p_binCtxt_last_org + i;\n\n                    /*inilined DecodeDecision_onebin begins*/\n\n                    {\n\n                        UWORD32 u4_qnt_int_range, u4_int_range_lps;\n                        UWORD32 u4_symbol, u1_mps_state;\n                        UWORD32 table_lookup;\n                        const UWORD32 *pu4_table =\n                                        (const UWORD32 *)ps_cab_env->cabac_table;\n                        UWORD32 u4_clz;\n\n                        u1_mps_state = (p_binCtxt_last->u1_mps_state);\n\n                        u4_clz = CLZ(u4_code_int_range);\n                        u4_qnt_int_range = u4_code_int_range << u4_clz;\n                        u4_qnt_int_range = (u4_qnt_int_range >> 29)\n                                        & 0x3;\n\n                        table_lookup = pu4_table[(u1_mps_state << 2)\n                                        + u4_qnt_int_range];\n                        u4_int_range_lps = table_lookup & 0xff;\n\n                        u4_int_range_lps = u4_int_range_lps\n                                        << (23 - u4_clz);\n\n                        u4_code_int_range = u4_code_int_range\n                                        - u4_int_range_lps;\n                        u4_symbol = ((u1_mps_state >> 6) & 0x1);\n                        u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n                        CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst,\n                                     u4_symbol, u4_int_range_lps,\n                                     u1_mps_state, table_lookup)\n\n                        INC_BIN_COUNT(ps_cab_env)\n\n                        p_binCtxt_last->u1_mps_state = u1_mps_state;\n                        uc_bin = u4_symbol;\n\n                    }\n\n                    /*inilined DecodeDecision_onebin ends*/\n                    if(uc_bin == 1)\n                        goto label_read_levels;\n\n                }\n\n                i = i + 1;\n\n            }\n            while(i < uc_last_coeff_idx);\n\n            num_sig_coeffs++;\n            SET_BIT(ps_tu_4x4->u2_sig_coeff_map, (i + first_coeff_offset));\n\n            label_read_levels: ;\n\n        }\n\n        /// VALUE of No of Coeff in BLOCK = i + 1 for second case else i;\n\n        /* Decode coeff_abs_level_minus1 and coeff_sign_flag */\n        {\n\n            WORD32 i2_abs_lvl;\n            UWORD32 u1_abs_level_equal1 = 1, u1_abs_level_gt1 = 0;\n\n            UWORD32 u4_ctx_inc;\n            UWORD32 ui_prefix;\n        bin_ctxt_model_t *p_ctxt_abs_level;\n\n\n        p_ctxt_abs_level = ps_dec->p_coeff_abs_level_minus1_t[u4_ctxcat];\n        u4_ctx_inc = ((0x51));\n\n        /*****************************************************/\n        /* Main Loop runs for no. of Significant coefficient */\n        /*****************************************************/\n\n\n        do\n            {\n\n                {\n                    INC_SYM_COUNT(&(ps_dec.s_cab_dec_env));\n\n                    /*****************************************************/\n                    /* inilining a modified ih264d_decode_bins_unary     */\n                    /*****************************************************/\n\n                    {\n                        UWORD32 u4_value;\n                        UWORD32 u4_symbol;\n                        bin_ctxt_model_t *ps_bin_ctxt;\n                        UWORD32 u4_ctx_Inc;\n\n                        u4_value = 0;\n\n                        u4_ctx_Inc = u4_ctx_inc & 0xf;\n                        ps_bin_ctxt = p_ctxt_abs_level + u4_ctx_Inc;\n\n                        do\n                        {\n\n                            {\n\n                                UWORD32 u4_qnt_int_range,\n                                                u4_int_range_lps;\n                                UWORD32 u1_mps_state;\n                                UWORD32 table_lookup;\n                                const UWORD32 *pu4_table =\n                                                (const UWORD32 *)ps_cab_env->cabac_table;\n                                UWORD32 u4_clz;\n\n                                u1_mps_state = (ps_bin_ctxt->u1_mps_state);\n                                u4_clz = CLZ(u4_code_int_range);\n                                u4_qnt_int_range = u4_code_int_range\n                                                << u4_clz;\n                                u4_qnt_int_range = (u4_qnt_int_range\n                                                >> 29) & 0x3;\n                                table_lookup = pu4_table[(u1_mps_state << 2)\n                                                + u4_qnt_int_range];\n                                u4_int_range_lps = table_lookup & 0xff;\n\n                                u4_int_range_lps = u4_int_range_lps\n                                                << (23 - u4_clz);\n                                u4_code_int_range = u4_code_int_range\n                                                - u4_int_range_lps;\n                                u4_symbol = ((u1_mps_state >> 6) & 0x1);\n                                u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n                                CHECK_IF_LPS(u4_code_int_range,\n                                             u4_code_int_val_ofst, u4_symbol,\n                                             u4_int_range_lps, u1_mps_state,\n                                             table_lookup)\n\n                                if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_9)\n                                {\n\n                                    RENORM_RANGE_OFFSET(u4_code_int_range,\n                                                        u4_code_int_val_ofst,\n                                                        u4_offset, pu4_buffer)\n                                }\n\n                                INC_BIN_COUNT(ps_cab_env);\n\n                                ps_bin_ctxt->u1_mps_state = u1_mps_state;\n                            }\n\n                            INC_BIN_COUNT(ps_cab_env);INC_DECISION_BINS(ps_cab_env);\n\n                            u4_value++;\n                            ps_bin_ctxt = p_ctxt_abs_level + (u4_ctx_inc >> 4);\n\n                        }\n                        while(u4_symbol && (u4_value < UCOFF_LEVEL));\n\n                        ui_prefix = u4_value - 1 + u4_symbol;\n\n                    }\n\n                    if(ui_prefix == UCOFF_LEVEL)\n                    {\n                        UWORD32 ui16_sufS = 0;\n                        UWORD32 u1_max_bins;\n                        UWORD32 u4_value;\n\n                        i2_abs_lvl = UCOFF_LEVEL;\n                        /*inlining ih264d_decode_bypass_bins_unary begins*/\n\n                        {\n                            UWORD32 uc_bin;\n                            UWORD32 bits_to_flush;\n\n\n                            bits_to_flush = 0;\n                            /*renormalize to ensure there 23 bits more in the u4_code_int_val_ofst*/\n                            {\n                                UWORD32 u4_clz, read_bits;\n\n                                u4_clz = CLZ(u4_code_int_range);\n                                FLUSHBITS(u4_offset, u4_clz)\n                                NEXTBITS(read_bits, u4_offset, pu4_buffer, CABAC_BITS_TO_READ)\n                                u4_code_int_range = u4_code_int_range << u4_clz;\n                                u4_code_int_val_ofst = (u4_code_int_val_ofst\n                                                << u4_clz) | read_bits;\n\n                            }\n\n                            do\n                            {\n                                bits_to_flush++;\n\n                                u4_code_int_range = u4_code_int_range >> 1;\n\n                                if(u4_code_int_val_ofst >= u4_code_int_range)\n                                {\n                                    /* S=1 */\n                                    uc_bin = 1;\n                                    u4_code_int_val_ofst -= u4_code_int_range;\n                                }\n                                else\n                                {\n                                    /* S=0 */\n                                    uc_bin = 0;\n                                }\n\n                                INC_BIN_COUNT(\n                                                ps_cab_env);INC_BYPASS_BINS(ps_cab_env);\n\n                            }\n                            while(uc_bin && (bits_to_flush < CABAC_BITS_TO_READ));\n\n                            u4_value = (bits_to_flush - 1);\n\n                        }\n                        /*inlining ih264d_decode_bypass_bins_unary ends*/\n\n                        ui16_sufS = (1 << u4_value);\n                        u1_max_bins = u4_value;\n\n                        if(u4_value > 0)\n                        {\n\n                            /*inline bypassbins_flc begins*/\n\n                            if(u4_value > 10)\n                            {\n                                UWORD32 u4_clz, read_bits;\n\n                                u4_clz = CLZ(u4_code_int_range);\n                                FLUSHBITS(u4_offset, u4_clz)\n                                NEXTBITS(read_bits, u4_offset, pu4_buffer, CABAC_BITS_TO_READ)\n                                u4_code_int_range = u4_code_int_range << u4_clz;\n                                u4_code_int_val_ofst = (u4_code_int_val_ofst\n                                                << u4_clz) | read_bits;\n                            }\n\n                            {\n                                UWORD32 ui_bins;\n                                UWORD32 uc_bin;\n                                UWORD32 bits_to_flush;\n\n                                ui_bins = 0;\n                                bits_to_flush = 0;\n\n                                do\n                                {\n                                    bits_to_flush++;\n\n                                    u4_code_int_range = u4_code_int_range >> 1;\n\n                                    if(u4_code_int_val_ofst\n                                                    >= u4_code_int_range)\n                                    {\n                                        /* S=1 */\n                                        uc_bin = 1;\n                                        u4_code_int_val_ofst -=\n                                                        u4_code_int_range;\n                                    }\n                                    else\n                                    {\n                                        /* S=0 */\n                                        uc_bin = 0;\n                                    }\n\n                                    INC_BIN_COUNT(\n                                                    ps_cab_env);INC_BYPASS_BINS(ps_cab_env);\n\n                                    ui_bins = ((ui_bins << 1) | uc_bin);\n\n                                }\n                                while(bits_to_flush < u1_max_bins);\n\n                                u4_value = ui_bins;\n                            }\n\n                            /*inline bypassbins_flc ends*/\n\n                        }\n\n                        //Value of K\n                        ui16_sufS += u4_value;\n                        i2_abs_lvl += ui16_sufS;\n\n                    }\n                    else\n                        i2_abs_lvl = 1 + ui_prefix;\n\n                    if(i2_abs_lvl > 1)\n                    {\n                        u1_abs_level_gt1++;\n                    }\n                    if(!u1_abs_level_gt1)\n                    {\n                        u1_abs_level_equal1++;\n                        u4_ctx_inc = (5 << 4) + MIN(u1_abs_level_equal1, 4);\n                    }\n                    else\n                        u4_ctx_inc = (5 + MIN(u1_abs_level_gt1, 4)) << 4;\n\n                    /*u4_ctx_inc = g_table_temp[u1_abs_level_gt1][u1_abs_level_equal1];*/\n\n                    /* encode coeff_sign_flag[i] */\n\n                    {\n                        u4_code_int_range = u4_code_int_range >> 1;\n\n                        if(u4_code_int_val_ofst >= (u4_code_int_range))\n                        {\n                            /* S=1 */\n                            u4_code_int_val_ofst -= u4_code_int_range;\n                            i2_abs_lvl = (-i2_abs_lvl);\n                        }\n\n                    }\n                    num_sig_coeffs--;\n                    *pi2_coeff_data++ = i2_abs_lvl;\n                }\n            }\n            while(num_sig_coeffs > 0);\n        }\n    }\n\n    if(u4_coded_flag)\n    {\n        WORD32 offset;\n        offset = (UWORD8 *)pi2_coeff_data - (UWORD8 *)ps_tu_4x4;\n        offset = ALIGN4(offset);\n        ps_dec->pv_parse_tu_coeff_data = (void *)((UWORD8 *)ps_dec->pv_parse_tu_coeff_data + offset);\n    }\n\n\n    /*updating structures*/\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n    ps_cab_env->u4_code_int_range = u4_code_int_range;\n    ps_bitstrm->u4_ofst = u4_offset;\n    return (u4_coded_flag);\n}\n/*!\n ********************************************************************************\n *   \\if Function name : ih264d_read_coeff8x8_cabac \\endif\n *\n *   \\brief  This function encodes residual_block_cabac as defined in 7.3.5.3.2.\n when transform_8x8_flag  = 1\n *\n *   \\return\n *       Returns the index of last significant coeff.\n *\n ********************************************************************************\n */\n\nvoid ih264d_read_coeff8x8_cabac(dec_bit_stream_t *ps_bitstrm,\n                                dec_struct_t *ps_dec, /*!< pointer to access global variables*/\n                                dec_mb_info_t *ps_cur_mb_info)\n{\n    decoding_envirnoment_t *ps_cab_env = &ps_dec->s_cab_dec_env;\n    UWORD32 u4_offset, *pu4_buffer;\n    UWORD32 u4_code_int_range, u4_code_int_val_ofst;\n\n    /* High profile related declarations */\n    UWORD8 u1_field_coding_flag = ps_cur_mb_info->ps_curmb->u1_mb_fld;\n    const UWORD8 *pu1_lastcoeff_context_inc =\n                    (UWORD8 *)gau1_ih264d_lastcoeff_context_inc;\n    const UWORD8 *pu1_sigcoeff_context_inc;\n    bin_ctxt_model_t *ps_ctxt_sig_coeff;\n    WORD32 num_sig_coeffs = 0;\n    tu_blk8x8_coeff_data_t *ps_tu_8x8;\n    WORD16 *pi2_coeff_data;\n\n    /*loading from strcuctures*/\n\n    ps_tu_8x8 = (tu_blk8x8_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n    ps_tu_8x8->au4_sig_coeff_map[0] = 0;\n    ps_tu_8x8->au4_sig_coeff_map[1] = 0;\n    pi2_coeff_data = &ps_tu_8x8->ai2_level[0];\n\n\n    if(!u1_field_coding_flag)\n    {\n        pu1_sigcoeff_context_inc =\n                        (UWORD8 *)gau1_ih264d_sigcoeff_context_inc_frame;\n\n        /*******************************************************************/\n        /* last coefficient context is derived from significant coeff u4_flag */\n        /* only significant coefficient matrix need to be initialized      */\n        /*******************************************************************/\n        ps_ctxt_sig_coeff = ps_dec->s_high_profile.ps_sigcoeff_8x8_frame;\n    }\n    else\n    {\n        pu1_sigcoeff_context_inc =\n                        (UWORD8 *)gau1_ih264d_sigcoeff_context_inc_field;\n\n        /*******************************************************************/\n        /* last coefficient context is derived from significant coeff u4_flag */\n        /* only significant coefficient matrix need to be initialized      */\n        /*******************************************************************/\n        ps_ctxt_sig_coeff = ps_dec->s_high_profile.ps_sigcoeff_8x8_field;\n    }\n\n    /*loading from strcuctures*/\n\n    u4_offset = ps_bitstrm->u4_ofst;\n    pu4_buffer = ps_bitstrm->pu4_buffer;\n\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n\n    {\n        {\n            bin_ctxt_model_t *p_binCtxt_last, *p_binCtxt_last_org,\n                            *p_ctxt_sig_coeff_org;\n            UWORD32 uc_last_coeff_idx;\n            UWORD32 uc_bin;\n            UWORD32 i;\n\n            i = 0;\n\n            uc_last_coeff_idx = 63;\n\n            p_binCtxt_last_org = ps_ctxt_sig_coeff\n                            + LAST_COEFF_CTXT_MINUS_SIG_COEFF_CTXT_8X8;\n\n            p_ctxt_sig_coeff_org = ps_ctxt_sig_coeff;\n\n            do\n            {\n                /*inilined DecodeDecision_onebin begins*/\n                {\n                    UWORD32 u4_qnt_int_range, u4_int_range_lps;\n                    UWORD32 u4_symbol, u1_mps_state;\n                    UWORD32 table_lookup;\n                    const UWORD32 *pu4_table =\n                                    (const UWORD32 *)ps_cab_env->cabac_table;\n                    UWORD32 u4_clz;\n\n                    u1_mps_state = (ps_ctxt_sig_coeff->u1_mps_state);\n\n                    u4_clz = CLZ(u4_code_int_range);\n\n                    u4_qnt_int_range = u4_code_int_range << u4_clz;\n                    u4_qnt_int_range = (u4_qnt_int_range >> 29) & 0x3;\n\n                    table_lookup = pu4_table[(u1_mps_state << 2)\n                                    + u4_qnt_int_range];\n\n                    u4_int_range_lps = table_lookup & 0xff;\n\n                    u4_int_range_lps = u4_int_range_lps << (23 - u4_clz);\n                    u4_code_int_range = u4_code_int_range - u4_int_range_lps;\n                    u4_symbol = ((u1_mps_state >> 6) & 0x1);\n                    u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n                    CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst,\n                                 u4_symbol, u4_int_range_lps, u1_mps_state,\n                                 table_lookup)\n\n                    if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_14)\n                    {\n                        UWORD32 read_bits, u4_clz;\n                        u4_clz = CLZ(u4_code_int_range);\n                        NEXTBITS(read_bits, (u4_offset + 23), pu4_buffer,\n                                 u4_clz)\n                        FLUSHBITS(u4_offset, (u4_clz))\n                        u4_code_int_range = u4_code_int_range << u4_clz;\n                        u4_code_int_val_ofst = (u4_code_int_val_ofst << u4_clz)\n                                        | read_bits;\n                    }\n\n                    ps_ctxt_sig_coeff->u1_mps_state = u1_mps_state;\n                    uc_bin = u4_symbol;\n                }\n                /*incrementing pointer to point to the context of the next bin*/\n                ps_ctxt_sig_coeff = p_ctxt_sig_coeff_org\n                                + pu1_sigcoeff_context_inc[i + 1];\n\n                /*inilined DecodeDecision_onebin ends*/\n                if(uc_bin)\n                {\n                    num_sig_coeffs++;\n                    SET_BIT(ps_tu_8x8->au4_sig_coeff_map[i>31], (i > 31 ? i - 32:i));\n\n                    p_binCtxt_last = p_binCtxt_last_org\n                                    + pu1_lastcoeff_context_inc[i];\n\n                    /*inilined DecodeDecision_onebin begins*/\n\n                    {\n                        UWORD32 u4_qnt_int_range, u4_int_range_lps;\n                        UWORD32 u4_symbol, u1_mps_state;\n                        UWORD32 table_lookup;\n                        const UWORD32 *pu4_table =\n                                        (const UWORD32 *)ps_cab_env->cabac_table;\n                        UWORD32 u4_clz;\n\n                        u1_mps_state = (p_binCtxt_last->u1_mps_state);\n\n                        u4_clz = CLZ(u4_code_int_range);\n                        u4_qnt_int_range = u4_code_int_range << u4_clz;\n                        u4_qnt_int_range = (u4_qnt_int_range >> 29)\n                                        & 0x3;\n\n                        table_lookup = pu4_table[(u1_mps_state << 2)\n                                        + u4_qnt_int_range];\n                        u4_int_range_lps = table_lookup & 0xff;\n\n                        u4_int_range_lps = u4_int_range_lps\n                                        << (23 - u4_clz);\n\n                        u4_code_int_range = u4_code_int_range\n                                        - u4_int_range_lps;\n                        u4_symbol = ((u1_mps_state >> 6) & 0x1);\n                        u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n                        CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst,\n                                     u4_symbol, u4_int_range_lps,\n                                     u1_mps_state, table_lookup)\n\n                        p_binCtxt_last->u1_mps_state = u1_mps_state;\n                        uc_bin = u4_symbol;\n                    }\n\n                    /*inilined DecodeDecision_onebin ends*/\n                    if(uc_bin == 1)\n                        goto label_read_levels;\n\n                }\n\n                i = i + 1;\n\n            }\n            while(i < uc_last_coeff_idx);\n\n            num_sig_coeffs++;\n            SET_BIT(ps_tu_8x8->au4_sig_coeff_map[i>31], (i > 31 ? i - 32:i));\n\n            label_read_levels: ;\n        }\n\n        /// VALUE of No of Coeff in BLOCK = i + 1 for second case else i;\n\n        /* Decode coeff_abs_level_minus1 and coeff_sign_flag */\n        {\n            WORD32 i2_abs_lvl;\n            UWORD32 u1_abs_level_equal1 = 1, u1_abs_level_gt1 = 0;\n\n            UWORD32 u4_ctx_inc;\n            UWORD32 ui_prefix;\n            bin_ctxt_model_t *p_ctxt_abs_level;\n\n            p_ctxt_abs_level =\n                            ps_dec->p_coeff_abs_level_minus1_t[LUMA_8X8_CTXCAT];\n            u4_ctx_inc = ((0x51));\n\n            /*****************************************************/\n            /* Main Loop runs for no. of Significant coefficient */\n            /*****************************************************/\n            do\n            {\n                {\n\n                    /*****************************************************/\n                    /* inilining a modified ih264d_decode_bins_unary     */\n                    /*****************************************************/\n\n                    {\n                        UWORD32 u4_value;\n                        UWORD32 u4_symbol;\n                        bin_ctxt_model_t *ps_bin_ctxt;\n                        UWORD32 u4_ctx_Inc;\n                        u4_value = 0;\n\n                        u4_ctx_Inc = u4_ctx_inc & 0xf;\n                        ps_bin_ctxt = p_ctxt_abs_level + u4_ctx_Inc;\n\n                        do\n                        {\n                            {\n                                UWORD32 u4_qnt_int_range,\n                                                u4_int_range_lps;\n                                UWORD32 u1_mps_state;\n                                UWORD32 table_lookup;\n                                const UWORD32 *pu4_table =\n                                                (const UWORD32 *)ps_cab_env->cabac_table;\n                                UWORD32 u4_clz;\n\n                                u1_mps_state = (ps_bin_ctxt->u1_mps_state);\n                                u4_clz = CLZ(u4_code_int_range);\n                                u4_qnt_int_range = u4_code_int_range\n                                                << u4_clz;\n                                u4_qnt_int_range = (u4_qnt_int_range\n                                                >> 29) & 0x3;\n                                table_lookup = pu4_table[(u1_mps_state << 2)\n                                                + u4_qnt_int_range];\n                                u4_int_range_lps = table_lookup & 0xff;\n\n                                u4_int_range_lps = u4_int_range_lps\n                                                << (23 - u4_clz);\n                                u4_code_int_range = u4_code_int_range\n                                                - u4_int_range_lps;\n                                u4_symbol = ((u1_mps_state >> 6) & 0x1);\n                                u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n                                CHECK_IF_LPS(u4_code_int_range,\n                                             u4_code_int_val_ofst, u4_symbol,\n                                             u4_int_range_lps, u1_mps_state,\n                                             table_lookup)\n\n                                if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_9)\n                                {\n\n                                    RENORM_RANGE_OFFSET(u4_code_int_range,\n                                                        u4_code_int_val_ofst,\n                                                        u4_offset, pu4_buffer)\n                                }\n\n                                ps_bin_ctxt->u1_mps_state = u1_mps_state;\n                            }\n\n                            u4_value++;\n                            ps_bin_ctxt = p_ctxt_abs_level + (u4_ctx_inc >> 4);\n\n                        }\n                        while(u4_symbol && (u4_value < UCOFF_LEVEL));\n\n                        ui_prefix = u4_value - 1 + u4_symbol;\n                    }\n\n                    if(ui_prefix == UCOFF_LEVEL)\n                    {\n                        UWORD32 ui16_sufS = 0;\n                        UWORD32 u1_max_bins;\n                        UWORD32 u4_value;\n\n                        i2_abs_lvl = UCOFF_LEVEL;\n                        /*inlining ih264d_decode_bypass_bins_unary begins*/\n\n                        {\n                            UWORD32 uc_bin;\n                            UWORD32 bits_to_flush;\n\n\n                            bits_to_flush = 0;\n                            /*renormalize to ensure there 23 bits more in the u4_code_int_val_ofst*/\n                            {\n                                UWORD32 u4_clz, read_bits;\n\n                                u4_clz = CLZ(u4_code_int_range);\n                                FLUSHBITS(u4_offset, u4_clz)\n                                NEXTBITS(read_bits, u4_offset, pu4_buffer, CABAC_BITS_TO_READ)\n                                u4_code_int_range = u4_code_int_range << u4_clz;\n                                u4_code_int_val_ofst = (u4_code_int_val_ofst\n                                                << u4_clz) | read_bits;\n                            }\n\n                            do\n                            {\n                                bits_to_flush++;\n\n                                u4_code_int_range = u4_code_int_range >> 1;\n\n                                if(u4_code_int_val_ofst >= u4_code_int_range)\n                                {\n                                    /* S=1 */\n                                    uc_bin = 1;\n                                    u4_code_int_val_ofst -= u4_code_int_range;\n                                }\n                                else\n                                {\n                                    /* S=0 */\n                                    uc_bin = 0;\n                                }\n\n                            }\n                            while(uc_bin && (bits_to_flush < CABAC_BITS_TO_READ));\n\n                            u4_value = (bits_to_flush - 1);\n                        }\n                        /*inlining ih264d_decode_bypass_bins_unary ends*/\n\n                        ui16_sufS = (1 << u4_value);\n                        u1_max_bins = u4_value;\n\n                        if(u4_value > 0)\n                        {\n                            /*inline bypassbins_flc begins*/\n\n                            if(u4_value > 10)\n                            {\n                                UWORD32 u4_clz, read_bits;\n\n                                u4_clz = CLZ(u4_code_int_range);\n                                FLUSHBITS(u4_offset, u4_clz)\n                                NEXTBITS(read_bits, u4_offset, pu4_buffer, CABAC_BITS_TO_READ)\n                                u4_code_int_range = u4_code_int_range << u4_clz;\n                                u4_code_int_val_ofst = (u4_code_int_val_ofst\n                                                << u4_clz) | read_bits;\n                            }\n\n                            {\n                                UWORD32 ui_bins;\n                                UWORD32 uc_bin;\n                                UWORD32 bits_to_flush;\n\n                                ui_bins = 0;\n                                bits_to_flush = 0;\n\n                                do\n                                {\n                                    bits_to_flush++;\n\n                                    u4_code_int_range = u4_code_int_range >> 1;\n\n                                    if(u4_code_int_val_ofst\n                                                    >= u4_code_int_range)\n                                    {\n                                        /* S=1 */\n                                        uc_bin = 1;\n                                        u4_code_int_val_ofst -=\n                                                        u4_code_int_range;\n                                    }\n                                    else\n                                    {\n                                        /* S=0 */\n                                        uc_bin = 0;\n                                    }\n\n                                    ui_bins = ((ui_bins << 1) | uc_bin);\n\n                                }\n                                while(bits_to_flush < u1_max_bins);\n\n                                u4_value = ui_bins;\n                            }\n                            /*inline bypassbins_flc ends*/\n                        }\n\n                        //Value of K\n                        ui16_sufS += u4_value;\n                        i2_abs_lvl += (WORD32)ui16_sufS;\n                    }\n                    else\n                    {\n                        i2_abs_lvl = 1 + ui_prefix;\n                    }\n\n                    if(i2_abs_lvl > 1)\n                    {\n                        u1_abs_level_gt1++;\n                    }\n                    if(!u1_abs_level_gt1)\n                    {\n                        u1_abs_level_equal1++;\n                        u4_ctx_inc = (5 << 4) + MIN(u1_abs_level_equal1, 4);\n                    }\n                    else\n                    {\n                        u4_ctx_inc = (5 + MIN(u1_abs_level_gt1, 4)) << 4;\n                    }\n\n                    /*u4_ctx_inc = g_table_temp[u1_abs_level_gt1][u1_abs_level_equal1];*/\n\n                    /* encode coeff_sign_flag[i] */\n\n                    {\n                        u4_code_int_range = u4_code_int_range >> 1;\n\n                        if(u4_code_int_val_ofst >= (u4_code_int_range))\n                        {\n                            /* S=1 */\n                            u4_code_int_val_ofst -= u4_code_int_range;\n                            i2_abs_lvl = (-i2_abs_lvl);\n                        }\n                    }\n\n                    *pi2_coeff_data++ = i2_abs_lvl;\n                    num_sig_coeffs--;\n                }\n            }\n            while(num_sig_coeffs > 0);\n        }\n    }\n\n    {\n        WORD32 offset;\n        offset = (UWORD8 *)pi2_coeff_data - (UWORD8 *)ps_tu_8x8;\n        offset = ALIGN4(offset);\n        ps_dec->pv_parse_tu_coeff_data = (void *)((UWORD8 *)ps_dec->pv_parse_tu_coeff_data + offset);\n    }\n\n    /*updating structures*/\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n    ps_cab_env->u4_code_int_range = u4_code_int_range;\n    ps_bitstrm->u4_ofst = u4_offset;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_cabac_parse_8x8block                                     */\n/*                                                                           */\n/*  Description   : This function does the residual parsing of 4 subblocks   */\n/*                  in a 8x8 block.                                          */\n/*                                                                           */\n/*  Inputs        : pi2_coeff_block : pointer to residual block where        */\n/*                  decoded and inverse scan coefficients are updated        */\n/*                                                                           */\n/*                  u4_sub_block_strd : indicates the number of sublocks    */\n/*                  in a row. It is 4 for luma and 2 for chroma.             */\n/*                                                                           */\n/*                  u4_ctx_cat : inidicates context category for residual    */\n/*                  decoding.                                                */\n/*                                                                           */\n/*                  ps_dec : pointer to Decstruct (decoder context)          */\n/*                                                                           */\n/*                  pu1_top_nnz : top nnz pointer                            */\n/*                                                                           */\n/*                  pu1_left_nnz : left nnz pointer                          */\n/*                                                                           */\n/*  Globals       : No                                                       */\n/*  Processing    : Parsing for four subblocks in unrolled, top and left nnz */\n/*                  are updated on the fly. csbp is set in accordance to     */\n/*                  decoded numcoeff for the subblock index in raster order  */\n/*                                                                           */\n/*  Outputs       : The updated residue buffer, nnzs and csbp current block  */\n/*                                                                           */\n/*  Returns       : Returns the coded sub block pattern csbp for the block   */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         09 10 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nUWORD32 ih264d_cabac_parse_8x8block(WORD16 *pi2_coeff_block,\n                                    UWORD32 u4_sub_block_strd,\n                                    UWORD32 u4_ctx_cat,\n                                    dec_struct_t * ps_dec,\n                                    UWORD8 *pu1_top_nnz,\n                                    UWORD8 *pu1_left_nnz)\n{\n    UWORD32 u4_ctxinc, u4_subblock_coded;\n    UWORD32 u4_top0, u4_top1;\n    UWORD32 u4_csbp = 0;\n    UWORD32 u4_idx = 0;\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    bin_ctxt_model_t * const ps_cbf = ps_dec->p_cbf_t[u4_ctx_cat];\n    bin_ctxt_model_t *ps_src_bin_ctxt;\n    bin_ctxt_model_t * const ps_sig_coeff_flag =\n                    ps_dec->p_significant_coeff_flag_t[u4_ctx_cat];\n\n    UWORD8 *pu1_inv_scan = ps_dec->pu1_inv_scan;\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 0                    */\n    /*------------------------------------------------------*/\n    u4_ctxinc = ((!!pu1_top_nnz[0]) << 1) + (!!pu1_left_nnz[0]);\n\n    ps_src_bin_ctxt = ps_cbf + u4_ctxinc;\n\n    u4_top0 = ih264d_read_coeff4x4_cabac( ps_bitstrm,\n                                         u4_ctx_cat, ps_sig_coeff_flag, ps_dec,\n                                         ps_src_bin_ctxt);\n\n    INSERT_BIT(u4_csbp, u4_idx, u4_top0);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 1                    */\n    /*------------------------------------------------------*/\n    u4_idx++;\n    pi2_coeff_block += NUM_COEFFS_IN_4x4BLK;\n    u4_ctxinc = ((!!pu1_top_nnz[1]) << 1) + u4_top0;\n\n    ps_src_bin_ctxt = ps_cbf + u4_ctxinc;\n\n    u4_top1 = ih264d_read_coeff4x4_cabac(ps_bitstrm,\n                                         u4_ctx_cat, ps_sig_coeff_flag, ps_dec,\n                                         ps_src_bin_ctxt);\n\n    INSERT_BIT(u4_csbp, u4_idx, u4_top1);\n    pu1_left_nnz[0] = u4_top1;\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 2                    */\n    /*------------------------------------------------------*/\n    u4_idx += (u4_sub_block_strd - 1);\n    pi2_coeff_block += ((u4_sub_block_strd - 1) * NUM_COEFFS_IN_4x4BLK);\n    u4_ctxinc = (u4_top0 << 1) + (!!pu1_left_nnz[1]);\n\n    ps_src_bin_ctxt = ps_cbf + u4_ctxinc;\n\n    u4_subblock_coded = ih264d_read_coeff4x4_cabac(ps_bitstrm, u4_ctx_cat,\n                                                   ps_sig_coeff_flag, ps_dec,\n                                                   ps_src_bin_ctxt);\n\n    INSERT_BIT(u4_csbp, u4_idx, u4_subblock_coded);\n    pu1_top_nnz[0] = u4_subblock_coded;\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 3                    */\n    /*------------------------------------------------------*/\n    u4_idx++;\n    pi2_coeff_block += NUM_COEFFS_IN_4x4BLK;\n    u4_ctxinc = (u4_top1 << 1) + u4_subblock_coded;\n\n    ps_src_bin_ctxt = ps_cbf + u4_ctxinc;\n\n    u4_subblock_coded = ih264d_read_coeff4x4_cabac(ps_bitstrm, u4_ctx_cat,\n                                                   ps_sig_coeff_flag, ps_dec,\n                                                   ps_src_bin_ctxt);\n\n    INSERT_BIT(u4_csbp, u4_idx, u4_subblock_coded);\n    pu1_top_nnz[1] = pu1_left_nnz[1] = u4_subblock_coded;\n\n    return (u4_csbp);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_residual4x4_cabac \\endif\n *\n * \\brief\n *    This function parses CABAC syntax of a Luma and Chroma AC Residuals.\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\n\nWORD32 ih264d_parse_residual4x4_cabac(dec_struct_t * ps_dec,\n                                      dec_mb_info_t *ps_cur_mb_info,\n                                      UWORD8 u1_offset)\n{\n    UWORD8 u1_cbp = ps_cur_mb_info->u1_cbp;\n    UWORD16 ui16_csbp = 0;\n    WORD16 *pi2_residual_buf;\n    UWORD8 uc_ctx_cat;\n    UWORD8 *pu1_top_nnz = ps_cur_mb_info->ps_curmb->pu1_nnz_y;\n    UWORD8 *pu1_left_nnz = ps_dec->pu1_left_nnz_y;\n    UWORD8 *pu1_top_nnz_uv = ps_cur_mb_info->ps_curmb->pu1_nnz_uv;\n    ctxt_inc_mb_info_t *p_curr_ctxt = ps_dec->ps_curr_ctxt_mb_info;\n    ctxt_inc_mb_info_t *ps_top_ctxt = ps_dec->p_top_ctxt_mb_info;\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 u4_nbr_avail = ps_dec->u1_mb_ngbr_availablity;\n    WORD16 *pi2_coeff_block = NULL;\n    bin_ctxt_model_t *ps_src_bin_ctxt;\n\n    UWORD8 u1_top_dc_csbp = (ps_top_ctxt->u1_yuv_dc_csbp) >> 1;\n    UWORD8 u1_left_dc_csbp = (ps_dec->pu1_left_yuv_dc_csbp[0]) >> 1;\n\n\n    if(!(u4_nbr_avail & TOP_MB_AVAILABLE_MASK))\n    {\n        if(p_curr_ctxt->u1_mb_type & CAB_INTRA_MASK)\n        {\n            *(UWORD32 *)pu1_top_nnz = 0;\n            u1_top_dc_csbp = 0;\n            *(UWORD32 *)pu1_top_nnz_uv = 0;\n        }\n        else\n        {\n            *(UWORD32 *)pu1_top_nnz = 0x01010101;\n            u1_top_dc_csbp = 0x3;\n            *(UWORD32 *)pu1_top_nnz_uv = 0x01010101;\n        }\n    }\n    else\n    {\n        UWORD32 *pu4_buf;\n        UWORD8 *pu1_buf;\n        pu1_buf = ps_cur_mb_info->ps_top_mb->pu1_nnz_y;\n        pu4_buf = (UWORD32 *)pu1_buf;\n        *(UWORD32 *)(pu1_top_nnz) = *pu4_buf;\n\n        pu1_buf = ps_cur_mb_info->ps_top_mb->pu1_nnz_uv;\n        pu4_buf = (UWORD32 *)pu1_buf;\n        *(UWORD32 *)(pu1_top_nnz_uv) = *pu4_buf;\n\n    }\n\n    if(!(u4_nbr_avail & LEFT_MB_AVAILABLE_MASK))\n    {\n        if(p_curr_ctxt->u1_mb_type & CAB_INTRA_MASK)\n        {\n            UWORD32 *pu4_buf;\n            UWORD8 *pu1_buf;\n            *(UWORD32 *)pu1_left_nnz = 0;\n            u1_left_dc_csbp = 0;\n            pu1_buf = ps_dec->pu1_left_nnz_uv;\n            pu4_buf = (UWORD32 *)pu1_buf;\n            *pu4_buf = 0;\n        }\n        else\n        {\n            UWORD32 *pu4_buf;\n            UWORD8 *pu1_buf;\n            *(UWORD32 *)pu1_left_nnz = 0x01010101;\n            u1_left_dc_csbp = 0x3;\n            pu1_buf = ps_dec->pu1_left_nnz_uv;\n            pu4_buf = (UWORD32 *)pu1_buf;\n            *pu4_buf = 0x01010101;\n        }\n    }\n\n    uc_ctx_cat = u1_offset ? LUMA_AC_CTXCAT : LUMA_4X4_CTXCAT;\n\n    ps_cur_mb_info->u1_qp_div6 = ps_dec->u1_qp_y_div6;\n    ps_cur_mb_info->u1_qpc_div6 = ps_dec->u1_qp_u_div6;\n    ps_cur_mb_info->u1_qp_rem6 = ps_dec->u1_qp_y_rem6;\n    ps_cur_mb_info->u1_qpc_rem6 = ps_dec->u1_qp_u_rem6;\n    // CHECK_THIS\n    ps_cur_mb_info->u1_qpcr_div6 = ps_dec->u1_qp_v_div6;\n    ps_cur_mb_info->u1_qpcr_rem6 = ps_dec->u1_qp_v_rem6;\n\n    if(u1_cbp & 0x0f)\n    {\n        if(ps_cur_mb_info->u1_tran_form8x8 == 0)\n        {\n            /*******************************************************************/\n            /* Block 0 residual decoding, check cbp and proceed (subblock = 0) */\n            /*******************************************************************/\n            if(!(u1_cbp & 0x1))\n            {\n                *(UWORD16 *)(pu1_top_nnz) = 0;\n                *(UWORD16 *)(pu1_left_nnz) = 0;\n            }\n            else\n            {\n                ui16_csbp = ih264d_cabac_parse_8x8block(pi2_coeff_block, 4,\n                                                        uc_ctx_cat, ps_dec,\n                                                        pu1_top_nnz,\n                                                        pu1_left_nnz);\n            }\n\n            /*******************************************************************/\n            /* Block 1 residual decoding, check cbp and proceed (subblock = 2) */\n            /*******************************************************************/\n            pi2_coeff_block += (2 * NUM_COEFFS_IN_4x4BLK);\n            if(!(u1_cbp & 0x2))\n            {\n                *(UWORD16 *)(pu1_top_nnz + 2) = 0;\n                *(UWORD16 *)(pu1_left_nnz) = 0;\n            }\n            else\n            {\n                UWORD32 u4_temp = ih264d_cabac_parse_8x8block(pi2_coeff_block,\n                                                              4, uc_ctx_cat,\n                                                              ps_dec,\n                                                              (pu1_top_nnz + 2),\n                                                              pu1_left_nnz);\n                ui16_csbp |= (u4_temp << 2);\n            }\n\n            /*******************************************************************/\n            /* Block 2 residual decoding, check cbp and proceed (subblock = 8) */\n            /*******************************************************************/\n            pi2_coeff_block += (6 * NUM_COEFFS_IN_4x4BLK);\n            if(!(u1_cbp & 0x4))\n            {\n                *(UWORD16 *)(pu1_top_nnz) = 0;\n                *(UWORD16 *)(pu1_left_nnz + 2) = 0;\n            }\n            else\n            {\n                UWORD32 u4_temp = ih264d_cabac_parse_8x8block(\n                                pi2_coeff_block, 4, uc_ctx_cat, ps_dec,\n                                pu1_top_nnz, (pu1_left_nnz + 2));\n                ui16_csbp |= (u4_temp << 8);\n            }\n\n            /*******************************************************************/\n            /* Block 3 residual decoding, check cbp and proceed (subblock = 10)*/\n            /*******************************************************************/\n            pi2_coeff_block += (2 * NUM_COEFFS_IN_4x4BLK);\n            if(!(u1_cbp & 0x8))\n            {\n                *(UWORD16 *)(pu1_top_nnz + 2) = 0;\n                *(UWORD16 *)(pu1_left_nnz + 2) = 0;\n            }\n            else\n            {\n                UWORD32 u4_temp = ih264d_cabac_parse_8x8block(\n                                pi2_coeff_block, 4, uc_ctx_cat, ps_dec,\n                                (pu1_top_nnz + 2), (pu1_left_nnz + 2));\n                ui16_csbp |= (u4_temp << 10);\n            }\n\n        }\n        else\n        {\n            ui16_csbp = 0;\n\n            /*******************************************************************/\n            /* Block 0 residual decoding, check cbp and proceed (subblock = 0) */\n            /*******************************************************************/\n            if(!(u1_cbp & 0x1))\n            {\n                *(UWORD16 *)(pu1_top_nnz) = 0;\n                *(UWORD16 *)(pu1_left_nnz) = 0;\n            }\n            else\n            {\n\n                dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n\n                ih264d_read_coeff8x8_cabac( ps_bitstrm,\n                                           ps_dec, ps_cur_mb_info);\n\n                pu1_left_nnz[0] = 1;\n                pu1_left_nnz[1] = 1;\n\n                pu1_top_nnz[0] = 1;\n                pu1_top_nnz[1] = 1;\n\n                /* added to be used by BS computation module */\n                ui16_csbp |= 0x0033;\n            }\n\n            /*******************************************************************/\n            /* Block 1 residual decoding, check cbp and proceed (subblock = 2) */\n            /*******************************************************************/\n            pi2_coeff_block += 64;\n\n            if(!(u1_cbp & 0x2))\n            {\n                *(UWORD16 *)(pu1_top_nnz + 2) = 0;\n                *(UWORD16 *)(pu1_left_nnz) = 0;\n            }\n            else\n            {\n\n\n                dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n\n                ih264d_read_coeff8x8_cabac(ps_bitstrm,\n                                           ps_dec, ps_cur_mb_info);\n\n                pu1_left_nnz[0] = 1;\n                pu1_left_nnz[1] = 1;\n\n                pu1_top_nnz[2] = 1;\n                pu1_top_nnz[3] = 1;\n\n                /* added to be used by BS computation module */\n                ui16_csbp |= 0x00CC;\n\n            }\n\n            /*******************************************************************/\n            /* Block 2 residual decoding, check cbp and proceed (subblock = 8) */\n            /*******************************************************************/\n            pi2_coeff_block += 64;\n            if(!(u1_cbp & 0x4))\n            {\n                *(UWORD16 *)(pu1_top_nnz) = 0;\n                *(UWORD16 *)(pu1_left_nnz + 2) = 0;\n            }\n            else\n            {\n\n                dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n\n                ih264d_read_coeff8x8_cabac(ps_bitstrm,\n                                           ps_dec, ps_cur_mb_info);\n\n                pu1_left_nnz[2] = 1;\n                pu1_left_nnz[3] = 1;\n\n                pu1_top_nnz[0] = 1;\n                pu1_top_nnz[1] = 1;\n\n                /* added to be used by BS computation module */\n                ui16_csbp |= 0x3300;\n            }\n\n            /*******************************************************************/\n            /* Block 3 residual decoding, check cbp and proceed (subblock = 10)*/\n            /*******************************************************************/\n            pi2_coeff_block += 64;\n\n            if(!(u1_cbp & 0x8))\n            {\n                *(UWORD16 *)(pu1_top_nnz + 2) = 0;\n                *(UWORD16 *)(pu1_left_nnz + 2) = 0;\n            }\n            else\n            {\n\n                dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n\n                ih264d_read_coeff8x8_cabac(ps_bitstrm,\n                                           ps_dec, ps_cur_mb_info);\n\n                pu1_left_nnz[2] = 1;\n                pu1_left_nnz[3] = 1;\n\n                pu1_top_nnz[2] = 1;\n                pu1_top_nnz[3] = 1;\n\n                /* added to be used by BS computation module */\n                ui16_csbp |= 0xCC00;\n            }\n        }\n    }\n    else\n    {\n        *(UWORD32 *)(pu1_top_nnz) = 0;\n        *(UWORD32 *)(pu1_left_nnz) = 0;\n    }\n    /*--------------------------------------------------------------------*/\n    /* Store the last row of N values to top row                          */\n    /*--------------------------------------------------------------------*/\n    ps_cur_mb_info->u2_luma_csbp = ui16_csbp;\n    ps_cur_mb_info->ps_curmb->u2_luma_csbp = ui16_csbp;\n    {\n        WORD8 i;\n        UWORD16 u2_chroma_csbp = 0;\n        ps_cur_mb_info->u2_chroma_csbp = 0;\n\n        u1_cbp >>= 4;\n        pu1_top_nnz = pu1_top_nnz_uv;\n        pu1_left_nnz = ps_dec->pu1_left_nnz_uv;\n        /*--------------------------------------------------------------------*/\n        /* if Chroma Component not present OR no ac values present            */\n        /* Set the values of N to zero                                        */\n        /*--------------------------------------------------------------------*/\n        if(u1_cbp == CBPC_ALLZERO)\n        {\n            ps_dec->pu1_left_yuv_dc_csbp[0] &= 0x1;\n            *(UWORD32 *)(pu1_top_nnz) = 0;\n            *(UWORD32 *)(pu1_left_nnz) = 0;\n            p_curr_ctxt->u1_yuv_dc_csbp &= 0x1;\n            return (0);\n        }\n\n        /*--------------------------------------------------------------------*/\n        /* Decode Chroma DC values                                            */\n        /*--------------------------------------------------------------------*/\n        for(i = 0; i < 2; i++)\n        {\n            UWORD8 uc_a = 1, uc_b = 1;\n            UWORD32 u4_ctx_inc;\n            UWORD8 uc_codedBlockFlag;\n            UWORD8 pu1_inv_scan[4] =\n                { 0, 1, 2, 3 };\n            WORD32 u4_scale;\n            WORD32 i4_mb_inter_inc;\n            tu_sblk4x4_coeff_data_t *ps_tu_4x4 =\n                            (tu_sblk4x4_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n            WORD16 *pi2_coeff_data =\n                            (WORD16 *)ps_dec->pv_parse_tu_coeff_data;\n            WORD16 ai2_dc_coef[4];\n\n            INC_SYM_COUNT(&(ps_dec->s_cab_dec_env));\n            u4_scale = (i) ?\n                            (ps_dec->pu2_quant_scale_v[0]\n                                            << ps_dec->u1_qp_v_div6) :\n                            (ps_dec->pu2_quant_scale_u[0]\n                                            << ps_dec->u1_qp_u_div6);\n\n            /*--------------------------------------------------------------------*/\n            /* Decode Bitstream to get the DC coeff                               */\n            /*--------------------------------------------------------------------*/\n            uc_a = (u1_left_dc_csbp >> i) & 0x01;\n            uc_b = (u1_top_dc_csbp >> i) & 0x01;\n            u4_ctx_inc = (uc_a + (uc_b << 1));\n\n            ps_src_bin_ctxt = (ps_dec->p_cbf_t[CHROMA_DC_CTXCAT]) + u4_ctx_inc;\n\n            uc_codedBlockFlag =\n                            ih264d_read_coeff4x4_cabac(ps_bitstrm,\n                                            CHROMA_DC_CTXCAT,\n                                            ps_dec->p_significant_coeff_flag_t[CHROMA_DC_CTXCAT],\n                                            ps_dec, ps_src_bin_ctxt);\n\n            i4_mb_inter_inc = (!((ps_cur_mb_info->ps_curmb->u1_mb_type == I_4x4_MB)\n                            || (ps_cur_mb_info->ps_curmb->u1_mb_type == I_16x16_MB)))\n                            * 3;\n\n            if(ps_dec->s_high_profile.u1_scaling_present)\n            {\n                u4_scale *=\n                                ps_dec->s_high_profile.i2_scalinglist4x4[i4_mb_inter_inc\n                                                + 1 + i][0];\n\n            }\n            else\n            {\n                u4_scale <<= 4;\n            }\n\n            if(uc_codedBlockFlag)\n            {\n                WORD32 i_z0, i_z1, i_z2, i_z3;\n                WORD32 *pi4_scale;\n\n                SET_BIT(u1_top_dc_csbp, i);\n                SET_BIT(u1_left_dc_csbp, i);\n\n                ai2_dc_coef[0] = 0;\n                ai2_dc_coef[1] = 0;\n                ai2_dc_coef[2] = 0;\n                ai2_dc_coef[3] = 0;\n\n                ih264d_unpack_coeff4x4_dc_4x4blk(ps_tu_4x4,\n                                                 ai2_dc_coef,\n                                                 pu1_inv_scan);\n                i_z0 = (ai2_dc_coef[0] + ai2_dc_coef[2]);\n                i_z1 = (ai2_dc_coef[0] - ai2_dc_coef[2]);\n                i_z2 = (ai2_dc_coef[1] - ai2_dc_coef[3]);\n                i_z3 = (ai2_dc_coef[1] + ai2_dc_coef[3]);\n\n                /*-----------------------------------------------------------*/\n                /* Scaling and storing the values back                       */\n                /*-----------------------------------------------------------*/\n                *pi2_coeff_data++ = ((i_z0 + i_z3) * u4_scale) >> 5;\n                *pi2_coeff_data++ = ((i_z0 - i_z3) * u4_scale) >> 5;\n                *pi2_coeff_data++ = ((i_z1 + i_z2) * u4_scale) >> 5;\n                *pi2_coeff_data++ = ((i_z1 - i_z2) * u4_scale) >> 5;\n\n                ps_dec->pv_parse_tu_coeff_data = (void *)pi2_coeff_data;\n\n                SET_BIT(ps_cur_mb_info->u1_yuv_dc_block_flag,(i+1));\n            }\n            else\n            {\n                CLEARBIT(u1_top_dc_csbp, i);\n                CLEARBIT(u1_left_dc_csbp, i);\n            }\n        }\n\n        /*********************************************************************/\n        /*                   Update the DC csbp                              */\n        /*********************************************************************/\n        ps_dec->pu1_left_yuv_dc_csbp[0] &= 0x1;\n        p_curr_ctxt->u1_yuv_dc_csbp &= 0x1;\n        ps_dec->pu1_left_yuv_dc_csbp[0] |= (u1_left_dc_csbp << 1);\n        p_curr_ctxt->u1_yuv_dc_csbp |= (u1_top_dc_csbp << 1);\n        if(u1_cbp == CBPC_ACZERO)\n        {\n            *(UWORD32 *)(pu1_top_nnz) = 0;\n            *(UWORD32 *)(pu1_left_nnz) = 0;\n            return (0);\n        }\n        /*--------------------------------------------------------------------*/\n        /* Decode Chroma AC values                                            */\n        /*--------------------------------------------------------------------*/\n        {\n            UWORD32 u4_temp;\n            /*****************************************************************/\n            /* U Block  residual decoding, check cbp and proceed (subblock=0)*/\n            /*****************************************************************/\n            u2_chroma_csbp = ih264d_cabac_parse_8x8block(pi2_coeff_block, 2,\n            CHROMA_AC_CTXCAT,\n                                                         ps_dec, pu1_top_nnz,\n                                                         pu1_left_nnz);\n\n            pi2_coeff_block += MB_CHROM_SIZE;\n            /*****************************************************************/\n            /* V Block  residual decoding, check cbp and proceed (subblock=1)*/\n            /*****************************************************************/\n            u4_temp = ih264d_cabac_parse_8x8block(pi2_coeff_block, 2,\n            CHROMA_AC_CTXCAT,\n                                                  ps_dec, (pu1_top_nnz + 2),\n                                                  (pu1_left_nnz + 2));\n            u2_chroma_csbp |= (u4_temp << 4);\n        }\n        /*********************************************************************/\n        /*                   Update the AC csbp                              */\n        /*********************************************************************/\n        ps_cur_mb_info->u2_chroma_csbp = u2_chroma_csbp;\n    }\n\n    return (0);\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_cabac.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*!\n ***************************************************************************\n * \\file ih264d_parse_cabac.h\n *\n * \\brief\n *    This file contains cabac Residual decoding routines.\n *\n * \\date\n *    20/03/2003\n *\n * \\author  NS\n ***************************************************************************\n */\n#ifndef _IH264D_PARSE_CABAC_H_\n#define _IH264D_PARSE_CABAC_H_\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n\n#define UCOFF_LEVEL  14\n\n\nUWORD8 ih264d_read_coeff4x4_cabac(dec_bit_stream_t *ps_bitstrm,\n                                  UWORD32 u4_ctxcat,\n                                  bin_ctxt_model_t *ps_ctxt_sig_coeff,\n                                  dec_struct_t *ps_dec,\n                                  bin_ctxt_model_t *ps_ctxt_coded);\n\nvoid ih264d_read_coeff8x8_cabac(dec_bit_stream_t *ps_bitstrm,\n                                dec_struct_t *ps_dec,\n                                dec_mb_info_t *ps_cur_mb_info);\n\nUWORD32 cabac_parse_8x8block_transform8x8_set(WORD16 *pi2_coeff_block,\n                                              dec_struct_t * ps_dec,\n                                              UWORD8 *pu1_top_nnz,\n                                              UWORD8 *pu1_left_nnz,\n                                              dec_mb_info_t *ps_cur_mb_info);\n\n#endif  /* _IH264D_PARSE_CABAC_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_cavlc.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n ***************************************************************************\n * \\file ih264d_parse_cavlc.c\n *\n * \\brief\n *    This file contains UVLC related functions.\n *\n * \\date\n *    20/11/2002\n *\n * \\author  NS\n ***************************************************************************\n */\n\n#include <string.h>\n#include <stdio.h>\n\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_cabac.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_mb_utils.h\"\n\nvoid ih264d_unpack_coeff4x4_dc_4x4blk(tu_sblk4x4_coeff_data_t *ps_tu_4x4,\n                                      WORD16 *pi2_out_coeff_data,\n                                      UWORD8 *pu1_inv_scan);\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_uev                                                  */\n/*                                                                           */\n/*  Description   : Reads the unsigned Exp Golomb codec syntax from the      */\n/*                  ps_bitstrm as specified in section 9.1 of H264 standard      */\n/*                  It also increases bitstream u4_ofst by the number of bits */\n/*                  parsed for UEV decode operation                          */\n/*                                                                           */\n/*  Inputs        : bitstream base pointer and bitsream u4_ofst in bits       */\n/*  Globals       : None                                                     */\n/*  Processing    :                                                          */\n/*  Outputs       : UEV decoded syntax element and incremented ps_bitstrm u4_ofst */\n/*  Returns       : UEV decoded syntax element                               */\n/*                                                                           */\n/*  Issues        : Does not check if ps_bitstrm u4_ofst exceeds max ps_bitstrm i4_size  */\n/*                  for performamce. Caller might have to do error resilence */\n/*                  check for bitstream overflow                             */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         19 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nUWORD32 ih264d_uev(UWORD32 *pu4_bitstrm_ofst, UWORD32 *pu4_bitstrm_buf)\n{\n    UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n    UWORD32 u4_word, u4_ldz;\n\n    /***************************************************************/\n    /* Find leading zeros in next 32 bits                          */\n    /***************************************************************/\n    NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n    u4_ldz = CLZ(u4_word);\n    /* Flush the ps_bitstrm */\n    u4_bitstream_offset += (u4_ldz + 1);\n    /* Read the suffix from the ps_bitstrm */\n    u4_word = 0;\n    if(u4_ldz)\n        GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf, u4_ldz);\n    *pu4_bitstrm_ofst = u4_bitstream_offset;\n    return ((1 << u4_ldz) + u4_word - 1);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_sev                                                  */\n/*                                                                           */\n/*  Description   : Reads the signed Exp Golomb codec syntax from the ps_bitstrm */\n/*                  as specified in section 9.1 of H264 standard.            */\n/*                  It also increases bitstream u4_ofst by the number of bits */\n/*                  parsed for SEV decode operation                          */\n/*                                                                           */\n/*  Inputs        : bitstream base pointer and bitsream u4_ofst in bits       */\n/*  Globals       : None                                                     */\n/*  Processing    :                                                          */\n/*  Outputs       : SEV decoded syntax element and incremented ps_bitstrm u4_ofst */\n/*  Returns       : SEV decoded syntax element                               */\n/*                                                                           */\n/*  Issues        : Does not check if ps_bitstrm u4_ofst exceeds max ps_bitstrm i4_size  */\n/*                  for performamce. Caller might have to do error resilence */\n/*                  check for bitstream overflow                             */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         19 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_sev(UWORD32 *pu4_bitstrm_ofst, UWORD32 *pu4_bitstrm_buf)\n{\n    UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n    UWORD32 u4_word, u4_ldz, u4_abs_val;\n\n    /***************************************************************/\n    /* Find leading zeros in next 32 bits                          */\n    /***************************************************************/\n    NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n    u4_ldz = CLZ(u4_word);\n\n    /* Flush the ps_bitstrm */\n    u4_bitstream_offset += (u4_ldz + 1);\n\n    /* Read the suffix from the ps_bitstrm */\n    u4_word = 0;\n    if(u4_ldz)\n        GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf, u4_ldz);\n\n    *pu4_bitstrm_ofst = u4_bitstream_offset;\n    u4_abs_val = ((1 << u4_ldz) + u4_word) >> 1;\n\n    if(u4_word & 0x1)\n        return (-(WORD32)u4_abs_val);\n    else\n        return (u4_abs_val);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : get_tev_range_1                                          */\n/*                                                                           */\n/*  Description   : Reads the TEV Exp Golomb codec syntax from the ps_bitstrm    */\n/*                  as specified in section 9.1 of H264 standard. This will  */\n/*                  called only when the input range is 1 for TEV decode.    */\n/*                  If range is more than 1, then UEV decode is done         */\n/*                                                                           */\n/*  Inputs        : bitstream base pointer and bitsream u4_ofst in bits       */\n/*  Globals       : None                                                     */\n/*  Processing    :                                                          */\n/*  Outputs       : TEV decoded syntax element and incremented ps_bitstrm u4_ofst */\n/*  Returns       : TEV decoded syntax element                               */\n/*                                                                           */\n/*  Issues        : Does not check if ps_bitstrm u4_ofst exceeds max ps_bitstrm i4_size  */\n/*                  for performamce. Caller might have to do error resilence */\n/*                  check for bitstream overflow                             */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         19 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nUWORD32 ih264d_tev_range1(UWORD32 *pu4_bitstrm_ofst, UWORD32 *pu4_bitstrm_buf)\n{\n    UWORD32 u4_code;\n    GETBIT(u4_code, *pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    return (!u4_code);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_uvlc \\endif\n *\n * \\brief\n *\n *    Reads the unsigned/signed/truncated integer Exp-Golomb-coded syntax element\n *    with the left bit first. The parsing process for this descriptor is specified\n *    in subclause 9.1.\n *\n * \\param ps_bitstrm       : Pointer to Bitstream Structure .\n * \\param u4_range           : Range value in case of Truncated Exp-Golomb-code\n * \\param pi_bitstrm_ofst : Pointer to the local copy of Bitstream u4_ofst\n * \\param u1_flag            : Flag indicating the case of UEV,SEV or TEV\n * \\param u4_bitstrm_ofst : Local copy of Bitstream u4_ofst\n * \\param pu4_bitstrm_buf : Pointer to the Bitstream buffer\n *\n * \\return\n *    Returns Code Value.\n *\n **************************************************************************\n */\n\nWORD32 ih264d_uvlc(dec_bit_stream_t *ps_bitstrm,\n                   UWORD32 u4_range,\n                   UWORD32 *pi_bitstrm_ofst,\n                   UWORD8 u1_flag,\n                   UWORD32 u4_bitstrm_ofst,\n                   UWORD32 *pu4_bitstrm_buf)\n{\n    UWORD32 word, word2, cur_bit, cur_word, code_val, code_num, clz;\n\n    SWITCHOFFTRACE;\n    cur_bit = u4_bitstrm_ofst & 0x1F;\n    cur_word = u4_bitstrm_ofst >> 5;\n    word = pu4_bitstrm_buf[cur_word];\n    word2 = pu4_bitstrm_buf[cur_word + 1];\n\n    if(cur_bit != 0)\n    {\n        word <<= cur_bit;\n        word2 >>= (32 - cur_bit);\n        word |= word2;\n    }\n\n    if(u1_flag == TEV && u4_range == 1)\n    {\n        word >>= 31;\n        word = 1 - word;\n        (*pi_bitstrm_ofst)++;\n        ps_bitstrm->u4_ofst = *pi_bitstrm_ofst;\n        return (WORD32)word;\n    }\n\n    //finding clz\n    {\n        UWORD32 ui32_code, ui32_mask;\n\n        ui32_code = word;\n        ui32_mask = 0x80000000;\n        clz = 0;\n\n        /* DSP implements this with LMBD instruction */\n        /* so there we don't need to break the loop */\n        while(!(ui32_code & ui32_mask))\n        {\n            clz++;\n            ui32_mask >>= 1;\n            if(0 == ui32_mask)\n                break;\n        }\n    }\n\n    if(clz == 0)\n    {\n        *pi_bitstrm_ofst = *pi_bitstrm_ofst + (2 * clz) + 1;\n        ps_bitstrm->u4_ofst = *pi_bitstrm_ofst;\n        return 0;\n    }\n\n    word <<= (clz + 1);\n    word >>= (32 - clz);\n    code_num = (1 << clz) + word - 1;\n    *pi_bitstrm_ofst = *pi_bitstrm_ofst + (2 * clz) + 1;\n    ps_bitstrm->u4_ofst = *pi_bitstrm_ofst;\n\n    if(u1_flag == TEV || u1_flag == UEV)\n        return (WORD32)code_num;\n\n    code_val = (code_num + 1) >> 1;\n    if(!(code_num & 0x01))\n        return -((WORD32)code_val);\n    return (WORD32)code_val;\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_cavlc_4x4res_block_totalcoeff_1                          */\n/*                                                                           */\n/*  Description   : This function does cavlc decoding of 4x4 block residual  */\n/*                  coefficient when total coeff is equal to 1. The parsing  */\n/*                  is done as defined in section 9.2.2 and 9.2.3 of the     */\n/*                  H264 standard.                                           */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         25 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_cavlc_4x4res_block_totalcoeff_1(UWORD32 u4_isdc,\n                                           UWORD32 u4_total_coeff_trail_one,\n                                           dec_bit_stream_t *ps_bitstrm)\n{\n\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 u4_bitstream_offset = ps_bitstrm->u4_ofst;\n    UWORD32 u4_trailing_ones = u4_total_coeff_trail_one & 0xFFFF;\n    WORD32 i2_level;\n    UWORD32 u4_tot_zero, u4_ldz, u4_scan_pos;\n\n    tu_sblk4x4_coeff_data_t *ps_tu_4x4;\n    WORD16 *pi2_coeff_data;\n    dec_struct_t *ps_dec = (dec_struct_t *)ps_bitstrm->pv_codec_handle;\n\n    ps_tu_4x4 = (tu_sblk4x4_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n    ps_tu_4x4->u2_sig_coeff_map = 0;\n    pi2_coeff_data = &ps_tu_4x4->ai2_level[0];\n\n\n    if(u4_trailing_ones)\n    {\n        UWORD32 u4_sign;\n        /****************************************************************/\n        /* Decode Trailing One as in section 9.2.2                      */\n        /****************************************************************/\n        GETBIT(u4_sign, u4_bitstream_offset, pu4_bitstrm_buf);\n        i2_level = u4_sign ? -1 : 1;\n    }\n    else\n    {\n        /****************************************************************/\n        /* Decoding Level based on prefix and suffix  as in 9.2.2       */\n        /****************************************************************/\n        UWORD32 u4_lev_suffix, u4_lev_suffix_size;\n        WORD32 u2_lev_code, u2_abs_value;\n        UWORD32 u4_lev_prefix;\n        /***************************************************************/\n        /* Find leading zeros in next 32 bits                          */\n        /***************************************************************/\n        FIND_ONE_IN_STREAM_32(u4_lev_prefix, u4_bitstream_offset,\n                              pu4_bitstrm_buf);\n        u2_lev_code = (2 + MIN(u4_lev_prefix, 15));\n\n        if(14 == u4_lev_prefix)\n            u4_lev_suffix_size = 4;\n        else if(15 <= u4_lev_prefix)\n        {\n            u2_lev_code += 15;\n            u4_lev_suffix_size = u4_lev_prefix - 3;\n        }\n        else\n            u4_lev_suffix_size = 0;\n\n        //HP_LEVEL_PREFIX\n        if(16 <= u4_lev_prefix)\n        {\n            u2_lev_code += ((1 << (u4_lev_prefix - 3)) - 4096);\n        }\n        if(u4_lev_suffix_size)\n        {\n            GETBITS(u4_lev_suffix, u4_bitstream_offset, pu4_bitstrm_buf,\n                    u4_lev_suffix_size);\n            u2_lev_code += u4_lev_suffix;\n        }\n\n        u2_abs_value = (u2_lev_code + 2) >> 1;\n        /*********************************************************/\n        /* If Level code is odd, level is negative else positive */\n        /*********************************************************/\n        i2_level = (u2_lev_code & 1) ? -u2_abs_value : u2_abs_value;\n\n    }\n\n    /****************************************************************/\n    /* Decoding total zeros as in section 9.2.3, table 9.7          */\n    /****************************************************************/\n    FIND_ONE_IN_STREAM_LEN(u4_ldz, u4_bitstream_offset, pu4_bitstrm_buf, 8);\n\n    if(u4_ldz)\n    {\n        GETBIT(u4_tot_zero, u4_bitstream_offset, pu4_bitstrm_buf);\n        u4_tot_zero = (u4_ldz << 1) - u4_tot_zero;\n    }\n    else\n        u4_tot_zero = 0;\n\n    /***********************************************************************/\n    /* Inverse scan and store  residual coeff. Update the bitstream u4_ofst */\n    /***********************************************************************/\n    u4_scan_pos = u4_tot_zero + u4_isdc;\n    if(u4_scan_pos > 15)\n        return -1;\n\n    SET_BIT(ps_tu_4x4->u2_sig_coeff_map, u4_scan_pos);\n    *pi2_coeff_data++ = i2_level;\n\n\n    {\n        WORD32 offset;\n        offset = (UWORD8 *)pi2_coeff_data - (UWORD8 *)ps_tu_4x4;\n        offset = ALIGN4(offset);\n        ps_dec->pv_parse_tu_coeff_data = (void *)((UWORD8 *)ps_dec->pv_parse_tu_coeff_data + offset);\n    }\n\n    ps_bitstrm->u4_ofst = u4_bitstream_offset;\n    return 0;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_cavlc_4x4res_block_totalcoeff_2to10                      */\n/*                                                                           */\n/*  Description   : This function does cavlc decoding of 4x4 block residual  */\n/*                  coefficient when total coeffs are between two and ten    */\n/*                  inclusive. Parsing is done as defined in section 9.2.2   */\n/*                  and 9.2.3 the H264 standard.                             */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         25 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_cavlc_4x4res_block_totalcoeff_2to10(UWORD32 u4_isdc,\n                                               UWORD32 u4_total_coeff_trail_one, /*!<TotalCoefficients<<16+trailingones*/\n                                               dec_bit_stream_t *ps_bitstrm)\n{\n    UWORD32 u4_total_zeroes;\n    WORD32 i;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 u4_bitstream_offset = ps_bitstrm->u4_ofst;\n    UWORD32 u4_trailing_ones = u4_total_coeff_trail_one & 0xFFFF;\n    UWORD32 u4_total_coeff = u4_total_coeff_trail_one >> 16;\n    // To avoid error check at 4x4 level, allocating for 3 extra levels(16+3)\n    // since u4_trailing_ones can at the max be 3. This will be required when\n    // u4_total_coeff is less than u4_trailing_ones\n    WORD16 ai2_level_arr[19];\n    WORD16 *i2_level_arr = &ai2_level_arr[3];\n\n    tu_sblk4x4_coeff_data_t *ps_tu_4x4;\n    WORD16 *pi2_coeff_data;\n    dec_struct_t *ps_dec = (dec_struct_t *)ps_bitstrm->pv_codec_handle;\n\n    ps_tu_4x4 = (tu_sblk4x4_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n    ps_tu_4x4->u2_sig_coeff_map = 0;\n    pi2_coeff_data = &ps_tu_4x4->ai2_level[0];\n\n    i = u4_total_coeff - 1;\n\n    if(u4_trailing_ones)\n    {\n        /*********************************************************************/\n        /* Decode Trailing Ones                                              */\n        /* read the sign of T1's and put them in level array                 */\n        /*********************************************************************/\n        UWORD32 u4_signs, u4_cnt = u4_trailing_ones;\n        WORD16 (*ppi2_trlone_lkup)[3] =\n                        (WORD16 (*)[3])gai2_ih264d_trailing_one_level;\n        WORD16 *pi2_trlone_lkup;\n\n        GETBITS(u4_signs, u4_bitstream_offset, pu4_bitstrm_buf, u4_cnt);\n\n        pi2_trlone_lkup = ppi2_trlone_lkup[(1 << u4_cnt) - 2 + u4_signs];\n\n        while(u4_cnt)\n        {\n            i2_level_arr[i--] = *pi2_trlone_lkup++;\n            u4_cnt--;\n        }\n    }\n\n    /****************************************************************/\n    /* Decoding Levels Begins                                       */\n    /****************************************************************/\n    if(i >= 0)\n    {\n        /****************************************************************/\n        /* First level is decoded outside the loop as it has lot of     */\n        /* special cases.                                               */\n        /****************************************************************/\n        UWORD32 u4_lev_suffix, u4_suffix_len, u4_lev_suffix_size;\n        WORD32 u2_lev_code, u2_abs_value;\n        UWORD32 u4_lev_prefix;\n\n        /***************************************************************/\n        /* u4_suffix_len = 0,  Find leading zeros in next 32 bits      */\n        /***************************************************************/\n        FIND_ONE_IN_STREAM_32(u4_lev_prefix, u4_bitstream_offset,\n                              pu4_bitstrm_buf);\n\n        /*********************************************************/\n        /* Special decoding case when trailing ones are 3        */\n        /*********************************************************/\n        u2_lev_code = MIN(15, u4_lev_prefix);\n\n        u2_lev_code += (3 == u4_trailing_ones) ? 0 : 2;\n\n        if(14 == u4_lev_prefix)\n            u4_lev_suffix_size = 4;\n        else if(15 <= u4_lev_prefix)\n        {\n            u2_lev_code += 15;\n            u4_lev_suffix_size = u4_lev_prefix - 3;\n        }\n        else\n            u4_lev_suffix_size = 0;\n\n        //HP_LEVEL_PREFIX\n        if(16 <= u4_lev_prefix)\n        {\n            u2_lev_code += ((1 << (u4_lev_prefix - 3)) - 4096);\n        }\n        if(u4_lev_suffix_size)\n        {\n            GETBITS(u4_lev_suffix, u4_bitstream_offset, pu4_bitstrm_buf,\n                    u4_lev_suffix_size);\n            u2_lev_code += u4_lev_suffix;\n        }\n\n        u2_abs_value = (u2_lev_code + 2) >> 1;\n        /*********************************************************/\n        /* If Level code is odd, level is negative else positive */\n        /*********************************************************/\n        i2_level_arr[i--] = (u2_lev_code & 1) ? -u2_abs_value : u2_abs_value;\n\n        u4_suffix_len = (u2_abs_value > 3) ? 2 : 1;\n\n        /*********************************************************/\n        /* Now loop over the remaining levels                    */\n        /*********************************************************/\n        while(i >= 0)\n        {\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            FIND_ONE_IN_STREAM_32(u4_lev_prefix, u4_bitstream_offset,\n                                  pu4_bitstrm_buf);\n\n            u4_lev_suffix_size =\n                            (15 <= u4_lev_prefix) ?\n                                            (u4_lev_prefix - 3) : u4_suffix_len;\n\n            /*********************************************************/\n            /* Compute level code using prefix and suffix            */\n            /*********************************************************/\n            GETBITS(u4_lev_suffix, u4_bitstream_offset, pu4_bitstrm_buf,\n                    u4_lev_suffix_size);\n            u2_lev_code = (MIN(15,u4_lev_prefix) << u4_suffix_len)\n                            + u4_lev_suffix;\n\n            //HP_LEVEL_PREFIX\n            if(16 <= u4_lev_prefix)\n            {\n                u2_lev_code += ((1 << (u4_lev_prefix - 3)) - 4096);\n            }\n            u2_abs_value = (u2_lev_code + 2) >> 1;\n\n            /*********************************************************/\n            /* If Level code is odd, level is negative else positive */\n            /*********************************************************/\n            i2_level_arr[i--] =\n                            (u2_lev_code & 1) ? -u2_abs_value : u2_abs_value;\n\n            /*********************************************************/\n            /* Increment suffix length if required                   */\n            /*********************************************************/\n            u4_suffix_len +=\n                            (u4_suffix_len < 6) ?\n                                            (u2_abs_value\n                                                            > (3\n                                                                            << (u4_suffix_len\n                                                                                            - 1))) :\n                                            0;\n        }\n\n        /****************************************************************/\n        /* Decoding Levels Ends                                         */\n        /****************************************************************/\n    }\n\n    /****************************************************************/\n    /* Decoding total zeros as in section 9.2.3, table 9.7          */\n    /****************************************************************/\n    {\n        UWORD32 u4_index;\n        const UWORD8 (*ppu1_total_zero_lkup)[64] =\n                        (const UWORD8 (*)[64])gau1_ih264d_table_total_zero_2to10;\n\n        NEXTBITS(u4_index, u4_bitstream_offset, pu4_bitstrm_buf, 6);\n        u4_total_zeroes = ppu1_total_zero_lkup[u4_total_coeff - 2][u4_index];\n\n        FLUSHBITS(u4_bitstream_offset, (u4_total_zeroes >> 4));\n        u4_total_zeroes &= 0xf;\n    }\n\n    /**************************************************************/\n    /* Decode the runs and form the coefficient buffer            */\n    /**************************************************************/\n    {\n        const UWORD8 *pu1_table_runbefore;\n        UWORD32 u4_run;\n        WORD32 k;\n        WORD32 u4_scan_pos = u4_total_coeff + u4_total_zeroes - 1 + u4_isdc;\n        WORD32 u4_zeroes_left = u4_total_zeroes;\n        k = u4_total_coeff - 1;\n\n        /**************************************************************/\n        /* Decoding Runs Begin for zeros left > 6                     */\n        /**************************************************************/\n        while((u4_zeroes_left > 6) && k)\n        {\n            UWORD32 u4_code;\n\n            NEXTBITS(u4_code, u4_bitstream_offset, pu4_bitstrm_buf, 3);\n\n            if(u4_code != 0)\n            {\n                FLUSHBITS(u4_bitstream_offset, 3);\n                u4_run = (7 - u4_code);\n            }\n            else\n            {\n\n                FIND_ONE_IN_STREAM_LEN(u4_code, u4_bitstream_offset,\n                                       pu4_bitstrm_buf, 11);\n                u4_run = (4 + u4_code);\n            }\n\n            SET_BIT(ps_tu_4x4->u2_sig_coeff_map, u4_scan_pos);\n            *pi2_coeff_data++ = i2_level_arr[k--];\n            u4_zeroes_left -= (WORD32)u4_run;\n            u4_scan_pos -= (WORD32)(u4_run + 1);\n        }\n\n        if (u4_zeroes_left < 0 || u4_scan_pos < 0)\n            return -1;\n\n        /**************************************************************/\n        /* Decoding Runs for 0 < zeros left <=6                       */\n        /**************************************************************/\n        pu1_table_runbefore = (UWORD8 *)gau1_ih264d_table_run_before;\n        while((u4_zeroes_left > 0) && k)\n        {\n            UWORD32 u4_code;\n            NEXTBITS(u4_code, u4_bitstream_offset, pu4_bitstrm_buf, 3);\n\n            u4_code = pu1_table_runbefore[u4_code + (u4_zeroes_left << 3)];\n            u4_run = u4_code >> 2;\n\n            FLUSHBITS(u4_bitstream_offset, (u4_code & 0x03));\n\n            SET_BIT(ps_tu_4x4->u2_sig_coeff_map, u4_scan_pos);\n            *pi2_coeff_data++ = i2_level_arr[k--];\n            u4_zeroes_left -= (WORD32)u4_run;\n            u4_scan_pos -= (WORD32)(u4_run + 1);\n        }\n        if (u4_zeroes_left < 0 || u4_scan_pos < 0)\n            return -1;\n        /**************************************************************/\n        /* Decoding Runs End                                          */\n        /**************************************************************/\n\n        /**************************************************************/\n        /* Copy the remaining coefficients                            */\n        /**************************************************************/\n        while(k >= 0)\n        {\n\n            SET_BIT(ps_tu_4x4->u2_sig_coeff_map, u4_scan_pos);\n            *pi2_coeff_data++ = i2_level_arr[k--];\n            u4_scan_pos--;\n        }\n    }\n\n    {\n        WORD32 offset;\n        offset = (UWORD8 *)pi2_coeff_data - (UWORD8 *)ps_tu_4x4;\n        offset = ALIGN4(offset);\n        ps_dec->pv_parse_tu_coeff_data = (void *)((UWORD8 *)ps_dec->pv_parse_tu_coeff_data + offset);\n    }\n\n    ps_bitstrm->u4_ofst = u4_bitstream_offset;\n    return 0;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_cavlc_4x4res_block_totalcoeff_11to16                     */\n/*                                                                           */\n/*  Description   : This function does cavlc decoding of 4x4 block residual  */\n/*                  coefficient when total coeffs are greater than ten.      */\n/*                  Parsing is done as defined in section 9.2.2 and 9.2.3 of */\n/*                  the H264 standard.                                       */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         25 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_cavlc_4x4res_block_totalcoeff_11to16(UWORD32 u4_isdc,\n                                                UWORD32 u4_total_coeff_trail_one, /*!<TotalCoefficients<<16+trailingones*/\n                                                dec_bit_stream_t *ps_bitstrm )\n{\n    UWORD32 u4_total_zeroes;\n    WORD32 i;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 u4_bitstream_offset = ps_bitstrm->u4_ofst;\n    UWORD32 u4_trailing_ones = u4_total_coeff_trail_one & 0xFFFF;\n    UWORD32 u4_total_coeff = u4_total_coeff_trail_one >> 16;\n    // To avoid error check at 4x4 level, allocating for 3 extra levels(16+3)\n    // since u4_trailing_ones can at the max be 3. This will be required when\n    // u4_total_coeff is less than u4_trailing_ones\n    WORD16 ai2_level_arr[19];//\n    WORD16 *i2_level_arr = &ai2_level_arr[3];\n\n    tu_sblk4x4_coeff_data_t *ps_tu_4x4;\n    WORD16 *pi2_coeff_data;\n    dec_struct_t *ps_dec = (dec_struct_t *)ps_bitstrm->pv_codec_handle;\n\n    ps_tu_4x4 = (tu_sblk4x4_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n    ps_tu_4x4->u2_sig_coeff_map = 0;\n    pi2_coeff_data = &ps_tu_4x4->ai2_level[0];\n\n    i = u4_total_coeff - 1;\n    if(u4_trailing_ones)\n    {\n        /*********************************************************************/\n        /* Decode Trailing Ones                                              */\n        /* read the sign of T1's and put them in level array                 */\n        /*********************************************************************/\n        UWORD32 u4_signs, u4_cnt = u4_trailing_ones;\n        WORD16 (*ppi2_trlone_lkup)[3] =\n                        (WORD16 (*)[3])gai2_ih264d_trailing_one_level;\n        WORD16 *pi2_trlone_lkup;\n\n        GETBITS(u4_signs, u4_bitstream_offset, pu4_bitstrm_buf, u4_cnt);\n\n        pi2_trlone_lkup = ppi2_trlone_lkup[(1 << u4_cnt) - 2 + u4_signs];\n\n        while(u4_cnt)\n        {\n            i2_level_arr[i--] = *pi2_trlone_lkup++;\n            u4_cnt--;\n        }\n    }\n\n    /****************************************************************/\n    /* Decoding Levels Begins                                       */\n    /****************************************************************/\n    if(i >= 0)\n    {\n        /****************************************************************/\n        /* First level is decoded outside the loop as it has lot of     */\n        /* special cases.                                               */\n        /****************************************************************/\n        UWORD32 u4_lev_suffix, u4_suffix_len, u4_lev_suffix_size;\n        UWORD16 u2_lev_code, u2_abs_value;\n        UWORD32 u4_lev_prefix;\n\n        if(u4_trailing_ones < 3)\n        {\n            /*********************************************************/\n            /* u4_suffix_len = 1                                     */\n            /*********************************************************/\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            FIND_ONE_IN_STREAM_32(u4_lev_prefix, u4_bitstream_offset,\n                                  pu4_bitstrm_buf);\n\n            u4_lev_suffix_size =\n                            (15 <= u4_lev_prefix) ? (u4_lev_prefix - 3) : 1;\n\n            GETBITS(u4_lev_suffix, u4_bitstream_offset, pu4_bitstrm_buf,\n                    u4_lev_suffix_size);\n            u2_lev_code = 2 + (MIN(u4_lev_prefix,15) << 1) + u4_lev_suffix;\n\n            //HP_LEVEL_PREFIX\n            if(16 <= u4_lev_prefix)\n            {\n                u2_lev_code += ((1 << (u4_lev_prefix - 3)) - 4096);\n            }\n        }\n        else\n        {\n            /*********************************************************/\n            /*u4_suffix_len = 0                                      */\n            /*********************************************************/\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            FIND_ONE_IN_STREAM_32(u4_lev_prefix, u4_bitstream_offset,\n                                  pu4_bitstrm_buf);\n\n            /*********************************************************/\n            /* Special decoding case when trailing ones are 3        */\n            /*********************************************************/\n            u2_lev_code = MIN(15, u4_lev_prefix);\n\n            u2_lev_code += (3 == u4_trailing_ones) ? 0 : (2);\n\n            if(14 == u4_lev_prefix)\n                u4_lev_suffix_size = 4;\n            else if(15 <= u4_lev_prefix)\n            {\n                u2_lev_code += 15;\n                u4_lev_suffix_size = (u4_lev_prefix - 3);\n            }\n            else\n                u4_lev_suffix_size = 0;\n\n            //HP_LEVEL_PREFIX\n            if(16 <= u4_lev_prefix)\n            {\n                u2_lev_code += ((1 << (u4_lev_prefix - 3)) - 4096);\n            }\n            if(u4_lev_suffix_size)\n            {\n                GETBITS(u4_lev_suffix, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_lev_suffix_size);\n                u2_lev_code += u4_lev_suffix;\n            }\n        }\n\n        u2_abs_value = (u2_lev_code + 2) >> 1;\n        /*********************************************************/\n        /* If Level code is odd, level is negative else positive */\n        /*********************************************************/\n        i2_level_arr[i--] = (u2_lev_code & 1) ? -u2_abs_value : u2_abs_value;\n\n        u4_suffix_len = (u2_abs_value > 3) ? 2 : 1;\n\n        /*********************************************************/\n        /* Now loop over the remaining levels                    */\n        /*********************************************************/\n        while(i >= 0)\n        {\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            FIND_ONE_IN_STREAM_32(u4_lev_prefix, u4_bitstream_offset,\n                                  pu4_bitstrm_buf);\n\n            u4_lev_suffix_size =\n                            (15 <= u4_lev_prefix) ?\n                                            (u4_lev_prefix - 3) : u4_suffix_len;\n\n            /*********************************************************/\n            /* Compute level code using prefix and suffix            */\n            /*********************************************************/\n            GETBITS(u4_lev_suffix, u4_bitstream_offset, pu4_bitstrm_buf,\n                    u4_lev_suffix_size);\n            u2_lev_code = (MIN(15,u4_lev_prefix) << u4_suffix_len)\n                            + u4_lev_suffix;\n\n            //HP_LEVEL_PREFIX\n            if(16 <= u4_lev_prefix)\n            {\n                u2_lev_code += ((1 << (u4_lev_prefix - 3)) - 4096);\n            }\n            u2_abs_value = (u2_lev_code + 2) >> 1;\n\n            /*********************************************************/\n            /* If Level code is odd, level is negative else positive */\n            /*********************************************************/\n            i2_level_arr[i--] =\n                            (u2_lev_code & 1) ? -u2_abs_value : u2_abs_value;\n\n            /*********************************************************/\n            /* Increment suffix length if required                   */\n            /*********************************************************/\n            u4_suffix_len +=\n                            (u4_suffix_len < 6) ?\n                                            (u2_abs_value\n                                                            > (3\n                                                                            << (u4_suffix_len\n                                                                                            - 1))) :\n                                            0;\n        }\n\n        /****************************************************************/\n        /* Decoding Levels Ends                                         */\n        /****************************************************************/\n    }\n\n    if(u4_total_coeff < (16 - u4_isdc))\n    {\n        UWORD32 u4_index;\n        const UWORD8 (*ppu1_total_zero_lkup)[16] =\n                        (const UWORD8 (*)[16])gau1_ih264d_table_total_zero_11to15;\n\n        NEXTBITS(u4_index, u4_bitstream_offset, pu4_bitstrm_buf, 4);\n        u4_total_zeroes = ppu1_total_zero_lkup[u4_total_coeff - 11][u4_index];\n\n        FLUSHBITS(u4_bitstream_offset, (u4_total_zeroes >> 4));\n        u4_total_zeroes &= 0xf;\n    }\n    else\n        u4_total_zeroes = 0;\n\n    /**************************************************************/\n    /* Decode the runs and form the coefficient buffer            */\n    /**************************************************************/\n    {\n        const UWORD8 *pu1_table_runbefore;\n        UWORD32 u4_run;\n        WORD32 k;\n        WORD32 u4_scan_pos = u4_total_coeff + u4_total_zeroes - 1 + u4_isdc;\n        WORD32 u4_zeroes_left = u4_total_zeroes;\n        k = u4_total_coeff - 1;\n\n        /**************************************************************/\n        /* Decoding Runs for 0 < zeros left <=6                       */\n        /**************************************************************/\n        pu1_table_runbefore = (UWORD8 *)gau1_ih264d_table_run_before;\n        while((u4_zeroes_left > 0) && k)\n        {\n            UWORD32 u4_code;\n            NEXTBITS(u4_code, u4_bitstream_offset, pu4_bitstrm_buf, 3);\n\n            u4_code = pu1_table_runbefore[u4_code + (u4_zeroes_left << 3)];\n            u4_run = u4_code >> 2;\n\n            FLUSHBITS(u4_bitstream_offset, (u4_code & 0x03));\n            SET_BIT(ps_tu_4x4->u2_sig_coeff_map, u4_scan_pos);\n            *pi2_coeff_data++ = i2_level_arr[k--];\n            u4_zeroes_left -= (WORD32)u4_run;\n            u4_scan_pos -= (WORD32)(u4_run + 1);\n        }\n        if (u4_zeroes_left < 0 || u4_scan_pos < 0)\n          return -1;\n\n        /**************************************************************/\n        /* Decoding Runs End                                          */\n        /**************************************************************/\n\n        /**************************************************************/\n        /* Copy the remaining coefficients                            */\n        /**************************************************************/\n        while(k >= 0)\n        {\n            SET_BIT(ps_tu_4x4->u2_sig_coeff_map, u4_scan_pos);\n            *pi2_coeff_data++ = i2_level_arr[k--];\n            u4_scan_pos--;\n        }\n    }\n\n    {\n        WORD32 offset;\n        offset = (UWORD8 *)pi2_coeff_data - (UWORD8 *)ps_tu_4x4;\n        offset = ALIGN4(offset);\n        ps_dec->pv_parse_tu_coeff_data = (void *)((UWORD8 *)ps_dec->pv_parse_tu_coeff_data + offset);\n    }\n\n    ps_bitstrm->u4_ofst = u4_bitstream_offset;\n    return 0;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_rest_of_residual_cav_chroma_dc_block              */\n/*                                                                           */\n/*  Description   : This function does the Cavlc parsing of the bitstream    */\n/*                  for chroma dc coefficients                               */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         15 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_rest_of_residual_cav_chroma_dc_block(UWORD32 u4_total_coeff_trail_one,\n                                                 dec_bit_stream_t *ps_bitstrm)\n{\n    UWORD32 u4_total_zeroes;\n    WORD16 i;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 u4_bitstream_offset = ps_bitstrm->u4_ofst;\n    UWORD32 u4_trailing_ones = u4_total_coeff_trail_one & 0xFFFF;\n    UWORD32 u4_total_coeff = u4_total_coeff_trail_one >> 16;\n    // To avoid error check at 4x4 level, allocating for 3 extra levels(4+3)\n    // since u4_trailing_ones can at the max be 3. This will be required when\n    // u4_total_coeff is less than u4_trailing_ones\n    WORD16 ai2_level_arr[7];//\n    WORD16 *i2_level_arr = &ai2_level_arr[3];\n\n    tu_sblk4x4_coeff_data_t *ps_tu_4x4;\n    WORD16 *pi2_coeff_data;\n    dec_struct_t *ps_dec = (dec_struct_t *)ps_bitstrm->pv_codec_handle;\n\n    ps_tu_4x4 = (tu_sblk4x4_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n    ps_tu_4x4->u2_sig_coeff_map = 0;\n    pi2_coeff_data = &ps_tu_4x4->ai2_level[0];\n\n    i = u4_total_coeff - 1;\n    if(u4_trailing_ones)\n    {\n        /*********************************************************************/\n        /* Decode Trailing Ones                                              */\n        /* read the sign of T1's and put them in level array                 */\n        /*********************************************************************/\n        UWORD32 u4_signs, u4_cnt = u4_trailing_ones;\n        WORD16 (*ppi2_trlone_lkup)[3] =\n                        (WORD16 (*)[3])gai2_ih264d_trailing_one_level;\n        WORD16 *pi2_trlone_lkup;\n\n        GETBITS(u4_signs, u4_bitstream_offset, pu4_bitstrm_buf, u4_cnt);\n\n        pi2_trlone_lkup = ppi2_trlone_lkup[(1 << u4_cnt) - 2 + u4_signs];\n\n        while(u4_cnt)\n        {\n            i2_level_arr[i--] = *pi2_trlone_lkup++;\n            u4_cnt--;\n        }\n    }\n\n    /****************************************************************/\n    /* Decoding Levels Begins                                       */\n    /****************************************************************/\n    if(i >= 0)\n    {\n        /****************************************************************/\n        /* First level is decoded outside the loop as it has lot of     */\n        /* special cases.                                               */\n        /****************************************************************/\n        UWORD32 u4_lev_suffix, u4_suffix_len, u4_lev_suffix_size;\n        UWORD16 u2_lev_code, u2_abs_value;\n        UWORD32 u4_lev_prefix;\n\n        /***************************************************************/\n        /* u4_suffix_len = 0,  Find leading zeros in next 32 bits      */\n        /***************************************************************/\n        FIND_ONE_IN_STREAM_32(u4_lev_prefix, u4_bitstream_offset,\n                              pu4_bitstrm_buf);\n\n        /*********************************************************/\n        /* Special decoding case when trailing ones are 3        */\n        /*********************************************************/\n        u2_lev_code = MIN(15, u4_lev_prefix);\n\n        u2_lev_code += (3 == u4_trailing_ones) ? 0 : (2);\n\n        if(14 == u4_lev_prefix)\n            u4_lev_suffix_size = 4;\n        else if(15 <= u4_lev_prefix)\n        {\n            u2_lev_code += 15;\n            u4_lev_suffix_size = u4_lev_prefix - 3;\n        }\n        else\n            u4_lev_suffix_size = 0;\n\n        //HP_LEVEL_PREFIX\n        if(16 <= u4_lev_prefix)\n        {\n            u2_lev_code += ((1 << (u4_lev_prefix - 3)) - 4096);\n        }\n        if(u4_lev_suffix_size)\n        {\n            GETBITS(u4_lev_suffix, u4_bitstream_offset, pu4_bitstrm_buf,\n                    u4_lev_suffix_size);\n            u2_lev_code += u4_lev_suffix;\n        }\n\n        u2_abs_value = (u2_lev_code + 2) >> 1;\n        /*********************************************************/\n        /* If Level code is odd, level is negative else positive */\n        /*********************************************************/\n        i2_level_arr[i--] = (u2_lev_code & 1) ? -u2_abs_value : u2_abs_value;\n\n        u4_suffix_len = (u2_abs_value > 3) ? 2 : 1;\n\n        /*********************************************************/\n        /* Now loop over the remaining levels                    */\n        /*********************************************************/\n        while(i >= 0)\n        {\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            FIND_ONE_IN_STREAM_32(u4_lev_prefix, u4_bitstream_offset,\n                                  pu4_bitstrm_buf);\n\n            u4_lev_suffix_size =\n                            (15 <= u4_lev_prefix) ?\n                                            (u4_lev_prefix - 3) : u4_suffix_len;\n\n            /*********************************************************/\n            /* Compute level code using prefix and suffix            */\n            /*********************************************************/\n            GETBITS(u4_lev_suffix, u4_bitstream_offset, pu4_bitstrm_buf,\n                    u4_lev_suffix_size);\n            u2_lev_code = (MIN(u4_lev_prefix,15) << u4_suffix_len)\n                            + u4_lev_suffix;\n\n            //HP_LEVEL_PREFIX\n            if(16 <= u4_lev_prefix)\n            {\n                u2_lev_code += ((1 << (u4_lev_prefix - 3)) - 4096);\n            }\n            u2_abs_value = (u2_lev_code + 2) >> 1;\n\n            /*********************************************************/\n            /* If Level code is odd, level is negative else positive */\n            /*********************************************************/\n            i2_level_arr[i--] =\n                            (u2_lev_code & 1) ? -u2_abs_value : u2_abs_value;\n\n            /*********************************************************/\n            /* Increment suffix length if required                   */\n            /*********************************************************/\n            u4_suffix_len += (u2_abs_value > (3 << (u4_suffix_len - 1)));\n        }\n\n        /****************************************************************/\n        /* Decoding Levels Ends                                         */\n        /****************************************************************/\n    }\n\n    if(u4_total_coeff < 4)\n    {\n        UWORD32 u4_max_ldz = (4 - u4_total_coeff);\n        FIND_ONE_IN_STREAM_LEN(u4_total_zeroes, u4_bitstream_offset,\n                               pu4_bitstrm_buf, u4_max_ldz);\n    }\n    else\n        u4_total_zeroes = 0;\n\n    /**************************************************************/\n    /* Decode the runs and form the coefficient buffer            */\n    /**************************************************************/\n    {\n        const UWORD8 *pu1_table_runbefore;\n        UWORD32 u4_run;\n        WORD32 u4_scan_pos = (u4_total_coeff + u4_total_zeroes - 1);\n        UWORD32 u4_zeroes_left = u4_total_zeroes;\n        i = u4_total_coeff - 1;\n\n        /**************************************************************/\n        /* Decoding Runs for 0 < zeros left <=6                       */\n        /**************************************************************/\n        pu1_table_runbefore = (UWORD8 *)gau1_ih264d_table_run_before;\n        while(u4_zeroes_left && i)\n        {\n            UWORD32 u4_code;\n            NEXTBITS(u4_code, u4_bitstream_offset, pu4_bitstrm_buf, 3);\n\n            u4_code = pu1_table_runbefore[u4_code + (u4_zeroes_left << 3)];\n            u4_run = u4_code >> 2;\n\n            FLUSHBITS(u4_bitstream_offset, (u4_code & 0x03));\n            SET_BIT(ps_tu_4x4->u2_sig_coeff_map, u4_scan_pos);\n            *pi2_coeff_data++ = i2_level_arr[i--];\n            u4_zeroes_left -= (WORD32)u4_run;\n            u4_scan_pos -= (WORD32)(u4_run + 1);\n        }\n        /**************************************************************/\n        /* Decoding Runs End                                          */\n        /**************************************************************/\n\n        /**************************************************************/\n        /* Copy the remaining coefficients                            */\n        /**************************************************************/\n        while(i >= 0)\n        {\n            SET_BIT(ps_tu_4x4->u2_sig_coeff_map, u4_scan_pos);\n            *pi2_coeff_data++ = i2_level_arr[i--];\n            u4_scan_pos--;\n        }\n    }\n\n    {\n        WORD32 offset;\n        offset = (UWORD8 *)pi2_coeff_data - (UWORD8 *)ps_tu_4x4;\n        offset = ALIGN4(offset);\n        ps_dec->pv_parse_tu_coeff_data = (void *)((UWORD8 *)ps_dec->pv_parse_tu_coeff_data + offset);\n    }\n\n    ps_bitstrm->u4_ofst = u4_bitstream_offset;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : CavlcParsingInvScanInvQuant \\endif\n *\n * \\brief\n *    This function do cavlc parsing of coefficient tokens for any block\n *    type except chromDc and depending\n *    on whenther any coefficients to be parsed calls module\n *    RestOfResidualBlockCavlc.\n *\n * \\return\n *    Returns total number of non-zero coefficients.\n *\n **************************************************************************\n */\n\nWORD32 ih264d_cavlc_parse4x4coeff_n0to7(WORD16 *pi2_coeff_block,\n                                        UWORD32 u4_isdc, /* is it a DC block */\n                                        WORD32 u4_n,\n                                        dec_struct_t *ps_dec,\n                                        UWORD32 *pu4_total_coeff)\n{\n    dec_bit_stream_t *ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 u4_bitstream_offset = ps_bitstrm->u4_ofst;\n    UWORD32 u4_code, u4_index, u4_ldz;\n    const UWORD16 *pu2_code = (const UWORD16*)gau2_ih264d_code_gx;\n    const UWORD16 *pu2_offset_num_vlc =\n                    (const UWORD16 *)gau2_ih264d_offset_num_vlc_tab;\n    UWORD32 u4_offset_num_vlc = pu2_offset_num_vlc[u4_n];\n\n\n    UNUSED(pi2_coeff_block);\n    *pu4_total_coeff = 0;\n    FIND_ONE_IN_STREAM_32(u4_ldz, u4_bitstream_offset, pu4_bitstrm_buf);\n    NEXTBITS(u4_index, u4_bitstream_offset, pu4_bitstrm_buf, 3);\n    u4_index += (u4_ldz << 3);\n    u4_index += u4_offset_num_vlc;\n\n    u4_index = MIN(u4_index, 303);\n    u4_code = pu2_code[u4_index];\n\n    FLUSHBITS(u4_bitstream_offset, (u4_code & 0x03));\n    ps_bitstrm->u4_ofst = u4_bitstream_offset;\n    *pu4_total_coeff = (u4_code >> 4);\n\n    if(*pu4_total_coeff)\n    {\n        UWORD32 u4_trailing_ones, u4_offset, u4_total_coeff_tone;\n        const UWORD8 *pu1_offset =\n                        (UWORD8 *)gau1_ih264d_total_coeff_fn_ptr_offset;\n        WORD32 ret;\n        u4_trailing_ones = ((u4_code >> 2) & 0x03);\n        u4_offset = pu1_offset[*pu4_total_coeff - 1];\n        u4_total_coeff_tone = (*pu4_total_coeff << 16) | u4_trailing_ones;\n\n        ret = ps_dec->pf_cavlc_4x4res_block[u4_offset](u4_isdc,\n                                                       u4_total_coeff_tone,\n                                                       ps_bitstrm);\n        if(ret != 0)\n            return ERROR_CAVLC_NUM_COEFF_T;\n    }\n\n    return OK;\n}\n\nWORD32 ih264d_cavlc_parse4x4coeff_n8(WORD16 *pi2_coeff_block,\n                                     UWORD32 u4_isdc, /* is it a DC block */\n                                     WORD32 u4_n,\n                                     dec_struct_t *ps_dec,\n                                     UWORD32 *pu4_total_coeff)\n{\n\n    dec_bit_stream_t *ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 u4_bitstream_offset = ps_bitstrm->u4_ofst;\n    UWORD32 u4_code;\n    UNUSED(u4_n);\n    UNUSED(pi2_coeff_block);\n    GETBITS(u4_code, u4_bitstream_offset, pu4_bitstrm_buf, 6);\n    ps_bitstrm->u4_ofst = u4_bitstream_offset;\n    *pu4_total_coeff = 0;\n\n    if(u4_code != 3)\n    {\n        UWORD8 *pu1_offset = (UWORD8 *)gau1_ih264d_total_coeff_fn_ptr_offset;\n        UWORD32 u4_trailing_ones, u4_offset, u4_total_coeff_tone;\n\n        *pu4_total_coeff = (u4_code >> 2) + 1;\n        u4_trailing_ones = u4_code & 0x03;\n        u4_offset = pu1_offset[*pu4_total_coeff - 1];\n        u4_total_coeff_tone = (*pu4_total_coeff << 16) | u4_trailing_ones;\n\n        ps_dec->pf_cavlc_4x4res_block[u4_offset](u4_isdc,\n                                                 u4_total_coeff_tone,\n                                                 ps_bitstrm);\n    }\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_cavlc_parse_chroma_dc \\endif\n *\n * \\brief\n *    This function do cavlc parsing of coefficient tokens chromDc block\n *    and depending  on whenther any coefficients to be parsed calls module\n *    ih264d_rest_of_residual_cav_chroma_dc_block.\n *\n * \\return\n *    Returns total number of non-zero coefficients.\n *\n **************************************************************************\n */\n\nvoid ih264d_cavlc_parse_chroma_dc(dec_mb_info_t *ps_cur_mb_info,\n                                  WORD16 *pi2_coeff_block,\n                                  dec_bit_stream_t *ps_bitstrm,\n                                  UWORD32 u4_scale_u,\n                                  UWORD32 u4_scale_v,\n                                  WORD32 i4_mb_inter_inc)\n{\n    UWORD32 u4_total_coeff, u4_trailing_ones, u4_total_coeff_tone, u4_code;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 u4_bitstream_offset = ps_bitstrm->u4_ofst;\n    const UWORD8 *pu1_cav_chromdc = (const UWORD8*)gau1_ih264d_cav_chromdc_vld;\n    UNUSED(i4_mb_inter_inc);\n    /******************************************************************/\n    /*  Chroma DC Block for U component                               */\n    /******************************************************************/\n    NEXTBITS(u4_code, u4_bitstream_offset, pu4_bitstrm_buf, 8);\n\n    u4_code = pu1_cav_chromdc[u4_code];\n\n    FLUSHBITS(u4_bitstream_offset, ((u4_code & 0x7) + 1));\n    ps_bitstrm->u4_ofst = u4_bitstream_offset;\n\n    u4_total_coeff = (u4_code >> 5);\n\n    if(u4_total_coeff)\n    {\n        WORD32 i_z0, i_z1, i_z2, i_z3;\n        tu_sblk4x4_coeff_data_t *ps_tu_4x4;\n        dec_struct_t *ps_dec = (dec_struct_t *)ps_bitstrm->pv_codec_handle;\n        WORD16 ai2_dc_coef[4];\n        UWORD8 pu1_inv_scan[4] =\n                        { 0, 1, 2, 3 };\n        WORD16 *pi2_coeff_data =\n                                    (WORD16 *)ps_dec->pv_parse_tu_coeff_data;\n\n        ps_tu_4x4 = (tu_sblk4x4_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n\n        u4_trailing_ones = ((u4_code >> 3) & 0x3);\n        u4_total_coeff_tone = (u4_total_coeff << 16) | u4_trailing_ones;\n        ih264d_rest_of_residual_cav_chroma_dc_block(u4_total_coeff_tone,\n                                                    ps_bitstrm);\n\n        ai2_dc_coef[0] = 0;\n        ai2_dc_coef[1] = 0;\n        ai2_dc_coef[2] = 0;\n        ai2_dc_coef[3] = 0;\n\n        ih264d_unpack_coeff4x4_dc_4x4blk(ps_tu_4x4,\n                                         ai2_dc_coef,\n                                         pu1_inv_scan);\n        /*-------------------------------------------------------------------*/\n        /* Inverse 2x2 transform and scaling  of chroma DC                   */\n        /*-------------------------------------------------------------------*/\n        i_z0 = (ai2_dc_coef[0] + ai2_dc_coef[2]);\n        i_z1 = (ai2_dc_coef[0] - ai2_dc_coef[2]);\n        i_z2 = (ai2_dc_coef[1] - ai2_dc_coef[3]);\n        i_z3 = (ai2_dc_coef[1] + ai2_dc_coef[3]);\n\n        /*-----------------------------------------------------------*/\n        /* Scaling and storing the values back                       */\n        /*-----------------------------------------------------------*/\n        *pi2_coeff_data++ = (WORD16)(((i_z0 + i_z3) * (WORD32)u4_scale_u) >> 5);\n        *pi2_coeff_data++ = (WORD16)(((i_z0 - i_z3) * (WORD32)u4_scale_u) >> 5);\n        *pi2_coeff_data++ = (WORD16)(((i_z1 + i_z2) * (WORD32)u4_scale_u) >> 5);\n        *pi2_coeff_data++ = (WORD16)(((i_z1 - i_z2) * (WORD32)u4_scale_u) >> 5);\n\n        ps_dec->pv_parse_tu_coeff_data = (void *)pi2_coeff_data;\n\n        SET_BIT(ps_cur_mb_info->u1_yuv_dc_block_flag,1);\n    }\n\n    /******************************************************************/\n    /*  Chroma DC Block for V component                               */\n    /******************************************************************/\n    pi2_coeff_block += 64;\n    u4_bitstream_offset = ps_bitstrm->u4_ofst;\n\n    NEXTBITS(u4_code, u4_bitstream_offset, pu4_bitstrm_buf, 8);\n\n    u4_code = pu1_cav_chromdc[u4_code];\n\n    FLUSHBITS(u4_bitstream_offset, ((u4_code & 0x7) + 1));\n    ps_bitstrm->u4_ofst = u4_bitstream_offset;\n\n    u4_total_coeff = (u4_code >> 5);\n\n    if(u4_total_coeff)\n    {\n        WORD32 i_z0, i_z1, i_z2, i_z3;\n        tu_sblk4x4_coeff_data_t *ps_tu_4x4;\n        dec_struct_t *ps_dec = (dec_struct_t *)ps_bitstrm->pv_codec_handle;\n        WORD16 ai2_dc_coef[4];\n        UWORD8 pu1_inv_scan[4] =\n                        { 0, 1, 2, 3 };\n        WORD16 *pi2_coeff_data =\n                                    (WORD16 *)ps_dec->pv_parse_tu_coeff_data;\n\n        ps_tu_4x4 = (tu_sblk4x4_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n\n        u4_trailing_ones = ((u4_code >> 3) & 0x3);\n        u4_total_coeff_tone = (u4_total_coeff << 16) | u4_trailing_ones;\n        ih264d_rest_of_residual_cav_chroma_dc_block(u4_total_coeff_tone,\n                                                    ps_bitstrm);\n\n        ai2_dc_coef[0] = 0;\n        ai2_dc_coef[1] = 0;\n        ai2_dc_coef[2] = 0;\n        ai2_dc_coef[3] = 0;\n\n        ih264d_unpack_coeff4x4_dc_4x4blk(ps_tu_4x4,\n                                         ai2_dc_coef,\n                                         pu1_inv_scan);\n\n        /*-------------------------------------------------------------------*/\n        /* Inverse 2x2 transform and scaling  of chroma DC                   */\n        /*-------------------------------------------------------------------*/\n        i_z0 = (ai2_dc_coef[0] + ai2_dc_coef[2]);\n        i_z1 = (ai2_dc_coef[0] - ai2_dc_coef[2]);\n        i_z2 = (ai2_dc_coef[1] - ai2_dc_coef[3]);\n        i_z3 = (ai2_dc_coef[1] + ai2_dc_coef[3]);\n\n        /*-----------------------------------------------------------*/\n        /* Scaling and storing the values back                       */\n        /*-----------------------------------------------------------*/\n        *pi2_coeff_data++ = (WORD16)(((i_z0 + i_z3) * (WORD32)u4_scale_v) >> 5);\n        *pi2_coeff_data++ = (WORD16)(((i_z0 - i_z3) * (WORD32)u4_scale_v) >> 5);\n        *pi2_coeff_data++ = (WORD16)(((i_z1 + i_z2) * (WORD32)u4_scale_v) >> 5);\n        *pi2_coeff_data++ = (WORD16)(((i_z1 - i_z2) * (WORD32)u4_scale_v) >> 5);\n\n        ps_dec->pv_parse_tu_coeff_data = (void *)pi2_coeff_data;\n\n        SET_BIT(ps_cur_mb_info->u1_yuv_dc_block_flag,2);\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_pmb_ref_index_cavlc_range1                         */\n/*                                                                           */\n/*  Description   : This function does the Cavlc  TEV range =1 parsing of    */\n/*                  reference index  for a P MB. Range is 1 when             */\n/*                  num_ref_idx_active_minus1 is 0                           */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         19 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_parse_pmb_ref_index_cavlc_range1(UWORD32 u4_num_part, /* Number of partitions in MB      */\n                                             dec_bit_stream_t *ps_bitstrm, /* Pointer to bitstream Structure. */\n                                             WORD8 *pi1_ref_idx, /* pointer to reference index array */\n                                             UWORD32 u4_num_ref_idx_active_minus1 /* Not used for range 1    */\n                                             )\n{\n    UWORD32 u4_i;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstream_off = &ps_bitstrm->u4_ofst;\n    UNUSED(u4_num_ref_idx_active_minus1);\n    for(u4_i = 0; u4_i < u4_num_part; u4_i++)\n    {\n        UWORD32 u4_ref_idx;\n        u4_ref_idx = ih264d_tev_range1(pu4_bitstream_off, pu4_bitstrm_buf);\n\n        /* Storing Reference Idx Information */\n        pi1_ref_idx[u4_i] = (WORD8)u4_ref_idx;\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_pmb_ref_index_cavlc                                */\n/*                                                                           */\n/*  Description   : This function does the Cavlc  TEV range > 1 parsing of   */\n/*                  reference index  for a P MB.                             */\n/*                  Range > 1 when num_ref_idx_active_minus1 > 0             */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         19 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_parse_pmb_ref_index_cavlc(UWORD32 u4_num_part, /* Number of partitions in MB      */\n                                      dec_bit_stream_t *ps_bitstrm, /* Pointer to bitstream Structure. */\n                                      WORD8 *pi1_ref_idx, /* pointer to reference index array */\n                                      UWORD32 u4_num_ref_idx_active_minus1 /* Number of active references - 1  */\n                                      )\n{\n    UWORD32 u4_i;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstream_off = &ps_bitstrm->u4_ofst;\n\n    for(u4_i = 0; u4_i < u4_num_part; u4_i++)\n    {\n        UWORD32 u4_ref_idx;\n//Inlined ih264d_uev\n        UWORD32 u4_bitstream_offset = *pu4_bitstream_off;\n        UWORD32 u4_word, u4_ldz;\n\n        /***************************************************************/\n        /* Find leading zeros in next 32 bits                          */\n        /***************************************************************/\n        NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n        u4_ldz = CLZ(u4_word);\n        /* Flush the ps_bitstrm */\n        u4_bitstream_offset += (u4_ldz + 1);\n        /* Read the suffix from the ps_bitstrm */\n        u4_word = 0;\n        if(u4_ldz)\n            GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf, u4_ldz);\n        *pu4_bitstream_off = u4_bitstream_offset;\n        u4_ref_idx = ((1 << u4_ldz) + u4_word - 1);\n//Inlined ih264d_uev\n\n        if(u4_ref_idx > u4_num_ref_idx_active_minus1)\n            return ERROR_REF_IDX;\n\n        /* Storing Reference Idx Information */\n        pi1_ref_idx[u4_i] = (WORD8)u4_ref_idx;\n    }\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_bmb_ref_index_cavlc_range1                         */\n/*                                                                           */\n/*  Description   : This function does the Cavlc  TEV range =1 parsing of    */\n/*                  reference index  for a B MB. Range is 1 when             */\n/*                  num_ref_idx_active_minus1 is 0                           */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         19 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_parse_bmb_ref_index_cavlc_range1(UWORD32 u4_num_part, /* Number of partitions in MB      */\n                                             dec_bit_stream_t *ps_bitstrm, /* Pointer to bitstream Structure. */\n                                             WORD8 *pi1_ref_idx, /* pointer to reference index array */\n                                             UWORD32 u4_num_ref_idx_active_minus1 /* Not used for range 1    */\n                                             )\n{\n    UWORD32 u4_i;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstream_off = &ps_bitstrm->u4_ofst;\n    UNUSED(u4_num_ref_idx_active_minus1);\n    for(u4_i = 0; u4_i < u4_num_part; u4_i++)\n    {\n        if(pi1_ref_idx[u4_i] > -1)\n        {\n            UWORD32 u4_ref_idx;\n\n            u4_ref_idx = ih264d_tev_range1(pu4_bitstream_off, pu4_bitstrm_buf);\n\n            /* Storing Reference Idx Information */\n            pi1_ref_idx[u4_i] = (WORD8)u4_ref_idx;\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_bmb_ref_index_cavlc                                */\n/*                                                                           */\n/*  Description   : This function does the Cavlc  TEV range > 1 parsing of   */\n/*                  reference index  for a B MB.                             */\n/*                  Range > 1 when num_ref_idx_active_minus1 > 0             */\n/*                                                                           */\n/*  Inputs        : <What inputs does the function take?>                    */\n/*  Globals       : <Does it use any global variables?>                      */\n/*  Processing    : <Describe how the function operates - include algorithm  */\n/*                  description>                                             */\n/*  Outputs       : <What does the function produce?>                        */\n/*  Returns       : <What does the function return?>                         */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         19 09 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_bmb_ref_index_cavlc(UWORD32 u4_num_part, /* Number of partitions in MB      */\n                                      dec_bit_stream_t *ps_bitstrm, /* Pointer to bitstream Structure. */\n                                      WORD8 *pi1_ref_idx, /* pointer to reference index array */\n                                      UWORD32 u4_num_ref_idx_active_minus1 /* Number of active references - 1  */\n                                      )\n{\n    UWORD32 u4_i;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstream_off = &ps_bitstrm->u4_ofst;\n\n    for(u4_i = 0; u4_i < u4_num_part; u4_i++)\n    {\n        if(pi1_ref_idx[u4_i] > -1)\n        {\n            UWORD32 u4_ref_idx;\n//inlining ih264d_uev\n            UWORD32 u4_bitstream_offset = *pu4_bitstream_off;\n            UWORD32 u4_word, u4_ldz;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n            u4_ldz = CLZ(u4_word);\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf, u4_ldz);\n            *pu4_bitstream_off = u4_bitstream_offset;\n            u4_ref_idx = ((1 << u4_ldz) + u4_word - 1);\n//inlining ih264d_uev\n            if(u4_ref_idx > u4_num_ref_idx_active_minus1)\n                return ERROR_REF_IDX;\n\n            /* Storing Reference Idx Information */\n            pi1_ref_idx[u4_i] = (WORD8)u4_ref_idx;\n        }\n    }\n    return OK;\n}\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_cavlc_parse_8x8block_both_available                      */\n/*                                                                           */\n/*  Description   : This function does the residual parsing of 4 subblocks   */\n/*                  in a 8x8 block when both top and left are available      */\n/*                                                                           */\n/*  Inputs        : pi2_coeff_block : pointer to residual block where        */\n/*                  decoded and inverse scan coefficients are updated        */\n/*                                                                           */\n/*                  u4_sub_block_strd : indicates the number of sublocks    */\n/*                  in a row. It is 4 for luma and 2 for chroma.             */\n/*                                                                           */\n/*                  u4_isdc : required to indicate 4x4 parse modules if the  */\n/*                  current  Mb is I_16x16/chroma DC coded.                  */\n/*                                                                           */\n/*                  ps_dec : pointer to Decstruct (decoder context)          */\n/*                                                                           */\n/*                  pu1_top_nnz : top nnz pointer                            */\n/*                                                                           */\n/*                  pu1_left_nnz : left nnz pointer                          */\n/*                                                                           */\n/*  Globals       : No                                                       */\n/*  Processing    : Parsing for four subblocks in unrolled, top and left nnz */\n/*                  are updated on the fly. csbp is set in accordance to     */\n/*                  decoded numcoeff for the subblock index in raster order  */\n/*                                                                           */\n/*  Outputs       : The updated residue buffer, nnzs and csbp current block  */\n/*                                                                           */\n/*  Returns       : Returns the coded sub block pattern csbp for the block   */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         09 10 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_cavlc_parse_8x8block_both_available(WORD16 *pi2_coeff_block,\n                                                  UWORD32 u4_sub_block_strd,\n                                                  UWORD32 u4_isdc,\n                                                  dec_struct_t * ps_dec,\n                                                  UWORD8 *pu1_top_nnz,\n                                                  UWORD8 *pu1_left_nnz,\n                                                  UWORD8 u1_tran_form8x8,\n                                                  UWORD8 u1_mb_field_decodingflag,\n                                                  UWORD32 *pu4_csbp)\n{\n    UWORD32 u4_num_coeff, u4_n, u4_subblock_coded;\n    UWORD32 u4_top0, u4_top1;\n    UWORD32 *pu4_dummy;\n    WORD32 (**pf_cavlc_parse4x4coeff)(WORD16 *pi2_coeff_block,\n                                      UWORD32 u4_isdc,\n                                      WORD32 u4_n,\n                                      struct _DecStruct *ps_dec,\n                                      UWORD32 *pu4_dummy) =\n                                      ps_dec->pf_cavlc_parse4x4coeff;\n    UWORD32 u4_idx = 0;\n    UWORD8 *puc_temp;\n    WORD32 ret;\n\n    *pu4_csbp = 0;\n    /* need to change the inverse scan matrices here */\n    puc_temp = ps_dec->pu1_inv_scan;\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 0                    */\n    /*------------------------------------------------------*/\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[0];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[0];\n        }\n    }\n    u4_n = (pu1_top_nnz[0] + pu1_left_nnz[0] + 1) >> 1;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    u4_top0 = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 1                    */\n    /*------------------------------------------------------*/\n    u4_idx++;\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[1];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[1];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += NUM_COEFFS_IN_4x4BLK;\n    }\n    u4_n = (pu1_top_nnz[1] + u4_num_coeff + 1) >> 1;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    u4_top1 = pu1_left_nnz[0] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 2                    */\n    /*------------------------------------------------------*/\n    u4_idx += (u4_sub_block_strd - 1);\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[2];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[2];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += ((u4_sub_block_strd - 1) * NUM_COEFFS_IN_4x4BLK);\n    }\n    u4_n = (u4_top0 + pu1_left_nnz[1] + 1) >> 1;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    pu1_top_nnz[0] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 3                    */\n    /*------------------------------------------------------*/\n    u4_idx++;\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[3];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[3];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += NUM_COEFFS_IN_4x4BLK;\n    }\n    u4_n = (u4_top1 + u4_num_coeff + 1) >> 1;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    pu1_top_nnz[1] = pu1_left_nnz[1] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    ps_dec->pu1_inv_scan = puc_temp;\n\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_cavlc_parse_8x8block_left_available                      */\n/*                                                                           */\n/*  Description   : This function does the residual parsing of 4 subblocks   */\n/*                  in a 8x8 block when only left is available for block     */\n/*                                                                           */\n/*  Inputs        : pi2_coeff_block : pointer to residual block where        */\n/*                  decoded and inverse scan coefficients are updated        */\n/*                                                                           */\n/*                  u4_sub_block_strd : indicates the number of sublocks    */\n/*                  in a row. It is 4 for luma and 2 for chroma.             */\n/*                                                                           */\n/*                  u4_isdc : required to indicate 4x4 parse modules if the  */\n/*                  current  Mb is I_16x16/chroma DC coded.                  */\n/*                                                                           */\n/*                  ps_dec : pointer to Decstruct (decoder context)          */\n/*                                                                           */\n/*                  pu1_top_nnz : top nnz pointer                            */\n/*                                                                           */\n/*                  pu1_left_nnz : left nnz pointer                          */\n/*                                                                           */\n/*  Globals       : No                                                       */\n/*  Processing    : Parsing for four subblocks in unrolled, top and left nnz */\n/*                  are updated on the fly. csbp is set in accordance to     */\n/*                  decoded numcoeff for the subblock index in raster order  */\n/*                                                                           */\n/*  Outputs       : The updated residue buffer, nnzs and csbp current block  */\n/*                                                                           */\n/*  Returns       : Returns the coded sub block pattern csbp for the block   */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         09 10 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_cavlc_parse_8x8block_left_available(WORD16 *pi2_coeff_block,\n                                                  UWORD32 u4_sub_block_strd,\n                                                  UWORD32 u4_isdc,\n                                                  dec_struct_t * ps_dec,\n                                                  UWORD8 *pu1_top_nnz,\n                                                  UWORD8 *pu1_left_nnz,\n                                                  UWORD8 u1_tran_form8x8,\n                                                  UWORD8 u1_mb_field_decodingflag,\n                                                  UWORD32 *pu4_csbp)\n{\n    UWORD32 u4_num_coeff, u4_n, u4_subblock_coded;\n    UWORD32 u4_top0, u4_top1;\n    UWORD32 *pu4_dummy;\n    WORD32 (**pf_cavlc_parse4x4coeff)(WORD16 *pi2_coeff_block,\n                                      UWORD32 u4_isdc,\n                                      WORD32 u4_n,\n                                      struct _DecStruct *ps_dec,\n                                      UWORD32 *pu4_dummy) =\n                                      ps_dec->pf_cavlc_parse4x4coeff;\n    UWORD32 u4_idx = 0;\n    UWORD8 *puc_temp;\n    WORD32 ret;\n\n    *pu4_csbp = 0;\n    puc_temp = ps_dec->pu1_inv_scan;\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 0                    */\n    /*------------------------------------------------------*/\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[0];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[0];\n        }\n    }\n    u4_n = pu1_left_nnz[0];\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    u4_top0 = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 1                    */\n    /*------------------------------------------------------*/\n    u4_idx++;\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[1];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[1];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += NUM_COEFFS_IN_4x4BLK;\n    }\n    u4_n = u4_num_coeff;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    u4_top1 = pu1_left_nnz[0] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 2                    */\n    /*------------------------------------------------------*/\n    u4_idx += (u4_sub_block_strd - 1);\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[2];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[2];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += ((u4_sub_block_strd - 1) * NUM_COEFFS_IN_4x4BLK);\n    }\n    u4_n = (u4_top0 + pu1_left_nnz[1] + 1) >> 1;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    pu1_top_nnz[0] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 3                    */\n    /*------------------------------------------------------*/\n    u4_idx++;\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[3];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[3];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += NUM_COEFFS_IN_4x4BLK;\n    }\n    u4_n = (u4_top1 + u4_num_coeff + 1) >> 1;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    pu1_top_nnz[1] = pu1_left_nnz[1] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    ps_dec->pu1_inv_scan = puc_temp;\n\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_cavlc_parse_8x8block_top_available                       */\n/*                                                                           */\n/*  Description   : This function does the residual parsing of 4 subblocks   */\n/*                  in a 8x8 block when only top is available for block      */\n/*                                                                           */\n/*  Inputs        : pi2_coeff_block : pointer to residual block where        */\n/*                  decoded and inverse scan coefficients are updated        */\n/*                                                                           */\n/*                  u4_sub_block_strd : indicates the number of sublocks    */\n/*                  in a row. It is 4 for luma and 2 for chroma.             */\n/*                                                                           */\n/*                  u4_isdc : required to indicate 4x4 parse modules if the  */\n/*                  current  Mb is I_16x16/chroma DC coded.                  */\n/*                                                                           */\n/*                  ps_dec : pointer to Decstruct (decoder context)          */\n/*                                                                           */\n/*                  pu1_top_nnz : top nnz pointer                            */\n/*                                                                           */\n/*                  pu1_left_nnz : left nnz pointer                          */\n/*                                                                           */\n/*  Globals       : No                                                       */\n/*  Processing    : Parsing for four subblocks in unrolled, top and left nnz */\n/*                  are updated on the fly. csbp is set in accordance to     */\n/*                  decoded numcoeff for the subblock index in raster order  */\n/*                                                                           */\n/*  Outputs       : The updated residue buffer, nnzs and csbp current block  */\n/*                                                                           */\n/*  Returns       : Returns the coded sub block pattern csbp for the block   */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         09 10 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_cavlc_parse_8x8block_top_available(WORD16 *pi2_coeff_block,\n                                                 UWORD32 u4_sub_block_strd,\n                                                 UWORD32 u4_isdc,\n                                                 dec_struct_t * ps_dec,\n                                                 UWORD8 *pu1_top_nnz,\n                                                 UWORD8 *pu1_left_nnz,\n                                                 UWORD8 u1_tran_form8x8,\n                                                 UWORD8 u1_mb_field_decodingflag,\n                                                 UWORD32 *pu4_csbp)\n{\n    UWORD32 u4_num_coeff, u4_n, u4_subblock_coded;\n    UWORD32 u4_top0, u4_top1;\n    UWORD32 *pu4_dummy;\n    WORD32 (**pf_cavlc_parse4x4coeff)(WORD16 *pi2_coeff_block,\n                                      UWORD32 u4_isdc,\n                                      WORD32 u4_n,\n                                      struct _DecStruct *ps_dec,\n                                      UWORD32 *pu4_dummy) =\n                                      ps_dec->pf_cavlc_parse4x4coeff;\n    UWORD32 u4_idx = 0;\n    UWORD8 *puc_temp;\n    WORD32 ret;\n\n    *pu4_csbp = 0;\n    puc_temp = ps_dec->pu1_inv_scan;\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 0                    */\n    /*------------------------------------------------------*/\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[0];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[0];\n        }\n    }\n    u4_n = pu1_top_nnz[0];\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    u4_top0 = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 1                    */\n    /*------------------------------------------------------*/\n    u4_idx++;\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[1];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[1];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += NUM_COEFFS_IN_4x4BLK;\n    }\n    u4_n = (pu1_top_nnz[1] + u4_num_coeff + 1) >> 1;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    u4_top1 = pu1_left_nnz[0] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 2                    */\n    /*------------------------------------------------------*/\n    u4_idx += (u4_sub_block_strd - 1);\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[2];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[2];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += ((u4_sub_block_strd - 1) * NUM_COEFFS_IN_4x4BLK);\n    }\n    u4_n = u4_top0;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    pu1_top_nnz[0] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 3                    */\n    /*------------------------------------------------------*/\n    u4_idx++;\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[3];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[3];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += NUM_COEFFS_IN_4x4BLK;\n    }\n    u4_n = (u4_top1 + u4_num_coeff + 1) >> 1;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    pu1_top_nnz[1] = pu1_left_nnz[1] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    ps_dec->pu1_inv_scan = puc_temp;\n\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_cavlc_parse_8x8block_none_available                      */\n/*                                                                           */\n/*  Description   : This function does the residual parsing of 4 subblocks   */\n/*                  in a 8x8 block when none of the neigbours are available  */\n/*                                                                           */\n/*  Inputs        : pi2_coeff_block : pointer to residual block where        */\n/*                  decoded and inverse scan coefficients are updated        */\n/*                                                                           */\n/*                  u4_sub_block_strd : indicates the number of sublocks    */\n/*                  in a row. It is 4 for luma and 2 for chroma.             */\n/*                                                                           */\n/*                  u4_isdc : required to indicate 4x4 parse modules if the  */\n/*                  current  Mb is I_16x16/chroma DC coded.                  */\n/*                                                                           */\n/*                  ps_dec : pointer to Decstruct (decoder context)          */\n/*                                                                           */\n/*                  pu1_top_nnz : top nnz pointer                            */\n/*                                                                           */\n/*                  pu1_left_nnz : left nnz pointer                          */\n/*                                                                           */\n/*  Globals       : No                                                       */\n/*  Processing    : Parsing for four subblocks in unrolled, top and left nnz */\n/*                  are updated on the fly. csbp is set in accordance to     */\n/*                  decoded numcoeff for the subblock index in raster order  */\n/*                                                                           */\n/*  Outputs       : The updated residue buffer, nnzs and csbp current block  */\n/*                                                                           */\n/*  Returns       : Returns the coded sub block pattern csbp for the block   */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         09 10 2008   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_cavlc_parse_8x8block_none_available(WORD16 *pi2_coeff_block,\n                                                  UWORD32 u4_sub_block_strd,\n                                                  UWORD32 u4_isdc,\n                                                  dec_struct_t * ps_dec,\n                                                  UWORD8 *pu1_top_nnz,\n                                                  UWORD8 *pu1_left_nnz,\n                                                  UWORD8 u1_tran_form8x8,\n                                                  UWORD8 u1_mb_field_decodingflag,\n                                                  UWORD32 *pu4_csbp)\n{\n    UWORD32 u4_num_coeff, u4_n, u4_subblock_coded;\n    UWORD32 u4_top0, u4_top1;\n    UWORD32 *pu4_dummy;\n    WORD32 (**pf_cavlc_parse4x4coeff)(WORD16 *pi2_coeff_block,\n                                      UWORD32 u4_isdc,\n                                      WORD32 u4_n,\n                                      struct _DecStruct *ps_dec,\n                                      UWORD32 *pu4_dummy) =\n                                      ps_dec->pf_cavlc_parse4x4coeff;\n    UWORD32 u4_idx = 0;\n    UWORD8 *puc_temp;\n    WORD32 ret;\n\n    *pu4_csbp = 0;\n    puc_temp = ps_dec->pu1_inv_scan;\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 0                    */\n    /*------------------------------------------------------*/\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[0];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[0];\n        }\n    }\n    ret = pf_cavlc_parse4x4coeff[0](pi2_coeff_block, u4_isdc, 0,\n                                    ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    u4_top0 = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 1                    */\n    /*------------------------------------------------------*/\n    u4_idx++;\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[1];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[1];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += NUM_COEFFS_IN_4x4BLK;\n    }\n    u4_n = u4_num_coeff;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    u4_top1 = pu1_left_nnz[0] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 2                    */\n    /*------------------------------------------------------*/\n    u4_idx += (u4_sub_block_strd - 1);\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[2];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[2];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += ((u4_sub_block_strd - 1) * NUM_COEFFS_IN_4x4BLK);\n    }\n    u4_n = u4_top0;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    pu1_top_nnz[0] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    /*------------------------------------------------------*/\n    /* Residual 4x4 decoding: SubBlock 3                    */\n    /*------------------------------------------------------*/\n    u4_idx++;\n    if(u1_tran_form8x8)\n    {\n        if(!u1_mb_field_decodingflag)\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[3];\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan =\n                            (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[3];\n        }\n    }\n    else\n    {\n        pi2_coeff_block += NUM_COEFFS_IN_4x4BLK;\n    }\n    u4_n = (u4_top1 + u4_num_coeff + 1) >> 1;\n    ret = pf_cavlc_parse4x4coeff[(u4_n > 7)](pi2_coeff_block, u4_isdc,\n                                             u4_n, ps_dec, &u4_num_coeff);\n    if(ret != OK)\n        return ret;\n\n    pu1_top_nnz[1] = pu1_left_nnz[1] = u4_num_coeff;\n    u4_subblock_coded = (u4_num_coeff != 0);\n    INSERT_BIT(*pu4_csbp, u4_idx, u4_subblock_coded);\n\n    ps_dec->pu1_inv_scan = puc_temp;\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_residual4x4_cavlc \\endif\n *\n * \\brief\n *    This function parses CAVLC syntax of a Luma and Chroma AC Residuals.\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\n\nWORD32 ih264d_parse_residual4x4_cavlc(dec_struct_t * ps_dec,\n                                      dec_mb_info_t *ps_cur_mb_info,\n                                      UWORD8 u1_offset)\n{\n    UWORD8 u1_cbp = ps_cur_mb_info->u1_cbp;\n    UWORD16 ui16_csbp = 0;\n    UWORD32 u4_nbr_avl;\n    WORD16 *pi2_residual_buf;\n\n    UWORD8 u1_is_top_mb_avail;\n    UWORD8 u1_is_left_mb_avail;\n\n    UWORD8 *pu1_top_nnz = ps_cur_mb_info->ps_curmb->pu1_nnz_y;\n    UWORD8 *pu1_left_nnz = ps_dec->pu1_left_nnz_y;\n    WORD16 *pi2_coeff_block = NULL;\n    UWORD32 *pu4_dummy;\n    WORD32 ret;\n\n    WORD32 (**pf_cavlc_parse_8x8block)(WORD16 *pi2_coeff_block,\n                                       UWORD32 u4_sub_block_strd,\n                                       UWORD32 u4_isdc,\n                                       struct _DecStruct *ps_dec,\n                                       UWORD8 *pu1_top_nnz,\n                                       UWORD8 *pu1_left_nnz,\n                                       UWORD8 u1_tran_form8x8,\n                                       UWORD8 u1_mb_field_decodingflag,\n                                       UWORD32 *pu4_dummy) = ps_dec->pf_cavlc_parse_8x8block;\n\n\n    {\n        UWORD8 uc_temp = ps_dec->u1_mb_ngbr_availablity;\n        u1_is_top_mb_avail = BOOLEAN(uc_temp & TOP_MB_AVAILABLE_MASK);\n        u1_is_left_mb_avail = BOOLEAN(uc_temp & LEFT_MB_AVAILABLE_MASK);\n        u4_nbr_avl = (u1_is_top_mb_avail << 1) | u1_is_left_mb_avail;\n    }\n\n    ps_cur_mb_info->u1_qp_div6 = ps_dec->u1_qp_y_div6;\n    ps_cur_mb_info->u1_qp_rem6 = ps_dec->u1_qp_y_rem6;\n    ps_cur_mb_info->u1_qpc_div6 = ps_dec->u1_qp_u_div6;\n    ps_cur_mb_info->u1_qpc_rem6 = ps_dec->u1_qp_u_rem6;\n    ps_cur_mb_info->u1_qpcr_div6 = ps_dec->u1_qp_v_div6;\n    ps_cur_mb_info->u1_qpcr_rem6 = ps_dec->u1_qp_v_rem6;\n\n    if(u1_cbp & 0xf)\n    {\n        pu1_top_nnz[0] = ps_cur_mb_info->ps_top_mb->pu1_nnz_y[0];\n        pu1_top_nnz[1] = ps_cur_mb_info->ps_top_mb->pu1_nnz_y[1];\n        pu1_top_nnz[2] = ps_cur_mb_info->ps_top_mb->pu1_nnz_y[2];\n        pu1_top_nnz[3] = ps_cur_mb_info->ps_top_mb->pu1_nnz_y[3];\n\n        /*******************************************************************/\n        /* Block 0 residual decoding, check cbp and proceed (subblock = 0) */\n        /*******************************************************************/\n        if(!(u1_cbp & 0x1))\n        {\n            *(UWORD16 *)(pu1_top_nnz) = 0;\n            *(UWORD16 *)(pu1_left_nnz) = 0;\n\n        }\n        else\n        {\n            UWORD32 u4_temp;\n            ret = pf_cavlc_parse_8x8block[u4_nbr_avl](\n                        pi2_coeff_block, 4, u1_offset, ps_dec, pu1_top_nnz,\n                        pu1_left_nnz, ps_cur_mb_info->u1_tran_form8x8,\n                        ps_cur_mb_info->u1_mb_field_decodingflag, &u4_temp);\n            if(ret != OK)\n                return ret;\n            ui16_csbp = u4_temp;\n        }\n\n        /*******************************************************************/\n        /* Block 1 residual decoding, check cbp and proceed (subblock = 2) */\n        /*******************************************************************/\n        if(ps_cur_mb_info->u1_tran_form8x8)\n        {\n            pi2_coeff_block += 64;\n        }\n        else\n        {\n            pi2_coeff_block += (2 * NUM_COEFFS_IN_4x4BLK);\n        }\n\n        if(!(u1_cbp & 0x2))\n        {\n            *(UWORD16 *)(pu1_top_nnz + 2) = 0;\n            *(UWORD16 *)(pu1_left_nnz) = 0;\n        }\n        else\n        {\n            UWORD32 u4_temp = (u4_nbr_avl | 0x1);\n            ret = pf_cavlc_parse_8x8block[u4_temp](\n                        pi2_coeff_block, 4, u1_offset, ps_dec,\n                        (pu1_top_nnz + 2), pu1_left_nnz,\n                        ps_cur_mb_info->u1_tran_form8x8,\n                        ps_cur_mb_info->u1_mb_field_decodingflag, &u4_temp);\n            if(ret != OK)\n                return ret;\n            ui16_csbp |= (u4_temp << 2);\n        }\n\n        /*******************************************************************/\n        /* Block 2 residual decoding, check cbp and proceed (subblock = 8) */\n        /*******************************************************************/\n        if(ps_cur_mb_info->u1_tran_form8x8)\n        {\n            pi2_coeff_block += 64;\n        }\n        else\n        {\n            pi2_coeff_block += (6 * NUM_COEFFS_IN_4x4BLK);\n        }\n\n        if(!(u1_cbp & 0x4))\n        {\n            *(UWORD16 *)(pu1_top_nnz) = 0;\n            *(UWORD16 *)(pu1_left_nnz + 2) = 0;\n        }\n        else\n        {\n            UWORD32 u4_temp = (u4_nbr_avl | 0x2);\n            ret = pf_cavlc_parse_8x8block[u4_temp](\n                        pi2_coeff_block, 4, u1_offset, ps_dec, pu1_top_nnz,\n                        (pu1_left_nnz + 2), ps_cur_mb_info->u1_tran_form8x8,\n                        ps_cur_mb_info->u1_mb_field_decodingflag, &u4_temp);\n            if(ret != OK)\n                return ret;\n            ui16_csbp |= (u4_temp << 8);\n        }\n\n        /*******************************************************************/\n        /* Block 3 residual decoding, check cbp and proceed (subblock = 10)*/\n        /*******************************************************************/\n        if(ps_cur_mb_info->u1_tran_form8x8)\n        {\n            pi2_coeff_block += 64;\n        }\n        else\n        {\n            pi2_coeff_block += (2 * NUM_COEFFS_IN_4x4BLK);\n        }\n\n        if(!(u1_cbp & 0x8))\n        {\n            *(UWORD16 *)(pu1_top_nnz + 2) = 0;\n            *(UWORD16 *)(pu1_left_nnz + 2) = 0;\n        }\n        else\n        {\n            UWORD32 u4_temp;\n            ret = pf_cavlc_parse_8x8block[0x3](\n                        pi2_coeff_block, 4, u1_offset, ps_dec,\n                        (pu1_top_nnz + 2), (pu1_left_nnz + 2),\n                        ps_cur_mb_info->u1_tran_form8x8,\n                        ps_cur_mb_info->u1_mb_field_decodingflag, &u4_temp);\n            if(ret != OK)\n                return ret;\n            ui16_csbp |= (u4_temp << 10);\n        }\n    }\n    else\n    {\n        *(UWORD32 *)(pu1_top_nnz) = 0;\n        *(UWORD32 *)(pu1_left_nnz) = 0;\n    }\n\n    ps_cur_mb_info->u2_luma_csbp = ui16_csbp;\n    ps_cur_mb_info->ps_curmb->u2_luma_csbp = ui16_csbp;\n\n    {\n        UWORD16 u2_chroma_csbp = 0;\n        ps_cur_mb_info->u2_chroma_csbp = 0;\n        pu1_top_nnz = ps_cur_mb_info->ps_curmb->pu1_nnz_uv;\n        pu1_left_nnz = ps_dec->pu1_left_nnz_uv;\n\n        u1_cbp >>= 4;\n        /*--------------------------------------------------------------------*/\n        /* if Chroma Component not present OR no ac values present            */\n        /* Set the values of N to zero                                        */\n        /*--------------------------------------------------------------------*/\n        if(u1_cbp == CBPC_ALLZERO || u1_cbp == CBPC_ACZERO)\n        {\n            *(UWORD32 *)(pu1_top_nnz) = 0;\n            *(UWORD32 *)(pu1_left_nnz) = 0;\n        }\n\n        if(u1_cbp == CBPC_ALLZERO)\n        {\n            return (0);\n        }\n        /*--------------------------------------------------------------------*/\n        /* Decode Chroma DC values                                            */\n        /*--------------------------------------------------------------------*/\n        {\n            WORD32 u4_scale_u;\n            WORD32 u4_scale_v;\n            WORD32 i4_mb_inter_inc;\n            u4_scale_u = ps_dec->pu2_quant_scale_u[0] << ps_dec->u1_qp_u_div6;\n            u4_scale_v = ps_dec->pu2_quant_scale_v[0] << ps_dec->u1_qp_v_div6;\n            i4_mb_inter_inc = (!((ps_cur_mb_info->ps_curmb->u1_mb_type == I_4x4_MB)\n                            || (ps_cur_mb_info->ps_curmb->u1_mb_type == I_16x16_MB)))\n                            * 3;\n\n            if(ps_dec->s_high_profile.u1_scaling_present)\n            {\n                u4_scale_u *=\n                                ps_dec->s_high_profile.i2_scalinglist4x4[i4_mb_inter_inc\n                                                + 1][0];\n                u4_scale_v *=\n                                ps_dec->s_high_profile.i2_scalinglist4x4[i4_mb_inter_inc\n                                                + 2][0];\n\n            }\n            else\n            {\n                u4_scale_u <<= 4;\n                u4_scale_v <<= 4;\n            }\n\n            ih264d_cavlc_parse_chroma_dc(ps_cur_mb_info,pi2_coeff_block, ps_dec->ps_bitstrm,\n                                         u4_scale_u, u4_scale_v,\n                                         i4_mb_inter_inc);\n        }\n\n        if(u1_cbp == CBPC_ACZERO)\n            return (0);\n\n        pu1_top_nnz[0] = ps_cur_mb_info->ps_top_mb->pu1_nnz_uv[0];\n        pu1_top_nnz[1] = ps_cur_mb_info->ps_top_mb->pu1_nnz_uv[1];\n        pu1_top_nnz[2] = ps_cur_mb_info->ps_top_mb->pu1_nnz_uv[2];\n        pu1_top_nnz[3] = ps_cur_mb_info->ps_top_mb->pu1_nnz_uv[3];\n        /*--------------------------------------------------------------------*/\n        /* Decode Chroma AC values                                            */\n        /*--------------------------------------------------------------------*/\n        {\n            UWORD32 u4_temp;\n            /*****************************************************************/\n            /* U Block  residual decoding, check cbp and proceed (subblock=0)*/\n            /*****************************************************************/\n            ret = pf_cavlc_parse_8x8block[u4_nbr_avl](\n                        pi2_coeff_block, 2, 1, ps_dec, pu1_top_nnz,\n                        pu1_left_nnz, 0, 0, &u4_temp);\n            if(ret != OK)\n                return ret;\n            u2_chroma_csbp = u4_temp;\n\n            pi2_coeff_block += MB_CHROM_SIZE;\n            /*****************************************************************/\n            /* V Block  residual decoding, check cbp and proceed (subblock=1)*/\n            /*****************************************************************/\n            ret = pf_cavlc_parse_8x8block[u4_nbr_avl](pi2_coeff_block, 2, 1,\n                                                      ps_dec,\n                                                      (pu1_top_nnz + 2),\n                                                      (pu1_left_nnz + 2), 0,\n                                                      0, &u4_temp);\n            if(ret != OK)\n                return ret;\n            u2_chroma_csbp |= (u4_temp << 4);\n        }\n\n        ps_cur_mb_info->u2_chroma_csbp = u2_chroma_csbp;\n    }\n    return OK;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_cavlc.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_PARSE_CAVLC_H_\n#define _IH264D_PARSE_CAVLC_H_\n/*!\n **************************************************************************\n * \\file ih264d_parse_cavlc.h\n *\n * \\brief\n *    Declaration of UVLC and CAVLC functions\n *\n * \\date\n *    18/12/2002\n *\n * \\author  AI\n **************************************************************************\n */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_cabac.h\"\n\nenum cavlcTableNum\n{\n    tableTotalZeroOffset,\n    tableTotalZero,\n    tableRunBefore,\n    codeGx,\n    chromTab,\n    offsetNumVlcTab\n};\n\nWORD32 ih264d_uvlc(dec_bit_stream_t *ps_bitstrm,\n                   UWORD32 u4_range,\n                   UWORD32 *pi_bitstrm_ofst,\n                   UWORD8 u1_flag,\n                   UWORD32 u4_bitstrm_ofst,\n                   UWORD32 *pi_bitstrm_buf);\n\nUWORD32 ih264d_uev(UWORD32 *pu4_bitstrm_ofst, UWORD32 *pu4_bitstrm_buf);\n\nWORD32 ih264d_sev(UWORD32 *pu4_bitstrm_ofst, UWORD32 *pu4_bitstrm_buf);\n\nUWORD32 ih264d_tev_range1(UWORD32 *pu4_bitstrm_ofst,\n                          UWORD32 *pu4_bitstrm_buf);\n\nUWORD8 RestOfResidualBlockCavlc(WORD16 *pi2_coeff_block,\n                                UWORD32 u1_ofst_is_dc_max_coef_scale_fact,\n                                UWORD32 u4_total_coeff_trail_one,\n                                dec_bit_stream_t *ps_bitstrm,\n                                UWORD8 *pu1_invscan);\n\nWORD32 ih264d_cavlc_4x4res_block_totalcoeff_1( UWORD32 u4_isdc,\n                                           UWORD32 u4_total_coeff_trail_one,\n                                           dec_bit_stream_t *ps_bitstrm);\n\nWORD32 ih264d_cavlc_4x4res_block_totalcoeff_2to10(UWORD32 u4_isdc,\n                                               UWORD32 u4_total_coeff_trail_one,\n                                               dec_bit_stream_t *ps_bitstrm);\n\nWORD32 ih264d_cavlc_4x4res_block_totalcoeff_11to16(UWORD32 u4_isdc,\n                                                UWORD32 u4_total_coeff_trail_one,\n                                                dec_bit_stream_t *ps_bitstrm);\n\nWORD32 ih264d_cavlc_parse4x4coeff_n0to7(WORD16 *pi2_coeff_block,\n                                        UWORD32 u4_isdc,\n                                        WORD32 u4_n,\n                                        dec_struct_t *ps_dec,\n                                        UWORD32 *pu4_total_coeff);\n\nWORD32 ih264d_cavlc_parse4x4coeff_n8(WORD16 *pi2_coeff_block,\n                                      UWORD32 u4_isdc,\n                                      WORD32 u4_n,\n                                      dec_struct_t *ps_dec,\n                                      UWORD32 *pu4_total_coeff);\n\nvoid ih264d_cavlc_parse_chroma_dc(dec_mb_info_t *ps_cur_mb_info,\n                                  WORD16 *pi2_coeff_block,\n                                  dec_bit_stream_t *ps_bitstrm,\n                                  UWORD32 u4_scale_u,\n                                  UWORD32 u4_scale_v,\n                                  WORD32 i4_mb_inter_inc);\n\nWORD32 ih264d_cavlc_parse_8x8block_none_available(WORD16 *pi2_coeff_block,\n                                                  UWORD32 u4_sub_block_strd,\n                                                  UWORD32 u4_isdc,\n                                                  dec_struct_t * ps_dec,\n                                                  UWORD8 *pu1_top_nnz,\n                                                  UWORD8 *pu1_left_nnz,\n                                                  UWORD8 u1_tran_form8x8,\n                                                  UWORD8 u1_mb_field_decodingflag,\n                                                  UWORD32 *pu4_csbp);\n\nWORD32 ih264d_cavlc_parse_8x8block_left_available(WORD16 *pi2_coeff_block,\n                                                  UWORD32 u4_sub_block_strd,\n                                                  UWORD32 u4_isdc,\n                                                  dec_struct_t * ps_dec,\n                                                  UWORD8 *pu1_top_nnz,\n                                                  UWORD8 *pu1_left_nnz,\n                                                  UWORD8 u1_tran_form8x8,\n                                                  UWORD8 u1_mb_field_decodingflag,\n                                                  UWORD32 *pu4_csbp);\n\nWORD32 ih264d_cavlc_parse_8x8block_top_available(WORD16 *pi2_coeff_block,\n                                                 UWORD32 u4_sub_block_strd,\n                                                 UWORD32 u4_isdc,\n                                                 dec_struct_t * ps_dec,\n                                                 UWORD8 *pu1_top_nnz,\n                                                 UWORD8 *pu1_left_nnz,\n                                                 UWORD8 u1_tran_form8x8,\n                                                 UWORD8 u1_mb_field_decodingflag,\n                                                 UWORD32 *pu4_csbp);\n\nWORD32 ih264d_cavlc_parse_8x8block_both_available(WORD16 *pi2_coeff_block,\n                                                  UWORD32 u4_sub_block_strd,\n                                                  UWORD32 u4_isdc,\n                                                  dec_struct_t * ps_dec,\n                                                  UWORD8 *pu1_top_nnz,\n                                                  UWORD8 *pu1_left_nnz,\n                                                  UWORD8 u1_tran_form8x8,\n                                                  UWORD8 u1_mb_field_decodingflag,\n                                                  UWORD32 *pu4_csbp);\n\nWORD8 ResidualBlockChromaDC(WORD16 *pi2_level, dec_bit_stream_t *ps_bitstrm);\n\nvoid ih264d_parse_pmb_ref_index_cavlc_range1(UWORD32 u4_num_part,\n                                             dec_bit_stream_t *ps_bitstrm,\n                                             WORD8 *pi1_ref_idx,\n                                             UWORD32 u4_num_ref_idx_active_minus1);\n\nWORD32 ih264d_parse_pmb_ref_index_cavlc(UWORD32 u4_num_part,\n                                      dec_bit_stream_t *ps_bitstrm,\n                                      WORD8 *pi1_ref_idx,\n                                      UWORD32 u4_num_ref_idx_active_minus1);\n\nvoid ih264d_parse_bmb_ref_index_cavlc_range1(UWORD32 u4_num_part,\n                                             dec_bit_stream_t *ps_bitstrm,\n                                             WORD8 *pi1_ref_idx,\n                                             UWORD32 u4_num_ref_idx_active_minus1);\n\nWORD32 ih264d_parse_bmb_ref_index_cavlc(UWORD32 u4_num_part,\n                                      dec_bit_stream_t *ps_bitstrm,\n                                      WORD8 *pi1_ref_idx,\n                                      UWORD32 u4_num_ref_idx_active_minus1);\n\n#endif  /* _IH264D_PARSE_CAVLC_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_headers.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n * Modified for use with Cemu emulator project\n */\n/*!\n **************************************************************************\n * \\file ih264d_parse_headers.c\n *\n * \\brief\n *    Contains High level syntax[above slice] parsing routines\n *\n * \\date\n *    19/12/2002\n *\n * \\author  AI\n **************************************************************************\n */\n#include <string.h>\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_defs.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_utils.h\"\n#include \"ih264d_nal.h\"\n#include \"ih264d_deblocking.h\"\n\n#include \"ih264d_mem_request.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_sei.h\"\n#include \"ih264d_vui.h\"\n#include \"ih264d_thread_parse_decode.h\"\n#include \"ih264d_thread_compute_bs.h\"\n#include \"ih264d_quant_scaling.h\"\n#include \"ih264d_defs.h\"\n#include \"ivd.h\"\n#include \"ih264d.h\"\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_get_pre_sei_params                                */\n/*                                                                           */\n/*  Description   : Gets valid pre-sei params in decoder struct from parse   */\n/*                  struct.                                                  */\n/*  Inputs        : u1_nal_unit_type slice type                              */\n/*                  ps_dec    Decoder parameters                             */\n/*  Globals       : None                                                     */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                          Draft                            */\n/*                                                                           */\n/*****************************************************************************/\n\nvoid ih264d_get_pre_sei_params(dec_struct_t *ps_dec, UWORD8 u1_nal_unit_type)\n{\n    if((NULL != ps_dec->ps_sei) &&\n        ((0 == ps_dec->ps_sei->s_sei_ccv_params.u1_ccv_cancel_flag) &&\n        (0 == ps_dec->ps_sei->s_sei_ccv_params.u1_ccv_persistence_flag)))\n    {\n        ps_dec->ps_sei->u1_sei_ccv_params_present_flag = 0;\n        memset(&ps_dec->ps_sei->s_sei_ccv_params, 0, sizeof(sei_ccv_params_t));\n    }\n\n    if((NULL != ps_dec->ps_cur_sps) &&\n        ((1 == ps_dec->ps_cur_sps->u1_vui_parameters_present_flag) &&\n        ((2 != ps_dec->ps_cur_sps->s_vui.u1_colour_primaries) &&\n        (2 != ps_dec->ps_cur_sps->s_vui.u1_matrix_coeffs) &&\n        (2 != ps_dec->ps_cur_sps->s_vui.u1_tfr_chars) &&\n        (4 != ps_dec->ps_cur_sps->s_vui.u1_tfr_chars) &&\n        (5 != ps_dec->ps_cur_sps->s_vui.u1_tfr_chars))))\n    {\n        if((1 == ps_dec->ps_sei_parse->u1_sei_ccv_params_present_flag) ||\n            (IDR_SLICE_NAL == u1_nal_unit_type))\n        {\n            ps_dec->ps_sei->u1_sei_ccv_params_present_flag =\n                        ps_dec->ps_sei_parse->u1_sei_ccv_params_present_flag;\n            ps_dec->ps_sei->s_sei_ccv_params = ps_dec->ps_sei_parse->s_sei_ccv_params;\n        }\n    }\n    else\n    {\n        ps_dec->ps_sei->u1_sei_ccv_params_present_flag = 0;\n        memset(&ps_dec->ps_sei->s_sei_ccv_params, 0, sizeof(sei_ccv_params_t));\n    }\n\n    if(IDR_SLICE_NAL == u1_nal_unit_type)\n    {\n        ps_dec->ps_sei->u1_sei_mdcv_params_present_flag =\n                        ps_dec->ps_sei_parse->u1_sei_mdcv_params_present_flag;\n        ps_dec->ps_sei->s_sei_mdcv_params = ps_dec->ps_sei_parse->s_sei_mdcv_params;\n        ps_dec->ps_sei->u1_sei_cll_params_present_flag =\n                        ps_dec->ps_sei_parse->u1_sei_cll_params_present_flag;\n        ps_dec->ps_sei->s_sei_cll_params = ps_dec->ps_sei_parse->s_sei_cll_params;\n        ps_dec->ps_sei->u1_sei_ave_params_present_flag =\n                        ps_dec->ps_sei_parse->u1_sei_ave_params_present_flag;\n        ps_dec->ps_sei->s_sei_ave_params = ps_dec->ps_sei_parse->s_sei_ave_params;\n    }\n\n    ps_dec->ps_sei_parse->u1_sei_mdcv_params_present_flag = 0;\n    memset(&ps_dec->ps_sei_parse->s_sei_mdcv_params, 0, sizeof(sei_mdcv_params_t));\n    ps_dec->ps_sei_parse->u1_sei_cll_params_present_flag = 0;\n    memset(&ps_dec->ps_sei_parse->s_sei_cll_params, 0, sizeof(sei_cll_params_t));\n    ps_dec->ps_sei_parse->u1_sei_ave_params_present_flag = 0;\n    memset(&ps_dec->ps_sei_parse->s_sei_ave_params, 0, sizeof(sei_ave_params_t));\n    ps_dec->ps_sei_parse->u1_sei_ccv_params_present_flag = 0;\n    memset(&ps_dec->ps_sei_parse->s_sei_ccv_params, 0, sizeof(sei_ccv_params_t));\n\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_slice_partition                                     */\n/*                                                                           */\n/*  Description   : This function is intended to parse and decode slice part */\n/*                  itions. Currently it's not implemented. Decoder will     */\n/*                  print a message, skips this NAL and continues            */\n/*  Inputs        : ps_dec    Decoder parameters                             */\n/*                  ps_bitstrm    Bitstream                                */\n/*  Globals       : None                                                     */\n/*  Processing    : This functionality needs to be implemented               */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : Not implemented                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_parse_slice_partition(dec_struct_t * ps_dec,\n                                    dec_bit_stream_t * ps_bitstrm)\n{\n    H264_DEC_DEBUG_PRINT(\"\\nSlice partition not supported\");\n    UNUSED(ps_dec);\n    UNUSED(ps_bitstrm);\n    return (0);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_sei                                                */\n/*                                                                           */\n/*  Description   : This function is intended to parse and decode SEI        */\n/*                  Currently it's not implemented. Decoder will print a     */\n/*                  message, skips this NAL and continues                    */\n/*  Inputs        : ps_dec    Decoder parameters                       */\n/*                  ps_bitstrm    Bitstream                                */\n/*  Globals       : None                                                     */\n/*  Processing    : This functionality needs to be implemented               */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : Not implemented                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_sei(dec_struct_t * ps_dec, dec_bit_stream_t * ps_bitstrm)\n{\n    UNUSED(ps_dec);\n    UNUSED(ps_bitstrm);\n    return (0);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_filler_data                                          */\n/*                                                                           */\n/*  Description   : This function is intended to parse and decode filler     */\n/*                  data NAL. Currently it's not implemented. Decoder will   */\n/*                  print a message, skips this NAL and continues            */\n/*  Inputs        : ps_dec    Decoder parameters                       */\n/*                  ps_bitstrm    Bitstream                                */\n/*  Globals       : None                                                     */\n/*  Processing    : This functionality needs to be implemented               */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : Not implemented                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_filler_data(dec_struct_t * ps_dec,\n                                dec_bit_stream_t * ps_bitstrm)\n{\n    UNUSED(ps_dec);\n    UNUSED(ps_bitstrm);\n    return (0);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_end_of_stream                                        */\n/*                                                                           */\n/*  Description   : This function is intended to parse and decode end of     */\n/*                  sequence. Currently it's not implemented. Decoder will   */\n/*                  print a message, skips this NAL and continues            */\n/*  Inputs        : ps_dec    Decoder parameters                       */\n/*  Globals       : None                                                     */\n/*  Processing    : This functionality needs to be implemented               */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : Not implemented                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_parse_end_of_stream(dec_struct_t * ps_dec)\n{\n    UNUSED(ps_dec);\n    return;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_pps \\endif\n *\n * \\brief\n *    Decodes Picture Parameter set\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_pps(dec_struct_t * ps_dec, dec_bit_stream_t * ps_bitstrm)\n{\n    UWORD8 uc_temp;\n    dec_seq_params_t * ps_sps = NULL;\n    dec_pic_params_t * ps_pps = NULL;\n    UWORD32 *pu4_bitstrm_buf = ps_dec->ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_dec->ps_bitstrm->u4_ofst;\n\n    /* Variables used for error resilience checks */\n    UWORD64 u8_temp;\n    UWORD32 u4_temp;\n    WORD32 i_temp;\n\n    /* For High profile related syntax elements */\n    UWORD8 u1_more_data_flag;\n    WORD32 i4_i;\n\n    if(!(ps_dec->i4_header_decoded & 1))\n        return ERROR_INV_SPS_PPS_T;\n\n    /*--------------------------------------------------------------------*/\n    /* Decode pic_parameter_set_id and find corresponding pic params      */\n    /*--------------------------------------------------------------------*/\n    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if(u4_temp & MASK_ERR_PIC_SET_ID)\n        return ERROR_INV_SPS_PPS_T;\n    ps_pps = ps_dec->pv_scratch_sps_pps;\n    *ps_pps = ps_dec->ps_pps[u4_temp];\n    ps_pps->u1_pic_parameter_set_id = (WORD8)u4_temp;\n    COPYTHECONTEXT(\"PPS: pic_parameter_set_id\",ps_pps->u1_pic_parameter_set_id);\n\n    /************************************************/\n    /* initilization of High profile syntax element */\n    /************************************************/\n    ps_pps->i4_transform_8x8_mode_flag = 0;\n    ps_pps->i4_pic_scaling_matrix_present_flag = 0;\n\n    /*--------------------------------------------------------------------*/\n    /* Decode seq_parameter_set_id and map it to a seq_parameter_set      */\n    /*--------------------------------------------------------------------*/\n    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if(u4_temp & MASK_ERR_SEQ_SET_ID)\n        return ERROR_INV_SPS_PPS_T;\n    COPYTHECONTEXT(\"PPS: seq_parameter_set_id\",u4_temp);\n    ps_sps = &ps_dec->ps_sps[u4_temp];\n\n    if(FALSE == ps_sps->u1_is_valid)\n        return ERROR_INV_SPS_PPS_T;\n    ps_pps->ps_sps = ps_sps;\n\n    /*--------------------------------------------------------------------*/\n    /* Decode entropy_coding_mode                                         */\n    /*--------------------------------------------------------------------*/\n    ps_pps->u1_entropy_coding_mode = ih264d_get_bit_h264(ps_bitstrm);\n    COPYTHECONTEXT(\"PPS: entropy_coding_mode_flag\",ps_pps->u1_entropy_coding_mode);\n\n    ps_pps->u1_pic_order_present_flag = ih264d_get_bit_h264(ps_bitstrm);\n    COPYTHECONTEXT(\"PPS: pic_order_present_flag\",ps_pps->u1_pic_order_present_flag);\n\n    /*--------------------------------------------------------------------*/\n    /* Decode num_slice_groups_minus1                                     */\n    /*--------------------------------------------------------------------*/\n    u8_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf) + (UWORD64)1;\n    if(u8_temp != 1)\n    {\n        return ERROR_FEATURE_UNAVAIL;\n    }\n    ps_pps->u1_num_slice_groups = u8_temp;\n    COPYTHECONTEXT(\"PPS: num_slice_groups_minus1\",ps_pps->u1_num_slice_groups -1);\n\n    /*--------------------------------------------------------------------*/\n    /* Other parameter set values                                         */\n    /*--------------------------------------------------------------------*/\n    u8_temp = (UWORD64)1 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if(u8_temp > H264_MAX_REF_IDX)\n        return ERROR_REF_IDX;\n    ps_pps->u1_num_ref_idx_lx_active[0] = u8_temp;\n    COPYTHECONTEXT(\"PPS: num_ref_idx_l0_active_minus1\",\n                    ps_pps->u1_num_ref_idx_lx_active[0] - 1);\n\n    u8_temp = (UWORD64)1 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if(u8_temp > H264_MAX_REF_IDX)\n        return ERROR_REF_IDX;\n    ps_pps->u1_num_ref_idx_lx_active[1] = u8_temp;\n    COPYTHECONTEXT(\"PPS: num_ref_idx_l1_active_minus1\",\n                    ps_pps->u1_num_ref_idx_lx_active[1] - 1);\n\n    ps_pps->u1_wted_pred_flag = ih264d_get_bit_h264(ps_bitstrm);\n    COPYTHECONTEXT(\"PPS: weighted prediction u4_flag\",ps_pps->u1_wted_pred_flag);\n    uc_temp = ih264d_get_bits_h264(ps_bitstrm, 2);\n    COPYTHECONTEXT(\"PPS: weighted_bipred_idc\",uc_temp);\n    ps_pps->u1_wted_bipred_idc = uc_temp;\n\n    if(ps_pps->u1_wted_bipred_idc > MAX_WEIGHT_BIPRED_IDC)\n        return ERROR_INV_SPS_PPS_T;\n\n    WORD64 i8_temp = (WORD64)26\n                        + ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n\n    if((i8_temp < MIN_H264_QP) || (i8_temp > MAX_H264_QP))\n        return ERROR_INV_RANGE_QP_T;\n\n    ps_pps->u1_pic_init_qp = i8_temp;\n    COPYTHECONTEXT(\"PPS: pic_init_qp_minus26\",ps_pps->u1_pic_init_qp - 26);\n\n    i8_temp = (WORD64)26 + ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n\n    if((i8_temp < MIN_H264_QP) || (i8_temp > MAX_H264_QP))\n        return ERROR_INV_RANGE_QP_T;\n\n    ps_pps->u1_pic_init_qs = i8_temp;\n    COPYTHECONTEXT(\"PPS: pic_init_qs_minus26\",ps_pps->u1_pic_init_qs - 26);\n\n    i_temp = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if((i_temp < -12) || (i_temp > 12))\n        return ERROR_INV_RANGE_QP_T;\n    ps_pps->i1_chroma_qp_index_offset = i_temp;\n    COPYTHECONTEXT(\"PPS: chroma_qp_index_offset\",ps_pps->i1_chroma_qp_index_offset);\n\n    /***************************************************************************/\n    /* initialize second_chroma_qp_index_offset to i1_chroma_qp_index_offset if */\n    /* second_chroma_qp_index_offset is not present in bit-ps_bitstrm              */\n    /***************************************************************************/\n    ps_pps->i1_second_chroma_qp_index_offset =\n                    ps_pps->i1_chroma_qp_index_offset;\n\n    ps_pps->u1_deblocking_filter_parameters_present_flag = ih264d_get_bit_h264(\n                    ps_bitstrm);\n    COPYTHECONTEXT(\"PPS: deblocking_filter_control_present_flag\",\n                    ps_pps->u1_deblocking_filter_parameters_present_flag);\n    ps_pps->u1_constrained_intra_pred_flag = ih264d_get_bit_h264(ps_bitstrm);\n    COPYTHECONTEXT(\"PPS: constrained_intra_pred_flag\",\n                    ps_pps->u1_constrained_intra_pred_flag);\n    ps_pps->u1_redundant_pic_cnt_present_flag = ih264d_get_bit_h264(ps_bitstrm);\n    COPYTHECONTEXT(\"PPS: redundant_pic_cnt_present_flag\",\n                    ps_pps->u1_redundant_pic_cnt_present_flag);\n\n    /* High profile related syntax elements */\n    u1_more_data_flag = MORE_RBSP_DATA(ps_bitstrm);\n    if(u1_more_data_flag && (ps_pps->ps_sps->u1_profile_idc == HIGH_PROFILE_IDC))\n    {\n        /* read transform_8x8_mode_flag  */\n        ps_pps->i4_transform_8x8_mode_flag = (WORD32)ih264d_get_bit_h264(\n                        ps_bitstrm);\n\n        /* read pic_scaling_matrix_present_flag */\n        ps_pps->i4_pic_scaling_matrix_present_flag =\n                        (WORD32)ih264d_get_bit_h264(ps_bitstrm);\n\n        if(ps_pps->i4_pic_scaling_matrix_present_flag)\n        {\n            /* read the scaling matrices */\n            for(i4_i = 0; i4_i < (6 + (ps_pps->i4_transform_8x8_mode_flag << 1)); i4_i++)\n            {\n                ps_pps->u1_pic_scaling_list_present_flag[i4_i] =\n                                ih264d_get_bit_h264(ps_bitstrm);\n\n                if(ps_pps->u1_pic_scaling_list_present_flag[i4_i])\n                {\n                    WORD32 ret;\n                    if(i4_i < 6)\n                    {\n                        ret = ih264d_scaling_list(\n                                        ps_pps->i2_pic_scalinglist4x4[i4_i],\n                                        16,\n                                        &ps_pps->u1_pic_use_default_scaling_matrix_flag[i4_i],\n                                        ps_bitstrm);\n                    }\n                    else\n                    {\n                        ret = ih264d_scaling_list(\n                                        ps_pps->i2_pic_scalinglist8x8[i4_i - 6],\n                                        64,\n                                        &ps_pps->u1_pic_use_default_scaling_matrix_flag[i4_i],\n                                        ps_bitstrm);\n                    }\n\n                    if(ret != OK)\n                    {\n                        return ret;\n                    }\n                }\n            }\n        }\n\n        /* read second_chroma_qp_index_offset syntax element */\n        i_temp = ih264d_sev(\n                        pu4_bitstrm_ofst, pu4_bitstrm_buf);\n\n        if((i_temp < -12) || (i_temp > 12))\n            return ERROR_INV_RANGE_QP_T;\n\n        ps_pps->i1_second_chroma_qp_index_offset = i_temp;\n    }\n\n    /* In case bitstream read has exceeded the filled size, then\n       return an error */\n    if(EXCEED_OFFSET(ps_bitstrm))\n    {\n        return ERROR_INV_SPS_PPS_T;\n    }\n    ps_pps->u1_is_valid = TRUE;\n    ps_dec->ps_pps[ps_pps->u1_pic_parameter_set_id] = *ps_pps;\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_sps \\endif\n *\n * \\brief\n *    Decodes Sequence parameter set from the bitstream\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nUWORD32 ih264d_correct_level_idc(UWORD32 u4_level_idc, UWORD32 u4_total_mbs)\n{\n    UWORD32 u4_max_mbs_allowed;\n\n    switch(u4_level_idc)\n    {\n        case H264_LEVEL_1_0:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_10;\n            break;\n        case H264_LEVEL_1_1:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_11;\n            break;\n        case H264_LEVEL_1_2:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_12;\n            break;\n        case H264_LEVEL_1_3:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_13;\n            break;\n        case H264_LEVEL_2_0:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_20;\n            break;\n        case H264_LEVEL_2_1:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_21;\n            break;\n        case H264_LEVEL_2_2:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_22;\n            break;\n        case H264_LEVEL_3_0:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_30;\n            break;\n        case H264_LEVEL_3_1:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_31;\n            break;\n        case H264_LEVEL_3_2:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_32;\n            break;\n        case H264_LEVEL_4_0:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_40;\n            break;\n        case H264_LEVEL_4_1:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_41;\n            break;\n        case H264_LEVEL_4_2:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_42;\n            break;\n        case H264_LEVEL_5_0:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_50;\n            break;\n        case H264_LEVEL_5_1:\n        default:\n            u4_max_mbs_allowed = MAX_MBS_LEVEL_51;\n            break;\n\n    }\n\n    /*correct of the level is incorrect*/\n    if(u4_total_mbs > u4_max_mbs_allowed)\n    {\n        if(u4_total_mbs > MAX_MBS_LEVEL_50)\n            u4_level_idc = H264_LEVEL_5_1;\n        else if(u4_total_mbs > MAX_MBS_LEVEL_42)\n            u4_level_idc = H264_LEVEL_5_0;\n        else if(u4_total_mbs > MAX_MBS_LEVEL_41)\n            u4_level_idc = H264_LEVEL_4_2;\n        else if(u4_total_mbs > MAX_MBS_LEVEL_40)\n            u4_level_idc = H264_LEVEL_4_1;\n        else if(u4_total_mbs > MAX_MBS_LEVEL_32)\n            u4_level_idc = H264_LEVEL_4_0;\n        else if(u4_total_mbs > MAX_MBS_LEVEL_31)\n            u4_level_idc = H264_LEVEL_3_2;\n        else if(u4_total_mbs > MAX_MBS_LEVEL_30)\n            u4_level_idc = H264_LEVEL_3_1;\n        else if(u4_total_mbs > MAX_MBS_LEVEL_21)\n            u4_level_idc = H264_LEVEL_3_0;\n        else if(u4_total_mbs > MAX_MBS_LEVEL_20)\n            u4_level_idc = H264_LEVEL_2_1;\n        else if(u4_total_mbs > MAX_MBS_LEVEL_10)\n            u4_level_idc = H264_LEVEL_2_0;\n    }\n\n    return (u4_level_idc);\n\n}\nWORD32 ih264d_parse_sps(dec_struct_t *ps_dec, dec_bit_stream_t *ps_bitstrm)\n{\n    UWORD8 i;\n    dec_seq_params_t *ps_seq = NULL;\n    UWORD8 u1_profile_idc, u1_level_idc, u1_seq_parameter_set_id, u1_mb_aff_flag = 0;\n    UWORD16 i2_max_frm_num;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD8 u1_frm, uc_constraint_set0_flag, uc_constraint_set1_flag;\n    WORD32 i4_cropped_ht, i4_cropped_wd;\n    UWORD32 u4_temp;\n    UWORD64 u8_temp;\n    UWORD32 u4_pic_height_in_map_units, u4_pic_width_in_mbs;\n    UWORD32 u2_pic_wd = 0;\n    UWORD32 u2_pic_ht = 0;\n    UWORD32 u2_frm_wd_y = 0;\n    UWORD32 u2_frm_ht_y = 0;\n    UWORD32 u2_frm_wd_uv = 0;\n    UWORD32 u2_frm_ht_uv = 0;\n    UWORD32 u2_crop_offset_y = 0;\n    UWORD32 u2_crop_offset_uv = 0;\n    WORD32 ret;\n    WORD32 num_reorder_frames;\n    /* High profile related syntax element */\n    WORD32 i4_i;\n    /* G050 */\n    UWORD8 u1_frame_cropping_flag, u1_frame_cropping_rect_left_ofst,\n                    u1_frame_cropping_rect_right_ofst,\n                    u1_frame_cropping_rect_top_ofst,\n                    u1_frame_cropping_rect_bottom_ofst;\n    /* G050 */\n    /*--------------------------------------------------------------------*/\n    /* Decode seq_parameter_set_id and profile and level values           */\n    /*--------------------------------------------------------------------*/\n    SWITCHONTRACE;\n    u1_profile_idc = ih264d_get_bits_h264(ps_bitstrm, 8);\n    COPYTHECONTEXT(\"SPS: profile_idc\",u1_profile_idc);\n\n    /* G050 */\n    uc_constraint_set0_flag = ih264d_get_bit_h264(ps_bitstrm);\n    uc_constraint_set1_flag = ih264d_get_bit_h264(ps_bitstrm);\n    ih264d_get_bit_h264(ps_bitstrm);\n\n    /*****************************************************/\n    /* Read 5 bits for uc_constraint_set3_flag (1 bit)   */\n    /* and reserved_zero_4bits (4 bits) - Sushant        */\n    /*****************************************************/\n    ih264d_get_bits_h264(ps_bitstrm, 5);\n    /* G050 */\n\n    /* Check whether particular profile is suported or not */\n    /* Check whether particular profile is suported or not */\n    if((u1_profile_idc != MAIN_PROFILE_IDC) &&\n\n    (u1_profile_idc != BASE_PROFILE_IDC) &&\n\n    (u1_profile_idc != HIGH_PROFILE_IDC)\n\n    )\n    {\n\n        /* Apart from Baseline, main and high profile,\n         * only extended profile is supported provided\n         * uc_constraint_set0_flag or uc_constraint_set1_flag are set to 1\n         */\n        if((u1_profile_idc != EXTENDED_PROFILE_IDC) ||\n           ((uc_constraint_set1_flag != 1) && (uc_constraint_set0_flag != 1)))\n        {\n            return (ERROR_FEATURE_UNAVAIL);\n        }\n    }\n\n    u1_level_idc = ih264d_get_bits_h264(ps_bitstrm, 8);\n\n\n\n    COPYTHECONTEXT(\"SPS: u4_level_idc\",u1_level_idc);\n\n    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if(u4_temp & MASK_ERR_SEQ_SET_ID)\n        return ERROR_INV_SPS_PPS_T;\n    u1_seq_parameter_set_id = u4_temp;\n    COPYTHECONTEXT(\"SPS: seq_parameter_set_id\",\n                    u1_seq_parameter_set_id);\n\n    /*--------------------------------------------------------------------*/\n    /* Find an seq param entry in seqparam array of decStruct             */\n    /*--------------------------------------------------------------------*/\n\n    ps_seq = ps_dec->pv_scratch_sps_pps;\n    memset(ps_seq, 0, sizeof(dec_seq_params_t));\n\n    if(ps_dec->i4_header_decoded & 1)\n    {\n        *ps_seq = *ps_dec->ps_cur_sps;\n    }\n\n\n    if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_profile_idc != u1_profile_idc))\n    {\n        ps_dec->u1_res_changed = 1;\n        return IVD_RES_CHANGED;\n    }\n\n    if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_level_idc != u1_level_idc))\n    {\n        ps_dec->u1_res_changed = 1;\n        return IVD_RES_CHANGED;\n    }\n\n    ps_seq->u1_profile_idc = u1_profile_idc;\n    ps_seq->u1_level_idc = u1_level_idc;\n    ps_seq->u1_seq_parameter_set_id = u1_seq_parameter_set_id;\n\n    /*******************************************************************/\n    /* Initializations for high profile - Sushant                      */\n    /*******************************************************************/\n    ps_seq->i4_chroma_format_idc = 1;\n    ps_seq->i4_bit_depth_luma_minus8 = 0;\n    ps_seq->i4_bit_depth_chroma_minus8 = 0;\n    ps_seq->i4_qpprime_y_zero_transform_bypass_flag = 0;\n    ps_seq->i4_seq_scaling_matrix_present_flag = 0;\n    if(u1_profile_idc == HIGH_PROFILE_IDC)\n    {\n\n        /* reading chroma_format_idc   */\n        ps_seq->i4_chroma_format_idc = ih264d_uev(pu4_bitstrm_ofst,\n                                                  pu4_bitstrm_buf);\n\n        /* Monochrome is not supported */\n        if(ps_seq->i4_chroma_format_idc != 1)\n        {\n            return ERROR_FEATURE_UNAVAIL;\n        }\n\n        /* reading bit_depth_luma_minus8   */\n        ps_seq->i4_bit_depth_luma_minus8 = ih264d_uev(pu4_bitstrm_ofst,\n                                                      pu4_bitstrm_buf);\n\n        if(ps_seq->i4_bit_depth_luma_minus8 != 0)\n        {\n            return ERROR_FEATURE_UNAVAIL;\n        }\n\n        /* reading bit_depth_chroma_minus8   */\n        ps_seq->i4_bit_depth_chroma_minus8 = ih264d_uev(pu4_bitstrm_ofst,\n                                                        pu4_bitstrm_buf);\n\n        if(ps_seq->i4_bit_depth_chroma_minus8 != 0)\n        {\n            return ERROR_FEATURE_UNAVAIL;\n        }\n\n        /* reading qpprime_y_zero_transform_bypass_flag   */\n        ps_seq->i4_qpprime_y_zero_transform_bypass_flag =\n                        (WORD32)ih264d_get_bit_h264(ps_bitstrm);\n\n        if(ps_seq->i4_qpprime_y_zero_transform_bypass_flag != 0)\n        {\n            return ERROR_INV_SPS_PPS_T;\n        }\n\n        /* reading seq_scaling_matrix_present_flag   */\n        ps_seq->i4_seq_scaling_matrix_present_flag =\n                        (WORD32)ih264d_get_bit_h264(ps_bitstrm);\n\n        if(ps_seq->i4_seq_scaling_matrix_present_flag)\n        {\n            for(i4_i = 0; i4_i < 8; i4_i++)\n            {\n                ps_seq->u1_seq_scaling_list_present_flag[i4_i] =\n                                ih264d_get_bit_h264(ps_bitstrm);\n\n                /* initialize u1_use_default_scaling_matrix_flag[i4_i] to zero */\n                /* before calling scaling list                             */\n                ps_seq->u1_use_default_scaling_matrix_flag[i4_i] = 0;\n\n                if(ps_seq->u1_seq_scaling_list_present_flag[i4_i])\n                {\n                    if(i4_i < 6)\n                    {\n                        ret = ih264d_scaling_list(\n                                        ps_seq->i2_scalinglist4x4[i4_i],\n                                        16,\n                                        &ps_seq->u1_use_default_scaling_matrix_flag[i4_i],\n                                        ps_bitstrm);\n                    }\n                    else\n                    {\n                        ret = ih264d_scaling_list(\n                                        ps_seq->i2_scalinglist8x8[i4_i - 6],\n                                        64,\n                                        &ps_seq->u1_use_default_scaling_matrix_flag[i4_i],\n                                        ps_bitstrm);\n                    }\n                    if(ret != OK)\n                    {\n                        return ret;\n                    }\n                }\n            }\n        }\n    }\n    /*--------------------------------------------------------------------*/\n    /* Decode MaxFrameNum                                                 */\n    /*--------------------------------------------------------------------*/\n    u8_temp = (UWORD64)4 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if(u8_temp > MAX_BITS_IN_FRAME_NUM)\n    {\n        return ERROR_INV_SPS_PPS_T;\n    }\n    ps_seq->u1_bits_in_frm_num = u8_temp;\n    COPYTHECONTEXT(\"SPS: log2_max_frame_num_minus4\",\n                    (ps_seq->u1_bits_in_frm_num - 4));\n\n    i2_max_frm_num = (1 << (ps_seq->u1_bits_in_frm_num));\n    ps_seq->u2_u4_max_pic_num_minus1 = i2_max_frm_num - 1;\n    /*--------------------------------------------------------------------*/\n    /* Decode picture order count and related values                      */\n    /*--------------------------------------------------------------------*/\n    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n\n    if(u4_temp > MAX_PIC_ORDER_CNT_TYPE)\n    {\n        return ERROR_INV_POC_TYPE_T;\n    }\n    ps_seq->u1_pic_order_cnt_type = u4_temp;\n    COPYTHECONTEXT(\"SPS: pic_order_cnt_type\",ps_seq->u1_pic_order_cnt_type);\n\n    ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle = 1;\n    if(ps_seq->u1_pic_order_cnt_type == 0)\n    {\n        u8_temp = (UWORD64)4 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        if(u8_temp > MAX_BITS_IN_POC_LSB)\n        {\n            return ERROR_INV_SPS_PPS_T;\n        }\n        ps_seq->u1_log2_max_pic_order_cnt_lsb_minus = u8_temp;\n        ps_seq->i4_max_pic_order_cntLsb = (1 << u8_temp);\n        COPYTHECONTEXT(\"SPS: log2_max_pic_order_cnt_lsb_minus4\",(u8_temp - 4));\n    }\n    else if(ps_seq->u1_pic_order_cnt_type == 1)\n    {\n        ps_seq->u1_delta_pic_order_always_zero_flag = ih264d_get_bit_h264(\n                        ps_bitstrm);\n        COPYTHECONTEXT(\"SPS: delta_pic_order_always_zero_flag\",\n                        ps_seq->u1_delta_pic_order_always_zero_flag);\n\n        ps_seq->i4_ofst_for_non_ref_pic = ih264d_sev(pu4_bitstrm_ofst,\n                                                     pu4_bitstrm_buf);\n        COPYTHECONTEXT(\"SPS: offset_for_non_ref_pic\",\n                        ps_seq->i4_ofst_for_non_ref_pic);\n\n        ps_seq->i4_ofst_for_top_to_bottom_field = ih264d_sev(\n                        pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        COPYTHECONTEXT(\"SPS: offset_for_top_to_bottom_field\",\n                        ps_seq->i4_ofst_for_top_to_bottom_field);\n\n        u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        if(u4_temp > 255)\n            return ERROR_INV_SPS_PPS_T;\n        ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle = u4_temp;\n        COPYTHECONTEXT(\"SPS: num_ref_frames_in_pic_order_cnt_cycle\",\n                        ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle);\n\n        for(i = 0; i < ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle; i++)\n        {\n            ps_seq->i4_ofst_for_ref_frame[i] = ih264d_sev(\n                            pu4_bitstrm_ofst, pu4_bitstrm_buf);\n            COPYTHECONTEXT(\"SPS: offset_for_ref_frame\",\n                            ps_seq->i4_ofst_for_ref_frame[i]);\n        }\n    }\n\n    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n\n    if((u4_temp > H264_MAX_REF_PICS))\n    {\n        return ERROR_NUM_REF;\n    }\n\n    /* Compare with older num_ref_frames is header is already once */\n    if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_num_ref_frames != u4_temp))\n    {\n        ps_dec->u1_res_changed = 1;\n        return IVD_RES_CHANGED;\n    }\n\n    ps_seq->u1_num_ref_frames = u4_temp;\n    COPYTHECONTEXT(\"SPS: num_ref_frames\",ps_seq->u1_num_ref_frames);\n\n    ps_seq->u1_gaps_in_frame_num_value_allowed_flag = ih264d_get_bit_h264(\n                    ps_bitstrm);\n    COPYTHECONTEXT(\"SPS: gaps_in_frame_num_value_allowed_flag\",\n                    ps_seq->u1_gaps_in_frame_num_value_allowed_flag);\n\n    /*--------------------------------------------------------------------*/\n    /* Decode FrameWidth and FrameHeight and related values               */\n    /*--------------------------------------------------------------------*/\n    u8_temp = (UWORD64)1 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    /* Check  for unsupported resolutions*/\n    if(u8_temp > (H264_MAX_FRAME_WIDTH >> 4))\n    {\n        return IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED;\n    }\n    u4_pic_width_in_mbs = u8_temp;\n    COPYTHECONTEXT(\"SPS: pic_width_in_mbs_minus1\",\n                   u4_pic_width_in_mbs - 1);\n\n    u8_temp = (UWORD64)1 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if (u8_temp > (H264_MAX_FRAME_HEIGHT >> 4))\n    {\n        return IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED;\n    }\n    u4_pic_height_in_map_units = u8_temp;\n\n    ps_seq->u2_frm_wd_in_mbs = u4_pic_width_in_mbs;\n    ps_seq->u2_frm_ht_in_mbs = u4_pic_height_in_map_units;\n\n    u2_pic_wd = (u4_pic_width_in_mbs << 4);\n    u2_pic_ht = (u4_pic_height_in_map_units << 4);\n    /*--------------------------------------------------------------------*/\n    /* Get the value of MaxMbAddress and Number of bits needed for it     */\n    /*--------------------------------------------------------------------*/\n    ps_seq->u2_max_mb_addr = (ps_seq->u2_frm_wd_in_mbs\n                    * ps_seq->u2_frm_ht_in_mbs) - 1;\n\n    ps_seq->u2_total_num_of_mbs = ps_seq->u2_max_mb_addr + 1;\n\n    ps_seq->u1_level_idc = ih264d_correct_level_idc(\n                    u1_level_idc, ps_seq->u2_total_num_of_mbs);\n\n    u1_frm = ih264d_get_bit_h264(ps_bitstrm);\n    if((ps_dec->i4_header_decoded & 1) && (ps_seq->u1_frame_mbs_only_flag != u1_frm))\n    {\n        ps_dec->u1_res_changed = 1;\n        return IVD_RES_CHANGED;\n    }\n\n    ps_seq->u1_frame_mbs_only_flag = u1_frm;\n\n    COPYTHECONTEXT(\"SPS: frame_mbs_only_flag\", u1_frm);\n\n    if(!u1_frm)\n        u1_mb_aff_flag = ih264d_get_bit_h264(ps_bitstrm);\n\n    if((ps_dec->i4_header_decoded & 1)\n                    && (ps_seq->u1_mb_aff_flag != u1_mb_aff_flag))\n    {\n        ps_dec->u1_res_changed = 1;\n        return IVD_RES_CHANGED;\n    }\n\n    if(!u1_frm)\n    {\n        u2_pic_ht <<= 1;\n        ps_seq->u1_mb_aff_flag = u1_mb_aff_flag;\n        COPYTHECONTEXT(\"SPS: mb_adaptive_frame_field_flag\",\n                        ps_seq->u1_mb_aff_flag);\n\n    }\n    else\n        ps_seq->u1_mb_aff_flag = 0;\n\n    ps_seq->u1_direct_8x8_inference_flag = ih264d_get_bit_h264(ps_bitstrm);\n\n    COPYTHECONTEXT(\"SPS: direct_8x8_inference_flag\",\n                    ps_seq->u1_direct_8x8_inference_flag);\n\n    /* G050 */\n    u1_frame_cropping_flag = ih264d_get_bit_h264(ps_bitstrm);\n    COPYTHECONTEXT(\"SPS: frame_cropping_flag\",u1_frame_cropping_flag);\n\n    if(u1_frame_cropping_flag)\n    {\n        u1_frame_cropping_rect_left_ofst = ih264d_uev(pu4_bitstrm_ofst,\n                                                      pu4_bitstrm_buf);\n        COPYTHECONTEXT(\"SPS: frame_cropping_rect_left_offset\",\n                        u1_frame_cropping_rect_left_ofst);\n        u1_frame_cropping_rect_right_ofst = ih264d_uev(pu4_bitstrm_ofst,\n                                                       pu4_bitstrm_buf);\n        COPYTHECONTEXT(\"SPS: frame_cropping_rect_right_offset\",\n                        u1_frame_cropping_rect_right_ofst);\n        u1_frame_cropping_rect_top_ofst = ih264d_uev(pu4_bitstrm_ofst,\n                                                     pu4_bitstrm_buf);\n        COPYTHECONTEXT(\"SPS: frame_cropping_rect_top_offset\",\n                        u1_frame_cropping_rect_top_ofst);\n        u1_frame_cropping_rect_bottom_ofst = ih264d_uev(pu4_bitstrm_ofst,\n                                                        pu4_bitstrm_buf);\n        COPYTHECONTEXT(\"SPS: frame_cropping_rect_bottom_offset\",\n                        u1_frame_cropping_rect_bottom_ofst);\n\n\t\tps_dec->u1_frame_cropping_flag = u1_frame_cropping_flag;\n\t\tps_dec->u1_frame_cropping_rect_left_ofst = u1_frame_cropping_rect_left_ofst;\n\t\tps_dec->u1_frame_cropping_rect_right_ofst = u1_frame_cropping_rect_right_ofst;\n\t\tps_dec->u1_frame_cropping_rect_top_ofst = u1_frame_cropping_rect_top_ofst;\n\t\tps_dec->u1_frame_cropping_rect_bottom_ofst = u1_frame_cropping_rect_bottom_ofst;\n    }\n    else\n    {\n        ps_dec->u1_frame_cropping_flag = 0;\n\t\tps_dec->u1_frame_cropping_rect_left_ofst = 0;\n\t\tps_dec->u1_frame_cropping_rect_right_ofst = 0;\n\t\tps_dec->u1_frame_cropping_rect_top_ofst = 0;\n\t\tps_dec->u1_frame_cropping_rect_bottom_ofst = 0;\n    }\n\n    /* G050 */\n\n    ps_seq->u1_vui_parameters_present_flag = ih264d_get_bit_h264(ps_bitstrm);\n    COPYTHECONTEXT(\"SPS: vui_parameters_present_flag\",\n                    ps_seq->u1_vui_parameters_present_flag);\n\n    u2_frm_wd_y = u2_pic_wd + (UWORD8)(PAD_LEN_Y_H << 1);\n    if(1 == ps_dec->u4_share_disp_buf)\n    {\n        if(ps_dec->u4_app_disp_width > u2_frm_wd_y)\n            u2_frm_wd_y = ps_dec->u4_app_disp_width;\n    }\n\n    u2_frm_ht_y = u2_pic_ht + (UWORD8)(PAD_LEN_Y_V << 2);\n    u2_frm_wd_uv = u2_pic_wd + (UWORD8)(PAD_LEN_UV_H << 2);\n    u2_frm_wd_uv = MAX(u2_frm_wd_uv, u2_frm_wd_y);\n\n    u2_frm_ht_uv = (u2_pic_ht >> 1) + (UWORD8)(PAD_LEN_UV_V << 2);\n    u2_frm_ht_uv = MAX(u2_frm_ht_uv, (u2_frm_ht_y >> 1));\n\n\n    /* Calculate display picture width, height and start u4_ofst from YUV420 */\n    /* pictute buffers as per cropping information parsed above             */\n    {\n        UWORD16 u2_rgt_ofst = 0;\n        UWORD16 u2_lft_ofst = 0;\n        UWORD16 u2_top_ofst = 0;\n        UWORD16 u2_btm_ofst = 0;\n        UWORD8 u1_frm_mbs_flag;\n        UWORD8 u1_vert_mult_factor;\n\n        //if(u1_frame_cropping_flag)\n        //{\n        //    /* Calculate right and left u4_ofst for cropped picture           */\n        //    u2_rgt_ofst = u1_frame_cropping_rect_right_ofst << 1;\n        //    u2_lft_ofst = u1_frame_cropping_rect_left_ofst << 1;\n\n        //    /* Know frame MBs only u4_flag                                      */\n        //    u1_frm_mbs_flag = (1 == ps_seq->u1_frame_mbs_only_flag);\n\n        //    /* Simplify the vertical u4_ofst calculation from field/frame     */\n        //    u1_vert_mult_factor = (2 - u1_frm_mbs_flag);\n\n        //    /* Calculate bottom and top u4_ofst for cropped  picture          */\n        //    u2_btm_ofst = (u1_frame_cropping_rect_bottom_ofst\n        //                    << u1_vert_mult_factor);\n        //    u2_top_ofst = (u1_frame_cropping_rect_top_ofst\n        //                    << u1_vert_mult_factor);\n        //}\n\n        /* Calculate u4_ofst from start of YUV 420 picture buffer to start of*/\n        /* cropped picture buffer                                           */\n        u2_crop_offset_y = (u2_frm_wd_y * u2_top_ofst) + (u2_lft_ofst);\n        u2_crop_offset_uv = (u2_frm_wd_uv * (u2_top_ofst >> 1))\n                        + (u2_lft_ofst >> 1) * YUV420SP_FACTOR;\n        /* Calculate the display picture width and height based on crop      */\n        /* information                                                       */\n        i4_cropped_ht = (WORD32)u2_pic_ht - (WORD32)(u2_btm_ofst + u2_top_ofst);\n        i4_cropped_wd = (WORD32)u2_pic_wd - (WORD32)(u2_rgt_ofst + u2_lft_ofst);\n\n        if((i4_cropped_ht < MB_SIZE) || (i4_cropped_wd < MB_SIZE))\n        {\n            return ERROR_INV_SPS_PPS_T;\n        }\n\n        if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_pic_wd != u2_pic_wd))\n        {\n            ps_dec->u1_res_changed = 1;\n            return IVD_RES_CHANGED;\n        }\n\n        if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_disp_width != i4_cropped_wd))\n        {\n            ps_dec->u1_res_changed = 1;\n            return IVD_RES_CHANGED;\n        }\n\n        if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_pic_ht != u2_pic_ht))\n        {\n            ps_dec->u1_res_changed = 1;\n            return IVD_RES_CHANGED;\n        }\n\n        if((ps_dec->i4_header_decoded & 1) && (ps_dec->u2_disp_height != i4_cropped_ht))\n        {\n            ps_dec->u1_res_changed = 1;\n            return IVD_RES_CHANGED;\n        }\n\n        /* Check again for unsupported resolutions with updated values*/\n        if((u2_pic_wd > H264_MAX_FRAME_WIDTH) || (u2_pic_ht > H264_MAX_FRAME_HEIGHT)\n                || (u2_pic_wd < H264_MIN_FRAME_WIDTH) || (u2_pic_ht < H264_MIN_FRAME_HEIGHT)\n                || (u2_pic_wd * (UWORD32)u2_pic_ht > H264_MAX_FRAME_SIZE))\n        {\n            return IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED;\n        }\n\n        /* If MBAff is enabled, decoder support is limited to streams with\n         * width less than half of H264_MAX_FRAME_WIDTH.\n         * In case of MBAff decoder processes two rows at a time\n         */\n        if((u2_pic_wd << ps_seq->u1_mb_aff_flag) > H264_MAX_FRAME_WIDTH)\n        {\n            return IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED;\n        }\n\n    }\n\n    /* Backup num_reorder_frames if header is already decoded */\n    if((ps_dec->i4_header_decoded & 1) &&\n                    (1 == ps_seq->u1_vui_parameters_present_flag) &&\n                    (1 == ps_seq->s_vui.u1_bitstream_restriction_flag))\n    {\n        num_reorder_frames =  (WORD32)ps_seq->s_vui.u4_num_reorder_frames;\n    }\n    else\n    {\n        num_reorder_frames = -1;\n    }\n    if(1 == ps_seq->u1_vui_parameters_present_flag)\n    {\n        ret = ih264d_parse_vui_parametres(&ps_seq->s_vui, ps_bitstrm);\n        if(ret != OK)\n            return ret;\n    }\n\n    /* Compare older num_reorder_frames with the new one if header is already decoded */\n    if((ps_dec->i4_header_decoded & 1) &&\n                    (-1 != num_reorder_frames) &&\n                    (1 == ps_seq->u1_vui_parameters_present_flag) &&\n                    (1 == ps_seq->s_vui.u1_bitstream_restriction_flag) &&\n                    ((WORD32)ps_seq->s_vui.u4_num_reorder_frames != num_reorder_frames))\n    {\n        ps_dec->u1_res_changed = 1;\n        return IVD_RES_CHANGED;\n    }\n\n    /* In case bitstream read has exceeded the filled size, then\n     return an error */\n    if (EXCEED_OFFSET(ps_bitstrm))\n    {\n        return ERROR_INV_SPS_PPS_T;\n    }\n\n    /*--------------------------------------------------------------------*/\n    /* All initializations to ps_dec are beyond this point                */\n    /*--------------------------------------------------------------------*/\n    {\n        WORD32 reorder_depth = ih264d_get_dpb_size(ps_seq);\n        if((1 == ps_seq->u1_vui_parameters_present_flag) &&\n           (1 == ps_seq->s_vui.u1_bitstream_restriction_flag))\n        {\n            reorder_depth = ps_seq->s_vui.u4_num_reorder_frames + 1;\n        }\n\n        if (reorder_depth > H264_MAX_REF_PICS)\n        {\n            return ERROR_INV_SPS_PPS_T;\n        }\n\n        if(ps_seq->u1_frame_mbs_only_flag != 1)\n            reorder_depth *= 2;\n        ps_dec->i4_reorder_depth = reorder_depth + DISPLAY_LATENCY;\n    }\n    ps_dec->u2_disp_height = i4_cropped_ht;\n    ps_dec->u2_disp_width = i4_cropped_wd;\n\n    ps_dec->u2_pic_wd = u2_pic_wd;\n    ps_dec->u2_pic_ht = u2_pic_ht;\n\n    /* Determining the Width and Height of Frame from that of Picture */\n    ps_dec->u2_frm_wd_y = u2_frm_wd_y;\n    ps_dec->u2_frm_ht_y = u2_frm_ht_y;\n\n    ps_dec->u2_frm_wd_uv = u2_frm_wd_uv;\n    ps_dec->u2_frm_ht_uv = u2_frm_ht_uv;\n    ps_dec->s_pad_mgr.u1_pad_len_y_v = (UWORD8)(PAD_LEN_Y_V << (1 - u1_frm));\n    ps_dec->s_pad_mgr.u1_pad_len_cr_v = (UWORD8)(PAD_LEN_UV_V << (1 - u1_frm));\n\n    ps_dec->u2_frm_wd_in_mbs = ps_seq->u2_frm_wd_in_mbs;\n    ps_dec->u2_frm_ht_in_mbs = ps_seq->u2_frm_ht_in_mbs;\n\n    ps_dec->u2_crop_offset_y = u2_crop_offset_y;\n    ps_dec->u2_crop_offset_uv = u2_crop_offset_uv;\n\n    ps_seq->u1_is_valid = TRUE;\n    ps_dec->ps_sps[u1_seq_parameter_set_id] = *ps_seq;\n    ps_dec->ps_cur_sps = &ps_dec->ps_sps[u1_seq_parameter_set_id];\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_end_of_sequence \\endif\n *\n * \\brief\n *    Decodes End of Sequence.\n *\n * \\param ps_bitstrm   : Pointer to bit ps_bitstrm containing the NAL unit\n *\n * \\return\n *    0 on Success and error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_end_of_sequence(dec_struct_t * ps_dec)\n{\n    WORD32 ret;\n\n    ret = ih264d_end_of_pic_processing(ps_dec);\n    return ret;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : AcessUnitDelimiterRbsp \\endif\n *\n * \\brief\n *    Decodes AcessUnitDelimiterRbsp.\n *\n * \\param ps_bitstrm   : Pointer to bit ps_bitstrm containing the NAL unit\n *\n * \\return\n *    0 on Success and error code otherwise\n **************************************************************************\n */\n\nWORD32 ih264d_access_unit_delimiter_rbsp(dec_struct_t * ps_dec)\n{\n    UWORD8 u1_primary_pic_type;\n    u1_primary_pic_type = ih264d_get_bits_h264(ps_dec->ps_bitstrm, 3);\n    switch(u1_primary_pic_type)\n    {\n        case I_PIC:\n        case SI_PIC:\n        case ISI_PIC:\n            ps_dec->ps_dec_err_status->u1_pic_aud_i = PIC_TYPE_I;\n            break;\n        default:\n            ps_dec->ps_dec_err_status->u1_pic_aud_i = PIC_TYPE_UNKNOWN;\n    }\n    return (0);\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_nal_unit \\endif\n *\n * \\brief\n *    Decodes NAL unit\n *\n * \\return\n *    0 on Success and error code otherwise\n **************************************************************************\n */\n\nWORD32 ih264d_parse_nal_unit(iv_obj_t *dec_hdl,\n                          ivd_video_decode_op_t *ps_dec_op,\n                          UWORD8 *pu1_buf,\n                          UWORD32 u4_length)\n{\n\n    dec_bit_stream_t *ps_bitstrm;\n\n\n    dec_struct_t *ps_dec = (dec_struct_t *)dec_hdl->pv_codec_handle;\n    ivd_video_decode_ip_t *ps_dec_in =\n                    (ivd_video_decode_ip_t *)ps_dec->pv_dec_in;\n    dec_slice_params_t * ps_cur_slice = ps_dec->ps_cur_slice;\n    UWORD8 u1_first_byte, u1_nal_ref_idc;\n    UWORD8 u1_nal_unit_type;\n    WORD32 i_status = OK;\n    ps_bitstrm = ps_dec->ps_bitstrm;\n\n    if(pu1_buf)\n    {\n        if(u4_length)\n        {\n            ps_dec_op->u4_frame_decoded_flag = 0;\n            ih264d_process_nal_unit(ps_dec->ps_bitstrm, pu1_buf,\n                                    u4_length);\n\n            SWITCHOFFTRACE;\n            u1_first_byte = ih264d_get_bits_h264(ps_bitstrm, 8);\n\n            if(NAL_FORBIDDEN_BIT(u1_first_byte))\n            {\n                H264_DEC_DEBUG_PRINT(\"\\nForbidden bit set in Nal Unit, Let's try\\n\");\n            }\n            u1_nal_unit_type = NAL_UNIT_TYPE(u1_first_byte);\n            // if any other nal unit other than slice nal is encountered in between a\n            // frame break out of loop without consuming header\n            if ((ps_dec->u4_slice_start_code_found == 1)\n                    && (ps_dec->u1_pic_decode_done != 1)\n                    && (u1_nal_unit_type > IDR_SLICE_NAL))\n            {\n                return ERROR_INCOMPLETE_FRAME;\n            }\n            ps_dec->u1_nal_unit_type = u1_nal_unit_type;\n            u1_nal_ref_idc = (UWORD8)(NAL_REF_IDC(u1_first_byte));\n            //Skip all NALUs if SPS and PPS are not decoded\n            switch(u1_nal_unit_type)\n            {\n                case SLICE_DATA_PARTITION_A_NAL:\n                case SLICE_DATA_PARTITION_B_NAL:\n                case SLICE_DATA_PARTITION_C_NAL:\n                    if(!ps_dec->i4_decode_header)\n                        ih264d_parse_slice_partition(ps_dec, ps_bitstrm);\n\n                    break;\n\n                case IDR_SLICE_NAL:\n                case SLICE_NAL:\n\n                    /* ! */\n                    DEBUG_THREADS_PRINTF(\"Decoding  a slice NAL\\n\");\n                    if(!ps_dec->i4_decode_header)\n                    {\n                        if(ps_dec->i4_header_decoded == 3)\n                        {\n                            ih264d_get_pre_sei_params(ps_dec, u1_nal_unit_type);\n                            /* ! */\n                            ps_dec->u4_slice_start_code_found = 1;\n\n                            ih264d_rbsp_to_sodb(ps_dec->ps_bitstrm);\n\n                            i_status = ih264d_parse_decode_slice(\n                                            (UWORD8)(u1_nal_unit_type\n                                                            == IDR_SLICE_NAL),\n                                            u1_nal_ref_idc, ps_dec);\n\n                            if(i_status != OK)\n                            {\n                                return i_status;\n                            }\n                        }\n                        else\n                        {\n                            H264_DEC_DEBUG_PRINT(\n                                            \"\\nSlice NAL Supplied but no header has been supplied\\n\");\n                        }\n                    }\n                    break;\n\n                case SEI_NAL:\n                    if(!ps_dec->i4_decode_header)\n                    {\n                        ih264d_rbsp_to_sodb(ps_dec->ps_bitstrm);\n                        i_status = ih264d_parse_sei_message(ps_dec, ps_bitstrm);\n                        if(i_status != OK)\n                            return i_status;\n                        ih264d_parse_sei(ps_dec, ps_bitstrm);\n                    }\n                    break;\n                case SEQ_PARAM_NAL:\n                    /* ! */\n                    ih264d_rbsp_to_sodb(ps_dec->ps_bitstrm);\n                    i_status = ih264d_parse_sps(ps_dec, ps_bitstrm);\n                    ps_dec->u4_sps_cnt_in_process++;\n                    /*If a resolution change happens within a process call, due to multiple sps\n                     * we will not support it.\n                     */\n                    if((ps_dec->u4_sps_cnt_in_process > 1 ) &&\n                                    (i_status == IVD_RES_CHANGED))\n                    {\n                        i_status = ERROR_INV_SPS_PPS_T;\n                        ps_dec->u1_res_changed = 0;\n                    }\n                    if(i_status == ERROR_INV_SPS_PPS_T)\n                        return i_status;\n                    if(!i_status)\n                        ps_dec->i4_header_decoded |= 0x1;\n                    break;\n\n                case PIC_PARAM_NAL:\n                    /* ! */\n                    ih264d_rbsp_to_sodb(ps_dec->ps_bitstrm);\n                    i_status = ih264d_parse_pps(ps_dec, ps_bitstrm);\n                    if(i_status == ERROR_INV_SPS_PPS_T)\n                        return i_status;\n                    if(!i_status)\n                        ps_dec->i4_header_decoded |= 0x2;\n                    break;\n                case ACCESS_UNIT_DELIMITER_RBSP:\n                    if(!ps_dec->i4_decode_header)\n                    {\n                        ih264d_access_unit_delimiter_rbsp(ps_dec);\n                    }\n                    break;\n                    //Let us ignore the END_OF_SEQ_RBSP NAL and decode even after this NAL\n                case END_OF_STREAM_RBSP:\n                    if(!ps_dec->i4_decode_header)\n                    {\n                        ih264d_parse_end_of_stream(ps_dec);\n                    }\n                    break;\n                case FILLER_DATA_NAL:\n                    if(!ps_dec->i4_decode_header)\n                    {\n                        ih264d_parse_filler_data(ps_dec, ps_bitstrm);\n                    }\n                    break;\n                default:\n                    H264_DEC_DEBUG_PRINT(\"\\nUnknown NAL type %d\\n\", u1_nal_unit_type);\n                    break;\n            }\n\n        }\n\n    }\n\n    return i_status;\n\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_headers.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n * Modified for use with Cemu emulator project\n*/\n#ifndef  _IH264D_PARSE_HEADERS_H_\n#define  _IH264D_PARSE_HEADERS_H_\n/*!\n**************************************************************************\n* \\file ih264d_parse_headers.h\n*\n* \\brief\n*    Contains declarations high level syntax[above slice]\n*    parsing routines\n*\n* \\date\n*    19/12/2002\n*\n* \\author  AI\n**************************************************************************\n*/\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_structs.h\"\nWORD32 ih264d_parse_nal_unit(iv_obj_t *dec_hdl,\n                          ivd_video_decode_op_t *ps_dec_op,\n                          UWORD8 *pu1_buf,\n                          UWORD32 u4_length);\n\n#endif /* _IH264D_PARSE_HEADERS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_islice.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*!\n **************************************************************************\n * \\file ih264d_parse_islice.c\n *\n * \\brief\n *    Contains routines that decode a I slice type\n *\n * Detailed_description\n *\n * \\date\n *    07/07/2003\n *\n * \\author  NS\n **************************************************************************\n */\n#include <string.h>\n#include \"ih264_defs.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_cabac.h\"\n#include \"ih264d_parse_cabac.h\"\n#include \"ih264d_parse_mb_header.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_process_pslice.h\"\n#include \"ih264d_process_intra_mb.h\"\n#include \"ih264d_parse_islice.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_mvpred.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_thread_parse_decode.h\"\n#include \"ithread.h\"\n#include \"ih264d_parse_mb_header.h\"\n#include \"assert.h\"\n#include \"ih264d_utils.h\"\n#include \"ih264d_format_conv.h\"\n\nvoid ih264d_init_cabac_contexts(UWORD8 u1_slice_type, dec_struct_t * ps_dec);\n\nvoid ih264d_itrans_recon_luma_dc(dec_struct_t *ps_dec,\n                                 WORD16* pi2_src,\n                                 WORD16* pi2_coeff_block,\n                                 const UWORD16 *pu2_weigh_mat);\n\n\n\n/*!\n **************************************************************************\n * \\if Function name : ParseIMb \\endif\n *\n * \\brief\n *    This function parses CAVLC syntax of a I MB. If 16x16 Luma DC transform\n *    is also done here. Transformed Luma DC values are copied in their\n *    0th pixel location of corrosponding CoeffBlock.\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_imb_cavlc(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_num,\n                              UWORD8 u1_mb_type)\n{\n    WORD32 i4_delta_qp;\n    UWORD32 u4_temp;\n    UWORD32 ui_is_top_mb_available;\n    UWORD32 ui_is_left_mb_available;\n    UWORD32 u4_cbp;\n    UWORD32 u4_offset;\n    UWORD32 *pu4_bitstrm_buf;\n    WORD32 ret;\n\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UNUSED(u1_mb_num);\n    ps_cur_mb_info->u1_tran_form8x8 = 0;\n    ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n\n    ps_cur_mb_info->u1_yuv_dc_block_flag = 0;\n\n    u4_temp = ps_dec->u1_mb_ngbr_availablity;\n    ui_is_top_mb_available = BOOLEAN(u4_temp & TOP_MB_AVAILABLE_MASK);\n    ui_is_left_mb_available = BOOLEAN(u4_temp & LEFT_MB_AVAILABLE_MASK);\n\n    pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n\n    if(u1_mb_type == I_4x4_MB)\n    {\n        ps_cur_mb_info->ps_curmb->u1_mb_type = I_4x4_MB;\n        u4_offset = 0;\n\n        /*--------------------------------------------------------------------*/\n        /* Read transform_size_8x8_flag if present                            */\n        /*--------------------------------------------------------------------*/\n        if(ps_dec->s_high_profile.u1_transform8x8_present)\n        {\n            ps_cur_mb_info->u1_tran_form8x8 = ih264d_get_bit_h264(ps_bitstrm);\n            COPYTHECONTEXT(\"transform_size_8x8_flag\", ps_cur_mb_info->u1_tran_form8x8);\n            ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = ps_cur_mb_info->u1_tran_form8x8;\n        }\n\n        /*--------------------------------------------------------------------*/\n        /* Read the IntraPrediction modes for LUMA                            */\n        /*--------------------------------------------------------------------*/\n        if (!ps_cur_mb_info->u1_tran_form8x8)\n        {\n            UWORD8 *pu1_temp;\n            ih264d_read_intra_pred_modes(ps_dec,\n                                          ((UWORD8 *)ps_dec->pv_parse_tu_coeff_data),\n                                          ((UWORD8 *)ps_dec->pv_parse_tu_coeff_data+16),\n                                          ps_cur_mb_info->u1_tran_form8x8);\n            pu1_temp = (UWORD8 *)ps_dec->pv_parse_tu_coeff_data;\n            pu1_temp += 32;\n            ps_dec->pv_parse_tu_coeff_data = (void *)pu1_temp;\n        }\n        else\n        {\n            UWORD8 *pu1_temp;\n            ih264d_read_intra_pred_modes(ps_dec,\n                                          ((UWORD8 *)ps_dec->pv_parse_tu_coeff_data),\n                                          ((UWORD8 *)ps_dec->pv_parse_tu_coeff_data+4),\n                                          ps_cur_mb_info->u1_tran_form8x8);\n            pu1_temp = (UWORD8 *)ps_dec->pv_parse_tu_coeff_data;\n            pu1_temp += 8;\n            ps_dec->pv_parse_tu_coeff_data = (void *)pu1_temp;\n        }\n        /*--------------------------------------------------------------------*/\n        /* Read the IntraPrediction mode for CHROMA                           */\n        /*--------------------------------------------------------------------*/\n//Inlined ih264d_uev\n        {\n            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n            UWORD32 u4_word, u4_ldz, u4_temp;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n            u4_ldz = CLZ(u4_word);\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n            {\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_ldz);\n            }\n            *pu4_bitstrm_ofst = u4_bitstream_offset;\n            u4_temp = ((1 << u4_ldz) + u4_word - 1);\n            if(u4_temp > 3)\n            {\n                return ERROR_CHROMA_PRED_MODE;\n            }\n            ps_cur_mb_info->u1_chroma_pred_mode = u4_temp;\n            COPYTHECONTEXT(\"intra_chroma_pred_mode\", ps_cur_mb_info->u1_chroma_pred_mode);\n        }\n        /*--------------------------------------------------------------------*/\n        /* Read the Coded block pattern                                       */\n        /*--------------------------------------------------------------------*/\n        {\n            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n            UWORD32 u4_word, u4_ldz;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n            u4_ldz = CLZ(u4_word);\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n            {\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_ldz);\n            }\n            *pu4_bitstrm_ofst = u4_bitstream_offset;\n            u4_cbp = ((1 << u4_ldz) + u4_word - 1);\n        }\n        if(u4_cbp > 47)\n        {\n            return ERROR_CBP;\n        }\n\n        u4_cbp = gau1_ih264d_cbp_table[u4_cbp][0];\n        COPYTHECONTEXT(\"coded_block_pattern\", u1_cbp);\n        ps_cur_mb_info->u1_cbp = u4_cbp;\n\n        /*--------------------------------------------------------------------*/\n        /* Read mb_qp_delta                                                   */\n        /*--------------------------------------------------------------------*/\n        if(ps_cur_mb_info->u1_cbp)\n        {\n            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n            UWORD32 u4_word, u4_ldz, u4_abs_val;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n            u4_ldz = CLZ(u4_word);\n\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n            {\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_ldz);\n            }\n\n            *pu4_bitstrm_ofst = u4_bitstream_offset;\n            u4_abs_val = ((1 << u4_ldz) + u4_word) >> 1;\n\n            if(u4_word & 0x1)\n            {\n                i4_delta_qp = (-(WORD32)u4_abs_val);\n            }\n            else\n            {\n                i4_delta_qp = (u4_abs_val);\n            }\n\n            if((i4_delta_qp < -26) || (i4_delta_qp > 25))\n            {\n                return ERROR_INV_RANGE_QP_T;\n            }\n\n            COPYTHECONTEXT(\"mb_qp_delta\", i1_delta_qp);\n            if(i4_delta_qp != 0)\n            {\n                ret = ih264d_update_qp(ps_dec, (WORD8)i4_delta_qp);\n                if(ret != OK)\n                    return ret;\n            }\n        }\n\n    }\n    else\n    {\n        u4_offset = 1;\n        ps_cur_mb_info->ps_curmb->u1_mb_type = I_16x16_MB;\n        /*-------------------------------------------------------------------*/\n        /* Read the IntraPrediction mode for CHROMA                          */\n        /*-------------------------------------------------------------------*/\n        {\n            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n            UWORD32 u4_word, u4_ldz;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n            u4_ldz = CLZ(u4_word);\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n            {\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_ldz);\n            }\n            *pu4_bitstrm_ofst = u4_bitstream_offset;\n            u4_temp = ((1 << u4_ldz) + u4_word - 1);\n\n//Inlined ih264d_uev\n\n            if(u4_temp > 3)\n            {\n                return ERROR_CHROMA_PRED_MODE;\n            }\n            ps_cur_mb_info->u1_chroma_pred_mode = u4_temp;\n            COPYTHECONTEXT(\"intra_chroma_pred_mode\", ps_cur_mb_info->u1_chroma_pred_mode);\n        }\n        /*-------------------------------------------------------------------*/\n        /* Read the Coded block pattern                                      */\n        /*-------------------------------------------------------------------*/\n        u4_cbp = gau1_ih264d_cbp_tab[(u1_mb_type - 1) >> 2];\n        ps_cur_mb_info->u1_cbp = u4_cbp;\n\n        /*-------------------------------------------------------------------*/\n        /* Read mb_qp_delta                                                  */\n        /*-------------------------------------------------------------------*/\n        {\n            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n            UWORD32 u4_word, u4_ldz, u4_abs_val;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n            u4_ldz = CLZ(u4_word);\n\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_ldz);\n\n            *pu4_bitstrm_ofst = u4_bitstream_offset;\n            u4_abs_val = ((1 << u4_ldz) + u4_word) >> 1;\n\n            if(u4_word & 0x1)\n                i4_delta_qp = (-(WORD32)u4_abs_val);\n            else\n                i4_delta_qp = (u4_abs_val);\n\n            if((i4_delta_qp < -26) || (i4_delta_qp > 25))\n                return ERROR_INV_RANGE_QP_T;\n\n        }\n//inlinined ih264d_sev\n        COPYTHECONTEXT(\"Delta quant\", i1_delta_qp);\n\n        if(i4_delta_qp != 0)\n        {\n            ret = ih264d_update_qp(ps_dec, (WORD8)i4_delta_qp);\n            if(ret != OK)\n                return ret;\n        }\n\n        {\n            WORD16 i_scaleFactor;\n            UWORD32 ui_N = 0;\n            WORD16 *pi2_scale_matrix_ptr;\n            /*******************************************************************/\n            /* for luma DC coefficients the scaling is done during the parsing */\n            /* to preserve the precision                                       */\n            /*******************************************************************/\n            if(ps_dec->s_high_profile.u1_scaling_present)\n            {\n                pi2_scale_matrix_ptr =\n                                ps_dec->s_high_profile.i2_scalinglist4x4[0];\n            }\n            else\n            {\n                i_scaleFactor = 16;\n                pi2_scale_matrix_ptr = &i_scaleFactor;\n            }\n\n            /*---------------------------------------------------------------*/\n            /* Decode DC coefficients                                        */\n            /*---------------------------------------------------------------*/\n            /*---------------------------------------------------------------*/\n            /* Calculation of N                                              */\n            /*---------------------------------------------------------------*/\n            if(ui_is_left_mb_available)\n            {\n\n                if(ui_is_top_mb_available)\n                {\n                    ui_N = ((ps_cur_mb_info->ps_top_mb->pu1_nnz_y[0]\n                                    + ps_dec->pu1_left_nnz_y[0] + 1) >> 1);\n                }\n                else\n                {\n                    ui_N = ps_dec->pu1_left_nnz_y[0];\n                }\n            }\n            else if(ui_is_top_mb_available)\n            {\n                ui_N = ps_cur_mb_info->ps_top_mb->pu1_nnz_y[0];\n            }\n\n            {\n                WORD16 pi2_dc_coef[16];\n                WORD32 pi4_tmp[16];\n                tu_sblk4x4_coeff_data_t *ps_tu_4x4 =\n                                (tu_sblk4x4_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n                WORD16 *pi2_coeff_block =\n                                (WORD16 *)ps_dec->pv_parse_tu_coeff_data;\n                UWORD32 u4_num_coeff;\n                ps_tu_4x4->u2_sig_coeff_map = 0;\n\n                ret = ps_dec->pf_cavlc_parse4x4coeff[(ui_N > 7)](pi2_dc_coef, 0, ui_N,\n                                                                 ps_dec, &u4_num_coeff);\n                if(ret != OK)\n                    return ret;\n\n                if(EXCEED_OFFSET(ps_bitstrm))\n                    return ERROR_EOB_TERMINATE_T;\n                if(ps_tu_4x4->u2_sig_coeff_map)\n                {\n                    memset(pi2_dc_coef,0,sizeof(pi2_dc_coef));\n                    ih264d_unpack_coeff4x4_dc_4x4blk(ps_tu_4x4,\n                                                     pi2_dc_coef,\n                                                     ps_dec->pu1_inv_scan);\n\n                    PROFILE_DISABLE_IQ_IT_RECON()\n                    ps_dec->pf_ihadamard_scaling_4x4(pi2_dc_coef,\n                                                     pi2_coeff_block,\n                                                     ps_dec->pu2_quant_scale_y,\n                                                     (UWORD16 *)pi2_scale_matrix_ptr,\n                                                     ps_dec->u1_qp_y_div6,\n                                                     pi4_tmp);\n                    pi2_coeff_block += 16;\n                    ps_dec->pv_parse_tu_coeff_data = (void *)pi2_coeff_block;\n                    SET_BIT(ps_cur_mb_info->u1_yuv_dc_block_flag,0);\n                }\n\n            }\n        }\n    }\n\n\n    if(u4_cbp)\n    {\n\n        ret = ih264d_parse_residual4x4_cavlc(ps_dec, ps_cur_mb_info,\n                                       (UWORD8)u4_offset);\n        if(ret != OK)\n            return ret;\n        if(EXCEED_OFFSET(ps_bitstrm))\n            return ERROR_EOB_TERMINATE_T;\n\n        /* Store Left Mb NNZ and TOP chroma NNZ */\n    }\n    else\n    {\n        ps_cur_mb_info->u1_qp_div6 = ps_dec->u1_qp_y_div6;\n        ps_cur_mb_info->u1_qpc_div6 = ps_dec->u1_qp_u_div6;\n        ps_cur_mb_info->u1_qpcr_div6 = ps_dec->u1_qp_v_div6;\n        ps_cur_mb_info->u1_qp_rem6 = ps_dec->u1_qp_y_rem6;\n        ps_cur_mb_info->u1_qpc_rem6 = ps_dec->u1_qp_u_rem6;\n        ps_cur_mb_info->u1_qpcr_rem6 = ps_dec->u1_qp_v_rem6;\n        ih264d_update_nnz_for_skipmb(ps_dec, ps_cur_mb_info, CAVLC);\n    }\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ParseIMbCab \\endif\n *\n * \\brief\n *    This function parses CABAC syntax of a I MB. If 16x16 Luma DC transform\n *    is also done here. Transformed Luma DC values are copied in their\n *    0th pixel location of corrosponding CoeffBlock.\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_imb_cabac(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_type)\n{\n    WORD8 i1_delta_qp;\n    UWORD8 u1_cbp;\n    UWORD8 u1_offset;\n    /* Variables for handling Cabac contexts */\n    ctxt_inc_mb_info_t *p_curr_ctxt = ps_dec->ps_curr_ctxt_mb_info;\n    ctxt_inc_mb_info_t *ps_left_ctxt = ps_dec->p_left_ctxt_mb_info;\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    bin_ctxt_model_t *p_bin_ctxt;\n\n    UWORD8 u1_intra_chrom_pred_mode;\n    UWORD8 u1_dc_block_flag = 0;\n    WORD32 ret;\n\n    ps_cur_mb_info->u1_yuv_dc_block_flag = 0;\n\n    if(ps_left_ctxt == ps_dec->ps_def_ctxt_mb_info)\n    {\n        ps_dec->pu1_left_yuv_dc_csbp[0] = 0xf;\n    }\n\n    if(ps_dec->ps_cur_slice->u1_slice_type != I_SLICE)\n    {\n        WORD32 *pi4_buf;\n        WORD8 *pi1_buf;\n        MEMSET_16BYTES(&ps_dec->pu1_left_mv_ctxt_inc[0][0], 0);\n        *((UWORD32 *)ps_dec->pi1_left_ref_idx_ctxt_inc) = 0;\n        MEMSET_16BYTES(p_curr_ctxt->u1_mv, 0);\n        memset(p_curr_ctxt->i1_ref_idx, 0, 4);\n    }\n\n    if(u1_mb_type == I_4x4_MB)\n    {\n        ps_cur_mb_info->ps_curmb->u1_mb_type = I_4x4_MB;\n        p_curr_ctxt->u1_mb_type = CAB_I4x4;\n        u1_offset = 0;\n\n        ps_cur_mb_info->u1_tran_form8x8 = 0;\n        ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n\n        /*--------------------------------------------------------------------*/\n        /* Read transform_size_8x8_flag if present                            */\n        /*--------------------------------------------------------------------*/\n        if(ps_dec->s_high_profile.u1_transform8x8_present)\n        {\n            ps_cur_mb_info->u1_tran_form8x8 = ih264d_parse_transform8x8flag_cabac(\n                            ps_dec, ps_cur_mb_info);\n            COPYTHECONTEXT(\"transform_size_8x8_flag\", ps_cur_mb_info->u1_tran_form8x8);\n            p_curr_ctxt->u1_transform8x8_ctxt = ps_cur_mb_info->u1_tran_form8x8;\n            ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = ps_cur_mb_info->u1_tran_form8x8;\n        }\n        else\n        {\n            p_curr_ctxt->u1_transform8x8_ctxt = 0;\n        }\n\n        /*--------------------------------------------------------------------*/\n        /* Read the IntraPrediction modes for LUMA                            */\n        /*--------------------------------------------------------------------*/\n        if (!ps_cur_mb_info->u1_tran_form8x8)\n        {\n            UWORD8 *pu1_temp;\n            ih264d_read_intra_pred_modes_cabac(\n                            ps_dec,\n                            ((UWORD8 *)ps_dec->pv_parse_tu_coeff_data),\n                            ((UWORD8 *)ps_dec->pv_parse_tu_coeff_data+16),\n                            ps_cur_mb_info->u1_tran_form8x8);\n            pu1_temp = (UWORD8 *)ps_dec->pv_parse_tu_coeff_data;\n            pu1_temp += 32;\n            ps_dec->pv_parse_tu_coeff_data = (void *)pu1_temp;\n        }\n        else\n        {\n            UWORD8 *pu1_temp;\n            ih264d_read_intra_pred_modes_cabac(\n                            ps_dec,\n                            ((UWORD8 *)ps_dec->pv_parse_tu_coeff_data),\n                            ((UWORD8 *)ps_dec->pv_parse_tu_coeff_data+4),\n                            ps_cur_mb_info->u1_tran_form8x8);\n            pu1_temp = (UWORD8 *)ps_dec->pv_parse_tu_coeff_data;\n            pu1_temp += 8;\n            ps_dec->pv_parse_tu_coeff_data = (void *)pu1_temp;\n        }\n        /*--------------------------------------------------------------------*/\n        /* Read the IntraPrediction mode for CHROMA                           */\n        /*--------------------------------------------------------------------*/\n        u1_intra_chrom_pred_mode = ih264d_parse_chroma_pred_mode_cabac(ps_dec);\n        COPYTHECONTEXT(\"intra_chroma_pred_mode\", u1_intra_chrom_pred_mode);\n        p_curr_ctxt->u1_intra_chroma_pred_mode = ps_cur_mb_info->u1_chroma_pred_mode =\n                        u1_intra_chrom_pred_mode;\n\n        /*--------------------------------------------------------------------*/\n        /* Read the Coded block pattern                                       */\n        /*--------------------------------------------------------------------*/\n        u1_cbp = ih264d_parse_ctx_cbp_cabac(ps_dec);\n        COPYTHECONTEXT(\"coded_block_pattern\", u1_cbp);\n        ps_cur_mb_info->u1_cbp = u1_cbp;\n        p_curr_ctxt->u1_cbp = u1_cbp;\n\n        /*--------------------------------------------------------------------*/\n        /* Read mb_qp_delta                                                   */\n        /*--------------------------------------------------------------------*/\n        if(ps_cur_mb_info->u1_cbp)\n        {\n            ret = ih264d_parse_mb_qp_delta_cabac(ps_dec, &i1_delta_qp);\n            if(ret != OK)\n                return ret;\n            COPYTHECONTEXT(\"mb_qp_delta\", i1_delta_qp);\n            if(i1_delta_qp != 0)\n            {\n                ret = ih264d_update_qp(ps_dec, i1_delta_qp);\n                if(ret != OK)\n                    return ret;\n            }\n        }\n        else\n            ps_dec->i1_prev_mb_qp_delta = 0;\n        p_curr_ctxt->u1_yuv_dc_csbp &= 0xFE;\n    }\n    else\n    {\n        u1_offset = 1;\n        ps_cur_mb_info->ps_curmb->u1_mb_type = I_16x16_MB;\n        p_curr_ctxt->u1_mb_type = CAB_I16x16;\n        ps_cur_mb_info->u1_tran_form8x8 = 0;\n        p_curr_ctxt->u1_transform8x8_ctxt = 0;\n        ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n        /*--------------------------------------------------------------------*/\n        /* Read the IntraPrediction mode for CHROMA                           */\n        /*--------------------------------------------------------------------*/\n        u1_intra_chrom_pred_mode = ih264d_parse_chroma_pred_mode_cabac(ps_dec);\n        if(u1_intra_chrom_pred_mode > 3)\n            return ERROR_CHROMA_PRED_MODE;\n\n        COPYTHECONTEXT(\"Chroma intra_chroma_pred_mode pred mode\", u1_intra_chrom_pred_mode);\n        p_curr_ctxt->u1_intra_chroma_pred_mode = ps_cur_mb_info->u1_chroma_pred_mode =\n                        u1_intra_chrom_pred_mode;\n\n        /*--------------------------------------------------------------------*/\n        /* Read the Coded block pattern                                       */\n        /*--------------------------------------------------------------------*/\n        u1_cbp = gau1_ih264d_cbp_tab[(u1_mb_type - 1) >> 2];\n        ps_cur_mb_info->u1_cbp = u1_cbp;\n        p_curr_ctxt->u1_cbp = u1_cbp;\n\n        /*--------------------------------------------------------------------*/\n        /* Read mb_qp_delta                                                   */\n        /*--------------------------------------------------------------------*/\n        ret = ih264d_parse_mb_qp_delta_cabac(ps_dec, &i1_delta_qp);\n        if(ret != OK)\n            return ret;\n        COPYTHECONTEXT(\"mb_qp_delta\", i1_delta_qp);\n        if(i1_delta_qp != 0)\n        {\n            ret = ih264d_update_qp(ps_dec, i1_delta_qp);\n            if(ret != OK)\n                return ret;\n        }\n\n        {\n            WORD16 i_scaleFactor;\n            WORD16* pi2_scale_matrix_ptr;\n            /*******************************************************************/\n            /* for luma DC coefficients the scaling is done during the parsing */\n            /* to preserve the precision                                       */\n            /*******************************************************************/\n            if(ps_dec->s_high_profile.u1_scaling_present)\n            {\n                pi2_scale_matrix_ptr =\n                                ps_dec->s_high_profile.i2_scalinglist4x4[0];\n\n            }\n            else\n            {\n                i_scaleFactor = 16;\n                pi2_scale_matrix_ptr = &i_scaleFactor;\n            }\n            {\n                ctxt_inc_mb_info_t *ps_top_ctxt = ps_dec->p_top_ctxt_mb_info;\n                UWORD8 uc_a, uc_b;\n                UWORD32 u4_ctx_inc;\n\n                INC_SYM_COUNT(&(ps_dec->s_cab_dec_env));\n\n                /* if MbAddrN not available then CondTermN = 1 */\n                uc_b = ((ps_top_ctxt->u1_yuv_dc_csbp) & 0x01);\n\n                /* if MbAddrN not available then CondTermN = 1 */\n                uc_a = ((ps_dec->pu1_left_yuv_dc_csbp[0]) & 0x01);\n\n                u4_ctx_inc = (uc_a + (uc_b << 1));\n\n                {\n                    WORD16 pi2_dc_coef[16];\n                    tu_sblk4x4_coeff_data_t *ps_tu_4x4 =\n                                    (tu_sblk4x4_coeff_data_t *)ps_dec->pv_parse_tu_coeff_data;\n                    WORD16 *pi2_coeff_block =\n                                    (WORD16 *)ps_dec->pv_parse_tu_coeff_data;\n\n                    p_bin_ctxt = (ps_dec->p_cbf_t[LUMA_DC_CTXCAT]) + u4_ctx_inc;\n\n                    u1_dc_block_flag =\n                                    ih264d_read_coeff4x4_cabac(ps_bitstrm,\n                                                    LUMA_DC_CTXCAT,\n                                                    ps_dec->p_significant_coeff_flag_t[LUMA_DC_CTXCAT],\n                                                    ps_dec, p_bin_ctxt);\n\n                    /* Store coded_block_flag */\n                    p_curr_ctxt->u1_yuv_dc_csbp &= 0xFE;\n                    p_curr_ctxt->u1_yuv_dc_csbp |= u1_dc_block_flag;\n                    if(u1_dc_block_flag)\n                    {\n                        WORD32 pi4_tmp[16];\n                        memset(pi2_dc_coef,0,sizeof(pi2_dc_coef));\n                        ih264d_unpack_coeff4x4_dc_4x4blk(ps_tu_4x4,\n                                                         pi2_dc_coef,\n                                                         ps_dec->pu1_inv_scan);\n\n                        PROFILE_DISABLE_IQ_IT_RECON()\n                        ps_dec->pf_ihadamard_scaling_4x4(pi2_dc_coef,\n                                                         pi2_coeff_block,\n                                                         ps_dec->pu2_quant_scale_y,\n                                                         (UWORD16 *)pi2_scale_matrix_ptr,\n                                                         ps_dec->u1_qp_y_div6,\n                                                         pi4_tmp);\n                        pi2_coeff_block += 16;\n                        ps_dec->pv_parse_tu_coeff_data = (void *)pi2_coeff_block;\n                        SET_BIT(ps_cur_mb_info->u1_yuv_dc_block_flag,0);\n                    }\n\n                }\n\n            }\n        }\n    }\n\n    ps_dec->pu1_left_yuv_dc_csbp[0] &= 0x6;\n    ps_dec->pu1_left_yuv_dc_csbp[0] |= u1_dc_block_flag;\n\n    ih264d_parse_residual4x4_cabac(ps_dec, ps_cur_mb_info, u1_offset);\n    if(EXCEED_OFFSET(ps_bitstrm))\n        return ERROR_EOB_TERMINATE_T;\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_islice_data_cavlc                                  */\n/*                                                                           */\n/*  Description   : This function parses cabac syntax of a inter slice on    */\n/*                  N MB basis.                                              */\n/*                                                                           */\n/*  Inputs        : ps_dec                                                   */\n/*                  sliceparams                                              */\n/*                  firstMbInSlice                                           */\n/*                                                                           */\n/*  Processing    : 1. After parsing syntax for N MBs those N MBs are        */\n/*                     decoded till the end of slice.                        */\n/*                                                                           */\n/*  Returns       : 0                                                        */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         24 06 2005   ARNY            Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_islice_data_cavlc(dec_struct_t * ps_dec,\n                                      dec_slice_params_t * ps_slice,\n                                      UWORD16 u2_first_mb_in_slice)\n{\n    UWORD8 uc_more_data_flag;\n    UWORD8 u1_num_mbs, u1_mb_idx;\n    dec_mb_info_t *ps_cur_mb_info;\n    deblk_mb_t *ps_cur_deblk_mb;\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD16 i2_pic_wdin_mbs = ps_dec->u2_frm_wd_in_mbs;\n    WORD16 i2_cur_mb_addr;\n    UWORD8 u1_mbaff;\n    UWORD8 u1_num_mbs_next, u1_end_of_row, u1_tfr_n_mb;\n    WORD32 ret = OK;\n\n    ps_dec->u1_qp = ps_slice->u1_slice_qp;\n    ih264d_update_qp(ps_dec, 0);\n    u1_mbaff = ps_slice->u1_mbaff_frame_flag;\n\n    /* initializations */\n    u1_mb_idx = ps_dec->u1_mb_idx;\n    u1_num_mbs = u1_mb_idx;\n\n    uc_more_data_flag = 1;\n    i2_cur_mb_addr = u2_first_mb_in_slice << u1_mbaff;\n\n    do\n    {\n        UWORD8 u1_mb_type;\n\n        ps_dec->pv_prev_mb_parse_tu_coeff_data = ps_dec->pv_parse_tu_coeff_data;\n\n        if(i2_cur_mb_addr > ps_dec->ps_cur_sps->u2_max_mb_addr)\n        {\n            break;\n        }\n\n        ps_cur_mb_info = ps_dec->ps_nmb_info + u1_num_mbs;\n        ps_dec->u4_num_mbs_cur_nmb = u1_num_mbs;\n        ps_dec->u4_num_pmbair = (u1_num_mbs >> u1_mbaff);\n\n        ps_cur_mb_info->u1_end_of_slice = 0;\n\n        /***************************************************************/\n        /* Get the required information for decoding of MB             */\n        /* mb_x, mb_y , neighbour availablity,                         */\n        /***************************************************************/\n        ps_dec->pf_get_mb_info(ps_dec, i2_cur_mb_addr, ps_cur_mb_info, 0);\n\n        /***************************************************************/\n        /* Set the deblocking parameters for this MB                   */\n        /***************************************************************/\n        ps_cur_deblk_mb = ps_dec->ps_deblk_mbn + u1_num_mbs;\n\n        if(ps_dec->u4_app_disable_deblk_frm == 0)\n            ih264d_set_deblocking_parameters(ps_cur_deblk_mb, ps_slice,\n                                             ps_dec->u1_mb_ngbr_availablity,\n                                             ps_dec->u1_cur_mb_fld_dec_flag);\n\n        ps_cur_deblk_mb->u1_mb_type = ps_cur_deblk_mb->u1_mb_type | D_INTRA_MB;\n\n        /**************************************************************/\n        /* Macroblock Layer Begins, Decode the u1_mb_type                */\n        /**************************************************************/\n//Inlined ih264d_uev\n        {\n            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n            UWORD32 u4_word, u4_ldz, u4_temp;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n            u4_ldz = CLZ(u4_word);\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_ldz);\n            *pu4_bitstrm_ofst = u4_bitstream_offset;\n            u4_temp = ((1 << u4_ldz) + u4_word - 1);\n            if(u4_temp > 25)\n                return ERROR_MB_TYPE;\n            u1_mb_type = u4_temp;\n\n        }\n//Inlined ih264d_uev\n        ps_cur_mb_info->u1_mb_type = u1_mb_type;\n        COPYTHECONTEXT(\"u1_mb_type\", u1_mb_type);\n\n        /**************************************************************/\n        /* Parse Macroblock data                                      */\n        /**************************************************************/\n        if(25 == u1_mb_type)\n        {\n            /* I_PCM_MB */\n            ps_cur_mb_info->ps_curmb->u1_mb_type = I_PCM_MB;\n            ret = ih264d_parse_ipcm_mb(ps_dec, ps_cur_mb_info, u1_num_mbs);\n            if(ret != OK)\n                return ret;\n            ps_cur_deblk_mb->u1_mb_qp = 0;\n        }\n        else\n        {\n            ret = ih264d_parse_imb_cavlc(ps_dec, ps_cur_mb_info, u1_num_mbs, u1_mb_type);\n            if(ret != OK)\n                return ret;\n            ps_cur_deblk_mb->u1_mb_qp = ps_dec->u1_qp;\n        }\n\n        uc_more_data_flag = MORE_RBSP_DATA(ps_bitstrm);\n\n        if(u1_mbaff)\n        {\n            ih264d_update_mbaff_left_nnz(ps_dec, ps_cur_mb_info);\n            if(!uc_more_data_flag && (0 == (i2_cur_mb_addr & 1)))\n            {\n                return ERROR_EOB_FLUSHBITS_T;\n            }\n        }\n        /**************************************************************/\n        /* Get next Macroblock address                                */\n        /**************************************************************/\n\n        i2_cur_mb_addr++;\n\n\n        /* Store the colocated information */\n        {\n            mv_pred_t *ps_mv_nmb_start = ps_dec->ps_mv_cur + (u1_num_mbs << 4);\n\n            mv_pred_t s_mvPred =\n                {\n                    { 0, 0, 0, 0 },\n                      { -1, -1 }, 0, 0};\n            ih264d_rep_mv_colz(ps_dec, &s_mvPred, ps_mv_nmb_start, 0,\n                               (UWORD8)(ps_dec->u1_cur_mb_fld_dec_flag << 1), 4,\n                               4);\n        }\n\n        /*if num _cores is set to 3,compute bs will be done in another thread*/\n        if(ps_dec->u4_num_cores < 3)\n        {\n            if(ps_dec->u4_app_disable_deblk_frm == 0)\n                ps_dec->pf_compute_bs(ps_dec, ps_cur_mb_info,\n                                     (UWORD16)(u1_num_mbs >> u1_mbaff));\n        }\n        u1_num_mbs++;\n\n        /****************************************************************/\n        /* Check for End Of Row                                         */\n        /****************************************************************/\n        u1_num_mbs_next = i2_pic_wdin_mbs - ps_dec->u2_mbx - 1;\n        u1_end_of_row = (!u1_num_mbs_next) && (!(u1_mbaff && (u1_num_mbs & 0x01)));\n        u1_tfr_n_mb = (u1_num_mbs == ps_dec->u1_recon_mb_grp) || u1_end_of_row\n                        || (!uc_more_data_flag);\n        ps_cur_mb_info->u1_end_of_slice = (!uc_more_data_flag);\n\n        /*H264_DEC_DEBUG_PRINT(\"Pic: %d Mb_X=%d Mb_Y=%d\",\n         ps_slice->i4_poc >> ps_slice->u1_field_pic_flag,\n         ps_dec->u2_mbx,ps_dec->u2_mby + (1 - ps_cur_mb_info->u1_topmb));\n         H264_DEC_DEBUG_PRINT(\"u1_tfr_n_mb || (!uc_more_data_flag): %d\", u1_tfr_n_mb || (!uc_more_data_flag));*/\n        if(u1_tfr_n_mb || (!uc_more_data_flag))\n        {\n\n            if(ps_dec->u1_separate_parse)\n            {\n                ih264d_parse_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                                     u1_num_mbs_next, u1_tfr_n_mb, u1_end_of_row);\n                ps_dec->ps_nmb_info +=  u1_num_mbs;\n            }\n            else\n            {\n                ih264d_decode_recon_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                                            u1_num_mbs_next, u1_tfr_n_mb,\n                                            u1_end_of_row);\n            }\n            ps_dec->u2_total_mbs_coded += u1_num_mbs;\n            if(u1_tfr_n_mb)\n                u1_num_mbs = 0;\n            u1_mb_idx = u1_num_mbs;\n            ps_dec->u1_mb_idx = u1_num_mbs;\n\n        }\n    }\n    while(uc_more_data_flag);\n\n    ps_dec->u4_num_mbs_cur_nmb = 0;\n    ps_dec->ps_cur_slice->u4_mbs_in_slice = i2_cur_mb_addr\n\n                        - (u2_first_mb_in_slice << u1_mbaff);\n\n    return ret;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_islice_data_cabac                                  */\n/*                                                                           */\n/*  Description   : This function parses cabac syntax of a inter slice on    */\n/*                  N MB basis.                                              */\n/*                                                                           */\n/*  Inputs        : ps_dec                                                   */\n/*                  sliceparams                                              */\n/*                  firstMbInSlice                                           */\n/*                                                                           */\n/*  Processing    : 1. After parsing syntax for N MBs those N MBs are        */\n/*                     decoded till the end of slice.                        */\n/*                                                                           */\n/*  Returns       : 0                                                        */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         24 06 2005   ARNY            Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_islice_data_cabac(dec_struct_t * ps_dec,\n                                      dec_slice_params_t * ps_slice,\n                                      UWORD16 u2_first_mb_in_slice)\n{\n    UWORD8 uc_more_data_flag;\n    UWORD8 u1_num_mbs, u1_mb_idx;\n    dec_mb_info_t *ps_cur_mb_info;\n    deblk_mb_t *ps_cur_deblk_mb;\n\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD16 i2_pic_wdin_mbs = ps_dec->u2_frm_wd_in_mbs;\n    WORD16 i2_cur_mb_addr;\n    UWORD8 u1_mbaff;\n    UWORD8 u1_num_mbs_next, u1_end_of_row, u1_tfr_n_mb;\n    WORD32 ret = OK;\n\n    ps_dec->u1_qp = ps_slice->u1_slice_qp;\n    ih264d_update_qp(ps_dec, 0);\n    u1_mbaff = ps_slice->u1_mbaff_frame_flag;\n\n    if(ps_bitstrm->u4_ofst & 0x07)\n    {\n        ps_bitstrm->u4_ofst += 8;\n        ps_bitstrm->u4_ofst &= 0xFFFFFFF8;\n    }\n    ret = ih264d_init_cabac_dec_envirnoment(&(ps_dec->s_cab_dec_env), ps_bitstrm);\n    if(ret != OK)\n        return ret;\n    ih264d_init_cabac_contexts(I_SLICE, ps_dec);\n\n    ps_dec->i1_prev_mb_qp_delta = 0;\n\n    /* initializations */\n    u1_mb_idx = ps_dec->u1_mb_idx;\n    u1_num_mbs = u1_mb_idx;\n\n    uc_more_data_flag = 1;\n    i2_cur_mb_addr = u2_first_mb_in_slice << u1_mbaff;\n    do\n    {\n        UWORD16 u2_mbx;\n\n        ps_dec->pv_prev_mb_parse_tu_coeff_data = ps_dec->pv_parse_tu_coeff_data;\n\n        if(i2_cur_mb_addr > ps_dec->ps_cur_sps->u2_max_mb_addr)\n        {\n            break;\n        }\n\n        {\n            UWORD8 u1_mb_type;\n\n            ps_cur_mb_info = ps_dec->ps_nmb_info + u1_num_mbs;\n            ps_dec->u4_num_mbs_cur_nmb = u1_num_mbs;\n            ps_dec->u4_num_pmbair = (u1_num_mbs >> u1_mbaff);\n\n            ps_cur_mb_info->u1_end_of_slice = 0;\n\n            /***************************************************************/\n            /* Get the required information for decoding of MB                  */\n            /* mb_x, mb_y , neighbour availablity,                              */\n            /***************************************************************/\n            ps_dec->pf_get_mb_info(ps_dec, i2_cur_mb_addr, ps_cur_mb_info, 0);\n            u2_mbx = ps_dec->u2_mbx;\n\n            /*********************************************************************/\n            /* initialize u1_tran_form8x8 to zero to aviod uninitialized accesses */\n            /*********************************************************************/\n            ps_cur_mb_info->u1_tran_form8x8 = 0;\n            ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n\n            /***************************************************************/\n            /* Set the deblocking parameters for this MB                   */\n            /***************************************************************/\n            ps_cur_deblk_mb = ps_dec->ps_deblk_mbn + u1_num_mbs;\n            if(ps_dec->u4_app_disable_deblk_frm == 0)\n                ih264d_set_deblocking_parameters(\n                                ps_cur_deblk_mb, ps_slice,\n                                ps_dec->u1_mb_ngbr_availablity,\n                                ps_dec->u1_cur_mb_fld_dec_flag);\n\n            ps_cur_deblk_mb->u1_mb_type = ps_cur_deblk_mb->u1_mb_type\n                            | D_INTRA_MB;\n\n            /* Macroblock Layer Begins */\n            /* Decode the u1_mb_type */\n            u1_mb_type = ih264d_parse_mb_type_intra_cabac(0, ps_dec);\n            if(u1_mb_type > 25)\n                return ERROR_MB_TYPE;\n            ps_cur_mb_info->u1_mb_type = u1_mb_type;\n            COPYTHECONTEXT(\"u1_mb_type\", u1_mb_type);\n\n            /* Parse Macroblock Data */\n            if(25 == u1_mb_type)\n            {\n                /* I_PCM_MB */\n                ps_cur_mb_info->ps_curmb->u1_mb_type = I_PCM_MB;\n                ret = ih264d_parse_ipcm_mb(ps_dec, ps_cur_mb_info, u1_num_mbs);\n                if(ret != OK)\n                    return ret;\n                ps_cur_deblk_mb->u1_mb_qp = 0;\n            }\n            else\n            {\n                ret = ih264d_parse_imb_cabac(ps_dec, ps_cur_mb_info, u1_mb_type);\n                if(ret != OK)\n                    return ret;\n                ps_cur_deblk_mb->u1_mb_qp = ps_dec->u1_qp;\n            }\n\n            if(u1_mbaff)\n            {\n                ih264d_update_mbaff_left_nnz(ps_dec, ps_cur_mb_info);\n            }\n\n\n            if(ps_cur_mb_info->u1_topmb && u1_mbaff)\n                uc_more_data_flag = 1;\n            else\n            {\n                uc_more_data_flag = ih264d_decode_terminate(&ps_dec->s_cab_dec_env,\n                                                          ps_bitstrm);\n                uc_more_data_flag = !uc_more_data_flag;\n                COPYTHECONTEXT(\"Decode Sliceterm\",!uc_more_data_flag);\n            }\n\n            if(u1_mbaff)\n            {\n                if(!uc_more_data_flag && (0 == (i2_cur_mb_addr & 1)))\n                {\n                    return ERROR_EOB_FLUSHBITS_T;\n                }\n            }\n            /* Next macroblock information */\n            i2_cur_mb_addr++;\n            /* Store the colocated information */\n            {\n\n                mv_pred_t *ps_mv_nmb_start = ps_dec->ps_mv_cur + (u1_num_mbs << 4);\n                mv_pred_t s_mvPred =\n                    {\n                        { 0, 0, 0, 0 },\n                          { -1, -1 }, 0, 0};\n                ih264d_rep_mv_colz(\n                                ps_dec, &s_mvPred, ps_mv_nmb_start, 0,\n                                (UWORD8)(ps_dec->u1_cur_mb_fld_dec_flag << 1),\n                                4, 4);\n            }\n            /*if num _cores is set to 3,compute bs will be done in another thread*/\n            if(ps_dec->u4_num_cores < 3)\n            {\n                if(ps_dec->u4_app_disable_deblk_frm == 0)\n                    ps_dec->pf_compute_bs(ps_dec, ps_cur_mb_info,\n                                         (UWORD16)(u1_num_mbs >> u1_mbaff));\n            }\n            u1_num_mbs++;\n\n        }\n\n        /****************************************************************/\n        /* Check for End Of Row                                         */\n        /****************************************************************/\n        u1_num_mbs_next = i2_pic_wdin_mbs - u2_mbx - 1;\n        u1_end_of_row = (!u1_num_mbs_next) && (!(u1_mbaff && (u1_num_mbs & 0x01)));\n        u1_tfr_n_mb = (u1_num_mbs == ps_dec->u1_recon_mb_grp) || u1_end_of_row\n                        || (!uc_more_data_flag);\n        ps_cur_mb_info->u1_end_of_slice = (!uc_more_data_flag);\n\n        if(u1_tfr_n_mb || (!uc_more_data_flag))\n        {\n\n\n            if(ps_dec->u1_separate_parse)\n            {\n                ih264d_parse_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                                     u1_num_mbs_next, u1_tfr_n_mb, u1_end_of_row);\n                ps_dec->ps_nmb_info +=  u1_num_mbs;\n            }\n            else\n            {\n                ih264d_decode_recon_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                                            u1_num_mbs_next, u1_tfr_n_mb,\n                                            u1_end_of_row);\n            }\n            ps_dec->u2_total_mbs_coded += u1_num_mbs;\n            if(u1_tfr_n_mb)\n                u1_num_mbs = 0;\n            u1_mb_idx = u1_num_mbs;\n            ps_dec->u1_mb_idx = u1_num_mbs;\n\n        }\n    }\n    while(uc_more_data_flag);\n\n    ps_dec->u4_num_mbs_cur_nmb = 0;\n    ps_dec->ps_cur_slice->u4_mbs_in_slice = i2_cur_mb_addr\n\n                        - (u2_first_mb_in_slice << u1_mbaff);\n\n    return ret;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_ipcm_mb                                       */\n/*                                                                           */\n/*  Description   : This function decodes the pixel values of I_PCM Mb.      */\n/*                                                                           */\n/*  Inputs        : ps_dec,  ps_cur_mb_info and mb number                          */\n/*                                                                           */\n/*  Description   : This function reads the luma and chroma pixels directly  */\n/*                  from the bitstream when the mbtype is I_PCM and stores   */\n/*                  them in recon buffer. If the entropy coding mode is      */\n/*                  cabac, decoding engine is re-initialized. The nnzs and   */\n/*                  cabac contexts are appropriately modified.               */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 07 2002   Jay                                                  */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_parse_ipcm_mb(dec_struct_t * ps_dec,\n                          dec_mb_info_t *ps_cur_mb_info,\n                          UWORD8 u1_mbNum)\n{\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    UWORD8 *pu1_y, *pu1_u, *pu1_v;\n    WORD32 ret;\n\n    UWORD32 u4_rec_width_y, u4_rec_width_uv;\n    UWORD32 u1_num_mb_pair;\n    UWORD8 u1_x, u1_y;\n    /* CHANGED CODE */\n    tfr_ctxt_t *ps_frame_buf;\n    UWORD8 u1_mb_field_decoding_flag;\n    UWORD32 *pu4_buf;\n    UWORD8 *pu1_buf;\n    /* CHANGED CODE */\n\n    if(ps_dec->u1_separate_parse)\n    {\n        ps_frame_buf = &ps_dec->s_tran_addrecon_parse;\n    }\n    else\n    {\n        ps_frame_buf = &ps_dec->s_tran_addrecon;\n    }\n    /* align bistream to byte boundary. */\n    /* pcm_alignment_zero_bit discarded */\n    /* For XX GotoByteBoundary */\n    if(ps_bitstrm->u4_ofst & 0x07)\n    {\n        ps_bitstrm->u4_ofst += 8;\n        ps_bitstrm->u4_ofst &= 0xFFFFFFF8;\n    }\n\n    /*  Store left Nnz as 16 for each 4x4 blk */\n\n    pu1_buf = ps_dec->pu1_left_nnz_y;\n    pu4_buf = (UWORD32 *)pu1_buf;\n    *pu4_buf = 0x10101010;\n    pu1_buf = ps_cur_mb_info->ps_curmb->pu1_nnz_y;\n    pu4_buf = (UWORD32 *)pu1_buf;\n    *pu4_buf = 0x10101010;\n    pu1_buf = ps_cur_mb_info->ps_curmb->pu1_nnz_uv;\n    pu4_buf = (UWORD32 *)pu1_buf;\n    *pu4_buf = 0x10101010;\n    pu1_buf = ps_dec->pu1_left_nnz_uv;\n    pu4_buf = (UWORD32 *)pu1_buf;\n    *pu4_buf = 0x10101010;\n    ps_cur_mb_info->u1_cbp = 0xff;\n\n    ps_dec->i1_prev_mb_qp_delta = 0;\n    /* Get neighbour MB's */\n    u1_num_mb_pair = (u1_mbNum >> u1_mbaff);\n\n    /*****************************************************************************/\n    /* calculate the RECON buffer YUV pointers for the PCM data                  */\n    /*****************************************************************************/\n    /* CHANGED CODE  */\n    u1_mb_field_decoding_flag = ps_cur_mb_info->u1_mb_field_decodingflag;\n    pu1_y = ps_frame_buf->pu1_dest_y + (u1_num_mb_pair << 4);\n    pu1_u = ps_frame_buf->pu1_dest_u + (u1_num_mb_pair << 4);\n    pu1_v = pu1_u + 1;\n\n    u4_rec_width_y = ps_dec->u2_frm_wd_y << u1_mb_field_decoding_flag;\n    u4_rec_width_uv = ps_dec->u2_frm_wd_uv << u1_mb_field_decoding_flag;\n    /* CHANGED CODE  */\n\n    if(u1_mbaff)\n    {\n        UWORD8 u1_top_mb;\n\n        u1_top_mb = ps_cur_mb_info->u1_topmb;\n\n        if(u1_top_mb == 0)\n        {\n            pu1_y += (u1_mb_field_decoding_flag ?\n                            (u4_rec_width_y >> 1) : (u4_rec_width_y << 4));\n            pu1_u += (u1_mb_field_decoding_flag ?\n                            (u4_rec_width_uv) : (u4_rec_width_uv << 4));\n            pu1_v = pu1_u + 1;\n        }\n    }\n\n    /* Read Luma samples */\n    for(u1_y = 0; u1_y < 16; u1_y++)\n    {\n        for(u1_x = 0; u1_x < 16; u1_x++)\n            pu1_y[u1_x] = ih264d_get_bits_h264(ps_bitstrm, 8);\n\n        pu1_y += u4_rec_width_y;\n    }\n\n    /* Read Chroma samples */\n    for(u1_y = 0; u1_y < 8; u1_y++)\n    {\n        for(u1_x = 0; u1_x < 8; u1_x++)\n            pu1_u[u1_x * YUV420SP_FACTOR] = ih264d_get_bits_h264(ps_bitstrm, 8);\n\n        pu1_u += u4_rec_width_uv;\n    }\n\n    for(u1_y = 0; u1_y < 8; u1_y++)\n    {\n        for(u1_x = 0; u1_x < 8; u1_x++)\n            pu1_v[u1_x * YUV420SP_FACTOR] = ih264d_get_bits_h264(ps_bitstrm, 8);\n\n        pu1_v += u4_rec_width_uv;\n    }\n\n    if(CABAC == ps_dec->ps_cur_pps->u1_entropy_coding_mode)\n    {\n        UWORD32 *pu4_buf;\n        UWORD8 *pu1_buf;\n        ctxt_inc_mb_info_t *p_curr_ctxt = ps_dec->ps_curr_ctxt_mb_info;\n        /* Re-initialize the cabac decoding engine. */\n        ret = ih264d_init_cabac_dec_envirnoment(&(ps_dec->s_cab_dec_env), ps_bitstrm);\n        if(ret != OK)\n            return ret;\n        /* update the cabac contetxs */\n        p_curr_ctxt->u1_mb_type = CAB_I_PCM;\n        p_curr_ctxt->u1_cbp = 47;\n        p_curr_ctxt->u1_intra_chroma_pred_mode = 0;\n        p_curr_ctxt->u1_transform8x8_ctxt = 0;\n        ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n\n        pu1_buf = ps_dec->pu1_left_nnz_y;\n        pu4_buf = (UWORD32 *)pu1_buf;\n        *pu4_buf = 0x01010101;\n\n        pu1_buf = ps_cur_mb_info->ps_curmb->pu1_nnz_y;\n        pu4_buf = (UWORD32 *)pu1_buf;\n        *pu4_buf = 0x01010101;\n\n        pu1_buf = ps_cur_mb_info->ps_curmb->pu1_nnz_uv;\n        pu4_buf = (UWORD32 *)pu1_buf;\n        *pu4_buf = 0x01010101;\n\n        pu1_buf = ps_dec->pu1_left_nnz_uv;\n        pu4_buf = (UWORD32 *)pu1_buf;\n        *pu4_buf = 0x01010101;\n\n        p_curr_ctxt->u1_yuv_dc_csbp = 0x7;\n        ps_dec->pu1_left_yuv_dc_csbp[0] = 0x7;\n        if(ps_dec->ps_cur_slice->u1_slice_type != I_SLICE)\n        {\n\n            MEMSET_16BYTES(&ps_dec->pu1_left_mv_ctxt_inc[0][0], 0);\n            memset(ps_dec->pi1_left_ref_idx_ctxt_inc, 0, 4);\n            MEMSET_16BYTES(p_curr_ctxt->u1_mv, 0);\n            memset(p_curr_ctxt->i1_ref_idx, 0, 4);\n\n        }\n    }\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_decode_islice \\endif\n *\n * \\brief\n *    Decodes an I Slice\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_islice(dec_struct_t *ps_dec,\n                            UWORD16 u2_first_mb_in_slice)\n{\n    dec_pic_params_t * ps_pps = ps_dec->ps_cur_pps;\n    dec_slice_params_t * ps_slice = ps_dec->ps_cur_slice;\n    UWORD32 *pu4_bitstrm_buf = ps_dec->ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_dec->ps_bitstrm->u4_ofst;\n    UWORD32 u4_temp;\n    WORD32 i_temp;\n    WORD32 ret;\n\n    /*--------------------------------------------------------------------*/\n    /* Read remaining contents of the slice header                        */\n    /*--------------------------------------------------------------------*/\n    /* dec_ref_pic_marking function */\n    /* G050 */\n    if(ps_slice->u1_nal_ref_idc != 0)\n    {\n        if(!ps_dec->ps_dpb_cmds->u1_dpb_commands_read)\n        {\n            i_temp = ih264d_read_mmco_commands(ps_dec);\n            if (i_temp < 0)\n            {\n                return ERROR_DBP_MANAGER_T;\n            }\n            ps_dec->u4_bitoffset = i_temp;\n        }\n        else\n            ps_dec->ps_bitstrm->u4_ofst += ps_dec->u4_bitoffset;\n    }\n    /* G050 */\n\n    /* Read slice_qp_delta */\n    WORD64 i8_temp = (WORD64)ps_pps->u1_pic_init_qp\n                        + ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if((i8_temp < MIN_H264_QP) || (i8_temp > MAX_H264_QP))\n        return ERROR_INV_RANGE_QP_T;\n    ps_slice->u1_slice_qp = i8_temp;\n    COPYTHECONTEXT(\"SH: slice_qp_delta\",\n                    ps_slice->u1_slice_qp - ps_pps->u1_pic_init_qp);\n\n    if(ps_pps->u1_deblocking_filter_parameters_present_flag == 1)\n    {\n        u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        COPYTHECONTEXT(\"SH: disable_deblocking_filter_idc\", u4_temp);\n\n        if(u4_temp > SLICE_BOUNDARY_DBLK_DISABLED)\n        {\n            return ERROR_INV_SLICE_HDR_T;\n        }\n        ps_slice->u1_disable_dblk_filter_idc = u4_temp;\n        if(u4_temp != 1)\n        {\n            i_temp = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf)\n                            << 1;\n            if((MIN_DBLK_FIL_OFF > i_temp) || (i_temp > MAX_DBLK_FIL_OFF))\n            {\n                return ERROR_INV_SLICE_HDR_T;\n            }\n            ps_slice->i1_slice_alpha_c0_offset = i_temp;\n            COPYTHECONTEXT(\"SH: slice_alpha_c0_offset_div2\",\n                            ps_slice->i1_slice_alpha_c0_offset >> 1);\n\n            i_temp = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf)\n                            << 1;\n            if((MIN_DBLK_FIL_OFF > i_temp) || (i_temp > MAX_DBLK_FIL_OFF))\n            {\n                return ERROR_INV_SLICE_HDR_T;\n            }\n            ps_slice->i1_slice_beta_offset = i_temp;\n            COPYTHECONTEXT(\"SH: slice_beta_offset_div2\",\n                            ps_slice->i1_slice_beta_offset >> 1);\n\n        }\n        else\n        {\n            ps_slice->i1_slice_alpha_c0_offset = 0;\n            ps_slice->i1_slice_beta_offset = 0;\n        }\n    }\n    else\n    {\n        ps_slice->u1_disable_dblk_filter_idc = 0;\n        ps_slice->i1_slice_alpha_c0_offset = 0;\n        ps_slice->i1_slice_beta_offset = 0;\n    }\n\n    /* Initialization to check if number of motion vector per 2 Mbs */\n    /* are exceeding the range or not */\n    ps_dec->u2_mv_2mb[0] = 0;\n    ps_dec->u2_mv_2mb[1] = 0;\n\n\n    /*set slice header cone to 2 ,to indicate  correct header*/\n    ps_dec->u1_slice_header_done = 2;\n\n    if(ps_pps->u1_entropy_coding_mode)\n    {\n        SWITCHOFFTRACE; SWITCHONTRACECABAC;\n        if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag)\n        {\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cabac_mbaff;\n        }\n        else\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cabac_nonmbaff;\n\n        ret = ih264d_parse_islice_data_cabac(ps_dec, ps_slice,\n                                             u2_first_mb_in_slice);\n        if(ret != OK)\n            return ret;\n        SWITCHONTRACE; SWITCHOFFTRACECABAC;\n    }\n    else\n    {\n        if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag)\n        {\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cavlc_mbaff;\n        }\n        else\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cavlc_nonmbaff;\n        ret = ih264d_parse_islice_data_cavlc(ps_dec, ps_slice,\n                                       u2_first_mb_in_slice);\n        if(ret != OK)\n            return ret;\n    }\n\n    return OK;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_islice.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*!\n **************************************************************************\n * \\file ih264d_parse_islice.h\n *\n * \\brief\n *    Contains routines that decode a I slice type\n *\n * Detailed_description\n *\n * \\date\n *    07/07/2003\n *\n * \\author  NS\n **************************************************************************\n */\n\n#ifndef _IH264D_PARSE_ISLICE_H_\n#define _IH264D_PARSE_ISLICE_H_\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_tables.h\"\n\nWORD32 ih264d_parse_residual4x4_cavlc(dec_struct_t * ps_dec,\n                                      dec_mb_info_t *ps_cur_mb_info,\n                                      UWORD8 u1_offset);\nWORD32 ih264d_parse_residual4x4_cabac(dec_struct_t * ps_dec,\n                                      dec_mb_info_t *ps_cur_mb_info,\n                                      UWORD8 u1_offset);\nWORD32 ih264d_parse_imb_cavlc(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_num,\n                              UWORD8 u1_mb_type);\nWORD32 ih264d_parse_imb_cabac(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_type);\n\nWORD32 ih264d_parse_islice_data_cavlc(dec_struct_t * ps_dec,\n                                      dec_slice_params_t * ps_slice,\n                                      UWORD16 u2_first_mb_in_slice);\nWORD32 ih264d_parse_islice_data_cabac(dec_struct_t * ps_dec,\n                                      dec_slice_params_t * ps_slice,\n                                      UWORD16 u2_first_mb_in_slice);\nWORD32 ih264d_parse_pmb_cavlc(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_num,\n                              UWORD8 u1_num_mbsNby2);\nWORD32 ih264d_parse_pmb_cabac(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_num,\n                              UWORD8 u1_num_mbsNby2);\n\nWORD32 ih264d_parse_bmb_non_direct_cavlc(dec_struct_t * ps_dec,\n                                       dec_mb_info_t * ps_cur_mb_info,\n                                       UWORD8 u1_mb_num,\n                                       UWORD8 u1_mbNumModNBy2);\n\nWORD32 ih264d_parse_bmb_non_direct_cabac(dec_struct_t * ps_dec,\n                                       dec_mb_info_t * ps_cur_mb_info,\n                                       UWORD8 u1_mb_num,\n                                       UWORD8 u1_mbNumModNBy2);\n\nWORD32 ih264d_parse_bmb_cavlc(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_num,\n                              UWORD8 u1_num_mbsNby2);\n\nWORD32 ih264d_parse_bmb_cabac(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_num,\n                              UWORD8 u1_num_mbsNby2);\n\nWORD32 ih264d_parse_inter_slice_data_cavlc(dec_struct_t * ps_dec,\n                                           dec_slice_params_t * ps_slice,\n                                           UWORD16 u2_first_mb_in_slice);\n\nWORD32 ih264d_parse_inter_slice_data_cabac(dec_struct_t * ps_dec,\n                                           dec_slice_params_t * ps_slice,\n                                           UWORD16 u2_first_mb_in_slice);\n\nWORD32 ParseBMb(dec_struct_t * ps_dec,\n                dec_mb_info_t * ps_cur_mb_info,\n                UWORD8 u1_mb_num,\n                UWORD8 u1_num_mbsNby2);\n\nWORD32 ih264d_parse_ipcm_mb(dec_struct_t * ps_dec,\n                            dec_mb_info_t *ps_cur_mb_info,\n                            UWORD8 u1_mbNum);\nWORD32 ih264d_parse_islice(dec_struct_t *ps_dec,\n                            UWORD16 u2_first_mb_in_slice);\n\n#endif  /* _IH264D_PARSE_ISLICE_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_mb_header.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n ***************************************************************************\n * \\file ih264d_parse_mb_header.c\n *\n * \\brief\n *    This file contains context identifier encoding routines.\n *\n * \\date\n *    04/02/2003\n *\n * \\author  NS\n ***************************************************************************\n */\n#include <string.h>\n#include \"ih264d_structs.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_cabac.h\"\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_parse_mb_header.h\"\n#include \"ih264d_defs.h\"\n\n/*! < CtxtInc index 0 - CtxMbTypeI, CtxMbTypeSISuffix\n index 1 - CtxMbTypePSuffix, CtxMbTypeBSuffix\n */\n\n\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_mb_type_intra_cabac \\endif\n *\n * \\brief\n *    This function decodes MB type using CABAC entropy coding mode.\n *\n * \\return\n *    MBType.\n *\n **************************************************************************\n */\nUWORD8 ih264d_parse_mb_type_intra_cabac(UWORD8 u1_inter,\n                                        struct _DecStruct * ps_dec)\n{\n    decoding_envirnoment_t * ps_cab_env = &ps_dec->s_cab_dec_env;\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n    ctxt_inc_mb_info_t * ps_left_ctxt = ps_dec->p_left_ctxt_mb_info;\n    ctxt_inc_mb_info_t * ps_top_ctxt = ps_dec->p_top_ctxt_mb_info;\n    bin_ctxt_model_t *ps_mb_bin_ctxt = ps_dec->p_mb_type_t;\n    WORD8 u1_mb_type, u1_bin;\n    UWORD32 u4_cxt_inc;\n\n    u4_cxt_inc = 0;\n    if(!u1_inter)\n    {\n        if(ps_left_ctxt != ps_dec->ps_def_ctxt_mb_info)\n            u4_cxt_inc += ((ps_left_ctxt->u1_mb_type != CAB_I4x4) ? 1 : 0);\n        if(ps_top_ctxt != ps_dec->ps_def_ctxt_mb_info)\n            u4_cxt_inc += ((ps_top_ctxt->u1_mb_type != CAB_I4x4) ? 1 : 0);\n    }\n    else\n    {\n        ps_mb_bin_ctxt = ps_mb_bin_ctxt + 3 + (ps_dec->u1_B << 1);\n    }\n\n    /* b0 */\n    u1_mb_type = (UWORD8)ih264d_decode_bin(u4_cxt_inc, ps_mb_bin_ctxt, ps_bitstrm,\n                                          ps_cab_env);\n    if(u1_mb_type)\n    {\n        /* I16x16 or I_PCM mode */\n        /* b1 */\n        u1_bin = ih264d_decode_terminate(ps_cab_env, ps_bitstrm);\n        if(u1_bin == 0)\n        {\n            /* I16x16 mode */\n            /* Read b2 and b3 */\n            u4_cxt_inc = (u1_inter) ? 0x021 : 0x043;\n\n            u1_bin = ih264d_decode_bins(2, u4_cxt_inc, ps_mb_bin_ctxt, ps_bitstrm,\n                                        ps_cab_env);\n\n            if(u1_bin & 0x01)\n                u1_mb_type += 4;\n\n            if(u1_bin & 0x02)\n                u1_mb_type += 12;\n\n            if(u1_bin & 0x01)\n            {\n                /* since b3=1, Read three bins */\n                u4_cxt_inc = (u1_inter) ? 0x0332 : 0x0765;\n                u1_bin = (UWORD8)ih264d_decode_bins(3, u4_cxt_inc, ps_mb_bin_ctxt,\n                                                    ps_bitstrm, ps_cab_env);\n\n            }\n            else\n            {\n                /* Read two bins */\n                u4_cxt_inc = (u1_inter) ? 0x033 : 0x076;\n                u1_bin = (UWORD8)ih264d_decode_bins(2, u4_cxt_inc, ps_mb_bin_ctxt,\n                                                    ps_bitstrm, ps_cab_env);\n            }\n            u1_mb_type += u1_bin;\n        }\n        else\n        {\n            /* I_PCM mode */\n            /* b1=1 */\n            u1_mb_type = 25;\n        }\n    }\n    return (u1_mb_type);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_mb_type_cabac \\endif\n *\n * \\brief\n *    This function decodes MB type using CABAC entropy coding mode.\n *\n * \\return\n *    MBType.\n *\n **************************************************************************\n */\nUWORD32 ih264d_parse_mb_type_cabac(struct _DecStruct * ps_dec)\n{\n    const UWORD8 uc_slice_type = ps_dec->ps_cur_slice->u1_slice_type;\n    decoding_envirnoment_t *ps_cab_env = &ps_dec->s_cab_dec_env;\n    dec_bit_stream_t *ps_bitstrm = ps_dec->ps_bitstrm;\n    ctxt_inc_mb_info_t *ps_left_ctxt = ps_dec->p_left_ctxt_mb_info;\n    ctxt_inc_mb_info_t *ps_top_ctxt = ps_dec->p_top_ctxt_mb_info;\n    WORD8 c_ctxt_inc;\n    bin_ctxt_model_t *ps_mb_bin_ctxt = ps_dec->p_mb_type_t;\n    WORD8 u1_mb_type = 0, u1_bin;\n    UWORD32 u4_cxt_inc;\n\n    INC_SYM_COUNT(ps_cab_env);\n\n    c_ctxt_inc = 0;\n\n    if(uc_slice_type == SI_SLICE)\n    {\n        /* b0 */\n        if(ps_left_ctxt != ps_dec->ps_def_ctxt_mb_info)\n            c_ctxt_inc += ((ps_left_ctxt->u1_mb_type != CAB_SI4x4) ? 1 : 0);\n        if(ps_top_ctxt != ps_dec->ps_def_ctxt_mb_info)\n            c_ctxt_inc += ((ps_top_ctxt->u1_mb_type != CAB_SI4x4) ? 1 : 0);\n\n        u4_cxt_inc = c_ctxt_inc;\n        u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc, ps_mb_bin_ctxt, ps_bitstrm,\n                                           ps_cab_env);\n        if(u1_bin == 0)\n        {\n            /* SI MB */\n            u1_mb_type = 0;\n        }\n        else\n        {\n            u1_mb_type = 1 + ih264d_parse_mb_type_intra_cabac(0, ps_dec);\n        }\n    }\n    else if(uc_slice_type == P_SLICE)\n    {\n        /* P Slice */\n        /* b0 */\n        u4_cxt_inc = 0;\n        u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc, ps_mb_bin_ctxt, ps_bitstrm,\n                                           ps_cab_env);\n        if(!u1_bin)\n        {\n            /* Inter MB types */\n            /* b1 */\n            u4_cxt_inc = 0x01;\n            u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc, ps_mb_bin_ctxt,\n                                               ps_bitstrm, ps_cab_env);\n            /* b2 */\n            u4_cxt_inc = u1_bin + 2;\n            u1_mb_type = (UWORD8)ih264d_decode_bin(u4_cxt_inc, ps_mb_bin_ctxt,\n                                                  ps_bitstrm, ps_cab_env);\n            u1_mb_type = (u1_bin << 1) + u1_mb_type;\n            if(u1_mb_type)\n                u1_mb_type = 4 - u1_mb_type;\n        }\n        else\n        {\n            /* Intra Prefix 1 found */\n            /* Intra MB type */\n            u1_mb_type = 5 + ih264d_parse_mb_type_intra_cabac(1, ps_dec);\n        }\n    }\n    else if(uc_slice_type == B_SLICE)\n    {\n        WORD8 a, b;\n        /* B Slice */\n        /* b0 */\n        /* a = b = 0, if B slice and MB is a SKIP or B_DIRECT16x16 */\n        a = 0;\n        b = 0;\n        u1_mb_type = 0;\n        if(ps_left_ctxt != ps_dec->ps_def_ctxt_mb_info)\n            a = ((ps_left_ctxt->u1_mb_type & CAB_BD16x16_MASK) != CAB_BD16x16);\n        if(ps_top_ctxt != ps_dec->ps_def_ctxt_mb_info)\n            b = ((ps_top_ctxt->u1_mb_type & CAB_BD16x16_MASK) != CAB_BD16x16);\n\n        u4_cxt_inc = a + b;\n\n        u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc, ps_mb_bin_ctxt, ps_bitstrm,\n                                           ps_cab_env);\n\n        if(u1_bin)\n        {\n\n            /* b1 */\n            u4_cxt_inc = 0x03;\n            u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc, ps_mb_bin_ctxt,\n                                               ps_bitstrm, ps_cab_env);\n\n            if(!u1_bin)\n            {\n                /* b2 */\n                u4_cxt_inc = 0x05;\n                u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc, ps_mb_bin_ctxt,\n                                                   ps_bitstrm, ps_cab_env);\n\n                u1_mb_type = u1_bin + 1;\n            }\n            else\n            {\n                u1_mb_type = 3;\n                /* b2 */\n                u4_cxt_inc = 0x04;\n                u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc, ps_mb_bin_ctxt,\n                                                   ps_bitstrm, ps_cab_env);\n\n                if(u1_bin)\n                {\n                    u1_mb_type += 8;\n                    /* b3 */\n                    u4_cxt_inc = 0x05;\n                    u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc, ps_mb_bin_ctxt,\n                                                       ps_bitstrm, ps_cab_env);\n\n                    if(!u1_bin)\n                    {\n                        u1_mb_type++;\n                        /* b4, b5, b6 */\n                        u4_cxt_inc = 0x0555;\n                        u1_bin = (UWORD8)ih264d_decode_bins(3, u4_cxt_inc,\n                                                            ps_mb_bin_ctxt,\n                                                            ps_bitstrm,\n                                                            ps_cab_env);\n\n\n\n                        u1_mb_type += u1_bin;\n                    }\n                    else\n                    {\n                        /* b4 */\n                        u4_cxt_inc = 0x05;\n                        u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc,\n                                                           ps_mb_bin_ctxt,\n                                                           ps_bitstrm,\n                                                           ps_cab_env);\n\n                        if(u1_bin)\n                        {\n                            /* b5 */\n                            u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc,\n                                                               ps_mb_bin_ctxt,\n                                                               ps_bitstrm,\n                                                               ps_cab_env);\n\n                            u1_mb_type += (u1_bin ? 11 : 0);\n                        }\n                        else\n                        {\n                            u1_mb_type = 20;\n                            /* b5 */\n                            u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc,\n                                                               ps_mb_bin_ctxt,\n                                                               ps_bitstrm,\n                                                               ps_cab_env);\n\n                            if(!u1_bin)\n                            {\n                                /* b6 */\n                                u1_bin = (UWORD8)ih264d_decode_bin(u4_cxt_inc,\n                                                                   ps_mb_bin_ctxt,\n                                                                   ps_bitstrm,\n                                                                   ps_cab_env);\n\n                                u1_mb_type += u1_bin;\n                            }\n                            else\n                            {\n                                /* Intra Prefix 111101 found */\n                                /* Intra MB type */\n                                u1_mb_type =\n                                                23\n                                                                + ih264d_parse_mb_type_intra_cabac(\n                                                                                1,\n                                                                                ps_dec);\n                            }\n                        }\n                    }\n                }\n                else\n                {\n                    /* b3, b4, b5 */\n                    u4_cxt_inc = 0x0555;\n                    u1_bin = (UWORD8)ih264d_decode_bins(3, u4_cxt_inc,\n                                                        ps_mb_bin_ctxt, ps_bitstrm,\n                                                        ps_cab_env);\n\n\n\n\n                    u1_mb_type += u1_bin;\n                }\n            }\n        }\n    }\n    return ((UWORD32)u1_mb_type);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : DecSubMBType \\endif\n *\n * \\brief\n *    This function decodes MB type using CABAC entropy coding mode.\n *\n * \\return\n *    MBType.\n *\n **************************************************************************\n */\nUWORD32 ih264d_parse_submb_type_cabac(const UWORD8 u1_slc_type_b,\n                                      decoding_envirnoment_t * ps_cab_env,\n                                      dec_bit_stream_t * ps_bitstrm,\n                                      bin_ctxt_model_t * ps_sub_mb_cxt)\n{\n    WORD8 u1_sub_mb_type, u1_bin;\n\n    INC_SYM_COUNT(ps_cab_env);\n\n    u1_sub_mb_type = 0;\n    u1_bin = (UWORD8)ih264d_decode_bin(0, ps_sub_mb_cxt, ps_bitstrm,\n                                       ps_cab_env);\n\n    if(u1_slc_type_b ^ u1_bin)\n        return 0;\n\n    if(!u1_slc_type_b)\n    {\n        /* P Slice */\n        u1_sub_mb_type = 1;\n        u1_bin = (UWORD8)ih264d_decode_bin(1, ps_sub_mb_cxt, ps_bitstrm,\n                                           ps_cab_env);\n        if(u1_bin == 1)\n        {\n            u1_bin = (UWORD8)ih264d_decode_bin(2, ps_sub_mb_cxt, ps_bitstrm,\n                                               ps_cab_env);\n            u1_sub_mb_type = (2 + (!u1_bin));\n        }\n\n        return u1_sub_mb_type;\n    }\n    else\n    {\n        /* B Slice */\n\n        /* b1 */\n        u1_bin = (UWORD8)ih264d_decode_bin(1, ps_sub_mb_cxt, ps_bitstrm,\n                                           ps_cab_env);\n        if(u1_bin)\n        {\n            /* b2 */\n            u1_bin = (UWORD8)ih264d_decode_bin(2, ps_sub_mb_cxt, ps_bitstrm,\n                                               ps_cab_env);\n            if(u1_bin)\n            {\n                /* b3 */\n                u1_sub_mb_type = 7;\n                u1_bin = (UWORD8)ih264d_decode_bin(3, ps_sub_mb_cxt, ps_bitstrm,\n                                                   ps_cab_env);\n                u1_sub_mb_type += u1_bin << 2;\n                u1_bin = !u1_bin;\n                /* b4 */\n                if(u1_bin == 0)\n                {\n                    u1_bin = ih264d_decode_bin(3, ps_sub_mb_cxt, ps_bitstrm,\n                                               ps_cab_env);\n                }\n                else\n                {\n                    u1_bin = (UWORD8)ih264d_decode_bins(2, 0x33, ps_sub_mb_cxt,\n                                                        ps_bitstrm, ps_cab_env);\n                }\n\n                return (u1_sub_mb_type + u1_bin);\n            }\n            else\n            {\n                /* b3 */\n                u1_bin = (UWORD8)ih264d_decode_bins(2, 0x33, ps_sub_mb_cxt,\n                                                    ps_bitstrm, ps_cab_env);\n                return (3 + u1_bin);\n            }\n        }\n        else\n        {\n            /* b2 */\n            u1_bin = (UWORD8)ih264d_decode_bin(3, ps_sub_mb_cxt, ps_bitstrm,\n                                               ps_cab_env);\n            return (1 + u1_bin);\n        }\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_ref_idx_cabac \\endif\n *\n * \\brief\n *    This function decodes Reference Index using CABAC entropy coding mode.\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\nWORD32 ih264d_parse_ref_idx_cabac(const UWORD8 u1_num_part,\n                                const UWORD8 u1_b2,\n                                const UWORD8 u1_max_ref_minus1,\n                                const UWORD8 u1_mb_mode,\n                                WORD8 * pi1_ref_idx,\n                                WORD8 * const pi1_lft_cxt,\n                                WORD8 * const pi1_top_cxt,\n                                decoding_envirnoment_t * const ps_cab_env,\n                                dec_bit_stream_t * const ps_bitstrm,\n                                bin_ctxt_model_t * const ps_ref_cxt)\n{\n    UWORD8 u1_a, u1_b;\n    UWORD32 u4_cxt_inc;\n    UWORD8 u1_blk_no, u1_i, u1_idx_lft, u1_idx_top;\n    WORD8 i1_ref_idx;\n\n    for(u1_blk_no = 0, u1_i = 0; u1_i < u1_num_part; u1_i++, pi1_ref_idx++)\n    {\n        u1_idx_lft = ((u1_blk_no & 0x02) >> 1) + u1_b2;\n        u1_idx_top = (u1_blk_no & 0x01) + u1_b2;\n        i1_ref_idx = *pi1_ref_idx;\n\n        if(i1_ref_idx > 0)\n        {\n            u1_a = pi1_lft_cxt[u1_idx_lft] > 0;\n            u1_b = pi1_top_cxt[u1_idx_top] > 0;\n\n            u4_cxt_inc = u1_a + (u1_b << 1);\n            u4_cxt_inc = (u4_cxt_inc | 0x55540);\n\n            i1_ref_idx = (WORD8)ih264d_decode_bins_unary(32, u4_cxt_inc,\n                                                         ps_ref_cxt, ps_bitstrm,\n                                                         ps_cab_env);\n\n            if((i1_ref_idx > u1_max_ref_minus1) || (i1_ref_idx < 0))\n            {\n                return ERROR_REF_IDX;\n            }\n\n            *pi1_ref_idx = i1_ref_idx;\n\n            INC_SYM_COUNT(ps_cab_env);\n\n        }\n\n        /* Storing Reference Idx Information */\n        pi1_lft_cxt[u1_idx_lft] = i1_ref_idx;\n        pi1_top_cxt[u1_idx_top] = i1_ref_idx;\n        u1_blk_no = u1_blk_no + 1 + (u1_mb_mode & 0x01);\n    }\n    /* if(!u1_sub_mb) */\n    if(u1_num_part != 4)\n    {\n        pi1_lft_cxt[(!(u1_mb_mode & 0x1)) + u1_b2] = pi1_lft_cxt[u1_b2];\n        pi1_top_cxt[(!(u1_mb_mode & 0x2)) + u1_b2] = pi1_top_cxt[u1_b2];\n    }\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_mb_qp_delta_cabac \\endif\n *\n * \\brief\n *    This function decodes MB Qp delta using CABAC entropy coding mode.\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\nWORD32 ih264d_parse_mb_qp_delta_cabac(struct _DecStruct * ps_dec,\n                                      WORD8 *pi1_mb_qp_delta)\n{\n    decoding_envirnoment_t * ps_cab_env = &ps_dec->s_cab_dec_env;\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n\n    UWORD8 u1_code_num;\n    bin_ctxt_model_t *ps_mb_qp_delta_ctxt = ps_dec->p_mb_qp_delta_t;\n    UWORD32 u4_cxt_inc;\n\n    INC_SYM_COUNT(ps_cab_env);\n\n    u4_cxt_inc = (!(!(ps_dec->i1_prev_mb_qp_delta)));\n\n    u1_code_num = 0;\n    u4_cxt_inc = (u4_cxt_inc | 0x33320);\n    /* max number of bins = 53,\n     since Range for MbQpDelta= -26 to +25 inclusive, UNARY code */\n    u1_code_num = ih264d_decode_bins_unary(32, u4_cxt_inc, ps_mb_qp_delta_ctxt,\n                                          ps_bitstrm, ps_cab_env);\n    if(u1_code_num == 32)\n    {\n        /* Read remaining 21 bins */\n        UWORD8 uc_codeNumX;\n        u4_cxt_inc = 0x33333;\n        uc_codeNumX = ih264d_decode_bins_unary(21, u4_cxt_inc, ps_mb_qp_delta_ctxt,\n                                               ps_bitstrm, ps_cab_env);\n        u1_code_num = u1_code_num + uc_codeNumX;\n    }\n\n    *pi1_mb_qp_delta = (u1_code_num + 1) >> 1;\n    /* Table 9.3: If code_num is even Syntax Element has -ve value */\n    if(!(u1_code_num & 0x01))\n        *pi1_mb_qp_delta = -(*pi1_mb_qp_delta);\n\n    /* Range of MbQpDelta= -26 to +25 inclusive */\n    if((*pi1_mb_qp_delta < -26) || (*pi1_mb_qp_delta > 25))\n        return ERROR_INV_RANGE_QP_T;\n    ps_dec->i1_prev_mb_qp_delta = *pi1_mb_qp_delta;\n    return OK;\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_chroma_pred_mode_cabac \\endif\n *\n * \\brief\n *    This function decodes Chroma Pred mode using CABAC entropy coding mode.\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\nWORD8 ih264d_parse_chroma_pred_mode_cabac(struct _DecStruct * ps_dec)\n{\n    decoding_envirnoment_t * ps_cab_env = &ps_dec->s_cab_dec_env;\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n    ctxt_inc_mb_info_t * ps_left_ctxt = ps_dec->p_left_ctxt_mb_info;\n    ctxt_inc_mb_info_t * ps_top_ctxt = ps_dec->p_top_ctxt_mb_info;\n    WORD8 i1_chroma_pred_mode, a, b;\n    UWORD32 u4_cxt_inc;\n\n    INC_SYM_COUNT(ps_cab_env);\n\n    /* Binarization is TU and Cmax=3 */\n    i1_chroma_pred_mode = 0;\n    a = 0;\n    b = 0;\n\n    a = ((ps_left_ctxt->u1_intra_chroma_pred_mode != 0) ? 1 : 0);\n\n    b = ((ps_top_ctxt->u1_intra_chroma_pred_mode != 0) ? 1 : 0);\n    u4_cxt_inc = a + b;\n\n    u4_cxt_inc = (u4_cxt_inc | 0x330);\n\n    i1_chroma_pred_mode = ih264d_decode_bins_tunary(\n                    3, u4_cxt_inc, ps_dec->p_intra_chroma_pred_mode_t,\n                    ps_bitstrm, ps_cab_env);\n\n    return (i1_chroma_pred_mode);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_transform8x8flag_cabac                                     */\n/*                                                                           */\n/*  Description   :                                                          */\n/*  Inputs        :                                                          */\n/*                                                                           */\n/*                                                                           */\n/*  Returns       :                                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                      Rajasekhar      Creation                             */\n/*                                                                           */\n/*****************************************************************************/\nUWORD8 ih264d_parse_transform8x8flag_cabac(struct _DecStruct * ps_dec,\n                                           dec_mb_info_t * ps_cur_mb_info)\n{\n    decoding_envirnoment_t * ps_cab_env = &ps_dec->s_cab_dec_env;\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n    ctxt_inc_mb_info_t * ps_left_ctxt = ps_dec->p_left_ctxt_mb_info;\n    ctxt_inc_mb_info_t * ps_top_ctxt = ps_dec->p_top_ctxt_mb_info;\n    UWORD8 u1_transform_8x8flag;\n    UWORD8 u1_mb_ngbr_avail = ps_cur_mb_info->u1_mb_ngbr_availablity;\n\n    WORD8 a, b;\n    UWORD32 u4_cxt_inc;\n\n    /* for calculating the context increment for transform8x8 u4_flag */\n    /* it reads transform8x8 u4_flag of the neighbors through */\n\n    /* Binarization is FLC */\n    a = 0;\n    b = 0;\n\n    if(u1_mb_ngbr_avail & LEFT_MB_AVAILABLE_MASK)\n    {\n        a = ps_left_ctxt->u1_transform8x8_ctxt;\n    }\n    if(u1_mb_ngbr_avail & TOP_MB_AVAILABLE_MASK)\n    {\n        b = ps_top_ctxt->u1_transform8x8_ctxt;\n\n    }\n\n    u4_cxt_inc = a + b;\n\n    u1_transform_8x8flag = ih264d_decode_bin(\n                    u4_cxt_inc, ps_dec->s_high_profile.ps_transform8x8_flag,\n                    ps_bitstrm, ps_cab_env);\n\n    return (u1_transform_8x8flag);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_read_intra_pred_modes_cabac \\endif\n *\n * \\brief\n *    Reads the intra pred mode related values of I4x4 MB from bitstream.\n *\n *    This function will read the prev intra pred mode flags and\n *    stores it in pu1_prev_intra4x4_pred_mode_flag. If the u4_flag\n *    indicates that most probable mode is not intra pred mode, then\n *    the rem_intra4x4_pred_mode is read and stored in\n *    pu1_rem_intra4x4_pred_mode array.\n *\n *\n * \\return\n *    0 on success and Error code otherwise\n *\n **************************************************************************\n */\nWORD32 ih264d_read_intra_pred_modes_cabac(dec_struct_t * ps_dec,\n                                          UWORD8 * pu1_prev_intra4x4_pred_mode_flag,\n                                          UWORD8 * pu1_rem_intra4x4_pred_mode,\n                                          UWORD8 u1_tran_form8x8)\n{\n    WORD32 i4x4_luma_blk_idx = 0;\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n    decoding_envirnoment_t * ps_cab_env = &ps_dec->s_cab_dec_env;\n    bin_ctxt_model_t *ps_ctxt_ipred_luma_mpm, *ps_ctx_ipred_luma_rm;\n    WORD32 i4_rem_intra4x4_pred_mode;\n    UWORD32 u4_prev_intra4x4_pred_mode_flag;\n    UWORD32 u4_code_int_range, u4_code_int_val_ofst;\n    const UWORD32 *pu4_table = (const UWORD32 *)ps_cab_env->cabac_table;\n\n    ps_ctxt_ipred_luma_mpm = ps_dec->p_prev_intra4x4_pred_mode_flag_t;\n    ps_ctx_ipred_luma_rm = ps_dec->p_rem_intra4x4_pred_mode_t;\n    SWITCHOFFTRACE;\n\n    i4x4_luma_blk_idx = (0 == u1_tran_form8x8) ? 16 : 4;\n\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n\n    do\n    {\n\n        DECODE_ONE_BIN_MACRO(ps_ctxt_ipred_luma_mpm, u4_code_int_range,\n                             u4_code_int_val_ofst, pu4_table, ps_bitstrm,\n                             u4_prev_intra4x4_pred_mode_flag)\n        *pu1_prev_intra4x4_pred_mode_flag = u4_prev_intra4x4_pred_mode_flag;\n\n        i4_rem_intra4x4_pred_mode = -1;\n        if(!u4_prev_intra4x4_pred_mode_flag)\n        {\n\n            /*inlining DecodeDecisionBins_FLC*/\n\n            {\n\n                UWORD8 u1_max_bins = 3;\n                UWORD32 u4_value;\n                UWORD32 u4_symbol, i;\n\n                i = 0;\n                u4_value = 0;\n\n                do\n                {\n\n                    DECODE_ONE_BIN_MACRO(ps_ctx_ipred_luma_rm, u4_code_int_range,\n                                         u4_code_int_val_ofst, pu4_table,\n                                         ps_bitstrm, u4_symbol)\n\n                    INC_BIN_COUNT(ps_cab_env);INC_DECISION_BINS(ps_cab_env);\n\n                    u4_value = u4_value | (u4_symbol << i);\n\n                    i++;\n                }\n                while(i < u1_max_bins);\n\n                i4_rem_intra4x4_pred_mode = (u4_value);\n\n            }\n\n        }\n\n        (*pu1_rem_intra4x4_pred_mode) = i4_rem_intra4x4_pred_mode;\n\n        COPYTHECONTEXT(\"intra4x4_pred_mode\", i4_rem_intra4x4_pred_mode);\n\n        pu1_prev_intra4x4_pred_mode_flag++;\n        pu1_rem_intra4x4_pred_mode++;\n\n        i4x4_luma_blk_idx--;\n    }\n    while(i4x4_luma_blk_idx);\n\n    ps_cab_env->u4_code_int_range = u4_code_int_range;\n    ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n\n    return (0);\n\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_ctx_cbp_cabac \\endif\n *\n * \\brief\n *    This function decodes CtxCbpLuma and CtxCbpChroma (CBP of a Macroblock).\n *    using CABAC entropy coding mode.\n *\n * \\return\n *    CBP of a MB.\n *\n **************************************************************************\n */\nUWORD32 ih264d_parse_ctx_cbp_cabac(struct _DecStruct * ps_dec)\n{\n\n    UWORD32 u4_cxt_inc;\n    decoding_envirnoment_t * ps_cab_env = &ps_dec->s_cab_dec_env;\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n    ctxt_inc_mb_info_t * ps_left_ctxt = ps_dec->p_left_ctxt_mb_info;\n    ctxt_inc_mb_info_t * ps_top_ctxt = ps_dec->p_top_ctxt_mb_info;\n    bin_ctxt_model_t *ps_ctxt_cbp_luma = ps_dec->p_cbp_luma_t, *ps_bin_ctxt;\n    WORD8 c_Cbp; //,i,j;\n    UWORD32 u4_code_int_range, u4_code_int_val_ofst;\n    UWORD32 u4_offset, *pu4_buffer;\n    const UWORD32 *pu4_table = (const UWORD32 *)ps_cab_env->cabac_table;\n\n    INC_SYM_COUNT(ps_cab_env);\n\n\n\n    /* CBP Luma, FL, Cmax = 15, L = 4 */\n    u4_cxt_inc = (!((ps_top_ctxt->u1_cbp >> 2) & 0x01)) << 1;\n    u4_cxt_inc += !((ps_left_ctxt->u1_cbp >> 1) & 0x01);\n\n    u4_offset = ps_bitstrm->u4_ofst;\n    pu4_buffer = ps_bitstrm->pu4_buffer;\n\n    u4_code_int_range = ps_cab_env->u4_code_int_range;\n    u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n    /*renormalize to ensure there 23 bits more in the u4_code_int_val_ofst*/\n    {\n        UWORD32 u4_clz, read_bits;\n\n        u4_clz = CLZ(u4_code_int_range);\n        FLUSHBITS(u4_offset, u4_clz)\n        NEXTBITS(read_bits, u4_offset, pu4_buffer, 23)\n        u4_code_int_range = u4_code_int_range << u4_clz;\n        u4_code_int_val_ofst = (u4_code_int_val_ofst << u4_clz) | read_bits;\n    }\n\n    ps_bin_ctxt = ps_ctxt_cbp_luma + u4_cxt_inc;\n\n    /*inlining DecodeDecision_onebin without renorm*/\n    {\n\n        UWORD32 u4_qnt_int_range, u4_int_range_lps;\n        UWORD32 u4_symbol, u1_mps_state;\n        UWORD32 table_lookup;\n        UWORD32 u4_clz;\n\n        u1_mps_state = (ps_bin_ctxt->u1_mps_state);\n\n        u4_clz = CLZ(u4_code_int_range);\n        u4_qnt_int_range = u4_code_int_range << u4_clz;\n        u4_qnt_int_range = (u4_qnt_int_range >> 29) & 0x3;\n\n        table_lookup = pu4_table[(u1_mps_state << 2) + u4_qnt_int_range];\n        u4_int_range_lps = table_lookup & 0xff;\n\n        u4_int_range_lps = u4_int_range_lps << (23 - u4_clz);\n        u4_code_int_range = u4_code_int_range - u4_int_range_lps;\n\n        u4_symbol = ((u1_mps_state >> 6) & 0x1);\n\n        /*if mps*/\n        u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n        CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst, u4_symbol,\n                     u4_int_range_lps, u1_mps_state, table_lookup)\n\n        INC_BIN_COUNT(ps_cab_env);\n\n        ps_bin_ctxt->u1_mps_state = u1_mps_state;\n\n        c_Cbp = u4_symbol;\n\n    }\n\n    u4_cxt_inc = (!((ps_top_ctxt->u1_cbp >> 3) & 0x01)) << 1;\n    u4_cxt_inc += !(c_Cbp & 0x01);\n    ps_bin_ctxt = ps_ctxt_cbp_luma + u4_cxt_inc;\n    /*inlining DecodeDecision_onebin without renorm*/\n\n    {\n\n        UWORD32 u4_qnt_int_range, u4_int_range_lps;\n        UWORD32 u4_symbol, u1_mps_state;\n        UWORD32 table_lookup;\n        UWORD32 u4_clz;\n\n        u1_mps_state = (ps_bin_ctxt->u1_mps_state);\n\n        u4_clz = CLZ(u4_code_int_range);\n        u4_qnt_int_range = u4_code_int_range << u4_clz;\n        u4_qnt_int_range = (u4_qnt_int_range >> 29) & 0x3;\n\n        table_lookup = pu4_table[(u1_mps_state << 2) + u4_qnt_int_range];\n        u4_int_range_lps = table_lookup & 0xff;\n\n        u4_int_range_lps = u4_int_range_lps << (23 - u4_clz);\n        u4_code_int_range = u4_code_int_range - u4_int_range_lps;\n\n        u4_symbol = ((u1_mps_state >> 6) & 0x1);\n\n        /*if mps*/\n        u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n        CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst, u4_symbol,\n                     u4_int_range_lps, u1_mps_state, table_lookup)\n\n        INC_BIN_COUNT(ps_cab_env);\n\n        ps_bin_ctxt->u1_mps_state = u1_mps_state;\n\n        c_Cbp |= u4_symbol << 1;\n\n    }\n\n    u4_cxt_inc = (!(c_Cbp & 0x01)) << 1;\n    u4_cxt_inc += !((ps_left_ctxt->u1_cbp >> 3) & 0x01);\n    ps_bin_ctxt = ps_ctxt_cbp_luma + u4_cxt_inc;\n    /*inlining DecodeDecision_onebin without renorm*/\n\n    {\n\n        UWORD32 u4_qnt_int_range, u4_int_range_lps;\n        UWORD32 u4_symbol, u1_mps_state;\n        UWORD32 table_lookup;\n        UWORD32 u4_clz;\n\n        u1_mps_state = (ps_bin_ctxt->u1_mps_state);\n\n        u4_clz = CLZ(u4_code_int_range);\n        u4_qnt_int_range = u4_code_int_range << u4_clz;\n        u4_qnt_int_range = (u4_qnt_int_range >> 29) & 0x3;\n\n        table_lookup = pu4_table[(u1_mps_state << 2) + u4_qnt_int_range];\n        u4_int_range_lps = table_lookup & 0xff;\n\n        u4_int_range_lps = u4_int_range_lps << (23 - u4_clz);\n        u4_code_int_range = u4_code_int_range - u4_int_range_lps;\n\n        u4_symbol = ((u1_mps_state >> 6) & 0x1);\n\n        /*if mps*/\n        u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n        CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst, u4_symbol,\n                     u4_int_range_lps, u1_mps_state, table_lookup)\n\n        INC_BIN_COUNT(ps_cab_env);\n\n        ps_bin_ctxt->u1_mps_state = u1_mps_state;\n\n        c_Cbp |= u4_symbol << 2;\n\n    }\n\n    u4_cxt_inc = (!((c_Cbp >> 1) & 0x01)) << 1;\n    u4_cxt_inc += !((c_Cbp >> 2) & 0x01);\n    ps_bin_ctxt = ps_ctxt_cbp_luma + u4_cxt_inc;\n    /*inlining DecodeDecision_onebin without renorm*/\n\n    {\n\n        UWORD32 u4_qnt_int_range, u4_int_range_lps;\n        UWORD32 u4_symbol, u1_mps_state;\n        UWORD32 table_lookup;\n        UWORD32 u4_clz;\n\n        u1_mps_state = (ps_bin_ctxt->u1_mps_state);\n\n        u4_clz = CLZ(u4_code_int_range);\n        u4_qnt_int_range = u4_code_int_range << u4_clz;\n        u4_qnt_int_range = (u4_qnt_int_range >> 29) & 0x3;\n\n        table_lookup = pu4_table[(u1_mps_state << 2) + u4_qnt_int_range];\n        u4_int_range_lps = table_lookup & 0xff;\n\n        u4_int_range_lps = u4_int_range_lps << (23 - u4_clz);\n        u4_code_int_range = u4_code_int_range - u4_int_range_lps;\n\n        u4_symbol = ((u1_mps_state >> 6) & 0x1);\n\n        /*if mps*/\n        u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n        CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst, u4_symbol,\n                     u4_int_range_lps, u1_mps_state, table_lookup)\n\n        INC_BIN_COUNT(ps_cab_env);\n\n        ps_bin_ctxt->u1_mps_state = u1_mps_state;\n\n        c_Cbp |= u4_symbol << 3;\n\n    }\n\n    if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_8)\n    {\n\n        RENORM_RANGE_OFFSET(u4_code_int_range, u4_code_int_val_ofst, u4_offset,\n                            pu4_buffer)\n\n    }\n\n    {\n        UWORD32 u4_cxt_inc;\n        WORD8 a, b, c, d;\n        bin_ctxt_model_t *p_CtxtCbpChroma = ps_dec->p_cbp_chroma_t;\n\n        /* CBP Chroma, TU, Cmax = 2 */\n        a = 0;\n        b = 0;\n        c = 0;\n        d = 0;\n\n        {\n            a = (ps_top_ctxt->u1_cbp > 15) ? 2 : 0;\n            c = (ps_top_ctxt->u1_cbp > 31) ? 2 : 0;\n        }\n\n        {\n            b = (ps_left_ctxt->u1_cbp > 15) ? 1 : 0;\n            d = (ps_left_ctxt->u1_cbp > 31) ? 1 : 0;\n        }\n        u4_cxt_inc = a + b;\n        u4_cxt_inc = (u4_cxt_inc | ((4 + c + d) << 4));\n\n        /*inlining ih264d_decode_bins_tunary */\n\n        {\n\n            UWORD8 u1_max_bins = 2;\n            UWORD32 u4_ctx_inc = u4_cxt_inc;\n\n            UWORD32 u4_value;\n            UWORD32 u4_symbol;\n            UWORD8 u4_ctx_Inc;\n            bin_ctxt_model_t *ps_bin_ctxt;\n            u4_value = 0;\n\n            do\n            {\n                u4_ctx_Inc = u4_ctx_inc & 0xF;\n                u4_ctx_inc = u4_ctx_inc >> 4;\n\n                ps_bin_ctxt = p_CtxtCbpChroma + u4_ctx_Inc;\n                /*inlining DecodeDecision_onebin*/\n                {\n\n                    UWORD32 u4_qnt_int_range, u4_int_range_lps;\n\n                    UWORD32 u1_mps_state;\n                    UWORD32 table_lookup;\n                    UWORD32 u4_clz;\n\n                    u1_mps_state = (ps_bin_ctxt->u1_mps_state);\n\n                    u4_clz = CLZ(u4_code_int_range);\n                    u4_qnt_int_range = u4_code_int_range << u4_clz;\n                    u4_qnt_int_range = (u4_qnt_int_range >> 29) & 0x3;\n\n                    table_lookup = pu4_table[(u1_mps_state << 2)\n                                    + u4_qnt_int_range];\n                    u4_int_range_lps = table_lookup & 0xff;\n\n                    u4_int_range_lps = u4_int_range_lps << (23 - u4_clz);\n                    u4_code_int_range = u4_code_int_range - u4_int_range_lps;\n\n                    u4_symbol = ((u1_mps_state >> 6) & 0x1);\n\n                    /*if mps*/\n                    u1_mps_state = (table_lookup >> 8) & 0x7F;\n\n                    CHECK_IF_LPS(u4_code_int_range, u4_code_int_val_ofst,\n                                 u4_symbol, u4_int_range_lps, u1_mps_state,\n                                 table_lookup)\n\n                    if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_8)\n                    {\n                        RENORM_RANGE_OFFSET(u4_code_int_range,\n                                            u4_code_int_val_ofst, u4_offset,\n                                            pu4_buffer)\n                    }\n                    ps_bin_ctxt->u1_mps_state = u1_mps_state;\n                }\n\n                INC_BIN_COUNT(ps_cab_env);INC_DECISION_BINS(\n                                ps_cab_env);\n\n                u4_value++;\n            }\n            while((u4_value < u1_max_bins) & (u4_symbol));\n\n            u4_value = u4_value - 1 + u4_symbol;\n\n            a = (u4_value);\n\n        }\n\nc_Cbp = (c_Cbp | (a << 4));\n}\n\nps_bitstrm->u4_ofst = u4_offset;\n\nps_cab_env->u4_code_int_range = u4_code_int_range;\nps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n\nreturn (c_Cbp);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_get_mvd_cabac \\endif\n *\n * \\brief\n *    This function decodes Horz and Vert mvd_l0 and mvd_l1 using CABAC entropy\n *    coding mode as defined in 9.3.2.3.\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\nvoid ih264d_get_mvd_cabac(UWORD8 u1_sub_mb,\n                          UWORD8 u1_b2,\n                          UWORD8 u1_part_wd,\n                          UWORD8 u1_part_ht,\n                          UWORD8 u1_dec_mvd,\n                          dec_struct_t *ps_dec,\n                          mv_pred_t *ps_mv)\n{\n    UWORD8 u1_abs_mvd_x = 0, u1_abs_mvd_y = 0;\n    UWORD8 u1_sub_mb_x, u1_sub_mb_y;\n    UWORD8 *pu1_top_mv_ctxt, *pu1_lft_mv_ctxt;\n    WORD16 *pi2_mv;\n\n    u1_sub_mb_x = (UWORD8)(u1_sub_mb & 0x03);\n    u1_sub_mb_y = (UWORD8)(u1_sub_mb >> 2);\n    pu1_top_mv_ctxt = &ps_dec->ps_curr_ctxt_mb_info->u1_mv[u1_sub_mb_x][u1_b2];\n    pu1_lft_mv_ctxt = &ps_dec->pu1_left_mv_ctxt_inc[u1_sub_mb_y][u1_b2];\n    pi2_mv = &ps_mv->i2_mv[u1_b2];\n\n    if(u1_dec_mvd)\n    {\n        WORD16 i2_mv_x, i2_mv_y;\n        WORD32 i2_temp;\n        {\n            decoding_envirnoment_t * ps_cab_env = &ps_dec->s_cab_dec_env;\n            dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n            UWORD16 u2_abs_mvd_x_a, u2_abs_mvd_x_b, u2_abs_mvd_y_a,\n                            u2_abs_mvd_y_b;\n\n            u2_abs_mvd_x_b = (UWORD16)pu1_top_mv_ctxt[0];\n            u2_abs_mvd_y_b = (UWORD16)pu1_top_mv_ctxt[1];\n            u2_abs_mvd_x_a = (UWORD16)pu1_lft_mv_ctxt[0];\n            u2_abs_mvd_y_a = (UWORD16)pu1_lft_mv_ctxt[1];\n\n            i2_temp = u2_abs_mvd_x_a + u2_abs_mvd_x_b;\n\n            i2_mv_x = ih264d_parse_mvd_cabac(ps_bitstrm, ps_cab_env,\n                                             ps_dec->p_mvd_x_t, i2_temp);\n\n            i2_temp = u2_abs_mvd_y_a + u2_abs_mvd_y_b;\n\n            i2_mv_y = ih264d_parse_mvd_cabac(ps_bitstrm, ps_cab_env,\n                                             ps_dec->p_mvd_y_t, i2_temp);\n        }\n\n        /***********************************************************************/\n        /* Store the abs_mvd_values in cabac contexts                          */\n        /* The follownig code can be easily optimzed if mvX, mvY clip values   */\n        /* are packed in 16 bits follwed by memcpy                             */\n        /***********************************************************************/\n        u1_abs_mvd_x = CLIP3(0, 127, ABS(i2_mv_x));\n        u1_abs_mvd_y = CLIP3(0, 127, ABS(i2_mv_y));\n\n        COPYTHECONTEXT(\"MVD\", i2_mv_x);COPYTHECONTEXT(\"MVD\", i2_mv_y);\n\n        /* Storing Mv residuals */\n        pi2_mv[0] = i2_mv_x;\n        pi2_mv[1] = i2_mv_y;\n    }\n\n    /***************************************************************/\n    /* Store abs_mvd_values cabac contexts                         */\n    /***************************************************************/\n    {\n        UWORD8 u1_i;\n        for(u1_i = 0; u1_i < u1_part_wd; u1_i++, pu1_top_mv_ctxt += 4)\n        {\n            pu1_top_mv_ctxt[0] = u1_abs_mvd_x;\n            pu1_top_mv_ctxt[1] = u1_abs_mvd_y;\n        }\n\n        for(u1_i = 0; u1_i < u1_part_ht; u1_i++, pu1_lft_mv_ctxt += 4)\n        {\n            pu1_lft_mv_ctxt[0] = u1_abs_mvd_x;\n            pu1_lft_mv_ctxt[1] = u1_abs_mvd_y;\n        }\n    }\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_mvd_cabac                                                  */\n/*                                                                           */\n/*  Description   : This cabac function decodes the mvd in a given direction */\n/*                  direction ( x or y ) as defined in 9.3.2.3.              */\n/*                                                                           */\n/*  Inputs        : 1. pointer to Bitstream                                  */\n/*                  2. pointer to cabac decoding environmnet                 */\n/*                  3. pointer to Mvd context                                */\n/*                  4. abs(Top mvd) = u2_abs_mvd_b                           */\n/*                  5. abs(left mvd)= u2_abs_mvd_a                           */\n/*                                                                           */\n/*  Processing    : see section 9.3.2.3 of the standard                      */\n/*                                                                           */\n/*  Outputs       : i2_mvd                                                   */\n/*  Returns       : i2_mvd                                                   */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         16 06 2005   Jay          Draft                                   */\n/*                                                                           */\n/*****************************************************************************/\nWORD16 ih264d_parse_mvd_cabac(dec_bit_stream_t * ps_bitstrm,\n                              decoding_envirnoment_t * ps_cab_env,\n                              bin_ctxt_model_t * p_ctxt_mvd,\n                              UWORD32 i4_temp)\n\n{\n    WORD8 k;\n    WORD16 i2_suf;\n    WORD16 i2_mvd;\n    UWORD16 u2_abs_mvd;\n    UWORD32 u4_ctx_inc;\n    UWORD32 u4_prefix;\n    const UWORD32 *pu4_table = (const UWORD32 *)ps_cab_env->cabac_table;\n    UWORD32 u4_code_int_range, u4_code_int_val_ofst;\n\n    /*  if mvd < 9                                                  */\n    /*  mvd =  Prefix                                                   */\n    /*  else                                                            */\n    /*  mvd = Prefix + Suffix                                           */\n    /*  decode sign bit                                                 */\n    /*  Prefix TU decoding Cmax =Ucoff and Suffix 3rd order Exp-Golomb  */\n\n    u2_abs_mvd = (UWORD16)i4_temp;\n    u4_ctx_inc = 1;\n\n    if(u2_abs_mvd < 3)\n        u4_ctx_inc = 0;\n    else if(u2_abs_mvd > 32)\n        u4_ctx_inc = 2;\n\n    u4_ctx_inc = (u4_ctx_inc | 0x65430);\n\n    /*inlining modified version of ih264d_decode_bins_unary*/\n\n    {\n        UWORD8 u1_max_bins = 9;\n        UWORD32 u4_value;\n        UWORD32 u4_symbol;\n        bin_ctxt_model_t *ps_bin_ctxt;\n        UWORD32 u4_ctx_Inc;\n\n        u4_value = 0;\n        u4_code_int_range = ps_cab_env->u4_code_int_range;\n        u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n\n        do\n        {\n            u4_ctx_Inc = u4_ctx_inc & 0xf;\n            u4_ctx_inc = u4_ctx_inc >> 4;\n\n            ps_bin_ctxt = p_ctxt_mvd + u4_ctx_Inc;\n\n            DECODE_ONE_BIN_MACRO(ps_bin_ctxt, u4_code_int_range,\n                                 u4_code_int_val_ofst, pu4_table, ps_bitstrm,\n                                 u4_symbol)\n\n            INC_BIN_COUNT(ps_cab_env);INC_DECISION_BINS(ps_cab_env);\n\n            u4_value++;\n\n        }\n        while(u4_symbol && u4_value < 5);\n\n        ps_bin_ctxt = p_ctxt_mvd + 6;\n\n        if(u4_symbol && (u4_value < u1_max_bins))\n        {\n\n            do\n            {\n\n                DECODE_ONE_BIN_MACRO(ps_bin_ctxt, u4_code_int_range,\n                                     u4_code_int_val_ofst, pu4_table,\n                                     ps_bitstrm, u4_symbol)\n\n                INC_BIN_COUNT(ps_cab_env);INC_DECISION_BINS(ps_cab_env);\n                u4_value++;\n            }\n            while(u4_symbol && (u4_value < u1_max_bins));\n\n        }\n\n        ps_cab_env->u4_code_int_range = u4_code_int_range;\n        ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n        u4_value = u4_value - 1 + u4_symbol;\n        u4_prefix = (u4_value);\n    }\n\n    i2_mvd = u4_prefix;\n\n    if(i2_mvd == 9)\n    {\n        /* Read Suffix */\n        k = ih264d_decode_bypass_bins_unary(ps_cab_env, ps_bitstrm);\n        i2_suf = (1 << k) - 1;\n        k = k + 3;\n        i2_suf = (i2_suf << 3);\n        i2_mvd += i2_suf;\n        i2_suf = ih264d_decode_bypass_bins(ps_cab_env, k, ps_bitstrm);\n        i2_mvd += i2_suf;\n    }\n    /* Read Sign bit */\n    if(!i2_mvd)\n        return (i2_mvd);\n\n    else\n    {\n        UWORD32 u4_code_int_val_ofst, u4_code_int_range;\n\n        u4_code_int_val_ofst = ps_cab_env->u4_code_int_val_ofst;\n        u4_code_int_range = ps_cab_env->u4_code_int_range;\n\n        if(u4_code_int_range < ONE_RIGHT_SHIFTED_BY_9)\n        {\n            UWORD32 *pu4_buffer, u4_offset;\n\n            pu4_buffer = ps_bitstrm->pu4_buffer;\n            u4_offset = ps_bitstrm->u4_ofst;\n\n            RENORM_RANGE_OFFSET(u4_code_int_range, u4_code_int_val_ofst,\n                                u4_offset, pu4_buffer)\n            ps_bitstrm->u4_ofst = u4_offset;\n        }\n\n        u4_code_int_range = u4_code_int_range >> 1;\n\n        if(u4_code_int_val_ofst >= u4_code_int_range)\n        {\n            /* S=1 */\n            u4_code_int_val_ofst -= u4_code_int_range;\n            i2_mvd = (-i2_mvd);\n        }\n\n        ps_cab_env->u4_code_int_val_ofst = u4_code_int_val_ofst;\n        ps_cab_env->u4_code_int_range = u4_code_int_range;\n\n        return (i2_mvd);\n\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_mb_header.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n ***************************************************************************\n * \\file ih264d_parse_mb_header.h\n *\n * \\brief\n *    This file contains context identifier decoding routines.\n *\n * \\date\n *    04/02/2003\n *\n * \\author  NS\n ***************************************************************************\n */\n#ifndef _IH264D_PARSE_MB_HEADER_H_\n#define _IH264D_PARSE_MB_HEADER_H_\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_cabac.h\"\n\nWORD32 ih264d_read_intra_pred_modes_cabac(dec_struct_t * ps_dec,\n                                          UWORD8 * pu1_prev_intra4x4_pred_mode_flag,\n                                          UWORD8 * pu1_rem_intra4x4_pred_mode,\n                                          UWORD8 u1_tran_form8x8);\n\nUWORD32 ih264d_parse_mb_type_cabac(struct _DecStruct * ps_dec);\nUWORD8 ih264d_parse_mb_type_intra_cabac(UWORD8 u1_inter,\n                                        struct _DecStruct * ps_dec);\n\nUWORD32 ih264d_parse_submb_type_cabac(const UWORD8 u1_slc_type_p,\n                                      decoding_envirnoment_t * ps_cab_env,\n                                      dec_bit_stream_t * ps_bitstrm,\n                                      bin_ctxt_model_t * ps_sub_mb_cxt);\nWORD32 ih264d_parse_ref_idx_cabac(const UWORD8 u1_num_part,\n                                const UWORD8 u1_b2,\n                                const UWORD8 u1_max_ref_minus1,\n                                const UWORD8 u1_mb_mode,\n                                WORD8 * pi1_ref_idx,\n                                WORD8 * const pi1_lft_cxt,\n                                WORD8 * const pi1_top_cxt,\n                                decoding_envirnoment_t * const ps_cab_env,\n                                dec_bit_stream_t * const ps_bitstrm,\n                                bin_ctxt_model_t * const ps_ref_cxt);\n\nWORD32 ih264d_parse_mb_qp_delta_cabac(struct _DecStruct * ps_dec,\n                                      WORD8 *pi1_mb_qp_delta);\nWORD8 ih264d_parse_chroma_pred_mode_cabac(struct _DecStruct * ps_dec);\n\nUWORD32 ih264d_parse_ctx_cbp_cabac(struct _DecStruct * ps_dec);\n\nUWORD8 ih264d_parse_transform8x8flag_cabac(struct _DecStruct * ps_dec,\n                                           dec_mb_info_t * ps_cur_mb_info);\n\nvoid ih264d_get_mvd_cabac(UWORD8 u1_sub_mb,\n                          UWORD8 u1_b2,\n                          UWORD8 u1_part_wd,\n                          UWORD8 u1_part_ht,\n                          UWORD8 u1_dec_mvd,\n                          dec_struct_t *ps_dec,\n                          mv_pred_t *ps_mv);\n\nWORD16 ih264d_parse_mvd_cabac(dec_bit_stream_t * ps_bitstrm,\n                              decoding_envirnoment_t * ps_cab_env,\n                              bin_ctxt_model_t * p_ctxt_mvd,\n                              UWORD32 temp);\n\n#endif /* _IH264D_PARSE_MB_HEADER_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_pslice.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*!\n **************************************************************************\n * \\file ih264d_parse_pslice.c\n *\n * \\brief\n *    Contains routines that decode a I slice type\n *\n * Detailed_description\n *\n * \\date\n *    07/07/2003\n *\n * \\author  NS\n **************************************************************************\n */\n\n#include <string.h>\n#include \"ih264_defs.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_mvpred.h\"\n#include \"ih264d_parse_islice.h\"\n#include \"ih264d_process_intra_mb.h\"\n#include \"ih264d_inter_pred.h\"\n#include \"ih264d_process_pslice.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_cabac.h\"\n#include \"ih264d_parse_mb_header.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_format_conv.h\"\n#include \"ih264d_quant_scaling.h\"\n#include \"ih264d_thread_parse_decode.h\"\n#include \"ih264d_thread_compute_bs.h\"\n#include \"ih264d_process_bslice.h\"\n#include \"ithread.h\"\n#include \"ih264d_utils.h\"\n#include \"ih264d_format_conv.h\"\n\nvoid ih264d_init_cabac_contexts(UWORD8 u1_slice_type, dec_struct_t * ps_dec);\nvoid ih264d_deblock_mb_level(dec_struct_t *ps_dec,\n                             dec_mb_info_t *ps_cur_mb_info,\n                             UWORD32 nmb_index);\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_pmb_cavlc \\endif\n *\n * \\brief\n *    This function parses CAVLC syntax of a P MB.\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_pmb_cavlc(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_num,\n                              UWORD8 u1_num_mbsNby2)\n{\n    UWORD32 u1_num_mb_part;\n    UWORD32 uc_sub_mb;\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 * const pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n\n    parse_pmbarams_t * ps_parse_mb_data = ps_dec->ps_parse_mb_data\n                    + u1_num_mbsNby2;\n    WORD8 * pi1_ref_idx = ps_parse_mb_data->i1_ref_idx[0];\n    const UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    const UWORD8 * pu1_num_mb_part = (const UWORD8 *)gau1_ih264d_num_mb_part;\n    UWORD8 * pu1_col_info = ps_parse_mb_data->u1_col_info;\n\n    UWORD32 u1_mb_type = ps_cur_mb_info->u1_mb_type;\n    UWORD32 u4_sum_mb_mode_pack = 0;\n    WORD32 ret;\n\n    UWORD8 u1_no_submb_part_size_lt8x8_flag = 1;\n    ps_cur_mb_info->u1_tran_form8x8 = 0;\n    ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n\n    ps_cur_mb_info->u1_yuv_dc_block_flag = 0;\n\n    ps_cur_mb_info->u1_mb_mc_mode = u1_mb_type;\n    uc_sub_mb = ((u1_mb_type == PRED_8x8) | (u1_mb_type == PRED_8x8R0));\n\n    /* Reading the subMB type */\n    if(uc_sub_mb)\n    {\n        WORD32 i;\n        UWORD8 u1_colz = (PRED_8x8 << 6);\n\n        for(i = 0; i < 4; i++)\n        {\n            UWORD32 ui_sub_mb_mode;\n\n            //Inlined ih264d_uev\n            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n            UWORD32 u4_word, u4_ldz;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n            u4_ldz = CLZ(u4_word);\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_ldz);\n            *pu4_bitstrm_ofst = u4_bitstream_offset;\n            ui_sub_mb_mode = ((1 << u4_ldz) + u4_word - 1);\n            //Inlined ih264d_uev\n\n            if(ui_sub_mb_mode > 3)\n            {\n                return ERROR_SUB_MB_TYPE;\n            }\n            else\n            {\n                u4_sum_mb_mode_pack = (u4_sum_mb_mode_pack << 8) | ui_sub_mb_mode;\n                /* Storing collocated information */\n                *pu1_col_info++ = u1_colz | (UWORD8)(ui_sub_mb_mode << 4);\n\n                COPYTHECONTEXT(\"sub_mb_type\", ui_sub_mb_mode);\n            }\n\n            /* check if Motion compensation is done below 8x8 */\n            if(ui_sub_mb_mode != P_L0_8x8)\n            {\n                u1_no_submb_part_size_lt8x8_flag = 0;\n            }\n        }\n\n        //\n        u1_num_mb_part = 4;\n    }\n    else\n    {\n        *pu1_col_info++ = (u1_mb_type << 6);\n        if(u1_mb_type)\n            *pu1_col_info++ = (u1_mb_type << 6);\n        u1_num_mb_part = pu1_num_mb_part[u1_mb_type];\n\n    }\n\n    /* Decoding reference index 0: For simple profile the following   */\n    /* conditions are always true (mb_field_decoding_flag == 0);      */\n    /* (MbPartPredMode != PredL1)                                     */\n\n    {\n\n        UWORD8 uc_field = ps_cur_mb_info->u1_mb_field_decodingflag;\n        UWORD8 uc_num_ref_idx_l0_active_minus1 =\n                        (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0]\n                                        << (u1_mbaff & uc_field)) - 1;\n\n        if((uc_num_ref_idx_l0_active_minus1 > 0) & (u1_mb_type != PRED_8x8R0))\n        {\n            if(1 == uc_num_ref_idx_l0_active_minus1)\n                ih264d_parse_pmb_ref_index_cavlc_range1(\n                                u1_num_mb_part, ps_bitstrm, pi1_ref_idx,\n                                uc_num_ref_idx_l0_active_minus1);\n            else\n            {\n                ret = ih264d_parse_pmb_ref_index_cavlc(\n                                u1_num_mb_part, ps_bitstrm, pi1_ref_idx,\n                                uc_num_ref_idx_l0_active_minus1);\n                if(ret != OK)\n                    return ret;\n            }\n        }\n        else\n        {\n            /* When there exists only a single frame to predict from */\n            UWORD8 uc_i;\n            for(uc_i = 0; uc_i < u1_num_mb_part; uc_i++)\n                /* Storing Reference Idx Information */\n                pi1_ref_idx[uc_i] = 0;\n        }\n    }\n\n    {\n        UWORD8 u1_p_idx, uc_i;\n        parse_part_params_t * ps_part = ps_dec->ps_part;\n        UWORD8 u1_sub_mb_mode, u1_num_subpart, u1_mb_part_width, u1_mb_part_height;\n        UWORD8 u1_sub_mb_num;\n        const UWORD8 * pu1_top_left_sub_mb_indx;\n        mv_pred_t * ps_mv, *ps_mv_start = ps_dec->ps_mv_cur + (u1_mb_num << 4);\n        /* Loading the table pointers */\n        const UWORD8 * pu1_mb_partw = (const UWORD8 *)gau1_ih264d_mb_partw;\n        const UWORD8 * pu1_mb_parth = (const UWORD8 *)gau1_ih264d_mb_parth;\n        const UWORD8 * pu1_sub_mb_indx_mod =\n                        (const UWORD8 *)(gau1_ih264d_submb_indx_mod)\n                                        + (uc_sub_mb * 6);\n        const UWORD8 * pu1_sub_mb_partw = (const UWORD8 *)gau1_ih264d_submb_partw;\n        const UWORD8 * pu1_sub_mb_parth = (const UWORD8 *)gau1_ih264d_submb_parth;\n        const UWORD8 * pu1_num_sub_mb_part =\n                        (const UWORD8 *)gau1_ih264d_num_submb_part;\n\n        UWORD16 u2_sub_mb_num = 0x028A;\n\n        /*********************************************************/\n        /* default initialisations for condition (uc_sub_mb == 0) */\n        /* i.e. all are subpartitions of 8x8                     */\n        /*********************************************************/\n        u1_sub_mb_mode = 0;\n        u1_num_subpart = 1;\n        u1_mb_part_width = pu1_mb_partw[u1_mb_type];\n        u1_mb_part_height = pu1_mb_parth[u1_mb_type];\n        pu1_top_left_sub_mb_indx = pu1_sub_mb_indx_mod + (u1_mb_type << 1);\n        u1_sub_mb_num = 0;\n\n        /* Loop on number of partitions */\n        for(uc_i = 0, u1_p_idx = 0; uc_i < u1_num_mb_part; uc_i++)\n        {\n            UWORD8 uc_j;\n            if(uc_sub_mb)\n            {\n                u1_sub_mb_mode = u4_sum_mb_mode_pack >> 24;\n                u1_num_subpart = pu1_num_sub_mb_part[u1_sub_mb_mode];\n                u1_mb_part_width = pu1_sub_mb_partw[u1_sub_mb_mode];\n                u1_mb_part_height = pu1_sub_mb_parth[u1_sub_mb_mode];\n                pu1_top_left_sub_mb_indx = pu1_sub_mb_indx_mod + (u1_sub_mb_mode << 1);\n                u1_sub_mb_num = u2_sub_mb_num >> 12;\n                u4_sum_mb_mode_pack <<= 8;\n                u2_sub_mb_num <<= 4;\n            }\n\n            /* Loop on Number of sub-partitions */\n            for(uc_j = 0; uc_j < u1_num_subpart; uc_j++, pu1_top_left_sub_mb_indx++)\n            {\n                WORD16 i2_mvx, i2_mvy;\n                u1_sub_mb_num += *pu1_top_left_sub_mb_indx;\n                ps_mv = ps_mv_start + u1_sub_mb_num;\n\n                /* Reading the differential Mv from the bitstream */\n                //i2_mvx = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n                //inlining ih264d_sev\n                {\n                    UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n                    UWORD32 u4_word, u4_ldz, u4_abs_val;\n\n                    /***************************************************************/\n                    /* Find leading zeros in next 32 bits                          */\n                    /***************************************************************/\n                    NEXTBITS_32(u4_word, u4_bitstream_offset,\n                                pu4_bitstrm_buf);\n                    u4_ldz = CLZ(u4_word);\n\n                    /* Flush the ps_bitstrm */\n                    u4_bitstream_offset += (u4_ldz + 1);\n\n                    /* Read the suffix from the ps_bitstrm */\n                    u4_word = 0;\n                    if(u4_ldz)\n                        GETBITS(u4_word, u4_bitstream_offset,\n                                pu4_bitstrm_buf, u4_ldz);\n\n                    *pu4_bitstrm_ofst = u4_bitstream_offset;\n                    u4_abs_val = ((1 << u4_ldz) + u4_word) >> 1;\n\n                    if(u4_word & 0x1)\n                        i2_mvx = (-(WORD32)u4_abs_val);\n                    else\n                        i2_mvx = (u4_abs_val);\n                }\n                //inlinined ih264d_sev\n                COPYTHECONTEXT(\"MVD\", i2_mvx);\n                i2_mvy = ih264d_sev(pu4_bitstrm_ofst,\n                                     pu4_bitstrm_buf);\n                COPYTHECONTEXT(\"MVD\", i2_mvy);\n\n                /* Storing Info for partitions */\n                ps_part->u1_is_direct = PART_NOT_DIRECT;\n                ps_part->u1_sub_mb_num = u1_sub_mb_num;\n                ps_part->u1_partheight = u1_mb_part_height;\n                ps_part->u1_partwidth = u1_mb_part_width;\n\n                /* Storing Mv residuals */\n                ps_mv->i2_mv[0] = i2_mvx;\n                ps_mv->i2_mv[1] = i2_mvy;\n\n                /* Increment partition Index */\n                u1_p_idx++;\n                ps_part++;\n            }\n        }\n        ps_parse_mb_data->u1_num_part = u1_p_idx;\n        ps_dec->ps_part = ps_part;\n    }\n\n    {\n        UWORD32 u4_cbp;\n\n        /* Read the Coded block pattern */\n        UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n        UWORD32 u4_word, u4_ldz;\n\n        /***************************************************************/\n        /* Find leading zeros in next 32 bits                          */\n        /***************************************************************/\n        NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n        u4_ldz = CLZ(u4_word);\n        /* Flush the ps_bitstrm */\n        u4_bitstream_offset += (u4_ldz + 1);\n        /* Read the suffix from the ps_bitstrm */\n        u4_word = 0;\n        if(u4_ldz)\n            GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf, u4_ldz);\n        *pu4_bitstrm_ofst = u4_bitstream_offset;\n        u4_cbp = ((1 << u4_ldz) + u4_word - 1);\n\n        if(u4_cbp > 47)\n            return ERROR_CBP;\n\n        u4_cbp = *((UWORD8*)gau1_ih264d_cbp_inter + u4_cbp);\n        COPYTHECONTEXT(\"coded_block_pattern\", u4_cbp);\n        ps_cur_mb_info->u1_cbp = u4_cbp;\n\n        /* Read the transform8x8 u4_flag if present */\n        if((ps_dec->s_high_profile.u1_transform8x8_present) && (u4_cbp & 0xf)\n                        && u1_no_submb_part_size_lt8x8_flag)\n        {\n            ps_cur_mb_info->u1_tran_form8x8 = ih264d_get_bit_h264(ps_bitstrm);\n            COPYTHECONTEXT(\"transform_size_8x8_flag\", ps_cur_mb_info->u1_tran_form8x8);\n            ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = ps_cur_mb_info->u1_tran_form8x8;\n        }\n\n        /* Read mb_qp_delta */\n        if(u4_cbp)\n        {\n            WORD32 i_temp;\n\n            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n            UWORD32 u4_word, u4_ldz, u4_abs_val;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n            u4_ldz = CLZ(u4_word);\n\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_ldz);\n\n            *pu4_bitstrm_ofst = u4_bitstream_offset;\n            u4_abs_val = ((1 << u4_ldz) + u4_word) >> 1;\n\n            if(u4_word & 0x1)\n                i_temp = (-(WORD32)u4_abs_val);\n            else\n                i_temp = (u4_abs_val);\n\n            if((i_temp < -26) || (i_temp > 25))\n                return ERROR_INV_RANGE_QP_T;\n            //inlinined ih264d_sev\n\n            COPYTHECONTEXT(\"mb_qp_delta\", i_temp);\n            if(i_temp)\n            {\n                ret = ih264d_update_qp(ps_dec, (WORD8)i_temp);\n                if(ret != OK)\n                    return ret;\n            }\n\n            ret = ih264d_parse_residual4x4_cavlc(ps_dec, ps_cur_mb_info, 0);\n            if(ret != OK)\n                return ret;\n            if(EXCEED_OFFSET(ps_bitstrm))\n                return ERROR_EOB_TERMINATE_T;\n        }\n        else\n        {\n            ih264d_update_nnz_for_skipmb(ps_dec, ps_cur_mb_info, CAVLC);\n        }\n\n\n\n    }\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_pmb_cabac \\endif\n *\n * \\brief\n *    This function parses CABAC syntax of a P MB.\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_pmb_cabac(dec_struct_t * ps_dec,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD8 u1_mb_num,\n                              UWORD8 u1_num_mbsNby2)\n{\n    UWORD32 u1_num_mb_part;\n    UWORD32 uc_sub_mb;\n    parse_pmbarams_t * ps_parse_mb_data = ps_dec->ps_parse_mb_data\n                    + u1_num_mbsNby2;\n    WORD8 * pi1_ref_idx = ps_parse_mb_data->i1_ref_idx[0];\n    const UWORD8 * pu1_num_mb_part = (const UWORD8 *)gau1_ih264d_num_mb_part;\n    const UWORD32 u1_mb_type = ps_cur_mb_info->u1_mb_type;\n    UWORD8 * pu1_col_info = ps_parse_mb_data->u1_col_info;\n    UWORD32 u1_mb_mc_mode = u1_mb_type;\n    ctxt_inc_mb_info_t * p_curr_ctxt = ps_dec->ps_curr_ctxt_mb_info;\n    decoding_envirnoment_t * ps_cab_env = &ps_dec->s_cab_dec_env;\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 u4_sub_mb_pack = 0;\n    WORD32 ret;\n\n    UWORD8 u1_no_submb_part_size_lt8x8_flag = 1;\n    ps_cur_mb_info->u1_tran_form8x8 = 0;\n    ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n\n    ps_cur_mb_info->u1_yuv_dc_block_flag = 0;\n\n    p_curr_ctxt->u1_mb_type = CAB_P;\n    ps_cur_mb_info->u1_mb_mc_mode = u1_mb_type;\n    uc_sub_mb = ((u1_mb_type == PRED_8x8) | (u1_mb_type == PRED_8x8R0));\n\n    /* Reading the subMB type */\n    if(uc_sub_mb)\n    {\n\n        UWORD8 u1_colz = (PRED_8x8 << 6);\n        u1_mb_mc_mode = 0;\n\n        {\n            UWORD8 u1_sub_mb_mode;\n            u1_sub_mb_mode = ih264d_parse_submb_type_cabac(\n                            0, ps_cab_env, ps_bitstrm,\n                            ps_dec->p_sub_mb_type_t);\n            if(u1_sub_mb_mode > 3)\n                return ERROR_SUB_MB_TYPE;\n\n            u4_sub_mb_pack = (u4_sub_mb_pack << 8) | u1_sub_mb_mode;\n            /* Storing collocated information */\n            *pu1_col_info++ = u1_colz | ((UWORD8)(u1_sub_mb_mode << 4));\n            COPYTHECONTEXT(\"sub_mb_type\", u1_sub_mb_mode);\n            /* check if Motion compensation is done below 8x8 */\n            if(u1_sub_mb_mode != P_L0_8x8)\n            {\n                u1_no_submb_part_size_lt8x8_flag = 0;\n            }\n        }\n        {\n            UWORD8 u1_sub_mb_mode;\n            u1_sub_mb_mode = ih264d_parse_submb_type_cabac(\n                            0, ps_cab_env, ps_bitstrm,\n                            ps_dec->p_sub_mb_type_t);\n            if(u1_sub_mb_mode > 3)\n                return ERROR_SUB_MB_TYPE;\n\n            u4_sub_mb_pack = (u4_sub_mb_pack << 8) | u1_sub_mb_mode;\n            /* Storing collocated information */\n            *pu1_col_info++ = u1_colz | ((UWORD8)(u1_sub_mb_mode << 4));\n            COPYTHECONTEXT(\"sub_mb_type\", u1_sub_mb_mode);\n            /* check if Motion compensation is done below 8x8 */\n            if(u1_sub_mb_mode != P_L0_8x8)\n            {\n                u1_no_submb_part_size_lt8x8_flag = 0;\n            }\n        }\n        {\n            UWORD8 u1_sub_mb_mode;\n            u1_sub_mb_mode = ih264d_parse_submb_type_cabac(\n                            0, ps_cab_env, ps_bitstrm,\n                            ps_dec->p_sub_mb_type_t);\n            if(u1_sub_mb_mode > 3)\n                return ERROR_SUB_MB_TYPE;\n\n            u4_sub_mb_pack = (u4_sub_mb_pack << 8) | u1_sub_mb_mode;\n            /* Storing collocated information */\n            *pu1_col_info++ = u1_colz | ((UWORD8)(u1_sub_mb_mode << 4));\n            COPYTHECONTEXT(\"sub_mb_type\", u1_sub_mb_mode);\n            /* check if Motion compensation is done below 8x8 */\n            if(u1_sub_mb_mode != P_L0_8x8)\n            {\n                u1_no_submb_part_size_lt8x8_flag = 0;\n            }\n        }\n        {\n            UWORD8 u1_sub_mb_mode;\n            u1_sub_mb_mode = ih264d_parse_submb_type_cabac(\n                            0, ps_cab_env, ps_bitstrm,\n                            ps_dec->p_sub_mb_type_t);\n            if(u1_sub_mb_mode > 3)\n                return ERROR_SUB_MB_TYPE;\n\n            u4_sub_mb_pack = (u4_sub_mb_pack << 8) | u1_sub_mb_mode;\n            /* Storing collocated information */\n            *pu1_col_info++ = u1_colz | ((UWORD8)(u1_sub_mb_mode << 4));\n            COPYTHECONTEXT(\"sub_mb_type\", u1_sub_mb_mode);\n            /* check if Motion compensation is done below 8x8 */\n            if(u1_sub_mb_mode != P_L0_8x8)\n            {\n                u1_no_submb_part_size_lt8x8_flag = 0;\n            }\n        }\n        u1_num_mb_part = 4;\n    }\n    else\n    {\n        u1_num_mb_part = pu1_num_mb_part[u1_mb_type];\n        /* Storing collocated Mb and SubMb mode information */\n        *pu1_col_info++ = (u1_mb_type << 6);\n        if(u1_mb_type)\n            *pu1_col_info++ = (u1_mb_type << 6);\n    }\n    /* Decoding reference index 0: For simple profile the following   */\n    /* conditions are always true (mb_field_decoding_flag == 0);      */\n    /* (MbPartPredMode != PredL1)                                     */\n    {\n        WORD8 * pi1_top_ref_idx_ctx_inc_arr = p_curr_ctxt->i1_ref_idx;\n        WORD8 * pi1_left_ref_idx_ctxt_inc = ps_dec->pi1_left_ref_idx_ctxt_inc;\n        UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n        UWORD8 uc_field = ps_cur_mb_info->u1_mb_field_decodingflag;\n        UWORD8 uc_num_ref_idx_l0_active_minus1 =\n                        (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0]\n                                        << (u1_mbaff & uc_field)) - 1;\n\n        if((uc_num_ref_idx_l0_active_minus1 > 0) & (u1_mb_type != PRED_8x8R0))\n        {\n            /* force the routine to decode ref idx for each partition */\n            *((UWORD32 *)pi1_ref_idx) = 0x01010101;\n            ret = ih264d_parse_ref_idx_cabac(u1_num_mb_part, 0,\n                                             uc_num_ref_idx_l0_active_minus1,\n                                             u1_mb_mc_mode, pi1_ref_idx,\n                                             pi1_left_ref_idx_ctxt_inc,\n                                             pi1_top_ref_idx_ctx_inc_arr, ps_cab_env,\n                                             ps_bitstrm, ps_dec->p_ref_idx_t);\n            if(ret != OK)\n                return ret;\n        }\n        else\n        {\n            /* When there exists only a single frame to predict from */\n            pi1_left_ref_idx_ctxt_inc[0] = 0;\n            pi1_left_ref_idx_ctxt_inc[1] = 0;\n            pi1_top_ref_idx_ctx_inc_arr[0] = 0;\n            pi1_top_ref_idx_ctx_inc_arr[1] = 0;\n            *((UWORD32 *)pi1_ref_idx) = 0;\n        }\n    }\n\n    {\n        UWORD8 u1_p_idx, uc_i;\n        parse_part_params_t * ps_part = ps_dec->ps_part;\n        UWORD8 u1_sub_mb_mode, u1_num_subpart, u1_mb_part_width, u1_mb_part_height;\n        UWORD8 u1_sub_mb_num;\n        const UWORD8 * pu1_top_left_sub_mb_indx;\n        mv_pred_t *ps_mv_start = ps_dec->ps_mv_cur + (u1_mb_num << 4);\n        UWORD16 u2_sub_mb_num_pack = 0x028A;\n\n        /* Loading the table pointers */\n        const UWORD8 * pu1_mb_partw = (const UWORD8 *)gau1_ih264d_mb_partw;\n        const UWORD8 * pu1_mb_parth = (const UWORD8 *)gau1_ih264d_mb_parth;\n        const UWORD8 * pu1_sub_mb_indx_mod =\n                        (const UWORD8 *)(gau1_ih264d_submb_indx_mod)\n                                        + (uc_sub_mb * 6);\n        const UWORD8 * pu1_sub_mb_partw = (const UWORD8 *)gau1_ih264d_submb_partw;\n        const UWORD8 * pu1_sub_mb_parth = (const UWORD8 *)gau1_ih264d_submb_parth;\n        const UWORD8 * pu1_num_sub_mb_part =\n                        (const UWORD8 *)gau1_ih264d_num_submb_part;\n\n        /*********************************************************/\n        /* default initialisations for condition (uc_sub_mb == 0) */\n        /* i.e. all are subpartitions of 8x8                     */\n        /*********************************************************/\n        u1_sub_mb_mode = 0;\n        u1_num_subpart = 1;\n        u1_mb_part_width = pu1_mb_partw[u1_mb_type];\n        u1_mb_part_height = pu1_mb_parth[u1_mb_type];\n        pu1_top_left_sub_mb_indx = pu1_sub_mb_indx_mod + (u1_mb_type << 1);\n        u1_sub_mb_num = 0;\n\n        /* Loop on number of partitions */\n        for(uc_i = 0, u1_p_idx = 0; uc_i < u1_num_mb_part; uc_i++)\n        {\n            UWORD8 uc_j;\n            if(uc_sub_mb)\n            {\n                u1_sub_mb_mode = u4_sub_mb_pack >> 24;\n                u1_num_subpart = pu1_num_sub_mb_part[u1_sub_mb_mode];\n                u1_mb_part_width = pu1_sub_mb_partw[u1_sub_mb_mode];\n                u1_mb_part_height = pu1_sub_mb_parth[u1_sub_mb_mode];\n                pu1_top_left_sub_mb_indx = pu1_sub_mb_indx_mod + (u1_sub_mb_mode << 1);\n                u1_sub_mb_num = u2_sub_mb_num_pack >> 12;\n                u4_sub_mb_pack <<= 8;\n                u2_sub_mb_num_pack <<= 4;\n            }\n            /* Loop on Number of sub-partitions */\n            for(uc_j = 0; uc_j < u1_num_subpart; uc_j++, pu1_top_left_sub_mb_indx++)\n            {\n                mv_pred_t * ps_mv;\n\n                u1_sub_mb_num += *pu1_top_left_sub_mb_indx;\n                ps_mv = ps_mv_start + u1_sub_mb_num;\n\n                /* Storing Info for partitions */\n                ps_part->u1_is_direct = PART_NOT_DIRECT;\n                ps_part->u1_sub_mb_num = u1_sub_mb_num;\n                ps_part->u1_partheight = u1_mb_part_height;\n                ps_part->u1_partwidth = u1_mb_part_width;\n\n                /* Increment partition Index */\n                u1_p_idx++;\n                ps_part++;\n\n                ih264d_get_mvd_cabac(u1_sub_mb_num, 0, u1_mb_part_width,\n                                     u1_mb_part_height, 1, ps_dec, ps_mv);\n            }\n        }\n        ps_parse_mb_data->u1_num_part = u1_p_idx;\n        ps_dec->ps_part = ps_part;\n    }\n    {\n        UWORD8 u1_cbp;\n\n        /* Read the Coded block pattern */\n        u1_cbp = (WORD8)ih264d_parse_ctx_cbp_cabac(ps_dec);\n        COPYTHECONTEXT(\"coded_block_pattern\", u1_cbp);\n        ps_cur_mb_info->u1_cbp = u1_cbp;\n        p_curr_ctxt->u1_cbp = u1_cbp;\n        p_curr_ctxt->u1_intra_chroma_pred_mode = 0;\n        p_curr_ctxt->u1_yuv_dc_csbp &= 0xFE;\n        ps_dec->pu1_left_yuv_dc_csbp[0] &= 0x6;\n\n        if(u1_cbp > 47)\n            return ERROR_CBP;\n\n        ps_cur_mb_info->u1_tran_form8x8 = 0;\n        ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n\n        /* Read the transform8x8 u4_flag if present */\n        if((ps_dec->s_high_profile.u1_transform8x8_present) && (u1_cbp & 0xf)\n                        && u1_no_submb_part_size_lt8x8_flag)\n        {\n            ps_cur_mb_info->u1_tran_form8x8 = ih264d_parse_transform8x8flag_cabac(\n                            ps_dec, ps_cur_mb_info);\n            COPYTHECONTEXT(\"transform_size_8x8_flag\", ps_cur_mb_info->u1_tran_form8x8);\n            p_curr_ctxt->u1_transform8x8_ctxt = ps_cur_mb_info->u1_tran_form8x8;\n            ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = ps_cur_mb_info->u1_tran_form8x8;\n\n        }\n        else\n        {\n            p_curr_ctxt->u1_transform8x8_ctxt = 0;\n        }\n\n        /* Read mb_qp_delta */\n        if(u1_cbp)\n        {\n            WORD8 c_temp;\n            ret = ih264d_parse_mb_qp_delta_cabac(ps_dec, &c_temp);\n            if(ret != OK)\n                return ret;\n            COPYTHECONTEXT(\"mb_qp_delta\", c_temp);\n            if(c_temp != 0)\n            {\n                ret = ih264d_update_qp(ps_dec, c_temp);\n                if(ret != OK)\n                    return ret;\n            }\n        }\n        else\n            ps_dec->i1_prev_mb_qp_delta = 0;\n\n\n\n        ih264d_parse_residual4x4_cabac(ps_dec, ps_cur_mb_info, 0);\n        if(EXCEED_OFFSET(ps_dec->ps_bitstrm))\n            return ERROR_EOB_TERMINATE_T;\n    }\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : parsePSliceData \\endif\n *\n * \\brief\n *    This function parses CAVLC syntax of N MB's of a P slice.\n *    1. After parsing syntax of N MB's, for those N MB's (less than N, incase\n *       of end of slice or end of row), MB is decoded. This process is carried\n *       for one complete MB row or till end of slice.\n *    2. Bottom one row of current MB is copied to IntraPredLine buffers.\n *       IntraPredLine buffers are used for Intra prediction of next row.\n *    3. Current MB row along with previous 4 rows of Luma (and 2 of Chroma) are\n *       deblocked.\n *    4. 4 rows (2 for Chroma) previous row and 12 rows (6 for Chroma) are\n *       DMA'ed to picture buffers.\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_update_nnz_for_skipmb \\endif\n *\n * \\brief\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\nvoid ih264d_update_nnz_for_skipmb(dec_struct_t * ps_dec,\n                                  dec_mb_info_t * ps_cur_mb_info,\n                                  UWORD8 u1_entrpy)\n{\n    UWORD32 *pu4_buf;\n    UWORD8 *pu1_buf;\n    UNUSED(u1_entrpy);\n    pu1_buf = ps_dec->pu1_left_nnz_y;\n    pu4_buf = (UWORD32 *)pu1_buf;\n    *pu4_buf = 0;\n    pu1_buf = ps_dec->pu1_left_nnz_uv;\n    pu4_buf = (UWORD32 *)pu1_buf;\n    *pu4_buf = 0;\n    pu1_buf = ps_cur_mb_info->ps_curmb->pu1_nnz_y;\n    pu4_buf = (UWORD32 *)pu1_buf;\n    *pu4_buf = 0;\n    pu1_buf = ps_cur_mb_info->ps_curmb->pu1_nnz_uv;\n    pu4_buf = (UWORD32 *)pu1_buf;\n    *pu4_buf = 0;\n    ps_cur_mb_info->ps_curmb->u2_luma_csbp = 0;\n    ps_cur_mb_info->u2_luma_csbp = 0;\n    ps_cur_mb_info->u2_chroma_csbp = 0;\n}\n\n\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_inter_slice_data_cabac                             */\n/*                                                                           */\n/*  Description   : This function parses cabac syntax of a inter slice on    */\n/*                  N MB basis.                                              */\n/*                                                                           */\n/*  Inputs        : ps_dec                                                   */\n/*                  sliceparams                                              */\n/*                  firstMbInSlice                                           */\n/*                                                                           */\n/*  Processing    : 1. After parsing syntax for N MBs those N MBs are        */\n/*                     decoded till the end of slice.                        */\n/*                  2. MV prediction and DMA happens on a N/2 MB basis.      */\n/*                                                                           */\n/*  Returns       : 0                                                        */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 07 2002   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_inter_slice_data_cabac(dec_struct_t * ps_dec,\n                                           dec_slice_params_t * ps_slice,\n                                           UWORD16 u2_first_mb_in_slice)\n{\n    UWORD32 uc_more_data_flag;\n    WORD32 i2_cur_mb_addr;\n    UWORD32 u1_num_mbs, u1_num_mbsNby2, u1_mb_idx;\n    UWORD32 u1_mbaff;\n    UWORD32 u1_num_mbs_next, u1_end_of_row;\n    const UWORD16 i2_pic_wdin_mbs = ps_dec->u2_frm_wd_in_mbs;\n    UWORD32 u1_slice_end = 0;\n    UWORD32 u1_tfr_n_mb = 0;\n    UWORD32 u1_decode_nmb = 0;\n\n\n    deblk_mb_t *ps_cur_deblk_mb;\n    dec_mb_info_t *ps_cur_mb_info;\n\n    parse_pmbarams_t *ps_parse_mb_data = ps_dec->ps_parse_mb_data;\n    UWORD32 u1_inter_mb_skip_type;\n    UWORD32 u1_inter_mb_type;\n    UWORD32 u1_deblk_mb_type;\n    UWORD32 u1_mb_threshold;\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    WORD32 ret = OK;\n\n    /******************************************************/\n    /* Initialisations specific to B or P slice           */\n    /******************************************************/\n    if(ps_slice->u1_slice_type == P_SLICE)\n    {\n        u1_inter_mb_skip_type = CAB_P_SKIP;\n        u1_inter_mb_type = P_MB;\n        u1_deblk_mb_type = D_INTER_MB;\n        u1_mb_threshold = 5;\n    }\n    else // B_SLICE\n    {\n        u1_inter_mb_skip_type = CAB_B_SKIP;\n        u1_inter_mb_type = B_MB;\n        u1_deblk_mb_type = D_B_SLICE;\n        u1_mb_threshold = 23;\n    }\n\n    /******************************************************/\n    /* Slice Level Initialisations                        */\n    /******************************************************/\n    i2_cur_mb_addr = u2_first_mb_in_slice;\n    ps_dec->u1_qp = ps_slice->u1_slice_qp;\n    ih264d_update_qp(ps_dec, 0);\n    u1_mb_idx = ps_dec->u1_mb_idx;\n    u1_num_mbs = u1_mb_idx;\n    u1_num_mbsNby2 = 0;\n    u1_mbaff = ps_slice->u1_mbaff_frame_flag;\n    i2_cur_mb_addr = u2_first_mb_in_slice << u1_mbaff;\n    uc_more_data_flag = 1;\n\n    /* Initialisations specific to cabac */\n    if(ps_bitstrm->u4_ofst & 0x07)\n    {\n        ps_bitstrm->u4_ofst += 8;\n        ps_bitstrm->u4_ofst &= 0xFFFFFFF8;\n    }\n\n    ret = ih264d_init_cabac_dec_envirnoment(&(ps_dec->s_cab_dec_env), ps_bitstrm);\n    if(ret != OK)\n        return ret;\n\n    ps_dec->i1_prev_mb_qp_delta = 0;\n\n    while(!u1_slice_end)\n    {\n        UWORD8 u1_mb_type;\n        UWORD32 u4_mb_skip;\n\n        ps_dec->pv_prev_mb_parse_tu_coeff_data = ps_dec->pv_parse_tu_coeff_data;\n\n        if(i2_cur_mb_addr > ps_dec->ps_cur_sps->u2_max_mb_addr)\n        {\n            break;\n        }\n\n        ps_cur_mb_info = ps_dec->ps_nmb_info + u1_num_mbs;\n        ps_dec->u4_num_mbs_cur_nmb = u1_num_mbs;\n\n        ps_cur_mb_info->u1_Mux = 0;\n        ps_dec->u4_num_pmbair = (u1_num_mbs >> u1_mbaff);\n        ps_cur_deblk_mb = ps_dec->ps_deblk_mbn + u1_num_mbs;\n\n        ps_cur_mb_info->u1_end_of_slice = 0;\n\n        /* Storing Default partition info */\n        ps_parse_mb_data->u1_num_part = 1;\n        ps_parse_mb_data->u1_isI_mb = 0;\n\n        /***************************************************************/\n        /* Get the required information for decoding of MB             */\n        /* mb_x, mb_y , neighbour availablity,                         */\n        /***************************************************************/\n        u4_mb_skip = ps_dec->pf_get_mb_info(ps_dec, i2_cur_mb_addr, ps_cur_mb_info, 1);\n\n        /*********************************************************************/\n        /* initialize u1_tran_form8x8 to zero to aviod uninitialized accesses */\n        /*********************************************************************/\n        ps_cur_mb_info->u1_tran_form8x8 = 0;\n        ps_cur_mb_info->ps_curmb->u1_tran_form8x8 = 0;\n\n        /***************************************************************/\n        /* Set the deblocking parameters for this MB                   */\n        /***************************************************************/\n        if(ps_dec->u4_app_disable_deblk_frm == 0)\n            ih264d_set_deblocking_parameters(ps_cur_deblk_mb, ps_slice,\n                                             ps_dec->u1_mb_ngbr_availablity,\n                                             ps_dec->u1_cur_mb_fld_dec_flag);\n\n        if(u4_mb_skip)\n        {\n\n            /* Set appropriate flags in ps_cur_mb_info and ps_dec */\n            memset(ps_dec->ps_curr_ctxt_mb_info, 0, sizeof(ctxt_inc_mb_info_t));\n            ps_dec->ps_curr_ctxt_mb_info->u1_mb_type = u1_inter_mb_skip_type;\n\n            MEMSET_16BYTES(&ps_dec->pu1_left_mv_ctxt_inc[0][0], 0);\n\n            *((UWORD32 *)ps_dec->pi1_left_ref_idx_ctxt_inc) = 0;\n            *(ps_dec->pu1_left_yuv_dc_csbp) = 0;\n\n            ps_dec->i1_prev_mb_qp_delta = 0;\n            ps_cur_mb_info->u1_mb_type = MB_SKIP;\n            ps_cur_mb_info->u1_cbp = 0;\n\n            {\n                /* Storing Skip partition info */\n                parse_part_params_t *ps_part_info = ps_dec->ps_part;\n                ps_part_info->u1_is_direct = PART_DIRECT_16x16;\n                ps_part_info->u1_sub_mb_num = 0;\n                ps_dec->ps_part++;\n            }\n\n            /* Update Nnzs */\n            ih264d_update_nnz_for_skipmb(ps_dec, ps_cur_mb_info, CABAC);\n\n            ps_cur_mb_info->ps_curmb->u1_mb_type = u1_inter_mb_type;\n            ps_cur_deblk_mb->u1_mb_type |= u1_deblk_mb_type;\n            ps_cur_deblk_mb->u1_mb_qp = ps_dec->u1_qp;\n\n        }\n        else\n        {\n\n            /* Macroblock Layer Begins */\n            /* Decode the u1_mb_type */\n            u1_mb_type = ih264d_parse_mb_type_cabac(ps_dec);\n            ps_cur_mb_info->u1_mb_type = u1_mb_type;\n            if(u1_mb_type > (25 + u1_mb_threshold))\n                return ERROR_MB_TYPE;\n\n            /* Parse Macroblock Data */\n            if(u1_mb_type < u1_mb_threshold)\n            {\n                ps_cur_mb_info->ps_curmb->u1_mb_type = u1_inter_mb_type;\n                *(ps_dec->pu1_left_yuv_dc_csbp) &= 0x6;\n\n                ret = ps_dec->pf_parse_inter_mb(ps_dec, ps_cur_mb_info, u1_num_mbs,\n                                          u1_num_mbsNby2);\n                if(ret != OK)\n                    return ret;\n                ps_cur_deblk_mb->u1_mb_qp = ps_dec->u1_qp;\n                ps_cur_deblk_mb->u1_mb_type |= u1_deblk_mb_type;\n            }\n            else\n            {\n                /* Storing Intra partition info */\n                ps_parse_mb_data->u1_num_part = 0;\n                ps_parse_mb_data->u1_isI_mb = 1;\n\n                if((25 + u1_mb_threshold) == u1_mb_type)\n                {\n                    /* I_PCM_MB */\n                    ps_cur_mb_info->ps_curmb->u1_mb_type = I_PCM_MB;\n                    ret = ih264d_parse_ipcm_mb(ps_dec, ps_cur_mb_info, u1_num_mbs);\n                    if(ret != OK)\n                        return ret;\n                    ps_cur_deblk_mb->u1_mb_qp = 0;\n                }\n                else\n                {\n                    if(u1_mb_type == u1_mb_threshold)\n                        ps_cur_mb_info->ps_curmb->u1_mb_type = I_4x4_MB;\n                    else\n                        ps_cur_mb_info->ps_curmb->u1_mb_type = I_16x16_MB;\n\n                    ret = ih264d_parse_imb_cabac(\n                                    ps_dec, ps_cur_mb_info,\n                                    (UWORD8)(u1_mb_type - u1_mb_threshold));\n                    if(ret != OK)\n                        return ret;\n                    ps_cur_deblk_mb->u1_mb_qp = ps_dec->u1_qp;\n                }\n                ps_cur_deblk_mb->u1_mb_type |= D_INTRA_MB;\n\n            }\n\n        }\n\n        if(u1_mbaff)\n        {\n            ih264d_update_mbaff_left_nnz(ps_dec, ps_cur_mb_info);\n        }\n\n\n        if(ps_cur_mb_info->u1_topmb && u1_mbaff)\n            uc_more_data_flag = 1;\n        else\n        {\n            uc_more_data_flag = ih264d_decode_terminate(&ps_dec->s_cab_dec_env,\n                                                      ps_bitstrm);\n            uc_more_data_flag = !uc_more_data_flag;\n            COPYTHECONTEXT(\"Decode Sliceterm\",!uc_more_data_flag);\n        }\n\n        if(u1_mbaff)\n        {\n            if(!uc_more_data_flag && (0 == (i2_cur_mb_addr & 1)))\n            {\n                return ERROR_EOB_FLUSHBITS_T;\n            }\n        }\n        /* Next macroblock information */\n        i2_cur_mb_addr++;\n        u1_num_mbs++;\n        u1_num_mbsNby2++;\n        ps_parse_mb_data++;\n\n        /****************************************************************/\n        /* Check for End Of Row and other flags that determine when to  */\n        /* do DMA setup for N/2-Mb, Decode for N-Mb, and Transfer for   */\n        /* N-Mb                                                         */\n        /****************************************************************/\n        u1_num_mbs_next = i2_pic_wdin_mbs - ps_dec->u2_mbx - 1;\n        u1_end_of_row = (!u1_num_mbs_next) && (!(u1_mbaff && (u1_num_mbs & 0x01)));\n        u1_slice_end = !uc_more_data_flag;\n        u1_tfr_n_mb = (u1_num_mbs == ps_dec->u1_recon_mb_grp) || u1_end_of_row\n                        || u1_slice_end;\n        u1_decode_nmb = u1_tfr_n_mb || u1_slice_end;\n        ps_cur_mb_info->u1_end_of_slice = u1_slice_end;\n        /*u1_dma_nby2mb   = u1_decode_nmb ||\n         (u1_num_mbsNby2 == ps_dec->u1_recon_mb_grp_pair);*/\n\n//if(u1_dma_nby2mb)\n        if(u1_decode_nmb)\n        {\n\n            ps_dec->pf_mvpred_ref_tfr_nby2mb(ps_dec, u1_mb_idx, u1_num_mbs);\n            u1_num_mbsNby2 = 0;\n\n            {\n                ps_parse_mb_data = ps_dec->ps_parse_mb_data;\n                ps_dec->ps_part = ps_dec->ps_parse_part_params;\n            }\n        }\n\n        /*H264_DEC_DEBUG_PRINT(\"Pic: %d Mb_X=%d Mb_Y=%d\",\n         ps_slice->i4_poc >> ps_slice->u1_field_pic_flag,\n         ps_dec->u2_mbx,ps_dec->u2_mby + (1 - ps_cur_mb_info->u1_topmb));\n         H264_DEC_DEBUG_PRINT(\"u1_decode_nmb: %d, u1_num_mbs: %d\", u1_decode_nmb, u1_num_mbs);*/\n        if(u1_decode_nmb)\n        {\n\n            if(ps_dec->u1_separate_parse)\n            {\n                ih264d_parse_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                                     u1_num_mbs_next, u1_tfr_n_mb, u1_end_of_row);\n                ps_dec->ps_nmb_info +=  u1_num_mbs;\n            }\n            else\n            {\n                ih264d_decode_recon_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                                            u1_num_mbs_next, u1_tfr_n_mb,\n                                            u1_end_of_row);\n            }\n            ps_dec->u2_total_mbs_coded += u1_num_mbs;\n            if(u1_tfr_n_mb)\n                u1_num_mbs = 0;\n            u1_mb_idx = u1_num_mbs;\n            ps_dec->u1_mb_idx = u1_num_mbs;\n\n        }\n    }\n\n\n    ps_dec->u4_num_mbs_cur_nmb = 0;\n    ps_dec->ps_cur_slice->u4_mbs_in_slice = i2_cur_mb_addr\n\n                        - (u2_first_mb_in_slice << u1_mbaff);\n\n    return ret;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_inter_slice_data_cavlc                             */\n/*                                                                           */\n/*  Description   : This function parses cavlc syntax of a inter slice on    */\n/*                  N MB basis.                                              */\n/*                                                                           */\n/*  Inputs        : ps_dec                                                   */\n/*                  sliceparams                                              */\n/*                  firstMbInSlice                                           */\n/*                                                                           */\n/*  Processing    : 1. After parsing syntax for N MBs those N MBs are        */\n/*                     decoded till the end of slice.                        */\n/*                  2. MV prediction and DMA happens on a N/2 MB basis.      */\n/*                                                                           */\n/*  Returns       : 0                                                        */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 07 2002   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_parse_inter_slice_data_cavlc(dec_struct_t * ps_dec,\n                                           dec_slice_params_t * ps_slice,\n                                           UWORD16 u2_first_mb_in_slice)\n{\n    UWORD32 uc_more_data_flag;\n    WORD32 i2_cur_mb_addr;\n    UWORD32 u1_num_mbs, u1_num_mbsNby2, u1_mb_idx;\n    UWORD32 i2_mb_skip_run;\n    UWORD32 u1_read_mb_type;\n\n    UWORD32 u1_mbaff;\n    UWORD32 u1_num_mbs_next, u1_end_of_row;\n    const UWORD32 i2_pic_wdin_mbs = ps_dec->u2_frm_wd_in_mbs;\n    UWORD32 u1_slice_end = 0;\n    UWORD32 u1_tfr_n_mb = 0;\n    UWORD32 u1_decode_nmb = 0;\n\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    deblk_mb_t *ps_cur_deblk_mb;\n    dec_mb_info_t *ps_cur_mb_info;\n    parse_pmbarams_t *ps_parse_mb_data = ps_dec->ps_parse_mb_data;\n    UWORD32 u1_inter_mb_type;\n    UWORD32 u1_deblk_mb_type;\n    UWORD32 u1_mb_threshold;\n    WORD32 ret = OK;\n\n    /******************************************************/\n    /* Initialisations specific to B or P slice           */\n    /******************************************************/\n\n    if(ps_slice->u1_slice_type == P_SLICE)\n    {\n        u1_inter_mb_type = P_MB;\n        u1_deblk_mb_type = D_INTER_MB;\n        u1_mb_threshold = 5;\n    }\n    else // B_SLICE\n    {\n        u1_inter_mb_type = B_MB;\n        u1_deblk_mb_type = D_B_SLICE;\n        u1_mb_threshold = 23;\n    }\n    /******************************************************/\n    /* Slice Level Initialisations                        */\n    /******************************************************/\n    ps_dec->u1_qp = ps_slice->u1_slice_qp;\n    ih264d_update_qp(ps_dec, 0);\n    u1_mb_idx = ps_dec->u1_mb_idx;\n    u1_num_mbs = u1_mb_idx;\n\n    u1_num_mbsNby2 = 0;\n    u1_mbaff = ps_slice->u1_mbaff_frame_flag;\n    i2_cur_mb_addr = u2_first_mb_in_slice << u1_mbaff;\n    i2_mb_skip_run = 0;\n    uc_more_data_flag = 1;\n    u1_read_mb_type = 0;\n\n    while(!u1_slice_end)\n    {\n        UWORD8 u1_mb_type;\n\n        ps_dec->pv_prev_mb_parse_tu_coeff_data = ps_dec->pv_parse_tu_coeff_data;\n\n        if(i2_cur_mb_addr > ps_dec->ps_cur_sps->u2_max_mb_addr)\n        {\n            break;\n        }\n\n\n        ps_cur_mb_info = ps_dec->ps_nmb_info + u1_num_mbs;\n        ps_dec->u4_num_mbs_cur_nmb = u1_num_mbs;\n\n        ps_cur_mb_info->u1_Mux = 0;\n        ps_dec->u4_num_pmbair = (u1_num_mbs >> u1_mbaff);\n        ps_cur_deblk_mb = ps_dec->ps_deblk_mbn + u1_num_mbs;\n\n        ps_cur_mb_info->u1_end_of_slice = 0;\n\n        /* Storing Default partition info */\n        ps_parse_mb_data->u1_num_part = 1;\n        ps_parse_mb_data->u1_isI_mb = 0;\n\n        if((!i2_mb_skip_run) && (!u1_read_mb_type))\n        {\n\n            //Inlined ih264d_uev\n            UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n            UWORD32 u4_word, u4_ldz;\n\n            /***************************************************************/\n            /* Find leading zeros in next 32 bits                          */\n            /***************************************************************/\n            NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n\n            u4_ldz = CLZ(u4_word);\n\n            /* Flush the ps_bitstrm */\n            u4_bitstream_offset += (u4_ldz + 1);\n            /* Read the suffix from the ps_bitstrm */\n            u4_word = 0;\n            if(u4_ldz)\n            {\n                GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                        u4_ldz);\n            }\n            *pu4_bitstrm_ofst = u4_bitstream_offset;\n            i2_mb_skip_run = ((1 << u4_ldz) + u4_word - 1);\n            //Inlined ih264d_uev\n            COPYTHECONTEXT(\"mb_skip_run\", i2_mb_skip_run);\n            uc_more_data_flag = MORE_RBSP_DATA(ps_bitstrm);\n            u1_read_mb_type = uc_more_data_flag;\n        }\n\n        /***************************************************************/\n        /* Get the required information for decoding of MB                  */\n        /* mb_x, mb_y , neighbour availablity,                              */\n        /***************************************************************/\n        ps_dec->pf_get_mb_info(ps_dec, i2_cur_mb_addr, ps_cur_mb_info, i2_mb_skip_run);\n\n        /***************************************************************/\n        /* Set the deblocking parameters for this MB                   */\n        /***************************************************************/\n        if(ps_dec->u4_app_disable_deblk_frm == 0)\n            ih264d_set_deblocking_parameters(ps_cur_deblk_mb, ps_slice,\n                                             ps_dec->u1_mb_ngbr_availablity,\n                                             ps_dec->u1_cur_mb_fld_dec_flag);\n\n        if(i2_mb_skip_run)\n        {\n            /* Set appropriate flags in ps_cur_mb_info and ps_dec */\n            ps_dec->i1_prev_mb_qp_delta = 0;\n            ps_dec->u1_sub_mb_num = 0;\n            ps_cur_mb_info->u1_mb_type = MB_SKIP;\n            ps_cur_mb_info->u1_mb_mc_mode = PRED_16x16;\n            ps_cur_mb_info->u1_cbp = 0;\n\n            {\n                /* Storing Skip partition info */\n                parse_part_params_t *ps_part_info = ps_dec->ps_part;\n                ps_part_info->u1_is_direct = PART_DIRECT_16x16;\n                ps_part_info->u1_sub_mb_num = 0;\n                ps_dec->ps_part++;\n            }\n\n            /* Update Nnzs */\n            ih264d_update_nnz_for_skipmb(ps_dec, ps_cur_mb_info, CAVLC);\n\n            ps_cur_mb_info->ps_curmb->u1_mb_type = u1_inter_mb_type;\n            ps_cur_deblk_mb->u1_mb_type |= u1_deblk_mb_type;\n\n            i2_mb_skip_run--;\n        }\n        else\n        {\n            u1_read_mb_type = 0;\n            /**************************************************************/\n            /* Macroblock Layer Begins, Decode the u1_mb_type                */\n            /**************************************************************/\n            {\n                UWORD32 u4_bitstream_offset = *pu4_bitstrm_ofst;\n                UWORD32 u4_word, u4_ldz, u4_temp;\n\n\n                //Inlined ih264d_uev\n                /***************************************************************/\n                /* Find leading zeros in next 32 bits                          */\n                /***************************************************************/\n                NEXTBITS_32(u4_word, u4_bitstream_offset, pu4_bitstrm_buf);\n                u4_ldz = CLZ(u4_word);\n                /* Flush the ps_bitstrm */\n                u4_bitstream_offset += (u4_ldz + 1);\n                /* Read the suffix from the ps_bitstrm */\n                u4_word = 0;\n                if(u4_ldz)\n                    GETBITS(u4_word, u4_bitstream_offset, pu4_bitstrm_buf,\n                            u4_ldz);\n                *pu4_bitstrm_ofst = u4_bitstream_offset;\n                u4_temp = ((1 << u4_ldz) + u4_word - 1);\n                //Inlined ih264d_uev\n                if(u4_temp > (UWORD32)(25 + u1_mb_threshold))\n                    return ERROR_MB_TYPE;\n                u1_mb_type = u4_temp;\n                COPYTHECONTEXT(\"u1_mb_type\", u1_mb_type);\n            }\n            ps_cur_mb_info->u1_mb_type = u1_mb_type;\n\n            /**************************************************************/\n            /* Parse Macroblock data                                      */\n            /**************************************************************/\n            if(u1_mb_type < u1_mb_threshold)\n            {\n                ps_cur_mb_info->ps_curmb->u1_mb_type = u1_inter_mb_type;\n\n                ret = ps_dec->pf_parse_inter_mb(ps_dec, ps_cur_mb_info, u1_num_mbs,\n                                          u1_num_mbsNby2);\n                if(ret != OK)\n                    return ret;\n                ps_cur_deblk_mb->u1_mb_type |= u1_deblk_mb_type;\n            }\n            else\n            {\n                /* Storing Intra partition info */\n                ps_parse_mb_data->u1_num_part = 0;\n                ps_parse_mb_data->u1_isI_mb = 1;\n\n                if((25 + u1_mb_threshold) == u1_mb_type)\n                {\n                    /* I_PCM_MB */\n                    ps_cur_mb_info->ps_curmb->u1_mb_type = I_PCM_MB;\n                    ret = ih264d_parse_ipcm_mb(ps_dec, ps_cur_mb_info, u1_num_mbs);\n                    if(ret != OK)\n                         return ret;\n                    ps_dec->u1_qp = 0;\n                }\n                else\n                {\n                    ret = ih264d_parse_imb_cavlc(\n                                    ps_dec, ps_cur_mb_info, u1_num_mbs,\n                                    (UWORD8)(u1_mb_type - u1_mb_threshold));\n                    if(ret != OK)\n                        return ret;\n                }\n\n                ps_cur_deblk_mb->u1_mb_type |= D_INTRA_MB;\n            }\n            uc_more_data_flag = MORE_RBSP_DATA(ps_bitstrm);\n        }\n        ps_cur_deblk_mb->u1_mb_qp = ps_dec->u1_qp;\n\n        if(u1_mbaff)\n        {\n            ih264d_update_mbaff_left_nnz(ps_dec, ps_cur_mb_info);\n            if(!uc_more_data_flag && !i2_mb_skip_run && (0 == (i2_cur_mb_addr & 1)))\n            {\n                return ERROR_EOB_FLUSHBITS_T;\n            }\n        }\n        /**************************************************************/\n        /* Get next Macroblock address                                */\n        /**************************************************************/\n        i2_cur_mb_addr++;\n\n        u1_num_mbs++;\n        u1_num_mbsNby2++;\n        ps_parse_mb_data++;\n\n        /****************************************************************/\n        /* Check for End Of Row and other flags that determine when to  */\n        /* do DMA setup for N/2-Mb, Decode for N-Mb, and Transfer for   */\n        /* N-Mb                                                         */\n        /****************************************************************/\n        u1_num_mbs_next = i2_pic_wdin_mbs - ps_dec->u2_mbx - 1;\n        u1_end_of_row = (!u1_num_mbs_next) && (!(u1_mbaff && (u1_num_mbs & 0x01)));\n        u1_slice_end = (!(uc_more_data_flag || i2_mb_skip_run));\n        u1_tfr_n_mb = (u1_num_mbs == ps_dec->u1_recon_mb_grp) || u1_end_of_row\n                        || u1_slice_end;\n        u1_decode_nmb = u1_tfr_n_mb || u1_slice_end;\n        ps_cur_mb_info->u1_end_of_slice = u1_slice_end;\n\n        /*u1_dma_nby2mb   = u1_decode_nmb ||\n         (u1_num_mbsNby2 == ps_dec->u1_recon_mb_grp_pair);*/\n\n//if(u1_dma_nby2mb)\n        if(u1_decode_nmb)\n        {\n            ps_dec->pf_mvpred_ref_tfr_nby2mb(ps_dec, u1_mb_idx, u1_num_mbs);\n            u1_num_mbsNby2 = 0;\n\n            {\n                ps_parse_mb_data = ps_dec->ps_parse_mb_data;\n                ps_dec->ps_part = ps_dec->ps_parse_part_params;\n            }\n        }\n\n        /*H264_DEC_DEBUG_PRINT(\"Pic: %d Mb_X=%d Mb_Y=%d\",\n         ps_slice->i4_poc >> ps_slice->u1_field_pic_flag,\n         ps_dec->u2_mbx,ps_dec->u2_mby + (1 - ps_cur_mb_info->u1_topmb));\n         H264_DEC_DEBUG_PRINT(\"u1_decode_nmb: %d\", u1_decode_nmb);*/\n        if(u1_decode_nmb)\n        {\n\n\n\n            if(ps_dec->u1_separate_parse)\n            {\n                ih264d_parse_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                                     u1_num_mbs_next, u1_tfr_n_mb, u1_end_of_row);\n                ps_dec->ps_nmb_info +=  u1_num_mbs;\n            }\n            else\n            {\n                ih264d_decode_recon_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                                            u1_num_mbs_next, u1_tfr_n_mb,\n                                            u1_end_of_row);\n            }\n            ps_dec->u2_total_mbs_coded += u1_num_mbs;\n            if(u1_tfr_n_mb)\n                u1_num_mbs = 0;\n            u1_mb_idx = u1_num_mbs;\n            ps_dec->u1_mb_idx = u1_num_mbs;\n\n        }\n//ps_dec->ps_pred++;\n    }\n\n    ps_dec->u4_num_mbs_cur_nmb = 0;\n    ps_dec->ps_cur_slice->u4_mbs_in_slice = i2_cur_mb_addr\n                        - (u2_first_mb_in_slice << u1_mbaff);\n\n\n    return ret;\n}\n\nWORD32 ih264d_mark_err_slice_skip(dec_struct_t * ps_dec,\n                                WORD32 num_mb_skip,\n                                UWORD8 u1_is_idr_slice,\n                                UWORD16 u2_frame_num,\n                                pocstruct_t *ps_cur_poc,\n                                WORD32 prev_slice_err)\n{\n    WORD32 i2_cur_mb_addr;\n    UWORD32 u1_num_mbs, u1_num_mbsNby2;\n    UWORD32 u1_mb_idx = ps_dec->u1_mb_idx;\n    UWORD32 i2_mb_skip_run;\n\n    UWORD32 u1_num_mbs_next, u1_end_of_row;\n    const UWORD32 i2_pic_wdin_mbs = ps_dec->u2_frm_wd_in_mbs;\n    UWORD32 u1_slice_end;\n    UWORD32 u1_tfr_n_mb;\n    UWORD32 u1_decode_nmb;\n    dec_bit_stream_t * const ps_bitstrm = ps_dec->ps_bitstrm;\n    dec_slice_params_t * ps_slice = ps_dec->ps_cur_slice;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    deblk_mb_t *ps_cur_deblk_mb;\n    dec_mb_info_t *ps_cur_mb_info;\n    parse_pmbarams_t *ps_parse_mb_data;\n    UWORD32 u1_inter_mb_type;\n    UWORD32 u1_deblk_mb_type;\n    UWORD16 u2_total_mbs_coded;\n    UWORD32 u1_mbaff;\n    parse_part_params_t *ps_part_info;\n    WORD32 ret;\n    UNUSED(u1_is_idr_slice);\n\n    if(ps_dec->ps_dec_err_status->u1_err_flag & REJECT_CUR_PIC)\n    {\n        ih264d_err_pic_dispbuf_mgr(ps_dec);\n        return 0;\n    }\n\n    if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag && (num_mb_skip & 1))\n    {\n        num_mb_skip++;\n    }\n    ps_dec->ps_dpb_cmds->u1_long_term_reference_flag = 0;\n    if(prev_slice_err == 1)\n    {\n        /* first slice - missing/header corruption */\n        ps_dec->ps_cur_slice->u2_frame_num = u2_frame_num;\n        {\n            WORD32 i, j, poc = 0;\n\n            ps_dec->ps_cur_slice->u2_first_mb_in_slice = 0;\n\n            ps_dec->pf_mvpred = ih264d_mvpred_nonmbaff;\n            ps_dec->p_form_mb_part_info = ih264d_form_mb_part_info_bp;\n            ps_dec->p_motion_compensate = ih264d_motion_compensate_bp;\n\n            if(ps_dec->ps_cur_pic != NULL)\n            {\n                poc = ps_dec->ps_cur_pic->i4_poc;\n                if (poc <= INT32_MAX - 2)\n                    poc += 2;\n            }\n\n            j = -1;\n            for(i = 0; i < MAX_NUM_PIC_PARAMS; i++)\n            {\n                   if(ps_dec->ps_pps[i].u1_is_valid == TRUE)\n                   {\n                       if(ps_dec->ps_pps[i].ps_sps->u1_is_valid == TRUE)\n                       {\n                           j = i;\n                           break;\n                       }\n                   }\n            }\n\n            //if valid SPS PPS is not found return error\n            if(j == -1)\n            {\n                return ERROR_INV_SLICE_HDR_T;\n            }\n\n            /* call ih264d_start_of_pic only if it was not called earlier*/\n            if(ps_dec->u4_pic_buf_got == 0)\n            {\n                //initialize slice params required by ih264d_start_of_pic to valid values\n                ps_dec->ps_cur_slice->u1_slice_type = P_SLICE;\n                ps_dec->ps_cur_slice->u1_nal_ref_idc = 1;\n                ps_dec->ps_cur_slice->u1_nal_unit_type = 1;\n                ret = ih264d_start_of_pic(ps_dec, poc, ps_cur_poc,\n                        ps_dec->ps_cur_slice->u2_frame_num,\n                        &ps_dec->ps_pps[j]);\n\n                if(ret != OK)\n                {\n                    return ret;\n                }\n            }\n\n            ps_dec->ps_ref_pic_buf_lx[0][0]->u1_pic_buf_id = 0;\n\n            ps_dec->u4_output_present = 0;\n\n            {\n                ih264d_get_next_display_field(ps_dec,\n                                              ps_dec->ps_out_buffer,\n                                              &(ps_dec->s_disp_op));\n                /* If error code is non-zero then there is no buffer available for display,\n                 hence avoid format conversion */\n\n                if(0 != ps_dec->s_disp_op.u4_error_code)\n                {\n                    ps_dec->u4_fmt_conv_cur_row = ps_dec->s_disp_frame_info.u4_y_ht;\n                }\n                else\n                    ps_dec->u4_output_present = 1;\n            }\n\n            if(ps_dec->u1_separate_parse == 1)\n            {\n                if(ps_dec->u4_dec_thread_created == 0)\n                {\n                    ithread_create(ps_dec->pv_dec_thread_handle, NULL,\n                                   (void *)ih264d_decode_picture_thread,\n                                   (void *)ps_dec);\n\n                    ps_dec->u4_dec_thread_created = 1;\n                }\n\n                if((ps_dec->u4_num_cores == 3) &&\n                                ((ps_dec->u4_app_disable_deblk_frm == 0) || ps_dec->i1_recon_in_thread3_flag)\n                                && (ps_dec->u4_bs_deblk_thread_created == 0))\n                {\n                    ps_dec->u4_start_recon_deblk = 0;\n                    ithread_create(ps_dec->pv_bs_deblk_thread_handle, NULL,\n                                   (void *)ih264d_recon_deblk_thread,\n                                   (void *)ps_dec);\n                    ps_dec->u4_bs_deblk_thread_created = 1;\n                }\n            }\n        }\n    }\n    else\n    {\n        // Middle / last slice\n\n        dec_slice_struct_t *ps_parse_cur_slice;\n        ps_parse_cur_slice = ps_dec->ps_dec_slice_buf + ps_dec->u2_cur_slice_num;\n\n        if(ps_dec->u1_slice_header_done\n            && ps_parse_cur_slice == ps_dec->ps_parse_cur_slice)\n        {\n            // Slice data corrupted\n            // in the case of mbaff, conceal from the even mb.\n            if((ps_dec->ps_cur_slice->u1_mbaff_frame_flag) && (ps_dec->u4_num_mbs_cur_nmb & 1))\n            {\n                ps_dec->u4_num_mbs_cur_nmb = ps_dec->u4_num_mbs_cur_nmb - 1;\n                ps_dec->u2_cur_mb_addr--;\n            }\n\n            u1_num_mbs = ps_dec->u4_num_mbs_cur_nmb;\n            if(u1_num_mbs)\n            {\n                ps_cur_mb_info = ps_dec->ps_nmb_info + u1_num_mbs - 1;\n            }\n            else\n            {\n                if(ps_dec->u1_separate_parse)\n                {\n                    ps_cur_mb_info = ps_dec->ps_nmb_info;\n                }\n                else\n                {\n                    ps_cur_mb_info = ps_dec->ps_nmb_info\n                            + ps_dec->u4_num_mbs_prev_nmb - 1;\n                }\n            }\n\n            ps_dec->u2_mby = ps_cur_mb_info->u2_mby;\n            ps_dec->u2_mbx = ps_cur_mb_info->u2_mbx;\n\n            ps_dec->u1_mb_ngbr_availablity =\n                    ps_cur_mb_info->u1_mb_ngbr_availablity;\n\n            if(u1_num_mbs)\n            {\n                // Going back 1 mb\n                ps_dec->pv_parse_tu_coeff_data = ps_dec->pv_prev_mb_parse_tu_coeff_data;\n                ps_dec->u2_cur_mb_addr--;\n                ps_dec->i4_submb_ofst -= SUB_BLK_SIZE;\n\n                // Parse/decode N-MB left unparsed\n                if (ps_dec->u1_pr_sl_type == P_SLICE\n                        || ps_dec->u1_pr_sl_type == B_SLICE)\n                {\n                    ps_dec->pf_mvpred_ref_tfr_nby2mb(ps_dec, u1_mb_idx,    u1_num_mbs);\n                    ps_dec->ps_part = ps_dec->ps_parse_part_params;\n                }\n\n                u1_num_mbs_next = i2_pic_wdin_mbs - ps_dec->u2_mbx - 1;\n                u1_end_of_row = (!u1_num_mbs_next)\n                        && (!(ps_dec->ps_cur_slice->u1_mbaff_frame_flag && (u1_num_mbs & 0x01)));\n                u1_slice_end = 1;\n                u1_tfr_n_mb = 1;\n                ps_cur_mb_info->u1_end_of_slice = u1_slice_end;\n\n                if(ps_dec->u1_separate_parse)\n                {\n                    ih264d_parse_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                            u1_num_mbs_next, u1_tfr_n_mb, u1_end_of_row);\n                    ps_dec->ps_nmb_info += u1_num_mbs;\n                }\n                else\n                {\n                    ih264d_decode_recon_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                            u1_num_mbs_next, u1_tfr_n_mb, u1_end_of_row);\n                }\n                ps_dec->u2_total_mbs_coded += u1_num_mbs;\n                ps_dec->u1_mb_idx = 0;\n                ps_dec->u4_num_mbs_cur_nmb = 0;\n            }\n\n            if(ps_dec->u2_total_mbs_coded\n                    >= ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)\n            {\n                ps_dec->u1_pic_decode_done = 1;\n                return 0;\n            }\n\n            /* Inserting new slice only if the current slice has atleast 1 MB*/\n            if(ps_dec->ps_parse_cur_slice->u4_first_mb_in_slice <\n                    (UWORD32)(ps_dec->u2_total_mbs_coded >> ps_slice->u1_mbaff_frame_flag))\n            {\n                ps_dec->i2_prev_slice_mbx = ps_dec->u2_mbx;\n                ps_dec->i2_prev_slice_mby = ps_dec->u2_mby;\n                ps_dec->u2_cur_slice_num++;\n                ps_dec->ps_parse_cur_slice++;\n            }\n\n        }\n        else\n        {\n            // Slice missing / header corrupted\n            ps_dec->ps_parse_cur_slice = ps_dec->ps_dec_slice_buf\n                                            + ps_dec->u2_cur_slice_num;\n        }\n    }\n\n    /******************************************************/\n    /* Initializations to new slice                       */\n    /******************************************************/\n    {\n        WORD32 num_entries;\n        WORD32 size;\n        UWORD8 *pu1_buf;\n\n        num_entries = MAX_FRAMES;\n        if((1 >= ps_dec->ps_cur_sps->u1_num_ref_frames) &&\n            (0 == ps_dec->i4_display_delay))\n        {\n            num_entries = 1;\n        }\n        num_entries = ((2 * num_entries) + 1);\n        num_entries *= 2;\n\n        size = num_entries * sizeof(void *);\n        size += PAD_MAP_IDX_POC * sizeof(void *);\n\n        pu1_buf = (UWORD8 *)ps_dec->pv_map_ref_idx_to_poc_buf;\n        pu1_buf += size * ps_dec->u2_cur_slice_num;\n        ps_dec->ps_parse_cur_slice->ppv_map_ref_idx_to_poc = (volatile void **)pu1_buf;\n    }\n    u1_mbaff = ps_slice->u1_mbaff_frame_flag;\n    ps_dec->ps_cur_slice->u2_first_mb_in_slice = ps_dec->u2_total_mbs_coded >> u1_mbaff;\n    ps_dec->ps_cur_slice->i1_slice_alpha_c0_offset = 0;\n    ps_dec->ps_cur_slice->i1_slice_beta_offset = 0;\n\n    if(ps_dec->ps_cur_slice->u1_field_pic_flag)\n        ps_dec->u2_prv_frame_num = ps_dec->ps_cur_slice->u2_frame_num;\n\n    ps_dec->ps_parse_cur_slice->u4_first_mb_in_slice = ps_dec->u2_total_mbs_coded >> u1_mbaff;\n    ps_dec->ps_parse_cur_slice->u2_log2Y_crwd =    ps_dec->ps_cur_slice->u2_log2Y_crwd;\n\n\n    if(ps_dec->u1_separate_parse)\n    {\n        ps_dec->ps_parse_cur_slice->pv_tu_coeff_data_start = ps_dec->pv_parse_tu_coeff_data;\n    }\n    else\n    {\n        ps_dec->pv_proc_tu_coeff_data = ps_dec->pv_parse_tu_coeff_data;\n    }\n\n    /******************************************************/\n    /* Initializations specific to P slice                */\n    /******************************************************/\n    u1_inter_mb_type = P_MB;\n    u1_deblk_mb_type = D_INTER_MB;\n\n    ps_dec->ps_cur_slice->u1_slice_type = P_SLICE;\n    ps_dec->ps_parse_cur_slice->slice_type = P_SLICE;\n    ps_dec->pf_mvpred_ref_tfr_nby2mb = ih264d_mv_pred_ref_tfr_nby2_pmb;\n    ps_dec->ps_part = ps_dec->ps_parse_part_params;\n    ps_dec->u2_mbx =\n                    (MOD(ps_dec->ps_cur_slice->u2_first_mb_in_slice - 1, ps_dec->u2_frm_wd_in_mbs));\n    ps_dec->u2_mby =\n                    (DIV(ps_dec->ps_cur_slice->u2_first_mb_in_slice - 1, ps_dec->u2_frm_wd_in_mbs));\n    ps_dec->u2_mby <<= u1_mbaff;\n\n    /******************************************************/\n    /* Parsing / decoding the slice                       */\n    /******************************************************/\n    ps_dec->u1_slice_header_done = 2;\n    ps_dec->u1_qp = ps_slice->u1_slice_qp;\n    ih264d_update_qp(ps_dec, 0);\n    u1_mb_idx = ps_dec->u1_mb_idx;\n    ps_parse_mb_data = ps_dec->ps_parse_mb_data;\n    u1_num_mbs = u1_mb_idx;\n\n    u1_slice_end = 0;\n    u1_tfr_n_mb = 0;\n    u1_decode_nmb = 0;\n    u1_num_mbsNby2 = 0;\n    i2_cur_mb_addr = ps_dec->u2_total_mbs_coded;\n    i2_mb_skip_run = num_mb_skip;\n\n    while(!u1_slice_end)\n    {\n        UWORD8 u1_mb_type;\n\n        if(i2_cur_mb_addr > ps_dec->ps_cur_sps->u2_max_mb_addr)\n            break;\n\n        ps_cur_mb_info = ps_dec->ps_nmb_info + u1_num_mbs;\n        ps_dec->u4_num_mbs_cur_nmb = u1_num_mbs;\n\n        ps_cur_mb_info->u1_Mux = 0;\n        ps_dec->u4_num_pmbair = (u1_num_mbs >> u1_mbaff);\n        ps_cur_deblk_mb = ps_dec->ps_deblk_mbn + u1_num_mbs;\n\n        ps_cur_mb_info->u1_end_of_slice = 0;\n\n        /* Storing Default partition info */\n        ps_parse_mb_data->u1_num_part = 1;\n        ps_parse_mb_data->u1_isI_mb = 0;\n\n        /**************************************************************/\n        /* Get the required information for decoding of MB            */\n        /**************************************************************/\n        /* mb_x, mb_y, neighbor availablity, */\n        if (u1_mbaff)\n            ih264d_get_mb_info_cavlc_mbaff(ps_dec, i2_cur_mb_addr, ps_cur_mb_info, i2_mb_skip_run);\n        else\n            ih264d_get_mb_info_cavlc_nonmbaff(ps_dec, i2_cur_mb_addr, ps_cur_mb_info, i2_mb_skip_run);\n\n        /* Set the deblocking parameters for this MB */\n        if(ps_dec->u4_app_disable_deblk_frm == 0)\n        {\n            ih264d_set_deblocking_parameters(ps_cur_deblk_mb, ps_slice,\n                                             ps_dec->u1_mb_ngbr_availablity,\n                                             ps_dec->u1_cur_mb_fld_dec_flag);\n        }\n\n        /* Set appropriate flags in ps_cur_mb_info and ps_dec */\n        ps_dec->i1_prev_mb_qp_delta = 0;\n        ps_dec->u1_sub_mb_num = 0;\n        ps_cur_mb_info->u1_mb_type = MB_SKIP;\n        ps_cur_mb_info->u1_mb_mc_mode = PRED_16x16;\n        ps_cur_mb_info->u1_cbp = 0;\n\n        /* Storing Skip partition info */\n        ps_part_info = ps_dec->ps_part;\n        ps_part_info->u1_is_direct = PART_DIRECT_16x16;\n        ps_part_info->u1_sub_mb_num = 0;\n        ps_dec->ps_part++;\n\n        /* Update Nnzs */\n        ih264d_update_nnz_for_skipmb(ps_dec, ps_cur_mb_info, CAVLC);\n\n        ps_cur_mb_info->ps_curmb->u1_mb_type = u1_inter_mb_type;\n        ps_cur_deblk_mb->u1_mb_type |= u1_deblk_mb_type;\n\n        i2_mb_skip_run--;\n\n        ps_cur_deblk_mb->u1_mb_qp = ps_dec->u1_qp;\n\n        if (u1_mbaff)\n        {\n            ih264d_update_mbaff_left_nnz(ps_dec, ps_cur_mb_info);\n        }\n\n        /**************************************************************/\n        /* Get next Macroblock address                                */\n        /**************************************************************/\n        i2_cur_mb_addr++;\n\n        u1_num_mbs++;\n        u1_num_mbsNby2++;\n        ps_parse_mb_data++;\n\n        /****************************************************************/\n        /* Check for End Of Row and other flags that determine when to  */\n        /* do DMA setup for N/2-Mb, Decode for N-Mb, and Transfer for   */\n        /* N-Mb                                                         */\n        /****************************************************************/\n        u1_num_mbs_next = i2_pic_wdin_mbs - ps_dec->u2_mbx - 1;\n        u1_end_of_row = (!u1_num_mbs_next) && (!(u1_mbaff && (u1_num_mbs & 0x01)));\n        u1_slice_end = !i2_mb_skip_run;\n        u1_tfr_n_mb = (u1_num_mbs == ps_dec->u1_recon_mb_grp) || u1_end_of_row\n                        || u1_slice_end;\n        u1_decode_nmb = u1_tfr_n_mb || u1_slice_end;\n        ps_cur_mb_info->u1_end_of_slice = u1_slice_end;\n\n        if(u1_decode_nmb)\n        {\n            ps_dec->pf_mvpred_ref_tfr_nby2mb(ps_dec, u1_mb_idx, u1_num_mbs);\n            u1_num_mbsNby2 = 0;\n\n            ps_parse_mb_data = ps_dec->ps_parse_mb_data;\n            ps_dec->ps_part = ps_dec->ps_parse_part_params;\n\n            if(ps_dec->u1_separate_parse)\n            {\n                ih264d_parse_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs,\n                                     u1_num_mbs_next, u1_tfr_n_mb, u1_end_of_row);\n                ps_dec->ps_nmb_info +=  u1_num_mbs;\n            }\n            else\n            {\n                ih264d_decode_recon_tfr_nmb(ps_dec, u1_mb_idx, u1_num_mbs, u1_num_mbs_next,\n                                            u1_tfr_n_mb, u1_end_of_row);\n            }\n            ps_dec->u2_total_mbs_coded += u1_num_mbs;\n            if(u1_tfr_n_mb)\n                u1_num_mbs = 0;\n            u1_mb_idx = u1_num_mbs;\n            ps_dec->u1_mb_idx = u1_num_mbs;\n        }\n    }\n\n    ps_dec->u4_num_mbs_cur_nmb = 0;\n    ps_dec->ps_cur_slice->u4_mbs_in_slice = i2_cur_mb_addr\n                        - ps_dec->ps_parse_cur_slice->u4_first_mb_in_slice;\n\n    H264_DEC_DEBUG_PRINT(\"Mbs in slice: %d\\n\", ps_dec->ps_cur_slice->u4_mbs_in_slice);\n\n\n    /* incremented here only if first slice is inserted */\n    if(ps_dec->u4_first_slice_in_pic != 0)\n    {\n        ps_dec->ps_parse_cur_slice++;\n        ps_dec->u2_cur_slice_num++;\n    }\n\n    ps_dec->i2_prev_slice_mbx = ps_dec->u2_mbx;\n    ps_dec->i2_prev_slice_mby = ps_dec->u2_mby;\n\n    if(ps_dec->u2_total_mbs_coded\n            >= ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)\n    {\n        ps_dec->u1_pic_decode_done = 1;\n    }\n\n    return 0;\n\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_decode_pslice \\endif\n *\n * \\brief\n *    Decodes a P Slice\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_parse_pslice(dec_struct_t *ps_dec, UWORD16 u2_first_mb_in_slice)\n{\n    dec_pic_params_t * ps_pps = ps_dec->ps_cur_pps;\n    dec_slice_params_t * ps_cur_slice = ps_dec->ps_cur_slice;\n    dec_bit_stream_t *ps_bitstrm = ps_dec->ps_bitstrm;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag; //ps_dec->ps_cur_sps->u1_mb_aff_flag;\n    UWORD8 u1_field_pic_flag = ps_cur_slice->u1_field_pic_flag;\n\n    UWORD64 u8_ref_idx_l0;\n    UWORD32 u4_temp;\n    WORD32 i_temp;\n    WORD32 ret;\n\n    /*--------------------------------------------------------------------*/\n    /* Read remaining contents of the slice header                        */\n    /*--------------------------------------------------------------------*/\n    {\n        WORD8 *pi1_buf;\n        WORD16 *pi2_mv = ps_dec->s_default_mv_pred.i2_mv;\n        WORD32 *pi4_mv = (WORD32*)pi2_mv;\n        WORD16 *pi16_refFrame;\n\n        pi1_buf = ps_dec->s_default_mv_pred.i1_ref_frame;\n        pi16_refFrame = (WORD16*)pi1_buf;\n        *pi4_mv = 0;\n        *(pi4_mv + 1) = 0;\n        *pi16_refFrame = OUT_OF_RANGE_REF;\n        ps_dec->s_default_mv_pred.u1_col_ref_pic_idx = (UWORD8)-1;\n        ps_dec->s_default_mv_pred.u1_pic_type = (UWORD8)-1;\n    }\n\n    ps_cur_slice->u1_num_ref_idx_active_override_flag = ih264d_get_bit_h264(\n                    ps_bitstrm);\n\n    COPYTHECONTEXT(\"SH: num_ref_idx_override_flag\",\n                    ps_cur_slice->u1_num_ref_idx_active_override_flag);\n\n    u8_ref_idx_l0 = ps_dec->ps_cur_pps->u1_num_ref_idx_lx_active[0];\n    if(ps_cur_slice->u1_num_ref_idx_active_override_flag)\n    {\n        u8_ref_idx_l0 = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf) + (UWORD64)1;\n    }\n\n    {\n        UWORD8 u1_max_ref_idx = H264_MAX_REF_PICS << u1_field_pic_flag;\n        if(u8_ref_idx_l0 > u1_max_ref_idx)\n        {\n            return ERROR_NUM_REF;\n        }\n        ps_cur_slice->u1_num_ref_idx_lx_active[0] = u8_ref_idx_l0;\n        COPYTHECONTEXT(\"SH: num_ref_idx_l0_active_minus1\",\n                        ps_cur_slice->u1_num_ref_idx_lx_active[0] - 1);\n\n    }\n\n    {\n        UWORD8 uc_refIdxReFlagL0 = ih264d_get_bit_h264(ps_bitstrm);\n        COPYTHECONTEXT(\"SH: ref_pic_list_reordering_flag_l0\",uc_refIdxReFlagL0);\n\n        ih264d_init_ref_idx_lx_p(ps_dec);\n        /* Store the value for future slices in the same picture */\n        ps_dec->u1_num_ref_idx_lx_active_prev =\n                        ps_cur_slice->u1_num_ref_idx_lx_active[0];\n\n        /* Modified temporarily */\n        if(uc_refIdxReFlagL0)\n        {\n            WORD8 ret;\n            ps_dec->ps_ref_pic_buf_lx[0] = ps_dec->ps_dpb_mgr->ps_mod_dpb[0];\n            ret = ih264d_ref_idx_reordering(ps_dec, 0);\n            if(ret == -1)\n                return ERROR_REFIDX_ORDER_T;\n            ps_dec->ps_ref_pic_buf_lx[0] = ps_dec->ps_dpb_mgr->ps_mod_dpb[0];\n        }\n        else\n            ps_dec->ps_ref_pic_buf_lx[0] =\n                            ps_dec->ps_dpb_mgr->ps_init_dpb[0];\n    }\n    /* Create refIdx to POC mapping */\n    {\n        void **pui_map_ref_idx_to_poc_lx0, **pui_map_ref_idx_to_poc_lx1;\n        WORD8 idx;\n        struct pic_buffer_t *ps_pic;\n\n        pui_map_ref_idx_to_poc_lx0 = ps_dec->ppv_map_ref_idx_to_poc + FRM_LIST_L0;\n        pui_map_ref_idx_to_poc_lx0[0] = 0; //For ref_idx = -1\n        pui_map_ref_idx_to_poc_lx0++;\n        for(idx = 0; idx < ps_cur_slice->u1_num_ref_idx_lx_active[0]; idx++)\n        {\n            ps_pic = ps_dec->ps_ref_pic_buf_lx[0][idx];\n            pui_map_ref_idx_to_poc_lx0[idx] = (ps_pic->pu1_buf1);\n        }\n\n        /* Bug Fix Deblocking */\n        pui_map_ref_idx_to_poc_lx1 = ps_dec->ppv_map_ref_idx_to_poc + FRM_LIST_L1;\n        pui_map_ref_idx_to_poc_lx1[0] = 0;\n\n        if(u1_mbaff)\n        {\n            void **ppv_map_ref_idx_to_poc_lx_t, **ppv_map_ref_idx_to_poc_lx_b;\n            void **ppv_map_ref_idx_to_poc_lx_t1, **ppv_map_ref_idx_to_poc_lx_b1;\n            ppv_map_ref_idx_to_poc_lx_t = ps_dec->ppv_map_ref_idx_to_poc\n                            + TOP_LIST_FLD_L0;\n            ppv_map_ref_idx_to_poc_lx_b = ps_dec->ppv_map_ref_idx_to_poc\n                            + BOT_LIST_FLD_L0;\n\n            ppv_map_ref_idx_to_poc_lx_t[0] = 0; //  For ref_idx = -1\n            ppv_map_ref_idx_to_poc_lx_t++;\n            ppv_map_ref_idx_to_poc_lx_b[0] = 0; // For ref_idx = -1\n            ppv_map_ref_idx_to_poc_lx_b++;\n\n            idx = 0;\n            for(idx = 0; idx < ps_cur_slice->u1_num_ref_idx_lx_active[0]; idx++)\n            {\n                ps_pic = ps_dec->ps_ref_pic_buf_lx[0][idx];\n                ppv_map_ref_idx_to_poc_lx_t[0] = (ps_pic->pu1_buf1);\n                ppv_map_ref_idx_to_poc_lx_b[1] = (ps_pic->pu1_buf1);\n\n                ppv_map_ref_idx_to_poc_lx_b[0] = (ps_pic->pu1_buf1) + 1;\n                ppv_map_ref_idx_to_poc_lx_t[1] = (ps_pic->pu1_buf1) + 1;\n\n                ppv_map_ref_idx_to_poc_lx_t += 2;\n                ppv_map_ref_idx_to_poc_lx_b += 2;\n            }\n            ppv_map_ref_idx_to_poc_lx_t1 = ps_dec->ppv_map_ref_idx_to_poc\n                            + TOP_LIST_FLD_L1;\n            ppv_map_ref_idx_to_poc_lx_t1[0] = 0;\n            ppv_map_ref_idx_to_poc_lx_b1 = ps_dec->ppv_map_ref_idx_to_poc\n                            + BOT_LIST_FLD_L1;\n            ppv_map_ref_idx_to_poc_lx_b1[0] = 0;\n\n        }\n\n        if(ps_dec->u4_num_cores >= 3)\n        {\n            WORD32 num_entries;\n            WORD32 size;\n\n            num_entries = MAX_FRAMES;\n            if((1 >= ps_dec->ps_cur_sps->u1_num_ref_frames) &&\n                (0 == ps_dec->i4_display_delay))\n            {\n                num_entries = 1;\n            }\n            num_entries = ((2 * num_entries) + 1);\n            num_entries *= 2;\n\n            size = num_entries * sizeof(void *);\n            size += PAD_MAP_IDX_POC * sizeof(void *);\n\n            memcpy((void *)ps_dec->ps_parse_cur_slice->ppv_map_ref_idx_to_poc,\n                   ps_dec->ppv_map_ref_idx_to_poc,\n                   size);\n        }\n\n\n    }\n    if(ps_pps->u1_wted_pred_flag)\n    {\n        ret = ih264d_parse_pred_weight_table(ps_cur_slice, ps_bitstrm);\n        if(ret != OK)\n            return ret;\n        ih264d_form_pred_weight_matrix(ps_dec);\n        ps_dec->pu4_wt_ofsts = ps_dec->pu4_wts_ofsts_mat;\n    }\n    else\n    {\n        ps_dec->ps_cur_slice->u2_log2Y_crwd = 0;\n        ps_dec->pu4_wt_ofsts = ps_dec->pu4_wts_ofsts_mat;\n    }\n\n    ps_dec->ps_parse_cur_slice->u2_log2Y_crwd =\n                    ps_dec->ps_cur_slice->u2_log2Y_crwd;\n\n    if(u1_mbaff && (u1_field_pic_flag == 0))\n    {\n        ih264d_convert_frm_mbaff_list(ps_dec);\n    }\n\n    /* G050 */\n    if(ps_cur_slice->u1_nal_ref_idc != 0)\n    {\n        if(!ps_dec->ps_dpb_cmds->u1_dpb_commands_read)\n        {\n            i_temp = ih264d_read_mmco_commands(ps_dec);\n            if (i_temp < 0)\n            {\n                return ERROR_DBP_MANAGER_T;\n            }\n            ps_dec->u4_bitoffset = i_temp;\n        }\n        else\n            ps_bitstrm->u4_ofst += ps_dec->u4_bitoffset;\n\n    }\n    /* G050 */\n\n    if(ps_pps->u1_entropy_coding_mode == CABAC)\n    {\n        u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n\n        if(u4_temp > MAX_CABAC_INIT_IDC)\n        {\n            return ERROR_INV_SLICE_HDR_T;\n        }\n        ps_cur_slice->u1_cabac_init_idc = u4_temp;\n        COPYTHECONTEXT(\"SH: cabac_init_idc\",ps_cur_slice->u1_cabac_init_idc);\n    }\n\n    /* Read slice_qp_delta */\n    WORD64 i8_temp = (WORD64)ps_pps->u1_pic_init_qp\n                        + ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if((i8_temp < MIN_H264_QP) || (i8_temp > MAX_H264_QP))\n    {\n        return ERROR_INV_RANGE_QP_T;\n    }\n    ps_cur_slice->u1_slice_qp = i8_temp;\n    COPYTHECONTEXT(\"SH: slice_qp_delta\",\n                    (WORD8)(ps_cur_slice->u1_slice_qp - ps_pps->u1_pic_init_qp));\n\n    if(ps_pps->u1_deblocking_filter_parameters_present_flag == 1)\n    {\n        u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        if(u4_temp > SLICE_BOUNDARY_DBLK_DISABLED)\n        {\n            return ERROR_INV_SLICE_HDR_T;\n        }\n\n        COPYTHECONTEXT(\"SH: disable_deblocking_filter_idc\", u4_temp);\n        ps_cur_slice->u1_disable_dblk_filter_idc = u4_temp;\n        if(u4_temp != 1)\n        {\n            i_temp = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf)\n                            << 1;\n            if((MIN_DBLK_FIL_OFF > i_temp) || (i_temp > MAX_DBLK_FIL_OFF))\n            {\n                return ERROR_INV_SLICE_HDR_T;\n            }\n            ps_cur_slice->i1_slice_alpha_c0_offset = i_temp;\n            COPYTHECONTEXT(\"SH: slice_alpha_c0_offset_div2\",\n                            ps_cur_slice->i1_slice_alpha_c0_offset >> 1);\n\n            i_temp = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf)\n                            << 1;\n            if((MIN_DBLK_FIL_OFF > i_temp) || (i_temp > MAX_DBLK_FIL_OFF))\n            {\n                return ERROR_INV_SLICE_HDR_T;\n            }\n            ps_cur_slice->i1_slice_beta_offset = i_temp;\n            COPYTHECONTEXT(\"SH: slice_beta_offset_div2\",\n                            ps_cur_slice->i1_slice_beta_offset >> 1);\n        }\n        else\n        {\n            ps_cur_slice->i1_slice_alpha_c0_offset = 0;\n            ps_cur_slice->i1_slice_beta_offset = 0;\n        }\n    }\n    else\n    {\n        ps_cur_slice->u1_disable_dblk_filter_idc = 0;\n        ps_cur_slice->i1_slice_alpha_c0_offset = 0;\n        ps_cur_slice->i1_slice_beta_offset = 0;\n    }\n\n    ps_dec->u1_slice_header_done = 2;\n\n    if(ps_pps->u1_entropy_coding_mode)\n    {\n        SWITCHOFFTRACE; SWITCHONTRACECABAC;\n        ps_dec->pf_parse_inter_slice = ih264d_parse_inter_slice_data_cabac;\n        ps_dec->pf_parse_inter_mb = ih264d_parse_pmb_cabac;\n        ih264d_init_cabac_contexts(P_SLICE, ps_dec);\n\n        if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag)\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cabac_mbaff;\n        else\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cabac_nonmbaff;\n    }\n    else\n    {\n        SWITCHONTRACE; SWITCHOFFTRACECABAC;\n        ps_dec->pf_parse_inter_slice = ih264d_parse_inter_slice_data_cavlc;\n        ps_dec->pf_parse_inter_mb = ih264d_parse_pmb_cavlc;\n        if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag)\n        {\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cavlc_mbaff;\n        }\n        else\n            ps_dec->pf_get_mb_info = ih264d_get_mb_info_cavlc_nonmbaff;\n    }\n\n    ps_dec->u1_B = 0;\n    ps_dec->pf_mvpred_ref_tfr_nby2mb = ih264d_mv_pred_ref_tfr_nby2_pmb;\n    ret = ps_dec->pf_parse_inter_slice(ps_dec, ps_cur_slice, u2_first_mb_in_slice);\n    if(ret != OK)\n        return ret;\n//    ps_dec->curr_slice_in_error = 0 ;\n    return OK;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_slice.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n * \\file ih264d_parse_slice.c\n *\n * \\brief\n *    Contains routines that decodes a slice NAL unit\n *\n * \\date\n *    19/12/2002\n *\n * \\author  AI\n **************************************************************************\n */\n#include <string.h>\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ithread.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_parse_mb_header.h\"\n#include \"ih264d_process_bslice.h\"\n#include \"ih264d_process_pslice.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_utils.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_mem_request.h\"\n#include \"ih264d_parse_islice.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_mvpred.h\"\n#include \"ih264d_mb_utils.h\"\n\n#include \"ih264d_defs.h\"\n#include \"ih264d_quant_scaling.h\"\n\n#include \"ih264d_inter_pred.h\"\n\n#include \"ih264d_sei.h\"\n#include \"ih264d.h\"\n#include \"ih264_error.h\"\n#include \"ih264_disp_mgr.h\"\n#include \"ih264_buf_mgr.h\"\n\n#include \"ih264d_thread_parse_decode.h\"\n#include \"ih264d_thread_compute_bs.h\"\n#include \"ih264d_dpb_manager.h\"\n#include <assert.h>\n#include \"ih264d_parse_islice.h\"\n#define RET_LAST_SKIP  0x80000000\n\nWORD32 check_app_out_buf_size(dec_struct_t *ps_dec);\n/*!\n **************************************************************************\n * \\if Function name : ih264d_form_pred_weight_matrix \\endif\n *\n * \\brief\n *    Forms pred weight matrix.\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\n\nvoid ih264d_form_pred_weight_matrix(dec_struct_t *ps_dec)\n{\n    dec_slice_params_t *ps_cur_slice;\n    UWORD8 uc_num_ref_idx_l0_active, uc_num_ref_idx_l1_active;\n    UWORD8 i, j;\n    UWORD32 *pu4_mat_iwt_ofst;\n    UWORD16 i2_idx;\n    UWORD32 *pui32_weight_offset_l0, *pui32_weight_offset_l1;\n    UWORD32 u4_temp;\n\n    ps_cur_slice = ps_dec->ps_cur_slice;\n    uc_num_ref_idx_l0_active = ps_cur_slice->u1_num_ref_idx_lx_active[0];\n    uc_num_ref_idx_l1_active = ps_cur_slice->u1_num_ref_idx_lx_active[1];\n\n    pu4_mat_iwt_ofst = ps_dec->pu4_wts_ofsts_mat;\n\n    if(ps_cur_slice->u1_slice_type == B_SLICE)\n    {\n        for(i = 0; i < uc_num_ref_idx_l0_active; i++)\n        {\n            pui32_weight_offset_l0 = ps_cur_slice->u4_wt_ofst_lx[0][i];\n            for(j = 0; j < uc_num_ref_idx_l1_active; j++)\n            {\n                pui32_weight_offset_l1 = ps_cur_slice->u4_wt_ofst_lx[1][j];\n                i2_idx = i * uc_num_ref_idx_l0_active + j;\n                i2_idx = X3(i2_idx);\n                /*        u4_temp = (pui32_weight_offset_l0[0] | (pui32_weight_offset_l1[0] << 16));\n                 pu4_mat_iwt_ofst[0] = u4_temp;\n                 u4_temp = (pui32_weight_offset_l0[1] | (pui32_weight_offset_l1[1] << 16));\n                 pu4_mat_iwt_ofst[1] = u4_temp;\n                 u4_temp = (pui32_weight_offset_l0[2] | (pui32_weight_offset_l1[2] << 16));\n                 pu4_mat_iwt_ofst[2] = u4_temp;\n                 pu4_mat_iwt_ofst += 3;*/\n                pu4_mat_iwt_ofst[0] = pui32_weight_offset_l0[0];\n                pu4_mat_iwt_ofst[1] = pui32_weight_offset_l1[0];\n                pu4_mat_iwt_ofst[2] = pui32_weight_offset_l0[1];\n                pu4_mat_iwt_ofst[3] = pui32_weight_offset_l1[1];\n                pu4_mat_iwt_ofst[4] = pui32_weight_offset_l0[2];\n                pu4_mat_iwt_ofst[5] = pui32_weight_offset_l1[2];\n                pu4_mat_iwt_ofst += 6;\n            }\n        }\n    }\n    else\n    {\n        for(i = 0; i < uc_num_ref_idx_l0_active; i++)\n        {\n            pui32_weight_offset_l0 = ps_cur_slice->u4_wt_ofst_lx[0][i];\n            i2_idx = X3(i);\n            u4_temp = (UWORD32)pui32_weight_offset_l0[0];\n            pu4_mat_iwt_ofst[0] = u4_temp;\n            u4_temp = (UWORD32)pui32_weight_offset_l0[1];\n            pu4_mat_iwt_ofst[2] = u4_temp;\n            u4_temp = (UWORD32)pui32_weight_offset_l0[2];\n            pu4_mat_iwt_ofst[4] = u4_temp;\n            pu4_mat_iwt_ofst += 6;\n        }\n    }\n}\n\n\n/*!\n **************************************************************************\n * \\if Function name :  init_firstSliceParam \\endif\n *\n * \\brief\n *    Initialize the Parameter required for all the slices for a picture\n *\n * \\return           : Nothing\n *\n **************************************************************************\n */\n\nWORD32 ih264d_start_of_pic(dec_struct_t *ps_dec,\n                         WORD32 i4_poc,\n                         pocstruct_t *ps_temp_poc,\n                         UWORD16 u2_frame_num,\n                         dec_pic_params_t *ps_pps)\n{\n    pocstruct_t *ps_prev_poc = &ps_dec->s_cur_pic_poc;\n    pocstruct_t *ps_cur_poc = ps_temp_poc;\n\n    pic_buffer_t *pic_buf;\n\n    ivd_video_decode_op_t * ps_dec_output =\n                    (ivd_video_decode_op_t *)ps_dec->pv_dec_out;\n    dec_slice_params_t *ps_cur_slice = ps_dec->ps_cur_slice;\n    dec_seq_params_t *ps_seq = ps_pps->ps_sps;\n    UWORD8 u1_bottom_field_flag = ps_cur_slice->u1_bottom_field_flag;\n    UWORD8 u1_field_pic_flag = ps_cur_slice->u1_field_pic_flag;\n    /* high profile related declarations */\n    high_profile_tools_t s_high_profile;\n    WORD32 ret;\n\n    H264_MUTEX_LOCK(&ps_dec->process_disp_mutex);\n\n    /* check output buffer size given by the application */\n    if(check_app_out_buf_size(ps_dec) != IV_SUCCESS)\n        return IVD_DISP_FRM_ZERO_OP_BUF_SIZE;\n\n    ps_prev_poc->i4_pic_order_cnt_lsb = ps_cur_poc->i4_pic_order_cnt_lsb;\n    ps_prev_poc->i4_pic_order_cnt_msb = ps_cur_poc->i4_pic_order_cnt_msb;\n    ps_prev_poc->i4_delta_pic_order_cnt_bottom =\n                    ps_cur_poc->i4_delta_pic_order_cnt_bottom;\n    ps_prev_poc->i4_delta_pic_order_cnt[0] =\n                    ps_cur_poc->i4_delta_pic_order_cnt[0];\n    ps_prev_poc->i4_delta_pic_order_cnt[1] =\n                    ps_cur_poc->i4_delta_pic_order_cnt[1];\n    ps_prev_poc->u1_bot_field = ps_dec->ps_cur_slice->u1_bottom_field_flag;\n    ps_prev_poc->i4_prev_frame_num_ofst = ps_cur_poc->i4_prev_frame_num_ofst;\n    ps_prev_poc->u2_frame_num = u2_frame_num;\n    ps_dec->i1_prev_mb_qp_delta = 0;\n    ps_dec->i1_next_ctxt_idx = 0;\n\n\n    ps_dec->u4_nmb_deblk = 0;\n    if(ps_dec->u4_num_cores == 1)\n       ps_dec->u4_nmb_deblk = 1;\n\n\n\n    if(ps_seq->u1_mb_aff_flag == 1)\n    {\n        ps_dec->u4_nmb_deblk = 0;\n        if(ps_dec->u4_num_cores > 2)\n            ps_dec->u4_num_cores = 2;\n    }\n\n        ps_dec->u4_use_intrapred_line_copy = 0;\n\n\n\n    if (ps_seq->u1_mb_aff_flag == 0)\n    {\n        ps_dec->u4_use_intrapred_line_copy = 1;\n    }\n\n    ps_dec->u4_app_disable_deblk_frm = 0;\n    /* If degrade is enabled, set the degrade flags appropriately */\n    if(ps_dec->i4_degrade_type && ps_dec->i4_degrade_pics)\n    {\n        WORD32 degrade_pic;\n        ps_dec->i4_degrade_pic_cnt++;\n        degrade_pic = 0;\n\n        /* If degrade is to be done in all frames, then do not check further */\n        switch(ps_dec->i4_degrade_pics)\n        {\n            case 4:\n            {\n                degrade_pic = 1;\n                break;\n            }\n            case 3:\n            {\n                if(ps_cur_slice->u1_slice_type != I_SLICE)\n                    degrade_pic = 1;\n\n                break;\n            }\n            case 2:\n            {\n\n                /* If pic count hits non-degrade interval or it is an islice, then do not degrade */\n                if((ps_cur_slice->u1_slice_type != I_SLICE)\n                                && (ps_dec->i4_degrade_pic_cnt\n                                                != ps_dec->i4_nondegrade_interval))\n                    degrade_pic = 1;\n\n                break;\n            }\n            case 1:\n            {\n                /* Check if the current picture is non-ref */\n                if(0 == ps_cur_slice->u1_nal_ref_idc)\n                {\n                    degrade_pic = 1;\n                }\n                break;\n            }\n\n        }\n        if(degrade_pic)\n        {\n            if(ps_dec->i4_degrade_type & 0x2)\n                ps_dec->u4_app_disable_deblk_frm = 1;\n\n            /* MC degrading is done only for non-ref pictures */\n            if(0 == ps_cur_slice->u1_nal_ref_idc)\n            {\n                if(ps_dec->i4_degrade_type & 0x4)\n                    ps_dec->i4_mv_frac_mask = 0;\n\n                if(ps_dec->i4_degrade_type & 0x8)\n                    ps_dec->i4_mv_frac_mask = 0;\n            }\n        }\n        else\n            ps_dec->i4_degrade_pic_cnt = 0;\n    }\n\n    {\n        dec_err_status_t * ps_err = ps_dec->ps_dec_err_status;\n        if((ps_cur_slice->u1_slice_type == I_SLICE)\n                        || (ps_cur_slice->u1_slice_type == SI_SLICE))\n            ps_err->u1_cur_pic_type = PIC_TYPE_I;\n        else\n            ps_err->u1_cur_pic_type = PIC_TYPE_UNKNOWN;\n\n        if(ps_err->u1_pic_aud_i == PIC_TYPE_I)\n        {\n            ps_err->u1_cur_pic_type = PIC_TYPE_I;\n            ps_err->u1_pic_aud_i = PIC_TYPE_UNKNOWN;\n        }\n\n        if(ps_cur_slice->u1_nal_unit_type == IDR_SLICE_NAL)\n        {\n            if(ps_err->u1_err_flag)\n                ih264d_reset_ref_bufs(ps_dec->ps_dpb_mgr);\n            ps_err->u1_err_flag = ACCEPT_ALL_PICS;\n        }\n    }\n\n    if(ps_dec->u1_init_dec_flag && ps_dec->s_prev_seq_params.u1_eoseq_pending)\n    {\n        /* Reset the decoder picture buffers */\n        WORD32 j;\n        for(j = 0; j < MAX_DISP_BUFS_NEW; j++)\n        {\n\n            ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                  j,\n                                  BUF_MGR_REF);\n            ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_mv_buf_mgr,\n                                  ps_dec->au1_pic_buf_id_mv_buf_id_map[j],\n                                  BUF_MGR_REF);\n            ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                  j,\n                                  BUF_MGR_IO);\n        }\n\n        /* reset the decoder structure parameters related to buffer handling */\n        ps_dec->u1_second_field = 0;\n        ps_dec->i4_cur_display_seq = 0;\n\n        /********************************************************************/\n        /* indicate in the decoder output i4_status that some frames are being */\n        /* dropped, so that it resets timestamp and wait for a new sequence */\n        /********************************************************************/\n\n        ps_dec->s_prev_seq_params.u1_eoseq_pending = 0;\n    }\n    ret = ih264d_init_pic(ps_dec, u2_frame_num, i4_poc, ps_pps);\n    if(ret != OK)\n        return ret;\n\n    ps_dec->pv_parse_tu_coeff_data = ps_dec->pv_pic_tu_coeff_data;\n    ps_dec->pv_proc_tu_coeff_data  = ps_dec->pv_pic_tu_coeff_data;\n    ps_dec->ps_nmb_info = ps_dec->ps_frm_mb_info;\n    if(ps_dec->u1_separate_parse)\n    {\n        UWORD16 pic_wd;\n        UWORD16 pic_ht;\n        UWORD32 num_mbs;\n\n        pic_wd = ps_dec->u2_pic_wd;\n        pic_ht = ps_dec->u2_pic_ht;\n        num_mbs = (pic_wd * pic_ht) >> 8;\n\n        if(ps_dec->pu1_dec_mb_map)\n        {\n            memset((void *)ps_dec->pu1_dec_mb_map, 0, num_mbs);\n        }\n\n        if(ps_dec->pu1_recon_mb_map)\n        {\n\n            memset((void *)ps_dec->pu1_recon_mb_map, 0, num_mbs);\n        }\n\n        if(ps_dec->pu2_slice_num_map)\n        {\n            memset((void *)ps_dec->pu2_slice_num_map, 0,\n                   (num_mbs * sizeof(UWORD16)));\n        }\n\n    }\n\n    ps_dec->ps_parse_cur_slice = &(ps_dec->ps_dec_slice_buf[0]);\n    ps_dec->ps_decode_cur_slice = &(ps_dec->ps_dec_slice_buf[0]);\n    ps_dec->ps_computebs_cur_slice = &(ps_dec->ps_dec_slice_buf[0]);\n    ps_dec->u2_cur_slice_num = 0;\n\n    /* Initialize all the HP toolsets to zero */\n    ps_dec->s_high_profile.u1_scaling_present = 0;\n    ps_dec->s_high_profile.u1_transform8x8_present = 0;\n\n    /* Get Next Free Picture */\n    if(1 == ps_dec->u4_share_disp_buf)\n    {\n        UWORD32 i;\n        /* Free any buffer that is in the queue to be freed */\n        for(i = 0; i < MAX_DISP_BUFS_NEW; i++)\n        {\n            if(0 == ps_dec->u4_disp_buf_to_be_freed[i])\n                continue;\n            ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr, i,\n            BUF_MGR_IO);\n            ps_dec->u4_disp_buf_to_be_freed[i] = 0;\n            ps_dec->u4_disp_buf_mapping[i] = 0;\n\n        }\n    }\n    if(!(u1_field_pic_flag && 0 != ps_dec->u1_top_bottom_decoded)) //ps_dec->u1_second_field))\n    {\n        pic_buffer_t *ps_cur_pic;\n        WORD32 cur_pic_buf_id, cur_mv_buf_id;\n        col_mv_buf_t *ps_col_mv;\n        while(1)\n        {\n            ps_cur_pic = (pic_buffer_t *)ih264_buf_mgr_get_next_free(\n                            (buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                            &cur_pic_buf_id);\n            if(ps_cur_pic == NULL)\n            {\n                ps_dec->i4_error_code = ERROR_UNAVAIL_PICBUF_T;\n                return ERROR_UNAVAIL_PICBUF_T;\n            }\n            if(0 == ps_dec->u4_disp_buf_mapping[cur_pic_buf_id])\n            {\n                break;\n            }\n\n        }\n        ps_col_mv = (col_mv_buf_t *)ih264_buf_mgr_get_next_free((buf_mgr_t *)ps_dec->pv_mv_buf_mgr,\n                                                               &cur_mv_buf_id);\n        if(ps_col_mv == NULL)\n        {\n            ps_dec->i4_error_code = ERROR_UNAVAIL_MVBUF_T;\n            return ERROR_UNAVAIL_MVBUF_T;\n        }\n\n        ps_dec->ps_cur_pic = ps_cur_pic;\n        ps_dec->u1_pic_buf_id = cur_pic_buf_id;\n        ps_cur_pic->u4_ts = ps_dec->u4_ts;\n        memcpy(&ps_cur_pic->s_sei_pic, ps_dec->ps_sei, sizeof(sei));\n\n        ps_cur_pic->u1_mv_buf_id = cur_mv_buf_id;\n        ps_dec->au1_pic_buf_id_mv_buf_id_map[cur_pic_buf_id] = cur_mv_buf_id;\n\n        ps_cur_pic->pu1_col_zero_flag = (UWORD8 *)ps_col_mv->pv_col_zero_flag;\n        ps_cur_pic->ps_mv = (mv_pred_t *)ps_col_mv->pv_mv;\n        ps_dec->au1_pic_buf_ref_flag[cur_pic_buf_id] = 0;\n\n        {\n            /*make first entry of list0 and list1 point to cur pic,\n             *so that if first slice is in error, ref pic struct will have valid entries*/\n            ps_dec->ps_ref_pic_buf_lx[0] = ps_dec->ps_dpb_mgr->ps_init_dpb[0];\n            ps_dec->ps_ref_pic_buf_lx[1] = ps_dec->ps_dpb_mgr->ps_init_dpb[1];\n            *(ps_dec->ps_dpb_mgr->ps_init_dpb[0][0]) = *ps_cur_pic;\n            /* Initialize for field reference as well */\n            *(ps_dec->ps_dpb_mgr->ps_init_dpb[0][MAX_REF_BUFS]) = *ps_cur_pic;\n\n            *(ps_dec->ps_dpb_mgr->ps_mod_dpb[0][0]) = *ps_cur_pic;\n            /* Initialize for field reference as well */\n            *(ps_dec->ps_dpb_mgr->ps_mod_dpb[0][MAX_REF_BUFS]) = *ps_cur_pic;\n            *(ps_dec->ps_dpb_mgr->ps_init_dpb[1][0]) = *ps_cur_pic;\n            /* Initialize for field reference as well */\n            *(ps_dec->ps_dpb_mgr->ps_init_dpb[1][MAX_REF_BUFS]) = *ps_cur_pic;\n            *(ps_dec->ps_dpb_mgr->ps_mod_dpb[1][0]) = *ps_cur_pic;\n            /* Initialize for field reference as well */\n            *(ps_dec->ps_dpb_mgr->ps_mod_dpb[1][MAX_REF_BUFS]) = *ps_cur_pic;\n        }\n\n        if(!ps_dec->ps_cur_pic)\n        {\n            WORD32 j;\n            H264_DEC_DEBUG_PRINT(\"------- Display Buffers Reset --------\\n\");\n            for(j = 0; j < MAX_DISP_BUFS_NEW; j++)\n            {\n\n                ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                      j,\n                                      BUF_MGR_REF);\n                ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_mv_buf_mgr,\n                                      ps_dec->au1_pic_buf_id_mv_buf_id_map[j],\n                                      BUF_MGR_REF);\n                ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                      j,\n                                      BUF_MGR_IO);\n            }\n\n            ps_dec->i4_cur_display_seq = 0;\n            ps_dec->i4_prev_max_display_seq = 0;\n            ps_dec->i4_max_poc = 0;\n\n            ps_cur_pic = (pic_buffer_t *)ih264_buf_mgr_get_next_free(\n                            (buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                            &cur_pic_buf_id);\n            if(ps_cur_pic == NULL)\n            {\n                ps_dec->i4_error_code = ERROR_UNAVAIL_PICBUF_T;\n                return ERROR_UNAVAIL_PICBUF_T;\n            }\n\n            ps_col_mv = (col_mv_buf_t *)ih264_buf_mgr_get_next_free((buf_mgr_t *)ps_dec->pv_mv_buf_mgr,\n                                                                   &cur_mv_buf_id);\n            if(ps_col_mv == NULL)\n            {\n                ps_dec->i4_error_code = ERROR_UNAVAIL_MVBUF_T;\n                return ERROR_UNAVAIL_MVBUF_T;\n            }\n\n            ps_dec->ps_cur_pic = ps_cur_pic;\n            ps_dec->u1_pic_buf_id = cur_pic_buf_id;\n            ps_cur_pic->u4_ts = ps_dec->u4_ts;\n            ps_dec->apv_buf_id_pic_buf_map[cur_pic_buf_id] = (void *)ps_cur_pic;\n\n            ps_cur_pic->u1_mv_buf_id = cur_mv_buf_id;\n            ps_dec->au1_pic_buf_id_mv_buf_id_map[cur_pic_buf_id] = cur_mv_buf_id;\n\n            ps_cur_pic->pu1_col_zero_flag = (UWORD8 *)ps_col_mv->pv_col_zero_flag;\n            ps_cur_pic->ps_mv = (mv_pred_t *)ps_col_mv->pv_mv;\n            ps_dec->au1_pic_buf_ref_flag[cur_pic_buf_id] = 0;\n\n        }\n\n        ps_dec->ps_cur_pic->u1_picturetype = u1_field_pic_flag;\n        ps_dec->ps_cur_pic->u4_pack_slc_typ = SKIP_NONE;\n        H264_DEC_DEBUG_PRINT(\"got a buffer\\n\");\n    }\n    else\n    {\n        H264_DEC_DEBUG_PRINT(\"did not get a buffer\\n\");\n    }\n\n    ps_dec->u4_pic_buf_got = 1;\n\n    ps_dec->ps_cur_pic->i4_poc = i4_poc;\n    ps_dec->ps_cur_pic->i4_frame_num = u2_frame_num;\n    ps_dec->ps_cur_pic->i4_pic_num = u2_frame_num;\n    ps_dec->ps_cur_pic->i4_top_field_order_cnt = ps_pps->i4_top_field_order_cnt;\n    ps_dec->ps_cur_pic->i4_bottom_field_order_cnt =\n                    ps_pps->i4_bottom_field_order_cnt;\n    ps_dec->ps_cur_pic->i4_avg_poc = ps_pps->i4_avg_poc;\n    ps_dec->ps_cur_pic->u4_time_stamp = ps_dec->u4_pts;\n\n    ps_dec->s_cur_pic = *(ps_dec->ps_cur_pic);\n    if(u1_field_pic_flag && u1_bottom_field_flag)\n    {\n        WORD32 i4_temp_poc;\n        WORD32 i4_top_field_order_poc, i4_bot_field_order_poc;\n        /* Point to odd lines, since it's bottom field */\n        ps_dec->s_cur_pic.pu1_buf1 += ps_dec->s_cur_pic.u2_frm_wd_y;\n        ps_dec->s_cur_pic.pu1_buf2 += ps_dec->s_cur_pic.u2_frm_wd_uv;\n        ps_dec->s_cur_pic.pu1_buf3 += ps_dec->s_cur_pic.u2_frm_wd_uv;\n        ps_dec->s_cur_pic.ps_mv +=\n                        ((ps_dec->u2_pic_ht * ps_dec->u2_pic_wd) >> 5);\n        ps_dec->s_cur_pic.pu1_col_zero_flag += ((ps_dec->u2_pic_ht\n                        * ps_dec->u2_pic_wd) >> 5);\n        ps_dec->ps_cur_pic->u1_picturetype |= BOT_FLD;\n        i4_top_field_order_poc = ps_dec->ps_cur_pic->i4_top_field_order_cnt;\n        i4_bot_field_order_poc = ps_dec->ps_cur_pic->i4_bottom_field_order_cnt;\n        i4_temp_poc = MIN(i4_top_field_order_poc,\n                                 i4_bot_field_order_poc);\n        ps_dec->ps_cur_pic->i4_avg_poc = i4_temp_poc;\n    }\n\n    ps_cur_slice->u1_mbaff_frame_flag = ps_seq->u1_mb_aff_flag\n                    && (!u1_field_pic_flag);\n\n    ps_dec->ps_cur_pic->u1_picturetype |= (ps_cur_slice->u1_mbaff_frame_flag\n                    << 2);\n\n    ps_dec->ps_cur_mb_row = ps_dec->ps_nbr_mb_row; //[0];\n    //Increment by 2 ,so that left mb (mbaff decrements by 2)  will always be valid\n    ps_dec->ps_cur_mb_row += 2;\n    ps_dec->ps_top_mb_row = ps_dec->ps_nbr_mb_row;\n    ps_dec->ps_top_mb_row += ((ps_dec->u2_frm_wd_in_mbs + 2) << (1 - ps_dec->ps_cur_sps->u1_frame_mbs_only_flag));\n    //Increment by 2 ,so that left mb (mbaff decrements by 2)  will always be valid\n    ps_dec->ps_top_mb_row += 2;\n\n    /* CHANGED CODE */\n    ps_dec->ps_mv_cur = ps_dec->s_cur_pic.ps_mv;\n    ps_dec->ps_mv_top = ps_dec->ps_mv_top_p[0];\n    /* CHANGED CODE */\n    ps_dec->u1_mv_top_p = 0;\n    ps_dec->u1_mb_idx = 0;\n    /* CHANGED CODE */\n    ps_dec->ps_mv_left = ps_dec->s_cur_pic.ps_mv;\n    ps_dec->u2_total_mbs_coded = 0;\n    ps_dec->i4_submb_ofst = -(SUB_BLK_SIZE);\n    ps_dec->u4_pred_info_idx = 0;\n    ps_dec->u4_pred_info_pkd_idx = 0;\n    ps_dec->u4_dma_buf_idx = 0;\n    ps_dec->ps_mv = ps_dec->s_cur_pic.ps_mv;\n    ps_dec->ps_mv_bank_cur = ps_dec->s_cur_pic.ps_mv;\n    ps_dec->pu1_col_zero_flag = ps_dec->s_cur_pic.pu1_col_zero_flag;\n    ps_dec->ps_part = ps_dec->ps_parse_part_params;\n    ps_dec->i2_prev_slice_mbx = -1;\n    ps_dec->i2_prev_slice_mby = 0;\n    ps_dec->u2_mv_2mb[0] = 0;\n    ps_dec->u2_mv_2mb[1] = 0;\n    ps_dec->u1_last_pic_not_decoded = 0;\n\n    ps_dec->u2_cur_slice_num_dec_thread = 0;\n    ps_dec->u2_cur_slice_num_bs = 0;\n    ps_dec->u4_intra_pred_line_ofst = 0;\n    ps_dec->pu1_cur_y_intra_pred_line = ps_dec->pu1_y_intra_pred_line;\n    ps_dec->pu1_cur_u_intra_pred_line = ps_dec->pu1_u_intra_pred_line;\n    ps_dec->pu1_cur_v_intra_pred_line = ps_dec->pu1_v_intra_pred_line;\n\n    ps_dec->pu1_cur_y_intra_pred_line_base = ps_dec->pu1_y_intra_pred_line;\n    ps_dec->pu1_cur_u_intra_pred_line_base = ps_dec->pu1_u_intra_pred_line;\n    ps_dec->pu1_cur_v_intra_pred_line_base = ps_dec->pu1_v_intra_pred_line;\n\n\n\n\n\n    ps_dec->pu1_prev_y_intra_pred_line = ps_dec->pu1_y_intra_pred_line\n                    + (ps_dec->u2_frm_wd_in_mbs * MB_SIZE);\n\n    ps_dec->pu1_prev_u_intra_pred_line = ps_dec->pu1_u_intra_pred_line\n                    + ps_dec->u2_frm_wd_in_mbs * BLK8x8SIZE * YUV420SP_FACTOR;\n    ps_dec->pu1_prev_v_intra_pred_line = ps_dec->pu1_v_intra_pred_line\n                    + ps_dec->u2_frm_wd_in_mbs * BLK8x8SIZE;\n\n    ps_dec->ps_deblk_mbn = ps_dec->ps_deblk_pic;\n    /* Initialize The Function Pointer Depending Upon the Entropy and MbAff Flag */\n    {\n        if(ps_cur_slice->u1_mbaff_frame_flag)\n        {\n            ps_dec->pf_compute_bs = ih264d_compute_bs_mbaff;\n            ps_dec->pf_mvpred = ih264d_mvpred_mbaff;\n        }\n        else\n        {\n            ps_dec->pf_compute_bs = ih264d_compute_bs_non_mbaff;\n            ps_dec->u1_cur_mb_fld_dec_flag = ps_cur_slice->u1_field_pic_flag;\n        }\n    }\n    /* Set up the Parameter for DMA transfer */\n    {\n        UWORD8 u1_field_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag;\n\n        UWORD8 u1_mbaff = ps_cur_slice->u1_mbaff_frame_flag;\n\n        UWORD8 uc_lastmbs = (((ps_dec->u2_pic_wd) >> 4)\n                        % (ps_dec->u1_recon_mb_grp >> u1_mbaff));\n        UWORD16 ui16_lastmbs_widthY =\n                        (uc_lastmbs ? (uc_lastmbs << 4) : ((ps_dec->u1_recon_mb_grp\n                                        >> u1_mbaff) << 4));\n        UWORD16 ui16_lastmbs_widthUV =\n                        uc_lastmbs ? (uc_lastmbs << 3) : ((ps_dec->u1_recon_mb_grp\n                                        >> u1_mbaff) << 3);\n\n        ps_dec->s_tran_addrecon.pu1_dest_y = ps_dec->s_cur_pic.pu1_buf1;\n        ps_dec->s_tran_addrecon.pu1_dest_u = ps_dec->s_cur_pic.pu1_buf2;\n        ps_dec->s_tran_addrecon.pu1_dest_v = ps_dec->s_cur_pic.pu1_buf3;\n\n        ps_dec->s_tran_addrecon.u2_frm_wd_y = ps_dec->u2_frm_wd_y\n                        << u1_field_pic_flag;\n        ps_dec->s_tran_addrecon.u2_frm_wd_uv = ps_dec->u2_frm_wd_uv\n                        << u1_field_pic_flag;\n\n        if(u1_field_pic_flag)\n        {\n            ui16_lastmbs_widthY += ps_dec->u2_frm_wd_y;\n            ui16_lastmbs_widthUV += ps_dec->u2_frm_wd_uv;\n        }\n\n        /* Normal Increment of Pointer */\n        ps_dec->s_tran_addrecon.u4_inc_y[0] = ((ps_dec->u1_recon_mb_grp << 4)\n                        >> u1_mbaff);\n        ps_dec->s_tran_addrecon.u4_inc_uv[0] = ((ps_dec->u1_recon_mb_grp << 4)\n                        >> u1_mbaff);\n\n        /* End of Row Increment */\n        ps_dec->s_tran_addrecon.u4_inc_y[1] = (ui16_lastmbs_widthY\n                        + (PAD_LEN_Y_H << 1)\n                        + ps_dec->s_tran_addrecon.u2_frm_wd_y\n                                        * ((15 << u1_mbaff) + u1_mbaff));\n        ps_dec->s_tran_addrecon.u4_inc_uv[1] = (ui16_lastmbs_widthUV\n                        + (PAD_LEN_UV_H << 2)\n                        + ps_dec->s_tran_addrecon.u2_frm_wd_uv\n                                        * ((15 << u1_mbaff) + u1_mbaff));\n\n        /* Assign picture numbers to each frame/field  */\n        /* only once per picture.                      */\n        ih264d_assign_pic_num(ps_dec);\n        ps_dec->s_tran_addrecon.u2_mv_top_left_inc = (ps_dec->u1_recon_mb_grp\n                        << 2) - 1 - (u1_mbaff << 2);\n        ps_dec->s_tran_addrecon.u2_mv_left_inc = ((ps_dec->u1_recon_mb_grp\n                        >> u1_mbaff) - 1) << (4 + u1_mbaff);\n    }\n    /**********************************************************************/\n    /* High profile related initialization at pictrue level               */\n    /**********************************************************************/\n    if(ps_seq->u1_profile_idc == HIGH_PROFILE_IDC)\n    {\n        if((ps_seq->i4_seq_scaling_matrix_present_flag)\n                        || (ps_pps->i4_pic_scaling_matrix_present_flag))\n        {\n            ret = ih264d_form_scaling_matrix_picture(ps_seq, ps_pps, ps_dec);\n            ps_dec->s_high_profile.u1_scaling_present = 1;\n        }\n        else\n        {\n            ret = ih264d_form_default_scaling_matrix(ps_dec);\n        }\n\n        if(ps_pps->i4_transform_8x8_mode_flag)\n        {\n            ps_dec->s_high_profile.u1_transform8x8_present = 1;\n        }\n    }\n    else\n    {\n        ret = ih264d_form_default_scaling_matrix(ps_dec);\n    }\n    \n    if(ret != OK)\n        return ret;\n \n    /* required while reading the transform_size_8x8 u4_flag */\n    ps_dec->s_high_profile.u1_direct_8x8_inference_flag =\n                    ps_seq->u1_direct_8x8_inference_flag;\n    ps_dec->s_high_profile.s_cavlc_ctxt = ps_dec->s_cavlc_ctxt;\n\n    ps_dec->i1_recon_in_thread3_flag = 1;\n    ps_dec->ps_frame_buf_ip_recon = &ps_dec->s_tran_addrecon;\n    if(ps_dec->u1_separate_parse)\n    {\n        memcpy(&ps_dec->s_tran_addrecon_parse, &ps_dec->s_tran_addrecon,\n               sizeof(tfr_ctxt_t));\n        if(ps_dec->u4_num_cores >= 3 && ps_dec->i1_recon_in_thread3_flag)\n        {\n            memcpy(&ps_dec->s_tran_iprecon, &ps_dec->s_tran_addrecon,\n                   sizeof(tfr_ctxt_t));\n            ps_dec->ps_frame_buf_ip_recon = &ps_dec->s_tran_iprecon;\n        }\n    }\n\n\n    ih264d_init_deblk_tfr_ctxt(ps_dec,&(ps_dec->s_pad_mgr), &(ps_dec->s_tran_addrecon),\n                               ps_dec->u2_frm_wd_in_mbs, 0);\n\n    ps_dec->ps_cur_deblk_mb = ps_dec->ps_deblk_pic;\n    ps_dec->u4_cur_deblk_mb_num = 0;\n\n    ps_dec->u4_deblk_mb_x = 0;\n    ps_dec->u4_deblk_mb_y = 0;\n    ps_dec->pu4_wt_ofsts = ps_dec->pu4_wts_ofsts_mat;\n\n    ps_dec->u4_first_slice_in_pic = 0;\n    H264_MUTEX_UNLOCK(&ps_dec->process_disp_mutex);\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name :  ih264d_deblock_display \\endif\n *\n * \\brief            :  The function callls the deblocking routine and manages\n :  the Recon buffers and displays .\n * \\return           :  Nothing\n *\n **************************************************************************\n */\nWORD32 ih264d_end_of_pic_dispbuf_mgr(dec_struct_t * ps_dec)\n{\n    dec_slice_params_t *ps_cur_slice = ps_dec->ps_cur_slice;\n    UWORD8 u1_num_of_users = 0;\n    WORD32 ret;\n\n    H264_MUTEX_LOCK(&ps_dec->process_disp_mutex);\n    if(1)\n    {\n\n        {\n            ih264d_delete_nonref_nondisplay_pics(ps_dec->ps_dpb_mgr);\n            if(ps_cur_slice->u1_mmco_equalto5\n                            || (ps_cur_slice->u1_nal_unit_type == IDR_SLICE_NAL))\n            {\n                ps_dec->ps_cur_pic->i4_poc = 0;\n                if(ps_dec->u2_total_mbs_coded\n                                == (ps_dec->ps_cur_sps->u2_max_mb_addr + 1))\n                    ih264d_reset_ref_bufs(ps_dec->ps_dpb_mgr);\n                ih264d_release_display_bufs(ps_dec);\n            }\n            if(IVD_DECODE_FRAME_OUT != ps_dec->e_frm_out_mode)\n            {\n                ret = ih264d_assign_display_seq(ps_dec);\n                if(ret != OK)\n                    return ret;\n            }\n        }\n\n        if(ps_cur_slice->u1_nal_ref_idc)\n        {\n            /* Mark pic buf as needed for reference */\n            ih264_buf_mgr_set_status((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                     ps_dec->u1_pic_buf_id,\n                                     BUF_MGR_REF);\n            /* Mark mv buf as needed for reference */\n            ih264_buf_mgr_set_status((buf_mgr_t *)ps_dec->pv_mv_buf_mgr,\n                                     ps_dec->au1_pic_buf_id_mv_buf_id_map[ps_dec->u1_pic_buf_id],\n                                     BUF_MGR_REF);\n            ps_dec->au1_pic_buf_ref_flag[ps_dec->u1_pic_buf_id] = 1;\n        }\n\n        /* 420 consumer */\n        /* Increment the number of users by 1 for display based upon */\n        /*the SEEK KEY FRAME control sent to decoder                 */\n        if(((0 == ps_dec->u1_last_pic_not_decoded)\n                        && (0\n                                        == (ps_dec->ps_cur_pic->u4_pack_slc_typ\n                                                        & ps_dec->u4_skip_frm_mask)))\n                        || (ps_cur_slice->u1_nal_unit_type == IDR_SLICE_NAL))\n        {\n            /* Mark pic buf as needed for display */\n            ih264_buf_mgr_set_status((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                     ps_dec->u1_pic_buf_id,\n                                     BUF_MGR_IO);\n\n        }\n\n        if(!ps_cur_slice->u1_field_pic_flag\n                        || ((TOP_FIELD_ONLY | BOT_FIELD_ONLY)\n                                        != ps_dec->u1_top_bottom_decoded))\n        {\n            pic_buffer_t *ps_cur_pic = ps_dec->ps_cur_pic;\n            ps_cur_pic->u2_disp_width = ps_dec->u2_disp_width;\n            ps_cur_pic->u2_disp_height = ps_dec->u2_disp_height >> 1;\n\n            ps_cur_pic->u2_crop_offset_y = ps_dec->u2_crop_offset_y;\n            ps_cur_pic->u2_crop_offset_uv = ps_dec->u2_crop_offset_uv;\n            ps_cur_pic->u1_pic_type = 0;\n            {\n                WORD64 i8_display_poc;\n                i8_display_poc = (WORD64)ps_dec->i4_prev_max_display_seq +\n                            ps_dec->ps_cur_pic->i4_poc;\n                if(IS_OUT_OF_RANGE_S32(i8_display_poc))\n                {\n                    ps_dec->i4_prev_max_display_seq = 0;\n                }\n            }\n            ret = ih264d_insert_pic_in_display_list(\n                            ps_dec->ps_dpb_mgr,\n                            ps_dec->u1_pic_buf_id,\n                            ps_dec->i4_prev_max_display_seq\n                                            + ps_dec->ps_cur_pic->i4_poc,\n                            ps_dec->ps_cur_pic->i4_frame_num);\n            if(ret != OK)\n                return ret;\n\n            {\n                ivd_video_decode_op_t * ps_dec_output =\n                                (ivd_video_decode_op_t *)ps_dec->pv_dec_out;\n\n                ps_dec_output->u4_frame_decoded_flag = 1;\n            }\n            if(ps_dec->au1_pic_buf_ref_flag[ps_dec->u1_pic_buf_id] == 0)\n            {\n                ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_mv_buf_mgr,\n                                      ps_dec->au1_pic_buf_id_mv_buf_id_map[ps_dec->u1_pic_buf_id],\n                                      BUF_MGR_REF);\n                ps_dec->au1_pic_buf_ref_flag[ps_dec->u1_pic_buf_id] = 0;\n\n            }\n        }\n        else\n        {\n            H264_DEC_DEBUG_PRINT(\"pic not inserted display %d %d\\n\",\n                                 ps_cur_slice->u1_field_pic_flag,\n                                 ps_dec->u1_second_field);\n        }\n\n        if(!ps_cur_slice->u1_field_pic_flag\n                        || ((TOP_FIELD_ONLY | BOT_FIELD_ONLY)\n                                        == ps_dec->u1_top_bottom_decoded))\n        {\n            if(IVD_DECODE_FRAME_OUT == ps_dec->e_frm_out_mode)\n            {\n                ret = ih264d_assign_display_seq(ps_dec);\n                if(ret != OK)\n                    return ret;\n            }\n        }\n    }\n\n    H264_MUTEX_UNLOCK(&ps_dec->process_disp_mutex);\n\n    return OK;\n}\n\nvoid ih264d_err_pic_dispbuf_mgr(dec_struct_t *ps_dec)\n{\n    dec_slice_params_t *ps_cur_slice = ps_dec->ps_cur_slice;\n    ivd_video_decode_op_t * ps_dec_output =\n                    (ivd_video_decode_op_t *)ps_dec->pv_dec_out;\n\n    ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                          ps_dec->u1_pic_buf_id,\n                          BUF_MGR_REF);\n    ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_mv_buf_mgr,\n                          ps_dec->au1_pic_buf_id_mv_buf_id_map[ps_dec->u1_pic_buf_id],\n                          BUF_MGR_REF);\n    ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                          ps_dec->u1_pic_buf_id,\n                          BUF_MGR_IO);\n}\n\nvoid ih264d_deblock_picture(void *ptr)\n{\n    dec_struct_t *ps_dec = (dec_struct_t *)ptr;\n\n    {\n        /*Deblock picture only if all the mb's in the frame have been decoded*/\n        if(ps_dec->u1_pic_decode_done == 1)\n        {\n            if(ps_dec->ps_cur_slice->u1_mbaff_frame_flag\n                            || ps_dec->ps_cur_slice->u1_field_pic_flag)\n            {\n                ps_dec->p_DeblockPicture[ps_dec->ps_cur_slice->u1_mbaff_frame_flag](\n                                ps_dec);\n            }\n            else\n\n            {\n\n                ih264d_deblock_picture_progressive(ps_dec);\n            }\n\n        }\n    }\n\n}\n\n/*!\n **************************************************************************\n * \\if Function name :  ih264d_deblock_display \\endif\n *\n * \\brief            :  The function callls the deblocking routine and manages\n :  the Recon buffers and displays .\n * \\return           :  Nothing\n *\n **************************************************************************\n */\nWORD32 ih264d_deblock_display(dec_struct_t *ps_dec)\n{\n    WORD32 ret;\n    /* Call deblocking */\n    ih264d_deblock_picture(ps_dec);\n\n    ret = ih264d_end_of_pic_dispbuf_mgr(ps_dec);\n    if(ret != OK)\n        return ret;\n\n    return OK;\n}\n\n/*\n *!\n **************************************************************************\n * \\if Function name : EndofPoc \\endif\n *\n * \\brief\n *    EndofPoc Processing\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\n\nWORD32 ih264d_end_of_pic(dec_struct_t *ps_dec)\n{\n    dec_slice_params_t *ps_cur_slice = ps_dec->ps_cur_slice;\n    WORD32 ret;\n\n    {\n        dec_err_status_t * ps_err = ps_dec->ps_dec_err_status;\n        if(ps_err->u1_err_flag & REJECT_CUR_PIC)\n        {\n            ih264d_err_pic_dispbuf_mgr(ps_dec);\n            return ERROR_NEW_FRAME_EXPECTED;\n        }\n    }\n\n    H264_MUTEX_LOCK(&ps_dec->process_disp_mutex);\n    ret = ih264d_end_of_pic_processing(ps_dec);\n    if(ret != OK)\n        return ret;\n    /*--------------------------------------------------------------------*/\n    /* ih264d_decode_pic_order_cnt - calculate the Pic Order Cnt                    */\n    /* Needed to detect end of picture                                    */\n    /*--------------------------------------------------------------------*/\n\n    H264_MUTEX_UNLOCK(&ps_dec->process_disp_mutex);\n\n    return OK;\n}\n\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_fix_error_in_dpb \\endif\n *\n * \\brief\n *    fix error in DPB\n *\n * \\return\n *    Number of node(s) deleted\n **************************************************************************\n */\n\nWORD32 ih264d_fix_error_in_dpb(dec_struct_t *ps_dec)\n{\n    /*--------------------------------------------------------------------*/\n    /* If there is common node in lt_list and st_list then delete it from */\n    /* st_list                                                            */\n    /*--------------------------------------------------------------------*/\n    UWORD8 no_of_nodes_deleted = 0;\n    UWORD8 lt_ref_num = ps_dec->ps_dpb_mgr->u1_num_lt_ref_bufs;\n    struct dpb_info_t *ps_lt_curr_dpb = ps_dec->ps_dpb_mgr->ps_dpb_ht_head;\n    while(lt_ref_num && ps_lt_curr_dpb)\n    {\n        if(ps_dec->ps_dpb_mgr->ps_dpb_st_head\n                && ((ps_lt_curr_dpb->s_bot_field.u1_reference_info\n                        | ps_lt_curr_dpb->s_top_field.u1_reference_info)\n                        == (IS_SHORT_TERM | IS_LONG_TERM)))\n        {\n            struct dpb_info_t *ps_st_next_dpb = ps_dec->ps_dpb_mgr->ps_dpb_st_head;\n            struct dpb_info_t *ps_st_curr_dpb = ps_dec->ps_dpb_mgr->ps_dpb_st_head;\n            UWORD8 st_ref_num = ps_dec->ps_dpb_mgr->u1_num_st_ref_bufs;\n            while(st_ref_num && ps_st_curr_dpb)\n            {\n                if(ps_st_curr_dpb == ps_lt_curr_dpb)\n                {\n                    if(st_ref_num == ps_dec->ps_dpb_mgr->u1_num_st_ref_bufs)\n                    {\n                        ps_dec->ps_dpb_mgr->ps_dpb_st_head =\n                                ps_dec->ps_dpb_mgr->ps_dpb_st_head->ps_prev_short;\n                        ps_st_curr_dpb = ps_dec->ps_dpb_mgr->ps_dpb_st_head;\n                    }\n                    else\n                    {\n                        ps_st_next_dpb->ps_prev_short = ps_st_curr_dpb->ps_prev_short;\n                    }\n                    ps_dec->ps_dpb_mgr->u1_num_st_ref_bufs--;\n                    no_of_nodes_deleted++;\n                    break;\n                }\n                ps_st_next_dpb = ps_st_curr_dpb;\n                ps_st_curr_dpb = ps_st_curr_dpb->ps_prev_short;\n                st_ref_num--;\n            }\n        }\n        ps_lt_curr_dpb = ps_lt_curr_dpb->ps_prev_long;\n        lt_ref_num--;\n    }\n    return no_of_nodes_deleted;\n}\n\n\n/*!\n **************************************************************************\n * \\if Function name : DecodeSlice \\endif\n *\n * \\brief\n *    Parses a slice\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\n\nWORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,\n                                 UWORD8 u1_nal_ref_idc,\n                                 dec_struct_t *ps_dec /* Decoder parameters */\n                                 )\n{\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n    dec_pic_params_t *ps_pps;\n    dec_seq_params_t *ps_seq;\n    dec_slice_params_t *ps_cur_slice = ps_dec->ps_cur_slice;\n    pocstruct_t s_tmp_poc = {0};\n    WORD32 i_delta_poc[2];\n    WORD32 i4_poc = 0;\n    UWORD16 u2_first_mb_in_slice, u2_frame_num;\n    UWORD8 u1_field_pic_flag, u1_redundant_pic_cnt = 0, u1_slice_type;\n    UWORD32 u4_idr_pic_id = 0;\n    UWORD8 u1_bottom_field_flag, u1_pic_order_cnt_type;\n\n    UWORD8 u1_nal_unit_type;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    WORD8 i1_is_end_of_poc;\n\n    WORD32 ret, end_of_frame;\n    WORD32 prev_slice_err, num_mb_skipped;\n    UWORD8 u1_mbaff;\n    pocstruct_t *ps_cur_poc;\n\n    UWORD32 u4_temp;\n    WORD32 i_temp;\n    UWORD32 u4_call_end_of_pic = 0;\n\n    /* read FirstMbInSlice  and slice type*/\n    ps_dec->ps_dpb_cmds->u1_dpb_commands_read_slc = 0;\n    u2_first_mb_in_slice = ih264d_uev(pu4_bitstrm_ofst,\n                                     pu4_bitstrm_buf);\n    if(u2_first_mb_in_slice\n                    >= (ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs))\n    {\n\n        return ERROR_CORRUPTED_SLICE;\n    }\n\n    /*we currently don not support ASO*/\n    if(((u2_first_mb_in_slice << ps_cur_slice->u1_mbaff_frame_flag)\n                    <= ps_dec->u2_cur_mb_addr) && (ps_dec->u4_first_slice_in_pic == 0))\n    {\n        return ERROR_CORRUPTED_SLICE;\n    }\n\n    COPYTHECONTEXT(\"SH: first_mb_in_slice\",u2_first_mb_in_slice);\n\n    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n\n    if(u4_temp > 9)\n        return ERROR_INV_SLC_TYPE_T;\n\n    u1_slice_type = u4_temp;\n    COPYTHECONTEXT(\"SH: slice_type\",(u1_slice_type));\n    /* Find Out the Slice Type is 5 to 9 or not then Set the Flag   */\n    /* u1_sl_typ_5_9 = 1 .Which tells that all the slices in the Pic*/\n    /* will be of same type of current                            */\n    if(u1_slice_type > 4)\n    {\n        u1_slice_type -= 5;\n    }\n\n    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if(u4_temp & MASK_ERR_PIC_SET_ID)\n        return ERROR_INV_SLICE_HDR_T;\n    /* discard slice if pic param is invalid */\n    COPYTHECONTEXT(\"SH: pic_parameter_set_id\", u4_temp);\n    ps_pps = &ps_dec->ps_pps[u4_temp];\n    if(FALSE == ps_pps->u1_is_valid)\n    {\n        return ERROR_INV_SLICE_HDR_T;\n    }\n    ps_seq = ps_pps->ps_sps;\n    if(!ps_seq)\n        return ERROR_INV_SLICE_HDR_T;\n    if(FALSE == ps_seq->u1_is_valid)\n        return ERROR_INV_SLICE_HDR_T;\n\n    /* Get the frame num */\n    u2_frame_num = ih264d_get_bits_h264(ps_bitstrm,\n                                         ps_seq->u1_bits_in_frm_num);\n//    H264_DEC_DEBUG_PRINT(\"FRAME %d First MB in slice: %d\\n\", u2_frame_num, u2_first_mb_in_slice);\n\n    COPYTHECONTEXT(\"SH: frame_num\", u2_frame_num);\n//    H264_DEC_DEBUG_PRINT(\"Second field: %d frame num: %d prv_frame_num: %d \\n\", ps_dec->u1_second_field, u2_frame_num, ps_dec->u2_prv_frame_num);\n    if(!ps_dec->u1_first_slice_in_stream && ps_dec->u4_first_slice_in_pic)\n    {\n        pocstruct_t *ps_prev_poc = &ps_dec->s_prev_pic_poc;\n        pocstruct_t *ps_cur_poc = &ps_dec->s_cur_pic_poc;\n\n        ps_dec->u2_mbx = 0xffff;\n        ps_dec->u2_mby = 0;\n\n        if((0 == u1_is_idr_slice) && ps_cur_slice->u1_nal_ref_idc)\n            ps_dec->u2_prev_ref_frame_num = ps_cur_slice->u2_frame_num;\n\n        if(u1_is_idr_slice || ps_cur_slice->u1_mmco_equalto5)\n            ps_dec->u2_prev_ref_frame_num = 0;\n\n        if(ps_dec->ps_cur_sps->u1_gaps_in_frame_num_value_allowed_flag)\n        {\n            ih264d_decode_gaps_in_frame_num(ps_dec, u2_frame_num);\n        }\n\n        ps_prev_poc->i4_prev_frame_num_ofst = ps_cur_poc->i4_prev_frame_num_ofst;\n        ps_prev_poc->u2_frame_num = ps_cur_poc->u2_frame_num;\n        ps_prev_poc->u1_mmco_equalto5 = ps_cur_slice->u1_mmco_equalto5;\n        if(ps_cur_slice->u1_nal_ref_idc)\n        {\n            ps_prev_poc->i4_pic_order_cnt_lsb = ps_cur_poc->i4_pic_order_cnt_lsb;\n            ps_prev_poc->i4_pic_order_cnt_msb = ps_cur_poc->i4_pic_order_cnt_msb;\n            ps_prev_poc->i4_delta_pic_order_cnt_bottom =\n                            ps_cur_poc->i4_delta_pic_order_cnt_bottom;\n            ps_prev_poc->i4_delta_pic_order_cnt[0] =\n                            ps_cur_poc->i4_delta_pic_order_cnt[0];\n            ps_prev_poc->i4_delta_pic_order_cnt[1] =\n                            ps_cur_poc->i4_delta_pic_order_cnt[1];\n            ps_prev_poc->u1_bot_field = ps_cur_poc->u1_bot_field;\n        }\n\n        ps_dec->u2_total_mbs_coded = 0;\n    }\n    /* Get the field related flags  */\n    if(!ps_seq->u1_frame_mbs_only_flag)\n    {\n\n        u1_field_pic_flag = ih264d_get_bit_h264(ps_bitstrm);\n        COPYTHECONTEXT(\"SH: field_pic_flag\", u1_field_pic_flag);\n        u1_bottom_field_flag = 0;\n\n        if(u1_field_pic_flag)\n        {\n            ps_dec->pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan_fld;\n            u1_bottom_field_flag = ih264d_get_bit_h264(ps_bitstrm);\n            COPYTHECONTEXT(\"SH: bottom_field_flag\", u1_bottom_field_flag);\n\n        }\n        else\n        {\n            ps_dec->pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan;\n        }\n    }\n    else\n    {\n        u1_field_pic_flag = 0;\n        u1_bottom_field_flag = 0;\n\n        ps_dec->pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan;\n    }\n\n    u1_nal_unit_type = SLICE_NAL;\n    if(u1_is_idr_slice)\n    {\n        u1_nal_unit_type = IDR_SLICE_NAL;\n        u4_idr_pic_id = ih264d_uev(pu4_bitstrm_ofst,\n                                   pu4_bitstrm_buf);\n        if(u4_idr_pic_id > 65535)\n            return ERROR_INV_SLICE_HDR_T;\n        COPYTHECONTEXT(\"SH:  \", u4_idr_pic_id);\n    }\n\n    /* read delta pic order count information*/\n    i_delta_poc[0] = i_delta_poc[1] = 0;\n    s_tmp_poc.i4_pic_order_cnt_lsb = 0;\n    s_tmp_poc.i4_delta_pic_order_cnt_bottom = 0;\n    u1_pic_order_cnt_type = ps_seq->u1_pic_order_cnt_type;\n    if(u1_pic_order_cnt_type == 0)\n    {\n        i_temp = ih264d_get_bits_h264(\n                        ps_bitstrm,\n                        ps_seq->u1_log2_max_pic_order_cnt_lsb_minus);\n        if(i_temp < 0 || i_temp >= ps_seq->i4_max_pic_order_cntLsb)\n            return ERROR_INV_SLICE_HDR_T;\n        s_tmp_poc.i4_pic_order_cnt_lsb = i_temp;\n        COPYTHECONTEXT(\"SH: pic_order_cnt_lsb\", s_tmp_poc.i4_pic_order_cnt_lsb);\n\n        if((ps_pps->u1_pic_order_present_flag == 1) && (!u1_field_pic_flag))\n        {\n            s_tmp_poc.i4_delta_pic_order_cnt_bottom = ih264d_sev(\n                            pu4_bitstrm_ofst, pu4_bitstrm_buf);\n            //if(s_tmp_poc.i4_delta_pic_order_cnt_bottom > ps_seq->i4_max_pic_order_cntLsb)\n            COPYTHECONTEXT(\"SH: delta_pic_order_cnt_bottom\",\n                            s_tmp_poc.i4_delta_pic_order_cnt_bottom);\n        }\n    }\n\n    s_tmp_poc.i4_delta_pic_order_cnt[0] = 0;\n    s_tmp_poc.i4_delta_pic_order_cnt[1] = 0;\n    if(u1_pic_order_cnt_type == 1\n                    && (!ps_seq->u1_delta_pic_order_always_zero_flag))\n    {\n        s_tmp_poc.i4_delta_pic_order_cnt[0] = ih264d_sev(pu4_bitstrm_ofst,\n                                                         pu4_bitstrm_buf);\n        COPYTHECONTEXT(\"SH: delta_pic_order_cnt[0]\",\n                        s_tmp_poc.i4_delta_pic_order_cnt[0]);\n\n        if(ps_pps->u1_pic_order_present_flag && !u1_field_pic_flag)\n        {\n            s_tmp_poc.i4_delta_pic_order_cnt[1] = ih264d_sev(\n                            pu4_bitstrm_ofst, pu4_bitstrm_buf);\n            COPYTHECONTEXT(\"SH: delta_pic_order_cnt[1]\",\n                            s_tmp_poc.i4_delta_pic_order_cnt[1]);\n        }\n    }\n\n    if(ps_pps->u1_redundant_pic_cnt_present_flag)\n    {\n        u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n        if(u4_temp > MAX_REDUNDANT_PIC_CNT)\n            return ERROR_INV_SLICE_HDR_T;\n        u1_redundant_pic_cnt = u4_temp;\n        COPYTHECONTEXT(\"SH: redundant_pic_cnt\", u1_redundant_pic_cnt);\n    }\n\n    /*--------------------------------------------------------------------*/\n    /* Check if the slice is part of new picture                          */\n    /*--------------------------------------------------------------------*/\n    /* First slice of a picture is always considered as part of new picture */\n    i1_is_end_of_poc = 1;\n    ps_dec->ps_dec_err_status->u1_err_flag &= MASK_REJECT_CUR_PIC;\n\n    if(ps_dec->u4_first_slice_in_pic == 0)\n    {\n        i1_is_end_of_poc = ih264d_is_end_of_pic(u2_frame_num, u1_nal_ref_idc,\n                                            &s_tmp_poc, &ps_dec->s_cur_pic_poc,\n                                            ps_cur_slice, u1_pic_order_cnt_type,\n                                            u1_nal_unit_type, u4_idr_pic_id,\n                                            u1_field_pic_flag,\n                                            u1_bottom_field_flag);\n        if(i1_is_end_of_poc)\n        {\n            ps_dec->u1_first_slice_in_stream = 0;\n            return ERROR_INCOMPLETE_FRAME;\n        }\n\n    }\n\n    /*--------------------------------------------------------------------*/\n    /* Check for error in slice and parse the missing/corrupted MB's      */\n    /* as skip-MB's in an inserted P-slice                                */\n    /*--------------------------------------------------------------------*/\n    u1_mbaff = ps_seq->u1_mb_aff_flag && (!u1_field_pic_flag);\n    prev_slice_err = 0;\n\n    if(i1_is_end_of_poc || ps_dec->u1_first_slice_in_stream)\n    {\n        /* If the current slice is not a field or frame number of the current\n         * slice doesn't match with previous slice, and decoder is expecting\n         * to decode a field i.e. ps_dec->u1_top_bottom_decoded is not 0 and\n         * is not (TOP_FIELD_ONLY | BOT_FIELD_ONLY), treat it as a dangling\n         * field */\n        if((u1_field_pic_flag == 0 || u2_frame_num != ps_dec->u2_prv_frame_num)\n               && ps_dec->u1_top_bottom_decoded != 0\n                   && ps_dec->u1_top_bottom_decoded\n                       != (TOP_FIELD_ONLY | BOT_FIELD_ONLY))\n        {\n            ps_dec->u1_dangling_field = 1;\n            if(ps_dec->u4_first_slice_in_pic)\n            {\n                // first slice - dangling field\n                prev_slice_err = 1;\n            }\n            else\n            {\n                // last slice - dangling field\n                prev_slice_err = 2;\n            }\n\n            if(ps_dec->u1_top_bottom_decoded ==TOP_FIELD_ONLY)\n                ps_cur_slice->u1_bottom_field_flag = 1;\n            else\n                ps_cur_slice->u1_bottom_field_flag = 0;\n\n            num_mb_skipped = (ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)\n                    - ps_dec->u2_total_mbs_coded;\n            ps_cur_poc = &ps_dec->s_cur_pic_poc;\n\n            u1_is_idr_slice = ps_cur_slice->u1_nal_unit_type == IDR_SLICE_NAL;\n        }\n        else if(ps_dec->u4_first_slice_in_pic)\n        {\n            if(u2_first_mb_in_slice > 0)\n            {\n                // first slice - missing/header corruption\n                prev_slice_err = 1;\n                num_mb_skipped = u2_first_mb_in_slice << u1_mbaff;\n                ps_cur_poc = &s_tmp_poc;\n\n                // initializing slice parameters\n                ps_cur_slice->u4_idr_pic_id = u4_idr_pic_id;\n                ps_cur_slice->u1_field_pic_flag = u1_field_pic_flag;\n                ps_cur_slice->u1_bottom_field_flag = u1_bottom_field_flag;\n                ps_cur_slice->i4_pic_order_cnt_lsb =\n                        s_tmp_poc.i4_pic_order_cnt_lsb;\n                ps_cur_slice->u1_nal_unit_type = u1_nal_unit_type;\n                ps_cur_slice->u1_redundant_pic_cnt = u1_redundant_pic_cnt;\n                ps_cur_slice->u1_nal_ref_idc = u1_nal_ref_idc;\n                ps_cur_slice->u1_pic_order_cnt_type = u1_pic_order_cnt_type;\n                ps_cur_slice->u1_mbaff_frame_flag = ps_seq->u1_mb_aff_flag\n                        && (!u1_field_pic_flag);\n            }\n        }\n        else\n        {\n            /* since i1_is_end_of_poc is set ,means new frame num is encountered. so conceal the current frame\n             * completely */\n            prev_slice_err = 2;\n            num_mb_skipped = (ps_dec->u2_frm_ht_in_mbs\n                            * ps_dec->u2_frm_wd_in_mbs)\n                            - ps_dec->u2_total_mbs_coded;\n            ps_cur_poc = &s_tmp_poc;\n        }\n    }\n    else\n    {\n        if((u2_first_mb_in_slice << u1_mbaff) > ps_dec->u2_total_mbs_coded)\n        {\n            // previous slice - missing/corruption\n            prev_slice_err = 2;\n            num_mb_skipped = (u2_first_mb_in_slice << u1_mbaff)\n                    - ps_dec->u2_total_mbs_coded;\n            ps_cur_poc = &s_tmp_poc;\n        }\n        else if((u2_first_mb_in_slice << u1_mbaff) < ps_dec->u2_total_mbs_coded)\n        {\n            return ERROR_CORRUPTED_SLICE;\n        }\n    }\n\n    if(prev_slice_err)\n    {\n        ret = ih264d_mark_err_slice_skip(ps_dec, num_mb_skipped, u1_is_idr_slice, u2_frame_num, ps_cur_poc, prev_slice_err);\n\n        if(ps_dec->u1_dangling_field == 1)\n        {\n            ps_dec->u1_second_field = 1 - ps_dec->u1_second_field;\n            ps_dec->u1_first_slice_in_stream = 0;\n            ps_dec->u1_top_bottom_decoded = TOP_FIELD_ONLY | BOT_FIELD_ONLY;\n            return ERROR_DANGLING_FIELD_IN_PIC;\n        }\n\n        if(prev_slice_err == 2)\n        {\n            ps_dec->u1_first_slice_in_stream = 0;\n            return ERROR_INCOMPLETE_FRAME;\n        }\n\n        if(ps_dec->u2_total_mbs_coded\n                >= ps_dec->u2_frm_ht_in_mbs * ps_dec->u2_frm_wd_in_mbs)\n        {\n            /* return if all MBs in frame are parsed*/\n            ps_dec->u1_first_slice_in_stream = 0;\n            return ERROR_IN_LAST_SLICE_OF_PIC;\n        }\n\n        if(ps_dec->ps_dec_err_status->u1_err_flag & REJECT_CUR_PIC)\n        {\n            ih264d_err_pic_dispbuf_mgr(ps_dec);\n            return ERROR_NEW_FRAME_EXPECTED;\n        }\n\n        if(ret != OK)\n            return ret;\n\n        i1_is_end_of_poc = 0;\n    }\n\n    /* Increment only if the current slice has atleast 1 more MB */\n    if (ps_dec->u4_first_slice_in_pic == 0 &&\n        (ps_dec->ps_parse_cur_slice->u4_first_mb_in_slice <\n        (UWORD32)(ps_dec->u2_total_mbs_coded >> ps_dec->ps_cur_slice->u1_mbaff_frame_flag)))\n    {\n        ps_dec->ps_parse_cur_slice++;\n        ps_dec->u2_cur_slice_num++;\n        // in the case of single core increment ps_decode_cur_slice\n        if(ps_dec->u1_separate_parse == 0)\n        {\n            ps_dec->ps_decode_cur_slice++;\n        }\n    }\n\n    ps_dec->u1_slice_header_done = 0;\n\n\n    if(u1_field_pic_flag)\n    {\n        ps_dec->u2_prv_frame_num = u2_frame_num;\n    }\n\n    if(ps_cur_slice->u1_mmco_equalto5)\n    {\n        WORD32 i4_temp_poc;\n        WORD32 i4_top_field_order_poc, i4_bot_field_order_poc;\n\n        if(!ps_cur_slice->u1_field_pic_flag) // or a complementary field pair\n        {\n            i4_top_field_order_poc = ps_dec->ps_cur_pic->i4_top_field_order_cnt;\n            i4_bot_field_order_poc =\n                            ps_dec->ps_cur_pic->i4_bottom_field_order_cnt;\n            i4_temp_poc = MIN(i4_top_field_order_poc,\n                                     i4_bot_field_order_poc);\n        }\n        else if(!ps_cur_slice->u1_bottom_field_flag)\n            i4_temp_poc = ps_dec->ps_cur_pic->i4_top_field_order_cnt;\n        else\n            i4_temp_poc = ps_dec->ps_cur_pic->i4_bottom_field_order_cnt;\n\n        WORD64 i8_result = (WORD64)i4_temp_poc\n                        - ps_dec->ps_cur_pic->i4_top_field_order_cnt;\n        if(IS_OUT_OF_RANGE_S32(i8_result))\n        {\n            return ERROR_INV_POC;\n        }\n        ps_dec->ps_cur_pic->i4_top_field_order_cnt = i8_result;\n        i8_result = (WORD64)i4_temp_poc\n                        - ps_dec->ps_cur_pic->i4_bottom_field_order_cnt;\n        if(IS_OUT_OF_RANGE_S32(i8_result))\n        {\n            return ERROR_INV_POC;\n        }\n        ps_dec->ps_cur_pic->i4_bottom_field_order_cnt = i8_result;\n        ps_dec->ps_cur_pic->i4_poc = i4_temp_poc;\n        ps_dec->ps_cur_pic->i4_avg_poc = i4_temp_poc;\n    }\n    if(ps_dec->u4_first_slice_in_pic)\n    {\n        ret = ih264d_decode_pic_order_cnt(u1_is_idr_slice, u2_frame_num,\n                                          &ps_dec->s_prev_pic_poc,\n                                          &s_tmp_poc, ps_cur_slice, ps_pps,\n                                          u1_nal_ref_idc,\n                                          u1_bottom_field_flag,\n                                          u1_field_pic_flag, &i4_poc);\n        if(ret != OK)\n            return ret;\n        /* Display seq no calculations */\n        if(i4_poc >= ps_dec->i4_max_poc)\n            ps_dec->i4_max_poc = i4_poc;\n        /* IDR Picture or POC wrap around */\n        if(i4_poc == 0)\n        {\n            WORD64 i8_temp;\n            i8_temp = (WORD64)ps_dec->i4_prev_max_display_seq\n                      + ps_dec->i4_max_poc\n                      + ps_dec->u1_max_dec_frame_buffering + 1;\n            /*If i4_prev_max_display_seq overflows integer range, reset it */\n            ps_dec->i4_prev_max_display_seq = IS_OUT_OF_RANGE_S32(i8_temp)?\n                                              0 : i8_temp;\n            ps_dec->i4_max_poc = 0;\n        }\n    }\n\n    /*--------------------------------------------------------------------*/\n    /* Copy the values read from the bitstream to the slice header and then*/\n    /* If the slice is first slice in picture, then do Start of Picture   */\n    /* processing.                                                        */\n    /*--------------------------------------------------------------------*/\n    ps_cur_slice->i4_delta_pic_order_cnt[0] = i_delta_poc[0];\n    ps_cur_slice->i4_delta_pic_order_cnt[1] = i_delta_poc[1];\n    ps_cur_slice->u4_idr_pic_id = u4_idr_pic_id;\n    ps_cur_slice->u2_first_mb_in_slice = u2_first_mb_in_slice;\n    ps_cur_slice->u1_field_pic_flag = u1_field_pic_flag;\n    ps_cur_slice->u1_bottom_field_flag = u1_bottom_field_flag;\n    ps_cur_slice->u1_slice_type = u1_slice_type;\n    ps_cur_slice->i4_pic_order_cnt_lsb = s_tmp_poc.i4_pic_order_cnt_lsb;\n\n    ps_cur_slice->u1_nal_unit_type = u1_nal_unit_type;\n    ps_cur_slice->u1_redundant_pic_cnt = u1_redundant_pic_cnt;\n    ps_cur_slice->u1_nal_ref_idc = u1_nal_ref_idc;\n    ps_cur_slice->u1_pic_order_cnt_type = u1_pic_order_cnt_type;\n\n    if(ps_seq->u1_frame_mbs_only_flag)\n        ps_cur_slice->u1_direct_8x8_inference_flag =\n                        ps_seq->u1_direct_8x8_inference_flag;\n    else\n        ps_cur_slice->u1_direct_8x8_inference_flag = 1;\n\n    if(u1_slice_type == B_SLICE)\n    {\n        ps_cur_slice->u1_direct_spatial_mv_pred_flag = ih264d_get_bit_h264(\n                        ps_bitstrm);\n        COPYTHECONTEXT(\"SH: direct_spatial_mv_pred_flag\",\n                        ps_cur_slice->u1_direct_spatial_mv_pred_flag);\n\n        if(ps_cur_slice->u1_direct_spatial_mv_pred_flag)\n            ps_cur_slice->pf_decodeDirect = ih264d_decode_spatial_direct;\n        else\n            ps_cur_slice->pf_decodeDirect = ih264d_decode_temporal_direct;\n        if(!((ps_pps->ps_sps->u1_mb_aff_flag) && (!u1_field_pic_flag)))\n            ps_dec->pf_mvpred = ih264d_mvpred_nonmbaffB;\n    }\n    else\n    {\n        if(!((ps_pps->ps_sps->u1_mb_aff_flag) && (!u1_field_pic_flag)))\n            ps_dec->pf_mvpred = ih264d_mvpred_nonmbaff;\n    }\n\n    if(ps_dec->u4_first_slice_in_pic)\n    {\n        if(u2_first_mb_in_slice == 0)\n        {\n            ret = ih264d_start_of_pic(ps_dec, i4_poc, &s_tmp_poc, u2_frame_num, ps_pps);\n            if(ret != OK)\n                return ret;\n        }\n\n        ps_dec->u4_output_present = 0;\n\n        {\n            ih264d_get_next_display_field(ps_dec,\n                                          ps_dec->ps_out_buffer,\n                                          &(ps_dec->s_disp_op));\n            /* If error code is non-zero then there is no buffer available for display,\n             hence avoid format conversion */\n\n            if(0 != ps_dec->s_disp_op.u4_error_code)\n            {\n                ps_dec->u4_fmt_conv_cur_row = ps_dec->s_disp_frame_info.u4_y_ht;\n            }\n            else\n                ps_dec->u4_output_present = 1;\n        }\n        if(ps_dec->u1_separate_parse == 1)\n        {\n            if(ps_dec->u4_dec_thread_created == 0)\n            {\n                ithread_create(ps_dec->pv_dec_thread_handle, NULL,\n                               (void *)ih264d_decode_picture_thread,\n                               (void *)ps_dec);\n\n                ps_dec->u4_dec_thread_created = 1;\n            }\n\n            if((ps_dec->u4_num_cores == 3) &&\n                            ((ps_dec->u4_app_disable_deblk_frm == 0) || ps_dec->i1_recon_in_thread3_flag)\n                            && (ps_dec->u4_bs_deblk_thread_created == 0))\n            {\n                ps_dec->u4_start_recon_deblk = 0;\n                ithread_create(ps_dec->pv_bs_deblk_thread_handle, NULL,\n                               (void *)ih264d_recon_deblk_thread,\n                               (void *)ps_dec);\n                ps_dec->u4_bs_deblk_thread_created = 1;\n            }\n        }\n\n    }\n\n    /* INITIALIZATION of fn ptrs for MC and formMbPartInfo functions */\n    {\n        UWORD8 uc_nofield_nombaff;\n\n\n\n        uc_nofield_nombaff = ((ps_dec->ps_cur_slice->u1_field_pic_flag == 0)\n                        && (ps_dec->ps_cur_slice->u1_mbaff_frame_flag == 0)\n                        && (u1_slice_type != B_SLICE)\n                        && (ps_dec->ps_cur_pps->u1_wted_pred_flag == 0));\n\n        /* Initialise MC and formMbPartInfo fn ptrs one time based on profile_idc */\n\n        if(uc_nofield_nombaff)\n        {\n            ps_dec->p_form_mb_part_info = ih264d_form_mb_part_info_bp;\n            ps_dec->p_motion_compensate = ih264d_motion_compensate_bp;\n        }\n        else\n        {\n            ps_dec->p_form_mb_part_info = ih264d_form_mb_part_info_mp;\n            ps_dec->p_motion_compensate = ih264d_motion_compensate_mp;\n        }\n\n\n    }\n\n    /*\n     * Decide whether to decode the current picture or not\n     */\n    {\n        dec_err_status_t * ps_err = ps_dec->ps_dec_err_status;\n        if(ps_err->u4_frm_sei_sync == u2_frame_num)\n        {\n            ps_err->u1_err_flag = ACCEPT_ALL_PICS;\n            ps_err->u4_frm_sei_sync = SYNC_FRM_DEFAULT;\n        }\n        ps_err->u4_cur_frm = u2_frame_num;\n    }\n\n    /* Decision for decoding if the picture is to be skipped */\n    {\n        WORD32 i4_skip_b_pic, i4_skip_p_pic;\n\n        i4_skip_b_pic = (ps_dec->u4_skip_frm_mask & B_SLC_BIT)\n                        && (B_SLICE == u1_slice_type) && (0 == u1_nal_ref_idc);\n\n        i4_skip_p_pic = (ps_dec->u4_skip_frm_mask & P_SLC_BIT)\n                        && (P_SLICE == u1_slice_type) && (0 == u1_nal_ref_idc);\n\n        /**************************************************************/\n        /* Skip the B picture if skip mask is set for B picture and   */\n        /* Current B picture is a non reference B picture or there is */\n        /* no user for reference B picture                            */\n        /**************************************************************/\n        if(i4_skip_b_pic)\n        {\n            ps_dec->ps_cur_pic->u4_pack_slc_typ |= B_SLC_BIT;\n            /* Don't decode the picture in SKIP-B mode if that picture is B */\n            /* and also it is not to be used as a reference picture         */\n            ps_dec->u1_last_pic_not_decoded = 1;\n\n            return OK;\n        }\n        /**************************************************************/\n        /* Skip the P picture if skip mask is set for P picture and   */\n        /* Current P picture is a non reference P picture or there is */\n        /* no user for reference P picture                            */\n        /**************************************************************/\n        if(i4_skip_p_pic)\n        {\n            ps_dec->ps_cur_pic->u4_pack_slc_typ |= P_SLC_BIT;\n            /* Don't decode the picture in SKIP-P mode if that picture is P */\n            /* and also it is not to be used as a reference picture         */\n            ps_dec->u1_last_pic_not_decoded = 1;\n\n            return OK;\n        }\n    }\n\n    {\n        UWORD16 u2_mb_x, u2_mb_y;\n\n        ps_dec->i4_submb_ofst = ((u2_first_mb_in_slice\n                        << ps_cur_slice->u1_mbaff_frame_flag) * SUB_BLK_SIZE)\n                        - SUB_BLK_SIZE;\n        if(u2_first_mb_in_slice)\n        {\n            UWORD8 u1_mb_aff;\n            UWORD8 u1_field_pic;\n            UWORD16 u2_frm_wd_in_mbs;\n            u2_frm_wd_in_mbs = ps_seq->u2_frm_wd_in_mbs;\n            u1_mb_aff = ps_cur_slice->u1_mbaff_frame_flag;\n            u1_field_pic = ps_cur_slice->u1_field_pic_flag;\n\n            {\n                UWORD32 x_offset;\n                UWORD32 y_offset;\n                UWORD32 u4_frame_stride;\n                tfr_ctxt_t *ps_trns_addr; // = &ps_dec->s_tran_addrecon_parse;\n\n                if(ps_dec->u1_separate_parse)\n                {\n                    ps_trns_addr = &ps_dec->s_tran_addrecon_parse;\n                }\n                else\n                {\n                    ps_trns_addr = &ps_dec->s_tran_addrecon;\n                }\n                u2_mb_x = MOD(u2_first_mb_in_slice, u2_frm_wd_in_mbs);\n                u2_mb_y = DIV(u2_first_mb_in_slice, u2_frm_wd_in_mbs);\n\n                u2_mb_y <<= u1_mb_aff;\n\n                if((u2_mb_x > u2_frm_wd_in_mbs - 1)\n                                || (u2_mb_y > ps_dec->u2_frm_ht_in_mbs - 1))\n                {\n                    return ERROR_CORRUPTED_SLICE;\n                }\n\n                u4_frame_stride = ps_dec->u2_frm_wd_y << u1_field_pic;\n                x_offset = u2_mb_x << 4;\n                y_offset = (u2_mb_y * u4_frame_stride) << 4;\n\n                ps_trns_addr->pu1_dest_y = ps_dec->s_cur_pic.pu1_buf1 + x_offset\n                                + y_offset;\n\n                u4_frame_stride = ps_dec->u2_frm_wd_uv << u1_field_pic;\n                x_offset >>= 1;\n                y_offset = (u2_mb_y * u4_frame_stride) << 3;\n\n                x_offset *= YUV420SP_FACTOR;\n\n                ps_trns_addr->pu1_dest_u = ps_dec->s_cur_pic.pu1_buf2 + x_offset\n                                + y_offset;\n                ps_trns_addr->pu1_dest_v = ps_dec->s_cur_pic.pu1_buf3 + x_offset\n                                + y_offset;\n\n                ps_trns_addr->pu1_mb_y = ps_trns_addr->pu1_dest_y;\n                ps_trns_addr->pu1_mb_u = ps_trns_addr->pu1_dest_u;\n                ps_trns_addr->pu1_mb_v = ps_trns_addr->pu1_dest_v;\n\n\n                // assign the deblock structure pointers to start of slice\n                if(ps_dec->u1_separate_parse == 1)\n                {\n                    ps_dec->ps_deblk_mbn = ps_dec->ps_deblk_pic\n                                    + (u2_first_mb_in_slice << u1_mb_aff);\n                }\n                else\n                {\n                        ps_dec->ps_deblk_mbn = ps_dec->ps_deblk_pic\n                                        + (u2_first_mb_in_slice << u1_mb_aff);\n                }\n\n                ps_dec->u2_cur_mb_addr = (u2_first_mb_in_slice << u1_mb_aff);\n\n                ps_dec->ps_mv_cur = ps_dec->s_cur_pic.ps_mv\n                                + ((u2_first_mb_in_slice << u1_mb_aff) << 4);\n            }\n        }\n        else\n        {\n            tfr_ctxt_t *ps_trns_addr;\n\n            if(ps_dec->u1_separate_parse)\n            {\n                ps_trns_addr = &ps_dec->s_tran_addrecon_parse;\n            }\n            else\n            {\n                ps_trns_addr = &ps_dec->s_tran_addrecon;\n            }\n\n            u2_mb_x = 0xffff;\n            u2_mb_y = 0;\n            // assign the deblock structure pointers to start of slice\n            ps_dec->u2_cur_mb_addr = 0;\n            ps_dec->ps_deblk_mbn = ps_dec->ps_deblk_pic;\n            ps_dec->ps_mv_cur = ps_dec->s_cur_pic.ps_mv;\n            ps_trns_addr->pu1_dest_y = ps_dec->s_cur_pic.pu1_buf1;\n            ps_trns_addr->pu1_dest_u = ps_dec->s_cur_pic.pu1_buf2;\n            ps_trns_addr->pu1_dest_v = ps_dec->s_cur_pic.pu1_buf3;\n\n            ps_trns_addr->pu1_mb_y = ps_trns_addr->pu1_dest_y;\n            ps_trns_addr->pu1_mb_u = ps_trns_addr->pu1_dest_u;\n            ps_trns_addr->pu1_mb_v = ps_trns_addr->pu1_dest_v;\n\n        }\n\n        ps_dec->ps_part = ps_dec->ps_parse_part_params;\n\n        ps_dec->u2_mbx =\n                        (MOD(u2_first_mb_in_slice - 1, ps_seq->u2_frm_wd_in_mbs));\n        ps_dec->u2_mby =\n                        (DIV(u2_first_mb_in_slice - 1, ps_seq->u2_frm_wd_in_mbs));\n        ps_dec->u2_mby <<= ps_cur_slice->u1_mbaff_frame_flag;\n        ps_dec->i2_prev_slice_mbx = ps_dec->u2_mbx;\n        ps_dec->i2_prev_slice_mby = ps_dec->u2_mby;\n    }\n\n    /* RBSP stop bit is used for CABAC decoding*/\n    ps_bitstrm->u4_max_ofst += ps_dec->ps_cur_pps->u1_entropy_coding_mode;\n\n    ps_dec->u1_B = (u1_slice_type == B_SLICE);\n    ps_dec->u4_next_mb_skip = 0;\n\n    ps_dec->ps_parse_cur_slice->u4_first_mb_in_slice =\n                    ps_dec->ps_cur_slice->u2_first_mb_in_slice;\n    ps_dec->ps_parse_cur_slice->slice_type =\n                    ps_dec->ps_cur_slice->u1_slice_type;\n\n\n    ps_dec->u4_start_recon_deblk = 1;\n    {\n        WORD32 num_entries;\n        WORD32 size;\n        UWORD8 *pu1_buf;\n\n        num_entries = MAX_FRAMES;\n        if((1 >= ps_dec->ps_cur_sps->u1_num_ref_frames) &&\n            (0 == ps_dec->i4_display_delay))\n        {\n            num_entries = 1;\n        }\n        num_entries = ((2 * num_entries) + 1);\n        num_entries *= 2;\n\n\n        size = num_entries * sizeof(void *);\n        size += PAD_MAP_IDX_POC * sizeof(void *);\n\n        pu1_buf = (UWORD8 *)ps_dec->pv_map_ref_idx_to_poc_buf;\n        pu1_buf += size * ps_dec->u2_cur_slice_num;\n        ps_dec->ps_parse_cur_slice->ppv_map_ref_idx_to_poc = ( void *)pu1_buf;\n    }\n\n    if(ps_dec->u1_separate_parse)\n    {\n        ps_dec->ps_parse_cur_slice->pv_tu_coeff_data_start = ps_dec->pv_parse_tu_coeff_data;\n    }\n    else\n    {\n        ps_dec->pv_proc_tu_coeff_data = ps_dec->pv_parse_tu_coeff_data;\n    }\n\n    ret = ih264d_fix_error_in_dpb(ps_dec);\n    if(ret < 0)\n        return ERROR_DBP_MANAGER_T;\n\n    if(u1_slice_type == I_SLICE)\n    {\n        ps_dec->ps_cur_pic->u4_pack_slc_typ |= I_SLC_BIT;\n\n        ret = ih264d_parse_islice(ps_dec, u2_first_mb_in_slice);\n        ps_dec->u1_pr_sl_type = u1_slice_type;\n        if(ps_dec->i4_pic_type != B_SLICE && ps_dec->i4_pic_type != P_SLICE)\n            ps_dec->i4_pic_type = I_SLICE;\n\n    }\n    else if(u1_slice_type == P_SLICE)\n    {\n        ps_dec->ps_cur_pic->u4_pack_slc_typ |= P_SLC_BIT;\n        ret = ih264d_parse_pslice(ps_dec, u2_first_mb_in_slice);\n        ps_dec->u1_pr_sl_type = u1_slice_type;\n        if(ps_dec->i4_pic_type != B_SLICE)\n            ps_dec->i4_pic_type = P_SLICE;\n    }\n    else if(u1_slice_type == B_SLICE)\n    {\n        ps_dec->ps_cur_pic->u4_pack_slc_typ |= B_SLC_BIT;\n        ret = ih264d_parse_bslice(ps_dec, u2_first_mb_in_slice);\n        ps_dec->u1_pr_sl_type = u1_slice_type;\n        ps_dec->i4_pic_type = B_SLICE;\n    }\n    else\n        return ERROR_INV_SLC_TYPE_T;\n\n    if(ps_dec->u1_slice_header_done)\n    {\n        /* set to zero to indicate a valid slice has been decoded */\n        ps_dec->u1_first_slice_in_stream = 0;\n    }\n\n    if(ret != OK)\n        return ret;\n\n    if(u1_nal_ref_idc != 0)\n    {\n        if(!ps_dec->ps_dpb_cmds->u1_dpb_commands_read)\n        {\n            memcpy((void *)ps_dec->ps_dpb_cmds, (void *)(&(ps_dec->s_dpb_cmds_scratch)),\n                   sizeof(dpb_commands_t));\n        }\n    }\n\n    /* storing last Mb X and MbY of the slice */\n    ps_dec->i2_prev_slice_mbx = ps_dec->u2_mbx;\n    ps_dec->i2_prev_slice_mby = ps_dec->u2_mby;\n\n    /* End of Picture detection */\n\n    if(ps_dec->u2_total_mbs_coded >= (ps_seq->u2_max_mb_addr + 1))\n    {\n        ps_dec->u1_pic_decode_done = 1;\n\n    }\n\n    {\n        dec_err_status_t * ps_err = ps_dec->ps_dec_err_status;\n        if((ps_err->u1_err_flag & REJECT_PB_PICS)\n                        && (ps_err->u1_cur_pic_type == PIC_TYPE_I))\n        {\n            ps_err->u1_err_flag = ACCEPT_ALL_PICS;\n        }\n    }\n\n    PRINT_BIN_BIT_RATIO(ps_dec)\n\n    return ret;\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_parse_slice.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_PARSE_SLICE_H_\n#define _IH264D_PARSE_SLICE_H_\n/*!\n **************************************************************************\n * \\file ih264d_parse_slice.h\n *\n * \\brief\n *    Contains routines that decodes a slice NAL unit\n *\n * \\date\n *    19/12/2002\n *\n * \\author  AI\n **************************************************************************\n */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_error_handler.h\"\nWORD32 ih264d_fix_error_in_dpb(dec_struct_t * ps_dec);\nWORD32 ih264d_parse_decode_slice(UWORD8 u1_is_idr_slice,\n                                 UWORD8 u1_nal_ref_idc,\n                                 dec_struct_t * ps_dec );\n\nWORD32 ih264d_end_of_pic(dec_struct_t *ps_dec);\nWORD32 ih264d_start_of_pic(dec_struct_t *ps_dec,\n                           WORD32 i4_poc,\n                           pocstruct_t *ps_temp_poc,\n                           UWORD16 u2_frame_num,\n                           dec_pic_params_t *ps_pps);\n\nWORD32 ih264d_ref_idx_reordering(dec_struct_t * ps_dec, UWORD8 u1_isB);\nWORD32 ih264d_read_mmco_commands(dec_struct_t * ps_dec);\nvoid ih264d_form_pred_weight_matrix(dec_struct_t *ps_dec);\nWORD32 ih264d_end_of_pic_dispbuf_mgr(dec_struct_t * ps_dec);\n#endif /* _IH264D_PARSE_SLICE_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_process_bslice.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n * \\file ih264d_process_bslice.c\n *\n * \\brief\n *    Contains routines that decode B slice type\n *\n * Detailed_description\n *\n * \\date\n *    21/12/2002\n *\n * \\author  NS\n **************************************************************************\n */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n\n#include <string.h>\n#include \"ih264d_structs.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_mvpred.h\"\n#include \"ih264d_inter_pred.h\"\n#include \"ih264d_process_pslice.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_process_pslice.h\"\n#include \"ih264d_process_bslice.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_parse_islice.h\"\n#include \"ih264d_mvpred.h\"\n\nvoid ih264d_init_cabac_contexts(UWORD8 u1_slice_type, dec_struct_t * ps_dec);\n//UWORD32 g_hits = 0;\n//UWORD32 g_miss = 0;\n/*!\n **************************************************************************\n * \\if Function name : ih264d_decode_spatial_direct \\endif\n *\n * \\brief\n *    Decodes spatial direct mode.\n *\n * \\return\n *    None.\n *    Arunoday T\n **************************************************************************\n */\nWORD32 ih264d_decode_spatial_direct(dec_struct_t * ps_dec,\n                                    UWORD8 u1_wd_x,\n                                    dec_mb_info_t * ps_cur_mb_info,\n                                    UWORD8 u1_mb_num)\n{\n    mv_pred_t s_mv_pred, *ps_mv;\n    UWORD8 u1_col_zero_flag, u1_sub_mb_num, u1_direct_zero_pred_flag = 0;\n    UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    mv_pred_t *ps_mv_ntop_start;\n    mv_pred_t *ps_mv_nmb_start = ps_dec->ps_mv_cur + (u1_mb_num << 4);\n    UWORD8 partition_size, sub_partition, u1_mb_partw, u1_mb_parth;\n    UWORD8 i;\n    WORD8 i1_pred, i1_ref_frame0, i1_ref_frame1;\n    struct pic_buffer_t *ps_ref_frame = NULL, *ps_col_pic, *ps_pic_buff0 = NULL,\n                    *ps_pic_buff1 = NULL;\n\n    UWORD8 u1_zero_pred_cond_f, u1_zero_pred_cond_b;\n    WORD16 i2_def_mv[2], i2_spat_pred_mv[4], *pi2_final_mv0, *pi2_final_mv1;\n    UWORD16 ui2_mask_fwd = 0, ui2_mask_bwd = 0, u2_mask = 0;\n    UWORD32 *pui32_weight_ofsts = NULL;\n    directmv_t s_mvdirect;\n    UWORD8 u1_colz;\n    UWORD8 u1_final_ref_idx = 0;\n    const UWORD8 *pu1_mb_parth = (const UWORD8 *)gau1_ih264d_mb_parth;\n    const UWORD8 *pu1_mb_partw = (const UWORD8 *)gau1_ih264d_mb_partw;\n    const UWORD16 sub_mask_table[] =\n        { 0x33, 0x3, 0x11, 0x1 };\n    const UWORD16 mask_table[] =\n        { 0xffff, /*16x16 NA */\n          0xff, /* 16x8*/\n          0x3333, /* 8x16*/\n          0x33 };/* 8x8*/\n    mv_pred_t s_temp_mv_pred;\n    WORD32 ret = 0;\n\n    /* CHANGED CODE */\n    ps_mv_ntop_start = ps_dec->ps_mv_cur + (u1_mb_num << 4)\n                    - (ps_dec->u2_frm_wd_in_mbs << (4 + u1_mbaff)) + 12;\n\n    /* assign default values for MotionVector as zero */\n    i2_def_mv[0] = 0;\n    i2_def_mv[1] = 0;\n\n    u1_direct_zero_pred_flag = ps_dec->pf_mvpred(ps_dec, ps_cur_mb_info, ps_mv_nmb_start,\n                                              ps_mv_ntop_start, &s_mv_pred, 0, 4,\n                                              0, 1, B_DIRECT_SPATIAL);\n\n    i2_spat_pred_mv[0] = s_mv_pred.i2_mv[0];\n    i2_spat_pred_mv[1] = s_mv_pred.i2_mv[1];\n    i2_spat_pred_mv[2] = s_mv_pred.i2_mv[2];\n    i2_spat_pred_mv[3] = s_mv_pred.i2_mv[3];\n\n    i1_ref_frame0 = s_mv_pred.i1_ref_frame[0];\n    i1_ref_frame1 = s_mv_pred.i1_ref_frame[1];\n\n    i1_ref_frame0 = (i1_ref_frame0 < 0) ? -1 : i1_ref_frame0;\n    i1_ref_frame1 = (i1_ref_frame1 < 0) ? -1 : i1_ref_frame1;\n\n    i1_pred = 0;\n\n    {\n        WORD8 u1_ref_idx, u1_ref_idx1;\n        UWORD32 uc_Idx, uc_Idx1;\n        UWORD8 u1_scale_ref = (ps_dec->ps_cur_slice->u1_mbaff_frame_flag\n                        && ps_cur_mb_info->u1_mb_field_decodingflag);\n        u1_final_ref_idx = i1_ref_frame0;\n        if(i1_ref_frame0 >= 0)\n        {\n            /* convert RefIdx if it is MbAff */\n            u1_ref_idx = i1_ref_frame0;\n            u1_ref_idx1 = i1_ref_frame0;\n            if(u1_scale_ref)\n            {\n                u1_ref_idx1 = u1_ref_idx >> 1;\n                if((u1_ref_idx & 0x01) != (1 - ps_cur_mb_info->u1_topmb))\n                    u1_ref_idx1 += MAX_REF_BUFS;\n            }\n            /* If i1_ref_frame0 < 0 then refIdxCol is obtained from ps_pic_buff1 */\n            ps_pic_buff0 = ps_dec->ps_ref_pic_buf_lx[0][u1_ref_idx1];\n            ps_ref_frame = ps_pic_buff0;\n            i1_pred = PRED_L0;\n        }\n\n        if(i1_ref_frame1 >= 0)\n        {\n            /* convert RefIdx if it is MbAff */\n            u1_ref_idx = i1_ref_frame1;\n            u1_ref_idx1 = i1_ref_frame1;\n            if(u1_scale_ref)\n            {\n                u1_ref_idx1 = u1_ref_idx >> 1;\n                if((u1_ref_idx & 0x01) != (1 - ps_cur_mb_info->u1_topmb))\n                    u1_ref_idx1 += MAX_REF_BUFS;\n            }\n            ps_pic_buff1 = ps_dec->ps_ref_pic_buf_lx[1][u1_ref_idx1];\n            i1_pred = i1_pred | PRED_L1;\n        }\n        if(i1_ref_frame0 < 0)\n        {\n            ps_ref_frame = ps_pic_buff1;\n            u1_final_ref_idx = i1_ref_frame1;\n        }\n\n        u1_zero_pred_cond_f = (u1_direct_zero_pred_flag) || (i1_ref_frame0 < 0);\n        u1_zero_pred_cond_b = (u1_direct_zero_pred_flag) || (i1_ref_frame1 < 0);\n\n        if(ps_dec->ps_cur_pps->u1_wted_bipred_idc)\n        {\n            uc_Idx = ((i1_ref_frame0 < 1) ? 0 : i1_ref_frame0)\n                            * ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1];\n            if(u1_scale_ref)\n                uc_Idx >>= 1;\n            uc_Idx1 = (i1_ref_frame1 < 0) ? 0 : i1_ref_frame1;\n            uc_Idx += (u1_scale_ref) ? (uc_Idx1 >> 1) : uc_Idx1;\n            pui32_weight_ofsts =\n                            (UWORD32*)&ps_dec->pu4_wt_ofsts[2 * X3(uc_Idx)];\n\n            if(i1_ref_frame0 < 0)\n                pui32_weight_ofsts += 1;\n\n            if(u1_scale_ref && (ps_dec->ps_cur_pps->u1_wted_bipred_idc == 2))\n            {\n                WORD16 i2_ref_idx;\n                i2_ref_idx = MAX(i1_ref_frame0, 0);\n                i2_ref_idx *= (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1]\n                                << 1);\n                i2_ref_idx += MAX(i1_ref_frame1, 0);\n                if(!ps_cur_mb_info->u1_topmb)\n                    i2_ref_idx +=\n                                    (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0]\n                                                    << 1)\n                                                    * (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1]\n                                                                    << 1);\n                pui32_weight_ofsts = (UWORD32*)&ps_dec->pu4_mbaff_wt_mat[2\n                                * X3(i2_ref_idx)];\n            }\n        }\n    }\n\n    s_temp_mv_pred.i1_ref_frame[0] = i1_ref_frame0;\n    s_temp_mv_pred.i1_ref_frame[1] = i1_ref_frame1;\n    s_temp_mv_pred.u1_col_ref_pic_idx = ps_ref_frame->u1_mv_buf_id;\n    s_temp_mv_pred.u1_pic_type = ps_ref_frame->u1_pic_type;\n\n    /**********************************************************************/\n    /* Call the function which gets the number of partitions and          */\n    /* partition info of colocated Mb                                     */\n    /**********************************************************************/\n\n    ps_dec->pf_parse_mvdirect(ps_dec, ps_dec->ps_col_pic, &s_mvdirect, u1_wd_x,\n                           ps_dec->i4_submb_ofst, ps_cur_mb_info);\n    ps_col_pic = ps_dec->ps_col_pic;\n    if((s_mvdirect.u1_col_zeroflag_change == 0) || u1_direct_zero_pred_flag)\n    {\n        WORD16 i2_mv_x, i2_mv_y, i2_mvX1, i2_mvY1;\n        /* Most probable case */\n        u1_col_zero_flag = *(ps_col_pic->pu1_col_zero_flag\n                        + s_mvdirect.i4_mv_indices[0]);\n        u1_col_zero_flag = u1_col_zero_flag & 0x01;\n\n        if(u1_zero_pred_cond_f || ((i1_ref_frame0 == 0) && (u1_col_zero_flag == 1)))\n        {\n            i2_mv_x = 0;\n            i2_mv_y = 0;\n        }\n        else\n        {\n            i2_mv_x = i2_spat_pred_mv[0];\n            i2_mv_y = i2_spat_pred_mv[1];\n\n        }\n\n        if(u1_zero_pred_cond_b || ((i1_ref_frame1 == 0) && (u1_col_zero_flag == 1)))\n        {\n            i2_mvX1 = 0;\n            i2_mvY1 = 0;\n        }\n        else\n        {\n            i2_mvX1 = i2_spat_pred_mv[2];\n            i2_mvY1 = i2_spat_pred_mv[3];\n        }\n\n        u1_sub_mb_num = ps_dec->u1_sub_mb_num;\n        u1_mb_partw = (u1_wd_x >> 2);\n\n\n        if(i1_ref_frame0 >= 0)\n        {\n            {\n               pred_info_pkd_t *ps_pred_pkd;\n               WORD16 i2_mv[2];\n               WORD8 i1_ref_idx= 0;\n\n               i2_mv[0] = i2_mv_x;\n               i2_mv[1] = i2_mv_y;\n\n               ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n            ih264d_fill_pred_info(i2_mv,u1_mb_partw,u1_mb_partw,u1_sub_mb_num,i1_pred,\n                            ps_pred_pkd,ps_pic_buff0->u1_pic_buf_id,i1_ref_idx,pui32_weight_ofsts,\n                            ps_pic_buff0->u1_pic_type);\n            ps_dec->u4_pred_info_pkd_idx++;\n            ps_cur_mb_info->u1_num_pred_parts++;\n\n\n            }\n\n        }\n\n        if(i1_ref_frame1 >= 0)\n        {\n            {\n                pred_info_pkd_t *ps_pred_pkd;\n               WORD16 i2_mv[2];\n               WORD8 i1_ref_idx= 0;\n\n               i2_mv[0] = i2_mvX1;\n               i2_mv[1] = i2_mvY1;\n\n               ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n            ih264d_fill_pred_info(i2_mv,u1_mb_partw,u1_mb_partw,u1_sub_mb_num,i1_pred,\n                            ps_pred_pkd,ps_pic_buff1->u1_pic_buf_id,i1_ref_idx,pui32_weight_ofsts,\n                            ps_pic_buff1->u1_pic_type);\n            ps_dec->u4_pred_info_pkd_idx++;\n            ps_cur_mb_info->u1_num_pred_parts++;\n\n\n            }\n        }\n\n\n        /* Replication optimisation */\n        s_temp_mv_pred.i2_mv[0] = i2_mv_x;\n        s_temp_mv_pred.i2_mv[1] = i2_mv_y;\n        s_temp_mv_pred.i2_mv[2] = i2_mvX1;\n        s_temp_mv_pred.i2_mv[3] = i2_mvY1;\n\n        /* Calculating colocated zero information */\n        {\n            /*************************************/\n            /* If(bit2 and bit3 set)             */\n            /* then                              */\n            /*  (bit0 and bit1) => submmbmode    */\n            /*  (bit2 and bit3) => mbmode        */\n            /* else                              */\n            /*  (bit0 and bit1) => mbmode        */\n            /*************************************/\n            /*UWORD8 u1_packed_mb_sub_mb_mode = sub_partition ?\n             (s_mvdirect.i1_partitionsize[0]) : ((s_mvdirect.i1_partitionsize[0]) << 2);*/\n            UWORD8 u1_packed_mb_sub_mb_mode = (u1_mb_partw == 2) ? 0x03 : 0;\n\n            if(i1_ref_frame0 < 0)\n            {\n                i2_mv_x = i2_mvX1;\n                i2_mv_y = i2_mvY1;\n            }\n\n            /* Change from left shift 4 to 6 - Varun */\n            u1_colz = (ps_cur_mb_info->u1_mb_field_decodingflag << 1)\n                            | ((u1_final_ref_idx == 0) && (ABS(i2_mv_x) <= 1)\n                                            && (ABS(i2_mv_y) <= 1));\n            u1_colz |= (u1_packed_mb_sub_mb_mode << 6);\n        }\n        ps_mv = ps_mv_nmb_start + u1_sub_mb_num;\n        ih264d_rep_mv_colz(ps_dec, &s_temp_mv_pred, ps_mv, u1_sub_mb_num, u1_colz,\n                           u1_mb_partw, u1_mb_partw);\n        if(u1_wd_x == MB_SIZE)\n            ps_dec->u1_currB_type = 0;\n\n\n\n        return OK;\n    }\n    /***************************************************************************/\n    /* If present MB is 16x16 and the partition of colocated Mb is >= PRED_8x8 */\n    /* i.e 8x8 or less than 8x8 partitions then set up DMA for (0,0) and       */\n    /* spatially predicted motion vector and do the multiplexing after         */\n    /* motion compensation                                                     */\n    /***************************************************************************/\n\n\n    if((u1_wd_x == MB_SIZE) && (s_mvdirect.i1_num_partitions > 2))\n    {\n        ps_cur_mb_info->u1_Mux = 1;\n        if(i1_ref_frame0 >= 0)\n        {\n\n            {\n                pred_info_pkd_t *ps_pred_pkd;\n               WORD8 i1_ref_idx= 0;\n\n               ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n            ih264d_fill_pred_info(&(i2_spat_pred_mv[0]),4,4,0,i1_pred,\n                            ps_pred_pkd,ps_pic_buff0->u1_pic_buf_id,i1_ref_idx,pui32_weight_ofsts,\n                            ps_pic_buff0->u1_pic_type);\n            ps_dec->u4_pred_info_pkd_idx++;\n            ps_cur_mb_info->u1_num_pred_parts++;\n\n\n            }\n\n            /******    (0,0) Motion vectors DMA     *****/\n            {\n                pred_info_pkd_t *ps_pred_pkd;\n               WORD16 i2_mv[2];\n               WORD8 i1_ref_idx= 0;\n\n               i2_mv[0] = 0;\n               i2_mv[1] = 0;\n\n               ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n            ih264d_fill_pred_info(i2_mv,4,4,0,i1_pred,\n                            ps_pred_pkd,ps_pic_buff0->u1_pic_buf_id,i1_ref_idx,pui32_weight_ofsts,\n                            ps_pic_buff0->u1_pic_type);\n            ps_dec->u4_pred_info_pkd_idx++;\n            ps_cur_mb_info->u1_num_pred_parts++;\n\n\n            }\n        }\n        if(i1_ref_frame1 >= 0)\n        {\n            {\n                pred_info_pkd_t *ps_pred_pkd;\n               WORD16 i2_mv[2];\n               WORD8 i1_ref_idx= 0;\n\n               ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n            ih264d_fill_pred_info(&(i2_spat_pred_mv[2]),4,4,0,i1_pred,\n                            ps_pred_pkd,ps_pic_buff1->u1_pic_buf_id,i1_ref_idx,pui32_weight_ofsts,\n                            ps_pic_buff1->u1_pic_type);\n            ps_dec->u4_pred_info_pkd_idx++;\n            ps_cur_mb_info->u1_num_pred_parts++;\n\n\n            }\n\n            /******    (0,0) Motion vectors DMA     *****/\n\n            {\n                pred_info_pkd_t *ps_pred_pkd;\n               WORD16 i2_mv[2];\n               WORD8 i1_ref_idx= 0;\n\n               i2_mv[0] = 0;\n               i2_mv[1] = 0;\n\n               ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n            ih264d_fill_pred_info(i2_mv,4,4,0,i1_pred,\n                            ps_pred_pkd,ps_pic_buff1->u1_pic_buf_id,i1_ref_idx,pui32_weight_ofsts,\n                            ps_pic_buff1->u1_pic_type);\n            ps_dec->u4_pred_info_pkd_idx++;\n            ps_cur_mb_info->u1_num_pred_parts++;\n\n\n            }\n        }\n    }\n\n    /*u1_col = *(ps_col_pic->pu1_col_zero_flag + s_mvdirect.i4_mv_indices[0]);\n     u1_col &= 1;\n     u1_init = 0;*/\n\n    for(i = 0; i < s_mvdirect.i1_num_partitions; i++)\n    {\n        partition_size = s_mvdirect.i1_partitionsize[i];\n        u1_sub_mb_num = s_mvdirect.i1_submb_num[i];\n\n        sub_partition = partition_size >> 2;\n        partition_size &= 0x3;\n        u1_mb_partw = pu1_mb_partw[partition_size];\n        u1_mb_parth = pu1_mb_parth[partition_size];\n        u2_mask = mask_table[partition_size];\n        if(sub_partition != 0)\n        {\n            u1_mb_partw >>= 1;\n            u1_mb_parth >>= 1;\n            u2_mask = sub_mask_table[partition_size];\n        }\n\n        u1_col_zero_flag = *(ps_col_pic->pu1_col_zero_flag\n                        + s_mvdirect.i4_mv_indices[i]);\n        u1_col_zero_flag = u1_col_zero_flag & 0x01;\n\n        /*if(u1_col != u1_col_zero_flag)\n         u1_init = 1;*/\n\n        if(u1_zero_pred_cond_f || ((i1_ref_frame0 == 0) && (u1_col_zero_flag == 1)))\n        {\n            pi2_final_mv0 = &i2_def_mv[0];\n            ui2_mask_fwd |= (u2_mask << u1_sub_mb_num);\n        }\n        else\n            pi2_final_mv0 = &i2_spat_pred_mv[0];\n\n        if(u1_zero_pred_cond_b || ((i1_ref_frame1 == 0) && (u1_col_zero_flag == 1)))\n        {\n            pi2_final_mv1 = &i2_def_mv[0];\n            ui2_mask_bwd |= (u2_mask << u1_sub_mb_num);\n        }\n        else\n            pi2_final_mv1 = &i2_spat_pred_mv[2];\n\n        if(ps_cur_mb_info->u1_Mux != 1)\n        {\n            /*u1_sub_mb_x = u1_sub_mb_num & 0x03;\n             uc_sub_mb_y = (u1_sub_mb_num >> 2);*/\n            if(i1_ref_frame0 >= 0)\n            {\n\n                {\n                    pred_info_pkd_t *ps_pred_pkd;\n                   WORD8 i1_ref_idx= 0;\n\n                   ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n                ih264d_fill_pred_info(pi2_final_mv0,u1_mb_partw,u1_mb_parth,u1_sub_mb_num,i1_pred,\n                                ps_pred_pkd,ps_pic_buff0->u1_pic_buf_id,i1_ref_idx,pui32_weight_ofsts,\n                                ps_pic_buff0->u1_pic_type);\n                ps_dec->u4_pred_info_pkd_idx++;\n                ps_cur_mb_info->u1_num_pred_parts++;\n\n\n                }\n\n            }\n\n            if(i1_ref_frame1 >= 0)\n            {\n                {\n                    pred_info_pkd_t *ps_pred_pkd;\n                   WORD8 i1_ref_idx= 0;\n\n                   ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n                ih264d_fill_pred_info(pi2_final_mv1,u1_mb_partw,u1_mb_parth,u1_sub_mb_num,i1_pred,\n                                ps_pred_pkd,ps_pic_buff1->u1_pic_buf_id,i1_ref_idx,pui32_weight_ofsts,\n                                ps_pic_buff1->u1_pic_type);\n                ps_dec->u4_pred_info_pkd_idx++;\n                ps_cur_mb_info->u1_num_pred_parts++;\n\n\n                }\n            }\n        }\n\n        /* Replication optimisation */\n        s_temp_mv_pred.i2_mv[0] = pi2_final_mv0[0];\n        s_temp_mv_pred.i2_mv[1] = pi2_final_mv0[1];\n        s_temp_mv_pred.i2_mv[2] = pi2_final_mv1[0];\n        s_temp_mv_pred.i2_mv[3] = pi2_final_mv1[1];\n\n        /* Calculating colocated zero information */\n        {\n            WORD16 i2_mv_x = 0, i2_mv_y = 0;\n            /*************************************/\n            /* If(bit2 and bit3 set)             */\n            /* then                              */\n            /*  (bit0 and bit1) => submmbmode    */\n            /*  (bit2 and bit3) => mbmode        */\n            /* else                              */\n            /*  (bit0 and bit1) => mbmode        */\n            /*************************************/\n            UWORD8 u1_packed_mb_sub_mb_mode =\n                            sub_partition ? (s_mvdirect.i1_partitionsize[i]) : ((s_mvdirect.i1_partitionsize[i])\n                                                            << 2);\n\n            if(i1_ref_frame0 >= 0)\n            {\n                i2_mv_x = pi2_final_mv0[0];\n                i2_mv_y = pi2_final_mv0[1];\n            }\n            else\n            {\n                i2_mv_x = pi2_final_mv1[0];\n                i2_mv_y = pi2_final_mv1[1];\n            }\n\n            u1_colz = (ps_cur_mb_info->u1_mb_field_decodingflag << 1)\n                            | ((u1_final_ref_idx == 0) && (ABS(i2_mv_x) <= 1)\n                                            && (ABS(i2_mv_y) <= 1));\n            u1_colz |= (u1_packed_mb_sub_mb_mode << 4);\n        }\n        ps_mv = ps_mv_nmb_start + u1_sub_mb_num;\n        ih264d_rep_mv_colz(ps_dec, &s_temp_mv_pred, ps_mv, u1_sub_mb_num, u1_colz,\n                           u1_mb_parth, u1_mb_partw);\n    }\n    i = 0;\n    if(i1_ref_frame0 >= 0)\n        ps_cur_mb_info->u2_mask[i++] = ui2_mask_fwd;\n    if(i1_ref_frame1 >= 0)\n        ps_cur_mb_info->u2_mask[i] = ui2_mask_bwd;\n\n    /*if(u1_init)\n     H264_DEC_DEBUG_PRINT(\"hit\\n\");\n     else\n     H264_DEC_DEBUG_PRINT(\"miss\\n\");*/\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_decode_temporal_direct \\endif\n *\n * \\brief\n *    Decodes temporal direct mode.\n *\n * \\return\n *    None.\n *\n **************************************************************************\n */\nWORD32 ih264d_decode_temporal_direct(dec_struct_t * ps_dec,\n                                     UWORD8 u1_wd_x,\n                                     dec_mb_info_t * ps_cur_mb_info,\n                                     UWORD8 u1_mb_num)\n{\n    struct pic_buffer_t *ps_pic_buff0, *ps_pic_buff1, *ps_col_pic;\n    mv_pred_t *ps_mv, s_temp_mv_pred;\n    UWORD8 u1_sub_mb_num;\n    UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    WORD16 i2_mv_x0, i2_mv_y0, i2_mv_x1, i2_mv_y1;\n    UWORD8 u1_mb_partw, u1_mb_parth;\n    UWORD8 i, partition_size, sub_partition;\n    UWORD32 *pui32_weight_ofsts = NULL;\n    directmv_t s_mvdirect;\n    const UWORD8 *pu1_mb_parth = (const UWORD8 *)gau1_ih264d_mb_parth;\n    const UWORD8 *pu1_mb_partw = (const UWORD8 *)gau1_ih264d_mb_partw;\n    WORD8 c_refFrm0, c_refFrm1;\n    UWORD8 u1_ref_idx0, u1_is_cur_mb_fld;\n    WORD32 pic0_poc, pic1_poc, cur_poc;\n    WORD32 ret = 0;\n\n    u1_is_cur_mb_fld = ps_cur_mb_info->u1_mb_field_decodingflag;\n    ps_pic_buff1 = ps_dec->ps_ref_pic_buf_lx[1][0];\n\n    /**********************************************************************/\n    /* Call the function which gets the number of partitions and          */\n    /* partition info of colocated Mb                                     */\n    /**********************************************************************/\n    ps_dec->pf_parse_mvdirect(ps_dec, ps_dec->ps_col_pic, &s_mvdirect, u1_wd_x,\n                           ps_dec->i4_submb_ofst, ps_cur_mb_info);\n    ps_col_pic = ps_dec->ps_col_pic;\n\n    for(i = 0; i < s_mvdirect.i1_num_partitions; i++)\n    {\n        UWORD8 u1_colz;\n        partition_size = s_mvdirect.i1_partitionsize[i];\n        u1_sub_mb_num = s_mvdirect.i1_submb_num[i];\n        ps_mv = ps_col_pic->ps_mv + s_mvdirect.i4_mv_indices[i];\n\n        /* This should be removed to catch unitialized memory read */\n        u1_ref_idx0 = 0;\n\n        sub_partition = partition_size >> 2;\n        partition_size &= 0x3;\n        u1_mb_partw = pu1_mb_partw[partition_size];\n        u1_mb_parth = pu1_mb_parth[partition_size];\n        if(sub_partition != 0)\n        {\n            u1_mb_partw >>= 1;\n            u1_mb_parth >>= 1;\n        }\n        c_refFrm0 = ps_mv->i1_ref_frame[0];\n        c_refFrm1 = ps_mv->i1_ref_frame[1];\n\n        if((c_refFrm0 == -1) && (c_refFrm1 == -1))\n        {\n            u1_ref_idx0 = 0;\n            ps_pic_buff0 = ps_dec->ps_ref_pic_buf_lx[0][0];\n            if(u1_mbaff && u1_is_cur_mb_fld)\n            {\n                if(ps_cur_mb_info->u1_topmb)\n                {\n                    pic0_poc = ps_pic_buff0->i4_top_field_order_cnt;\n                    pic1_poc = ps_pic_buff1->i4_top_field_order_cnt;\n                    cur_poc = ps_dec->ps_cur_pic->i4_top_field_order_cnt;\n                }\n                else\n                {\n                    pic1_poc = ps_pic_buff1->i4_bottom_field_order_cnt;\n                    cur_poc = ps_dec->ps_cur_pic->i4_bottom_field_order_cnt;\n                    ps_pic_buff1 = ps_dec->ps_ref_pic_buf_lx[1][MAX_REF_BUFS];\n                    pic0_poc = ps_pic_buff0->i4_bottom_field_order_cnt;\n                    ps_pic_buff0 = ps_dec->ps_ref_pic_buf_lx[0][MAX_REF_BUFS];\n                }\n            }\n            else\n            {\n                pic0_poc = ps_pic_buff0->i4_avg_poc;\n                pic1_poc = ps_pic_buff1->i4_avg_poc;\n                cur_poc = ps_dec->ps_cur_pic->i4_poc;\n            }\n        }\n        else\n        {\n            UWORD8 uc_i, u1_num_frw_ref_pics;\n            UWORD8 buf_id, u1_pic_type;\n            buf_id = ps_mv->u1_col_ref_pic_idx;\n            u1_pic_type = ps_mv->u1_pic_type;\n            if(ps_dec->ps_cur_slice->u1_field_pic_flag)\n            {\n                if(s_mvdirect.u1_vert_mv_scale == FRM_TO_FLD)\n                {\n                    u1_pic_type = TOP_FLD;\n                    if(ps_dec->ps_cur_slice->u1_bottom_field_flag)\n                        u1_pic_type = BOT_FLD;\n                }\n            }\n            u1_num_frw_ref_pics =\n                            ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0];\n\n            for(uc_i = 0; uc_i < u1_num_frw_ref_pics; uc_i++)\n            {\n                if(ps_dec->ps_cur_slice->u1_field_pic_flag)\n                {\n                    if(ps_dec->ps_ref_pic_buf_lx[0][uc_i]->u1_mv_buf_id == buf_id)\n                    {\n                        if(ps_dec->ps_ref_pic_buf_lx[0][uc_i]->u1_pic_type\n                                        == u1_pic_type)\n                        {\n                            u1_ref_idx0 = uc_i;\n                            break;\n                        }\n                    }\n                }\n                else\n                {\n                    if(ps_dec->ps_ref_pic_buf_lx[0][uc_i]->u1_mv_buf_id == buf_id)\n                    {\n                        u1_ref_idx0 = uc_i;\n                        break;\n                    }\n                }\n            }\n\n            ps_pic_buff0 = ps_dec->ps_ref_pic_buf_lx[0][u1_ref_idx0];\n            ps_pic_buff1 = ps_dec->ps_ref_pic_buf_lx[1][0];\n\n            if(u1_mbaff && u1_is_cur_mb_fld)\n            {\n                pic0_poc = ps_pic_buff0->i4_top_field_order_cnt;\n                u1_ref_idx0 <<= 1;\n                if(s_mvdirect.u1_vert_mv_scale == ONE_TO_ONE)\n                {\n                    if(u1_pic_type == BOT_FLD)\n                    {\n                        pic0_poc = ps_pic_buff0->i4_bottom_field_order_cnt;\n                        ps_pic_buff0 = ps_dec->ps_ref_pic_buf_lx[0][(u1_ref_idx0\n                                        >> 1) + MAX_REF_BUFS];\n                        if(ps_cur_mb_info->u1_topmb)\n                            u1_ref_idx0++;\n                    }\n                    else\n                    {\n                        if(1 - ps_cur_mb_info->u1_topmb)\n                            u1_ref_idx0++;\n                    }\n                }\n                if(s_mvdirect.u1_vert_mv_scale == FRM_TO_FLD)\n                {\n                    if(1 - ps_cur_mb_info->u1_topmb)\n                    {\n                        pic0_poc = ps_pic_buff0->i4_bottom_field_order_cnt;\n                        ps_pic_buff0 = ps_dec->ps_ref_pic_buf_lx[0][(u1_ref_idx0\n                                        >> 1) + MAX_REF_BUFS];\n                    }\n                }\n                if(ps_cur_mb_info->u1_topmb)\n                {\n                    pic1_poc = ps_pic_buff1->i4_top_field_order_cnt;\n                    cur_poc = ps_dec->ps_cur_pic->i4_top_field_order_cnt;\n                }\n                else\n                {\n                    pic1_poc = ps_pic_buff1->i4_bottom_field_order_cnt;\n                    cur_poc = ps_dec->ps_cur_pic->i4_bottom_field_order_cnt;\n                    ps_pic_buff1 = ps_dec->ps_ref_pic_buf_lx[1][MAX_REF_BUFS];\n                }\n            }\n            else\n            {\n                pic0_poc = ps_pic_buff0->i4_avg_poc;\n                pic1_poc = ps_pic_buff1->i4_avg_poc;\n                cur_poc = ps_dec->ps_cur_pic->i4_poc;\n            }\n        }\n        {\n            WORD16 i16_td;\n            WORD64 diff;\n            if(c_refFrm0 >= 0)\n            {\n                i2_mv_x0 = ps_mv->i2_mv[0];\n                i2_mv_y0 = ps_mv->i2_mv[1];\n            }\n            else if(c_refFrm1 >= 0)\n            {\n                i2_mv_x0 = ps_mv->i2_mv[2];\n                i2_mv_y0 = ps_mv->i2_mv[3];\n            }\n            else\n            {\n                i2_mv_x0 = 0;\n                i2_mv_y0 = 0;\n            }\n            /* If FRM_TO_FLD or FLD_TO_FRM scale the \"y\" component of the colocated Mv*/\n            if(s_mvdirect.u1_vert_mv_scale == FRM_TO_FLD)\n            {\n                i2_mv_y0 /= 2;\n            }\n            else if(s_mvdirect.u1_vert_mv_scale == FLD_TO_FRM)\n            {\n                i2_mv_y0 *= 2;\n            }\n\n            diff = (WORD64)pic1_poc - pic0_poc;\n            i16_td = CLIP_S8(diff);\n            if((ps_pic_buff0->u1_is_short == 0) || (i16_td == 0))\n            {\n                i2_mv_x1 = 0;\n                i2_mv_y1 = 0;\n            }\n            else\n            {\n                WORD16 i2_tb, i2_tx, i2_dist_scale_factor, i2_temp;\n\n                diff = (WORD64)cur_poc - pic0_poc;\n                i2_tb = CLIP_S8(diff);\n\n                i2_tx = (16384 + ABS(SIGN_POW2_DIV(i16_td, 1))) / i16_td;\n                i2_dist_scale_factor = CLIP_S11(\n                                            (((i2_tb * i2_tx) + 32) >> 6));\n                i2_temp = (i2_mv_x0 * i2_dist_scale_factor + 128) >> 8;\n                i2_mv_x1 = i2_temp - i2_mv_x0;\n                i2_mv_x0 = i2_temp;\n\n                i2_temp = (i2_mv_y0 * i2_dist_scale_factor + 128) >> 8;\n                i2_mv_y1 = i2_temp - i2_mv_y0;\n                i2_mv_y0 = i2_temp;\n            }\n            {\n                mv_pred_t *ps_mv;\n\n                /*u1_sub_mb_x = u1_sub_mb_num & 0x03;\n                 uc_sub_mb_y = u1_sub_mb_num >> 2;*/\n                if(ps_dec->ps_cur_pps->u1_wted_bipred_idc)\n                {\n                    UWORD8 u1_idx =\n                                    u1_ref_idx0\n                                                    * ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1];\n                    UWORD8 u1_scale_ref = u1_mbaff && u1_is_cur_mb_fld;\n                    if(u1_scale_ref)\n                        u1_idx >>= 1;\n                    pui32_weight_ofsts = (UWORD32*)&ps_dec->pu4_wt_ofsts[2\n                                    * X3(u1_idx)];\n                    if(u1_scale_ref\n                                    && (ps_dec->ps_cur_pps->u1_wted_bipred_idc\n                                                    == 2))\n                    {\n                        WORD16 i2_ref_idx;\n                        i2_ref_idx = u1_ref_idx0;\n                        i2_ref_idx *=\n                                        (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1]\n                                                        << 1);\n                        if(!ps_cur_mb_info->u1_topmb)\n                            i2_ref_idx +=\n                                            (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0]\n                                                            << 1)\n                                                            * (ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1]\n                                                                            << 1);\n                        pui32_weight_ofsts =\n                                        (UWORD32*)&ps_dec->pu4_mbaff_wt_mat[2\n                                                        * X3(i2_ref_idx)];\n                    }\n                }\n                {\n                    pred_info_pkd_t *ps_pred_pkd;\n                   WORD16 i2_mv[2];\n                   WORD8 i1_ref_idx= 0;\n\n                   i2_mv[0] = i2_mv_x0;\n                   i2_mv[1] = i2_mv_y0;\n\n                   ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n                ih264d_fill_pred_info(i2_mv,u1_mb_partw,u1_mb_parth,u1_sub_mb_num,PRED_L0 | PRED_L1,\n                                ps_pred_pkd,ps_pic_buff0->u1_pic_buf_id,i1_ref_idx,pui32_weight_ofsts,\n                                ps_pic_buff0->u1_pic_type);\n                ps_dec->u4_pred_info_pkd_idx++;\n                ps_cur_mb_info->u1_num_pred_parts++;\n\n\n                }\n                {\n                   pred_info_pkd_t *ps_pred_pkd;\n                   WORD16 i2_mv[2];\n                   WORD8 i1_ref_idx= 0;\n\n                   i2_mv[0] = i2_mv_x1;\n                   i2_mv[1] = i2_mv_y1;\n\n                   ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n                ih264d_fill_pred_info(i2_mv,u1_mb_partw,u1_mb_parth,u1_sub_mb_num,PRED_L0 | PRED_L1,\n                                ps_pred_pkd,ps_pic_buff1->u1_pic_buf_id,i1_ref_idx,pui32_weight_ofsts,\n                                ps_pic_buff1->u1_pic_type);\n                ps_dec->u4_pred_info_pkd_idx++;\n                ps_cur_mb_info->u1_num_pred_parts++;\n\n\n                }\n\n                /* Replication optimisation */\n                s_temp_mv_pred.i2_mv[0] = i2_mv_x0;\n                s_temp_mv_pred.i2_mv[1] = i2_mv_y0;\n                s_temp_mv_pred.i2_mv[2] = i2_mv_x1;\n                s_temp_mv_pred.i2_mv[3] = i2_mv_y1;\n                s_temp_mv_pred.i1_ref_frame[0] = u1_ref_idx0;\n                s_temp_mv_pred.i1_ref_frame[1] = 0;\n                s_temp_mv_pred.u1_col_ref_pic_idx = ps_pic_buff0->u1_mv_buf_id;\n                s_temp_mv_pred.u1_pic_type = ps_pic_buff0->u1_pic_type;\n                ps_mv = ps_dec->ps_mv_cur + (u1_mb_num << 4) + u1_sub_mb_num;\n\n                {\n                    WORD16 i2_mv_x = 0, i2_mv_y = 0;\n                    UWORD8 u1_packed_mb_sub_mb_mode =\n                                    sub_partition ? (s_mvdirect.i1_partitionsize[i]) : ((s_mvdirect.i1_partitionsize[i])\n                                                                    << 2);\n\n                    if(c_refFrm0 >= 0)\n                    {\n                        i2_mv_x = i2_mv_x0;\n                        i2_mv_y = i2_mv_y0;\n                    }\n                    else\n                    {\n                        i2_mv_x = i2_mv_x1;\n                        i2_mv_y = i2_mv_y1;\n                    }\n\n                    u1_colz =\n                                    (ps_cur_mb_info->u1_mb_field_decodingflag << 1)\n                                                    | ((u1_ref_idx0 == 0)\n                                                                    && (ABS(i2_mv_x)\n                                                                                    <= 1)\n                                                                    && (ABS(i2_mv_y)\n                                                                                    <= 1));\n                    u1_colz |= (u1_packed_mb_sub_mb_mode << 4);\n                }\n                ih264d_rep_mv_colz(ps_dec, &s_temp_mv_pred, ps_mv, u1_sub_mb_num,\n                                   u1_colz, u1_mb_parth, u1_mb_partw);\n            }\n        }\n    }\n    /* return value set to UWORD8 to make it homogeneous  */\n    /* with decodespatialdirect                           */\n    return OK;\n}\n\nvoid ih264d_convert_frm_to_fld_list(struct pic_buffer_t *ps_ref_pic_buf_lx,\n                                    UWORD8 *pu1_L0,\n                                    dec_struct_t *ps_dec,\n                                    UWORD8 u1_num_short_term_bufs)\n{\n    UWORD8 uc_count = *pu1_L0, i, uc_l1, uc_lx, j;\n    struct pic_buffer_t *ps_ref_lx[2], *ps_ref_pic_lx;\n    UWORD8 u1_bottom_field_flag;\n    dec_slice_params_t *ps_cur_slice;\n    UWORD8 u1_ref[2], u1_fld[2], u1_same_fld, u1_op_fld;\n    UWORD32 ui_half_num_of_sub_mbs;\n\n    uc_l1 = 0;\n    uc_lx = 0;\n    ps_cur_slice = ps_dec->ps_cur_slice;\n    ps_ref_pic_lx = ps_ref_pic_buf_lx - MAX_REF_BUFS;\n    ps_ref_lx[0] = ps_ref_pic_buf_lx;\n    ps_ref_lx[1] = ps_ref_pic_buf_lx;\n    u1_bottom_field_flag = ps_cur_slice->u1_bottom_field_flag;\n    ui_half_num_of_sub_mbs = ((ps_dec->u2_pic_ht * ps_dec->u2_pic_wd) >> 5);\n    if(u1_bottom_field_flag)\n    {\n        u1_ref[0] = BOT_REF;\n        u1_ref[1] = TOP_REF;\n        u1_fld[0] = BOT_FLD;\n        u1_fld[1] = TOP_FLD;\n        u1_same_fld = BOT_FLD;\n        u1_op_fld = TOP_FLD;\n    }\n    else\n    {\n        u1_ref[0] = TOP_REF;\n        u1_ref[1] = BOT_REF;\n        u1_fld[0] = TOP_FLD;\n        u1_fld[1] = BOT_FLD;\n        u1_same_fld = TOP_FLD;\n        u1_op_fld = BOT_FLD;\n    }\n\n    /* Create the field list starting with all the short term     */\n    /* frames followed by all the long term frames. No long term  */\n    /* reference field should have a list idx less than a short   */\n    /* term reference field during initiailization.               */\n\n    for(j = 0; j < 2; j++)\n    {\n        i = ((j == 0) ? 0 : u1_num_short_term_bufs);\n        uc_count = ((j == 0) ? u1_num_short_term_bufs : *pu1_L0);\n        for(; i < uc_count; i++, ps_ref_lx[0]++)\n        {\n            /* Search field of same parity in Frame list */\n            if((ps_ref_lx[0]->u1_pic_type & u1_ref[0])) // || ((ps_ref_lx[0]->u1_picturetype & 0x3) == 0))\n            {\n                /* Insert PIC of same parity in RefPicList */\n                ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_lx, ps_ref_lx[0]);\n                ps_ref_pic_lx->i4_pic_num = (ps_ref_pic_lx->i4_pic_num * 2 + 1);\n                ps_ref_pic_lx->u1_long_term_pic_num =\n                                (ps_ref_pic_lx->u1_long_term_frm_idx * 2 + 1);\n                ps_ref_pic_lx->u1_pic_type = u1_same_fld;\n                if(u1_fld[0] & BOT_FLD)\n                {\n                    ps_ref_pic_lx->u1_pic_type = BOT_FLD;\n                    ps_ref_pic_lx->pu1_buf1 += ps_ref_pic_lx->u2_frm_wd_y;\n                    ps_ref_pic_lx->pu1_buf2 += ps_ref_pic_lx->u2_frm_wd_uv;\n                    ps_ref_pic_lx->pu1_buf3 += ps_ref_pic_lx->u2_frm_wd_uv;\n                    if(ps_ref_pic_lx->u1_picturetype & 0x3)\n                    {\n                        ps_ref_pic_lx->pu1_col_zero_flag += ui_half_num_of_sub_mbs;\n                        ps_ref_pic_lx->ps_mv += ui_half_num_of_sub_mbs;\n                    }\n                    ps_ref_pic_lx->i4_poc =\n                                    ps_ref_pic_lx->i4_bottom_field_order_cnt;\n                    ps_ref_pic_lx->i4_avg_poc =\n                                    ps_ref_pic_lx->i4_bottom_field_order_cnt;\n                }\n                else\n                {\n                    ps_ref_pic_lx->u1_pic_type = TOP_FLD;\n                    ps_ref_pic_lx->i4_poc = ps_ref_pic_lx->i4_top_field_order_cnt;\n                    ps_ref_pic_lx->i4_avg_poc =\n                                    ps_ref_pic_lx->i4_top_field_order_cnt;\n                }\n\n                ps_ref_pic_lx++;\n                uc_lx++;\n                /* Find field of opposite parity */\n                if(uc_l1 < uc_count && ps_ref_lx[1])\n                {\n                    while(!(ps_ref_lx[1]->u1_pic_type & u1_ref[1]))\n                    {\n                        ps_ref_lx[1]++;\n                        uc_l1++;\n                        if(uc_l1 >= uc_count)\n                            ps_ref_lx[1] = 0;\n                        if(!ps_ref_lx[1])\n                            break;\n                    }\n\n                    if(ps_ref_lx[1])\n                    {\n                        uc_l1++;\n                        ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_lx,\n                                                           ps_ref_lx[1]);\n                        ps_ref_pic_lx->u1_pic_type = u1_op_fld;\n                        ps_ref_pic_lx->i4_pic_num = (ps_ref_pic_lx->i4_pic_num * 2);\n                        ps_ref_pic_lx->u1_long_term_pic_num =\n                                        (ps_ref_pic_lx->u1_long_term_frm_idx * 2);\n                        if(u1_fld[1] & BOT_FLD)\n                        {\n                            ps_ref_pic_lx->u1_pic_type = BOT_FLD;\n                            ps_ref_pic_lx->pu1_buf1 += ps_ref_pic_lx->u2_frm_wd_y;\n                            ps_ref_pic_lx->pu1_buf2 += ps_ref_pic_lx->u2_frm_wd_uv;\n                            ps_ref_pic_lx->pu1_buf3 += ps_ref_pic_lx->u2_frm_wd_uv;\n                            if(ps_ref_pic_lx->u1_picturetype & 0x3)\n                            {\n                                ps_ref_pic_lx->pu1_col_zero_flag +=\n                                                ui_half_num_of_sub_mbs;\n                                ps_ref_pic_lx->ps_mv += ui_half_num_of_sub_mbs;\n                            }\n                            ps_ref_pic_lx->i4_poc =\n                                            ps_ref_pic_lx->i4_bottom_field_order_cnt;\n                            ps_ref_pic_lx->i4_avg_poc =\n                                            ps_ref_pic_lx->i4_bottom_field_order_cnt;\n                        }\n                        else\n                        {\n                            ps_ref_pic_lx->u1_pic_type = TOP_FLD;\n                            ps_ref_pic_lx->i4_poc =\n                                            ps_ref_pic_lx->i4_top_field_order_cnt;\n                            ps_ref_pic_lx->i4_avg_poc =\n                                            ps_ref_pic_lx->i4_top_field_order_cnt;\n                        }\n                        ps_ref_pic_lx++;\n                        uc_lx++;\n                        ps_ref_lx[1]++;\n                    }\n                }\n            }\n        }\n\n        /* Same parity fields are over, now insert left over opposite parity fields */\n        /** Added  if(ps_ref_lx[1]) for error checks */\n        if(ps_ref_lx[1])\n        {\n            for(; uc_l1 < uc_count; uc_l1++)\n            {\n                if(ps_ref_lx[1]->u1_pic_type & u1_ref[1])\n                {\n                    /* Insert PIC of opposite parity in RefPicList */\n                    ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_lx,\n                                                       ps_ref_lx[1]);\n                    ps_ref_pic_lx->u1_pic_type = u1_op_fld;\n                    ps_ref_pic_lx->i4_pic_num = (ps_ref_pic_lx->i4_pic_num * 2);\n                    ps_ref_pic_lx->u1_long_term_pic_num =\n                                    (ps_ref_pic_lx->u1_long_term_frm_idx * 2);\n                    if(u1_op_fld == BOT_FLD)\n                    {\n                        ps_ref_pic_lx->u1_pic_type = BOT_FLD;\n                        ps_ref_pic_lx->pu1_buf1 += ps_ref_pic_lx->u2_frm_wd_y;\n                        ps_ref_pic_lx->pu1_buf2 += ps_ref_pic_lx->u2_frm_wd_uv;\n                        ps_ref_pic_lx->pu1_buf3 += ps_ref_pic_lx->u2_frm_wd_uv;\n                        if(ps_ref_pic_lx->u1_picturetype & 0x3)\n                        {\n                            ps_ref_pic_lx->pu1_col_zero_flag +=\n                                            ui_half_num_of_sub_mbs;\n                            ps_ref_pic_lx->ps_mv += ui_half_num_of_sub_mbs;\n                        }\n                        ps_ref_pic_lx->i4_poc =\n                                        ps_ref_pic_lx->i4_bottom_field_order_cnt;\n                        ps_ref_pic_lx->i4_avg_poc =\n                                        ps_ref_pic_lx->i4_bottom_field_order_cnt;\n                    }\n                    else\n                    {\n                        ps_ref_pic_lx->i4_poc =\n                                        ps_ref_pic_lx->i4_top_field_order_cnt;\n                        ps_ref_pic_lx->i4_avg_poc =\n                                        ps_ref_pic_lx->i4_top_field_order_cnt;\n                    }\n                    ps_ref_pic_lx++;\n                    uc_lx++;\n                    ps_ref_lx[1]++;\n                }\n            }\n        }\n    }\n    *pu1_L0 = uc_lx;\n}\n\nvoid ih264d_convert_frm_mbaff_list(dec_struct_t *ps_dec)\n{\n    struct pic_buffer_t **ps_ref_pic_lx;\n    UWORD8 u1_max_ref_idx, idx;\n    UWORD16 u2_frm_wd_y, u2_frm_wd_uv;\n    struct pic_buffer_t **ps_ref_pic_buf_lx;\n    UWORD32 u4_half_num_of_sub_mbs = ((ps_dec->u2_pic_ht * ps_dec->u2_pic_wd) >> 5);\n\n    ps_ref_pic_buf_lx = ps_dec->ps_ref_pic_buf_lx[0];\n    ps_ref_pic_lx = ps_dec->ps_ref_pic_buf_lx[0];\n    u1_max_ref_idx = ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[0];\n    for(idx = 0; idx < u1_max_ref_idx; idx++)\n    {\n        ps_ref_pic_lx[idx]->u1_pic_type = TOP_FLD;\n        ps_ref_pic_lx[idx]->i4_poc = ps_ref_pic_lx[idx]->i4_top_field_order_cnt;\n\n    }\n    u2_frm_wd_y = ps_dec->u2_frm_wd_y;\n    u2_frm_wd_uv = ps_dec->u2_frm_wd_uv;\n\n    for(idx = 0; idx < u1_max_ref_idx; idx++)\n    {\n        *ps_ref_pic_lx[idx + MAX_REF_BUFS] = *ps_ref_pic_buf_lx[idx];\n        ps_ref_pic_lx[idx + MAX_REF_BUFS]->pu1_buf1 =\n                        ps_ref_pic_buf_lx[idx]->pu1_buf1 + u2_frm_wd_y;\n        ps_ref_pic_lx[idx + MAX_REF_BUFS]->pu1_buf2 =\n                        ps_ref_pic_buf_lx[idx]->pu1_buf2 + u2_frm_wd_uv;\n        ps_ref_pic_lx[idx + MAX_REF_BUFS]->pu1_buf3 =\n                        ps_ref_pic_buf_lx[idx]->pu1_buf3 + u2_frm_wd_uv;\n\n        ps_ref_pic_lx[idx + MAX_REF_BUFS]->u1_pic_type = BOT_FLD;\n        ps_ref_pic_lx[idx + MAX_REF_BUFS]->i4_poc =\n                        ps_ref_pic_buf_lx[idx]->i4_bottom_field_order_cnt;\n        if(ps_ref_pic_buf_lx[idx]->u1_picturetype & 0x3)\n        {\n            ps_ref_pic_lx[idx + MAX_REF_BUFS]->pu1_col_zero_flag =\n                            ps_ref_pic_buf_lx[idx]->pu1_col_zero_flag\n                                            + u4_half_num_of_sub_mbs;\n            ps_ref_pic_lx[idx + MAX_REF_BUFS]->ps_mv =\n                            ps_ref_pic_buf_lx[idx]->ps_mv + u4_half_num_of_sub_mbs;\n        }\n    }\n\n    if(ps_dec->u1_B)\n    {\n        ps_ref_pic_buf_lx = ps_dec->ps_ref_pic_buf_lx[1];\n        ps_ref_pic_lx = ps_dec->ps_ref_pic_buf_lx[1];\n        u1_max_ref_idx = ps_dec->ps_cur_slice->u1_num_ref_idx_lx_active[1];\n        for(idx = 0; idx < u1_max_ref_idx; idx++)\n        {\n            ps_ref_pic_lx[idx]->u1_pic_type = TOP_FLD;\n            ps_ref_pic_lx[idx]->i4_poc = ps_ref_pic_lx[idx]->i4_top_field_order_cnt;\n\n        }\n\n        for(idx = 0; idx < u1_max_ref_idx; idx++)\n        {\n            *ps_ref_pic_lx[idx + MAX_REF_BUFS] = *ps_ref_pic_buf_lx[idx];\n            ps_ref_pic_lx[idx + MAX_REF_BUFS]->pu1_buf1 =\n                            ps_ref_pic_buf_lx[idx]->pu1_buf1 + u2_frm_wd_y;\n            ps_ref_pic_lx[idx + MAX_REF_BUFS]->pu1_buf2 =\n                            ps_ref_pic_buf_lx[idx]->pu1_buf2 + u2_frm_wd_uv;\n            ps_ref_pic_lx[idx + MAX_REF_BUFS]->pu1_buf3 =\n                            ps_ref_pic_buf_lx[idx]->pu1_buf3 + u2_frm_wd_uv;\n            ps_ref_pic_lx[idx + MAX_REF_BUFS]->u1_pic_type = BOT_FLD;\n            ps_ref_pic_lx[idx + MAX_REF_BUFS]->i4_poc =\n                            ps_ref_pic_buf_lx[idx]->i4_bottom_field_order_cnt;\n\n            if(ps_ref_pic_buf_lx[idx]->u1_picturetype & 0x3)\n            {\n                ps_ref_pic_lx[idx + MAX_REF_BUFS]->pu1_col_zero_flag =\n                                ps_ref_pic_buf_lx[idx]->pu1_col_zero_flag\n                                                + u4_half_num_of_sub_mbs;\n                ps_ref_pic_lx[idx + MAX_REF_BUFS]->ps_mv =\n                                ps_ref_pic_buf_lx[idx]->ps_mv\n                                                + u4_half_num_of_sub_mbs;\n            }\n        }\n    }\n}\nstatic int poc_compare(const void *pv_pic1, const void *pv_pic2)\n{\n    struct pic_buffer_t *ps_pic1 = *(struct pic_buffer_t **) pv_pic1;\n    struct pic_buffer_t *ps_pic2 = *(struct pic_buffer_t **) pv_pic2;\n    if (ps_pic1->i4_poc < ps_pic2->i4_poc)\n    {\n        return -1;\n    }\n    else if (ps_pic1->i4_poc > ps_pic2->i4_poc)\n    {\n        return 1;\n    }\n    else\n    {\n        return 0;\n    }\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_init_ref_idx_lx_b \\endif\n *\n * \\brief\n *    Initializes forward and backward refernce lists for B slice decoding.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nvoid ih264d_init_ref_idx_lx_b(dec_struct_t *ps_dec)\n{\n    struct pic_buffer_t *ps_ref_pic_buf_lx;\n    dpb_manager_t *ps_dpb_mgr;\n    struct dpb_info_t *ps_next_dpb;\n    WORD32 i_cur_poc, i_max_st_poc, i_min_st_poc, i_ref_poc, i_temp_poc;\n    WORD8 i, j;\n    UWORD8 u1_max_lt_index, u1_min_lt_index;\n    UWORD32 u4_lt_index;\n    WORD32 i_cur_idx;\n    UWORD8 u1_field_pic_flag;\n    dec_slice_params_t *ps_cur_slice;\n    UWORD8 u1_L0, u1_L1;\n    UWORD8 u1_num_short_term_bufs;\n    UWORD8 u1_max_ref_idx_l0, u1_max_ref_idx_l1;\n    struct pic_buffer_t *aps_st_pic_bufs[2 * MAX_REF_BUFS] = {NULL};\n    ps_cur_slice = ps_dec->ps_cur_slice;\n    u1_field_pic_flag = ps_cur_slice->u1_field_pic_flag;\n    u1_max_ref_idx_l0 = ps_cur_slice->u1_num_ref_idx_lx_active[0]\n                    << u1_field_pic_flag;\n    u1_max_ref_idx_l1 = ps_cur_slice->u1_num_ref_idx_lx_active[1]\n                    << u1_field_pic_flag;\n\n    ps_dpb_mgr = ps_dec->ps_dpb_mgr;\n    /* Get the current POC */\n    i_cur_poc = ps_dec->ps_cur_pic->i4_poc;\n\n    /* Get MaxStPOC,MinStPOC,MaxLt,MinLt */\n    i_max_st_poc = i_cur_poc;\n    i_min_st_poc = i_cur_poc;\n    u1_max_lt_index = MAX_REF_BUFS + 1;\n    u1_min_lt_index = MAX_REF_BUFS + 1;\n    /* Start from ST head */\n    ps_next_dpb = ps_dpb_mgr->ps_dpb_st_head;\n    for(i = 0; i < ps_dpb_mgr->u1_num_st_ref_bufs; i++)\n    {\n        i_ref_poc = ps_next_dpb->ps_pic_buf->i4_poc;\n        if(i_ref_poc < i_cur_poc)\n        {\n            /* RefPic Buf POC is before Current POC in display order */\n            i_min_st_poc = MIN(i_min_st_poc, i_ref_poc);\n        }\n        else\n        {\n            /* RefPic Buf POC is after Current POC in display order */\n            i_max_st_poc = MAX(i_max_st_poc, i_ref_poc);\n        }\n\n        /* Chase the next link */\n        ps_next_dpb = ps_next_dpb->ps_prev_short;\n    }\n\n    /* Sort ST ref pocs in ascending order */\n    ps_next_dpb = ps_dpb_mgr->ps_dpb_st_head;\n    for (j = 0; j < ps_dpb_mgr->u1_num_st_ref_bufs; j++)\n    {\n        aps_st_pic_bufs[j] = ps_next_dpb->ps_pic_buf;\n        ps_next_dpb = ps_next_dpb->ps_prev_short;\n    }\n    qsort(aps_st_pic_bufs, ps_dpb_mgr->u1_num_st_ref_bufs,\n        sizeof(aps_st_pic_bufs[0]), poc_compare);\n\n    /* Start from LT head */\n    ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;\n    if(ps_next_dpb)\n    {\n        u1_max_lt_index = ps_next_dpb->u1_lt_idx;\n        u1_min_lt_index = ps_next_dpb->u1_lt_idx;\n    }\n    for(i = 0; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)\n    {\n        u4_lt_index = ps_next_dpb->u1_lt_idx;\n        u1_max_lt_index = (UWORD8)(MAX(u1_max_lt_index, u4_lt_index));\n        u1_min_lt_index = (UWORD8)(MIN(u1_min_lt_index, u4_lt_index));\n\n        /* Chase the next link */\n        ps_next_dpb = ps_next_dpb->ps_prev_long;\n    }\n\n    /* 1. Initialize refIdxL0 */\n    u1_L0 = 0;\n    i_temp_poc = i_cur_poc;\n    if(u1_field_pic_flag)\n    {\n        ps_ref_pic_buf_lx = ps_dpb_mgr->ps_init_dpb[0][0];\n        ps_ref_pic_buf_lx += MAX_REF_BUFS;\n    }\n    else\n    {\n        ps_ref_pic_buf_lx = ps_dpb_mgr->ps_init_dpb[0][0];\n        /* Avoid integer overflow while decrementing by one */\n        if (i_temp_poc > INT32_MIN)\n            i_temp_poc--;\n    }\n\n    i_cur_idx = -1;\n    for(j = 0; j < ps_dpb_mgr->u1_num_st_ref_bufs; j++)\n    {\n        if (NULL == aps_st_pic_bufs[j])\n        {\n            break;\n        }\n        if (aps_st_pic_bufs[j]->i4_poc <= i_temp_poc)\n        {\n            i_cur_idx = j;\n        }\n    }\n    /* Arrange all short term buffers in output order as given by POC */\n    /* 1.1 Arrange POC's less than CurrPOC in the descending POC order starting\n     from (CurrPOC - 1)*/\n    for(j = i_cur_idx; j >= 0; j--)\n    {\n        if(aps_st_pic_bufs[j])\n        {\n            /* Copy info in pic buffer */\n            ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,\n                                               aps_st_pic_bufs[j]);\n            ps_ref_pic_buf_lx++;\n            u1_L0++;\n        }\n    }\n\n    /* 1.2. Arrange POC's more than CurrPOC in the ascending POC order starting\n     from (CurrPOC + 1)*/\n    for(j = i_cur_idx + 1; j < ps_dpb_mgr->u1_num_st_ref_bufs; j++)\n    {\n        if(aps_st_pic_bufs[j])\n        {\n            ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,\n                                               aps_st_pic_bufs[j]);\n            ps_ref_pic_buf_lx++;\n            u1_L0++;\n        }\n    }\n\n    /* 1.3 Arrange all Long term buffers in ascending order, in LongtermIndex */\n    /* Start from ST head */\n\n    u1_num_short_term_bufs = u1_L0;\n    for(u4_lt_index = u1_min_lt_index; u4_lt_index <= u1_max_lt_index; u4_lt_index++)\n    {\n        ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;\n        for(i = 0; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)\n        {\n            if(ps_next_dpb->u1_lt_idx == u4_lt_index)\n            {\n                ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,\n                                                   ps_next_dpb->ps_pic_buf);\n                ps_ref_pic_buf_lx->u1_long_term_pic_num =\n                                ps_ref_pic_buf_lx->u1_long_term_frm_idx;\n\n                ps_ref_pic_buf_lx++;\n                u1_L0++;\n                break;\n            }\n            ps_next_dpb = ps_next_dpb->ps_prev_long;\n        }\n    }\n\n    if(u1_field_pic_flag)\n    {\n        /* Initialize the rest of the entries in the */\n        /* reference list to handle of errors        */\n        {\n            UWORD8 u1_i;\n            pic_buffer_t ref_pic;\n\n            ref_pic = *(ps_dpb_mgr->ps_init_dpb[0][0] + MAX_REF_BUFS);\n\n            if(NULL == ref_pic.pu1_buf1)\n            {\n                ref_pic = *ps_dec->ps_cur_pic;\n            }\n            for(u1_i = u1_L0; u1_i < u1_max_ref_idx_l0; u1_i++)\n            {\n                *ps_ref_pic_buf_lx = ref_pic;\n                ps_ref_pic_buf_lx++;\n            }\n        }\n        ih264d_convert_frm_to_fld_list(\n                        ps_dpb_mgr->ps_init_dpb[0][0] + MAX_REF_BUFS, &u1_L0,\n                        ps_dec, u1_num_short_term_bufs);\n\n        ps_ref_pic_buf_lx = ps_dpb_mgr->ps_init_dpb[0][0] + u1_L0;\n    }\n\n    ps_dec->ps_cur_slice->u1_initial_list_size[0] = u1_L0;\n\n    /* Initialize the rest of the entries in the */\n    /* reference list to handle of errors        */\n    {\n        UWORD8 u1_i;\n        pic_buffer_t ref_pic;\n\n        ref_pic = *(ps_dpb_mgr->ps_init_dpb[0][0]);\n\n        if(NULL == ref_pic.pu1_buf1)\n        {\n            ref_pic = *ps_dec->ps_cur_pic;\n        }\n        for(u1_i = u1_L0; u1_i < u1_max_ref_idx_l0; u1_i++)\n        {\n            *ps_ref_pic_buf_lx = ref_pic;\n            ps_ref_pic_buf_lx++;\n        }\n    }\n    {\n        /* 2. Initialize refIdxL1 */\n        u1_L1 = 0;\n        if(u1_field_pic_flag)\n        {\n            ps_ref_pic_buf_lx = ps_dpb_mgr->ps_init_dpb[1][0] + MAX_REF_BUFS;\n        }\n        else\n        {\n            ps_ref_pic_buf_lx = ps_dpb_mgr->ps_init_dpb[1][0];\n        }\n\n        /* 2.1. Arrange POC's more than CurrPOC in the ascending POC order starting\n         from (CurrPOC + 1)*/\n        for(j = i_cur_idx + 1; j < ps_dpb_mgr->u1_num_st_ref_bufs; j++)\n        {\n            if(aps_st_pic_bufs[j])\n            {\n                /* Start from ST head */\n                ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,\n                                                   aps_st_pic_bufs[j]);\n                ps_ref_pic_buf_lx++;\n                u1_L1++;\n            }\n        }\n\n        /* Arrange all short term buffers in output order as given by POC */\n        /* 2.2 Arrange POC's less than CurrPOC in the descending POC order starting\n         from (CurrPOC - 1)*/\n        for(j = i_cur_idx; j >= 0; j--)\n        {\n            if(aps_st_pic_bufs[j])\n            {\n                ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,\n                                                   aps_st_pic_bufs[j]);\n                ps_ref_pic_buf_lx++;\n                u1_L1++;\n            }\n        }\n\n        /* 2.3 Arrange all Long term buffers in ascending order, in LongtermIndex */\n        /* Start from ST head */\n        u1_num_short_term_bufs = u1_L1;\n\n        for(u4_lt_index = u1_min_lt_index; u4_lt_index <= u1_max_lt_index;\n                        u4_lt_index++)\n        {\n            ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;\n            for(i = 0; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)\n            {\n                if(ps_next_dpb->u1_lt_idx == u4_lt_index)\n                {\n                    ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,\n                                                       ps_next_dpb->ps_pic_buf);\n                    ps_ref_pic_buf_lx->u1_long_term_pic_num =\n                                    ps_ref_pic_buf_lx->u1_long_term_frm_idx;\n                    ps_ref_pic_buf_lx++;\n                    u1_L1++;\n                    break;\n                }\n                ps_next_dpb = ps_next_dpb->ps_prev_long;\n            }\n        }\n\n        if(u1_field_pic_flag)\n        {\n            /* Initialize the rest of the entries in the */\n            /* reference list to handle of errors        */\n            {\n                UWORD8 u1_i;\n                pic_buffer_t ref_pic;\n\n                ref_pic = *(ps_dpb_mgr->ps_init_dpb[0][0] + MAX_REF_BUFS);\n\n                if(NULL == ref_pic.pu1_buf1)\n                {\n                    ref_pic = *ps_dec->ps_cur_pic;\n                }\n                for(u1_i = u1_L1; u1_i < u1_max_ref_idx_l1; u1_i++)\n                {\n                    *ps_ref_pic_buf_lx = ref_pic;\n                    ps_ref_pic_buf_lx++;\n                }\n            }\n\n            ih264d_convert_frm_to_fld_list(\n                            ps_dpb_mgr->ps_init_dpb[1][0] + MAX_REF_BUFS,\n                            &u1_L1, ps_dec, u1_num_short_term_bufs);\n            ps_ref_pic_buf_lx = ps_dpb_mgr->ps_init_dpb[1][0] + u1_L1;\n        }\n\n        ps_dec->ps_cur_slice->u1_initial_list_size[1] = u1_L1;\n\n        /* Initialize the rest of the entries in the */\n        /* reference list to handle of errors        */\n        {\n            UWORD8 u1_i;\n            pic_buffer_t ref_pic;\n\n            ref_pic = *(ps_dpb_mgr->ps_init_dpb[0][0]);\n\n            if(NULL == ref_pic.pu1_buf1)\n            {\n                ref_pic = *ps_dec->ps_cur_pic;\n            }\n            for(u1_i = u1_L1; u1_i < u1_max_ref_idx_l1; u1_i++)\n            {\n                *ps_ref_pic_buf_lx = ref_pic;\n                ps_ref_pic_buf_lx++;\n            }\n        }\n\n        /* If list0 and list 1 ebtries are same then swap the 0th and 1st entry */\n        /* of list 1                                                            */\n        {\n            struct pic_buffer_t *ps_ref_pic1_buf_l0, *ps_ref_pic1_buf_l1;\n            struct pic_buffer_t s_ref_pic1_buf_temp;\n\n            ps_ref_pic1_buf_l0 = ps_dpb_mgr->ps_init_dpb[0][0];\n            ps_ref_pic1_buf_l1 = ps_dpb_mgr->ps_init_dpb[1][0];\n\n            if((u1_L0 == u1_L1) && (u1_L0 > 1))\n            {\n                WORD32 i_index, i_swap;\n\n                i_swap = 1;\n\n                for(i_index = 0; i_index < u1_L0; i_index++)\n                {\n                    if((ps_ref_pic1_buf_l0[i_index]).pu1_buf1\n                                    != (ps_ref_pic1_buf_l1[i_index]).pu1_buf1)\n                    {\n                        i_swap = 0;\n                        break;\n                    }\n                }\n                if(1 == i_swap)\n                {\n                    memcpy(&s_ref_pic1_buf_temp, &ps_ref_pic1_buf_l1[1],\n                           sizeof(struct pic_buffer_t));\n                    memcpy(&ps_ref_pic1_buf_l1[1], &ps_ref_pic1_buf_l1[0],\n                           sizeof(struct pic_buffer_t));\n                    memcpy(&ps_ref_pic1_buf_l1[0], &s_ref_pic1_buf_temp,\n                           sizeof(struct pic_buffer_t));\n                }\n            }\n        }\n    }\n}\n\n\n\nvoid ih264d_get_implicit_weights(dec_struct_t *ps_dec);\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_one_to_one \\endif\n *\n * \\brief\n *    Initializes forward and backward refernce lists for B slice decoding.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nvoid ih264d_one_to_one(dec_struct_t *ps_dec,\n                       struct pic_buffer_t *ps_col_pic,\n                       directmv_t *ps_direct,\n                       UWORD8 u1_wd_x,\n                       WORD32 u2_sub_mb_ofst,\n                       dec_mb_info_t * ps_cur_mb_info)\n{\n    UWORD8 *pu1_col_zero_flag_start, u1_col_mb_pred_mode, u1_num_blks, u1_sub_mb_num;\n    UWORD8 u1_init_colzero_flag;\n    UNUSED(ps_cur_mb_info);\n    pu1_col_zero_flag_start = ps_col_pic->pu1_col_zero_flag + u2_sub_mb_ofst;\n    u1_col_mb_pred_mode = pu1_col_zero_flag_start[ps_dec->u1_sub_mb_num];\n    u1_init_colzero_flag = u1_col_mb_pred_mode & 1;\n    u1_col_mb_pred_mode >>= 6;\n    ps_direct->u1_vert_mv_scale = ONE_TO_ONE;\n    ps_direct->u1_col_zeroflag_change = 0;\n\n    if(u1_wd_x == MB_SIZE)\n    {\n        ps_dec->u1_currB_type = (!!u1_col_mb_pred_mode);\n        if(u1_col_mb_pred_mode == PRED_16x16)\n        {\n            ps_direct->i1_num_partitions = 1;\n            ps_direct->i4_mv_indices[0] = u2_sub_mb_ofst;\n            ps_direct->i1_submb_num[0] = 0;\n            ps_direct->i1_partitionsize[0] = PRED_16x16;\n\n            return;\n        }\n        else if(u1_col_mb_pred_mode < PRED_8x8)\n        {\n            ps_direct->i1_num_partitions = 2;\n            ps_direct->i4_mv_indices[0] = u2_sub_mb_ofst;\n            ps_direct->i1_submb_num[0] = 0;\n            ps_direct->i1_partitionsize[0] = u1_col_mb_pred_mode;\n            u1_sub_mb_num = (u1_col_mb_pred_mode == PRED_16x8) ? 8 : 2;\n            ps_direct->i1_submb_num[1] = u1_sub_mb_num;\n            ps_direct->i4_mv_indices[1] = u2_sub_mb_ofst\n                            + ps_direct->i1_submb_num[1];\n            ps_direct->i1_partitionsize[1] = u1_col_mb_pred_mode;\n            if((pu1_col_zero_flag_start[u1_sub_mb_num] & 1) != u1_init_colzero_flag)\n                ps_direct->u1_col_zeroflag_change = 1;\n            return;\n        }\n        else\n        {\n            u1_num_blks = 4;\n        }\n    }\n    else\n    {\n        u1_num_blks = 1;\n    }\n\n    {\n        const UWORD8 *pu1_top_lt_mb_part_idx;\n        UWORD8 u1_col_sub_mb_pred_mode, uc_blk, u1_sub_blk, u1_submb_col = 0;\n        UWORD8 u1_num_sub_blks, uc_direct8x8inf, *pu1_col_zero_flag, u1_sub_mb_num;\n        const UWORD8 *pu1_num_sub_mb_part =\n                        (const UWORD8 *)gau1_ih264d_num_submb_part;\n        UWORD8 i1_num_partitions = 0, partition_size;\n        WORD32 mv_index;\n        const UWORD8 *pu1_top_lt_sub_mb_idx = gau1_ih264d_submb_indx_mod_sp_drct;\n\n        u1_sub_mb_num = ps_dec->u1_sub_mb_num;\n        uc_direct8x8inf = ps_dec->ps_cur_slice->u1_direct_8x8_inference_flag;\n        pu1_top_lt_mb_part_idx = gau1_ih264d_top_left_mb_part_indx_mod\n                        + (PRED_8x8 << 1) + 1;\n\n        for(uc_blk = 0; uc_blk < u1_num_blks; uc_blk++)\n        {\n            partition_size = PRED_8x8;\n            pu1_top_lt_sub_mb_idx = gau1_ih264d_submb_indx_mod_sp_drct;\n            if(uc_direct8x8inf == 1)\n            {\n                u1_submb_col = u1_sub_mb_num | (u1_sub_mb_num >> 1);\n                mv_index = u2_sub_mb_ofst + u1_submb_col;\n                u1_num_sub_blks = 1;\n            }\n            else\n            {\n                /* colMbPart is either 8x8, 8x4, 4x8, 4x4 */\n                pu1_col_zero_flag = pu1_col_zero_flag_start + u1_sub_mb_num;\n                u1_col_sub_mb_pred_mode = *pu1_col_zero_flag;\n                u1_col_sub_mb_pred_mode = (u1_col_sub_mb_pred_mode & 0x30) >> 4;\n                partition_size = (UWORD8)((u1_col_sub_mb_pred_mode)\n                                | (PRED_8x8 << 2));\n                mv_index = u2_sub_mb_ofst + u1_sub_mb_num;\n                pu1_top_lt_sub_mb_idx += (u1_col_sub_mb_pred_mode << 1);\n                u1_num_sub_blks = pu1_num_sub_mb_part[u1_col_sub_mb_pred_mode];\n\n            }\n\n            for(u1_sub_blk = 0; u1_sub_blk < u1_num_sub_blks;\n                            u1_sub_blk++, pu1_top_lt_sub_mb_idx++)\n            {\n                u1_sub_mb_num += *pu1_top_lt_sub_mb_idx;\n                mv_index += *pu1_top_lt_sub_mb_idx;\n                ps_direct->i4_mv_indices[i1_num_partitions] = mv_index;\n                ps_direct->i1_submb_num[i1_num_partitions] = u1_sub_mb_num;\n                ps_direct->i1_partitionsize[i1_num_partitions] = partition_size;\n                i1_num_partitions++;\n                if(!uc_direct8x8inf)\n                    u1_submb_col = u1_sub_mb_num;\n                if((pu1_col_zero_flag_start[u1_submb_col] & 1)\n                                != u1_init_colzero_flag)\n                    ps_direct->u1_col_zeroflag_change = 1;\n            }\n            u1_sub_mb_num = *pu1_top_lt_mb_part_idx++;\n        }\n        ps_direct->i1_num_partitions = i1_num_partitions;\n    }\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_mbaff_cross_pmbair \\endif\n *\n * \\brief\n *    Initializes forward and backward refernce lists for B slice decoding.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nvoid ih264d_mbaff_cross_pmbair(dec_struct_t *ps_dec,\n                               struct pic_buffer_t *ps_col_pic,\n                               directmv_t *ps_direct,\n                               UWORD8 u1_wd_x,\n                               WORD32 u2_sub_mb_ofst,\n                               dec_mb_info_t * ps_cur_mb_info)\n{\n    UWORD8 *pu1_col_zero_flag_start, *pu1_col_zero_flag, u1_sub_mb_num,\n                    uc_sub_mb_num_col;\n    UWORD8 *pu1_col_zero_flag_right_half;\n    WORD32 i4_force_8X8;\n    UWORD8 u1_num_blks, u1_col_mb_pred_mode, uc_blk, u1_col_sub_mb_pred_mode,\n                    u1_col_sub_mb_pred_mode_rt;\n    UWORD8 i1_num_partitions = 0, partition_size;\n\n    WORD32 mv_index;\n\n    UWORD8 u1_num_sub_blks;\n    UWORD8 u1_is_cur_mb_fld, i;\n    UWORD8 u1_init_colzero_flag;\n\n    u1_is_cur_mb_fld = ps_cur_mb_info->u1_mb_field_decodingflag;\n    u1_sub_mb_num = ps_dec->u1_sub_mb_num;\n    ps_direct->u1_col_zeroflag_change = 0;\n    /*pu1_col_zero_flag_start = ps_col_pic->pu1_col_zero_flag + u2_sub_mb_ofst;\n     u1_col_mb_pred_mode = pu1_col_zero_flag_start[u1_sub_mb_num];\n     u1_init_colzero_flag = u1_col_mb_pred_mode & 1;\n     u1_col_mb_pred_mode >>= 6; */\n    if(0 == u1_is_cur_mb_fld)\n    {\n        ps_direct->u1_vert_mv_scale = FLD_TO_FRM;\n        if(u1_wd_x == MB_SIZE)\n        {\n            pu1_col_zero_flag_start = ps_col_pic->pu1_col_zero_flag\n                            + u2_sub_mb_ofst;\n            u1_col_mb_pred_mode = pu1_col_zero_flag_start[0];\n            u1_init_colzero_flag = u1_col_mb_pred_mode & 1;\n            u1_col_mb_pred_mode >>= 6;\n\n\n            if(u1_col_mb_pred_mode & 0x2)\n            {\n                ps_dec->u1_currB_type = 1;\n                if(u1_col_mb_pred_mode == PRED_8x16)\n                {\n                    ps_direct->i1_num_partitions = 2;\n                    ps_direct->i4_mv_indices[0] = u2_sub_mb_ofst;\n                    ps_direct->i1_submb_num[0] = 0;\n                    ps_direct->i1_partitionsize[0] = PRED_8x16;\n                    ps_direct->i4_mv_indices[1] = u2_sub_mb_ofst + 2;\n                    ps_direct->i1_submb_num[1] = 2;\n                    ps_direct->i1_partitionsize[1] = PRED_8x16;\n                    if((pu1_col_zero_flag_start[2] & 1) != u1_init_colzero_flag)\n                        ps_direct->u1_col_zeroflag_change = 1;\n                }\n                else\n                {\n                    pu1_col_zero_flag = pu1_col_zero_flag_start + u1_sub_mb_num;\n                    u1_col_sub_mb_pred_mode = (*pu1_col_zero_flag & 0x10);/* 8x4 or 4x4 mode */\n\n                    pu1_col_zero_flag_right_half = pu1_col_zero_flag_start\n                                    + u1_sub_mb_num + 2;\n                    u1_col_sub_mb_pred_mode_rt =\n                                    (*pu1_col_zero_flag_right_half & 0x10);/* 8x4 or 4x4 mode */\n\n                    i4_force_8X8 = (u1_col_sub_mb_pred_mode)\n                                    || (u1_col_sub_mb_pred_mode_rt);\n                    if(i4_force_8X8)\n                    {\n                        u1_num_sub_blks = 2;\n                        partition_size = PRED_8x8;\n                    }\n                    else\n                    {\n                        partition_size = PRED_8x16;\n                        u1_num_sub_blks = 1;\n                    }\n\n                    for(i = 0; i < 2; i++)\n                    {\n                        for(uc_blk = 0; uc_blk < u1_num_sub_blks; uc_blk++)\n                        {\n                            uc_sub_mb_num_col = u1_sub_mb_num | (u1_sub_mb_num >> 1);\n                            uc_sub_mb_num_col &= 0x7;\n                            mv_index = u2_sub_mb_ofst + uc_sub_mb_num_col;\n\n                            ps_direct->i4_mv_indices[i1_num_partitions] =\n                                            mv_index;\n                            ps_direct->i1_submb_num[i1_num_partitions] =\n                                            u1_sub_mb_num;\n                            ps_direct->i1_partitionsize[i1_num_partitions] =\n                                            partition_size;\n                            i1_num_partitions++;\n                            if((pu1_col_zero_flag_start[uc_sub_mb_num_col] & 1)\n                                            != u1_init_colzero_flag)\n                                ps_direct->u1_col_zeroflag_change = 1;\n                            u1_sub_mb_num += 8;\n                        }\n                        u1_sub_mb_num = 2; /* move to second half of Cur MB */\n                    }\n                    ps_direct->i1_num_partitions = i1_num_partitions;\n                    return;\n                }\n            }\n            else\n            {\n                ps_direct->i1_num_partitions = 1;\n                ps_direct->i4_mv_indices[0] = u2_sub_mb_ofst;\n                ps_direct->i1_submb_num[0] = 0;\n                ps_direct->i1_partitionsize[0] = PRED_16x16;\n                ps_dec->u1_currB_type = 0;\n                return;\n            }\n        }\n        else\n        {\n            uc_sub_mb_num_col = u1_sub_mb_num | (u1_sub_mb_num >> 1);\n            uc_sub_mb_num_col &= 0x7;\n\n            ps_direct->i4_mv_indices[0] = u2_sub_mb_ofst + uc_sub_mb_num_col;\n            ps_direct->i1_submb_num[0] = u1_sub_mb_num;\n            ps_direct->i1_partitionsize[0] = PRED_8x8;\n            ps_direct->i1_num_partitions = 1;\n        }\n    }\n    else\n    {\n        ps_direct->u1_vert_mv_scale = FRM_TO_FLD;\n        pu1_col_zero_flag_start = ps_col_pic->pu1_col_zero_flag + u2_sub_mb_ofst;\n        u1_init_colzero_flag = pu1_col_zero_flag_start[0] & 1;\n\n        if(u1_wd_x == MB_SIZE)\n        {\n            UWORD8 u1_submb_col;\n            UWORD8 *puc_colZeroFlagStart_bot_mb, uc_colMbPredMode_bot_mb;\n\n            pu1_col_zero_flag_start = ps_col_pic->pu1_col_zero_flag\n                            + u2_sub_mb_ofst;\n            u1_col_mb_pred_mode = pu1_col_zero_flag_start[u1_sub_mb_num] >> 6;\n\n            puc_colZeroFlagStart_bot_mb = ps_col_pic->pu1_col_zero_flag\n                            + u2_sub_mb_ofst + 16;\n            uc_colMbPredMode_bot_mb = puc_colZeroFlagStart_bot_mb[8] >> 6;\n\n            i4_force_8X8 = (u1_col_mb_pred_mode & 0x2)\n                            || (uc_colMbPredMode_bot_mb & 0x2);\n            if(i4_force_8X8)\n            {\n                u1_num_blks = 2;\n                partition_size = PRED_8x8;\n            }\n            else\n            {\n                u1_num_blks = 1;\n                partition_size = PRED_16x8;\n            }\n\n            ps_dec->u1_currB_type = 1;\n            /*As this mb is derived from 2 Mbs min no of partitions = 2*/\n            for(i = 0; i < 2; i++)\n            {\n\n                pu1_col_zero_flag_start = ps_col_pic->pu1_col_zero_flag\n                                + u2_sub_mb_ofst;\n                u1_col_mb_pred_mode = pu1_col_zero_flag_start[u1_sub_mb_num] >> 6;\n\n                for(uc_blk = 0; uc_blk < u1_num_blks; uc_blk++)\n                {\n                    u1_submb_col = (u1_sub_mb_num & 0x7) ? 1 : 0;\n                    u1_submb_col += u1_sub_mb_num;\n                    mv_index = u2_sub_mb_ofst + u1_submb_col;\n\n\n                    ps_direct->i4_mv_indices[i1_num_partitions] = mv_index;\n                    ps_direct->i1_submb_num[i1_num_partitions] = u1_sub_mb_num;\n                    ps_direct->i1_partitionsize[i1_num_partitions] =\n                                    partition_size;\n                    i1_num_partitions++;\n                    if((pu1_col_zero_flag_start[u1_submb_col] & 1)\n                                    != u1_init_colzero_flag)\n                        ps_direct->u1_col_zeroflag_change = 1;\n                    u1_sub_mb_num += 2;\n                }\n                u1_sub_mb_num = 8; /* move to second half of Cur MB */\n                u2_sub_mb_ofst += 16;/* move to next Colocated MB */\n            }\n            ps_direct->i1_num_partitions = i1_num_partitions;\n            return;\n        }\n        else\n        {\n            uc_sub_mb_num_col = u1_sub_mb_num | (u1_sub_mb_num >> 1);\n            uc_sub_mb_num_col &= 0xb;\n            u2_sub_mb_ofst += (u1_sub_mb_num >> 3) ? 16 : 0;\n\n            ps_direct->i4_mv_indices[0] = u2_sub_mb_ofst + uc_sub_mb_num_col;\n            ps_direct->i1_submb_num[0] = u1_sub_mb_num;\n            ps_direct->i1_partitionsize[0] = PRED_8x8;\n            ps_direct->i1_num_partitions = 1;\n            return;\n        }\n    }\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_cal_col_pic \\endif\n *\n * \\brief\n *    Finds the colocated picture.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_cal_col_pic(dec_struct_t *ps_dec)\n{\n    struct pic_buffer_t* ps_col_pic = ps_dec->ps_col_pic;\n    UWORD8 uc_curpictype, uc_colpictype;\n    ps_col_pic = ps_dec->ps_ref_pic_buf_lx[1][0];\n    uc_curpictype = (ps_dec->ps_cur_pic->u1_picturetype & 0x7);\n    uc_colpictype = (ps_col_pic->u1_picturetype & 0x7);\n    if(uc_curpictype == FRM_PIC)\n    {\n        if(uc_colpictype == FRM_PIC)\n            ps_dec->pf_parse_mvdirect = ih264d_one_to_one;\n        else if(uc_colpictype == COMP_FLD_PAIR)\n        {\n            ps_dec->pf_parse_mvdirect = ih264d_fld_to_frm;\n            if(ps_col_pic->i4_top_field_order_cnt\n                            >= ps_col_pic->i4_bottom_field_order_cnt)\n            {\n                struct pic_buffer_t* ps_tempPic = ps_col_pic;\n                UWORD32 ui_half_num_of_sub_mbs = ((ps_dec->u2_pic_ht\n                                * ps_dec->u2_pic_wd) >> 5);\n                ps_col_pic = ps_dec->ps_ref_pic_buf_lx[1][MAX_REF_BUFS];\n                /* memcpy ps_tempPic to ps_col_pic */\n                *ps_col_pic = *ps_tempPic;\n                ps_col_pic->pu1_buf1 = ps_tempPic->pu1_buf1\n                                + ps_tempPic->u2_frm_wd_y;\n                ps_col_pic->pu1_buf2 = ps_tempPic->pu1_buf2\n                                + ps_tempPic->u2_frm_wd_uv;\n                ps_col_pic->pu1_buf3 = ps_tempPic->pu1_buf3\n                                + ps_tempPic->u2_frm_wd_uv;\n                ps_col_pic->pu1_col_zero_flag = ps_tempPic->pu1_col_zero_flag\n                                + ui_half_num_of_sub_mbs;\n                ps_col_pic->ps_mv = ps_tempPic->ps_mv + ui_half_num_of_sub_mbs;\n\n\n                ps_col_pic->u1_pic_type = 0;/*complementary reference field pair-refering as frame */\n\n\n\n            }\n        }\n        else\n        {\n            UWORD32 i4_error_code;\n            i4_error_code = ERROR_DBP_MANAGER_T;\n//          i4_error_code |= 1<<IVD_CORRUPTEDDATA;\n            return i4_error_code;\n        }\n    }\n    else if(uc_curpictype == AFRM_PIC)\n    {\n        ps_dec->pf_parse_mvdirect = ih264d_fld_to_mbaff;\n    }\n    else /* must be a field*/\n    {\n        if(uc_colpictype == FRM_PIC)\n            ps_dec->pf_parse_mvdirect = ih264d_frm_to_fld;\n        else if(uc_colpictype == AFRM_PIC)\n            ps_dec->pf_parse_mvdirect = ih264d_mbaff_to_fld;\n        else\n            ps_dec->pf_parse_mvdirect = ih264d_one_to_one;\n    }\n    ps_dec->ps_col_pic = ps_col_pic;\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_frm_to_fld \\endif\n *\n * \\brief\n *    Initializes forward and backward refernce lists for B slice decoding.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nvoid ih264d_frm_to_fld(dec_struct_t *ps_dec,\n                       struct pic_buffer_t *ps_col_pic,\n                       directmv_t *ps_direct,\n                       UWORD8 u1_wd_x,\n                       WORD32 u2_sub_mb_ofst,\n                       dec_mb_info_t * ps_cur_mb_info)\n{\n    UWORD8 *pu1_col_zero_flag_start, u1_sub_mb_num;\n    UWORD8 u1_num_blks, u1_col_mb_pred_mode, uc_blk;\n    UWORD8 i1_num_partitions = 0, partition_size, i;\n    WORD32 mv_index;\n    UWORD32 increment;\n    WORD32 i4_force_8X8;\n    UNUSED(ps_cur_mb_info);\n    ps_direct->u1_col_zeroflag_change = 1;\n    ps_direct->u1_vert_mv_scale = FRM_TO_FLD;\n    u1_sub_mb_num = ps_dec->u1_sub_mb_num;\n\n    /* new calculation specific to this function */\n    if((ps_col_pic->u1_picturetype & 0x7) == FRM_PIC)\n    {\n        UWORD16 u2_frm_wd_in_mbs = ps_dec->u2_frm_wd_in_mbs;\n        increment = (u2_frm_wd_in_mbs << 4);\n        /*mbAddrCol = mbAddrCol1 */\n        u2_sub_mb_ofst = (ps_dec->u2_mbx\n                        + (2 * ps_dec->u2_mby * u2_frm_wd_in_mbs)) << 4;\n    }\n    else\n        increment = 16;\n\n    if(u1_wd_x == MB_SIZE)\n    {\n        ps_dec->u1_currB_type = 1;\n\n        {\n            UWORD8 *puc_colZeroFlagStart_bot_mb, uc_colMbPredMode_bot_mb;\n\n            pu1_col_zero_flag_start = ps_col_pic->pu1_col_zero_flag\n                            + u2_sub_mb_ofst;\n            u1_col_mb_pred_mode = (*pu1_col_zero_flag_start >> 6);\n\n            puc_colZeroFlagStart_bot_mb = ps_col_pic->pu1_col_zero_flag\n                            + u2_sub_mb_ofst + increment;\n            uc_colMbPredMode_bot_mb = (*puc_colZeroFlagStart_bot_mb >> 6);\n\n            i4_force_8X8 = (u1_col_mb_pred_mode & 0x2)\n                            || (uc_colMbPredMode_bot_mb & 0x2);\n\n            if(i4_force_8X8)\n            {\n                u1_num_blks = 2;\n                partition_size = PRED_8x8;\n            }\n            else\n            {\n                partition_size = PRED_16x8;\n                u1_num_blks = 1;\n            }\n        }\n\n        /*As this mb is derived from 2 Mbs, min no of partitions = 2*/\n        for(i = 0; i < 2; i++)\n        {\n            for(uc_blk = 0; uc_blk < u1_num_blks; uc_blk++)\n            {\n                mv_index = u2_sub_mb_ofst + u1_sub_mb_num;\n                mv_index += (u1_sub_mb_num & 0x7) ? 1 : 0;\n\n                ps_direct->i4_mv_indices[i1_num_partitions] = mv_index;\n                ps_direct->i1_submb_num[i1_num_partitions] = u1_sub_mb_num;\n                ps_direct->i1_partitionsize[i1_num_partitions] = partition_size;\n                i1_num_partitions++;\n\n                u1_sub_mb_num += 2;\n            }\n            u1_sub_mb_num = 8; /* move to second half of Cur MB */\n            u2_sub_mb_ofst += increment;/* move to next Colocated MB */\n        }\n        ps_direct->i1_num_partitions = i1_num_partitions;\n        return;\n    }\n    else\n    {\n        UWORD8 u1_sub_mb_num_col;\n        u1_sub_mb_num_col = u1_sub_mb_num | (u1_sub_mb_num >> 1);\n        u1_sub_mb_num_col &= 0xb;\n        u2_sub_mb_ofst += (u1_sub_mb_num >> 3) ? increment : 0;\n\n        ps_direct->i4_mv_indices[0] = u2_sub_mb_ofst + u1_sub_mb_num_col;\n        ps_direct->i1_submb_num[0] = u1_sub_mb_num;\n        ps_direct->i1_partitionsize[0] = PRED_8x8;\n        ps_direct->i1_num_partitions = 1;\n        return;\n    }\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_fld_to_frm \\endif\n *\n * \\brief\n *    Initializes forward and backward refernce lists for B slice decoding.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nvoid ih264d_fld_to_frm(dec_struct_t *ps_dec,\n                       struct pic_buffer_t *ps_col_pic,\n                       directmv_t *ps_direct,\n                       UWORD8 u1_wd_x,\n                       WORD32 u2_sub_mb_ofst,\n                       dec_mb_info_t * ps_cur_mb_info)\n{\n    UWORD8 *pu1_col_zero_flag_start, *pu1_col_zero_flag,\n                    *pu1_col_zero_flag_right_half, u1_sub_mb_num, uc_sub_mb_num_col;\n    UWORD8 u1_col_mb_pred_mode, uc_blk;\n    WORD32 i4_force_8X8;\n\n    UNUSED(ps_cur_mb_info);\n    ps_direct->u1_vert_mv_scale = FLD_TO_FRM;\n    ps_direct->u1_col_zeroflag_change = 1;\n    /* new calculation specific to this function for u2_sub_mb_ofst*/\n    u2_sub_mb_ofst = (ps_dec->u2_mbx\n                    + ((ps_dec->u2_mby >> 1) * ps_dec->u2_frm_wd_in_mbs)) << 4;\n    u2_sub_mb_ofst += ((ps_dec->u2_mby & 1) << 3);\n\n    if(u1_wd_x == MB_SIZE)\n    {\n        pu1_col_zero_flag_start = ps_col_pic->pu1_col_zero_flag + u2_sub_mb_ofst;\n        u1_col_mb_pred_mode = (*pu1_col_zero_flag_start >> 6);\n        ps_dec->u1_currB_type = (!!u1_col_mb_pred_mode);\n\n        if(u1_col_mb_pred_mode & 0x2)\n        {\n            if(u1_col_mb_pred_mode == PRED_8x16)\n            {\n                ps_direct->i1_num_partitions = 2;\n                ps_direct->i4_mv_indices[0] = u2_sub_mb_ofst;\n                ps_direct->i1_submb_num[0] = 0;\n                ps_direct->i1_partitionsize[0] = PRED_8x16;\n                ps_direct->i4_mv_indices[1] = u2_sub_mb_ofst + 2;\n                ps_direct->i1_submb_num[1] = 2;\n                ps_direct->i1_partitionsize[1] = PRED_8x16;\n            }\n            else\n            {\n                UWORD8 i1_num_partitions = 0, partition_size;\n                UWORD32 mv_index;\n                UWORD8 u1_num_sub_blks, i, u1_col_sub_mb_pred_mode,\n                                u1_col_sub_mb_pred_mode_rt;\n\n                u1_sub_mb_num = ps_dec->u1_sub_mb_num;\n\n                pu1_col_zero_flag = pu1_col_zero_flag_start + u1_sub_mb_num;\n                u1_col_sub_mb_pred_mode = (*pu1_col_zero_flag & 0x10);/* 8x4 or 4x4 mode */\n\n                pu1_col_zero_flag_right_half = pu1_col_zero_flag_start + u1_sub_mb_num\n                                + 2;\n                u1_col_sub_mb_pred_mode_rt = (*pu1_col_zero_flag_right_half\n                                & 0x10);/* 8x4 or 4x4 mode */\n\n                i4_force_8X8 = (u1_col_sub_mb_pred_mode)\n                                || (u1_col_sub_mb_pred_mode_rt);\n                if(i4_force_8X8)\n                {\n                    u1_num_sub_blks = 2;\n                    partition_size = PRED_8x8;\n                }\n                else\n                {\n                    partition_size = PRED_8x16;\n                    u1_num_sub_blks = 1;\n                }\n\n                for(i = 0; i < 2; i++)\n                {\n                    for(uc_blk = 0; uc_blk < u1_num_sub_blks; uc_blk++)\n                    {\n                        uc_sub_mb_num_col = u1_sub_mb_num | (u1_sub_mb_num >> 1);\n                        uc_sub_mb_num_col &= 0x7;\n                        mv_index = u2_sub_mb_ofst + uc_sub_mb_num_col;\n\n                        ps_direct->i4_mv_indices[i1_num_partitions] = mv_index;\n                        ps_direct->i1_submb_num[i1_num_partitions] =\n                                        u1_sub_mb_num;\n                        ps_direct->i1_partitionsize[i1_num_partitions] =\n                                        partition_size;\n                        i1_num_partitions++;\n                        u1_sub_mb_num += 8;\n                    }\n\n                    u1_sub_mb_num = 2; /* move to second half of Cur MB */\n\n                }\n                ps_direct->i1_num_partitions = i1_num_partitions;\n                return;\n            }\n        }\n        else\n        {\n            ps_direct->i1_num_partitions = 1;\n            ps_direct->i4_mv_indices[0] = u2_sub_mb_ofst;\n            ps_direct->i1_submb_num[0] = 0;\n            ps_direct->i1_partitionsize[0] = PRED_16x16;\n            return;\n        }\n    }\n    else\n    {\n        u1_sub_mb_num = ps_dec->u1_sub_mb_num;\n        uc_sub_mb_num_col = u1_sub_mb_num | (u1_sub_mb_num >> 1);\n        uc_sub_mb_num_col &= 0x7;\n\n        ps_direct->i4_mv_indices[0] = u2_sub_mb_ofst + uc_sub_mb_num_col;\n        ps_direct->i1_submb_num[0] = u1_sub_mb_num;\n        ps_direct->i1_partitionsize[0] = PRED_8x8;\n        ps_direct->i1_num_partitions = 1;\n    }\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_one_to_one \\endif\n *\n * \\brief\n *    Initializes forward and backward refernce lists for B slice decoding.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nvoid ih264d_mbaff_to_fld(dec_struct_t *ps_dec,\n                         struct pic_buffer_t *ps_col_pic,\n                         directmv_t *ps_direct,\n                         UWORD8 u1_wd_x,\n                         WORD32 u2_sub_mb_ofst,\n                         dec_mb_info_t * ps_cur_mb_info)\n{\n    UWORD8* pu1_col_zero_flag, u1_iscol_mb_fld;\n    u2_sub_mb_ofst <<= 1;\n    pu1_col_zero_flag = ps_col_pic->pu1_col_zero_flag + u2_sub_mb_ofst;\n    u1_iscol_mb_fld = (*pu1_col_zero_flag & 0x2) >> 1;\n    if(u1_iscol_mb_fld)\n    {\n        u2_sub_mb_ofst += (ps_dec->ps_cur_slice->u1_bottom_field_flag << 4);\n        ih264d_one_to_one(ps_dec, ps_col_pic, ps_direct, u1_wd_x,\n                          u2_sub_mb_ofst, ps_cur_mb_info);\n    }\n    else\n        ih264d_frm_to_fld(ps_dec, ps_col_pic, ps_direct, u1_wd_x,\n                          u2_sub_mb_ofst, ps_cur_mb_info);\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_one_to_one \\endif\n *\n * \\brief\n *    Initializes forward and backward refernce lists for B slice decoding.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nvoid ih264d_fld_to_mbaff(dec_struct_t *ps_dec,\n                         struct pic_buffer_t *ps_col_pic,\n                         directmv_t *ps_direct,\n                         UWORD8 u1_wd_x,\n                         WORD32 u2_sub_mb_ofst,\n                         dec_mb_info_t * ps_cur_mb_info)\n{\n    if((ps_col_pic->u1_picturetype & 0x7) == COMP_FLD_PAIR)\n    {\n        /* first calculate the colocated picture which varies with Mb */\n        UWORD8 u1_is_cur_mb_fld;\n        u1_is_cur_mb_fld = ps_cur_mb_info->u1_mb_field_decodingflag;\n        u2_sub_mb_ofst = (u2_sub_mb_ofst & 0xffe0); /* mbaddrCol5 = curmbaddr/2;*/\n        u2_sub_mb_ofst >>= 1;\n\n        ps_col_pic = ps_dec->ps_ref_pic_buf_lx[1][0];\n        if(u1_is_cur_mb_fld)\n        {\n            if(1 - ps_cur_mb_info->u1_topmb)\n                ps_col_pic = ps_dec->ps_ref_pic_buf_lx[1][MAX_REF_BUFS];\n\n            ih264d_one_to_one(ps_dec, ps_col_pic, ps_direct, u1_wd_x,\n                              u2_sub_mb_ofst, ps_cur_mb_info);\n        }\n        else\n        {\n\n            if(ABS(ps_col_pic->i4_top_field_order_cnt\n                            - (WORD64)ps_dec->ps_cur_pic->i4_poc) >=\n                            ABS((WORD64)ps_dec->ps_cur_pic->i4_poc\n                                                - ps_col_pic->i4_bottom_field_order_cnt))\n            {\n                ps_col_pic = ps_dec->ps_ref_pic_buf_lx[1][MAX_REF_BUFS];\n            }\n\n            if(ps_cur_mb_info->u1_topmb == 0)\n                u2_sub_mb_ofst += 8;\n            ih264d_mbaff_cross_pmbair(ps_dec, ps_col_pic, ps_direct, u1_wd_x,\n                                      u2_sub_mb_ofst, ps_cur_mb_info);\n        }\n        ps_dec->ps_col_pic = ps_col_pic;\n    }\n    else\n    {\n        UWORD8* pu1_col_zero_flag = ps_col_pic->pu1_col_zero_flag\n                        + u2_sub_mb_ofst;\n        UWORD8 temp, u1_is_cur_mb_fld, u1_iscol_mb_fld;\n\n        u1_iscol_mb_fld = (*pu1_col_zero_flag & 0x2) >> 1;\n        u1_is_cur_mb_fld = ps_cur_mb_info->u1_mb_field_decodingflag;\n        temp = (u1_iscol_mb_fld ^ u1_is_cur_mb_fld);\n\n        if(temp == 0)\n            ih264d_one_to_one(ps_dec, ps_col_pic, ps_direct, u1_wd_x,\n                              u2_sub_mb_ofst, ps_cur_mb_info);\n        else\n        {\n            u2_sub_mb_ofst &= 0xffef;\n            if(u1_is_cur_mb_fld == 0)\n            {\n                if(ABS(ps_col_pic->i4_top_field_order_cnt\n                                - (WORD64)ps_dec->ps_cur_pic->i4_poc) >=\n                                ABS((WORD64)ps_dec->ps_cur_pic->i4_poc\n                                                    - ps_col_pic->i4_bottom_field_order_cnt))\n                {\n                    u2_sub_mb_ofst += 0x10;\n                }\n                if(ps_cur_mb_info->u1_topmb == 0)\n                    u2_sub_mb_ofst += 8;\n            }\n            ih264d_mbaff_cross_pmbair(ps_dec, ps_col_pic, ps_direct, u1_wd_x,\n                                      u2_sub_mb_ofst, ps_cur_mb_info);\n        }\n    }\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_process_bslice.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_PARSE_BSLICE_H_\n#define _IH264D_PARSE_BSLICE_H_\n/*!\n**************************************************************************\n* \\file ih264d_process_bslice.h\n*\n* \\brief\n*    Contains declarations of routines that decode a B slice type\n*\n* Detailed_description\n*\n* \\date\n*    21/12/2002\n*\n* \\author  NS\n**************************************************************************\n*/\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\nWORD32 ih264d_parse_bslice(dec_struct_t * ps_dec,\n                            UWORD16 u2_first_mb_in_slice);\nWORD32 ih264d_decode_spatial_direct(dec_struct_t * ps_dec,\n                                    UWORD8 u1_wd_x,\n                                    dec_mb_info_t * ps_cur_mb_info,\n                                    UWORD8 u1_mb_num);\nWORD32 ih264d_decode_temporal_direct(dec_struct_t * ps_dec,\n                                     UWORD8 u1_wd_x,\n                                     dec_mb_info_t * ps_cur_mb_info,\n                                     UWORD8 u1_mb_num);\nWORD32 parseBSliceData(dec_struct_t * ps_dec,\n                       dec_slice_params_t * ps_slice,\n                       UWORD16 u2_first_mb_in_slice);\nWORD32 parseBSliceData(dec_struct_t * ps_dec,\n                       dec_slice_params_t * ps_slice,\n                       UWORD16 u2_first_mb_in_slice);\n\nvoid ih264d_init_ref_idx_lx_b(dec_struct_t *ps_dec);\n\nvoid ih264d_convert_frm_to_fld_list(struct pic_buffer_t *ps_ref_pic_buf_lx,\n                                    UWORD8 *pu1_L0,\n                                    dec_struct_t *ps_dec,\n                                    UWORD8 u1_num_short_term_bufs);\n\nvoid ih264d_convert_frm_mbaff_list(dec_struct_t *ps_dec);\nvoid ih264d_one_to_one(dec_struct_t *ps_dec,\n                       struct pic_buffer_t *ps_col_pic,\n                       directmv_t *ps_direct,\n                       UWORD8 u1_wd_x,\n                       WORD32 u2_sub_mb_ofst,\n                       dec_mb_info_t * ps_cur_mb_info);\nvoid ih264d_mbaff_cross_pmbair(dec_struct_t *ps_dec,\n                               struct pic_buffer_t *ps_col_pic,\n                               directmv_t *ps_direct,\n                               UWORD8 u1_wd_x,\n                               WORD32 u2_sub_mb_ofst,\n                               dec_mb_info_t * ps_cur_mb_info);\nvoid ih264d_frm_to_fld(dec_struct_t *ps_dec,\n                       struct pic_buffer_t *ps_col_pic,\n                       directmv_t *ps_direct,\n                       UWORD8 u1_wd_x,\n                       WORD32 u2_sub_mb_ofst,\n                       dec_mb_info_t * ps_cur_mb_info);\nvoid ih264d_fld_to_frm(dec_struct_t *ps_dec,\n                       struct pic_buffer_t *ps_col_pic,\n                       directmv_t *ps_direct,\n                       UWORD8 u1_wd_x,\n                       WORD32 u2_sub_mb_ofst,\n                       dec_mb_info_t * ps_cur_mb_info);\nvoid ih264d_mbaff_to_fld(dec_struct_t *ps_dec,\n                         struct pic_buffer_t *ps_col_pic,\n                         directmv_t *ps_direct,\n                         UWORD8 u1_wd_x,\n                         WORD32 u2_sub_mb_ofst,\n                         dec_mb_info_t * ps_cur_mb_info);\nvoid ih264d_fld_to_mbaff(dec_struct_t *ps_dec,\n                         struct pic_buffer_t *ps_col_pic,\n                         directmv_t *ps_direct,\n                         UWORD8 u1_wd_x,\n                         WORD32 u2_sub_mb_ofst,\n                         dec_mb_info_t * ps_cur_mb_info);\nWORD32 ih264d_cal_col_pic(dec_struct_t *ps_dec);\n\nWORD32 ih264d_mv_pred_ref_tfr_nby2_bmb(dec_struct_t * ps_dec,\n                                     UWORD8 u1_num_mbs,\n                                     UWORD8 u1_num_mbsNby2);\n\n#endif /* _IH264D_PARSE_BSLICE_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_process_intra_mb.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n * \\file ih264d_process_intra_mb.c\n *\n * \\brief\n *    Contains routines that decode a I slice type\n *\n * Detailed_description\n *\n * \\date\n *    07/07/2003\n *\n * \\author  NS\n **************************************************************************\n */\n\n#include <string.h>\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_process_intra_mb.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_quant_scaling.h\"\n#include \"ih264d_tables.h\"\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_itrans_recon_luma_dc \\endif\n *\n * \\brief\n *    This function does InvTransform, scaling and reconstruction of Luma DC.\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nvoid ih264d_itrans_recon_luma_dc(dec_struct_t *ps_dec,\n                                 WORD16* pi2_src,\n                                 WORD16* pi2_coeff_block,\n                                 const UWORD16 *pu2_weigh_mat)\n{\n    WORD32 i;\n    WORD16 pi2_out[16];\n    WORD32 pi4_tmp[16];\n    WORD16 *pi2_out_ptr = &pi2_out[0];\n    PROFILE_DISABLE_IQ_IT_RECON_RETURN()\n    ps_dec->pf_ihadamard_scaling_4x4(pi2_src, pi2_out,\n                                     ps_dec->pu2_quant_scale_y, pu2_weigh_mat,\n                                     ps_dec->u1_qp_y_div6, pi4_tmp);\n    for(i = 0; i < 4; i++)\n    {\n        pi2_coeff_block[0] = pi2_out_ptr[0];\n        pi2_coeff_block[4 * 16] = pi2_out_ptr[4];\n        pi2_coeff_block[8 * 16] = pi2_out_ptr[8];\n        pi2_coeff_block[12 * 16] = pi2_out_ptr[12];\n\n        pi2_out_ptr++; /* Point to next column */\n        pi2_coeff_block += 16;\n    }\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_read_intra_pred_modes \\endif\n *\n * \\brief\n *    Reads the intra pred mode related values of I4x4 MB from bitstream.\n *\n *    This function will read the prev intra pred mode flags and\n *    stores it in pu1_prev_intra4x4_pred_mode_flag. If the u4_flag\n *    indicates that most probable mode is not intra pred mode, then\n *    the rem_intra4x4_pred_mode is read and stored in\n *    pu1_rem_intra4x4_pred_mode array.\n *\n *\n * \\return\n *    0 on success and Error code otherwise\n *\n **************************************************************************\n */\nWORD32 ih264d_read_intra_pred_modes(dec_struct_t * ps_dec,\n                                    UWORD8 * pu1_prev_intra4x4_pred_mode_flag,\n                                    UWORD8 * pu1_rem_intra4x4_pred_mode,\n                                    UWORD32 u4_trans_form8x8)\n{\n    WORD32 i4x4_luma_blk_idx = 0, i8x8_luma_blk_idx = 0;\n\n    dec_bit_stream_t * ps_bitstrm = ps_dec->ps_bitstrm;\n\n    if(!u4_trans_form8x8)\n    {\n        for(i4x4_luma_blk_idx = 0; i4x4_luma_blk_idx < 16; ++i4x4_luma_blk_idx)\n        {\n            UWORD32 u4_temp;\n            SWITCHOFFTRACE;\n\n            GETBIT(u4_temp, ps_bitstrm->u4_ofst, ps_bitstrm->pu4_buffer);\n            *pu1_prev_intra4x4_pred_mode_flag = (UWORD8)u4_temp;\n            if(!(*pu1_prev_intra4x4_pred_mode_flag))\n            {\n                GETBITS(u4_temp, ps_bitstrm->u4_ofst, ps_bitstrm->pu4_buffer, 3);\n\n                *(pu1_rem_intra4x4_pred_mode) = (UWORD8)u4_temp;\n            }\n\n            pu1_prev_intra4x4_pred_mode_flag++;\n            pu1_rem_intra4x4_pred_mode++;\n        }\n    }\n    else\n    {\n        /**********************************************************************/\n        /* prev_intra4x4_pred_modes to be interpreted as                      */\n        /* prev_intra8x8_pred_modes in case of transform 8x8                  */\n        /**********************************************************************/\n        for(i8x8_luma_blk_idx = 0; i8x8_luma_blk_idx < 4; i8x8_luma_blk_idx++)\n        {\n            UWORD32 u4_temp;\n            GETBIT(u4_temp, ps_bitstrm->u4_ofst, ps_bitstrm->pu4_buffer);\n            *pu1_prev_intra4x4_pred_mode_flag = (UWORD8)u4_temp;\n            if(!(*pu1_prev_intra4x4_pred_mode_flag))\n            {\n                GETBITS(u4_temp, ps_bitstrm->u4_ofst, ps_bitstrm->pu4_buffer, 3);\n\n                (*pu1_rem_intra4x4_pred_mode) = (UWORD8)u4_temp;\n            }\n            pu1_prev_intra4x4_pred_mode_flag++;\n            pu1_rem_intra4x4_pred_mode++;\n        }\n    }\n    return (0);\n}\nWORD32 ih264d_unpack_coeff4x4_4x4blk(dec_struct_t * ps_dec,\n                                   WORD16 *pi2_out_coeff_data,\n                                   UWORD8 *pu1_inv_scan)\n{\n    tu_sblk4x4_coeff_data_t *ps_tu_4x4 = (tu_sblk4x4_coeff_data_t *)ps_dec->pv_proc_tu_coeff_data;\n    UWORD16 u2_sig_coeff_map = ps_tu_4x4->u2_sig_coeff_map;\n    WORD32 idx = 0;\n    WORD16 *pi2_coeff_data = &ps_tu_4x4->ai2_level[0];\n    WORD32 dc_only_flag = 0;\n    WORD32 num_coeff = 0;\n\n    PROFILE_DISABLE_UNPACK_LUMA()\n    while(u2_sig_coeff_map)\n    {\n        idx = CLZ(u2_sig_coeff_map);\n\n        idx = 31 - idx;\n        RESET_BIT(u2_sig_coeff_map,idx);\n\n        idx = pu1_inv_scan[idx];\n        pi2_out_coeff_data[idx] = *pi2_coeff_data++;\n        num_coeff++;\n    }\n\n    if((num_coeff == 1) && (idx == 0))\n    {\n        dc_only_flag = 1;\n    }\n\n    {\n        WORD32 offset;\n        offset = (UWORD8 *)pi2_coeff_data - (UWORD8 *)ps_tu_4x4;\n        offset = ALIGN4(offset);\n        ps_dec->pv_proc_tu_coeff_data = (void *)((UWORD8 *)ps_dec->pv_proc_tu_coeff_data + offset);\n    }\n\n    return dc_only_flag;\n}\n\nUWORD32 ih264d_unpack_coeff4x4_8x8blk(dec_struct_t * ps_dec,\n                                   dec_mb_info_t * ps_cur_mb_info,\n                                   UWORD16 ui2_luma_csbp,\n                                   WORD16 *pi2_out_coeff_data)\n{\n    UWORD8 *pu1_inv_scan;\n    UWORD8 u1_mb_field_decoding_flag = ps_cur_mb_info->u1_mb_field_decodingflag;\n    UWORD8 u1_field_coding_flag = ps_cur_mb_info->ps_curmb->u1_mb_fld;\n    UWORD32 u4_luma_dc_only_csbp = 0;\n    WORD32 dc_only_flag = 0;\n\n    PROFILE_DISABLE_UNPACK_LUMA()\n    if(u1_field_coding_flag || u1_mb_field_decoding_flag)\n    {\n        pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan_fld;\n    }\n    else\n    {\n        pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan;\n    }\n\n    // sub 0\n    if(ui2_luma_csbp & 0x1)\n    {\n        memset(pi2_out_coeff_data,0,16*sizeof(WORD16));\n        dc_only_flag = ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n\n        INSERT_BIT(u4_luma_dc_only_csbp, 0, dc_only_flag);\n    }\n\n    pi2_out_coeff_data += 16;\n    // sub 1\n    if(ui2_luma_csbp & 0x2)\n    {\n        memset(pi2_out_coeff_data,0,16*sizeof(WORD16));\n        dc_only_flag = ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n        INSERT_BIT(u4_luma_dc_only_csbp, 1, dc_only_flag);\n    }\n\n    pi2_out_coeff_data += 16 + 32;\n    // sub 2\n    if(ui2_luma_csbp & 0x10)\n    {\n        memset(pi2_out_coeff_data,0,16*sizeof(WORD16));\n        dc_only_flag = ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n        INSERT_BIT(u4_luma_dc_only_csbp, 4, dc_only_flag);\n    }\n\n    pi2_out_coeff_data += 16;\n    // sub 3\n    if(ui2_luma_csbp & 0x20)\n    {\n        memset(pi2_out_coeff_data,0,16*sizeof(WORD16));\n        dc_only_flag = ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n        INSERT_BIT(u4_luma_dc_only_csbp, 5, dc_only_flag);\n    }\n    return u4_luma_dc_only_csbp;\n}\nWORD32 ih264d_unpack_coeff8x8_8x8blk_cavlc(dec_struct_t * ps_dec,\n                                            dec_mb_info_t * ps_cur_mb_info,\n                                            UWORD16 ui2_luma_csbp,\n                                            WORD16 *pi2_out_coeff_data)\n{\n    UWORD8 *pu1_inv_scan;\n    UWORD8 u1_mb_field_decoding_flag = ps_cur_mb_info->u1_mb_field_decodingflag;\n    UWORD8 u1_field_coding_flag = ps_cur_mb_info->ps_curmb->u1_mb_fld;\n    WORD32 dc_only_flag = 0;\n\n    PROFILE_DISABLE_UNPACK_LUMA()\n    if(ui2_luma_csbp & 0x33)\n    {\n        memset(pi2_out_coeff_data,0,64*sizeof(WORD16));\n    }\n\n    if(!u1_mb_field_decoding_flag)\n    {\n        pu1_inv_scan =\n                        (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[0];\n    }\n    else\n    {\n        pu1_inv_scan =\n                        (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[0];\n    }\n    // sub 0\n    if(ui2_luma_csbp & 0x1)\n    {\n        dc_only_flag = ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n    }\n\n    if(!u1_mb_field_decoding_flag)\n    {\n        pu1_inv_scan =\n                        (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[1];\n    }\n    else\n    {\n        pu1_inv_scan =\n                        (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[1];\n    }\n    // sub 1\n    if(ui2_luma_csbp & 0x2)\n    {\n        dc_only_flag = 0;\n        ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n    }\n\n    if(!u1_mb_field_decoding_flag)\n    {\n        pu1_inv_scan =\n                        (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[2];\n    }\n    else\n    {\n        pu1_inv_scan =\n                        (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[2];\n    }\n    // sub 2\n    if(ui2_luma_csbp & 0x10)\n    {\n        dc_only_flag = 0;\n        ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n    }\n\n    if(!u1_mb_field_decoding_flag)\n    {\n        pu1_inv_scan =\n                        (UWORD8*)gau1_ih264d_inv_scan_prog8x8_cavlc[3];\n    }\n    else\n    {\n        pu1_inv_scan =\n                        (UWORD8*)gau1_ih264d_inv_scan_int8x8_cavlc[3];\n    }\n    // sub 3\n    if(ui2_luma_csbp & 0x20)\n    {\n        dc_only_flag = 0;\n        ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n    }\n    return dc_only_flag;\n}\nvoid ih264d_unpack_coeff4x4_8x8blk_chroma(dec_struct_t * ps_dec,\n                                          dec_mb_info_t * ps_cur_mb_info,\n                                          UWORD16 ui2_chroma_csbp,\n                                          WORD16 *pi2_out_coeff_data)\n{\n    UWORD8 *pu1_inv_scan;\n    UWORD8 u1_mb_field_decoding_flag = ps_cur_mb_info->u1_mb_field_decodingflag;\n    UWORD8 u1_field_coding_flag = ps_cur_mb_info->ps_curmb->u1_mb_fld;\n\n    PROFILE_DISABLE_UNPACK_CHROMA()\n    if(u1_field_coding_flag || u1_mb_field_decoding_flag)\n    {\n        pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan_fld;\n    }\n    else\n    {\n        pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan;\n    }\n\n    if(ui2_chroma_csbp & 0x1)\n    {\n        memset(pi2_out_coeff_data,0,16*sizeof(WORD16));\n        ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n    }\n    pi2_out_coeff_data += 16;\n    if(ui2_chroma_csbp & 0x2)\n    {\n        memset(pi2_out_coeff_data,0,16*sizeof(WORD16));\n        ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n    }\n\n    pi2_out_coeff_data += 16;\n    if(ui2_chroma_csbp & 0x4)\n    {\n        memset(pi2_out_coeff_data,0,16*sizeof(WORD16));\n        ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n    }\n\n    pi2_out_coeff_data += 16;\n    if(ui2_chroma_csbp & 0x8)\n    {\n        memset(pi2_out_coeff_data,0,16*sizeof(WORD16));\n        ih264d_unpack_coeff4x4_4x4blk(ps_dec,\n                                      pi2_out_coeff_data,\n                                      pu1_inv_scan);\n    }\n}\nUWORD32 ih264d_unpack_luma_coeff4x4_mb(dec_struct_t * ps_dec,\n                                    dec_mb_info_t * ps_cur_mb_info,\n                                    UWORD8 intra_flag)\n{\n    UWORD8 u1_mb_type = ps_cur_mb_info->u1_mb_type;\n    UWORD16 ui2_luma_csbp = ps_cur_mb_info->u2_luma_csbp;\n    UWORD8 *pu1_inv_scan = ps_dec->pu1_inv_scan;\n    WORD16 *pi2_coeff_data = ps_dec->pi2_coeff_data;\n\n    PROFILE_DISABLE_UNPACK_LUMA()\n    if(!ps_cur_mb_info->u1_tran_form8x8)\n    {\n        UWORD32 u4_luma_dc_only_csbp = 0;\n        UWORD32 u4_temp = 0;\n        WORD16* pi2_dc_val = NULL;\n        /*\n         * Reserve the pointer to dc vals. The dc vals will be copied\n         * after unpacking of ac vals since memset to 0 inside.\n         */\n        if(intra_flag && (u1_mb_type != I_4x4_MB))\n        {\n            if(CHECKBIT(ps_cur_mb_info->u1_yuv_dc_block_flag,0))\n            {\n                pi2_dc_val = (WORD16 *)ps_dec->pv_proc_tu_coeff_data;\n\n                ps_dec->pv_proc_tu_coeff_data = (void *)(pi2_dc_val + 16);\n            }\n        }\n\n        if(ui2_luma_csbp)\n        {\n            pi2_coeff_data = ps_dec->pi2_coeff_data;\n            u4_temp = ih264d_unpack_coeff4x4_8x8blk(ps_dec,\n                                          ps_cur_mb_info,\n                                          ui2_luma_csbp,\n                                          pi2_coeff_data);\n            u4_luma_dc_only_csbp = u4_temp;\n\n            pi2_coeff_data += 32;\n\n            ui2_luma_csbp = ui2_luma_csbp >> 2;\n            u4_temp = ih264d_unpack_coeff4x4_8x8blk(ps_dec,\n                                          ps_cur_mb_info,\n                                          ui2_luma_csbp,\n                                          pi2_coeff_data);\n\n            u4_luma_dc_only_csbp |= (u4_temp << 2);\n\n            pi2_coeff_data += 32 + 64;\n\n            ui2_luma_csbp = ui2_luma_csbp >> 6;\n            u4_temp = ih264d_unpack_coeff4x4_8x8blk(ps_dec,\n                                          ps_cur_mb_info,\n                                          ui2_luma_csbp,\n                                          pi2_coeff_data);\n\n            u4_luma_dc_only_csbp |= (u4_temp << 8);\n\n            pi2_coeff_data += 32;\n\n            ui2_luma_csbp = ui2_luma_csbp >> 2;\n            u4_temp = ih264d_unpack_coeff4x4_8x8blk(ps_dec,\n                                          ps_cur_mb_info,\n                                          ui2_luma_csbp,\n                                          pi2_coeff_data);\n            u4_luma_dc_only_csbp |= (u4_temp << 10);\n        }\n\n        if(pi2_dc_val != NULL)\n        {\n            WORD32 i;\n            pi2_coeff_data = ps_dec->pi2_coeff_data;\n            for(i = 0; i < 4; i++)\n            {\n                pi2_coeff_data[0] = pi2_dc_val[0];\n                pi2_coeff_data[4 * 16] = pi2_dc_val[4];\n                pi2_coeff_data[8 * 16] = pi2_dc_val[8];\n                pi2_coeff_data[12 * 16] = pi2_dc_val[12];\n\n                pi2_dc_val++; /* Point to next column */\n                pi2_coeff_data += 16;\n            }\n            u4_luma_dc_only_csbp = ps_cur_mb_info->u2_luma_csbp ^ 0xFFFF;\n        }\n        return u4_luma_dc_only_csbp;\n    }\n    else\n    {\n        UWORD32 u4_luma_dc_only_cbp = 0;\n        WORD32 dc_only_flag;\n        if(ui2_luma_csbp)\n        {\n            pi2_coeff_data = ps_dec->pi2_coeff_data;\n            dc_only_flag = ih264d_unpack_coeff8x8_8x8blk_cavlc(ps_dec,\n                                          ps_cur_mb_info,\n                                          ui2_luma_csbp,\n                                          pi2_coeff_data);\n            INSERT_BIT(u4_luma_dc_only_cbp, 0, dc_only_flag);\n\n            pi2_coeff_data += 64;\n\n            ui2_luma_csbp = ui2_luma_csbp >> 2;\n            dc_only_flag = ih264d_unpack_coeff8x8_8x8blk_cavlc(ps_dec,\n                                          ps_cur_mb_info,\n                                          ui2_luma_csbp,\n                                          pi2_coeff_data);\n\n            INSERT_BIT(u4_luma_dc_only_cbp, 1, dc_only_flag);\n\n            pi2_coeff_data += 64;\n\n            ui2_luma_csbp = ui2_luma_csbp >> 6;\n            dc_only_flag = ih264d_unpack_coeff8x8_8x8blk_cavlc(ps_dec,\n                                          ps_cur_mb_info,\n                                          ui2_luma_csbp,\n                                          pi2_coeff_data);\n\n            INSERT_BIT(u4_luma_dc_only_cbp, 2, dc_only_flag);\n\n            pi2_coeff_data += 64;\n            ui2_luma_csbp = ui2_luma_csbp >> 2;\n            dc_only_flag = ih264d_unpack_coeff8x8_8x8blk_cavlc(ps_dec,\n                                          ps_cur_mb_info,\n                                          ui2_luma_csbp,\n                                          pi2_coeff_data);\n            INSERT_BIT(u4_luma_dc_only_cbp, 3, dc_only_flag);\n        }\n        return u4_luma_dc_only_cbp;\n    }\n\n}\n\nvoid ih264d_unpack_chroma_coeff4x4_mb(dec_struct_t * ps_dec,\n                                      dec_mb_info_t * ps_cur_mb_info)\n{\n    UWORD8 u1_mb_type = ps_cur_mb_info->u1_mb_type;\n    UWORD16 ui2_chroma_csbp = ps_cur_mb_info->u2_chroma_csbp;\n    UWORD8 *pu1_inv_scan = ps_dec->pu1_inv_scan;\n    WORD16 *pi2_coeff_data = ps_dec->pi2_coeff_data;\n    WORD32 i;\n    WORD16 *pi2_dc_val_u = NULL;\n    WORD16 *pi2_dc_val_v = NULL;\n\n    PROFILE_DISABLE_UNPACK_CHROMA()\n    if((ps_cur_mb_info->u1_cbp >> 4) == CBPC_ALLZERO)\n        return;\n\n    /*\n     * Reserve the pointers to dc vals. The dc vals will be copied\n     * after unpacking of ac vals since memset to 0 inside.\n     */\n    if(CHECKBIT(ps_cur_mb_info->u1_yuv_dc_block_flag,1))\n    {\n        pi2_dc_val_u = (WORD16 *)ps_dec->pv_proc_tu_coeff_data;\n\n        ps_dec->pv_proc_tu_coeff_data = (void *)(pi2_dc_val_u + 4);\n    }\n    if(CHECKBIT(ps_cur_mb_info->u1_yuv_dc_block_flag,2))\n    {\n        pi2_dc_val_v = (WORD16 *)ps_dec->pv_proc_tu_coeff_data;\n\n        ps_dec->pv_proc_tu_coeff_data = (void *)(pi2_dc_val_v + 4);\n    }\n\n    if((ps_cur_mb_info->u1_cbp >> 4) == CBPC_NONZERO)\n    {\n        pi2_coeff_data = ps_dec->pi2_coeff_data;\n        ih264d_unpack_coeff4x4_8x8blk_chroma(ps_dec,\n                                             ps_cur_mb_info,\n                                             ui2_chroma_csbp,\n                                             pi2_coeff_data);\n\n        pi2_coeff_data += 64;\n        ui2_chroma_csbp = ui2_chroma_csbp >> 4;\n        ih264d_unpack_coeff4x4_8x8blk_chroma(ps_dec,\n                                             ps_cur_mb_info,\n                                             ui2_chroma_csbp,\n                                             pi2_coeff_data);\n\n    }\n\n    pi2_coeff_data = ps_dec->pi2_coeff_data;\n    if(pi2_dc_val_u != NULL)\n    {\n        pi2_coeff_data[0] = *pi2_dc_val_u++;\n        pi2_coeff_data[1 * 16] = *pi2_dc_val_u++;\n        pi2_coeff_data[2 * 16] = *pi2_dc_val_u++;\n        pi2_coeff_data[3 * 16] = *pi2_dc_val_u++;\n    }\n    else\n    {\n        pi2_coeff_data[0] = 0;\n        pi2_coeff_data[1 * 16] = 0;\n        pi2_coeff_data[2 * 16] = 0;\n        pi2_coeff_data[3 * 16] = 0;\n    }\n    pi2_coeff_data += 64;\n    if(pi2_dc_val_v != NULL)\n    {\n        pi2_coeff_data[0] = *pi2_dc_val_v++;\n        pi2_coeff_data[1 * 16] = *pi2_dc_val_v++;\n        pi2_coeff_data[2 * 16] = *pi2_dc_val_v++;\n        pi2_coeff_data[3 * 16] = *pi2_dc_val_v++;\n    }\n    else\n    {\n        pi2_coeff_data[0] = 0;\n        pi2_coeff_data[1 * 16] = 0;\n        pi2_coeff_data[2 * 16] = 0;\n        pi2_coeff_data[3 * 16] = 0;\n    }\n}\nUWORD32 ih264d_unpack_luma_coeff8x8_mb(dec_struct_t * ps_dec,\n                                    dec_mb_info_t * ps_cur_mb_info)\n{\n    WORD32 blk_8x8_cnt;\n    WORD16 *pi2_out_coeff_data = ps_dec->pi2_coeff_data;\n    UWORD8 u1_field_coding_flag = ps_cur_mb_info->ps_curmb->u1_mb_fld;\n    UWORD8 *pu1_inv_scan;\n    UWORD32 u4_luma_dc_only_cbp = 0;\n\n    PROFILE_DISABLE_UNPACK_LUMA()\n    if(!u1_field_coding_flag)\n    {\n        /*******************************************************************/\n        /* initializing inverse scan  matrices                             */\n        /*******************************************************************/\n        pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan_prog8x8_cabac;\n    }\n    else\n    {\n        /*******************************************************************/\n        /* initializing inverse scan  matrices                             */\n        /*******************************************************************/\n        pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan_int8x8_cabac;\n    }\n\n    for(blk_8x8_cnt = 0; blk_8x8_cnt < 4; blk_8x8_cnt++)\n    {\n        if(CHECKBIT(ps_cur_mb_info->u1_cbp, blk_8x8_cnt))\n        {\n            tu_blk8x8_coeff_data_t *ps_tu_8x8 = (tu_blk8x8_coeff_data_t *)ps_dec->pv_proc_tu_coeff_data;\n            UWORD32 u4_sig_coeff_map;\n            WORD32 idx = 0;\n            WORD16 *pi2_coeff_data = &ps_tu_8x8->ai2_level[0];\n            WORD32 num_coeff = 0;\n\n            /* memset 64 coefficient to zero */\n            memset(pi2_out_coeff_data,0,64*sizeof(WORD16));\n\n            u4_sig_coeff_map = ps_tu_8x8->au4_sig_coeff_map[1];\n\n            while(u4_sig_coeff_map)\n            {\n                idx = CLZ(u4_sig_coeff_map);\n\n                idx = 31 - idx;\n                RESET_BIT(u4_sig_coeff_map,idx);\n\n                idx = pu1_inv_scan[idx + 32];\n                pi2_out_coeff_data[idx] = *pi2_coeff_data++;\n                num_coeff++;\n            }\n\n            u4_sig_coeff_map = ps_tu_8x8->au4_sig_coeff_map[0];\n            while(u4_sig_coeff_map)\n            {\n                idx = CLZ(u4_sig_coeff_map);\n\n                idx = 31 - idx;\n                RESET_BIT(u4_sig_coeff_map,idx);\n\n                idx = pu1_inv_scan[idx];\n                pi2_out_coeff_data[idx] = *pi2_coeff_data++;\n                num_coeff++;\n            }\n\n            if((num_coeff == 1) && (idx == 0))\n            {\n                SET_BIT(u4_luma_dc_only_cbp,blk_8x8_cnt);\n            }\n\n\n            {\n                WORD32 offset;\n                offset = (UWORD8 *)pi2_coeff_data - (UWORD8 *)ps_tu_8x8;\n                offset = ALIGN4(offset);\n                ps_dec->pv_proc_tu_coeff_data = (void *)((UWORD8 *)ps_dec->pv_proc_tu_coeff_data + offset);\n            }\n        }\n        pi2_out_coeff_data += 64;\n    }\n\n    return u4_luma_dc_only_cbp;\n}\n/*!\n **************************************************************************\n * \\if Function name : ih264d_process_intra_mb \\endif\n *\n * \\brief\n *    This function decodes an I MB. Intraprediction is carried out followed\n *    by InvTramsform. Both IntraPrediction and Reconstrucion are carried out\n *    row buffer itself.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_process_intra_mb(dec_struct_t * ps_dec,\n                               dec_mb_info_t * ps_cur_mb_info,\n                               UWORD8 u1_mb_num)\n{\n    UWORD8 u1_mb_type = ps_cur_mb_info->u1_mb_type;\n    UWORD8 uc_temp = ps_cur_mb_info->u1_mb_ngbr_availablity;\n    UWORD8 u1_top_available = BOOLEAN(uc_temp & TOP_MB_AVAILABLE_MASK);\n    UWORD8 u1_left_available = BOOLEAN(uc_temp & LEFT_MB_AVAILABLE_MASK);\n    UWORD8 u1_use_top_right_mb = BOOLEAN(uc_temp & TOP_RIGHT_MB_AVAILABLE_MASK);\n    UWORD8 u1_use_top_left_mb = BOOLEAN(uc_temp & TOP_LEFT_MB_AVAILABLE_MASK);\n    UWORD8 uc_useTopMB = u1_top_available;\n    UWORD16 u2_use_left_mb = u1_left_available;\n    UWORD16 u2_use_left_mb_pack;\n    UWORD8 *pu1_luma_pred_buffer;\n    /* CHANGED CODE */\n    UWORD8 *pu1_luma_rec_buffer;\n    UWORD8 *puc_top;\n\n    mb_neigbour_params_t *ps_left_mb;\n    mb_neigbour_params_t *ps_top_mb;\n    mb_neigbour_params_t *ps_top_right_mb;\n    mb_neigbour_params_t *ps_curmb;\n\n    UWORD16 u2_mbx = ps_cur_mb_info->u2_mbx;\n    UWORD32 ui_pred_width, ui_rec_width;\n    WORD16 *pi2_y_coeff;\n    UWORD8 u1_mbaff, u1_topmb, u1_mb_field_decoding_flag;\n    UWORD32 u4_num_pmbair;\n    UWORD16 ui2_luma_csbp = ps_cur_mb_info->u2_luma_csbp;\n    UWORD8 *pu1_yleft, *pu1_ytop_left;\n    /* Chroma variables*/\n    UWORD8 *pu1_top_u;\n    UWORD8 *pu1_uleft;\n    UWORD8 *pu1_u_top_left;\n    /* CHANGED CODE */\n    UWORD8 *pu1_mb_cb_rei1_buffer, *pu1_mb_cr_rei1_buffer;\n    UWORD32 u4_recwidth_cr;\n    /* CHANGED CODE */\n    tfr_ctxt_t *ps_frame_buf = ps_dec->ps_frame_buf_ip_recon;\n    UWORD32 u4_luma_dc_only_csbp = 0;\n    UWORD32 u4_luma_dc_only_cbp = 0;\n\n    UWORD8 *pu1_prev_intra4x4_pred_mode_data = (UWORD8 *)ps_dec->pv_proc_tu_coeff_data;                 //Pointer to keep track of intra4x4_pred_mode data in pv_proc_tu_coeff_data buffer\n    u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    u1_topmb = ps_cur_mb_info->u1_topmb;\n    u4_num_pmbair = (u1_mb_num >> u1_mbaff);\n\n\n    /*--------------------------------------------------------------------*/\n    /* Find the current MB's mb params                                    */\n    /*--------------------------------------------------------------------*/\n    u1_mb_field_decoding_flag = ps_cur_mb_info->u1_mb_field_decodingflag;\n\n    ps_curmb = ps_cur_mb_info->ps_curmb;\n    ps_top_mb = ps_cur_mb_info->ps_top_mb;\n    ps_left_mb = ps_cur_mb_info->ps_left_mb;\n    ps_top_right_mb = ps_cur_mb_info->ps_top_right_mb;\n\n    /*--------------------------------------------------------------------*/\n    /* Check whether neighbouring MB is Inter MB and                      */\n    /* constrained intra pred is 1.                                       */\n    /*--------------------------------------------------------------------*/\n    u2_use_left_mb_pack = (u2_use_left_mb << 8) + u2_use_left_mb;\n\n    if(ps_dec->ps_cur_pps->u1_constrained_intra_pred_flag)\n    {\n        UWORD8 u1_left = (UWORD8)u2_use_left_mb;\n\n        uc_useTopMB = uc_useTopMB\n                        && ((ps_top_mb->u1_mb_type != P_MB)\n                                        && (ps_top_mb->u1_mb_type != B_MB));\n        u2_use_left_mb = u2_use_left_mb\n                        && ((ps_left_mb->u1_mb_type != P_MB)\n                                        && (ps_left_mb->u1_mb_type != B_MB));\n\n        u2_use_left_mb_pack = (u2_use_left_mb << 8) + u2_use_left_mb;\n        if(u1_mbaff)\n        {\n            if(u1_mb_field_decoding_flag ^ ps_left_mb->u1_mb_fld)\n            {\n                u1_left = u1_left\n                                && (((ps_left_mb + 1)->u1_mb_type != P_MB)\n                                                && ((ps_left_mb + 1)->u1_mb_type\n                                                                != B_MB));\n                u2_use_left_mb = u2_use_left_mb && u1_left;\n                if(u1_mb_field_decoding_flag)\n                    u2_use_left_mb_pack = (u1_left << 8)\n                                    + (u2_use_left_mb_pack & 0xff);\n                else\n                    u2_use_left_mb_pack = (u2_use_left_mb << 8)\n                                    + (u2_use_left_mb);\n            }\n        }\n        u1_use_top_right_mb =\n                        u1_use_top_right_mb\n                                        && ((ps_top_right_mb->u1_mb_type != P_MB)\n                                                        && (ps_top_right_mb->u1_mb_type\n                                                                        != B_MB));\n\n        u1_use_top_left_mb =\n                        u1_use_top_left_mb\n                                        && ((ps_cur_mb_info->u1_topleft_mbtype != P_MB)\n                                                        && (ps_cur_mb_info->u1_topleft_mbtype\n                                                                        != B_MB));\n    }\n\n    /*********************Common pointer calculations *************************/\n    /* CHANGED CODE */\n    pu1_luma_pred_buffer = ps_dec->pu1_y;\n    pu1_luma_rec_buffer = ps_frame_buf->pu1_dest_y + (u4_num_pmbair << 4);\n    pu1_mb_cb_rei1_buffer = ps_frame_buf->pu1_dest_u\n                    + (u4_num_pmbair << 3) * YUV420SP_FACTOR;\n    pu1_mb_cr_rei1_buffer = ps_frame_buf->pu1_dest_v + (u4_num_pmbair << 3);\n    ui_pred_width = MB_SIZE;\n    ui_rec_width = ps_dec->u2_frm_wd_y << u1_mb_field_decoding_flag;\n    u4_recwidth_cr = ps_dec->u2_frm_wd_uv << u1_mb_field_decoding_flag;\n    /************* Current and top luma pointer *****************/\n\n    if(u1_mbaff)\n    {\n        if(u1_topmb == 0)\n        {\n            pu1_luma_rec_buffer += (\n                            u1_mb_field_decoding_flag ?\n                                            (ui_rec_width >> 1) :\n                                            (ui_rec_width << 4));\n            pu1_mb_cb_rei1_buffer += (\n                            u1_mb_field_decoding_flag ?\n                                            (u4_recwidth_cr >> 1) :\n                                            (u4_recwidth_cr << 3));\n            pu1_mb_cr_rei1_buffer += (\n                            u1_mb_field_decoding_flag ?\n                                            (u4_recwidth_cr >> 1) :\n                                            (u4_recwidth_cr << 3));\n        }\n    }\n\n    /* CHANGED CODE */\n    if(ps_dec->u4_use_intrapred_line_copy == 1)\n    {\n        puc_top = ps_dec->pu1_prev_y_intra_pred_line + (ps_cur_mb_info->u2_mbx << 4);\n        pu1_top_u = ps_dec->pu1_prev_u_intra_pred_line\n                        + (ps_cur_mb_info->u2_mbx << 3) * YUV420SP_FACTOR;\n    }\n    else\n    {\n        puc_top = pu1_luma_rec_buffer - ui_rec_width;\n        pu1_top_u = pu1_mb_cb_rei1_buffer - u4_recwidth_cr;\n    }\n    /* CHANGED CODE */\n\n    /************* Left pointer *****************/\n    pu1_yleft = pu1_luma_rec_buffer - 1;\n    pu1_uleft = pu1_mb_cb_rei1_buffer - 1 * YUV420SP_FACTOR;\n\n    /**************Top Left pointer calculation**********/\n    pu1_ytop_left = puc_top - 1;\n    pu1_u_top_left = pu1_top_u - 1 * YUV420SP_FACTOR;\n\n    /* CHANGED CODE */\n    PROFILE_DISABLE_INTRA_PRED()\n    {\n        pu1_prev_intra4x4_pred_mode_data = (UWORD8 *)ps_dec->pv_proc_tu_coeff_data;\n        if(u1_mb_type == I_4x4_MB && ps_cur_mb_info->u1_tran_form8x8 == 0)\n        {\n            ps_dec->pv_proc_tu_coeff_data = (void *)((UWORD8 *)ps_dec->pv_proc_tu_coeff_data + 32);\n\n        }\n        else if (u1_mb_type == I_4x4_MB && ps_cur_mb_info->u1_tran_form8x8 == 1)\n        {\n            ps_dec->pv_proc_tu_coeff_data = (void *)((UWORD8 *)ps_dec->pv_proc_tu_coeff_data + 8);\n        }\n    }\n    if(!ps_cur_mb_info->u1_tran_form8x8)\n    {\n        u4_luma_dc_only_csbp = ih264d_unpack_luma_coeff4x4_mb(ps_dec,\n                                       ps_cur_mb_info,\n                                       1);\n    }\n    else\n    {\n        if(!ps_dec->ps_cur_pps->u1_entropy_coding_mode)\n        {\n            u4_luma_dc_only_cbp = ih264d_unpack_luma_coeff4x4_mb(ps_dec,\n                                           ps_cur_mb_info,\n                                           1);\n        }\n        else\n        {\n            u4_luma_dc_only_cbp = ih264d_unpack_luma_coeff8x8_mb(ps_dec,\n                                           ps_cur_mb_info);\n        }\n    }\n\n    pi2_y_coeff = ps_dec->pi2_coeff_data;\n\n    if(u1_mb_type != I_4x4_MB)\n    {\n        UWORD8 u1_intrapred_mode = MB_TYPE_TO_INTRA_16x16_MODE(u1_mb_type);\n        /*--------------------------------------------------------------------*/\n        /* 16x16 IntraPrediction                                              */\n        /*--------------------------------------------------------------------*/\n        {\n            UWORD8 u1_packed_modes = (u1_top_available << 1)\n                            + u1_left_available;\n            UWORD8 u1_err_code =\n                            (u1_intrapred_mode & 1) ?\n                                            u1_intrapred_mode :\n                                            (u1_intrapred_mode ^ 2);\n\n            if((u1_err_code & u1_packed_modes) ^ u1_err_code)\n            {\n                u1_intrapred_mode = 0;\n                ps_dec->i4_error_code = ERROR_INTRAPRED;\n            }\n        }\n        {\n            /* Align the size to multiple of 8, so that SIMD functions\n               can read 64 bits at a time. Only 33 bytes are actaully used */\n            UWORD8 au1_ngbr_pels[40];\n            /* Get neighbour pixels */\n            /* left pels */\n            if(u2_use_left_mb)\n            {\n                WORD32 i;\n                for(i = 0; i < 16; i++)\n                    au1_ngbr_pels[16 - 1 - i] = pu1_yleft[i * ui_rec_width];\n            }\n            else\n            {\n                memset(au1_ngbr_pels, 0, 16);\n            }\n\n            /* top left pels */\n            au1_ngbr_pels[16] = *pu1_ytop_left;\n\n            /* top pels */\n            if(uc_useTopMB)\n            {\n                memcpy(au1_ngbr_pels + 16 + 1, puc_top, 16);\n            }\n            else\n            {\n                memset(au1_ngbr_pels + 16 + 1, 0, 16);\n            }\n            PROFILE_DISABLE_INTRA_PRED()\n            ps_dec->apf_intra_pred_luma_16x16[u1_intrapred_mode](\n                            au1_ngbr_pels, pu1_luma_rec_buffer, 1, ui_rec_width,\n                            ((uc_useTopMB << 2) | u2_use_left_mb));\n        }\n        {\n            UWORD32 i;\n            WORD16 ai2_tmp[16];\n            for(i = 0; i < 16; i++)\n            {\n                WORD16 *pi2_level = pi2_y_coeff + (i << 4);\n                UWORD8 *pu1_pred_sblk = pu1_luma_rec_buffer\n                                + ((i & 0x3) * BLK_SIZE)\n                                + (i >> 2) * (ui_rec_width << 2);\n                PROFILE_DISABLE_IQ_IT_RECON()\n                {\n                    if(CHECKBIT(ps_cur_mb_info->u2_luma_csbp, i))\n                    {\n                        ps_dec->pf_iquant_itrans_recon_luma_4x4(\n                                        pi2_level,\n                                        pu1_pred_sblk,\n                                        pu1_pred_sblk,\n                                        ui_rec_width,\n                                        ui_rec_width,\n                                        gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qp_rem6],\n                                        (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[0],\n                                        ps_cur_mb_info->u1_qp_div6, ai2_tmp, 1,\n                                        pi2_level);\n                    }\n                    else if((CHECKBIT(u4_luma_dc_only_csbp, i)) && pi2_level[0] != 0)\n                    {\n                        ps_dec->pf_iquant_itrans_recon_luma_4x4_dc(\n                                        pi2_level,\n                                        pu1_pred_sblk,\n                                        pu1_pred_sblk,\n                                        ui_rec_width,\n                                        ui_rec_width,\n                                        gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qp_rem6],\n                                        (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[0],\n                                        ps_cur_mb_info->u1_qp_div6, ai2_tmp, 1,\n                                        pi2_level);\n                    }\n                }\n            }\n        }\n    }\n    else if(!ps_cur_mb_info->u1_tran_form8x8)\n    {\n        UWORD8 u1_is_left_sub_block, u1_is_top_sub_block = uc_useTopMB;\n        UWORD8 u1_sub_blk_x, u1_sub_blk_y, u1_sub_mb_num;\n        WORD8 i1_top_pred_mode;\n        WORD8 i1_left_pred_mode;\n        UWORD8 *pu1_top, *pu1_left, *pu1_top_left, *pu1_top_right;\n        WORD8 *pi1_cur_pred_mode, *pi1_left_pred_mode, *pc_topPredMode;\n        UWORD16 ui2_left_pred_buf_width = 0xffff;\n        WORD8 i1_intra_pred;\n        UWORD8 *pu1_prev_intra4x4_pred_mode_flag = pu1_prev_intra4x4_pred_mode_data;\n        UWORD8 *pu1_rem_intra4x4_pred_mode = pu1_prev_intra4x4_pred_mode_data + 16;\n        WORD16 *pi2_y_coeff1;\n        UWORD8 u1_cur_sub_block;\n        UWORD16 ui2_top_rt_mask;\n\n        /*--------------------------------------------------------------------*/\n        /* 4x4 IntraPrediction                                                */\n        /*--------------------------------------------------------------------*/\n        /* Calculation of Top Right subblock mask                             */\n        /*                                                                    */\n        /* (a) Set it to default mask                                         */\n        /*     [It has 0 for sublocks which will never have top-right sub block] */\n        /*                                                                    */\n        /* (b) If top MB is not available                                     */\n        /*      Clear the bits of the first row sub blocks                    */\n        /*                                                                    */\n        /* (c) Set/Clear bit for top-right sublock of MB                      */\n        /*      [5 sub-block in decoding order] based on TOP RIGHT MB availablity */\n        /*--------------------------------------------------------------------*/\n\n        pu1_top = puc_top;\n\n        ui2_top_rt_mask = (u1_use_top_right_mb << 3) | (0x5750);\n        if(uc_useTopMB)\n            ui2_top_rt_mask |= 0x7;\n\n        /*Top Related initialisations*/\n\n\n        pi1_cur_pred_mode = ps_cur_mb_info->ps_curmb->pi1_intrapredmodes;\n        pc_topPredMode = ps_cur_mb_info->ps_top_mb->pi1_intrapredmodes;\n        /*--------------------------------------\n         if(u1_mbaff)\n         {\n\n         pi1_cur_pred_mode += (u2_mbx << 2);\n         pc_topPredMode = pi1_cur_pred_mode + ps_cur_mb_info->i1_offset;\n         pi1_cur_pred_mode += (u1_topmb) ? 0: 4;\n         }*/\n\n        if(u1_top_available)\n        {\n            if(ps_top_mb->u1_mb_type == I_4x4_MB)\n                *(WORD32*)pi1_cur_pred_mode = *(WORD32*)pc_topPredMode;\n            else\n                *(WORD32*)pi1_cur_pred_mode =\n                                (uc_useTopMB) ? DC_DC_DC_DC : NOT_VALID;\n        }\n        else\n            *(WORD32*)pi1_cur_pred_mode = NOT_VALID;\n        /* CHANGED CODE */\n\n        /* CHANGED CODE */\n\n        /*Left Related initialisations*/\n        pi1_left_pred_mode = ps_dec->pi1_left_pred_mode;\n        if(!u1_mbaff)\n        {\n\n            if(u1_left_available)\n            {\n\n                if(ps_left_mb->u1_mb_type != I_4x4_MB)\n                    *(WORD32*)pi1_left_pred_mode =\n                                    (u2_use_left_mb_pack) ?\n                                    DC_DC_DC_DC :\n                                                            NOT_VALID;\n\n            }\n            else\n            {\n\n                *(WORD32*)pi1_left_pred_mode = NOT_VALID;\n            }\n\n        }\n        else\n        {\n            UWORD8 u1_curMbfld = ps_cur_mb_info->u1_mb_field_decodingflag;\n            UWORD8 u1_leftMbfld = ps_left_mb->u1_mb_fld;\n\n            if(u1_curMbfld ^ u1_leftMbfld)\n            {\n\n                if(u1_topmb\n                                | ((u1_topmb == 0)\n                                                && ((ps_curmb - 1)->u1_mb_type\n                                                                != I_4x4_MB)))\n                {\n                    if(u1_left_available)\n                    {\n                        if(ps_left_mb->u1_mb_type != I_4x4_MB)\n                        {\n                            if(CHECKBIT(u2_use_left_mb_pack,0) == 0)\n                                *(WORD32*)pi1_left_pred_mode = NOT_VALID;\n                            else\n                                *(WORD32*)pi1_left_pred_mode = DC_DC_DC_DC;\n                        }\n                    }\n                    else\n                        *(WORD32*)pi1_left_pred_mode = NOT_VALID;\n\n                    if(u1_curMbfld)\n                    {\n                        if(u1_left_available)\n                        {\n                            if((ps_left_mb + 1)->u1_mb_type != I_4x4_MB)\n                            {\n                                if(u2_use_left_mb_pack >> 8)\n                                    *(WORD32*)(pi1_left_pred_mode + 4) =\n                                                    DC_DC_DC_DC;\n                                else\n                                    *(WORD32*)(pi1_left_pred_mode + 4) =\n                                                    NOT_VALID;\n                            }\n                        }\n                        else\n                            *(WORD32*)(pi1_left_pred_mode + 4) = NOT_VALID;\n                        pi1_left_pred_mode[1] = pi1_left_pred_mode[2];\n                        pi1_left_pred_mode[2] = pi1_left_pred_mode[4];\n                        pi1_left_pred_mode[3] = pi1_left_pred_mode[6];\n                        *(WORD32*)(pi1_left_pred_mode + 4) =\n                                        *(WORD32*)pi1_left_pred_mode;\n                    }\n                    else\n                    {\n\n                        pi1_left_pred_mode[7] = pi1_left_pred_mode[3];\n                        pi1_left_pred_mode[6] = pi1_left_pred_mode[3];\n                        pi1_left_pred_mode[5] = pi1_left_pred_mode[2];\n                        pi1_left_pred_mode[4] = pi1_left_pred_mode[2];\n                        pi1_left_pred_mode[3] = pi1_left_pred_mode[1];\n                        pi1_left_pred_mode[2] = pi1_left_pred_mode[1];\n                        pi1_left_pred_mode[1] = pi1_left_pred_mode[0];\n                    }\n                }\n                pi1_left_pred_mode += (u1_topmb) ? 0 : 4;\n            }\n            else\n            {\n\n                pi1_left_pred_mode += (u1_topmb) ? 0 : 4;\n                if(u1_left_available)\n                {\n\n                    if(ps_left_mb->u1_mb_type != I_4x4_MB)\n                        *(WORD32*)pi1_left_pred_mode =\n                                        (u2_use_left_mb_pack) ?\n                                        DC_DC_DC_DC :\n                                                                NOT_VALID;\n                }\n                else\n                    *(WORD32*)pi1_left_pred_mode = NOT_VALID;\n            }\n        }\n        /* One time pointer initialisations*/\n        pi2_y_coeff1 = pi2_y_coeff;\n        pu1_top_left = pu1_ytop_left;\n\n        /* Scan the sub-blocks in Raster Scan Order */\n        for(u1_sub_mb_num = 0; u1_sub_mb_num < 16; u1_sub_mb_num++)\n        {\n            /* Align the size to multiple of 8, so that SIMD functions\n               can read 64 bits at a time. Only 13 bytes are actaully used */\n            UWORD8 au1_ngbr_pels[16];\n\n            u1_sub_blk_x = u1_sub_mb_num & 0x3;\n            u1_sub_blk_y = u1_sub_mb_num >> 2;\n            i1_top_pred_mode = pi1_cur_pred_mode[u1_sub_blk_x];\n            i1_left_pred_mode = pi1_left_pred_mode[u1_sub_blk_y];\n            u1_use_top_right_mb = (!!CHECKBIT(ui2_top_rt_mask, u1_sub_mb_num));\n\n            /*********** left subblock availability**********/\n            if(u1_sub_blk_x)\n                u1_is_left_sub_block = 1;\n            else\n                u1_is_left_sub_block =\n                                (u1_sub_blk_y < 2) ?\n                                                (CHECKBIT(u2_use_left_mb_pack,\n                                                          0)) :\n                                                (u2_use_left_mb_pack >> 8);\n\n            /* CHANGED CODE */\n            if(u1_sub_blk_y)\n                u1_is_top_sub_block = 1;\n\n            /* CHANGED CODE */\n            /***************** Top *********************/\n            if(ps_dec->u4_use_intrapred_line_copy == 1)\n            {\n\n                if(u1_sub_blk_y)\n                    pu1_top = pu1_luma_rec_buffer - ui_rec_width;\n                else\n                    pu1_top = puc_top + (u1_sub_blk_x << 2);\n            }\n            else\n            {\n                pu1_top = pu1_luma_rec_buffer - ui_rec_width;\n            }\n            /***************** Top Right *********************/\n            pu1_top_right = pu1_top + 4;\n            /***************** Top Left *********************/\n            pu1_top_left = pu1_top - 1;\n            /***************** Left *********************/\n            pu1_left = pu1_luma_rec_buffer - 1;\n            /* CHANGED CODE */\n\n            /*---------------------------------------------------------------*/\n            /* Calculation of Intra prediction mode                          */\n            /*---------------------------------------------------------------*/\n            i1_intra_pred = ((i1_left_pred_mode < 0) | (i1_top_pred_mode < 0)) ?\n                            DC : MIN(i1_left_pred_mode, i1_top_pred_mode);\n            {\n                UWORD8 u1_packed_modes = (u1_is_top_sub_block << 1)\n                                + u1_is_left_sub_block;\n                UWORD8 *pu1_intra_err_codes =\n                                (UWORD8 *)gau1_ih264d_intra_pred_err_code;\n                UWORD8 uc_b2b0 = ((u1_sub_mb_num & 4) >> 1) | (u1_sub_mb_num & 1);\n                UWORD8 uc_b3b1 = ((u1_sub_mb_num & 8) >> 2)\n                                | ((u1_sub_mb_num & 2) >> 1);\n\n                u1_cur_sub_block = (uc_b3b1 << 2) + uc_b2b0;\n                PROFILE_DISABLE_INTRA_PRED()\n                if(!pu1_prev_intra4x4_pred_mode_flag[u1_cur_sub_block])\n                {\n                    i1_intra_pred =\n                                    pu1_rem_intra4x4_pred_mode[u1_cur_sub_block]\n                                                    + (pu1_rem_intra4x4_pred_mode[u1_cur_sub_block]\n                                                                    >= i1_intra_pred);\n                }\n                i1_intra_pred = CLIP3(0, 8, i1_intra_pred);\n                {\n                    UWORD8 u1_err_code = pu1_intra_err_codes[i1_intra_pred];\n\n                    if((u1_err_code & u1_packed_modes) ^ u1_err_code)\n                     {\n                        i1_intra_pred = 0;\n                        ps_dec->i4_error_code = ERROR_INTRAPRED;\n                     }\n\n                }\n            }\n            {\n                /* Get neighbour pixels */\n                /* left pels */\n                if(u1_is_left_sub_block)\n                {\n                    WORD32 i;\n                    for(i = 0; i < 4; i++)\n                        au1_ngbr_pels[4 - 1 - i] = pu1_left[i * ui_rec_width];\n                }\n                else\n                {\n                    memset(au1_ngbr_pels, 0, 4);\n                }\n\n                /* top left pels */\n                au1_ngbr_pels[4] = *pu1_top_left;\n\n                /* top pels */\n                if(u1_is_top_sub_block)\n                {\n                    memcpy(au1_ngbr_pels + 4 + 1, pu1_top, 4);\n                }\n                else\n                {\n                    memset(au1_ngbr_pels + 4 + 1, 0, 4);\n                }\n\n                /* top right pels */\n                if(u1_use_top_right_mb)\n                {\n                    memcpy(au1_ngbr_pels + 4 * 2 + 1, pu1_top_right, 4);\n                }\n                else if(u1_is_top_sub_block)\n                {\n                    memset(au1_ngbr_pels + 4 * 2 + 1, au1_ngbr_pels[4 * 2], 4);\n                }\n            }\n            PROFILE_DISABLE_INTRA_PRED()\n            ps_dec->apf_intra_pred_luma_4x4[i1_intra_pred](\n                            au1_ngbr_pels, pu1_luma_rec_buffer, 1,\n                            ui_rec_width,\n                            ((u1_is_top_sub_block << 2) | u1_is_left_sub_block));\n\n            /* CHANGED CODE */\n            if(CHECKBIT(ui2_luma_csbp, u1_sub_mb_num))\n            {\n                WORD16 ai2_tmp[16];\n                PROFILE_DISABLE_IQ_IT_RECON()\n                {\n                    if(CHECKBIT(u4_luma_dc_only_csbp, u1_sub_mb_num))\n                    {\n                        ps_dec->pf_iquant_itrans_recon_luma_4x4_dc(\n                                        pi2_y_coeff1,\n                                        pu1_luma_rec_buffer,\n                                        pu1_luma_rec_buffer,\n                                        ui_rec_width,\n                                        ui_rec_width,\n                                        gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qp_rem6],\n                                        (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[0],\n                                        ps_cur_mb_info->u1_qp_div6, ai2_tmp, 0,\n                                        NULL);\n                    }\n                    else\n                    {\n                        ps_dec->pf_iquant_itrans_recon_luma_4x4(\n                                        pi2_y_coeff1,\n                                        pu1_luma_rec_buffer,\n                                        pu1_luma_rec_buffer,\n                                        ui_rec_width,\n                                        ui_rec_width,\n                                        gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qp_rem6],\n                                        (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[0],\n                                        ps_cur_mb_info->u1_qp_div6, ai2_tmp, 0,\n                                        NULL);\n                    }\n                }\n\n            }\n\n            /*---------------------------------------------------------------*/\n            /* Update sub block number                                       */\n            /*---------------------------------------------------------------*/\n            pi2_y_coeff1 += 16;\n            pu1_luma_rec_buffer +=\n                            (u1_sub_blk_x == 3) ? (ui_rec_width << 2) - 12 : 4;\n            pu1_luma_pred_buffer +=\n                            (u1_sub_blk_x == 3) ? (ui_pred_width << 2) - 12 : 4;\n            /* CHANGED CODE */\n            pi1_cur_pred_mode[u1_sub_blk_x] = i1_intra_pred;\n            pi1_left_pred_mode[u1_sub_blk_y] = i1_intra_pred;\n        }\n    }\n    else if((u1_mb_type == I_4x4_MB) && (ps_cur_mb_info->u1_tran_form8x8 == 1))\n    {\n        UWORD8 u1_is_left_sub_block, u1_is_top_sub_block = uc_useTopMB;\n        UWORD8 u1_sub_blk_x, u1_sub_blk_y, u1_sub_mb_num;\n        WORD8 i1_top_pred_mode;\n        WORD8 i1_left_pred_mode;\n        UWORD8 *pu1_top, *pu1_left, *pu1_top_left;\n        WORD8 *pi1_cur_pred_mode, *pi1_left_pred_mode, *pc_topPredMode;\n        UWORD16 ui2_left_pred_buf_width = 0xffff;\n        WORD8 i1_intra_pred;\n        UWORD8 *pu1_prev_intra4x4_pred_mode_flag = pu1_prev_intra4x4_pred_mode_data;\n        UWORD8 *pu1_rem_intra4x4_pred_mode = pu1_prev_intra4x4_pred_mode_data + 4;\n        WORD16 *pi2_y_coeff1;\n        UWORD16 ui2_top_rt_mask;\n        UWORD32 u4_4x4_left_offset = 0;\n\n        /*--------------------------------------------------------------------*/\n        /* 8x8 IntraPrediction                                                */\n        /*--------------------------------------------------------------------*/\n        /* Calculation of Top Right subblock mask                             */\n        /*                                                                    */\n        /* (a) Set it to default mask                                         */\n        /*  [It has 0 for sublocks which will never have top-right sub block] */\n        /*                                                                    */\n        /* (b) If top MB is not available                                     */\n        /*      Clear the bits of the first row sub blocks                    */\n        /*                                                                    */\n        /* (c) Set/Clear bit for top-right sublock of MB                      */\n        /*  [5 sub-block in decoding order] based on TOP RIGHT MB availablity */\n        /*                                                                    */\n        /* ui2_top_rt_mask: marks availibility of top right(neighbour)         */\n        /* in the 8x8 Block ordering                                          */\n        /*                                                                    */\n        /*      tr0   tr1                                                     */\n        /*   0    1   tr3                                                     */\n        /*   2    3                                                           */\n        /*                                                                    */\n        /*  Top rights for 0 is in top MB                                     */\n        /*  top right of 1 will be in top right MB                            */\n        /*  top right of 3 in right MB and hence not available                */\n        /*  This corresponds to ui2_top_rt_mask  having default value 0x4      */\n        /*--------------------------------------------------------------------*/\n\n        ui2_top_rt_mask = (u1_use_top_right_mb << 1) | (0x4);\n\n        if(uc_useTopMB)\n        {\n            ui2_top_rt_mask |= 0x1;\n        }\n\n        /* Top Related initialisations */\n        pi1_cur_pred_mode = ps_cur_mb_info->ps_curmb->pi1_intrapredmodes;\n        pc_topPredMode = ps_cur_mb_info->ps_top_mb->pi1_intrapredmodes;\n        /*\n         if(u1_mbaff)\n         {\n         pi1_cur_pred_mode += (u2_mbx << 2);\n         pc_topPredMode = pi1_cur_pred_mode + ps_cur_mb_info->i1_offset;\n         pi1_cur_pred_mode += (u1_topmb) ? 0: 4;\n         }\n         */\n        if(u1_top_available)\n        {\n            if(ps_top_mb->u1_mb_type == I_4x4_MB)\n            {\n                *(WORD32*)pi1_cur_pred_mode = *(WORD32*)pc_topPredMode;\n            }\n            else\n            {\n                *(WORD32*)pi1_cur_pred_mode =\n                                (uc_useTopMB) ? DC_DC_DC_DC : NOT_VALID;\n            }\n        }\n        else\n        {\n            *(WORD32*)pi1_cur_pred_mode = NOT_VALID;\n        }\n\n        pu1_top = puc_top - 8;\n\n        /*Left Related initialisations*/\n        pi1_left_pred_mode = ps_dec->pi1_left_pred_mode;\n\n        if(!u1_mbaff)\n        {\n            if(u1_left_available)\n            {\n                if(ps_left_mb->u1_mb_type != I_4x4_MB)\n                {\n                    *(WORD32*)pi1_left_pred_mode =\n                                    (u2_use_left_mb_pack) ?\n                                    DC_DC_DC_DC :\n                                                            NOT_VALID;\n                }\n            }\n            else\n            {\n                *(WORD32*)pi1_left_pred_mode = NOT_VALID;\n            }\n        }\n        else\n        {\n            UWORD8 u1_curMbfld = ps_cur_mb_info->u1_mb_field_decodingflag;\n\n            UWORD8 u1_leftMbfld = ps_left_mb->u1_mb_fld;\n\n            if((!u1_curMbfld) && (u1_leftMbfld))\n            {\n                u4_4x4_left_offset = 1;\n            }\n\n            if(u1_curMbfld ^ u1_leftMbfld)\n            {\n\n                if(u1_topmb\n                                | ((u1_topmb == 0)\n                                                && ((ps_curmb - 1)->u1_mb_type\n                                                                != I_4x4_MB)))\n\n                {\n                    if(u1_left_available)\n                    {\n                        if(ps_left_mb->u1_mb_type != I_4x4_MB)\n                        {\n                            if(CHECKBIT(u2_use_left_mb_pack,0) == 0)\n                            {\n                                *(WORD32*)pi1_left_pred_mode = NOT_VALID;\n                            }\n                            else\n                            {\n                                *(WORD32*)pi1_left_pred_mode = DC_DC_DC_DC;\n                            }\n                        }\n                    }\n                    else\n                    {\n                        *(WORD32*)pi1_left_pred_mode = NOT_VALID;\n                    }\n\n                    if(u1_curMbfld)\n                    {\n                        if(u1_left_available)\n                        {\n                            if((ps_left_mb + 1)->u1_mb_type != I_4x4_MB)\n                            {\n                                if(u2_use_left_mb_pack >> 8)\n                                {\n                                    *(WORD32*)(pi1_left_pred_mode + 4) =\n                                                    DC_DC_DC_DC;\n                                }\n                                else\n                                {\n                                    *(WORD32*)(pi1_left_pred_mode + 4) =\n                                                    NOT_VALID;\n                                }\n                            }\n                        }\n                        else\n                        {\n                            *(WORD32*)(pi1_left_pred_mode + 4) = NOT_VALID;\n                        }\n\n                        pi1_left_pred_mode[1] = pi1_left_pred_mode[2];\n                        pi1_left_pred_mode[2] = pi1_left_pred_mode[4];\n                        pi1_left_pred_mode[3] = pi1_left_pred_mode[6];\n                        *(WORD32*)(pi1_left_pred_mode + 4) =\n                                        *(WORD32*)pi1_left_pred_mode;\n                    }\n                    else\n                    {\n                        pi1_left_pred_mode[7] = pi1_left_pred_mode[3];\n                        pi1_left_pred_mode[6] = pi1_left_pred_mode[3];\n                        pi1_left_pred_mode[5] = pi1_left_pred_mode[2];\n                        pi1_left_pred_mode[4] = pi1_left_pred_mode[2];\n                        pi1_left_pred_mode[3] = pi1_left_pred_mode[1];\n                        pi1_left_pred_mode[2] = pi1_left_pred_mode[1];\n                        pi1_left_pred_mode[1] = pi1_left_pred_mode[0];\n                    }\n                }\n                pi1_left_pred_mode += (u1_topmb) ? 0 : 4;\n            }\n            else\n            {\n                pi1_left_pred_mode += (u1_topmb) ? 0 : 4;\n\n                if(u1_left_available)\n                {\n                    if(ps_left_mb->u1_mb_type != I_4x4_MB)\n                    {\n                        *(WORD32*)pi1_left_pred_mode =\n                                        (u2_use_left_mb_pack) ?\n                                        DC_DC_DC_DC :\n                                                                NOT_VALID;\n                    }\n                }\n                else\n                {\n                    *(WORD32*)pi1_left_pred_mode = NOT_VALID;\n                }\n            }\n        }\n\n        /* One time pointer initialisations*/\n        pi2_y_coeff1 = pi2_y_coeff;\n\n        if(u1_use_top_left_mb)\n        {\n            pu1_top_left = pu1_ytop_left;\n        }\n        else\n        {\n            pu1_top_left = NULL;\n        }\n\n        /* Scan the sub-blocks in Raster Scan Order */\n        for(u1_sub_mb_num = 0; u1_sub_mb_num < 4; u1_sub_mb_num++)\n        {\n            u1_sub_blk_x = (u1_sub_mb_num & 0x1);\n            u1_sub_blk_y = (u1_sub_mb_num >> 1);\n            i1_top_pred_mode = pi1_cur_pred_mode[u1_sub_blk_x << 1];\n            i1_left_pred_mode = pi1_left_pred_mode[u1_sub_blk_y << 1];\n\n            if(2 == u1_sub_mb_num)\n            {\n                i1_left_pred_mode = pi1_left_pred_mode[(u1_sub_blk_y << 1)\n                                + u4_4x4_left_offset];\n            }\n\n            u1_use_top_right_mb = (!!CHECKBIT(ui2_top_rt_mask, u1_sub_mb_num));\n\n            /*********** left subblock availability**********/\n            if(u1_sub_blk_x)\n            {\n                u1_is_left_sub_block = 1;\n            }\n            else\n            {\n                u1_is_left_sub_block =\n                                (u1_sub_blk_y < 1) ?\n                                                (CHECKBIT(u2_use_left_mb_pack,\n                                                          0)) :\n                                                (u2_use_left_mb_pack >> 8);\n            }\n\n            /***************** Top *********************/\n            if(u1_sub_blk_y)\n            {\n                u1_is_top_sub_block = 1;\n                // sushant\n                pu1_top = /*pu1_luma_pred_buffer*/pu1_luma_rec_buffer - ui_rec_width;\n            }\n            else\n            {\n                pu1_top += 8;\n            }\n\n            /***************** Left *********************/\n            if((u1_sub_blk_x) | (u4_num_pmbair != 0))\n            {\n                // sushant\n                pu1_left = /*pu1_luma_pred_buffer*/pu1_luma_rec_buffer - 1;\n                ui2_left_pred_buf_width = ui_rec_width;\n            }\n            else\n            {\n                pu1_left = pu1_yleft;\n                pu1_yleft += (ui_rec_width << 3);\n                ui2_left_pred_buf_width = ui_rec_width;\n            }\n\n            /***************** Top Left *********************/\n            if(u1_sub_mb_num)\n            {\n                pu1_top_left = (u1_sub_blk_x) ?\n                                pu1_top - 1 : pu1_left - ui_rec_width;\n\n                if((u1_sub_blk_x && (!u1_is_top_sub_block))\n                                || ((!u1_sub_blk_x) && (!u1_is_left_sub_block)))\n                {\n                    pu1_top_left = NULL;\n                }\n            }\n\n            /*---------------------------------------------------------------*/\n            /* Calculation of Intra prediction mode                          */\n            /*---------------------------------------------------------------*/\n            i1_intra_pred = ((i1_left_pred_mode < 0) | (i1_top_pred_mode < 0)) ?\n                            DC : MIN(i1_left_pred_mode, i1_top_pred_mode);\n            {\n                UWORD8 u1_packed_modes = (u1_is_top_sub_block << 1)\n                                + u1_is_left_sub_block;\n                UWORD8 *pu1_intra_err_codes =\n                                (UWORD8 *)gau1_ih264d_intra_pred_err_code;\n\n                /********************************************************************/\n                /* Same intra4x4_pred_mode array is filled with intra4x4_pred_mode  */\n                /* for a MB with 8x8 intrapredicition                               */\n                /********************************************************************/\n                PROFILE_DISABLE_INTRA_PRED()\n                if(!pu1_prev_intra4x4_pred_mode_flag[u1_sub_mb_num])\n                {\n                    i1_intra_pred = pu1_rem_intra4x4_pred_mode[u1_sub_mb_num]\n                                    + (pu1_rem_intra4x4_pred_mode[u1_sub_mb_num]\n                                                    >= i1_intra_pred);\n                }\n                i1_intra_pred = CLIP3(0, 8, i1_intra_pred);\n                {\n                    UWORD8 u1_err_code = pu1_intra_err_codes[i1_intra_pred];\n\n                    if((u1_err_code & u1_packed_modes) ^ u1_err_code)\n                    {\n                        i1_intra_pred = 0;\n                        ps_dec->i4_error_code = ERROR_INTRAPRED;\n                    }\n                }\n            }\n\n            {\n                /* Align the size to multiple of 8, so that SIMD functions\n                can read 64 bits at a time. Only 25 bytes are actaully used */\n                UWORD8 au1_ngbr_pels[32] = {0};\n                WORD32 ngbr_avail;\n                ngbr_avail = u1_is_left_sub_block << 0;\n                ngbr_avail |= u1_is_top_sub_block << 2;\n\n                if(pu1_top_left)\n                    ngbr_avail |= 1 << 1;\n\n                ngbr_avail |= u1_use_top_right_mb << 3;\n                PROFILE_DISABLE_INTRA_PRED()\n                {\n                    ps_dec->pf_intra_pred_ref_filtering(pu1_left, pu1_top_left,\n                                                        pu1_top, au1_ngbr_pels,\n                                                        ui2_left_pred_buf_width,\n                                                        ngbr_avail);\n\n                    ps_dec->apf_intra_pred_luma_8x8[i1_intra_pred](\n                                    au1_ngbr_pels, pu1_luma_rec_buffer, 1,\n                                    ui_rec_width,\n                                    ((u1_is_top_sub_block << 2) | u1_is_left_sub_block));\n                }\n            }\n\n            /* Inverse Transform and Reconstruction */\n            if(CHECKBIT(ps_cur_mb_info->u1_cbp, u1_sub_mb_num))\n            {\n                WORD16 *pi2_scale_matrix_ptr;\n                WORD16 ai2_tmp[64];\n\n                pi2_scale_matrix_ptr =\n                                ps_dec->s_high_profile.i2_scalinglist8x8[0];\n                PROFILE_DISABLE_IQ_IT_RECON()\n                {\n                    if(CHECKBIT(u4_luma_dc_only_cbp, u1_sub_mb_num))\n                    {\n                        ps_dec->pf_iquant_itrans_recon_luma_8x8_dc(\n                                        pi2_y_coeff1,\n                                        pu1_luma_rec_buffer,\n                                        pu1_luma_rec_buffer,\n                                        ui_rec_width,\n                                        ui_rec_width,\n                                        gau1_ih264d_dequant8x8_cavlc[ps_cur_mb_info->u1_qp_rem6],\n                                        (UWORD16 *)pi2_scale_matrix_ptr,\n                                        ps_cur_mb_info->u1_qp_div6, ai2_tmp, 0,\n                                        NULL);\n                    }\n                    else\n                    {\n                        ps_dec->pf_iquant_itrans_recon_luma_8x8(\n                                        pi2_y_coeff1,\n                                        pu1_luma_rec_buffer,\n                                        pu1_luma_rec_buffer,\n                                        ui_rec_width,\n                                        ui_rec_width,\n                                        gau1_ih264d_dequant8x8_cavlc[ps_cur_mb_info->u1_qp_rem6],\n                                        (UWORD16 *)pi2_scale_matrix_ptr,\n                                        ps_cur_mb_info->u1_qp_div6, ai2_tmp, 0,\n                                        NULL);\n                    }\n                }\n\n            }\n\n            /*---------------------------------------------------------------*/\n            /* Update sub block number                                       */\n            /*---------------------------------------------------------------*/\n            pi2_y_coeff1 += 64;\n\n            pu1_luma_rec_buffer +=\n                            (u1_sub_blk_x == 1) ?\n                                            (ui_rec_width << 3) - (8 * 1) : 8;\n\n            /*---------------------------------------------------------------*/\n            /* Pred mode filled in terms of 4x4 block so replicated in 2     */\n            /* locations.                                                    */\n            /*---------------------------------------------------------------*/\n            pi1_cur_pred_mode[u1_sub_blk_x << 1] = i1_intra_pred;\n            pi1_cur_pred_mode[(u1_sub_blk_x << 1) + 1] = i1_intra_pred;\n            pi1_left_pred_mode[u1_sub_blk_y << 1] = i1_intra_pred;\n            pi1_left_pred_mode[(u1_sub_blk_y << 1) + 1] = i1_intra_pred;\n        }\n    }\n    /* Decode Chroma Block */\n    ih264d_unpack_chroma_coeff4x4_mb(ps_dec,\n                                     ps_cur_mb_info);\n    /*--------------------------------------------------------------------*/\n    /* Chroma Blocks decoding                                             */\n    /*--------------------------------------------------------------------*/\n    {\n        UWORD8 u1_intra_chrom_pred_mode;\n        UWORD8 u1_chroma_cbp = (UWORD8)(ps_cur_mb_info->u1_cbp >> 4);\n\n        /*--------------------------------------------------------------------*/\n        /* Perform Chroma intra prediction                                    */\n        /*--------------------------------------------------------------------*/\n\n        u1_intra_chrom_pred_mode = CHROMA_TO_LUMA_INTRA_MODE(\n                        ps_cur_mb_info->u1_chroma_pred_mode);\n\n        {\n            UWORD8 u1_packed_modes = (u1_top_available << 1)\n                            + u1_left_available;\n            UWORD8 u1_err_code =\n                            (u1_intra_chrom_pred_mode & 1) ?\n                                            u1_intra_chrom_pred_mode :\n                                            (u1_intra_chrom_pred_mode ^ 2);\n            if((u1_err_code & u1_packed_modes) ^ u1_err_code)\n            {\n                u1_intra_chrom_pred_mode = 0;\n                ps_dec->i4_error_code = ERROR_INTRAPRED;\n            }\n        }\n\n        /* CHANGED CODE */\n        if(u1_chroma_cbp != CBPC_ALLZERO)\n        {\n            UWORD16 u2_chroma_csbp =\n                            (u1_chroma_cbp == CBPC_ACZERO) ?\n                                            0 : ps_cur_mb_info->u2_chroma_csbp;\n            UWORD32 u4_scale_u;\n            UWORD32 u4_scale_v;\n\n            {\n                UWORD16 au2_ngbr_pels[33];\n                UWORD8 *pu1_ngbr_pels = (UWORD8 *)au2_ngbr_pels;\n                UWORD16 *pu2_left_uv;\n                UWORD16 *pu2_topleft_uv;\n                WORD32 use_left1 = (u2_use_left_mb_pack & 0x0ff);\n                WORD32 use_left2 = (u2_use_left_mb_pack & 0xff00) >> 8;\n\n                pu2_left_uv = (UWORD16 *)pu1_uleft;\n                pu2_topleft_uv = (UWORD16 *)pu1_u_top_left;\n                /* Get neighbour pixels */\n                /* left pels */\n                if(u2_use_left_mb_pack)\n                {\n                    WORD32 i;\n                    if(use_left1)\n                    {\n                        for(i = 0; i < 4; i++)\n                            au2_ngbr_pels[8 - 1 - i] = pu2_left_uv[i\n                                            * u4_recwidth_cr / YUV420SP_FACTOR];\n                    }\n                    else\n                    {\n                        memset(au2_ngbr_pels + 4, 0, 4 * sizeof(UWORD16));\n                    }\n\n                    if(use_left2)\n                    {\n                        for(i = 4; i < 8; i++)\n                            au2_ngbr_pels[8 - 1 - i] = pu2_left_uv[i\n                                            * u4_recwidth_cr / YUV420SP_FACTOR];\n                    }\n                    else\n                    {\n                        memset(au2_ngbr_pels, 0, 4 * sizeof(UWORD16));\n                    }\n                }\n                else\n                {\n                    memset(au2_ngbr_pels, 0, 8 * sizeof(UWORD16));\n                }\n\n                /* top left pels */\n                au2_ngbr_pels[8] = *pu2_topleft_uv;\n\n                /* top pels */\n                if(uc_useTopMB)\n                {\n                    memcpy(au2_ngbr_pels + 8 + 1, pu1_top_u,\n                           8 * sizeof(UWORD16));\n                }\n                else\n                {\n                    memset(au2_ngbr_pels + 8 + 1, 0, 8 * sizeof(UWORD16));\n                }\n\n                PROFILE_DISABLE_INTRA_PRED()\n                ps_dec->apf_intra_pred_chroma[u1_intra_chrom_pred_mode](\n                                pu1_ngbr_pels,\n                                pu1_mb_cb_rei1_buffer,\n                                1,\n                                u4_recwidth_cr,\n                                ((uc_useTopMB << 2) | (use_left2 << 4)\n                                                | use_left1));\n            }\n            u4_scale_u = ps_cur_mb_info->u1_qpc_div6;\n            u4_scale_v = ps_cur_mb_info->u1_qpcr_div6;\n            pi2_y_coeff = ps_dec->pi2_coeff_data;\n\n            {\n                UWORD32 i;\n                WORD16 ai2_tmp[16];\n                for(i = 0; i < 4; i++)\n                {\n                    WORD16 *pi2_level = pi2_y_coeff + (i << 4);\n                    UWORD8 *pu1_pred_sblk = pu1_mb_cb_rei1_buffer\n                                    + ((i & 0x1) * BLK_SIZE * YUV420SP_FACTOR)\n                                    + (i >> 1) * (u4_recwidth_cr << 2);\n                    PROFILE_DISABLE_IQ_IT_RECON()\n                    {\n                        if(CHECKBIT(u2_chroma_csbp, i))\n                        {\n                            ps_dec->pf_iquant_itrans_recon_chroma_4x4(\n                                            pi2_level,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            u4_recwidth_cr,\n                                            u4_recwidth_cr,\n                                            gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qpc_rem6],\n                                            (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[1],\n                                            u4_scale_u, ai2_tmp, pi2_level);\n                        }\n                        else if(pi2_level[0] != 0)\n                        {\n                            ps_dec->pf_iquant_itrans_recon_chroma_4x4_dc(\n                                            pi2_level,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            u4_recwidth_cr,\n                                            u4_recwidth_cr,\n                                            gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qpc_rem6],\n                                            (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[1],\n                                            u4_scale_u, ai2_tmp, pi2_level);\n                        }\n                    }\n\n                }\n            }\n\n            pi2_y_coeff += MB_CHROM_SIZE;\n            u2_chroma_csbp = u2_chroma_csbp >> 4;\n            {\n                UWORD32 i;\n                WORD16 ai2_tmp[16];\n                for(i = 0; i < 4; i++)\n                {\n                    WORD16 *pi2_level = pi2_y_coeff + (i << 4);\n                    UWORD8 *pu1_pred_sblk = pu1_mb_cb_rei1_buffer + 1\n                                    + ((i & 0x1) * BLK_SIZE * YUV420SP_FACTOR)\n                                    + (i >> 1) * (u4_recwidth_cr << 2);\n                    PROFILE_DISABLE_IQ_IT_RECON()\n                    {\n                        if(CHECKBIT(u2_chroma_csbp, i))\n                        {\n                            ps_dec->pf_iquant_itrans_recon_chroma_4x4(\n                                            pi2_level,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            u4_recwidth_cr,\n                                            u4_recwidth_cr,\n                                            gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qpcr_rem6],\n                                            (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[2],\n                                            u4_scale_v, ai2_tmp, pi2_level);\n                        }\n                        else if(pi2_level[0] != 0)\n                        {\n                            ps_dec->pf_iquant_itrans_recon_chroma_4x4_dc(\n                                            pi2_level,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            u4_recwidth_cr,\n                                            u4_recwidth_cr,\n                                            gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qpcr_rem6],\n                                            (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[2],\n                                            u4_scale_v, ai2_tmp, pi2_level);\n                        }\n                    }\n                }\n            }\n\n        }\n        else\n        {\n            /* If no inverse transform is needed, pass recon buffer pointer */\n            /* to Intraprediction module instead of pred buffer pointer     */\n            {\n                UWORD16 au2_ngbr_pels[33];\n                UWORD8 *pu1_ngbr_pels = (UWORD8 *)au2_ngbr_pels;\n                UWORD16 *pu2_left_uv;\n                UWORD16 *pu2_topleft_uv;\n                WORD32 use_left1 = (u2_use_left_mb_pack & 0x0ff);\n                WORD32 use_left2 = (u2_use_left_mb_pack & 0xff00) >> 8;\n\n                pu2_topleft_uv = (UWORD16 *)pu1_u_top_left;\n                pu2_left_uv = (UWORD16 *)pu1_uleft;\n\n                /* Get neighbour pixels */\n                /* left pels */\n                if(u2_use_left_mb_pack)\n                {\n                    WORD32 i;\n                    if(use_left1)\n                    {\n                        for(i = 0; i < 4; i++)\n                            au2_ngbr_pels[8 - 1 - i] = pu2_left_uv[i\n                                            * u4_recwidth_cr / YUV420SP_FACTOR];\n                    }\n                    else\n                    {\n                        memset(au2_ngbr_pels + 4, 0, 4 * sizeof(UWORD16));\n                    }\n\n                    if(use_left2)\n                    {\n                        for(i = 4; i < 8; i++)\n                            au2_ngbr_pels[8 - 1 - i] = pu2_left_uv[i\n                                            * u4_recwidth_cr / YUV420SP_FACTOR];\n                    }\n                    else\n                    {\n                        memset(au2_ngbr_pels, 0, 4 * sizeof(UWORD16));\n                    }\n\n                }\n                else\n                {\n                    memset(au2_ngbr_pels, 0, 8 * sizeof(UWORD16));\n                }\n\n                /* top left pels */\n                au2_ngbr_pels[8] = *pu2_topleft_uv;\n\n                /* top pels */\n                if(uc_useTopMB)\n                {\n                    memcpy(au2_ngbr_pels + 8 + 1, pu1_top_u,\n                           8 * sizeof(UWORD16));\n                }\n                else\n                {\n                    memset(au2_ngbr_pels + 8 + 1, 0, 8 * sizeof(UWORD16));\n                }\n\n                PROFILE_DISABLE_INTRA_PRED()\n                ps_dec->apf_intra_pred_chroma[u1_intra_chrom_pred_mode](\n                                pu1_ngbr_pels,\n                                pu1_mb_cb_rei1_buffer,\n                                1,\n                                u4_recwidth_cr,\n                                ((uc_useTopMB << 2) | (use_left2 << 4)\n                                                | use_left1));\n            }\n\n        }\n\n    }\n    return OK;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_process_intra_mb.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*!\n **************************************************************************\n * \\file ih264d_process_intra_mb.h\n *\n * \\brief\n *    Contains routines that decode a I slice type\n *\n * Detailed_description\n *\n * \\date\n *    07/07/2003\n *\n * \\author  NS\n **************************************************************************\n */\n#ifndef _IH264D_PROCESS_INTRA_MB_H_\n#define _IH264D_PROCESS_INTRA_MB_H_\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\n\n#define CHROMA_TO_LUMA_INTRA_MODE(x)   (x ^ ( (!(x & 0x01)) << 1))\n#define MB_TYPE_TO_INTRA_16x16_MODE(x) ((x - 1) & 0x03)\n\nUWORD32 ih264d_unpack_luma_coeff4x4_mb(dec_struct_t * ps_dec,\n                                    dec_mb_info_t * ps_cur_mb_info,\n                                    UWORD8 intra_flag);\nvoid ih264d_unpack_chroma_coeff4x4_mb(dec_struct_t * ps_dec,\n                                      dec_mb_info_t * ps_cur_mb_info);\nUWORD32 ih264d_unpack_luma_coeff8x8_mb(dec_struct_t * ps_dec,\n                                    dec_mb_info_t * ps_cur_mb_info);\n\nWORD32 ih264d_read_intra_pred_modes(dec_struct_t *ps_dec,\n                                    UWORD8 *pu1_prev_intra4x4_pred_mode_flag,\n                                    UWORD8 *pu1_rem_intra4x4_pred_mode,\n                                    UWORD32 u4_trans_form8x8);\n\nWORD32 ih264d_process_intra_mb(dec_struct_t * ps_dec,\n                               dec_mb_info_t * ps_cur_mb_info,\n                               UWORD8 u1_mb_num);\n\n#endif  /* _IH264D_PROCESS_INTRA_MB_H_ */\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_process_pslice.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n * \\file ih264d_process_pslice.c\n *\n * \\brief\n *    Contains routines that decode a I slice type\n *\n * Detailed_description\n *\n * \\date\n *    21/12/2002\n *\n * \\author  NS\n **************************************************************************\n */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n\n#include <string.h>\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_dpb_manager.h\"\n#include \"ih264d_mvpred.h\"\n#include \"ih264d_inter_pred.h\"\n#include \"ih264d_process_pslice.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_cabac.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_utils.h\"\n#include \"ih264d_parse_islice.h\"\n#include \"ih264d_process_bslice.h\"\n#include \"ih264d_process_intra_mb.h\"\n\nvoid ih264d_init_cabac_contexts(UWORD8 u1_slice_type, dec_struct_t * ps_dec);\n\nvoid ih264d_insert_pic_in_ref_pic_listx(struct pic_buffer_t *ps_ref_pic_buf_lx,\n                                        struct pic_buffer_t *ps_pic)\n{\n    *ps_ref_pic_buf_lx = *ps_pic;\n}\n\nWORD32 ih264d_mv_pred_ref_tfr_nby2_pmb(dec_struct_t * ps_dec,\n                                     UWORD8 u1_mb_idx,\n                                     UWORD8 u1_num_mbs)\n{\n    parse_pmbarams_t * ps_mb_part_info;\n    parse_part_params_t * ps_part;\n    mv_pred_t *ps_mv_nmb, *ps_mv_nmb_start, *ps_mv_ntop, *ps_mv_ntop_start;\n    UWORD32 i, j;\n    const UWORD32 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    dec_mb_info_t * ps_cur_mb_info;\n    WORD32 i2_mv_x, i2_mv_y;\n    WORD32 ret;\n\n    ps_dec->i4_submb_ofst -= (u1_num_mbs - u1_mb_idx) << 4;\n    ps_mb_part_info = ps_dec->ps_parse_mb_data; // + u1_mb_idx;\n    ps_part = ps_dec->ps_parse_part_params; // + u1_mb_idx;\n\n    /* N/2 Mb MvPred and Transfer Setup Loop */\n    for(i = u1_mb_idx; i < u1_num_mbs; i++, ps_mb_part_info++)\n    {\n        UWORD32 u1_colz;\n        UWORD32 u1_field;\n        mv_pred_t s_mvPred;\n        mv_pred_t *ps_mv_pred = &s_mvPred;\n\n\n\n        *ps_mv_pred = ps_dec->s_default_mv_pred;\n\n        ps_dec->i4_submb_ofst += SUB_BLK_SIZE;\n\n        /* Restore the slice scratch MbX and MbY context */\n        ps_cur_mb_info = ps_dec->ps_nmb_info + i;\n        u1_field = ps_cur_mb_info->u1_mb_field_decodingflag;\n\n\n\n        ps_mv_nmb_start = ps_dec->ps_mv_cur + (i << 4);\n        ps_dec->u2_mbx = ps_cur_mb_info->u2_mbx;\n        ps_dec->u2_mby = ps_cur_mb_info->u2_mby;\n        ps_dec->u2_mv_2mb[i & 0x1] = 0;\n\n        /* Look for MV Prediction and Reference Transfer in Non-I Mbs */\n        if(!ps_mb_part_info->u1_isI_mb)\n        {\n            UWORD32 u1_blk_no;\n            WORD32 i1_ref_idx, i1_ref_idx1;\n            UWORD32 u1_sub_mb_x, u1_sub_mb_y, u1_sub_mb_num;\n            UWORD32 u1_num_part, u1_num_ref, u1_wd, u1_ht;\n            UWORD32 *pu4_wt_offst, **ppu4_wt_ofst;\n            UWORD32 u1_scale_ref, u4_bot_mb;\n            WORD8 *pi1_ref_idx = ps_mb_part_info->i1_ref_idx[0];\n            pic_buffer_t *ps_ref_frame, **pps_ref_frame;\n            deblk_mb_t * ps_cur_deblk_mb = ps_dec->ps_deblk_mbn + i;\n\n            /* MB Level initialisations */\n            ps_dec->u4_num_pmbair = i >> u1_mbaff;\n            ps_dec->u1_mb_idx_mv = i;\n            ppu4_wt_ofst = ps_mb_part_info->pu4_wt_offst;\n            pps_ref_frame = ps_dec->ps_ref_pic_buf_lx[0];\n            /* CHANGED CODE */\n            ps_mv_ntop_start = ps_mv_nmb_start\n                            - (ps_dec->u2_frm_wd_in_mbs << (4 + u1_mbaff)) + 12;\n\n            u1_num_part = ps_mb_part_info->u1_num_part;\n            ps_cur_deblk_mb->u1_mb_type |= (u1_num_part > 1) << 1;\n            ps_cur_mb_info->u4_pred_info_pkd_idx = ps_dec->u4_pred_info_pkd_idx;\n            ps_cur_mb_info->u1_num_pred_parts = 0;\n\n\n            /****************************************************/\n            /* weighted u4_ofst pointer calculations, this loop  */\n            /* runs maximum 4 times, even in direct cases       */\n            /****************************************************/\n            u1_scale_ref = u1_mbaff & u1_field;\n\n            u4_bot_mb = 1 - ps_cur_mb_info->u1_topmb;\n            if(ps_dec->ps_cur_pps->u1_wted_pred_flag)\n            {\n                u1_num_ref = MIN(u1_num_part, 4);\n                for(u1_blk_no = 0; u1_blk_no < u1_num_ref; u1_blk_no++)\n                {\n                    i1_ref_idx = pi1_ref_idx[u1_blk_no];\n                    if(u1_scale_ref)\n                        i1_ref_idx >>= 1;\n                    pu4_wt_offst = (UWORD32*)&ps_dec->pu4_wt_ofsts[2\n                                    * X3(i1_ref_idx)];\n                    ppu4_wt_ofst[u1_blk_no] = pu4_wt_offst;\n                }\n            }\n            else\n            {\n                ppu4_wt_ofst[0] = NULL;\n                ppu4_wt_ofst[1] = NULL;\n                ppu4_wt_ofst[2] = NULL;\n                ppu4_wt_ofst[3] = NULL;\n            }\n\n            /**************************************************/\n            /* Loop on Partitions                             */\n            /**************************************************/\n            for(j = 0; j < u1_num_part; j++, ps_part++)\n            {\n\n                u1_sub_mb_num = ps_part->u1_sub_mb_num;\n                ps_dec->u1_sub_mb_num = u1_sub_mb_num;\n\n                if(PART_NOT_DIRECT != ps_part->u1_is_direct)\n                {\n                    /* Mb Skip Mode */\n                    /* Setting the default and other members of MvPred Structure */\n                    s_mvPred.i2_mv[2] = -1;\n                    s_mvPred.i2_mv[3] = -1;\n                    s_mvPred.i1_ref_frame[0] = 0;\n                    i1_ref_idx = (u1_scale_ref && u4_bot_mb) ? MAX_REF_BUFS : 0;\n                    ps_ref_frame = pps_ref_frame[i1_ref_idx];\n                    s_mvPred.u1_col_ref_pic_idx = ps_ref_frame->u1_mv_buf_id;\n                    s_mvPred.u1_pic_type = ps_ref_frame->u1_pic_type;\n                    pu4_wt_offst = (UWORD32*)&ps_dec->pu4_wt_ofsts[0];\n\n                    ps_dec->pf_mvpred(ps_dec, ps_cur_mb_info, ps_mv_nmb_start,\n                                      ps_mv_ntop_start, &s_mvPred, 0, 4, 0, 1,\n                                      MB_SKIP);\n\n\n\n\n\n\n                    {\n                        pred_info_pkd_t *ps_pred_pkd;\n                        ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n                    ih264d_fill_pred_info (s_mvPred.i2_mv,4,4,0,PRED_L0,ps_pred_pkd,ps_ref_frame->u1_pic_buf_id,\n                                           (i1_ref_idx >> u1_scale_ref),pu4_wt_offst,\n                                           ps_ref_frame->u1_pic_type);\n\n\n                    ps_dec->u4_pred_info_pkd_idx++;\n                    ps_cur_mb_info->u1_num_pred_parts++;\n                    }\n\n\n\n                    /* Storing colocated zero information */\n                    u1_colz = ((ABS(s_mvPred.i2_mv[0]) <= 1)\n                                    && (ABS(s_mvPred.i2_mv[1]) <= 1))\n                                    + (u1_field << 1);\n\n                    ih264d_rep_mv_colz(ps_dec, &s_mvPred, ps_mv_nmb_start, 0,\n                                       u1_colz, 4, 4);\n                }\n                else\n                {\n                    u1_sub_mb_x = u1_sub_mb_num & 0x03;\n                    u1_sub_mb_y = u1_sub_mb_num >> 2;\n                    u1_blk_no =\n                                    (u1_num_part < 4) ?\n                                                    j :\n                                                    (((u1_sub_mb_y >> 1) << 1)\n                                                                    + (u1_sub_mb_x\n                                                                                    >> 1));\n\n                    ps_mv_ntop = ps_mv_ntop_start + u1_sub_mb_x;\n                    ps_mv_nmb = ps_mv_nmb_start + u1_sub_mb_num;\n\n                    u1_wd = ps_part->u1_partwidth;\n                    u1_ht = ps_part->u1_partheight;\n\n                    /* Populate the colpic info and reference frames */\n                    i1_ref_idx = pi1_ref_idx[u1_blk_no];\n                    s_mvPred.i1_ref_frame[0] = i1_ref_idx;\n\n                    /********************************************************/\n                    /* Predict Mv                                           */\n                    /* Add Mv Residuals and store back                      */\n                    /********************************************************/\n                    ps_dec->pf_mvpred(ps_dec, ps_cur_mb_info, ps_mv_nmb, ps_mv_ntop,\n                                      &s_mvPred, u1_sub_mb_num, u1_wd, 0, 1,\n                                      ps_cur_mb_info->u1_mb_mc_mode);\n                    i2_mv_x = ps_mv_nmb->i2_mv[0];\n                    i2_mv_y = ps_mv_nmb->i2_mv[1];\n                    i2_mv_x += s_mvPred.i2_mv[0];\n                    i2_mv_y += s_mvPred.i2_mv[1];\n                    s_mvPred.i2_mv[0] = i2_mv_x;\n                    s_mvPred.i2_mv[1] = i2_mv_y;\n\n                    /********************************************************/\n                    /* Transfer setup call                                  */\n                    /* convert RefIdx if it is MbAff                        */\n                    /* Pass Weight Offset and refFrame                      */\n                    /********************************************************/\n                    i1_ref_idx1 = i1_ref_idx >> u1_scale_ref;\n                    if(u1_scale_ref && ((i1_ref_idx & 0x01) != u4_bot_mb))\n                        i1_ref_idx1 += MAX_REF_BUFS;\n                    ps_ref_frame = pps_ref_frame[i1_ref_idx1];\n                    pu4_wt_offst = ppu4_wt_ofst[u1_blk_no];\n\n\n\n\n\n\n                    {\n                    pred_info_pkd_t *ps_pred_pkd;\n                    ps_pred_pkd = ps_dec->ps_pred_pkd + ps_dec->u4_pred_info_pkd_idx;\n                    ih264d_fill_pred_info (s_mvPred.i2_mv,u1_wd,u1_ht,u1_sub_mb_num,PRED_L0,ps_pred_pkd,\n                                           ps_ref_frame->u1_pic_buf_id,(i1_ref_idx >> u1_scale_ref),pu4_wt_offst,\n                                           ps_ref_frame->u1_pic_type);\n\n                    ps_dec->u4_pred_info_pkd_idx++;\n                    ps_cur_mb_info->u1_num_pred_parts++;\n                    }\n\n\n\n                    /* Fill colocated info in MvPred structure */\n                    s_mvPred.u1_col_ref_pic_idx = ps_ref_frame->u1_mv_buf_id;\n                    s_mvPred.u1_pic_type = ps_ref_frame->u1_pic_type;\n\n                    /* Calculating colocated zero information */\n                    u1_colz =\n                                    (u1_field << 1)\n                                                    | ((i1_ref_idx == 0)\n                                                                    && (ABS(i2_mv_x)\n                                                                                    <= 1)\n                                                                    && (ABS(i2_mv_y)\n                                                                                    <= 1));\n                    u1_colz |= ps_mb_part_info->u1_col_info[u1_blk_no];\n\n                    /* Replicate the motion vectors and colzero u4_flag  */\n                    /* for all sub-partitions                         */\n\n                    ih264d_rep_mv_colz(ps_dec, &s_mvPred, ps_mv_nmb,\n                                       u1_sub_mb_num, u1_colz, u1_ht,\n                                       u1_wd);\n                }\n            }\n\n        }\n        else\n        {\n            /* Storing colocated zero information */\n            ih264d_rep_mv_colz(ps_dec, &s_mvPred, ps_mv_nmb_start, 0,\n                               (UWORD8)(u1_field << 1), 4, 4);\n\n        }\n        /*if num _cores is set to 3,compute bs will be done in another thread*/\n        if(ps_dec->u4_num_cores < 3)\n        {\n\n            if(ps_dec->u4_app_disable_deblk_frm == 0)\n                ps_dec->pf_compute_bs(ps_dec, ps_cur_mb_info,\n                                     (UWORD16)(i >> u1_mbaff));\n        }\n    }\n\n\n\n    return OK;\n}\n\n\nWORD32 ih264d_decode_recon_tfr_nmb(dec_struct_t * ps_dec,\n                                   UWORD8 u1_mb_idx,\n                                   UWORD8 u1_num_mbs,\n                                   UWORD8 u1_num_mbs_next,\n                                   UWORD8 u1_tfr_n_mb,\n                                   UWORD8 u1_end_of_row)\n{\n    WORD32 i,j;\n    UWORD32 u1_end_of_row_next;\n    dec_mb_info_t * ps_cur_mb_info;\n    UWORD32 u4_update_mbaff = 0;\n    WORD32 ret;\n    const UWORD32 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    const UWORD32 u1_slice_type = ps_dec->ps_cur_slice->u1_slice_type;\n    const WORD32 u1_skip_th = (\n                    (u1_slice_type != I_SLICE) ?\n                                    (ps_dec->u1_B ? B_8x8 : PRED_8x8R0) : -1);\n    const UWORD32 u1_ipcm_th = (\n                    (u1_slice_type != I_SLICE) ? (ps_dec->u1_B ? 23 : 5) : 0);\n\n\n\n\n\n    /* N Mb MC Loop */\n    for(i = u1_mb_idx; i < u1_num_mbs; i++)\n    {\n        ps_cur_mb_info = ps_dec->ps_nmb_info + i;\n        ps_dec->u4_dma_buf_idx = 0;\n        ps_dec->u4_pred_info_idx = 0;\n\n        if(ps_cur_mb_info->u1_mb_type <= u1_skip_th)\n        {\n            {\n                WORD32 pred_cnt = 0;\n                pred_info_pkd_t *ps_pred_pkd;\n                UWORD32 u4_pred_info_pkd_idx;\n                WORD8 i1_pred;\n\n                u4_pred_info_pkd_idx = ps_cur_mb_info->u4_pred_info_pkd_idx;\n\n                while(pred_cnt < ps_cur_mb_info->u1_num_pred_parts)\n                {\n\n                    ps_pred_pkd = ps_dec->ps_pred_pkd + u4_pred_info_pkd_idx;\n\n                     ps_dec->p_form_mb_part_info(ps_pred_pkd,ps_dec,\n                                               ps_cur_mb_info->u2_mbx,ps_cur_mb_info->u2_mby,(i >> u1_mbaff),\n                                         ps_cur_mb_info);\n                    u4_pred_info_pkd_idx++;\n                    pred_cnt++;\n                }\n            }\n\n            ps_dec->p_motion_compensate(ps_dec, ps_cur_mb_info);\n\n        }\n        else if(ps_cur_mb_info->u1_mb_type == MB_SKIP)\n        {\n            {\n                WORD32 pred_cnt = 0;\n                pred_info_pkd_t *ps_pred_pkd;\n                UWORD32 u4_pred_info_pkd_idx;\n                WORD8 i1_pred;\n\n                u4_pred_info_pkd_idx = ps_cur_mb_info->u4_pred_info_pkd_idx;\n\n                while(pred_cnt < ps_cur_mb_info->u1_num_pred_parts)\n                {\n\n                    ps_pred_pkd = ps_dec->ps_pred_pkd + u4_pred_info_pkd_idx;\n\n                    ps_dec->p_form_mb_part_info(ps_pred_pkd,ps_dec,\n                                               ps_cur_mb_info->u2_mbx,ps_cur_mb_info->u2_mby,(i >> u1_mbaff),\n                                         ps_cur_mb_info);\n\n                    u4_pred_info_pkd_idx++;\n                    pred_cnt++;\n                }\n            }\n            /* Decode MB skip */\n            ps_dec->p_motion_compensate(ps_dec, ps_cur_mb_info);\n\n        }\n\n     }\n\n\n    /* N Mb IQ IT RECON  Loop */\n    for(j = u1_mb_idx; j < i; j++)\n    {\n        ps_cur_mb_info = ps_dec->ps_nmb_info + j;\n\n        if(ps_cur_mb_info->u1_mb_type <= u1_skip_th)\n        {\n            ih264d_process_inter_mb(ps_dec, ps_cur_mb_info, j);\n\n        }\n        else if(ps_cur_mb_info->u1_mb_type != MB_SKIP)\n        {\n            if((u1_ipcm_th + 25) != ps_cur_mb_info->u1_mb_type)\n            {\n                ps_cur_mb_info->u1_mb_type -= (u1_skip_th + 1);\n                ih264d_process_intra_mb(ps_dec, ps_cur_mb_info, j);\n            }\n        }\n\n\n        if(ps_dec->u4_use_intrapred_line_copy)\n        {\n            ih264d_copy_intra_pred_line(ps_dec, ps_cur_mb_info, j);\n        }\n\n    }\n\n    /*N MB deblocking*/\n    if(ps_dec->u4_nmb_deblk == 1)\n    {\n\n        UWORD32 u4_cur_mb, u4_right_mb;\n        UWORD32 u4_mb_x, u4_mb_y;\n        UWORD32 u4_wd_y, u4_wd_uv;\n        tfr_ctxt_t *ps_tfr_cxt = &(ps_dec->s_tran_addrecon);\n        UWORD8 u1_field_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag;\n        const WORD32 i4_cb_qp_idx_ofst =\n                       ps_dec->ps_cur_pps->i1_chroma_qp_index_offset;\n        const WORD32 i4_cr_qp_idx_ofst =\n                       ps_dec->ps_cur_pps->i1_second_chroma_qp_index_offset;\n\n        u4_wd_y = ps_dec->u2_frm_wd_y << u1_field_pic_flag;\n        u4_wd_uv = ps_dec->u2_frm_wd_uv << u1_field_pic_flag;\n\n\n        ps_cur_mb_info = ps_dec->ps_nmb_info + u1_mb_idx;\n\n        ps_dec->u4_deblk_mb_x = ps_cur_mb_info->u2_mbx;\n        ps_dec->u4_deblk_mb_y = ps_cur_mb_info->u2_mby;\n\n        for(j = u1_mb_idx; j < i; j++)\n        {\n\n            ih264d_deblock_mb_nonmbaff(ps_dec, ps_tfr_cxt,\n                                       i4_cb_qp_idx_ofst, i4_cr_qp_idx_ofst,\n                                        u4_wd_y, u4_wd_uv);\n\n\n        }\n\n\n\n    }\n\n\n\n    if(u1_tfr_n_mb)\n    {\n        /****************************************************************/\n        /* Check for End Of Row in Next iteration                       */\n        /****************************************************************/\n        u1_end_of_row_next =\n                        u1_num_mbs_next\n                                        && (u1_num_mbs_next\n                                                        <= (ps_dec->u1_recon_mb_grp\n                                                                        >> u1_mbaff));\n\n        /****************************************************************/\n        /* Transfer the Following things                                */\n        /* N-Mb DeblkParams Data    ( To Ext DeblkParams Buffer )       */\n        /* N-Mb Recon Data          ( To Ext Frame Buffer )             */\n        /* N-Mb Intrapredline Data  ( Updated Internally)               */\n        /* N-Mb MV Data             ( To Ext MV Buffer )                */\n        /* N-Mb MVTop/TopRight Data ( To Int MV Top Scratch Buffers)    */\n        /****************************************************************/\n        ih264d_transfer_mb_group_data(ps_dec, u1_num_mbs, u1_end_of_row,\n                                      u1_end_of_row_next);\n        ps_dec->u4_num_mbs_prev_nmb = u1_num_mbs;\n\n        ps_dec->u4_pred_info_idx = 0;\n        ps_dec->u4_dma_buf_idx = 0;\n\n\n    }\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_process_inter_mb \\endif\n *\n * \\brief\n *    This function decodes an Inter MB.\n *\n *\n * \\return\n *    0 on Success and Error code otherwise\n **************************************************************************\n */\nWORD32 ih264d_process_inter_mb(dec_struct_t * ps_dec,\n                               dec_mb_info_t * ps_cur_mb_info,\n                               UWORD8 u1_mb_num)\n{\n    /* CHANGED CODE */\n    UWORD8 *pu1_rec_y, *pu1_rec_u, *pu1_rec_v;\n\n    /*CHANGED CODE */\n    UWORD32 ui_rec_width, u4_recwidth_cr;\n    WORD16 *pi2_y_coeff;\n    UWORD32 u1_mb_field_decoding_flag;\n    const UWORD8 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    UWORD32 uc_botMb;\n    UWORD32 u4_num_pmbair;\n    /* CHANGED CODE */\n    tfr_ctxt_t *ps_frame_buf = ps_dec->ps_frame_buf_ip_recon;\n    UWORD32 u4_luma_dc_only_csbp = 0;\n    UWORD32 u4_luma_dc_only_cbp = 0;\n    /* CHANGED CODE */\n\n    uc_botMb = 1 - ps_cur_mb_info->u1_topmb;\n    u4_num_pmbair = (u1_mb_num >> u1_mbaff);\n    u1_mb_field_decoding_flag = ps_cur_mb_info->u1_mb_field_decodingflag;\n\n\n    /* CHANGED CODE */\n    pu1_rec_y = ps_frame_buf->pu1_dest_y + (u4_num_pmbair << 4);\n    pu1_rec_u =\n                    ps_frame_buf->pu1_dest_u\n                                    + (u4_num_pmbair << 3) * YUV420SP_FACTOR;\n    pu1_rec_v = ps_frame_buf->pu1_dest_v + (u4_num_pmbair << 3);\n    ui_rec_width = ps_dec->u2_frm_wd_y << u1_mb_field_decoding_flag;\n    u4_recwidth_cr = ps_dec->u2_frm_wd_uv << u1_mb_field_decoding_flag;\n\n    /* CHANGED CODE */\n\n    if(u1_mbaff)\n    {\n        if(uc_botMb)\n        {\n            pu1_rec_y += (u1_mb_field_decoding_flag ?\n                            (ui_rec_width >> 1) : (ui_rec_width << 4));\n            pu1_rec_u += (u1_mb_field_decoding_flag ?\n                            (u4_recwidth_cr >> 1) : (u4_recwidth_cr << 3));\n            pu1_rec_v += (u1_mb_field_decoding_flag ?\n                            (u4_recwidth_cr >> 1) : (u4_recwidth_cr << 3));\n        }\n    }\n\n    if(!ps_cur_mb_info->u1_tran_form8x8)\n    {\n        u4_luma_dc_only_csbp = ih264d_unpack_luma_coeff4x4_mb(ps_dec,\n                                       ps_cur_mb_info,\n                                       0);\n    }\n    else\n    {\n        if(!ps_dec->ps_cur_pps->u1_entropy_coding_mode)\n        {\n            u4_luma_dc_only_cbp = ih264d_unpack_luma_coeff4x4_mb(ps_dec,\n                                           ps_cur_mb_info,\n                                           0);\n        }\n        else\n        {\n            u4_luma_dc_only_cbp = ih264d_unpack_luma_coeff8x8_mb(ps_dec,\n                                           ps_cur_mb_info);\n        }\n    }\n\n    pi2_y_coeff = ps_dec->pi2_coeff_data;\n    /* Inverse Transform and Reconstruction */\n    if(ps_cur_mb_info->u1_cbp & 0x0f)\n    {\n        /* CHANGED CODE */\n        if(!ps_cur_mb_info->u1_tran_form8x8)\n        {\n            UWORD32 i;\n            WORD16 ai2_tmp[16];\n            for(i = 0; i < 16; i++)\n            {\n                if(CHECKBIT(ps_cur_mb_info->u2_luma_csbp, i))\n                {\n                    WORD16 *pi2_level = pi2_y_coeff + (i << 4);\n                    UWORD8 *pu1_pred_sblk = pu1_rec_y + ((i & 0x3) * BLK_SIZE)\n                                    + (i >> 2) * (ui_rec_width << 2);\n                    PROFILE_DISABLE_IQ_IT_RECON()\n                    {\n                        if(CHECKBIT(u4_luma_dc_only_csbp, i))\n                        {\n                            ps_dec->pf_iquant_itrans_recon_luma_4x4_dc(\n                                            pi2_level,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            ui_rec_width,\n                                            ui_rec_width,\n                                            gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qp_rem6],\n                                            (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[3],\n                                            ps_cur_mb_info->u1_qp_div6, ai2_tmp, 0,\n                                            NULL);\n                        }\n                        else\n                        {\n                            ps_dec->pf_iquant_itrans_recon_luma_4x4(\n                                            pi2_level,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            ui_rec_width,\n                                            ui_rec_width,\n                                            gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qp_rem6],\n                                            (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[3],\n                                            ps_cur_mb_info->u1_qp_div6, ai2_tmp, 0,\n                                            NULL);\n                        }\n                    }\n                }\n            }\n        }\n        else\n        {\n            WORD16 *pi2_scale_matrix_ptr;\n            WORD32 i;\n\n            pi2_scale_matrix_ptr =\n                            ps_dec->s_high_profile.i2_scalinglist8x8[1];\n\n            for(i = 0; i < 4; i++)\n            {\n                WORD16 ai2_tmp[64];\n                WORD16 *pi16_levelBlock = pi2_y_coeff + (i << 6); /* move to the next 8x8 adding 64 */\n\n                UWORD8 *pu1_pred_sblk = pu1_rec_y + ((i & 0x1) * BLK8x8SIZE)\n                                + (i >> 1) * (ui_rec_width << 3);\n                if(CHECKBIT(ps_cur_mb_info->u1_cbp, i))\n                {\n                    PROFILE_DISABLE_IQ_IT_RECON()\n                    {\n                        if(CHECKBIT(u4_luma_dc_only_cbp, i))\n                        {\n                            ps_dec->pf_iquant_itrans_recon_luma_8x8_dc(\n                                            pi16_levelBlock,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            ui_rec_width,\n                                            ui_rec_width,\n                                            gau1_ih264d_dequant8x8_cavlc[ps_cur_mb_info->u1_qp_rem6],\n                                            (UWORD16 *)pi2_scale_matrix_ptr,\n                                            ps_cur_mb_info->u1_qp_div6, ai2_tmp, 0,\n                                            NULL);\n                        }\n                        else\n                        {\n                            ps_dec->pf_iquant_itrans_recon_luma_8x8(\n                                            pi16_levelBlock,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            ui_rec_width,\n                                            ui_rec_width,\n                                            gau1_ih264d_dequant8x8_cavlc[ps_cur_mb_info->u1_qp_rem6],\n                                            (UWORD16 *)pi2_scale_matrix_ptr,\n                                            ps_cur_mb_info->u1_qp_div6, ai2_tmp, 0,\n                                            NULL);\n                        }\n                    }\n                }\n            }\n\n        }\n    }\n\n    /* Decode Chroma Block */\n    ih264d_unpack_chroma_coeff4x4_mb(ps_dec,\n                                     ps_cur_mb_info);\n    /*--------------------------------------------------------------------*/\n    /* Chroma Blocks decoding                                             */\n    /*--------------------------------------------------------------------*/\n    {\n        UWORD8 u1_chroma_cbp = (UWORD8)(ps_cur_mb_info->u1_cbp >> 4);\n\n        if(u1_chroma_cbp != CBPC_ALLZERO)\n        {\n            UWORD32 u4_scale_u = ps_cur_mb_info->u1_qpc_div6;\n            UWORD32 u4_scale_v = ps_cur_mb_info->u1_qpcr_div6;\n            UWORD16 u2_chroma_csbp = ps_cur_mb_info->u2_chroma_csbp;\n\n            pi2_y_coeff = ps_dec->pi2_coeff_data;\n\n            {\n                UWORD32 i;\n                WORD16 ai2_tmp[16];\n                for(i = 0; i < 4; i++)\n                {\n                    WORD16 *pi2_level = pi2_y_coeff + (i << 4);\n                    UWORD8 *pu1_pred_sblk = pu1_rec_u\n                                    + ((i & 0x1) * BLK_SIZE * YUV420SP_FACTOR)\n                                    + (i >> 1) * (u4_recwidth_cr << 2);\n                    PROFILE_DISABLE_IQ_IT_RECON()\n                    {\n                        if(CHECKBIT(u2_chroma_csbp, i))\n                        {\n                            ps_dec->pf_iquant_itrans_recon_chroma_4x4(\n                                            pi2_level,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            u4_recwidth_cr,\n                                            u4_recwidth_cr,\n                                            gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qpc_rem6],\n                                            (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[4],\n                                            u4_scale_u, ai2_tmp, pi2_level);\n                        }\n                        else if(pi2_level[0] != 0)\n                        {\n                            ps_dec->pf_iquant_itrans_recon_chroma_4x4_dc(\n                                            pi2_level,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            u4_recwidth_cr,\n                                            u4_recwidth_cr,\n                                            gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qpc_rem6],\n                                            (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[4],\n                                            u4_scale_u, ai2_tmp, pi2_level);\n                        }\n                    }\n                }\n            }\n\n            pi2_y_coeff += MB_CHROM_SIZE;\n            u2_chroma_csbp >>= 4;\n\n            {\n                UWORD32 i;\n                WORD16 ai2_tmp[16];\n                for(i = 0; i < 4; i++)\n                {\n                    WORD16 *pi2_level = pi2_y_coeff + (i << 4);\n                    UWORD8 *pu1_pred_sblk = pu1_rec_u + 1\n                                    + ((i & 0x1) * BLK_SIZE * YUV420SP_FACTOR)\n                                    + (i >> 1) * (u4_recwidth_cr << 2);\n                    PROFILE_DISABLE_IQ_IT_RECON()\n                    {\n                        if(CHECKBIT(u2_chroma_csbp, i))\n                        {\n                            ps_dec->pf_iquant_itrans_recon_chroma_4x4(\n                                            pi2_level,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            u4_recwidth_cr,\n                                            u4_recwidth_cr,\n                                            gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qpcr_rem6],\n                                            (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[5],\n                                            u4_scale_v, ai2_tmp, pi2_level);\n                        }\n                        else if(pi2_level[0] != 0)\n                        {\n                            ps_dec->pf_iquant_itrans_recon_chroma_4x4_dc(\n                                            pi2_level,\n                                            pu1_pred_sblk,\n                                            pu1_pred_sblk,\n                                            u4_recwidth_cr,\n                                            u4_recwidth_cr,\n                                            gau2_ih264_iquant_scale_4x4[ps_cur_mb_info->u1_qpcr_rem6],\n                                            (UWORD16 *)ps_dec->s_high_profile.i2_scalinglist4x4[5],\n                                            u4_scale_v, ai2_tmp, pi2_level);\n                        }\n                    }\n                }\n            }\n        }\n    }\n    return (0);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_parse_pred_weight_table \\endif\n *\n * \\brief\n *    Implements pred_weight_table() of 7.3.3.2.\n *\n * \\return\n *    None\n *\n **************************************************************************\n */\nWORD32 ih264d_parse_pred_weight_table(dec_slice_params_t * ps_cur_slice,\n                                      dec_bit_stream_t * ps_bitstrm)\n{\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    WORD8 i, cont, lx;\n    UWORD8 uc_weight_flag;\n    UWORD32 *pui32_weight_offset_lx;\n    WORD16 c_weight, c_offset;\n    UWORD32 ui32_y_def_weight_ofst, ui32_cr_def_weight_ofst;\n    UWORD32 ui32_temp;\n    UWORD8 uc_luma_log2_weight_denom;\n    UWORD8 uc_chroma_log2_weight_denom;\n\n    /* Variables for error resilience checks */\n    UWORD32 u4_temp;\n    WORD32 i_temp;\n\n    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if(u4_temp > MAX_LOG2_WEIGHT_DENOM)\n    {\n        return ERROR_PRED_WEIGHT_TABLE_T;\n    }\n    uc_luma_log2_weight_denom = u4_temp;\n    COPYTHECONTEXT(\"SH: luma_log2_weight_denom\",uc_luma_log2_weight_denom);\n    ui32_y_def_weight_ofst = (1 << uc_luma_log2_weight_denom);\n\n    u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if(u4_temp > MAX_LOG2_WEIGHT_DENOM)\n    {\n        return ERROR_PRED_WEIGHT_TABLE_T;\n    }\n    uc_chroma_log2_weight_denom = u4_temp;\n    COPYTHECONTEXT(\"SH: chroma_log2_weight_denom\",uc_chroma_log2_weight_denom);\n    ui32_cr_def_weight_ofst = (1 << uc_chroma_log2_weight_denom);\n\n    ps_cur_slice->u2_log2Y_crwd = uc_luma_log2_weight_denom\n                    | (uc_chroma_log2_weight_denom << 8);\n\n    cont = (ps_cur_slice->u1_slice_type == B_SLICE);\n    lx = 0;\n    do\n    {\n        for(i = 0; i < ps_cur_slice->u1_num_ref_idx_lx_active[lx]; i++)\n        {\n            pui32_weight_offset_lx = ps_cur_slice->u4_wt_ofst_lx[lx][i];\n\n            uc_weight_flag = ih264d_get_bit_h264(ps_bitstrm);\n            pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n            COPYTHECONTEXT(\"SH: luma_weight_l0_flag\",uc_weight_flag);\n            if(uc_weight_flag)\n            {\n                i_temp = ih264d_sev(pu4_bitstrm_ofst,\n                                    pu4_bitstrm_buf);\n                if((i_temp < PRED_WEIGHT_MIN) || (i_temp > PRED_WEIGHT_MAX))\n                    return ERROR_PRED_WEIGHT_TABLE_T;\n                c_weight = i_temp;\n                COPYTHECONTEXT(\"SH: luma_weight_l0\",c_weight);\n\n                i_temp = ih264d_sev(pu4_bitstrm_ofst,\n                                    pu4_bitstrm_buf);\n                if((i_temp < PRED_WEIGHT_MIN) || (i_temp > PRED_WEIGHT_MAX))\n                    return ERROR_PRED_WEIGHT_TABLE_T;\n                c_offset = i_temp;\n                COPYTHECONTEXT(\"SH: luma_offset_l0\",c_offset);\n\n                ui32_temp = (c_offset << 16) | (c_weight & 0xFFFF);\n                pui32_weight_offset_lx[0] = ui32_temp;\n            }\n            else\n            {\n\n                pui32_weight_offset_lx[0] = ui32_y_def_weight_ofst;\n            }\n\n            {\n                WORD8 c_weightCb, c_weightCr, c_offsetCb, c_offsetCr;\n                uc_weight_flag = ih264d_get_bit_h264(ps_bitstrm);\n                pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n                COPYTHECONTEXT(\"SH: chroma_weight_l0_flag\",uc_weight_flag);\n                if(uc_weight_flag)\n                {\n                    i_temp = ih264d_sev(pu4_bitstrm_ofst,\n                                        pu4_bitstrm_buf);\n                    if((i_temp < PRED_WEIGHT_MIN) || (i_temp > PRED_WEIGHT_MAX))\n                        return ERROR_PRED_WEIGHT_TABLE_T;\n                    c_weightCb = i_temp;\n                    COPYTHECONTEXT(\"SH: chroma_weight_l0\",c_weightCb);\n\n                    i_temp = ih264d_sev(pu4_bitstrm_ofst,\n                                        pu4_bitstrm_buf);\n                    if((i_temp < PRED_WEIGHT_MIN) || (i_temp > PRED_WEIGHT_MAX))\n                        return ERROR_PRED_WEIGHT_TABLE_T;\n                    c_offsetCb = i_temp;\n                    COPYTHECONTEXT(\"SH: chroma_weight_l0\",c_offsetCb);\n\n                    ui32_temp = (c_offsetCb << 16) | (c_weightCb & 0xFFFF);\n                    pui32_weight_offset_lx[1] = ui32_temp;\n\n                    i_temp = ih264d_sev(pu4_bitstrm_ofst,\n                                        pu4_bitstrm_buf);\n                    if((i_temp < PRED_WEIGHT_MIN) || (i_temp > PRED_WEIGHT_MAX))\n                        return ERROR_PRED_WEIGHT_TABLE_T;\n                    c_weightCr = i_temp;\n                    COPYTHECONTEXT(\"SH: chroma_weight_l0\",c_weightCr);\n\n                    i_temp = ih264d_sev(pu4_bitstrm_ofst,\n                                        pu4_bitstrm_buf);\n                    if((i_temp < PRED_WEIGHT_MIN) || (i_temp > PRED_WEIGHT_MAX))\n                        return ERROR_PRED_WEIGHT_TABLE_T;\n                    c_offsetCr = i_temp;\n                    COPYTHECONTEXT(\"SH: chroma_weight_l0\",c_offsetCr);\n\n                    ui32_temp = (c_offsetCr << 16) | (c_weightCr & 0xFFFF);\n                    pui32_weight_offset_lx[2] = ui32_temp;\n                }\n                else\n                {\n                    pui32_weight_offset_lx[1] = ui32_cr_def_weight_ofst;\n                    pui32_weight_offset_lx[2] = ui32_cr_def_weight_ofst;\n                }\n            }\n        }\n        lx++;\n    }\n    while(cont--);\n\n    return OK;\n}\n\nstatic int pic_num_compare(const void *pv_pic1, const void *pv_pic2)\n{\n    struct pic_buffer_t *ps_pic1 = *(struct pic_buffer_t **) pv_pic1;\n    struct pic_buffer_t *ps_pic2 = *(struct pic_buffer_t **) pv_pic2;\n    if (ps_pic1->i4_pic_num < ps_pic2->i4_pic_num)\n    {\n        return -1;\n    }\n    else if (ps_pic1->i4_pic_num > ps_pic2->i4_pic_num)\n    {\n        return 1;\n    }\n    else\n    {\n        return 0;\n    }\n}\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_init_ref_idx_lx_p                                        */\n/*                                                                           */\n/*  Description   : This function initializes the reference picture L0 list  */\n/*                  for P slices as per section 8.2.4.2.1 and 8.2.4.2.2.     */\n/*                                                                           */\n/*  Inputs        : pointer to ps_dec struture                               */\n/*  Globals       : NO                                                       */\n/*  Processing    : arranges all the short term pictures according to        */\n/*                  pic_num in descending order starting from curr pic_num.  */\n/*                  and inserts it in L0 list followed by all Long term      */\n/*                  pictures in ascending order.                             */\n/*                                                                           */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : <List any issues or problems with this function>         */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 07 2002   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_init_ref_idx_lx_p(dec_struct_t *ps_dec)\n{\n    struct pic_buffer_t *ps_ref_pic_buf_lx;\n    dpb_manager_t *ps_dpb_mgr;\n    struct dpb_info_t *ps_next_dpb;\n    WORD8 i, j;\n    UWORD8 u1_max_lt_index, u1_min_lt_index;\n    UWORD32 u4_lt_index;\n    UWORD8 u1_field_pic_flag;\n    dec_slice_params_t *ps_cur_slice;\n    UWORD8 u1_L0;\n    WORD32 i4_cur_pic_num, i4_min_st_pic_num;\n    WORD32 i4_temp_pic_num, i4_ref_pic_num;\n    UWORD8 u1_num_short_term_bufs;\n    UWORD8 u1_max_ref_idx_l0;\n    struct pic_buffer_t *aps_st_pic_bufs[2 * MAX_REF_BUFS] = {NULL};\n\n    ps_cur_slice = ps_dec->ps_cur_slice;\n    u1_field_pic_flag = ps_cur_slice->u1_field_pic_flag;\n    u1_max_ref_idx_l0 = ps_cur_slice->u1_num_ref_idx_lx_active[0]\n                    << u1_field_pic_flag;\n\n    ps_dpb_mgr = ps_dec->ps_dpb_mgr;\n    /* Get the current frame number */\n    i4_cur_pic_num = ps_dec->ps_cur_pic->i4_pic_num;\n\n    /* Get Min pic_num,MinLt */\n    i4_min_st_pic_num = i4_cur_pic_num;\n    u1_max_lt_index = MAX_REF_BUFS + 1;\n    u1_min_lt_index = MAX_REF_BUFS + 1;\n\n    /* Start from ST head */\n    ps_next_dpb = ps_dpb_mgr->ps_dpb_st_head;\n    for(i = 0; i < ps_dpb_mgr->u1_num_st_ref_bufs; i++)\n    {\n        i4_ref_pic_num = ps_next_dpb->ps_pic_buf->i4_pic_num;\n        if(i4_ref_pic_num < i4_cur_pic_num)\n        {\n            /* RefPic Buf pic_num is before Current pic_num in decode order */\n            i4_min_st_pic_num = MIN(i4_min_st_pic_num, i4_ref_pic_num);\n        }\n\n        /* Chase the next link */\n        ps_next_dpb = ps_next_dpb->ps_prev_short;\n    }\n\n    /* Sort ST ref pocs in ascending order */\n    ps_next_dpb = ps_dpb_mgr->ps_dpb_st_head;\n    for (j = 0; j < ps_dpb_mgr->u1_num_st_ref_bufs; j++)\n    {\n        aps_st_pic_bufs[j] = ps_next_dpb->ps_pic_buf;\n        ps_next_dpb = ps_next_dpb->ps_prev_short;\n    }\n    qsort(aps_st_pic_bufs, ps_dpb_mgr->u1_num_st_ref_bufs,\n        sizeof(aps_st_pic_bufs[0]), pic_num_compare);\n\n    /* Start from LT head */\n    ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;\n    if(ps_next_dpb)\n    {\n        u1_max_lt_index = ps_next_dpb->u1_lt_idx;\n        u1_min_lt_index = ps_next_dpb->u1_lt_idx;\n\n        for(i = 0; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)\n        {\n            u4_lt_index = ps_next_dpb->u1_lt_idx;\n            u1_max_lt_index = (UWORD8)(MAX(u1_max_lt_index, u4_lt_index));\n            u1_min_lt_index = (UWORD8)(MIN(u1_min_lt_index, u4_lt_index));\n\n            /* Chase the next link */\n            ps_next_dpb = ps_next_dpb->ps_prev_long;\n        }\n    }\n    /* 1. Initialize refIdxL0 */\n    u1_L0 = 0;\n    if(u1_field_pic_flag)\n    {\n        ps_ref_pic_buf_lx = ps_dpb_mgr->ps_init_dpb[0][0];\n        ps_ref_pic_buf_lx += MAX_REF_BUFS;\n        i4_temp_pic_num = i4_cur_pic_num;\n    }\n    else\n    {\n        ps_ref_pic_buf_lx = ps_dpb_mgr->ps_init_dpb[0][0];\n        i4_temp_pic_num = i4_cur_pic_num;\n    }\n    /* Arrange all short term buffers in output order as given by pic_num */\n    /* Arrange pic_num's less than Curr pic_num in the descending pic_num */\n    /* order starting from (Curr pic_num - 1)                             */\n    for(j = ps_dpb_mgr->u1_num_st_ref_bufs - 1; j >= 0; j--)\n    {\n        if(aps_st_pic_bufs[j])\n        {\n            /* Copy info in pic buffer */\n            ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,\n                                               aps_st_pic_bufs[j]);\n            ps_ref_pic_buf_lx++;\n            u1_L0++;\n        }\n    }\n\n    /* Arrange all Long term buffers in ascending order, in LongtermIndex */\n    /* Start from LT head */\n    u1_num_short_term_bufs = u1_L0;\n    for(u4_lt_index = u1_min_lt_index; u4_lt_index <= u1_max_lt_index;\n                    u4_lt_index++)\n    {\n        ps_next_dpb = ps_dpb_mgr->ps_dpb_ht_head;\n        for(i = 0; i < ps_dpb_mgr->u1_num_lt_ref_bufs; i++)\n        {\n            if(ps_next_dpb->u1_lt_idx == u4_lt_index)\n            {\n                ih264d_insert_pic_in_ref_pic_listx(ps_ref_pic_buf_lx,\n                                                   ps_next_dpb->ps_pic_buf);\n\n                ps_ref_pic_buf_lx->u1_long_term_pic_num =\n                                ps_ref_pic_buf_lx->u1_long_term_frm_idx;\n                ps_ref_pic_buf_lx++;\n                u1_L0++;\n                break;\n            }\n            ps_next_dpb = ps_next_dpb->ps_prev_long;\n        }\n    }\n\n    if(u1_field_pic_flag)\n    {\n        /* Initialize the rest of the entries in the */\n        /* reference list to handle of errors        */\n        {\n            UWORD8 u1_i;\n            pic_buffer_t ref_pic;\n\n            ref_pic = *(ps_dpb_mgr->ps_init_dpb[0][0] + MAX_REF_BUFS);\n\n            if(NULL == ref_pic.pu1_buf1)\n            {\n                ref_pic = *ps_dec->ps_cur_pic;\n            }\n            for(u1_i = u1_L0; u1_i < u1_max_ref_idx_l0; u1_i++)\n            {\n                *ps_ref_pic_buf_lx = ref_pic;\n                ps_ref_pic_buf_lx++;\n            }\n        }\n\n        ih264d_convert_frm_to_fld_list(\n                        ps_dpb_mgr->ps_init_dpb[0][0] + MAX_REF_BUFS, &u1_L0,\n                        ps_dec, u1_num_short_term_bufs);\n\n        ps_ref_pic_buf_lx = ps_dpb_mgr->ps_init_dpb[0][0] + u1_L0;\n    }\n\n    /* Initialize the rest of the entries in the */\n    /* reference list to handle of errors        */\n    {\n        UWORD8 u1_i;\n        pic_buffer_t ref_pic;\n\n        ref_pic = *(ps_dpb_mgr->ps_init_dpb[0][0]);\n\n        if(NULL == ref_pic.pu1_buf1)\n        {\n            ref_pic = *ps_dec->ps_cur_pic;\n        }\n        for(u1_i = u1_L0; u1_i < u1_max_ref_idx_l0; u1_i++)\n        {\n            *ps_ref_pic_buf_lx = ref_pic;\n            ps_ref_pic_buf_lx++;\n        }\n    }\n    ps_dec->ps_cur_slice->u1_initial_list_size[0] = u1_L0;\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_process_pslice.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_PROCESS_PSLICE_H_\n#define _IH264D_PROCESS_PSLICE_H_\n/*!\n**************************************************************************\n* \\file ih264d_process_pslice.h\n*\n* \\brief\n*    Contains declarations of routines that decode a P slice type\n*\n* Detailed_description\n*\n* \\date\n*    21/12/2002\n*\n* \\author  NS\n**************************************************************************\n*/\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\nWORD32 ih264d_parse_pslice(dec_struct_t *ps_dec,\n                            UWORD16 u2_first_mb_in_slice);\nWORD32 ih264d_parse_pred_weight_table(dec_slice_params_t * ps_cur_slice,\n                                    dec_bit_stream_t * ps_bitstrm);\n\nWORD32 parsePSliceData(dec_struct_t * ps_dec,\n                       dec_slice_params_t * ps_slice,\n                       UWORD16 u2_first_mb_in_slice);\n\nWORD32 ih264d_process_inter_mb(dec_struct_t * ps_dec,\n                               dec_mb_info_t * ps_cur_mb_info,\n                               UWORD8 u1_mb_num);\n\nvoid ih264d_init_ref_idx_lx_p(dec_struct_t *ps_dec);\n\nWORD32 ih264d_mv_pred_ref_tfr_nby2_pmb(dec_struct_t * ps_dec,\n                                     UWORD8 u1_num_mbs,\n                                     UWORD8 u1_num_mbsNby2);\n\nWORD32 ih264d_decode_recon_tfr_nmb(dec_struct_t * ps_dec,\n                                 UWORD8 u1_mb_idx,\n                                 UWORD8 u1_num_mbs,\n                                 UWORD8 u1_num_mbs_next,\n                                 UWORD8 u1_tfr_n_mb,\n                                 UWORD8 u1_end_of_row);\n\nvoid ih264d_insert_pic_in_ref_pic_listx(struct pic_buffer_t *ps_ref_pic_buf_lx,\n                                        struct pic_buffer_t *ps_pic);\n#endif /* _IH264D_PROCESS_PSLICE_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_quant_scaling.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264_defs.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_defs.h\"\n\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_utils.h\"\n#include \"ih264d_nal.h\"\n#include \"ih264d_deblocking.h\"\n\n#include \"ih264d_mem_request.h\"\n#include \"ih264d_debug.h\"\n\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_sei.h\"\n#include \"ih264d_vui.h\"\n#include \"ih264d_tables.h\"\n\n#define IDCT_BLOCK_WIDTH8X8  8\n\nWORD32 ih264d_scaling_list(WORD16 *pi2_scaling_list,\n                         WORD32 i4_size_of_scalinglist,\n                         UWORD8 *pu1_use_default_scaling_matrix_flag,\n                         dec_bit_stream_t *ps_bitstrm)\n{\n    WORD32 i4_j, i4_delta_scale, i4_lastScale = 8, i4_nextScale = 8;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n\n    *pu1_use_default_scaling_matrix_flag = 0;\n\n    for(i4_j = 0; i4_j < i4_size_of_scalinglist; i4_j++)\n    {\n        if(i4_nextScale != 0)\n        {\n            i4_delta_scale = ih264d_sev(pu4_bitstrm_ofst,\n                                        pu4_bitstrm_buf);\n\n            if(i4_delta_scale < MIN_H264_DELTA_SCALE ||\n                        i4_delta_scale > MAX_H264_DELTA_SCALE)\n            {\n                return ERROR_INV_RANGE_QP_T;\n            }\n            i4_nextScale = ((i4_lastScale + i4_delta_scale + 256) & 0xff);\n\n            *pu1_use_default_scaling_matrix_flag = ((i4_j == 0)\n                            && (i4_nextScale == 0));\n\n        }\n        pi2_scaling_list[i4_j] =\n                        (i4_nextScale == 0) ? (i4_lastScale) : (i4_nextScale);\n        i4_lastScale = pi2_scaling_list[i4_j];\n    }\n    return OK;\n}\n\nWORD32 ih264d_form_default_scaling_matrix(dec_struct_t *ps_dec)\n{\n\n    /*************************************************************************/\n    /* perform the inverse scanning for the frame and field scaling matrices */\n    /*************************************************************************/\n    {\n        UWORD8 *pu1_inv_scan;\n        WORD32 i4_i, i4_j;\n\n        pu1_inv_scan = (UWORD8 *)gau1_ih264d_inv_scan;\n\n        /* for all 4x4 matrices */\n        for(i4_i = 0; i4_i < 6; i4_i++)\n        {\n            for(i4_j = 0; i4_j < 16; i4_j++)\n            {\n                ps_dec->s_high_profile.i2_scalinglist4x4[i4_i][pu1_inv_scan[i4_j]] =\n                                16;\n\n            }\n        }\n\n        /* for all 8x8 matrices */\n        for(i4_i = 0; i4_i < 2; i4_i++)\n        {\n            for(i4_j = 0; i4_j < 64; i4_j++)\n            {\n                ps_dec->s_high_profile.i2_scalinglist8x8[i4_i][gau1_ih264d_inv_scan_prog8x8_cabac[i4_j]] =\n                                16;\n\n            }\n        }\n    }\n    return OK;\n}\n\nWORD32 ih264d_form_scaling_matrix_picture(dec_seq_params_t *ps_seq,\n                                          dec_pic_params_t *ps_pic,\n                                          dec_struct_t *ps_dec)\n{\n    /* default scaling matrices */\n    WORD32 i4_i;\n\n    /* check the SPS first */\n    if(ps_seq->i4_seq_scaling_matrix_present_flag)\n    {\n        for(i4_i = 0; i4_i < 8; i4_i++)\n        {\n            if(i4_i < 6)\n            {\n                /* fall-back rule A */\n                if(!ps_seq->u1_seq_scaling_list_present_flag[i4_i])\n                {\n                    if((i4_i == 0) || (i4_i == 3))\n                    {\n                        ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                        (i4_i == 0) ? (WORD16 *)(gai2_ih264d_default_intra4x4) : (WORD16 *)(gai2_ih264d_default_inter4x4);\n                    }\n                    else\n                    {\n                        ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                        ps_dec->s_high_profile.pi2_scale_mat[i4_i\n                                                        - 1];\n                    }\n                }\n                else\n                {\n                    if(ps_seq->u1_use_default_scaling_matrix_flag[i4_i])\n                    {\n                        ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                        (i4_i < 3) ? (WORD16 *)(gai2_ih264d_default_intra4x4) : (WORD16 *)(gai2_ih264d_default_inter4x4);\n                    }\n                    else\n                    {\n                        ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                        ps_seq->i2_scalinglist4x4[i4_i];\n                    }\n                }\n\n            }\n            else\n            {\n                /* fall-back rule A */\n                if((!ps_seq->u1_seq_scaling_list_present_flag[i4_i])\n                                || (ps_seq->u1_use_default_scaling_matrix_flag[i4_i]))\n                {\n                    ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                    (i4_i == 6) ? ((WORD16*)gai2_ih264d_default_intra8x8) : ((WORD16*)gai2_ih264d_default_inter8x8);\n                }\n                else\n                {\n                    ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                    ps_seq->i2_scalinglist8x8[i4_i - 6];\n                }\n            }\n        }\n    }\n\n    /* checking for the PPS */\n\n    if(ps_pic->i4_pic_scaling_matrix_present_flag)\n    {\n        for(i4_i = 0; i4_i < 8; i4_i++)\n        {\n            if(i4_i < 6)\n            {\n                /* fall back rule B */\n                if(!ps_pic->u1_pic_scaling_list_present_flag[i4_i])\n                {\n                    if((i4_i == 0) || (i4_i == 3))\n                    {\n                        if(!ps_seq->i4_seq_scaling_matrix_present_flag)\n                        {\n                            ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                            (i4_i == 0) ? (WORD16 *)(gai2_ih264d_default_intra4x4) : (WORD16 *)(gai2_ih264d_default_inter4x4);\n                        }\n                    }\n                    else\n                    {\n                        ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                        ps_dec->s_high_profile.pi2_scale_mat[i4_i\n                                                        - 1];\n                    }\n                }\n                else\n                {\n                    if(ps_pic->u1_pic_use_default_scaling_matrix_flag[i4_i])\n                    {\n                        ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                        (i4_i < 3) ? (WORD16 *)(gai2_ih264d_default_intra4x4) : (WORD16 *)(gai2_ih264d_default_inter4x4);\n                    }\n                    else\n                    {\n                        ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                        ps_pic->i2_pic_scalinglist4x4[i4_i];\n                    }\n                }\n            }\n            else\n            {\n                if(!ps_pic->u1_pic_scaling_list_present_flag[i4_i])\n                {\n                    if(!ps_seq->i4_seq_scaling_matrix_present_flag)\n                    {\n                        ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                        (i4_i == 6) ? ((WORD16*)gai2_ih264d_default_intra8x8) : ((WORD16*)gai2_ih264d_default_inter8x8);\n                    }\n                }\n                else\n                {\n                    if(ps_pic->u1_pic_use_default_scaling_matrix_flag[i4_i])\n                    {\n                        ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                        (i4_i == 6) ? (WORD16 *)(gai2_ih264d_default_intra8x8) : (WORD16 *)(gai2_ih264d_default_inter8x8);\n                    }\n                    else\n                    {\n                        ps_dec->s_high_profile.pi2_scale_mat[i4_i] =\n                                        ps_pic->i2_pic_scalinglist8x8[i4_i - 6];\n                    }\n                }\n            }\n        }\n    }\n\n    /*************************************************************************/\n    /* perform the inverse scanning for the frame and field scaling matrices */\n    /*************************************************************************/\n    {\n        UWORD8 *pu1_inv_scan_4x4;\n        WORD32 i4_i, i4_j;\n\n        pu1_inv_scan_4x4 = (UWORD8 *)gau1_ih264d_inv_scan;\n\n        /* for all 4x4 matrices */\n        for(i4_i = 0; i4_i < 6; i4_i++)\n        {\n            if(ps_dec->s_high_profile.pi2_scale_mat[i4_i] == NULL)\n                return ERROR_CORRUPTED_SLICE;\n\n            for(i4_j = 0; i4_j < 16; i4_j++)\n            {\n                ps_dec->s_high_profile.i2_scalinglist4x4[i4_i][pu1_inv_scan_4x4[i4_j]] =\n                                ps_dec->s_high_profile.pi2_scale_mat[i4_i][i4_j];\n\n            }\n        }\n\n        /* for all 8x8 matrices */\n        for(i4_i = 0; i4_i < 2; i4_i++)\n        {\n            if(ps_dec->s_high_profile.pi2_scale_mat[i4_i + 6] == NULL)\n                return ERROR_CORRUPTED_SLICE;\n\n            for(i4_j = 0; i4_j < 64; i4_j++)\n            {\n                ps_dec->s_high_profile.i2_scalinglist8x8[i4_i][gau1_ih264d_inv_scan_prog8x8_cabac[i4_j]] =\n                                ps_dec->s_high_profile.pi2_scale_mat[i4_i + 6][i4_j];\n\n            }\n        }\n    }\n    return OK;\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_quant_scaling.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_QUANT_SCALING_H_\n#define _IH264D_QUANT_SCALING_H_\nWORD32 ih264d_scaling_list(WORD16 *pi2_scaling_list,\n                  WORD32 i4_size_of_scalinglist,\n                  UWORD8 *pu1_use_default_scaling_matrix_flag,\n                  dec_bit_stream_t *ps_bitstrm);\n\n\nWORD32 ih264d_form_scaling_matrix_picture(dec_seq_params_t *ps_seq,\n                                          dec_pic_params_t *ps_pic,\n                                          dec_struct_t *ps_dec);\n\nWORD32 ih264d_form_default_scaling_matrix(dec_struct_t *ps_dec);\n\n\n\n\n#endif\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_sei.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264d_sei.c                                         */\n/*                                                                           */\n/*  Description       : This file contains routines to parse SEI NAL's       */\n/*                                                                           */\n/*  List of Functions : <List the functions defined in this file>            */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         25 05 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\n#include <string.h>\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_vui.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_defs.h\"\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_buffering_period                            */\n/*                                                                           */\n/*  Description   : This function parses SEI message buffering_period        */\n/*  Inputs        : ps_buf_prd pointer to struct buf_period_t                */\n/*                  ps_bitstrm    Bitstream                                  */\n/*  Globals       : None                                                     */\n/*  Processing    : Parses SEI payload buffering period.                     */\n/*  Outputs       : None                                                     */\n/*  Return        : 0 for successfull parsing, else error message            */\n/*                                                                           */\n/*  Issues        : Not implemented fully                                    */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_parse_buffering_period(buf_period_t *ps_buf_prd,\n                                     dec_bit_stream_t *ps_bitstrm,\n                                     dec_struct_t *ps_dec)\n{\n    UWORD8 u1_seq_parameter_set_id;\n    dec_seq_params_t *ps_seq;\n    UWORD8 u1_nal_hrd_present, u1_vcl_hrd_present;\n    UWORD32 i;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UNUSED(ps_buf_prd);\n    u1_seq_parameter_set_id = ih264d_uev(pu4_bitstrm_ofst,\n                                         pu4_bitstrm_buf);\n    if(u1_seq_parameter_set_id >= MAX_NUM_SEQ_PARAMS)\n        return ERROR_INVALID_SEQ_PARAM;\n    ps_seq = &ps_dec->ps_sps[u1_seq_parameter_set_id];\n    if(TRUE != ps_seq->u1_is_valid)\n        return ERROR_INVALID_SEQ_PARAM;\n\n    ps_dec->ps_sei->u1_seq_param_set_id = u1_seq_parameter_set_id;\n    ps_dec->ps_cur_sps = ps_seq;\n    if(FALSE == ps_seq->u1_is_valid)\n        return ERROR_INVALID_SEQ_PARAM;\n    if(1 == ps_seq->u1_vui_parameters_present_flag)\n    {\n        u1_nal_hrd_present = ps_seq->s_vui.u1_nal_hrd_params_present;\n        if(u1_nal_hrd_present)\n        {\n            for(i = 0; i < ps_seq->s_vui.s_nal_hrd.u4_cpb_cnt; i++)\n            {\n                ih264d_get_bits_h264(\n                                ps_bitstrm,\n                                ps_seq->s_vui.s_nal_hrd.u1_initial_cpb_removal_delay);\n                ih264d_get_bits_h264(\n                                ps_bitstrm,\n                                ps_seq->s_vui.s_nal_hrd.u1_initial_cpb_removal_delay);\n            }\n        }\n\n        u1_vcl_hrd_present = ps_seq->s_vui.u1_vcl_hrd_params_present;\n        if(u1_vcl_hrd_present)\n        {\n            for(i = 0; i < ps_seq->s_vui.s_vcl_hrd.u4_cpb_cnt; i++)\n            {\n                ih264d_get_bits_h264(\n                                ps_bitstrm,\n                                ps_seq->s_vui.s_vcl_hrd.u1_initial_cpb_removal_delay);\n                ih264d_get_bits_h264(\n                                ps_bitstrm,\n                                ps_seq->s_vui.s_vcl_hrd.u1_initial_cpb_removal_delay);\n            }\n        }\n    }\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_pic_timing                                  */\n/*                                                                           */\n/*  Description   : This function parses SEI message pic_timing              */\n/*  Inputs        : ps_bitstrm    Bitstream                                  */\n/*                  ps_dec          Poniter decoder context                  */\n/*                  ui4_payload_size pay load i4_size                        */\n/*  Globals       : None                                                     */\n/*  Processing    : Parses SEI payload picture timing                        */\n/*  Outputs       : None                                                     */\n/*  Return        : 0                                                        */\n/*                                                                           */\n/*  Issues        : Not implemented fully                                    */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_pic_timing(dec_bit_stream_t *ps_bitstrm,\n                               dec_struct_t *ps_dec,\n                               UWORD32 ui4_payload_size)\n{\n    sei *ps_sei;\n    vui_t *ps_vu4;\n    UWORD8 u1_cpb_dpb_present;\n    UWORD8 u1_pic_struct_present_flag;\n    UWORD32 u4_start_offset, u4_bits_consumed;\n    UWORD8 u1_cpb_removal_delay_length, u1_dpb_output_delay_length;\n\n    ps_sei = (sei *)ps_dec->ps_sei;\n    ps_vu4 = &ps_dec->ps_cur_sps->s_vui;\n\n    u1_cpb_dpb_present = ps_vu4->u1_vcl_hrd_params_present\n                    + ps_vu4->u1_nal_hrd_params_present;\n\n    if(ps_vu4->u1_vcl_hrd_params_present)\n    {\n        u1_cpb_removal_delay_length =\n                        ps_vu4->s_vcl_hrd.u1_cpb_removal_delay_length;\n        u1_dpb_output_delay_length =\n                        ps_vu4->s_vcl_hrd.u1_dpb_output_delay_length;\n    }\n    else if(ps_vu4->u1_nal_hrd_params_present)\n    {\n        u1_cpb_removal_delay_length =\n                        ps_vu4->s_nal_hrd.u1_cpb_removal_delay_length;\n        u1_dpb_output_delay_length =\n                        ps_vu4->s_nal_hrd.u1_dpb_output_delay_length;\n    }\n    else\n    {\n        u1_cpb_removal_delay_length = 24;\n        u1_dpb_output_delay_length = 24;\n\n    }\n\n    u4_start_offset = ps_bitstrm->u4_ofst;\n    if(u1_cpb_dpb_present)\n    {\n        ih264d_get_bits_h264(ps_bitstrm, u1_cpb_removal_delay_length);\n        ih264d_get_bits_h264(ps_bitstrm, u1_dpb_output_delay_length);\n    }\n\n    u1_pic_struct_present_flag = ps_vu4->u1_pic_struct_present_flag;\n    if(u1_pic_struct_present_flag)\n    {\n        ps_sei->u1_pic_struct = ih264d_get_bits_h264(ps_bitstrm, 4);\n        ps_dec->u1_pic_struct_copy = ps_sei->u1_pic_struct;\n        ps_sei->u1_is_valid = 1;\n    }\n    u4_bits_consumed = ps_bitstrm->u4_ofst - u4_start_offset;\n\n    if((ui4_payload_size << 3) < u4_bits_consumed)\n        return ERROR_CORRUPTED_SLICE;\n\n    ih264d_flush_bits_h264(ps_bitstrm,\n                           (ui4_payload_size << 3) - u4_bits_consumed);\n\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_recovery_point                              */\n/*                                                                           */\n/*  Description   : This function parses SEI message recovery point          */\n/*  Inputs        : ps_bitstrm    Bitstream                                  */\n/*                  ps_dec          Poniter decoder context                  */\n/*                  ui4_payload_size pay load i4_size                        */\n/*  Globals       : None                                                     */\n/*  Processing    : Parses SEI payload picture timing                        */\n/*  Outputs       : None                                                     */\n/*  Return        : 0                                                        */\n/*                                                                           */\n/*  Issues        : Not implemented fully                                    */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_recovery_point(dec_bit_stream_t *ps_bitstrm,\n                                   dec_struct_t *ps_dec,\n                                   UWORD32 ui4_payload_size)\n{\n    sei *ps_sei = ps_dec->ps_sei;\n    dec_err_status_t *ps_err = ps_dec->ps_dec_err_status;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UNUSED(ui4_payload_size);\n    ps_sei->u2_recovery_frame_cnt = ih264d_uev(pu4_bitstrm_ofst,\n                                               pu4_bitstrm_buf);\n    ps_err->u4_frm_sei_sync = ps_err->u4_cur_frm\n                    + ps_sei->u2_recovery_frame_cnt;\n    ps_sei->u1_exact_match_flag = ih264d_get_bit_h264(ps_bitstrm);\n    ps_sei->u1_broken_link_flag = ih264d_get_bit_h264(ps_bitstrm);\n    ps_sei->u1_changing_slice_grp_idc = ih264d_get_bits_h264(ps_bitstrm, 2);\n\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_mdcv                                        */\n/*                                                                           */\n/*  Description   : This function parses SEI message mdcv                    */\n/*  Inputs        : ps_bitstrm    Bitstream                                  */\n/*                  ps_dec          Poniter decoder context                  */\n/*                  ui4_payload_size pay load i4_size                        */\n/*  Globals       : None                                                     */\n/*  Processing    :                                                          */\n/*  Outputs       : None                                                     */\n/*  Return        : 0 for successfull parsing, else -1                       */\n/*                                                                           */\n/*  Issues        :                                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                         Draft                             */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_mdcv(dec_bit_stream_t *ps_bitstrm,\n                         dec_struct_t *ps_dec,\n                         UWORD32 ui4_payload_size)\n{\n    sei *ps_sei = ps_dec->ps_sei_parse;\n    dec_err_status_t *ps_err = ps_dec->ps_dec_err_status;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 u4_count;\n    UNUSED(ui4_payload_size);\n\n    if((ps_dec == NULL) || (ps_sei == NULL))\n    {\n        return NOT_OK;\n    }\n\n    ps_sei->u1_sei_mdcv_params_present_flag = 1;\n\n    /* display primaries x */\n    for(u4_count = 0; u4_count < NUM_SEI_MDCV_PRIMARIES; u4_count++)\n    {\n        ps_sei->s_sei_mdcv_params.au2_display_primaries_x[u4_count] =\n                                    (UWORD16)ih264d_get_bits_h264(ps_bitstrm, 16);\n\n        if((ps_sei->s_sei_mdcv_params.au2_display_primaries_x[u4_count] >\n                                                DISPLAY_PRIMARIES_X_UPPER_LIMIT) ||\n           (ps_sei->s_sei_mdcv_params.au2_display_primaries_x[u4_count] <\n                                                DISPLAY_PRIMARIES_X_LOWER_LIMIT) ||\n           ((ps_sei->s_sei_mdcv_params.au2_display_primaries_x[u4_count] %\n                                               DISPLAY_PRIMARIES_X_DIVISION_FACTOR) != 0))\n        {\n            ps_sei->u1_sei_mdcv_params_present_flag = 0;\n            return ERROR_INV_SEI_MDCV_PARAMS;\n        }\n\n        ps_sei->s_sei_mdcv_params.au2_display_primaries_y[u4_count] =\n                                    (UWORD16)ih264d_get_bits_h264(ps_bitstrm, 16);\n\n        if((ps_sei->s_sei_mdcv_params.au2_display_primaries_y[u4_count] >\n                                                DISPLAY_PRIMARIES_Y_UPPER_LIMIT) ||\n           (ps_sei->s_sei_mdcv_params.au2_display_primaries_y[u4_count] <\n                                               DISPLAY_PRIMARIES_Y_LOWER_LIMIT) ||\n           ((ps_sei->s_sei_mdcv_params.au2_display_primaries_y[u4_count] %\n                                              DISPLAY_PRIMARIES_Y_DIVISION_FACTOR) != 0))\n        {\n            ps_sei->u1_sei_mdcv_params_present_flag = 0;\n            return ERROR_INV_SEI_MDCV_PARAMS;\n        }\n    }\n\n    /* white point x */\n    ps_sei->s_sei_mdcv_params.u2_white_point_x = (UWORD16)ih264d_get_bits_h264(ps_bitstrm, 16);\n\n    if((ps_sei->s_sei_mdcv_params.u2_white_point_x > WHITE_POINT_X_UPPER_LIMIT) ||\n       (ps_sei->s_sei_mdcv_params.u2_white_point_x < WHITE_POINT_X_LOWER_LIMIT) ||\n       ((ps_sei->s_sei_mdcv_params.u2_white_point_x % WHITE_POINT_X_DIVISION_FACTOR) != 0))\n    {\n        ps_sei->u1_sei_mdcv_params_present_flag = 0;\n        return ERROR_INV_SEI_MDCV_PARAMS;\n    }\n    /* white point y */\n    ps_sei->s_sei_mdcv_params.u2_white_point_y = (UWORD16)ih264d_get_bits_h264(ps_bitstrm, 16);\n\n    if((ps_sei->s_sei_mdcv_params.u2_white_point_y > WHITE_POINT_Y_UPPER_LIMIT) ||\n       (ps_sei->s_sei_mdcv_params.u2_white_point_y < WHITE_POINT_Y_LOWER_LIMIT) ||\n       ((ps_sei->s_sei_mdcv_params.u2_white_point_y % WHITE_POINT_Y_DIVISION_FACTOR) != 0))\n    {\n        ps_sei->u1_sei_mdcv_params_present_flag = 0;\n        return ERROR_INV_SEI_MDCV_PARAMS;\n    }\n    /* max display mastering luminance */\n    ps_sei->s_sei_mdcv_params.u4_max_display_mastering_luminance =\n                                    (UWORD32)ih264d_get_bits_h264(ps_bitstrm, 32);\n\n    if((ps_sei->s_sei_mdcv_params.u4_max_display_mastering_luminance >\n                                            MAX_DISPLAY_MASTERING_LUMINANCE_UPPER_LIMIT) ||\n       (ps_sei->s_sei_mdcv_params.u4_max_display_mastering_luminance <\n                                            MAX_DISPLAY_MASTERING_LUMINANCE_LOWER_LIMIT) ||\n       ((ps_sei->s_sei_mdcv_params.u4_max_display_mastering_luminance %\n                                        MAX_DISPLAY_MASTERING_LUMINANCE_DIVISION_FACTOR) != 0))\n    {\n        ps_sei->u1_sei_mdcv_params_present_flag = 0;\n        return ERROR_INV_SEI_MDCV_PARAMS;\n    }\n    /* min display mastering luminance */\n    ps_sei->s_sei_mdcv_params.u4_min_display_mastering_luminance =\n                                    (UWORD32)ih264d_get_bits_h264(ps_bitstrm, 32);\n\n    if((ps_sei->s_sei_mdcv_params.u4_min_display_mastering_luminance >\n                                            MIN_DISPLAY_MASTERING_LUMINANCE_UPPER_LIMIT) ||\n        (ps_sei->s_sei_mdcv_params.u4_min_display_mastering_luminance <\n                                            MIN_DISPLAY_MASTERING_LUMINANCE_LOWER_LIMIT))\n    {\n        ps_sei->u1_sei_mdcv_params_present_flag = 0;\n        return ERROR_INV_SEI_MDCV_PARAMS;\n    }\n    if(ps_sei->s_sei_mdcv_params.u4_max_display_mastering_luminance <=\n            ps_sei->s_sei_mdcv_params.u4_min_display_mastering_luminance)\n    {\n        ps_sei->u1_sei_mdcv_params_present_flag = 0;\n        return ERROR_INV_SEI_MDCV_PARAMS;\n    }\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_cll                                         */\n/*                                                                           */\n/*  Description   : This function parses SEI message cll                     */\n/*  Inputs        : ps_bitstrm    Bitstream                                  */\n/*                  ps_dec          Poniter decoder context                  */\n/*                  ui4_payload_size pay load i4_size                        */\n/*  Globals       : None                                                     */\n/*  Processing    :                                                          */\n/*  Outputs       : None                                                     */\n/*  Return        : 0 for successfull parsing, else -1                       */\n/*                                                                           */\n/*  Issues        :                                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                         Draft                             */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_cll(dec_bit_stream_t *ps_bitstrm,\n                        dec_struct_t *ps_dec,\n                        UWORD32 ui4_payload_size)\n{\n    sei *ps_sei = ps_dec->ps_sei_parse;\n    dec_err_status_t *ps_err = ps_dec->ps_dec_err_status;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UNUSED(ui4_payload_size);\n\n    if((ps_dec == NULL) || (ps_sei == NULL))\n    {\n        return NOT_OK;\n    }\n\n    ps_sei->u1_sei_cll_params_present_flag = 1;\n\n    ps_sei->s_sei_cll_params.u2_max_content_light_level =\n                        (UWORD16)ih264d_get_bits_h264(ps_bitstrm, 16);\n    ps_sei->s_sei_cll_params.u2_max_pic_average_light_level =\n                        (UWORD16)ih264d_get_bits_h264(ps_bitstrm, 16);\n    /*No any sanity checks done for CLL params*/\n\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_ave                                         */\n/*                                                                           */\n/*  Description   : This function parses SEI message ave                     */\n/*  Inputs        : ps_bitstrm    Bitstream                                  */\n/*                  ps_dec          Poniter decoder context                  */\n/*                  ui4_payload_size pay load i4_size                        */\n/*  Globals       : None                                                     */\n/*  Processing    :                                                          */\n/*  Outputs       : None                                                     */\n/*  Return        : 0 for successfull parsing, else -1                       */\n/*                                                                           */\n/*  Issues        :                                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                         Draft                             */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_ave(dec_bit_stream_t *ps_bitstrm,\n                        dec_struct_t *ps_dec,\n                        UWORD32 ui4_payload_size)\n{\n    sei *ps_sei = ps_dec->ps_sei_parse;\n    dec_err_status_t *ps_err = ps_dec->ps_dec_err_status;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UNUSED(ui4_payload_size);\n\n    if((ps_dec == NULL) || (ps_sei == NULL))\n    {\n        return NOT_OK;\n    }\n\n    ps_sei->u1_sei_ave_params_present_flag = 1;\n\n    ps_sei->s_sei_ave_params.u4_ambient_illuminance = (UWORD32)ih264d_get_bits_h264(ps_bitstrm, 32);\n    if(0 == ps_sei->s_sei_ave_params.u4_ambient_illuminance)\n    {\n        ps_sei->u1_sei_ave_params_present_flag = 0;\n        return ERROR_INV_SEI_AVE_PARAMS;\n    }\n\n    ps_sei->s_sei_ave_params.u2_ambient_light_x = (UWORD16)ih264d_get_bits_h264(ps_bitstrm, 16);\n    if(ps_sei->s_sei_ave_params.u2_ambient_light_x > AMBIENT_LIGHT_X_UPPER_LIMIT)\n    {\n        ps_sei->u1_sei_ave_params_present_flag = 0;\n        return ERROR_INV_SEI_AVE_PARAMS;\n    }\n\n    ps_sei->s_sei_ave_params.u2_ambient_light_y = (UWORD16)ih264d_get_bits_h264(ps_bitstrm, 16);\n    if(ps_sei->s_sei_ave_params.u2_ambient_light_y > AMBIENT_LIGHT_Y_UPPER_LIMIT)\n    {\n        ps_sei->u1_sei_ave_params_present_flag = 0;\n        return ERROR_INV_SEI_AVE_PARAMS;\n    }\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_ccv                                         */\n/*                                                                           */\n/*  Description   : This function parses SEI message ccv                     */\n/*  Inputs        : ps_bitstrm    Bitstream                                  */\n/*                  ps_dec          Poniter decoder context                  */\n/*                  ui4_payload_size pay load i4_size                        */\n/*  Globals       : None                                                     */\n/*  Processing    :                                                          */\n/*  Outputs       : None                                                     */\n/*  Return        : 0 for successfull parsing, else -1                       */\n/*                                                                           */\n/*  Issues        :                                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                         Draft                                             */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_parse_ccv(dec_bit_stream_t *ps_bitstrm,\n                        dec_struct_t *ps_dec,\n                        UWORD32 ui4_payload_size)\n{\n    sei *ps_sei = ps_dec->ps_sei_parse;\n    dec_err_status_t *ps_err = ps_dec->ps_dec_err_status;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    UWORD32 u4_count;\n    UNUSED(ui4_payload_size);\n\n    if((ps_dec == NULL) || (ps_sei == NULL))\n    {\n        return NOT_OK;\n    }\n\n    ps_sei->u1_sei_ccv_params_present_flag = 0;\n\n    ps_sei->s_sei_ccv_params.u1_ccv_cancel_flag = (UWORD8)ih264d_get_bit_h264(ps_bitstrm);\n\n    if(ps_sei->s_sei_ccv_params.u1_ccv_cancel_flag > 1)\n    {\n        return ERROR_INV_SEI_CCV_PARAMS;\n    }\n    if(0 == ps_sei->s_sei_ccv_params.u1_ccv_cancel_flag)\n    {\n        ps_sei->s_sei_ccv_params.u1_ccv_persistence_flag =\n                                                (UWORD8)ih264d_get_bit_h264(ps_bitstrm);\n        if(ps_sei->s_sei_ccv_params.u1_ccv_persistence_flag > 1)\n        {\n            return ERROR_INV_SEI_CCV_PARAMS;\n        }\n        ps_sei->s_sei_ccv_params.u1_ccv_primaries_present_flag =\n                                                (UWORD8)ih264d_get_bit_h264(ps_bitstrm);\n        if(ps_sei->s_sei_ccv_params.u1_ccv_primaries_present_flag > 1)\n        {\n            return ERROR_INV_SEI_CCV_PARAMS;\n        }\n        ps_sei->s_sei_ccv_params.u1_ccv_min_luminance_value_present_flag =\n                                                (UWORD8)ih264d_get_bit_h264(ps_bitstrm);\n        if(ps_sei->s_sei_ccv_params.u1_ccv_min_luminance_value_present_flag > 1)\n        {\n            return ERROR_INV_SEI_CCV_PARAMS;\n        }\n        ps_sei->s_sei_ccv_params.u1_ccv_max_luminance_value_present_flag =\n                                                (UWORD8)ih264d_get_bit_h264(ps_bitstrm);\n        if(ps_sei->s_sei_ccv_params.u1_ccv_max_luminance_value_present_flag > 1)\n        {\n            return ERROR_INV_SEI_CCV_PARAMS;\n        }\n        ps_sei->s_sei_ccv_params.u1_ccv_avg_luminance_value_present_flag =\n                                                (UWORD8)ih264d_get_bit_h264(ps_bitstrm);\n        if(ps_sei->s_sei_ccv_params.u1_ccv_avg_luminance_value_present_flag > 1)\n        {\n            return ERROR_INV_SEI_CCV_PARAMS;\n        }\n\n        if((ps_sei->s_sei_ccv_params.u1_ccv_primaries_present_flag == 0) &&\n           (ps_sei->s_sei_ccv_params.u1_ccv_min_luminance_value_present_flag == 0) &&\n           (ps_sei->s_sei_ccv_params.u1_ccv_max_luminance_value_present_flag == 0) &&\n           (ps_sei->s_sei_ccv_params.u1_ccv_avg_luminance_value_present_flag == 0))\n        {\n            return ERROR_INV_SEI_CCV_PARAMS;\n\t }\n\n        ps_sei->s_sei_ccv_params.u1_ccv_reserved_zero_2bits =\n                                                (UWORD8)ih264d_get_bits_h264(ps_bitstrm, 2);\n        if((ps_sei->s_sei_ccv_params.u1_ccv_reserved_zero_2bits != 0))\n        {\n            return ERROR_INV_SEI_CCV_PARAMS;\n        }\n\n        /* ccv primaries */\n        if(1 == ps_sei->s_sei_ccv_params.u1_ccv_primaries_present_flag)\n        {\n            for(u4_count = 0; u4_count < NUM_SEI_CCV_PRIMARIES; u4_count++)\n            {\n                ps_sei->s_sei_ccv_params.ai4_ccv_primaries_x[u4_count] =\n                                                (WORD32)ih264d_get_bits_h264(ps_bitstrm, 32);\n                if((ps_sei->s_sei_ccv_params.ai4_ccv_primaries_x[u4_count] >\n                                                        CCV_PRIMARIES_X_UPPER_LIMIT) ||\n                   (ps_sei->s_sei_ccv_params.ai4_ccv_primaries_x[u4_count] <\n                                                        CCV_PRIMARIES_X_LOWER_LIMIT))\n                {\n                    return ERROR_INV_SEI_CCV_PARAMS;\n                }\n\n                ps_sei->s_sei_ccv_params.ai4_ccv_primaries_y[u4_count] =\n                                                (WORD32)ih264d_get_bits_h264(ps_bitstrm, 32);\n                if((ps_sei->s_sei_ccv_params.ai4_ccv_primaries_y[u4_count] >\n                                                        CCV_PRIMARIES_Y_UPPER_LIMIT) ||\n                   (ps_sei->s_sei_ccv_params.ai4_ccv_primaries_y[u4_count] <\n                                                        CCV_PRIMARIES_Y_LOWER_LIMIT))\n                {\n                    return ERROR_INV_SEI_CCV_PARAMS;\n                }\n            }\n        }\n\n        if(1 == ps_sei->s_sei_ccv_params.u1_ccv_min_luminance_value_present_flag)\n        {\n            ps_sei->s_sei_ccv_params.u4_ccv_min_luminance_value =\n                                                (UWORD32)ih264d_get_bits_h264(ps_bitstrm, 32);\n        }\n\n        if(1 == ps_sei->s_sei_ccv_params.u1_ccv_max_luminance_value_present_flag)\n        {\n            ps_sei->s_sei_ccv_params.u4_ccv_max_luminance_value =\n                                                (UWORD32)ih264d_get_bits_h264(ps_bitstrm, 32);\n            if((1 == ps_sei->s_sei_ccv_params.u1_ccv_min_luminance_value_present_flag) &&\n                (ps_sei->s_sei_ccv_params.u4_ccv_max_luminance_value <\n                                                ps_sei->s_sei_ccv_params.u4_ccv_min_luminance_value))\n            {\n                return ERROR_INV_SEI_CCV_PARAMS;\n            }\n        }\n        if(1 == ps_sei->s_sei_ccv_params.u1_ccv_avg_luminance_value_present_flag)\n        {\n            ps_sei->s_sei_ccv_params.u4_ccv_avg_luminance_value =\n                                                (UWORD32)ih264d_get_bits_h264(ps_bitstrm, 32);\n            if((1 == ps_sei->s_sei_ccv_params.u1_ccv_min_luminance_value_present_flag) &&\n                (ps_sei->s_sei_ccv_params.u4_ccv_avg_luminance_value <\n                                                ps_sei->s_sei_ccv_params.u4_ccv_min_luminance_value))\n            {\n                return ERROR_INV_SEI_CCV_PARAMS;\n            }\n            if((1 == ps_sei->s_sei_ccv_params.u1_ccv_max_luminance_value_present_flag) &&\n                (ps_sei->s_sei_ccv_params.u4_ccv_max_luminance_value <\n                                                ps_sei->s_sei_ccv_params.u4_ccv_avg_luminance_value))\n            {\n                return ERROR_INV_SEI_CCV_PARAMS;\n            }\n        }\n    }\n    ps_sei->u1_sei_ccv_params_present_flag = 1;\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_sei_payload                                 */\n/*                                                                           */\n/*  Description   : This function parses SEI pay loads. Currently it's       */\n/*                  implemented partially.                                   */\n/*  Inputs        : ps_bitstrm    Bitstream                                  */\n/*                  ui4_payload_type  SEI payload type                       */\n/*                  ui4_payload_size  SEI payload i4_size                    */\n/*  Globals       : None                                                     */\n/*  Processing    : Parses SEI payloads units and stores the info            */\n/*  Outputs       : None                                                     */\n/*  Return        : status for successful parsing, else -1                   */\n/*                                                                           */\n/*  Issues        : Not implemented fully                                    */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_parse_sei_payload(dec_bit_stream_t *ps_bitstrm,\n                                UWORD32 ui4_payload_type,\n                                UWORD32 ui4_payload_size,\n                                dec_struct_t *ps_dec)\n{\n    sei *ps_sei;\n    WORD32 i4_status = 0;\n    ps_sei = (sei *)ps_dec->ps_sei_parse;\n\n    if(ui4_payload_size == 0)\n        return -1;\n    if(NULL == ps_bitstrm)\n    {\n        return NOT_OK;\n    }\n\n    switch(ui4_payload_type)\n    {\n        case SEI_BUF_PERIOD:\n\n            i4_status = ih264d_parse_buffering_period(&ps_sei->s_buf_period,\n                                                      ps_bitstrm, ps_dec);\n            break;\n        case SEI_PIC_TIMING:\n            if(NULL == ps_dec->ps_cur_sps)\n                i4_status = ih264d_flush_bits_h264(ps_bitstrm, (ui4_payload_size << 3));\n            else\n                i4_status = ih264d_parse_pic_timing(ps_bitstrm, ps_dec,\n                                        ui4_payload_size);\n            break;\n        case SEI_RECOVERY_PT:\n            i4_status = ih264d_parse_recovery_point(ps_bitstrm, ps_dec,\n                                        ui4_payload_size);\n            break;\n        case SEI_MASTERING_DISP_COL_VOL:\n\n            i4_status = ih264d_parse_mdcv(ps_bitstrm, ps_dec,\n                                          ui4_payload_size);\n            break;\n        case SEI_CONTENT_LIGHT_LEVEL_DATA:\n\n            i4_status = ih264d_parse_cll(ps_bitstrm, ps_dec,\n                                         ui4_payload_size);\n            break;\n        case SEI_AMBIENT_VIEWING_ENVIRONMENT:\n\n            i4_status = ih264d_parse_ave(ps_bitstrm, ps_dec,\n                                         ui4_payload_size);\n            break;\n        case SEI_CONTENT_COLOR_VOLUME:\n\n            i4_status = ih264d_parse_ccv(ps_bitstrm, ps_dec,\n                                         ui4_payload_size);\n            break;\n        default:\n            i4_status = ih264d_flush_bits_h264(ps_bitstrm, (ui4_payload_size << 3));\n            break;\n    }\n    return (i4_status);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_sei_message                                        */\n/*                                                                           */\n/*  Description   : This function is parses and decode SEI. Currently it's   */\n/*                  not implemented fully.                                   */\n/*  Inputs        : ps_dec    Decoder parameters                       */\n/*                  ps_bitstrm    Bitstream                                */\n/*  Globals       : None                                                     */\n/*  Processing    : Parses SEI NAL units and stores the info                 */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : Not implemented fully                                    */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_parse_sei_message(dec_struct_t *ps_dec,\n                                dec_bit_stream_t *ps_bitstrm)\n{\n    UWORD32 ui4_payload_type, ui4_payload_size;\n    UWORD32 u4_bits;\n    WORD32 i4_status = 0;\n\n    do\n    {\n        ui4_payload_type = 0;\n\n        if(!CHECK_BITS_SUFFICIENT(ps_bitstrm, 8))\n        {\n            return ERROR_EOB_GETBITS_T;\n        }\n        u4_bits = ih264d_get_bits_h264(ps_bitstrm, 8);\n        while(0xff == u4_bits && CHECK_BITS_SUFFICIENT(ps_bitstrm, 8))\n        {\n            u4_bits = ih264d_get_bits_h264(ps_bitstrm, 8);\n            ui4_payload_type += 255;\n        }\n        ui4_payload_type += u4_bits;\n\n        ui4_payload_size = 0;\n        if(!CHECK_BITS_SUFFICIENT(ps_bitstrm, 8))\n        {\n            return ERROR_EOB_GETBITS_T;\n        }\n        u4_bits = ih264d_get_bits_h264(ps_bitstrm, 8);\n        while(0xff == u4_bits && CHECK_BITS_SUFFICIENT(ps_bitstrm, 8))\n        {\n            u4_bits = ih264d_get_bits_h264(ps_bitstrm, 8);\n            ui4_payload_size += 255;\n        }\n        ui4_payload_size += u4_bits;\n\n        if(!CHECK_BITS_SUFFICIENT(ps_bitstrm, (ui4_payload_size << 3)))\n        {\n            return ERROR_EOB_GETBITS_T;\n        }\n        i4_status = ih264d_parse_sei_payload(ps_bitstrm, ui4_payload_type,\n                                             ui4_payload_size, ps_dec);\n        if(i4_status != OK)\n            return i4_status;\n\n        if(ih264d_check_byte_aligned(ps_bitstrm) == 0)\n        {\n            u4_bits = ih264d_get_bit_h264(ps_bitstrm);\n            if(0 == u4_bits)\n            {\n                H264_DEC_DEBUG_PRINT(\"\\nError in parsing SEI message\");\n            }\n            while(0 == ih264d_check_byte_aligned(ps_bitstrm)\n                            && CHECK_BITS_SUFFICIENT(ps_bitstrm, 1))\n            {\n                u4_bits = ih264d_get_bit_h264(ps_bitstrm);\n                if(u4_bits)\n                {\n                    H264_DEC_DEBUG_PRINT(\"\\nError in parsing SEI message\");\n                }\n            }\n        }\n    }\n    while(MORE_RBSP_DATA(ps_bitstrm));\n    return (i4_status);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_export_sei_mdcv_params                            */\n/*                                                                           */\n/*  Description   : This function populates SEI mdcv message in              */\n/*                     output structure                                      */\n/*  Inputs        : ps_sei_mdcv_op pointer to sei mdcv o\\p struct            */\n/*                : ps_sei pointer to decoded sei params                     */\n/*  Outputs       :                                                          */\n/*  Returns       : returns 0 for success; -1 for failure                    */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                                                           */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_export_sei_mdcv_params(ivd_sei_decode_op_t *ps_sei_decode_op,\n                                     sei *ps_sei, sei *ps_sei_export)\n{\n    if((ps_sei_export == NULL) || (ps_sei == NULL))\n    {\n        return NOT_OK;\n    }\n\n    ps_sei_export->u1_sei_mdcv_params_present_flag = ps_sei->u1_sei_mdcv_params_present_flag;\n    ps_sei_decode_op->u1_sei_mdcv_params_present_flag = ps_sei->u1_sei_mdcv_params_present_flag;\n\n    if(0 == ps_sei_export->u1_sei_mdcv_params_present_flag)\n    {\n        memset(&ps_sei_export->s_sei_mdcv_params, 0, sizeof(sei_mdcv_params_t));\n    }\n    else\n    {\n        memcpy(&ps_sei_export->s_sei_mdcv_params, &ps_sei->s_sei_mdcv_params,\n                                                    sizeof(sei_mdcv_params_t));\n    }\n\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_export_sei_cll_params                             */\n/*                                                                           */\n/*  Description   : This function populates SEI cll message in               */\n/*                     output structure                                      */\n/*  Inputs        : ps_sei_cll_op pointer to sei cll o\\p struct              */\n/*                : ps_sei pointer to decoded sei params                     */\n/*  Outputs       :                                                          */\n/*  Returns       : returns 0 for success; -1 for failure                    */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                                                           */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_export_sei_cll_params(ivd_sei_decode_op_t *ps_sei_decode_op,\n                                    sei *ps_sei, sei *ps_sei_export)\n{\n    if((ps_sei_export == NULL) || (ps_sei == NULL))\n    {\n        return NOT_OK;\n    }\n\n    ps_sei_export->u1_sei_cll_params_present_flag = ps_sei->u1_sei_cll_params_present_flag;\n    ps_sei_decode_op->u1_sei_cll_params_present_flag = ps_sei->u1_sei_cll_params_present_flag;\n\n    if(0 == ps_sei_export->u1_sei_cll_params_present_flag)\n    {\n        memset(&ps_sei_export->s_sei_cll_params, 0, sizeof(sei_cll_params_t));\n    }\n    else\n    {\n        memcpy(&ps_sei_export->s_sei_cll_params, &ps_sei->s_sei_cll_params,\n                                                    sizeof(sei_cll_params_t));\n    }\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_export_sei_ave_params                             */\n/*                                                                           */\n/*  Description   : This function populates SEI ave message in               */\n/*                     output structure                                      */\n/*  Inputs        : ps_sei_ave_op pointer to sei ave o\\p struct              */\n/*                : ps_sei pointer to decoded sei params                     */\n/*  Outputs       :                                                          */\n/*  Returns       : returns 0 for success; -1 for failure                    */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                                                           */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_export_sei_ave_params(ivd_sei_decode_op_t *ps_sei_decode_op,\n                                    sei *ps_sei, sei *ps_sei_export)\n{\n    if((ps_sei_export == NULL) || (ps_sei == NULL))\n    {\n        return NOT_OK;\n    }\n\n    ps_sei_export->u1_sei_ave_params_present_flag = ps_sei->u1_sei_ave_params_present_flag;\n    ps_sei_decode_op->u1_sei_ave_params_present_flag = ps_sei->u1_sei_ave_params_present_flag;\n\n    if(0 == ps_sei_export->u1_sei_ave_params_present_flag)\n    {\n        memset(&ps_sei_export->s_sei_ave_params, 0, sizeof(sei_ave_params_t));\n    }\n    else\n    {\n        memcpy(&ps_sei_export->s_sei_ave_params, &ps_sei->s_sei_ave_params,\n                                                    sizeof(sei_ave_params_t));\n    }\n\n    return (OK);\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_export_sei_ccv_params                             */\n/*                                                                           */\n/*  Description   : This function populates SEI ccv message in               */\n/*                     output structure                                      */\n/*  Inputs        : ps_sei_ccv_op pointer to sei ccv o\\p struct              */\n/*                : ps_sei pointer to decoded sei params                     */\n/*  Outputs       :                                                          */\n/*  Returns       : returns 0 for success; -1 for failure                    */\n/*                                                                           */\n/*  Issues        : none                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                                                                           */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_export_sei_ccv_params(ivd_sei_decode_op_t *ps_sei_decode_op,\n                                    sei *ps_sei, sei *ps_sei_export)\n{\n    if((ps_sei_export == NULL) || (ps_sei == NULL))\n    {\n        return NOT_OK;\n    }\n\n    ps_sei_export->u1_sei_ccv_params_present_flag = ps_sei->u1_sei_ccv_params_present_flag;\n    ps_sei_decode_op->u1_sei_ccv_params_present_flag = ps_sei->u1_sei_ccv_params_present_flag;\n\n    if(0 == ps_sei_export->u1_sei_ccv_params_present_flag)\n    {\n        memset(&ps_sei_export->s_sei_ccv_params, 0, sizeof(sei_ccv_params_t));\n    }\n    else\n    {\n        memcpy(&ps_sei_export->s_sei_ccv_params, &ps_sei->s_sei_ccv_params,\n                                                    sizeof(sei_ccv_params_t));\n    }\n    return (OK);\n}\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_sei.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264d_sei.h                                                */\n/*                                                                           */\n/*  Description       : This file contains routines to parse SEI NAL's       */\n/*                                                                           */\n/*  List of Functions : <List the functions defined in this file>            */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         25 05 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\n#ifndef _IH264D_SEI_H_\n#define _IH264D_SEI_H_\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d.h\"\n\n#define SEI_BUF_PERIOD      0\n#define SEI_PIC_TIMING      1\n#define SEI_PAN_SCAN_RECT   2\n#define SEI_FILLER          3\n#define SEI_UD_REG_T35      4\n#define SEI_UD_UN_REG       5\n#define SEI_RECOVERY_PT     6\n#define SEI_DEC_REF_MARK    7\n#define SEI_SPARE_PIC       8\n#define SEI_SCENE_INFO      9\n#define SEI_SUB_SEQN_INFO   10\n#define SEI_SUB_SEQN_LAY_CHAR       11\n#define SEI_SUB_SEQN_CHAR   12\n#define SEI_FULL_FRAME_FREEZE       13\n#define SEI_FULL_FRAME_FREEZE_REL   14\n#define SEI_FULL_FRAME_SNAP_SHOT    15\n#define SEI_PROG_REF_SEGMENT_START  16\n#define SEI_PROG_REF_SEGMENT_END    17\n#define SEI_MOT_CON_SLICE_GRP_SET   18\n#define SEI_MASTERING_DISP_COL_VOL       137\n#define SEI_CONTENT_LIGHT_LEVEL_DATA     144\n#define SEI_AMBIENT_VIEWING_ENVIRONMENT  148\n#define SEI_CONTENT_COLOR_VOLUME         149\n\n/* Declaration of dec_struct_t to avoid CCS compilation Error */\nstruct _DecStruct;\nWORD32 ih264d_parse_sei_message(struct _DecStruct *ps_dec,\n                                dec_bit_stream_t *ps_bitstrm);\ntypedef struct\n{\n    UWORD8 u1_seq_parameter_set_id;\n    UWORD32 u4_initial_cpb_removal_delay;\n    UWORD32 u4_nitial_cpb_removal_delay_offset;\n\n} buf_period_t;\n\n/**\n * Structure to hold Mastering Display Color Volume SEI\n */\ntypedef struct\n{\n    /**\n     * Array to store the display_primaries_x values\n     */\n    UWORD16 au2_display_primaries_x[NUM_SEI_MDCV_PRIMARIES];\n\n    /**\n     * Array to store the display_primaries_y values\n     */\n    UWORD16 au2_display_primaries_y[NUM_SEI_MDCV_PRIMARIES];\n\n    /**\n     * Variable to store the white point x value\n     */\n    UWORD16 u2_white_point_x;\n\n    /**\n     * Variable to store the white point y value\n     */\n    UWORD16 u2_white_point_y;\n\n    /**\n     * Variable to store the max display mastering luminance value\n     */\n    UWORD32 u4_max_display_mastering_luminance;\n\n    /**\n     * Variable to store the min display mastering luminance value\n     */\n    UWORD32 u4_min_display_mastering_luminance;\n\n}sei_mdcv_params_t;\n\n\n/**\n * Structure for Content Light Level Info\n *\n */\ntypedef struct\n{\n    /**\n     * The maximum pixel intensity of all samples\n     */\n    UWORD16 u2_max_content_light_level;\n\n    /**\n     * The average pixel intensity of all samples\n     */\n    UWORD16 u2_max_pic_average_light_level;\n\n}sei_cll_params_t;\n\n\n/**\n * Structure to hold Ambient viewing environment SEI\n */\ntypedef struct\n{\n\n    /**\n     * specifies the environmental illuminance of the ambient viewing environment\n     */\n    UWORD32 u4_ambient_illuminance;\n\n    /*\n     * specify the normalized x chromaticity coordinates of the\n     * environmental ambient light in the nominal viewing environment\n     */\n    UWORD16 u2_ambient_light_x;\n\n    /*\n    * specify the normalized y chromaticity coordinates of the\n    * environmental ambient light in the nominal viewing environment\n    */\n    UWORD16 u2_ambient_light_y;\n\n}sei_ave_params_t;\n\n\n/**\n * Structure to hold Content color volume SEI\n */\ntypedef struct\n{\n    /*\n     * Flag used to control persistence of CCV SEI messages\n     */\n    UWORD8 u1_ccv_cancel_flag;\n\n    /*\n     * specifies the persistence of the CCV SEI message for the current layer\n     */\n    UWORD8 u1_ccv_persistence_flag;\n\n    /*\n     * specifies the presence of syntax elements ccv_primaries_x and ccv_primaries_y\n     */\n    UWORD8 u1_ccv_primaries_present_flag;\n\n    /*\n     * specifies that the syntax element ccv_min_luminance_value is present\n     */\n    UWORD8 u1_ccv_min_luminance_value_present_flag;\n\n    /*\n     * specifies that the syntax element ccv_max_luminance_value is present\n     */\n    UWORD8 u1_ccv_max_luminance_value_present_flag;\n\n    /*\n     * specifies that the syntax element ccv_avg_luminance_value is present\n     */\n    UWORD8 u1_ccv_avg_luminance_value_present_flag;\n\n    /*\n     * shall be equal to 0 in bitstreams conforming to this version. Other values\n     * for reserved_zero_2bits are reserved for future use\n     */\n    UWORD8 u1_ccv_reserved_zero_2bits;\n\n    /*\n     * specify the normalized x chromaticity coordinates of the colour\n     * primary component c of the nominal content colour volume\n     */\n    WORD32 ai4_ccv_primaries_x[NUM_SEI_CCV_PRIMARIES];\n\n    /*\n     * specify the normalized y chromaticity coordinates of the colour\n     * primary component c of the nominal content colour volume\n     */\n    WORD32 ai4_ccv_primaries_y[NUM_SEI_CCV_PRIMARIES];\n\n    /*\n     * specifies the normalized minimum luminance value\n     */\n    UWORD32 u4_ccv_min_luminance_value;\n\n    /*\n     * specifies the normalized maximum luminance value\n     */\n    UWORD32 u4_ccv_max_luminance_value;\n\n    /*\n     * specifies the normalized average luminance value\n     */\n    UWORD32 u4_ccv_avg_luminance_value;\n\n}sei_ccv_params_t;\n\nstruct _sei\n{\n    UWORD8 u1_seq_param_set_id;\n    buf_period_t s_buf_period;\n    UWORD8 u1_pic_struct;\n    UWORD16 u2_recovery_frame_cnt;\n    UWORD8 u1_exact_match_flag;\n    UWORD8 u1_broken_link_flag;\n    UWORD8 u1_changing_slice_grp_idc;\n    UWORD8 u1_is_valid;\n\n    /**\n     *  mastering display color volume info present flag\n     */\n    UWORD8 u1_sei_mdcv_params_present_flag;\n\n    /*\n     * MDCV parameters\n     */\n    sei_mdcv_params_t s_sei_mdcv_params;\n\n    /**\n     * content light level info present flag\n     */\n    UWORD8 u1_sei_cll_params_present_flag;\n\n    /*\n     * CLL parameters\n     */\n    sei_cll_params_t s_sei_cll_params;\n\n    /**\n     * ambient viewing environment info present flag\n     */\n    UWORD8 u1_sei_ave_params_present_flag;\n\n    /*\n     * AVE parameters\n     */\n    sei_ave_params_t s_sei_ave_params;\n\n    /**\n     * content color volume info present flag\n     */\n    UWORD8 u1_sei_ccv_params_present_flag;\n\n    /*\n     * CCV parameters\n     */\n    sei_ccv_params_t s_sei_ccv_params;\n\n};\ntypedef struct _sei sei;\n\nWORD32 ih264d_export_sei_mdcv_params(ivd_sei_decode_op_t *ps_sei_decode_op,\n                                     sei *ps_sei, sei *ps_sei_export);\n\nWORD32 ih264d_export_sei_cll_params(ivd_sei_decode_op_t *ps_sei_decode_op,\n                                    sei *ps_sei, sei *ps_sei_export);\n\nWORD32 ih264d_export_sei_ave_params(ivd_sei_decode_op_t *ps_sei_decode_op,\n                                    sei *ps_sei, sei *ps_sei_export);\n\nWORD32 ih264d_export_sei_ccv_params(ivd_sei_decode_op_t *ps_sei_decode_op,\n                                    sei *ps_sei, sei *ps_sei_export);\n\n#endif /* _IH264D_SEI_H_ */\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_structs.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_STRUCTS_H_\n#define _IH264D_STRUCTS_H_\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n\n#include \"ih264d_transfer_address.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_dpb_manager.h\"\n/* includes for CABAC */\n#include \"ih264d_cabac.h\"\n#include \"ih264d_dpb_manager.h\"\n\n#include \"ih264d_vui.h\"\n#include \"ih264d_sei.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n\n#include \"ih264_weighted_pred.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include \"ih264_inter_pred_filters.h\"\n#include \"ih264_mem_fns.h\"\n#include \"ih264_padding.h\"\n#include \"ih264_intra_pred_filters.h\"\n#include \"ih264_deblk_edge_filters.h\"\n\n\n\n\n\n/** Number of Mb's whoose syntax will be read */\n/************************************************************/\n/* MB_GROUP should be a multiple of 2                       */\n/************************************************************/\n#define PARSE_MB_GROUP_4            4\n\n/* MV_SCRATCH_BUFS assumed to be pow(2) */\n#define MV_SCRATCH_BUFS             4\n\n#define TOP_FIELD_ONLY      0x02\n#define BOT_FIELD_ONLY      0x01\n\n#define MAX_REF_BUF_SIZE       (3776*2*2)\n\nstruct _DecStruct;\nstruct _DecMbInfo;\n\ntypedef enum\n{\n    MB_TYPE_SI_SLICE = 0,\n    MB_TYPE_I_SLICE = 3,\n    MB_SKIP_FLAG_P_SLICE = 11,\n    MB_TYPE_P_SLICE = 14,\n    SUB_MB_TYPE_P_SLICE = 21,\n    MB_SKIP_FLAG_B_SLICE = 24,\n    MB_TYPE_B_SLICE = 27,\n    SUB_MB_TYPE_B_SLICE = 36,\n    MVD_X = 40,\n    MVD_Y = 47,\n    REF_IDX = 54,\n    MB_QP_DELTA = 60,\n    INTRA_CHROMA_PRED_MODE = 64,\n    PREV_INTRA4X4_PRED_MODE_FLAG = 68,\n    REM_INTRA4X4_PRED_MODE = 69,\n    MB_FIELD_DECODING_FLAG = 70,\n    CBP_LUMA = 73,\n    CBP_CHROMA = 77,\n    CBF = 85,\n    SIGNIFICANT_COEFF_FLAG_FRAME = 105,\n    SIGNIFICANT_COEFF_FLAG_FLD = 277,\n    LAST_SIGNIFICANT_COEFF_FLAG_FRAME = 166,\n    LAST_SIGNIFICANT_COEFF_FLAG_FLD = 338,\n    COEFF_ABS_LEVEL_MINUS1 = 227,\n\n    /* High profile related Syntax element CABAC offsets */\n    TRANSFORM_SIZE_8X8_FLAG = 399,\n    SIGNIFICANT_COEFF_FLAG_8X8_FRAME = 402,\n    LAST_SIGNIFICANT_COEFF_FLAG_8X8_FRAME = 417,\n    COEFF_ABS_LEVEL_MINUS1_8X8 = 426,\n    SIGNIFICANT_COEFF_FLAG_8X8_FIELD = 436,\n    LAST_SIGNIFICANT_COEFF_FLAG_8X8_FIELD = 451\n\n} cabac_table_num_t;\n\ntypedef enum\n{\n    SIG_COEFF_CTXT_CAT_0_OFFSET = 0,\n    SIG_COEFF_CTXT_CAT_1_OFFSET = 15,\n    SIG_COEFF_CTXT_CAT_2_OFFSET = 29,\n    SIG_COEFF_CTXT_CAT_3_OFFSET = 44,\n    SIG_COEFF_CTXT_CAT_4_OFFSET = 47,\n    SIG_COEFF_CTXT_CAT_5_OFFSET = 0,\n    COEFF_ABS_LEVEL_CAT_0_OFFSET = 0,\n    COEFF_ABS_LEVEL_CAT_1_OFFSET = 10,\n    COEFF_ABS_LEVEL_CAT_2_OFFSET = 20,\n    COEFF_ABS_LEVEL_CAT_3_OFFSET = 30,\n    COEFF_ABS_LEVEL_CAT_4_OFFSET = 39,\n    COEFF_ABS_LEVEL_CAT_5_OFFSET = 0\n} cabac_blk_cat_offset_t;\n\n/** Structure for the MV bank */\ntypedef struct _mv_pred_t\n{\n    WORD16 i2_mv[4]; /** 0- mvFwdX, 1- mvFwdY, 2- mvBwdX, 3- mvBwdY */\n    WORD8 i1_ref_frame[2];\n\n    UWORD8 u1_col_ref_pic_idx; /** Idx into the pic buff array */\n    UWORD8 u1_pic_type; /** Idx into the pic buff array */\n\n} mv_pred_t;\n\ntypedef struct\n{\n    WORD32 i4_mv_indices[16];\n    WORD8 i1_submb_num[16];\n    WORD8 i1_partitionsize[16];\n    WORD8 i1_num_partitions;\n    WORD8 u1_vert_mv_scale;\n    UWORD8 u1_col_zeroflag_change;\n} directmv_t;\n\ntypedef struct pic_buffer_t\n{\n    /**Different components of the picture */\n    UWORD8 *pu1_buf1;\n    UWORD8 *pu1_buf2;\n    UWORD8 *pu1_buf3;\n    UWORD16 u2_disp_width; /** Width of the display luma frame in pixels */\n    UWORD16 u2_disp_height; /** Height of the display luma frame in pixels */\n    UWORD32 u4_time_stamp; /** Time at which frame has to be displayed */\n    UWORD16 u2_frm_wd_y; /** Width of the luma frame in pixels */\n    UWORD16 u2_frm_wd_uv; /** Width of the chroma frame */\n    UWORD16 u2_frm_ht_y; /** Height of the luma frame in pixels */\n    UWORD16 u2_frm_ht_uv; /** Height of the chroma frame */\n    /* Upto this is resembling the structure IH264DEC_DispUnit */\n\n    /* If any member is to be added, add below this            */\n\n    /* u4_ofst from start of picture buffer to display position for Y buffer  */\n    UWORD16 u2_crop_offset_y;\n\n    /* u4_ofst from start of picture buffer to display position for UV buffer */\n    UWORD16 u2_crop_offset_uv;\n\n    UWORD8 u1_is_short; /** (1: short 0: long) term ref pic */\n    UWORD8 u1_pic_type; /** frame / field / complementary field pair */\n    UWORD8 u1_pic_buf_id; /** Idx into the picBufAPI array */\n    UWORD8 u1_mv_buf_id;\n    WORD32 i4_seq;\n    UWORD8 *pu1_col_zero_flag;\n    mv_pred_t *ps_mv; /** Pointer to the MV bank array */\n    WORD32 i4_poc; /** POC */\n    WORD32 i4_pic_num;\n    WORD32 i4_frame_num;\n    WORD32 i4_top_field_order_cnt; /** TopPOC */\n    WORD32 i4_bottom_field_order_cnt; /** BottomPOC */\n    WORD32 i4_avg_poc; /** minPOC */\n    UWORD8 u1_picturetype; /*Same as u1_pic_type..u1_pic_type gets overwritten whereas\n     this doesnot get overwritten ...stores the pictype of\n     frame/complementary field pair/ mbaff */\n    UWORD8 u1_long_term_frm_idx;\n    UWORD8 u1_long_term_pic_num;\n    UWORD32 u4_pack_slc_typ; /* It will contain information about types of slices */\n\n    /* ! */\n    UWORD32 u4_ts;\n    UWORD8 u1_pic_struct;/* Refer to SEI table D-1 */\n    sei s_sei_pic;\n\n} pic_buffer_t;\n\ntypedef struct\n{\n    void *u4_add[4];\n} neighbouradd_t;\n\ntypedef struct\n{\n    const UWORD8 *pu1_inv_scan;\n    void *pv_table[6];\n} cavlc_cntxt_t;\n\n/**\n ************************************************************************\n * \\file ih264d_structs.h\n *\n * \\brief\n *    Structures used in the H.264 decoder\n *\n * \\date\n *    18/11/2002\n *\n * \\author  Sriram Sethuraman\n *\n ************************************************************************\n */\n\n/**\n * Structure to represent a MV Bank buffer and col flag\n */\ntypedef struct\n{\n    /**\n     *  Pointer to buffer that holds col flag.\n     */\n    void *pv_col_zero_flag;\n\n    /**\n     * Pointer to buffer that holds mv_pred\n     */\n    void *pv_mv;\n\n }col_mv_buf_t;\n\n\ntypedef struct\n{\n    UWORD8 u1_dydx; /** 4*dy + dx for Y comp / 8*dy + dx for UV comp */\n    UWORD8 u1_is_bi_direct; /** 1: is bi-direct 0: forward / backward only   */\n    UWORD8 u1_wght_pred_type; /** 0-default 1-singleWeighted 2-BiWeighted      */\n    WORD8 i1_mb_partwidth; /** Width of MB partition                        */\n    WORD8 i1_mb_partheight; /** Height of MB partition                       */\n    WORD8 i1_mc_wd; /** Number of bytes in a DMA stride              */\n    WORD8 i1_dma_ht; /** Number of strides                            */\n\n    WORD8 i1_pod_ht; /** Flag specifying height of pad on demand      */\n    /** 0 (No pod) -ve(Top pod) +ve(Bottom pod)      */\n    UWORD16 u2_dst_stride; /** Stride value of the destination              */\n    UWORD16 u2_u1_ref_buf_wd; /** Width of the ref buffer                      */\n    UWORD16 u2_frm_wd;\n    UWORD16 u2_dummy;\n\n    UWORD8 *u1_pi1_wt_ofst_rec_v; /** Pointer to packed weight and u4_ofst          */\n    UWORD8 *pu1_rec_y_u; /** MB partition address in row buffer           */\n    UWORD8 *pu1_dma_dest_addr; /** Destination address for DMA transfer         */\n    UWORD8 *pu1_y_ref;\n    UWORD8 *pu1_u_ref;\n    UWORD8 *pu1_v_ref;\n\n    UWORD8 *pu1_pred;\n    UWORD8 *pu1_pred_u;\n    UWORD8 *pu1_pred_v;\n    UWORD8 u1_dma_wd_y;\n    UWORD8 u1_dma_ht_y;\n    UWORD8 u1_dma_wd_uv;\n    UWORD8 u1_dma_ht_uv;\n} pred_info_t;\n\ntypedef struct\n{\n    UWORD32 *pu4_wt_offst;\n    WORD16 i2_mv[2];\n\n    /***************************************************/\n    /*packing information  i1_size_pos_info             */\n    /* bit 1:0 -> X position in terms of  (4x4) units   */\n    /* bit 3:2 -> Y position in terms of  (4x4) units   */\n    /* bit 5:4 -> PU width 0:4,1:8,2:16                 */\n    /* bit 7:6 -> PU height 0:4,1:8,2:16                */\n     /***************************************************/\n    WORD8 i1_size_pos_info;\n\n    /***************************************************/\n    /*packing information ref idx info                 */\n    /* bit 5:0 ->ref_idx                              */\n    /* bit 6:7   -> 0:l0,1:l1,2:bipred                  */\n     /***************************************************/\n    WORD8 i1_ref_idx_info;\n\n    WORD8 i1_buf_id;\n\n\n    UWORD8 u1_pic_type; /** frame /top field/bottom field/mbaff / complementary field pair */\n\n}pred_info_pkd_t;\n/*! Sequence level parameters */\n\ntypedef struct\n{\n    UWORD8 u1_seq_parameter_set_id; /** id for the seq par set 0-31 */\n    UWORD8 u1_is_valid; /** is Seq Param set valid */\n\n    UWORD16 u2_frm_wd_in_mbs; /** Frame width expressed in MB units */\n    UWORD16 u2_frm_ht_in_mbs; /** Frame height expressed in MB units */\n\n    /* Following are derived from the above two */\n    UWORD16 u2_fld_ht_in_mbs; /** Field height expressed in MB units */\n    UWORD16 u2_max_mb_addr; /** Total number of macroblocks in a coded picture */\n    UWORD16 u2_total_num_of_mbs; /** Total number of macroblocks in a coded picture */\n    UWORD32 u4_fld_ht; /** field height */\n    UWORD32 u4_cwidth; /** chroma width */\n    UWORD32 u4_chr_frm_ht; /** chroma height */\n    UWORD32 u4_chr_fld_ht; /** chroma field height */\n    UWORD8 u1_mb_aff_flag; /** 0 - no mb_aff; 1 - uses mb_aff */\n\n    UWORD8 u1_profile_idc; /** profile value */\n    UWORD8 u1_level_idc; /** level value */\n\n    /* high profile related syntax elements   */\n    WORD32 i4_chroma_format_idc;\n    WORD32 i4_bit_depth_luma_minus8;\n    WORD32 i4_bit_depth_chroma_minus8;\n    WORD32 i4_qpprime_y_zero_transform_bypass_flag;\n    WORD32 i4_seq_scaling_matrix_present_flag;\n    UWORD8 u1_seq_scaling_list_present_flag[8];\n    UWORD8 u1_use_default_scaling_matrix_flag[8];\n    WORD16 i2_scalinglist4x4[6][16];\n    WORD16 i2_scalinglist8x8[2][64];\n    UWORD8 u1_more_than_one_slice_group_allowed_flag;\n    UWORD8 u1_arbitrary_slice_order_allowed_flag;\n    UWORD8 u1_redundant_slices_allowed_flag;\n    UWORD8 u1_bits_in_frm_num; /** Number of bits in frame num */\n    UWORD16 u2_u4_max_pic_num_minus1; /** Maximum frame num minus 1 */\n    UWORD8 u1_pic_order_cnt_type; /** 0 - 2 indicates the method to code picture order count */\n    UWORD8 u1_log2_max_pic_order_cnt_lsb_minus;\n    WORD32 i4_max_pic_order_cntLsb;\n    UWORD8 u1_num_ref_frames_in_pic_order_cnt_cycle;\n    UWORD8 u1_delta_pic_order_always_zero_flag;\n    WORD32 i4_ofst_for_non_ref_pic;\n    WORD32 i4_ofst_for_top_to_bottom_field;\n    WORD32 i4_ofst_for_ref_frame[MAX_NUM_REF_FRAMES_OFFSET];\n    UWORD8 u1_num_ref_frames;\n    UWORD8 u1_gaps_in_frame_num_value_allowed_flag;\n    UWORD8 u1_frame_mbs_only_flag; /** 1 - frame only; 0 - field/frame pic */\n    UWORD8 u1_direct_8x8_inference_flag;\n    UWORD8 u1_vui_parameters_present_flag;\n    vui_t s_vui;\n} dec_seq_params_t;\n\ntypedef struct\n{\n    UWORD16 u2_frm_wd_in_mbs; /** Frame width expressed in MB units    */\n    UWORD16 u2_frm_ht_in_mbs; /** Frame height expressed in MB units   */\n    UWORD8 u1_frame_mbs_only_flag; /** 1 - frame only; 0 - field/frame pic  */\n    UWORD8 u1_profile_idc; /** profile value                        */\n    UWORD8 u1_level_idc; /** level value                          */\n    UWORD8 u1_direct_8x8_inference_flag;\n    UWORD8 u1_eoseq_pending;\n} prev_seq_params_t;\n\n/** Picture level parameters */\ntypedef struct\n{\n    dec_seq_params_t *ps_sps; /** applicable seq. parameter set */\n\n    /* High profile related syntax elements */\n    WORD32 i4_transform_8x8_mode_flag;\n    WORD32 i4_pic_scaling_matrix_present_flag;\n    UWORD8 u1_pic_scaling_list_present_flag[8];\n    UWORD8 u1_pic_use_default_scaling_matrix_flag[8];\n    WORD16 i2_pic_scalinglist4x4[6][16];\n    WORD16 i2_pic_scalinglist8x8[2][64];\n    WORD8 i1_second_chroma_qp_index_offset;\n\n    UWORD32 u4_slice_group_change_rate;\n    UWORD8 *pu1_slice_groupmb_map; /** MB map with slice membership labels */\n    UWORD8 u1_pic_parameter_set_id; /** id for the picture par set 0-255*/\n    UWORD8 u1_entropy_coding_mode; /** Entropy coding : 0-VLC; 1 - CABAC */\n    UWORD8 u1_num_slice_groups; /** Number of slice groups */\n    UWORD8 u1_pic_init_qp; /** Initial QPY for the picture {-26,25}*/\n    WORD8 i1_chroma_qp_index_offset; /** Chroma QP u4_ofst w.r.t QPY {-12,12} */\n    UWORD8 u1_dblk_filter_parms_flag; /** Slice layer has deblocking filter parameters */\n    UWORD8 u1_constrained_intra_pred_flag; /** Constrained intra prediction u4_flag */\n    UWORD8 u1_redundant_pic_cnt_present_flag; /** Redundant_pic_cnt is in slices using this PPS */\n    UWORD8 u1_pic_order_present_flag; /** Pic order present u4_flag */\n    UWORD8 u1_num_ref_idx_lx_active[2]; /** Maximum reference picture index in the reference list 0 : range [1 - 15] */\n    UWORD8 u1_wted_pred_flag;\n    UWORD8 u1_wted_bipred_idc;\n    UWORD8 u1_pic_init_qs;\n    UWORD8 u1_deblocking_filter_parameters_present_flag;\n    UWORD8 u1_vui_pic_parameters_flag;\n    UWORD8 u1_mb_slice_group_map_type;\n    UWORD8 u1_slice_group_change_direction_flag;\n    UWORD8 u1_frame_cropping_flag;\n    UWORD8 u1_frame_cropping_rect_left_ofst;\n    UWORD8 u1_frame_cropping_rect_right_ofst;\n    UWORD8 u1_frame_cropping_rect_top_ofst;\n    UWORD8 u1_frame_cropping_rect_bottom_ofst;\n    void * pv_codec_handle; /* For Error Handling */\n    WORD32 i4_top_field_order_cnt;\n    WORD32 i4_bottom_field_order_cnt;\n    WORD32 i4_avg_poc;\n    UWORD8 u1_is_valid; /** is Pic Param set valid */\n} dec_pic_params_t;\n\n/** Picture Order Count Paramsters */\ntypedef struct\n{\n    WORD32 i4_pic_order_cnt_lsb;\n    WORD32 i4_pic_order_cnt_msb;\n    WORD32 i4_delta_pic_order_cnt_bottom;\n    WORD32 i4_delta_pic_order_cnt[2];\n    WORD32 i4_prev_frame_num_ofst;\n    UWORD8 u1_mmco_equalto5;\n    UWORD8 u1_bot_field;\n    UWORD16 u2_frame_num;\n    WORD32 i4_top_field_order_count;\n    WORD32 i4_bottom_field_order_count;\n} pocstruct_t;\n\n/*****************************************************************************/\n/* parse_mb_pers_info contains necessary mb info data required persistently  */\n/* in the form of top and left neighbours.                                   */\n/*****************************************************************************/\ntypedef struct\n{\n    void *u4_pic_addrress[4]; /* picture address for BS calc */\n    WORD8 pi1_intrapredmodes[4]; /* calc Intra pred modes */\n    UWORD8 pu1_nnz_y[4];\n    UWORD8 pu1_nnz_uv[4];\n    UWORD8 u1_mb_fld;\n    UWORD8 u1_mb_type;\n    UWORD16 u2_luma_csbp; /* Luma csbp used for BS calc */\n    UWORD8 u1_tran_form8x8;\n} mb_neigbour_params_t;\n\n/* This info is required for decoding purposes except Deblockng */\ntypedef struct _DecMbInfo\n{\n    UWORD8 u1_mb_type; /** macroblock type: I/P/B/SI/SP */\n    UWORD8 u1_chroma_pred_mode;\n    UWORD8 u1_cbp;\n    UWORD8 u1_mb_mc_mode; /** 16x16, 2 16x8, 2 8x16, 4 8x8 */\n    UWORD8 u1_topmb; /** top Mb u4_flag */\n    UWORD8 u1_mb_ngbr_availablity;\n    UWORD8 u1_end_of_slice;\n    UWORD8 u1_mb_field_decodingflag;\n    UWORD8 u1_topleft_mb_fld;\n    UWORD8 u1_topleft_mbtype;\n    WORD8 i1_offset;\n    UWORD8 u1_Mux;\n    UWORD8 u1_qp_div6;\n    UWORD8 u1_qp_rem6;\n    UWORD8 u1_qpc_div6;\n    UWORD8 u1_qpcr_div6;\n    UWORD8 u1_qpc_rem6;\n    UWORD8 u1_qpcr_rem6;\n    UWORD8 u1_tran_form8x8;\n    UWORD8 u1_num_pred_parts;\n    UWORD8 u1_yuv_dc_block_flag;\n    UWORD16 u2_top_right_avail_mask;\n    UWORD16 u2_top_left_avail_mask;\n    UWORD16 u2_luma_csbp; /** Coded 4x4 Sub Block Pattern */\n    UWORD16 u2_chroma_csbp; /** Coded 4x4 Sub Block Pattern */\n    UWORD16 u2_mbx;\n    UWORD16 u2_mby;\n    UWORD16 u2_mask[2];\n\n    UWORD32 u4_pred_info_pkd_idx;\n\n    mb_neigbour_params_t *ps_left_mb;\n    mb_neigbour_params_t *ps_top_mb;\n    mb_neigbour_params_t *ps_top_right_mb;\n    mb_neigbour_params_t *ps_curmb;\n} dec_mb_info_t;\n\n\n/** Slice level parameters */\ntypedef struct\n{\n    dec_pic_params_t *ps_pps; /** PPS used */\n    WORD32 i4_delta_pic_order_cnt[2];\n    WORD32 i4_poc; /** Pic order cnt of picture to which slice belongs*/\n    UWORD32 u4_idr_pic_id; /** IDR pic ID */\n    UWORD16 u2_first_mb_in_slice; /** Address of first MB in slice*/\n    UWORD16 u2_frame_num; /** Frame number from prev IDR pic */\n\n    UWORD8 u1_mbaff_frame_flag; /** Mb adaptive frame field u4_flag */\n    UWORD8 u1_field_pic_flag; /** Field picture or not */\n    UWORD8 u1_bottom_field_flag; /** If slice belongs to bot field pic */\n    UWORD8 u1_slice_type; /** I/P/B/SI/SP */\n    WORD32 i4_pic_order_cnt_lsb; /** Picture Order Count */\n    UWORD8 u1_slice_qp; /** Add slice_qp_delta to pic_init_QP */\n    UWORD8 u1_disable_dblk_filter_idc; /** 0-dblk all edges; 1 - suppress; 2 - suppress only edges */\n    WORD8 i1_slice_alpha_c0_offset; /** dblk: alpha and C0 table u4_ofst {-12,12}*/\n    WORD8 i1_slice_beta_offset; /** dblk: beta table u4_ofst {-12, 12}*/\n    UWORD8 u1_sp_for_switch_flag;\n    UWORD8 u1_no_output_of_prior_pics_flag;\n    UWORD8 u1_long_term_reference_flag;\n    UWORD8 u1_num_ref_idx_lx_active[2];\n    UWORD8 u1_cabac_init_idc; /** cabac_init_idc */\n    UWORD8 u1_num_ref_idx_active_override_flag;\n    UWORD8 u1_direct_spatial_mv_pred_flag;\n    WORD32 (*pf_decodeDirect)(struct _DecStruct *ps_dec,\n                              UWORD8 u1_wd_x,\n                              dec_mb_info_t *ps_cur_mb_info,\n                              UWORD8 u1_mb_num);\n    UWORD8 u1_redundant_pic_cnt;\n    WORD8 i1_slice_qs_delta;\n    UWORD8 u1_nal_ref_idc; /** NAL ref idc of the Slice NAL unit */\n    UWORD8 u1_nal_unit_type; /** NAL unit type of the Slice NAL */\n    UWORD8 u1_direct_8x8_inference_flag;\n    UWORD8 u1_mmco_equalto5; /** any of the MMCO command equal to 5 */\n    UWORD8 u1_pic_order_cnt_type;\n    pocstruct_t s_POC;\n    /* DataStructures required for weighted prediction */\n    UWORD16 u2_log2Y_crwd; /** Packed luma and chroma log2_weight_denom */\n    /* [list0/list1]:[ref pics index]:[0-Y 1-Cb 2-Cr] [weight/u4_ofst],\n     weights and offsets are signed numbers, since they are packed, it is defined\n     unsigned. LSB byte : weight and MSB byte: u4_ofst */\n    UWORD32 u4_wt_ofst_lx[2][MAX_REF_BUFS][3];\n    void * pv_codec_handle; /* For Error Handling */\n\n    /*  This is used when reordering is done in Forward or    */\n    /*  backward lists. This is because reordering can point  */\n    /*  to any valid entry in initial list irrespective of    */\n    /*  num_ref_idx_active which could be overwritten using   */\n    /*  ref_idx_reorder_flag                                  */\n    UWORD8 u1_initial_list_size[2];\n    UWORD32 u4_mbs_in_slice;\n} dec_slice_params_t;\n\n\ntypedef struct\n{\n    UWORD8 u1_mb_type; /* Bit representations, X- reserved */\n    /** |Field/Frame|X|X|X|X|Bslice u4_flag|PRED_NON_16x16 u4_flag |Intra Mbflag| */\n    UWORD8 u1_mb_qp;\n    UWORD8 u1_deblocking_mode; /** dblk: Mode [ NO / NO TOP / NO LEFT] filter */\n    WORD8 i1_slice_alpha_c0_offset; /** dblk: alpha and C0 table u4_ofst {-12,12}*/\n    WORD8 i1_slice_beta_offset; /** dblk: beta table u4_ofst {-12, 12}*/\n    UWORD8 u1_single_call;\n    UWORD8 u1_topmb_qp;\n    UWORD8 u1_left_mb_qp;\n    UWORD32 u4_bs_table[10]; /* Boundary strength */\n\n} deblk_mb_t;\n\ntypedef struct\n{\n    UWORD8 u1_mb_type;\n    UWORD8 u1_mb_qp;\n} deblkmb_neighbour_t;\n\n#define MAX_MV_RESIDUAL_INFO_PER_MB    32\n#define MAX_REFIDX_INFO_PER_MB         4\n#define PART_NOT_DIRECT                0\n#define PART_DIRECT_8x8                1\n#define PART_DIRECT_16x16              2\ntypedef struct\n{\n    UWORD8 u1_is_direct;\n    UWORD8 u1_pred_mode;\n    UWORD8 u1_sub_mb_num;\n    UWORD8 u1_partheight;\n    UWORD8 u1_partwidth;\n} parse_part_params_t;\n\ntypedef struct\n{\n    UWORD8 u1_isI_mb;\n    UWORD8 u1_num_part;\n    UWORD32 *pu4_wt_offst[MAX_REFIDX_INFO_PER_MB];\n    WORD8 i1_ref_idx[2][MAX_REFIDX_INFO_PER_MB];\n    UWORD8 u1_col_info[MAX_REFIDX_INFO_PER_MB];\n} parse_pmbarams_t;\n\ntypedef struct\n{\n    UWORD8 u1_vert_pad_top; /* flip-flop u4_flag remembering pad area (Vert) */\n    UWORD8 u1_vert_pad_bot; /* flip-flop u4_flag remembering pad area (Vert) */\n    UWORD8 u1_horz_pad; /* flip-flop u4_flag remembering pad area (Vert) */\n    UWORD8 u1_pad_len_y_v; /* vertical pad amount for luma               */\n    UWORD8 u1_pad_len_cr_v; /* vertical pad amount for chroma             */\n} pad_mgr_t;\n\n\n#define ACCEPT_ALL_PICS   (0x00)\n#define REJECT_CUR_PIC    (0x01)\n#define REJECT_PB_PICS    (0x02)\n\n#define MASK_REJECT_CUR_PIC (0xFE)\n#define MASK_REJECT_PB_PICS (0xFD)\n\n#define PIC_TYPE_UNKNOWN  (0xFF)\n#define PIC_TYPE_I        (0x00)\n#define SYNC_FRM_DEFAULT  (0xFFFFFFFF)\n#define INIT_FRAME        (0xFFFFFF)\n\ntypedef struct dec_err_status_t\n{\n    UWORD8 u1_cur_pic_type;\n    UWORD8 u1_pic_aud_i;\n    UWORD8 u1_err_flag;\n    UWORD32 u4_frm_sei_sync;\n    UWORD32 u4_cur_frm;\n} dec_err_status_t;\n\n/**************************************************************************/\n/* Structure holds information about all high profile toolsets            */\n/**************************************************************************/\ntypedef struct\n{\n    /*****************************************/\n    /* variables required for scaling        */\n    /*****************************************/\n    UWORD8 u1_scaling_present;\n    WORD16 *pi2_scale_mat[8];\n\n    /*************************************************/\n    /* scaling matrices for frame macroblocks after  */\n    /* inverse scanning                              */\n    /*************************************************/\n    WORD16 i2_scalinglist4x4[6][16];\n    WORD16 i2_scalinglist8x8[2][64];\n\n\n    /*****************************************/\n    /* variables required for transform8x8   */\n    /*****************************************/\n    UWORD8 u1_transform8x8_present;\n    UWORD8 u1_direct_8x8_inference_flag;\n    /* temporary variable to get noSubMbPartSizeLessThan8x8Flag from ih264d_parse_bmb_non_direct_cavlc */\n    UWORD8 u1_no_submb_part_size_lt8x8_flag;\n\n    /* needed for inverse scanning */\n    cavlc_cntxt_t s_cavlc_ctxt;\n\n    /* contexts for the CABAC related parsing */\n    bin_ctxt_model_t *ps_transform8x8_flag;\n    bin_ctxt_model_t *ps_sigcoeff_8x8_frame;\n    bin_ctxt_model_t *ps_last_sigcoeff_8x8_frame;\n    bin_ctxt_model_t *ps_coeff_abs_levelminus1;\n    bin_ctxt_model_t *ps_sigcoeff_8x8_field;\n    bin_ctxt_model_t *ps_last_sigcoeff_8x8_field;\n\n/* variables required for intra8x8 */\n\n/* variables required for handling different Qp for Cb and Cr */\n\n} high_profile_tools_t;\n\ntypedef struct\n{\n    UWORD32 u4_num_bufs; /* Number of buffers in each display frame. 2 for 420SP and 3 for 420P and so on */\n    void *buf[3]; /* Pointers to each of the components */\n    UWORD32 u4_bufsize[3];\n    UWORD32 u4_ofst[3];\n} disp_buf_t;\ntypedef struct _dec_slice_struct\n{\n    volatile UWORD32 u4_first_mb_in_slice;\n    volatile UWORD32 slice_type;\n    volatile UWORD16 u2_log2Y_crwd;\n    volatile void **ppv_map_ref_idx_to_poc;\n    volatile void *pv_tu_coeff_data_start;\n} dec_slice_struct_t;\n\n/**\n * Structure to hold coefficient info for a 4x4 transform\n */\ntypedef struct\n{\n    /**\n     * significant coefficient map\n     */\n    UWORD16 u2_sig_coeff_map;\n\n    /**\n     * holds coefficients\n     */\n    WORD16  ai2_level[16];\n}tu_sblk4x4_coeff_data_t;\n\n/**\n * Structure to hold coefficient info for a 8x8 transform\n */\ntypedef struct\n{\n\n    /**\n     * significant coefficient map\n     */\n    UWORD32 au4_sig_coeff_map[2];\n\n    /**\n     * holds coefficients\n     */\n    WORD16  ai2_level[64];\n}tu_blk8x8_coeff_data_t;\n\n/** Aggregating structure that is globally available */\ntypedef struct _DecStruct\n{\n\n    /* Add below all other static memory allocations and pointers to items\n     that are dynamically allocated once per session */\n    dec_bit_stream_t *ps_bitstrm;\n    dec_seq_params_t *ps_cur_sps;\n    dec_pic_params_t *ps_cur_pps;\n    dec_slice_params_t *ps_cur_slice;\n\n    dec_pic_params_t *ps_pps;\n    dec_seq_params_t *ps_sps;\n    const UWORD16 *pu2_quant_scale_y;\n    const UWORD16 *pu2_quant_scale_u;\n    const UWORD16 *pu2_quant_scale_v;\n    UWORD16 u2_mbx;\n    UWORD16 u2_mby;\n\n    UWORD16 u2_frm_wd_y; /** Width for luma buff */\n    UWORD16 u2_frm_ht_y; /** Height for luma buff */\n    UWORD16 u2_frm_wd_uv; /** Width for chroma buff */\n    UWORD16 u2_frm_ht_uv; /** Height for chroma buff */\n    UWORD16 u2_frm_wd_in_mbs; /** Frame width expressed in MB units */\n    UWORD16 u2_frm_ht_in_mbs; /** Frame height expressed in MB units */\n    WORD32 i4_submb_ofst; /** Offset in subMbs from the top left edge */\n    /* Pointer to colocated Zero frame Image, will be used in B_DIRECT mode */\n    /* colZeroFlag | // 0th bit\n     field_flag  | // 1st bit\n     XX          | // 2:3 bit don't cares\n     subMbMode   | // 4:5 bit\n     MbMode      | // 6:7 bit */\n\n    UWORD8 *pu1_col_zero_flag;\n\n    UWORD16 u2_pic_wd; /** Width of the picture being decoded */\n    UWORD16 u2_pic_ht; /** Height of the picture being decoded */\n\n    UWORD8 u1_first_slice_in_stream;\n    UWORD8 u1_mb_ngbr_availablity;\n    UWORD8 u1_ref_idxl0_active_minus1;\n    UWORD8 u1_qp;\n    UWORD8 u1_qp_y_div6;\n    UWORD8 u1_qp_u_div6;\n    UWORD8 u1_qp_y_rem6;\n    UWORD8 u1_qp_u_rem6;\n\n    /*********************************/\n    /* configurable mb-group numbers */\n    /* very critical to the decoder  */\n    /*********************************/\n    /************************************************************/\n    /* MB_GROUP should be a multiple of 2                       */\n    /************************************************************/\n    UWORD8 u1_recon_mb_grp;\n    UWORD8 u1_recon_mb_grp_pair;\n    /* Variables to handle Cabac */\n    decoding_envirnoment_t s_cab_dec_env; /* < Structure for decoding_envirnoment_t */\n    /* These things need to be updated at each MbLevel */\n    WORD8 i1_next_ctxt_idx; /* < next Ctxt Index */\n    UWORD8 u1_currB_type;\n    WORD8 i1_prev_mb_qp_delta; /* Prev MbQpDelta */\n    UWORD8 u1_nal_unit_type;\n\n    ctxt_inc_mb_info_t *p_ctxt_inc_mb_map; /* Pointer to ctxt_inc_mb_info_t map */\n    ctxt_inc_mb_info_t *p_left_ctxt_mb_info; /* Pointer to left ctxt_inc_mb_info_t */\n    ctxt_inc_mb_info_t *p_top_ctxt_mb_info; /* Pointer to top ctxt_inc_mb_info_t */\n    ctxt_inc_mb_info_t *ps_curr_ctxt_mb_info; /* Pointer to current ctxt_inc_mb_info_t */\n    ctxt_inc_mb_info_t *ps_def_ctxt_mb_info; /* Pointer to default ctxt_inc_mb_info_t */\n\n    /* mv contexts for mv decoding using cabac */\n    //UWORD8   u1_top_mv_ctxt_inc[4][4];\n    /* Dimensions for u1_left_mv_ctxt_inc_arr is [2][4][4] for Mbaff case */\n    UWORD8 u1_left_mv_ctxt_inc_arr[2][4][4];\n    UWORD8 (*pu1_left_mv_ctxt_inc)[4];\n\n    UWORD8 u1_sub_mb_num;\n    UWORD8 u1_B; /** if B slice u1_B = 1 else 0 */\n    WORD16 i2_only_backwarddma_info_idx;\n    mv_pred_t *ps_mv; /** Pointer to the MV bank array */\n    mv_pred_t *ps_mv_bank_cur; /** Pointer to the MV bank array */\n    mv_pred_t s_default_mv_pred; /** Structure containing the default values\n     for MV predictor */\n\n    pred_info_t *ps_pred; /** Stores info to cfg MC */\n    pred_info_t *ps_pred_start;\n\n    UWORD32 u4_pred_info_idx;\n    pred_info_pkd_t *ps_pred_pkd;\n    pred_info_pkd_t *ps_pred_pkd_start;\n    UWORD32 u4_pred_info_pkd_idx;\n    UWORD8 *pu1_ref_buff; /** Destination buffer for DMAs */\n    UWORD32 u4_dma_buf_idx;\n\n    UWORD8 *pu1_y;\n    UWORD8 *pu1_u;\n    UWORD8 *pu1_v;\n\n    WORD16 *pi2_y_coeff;\n    UWORD8 *pu1_inv_scan;\n\n    /**\n     * Pointer frame level TU subblock coeff data\n     */\n    void *pv_pic_tu_coeff_data;\n\n    /**\n     * Pointer to TU subblock coeff data and number of subblocks and scan idx\n     * Incremented each time a coded subblock is processed\n     *\n     */\n    void *pv_parse_tu_coeff_data;\n    void *pv_prev_mb_parse_tu_coeff_data;\n\n    void *pv_proc_tu_coeff_data;\n\n    WORD16 *pi2_coeff_data;\n\n    cavlc_cntxt_t s_cavlc_ctxt;\n\n    UWORD32 u4_n_leftY[2];\n    UWORD32 u4_n_left_cr[2];\n    UWORD32 u4_n_left_temp_y;\n\n    UWORD8 pu1_left_nnz_y[4];\n    UWORD8 pu1_left_nnz_uv[4];\n    UWORD32 u4_n_left_temp_uv;\n    /***************************************************************************/\n    /*          Base pointer to all the cabac contexts                         */\n    /***************************************************************************/\n    bin_ctxt_model_t *p_cabac_ctxt_table_t;\n\n    /***************************************************************************/\n    /* cabac context pointers for every SE mapped into in p_cabac_ctxt_table_t */\n    /***************************************************************************/\n    bin_ctxt_model_t *p_mb_type_t;\n    bin_ctxt_model_t *p_mb_skip_flag_t;\n    bin_ctxt_model_t *p_sub_mb_type_t;\n    bin_ctxt_model_t *p_mvd_x_t;\n    bin_ctxt_model_t *p_mvd_y_t;\n    bin_ctxt_model_t *p_ref_idx_t;\n    bin_ctxt_model_t *p_mb_qp_delta_t;\n    bin_ctxt_model_t *p_intra_chroma_pred_mode_t;\n    bin_ctxt_model_t *p_prev_intra4x4_pred_mode_flag_t;\n    bin_ctxt_model_t *p_rem_intra4x4_pred_mode_t;\n    bin_ctxt_model_t *p_mb_field_dec_flag_t;\n    bin_ctxt_model_t *p_cbp_luma_t;\n    bin_ctxt_model_t *p_cbp_chroma_t;\n    bin_ctxt_model_t *p_cbf_t[NUM_CTX_CAT];\n    bin_ctxt_model_t *p_significant_coeff_flag_t[NUM_CTX_CAT];\n    bin_ctxt_model_t *p_coeff_abs_level_minus1_t[NUM_CTX_CAT];\n\n    UWORD32 u4_num_pmbair; /** MB pair number */\n    mv_pred_t *ps_mv_left; /** Pointer to left motion vector bank */\n    mv_pred_t *ps_mv_top_left; /** Pointer to top left motion vector bank */\n    mv_pred_t *ps_mv_top_right; /** Pointer to top right motion vector bank */\n\n    UWORD8 *pu1_left_yuv_dc_csbp;\n\n\n    deblkmb_neighbour_t deblk_left_mb[2];\n    deblkmb_neighbour_t *ps_deblk_top_mb;\n    neighbouradd_t (*ps_left_mvpred_addr)[2]; /* Left MvPred Address Ping Pong*/\n\n    /***************************************************************************/\n    /*       Ref_idx contexts  are stored in the following way                 */\n    /*  Array Idx 0,1 for reference indices in Forward direction               */\n    /*  Array Idx 2,3 for reference indices in backward direction              */\n    /***************************************************************************/\n\n    /* Dimensions for u1_left_ref_ctxt_inc_arr is [2][4] for Mbaff:Top and Bot */\n    WORD8 i1_left_ref_idx_ctx_inc_arr[2][4];\n    WORD8 *pi1_left_ref_idx_ctxt_inc;\n\n    /*************************************************************************/\n    /*               Arrangnment of DC CSBP                                  */\n    /*        bits:  b7  b6  b5  b4  b3  b2  b1  b0                          */\n    /*        CSBP:   x   x   x   x   x  Vdc Udc Ydc                         */\n    /*************************************************************************/\n    /*************************************************************************/\n    /*  Points either to u1_yuv_dc_csbp_topmb or  u1_yuv_dc_csbp_bot_mb     */\n    /*************************************************************************/\n    UWORD8 u1_yuv_dc_csbp_topmb;\n    UWORD8 u1_yuv_dc_csbp_bot_mb;\n\n    /* DMA SETUP */\n    tfr_ctxt_t s_tran_addrecon_parse;\n    tfr_ctxt_t s_tran_addrecon;\n    tfr_ctxt_t s_tran_iprecon;\n    tfr_ctxt_t *ps_frame_buf_ip_recon;\n    WORD8 i1_recon_in_thread3_flag;\n\n    /* slice Header Simplification */\n    UWORD8 u1_pr_sl_type;\n    WORD32 i4_frametype;\n    UWORD32 u4_app_disp_width;\n    WORD32 i4_error_code;\n    UWORD32 u4_bitoffset;\n\n    /* Variables added to handle field pics */\n\n    UWORD8 u1_second_field;\n    WORD32 i4_pic_type;\n    WORD32 i4_content_type;\n    WORD32 i4_decode_header;\n    WORD32 i4_header_decoded;\n    UWORD32 u4_total_frames_decoded;\n\n    ctxt_inc_mb_info_t *ps_left_mb_ctxt_info; /* structure containing the left MB's\n     context info, incase of Mbaff */\n    pocstruct_t s_prev_pic_poc;\n    pocstruct_t s_cur_pic_poc;\n    WORD32 i4_cur_display_seq;\n    WORD32 i4_prev_max_display_seq;\n    WORD32 i4_max_poc;\n    deblk_mb_t *ps_cur_deblk_mb;\n\n    /* Pointers to local scratch buffers */\n    deblk_mb_t *ps_deblk_pic;\n\n    /* Pointers to Picture Buffers (Given by BufAPI Lib) */\n    struct pic_buffer_t *ps_cur_pic; /** Pointer to Current picture buffer */\n\n    /* Scratch Picture Buffers (Given by BufAPI Lib) */\n    struct pic_buffer_t s_cur_pic;\n\n    /* Current Slice related information */\n    volatile UWORD16 u2_cur_slice_num;\n    volatile UWORD16 u2_cur_slice_num_dec_thread;\n\n    /* Variables needed for Buffer API handling */\n    UWORD8 u1_nal_buf_id;\n    UWORD8 u1_pic_buf_id;\n    UWORD8 u1_pic_bufs;\n\n    WORD16 *pi2_pred1; //[441];  /** Temp predictor buffer for MC */\n    /* Pointer to refernce Pic buffers list, 0:fwd, 1:bwd */\n    pic_buffer_t **ps_ref_pic_buf_lx[2];\n    /* refIdx to POC mapping */\n    void **ppv_map_ref_idx_to_poc;\n    void **ppv_map_ref_idx_to_poc_base;\n    UWORD32 *pu4_wts_ofsts_mat;\n    UWORD32 *pu4_wt_ofsts;\n    UWORD32 *pu4_mbaff_wt_mat;\n    /* Function pointers to read Params common to CAVLC and CABAC */\n    WORD32 (*pf_parse_inter_mb)(struct _DecStruct * ps_dec,\n                                dec_mb_info_t * ps_cur_mb_info,\n                                UWORD8 u1_mb_num,\n                                UWORD8 u1_num_mbsNby2);\n    WORD32 (*pf_mvpred_ref_tfr_nby2mb)(struct _DecStruct * ps_dec,\n                                     UWORD8 u1_num_mbs,\n                                     UWORD8 u1_num_mbsNby2);\n\n    WORD32 (*pf_parse_inter_slice)(struct _DecStruct * ps_dec,\n                                   dec_slice_params_t * ps_slice,\n                                   UWORD16 u2_first_mb_in_slice);\n\n    UWORD32 (*pf_get_mb_info)(struct _DecStruct * ps_dec,\n                              const UWORD16 u2_cur_mb_address,\n                              dec_mb_info_t * ps_cur_mb_info,\n                              UWORD32 u4_mbskip_run);\n\n    /* Variables for Decode Buffer Management */\n    dpb_manager_t *ps_dpb_mgr;\n    dpb_commands_t *ps_dpb_cmds;\n    dpb_commands_t s_dpb_cmds_scratch;\n\n    /* Variables Required for N MB design */\n    dec_mb_info_t *ps_nmb_info;\n\n    UWORD8 *pu1_y_intra_pred_line;\n    UWORD8 *pu1_u_intra_pred_line;\n    UWORD8 *pu1_v_intra_pred_line;\n\n    UWORD8 *pu1_cur_y_intra_pred_line;\n    UWORD8 *pu1_cur_u_intra_pred_line;\n    UWORD8 *pu1_cur_v_intra_pred_line;\n\n    UWORD8 *pu1_cur_y_intra_pred_line_base;\n    UWORD8 *pu1_cur_u_intra_pred_line_base;\n    UWORD8 *pu1_cur_v_intra_pred_line_base;\n\n    UWORD8 *pu1_prev_y_intra_pred_line;\n    UWORD8 *pu1_prev_u_intra_pred_line;\n    UWORD8 *pu1_prev_v_intra_pred_line;\n\n    UWORD32 u4_intra_pred_line_ofst;\n\n    UWORD8 u1_res_changed;\n\n    mv_pred_t *ps_mv_cur; /** pointer to current motion vector bank */\n    mv_pred_t *ps_mv_top; /** pointer to top motion vector bank */\n    mv_pred_t *ps_mv_top_right2;/** Pointer to top right motion vector bank */\n    mv_pred_t *ps_mv_p[2]; /** Scratch ping motion vector bank */\n    mv_pred_t *ps_mv_top_p[MV_SCRATCH_BUFS]; /** Scratch top pong motion vector bank */\n    UWORD8 u1_mv_top_p;\n\n    deblk_mb_t *ps_deblk_mbn;\n\n    UWORD8 *pu1_temp_mc_buffer;\n\n    struct _sei *ps_sei;\n    struct _sei *ps_sei_parse;\n    struct _sei s_sei_export;\n\n    void *pv_disp_sei_params;\n\n    UWORD8 u1_pic_struct_copy;\n    /* Variables required for cropping */\n    UWORD16 u2_disp_width;\n    UWORD16 u2_disp_height;\n    UWORD16 u2_crop_offset_y;\n    UWORD16 u2_crop_offset_uv;\n\n    /* Crop info from SPS */\n\tUWORD8 u1_frame_cropping_flag;\n\tUWORD8 u1_frame_cropping_rect_left_ofst;\n\tUWORD8 u1_frame_cropping_rect_right_ofst;\n\tUWORD8 u1_frame_cropping_rect_top_ofst;\n\tUWORD8 u1_frame_cropping_rect_bottom_ofst;\n\n    /* Variable required to get presentation time stamp through application */\n    UWORD32 u4_pts;\n\n    /* Variables used for gaps in frame number */\n    UWORD16 u2_prev_ref_frame_num;\n\n    UWORD8 u1_mb_idx;\n    struct pic_buffer_t *ps_col_pic;\n    void (*pf_parse_mvdirect)(struct _DecStruct*,\n                           struct pic_buffer_t*,\n                           directmv_t*,\n                           UWORD8,\n                           WORD32,\n                           dec_mb_info_t *);\n    void *pv_dec_out;\n    void *pv_dec_in;\n    void *pv_scratch_sps_pps; /*used temeporarily store sps/ spps while parsing*/\n\n    /* state pointers to mb and partition information */\n    parse_pmbarams_t *ps_parse_mb_data;\n    parse_part_params_t *ps_parse_part_params;\n\n    /* scratch pointers to mb and partition information */\n    parse_part_params_t *ps_part;\n\n    UWORD8 u1_max_dec_frame_buffering;\n    pad_mgr_t s_pad_mgr;\n    UWORD8 (*pf_mvpred)(struct _DecStruct *ps_dec,\n                        struct _DecMbInfo *ps_cur_mb_info,\n                        mv_pred_t *ps_mv_pred,\n                        mv_pred_t *ps_mv_nmb,\n                        mv_pred_t *ps_mv_ntop,\n                        UWORD8 u1_sub_mb_num,\n                        UWORD8 uc_mb_part_width,\n                        UWORD8 uc_lxstart,\n                        UWORD8 uc_lxend,\n                        UWORD8 u1_mb_mc_mode);\n    void (*pf_compute_bs)(struct _DecStruct * ps_dec,\n                         struct _DecMbInfo * ps_cur_mb_info,\n                         const UWORD16 u2_mbxn_mb);\n    UWORD8 u1_init_dec_flag;\n    WORD32 i4_reorder_depth;\n    prev_seq_params_t s_prev_seq_params;\n    UWORD8 u1_cur_mb_fld_dec_flag; /* current Mb fld or Frm */\n\n    UWORD8 u1_topleft_mb_fld;\n    UWORD8 u1_topleft_mbtype;\n    UWORD8 u1_topleft_mb_fld_bot;\n    UWORD8 u1_topleft_mbtype_bot;\n    WORD16 i2_prev_slice_mbx;\n    WORD16 i2_prev_slice_mby;\n    UWORD16 u2_top_left_mask;\n    UWORD16 u2_top_right_mask;\n    dec_err_status_t * ps_dec_err_status;\n    /* Ensure pi1_left_pred_mode is aligned to 4 byte boundary,\n    by declaring this after a pointer or an integer */\n    WORD8 pi1_left_pred_mode[8];\n\n    UWORD8 u1_mb_idx_mv;\n    UWORD16 u2_mv_2mb[2];\n    UWORD32 u4_skip_frm_mask;\n\n    /* variable for finding the no.of mbs decoded in the current picture */\n    UWORD16 u2_total_mbs_coded;\n    /* member added for supporting fragmented annex - B */\n//  frg_annex_read_t s_frag_annex_read;\n    /* added for vui_t, sei support*/\n    WORD32 i4_vui_frame_rate;\n    /* To Store the value of ref_idx_active for previous slice */\n    /* useful in error handling                                */\n    UWORD8 u1_num_ref_idx_lx_active_prev;\n    /* Flag added to come out of process call in annex-b if&if frame is decoded */\n    /* presence of access unit delimters and pps and sps                        */\n    UWORD8 u1_frame_decoded_flag;\n\n    /* To keep track of whether the last picture was decoded or not */\n    /* in case of skip mode set by the application                  */\n    UWORD8 u1_last_pic_not_decoded;\n\n    WORD32 e_dec_status;\n    UWORD32 u4_num_fld_in_frm;\n\n    /* Function pointer for 4x4 residual cavlc parsing based on total coeff */\n    WORD32 (*pf_cavlc_4x4res_block[3])(UWORD32 u4_isdc,\n                                    UWORD32 u4_total_coeff_trail_one, /**TotalCoefficients<<16+trailingones*/\n                                    dec_bit_stream_t *ps_bitstrm);\n\n    /* Function pointer array for interpolate functions in called from motion compensattion module */\n    void (*p_mc_interpolate_x_y[16][3])(UWORD8*,\n                                        UWORD8*,\n                                        UWORD8*,\n                                        UWORD8,\n                                        UWORD16,\n                                        UWORD16,\n                                        UWORD8);\n\n    /**************************************************************************/\n    /* Function pointer for 4x4 totalcoeff, trlone and residual cavlc parsing */\n    /* based on u4_n (neigbourinng nnz average)                               */\n    /* These point to two functions depending on (u4_n > 7) and (u4_n <= 7)   */\n    /**************************************************************************/\n    WORD32 (*pf_cavlc_parse4x4coeff[2])(WORD16 *pi2_coeff_block,\n                                        UWORD32 u4_isdc, /* is it a DC block */\n                                        WORD32 u4_n,\n                                        struct _DecStruct *ps_dec, /** Decoder Parameters */\n                                        UWORD32 *pu4_total_coeff);\n\n    /**************************************************************************/\n    /* Function pointer for luma 8x8block cavlc parsing based on top and left */\n    /* neigbour availability.                                                 */\n    /**************************************************************************/\n    WORD32 (*pf_cavlc_parse_8x8block[4])(WORD16 *pi2_coeff_block,\n                                         UWORD32 u4_sub_block_strd,\n                                         UWORD32 u4_isdc,\n                                         struct _DecStruct *ps_dec,\n                                         UWORD8 *pu1_top_nnz,\n                                         UWORD8 *pu1_left_nnz,\n                                         UWORD8 u1_tran_form8x8,\n                                         UWORD8 u1_mb_field_decodingflag,\n                                         UWORD32 *pu4_csbp);\n\n    /**************************************************************************/\n    /* Ping pong top and current rows of mb neigbour_params                   */\n    /**************************************************************************/\n    mb_neigbour_params_t *ps_nbr_mb_row;\n    mb_neigbour_params_t *ps_cur_mb_row;\n    mb_neigbour_params_t *ps_top_mb_row;\n\n    /**************************************************************************/\n    /* Function pointer for 16x16 and non16x16 Bs1 calculations depending on   */\n    /* P and B slice.                                                          */\n    /***************************************************************************/\n    void (*pf_fill_bs1[2][2])(mv_pred_t *ps_cur_mv_pred,\n                              mv_pred_t *ps_top_mv_pred,\n                              void **ppv_map_ref_idx_to_poc,\n                              UWORD32 *pu4_bs_table, /* pointer to the BsTable array */\n                              mv_pred_t *ps_leftmost_mv_pred,\n                              neighbouradd_t *ps_left_addr,\n                              void **u4_pic_addrress,\n                              WORD32 i4_ver_mvlimit);\n\n    void (*pf_fill_bs_xtra_left_edge[2])(UWORD32 *pu4_bs, /* Base pointer of BS table */\n                                         WORD32 u4_left_mb_t_csbp, /* left mbpair's top csbp   */\n                                         WORD32 u4_left_mb_b_csbp, /* left mbpair's bottom csbp*/\n                                         WORD32 u4_cur_mb_csbp, /* csbp of current mb */\n                                         UWORD32 u4_cur_mb_bot /* is top or bottom mb */\n\n                                         );\n    /* Function pointer array for BP and MP functions for MC*/\n    void (*p_motion_compensate)(struct _DecStruct * ps_dec,\n                               dec_mb_info_t *ps_cur_mb_info);\n\n\n    void (*p_mc_dec_thread)(struct _DecStruct * ps_dec, dec_mb_info_t *ps_cur_mb_info);\n\n    /* Function pointer array for BP and MP functions for formMbPartInfo*/\n\n    WORD32 (*p_form_mb_part_info)(pred_info_pkd_t *ps_pred_pkd,\n                                struct _DecStruct * ps_dec,\n                                     UWORD16 u2_mb_x,\n                                     UWORD16 u2_mb_y,\n                                     WORD32 mb_index,\n                                     dec_mb_info_t *ps_cur_mb_info);\n\n    WORD32 (*p_form_mb_part_info_thread)(pred_info_pkd_t *ps_pred_pkd,\n                                struct _DecStruct * ps_dec,\n                                     UWORD16 u2_mb_x,\n                                     UWORD16 u2_mb_y,\n                                     WORD32 mb_index,\n                                     dec_mb_info_t *ps_cur_mb_info);\n\n\n    /* Required for cabac mbaff bottom mb */\n    UWORD32 u4_next_mb_skip;\n\n    void (*p_DeblockPicture[2])(struct _DecStruct *);\n\n    /* ! */\n    UWORD32 u4_ts;\n    UWORD8 u1_flushfrm;\n\n    /* Output format sent by the application */\n    UWORD8 u1_chroma_format;\n    UWORD8 u1_pic_decode_done;\n    UWORD8 u1_slice_header_done;\n    WORD32 init_done;\n\n    /******************************************/\n    /* For the high profile related variables */\n    /******************************************/\n    high_profile_tools_t s_high_profile;\n    /* CBCR */\n    UWORD8 u1_qp_v_div6;\n    UWORD8 u1_qp_v_rem6;\n    /*\n     * TO help solve the dangling field case.\n     * Check for the previous frame number and the current frame number.\n     */\n    UWORD16 u2_prv_frame_num;\n    UWORD8 u1_top_bottom_decoded;\n    UWORD8 u1_dangling_field;\n\n    IVD_DISPLAY_FRAME_OUT_MODE_T                e_frm_out_mode;\n\n    UWORD8 *pu1_bits_buf_static;\n    UWORD8 *pu1_bits_buf_dynamic;\n\n    UWORD32 u4_static_bits_buf_size;\n    UWORD32 u4_dynamic_bits_buf_size;\n\n    UWORD32 u4_num_disp_bufs_requested;\n    WORD32 i4_display_delay;\n    UWORD32 u4_slice_start_code_found;\n\n    UWORD32 u4_nmb_deblk;\n    UWORD32 u4_use_intrapred_line_copy;\n    UWORD32 u4_num_mbs_prev_nmb;\n    UWORD32 u4_num_mbs_cur_nmb;\n    UWORD32 u4_app_deblk_disable_level;\n    UWORD32 u4_app_disable_deblk_frm;\n    WORD32 i4_mv_frac_mask;\n\n    disp_buf_t disp_bufs[MAX_DISP_BUFS_NEW];\n    UWORD32 u4_disp_buf_mapping[MAX_DISP_BUFS_NEW];\n    UWORD32 u4_disp_buf_to_be_freed[MAX_DISP_BUFS_NEW];\n    UWORD32 u4_share_disp_buf;\n    UWORD32 u4_num_disp_bufs;\n\n    UWORD32 u4_bs_deblk_thread_created;\n    volatile UWORD32 u4_start_recon_deblk;\n    void *pv_bs_deblk_thread_handle;\n\n    UWORD32 u4_cur_bs_mb_num;\n    UWORD32 u4_bs_cur_slice_num_mbs;\n    UWORD32 u4_cur_deblk_mb_num;\n    UWORD32 u4_sps_cnt_in_process;\n    volatile UWORD16 u2_cur_slice_num_bs;\n\n    UWORD32 u4_deblk_mb_x;\n    UWORD32 u4_deblk_mb_y;\n\n\n\n    iv_yuv_buf_t s_disp_frame_info;\n    UWORD32 u4_fmt_conv_num_rows;\n    UWORD32 u4_fmt_conv_cur_row;\n    ivd_out_bufdesc_t *ps_out_buffer;\n    ivd_get_display_frame_op_t s_disp_op;\n    UWORD32 u4_output_present;\n\n    volatile UWORD16 cur_dec_mb_num;\n    volatile UWORD16 cur_recon_mb_num;\n    volatile UWORD16 u2_cur_mb_addr;\n    WORD16 i2_dec_thread_mb_y;\n    WORD16 i2_recon_thread_mb_y;\n\n    UWORD8 u1_separate_parse;\n    UWORD32 u4_dec_thread_created;\n    void *pv_dec_thread_handle;\n    volatile UWORD8 *pu1_dec_mb_map;\n    volatile UWORD8 *pu1_recon_mb_map;\n    volatile UWORD16 *pu2_slice_num_map;\n    dec_slice_struct_t *ps_dec_slice_buf;\n    void *pv_map_ref_idx_to_poc_buf;\n    dec_mb_info_t *ps_frm_mb_info;\n    volatile dec_slice_struct_t * volatile ps_parse_cur_slice;\n    volatile dec_slice_struct_t * volatile ps_decode_cur_slice;\n    volatile dec_slice_struct_t * volatile ps_computebs_cur_slice;\n    UWORD32 u4_cur_slice_decode_done;\n    UWORD32 u4_extra_mem_used;\n\n    /* 2 first slice not parsed , 1 :first slice parsed , 0 :first valid slice header parsed*/\n    UWORD32 u4_first_slice_in_pic;\n    UWORD32 u4_num_cores;\n    IVD_ARCH_T e_processor_arch;\n    IVD_SOC_T e_processor_soc;\n\n    /**\n     * Pictures that are are degraded\n     * 0 : No degrade\n     * 1 : Only on non-reference frames\n     * 2 : Use interval specified by u4_nondegrade_interval\n     * 3 : All non-key frames\n     * 4 : All frames\n     */\n    WORD32 i4_degrade_pics;\n\n    /**\n     * Interval for pictures which are completely decoded without any degradation\n     */\n    WORD32 i4_nondegrade_interval;\n\n    /**\n     * bit position (lsb is zero): Type of degradation\n     * 1 : Disable deblocking\n     * 2 : Faster inter prediction filters\n     * 3 : Fastest inter prediction filters\n     */\n    WORD32 i4_degrade_type;\n\n    /** Degrade pic count, Used to maintain the interval between non-degraded pics\n     *\n     */\n    WORD32 i4_degrade_pic_cnt;\n    WORD32 i4_display_index;\n    UWORD32 u4_pic_buf_got;\n\n    /**\n     * Col flag and mv pred buffer manager\n     */\n    void *pv_mv_buf_mgr;\n\n    /**\n     * Picture buffer manager\n     */\n    void *pv_pic_buf_mgr;\n\n    /**\n     * Display buffer manager\n     */\n    void *pv_disp_buf_mgr;\n\n    void *apv_buf_id_pic_buf_map[MAX_DISP_BUFS_NEW];\n\n    UWORD8 au1_pic_buf_id_mv_buf_id_map[MAX_DISP_BUFS_NEW];\n\n    UWORD8 au1_pic_buf_ref_flag[MAX_DISP_BUFS_NEW];\n\n    struct pic_buffer_t *ps_pic_buf_base;\n\n    UWORD8 *pu1_ref_buff_base;\n    col_mv_buf_t *ps_col_mv_base;\n    void *(*pf_aligned_alloc)(void *pv_mem_ctxt, WORD32 alignment, WORD32 size);\n    void (*pf_aligned_free)(void *pv_mem_ctxt, void *pv_buf);\n    void *pv_mem_ctxt;\n\n    UWORD8 *pu1_pic_buf_base;\n    UWORD8 *pu1_mv_bank_buf_base;\n    UWORD8 *pu1_init_dpb_base;\n\n    ih264_default_weighted_pred_ft *pf_default_weighted_pred_luma;\n\n    ih264_default_weighted_pred_ft *pf_default_weighted_pred_chroma;\n\n    ih264_weighted_pred_ft *pf_weighted_pred_luma;\n\n    ih264_weighted_pred_ft *pf_weighted_pred_chroma;\n\n    ih264_weighted_bi_pred_ft *pf_weighted_bi_pred_luma;\n\n    ih264_weighted_bi_pred_ft *pf_weighted_bi_pred_chroma;\n\n    ih264_pad *pf_pad_top;\n    ih264_pad *pf_pad_bottom;\n    ih264_pad *pf_pad_left_luma;\n    ih264_pad *pf_pad_left_chroma;\n    ih264_pad *pf_pad_right_luma;\n    ih264_pad *pf_pad_right_chroma;\n\n    ih264_inter_pred_chroma_ft *pf_inter_pred_chroma;\n\n    ih264_inter_pred_luma_ft *apf_inter_pred_luma[16];\n\n    ih264_intra_pred_luma_ft *apf_intra_pred_luma_16x16[4];\n\n    ih264_intra_pred_luma_ft *apf_intra_pred_luma_8x8[9];\n\n    ih264_intra_pred_luma_ft *apf_intra_pred_luma_4x4[9];\n\n    ih264_intra_pred_ref_filtering_ft *pf_intra_pred_ref_filtering;\n\n    ih264_intra_pred_chroma_ft *apf_intra_pred_chroma[4];\n\n    ih264_iquant_itrans_recon_ft *pf_iquant_itrans_recon_luma_4x4;\n\n    ih264_iquant_itrans_recon_ft *pf_iquant_itrans_recon_luma_4x4_dc;\n\n    ih264_iquant_itrans_recon_ft *pf_iquant_itrans_recon_luma_8x8;\n\n    ih264_iquant_itrans_recon_ft *pf_iquant_itrans_recon_luma_8x8_dc;\n\n    ih264_iquant_itrans_recon_chroma_ft *pf_iquant_itrans_recon_chroma_4x4;\n\n    ih264_iquant_itrans_recon_chroma_ft *pf_iquant_itrans_recon_chroma_4x4_dc;\n\n    ih264_ihadamard_scaling_ft *pf_ihadamard_scaling_4x4;\n\n    /**\n     * deblock vertical luma edge with blocking strength 4\n     */\n    ih264_deblk_edge_bs4_ft *pf_deblk_luma_vert_bs4;\n\n    /**\n     * deblock vertical luma edge with blocking strength less than 4\n     */\n    ih264_deblk_edge_bslt4_ft *pf_deblk_luma_vert_bslt4;\n\n    /**\n     * deblock vertical luma edge with blocking strength 4 for mbaff\n     */\n    ih264_deblk_edge_bs4_ft *pf_deblk_luma_vert_bs4_mbaff;\n\n    /**\n     * deblock vertical luma edge with blocking strength less than 4 for mbaff\n     */\n    ih264_deblk_edge_bslt4_ft *pf_deblk_luma_vert_bslt4_mbaff;\n\n    /**\n     * deblock vertical chroma edge with blocking strength 4\n     */\n    ih264_deblk_chroma_edge_bs4_ft *pf_deblk_chroma_vert_bs4;\n\n    /**\n     * deblock vertical chroma edge with blocking strength less than 4\n     */\n    ih264_deblk_chroma_edge_bslt4_ft *pf_deblk_chroma_vert_bslt4;\n\n    /**\n     * deblock vertical chroma edge with blocking strength 4 for mbaff\n     */\n    ih264_deblk_chroma_edge_bs4_ft *pf_deblk_chroma_vert_bs4_mbaff;\n\n    /**\n     * deblock vertical chroma edge with blocking strength less than 4 for mbaff\n     */\n    ih264_deblk_chroma_edge_bslt4_ft *pf_deblk_chroma_vert_bslt4_mbaff;\n\n    /**\n     * deblock horizontal luma edge with blocking strength 4\n     */\n    ih264_deblk_edge_bs4_ft *pf_deblk_luma_horz_bs4;\n\n    /**\n     * deblock horizontal luma edge with blocking strength less than 4\n     */\n    ih264_deblk_edge_bslt4_ft *pf_deblk_luma_horz_bslt4;\n\n    /**\n     * deblock horizontal chroma edge with blocking strength 4\n     */\n    ih264_deblk_chroma_edge_bs4_ft *pf_deblk_chroma_horz_bs4;\n\n    /**\n     * deblock horizontal chroma edge with blocking strength less than 4\n     */\n    ih264_deblk_chroma_edge_bslt4_ft *pf_deblk_chroma_horz_bslt4;\n\n\n} dec_struct_t;\n\n#endif /* _H264_DEC_STRUCTS_H */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_tables.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/**\n **************************************************************************\n * \\file ih264d_tables.c\n *\n * \\brief\n *    Defination of all tables used by h264 decoder\n *\n * \\date\n *    17/09/2004\n *\n * \\author  MA\n **************************************************************************\n */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_tables.h\"\n\nconst UWORD8 gau1_ih264d_qp_scale_cr[] =\n    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\n      12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n      29, 30, 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 38,\n      39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39 };\nconst UWORD8 gau1_ih264d_alpha_table[] =\n    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n      0, 0, 0, 4, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 17, 20, 22, 25, 28, 32, 36,\n      40, 45, 50, 56, 63, 71, 80, 90, 101, 113, 127, 144, 162, 182, 203, 226,\n      255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };\nconst UWORD8 gau1_ih264d_beta_table[] =\n    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n      0, 0, 0, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11,\n      11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 18,\n      18, 18, 18, 18, 18, 18, 18, 18, 18 };\n\nconst UWORD8 gau1_ih264d_clip_table[][4] =\n    {\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 0 },\n          { 0, 0, 0, 1 },\n          { 0, 0, 0, 1 },\n          { 0, 0, 0, 1 },\n          { 0, 0, 0, 1 },\n          { 0, 0, 1, 1 },\n          { 0, 0, 1, 1 },\n          { 0, 1, 1, 1 },\n          { 0, 1, 1, 1 },\n          { 0, 1, 1, 1 },\n          { 0, 1, 1, 1 },\n          { 0, 1, 1, 2 },\n          { 0, 1, 1, 2 },\n          { 0, 1, 1, 2 },\n          { 0, 1, 1, 2 },\n          { 0, 1, 2, 3 },\n          { 0, 1, 2, 3 },\n          { 0, 2, 2, 3 },\n          { 0, 2, 2, 4 },\n          { 0, 2, 3, 4 },\n          { 0, 2, 3, 4 },\n          { 0, 3, 3, 5 },\n          { 0, 3, 4, 6 },\n          { 0, 3, 4, 6 },\n          { 0, 4, 5, 7 },\n          { 0, 4, 5, 8 },\n          { 0, 4, 6, 9 },\n          { 0, 5, 7, 10 },\n          { 0, 6, 8, 11 },\n          { 0, 6, 8, 13 },\n          { 0, 7, 10, 14 },\n          { 0, 8, 11, 16 },\n          { 0, 9, 12, 18 },\n          { 0, 10, 13, 20 },\n          { 0, 11, 15, 23 },\n          { 0, 13, 17, 25 },\n\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 },\n          { 0, 13, 17, 25 }\n\n    };\nconst UWORD8 gau1_ih264d_clip_table_deblock[] =\n    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,\n      12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,\n      30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,\n      48, 49, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51 };\n\n/****************DEBLOCKING TABLES ENDS*******************/\n\n/*************************************************************/\n/* BS CALCULATION TABLES                                     */\n/*************************************************************/\nUWORD32 const gau4_ih264d_packed_bs2[32] =\n    {\n    /*************************************************************/\n    /* BS TABLES FOR NORMAL EDGES                                */\n    /*************************************************************/\n    0x00000000,\n      0x02000000, 0x00020000, 0x02020000, 0x00000200, 0x02000200, 0x00020200,\n      0x02020200, 0x00000002, 0x02000002, 0x00020002, 0x02020002, 0x00000202,\n      0x02000202, 0x00020202, 0x02020202,\n\n      /*************************************************************/\n      /* BS TABLES FOR XTRA LEFT MB EDGES IN MBAFF CASE            */\n      /*************************************************************/\n      0x01010101,\n      0x02010101, 0x01020101, 0x02020101, 0x01010201, 0x02010201, 0x01020201,\n      0x02020201, 0x01010102, 0x02010102, 0x01020102, 0x02020102, 0x01010202,\n      0x02010202, 0x01020202, 0x02020202, };\n\nUWORD16 const gau2_ih264d_4x4_v2h_reorder[16] =\n    { 0x0000, 0x0001, 0x0010, 0x0011, 0x0100, 0x0101, 0x0110, 0x0111, 0x1000,\n      0x1001, 0x1010, 0x1011, 0x1100, 0x1101, 0x1110, 0x1111 };\n\n/****************SCALING TABLES STARTS *****************/\nconst WORD16 gai2_ih264d_default_intra4x4[16] =\n    { 6, 13, 13, 20, 20, 20, 28, 28, 28, 28, 32, 32, 32, 37, 37, 42 };\n\nconst WORD16 gai2_ih264d_default_inter4x4[16] =\n    { 10, 14, 14, 20, 20, 20, 24, 24, 24, 24, 27, 27, 27, 30, 30, 34 };\n\nconst WORD16 gai2_ih264d_default_intra8x8[64] =\n    { 6, 10, 10, 13, 11, 13, 16, 16, 16, 16, 18, 18, 18, 18, 18, 23, 23, 23, 23,\n      23, 23, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 27, 27, 29,\n      29, 29, 29, 29, 29, 29, 31, 31, 31, 31, 31, 31, 33, 33, 33, 33, 33, 36,\n      36, 36, 36, 38, 38, 38, 40, 40, 42 };\n\nconst WORD16 gai2_ih264d_default_inter8x8[64] =\n    { 9, 13, 13, 15, 13, 15, 17, 17, 17, 17, 19, 19, 19, 19, 19, 21, 21, 21, 21,\n      21, 21, 22, 22, 22, 22, 22, 22, 22, 24, 24, 24, 24, 24, 24, 24, 24, 25,\n      25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 30,\n      30, 30, 30, 32, 32, 32, 33, 33, 35 };\n\nconst WORD16 gai2_ih264d_flat_4x4[16] =\n    { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 };\n\nconst WORD16 gai2_ih264d_flat_8x8[64] =\n    { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n      16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n      16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,\n      16, 16, 16, 16, 16, 16, 16, 16, 16, 16 };\n\n/****************SCALING TABLES ENDS *****************/\n\n/*Inverse scan tables for individual 4x4 blocks of 8x8 transform coeffs of CAVLC */\n\n/* progressive */\n\nconst UWORD8 gau1_ih264d_inv_scan_prog8x8_cavlc[4][16] =\n    {\n        { 0, 9, 17, 18, 12, 40, 27, 7, 35, 57, 29, 30, 58, 38, 53, 47 }, /* for First subblock  */\n          { 1, 2, 24, 11, 19, 48, 20, 14, 42, 50, 22, 37, 59, 31, 60, 55 }, /* for second subblock */\n          { 8, 3, 32, 4, 26, 41, 13, 21, 49, 43, 15, 44, 52, 39, 61, 62 }, /* for third subblock  */\n          { 16, 10, 25, 5, 33, 34, 6, 28, 56, 36, 23, 51, 45, 46, 54, 63 } /* for fourth subblock */\n    };\n\nconst UWORD8 gau1_ih264d_inv_scan_int8x8_cavlc[4][16] =\n    {\n        { 0, 9, 2, 56, 18, 26, 34, 27, 35, 28, 36, 29, 45, 7, 54, 39 }, /* for First subblock  */\n          { 8, 24, 25, 33, 41, 11, 42, 12, 43, 13, 44, 14, 53, 15, 62, 47 }, /* for second subblock */\n          { 16, 32, 40, 10, 49, 4, 50, 5, 51, 6, 52, 22, 61, 38, 23, 55 }, /* for third subblock  */\n          { 1, 17, 48, 3, 57, 19, 58, 20, 59, 21, 60, 37, 30, 46, 31, 63 } /* for fourth subblock */\n    };\n\n/*Inverse scan tables for individual 8x8 blocks of 8x8 transform coeffs of CABAC */\n/* progressive */\n\nconst UWORD8 gau1_ih264d_inv_scan_prog8x8_cabac[64] =\n    { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33,\n      40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43,\n      36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53,\n      60, 61, 54, 47, 55, 62, 63 };\n\n/* interlace */\n\nconst UWORD8 gau1_ih264d_inv_scan_int8x8_cabac[64] =\n    { 0, 8, 16, 1, 9, 24, 32, 17, 2, 25, 40, 48, 56, 33, 10, 3, 18, 41, 49, 57,\n      26, 11, 4, 19, 34, 42, 50, 58, 27, 12, 5, 20, 35, 43, 51, 59, 28, 13, 6,\n      21, 36, 44, 52, 60, 29, 14, 22, 37, 45, 53, 61, 30, 7, 15, 38, 46, 54, 62,\n      23, 31, 39, 47, 55, 63 };\n\n/****************PARSING TABLES *******************/\nUWORD8 const gau1_ih264d_subblk_offset[16] =\n    { 8, 9, 12, 13, 10, 11, 14, 15, 16, 17, 20, 21, 18, 19, 22, 23 };\n\nconst UWORD8 gau1_ih264d_cbp_tab[6] =\n    { 0, 16, 32, 15, 31, 47 };\n\n/** gives CBP value from codeword number, both for intra and inter */\n\nconst UWORD8 gau1_ih264d_cbp_table[48][2] =\n    {\n        { 47, 0 },\n          { 31, 16 },\n          { 15, 1 },\n          { 0, 2 },\n          { 23, 4 },\n          { 27, 8 },\n          { 29, 32 },\n          { 30, 3 },\n          { 7, 5 },\n          { 11, 10 },\n          { 13, 12 },\n          { 14, 15 },\n          { 39, 47 },\n          { 43, 7 },\n          { 45, 11 },\n          { 46, 13 },\n          { 16, 14 },\n          { 3, 6 },\n          { 5, 9 },\n          { 10, 31 },\n          { 12, 35 },\n          { 19, 37 },\n          { 21, 42 },\n          { 26, 44 },\n          { 28, 33 },\n          { 35, 34 },\n          { 37, 36 },\n          { 42, 40 },\n          { 44, 39 },\n          { 1, 43 },\n          { 2, 45 },\n          { 4, 46 },\n          { 8, 17 },\n          { 17, 18 },\n          { 18, 20 },\n          { 20, 24 },\n          { 24, 19 },\n          { 6, 21 },\n          { 9, 26 },\n          { 22, 28 },\n          { 25, 23 },\n          { 32, 27 },\n          { 33, 29 },\n          { 34, 30 },\n          { 36, 22 },\n          { 40, 25 },\n          { 38, 38 },\n          { 41, 41 }, };\n/****************PARSING TABLES ENDS *******************/\n\n/****************DECODE SLICE TABLES STARTS *******************/\n/*Definition of Tables needed by functions of this file */\nconst UWORD8 gau1_ih264d_inv_scan[16] =\n    { 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 };\n\nconst UWORD8 gau1_ih264d_inv_scan_fld[16] =\n    { 0, 4, 1, 8, 12, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };\n\nconst UWORD8 gau1_ih264d_dequant_matrix[6][16] =\n{\n    {   10, 13, 10, 13, 13, 16, 13, 16, 10, 13, 10 ,13, 13, 16, 13, 16},\n    {   11, 14, 11, 14, 14, 18, 14, 18, 11, 14, 11 ,14, 14, 18, 14, 18},\n    {   13, 16, 13, 16, 16, 20, 16, 20, 13, 16, 13 ,16, 16, 20, 16, 20},\n    {   14, 18, 14, 18, 18, 23, 18, 23, 14, 18, 14, 18, 18, 23, 18, 23},\n    {   16, 20, 16, 20, 20, 25, 20, 25, 16, 20, 16, 20, 20, 25, 20, 25},\n    {   18, 23, 18, 23, 23, 29, 23, 29, 18, 23, 18, 23, 23, 29, 23, 29}\n};\n\nconst UWORD16 gau2_ih264_iquant_scale_4x4[6][16] =\n    {\n        { 10, 13, 10, 13, 13, 16, 13, 16, 10, 13, 10, 13, 13, 16, 13, 16 },\n          { 11, 14, 11, 14, 14, 18, 14, 18, 11, 14, 11, 14, 14, 18, 14, 18 },\n          { 13, 16, 13, 16, 16, 20, 16, 20, 13, 16, 13, 16, 16, 20, 16, 20 },\n          { 14, 18, 14, 18, 18, 23, 18, 23, 14, 18, 14, 18, 18, 23, 18, 23 },\n          { 16, 20, 16, 20, 20, 25, 20, 25, 16, 20, 16, 20, 20, 25, 20, 25 },\n          { 18, 23, 18, 23, 23, 29, 23, 29, 18, 23, 18, 23, 23, 29, 23, 29 } };\n\nconst UWORD8 gau1_ih264d_dequant8x8_zigzag_cavlc[4][6][16] =\n                    {\n                        {\n                            { 20, 18, 24, 32, 19, 19, 18, 19, 19, 18, 18, 24,\n                              24, 25, 24, 18 }, /* for First subblock  */\n                              { 22, 19, 26, 35, 21, 21, 19, 21, 21, 19, 19, 26,\n                                26, 28, 26, 19 },\n                              { 26, 23, 31, 42, 24, 24, 23, 24, 24, 23, 23, 31,\n                                31, 33, 31, 23 },\n                              { 28, 25, 33, 45, 26, 26, 25, 26, 26, 25, 25, 33,\n                                33, 35, 33, 25 },\n                              { 32, 28, 38, 51, 30, 30, 28, 30, 30, 28, 28, 38,\n                                38, 40, 38, 28 },\n                              { 36, 32, 43, 58, 34, 34, 32, 34, 34, 32, 32, 43,\n                                43, 46, 43, 32 } },\n                          {\n                              { 19, 25, 19, 18, 24, 25, 25, 24, 24, 32, 32, 19,\n                                18, 18, 19, 24 }, /* for second subblock */\n                                { 21, 28, 21, 19, 26, 28, 28, 26, 26, 35, 35,\n                                  21, 19, 19, 21, 26 },\n                                { 24, 33, 24, 23, 31, 33, 33, 31, 31, 42, 42,\n                                  24, 23, 23, 24, 31 },\n                                { 26, 35, 26, 25, 33, 35, 35, 33, 33, 45, 45,\n                                  26, 25, 25, 26, 33 },\n                                { 30, 40, 30, 28, 38, 40, 40, 38, 38, 51, 51,\n                                  30, 28, 28, 30, 38 },\n                                { 34, 46, 34, 32, 43, 46, 46, 43, 43, 58, 58,\n                                  34, 32, 32, 34, 43 } },\n                          {\n                              { 19, 19, 20, 20, 24, 18, 18, 24, 24, 18, 18, 19,\n                                25, 19, 18, 24 }, /* for third subblock  */\n                                { 21, 21, 22, 22, 26, 19, 19, 26, 26, 19, 19,\n                                  21, 28, 21, 19, 26 },\n                                { 24, 24, 26, 26, 31, 23, 23, 31, 31, 23, 23,\n                                  24, 33, 24, 23, 31 },\n                                { 26, 26, 28, 28, 33, 25, 25, 33, 33, 25, 25,\n                                  26, 35, 26, 25, 33 },\n                                { 30, 30, 32, 32, 38, 28, 28, 38, 38, 28, 28,\n                                  30, 40, 30, 28, 38 },\n                                { 34, 34, 36, 36, 43, 32, 32, 43, 43, 32, 32,\n                                  34, 46, 34, 32, 43 } },\n                          {\n                              { 25, 24, 18, 19, 19, 25, 25, 19, 19, 20, 24, 24,\n                                18, 24, 32, 18 }, /* for fourth subblock */\n                                { 28, 26, 19, 21, 21, 28, 28, 21, 21, 22, 26,\n                                  26, 19, 26, 35, 19 },\n                                { 33, 31, 23, 24, 24, 33, 33, 24, 24, 26, 31,\n                                  31, 23, 31, 42, 23 },\n                                { 35, 33, 25, 26, 26, 35, 35, 26, 26, 28, 33,\n                                  33, 25, 33, 45, 25 },\n                                { 40, 38, 28, 30, 30, 40, 40, 30, 30, 32, 38,\n                                  38, 28, 38, 51, 28 },\n                                { 46, 43, 32, 34, 34, 46, 46, 34, 34, 36, 43,\n                                  43, 32, 43, 58, 32 } }\n\n                    };\n\nconst UWORD16 gau1_ih264d_dequant8x8_cavlc[6][64] =\n                    {\n                        { 20, 19, 25, 19, 20, 19, 25, 19, 19, 18, 24, 18, 19,\n                          18, 24, 18, 25, 24, 32, 24, 25, 24, 32, 24, 19, 18,\n                          24, 18, 19, 18, 24, 18, 20, 19, 25, 19, 20, 19, 25,\n                          19, 19, 18, 24, 18, 19, 18, 24, 18, 25, 24, 32, 24,\n                          25, 24, 32, 24, 19, 18, 24, 18, 19, 18, 24, 18 },\n                          { 22, 21, 28, 21, 22, 21, 28, 21, 21, 19, 26, 19, 21,\n                            19, 26, 19, 28, 26, 35, 26, 28, 26, 35, 26, 21, 19,\n                            26, 19, 21, 19, 26, 19, 22, 21, 28, 21, 22, 21, 28,\n                            21, 21, 19, 26, 19, 21, 19, 26, 19, 28, 26, 35, 26,\n                            28, 26, 35, 26, 21, 19, 26, 19, 21, 19, 26, 19 },\n                          { 26, 24, 33, 24, 26, 24, 33, 24, 24, 23, 31, 23, 24,\n                            23, 31, 23, 33, 31, 42, 31, 33, 31, 42, 31, 24, 23,\n                            31, 23, 24, 23, 31, 23, 26, 24, 33, 24, 26, 24, 33,\n                            24, 24, 23, 31, 23, 24, 23, 31, 23, 33, 31, 42, 31,\n                            33, 31, 42, 31, 24, 23, 31, 23, 24, 23, 31, 23 },\n                          { 28, 26, 35, 26, 28, 26, 35, 26, 26, 25, 33, 25, 26,\n                            25, 33, 25, 35, 33, 45, 33, 35, 33, 45, 33, 26, 25,\n                            33, 25, 26, 25, 33, 25, 28, 26, 35, 26, 28, 26, 35,\n                            26, 26, 25, 33, 25, 26, 25, 33, 25, 35, 33, 45, 33,\n                            35, 33, 45, 33, 26, 25, 33, 25, 26, 25, 33, 25 },\n                          { 32, 30, 40, 30, 32, 30, 40, 30, 30, 28, 38, 28, 30,\n                            28, 38, 28, 40, 38, 51, 38, 40, 38, 51, 38, 30, 28,\n                            38, 28, 30, 28, 38, 28, 32, 30, 40, 30, 32, 30, 40,\n                            30, 30, 28, 38, 28, 30, 28, 38, 28, 40, 38, 51, 38,\n                            40, 38, 51, 38, 30, 28, 38, 28, 30, 28, 38, 28 },\n                          { 36, 34, 46, 34, 36, 34, 46, 34, 34, 32, 43, 32, 34,\n                            32, 43, 32, 46, 43, 58, 43, 46, 43, 58, 43, 34, 32,\n                            43, 32, 34, 32, 43, 32, 36, 34, 46, 34, 36, 34, 46,\n                            34, 34, 32, 43, 32, 34, 32, 43, 32, 46, 43, 58, 43,\n                            46, 43, 58, 43, 34, 32, 43, 32, 34, 32, 43, 32 }, };\n\n/****************DECODE SLICE TABLES ENDS *******************/\n\n/****************MOTION VECTOR DECODING TABLES STARTS *******************/\n\n/**\n **************************************************************************\n *   \\brief   This array is used to evaluate the condition when only one of\n *   predictor subMbs has a reference frame equal to that of E subMb.\n **************************************************************************\n */\n\nconst WORD8 gau1_ih264d_mv_pred_condition[] =\n    { -1, 0, 1, -1, 2, -1, -1, -1 };\n\n/** Number of subMbs for the 8x8 prediction mode */\nconst UWORD8 gau1_ih264d_num_submb_part[] =\n    { 1, 2, 2, 4 };\n\n/** Width of the 8x8 prediction mode in terms of subMbs */\nconst UWORD8 gau1_ih264d_submb_partw[] =\n    { 2, 2, 1, 1 };\n\n/** Height of the 8x8 prediction mode in terms of subMbs */\nconst UWORD8 gau1_ih264d_submb_parth[] =\n    { 2, 1, 2, 1 };\n\n/** Number of MB partitions for the MB prediction mode */\nconst UWORD8 gau1_ih264d_num_mb_part[] =\n    { 1, 2, 2, 4 };\n\n/** Width of the MB partition in terms of subMbs */\nconst UWORD8 gau1_ih264d_mb_partw[] =\n    { 4, 4, 2, 2, 2 };\n\n/** Height of the MB partition in terms of subMbs */\nconst UWORD8 gau1_ih264d_mb_parth[] =\n    { 4, 2, 4, 2, 2 };\n\n/** MB partition information is packed into a UWORD32 {0,number,width,height} */\nconst UWORD32 gau4_ih264d_submb_part[] =\n    { 0x00010202, 0x00020201, 0x00020102, 0x00040101 };\n\nconst UWORD8 gau1_ih264d_submb_indx_mod[] =\n    { 0, 0, /* 16x16 */\n      0, 8, /* 16x8 */\n      0, 2, /* 8x16 */\n      0, 0, /* 8x8 */\n      0, 4, /* 8x4 */\n      0, 1, /* 4x8 */\n      0, 1, 3, 1 /* 4x4 */\n    };\n\n/** This table is used to assign CBPs to Inter MBs. */\nconst UWORD8 gau1_ih264d_cbp_inter[] =\n    { 0, 16, 1, 2, 4, 8, 32, 3, 5, 10, 12, 15, 47, 7, 11, 13, 14, 6, 9, 31, 35,\n      37, 42, 44, 33, 34, 36, 40, 39, 43, 45, 46, 17, 18, 20, 24, 19, 21, 26,\n      28, 23, 27, 29, 30, 22, 25, 38, 41 };\n\n/** Motion comp modes for P followed by B,\n 0 to 4   : P Mbs\n 5 to 27  : B Mbs\n 28 to 30 : DIRECT */\nconst UWORD8 gau1_ih264d_mb_mc_mode[] =\n    {\n    PRED_16x16,\n      PRED_16x8, PRED_8x16, PRED_8x8, PRED_8x8R0,\n      PRED_16x16,\n      PRED_16x16, PRED_16x16, PRED_16x16, PRED_16x8, PRED_8x16,\n      PRED_16x8,\n      PRED_8x16, PRED_16x8, PRED_8x16, PRED_16x8, PRED_8x16,\n      PRED_16x8,\n      PRED_8x16, PRED_16x8, PRED_8x16, PRED_16x8, PRED_8x16,\n      PRED_16x8,\n      PRED_8x16, PRED_16x8, PRED_8x16, PRED_8x8,\n      /* Self defined modes for B_SKIP and DIRECT16x16 */\n      PRED_8x8,\n      PRED_8x8, PRED_8x8 };\n\nconst UWORD8 gau1_ih264d_submb_mc_mode[] =\n    { SUBMB_8x8, SUBMB_8x4, SUBMB_4x8, SUBMB_4x4,\n    SUBMB_8x8,\n      SUBMB_8x8, SUBMB_8x8, SUBMB_8x8, SUBMB_8x4, SUBMB_4x8,\n      SUBMB_8x4,\n      SUBMB_4x8, SUBMB_8x4, SUBMB_4x8, SUBMB_4x4, SUBMB_4x4, SUBMB_4x4,\n      /* Self defined modes B DIRECT8x8 */\n      SUBMB_4x4,\n      SUBMB_4x4, SUBMB_4x4 };\n\n/** Sub MB pred modes for B slice */\nconst UWORD8 gau1_ih264d_submb_pred_modes[] =\n    {\n    PRED_L0,\n      PRED_L0, PRED_L0, PRED_L0,\n      B_DIRECT,\n      PRED_L0, PRED_L1, BI_PRED, PRED_L0, PRED_L0, PRED_L1,\n      PRED_L1,\n      BI_PRED, BI_PRED, PRED_L0, PRED_L1, BI_PRED,\n      /* Self defined modes for B DIRECT8x8 */\n      BI_PRED,\n      PRED_L0, PRED_L1, };\n\n/** MB pred modes for P and B slice */\nconst WORD8 gau1_ih264d_mb_pred_modes[2][32] =\n    {\n        { PRED_L0, PRED_L0, PRED_L0, PRED_INVALID, PRED_INVALID,\n        B_DIRECT,\n          PRED_L0, PRED_L1, BI_PRED, PRED_L0, PRED_L0, PRED_L1, PRED_L1,\n          PRED_L0,\n          PRED_L0, PRED_L1, PRED_L1, PRED_L0, PRED_L0, PRED_L1, PRED_L1,\n          BI_PRED,\n          BI_PRED, BI_PRED, BI_PRED, BI_PRED, BI_PRED, PRED_INVALID,\n          /* Self defined modes for B_SKIP and DIRECT16x16 */\n          BI_PRED,\n          PRED_L0, PRED_L1, },\n          { PRED_INVALID, PRED_L0, PRED_L0, PRED_INVALID, PRED_INVALID,\n          PRED_INVALID,\n            PRED_INVALID, PRED_INVALID, PRED_INVALID, PRED_L0, PRED_L0,\n            PRED_L1,\n            PRED_L1, PRED_L1, PRED_L1, PRED_L0, PRED_L0, BI_PRED, BI_PRED,\n            BI_PRED,\n            BI_PRED, PRED_L0, PRED_L0, PRED_L1, PRED_L1, BI_PRED, BI_PRED,\n            PRED_INVALID,\n            /* Self defined modes for B_SKIP and DIRECT16x16 */\n            PRED_INVALID,\n            PRED_INVALID, PRED_INVALID } };\n\n/****************MOTION VECTOR DECODING TABLES ENDS *******************/\n\n/****************CAVLC DECODING TABLES STARTS *******************/\n\n/*****************************************************************************/\n/* 6 Bit table look for total zeros (totalcoeff = 2to10) as in Table 9.7     */\n/* of H264 standard. In each table entry, lower 4 bits represent total zeros */\n/* decoded while upper 4 bit represent the bits to be flushed from ps_bitstrm    */\n/*****************************************************************************/\nconst UWORD8 gau1_ih264d_table_total_zero_2to10[9][64] =\n    {\n    /* For total coeff = 2 */\n        { 0x6E, 0x6D, 0x6C, 0x6B, 0x5A, 0x5A, 0x59, 0x59, 0x48, 0x48, 0x48,\n          0x48, 0x47, 0x47, 0x47, 0x47, 0x46, 0x46, 0x46, 0x46, 0x45, 0x45,\n          0x45, 0x45, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x33,\n          0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,\n          0x32, 0x32, 0x32, 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,\n          0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, },\n\n      /* For total coeff = 3 */\n          { 0x6D, 0x6B, 0x5C, 0x5C, 0x5A, 0x5A, 0x59, 0x59, 0x48, 0x48, 0x48,\n            0x48, 0x45, 0x45, 0x45, 0x45, 0x44, 0x44, 0x44, 0x44, 0x40, 0x40,\n            0x40, 0x40, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x36,\n            0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x33, 0x33, 0x33, 0x33,\n            0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,\n            0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, },\n\n      /* For total coeff = 4 */\n          { 0x5C, 0x5C, 0x5B, 0x5B, 0x5A, 0x5A, 0x50, 0x50, 0x49, 0x49, 0x49,\n            0x49, 0x47, 0x47, 0x47, 0x47, 0x43, 0x43, 0x43, 0x43, 0x42, 0x42,\n            0x42, 0x42, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x36,\n            0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, 0x35,\n            0x35, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,\n            0x34, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, },\n\n      /* For total coeff = 5 */\n          { 0x5B, 0x5B, 0x59, 0x59, 0x4A, 0x4A, 0x4A, 0x4A, 0x48, 0x48, 0x48,\n            0x48, 0x42, 0x42, 0x42, 0x42, 0x41, 0x41, 0x41, 0x41, 0x40, 0x40,\n            0x40, 0x40, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x36,\n            0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x35, 0x35, 0x35, 0x35,\n            0x35, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34,\n            0x34, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, },\n\n      /* For total coeff = 6 */\n          { 0x6A, 0x60, 0x51, 0x51, 0x48, 0x48, 0x48, 0x48, 0x39, 0x39, 0x39,\n            0x39, 0x39, 0x39, 0x39, 0x39, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,\n            0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x35,\n            0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34,\n            0x34, 0x34, 0x34, 0x34, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,\n            0x33, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, },\n\n      /* For total coeff = 7 */\n          { 0x69, 0x60, 0x51, 0x51, 0x47, 0x47, 0x47, 0x47, 0x38, 0x38, 0x38,\n            0x38, 0x38, 0x38, 0x38, 0x38, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,\n            0x36, 0x36, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x33,\n            0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,\n            0x32, 0x32, 0x32, 0x32, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,\n            0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, },\n\n      /* For total coeff = 8 */\n          { 0x68, 0x60, 0x52, 0x52, 0x41, 0x41, 0x41, 0x41, 0x37, 0x37, 0x37,\n            0x37, 0x37, 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,\n            0x36, 0x36, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x25,\n            0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,\n            0x25, 0x25, 0x25, 0x25, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,\n            0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, },\n\n      /* For total coeff = 9 */\n          { 0x61, 0x60, 0x57, 0x57, 0x42, 0x42, 0x42, 0x42, 0x35, 0x35, 0x35,\n            0x35, 0x35, 0x35, 0x35, 0x35, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\n            0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x24,\n            0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,\n            0x24, 0x24, 0x24, 0x24, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,\n            0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, },\n\n      /* For total coeff = 10 */\n          { 0x51, 0x51, 0x50, 0x50, 0x46, 0x46, 0x46, 0x46, 0x32, 0x32, 0x32,\n            0x32, 0x32, 0x32, 0x32, 0x32, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,\n            0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x24,\n            0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,\n            0x24, 0x24, 0x24, 0x24, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23,\n            0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, }\n\n    };\n\n/*****************************************************************************/\n/* 4 Bit table look for total zeros (totalcoeff = 11to15) as in Table 9.7    */\n/* of H264 standard. In each table entry, lower 4 bits represent total zeros */\n/* decoded while upper 4 bit represent the bits to be flushed from ps_bitstrm    */\n/*****************************************************************************/\nconst UWORD8 gau1_ih264d_table_total_zero_11to15[5][16] =\n    {\n    /* For total coeff = 11 */\n        { 0x40, 0x41, 0x32, 0x32, 0x33, 0x33, 0x35, 0x35, 0x14, 0x14, 0x14,\n          0x14, 0x14, 0x14, 0x14, 0x14, },\n\n      /* For total coeff = 12 */\n          { 0x40, 0x41, 0x34, 0x34, 0x22, 0x22, 0x22, 0x22, 0x13, 0x13, 0x13,\n            0x13, 0x13, 0x13, 0x13, 0x13, },\n\n      /* For total coeff = 13 */\n          { 0x30, 0x30, 0x31, 0x31, 0x23, 0x23, 0x23, 0x23, 0x12, 0x12, 0x12,\n            0x12, 0x12, 0x12, 0x12, 0x12, },\n\n      /* For total coeff = 14 */\n          { 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x12, 0x12, 0x12,\n            0x12, 0x12, 0x12, 0x12, 0x12, },\n\n      /* For total coeff = 15 */\n          { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11,\n            0x11, 0x11, 0x11, 0x11, 0x11, }, };\n\n/** Tables used to read \"Run Before\", Below tables are packed to reduce lookups */\n/** (Base addess of Gx << 2)  + (Max code length for that Gx) */\nconst UWORD8 gau1_ih264d_table_run_before[64] =\n    { 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 1, 1, 1, 1, 10, 10, 6, 6, 1, 1, 1, 1,\n      14, 14, 10, 10, 6, 6, 2, 2, 19, 15, 10, 10, 6, 6, 2, 2, 23, 19, 15, 11, 6,\n      6, 2, 2, 7, 11, 19, 15, 27, 23, 2, 2, 27, 27, 23, 19, 15, 11, 7, 3 };\n\n/*****************************************************************************/\n/* Lookup table for CAVLC 4x4  total_coeff,trailing_ones as pers Table 9-5   */\n/* in the standard. Starting form lsb first 2 bits=flushbits, next 2bits=    */\n/* trailing ones, next 5 bits=total_coeff. Total bits used = 9 out of 16     */\n/*****************************************************************************/\nconst UWORD16 gau2_ih264d_code_gx[304] =\n    {\n    /* Lookup for 0 <= nC < 2 */\n    0x0000,\n      0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0014, 0x0014,\n      0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0028, 0x0028, 0x0028,\n      0x0028, 0x0028, 0x0028, 0x0028, 0x0028, 0x0026, 0x0026, 0x0012, 0x0012,\n      0x003D, 0x003D, 0x003D, 0x003D, 0x005E, 0x005E, 0x003A, 0x003A, 0x004D,\n      0x004D, 0x004D, 0x004D, 0x006E, 0x006E, 0x004A, 0x004A, 0x0036, 0x0036,\n      0x0022, 0x0022, 0x007E, 0x007E, 0x005A, 0x005A, 0x0046, 0x0046, 0x0032,\n      0x0032, 0x008E, 0x008E, 0x006A, 0x006A, 0x0056, 0x0056, 0x0042, 0x0042,\n      0x009E, 0x009E, 0x007A, 0x007A, 0x0066, 0x0066, 0x0052, 0x0052, 0x0083,\n      0x009B, 0x0087, 0x0073, 0x00AF, 0x008B, 0x0077, 0x0063, 0x00CF, 0x00BB,\n      0x00A7, 0x00A3, 0x00BF, 0x00AB, 0x0097, 0x0093, 0x00EF, 0x00DB, 0x00C7,\n      0x00C3, 0x00DF, 0x00CB, 0x00B7, 0x00B3, 0x010F, 0x00FB, 0x00F7, 0x00E3,\n      0x00FF, 0x00EB, 0x00E7, 0x00D3, 0x0102, 0x0102, 0x010A, 0x010A, 0x0106,\n      0x0106, 0x00F2, 0x00F2, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,\n      0x00D4, 0x00D4,\n\n      /* Lookup for 2 <= nC < 4 */\n      0x0015,\n      0x0015, 0x0015, 0x0015, 0x0001, 0x0001, 0x0001, 0x0001, 0x004E, 0x004E,\n      0x003E, 0x003E, 0x0029, 0x0029, 0x0029, 0x0029, 0x006F, 0x003B, 0x0037,\n      0x0013, 0x005E, 0x005E, 0x0026, 0x0026, 0x007E, 0x007E, 0x004A, 0x004A,\n      0x0046, 0x0046, 0x0022, 0x0022, 0x008E, 0x008E, 0x005A, 0x005A, 0x0056,\n      0x0056, 0x0032, 0x0032, 0x0052, 0x0052, 0x006A, 0x006A, 0x0066, 0x0066,\n      0x0042, 0x0042, 0x009E, 0x009E, 0x007A, 0x007A, 0x0076, 0x0076, 0x0062,\n      0x0062, 0x00BF, 0x009B, 0x0097, 0x0083, 0x00AF, 0x008B, 0x0087, 0x0073,\n      0x00B3, 0x00BB, 0x00B7, 0x00A3, 0x00CF, 0x00AB, 0x00A7, 0x0093, 0x00EF,\n      0x00DB, 0x00D7, 0x00D3, 0x00DF, 0x00CB, 0x00C7, 0x00C3, 0x00F7, 0x00F3,\n      0x00FB, 0x00E7, 0x00EA, 0x00EA, 0x00E2, 0x00E2, 0x010E, 0x010E, 0x010A,\n      0x010A, 0x0106, 0x0106, 0x0102, 0x0102, 0x00FC, 0x00FC, 0x00FC, 0x00FC,\n      0x00FC, 0x00FC, 0x00FC, 0x00FC,\n\n      /* Lookup for 4 <= nC < 8 */\n      0x007F,\n      0x006F, 0x005F, 0x004F, 0x003F, 0x002B, 0x0017, 0x0003, 0x0057, 0x005B,\n      0x0047, 0x004B, 0x0037, 0x008F, 0x003B, 0x0027, 0x0033, 0x007B, 0x0077,\n      0x0023, 0x009F, 0x006B, 0x0067, 0x0013, 0x0073, 0x0063, 0x009B, 0x0053,\n      0x00AF, 0x008B, 0x0087, 0x0043, 0x00CF, 0x00BB, 0x00A7, 0x0093, 0x00BF,\n      0x00AB, 0x0097, 0x0083, 0x00C3, 0x00DB, 0x00C7, 0x00B3, 0x00DF, 0x00CB,\n      0x00B7, 0x00A3, 0x00F7, 0x00E3, 0x00EF, 0x00EB, 0x00E7, 0x00D3, 0x00D6,\n      0x00D6, 0x0106, 0x0106, 0x00F2, 0x00F2, 0x00FE, 0x00FE, 0x00FA, 0x00FA,\n      0x010D, 0x010D, 0x010D, 0x010D, 0x0109, 0x0109, 0x0109, 0x0109, 0x0100,\n      0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100 };\n\n/*****************************************************************************/\n/* Lookup table for CAVLC ChromaDC total_coeff,trailing_ones parsing as per  */\n/* Table 9-5 in the standard. Starting from msb, First 4bits=total_coeff,    */\n/* next 2bits=trailing_ones and last 2bits=flushbits-1                       */\n/*****************************************************************************/\nconst UWORD8 gau1_ih264d_cav_chromdc_vld[256] =\n    { 0x9E, 0x9E, 0x97, 0x8F, 0x76, 0x76, 0x6E, 0x6E, 0x85, 0x85, 0x85, 0x85,\n      0x65, 0x65, 0x65, 0x65, 0x45, 0x45, 0x45, 0x45, 0x7D, 0x7D, 0x7D, 0x7D,\n      0x4D, 0x4D, 0x4D, 0x4D, 0x25, 0x25, 0x25, 0x25,\n\n      0x52,\n      0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52,\n      0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52,\n      0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52,\n\n      0x01,\n      0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\n      0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\n      0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\n      0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\n      0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\n      0x01, 0x01, 0x01,\n\n      0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,\n      0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, };\n\nconst UWORD16 gau2_ih264d_offset_num_vlc_tab[9] =\n    { 0, 0, 120, 120, 224, 224, 224, 224, 224 };\n\n/*****************************************************************************/\n/* Function pointer u4_ofst table lookup for parsing 4x4 residual blocks in   */\n/* CAVLC. The u4_ofst is dependent on total coeffs coded                      */\n/*****************************************************************************/\nconst UWORD8 gau1_ih264d_total_coeff_fn_ptr_offset[16] =\n    { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2 };\n\n/****************************************************************************/\n/*  gai2_ih264d_trailing_one_level lookup tables based on trailing one bits        */\n/*  All zeroes are u2_dummy in the table are u2_dummy to keep 3 uniform elements  */\n/****************************************************************************/\nconst WORD16 gai2_ih264d_trailing_one_level[14][3] =\n    {\n    /* All zeroes are u2_dummy */\n    /**********************************************************************/\n    /* Levels for trailing ones = 1, bits read can be 0 or 1              */\n    /**********************************************************************/\n        { 1, 0, 0 }, /* 0 */\n          { -1, 0, 0 }, /* 1 */\n\n      /**********************************************************************/\n      /* Levels for trailing ones = 2, bits read can be 00, 01, 10 ,11      */\n      /**********************************************************************/\n          { 1, 1, 0 }, /* 00 */\n          { 1, -1, 0 }, /* 01 */\n          { -1, 1, 0 }, /* 10 */\n          { -1, -1, 0 }, /* 11 */\n\n      /**********************************************************************/\n      /* Levels for trailing ones = 3, bits read can be 000 - 111           */\n      /**********************************************************************/\n          { 1, 1, 1 }, /* 000 */\n          { 1, 1, -1 }, /* 001 */\n          { 1, -1, 1 }, /* 010 */\n          { 1, -1, -1 }, /* 011 */\n          { -1, 1, 1 }, /* 100 */\n          { -1, 1, -1 }, /* 101 */\n          { -1, -1, 1 }, /* 110 */\n          { -1, -1, -1 }, /* 111 */\n    };\n/****************CAVLC DECODING TABLES ENDS *******************/\n\n/****************************************************************************/\n/* These are the codes used for error detection in intra pred4x4 modes      */\n/****************************************************************************/\nconst UWORD8 gau1_ih264d_intra_pred_err_code[9] =\n    { 2, 1, 0, 2, 3, 3, 3, 2, 1 };\n\n/* Number of users for top field , bottom field, which field needs to be     */\n/* displayed first                                                           */\nconst UWORD8 gau1_ih264d_sei_fld_usage[9][3] =\n    {\n        { 1, 1, DISP_FLD_FIRST_UNDEF },\n          { 1, 0, DISP_TOP_FLD_FIRST },\n          { 0, 1, DISP_BOT_FLD_FIRST },\n          { 1, 1, DISP_TOP_FLD_FIRST },\n          { 1, 1, DISP_BOT_FLD_FIRST },\n          { 2, 1, DISP_TOP_FLD_FIRST },\n          { 1, 2, DISP_BOT_FLD_FIRST },\n          { 2, 2, DISP_FLD_FIRST_UNDEF },\n          { 3, 3, DISP_FLD_FIRST_UNDEF } };\n\n/*****************************************************************/\n/* Context increment for significant coefficient(CABAC)          */\n/* Requires only 63 elements. But the last element with value -1 */\n/* is kept to make it 64                                         */\n/*****************************************************************/\nconst UWORD8 gau1_ih264d_sigcoeff_context_inc_frame[64] =\n    { 0, 1, 2, 3, 4, 5, 5, 4, 4, 3, 3, 4, 4, 4, 5, 5, 4, 4, 4, 4, 3, 3, 6, 7, 7,\n      7, 8, 9, 10, 9, 8, 7, 7, 6, 11, 12, 13, 11, 6, 7, 8, 9, 14, 10, 9, 8, 6,\n      11, 12, 13, 11, 6, 9, 14, 10, 9, 11, 12, 13, 11, 14, 10, 12, -1 };\n\nconst UWORD8 gau1_ih264d_sigcoeff_context_inc_field[64] =\n    { 0, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7, 7, 7, 8, 4, 5, 6, 9, 10, 10, 8, 11, 12,\n      11, 9, 9, 10, 10, 8, 11, 12, 11, 9, 9, 10, 10, 8, 11, 12, 11, 9, 9, 10,\n      10, 8, 13, 13, 9, 9, 10, 10, 8, 13, 13, 9, 9, 10, 10, 14, 14, 14, 14, 14,\n      -1 };\n\nconst UWORD8 gau1_ih264d_lastcoeff_context_inc[64] =\n    { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n      2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,\n      5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, -1 };\n\n/*!\n **************************************************************************\n *   \\brief   gau1_ih264d_top_left_mb_part_indx_mod\n *\n *   SubBlk number of the top left subBlk in each of the MB partition\n *   (16x16, 16x8, 8x16, 8x8)\n **************************************************************************\n */\nconst UWORD8 gau1_ih264d_top_left_mb_part_indx_mod[] =\n    { 0, 0 /* Junk */, /* 16x16 */\n      0, 8, /* 16x8 */\n      0, 2, /* 8x16 */\n      0, 2, 8, 10 /* 8x8 */,\n      0 /* One extra entry is read at the end of loop, but not used */\n    };\n\n/*!\n **************************************************************************\n *   \\brief   gau1_ih264d_submb_indx_mod_sp_drct\n *\n *   Contains increments to the subBlk num in a given subMb partition.\n **************************************************************************\n */\nconst UWORD8 gau1_ih264d_submb_indx_mod_sp_drct[] =\n    { 0, 0 /* Junk */, /* 8x8 */\n      0, 4, /* 8x4 */\n      0, 1, /* 4x8 */\n      0, 1, 3, 1 /* 4x4 */\n    };\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_tables.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n#ifndef  _IH264D_TABLES_H_\n#define  _IH264D_TABLES_H_\n\n/**\n **************************************************************************\n * \\file ih264d_tables.h\n *\n * \\brief\n *    Declaration of all tables used by h264 decoder\n *\n * \\date\n *    17/09/2004\n *\n * \\author  MA\n **************************************************************************\n */\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_cabac.h\"\n\n/*Deblocking Table declaration*/\nextern const UWORD8 gau1_ih264d_qp_scale_cr[];\nextern const UWORD8 gau1_ih264d_alpha_table[];\nextern const UWORD8 gau1_ih264d_clip_table_deblock[];\nextern const UWORD8 gau1_ih264d_beta_table[];\nextern const UWORD8 gau1_ih264d_clip_table[][4];\n\n/*Parsing Table declaration*/\nextern const UWORD8 gau1_ih264d_cbp_tab[6];\nextern const UWORD32 gau4_ih264d_packed_bs2[32];\nextern const UWORD16 gau2_ih264d_4x4_v2h_reorder[16];\nextern const UWORD8 gau1_ih264d_subblk_offset[16];\nextern const UWORD8 gau1_ih264d_cbp_table[48][2];\n\n/*Decode Slice Table declaration*/\nextern const UWORD8 gau1_ih264d_inv_scan[16];\nextern const UWORD8 gau1_ih264d_inv_scan_fld[16];\nextern const UWORD8 gau1_ih264d_dequant_matrix[6][16];\nextern const UWORD16 gau2_ih264_iquant_scale_4x4[6][16];\nextern const UWORD8 gau1_ih264d_dequant8x8_zigzag_cavlc[4][6][16];\nextern const UWORD16 gau1_ih264d_dequant8x8_cavlc[6][64];\n\nextern const UWORD8 gau1_ih264d_inv_scan_prog8x8_cavlc[4][16];\nextern const UWORD8 gau1_ih264d_inv_scan_int8x8_cavlc[4][16];\nextern const UWORD8 gau1_ih264d_inv_scan_prog8x8_cabac[64];\nextern const UWORD8 gau1_ih264d_inv_scan_int8x8_cabac[64];\n\nextern const UWORD8 gau1_ih264d_lastcoeff_context_inc[64];\nextern const UWORD8 gau1_ih264d_sigcoeff_context_inc_frame[64];\nextern const UWORD8 gau1_ih264d_sigcoeff_context_inc_field[64];\n\n/* scaling related table declaration */\nextern const WORD16 gai2_ih264d_default_intra4x4[16];\nextern const WORD16 gai2_ih264d_default_inter4x4[16];\nextern const WORD16 gai2_ih264d_default_intra8x8[64];\nextern const WORD16 gai2_ih264d_default_inter8x8[64];\nextern const WORD16 gai2_ih264d_flat_4x4[16];\nextern const WORD16 gai2_ih264d_flat_8x8[64];\n\n/*Decode MV Table declaration*/\nextern const WORD8 gau1_ih264d_mv_pred_condition[];\n\n/** Number of subMbs for the 8x8 prediction mode */\nextern const UWORD8 gau1_ih264d_num_submb_part[];\n\n/** Width of the 8x8 prediction mode in terms of subMbs */\nextern const UWORD8 gau1_ih264d_submb_partw[];\n\n/** Height of the 8x8 prediction mode in terms of subMbs */\nextern const UWORD8 gau1_ih264d_submb_parth[];\n\n/** Number of MB partitions for the MB prediction mode */\nextern const UWORD8 gau1_ih264d_num_mb_part[];\n\n/** Width of the MB partition in terms of subMbs */\nextern const UWORD8 gau1_ih264d_mb_partw[];\n\n/** Height of the MB partition in terms of subMbs */\nextern const UWORD8 gau1_ih264d_mb_parth[];\n\n/** MB partition information is packed into a UWORD32 {0,number,width,height} */\nextern const UWORD32 gau4_ih264d_submb_part[];\n\nextern const UWORD8 gau1_ih264d_submb_indx_mod[];\n\n/** This table is used to assign CBPs to Inter MBs. */\nextern const UWORD8 gau1_ih264d_cbp_inter[];\n\n/** Motion comp modes for P followed by B,\n 0 to 4   : P Mbs\n 5 to 27  : B Mbs\n 28 to 30 : DIRECT */\nextern const UWORD8 gau1_ih264d_mb_mc_mode[];\n\nextern const UWORD8 gau1_ih264d_submb_mc_mode[];\n\n/** Sub MB pred modes for B slice */\nextern const UWORD8 gau1_ih264d_submb_pred_modes[];\n\n/** MB pred modes for P and B slice */\nextern const WORD8 gau1_ih264d_mb_pred_modes[2][32];\n\n/*Decode CAVLC Table declaration*/\nextern const UWORD8 gau1_ih264d_table_total_zero_2to10[9][64];\nextern const UWORD8 gau1_ih264d_table_total_zero_11to15[5][16];\nextern const UWORD8 gau1_ih264d_table_run_before[64];\nextern const UWORD16 gau2_ih264d_code_gx[304];\nextern const UWORD8 gau1_ih264d_cav_chromdc_vld[256];\nextern const UWORD16 gau2_ih264d_offset_num_vlc_tab[9];\nextern const UWORD8 gau1_ih264d_total_coeff_fn_ptr_offset[16];\nextern const WORD16 gai2_ih264d_trailing_one_level[14][3];\n\n/*Decode CABAC Table declaration*/\nextern const UWORD32 gau4_ih264d_cabac_table[128][4];\n\n/****************************************************************************/\n/*             For error detection in intra pred4x4 modes                   */\n/****************************************************************************/\nextern const UWORD8 gau1_ih264d_intra_pred_err_code[9];\n\n/*****************************************************************************/\n/* Cabac tables for context initialization depending upon type of Slice,     */\n/* cabac init Idc value and Qp.                                              */\n/*****************************************************************************/\nextern const UWORD8 gau1_ih264d_cabac_ctxt_init_table[NUM_CAB_INIT_IDC_PLUS_ONE][QP_RANGE][NUM_CABAC_CTXTS];\n\n/*****************************************************************************/\n/* SEI tables for field usge and which field first                           */\n/*****************************************************************************/\nextern const UWORD8 gau1_ih264d_sei_fld_usage[9][3];\n\n\nextern const UWORD8 gau1_ih264d_top_left_mb_part_indx_mod[];\nextern const UWORD8 gau1_ih264d_submb_indx_mod_sp_drct[];\n\n#endif /*TABLES_H*/\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_thread_compute_bs.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*!\n **************************************************************************\n * \\file ih264d_thread_compute_bs.c\n *\n * \\brief\n *    Contains routines that for multi-thread decoder\n *\n * Detailed_description\n *\n * \\date\n *    20/02/2012\n *\n * \\author  ZR\n **************************************************************************\n */\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_debug.h\"\n#include <string.h>\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_mb_utils.h\"\n\n#include \"ih264d_thread_compute_bs.h\"\n#include \"ithread.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_process_pslice.h\"\n#include \"ih264d_process_intra_mb.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_format_conv.h\"\n#include \"ih264d_defs.h\"\nUWORD16 ih264d_update_csbp_8x8(UWORD16 u2_luma_csbp);\nvoid ih264d_fill_bs2_horz_vert(UWORD32 *pu4_bs, /* Base pointer of BS table */\n                               WORD32 u4_left_mb_csbp, /* csbp of left mb */\n                               WORD32 u4_top_mb_csbp, /* csbp of top mb */\n                               WORD32 u4_cur_mb_csbp, /* csbp of current mb */\n                               const UWORD32 *pu4_packed_bs2, const UWORD16 *pu2_4x4_v2h_reorder);\nvoid ih264d_copy_intra_pred_line(dec_struct_t *ps_dec,\n                                 dec_mb_info_t *ps_cur_mb_info,\n                                 UWORD32 nmb_index);\n\n#define BS_MB_GROUP 4\n#define DEBLK_MB_GROUP 1\n#define FORMAT_CONV_MB_GROUP 4\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_compute_bs_non_mbaff_thread                                           */\n/*                                                                           */\n/*  Description   : This function computes the pointers of left,top & current*/\n/*                : Nnz, MvPred & deblk_mb_t and supplies to FillBs function for*/\n/*                : Boundary Strength Calculation .this function is used     */\n/*                : BS being calculated in separate thread                   */\n/*  Inputs        : pointer to decoder context,cur_mb_info,u4_mb_num            */\n/*  Processing    :                                                          */\n/*                                                                           */\n/*  Outputs       : Produces the Boundary Strength for Current Mb            */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*                      ITTIAM                                               */\n/*****************************************************************************/\n\nvoid ih264d_compute_bs_non_mbaff_thread(dec_struct_t * ps_dec,\n                                        dec_mb_info_t * ps_cur_mb_info,\n                                        UWORD32 u4_mb_num)\n{\n    /* Mvpred and Nnz for top and Courrent */\n    mv_pred_t *ps_cur_mv_pred, *ps_top_mv_pred = NULL, *ps_left_mv_pred;\n    /* deblk_mb_t Params */\n    deblk_mb_t *ps_cur_mb_params; /*< Parameters of current MacroBlock */\n    deblkmb_neighbour_t *ps_deblk_top_mb;\n\n    /* Reference Index to POC mapping*/\n    void ** apv_map_ref_idx_to_poc;\n    UWORD32 u4_leftmbtype;\n\n    UWORD16 u2_left_csbp, u2_top_csbp, u2_cur_csbp;\n\n    /* Set of flags */\n    UWORD32 u4_cur_mb_intra, u1_top_mb_typ, u4_cur_mb_fld;\n    UWORD32 u1_cur_mb_type;\n    UWORD32 * pu4_bs_table;\n\n    /* Neighbour availability */\n    /* Initialization */\n    const UWORD32 u2_mbx = ps_cur_mb_info->u2_mbx;\n    const UWORD32 u2_mby = ps_cur_mb_info->u2_mby;\n    const UWORD32 u1_pingpong = u2_mbx & 0x01;\n\n    PROFILE_DISABLE_BOUNDARY_STRENGTH()\n    ps_deblk_top_mb = ps_dec->ps_deblk_top_mb + u2_mbx;\n\n    /* Pointer assignment for Current DeblkMB, Current Mv Pred  */\n    ps_cur_mb_params = ps_dec->ps_deblk_pic + u4_mb_num;\n    ps_cur_mv_pred = ps_dec->s_cur_pic.ps_mv + (u4_mb_num << 4);\n\n    apv_map_ref_idx_to_poc =\n                    (void **)ps_dec->ps_computebs_cur_slice->ppv_map_ref_idx_to_poc\n                                    + 1;\n    u1_cur_mb_type = ps_cur_mb_params->u1_mb_type;\n    u1_top_mb_typ = ps_deblk_top_mb->u1_mb_type;\n    ps_deblk_top_mb->u1_mb_type = u1_cur_mb_type;\n\n    {\n        ps_cur_mb_params->u1_topmb_qp = ps_deblk_top_mb->u1_mb_qp;\n        ps_deblk_top_mb->u1_mb_qp = ps_cur_mb_params->u1_mb_qp;\n\n        ps_cur_mb_params->u1_left_mb_qp = ps_dec->deblk_left_mb[1].u1_mb_qp;\n        ps_dec->deblk_left_mb[1].u1_mb_qp = ps_cur_mb_params->u1_mb_qp;\n\n    }\n\n    /* if no deblocking required for current Mb then continue */\n    /* Check next Mbs   in Mb group                           */\n    if(ps_cur_mb_params->u1_deblocking_mode & MB_DISABLE_FILTERING)\n    {\n        void ** pu4_map_ref_idx_to_poc_l1 = apv_map_ref_idx_to_poc +\n        POC_LIST_L0_TO_L1_DIFF;\n        {\n            /* Store Parameter for Top MvPred refernce frame Address */\n\n            void ** ppv_top_mv_pred_addr = ps_cur_mb_info->ps_curmb->u4_pic_addrress;\n            WORD8 * p1_refTop0 = (ps_cur_mv_pred + 12)->i1_ref_frame;\n            WORD8 * p1_refTop1 = (ps_cur_mv_pred + 14)->i1_ref_frame;\n\n            /* Store Left addresses for Next Mb   */\n            void ** ppv_left_mv_pred_addr =\n                            ps_dec->ps_left_mvpred_addr[!u1_pingpong][1].u4_add;\n            WORD8 * p1_refleft0 = (ps_cur_mv_pred + 3)->i1_ref_frame;\n\n\n            ppv_top_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refTop0[0]];\n            ppv_top_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refTop0[1]];\n\n            ppv_left_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_top_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_left_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n            ppv_top_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n\n            ppv_left_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refleft0[0]];\n            ppv_left_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refleft0[1]];\n            //}\n            /* Storing the leftMbtype for next Mb */\n            ps_dec->deblk_left_mb[1].u1_mb_type = ps_cur_mb_params->u1_mb_type;\n        }\n\n        return;\n    }\n\n    /* Flag for extra left Edge */\n    ps_cur_mb_params->u1_single_call = 1;\n\n    /* Update the Left deblk_mb_t and Left MvPred Parameters           */\n    if(!u2_mbx)\n    {\n        u4_leftmbtype = 0;\n\n        /* Initialize the ps_left_mv_pred with Junk but Valid Location */\n        /* to avoid invalid memory access                           */\n        /* this is read only pointer                                */\n        ps_left_mv_pred = ps_cur_mv_pred + 3;\n    }\n    else\n    {\n        u4_leftmbtype = ps_dec->deblk_left_mb[1].u1_mb_type;\n\n        /* Come to Left Most Edge of the MB */\n        ps_left_mv_pred = ps_cur_mv_pred - (1 << 4) + 3;\n    }\n\n    if(!u2_mby)\n        u1_top_mb_typ = 0;\n\n    /* MvPred Pointer Calculation */\n    /* CHANGED CODE */\n    ps_top_mv_pred = ps_cur_mv_pred - (ps_dec->u2_frm_wd_in_mbs << 4) + 12;\n\n    u4_cur_mb_intra = u1_cur_mb_type & D_INTRA_MB;\n    u4_cur_mb_fld = !!(u1_cur_mb_type & D_FLD_MB);\n    /* Compute BS function */\n    pu4_bs_table = ps_cur_mb_params->u4_bs_table;\n\n    u2_cur_csbp = ps_cur_mb_info->ps_curmb->u2_luma_csbp;\n    u2_left_csbp = ps_cur_mb_info->ps_left_mb->u2_luma_csbp;\n    u2_top_csbp = ps_cur_mb_info->ps_top_mb->u2_luma_csbp;\n\n    /* Compute BS function */\n    if(ps_dec->ps_cur_sps->u1_profile_idc == HIGH_PROFILE_IDC)\n    {\n        if(ps_cur_mb_info->u1_tran_form8x8 == 1)\n        {\n            u2_cur_csbp = ih264d_update_csbp_8x8(\n                            ps_cur_mb_info->ps_curmb->u2_luma_csbp);\n        }\n\n        if(ps_cur_mb_info->ps_left_mb->u1_tran_form8x8 == 1)\n        {\n            u2_left_csbp = ih264d_update_csbp_8x8(\n                            ps_cur_mb_info->ps_left_mb->u2_luma_csbp);\n        }\n\n        if(ps_cur_mb_info->ps_top_mb->u1_tran_form8x8 == 1)\n        {\n            u2_top_csbp = ih264d_update_csbp_8x8(\n                            ps_cur_mb_info->ps_top_mb->u2_luma_csbp);\n        }\n    }\n    if(u4_cur_mb_intra)\n    {\n\n        pu4_bs_table[4] = 0x04040404;\n        pu4_bs_table[0] = u4_cur_mb_fld ? 0x03030303 : 0x04040404;\n        pu4_bs_table[1] = 0x03030303;\n        pu4_bs_table[2] = 0x03030303;\n        pu4_bs_table[3] = 0x03030303;\n        pu4_bs_table[5] = 0x03030303;\n        pu4_bs_table[6] = 0x03030303;\n        pu4_bs_table[7] = 0x03030303;\n    }\n    else\n    {\n        UWORD32 u4_is_non16x16 = !!(u1_cur_mb_type & D_PRED_NON_16x16);\n        UWORD32 u4_is_b =\n                        (ps_dec->ps_computebs_cur_slice->slice_type == B_SLICE);\n\n\n\n\n\n\n        ih264d_fill_bs2_horz_vert(pu4_bs_table, u2_left_csbp, u2_top_csbp,\n                                  u2_cur_csbp, gau4_ih264d_packed_bs2,\n                                  gau2_ih264d_4x4_v2h_reorder);\n\n        if(u4_leftmbtype & D_INTRA_MB)\n            pu4_bs_table[4] = 0x04040404;\n\n        if(u1_top_mb_typ & D_INTRA_MB)\n            pu4_bs_table[0] = u4_cur_mb_fld ? 0x03030303 : 0x04040404;\n\n        ps_dec->pf_fill_bs1[u4_is_b][u4_is_non16x16](\n                        ps_cur_mv_pred, ps_top_mv_pred, apv_map_ref_idx_to_poc,\n                        pu4_bs_table, ps_left_mv_pred,\n                        &(ps_dec->ps_left_mvpred_addr[u1_pingpong][1]),\n                        ps_cur_mb_info->ps_top_mb->u4_pic_addrress,\n                        (4 >> u4_cur_mb_fld));\n    }\n\n    {\n        void ** pu4_map_ref_idx_to_poc_l1 = apv_map_ref_idx_to_poc +\n        POC_LIST_L0_TO_L1_DIFF;\n        {\n            /* Store Parameter for Top MvPred refernce frame Address */\n\n            void ** ppv_top_mv_pred_addr = ps_cur_mb_info->ps_curmb->u4_pic_addrress;\n            WORD8 * p1_refTop0 = (ps_cur_mv_pred + 12)->i1_ref_frame;\n            WORD8 * p1_refTop1 = (ps_cur_mv_pred + 14)->i1_ref_frame;\n\n            /* Store Left addresses for Next Mb   */\n            void ** ppv_left_mv_pred_addr =\n                            ps_dec->ps_left_mvpred_addr[!u1_pingpong][1].u4_add;\n            WORD8 * p1_refleft0 = (ps_cur_mv_pred + 3)->i1_ref_frame;\n\n            ppv_top_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refTop0[0]];\n            ppv_top_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refTop0[1]];\n\n            ppv_left_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_top_mv_pred_addr[2] = apv_map_ref_idx_to_poc[p1_refTop1[0]];\n            ppv_left_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n            ppv_top_mv_pred_addr[3] = pu4_map_ref_idx_to_poc_l1[p1_refTop1[1]];\n\n            ppv_left_mv_pred_addr[0] = apv_map_ref_idx_to_poc[p1_refleft0[0]];\n            ppv_left_mv_pred_addr[1] = pu4_map_ref_idx_to_poc_l1[p1_refleft0[1]];\n\n            /* Storing the leftMbtype for next Mb */\n            ps_dec->deblk_left_mb[1].u1_mb_type = ps_cur_mb_params->u1_mb_type;\n\n        }\n    }\n\n    /* For transform 8x8 disable deblocking of the intrernal edges of a 8x8 block */\n    if(ps_cur_mb_info->u1_tran_form8x8)\n    {\n        pu4_bs_table[1] = 0;\n        pu4_bs_table[3] = 0;\n        pu4_bs_table[5] = 0;\n        pu4_bs_table[7] = 0;\n    }\n}\n\n\nvoid ih264d_check_mb_map_deblk(dec_struct_t *ps_dec,\n                                    UWORD32 deblk_mb_grp,\n                                    tfr_ctxt_t *ps_tfr_cxt,\n                                    UWORD32 u4_check_mb_map)\n{\n    UWORD32 i = 0;\n    UWORD32 u4_mb_num;\n    UWORD32 u4_cond;\n    volatile UWORD8 *mb_map = ps_dec->pu1_recon_mb_map;\n    const WORD32 i4_cb_qp_idx_ofst =\n                    ps_dec->ps_cur_pps->i1_chroma_qp_index_offset;\n    const WORD32 i4_cr_qp_idx_ofst =\n                    ps_dec->ps_cur_pps->i1_second_chroma_qp_index_offset;\n\n    UWORD32 u4_wd_y, u4_wd_uv;\n    UWORD8 u1_field_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag;\n\n\n    u4_wd_y = ps_dec->u2_frm_wd_y << u1_field_pic_flag;\n    u4_wd_uv = ps_dec->u2_frm_wd_uv << u1_field_pic_flag;\n\n\n    for(i = 0; i < deblk_mb_grp; i++)\n    {\n        WORD32 nop_cnt = 8*128;\n        while(u4_check_mb_map == 1)\n        {\n            u4_mb_num = ps_dec->u4_cur_deblk_mb_num;\n            /*we wait for the right mb because of intra pred data dependency*/\n            u4_mb_num = MIN(u4_mb_num + 1, (ps_dec->u4_deblk_mb_y + 1) * ps_dec->u2_frm_wd_in_mbs - 1);\n            CHECK_MB_MAP_BYTE(u4_mb_num, mb_map, u4_cond);\n\n            if(u4_cond)\n            {\n                break;\n            }\n            else\n            {\n                if(nop_cnt > 0)\n                {\n                    nop_cnt -= 128;\n                    NOP(128);\n                }\n                else\n                {\n                    nop_cnt = 8*128;\n                    ithread_yield();\n                }\n            }\n        }\n\n        ih264d_deblock_mb_nonmbaff(ps_dec, ps_tfr_cxt,\n                                   i4_cb_qp_idx_ofst, i4_cr_qp_idx_ofst,\n                                    u4_wd_y, u4_wd_uv);\n\n\n    }\n\n\n}\nvoid ih264d_recon_deblk_slice(dec_struct_t *ps_dec, tfr_ctxt_t *ps_tfr_cxt)\n{\n    dec_mb_info_t *p_cur_mb;\n    UWORD32 u4_max_addr;\n    WORD32 i;\n    UWORD32 u1_mb_aff;\n    UWORD16 u2_slice_num;\n    UWORD32 u4_mb_num;\n    UWORD16 u2_first_mb_in_slice;\n    UWORD32 i2_pic_wdin_mbs;\n    UWORD8 u1_num_mbsleft, u1_end_of_row;\n    UWORD8 u1_mbaff;\n    UWORD16 i16_mb_x, i16_mb_y;\n    WORD32 j;\n    dec_mb_info_t * ps_cur_mb_info;\n    UWORD32 u1_slice_type, u1_B;\n    WORD32 u1_skip_th;\n    UWORD32 u1_ipcm_th;\n    WORD32 ret;\n    tfr_ctxt_t *ps_trns_addr;\n    UWORD32 u4_frame_stride;\n    UWORD32 x_offset, y_offset;\n    UWORD32 u4_slice_end;\n    pad_mgr_t *ps_pad_mgr ;\n\n    /*check for mb map of first mb in slice to ensure slice header is parsed*/\n    while(1)\n    {\n        UWORD32 u4_mb_num = ps_dec->cur_recon_mb_num;\n        UWORD32 u4_cond = 0;\n        WORD32 nop_cnt = 8*128;\n\n        CHECK_MB_MAP_BYTE(u4_mb_num, ps_dec->pu1_recon_mb_map, u4_cond);\n        if(u4_cond)\n        {\n            break;\n        }\n        else\n        {\n            if(nop_cnt > 0)\n            {\n                nop_cnt -= 128;\n                NOP(128);\n            }\n            else\n            {\n                if(ps_dec->u4_output_present &&\n                   (ps_dec->u4_fmt_conv_cur_row < ps_dec->s_disp_frame_info.u4_y_ht))\n                {\n                    ps_dec->u4_fmt_conv_num_rows =\n                                    MIN(FMT_CONV_NUM_ROWS,\n                                        (ps_dec->s_disp_frame_info.u4_y_ht\n                                                        - ps_dec->u4_fmt_conv_cur_row));\n                    ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),\n                                          ps_dec->u4_fmt_conv_cur_row,\n                                          ps_dec->u4_fmt_conv_num_rows);\n                    ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;\n                }\n                else\n                {\n                    nop_cnt = 8*128;\n                    ithread_yield();\n                }\n            }\n            DEBUG_THREADS_PRINTF(\"waiting for mb mapcur_dec_mb_num = %d,ps_dec->u2_cur_mb_addr  = %d\\n\",u2_cur_dec_mb_num,\n                            ps_dec->u2_cur_mb_addr);\n\n        }\n    }\n\n    u4_max_addr = ps_dec->ps_cur_sps->u2_max_mb_addr;\n    u1_mb_aff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    u2_first_mb_in_slice = ps_dec->ps_computebs_cur_slice->u4_first_mb_in_slice;\n    i2_pic_wdin_mbs = ps_dec->u2_frm_wd_in_mbs;\n    u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    ps_pad_mgr = &ps_dec->s_pad_mgr;\n\n    if(u2_first_mb_in_slice == 0)\n    ih264d_init_deblk_tfr_ctxt(ps_dec, ps_pad_mgr, ps_tfr_cxt,\n                               ps_dec->u2_frm_wd_in_mbs, 0);\n\n\n    i16_mb_x = MOD(u2_first_mb_in_slice, i2_pic_wdin_mbs);\n    i16_mb_y = DIV(u2_first_mb_in_slice, i2_pic_wdin_mbs);\n    i16_mb_y <<= u1_mbaff;\n    ps_dec->i2_recon_thread_mb_y = i16_mb_y;\n    u4_frame_stride = ps_dec->u2_frm_wd_y\n                    << ps_dec->ps_cur_slice->u1_field_pic_flag;\n\n    x_offset = i16_mb_x << 4;\n    y_offset = (i16_mb_y * u4_frame_stride) << 4;\n    ps_trns_addr = &ps_dec->s_tran_iprecon;\n\n    ps_trns_addr->pu1_dest_y = ps_dec->s_cur_pic.pu1_buf1 + x_offset + y_offset;\n\n    u4_frame_stride = ps_dec->u2_frm_wd_uv\n                    << ps_dec->ps_cur_slice->u1_field_pic_flag;\n    x_offset >>= 1;\n    y_offset = (i16_mb_y * u4_frame_stride) << 3;\n\n    x_offset *= YUV420SP_FACTOR;\n\n    ps_trns_addr->pu1_dest_u = ps_dec->s_cur_pic.pu1_buf2 + x_offset + y_offset;\n    ps_trns_addr->pu1_dest_v = ps_dec->s_cur_pic.pu1_buf3 + x_offset + y_offset;\n\n    ps_trns_addr->pu1_mb_y = ps_trns_addr->pu1_dest_y;\n    ps_trns_addr->pu1_mb_u = ps_trns_addr->pu1_dest_u;\n    ps_trns_addr->pu1_mb_v = ps_trns_addr->pu1_dest_v;\n\n    ps_dec->cur_recon_mb_num = u2_first_mb_in_slice << u1_mbaff;\n\n    u4_slice_end = 0;\n    ps_dec->u4_bs_cur_slice_num_mbs = 0;\n    ps_dec->u4_cur_bs_mb_num =\n                    (ps_dec->ps_computebs_cur_slice->u4_first_mb_in_slice)\n                                    << u1_mb_aff;\n\n    if(ps_dec->i1_recon_in_thread3_flag)\n    {\n        ps_dec->pv_proc_tu_coeff_data =\n                (void *) ps_dec->ps_computebs_cur_slice->pv_tu_coeff_data_start;\n    }\n\n    u1_slice_type = ps_dec->ps_computebs_cur_slice->slice_type;\n\n    u1_B = (u1_slice_type == B_SLICE);\n\n    u1_skip_th = ((u1_slice_type != I_SLICE) ?\n                                    (u1_B ? B_8x8 : PRED_8x8R0) : -1);\n\n    u1_ipcm_th = ((u1_slice_type != I_SLICE) ? (u1_B ? 23 : 5) : 0);\n\n\n\n    while(u4_slice_end != 1)\n    {\n        WORD32 recon_mb_grp,bs_mb_grp;\n        WORD32 nop_cnt = 8*128;\n        u1_num_mbsleft = ((i2_pic_wdin_mbs - i16_mb_x) << u1_mbaff);\n        if(u1_num_mbsleft <= ps_dec->u1_recon_mb_grp)\n        {\n            recon_mb_grp = u1_num_mbsleft;\n            u1_end_of_row = 1;\n            i16_mb_x = 0;\n        }\n        else\n        {\n            recon_mb_grp = ps_dec->u1_recon_mb_grp;\n            u1_end_of_row = 0;\n            i16_mb_x += (recon_mb_grp >> u1_mbaff);\n        }\n\n\n        while(1)\n        {\n            UWORD32 u4_cond = 0;\n            UWORD32 u4_mb_num = ps_dec->cur_recon_mb_num + recon_mb_grp - 1;\n\n            /*\n             * Wait for one extra mb of MC, because some chroma IQ-IT functions\n             * sometimes loads the pixels of the right mb and stores with the loaded\n             * values.\n             */\n            u4_mb_num = MIN(u4_mb_num + 1, (ps_dec->i2_recon_thread_mb_y + 1) * i2_pic_wdin_mbs - 1);\n\n            CHECK_MB_MAP_BYTE(u4_mb_num, ps_dec->pu1_recon_mb_map, u4_cond);\n            if(u4_cond)\n            {\n                break;\n            }\n            else\n            {\n                if(nop_cnt > 0)\n                {\n                    nop_cnt -= 128;\n                    NOP(128);\n                }\n                else\n                {\n                    if(ps_dec->u4_output_present &&\n                       (ps_dec->u4_fmt_conv_cur_row < ps_dec->s_disp_frame_info.u4_y_ht))\n                    {\n                        ps_dec->u4_fmt_conv_num_rows =\n                                        MIN(FMT_CONV_NUM_ROWS,\n                                            (ps_dec->s_disp_frame_info.u4_y_ht\n                                                            - ps_dec->u4_fmt_conv_cur_row));\n                        ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),\n                                              ps_dec->u4_fmt_conv_cur_row,\n                                              ps_dec->u4_fmt_conv_num_rows);\n                        ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;\n                    }\n                    else\n                    {\n                        nop_cnt = 8*128;\n                        ithread_yield();\n                    }\n                }\n            }\n        }\n\n        for(j = 0; j < recon_mb_grp; j++)\n        {\n            GET_SLICE_NUM_MAP(ps_dec->pu2_slice_num_map, ps_dec->cur_recon_mb_num,\n                              u2_slice_num);\n\n            if(u2_slice_num != ps_dec->u2_cur_slice_num_bs)\n            {\n                u4_slice_end = 1;\n                break;\n            }\n            if(ps_dec->i1_recon_in_thread3_flag)\n            {\n                ps_cur_mb_info = &ps_dec->ps_frm_mb_info[ps_dec->cur_recon_mb_num];\n\n                if(ps_cur_mb_info->u1_mb_type <= u1_skip_th)\n                {\n                    ih264d_process_inter_mb(ps_dec, ps_cur_mb_info, j);\n                }\n                else if(ps_cur_mb_info->u1_mb_type != MB_SKIP)\n                {\n                    if((u1_ipcm_th + 25) != ps_cur_mb_info->u1_mb_type)\n                    {\n                        ps_cur_mb_info->u1_mb_type -= (u1_skip_th + 1);\n                        ih264d_process_intra_mb(ps_dec, ps_cur_mb_info, j);\n                    }\n                }\n\n                ih264d_copy_intra_pred_line(ps_dec, ps_cur_mb_info, j);\n            }\n            ps_dec->cur_recon_mb_num++;\n        }\n\n        if(j != recon_mb_grp)\n        {\n            u1_end_of_row = 0;\n        }\n\n        {\n            tfr_ctxt_t *ps_trns_addr = &ps_dec->s_tran_iprecon;\n            UWORD16 u2_mb_y;\n\n            ps_trns_addr->pu1_dest_y += ps_trns_addr->u4_inc_y[u1_end_of_row];\n            ps_trns_addr->pu1_dest_u += ps_trns_addr->u4_inc_uv[u1_end_of_row];\n            ps_trns_addr->pu1_dest_v += ps_trns_addr->u4_inc_uv[u1_end_of_row];\n\n            if(u1_end_of_row)\n            {\n                ps_dec->i2_recon_thread_mb_y += (1 << u1_mbaff);\n                u2_mb_y = ps_dec->i2_recon_thread_mb_y;\n                y_offset = (u2_mb_y * u4_frame_stride) << 4;\n                ps_trns_addr->pu1_dest_y = ps_dec->s_cur_pic.pu1_buf1 + y_offset;\n\n                u4_frame_stride = ps_dec->u2_frm_wd_uv\n                                << ps_dec->ps_cur_slice->u1_field_pic_flag;\n                y_offset = (u2_mb_y * u4_frame_stride) << 3;\n                ps_trns_addr->pu1_dest_u = ps_dec->s_cur_pic.pu1_buf2 + y_offset;\n                ps_trns_addr->pu1_dest_v = ps_dec->s_cur_pic.pu1_buf3 + y_offset;\n\n                ps_trns_addr->pu1_mb_y = ps_trns_addr->pu1_dest_y;\n                ps_trns_addr->pu1_mb_u = ps_trns_addr->pu1_dest_u;\n                ps_trns_addr->pu1_mb_v = ps_trns_addr->pu1_dest_v;\n\n            }\n        }\n\n        bs_mb_grp = j;\n        /* Compute BS for NMB group*/\n        for(i = 0; i < bs_mb_grp; i++)\n        {\n            p_cur_mb = &ps_dec->ps_frm_mb_info[ps_dec->u4_cur_bs_mb_num];\n\n            DEBUG_THREADS_PRINTF(\"ps_dec->u4_cur_bs_mb_num = %d\\n\",ps_dec->u4_cur_bs_mb_num);\n            ih264d_compute_bs_non_mbaff_thread(ps_dec, p_cur_mb,\n                                               ps_dec->u4_cur_bs_mb_num);\n            ps_dec->u4_cur_bs_mb_num++;\n            ps_dec->u4_bs_cur_slice_num_mbs++;\n\n        }\n\n        if(ps_dec->u4_cur_bs_mb_num > u4_max_addr)\n        {\n            u4_slice_end = 1;\n        }\n\n        /*deblock MB group*/\n        {\n            UWORD32 u4_num_mbs;\n\n            if(ps_dec->u4_cur_bs_mb_num > ps_dec->u4_cur_deblk_mb_num)\n            {\n                if(u1_end_of_row)\n                {\n                    u4_num_mbs = ps_dec->u4_cur_bs_mb_num\n                                    - ps_dec->u4_cur_deblk_mb_num;\n                }\n                else\n                {\n                    u4_num_mbs = ps_dec->u4_cur_bs_mb_num\n                                    - ps_dec->u4_cur_deblk_mb_num - 1;\n                }\n            }\n            else\n                u4_num_mbs = 0;\n\n            ih264d_check_mb_map_deblk(ps_dec, u4_num_mbs, ps_tfr_cxt,0);\n        }\n\n    }\n}\n\nvoid ih264d_recon_deblk_thread(dec_struct_t *ps_dec)\n{\n    tfr_ctxt_t s_tfr_ctxt;\n    tfr_ctxt_t *ps_tfr_cxt = &s_tfr_ctxt; // = &ps_dec->s_tran_addrecon;\n\n\n    UWORD32 yield_cnt = 0;\n\n    ithread_set_name(\"ih264d_recon_deblk_thread\");\n\n    while(1)\n    {\n\n        DEBUG_THREADS_PRINTF(\" Entering compute bs slice\\n\");\n        ih264d_recon_deblk_slice(ps_dec, ps_tfr_cxt);\n\n        DEBUG_THREADS_PRINTF(\" Exit  compute bs slice \\n\");\n\n        if(ps_dec->cur_recon_mb_num > ps_dec->ps_cur_sps->u2_max_mb_addr)\n        {\n                break;\n        }\n        else\n        {\n            ps_dec->ps_computebs_cur_slice++;\n            ps_dec->u2_cur_slice_num_bs++;\n        }\n        DEBUG_THREADS_PRINTF(\"CBS thread:Got next slice/end of frame signal \\n \");\n\n    }\n\n    if(ps_dec->u4_output_present &&\n       (3 == ps_dec->u4_num_cores) &&\n       (ps_dec->u4_fmt_conv_cur_row < ps_dec->s_disp_frame_info.u4_y_ht))\n    {\n        ps_dec->u4_fmt_conv_num_rows =\n                        (ps_dec->s_disp_frame_info.u4_y_ht\n                                        - ps_dec->u4_fmt_conv_cur_row);\n        ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),\n                              ps_dec->u4_fmt_conv_cur_row,\n                              ps_dec->u4_fmt_conv_num_rows);\n        ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;\n\n    }\n\n\n\n}\n\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_thread_compute_bs.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*\n * ih264d_thread_parse_decode.h\n *\n *  Created on: Feb 21, 2012\n *      Author: 100492\n */\n\n#ifndef _IH264D_THREAD_COMPUTE_BS_H_\n#define _IH264D_THREAD_COMPUTE_BS_H_\nvoid ih264d_compute_bs_non_mbaff_thread(dec_struct_t * ps_dec,\n                                        dec_mb_info_t * ps_cur_mb_info,\n                                        UWORD32 u4_mb_num);\n\nvoid ih264d_recon_deblk_thread(dec_struct_t *ps_dec);\nvoid ih264d_check_mb_map_deblk(dec_struct_t *ps_dec,\n                                    UWORD32 deblk_mb_grp,\n                                    tfr_ctxt_t *ps_tfr_cxt,\n                                    UWORD32 u4_check_mb_map);\n#endif /* _IH264D_THREAD_COMPUTE_BS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_thread_parse_decode.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n * \\file ih264d_thread_parse_decode.c\n *\n * \\brief\n *    Contains routines that for multi-thread decoder\n *\n * Detailed_description\n *\n * \\date\n *    20/02/2012\n *\n * \\author  ZR\n **************************************************************************\n */\n\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_debug.h\"\n#include \"ithread.h\"\n#include <string.h>\n#include \"ih264d_defs.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_thread_parse_decode.h\"\n#include \"ih264d_inter_pred.h\"\n\n#include \"ih264d_process_pslice.h\"\n#include \"ih264d_process_intra_mb.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_format_conv.h\"\n\nvoid ih264d_deblock_mb_level(dec_struct_t *ps_dec,\n                             dec_mb_info_t *ps_cur_mb_info,\n                             UWORD32 nmb_index);\n\nvoid ih264d_copy_intra_pred_line(dec_struct_t *ps_dec,\n                                 dec_mb_info_t *ps_cur_mb_info,\n                                 UWORD32 nmb_index);\n\nvoid ih264d_parse_tfr_nmb(dec_struct_t * ps_dec,\n                          UWORD8 u1_mb_idx,\n                          UWORD8 u1_num_mbs,\n                          UWORD8 u1_num_mbs_next,\n                          UWORD8 u1_tfr_n_mb,\n                          UWORD8 u1_end_of_row)\n{\n    WORD32 i, u4_mb_num;\n\n    const UWORD32 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    UWORD32 u4_n_mb_start;\n\n    UNUSED(u1_mb_idx);\n    UNUSED(u1_num_mbs_next);\n    if(u1_tfr_n_mb)\n    {\n\n\n        u4_n_mb_start = (ps_dec->u2_cur_mb_addr + 1) - u1_num_mbs;\n\n        // copy into s_frmMbInfo\n\n        u4_mb_num = u4_n_mb_start;\n        u4_mb_num = (ps_dec->u2_cur_mb_addr + 1) - u1_num_mbs;\n\n        for(i = 0; i < u1_num_mbs; i++)\n        {\n            UPDATE_SLICE_NUM_MAP(ps_dec->pu2_slice_num_map, u4_mb_num,\n                                 ps_dec->u2_cur_slice_num);\n            DATA_SYNC();\n            UPDATE_MB_MAP_MBNUM_BYTE(ps_dec->pu1_dec_mb_map, u4_mb_num);\n\n            u4_mb_num++;\n        }\n\n        /****************************************************************/\n        /* Check for End Of Row in Next iteration                       */\n        /****************************************************************/\n\n        /****************************************************************/\n        /* Transfer the Following things                                */\n        /* N-Mb DeblkParams Data    ( To Ext DeblkParams Buffer )       */\n        /* N-Mb Recon Data          ( To Ext Frame Buffer )             */\n        /* N-Mb Intrapredline Data  ( Updated Internally)               */\n        /* N-Mb MV Data             ( To Ext MV Buffer )                */\n        /* N-Mb MVTop/TopRight Data ( To Int MV Top Scratch Buffers)    */\n        /****************************************************************/\n\n        /* Swap top and current pointers */\n\n        ps_dec->s_tran_addrecon_parse.pu1_dest_y +=\n                        ps_dec->s_tran_addrecon_parse.u4_inc_y[u1_end_of_row];\n        ps_dec->s_tran_addrecon_parse.pu1_dest_u +=\n                        ps_dec->s_tran_addrecon_parse.u4_inc_uv[u1_end_of_row];\n        ps_dec->s_tran_addrecon_parse.pu1_dest_v +=\n                        ps_dec->s_tran_addrecon_parse.u4_inc_uv[u1_end_of_row];\n\n        if(u1_end_of_row)\n        {\n            UWORD16 u2_mb_y;\n            UWORD32 u4_frame_stride, y_offset;\n\n            ps_dec->ps_top_mb_row = ps_dec->ps_cur_mb_row;\n            ps_dec->ps_cur_mb_row += ((ps_dec->u2_frm_wd_in_mbs) << u1_mbaff);\n\n            u2_mb_y = ps_dec->u2_mby + (1 + u1_mbaff);\n            u4_frame_stride = ps_dec->u2_frm_wd_y\n                            << ps_dec->ps_cur_slice->u1_field_pic_flag;\n            y_offset = (u2_mb_y * u4_frame_stride) << 4;\n            ps_dec->s_tran_addrecon_parse.pu1_dest_y =\n                            ps_dec->s_cur_pic.pu1_buf1 + y_offset;\n\n            u4_frame_stride = ps_dec->u2_frm_wd_uv\n                            << ps_dec->ps_cur_slice->u1_field_pic_flag;\n            y_offset = (u2_mb_y * u4_frame_stride) << 3;\n            ps_dec->s_tran_addrecon_parse.pu1_dest_u =\n                            ps_dec->s_cur_pic.pu1_buf2 + y_offset;\n            ps_dec->s_tran_addrecon_parse.pu1_dest_v =\n                            ps_dec->s_cur_pic.pu1_buf3 + y_offset;\n\n        }\n\n        ps_dec->ps_deblk_mbn += u1_num_mbs;\n\n        /*\n         * The Slice boundary is also a valid condition to transfer. So recalculate\n         * the Left increment, in case the number of MBs is lesser than the\n         * N MB value. c_numMbs will be equal to N of N MB if the entire N Mb is\n         * decoded.\n         */\n        ps_dec->s_tran_addrecon.u2_mv_left_inc = ((u1_num_mbs >> u1_mbaff) - 1)\n                        << (4 + u1_mbaff);\n        ps_dec->s_tran_addrecon.u2_mv_top_left_inc = (u1_num_mbs << 2) - 1\n                        - (u1_mbaff << 2);\n\n        /* reassign left MV and cur MV pointers */\n        ps_dec->ps_mv_left = ps_dec->ps_mv_cur\n                        + ps_dec->s_tran_addrecon.u2_mv_left_inc;\n\n        ps_dec->ps_mv_cur += (u1_num_mbs << 4);\n        ps_dec->u4_num_mbs_prev_nmb = u1_num_mbs;\n\n    }\n}\n\nvoid ih264d_decode_tfr_nmb(dec_struct_t * ps_dec,\n                           UWORD8 u1_num_mbs,\n                           UWORD8 u1_num_mbs_next,\n                           UWORD8 u1_end_of_row)\n{\n\n    UWORD32 u1_end_of_row_next;\n\n    const UWORD32 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n\n    /****************************************************************/\n    /* Check for End Of Row in Next iteration                       */\n    /****************************************************************/\n    u1_end_of_row_next = u1_num_mbs_next &&\n                        ((u1_num_mbs_next) <= (ps_dec->u1_recon_mb_grp >> u1_mbaff));\n\n    /****************************************************************/\n    /* Transfer the Following things                                */\n    /* N-Mb DeblkParams Data    ( To Ext DeblkParams Buffer )       */\n    /* N-Mb Recon Data          ( To Ext Frame Buffer )             */\n    /* N-Mb Intrapredline Data  ( Updated Internally)               */\n    /* N-Mb MV Data             ( To Ext MV Buffer )                */\n    /* N-Mb MVTop/TopRight Data ( To Int MV Top Scratch Buffers)    */\n    /****************************************************************/\n    if(u1_end_of_row)\n    {\n        ps_dec->i2_dec_thread_mb_y += (1 << u1_mbaff);\n    }\n    ih264d_transfer_mb_group_data(ps_dec, u1_num_mbs, u1_end_of_row,\n                                  u1_end_of_row_next);\n\n}\n\nWORD32 ih264d_decode_recon_tfr_nmb_thread(dec_struct_t * ps_dec,\n                                          UWORD8 u1_num_mbs,\n                                          UWORD8 u1_num_mbs_next,\n                                          UWORD8 u1_end_of_row)\n{\n    WORD32 i,j;\n    dec_mb_info_t * ps_cur_mb_info;\n    UWORD32 u4_update_mbaff = 0;\n    const UWORD32 u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n    UWORD32 u1_slice_type, u1_B;\n    WORD32 u1_skip_th;\n    UWORD32 u1_ipcm_th;\n    UWORD32 u4_cond;\n    UWORD16 u2_slice_num,u2_cur_dec_mb_num;\n    WORD32 ret;\n    UWORD32 u4_mb_num;\n    WORD32 nop_cnt = 8*128;\n    u1_slice_type = ps_dec->ps_decode_cur_slice->slice_type;\n\n    u1_B = (u1_slice_type == B_SLICE);\n\n    u1_skip_th = ((u1_slice_type != I_SLICE) ?\n                                    (u1_B ? B_8x8 : PRED_8x8R0) : -1);\n\n    u1_ipcm_th = ((u1_slice_type != I_SLICE) ? (u1_B ? 23 : 5) : 0);\n\n    u2_cur_dec_mb_num = ps_dec->cur_dec_mb_num;\n\n    while(1)\n    {\n\n        UWORD32 u4_max_mb = (UWORD32)(ps_dec->i2_dec_thread_mb_y + (1 << u1_mbaff)) * ps_dec->u2_frm_wd_in_mbs - 1;\n        u4_mb_num = u2_cur_dec_mb_num;\n        /*introducing 1 MB delay*/\n        u4_mb_num = MIN(u4_mb_num + u1_num_mbs + 1, u4_max_mb);\n\n        CHECK_MB_MAP_BYTE(u4_mb_num, ps_dec->pu1_dec_mb_map, u4_cond);\n        if(u4_cond)\n        {\n            break;\n        }\n        else\n        {\n            if(nop_cnt > 0)\n            {\n                nop_cnt -= 128;\n                NOP(128);\n            }\n            else\n            {\n                if(ps_dec->u4_output_present && (2 == ps_dec->u4_num_cores) &&\n                   (ps_dec->u4_fmt_conv_cur_row < ps_dec->s_disp_frame_info.u4_y_ht))\n                {\n                    ps_dec->u4_fmt_conv_num_rows =\n                                MIN(FMT_CONV_NUM_ROWS,\n                                    (ps_dec->s_disp_frame_info.u4_y_ht\n                                                    - ps_dec->u4_fmt_conv_cur_row));\n                    ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),\n                                          ps_dec->u4_fmt_conv_cur_row,\n                                          ps_dec->u4_fmt_conv_num_rows);\n                    ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;\n                }\n                else\n                {\n                    nop_cnt = 8*128;\n                    ithread_yield();\n                }\n            }\n        }\n    }\n    /* N Mb MC Loop */\n    for(i = 0; i < u1_num_mbs; i++)\n    {\n        u4_mb_num = u2_cur_dec_mb_num;\n\n        GET_SLICE_NUM_MAP(ps_dec->pu2_slice_num_map, u2_cur_dec_mb_num,\n                          u2_slice_num);\n\n        if(u2_slice_num != ps_dec->u2_cur_slice_num_dec_thread)\n        {\n            ps_dec->u4_cur_slice_decode_done = 1;\n            break;\n        }\n\n        ps_cur_mb_info = &ps_dec->ps_frm_mb_info[u2_cur_dec_mb_num];\n\n        ps_dec->u4_dma_buf_idx = 0;\n        ps_dec->u4_pred_info_idx = 0;\n\n        if(ps_cur_mb_info->u1_mb_type <= u1_skip_th)\n        {\n            WORD32 pred_cnt = 0;\n            pred_info_pkd_t *ps_pred_pkd;\n            UWORD32 u4_pred_info_pkd_idx;\n            WORD8 i1_pred;\n\n            u4_pred_info_pkd_idx = ps_cur_mb_info->u4_pred_info_pkd_idx;\n\n            while(pred_cnt < ps_cur_mb_info->u1_num_pred_parts)\n            {\n                ps_pred_pkd = ps_dec->ps_pred_pkd + u4_pred_info_pkd_idx;\n\n                ps_dec->p_form_mb_part_info_thread(ps_pred_pkd,ps_dec,\n                                                   ps_cur_mb_info->u2_mbx,\n                                                   ps_cur_mb_info->u2_mby,\n                                                   (i >> u1_mbaff),\n                                                   ps_cur_mb_info);\n\n                u4_pred_info_pkd_idx++;\n                pred_cnt++;\n            }\n            ps_dec->p_mc_dec_thread(ps_dec, ps_cur_mb_info);\n        }\n        else if(ps_cur_mb_info->u1_mb_type == MB_SKIP)\n        {\n            WORD32 pred_cnt = 0;\n            pred_info_pkd_t *ps_pred_pkd;\n            UWORD32 u4_pred_info_pkd_idx;\n            WORD8 i1_pred;\n\n            u4_pred_info_pkd_idx = ps_cur_mb_info->u4_pred_info_pkd_idx;\n\n            while(pred_cnt < ps_cur_mb_info->u1_num_pred_parts)\n            {\n                ps_pred_pkd = ps_dec->ps_pred_pkd + u4_pred_info_pkd_idx;\n\n                ps_dec->p_form_mb_part_info_thread(ps_pred_pkd,ps_dec,\n                                                   ps_cur_mb_info->u2_mbx,\n                                                   ps_cur_mb_info->u2_mby,\n                                                   (i >> u1_mbaff),\n                                                   ps_cur_mb_info);\n\n                u4_pred_info_pkd_idx++;\n                pred_cnt++;\n            }\n            /* Decode MB skip */\n            ps_dec->p_mc_dec_thread(ps_dec, ps_cur_mb_info);\n        }\n\n        u2_cur_dec_mb_num++;\n    }\n\n    /* N Mb IQ IT RECON  Loop */\n    for(j = 0; j < i; j++)\n    {\n        ps_cur_mb_info = &ps_dec->ps_frm_mb_info[ps_dec->cur_dec_mb_num];\n\n        if((ps_dec->u4_num_cores == 2) || !ps_dec->i1_recon_in_thread3_flag)\n        {\n            if(ps_cur_mb_info->u1_mb_type <= u1_skip_th)\n            {\n                ih264d_process_inter_mb(ps_dec, ps_cur_mb_info, j);\n            }\n            else if(ps_cur_mb_info->u1_mb_type != MB_SKIP)\n            {\n                if((u1_ipcm_th + 25) != ps_cur_mb_info->u1_mb_type)\n                {\n                    ps_cur_mb_info->u1_mb_type -= (u1_skip_th + 1);\n                    ih264d_process_intra_mb(ps_dec, ps_cur_mb_info, j);\n                }\n            }\n\n\n         if(ps_dec->u4_use_intrapred_line_copy == 1)\n                ih264d_copy_intra_pred_line(ps_dec, ps_cur_mb_info, j);\n        }\n\n        DATA_SYNC();\n\n        if(u1_mbaff)\n        {\n            if(u4_update_mbaff)\n            {\n                UWORD32 u4_mb_num = ps_cur_mb_info->u2_mbx\n                                + ps_dec->u2_frm_wd_in_mbs\n                                                * (ps_cur_mb_info->u2_mby >> 1);\n                UPDATE_MB_MAP_MBNUM_BYTE(ps_dec->pu1_recon_mb_map, u4_mb_num);\n                u4_update_mbaff = 0;\n            }\n            else\n            {\n                u4_update_mbaff = 1;\n            }\n        }\n        else\n        {\n            UWORD32 u4_mb_num = ps_cur_mb_info->u2_mbx\n                            + ps_dec->u2_frm_wd_in_mbs * ps_cur_mb_info->u2_mby;\n            UPDATE_MB_MAP_MBNUM_BYTE(ps_dec->pu1_recon_mb_map, u4_mb_num);\n        }\n        ps_dec->cur_dec_mb_num++;\n     }\n\n    /*N MB deblocking*/\n    if(ps_dec->u4_nmb_deblk == 1)\n    {\n        UWORD32 u4_wd_y, u4_wd_uv;\n        tfr_ctxt_t *ps_tfr_cxt = &(ps_dec->s_tran_addrecon);\n        UWORD8 u1_field_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag;\n        const WORD32 i4_cb_qp_idx_ofst =\n                       ps_dec->ps_cur_pps->i1_chroma_qp_index_offset;\n        const WORD32 i4_cr_qp_idx_ofst =\n                       ps_dec->ps_cur_pps->i1_second_chroma_qp_index_offset;\n\n        u4_wd_y = ps_dec->u2_frm_wd_y << u1_field_pic_flag;\n        u4_wd_uv = ps_dec->u2_frm_wd_uv << u1_field_pic_flag;\n\n        ps_cur_mb_info = &ps_dec->ps_frm_mb_info[ps_dec->u4_cur_deblk_mb_num];\n\n        ps_dec->u4_deblk_mb_x = ps_cur_mb_info->u2_mbx;\n        ps_dec->u4_deblk_mb_y = ps_cur_mb_info->u2_mby;\n\n\n        for(j = 0; j < i; j++)\n        {\n            ih264d_deblock_mb_nonmbaff(ps_dec, ps_tfr_cxt,\n                                       i4_cb_qp_idx_ofst, i4_cr_qp_idx_ofst,\n                                        u4_wd_y, u4_wd_uv);\n\n        }\n    }\n\n    /*handle the last mb in picture case*/\n    if(ps_dec->cur_dec_mb_num > ps_dec->ps_cur_sps->u2_max_mb_addr)\n        ps_dec->u4_cur_slice_decode_done = 1;\n\n    if(i != u1_num_mbs)\n    {\n        u1_end_of_row = 0;\n        /*Number of MB's left in row*/\n        u1_num_mbs_next = u1_num_mbs_next + ((u1_num_mbs - i) >> u1_mbaff);\n    }\n\n    ih264d_decode_tfr_nmb(ps_dec, (i), u1_num_mbs_next, u1_end_of_row);\n\n    return OK;\n}\n\nWORD32 ih264d_decode_slice_thread(dec_struct_t *ps_dec)\n{\n    UWORD8 u1_num_mbs_next, u1_num_mbsleft, u1_end_of_row = 0;\n    const UWORD32 i2_pic_wdin_mbs = ps_dec->u2_frm_wd_in_mbs;\n    UWORD8 u1_mbaff, u1_num_mbs;\n\n    UWORD16 u2_first_mb_in_slice;\n    UWORD16 i16_mb_x, i16_mb_y;\n    UWORD8 u1_field_pic;\n    UWORD32 u4_frame_stride, x_offset, y_offset;\n    WORD32 ret;\n\n    tfr_ctxt_t *ps_trns_addr;\n\n    /*check for mb map of first mb in slice to ensure slice header is parsed*/\n    while(1)\n    {\n        UWORD32 u4_mb_num = ps_dec->cur_dec_mb_num;\n        UWORD32 u4_cond = 0;\n        WORD32 nop_cnt = 8 * 128;\n        CHECK_MB_MAP_BYTE(u4_mb_num, ps_dec->pu1_dec_mb_map, u4_cond);\n        if(u4_cond)\n        {\n            break;\n        }\n        else\n        {\n            if(nop_cnt > 0)\n            {\n                nop_cnt -= 128;\n                NOP(128);\n            }\n            else if(ps_dec->u4_output_present && (2 == ps_dec->u4_num_cores) &&\n               (ps_dec->u4_fmt_conv_cur_row < ps_dec->s_disp_frame_info.u4_y_ht))\n            {\n                ps_dec->u4_fmt_conv_num_rows =\n                                MIN(FMT_CONV_NUM_ROWS,\n                                    (ps_dec->s_disp_frame_info.u4_y_ht\n                                                    - ps_dec->u4_fmt_conv_cur_row));\n                ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),\n                                      ps_dec->u4_fmt_conv_cur_row,\n                                      ps_dec->u4_fmt_conv_num_rows);\n                ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;\n            }\n            else\n            {\n                nop_cnt = 8*128;\n                ithread_yield();\n            }\n            DEBUG_THREADS_PRINTF(\"waiting for mb mapcur_dec_mb_num = %d,ps_dec->u2_cur_mb_addr  = %d\\n\",u2_cur_dec_mb_num,\n                            ps_dec->u2_cur_mb_addr);\n\n        }\n    }\n\n\n\n    u1_mbaff = ps_dec->ps_cur_slice->u1_mbaff_frame_flag;\n\n    u2_first_mb_in_slice = ps_dec->ps_decode_cur_slice->u4_first_mb_in_slice;\n\n    i16_mb_x = MOD(u2_first_mb_in_slice, i2_pic_wdin_mbs);\n    i16_mb_y = DIV(u2_first_mb_in_slice, i2_pic_wdin_mbs);\n    i16_mb_y <<= u1_mbaff;\n    ps_dec->i2_dec_thread_mb_y = i16_mb_y;\n\n\n    ps_dec->cur_dec_mb_num = u2_first_mb_in_slice << u1_mbaff;\n\n    if((ps_dec->u4_num_cores == 2) || !ps_dec->i1_recon_in_thread3_flag)\n    {\n        ps_dec->pv_proc_tu_coeff_data =\n                (void *) ps_dec->ps_decode_cur_slice->pv_tu_coeff_data_start;\n    }\n\n    // recalculate recon pointers\n    u1_field_pic = ps_dec->ps_cur_slice->u1_field_pic_flag;\n    u4_frame_stride = ps_dec->u2_frm_wd_y << u1_field_pic;\n    x_offset = i16_mb_x << 4;\n    y_offset = (i16_mb_y * u4_frame_stride) << 4;\n\n    ps_trns_addr = &(ps_dec->s_tran_addrecon);\n\n    ps_trns_addr->pu1_dest_y = ps_dec->s_cur_pic.pu1_buf1 + x_offset + y_offset;\n\n    u4_frame_stride = ps_dec->u2_frm_wd_uv << u1_field_pic;\n    x_offset >>= 1;\n    y_offset = (i16_mb_y * u4_frame_stride) << 3;\n\n    x_offset *= YUV420SP_FACTOR;\n\n    ps_trns_addr->pu1_dest_u = ps_dec->s_cur_pic.pu1_buf2 + x_offset + y_offset;\n    ps_trns_addr->pu1_dest_v = ps_dec->s_cur_pic.pu1_buf3 + x_offset + y_offset;\n\n    ps_trns_addr->pu1_mb_y = ps_trns_addr->pu1_dest_y;\n    ps_trns_addr->pu1_mb_u = ps_trns_addr->pu1_dest_u;\n    ps_trns_addr->pu1_mb_v = ps_trns_addr->pu1_dest_v;\n\n\n    /* Initialise MC and formMbPartInfo fn ptrs one time based on profile_idc */\n    {\n        ps_dec->p_mc_dec_thread = ih264d_motion_compensate_bp;\n        ps_dec->p_form_mb_part_info_thread = ih264d_form_mb_part_info_bp;\n    }\n    {\n        UWORD8 uc_nofield_nombaff;\n        uc_nofield_nombaff = ((ps_dec->ps_cur_slice->u1_field_pic_flag == 0)\n                        && (ps_dec->ps_cur_slice->u1_mbaff_frame_flag == 0)\n                        && (ps_dec->ps_decode_cur_slice->slice_type != B_SLICE)\n                        && (ps_dec->ps_cur_pps->u1_wted_pred_flag == 0));\n\n        if(uc_nofield_nombaff == 0)\n        {\n            ps_dec->p_mc_dec_thread = ih264d_motion_compensate_mp;\n            ps_dec->p_form_mb_part_info_thread = ih264d_form_mb_part_info_mp;\n        }\n\n    }\n\n    ps_dec->u4_cur_slice_decode_done = 0;\n\n\n    while(ps_dec->u4_cur_slice_decode_done != 1)\n    {\n\n        u1_num_mbsleft = ((i2_pic_wdin_mbs - i16_mb_x) << u1_mbaff);\n\n        if(u1_num_mbsleft <= ps_dec->u1_recon_mb_grp)\n        {\n            u1_num_mbs = u1_num_mbsleft;\n\n            /*Indicate number of mb's left in a row*/\n            u1_num_mbs_next = 0;\n            u1_end_of_row = 1;\n            i16_mb_x = 0;\n        }\n        else\n        {\n            u1_num_mbs = ps_dec->u1_recon_mb_grp;\n\n            /*Indicate number of mb's left in a row*/\n            u1_num_mbs_next = i2_pic_wdin_mbs - i16_mb_x\n                            - (ps_dec->u1_recon_mb_grp >> u1_mbaff);\n            i16_mb_x += (u1_num_mbs >> u1_mbaff);\n            u1_end_of_row = 0;\n\n        }\n        ret = ih264d_decode_recon_tfr_nmb_thread(ps_dec, u1_num_mbs, u1_num_mbs_next,\n                                           u1_end_of_row);\n        if(ret != OK)\n            return ret;\n    }\n    return OK;\n}\n\nvoid ih264d_decode_picture_thread(dec_struct_t *ps_dec )\n{\n    ithread_set_name(\"ih264d_decode_picture_thread\");\n    while(1)\n    {\n        /*Complete all writes before processing next slice*/\n\n        DEBUG_THREADS_PRINTF(\" Entering decode slice\\n\");\n\n        ih264d_decode_slice_thread(ps_dec);\n        DEBUG_THREADS_PRINTF(\" Exit  ih264d_decode_slice_thread \\n\");\n\n\n        if(ps_dec->cur_dec_mb_num\n                        > ps_dec->ps_cur_sps->u2_max_mb_addr)\n        {\n            /*Last slice in frame*/\n            break;\n        }\n        else\n        {\n            ps_dec->ps_decode_cur_slice++;\n            ps_dec->u2_cur_slice_num_dec_thread++;\n        }\n\n    }\n    if(ps_dec->u4_output_present && (2 == ps_dec->u4_num_cores) &&\n       (ps_dec->u4_fmt_conv_cur_row < ps_dec->s_disp_frame_info.u4_y_ht))\n    {\n        ps_dec->u4_fmt_conv_num_rows =\n                        (ps_dec->s_disp_frame_info.u4_y_ht\n                                        - ps_dec->u4_fmt_conv_cur_row);\n        ih264d_format_convert(ps_dec, &(ps_dec->s_disp_op),\n                              ps_dec->u4_fmt_conv_cur_row,\n                              ps_dec->u4_fmt_conv_num_rows);\n        ps_dec->u4_fmt_conv_cur_row += ps_dec->u4_fmt_conv_num_rows;\n    }\n}\n\nvoid ih264d_signal_decode_thread(dec_struct_t *ps_dec)\n{\n    if(ps_dec->u4_dec_thread_created == 1)\n    {\n        ithread_join(ps_dec->pv_dec_thread_handle, NULL);\n        ps_dec->u4_dec_thread_created = 0;\n    }\n}\nvoid ih264d_signal_bs_deblk_thread(dec_struct_t *ps_dec)\n{\n    if(ps_dec->u4_bs_deblk_thread_created)\n    {\n        ithread_join(ps_dec->pv_bs_deblk_thread_handle, NULL);\n        ps_dec->u4_bs_deblk_thread_created = 0;\n    }\n\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_thread_parse_decode.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*\n * ih264d_thread_parse_decode.h\n *\n *  Created on: Feb 21, 2012\n *      Author: 100492\n */\n\n#ifndef _IH264D_THREAD_PARSE_DECPDE_H_\n#define _IH264D_THREAD_PARSE_DECPDE_H_\nvoid ih264d_parse_tfr_nmb(dec_struct_t *ps_dec,\n                          UWORD8 u1_mb_idx,\n                          UWORD8 u1_num_mbs,\n                          UWORD8 u1_num_mbs_next,\n                          UWORD8 u1_tfr_n_mb,\n                          UWORD8 u1_end_of_row);\nvoid ih264d_decode_tfr_nmb(dec_struct_t *ps_dec,\n                           UWORD8 u1_num_mbs,\n                           UWORD8 u1_num_mbs_next,\n                           UWORD8 u1_end_of_row);\nWORD32 ih264d_decode_recon_tfr_nmb_thread(dec_struct_t * ps_dec,\n                                          UWORD8 u1_num_mbs,\n                                          UWORD8 u1_num_mbs_next,\n                                          UWORD8 u1_end_of_row);\nvoid ih264d_decode_picture_thread(dec_struct_t *ps_dec);\nWORD32 ih264d_decode_slice_thread(dec_struct_t *ps_dec);\n\n\n\n#endif /* _IH264D_THREAD_PARSE_DECPDE_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_transfer_address.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef _IH264D_TRANSFER_ADDRESS_H_\n#define _IH264D_TRANSFER_ADDRESS_H_\n\ntypedef struct\n{\n    UWORD8 *pu1_src_y;\n    UWORD8 *pu1_src_u;\n    UWORD8 *pu1_src_v;\n    UWORD8 *pu1_dest_y;\n    UWORD8 *pu1_dest_u;\n    UWORD8 *pu1_dest_v;\n    UWORD32 u4_inc_y[2];\n    UWORD32 u4_inc_uv[2];\n    UWORD16 u2_frm_wd_y;\n    UWORD16 u2_frm_wd_uv;\n    UWORD8 *pu1_mb_y;\n    UWORD8 *pu1_mb_u;\n    UWORD8 *pu1_mb_v;\n    UWORD16 u2_mv_left_inc;\n    UWORD16 u2_mv_top_left_inc;\n    UWORD32 u4_y_inc;\n    UWORD32 u4_uv_inc;\n\n} tfr_ctxt_t;\n\n#endif\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_utils.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/*!\n **************************************************************************\n * \\file ih264d_utils.c\n *\n * \\brief\n *    Contains routines that handle of start and end of pic processing\n *\n * \\date\n *    19/12/2002\n *\n * \\author  AI\n **************************************************************************\n */\n\n#include <string.h>\n#include \"ih264_typedefs.h\"\n#include \"ithread.h\"\n#include \"ih264d_deblocking.h\"\n#include \"ih264d_parse_slice.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_dpb_manager.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_mem_request.h\"\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_debug.h\"\n#include \"ih264d_mb_utils.h\"\n#include \"ih264d_error_handler.h\"\n#include \"ih264d_dpb_manager.h\"\n#include \"ih264d_utils.h\"\n#include \"ih264d_defs.h\"\n#include \"ih264d_tables.h\"\n#include \"ih264d_inter_pred.h\"\n#include \"ih264d_dpb_manager.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264d_format_conv.h\"\n#include \"ih264_error.h\"\n#include \"ih264_disp_mgr.h\"\n#include \"ih264_buf_mgr.h\"\n#include \"ih264d_utils.h\"\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_is_end_of_pic \\endif\n *\n * \\brief\n *    Determines whether current slice is first slice of a new picture as\n *    defined in 7.4.1.2.4 of 14496-10.\n *\n * \\return\n *    Return 1 if current slice is first slice of a new picture\n *    Otherwise it returns 0\n **************************************************************************\n */\nUWORD8 ih264d_is_end_of_pic(UWORD16 u2_frame_num,\n                            UWORD8 u1_nal_ref_idc,\n                            pocstruct_t *ps_cur_poc,\n                            pocstruct_t *ps_prev_poc,\n                            dec_slice_params_t * ps_prev_slice, /*!< Previous slice parameters*/\n                            UWORD8 u1_pic_order_cnt_type,\n                            UWORD8 u1_nal_unit_type,\n                            UWORD32 u4_idr_pic_id,\n                            UWORD8 u1_field_pic_flag,\n                            UWORD8 u1_bottom_field_flag)\n{\n    WORD8 i1_is_end_of_pic;\n    WORD8 a, b, c, d, e, f, g, h;\n\n    a = b = c = d = e = f = g = h = 0;\n    a = (ps_prev_slice->u2_frame_num != u2_frame_num);\n    b = (ps_prev_slice->u1_field_pic_flag != u1_field_pic_flag);\n    if(u1_field_pic_flag && ps_prev_slice->u1_field_pic_flag)\n        c = (u1_bottom_field_flag != ps_prev_slice->u1_bottom_field_flag);\n    d =\n                    (u1_nal_ref_idc == 0 && ps_prev_slice->u1_nal_ref_idc != 0)\n                                    || (u1_nal_ref_idc != 0\n                                                    && ps_prev_slice->u1_nal_ref_idc\n                                                                    == 0);\n    if(!a)\n    {\n        if((u1_pic_order_cnt_type == 0)\n                        && (ps_prev_slice->u1_pic_order_cnt_type == 0))\n        {\n            e =\n                            ((ps_cur_poc->i4_pic_order_cnt_lsb\n                                            != ps_prev_poc->i4_pic_order_cnt_lsb)\n                                            || (ps_cur_poc->i4_delta_pic_order_cnt_bottom\n                                                            != ps_prev_poc->i4_delta_pic_order_cnt_bottom));\n        }\n\n        if((u1_pic_order_cnt_type == 1)\n                        && (ps_prev_slice->u1_pic_order_cnt_type == 1))\n        {\n            f =\n                            ((ps_cur_poc->i4_delta_pic_order_cnt[0]\n                                            != ps_prev_poc->i4_delta_pic_order_cnt[0])\n                                            || (ps_cur_poc->i4_delta_pic_order_cnt[1]\n                                                            != ps_prev_poc->i4_delta_pic_order_cnt[1]));\n        }\n    }\n\n    if((u1_nal_unit_type == IDR_SLICE_NAL)\n                    && (ps_prev_slice->u1_nal_unit_type == IDR_SLICE_NAL))\n    {\n        g = (u4_idr_pic_id != ps_prev_slice->u4_idr_pic_id);\n    }\n\n    if((u1_nal_unit_type == IDR_SLICE_NAL)\n                    && (ps_prev_slice->u1_nal_unit_type != IDR_SLICE_NAL))\n    {\n        h = 1;\n    }\n    i1_is_end_of_pic = a + b + c + d + e + f + g + h;\n    return (i1_is_end_of_pic);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_decode_pic_order_cnt \\endif\n *\n * \\brief\n *    Calculates picture order count of picture.\n *\n * \\return\n *    Returns the pic order count of the picture to which current\n *    Slice belongs.\n *\n **************************************************************************\n */\nWORD32 ih264d_decode_pic_order_cnt(UWORD8 u1_is_idr_slice,\n                                   UWORD32 u2_frame_num,\n                                   pocstruct_t *ps_prev_poc,\n                                   pocstruct_t *ps_cur_poc,\n                                   dec_slice_params_t *ps_cur_slice, /*!< Pointer to current slice Params*/\n                                   dec_pic_params_t * ps_pps,\n                                   UWORD8 u1_nal_ref_idc,\n                                   UWORD8 u1_bottom_field_flag,\n                                   UWORD8 u1_field_pic_flag,\n                                   WORD32 *pi4_poc)\n{\n    WORD64 i8_pic_msb;\n    WORD32 i4_top_field_order_cnt = 0, i4_bottom_field_order_cnt = 0;\n    dec_seq_params_t *ps_seq = ps_pps->ps_sps;\n    WORD32 i4_prev_frame_num_ofst;\n\n    switch(ps_seq->u1_pic_order_cnt_type)\n    {\n        case 0:\n            /* POC TYPE 0 */\n            if(u1_is_idr_slice)\n            {\n                ps_prev_poc->i4_pic_order_cnt_msb = 0;\n                ps_prev_poc->i4_pic_order_cnt_lsb = 0;\n            }\n            if(ps_prev_poc->u1_mmco_equalto5)\n            {\n                if(ps_prev_poc->u1_bot_field != 1)\n                {\n                    ps_prev_poc->i4_pic_order_cnt_msb = 0;\n                    ps_prev_poc->i4_pic_order_cnt_lsb =\n                                    ps_prev_poc->i4_top_field_order_count;\n                }\n                else\n                {\n                    ps_prev_poc->i4_pic_order_cnt_msb = 0;\n                    ps_prev_poc->i4_pic_order_cnt_lsb = 0;\n                }\n            }\n\n            if((ps_cur_poc->i4_pic_order_cnt_lsb\n                            < ps_prev_poc->i4_pic_order_cnt_lsb)\n                            && ((ps_prev_poc->i4_pic_order_cnt_lsb\n                                            - ps_cur_poc->i4_pic_order_cnt_lsb)\n                                            >= (ps_seq->i4_max_pic_order_cntLsb\n                                                            >> 1)))\n            {\n                i8_pic_msb = (WORD64)ps_prev_poc->i4_pic_order_cnt_msb\n                                + ps_seq->i4_max_pic_order_cntLsb;\n            }\n            else if((ps_cur_poc->i4_pic_order_cnt_lsb\n                            > ps_prev_poc->i4_pic_order_cnt_lsb)\n                            && ((ps_cur_poc->i4_pic_order_cnt_lsb\n                                            - ps_prev_poc->i4_pic_order_cnt_lsb)\n                                            >= (ps_seq->i4_max_pic_order_cntLsb\n                                                            >> 1)))\n            {\n                i8_pic_msb = (WORD64)ps_prev_poc->i4_pic_order_cnt_msb\n                                - ps_seq->i4_max_pic_order_cntLsb;\n            }\n            else\n            {\n                i8_pic_msb = ps_prev_poc->i4_pic_order_cnt_msb;\n            }\n\n            if(!u1_field_pic_flag || !u1_bottom_field_flag)\n            {\n                WORD64 i8_result = i8_pic_msb + ps_cur_poc->i4_pic_order_cnt_lsb;\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                {\n                    return ERROR_INV_POC;\n                }\n                i4_top_field_order_cnt = i8_result;\n            }\n\n            if(!u1_field_pic_flag)\n            {\n                WORD64 i8_result = (WORD64)i4_top_field_order_cnt\n                                     + ps_cur_poc->i4_delta_pic_order_cnt_bottom;\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                {\n                    return ERROR_INV_POC;\n                }\n                i4_bottom_field_order_cnt = i8_result;\n            }\n            else if(u1_bottom_field_flag)\n            {\n                WORD64 i8_result = i8_pic_msb + ps_cur_poc->i4_pic_order_cnt_lsb;\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                {\n                    return ERROR_INV_POC;\n                }\n                i4_bottom_field_order_cnt = i8_result;\n            }\n\n            if(IS_OUT_OF_RANGE_S32(i8_pic_msb))\n            {\n                return ERROR_INV_POC;\n            }\n            ps_cur_poc->i4_pic_order_cnt_msb = i8_pic_msb;\n            break;\n\n        case 1:\n        {\n            /* POC TYPE 1 */\n            UWORD8 i;\n            WORD32 prev_frame_num;\n            WORD32 frame_num_ofst;\n            WORD32 abs_frm_num;\n            WORD32 poc_cycle_cnt, frame_num_in_poc_cycle;\n            WORD64 i8_expected_delta_poc_cycle;\n            WORD32 expected_poc;\n            WORD64 i8_result;\n\n            prev_frame_num = (WORD32)ps_cur_slice->u2_frame_num;\n            if(!u1_is_idr_slice)\n            {\n                if(ps_cur_slice->u1_mmco_equalto5)\n                {\n                    prev_frame_num = 0;\n                    i4_prev_frame_num_ofst = 0;\n                }\n                else\n                {\n                    i4_prev_frame_num_ofst = ps_prev_poc->i4_prev_frame_num_ofst;\n                }\n            }\n            else\n                i4_prev_frame_num_ofst = 0;\n\n            /* 1. Derivation for FrameNumOffset */\n            if(u1_is_idr_slice)\n            {\n                frame_num_ofst = 0;\n                ps_cur_poc->i4_delta_pic_order_cnt[0] = 0;\n                ps_cur_poc->i4_delta_pic_order_cnt[1] = 0;\n            }\n            else if(prev_frame_num > ((WORD32)u2_frame_num))\n            {\n                WORD64 i8_result = i4_prev_frame_num_ofst\n                                + (WORD64)ps_seq->u2_u4_max_pic_num_minus1 + 1;\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                {\n                    return ERROR_INV_FRAME_NUM;\n                }\n                frame_num_ofst = i8_result;\n            }\n            else\n                frame_num_ofst = i4_prev_frame_num_ofst;\n\n            /* 2. Derivation for absFrameNum */\n            if(0 != ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle)\n            {\n                WORD64 i8_result = frame_num_ofst + (WORD64)u2_frame_num;\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                {\n                    return ERROR_INV_FRAME_NUM;\n                }\n                abs_frm_num = i8_result;\n            }\n            else\n                abs_frm_num = 0;\n            if((u1_nal_ref_idc == 0) && (abs_frm_num > 0))\n                abs_frm_num = abs_frm_num - 1;\n\n            /* 4. expectedDeltaPerPicOrderCntCycle is derived as */\n            i8_expected_delta_poc_cycle = 0;\n            for(i = 0; i < ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle;\n                            i++)\n            {\n                i8_expected_delta_poc_cycle +=\n                                ps_seq->i4_ofst_for_ref_frame[i];\n            }\n\n            /* 3. When absFrameNum > 0, picOrderCntCycleCnt and\n             frame_num_in_poc_cycle are derived as : */\n            /* 5. expectedPicOrderCnt is derived as : */\n            if(abs_frm_num > 0)\n            {\n                poc_cycle_cnt =\n                                DIV((abs_frm_num - 1),\n                                    ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle);\n                frame_num_in_poc_cycle =\n                                MOD((abs_frm_num - 1),\n                                    ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle);\n\n                i8_result = poc_cycle_cnt\n                                * i8_expected_delta_poc_cycle;\n\n                for(i = 0; i <= frame_num_in_poc_cycle; i++)\n                {\n                    i8_result = i8_result\n                                    + ps_seq->i4_ofst_for_ref_frame[i];\n                }\n\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                    return ERROR_INV_POC;\n\n                expected_poc = (WORD32)i8_result;\n\n            }\n            else\n                expected_poc = 0;\n\n            if(u1_nal_ref_idc == 0)\n            {\n                i8_result = (WORD64)expected_poc\n                                + ps_seq->i4_ofst_for_non_ref_pic;\n\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                    return ERROR_INV_POC;\n\n                expected_poc = (WORD32)i8_result;\n            }\n\n            /* 6. TopFieldOrderCnt or BottomFieldOrderCnt are derived as */\n            if(!u1_field_pic_flag)\n            {\n                i8_result = (WORD64)expected_poc\n                                + ps_cur_poc->i4_delta_pic_order_cnt[0];\n\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                    return ERROR_INV_POC;\n                i4_top_field_order_cnt = (WORD32)i8_result;\n\n                i8_result = (WORD64)i4_top_field_order_cnt\n                                + ps_seq->i4_ofst_for_top_to_bottom_field\n                                + ps_cur_poc->i4_delta_pic_order_cnt[1];\n\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                    return ERROR_INV_POC;\n                i4_bottom_field_order_cnt = (WORD32)i8_result;\n            }\n            else if(!u1_bottom_field_flag)\n            {\n                i8_result = (WORD64)expected_poc\n                                + ps_cur_poc->i4_delta_pic_order_cnt[0];\n\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                    return ERROR_INV_POC;\n                i4_top_field_order_cnt = (WORD32)i8_result;\n            }\n            else\n            {\n                i8_result = (WORD64)expected_poc\n                                + ps_seq->i4_ofst_for_top_to_bottom_field\n                                + ps_cur_poc->i4_delta_pic_order_cnt[0];\n\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                    return ERROR_INV_POC;\n                i4_bottom_field_order_cnt = (WORD32)i8_result;\n            }\n            /* Copy the current POC info into Previous POC structure */\n            ps_cur_poc->i4_prev_frame_num_ofst = frame_num_ofst;\n        }\n\n            break;\n        case 2:\n        {\n            /* POC TYPE 2 */\n            WORD32 prev_frame_num;\n            WORD32 frame_num_ofst;\n            WORD32 tmp_poc;\n\n            prev_frame_num = (WORD32)ps_cur_slice->u2_frame_num;\n            if(!u1_is_idr_slice)\n            {\n                if(ps_cur_slice->u1_mmco_equalto5)\n                {\n                    prev_frame_num = 0;\n                    i4_prev_frame_num_ofst = 0;\n                }\n                else\n                    i4_prev_frame_num_ofst = ps_prev_poc->i4_prev_frame_num_ofst;\n            }\n            else\n                i4_prev_frame_num_ofst = 0;\n\n            /* 1. Derivation for FrameNumOffset */\n            if(u1_is_idr_slice)\n            {\n                frame_num_ofst = 0;\n                ps_cur_poc->i4_delta_pic_order_cnt[0] = 0;\n                ps_cur_poc->i4_delta_pic_order_cnt[1] = 0;\n            }\n            else if(prev_frame_num > ((WORD32)u2_frame_num))\n            {\n                WORD64 i8_result = i4_prev_frame_num_ofst\n                                + (WORD64)ps_seq->u2_u4_max_pic_num_minus1 + 1;\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                {\n                    return ERROR_INV_FRAME_NUM;\n                }\n                frame_num_ofst = i8_result;\n            }\n            else\n                frame_num_ofst = i4_prev_frame_num_ofst;\n\n            /* 2. Derivation for tempPicOrderCnt */\n            if(u1_is_idr_slice)\n                tmp_poc = 0;\n            else if(u1_nal_ref_idc == 0)\n            {\n                WORD64 i8_result = ((frame_num_ofst + (WORD64)u2_frame_num) << 1) - 1;\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                {\n                    return ERROR_INV_POC;\n                }\n                tmp_poc = i8_result;\n            }\n            else\n            {\n                WORD64 i8_result = (frame_num_ofst + (WORD64)u2_frame_num) << 1;\n                if(IS_OUT_OF_RANGE_S32(i8_result))\n                {\n                    return ERROR_INV_POC;\n                }\n                tmp_poc = i8_result;\n            }\n\n            /* 6. TopFieldOrderCnt or BottomFieldOrderCnt are derived as */\n            if(!u1_field_pic_flag)\n            {\n                i4_top_field_order_cnt = tmp_poc;\n                i4_bottom_field_order_cnt = tmp_poc;\n            }\n            else if(!u1_bottom_field_flag)\n                i4_top_field_order_cnt = tmp_poc;\n            else\n                i4_bottom_field_order_cnt = tmp_poc;\n\n            /* Copy the current POC info into Previous POC structure */\n            ps_prev_poc->i4_prev_frame_num_ofst = frame_num_ofst;\n            ps_cur_poc->i4_prev_frame_num_ofst = frame_num_ofst;\n        }\n            break;\n        default:\n            return ERROR_INV_POC_TYPE_T;\n            break;\n    }\n\n    if(!u1_field_pic_flag) // or a complementary field pair\n    {\n        *pi4_poc = MIN(i4_top_field_order_cnt, i4_bottom_field_order_cnt);\n        ps_pps->i4_top_field_order_cnt = i4_top_field_order_cnt;\n        ps_pps->i4_bottom_field_order_cnt = i4_bottom_field_order_cnt;\n    }\n    else if(!u1_bottom_field_flag)\n    {\n        *pi4_poc = i4_top_field_order_cnt;\n        ps_pps->i4_top_field_order_cnt = i4_top_field_order_cnt;\n    }\n    else\n    {\n        *pi4_poc = i4_bottom_field_order_cnt;\n        ps_pps->i4_bottom_field_order_cnt = i4_bottom_field_order_cnt;\n    }\n\n    ps_pps->i4_avg_poc = *pi4_poc;\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_end_of_pic_processing \\endif\n *\n * \\brief\n *    Performs the end of picture processing.\n *\n * It performs deblocking on the current picture and sets the i4_status of\n * current picture as decoded.\n *\n * \\return\n *    0 on Success and Error code otherwise.\n **************************************************************************\n */\nWORD32 ih264d_end_of_pic_processing(dec_struct_t *ps_dec)\n{\n    UWORD8 u1_pic_type, u1_nal_ref_idc;\n    dec_slice_params_t *ps_cur_slice = ps_dec->ps_cur_slice;\n\n    /* If nal_ref_idc is equal to 0 for one slice or slice data partition NAL\n     unit of a particular picture, it shall be equal to 0 for all slice and\n     slice data partition NAL units of the picture. nal_ref_idc greater\n     than 0 indicates that the content of the NAL unit belongs to a decoded\n     picture that is stored and marked for use as a reference picture in the\n     decoded picture buffer. */\n\n    /* 1. Do MMCO\n     2. Add Cur Pic to list of reference pics.\n     */\n\n    /* Call MMCO */\n    u1_pic_type = 0;\n    u1_nal_ref_idc = ps_cur_slice->u1_nal_ref_idc;\n\n    if(u1_nal_ref_idc)\n    {\n        if(ps_cur_slice->u1_nal_unit_type == IDR_SLICE_NAL)\n        {\n            ps_dec->ps_dpb_mgr->u1_mmco_error_in_seq = 0;\n            if(ps_dec->ps_dpb_cmds->u1_long_term_reference_flag == 0)\n            {\n                ih264d_reset_ref_bufs(ps_dec->ps_dpb_mgr);\n                /* ignore DPB errors */\n                ih264d_insert_st_node(ps_dec->ps_dpb_mgr,\n                                      ps_dec->ps_cur_pic,\n                                      ps_dec->u1_pic_buf_id,\n                                      ps_cur_slice->u2_frame_num);\n                ps_dec->ps_dpb_mgr->u1_max_lt_frame_idx = NO_LONG_TERM_INDICIES;\n            }\n            else\n            {\n                /* Equivalent of inserting a pic directly as longterm Pic */\n\n                {\n                    /* ignore DPB errors */\n                    ih264d_insert_st_node(ps_dec->ps_dpb_mgr,\n                                          ps_dec->ps_cur_pic,\n                                          ps_dec->u1_pic_buf_id,\n                                          ps_cur_slice->u2_frame_num);\n\n                    /* Set longTermIdx = 0, MaxLongTermFrameIdx = 0 */\n                    ih264d_delete_st_node_or_make_lt(\n                                    ps_dec->ps_dpb_mgr,\n                                    ps_cur_slice->u2_frame_num, 0,\n                                    ps_cur_slice->u1_field_pic_flag);\n\n                    ps_dec->ps_dpb_mgr->u1_max_lt_frame_idx = 0;\n                }\n            }\n        }\n        else\n        {\n\n            {\n                UWORD16 u2_pic_num = ps_cur_slice->u2_frame_num;\n\n                if(!ps_dec->ps_dpb_mgr->u1_mmco_error_in_seq)\n                {\n                    WORD32 ret = ih264d_do_mmco_buffer(ps_dec->ps_dpb_cmds, ps_dec->ps_dpb_mgr,\n                                               ps_dec->ps_cur_sps->u1_num_ref_frames, u2_pic_num,\n                                               (ps_dec->ps_cur_sps->u2_u4_max_pic_num_minus1),\n                                               ps_dec->u1_nal_unit_type, ps_dec->ps_cur_pic,\n                                               ps_dec->u1_pic_buf_id,\n                                               ps_cur_slice->u1_field_pic_flag,\n                                               ps_dec->e_dec_status);\n                    ps_dec->ps_dpb_mgr->u1_mmco_error_in_seq = ret != OK;\n                }\n            }\n        }\n        ih264d_update_default_index_list(ps_dec->ps_dpb_mgr);\n    }\n\n    if(ps_cur_slice->u1_field_pic_flag)\n    {\n        if(ps_cur_slice->u1_bottom_field_flag)\n        {\n            if(u1_nal_ref_idc)\n                u1_pic_type = u1_pic_type | BOT_REF;\n            u1_pic_type = u1_pic_type | BOT_FLD;\n        }\n        else\n        {\n            if(u1_nal_ref_idc)\n                u1_pic_type = u1_pic_type | TOP_REF;\n            u1_pic_type = u1_pic_type | TOP_FLD;\n        }\n    }\n    else\n        u1_pic_type = TOP_REF | BOT_REF;\n    ps_dec->ps_cur_pic->u1_pic_type |= u1_pic_type;\n\n\n    if(ps_cur_slice->u1_field_pic_flag)\n    {\n        H264_DEC_DEBUG_PRINT(\"Toggling secondField\\n\");\n        ps_dec->u1_second_field = 1 - ps_dec->u1_second_field;\n    }\n\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : init_dpb_size                                            */\n/*                                                                           */\n/*  Description   : This function calculates the DBP i4_size in frames          */\n/*  Inputs        : ps_seq - current sequence params                         */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*                                                                           */\n/*  Outputs       : None                                                     */\n/*                                                                           */\n/*  Returns       : DPB in frames                                            */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         28 04 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_get_dpb_size(dec_seq_params_t *ps_seq)\n{\n    WORD32 i4_size;\n    UWORD8 u1_level_idc;\n\n    u1_level_idc = ps_seq->u1_level_idc;\n\n    switch(u1_level_idc)\n    {\n        case 10:\n            i4_size = 152064;\n            break;\n        case 11:\n            i4_size = 345600;\n            break;\n        case 12:\n            i4_size = 912384;\n            break;\n        case 13:\n            i4_size = 912384;\n            break;\n        case 20:\n            i4_size = 912384;\n            break;\n        case 21:\n            i4_size = 1824768;\n            break;\n        case 22:\n            i4_size = 3110400;\n            break;\n        case 30:\n            i4_size = 3110400;\n            break;\n        case 31:\n            i4_size = 6912000;\n            break;\n        case 32:\n            i4_size = 7864320;\n            break;\n        case 40:\n            i4_size = 12582912;\n            break;\n        case 41:\n            i4_size = 12582912;\n            break;\n        case 42:\n            i4_size = 12582912;\n            break;\n        case 50:\n            i4_size = 42393600;\n            break;\n        case 51:\n            i4_size = 70778880;\n            break;\n        case 52:\n            i4_size = 70778880;\n            break;\n        default:\n            i4_size = 70778880;\n            break;\n    }\n\n    i4_size /= (ps_seq->u2_frm_wd_in_mbs * (ps_seq->u2_frm_ht_in_mbs << (1 - ps_seq->u1_frame_mbs_only_flag)));\n    i4_size /= 384;\n    i4_size = MIN(i4_size, 16);\n    i4_size = MAX(i4_size, 1);\n    return (i4_size);\n}\n\n/**************************************************************************/\n/* This function initialises the value of ps_dec->u1_recon_mb_grp         */\n/* ps_dec->u1_recon_mb_grp must satisfy the following criteria            */\n/*  - multiple of 2 (required for N/2 parse-mvpred design)                */\n/*  - multiple of 4 (if it is not a frame_mbs_only sequence),             */\n/*         in this case N/2 itself needs to be even for mbpair processing */\n/*  - lesser than ps_dec->u2_frm_wd_in_mbs/2 (at least 3 N-Chunks       */\n/*         should make a row to ensure proper MvTop transferring)         */\n/**************************************************************************/\nWORD32 ih264d_init_dec_mb_grp(dec_struct_t *ps_dec)\n{\n    dec_seq_params_t *ps_seq = ps_dec->ps_cur_sps;\n    UWORD8 u1_frm = ps_seq->u1_frame_mbs_only_flag;\n\n    ps_dec->u1_recon_mb_grp = ps_dec->u2_frm_wd_in_mbs << ps_seq->u1_mb_aff_flag;\n\n    ps_dec->u1_recon_mb_grp_pair = ps_dec->u1_recon_mb_grp >> 1;\n\n    if(!ps_dec->u1_recon_mb_grp)\n    {\n        return ERROR_MB_GROUP_ASSGN_T;\n    }\n\n    ps_dec->u4_num_mbs_prev_nmb = ps_dec->u1_recon_mb_grp;\n\n    return OK;\n}\n\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_init_pic \\endif\n *\n * \\brief\n *    Initializes the picture.\n *\n * \\return\n *    0 on Success and Error code otherwise\n *\n * \\note\n *    This function is called when first slice of the\n *    NON -IDR picture is encountered.\n **************************************************************************\n */\nWORD32 ih264d_init_pic(dec_struct_t *ps_dec,\n                       UWORD16 u2_frame_num,\n                       WORD32 i4_poc,\n                       dec_pic_params_t *ps_pps)\n{\n    dec_seq_params_t *ps_seq = ps_pps->ps_sps;\n    prev_seq_params_t * ps_prev_seq_params = &ps_dec->s_prev_seq_params;\n    WORD32 i4_pic_bufs;\n    WORD32 ret;\n\n    ps_dec->ps_cur_slice->u2_frame_num = u2_frame_num;\n    ps_dec->ps_cur_slice->i4_poc = i4_poc;\n    ps_dec->ps_cur_pps = ps_pps;\n    ps_dec->ps_cur_pps->pv_codec_handle = ps_dec;\n\n    ps_dec->ps_cur_sps = ps_seq;\n    ps_dec->ps_dpb_mgr->i4_max_frm_num = ps_seq->u2_u4_max_pic_num_minus1\n                    + 1;\n\n    ps_dec->ps_dpb_mgr->u2_pic_ht = ps_dec->u2_pic_ht;\n    ps_dec->ps_dpb_mgr->u2_pic_wd = ps_dec->u2_pic_wd;\n    ps_dec->i4_pic_type = NA_SLICE;\n    ps_dec->i4_frametype = IV_NA_FRAME;\n    ps_dec->i4_content_type = IV_CONTENTTYPE_NA;\n\n    /*--------------------------------------------------------------------*/\n    /* Get the value of MaxMbAddress and frmheight in Mbs                 */\n    /*--------------------------------------------------------------------*/\n    ps_seq->u2_max_mb_addr =\n                    (ps_seq->u2_frm_wd_in_mbs\n                                    * (ps_dec->u2_pic_ht\n                                                    >> (4\n                                                                    + ps_dec->ps_cur_slice->u1_field_pic_flag)))\n                                    - 1;\n    ps_dec->u2_frm_ht_in_mbs = (ps_dec->u2_pic_ht\n                    >> (4 + ps_dec->ps_cur_slice->u1_field_pic_flag));\n\n    /***************************************************************************/\n    /* If change in Level or the required PicBuffers i4_size is more than the  */\n    /* current one FREE the current PicBuffers and allocate affresh            */\n    /***************************************************************************/\n    if(!ps_dec->u1_init_dec_flag)\n    {\n        ps_dec->u1_max_dec_frame_buffering = ih264d_get_dpb_size(ps_seq);\n\n        ps_dec->i4_display_delay = ps_dec->u1_max_dec_frame_buffering;\n        if((1 == ps_seq->u1_vui_parameters_present_flag) &&\n           (1 == ps_seq->s_vui.u1_bitstream_restriction_flag))\n        {\n            if(ps_seq->u1_frame_mbs_only_flag == 1)\n                ps_dec->i4_display_delay = ps_seq->s_vui.u4_num_reorder_frames + 1;\n            else\n                ps_dec->i4_display_delay = ps_seq->s_vui.u4_num_reorder_frames * 2 + 2;\n        }\n\n        if(IVD_DECODE_FRAME_OUT == ps_dec->e_frm_out_mode)\n            ps_dec->i4_display_delay = 0;\n\n        if(ps_dec->u4_share_disp_buf == 0)\n        {\n            if(ps_seq->u1_frame_mbs_only_flag == 1)\n                ps_dec->u1_pic_bufs = ps_dec->i4_display_delay + ps_seq->u1_num_ref_frames + 1;\n            else\n                ps_dec->u1_pic_bufs = ps_dec->i4_display_delay + ps_seq->u1_num_ref_frames * 2 + 2;\n        }\n        else\n        {\n            ps_dec->u1_pic_bufs = (WORD32)ps_dec->u4_num_disp_bufs;\n        }\n\n        /* Ensure at least two buffers are allocated */\n        ps_dec->u1_pic_bufs = MAX(ps_dec->u1_pic_bufs, 2);\n\n        if(ps_dec->u4_share_disp_buf == 0)\n            ps_dec->u1_pic_bufs = MIN(ps_dec->u1_pic_bufs,\n                                      (H264_MAX_REF_PICS * 2));\n\n        ps_dec->u1_max_dec_frame_buffering = MIN(\n                        ps_dec->u1_max_dec_frame_buffering,\n                        ps_dec->u1_pic_bufs);\n\n        /* Temporary hack to run Tractor Cav/Cab/MbAff Profiler streams  also for CAFI1_SVA_C.264 in conformance*/\n        if(ps_dec->u1_init_dec_flag)\n        {\n            ih264d_release_pics_in_dpb((void *)ps_dec,\n                                       ps_dec->u1_pic_bufs);\n            ih264d_release_display_bufs(ps_dec);\n            ih264d_reset_ref_bufs(ps_dec->ps_dpb_mgr);\n        }\n\n        /*********************************************************************/\n        /* Configuring decoder parameters based on level and then            */\n        /* fresh pointer initialisation in decoder scratch and state buffers */\n        /*********************************************************************/\n        if(!ps_dec->u1_init_dec_flag ||\n                ((ps_seq->u1_level_idc < H264_LEVEL_3_0) ^ (ps_prev_seq_params->u1_level_idc < H264_LEVEL_3_0)))\n        {\n            ret = ih264d_init_dec_mb_grp(ps_dec);\n            if(ret != OK)\n                return ret;\n        }\n\n        ret = ih264d_allocate_dynamic_bufs(ps_dec);\n        if(ret != OK)\n        {\n            /* Free any dynamic buffers that are allocated */\n            ih264d_free_dynamic_bufs(ps_dec);\n            ps_dec->i4_error_code = IVD_MEM_ALLOC_FAILED;\n            return IVD_MEM_ALLOC_FAILED;\n        }\n\n        ret = ih264d_create_pic_buffers(ps_dec->u1_pic_bufs,\n                                        ps_dec);\n        if(ret != OK)\n            return ret;\n\n\n\n        ret = ih264d_create_mv_bank(ps_dec, ps_dec->u2_pic_wd,\n                                    ps_dec->u2_pic_ht);\n        if(ret != OK)\n            return ret;\n\n        /* In shared mode, set all of them as used by display */\n        if(ps_dec->u4_share_disp_buf == 1)\n        {\n            WORD32 i;\n\n            for(i = 0; i < ps_dec->u1_pic_bufs; i++)\n            {\n                ih264_buf_mgr_set_status((buf_mgr_t *)ps_dec->pv_pic_buf_mgr, i,\n                                         BUF_MGR_IO);\n            }\n        }\n\n        ps_dec->u1_init_dec_flag = 1;\n        ps_prev_seq_params->u2_frm_wd_in_mbs = ps_seq->u2_frm_wd_in_mbs;\n        ps_prev_seq_params->u1_level_idc = ps_seq->u1_level_idc;\n        ps_prev_seq_params->u1_profile_idc = ps_seq->u1_profile_idc;\n        ps_prev_seq_params->u2_frm_ht_in_mbs = ps_seq->u2_frm_ht_in_mbs;\n        ps_prev_seq_params->u1_frame_mbs_only_flag =\n                        ps_seq->u1_frame_mbs_only_flag;\n        ps_prev_seq_params->u1_direct_8x8_inference_flag =\n                        ps_seq->u1_direct_8x8_inference_flag;\n\n        ps_dec->i4_cur_display_seq = 0;\n        ps_dec->i4_prev_max_display_seq = 0;\n        ps_dec->i4_max_poc = 0;\n\n        {\n            /* 0th entry of CtxtIncMbMap will be always be containing default values\n             for CABAC context representing MB not available */\n            ctxt_inc_mb_info_t *p_DefCtxt = ps_dec->p_ctxt_inc_mb_map - 1;\n            UWORD8 *pu1_temp;\n            WORD8 i;\n            p_DefCtxt->u1_mb_type = CAB_SKIP;\n\n            p_DefCtxt->u1_cbp = 0x0f;\n            p_DefCtxt->u1_intra_chroma_pred_mode = 0;\n\n            p_DefCtxt->u1_yuv_dc_csbp = 0x7;\n\n            p_DefCtxt->u1_transform8x8_ctxt = 0;\n\n            pu1_temp = (UWORD8*)p_DefCtxt->i1_ref_idx;\n            for(i = 0; i < 4; i++, pu1_temp++)\n                (*pu1_temp) = 0;\n            pu1_temp = (UWORD8*)p_DefCtxt->u1_mv;\n            for(i = 0; i < 16; i++, pu1_temp++)\n                (*pu1_temp) = 0;\n            ps_dec->ps_def_ctxt_mb_info = p_DefCtxt;\n        }\n\n    }\n    /* reset DBP commands read u4_flag */\n    ps_dec->ps_dpb_cmds->u1_dpb_commands_read = 0;\n\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_get_next_display_field                                   */\n/*                                                                           */\n/*  Description   : Application calls this module to get the next field      */\n/*                  to be displayed                                          */\n/*                                                                           */\n/*  Inputs        : 1.   IBUFAPI_Handle Hnadle to the Display buffer         */\n/*                  2.   IH264DEC_DispUnit    Pointer to the display struct  */\n/*                                                                           */\n/*  Globals       :                                                          */\n/*                                                                           */\n/*                                                                           */\n/*  Processing    : None                                                     */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         27 05 2005   Ittiam          Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_get_next_display_field(dec_struct_t * ps_dec,\n                                  ivd_out_bufdesc_t *ps_out_buffer,\n                                  ivd_get_display_frame_op_t *pv_disp_op)\n{\n    pic_buffer_t *pic_buf;\n\n    UWORD8 i1_cur_fld;\n    WORD32 u4_api_ret = -1;\n    WORD32 i4_disp_buf_id;\n    iv_yuv_buf_t *ps_op_frm;\n\n\n\n    ps_op_frm = &(ps_dec->s_disp_frame_info);\n    H264_MUTEX_LOCK(&ps_dec->process_disp_mutex);\n    pic_buf = (pic_buffer_t *)ih264_disp_mgr_get(\n                    (disp_mgr_t *)ps_dec->pv_disp_buf_mgr, &i4_disp_buf_id);\n    ps_dec->u4_num_fld_in_frm = 0;\n    u4_api_ret = -1;\n    pv_disp_op->u4_ts = 0;\n    pv_disp_op->e_output_format = ps_dec->u1_chroma_format;\n\n    pv_disp_op->s_disp_frm_buf.pv_y_buf = ps_out_buffer->pu1_bufs[0];\n    pv_disp_op->s_disp_frm_buf.pv_u_buf = ps_out_buffer->pu1_bufs[1];\n    pv_disp_op->s_disp_frm_buf.pv_v_buf = ps_out_buffer->pu1_bufs[2];\n    ps_dec->i4_display_index  = DEFAULT_POC;\n    if(pic_buf != NULL)\n    {\n        ps_dec->pv_disp_sei_params = &pic_buf->s_sei_pic;\n        pv_disp_op->e4_fld_type = 0;\n        pv_disp_op->u4_disp_buf_id = i4_disp_buf_id;\n\n        ps_op_frm->u4_y_ht = pic_buf->u2_disp_height << 1;\n        ps_op_frm->u4_u_ht = ps_op_frm->u4_v_ht = ps_op_frm->u4_y_ht >> 1;\n        ps_op_frm->u4_y_wd = pic_buf->u2_disp_width;\n\n        ps_op_frm->u4_u_wd = ps_op_frm->u4_v_wd = ps_op_frm->u4_y_wd >> 1;\n\n        ps_op_frm->u4_y_strd = pic_buf->u2_frm_wd_y;\n        ps_op_frm->u4_u_strd = ps_op_frm->u4_v_strd = pic_buf->u2_frm_wd_uv;\n\n        /* ! */\n        pv_disp_op->u4_ts = pic_buf->u4_ts;\n        ps_dec->i4_display_index = pic_buf->i4_poc;\n\n        /* set the start of the Y, U and V buffer pointer for display    */\n        ps_op_frm->pv_y_buf = pic_buf->pu1_buf1 + pic_buf->u2_crop_offset_y;\n        ps_op_frm->pv_u_buf = pic_buf->pu1_buf2 + pic_buf->u2_crop_offset_uv;\n        ps_op_frm->pv_v_buf = pic_buf->pu1_buf3 + pic_buf->u2_crop_offset_uv;\n        ps_dec->u4_num_fld_in_frm++;\n        ps_dec->u4_num_fld_in_frm++;\n        u4_api_ret = 0;\n\n        if(pic_buf->u1_picturetype == 0)\n            pv_disp_op->u4_progressive_frame_flag = 1;\n        else\n            pv_disp_op->u4_progressive_frame_flag = 0;\n\n    } H264_MUTEX_UNLOCK(&ps_dec->process_disp_mutex);\n    pv_disp_op->u4_error_code = u4_api_ret;\n    pv_disp_op->e_pic_type = 0xFFFFFFFF; //Junk;\n\n    if(u4_api_ret)\n    {\n        pv_disp_op->u4_error_code = 1; //put a proper error code here\n    }\n    else\n    {\n\n        //Release the buffer if being sent for display\n        UWORD32 temp;\n        UWORD32 dest_inc_Y = 0, dest_inc_UV = 0;\n\n        pv_disp_op->s_disp_frm_buf.u4_y_wd = temp = MIN(ps_op_frm->u4_y_wd,\n                                                        ps_op_frm->u4_y_strd);\n        pv_disp_op->s_disp_frm_buf.u4_u_wd = pv_disp_op->s_disp_frm_buf.u4_y_wd\n                        >> 1;\n        pv_disp_op->s_disp_frm_buf.u4_v_wd = pv_disp_op->s_disp_frm_buf.u4_y_wd\n                        >> 1;\n\n        pv_disp_op->s_disp_frm_buf.u4_y_ht = ps_op_frm->u4_y_ht;\n        pv_disp_op->s_disp_frm_buf.u4_u_ht = pv_disp_op->s_disp_frm_buf.u4_y_ht\n                        >> 1;\n        pv_disp_op->s_disp_frm_buf.u4_v_ht = pv_disp_op->s_disp_frm_buf.u4_y_ht\n                        >> 1;\n        if(0 == ps_dec->u4_share_disp_buf)\n        {\n            pv_disp_op->s_disp_frm_buf.u4_y_strd =\n                            pv_disp_op->s_disp_frm_buf.u4_y_wd;\n            pv_disp_op->s_disp_frm_buf.u4_u_strd =\n                            pv_disp_op->s_disp_frm_buf.u4_y_wd >> 1;\n            pv_disp_op->s_disp_frm_buf.u4_v_strd =\n                            pv_disp_op->s_disp_frm_buf.u4_y_wd >> 1;\n\n        }\n        else\n        {\n            pv_disp_op->s_disp_frm_buf.u4_y_strd = ps_op_frm->u4_y_strd;\n        }\n\n        if(ps_dec->u4_app_disp_width)\n        {\n            pv_disp_op->s_disp_frm_buf.u4_y_strd = MAX(\n                            ps_dec->u4_app_disp_width,\n                            pv_disp_op->s_disp_frm_buf.u4_y_strd);\n        }\n\n        pv_disp_op->u4_error_code = 0;\n        if(pv_disp_op->e_output_format == IV_YUV_420P)\n        {\n            UWORD32 i;\n            pv_disp_op->s_disp_frm_buf.u4_u_strd =\n                            pv_disp_op->s_disp_frm_buf.u4_y_strd >> 1;\n            pv_disp_op->s_disp_frm_buf.u4_v_strd =\n                            pv_disp_op->s_disp_frm_buf.u4_y_strd >> 1;\n\n            pv_disp_op->s_disp_frm_buf.u4_u_wd = ps_op_frm->u4_y_wd >> 1;\n            pv_disp_op->s_disp_frm_buf.u4_v_wd = ps_op_frm->u4_y_wd >> 1;\n\n            if(1 == ps_dec->u4_share_disp_buf)\n            {\n                pv_disp_op->s_disp_frm_buf.pv_y_buf = ps_op_frm->pv_y_buf;\n\n                for(i = 0; i < MAX_DISP_BUFS_NEW; i++)\n                {\n                    UWORD8 *buf = ps_dec->disp_bufs[i].buf[0];\n                    buf += ps_dec->disp_bufs[i].u4_ofst[0];\n                    if(((UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_y_buf\n                                    - pic_buf->u2_crop_offset_y) == buf)\n                    {\n                        buf = ps_dec->disp_bufs[i].buf[1];\n                        buf += ps_dec->disp_bufs[i].u4_ofst[1];\n                        pv_disp_op->s_disp_frm_buf.pv_u_buf = buf\n                                        + (pic_buf->u2_crop_offset_uv\n                                           / YUV420SP_FACTOR);\n\n                        buf = ps_dec->disp_bufs[i].buf[2];\n                        buf += ps_dec->disp_bufs[i].u4_ofst[2];\n                        pv_disp_op->s_disp_frm_buf.pv_v_buf = buf\n                                        + (pic_buf->u2_crop_offset_uv\n                                           / YUV420SP_FACTOR);\n\n                    }\n                }\n            }\n\n        }\n        else if((pv_disp_op->e_output_format == IV_YUV_420SP_UV)\n                        || (pv_disp_op->e_output_format == IV_YUV_420SP_VU))\n        {\n            pv_disp_op->s_disp_frm_buf.u4_u_strd =\n                            pv_disp_op->s_disp_frm_buf.u4_y_strd;\n            pv_disp_op->s_disp_frm_buf.u4_v_strd = 0;\n\n            if(1 == ps_dec->u4_share_disp_buf)\n            {\n                UWORD32 i;\n\n                pv_disp_op->s_disp_frm_buf.pv_y_buf = ps_op_frm->pv_y_buf;\n\n                for(i = 0; i < MAX_DISP_BUFS_NEW; i++)\n                {\n                    UWORD8 *buf = ps_dec->disp_bufs[i].buf[0];\n                    buf += ps_dec->disp_bufs[i].u4_ofst[0];\n                    if((UWORD8 *)pv_disp_op->s_disp_frm_buf.pv_y_buf\n                                    - pic_buf->u2_crop_offset_y == buf)\n                    {\n                        buf = ps_dec->disp_bufs[i].buf[1];\n                        buf += ps_dec->disp_bufs[i].u4_ofst[1];\n                        pv_disp_op->s_disp_frm_buf.pv_u_buf = buf\n                                        + pic_buf->u2_crop_offset_uv;\n                        ;\n\n                        buf = ps_dec->disp_bufs[i].buf[2];\n                        buf += ps_dec->disp_bufs[i].u4_ofst[2];\n                        pv_disp_op->s_disp_frm_buf.pv_v_buf = buf\n                                        + pic_buf->u2_crop_offset_uv;\n                        ;\n                    }\n                }\n            }\n            pv_disp_op->s_disp_frm_buf.u4_u_wd =\n                            pv_disp_op->s_disp_frm_buf.u4_y_wd;\n            pv_disp_op->s_disp_frm_buf.u4_v_wd = 0;\n\n        }\n        else if((pv_disp_op->e_output_format == IV_RGB_565)\n                        || (pv_disp_op->e_output_format == IV_YUV_422ILE))\n        {\n\n            pv_disp_op->s_disp_frm_buf.u4_u_strd = 0;\n            pv_disp_op->s_disp_frm_buf.u4_v_strd = 0;\n            pv_disp_op->s_disp_frm_buf.u4_u_wd = 0;\n            pv_disp_op->s_disp_frm_buf.u4_v_wd = 0;\n            pv_disp_op->s_disp_frm_buf.u4_u_ht = 0;\n            pv_disp_op->s_disp_frm_buf.u4_v_ht = 0;\n\n        }\n\n\n    }\n\n    return u4_api_ret;\n}\n\n\n/*****************************************************************************/\n/*  Function Name : ih264d_release_display_field                                         */\n/*                                                                           */\n/*  Description   : This function releases the display field that was returned   */\n/*                  here.                                                    */\n/*  Inputs        : ps_dec - Decoder parameters                              */\n/*  Globals       : None                                                     */\n/*  Processing    : Refer bumping process in the standard                    */\n/*  Outputs       : Assigns display sequence number.                         */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         27 04 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_release_display_field(dec_struct_t *ps_dec,\n                                  ivd_get_display_frame_op_t *pv_disp_op)\n{\n    if(1 == pv_disp_op->u4_error_code)\n    {\n        if(1 == ps_dec->u1_flushfrm)\n        {\n            UWORD32 i;\n\n            if(1 == ps_dec->u4_share_disp_buf)\n            {\n                H264_MUTEX_LOCK(&ps_dec->process_disp_mutex);\n                for(i = 0; i < (MAX_DISP_BUFS_NEW); i++)\n                {\n                    if(1 == ps_dec->u4_disp_buf_mapping[i])\n                    {\n                        ih264_buf_mgr_release(\n                                        (buf_mgr_t *)ps_dec->pv_pic_buf_mgr, i,\n                                        BUF_MGR_IO);\n                        ps_dec->u4_disp_buf_mapping[i] = 0;\n                    }\n                } H264_MUTEX_UNLOCK(&ps_dec->process_disp_mutex);\n\n                memset(ps_dec->u4_disp_buf_to_be_freed, 0,\n                       (MAX_DISP_BUFS_NEW) * sizeof(UWORD32));\n                for(i = 0; i < ps_dec->u1_pic_bufs; i++)\n                    ps_dec->u4_disp_buf_mapping[i] = 1;\n            }\n            ps_dec->u1_flushfrm = 0;\n\n        }\n    }\n    else\n    {\n        H264_MUTEX_LOCK(&ps_dec->process_disp_mutex);\n\n        if(0 == ps_dec->u4_share_disp_buf)\n        {\n            ih264_buf_mgr_release((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                  pv_disp_op->u4_disp_buf_id,\n                                  BUF_MGR_IO);\n\n        }\n        else\n        {\n            ps_dec->u4_disp_buf_mapping[pv_disp_op->u4_disp_buf_id] = 1;\n        } H264_MUTEX_UNLOCK(&ps_dec->process_disp_mutex);\n\n    }\n}\n/*****************************************************************************/\n/*  Function Name : ih264d_assign_display_seq                                         */\n/*                                                                           */\n/*  Description   : This function implments bumping process. Every outgoing  */\n/*                  frame from DPB is assigned a display sequence number     */\n/*                  which increases monotonically. System looks for this     */\n/*                  number to display a frame.                              */\n/*                  here.                                                    */\n/*  Inputs        : ps_dec - Decoder parameters                              */\n/*  Globals       : None                                                     */\n/*  Processing    : Refer bumping process in the standard                    */\n/*  Outputs       : Assigns display sequence number.                         */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         27 04 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_assign_display_seq(dec_struct_t *ps_dec)\n{\n    WORD32 i;\n    WORD32 i4_min_poc;\n    WORD32 i4_min_poc_buf_id;\n    WORD32 i4_min_index;\n    dpb_manager_t *ps_dpb_mgr = ps_dec->ps_dpb_mgr;\n    WORD32 (*i4_poc_buf_id_map)[3] = ps_dpb_mgr->ai4_poc_buf_id_map;\n\n    i4_min_poc = 0x7fffffff;\n    i4_min_poc_buf_id = -1;\n    i4_min_index = -1;\n\n    if(ps_dpb_mgr->i1_poc_buf_id_entries >= ps_dec->i4_display_delay)\n    {\n        for(i = 0; i < MAX_FRAMES; i++)\n        {\n            if((i4_poc_buf_id_map[i][0] != -1)\n                            && (DO_NOT_DISP\n                                            != ps_dpb_mgr->ai4_poc_buf_id_map[i][0]))\n            {\n                /* Checking for <= is necessary to handle cases where there is one\n                   valid buffer with poc set to 0x7FFFFFFF. */\n                if(i4_poc_buf_id_map[i][1] <= i4_min_poc)\n                {\n                    i4_min_poc = i4_poc_buf_id_map[i][1];\n                    i4_min_poc_buf_id = i4_poc_buf_id_map[i][0];\n                    i4_min_index = i;\n                }\n            }\n        }\n\n        if((i4_min_index != -1) && (DO_NOT_DISP != i4_min_poc_buf_id))\n        {\n            ps_dec->i4_cur_display_seq++;\n            ih264_disp_mgr_add(\n                            (disp_mgr_t *)ps_dec->pv_disp_buf_mgr,\n                            i4_min_poc_buf_id, ps_dec->i4_cur_display_seq,\n                            ps_dec->apv_buf_id_pic_buf_map[i4_min_poc_buf_id]);\n            i4_poc_buf_id_map[i4_min_index][0] = -1;\n            i4_poc_buf_id_map[i4_min_index][1] = 0x7fffffff;\n            ps_dpb_mgr->i1_poc_buf_id_entries--;\n        }\n        else if(DO_NOT_DISP == i4_min_poc_buf_id)\n        {\n            WORD32 i4_error_code;\n            i4_error_code = ERROR_GAPS_IN_FRM_NUM;\n//          i4_error_code |= 1<<IVD_CORRUPTEDDATA;\n            return i4_error_code;\n        }\n    }\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_release_display_bufs                                       */\n/*                                                                           */\n/*  Description   : This function implments bumping process when mmco = 5.   */\n/*                  Each outgoing frame from DPB is assigned a display       */\n/*                  sequence number which increases monotonically. System    */\n/*                  looks for this number to display a frame.                */\n/*  Inputs        : ps_dec - Decoder parameters                              */\n/*  Globals       : None                                                     */\n/*  Processing    : Refer bumping process in the standard for mmco = 5       */\n/*  Outputs       : Assigns display sequence number.                         */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         27 04 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nvoid ih264d_release_display_bufs(dec_struct_t *ps_dec)\n{\n    WORD32 i, j;\n    WORD32 i4_min_poc;\n    WORD32 i4_min_poc_buf_id;\n    WORD32 i4_min_index;\n    WORD64 i8_temp;\n    dpb_manager_t *ps_dpb_mgr = ps_dec->ps_dpb_mgr;\n    WORD32 (*i4_poc_buf_id_map)[3] = ps_dpb_mgr->ai4_poc_buf_id_map;\n\n    i4_min_poc = 0x7fffffff;\n    i4_min_poc_buf_id = 0;\n    i4_min_index = 0;\n\n    ih264d_delete_nonref_nondisplay_pics(ps_dpb_mgr);\n\n    for(j = 0; j < ps_dpb_mgr->i1_poc_buf_id_entries; j++)\n    {\n        i4_min_poc = 0x7fffffff;\n        for(i = 0; i < MAX_FRAMES; i++)\n        {\n            if(i4_poc_buf_id_map[i][0] != -1)\n            {\n                /* Checking for <= is necessary to handle cases where there is one\n                   valid buffer with poc set to 0x7FFFFFFF. */\n                if(i4_poc_buf_id_map[i][1] <= i4_min_poc)\n                {\n                    i4_min_poc = i4_poc_buf_id_map[i][1];\n                    i4_min_poc_buf_id = i4_poc_buf_id_map[i][0];\n                    i4_min_index = i;\n                }\n            }\n        }\n\n        if(DO_NOT_DISP != i4_min_poc_buf_id)\n        {\n            ps_dec->i4_cur_display_seq++;\n            ih264_disp_mgr_add(\n                            (disp_mgr_t *)ps_dec->pv_disp_buf_mgr,\n                            i4_min_poc_buf_id, ps_dec->i4_cur_display_seq,\n                            ps_dec->apv_buf_id_pic_buf_map[i4_min_poc_buf_id]);\n            i4_poc_buf_id_map[i4_min_index][0] = -1;\n            i4_poc_buf_id_map[i4_min_index][1] = 0x7fffffff;\n            ps_dpb_mgr->ai4_poc_buf_id_map[i4_min_index][2] = 0;\n        }\n        else\n        {\n            i4_poc_buf_id_map[i4_min_index][0] = -1;\n            i4_poc_buf_id_map[i4_min_index][1] = 0x7fffffff;\n            ps_dpb_mgr->ai4_poc_buf_id_map[i4_min_index][2] = 0;\n        }\n    }\n    ps_dpb_mgr->i1_poc_buf_id_entries = 0;\n    i8_temp = (WORD64)ps_dec->i4_prev_max_display_seq + ps_dec->i4_max_poc\n              + ps_dec->u1_max_dec_frame_buffering + 1;\n    /*If i4_prev_max_display_seq overflows integer range, reset it */\n    ps_dec->i4_prev_max_display_seq = IS_OUT_OF_RANGE_S32(i8_temp)?\n                                      0 : i8_temp;\n    ps_dec->i4_max_poc = 0;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_assign_pic_num                                           */\n/*                                                                           */\n/*  Description   : This function assigns pic num to each reference frame    */\n/*                  depending on the cur_frame_num as speified in section    */\n/*                  8.2.4.1                                                  */\n/*                                                                           */\n/*  Inputs        : ps_dec                                                   */\n/*                                                                           */\n/*  Globals       : NO globals used                                          */\n/*                                                                           */\n/*  Processing    : for all ST pictures                                      */\n/*                    if( FrameNum > cur_frame_num)                          */\n/*                    PicNum = FrameNum - MaxFrameNum                        */\n/*                    else                                                   */\n/*                    PicNum = FrameNum                                      */\n/*                                                                           */\n/*  Returns       : void                                                     */\n/*                                                                           */\n/*  Issues        : NO                                                       */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         13 07 2002   Jay             Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nvoid ih264d_assign_pic_num(dec_struct_t *ps_dec)\n{\n    dpb_manager_t *ps_dpb_mgr;\n    struct dpb_info_t *ps_next_dpb;\n    WORD8 i;\n    WORD32 i4_cur_frame_num, i4_max_frame_num;\n    WORD32 i4_ref_frame_num;\n    UWORD8 u1_fld_pic_flag = ps_dec->ps_cur_slice->u1_field_pic_flag;\n\n    i4_max_frame_num = ps_dec->ps_cur_sps->u2_u4_max_pic_num_minus1 + 1;\n    i4_cur_frame_num = ps_dec->ps_cur_pic->i4_frame_num;\n    ps_dpb_mgr = ps_dec->ps_dpb_mgr;\n\n    /* Start from ST head */\n    ps_next_dpb = ps_dpb_mgr->ps_dpb_st_head;\n    for(i = 0; i < ps_dpb_mgr->u1_num_st_ref_bufs; i++)\n    {\n        WORD32 i4_pic_num;\n\n        i4_ref_frame_num = ps_next_dpb->ps_pic_buf->i4_frame_num;\n        if(i4_ref_frame_num > i4_cur_frame_num)\n        {\n            /* RefPic Buf frame_num is before Current frame_num in decode order */\n            i4_pic_num = i4_ref_frame_num - i4_max_frame_num;\n        }\n        else\n        {\n            /* RefPic Buf frame_num is after Current frame_num in decode order */\n            i4_pic_num = i4_ref_frame_num;\n        }\n\n        ps_next_dpb->ps_pic_buf->i4_pic_num = i4_pic_num;\n        ps_next_dpb->i4_frame_num = i4_pic_num;\n        ps_next_dpb->ps_pic_buf->u1_long_term_frm_idx = MAX_REF_BUFS + 1;\n        if(u1_fld_pic_flag)\n        {\n            /* Assign the pic num to top fields and bot fields */\n\n            ps_next_dpb->s_top_field.i4_pic_num = i4_pic_num * 2\n                            + !(ps_dec->ps_cur_slice->u1_bottom_field_flag);\n            ps_next_dpb->s_bot_field.i4_pic_num = i4_pic_num * 2\n                            + ps_dec->ps_cur_slice->u1_bottom_field_flag;\n        }\n        /* Chase the next link */\n        ps_next_dpb = ps_next_dpb->ps_prev_short;\n    }\n\n    if(ps_dec->ps_cur_sps->u1_gaps_in_frame_num_value_allowed_flag\n                    && ps_dpb_mgr->u1_num_gaps)\n    {\n        WORD32 i4_start_frm, i4_end_frm;\n        /* Assign pic numbers for gaps */\n        for(i = 0; i < MAX_FRAMES; i++)\n        {\n            i4_start_frm = ps_dpb_mgr->ai4_gaps_start_frm_num[i];\n            if(i4_start_frm != INVALID_FRAME_NUM)\n            {\n                if(i4_start_frm > i4_cur_frame_num)\n                {\n                    /* gap's frame_num is before Current frame_num in\n                     decode order */\n                    i4_start_frm -= i4_max_frame_num;\n                }\n                ps_dpb_mgr->ai4_gaps_start_frm_num[i] = i4_start_frm;\n                i4_end_frm = ps_dpb_mgr->ai4_gaps_end_frm_num[i];\n\n                if(i4_end_frm > i4_cur_frame_num)\n                {\n                    /* gap's frame_num is before Current frame_num in\n                     decode order */\n                    i4_end_frm -= i4_max_frame_num;\n                }\n                ps_dpb_mgr->ai4_gaps_end_frm_num[i] = i4_end_frm;\n            }\n        }\n    }\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_update_qp \\endif\n *\n * \\brief\n *    Updates the values of QP and its related entities\n *\n * \\return\n *    0 on Success and Error code otherwise\n *\n **************************************************************************\n */\nWORD32 ih264d_update_qp(dec_struct_t * ps_dec, const WORD8 i1_qp)\n{\n    WORD32 i_temp;\n    i_temp = (ps_dec->u1_qp + i1_qp + 52) % 52;\n\n    if((i_temp < 0) || (i_temp > 51) || (i1_qp < -26) || (i1_qp > 25))\n        return ERROR_INV_RANGE_QP_T;\n\n    ps_dec->u1_qp = i_temp;\n    ps_dec->u1_qp_y_rem6 = ps_dec->u1_qp % 6;\n    ps_dec->u1_qp_y_div6 = ps_dec->u1_qp / 6;\n    i_temp = CLIP3(0, 51, ps_dec->u1_qp + ps_dec->ps_cur_pps->i1_chroma_qp_index_offset);\n    ps_dec->u1_qp_u_rem6 = MOD(gau1_ih264d_qp_scale_cr[12 + i_temp], 6);\n    ps_dec->u1_qp_u_div6 = DIV(gau1_ih264d_qp_scale_cr[12 + i_temp], 6);\n\n    i_temp = CLIP3(0, 51, ps_dec->u1_qp + ps_dec->ps_cur_pps->i1_second_chroma_qp_index_offset);\n    ps_dec->u1_qp_v_rem6 = MOD(gau1_ih264d_qp_scale_cr[12 + i_temp], 6);\n    ps_dec->u1_qp_v_div6 = DIV(gau1_ih264d_qp_scale_cr[12 + i_temp], 6);\n\n    ps_dec->pu2_quant_scale_y =\n                    gau2_ih264_iquant_scale_4x4[ps_dec->u1_qp_y_rem6];\n    ps_dec->pu2_quant_scale_u =\n                    gau2_ih264_iquant_scale_4x4[ps_dec->u1_qp_u_rem6];\n    ps_dec->pu2_quant_scale_v =\n                    gau2_ih264_iquant_scale_4x4[ps_dec->u1_qp_v_rem6];\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_decode_gaps_in_frame_num                                 */\n/*                                                                           */\n/*  Description   : This function decodes gaps in frame number               */\n/*                                                                           */\n/*  Inputs        : ps_dec          Decoder parameters                       */\n/*                  u2_frame_num   current frame number                     */\n/*                                                                           */\n/*  Globals       : None                                                     */\n/*  Processing    : This functionality needs to be implemented               */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : Not implemented                                          */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\nWORD32 ih264d_decode_gaps_in_frame_num(dec_struct_t *ps_dec,\n                                       UWORD16 u2_frame_num)\n{\n    UWORD32 u4_next_frm_num, u4_start_frm_num;\n    UWORD32 u4_max_frm_num;\n    pocstruct_t s_tmp_poc;\n    WORD32 i4_poc;\n    dec_slice_params_t *ps_cur_slice;\n\n    dec_pic_params_t *ps_pic_params;\n    WORD8 i1_gap_idx;\n    WORD32 *i4_gaps_start_frm_num;\n    dpb_manager_t *ps_dpb_mgr;\n    WORD32 i4_frame_gaps;\n    WORD8 *pi1_gaps_per_seq;\n    WORD32 ret;\n\n    ps_cur_slice = ps_dec->ps_cur_slice;\n    if(ps_cur_slice->u1_field_pic_flag)\n    {\n        if(ps_dec->u2_prev_ref_frame_num == u2_frame_num)\n            return 0;\n    }\n\n    u4_next_frm_num = ps_dec->u2_prev_ref_frame_num + 1;\n    u4_max_frm_num = ps_dec->ps_cur_sps->u2_u4_max_pic_num_minus1 + 1;\n\n    // check\n    if(u4_next_frm_num >= u4_max_frm_num)\n    {\n        u4_next_frm_num -= u4_max_frm_num;\n    }\n\n    if(u4_next_frm_num == u2_frame_num)\n    {\n        return (0);\n    }\n\n    // check\n    if((ps_dec->u1_nal_unit_type == IDR_SLICE_NAL)\n                    && (u4_next_frm_num >= u2_frame_num))\n    {\n        return (0);\n    }\n    u4_start_frm_num = u4_next_frm_num;\n\n    s_tmp_poc.i4_pic_order_cnt_lsb = 0;\n    s_tmp_poc.i4_delta_pic_order_cnt_bottom = 0;\n    s_tmp_poc.i4_pic_order_cnt_lsb = 0;\n    s_tmp_poc.i4_delta_pic_order_cnt_bottom = 0;\n    s_tmp_poc.i4_delta_pic_order_cnt[0] = 0;\n    s_tmp_poc.i4_delta_pic_order_cnt[1] = 0;\n\n    ps_cur_slice = ps_dec->ps_cur_slice;\n    ps_pic_params = ps_dec->ps_cur_pps;\n\n    i4_frame_gaps = 0;\n    ps_dpb_mgr = ps_dec->ps_dpb_mgr;\n\n    /* Find a empty slot to store gap seqn info */\n    i4_gaps_start_frm_num = ps_dpb_mgr->ai4_gaps_start_frm_num;\n    for(i1_gap_idx = 0; i1_gap_idx < MAX_FRAMES; i1_gap_idx++)\n    {\n        if(INVALID_FRAME_NUM == i4_gaps_start_frm_num[i1_gap_idx])\n            break;\n    }\n    if(MAX_FRAMES == i1_gap_idx)\n    {\n        UWORD32 i4_error_code;\n        i4_error_code = ERROR_DBP_MANAGER_T;\n//          i4_error_code |= 1<<IVD_CORRUPTEDDATA;\n        return i4_error_code;\n    }\n\n    i4_poc = 0;\n    i4_gaps_start_frm_num[i1_gap_idx] = u4_start_frm_num;\n    ps_dpb_mgr->ai4_gaps_end_frm_num[i1_gap_idx] = u2_frame_num - 1;\n    pi1_gaps_per_seq = ps_dpb_mgr->ai1_gaps_per_seq;\n    pi1_gaps_per_seq[i1_gap_idx] = 0;\n    while(u4_next_frm_num != u2_frame_num)\n    {\n        ih264d_delete_nonref_nondisplay_pics(ps_dpb_mgr);\n        if(ps_pic_params->ps_sps->u1_pic_order_cnt_type)\n        {\n            /* allocate a picture buffer and insert it as ST node */\n            ret = ih264d_decode_pic_order_cnt(0, u4_next_frm_num,\n                                              &ps_dec->s_prev_pic_poc,\n                                              &s_tmp_poc, ps_cur_slice,\n                                              ps_pic_params, 1, 0, 0,\n                                              &i4_poc);\n            if(ret != OK)\n                return ret;\n\n            /* Display seq no calculations */\n            if(i4_poc >= ps_dec->i4_max_poc)\n                ps_dec->i4_max_poc = i4_poc;\n            /* IDR Picture or POC wrap around */\n            if(i4_poc == 0)\n            {\n                WORD64 i8_temp;\n                i8_temp = (WORD64)ps_dec->i4_prev_max_display_seq\n                          + ps_dec->i4_max_poc\n                          + ps_dec->u1_max_dec_frame_buffering + 1;\n                /*If i4_prev_max_display_seq overflows integer range, reset it */\n                ps_dec->i4_prev_max_display_seq = IS_OUT_OF_RANGE_S32(i8_temp)?\n                                                  0 : i8_temp;\n                ps_dec->i4_max_poc = 0;\n            }\n\n            ps_cur_slice->u1_mmco_equalto5 = 0;\n            ps_cur_slice->u2_frame_num = u4_next_frm_num;\n        }\n\n        // check\n        if(ps_dpb_mgr->i1_poc_buf_id_entries\n                        >= ps_dec->u1_max_dec_frame_buffering)\n        {\n            ret = ih264d_assign_display_seq(ps_dec);\n            if(ret != OK)\n                return ret;\n        }\n\n        {\n            WORD64 i8_display_poc;\n            i8_display_poc = (WORD64)ps_dec->i4_prev_max_display_seq +\n                        i4_poc;\n            if(IS_OUT_OF_RANGE_S32(i8_display_poc))\n            {\n                ps_dec->i4_prev_max_display_seq = 0;\n            }\n        }\n        ret = ih264d_insert_pic_in_display_list(\n                        ps_dec->ps_dpb_mgr, (WORD8) DO_NOT_DISP,\n                        (WORD32)(ps_dec->i4_prev_max_display_seq + i4_poc),\n                        u4_next_frm_num);\n        if(ret != OK)\n            return ret;\n\n        pi1_gaps_per_seq[i1_gap_idx]++;\n        ret = ih264d_do_mmco_for_gaps(ps_dpb_mgr,\n                                ps_dec->ps_cur_sps->u1_num_ref_frames);\n        if(ret != OK)\n            return ret;\n\n        ih264d_delete_nonref_nondisplay_pics(ps_dpb_mgr);\n\n        u4_next_frm_num++;\n        if(u4_next_frm_num >= u4_max_frm_num)\n        {\n            u4_next_frm_num -= u4_max_frm_num;\n        }\n\n        i4_frame_gaps++;\n    }\n\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_create_pic_buffers \\endif\n *\n * \\brief\n *    This function creates Picture Buffers.\n *\n * \\return\n *    0 on Success and -1 on error\n **************************************************************************\n */\nWORD32 ih264d_create_pic_buffers(UWORD8 u1_num_of_buf,\n                               dec_struct_t *ps_dec)\n{\n    struct pic_buffer_t *ps_pic_buf;\n    UWORD8 i;\n    UWORD32 u4_luma_size, u4_chroma_size;\n    UWORD8 u1_frm = ps_dec->ps_cur_sps->u1_frame_mbs_only_flag;\n    WORD32 j;\n    UWORD8 *pu1_buf;\n\n    ps_pic_buf = ps_dec->ps_pic_buf_base;\n    ih264_disp_mgr_init((disp_mgr_t *)ps_dec->pv_disp_buf_mgr);\n    ih264_buf_mgr_init((buf_mgr_t *)ps_dec->pv_pic_buf_mgr);\n    u4_luma_size = ps_dec->u2_frm_wd_y * ps_dec->u2_frm_ht_y;\n    u4_chroma_size = ps_dec->u2_frm_wd_uv * ps_dec->u2_frm_ht_uv;\n\n    {\n        if(ps_dec->u4_share_disp_buf == 1)\n        {\n            /* In case of buffers getting shared between application and library\n             there is no need of reference memtabs. Instead of setting the i4_size\n             to zero, it is reduced to a small i4_size to ensure that changes\n             in the code are minimal */\n            if((ps_dec->u1_chroma_format == IV_YUV_420SP_UV)\n                            || (ps_dec->u1_chroma_format == IV_YUV_420SP_VU)\n                            || (ps_dec->u1_chroma_format == IV_YUV_420P))\n            {\n                u4_luma_size = 64;\n            }\n\n            if(ps_dec->u1_chroma_format == IV_YUV_420SP_UV)\n            {\n                u4_chroma_size = 64;\n            }\n\n        }\n    }\n\n    pu1_buf = ps_dec->pu1_pic_buf_base;\n\n    /* Allocate memory for refernce buffers */\n    for(i = 0; i < u1_num_of_buf; i++)\n    {\n        UWORD32 u4_offset;\n        WORD32 buf_ret;\n        UWORD8 *pu1_luma, *pu1_chroma;\n        void *pv_mem_ctxt = ps_dec->pv_mem_ctxt;\n\n        pu1_luma = pu1_buf;\n        pu1_buf += ALIGN64(u4_luma_size);\n        pu1_chroma = pu1_buf;\n        pu1_buf += ALIGN64(u4_chroma_size);\n\n        /* Offset to the start of the pic from the top left corner of the frame\n         buffer */\n\n        if((0 == ps_dec->u4_share_disp_buf)\n                        || (NULL == ps_dec->disp_bufs[i].buf[0]))\n        {\n            UWORD32 pad_len_h, pad_len_v;\n\n            u4_offset = ps_dec->u2_frm_wd_y * (PAD_LEN_Y_V << 1) + PAD_LEN_Y_H;\n            ps_pic_buf->pu1_buf1 = (UWORD8 *)(pu1_luma) + u4_offset;\n\n            pad_len_h = MAX(PAD_LEN_UV_H, (PAD_LEN_Y_H >> 1));\n            pad_len_v = MAX(PAD_LEN_UV_V, PAD_LEN_Y_V);\n\n            u4_offset = ps_dec->u2_frm_wd_uv * pad_len_v + pad_len_h;\n\n            ps_pic_buf->pu1_buf2 = (UWORD8 *)(pu1_chroma) + u4_offset;\n            ps_pic_buf->pu1_buf3 = (UWORD8 *)(NULL) + u4_offset;\n\n        }\n        else\n        {\n            UWORD32 pad_len_h, pad_len_v;\n            u4_offset = ps_dec->u2_frm_wd_y * (PAD_LEN_Y_V << 1) + PAD_LEN_Y_H;\n            ps_pic_buf->pu1_buf1 = (UWORD8 *)ps_dec->disp_bufs[i].buf[0]\n                            + u4_offset;\n\n            ps_dec->disp_bufs[i].u4_ofst[0] = u4_offset;\n\n            if(ps_dec->u1_chroma_format == IV_YUV_420P)\n            {\n                pad_len_h = MAX(PAD_LEN_UV_H * YUV420SP_FACTOR,\n                                (PAD_LEN_Y_H >> 1));\n                pad_len_v = MAX(PAD_LEN_UV_V, PAD_LEN_Y_V);\n\n                u4_offset = ps_dec->u2_frm_wd_uv * pad_len_v + pad_len_h;\n                ps_pic_buf->pu1_buf2 = (UWORD8 *)(pu1_chroma) + u4_offset;\n                ps_pic_buf->pu1_buf3 = (UWORD8 *)(NULL) + u4_offset;\n\n                ps_dec->disp_bufs[i].u4_ofst[1] = u4_offset;\n                ps_dec->disp_bufs[i].u4_ofst[2] = u4_offset;\n\n            }\n            else\n            {\n                pad_len_h = MAX(PAD_LEN_UV_H * YUV420SP_FACTOR,\n                                (PAD_LEN_Y_H >> 1));\n                pad_len_v = MAX(PAD_LEN_UV_V, PAD_LEN_Y_V);\n\n                u4_offset = ps_dec->u2_frm_wd_uv * pad_len_v + pad_len_h;\n                ps_pic_buf->pu1_buf2 = (UWORD8 *)(ps_dec->disp_bufs[i].buf[1])\n                                + u4_offset;\n                ps_pic_buf->pu1_buf3 = (UWORD8 *)(ps_dec->disp_bufs[i].buf[1])\n                                + u4_offset;\n\n                ps_dec->disp_bufs[i].u4_ofst[1] = u4_offset;\n                ps_dec->disp_bufs[i].u4_ofst[2] = u4_offset;\n            }\n        }\n\n        ps_pic_buf->u2_frm_ht_y = ps_dec->u2_frm_ht_y;\n        ps_pic_buf->u2_frm_ht_uv = ps_dec->u2_frm_ht_uv;\n        ps_pic_buf->u2_frm_wd_y = ps_dec->u2_frm_wd_y;\n        ps_pic_buf->u2_frm_wd_uv = ps_dec->u2_frm_wd_uv;\n\n        ps_pic_buf->u1_pic_buf_id = i;\n\n        buf_ret = ih264_buf_mgr_add((buf_mgr_t *)ps_dec->pv_pic_buf_mgr,\n                                    ps_pic_buf, i);\n        if(0 != buf_ret)\n        {\n            ps_dec->i4_error_code = ERROR_BUF_MGR;\n            return ERROR_BUF_MGR;\n        }\n\n        ps_dec->apv_buf_id_pic_buf_map[i] = (void *)ps_pic_buf;\n        ps_pic_buf++;\n    }\n\n    if(1 == ps_dec->u4_share_disp_buf)\n    {\n        for(i = 0; i < u1_num_of_buf; i++)\n            ps_dec->u4_disp_buf_mapping[i] = 1;\n    }\n    return OK;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_allocate_dynamic_bufs \\endif\n *\n * \\brief\n *    This function allocates memory required by Decoder.\n *\n * \\param ps_dec: Pointer to dec_struct_t.\n *\n * \\return\n *    Returns i4_status as returned by MemManager.\n *\n **************************************************************************\n */\nWORD16 ih264d_allocate_dynamic_bufs(dec_struct_t * ps_dec)\n{\n    struct MemReq s_MemReq;\n    struct MemBlock *p_MemBlock;\n\n    pred_info_t *ps_pred_frame;\n    dec_mb_info_t *ps_frm_mb_info;\n    dec_slice_struct_t *ps_dec_slice_buf;\n    UWORD8 *pu1_dec_mb_map, *pu1_recon_mb_map;\n    UWORD16 *pu2_slice_num_map;\n\n    WORD16 *pi16_res_coeff;\n    WORD16 i16_status = 0;\n    UWORD8 uc_frmOrFld = (1 - ps_dec->ps_cur_sps->u1_frame_mbs_only_flag);\n    UWORD16 u4_luma_wd = ps_dec->u2_frm_wd_y;\n    UWORD16 u4_chroma_wd = ps_dec->u2_frm_wd_uv;\n    WORD8 c_i = 0;\n    dec_seq_params_t *ps_sps = ps_dec->ps_cur_sps;\n    UWORD32 u4_total_mbs = ps_sps->u2_total_num_of_mbs << uc_frmOrFld;\n    UWORD32 u4_wd_mbs = ps_dec->u2_frm_wd_in_mbs;\n    UWORD32 u4_ht_mbs = ps_dec->u2_frm_ht_in_mbs;\n    UWORD32 u4_blk_wd;\n    UWORD32 ui_size = 0;\n    UWORD32 u4_int_scratch_size = 0, u4_ref_pred_size = 0;\n    UWORD8 *pu1_buf;\n    WORD32 num_entries;\n    WORD32 size;\n    void *pv_buf;\n    UWORD32 u4_num_bufs;\n    UWORD32 u4_luma_size, u4_chroma_size;\n    void *pv_mem_ctxt = ps_dec->pv_mem_ctxt;\n\n    size = u4_total_mbs;\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pu1_dec_mb_map = pv_buf;\n\n    size = u4_total_mbs;\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pu1_recon_mb_map = pv_buf;\n\n    size = u4_total_mbs * sizeof(UWORD16);\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pu2_slice_num_map = pv_buf;\n\n    /************************************************************/\n    /* Post allocation Initialisations                          */\n    /************************************************************/\n    ps_dec->ps_parse_cur_slice = &(ps_dec->ps_dec_slice_buf[0]);\n    ps_dec->ps_decode_cur_slice = &(ps_dec->ps_dec_slice_buf[0]);\n    ps_dec->ps_computebs_cur_slice = &(ps_dec->ps_dec_slice_buf[0]);\n\n    ps_dec->ps_pred_start = ps_dec->ps_pred;\n\n    size = sizeof(parse_pmbarams_t) * (ps_dec->u1_recon_mb_grp);\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_parse_mb_data = pv_buf;\n\n    size = sizeof(parse_part_params_t)\n                        * ((ps_dec->u1_recon_mb_grp) << 4);\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_parse_part_params = pv_buf;\n\n    size = ((u4_wd_mbs * sizeof(deblkmb_neighbour_t)) << uc_frmOrFld);\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_deblk_top_mb = pv_buf;\n\n    size = ((sizeof(ctxt_inc_mb_info_t))\n                        * (((u4_wd_mbs + 1) << uc_frmOrFld) + 1));\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->p_ctxt_inc_mb_map = pv_buf;\n\n    /* 0th entry of CtxtIncMbMap will be always be containing default values\n     for CABAC context representing MB not available */\n    ps_dec->p_ctxt_inc_mb_map += 1;\n\n    size = (sizeof(mv_pred_t) * ps_dec->u1_recon_mb_grp\n                        * 16);\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_mv_p[0] = pv_buf;\n\n    size = (sizeof(mv_pred_t) * ps_dec->u1_recon_mb_grp\n                        * 16);\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_mv_p[1] = pv_buf;\n\n    {\n        UWORD8 i;\n        for(i = 0; i < MV_SCRATCH_BUFS; i++)\n        {\n            size = (sizeof(mv_pred_t)\n                            * ps_dec->u1_recon_mb_grp * 4);\n            pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n            RETURN_IF((NULL == pv_buf), IV_FAIL);\n            memset(pv_buf, 0, size);\n            ps_dec->ps_mv_top_p[i] = pv_buf;\n        }\n    }\n\n    size = sizeof(UWORD8) * ((u4_wd_mbs + 2) * MB_SIZE) * 2;\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    ps_dec->pu1_y_intra_pred_line = pv_buf;\n    memset(ps_dec->pu1_y_intra_pred_line, 0, size);\n    ps_dec->pu1_y_intra_pred_line += MB_SIZE;\n\n    size = sizeof(UWORD8) * ((u4_wd_mbs + 2) * MB_SIZE) * 2;\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    ps_dec->pu1_u_intra_pred_line = pv_buf;\n    memset(ps_dec->pu1_u_intra_pred_line, 0, size);\n    ps_dec->pu1_u_intra_pred_line += MB_SIZE;\n\n    size = sizeof(UWORD8) * ((u4_wd_mbs + 2) * MB_SIZE) * 2;\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    ps_dec->pu1_v_intra_pred_line = pv_buf;\n    memset(ps_dec->pu1_v_intra_pred_line, 0, size);\n    ps_dec->pu1_v_intra_pred_line += MB_SIZE;\n\n    if(ps_dec->u1_separate_parse)\n    {\n        /* Needs one extra row of info, to hold top row data */\n        size = sizeof(mb_neigbour_params_t)\n                        * 2 * ((u4_wd_mbs + 2) * (u4_ht_mbs + 1));\n    }\n    else\n    {\n        size = sizeof(mb_neigbour_params_t)\n                        * 2 * ((u4_wd_mbs + 2) << uc_frmOrFld);\n    }\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n\n    ps_dec->ps_nbr_mb_row = pv_buf;\n    memset(ps_dec->ps_nbr_mb_row, 0, size);\n\n    /* Allocate deblock MB info */\n    size = (u4_total_mbs + u4_wd_mbs) * sizeof(deblk_mb_t);\n\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    ps_dec->ps_deblk_pic = pv_buf;\n\n    memset(ps_dec->ps_deblk_pic, 0, size);\n\n    /* Allocate frame level mb info */\n    size = sizeof(dec_mb_info_t) * u4_total_mbs;\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    ps_dec->ps_frm_mb_info = pv_buf;\n    memset(ps_dec->ps_frm_mb_info, 0, size);\n\n    /* Allocate memory for slice headers dec_slice_struct_t */\n    num_entries = MAX_FRAMES;\n    if((1 >= ps_dec->ps_cur_sps->u1_num_ref_frames) &&\n        (0 == ps_dec->i4_display_delay))\n    {\n        num_entries = 1;\n    }\n    num_entries = ((2 * num_entries) + 1);\n    num_entries *= 2;\n\n    size = num_entries * sizeof(void *);\n    size += PAD_MAP_IDX_POC * sizeof(void *);\n    size *= u4_total_mbs;\n    size += sizeof(dec_slice_struct_t) * u4_total_mbs;\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n\n    ps_dec->ps_dec_slice_buf = pv_buf;\n    memset(ps_dec->ps_dec_slice_buf, 0, size);\n    pu1_buf = (UWORD8 *)ps_dec->ps_dec_slice_buf;\n    pu1_buf += sizeof(dec_slice_struct_t) * u4_total_mbs;\n    ps_dec->pv_map_ref_idx_to_poc_buf = (void *)pu1_buf;\n\n    /* Allocate memory for packed pred info */\n    num_entries = u4_total_mbs;\n    num_entries *= 16 * 2;\n\n    size = sizeof(pred_info_pkd_t) * num_entries;\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->ps_pred_pkd = pv_buf;\n\n    /* Allocate memory for coeff data */\n    size = MB_LUM_SIZE * sizeof(WORD16);\n    /*For I16x16 MBs, 16 4x4 AC coeffs and 1 4x4 DC coeff TU blocks will be sent\n    For all MBs along with 8 4x4 AC coeffs 2 2x2 DC coeff TU blocks will be sent\n    So use 17 4x4 TU blocks for luma and 9 4x4 TU blocks for chroma */\n    size += u4_total_mbs * (MAX(17 * sizeof(tu_sblk4x4_coeff_data_t),4 * sizeof(tu_blk8x8_coeff_data_t))\n                                            + 9 * sizeof(tu_sblk4x4_coeff_data_t));\n    //32 bytes for each mb to store u1_prev_intra4x4_pred_mode and u1_rem_intra4x4_pred_mode data\n    size += u4_total_mbs * 32;\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n\n    ps_dec->pi2_coeff_data = pv_buf;\n\n    ps_dec->pv_pic_tu_coeff_data = (void *)(ps_dec->pi2_coeff_data + MB_LUM_SIZE);\n\n    /* Allocate MV bank buffer */\n    {\n        UWORD32 col_flag_buffer_size, mvpred_buffer_size;\n\n        col_flag_buffer_size = ((ps_dec->u2_pic_wd * ps_dec->u2_pic_ht) >> 4);\n        mvpred_buffer_size = sizeof(mv_pred_t)\n                        * ((ps_dec->u2_pic_wd * (ps_dec->u2_pic_ht + PAD_MV_BANK_ROW)) >> 4);\n\n        u4_num_bufs = ps_dec->ps_cur_sps->u1_num_ref_frames + 1;\n\n        u4_num_bufs = MIN(u4_num_bufs, ps_dec->u1_pic_bufs);\n        u4_num_bufs = MAX(u4_num_bufs, 2);\n        size = ALIGN64(mvpred_buffer_size) + ALIGN64(col_flag_buffer_size);\n        size *= u4_num_bufs;\n        pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n        RETURN_IF((NULL == pv_buf), IV_FAIL);\n        memset(pv_buf, 0, size);\n        ps_dec->pu1_mv_bank_buf_base = pv_buf;\n    }\n\n    /* Allocate Pic buffer */\n    u4_luma_size = ps_dec->u2_frm_wd_y * ps_dec->u2_frm_ht_y;\n    u4_chroma_size = ps_dec->u2_frm_wd_uv * ps_dec->u2_frm_ht_uv;\n\n    {\n        if(ps_dec->u4_share_disp_buf == 1)\n        {\n            /* In case of buffers getting shared between application and library\n             there is no need of reference memtabs. Instead of setting the i4_size\n             to zero, it is reduced to a small i4_size to ensure that changes\n             in the code are minimal */\n            if((ps_dec->u1_chroma_format == IV_YUV_420SP_UV)\n                            || (ps_dec->u1_chroma_format == IV_YUV_420SP_VU)\n                            || (ps_dec->u1_chroma_format == IV_YUV_420P))\n            {\n                u4_luma_size = 64;\n            }\n\n            if(ps_dec->u1_chroma_format == IV_YUV_420SP_UV)\n            {\n                u4_chroma_size = 64;\n            }\n\n        }\n    }\n\n    size = ALIGN64(u4_luma_size) + ALIGN64(u4_chroma_size);\n    size *= ps_dec->u1_pic_bufs;\n    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);\n    RETURN_IF((NULL == pv_buf), IV_FAIL);\n    memset(pv_buf, 0, size);\n    ps_dec->pu1_pic_buf_base = pv_buf;\n\n    /* Post allocation Increment Actions */\n\n    /***************************************************************************/\n    /*Initialize cabac context pointers for every SE that has fixed contextIdx */\n    /***************************************************************************/\n    {\n        bin_ctxt_model_t * const p_cabac_ctxt_table_t =\n                        ps_dec->p_cabac_ctxt_table_t;\n        bin_ctxt_model_t * * p_coeff_abs_level_minus1_t =\n                        ps_dec->p_coeff_abs_level_minus1_t;\n        bin_ctxt_model_t * * p_cbf_t = ps_dec->p_cbf_t;\n\n        ps_dec->p_mb_field_dec_flag_t = p_cabac_ctxt_table_t\n                        + MB_FIELD_DECODING_FLAG;\n        ps_dec->p_prev_intra4x4_pred_mode_flag_t = p_cabac_ctxt_table_t\n                        + PREV_INTRA4X4_PRED_MODE_FLAG;\n        ps_dec->p_rem_intra4x4_pred_mode_t = p_cabac_ctxt_table_t\n                        + REM_INTRA4X4_PRED_MODE;\n        ps_dec->p_intra_chroma_pred_mode_t = p_cabac_ctxt_table_t\n                        + INTRA_CHROMA_PRED_MODE;\n        ps_dec->p_mb_qp_delta_t = p_cabac_ctxt_table_t + MB_QP_DELTA;\n        ps_dec->p_ref_idx_t = p_cabac_ctxt_table_t + REF_IDX;\n        ps_dec->p_mvd_x_t = p_cabac_ctxt_table_t + MVD_X;\n        ps_dec->p_mvd_y_t = p_cabac_ctxt_table_t + MVD_Y;\n        p_cbf_t[0] = p_cabac_ctxt_table_t + CBF + 0;\n        p_cbf_t[1] = p_cabac_ctxt_table_t + CBF + 4;\n        p_cbf_t[2] = p_cabac_ctxt_table_t + CBF + 8;\n        p_cbf_t[3] = p_cabac_ctxt_table_t + CBF + 12;\n        p_cbf_t[4] = p_cabac_ctxt_table_t + CBF + 16;\n        ps_dec->p_cbp_luma_t = p_cabac_ctxt_table_t + CBP_LUMA;\n        ps_dec->p_cbp_chroma_t = p_cabac_ctxt_table_t + CBP_CHROMA;\n\n        p_coeff_abs_level_minus1_t[LUMA_DC_CTXCAT] = p_cabac_ctxt_table_t\n                        + COEFF_ABS_LEVEL_MINUS1 + COEFF_ABS_LEVEL_CAT_0_OFFSET;\n\n        p_coeff_abs_level_minus1_t[LUMA_AC_CTXCAT] = p_cabac_ctxt_table_t\n                        + COEFF_ABS_LEVEL_MINUS1 + COEFF_ABS_LEVEL_CAT_1_OFFSET;\n\n        p_coeff_abs_level_minus1_t[LUMA_4X4_CTXCAT] = p_cabac_ctxt_table_t\n                        + COEFF_ABS_LEVEL_MINUS1 + COEFF_ABS_LEVEL_CAT_2_OFFSET;\n\n        p_coeff_abs_level_minus1_t[CHROMA_DC_CTXCAT] = p_cabac_ctxt_table_t\n                        + COEFF_ABS_LEVEL_MINUS1 + COEFF_ABS_LEVEL_CAT_3_OFFSET;\n\n        p_coeff_abs_level_minus1_t[CHROMA_AC_CTXCAT] = p_cabac_ctxt_table_t\n                        + COEFF_ABS_LEVEL_MINUS1 + COEFF_ABS_LEVEL_CAT_4_OFFSET;\n\n        p_coeff_abs_level_minus1_t[LUMA_8X8_CTXCAT] = p_cabac_ctxt_table_t\n                        + COEFF_ABS_LEVEL_MINUS1_8X8\n                        + COEFF_ABS_LEVEL_CAT_5_OFFSET;\n\n        /********************************************************/\n        /* context for the high profile related syntax elements */\n        /* This is maintained seperately in s_high_profile     */\n        /********************************************************/\n        {\n\n            ps_dec->s_high_profile.ps_transform8x8_flag = p_cabac_ctxt_table_t\n                            + TRANSFORM_SIZE_8X8_FLAG;\n\n            ps_dec->s_high_profile.ps_sigcoeff_8x8_frame = p_cabac_ctxt_table_t\n                            + SIGNIFICANT_COEFF_FLAG_8X8_FRAME;\n\n            ps_dec->s_high_profile.ps_last_sigcoeff_8x8_frame =\n                            p_cabac_ctxt_table_t\n                                            + LAST_SIGNIFICANT_COEFF_FLAG_8X8_FRAME;\n\n            ps_dec->s_high_profile.ps_coeff_abs_levelminus1 =\n                            p_cabac_ctxt_table_t + COEFF_ABS_LEVEL_MINUS1_8X8;\n\n            ps_dec->s_high_profile.ps_sigcoeff_8x8_field = p_cabac_ctxt_table_t\n                            + SIGNIFICANT_COEFF_FLAG_8X8_FIELD;\n\n            ps_dec->s_high_profile.ps_last_sigcoeff_8x8_field =\n                            p_cabac_ctxt_table_t\n                                            + LAST_SIGNIFICANT_COEFF_FLAG_8X8_FIELD;\n        }\n    }\n    return (i16_status);\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_free_dynamic_bufs \\endif\n *\n * \\brief\n *    This function frees dynamic memory allocated by Decoder.\n *\n * \\param ps_dec: Pointer to dec_struct_t.\n *\n * \\return\n *    Returns i4_status as returned by MemManager.\n *\n **************************************************************************\n */\nWORD16 ih264d_free_dynamic_bufs(dec_struct_t * ps_dec)\n{\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_bits_buf_dynamic);\n\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_deblk_pic);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_dec_mb_map);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_recon_mb_map);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu2_slice_num_map);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_dec_slice_buf);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_frm_mb_info);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pi2_coeff_data);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_parse_mb_data);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_parse_part_params);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_deblk_top_mb);\n\n    if(ps_dec->p_ctxt_inc_mb_map)\n    {\n        ps_dec->p_ctxt_inc_mb_map -= 1;\n        PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->p_ctxt_inc_mb_map);\n    }\n\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_mv_p[0]);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_mv_p[1]);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_pred_pkd);\n    {\n        UWORD8 i;\n        for(i = 0; i < MV_SCRATCH_BUFS; i++)\n        {\n            PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_mv_top_p[i]);\n        }\n    }\n\n    if(ps_dec->pu1_y_intra_pred_line)\n    {\n        ps_dec->pu1_y_intra_pred_line -= MB_SIZE;\n    }\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_y_intra_pred_line);\n\n    if(ps_dec->pu1_u_intra_pred_line)\n    {\n        ps_dec->pu1_u_intra_pred_line -= MB_SIZE;\n    }\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_u_intra_pred_line);\n\n    if(ps_dec->pu1_v_intra_pred_line)\n    {\n        ps_dec->pu1_v_intra_pred_line -= MB_SIZE;\n    }\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_v_intra_pred_line);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->ps_nbr_mb_row);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_mv_bank_buf_base);\n    PS_DEC_ALIGNED_FREE(ps_dec, ps_dec->pu1_pic_buf_base);\n    return 0;\n}\n\n/*!\n **************************************************************************\n * \\if Function name : ih264d_create_mv_bank \\endif\n *\n * \\brief\n *    This function creates MV bank.\n *\n * \\param memType  : Type of memory being handled\n *                   0: Display Buffer\n *                   1: Decoder Buffer\n *                   2: Internal Buffer\n * \\param u1_num_of_buf: Number of decode or display buffers.\n * \\param u4_wd : Frame width.\n * \\param u4_ht : Frame Height.\n * \\param ps_pic_buf_api : Pointer to Picture Buffer API.\n * \\param ih264d_dec_mem_manager  : Memory manager utility supplied by system.\n *\n * \\return\n *    0 on Success and -1 on error\n *\n **************************************************************************\n */\nWORD32 ih264d_create_mv_bank(void *pv_dec,\n                             UWORD32 ui_width,\n                             UWORD32 ui_height)\n{\n    UWORD8  i;\n    UWORD32 col_flag_buffer_size, mvpred_buffer_size;\n    UWORD8 *pu1_mv_buf_mgr_base, *pu1_mv_bank_base;\n    col_mv_buf_t *ps_col_mv;\n    mv_pred_t *ps_mv;\n    UWORD8 *pu1_col_zero_flag_buf;\n    dec_struct_t *ps_dec = (dec_struct_t *)pv_dec;\n    WORD32 buf_ret;\n    UWORD32 u4_num_bufs;\n    UWORD8 *pu1_buf;\n    WORD32 size;\n    void *pv_mem_ctxt = ps_dec->pv_mem_ctxt;\n\n    col_flag_buffer_size = ((ui_width * ui_height) >> 4);\n    mvpred_buffer_size = sizeof(mv_pred_t)\n                    * ((ui_width * (ui_height + PAD_MV_BANK_ROW)) >> 4);\n\n    ih264_buf_mgr_init((buf_mgr_t *)ps_dec->pv_mv_buf_mgr);\n\n    ps_col_mv = ps_dec->ps_col_mv_base;\n\n    u4_num_bufs = ps_dec->ps_cur_sps->u1_num_ref_frames + 1;\n\n    u4_num_bufs = MIN(u4_num_bufs, ps_dec->u1_pic_bufs);\n    u4_num_bufs = MAX(u4_num_bufs, 2);\n    pu1_buf = ps_dec->pu1_mv_bank_buf_base;\n    for(i = 0 ; i < u4_num_bufs ; i++)\n    {\n        pu1_col_zero_flag_buf = pu1_buf;\n        pu1_buf += ALIGN64(col_flag_buffer_size);\n\n        ps_mv = (mv_pred_t *)pu1_buf;\n        pu1_buf += ALIGN64(mvpred_buffer_size);\n\n        memset(ps_mv, 0, ((ui_width * OFFSET_MV_BANK_ROW) >> 4) * sizeof(mv_pred_t));\n        ps_mv += (ui_width*OFFSET_MV_BANK_ROW) >> 4;\n\n        ps_col_mv->pv_col_zero_flag = (void *)pu1_col_zero_flag_buf;\n        ps_col_mv->pv_mv = (void *)ps_mv;\n        buf_ret = ih264_buf_mgr_add((buf_mgr_t *)ps_dec->pv_mv_buf_mgr, ps_col_mv, i);\n        if(0 != buf_ret)\n        {\n            ps_dec->i4_error_code = ERROR_BUF_MGR;\n            return ERROR_BUF_MGR;\n        }\n        ps_col_mv++;\n    }\n    return OK;\n}\n\nvoid ih264d_unpack_coeff4x4_dc_4x4blk(tu_sblk4x4_coeff_data_t *ps_tu_4x4,\n                                      WORD16 *pi2_out_coeff_data,\n                                      UWORD8 *pu1_inv_scan)\n{\n    UWORD16 u2_sig_coeff_map = ps_tu_4x4->u2_sig_coeff_map;\n    WORD32 idx;\n    WORD16 *pi2_coeff_data = &ps_tu_4x4->ai2_level[0];\n\n    while(u2_sig_coeff_map)\n    {\n        idx = CLZ(u2_sig_coeff_map);\n\n        idx = 31 - idx;\n        RESET_BIT(u2_sig_coeff_map,idx);\n\n        idx = pu1_inv_scan[idx];\n        pi2_out_coeff_data[idx] = *pi2_coeff_data++;\n\n    }\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_utils.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n#ifndef  _IH264D_UTILS_H_\n#define  _IH264D_UTILS_H_\n/*!\n**************************************************************************\n* \\file ih264d_utils.h\n*\n* \\brief\n*    Contains declaration of routines\n*    that handle of start and end of pic processing\n*\n* \\date\n*    19/12/2002\n*\n* \\author  AI\n**************************************************************************\n*/\n#include \"ih264d_defs.h\"\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_parse_cavlc.h\"\n\n#define PS_DEC_ALIGNED_FREE(ps_dec, y) \\\nif(y) {ps_dec->pf_aligned_free(ps_dec->pv_mem_ctxt, ((void *)y)); (y) = NULL;}\nvoid pad_frm_buff_vert(dec_struct_t *ps_dec);\n\nUWORD8 ih264d_is_end_of_pic(UWORD16 u2_frame_num,\n                            UWORD8 u1_nal_ref_idc,\n                            pocstruct_t *ps_cur_poc,\n                            pocstruct_t *ps_prev_poc,\n                            dec_slice_params_t * ps_prev_slice,\n                            UWORD8 u1_pic_order_cnt_type,\n                            UWORD8 u1_nal_unit_type,\n                            UWORD32 u4_idr_pic_id,\n                            UWORD8 u1_field_pic_flag,\n                            UWORD8 u1_bottom_field_flag);\n\nWORD32 ih264d_end_of_pic_processing(dec_struct_t * ps_dec);\n\nWORD32 ih264d_init_pic(dec_struct_t *ps_dec,\n                       UWORD16 u2_frame_num,\n                       WORD32 i4_poc,\n                       dec_pic_params_t * ps_pps);\n\nWORD32 ih264d_end_of_pic_processing(dec_struct_t * ps_dec);\nWORD32 ih264d_decode_pic_order_cnt(UWORD8 u1_is_idr_slice,\n                                   UWORD32 u2_frame_num,\n                                   pocstruct_t *ps_prev_poc,\n                                   pocstruct_t *ps_cur_poc,\n                                   dec_slice_params_t *ps_cur_slice,\n                                   dec_pic_params_t * ps_pps,\n                                   UWORD8 u1_nal_ref_idc,\n                                   UWORD8 u1_bottom_field_flag,\n                                   UWORD8 u1_field_pic_flag,\n                                   WORD32 *pi4_poc);\nvoid ih264d_release_display_bufs(dec_struct_t *ps_dec);\nWORD32 ih264d_assign_display_seq(dec_struct_t *ps_dec);\nvoid ih264d_assign_pic_num(dec_struct_t *ps_dec);\n\nvoid ih264d_unpack_coeff4x4_dc_4x4blk(tu_sblk4x4_coeff_data_t *ps_tu_4x4,\n                                      WORD16 *pi2_out_coeff_data,\n                                      UWORD8 *pu1_inv_scan);\n\nWORD32 ih264d_update_qp(dec_struct_t * ps_dec, const WORD8 i1_qp);\nWORD32 ih264d_decode_gaps_in_frame_num(dec_struct_t *ps_dec,\n                                       UWORD16 u2_frame_num);\n\nWORD32 ih264d_get_next_display_field(dec_struct_t * ps_dec,\n                                  ivd_out_bufdesc_t *ps_out_buffer,\n                                  ivd_get_display_frame_op_t *pv_disp_op);\n\nvoid ih264d_release_display_field(dec_struct_t *ps_dec,\n                                  ivd_get_display_frame_op_t *pv_disp_op);\nvoid ih264d_close_video_decoder(iv_obj_t *iv_obj_t);\nWORD32 ih264d_get_dpb_size(dec_seq_params_t *ps_seq);\nWORD32 ih264d_get_next_nal_unit(UWORD8 *pu1_buf,\n                                UWORD32 u4_cur_pos,\n                                UWORD32 u4_max_ofst,\n                                UWORD32 *pu4_length_of_start_code);\n\nWORD16 ih264d_free_dynamic_bufs(dec_struct_t * ps_dec);\n#endif /* _IH264D_UTILS_H_ */\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_vui.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264d_vui.c                                                */\n/*                                                                           */\n/*  Description       : This file contains routines to parse VUI NAL's       */\n/*                                                                           */\n/*  List of Functions : <List the functions defined in this file>            */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         25 05 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_vui.h\"\n#include \"ih264d_bitstrm.h\"\n#include \"ih264d_parse_cavlc.h\"\n#include \"ih264d_structs.h\"\n#include \"ih264d_error_handler.h\"\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_hrd_parametres                                     */\n/*                                                                           */\n/*  Description   : This function parses hrd_t parametres                      */\n/*  Inputs        : ps_hrd          pointer to HRD params                    */\n/*                  ps_bitstrm   Bitstream                                */\n/*  Globals       : None                                                     */\n/*  Processing    : Parses HRD params                                        */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_parse_hrd_parametres(hrd_t *ps_hrd,\n                                   dec_bit_stream_t *ps_bitstrm)\n{\n    UWORD8 u1_index;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n\n    ps_hrd->u4_cpb_cnt = 1\n                    + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf);\n    if(ps_hrd->u4_cpb_cnt > 31)\n        return ERROR_INV_SPS_PPS_T;\n    ps_hrd->u1_bit_rate_scale = ih264d_get_bits_h264(ps_bitstrm, 4);\n    ps_hrd->u1_cpb_size_scale = ih264d_get_bits_h264(ps_bitstrm, 4);\n\n    for(u1_index = 0; u1_index < (UWORD8)ps_hrd->u4_cpb_cnt; u1_index++)\n    {\n        ps_hrd->u4_bit_rate[u1_index] = 1\n                        + ih264d_uev(pu4_bitstrm_ofst,\n                                     pu4_bitstrm_buf);\n        ps_hrd->u4_cpb_size[u1_index] = 1\n                        + ih264d_uev(pu4_bitstrm_ofst,\n                                     pu4_bitstrm_buf);\n        ps_hrd->u1_cbr_flag[u1_index] = ih264d_get_bits_h264(ps_bitstrm, 1);\n    }\n\n    ps_hrd->u1_initial_cpb_removal_delay = 1\n                    + ih264d_get_bits_h264(ps_bitstrm, 5);\n    ps_hrd->u1_cpb_removal_delay_length = 1\n                    + ih264d_get_bits_h264(ps_bitstrm, 5);\n    ps_hrd->u1_dpb_output_delay_length = 1\n                    + ih264d_get_bits_h264(ps_bitstrm, 5);\n    ps_hrd->u1_time_offset_length = ih264d_get_bits_h264(ps_bitstrm, 5);\n\n    return OK;\n}\n\n/*****************************************************************************/\n/*                                                                           */\n/*  Function Name : ih264d_parse_vui_parametres                                     */\n/*                                                                           */\n/*  Description   : This function parses VUI NALs.                           */\n/*  Inputs        : ps_vu4          pointer to VUI params                    */\n/*                  ps_bitstrm   Bitstream                                */\n/*  Globals       : None                                                     */\n/*  Processing    : Parses VUI NAL's units and stores the info               */\n/*  Outputs       : None                                                     */\n/*  Returns       : None                                                     */\n/*                                                                           */\n/*  Issues        : None                                                     */\n/*                                                                           */\n/*  Revision History:                                                        */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         06 05 2002   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\nWORD32 ih264d_parse_vui_parametres(vui_t *ps_vu4,\n                                   dec_bit_stream_t *ps_bitstrm)\n{\n    UWORD8 u4_bits;\n    UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst;\n    UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer;\n    WORD32 ret;\n\n    u4_bits = ih264d_get_bits_h264(ps_bitstrm, 1);\n    if(u4_bits)\n    {\n        u4_bits = ih264d_get_bits_h264(ps_bitstrm, 8);\n        ps_vu4->u1_aspect_ratio_idc = (UWORD8)u4_bits;\n        if(VUI_EXTENDED_SAR == u4_bits)\n        {\n            ps_vu4->u2_sar_width = ih264d_get_bits_h264(ps_bitstrm, 16);\n            ps_vu4->u2_sar_height = ih264d_get_bits_h264(ps_bitstrm, 16);\n        }\n    }\n\n    u4_bits = ih264d_get_bits_h264(ps_bitstrm, 1);\n    if(u4_bits)\n    {\n        ps_vu4->u1_overscan_appropriate_flag = ih264d_get_bits_h264(\n                        ps_bitstrm, 1);\n    }\n    u4_bits = ih264d_get_bits_h264(ps_bitstrm, 1);\n    /* Initialize to unspecified (5 for video_format and\n       2 for colour_primaries, tfr_chars, matrix_coeffs  */\n    ps_vu4->u1_video_format = 5;\n    ps_vu4->u1_video_full_range_flag = 0;\n    ps_vu4->u1_colour_primaries = 2;\n    ps_vu4->u1_tfr_chars = 2;\n    ps_vu4->u1_matrix_coeffs = 2;\n\n    if(u4_bits)\n    {\n        ps_vu4->u1_video_format = ih264d_get_bits_h264(ps_bitstrm, 3);\n        ps_vu4->u1_video_full_range_flag = ih264d_get_bits_h264(ps_bitstrm,\n                                                                1);\n        u4_bits = ih264d_get_bits_h264(ps_bitstrm, 1);\n        if(u4_bits)\n        {\n            ps_vu4->u1_colour_primaries = ih264d_get_bits_h264(ps_bitstrm,\n                                                               8);\n            ps_vu4->u1_tfr_chars = ih264d_get_bits_h264(ps_bitstrm, 8);\n            ps_vu4->u1_matrix_coeffs = ih264d_get_bits_h264(ps_bitstrm, 8);\n        }\n    }\n\n    u4_bits = ih264d_get_bits_h264(ps_bitstrm, 1);\n    if(u4_bits)\n    {\n        ps_vu4->u1_cr_top_field = ih264d_uev(pu4_bitstrm_ofst,\n                                             pu4_bitstrm_buf);\n        ps_vu4->u1_cr_bottom_field = ih264d_uev(pu4_bitstrm_ofst,\n                                                pu4_bitstrm_buf);\n    }\n\n    u4_bits = ih264d_get_bits_h264(ps_bitstrm, 1);\n    if(u4_bits)\n    {\n        ps_vu4->u4_num_units_in_tick = ih264d_get_bits_h264(ps_bitstrm, 32);\n        ps_vu4->u4_time_scale = ih264d_get_bits_h264(ps_bitstrm, 32);\n        ps_vu4->u1_fixed_frame_rate_flag = ih264d_get_bits_h264(ps_bitstrm,\n                                                                1);\n    }\n\n    u4_bits = ih264d_get_bits_h264(ps_bitstrm, 1);\n    ps_vu4->u1_nal_hrd_params_present = u4_bits;\n    if(u4_bits)\n    {\n        ret = ih264d_parse_hrd_parametres(&ps_vu4->s_nal_hrd, ps_bitstrm);\n        if(ret != OK)\n            return ret;\n    }\n    u4_bits = ih264d_get_bits_h264(ps_bitstrm, 1);\n    ps_vu4->u1_vcl_hrd_params_present = u4_bits;\n    if(u4_bits)\n    {\n        ret = ih264d_parse_hrd_parametres(&ps_vu4->s_vcl_hrd, ps_bitstrm);\n        if(ret != OK)\n            return ret;\n    }\n\n    if(ps_vu4->u1_nal_hrd_params_present || u4_bits)\n    {\n        ps_vu4->u1_low_delay_hrd_flag = ih264d_get_bits_h264(ps_bitstrm, 1);\n    }\n    ps_vu4->u1_pic_struct_present_flag = ih264d_get_bits_h264(ps_bitstrm, 1);\n\n    ps_vu4->u1_bitstream_restriction_flag = ih264d_get_bits_h264(ps_bitstrm, 1);\n\n    if(ps_vu4->u1_bitstream_restriction_flag)\n    {\n        ps_vu4->u1_mv_over_pic_boundaries_flag = ih264d_get_bits_h264(\n                        ps_bitstrm, 1);\n        ps_vu4->u4_max_bytes_per_pic_denom = ih264d_uev(pu4_bitstrm_ofst,\n                                                        pu4_bitstrm_buf);\n        ps_vu4->u4_max_bits_per_mb_denom = ih264d_uev(pu4_bitstrm_ofst,\n                                                      pu4_bitstrm_buf);\n        ps_vu4->u4_log2_max_mv_length_horz = ih264d_uev(pu4_bitstrm_ofst,\n                                                        pu4_bitstrm_buf);\n        ps_vu4->u4_log2_max_mv_length_vert = ih264d_uev(pu4_bitstrm_ofst,\n                                                        pu4_bitstrm_buf);\n        ps_vu4->u4_num_reorder_frames = ih264d_uev(pu4_bitstrm_ofst,\n                                                   pu4_bitstrm_buf);\n        ps_vu4->u4_max_dec_frame_buffering = ih264d_uev(pu4_bitstrm_ofst,\n                                                        pu4_bitstrm_buf);\n        if((ps_vu4->u4_max_dec_frame_buffering > (H264_MAX_REF_PICS * 2)) ||\n           (ps_vu4->u4_num_reorder_frames > ps_vu4->u4_max_dec_frame_buffering))\n        {\n            return ERROR_INV_SPS_PPS_T;\n        }\n    }\n    else\n    {\n        /* Setting this to a large value if not present */\n        ps_vu4->u4_num_reorder_frames = 64;\n        ps_vu4->u4_max_dec_frame_buffering = 64;\n    }\n\n    return OK;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ih264d_vui.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n\n/*****************************************************************************/\n/*                                                                           */\n/*  File Name         : ih264d_vui.h                                                */\n/*                                                                           */\n/*  Description       : This file contains routines to parse SEI NAL's       */\n/*                                                                           */\n/*  List of Functions : <List the functions defined in this file>            */\n/*                                                                           */\n/*  Issues / Problems : None                                                 */\n/*                                                                           */\n/*  Revision History  :                                                      */\n/*                                                                           */\n/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */\n/*         25 05 2005   NS              Draft                                */\n/*                                                                           */\n/*****************************************************************************/\n\n#ifndef _IH264D_VUI_H_\n#define _IH264D_VUI_H_\n\n#include \"ih264_typedefs.h\"\n#include \"ih264_macros.h\"\n#include \"ih264_platform_macros.h\"\n#include \"ih264d_bitstrm.h\"\n\n#define VUI_EXTENDED_SAR    255\n\ntypedef struct\n{\n    UWORD32 u4_cpb_cnt;\n    UWORD8 u1_bit_rate_scale;\n    UWORD8 u1_cpb_size_scale;\n    UWORD32 u4_bit_rate[32];\n    UWORD32 u4_cpb_size[32];\n    UWORD8 u1_cbr_flag[32];\n    UWORD8 u1_initial_cpb_removal_delay;\n    UWORD8 u1_cpb_removal_delay_length;\n    UWORD8 u1_dpb_output_delay_length;\n    UWORD8 u1_time_offset_length;\n} hrd_t;\n\ntypedef struct\n{\n    UWORD8 u1_aspect_ratio_idc;\n    UWORD16 u2_sar_width;\n    UWORD16 u2_sar_height;\n    UWORD8 u1_overscan_appropriate_flag;\n    UWORD8 u1_video_format;\n    UWORD8 u1_video_full_range_flag;\n    UWORD8 u1_colour_primaries;\n    UWORD8 u1_tfr_chars;\n    UWORD8 u1_matrix_coeffs;\n    UWORD8 u1_cr_top_field;\n    UWORD8 u1_cr_bottom_field;\n    UWORD32 u4_num_units_in_tick;\n    UWORD32 u4_time_scale;\n    UWORD8 u1_fixed_frame_rate_flag;\n    UWORD8 u1_nal_hrd_params_present;\n    hrd_t s_nal_hrd;\n    UWORD8 u1_vcl_hrd_params_present;\n    hrd_t s_vcl_hrd;\n    UWORD8 u1_low_delay_hrd_flag;\n    UWORD8 u1_pic_struct_present_flag;\n    UWORD8 u1_bitstream_restriction_flag;\n    UWORD8 u1_mv_over_pic_boundaries_flag;\n    UWORD32 u4_max_bytes_per_pic_denom;\n    UWORD32 u4_max_bits_per_mb_denom;\n    UWORD32 u4_log2_max_mv_length_horz;\n    UWORD32 u4_log2_max_mv_length_vert;\n    UWORD32 u4_num_reorder_frames;\n    UWORD32 u4_max_dec_frame_buffering;\n} vui_t;\n\nWORD32 ih264d_parse_vui_parametres(vui_t *ps_vu4,\n                                   dec_bit_stream_t *ps_bitstrm);\n#endif /* _SEI_H_ */\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/iv.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n * Modified for use with Cemu emulator project\n*/\n/**\n*******************************************************************************\n* @file\n*  iv.h\n*\n* @brief\n*  This file contains all the necessary structure and  enumeration\n* definitions needed for the Application  Program Interface(API) of the\n* Ittiam Video and Image  codecs\n*\n* @author\n*  100239(RCY)\n*\n* @par List of Functions:\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n\n#ifndef _IV_H\n#define _IV_H\n\n/*****************************************************************************/\n/* Constant Macros                                                           */\n/*****************************************************************************/\n\n\n/*****************************************************************************/\n/* Typedefs                                                                  */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/* Enums                                                                     */\n/*****************************************************************************/\n\n\n/* IV_API_CALL_STATUS_T:This is only to return the FAIL/PASS status to the  */\n/* application for the current API call                                     */\n\ntypedef enum {\n    IV_STATUS_NA                                = 0x7FFFFFFF,\n    IV_SUCCESS                                  = 0x0,\n    IV_FAIL                                     = 0x1,\n}IV_API_CALL_STATUS_T;\n\n\n/* IV_COLOR_FORMAT_T: This enumeration lists all the color formats which    */\n/* finds usage in video/image codecs                                        */\n\ntypedef enum {\n    IV_CHROMA_NA                            = 0x7FFFFFFF,\n    IV_YUV_420P                             = 0x1,\n    IV_YUV_422P                             = 0x2,\n    IV_420_UV_INTL                          = 0x3,\n    IV_YUV_422IBE                           = 0x4,\n    IV_YUV_422ILE                           = 0x5,\n    IV_YUV_444P                             = 0x6,\n    IV_YUV_411P                             = 0x7,\n    IV_GRAY                                 = 0x8,\n    IV_RGB_565                              = 0x9,\n    IV_RGB_24                               = 0xa,\n    IV_YUV_420SP_UV                         = 0xb,\n    IV_YUV_420SP_VU                         = 0xc,\n    IV_RGBA_8888                            = 0xd\n}IV_COLOR_FORMAT_T;\n\n/* IV_PICTURE_CODING_TYPE_T: VOP/Frame coding type Enumeration              */\n\ntypedef enum {\n    IV_NA_FRAME                             = 0x7FFFFFFF,\n    IV_I_FRAME                              = 0x0,\n    IV_P_FRAME                              = 0x1,\n    IV_B_FRAME                              = 0x2,\n    IV_IDR_FRAME                            = 0x3,\n    IV_II_FRAME                             = 0x4,\n    IV_IP_FRAME                             = 0x5,\n    IV_IB_FRAME                             = 0x6,\n    IV_PI_FRAME                             = 0x7,\n    IV_PP_FRAME                             = 0x8,\n    IV_PB_FRAME                             = 0x9,\n    IV_BI_FRAME                             = 0xa,\n    IV_BP_FRAME                             = 0xb,\n    IV_BB_FRAME                             = 0xc,\n    IV_MBAFF_I_FRAME                        = 0xd,\n    IV_MBAFF_P_FRAME                        = 0xe,\n    IV_MBAFF_B_FRAME                        = 0xf,\n    IV_MBAFF_IDR_FRAME                      = 0x10,\n    IV_NOT_CODED_FRAME                      = 0x11,\n    IV_FRAMETYPE_DEFAULT                    = IV_I_FRAME\n}IV_PICTURE_CODING_TYPE_T;\n\n/* IV_FLD_TYPE_T: field type Enumeration                                    */\n\ntypedef enum {\n    IV_NA_FLD                               = 0x7FFFFFFF,\n    IV_TOP_FLD                              = 0x0,\n    IV_BOT_FLD                              = 0x1,\n    IV_FLD_TYPE_DEFAULT                     = IV_TOP_FLD\n}IV_FLD_TYPE_T;\n\n/* IV_CONTENT_TYPE_T: Video content type                                     */\n\ntypedef enum {\n    IV_CONTENTTYPE_NA                       = 0x7FFFFFFF,\n    IV_PROGRESSIVE                          = 0x0,\n    IV_INTERLACED                           = 0x1,\n    IV_PROGRESSIVE_FRAME                    = 0x2,\n    IV_INTERLACED_FRAME                     = 0x3,\n    IV_INTERLACED_TOPFIELD                  = 0x4,\n    IV_INTERLACED_BOTTOMFIELD               = 0x5,\n    IV_CONTENTTYPE_DEFAULT                  = IV_PROGRESSIVE,\n}IV_CONTENT_TYPE_T;\n\n/* IV_API_COMMAND_TYPE_T:API command type                                   */\ntypedef enum {\n    IV_CMD_NA                           = 0x7FFFFFFF,\n    IV_CMD_DUMMY_ELEMENT                = 0x4,\n}IV_API_COMMAND_TYPE_T;\n\n/*****************************************************************************/\n/* Structure                                                                 */\n/*****************************************************************************/\n\n/* IV_OBJ_T: This structure defines the handle for the codec instance        */\n\ntypedef struct {\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * Pointer to the API function pointer table of the codec\n     */\n    void                                        *pv_fxns;\n\n    /**\n     * Pointer to the handle of the codec\n     */\n    void                                        *pv_codec_handle;\n}iv_obj_t;\n\n\n/* IV_YUV_BUF_T: This structure defines attributes for the yuv buffer        */\n\ntypedef struct {\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * Pointer to Luma (Y) Buffer\n     */\n\n    void                                        *pv_y_buf;\n    /**\n     * Pointer to Chroma (Cb) Buffer\n     */\n    void                                        *pv_u_buf;\n\n    /**\n     * Pointer to Chroma (Cr) Buffer\n     */\n    void                                        *pv_v_buf;\n\n    /**\n     * Width of the Luma (Y) Buffer\n     */\n    UWORD32                                     u4_y_wd;\n\n    /**\n     * Height of the Luma (Y) Buffer\n     */\n    UWORD32                                     u4_y_ht;\n\n    /**\n     * Stride/Pitch of the Luma (Y) Buffer\n     */\n    UWORD32                                     u4_y_strd;\n\n    /**\n     * Width of the Chroma (Cb) Buffer\n     */\n    UWORD32                                     u4_u_wd;\n\n    /**\n     * Height of the Chroma (Cb) Buffer\n     */\n    UWORD32                                     u4_u_ht;\n\n    /**\n     * Stride/Pitch of the Chroma (Cb) Buffer\n     */\n    UWORD32                                     u4_u_strd;\n\n    /**\n     * Width of the Chroma (Cr) Buffer\n     */\n    UWORD32                                     u4_v_wd;\n\n    /**\n     * Height of the Chroma (Cr) Buffer\n     */\n    UWORD32                                     u4_v_ht;\n\n    /**\n     * Stride/Pitch of the Chroma (Cr) Buffer\n     */\n    UWORD32                                     u4_v_strd;\n}iv_yuv_buf_t;\n\n\n\n#endif /* _IV_H */\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/ivd.h",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ivd.h\n*\n* @brief\n*  This file contains all the necessary structure and  enumeration\n* definitions needed for the Application  Program Interface(API) of the\n* Ittiam Video Decoders\n*\n* @author\n*  100239(RCY)\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n#ifndef _IVD_H\n#define _IVD_H\n\n/*****************************************************************************/\n/* Constant Macros                                                           */\n/*****************************************************************************/\n#define IVD_VIDDEC_MAX_IO_BUFFERS 64\n\n/** SEI macros */\n/*\n * @brief  specifies the number of colour primary components of the mastering display\n */\n#define NUM_SEI_MDCV_PRIMARIES        3\n\n/*\n * @brief  specifies the number of colour primary components of the nominal content colour volume\n */\n#define NUM_SEI_CCV_PRIMARIES         3\n\n/*****************************************************************************/\n/* Typedefs                                                                  */\n/*****************************************************************************/\n\n/*****************************************************************************/\n/* Enums                                                                     */\n/*****************************************************************************/\n\n/* IVD_ARCH_T: Architecture Enumeration                               */\ntypedef enum\n{\n    ARCH_NA                 =   0x7FFFFFFF,\n    ARCH_ARM_NONEON         =   0x0,\n    ARCH_ARM_A9Q,\n    ARCH_ARM_A9A,\n    ARCH_ARM_A9,\n    ARCH_ARM_A7,\n    ARCH_ARM_A5,\n    ARCH_ARM_A15,\n    ARCH_ARM_NEONINTR,\n    ARCH_ARMV8_GENERIC,\n    ARCH_X86_GENERIC        =   0x100,\n    ARCH_X86_SSSE3,\n    ARCH_X86_SSE42,\n    ARCH_X86_AVX2,\n    ARCH_MIPS_GENERIC       =   0x200,\n    ARCH_MIPS_32\n}IVD_ARCH_T;\n\n/* IVD_SOC_T: SOC Enumeration                               */\ntypedef enum\n{\n    SOC_NA                  = 0x7FFFFFFF,\n    SOC_GENERIC             = 0x0,\n    SOC_HISI_37X            = 0x100,\n}IVD_SOC_T;\n\n/* IVD_FRAME_SKIP_MODE_T:Skip mode Enumeration                               */\n\ntypedef enum {\n    IVD_SKIP_NONE                               = 0x7FFFFFFF,\n    IVD_SKIP_P                                  = 0x1,\n    IVD_SKIP_B                                  = 0x2,\n    IVD_SKIP_I                                  = 0x3,\n    IVD_SKIP_IP                                 = 0x4,\n    IVD_SKIP_IB                                 = 0x5,\n    IVD_SKIP_PB                                 = 0x6,\n    IVD_SKIP_IPB                                = 0x7,\n    IVD_SKIP_IDR                                = 0x8,\n    IVD_SKIP_DEFAULT                            = IVD_SKIP_NONE,\n}IVD_FRAME_SKIP_MODE_T;\n\n/* IVD_VIDEO_DECODE_MODE_T: Set decoder to decode either frame worth of data */\n/* or only header worth of data                                              */\n\ntypedef enum {\n    IVD_DECODE_MODE_NA                          = 0x7FFFFFFF,\n\n    /* This enables the codec to process all decodable units */\n    IVD_DECODE_FRAME                            = 0x0,\n\n    /* This enables the codec to decode header only */\n    IVD_DECODE_HEADER                           = 0x1,\n\n\n\n}IVD_VIDEO_DECODE_MODE_T;\n\n\n/* IVD_DISPLAY_FRAME_OUT_MODE_T: Video Display Frame Output Mode             */\n\ntypedef enum {\n\n    IVD_DISPLAY_ORDER_NA                        = 0x7FFFFFFF,\n    /* To set codec to fill output buffers in display order */\n    IVD_DISPLAY_FRAME_OUT                       = 0x0,\n\n    /* To set codec to fill output buffers in decode order */\n    IVD_DECODE_FRAME_OUT                        = 0x1,\n}IVD_DISPLAY_FRAME_OUT_MODE_T;\n\n\n/* IVD_API_COMMAND_TYPE_T:API command type                                   */\ntypedef enum {\n    IVD_CMD_VIDEO_NA                          = 0x7FFFFFFF,\n    IVD_CMD_CREATE                            = IV_CMD_DUMMY_ELEMENT + 1,\n    IVD_CMD_DELETE,\n    IVD_CMD_VIDEO_CTL,\n    IVD_CMD_VIDEO_DECODE,\n    IVD_CMD_GET_DISPLAY_FRAME,\n    IVD_CMD_REL_DISPLAY_FRAME,\n    IVD_CMD_SET_DISPLAY_FRAME\n}IVD_API_COMMAND_TYPE_T;\n\n/* IVD_CONTROL_API_COMMAND_TYPE_T: Video Control API command type            */\n\ntypedef enum {\n    IVD_CMD_NA                          = 0x7FFFFFFF,\n    IVD_CMD_CTL_GETPARAMS               = 0x0,\n    IVD_CMD_CTL_SETPARAMS               = 0x1,\n    IVD_CMD_CTL_RESET                   = 0x2,\n    IVD_CMD_CTL_SETDEFAULT              = 0x3,\n    IVD_CMD_CTL_FLUSH                   = 0x4,\n    IVD_CMD_CTL_GETBUFINFO              = 0x5,\n    IVD_CMD_CTL_GETVERSION              = 0x6,\n    IVD_CMD_CTL_CODEC_SUBCMD_START         = 0x7\n}IVD_CONTROL_API_COMMAND_TYPE_T;\n\n\n/* IVD_ERROR_BITS_T: A UWORD32 container will be used for reporting the error*/\n/* code to the application. The first 8 bits starting from LSB have been     */\n/* reserved for the codec to report internal error details. The rest of the  */\n/* bits will be generic for all video decoders and each bit has an associated*/\n/* meaning as mentioned below. The unused bit fields are reserved for future */\n/* extenstions and will be zero in the current implementation                */\n\ntypedef enum {\n    /* Bit 8  - Applied concealment.                                         */\n    IVD_APPLIEDCONCEALMENT                      = 0x8,\n    /* Bit 9 - Insufficient input data.                                     */\n    IVD_INSUFFICIENTDATA                        = 0x9,\n    /* Bit 10 - Data problem/corruption.                                     */\n    IVD_CORRUPTEDDATA                           = 0xa,\n    /* Bit 11 - Header problem/corruption.                                   */\n    IVD_CORRUPTEDHEADER                         = 0xb,\n    /* Bit 12 - Unsupported feature/parameter in input.                      */\n    IVD_UNSUPPORTEDINPUT                        = 0xc,\n    /* Bit 13 - Unsupported input parameter orconfiguration.                 */\n    IVD_UNSUPPORTEDPARAM                        = 0xd,\n    /* Bit 14 - Fatal error (stop the codec).If there is an                  */\n    /* error and this bit is not set, the error is a recoverable one.        */\n    IVD_FATALERROR                              = 0xe,\n    /* Bit 15 - Invalid bitstream. Applies when Bitstream/YUV frame          */\n    /* buffer for encode/decode call is made with non-valid or zero u4_size  */\n    /* data                                                                  */\n    IVD_INVALID_BITSTREAM                       = 0xf,\n    /* Bit 16          */\n    IVD_INCOMPLETE_BITSTREAM                    = 0x10,\n    IVD_ERROR_BITS_T_DUMMY_ELEMENT              = 0x7FFFFFFF\n}IVD_ERROR_BITS_T;\n\n\n/* IVD_CONTROL_API_COMMAND_TYPE_T: Video Control API command type            */\ntypedef enum {\n    IVD_ERROR_NONE                              = 0x0,\n    IVD_NUM_MEM_REC_FAILED                      = 0x1,\n    IVD_NUM_REC_NOT_SUFFICIENT                  = 0x2,\n    IVD_FILL_MEM_REC_FAILED                     = 0x3,\n    IVD_REQUESTED_WIDTH_NOT_SUPPPORTED          = 0x4,\n    IVD_REQUESTED_HEIGHT_NOT_SUPPPORTED         = 0x5,\n    IVD_INIT_DEC_FAILED                         = 0x6,\n    IVD_INIT_DEC_NOT_SUFFICIENT                 = 0x7,\n    IVD_INIT_DEC_WIDTH_NOT_SUPPPORTED           = 0x8,\n    IVD_INIT_DEC_HEIGHT_NOT_SUPPPORTED          = 0x9,\n    IVD_INIT_DEC_MEM_NOT_ALIGNED                = 0xa,\n    IVD_INIT_DEC_COL_FMT_NOT_SUPPORTED          = 0xb,\n    IVD_INIT_DEC_MEM_REC_NOT_SUFFICIENT         = 0xc,\n    IVD_GET_VERSION_DATABUFFER_SZ_INSUFFICIENT  = 0xd,\n    IVD_BUFFER_SIZE_SET_TO_ZERO                 = 0xe,\n    IVD_UNEXPECTED_END_OF_STREAM                = 0xf,\n    IVD_SEQUENCE_HEADER_NOT_DECODED             = 0x10,\n    IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED       = 0x11,\n    IVD_MAX_FRAME_LIMIT_REACHED                 = 0x12,\n    IVD_IP_API_STRUCT_SIZE_INCORRECT            = 0x13,\n    IVD_OP_API_STRUCT_SIZE_INCORRECT            = 0x14,\n    IVD_HANDLE_NULL                             = 0x15,\n    IVD_HANDLE_STRUCT_SIZE_INCORRECT            = 0x16,\n    IVD_INVALID_HANDLE_NULL                     = 0x17,\n    IVD_INVALID_API_CMD                         = 0x18,\n    IVD_UNSUPPORTED_API_CMD                     = 0x19,\n    IVD_MEM_REC_STRUCT_SIZE_INCORRECT           = 0x1a,\n    IVD_DISP_FRM_ZERO_OP_BUFS                   = 0x1b,\n    IVD_DISP_FRM_OP_BUF_NULL                    = 0x1c,\n    IVD_DISP_FRM_ZERO_OP_BUF_SIZE               = 0x1d,\n    IVD_DEC_FRM_BS_BUF_NULL                     = 0x1e,\n    IVD_SET_CONFG_INVALID_DEC_MODE              = 0x1f,\n    IVD_SET_CONFG_UNSUPPORTED_DISP_WIDTH        = 0x20,\n    IVD_RESET_FAILED                            = 0x21,\n    IVD_INIT_DEC_MEM_REC_OVERLAP_ERR            = 0x22,\n    IVD_INIT_DEC_MEM_REC_BASE_NULL              = 0x23,\n    IVD_INIT_DEC_MEM_REC_ALIGNMENT_ERR          = 0x24,\n    IVD_INIT_DEC_MEM_REC_INSUFFICIENT_SIZE      = 0x25,\n    IVD_INIT_DEC_MEM_REC_INCORRECT_TYPE         = 0x26,\n    IVD_DEC_NUMBYTES_INV                        = 0x27,\n    IVD_DEC_REF_BUF_NULL                        = 0x28,\n    IVD_DEC_FRM_SKIPPED                         = 0x29,\n    IVD_RES_CHANGED                             = 0x2a,\n    IVD_MEM_ALLOC_FAILED                        = 0x2b,\n    IVD_DUMMY_ELEMENT_FOR_CODEC_EXTENSIONS      = 0xD0,\n}IVD_ERROR_CODES_T;\n\n\n/*****************************************************************************/\n/* Structure                                                                 */\n/*****************************************************************************/\n/* structure for passing output buffers to codec during get display buffer   */\n/* call                                                                      */\ntypedef struct {\n\n    /**\n     * number of output buffers\n     */\n    UWORD32             u4_num_bufs;\n\n    /**\n     *list of pointers to output buffers\n     */\n    UWORD8              *pu1_bufs[IVD_VIDDEC_MAX_IO_BUFFERS];\n\n    /**\n     * sizes of each output buffer\n     */\n    UWORD32             u4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];\n\n}ivd_out_bufdesc_t;\n\n/*****************************************************************************/\n/*   Create decoder                                                          */\n/*****************************************************************************/\n\n/* IVD_API_COMMAND_TYPE_T::e_cmd = IVD_CMD_CREATE                            */\n\n\ntypedef struct {\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     *  e_cmd\n     */\n    IVD_API_COMMAND_TYPE_T                  e_cmd;\n\n    /**\n     * format in which codec has to give out frame data for display\n     */\n    IV_COLOR_FORMAT_T                       e_output_format;\n\n    /**\n     * Flag to indicate shared display buffer mode\n     */\n    UWORD32                                 u4_share_disp_buf;\n\n    /**\n     * Pointer to a function for aligned allocation.\n     */\n    void    *(*pf_aligned_alloc)(void *pv_mem_ctxt, WORD32 alignment, WORD32 size);\n\n    /**\n     * Pointer to a function for aligned free.\n     */\n    void   (*pf_aligned_free)(void *pv_mem_ctxt, void *pv_buf);\n\n    /**\n     * Pointer to memory context that is needed during alloc/free for custom\n     * memory managers. This will be passed as first argument to pf_aligned_alloc and\n     * pf_aligned_free.\n     * If application is using standard memory functions like\n     * malloc/aligned_malloc/memalign/free/aligned_free,\n     * then this is not needed and can be set to NULL\n     */\n    void    *pv_mem_ctxt;\n\n}ivd_create_ip_t;\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * u4_error_code\n     */\n    UWORD32                                 u4_error_code;\n\n    /**\n     * Codec Handle\n     */\n    void                                    *pv_handle;\n\n}ivd_create_op_t;\n\n\n/*****************************************************************************/\n/*  Delete decoder                                                           */\n/*****************************************************************************/\n\n/* IVD_API_COMMAND_TYPE_T::e_cmd = IVD_CMD_DELETE                              */\n\n\n\ntypedef struct {\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                       e_cmd;\n\n}ivd_delete_ip_t;\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * error_code\n     */\n    UWORD32                                     u4_error_code;\n\n}ivd_delete_op_t;\n\n/*****************************************************************************/\n/*   Video Decode                                                            */\n/*****************************************************************************/\n\n/* SEI params deocde */\ntypedef struct {\n    UWORD8                                         u1_sei_mdcv_params_present_flag;\n\n    UWORD8                                         u1_sei_cll_params_present_flag;\n\n    UWORD8                                         u1_sei_ave_params_present_flag;\n\n    UWORD8                                         u1_sei_ccv_params_present_flag;\n\n}ivd_sei_decode_op_t;\n\n/* IVD_API_COMMAND_TYPE_T::e_cmd = IVD_CMD_VIDEO_DECODE                      */\n\n\ntypedef struct {\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * e_cmd\n     */\n    IVD_API_COMMAND_TYPE_T                  e_cmd;\n\n    /**\n     * u4_ts\n     */\n    UWORD32                                 u4_ts;\n\n    /**\n     * u4_num_Bytes\n     */\n    UWORD32                                 u4_num_Bytes;\n\n    /**\n     * pv_stream_buffer\n     */\n    void                                    *pv_stream_buffer;\n\n    /**\n     * output buffer desc\n     */\n    ivd_out_bufdesc_t                       s_out_buffer;\n\n}ivd_video_decode_ip_t;\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * u4_error_code\n     */\n    UWORD32                                 u4_error_code;\n\n    /**\n     * num_bytes_consumed\n     */\n    UWORD32                                 u4_num_bytes_consumed;\n\n    /**\n     * pic_wd\n     */\n    UWORD32                                 u4_pic_wd;\n\n    /**\n     * pic_ht\n     */\n    UWORD32                                 u4_pic_ht;\n\n    /**\n     * pic_type\n     */\n    IV_PICTURE_CODING_TYPE_T                e_pic_type;\n\n    /**\n     * frame_decoded_flag\n     */\n    UWORD32                                 u4_frame_decoded_flag;\n\n    /**\n     * new_seq\n     */\n    UWORD32                                 u4_new_seq;\n\n    /**\n     * output_present\n     */\n    UWORD32                                 u4_output_present;\n\n    /**\n     * progressive_frame_flag\n     */\n    UWORD32                                 u4_progressive_frame_flag;\n\n    /**\n     * is_ref_flag\n     */\n    UWORD32                                 u4_is_ref_flag;\n\n    /**\n     * output_format\n     */\n    IV_COLOR_FORMAT_T                       e_output_format;\n\n    /**\n     * disp_frm_buf\n     */\n    iv_yuv_buf_t                            s_disp_frm_buf;\n\n    /**\n     * sei params o/p struct\n     */\n    ivd_sei_decode_op_t                     s_sei_decode_op;\n\n    /**\n     * fld_type\n     */\n    IV_FLD_TYPE_T                           e4_fld_type;\n\n    /**\n     * ts\n     */\n    UWORD32                                 u4_ts;\n\n    /**\n     * disp_buf_id\n     */\n    UWORD32                                 u4_disp_buf_id;\n\n    /**\n     * reorder_depth\n     */\n    WORD32                                  i4_reorder_depth;\n\n    /**\n     * disp_buf_id\n     */\n    WORD32                                  i4_display_index;\n\n    /* crop info from SPS */\n\tUWORD8                                   u1_frame_cropping_flag;\n\tUWORD8                                   u1_frame_cropping_rect_left_ofst;\n\tUWORD8                                   u1_frame_cropping_rect_right_ofst;\n\tUWORD8                                   u1_frame_cropping_rect_top_ofst;\n\tUWORD8                                   u1_frame_cropping_rect_bottom_ofst;\n\n    /* uncropped image size */\n\tUWORD32                                  u4_raw_wd;\n\tUWORD32                                  u4_raw_ht;\n\n}ivd_video_decode_op_t;\n\n\n/*****************************************************************************/\n/*   Get Display Frame                                                       */\n/*****************************************************************************/\n\n\n/* IVD_API_COMMAND_TYPE_T::e_cmd = IVD_CMD_GET_DISPLAY_FRAME                 */\n\ntypedef struct\n{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * e_cmd\n     */\n    IVD_API_COMMAND_TYPE_T                  e_cmd;\n\n    /**\n     * output buffer desc\n     */\n    ivd_out_bufdesc_t                       s_out_buffer;\n\n}ivd_get_display_frame_ip_t;\n\n\ntypedef struct\n{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * error_code\n     */\n    UWORD32                                 u4_error_code;\n\n    /**\n     * progressive_frame_flag\n     */\n    UWORD32                                 u4_progressive_frame_flag;\n\n    /**\n     * pic_type\n     */\n    IV_PICTURE_CODING_TYPE_T                e_pic_type;\n\n    /**\n     * is_ref_flag\n     */\n    UWORD32                                 u4_is_ref_flag;\n\n    /**\n     * output_format\n     */\n    IV_COLOR_FORMAT_T                       e_output_format;\n\n    /**\n     * disp_frm_buf\n     */\n    iv_yuv_buf_t                            s_disp_frm_buf;\n\n    /**\n     * fld_type\n     */\n    IV_FLD_TYPE_T                           e4_fld_type;\n\n    /**\n     * ts\n     */\n    UWORD32                                 u4_ts;\n\n    /**\n     * disp_buf_id\n     */\n    UWORD32                                 u4_disp_buf_id;\n}ivd_get_display_frame_op_t;\n\n/*****************************************************************************/\n/*   Set Display Frame                                                       */\n/*****************************************************************************/\n\n\n/* IVD_API_COMMAND_TYPE_T::e_cmd = IVD_CMD_SET_DISPLAY_FRAME                 */\n\ntypedef struct\n{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                  e_cmd;\n\n    /**\n     * num_disp_bufs\n     */\n    UWORD32                                 num_disp_bufs;\n\n    /**\n     * output buffer desc\n     */\n    ivd_out_bufdesc_t                       s_disp_buffer[IVD_VIDDEC_MAX_IO_BUFFERS];\n\n}ivd_set_display_frame_ip_t;\n\n\ntypedef struct\n{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * error code\n     */\n    UWORD32                                 u4_error_code;\n}ivd_set_display_frame_op_t;\n\n\n/*****************************************************************************/\n/*   Release Display Frame                                                       */\n/*****************************************************************************/\n\n\n/* IVD_API_COMMAND_TYPE_T::e_cmd = IVD_CMD_SET_DISPLAY_FRAME                 */\n\ntypedef struct\n{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * e_cmd\n     */\n    IVD_API_COMMAND_TYPE_T                  e_cmd;\n\n    /**\n     * disp_buf_id\n     */\n    UWORD32                                 u4_disp_buf_id;\n}ivd_rel_display_frame_ip_t;\n\n\ntypedef struct\n{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * error code\n     */\n    UWORD32                                 u4_error_code;\n}ivd_rel_display_frame_op_t;\n\n/*****************************************************************************/\n/*   Video control  Flush                                                    */\n/*****************************************************************************/\n/* IVD_API_COMMAND_TYPE_T::e_cmd            = IVD_CMD_VIDEO_CTL              */\n/* IVD_CONTROL_API_COMMAND_TYPE_T::e_sub_cmd    = IVD_CMD_ctl_FLUSH          */\n\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                  e_cmd;\n\n    /**\n     * sub_cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T          e_sub_cmd;\n}ivd_ctl_flush_ip_t;\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * error code\n     */\n    UWORD32                                 u4_error_code;\n}ivd_ctl_flush_op_t;\n\n/*****************************************************************************/\n/*   Video control reset                                                     */\n/*****************************************************************************/\n/* IVD_API_COMMAND_TYPE_T::e_cmd            = IVD_CMD_VIDEO_CTL              */\n/* IVD_CONTROL_API_COMMAND_TYPE_T::e_sub_cmd    = IVD_CMD_ctl_RESET          */\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                  e_cmd;\n\n    /**\n     * sub_cmd\n     */\n\n    IVD_CONTROL_API_COMMAND_TYPE_T          e_sub_cmd;\n}ivd_ctl_reset_ip_t;\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                 u4_size;\n\n    /**\n     * error code\n     */\n    UWORD32                                 u4_error_code;\n}ivd_ctl_reset_op_t;\n\n\n/*****************************************************************************/\n/*   Video control  Set Params                                               */\n/*****************************************************************************/\n/* IVD_API_COMMAND_TYPE_T::e_cmd        = IVD_CMD_VIDEO_CTL                  */\n/* IVD_CONTROL_API_COMMAND_TYPE_T::e_sub_cmd=IVD_CMD_ctl_SETPARAMS           */\n/* IVD_CONTROL_API_COMMAND_TYPE_T::e_sub_cmd=IVD_CMD_ctl_SETDEFAULT          */\n\n\n\ntypedef struct {\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n\n    /**\n     * sub_cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n\n    /**\n     * vid_dec_mode\n     */\n    IVD_VIDEO_DECODE_MODE_T                     e_vid_dec_mode;\n\n    /**\n     * disp_wd\n     */\n    UWORD32                                     u4_disp_wd;\n\n    /**\n     * frm_skip_mode\n     */\n    IVD_FRAME_SKIP_MODE_T                       e_frm_skip_mode;\n\n    /**\n     * frm_out_mode\n     */\n    IVD_DISPLAY_FRAME_OUT_MODE_T                e_frm_out_mode;\n}ivd_ctl_set_config_ip_t;\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * u4_error_code\n     */\n    UWORD32                                     u4_error_code;\n}ivd_ctl_set_config_op_t;\n\n/*****************************************************************************/\n/*   Video control:Get Buf Info                                              */\n/*****************************************************************************/\n\n/* IVD_API_COMMAND_TYPE_T::e_cmd         = IVD_CMD_VIDEO_CTL                 */\n/* IVD_CONTROL_API_COMMAND_TYPE_T::e_sub_cmd=IVD_CMD_ctl_GETBUFINFO          */\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     *  e_cmd\n     */\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n\n    /**\n     * sub_cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n}ivd_ctl_getbufinfo_ip_t;\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * error code\n     */\n    UWORD32                                     u4_error_code;\n\n    /**\n     * no of display buffer sets required by codec\n     */\n    UWORD32                                     u4_num_disp_bufs;\n\n    /**\n     * no of input buffers required for codec\n     */\n    UWORD32                                     u4_min_num_in_bufs;\n\n    /**\n     * no of output buffers required for codec\n     */\n    UWORD32                                     u4_min_num_out_bufs;\n\n    /**\n     * sizes of each input buffer required\n     */\n    UWORD32                                     u4_min_in_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];\n\n    /**\n     * sizes of each output buffer required\n     */\n    UWORD32                                     u4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];\n}ivd_ctl_getbufinfo_op_t;\n\n\n/*****************************************************************************/\n/*   Video control:Getstatus Call                                            */\n/*****************************************************************************/\n\n\n/* IVD_API_COMMAND_TYPE_T::e_cmd        = IVD_CMD_VIDEO_CTL                  */\n/* IVD_CONTROL_API_COMMAND_TYPE_T::e_sub_cmd=IVD_CMD_ctl_GETPARAMS           */\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n\n    /**\n     * sub_cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n}ivd_ctl_getstatus_ip_t;\n\n\ntypedef struct{\n\n     /**\n      * u4_size of the structure\n      */\n    UWORD32                  u4_size;\n\n    /**\n      * error code\n      */\n    UWORD32                  u4_error_code;\n\n    /**\n     * no of display buffer sets required by codec\n     */\n    UWORD32                  u4_num_disp_bufs;\n\n    /**\n     * u4_pic_ht\n     */\n    UWORD32                  u4_pic_ht;\n\n    /**\n     * u4_pic_wd\n     */\n    UWORD32                  u4_pic_wd;\n\n    /**\n     * frame_rate\n     */\n    UWORD32                  u4_frame_rate;\n\n    /**\n     * u4_bit_rate\n     */\n    UWORD32                  u4_bit_rate;\n\n    /**\n     * content_type\n     */\n    IV_CONTENT_TYPE_T        e_content_type;\n\n    /**\n     * output_chroma_format\n     */\n    IV_COLOR_FORMAT_T        e_output_chroma_format;\n\n    /**\n     * no of input buffers required for codec\n     */\n    UWORD32                  u4_min_num_in_bufs;\n\n    /**\n     * no of output buffers required for codec\n     */\n    UWORD32                  u4_min_num_out_bufs;\n\n    /**\n     * sizes of each input buffer required\n     */\n    UWORD32                  u4_min_in_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];\n\n    /**\n     * sizes of each output buffer required\n     */\n    UWORD32                  u4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];\n}ivd_ctl_getstatus_op_t;\n\n\n/*****************************************************************************/\n/*   Video control:Get Version Info                                          */\n/*****************************************************************************/\n\n/* IVD_API_COMMAND_TYPE_T::e_cmd        = IVD_CMD_VIDEO_CTL                  */\n/* IVD_CONTROL_API_COMMAND_TYPE_T::e_sub_cmd=IVD_CMD_ctl_GETVERSION          */\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * cmd\n     */\n    IVD_API_COMMAND_TYPE_T                      e_cmd;\n\n    /**\n     * sub_cmd\n     */\n    IVD_CONTROL_API_COMMAND_TYPE_T              e_sub_cmd;\n\n    /**\n     * pv_version_buffer\n     */\n    void                                        *pv_version_buffer;\n\n    /**\n     * version_buffer_size\n     */\n    UWORD32                                     u4_version_buffer_size;\n}ivd_ctl_getversioninfo_ip_t;\n\n\ntypedef struct{\n    /**\n     * u4_size of the structure\n     */\n    UWORD32                                     u4_size;\n\n    /**\n     * error code\n     */\n    UWORD32                                     u4_error_code;\n}ivd_ctl_getversioninfo_op_t;\n\n#endif /* __IVD_H__ */\n\n"
  },
  {
    "path": "dependencies/ih264d/decoder/mips/ih264d_function_selector.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  imp2d_function_selector.c\n*\n* @brief\n*  Contains functions to initialize function pointers used in hevc\n*\n* @author\n*  Naveen\n*\n* @par List of Functions:\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* User Include files */\n#include \"ih264_typedefs.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_error.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include \"ih264_inter_pred_filters.h\"\n\n#include \"ih264d_structs.h\"\n#include \"ih264d_function_selector.h\"\n\nvoid ih264d_init_function_ptr(dec_struct_t *ps_codec)\n{\n    ih264d_init_function_ptr_generic(ps_codec);\n}\nvoid ih264d_init_arch(dec_struct_t *ps_codec)\n{\n    ps_codec->e_processor_arch = ARCH_NA;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/x86/ih264d_function_selector.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n * Modified for use with Cemu emulator project\n*/\n/**\n*******************************************************************************\n* @file\n*  imp2d_function_selector.c\n*\n* @brief\n*  Contains functions to initialize function pointers used in hevc\n*\n* @author\n*  Naveen\n*\n* @par List of Functions:\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* User Include files */\n#include \"ih264_typedefs.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_error.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include \"ih264_inter_pred_filters.h\"\n\n#include \"ih264d_structs.h\"\n#include \"ih264d_function_selector.h\"\n\nvoid ih264d_init_function_ptr(dec_struct_t *ps_codec)\n{\n\n    ih264d_init_function_ptr_generic(ps_codec);\n    switch(ps_codec->e_processor_arch)\n    {\n        case ARCH_X86_GENERIC:\n            ih264d_init_function_ptr_generic(ps_codec);\n        break;\n        case ARCH_X86_SSSE3:\n            ih264d_init_function_ptr_ssse3(ps_codec);\n            break;\n        case ARCH_X86_SSE42:\n        default:\n            ih264d_init_function_ptr_ssse3(ps_codec);\n            ih264d_init_function_ptr_sse42(ps_codec);\n        break;\n    }\n}\n\n#ifdef __GNUC__\n#include <cpuid.h>\n\nvoid __cpuid2(signed int* cpuInfo, unsigned int level)\n{\n    __get_cpuid (level, (unsigned int*)cpuInfo+0, (unsigned int*)cpuInfo+1, (unsigned int*)cpuInfo+2, (unsigned int*)cpuInfo+3);\n}\n\n#define __getCPUId __cpuid2\n\n#else\n#define __getCPUId __cpuid\n#endif\n\nvoid ih264d_init_arch(dec_struct_t *ps_codec)\n{\n\tint cpuInfo[4];\n    UWORD8 hasSSSE3;\n    UWORD8 hasSSE4_2;\n\t__getCPUId(cpuInfo, 0x1);\n\thasSSSE3 = ((cpuInfo[2] >> 9) & 1);\n\thasSSE4_2 = ((cpuInfo[2] >> 20) & 1);\n    if (hasSSE4_2 != 0)\n        ps_codec->e_processor_arch = ARCH_X86_SSE42;\n    else if (hasSSSE3 != 0)\n\t\tps_codec->e_processor_arch = ARCH_X86_SSSE3;\n\telse\n        ps_codec->e_processor_arch = ARCH_X86_GENERIC;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/x86/ih264d_function_selector_sse42.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264e_function_selector_generic.c\n*\n* @brief\n*  Contains functions to initialize function pointers of codec context\n*\n* @author\n*  Ittiam\n*\n* @par List of Functions:\n*  - ih264e_init_function_ptr_generic\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System Include files */\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* User Include files */\n#include \"ih264_typedefs.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_error.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include \"ih264_inter_pred_filters.h\"\n\n#include \"ih264d_structs.h\"\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSE42 __attribute__((target(\"sse4.2\")))\n#else\n#define ATTRIBUTE_SSE42\n#endif\n\n\n/**\n*******************************************************************************\n*\n* @brief Initialize the intra/inter/transform/deblk function pointers of\n* codec context\n*\n* @par Description: the current routine initializes the function pointers of\n* codec context basing on the architecture in use\n*\n* @param[in] ps_codec\n*  Codec context pointer\n*\n* @returns  none\n*\n* @remarks none\n*\n*******************************************************************************\n*/\nATTRIBUTE_SSE42\nvoid ih264d_init_function_ptr_sse42(dec_struct_t *ps_codec)\n{\n    ps_codec->pf_default_weighted_pred_luma = ih264_default_weighted_pred_luma_sse42;\n    ps_codec->pf_default_weighted_pred_chroma = ih264_default_weighted_pred_chroma_sse42;\n    ps_codec->pf_weighted_pred_luma = ih264_weighted_pred_luma_sse42;\n    ps_codec->pf_weighted_pred_chroma = ih264_weighted_pred_chroma_sse42;\n    ps_codec->pf_weighted_bi_pred_luma = ih264_weighted_bi_pred_luma_sse42;\n    ps_codec->pf_weighted_bi_pred_chroma = ih264_weighted_bi_pred_chroma_sse42;\n\n    ps_codec->pf_iquant_itrans_recon_luma_4x4 = ih264_iquant_itrans_recon_4x4_sse42;\n    ps_codec->pf_iquant_itrans_recon_chroma_4x4 = ih264_iquant_itrans_recon_chroma_4x4_sse42;\n    ps_codec->pf_ihadamard_scaling_4x4 = ih264_ihadamard_scaling_4x4_sse42;\n    return;\n}\n"
  },
  {
    "path": "dependencies/ih264d/decoder/x86/ih264d_function_selector_ssse3.c",
    "content": "/******************************************************************************\n *\n * Copyright (C) 2015 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at:\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n *****************************************************************************\n * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\n*/\n/**\n*******************************************************************************\n* @file\n*  ih264e_function_selector_generic.c\n*\n* @brief\n*  Contains functions to initialize function pointers of codec context\n*\n* @author\n*  Ittiam\n*\n* @par List of Functions:\n*  - ih264e_init_function_ptr_generic\n*\n* @remarks\n*  None\n*\n*******************************************************************************\n*/\n\n\n/*****************************************************************************/\n/* File Includes                                                             */\n/*****************************************************************************/\n\n/* System Include files */\n#include <stdio.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <string.h>\n\n/* User Include files */\n#include \"ih264_typedefs.h\"\n#include \"iv.h\"\n#include \"ivd.h\"\n#include \"ih264_defs.h\"\n#include \"ih264_size_defs.h\"\n#include \"ih264_error.h\"\n#include \"ih264_trans_quant_itrans_iquant.h\"\n#include \"ih264_inter_pred_filters.h\"\n\n#include \"ih264d_structs.h\"\n\n#ifdef __GNUC__\n#define ATTRIBUTE_SSSE3 __attribute__((target(\"ssse3\")))\n#else\n#define ATTRIBUTE_SSSE3\n#endif\n\n\n/**\n*******************************************************************************\n*\n* @brief Initialize the intra/inter/transform/deblk function pointers of\n* codec context\n*\n* @par Description: the current routine initializes the function pointers of\n* codec context basing on the architecture in use\n*\n* @param[in] ps_codec\n*  Codec context pointer\n*\n* @returns  none\n*\n* @remarks none\n*\n*******************************************************************************\n*/\nATTRIBUTE_SSSE3\nvoid ih264d_init_function_ptr_ssse3(dec_struct_t *ps_codec)\n{\n\n\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 16x16 */\n    ps_codec->apf_intra_pred_luma_16x16[0] = ih264_intra_pred_luma_16x16_mode_vert_ssse3;\n    ps_codec->apf_intra_pred_luma_16x16[1] = ih264_intra_pred_luma_16x16_mode_horz_ssse3;\n    ps_codec->apf_intra_pred_luma_16x16[2] = ih264_intra_pred_luma_16x16_mode_dc_ssse3;\n    ps_codec->apf_intra_pred_luma_16x16[3] = ih264_intra_pred_luma_16x16_mode_plane_ssse3;\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 4x4 */\n    ps_codec->apf_intra_pred_luma_4x4[0] = ih264_intra_pred_luma_4x4_mode_vert_ssse3;\n    ps_codec->apf_intra_pred_luma_4x4[1] = ih264_intra_pred_luma_4x4_mode_horz_ssse3;\n    ps_codec->apf_intra_pred_luma_4x4[2] = ih264_intra_pred_luma_4x4_mode_dc_ssse3;\n    ps_codec->apf_intra_pred_luma_4x4[3] = ih264_intra_pred_luma_4x4_mode_diag_dl_ssse3;\n    ps_codec->apf_intra_pred_luma_4x4[4] = ih264_intra_pred_luma_4x4_mode_diag_dr_ssse3;\n    ps_codec->apf_intra_pred_luma_4x4[5] = ih264_intra_pred_luma_4x4_mode_vert_r_ssse3;\n    ps_codec->apf_intra_pred_luma_4x4[6] = ih264_intra_pred_luma_4x4_mode_horz_d_ssse3;\n    ps_codec->apf_intra_pred_luma_4x4[7] = ih264_intra_pred_luma_4x4_mode_vert_l_ssse3;\n    ps_codec->apf_intra_pred_luma_4x4[8] = ih264_intra_pred_luma_4x4_mode_horz_u_ssse3;\n\n    /* Init function pointers for intra pred leaf level functions luma\n     * Intra 8x8 */\n    ps_codec->apf_intra_pred_luma_8x8[0] = ih264_intra_pred_luma_8x8_mode_vert_ssse3;\n    ps_codec->apf_intra_pred_luma_8x8[1] = ih264_intra_pred_luma_8x8_mode_horz_ssse3;\n    ps_codec->apf_intra_pred_luma_8x8[2] = ih264_intra_pred_luma_8x8_mode_dc_ssse3;\n    ps_codec->apf_intra_pred_luma_8x8[3] = ih264_intra_pred_luma_8x8_mode_diag_dl_ssse3;\n    ps_codec->apf_intra_pred_luma_8x8[4] = ih264_intra_pred_luma_8x8_mode_diag_dr_ssse3;\n    ps_codec->apf_intra_pred_luma_8x8[5] = ih264_intra_pred_luma_8x8_mode_vert_r_ssse3;\n    ps_codec->apf_intra_pred_luma_8x8[6] = ih264_intra_pred_luma_8x8_mode_horz_d_ssse3;\n    ps_codec->apf_intra_pred_luma_8x8[7] = ih264_intra_pred_luma_8x8_mode_vert_l_ssse3;\n    ps_codec->apf_intra_pred_luma_8x8[8] = ih264_intra_pred_luma_8x8_mode_horz_u_ssse3;\n\n    ps_codec->pf_intra_pred_ref_filtering = ih264_intra_pred_luma_8x8_mode_ref_filtering;\n\n    /* Init function pointers for intra pred leaf level functions chroma\n     * Intra 8x8 */\n    ps_codec->apf_intra_pred_chroma[0] = ih264_intra_pred_chroma_8x8_mode_vert_ssse3;\n    ps_codec->apf_intra_pred_chroma[1] = ih264_intra_pred_chroma_8x8_mode_horz_ssse3;\n    ps_codec->apf_intra_pred_chroma[2] = ih264_intra_pred_chroma_8x8_mode_dc;\n    ps_codec->apf_intra_pred_chroma[3] = ih264_intra_pred_chroma_8x8_mode_plane_ssse3;\n\n\n    ps_codec->pf_pad_left_luma = ih264_pad_left_luma_ssse3;\n    ps_codec->pf_pad_left_chroma = ih264_pad_left_chroma_ssse3;\n    ps_codec->pf_pad_right_luma = ih264_pad_right_luma_ssse3;\n    ps_codec->pf_pad_right_chroma = ih264_pad_right_chroma_ssse3;\n\n\n    ps_codec->pf_iquant_itrans_recon_luma_4x4 = ih264_iquant_itrans_recon_4x4_ssse3;\n    ps_codec->pf_iquant_itrans_recon_luma_4x4_dc = ih264_iquant_itrans_recon_4x4_dc_ssse3;\n    ps_codec->pf_iquant_itrans_recon_luma_8x8 = ih264_iquant_itrans_recon_8x8_ssse3;\n    ps_codec->pf_iquant_itrans_recon_luma_8x8_dc = ih264_iquant_itrans_recon_8x8_dc_ssse3;\n\n    ps_codec->pf_iquant_itrans_recon_chroma_4x4_dc = ih264_iquant_itrans_recon_chroma_4x4_dc_ssse3;\n\n    /* Init fn ptr luma deblocking */\n    ps_codec->pf_deblk_luma_vert_bs4 = ih264_deblk_luma_vert_bs4_ssse3;\n    ps_codec->pf_deblk_luma_vert_bslt4 = ih264_deblk_luma_vert_bslt4_ssse3;\n    ps_codec->pf_deblk_luma_vert_bs4_mbaff = ih264_deblk_luma_vert_bs4_mbaff_ssse3;\n    ps_codec->pf_deblk_luma_vert_bslt4_mbaff = ih264_deblk_luma_vert_bslt4_mbaff_ssse3;\n\n    ps_codec->pf_deblk_luma_horz_bs4 = ih264_deblk_luma_horz_bs4_ssse3;\n    ps_codec->pf_deblk_luma_horz_bslt4 = ih264_deblk_luma_horz_bslt4_ssse3;\n\n    /* Init fn ptr chroma deblocking */\n    ps_codec->pf_deblk_chroma_vert_bs4 = ih264_deblk_chroma_vert_bs4_ssse3;\n    ps_codec->pf_deblk_chroma_horz_bs4 = ih264_deblk_chroma_horz_bs4_ssse3;\n    ps_codec->pf_deblk_chroma_vert_bs4_mbaff = ih264_deblk_chroma_vert_bs4_mbaff_ssse3;\n    ps_codec->pf_deblk_chroma_vert_bslt4 = ih264_deblk_chroma_vert_bslt4_ssse3;\n    ps_codec->pf_deblk_chroma_horz_bslt4 = ih264_deblk_chroma_horz_bslt4_ssse3;\n    ps_codec->pf_deblk_chroma_vert_bslt4_mbaff = ih264_deblk_chroma_vert_bslt4_mbaff_ssse3;\n\n    /* Inter pred leaf level functions */\n\n    ps_codec->apf_inter_pred_luma[0] = ih264_inter_pred_luma_copy_ssse3;\n    ps_codec->apf_inter_pred_luma[1] = ih264_inter_pred_luma_horz_qpel_ssse3;\n    ps_codec->apf_inter_pred_luma[2] = ih264_inter_pred_luma_horz_ssse3;\n    ps_codec->apf_inter_pred_luma[3] = ih264_inter_pred_luma_horz_qpel_ssse3;\n    ps_codec->apf_inter_pred_luma[4] = ih264_inter_pred_luma_vert_qpel_ssse3;\n    ps_codec->apf_inter_pred_luma[5] = ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3;\n    ps_codec->apf_inter_pred_luma[6] = ih264_inter_pred_luma_horz_hpel_vert_qpel_ssse3;\n    ps_codec->apf_inter_pred_luma[7] = ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3;\n    ps_codec->apf_inter_pred_luma[8] = ih264_inter_pred_luma_vert_ssse3;\n    ps_codec->apf_inter_pred_luma[9] = ih264_inter_pred_luma_horz_qpel_vert_hpel_ssse3;\n    ps_codec->apf_inter_pred_luma[10] = ih264_inter_pred_luma_horz_hpel_vert_hpel_ssse3;\n    ps_codec->apf_inter_pred_luma[11] = ih264_inter_pred_luma_horz_qpel_vert_hpel_ssse3;\n    ps_codec->apf_inter_pred_luma[12] = ih264_inter_pred_luma_vert_qpel_ssse3;\n    ps_codec->apf_inter_pred_luma[13] = ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3;\n    ps_codec->apf_inter_pred_luma[14] = ih264_inter_pred_luma_horz_hpel_vert_qpel_ssse3;\n    ps_codec->apf_inter_pred_luma[15] = ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3;\n\n    ps_codec->pf_inter_pred_chroma = ih264_inter_pred_chroma_ssse3;\n\n\n    return;\n}\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/.gitkeep",
    "content": ""
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/example/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.7)\n\nproject(wxwidgets-example)\n\nadd_executable(main WIN32 popup.cpp)\n\nfind_package(wxWidgets REQUIRED)\ntarget_compile_features(main PRIVATE cxx_std_11)\ntarget_compile_definitions(main PRIVATE ${wxWidgets_DEFINITIONS} \"$<$<CONFIG:DEBUG>:${wxWidgets_DEFINITIONS_DEBUG}>\")\ntarget_include_directories(main PRIVATE ${wxWidgets_INCLUDE_DIRS})\ntarget_link_libraries(main PRIVATE ${wxWidgets_LIBRARIES})\n\nadd_executable(main2 WIN32 popup.cpp)\n\nfind_package(wxWidgets CONFIG REQUIRED)\ntarget_link_libraries(main2 PRIVATE wx::core wx::base)\ntarget_compile_features(main2 PRIVATE cxx_std_11)\n\noption(USE_WXRC \"Use the wxrc resource compiler\" ON)\nif(USE_WXRC)\n    execute_process(\n        COMMAND \"${wxWidgets_wxrc_EXECUTABLE}\" --help\n        RESULTS_VARIABLE error_result\n    )\n    if(error_result)\n        message(FATAL_ERROR \"Failed to run wxWidgets_wxrc_EXECUTABLE (${wxWidgets_wxrc_EXECUTABLE})\")\n    endif()\nendif()\n\nset(PRINT_VARS \"\" CACHE STRING \"Variables to print at the end of configuration\")\nforeach(var IN LISTS PRINT_VARS)\n    message(STATUS \"${var}:=${${var}}\")\nendforeach()\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/fix-libs-export.patch",
    "content": "diff --git a/build/cmake/config.cmake b/build/cmake/config.cmake\nindex b359560..7504458 100644\n--- a/build/cmake/config.cmake\n+++ b/build/cmake/config.cmake\n@@ -39,8 +39,14 @@ macro(wx_get_dependencies var lib)\n             else()\n                 # For the value like $<$<CONFIG:DEBUG>:LIB_PATH>\n                 # Or $<$<NOT:$<CONFIG:DEBUG>>:LIB_PATH>\n-                string(REGEX REPLACE \"^.+>:(.+)>$\" \"\\\\1\" dep_name ${dep})\n-                if (NOT dep_name)\n+                if(dep MATCHES \"^(.+>):(.+)>$\")\n+                    if(CMAKE_BUILD_TYPE STREQUAL \"Debug\" AND CMAKE_MATCH_1 STREQUAL [[$<$<NOT:$<CONFIG:DEBUG>>]])\n+                        continue()\n+                    elseif(CMAKE_BUILD_TYPE STREQUAL \"Release\" AND CMAKE_MATCH_1 STREQUAL [[$<$<CONFIG:DEBUG>]])\n+                        continue()\n+                    endif()\n+                    set(dep_name \"${CMAKE_MATCH_2}\")\n+                else()\n                     set(dep_name ${dep})\n                 endif()\n             endif()\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/fix-listctrl-layout.patch",
    "content": "diff --git a/src/msw/listctrl.cpp b/src/msw/listctrl.cpp\nindex 5e1cd98a8b..169ab7847d 100644\n--- a/src/msw/listctrl.cpp\n+++ b/src/msw/listctrl.cpp\n@@ -1385,20 +1385,29 @@ bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code)\n \n     wxCopyRECTToRect(rectWin, rect);\n \n-    // We can't use wxGetListCtrlSubItemRect() for the 0th subitem as 0 means\n-    // the entire row for this function, so we need to calculate it ourselves.\n-    if ( subItem == 0 && code == wxLIST_RECT_BOUNDS )\n+    // We can't trust the native LVM_GETSUBITEMRECT for LVIR_BOUNDS because:\n+    //  - subitem 0 returns the entire row bounds, not just column 0\n+    //  - when column 0 is narrower than the icon, the native control clamps\n+    //    all subitems' left edge to at least the icon width, misaligning them\n+    //\n+    // So for all subitems we calculate x and width from GetColumnWidth() in\n+    // visual (column order) order, which always reflects the real column sizes.\n+    if ( subItem != wxLIST_GETSUBITEMRECT_WHOLEITEM && code == wxLIST_RECT_BOUNDS )\n     {\n-        // Because the columns can be reordered, we need to sum the widths of\n-        // all preceding columns to get the correct x position.\n+        // Start from the row's left edge (which accounts for scrolling).\n+        RECT rowRect;\n+        wxGetListCtrlItemRect(GetHwnd(), item, LVIR_BOUNDS, rowRect);\n+        int x = rowRect.left;\n+\n         for ( auto col : GetColumnsOrder() )\n         {\n             if ( col == subItem )\n                 break;\n \n-            rect.x += GetColumnWidth(col);\n+            x += GetColumnWidth(col);\n         }\n \n+        rect.x = x;\n         rect.width = GetColumnWidth(subItem);\n     }\n \n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/fix-pcre2.patch",
    "content": "diff --git a/build/cmake/modules/FindPCRE2.cmake b/build/cmake/modules/FindPCRE2.cmake\nindex a27693a..455675a 100644\n--- a/build/cmake/modules/FindPCRE2.cmake\n+++ b/build/cmake/modules/FindPCRE2.cmake\n@@ -24,7 +24,10 @@ set(PCRE2_CODE_UNIT_WIDTH_USED \"${PCRE2_CODE_UNIT_WIDTH}\" CACHE INTERNAL \"\")\n \n find_package(PkgConfig QUIET)\n pkg_check_modules(PC_PCRE2 QUIET libpcre2-${PCRE2_CODE_UNIT_WIDTH})\n+set(PCRE2_LIBRARIES ${PC_PCRE2_LINK_LIBRARIES})\n+set(PCRE2_INCLUDE_DIRS ${PC_PCRE2_INCLUDE_DIRS})\n \n+if (0)\n find_path(PCRE2_INCLUDE_DIRS\n     NAMES pcre2.h\n     HINTS ${PC_PCRE2_INCLUDEDIR}\n@@ -36,6 +39,7 @@ find_library(PCRE2_LIBRARIES\n     HINTS ${PC_PCRE2_LIBDIR}\n           ${PC_PCRE2_LIBRARY_DIRS}\n )\n+endif()\n \n include(FindPackageHandleStandardArgs)\n FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE2 REQUIRED_VARS PCRE2_LIBRARIES PCRE2_INCLUDE_DIRS VERSION_VAR PC_PCRE2_VERSION)\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/gtk3-link-libraries.patch",
    "content": "diff --git a/build/cmake/modules/FindGTK3.cmake b/build/cmake/modules/FindGTK3.cmake\nindex d2939a1..daf33fe 100644\n--- a/build/cmake/modules/FindGTK3.cmake\n+++ b/build/cmake/modules/FindGTK3.cmake\n@@ -47,6 +47,12 @@ include(CheckSymbolExists)\n set(CMAKE_REQUIRED_INCLUDES ${GTK3_INCLUDE_DIRS})\n check_symbol_exists(GDK_WINDOWING_WAYLAND \"gdk/gdk.h\" wxHAVE_GDK_WAYLAND)\n check_symbol_exists(GDK_WINDOWING_X11 \"gdk/gdk.h\" wxHAVE_GDK_X11)\n+# With Lerc support in TIFF, Gtk3 may carry C++ compiler libs which break FindWxWidgets.cmake.\n+# WxWidgets is C++, so we can remove them here using the inverse pattern.\n+set(cxx_libs \"${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES}\")\n+list(REMOVE_ITEM cxx_libs ${CMAKE_C_IMPLICIT_LINK_LIBRARIES})\n+list(REMOVE_ITEM GTK3_LINK_LIBRARIES ${cxx_libs})\n+set(GTK3_LIBRARIES \"${GTK3_LINK_LIBRARIES}\" CACHE INTERNAL \"\")\n include(FindPackageHandleStandardArgs)\n FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK3 DEFAULT_MSG GTK3_INCLUDE_DIRS GTK3_LIBRARIES VERSION_OK)\n \n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/install-layout.patch",
    "content": "diff --git a/build/cmake/init.cmake b/build/cmake/init.cmake\nindex 4ed7b264ef..195d776aeb 100644\n--- a/build/cmake/init.cmake\n+++ b/build/cmake/init.cmake\n@@ -201,11 +201,11 @@ endif()\n wx_get_install_dir(include)\n if(WIN32_MSVC_NAMING)\n     if(wxBUILD_SHARED)\n-        set(lib_suffix \"_dll\")\n+        # set(lib_suffix \"_dll\")\n     else()\n-        set(lib_suffix \"_lib\")\n+        # set(lib_suffix \"_lib\")\n     endif()\n-    set(wxPLATFORM_LIB_DIR \"${wxCOMPILER_PREFIX}${wxARCH_SUFFIX}${lib_suffix}\")\n+    # set(wxPLATFORM_LIB_DIR \"${wxCOMPILER_PREFIX}${wxARCH_SUFFIX}${lib_suffix}\")\n     set(wxINSTALL_INCLUDE_DIR \"${include_dir}\")\n else()\n     wx_get_flavour(lib_flavour \"-\")\ndiff --git a/build/cmake/install.cmake b/build/cmake/install.cmake\nindex cbbefdebe9..8f2759d5ad 100644\n--- a/build/cmake/install.cmake\n+++ b/build/cmake/install.cmake\n@@ -66,7 +66,7 @@ else()\n     wx_get_install_platform_dir(runtime)\n     install(DIRECTORY DESTINATION \"${runtime_dir}\")\n     install(CODE \"execute_process( \\\n-        COMMAND ${CMAKE_COMMAND} -E create_symlink \\\n+        COMMAND ${CMAKE_COMMAND} -E copy \\\n         \\\"${CMAKE_INSTALL_PREFIX}/${library_dir}/wx/config/${wxBUILD_FILE_ID}\\\" \\\n         \\\"\\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${runtime_dir}/wx-config\\\" \\\n         )\"\ndiff --git a/build/cmake/utils/CMakeLists.txt b/build/cmake/utils/CMakeLists.txt\nindex 608351ac42..d8110f9148 100644\n--- a/build/cmake/utils/CMakeLists.txt\n+++ b/build/cmake/utils/CMakeLists.txt\n@@ -40,7 +40,7 @@ if(wxUSE_XRC)\n \n         # Don't use wx_install() here to preserve escaping.\n         install(CODE \"execute_process( \\\n-            COMMAND ${CMAKE_COMMAND} -E create_symlink \\\n+            COMMAND ${CMAKE_COMMAND} -E copy \\\n             \\\"${CMAKE_INSTALL_PREFIX}/${runtime_dir}/${wxrc_output_name}${EXE_SUFFIX}\\\" \\\n             \\\"\\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${runtime_dir}/wxrc${EXE_SUFFIX}\\\" \\\n             )\"\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/nanosvg-ext-depend.patch",
    "content": "diff --git a/build/cmake/wxWidgetsConfig.cmake.in b/build/cmake/wxWidgetsConfig.cmake.in\nindex 2f3a735d92..c134900764 100644\n--- a/build/cmake/wxWidgetsConfig.cmake.in\n+++ b/build/cmake/wxWidgetsConfig.cmake.in\n@@ -155,6 +155,7 @@ foreach(libname @wxLIB_TARGETS@)\n endforeach()\n \n include(CMakeFindDependencyMacro)\n+find_dependency(NanoSVG CONFIG)\n \n if(TARGET wx::wxnet AND @wxUSE_WEBREQUEST_CURL@)\n     # make sure CURL targets are available:\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/portfile.cmake",
    "content": "vcpkg_from_github(\n    OUT_SOURCE_PATH SOURCE_PATH\n    REPO wxWidgets/wxWidgets\n    REF \"v${VERSION}\"\n    SHA512 c47460c8bc150445e7774a287a79bd70b6d96b91ea46b51f238a317f068e466d570c5a94e2204d112e42da781a5cef98236718efff4b7f539d61a12ceaf65eb7\n    HEAD_REF master\n    PATCHES\n        install-layout.patch\n        relocatable-wx-config.patch\n        nanosvg-ext-depend.patch\n        fix-libs-export.patch\n        fix-pcre2.patch\n        gtk3-link-libraries.patch\n        sdl2.patch\n        fix-listctrl-layout.patch\n)\n\n# Submodule dependencies\nvcpkg_from_github(\n    OUT_SOURCE_PATH lexilla_SOURCE_PATH\n    REPO wxWidgets/lexilla\n    REF \"0dbce0b418b8b3d2ef30304d0bf53ff58c07ed84\"\n    SHA512 61f7b0217f4518121ecad32f015b53600e565bdd499d4020468cf6c8a533d516c6881115aa5e640afca5ea428535f47680cde426fa3dbabe9e4423b4526853fd\n    HEAD_REF wx\n)\nfile(COPY \"${lexilla_SOURCE_PATH}/\" DESTINATION \"${SOURCE_PATH}/src/stc/lexilla\")\nvcpkg_from_github(\n    OUT_SOURCE_PATH scintilla_SOURCE_PATH\n    REPO wxWidgets/scintilla\n    REF \"0b90f31ced23241054e8088abb50babe9a44ae67\"\n    SHA512 db1f3007f4bd8860fad0817b6cf87980a4b713777025128cf5caea8d6d17b6fafe23fd22ff6886d7d5a420f241d85b7502b85d7e52b4ddb0774edc4b0a0203e7\n    HEAD_REF wx\n)\nfile(COPY \"${scintilla_SOURCE_PATH}/\" DESTINATION \"${SOURCE_PATH}/src/stc/scintilla\")\n\nvcpkg_check_features(\n    OUT_FEATURE_OPTIONS FEATURE_OPTIONS\n    FEATURES\n        fonts   wxUSE_PRIVATE_FONTS\n        media   wxUSE_MEDIACTRL\n        secretstore wxUSE_SECRETSTORE\n        sound   wxUSE_SOUND\n        webview wxUSE_WEBVIEW\n        webview wxUSE_WEBVIEW_EDGE\n)\n\nset(OPTIONS_RELEASE \"\")\nif(NOT \"debug-support\" IN_LIST FEATURES)\n    list(APPEND OPTIONS_RELEASE \"-DwxBUILD_DEBUG_LEVEL=0\")\nendif()\n\nset(OPTIONS \"\")\nif(VCPKG_TARGET_IS_WINDOWS AND (VCPKG_TARGET_ARCHITECTURE STREQUAL \"arm64\" OR VCPKG_TARGET_ARCHITECTURE STREQUAL \"arm\"))\n    list(APPEND OPTIONS\n        -DwxUSE_STACKWALKER=OFF\n    )\nendif()\n\nif(VCPKG_TARGET_IS_WINDOWS OR VCPKG_TARGET_IS_OSX)\n    list(APPEND OPTIONS -DwxUSE_WEBREQUEST_CURL=OFF)\nelse()\n    list(APPEND OPTIONS -DwxUSE_WEBREQUEST_CURL=ON)\nendif()\n\nif(VCPKG_TARGET_IS_WINDOWS)\n    if(VCPKG_CRT_LINKAGE STREQUAL \"dynamic\")\n        list(APPEND OPTIONS -DwxBUILD_USE_STATIC_RUNTIME=OFF)\n    else()\n        list(APPEND OPTIONS -DwxBUILD_USE_STATIC_RUNTIME=ON)\n    endif()\nendif()\n\nif(\"webview\" IN_LIST FEATURES AND VCPKG_LIBRARY_LINKAGE STREQUAL \"static\")\n  list(APPEND OPTIONS -DwxUSE_WEBVIEW_EDGE_STATIC=ON)\nendif()\n\nvcpkg_find_acquire_program(PKGCONFIG)\n\n# This may be set to ON by users in a custom triplet.\n# The use of 'WXWIDGETS_USE_STD_CONTAINERS' (ON or OFF) is not API compatible\n# which is why it must be set in a custom triplet rather than a port feature.\n# For backwards compatibility, we also replace 'wxUSE_STL' (which no longer\n# exists) with 'wxUSE_STD_STRING_CONV_IN_WXSTRING' which still exists and was\n# set by `wxUSE_STL` previously.\nif(NOT DEFINED WXWIDGETS_USE_STL)\n    set(WXWIDGETS_USE_STL OFF)\nendif()\n\nif(NOT DEFINED WXWIDGETS_USE_STD_CONTAINERS)\n    set(WXWIDGETS_USE_STD_CONTAINERS OFF)\nendif()\n\nvcpkg_cmake_configure(\n    SOURCE_PATH \"${SOURCE_PATH}\"\n    OPTIONS\n        ${FEATURE_OPTIONS}\n        -DwxUSE_REGEX=sys\n        -DwxUSE_ZLIB=sys\n        -DwxUSE_EXPAT=sys\n        -DwxUSE_LIBJPEG=sys\n        -DwxUSE_LIBPNG=sys\n        -DwxUSE_LIBTIFF=sys\n        -DwxUSE_NANOSVG=sys\n        -DwxUSE_LIBWEBP=sys\n        -DwxUSE_GLCANVAS=ON\n        -DwxUSE_LIBGNOMEVFS=OFF\n        -DwxUSE_LIBNOTIFY=OFF\n        -DwxUSE_STD_STRING_CONV_IN_WXSTRING=${WXWIDGETS_USE_STL}\n        -DwxUSE_STD_CONTAINERS=${WXWIDGETS_USE_STD_CONTAINERS}\n        -DwxUSE_UIACTIONSIMULATOR=OFF\n        -DCMAKE_DISABLE_FIND_PACKAGE_GSPELL=ON\n        -DCMAKE_DISABLE_FIND_PACKAGE_MSPACK=ON\n        -DwxBUILD_INSTALL_RUNTIME_DIR:PATH=bin\n        ${OPTIONS}\n        \"-DPKG_CONFIG_EXECUTABLE=${PKGCONFIG}\"\n        # The minimum cmake version requirement for Cotire is 2.8.12.\n        # however, we need to declare that the minimum cmake version requirement is at least 3.1 to use CMAKE_PREFIX_PATH as the path to find .pc.\n        -DPKG_CONFIG_USE_CMAKE_PREFIX_PATH=ON\n    OPTIONS_RELEASE\n        ${OPTIONS_RELEASE}\n    MAYBE_UNUSED_VARIABLES\n        CMAKE_DISABLE_FIND_PACKAGE_GSPELL\n        CMAKE_DISABLE_FIND_PACKAGE_MSPACK\n)\n\nvcpkg_cmake_install()\nvcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/wxWidgets-3.3)\n\n# The CMake export is not ready for use: It lacks a config file.\nfile(REMOVE_RECURSE\n    ${CURRENT_PACKAGES_DIR}/lib/cmake\n    ${CURRENT_PACKAGES_DIR}/debug/lib/cmake\n)\n\nset(tools wxrc)\nif(NOT VCPKG_TARGET_IS_WINDOWS)\n    list(APPEND tools wxrc-3.3)\n    file(MAKE_DIRECTORY \"${CURRENT_PACKAGES_DIR}/tools/${PORT}\")\n    file(RENAME \"${CURRENT_PACKAGES_DIR}/bin/wx-config\" \"${CURRENT_PACKAGES_DIR}/tools/${PORT}/wx-config\")\n    if(NOT VCPKG_BUILD_TYPE)\n        file(MAKE_DIRECTORY \"${CURRENT_PACKAGES_DIR}/tools/${PORT}/debug\")\n        file(RENAME \"${CURRENT_PACKAGES_DIR}/debug/bin/wx-config\" \"${CURRENT_PACKAGES_DIR}/tools/${PORT}/debug/wx-config\")\n    endif()\nendif()\nvcpkg_copy_tools(TOOL_NAMES ${tools} AUTO_CLEAN)\n\n# do the copy pdbs now after the dlls got moved to the expected /bin folder above\nvcpkg_copy_pdbs()\n\nfile(REMOVE_RECURSE \"${CURRENT_PACKAGES_DIR}/include/msvc\")\nfile(REMOVE_RECURSE \"${CURRENT_PACKAGES_DIR}/debug/include\")\nfile(REMOVE_RECURSE \"${CURRENT_PACKAGES_DIR}/debug/lib/mswu\")\nif(VCPKG_BUILD_TYPE STREQUAL \"release\")\n    file(REMOVE_RECURSE \"${CURRENT_PACKAGES_DIR}/lib/mswud\")\nendif()\n\nfile(GLOB_RECURSE INCLUDES \"${CURRENT_PACKAGES_DIR}/include/*.h\")\nif(EXISTS \"${CURRENT_PACKAGES_DIR}/lib/mswu/wx/setup.h\")\n    list(APPEND INCLUDES \"${CURRENT_PACKAGES_DIR}/lib/mswu/wx/setup.h\")\nendif()\nif(EXISTS \"${CURRENT_PACKAGES_DIR}/debug/lib/mswud/wx/setup.h\")\n    list(APPEND INCLUDES \"${CURRENT_PACKAGES_DIR}/debug/lib/mswud/wx/setup.h\")\nendif()\nforeach(INC IN LISTS INCLUDES)\n    file(READ \"${INC}\" _contents)\n    if(VCPKG_LIBRARY_LINKAGE STREQUAL \"static\")\n        string(REPLACE \"defined(WXUSINGDLL)\" \"0\" _contents \"${_contents}\")\n    else()\n        string(REPLACE \"defined(WXUSINGDLL)\" \"1\" _contents \"${_contents}\")\n    endif()\n    # Remove install prefix from setup.h to ensure package is relocatable\n    string(REGEX REPLACE \"\\n#define wxINSTALL_PREFIX [^\\n]*\" \"\\n#define wxINSTALL_PREFIX \\\"\\\"\" _contents \"${_contents}\")\n    file(WRITE \"${INC}\" \"${_contents}\")\nendforeach()\n\nif(NOT EXISTS \"${CURRENT_PACKAGES_DIR}/include/wx/setup.h\")\n    file(GLOB_RECURSE WX_SETUP_H_FILES_DBG \"${CURRENT_PACKAGES_DIR}/debug/lib/*.h\")\n    file(GLOB_RECURSE WX_SETUP_H_FILES_REL \"${CURRENT_PACKAGES_DIR}/lib/*.h\")\n\n    if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL \"release\")\n        vcpkg_replace_string(\"${WX_SETUP_H_FILES_REL}\" \"${CURRENT_PACKAGES_DIR}\" \"\" IGNORE_UNCHANGED)\n\n        string(REPLACE \"${CURRENT_PACKAGES_DIR}/lib/\" \"\" WX_SETUP_H_FILES_REL \"${WX_SETUP_H_FILES_REL}\")\n        string(REPLACE \"/setup.h\" \"\" WX_SETUP_H_REL_RELATIVE \"${WX_SETUP_H_FILES_REL}\")\n    endif()\n    if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL \"debug\")\n        vcpkg_replace_string(\"${WX_SETUP_H_FILES_DBG}\" \"${CURRENT_PACKAGES_DIR}\" \"\" IGNORE_UNCHANGED)\n\n        string(REPLACE \"${CURRENT_PACKAGES_DIR}/debug/lib/\" \"\" WX_SETUP_H_FILES_DBG \"${WX_SETUP_H_FILES_DBG}\")\n        string(REPLACE \"/setup.h\" \"\" WX_SETUP_H_DBG_RELATIVE \"${WX_SETUP_H_FILES_DBG}\")\n    endif()\n\n    configure_file(\"${CMAKE_CURRENT_LIST_DIR}/setup.h.in\" \"${CURRENT_PACKAGES_DIR}/include/wx/setup.h\" @ONLY)\nendif()\n\nfile(GLOB configs LIST_DIRECTORIES false \"${CURRENT_PACKAGES_DIR}/lib/wx/config/*\" \"${CURRENT_PACKAGES_DIR}/tools/${PORT}/wx-config\")\nforeach(config IN LISTS configs)\n    vcpkg_replace_string(\"${config}\" \"${CURRENT_INSTALLED_DIR}\" [[${prefix}]])\nendforeach()\nfile(GLOB configs LIST_DIRECTORIES false \"${CURRENT_PACKAGES_DIR}/debug/lib/wx/config/*\" \"${CURRENT_PACKAGES_DIR}/tools/${PORT}/debug/wx-config\")\nforeach(config IN LISTS configs)\n    vcpkg_replace_string(\"${config}\" \"${CURRENT_INSTALLED_DIR}/debug\" [[${prefix}]])\nendforeach()\n\n# For CMake multi-config in connection with wrapper\nif(EXISTS \"${CURRENT_PACKAGES_DIR}/debug/lib/mswud/wx/setup.h\")\n    file(INSTALL \"${CURRENT_PACKAGES_DIR}/debug/lib/mswud/wx/setup.h\"\n        DESTINATION \"${CURRENT_PACKAGES_DIR}/lib/mswud/wx\"\n    )\nendif()\n\nif(NOT \"debug-support\" IN_LIST FEATURES)\n    if(VCPKG_TARGET_IS_WINDOWS)\n        vcpkg_replace_string(\"${CURRENT_PACKAGES_DIR}/include/wx/debug.h\" \"#define wxDEBUG_LEVEL 1\" \"#define wxDEBUG_LEVEL 0\")\n    else()\n        vcpkg_replace_string(\"${CURRENT_PACKAGES_DIR}/include/wx-3.3/wx/debug.h\" \"#define wxDEBUG_LEVEL 1\" \"#define wxDEBUG_LEVEL 0\")\n    endif()\nendif()\n\nif(\"example\" IN_LIST FEATURES)\n    file(INSTALL\n            \"${CMAKE_CURRENT_LIST_DIR}/minimal_example/CMakeLists.txt\"\n            \"${SOURCE_PATH}/samples/minimal/minimal.cpp\"\n            \"${SOURCE_PATH}/samples/sample.xpm\"\n            \"${SOURCE_PATH}/samples/sample.rc\"\n            DESTINATION \"${CURRENT_PACKAGES_DIR}/share/${PORT}/minimal_example\"\n    )\n\n    vcpkg_replace_string(\"${CURRENT_PACKAGES_DIR}/share/${PORT}/minimal_example/minimal.cpp\" \"../sample.xpm\" \"sample.xpm\")\nendif()\n\nif(\"example\" IN_LIST FEATURES)\n    file(INSTALL\n        \"${CMAKE_CURRENT_LIST_DIR}/listctrl_example/CMakeLists.txt\"\n        \"${SOURCE_PATH}/samples/listctrl/listtest.cpp\"\n        \"${SOURCE_PATH}/samples/listctrl/listtest.h\"\n        \"${SOURCE_PATH}/samples/listctrl/listtest.rc\"\n        \"${SOURCE_PATH}/samples/sample.xpm\"\n        \"${SOURCE_PATH}/samples/sample.rc\"\n        \"${SOURCE_PATH}/samples/listctrl/bitmaps\"\n        DESTINATION \"${CURRENT_PACKAGES_DIR}/share/${PORT}/listctrl_example\"\n    )\n\n    vcpkg_replace_string(\"${CURRENT_PACKAGES_DIR}/share/${PORT}/listctrl_example/listtest.cpp\" \"../sample.xpm\" \"sample.xpm\")\n    vcpkg_replace_string(\"${CURRENT_PACKAGES_DIR}/share/${PORT}/listctrl_example/listtest.rc\" \"../sample.rc\" \"sample.rc\")\nendif()\n\nconfigure_file(\"${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake\" \"${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-cmake-wrapper.cmake\" @ONLY)\n\nfile(REMOVE \"${CURRENT_PACKAGES_DIR}/wxwidgets.props\")\nfile(REMOVE \"${CURRENT_PACKAGES_DIR}/debug/wxwidgets.props\")\nfile(REMOVE_RECURSE \"${CURRENT_PACKAGES_DIR}/build\")\nfile(REMOVE_RECURSE \"${CURRENT_PACKAGES_DIR}/debug/build\")\nfile(REMOVE_RECURSE \"${CURRENT_PACKAGES_DIR}/debug/share\")\n\nfile(INSTALL \"${CMAKE_CURRENT_LIST_DIR}/usage\" DESTINATION \"${CURRENT_PACKAGES_DIR}/share/${PORT}\")\nvcpkg_install_copyright(FILE_LIST \"${SOURCE_PATH}/docs/licence.txt\")\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/relocatable-wx-config.patch",
    "content": "diff --git a/wx-config.in b/wx-config.in\nindex 4df8571..a90db3d 100644\n--- a/wx-config.in\n+++ b/wx-config.in\n@@ -398,8 +398,23 @@ is_cross()  { [ \"x@cross_compiling@\" = \"xyes\" ]; }\n \n \n # Determine the base directories we require.\n-prefix=${input_option_prefix-${this_prefix:-@prefix@}}\n-exec_prefix=${input_option_exec_prefix-${input_option_prefix-${this_exec_prefix:-@exec_prefix@}}}\n+vcpkg_prefix=$(CDPATH= cd -- \"$(dirname -- \"$0\")\" && pwd -P)\n+case \"$vcpkg_prefix\" in\n+    */lib/wx/config)\n+        vcpkg_prefix=${vcpkg_prefix%/*/*/*}\n+        ;;\n+    */tools/wxwidgets/debug)\n+        vcpkg_prefix=${vcpkg_prefix%/*/*/*}/debug\n+        ;;\n+    */tools/wxwidgets)\n+        vcpkg_prefix=${vcpkg_prefix%/*/*}\n+        ;;\n+esac\n+if [ -n \"@MINGW@\" -a -n \"@CMAKE_HOST_WIN32@\" ]; then\n+    vcpkg_prefix=$(cygpath -m \"$vcpkg_prefix\")\n+fi\n+prefix=${input_option_prefix-${this_prefix:-$vcpkg_prefix}}\n+exec_prefix=${input_option_exec_prefix-${input_option_prefix-${this_exec_prefix:-$prefix}}}\n wxconfdir=\"@libdir@/wx/config\"\n \n installed_configs=`cd \"$wxconfdir\" 2> /dev/null && ls | grep -v \"^inplace-\"`\n@@ -936,6 +951,9 @@ prefix=${this_prefix-$prefix}\n exec_prefix=${this_exec_prefix-$exec_prefix}\n \n includedir=\"@includedir@\"\n+if [ \"@CMAKE_BUILD_TYPE@\" = \"Debug\" ] ; then\n+    includedir=\"${includedir%/debug/include}/include\"\n+fi\n libdir=\"@libdir@\"\n bindir=\"@bindir@\"\n \n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/sdl2.patch",
    "content": "diff --git a/build/cmake/init.cmake b/build/cmake/init.cmake\nindex 4ed7b264ef..9abf7c9d5d 100644\n--- a/build/cmake/init.cmake\n+++ b/build/cmake/init.cmake\n@@ -667,7 +667,9 @@ if(wxUSE_GUI)\n     endif()\n \n     if(wxUSE_SOUND AND wxUSE_LIBSDL AND UNIX AND NOT APPLE)\n-        find_package(SDL2)\n+        find_package(SDL2 CONFIG REQUIRED)\n+        set(SDL2_INCLUDE_DIR \"\" CACHE INTERNAL \"\")\n+        set(SDL2_LIBRARY SDL2::SDL2 CACHE INTERNAL \"\")\n         if(NOT SDL2_FOUND)\n             find_package(SDL)\n             mark_as_advanced(SDL_INCLUDE_DIR SDLMAIN_LIBRARY)\ndiff --git a/build/cmake/wxWidgetsConfig.cmake.in b/build/cmake/wxWidgetsConfig.cmake.in\nindex c134900764..7bcb691074 100644\n--- a/build/cmake/wxWidgetsConfig.cmake.in\n+++ b/build/cmake/wxWidgetsConfig.cmake.in\n@@ -156,6 +156,9 @@ endforeach()\n \n include(CMakeFindDependencyMacro)\n find_dependency(NanoSVG CONFIG)\n+if(\"@wxUSE_LIBSDL@\")\n+    find_dependency(SDL2 CONFIG)\n+endif()\n \n if(TARGET wx::wxnet AND @wxUSE_WEBREQUEST_CURL@)\n     # make sure CURL targets are available:\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/setup.h.in",
    "content": "#ifdef _DEBUG\n#include \"../../debug/lib/@WX_SETUP_H_DBG_RELATIVE@/setup.h\"\n#else\n#include \"../../lib/@WX_SETUP_H_REL_RELATIVE@/setup.h\"\n#endif\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/usage",
    "content": "The package wxwidgets provides CMake targets:\n\n    find_package(wxWidgets CONFIG REQUIRED)\n    target_link_libraries(main PRIVATE wx::core wx::base)\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/vcpkg-cmake-wrapper.cmake",
    "content": "cmake_policy(PUSH)\ncmake_policy(SET CMP0012 NEW)\ncmake_policy(SET CMP0054 NEW)\ncmake_policy(SET CMP0057 NEW)\n\nget_filename_component(_vcpkg_wx_root \"${CMAKE_CURRENT_LIST_DIR}/../..\" ABSOLUTE)\nset(wxWidgets_ROOT_DIR \"${_vcpkg_wx_root}\" CACHE INTERNAL \"\")\nset(WX_ROOT_DIR \"${_vcpkg_wx_root}\" CACHE INTERNAL \"\")\nunset(_vcpkg_wx_root)\n\nif(WIN32)\n    # Find all libs with \"33\" infix which is unknown to FindwxWidgets.cmake\n    function(z_vcpkg_wxwidgets_find_base_library BASENAME)\n        find_library(WX_${BASENAME}d wx${BASENAME}33ud NAMES wx${BASENAME}d PATHS \"${wxWidgets_ROOT_DIR}/debug/lib\" NO_DEFAULT_PATH)\n        find_library(WX_${BASENAME}  wx${BASENAME}33u  NAMES wx${BASENAME}  PATHS \"${wxWidgets_ROOT_DIR}/lib\" NO_DEFAULT_PATH REQUIRED)\n    endfunction()\n    function(z_vcpkg_wxwidgets_find_suffix_library BASENAME)\n        foreach(lib IN LISTS ARGN)\n            find_library(WX_${lib}d NAMES wx${BASENAME}33ud_${lib} PATHS \"${wxWidgets_ROOT_DIR}/debug/lib\" NO_DEFAULT_PATH)\n            find_library(WX_${lib}  NAMES wx${BASENAME}33u_${lib}  PATHS \"${wxWidgets_ROOT_DIR}/lib\" NO_DEFAULT_PATH)\n        endforeach()\n    endfunction()\n    z_vcpkg_wxwidgets_find_base_library(base)\n    z_vcpkg_wxwidgets_find_suffix_library(base net odbc xml)\n    z_vcpkg_wxwidgets_find_suffix_library(msw core adv aui html media xrc dbgrid gl qa richtext stc ribbon propgrid webview)\n    if(WX_stc AND \"@VCPKG_LIBRARY_LINKAGE@\" STREQUAL \"static\")\n        z_vcpkg_wxwidgets_find_base_library(scintilla)\n    endif()\n    # Force FindwxWidgets.cmake win32 mode for all windows targets built on windows\n    set(_vcpkg_wxwidgets_backup_crosscompiling \"${CMAKE_CROSSCOMPILING}\")\n    set(CMAKE_CROSSCOMPILING 0)\n    set(wxWidgets_LIB_DIR \"${wxWidgets_ROOT_DIR}/lib\" CACHE INTERNAL \"\")\nelse()\n    # FindwxWidgets.cmake unix mode, single-config\n    set(_vcpkg_wxconfig \"\")\n    if(CMAKE_BUILD_TYPE STREQUAL \"Debug\" OR \"Debug\" IN_LIST MAP_IMPORTED_CONFIG_${CMAKE_BUILD_TYPE})\n        # Debug\n        set(wxWidgets_LIB_DIR \"${wxWidgets_ROOT_DIR}/debug/lib\" CACHE INTERNAL \"\")\n        file(GLOB _vcpkg_wxconfig LIST_DIRECTORIES false \"${wxWidgets_LIB_DIR}/wx/config/*\")\n    endif()\n    if(NOT _vcpkg_wxconfig)\n        # Release or fallback\n        set(wxWidgets_LIB_DIR \"${wxWidgets_ROOT_DIR}/lib\" CACHE INTERNAL \"\")\n        file(GLOB _vcpkg_wxconfig LIST_DIRECTORIES false \"${wxWidgets_LIB_DIR}/wx/config/*\")\n    endif()\n    set(wxWidgets_CONFIG_EXECUTABLE \"${_vcpkg_wxconfig}\" CACHE INTERNAL \"\")\n    unset(_vcpkg_wxconfig)\nendif()\nset(WX_LIB_DIR \"${wxWidgets_LIB_DIR}\" CACHE INTERNAL \"\")\n\n# https://gitlab.kitware.com/cmake/cmake/-/issues/26718\n# Instead of special-casing the `atomic` library, we skip the checks entirely.\nset(_wx_lib_found TRUE)\n\n_find_package(${ARGS})\n\nunset(_wx_lib_found)\n\nif(DEFINED _vcpkg_wxwidgets_backup_crosscompiling)\n    set(CMAKE_CROSSCOMPILING \"${_vcpkg_wxwidgets_backup_crosscompiling}\")\n    unset(_vcpkg_wxwidgets_backup_crosscompiling)\nendif()\n\nif(\"@VCPKG_LIBRARY_LINKAGE@\" STREQUAL \"static\" AND NOT \"wx::core\" IN_LIST wxWidgets_LIBRARIES)\n    find_package(NanoSVG CONFIG QUIET)\n    list(APPEND wxWidgets_LIBRARIES\n        NanoSVG::nanosvg NanoSVG::nanosvgrast\n        )\nendif()\n\n\nif(WIN32 AND \"@VCPKG_LIBRARY_LINKAGE@\" STREQUAL \"static\" AND NOT \"wx::core\" IN_LIST wxWidgets_LIBRARIES)\n    find_package(EXPAT QUIET)\n    find_package(JPEG QUIET)\n    find_package(PNG QUIET)\n    find_package(TIFF QUIET)\n    find_package(ZLIB QUIET)\n    list(APPEND wxWidgets_LIBRARIES\n        ${EXPAT_LIBRARIES}\n        ${JPEG_LIBRARIES}\n        ${PNG_LIBRARIES}\n        ${TIFF_LIBRARIES}\n        ${ZLIB_LIBRARIES}\n    )\nendif()\n\ncmake_policy(POP)\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports/wxwidgets/vcpkg.json",
    "content": "{\n  \"name\": \"wxwidgets\",\n  \"version\": \"3.3.2\",\n  \"description\": [\n    \"Widget toolkit and tools library for creating graphical user interfaces (GUIs) for cross-platform applications. \",\n    \"Set WXWIDGETS_USE_STL in a custom triplet to build with the wxUSE_STL build option.\",\n    \"Set WXWIDGETS_USE_STD_CONTAINERS in a custom triplet to build with the wxUSE_STD_CONTAINERS build option.\"\n  ],\n  \"homepage\": \"https://github.com/wxWidgets/wxWidgets\",\n  \"license\": \"LGPL-2.0-or-later WITH WxWindows-exception-3.1\",\n  \"supports\": \"!uwp & !xbox\",\n  \"dependencies\": [\n    {\n      \"name\": \"cairo\",\n      \"default-features\": false,\n      \"platform\": \"!windows & !osx & !ios\"\n    },\n    {\n      \"name\": \"curl\",\n      \"default-features\": false,\n      \"platform\": \"!windows & !osx\"\n    },\n    \"expat\",\n    {\n      \"name\": \"gtk3\",\n      \"platform\": \"!windows & !osx & !ios\"\n    },\n    {\n      \"name\": \"libiconv\",\n      \"platform\": \"!windows\"\n    },\n    \"libjpeg-turbo\",\n    \"libpng\",\n    \"libwebp\",\n    \"nanosvg\",\n    \"opengl\",\n    {\n      \"name\": \"pcre2\",\n      \"default-features\": false\n    },\n    {\n      \"name\": \"tiff\",\n      \"default-features\": false\n    },\n    {\n      \"name\": \"vcpkg-cmake\",\n      \"host\": true\n    },\n    {\n      \"name\": \"vcpkg-cmake-config\",\n      \"host\": true\n    },\n    \"zlib\"\n  ],\n  \"default-features\": [\n    \"debug-support\",\n    \"sound\"\n  ],\n  \"features\": {\n    \"debug-support\": {\n      \"description\": \"Enable wxWidgets debugging support hooks even for release builds (wxDEBUG_LEVEL 1)\"\n    },\n    \"example\": {\n      \"description\": \"Example source code and CMake project\"\n    },\n    \"fonts\": {\n      \"description\": \"Enable to use the font functionality of wxWidgets\",\n      \"dependencies\": [\n        {\n          \"name\": \"fontconfig\",\n          \"platform\": \"!windows & !osx\"\n        },\n        {\n          \"name\": \"pango\",\n          \"platform\": \"!windows & !osx\"\n        }\n      ]\n    },\n    \"media\": {\n      \"description\": \"Build wxMediaCtrl support\",\n      \"dependencies\": [\n        {\n          \"name\": \"gstreamer\",\n          \"default-features\": false,\n          \"platform\": \"!windows & !osx & !ios\"\n        }\n      ]\n    },\n    \"secretstore\": {\n      \"description\": \"Use wxSecretStore class\"\n    },\n    \"sound\": {\n      \"description\": \"Build wxSound support\",\n      \"dependencies\": [\n        {\n          \"name\": \"sdl2\",\n          \"default-features\": false,\n          \"platform\": \"!windows & !osx & !ios\"\n        }\n      ]\n    },\n    \"webview\": {\n      \"description\": \"The Edge backend uses Microsoft's Edge WebView2\",\n      \"dependencies\": [\n        \"webview2\"\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_linux/.gitkeep",
    "content": ""
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_linux/cairo/portfile.cmake",
    "content": "set(VCPKG_POLICY_EMPTY_PACKAGE enabled)\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_linux/cairo/vcpkg.json",
    "content": "{\n  \"name\": \"cairo\",\n  \"version\": \"1.17.8\",\n  \"description\": \"Cairo is a 2D graphics library with support for multiple output devices. Currently supported output targets include the X Window System (via both Xlib and XCB), Quartz, Win32, image buffers, PostScript, PDF, and SVG file output. Experimental backends include OpenGL, BeOS, OS/2, and DirectFB.\",\n  \"homepage\": \"https://cairographics.org\",\n  \"license\": \"MPL-1.1\",\n  \"port-version\": 2\n}\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_linux/glm/portfile.cmake",
    "content": "set(VCPKG_POLICY_EMPTY_PACKAGE enabled)\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_linux/glm/vcpkg.json",
    "content": "{\n  \"name\": \"glm\",\n  \"version\": \"0.9.9.8\",\n  \"port-version\": 3,\n  \"description\": \"OpenGL Mathematics (GLM)\",\n  \"homepage\": \"https://glm.g-truc.net\",\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_linux/gtk3/portfile.cmake",
    "content": "set(VCPKG_POLICY_EMPTY_PACKAGE enabled)\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_linux/gtk3/vcpkg.json",
    "content": "{\n  \"name\": \"gtk3\",\n  \"version\": \"3.24.34\",\n  \"port-version\": 5,\n  \"description\": \"Portable library for creating graphical user interfaces.\",\n  \"homepage\": \"https://www.gtk.org/\",\n  \"license\": null\n}\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_linux/libpng/portfile.cmake",
    "content": "set(VCPKG_POLICY_EMPTY_PACKAGE enabled)\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_linux/libpng/vcpkg.json",
    "content": "{\n  \"name\": \"libpng\",\n  \"version\": \"1.6.39\",\n  \"port-version\": 2,\n  \"description\": \"libpng is a library implementing an interface for reading and writing PNG (Portable Network Graphics) format files\",\n  \"homepage\": \"https://github.com/glennrp/libpng\",\n  \"license\": \"libpng-2.0\"\n}\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_mac/.gitkeep",
    "content": ""
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_mac/libusb/portfile.cmake",
    "content": "set(VCPKG_LIBRARY_LINKAGE dynamic)\n\nif(VCPKG_TARGET_IS_LINUX)\n    message(\"${PORT} currently requires the following tools and libraries from the system package manager:\\n    autoreconf\\n    libudev\\n\\nThese can be installed on Ubuntu systems via apt-get install autoconf libudev-dev\")\nendif()\n\nset(VERSION 1.0.26)\nvcpkg_from_github(\n    OUT_SOURCE_PATH SOURCE_PATH\n    REPO libusb/libusb\n    REF fcf0c710ef5911ae37fbbf1b39d48a89f6f14e8a # v1.0.26.11791 2023-03-12\n    SHA512 0aa6439f7988487adf2a3bff473fec80b5c722a47f117a60696d2aa25c87cc3f20fb6aaca7c66e49be25db6a35eb0bb5f71ed7b211d1b8ee064c5d7f1b985c73\n    HEAD_REF master\n)\n\nif(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW)\n\n  if(VCPKG_LIBRARY_LINKAGE STREQUAL \"dynamic\")\n      set(LIBUSB_PROJECT_TYPE dll)\n  else()\n      set(LIBUSB_PROJECT_TYPE static)\n  endif()\n\n  # The README.md file in the archive is a symlink to README\n  # which causes issues with the windows MSBUILD process\n  file(REMOVE \"${SOURCE_PATH}/README.md\")\n\n  vcpkg_msbuild_install(\n      SOURCE_PATH \"${SOURCE_PATH}\"\n      PROJECT_SUBPATH msvc/libusb_${LIBUSB_PROJECT_TYPE}.vcxproj\n  )\n\n  file(INSTALL \"${SOURCE_PATH}/libusb/libusb.h\"  DESTINATION \"${CURRENT_PACKAGES_DIR}/include/libusb-1.0\")\n  set(prefix \"\")\n  set(exec_prefix [[${prefix}]])\n  set(libdir [[${prefix}/lib]])\n  set(includedir [[${prefix}/include]])  \n  configure_file(\"${SOURCE_PATH}/libusb-1.0.pc.in\" \"${CURRENT_PACKAGES_DIR}/lib/pkgconfig/libusb-1.0.pc\" @ONLY)\n  vcpkg_replace_string(\"${CURRENT_PACKAGES_DIR}/lib/pkgconfig/libusb-1.0.pc\" \" -lusb-1.0\" \" -llibusb-1.0\")\n  if(NOT VCPKG_BUILD_TYPE)\n      set(includedir [[${prefix}/../include]])  \n      configure_file(\"${SOURCE_PATH}/libusb-1.0.pc.in\" \"${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/libusb-1.0.pc\" @ONLY)\n      vcpkg_replace_string(\"${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/libusb-1.0.pc\" \" -lusb-1.0\" \" -llibusb-1.0\")\n  endif()\nelse()\n    vcpkg_list(SET MAKE_OPTIONS)\n    vcpkg_list(SET LIBUSB_LINK_LIBRARIES)\n    if(VCPKG_TARGET_IS_EMSCRIPTEN)\n        vcpkg_list(APPEND MAKE_OPTIONS BUILD_TRIPLET --host=wasm32)\n    endif()\n    if(\"udev\" IN_LIST FEATURES)\n        vcpkg_list(APPEND MAKE_OPTIONS \"--enable-udev\")\n        vcpkg_list(APPEND LIBUSB_LINK_LIBRARIES udev)\n    else()\n        vcpkg_list(APPEND MAKE_OPTIONS \"--disable-udev\")\n    endif()\n    vcpkg_configure_make(\n        SOURCE_PATH \"${SOURCE_PATH}\"\n        AUTOCONFIG\n        OPTIONS \n            ${MAKE_OPTIONS}\n            \"--enable-examples-build=no\"\n            \"--enable-tests-build=no\"\n    )\n    vcpkg_install_make()\nendif()\n\nvcpkg_fixup_pkgconfig()\n\nfile(INSTALL \"${CMAKE_CURRENT_LIST_DIR}/usage\" DESTINATION \"${CURRENT_PACKAGES_DIR}/share/${PORT}\")\nvcpkg_install_copyright(FILE_LIST \"${SOURCE_PATH}/COPYING\")\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_mac/libusb/usage",
    "content": "libusb can be imported via CMake FindPkgConfig module:\n    find_package(PkgConfig REQUIRED)\n    pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0)\n\n    target_link_libraries(main PRIVATE PkgConfig::libusb)\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_mac/libusb/vcpkg.json",
    "content": "{\n  \"name\": \"libusb\",\n  \"version\": \"1.0.26.11791\",\n  \"port-version\": 7,\n  \"description\": \"a cross-platform library to access USB devices\",\n  \"homepage\": \"https://github.com/libusb/libusb\",\n  \"license\": \"LGPL-2.1-or-later\"\n}\n"
  },
  {
    "path": "dependencies/vcpkg_overlay_ports_win/.gitkeep",
    "content": ""
  },
  {
    "path": "dist/linux/appimage.sh",
    "content": "#!/bin/bash\n\nif [ \"$1\" == 'X64' ]; then CPU_ARCH=\"x86_64\"; else CPU_ARCH=\"aarch64\"; fi\n\nif [[ -z \"${GITHUB_WORKSPACE}\" ]]; then\n\texport GITHUB_WORKSPACE=\".\"\nfi\n\ncurl -sSfLO \"https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-\"${CPU_ARCH}\".AppImage\"\nchmod a+x linuxdeploy*.AppImage\ncurl -sSfL https://github.com\"$(curl https://github.com/probonopd/go-appimage/releases/expanded_assets/continuous | grep \"mkappimage-.*-\"${CPU_ARCH}\".AppImage\" | head -n 1 | cut -d '\"' -f 2)\" -o mkappimage.AppImage\nchmod a+x mkappimage.AppImage\ncurl -sSfLO \"https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh\"\nchmod a+x linuxdeploy-plugin-gtk.sh\ncurl -sSfLO \"https://github.com/darealshinji/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt.sh\"\nchmod a+x linuxdeploy-plugin-checkrt.sh\n\nif [[ ! -e /usr/lib/\"${CPU_ARCH}\"-linux-gnu ]]; then\n\tsed -i 's#lib\\/\"${CPU_ARCH}\"-linux-gnu#lib64#g' linuxdeploy-plugin-gtk.sh\nfi\n\nmkdir -p AppDir/usr/bin\nmkdir -p AppDir/usr/share/Cemu\nmkdir -p AppDir/usr/share/applications\nmkdir -p AppDir/usr/share/icons/hicolor/128x128/apps\nmkdir -p AppDir/usr/share/metainfo\nmkdir -p AppDir/usr/lib\n\ncp dist/linux/info.cemu.Cemu.{desktop,png} AppDir/\ncp dist/linux/info.cemu.Cemu.metainfo.xml AppDir/usr/share/metainfo/info.cemu.Cemu.appdata.xml\n\ncp -r bin/* AppDir/usr/share/Cemu\n\nmv AppDir/usr/share/Cemu/Cemu AppDir/usr/bin/\nchmod +x AppDir/usr/bin/Cemu\n\ncp /usr/lib/\"${CPU_ARCH}\"-linux-gnu/{libsepol.so.1,libffi.so.7,libpcre.so.3,libGLU.so.1,libthai.so.0} AppDir/usr/lib\n\nexport UPD_INFO=\"gh-releases-zsync|cemu-project|Cemu|ci|Cemu.AppImage.zsync\"\nexport NO_STRIP=1\n./linuxdeploy-\"${CPU_ARCH}\".AppImage --appimage-extract-and-run \\\n  --appdir=\"${GITHUB_WORKSPACE}\"/AppDir/ \\\n  -d \"${GITHUB_WORKSPACE}\"/AppDir/info.cemu.Cemu.desktop \\\n  -i \"${GITHUB_WORKSPACE}\"/AppDir/info.cemu.Cemu.png \\\n  -e \"${GITHUB_WORKSPACE}\"/AppDir/usr/bin/Cemu \\\n  --plugin gtk \\\n  --plugin checkrt\n\nif ! GITVERSION=\"$(git rev-parse --short HEAD 2>/dev/null)\"; then\n\tGITVERSION=experimental\nfi\necho \"Cemu Version Cemu-${GITVERSION}\"\n\nrm AppDir/usr/lib/libwayland-client.so.0\necho -e \"export LC_ALL=C\\nexport FONTCONFIG_PATH=/etc/fonts\" >> AppDir/apprun-hooks/linuxdeploy-plugin-gtk.sh\nVERSION=\"${GITVERSION}\" ./mkappimage.AppImage --appimage-extract-and-run \"${GITHUB_WORKSPACE}\"/AppDir\n\nmkdir -p \"${GITHUB_WORKSPACE}\"/artifacts/\nmv Cemu-\"${GITVERSION}\"-\"${CPU_ARCH}\".AppImage \"${GITHUB_WORKSPACE}\"/artifacts/\n"
  },
  {
    "path": "dist/linux/info.cemu.Cemu.desktop",
    "content": "[Desktop Entry]\nName=Cemu\nType=Application\nTerminal=false\nIcon=info.cemu.Cemu\nExec=Cemu\nGenericName=Wii U Emulator\nGenericName[fi]=Wii U -emulaattori\nGenericName[el]=Πρόγραμμα προσομοίωσης Wii U\nGenericName[es]=Emulador de Wii U\nGenericName[pt_BR]=Emulador de Wii U\nGenericName[fr]=Émulateur de Wii U\nGenericName[it]=Emulatore Wii U\nComment=Software to emulate Wii U games and applications on PC\nComment[fi]=Ohjelmisto Wii U -pelien ja sovellusten emulointiin PC:lla\nComment[de]=Software zum emulieren von Wii U Spielen und Anwendungen auf dem PC\nComment[ru]=Программа для эмуляции игр и приложений Wii U на PC\nComment[fr]=Application pour émuler des jeux et des applications Wii U sur PC\nComment[nl]=Applicatie om Wii U spellen en applicaties te emuleren op PC\nComment[el]=Πρόγραμμα προσομοίωσης παιχνιδιών και εφαρμογών Wii U στον υπολογιστή\nComment[es]=Software para emular juegos y aplicaciones de Wii U en PC\nComment[pt_BR]=Software para emular jogos e aplicativos de Wii U no PC\nComment[it]=Software per emulare giochi e applicazioni per Wii U su PC\nCategories=Game;Emulator;\nKeywords=Nintendo;\nMimeType=application/x-wii-u-rom;\nStartupWMClass=Cemu\n"
  },
  {
    "path": "dist/linux/info.cemu.Cemu.metainfo.xml",
    "content": "<?xml version='1.0' encoding='utf-8'?>\n<component type=\"desktop\">\n  <!--Created with jdAppdataEdit 4.2-->\n  <id>info.cemu.Cemu</id>\n  <name>Cemu</name>\n  <summary>Nintendo Wii U Emulator</summary>\n  <summary xml:lang=\"de\">Nintendo Wii U Emulator</summary>\n  <summary xml:lang=\"fr\">Émulateur Nintendo Wii U</summary>\n  <summary xml:lang=\"nl\">Nintendo Wii U Emulator</summary>\n  <summary xml:lang=\"el\">Εξομοιωτής Nintendo Wii U</summary>\n  <summary xml:lang=\"es\">Emulador de Nintendo Wii U</summary>\n  <summary xml:lang=\"pt_BR\">Emulador Nintendo Wii U</summary>\n  <summary xml:lang=\"it\">Emulatore Nintendo Wii U</summary>\n  <summary xml:lang=\"fi\">Nintendo Wii U Emulaattori</summary>\n  <developer_name>Cemu Project</developer_name>\n  <launchable type=\"desktop-id\">info.cemu.Cemu.desktop</launchable>\n  <metadata_license>CC0-1.0</metadata_license>\n  <project_license>MPL-2.0</project_license>\n  <description>\n    <p>Cemu is a Nintendo Wii U emulator that is able to run most Wii U games and homebrew in a playable state. Created by Exzap, and written in C/C++.</p>\n    <p xml:lang=\"de\">Cemu ist ein Nintendo Wii U-Emulator, der die meisten Wii U Spiele und Homebrew in einem spielbaren Zustand ausführen kann. Erstellt von Exzap, und geschrieben in C/C++.</p>\n    <p xml:lang=\"fr\">Cemu est un émulateur de Wii U capable de lancer la plupart des jeux Wii U et des homebrews en interface de jeu. Crée par Exzap, et développé en C/C++.</p>\n    <p xml:lang=\"nl\">Cemu is een Nintendo Wii U emulator die de meeste Wii U en Homebrew games speelbaar kan runnen. Het project is begonnen door Exzap, en het is geschreven in C/C++.</p>\n    <p xml:lang=\"el\">Το Cemu είναι ένας προσομοιωτής της κονσόλας Nintendo Wii U που προσομοιώνει επίσημα παιχνίδια, καθώς και μη επίσημα προγράμματα (\"homebrew\") του Wii U. Δημιουργήθηκε από τον Exzap σε C/C++.</p>\n    <p xml:lang=\"es\">Cemu es un emulador de Nintendo Wii U que es capaz de ejecutar la mayoría de los juegos de Wii U y homebrew en un estado jugable. Creado por Exzap, y escrito en C y C++.</p>\n    <p xml:lang=\"pt_BR\">Cemu é um emulador de Nintendo Wii U que é capaz de executar a maioría dos jogos de Wii U e homebrew em um estado jogavel. Criado por Exzap, e escrito em C e C++.</p>\n    <p xml:lang=\"it\">Cemu è un emulatore del Nintendo Wii U in grado di eseguire in stato giocabile la maggior parte dei giochi e homebrew per Wii U. Creato da Exzap, e scritto in C/C++.</p>\n    <p xml:lang=\"fi\">Cemu on Wii U -emulaattori, joka pystyy toistamaan useimpia Wii U -pelejä ja homebrew'ta pelikelvollisesti. Luonut Exzap, kirjoitettu C:llä/C++:lla.</p>    \n    <p>This emulator aims at providing both high-accuracy and performance, and is actively being developed with new features and fixes to increase compatibility, convenience and usability.</p>\n    <p xml:lang=\"de\">Dieser Emulator zielt darauf ab, sowohl hohe Genauigkeit als auch Leistung zu bieten, und wird aktiv mit neuen Funktionen und Korrekturen weiterentwickelt, um Kompatibilität, Komfort und Benutzerfreundlichkeit zu verbessern.</p>\n    <p xml:lang=\"fr\">Cet émulateur vise à la fois à offrir fidélité et performance, il est activement développé avec des nouvelles fonctionnalités et des correctifs pour augmenter la compatibilité, la commodité et la facilité d'utilisation.</p>\n    <p xml:lang=\"nl\">De emulator richt zich op integriteit en snelheid, en wordt continu verder ontwikkeld met nieuwe toevoegingen en fixes om de compatibiliteit, het gemak en de gebruiksvriendelijkheid te verbeteren.</p>\n    <p xml:lang=\"el\">Ο προσομοιωτής αυτός στοχεύει τόσο στην ακρίβεια, όσο και στην ταχύτητα, και βελτιώνεται συνεχώς με νέες δυνατότητες και διορθώσεις που τον καθιστούν πιο βολικό, εύκολο στην χρήση και συμβατό με περισσότερα παιχνίδια.</p>\n    <p xml:lang=\"es\">Este emulador tiene como objetivo proporcionar tanto alta precisión como rendimiento y se desarrolla activamente con nuevas características y correcciones para mejorar la compatibilidad, la comodidad y la usabilidad.</p>\n    <p xml:lang=\"pt_BR\">Esse emulador visa proporcionar tanto alta precisão como rendimento e está sendo ativamente desenvolvido com novas características e correções para melhorar a compatibilidade, a comodidade e a usabilidade.</p>\n    <p xml:lang=\"it\">Questo emulatore ha l'obiettivo di fornire sia alta precisione che alte prestazioni, ed è in continuo sviluppo con nuove funzionalità e correzioni per aumentare la compatibilità, la comodità e l'usabilità.</p>\n    <p xml:lang=\"fi\">Tämä emulaattori pyrkii tarjoamaan korkeaa tarkkuutta sekä suorituskykyä, ja sitä kehitetään aktiivisesti uusilla ominaisuuksilla ja korjauksilla, jotka parantavat yhteensopivuutta, mukavuutta ja käytettävyyttä..</p>\n    <p>It was written from scratch and development on the project began roughly early 2015.</p>\n    <p xml:lang=\"de\">Er wird seit Anfang 2015 entwickelt.</p>\n    <p xml:lang=\"fr\">Il a été écrit à partir de zéro et son développement a débuté vers le début de l'année 2015.</p>\n    <p xml:lang=\"nl\">Ontwikkeling van Cemu begon ongeveer in het voorjaar van 2015.</p>\n    <p xml:lang=\"el\">Αρχισε απο το τίποτα και βρίσκεται υπό ανάπτυξη από το 2015.</p>\n    <p xml:lang=\"es\">Fue escrito desde cero y el desarrollo del proyecto comenzó aproximadamente a principios de 2015.</p>\n    <p xml:lang=\"pt_BR\">Foi escrito do zero e o desenvolvimento do projeto começou aproximadamente a princípio de 2015.</p>\n    <p xml:lang=\"it\">È stato scritto da zero e lo sviluppo del progetto è cominciato intorno all'inizio del 2015.</p>\n    <p xml:lang=\"fi\">Se kirjoitettiin tyhjästä ja sen kehitys alkoi suunnilleen vuoden 2015 alussa.</p>\n    \n  </description>\n  <screenshots>\n    <screenshot type=\"default\">\n      <image type=\"source\">https://upload.wikimedia.org/wikipedia/commons/5/58/Cemu_Screenshot.png</image>\n    </screenshot>\n  </screenshots>\n  <releases>\n    <release version=\"2.0\" date=\"2022-08-22\" type=\"stable\">\n      <url>https://github.com/cemu-project/Cemu/releases/tag/v2.0</url>\n    </release>\n  </releases>\n  <url type=\"homepage\">https://cemu.info</url>\n  <url type=\"bugtracker\">https://github.com/cemu-project/Cemu/issues</url>\n  <url type=\"faq\">https://cemu.info/faq.html</url>\n  <url type=\"help\">https://wiki.cemu.info</url>\n  <!-- <url type=\"vcs-browser\">https://github.com/cemu-project/Cemu</url> -->\n  <categories>\n    <category>Game</category>\n    <category>Emulator</category>\n  </categories>\n  <recommends>\n    <memory>8192</memory>\n  </recommends>\n  <supports>\n    <control>pointing</control>\n    <control>keyboard</control>\n    <control>gamepad</control>\n  </supports>\n  <content_rating type=\"oars-1.1\"/>\n  <provides>\n    <binary>cemu</binary>\n    <mediatype>application/x-wii-u-rom</mediatype>\n  </provides>\n  <keywords>\n    <keyword>nintendo</keyword>\n  </keywords>\n</component>\n"
  },
  {
    "path": "dist/network_services.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<content>\n    <networkname>CustomExample</networkname>\n    <disablesslverification>0</disablesslverification>\n    <urls>\n        <act>https://account.nintendo.net</act>\n        <ecs>https://ecs.wup.shop.nintendo.net/ecs/services/ECommerceSOAP</ecs>\n        <nus>https://nus.wup.shop.nintendo.net/nus/services/NetUpdateSOAP</nus>\n        <ias>https://ias.wup.shop.nintendo.net/ias/services/IdentityAuthenticationSOAP</ias>\n        <ccsu>https://ccs.wup.shop.nintendo.net/ccs/download</ccsu>\n        <ccs>http://ccs.cdn.wup.shop.nintendo.net/ccs/download</ccs>\n        <idbe>https://idbe-wup.cdn.nintendo.net/icondata</idbe>\n        <boss>https://npts.app.nintendo.net/p01/tasksheet</boss>\n        <tagaya>https://tagaya.wup.shop.nintendo.net/tagaya/versionlist</tagaya>\n        <olv>https://discovery.olv.nintendo.net/v1/endpoint</olv>\n    </urls>\n</content>"
  },
  {
    "path": "dist/windows/Cemu.manifest",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n    <dependency>\n        <dependentAssembly>\n            <assemblyIdentity type=\"win32\" name=\"Microsoft.Windows.Common-Controls\" version=\"6.0.0.0\" processorArchitecture=\"amd64\" publicKeyToken=\"6595b64144ccf1df\" language=\"*\"></assemblyIdentity>\n        </dependentAssembly>\n    </dependency>\n    <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\"><security><requestedPrivileges>\n        <requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\"></requestedExecutionLevel></requestedPrivileges></security>\n    </trustInfo>\n    <application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n        <windowsSettings>\n            <dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">True/PM</dpiAware>\n        </windowsSettings>\n    </application>\n</assembly>"
  },
  {
    "path": "src/CMakeLists.txt",
    "content": "project(cemuMain)\n\noption(CEMU_CXX_FLAGS \"Additional flags used for compiling Cemu source code\")\nif(CEMU_CXX_FLAGS)\n\tadd_compile_options(${CEMU_CXX_FLAGS})\nendif()\n\nif(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)\n\tmessage( FATAL_ERROR \"Pointers are not 64bit\" )\nendif()\n\nif(MSVC)\n\tadd_compile_definitions(WIN32_LEAN_AND_MEAN CURL_STATICLIB)\nelseif(UNIX)\n\tif(APPLE)\n\t\tadd_compile_definitions(\n\t\t\t_XOPEN_SOURCE\n\t\t\tVK_USE_PLATFORM_MACOS_MVK\n\t\t\tVK_USE_PLATFORM_METAL_EXT\n\t\t)\n\telse()\n\t\tadd_compile_definitions(\n\t\t\tVK_USE_PLATFORM_XLIB_KHR # legacy. Do we need to support XLIB surfaces?\n\t\t\tVK_USE_PLATFORM_XCB_KHR\n\t\t)\n\t\tif (ENABLE_WAYLAND)\n\t\t\tadd_compile_definitions(VK_USE_PLATFORM_WAYLAND_KHR)\n\t\tendif()\n\tendif()\n\t# warnings\n\tif(CMAKE_C_COMPILER_ID STREQUAL \"Clang\")\n\t\tadd_compile_options(-Wno-ambiguous-reversed-operator)\n\tendif()\n\n    add_compile_options(-Wno-multichar -Wno-invalid-offsetof -Wno-switch -Wno-ignored-attributes -Wno-deprecated-enum-enum-conversion)\nendif()\n\nadd_compile_definitions(VK_NO_PROTOTYPES)\n\nset(CMAKE_INCLUDE_CURRENT_DIR ON)\n\nadd_subdirectory(Common)\nadd_subdirectory(gui)\nadd_subdirectory(Cafe)\nadd_subdirectory(Cemu)\nadd_subdirectory(config)\nadd_subdirectory(input)\nadd_subdirectory(audio)\nadd_subdirectory(util)\nadd_subdirectory(imgui)\nadd_subdirectory(resource)\n\nadd_executable(CemuBin\n\tmain.cpp\n\tmainLLE.cpp\n)\n\nif(MSVC AND MSVC_VERSION EQUAL 1940)\n\t# workaround for an msvc issue on VS 17.10 where generated ILK files are too large\n\t# see https://developercommunity.visualstudio.com/t/After-updating-to-VS-1710-the-size-of-/10665511\n\tset_target_properties(CemuBin PROPERTIES LINK_FLAGS \"/INCREMENTAL:NO\")\nendif()\n\nif(WIN32)\n\ttarget_sources(CemuBin PRIVATE\n\tresource/cemu.rc\n\t../dist/windows/cemu.manifest\n\t)\nendif()\n\nset_property(TARGET CemuBin PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\nset_property(TARGET CemuBin PROPERTY WIN32_EXECUTABLE $<NOT:$<CONFIG:Debug>>)\nset(OUTPUT_NAME \"Cemu_$<LOWER_CASE:$<CONFIG>>\")\n\nif (MACOS_BUNDLE)\n\tset_property(TARGET CemuBin PROPERTY MACOSX_BUNDLE_INFO_PLIST \"${CMAKE_CURRENT_SOURCE_DIR}/resource/MacOSXBundleInfo.plist.in\")\n\n\tset(RESOURCE_FILES \"${CMAKE_SOURCE_DIR}/src/resource/cemu.icns\")\n\ttarget_sources(CemuBin PRIVATE \"${RESOURCE_FILES}\")\n\n\tset(MACOSX_BUNDLE_ICON_FILE \"cemu.icns\")\n\tset(MACOSX_BUNDLE_GUI_IDENTIFIER \"info.cemu.Cemu\")\n\tset(MACOSX_BUNDLE_BUNDLE_NAME \"Cemu\")\n\tset(MACOSX_BUNDLE_SHORT_VERSION_STRING \"${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH}\")\n\tset(MACOSX_BUNDLE_BUNDLE_VERSION \"${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH}\")\n\tset(MACOSX_BUNDLE_COPYRIGHT \"Copyright © 2024 Cemu Project\")\n\n\tset(MACOSX_BUNDLE_CATEGORY \"public.app-category.games\")\n \tset(MACOSX_MINIMUM_SYSTEM_VERSION \"13.4\")\n  \tset(MACOSX_BUNDLE_TYPE_EXTENSION \"wua\")\n\n\tset_target_properties(CemuBin PROPERTIES\n\t\tMACOSX_BUNDLE true\n\t\tRESOURCE \"${RESOURCE_FILES}\"\n\t)\n\n\tset(FOLDERS gameProfiles resources)\n\tforeach(folder ${FOLDERS})\n\t\tadd_custom_command (TARGET CemuBin POST_BUILD\n\t\t\tCOMMAND ${CMAKE_COMMAND} ARGS -E copy_directory \"${CMAKE_SOURCE_DIR}/bin/${folder}\" \"${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/SharedSupport/${folder}\")\n\tendforeach(folder)\n\n\tif(CMAKE_BUILD_TYPE STREQUAL \"Debug\")\n\t    set(LIBUSB_PATH \"${CMAKE_BINARY_DIR}/vcpkg_installed/${VCPKG_TARGET_TRIPLET}/debug/lib/libusb-1.0.0.dylib\")\n\telse()\n\t    set(LIBUSB_PATH \"${CMAKE_BINARY_DIR}/vcpkg_installed/${VCPKG_TARGET_TRIPLET}/lib/libusb-1.0.0.dylib\")\n\tendif()\n\n\tif (EXISTS \"/usr/local/lib/libMoltenVK.dylib\")\n\t\tset(MOLTENVK_PATH \"/usr/local/lib/libMoltenVK.dylib\")\n\telseif (EXISTS \"/opt/homebrew/lib/libMoltenVK.dylib\")\n\t\tset(MOLTENVK_PATH \"/opt/homebrew/lib/libMoltenVK.dylib\")\n\telse()\n\t\tmessage(FATAL_ERROR \"failed to find libMoltenVK.dylib\")\n\tendif ()\n\n\tadd_custom_command (TARGET CemuBin POST_BUILD\n\t\tCOMMAND ${CMAKE_COMMAND} ARGS -E copy \"${MOLTENVK_PATH}\" \"${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libMoltenVK.dylib\"\n\t\tCOMMAND ${CMAKE_COMMAND} ARGS -E copy \"${LIBUSB_PATH}\" \"${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libusb-1.0.0.dylib\"\n\t\tCOMMAND ${CMAKE_COMMAND} ARGS -E copy \"${CMAKE_SOURCE_DIR}/src/resource/update.sh\" \"${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/update.sh\"\n\t\tCOMMAND bash -c \"install_name_tool -add_rpath @executable_path/../Frameworks ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}\"\n\t\tCOMMAND bash -c \"install_name_tool -change ${LIBUSB_PATH} @executable_path/../Frameworks/libusb-1.0.0.dylib ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}\")\nelse()\n    if(APPLE)\n        find_library(MOLTENVK_LIBRARY \n            NAMES MoltenVK moltenvk libMoltenVK.dylib\n            PATHS /usr/local/lib /opt/homebrew/lib\n        )\n        if(MOLTENVK_LIBRARY)\n            message(STATUS \"Found MoltenVK: ${MOLTENVK_LIBRARY}\")\n            target_link_libraries(CemuBin PRIVATE ${MOLTENVK_LIBRARY})\n        else()\n            message(WARNING \"libMoltenVK.dylib not found\")\n        endif()\n        set_target_properties(CemuBin PROPERTIES \n            BUILD_WITH_INSTALL_RPATH TRUE\n            INSTALL_RPATH \"/usr/local/lib;/opt/homebrew/lib\"\n        )\n    endif()\nendif()\n\nset_target_properties(CemuBin PROPERTIES\n\t# multi-configuration generators will add a config subdirectory to RUNTIME_OUTPUT_DIRECTORY if no generator expression is used\n\t# to get the same behavior everywhere we append an empty generator expression\n\tRUNTIME_OUTPUT_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}/../bin/$<1:>\"\n\tOUTPUT_NAME \"${OUTPUT_NAME}\"\n)\n\ntarget_link_libraries(CemuBin PRIVATE\n\tCemuAudio\n\tCemuCafe\n\tCemuCommon\n\tCemuComponents\n\tCemuConfig\n\tCemuGui\n\tCemuInput\n\tCemuUtil\n\tSDL2::SDL2\n)\n\nif(UNIX AND NOT APPLE)\n\t# due to nasm output some linkers will make stack executable\n\t# cemu does not require this so we explicity disable it\n\ttarget_link_options(CemuBin PRIVATE -z noexecstack)\n\t# some residual debug info from boost/discord-rpc is normally included\n\t# most likely not helpful in debugging problems with cemu code\n\ttarget_link_options(CemuBin PRIVATE \"$<$<CONFIG:Release>:-Xlinker;--strip-debug>\")\nendif()\n\nif (BSD)\n\ttarget_link_libraries(CemuBin PRIVATE execinfo SPIRV-Tools SPIRV-Tools-opt)\nendif()\n"
  },
  {
    "path": "src/Cafe/Account/Account.cpp",
    "content": "#include \"Account.h\"\n#include \"util/helpers/helpers.h\"\n#include \"util/helpers/SystemException.h\"\n#include \"util/helpers/StringHelpers.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n#include \"Common/FileStream.h\"\n#include <boost/random/uniform_int.hpp>\n\n#include <random>\n\nstd::vector<Account> Account::s_account_list;\n\nAccount::Account(uint32 persistent_id)\n\t: m_persistent_id(persistent_id) {}\n\n\ntypedef struct\n{\n\tuint32be high;\n\tuint32be low;\n}FFLDataID_t;\n\ntypedef struct\n{\n\t/* +0x00 */ uint32\t\tuknFlags;\n\t/* +0x04 */ FFLDataID_t miiId; // bytes 8 and 9 are part of the CRC? (miiId is based on account transferable id?)\n\t/* +0x0C */ uint8\t\tukn0C[0xA];\n\t/* +0x16 */ uint8\t\tukn16[2];\n\t/* +0x18 */ uint16\t\tukn18;\n\t/* +0x1A */ uint16le\tmiiName[10];\n\t/* +0x2E */ uint16\t\tukn2E;\n\t/* +0x30 */ uint8\t\tukn30[96 - 0x30];\n}FFLData_t;\n\nuint16 FFLCalculateCRC16(uint8* input, sint32 length)\n{\n\tcemu_assert_debug((length % 8) == 0);\n\t\n\tuint16 crc = 0;\n\tfor (sint32 c = 0; c < length; c++)\n\t{\n\t\tfor (sint32 f = 0; f < 8; f++)\n\t\t{\n\t\t\tif ((crc & 0x8000) != 0)\n\t\t\t{\n\t\t\t\tuint16 t = crc << 1;\n\t\t\t\tcrc = t ^ 0x1021;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcrc <<= 1;\n\t\t\t}\n\t\t}\n\t\tcrc ^= (uint16)input[c];\n\t}\n\treturn crc;\n}\n\nAccount::Account(uint32 persistent_id, std::wstring_view mii_name)\n\t: m_persistent_id(persistent_id)\n{\n\tif (mii_name.empty())\n\t\tthrow std::system_error(AccountErrc::InvalidMiiName);\n\t\n\tstatic std::random_device s_random_device;\n\tstatic std::mt19937 s_mte(s_random_device());\n\n        // use boost library to escape static asserts in linux builds\n        boost::random::uniform_int_distribution<uint16> dist(std::numeric_limits<uint8>::min(), std::numeric_limits<uint8>::max());\n        \n        std::generate(m_uuid.begin(), m_uuid.end(), [&]() { return (uint8)dist(s_mte); });\n\n\t// 1000004 or 2000004 | lower uint32 from uuid from uuid\n\tm_transferable_id_base = (0x2000004ULL << 32);\n\tm_transferable_id_base |= ((uint64)m_uuid[12] << 24) | ((uint64)m_uuid[13] << 16) | ((uint64)m_uuid[14] << 8) | (uint64)m_uuid[15];\n\t\n\tSetMiiName(mii_name);\n\n\t// todo: generate mii data\n\t// iosuAct_generateDefaultMii\n\t// void* pMiiData = &_actAccountData[accountIndex].miiData;\n\tuint8* fflByteDataBE = m_mii_data.data();\n\n\tuint16* fflDataBE = (uint16*)m_mii_data.data();\n\t// FFLCreateId is derived from the words at location: 0x7 - 0xb (5 words, so it's a 80 bit id)\n\tfor (sint32 i = 0; i < 96 / 2; i++)\n\t\tfflDataBE[i] = _swapEndianU16(1);\n\n\t*(uint16*)(fflByteDataBE + 0x3A) = _swapEndianU16(1 | (3 << 9));\n\t*(uint16*)(fflByteDataBE + 0x2) = _swapEndianU16(1 | (1 << 12));\n\n\t//*(uint32*)(fflByteDataBE + 4) = 0; // transferable id high ?\n\t*(uint32*)(fflByteDataBE + 8) = _swapEndianU32(0x33333 + 0 + 1); // mii id low\n\n\t// swap endian (apparently it's stored little-endian)\n\tfor (sint32 i = 0; i < 96 / 2; i++)\n\t\tfflDataBE[i] = _swapEndianU16(fflDataBE[i]);\n\n\t// set default name\n\tFFLData_t* fflData = (FFLData_t*)m_mii_data.data();\n\tconst auto tmp_name = GetMiiName();\n\tmemset(fflData->miiName, 0, sizeof(fflData->miiName));\n\tstd::copy(tmp_name.begin(), tmp_name.end(), fflData->miiName);\n\n\t// calculate checksum\n\tuint32 crcCounter = 0;\n\twhile (FFLCalculateCRC16(m_mii_data.data(), 96) != 0)\n\t{\n\t\t*(uint32*)(fflDataBE + 2) = _swapEndianU32(crcCounter);\n\t\tcrcCounter++;\n\t}\n\n\tconst auto error = CheckValid();\n\tif (error)\n\t\tthrow std::system_error(error);\n}\n\nAccount::Account(std::wstring_view file_name)\n{\n\tif (!fs::exists(file_name.data()))\n\t\tthrow std::runtime_error(\"given file doesn't exist\");\n\n\tstd::unique_ptr<FileStream> file(FileStream::openFile2(file_name));\n\tif (!file)\n\t\tthrow std::runtime_error(\"can't open file\");\n\n\tParseFile(file.get());\n\tconst auto error = CheckValid();\n\tif (error)\n\t\tthrow std::system_error(error);\n}\n\nstd::error_code Account::CheckValid() const\n{\n\tif (m_persistent_id < kMinPersistendId)\n\t\treturn AccountErrc::InvalidPersistentId;\n\t\t\n\tif (m_mii_name[0] == '\\0')\n\t\treturn AccountErrc::InvalidMiiName;\n\t\n\tif (m_mii_data == decltype(m_mii_data){})\n\t\treturn AccountErrc::InvalidMiiData;\n\n\t// todo: check for other needed properties\n\n\treturn AccountErrc::NoError;\n}\n\nstd::error_code Account::Load()\n{\n\tconst auto persistent_id = m_persistent_id;\n\tconst fs::path path = GetFileName();\n\ttry\n\t{\n\t\tstd::unique_ptr<FileStream> file(FileStream::openFile2(path));\n\t\tif (!file)\n\t\t\tthrow std::runtime_error(\"can't open file\");\n\t\tParseFile(file.get());\n\t\t// fix persistent id if it's in the wrong folder\n\t\tm_persistent_id = persistent_id;\n\t\treturn CheckValid();\n\t}\n\tcatch (const std::system_error& ex)\n\t{\n\t\treturn ex.code();\n\t}\n\tcatch(const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"handled error in Account::Load: {}\", ex.what());\n\t\treturn AccountErrc::ParseError;\n\t}\n}\n\nstd::error_code Account::Save()\n{\n\tfs::path path = ActiveSettings::GetMlcPath(fmt::format(L\"usr/save/system/act/{:08x}\", m_persistent_id));\n\tif (!fs::exists(path))\n\t{\n\t\tstd::error_code ec;\n\t\tfs::create_directories(path, ec);\n\t\tif (ec)\n\t\t\treturn ec;\n\t}\n\t\t\n\tpath /= \"account.dat\";\n\n\ttry\n\t{\n\t\tstd::ofstream file;\n\t\tfile.exceptions(std::ios::badbit);\n\t\tfile.open(path);\n\t\n\t\tfile << \"AccountInstance_20120705\" << std::endl;\n\t\tfile << fmt::format(\"PersistentId={:08x}\", m_persistent_id) << std::endl;\n\t\tfile << fmt::format(\"TransferableIdBase={:x}\", m_transferable_id_base) << std::endl;\n\n\t\tfile << fmt::format(\"Uuid=\");\n\t\tfor (const auto& b : m_uuid)\n\t\t\tfile << fmt::format(\"{:02x}\", b);\n\t\tfile << std::endl;\n\n\t\tfile << fmt::format(\"MiiData=\");\n\t\tfor (const auto& b : m_mii_data)\n\t\t\tfile << fmt::format(\"{:02x}\", b);\n\t\tfile << std::endl;\n\t\t\n\t\tfile << fmt::format(\"MiiName=\");\n\t\tfor (const auto& b : m_mii_name)\n\t\t\tfile << fmt::format(\"{:04x}\", (uint16)b);\n\t\tfile << std::endl;\n\t\t\n\t\tfile << fmt::format(\"AccountId={}\", m_account_id) << std::endl;\n\t\tfile << fmt::format(\"BirthYear={:x}\", m_birth_year) << std::endl;\n\t\tfile << fmt::format(\"BirthMonth={:x}\", m_birth_month) << std::endl;\n\t\tfile << fmt::format(\"BirthDay={:x}\", m_birth_day) << std::endl;\n\t\tfile << fmt::format(\"Gender={:x}\", m_gender) << std::endl;\n\t\tfile << fmt::format(\"EmailAddress={}\", m_email) << std::endl;\n\t\tfile << fmt::format(\"Country={:x}\", m_country) << std::endl;\n\t\tfile << fmt::format(\"SimpleAddressId={:x}\", m_simple_address_id) << std::endl;\n\t\tfile << fmt::format(\"PrincipalId={:x}\", m_principal_id) << std::endl;\n\t\tfile << fmt::format(\"IsPasswordCacheEnabled={:x}\", m_password_cache_enabled) << std::endl;\n\n\t\tfile << fmt::format(\"AccountPasswordCache=\");\n\t\tfor (const auto& b : m_account_password_cache)\n\t\t\tfile << fmt::format(\"{:02x}\", b);\n\t\tfile << std::endl;\n\t\t\n\t\t// write rest of stuff we got\n\t\tfor(const auto& [key, value] : m_storage)\n\t\t{\n\t\t\tfile << fmt::format(\"{}={}\", key, value) << std::endl;\n\t\t}\n\t\t\n\t\tfile.flush();\n\t\tfile.close();\n\t\treturn CheckValid();\n\t}\n\tcatch (const std::system_error& e)\n\t{\n\t\treturn e.code();\n\t}\n}\n\nOnlineAccountError Account::GetOnlineAccountError() const\n{\n\tif (m_account_id.empty())\n\t\treturn OnlineAccountError::kNoAccountId;\n\n\tif (!IsPasswordCacheEnabled())\n\t\treturn OnlineAccountError::kNoPasswordCached;\n\n\tif (m_account_password_cache == decltype(m_account_password_cache){})\n\t\treturn OnlineAccountError::kPasswordCacheEmpty;\n\n\t/*if (m_simple_address_id == 0) not really needed\n\t\treturn false;*/\n\t\n\tif (m_principal_id == 0)\n\t\treturn OnlineAccountError::kNoPrincipalId;\n\t\n\t// TODO\n\treturn OnlineAccountError::kNone;\n}\n\nbool Account::IsValidOnlineAccount() const\n{\n\treturn GetOnlineAccountError() == OnlineAccountError::kNone;\n}\n\nfs::path Account::GetFileName() const\n{\n\treturn GetFileName(m_persistent_id);\n}\n\nstd::wstring_view Account::GetMiiName() const\n{\n\tconst auto it = std::find(m_mii_name.cbegin(), m_mii_name.cend(), '\\0');\n\tif(it == m_mii_name.cend())\n\t\treturn { m_mii_name.data(), m_mii_name.size() - 1 };\n\n\tconst size_t count = std::distance(m_mii_name.cbegin(), it);\n\treturn { m_mii_name.data(),  count}; \n}\n\nstd::string_view Account::GetStorageValue(std::string_view key) const\n{\n\tconst auto it = m_storage.find(key.data());\n\tif (it == m_storage.cend())\n\t\treturn {};\n\n\treturn it->second;\n}\n\nvoid Account::SetMiiName(std::wstring_view name)\n{\n\tm_mii_name = {};\n\tstd::copy(name.data(), name.data() + std::min(name.size(), m_mii_name.size() - 1), m_mii_name.begin());\n}\n\nconst std::vector<Account>& Account::RefreshAccounts()\n{\n\tstd::vector<Account> result;\n\tconst fs::path path = ActiveSettings::GetMlcPath(\"usr/save/system/act\");\n\tif (fs::exists(path))\n\t{\n\t\tfor (const auto& it : fs::directory_iterator(path))\n\t\t{\n\t\t\tif (!fs::is_directory(it))\n\t\t\t\tcontinue;\n\n\t\t\tconst auto file_name = it.path().filename().string();\n\t\t\tif (file_name.size() != 8)\n\t\t\t\tcontinue;\n\n\t\t\tconst auto persistent_id = ConvertString<uint32>(file_name, 16);\n\t\t\tif (persistent_id < kMinPersistendId)\n\t\t\t\tcontinue;\n\n\t\t\tAccount account(persistent_id);\n\t\t\tconst auto error = account.Load();\n\t\t\tif (!error)\n\t\t\t\tresult.emplace_back(account);\n\t\t}\n\t}\n\t\n\t// we always force at least one account\n\tif (result.empty())\n\t{\n\t\tresult.emplace_back(kMinPersistendId, L\"default\");\n\t\tresult.begin()->Save();\n\t}\n\n\ts_account_list = result;\n\tUpdatePersisidDat();\n\treturn s_account_list;\n}\n\nvoid Account::UpdatePersisidDat()\n{\n\tconst auto max_id = std::max(kMinPersistendId, GetNextPersistentId() - 1);\n\tconst auto file = ActiveSettings::GetMlcPath(\"usr/save/system/act/persisid.dat\");\n\tstd::ofstream f(file);\n\tif(f.is_open())\n\t{\n\t\tf << \"PersistentIdManager_20120607\" << std::endl << \"PersistentIdHead=\" << std::hex << max_id << std::endl << std::endl;\n\t\tf.flush();\n\t\tf.close();\n\t}\n\telse\n\t\tcemuLog_log(LogType::Force, \"Unable to save persisid.dat\");\n}\n\nbool Account::HasFreeAccountSlots()\n{\n\treturn s_account_list.size() < 12;\n}\n\nconst std::vector<Account>& Account::GetAccounts()\n{\n\tif (!s_account_list.empty())\n\t\treturn s_account_list;\n\n\treturn RefreshAccounts();\n}\n\nconst Account& Account::GetAccount(uint32 persistent_id)\n{\n\tfor (const auto& account : GetAccounts())\n\t{\n\t\tif (account.GetPersistentId() == persistent_id)\n\t\t\treturn account;\n\t}\n\n\treturn *GetAccounts().begin();\n}\n\nconst Account& Account::GetCurrentAccount()\n{\n\treturn GetAccount(ActiveSettings::GetPersistentId());\n}\n\nuint32 Account::GetNextPersistentId()\n{\n\tuint32 result = kMinPersistendId;\n\tconst auto file = ActiveSettings::GetMlcPath(\"usr/save/system/act/persisid.dat\");\n\tif(fs::exists(file))\n\t{\n\t\tstd::ifstream f(file);\n\t\tif(f.is_open())\n\t\t{\n\t\t\tstd::string line;\n\t\t\twhile(std::getline(f, line))\n\t\t\t{\n\t\t\t\tif(boost::starts_with(line, \"PersistentIdHead=\"))\n\t\t\t\t{\n\t\t\t\t\tresult = ConvertString<uint32>(line.data() + sizeof(\"PersistentIdHead=\") - 1, 16);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// next id\n\t++result;\n\t\n\tconst auto it = std::max_element(s_account_list.cbegin(), s_account_list.cend(), [](const Account& acc1, const Account& acc2) {return acc1.GetPersistentId() < acc2.GetPersistentId(); });\n\tif (it != s_account_list.cend())\n\t\treturn std::max(result, it->GetPersistentId() + 1);\n\telse\n\t\treturn result;\n}\n\nfs::path Account::GetFileName(uint32 persistent_id)\n{\n\tif (persistent_id < kMinPersistendId)\n\t\tthrow std::invalid_argument(fmt::format(\"persistent id {:#x} is invalid\", persistent_id));\n\t\n\treturn ActiveSettings::GetMlcPath(fmt::format(\"usr/save/system/act/{:08x}/account.dat\", persistent_id));\n}\n\nOnlineValidator Account::ValidateOnlineFiles() const\n{\n\tOnlineValidator result{};\n\t\n\tconst auto otp = ActiveSettings::GetUserDataPath(\"otp.bin\");\n\tif (!fs::exists(otp))\n\t\tresult.otp = OnlineValidator::FileState::Missing;\n\telse if (fs::file_size(otp) != 1024)\n\t\tresult.otp = OnlineValidator::FileState::Corrupted;\n\telse\n\t\tresult.otp = OnlineValidator::FileState::Ok;\n\t\n\tconst auto seeprom = ActiveSettings::GetUserDataPath(\"seeprom.bin\");\n\tif (!fs::exists(seeprom))\n\t\tresult.seeprom = OnlineValidator::FileState::Missing;\n\telse if (fs::file_size(seeprom) != 512)\n\t\tresult.seeprom = OnlineValidator::FileState::Corrupted;\n\telse\n\t\tresult.seeprom = OnlineValidator::FileState::Ok;\n\n\tfor(const auto& v : iosuCrypt_getCertificateKeys())\n\t{\n\t\tconst auto p = ActiveSettings::GetMlcPath(L\"sys/title/0005001b/10054000/content/{}\", v);\n\t\tif (!fs::exists(p) || !fs::is_regular_file(p))\n\t\t\tresult.missing_files.emplace_back(p.generic_wstring());\n\t}\n\n\tfor (const auto& v : iosuCrypt_getCertificateNames())\n\t{\n\t\tconst auto p = ActiveSettings::GetMlcPath(L\"sys/title/0005001b/10054000/content/{}\", v);\n\t\tif (!fs::exists(p) || !fs::is_regular_file(p))\n\t\t\tresult.missing_files.emplace_back(p.generic_wstring());\n\t}\n\n\tresult.valid_account = IsValidOnlineAccount();\n\tresult.account_error = GetOnlineAccountError();\n\t\n\treturn result;\n}\n\nvoid Account::ParseFile(class FileStream* file)\n{\n\tstd::vector<uint8> buffer;\n\tbuffer.resize(file->GetSize());\n\tif( file->readData(buffer.data(), buffer.size()) != buffer.size())\n\t\tthrow std::system_error(AccountErrc::ParseError);\n\tfor (const auto& s : StringHelpers::StringLineIterator(buffer))\n\t{\n\t\tstd::string_view view = s;\n\t\tconst auto find = view.find('=');\n\t\tif (find == std::string_view::npos)\n\t\t\tcontinue;\n\n\t\tconst auto key = view.substr(0, find);\n\t\tconst auto value = view.substr(find + 1);\n\t\tif (key == \"PersistentId\")\n\t\t\tm_persistent_id = ConvertString<uint32>(value, 16);\n\t\telse if (key == \"TransferableIdBase\")\n\t\t\tm_transferable_id_base = ConvertString<uint64>(value, 16);\n\t\telse if (key == \"Uuid\")\n\t\t{\n\t\t\tif (value.size() != m_uuid.size() * 2) // = 32\n\t\t\t\tthrow std::system_error(AccountErrc::InvalidUuid);\n\t\t\t\n\t\t\tfor (size_t i = 0; i < m_uuid.size(); ++i)\n\t\t\t{\n\t\t\t\tm_uuid[i] = ConvertString<uint8>(value.substr(i * 2, 2), 16);\n\t\t\t}\n\t\t}\n\t\telse if (key == \"MiiData\")\n\t\t{\n\t\t\tif (value.size() != m_mii_data.size() * 2) // = 192\n\t\t\t\tthrow std::system_error(AccountErrc::InvalidMiiData);\n\t\t\t\n\t\t\tfor (size_t i = 0; i < m_mii_data.size(); ++i)\n\t\t\t{\n\t\t\t\tm_mii_data[i] = ConvertString<uint8>(value.substr(i * 2, 2), 16);\n\t\t\t}\n\t\t}\n\t\telse if (key == \"MiiName\")\n\t\t{\n\t\t\tif(value.size() != m_mii_name.size() * 4) // = 44\n\t\t\t\tthrow std::system_error(AccountErrc::InvalidMiiName);\n\t\t\t\n\t\t\tfor (size_t i = 0; i < m_mii_name.size(); ++i)\n\t\t\t{\n\t\t\t\tm_mii_name[i] = (wchar_t)ConvertString<uint16>(value.substr(i * 4, 4), 16);\n\t\t\t}\n\t\t}\n\t\telse if (key == \"AccountId\")\n\t\t\tm_account_id = value;\n\t\telse if (key == \"BirthYear\")\n\t\t\tm_birth_year = ConvertString<uint16>(value, 16);\n\t\telse if (key == \"BirthMonth\")\n\t\t\tm_birth_month = ConvertString<uint8>(value, 16);\n\t\telse if (key == \"BirthDay\")\n\t\t\tm_birth_day = ConvertString<uint8>(value, 16);\n\t\telse if (key == \"Gender\")\n\t\t\tm_gender = ConvertString<uint8>(value, 16);\n\t\telse if (key == \"EmailAddress\")\n\t\t\tm_email = value;\n\t\telse if (key == \"Country\")\n\t\t\tm_country = ConvertString<uint32>(value, 16);\n\t\telse if (key == \"SimpleAddressId\")\n\t\t\tm_simple_address_id = ConvertString<uint32>(value, 16);\n\t\telse if (key == \"TimeZoneId\")\n\t\t\tm_timezone_id = value;\n\t\telse if (key == \"UtcOffset\")\n\t\t\tm_utc_offset = ConvertString<uint64>(value, 16);\n\t\telse if (key == \"PrincipalId\")\n\t\t\tm_principal_id = ConvertString<uint32>(value, 16);\n\t\telse if (key == \"IsPasswordCacheEnabled\")\n\t\t\tm_password_cache_enabled = ConvertString<uint8>(value, 16);\n\t\telse if (key == \"AccountPasswordCache\")\n\t\t{\n\t\t\tfor (size_t i = 0; i < m_account_password_cache.size(); ++i)\n\t\t\t{\n\t\t\t\tm_account_password_cache[i] = ConvertString<uint8>(value.substr(i * 2, 2), 16);\n\t\t\t}\n\t\t}\n\t\telse // store anything else not needed for now\n\t\t\tm_storage[std::string(key)] = value;\n\t}\n}\n\n#include\"openssl/sha.h\"\n\nvoid makePWHash(uint8* input, sint32 length, uint32 magic, uint8* output)\n{\n\tuint8 buffer[64 + 8];\n\tif (length > (sizeof(buffer) - 8))\n\t{\n\t\tcemu_assert_debug(false);\n\t\tmemset(output, 0, 32);\n\t\treturn;\n\t}\n\tbuffer[4] = 0x02;\n\tbuffer[5] = 0x65;\n\tbuffer[6] = 0x43;\n\tbuffer[7] = 0x46;\n\tbuffer[0] = (magic >> 0) & 0xFF;\n\tbuffer[1] = (magic >> 8) & 0xFF;\n\tbuffer[2] = (magic >> 16) & 0xFF;\n\tbuffer[3] = (magic >> 24) & 0xFF;\n\tmemcpy(buffer + 8, input, length);\n\tuint8 md[SHA256_DIGEST_LENGTH];\n\tSHA256(buffer, 8 + length, md);\n\tmemcpy(output, md, SHA256_DIGEST_LENGTH);\n}\n\nvoid actPwTest()\n{\n\tuint8 pwHash[32];\n\n\tuint32 principalId = 0x12345678;\n\n\tuint32 pid = 0x12345678;\n\n\tmakePWHash((uint8*)\"pass123\", 7, pid, pwHash); // calculates AccountPasswordCache\n\n\tmakePWHash(pwHash, 32, pid, pwHash); // calculates AccountPasswordHash\n\n\tassert_dbg();\n}\n"
  },
  {
    "path": "src/Cafe/Account/Account.h",
    "content": "#pragma once\n\n#include \"AccountError.h\"\n\n#include <string>\n#include <string_view>\n#include <system_error>\n#include <vector>\n#include <optional>\n\nenum class OnlineAccountError\n{\n\tkNone,\n\tkNoAccountId,\n\tkNoPasswordCached,\n\tkPasswordCacheEmpty,\n\tkNoPrincipalId,\n};\n\nstruct OnlineValidator\n{\n\tenum class FileState\n\t{\n\t\tMissing,\n\t\tCorrupted,\n\t\tOk,\n\t};\n\n\tbool valid_account = false;\n\tFileState otp = FileState::Missing;\n\tFileState seeprom = FileState::Missing;\n\tstd::vector<std::wstring> missing_files;\n\tOnlineAccountError account_error = OnlineAccountError::kNone;\n\n\tbool IsValid() const\n\t{\n\t\treturn valid_account && otp == FileState::Ok && seeprom == FileState::Ok && missing_files.empty();\n\t}\n\n\texplicit operator bool() const\n\t{\n\t\treturn IsValid();\n\t}\n};\n\nclass Account\n{\npublic:\n\tstatic constexpr uint32 kMinPersistendId = 0x80000001;\n\t\n\t// create dummy account object from scratch\n\tAccount(uint32 persistent_id, std::wstring_view mii_name);\n\n\t// load an existing account\n\tAccount(std::wstring_view file_name);\n\n\tstd::error_code Load();\n\tstd::error_code Save();\n\n\t[[nodiscard]] std::wstring ToString() const { return fmt::format(L\"{} ({:x})\", GetMiiName(), GetPersistentId()); }\n\n\t// test if the account file has all fields set required for online play\n\t[[nodiscard]] bool IsValidOnlineAccount() const;\n\t[[nodiscard]] OnlineAccountError GetOnlineAccountError() const;\n\t[[nodiscard]] fs::path GetFileName() const;\n\n\t[[nodiscard]] uint32 GetPersistentId() const { return m_persistent_id; }\n\t[[nodiscard]] uint64 GetTransferableIdBase() const { return m_transferable_id_base; }\n\t[[nodiscard]] const std::array<uint8, 16>& GetUuid() const { return m_uuid; }\n\t[[nodiscard]] const std::array<uint8, 96>& GetMiiData() const { return m_mii_data; }\n\t[[nodiscard]] std::wstring_view GetMiiName() const; // only max 10 characters excluding '\\0'\n\t[[nodiscard]] std::string_view GetAccountId() const { return m_account_id; }\n\t[[nodiscard]] uint16 GetBirthYear() const { return m_birth_year; }\n\t[[nodiscard]] uint8 GetBirthMonth() const { return m_birth_month; }\n\t[[nodiscard]] uint8 GetBirthDay() const { return m_birth_day; }\n\t[[nodiscard]] uint8 GetGender() const { return m_gender; }\n\t[[nodiscard]] std::string_view GetEmail() const { return m_email; }\n\t[[nodiscard]] uint32 GetCountry() const { return m_country; }\n\t[[nodiscard]] uint32 GetSimpleAddressId() const { return m_simple_address_id; }\n\t[[nodiscard]] std::string_view GetTimeZoneId() const { return m_timezone_id; }\n\t[[nodiscard]] sint64 GetUtcOffset() const { return m_utc_offset; }\n\t[[nodiscard]] uint32 GetPrincipalId() const { return m_principal_id; }\n\t[[nodiscard]] bool IsPasswordCacheEnabled() const { return m_password_cache_enabled != 0; }\n\t[[nodiscard]] const std::array<uint8, 32>& GetAccountPasswordCache() const { return m_account_password_cache; }\n\n\t[[nodiscard]] std::string_view GetStorageValue(std::string_view key) const;\n\n\tvoid SetMiiName(std::wstring_view name);\n\tvoid SetBirthYear(uint16 birth_year) { m_birth_year = birth_year; }\n\tvoid SetBirthMonth(uint8 birth_month) { m_birth_month = birth_month; }\n\tvoid SetBirthDay(uint8 birth_day) { m_birth_day = birth_day; }\n\tvoid SetGender(uint8 gender) { m_gender = gender; }\n\tvoid SetEmail(std::string_view email) { m_email = email; }\n\tvoid SetCountry(uint32 country) { m_country = country; }\n\tvoid SetTimeZoneId(std::string_view timezone_id) { m_timezone_id = timezone_id; }\n\tvoid SetUtcOffset(sint64 utc_offset) { m_utc_offset = utc_offset; }\n\n\t// this will always return at least one account (default one)\n\tstatic const std::vector<Account>& RefreshAccounts();\n\tstatic void UpdatePersisidDat();\n\t\n\t[[nodiscard]] static bool HasFreeAccountSlots();\n\t[[nodiscard]] static const std::vector<Account>& GetAccounts();\n\t[[nodiscard]] static const Account& GetAccount(uint32 persistent_id);\n\t[[nodiscard]] static const Account& GetCurrentAccount();\n\t[[nodiscard]] static uint32 GetNextPersistentId();\n\t[[nodiscard]] static fs::path GetFileName(uint32 persistent_id);\n\t[[nodiscard]] OnlineValidator ValidateOnlineFiles() const;\nprivate:\n\tAccount(uint32 persistent_id);\n\n\t[[nodiscard]] std::error_code CheckValid() const;\n\tvoid ParseFile(class FileStream* file);\n\n\tuint32 m_persistent_id = 0;\n\tuint64 m_transferable_id_base = 0;\n\tstd::array<uint8, 16> m_uuid {};\n\tstd::array<uint8, 96> m_mii_data{};\n\tstd::array<wchar_t, 11> m_mii_name{};\n\tstd::string m_account_id;\n\n\tuint16 m_birth_year = 0;\n\tuint8 m_birth_month = 0;\n\tuint8 m_birth_day = 0;\n\tuint8 m_gender = 0;\n\n\tstd::string m_email;\n\tuint32 m_country = 0;\n\tuint32 m_simple_address_id = 0;\n\tstd::string m_timezone_id;\n\tsint64 m_utc_offset;\n\tuint32 m_principal_id = 0;\n\tuint8 m_password_cache_enabled = 0;\n\tstd::array<uint8, 32> m_account_password_cache{};\n\n\t// misc storage for unused local properties\n\tstd::unordered_map<std::string, std::string> m_storage;\n\n\tstatic std::vector<Account> s_account_list;\n};\n"
  },
  {
    "path": "src/Cafe/Account/AccountError.h",
    "content": "#pragma once\n\n#include <system_error>\n\nenum class AccountErrc\n{\n\tNoError = 0,\n\tParseError,\n\tInvalidPersistentId,\n\tInvalidUuid,\n\tInvalidMiiName,\n\tInvalidMiiData,\n};\nnamespace std\n{\n\ttemplate <> struct is_error_code_enum<AccountErrc> : true_type {};\n}\nnamespace detail\n{\n\t// Define a custom error code category derived from std::error_category\n\tclass AccountErrc_category : public std::error_category\n\t{\n\tpublic:\n\t\t// Return a short descriptive name for the category\n\t\t[[nodiscard]] const char* name() const noexcept override final { return \"AccountError\"; }\n\n\t\t// Return what each enum means in text\n\t\t[[nodiscard]] std::string message(int c) const override final\n\t\t{\n\t\t\tswitch (static_cast<AccountErrc>(c))\n\t\t\t{\n\t\t\tcase AccountErrc::NoError:\n\t\t\t\treturn \"no error\";\n\t\t\tcase AccountErrc::InvalidPersistentId:\n\t\t\t\treturn \"invalid PersistentId\";\n\t\t\tcase AccountErrc::InvalidMiiName:\n\t\t\t\treturn \"invalid MiiName\";\n\t\t\tdefault:\n\t\t\t\treturn \"unknown error\";\n\t\t\t}\n\t\t}\n\n\t\t[[nodiscard]] std::error_condition default_error_condition(int c) const noexcept override final\n\t\t{\n\t\t\tswitch (static_cast<AccountErrc>(c))\n\t\t\t{\n\t\t\tcase AccountErrc::InvalidPersistentId:\n\t\t\t\treturn make_error_condition(std::errc::invalid_argument);\n\t\t\tdefault:\n\t\t\t\treturn std::error_condition(c, *this);\n\t\t\t}\n\t\t}\n\t};\n}\n\ninline std::error_code make_error_code(AccountErrc e)\n{\n\tstatic detail::AccountErrc_category c;\n\treturn { static_cast<int>(e), c };\n}"
  },
  {
    "path": "src/Cafe/CMakeLists.txt",
    "content": "add_library(CemuCafe\n  Account/Account.cpp\n  Account/AccountError.h\n  Account/Account.h\n  CafeSystem.cpp\n  CafeSystem.h\n  Filesystem/fsc.cpp\n  Filesystem/fscDeviceHostFS.cpp\n  Filesystem/fscDeviceHostFS.h\n  Filesystem/fscDeviceRedirect.cpp\n  Filesystem/fscDeviceWua.cpp\n  Filesystem/fscDeviceWud.cpp\n  Filesystem/fscDeviceWuhb.cpp\n  Filesystem/fsc.h\n  Filesystem/FST/FST.cpp\n  Filesystem/FST/FST.h\n  Filesystem/FST/fstUtil.h\n  Filesystem/FST/KeyCache.cpp\n  Filesystem/FST/KeyCache.h\n  Filesystem/WUD/wud.cpp\n  Filesystem/WUD/wud.h\n  Filesystem/WUHB/RomFSStructs.h\n  Filesystem/WUHB/WUHBReader.cpp\n  Filesystem/WUHB/WUHBReader.h\n  GamePatch.cpp\n  GamePatch.h\n  GameProfile/GameProfile.cpp\n  GameProfile/GameProfile.h\n  GraphicPack/GraphicPack2.cpp\n  GraphicPack/GraphicPack2.h\n  GraphicPack/GraphicPack2PatchesApply.cpp\n  GraphicPack/GraphicPack2Patches.cpp\n  GraphicPack/GraphicPack2Patches.h\n  GraphicPack/GraphicPack2PatchesParser.cpp\n  GraphicPack/GraphicPackError.h\n  HW/ACR/ACR.cpp\n  HW/AI/AI.cpp\n  HW/AI/AI.h\n  HW/Common/HwReg.h\n  HW/Espresso/Const.h\n  HW/Espresso/Debugger/Debugger.cpp\n  HW/Espresso/Debugger/Debugger.h\n  HW/Espresso/Debugger/DebugSymbolStorage.cpp\n  HW/Espresso/Debugger/DebugSymbolStorage.h\n  HW/Espresso/Debugger/GDBStub.h\n  HW/Espresso/Debugger/GDBStub.cpp\n  HW/Espresso/Debugger/GDBBreakpoints.cpp\n  HW/Espresso/Debugger/GDBBreakpoints.h\n  HW/Espresso/EspressoISA.h\n  HW/Espresso/Interpreter/PPCInterpreterALU.hpp\n  HW/Espresso/Interpreter/PPCInterpreterFPU.cpp\n  HW/Espresso/Interpreter/PPCInterpreterHelper.h\n  HW/Espresso/Interpreter/PPCInterpreterHLE.cpp\n  HW/Espresso/Interpreter/PPCInterpreterImpl.cpp\n  HW/Espresso/Interpreter/PPCInterpreterInternal.h\n  HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp\n  HW/Espresso/Interpreter/PPCInterpreterMain.cpp\n  HW/Espresso/Interpreter/PPCInterpreterOPC.cpp\n  HW/Espresso/Interpreter/PPCInterpreterOPC.hpp\n  HW/Espresso/Interpreter/PPCInterpreterPS.cpp\n  HW/Espresso/Interpreter/PPCInterpreterSPR.hpp\n  HW/Espresso/PPCCallback.h\n  HW/Espresso/PPCScheduler.cpp\n  HW/Espresso/PPCSchedulerLLE.cpp\n  HW/Espresso/PPCState.h\n  HW/Espresso/PPCTimer.cpp\n  HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h\n  HW/Espresso/Recompiler/PPCRecompiler.cpp\n  HW/Espresso/Recompiler/PPCRecompiler.h\n  HW/Espresso/Recompiler/IML/IML.h\n  HW/Espresso/Recompiler/IML/IMLSegment.cpp\n  HW/Espresso/Recompiler/IML/IMLSegment.h\n  HW/Espresso/Recompiler/IML/IMLInstruction.cpp\n  HW/Espresso/Recompiler/IML/IMLInstruction.h\n  HW/Espresso/Recompiler/IML/IMLDebug.cpp\n  HW/Espresso/Recompiler/IML/IMLAnalyzer.cpp\n  HW/Espresso/Recompiler/IML/IMLOptimizer.cpp\n  HW/Espresso/Recompiler/IML/IMLRegisterAllocator.cpp\n  HW/Espresso/Recompiler/IML/IMLRegisterAllocator.h\n  HW/Espresso/Recompiler/IML/IMLRegisterAllocatorRanges.cpp\n  HW/Espresso/Recompiler/IML/IMLRegisterAllocatorRanges.h\n  HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp\n  HW/Espresso/Recompiler/PPCRecompilerImlGenFPU.cpp\n  HW/Espresso/Recompiler/PPCRecompilerIml.h\n  HW/Espresso/Recompiler/PPCRecompilerIntermediate.cpp\n  HW/Espresso/Recompiler/BackendX64/BackendX64AVX.cpp\n  HW/Espresso/Recompiler/BackendX64/BackendX64BMI.cpp\n  HW/Espresso/Recompiler/BackendX64/BackendX64.cpp\n  HW/Espresso/Recompiler/BackendX64/BackendX64FPU.cpp\n  HW/Espresso/Recompiler/BackendX64/BackendX64Gen.cpp\n  HW/Espresso/Recompiler/BackendX64/BackendX64GenFPU.cpp\n  HW/Espresso/Recompiler/BackendX64/BackendX64.h\n  HW/Espresso/Recompiler/BackendX64/X64Emit.hpp\n  HW/Espresso/Recompiler/BackendX64/x86Emitter.h\n  HW/Latte/Common/RegisterSerializer.cpp\n  HW/Latte/Common/RegisterSerializer.h\n  HW/Latte/Common/ShaderSerializer.cpp\n  HW/Latte/Common/ShaderSerializer.h\n  HW/Latte/Core/FetchShader.cpp\n  HW/Latte/Core/FetchShader.h\n  HW/Latte/Core/LatteAsyncCommands.cpp\n  HW/Latte/Core/LatteAsyncCommands.h\n  HW/Latte/Core/LatteBufferCache.cpp\n  HW/Latte/Core/LatteBufferCache.h\n  HW/Latte/Core/LatteBufferData.cpp\n  HW/Latte/Core/LatteCachedFBO.h\n  HW/Latte/Core/LatteCommandProcessor.cpp\n  HW/Latte/Core/LatteConst.h\n  HW/Latte/Core/LatteDefaultShaders.cpp\n  HW/Latte/Core/LatteDefaultShaders.h\n  HW/Latte/Core/LatteDraw.h\n  HW/Latte/Core/LatteGSCopyShaderParser.cpp\n  HW/Latte/Core/Latte.h\n  HW/Latte/Core/LatteIndices.cpp\n  HW/Latte/Core/LatteIndices.h\n  HW/Latte/Core/LatteOverlay.cpp\n  HW/Latte/Core/LatteOverlay.h\n  HW/Latte/Core/LattePerformanceMonitor.cpp\n  HW/Latte/Core/LattePerformanceMonitor.h\n  HW/Latte/Core/LattePM4.h\n  HW/Latte/Core/LatteQuery.cpp\n  HW/Latte/Core/LatteQueryObject.h\n  HW/Latte/Core/LatteRenderTarget.cpp\n  HW/Latte/Core/LatteRingBuffer.cpp\n  HW/Latte/Core/LatteRingBuffer.h\n  HW/Latte/Core/LatteShaderAssembly.h\n  HW/Latte/Core/LatteShaderCache.cpp\n  HW/Latte/Core/LatteShaderCache.h\n  HW/Latte/Core/LatteShader.cpp\n  HW/Latte/Core/LatteShaderGL.cpp\n  HW/Latte/Core/LatteShader.h\n  HW/Latte/Core/LatteSoftware.cpp\n  HW/Latte/Core/LatteSoftware.h\n  HW/Latte/Core/LatteStreamoutGPU.cpp\n  HW/Latte/Core/LatteSurfaceCopy.cpp\n  HW/Latte/Core/LatteTextureCache.cpp\n  HW/Latte/Core/LatteTexture.cpp\n  HW/Latte/Core/LatteTexture.h\n  HW/Latte/Core/LatteTextureLegacy.cpp\n  HW/Latte/Core/LatteTextureLoader.cpp\n  HW/Latte/Core/LatteTextureLoader.h\n  HW/Latte/Core/LatteTextureReadback.cpp\n  HW/Latte/Core/LatteTextureReadbackInfo.h\n  HW/Latte/Core/LatteTextureView.cpp\n  HW/Latte/Core/LatteTextureView.h\n  HW/Latte/Core/LatteThread.cpp\n  HW/Latte/Core/LatteTiming.cpp\n  HW/Latte/Core/LatteTiming.h\n  HW/Latte/ISA/LatteInstructions.h\n  HW/Latte/ISA/LatteReg.h\n  HW/Latte/ISA/RegDefines.h\n  HW/Latte/LatteAddrLib/AddrLibFastDecode.h\n  HW/Latte/LatteAddrLib/LatteAddrLib_Coord.cpp\n  HW/Latte/LatteAddrLib/LatteAddrLib.cpp\n  HW/Latte/LatteAddrLib/LatteAddrLib.h\n  HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp\n  HW/Latte/LegacyShaderDecompiler/LatteDecompiler.cpp\n  HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLAttrDecoder.cpp\n  HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp\n  HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLHeader.hpp\n  HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\n  HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h\n  HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h\n  HW/Latte/LegacyShaderDecompiler/LatteDecompilerRegisterDataTypeTracker.cpp\n  HW/Latte/Renderer/OpenGL/CachedFBOGL.h\n  HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp\n  HW/Latte/Renderer/OpenGL/LatteTextureGL.h\n  HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp\n  HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h\n  HW/Latte/Renderer/OpenGL/OpenGLQuery.cpp\n  HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp\n  HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp\n  HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\n  HW/Latte/Renderer/OpenGL/OpenGLRendererStreamout.cpp\n  HW/Latte/Renderer/OpenGL/OpenGLRendererUniformData.cpp\n  HW/Latte/Renderer/OpenGL/OpenGLSurfaceCopy.cpp\n  HW/Latte/Renderer/OpenGL/OpenGLTextureReadback.h\n  HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp\n  HW/Latte/Renderer/OpenGL/RendererShaderGL.h\n  HW/Latte/Renderer/OpenGL/TextureReadbackGL.cpp\n  HW/Latte/Renderer/Renderer.cpp\n  HW/Latte/Renderer/Renderer.h\n  HW/Latte/Renderer/RendererOuputShader.cpp\n  HW/Latte/Renderer/RendererOuputShader.h\n  HW/Latte/Renderer/RendererShader.cpp\n  HW/Latte/Renderer/RendererShader.h\n  HW/Latte/Renderer/Vulkan/CachedFBOVk.cpp\n  HW/Latte/Renderer/Vulkan/CachedFBOVk.h\n  HW/Latte/Renderer/Vulkan/CocoaSurface.h\n  HW/Latte/Renderer/Vulkan/LatteTextureViewVk.cpp\n  HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h\n  HW/Latte/Renderer/Vulkan/LatteTextureVk.cpp\n  HW/Latte/Renderer/Vulkan/LatteTextureVk.h\n  HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp\n  HW/Latte/Renderer/Vulkan/RendererShaderVk.h\n  HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp\n  HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h\n  HW/Latte/Renderer/Vulkan/TextureReadbackVk.cpp\n  HW/Latte/Renderer/Vulkan/VKRBase.h\n  HW/Latte/Renderer/Vulkan/VKRMemoryManager.cpp\n  HW/Latte/Renderer/Vulkan/VKRMemoryManager.h\n  HW/Latte/Renderer/Vulkan/VKRPipelineInfo.cpp\n  HW/Latte/Renderer/Vulkan/VsyncDriver.cpp\n  HW/Latte/Renderer/Vulkan/VsyncDriver.h\n  HW/Latte/Renderer/Vulkan/VulkanAPI.cpp\n  HW/Latte/Renderer/Vulkan/VulkanAPI.h\n  HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp\n  HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h\n  HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp\n  HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h\n  HW/Latte/Renderer/Vulkan/VulkanQuery.cpp\n  HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp\n  HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp\n  HW/Latte/Renderer/Vulkan/VulkanRenderer.h\n  HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp\n  HW/Latte/Renderer/Vulkan/VulkanTextureReadback.h\n  HW/Latte/ShaderInfo/ShaderDescription.cpp\n  HW/Latte/ShaderInfo/ShaderInfo.h\n  HW/Latte/ShaderInfo/ShaderInstanceInfo.cpp\n  HW/Latte/Transcompiler/LatteTC.cpp\n  HW/Latte/Transcompiler/LatteTCGenIR.cpp\n  HW/Latte/Transcompiler/LatteTC.h\n  HW/MMU/MMU.cpp\n  HW/MMU/MMU.h\n  HW/SI/SI.cpp\n  HW/SI/si.h\n  HW/VI/VI.cpp\n  IOSU/ccr_nfc/iosu_ccr_nfc.cpp\n  IOSU/ccr_nfc/iosu_ccr_nfc.h\n  IOSU/fsa/fsa_types.h\n  IOSU/fsa/iosu_fsa.cpp\n  IOSU/fsa/iosu_fsa.h\n  IOSU/iosu_ipc_common.h\n  IOSU/iosu_types_common.h\n  IOSU/kernel/iosu_kernel.cpp\n  IOSU/kernel/iosu_kernel.h\n  IOSU/legacy/iosu_acp.cpp\n  IOSU/legacy/iosu_acp.h\n  IOSU/legacy/iosu_act.cpp\n  IOSU/legacy/iosu_act.h\n  IOSU/legacy/iosu_crypto.cpp\n  IOSU/legacy/iosu_crypto.h\n  IOSU/legacy/iosu_fpd.cpp\n  IOSU/legacy/iosu_fpd.h\n  IOSU/legacy/iosu_ioctl.cpp\n  IOSU/legacy/iosu_ioctl.h\n  IOSU/legacy/iosu_mcp.cpp\n  IOSU/legacy/iosu_mcp.h\n  IOSU/legacy/iosu_nim.cpp\n  IOSU/legacy/iosu_nim.h\n  IOSU/nn/iosu_nn_service.cpp\n  IOSU/nn/iosu_nn_service.h\n  IOSU/nn/boss/boss_common.cpp\n  IOSU/nn/boss/boss_common.h\n  IOSU/nn/boss/boss_service.cpp\n  IOSU/nn/boss/boss_service.h\n  IOSU/PDM/iosu_pdm.cpp\n  IOSU/PDM/iosu_pdm.h\n  IOSU/ODM/iosu_odm.cpp\n  IOSU/ODM/iosu_odm.h\n  OS/common/OSCommon.cpp\n  OS/common/OSCommon.h\n  OS/common/OSUtil.h\n  OS/common/PPCConcurrentQueue.h\n  OS/libs/avm/avm.cpp\n  OS/libs/avm/avm.h\n  OS/libs/camera/camera.cpp\n  OS/libs/camera/camera.h\n  OS/libs/coreinit/coreinit_Alarm.cpp\n  OS/libs/coreinit/coreinit_Alarm.h\n  OS/libs/coreinit/coreinit_Atomic.cpp\n  OS/libs/coreinit/coreinit_Atomic.h\n  OS/libs/coreinit/coreinit_BSP.cpp\n  OS/libs/coreinit/coreinit_BSP.h\n  OS/libs/coreinit/coreinit_Callbacks.cpp\n  OS/libs/coreinit/coreinit_CodeGen.cpp\n  OS/libs/coreinit/coreinit_CodeGen.h\n  OS/libs/coreinit/coreinit_Coroutine.cpp\n  OS/libs/coreinit/coreinit_Coroutine.h\n  OS/libs/coreinit/coreinit.cpp\n  OS/libs/coreinit/coreinit_DynLoad.cpp\n  OS/libs/coreinit/coreinit_DynLoad.h\n  OS/libs/coreinit/coreinit_FG.cpp\n  OS/libs/coreinit/coreinit_FG.h\n  OS/libs/coreinit/coreinit_FS.cpp\n  OS/libs/coreinit/coreinit_FS.h\n  OS/libs/coreinit/coreinit_GHS.cpp\n  OS/libs/coreinit/coreinit_GHS.h\n  OS/libs/coreinit/coreinit.h\n  OS/libs/coreinit/coreinit_HWInterface.cpp\n  OS/libs/coreinit/coreinit_HWInterface.h\n  OS/libs/coreinit/coreinit_IM.cpp\n  OS/libs/coreinit/coreinit_IM.h\n  OS/libs/coreinit/coreinit_Init.cpp\n  OS/libs/coreinit/coreinit_IOS.cpp\n  OS/libs/coreinit/coreinit_IOS.h\n  OS/libs/coreinit/coreinit_IPCBuf.cpp\n  OS/libs/coreinit/coreinit_IPCBuf.h\n  OS/libs/coreinit/coreinit_IPC.cpp\n  OS/libs/coreinit/coreinit_IPC.h\n  OS/libs/coreinit/coreinit_LockedCache.cpp\n  OS/libs/coreinit/coreinit_LockedCache.h\n  OS/libs/coreinit/coreinit_MCP.cpp\n  OS/libs/coreinit/coreinit_MCP.h\n  OS/libs/coreinit/coreinit_MEM_BlockHeap.cpp\n  OS/libs/coreinit/coreinit_MEM_BlockHeap.h\n  OS/libs/coreinit/coreinit_MEM.cpp\n  OS/libs/coreinit/coreinit_MEM_ExpHeap.cpp\n  OS/libs/coreinit/coreinit_MEM_ExpHeap.h\n  OS/libs/coreinit/coreinit_MEM_FrmHeap.cpp\n  OS/libs/coreinit/coreinit_MEM_FrmHeap.h\n  OS/libs/coreinit/coreinit_MEM.h\n  OS/libs/coreinit/coreinit_Memory.cpp\n  OS/libs/coreinit/coreinit_Memory.h\n  OS/libs/coreinit/coreinit_MemoryMapping.cpp\n  OS/libs/coreinit/coreinit_MemoryMapping.h\n  OS/libs/coreinit/coreinit_MEM_UnitHeap.cpp\n  OS/libs/coreinit/coreinit_MEM_UnitHeap.h\n  OS/libs/coreinit/coreinit_MessageQueue.cpp\n  OS/libs/coreinit/coreinit_MessageQueue.h\n  OS/libs/coreinit/coreinit_Misc.cpp\n  OS/libs/coreinit/coreinit_Misc.h\n  OS/libs/coreinit/coreinit_MPQueue.cpp\n  OS/libs/coreinit/coreinit_MPQueue.h\n  OS/libs/coreinit/coreinit_OSScreen.cpp\n  OS/libs/coreinit/coreinit_OSScreen_font.h\n  OS/libs/coreinit/coreinit_OSScreen.h\n  OS/libs/coreinit/coreinit_OverlayArena.cpp\n  OS/libs/coreinit/coreinit_OverlayArena.h\n  OS/libs/coreinit/coreinit_Scheduler.cpp\n  OS/libs/coreinit/coreinit_Scheduler.h\n  OS/libs/coreinit/coreinit_Spinlock.cpp\n  OS/libs/coreinit/coreinit_Spinlock.h\n  OS/libs/coreinit/coreinit_Synchronization.cpp\n  OS/libs/coreinit/coreinit_SysHeap.cpp\n  OS/libs/coreinit/coreinit_SysHeap.h\n  OS/libs/coreinit/coreinit_SystemInfo.cpp\n  OS/libs/coreinit/coreinit_SystemInfo.h\n  OS/libs/coreinit/coreinit_Thread.cpp\n  OS/libs/coreinit/coreinit_Thread.h\n  OS/libs/coreinit/coreinit_ThreadQueue.cpp\n  OS/libs/coreinit/coreinit_Time.cpp\n  OS/libs/coreinit/coreinit_Time.h\n  OS/libs/dmae/dmae.cpp\n  OS/libs/dmae/dmae.h\n  OS/libs/drmapp/drmapp.cpp\n  OS/libs/drmapp/drmapp.h\n  OS/libs/erreula/erreula.cpp\n  OS/libs/erreula/erreula.h\n  OS/libs/gx2/GX2_AddrTest.cpp\n  OS/libs/gx2/GX2_Blit.cpp\n  OS/libs/gx2/GX2_Blit.h\n  OS/libs/gx2/GX2_Command.cpp\n  OS/libs/gx2/GX2_Command.h\n  OS/libs/gx2/GX2_ContextState.cpp\n  OS/libs/gx2/GX2.cpp\n  OS/libs/gx2/GX2_Draw.cpp\n  OS/libs/gx2/GX2_Draw.h\n  OS/libs/gx2/GX2_Event.cpp\n  OS/libs/gx2/GX2_Event.h\n  OS/libs/gx2/GX2.h\n  OS/libs/gx2/GX2_Memory.cpp\n  OS/libs/gx2/GX2_Memory.h\n  OS/libs/gx2/GX2_Misc.cpp\n  OS/libs/gx2/GX2_Misc.h\n  OS/libs/gx2/GX2_Query.cpp\n  OS/libs/gx2/GX2_Query.h\n  OS/libs/gx2/GX2_RenderTarget.cpp\n  OS/libs/gx2/GX2_Resource.cpp\n  OS/libs/gx2/GX2_Resource.h\n  OS/libs/gx2/GX2_Shader.cpp\n  OS/libs/gx2/GX2_Shader.h\n  OS/libs/gx2/GX2_shader_legacy.cpp\n  OS/libs/gx2/GX2_State.cpp\n  OS/libs/gx2/GX2_State.h\n  OS/libs/gx2/GX2_Streamout.cpp\n  OS/libs/gx2/GX2_Streamout.h\n  OS/libs/gx2/GX2_Surface_Copy.cpp\n  OS/libs/gx2/GX2_Surface_Copy.h\n  OS/libs/gx2/GX2_Surface.cpp\n  OS/libs/gx2/GX2_Surface.h\n  OS/libs/gx2/GX2_Texture.cpp\n  OS/libs/gx2/GX2_Texture.h\n  OS/libs/gx2/GX2_TilingAperture.cpp\n  OS/libs/h264_avc/H264Dec.cpp\n  OS/libs/h264_avc/H264DecBackendAVC.cpp\n  OS/libs/h264_avc/h264dec.h\n  OS/libs/h264_avc/H264DecInternal.h\n  OS/libs/h264_avc/parser\n  OS/libs/h264_avc/parser/H264Parser.cpp\n  OS/libs/h264_avc/parser/H264Parser.h\n  OS/libs/mic/mic.cpp\n  OS/libs/mic/mic.h\n  OS/libs/nfc/ndef.cpp\n  OS/libs/nfc/ndef.h\n  OS/libs/nfc/nfc.cpp\n  OS/libs/nfc/nfc.h\n  OS/libs/nfc/stream.cpp\n  OS/libs/nfc/stream.h\n  OS/libs/nfc/TagV0.cpp\n  OS/libs/nfc/TagV0.h\n  OS/libs/nfc/TLV.cpp\n  OS/libs/nfc/TLV.h\n  OS/libs/nlibcurl/nlibcurl.cpp\n  OS/libs/nlibcurl/nlibcurlDebug.hpp\n  OS/libs/nlibcurl/nlibcurl.h\n  OS/libs/nlibnss/nlibnss.cpp\n  OS/libs/nlibnss/nlibnss.h\n  OS/libs/nn_ac/nn_ac.cpp\n  OS/libs/nn_ac/nn_ac.h\n  OS/libs/nn_acp/nn_acp.cpp\n  OS/libs/nn_acp/nn_acp.h\n  OS/libs/nn_act/nn_act.cpp\n  OS/libs/nn_act/nn_act.h\n  OS/libs/nn_aoc/nn_aoc.cpp\n  OS/libs/nn_aoc/nn_aoc.h\n  OS/libs/nn_boss/nn_boss.cpp\n  OS/libs/nn_boss/nn_boss.h\n  OS/libs/nn_ccr/nn_ccr.cpp\n  OS/libs/nn_ccr/nn_ccr.h\n  OS/libs/nn_cmpt/nn_cmpt.cpp\n  OS/libs/nn_cmpt/nn_cmpt.h\n  OS/libs/nn_client_service.h\n  OS/libs/nn_common.h\n  OS/libs/nn_ec/nn_ec.cpp\n  OS/libs/nn_ec/nn_ec.h\n  OS/libs/nn_fp/nn_fp.cpp\n  OS/libs/nn_fp/nn_fp.h\n  OS/libs/nn_idbe/nn_idbe.cpp\n  OS/libs/nn_idbe/nn_idbe.h\n  OS/libs/nn_ndm/nn_ndm.cpp\n  OS/libs/nn_ndm/nn_ndm.h\n  OS/libs/nn_spm/nn_spm.cpp\n  OS/libs/nn_spm/nn_spm.h\n  OS/libs/nn_sl/nn_sl.cpp\n  OS/libs/nn_sl/nn_sl.h\n  OS/libs/nn_nfp/AmiiboCrypto.h\n  OS/libs/nn_nfp/nn_nfp.cpp\n  OS/libs/nn_nfp/nn_nfp.h\n  OS/libs/nn_nim/nn_nim.cpp\n  OS/libs/nn_nim/nn_nim.h\n  OS/libs/nn_olv/nn_olv.cpp\n  OS/libs/nn_olv/nn_olv.h\n  OS/libs/nn_olv/nn_olv_Common.cpp\n  OS/libs/nn_olv/nn_olv_Common.h\n  OS/libs/nn_olv/nn_olv_InitializeTypes.cpp\n  OS/libs/nn_olv/nn_olv_InitializeTypes.h\n  OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp\n  OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.h\n  OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp\n  OS/libs/nn_olv/nn_olv_UploadCommunityTypes.h\n  OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp\n  OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.h\n  OS/libs/nn_olv/nn_olv_PostTypes.cpp\n  OS/libs/nn_olv/nn_olv_PostTypes.h\n  OS/libs/nn_olv/nn_olv_OfflineDB.cpp\n  OS/libs/nn_olv/nn_olv_OfflineDB.h\n  OS/libs/nn_pdm/nn_pdm.cpp\n  OS/libs/nn_pdm/nn_pdm.h\n  OS/libs/nn_save/nn_save.cpp\n  OS/libs/nn_save/nn_save.h\n  OS/libs/nn_temp/nn_temp.cpp\n  OS/libs/nn_temp/nn_temp.h\n  OS/libs/nn_uds/nn_uds.cpp\n  OS/libs/nn_uds/nn_uds.h\n  OS/libs/nsyshid/nsyshid.cpp\n  OS/libs/nsyshid/nsyshid.h\n  OS/libs/nsyshid/Backend.h\n  OS/libs/nsyshid/AttachDefaultBackends.cpp\n  OS/libs/nsyshid/Whitelist.cpp\n  OS/libs/nsyshid/Whitelist.h\n  OS/libs/nsyshid/BackendEmulated.cpp\n  OS/libs/nsyshid/BackendEmulated.h\n  OS/libs/nsyshid/BackendLibusb.cpp\n  OS/libs/nsyshid/BackendLibusb.h\n  OS/libs/nsyshid/Dimensions.cpp\n  OS/libs/nsyshid/Dimensions.h\n  OS/libs/nsyshid/Infinity.cpp\n  OS/libs/nsyshid/Infinity.h\n  OS/libs/nsyshid/Skylander.cpp\n  OS/libs/nsyshid/Skylander.h\n  OS/libs/nsyshid/SkylanderXbox360.cpp\n  OS/libs/nsyshid/SkylanderXbox360.h\n  OS/libs/nsyshid/g721/g721.cpp\n  OS/libs/nsyshid/g721/g721.h\n  OS/libs/nsyskbd/nsyskbd.cpp\n  OS/libs/nsyskbd/nsyskbd.h\n  OS/libs/nsysnet/nsysnet.cpp\n  OS/libs/nsysnet/nsysnet.h\n  OS/libs/ntag/ntag.cpp\n  OS/libs/ntag/ntag.h\n  OS/libs/padscore/padscore.cpp\n  OS/libs/padscore/padscore.h\n  OS/libs/proc_ui/proc_ui.cpp\n  OS/libs/proc_ui/proc_ui.h\n  OS/libs/snd_core/ax_aux.cpp\n  OS/libs/snd_core/ax_exports.cpp\n  OS/libs/snd_core/ax.h\n  OS/libs/snd_core/ax_internal.h\n  OS/libs/snd_core/ax_ist.cpp\n  OS/libs/snd_core/ax_mix.cpp\n  OS/libs/snd_core/ax_multivoice.cpp\n  OS/libs/snd_core/ax_out.cpp\n  OS/libs/snd_core/ax_voice.cpp\n  OS/libs/snd_user/snd_user.cpp\n  OS/libs/snd_user/snd_user.h\n  OS/libs/swkbd/swkbd.cpp\n  OS/libs/swkbd/swkbd.h\n  OS/libs/sysapp/sysapp.cpp\n  OS/libs/sysapp/sysapp.h\n  OS/libs/TCL/TCL.cpp\n  OS/libs/TCL/TCL.h\n  OS/libs/vpad/vpad.cpp\n  OS/libs/vpad/vpad.h\n  OS/libs/zlib125\n  OS/libs/zlib125/zlib125.cpp\n  OS/libs/zlib125/zlib125.h\n  OS/RPL/COSModule.cpp\n  OS/RPL/COSModule.h\n  OS/RPL/elf.cpp\n  OS/RPL/rpl.cpp\n  OS/RPL/rpl_debug_symbols.cpp\n  OS/RPL/rpl_debug_symbols.h\n  OS/RPL/rpl.h\n  OS/RPL/rpl_structs.h\n  OS/RPL/rpl_symbol_storage.cpp\n  OS/RPL/rpl_symbol_storage.h\n  TitleList/GameInfo.h\n  TitleList/ParsedMetaXml.h\n  TitleList/SaveInfo.cpp\n  TitleList/SaveInfo.h\n  TitleList/SaveList.cpp\n  TitleList/SaveList.h\n  TitleList/TitleId.h\n  TitleList/TitleInfo.cpp\n  TitleList/TitleInfo.h\n  TitleList/TitleList.cpp\n  TitleList/TitleList.h\n)\n\nif(APPLE)\n\ttarget_sources(CemuCafe PRIVATE\n\t    HW/Latte/Renderer/Vulkan/CocoaSurface.mm\n\t    HW/Latte/Renderer/MetalView.mm\n\t    HW/Latte/Renderer/MetalView.h\n\t)\nendif()\n\nif(ENABLE_METAL)\n    target_sources(CemuCafe PRIVATE\n        HW/Latte/Renderer/Metal/CachedFBOMtl.cpp\n        HW/Latte/Renderer/Metal/CachedFBOMtl.h\n        HW/Latte/Renderer/Metal/LatteTextureMtl.cpp\n        HW/Latte/Renderer/Metal/LatteTextureMtl.h\n        HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.cpp\n        HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h\n        HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp\n        HW/Latte/Renderer/Metal/LatteTextureViewMtl.h\n        HW/Latte/Renderer/Metal/LatteToMtl.cpp\n        HW/Latte/Renderer/Metal/LatteToMtl.h\n        HW/Latte/Renderer/Metal/MetalAttachmentsInfo.cpp\n        HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h\n        HW/Latte/Renderer/Metal/MetalBufferAllocator.cpp\n        HW/Latte/Renderer/Metal/MetalBufferAllocator.h\n        HW/Latte/Renderer/Metal/MetalCommon.h\n        HW/Latte/Renderer/Metal/MetalCppImpl.cpp\n        HW/Latte/Renderer/Metal/MetalDepthStencilCache.cpp\n        HW/Latte/Renderer/Metal/MetalDepthStencilCache.h\n        HW/Latte/Renderer/Metal/MetalLayer.h\n        HW/Latte/Renderer/Metal/MetalLayer.mm\n        HW/Latte/Renderer/Metal/MetalLayerHandle.cpp\n        HW/Latte/Renderer/Metal/MetalLayerHandle.h\n        HW/Latte/Renderer/Metal/MetalMemoryManager.cpp\n        HW/Latte/Renderer/Metal/MetalMemoryManager.h\n        HW/Latte/Renderer/Metal/MetalOutputShaderCache.cpp\n        HW/Latte/Renderer/Metal/MetalOutputShaderCache.h\n        HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h\n        HW/Latte/Renderer/Metal/MetalPipelineCache.cpp\n        HW/Latte/Renderer/Metal/MetalPipelineCache.h\n        HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp\n        HW/Latte/Renderer/Metal/MetalPipelineCompiler.h\n        HW/Latte/Renderer/Metal/MetalQuery.cpp\n        HW/Latte/Renderer/Metal/MetalQuery.h\n        HW/Latte/Renderer/Metal/MetalRenderer.cpp\n        HW/Latte/Renderer/Metal/MetalRenderer.h\n        HW/Latte/Renderer/Metal/MetalSamplerCache.cpp\n        HW/Latte/Renderer/Metal/MetalSamplerCache.h\n        HW/Latte/Renderer/Metal/MetalVoidVertexPipeline.cpp\n        HW/Latte/Renderer/Metal/MetalVoidVertexPipeline.h\n        HW/Latte/Renderer/Metal/RendererShaderMtl.cpp\n        HW/Latte/Renderer/Metal/RendererShaderMtl.h\n        HW/Latte/Renderer/Metal/UtilityShaderSource.h\n    )\n\n    target_sources(CemuCafe PRIVATE\n        HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLAttrDecoder.cpp\n        HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSL.cpp\n        HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp\n    )\n\n    target_link_libraries(CemuCafe PRIVATE\n        \"-framework Metal\"\n        \"-framework QuartzCore\"\n    )\nendif()\n\nif(CEMU_ARCHITECTURE MATCHES \"(aarch64)|(AARCH64)|(arm64)|(ARM64)\")\n  target_sources(CemuCafe PRIVATE\n    HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp\n    HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.h\n  )\n  target_link_libraries(CemuCafe PRIVATE xbyak_aarch64)\nendif()\n\nset_property(TARGET CemuCafe PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\ntarget_include_directories(CemuCafe PUBLIC \"../\")\n\nif (glslang_VERSION VERSION_LESS \"15.0.0\")\n\tset(glslang_target \"glslang::SPIRV\")\nelse()\n\tset(glslang_target \"glslang::glslang\")\nendif()\n\ntarget_link_libraries(CemuCafe PRIVATE\n\tCemuCommon\n  CemuGui\n  ZArchive::zarchive\n  imguiImpl\n  pugixml::pugixml\n  ZLIB::ZLIB\n  CURL::libcurl\n  ih264d\n  ${glslang_target}\n  PUBLIC\n  OpenSSL::SSL\n)\n\nif (ENABLE_WAYLAND)\n\t# PUBLIC because wayland-client.h is included in VulkanAPI.h\n  target_link_libraries(CemuCafe PUBLIC Wayland::Client)\nendif()\n\nif (ENABLE_VCPKG)\n  if(WIN32)\n    set(PKG_CONFIG_EXECUTABLE \"${VCPKG_INSTALLED_DIR}/x64-windows/tools/pkgconf/pkgconf.exe\")\n  endif()\n  find_package(PkgConfig REQUIRED)\n  pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0)\n  target_link_libraries(CemuCafe PRIVATE PkgConfig::libusb)\nelse ()\n  find_package(libusb MODULE REQUIRED)\n  target_link_libraries(CemuCafe PRIVATE libusb::libusb)\nendif ()\n\nif(WIN32)\n\ttarget_link_libraries(CemuCafe PRIVATE iphlpapi)\nendif()\n"
  },
  {
    "path": "src/Cafe/CafeSystem.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"WindowSystem.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include \"Cafe/OS/RPL/rpl_symbol_storage.h\"\n#include \"audio/IAudioAPI.h\"\n#include \"audio/IAudioInputAPI.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/LaunchSettings.h\"\n#include \"Cafe/TitleList/GameInfo.h\"\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"util/helpers/SystemException.h\"\n#include \"Common/cpu_features.h\"\n#include \"input/InputManager.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n#include \"Cafe/TitleList/GameInfo.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/Filesystem/FST/FST.h\"\n#include \"Common/FileStream.h\"\n#include \"GamePatch.h\"\n#include \"HW/Espresso/Debugger/GDBStub.h\"\n\n#include \"Cafe/IOSU/legacy/iosu_ioctl.h\"\n#include \"Cafe/IOSU/legacy/iosu_act.h\"\n#include \"Cafe/IOSU/legacy/iosu_fpd.h\"\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n#include \"Cafe/IOSU/legacy/iosu_mcp.h\"\n#include \"Cafe/IOSU/legacy/iosu_acp.h\"\n#include \"Cafe/IOSU/legacy/iosu_nim.h\"\n#include \"Cafe/IOSU/PDM/iosu_pdm.h\"\n#include \"Cafe/IOSU/ccr_nfc/iosu_ccr_nfc.h\"\n#include \"Cafe/IOSU/nn/boss/boss_service.h\"\n\n// IOSU initializer functions\n#include \"Cafe/IOSU/kernel/iosu_kernel.h\"\n#include \"Cafe/IOSU/fsa/iosu_fsa.h\"\n#include \"Cafe/IOSU/ODM/iosu_odm.h\"\n\n// Cafe OS initializer and shutdown functions\n#include \"Cafe/OS/libs/avm/avm.h\"\n#include \"Cafe/OS/libs/drmapp/drmapp.h\"\n#include \"Cafe/OS/libs/TCL/TCL.h\"\n#include \"Cafe/OS/libs/snd_user/snd_user.h\"\n#include \"Cafe/OS/libs/h264_avc/h264dec.h\"\n#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"Cafe/OS/libs/gx2/GX2_Misc.h\"\n#include \"Cafe/OS/libs/mic/mic.h\"\n#include \"Cafe/OS/libs/nfc/nfc.h\"\n#include \"Cafe/OS/libs/ntag/ntag.h\"\n#include \"Cafe/OS/libs/nn_aoc/nn_aoc.h\"\n#include \"Cafe/OS/libs/nn_pdm/nn_pdm.h\"\n#include \"Cafe/OS/libs/nn_cmpt/nn_cmpt.h\"\n#include \"Cafe/OS/libs/nn_ccr/nn_ccr.h\"\n#include \"Cafe/OS/libs/nn_temp/nn_temp.h\"\n#include \"Cafe/OS/libs/nn_save/nn_save.h\"\n\n// HW interfaces\n#include \"Cafe/HW/SI/si.h\"\n\n#include <time.h>\n\n#if BOOST_OS_LINUX\n#include <sys/sysinfo.h>\n#elif BOOST_OS_MACOS || BOOST_OS_BSD\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#endif\n\nstd::string _pathToExecutable;\nstd::string _pathToBaseExecutable;\n\nRPLModule* applicationRPX = nullptr;\nuint32 currentBaseApplicationHash = 0;\nuint32 currentUpdatedApplicationHash = 0;\n\nbool isLaunchTypeELF = false;\n\nMPTR _entryPoint = MPTR_NULL;\n\nuint32 generateHashFromRawRPXData(uint8* rpxData, sint32 size)\n{\n\tuint32 h = 0x3416DCBF;\n\tfor (sint32 i = 0; i < size; i++)\n\t{\n\t\tuint32 c = rpxData[i];\n\t\th = (h << 3) | (h >> 29);\n\t\th += c;\n\t}\n\treturn h;\n}\n\nbool ScanForRPX()\n{\n\tbool rpxFound = false;\n\tsint32 fscStatus = 0;\n\tFSCVirtualFile* fscDirItr = fsc_openDirIterator(\"/internal/current_title/code/\", &fscStatus);\n\tif (fscDirItr)\n\t{\n\t\tFSCDirEntry dirEntry;\n\t\twhile (fsc_nextDir(fscDirItr, &dirEntry))\n\t\t{\n\t\t\tsint32 dirItrPathLen = strlen(dirEntry.path);\n\t\t\tif (dirItrPathLen < 4)\n\t\t\t\tcontinue;\n\t\t\tif (boost::iequals(dirEntry.path + dirItrPathLen - 4, \".rpx\"))\n\t\t\t{\n\t\t\t\trpxFound = true;\n\t\t\t\t_pathToExecutable = fmt::format(\"/internal/current_title/code/{}\", dirEntry.path);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tfsc_close(fscDirItr);\n\t}\n\treturn rpxFound;\n}\n\nvoid SetEntryPoint(MPTR entryPoint)\n{\n\t_entryPoint = entryPoint;\n}\n\n// load executable into virtual memory and set entrypoint\nvoid LoadMainExecutable()\n{\n\tisLaunchTypeELF = false;\n\t// when launching from a disc image _pathToExecutable is initially empty\n\tif (_pathToExecutable.empty())\n\t{\n\t\t// try to get the RPX path from the meta files\n\t\t// todo\n\t\t// otherwise search for first file with .rpx extension in the code folder\n\t\tif (!ScanForRPX())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Unable to find RPX executable\");\n\t\t\tcemuLog_waitForFlush();\n\t\t\tcemu_assert(false);\n\t\t}\n\t}\n\t// extract and load RPX\n\tuint32 rpxSize = 0;\n\tuint8* rpxData = fsc_extractFile(_pathToExecutable.c_str(), &rpxSize);\n\tif (rpxData == nullptr)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to load \\\"{}\\\"\", _pathToExecutable);\n\t\tcemuLog_waitForFlush();\n\t\tcemu_assert(false);\n\t}\n\tcurrentUpdatedApplicationHash = generateHashFromRawRPXData(rpxData, rpxSize);\n\t// determine if this file is an ELF\n\tconst uint8 elfHeaderMagic[9] = { 0x7F,0x45,0x4C,0x46,0x01,0x02,0x01,0x00,0x00 };\n\tif (rpxSize >= 10 && memcmp(rpxData, elfHeaderMagic, sizeof(elfHeaderMagic)) == 0)\n\t{\n\t\t// ELF\n\t\tSetEntryPoint(ELF_LoadFromMemory(rpxData, rpxSize, _pathToExecutable.c_str()));\n\t\tisLaunchTypeELF = true;\n\t}\n\telse\n\t{\n\t\t// RPX\n\t\tRPLLoader_AddDependency(_pathToExecutable.c_str());\n\t\tapplicationRPX = RPLLoader_LoadFromMemory(rpxData, rpxSize, (char*)_pathToExecutable.c_str());\n\t\tif (!applicationRPX)\n\t\t{\n\t\t\tWindowSystem::ShowErrorDialog(_tr(\"Failed to run this title because the executable is damaged\"));\n\t\t\tcemuLog_createLogFile(false);\n\t\t\tcemuLog_waitForFlush();\n\t\t\texit(0);\n\t\t}\n\t\tRPLLoader_SetMainModule(applicationRPX);\n\t\tSetEntryPoint(RPLLoader_GetModuleEntrypoint(applicationRPX));\n\t}\n\tfree(rpxData);\n\t// get RPX hash of game without update\n\tuint32 baseRpxSize = 0;\n\tuint8* baseRpxData = fsc_extractFile(!_pathToBaseExecutable.empty() ? _pathToBaseExecutable.c_str() : _pathToExecutable.c_str(), &baseRpxSize, FSC_PRIORITY_BASE);\n\tif (baseRpxData == nullptr)\n\t{\n\t\tcurrentBaseApplicationHash = currentUpdatedApplicationHash;\n\t}\n\telse\n\t{\n\t\tcurrentBaseApplicationHash = generateHashFromRawRPXData(baseRpxData, baseRpxSize);\n\t}\n\tfree(baseRpxData);\n\tdebug_printf(\"RPXHash: 0x%08x\\n\", currentBaseApplicationHash);\n}\n\nfs::path getTitleSavePath()\n{\n\tconst uint64 titleId = CafeSystem::GetForegroundTitleId();\n\treturn ActiveSettings::GetMlcPath(\"usr/save/{:08X}/{:08X}/user/\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n}\n\nvoid InfoLog_TitleLoaded()\n{\n\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\tcemuLog_log(LogType::Force, \"------- Loaded title -------\");\n\tcemuLog_log(LogType::Force, \"TitleId: {:08x}-{:08x}\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\tcemuLog_log(LogType::Force, \"TitleVersion: v{}\", CafeSystem::GetForegroundTitleVersion());\n\tCafeConsoleRegion region = CafeSystem::GetForegroundTitleRegion();\n\tif(region == CafeConsoleRegion::JPN)\n\t\tcemuLog_log(LogType::Force, \"TitleRegion: JP\");\n\telse if (region == CafeConsoleRegion::EUR)\n\t\tcemuLog_log(LogType::Force, \"TitleRegion: EU\");\n\telse if (region == CafeConsoleRegion::USA)\n\t\tcemuLog_log(LogType::Force, \"TitleRegion: US\");\n\n\tfs::path effectiveSavePath = getTitleSavePath();\n\tstd::error_code ec;\n\tconst bool saveDirExists = fs::exists(effectiveSavePath, ec);\n\tcemuLog_log(LogType::Force, \"Save path:   {}{}\", _pathToUtf8(effectiveSavePath), saveDirExists ? \"\" : \" (not present)\");\n\n\t// log shader cache name\n\tcemuLog_log(LogType::Force, \"Shader cache file: shaderCache/transferable/{:016x}.bin\", titleId);\n\t// game profile info\n\tstd::string gameProfilePath;\n\tif(g_current_game_profile->IsDefaultProfile())\n\t\tgameProfilePath = fmt::format(\"gameProfiles/default/{:016x}.ini\", titleId);\n\telse\n\t\tgameProfilePath = fmt::format(\"gameProfiles/{:016x}.ini\", titleId);\n\tcemuLog_log(LogType::Force, \"gameprofile path: {}\", g_current_game_profile->IsLoaded() ? gameProfilePath : std::string(\" (not present)\"));\n\t// rpx hash of updated game\n\tcemuLog_log(LogType::Force, \"RPX hash (updated): {:08x}\", currentUpdatedApplicationHash);\n\tcemuLog_log(LogType::Force, \"RPX hash (base): {:08x}\", currentBaseApplicationHash);\n\n\tmemory_logModifiedMemoryRanges();\n}\n\nvoid InfoLog_PrintActiveSettings()\n{\n\tconst auto& config = GetConfig();\n\tcemuLog_log(LogType::Force, \"------- Active settings -------\");\n\n\t// settings to log:\n\tcemuLog_log(LogType::Force, \"CPU-Mode: {}{}\", fmt::format(\"{}\", ActiveSettings::GetCPUMode()).c_str(), g_current_game_profile->GetCPUMode().has_value() ? \" (gameprofile)\" : \"\");\n\tcemuLog_log(LogType::Force, \"Load shared libraries: {}{}\", ActiveSettings::LoadSharedLibrariesEnabled() ? \"true\" : \"false\", g_current_game_profile->ShouldLoadSharedLibraries().has_value() ? \" (gameprofile)\" : \"\");\n\tcemuLog_log(LogType::Force, \"Use precompiled shaders: {}{}\", fmt::format(\"{}\", ActiveSettings::GetPrecompiledShadersOption()), g_current_game_profile->GetPrecompiledShadersState().has_value() ? \" (gameprofile)\" : \"\");\n\tcemuLog_log(LogType::Force, \"Full sync at GX2DrawDone: {}\", ActiveSettings::WaitForGX2DrawDoneEnabled() ? \"true\" : \"false\");\n\tcemuLog_log(LogType::Force, \"Strict shader mul: {}\", g_current_game_profile->GetAccurateShaderMul() == AccurateShaderMulOption::True ? \"true\" : \"false\");\n\tif (ActiveSettings::GetGraphicsAPI() == GraphicAPI::kVulkan)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Async compile: {}\", GetConfig().async_compile.GetValue() ? \"true\" : \"false\");\n\t\tif (!GetConfig().vk_accurate_barriers.GetValue())\n\t\t\tcemuLog_log(LogType::Force, \"Accurate barriers are disabled!\");\n\t}\n#if ENABLE_METAL\n\telse if (ActiveSettings::GetGraphicsAPI() == GraphicAPI::kMetal)\n\t{\n\t    cemuLog_log(LogType::Force, \"Async compile: {}\", GetConfig().async_compile.GetValue() ? \"true\" : \"false\");\n\t    cemuLog_log(LogType::Force, \"Force mesh shaders: {}\", GetConfig().force_mesh_shaders.GetValue() ? \"true\" : \"false\");\n\t\tcemuLog_log(LogType::Force, \"Fast math: {}\", g_current_game_profile->GetShaderFastMath() ? \"true\" : \"false\");\n\t\tcemuLog_log(LogType::Force, \"Buffer cache type: {}\", g_current_game_profile->GetBufferCacheMode());\n\t\tcemuLog_log(LogType::Force, \"Position invariance: {}\", g_current_game_profile->GetPositionInvariance());\n\t\tif (!GetConfig().vk_accurate_barriers.GetValue())\n\t\t\tcemuLog_log(LogType::Force, \"Accurate barriers are disabled!\");\n\t}\n#endif\n\tcemuLog_log(LogType::Force, \"Console language: {}\", stdx::to_underlying(config.console_language.GetValue()));\n}\n\nstruct SharedDataEntry\n{\n\t/* +0x00 */ uint32be name;\n\t/* +0x04 */ uint32be fileType; // 2 = font\n\t/* +0x08 */ uint32be kernelFilenamePtr;\n\t/* +0x0C */ MEMPTR<void> data;\n\t/* +0x10 */ uint32be size;\n\t/* +0x14 */ uint32be ukn14;\n\t/* +0x18 */ uint32be ukn18;\n};\n\nstruct\n{\n\tuint32 name;\n\tuint32 fileType;\n\tconst char* fileName;\n\tconst char* resourcePath;\n\tconst char* mlcPath;\n}shareddataDef[] =\n{\n\t0xFFCAFE01, 2, \"CafeCn.ttf\", \"resources/sharedFonts/CafeCn.ttf\", \"sys/title/0005001b/10042400/content/CafeCn.ttf\",\n\t0xFFCAFE02, 2, \"CafeKr.ttf\", \"resources/sharedFonts/CafeKr.ttf\", \"sys/title/0005001b/10042400/content/CafeKr.ttf\",\n\t0xFFCAFE03, 2, \"CafeStd.ttf\", \"resources/sharedFonts/CafeStd.ttf\", \"sys/title/0005001b/10042400/content/CafeStd.ttf\",\n\t0xFFCAFE04, 2, \"CafeTw.ttf\", \"resources/sharedFonts/CafeTw.ttf\", \"sys/title/0005001b/10042400/content/CafeTw.ttf\"\n};\n\nstatic_assert(sizeof(SharedDataEntry) == 0x1C);\n\nuint32 LoadSharedData()\n{\n\t// check if font files are dumped\n\tbool hasAllShareddataFiles = true;\n\tfor (sint32 i = 0; i < sizeof(shareddataDef) / sizeof(shareddataDef[0]); i++)\n\t{\n\t\tbool existsInMLC = fs::exists(ActiveSettings::GetMlcPath(shareddataDef[i].mlcPath));\n\t\tbool existsInResources = fs::exists(ActiveSettings::GetDataPath(shareddataDef[i].resourcePath));\n\n\t\tif (!existsInMLC && !existsInResources)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Shared font {} is not present\", shareddataDef[i].fileName);\n\t\t\thasAllShareddataFiles = false;\n\t\t\tbreak;\n\t\t}\n\t}\n\tsint32 numEntries = sizeof(shareddataDef) / sizeof(shareddataDef[0]);\n\tif (hasAllShareddataFiles)\n\t{\n\t\t// all shareddata font files are present -> load them\n\t\tSharedDataEntry* shareddataTable = (SharedDataEntry*)memory_getPointerFromVirtualOffset(0xF8000000);\n\t\tmemset(shareddataTable, 0, sizeof(SharedDataEntry) * numEntries);\n\t\tuint8* dataWritePtr = memory_getPointerFromVirtualOffset(0xF8000000 + sizeof(SharedDataEntry) * numEntries);\n\t\t// setup entries\n\t\tfor (sint32 i = 0; i < numEntries; i++)\n\t\t{\n\t\t\t// try to read font from MLC first\n\t\t\tauto path = ActiveSettings::GetMlcPath(shareddataDef[i].mlcPath);\n\t\t\tFileStream* fontFile = FileStream::openFile2(path);\n\t\t\t// alternatively fall back to our shared fonts\n\t\t\tif (!fontFile)\n\t\t\t{\n\t\t\t\tpath = ActiveSettings::GetDataPath(shareddataDef[i].resourcePath);\n\t\t\t\tfontFile = FileStream::openFile2(path);\n\t\t\t}\n\t\t\tif (!fontFile)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to load shared font {}\", shareddataDef[i].fileName);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tuint32 fileSize = fontFile->GetSize();\n\t\t\tfontFile->readData(dataWritePtr, fileSize);\n\t\t\tdelete fontFile;\n\t\t\t// setup entry\n\t\t\tshareddataTable[i].name = shareddataDef[i].name;\n\t\t\tshareddataTable[i].fileType = shareddataDef[i].fileType;\n\t\t\tshareddataTable[i].kernelFilenamePtr = 0x00000000;\n\t\t\tshareddataTable[i].data = dataWritePtr;\n\t\t\tshareddataTable[i].size = fileSize;\n\t\t\tshareddataTable[i].ukn14 = 0x00000000;\n\t\t\tshareddataTable[i].ukn18 = 0x00000000;\n\t\t\t// advance write offset and pad to 16 byte alignment\n\t\t\tdataWritePtr += ((fileSize + 15) & ~15);\n\t\t}\n\t\tcemuLog_log(LogType::Force, \"COS: System fonts found. Generated shareddata ({}KB)\", (uint32)(dataWritePtr - (uint8*)shareddataTable) / 1024);\n\t\treturn memory_getVirtualOffsetFromPointer(dataWritePtr);\n\t}\n\t// alternative method: load RAM dump\n\tconst auto path = ActiveSettings::GetUserDataPath(\"shareddata.bin\");\n\tFileStream* ramDumpFile = FileStream::openFile2(path);\n\tif (ramDumpFile)\n\t{\n\t\tramDumpFile->readData(memory_getPointerFromVirtualOffset(0xF8000000), 0x02000000);\n\t\tdelete ramDumpFile;\n\t\treturn (mmuRange_SHARED_AREA.getBase() + 0x02000000);\n\t}\n\treturn mmuRange_SHARED_AREA.getBase() + sizeof(SharedDataEntry) * numEntries;\n}\n\nvoid cemu_initForGame()\n{\n\tWindowSystem::UpdateWindowTitles(false, true, 0.0);\n\tcemuLog_createLogFile(false);\n\t// input manager apply game profile\n\tInputManager::instance().apply_game_profile();\n\t// determine cycle offset since 1.1.2000\n\tuint64 secondsSince2000_UTC = (uint64)(time(NULL) - 946684800);\n\tppcCyclesSince2000_UTC = secondsSince2000_UTC * (uint64)ESPRESSO_CORE_CLOCK;\n\ttime_t theTime = (time(NULL) - 946684800);\n\t{\n\t\ttm* lt = localtime(&theTime);\n#if BOOST_OS_WINDOWS\n\t\ttheTime = _mkgmtime(lt);\n#else\n\t\ttheTime = timegm(lt);\n#endif\n\t}\n\tppcCyclesSince2000 = theTime * (uint64)ESPRESSO_CORE_CLOCK;\n\tppcCyclesSince2000TimerClock = ppcCyclesSince2000 / 20ULL;\n\tPPCTimer_start();\n\t// coreinit is bootstrapped first and then the main game executable is loaded\n\tRPLLoader_LoadCoreinit();\n\tLoadMainExecutable();\n\t// log info for launched title\n\tInfoLog_TitleLoaded();\n\t// link all modules\n\tuint32 linkTimeStart = GetTickCount();\n\tRPLLoader_UpdateDependencies();\n\tRPLLoader_Link();\n\tRPLLoader_NotifyControlPassedToApplication();\n\tuint32 linkTime = GetTickCount() - linkTimeStart;\n\tcemuLog_log(LogType::Force, \"RPL link time: {}ms\", linkTime);\n\t// for HBL ELF: Setup OS-specifics struct\n\tif (isLaunchTypeELF)\n\t{\n\t\tmemory_writeU32(0x801500, rpl_mapHLEImport(nullptr, \"coreinit\", \"OSDynLoad_Acquire\", true));\n\t\tmemory_writeU32(0x801504, rpl_mapHLEImport(nullptr, \"coreinit\", \"OSDynLoad_FindExport\", true));\n\t}\n\telse\n\t{\n\t\t// replace any known function signatures with our HLE implementations and patch bugs in the games\n\t\tGamePatch_scan();\n\t}\n\tLatteGPUState.isDRCPrimary = ActiveSettings::DisplayDRCEnabled();\n\tInfoLog_PrintActiveSettings();\n\tLatte_Start();\n\t// check for debugger entrypoint bp\n    if (g_gdbstub)\n    {\n        g_gdbstub->HandleEntryStop(_entryPoint);\n        g_gdbstub->Initialize();\n    }\n\tdebugger_handleEntryBreakpoint(_entryPoint);\n\t// load graphic packs\n\tcemuLog_log(LogType::Force, \"------- Activate graphic packs -------\");\n\tGraphicPack2::ActivateForCurrentTitle();\n\t// print audio log\n\tIAudioAPI::PrintLogging();\n\tIAudioInputAPI::PrintLogging();\n\t// everything initialized\n\tcemuLog_log(LogType::Force, \"------- Run title -------\");\n\t// wait till GPU thread is initialized\n\twhile (g_isGPUInitFinished == false) std::this_thread::sleep_for(std::chrono::milliseconds(50));\n\t// run coreinit rpl_entry\n\tRPLLoader_CallCoreinitEntrypoint();\n\t// init AX and start AX I/O thread\n\tsnd_core::AXOut_init();\n}\n\nnamespace CafeSystem\n{\n\tvoid InitVirtualMlcStorage();\n\tvoid MlcStorageMountTitle(TitleInfo& titleInfo);\n    void MlcStorageUnmountAllTitles();\n\n    static bool s_initialized = false;\n\tstatic SystemImplementation* s_implementation{nullptr};\n    bool sLaunchModeIsStandalone = false;\n\tstd::optional<std::vector<std::string>> s_overrideArgs;\n\n\tbool sSystemRunning = false;\n\tTitleId sForegroundTitleId = 0;\n\n\tGameInfo2 sGameInfo_ForegroundTitle;\n\n\n\tstatic void _CheckForWine()\n\t{\n\t\t#if BOOST_OS_WINDOWS\n\t\tconst HMODULE hmodule = GetModuleHandleA(\"ntdll.dll\");\n\t\tif (!hmodule)\n\t\t\treturn;\n\n\t\tconst auto pwine_get_version = (const char*(__cdecl*)())GetProcAddress(hmodule, \"wine_get_version\");\n\t\tif (pwine_get_version)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Wine version: {}\", pwine_get_version());\n\t\t}\n\t\t#endif\n\t}\n\n\tvoid logCPUAndMemoryInfo()\n\t{\n\t\tstd::string cpuName = g_CPUFeatures.GetCPUName();\n\t\tif (!cpuName.empty())\n\t\t\tcemuLog_log(LogType::Force, \"CPU: {}\", cpuName);\n\t\t#if BOOST_OS_WINDOWS\n\t\tMEMORYSTATUSEX statex;\n\t\tstatex.dwLength = sizeof(statex);\n\t\tGlobalMemoryStatusEx(&statex);\n\t\tuint32 memoryInMB = (uint32)(statex.ullTotalPhys / 1024LL / 1024LL);\n\t\tcemuLog_log(LogType::Force, \"RAM: {}MB\", memoryInMB);\n\t\t#elif BOOST_OS_LINUX\n\t\tstruct sysinfo info {};\n\t\tsysinfo(&info);\n\t\tcemuLog_log(LogType::Force, \"RAM: {}MB\", ((static_cast<uint64_t>(info.totalram) * info.mem_unit) / 1024LL / 1024LL));\n\t\t#elif BOOST_OS_MACOS\n\t\tint64_t totalRam;\n\t\tsize_t size = sizeof(totalRam);\n\t\tint result = sysctlbyname(\"hw.memsize\", &totalRam, &size, NULL, 0);\n\t\tif (result == 0)\n\t\t\tcemuLog_log(LogType::Force, \"RAM: {}MB\", (totalRam / 1024LL / 1024LL));\n\t\t#elif BOOST_OS_BSD\n\t\tint64_t totalRam;\n\t\tsize_t size = sizeof(totalRam);\n\t\tint result = sysctlbyname(\"hw.physmem\", &totalRam, &size, NULL, 0);\n\t\tif (result == 0)\n\t\t\tcemuLog_log(LogType::Force, \"RAM: {}MB\", (totalRam / 1024LL / 1024LL));\n\t\t#endif\n\t}\n\n\t#if BOOST_OS_WINDOWS\n\tstd::string GetWindowsNamedVersion(uint32& buildNumber)\n\t{\n\t\tchar productName[256];\n\t\tHKEY hKey;\n\t\tDWORD dwType = REG_SZ;\n\t\tDWORD dwSize = sizeof(productName);\n\t\tif (RegOpenKeyExA(HKEY_LOCAL_MACHINE, \"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\", 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)\n\t\t{\n\t\t\tif (RegQueryValueExA(hKey, \"ProductName\", NULL, &dwType, (LPBYTE)productName, &dwSize) != ERROR_SUCCESS)\n\t\t\t\tstrcpy(productName, \"Windows\");\n\t\t\tRegCloseKey(hKey);\n\t\t}\n\t\tOSVERSIONINFO osvi;\n\t\tZeroMemory(&osvi, sizeof(OSVERSIONINFO));\n\t\tosvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\n\t\tGetVersionEx(&osvi);\n\t\tbuildNumber = osvi.dwBuildNumber;\n\t\treturn std::string(productName);\n\t}\n\t#endif\n\n\tvoid logPlatformInfo()\n\t{\n\t\tstd::string buffer;\n\t\tconst char* platform = NULL;\n\t\t#if BOOST_OS_WINDOWS\n\t\tuint32 buildNumber;\n\t\tstd::string windowsVersionName = GetWindowsNamedVersion(buildNumber);\n\t\tbuffer = fmt::format(\"{} (Build {})\", windowsVersionName, buildNumber);\n\t\tplatform = buffer.c_str();\n\t\t#elif BOOST_OS_LINUX\n\t\tif (getenv (\"APPIMAGE\"))\n\t\t\tplatform = \"Linux (AppImage)\";\n\t\telse if (getenv (\"SNAP\"))\n\t\t\tplatform = \"Linux (Snap)\";\n\t\telse if (platform = getenv (\"container\"))\n\t\t{\n\t\t\tif (strcmp (platform, \"flatpak\") == 0)\n\t\t\t\tplatform = \"Linux (Flatpak)\";\n\t\t}\n\t\telse\n\t\t\tplatform = \"Linux\";\n\t\t#elif BOOST_OS_MACOS\n\t\tplatform = \"MacOS\";\n\t\t#elif BOOST_OS_BSD\n\t\t#if defined(__FreeBSD__)\n\t\tplatform = \"FreeBSD\";\n\t\t#elif defined(__OpenBSD__)\n\t\tplatform = \"OpenBSD\";\n\t\t#elif defined(__NetBSD__)\n\t\tplatform = \"NetBSD\";\n\t\t#else\n\t\tplatform = \"Unknown BSD\";\n\t\t#endif\n\t\t#endif\n\t\tcemuLog_log(LogType::Force, \"Platform: {}\", platform);\n\t}\n\n\tstatic std::vector<IOSUModule*> s_iosuModules =\n\t{\n\t\t// entries in this list are ordered by initialization order. Shutdown in reverse order\n\t\tiosu::kernel::GetModule(),\n\t\tiosu::acp::GetModule(),\n\t\tiosu::fpd::GetModule(),\n\t\tiosu::pdm::GetModule(),\n\t\tiosu::ccr_nfc::GetModule(),\n\t\tiosu::boss::GetModule()\n\t};\n\n\t// initialize all subsystems which are persistent and don't depend on a game running\n\tvoid Initialize()\n\t{\n\t\tif (s_initialized)\n\t\t\treturn;\n\t\ts_initialized = true;\n\t\t// init core systems\n\t\tcemuLog_log(LogType::Force, \"------- Init {} -------\", BUILD_VERSION_WITH_NAME_STRING);\n\t\tfsc_init();\n\t\tmemory_init();\n\t\tcemuLog_log(LogType::Force, \"Init Wii U memory space (base: 0x{:016x})\", (size_t)memory_base);\n\t\tPPCCore_init();\n\t\tRPLLoader_InitState();\n\t\tcemuLog_log(LogType::Force, \"mlc01 path: {}\", _pathToUtf8(ActiveSettings::GetMlcPath()));\n\t\t_CheckForWine();\n\t\t// CPU and RAM info\n\t\tlogCPUAndMemoryInfo();\n\t\tlogPlatformInfo();\n\t\tcemuLog_log(LogType::Force, \"Used CPU extensions: {}\", g_CPUFeatures.GetCommaSeparatedExtensionList());\n\t\t// misc systems\n\t\trplSymbolStorage_init();\n\t\t// allocate memory for all SysAllocators\n\t\t// must happen before COS module init, but also before iosu::kernel::Initialize()\n\t\tSysAllocatorContainer::GetInstance().Initialize();\n\t\t// init IOSU modules\n\t\tfor(auto& module : s_iosuModules)\n\t\t\tmodule->SystemLaunch();\n\t\t// init IOSU (deprecated manual init)\n\t\tiosuCrypto_init();\n\t\tiosu::fsa::Initialize();\n\t\tiosuIoctl_init();\n\t\tiosuAct_init_depr();\n\t\tiosu::act::Initialize();\n\t\tiosu::iosuMcp_init();\n\t\tiosu::mcp::Init();\n\t\tiosu::iosuAcp_init();\n\t\tiosu::nim::Initialize();\n\t\tiosu::odm::Initialize();\n\t\t// init hardware register interfaces\n\t\tHW_SI::Initialize();\n\t}\n\n\tvoid SetImplementation(SystemImplementation* impl)\n\t{\n\t\ts_implementation = impl;\n\t}\n\n    void Shutdown()\n    {\n        cemu_assert_debug(s_initialized);\n        // if a title is running, shut it down\n        if (sSystemRunning)\n            ShutdownTitle();\n        // shutdown persistent subsystems (deprecated manual shutdown)\n\t\tiosu::odm::Shutdown();\n\t\tiosu::act::Stop();\n        iosu::mcp::Shutdown();\n        iosu::fsa::Shutdown();\n\t\t// shutdown IOSU modules\n\t\tfor(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it)\n\t\t\t(*it)->SystemExit();\n        s_initialized = false;\n    }\n\n\tstd::string GetInternalVirtualCodeFolder()\n\t{\n\t\treturn \"/internal/current_title/code/\";\n\t}\n\n    void MountBaseDirectories()\n    {\n        const auto mlc = ActiveSettings::GetMlcPath();\n        FSCDeviceHostFS_Mount(\"/cemuBossStorage/\", _pathToUtf8(mlc / \"usr/boss/\"), FSC_PRIORITY_BASE);\n        FSCDeviceHostFS_Mount(\"/vol/storage_mlc01/\", _pathToUtf8(mlc / \"\"), FSC_PRIORITY_BASE);\n    }\n\n    void UnmountBaseDirectories()\n    {\n        fsc_unmount(\"/vol/storage_mlc01/\", FSC_PRIORITY_BASE);\n        fsc_unmount(\"/cemuBossStorage/\", FSC_PRIORITY_BASE);\n    }\n\n\tPREPARE_STATUS_CODE LoadAndMountForegroundTitle(TitleId titleId)\n\t{\n        cemuLog_log(LogType::Force, \"Mounting title {:016x}\", (uint64)titleId);\n\t\tsGameInfo_ForegroundTitle = CafeTitleList::GetGameInfo(titleId);\n\t\tif (!sGameInfo_ForegroundTitle.IsValid())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Mounting failed: Game meta information is either missing, inaccessible or not valid (missing or invalid .xml files in code and meta folder)\");\n\t\t\treturn PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;\n\t\t}\n\t\t// check base\n\t\tTitleInfo& titleBase = sGameInfo_ForegroundTitle.GetBase();\n\t\tif (!titleBase.IsValid())\n\t\t\treturn PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;\n\t\tif(!titleBase.ParseXmlInfo())\n\t\t\treturn PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;\n\t\tcemuLog_log(LogType::Force, \"Base: {}\", titleBase.GetPrintPath());\n\t\t// mount base\n\t\tif (!titleBase.Mount(\"/vol/content\", \"content\", FSC_PRIORITY_BASE) || !titleBase.Mount(GetInternalVirtualCodeFolder(), \"code\", FSC_PRIORITY_BASE))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Mounting failed\");\n\t\t\treturn PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;\n\t\t}\n\t\t// check update\n\t\tTitleInfo& titleUpdate = sGameInfo_ForegroundTitle.GetUpdate();\n\t\tif (titleUpdate.IsValid())\n\t\t{\n\t\t\tif (!titleUpdate.ParseXmlInfo())\n\t\t\t\treturn PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;\n\t\t\tcemuLog_log(LogType::Force, \"Update: {}\", titleUpdate.GetPrintPath());\n\t\t\t// mount update\n\t\t\tif (!titleUpdate.Mount(\"/vol/content\", \"content\", FSC_PRIORITY_PATCH) || !titleUpdate.Mount(GetInternalVirtualCodeFolder(), \"code\", FSC_PRIORITY_PATCH))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Mounting failed\");\n\t\t\t\treturn PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tcemuLog_log(LogType::Force, \"Update: Not present\");\n\t\t// check AOC\n\t\tauto aocList = sGameInfo_ForegroundTitle.GetAOC();\n\t\tif (!aocList.empty())\n\t\t{\n\t\t\t// todo - support for multi-title AOC\n\t\t\tTitleInfo& titleAOC = aocList[0];\n\t\t\tif (!titleAOC.ParseXmlInfo())\n\t\t\t\treturn PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;\n\t\t\tcemu_assert_debug(titleAOC.IsValid());\n\t\t\tcemuLog_log(LogType::Force, \"DLC: {}\", titleAOC.GetPrintPath());\n\t\t\t// mount AOC\n\t\t\tif (!titleAOC.Mount(fmt::format(\"/vol/aoc{:016x}\", titleAOC.GetAppTitleId()), \"content\", FSC_PRIORITY_PATCH))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Mounting failed\");\n\t\t\t\treturn PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tcemuLog_log(LogType::Force, \"DLC: Not present\");\n\t\tsForegroundTitleId = titleId;\n\t\treturn PREPARE_STATUS_CODE::SUCCESS;\n\t}\n\n    void UnmountForegroundTitle()\n    {\n        if(sLaunchModeIsStandalone)\n            return;\n        cemu_assert_debug(sGameInfo_ForegroundTitle.IsValid()); // unmounting title which was never mounted?\n        if (!sGameInfo_ForegroundTitle.IsValid())\n            return;\n        sGameInfo_ForegroundTitle.GetBase().Unmount(\"/vol/content\");\n        sGameInfo_ForegroundTitle.GetBase().Unmount(GetInternalVirtualCodeFolder());\n        if (sGameInfo_ForegroundTitle.HasUpdate())\n        {\n            if(auto& update = sGameInfo_ForegroundTitle.GetUpdate(); update.IsValid())\n            {\n                update.Unmount(\"/vol/content\");\n                update.Unmount(GetInternalVirtualCodeFolder());\n            }\n        }\n        auto aocList = sGameInfo_ForegroundTitle.GetAOC();\n        if (!aocList.empty())\n        {\n            TitleInfo& titleAOC = aocList[0];\n            titleAOC.Unmount(fmt::format(\"/vol/aoc{:016x}\", titleAOC.GetAppTitleId()));\n        }\n    }\n\n\tPREPARE_STATUS_CODE PrepareExecutable()\n\t{\n\t\t// set rpx path from cos.xml if available\n\t\t_pathToBaseExecutable = _pathToExecutable;\n\t\tif (!sLaunchModeIsStandalone)\n\t\t{\n\t\t\tstd::string _argstr = CafeSystem::GetForegroundTitleArgStr();\n\t\t\tconst char* argstr = _argstr.c_str();\n\t\t\tif (argstr && *argstr != '\\0')\n\t\t\t{\n\t\t\t\tconst std::string tmp = argstr;\n\t\t\t\tconst auto index = tmp.find(\".rpx\");\n\t\t\t\tif (index != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tfs::path rpx = _pathToExecutable;\n\t\t\t\t\trpx.replace_filename(tmp.substr(0, index + 4)); // cut off after .rpx\n\n\t\t\t\t\tstd::string rpxPath;\n\t\t\t\t\trpxPath = \"/internal/current_title/code/\";\n\t\t\t\t\trpxPath.append(rpx.generic_string());\n\n\t\t\t\t\tint status;\n\t\t\t\t\tconst auto file = fsc_open(rpxPath.c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &status);\n\t\t\t\t\tif (file)\n\t\t\t\t\t{\n\t\t\t\t\t\t_pathToExecutable = std::move(rpxPath);\n\t\t\t\t\t\tfsc_close(file);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn PREPARE_STATUS_CODE::SUCCESS;\n\t}\n\n    void SetupMemorySpace()\n    {\n        memory_mapForCurrentTitle();\n        LoadSharedData();\n    }\n\n    void DestroyMemorySpace()\n    {\n        memory_unmapForCurrentTitle();\n    }\n\n\tPREPARE_STATUS_CODE PrepareForegroundTitle(TitleId titleId)\n\t{\n\t\tCafeTitleList::WaitForMandatoryScan();\n\t\tsLaunchModeIsStandalone = false;\n        _pathToExecutable.clear();\n\t\tTitleIdParser tip(titleId);\n\t\tif (tip.GetType() == TitleIdParser::TITLE_TYPE::AOC || tip.GetType() == TitleIdParser::TITLE_TYPE::BASE_TITLE_UPDATE)\n\t\t\tcemuLog_log(LogType::Force, \"Launched titleId is not the base of a title\");\n        // mount mlc storage\n        MountBaseDirectories();\n        // mount title folders\n\t\tPREPARE_STATUS_CODE r = LoadAndMountForegroundTitle(titleId);\n\t\tif (r != PREPARE_STATUS_CODE::SUCCESS)\n\t\t\treturn r;\n\t\tgameProfile_load();\n\t\t// setup memory space and PPC recompiler\n        SetupMemorySpace();\n        PPCRecompiler_init();\n\t\tr = PrepareExecutable(); // load RPX\n\t\tif (r != PREPARE_STATUS_CODE::SUCCESS)\n\t\t\treturn r;\n\t\tInitVirtualMlcStorage();\n\t\treturn PREPARE_STATUS_CODE::SUCCESS;\n\t}\n\n\tPREPARE_STATUS_CODE PrepareForegroundTitleFromStandaloneRPX(const fs::path& path)\n\t{\n\t\tsLaunchModeIsStandalone = true;\n\t\tcemuLog_log(LogType::Force, \"Launching executable in standalone mode due to incorrect layout or missing meta files\");\n\t\tfs::path executablePath = path;\n\t\tstd::string dirName = _pathToUtf8(executablePath.parent_path().filename());\n\t\tif (boost::iequals(dirName, \"code\"))\n\t\t{\n\t\t\t// check for content folder\n\t\t\tfs::path contentPath = executablePath.parent_path().parent_path().append(\"content\");\n\t\t\tstd::error_code ec;\n\t\t\tif (fs::is_directory(contentPath, ec))\n\t\t\t{\n\t\t\t\t// mounting content folder\n\t\t\t\tbool r = FSCDeviceHostFS_Mount(std::string(\"/vol/content\").c_str(), _pathToUtf8(contentPath), FSC_PRIORITY_BASE);\n\t\t\t\tif (!r)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Failed to mount {}\", _pathToUtf8(contentPath));\n\t\t\t\t\treturn PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// mount code folder to a virtual temporary path\n\t\tFSCDeviceHostFS_Mount(std::string(\"/internal/code/\").c_str(), _pathToUtf8(executablePath.parent_path()), FSC_PRIORITY_BASE);\n\t\tstd::string internalExecutablePath = \"/internal/code/\";\n\t\tinternalExecutablePath.append(_pathToUtf8(executablePath.filename()));\n\t\t_pathToExecutable = internalExecutablePath;\n\t\t// since a lot of systems (including save folder location) rely on a TitleId, we derive a placeholder id from the executable hash\n\t\tauto execData = fsc_extractFile(_pathToExecutable.c_str());\n\t\tif (!execData)\n\t\t\treturn PREPARE_STATUS_CODE::INVALID_RPX;\n\t\tuint32 h = generateHashFromRawRPXData(execData->data(), execData->size());\n\t\tsForegroundTitleId = 0xFFFFFFFF00000000ULL | (uint64)h;\n\t\tcemuLog_log(LogType::Force, \"Generated placeholder TitleId: {:016x}\", sForegroundTitleId);\n\t\t// setup memory space and ppc recompiler\n        SetupMemorySpace();\n        PPCRecompiler_init();\n        // load executable\n        PrepareExecutable();\n\t\tInitVirtualMlcStorage();\n\t\treturn PREPARE_STATUS_CODE::SUCCESS;\n\t}\n\n\tvoid _LaunchTitleThread()\n\t{\n\t\tfor(auto& module : s_iosuModules)\n\t\t\tmodule->TitleStart();\n\t\tcemu_initForGame();\n\t\t// enter scheduler\n\t\tif ((ActiveSettings::GetCPUMode() == CPUMode::MulticoreRecompiler || LaunchSettings::ForceMultiCoreInterpreter()) && !LaunchSettings::ForceInterpreter())\n\t\t\tcoreinit::OSSchedulerBegin(3);\n\t\telse\n\t\t\tcoreinit::OSSchedulerBegin(1);\n\t}\n\n\tvoid LaunchForegroundTitle()\n\t{\n\t\tPPCTimer_waitForInit();\n\t\t// start system\n\t\tsSystemRunning = true;\n\t\tWindowSystem::NotifyGameLoaded();\n\t\tstd::thread t(_LaunchTitleThread);\n\t\tt.detach();\n\t}\n\n\tbool IsTitleRunning()\n\t{\n\t\treturn sSystemRunning;\n\t}\n\n\tTitleId GetForegroundTitleId()\n\t{\n\t\tcemu_assert_debug(sForegroundTitleId != 0);\n\t\treturn sForegroundTitleId;\n\t}\n\n\tuint16 GetForegroundTitleVersion()\n\t{\n\t\tif (sLaunchModeIsStandalone)\n\t\t\treturn 0;\n\t\treturn sGameInfo_ForegroundTitle.GetVersion();\n\t}\n\n\tuint32 GetForegroundTitleSDKVersion()\n\t{\n\t\tif (sLaunchModeIsStandalone)\n\t\t\treturn 999999;\n\t\treturn sGameInfo_ForegroundTitle.GetSDKVersion();\n\t}\n\n\tCafeConsoleRegion GetForegroundTitleRegion()\n\t{\n\t\tif (sLaunchModeIsStandalone)\n\t\t\treturn CafeConsoleRegion::USA;\n\t\treturn sGameInfo_ForegroundTitle.GetRegion();\n\t}\n\n\tstd::string GetForegroundTitleName()\n\t{\n\t\tif (sLaunchModeIsStandalone)\n\t\t\treturn \"Unknown Game\";\n\t\tstd::string applicationName;\n\t\tapplicationName = sGameInfo_ForegroundTitle.GetBase().GetMetaInfo()->GetShortName(GetConfig().console_language);\n\t\tif (applicationName.empty()) //Try to get the English Title\n\t\t\tapplicationName = sGameInfo_ForegroundTitle.GetBase().GetMetaInfo()->GetShortName(CafeConsoleLanguage::EN);\n\t\tif (applicationName.empty()) //Unknown Game\n\t\t\tapplicationName = \"Unknown Game\";\n\t\treturn applicationName;\n\t}\n\n\tuint32 GetForegroundTitleOlvAccesskey()\n\t{\n\t\tif (sLaunchModeIsStandalone)\n\t\t\treturn -1;\n\t\treturn sGameInfo_ForegroundTitle.GetBase().GetMetaInfo()->GetOlvAccesskey();\n\t}\n\n\tstd::string GetForegroundTitleArgStr()\n\t{\n\t\tif (sLaunchModeIsStandalone)\n\t\t\treturn \"\";\n\t\tauto& update = sGameInfo_ForegroundTitle.GetUpdate();\n\t\tif (update.IsValid())\n\t\t\treturn update.GetArgStr();\n\t\treturn sGameInfo_ForegroundTitle.GetBase().GetArgStr();\n\t}\n\n\tCosCapabilityBits GetForegroundTitleCosCapabilities(CosCapabilityGroup group)\n\t{\n\t\tif (sLaunchModeIsStandalone)\n\t\t\treturn CosCapabilityBits::All;\n\t\tauto& update = sGameInfo_ForegroundTitle.GetUpdate();\n\t\tif (update.IsValid())\n\t\t{\n\t\t\tParsedCosXml* cosXml = update.GetCosInfo();\n\t\t\tif (cosXml)\n\t\t\t\treturn cosXml->GetCapabilityBits(group);\n\t\t}\n\t\tauto& base = sGameInfo_ForegroundTitle.GetBase();\n\t\tif(base.IsValid())\n\t\t{\n\t\t\tParsedCosXml* cosXml = base.GetCosInfo();\n\t\t\tif (cosXml)\n\t\t\t\treturn cosXml->GetCapabilityBits(group);\n\t\t}\n\t\treturn CosCapabilityBits::All;\n\t}\n\n\t// when switching titles custom parameters can be passed, returns true if override args are used\n\tbool GetOverrideArgStr(std::vector<std::string>& args)\n\t{\n\t\targs.clear();\n\t\tif(!s_overrideArgs)\n\t\t\treturn false;\n\t\targs = *s_overrideArgs;\n\t\treturn true;\n\t}\n\n\tvoid SetOverrideArgs(std::span<std::string> args)\n\t{\n\t\ts_overrideArgs = std::vector<std::string>(args.begin(), args.end());\n\t}\n\n\tvoid UnsetOverrideArgs()\n\t{\n\t\ts_overrideArgs = std::nullopt;\n\t}\n\n\t// pick platform region based on title region\n\tCafeConsoleRegion GetPlatformRegion()\n\t{\n\t\tCafeConsoleRegion titleRegion = GetForegroundTitleRegion();\n\t\tCafeConsoleRegion platformRegion = CafeConsoleRegion::USA;\n\t\tif (HAS_FLAG(titleRegion, CafeConsoleRegion::JPN))\n\t\t\tplatformRegion = CafeConsoleRegion::JPN;\n\t\telse if (HAS_FLAG(titleRegion, CafeConsoleRegion::EUR))\n\t\t\tplatformRegion = CafeConsoleRegion::EUR;\n\t\telse if (HAS_FLAG(titleRegion, CafeConsoleRegion::USA))\n\t\t\tplatformRegion = CafeConsoleRegion::USA;\n\t\treturn platformRegion;\n\t}\n\n\tvoid UnmountCurrentTitle()\n\t{\n        UnmountForegroundTitle();\n        fsc_unmount(\"/internal/code/\", FSC_PRIORITY_BASE);\n\t}\n\n\tvoid ShutdownTitle()\n\t{\n\t\tif(!sSystemRunning)\n\t\t\treturn;\n        coreinit::OSSchedulerEnd();\n        Latte_Stop();\n        // reset Cafe OS userspace modules\n        snd_core::reset();\n        coreinit::OSAlarm_Shutdown();\n        GX2::_GX2DriverReset();\n        nn::save::ResetToDefaultState();\n        coreinit::__OSDeleteAllActivePPCThreads();\n        RPLLoader_UnloadAll();\n\t\tfor(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it)\n\t\t\t(*it)->TitleStop();\n        // reset Cemu subsystems\n        PPCRecompiler_Shutdown();\n        GraphicPack2::Reset();\n        UnmountCurrentTitle();\n        MlcStorageUnmountAllTitles();\n        UnmountBaseDirectories();\n        DestroyMemorySpace();\n\t\tsSystemRunning = false;\n\t}\n\n\t/* Virtual mlc storage */\n\n\tvoid InitVirtualMlcStorage()\n\t{\n\t\t// starting with Cemu 1.27.0 /vol/storage_mlc01/ is virtualized, meaning that it doesn't point to one singular host os folder anymore\n\t\t// instead it now uses a more complex solution to source titles with various formats (folder, wud, wua) from the game paths and host mlc path\n\n\t\t// todo - mount /vol/storage_mlc01/ with base priority to the host mlc?\n\n\t\t// since mounting titles is an expensive operation we have to avoid mounting all titles at once\n\t\t// only the current title gets mounted immediately, every other title should be mounted lazily on first access\n\n\t\t// always mount the currently running title\n\t\tif (sGameInfo_ForegroundTitle.GetBase().IsValid())\n\t\t\tMlcStorageMountTitle(sGameInfo_ForegroundTitle.GetBase());\n\t\tif (sGameInfo_ForegroundTitle.GetUpdate().IsValid())\n\t\t\tMlcStorageMountTitle(sGameInfo_ForegroundTitle.GetUpdate());\n\t\tfor(auto& it : sGameInfo_ForegroundTitle.GetAOC())\n\t\t\tMlcStorageMountTitle(it);\n\n\t\t// setup system for lazy-mounting of other known titles\n\t\t// todo - how to handle this?\n\t\t// when something iterates /vol/storage_mlc01/usr/title/ we can use a fake FS device mounted to /vol/storage_mlc01/usr/title and sys/title that simulates the title id folders\n\t\t// the same device would then have to mount titles when their folders are actually accessed\n\t}\n\n\t// /vol/storage_mlc01/<usr or sys>/title/<titleIdHigh>/<titleIdLow>\n\tstd::string GetMlcStoragePath(TitleId titleId)\n\t{\n\t\tTitleIdParser tip(titleId);\n\t\treturn fmt::format(\"/vol/storage_mlc01/{}/title/{:08x}/{:08x}\", tip.IsSystemTitle() ? \"sys\" : \"usr\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t}\n\n\tstd::map<TitleId, TitleInfo*> m_mlcMountedTitles;\n\n\t// mount title to our virtual MLC storage\n\t// /vol/storage_mlc01/<usr or sys>/title/<titleIdHigh>/<titleIdLow>\n\tvoid MlcStorageMountTitle(TitleInfo& titleInfo)\n\t{\n\t\tif (!titleInfo.IsValid())\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t\treturn;\n\t\t}\n\t\tTitleId titleId = titleInfo.GetAppTitleId();\n\t\tif (m_mlcMountedTitles.find(titleId) != m_mlcMountedTitles.end())\n\t\t\treturn;\n\t\tstd::string mlcStoragePath = GetMlcStoragePath(titleId);\n\t\tTitleInfo* mountTitleInfo = new TitleInfo(titleInfo);\n\t\tif (!mountTitleInfo->Mount(mlcStoragePath, \"\", FSC_PRIORITY_BASE))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to mount title to virtual storage\");\n\t\t\tdelete mountTitleInfo;\n\t\t\treturn;\n\t\t}\n\t\tm_mlcMountedTitles.emplace(titleId, mountTitleInfo);\n\t}\n\n\tvoid MlcStorageMountTitle(TitleId titleId)\n\t{\n\t\tTitleInfo titleInfo;\n\t\tif (!CafeTitleList::GetFirstByTitleId(titleId, titleInfo))\n\t\t\treturn;\n\t\tMlcStorageMountTitle(titleInfo);\n\t}\n\n\tvoid MlcStorageMountAllTitles()\n\t{\n\t\tstd::vector<uint64> titleIds = CafeTitleList::GetAllTitleIds();\n\t\tfor (auto& it : titleIds)\n\t\t\tMlcStorageMountTitle(it);\n\t}\n\n    void MlcStorageUnmountAllTitles()\n    {\n        for(auto& it : m_mlcMountedTitles)\n        {\n            std::string mlcStoragePath = GetMlcStoragePath(it.first);\n            it.second->Unmount(mlcStoragePath);\n        }\n        m_mlcMountedTitles.clear();\n    }\n\n\tuint32 GetRPXHashBase()\n\t{\n\t\treturn currentBaseApplicationHash;\n\t}\n\n\tuint32 GetRPXHashUpdated()\n\t{\n\t\treturn currentUpdatedApplicationHash;\n\t}\n\n\tvoid RequestRecreateCanvas()\n\t{\n\t\ts_implementation->CafeRecreateCanvas();\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/CafeSystem.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"util/helpers/Semaphore.h\"\n#include \"Cafe/TitleList/TitleId.h\"\n#include \"config/CemuConfig.h\"\n\nenum class CosCapabilityBits : uint64;\nenum class CosCapabilityGroup : uint32;\n\nnamespace CafeSystem\n{\n\tclass SystemImplementation\n\t{\n\tpublic:\n\t\tvirtual void CafeRecreateCanvas() = 0;\n\t};\n\n\tenum class PREPARE_STATUS_CODE\n\t{\n\t\tSUCCESS,\n\t\tINVALID_RPX,\n\t\tUNABLE_TO_MOUNT, // failed to mount through TitleInfo (most likely caused by an invalid or outdated path)\n\t};\n\n\tvoid Initialize();\n\tvoid SetImplementation(SystemImplementation* impl);\n    void Shutdown();\n\n\tPREPARE_STATUS_CODE PrepareForegroundTitle(TitleId titleId);\n\tPREPARE_STATUS_CODE PrepareForegroundTitleFromStandaloneRPX(const fs::path& path);\n\tvoid LaunchForegroundTitle();\n\tbool IsTitleRunning();\n\n\tbool GetOverrideArgStr(std::vector<std::string>& args);\n\tvoid SetOverrideArgs(std::span<std::string> args);\n\tvoid UnsetOverrideArgs();\n\n\tTitleId GetForegroundTitleId();\n\tuint16 GetForegroundTitleVersion();\n\tuint32 GetForegroundTitleSDKVersion();\n\tCafeConsoleRegion GetForegroundTitleRegion();\n\tCafeConsoleRegion GetPlatformRegion();\n\tstd::string GetForegroundTitleName();\n\tstd::string GetForegroundTitleArgStr();\n\tuint32 GetForegroundTitleOlvAccesskey();\n\tCosCapabilityBits GetForegroundTitleCosCapabilities(CosCapabilityGroup group);\n\n\tvoid ShutdownTitle();\n\n\tstd::string GetMlcStoragePath(TitleId titleId);\n\tvoid MlcStorageMountAllTitles();\n\n\tstd::string GetInternalVirtualCodeFolder();\n\n\tuint32 GetRPXHashBase();\n\tuint32 GetRPXHashUpdated();\n\n\tvoid RequestRecreateCanvas();\n};\n\nextern RPLModule* applicationRPX;\n\nextern std::atomic_bool g_isGPUInitFinished;\n"
  },
  {
    "path": "src/Cafe/Filesystem/FST/FST.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"Common/FileStream.h\"\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"Cafe/Filesystem/WUD/wud.h\"\n#include \"util/crypto/aes128.h\"\n#include \"openssl/sha.h\" /* SHA1 / SHA256 */\n#include \"fstUtil.h\"\n\n#include \"FST.h\"\n#include \"KeyCache.h\"\n\n#include \"boost/range/adaptor/reversed.hpp\"\n\n#define SET_FST_ERROR(__code) \tif (errorCodeOut) *errorCodeOut = ErrorCode::__code\n\nstatic_assert(sizeof(NCrypto::AesIv) == 16); // make sure IV is actually 16 bytes\n\nclass FSTDataSource\n{\npublic:\n\tvirtual uint64 readData(uint16 clusterIndex, uint64 clusterOffset, uint64 offset, void* data, uint64 size) = 0;\n\tvirtual ~FSTDataSource() {};\n\nprotected:\n\tFSTDataSource() {};\n\n\tbool m_isOpen;\n};\n\nclass FSTDataSourceWUD : public FSTDataSource\n{\npublic:\n\n\tstatic FSTDataSourceWUD* Open(const fs::path& path)\n\t{\n\t\twud_t* wudFile = wud_open(path);\n\t\tif (!wudFile)\n\t\t\treturn nullptr;\n\t\tFSTDataSourceWUD* ds = new FSTDataSourceWUD();\n\t\tds->m_wudFile = wudFile;\n\t\treturn ds;\n\t}\n\n\tvoid SetBaseOffset(uint64 baseOffset)\n\t{\n\t\tm_baseOffset = baseOffset;\n\t}\n\n\tuint64 GetBaseOffset() const\n\t{\n\t\treturn m_baseOffset;\n\t}\n\n\tuint64 readData(uint16 clusterIndex, uint64 clusterOffset, uint64 offset, void* data, uint64 size) override\n\t{\n\t\tcemu_assert_debug(size <= 0xFFFFFFFF);\n\t\treturn wud_readData(m_wudFile, data, (uint32)size, clusterOffset + offset + m_baseOffset);\n\t}\n\n\t~FSTDataSourceWUD() override\n\t{\n\t\tif(m_wudFile)\n\t\t\twud_close(m_wudFile);\n\t}\n\nprotected:\n\tFSTDataSourceWUD() {}\t\n\twud_t* m_wudFile;\n\tuint64 m_baseOffset{};\n\tstd::vector<uint64> m_clusterOffset;\n};\n\nclass FSTDataSourceApp : public FSTDataSource\n{\npublic:\n\tstatic FSTDataSourceApp* Open(fs::path path, NCrypto::TMDParser& tmd)\n\t{\n\t\tstd::vector<std::unique_ptr<FileStream>> clusterFile;\n\t\tuint32 maxIndex = 0;\n\t\tfor (auto& itr : tmd.GetContentList())\n\t\t\tmaxIndex = std::max(maxIndex, (uint32)itr.index);\n\t\tclusterFile.resize(maxIndex + 1);\n\t\t// open all the app files\n\t\tfor (auto& itr : tmd.GetContentList())\n\t\t{\n\t\t\tFileStream* appFile = FileStream::openFile2(path / fmt::format(\"{:08x}.app\", itr.contentId));\n\t\t\tif (!appFile)\n\t\t\t\treturn nullptr;\n\t\t\tclusterFile[itr.index].reset(appFile);\n\t\t}\n\t\t// construct FSTDataSourceApp\n\t\tFSTDataSourceApp* dsApp = new FSTDataSourceApp(std::move(clusterFile));\n\t\treturn dsApp;\n\t}\n\n\tuint64 readData(uint16 clusterIndex, uint64 clusterOffset, uint64 offset, void* data, uint64 size) override\n\t{\n\t\t// ignore clusterOffset for .app files since each file is already relative to the cluster base\n\t\tcemu_assert_debug(clusterIndex < m_clusterFile.size());\n\t\tcemu_assert_debug(m_clusterFile[clusterIndex].get());\n\t\tcemu_assert_debug(size <= 0xFFFFFFFF);\n\t\tif (!m_clusterFile[clusterIndex].get())\n\t\t\treturn 0;\n\t\tm_clusterFile[clusterIndex].get()->SetPosition(offset);\n\t\treturn m_clusterFile[clusterIndex].get()->readData(data, (uint32)size);\n\t}\n\n\t~FSTDataSourceApp() override\n\t{\n\t}\n\nprivate:\n\tFSTDataSourceApp(std::vector<std::unique_ptr<FileStream>>&& clusterFiles)\n\t{\n\t\tm_clusterFile = std::move(clusterFiles);\n\t}\n\n\tstd::vector<std::unique_ptr<FileStream>> m_clusterFile;\n};\n\nconstexpr size_t DISC_SECTOR_SIZE = 0x8000;\n\nstruct DiscHeaderA\n{\n\t// header in first sector (0x0)\n\tuint8 productCode[22]; // ?\n};\n\nstruct DiscHeaderB\n{\n\t// header at 0x10000\n\tstatic constexpr uint32 MAGIC_VALUE = 0xCC549EB9;\n\n\t/* +0x00 */ uint32be magic;\n};\n\nstatic_assert(sizeof(DiscHeaderB) == 0x04);\n\nstruct DiscPartitionTableHeader\n{\n\t// header at 0x18000, encrypted\n\tstatic constexpr uint32 MAGIC_VALUE = 0xCCA6E67B;\n\n\t/* +0x00 */ uint32be magic;\n\t/* +0x04 */ uint32be blockSize; // must be 0x8000?\n\t/* +0x08 */ uint8 partitionTableHash[20]; // hash of the data range at +0x800 to end of sector (0x8000)\n\t/* +0x1C */ uint32be numPartitions;\n};\n\nstatic_assert(sizeof(DiscPartitionTableHeader) == 0x20);\n\nstruct DiscPartitionTableEntry\n{\n\t/* +0x00 */ uint8be partitionName[31];\n\t/* +0x1F */ uint8be numAddresses; // ?\n\t/* +0x20 */ uint32be partitionAddress; // this is an array?\n\t/* +0x24 */ uint8 padding[0x80 - 0x24];\n};\n\nstatic_assert(sizeof(DiscPartitionTableEntry) == 0x80);\n\nstruct DiscPartitionHeader\n{\n\t// header at the beginning of each partition\n\tstatic constexpr uint32 MAGIC_VALUE = 0xCC93A4F5;\n\n\t/* +0x00 */ uint32be magic;\n\t/* +0x04 */ uint32be sectorSize; // must match DISC_SECTOR_SIZE for hashed blocks\n\n\t/* +0x08 */ uint32be ukn008;\n\t/* +0x0C */ uint32be ukn00C; // h3 array size?\n\t/* +0x10 */ uint32be h3HashNum;\n\t/* +0x14 */ uint32be fstSize; // in bytes\n\t/* +0x18 */ uint32be fstSector; // relative to partition start\n\t/* +0x1C */ uint32be ukn01C;\n\t/* +0x20 */ uint32be ukn020;\n\n\t// the hash and encryption mode for the FST cluster\n\t/* +0x24 */ uint8 fstHashType;\n\t/* +0x25 */ uint8 fstEncryptionType; // purpose of this isn't really understood. Maybe it controls which key is being used? (1 -> disc key, 2 -> partition key)\n\n\t/* +0x26 */ uint8be versionA;\n\t/* +0x27 */ uint8be ukn027; // also a version field?\n\n\t// there is an array at +0x40 ? Related to H3 list. Also related to value at +0x0C and h3HashNum\n\t/* +0x28 */ uint8be _uknOrPadding028[0x18];\n\t/* +0x40 */ uint8be h3HashArray[32]; // dynamic size. Only present if fstHashType != 0\n};\n\nstatic_assert(sizeof(DiscPartitionHeader) == 0x40+0x20);\n\nbool FSTVolume::FindDiscKey(const fs::path& path, NCrypto::AesKey& discTitleKey)\n{\n\tstd::unique_ptr<FSTDataSourceWUD> dataSource(FSTDataSourceWUD::Open(path));\n\tif (!dataSource)\n\t\treturn false;\n\n\t// read section of header which should only contain zero bytes if decrypted\n\tuint8 header[16*3];\n\tif (dataSource->readData(0, 0, 0x18000 + 0x100, header, sizeof(header)) != sizeof(header))\n\t\treturn false;\n\n\t// try all the keys\n\tuint8 headerDecrypted[sizeof(header)-16];\n\tfor (sint32 i = 0; i < 0x7FFFFFFF; i++)\n\t{\n\t\tuint8* key128 = KeyCache_GetAES128(i);\n\t\tif (key128 == NULL)\n\t\t\tbreak;\n\t\tAES128_CBC_decrypt(headerDecrypted, header + 16, sizeof(headerDecrypted), key128, header);\n\t\tif (std::all_of(headerDecrypted, headerDecrypted + sizeof(headerDecrypted), [](const uint8 v) {return v == 0; }))\n\t\t{\n\t\t\t// key found\n\t\t\tstd::memcpy(discTitleKey.b, key128, 16);\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n// open WUD image using key cache\n// if no matching key is found then keyFound will return false\nFSTVolume* FSTVolume::OpenFromDiscImage(const fs::path& path, ErrorCode* errorCodeOut)\n{\n\tSET_FST_ERROR(UNKNOWN_ERROR);\n\tKeyCache_Prepare();\n\tNCrypto::AesKey discTitleKey;\n\tif (!FindDiscKey(path, discTitleKey))\n\t{\n\t\tSET_FST_ERROR(DISC_KEY_MISSING);\n\t\treturn nullptr;\n\t}\n\treturn OpenFromDiscImage(path, discTitleKey, errorCodeOut);\n}\n\n// open WUD image\nFSTVolume* FSTVolume::OpenFromDiscImage(const fs::path& path, NCrypto::AesKey& discTitleKey, ErrorCode* errorCodeOut)\n\n{\n\t// WUD images support multiple partitions, each with their own key and FST\n\t// the process for loading game data FSTVolume from a WUD image is as follows:\n\t// 1) parse WUD headers and verify\n\t// 2) read SI partition FST\n\t// 3) find main GM partition\n\t// 4) use SI information to get titleKey for GM partition\n\t// 5) Load FST for GM\n\tSET_FST_ERROR(UNKNOWN_ERROR);\n\tstd::unique_ptr<FSTDataSourceWUD> dataSource(FSTDataSourceWUD::Open(path));\n\tif (!dataSource)\n\t\treturn nullptr;\n\t// check HeaderA (only contains product code?)\n\tDiscHeaderA headerA{};\n\tif (dataSource->readData(0, 0, 0, &headerA, sizeof(headerA)) != sizeof(headerA))\n\t\treturn nullptr;\n\t// check HeaderB\n\tDiscHeaderB headerB{};\n\tif (dataSource->readData(0, 0, DISC_SECTOR_SIZE * 2, &headerB, sizeof(headerB)) != sizeof(headerB))\n\t\treturn nullptr;\n\tif (headerB.magic != headerB.MAGIC_VALUE)\n\t\treturn nullptr;\n\n\t// read, decrypt and parse partition table\n\tuint8 partitionSector[DISC_SECTOR_SIZE];\n\tif (dataSource->readData(0, 0, DISC_SECTOR_SIZE * 3, partitionSector, DISC_SECTOR_SIZE) != DISC_SECTOR_SIZE)\n\t\treturn nullptr;\n\tuint8 iv[16]{};\n\tAES128_CBC_decrypt(partitionSector, partitionSector, DISC_SECTOR_SIZE, discTitleKey.b, iv);\n\t// parse partition info\n\tDiscPartitionTableHeader* partitionHeader = (DiscPartitionTableHeader*)partitionSector;\n\tif (partitionHeader->magic != DiscPartitionTableHeader::MAGIC_VALUE)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Disc image rejected because decryption failed\");\n\t\treturn nullptr;\n\t}\n\tif (partitionHeader->blockSize != DISC_SECTOR_SIZE)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Disc image rejected because partition sector size is invalid\");\n\t\treturn nullptr;\n\t}\n\tuint32 numPartitions = partitionHeader->numPartitions;\n\tif (numPartitions > 30) // there is space for up to 240 partitions but we use a more reasonable limit\n\t{\n\t\tcemuLog_log(LogType::Force, \"Disc image rejected due to exceeding the partition limit (has {} partitions)\", numPartitions);\n\t\treturn nullptr;\n\t}\n\tDiscPartitionTableEntry* partitionArray = (DiscPartitionTableEntry*)(partitionSector + 0x800);\n\t// validate partitions and find SI partition\n\tuint32 siPartitionIndex = std::numeric_limits<uint32>::max();\n\tuint32 gmPartitionIndex = std::numeric_limits<uint32>::max();\n\tfor (uint32 i = 0; i < numPartitions; i++)\n\t{\n\t\tif (partitionArray[i].numAddresses != 1)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Disc image has unsupported partition with {} addresses\", (uint32)partitionArray[i].numAddresses);\n\t\t\treturn nullptr;\n\t\t}\n\t\tauto& name = partitionArray[i].partitionName;\n\t\tif (name[0] == 'S' && name[1] == 'I')\n\t\t{\n\t\t\tif (siPartitionIndex != std::numeric_limits<uint32>::max())\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Disc image has multiple SI partitions. Not supported\");\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\tsiPartitionIndex = i;\n\t\t}\n\t\tif (name[0] == 'G' && name[1] == 'M')\n\t\t{\n\t\t\tif (gmPartitionIndex == std::numeric_limits<uint32>::max())\n\t\t\t\tgmPartitionIndex = i; // we use the first GM partition we find. This is likely not correct but it seems to work for practically all disc images\n\t\t}\n\t}\n\tif (siPartitionIndex == std::numeric_limits<uint32>::max() || gmPartitionIndex == std::numeric_limits<uint32>::max())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Disc image has no SI or GM partition. Cannot read game data\");\n\t\treturn nullptr;\n\t}\n\n\t// read and verify partition headers for SI and GM\n\tauto readPartitionHeader = [&](DiscPartitionHeader& partitionHeader, uint32 partitionIndex) -> bool\n\t{\n\t\tcemu_assert_debug(dataSource->GetBaseOffset() == 0);\n\t\tif (dataSource->readData(0, 0, partitionArray[partitionIndex].partitionAddress * DISC_SECTOR_SIZE, &partitionHeader, sizeof(DiscPartitionHeader)) != sizeof(DiscPartitionHeader))\n\t\t\treturn false;\n\t\tif (partitionHeader.magic != partitionHeader.MAGIC_VALUE && partitionHeader.sectorSize != DISC_SECTOR_SIZE)\n\t\t\treturn false;\n\t\treturn true;\n\t};\n\n\t// SI partition\n\tDiscPartitionHeader partitionHeaderSI{};\n\tif (!readPartitionHeader(partitionHeaderSI, siPartitionIndex))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Disc image SI partition header is invalid\");\n\t\treturn nullptr;\n\t}\n\n\tcemu_assert_debug(partitionHeaderSI.fstHashType == 0);\n\tcemu_assert_debug(partitionHeaderSI.fstEncryptionType == 1);\n\t// todo - check other fields?\n\n\tif(partitionHeaderSI.fstHashType == 0 && partitionHeaderSI.h3HashNum != 0)\n\t\tcemuLog_log(LogType::Force, \"FST: Partition uses unhashed blocks but stores a non-zero amount of H3 hashes\");\n\n\t// GM partition\n\tDiscPartitionHeader partitionHeaderGM{};\n\tif (!readPartitionHeader(partitionHeaderGM, gmPartitionIndex))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Disc image GM partition header is invalid\");\n\t\treturn nullptr;\n\t}\n\tcemu_assert_debug(partitionHeaderGM.fstHashType == 1);\n\tcemu_assert_debug(partitionHeaderGM.fstEncryptionType == 2);\n\n\t// if decryption is necessary\n\t// load SI FST\n\tdataSource->SetBaseOffset((uint64)partitionArray[siPartitionIndex].partitionAddress * DISC_SECTOR_SIZE);\n\tauto siFST = OpenFST(dataSource.get(), (uint64)partitionHeaderSI.fstSector * DISC_SECTOR_SIZE, partitionHeaderSI.fstSize, &discTitleKey, static_cast<FSTVolume::ClusterHashMode>(partitionHeaderSI.fstHashType), nullptr);\n\tif (!siFST)\n\t\treturn nullptr;\n\tcemu_assert_debug(!(siFST->HashIsDisabled() && partitionHeaderSI.h3HashNum != 0)); // if hash is disabled, no H3 data may be present\n\t// load ticket file for partition that we want to decrypt\n\tNCrypto::ETicketParser ticketParser;\n\tstd::vector<uint8> ticketData = siFST->ExtractFile(fmt::format(\"{:02x}/title.tik\", gmPartitionIndex));\n\tif (ticketData.empty() || !ticketParser.parse(ticketData.data(), ticketData.size()))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Disc image ticket file is invalid\");\n\t\treturn nullptr;\n\t}\n#if 0\n\t// each SI partition seems to contain a title.tmd that we could parse and which should have information about the associated GM partition\n\t// but the console seems to ignore this file for disc images, at least when mounting, so we shouldn't rely on it either\n\tstd::vector<uint8> tmdData = siFST->ExtractFile(fmt::format(\"{:02x}/title.tmd\", gmPartitionIndex));\n\tif (tmdData.empty())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Disc image TMD file is missing\");\n\t\treturn nullptr;\n\t}\n\t// parse TMD\n\tNCrypto::TMDParser tmdParser;\n\tif (!tmdParser.parse(tmdData.data(), tmdData.size()))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Disc image TMD file is invalid\");\n\t\treturn nullptr;\n\t}\n#endif\n\tdelete siFST;\n\tNCrypto::AesKey gmTitleKey;\n\tticketParser.GetTitleKey(gmTitleKey);\n\t// load GM partition\n\tdataSource->SetBaseOffset((uint64)partitionArray[gmPartitionIndex].partitionAddress * DISC_SECTOR_SIZE);\n\tFSTVolume* r = OpenFST(std::move(dataSource), (uint64)partitionHeaderGM.fstSector * DISC_SECTOR_SIZE, partitionHeaderGM.fstSize, &gmTitleKey, static_cast<FSTVolume::ClusterHashMode>(partitionHeaderGM.fstHashType), nullptr);\n\tif (r)\n\t\tSET_FST_ERROR(OK);\n\tcemu_assert_debug(!(r->HashIsDisabled() && partitionHeaderGM.h3HashNum != 0)); // if hash is disabled, no H3 data may be present\n\treturn r;\n}\n\nFSTVolume* FSTVolume::OpenFromContentFolder(fs::path folderPath, ErrorCode* errorCodeOut)\n{\n\tSET_FST_ERROR(UNKNOWN_ERROR);\n\t// load TMD\n\tFileStream* tmdFile = FileStream::openFile2(folderPath / \"title.tmd\");\n\tif (!tmdFile)\n\t\treturn nullptr;\n\tstd::vector<uint8> tmdData;\n\ttmdFile->extract(tmdData);\n\tdelete tmdFile;\n\tNCrypto::TMDParser tmdParser;\n\tif (!tmdParser.parse(tmdData.data(), tmdData.size()))\n\t{\n\t\tSET_FST_ERROR(BAD_TITLE_TMD);\n\t\treturn nullptr;\n\t}\n\t// load ticket\n\tFileStream* ticketFile = FileStream::openFile2(folderPath / \"title.tik\");\n\tif (!ticketFile)\n\t{\n\t\tSET_FST_ERROR(TITLE_TIK_MISSING);\n\t\treturn nullptr;\n\t}\n\tstd::vector<uint8> ticketData;\n\tticketFile->extract(ticketData);\n\tdelete ticketFile;\n\tNCrypto::ETicketParser ticketParser;\n\tif (!ticketParser.parse(ticketData.data(), ticketData.size()))\n\t{\n\t\tSET_FST_ERROR(BAD_TITLE_TIK);\n\t\treturn nullptr;\n\t}\n\tNCrypto::AesKey titleKey;\n\tticketParser.GetTitleKey(titleKey);\n\t// open data source\n\tstd::unique_ptr<FSTDataSource> dataSource(FSTDataSourceApp::Open(folderPath, tmdParser));\n\tif (!dataSource)\n\t\treturn nullptr;\n\t// get info about FST from first cluster (todo - is this correct or does the TMD store info about the fst?)\n\tClusterHashMode fstHashMode = ClusterHashMode::RAW;\n\tuint32 fstSize = 0;\n\tfor (auto& itr : tmdParser.GetContentList())\n\t{\n\t\tif (itr.index == 0)\n\t\t{\n\t\t\tif (HAS_FLAG(itr.contentFlags, NCrypto::TMDParser::TMDContentFlags::FLAG_HASHED_CONTENT))\n\t\t\t\tfstHashMode = ClusterHashMode::HASH_INTERLEAVED;\n\t\t\tcemu_assert_debug(itr.size <= 0xFFFFFFFF);\n\t\t\tfstSize = (uint32)itr.size;\n\t\t}\n\t}\n\t// load FST\n\t// fstSize = size of first cluster?\n\tFSTVolume* fstVolume = FSTVolume::OpenFST(std::move(dataSource), 0, fstSize, &titleKey, fstHashMode, &tmdParser);\n\tif (fstVolume)\n\t\tSET_FST_ERROR(OK);\n\treturn fstVolume;\n}\n\nFSTVolume* FSTVolume::OpenFST(FSTDataSource* dataSource, uint64 fstOffset, uint32 fstSize, NCrypto::AesKey* partitionTitleKey, ClusterHashMode fstHashMode, NCrypto::TMDParser* optionalTMD)\n{\n\tcemu_assert_debug(fstHashMode != ClusterHashMode::RAW || fstHashMode != ClusterHashMode::RAW_STREAM);\n\tif (fstSize < sizeof(FSTHeader))\n\t\treturn nullptr;\n\tconstexpr uint64 FST_CLUSTER_OFFSET = 0;\n\tuint32 fstSizePadded = (fstSize + 15) & ~15; // pad to AES block size\n\t// read FST data and decrypt\n\tstd::vector<uint8> fstData(fstSizePadded);\n\tif (dataSource->readData(0, FST_CLUSTER_OFFSET, fstOffset, fstData.data(), fstSizePadded) != fstSizePadded)\n\t\treturn nullptr;\n\tuint8 iv[16]{};\n\tAES128_CBC_decrypt(fstData.data(), fstData.data(), fstSizePadded, partitionTitleKey->b, iv);\n\t// validate header\n\tFSTHeader* fstHeader = (FSTHeader*)fstData.data();\n\tconst void* fstEnd = fstData.data() + fstSize;\n\tif (fstHeader->magic != 0x46535400 || fstHeader->numCluster >= 0x1000)\n\t{\n\t\tcemuLog_log(LogType::Force, \"FST has invalid header\");\n\t\treturn nullptr;\n\t}\n\t// load cluster table\n\tuint32 numCluster = fstHeader->numCluster;\n\tFSTHeader_ClusterEntry* clusterDataTable = (FSTHeader_ClusterEntry*)(fstData.data() + sizeof(FSTHeader));\n\tif ((clusterDataTable + numCluster) > fstEnd)\n\t\treturn nullptr;\n\tstd::vector<FSTCluster> clusterTable;\n\tclusterTable.resize(numCluster);\n\tfor (size_t i = 0; i < numCluster; i++)\n\t{\n\t\tclusterTable[i].offset = clusterDataTable[i].offset;\n\t\tclusterTable[i].size = clusterDataTable[i].size;\n\t\tclusterTable[i].hashMode = static_cast<FSTVolume::ClusterHashMode>((uint8)clusterDataTable[i].hashMode);\n\t\tclusterTable[i].hasContentHash = false; // from the TMD file (H4?)\n\t}\n\t// if the TMD is available (when opening .app files) we can use the extra info from it to validate unhashed clusters\n\t// each content entry in the TMD corresponds to one cluster used by the FST\n\tif(optionalTMD)\n\t{\n\t\tif(numCluster != optionalTMD->GetContentList().size())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"FST: Number of clusters does not match TMD content list\");\n\t\t\treturn nullptr;\n\t\t}\n\t\tauto& contentList = optionalTMD->GetContentList();\n\t\tfor(size_t i=0; i<contentList.size(); i++)\n\t\t{\n\t\t\tauto& cluster = clusterTable[i];\n\t\t\tauto& content = contentList[i];\n\t\t\tcluster.hasContentHash = true;\n\t\t\tcluster.contentHashIsSHA1 = HAS_FLAG(contentList[i].contentFlags, NCrypto::TMDParser::TMDContentFlags::FLAG_SHA1);\n\t\t\tcluster.contentSize = content.size;\n\t\t\tstatic_assert(sizeof(content.hash32) == sizeof(cluster.contentHash32));\n\t\t\tmemcpy(cluster.contentHash32, content.hash32, sizeof(cluster.contentHash32));\n\t\t\t// if unhashed mode, then initialize the hash context\n\t\t\tif(cluster.hashMode == ClusterHashMode::RAW || cluster.hashMode == ClusterHashMode::RAW_STREAM)\n\t\t\t{\n\t\t\t\tcluster.singleHashCtx.reset(EVP_MD_CTX_new());\n\t\t\t\tEVP_DigestInit_ex(cluster.singleHashCtx.get(), cluster.contentHashIsSHA1 ? EVP_sha1() : EVP_sha256(), nullptr);\n\t\t\t}\n\t\t}\n\t}\n\t// preprocess FST table\n\tFSTHeader_FileEntry* fileTable = (FSTHeader_FileEntry*)(clusterDataTable + numCluster);\n\tif ((fileTable + 1) > fstEnd)\n\t\treturn nullptr;\n\tif (fileTable[0].GetType() != FSTHeader_FileEntry::TYPE::DIRECTORY)\n\t\treturn nullptr;\n\tuint32 numFileEntries = fileTable[0].size;\n\tif (numFileEntries == 0 || (fileTable + numFileEntries) > fstEnd)\n\t\treturn nullptr;\n\t// load name string table\n\tptrdiff_t nameLookupTableSize = ((const uint8*)fstEnd - (const uint8*)(fileTable + numFileEntries));\n\tif (nameLookupTableSize < 1)\n\t\treturn nullptr;\n\tstd::vector<char> nameStringTable(nameLookupTableSize);\n\tstd::memcpy(nameStringTable.data(), (fileTable + numFileEntries), nameLookupTableSize);\n\t// process FST\n\tstd::vector<FSTEntry> fstEntries;\n\tif (!ProcessFST(fileTable, numFileEntries, numCluster, nameStringTable, fstEntries))\n\t\treturn nullptr;\n\t// construct FSTVolume from the processed data\n\tFSTVolume* fstVolume = new FSTVolume();\n\tfstVolume->m_dataSource = dataSource;\n\tfstVolume->m_offsetFactor = fstHeader->offsetFactor;\n\tfstVolume->m_sectorSize = DISC_SECTOR_SIZE;\n\tfstVolume->m_partitionTitlekey = *partitionTitleKey;\n\tfstVolume->m_hashIsDisabled = fstHeader->hashIsDisabled != 0;\n\tfstVolume->m_cluster = std::move(clusterTable);\n\tfstVolume->m_entries = std::move(fstEntries);\n\tfstVolume->m_nameStringTable = std::move(nameStringTable);\n\treturn fstVolume;\n}\n\nFSTVolume* FSTVolume::OpenFST(std::unique_ptr<FSTDataSource> dataSource, uint64 fstOffset, uint32 fstSize, NCrypto::AesKey* partitionTitleKey, ClusterHashMode fstHashMode, NCrypto::TMDParser* optionalTMD)\n{\n\tFSTDataSource* ds = dataSource.release();\n\tFSTVolume* fstVolume = OpenFST(ds, fstOffset, fstSize, partitionTitleKey, fstHashMode, optionalTMD);\n\tif (!fstVolume)\n\t{\n\t\tdelete ds;\n\t\treturn nullptr;\n\t}\n\tfstVolume->m_sourceIsOwned = true;\n\treturn fstVolume;\n}\n\nbool FSTVolume::ProcessFST(FSTHeader_FileEntry* fileTable, uint32 numFileEntries, uint32 numCluster, std::vector<char>& nameStringTable, std::vector<FSTEntry>& fstEntries)\n{\n\tstruct DirHierachyInfo\n\t{\n\t\tDirHierachyInfo(uint32 parentIndex, uint32 endIndex) : parentIndex(parentIndex), endIndex(endIndex) {};\n\n\t\tuint32 parentIndex;\n\t\tuint32 endIndex;\n\t};\n\tstd::vector<DirHierachyInfo> currentDirEnd;\n\tcurrentDirEnd.reserve(32);\n\tcurrentDirEnd.emplace_back(0, numFileEntries); // create a fake parent for the root directory, the root's parent index is zero (referencing itself)\n\tuint32 currentIndex = 0;\n\tFSTHeader_FileEntry* pFileIn = fileTable + currentIndex;\n\tfstEntries.resize(numFileEntries);\n\tFSTEntry* pFileOut = fstEntries.data();\n\t// validate root directory\n\tif (pFileIn->GetType() != FSTHeader_FileEntry::TYPE::DIRECTORY || pFileIn->GetDirectoryEndIndex() != numFileEntries || pFileIn->GetDirectoryParent() != 0)\n\t{\n\t\tcemuLog_log(LogType::Force, \"FSTVolume::ProcessFST() - root node is invalid\");\n\t\treturn false;\n\t}\n\tfor (; currentIndex < numFileEntries; currentIndex++)\n\t{\n\t\twhile (currentIndex >= currentDirEnd.back().endIndex)\n\t\t\tcurrentDirEnd.pop_back();\n\t\t// process entry name\n\t\tuint32 nameOffset = pFileIn->GetNameOffset();\n\t\tuint32 pos = nameOffset;\n\t\twhile (true)\n\t\t{\n\t\t\tif (pos >= nameStringTable.size())\n\t\t\t\treturn false; // name exceeds string table\n\t\t\tif (nameStringTable[pos] == '\\0')\n\t\t\t\tbreak;\n\t\t\tpos++;\n\t\t}\n\t\tuint32 nameLen = pos - nameOffset;\n\t\tpFileOut->nameOffset = nameOffset;\n\t\tpFileOut->nameHash = _QuickNameHash(nameStringTable.data() + nameOffset, nameLen);\n\t\t// parent directory index\n\t\tpFileOut->parentDirIndex = currentDirEnd.back().parentIndex;\n\t\t//if (currentDirEnd.back().parentIndex == 0)\n\t\t//\tpFileOut->parentDirIndex = std::numeric_limits<uint32>::max();\n\t\t//else\n\t\t//\tpFileOut->parentDirIndex = currentDirEnd.back().parentIndex;\n\t\t// process type specific data\n\t\tauto entryType = pFileIn->GetType();\n\n\t\tuint8 flags = 0;\n\t\tif (pFileIn->HasFlagLink())\n\t\t\tflags |= FSTEntry::FLAG_LINK;\n\t\tif (pFileIn->HasUknFlag02())\n\t\t\tflags |= FSTEntry::FLAG_UKN02;\n\t\tpFileOut->SetFlags((FSTEntry::FLAGS)flags);\n\n\t\tif (entryType == FSTHeader_FileEntry::TYPE::FILE)\n\t\t{\n\t\t\tbool isSysLink = entryType == FSTHeader_FileEntry::TYPE::FILE;\n\t\t\tif (pFileIn->clusterIndex >= numCluster)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"FST: File references cluster out of range\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcemu_assert_debug(pFileIn->flagsOrPermissions != 0x4004);\n\t\t\tpFileOut->SetType(FSTEntry::TYPE::FILE);\n\t\t\tpFileOut->fileInfo.fileOffset = pFileIn->offset;\n\t\t\tpFileOut->fileInfo.fileSize = pFileIn->size;\n\t\t\tpFileOut->fileInfo.clusterIndex = pFileIn->clusterIndex;\n\t\t}\n\t\telse if (entryType == FSTHeader_FileEntry::TYPE::DIRECTORY)\n\t\t{\n\t\t\tcemu_assert_debug(pFileIn->flagsOrPermissions != 0x4004);\n\t\t\tpFileOut->SetType(FSTEntry::TYPE::DIRECTORY);\n\t\t\tuint32 endIndex = pFileIn->GetDirectoryEndIndex();\n\t\t\tuint32 parentIndex = pFileIn->GetDirectoryParent();\n\t\t\tif (endIndex < currentIndex || endIndex > currentDirEnd.back().endIndex)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"FST: Directory range out of bounds\");\n\t\t\t\treturn false; // dir index out of range\n\t\t\t}\n\t\t\tif (parentIndex != currentDirEnd.back().parentIndex)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"FST: Parent index does not match\");\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcurrentDirEnd.emplace_back(currentIndex, endIndex);\n\t\t\tpFileOut->dirInfo.endIndex = endIndex;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"FST: Encountered node with unknown type\");\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn false;\n\t\t}\n\t\tpFileIn++;\n\t\tpFileOut++;\n\t}\n\t// end remaining directory hierarchy with final index\n\tcemu_assert_debug(currentIndex == numFileEntries);\n\twhile (!currentDirEnd.empty() && currentIndex >= currentDirEnd.back().endIndex)\n\t\tcurrentDirEnd.pop_back();\n\tcemu_assert_debug(currentDirEnd.empty()); // no entries should remain\n\treturn true;\n}\n\nuint32 FSTVolume::GetFileCount() const\n{\n\tuint32 fileCount = 0;\n\tfor (auto& itr : m_entries)\n\t{\n\t\tif (itr.GetType() == FSTEntry::TYPE::FILE)\n\t\t\tfileCount++;\n\t}\n\treturn fileCount;\n}\n\nbool FSTVolume::OpenFile(std::string_view path, FSTFileHandle& fileHandleOut, bool openOnlyFiles)\n{\n\tFSCPath fscPath(path);\n\tif (fscPath.GetNodeCount() == 0)\n\t{\n\t\t// empty path pointers to root directory\n\t\tif(openOnlyFiles)\n\t\t\treturn false;\n\t\tfileHandleOut.m_fstIndex = 0;\n\t\treturn true;\n\t}\n\n\t// scan directory and find sub folder or file\n\t// skips iterating subdirectories\n\tauto findSubentry = [this](size_t firstIndex, size_t lastIndex, std::string_view nodeName) -> sint32\n\t{\n\t\tuint16 nodeHash = _QuickNameHash(nodeName.data(), nodeName.size());\n\t\tsize_t index = firstIndex;\n\t\twhile (index < lastIndex)\n\t\t{\n\t\t\tif (m_entries[index].nameHash == nodeHash && MatchFSTEntryName(m_entries[index], nodeName))\n\t\t\t\treturn (sint32)index;\n\t\t\tif (m_entries[index].GetType() == FSTEntry::TYPE::DIRECTORY)\n\t\t\t\tindex = m_entries[index].dirInfo.endIndex;\n\t\t\telse\n\t\t\t\tindex++;\n\t\t}\n\t\treturn -1;\n\t};\n\n\t// current FST range we iterate, starting with root directory which covers all entries\n\tuint32 parentIndex = std::numeric_limits<uint32>::max();\n\tsize_t curDirStart = 1; // skip root directory\n\tsize_t curDirEnd = m_entries[0].dirInfo.endIndex;\n\n\t// find the subdirectory\n\tfor (size_t nodeIndex = 0; nodeIndex < fscPath.GetNodeCount() - 1; nodeIndex++)\n\t{\n\t\t// get hash of node name\n\t\tsint32 fstIndex = findSubentry(curDirStart, curDirEnd, fscPath.GetNodeName(nodeIndex));\n\t\tif (fstIndex < 0)\n\t\t\treturn false;\n\t\tif (m_entries[fstIndex].GetType() != FSTEntry::TYPE::DIRECTORY)\n\t\t\treturn false;\n\t\tparentIndex = fstIndex;\n\t\tcurDirStart = fstIndex + 1;\n\t\tcurDirEnd = m_entries[fstIndex].dirInfo.endIndex;\n\t}\n\t// find the entry\n\tsint32 fstIndex = findSubentry(curDirStart, curDirEnd, fscPath.GetNodeName(fscPath.GetNodeCount() - 1));\n\tif (fstIndex < 0)\n\t\treturn false;\n\tif (openOnlyFiles && m_entries[fstIndex].GetType() != FSTEntry::TYPE::FILE)\n\t\treturn false;\n\tfileHandleOut.m_fstIndex = fstIndex;\n\treturn true;\n}\n\nbool FSTVolume::IsDirectory(const FSTFileHandle& fileHandle) const\n{\n\tcemu_assert_debug(fileHandle.m_fstIndex < m_entries.size());\n\treturn m_entries[fileHandle.m_fstIndex].GetType() == FSTEntry::TYPE::DIRECTORY;\n};\n\nbool FSTVolume::IsFile(const FSTFileHandle& fileHandle) const\n{\n\tcemu_assert_debug(fileHandle.m_fstIndex < m_entries.size());\n\treturn m_entries[fileHandle.m_fstIndex].GetType() == FSTEntry::TYPE::FILE;\n};\n\nbool FSTVolume::HasLinkFlag(const FSTFileHandle& fileHandle) const\n{\n\tcemu_assert_debug(fileHandle.m_fstIndex < m_entries.size());\n\treturn HAS_FLAG(m_entries[fileHandle.m_fstIndex].GetFlags(), FSTEntry::FLAGS::FLAG_LINK);\n};\n\nstd::string_view FSTVolume::GetName(const FSTFileHandle& fileHandle) const\n{\n\tif (fileHandle.m_fstIndex > m_entries.size())\n\t\treturn \"\";\n\tconst char* entryName = m_nameStringTable.data() + m_entries[fileHandle.m_fstIndex].nameOffset;\n\treturn entryName;\n}\n\nstd::string FSTVolume::GetPath(const FSTFileHandle& fileHandle) const\n{\n\tstd::string path;\n\tauto& entry = m_entries[fileHandle.m_fstIndex];\n\t// get parent chain\n\tboost::container::small_vector<uint32, 8> parentChain;\n\tif (entry.HasNonRootNodeParent())\n\t{\n\t\tparentChain.emplace_back(entry.parentDirIndex);\n\t\tauto* parentItr = &m_entries[entry.parentDirIndex];\n\t\twhile (parentItr->HasNonRootNodeParent())\n\t\t{\n\t\t\tcemu_assert_debug(parentItr->GetType() == FSTEntry::TYPE::DIRECTORY);\n\t\t\tparentChain.emplace_back(parentItr->parentDirIndex);\n\t\t\tparentItr = &m_entries[parentItr->parentDirIndex];\n\t\t}\n\t}\n\t// build path\n\tcemu_assert_debug(parentChain.size() <= 1); // test this case\n\tfor (auto& itr : parentChain | boost::adaptors::reversed)\n\t{\n\t\tconst char* name = m_nameStringTable.data() + m_entries[itr].nameOffset;\n\t\tpath.append(name);\n\t\tpath.push_back('/');\n\t}\n\t// append node name\n\tconst char* name = m_nameStringTable.data() + entry.nameOffset;\n\tpath.append(name);\n\treturn path;\n}\n\nuint32 FSTVolume::GetFileSize(const FSTFileHandle& fileHandle) const\n{\n\tif (m_entries[fileHandle.m_fstIndex].GetType() != FSTEntry::TYPE::FILE)\n\t\treturn 0;\n\treturn m_entries[fileHandle.m_fstIndex].fileInfo.fileSize;\n}\n\nuint32 FSTVolume::ReadFile(FSTFileHandle& fileHandle, uint32 offset, uint32 size, void* dataOut)\n{\n\tFSTEntry& entry = m_entries[fileHandle.m_fstIndex];\n\tif (entry.GetType() != FSTEntry::TYPE::FILE)\n\t\treturn 0;\n\tcemu_assert_debug(!HAS_FLAG(entry.GetFlags(), FSTEntry::FLAGS::FLAG_LINK));\n\tFSTCluster& cluster = m_cluster[entry.fileInfo.clusterIndex];\n\tif (cluster.hashMode == ClusterHashMode::RAW || cluster.hashMode == ClusterHashMode::RAW_STREAM)\n\t\treturn ReadFile_HashModeRaw(entry.fileInfo.clusterIndex, entry, offset, size, dataOut);\n\telse if (cluster.hashMode == ClusterHashMode::HASH_INTERLEAVED)\n\t\treturn ReadFile_HashModeHashed(entry.fileInfo.clusterIndex, entry, offset, size, dataOut);\n\tcemu_assert_debug(false);\n\treturn 0;\n}\n\nconstexpr size_t BLOCK_SIZE = 0x10000;\nconstexpr size_t BLOCK_HASH_SIZE = 0x0400;\nconstexpr size_t BLOCK_FILE_SIZE = 0xFC00;\n\nstruct FSTRawBlock\n{\n\tstd::vector<uint8> rawData; // unhashed block size depends on sector size field in partition header\n};\n\nstruct FSTHashedBlock\n{\n\tuint8 rawData[BLOCK_SIZE];\n\n\tuint8* getHashData()\n\t{\n\t\treturn rawData;\n\t}\n\n\tuint8* getH0Hash(uint32 index)\n\t{\n\t\tcemu_assert_debug(index < 16);\n\t\treturn getHashData() + 20 * index;\n\t}\n\n\tuint8* getH1Hash(uint32 index)\n\t{\n\t\tcemu_assert_debug(index < 16);\n\t\treturn getHashData() + (20 * 16) * 1 + 20 * index;\n\t}\n\n\tuint8* getH2Hash(uint32 index)\n\t{\n\t\tcemu_assert_debug(index < 16);\n\t\treturn getHashData() + (20 * 16) * 2 + 20 * index;\n\t}\n\n\tuint8* getFileData()\n\t{\n\t\treturn rawData + BLOCK_HASH_SIZE;\n\t}\n\n\tuint8* getH0Hash(size_t index)\n\t{\n\t\tcemu_assert_debug(index < 16);\n\t\treturn rawData + index * 20;\n\t}\n};\n\nstatic_assert(sizeof(FSTHashedBlock) == BLOCK_SIZE);\n\nstruct FSTCachedRawBlock\n{\n\tFSTRawBlock blockData;\n\tNCrypto::AesIv ivForNextBlock;\n\tuint64 lastAccess;\n};\n\nstruct FSTCachedHashedBlock \n{\n\tFSTHashedBlock blockData;\n\tuint64 lastAccess;\n};\n\n// Checks cache fill state and if necessary drops least recently accessed block from the cache. Optionally allows to recycle the released cache entry to cut down cost of memory allocation and clearing\nvoid FSTVolume::TrimCacheIfRequired(FSTCachedRawBlock** droppedRawBlock, FSTCachedHashedBlock** droppedHashedBlock)\n{\n\t// calculate size used by cache\n\tsize_t cacheSize = 0;\n\tfor (auto& itr : m_cacheDecryptedRawBlocks)\n\t\tcacheSize += itr.second->blockData.rawData.size();\n\tfor (auto& itr : m_cacheDecryptedHashedBlocks)\n\t\tcacheSize += sizeof(FSTCachedHashedBlock) + sizeof(FSTHashedBlock);\n\t// only trim if cache is full (larger than 2MB)\n\tif (cacheSize < 2*1024*1024) // 2MB\n\t\treturn;\n\t// scan both cache lists to find least recently accessed block to drop\n\tauto dropRawItr = std::min_element(m_cacheDecryptedRawBlocks.begin(), m_cacheDecryptedRawBlocks.end(), [](const auto& a, const auto& b) -> bool\n\t\t\t\t\t\t\t\t\t\t{ return a.second->lastAccess < b.second->lastAccess; });\n\tauto dropHashedItr = std::min_element(m_cacheDecryptedHashedBlocks.begin(), m_cacheDecryptedHashedBlocks.end(), [](const auto& a, const auto& b) -> bool\n\t\t\t\t\t\t\t\t\t\t{ return a.second->lastAccess < b.second->lastAccess; });\n\tuint64 lastAccess = std::numeric_limits<uint64>::max();\n\tif(dropRawItr != m_cacheDecryptedRawBlocks.end())\n\t\tlastAccess = dropRawItr->second->lastAccess;\n\tif(dropHashedItr != m_cacheDecryptedHashedBlocks.end())\n\t\tlastAccess = std::min<uint64>(lastAccess, dropHashedItr->second->lastAccess);\n\tif(dropRawItr != m_cacheDecryptedRawBlocks.end() && dropRawItr->second->lastAccess == lastAccess)\n\t{\n\t\tif (droppedRawBlock)\n\t\t\t*droppedRawBlock = dropRawItr->second;\n\t\telse\n\t\t\tdelete dropRawItr->second;\n\t\tm_cacheDecryptedRawBlocks.erase(dropRawItr);\n\t\treturn;\n\t}\n\telse if(dropHashedItr != m_cacheDecryptedHashedBlocks.end() && dropHashedItr->second->lastAccess == lastAccess)\n\t{\n\t\tif (droppedHashedBlock)\n\t\t\t*droppedHashedBlock = dropHashedItr->second;\n\t\telse\n\t\t\tdelete dropHashedItr->second;\n\t\tm_cacheDecryptedHashedBlocks.erase(dropHashedItr);\n\t}\n}\n\nvoid FSTVolume::DetermineUnhashedBlockIV(uint32 clusterIndex, uint32 blockIndex, NCrypto::AesIv& ivOut)\n{\n\tivOut = {};\n\tif(blockIndex == 0)\n\t{\n\t\tivOut.iv[0] = (uint8)(clusterIndex >> 8);\n\t\tivOut.iv[1] = (uint8)(clusterIndex >> 0);\n\t}\n\telse\n\t{\n\t\t// the last 16 encrypted bytes of the previous block are the IV (AES CBC)\n\t\t// if the previous block is cached we can grab the IV from there. Otherwise we have to read the 16 bytes from the data source\n\t\tuint32 prevBlockIndex = blockIndex - 1;\n\t\tuint64 cacheBlockId = ((uint64)clusterIndex << (64 - 16)) | (uint64)prevBlockIndex;\n\t\tauto itr = m_cacheDecryptedRawBlocks.find(cacheBlockId);\n\t\tif (itr != m_cacheDecryptedRawBlocks.end())\n\t\t{\n\t\t\tivOut = itr->second->ivForNextBlock;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert(m_sectorSize >= NCrypto::AesIv::SIZE);\n\t\t\tuint64 clusterOffset = (uint64)m_cluster[clusterIndex].offset * m_sectorSize;\n\t\t\tNCrypto::AesIv prevIV{};\n\t\t\tif (m_dataSource->readData(clusterIndex, clusterOffset, blockIndex * m_sectorSize - NCrypto::AesIv::SIZE, prevIV.iv, NCrypto::AesIv::SIZE) != NCrypto::AesIv::SIZE)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to read IV for raw FST block\");\n\t\t\t\tm_detectedCorruption = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tivOut = prevIV;\n\t\t}\n\t}\n}\n\nFSTCachedRawBlock* FSTVolume::GetDecryptedRawBlock(uint32 clusterIndex, uint32 blockIndex)\n{\n\tFSTCluster& cluster = m_cluster[clusterIndex];\n\tuint64 clusterOffset = (uint64)cluster.offset * m_sectorSize;\n\t// generate id for cache\n\tuint64 cacheBlockId = ((uint64)clusterIndex << (64 - 16)) | (uint64)blockIndex;\n\t// lookup block in cache\n\tFSTCachedRawBlock* block = nullptr;\n\tauto itr = m_cacheDecryptedRawBlocks.find(cacheBlockId);\n\tif (itr != m_cacheDecryptedRawBlocks.end())\n\t{\n\t\tblock = itr->second;\n\t\tblock->lastAccess = ++m_cacheAccessCounter;\n\t\treturn block;\n\t}\n\t// if cache already full, drop least recently accessed block and recycle FSTCachedRawBlock object if possible\n\tTrimCacheIfRequired(&block, nullptr);\n\tif (!block)\n\t\tblock = new FSTCachedRawBlock();\n\tblock->blockData.rawData.resize(m_sectorSize);\n\t// block not cached, read new\n\tblock->lastAccess = ++m_cacheAccessCounter;\n\tif (m_dataSource->readData(clusterIndex, clusterOffset, blockIndex * m_sectorSize, block->blockData.rawData.data(), m_sectorSize) != m_sectorSize)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to read raw FST block\");\n\t\tdelete block;\n\t\tm_detectedCorruption = true;\n\t\treturn nullptr;\n\t}\n\t// decrypt hash data\n\tNCrypto::AesIv iv{};\n\tDetermineUnhashedBlockIV(clusterIndex, blockIndex, iv);\n\tstd::copy(block->blockData.rawData.data() + m_sectorSize - NCrypto::AesIv::SIZE, block->blockData.rawData.data() + m_sectorSize, block->ivForNextBlock.iv);\n\tAES128_CBC_decrypt(block->blockData.rawData.data(), block->blockData.rawData.data(), m_sectorSize, m_partitionTitlekey.b, iv.iv);\n\t// if this is the next block, then hash it\n\tif(cluster.hasContentHash)\n\t{\n\t\tif(cluster.singleHashNumBlocksHashed == blockIndex)\n\t\t{\n\t\t\tcemu_assert_debug(!(cluster.contentSize % m_sectorSize)); // size should be multiple of sector size? Regardless, the hashing code below can handle non-aligned sizes\n\t\t\tbool isLastBlock = blockIndex == (std::max<uint32>(cluster.contentSize / m_sectorSize, 1) - 1);\n\t\t\tuint32 hashSize = m_sectorSize;\n\t\t\tif(isLastBlock)\n\t\t\t\thashSize = cluster.contentSize - (uint64)blockIndex*m_sectorSize;\n\t\t\tEVP_DigestUpdate(cluster.singleHashCtx.get(), block->blockData.rawData.data(), hashSize);\n\t\t\tcluster.singleHashNumBlocksHashed++;\n\t\t\tif(isLastBlock)\n\t\t\t{\n\t\t\t\tuint8 hash[32];\n\t\t\t\tEVP_DigestFinal_ex(cluster.singleHashCtx.get(), hash, nullptr);\n\t\t\t\tif(memcmp(hash, cluster.contentHash32, cluster.contentHashIsSHA1 ? 20 : 32) != 0)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"FST: Raw section hash mismatch\");\n\t\t\t\t\tdelete block;\n\t\t\t\t\tm_detectedCorruption = true;\n\t\t\t\t\treturn nullptr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// register in cache\n\tm_cacheDecryptedRawBlocks.emplace(cacheBlockId, block);\n\treturn block;\n}\n\nFSTCachedHashedBlock* FSTVolume::GetDecryptedHashedBlock(uint32 clusterIndex, uint32 blockIndex)\n{\n\tconst FSTCluster& cluster = m_cluster[clusterIndex];\n\tuint64 clusterOffset = (uint64)cluster.offset * m_sectorSize;\n\t// generate id for cache\n\tuint64 cacheBlockId = ((uint64)clusterIndex << (64 - 16)) | (uint64)blockIndex;\n\t// lookup block in cache\n\tFSTCachedHashedBlock* block = nullptr;\n\tauto itr = m_cacheDecryptedHashedBlocks.find(cacheBlockId);\n\tif (itr != m_cacheDecryptedHashedBlocks.end())\n\t{\n\t\tblock = itr->second;\n\t\tblock->lastAccess = ++m_cacheAccessCounter;\n\t\treturn block;\n\t}\n\t// if cache already full, drop least recently accessed block and recycle FSTCachedHashedBlock object if possible\n\tTrimCacheIfRequired(nullptr, &block);\n\tif (!block)\n\t\tblock = new FSTCachedHashedBlock();\n\t// block not cached, read new\n\tblock->lastAccess = ++m_cacheAccessCounter;\n\tif (m_dataSource->readData(clusterIndex, clusterOffset, blockIndex * BLOCK_SIZE, block->blockData.rawData, BLOCK_SIZE) != BLOCK_SIZE)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to read hashed FST block\");\n\t\tdelete block;\n\t\tm_detectedCorruption = true;\n\t\treturn nullptr;\n\t}\n\t// decrypt hash data\n\tuint8 iv[16]{};\n\tAES128_CBC_decrypt(block->blockData.getHashData(), block->blockData.getHashData(), BLOCK_HASH_SIZE, m_partitionTitlekey.b, iv);\n\t// decrypt file data\n\tAES128_CBC_decrypt(block->blockData.getFileData(), block->blockData.getFileData(), BLOCK_FILE_SIZE, m_partitionTitlekey.b, block->blockData.getH0Hash(blockIndex%16));\n\t// compare with H0 to verify data integrity\n\tNCrypto::CHash160 h0;\n\tSHA1(block->blockData.getFileData(), BLOCK_FILE_SIZE, h0.b);\n\tuint32 h0Index = (blockIndex % 4096);\n\tif (memcmp(h0.b, block->blockData.getH0Hash(h0Index & 0xF), sizeof(h0.b)) != 0)\n\t{\n\t\tcemuLog_log(LogType::Force, \"FST: Hash H0 mismatch in hashed block (section {} index {})\", clusterIndex, blockIndex);\n\t\tdelete block;\n\t\tm_detectedCorruption = true;\n\t\treturn nullptr;\n\t}\n\t// register in cache\n\tm_cacheDecryptedHashedBlocks.emplace(cacheBlockId, block);\n\treturn block;\n}\n\nuint32 FSTVolume::ReadFile_HashModeRaw(uint32 clusterIndex, FSTEntry& entry, uint32 readOffset, uint32 readSize, void* dataOut)\n{\n\tuint8* dataOutU8 = (uint8*)dataOut;\n\tif (readOffset >= entry.fileInfo.fileSize)\n\t\treturn 0;\n\telse if ((readOffset + readSize) >= entry.fileInfo.fileSize)\n\t\treadSize = (entry.fileInfo.fileSize - readOffset);\n\tuint64 absFileOffset = entry.fileInfo.fileOffset * m_offsetFactor + readOffset;\n\tuint32 remainingReadSize = readSize;\n\twhile (remainingReadSize > 0)\n\t{\n\t\tconst FSTCachedRawBlock* rawBlock = this->GetDecryptedRawBlock(clusterIndex, absFileOffset/m_sectorSize);\n\t\tif (!rawBlock)\n\t\t\tbreak;\n\t\tuint32 blockOffset = (uint32)(absFileOffset % m_sectorSize);\n\t\tuint32 bytesToRead = std::min<uint32>(remainingReadSize, m_sectorSize - blockOffset);\n\t\tstd::memcpy(dataOutU8, rawBlock->blockData.rawData.data() + blockOffset, bytesToRead);\n\t\tdataOutU8 += bytesToRead;\n\t\tremainingReadSize -= bytesToRead;\n\t\tabsFileOffset += bytesToRead;\n\t}\n\treturn readSize - remainingReadSize;\n}\n\nuint32 FSTVolume::ReadFile_HashModeHashed(uint32 clusterIndex, FSTEntry& entry, uint32 readOffset, uint32 readSize, void* dataOut)\n{\n\t/*\n\t\tData is divided into 0x10000 (64KiB) blocks\n\t\tLayout:\n\t\t+0x0000\t\tHash20[16]\t\tH0 hashes\n\t\t+0x0140\t\tHash20[16]\t\tH1 hashes\n\t\t+0x0240\t\tHash20[16]\t\tH2 hashes\n\t\t+0x03C0\t\tuint8[64]\t\tpadding\n\t\t+0x0400\t\tuint8[0xFC00]\tfileData\n\t\n\t\tThe hash part (0-0x3FF) uses AES-CBC with IV initialized to zero\n\t\tThe file part (0x400 - 0xFFFF) uses AES-CBC with IV initialized to block->h0Hash[blockIndex % 16]\n\n\t\tThe hash data itself is calculated over 4096 blocks. Where each individual H0 entry hashes a single 0xFC00 file data block (unencrypted)\n\t\tEach H1 hash is calculated from 16 H0 hashes\n\t\tEach H2 hash is calculated from 16 H1 hashes.\n\t\tThe  H3 hash is calculated from 16 H2 hashes.\n\t\tThus for each 4096 block group we end up with:\n\t\t4096 H0 hashes\n\t\t256  H1 hashes\n\t\t16\t H2 hashes\n\t\t1    H3 hash\n\n\t\tThe embedded H0/H1 hashes per block are only a slice of the larger array. Whereas H2 always get embedded as a whole, due to only having 16 hashes in total\n\t\tThere is also a H4 hash that covers all H3 hashes and is stored in the TMD\n\n\t*/\n\n\tconst FSTCluster& cluster = m_cluster[clusterIndex];\n\tuint64 fileReadOffset = entry.fileInfo.fileOffset * m_offsetFactor + readOffset;\n\tuint32 blockIndex = (uint32)(fileReadOffset / BLOCK_FILE_SIZE);\n\tuint32 bytesRemaining = readSize;\n\tuint32 offsetWithinBlock = (uint32)(fileReadOffset % BLOCK_FILE_SIZE);\n\twhile (bytesRemaining > 0)\n\t{\n\t\tFSTCachedHashedBlock* block = GetDecryptedHashedBlock(clusterIndex, blockIndex);\n\t\tif (!block)\n\t\t\treturn 0;\n\t\tuint32 bytesToRead = std::min(bytesRemaining, (uint32)BLOCK_FILE_SIZE - offsetWithinBlock);\n\t\tstd::memcpy(dataOut, block->blockData.getFileData() + offsetWithinBlock, bytesToRead);\n\t\tdataOut = (uint8*)dataOut + bytesToRead;\n\t\tbytesRemaining -= bytesToRead;\n\t\tblockIndex++;\n\t\toffsetWithinBlock = 0;\n\t}\n\treturn readSize - bytesRemaining;\n}\n\nbool FSTVolume::OpenDirectoryIterator(std::string_view path, FSTDirectoryIterator& directoryIteratorOut)\n{\n\tFSTFileHandle fileHandle;\n\tif (!OpenFile(path, fileHandle, false))\n\t\treturn false;\n\tif (!IsDirectory(fileHandle))\n\t\treturn false;\n\tauto const& fstEntry = m_entries[fileHandle.m_fstIndex];\n\tdirectoryIteratorOut.dirHandle = fileHandle;\n\tdirectoryIteratorOut.startIndex = fileHandle.m_fstIndex + 1;\n\tdirectoryIteratorOut.endIndex = fstEntry.dirInfo.endIndex;\n\tdirectoryIteratorOut.currentIndex = directoryIteratorOut.startIndex;\n\treturn true;\n}\n\nbool FSTVolume::Next(FSTDirectoryIterator& directoryIterator, FSTFileHandle& fileHandleOut)\n{\n\tif (directoryIterator.currentIndex >= directoryIterator.endIndex)\n\t\treturn false;\n\tauto const& fstEntry = m_entries[directoryIterator.currentIndex];\n\tfileHandleOut.m_fstIndex = directoryIterator.currentIndex;\n\tif (fstEntry.GetType() == FSTEntry::TYPE::DIRECTORY)\n\t{\n\t\tcemu_assert_debug(fstEntry.dirInfo.endIndex > directoryIterator.currentIndex);\n\t\tdirectoryIterator.currentIndex = fstEntry.dirInfo.endIndex;\n\t}\n\telse\n\t\tdirectoryIterator.currentIndex++;\n\treturn true;\n}\n\nFSTVolume::~FSTVolume()\n{\n\tfor (auto& itr : m_cacheDecryptedRawBlocks)\n\t\tdelete itr.second;\n\tfor (auto& itr : m_cacheDecryptedHashedBlocks)\n\t\tdelete itr.second;\n\tif (m_sourceIsOwned)\n\t\tdelete m_dataSource;\n}\n\nbool FSTVerifier::VerifyContentFile(FileStream* fileContent, const NCrypto::AesKey* key, uint32 contentIndex, uint32 contentSize, uint32 contentSizePadded, bool isSHA1, const uint8* tmdContentHash)\n{\n\tcemu_assert_debug(isSHA1); // test this case\n\tcemu_assert_debug(((contentSize+0xF)&~0xF) == contentSizePadded);\n\n\tstd::vector<uint8> buffer;\n\tbuffer.resize(64 * 1024);\n\tif ((uint32)fileContent->GetSize() != contentSizePadded)\n\t\treturn false;\n\tfileContent->SetPosition(0);\n\tuint8 iv[16]{};\n\tiv[0] = (contentIndex >> 8) & 0xFF;\n\tiv[1] = (contentIndex >> 0) & 0xFF;\n\t// raw content\n\tuint64 remainingBytes = contentSize;\n\tuint8 calculatedHash[SHA256_DIGEST_LENGTH];\n\n\tEVP_MD_CTX *ctx = EVP_MD_CTX_new();\n\tEVP_DigestInit(ctx, isSHA1 ? EVP_sha1() : EVP_sha256());\n\n\twhile (remainingBytes > 0)\n\t{\n\t\tuint32 bytesToRead = (uint32)std::min(remainingBytes, (uint64)buffer.size());\n\t\tuint32 bytesToReadPadded = ((bytesToRead + 0xF) & ~0xF);\n\t\tuint32 bytesRead = fileContent->readData(buffer.data(), bytesToReadPadded);\n\t\tif (bytesRead != bytesToReadPadded)\n\t\t\treturn false;\n\t\tAES128_CBC_decrypt_updateIV(buffer.data(), buffer.data(), bytesToReadPadded, key->b, iv);\n\t\tEVP_DigestUpdate(ctx, buffer.data(), bytesToRead);\n\t\tremainingBytes -= bytesToRead;\n\t}\n\tunsigned int md_len;\n\tEVP_DigestFinal_ex(ctx, calculatedHash, &md_len);\n\tEVP_MD_CTX_free(ctx);\n\treturn memcmp(calculatedHash, tmdContentHash, md_len) == 0;\n}\n\nbool FSTVerifier::VerifyHashedContentFile(FileStream* fileContent, const NCrypto::AesKey* key, uint32 contentIndex, uint32 contentSize, uint32 contentSizePadded, bool isSHA1, const uint8* tmdContentHash)\n{\n\tif (!isSHA1)\n\t\treturn false; // not supported\n\tif ((contentSize % sizeof(FSTHashedBlock)) != 0)\n\t\treturn false;\n\tif ((uint32)fileContent->GetSize() != contentSize)\n\t\treturn false;\n\tfileContent->SetPosition(0);\n\n\tstd::vector<NCrypto::CHash160> h0List(4096);\n\n\tFSTHashedBlock block;\n\tuint32 numBlocks = contentSize / sizeof(FSTHashedBlock);\n\tfor (uint32 blockIndex = 0; blockIndex < numBlocks; blockIndex++)\n\t{\n\t\tif (fileContent->readData(&block, sizeof(FSTHashedBlock)) != sizeof(FSTHashedBlock))\n\t\t\treturn false;\n\t\tuint32 h0Index = (blockIndex % 4096);\n\t\t// decrypt hash data and file data\n\t\tuint8 iv[16]{};\n\t\tAES128_CBC_decrypt(block.getHashData(), block.getHashData(), BLOCK_HASH_SIZE, key->b, iv);\n\t\tAES128_CBC_decrypt(block.getFileData(), block.getFileData(), BLOCK_FILE_SIZE, key->b, block.getH0Hash(blockIndex % 16));\n\n\t\t// generate H0 hash and compare\n\t\tNCrypto::CHash160 h0;\n\t\tSHA1(block.getFileData(), BLOCK_FILE_SIZE, h0.b);\n\t\tif (memcmp(h0.b, block.getH0Hash(h0Index & 0xF), sizeof(h0.b)) != 0)\n\t\t\treturn false;\n\t\tstd::memcpy(h0List[h0Index].b, h0.b, sizeof(h0.b));\n\n\t\t// Sixteen H0 hashes become one H1 hash\n\t\tif (((h0Index + 1) % 16) == 0 && h0Index > 0)\n\t\t{\n\t\t\tuint32 h1Index = ((h0Index - 15) / 16);\n\n\t\t\tNCrypto::CHash160 h1;\n\t\t\tSHA1((unsigned char *) (h0List.data() + h1Index * 16), sizeof(NCrypto::CHash160) * 16, h1.b);\n\t\t\tif (memcmp(h1.b, block.getH1Hash(h1Index&0xF), sizeof(h1.b)) != 0)\n\t\t\t\treturn false;\n\t\t}\n\t\t// todo - repeat same for H1 and H2\n\t\t//        At the end all H3 hashes are hashed into a single H4 hash which is then compared with the content hash from the TMD\n\n\t\t// Checking only H0 and H1 is sufficient enough for verifying if the file data is intact\n\t\t// but if we wanted to be strict and only allow correctly signed data we would have to hash all the way up to H4\n\t}\n\treturn true;\n}\n\nvoid FSTVolumeTest()\n{\n\tFSTPathUnitTest();\n}\n"
  },
  {
    "path": "src/Cafe/Filesystem/FST/FST.h",
    "content": "#pragma once\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"openssl/evp.h\"\n\nstruct FSTFileHandle\n{\n\tfriend class FSTVolume;\nprivate:\n\tuint32 m_fstIndex;\n};\n\nstruct FSTDirectoryIterator\n{\n\tfriend class FSTVolume;\n\n\tconst FSTFileHandle& GetDirHandle() const\n\t{\n\t\treturn dirHandle;\n\t}\nprivate:\n    FSTFileHandle dirHandle;\n\tuint32 startIndex;\n\tuint32 endIndex;\n\tuint32 currentIndex;\n};\n\nclass FSTVolume\n{\npublic:\n\tenum class ErrorCode\n  \t{\n\t\tOK = 0,\n\t\tUNKNOWN_ERROR = 1,\n\t  \tDISC_KEY_MISSING = 2,\n\t  \tTITLE_TIK_MISSING = 3,\n\t    BAD_TITLE_TMD = 4,\n\t    BAD_TITLE_TIK = 5,\n  \t};\n\n\tstatic bool FindDiscKey(const fs::path& path, NCrypto::AesKey& discTitleKey);\n\n\tstatic FSTVolume* OpenFromDiscImage(const fs::path& path, NCrypto::AesKey& discTitleKey, ErrorCode* errorCodeOut = nullptr);\n\tstatic FSTVolume* OpenFromDiscImage(const fs::path& path, ErrorCode* errorCodeOut = nullptr);\n\tstatic FSTVolume* OpenFromContentFolder(fs::path folderPath, ErrorCode* errorCodeOut = nullptr);\n\n\t~FSTVolume();\n\n\tuint32 GetFileCount() const;\n\tbool HasCorruption() const { return m_detectedCorruption; }\n\n\tbool OpenFile(std::string_view path, FSTFileHandle& fileHandleOut, bool openOnlyFiles = false);\n\n\t// file and directory functions\n\tbool IsDirectory(const FSTFileHandle& fileHandle) const;\n\tbool IsFile(const FSTFileHandle& fileHandle) const;\n\tbool HasLinkFlag(const FSTFileHandle& fileHandle) const;\n\n\tstd::string_view GetName(const FSTFileHandle& fileHandle) const;\n\tstd::string GetPath(const FSTFileHandle& fileHandle) const;\n\n\t// file functions\n\tuint32 GetFileSize(const FSTFileHandle& fileHandle) const;\n\tuint32 ReadFile(FSTFileHandle& fileHandle, uint32 offset, uint32 size, void* dataOut);\n\n\t// directory iterator\n\tbool OpenDirectoryIterator(std::string_view path, FSTDirectoryIterator& directoryIteratorOut);\n\tbool Next(FSTDirectoryIterator& directoryIterator, FSTFileHandle& fileHandleOut);\n\n\t// helper function to read whole file\n\tstd::vector<uint8> ExtractFile(std::string_view path, bool* success = nullptr)\n\t{\n\t\tif (success)\n\t\t\t*success = false;\n\t\tstd::vector<uint8> fileData;\n\t\tFSTFileHandle fileHandle;\n\t\tif (!OpenFile(path, fileHandle, true))\n\t\t\treturn fileData;\n\t\tfileData.resize(GetFileSize(fileHandle));\n\t\tReadFile(fileHandle, 0, (uint32)fileData.size(), fileData.data());\n\t\tif (success)\n\t\t\t*success = true;\n\t\treturn fileData;\n\t}\n\nprivate:\n\t/* FST data (in memory) */\n\tenum class ClusterHashMode : uint8\n\t{\n\t\tRAW = 0, // raw data + encryption, no hashing?\n\t  \tRAW_STREAM = 1, // raw data + encryption, with hash stored in tmd?\n\t\tHASH_INTERLEAVED = 2, // hashes + raw interleaved in 0x10000 blocks (0x400 bytes of hashes at the beginning, followed by 0xFC00 bytes of data)\n\t};\n\n\tstruct FSTCluster\n\t{\n\t\tFSTCluster() : singleHashCtx(nullptr, &EVP_MD_CTX_free) {}\n\n\t\tuint32 offset;\n\t\tuint32 size;\n\t\tClusterHashMode hashMode;\n\t\t// extra data if TMD is available\n\t\tbool hasContentHash;\n\t\tuint8 contentHash32[32];\n\t\tbool contentHashIsSHA1; // if true then it's SHA1 (with extra bytes zeroed out), otherwise it's SHA256\n\t\tuint64 contentSize; // size of the content (in blocks)\n\t\t// hash context for single hash mode (content hash must be available)\n\t\tstd::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> singleHashCtx; // unique_ptr to make this move-only\n\t\tuint32 singleHashNumBlocksHashed{0};\n\t};\n\n\tstruct FSTEntry\n\t{\n\t\tenum class TYPE : uint8\n\t\t{\n\t\t\tFILE,\n\t\t\tDIRECTORY,\n\t\t};\n\n\t\tenum FLAGS : uint8\n\t\t{\n\t\t\tFLAG_NONE = 0x0,\n\t\t\tFLAG_LINK = 0x1,\n\t\t\tFLAG_UKN02 = 0x2, // seen in Super Mario Galaxy. Used for vWii files?\n\t\t};\n\n\t\tuint32 nameOffset;\n\t\tuint32 parentDirIndex; // index of parent directory\n\t\tuint16 nameHash;\n\t\tuint8 typeAndFlags;\n\n\t\tTYPE GetType() const\n\t\t{\n\t\t\treturn (TYPE)(typeAndFlags & 0xF);\n\t\t}\n\n\t\tvoid SetType(TYPE t)\n\t\t{\n\t\t\ttypeAndFlags &= ~0x0F;\n\t\t\ttypeAndFlags |= ((uint8)t);\n\t\t}\n\n\t\tFLAGS GetFlags() const\n\t\t{\n\t\t\treturn (FLAGS)(typeAndFlags >> 4);\n\t\t}\n\n\t\tvoid SetFlags(FLAGS flags)\n\t\t{\n\t\t\ttypeAndFlags &= ~0xF0;\n\t\t\ttypeAndFlags |= ((uint8)flags << 4);\n\t\t}\n\n\t\t// note: The root node is not considered a valid parent\n\t\tbool HasNonRootNodeParent() const\n\t\t{\n\t\t\treturn parentDirIndex != 0;\n\t\t}\n\n\t\tunion\n\t\t{\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tuint32 endIndex;\n\t\t\t}dirInfo;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tuint32 fileOffset;\n\t\t\t\tuint32 fileSize;\n\t\t\t\tuint16 clusterIndex;\n\t\t\t}fileInfo;\n\t\t};\n\t};\n\n\tclass FSTDataSource* m_dataSource;\n\tbool m_sourceIsOwned{};\n\tuint32 m_sectorSize{}; // for cluster offsets\n\tuint32 m_offsetFactor{}; // for file offsets\n\tbool m_hashIsDisabled{}; // disables hash verification (for all clusters of this volume?)\n\tstd::vector<FSTCluster> m_cluster;\n\tstd::vector<FSTEntry> m_entries;\n\tstd::vector<char> m_nameStringTable;\n\tNCrypto::AesKey m_partitionTitlekey;\n\tbool m_detectedCorruption{false};\n\n\tbool HashIsDisabled() const\n\t{\n\t\treturn m_hashIsDisabled;\n\t}\n\n\t/* Cache for decrypted raw and hashed blocks */\n\tstd::unordered_map<uint64, struct FSTCachedRawBlock*> m_cacheDecryptedRawBlocks;\n\tstd::unordered_map<uint64, struct FSTCachedHashedBlock*> m_cacheDecryptedHashedBlocks;\n\tuint64 m_cacheAccessCounter{};\n\n\tvoid DetermineUnhashedBlockIV(uint32 clusterIndex, uint32 blockIndex, NCrypto::AesIv& ivOut);\n\n\tstruct FSTCachedRawBlock* GetDecryptedRawBlock(uint32 clusterIndex, uint32 blockIndex);\n\tstruct FSTCachedHashedBlock* GetDecryptedHashedBlock(uint32 clusterIndex, uint32 blockIndex);\n\n\tvoid TrimCacheIfRequired(struct FSTCachedRawBlock** droppedRawBlock, struct FSTCachedHashedBlock** droppedHashedBlock);\n\n\t/* File reading */\n\tuint32 ReadFile_HashModeRaw(uint32 clusterIndex, FSTEntry& entry, uint32 readOffset, uint32 readSize, void* dataOut);\n\tuint32 ReadFile_HashModeHashed(uint32 clusterIndex, FSTEntry& entry, uint32 readOffset, uint32 readSize, void* dataOut);\n\n\t/* FST parsing */\n\tstruct FSTHeader\n\t{\n\t\t/* +0x00 */ uint32be magic;\n\t\t/* +0x04 */ uint32be offsetFactor;\n\t\t/* +0x08 */ uint32be numCluster;\n\t\t/* +0x0C */ uint8be hashIsDisabled;\n\t\t/* +0x0D */ uint8be ukn0D;\n\t\t/* +0x0E */ uint8be ukn0E;\n\t\t/* +0x0F */ uint8be ukn0F;\n\t\t/* +0x10 */ uint32be ukn10;\n\t\t/* +0x14 */ uint32be ukn14;\n\t\t/* +0x18 */ uint32be ukn18;\n\t\t/* +0x1C */ uint32be ukn1C;\n\t};\n\n\tstatic_assert(sizeof(FSTHeader) == 0x20);\n\n\tstruct FSTHeader_ClusterEntry\n\t{\n\t\t/* +0x00 */ uint32be offset;\n\t\t/* +0x04 */ uint32be size;\n\t\t/* +0x08 */ uint64be ownerTitleId;\n\t\t/* +0x10 */ uint32be groupId;\n\t\t/* +0x14 */ uint8be  hashMode;\n\t\t/* +0x15 */ uint8be  padding[0xB]; // ?\n\t};\n\tstatic_assert(sizeof(FSTHeader_ClusterEntry) == 0x20);\n\n\tstruct FSTHeader_FileEntry\n\t{\n\t\tenum class TYPE : uint8\n\t\t{\n\t\t\tFILE = 0,\n\t\t\tDIRECTORY = 1,\n\t\t};\n\n\t\t/* +0x00 */ uint32be typeAndNameOffset;\n\t\t/* +0x04 */ uint32be offset; // for directories: parent directory index\n\t\t/* +0x08 */ uint32be size; // for directories: end index\n\t\t/* +0x0C */ uint16be flagsOrPermissions; // three entries, each one shifted by 4. (so 0xXYZ). Possible bits per value seem to be 0x1 and 0x4 ? These are probably permissions\n\t\t/* +0x0E */ uint16be clusterIndex;\n\n\t\tTYPE GetType()\n\t\t{\n\t\t\tuint8 v = GetTypeFlagField();\n\t\t\tcemu_assert_debug((v & ~0x83) == 0); // unknown type/flag\n\t\t\treturn static_cast<TYPE>(v & 0x01);\n\t\t}\n\n\t\tbool HasFlagLink()\n\t\t{\n\t\t\tuint8 v = GetTypeFlagField();\n\t\t\treturn (v & 0x80) != 0;\n\t\t}\n\n\t\tbool HasUknFlag02()\n\t\t{\n\t\t\tuint8 v = GetTypeFlagField();\n\t\t\treturn (v & 0x02) != 0;\n\t\t}\n\n\t\tuint32 GetNameOffset()\n\t\t{\n\t\t\treturn (uint32)typeAndNameOffset & 0xFFFFFF;\n\t\t}\n\n\t\tuint32 GetDirectoryParent()\n\t\t{\n\t\t\treturn offset;\n\t\t}\n\n\t\tuint32 GetDirectoryEndIndex()\n\t\t{\n\t\t\treturn size;\n\t\t}\n\n\tprivate:\n\t\tuint8 GetTypeFlagField()\n\t\t{\n\t\t\treturn static_cast<uint8>((typeAndNameOffset >> 24) & 0xFF);\n\t\t}\n\t};\n\n\tstatic_assert(sizeof(FSTHeader_FileEntry) == 0x10);\n\n\tstatic FSTVolume* OpenFST(FSTDataSource* dataSource, uint64 fstOffset, uint32 fstSize, NCrypto::AesKey* partitionTitleKey, ClusterHashMode fstHashMode, NCrypto::TMDParser* optionalTMD);\n\tstatic FSTVolume* OpenFST(std::unique_ptr<FSTDataSource> dataSource, uint64 fstOffset, uint32 fstSize, NCrypto::AesKey* partitionTitleKey, ClusterHashMode fstHashMode, NCrypto::TMDParser* optionalTMD);\n\tstatic bool ProcessFST(FSTHeader_FileEntry* fileTable, uint32 numFileEntries, uint32 numCluster, std::vector<char>& nameStringTable, std::vector<FSTEntry>& fstEntries);\n\n\tbool MatchFSTEntryName(FSTEntry& entry, std::string_view comparedName)\n\t{\n\t\tconst char* entryName = m_nameStringTable.data() + entry.nameOffset;\n\t\tconst char* comparedNameCur = comparedName.data();\n\t\tconst char* comparedNameEnd = comparedName.data() + comparedName.size();\n\t\twhile (comparedNameCur < comparedNameEnd)\n\t\t{\n\t\t\tuint8 c1 = *entryName;\n\t\t\tuint8 c2 = *comparedNameCur;\n\t\t\tif (c1 >= (uint8)'A' && c1 <= (uint8)'Z')\n\t\t\t\tc1 = c1 - ((uint8)'A' - (uint8)'a');\n\t\t\tif (c2 >= (uint8)'A' && c2 <= (uint8)'Z')\n\t\t\t\tc2 = c2 - ((uint8)'A' - (uint8)'a');\n\t\t\tif (c1 != c2)\n\t\t\t\treturn false;\n\t\t\tentryName++;\n\t\t\tcomparedNameCur++;\n\t\t}\n\t\treturn *entryName == '\\0'; // all the characters match, check for same length\n\t}\n\n\t// we utilize hashes to accelerate string comparisons when doing path lookups\n\tstatic uint16 _QuickNameHash(const char* fileName, size_t len)\n\t{\n\t\tuint16 v = 0;\n\t\tconst char* fileNameEnd = fileName + len;\n\t\twhile (fileName < fileNameEnd)\n\t\t{\n\t\t\tuint8 c = (uint8)*fileName;\n\t\t\tif (c >= (uint8)'A' && c <= (uint8)'Z')\n\t\t\t\tc = c - ((uint8)'A' - (uint8)'a');\n\t\t\tv += (uint16)c;\n\t\t\tv = (v >> 3) | (v << 13);\n\t\t\tfileName++;\n\t\t}\n\t\treturn v;\n\t}\n\n};\n\nclass FSTVerifier\n{\npublic:\n\tstatic bool VerifyContentFile(class FileStream* fileContent, const NCrypto::AesKey* key, uint32 contentIndex, uint32 contentSize, uint32 contentSizePadded, bool isSHA1, const uint8* tmdContentHash);\n\tstatic bool VerifyHashedContentFile(class FileStream* fileContent, const NCrypto::AesKey* key, uint32 contentIndex, uint32 contentSize, uint32 contentSizePadded, bool isSHA1, const uint8* tmdContentHash);\n\n};"
  },
  {
    "path": "src/Cafe/Filesystem/FST/KeyCache.cpp",
    "content": "#include <mutex>\n\n#include \"Cemu/Logging/CemuLogging.h\"\n#include \"WindowSystem.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/crypto/aes128.h\"\n#include \"Common/FileStream.h\"\n#include \"util/helpers/StringHelpers.h\"\n\nstd::mutex mtxKeyCache;\n\nstruct KeyCacheEntry\n{\n\tuint8 aes128key[16];\n};\n\nstd::vector<KeyCacheEntry> g_keyCache;\n\nbool strishex(std::string_view str)\n{\n\tfor(size_t i=0; i<str.size(); i++)\n\t{\n\t\tchar c = str[i];\n\t\tif( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') )\n\t\t\tcontinue;\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n/*\n * Returns AES-128 key from the key cache\n * nullptr is returned if index >= max_keys\n */\nuint8* KeyCache_GetAES128(sint32 index)\n{\n\tif( index < 0 || index >= (sint32)g_keyCache.size())\n\t\treturn nullptr;\n\tKeyCacheEntry* keyCacheEntry = &g_keyCache[index];\n\treturn keyCacheEntry->aes128key;\n}\n\nvoid KeyCache_AddKey128(uint8* key)\n{\n\tKeyCacheEntry newEntry = {0};\n\tmemcpy(newEntry.aes128key, key, 16);\n\tg_keyCache.emplace_back(newEntry);\n}\n\nbool sKeyCachePrepared = false;\n\nvoid KeyCache_Prepare()\n{\n\tmtxKeyCache.lock();\n\tif (sKeyCachePrepared)\n\t{\n\t\tmtxKeyCache.unlock();\n\t\treturn;\n\t}\n\tsKeyCachePrepared = true;\n\tg_keyCache.clear();\n\t// load keys\n\tauto keysPath = ActiveSettings::GetUserDataPath(\"keys.txt\");\n\tFileStream* fs_keys = FileStream::openFile2(keysPath);\n\tif( !fs_keys )\n\t{\n\t\tfs_keys = FileStream::createFile2(keysPath);\n\t\tif(fs_keys)\n\t\t{\n\t\t\tfs_keys->writeString(\"# this file contains keys needed for decryption of disc file system data (WUD/WUX)\\r\\n\");\n\t\t\tfs_keys->writeString(\"# 1 key per line, any text after a '#' character is considered a comment\\r\\n\");\n\t\t\tfs_keys->writeString(\"# the emulator will automatically pick the right key\\r\\n\");\n\t\t\tfs_keys->writeString(\"541b9889519b27d363cd21604b97c67a # example key (can be deleted)\\r\\n\");\n\t\t\tdelete fs_keys;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tWindowSystem::ShowErrorDialog(_tr(\"Unable to create file keys.txt\\nThis can happen if Cemu does not have write permission to its own directory, the disk is full or if anti-virus software is blocking Cemu.\"), _tr(\"Error\"), WindowSystem::ErrorCategory::KEYS_TXT_CREATION);\n\t\t}\n\t\tmtxKeyCache.unlock();\n\t\treturn;\n\t}\n\tsint32 lineNumber = 0;\n\tstd::string line;\n\twhile( fs_keys->readLine(line) )\n\t{\n\t\tlineNumber++;\n\t\t// truncate anything after '#' or ';'\n\t\tfor(size_t i=0; i<line.size(); i++)\n\t\t{\n\t\t\tif(line[i] == '#' || line[i] == ';' )\n\t\t\t{\n\t\t\t\tline.resize(i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// remove whitespaces and other common formatting characters\n\t\tauto itr = line.begin();\n\t\twhile (itr != line.end())\n\t\t{\n\t\t\tchar c = *itr;\n\t\t\tif (c == ' ' || c == '\\t' || c == '-' || c == '_')\n\t\t\t\titr = line.erase(itr);\n\t\t\telse\n\t\t\t\titr++;\n\t\t}\n\t\tif (line.empty())\n\t\t\tcontinue;\n\t\tif( strishex(line) == false )\n\t\t{\n\t\t\tauto errorMsg = _tr(\"Error in keys.txt at line {}\", lineNumber);\n\t\t\tWindowSystem::ShowErrorDialog(errorMsg, WindowSystem::ErrorCategory::KEYS_TXT_CREATION);\n\t\t\tcontinue;\n\t\t}\n\t\tif(line.size() == 32 )\n\t\t{\n\t\t\t// 128-bit key\n\t\t\tuint8 keyData128[16];\n\t\t\tStringHelpers::ParseHexString(line, keyData128, 16);\n\t\t\tKeyCache_AddKey128(keyData128);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// invalid key length\n\t\t}\n\t}\n\tdelete fs_keys;\n\tmtxKeyCache.unlock();\n}"
  },
  {
    "path": "src/Cafe/Filesystem/FST/KeyCache.h",
    "content": "#pragma once\n\nvoid KeyCache_Prepare();\n\nuint8* KeyCache_GetAES128(sint32 index);"
  },
  {
    "path": "src/Cafe/Filesystem/FST/fstUtil.h",
    "content": "#pragma once\n#include <wchar.h>\n\n#include <boost/container/small_vector.hpp>\n\n#include \"../fsc.h\"\n\n// path parser and utility class for Wii U paths\n// optimized to be allocation-free for common path lengths\nclass FSCPath\n{\n\tstruct PathNode\n\t{\n\t\tPathNode(uint16 offset, uint16 len) : offset(offset), len(len) {};\n\n\t\tuint16 offset;\n\t\tuint16 len;\n\t};\n\n\tboost::container::small_vector<PathNode, 8> m_nodes;\n\tboost::container::small_vector<char, 64> m_names;\n\tbool m_isAbsolute{};\n\n\tinline bool isSlash(char c)\n\t{\n\t\treturn c == '\\\\' || c == '/';\n\t}\n\n\tvoid appendNode(const char* name, uint16 nameLen)\n\t{\n\t\tif (m_names.size() > 0xFFFF)\n\t\t\treturn;\n\t\tif (nameLen == 1 && *name == '.')\n\t\t\treturn;\n\t\tm_nodes.emplace_back((uint16)m_names.size(), nameLen);\n\t\tm_names.insert(m_names.end(), name, name + nameLen);\n\t}\n\npublic:\n\tFSCPath(std::string_view path)\n\t{\n\t\tif (path.empty())\n\t\t\treturn;\n\t\tif (isSlash(path.front()))\n\t\t{\n\t\t\tm_isAbsolute = true;\n\t\t\tpath.remove_prefix(1);\n\t\t\t// skip any additional leading slashes\n\t\t\twhile (!path.empty() && isSlash(path.front()))\n\t\t\t\tpath.remove_prefix(1);\n\t\t}\n\t\t// parse nodes\n\t\tsize_t n = 0;\n\t\tsize_t nodeNameStartIndex = 0;\n\t\twhile (n < path.size())\n\t\t{\n\t\t\tif (isSlash(path[n]))\n\t\t\t{\n\t\t\t\tsize_t nodeNameLen = n - nodeNameStartIndex;\n\t\t\t\tif (nodeNameLen > 0xFFFF)\n\t\t\t\t\tnodeNameLen = 0xFFFF; // truncate suspiciously long node names\n\t\t\t\tcemu_assert_debug(nodeNameLen > 0);\n\t\t\t\tappendNode(path.data() + nodeNameStartIndex, (uint16)nodeNameLen);\n\t\t\t\t// skip any repeating slashes\n\t\t\t\twhile (n < path.size() && isSlash(path[n]))\n\t\t\t\t\tn++;\n\t\t\t\tnodeNameStartIndex = n;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tn++;\n\t\t}\n\t\tif (nodeNameStartIndex < n)\n\t\t{\n\t\t\tsize_t nodeNameLen = n - nodeNameStartIndex;\n\t\t\tif (nodeNameLen > 0xFFFF)\n\t\t\t\tnodeNameLen = 0xFFFF; // truncate suspiciously long node names\n\t\t\tappendNode(path.data() + nodeNameStartIndex, (uint16)nodeNameLen);\n\t\t}\n\t}\n\n\tsize_t GetNodeCount() const\n\t{\n\t\treturn m_nodes.size();\n\t}\n\n\tstd::string_view GetNodeName(size_t index) const\n\t{\n\t\tif (index < 0 || index >= m_nodes.size())\n\t\t\treturn std::basic_string_view<char>();\n\t\treturn std::basic_string_view<char>(m_names.data() + m_nodes[index].offset, m_nodes[index].len);\n\t}\n\n\t// returns true if the node names match according to FSA case-insensitivity rules\n\tstatic bool MatchNodeName(std::string_view name1, std::string_view name2)\n\t{\n\t\tif (name1.size() != name2.size())\n\t\t\treturn false;\n\t\tfor (size_t i = 0; i < name1.size(); i++)\n\t\t{\n\t\t\tchar c1 = name1[i];\n\t\t\tchar c2 = name2[i];\n\t\t\tif (c1 >= 'A' && c1 <= 'Z')\n\t\t\t\tc1 += ('a' - 'A');\n\t\t\tif (c2 >= 'A' && c2 <= 'Z')\n\t\t\t\tc2 += ('a' - 'A');\n\t\t\tif (c1 != c2)\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool MatchNodeName(sint32 index, std::string_view name) const\n\t{\n\t\tif (index < 0 || index >= (sint32)m_nodes.size())\n\t\t\treturn false;\n\t\tauto nodeName = GetNodeName(index);\n\t\treturn MatchNodeName(nodeName, name);\n\t}\n};\n\ntemplate<typename F>\nclass FSAFileTree\n{\n  private:\n\n\tenum NODETYPE : uint8\n\t{\n\t\tNODETYPE_DIRECTORY,\n\t\tNODETYPE_FILE,\n\t};\n\n\tstruct node_t\n\t{\n\t\tstd::string name;\n\t\tstd::vector<node_t*> subnodes;\n\t\tsize_t fileSize;\n\t\tF* custom;\n\t\tNODETYPE type;\n\t};\n\n\tnode_t* getByNodePath(FSCPath& p, sint32 numNodes, bool createAsDirectories)\n\t{\n\t\tnode_t* currentNode = &rootNode;\n\t\tfor (sint32 i = 0; i < numNodes; i++)\n\t\t{\n\t\t\t// find subnode by path\n\t\t\tnode_t* foundSubnode = getSubnode(currentNode, p.GetNodeName(i));\n\t\t\tif (foundSubnode == nullptr)\n\t\t\t{\n\t\t\t\t// no subnode found -> create new directory node (if requested)\n\t\t\t\tif (createAsDirectories == false)\n\t\t\t\t\treturn nullptr; // path not found\n\t\t\t\tcurrentNode = newNode(currentNode, NODETYPE_DIRECTORY, p.GetNodeName(i));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcurrentNode = foundSubnode;\n\t\t\t}\n\t\t}\n\t\treturn currentNode;\n\t}\n\n\tnode_t* getSubnode(node_t* parentNode, std::string_view name)\n\t{\n\t\tfor (auto& sn : parentNode->subnodes)\n\t\t{\n\t\t\tif (FSCPath::MatchNodeName(sn->name, name))\n\t\t\t\treturn sn;\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tnode_t* newNode(node_t* parentNode, NODETYPE type, std::string_view name)\n\t{\n\t\tnode_t* newNode = new node_t;\n\t\tnewNode->name.assign(name);\n\t\tnewNode->type = type;\n\t\tnewNode->custom = nullptr;\n\t\tparentNode->subnodes.push_back(newNode);\n\t\treturn newNode;\n\t}\n\n\tclass DirectoryIterator : public FSCVirtualFile\n\t{\n\t  public:\n\t\tDirectoryIterator(node_t* node)\n\t\t\t: m_node(node), m_subnodeIndex(0)\n\t\t{\n\t\t}\n\n\t\tsint32 fscGetType() override\n\t\t{\n\t\t\treturn FSC_TYPE_DIRECTORY;\n\t\t}\n\n\t\tbool fscDirNext(FSCDirEntry* dirEntry) override\n\t\t{\n\t\t\tif (m_subnodeIndex >= m_node->subnodes.size())\n\t\t\t\treturn false;\n\n\t\t\tconst node_t* subnode = m_node->subnodes[m_subnodeIndex];\n\n\t\t\tstrncpy(dirEntry->path, subnode->name.c_str(), sizeof(dirEntry->path) - 1);\n\t\t\tdirEntry->path[sizeof(dirEntry->path) - 1] = '\\0';\n\t\t\tdirEntry->isDirectory = subnode->type == FSAFileTree::NODETYPE_DIRECTORY;\n\t\t\tdirEntry->isFile = subnode->type == FSAFileTree::NODETYPE_FILE;\n\t\t\tdirEntry->fileSize = subnode->type == FSAFileTree::NODETYPE_FILE ? subnode->fileSize : 0;\n\n\t\t\t++m_subnodeIndex;\n\t\t\treturn true;\n\t\t}\n\n\t\tbool fscRewindDir() override\n\t\t{\n\t\t\tm_subnodeIndex = 0;\n\t\t\treturn true;\n\t\t}\n\n\t  private:\n\t\tnode_t* m_node;\n\t\tsize_t m_subnodeIndex;\n\t};\n\npublic:\n\tFSAFileTree()\n\t{\n\t\trootNode.type = NODETYPE_DIRECTORY;\n\t}\n\n\tbool addFile(std::string_view path, size_t fileSize, F* custom)\n\t{\n\t\tFSCPath p(path);\n\t\tif (p.GetNodeCount() == 0)\n\t\t\treturn false;\n\t\tnode_t* directoryNode = getByNodePath(p, p.GetNodeCount() - 1, true);\n\t\t// check if a node with same name already exists\n\t\tif (getSubnode(directoryNode, p.GetNodeName(p.GetNodeCount() - 1)) != nullptr)\n\t\t\treturn false; // node already exists\n\t\t// add file node\n\t\tnode_t* fileNode = newNode(directoryNode, NODETYPE_FILE, p.GetNodeName(p.GetNodeCount() - 1));\n\t\tfileNode->fileSize = fileSize;\n\t\tfileNode->custom = custom;\n\t\treturn true;\n\t}\n\n\tbool getFile(std::string_view path, F* &custom)\n\t{\n\t\tFSCPath p(path);\n\t\tif (p.GetNodeCount() == 0)\n\t\t\treturn false;\n\t\tnode_t* node = getByNodePath(p, p.GetNodeCount(), false);\n\t\tif (node == nullptr)\n\t\t\treturn false;\n\t\tif (node->type != NODETYPE_FILE)\n\t\t\treturn false;\n\t\tcustom = node->custom;\n\t\treturn true;\n\t}\n\n\tbool getDirectory(std::string_view path, FSCVirtualFile*& dirIterator)\n\t{\n\t\tFSCPath p(path);\n\t\tif (p.GetNodeCount() == 0)\n\t\t\treturn false;\n\t\tnode_t* node = getByNodePath(p, p.GetNodeCount(), false);\n\t\tif (node == nullptr)\n\t\t\treturn false;\n\t\tif (node->type != NODETYPE_DIRECTORY)\n\t\t\treturn false;\n\t\tdirIterator = new DirectoryIterator(node);\n\t\treturn true;\n\t}\n\n\tbool removeFile(std::string_view path)\n\t{\n\t\tFSCPath p(path);\n\t\tif (p.GetNodeCount() == 0)\n\t\t\treturn false;\n\t\tnode_t* directoryNode = getByNodePath(p, p.GetNodeCount() - 1, false);\n\t\tif (directoryNode == nullptr)\n\t\t\treturn false;\n\t\t// find node\n\t\tnode_t* fileNode = getSubnode(directoryNode, p.GetNodeName(p.GetNodeCount() - 1));\n\t\tif (fileNode == nullptr)\n\t\t\treturn false;\n\t\tif (fileNode->type != NODETYPE_FILE)\n\t\t\treturn false;\n\t\tif (fileNode->subnodes.empty() == false)\n\t\t{\n\t\t\t// files shouldn't have subnodes\n\t\t\tassert(false);\n\t\t}\n\t\t// remove node from parent\n\t\tdirectoryNode->subnodes.erase(std::remove(directoryNode->subnodes.begin(), directoryNode->subnodes.end(), fileNode), directoryNode->subnodes.end());\n\t\t// delete node\n\t\tdelete fileNode;\n\t\treturn true;\n\t}\n\n\ttemplate<typename TFunc>\n\tbool listDirectory(std::string_view path, TFunc fn)\n\t{\n\t\tFSCPath p(path);\n\t\tnode_t* node = getByNodePath(p, p.GetNodeCount(), false);\n\t\tif (node == nullptr)\n\t\t\treturn false;\n\t\tif (node->type != NODETYPE_DIRECTORY)\n\t\t\treturn false;\n\t\tfor (auto& it : node->subnodes)\n\t\t{\n\t\t\tif (it->type == NODETYPE_DIRECTORY)\n\t\t\t{\n\t\t\t\tfn(it->name, true, it->custom);\n\t\t\t}\n\t\t\telse if (it->type == NODETYPE_FILE)\n\t\t\t{\n\t\t\t\tfn(it->name, false, it->custom);\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\nprivate:\n\tnode_t rootNode;\n};\n\nstatic void FSTPathUnitTest()\n{\n\t// test 1\n\tFSCPath p1(\"/vol/content\");\n\tcemu_assert_debug(p1.GetNodeCount() == 2);\n\tcemu_assert_debug(p1.MatchNodeName(0, \"tst\") == false);\n\tcemu_assert_debug(p1.MatchNodeName(0, \"vol\"));\n\tcemu_assert_debug(p1.MatchNodeName(1, \"CONTENT\"));\n\t// test 2\n\tFSCPath p2(\"/vol/content/\");\n\tcemu_assert_debug(p2.GetNodeCount() == 2);\n\tcemu_assert_debug(p2.MatchNodeName(0, \"vol\"));\n\tcemu_assert_debug(p2.MatchNodeName(1, \"content\"));\n\t// test 3\n\tFSCPath p3(\"/vol//content/\\\\/\");\n\tcemu_assert_debug(p3.GetNodeCount() == 2);\n\tcemu_assert_debug(p3.MatchNodeName(0, \"vol\"));\n\tcemu_assert_debug(p3.MatchNodeName(1, \"content\"));\n\t// test 4\n\tFSCPath p4(\"vol/content/\");\n\tcemu_assert_debug(p4.GetNodeCount() == 2);\n\t// test 5\n\tFSCPath p5(\"/vol/content/test.bin\");\n\tcemu_assert_debug(p5.GetNodeCount() == 3);\n\tcemu_assert_debug(p5.MatchNodeName(0, \"vol\"));\n\tcemu_assert_debug(p5.MatchNodeName(1, \"content\"));\n\tcemu_assert_debug(p5.MatchNodeName(2, \"TEST.BIN\"));\n\t// test 6 - empty paths\n\tFSCPath p6(\"\");\n\tcemu_assert_debug(p6.GetNodeCount() == 0);\n\tp6 = FSCPath(\"/////////////\");\n\tcemu_assert_debug(p6.GetNodeCount() == 0);\n\t// test 7 - periods in path\n\tFSCPath p7(\"/vol/content/./..\");\n\tcemu_assert_debug(p7.GetNodeCount() == 3);\n\tcemu_assert_debug(p7.MatchNodeName(0, \"vol\"));\n\tcemu_assert_debug(p7.MatchNodeName(1, \"content\"));\n\tcemu_assert_debug(p7.MatchNodeName(2, \"..\"));\n}\n\n\n\n\n\n\n"
  },
  {
    "path": "src/Cafe/Filesystem/WUD/wud.cpp",
    "content": "#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"wud.h\"\n#include \"Common/FileStream.h\"\n\nwud_t* wud_open(const fs::path& path)\n{\n\tFileStream* fs = FileStream::openFile2(path);\n\tif( !fs )\n\t\treturn nullptr;\n\t// allocate wud struct\n\twud_t* wud = (wud_t*)malloc(sizeof(wud_t));\n\tmemset(wud, 0x00, sizeof(wud_t));\n\twud->fs = fs;\n\t// get size of file\n\tlong long inputFileSize = wud->fs->GetSize();\n\t// determine whether the WUD is compressed or not\n\twuxHeader_t wuxHeader = {0};\n\tif( wud->fs->readData(&wuxHeader, sizeof(wuxHeader_t)) != sizeof(wuxHeader_t))\n\t{\n\t\t// file is too short to be either\n\t\twud_close(wud);\n\t\treturn nullptr;\n\t}\n\tif( wuxHeader.magic0 == WUX_MAGIC_0 && wuxHeader.magic1 == WUX_MAGIC_1 )\n\t{\n\t\t// this is a WUX file\n\t\twud->isCompressed = true;\n\t\twud->sectorSize = wuxHeader.sectorSize;\n\t\twud->uncompressedSize = wuxHeader.uncompressedSize;\n\t\t// validate header values\n\t\tif( wud->sectorSize < 0x100 || wud->sectorSize >= 0x10000000 )\n\t\t{\n\t\t\twud_close(wud);\n\t\t\treturn nullptr;\n\t\t}\n\t\t// calculate offsets and sizes\n\t\twud->indexTableEntryCount = (unsigned int)((wud->uncompressedSize+(long long)(wud->sectorSize-1)) / (long long)wud->sectorSize);\n\t\twud->offsetIndexTable = sizeof(wuxHeader_t);\n\t\twud->offsetSectorArray = (wud->offsetIndexTable + (long long)wud->indexTableEntryCount*sizeof(unsigned int));\n\t\t// align to SECTOR_SIZE\n\t\twud->offsetSectorArray = (wud->offsetSectorArray + (long long)(wud->sectorSize-1));\n\t\twud->offsetSectorArray = wud->offsetSectorArray - (wud->offsetSectorArray%(long long)wud->sectorSize);\n\t\t// read index table\n\t\tunsigned int indexTableSize = sizeof(unsigned int) * wud->indexTableEntryCount;\n\t\twud->indexTable = (unsigned int*)malloc(indexTableSize);\n\t\twud->fs->SetPosition(wud->offsetIndexTable);\n\t\tif( wud->fs->readData(wud->indexTable, indexTableSize) != indexTableSize )\n\t\t{\n\t\t\t// could not read index table\n\t\t\twud_close(wud);\n\t\t\treturn nullptr;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// uncompressed file\n\t\twud->uncompressedSize = inputFileSize;\n\t}\n\treturn wud;\n}\n\nvoid wud_close(wud_t* wud)\n{\n\tdelete wud->fs;\n\tif( wud->indexTable )\n\t\tfree(wud->indexTable);\n\tfree(wud);\n}\n\nbool wud_isWUXCompressed(wud_t* wud)\n{\n\treturn wud->isCompressed;\n}\n\n/*\n * Read data from WUD file\n * Can read up to 4GB at once\n */\nunsigned int wud_readData(wud_t* wud, void* buffer, unsigned int length, long long offset)\n{\n\t// make sure there is no out-of-bounds read\n\tlong long fileBytesLeft = wud->uncompressedSize - offset;\n\tif( fileBytesLeft <= 0 )\n\t\treturn 0;\n\tif( fileBytesLeft < (long long)length )\n\t\tlength = (unsigned int)fileBytesLeft;\n\t// read data\n\tunsigned int readBytes = 0;\n\tif( wud->isCompressed == false )\n\t{\n\t\t// uncompressed read is straight forward\n\t\twud->fs->SetPosition(offset);\n\t\treadBytes = (unsigned int)wud->fs->readData(buffer, length);\n\t}\n\telse\n\t{\n\t\t// compressed read must be handled on a per-sector level\n\t\twhile( length > 0 )\n\t\t{\n\t\t\tunsigned int sectorOffset = (unsigned int)(offset % (long long)wud->sectorSize);\n\t\t\tunsigned int remainingSectorBytes = wud->sectorSize - sectorOffset;\n\t\t\tunsigned int sectorIndex = (unsigned int)(offset / (long long)wud->sectorSize);\n\t\t\tunsigned int bytesToRead = (remainingSectorBytes<length)?remainingSectorBytes:length; // read only up to the end of the current sector\n\t\t\t// look up real sector index\n\t\t\tsectorIndex = wud->indexTable[sectorIndex];\n\t\t\twud->fs->SetPosition(wud->offsetSectorArray + (long long)sectorIndex * (long long)wud->sectorSize + (long long)sectorOffset);\n\t\t\treadBytes += (unsigned int)wud->fs->readData(buffer, bytesToRead);\n\t\t\t// progress read offset, write pointer and decrease length\n\t\t\tbuffer = (void*)((char*)buffer + bytesToRead);\n\t\t\tlength -= bytesToRead;\n\t\t\toffset += bytesToRead;\n\n\t\t}\n\t}\n\treturn readBytes;\n}\n\n/*\n * Returns the size of the data\n * For .wud: Size of file\n * For .wux: Size of uncompressed data\n */\nlong long wud_getWUDSize(wud_t* wud)\n{\n\treturn wud->uncompressedSize;\n}"
  },
  {
    "path": "src/Cafe/Filesystem/WUD/wud.h",
    "content": "#pragma once\n\nstruct wuxHeader_t\n{\n\tunsigned int\t\tmagic0;\n\tunsigned int\t\tmagic1;\n\tunsigned int\t\tsectorSize;\n\tunsigned long long\tuncompressedSize;\n\tunsigned int\t\tflags;\n};\n\nstruct wud_t\n{\n\tclass FileStream* fs;\n\tlong long\t\tuncompressedSize;\n\tbool\t\t\tisCompressed;\n\t// data used when compressed\n\tunsigned int\tsectorSize;\n\tunsigned int\tindexTableEntryCount;\n\tunsigned int*\tindexTable;\n\tlong long\t\toffsetIndexTable;\n\tlong long\t\toffsetSectorArray;\n};\n\n#define WUX_MAGIC_0\t'0XUW' // \"WUX0\"\n#define WUX_MAGIC_1\t0x1099d02e\n\n// wud and wux functions\nwud_t* wud_open(const fs::path& path); // transparently handles wud and wux files\nvoid wud_close(wud_t* wud);\n\nbool wud_isWUXCompressed(wud_t* wud);\nunsigned int wud_readData(wud_t* wud, void* buffer, unsigned int length, long long offset);\nlong long wud_getWUDSize(wud_t* wud);"
  },
  {
    "path": "src/Cafe/Filesystem/WUHB/RomFSStructs.h",
    "content": "#pragma once\n\nstruct romfs_header_t\n{\n\tuint32 header_magic;\n\tuint32be header_size;\n\tuint64be dir_hash_table_ofs;\n\tuint64be dir_hash_table_size;\n\tuint64be dir_table_ofs;\n\tuint64be dir_table_size;\n\tuint64be file_hash_table_ofs;\n\tuint64be file_hash_table_size;\n\tuint64be file_table_ofs;\n\tuint64be file_table_size;\n\tuint64be file_partition_ofs;\n};\n\nstruct romfs_direntry_t\n{\n\tuint32be parent;\n\tuint32be listNext;\t   // offset to next directory entry in linked list of parent directory (aka \"sibling\")\n\tuint32be dirListHead;  // offset to first entry in linked list of directory entries (aka \"child\")\n\tuint32be fileListHead; // offset to first entry in linked list of file entries (aka \"file\")\n\tuint32be hash;\n\tuint32be name_size;\n\tstd::string name;\n};\n\nstruct romfs_fentry_t\n{\n\tuint32be parent;\n\tuint32be listNext; // offset to next file entry in linked list of parent directory (aka \"sibling\")\n\tuint64be offset;\n\tuint64be size;\n\tuint32be hash;\n\tuint32be name_size;\n\tstd::string name;\n};\n\n#define ROMFS_ENTRY_EMPTY 0xFFFFFFFF\n"
  },
  {
    "path": "src/Cafe/Filesystem/WUHB/WUHBReader.cpp",
    "content": "#include \"WUHBReader.h\"\nWUHBReader* WUHBReader::FromPath(const fs::path& path)\n{\n\tFileStream* fileIn{FileStream::openFile2(path)};\n\tif (!fileIn)\n\t\treturn nullptr;\n\n\tWUHBReader* ret = new WUHBReader(fileIn);\n\tif (!ret->CheckMagicValue())\n\t{\n\t\tdelete ret;\n\t\treturn nullptr;\n\t}\n\n\tif (!ret->ReadHeader())\n\t{\n\t\tdelete ret;\n\t\treturn nullptr;\n\t}\n\n\treturn ret;\n}\n\nstatic const romfs_direntry_t fallbackDirEntry{\n\t.parent = ROMFS_ENTRY_EMPTY,\n\t.listNext = ROMFS_ENTRY_EMPTY,\n\t.dirListHead = ROMFS_ENTRY_EMPTY,\n\t.fileListHead = ROMFS_ENTRY_EMPTY,\n\t.hash = ROMFS_ENTRY_EMPTY,\n\t.name_size = 0,\n\t.name = \"\"\n};\nstatic const romfs_fentry_t fallbackFileEntry{\n\t.parent = ROMFS_ENTRY_EMPTY,\n\t.listNext = ROMFS_ENTRY_EMPTY,\n\t.offset = 0,\n\t.size = 0,\n\t.hash = ROMFS_ENTRY_EMPTY,\n\t.name_size = 0,\n\t.name = \"\"\n};\ntemplate<bool File>\nconst WUHBReader::EntryType<File>& WUHBReader::GetFallback()\n{\n\tif constexpr (File)\n\t\treturn fallbackFileEntry;\n\telse\n\t\treturn fallbackDirEntry;\n}\n\ntemplate<bool File>\nWUHBReader::EntryType<File> WUHBReader::GetEntry(uint32 offset) const\n{\n\tauto fallback = GetFallback<File>();\n\tif(offset == ROMFS_ENTRY_EMPTY)\n\t\treturn fallback;\n\n\tconst char* typeName = File ? \"fentry\" : \"direntry\";\n\tEntryType<File> ret;\n\tif (offset >= (File ? m_header.file_table_size : m_header.dir_table_size))\n\t{\n\t\tcemuLog_log(LogType::Force, \"WUHB {} offset exceeds table size declared in header\", typeName);\n\t\treturn fallback;\n\t}\n\n\t// read the entry\n\tm_fileIn->SetPosition((File ? m_header.file_table_ofs : m_header.dir_table_ofs) + offset);\n\tauto read = m_fileIn->readData(&ret, offsetof(EntryType<File>, name));\n\tif (read != offsetof(EntryType<File>, name))\n\t{\n\t\tcemuLog_log(LogType::Force, \"failed to read WUHB {} at offset: {}\", typeName, offset);\n\t\treturn fallback;\n\t}\n\n\t// read the name\n\tret.name.resize(ret.name_size);\n\tread = m_fileIn->readData(ret.name.data(), ret.name_size);\n\tif (read != ret.name_size)\n\t{\n\t\tcemuLog_log(LogType::Force, \"failed to read WUHB {} name\", typeName);\n\t\treturn fallback;\n\t}\n\n\treturn ret;\n}\n\nromfs_direntry_t WUHBReader::GetDirEntry(uint32 offset) const\n{\n\treturn GetEntry<false>(offset);\n}\nromfs_fentry_t WUHBReader::GetFileEntry(uint32 offset) const\n{\n\treturn GetEntry<true>(offset);\n}\n\nuint64 WUHBReader::GetFileSize(uint32 entryOffset) const\n{\n\treturn GetFileEntry(entryOffset).size;\n}\n\nuint64 WUHBReader::ReadFromFile(uint32 entryOffset, uint64 fileOffset, uint64 length, void* buffer) const\n{\n\tconst auto fileEntry = GetFileEntry(entryOffset);\n\tif (fileOffset >= fileEntry.size)\n\t\treturn 0;\n\tconst uint64 readAmount = std::min(length, fileEntry.size - fileOffset);\n\tconst uint64 wuhbOffset = m_header.file_partition_ofs + fileEntry.offset + fileOffset;\n\tm_fileIn->SetPosition(wuhbOffset);\n\treturn m_fileIn->readData(buffer, readAmount);\n}\n\nuint32 WUHBReader::GetHashTableEntryOffset(uint32 hash, bool isFile) const\n{\n\tconst uint64 hash_table_size = (isFile ? m_header.file_hash_table_size : m_header.dir_hash_table_size);\n\tconst uint64 hash_table_ofs = (isFile ? m_header.file_hash_table_ofs : m_header.dir_hash_table_ofs);\n\n\tconst uint64 hash_table_entry_count = hash_table_size / sizeof(uint32);\n\tconst uint64 hash_table_entry_offset = hash_table_ofs + (hash % hash_table_entry_count) * sizeof(uint32);\n\n\tm_fileIn->SetPosition(hash_table_entry_offset);\n\tuint32 tableOffset;\n\tif (!m_fileIn->readU32(tableOffset))\n\t{\n\t\tcemuLog_log(LogType::Force, \"failed to read WUHB hash table entry at file offset: {}\", hash_table_entry_offset);\n\t\treturn ROMFS_ENTRY_EMPTY;\n\t}\n\n\treturn uint32be::from_bevalue(tableOffset);\n}\n\ntemplate<bool T>\nbool WUHBReader::SearchHashList(uint32& entryOffset, const fs::path& targetName) const\n{\n\tfor (;;)\n\t{\n\t\tif (entryOffset == ROMFS_ENTRY_EMPTY)\n\t\t\treturn false;\n\t\tauto entry = GetEntry<T>(entryOffset);\n\n\t\tif (entry.name == targetName)\n\t\t\treturn true;\n\t\tentryOffset = entry.hash;\n\t}\n\treturn false;\n}\n\nuint32 WUHBReader::Lookup(const std::filesystem::path& path, bool isFile) const\n{\n\tuint32 currentEntryOffset = 0;\n\tauto look = [&](const fs::path& part, bool lookInFileHT) {\n\t\tconst auto partString = part.string();\n\t\tcurrentEntryOffset = GetHashTableEntryOffset(CalcPathHash(currentEntryOffset, partString.c_str(), 0, partString.size()), lookInFileHT);\n\t\tif (lookInFileHT)\n\t\t\treturn SearchHashList<true>(currentEntryOffset, part);\n\t\telse\n\t\t\treturn SearchHashList<false>(currentEntryOffset, part);\n\t};\n\t// look for the root entry\n\tif (!look(\"\", false))\n\t\treturn ROMFS_ENTRY_EMPTY;\n\n\tauto it = path.begin();\n\twhile (it != path.end())\n\t{\n\t\tfs::path part = *it;\n\t\t++it;\n\t\t// no need to recurse after trailing forward slash (e.g. directory/)\n\t\tif (part.empty() && !isFile)\n\t\t\tbreak;\n\t\t// skip leading forward slash\n\t\tif (part == \"/\")\n\t\t\tcontinue;\n\n\t\t// if the lookup target is a file and this is the last iteration, look in the file hash table instead.\n\t\tif (!look(part, it == path.end() && isFile))\n\t\t\treturn ROMFS_ENTRY_EMPTY;\n\t}\n\treturn currentEntryOffset;\n}\nbool WUHBReader::CheckMagicValue() const\n{\n\tuint8 magic[4];\n\tm_fileIn->SetPosition(0);\n\tint read = m_fileIn->readData(magic, 4);\n\tif (read != 4)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to read WUHB magic numbers\");\n\t\treturn false;\n\t}\n\tstatic_assert(sizeof(magic) == s_headerMagicValue.size());\n\treturn std::memcmp(&magic, s_headerMagicValue.data(), sizeof(magic)) == 0;\n}\nbool WUHBReader::ReadHeader()\n{\n\tm_fileIn->SetPosition(0);\n\tauto read = m_fileIn->readData(&m_header, sizeof(m_header));\n\tauto readSuccess = read == sizeof(m_header);\n\tif (!readSuccess)\n\t\tcemuLog_log(LogType::Force, \"Failed to read WUHB header\");\n\treturn readSuccess;\n}\nunsigned char WUHBReader::NormalizeChar(unsigned char c)\n{\n\tif (c >= 'a' && c <= 'z')\n\t{\n\t\treturn c + 'A' - 'a';\n\t}\n\telse\n\t{\n\t\treturn c;\n\t}\n}\nuint32 WUHBReader::CalcPathHash(uint32 parent, const char* path, uint32 start, size_t path_len)\n{\n\tcemu_assert(path != nullptr || path_len == 0);\n\tuint32 hash = parent ^ 123456789;\n\tfor (uint32 i = 0; i < path_len; i++)\n\t{\n\t\thash = (hash >> 5) | (hash << 27);\n\t\thash ^= NormalizeChar(path[start + i]);\n\t}\n\n\treturn hash;\n}\n"
  },
  {
    "path": "src/Cafe/Filesystem/WUHB/WUHBReader.h",
    "content": "#pragma once\n#include <Common/FileStream.h>\n#include \"RomFSStructs.h\"\nclass WUHBReader\n{\n  public:\n\tstatic WUHBReader* FromPath(const fs::path& path);\n\n\tromfs_direntry_t GetDirEntry(uint32 offset) const;\n\tromfs_fentry_t GetFileEntry(uint32 offset) const;\n\n\tuint64 GetFileSize(uint32 entryOffset) const;\n\n\tuint64 ReadFromFile(uint32 entryOffset, uint64 fileOffset, uint64 length, void* buffer) const;\n\n\tuint32 Lookup(const std::filesystem::path& path, bool isFile) const;\n\n  private:\n\tWUHBReader(FileStream* file)\n\t\t: m_fileIn(file)\n\t{\n\t\tcemu_assert_debug(file != nullptr);\n\t};\n\tWUHBReader() = delete;\n\n\tromfs_header_t m_header;\n\tstd::unique_ptr<FileStream> m_fileIn;\n\tconstexpr static std::string_view s_headerMagicValue = \"WUHB\";\n\tbool ReadHeader();\n\tbool CheckMagicValue() const;\n\n\tstatic inline unsigned char NormalizeChar(unsigned char c);\n\tstatic uint32 CalcPathHash(uint32 parent, const char* path, uint32 start, size_t path_len);\n\n\ttemplate<bool File>\n\tusing EntryType = std::conditional_t<File, romfs_fentry_t, romfs_direntry_t>;\n\ttemplate<bool File>\n\tstatic const EntryType<File>& GetFallback();\n\ttemplate<bool File>\n\tEntryType<File> GetEntry(uint32 offset) const;\n\n\ttemplate<bool T>\n\tbool SearchHashList(uint32& entryOffset, const fs::path& targetName) const;\n\tuint32 GetHashTableEntryOffset(uint32 hash, bool isFile) const;\n};\n"
  },
  {
    "path": "src/Cafe/Filesystem/fsc.cpp",
    "content": "#include \"Cafe/Filesystem/fsc.h\"\n#include \"Cafe/Filesystem/FST/fstUtil.h\"\n\nstruct FSCMountPathNode\n{\n\tstd::string path;\n\tstd::vector<FSCMountPathNode*> subnodes;\n\tFSCMountPathNode* parent;\n\t// associated device target and path\n\tfscDeviceC* device{ nullptr };\n\tvoid* ctx{ nullptr };\n\tstd::string deviceTargetPath; // the destination base path for the device, utf8\n\t// priority\n\tsint32 priority{};\n\n\tFSCMountPathNode(FSCMountPathNode* parent) : parent(parent)\n\t{\n\t}\n\n    void AssignDevice(fscDeviceC* device, void* ctx, std::string_view deviceBasePath)\n    {\n        this->device = device;\n        this->ctx = ctx;\n        this->deviceTargetPath = deviceBasePath;\n    }\n\n    void UnassignDevice()\n    {\n        this->device = nullptr;\n        this->ctx = nullptr;\n        this->deviceTargetPath.clear();\n    }\n\n    bool IsRootNode() const\n    {\n        return !parent;\n    }\n\n\t~FSCMountPathNode()\n\t{\n\t\tfor (auto& itr : subnodes)\n\t\t\tdelete itr;\n\t\tsubnodes.clear();\n\t}\n};\n\n// compare two file or directory names using FSA rules\nbool FSA_CompareNodeName(std::string_view a, std::string_view b)\n{\n\tif (a.size() != b.size())\n\t\treturn false;\n\tfor (size_t i = 0; i < a.size(); i++)\n\t{\n\t\tuint8 ac = (uint8)a[i];\n\t\tuint8 bc = (uint8)b[i];\n\t\t// lower case compare\n\t\tif (ac >= (uint8)'A' && ac <= (uint8)'Z')\n\t\t\tac -= ((uint8)'A' - (uint8)'a');\n\t\tif (bc >= (uint8)'A' && bc <= (uint8)'Z')\n\t\t\tbc -= ((uint8)'A' - (uint8)'a');\n\t\tif (ac != bc)\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\nFSCMountPathNode* s_fscRootNodePerPrio[FSC_PRIORITY_COUNT]{};\n\nstd::recursive_mutex s_fscMutex;\n\n#define fscEnter() s_fscMutex.lock();\n#define fscLeave() s_fscMutex.unlock();\n\nFSCMountPathNode* fsc_lookupPathVirtualNode(const char* path, sint32 priority = FSC_PRIORITY_BASE);\n\nvoid fsc_reset()\n{\n\t// delete existing nodes\n\tfor (auto& itr : s_fscRootNodePerPrio)\n\t{\n\t\tdelete itr;\n\t\titr = nullptr;\n\t}\n\t// init root node for each priority\n\tfor (sint32 i = 0; i < FSC_PRIORITY_COUNT; i++)\n\t\ts_fscRootNodePerPrio[i] = new FSCMountPathNode(nullptr);\n}\n\n/*\n * Creates a node chain for the given mount path. Returns the bottom node.\n * If the path already exists for the given priority, NULL is returned (we can't mount two devices to the same path with the same priority)\n * But we can map devices to subdirectories. Something like this is possible:\n * /vol/content\t\t -> Map to WUD (includes all subdirectories except /data, which is handled by the entry below. This exclusion rule applies only if the priority of both mount entries is the same)\n * /vol/content/data -> Map to HostFS\n * If overlapping paths with different priority are created, then the higher priority one will be checked first\n */\nFSCMountPathNode* fsc_createMountPath(const FSCPath& mountPath, sint32 priority)\n{\n\tcemu_assert(priority >= 0 && priority < FSC_PRIORITY_COUNT);\n\tfscEnter();\n\tFSCMountPathNode* nodeParent = s_fscRootNodePerPrio[priority];\n\tfor (size_t i=0; i< mountPath.GetNodeCount(); i++)\n\t{\n\t\t// search for subdirectory\n\t\tFSCMountPathNode* nodeSub = nullptr; // set if we found a subnode with a matching name, else this is used to store the new nodes\n\t\tfor (auto& nodeItr : nodeParent->subnodes)\n\t\t{\n\t\t\tif (mountPath.MatchNodeName(i, nodeItr->path))\n\t\t\t{\n\t\t\t\t// subnode found\n\t\t\t\tnodeSub = nodeItr;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (nodeSub)\n\t\t{\n\t\t\t// traverse subnode\n\t\t\tnodeParent = nodeSub;\n\t\t\tcontinue;\n\t\t}\n\t\t// no matching subnode, add new entry\n\t\tnodeSub = new FSCMountPathNode(nodeParent);\n\t\tnodeSub->path = mountPath.GetNodeName(i);\n\t\tnodeSub->priority = priority;\n\t\tnodeParent->subnodes.emplace_back(nodeSub);\n\t\tif (i == (mountPath.GetNodeCount() - 1))\n\t\t{\n\t\t\t// last node\n\t\t\tfscLeave();\n\t\t\treturn nodeSub;\n\t\t}\n\t\t// traverse subnode\n\t\tnodeParent = nodeSub;\n\t}\n\t// path is empty or already mounted\n\tfscLeave();\n\tif (mountPath.GetNodeCount() == 0)\n\t\treturn nodeParent;\n\treturn nullptr;\n}\n\n// Map a virtual FSC directory to a device. targetPath points to the destination base directory within the device\nsint32 fsc_mount(std::string_view mountPath, std::string_view targetPath, fscDeviceC* fscDevice, void* ctx, sint32 priority)\n{\n\tcemu_assert(fscDevice);\n\tstd::string mountPathTmp(mountPath);\n\t// make sure the target path ends with a slash\n\tstd::string targetPathWithSlash(targetPath);\n\tif (!targetPathWithSlash.empty() && (targetPathWithSlash.back() != '/' && targetPathWithSlash.back() != '\\\\'))\n\t\ttargetPathWithSlash.push_back('/');\n\n\tFSCPath parsedMountPath(mountPathTmp);\n\t// register path\n\tfscEnter();\n\tFSCMountPathNode* node = fsc_createMountPath(parsedMountPath, priority);\n\tif( !node )\n\t{\n\t\t// path empty, invalid or already used\n\t\tcemuLog_log(LogType::Force, \"fsc_mount failed (virtual path: {})\", mountPath);\n\t\tfscLeave();\n\t\treturn FSC_STATUS_INVALID_PATH;\n\t}\n    node->AssignDevice(fscDevice, ctx, targetPathWithSlash);\n\tfscLeave();\n\treturn FSC_STATUS_OK;\n}\n\nbool fsc_unmount(std::string_view mountPath, sint32 priority)\n{\n\tstd::string _tmp(mountPath);\n\tfscEnter();\n\tFSCMountPathNode* mountPathNode = fsc_lookupPathVirtualNode(_tmp.c_str(), priority);\n\tif (!mountPathNode)\n\t{\n\t\tfscLeave();\n\t\treturn false;\n\t}\n\tcemu_assert(mountPathNode->priority == priority);\n\tcemu_assert(mountPathNode->device);\n    // unassign device\n    mountPathNode->UnassignDevice();\n\t// prune empty branch\n\twhile (mountPathNode && !mountPathNode->IsRootNode() && mountPathNode->subnodes.empty() && !mountPathNode->device)\n\t{\n\t\tFSCMountPathNode* parent = mountPathNode->parent;\n        std::erase(parent->subnodes, mountPathNode);\n\t\tdelete mountPathNode;\n\t\tmountPathNode = parent;\n\t}\n\tfscLeave();\n\treturn true;\n}\n\nvoid fsc_unmountAll()\n{\n\tfscEnter();\n\tfsc_reset();\n\tfscLeave();\n}\n\n// lookup virtual path and find mounted device and relative device directory\nbool fsc_lookupPath(const char* path, std::string& devicePathOut, fscDeviceC** fscDeviceOut, void** ctxOut, sint32 priority = FSC_PRIORITY_BASE)\n{\n\tFSCPath parsedPath(path);\n\tFSCMountPathNode* nodeParent = s_fscRootNodePerPrio[priority];\n\tsize_t i;\n\tfscEnter();\n\tfor (i = 0; i < parsedPath.GetNodeCount(); i++)\n\t{\n\t\t// search for subdirectory\n\t\tFSCMountPathNode* nodeSub = nullptr;\n\t\tfor(auto& nodeItr : nodeParent->subnodes)\n\t\t{\t\t\t\n\t\t\tif (parsedPath.MatchNodeName(i, nodeItr->path))\n\t\t\t{\n\t\t\t\tnodeSub = nodeItr;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (nodeSub)\n\t\t{\n\t\t\tnodeParent = nodeSub;\n\t\t\tcontinue;\n\t\t}\n\t\t// no matching subnode\n\t\tbreak;\n\t}\n\t// if the found node is not a device mount point, then travel back towards the root until we find one\n\twhile (nodeParent)\n\t{\n\t\tif (nodeParent->device)\n\t\t{\n\t\t\tdevicePathOut = nodeParent->deviceTargetPath;\n\t\t\tfor (size_t f = i; f < parsedPath.GetNodeCount(); f++)\n\t\t\t{\n\t\t\t\tauto nodeName = parsedPath.GetNodeName(f);\n\t\t\t\tdevicePathOut.append(nodeName);\n\t\t\t\tif (f < (parsedPath.GetNodeCount() - 1))\n\t\t\t\t\tdevicePathOut.push_back('/');\n\t\t\t}\n\t\t\t*fscDeviceOut = nodeParent->device;\n\t\t\t*ctxOut = nodeParent->ctx;\n\t\t\tfscLeave();\n\t\t\treturn true;\n\t\t}\n\t\tnodeParent = nodeParent->parent;\n\t\ti--;\n\t}\n\tfscLeave();\n\treturn false;\n}\n\n// lookup path and find virtual device node\nFSCMountPathNode* fsc_lookupPathVirtualNode(const char* path, sint32 priority)\n{\n\tFSCPath parsedPath(path);\n\tFSCMountPathNode* nodeCurrentDir = s_fscRootNodePerPrio[priority];\n\tfscEnter();\n\tfor (size_t i = 0; i < parsedPath.GetNodeCount(); i++)\n\t{\n\t\t// search for subdirectory\n\t\tFSCMountPathNode* nodeSub = nullptr;\n\t\tfor (auto& nodeItr : nodeCurrentDir->subnodes)\n\t\t{\n\t\t\tif (parsedPath.MatchNodeName(i, nodeItr->path))\n\t\t\t{\n\t\t\t\tnodeSub = nodeItr;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (nodeSub)\n\t\t{\n\t\t\t// traverse subdirectory\n\t\t\tnodeCurrentDir = nodeSub;\n\t\t\tcontinue;\n\t\t}\n\t\tfscLeave();\n\t\treturn nullptr;\n\t}\n\tfscLeave();\n\treturn nodeCurrentDir;\n}\n\n// this wraps multiple iterated directories from different devices into one unified virtual representation\nclass FSCVirtualFileDirectoryIterator : public FSCVirtualFile\n{\npublic:\n\tsint32 fscGetType() override\n\t{\n\t\treturn FSC_TYPE_DIRECTORY;\n\t}\n\n\tFSCVirtualFileDirectoryIterator(std::string_view path, std::span<FSCVirtualFile*> mappedFolders)\n\t\t: m_path(path), m_folders(mappedFolders.begin(), mappedFolders.end())\n\t{\n\t\tdirIterator = nullptr;\n\t}\n\n\t~FSCVirtualFileDirectoryIterator()\n\t{\n\t\t// dirIterator is deleted in base constructor\n\t\tfor (auto& itr : m_folders)\n\t\t\tdelete itr;\n\t}\n\n\tbool fscDirNext(FSCDirEntry* dirEntry) override\n\t{\n\t\tif (!dirIterator)\n\t\t{\n\t\t\t// lazily populate list only if directory is actually iterated\n\t\t\tPopulateIterationList();\n\t\t\tcemu_assert_debug(dirIterator);\n\t\t}\n\t\tif (dirIterator->index >= dirIterator->dirEntries.size())\n\t\t\treturn false;\n\t\t*dirEntry = dirIterator->dirEntries[dirIterator->index];\n\t\tdirIterator->index++;\n\t\treturn true;\n\t}\n\n\tbool fscRewindDir() override\n\t{\n\t\tif (!dirIterator)\n\t\t\treturn true;\n\n\t\tdirIterator->index  = 0;\n\t\treturn true;\n\t}\n\n\tvoid addUniqueDirEntry(const FSCDirEntry& dirEntry)\n\t{\n\t\t// skip if already in list\n\t\tfor (auto& itr : dirIterator->dirEntries)\n\t\t{\n\t\t\tif (FSA_CompareNodeName(dirEntry.path, itr.path))\n\t\t\t\treturn;\n\t\t}\n\t\tdirIterator->dirEntries.emplace_back(dirEntry);\n\t}\n\nprivate:\n\tvoid PopulateIterationList()\n\t{\n\t\tcemu_assert_debug(!dirIterator);\n\t\tdirIterator = new FSCVirtualFile::FSCDirIteratorState();\n\t\tFSCDirEntry dirEntry;\n\t\tfscEnter();\n\t\tfor (auto& itr : m_folders)\n\t\t{\n\t\t\twhile (itr->fscDirNext(&dirEntry))\n\t\t\t\taddUniqueDirEntry(dirEntry);\n\t\t}\n\t\tfor (sint32 prio = FSC_PRIORITY_COUNT - 1; prio >= 0; prio--)\n\t\t{\n\t\t\tFSCMountPathNode* nodeVirtualPath = fsc_lookupPathVirtualNode(m_path.c_str(), prio);\n\t\t\tif (nodeVirtualPath)\n\t\t\t{\n\t\t\t\tfor (auto& itr : nodeVirtualPath->subnodes)\n\t\t\t\t{\n\t\t\t\t\tdirEntry = {};\n\t\t\t\t\tdirEntry.isDirectory = true;\n\t\t\t\t\tstrncpy(dirEntry.path, itr->path.c_str(), sizeof(dirEntry.path) - 1);\n\t\t\t\t\tdirEntry.path[sizeof(dirEntry.path) - 1] = '\\0';\n\t\t\t\t\tdirEntry.fileSize = 0;\n\t\t\t\t\taddUniqueDirEntry(dirEntry);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfscLeave();\n\t}\n\nprivate:\n\tstd::string m_path;\n\tstd::vector<FSCVirtualFile*> m_folders; // list of all folders mapped to the same directory (at different priorities)\n};\n\n// Open file or directory from virtual file system\nFSCVirtualFile* fsc_open(const char* path, FSC_ACCESS_FLAG accessFlags, sint32* fscStatus, sint32 maxPriority)\n{\n\tcemu_assert_debug(HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE) || HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR)); // must open either file or directory\n\tFSCVirtualFile* dirList[FSC_PRIORITY_COUNT];\n\tuint8 dirListCount = 0;\n\tstd::string devicePath;\n\tfscDeviceC* fscDevice = NULL;\n\t*fscStatus = FSC_STATUS_UNDEFINED;\n\tvoid* ctx;\n\tfscEnter();\n\tfor (sint32 prio = maxPriority; prio >= 0; prio--)\n\t{\n\t\tif (fsc_lookupPath(path, devicePath, &fscDevice, &ctx, prio))\n\t\t{\n\t\t\tFSCVirtualFile* fscVirtualFile = fscDevice->fscDeviceOpenByPath(devicePath, accessFlags, ctx, fscStatus);\n\t\t\tif (fscVirtualFile)\n\t\t\t{\n\t\t\t\tif (fscVirtualFile->fscGetType() == FSC_TYPE_DIRECTORY)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR));\n\t\t\t\t\t// collect all folders \n\t\t\t\t\tdirList[dirListCount] = fscVirtualFile;\n\t\t\t\t\tdirListCount++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// return first found file\n\t\t\t\t\tcemu_assert_debug(HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE));\n\t\t\t\t\tfscVirtualFile->m_isAppend = HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::IS_APPEND);\n\t\t\t\t\tfscLeave();\n\t\t\t\t\treturn fscVirtualFile;\n\t\t\t\t}\t\t\t\t\n\t\t\t}\n\t\t}\n\t}\n\t// for directories we create a virtual representation of the enumerated files of all priorities as well as the FSC folder structure itself\n\tif (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))\n\t{\n\t\t// create a virtual directory VirtualFile that represents all the mounted folders as well as the virtual FSC folder structure\n\t\tbool folderExists = dirListCount > 0;\n\t\tfor (sint32 prio = FSC_PRIORITY_COUNT - 1; prio >= 0; prio--)\n\t\t{\n\t\t\tif (folderExists)\n\t\t\t\tbreak;\n\t\t\tfolderExists |= (fsc_lookupPathVirtualNode(path, prio) != 0);\n\t\t}\n\t\tif (folderExists)\n\t\t{\n\t\t\tFSCVirtualFileDirectoryIterator* dirIteratorFile = new FSCVirtualFileDirectoryIterator(path, { dirList, dirListCount});\n\t\t\t*fscStatus = FSC_STATUS_OK;\n\t\t\tfscLeave();\n\t\t\treturn dirIteratorFile;\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(dirListCount == 0);\n\t}\n\tfscLeave();\n\t*fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\treturn nullptr;\n}\n\n/*\n * Open file using virtual path\n */\nFSCVirtualFile* fsc_openDirIterator(const char* path, sint32* fscStatus)\n{\n\treturn fsc_open(path, FSC_ACCESS_FLAG::OPEN_DIR, fscStatus);\n}\n\n/*\n* Iterate next node in directory\n* Returns false if there is no node left\n*/\nbool fsc_nextDir(FSCVirtualFile* fscFile, FSCDirEntry* dirEntry)\n{\n\tfscEnter();\n\tif (fscFile->fscGetType() != FSC_TYPE_DIRECTORY)\n\t{\n\t\tcemu_assert_suspicious();\n\t\tfscLeave();\n\t\treturn false;\n\t}\n\tbool r = fscFile->fscDirNext(dirEntry);\n\tfscLeave();\n\treturn r;\n}\n\n/*\n * Create directory\n */\nbool fsc_createDir(const char* path, sint32* fscStatus)\n{\n\tfscDeviceC* fscDevice = NULL;\n\t*fscStatus = FSC_STATUS_UNDEFINED;\n\tvoid* ctx;\n\tstd::string devicePath;\n\tfscEnter();\n\tif( fsc_lookupPath(path, devicePath, &fscDevice, &ctx) )\n\t{\n\t\tsint32 status = fscDevice->fscDeviceCreateDir(devicePath, ctx, fscStatus);\n\t\tfscLeave();\n\t\treturn status;\n\t}\n\tfscLeave();\n\treturn false;\n}\n\n/*\n * Rename file or directory\n */\nbool fsc_rename(const char* srcPath, const char* dstPath, sint32* fscStatus)\n{\n\tstd::string srcDevicePath;\n\tstd::string dstDevicePath;\n\tvoid* srcCtx;\n\tvoid* dstCtx;\n\tfscDeviceC* fscSrcDevice = NULL;\n\tfscDeviceC* fscDstDevice = NULL;\n\t*fscStatus = FSC_STATUS_UNDEFINED;\n\tif( fsc_lookupPath(srcPath, srcDevicePath, &fscSrcDevice, &srcCtx) && fsc_lookupPath(dstPath, dstDevicePath, &fscDstDevice, &dstCtx) )\n\t{\n\t\tif( fscSrcDevice == fscDstDevice )\n\t\t\treturn fscSrcDevice->fscDeviceRename(srcDevicePath, dstDevicePath, srcCtx, fscStatus);\n\t}\n\treturn false;\n}\n\n/*\n * Delete file or subdirectory\n */\nbool fsc_remove(const char* path, sint32* fscStatus)\n{\n\tstd::string devicePath;\n\tfscDeviceC* fscDevice = NULL;\n\t*fscStatus = FSC_STATUS_UNDEFINED;\n\tvoid* ctx;\n\tif( fsc_lookupPath(path, devicePath, &fscDevice, &ctx) )\n\t{\n\t\treturn fscDevice->fscDeviceRemoveFileOrDir(devicePath, ctx, fscStatus);\n\t}\n\treturn false;\n}\n\n/*\n * Close file handle\n */\nvoid fsc_close(FSCVirtualFile* fscFile)\n{\n\tfscEnter();\n\tdelete fscFile;\n\tfscLeave();\n}\n\n/*\n * Return size of file\n */\nuint32 fsc_getFileSize(FSCVirtualFile* fscFile)\n{\n\treturn (uint32)fscFile->fscQueryValueU64(FSC_QUERY_SIZE);\n}\n\n/*\n * Return file position\n */\nuint32 fsc_getFileSeek(FSCVirtualFile* fscFile)\n{\n\treturn (uint32)fscFile->fscGetSeek();\n}\n\n/*\n * Set file seek\n * For writable files the seek pointer can be set past the end of the file\n */\nvoid fsc_setFileSeek(FSCVirtualFile* fscFile, uint32 newSeek)\n{\n\tfscEnter();\n\tuint32 fileSize = fsc_getFileSize(fscFile);\n\tif (fsc_isWritable(fscFile) == false)\n\t\tnewSeek = std::min(newSeek, fileSize);\n\tfscFile->fscSetSeek((uint64)newSeek);\n\tfscLeave();\n}\n\n// set file length\nvoid fsc_setFileLength(FSCVirtualFile* fscFile, uint32 newEndOffset)\n{\n\tfscEnter();\n\tuint32 fileSize = fsc_getFileSize(fscFile);\n\tif (!fsc_isWritable(fscFile))\n\t{\n\t\tcemuLog_log(LogType::Force, \"TruncateFile called on read-only file\");\n\t}\n\telse\n\t{\n\t\tfscFile->fscSetFileLength((uint64)newEndOffset);\n\t}\n\tfscLeave();\n}\n\n/*\n * Returns true if the file object is a directory\n */\nbool fsc_isDirectory(FSCVirtualFile* fscFile)\n{\n\treturn fscFile->fscGetType() == FSC_TYPE_DIRECTORY;\n}\n\n/*\n * Returns true if the file object is a file\n */\nbool fsc_isFile(FSCVirtualFile* fscFile)\n{\n\treturn fscFile->fscGetType() == FSC_TYPE_FILE;\n}\n\n/*\n * Returns true if the file is writable\n */\nbool fsc_isWritable(FSCVirtualFile* fscFile)\n{\t\n\treturn fscFile->fscQueryValueU64(FSC_QUERY_WRITEABLE) != 0;\n}\n\n/*\n * Read data from file\n * Returns number of bytes successfully read\n */\nuint32 fsc_readFile(FSCVirtualFile* fscFile, void* buffer, uint32 size)\n{\n\tfscEnter();\n\tuint32 fscStatus = fscFile->fscReadData(buffer, size);\n\tfscLeave();\n\treturn fscStatus;\n}\n\n/*\n * Write data to file\n * Returns number of bytes successfully written\n */\nuint32 fsc_writeFile(FSCVirtualFile* fscFile, void* buffer, uint32 size)\n{\n\tfscEnter();\n\tif (fsc_isWritable(fscFile) == false)\n\t{\n\t\tfscLeave();\n\t\treturn 0;\n\t}\n\tif (fscFile->m_isAppend)\n\t\tfsc_setFileSeek(fscFile, fsc_getFileSize(fscFile));\n\n\tuint32 fscStatus = fscFile->fscWriteData(buffer, size);\n\tfscLeave();\n\treturn fscStatus;\n}\n\n// helper function to load a file into memory\nuint8* fsc_extractFile(const char* path, uint32* fileSize, sint32 maxPriority)\n{\n\tfscDeviceC* fscDevice = nullptr;\n\tsint32 fscStatus = FSC_STATUS_UNDEFINED;\n\tfscEnter();\n\tFSCVirtualFile* fscFile = fsc_open(path, FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus, maxPriority);\n\tif( !fscFile )\n\t{\n\t\t*fileSize = 0;\n\t\tfscLeave();\n\t\treturn nullptr;\n\t}\n\tuint32 fscFileSize = fsc_getFileSize(fscFile);\n\t*fileSize = fscFileSize;\n\tuint8* fileMem = (uint8*)malloc(fscFileSize);\n\tif( fsc_readFile(fscFile, fileMem, fscFileSize) != fscFileSize )\n\t{\n\t\tfree(fileMem);\n\t\tfsc_close(fscFile);\n\t\t*fileSize = 0;\n\t\tfscLeave();\n\t\treturn nullptr;\n\t}\n\tfsc_close(fscFile);\n\tfscLeave();\n\treturn fileMem;\n}\n\nstd::optional<std::vector<uint8>> fsc_extractFile(const char* path, sint32 maxPriority)\n{\n\tfscDeviceC* fscDevice = nullptr;\n\tsint32 fscStatus = FSC_STATUS_UNDEFINED;\n\tfscEnter();\n\tFSCVirtualFile* fscFile = fsc_open(path, FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus, maxPriority);\n\tif (!fscFile)\n\t{\n\t\tfscLeave();\n\t\treturn std::nullopt;\n\t}\n\tstd::vector<uint8> fileData;\n\tuint32 fscFileSize = fsc_getFileSize(fscFile);\n\tfileData.resize(fscFileSize);\n\n\tuint32 readOffset = 0;\n\twhile (readOffset < fscFileSize)\n\t{\n\t\tuint32 stepReadSize = std::min(fscFileSize - readOffset, (uint32)1024 * 1024 * 32);\n\t\tuint32 numBytesRead = fsc_readFile(fscFile, fileData.data() + readOffset, stepReadSize);\n\t\tif (numBytesRead != stepReadSize)\n\t\t{\n\t\t\tfsc_close(fscFile);\n\t\t\tfscLeave();\n\t\t\treturn std::nullopt;\n\t\t}\n\t\treadOffset += stepReadSize;\n\t}\n\tfsc_close(fscFile);\n\tfscLeave();\n\treturn fileData;\n}\n\n// helper function to check if a file exists\nbool fsc_doesFileExist(const char* path, sint32 maxPriority)\n{\n\tfscDeviceC* fscDevice = nullptr;\n\tsint32 fscStatus = FSC_STATUS_UNDEFINED;\n\tfscEnter();\n\tFSCVirtualFile* fscFile = fsc_open(path, FSC_ACCESS_FLAG::OPEN_FILE, &fscStatus, maxPriority);\n\tif (!fscFile)\n\t{\n\t\tfscLeave();\n\t\treturn false;\n\t}\n\tfsc_close(fscFile);\n\tfscLeave();\n\treturn true;\n}\n\n// helper function to check if a directory exists\nbool fsc_doesDirectoryExist(const char* path, sint32 maxPriority)\n{\n\tfscDeviceC* fscDevice = nullptr;\n\tsint32 fscStatus = FSC_STATUS_UNDEFINED;\n\tfscEnter();\n\tFSCVirtualFile* fscFile = fsc_open(path, FSC_ACCESS_FLAG::OPEN_DIR, &fscStatus, maxPriority);\n\tif (!fscFile)\n\t{\n\t\tfscLeave();\n\t\treturn false;\n\t}\n\tfsc_close(fscFile);\n\tfscLeave();\n\treturn true;\n}\n\n// initialize Cemu's virtual filesystem\nvoid fsc_init()\n{\n\tfsc_reset();\n}\n"
  },
  {
    "path": "src/Cafe/Filesystem/fsc.h",
    "content": "#pragma once\n\nstruct FSCVirtualFile;\n\n#define FSC_TYPE_INVALID\t\t\t\t(0)\n#define FSC_TYPE_FILE\t\t\t\t\t(1)\n#define FSC_TYPE_DIRECTORY\t\t\t\t(2)\n\n#define FSC_QUERY_SIZE\t\t\t\t\t(1) // file size, 0 for directories\n#define FSC_QUERY_WRITEABLE\t\t\t\t(2) // non-zero if file is writeable, else 0\n\nenum class FSC_ACCESS_FLAG : uint8\n{\n\tNONE = 0,\n\n\t// file permissions\n\tREAD_PERMISSION = (1<<0),\n\tWRITE_PERMISSION = (1<<1),\n\n\t// file open mode (incompatible with OPEN_DIR flag)\n\tFILE_ALLOW_CREATE = (1 << 2), // create file if it does not exist\n\tFILE_ALWAYS_CREATE = (1 << 3), // overwrite any existing file\n\n\t// which types can be opened\n\t// invalid operation if neither is set\n\tOPEN_DIR = (1 << 4), \n\tOPEN_FILE = (1 << 5),\n\n\t// Writing seeks to the end of the file if set\n\tIS_APPEND = (1 << 6)\n};\nDEFINE_ENUM_FLAG_OPERATORS(FSC_ACCESS_FLAG);\n\n#define FSC_STATUS_UNDEFINED\t\t\t(-1)\n#define FSC_STATUS_OK\t\t\t\t\t(0)\n#define FSC_STATUS_INVALID_PATH\t\t\t(1)\n#define FSC_STATUS_FILE_NOT_FOUND\t\t(2)\n#define FSC_STATUS_ALREADY_EXISTS\t\t(3)\n// note: Unlike the native Wii U filesystem, FSC does not provide separate error codes for NOT_A_FILE and NOT_A_DIRECTORY\n// to determine them manually, open with both modes (file and dir) and check the type\n\n#define FSC_MAX_DIR_NAME_LENGTH\t\t\t(256)\n#define FSC_MAX_DEVICE_PATH_LENGTH\t\t((std::max)(260,FSA_PATH_SIZE_MAX))\t// max length for FSC device paths (should be at least equal or greater than supported by host filesystem)\n\nstruct FSCDirEntry\n{\n\tchar path[FSC_MAX_DIR_NAME_LENGTH];\n\t// stats\n\tbool isDirectory;\n\tbool isFile;\n\tuint32 fileSize;\n\n\tstd::string_view GetPath()\n\t{\n\t\tsize_t len = strnlen(path, FSC_MAX_DIR_NAME_LENGTH);\n\t\treturn std::basic_string_view<char>(path, len);\n\t}\n};\n\nclass fscDeviceC\n{\npublic:\n\tvirtual FSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus)\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn nullptr;\n\t}\n\n\tvirtual bool fscDeviceCreateDir(std::string_view path, void* ctx, sint32* fscStatus)\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn false;\n\t}\n\n\tvirtual bool fscDeviceRemoveFileOrDir(std::string_view path, void* ctx, sint32* fscStatus)\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn false;\n\t}\n\n\tvirtual bool fscDeviceRename(std::string_view srcPath, std::string_view dstPath, void* ctx, sint32* fscStatus)\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn false;\n\t}\n\n};\n\n\nstruct FSCVirtualFile\n{\n\tstruct FSCDirIteratorState\n\t{\n\t\tsint32 index;\n\t\tstd::vector<FSCDirEntry> dirEntries;\n\t};\n\n\tFSCVirtualFile()\n\t{\n\n\t}\n\n\tvirtual ~FSCVirtualFile()\n\t{\n\t\tif (dirIterator)\n\t\t\tdelete dirIterator;\n\t}\n\n\tvirtual sint32 fscGetType()\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn 0;\n\t}\n\n\tvirtual uint64 fscQueryValueU64(uint32 id)\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn 0;\n\t}\n\n\tvirtual uint32 fscWriteData(void* buffer, uint32 size)\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn 0;\n\t}\n\n\tvirtual uint32 fscReadData(void* buffer, uint32 size)\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn 0;\n\t}\n\n\tvirtual void fscSetSeek(uint64 seek)\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tvirtual uint64 fscGetSeek()\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn 0;\n\t}\n\n\tvirtual void fscSetFileLength(uint64 endOffset)\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tvirtual bool fscDirNext(FSCDirEntry* dirEntry)\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn false;\n\t}\n\n\tvirtual bool fscRewindDir()\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn false;\n\t}\n\n\tFSCDirIteratorState* dirIterator{};\n\n\tbool m_isAppend{ false };\n};\n\n#define FSC_PRIORITY_BASE\t\t\t\t(0)\n#define FSC_PRIORITY_AOC\t\t\t\t(1)\n#define FSC_PRIORITY_PATCH\t\t\t\t(2)\n#define FSC_PRIORITY_REDIRECT\t\t\t(3)\n#define FSC_PRIORITY_MAX\t\t\t\t(3)\n\n#define FSC_PRIORITY_COUNT\t\t\t\t(4)\n\nvoid fsc_init();\nsint32 fsc_mount(std::string_view mountPath, std::string_view targetPath, fscDeviceC* fscDevice, void* ctx, sint32 priority=0);\nbool fsc_unmount(std::string_view mountPath, sint32 priority);\nvoid fsc_unmountAll();\n\nFSCVirtualFile* fsc_open(const char* path, FSC_ACCESS_FLAG accessFlags, sint32* fscStatus, sint32 maxPriority=FSC_PRIORITY_MAX);\nFSCVirtualFile* fsc_openDirIterator(const char* path, sint32* fscStatus);\nbool fsc_createDir(const char* path, sint32* fscStatus);\nbool fsc_rename(const char* srcPath, const char* dstPath, sint32* fscStatus);\nbool fsc_remove(const char* path, sint32* fscStatus);\nbool fsc_nextDir(FSCVirtualFile* fscFile, FSCDirEntry* dirEntry);\nvoid fsc_close(FSCVirtualFile* fscFile);\nuint32 fsc_getFileSize(FSCVirtualFile* fscFile);\nuint32 fsc_getFileSeek(FSCVirtualFile* fscFile);\nvoid fsc_setFileSeek(FSCVirtualFile* fscFile, uint32 newSeek);\nvoid fsc_setFileLength(FSCVirtualFile* fscFile, uint32 newEndOffset);\nbool fsc_isDirectory(FSCVirtualFile* fscFile);\nbool fsc_isFile(FSCVirtualFile* fscFile);\nbool fsc_isWritable(FSCVirtualFile* fscFile);\nuint32 fsc_readFile(FSCVirtualFile* fscFile, void* buffer, uint32 size);\nuint32 fsc_writeFile(FSCVirtualFile* fscFile, void* buffer, uint32 size);\n\nuint8* fsc_extractFile(const char* path, uint32* fileSize, sint32 maxPriority = FSC_PRIORITY_MAX);\nstd::optional<std::vector<uint8>> fsc_extractFile(const char* path, sint32 maxPriority = FSC_PRIORITY_MAX);\nbool fsc_doesFileExist(const char* path, sint32 maxPriority = FSC_PRIORITY_MAX);\nbool fsc_doesDirectoryExist(const char* path, sint32 maxPriority = FSC_PRIORITY_MAX);\n\n// wud device\nbool FSCDeviceWUD_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class FSTVolume* mountedVolume, sint32 priority);\n\n// wua device\nbool FSCDeviceWUA_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class ZArchiveReader* archive, sint32 priority);\n\n// wuhb device\nbool FSCDeviceWUHB_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class WUHBReader* wuhbReader, sint32 priority);\n\n// hostFS device\nbool FSCDeviceHostFS_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority);\n\n// redirect device\nvoid fscDeviceRedirect_map();\nvoid fscDeviceRedirect_add(std::string_view virtualSourcePath, size_t fileSize, const fs::path& targetFilePath, sint32 priority);\n"
  },
  {
    "path": "src/Cafe/Filesystem/fscDeviceHostFS.cpp",
    "content": "#include \"config/ActiveSettings.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n#include \"Cafe/Filesystem/fscDeviceHostFS.h\"\n\n#include \"Common/FileStream.h\"\n\n/* FSCVirtualFile implementation for HostFS */\n\nFSCVirtualFile_Host::~FSCVirtualFile_Host()\n{\n\tif (m_type == FSC_TYPE_FILE)\n\t\tdelete m_fs;\n}\n\nsint32 FSCVirtualFile_Host::fscGetType()\n{\n\treturn m_type;\n}\n\nuint32 FSCVirtualFile_Host::fscDeviceHostFSFile_getFileSize()\n{\n\tif (m_type == FSC_TYPE_FILE)\n\t{\n\t\tif (m_fileSize > 0xFFFFFFFFULL)\n\t\t\tcemu_assert_suspicious(); // files larger than 4GB are not supported by Wii U filesystem\n\t\treturn (uint32)m_fileSize;\n\t}\n\telse if (m_type == FSC_TYPE_DIRECTORY)\n\t{\n\t\t// todo\n\t\treturn (uint32)0;\n\t}\n\treturn 0;\n}\n\nuint64 FSCVirtualFile_Host::fscQueryValueU64(uint32 id)\n{\n\tif (m_type == FSC_TYPE_FILE)\n\t{\n\t\tif (id == FSC_QUERY_SIZE)\n\t\t\treturn fscDeviceHostFSFile_getFileSize();\n\t\telse if (id == FSC_QUERY_WRITEABLE)\n\t\t\treturn m_isWritable;\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse if (m_type == FSC_TYPE_DIRECTORY)\n\t{\n\t\tif (id == FSC_QUERY_SIZE)\n\t\t\treturn fscDeviceHostFSFile_getFileSize();\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\tcemu_assert_unimplemented();\n\treturn 0;\n}\n\nuint32 FSCVirtualFile_Host::fscWriteData(void* buffer, uint32 size)\n{\n\tif (m_type != FSC_TYPE_FILE)\n\t\treturn 0;\n\tif (size >= (2UL * 1024UL * 1024UL * 1024UL))\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn 0;\n\t}\n\tsint32 writtenBytes = m_fs->writeData(buffer, (sint32)size);\n\tm_seek += (uint64)writtenBytes;\n\tm_fileSize = std::max(m_fileSize, m_seek);\n\treturn (uint32)writtenBytes;\n}\n\nuint32 FSCVirtualFile_Host::fscReadData(void* buffer, uint32 size)\n{\n\tif (m_type != FSC_TYPE_FILE)\n\t\treturn 0;\n\tif (size >= (2UL * 1024UL * 1024UL * 1024UL))\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn 0;\n\t}\n\tuint32 bytesLeft = (uint32)(m_fileSize - m_seek);\n\tbytesLeft = std::min(bytesLeft, 0x7FFFFFFFu);\n\tsint32 bytesToRead = std::min(bytesLeft, size);\n\tuint32 bytesRead = m_fs->readData(buffer, bytesToRead);\n\tm_seek += bytesRead;\n\treturn bytesRead;\n}\n\nvoid FSCVirtualFile_Host::fscSetSeek(uint64 seek)\n{\n\tif (m_type != FSC_TYPE_FILE)\n\t\treturn;\n\tthis->m_seek = seek;\n\tcemu_assert_debug(seek <= m_fileSize);\n\tm_fs->SetPosition(seek);\n}\n\nuint64 FSCVirtualFile_Host::fscGetSeek()\n{\n\tif (m_type != FSC_TYPE_FILE)\n\t\treturn 0;\n\treturn m_seek;\n}\n\nvoid FSCVirtualFile_Host::fscSetFileLength(uint64 endOffset)\n{\n\tif (m_type != FSC_TYPE_FILE)\n\t\treturn;\n\tm_fs->SetPosition(endOffset);\n\tbool r = m_fs->SetEndOfFile();\n\tm_seek = std::min(m_seek, endOffset);\n\tm_fileSize = m_seek;\n\tm_fs->SetPosition(m_seek);\n\tif (!r)\n\t\tcemuLog_log(LogType::Force, \"fscSetFileLength: Failed to set size to 0x{:x}\", endOffset);\n}\n\nbool FSCVirtualFile_Host::fscDirNext(FSCDirEntry* dirEntry)\n{\n\tif (m_type != FSC_TYPE_DIRECTORY)\n\t\treturn false;\n\n\tif (!m_dirIterator)\n\t{\n\t\t// init iterator on first iteration attempt\n\t\tm_dirIterator.reset(new fs::directory_iterator(*m_path));\n\t\tif (!m_dirIterator)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to iterate directory: {}\", _pathToUtf8(*m_path));\n\t\t\treturn false;\n\t\t}\n\t}\n\tif (*m_dirIterator == fs::end(*m_dirIterator))\n\t\treturn false;\n\n\tconst fs::directory_entry& entry = **m_dirIterator;\n\t\n\tstd::string fileName = entry.path().filename().generic_string();\n\tif (fileName.size() >= sizeof(dirEntry->path) - 1)\n\t\tfileName.resize(sizeof(dirEntry->path) - 1);\n\tstrncpy(dirEntry->path, fileName.data(), sizeof(dirEntry->path));\n\tif (entry.is_directory())\n\t{\n\t\tdirEntry->isDirectory = true;\n\t\tdirEntry->isFile = false;\n\t\tdirEntry->fileSize = 0;\n\t}\n\telse\n\t{\n\t\tdirEntry->isDirectory = false;\n\t\tdirEntry->isFile = true;\n\t\tdirEntry->fileSize = entry.file_size();\n\t}\n\n\t(*m_dirIterator)++;\n\treturn true;\n}\n\nFSCVirtualFile* FSCVirtualFile_Host::OpenFile(const fs::path& path, FSC_ACCESS_FLAG accessFlags, sint32& fscStatus)\n{\n\tif (!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE) && !HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))\n\t\tcemu_assert_debug(false); // not allowed. At least one of both flags must be set\n\n\t// attempt to open as file\n\tif (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE))\n\t{\n\t\tFileStream* fs{};\n\t\tbool writeAccessRequested = HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::WRITE_PERMISSION);\n\t\tif (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::FILE_ALLOW_CREATE))\n\t\t{\n\t\t\tfs = FileStream::openFile2(path, writeAccessRequested);\n\t\t\tif (!fs)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(writeAccessRequested);\n\t\t\t\tfs = FileStream::createFile2(path);\n\t\t\t\tif (!fs)\n\t\t\t\t\tcemuLog_log(LogType::Force, \"FSC: File create failed for {}\", _pathToUtf8(path));\n\t\t\t}\n\t\t}\n\t\telse if (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::FILE_ALWAYS_CREATE))\n\t\t{\n\t\t\tfs = FileStream::createFile2(path);\n\t\t\tif (!fs)\n\t\t\t\tcemuLog_log(LogType::Force, \"FSC: File create failed for {}\", _pathToUtf8(path));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfs = FileStream::openFile2(path, writeAccessRequested);\n\t\t}\n\t\tif (fs)\n\t\t{\n\t\t\tFSCVirtualFile_Host* vf = new FSCVirtualFile_Host(FSC_TYPE_FILE);\n\t\t\tvf->m_fs = fs;\n\t\t\tvf->m_isWritable = writeAccessRequested;\n\t\t\tvf->m_fileSize = fs->GetSize();\n\t\t\tfscStatus = FSC_STATUS_OK;\n\t\t\treturn vf;\n\t\t}\n\t}\n\n\t// attempt to open as directory\n\tif (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))\n\t{\n\t\tstd::error_code ec;\n\t\tbool isExistingDir = fs::is_directory(path, ec);\n\t\tif (isExistingDir)\n\t\t{\n\t\t\tFSCVirtualFile_Host* vf = new FSCVirtualFile_Host(FSC_TYPE_DIRECTORY);\n\t\t\tvf->m_path.reset(new std::filesystem::path(path));\n\t\t\tfscStatus = FSC_STATUS_OK;\n\t\t\treturn vf;\n\t\t}\n\t}\n\tfscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\treturn nullptr;\n}\n\n/* Device implementation */\n\nclass fscDeviceHostFSC : public fscDeviceC\n{\npublic:\n\tFSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override\n\t{\n\t\t*fscStatus = FSC_STATUS_OK;\n\t\tFSCVirtualFile* vf = FSCVirtualFile_Host::OpenFile(_utf8ToPath(path), accessFlags, *fscStatus);\n\t\tcemu_assert_debug((bool)vf == (*fscStatus == FSC_STATUS_OK));\n\t\treturn vf;\n\t}\n\n\tbool fscDeviceCreateDir(std::string_view path, void* ctx, sint32* fscStatus) override\n\t{\n\t\tfs::path dirPath = _utf8ToPath(path);\n\t\tif (fs::exists(dirPath))\n\t\t{\n\t\t\tif (!fs::is_directory(dirPath))\n\t\t\t\tcemuLog_log(LogType::Force, \"CreateDir: {} already exists but is not a directory\", path);\n\t\t\t*fscStatus = FSC_STATUS_ALREADY_EXISTS;\n\t\t\treturn false;\n\t\t}\n\t\tstd::error_code ec;\n\t\tbool r = fs::create_directories(dirPath, ec);\n\t\tif (!r)\n\t\t\tcemuLog_log(LogType::Force, \"CreateDir: Failed to create {}\", path);\n\t\t*fscStatus = FSC_STATUS_OK;\n\t\treturn true;\n\t}\n\n\tbool fscDeviceRemoveFileOrDir(std::string_view path, void* ctx, sint32* fscStatus) override\n\t{\n\t\t*fscStatus = FSC_STATUS_OK;\n\t\tfs::path _path = _utf8ToPath(path);\n\t\tstd::error_code ec;\n\t\tif (!fs::exists(_path, ec))\n\t\t{\n\t\t\t*fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\treturn false;\n\t\t}\n\t\tif (!fs::remove(_path, ec))\n\t\t{\n\t\t\tcemu_assert_unimplemented(); // return correct error (e.g. if directory is non-empty)\n\t\t\t*fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool fscDeviceRename(std::string_view srcPath, std::string_view dstPath, void* ctx, sint32* fscStatus) override\n\t{\n\t\t*fscStatus = FSC_STATUS_OK;\n\t\tfs::path _srcPath = _utf8ToPath(srcPath);\n\t\tfs::path _dstPath = _utf8ToPath(dstPath);\n\t\tstd::error_code ec;\n\t\tif (!fs::exists(_srcPath, ec))\n\t\t{\n\t\t\t*fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\treturn false;\n\t\t}\n\t\tfs::rename(_srcPath, _dstPath, ec);\n\t\treturn true;\n\t}\n\n\t// singleton\npublic:\n\tstatic fscDeviceHostFSC& instance()\n\t{\n\t\tstatic fscDeviceHostFSC _instance;\n\t\treturn _instance;\n\t}\n};\n\nbool FSCDeviceHostFS_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority)\n{\n\treturn fsc_mount(mountPath, hostTargetPath, &fscDeviceHostFSC::instance(), nullptr, priority) == FSC_STATUS_OK;\n}"
  },
  {
    "path": "src/Cafe/Filesystem/fscDeviceHostFS.h",
    "content": "#include \"Cafe/Filesystem/fsc.h\"\n\nclass FSCVirtualFile_Host : public FSCVirtualFile\n{\npublic:\n\tstatic FSCVirtualFile* OpenFile(const fs::path& path, FSC_ACCESS_FLAG accessFlags, sint32& fscStatus);\n\t~FSCVirtualFile_Host() override;\n\n\tsint32 fscGetType() override;\n\n\tuint32 fscDeviceHostFSFile_getFileSize();\n\n\tuint64 fscQueryValueU64(uint32 id) override;\n\tuint32 fscWriteData(void* buffer, uint32 size) override;\n\tuint32 fscReadData(void* buffer, uint32 size) override;\n\tvoid fscSetSeek(uint64 seek) override;\n\tuint64 fscGetSeek() override;\n\tvoid fscSetFileLength(uint64 endOffset) override;\n\tbool fscDirNext(FSCDirEntry* dirEntry) override;\n\nprivate:\n\tFSCVirtualFile_Host(uint32 type) : m_type(type) {};\n\nprivate:\n\tuint32 m_type; // FSC_TYPE_*\n\tclass FileStream* m_fs{};\n\t// file\n\tuint64 m_seek{ 0 };\n\tuint64 m_fileSize{ 0 };\n\tbool m_isWritable{ false };\n\t// directory\n\tstd::unique_ptr<std::filesystem::path> m_path{};\n\tstd::unique_ptr<std::filesystem::directory_iterator> m_dirIterator{};\n};"
  },
  {
    "path": "src/Cafe/Filesystem/fscDeviceRedirect.cpp",
    "content": "#include \"util/helpers/helpers.h\"\n#include \"Cafe/Filesystem/fscDeviceHostFS.h\"\n#include \"FST/fstUtil.h\"\n\nstruct RedirectEntry\n{\n\tRedirectEntry(const fs::path& dstPath, sint32 priority) : dstPath(dstPath), priority(priority) {}\n\tfs::path dstPath;\n\tsint32 priority;\n};\n\nFSAFileTree<RedirectEntry> redirectTree;\n\nvoid fscDeviceRedirect_add(std::string_view virtualSourcePath, size_t fileSize, const fs::path& targetFilePath, sint32 priority)\n{\n\t// check if source already has a redirection\n\tRedirectEntry* existingEntry;\n\tif (redirectTree.getFile(virtualSourcePath, existingEntry))\n\t{\n\t\tif (existingEntry->priority >= priority)\n\t\t\treturn; // dont replace entries with equal or higher priority\n\t\t// unregister existing entry\n\t\tredirectTree.removeFile(virtualSourcePath);\n\t\tdelete existingEntry;\n\t}\n\tRedirectEntry* entry = new RedirectEntry(targetFilePath, priority);\n\tredirectTree.addFile(virtualSourcePath, fileSize, entry);\n}\n\nclass fscDeviceTypeRedirect : public fscDeviceC\n{\n\tFSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override\n\t{\n\t\tRedirectEntry* redirectionEntry;\n\n\t\tif (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE) && redirectTree.getFile(path, redirectionEntry))\n\t\t\treturn FSCVirtualFile_Host::OpenFile(redirectionEntry->dstPath, accessFlags, *fscStatus);\n\n\t\tFSCVirtualFile* dirIterator;\n\n\t\tif (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR) && redirectTree.getDirectory(path, dirIterator))\n\t\t\treturn dirIterator;\n\n\t\treturn nullptr;\n\t}\n\npublic:\n\tstatic fscDeviceTypeRedirect& instance()\n\t{\n\t\tstatic fscDeviceTypeRedirect _instance;\n\t\treturn _instance;\n\t}\n};\n\nbool _redirectMapped = false;\n\nvoid fscDeviceRedirect_map()\n{\n\tif (_redirectMapped)\n\t\treturn;\n\tfsc_mount(\"/\", \"/\", &fscDeviceTypeRedirect::instance(), nullptr, FSC_PRIORITY_REDIRECT);\n\t_redirectMapped = true;\n}\n"
  },
  {
    "path": "src/Cafe/Filesystem/fscDeviceWua.cpp",
    "content": "#include \"Cafe/Filesystem/fsc.h\"\n#include <zarchive/zarchivereader.h>\n\nclass FSCDeviceWuaFileCtx : public FSCVirtualFile\n{\n\tfriend class fscDeviceWUAC;\n\nprotected:\n\tFSCDeviceWuaFileCtx(ZArchiveReader* archive, ZArchiveNodeHandle fstFileHandle, uint32 fscType)\n\t{\n\t\tthis->m_archive = archive;\n\t\tthis->m_fscType = fscType;\n\t\tthis->m_nodeHandle = fstFileHandle;\n\t\tthis->m_seek = 0;\n\t};\n\npublic:\n\tsint32 fscGetType() override\n\t{\n\t\treturn m_fscType;\n\t}\n\n\tuint32 fscDeviceWuaFile_getFileSize()\n\t{\n\t\treturn (uint32)m_archive->GetFileSize(m_nodeHandle);\n\t}\n\n\tuint64 fscQueryValueU64(uint32 id) override\n\t{\n\t\tif (m_fscType == FSC_TYPE_FILE)\n\t\t{\n\t\t\tif (id == FSC_QUERY_SIZE)\n\t\t\t\treturn fscDeviceWuaFile_getFileSize();\n\t\t\telse if (id == FSC_QUERY_WRITEABLE)\n\t\t\t\treturn 0; // WUD images are read-only\n\t\t\telse\n\t\t\t\tcemu_assert_error();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\treturn 0;\n\t}\n\n\tuint32 fscWriteData(void* buffer, uint32 size) override\n\t{\n\t\tcemu_assert_error();\n\t\treturn 0;\n\t}\n\n\tuint32 fscReadData(void* buffer, uint32 size) override\n\t{\n\t\tif (m_fscType != FSC_TYPE_FILE)\n\t\t\treturn 0;\n\t\tcemu_assert(size < (2ULL * 1024 * 1024 * 1024)); // single read operation larger than 2GiB not supported\n\t\tuint32 bytesLeft = fscDeviceWuaFile_getFileSize() - m_seek;\n\t\tuint32 bytesToRead = (std::min)(bytesLeft, (uint32)size);\n\t\tuint32 bytesSuccessfullyRead = (uint32)m_archive->ReadFromFile(m_nodeHandle, m_seek, bytesToRead, buffer);\n\t\tm_seek += bytesSuccessfullyRead;\n\t\treturn bytesSuccessfullyRead;\n\t}\n\n\tvoid fscSetSeek(uint64 seek) override\n\t{\n\t\tif (m_fscType != FSC_TYPE_FILE)\n\t\t\treturn;\n\t\tcemu_assert_debug(seek <= 0xFFFFFFFFULL);\n\t\tthis->m_seek = (uint32)seek;\n\t}\n\n\tuint64 fscGetSeek() override\n\t{\n\t\tif (m_fscType != FSC_TYPE_FILE)\n\t\t\treturn 0;\n\t\treturn m_seek;\n\t}\n\n\tbool fscDirNext(FSCDirEntry* dirEntry) override\n\t{\n\t\tif (m_fscType != FSC_TYPE_DIRECTORY)\n\t\t\treturn false;\n\n\t\tZArchiveReader::DirEntry zarDirEntry;\n\t\tif (!m_archive->GetDirEntry(m_nodeHandle, m_iteratorIndex, zarDirEntry))\n\t\t\treturn false;\n\t\tm_iteratorIndex++;\n\n\t\tif (zarDirEntry.isDirectory)\n\t\t{\n\t\t\tdirEntry->isDirectory = true;\n\t\t\tdirEntry->isFile = false;\n\t\t\tdirEntry->fileSize = 0;\n\t\t}\n\t\telse if(zarDirEntry.isFile)\n\t\t{\n\t\t\tdirEntry->isDirectory = false;\n\t\t\tdirEntry->isFile = true;\n\t\t\tdirEntry->fileSize = (uint32)zarDirEntry.size;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t\tstd::memset(dirEntry->path, 0, sizeof(dirEntry->path));\n\t\tstd::strncpy(dirEntry->path, zarDirEntry.name.data(), std::min(sizeof(dirEntry->path) - 1, zarDirEntry.name.size()));\n\t\treturn true;\n\t}\n\nprivate:\n\tZArchiveReader* m_archive{nullptr};\n\tsint32 m_fscType;\n\tZArchiveNodeHandle m_nodeHandle;\n\t// file\n\tuint32 m_seek{0};\n\t// directory\n\tuint32 m_iteratorIndex{0};\n};\n\nclass fscDeviceWUAC : public fscDeviceC\n{\n\tFSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override\n\t{\n\t\tZArchiveReader* archive = (ZArchiveReader*)ctx;\n\t\tcemu_assert_debug(!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::WRITE_PERMISSION)); // writing to WUA is not supported\n\n\t\tZArchiveNodeHandle fileHandle = archive->LookUp(path, true, true);\n\t\tif (fileHandle == ZARCHIVE_INVALID_NODE)\n\t\t{\n\t\t\t*fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\treturn nullptr;\n\t\t}\n\t\tif (archive->IsFile(fileHandle))\n\t\t{\n\t\t\tif (!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE))\n\t\t\t{\n\t\t\t\t*fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\t*fscStatus = FSC_STATUS_OK;\n\t\t\treturn new FSCDeviceWuaFileCtx(archive, fileHandle, FSC_TYPE_FILE);\n\t\t}\n\t\telse if (archive->IsDirectory(fileHandle))\n\t\t{\n\t\t\tif (!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))\n\t\t\t{\n\t\t\t\t*fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\t*fscStatus = FSC_STATUS_OK;\n\t\t\treturn new FSCDeviceWuaFileCtx(archive, fileHandle, FSC_TYPE_DIRECTORY);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t\t*fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\treturn nullptr;\n\t}\n\n\t// singleton\npublic:\n\tstatic fscDeviceWUAC& instance()\n\t{\n\t\tstatic fscDeviceWUAC _instance;\n\t\treturn _instance;\n\t}\n};\n\nbool FSCDeviceWUA_Mount(std::string_view mountPath, std::string_view destinationBaseDir, ZArchiveReader* archive, sint32 priority)\n{\n\treturn fsc_mount(mountPath, destinationBaseDir, &fscDeviceWUAC::instance(), archive, priority) == FSC_STATUS_OK;\n}"
  },
  {
    "path": "src/Cafe/Filesystem/fscDeviceWud.cpp",
    "content": "#include \"Cafe/Filesystem/fsc.h\"\n#include \"Cafe/Filesystem/FST/FST.h\"\n\nclass FSCDeviceWudFileCtx : public FSCVirtualFile\n{\n\tfriend class fscDeviceWUDC;\n\nprotected:\n\tFSCDeviceWudFileCtx(FSTVolume* _volume, FSTFileHandle _fstFileHandle)\n\t{\n\t\tthis->m_volume = _volume;\n\t\tthis->m_fscType = FSC_TYPE_FILE;\n\t\tthis->m_fstFileHandle = _fstFileHandle;\n\t\tthis->m_seek = 0;\n\t};\n\n\tFSCDeviceWudFileCtx(FSTVolume* _volume, FSTDirectoryIterator _dirIterator)\n\t{\n\t\tthis->m_volume = _volume;\n\t\tthis->m_fscType = FSC_TYPE_DIRECTORY;\n\t\tthis->m_dirIterator = _dirIterator;\n\t}\n\npublic:\n\tsint32 fscGetType() override\n\t{\n\t\treturn m_fscType;\n\t}\n\n\tuint32 fscDeviceWudFile_getFileSize()\n\t{\n\t\treturn m_volume->GetFileSize(m_fstFileHandle);\n\t}\n\n\tuint64 fscQueryValueU64(uint32 id) override\n\t{\n\t\tif (m_fscType == FSC_TYPE_FILE)\n\t\t{\n\t\t\tif (id == FSC_QUERY_SIZE)\n\t\t\t\treturn fscDeviceWudFile_getFileSize();\n\t\t\telse if (id == FSC_QUERY_WRITEABLE)\n\t\t\t\treturn 0; // WUD images are read-only\n\t\t\telse\n\t\t\t\tcemu_assert_error();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\treturn 0;\n\t}\n\n\tuint32 fscWriteData(void* buffer, uint32 size) override\n\t{\n\t\tcemu_assert_error();\n\t\treturn 0;\n\t}\n\n\tuint32 fscReadData(void* buffer, uint32 size) override\n\t{\n\t\tif (m_fscType != FSC_TYPE_FILE)\n\t\t\treturn 0;\n\t\tcemu_assert(size < (2ULL * 1024 * 1024 * 1024)); // single read operation larger than 2GiB not supported\n\t\tuint32 bytesLeft = fscDeviceWudFile_getFileSize() - m_seek;\n\t\tuint32 bytesToRead = (std::min)(bytesLeft, (uint32)size);\n\t\tuint32 bytesSuccessfullyRead = m_volume->ReadFile(m_fstFileHandle, m_seek, bytesToRead, buffer);\n\t\tm_seek += bytesSuccessfullyRead;\n\t\treturn bytesSuccessfullyRead;\n\t}\n\n\tvoid fscSetSeek(uint64 seek) override\n\t{\n\t\tif (m_fscType != FSC_TYPE_FILE)\n\t\t\treturn;\n\t\tcemu_assert_debug(seek <= 0xFFFFFFFFULL);\n\t\tthis->m_seek = (uint32)seek;\n\t}\n\n\tuint64 fscGetSeek() override\n\t{\n\t\tif (m_fscType != FSC_TYPE_FILE)\n\t\t\treturn 0;\n\t\treturn m_seek;\n\t}\n\n\tbool fscDirNext(FSCDirEntry* dirEntry) override\n\t{\n\t\tif (m_fscType != FSC_TYPE_DIRECTORY)\n\t\t\treturn false;\n\t\tFSTFileHandle entryItr;\n\t\tif (!m_volume->Next(m_dirIterator, entryItr))\n\t\t\treturn false;\n\t\tif (m_volume->IsDirectory(entryItr))\n\t\t{\n\t\t\tdirEntry->isDirectory = true;\n\t\t\tdirEntry->isFile = false;\n\t\t\tdirEntry->fileSize = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdirEntry->isDirectory = false;\n\t\t\tdirEntry->isFile = true;\n\t\t\tdirEntry->fileSize = m_volume->GetFileSize(entryItr);\n\t\t}\n\t\tauto path = m_volume->GetName(entryItr);\n\t\tstd::memset(dirEntry->path, 0, sizeof(dirEntry->path));\n\t\tstd::strncpy(dirEntry->path, path.data(), std::min(sizeof(dirEntry->path) - 1, path.size()));\n\t\treturn true;\n\t}\n\nprivate:\n\tFSTVolume* m_volume{nullptr};\n\tsint32 m_fscType;\n\tFSTFileHandle m_fstFileHandle;\n\t// file\n\tuint32 m_seek{0};\n\t// directory\n\tFSTDirectoryIterator m_dirIterator{};\n};\n\nclass fscDeviceWUDC : public fscDeviceC\n{\n\tFSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override\n\t{\n\t\tFSTVolume* mountedVolume = (FSTVolume*)ctx;\n\t\tcemu_assert_debug(!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::WRITE_PERMISSION)); // writing to FST is never allowed\n\n\t\tif (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE))\n\t\t{\n\t\t\tFSTFileHandle fstFileHandle;\n\t\t\tif (mountedVolume->OpenFile(path, fstFileHandle, true) && !mountedVolume->HasLinkFlag(fstFileHandle))\n\t\t\t{\n\t\t\t\t*fscStatus = FSC_STATUS_OK;\n\t\t\t\treturn new FSCDeviceWudFileCtx(mountedVolume, fstFileHandle);\n\t\t\t}\n\t\t}\n\t\tif (HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))\n\t\t{\n\t\t\tFSTDirectoryIterator dirIterator;\n\t\t\tif (mountedVolume->OpenDirectoryIterator(path, dirIterator) && !mountedVolume->HasLinkFlag(dirIterator.GetDirHandle()))\n\t\t\t{\n\t\t\t\t*fscStatus = FSC_STATUS_OK;\n\t\t\t\treturn new FSCDeviceWudFileCtx(mountedVolume, dirIterator);\n\t\t\t}\n\t\t}\n\t\t*fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\treturn nullptr;\n\t}\n\n\t// singleton\npublic:\n\tstatic fscDeviceWUDC& instance()\n\t{\n\t\tstatic fscDeviceWUDC _instance;\n\t\treturn _instance;\n\t}\n};\n\nbool FSCDeviceWUD_Mount(std::string_view mountPath, std::string_view destinationBaseDir, FSTVolume* mountedVolume, sint32 priority)\n{\n\treturn fsc_mount(mountPath, destinationBaseDir, &fscDeviceWUDC::instance(), mountedVolume, priority) == FSC_STATUS_OK;\n}"
  },
  {
    "path": "src/Cafe/Filesystem/fscDeviceWuhb.cpp",
    "content": "#include \"Filesystem/WUHB/WUHBReader.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n#include \"Cafe/Filesystem/FST/FST.h\"\n\nclass FSCDeviceWuhbFileCtx : public FSCVirtualFile\n{\n  public:\n\tFSCDeviceWuhbFileCtx(WUHBReader* reader, uint32 entryOffset, uint32 fscType)\n\t\t: m_wuhbReader(reader), m_entryOffset(entryOffset), m_fscType(fscType)\n\t{\n\t\tcemu_assert(entryOffset != ROMFS_ENTRY_EMPTY);\n\t\tif (fscType == FSC_TYPE_DIRECTORY)\n\t\t{\n\t\t\tromfs_direntry_t entry = reader->GetDirEntry(entryOffset);\n\t\t\tm_dirIterOffset = entry.dirListHead;\n\t\t\tm_fileIterOffset = entry.fileListHead;\n\t\t}\n\t}\n\tsint32 fscGetType() override\n\t{\n\t\treturn m_fscType;\n\t}\n\tuint64 fscQueryValueU64(uint32 id) override\n\t{\n\t\tif (m_fscType == FSC_TYPE_FILE)\n\t\t{\n\t\t\tif (id == FSC_QUERY_SIZE)\n\t\t\t\treturn m_wuhbReader->GetFileSize(m_entryOffset);\n\t\t\telse if (id == FSC_QUERY_WRITEABLE)\n\t\t\t\treturn 0; // WUHB images are read-only\n\t\t\telse\n\t\t\t\tcemu_assert_error();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\treturn 0;\n\t}\n\tuint32 fscWriteData(void* buffer, uint32 size) override\n\t{\n\t\tcemu_assert_error();\n\t\treturn 0;\n\t}\n\tuint32 fscReadData(void* buffer, uint32 size) override\n\t{\n\t\tif (m_fscType != FSC_TYPE_FILE)\n\t\t\treturn 0;\n\t\tauto read = m_wuhbReader->ReadFromFile(m_entryOffset, m_seek, size, buffer);\n\t\tm_seek += read;\n\t\treturn read;\n\t}\n\tvoid fscSetSeek(uint64 seek) override\n\t{\n\t\tm_seek = seek;\n\t}\n\tuint64 fscGetSeek() override\n\t{\n\t\tif (m_fscType != FSC_TYPE_FILE)\n\t\t\treturn 0;\n\t\treturn m_seek;\n\t}\n\tvoid fscSetFileLength(uint64 endOffset) override\n\t{\n\t\tcemu_assert_error();\n\t}\n\tbool fscDirNext(FSCDirEntry* dirEntry) override\n\t{\n\t\tif (m_dirIterOffset != ROMFS_ENTRY_EMPTY)\n\t\t{\n\t\t\tromfs_direntry_t entry = m_wuhbReader->GetDirEntry(m_dirIterOffset);\n\t\t\tm_dirIterOffset = entry.listNext;\n\t\t\tif(entry.name_size > 0)\n\t\t\t{\n\t\t\t\tdirEntry->isDirectory = true;\n\t\t\t\tdirEntry->isFile = false;\n\t\t\t\tdirEntry->fileSize = 0;\n\t\t\t\tstd::strncpy(dirEntry->path, entry.name.c_str(), FSC_MAX_DIR_NAME_LENGTH);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tif (m_fileIterOffset != ROMFS_ENTRY_EMPTY)\n\t\t{\n\t\t\tromfs_fentry_t entry = m_wuhbReader->GetFileEntry(m_fileIterOffset);\n\t\t\tm_fileIterOffset = entry.listNext;\n\t\t\tif(entry.name_size > 0)\n\t\t\t{\n\t\t\t\tdirEntry->isDirectory = false;\n\t\t\t\tdirEntry->isFile = true;\n\t\t\t\tdirEntry->fileSize = entry.size;\n\t\t\t\tstd::strncpy(dirEntry->path, entry.name.c_str(), FSC_MAX_DIR_NAME_LENGTH);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n  private:\n\tWUHBReader* m_wuhbReader{};\n\tuint32 m_fscType;\n\tuint32 m_entryOffset = ROMFS_ENTRY_EMPTY;\n\tuint32 m_dirIterOffset = ROMFS_ENTRY_EMPTY;\n\tuint32 m_fileIterOffset = ROMFS_ENTRY_EMPTY;\n\tuint64 m_seek = 0;\n};\n\nclass fscDeviceWUHB : public fscDeviceC\n{\n\tFSCVirtualFile* fscDeviceOpenByPath(std::string_view path, FSC_ACCESS_FLAG accessFlags, void* ctx, sint32* fscStatus) override\n\t{\n\t\tWUHBReader* reader = (WUHBReader*)ctx;\n\t\tcemu_assert_debug(!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::WRITE_PERMISSION)); // writing to WUHB is not supported\n\n\t\tbool isFile;\n\t\tuint32 table_offset = ROMFS_ENTRY_EMPTY;\n\n\t\tif (table_offset == ROMFS_ENTRY_EMPTY && HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))\n\t\t{\n\t\t\ttable_offset = reader->Lookup(path, false);\n\t\t\tisFile = false;\n\t\t}\n\t\tif (table_offset == ROMFS_ENTRY_EMPTY && HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE))\n\t\t{\n\t\t\ttable_offset = reader->Lookup(path, true);\n\t\t\tisFile = true;\n\t\t}\n\n\t\tif (table_offset == ROMFS_ENTRY_EMPTY)\n\t\t{\n\t\t\t*fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\treturn nullptr;\n\t\t}\n\n\t\t*fscStatus = FSC_STATUS_OK;\n\t\treturn new FSCDeviceWuhbFileCtx(reader, table_offset, isFile ? FSC_TYPE_FILE : FSC_TYPE_DIRECTORY);\n\t}\n\n\t// singleton\n  public:\n\tstatic fscDeviceWUHB& instance()\n\t{\n\t\tstatic fscDeviceWUHB _instance;\n\t\treturn _instance;\n\t}\n};\n\nbool FSCDeviceWUHB_Mount(std::string_view mountPath, std::string_view destinationBaseDir, WUHBReader* wuhbReader, sint32 priority)\n{\n\treturn fsc_mount(mountPath, destinationBaseDir, &fscDeviceWUHB::instance(), wuhbReader, priority) == FSC_STATUS_OK;\n}\n"
  },
  {
    "path": "src/Cafe/GamePatch.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"CafeSystem.h\"\n#include \"config/ActiveSettings.h\" // Selectively add some patches based on network settings.\n\nvoid hleExport_breathOfTheWild_busyLoop(PPCInterpreter_t* hCPU)\n{\n\tuint32 queue7C = memory_readU32(hCPU->gpr[24] + 0x7C);\n\tuint32 queue80b = memory_readU8(hCPU->gpr[24] + 0x80);\n\n\tif (!(queue80b == 0 || hCPU->gpr[22] != 0 || queue7C > 0))\n\t{\n\t\tPPCInterpreter_relinquishTimeslice();\n\t}\n\n\thCPU->gpr[6] = hCPU->gpr[29];\n\thCPU->instructionPointer += 4;\n}\n\nvoid hleExport_breathOfTheWild_busyLoop2(PPCInterpreter_t* hCPU)\n{\n\tuint32 queue7C = memory_readU32(hCPU->gpr[24] + 0x7C);\n\tuint32 queue80b = memory_readU8(hCPU->gpr[24] + 0x80);\n\n\tif (!(queue80b == 0 || hCPU->gpr[22] != 0 || queue7C > 0))\n\t{\n\t\tPPCInterpreter_relinquishTimeslice();\n\t}\n\n\thCPU->gpr[12] = hCPU->gpr[29];\n\thCPU->instructionPointer += 4;\n}\n\nvoid hleExport_ffl_swapEndianFloatArray(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(valueArray, uint32, 0);\n\tppcDefineParamS32(valueCount, 1);\n\tfor (sint32 i = 0; i < valueCount; i++)\n\t{\n\t\tvalueArray[i] = _swapEndianU32(valueArray[i]);\n\t}\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\ntypedef struct  \n{\n\tstd::atomic<uint32be> count;\n\tuint32be ownerThreadId;\n\tuint32 ukn08;\n}xcxCS_t;\n\nvoid hleExport_xcx_enterCriticalSection(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(xcxCS, xcxCS_t, 0);\n\tuint32 threadId = MEMPTR<OSThread_t>(coreinit::OSGetCurrentThread()).GetMPTR();\n\tcemu_assert_debug(xcxCS->ukn08 != 0);\n\tcemu_assert_debug(threadId);\n\tif (xcxCS->ownerThreadId == (uint32be)threadId)\n\t{\n\t\txcxCS->count.store(xcxCS->count.load() + 1);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\n\t// quick check\n\tuint32be newCount = xcxCS->count.load() + 1;\n\tuint32be expectedCount = 0;\n\tif(xcxCS->count.compare_exchange_strong(expectedCount, newCount))\n\t{\n\t\txcxCS->ownerThreadId = threadId;\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\n\t// spinloop for a bit to reduce the time we occupy the scheduler lock (via PPCCore_switchToScheduler)\n\twhile (true)\n\t{\n\t\tfor (sint32 i = 0; i < 50; i++)\n\t\t{\n\t\t\tif (xcxCS->count.compare_exchange_strong(expectedCount, newCount))\n\t\t\t{\n\t\t\t\txcxCS->ownerThreadId = threadId;\n\t\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\t\treturn;\n\t\t\t}\n            _mm_pause();\n\t\t}\n\t\tPPCCore_switchToScheduler();\n\t}\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nbool mh3u_raceConditionWorkaround = true;\n\nvoid hleExport_mh3u_raceConditionWorkaround(PPCInterpreter_t* hCPU) // new style HLE method, does not need entry in hle_load (but can only be reached via BL and not the usual HLE instruction)\n{\n\tuint8 b = memory_readU8(hCPU->gpr[3] + 0x3E5);\n\tb ^= 1;\n\tif (mh3u_raceConditionWorkaround)\n\t{\n\t\tb = 0;\n\t\tmh3u_raceConditionWorkaround = false;\n\t}\n\tosLib_returnFromFunction(hCPU, b);\n}\n\nvoid hleExport_pmcs_yellowPaintStarCrashWorkaround(PPCInterpreter_t* hCPU)\n{\n\thCPU->gpr[7] = hCPU->gpr[3] * 4;\n\tMPTR parentLR = memory_readU32(hCPU->gpr[1] + 0x4C);\n\tif (hCPU->gpr[3] >= 0x00800000)\n\t{\n\t\thCPU->instructionPointer = parentLR;\n\t\thCPU->gpr[1] += 0x48;\n\t\thCPU->gpr[3] = 0;\n\t\treturn;\n\t}\n\thCPU->instructionPointer = hCPU->spr.LR;\n}\n\nuint8 hleSignature_wwhd_0173B2A0[] = {0x8D,0x43,0x00,0x01,0x7C,0xC9,0x52,0x78,0x55,0x2C,0x15,0xBA,0x7C,0x0C,0x28,0x2E,0x54,0xC8,0xC2,0x3E,0x7D,0x06,0x02,0x78,0x42,0x00,0xFF,0xE8,0x7C,0xC3,0x30,0xF8};\n\nvoid hle_scan(uint8* data, sint32 dataLength, char* hleFunctionName)\n{\n\tsint32 functionIndex = osLib_getFunctionIndex(\"hle\", hleFunctionName);\n\tif( functionIndex < 0 )\n\t{\n\t\tdebug_printf(\"HLE function unknown\\n\");\n\t\treturn;\n\t}\n\n\tuint8* scanStart = memory_getPointerFromVirtualOffset(0x01000000);\n\tuint8* scanEnd = scanStart + 0x0F000000 - dataLength;\n\tuint8* scanCurrent = scanStart;\n\twhile( scanCurrent < scanEnd )\n\t{\n\t\tif( memcmp(scanCurrent, data, dataLength) == 0 )\n\t\t{\n\t\t\tuint32 offset = (uint32)(scanCurrent - scanStart) + 0x01000000;\n\t\t\tdebug_printf(\"HLE signature for '%s' found at 0x%08x\\n\", hleFunctionName, offset);\n\t\t\tuint32 opcode = (1<<26)|(functionIndex+0x1000); // opcode for HLE: 0x1000 + FunctionIndex\n\t\t\tmemory_write<uint32>(offset, opcode);\n\t\t\tbreak;\n\t\t}\n\t\tscanCurrent += 4;\n\t}\n}\n\nMPTR hle_locate(uint8* data, sint32 dataLength)\n{\n\tuint8* scanStart = memory_getPointerFromVirtualOffset(0x01000000);\n\tuint8* scanEnd = scanStart + 0x0F000000 - dataLength;\n\tuint8* scanCurrent = scanStart;\n\twhile( scanCurrent < scanEnd )\n\t{\n\t\tif( memcmp(scanCurrent, data, dataLength) == 0 )\n\t\t{\n\t\t\treturn memory_getVirtualOffsetFromPointer(scanCurrent);\n\t\t}\n\t\tscanCurrent += 4;\n\t}\n\treturn MPTR_NULL;\n}\n\nbool compareMasked(uint8* mem, uint8* compare, uint8* mask, sint32 length)\n{\n\twhile( length )\n\t{\n\t\tuint8 m = *mask;\n\t\tif( (*mem&m) != (*compare&m) )\n\t\t\treturn false;\n\t\tmem++;\n\t\tcompare++;\n\t\tmask++;\n\t\tlength--;\n\t}\n\treturn true;\n}\n\nMPTR hle_locate(uint8* data, uint8* mask, sint32 dataLength)\n{\n\tuint8* scanStart = memory_getPointerFromVirtualOffset(MEMORY_CODEAREA_ADDR);\n\tuint8* scanEnd = memory_getPointerFromVirtualOffset(RPLLoader_GetMaxCodeOffset() - dataLength);\n\tuint8* scanCurrent = scanStart;\n\tif( mask )\n\t{\n\t\tif (dataLength >= 4 && *(uint32*)mask == 0xFFFFFFFF)\n\t\t{\n\t\t\t// fast path\n\t\t\tuint32 firstDword = *(uint32*)data;\n\t\t\twhile (scanCurrent < scanEnd)\n\t\t\t{\n\t\t\t\tif (*(uint32*)scanCurrent == firstDword && compareMasked(scanCurrent, data, mask, dataLength))\n\t\t\t\t{\n\t\t\t\t\treturn memory_getVirtualOffsetFromPointer(scanCurrent);\n\t\t\t\t}\n\t\t\t\tscanCurrent += 4;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tif (mask[0] != 0xFF)\n\t\t\t\tassert_dbg();\n#endif\n\t\t\tuint8 firstByte = data[0];\n\t\t\twhile (scanCurrent < scanEnd)\n\t\t\t{\n\t\t\t\tif (scanCurrent[0] == firstByte && compareMasked(scanCurrent, data, mask, dataLength))\n\t\t\t\t{\n\t\t\t\t\treturn memory_getVirtualOffsetFromPointer(scanCurrent);\n\t\t\t\t}\n\t\t\t\tscanCurrent += 4;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\twhile( scanCurrent < scanEnd )\n\t\t{\n\t\t\tif( memcmp(scanCurrent, data, dataLength) == 0 )\n\t\t\t{\n\t\t\t\treturn memory_getVirtualOffsetFromPointer(scanCurrent);\n\t\t\t}\n\t\t\tscanCurrent += 4;\n\t\t}\n\t}\n\treturn MPTR_NULL;\n}\n\nuint8 xcx_gpuHangDetection_degradeFramebuffer[] = {0x3B,0x39,0x00,0x01,0x28,0x19,0x4E,0x20,0x40,0x81,0x00,0x44};\n\nuint8 xcx_framebufferReductionSignature[] = {0x80,0xC9,0x00,0x1C,0x38,0xA0,0x00,0x01,0x80,0x7E,0x00,0x80,0x80,0x9E,0x02,0xEC,0x80,0xE9,0x00,0x20,0x48,0x06,0x1E,0xD1,0x7E,0x73,0x1B,0x78};\nuint8 xcx_framebufferReductionMask[] =      {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF};\n\nuint8 botw_busyLoopSignature[] = {0x80,0xE6,0x00,0x00,0x2C,0x07,0x00,0x01,0x41,0x82,0xFF,0xF8,0x7D,0x00,0x30,0x28,0x2C,0x08,0x00,0x00,0x40,0x82,0xFF,0xF8,0x7C,0x00,0x30,0x6C,0x39,0x00,0x00,0x01,0x7D,0x00,0x31,0x2D,0x40,0x82,0xFF,0xE8 };\nuint8 botw_busyLoopMask[] =      {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };\n\nuint8 botw_busyLoopSignature2[] = {0x80,0x0C,0x00,0x00,0x2C,0x00,0x00,0x01,0x41,0x82,0xFF,0xF8,0x7C,0xA0,0x60,0x28,0x2C,0x05,0x00,0x00,0x40,0x82,0xFF,0xF8,0x7C,0x00,0x60,0x6C,0x38,0x80,0x00,0x01,0x7C,0x80,0x61,0x2D,0x40,0x82,0xFF,0xE8};\nuint8 botw_busyLoopMask2[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};\n\nuint8 botw_crashFuncSignature[] = { 0x94,0x21,0xFF,0xD8,0x7C,0x08,0x02,0xA6,0xBF,0x41,0x00,0x10,0x7C,0xC7,0x33,0x78,0x7C,0xBE,0x2B,0x78,0x90,0x01,0x00,0x2C,0x7C,0x9D,0x23,0x78,0x38,0x00,0x00,0x00,0x7F,0xC6,0xF3,0x78,0x38,0x81,0x00,0x0C,0x90,0x01,0x00,0x0C,0x38,0xA1,0x00,0x08 };\nuint8 botw_crashFuncMask[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };\n\nuint8 ffl_floatArrayEndianSwap[] = { 0x7C,0x08,0x02,0xA6,0x94,0x21,0xFF,0xE8,0x93,0xC1,0x00,0x10,0x7C,0x7E,0x1B,0x78,0x93,0xE1,0x00,0x14,0x93,0x81,0x00,0x08,0x7C,0x9F,0x23,0x78,0x93,0xA1,0x00,0x0C,0x90,0x01,0x00,0x1C,0x3B,0xA0,0x00,0x00,0x7C,0x1D,0xF8,0x40,0x40,0x80,0x00,0x20,0x57,0xBC,0x10,0x3A,0x7C,0x3E,0xE4,0x2E };\n\nuint8 xcx_enterCriticalSectionSignature[] = { 0x94,0x21,0xFF,0xE0,0xBF,0x41,0x00,0x08,0x7C,0x08,0x02,0xA6,0x90,0x01,0x00,0x24,0x7C,0x7E,0x1B,0x78,0x80,0x1E,0x00,0x08,0x2C,0x00,0x00,0x00,0x41,0x82,0x00,0xC0,0x48,0x01,0xD7,0xA1,0x7C,0x7A,0x1B,0x79,0x41,0x82,0x00,0xB4,0x81,0x3E,0x00,0x04,0x7C,0x09,0xD0,0x40,0x40,0x82,0x00,0x2C,0x7D,0x20,0xF0,0x28,0x7C,0x00,0xF0,0x6C };\nuint8 xcx_enterCriticalSectionMask[] =      { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };\n\nuint8 smash4_softlockFixV0Signature[] = { 0x2C,0x03,0x00,0x00,0x41,0x82,0x00,0x20,0x38,0x60,0x00,0x0A,0x48,0x33,0xB8,0xAD,0x7F,0xA3,0xEB,0x78,0x7F,0xC4,0xF3,0x78,0x4B,0xFF,0xFF,0x09,0x2C,0x03,0x00,0x00 };\nuint8 smash4_softlockFixV0Mask[] =      { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF };\n\nuint8 mh3u_raceConditionWorkaroundV0Signature[] = { 0x38,0x21,0x00,0x40,0x38,0x60,0x00,0x00,0x4E,0x80,0x00,0x20,0x80,0x7B,0xDB,0x9C,0x48,0x11,0x6B,0x81,0x2C,0x03,0x00,0x00 };\nuint8 mh3u_raceConditionWorkaroundV0Mask[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF };\n\nuint8 pmcs_yellowPaintStarCrashV0Signature[] = { 0x94,0x21,0xFF,0xB8,0xBE,0x61,0x00,0x14,0x7C,0x08,0x02,0xA6,0x7C,0xB3,0x2B,0x78,0x90,0x01,0x00,0x4C,0x7C,0x9D,0x23,0x78,0x83,0x3D,0x00,0x0C,0x81,0x39,0x04,0xA8,0x54,0x67,0x10,0x3A,0x7F,0xC7,0x48,0x2E,0x83,0x1E,0x00,0xDC,0x82,0xF8,0x00,0x08,0x2C,0x17,0x00,0x00 };\n//uint8 mh3u_raceConditionWorkaroundV0Mask[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF };\n\nuint8 bayo2_audioQueueFixSignature[] = { 0x80,0x03,0x00,0x3C,0x81,0x43,0x00,0x5C,0x81,0x83,0x00,0x40,0x55,0x48,0xB2,0xBE,0x3D,0x40,0x10,0x1D,0x7D,0x6C,0x42,0x14,0x39,0x4A,0x46,0xF0,0x7D,0x8B,0x00,0x50 };\nuint8 bayo2_audioQueueFixMask[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xFF,0xFF };\n\nuint8 sm3dw_dynFrameBufferResScale[] = { 0x94,0x21,0xFF,0xB8,0xBF,0x21,0x00,0x2C,0x7C,0x08,0x02,0xA6,0x90,0x01,0x00,0x4C,0x7C,0x7E,0x1B,0x78,0x81,0x7E,0x07,0xD8,0x38,0x80,0x00,0x02,0x38,0x6B,0x00,0x03 };\n\nuint8 tww_waitFunc[] = { 0x7C,0x08,0x02,0xA6,0x94,0x21,0xFF,0xF0,0x93,0xE1,0x00,0x0C,0x7C,0x7F,0x1B,0x78,0x90,0x01,0x00,0x14,0x80,0x7F,0x02,0xE0,0x81,0x83,0x00,0x0C,0x80,0x0C,0x00,0x1C,0x7C,0x09,0x03,0xA6,0x38,0xA0,0x00,0x00,0x38,0x9F,0x03,0x68 };\n\nstatic_assert(sizeof(xcx_enterCriticalSectionSignature) == sizeof(xcx_enterCriticalSectionMask), \"xcx_enterCriticalSection signature and size mismatch\");\nstatic_assert(sizeof(bayo2_audioQueueFixSignature) == sizeof(bayo2_audioQueueFixMask), \"bayo2_audioQueueFix signature and size mismatch\");\n\nuint8 cars3_avro_schema_incref[] = { 0x2C,0x03,0x00,0x00,0x94,0x21,0xFF,0xE8,0x41,0x82,0x00,0x40,0x39,0x03,0x00,0x08,0x39,0x41,0x00,0x08,0x91,0x01,0x00,0x08,0x7D,0x80,0x50,0x28,0x2C,0x0C,0xFF,0xFF,0x41,0x82,0x00,0x28,0x39,0x21,0x00,0x0C,0x38,0x0C,0x00,0x01,0x38,0xE0,0x00,0x01,0x91,0x01,0x00,0x0C,0x7C,0x00,0x49,0x2D };\n\n// For USA titles: 000500301001610a / 000500301001410a\nuint8 miiverse_eshop_url_match_whitelist_func[] = {\n\t// For both titles, the code fully matches with the relative\n\t// branch targets, even if the absolute targets are different.\n\t0x89,0x45,0x00,0x00, // lbz r10, 0x0(r5)\n\t0x2c,0x0a,0x00,0x2e, // cmpwi r10, 0x2e\n\t0x40,0x82,0x00,0x08, // bne LAB_020ff3a8\n\t0x4b,0xff,0xff,0x5c // b FUN_020ff300\n};\nuint8 wave_libopenssl_ssl_verify_cert_chain[] = { 0x94,0x21,0xff,0x58,0x93,0xc1,0x00,0xa0,0x93,0xe1,0x00,0xa4,0x7c,0x9f,0x23,0x79,0x7c,0x7e,0x1b,0x78,0x90,0x01,0x00,0xac,0x41,0x82,0x00,0x14,0x7f,0xe3,0xfb,0x78 }; // rpl function for the above applets\n\nsint32 hleIndex_h000000001 = -1;\nsint32 hleIndex_h000000002 = -1;\nsint32 hleIndex_h000000003 = -1;\nsint32 hleIndex_h000000004 = -1;\n\n/*\n * Returns true for all HLE functions that do not jump to LR\n * Used by recompiler to determine function code flow\n */\nbool GamePatch_IsNonReturnFunction(uint32 hleIndex)\n{\n\tif (hleIndex == hleIndex_h000000001)\n\t\treturn true;\n\tif (hleIndex == hleIndex_h000000002)\n\t\treturn true;\n\tif (hleIndex == hleIndex_h000000003)\n\t\treturn false;\n\tif (hleIndex == hleIndex_h000000004)\n\t\treturn false;\n\treturn false;\n}\n\nvoid GamePatch_scan()\n{\n\tMPTR hleAddr;\n\tuint32 hleInstallStart = GetTickCount();\n\n\thleAddr = hle_locate(xcx_gpuHangDetection_degradeFramebuffer, NULL, sizeof(xcx_gpuHangDetection_degradeFramebuffer));\n\tif( hleAddr )\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tcemuLog_log(LogType::Force, \"HLE: XCX GPU hang detection\");\n#endif\n\t\t// remove the ADDI r25, r25, 1 instruction\n\t\tmemory_writeU32(hleAddr, memory_readU32(hleAddr+4));\n\t}\n\n\thleAddr = hle_locate(xcx_framebufferReductionSignature, xcx_framebufferReductionMask, sizeof(xcx_framebufferReductionSignature));\n\tif( hleAddr )\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tcemuLog_log(LogType::Force, \"HLE: Prevent XCX rendertarget reduction\");\n#endif\n\t\tuint32 bl = memory_readU32(hleAddr+0x14);\n\t\tuint32 func_isReductionBuffer = hleAddr + 0x14 + (bl&0x3FFFFFC);\n\n\t\t// patch isReductionBuffer\n\t\tmemory_writeU32(func_isReductionBuffer, 0x38600000); // LI R3, 0\n\t\tmemory_writeU32(func_isReductionBuffer+4, 0x4E800020); // BLR\n\n\t}\n\n\thleIndex_h000000001 = osLib_getFunctionIndex(\"hle\", \"h000000001\");\n\thleAddr = hle_locate(botw_busyLoopSignature, botw_busyLoopMask, sizeof(botw_busyLoopSignature));\n\tif (hleAddr)\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tcemuLog_log(LogType::Force, \"HLE: Patch BotW busy loop 1 at 0x{:08x}\", hleAddr);\n#endif\n\t\tsint32 functionIndex = hleIndex_h000000001;\n\t\tuint32 opcode = (1 << 26) | (functionIndex); // opcode for HLE: 0x1000 + FunctionIndex\n\t\tmemory_write<uint32>(hleAddr - 4, opcode);\n\t}\n\thleIndex_h000000002 = osLib_getFunctionIndex(\"hle\", \"h000000002\");\n\thleAddr = hle_locate(botw_busyLoopSignature2, botw_busyLoopMask2, sizeof(botw_busyLoopSignature2));\n\tif (hleAddr)\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tcemuLog_log(LogType::Force, \"HLE: Patch BotW busy loop 2 at 0x{:08x}\", hleAddr);\n#endif\n\t\tsint32 functionIndex = hleIndex_h000000002;\n\t\tuint32 opcode = (1 << 26) | (functionIndex); // opcode for HLE: 0x1000 + FunctionIndex\n\t\tmemory_write<uint32>(hleAddr - 4, opcode);\n\t}\n\n\t// FFL library float array endian conversion\n\t// original function needs invalid float values to remain intact between LFSX -> STFSX, which is not supported in recompiler mode\n\thleIndex_h000000003 = osLib_getFunctionIndex(\"hle\", \"h000000003\");\n\thleAddr = hle_locate(ffl_floatArrayEndianSwap, NULL, sizeof(ffl_floatArrayEndianSwap));\n\tif (hleAddr)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"HLE: Hook FFL float array endian swap function at 0x{:08x}\", hleAddr);\n\t\tsint32 functionIndex = hleIndex_h000000003;\n\t\tuint32 opcode = (1 << 26) | (functionIndex); // opcode for HLE: 0x1000 + FunctionIndex\n\t\tmemory_write<uint32>(hleAddr, opcode);\n\t}\n\n\t// XCX freeze workaround\n\t//hleAddr = hle_locate(xcx_enterCriticalSectionSignature, xcx_enterCriticalSectionMask, sizeof(xcx_enterCriticalSectionSignature));\n\t//if (hleAddr)\n\t//{\n\t//\tcemuLog_logDebug(LogType::Force, \"HLE: Hook XCX enterCriticalSection function at 0x{:08x}\", hleAddr);\n\t//\thleIndex_h000000004 = osLib_getFunctionIndex(\"hle\", \"h000000004\");\n\t//\tsint32 functionIndex = hleIndex_h000000004;\n\t//\tuint32 opcode = (1 << 26) | (functionIndex); // opcode for HLE: 0x1000 + FunctionIndex\n\t//\tmemory_writeU32Direct(hleAddr, opcode);\n\t//}\n\n\t// MH3U race condition (tested for EU+US 1.2)\n\thleAddr = hle_locate(mh3u_raceConditionWorkaroundV0Signature, mh3u_raceConditionWorkaroundV0Mask, sizeof(mh3u_raceConditionWorkaroundV0Mask));\n\tif (hleAddr)\n\t{\n\t\tuint32 patchAddr = hleAddr + 0x10;\n\t\tcemuLog_log(LogType::Force, \"HLE: Patch MH3U race condition candidate at 0x{:08x}\", patchAddr);\n\t\tuint32 funcAddr = PPCInterpreter_makeCallableExportDepr(hleExport_mh3u_raceConditionWorkaround);\n\t\t// set absolute jump\n\t\tuint32 opc = 0x48000000;\n\t\topc |= PPC_OPC_LK;\n\t\topc |= PPC_OPC_AA;\n\t\topc |= funcAddr;\n\t\tmemory_writeU32(patchAddr, opc);\n\t}\n\n\t// Super Smash Bros softlock fix\n\t// fixes random softlocks that can occur after matches\n\thleAddr = hle_locate(smash4_softlockFixV0Signature, smash4_softlockFixV0Mask, sizeof(smash4_softlockFixV0Signature));\n\tif (hleAddr)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Smash softlock fix: 0x{:08x}\", hleAddr);\n\t\tmemory_writeU32(hleAddr+0x20, memory_readU32(hleAddr+0x1C));\n\t}\n\n\t// Color Splash Yellow paint star crash workaround\n\t// fixes the crash at the beginning of the dream sequence cutscene after collecting the yellow paint star\n\thleAddr = hle_locate(pmcs_yellowPaintStarCrashV0Signature, nullptr, sizeof(pmcs_yellowPaintStarCrashV0Signature));\n\tif (hleAddr)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Color Splash crash fix: 0x{:08x}\", hleAddr);\n\t\tuint32 funcAddr = PPCInterpreter_makeCallableExportDepr(hleExport_pmcs_yellowPaintStarCrashWorkaround);\n\t\t// set absolute jump\n\t\tuint32 opc = 0x48000000;\n\t\topc |= PPC_OPC_LK;\n\t\topc |= PPC_OPC_AA;\n\t\topc |= funcAddr;\n\t\tmemory_writeU32(hleAddr+0x20, opc);\n\t}\n\n\t// Bayonetta 2 sound queue patch (fixes audio starting to loop infinitely when there is stutter)\n\thleAddr = hle_locate(bayo2_audioQueueFixSignature, bayo2_audioQueueFixMask, sizeof(bayo2_audioQueueFixSignature));\n\tif (hleAddr)\n\t{\n\t\t// replace CMPL with CMP\n\t\tcemuLog_log(LogType::Force, \"Patching Bayonetta 2 audio bug at: 0x{:08x}\", hleAddr+0x34);\n\t\tuint32 opc = memory_readU32(hleAddr + 0x34);\n\t\topc &= ~(0x3FF << 1); // turn CMPL to CMP\n\t\tmemory_writeU32(hleAddr + 0x34, opc);\n\t}\n\n\tif (CafeSystem::GetRPXHashUpdated() == 0xb1c033dd) // Wind Waker US\n\t{\n\t\tuint32 p = memory_readU32(0x02813878);\n\t\tif (p == 0x40800018)\n\t\t{\n\t\t\tdebug_printf(\"HLE: TWW US dsp kill channel patch\\n\");\n\t\t\tuint32 li = 0x18;\n\t\t\tuint32 opcode = (li & 0x3FFFFFC) | (18 << 26); // replace BGE with B instruction\n\t\t\tmemory_writeU32(0x02813878, opcode);\n\t\t}\n\t}\n\telse if (CafeSystem::GetRPXHashUpdated() == 0xCDC68ACD) // Wind Waker EU\n\t{\n\t\tuint32 p = memory_readU32(0x2814138);\n\t\tif (p == 0x40800018)\n\t\t{\n\t\t\tdebug_printf(\"HLE: TWW EU dsp kill channel patch\\n\");\n\t\t\tuint32 li = 0x18;\n\t\t\tuint32 opcode = (li & 0x3FFFFFC) | (18 << 26); // replace BGE with B instruction\n\t\t\tmemory_writeU32(0x02814138, opcode);\n\t\t}\n\t}\n\n\t// disable SM3DW dynamic resolution scaling (fixes level 1-5 spamming lots of texture creates when gradually resizing framebuffer)\n\thleAddr = hle_locate(sm3dw_dynFrameBufferResScale, nullptr, sizeof(sm3dw_dynFrameBufferResScale));\n\tif (hleAddr)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Patching SM3DW dynamic resolution scaling at: 0x{:08x}\", hleAddr);\n\t\tmemory_writeU32(hleAddr, 0x4E800020); // BLR\n\t}\n\n\t// remove unnecessary lock from a wait function in TWW\n\t// this resolves a deadlock in singlecore mode\n\thleAddr = hle_locate(tww_waitFunc, nullptr, sizeof(tww_waitFunc));\n\tif (hleAddr)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Patching TWW race conditon at: 0x{:08x}\", hleAddr);\n\t\t// NOP calls to Lock/Unlock mutex\n\t\tmemory_writeU32(hleAddr + 0x34, 0x60000000);\n\t\tmemory_writeU32(hleAddr + 0x48, 0x60000000);\n\t\tmemory_writeU32(hleAddr + 0x50, 0x60000000);\n\t\tmemory_writeU32(hleAddr + 0x64, 0x60000000);\n\t}\n\n\t// Patch function in Miiverse/eShop wave.rpx that matches\n\t// a domain against another to validate its whitelist.\n\t// This allows those browsers to load any domain.\n\tconst NetworkService service = ActiveSettings::GetNetworkService();\n\tif (service != NetworkService::Nintendo // Only patch for custom services.\n\t\t&& CafeSystem::GetForegroundTitleArgStr().ends_with(\"wave.rpx\")\n\t\t&& (hleAddr = hle_locate(miiverse_eshop_url_match_whitelist_func,\n\t\t\tnullptr, sizeof(miiverse_eshop_url_match_whitelist_func))))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Patching Miiverse/eShop whitelist check at: 0x{:08x}\", hleAddr);\n\t\t// Always return 1. (Note that the matched pattern is not at the beginning but still works)\n\t\tmemory_writeU32(hleAddr, 0x38600001);\n\t\tmemory_writeU32(hleAddr + 0x4, 0x4e800020);\n\t\t// Note that the same applies to Account Settings, but\n\t\t// its version of this function differs a lot.\n\t\t// Search: 88 0c ff ff 2c 00 00 2e (lbz r0,-0x1(r12); cmpwi r0,0x2e)\n\t}\n\n\t// Additionally patch out SSL checks for libopenssl.rpl, used by the browser.\n\tif (IsNetworkServiceSSLDisabled(service)\n\t\t&& RPLLoader_GetHandleByModuleName(\"libopenssl.rpl\") != RPL_INVALID_HANDLE\n\t\t&& (hleAddr = hle_locate(wave_libopenssl_ssl_verify_cert_chain,\n\t\t\tnullptr, sizeof(wave_libopenssl_ssl_verify_cert_chain))))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Patching OpenSSL ssl_verify_cert_chain at: 0x{:08x}\", hleAddr);\n\t\t// Reference: https://github.com/PretendoNetwork/Meowth/blob/meowth/src/patcher/patches/webkit_applets.cpp\n\t\tmemory_writeU32(hleAddr + 0x28, 0x60000000);\n\t\tmemory_writeU32(hleAddr + 0x40, 0x38600001);\n\t}\n\n\tuint32 hleInstallEnd = GetTickCount();\n\tcemuLog_log(LogType::Force, \"HLE scan time: {}ms\", hleInstallEnd-hleInstallStart);\n}\n\nRunAtCemuBoot _loadGamePatchAPI([]()\n\t{\n\t\tosLib_addFunction(\"hle\", \"h000000001\", hleExport_breathOfTheWild_busyLoop);\n\t\tosLib_addFunction(\"hle\", \"h000000002\", hleExport_breathOfTheWild_busyLoop2);\n\t\tosLib_addFunction(\"hle\", \"h000000003\", hleExport_ffl_swapEndianFloatArray);\n\t\tosLib_addFunction(\"hle\", \"h000000004\", hleExport_xcx_enterCriticalSection);\n\t});\n"
  },
  {
    "path": "src/Cafe/GamePatch.h",
    "content": "void GamePatch_scan();\nbool GamePatch_IsNonReturnFunction(uint32 hleIndex);"
  },
  {
    "path": "src/Cafe/GameProfile/GameProfile.cpp",
    "content": "#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"util/helpers/helpers.h\"\n\n#include \"boost/nowide/convert.hpp\"\n\n#include \"config/ActiveSettings.h\"\n#include \"Common/FileStream.h\"\n#include \"util/IniParser/IniParser.h\"\n#include \"util/helpers/StringHelpers.h\"\n#include \"Cafe/CafeSystem.h\"\n\nstd::unique_ptr<GameProfile> g_current_game_profile = std::make_unique<GameProfile>();\n\nstruct gameProfileBooleanOption_t\n{\n\tbool isPresent = false;\n\tbool value;\n};\n\n/*\n* Attempts to load a boolean option\n* If the option exists, true is returned.\n* The boolean is stored in *optionValue\n*/\nbool gameProfile_loadBooleanOption(IniParser* iniParser, char* optionName, gameProfileBooleanOption_t* option)\n{\n\tauto option_value = iniParser->FindOption(optionName);\n\toption->isPresent = false;\n\toption->value = false;\n\tif (!option_value)\n\t\treturn false;\n\t// parse option\n\tif (boost::iequals(*option_value, \"false\") || boost::iequals(*option_value, \"0\"))\n\t{\n\t\toption->isPresent = true;\n\t\toption->value = false;\n\t\treturn true;\n\t}\n\telse if (boost::iequals(*option_value, \"true\") || boost::iequals(*option_value, \"1\"))\n\t{\n\t\toption->isPresent = true;\n\t\toption->value = true;\n\t\treturn true;\n\t}\n\telse\n\t\tcemuLog_log(LogType::Force, \"Unknown value '{}' for option '{}' in game profile\", *option_value, optionName);\n\treturn false;\n}\n\n\nbool gameProfile_loadBooleanOption2(IniParser& iniParser, const char* optionName, bool& option)\n{\n\tauto option_value = iniParser.FindOption(optionName);\n\tif (!option_value)\n\t\treturn false;\n\tif (boost::iequals(*option_value, \"1\") || boost::iequals(*option_value, \"true\"))\n\t{\n\t\toption = true;\n\t\treturn true;\n\t}\n\telse if (boost::iequals(*option_value, \"0\") || boost::iequals(*option_value, \"false\"))\n\t{\n\t\toption = false;\n\t\treturn true;\n\t}\n\telse\n\t\tcemuLog_log(LogType::Force, \"Unknown value '{}' for option '{}' in game profile\", *option_value, optionName);\n\treturn false;\n}\n\nbool gameProfile_loadBooleanOption2(IniParser& iniParser, const char* optionName, std::optional<bool>& option)\n{\n\tbool tmp;\n\tconst auto result = gameProfile_loadBooleanOption2(iniParser, optionName, tmp);\n\tif(result)\n\t\toption = tmp;\n\treturn result;\n}\n\n/*\n* Attempts to load a integer option\n* Allows to specify min and max value (error is logged if out of range and default value is picked)\n*/\nbool gameProfile_loadIntegerOption(IniParser* iniParser, const char* optionName, gameProfileIntegerOption_t* option, sint32 defaultValue, sint32 minVal, sint32 maxVal)\n{\n\tauto option_value = iniParser->FindOption(optionName);\n\toption->isPresent = false;\n\tif (!option_value)\n\t{\n\t\toption->value = defaultValue;\n\t\treturn false;\n\t}\n\t// parse option\n\tsint32 val = StringHelpers::ToInt(*option_value, defaultValue);\n\tif (val < minVal || val > maxVal)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Value '{}' is out of range for option '{}' in game profile\", *option_value, optionName);\n\t\toption->value = defaultValue;\n\t\treturn false;\n\t}\n\toption->isPresent = true;\n\toption->value = val;\n\treturn true;\n}\n\ntemplate <typename T>\nbool gameProfile_loadIntegerOption(IniParser& iniParser, const char* optionName, T& option, T minVal, T maxVal)\n{\n\tstatic_assert(std::is_integral_v<T>);\n\tauto option_value = iniParser.FindOption(optionName);\n\tif (!option_value)\n\t\treturn false;\n\t// parse option\n\ttry\n\t{\n\t\tT val = ConvertString<T>(*option_value);\n\t\tif (val < minVal || val > maxVal)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Value '{}' is out of range for option '{}' in game profile\", *option_value, optionName);\n\t\t\treturn false;\n\t\t}\n\n\t\toption = val;\n\t\treturn true;\n\t}\n\tcatch(std::exception&)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Value '{}' is out of range for option '{}' in game profile\", *option_value, optionName);\n\t\treturn false;\n\t}\n}\n\ntemplate<typename T>\nbool gameProfile_loadEnumOption(IniParser& iniParser, const char* optionName, T& option)\n{\n\tstatic_assert(std::is_enum_v<T>);\n\tauto option_value = iniParser.FindOption(optionName);\n\tif (!option_value)\n\t\treturn false;\n\tfor(const T& v : T())\n\t{\n\t\t// test integer option\n\t\tif (boost::iequals(fmt::format(\"{}\", fmt::underlying(v)), *option_value))\n\t\t{\n\t\t\toption = v;\n\t\t\treturn true;\n\t\t}\n\n\t\t// test enum name\n\t\tif(boost::iequals(fmt::format(\"{}\", v), *option_value))\n\t\t{\n\t\t\toption = v;\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\ntemplate<typename T>\nbool gameProfile_loadEnumOption(IniParser& iniParser, const char* optionName, std::optional<T>& option)\n{\n\tT tmp;\n\tconst auto result = gameProfile_loadEnumOption(iniParser, optionName, tmp);\n\tif(result)\n\t\toption = tmp;\n\treturn result;\n}\n\nvoid gameProfile_load()\n{\n\tg_current_game_profile->ResetOptional(); // reset with global values as optional\n\tg_current_game_profile->Load(CafeSystem::GetForegroundTitleId());\n\n\t// apply some settings immediately\n\tppcThreadQuantum = g_current_game_profile->GetThreadQuantum();\n\n\tif (ppcThreadQuantum != GameProfile::kThreadQuantumDefault)\n\t\tcemuLog_log(LogType::Force, \"Thread quantum set to {}\", ppcThreadQuantum);\n}\n\nbool GameProfile::Load(uint64_t title_id)\n{\n\tauto gameProfilePath = ActiveSettings::GetConfigPath(\"gameProfiles/{:016x}.ini\", title_id);\n\n\tstd::optional<std::vector<uint8>> profileContents = FileStream::LoadIntoMemory(gameProfilePath);\n\tif (!profileContents)\n\t{\n\t\tgameProfilePath = ActiveSettings::GetDataPath(\"gameProfiles/default/{:016x}.ini\", title_id);\n\t\tprofileContents = FileStream::LoadIntoMemory(gameProfilePath);\n\t\tif (!profileContents)\n\t\t\treturn false;\n\t\tm_is_default = true;\n\t}\n\telse\n\t\tm_is_default = false;\n\n\tm_is_loaded = true;\n\t// most official gameprofiles start with \"# gamename\"\n\tstd::vector<char> game_name;\n\tif (profileContents->size() > 0 && profileContents->data()[0] == '#')\n\t{\n\t\tchar c;\n\t\tsize_t idx = 1;\n\t\twhile (idx < profileContents->size() && (c = profileContents->data()[idx]) != '\\n' && idx < 128)\n\t\t{\n\t\t\tgame_name.emplace_back(c);\n\t\t\tidx++;\n\t\t}\n\t\tm_gameName = std::string(game_name.begin(), game_name.end());\n\t\ttrim(m_gameName.value());\n\t}\n\tIniParser iniParser(*profileContents, _pathToUtf8(gameProfilePath));\n\t// parse ini\n\twhile (iniParser.NextSection())\n\t{\n\t\tif (boost::iequals(iniParser.GetCurrentSectionName(), \"General\"))\n\t\t{\n\t\t\tgameProfile_loadBooleanOption2(iniParser, \"loadSharedLibraries\", m_loadSharedLibraries);\n\t\t\tgameProfile_loadBooleanOption2(iniParser, \"startWithPadView\", m_startWithPadView);\n\t\t}\n\t\telse if (boost::iequals(iniParser.GetCurrentSectionName(), \"Graphics\"))\n\t\t{\n\t\t\tgameProfileIntegerOption_t graphicsApi;\n\t\t\tgameProfile_loadIntegerOption(&iniParser, \"graphics_api\", &graphicsApi, -1, 0, 1);\n\t\t\tif (graphicsApi.value != -1)\n\t\t\t\tm_graphics_api = (GraphicAPI)graphicsApi.value;\n\n\t\t\tgameProfile_loadEnumOption(iniParser, \"accurateShaderMul\", m_accurateShaderMul);\n#if ENABLE_METAL\n\t\t\tgameProfile_loadBooleanOption2(iniParser, \"shaderFastMath\", m_shaderFastMath);\n\t\t\tgameProfile_loadEnumOption(iniParser, \"metalBufferCacheMode2\", m_metalBufferCacheMode);\n\t\t\tgameProfile_loadEnumOption(iniParser, \"positionInvariance2\", m_positionInvariance);\n#endif\n\n\t\t\t// legacy support\n\t\t\tauto option_precompiledShaders = iniParser.FindOption(\"precompiledShaders\");\n\t\t\tif (option_precompiledShaders)\n\t\t\t{\n\t\t\t\tif (boost::iequals(*option_precompiledShaders, \"1\") || boost::iequals(*option_precompiledShaders, \"true\"))\n\t\t\t\t\tm_precompiledShaders = PrecompiledShaderOption::Enable;\n\t\t\t\telse if (boost::iequals(*option_precompiledShaders, \"0\") || boost::iequals(*option_precompiledShaders, \"false\"))\n\t\t\t\t\tm_precompiledShaders = PrecompiledShaderOption::Disable;\n\t\t\t\telse\n\t\t\t\t\tm_precompiledShaders = PrecompiledShaderOption::Auto;\n\t\t\t}\n\t\t\telse\n\t\t\t\tm_precompiledShaders = PrecompiledShaderOption::Auto;\n\t\t}\n\t\telse if (boost::iequals(iniParser.GetCurrentSectionName(), \"Audio\"))\n\t\t{\n\t\t\tgameProfile_loadBooleanOption2(iniParser, \"disableAudio\", m_disableAudio);\n\t\t}\n\t\telse if (boost::iequals(iniParser.GetCurrentSectionName(), \"CPU\"))\n\t\t{\n\t\t\tgameProfile_loadIntegerOption(iniParser, \"threadQuantum\", m_threadQuantum, 1000U, 536870912U);\n\t\t\tif (!gameProfile_loadEnumOption(iniParser, \"cpuMode\", m_cpuMode))\n\t\t\t{\n\t\t\t\t// try to load the old enum value strings\n\t\t\t\tstd::optional<CPUModeLegacy> cpu_mode_legacy;\n\t\t\t\tif (gameProfile_loadEnumOption(iniParser, \"cpuMode\", cpu_mode_legacy) && cpu_mode_legacy.has_value())\n\t\t\t\t{\n\t\t\t\t\tm_cpuMode = (CPUMode)cpu_mode_legacy.value();\n\t\t\t\t\tif (m_cpuMode == CPUMode::DualcoreRecompiler)\n\t\t\t\t\t\tm_cpuMode = CPUMode::MulticoreRecompiler;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (boost::iequals(iniParser.GetCurrentSectionName(), \"Controller\"))\n\t\t{\n\t\t\tfor (int i = 0; i < 8; ++i)\n\t\t\t{\n\t\t\t\tauto option_value = iniParser.FindOption(fmt::format(\"controller{}\", (i + 1)));\n\t\t\t\tif (option_value)\n\t\t\t\t\tm_controllerProfile[i] = std::string(*option_value);\n\t\t\t}\n\n\t\t}\n\t}\n\treturn true;\n}\n\nvoid GameProfile::Save(uint64_t title_id)\n{\n\tauto gameProfileDir = ActiveSettings::GetConfigPath(\"gameProfiles\");\n\tif (std::error_code ex_ec; !fs::exists(gameProfileDir, ex_ec))\n\t\tfs::create_directories(gameProfileDir, ex_ec);\n\tauto gameProfilePath = gameProfileDir / fmt::format(\"{:016x}.ini\", title_id);\n\tFileStream* fs = FileStream::createFile2(gameProfilePath);\n\tif (!fs)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to write game profile\");\n\t\treturn;\n\t}\n\n\tif (m_gameName)\n\t\tfs->writeLine(fmt::format(\"# {}\\n\", m_gameName.value()).c_str());\n\n#define WRITE_OPTIONAL_ENTRY(__NAME) if (m_##__NAME) fs->writeLine(fmt::format(\"{} = {}\", #__NAME, m_##__NAME.value()).c_str());\n#define WRITE_ENTRY(__NAME) fs->writeLine(fmt::format(\"{} = {}\", #__NAME, m_##__NAME).c_str());\n#define WRITE_ENTRY_NUMBERED(__NAME, __NUM) fs->writeLine(fmt::format(\"{} = {}\", #__NAME #__NUM, m_##__NAME).c_str());\n\n\tfs->writeLine(\"[General]\");\n\tWRITE_OPTIONAL_ENTRY(loadSharedLibraries);\n\tWRITE_ENTRY(startWithPadView);\n\tfs->writeLine(\"\");\n\n\tfs->writeLine(\"[CPU]\");\n\tWRITE_OPTIONAL_ENTRY(cpuMode);\n\tWRITE_ENTRY(threadQuantum);\n\tfs->writeLine(\"\");\n\n\tfs->writeLine(\"[Graphics]\");\n\tWRITE_ENTRY(accurateShaderMul);\n#if ENABLE_METAL\n\tWRITE_ENTRY(shaderFastMath);\n\tWRITE_ENTRY_NUMBERED(metalBufferCacheMode, 2);\n\tWRITE_ENTRY_NUMBERED(positionInvariance, 2);\n#endif\n\tWRITE_OPTIONAL_ENTRY(precompiledShaders);\n\tWRITE_OPTIONAL_ENTRY(graphics_api);\n\tfs->writeLine(\"\");\n\n\tfs->writeLine(\"[Controller]\");\n\tfor (int i = 0; i < 8; ++i)\n\t{\n\t\tif (m_controllerProfile[i])\n\t\t\tfs->writeLine(fmt::format(\"controller{} = {}\", (i + 1), m_controllerProfile[i].value()).c_str());\n\t}\n\n\tfs->writeLine(\"\");\n\n#undef WRITE_OPTIONAL_ENTRY\n#undef WRITE_ENTRY\n#undef WRITE_ENTRY_NUMBERED\n\n\tdelete fs;\n}\n\nvoid GameProfile::ResetOptional()\n{\n\tm_gameName.reset();\n\n\t// general settings\n\tm_loadSharedLibraries.reset(); // true;\n\tm_startWithPadView = false;\n\n\t// graphic settings\n\tm_accurateShaderMul = AccurateShaderMulOption::True;\n#if ENABLE_METAL\n\tm_shaderFastMath = true;\n\tm_metalBufferCacheMode = MetalBufferCacheMode::Auto;\n\tm_positionInvariance = PositionInvariance::Auto;\n#endif\n\t// cpu settings\n\tm_threadQuantum = kThreadQuantumDefault;\n\tm_cpuMode.reset(); // CPUModeOption::kSingleCoreRecompiler;\n\t// audio\n\tm_disableAudio = false;\n\t// controller settings\n\tfor (auto& profile : m_controllerProfile)\n\t\tprofile.reset();\n}\n\nvoid GameProfile::Reset()\n{\n\tm_gameName.reset();\n\n\t// general settings\n\tm_loadSharedLibraries = true;\n\tm_startWithPadView = false;\n\n\t// graphic settings\n\tm_accurateShaderMul = AccurateShaderMulOption::True;\n#if ENABLE_METAL\n\tm_shaderFastMath = true;\n\tm_metalBufferCacheMode = MetalBufferCacheMode::Auto;\n\tm_positionInvariance = PositionInvariance::Auto;\n#endif\n\tm_precompiledShaders = PrecompiledShaderOption::Auto;\n\t// cpu settings\n\tm_threadQuantum = kThreadQuantumDefault;\n\tm_cpuMode = CPUMode::Auto;\n\t// audio\n\tm_disableAudio = false;\n\t// controller settings\n\tfor (auto& profile : m_controllerProfile)\n\t\tprofile.reset();\n}\n"
  },
  {
    "path": "src/Cafe/GameProfile/GameProfile.h",
    "content": "#pragma once\n\n#include <optional>\n#include \"config/CemuConfig.h\"\n\nstruct gameProfileIntegerOption_t\n{\n\tbool isPresent = false;\n\tsint32 value;\n};\n\nclass GameProfile\n{\n\tfriend class GameProfileWindow;\n\npublic:\n\tstatic const uint32 kThreadQuantumDefault = 45000;\n\n\tbool Load(uint64_t title_id);\n\tvoid Save(uint64_t title_id);\n\tvoid ResetOptional();\n\tvoid Reset();\n\n\t[[nodiscard]] uint64 GetTitleId() const { return m_title_id; }\n\t[[nodiscard]] bool IsLoaded() const { return m_is_loaded; }\n\t[[nodiscard]] bool IsDefaultProfile() const { return m_is_default; }\n\t[[nodiscard]] const std::optional<std::string>& GetGameName() const { return m_gameName; }\n\n\t[[nodiscard]] const std::optional<bool>& ShouldLoadSharedLibraries() const { return m_loadSharedLibraries; }\n\t[[nodiscard]] bool StartWithGamepadView() const { return m_startWithPadView; }\n\n\t[[nodiscard]] const std::optional<GraphicAPI>& GetGraphicsAPI() const { return m_graphics_api; }\n\t[[nodiscard]] const AccurateShaderMulOption& GetAccurateShaderMul() const { return m_accurateShaderMul; }\n#if ENABLE_METAL\n\t[[nodiscard]] bool GetShaderFastMath() const { return m_shaderFastMath; }\n\t[[nodiscard]] MetalBufferCacheMode GetBufferCacheMode() const { return m_metalBufferCacheMode; }\n\t[[nodiscard]] PositionInvariance GetPositionInvariance() const { return m_positionInvariance; }\n#endif\n\t[[nodiscard]] const std::optional<PrecompiledShaderOption>& GetPrecompiledShadersState() const { return m_precompiledShaders; }\n\n\t[[nodiscard]] uint32 GetThreadQuantum() const { return m_threadQuantum; }\n\t[[nodiscard]] const std::optional<CPUMode>& GetCPUMode() const { return m_cpuMode; }\n\n\t[[nodiscard]] bool IsAudioDisabled() const { return m_disableAudio; }\n\n\t[[nodiscard]] const std::array< std::optional<std::string>, 8>& GetControllerProfile() const { return m_controllerProfile; }\n\nprivate:\n\tuint64_t m_title_id = 0;\n\tbool m_is_loaded = false;\n\tbool m_is_default = true;\n\n\tstd::optional<std::string> m_gameName{};\n\n\t// general settings\n\tstd::optional<bool> m_loadSharedLibraries{}; // = true;\n\tbool m_startWithPadView = false;\n\n\t// graphic settings\n\tstd::optional<GraphicAPI> m_graphics_api{};\n\tAccurateShaderMulOption m_accurateShaderMul = AccurateShaderMulOption::True;\n#if ENABLE_METAL\n\tbool m_shaderFastMath = true;\n\tMetalBufferCacheMode m_metalBufferCacheMode = MetalBufferCacheMode::Auto;\n\tPositionInvariance m_positionInvariance = PositionInvariance::Auto;\n#endif\n\tstd::optional<PrecompiledShaderOption> m_precompiledShaders{};\n\t// cpu settings\n\tuint32 m_threadQuantum = kThreadQuantumDefault; // values: 20000 45000 60000 80000 100000\n\tstd::optional<CPUMode> m_cpuMode{}; // = CPUModeOption::kSingleCoreRecompiler;\n\t// audio\n\tbool m_disableAudio = false;\n\t// controller settings\n\tstd::array< std::optional<std::string>, 8> m_controllerProfile{};\n};\nextern std::unique_ptr<GameProfile> g_current_game_profile;\n\nvoid gameProfile_load();\n"
  },
  {
    "path": "src/Cafe/GraphicPack/GraphicPack2.cpp",
    "content": "#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"config/CemuConfig.h\"\n#include \"config/ActiveSettings.h\"\n#include \"openssl/sha.h\"\n#include \"Cafe/HW/Latte/Renderer/RendererOuputShader.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n#include \"boost/algorithm/string.hpp\"\n#include \"util/helpers/MapAdaptor.h\"\n#include \"util/helpers/StringParser.h\"\n#include \"Cafe/HW/Latte/Core/LatteTiming.h\"\n#include \"util/IniParser/IniParser.h\"\n#include \"util/helpers/StringHelpers.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"HW/Espresso/Debugger/Debugger.h\"\n\n#include <cinttypes>\n\nstd::vector<GraphicPackPtr> GraphicPack2::s_graphic_packs;\nstd::vector<GraphicPackPtr> GraphicPack2::s_active_graphic_packs;\nstd::atomic_bool GraphicPack2::s_isReady;\n\n#define GP_LEGACY_VERSION\t\t(2)\n\nvoid GraphicPack2::LoadGraphicPack(fs::path graphicPackPath)\n{\n\tfs::path rulesPath = graphicPackPath;\n\trulesPath.append(\"rules.txt\");\n\tstd::unique_ptr<FileStream> fs_rules(FileStream::openFile2(rulesPath));\n\tif (!fs_rules)\n\t\treturn;\n\tstd::vector<uint8> rulesData;\n\tfs_rules->extract(rulesData);\n\tIniParser iniParser(rulesData, _pathToUtf8(rulesPath));\n\n\tif (!iniParser.NextSection())\n\t{\n\t\tcemuLog_log(LogType::Force, \"{}: Does not contain any sections\", _pathToUtf8(rulesPath));\n\t\treturn;\n\t}\n\tif (!boost::iequals(iniParser.GetCurrentSectionName(), \"Definition\"))\n\t{\n\t\tcemuLog_log(LogType::Force, \"{}: [Definition] must be the first section\", _pathToUtf8(rulesPath));\n\t\treturn;\n\t}\n\n\tauto option_version = iniParser.FindOption(\"version\");\n\tif (option_version)\n\t{\n\t\tsint32 versionNum = -1;\n\t\tauto [ptr, ec] = std::from_chars(option_version->data(), option_version->data() + option_version->size(), versionNum);\n\t\tif (ec != std::errc{})\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"{}: Unable to parse version\", _pathToUtf8(rulesPath));\n\t\t\treturn;\n\t\t}\n\t\tif (versionNum > GP_LEGACY_VERSION)\n\t\t{\n\t\t\tGraphicPack2::LoadGraphicPack(rulesPath, iniParser);\n\t\t\treturn;\n\t\t}\n\t}\n\tcemuLog_log(LogType::Force, \"{}: Outdated graphic pack\", _pathToUtf8(rulesPath));\n}\n\nvoid GraphicPack2::LoadAll()\n{\n\tstd::error_code ec;\n\tfs::path basePath = ActiveSettings::GetUserDataPath(\"graphicPacks\");\n\tfor (fs::recursive_directory_iterator it(basePath, ec); it != end(it); ++it)\n\t{\n\t\tif (!it->is_directory(ec))\n\t\t\tcontinue;\n\t\tfs::path gfxPackPath = it->path();\n\t\tif (fs::exists(gfxPackPath / \"rules.txt\", ec))\n\t\t{\n\t\t\tLoadGraphicPack(gfxPackPath);\n\t\t\tit.disable_recursion_pending(); // dont recurse deeper in a gfx pack directory\n\t\t\tcontinue;\n\t\t}\n\t}\n}\n\nbool GraphicPack2::LoadGraphicPack(const fs::path& rulesPath, IniParser& rules)\n{\n\ttry\n\t{\n\t\tauto gp = std::make_shared<GraphicPack2>(rulesPath, rules);\n\n\t\t// check if enabled and preset set\n\t\tconst auto& config_entries = GetConfigHandle().data().graphic_pack_entries;\n\n\t\t// legacy absolute path checking for not breaking compatibility\n\t\tauto file = gp->GetRulesPath();\n\t\tauto it = config_entries.find(file.lexically_normal());\n\t\tif (it == config_entries.cend())\n\t\t{\n\t\t\t// check for relative path\n\t\t\tit = config_entries.find(_utf8ToPath(gp->GetNormalizedPathString()));\n\t\t}\n\n\t\tif (it != config_entries.cend())\n\t\t{\n\t\t\tbool enabled = true;\n\t\t\tfor (auto& kv : it->second)\n\t\t\t{\n\t\t\t\tif (boost::iequals(kv.first, \"_disabled\"))\n\t\t\t\t{\n\t\t\t\t\tenabled = false;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tgp->SetActivePreset(kv.first, kv.second, false);\n\t\t\t}\n\n\t\t\tgp->SetEnabled(enabled);\n\t\t}\n\n\t\tgp->UpdatePresetVisibility();\n\t\tgp->ValidatePresetSelections();\n\n\t\ts_graphic_packs.emplace_back(gp);\n\t\treturn true;\n\t}\n\tcatch (const std::exception&)\n\t{\n\t\treturn false;\n\t}\n}\n\nbool GraphicPack2::ActivateGraphicPack(const std::shared_ptr<GraphicPack2>& graphic_pack)\n{\n\tif (graphic_pack->Activate())\n\t{\n\t\ts_active_graphic_packs.push_back(graphic_pack);\n\t\tg_debuggerDispatcher.NotifyGraphicPacksModified();\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nbool GraphicPack2::DeactivateGraphicPack(const std::shared_ptr<GraphicPack2>& graphic_pack)\n{\n\tif (!graphic_pack->IsActivated())\n\t\treturn false;\n\n\tconst auto it = std::find_if(s_active_graphic_packs.begin(), s_active_graphic_packs.end(),\n\t\t[graphic_pack](const GraphicPackPtr& gp)\n\t{\n\t\treturn gp->GetNormalizedPathString() == graphic_pack->GetNormalizedPathString();\n\t}\n\t);\n\n\tif (it == s_active_graphic_packs.end())\n\t\treturn false;\n\n\tgraphic_pack->Deactivate();\n\ts_active_graphic_packs.erase(it);\n\tg_debuggerDispatcher.NotifyGraphicPacksModified();\n\treturn true;\n}\n\nvoid GraphicPack2::ActivateForCurrentTitle()\n{\n\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t// activate graphic packs\n\tfor (const auto& gp : GraphicPack2::GetGraphicPacks())\n\t{\n\t\tif (!gp->IsEnabled())\n\t\t\tcontinue;\n\n\t\tif (!gp->ContainsTitleId(titleId))\n\t\t\tcontinue;\n\n\t\tif (GraphicPack2::ActivateGraphicPack(gp))\n\t\t{\n\t\t\tif (gp->GetPresets().empty())\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Activate graphic pack: {}\", gp->GetVirtualPath());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::string logLine;\n\t\t\t\tlogLine.assign(fmt::format(\"Activate graphic pack: {} [Presets: \", gp->GetVirtualPath()));\n\t\t\t\tbool isFirst = true;\n\t\t\t\tfor (auto& itr : gp->GetPresets())\n\t\t\t\t{\n\t\t\t\t\tif (!itr->active)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (isFirst)\n\t\t\t\t\t\tisFirst = false;\n\t\t\t\t\telse\n\t\t\t\t\t\tlogLine.append(\",\");\n\t\t\t\t\tlogLine.append(itr->name);\n\t\t\t\t}\n\t\t\t\tlogLine.append(\"]\");\n\t\t\t\tcemuLog_log(LogType::Force, logLine);\n\t\t\t}\n\t\t}\n\t}\n\ts_isReady = true;\n}\n\nvoid GraphicPack2::Reset()\n{\n\ts_active_graphic_packs.clear();\n\ts_isReady = false;\n}\n\nvoid GraphicPack2::ClearGraphicPacks()\n{\n\ts_graphic_packs.clear();\n\ts_active_graphic_packs.clear();\n}\n\nvoid GraphicPack2::WaitUntilReady()\n{\n\twhile (!s_isReady)\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(5));\n}\n\nstd::unordered_map<std::string, GraphicPack2::PresetVar> GraphicPack2::ParsePresetVars(IniParser& rules) const\n{\n\tExpressionParser parser;\n\tstd::unordered_map<std::string, PresetVar> vars;\n\tfor(auto& itr : rules.GetAllOptions())\n\t{\n\t\tauto option_name = itr.first;\n\t\tauto option_value = itr.second;\n\t\tif (option_name.empty() || option_name[0] != '$')\n\t\t\tcontinue;\n\t\tVarType type = kDouble;\n\t\tstd::string name(option_name);\n\t\tconst auto index = name.find(':');\n\t\tif(index != std::string::npos)\n\t\t{\n\t\t\tauto type_name = name.substr(index + 1);\n\t\t\tname = name.substr(0, index);\n\n\t\t\ttrim(name);\n\t\t\ttrim(type_name);\n\n\t\t\tif (type_name == \"double\")\n\t\t\t\ttype = kDouble;\n\t\t\telse if (type_name == \"int\")\n\t\t\t\ttype = kInt;\n\t\t}\n\t\tconst double value = parser.Evaluate(option_value);\n\t\tvars.try_emplace(name, std::make_pair(type, value));\n\t\tparser.AddConstant(name, value);\n\t}\n\treturn vars;\n}\n\nGraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)\n\t: m_rulesPath(std::move(rulesPath))\n{\n\t// we're already in [Definition]\n\tauto option_version = rules.FindOption(\"version\");\n\tif (!option_version)\n\t\tthrow std::exception();\n\tm_version = StringHelpers::ToInt(*option_version, -1);\n\tif (m_version < 0)\n\t{\n\t\tcemuLog_log(LogType::Force, \"{}: Invalid version\", _pathToUtf8(m_rulesPath));\n\t\tthrow std::exception();\n\t}\n\n\tauto option_rendererFilter = rules.FindOption(\"rendererFilter\");\n\tif (option_rendererFilter)\n\t{\n\t\tif (boost::iequals(*option_rendererFilter, \"vulkan\"))\n\t\t\tm_renderer_api = RendererAPI::Vulkan;\n\t\telse if (boost::iequals(*option_rendererFilter, \"opengl\"))\n\t\t\tm_renderer_api = RendererAPI::OpenGL;\n\t\telse if (boost::iequals(*option_rendererFilter, \"metal\"))\n\t\t\tm_renderer_api = RendererAPI::Metal;\n\t\telse\n\t\t\tcemuLog_log(LogType::Force, \"Unknown value '{}' for rendererFilter option\", *option_rendererFilter);\n\t}\n\n\tauto option_defaultEnabled = rules.FindOption(\"default\");\n\tif(option_defaultEnabled)\n\t{\n\t\tm_default_enabled = boost::iequals(*option_defaultEnabled, \"true\") || boost::iequals(*option_defaultEnabled, \"1\");\n\t\tm_enabled = m_default_enabled;\n\t}\n\n\tauto option_allowRendertargetSizeOptimization = rules.FindOption(\"colorbufferOptimizationAware\");\n\tif (option_allowRendertargetSizeOptimization)\n\t\tm_allowRendertargetSizeOptimization = boost::iequals(*option_allowRendertargetSizeOptimization, \"true\") || boost::iequals(*option_allowRendertargetSizeOptimization, \"1\");\n\n\tauto option_vendorFilter = rules.FindOption(\"vendorFilter\");\n\tif (option_vendorFilter)\n\t{\n\t\tif (boost::iequals(*option_vendorFilter, \"amd\"))\n\t\t\tm_gfx_vendor = GfxVendor::AMD;\n\t\telse if (boost::iequals(*option_vendorFilter, \"intel\"))\n\t\t\tm_gfx_vendor = GfxVendor::Intel;\n\t\telse if (boost::iequals(*option_vendorFilter, \"mesa\"))\n\t\t\tm_gfx_vendor = GfxVendor::Mesa;\n\t\telse if (boost::iequals(*option_vendorFilter, \"nvidia\"))\n\t\t\tm_gfx_vendor = GfxVendor::Nvidia;\n\t\telse if (boost::iequals(*option_vendorFilter, \"apple\"))\n\t\t\tm_gfx_vendor = GfxVendor::Apple;\n\t\telse\n\t\t\tcemuLog_log(LogType::Force, \"Unknown value '{}' for vendorFilter\", *option_vendorFilter);\n\t}\n\n\tauto option_path = rules.FindOption(\"path\");\n\tif (!option_path)\n\t{\n\t\tauto gp_name_log = rules.FindOption(\"name\");\n\t\tcemuLog_log(LogType::Force, \"[Definition] section from '{}' graphic pack must contain option: path\", gp_name_log.has_value() ? *gp_name_log : \"Unknown\");\n\t\tthrow std::exception();\n\t}\n\tm_virtualPath = *option_path;\n\n\tauto option_gp_name = rules.FindOption(\"name\");\n\tif (option_gp_name)\n\t\tm_name = *option_gp_name;\n\n\tauto option_description = rules.FindOption(\"description\");\n\tif (option_description)\n\t{\n\t\tm_description = *option_description;\n\t\tstd::replace(m_description.begin(), m_description.end(), '|', '\\n');\n\t}\n\n\tm_title_ids = ParseTitleIds(rules, \"titleIds\");\n\tif(m_title_ids.empty() && !m_universal)\n\t\tthrow std::exception();\n\n\tauto option_fsPriority = rules.FindOption(\"fsPriority\");\n\tif (option_fsPriority)\n\t{\n\t\tstd::string tmp(*option_fsPriority);\n\t\tm_fs_priority = std::stoi(tmp);\n\t}\n\n\t// load presets\n\twhile (rules.NextSection())\n\t{\n\t\tauto currentSectionName = rules.GetCurrentSectionName();\n\t\tif (boost::iequals(currentSectionName, \"Default\"))\n\t\t{\n\t\t\tm_preset_vars = ParsePresetVars(rules);\n\t\t}\n\t\telse if (boost::iequals(currentSectionName, \"Preset\"))\n\t\t{\n\t\t\tconst auto preset_name = rules.FindOption(\"name\");\n\t\t\tif (!preset_name)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Graphic pack \\\"{}\\\": Preset in line {} skipped because it has no name option defined\", GetNormalizedPathString(), rules.GetCurrentSectionLineNumber());\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst auto category = rules.FindOption(\"category\");\n\t\t\tconst auto condition = rules.FindOption(\"condition\");\n\t\t\tconst auto default_selected = rules.FindOption(\"default\");\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\tconst auto vars = ParsePresetVars(rules);\n\t\t\t\tPresetPtr preset;\n\t\t\t\tif (category && condition)\n\t\t\t\t\tpreset = std::make_shared<Preset>(*category, *preset_name, *condition, vars);\n\t\t\t\telse if (category)\n\t\t\t\t\tpreset = std::make_shared<Preset>(*category, *preset_name, vars);\n\t\t\t\telse\n\t\t\t\t\tpreset = std::make_shared<Preset>(*preset_name, vars);\n\t\t\t\tif (default_selected)\n\t\t\t\t\tpreset->is_default = StringHelpers::ToInt(*default_selected) != 0;\n\t\t\t\tm_presets.emplace_back(preset);\n\t\t\t}\n\t\t\tcatch (const std::exception & ex)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Graphic pack \\\"{}\\\": Can't parse preset \\\"{}\\\": {}\", GetNormalizedPathString(), *preset_name, ex.what());\n\t\t\t}\n\t\t}\n\t\telse if (boost::iequals(currentSectionName, \"RAM\"))\n\t\t{\n\t\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t\t{\n\t\t\t\tchar optionNameBuf[64];\n\t\t\t\t*fmt::format_to(optionNameBuf, \"mapping{}\", i) = '\\0';\n\t\t\t\tconst auto mappingOption = rules.FindOption(optionNameBuf);\n\t\t\t\tif (mappingOption)\n\t\t\t\t{\n\t\t\t\t\tif (m_version <= 5)\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"Graphic pack \\\"{}\\\": [RAM] options are only available for graphic pack version 6 or higher\", GetNormalizedPathString(), optionNameBuf);\n\t\t\t\t\t\tthrow std::exception();\n\t\t\t\t\t}\n\n\t\t\t\t\tStringTokenParser parser(*mappingOption);\n\t\t\t\t\tuint32 addrStart = 0, addrEnd = 0;\n\t\t\t\t\tif (parser.parseU32(addrStart) && parser.matchWordI(\"-\") && parser.parseU32(addrEnd) && parser.isEndOfString())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (addrEnd <= addrStart)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"Graphic pack \\\"{}\\\": start address (0x{:08x}) must be greater than end address (0x{:08x}) for {}\", GetNormalizedPathString(), addrStart, addrEnd, optionNameBuf);\n\t\t\t\t\t\t\tthrow std::exception();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ((addrStart & 0xFFF) != 0 || (addrEnd & 0xFFF) != 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"Graphic pack \\\"{}\\\": addresses for %s are not aligned to 0x1000\", GetNormalizedPathString(), optionNameBuf);\n\t\t\t\t\t\t\tthrow std::exception();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tm_ramMappings.emplace_back(addrStart, addrEnd);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"Graphic pack \\\"{}\\\": has invalid syntax for option {}\", GetNormalizedPathString(), optionNameBuf);\n\t\t\t\t\t\tthrow std::exception();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (m_version >= 5)\n\t{\n\t\t// store by category\n\t\tstd::unordered_map<std::string, std::vector<PresetPtr>> tmp_map;\n\n\t\t// all vars must be defined in the default preset vars before\n\t\tstd::vector<std::pair<std::string, std::string>> mismatchingPresetVars;\n\t\tfor (const auto& presetEntry : m_presets)\n\t\t{\n\t\t\ttmp_map[presetEntry->category].emplace_back(presetEntry);\n\n\t\t\tfor (auto& presetVar : presetEntry->variables)\n\t\t\t{\n\t\t\t\tconst auto it = m_preset_vars.find(presetVar.first);\n\t\t\t\tif (it == m_preset_vars.cend())\n\t\t\t\t{\n\t\t\t\t\tmismatchingPresetVars.emplace_back(presetEntry->name, presetVar.first);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// overwrite var type with default var type\n\t\t\t\tpresetVar.second.first = it->second.first;\n\t\t\t}\n\t\t}\n\n\t\tif(!mismatchingPresetVars.empty())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Graphic pack \\\"{}\\\" contains preset variables which are not defined in the [Default] section:\", GetNormalizedPathString());\n\t\t\tfor (const auto& [presetName, varName] : mismatchingPresetVars)\n\t\t\t\tcemuLog_log(LogType::Force, \"Preset: {} Variable: {}\", presetName, varName);\n\t\t\tthrow std::exception();\n\t\t}\n\n\t\t// have first entry be default active for every category if no default= is set\n\t\tfor(auto entry : get_values(tmp_map))\n\t\t{\n\t\t\tif (!entry.empty())\n\t\t\t{\n\t\t\t\tconst auto it = std::find_if(entry.cbegin(), entry.cend(), [](const PresetPtr& preset) { return preset->is_default; });\n\t\t\t\tif (it != entry.cend())\n\t\t\t\t\t(*it)->active = true;\n\t\t\t\telse\n\t\t\t\t\t(*entry.begin())->active = true;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// verify preset data to contain the same keys\n\t\tstd::unordered_map<std::string, std::vector<PresetPtr>> tmp_map;\n\t\tfor (const auto& entry : m_presets)\n\t\t\ttmp_map[entry->category].emplace_back(entry);\n\n\t\tfor (const auto& kv : tmp_map)\n\t\t{\n\t\t\tbool has_default = false;\n\t\t\tfor (size_t i = 0; i + 1 < kv.second.size(); ++i)\n\t\t\t{\n\t\t\t\tauto& p1 = kv.second[i];\n\t\t\t\tauto& p2 = kv.second[i + 1];\n\t\t\t\tif (p1->variables.size() != p2->variables.size())\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Graphic pack: \\\"{}\\\" contains inconsistent preset variables\", GetNormalizedPathString());\n\t\t\t\t\tthrow std::exception();\n\t\t\t\t}\n\n\t\t\t\tstd::set<std::string> keys1(get_keys(p1->variables).begin(), get_keys(p1->variables).end());\n\t\t\t\tstd::set<std::string> keys2(get_keys(p2->variables).begin(), get_keys(p2->variables).end());\n\t\t\t\tif (keys1 != keys2)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Graphic pack: \\\"{}\\\" contains inconsistent preset variables\", GetNormalizedPathString());\n\t\t\t\t\tthrow std::exception();\n\t\t\t\t}\n\n\t\t\t\tif(p1->is_default)\n\t\t\t\t{\n\t\t\t\t\tif(has_default)\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"Graphic pack: \\\"{}\\\" has more than one preset with the default key set for the same category \\\"{}\\\"\", GetNormalizedPathString(), p1->name);\n\t\t\t\t\tp1->active = true;\n\t\t\t\t\thas_default = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// have first entry by default active if no default is set\n\t\t\tif (!has_default)\n\t\t\t\tkv.second[0]->active = true;\n\t\t}\n\t}\n}\n\n// returns true if enabling, disabling (changeEnableState) or changing presets (changePreset) for the graphic pack requires restarting if the game is already running\nbool GraphicPack2::RequiresRestart(bool changeEnableState, bool changePreset)\n{\n\tif (!GetTextureRules().empty())\n\t\treturn true;\n\treturn false;\n}\n\nbool GraphicPack2::Reload()\n{\n\tDeactivate();\n\treturn Activate();\n}\n\nstd::string GraphicPack2::GetNormalizedPathString() const\n{\n\treturn _pathToUtf8(MakeRelativePath(ActiveSettings::GetUserDataPath(), GetRulesPath()).lexically_normal());\n}\n\nbool GraphicPack2::ContainsTitleId(uint64_t title_id) const\n{\n\tif (m_universal)\n\t\treturn true;\n\n\tconst auto it = std::find_if(m_title_ids.begin(), m_title_ids.end(), [title_id](uint64 id) { return id == title_id; });\n\treturn it != m_title_ids.end();\n}\n\nbool GraphicPack2::HasActivePreset() const\n{\n\treturn std::any_of(m_presets.cbegin(), m_presets.cend(), [](const PresetPtr& preset)\n\t\t{\n\t\t\treturn preset->active;\n\t\t});\n}\n\nstd::string GraphicPack2::GetActivePreset(std::string_view category) const\n{\n\tconst auto it = std::find_if(m_presets.cbegin(), m_presets.cend(), [category](const PresetPtr& preset)\n\t\t{\n\t\t\treturn preset->active && preset->category == category;\n\t\t});\n\treturn it != m_presets.cend() ? (*it)->name : std::string{ \"\" };\n}\n\nvoid GraphicPack2::UpdatePresetVisibility()\n{\n\t// update visiblity of each preset\n\tstd::for_each(m_presets.begin(), m_presets.end(), [this](PresetPtr& p)\n\t{\n\t\tp->visible = m_version >= 5 ? IsPresetVisible(p) : true;\n\t});\n}\n\nvoid GraphicPack2::ValidatePresetSelections()\n{\n\tif (m_version < 5)\n\t\treturn; // only applies to new categorized presets\n\n\t// if any preset is changed then other categories might be affected indirectly\n\t//\n\t// example: selecting the aspect ratio in a resolution graphic pack would change the available presets in the resolution category\n\t// how to handle: select the first available resolution (or the one marked as default)\n\t//\n\t// example: a preset category might be hidden entirely (e.g. due to a separate advanced options dropdown)\n\t// how to handle: leave the previously selected preset\n\t//\n\t// the logic is therefore as follows:\n\t// if there is a preset category with at least 1 visible preset entry then make sure one of those is actually selected\n\t// for completely hidden preset categories we leave the selection as-is\n\n\tstd::vector<std::string> order;\n\tstd::unordered_map<std::string, std::vector<GraphicPack2::PresetPtr>> categorizedPresets = GraphicPack2::GetCategorizedPresets(order);\n\n\tbool changedPresets = false;\n\tfor (auto& categoryItr : categorizedPresets)\n\t{\n\t\t// get selection of this category\n\t\tsize_t numVisiblePresets = 0;\n\t\tGraphicPack2::PresetPtr defaultSelection = nullptr;\n\t\tGraphicPack2::PresetPtr selectedPreset = nullptr;\n\t\tfor (auto& presetItr : categoryItr.second)\n\t\t{\n\t\t\tif (presetItr->visible)\n\t\t\t{\n\t\t\t\tnumVisiblePresets++;\n\t\t\t\tif (!defaultSelection || presetItr->is_default) // the preset marked as default becomes the default selection, otherwise pick first visible one\n\t\t\t\t\tdefaultSelection = presetItr;\n\t\t\t}\n\t\t\tif (presetItr->active)\n\t\t\t{\n\t\t\t\tif (selectedPreset)\n\t\t\t\t{\n\t\t\t\t\t// multiple selections inside the same group are invalid\n\t\t\t\t\tpresetItr->active = false;\n\t\t\t\t\tchangedPresets = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tselectedPreset = presetItr;\n\t\t\t}\n\t\t}\n\t\tif (numVisiblePresets == 0)\n\t\t\tcontinue; // do not touch selection\n\t\tif (!selectedPreset)\n\t\t{\n\t\t\t// no selection at all\n\t\t\tif (defaultSelection)\n\t\t\t{\n\t\t\t\tselectedPreset = defaultSelection;\n\t\t\t\tselectedPreset->active = true;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\t// if the currently selected preset is invisible, update it to the preferred visible selection\n\t\tif (!selectedPreset->visible)\n\t\t{\n\t\t\tselectedPreset->active = false;\n\t\t\tdefaultSelection->active = true;\n\t\t\tchangedPresets = true;\n\t\t}\n\t}\n\tif (changedPresets)\n\t\tUpdatePresetVisibility();\n}\n\nbool GraphicPack2::SetActivePreset(std::string_view category, std::string_view name, bool update_visibility)\n{\n\t// disable currently active preset\n\tstd::for_each(m_presets.begin(), m_presets.end(), [category](PresetPtr& p)\n\t{\n\t\tif(p->category == category)\n\t\t\tp->active = false;\n\t});\n\n\tif (name.empty())\n\t\treturn true;\n\n\t// enable new preset\n\tconst auto it = std::find_if(m_presets.cbegin(), m_presets.cend(), [category, name](const PresetPtr& preset)\n\t\t{\n\t\t\treturn preset->category == category && preset->name == name;\n\t\t});\n\n\tbool result;\n\tif (it != m_presets.cend())\n\t{\n\t\t(*it)->active = true;\n\t\tcemu_assert_debug(std::count_if(m_presets.cbegin(), m_presets.cend(), [category](const PresetPtr& p) { return p->category == category && p->active; }) == 1);\n\t\tresult = true;\n\t}\n\telse\n\t\tresult = false;\n\n\tif (update_visibility)\n\t{\n\t\tUpdatePresetVisibility();\n\t\tValidatePresetSelections();\n\t}\n\n\treturn result;\n}\n\nvoid GraphicPack2::LoadShaders()\n{\n\tfs::path path = GetRulesPath();\n\tfor (auto& it : fs::directory_iterator(path.remove_filename()))\n\t{\n\t\tif (!is_regular_file(it))\n\t\t\tcontinue;\n\n\t\ttry\n\t\t{\n\t\t\tconst auto& p = it.path();\n\t\t\tauto filename = p.filename().wstring();\n\t\t\tuint64 shader_base_hash = 0;\n\t\t\tuint64 shader_aux_hash = 0;\n\t\t\twchar_t shader_type[256]{};\n\t\t\tif (filename.size() < 256 && swscanf(filename.c_str(), L\"%\" SCNx64 \"_%\" SCNx64 \"_%ls\", &shader_base_hash, &shader_aux_hash, shader_type) == 3)\n\t\t\t{\n\t\t\t    bool isMetalShader = (shader_type[2] == '_' && shader_type[3] == 'm' && shader_type[4] == 's' && shader_type[5] == 'l');\n\n\t\t\t\tif (shader_type[0] == 'p' && shader_type[1] == 's')\n\t\t\t\t\tm_custom_shaders.emplace_back(LoadShader(p, shader_base_hash, shader_aux_hash, GP_SHADER_TYPE::PIXEL, isMetalShader));\n\t\t\t\telse if (shader_type[0] == 'v' && shader_type[1] == 's')\n\t\t\t\t\tm_custom_shaders.emplace_back(LoadShader(p, shader_base_hash, shader_aux_hash, GP_SHADER_TYPE::VERTEX, isMetalShader));\n\t\t\t\telse if (shader_type[0] == 'g' && shader_type[1] == 's')\n\t\t\t\t\tm_custom_shaders.emplace_back(LoadShader(p, shader_base_hash, shader_aux_hash, GP_SHADER_TYPE::GEOMETRY, isMetalShader));\n\t\t\t}\n\t\t\telse if (filename == L\"output.glsl\")\n\t\t\t{\n\t\t\t\tstd::ifstream file(p);\n\t\t\t\tif (!file.is_open())\n\t\t\t\t\tthrow std::runtime_error(fmt::format(\"can't open graphic pack file: {}\", _pathToUtf8(p.filename())));\n\n\t\t\t\tfile.seekg(0, std::ios::end);\n\t\t\t\tm_output_shader_source.reserve(file.tellg());\n\t\t\t\tfile.seekg(0, std::ios::beg);\n\n\t\t\t\tm_output_shader_source.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());\n\t\t\t\tApplyShaderPresets(m_output_shader_source);\n\t\t\t}\n\t\t\telse if (filename == L\"upscaling.glsl\")\n\t\t\t{\n\t\t\t\tstd::ifstream file(p);\n\t\t\t\tif (!file.is_open())\n\t\t\t\t\tthrow std::runtime_error(fmt::format(\"can't open graphic pack file: {}\", _pathToUtf8(p.filename())));\n\n\t\t\t\tfile.seekg(0, std::ios::end);\n\t\t\t\tm_upscaling_shader_source.reserve(file.tellg());\n\t\t\t\tfile.seekg(0, std::ios::beg);\n\n\t\t\t\tm_upscaling_shader_source.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());\n\t\t\t\tApplyShaderPresets(m_upscaling_shader_source);\n\t\t\t}\n\t\t\telse if (filename == L\"downscaling.glsl\")\n\t\t\t{\n\t\t\t\tstd::ifstream file(p);\n\t\t\t\tif (!file.is_open())\n\t\t\t\t\tthrow std::runtime_error(fmt::format(\"can't open graphic pack file: {}\", _pathToUtf8(p.filename())));\n\n\t\t\t\tfile.seekg(0, std::ios::end);\n\t\t\t\tm_downscaling_shader_source.reserve(file.tellg());\n\t\t\t\tfile.seekg(0, std::ios::beg);\n\n\t\t\t\tm_downscaling_shader_source.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());\n\t\t\t\tApplyShaderPresets(m_downscaling_shader_source);\n\t\t\t}\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"graphicPack: error while loading custom shader: {}\", ex.what());\n\t\t}\n\t}\n}\n\nbool GraphicPack2::SetActivePreset(std::string_view name)\n{\n\treturn SetActivePreset(\"\", name);\n}\n\nbool GraphicPack2::IsPresetVisible(const PresetPtr& preset) const\n{\n\tif (preset->condition.empty())\n\t\treturn true;\n\n\ttry\n\t{\n\t\tTExpressionParser<int> p;\n\t\tFillPresetConstants(p);\n\t\treturn p.Evaluate(preset->condition) != 0;\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"error when trying to check visiblity of preset: {}\", ex.what());\n\t\treturn false;\n\t}\n}\n\nstd::optional<GraphicPack2::PresetVar> GraphicPack2::GetPresetVariable(const std::vector<PresetPtr>& presets, std::string_view var_name) const\n{\n\t// no priority and visibility filter\n\tif(m_version < 5)\n\t{\n\t\tfor (const auto& preset : presets)\n\t\t{\n\t\t\tconst auto it = std::find_if(preset->variables.cbegin(), preset->variables.cend(), [&var_name](auto p) { return p.first == var_name; });\n\t\t\tif (it != preset->variables.cend())\n\t\t\t\treturn it->second;\n\t\t}\n\n\t\treturn {};\n\t}\n\n\t// visible > none visible > default\n\tfor (const auto& preset : presets)\n\t{\n\t\tif (preset->visible)\n\t\t{\n\t\t\tconst auto it = std::find_if(preset->variables.cbegin(), preset->variables.cend(), [&var_name](auto p) { return p.first == var_name; });\n\t\t\tif (it != preset->variables.cend())\n\t\t\t\treturn it->second;\n\t\t}\n\t}\n\n\tfor (const auto& preset : presets)\n\t{\n\t\tif (!preset->visible)\n\t\t{\n\t\t\tconst auto it = std::find_if(preset->variables.cbegin(), preset->variables.cend(), [&var_name](auto p) { return p.first == var_name; });\n\t\t\tif (it != preset->variables.cend())\n\t\t\t\treturn it->second;\n\t\t}\n\t}\n\n\tconst auto it = std::find_if(m_preset_vars.cbegin(), m_preset_vars.cend(), [&var_name](auto p) { return p.first == var_name; });\n\tif (it != m_preset_vars.cend())\n\t{\n\t\treturn it->second;\n\t}\n\n\treturn {};\n}\n\nvoid GraphicPack2::AddConstantsForCurrentPreset(ExpressionParser& ep)\n{\n\tif (m_version < 5)\n\t{\n\t\tfor (const auto& preset : GetActivePresets())\n\t\t{\n\t\t\tfor (auto& v : preset->variables)\n\t\t\t{\n\t\t\t\tep.AddConstant(v.first, v.second.second);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tFillPresetConstants(ep);\n\t}\n}\n\nvoid GraphicPack2::_iterateReplacedFiles(const fs::path& currentPath, bool isAOC, const char* virtualMountBase)\n{\n\tuint64 currentTitleId = CafeSystem::GetForegroundTitleId();\n\tuint64 aocTitleId = (currentTitleId & 0xFFFFFFFFull) | 0x0005000c00000000ull;\n\tfor (auto& it : fs::recursive_directory_iterator(currentPath))\n\t{\n\t\tif (fs::is_regular_file(it))\n\t\t{\n\t\t\tfs::path virtualMountPath = fs::relative(it.path(), currentPath);\n\t\t\tif (isAOC)\n\t\t\t{\n\t\t\t\tvirtualMountPath = fs::path(fmt::format(\"/vol/aoc{:016x}/\", aocTitleId)) / virtualMountPath;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tvirtualMountPath = fs::path(virtualMountBase) / virtualMountPath;\n\t\t\t}\n\t\t\tfscDeviceRedirect_add(virtualMountPath.generic_string(), it.file_size(), it.path().generic_string(), m_fs_priority);\n\t\t}\n\t}\n}\n\nvoid GraphicPack2::LoadReplacedFiles()\n{\n\tif (m_patchedFilesLoaded)\n\t\treturn;\n\tm_patchedFilesLoaded = true;\n\n\tfs::path gfxPackPath = GetRulesPath();\n\tgfxPackPath = gfxPackPath.remove_filename();\n\n\t// /content/\n\tfs::path contentPath(gfxPackPath);\n\tcontentPath.append(\"content\");\n\n\tstd::error_code ec;\n\tif (fs::exists(contentPath, ec))\n\t{\n\t\t// setup redirections\n\t\tfscDeviceRedirect_map();\n\t\t_iterateReplacedFiles(contentPath, false, \"vol/content/\");\n\t}\n\t// /aoc/\n\tfs::path aocPath(gfxPackPath);\n\taocPath.append(\"aoc\");\n\n\tif (fs::exists(aocPath, ec))\n\t{\n\t\tuint64 aocTitleId = CafeSystem::GetForegroundTitleId();\n\t\taocTitleId = aocTitleId & 0xFFFFFFFFULL;\n\t\taocTitleId |= 0x0005000c00000000ULL;\n\t\t// setup redirections\n\t\tfscDeviceRedirect_map();\n\t\t_iterateReplacedFiles(aocPath, true, nullptr);\n\t}\n\t\n\t// /code/\n\tfs::path codePath(gfxPackPath);\n\tcodePath.append(\"code\");\n\t\n\tif (fs::exists(codePath, ec))\n\t{\n\t    // setup redirections\n\t\tfscDeviceRedirect_map();\n\t\t_iterateReplacedFiles(codePath, false, CafeSystem::GetInternalVirtualCodeFolder().c_str());\n\t}\n}\n\nbool GraphicPack2::Activate()\n{\n\tif (m_activated)\n\t\treturn true;\n\n\t// check if gp should be loaded\n\tif (m_renderer_api.has_value() && m_renderer_api.value() != g_renderer->GetType())\n\t\treturn false;\n\n\tif (m_gfx_vendor.has_value())\n\t{\n\t\tauto vendor = g_renderer->GetVendor();\n\t\tif (m_gfx_vendor.value() != vendor)\n\t\t\treturn false;\n\t}\n\n\tFileStream* fs_rules = FileStream::openFile2(m_rulesPath);\n\tif (!fs_rules)\n\t\treturn false;\n\tstd::vector<uint8> rulesData;\n\tfs_rules->extract(rulesData);\n\tdelete fs_rules;\n\n\tIniParser rules({ (char*)rulesData.data(), rulesData.size()}, GetNormalizedPathString());\n\n\t// load rules\n\ttry\n\t{\n\t\tExpressionParser parser;\n\t\tAddConstantsForCurrentPreset(parser);\n\n\t\twhile (rules.NextSection())\n\t\t{\n\t\t\t//const char* category_name = sPref_currentCategoryName(rules);\n\t\t\tstd::string_view category_name = rules.GetCurrentSectionName();\n\t\t\tif (boost::iequals(category_name, \"TextureRedefine\"))\n\t\t\t{\n\t\t\t\tTextureRule rule{};\n\t\t\t\tParseRule(parser, rules, \"width\", &rule.filter_settings.width);\n\t\t\t\tParseRule(parser, rules, \"height\", &rule.filter_settings.height);\n\t\t\t\tParseRule(parser, rules, \"depth\", &rule.filter_settings.depth);\n\n\t\t\t\tbool inMem1 = false;\n\t\t\t\tif (ParseRule(parser, rules, \"inMEM1\", &inMem1))\n\t\t\t\t\trule.filter_settings.inMEM1 = inMem1 ? TextureRule::FILTER_SETTINGS::MEM1_FILTER::INSIDE : TextureRule::FILTER_SETTINGS::MEM1_FILTER::OUTSIDE;\n\n\t\t\t\trule.filter_settings.format_whitelist = ParseList<sint32>(parser, rules, \"formats\");\n\t\t\t\trule.filter_settings.format_blacklist = ParseList<sint32>(parser, rules, \"formatsExcluded\");\n\t\t\t\trule.filter_settings.tilemode_whitelist = ParseList<sint32>(parser, rules, \"tilemodes\");\n\t\t\t\trule.filter_settings.tilemode_blacklist = ParseList<sint32>(parser, rules, \"tilemodesExcluded\");\n\n\t\t\t\tParseRule(parser, rules, \"overwriteWidth\", &rule.overwrite_settings.width);\n\t\t\t\tParseRule(parser, rules, \"overwriteHeight\", &rule.overwrite_settings.height);\n\t\t\t\tParseRule(parser, rules, \"overwriteDepth\", &rule.overwrite_settings.depth);\n\t\t\t\tParseRule(parser, rules, \"overwriteFormat\", &rule.overwrite_settings.format);\n\n\t\t\t\tfloat lod_bias;\n\t\t\t\tif(ParseRule(parser, rules, \"overwriteLodBias\", &lod_bias))\n\t\t\t\t\trule.overwrite_settings.lod_bias = (sint32)(lod_bias * 64.0f);\n\n\t\t\t\tif(ParseRule(parser, rules, \"overwriteRelativeLodBias\", &lod_bias))\n\t\t\t\t\trule.overwrite_settings.relative_lod_bias = (sint32)(lod_bias * 64.0f);\n\n\t\t\t\tsint32 anisotropyValue;\n\t\t\t\tif (ParseRule(parser, rules, \"overwriteAnisotropy\", &anisotropyValue))\n\t\t\t\t{\n\t\t\t\t\tif (anisotropyValue == 1)\n\t\t\t\t\t\trule.overwrite_settings.anistropic_value = 0;\n\t\t\t\t\telse if (anisotropyValue == 2)\n\t\t\t\t\t\trule.overwrite_settings.anistropic_value = 1;\n\t\t\t\t\telse if (anisotropyValue == 4)\n\t\t\t\t\t\trule.overwrite_settings.anistropic_value = 2;\n\t\t\t\t\telse if (anisotropyValue == 8)\n\t\t\t\t\t\trule.overwrite_settings.anistropic_value = 3;\n\t\t\t\t\telse if (anisotropyValue == 16)\n\t\t\t\t\t\trule.overwrite_settings.anistropic_value = 4;\n\t\t\t\t\telse\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"Invalid value {} for overwriteAnisotropy in graphic pack {}. Only the values 1, 2, 4, 8 or 16 are allowed.\", anisotropyValue, GetNormalizedPathString());\n\t\t\t\t}\n\t\t\t\tm_texture_rules.emplace_back(rule);\n\t\t\t}\n\t\t\telse if (boost::iequals(category_name, \"Control\"))\n\t\t\t{\n\t\t\t\tParseRule(parser, rules, \"vsyncFrequency\", &m_vsync_frequency);\n\t\t\t}\n\t\t\telse if (boost::iequals(category_name, \"OutputShader\"))\n\t\t\t{\n\t\t\t\tauto option_upscale = rules.FindOption(\"upscaleMagFilter\");\n\t\t\t\tif(option_upscale && boost::iequals(*option_upscale, \"NearestNeighbor\"))\n\t\t\t\t\tm_output_settings.upscale_filter = LatteTextureView::MagFilter::kNearestNeighbor;\n\t\t\t\tauto option_downscale = rules.FindOption(\"downscaleMinFilter\");\n\t\t\t\tif (option_downscale && boost::iequals(*option_downscale, \"NearestNeighbor\"))\n\t\t\t\t\tm_output_settings.downscale_filter = LatteTextureView::MagFilter::kNearestNeighbor;\n\t\t\t}\n\t\t}\n\t}\n\tcatch(const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, ex.what());\n\t\treturn false;\n\t}\n\n\t// load shaders\n\tLoadShaders();\n\n\t// load patches\n\tLoadPatchFiles();\n\n\t// enable patch groups\n\tEnablePatches();\n\n\t// load replaced files\n\tLoadReplacedFiles();\n\n\t// set custom vsync\n\tif (HasCustomVSyncFrequency())\n\t{\n\t\tsint32 customVsyncFreq = GetCustomVSyncFrequency();\n\t\tsint32 globalCustomVsyncFreq = 0;\n\t\tif (LatteTiming_getCustomVsyncFrequency(globalCustomVsyncFreq))\n\t\t{\n\t\t\tif (customVsyncFreq != globalCustomVsyncFreq)\n\t\t\t\tcemuLog_log(LogType::Force, \"rules.txt error: Mismatching vsync frequency {} in graphic pack \\'{}\\'\", customVsyncFreq, GetVirtualPath());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Set vsync frequency to {} (graphic pack {})\", customVsyncFreq, GetVirtualPath());\n\t\t\tLatteTiming_setCustomVsyncFrequency(customVsyncFreq);\n\t\t}\n\t}\n\tm_activated = true;\n\treturn true;\n}\n\nbool GraphicPack2::Deactivate()\n{\n\tif (!m_activated)\n\t\treturn false;\n\n\tUnloadPatches();\n\n\tm_activated = false;\n\tm_custom_shaders.clear();\n\tm_texture_rules.clear();\n\n\tm_output_shader.reset();\n\tm_upscaling_shader.reset();\n\tm_downscaling_shader.reset();\n\n\tm_output_shader_ud.reset();\n\tm_upscaling_shader_ud.reset();\n\tm_downscaling_shader_ud.reset();\n\n\tm_output_shader_source.clear();\n\tm_upscaling_shader_source.clear();\n\tm_downscaling_shader_source.clear();\n\n\tif (HasCustomVSyncFrequency())\n\t{\n\t\tm_vsync_frequency = -1;\n\n\t\tLatteTiming_disableCustomVsyncFrequency();\n\t}\n\n\treturn true;\n}\n\nconst std::string* GraphicPack2::FindCustomShaderSource(uint64 shaderBaseHash, uint64 shaderAuxHash, GP_SHADER_TYPE type, bool isVulkanRenderer, bool isMetalRenderer)\n{\n\tfor (const auto& gp : GraphicPack2::GetActiveGraphicPacks())\n\t{\n\t\tconst auto it = std::find_if(gp->m_custom_shaders.begin(), gp->m_custom_shaders.end(),\n\t\t\t[shaderBaseHash, shaderAuxHash, type](const auto& s) { return s.shader_base_hash == shaderBaseHash && s.shader_aux_hash == shaderAuxHash && s.type == type; });\n\n\t\tif (it == gp->m_custom_shaders.end())\n\t\t\tcontinue;\n\n\t\tif (isVulkanRenderer && (*it).isPreVulkanShader)\n\t\t\tcontinue;\n\n\t\tif (isMetalRenderer != (*it).isMetalShader)\n\t\t    continue;\n\n\t\treturn &it->source;\n\t}\n\treturn nullptr;\n}\n\nstd::unordered_map<std::string, std::vector<GraphicPack2::PresetPtr>> GraphicPack2::GetCategorizedPresets(std::vector<std::string>& order) const\n{\n\torder.clear();\n\n\tstd::unordered_map<std::string, std::vector<PresetPtr>> result;\n\tfor(const auto& entry : m_presets)\n\t{\n\t\tresult[entry->category].emplace_back(entry);\n\t\tconst auto it = std::find(order.cbegin(), order.cend(), entry->category);\n\t\tif (it == order.cend())\n\t\t\torder.emplace_back(entry->category);\n\t}\n\n\treturn result;\n}\n\nbool GraphicPack2::HasShaders() const\n{\n\treturn !GetCustomShaders().empty()\n\t|| !m_output_shader_source.empty() || !m_upscaling_shader_source.empty() || !m_downscaling_shader_source.empty();\n}\n\nRendererOutputShader* GraphicPack2::GetOuputShader(bool render_upside_down)\n{\n\tif(render_upside_down)\n\t{\n\t\tif (m_output_shader_ud)\n\t\t\treturn m_output_shader_ud.get();\n\n\t\tif (!m_output_shader_source.empty())\n\t\t\tm_output_shader_ud = std::make_unique<RendererOutputShader>(RendererOutputShader::GetOpenGlVertexSource(render_upside_down), m_output_shader_source);\n\n\t\treturn m_output_shader_ud.get();\n\t}\n\telse\n\t{\n\t\tif (m_output_shader)\n\t\t\treturn m_output_shader.get();\n\n\t\tif (!m_output_shader_source.empty())\n\t\t\tm_output_shader = std::make_unique<RendererOutputShader>(RendererOutputShader::GetOpenGlVertexSource(render_upside_down), m_output_shader_source);\n\n\t\treturn m_output_shader.get();\n\t}\n}\n\nRendererOutputShader* GraphicPack2::GetUpscalingShader(bool render_upside_down)\n{\n\tif (render_upside_down)\n\t{\n\t\tif (m_upscaling_shader_ud)\n\t\t\treturn m_upscaling_shader_ud.get();\n\n\t\tif (!m_upscaling_shader_source.empty())\n\t\t\tm_upscaling_shader_ud = std::make_unique<RendererOutputShader>(RendererOutputShader::GetOpenGlVertexSource(render_upside_down), m_upscaling_shader_source);\n\n\t\treturn m_upscaling_shader_ud.get();\n\t}\n\telse\n\t{\n\t\tif (m_upscaling_shader)\n\t\t\treturn m_upscaling_shader.get();\n\n\t\tif (!m_upscaling_shader_source.empty())\n\t\t\tm_upscaling_shader = std::make_unique<RendererOutputShader>(RendererOutputShader::GetOpenGlVertexSource(render_upside_down), m_upscaling_shader_source);\n\n\t\treturn m_upscaling_shader.get();\n\t}\n}\n\nRendererOutputShader* GraphicPack2::GetDownscalingShader(bool render_upside_down)\n{\n\tif (render_upside_down)\n\t{\n\t\tif (m_downscaling_shader_ud)\n\t\t\treturn m_downscaling_shader_ud.get();\n\n\t\tif (!m_downscaling_shader_source.empty())\n\t\t\tm_downscaling_shader_ud = std::make_unique<RendererOutputShader>(RendererOutputShader::GetOpenGlVertexSource(render_upside_down), m_downscaling_shader_source);\n\n\t\treturn m_downscaling_shader_ud.get();\n\t}\n\telse\n\t{\n\t\tif (m_downscaling_shader)\n\t\t\treturn m_downscaling_shader.get();\n\n\t\tif (!m_downscaling_shader_source.empty())\n\t\t\tm_downscaling_shader = std::make_unique<RendererOutputShader>(RendererOutputShader::GetOpenGlVertexSource(render_upside_down), m_downscaling_shader_source);\n\n\t\treturn m_downscaling_shader.get();\n\t}\n}\n\n\nstd::vector<GraphicPack2::PresetPtr> GraphicPack2::GetActivePresets() const\n{\n\tstd::vector<PresetPtr> result;\n\tresult.reserve(m_presets.size());\n\tstd::copy_if(m_presets.cbegin(), m_presets.cend(), std::back_inserter(result), [](const PresetPtr& p) { return p->active; });\n\treturn result;\n}\n\nstd::vector<uint64> GraphicPack2::ParseTitleIds(IniParser& rules, const char* option_name)\n{\n\tstd::vector<uint64> result;\n\n\tauto option_text = rules.FindOption(option_name);\n\tif (!option_text)\n\t\treturn result;\n\n\tif (*option_text == \"*\")\n\t{\n\t\tm_universal = true;\n\t\treturn result;\n\t}\n\n\tfor (auto& token : TokenizeView(*option_text, ','))\n\t{\n\t\ttry\n\t\t{\n\t\t\tresult.emplace_back(ConvertString<uint64>(token, 16));\n\t\t}\n\t\tcatch (const std::invalid_argument&) {}\n\t}\n\n\treturn result;\n}\n\nvoid GraphicPack2::ApplyShaderPresets(std::string& shader_source) const\n{\n\tconst auto active_presets = GetActivePresets();\n\tconst std::regex regex(R\"(\\$[a-zA-Z_0-9]+)\");\n\n\tstd::smatch match;\n\tsize_t offset = 0;\n\twhile (std::regex_search(shader_source.cbegin() + offset, shader_source.cend(), match, regex))\n\t{\n\t\tif (active_presets.empty())\n\t\t\tthrow std::runtime_error(\"found variable in shader but no preset is active\");\n\n\t\tconst auto str = match.str();\n\n\t\tstd::optional<PresetVar> var = GetPresetVariable(active_presets, str);\n\t\tif(!var)\n\t\t\tthrow std::runtime_error(\"using an unknown preset variable in shader\");\n\n\t\tstd::string new_value;\n\t\tif (var->first == kInt)\n\t\t\tnew_value = fmt::format(\"{}\", (int)var->second);\n\t\telse\n\t\t\tnew_value = fmt::format(\"{:f}\", var->second);\n\n\t\tshader_source.replace(match.position() + offset, match.length(), new_value);\n\t\toffset += match.position() + new_value.length();\n\t}\n}\n\nGraphicPack2::CustomShader GraphicPack2::LoadShader(const fs::path& path, uint64 shader_base_hash, uint64 shader_aux_hash, GP_SHADER_TYPE shader_type, bool isMetalShader) const\n{\n\tCustomShader shader;\n\n\tstd::ifstream file(path);\n\tif (!file.is_open())\n\t\tthrow std::runtime_error(\"can't open shader file\");\n\n\tfile.seekg(0, std::ios::end);\n\tshader.source.reserve(file.tellg());\n\tfile.seekg(0, std::ios::beg);\n\n\tshader.source.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());\n\tApplyShaderPresets(shader.source);\n\n\tshader.shader_base_hash = shader_base_hash;\n\tshader.shader_aux_hash = shader_aux_hash;\n\tshader.type = shader_type;\n\tshader.isPreVulkanShader = this->m_version <= 3;\n\tshader.isMetalShader = isMetalShader;\n\n\treturn shader;\n}\n\nstd::vector<std::pair<MPTR, MPTR>> GraphicPack2::GetActiveRAMMappings()\n{\n\tuint64 currentTitleId = CafeSystem::GetForegroundTitleId();\n\tstd::vector<std::pair<MPTR, MPTR>> v;\n\tfor (const auto& gp : GraphicPack2::GetGraphicPacks())\n\t{\n\t\tif (!gp->IsEnabled())\n\t\t\tcontinue;\n\t\tif (!gp->ContainsTitleId(currentTitleId))\n\t\t\tcontinue;\n\t\tif (!gp->m_ramMappings.empty())\n\t\t\tv.insert(v.end(), gp->m_ramMappings.begin(), gp->m_ramMappings.end());\n\t}\n\tstd::sort(v.begin(), v.end(),\n\t\t[](const std::pair<MPTR, MPTR>& a, const std::pair<MPTR, MPTR>& b) -> bool\n\t\t{\n\t\t\treturn a.first < b.first;\n\t\t});\n\treturn v;\n}\n"
  },
  {
    "path": "src/Cafe/GraphicPack/GraphicPack2.h",
    "content": "#pragma once\n\n#include \"util/helpers/helpers.h\"\n#include \"Cemu/ExpressionParser/ExpressionParser.h\"\n#include \"Cafe/HW/Latte/Renderer/RendererOuputShader.h\"\n#include \"util/helpers/Serializer.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cemu/PPCAssembler/ppcAssembler.h\"\n#include <variant>\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"GraphicPack2Patches.h\"\n#include \"util/IniParser/IniParser.h\"\n\nclass GraphicPack2\n{\npublic:\n\tenum class GP_SHADER_TYPE : uint8\n\t{\n\t\tPIXEL = 0,\n\t\tVERTEX = 1,\n\t\tGEOMETRY = 2,\n\t};\n\n\tenum\n\t{\n\t\tGFXPACK_VERSION_5 = 5,\n\t\tGFXPACK_VERSION_6 = 6, // added memory extensions\n\t\tGFXPACK_VERSION_7 = 7, // added fine-grained origin control in patch format (no more forced 4 byte alignment), .string directive (an alias to .byte) and support for more than one constant per data directive\n\t};\n\n\tstruct TextureRule\n\t{\n\t\t// filter (texture must match these settings)\n\t\tstruct FILTER_SETTINGS\n\t\t{\n\t\t\tenum class MEM1_FILTER {\n\t\t\t\tBOTH,\n\t\t\t\tINSIDE,\n\t\t\t\tOUTSIDE,\n\t\t\t};\n\t\t\tsint32 width = -1;\n\t\t\tsint32 height = -1;\n\t\t\tsint32 depth = -1;\n\t\t\tMEM1_FILTER inMEM1 = MEM1_FILTER::BOTH;\n\t\t\tstd::vector<sint32> format_whitelist{};\n\t\t\tstd::vector<sint32> format_blacklist{};\n\t\t\tstd::vector<sint32> tilemode_whitelist{};\n\t\t\tstd::vector<sint32> tilemode_blacklist{};\n\t\t} filter_settings;\n\t\t// overwrite (if match found, these settings are overwritten)\n\t\tstruct OVERWRITE_SETTINGS\n\t\t{\n\t\t\tsint32 width = -1;\n\t\t\tsint32 height = -1;\n\t\t\tsint32 depth = -1;\n\t\t\tsint32 format = -1;\n\t\t\tsint32 lod_bias = -1; // in 1/64th steps\n\t\t\tsint32 relative_lod_bias = -1; // in 1/64th steps\n\t\t\tsint32 anistropic_value = -1; // 1<<n\n\t\t} overwrite_settings;\n\t};\n\n\tstruct CustomShader\n\t{\n\t\tstd::string source;\n\t\tuint64 shader_base_hash;\n\t\tuint64 shader_aux_hash;\n\t\tGP_SHADER_TYPE type;\n\t\tbool isPreVulkanShader{}; // set to true for V3 packs since the shaders are not compatible with the Vulkan renderer\n\t\tbool isMetalShader{}; // set to true if the shader is written in Metal Shading Language\n\t};\n\n\tenum VarType\n\t{\n\t\tkDouble = 0,\n\t\tkInt = 1,\n\t};\n\tusing PresetVar = std::pair<VarType, double>;\n\n\tstruct Preset\n\t{\n\t\tstd::string category; // preset category (empty for default)\n\t\tstd::string name; // displayed name\n\t\tstd::string condition;\n\t\tstd::unordered_map<std::string, PresetVar> variables;\n\t\tbool active = false; // selected/active preset\n\t\tbool visible = true; // set by condition or true\n\t\tbool is_default = false; // selected by default\n\n\t\tPreset(std::string_view name, std::unordered_map<std::string, PresetVar> vars)\n\t\t\t: name(name), variables(std::move(vars)) {}\n\n\t\tPreset(std::string_view category, std::string_view name, std::unordered_map<std::string, PresetVar> vars)\n\t\t\t: category(category), name(name), variables(std::move(vars)) {}\n\n\t\tPreset(std::string_view category, std::string_view name, std::string_view condition, std::unordered_map<std::string, PresetVar> vars)\n\t\t\t: category(category), name(name), condition(condition), variables(std::move(vars)) {}\n\t};\n\tusing PresetPtr = std::shared_ptr<Preset>;\n\n\tGraphicPack2(fs::path rulesPath, IniParser& rules);\n\n\tbool IsEnabled() const { return m_enabled; }\n\tbool IsActivated() const { return m_activated; }\n\tsint32 GetVersion() const { return m_version; }\n\tconst fs::path GetRulesPath() const { return m_rulesPath; }\n\tstd::string GetNormalizedPathString() const;\n\tbool RequiresRestart(bool changeEnableState, bool changePreset);\n\tbool Reload();\n\n\tbool HasName() const { return !m_name.empty();  }\n\tbool IsUniversal() const { return m_universal; }\n\n\tconst std::string& GetName() const { return m_name.empty() ? m_virtualPath : m_name; }\n\tconst std::string& GetVirtualPath() const { return m_virtualPath; } // returns the path in the gfx tree hierarchy\n\tconst std::string& GetDescription() const { return m_description; }\n\tbool IsDefaultEnabled() const {\treturn m_default_enabled; }\n\tbool AllowRendertargetSizeOptimization() const { return m_allowRendertargetSizeOptimization; }\n\n\tvoid SetEnabled(bool state) { m_enabled = state; }\n\n\tbool ContainsTitleId(uint64_t title_id) const;\n\tconst std::vector<uint64_t>& GetTitleIds() const { return m_title_ids; }\n\tbool HasCustomVSyncFrequency() const { return m_vsync_frequency >= 1; }\n\tsint32 GetCustomVSyncFrequency() const { return m_vsync_frequency; }\n\t\n\tconst std::vector<std::pair<MPTR, GPCallbackType>>& GetCallbacks() const { return m_callbacks; }\n\n\t// texture rules\n\tconst std::vector<TextureRule>& GetTextureRules() const { return m_texture_rules; }\n\n\t// presets\n\t[[nodiscard]] bool HasActivePreset() const;\n\t[[nodiscard]] std::string GetActivePreset(std::string_view category = \"\") const;\n\t[[nodiscard]] std::vector<PresetPtr> GetActivePresets() const;\n\t[[nodiscard]] bool IsPresetVisible(const PresetPtr& preset) const;\n\t[[nodiscard]] std::optional<PresetVar> GetPresetVariable(const std::vector<PresetPtr>& presets, std::string_view var_name) const;\n\n\tvoid ValidatePresetSelections();\n\tbool SetActivePreset(std::string_view category, std::string_view name, bool update_visibility = true);\n\tbool SetActivePreset(std::string_view name);\n\tvoid UpdatePresetVisibility();\n\n\tvoid AddConstantsForCurrentPreset(ExpressionParser& ep);\n\tbool ResolvePresetConstant(const std::string& varname, double& value) const;\n\n\t[[nodiscard]] const std::vector<PresetPtr>& GetPresets() const { return m_presets; }\n\t[[nodiscard]] std::unordered_map<std::string, std::vector<PresetPtr>> GetCategorizedPresets(std::vector<std::string>& order) const;\n\n\t// shaders\n\tvoid LoadShaders();\n\tbool HasShaders() const;\n\tconst std::vector<CustomShader>& GetCustomShaders() const { return m_custom_shaders; }\n\n\tstatic const std::string* FindCustomShaderSource(uint64 shaderBaseHash, uint64 shaderAuxHash, GP_SHADER_TYPE type, bool isVulkanRenderer, bool isMetalRenderer);\n\n\tconst std::string& GetOutputShaderSource() const { return m_output_shader_source; }\n\tconst std::string& GetDownscalingShaderSource() const { return m_downscaling_shader_source; }\n\tconst std::string& GetUpscalingShaderSource() const { return m_upscaling_shader_source; }\n\tRendererOutputShader* GetOuputShader(bool render_upside_down);\n\tRendererOutputShader* GetUpscalingShader(bool render_upside_down);\n\tRendererOutputShader* GetDownscalingShader(bool render_upside_down);\n\tLatteTextureView::MagFilter GetUpscalingMagFilter() const { return m_output_settings.upscale_filter; }\n\tLatteTextureView::MagFilter GetDownscalingMagFilter() const { return m_output_settings.downscale_filter; }\n\n\t// static methods\n\tstatic void LoadAll();\n\n\tstatic const std::vector<std::shared_ptr<GraphicPack2>>& GetGraphicPacks() { return s_graphic_packs; }\n\tstatic const std::vector<std::shared_ptr<GraphicPack2>>& GetActiveGraphicPacks() { return s_active_graphic_packs; }\n\tstatic void LoadGraphicPack(fs::path graphicPackPath);\n\tstatic bool LoadGraphicPack(const fs::path& rulesPath, class IniParser& rules);\n\tstatic bool ActivateGraphicPack(const std::shared_ptr<GraphicPack2>& graphic_pack);\n\tstatic bool DeactivateGraphicPack(const std::shared_ptr<GraphicPack2>& graphic_pack);\n\tstatic void ClearGraphicPacks();\n\tstatic void WaitUntilReady(); // wait until all graphic packs finished activation\n\n\tstatic void ActivateForCurrentTitle();\n\tstatic void Reset();\n\nprivate:\n\tbool Activate();\n\tbool Deactivate();\n\n\tstatic std::vector<std::shared_ptr<GraphicPack2>> s_graphic_packs;\n\tstatic std::vector<std::shared_ptr<GraphicPack2>> s_active_graphic_packs;\n\tstatic std::atomic_bool s_isReady;\n\n\ttemplate<typename TType>\n\tvoid FillPresetConstants(TExpressionParser<TType>& parser) const\n\t{\n\t\t// fils preset variables with priority\n\t\t// active && visible > active > default\n\t\tconst auto active_presets = GetActivePresets();\n\t\tfor(const auto& preset : active_presets)\n\t\t{\n\t\t\tif(preset->visible)\n\t\t\t{\n\t\t\t\tfor (auto& var : preset->variables)\n\t\t\t\t\tparser.AddConstant(var.first, (TType)var.second.second);\n\t\t\t}\n\t\t}\n\t\tfor(const auto& preset : active_presets)\n\t\t{\n\t\t\tif(!preset->visible)\n\t\t\t{\n\t\t\t\tfor (auto& var : preset->variables)\n\t\t\t\t\tparser.TryAddConstant(var.first, (TType)var.second.second);\n\t\t\t}\n\t\t}\n\n\t\tfor (auto& var : m_preset_vars)\n\t\t\tparser.TryAddConstant(var.first, (TType)var.second.second);\n\t}\n\n\tfs::path m_rulesPath;\n\n\tsint32 m_version;\n\tstd::string m_name;\n\tstd::string m_virtualPath;\n\tstd::string m_description;\n\n\tbool m_default_enabled = false;\n\n\tbool m_allowRendertargetSizeOptimization = false; // gfx pack supports framebuffers with non-padded sizes, which is an optional optimization introduced with Cemu 2.0-74\n\n\t// filter\n\tstd::optional<RendererAPI> m_renderer_api;\n\tstd::optional<GfxVendor> m_gfx_vendor;\n\n\tbool m_enabled = false;\n\tbool m_activated = false; // set if the graphic pack is currently used by the running game\n\tstd::vector<uint64_t> m_title_ids;\n\tbool m_patchedFilesLoaded = false; // set to true once patched files are loaded\n\tbool m_universal = false; // set if this pack applies to every title id\n\n\tsint32 m_vsync_frequency = -1;\n\tsint32 m_fs_priority = 100;\n\n\tstruct\n\t{\n\t\tLatteTextureView::MagFilter upscale_filter = LatteTextureView::MagFilter::kLinear;\n\t\tLatteTextureView::MagFilter downscale_filter = LatteTextureView::MagFilter::kLinear;\n\t} m_output_settings;\n\n\tstd::vector<PresetPtr> m_presets;\n\t// default preset vars\n\tstd::unordered_map<std::string, PresetVar> m_preset_vars;\n\n\tstd::vector<CustomShader> m_custom_shaders;\n\tstd::vector<TextureRule> m_texture_rules;\n\tstd::string m_output_shader_source, m_upscaling_shader_source, m_downscaling_shader_source;\n\tstd::unique_ptr<RendererOutputShader> m_output_shader, m_upscaling_shader, m_downscaling_shader, m_output_shader_ud, m_upscaling_shader_ud, m_downscaling_shader_ud;\n\n\ttemplate<typename T>\n\tbool ParseRule(const ExpressionParser& parser, IniParser& iniParser, const char* option_name, T* value_out) const;\n\n\ttemplate<typename T>\n\tstd::vector<T> ParseList(const ExpressionParser& parser, IniParser& iniParser, const char* option_name) const;\n\n\tstd::unordered_map<std::string, PresetVar> ParsePresetVars(IniParser& rules) const;\n\n\tstd::vector<uint64> ParseTitleIds(IniParser& rules, const char* option_name);\n\n\tCustomShader LoadShader(const fs::path& path, uint64 shader_base_hash, uint64 shader_aux_hash, GP_SHADER_TYPE shader_type, bool isMetalShader) const;\n\tvoid ApplyShaderPresets(std::string& shader_source) const;\n\tvoid LoadReplacedFiles();\n\tvoid _iterateReplacedFiles(const fs::path& currentPath, bool isAOC, const char* virtualMountBase);\n\n\t// ram mappings\n\tstd::vector<std::pair<MPTR, MPTR>> m_ramMappings;\n\n\t// patches\n\tvoid LoadPatchFiles(); // loads Cemuhook or Cemu patches\n\tbool LoadCemuPatches();\n\n\tvoid ParseCemuhookPatchesTxtInternal(MemStreamReader& patchesStream);\n\tbool ParseCemuPatchesTxtInternal(MemStreamReader& patchesStream);\n\tvoid CancelParsingPatches();\n\n\tvoid ApplyPatchGroups(std::vector<PatchGroup*>& groups, const RPLModule* rpl);\n\tvoid UndoPatchGroups(std::vector<PatchGroup*>& groups, const RPLModule* rpl);\n\n\tvoid AddPatchGroup(PatchGroup* group);\n\tsint32 GetLengthWithoutComment(const char* str, size_t length);\n\tvoid LogPatchesSyntaxError(sint32 lineNumber, std::string_view errorMsg);\n\n\tstd::vector<PatchGroup*> list_patchGroups;\n\t\n\tstd::vector<std::pair<MPTR, GPCallbackType>> m_callbacks;\n\n\tstatic std::recursive_mutex mtx_patches;\n\tstatic std::vector<const RPLModule*> list_modules;\n\npublic:\n\tstatic std::vector<std::pair<MPTR, MPTR>> GetActiveRAMMappings();\n\tvoid EnablePatches();\n\tvoid UnloadPatches();\n\tbool HasPatches();\n\tconst std::vector<PatchGroup*>& GetPatchGroups();\n\tvoid ApplyPatchesForModule(const RPLModule* rpl);\n\tvoid RevertPatchesForModule(const RPLModule* rpl);\n\n\tstatic void NotifyModuleLoaded(const RPLModule* rpl);\n\tstatic void NotifyModuleUnloaded(const RPLModule* rpl);\n};\n\nusing GraphicPackPtr = std::shared_ptr<GraphicPack2>;\n\ntemplate <typename T>\nbool GraphicPack2::ParseRule(const ExpressionParser& parser, IniParser& iniParser, const char* option_name, T* value_out) const\n{\n\tauto option_value = iniParser.FindOption(option_name);\n\tif (option_value)\n\t{\n\t\t*value_out = parser.Evaluate<T>(*option_value);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\ntemplate <typename T>\nstd::vector<T> GraphicPack2::ParseList(const ExpressionParser& parser, IniParser& iniParser, const char* option_name) const\n{\n\tstd::vector<T> result;\n\n\tauto option_text = iniParser.FindOption(option_name);\n\tif (!option_text)\n\t\treturn result;\n\n\tfor(auto& token : Tokenize(*option_text, ','))\n\t{\n\t\ttry\n\t\t{\n\t\t\tresult.emplace_back(parser.Evaluate<T>(token));\n\t\t}\n\t\tcatch (const std::invalid_argument&) {}\n\t}\n\n\treturn result;\n}\n"
  },
  {
    "path": "src/Cafe/GraphicPack/GraphicPack2Patches.cpp",
    "content": "#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"Cemu/Logging/CemuLogging.h\"\n#include \"Common/FileStream.h\"\n#include \"WindowSystem.h\"\n#include \"util/helpers/StringParser.h\"\n#include \"Cemu/PPCAssembler/ppcAssembler.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n#include \"boost/algorithm/string.hpp\"\n\n// error handler\nvoid PatchErrorHandler::printError(class PatchGroup* patchGroup, sint32 lineNumber, std::string_view errorMsg)\n{\n\tif (m_anyErrorTriggered == false)\n\t{\n\t\t// stage error msg\n\t\tcemu_assert(m_gp);\n\t\tif (m_stage == STAGE::PARSER)\n\t\t\tcemuLog_writeLineToLog(fmt::format(\"An error occurred while trying to parse the patches for graphic pack \\'{}\\'\", m_gp->GetName()), true, true);\n\t\telse if (m_stage == STAGE::APPLY)\n\t\t\tcemuLog_writeLineToLog(fmt::format(\"An error occurred while trying to apply the patches for graphic pack \\'{}\\'\", m_gp->GetName()), true, true);\n\t}\n\n\tstd::string msg;\n\tif (patchGroup == nullptr && lineNumber >= 0)\n\t\tmsg.append(fmt::format(\"[Line {}] \", lineNumber));\n\telse if (patchGroup && lineNumber >= 0)\n\t\tmsg.append(fmt::format(\"[{}, Line {}] \", patchGroup->getName(), lineNumber));\n\telse if (patchGroup && lineNumber < 0)\n\t\tmsg.append(fmt::format(\"[{}] \", patchGroup->getName()));\n\n\tmsg.append(errorMsg);\n\n\tcemuLog_writeLineToLog(msg, true, true);\n\tm_anyErrorTriggered = true;\n\n\tif (cemuLog_isLoggingEnabled(LogType::Patches))\n\t\terrorMessages.emplace_back(msg);\n}\n\nvoid PatchErrorHandler::showStageErrorMessageBox()\n{\n\tstd::string errorMsg;\n\tif (m_gp)\n\t{\n\t\tif (m_stage == STAGE::PARSER)\n\t\t\terrorMsg.assign(_tr(\"Failed to load patches for graphic pack \\'{}\\'\", m_gp->GetName()));\n\t\telse\n\t\t\terrorMsg.assign(_tr(\"Failed to apply patches for graphic pack \\'{}\\'\", m_gp->GetName()));\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false); // graphic pack should always be set\n\t}\n\tif (cemuLog_isLoggingEnabled(LogType::Patches))\n\t{\n\t\terrorMsg.append(\"\\n \\n\")\n\t\t\t.append(_tr(\"Details:\"))\n\t\t\t.append(\"\\n\");\n\t\tfor (auto& itr : errorMessages)\n\t\t{\n\t\t\terrorMsg.append(itr);\n\t\t\terrorMsg.append(\"\\n\");\n\t\t}\n\t}\n\n\tWindowSystem::ShowErrorDialog(errorMsg, _tr(\"Graphic pack error\"), WindowSystem::ErrorCategory::GRAPHIC_PACKS);\n}\n\n// loads Cemu-style patches (patch_<anything>.asm)\n// returns true if at least one file was found even if it could not be successfully parsed\nbool GraphicPack2::LoadCemuPatches()\n{\n\tbool foundPatches = false;\n\tfs::path path(m_rulesPath);\n\tpath.remove_filename();\n\tfor (auto& p : fs::directory_iterator(path))\n\t{\n\t\tauto& path = p.path();\n\t\tif (fs::is_regular_file(p.status()) && path.has_filename())\n\t\t{\n\t\t\t// check if filename matches\n\t\t\tstd::string filename = _pathToUtf8(path.filename());\n\t\t\tif (boost::istarts_with(filename, \"patch_\") && boost::iends_with(filename, \".asm\"))\n\t\t\t{\n\t\t\t\tFileStream* patchFile = FileStream::openFile2(path);\n\t\t\t\tif (patchFile)\n\t\t\t\t{\n\t\t\t\t\t// read file\n\t\t\t\t\tstd::vector<uint8> fileData;\n\t\t\t\t\tpatchFile->extract(fileData);\n\t\t\t\t\tdelete patchFile;\n\t\t\t\t\tMemStreamReader patchesStream(fileData.data(), (sint32)fileData.size());\n\t\t\t\t\t// load Cemu style patch file\n\t\t\t\t\tif (!ParseCemuPatchesTxtInternal(patchesStream))\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"Error while processing \\\"{}\\\". No patches for this graphic pack will be applied.\", _pathToUtf8(path));\n\t\t\t\t\t\tcemu_assert_debug(list_patchGroups.empty());\n\t\t\t\t\t\treturn true; // return true since a .asm patch was found even if we could not parse it\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Unable to load patch file \\\"{}\\\"\", _pathToUtf8(path));\n\t\t\t\t}\n\t\t\t\tfoundPatches = true;\n\t\t\t}\n\t\t}\n\t}\n\treturn foundPatches;\n}\n\nvoid GraphicPack2::LoadPatchFiles()\n{\n\t// order of loading patches:\n\t// 1) Load Cemu-style patches (patch_<name>.asm), stop here if at least one patch file exists\n\t// 2) Load Cemuhook patches.txt\n\tif (LoadCemuPatches())\n\t\treturn; // exit if at least one Cemu style patch file was found\n\t// fall back to Cemuhook patches.txt to guarantee backward compatibility\n\tfs::path path(m_rulesPath);\n\tpath.remove_filename();\n\tpath.append(\"patches.txt\");\n\tFileStream* patchFile = FileStream::openFile2(path);\n\tif (patchFile == nullptr)\n\t\treturn;\n\t// read file\n\tstd::vector<uint8> fileData;\n\tpatchFile->extract(fileData);\n\tdelete patchFile;\n\tcemu_assert_debug(list_patchGroups.empty());\n\t// parse\n\tMemStreamReader patchesStream(fileData.data(), (sint32)fileData.size());\n\tParseCemuhookPatchesTxtInternal(patchesStream);\n}\n\nvoid GraphicPack2::EnablePatches()\n{\n\tstd::lock_guard<std::recursive_mutex> lock(mtx_patches);\n\tfor (auto& itr : list_modules)\n\t\tApplyPatchesForModule(itr);\n}\n\nvoid GraphicPack2::UnloadPatches()\n{\n\tif (list_patchGroups.empty())\n\t\treturn;\n\tstd::lock_guard<std::recursive_mutex> lock(mtx_patches);\n\t// if any patch groups were applied then revert here\n\t// do this by calling RevertPatchesForModule for every module?\n\tfor (auto& itr : list_modules)\n\t\tRevertPatchesForModule(itr);\n\t// delete all patches\n\tfor (auto itr : list_patchGroups)\n\t\tdelete itr;\n\tlist_patchGroups.clear();\n}\n\nbool GraphicPack2::HasPatches()\n{\n\treturn !list_patchGroups.empty();\n}\n\nconst std::vector<PatchGroup*>& GraphicPack2::GetPatchGroups() {\n\treturn list_patchGroups;\n}\n\nvoid GraphicPack2::ApplyPatchesForModule(const RPLModule* rpl)\n{\n\tif (list_patchGroups.empty())\n\t\treturn;\n\t// gather list of all patch groups that apply to this module\n\tstd::vector<PatchGroup*> list_groups;\n\tfor (auto itr : list_patchGroups)\n\t{\n\t\tif (itr->matchesCRC(rpl->patchCRC) || (itr->m_isRpxOnlyTarget && rpl->IsRPX()))\n\t\t\tlist_groups.emplace_back(itr);\n\t}\n\t// apply all groups at once\n\tif (!list_groups.empty())\n\t\tApplyPatchGroups(list_groups, rpl);\n}\n\nvoid GraphicPack2::RevertPatchesForModule(const RPLModule* rpl)\n{\n\tif (list_patchGroups.empty())\n\t\treturn;\n\t// gather list of all patch groups that apply to this module\n\tstd::vector<PatchGroup*> list_groups;\n\tfor (auto itr : list_patchGroups)\n\t{\n\t\tif (itr->matchesCRC(rpl->patchCRC) || (itr->m_isRpxOnlyTarget && rpl->IsRPX()))\n\t\t\tlist_groups.emplace_back(itr);\n\t}\n\t// undo all groups at once\n\tif (!list_groups.empty())\n\t\tUndoPatchGroups(list_groups, rpl);\n}\n\nstd::recursive_mutex GraphicPack2::mtx_patches;\nstd::vector<const RPLModule*> GraphicPack2::list_modules;\n"
  },
  {
    "path": "src/Cafe/GraphicPack/GraphicPack2Patches.h",
    "content": "#pragma once\n\nclass PatchGroup;\n\n#include \"GraphicPackError.h\"\n\nstruct PatchContext_t\n{\n\tstruct UnresolvedSymbol\n\t{\n\t\tsint32 lineNumber;\n\t\tPatchGroup* patchGroup;\n\t\tstd::string symbolName;\n\n\t\tUnresolvedSymbol(sint32 _lineNumber, PatchGroup* _patchGroup, std::string _symbolName) : lineNumber(_lineNumber), patchGroup(_patchGroup), symbolName(_symbolName) {};\n\n\t\tbool operator < (const UnresolvedSymbol &other) const \n\t\t{ \n\t\t\tif (lineNumber == other.lineNumber)\n\t\t\t\treturn symbolName.compare(other.symbolName);\n\t\t\treturn lineNumber < other.lineNumber; \n\t\t}\n\t};\n\n\tclass GraphicPack2* graphicPack;\n\t//MEMPTR<void> codeCaveStart;\n\t//MEMPTR<void> codeCaveEnd;\n\tconst RPLModule* matchedModule;\n\tstd::unordered_map<std::string, uint32> map_values;\n\t// error information\n\t//std::unordered_set<std::string> unresolvedSymbols;\n\tstd::set<UnresolvedSymbol> unresolvedSymbols;\n\t//std::unordered_multiset<sint32, std::greater<std::string>> unresolvedSymbols;\n\t// error handler\n\tPatchErrorHandler errorHandler{};\n};\n\nenum class PATCH_RESOLVE_RESULT\n{\n\tRESOLVED, // successfully resolved any expressions or relocations\n\tEXPRESSION_ERROR, // syntax error in expression (usually this should be detected during the parsing stage already)\n\tVALUE_ERROR, // expression evaluated but the result is not useable (e.g. branch target out of range)\n\tUNKNOWN_VARIABLE, // variable not known or referencing unresolved variable (try again)\n\tVARIABLE_CONFLICT, // a variable or label with the same name was already defined\n\tINVALID_ADDRESS, // attempted to relocate address that is not within any known section\n\tUNDEFINED_ERROR, // unexpected error\n};\n\nenum class EXPRESSION_RESOLVE_RESULT\n{\n\tAVAILABLE,\n\tEXPRESSION_ERROR,\n\tUNKNOWN_VARIABLE\n};\n\nclass PatchEntry\n{\npublic:\n\tPatchEntry() {};\n\tvirtual ~PatchEntry() {};\n\n\t// apply relocation or evaluate any expressions for this entry\n\tvirtual PATCH_RESOLVE_RESULT resolve(PatchContext_t& ctx) = 0;\n};\n\n// represents symbol assignment (always treated like an address)\n// <symbolName> = <expression>\nclass PatchEntryCemuhookSymbolValue : public PatchEntry\n{\npublic:\n\tPatchEntryCemuhookSymbolValue(sint32 lineNumber, const char* symbolName, const sint32 symbolNameLen, const char* expressionStr, const sint32 expressionLen) : PatchEntry(), m_lineNumber(lineNumber)\n\t{\n\t\tm_symbolName.assign(symbolName, symbolNameLen);\n\t\tm_expressionString.assign(expressionStr, expressionLen);\n\t}\n\n\tsint32 getLineNumber() { return m_lineNumber; }\n\n\tPATCH_RESOLVE_RESULT resolve(PatchContext_t& ctx) override;\n\n\tstd::string& getSymbolName() { return m_symbolName; }\n\nprivate:\n\tsint32 m_lineNumber;\n\tstd::string m_symbolName;\n\tstd::string m_expressionString;\n\tuint32 m_resolvedValue;\n\tbool m_isResolved{};\n};\n\nenum class PATCHVARTYPE\n{\n\tDOUBLE,\n\tINT, // 32bit signed integer\n\tUINT, // 32bit unsigned integer or pointer\n\t//BOOL, // boolean\n};\n\n// represents variable value assignment\n// unlike Cemu symbols these are treated as a\n// <symbolName> = <expression>\nclass PatchEntryVariableValue : public PatchEntry\n{\npublic:\n\n\tPatchEntryVariableValue(sint32 lineNumber, const char* symbolName, const sint32 symbolNameLen, PATCHVARTYPE varType, const char* expressionStr, const sint32 expressionLen) : PatchEntry(), m_lineNumber(lineNumber), m_varType(varType)\n\t{\n\t\tm_symbolName.assign(symbolName, symbolNameLen);\n\t\tm_expressionString.assign(expressionStr, expressionLen);\n\t}\n\n\tsint32 getLineNumber() { return m_lineNumber; }\n\n\tPATCH_RESOLVE_RESULT resolve(PatchContext_t& ctx) override;\n\n\tstd::string& getSymbolName() { return m_symbolName; }\n\t//uint32 getSymbolValue() { return m_resolvedValue; }\n\nprivate:\n\tsint32 m_lineNumber;\n\tstd::string m_symbolName;\n\tstd::string m_expressionString;\n\tPATCHVARTYPE m_varType;\n\tstd::variant<sint32, uint32, double> m_resolvedValue;\n\tbool m_isResolved{};\n};\n\n// represents a label\nclass PatchEntryLabel : public PatchEntry\n{\npublic:\n\tPatchEntryLabel(sint32 lineNumber, const char* symbolName, const sint32 symbolNameLen) : PatchEntry(), m_lineNumber(lineNumber)\n\t{\n\t\tm_symbolName.assign(symbolName, symbolNameLen);\n\t}\n\n\tsint32 getLineNumber() { return m_lineNumber; }\n\n\tPATCH_RESOLVE_RESULT resolve(PatchContext_t& ctx) override;\n\n\tstd::string& getSymbolName() { return m_symbolName; }\n\tuint32 getSymbolValue() { return m_relocatedAddress; }\n\n\tvoid setAssignedVA(uint32 virtualAddress)\n\t{\n\t\tm_address = virtualAddress;\n\t}\n\nprivate:\n\tsint32 m_lineNumber;\n\tstd::string m_symbolName;\n\tuint32 m_address;\n\tuint32 m_relocatedAddress;\n\tbool m_isResolved{};\n};\n\n// represents assembled code/data\nclass PatchEntryInstruction : public PatchEntry\n{\npublic:\n\tPatchEntryInstruction(sint32 lineNumber, uint32 patchAddr, std::span<uint8> data, std::vector<PPCAssemblerReloc>& list_relocs) : PatchEntry(), m_lineNumber(lineNumber), m_addr(patchAddr), m_size((uint32)data.size()), m_relocs(list_relocs)\n\t{\n\t\tsint32 dataLength = (sint32)data.size();\n\t\tm_length = dataLength;\n\t\tm_data = new uint8[dataLength];\n\t\tm_dataWithRelocs = new uint8[dataLength];\n\t\tm_dataBackup = new uint8[dataLength];\n\t\tmemcpy(m_data, data.data(), dataLength);\n\t\tmemcpy(m_dataWithRelocs, data.data(), dataLength);\n\t}\n\n\t~PatchEntryInstruction()\n\t{\n\t\tif (m_data)\n\t\t\tdelete[] m_data;\n\t\tif (m_dataWithRelocs)\n\t\t\tdelete[] m_dataWithRelocs;\n\t\tif (m_dataBackup)\n\t\t\tdelete[] m_dataBackup;\n\t}\n\n\tuint32 getAddr() const\n\t{\n\t\treturn m_addr;\n\t}\n\n\tuint32 getRelocatedAddr()\n\t{\n\t\treturn m_relocatedAddr;\n\t}\n\tuint32 getSize() const\n\t{\n\t\treturn m_size;\n\t}\n\n\tPATCH_RESOLVE_RESULT resolve(PatchContext_t& ctx) override;\n\tPATCH_RESOLVE_RESULT resolveReloc(PatchContext_t& ctx, PPCAssemblerReloc* reloc);\n\n\tvoid applyPatch();\n\tvoid undoPatch();\n\nprivate:\n\tuint8* m_data{}; // original unrelocated data\n\tuint8* m_dataWithRelocs{}; // data with relocs applied\n\tuint8* m_dataBackup{}; // original data before patch was applied\n\tsint32 m_length{};\n\tstd::vector<PPCAssemblerReloc> m_relocs;\n\tuint32 m_lineNumber;\n\tuint32 m_addr;\n\tuint32 m_size;\n\tuint32 m_relocatedAddr;\n\tbool m_addrRelocated{};\n};\n\nenum class GPCallbackType {\n    Entry\n};\n\nclass PatchGroup\n{\n\tfriend class GraphicPack2;\n\npublic:\n\tPatchGroup(class GraphicPack2* gp, const char* nameStr, sint32 nameLength) : graphicPack(gp)\n\t{\n\t\tname = std::string(nameStr, nameLength);\n\t}\n\n\tbool matchesCRC(uint32 crc)\n\t{\n\t\tfor (auto& chk : list_moduleMatches)\n\t\t{\n\t\t\tif (chk == crc)\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tuint32 getCodeCaveBase()\n\t{\n\t\treturn codeCaveMem.GetMPTR();\n\t}\n\n\tuint32 getCodeCaveSize()\n\t{\n\t\treturn codeCaveSize;\n\t}\n\n\tstd::string_view getName()\n\t{\n\t\treturn name;\n\t}\n\n\tvoid setApplied() { m_isApplied = true; }\n\tvoid resetApplied() { m_isApplied = false; }\n\tbool isApplied() const { return m_isApplied; }\n\nprivate:\n\tclass GraphicPack2* graphicPack;\n\tstd::string name;\n\tstd::vector<uint32> list_moduleMatches;\n\tstd::vector<PatchEntry*> list_patches;\n\tstd::vector<std::pair<std::string, GPCallbackType>> list_callbacks;\n\tuint32 codeCaveSize;\n\tMEMPTR<void> codeCaveMem;\n\tbool m_isApplied{};\n\tbool m_isRpxOnlyTarget{};\n};"
  },
  {
    "path": "src/Cafe/GraphicPack/GraphicPack2PatchesApply.cpp",
    "content": "#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"Common/FileStream.h\"\n#include \"Cemu/PPCAssembler/ppcAssembler.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n#include \"Cafe/OS/RPL/rpl_symbol_storage.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n#include \"Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h\"\n\nbool _relocateAddress(PatchGroup* group, PatchContext_t* ctx, uint32 addr, uint32& relocatedAddress)\n{\n\tif (addr >= 0 && addr <= 1024 * 1024 * 8)\n\t{\n\t\t// codecave address\n\t\trelocatedAddress = group->getCodeCaveBase() + addr;\n\t\treturn true;\n\t}\n\t// check if address is within module section\n\tfor (sint32 i = 0; i < ctx->matchedModule->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\tauto sect = ctx->matchedModule->sectionTablePtr + i;\n\t\tif (addr >= sect->virtualAddress && addr < (sect->virtualAddress + sect->sectionSize))\n\t\t{\n\t\t\trelocatedAddress = addr - sect->virtualAddress + memory_getVirtualOffsetFromPointer(ctx->matchedModule->sectionAddressTable2[i].ptr);\n\t\t\treturn true;\n\t\t}\n\t}\n\trelocatedAddress = 0;\n\treturn false;\n}\n\nstruct  \n{\n\tbool hasUnknownVariable;\n\tPatchContext_t* activePatchContext;\n\tPatchGroup* currentGroup;\n\t// additional error information tracking\n\tsint32 lineNumber; // line number of the expression being processed, negative if not available\n\tbool captureUnresolvedSymbols;\n}resolverState{};\n\nbool GraphicPack2::ResolvePresetConstant(const std::string& varname, double& value) const\n{\n\tconst auto var = GetPresetVariable(GetActivePresets(), varname);\n\tif (var)\n\t{\n\t\tvalue = var->second;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\ntemplate<typename T>\nT _expressionFuncHA(T input)\n{\n\tuint32 u32 = (uint32)input;\n\tu32 = (((u32 >> 16) + ((u32 & 0x8000) ? 1 : 0)) & 0xffff);\n\treturn (T)u32;\n}\n\ntemplate<typename T>\nT _expressionFuncHI(T input)\n{\n\tuint32 u32 = (uint32)input;\n\tu32 = (u32 >> 16) & 0xffff;\n\treturn (T)u32;\n}\n\ntemplate<typename T>\nT _expressionFuncLO(T input)\n{\n\tuint32 u32 = (uint32)input;\n\tu32 &= 0xffff;\n\treturn (T)u32;\n}\n\ntemplate<typename T>\nT _expressionFuncReloc(T input)\n{\n\tuint32 addr = (uint32)input;\n\tuint32 relocatedAddress = 0;\n\tif(!_relocateAddress(resolverState.currentGroup, resolverState.activePatchContext, addr, relocatedAddress))\n\t{\n\t\tresolverState.activePatchContext->errorHandler.printError(resolverState.currentGroup, resolverState.lineNumber, fmt::format(\"reloc({0:#08x}): Address does not point to a known memory region\", addr));\n\t\treturn (T)0;\n\t}\n\treturn (T)relocatedAddress;\n}\n\ndouble _cbResolveConstant(std::string_view varname)\n{\n\tstd::string varnameOnly;\n\tstd::string tokenOnly;\n\t// detect suffix\n\tbool hasSuffix = false;\n\tconst auto idx = varname.find('@');\n\tif (idx != std::string_view::npos)\n\t{\n\t\thasSuffix = true;\n\t\tvarnameOnly = varname.substr(0, idx);\n\t\ttokenOnly = varname.substr(idx + 1);\n\t}\n\telse\n\t\tvarnameOnly = varname;\n\n\tdouble value;\n\tif (varnameOnly.length() >= 1 && varnameOnly[0] == '$')\n\t{\n\t\t// resolve preset variable\n\t\tif (!resolverState.activePatchContext->graphicPack->ResolvePresetConstant(varnameOnly, value))\n\t\t{\n\t\t\tresolverState.hasUnknownVariable = true;\n\t\t\tif (resolverState.captureUnresolvedSymbols)\n\t\t\t\tresolverState.activePatchContext->unresolvedSymbols.emplace(resolverState.lineNumber, resolverState.currentGroup, varnameOnly);\n\t\t\treturn 0.0;\n\t\t}\n\t}\n\telse if (varnameOnly.length() >= 7 && boost::iequals(varnameOnly.substr(0, 7), \"import.\"))\n\t{\n\t\t// resolve import\n\t\tstd::string importName = varnameOnly.substr(7);\n\t\t// detect imports\n\t\tconst auto idxDot = importName.find('.');\n\t\tbool isValidImport = false;\n\t\tstd::string_view importError = \"\";\n\t\tif (idxDot != std::string_view::npos)\n\t\t{\n\t\t\tstd::string moduleName = importName.substr(0, idxDot);\n\t\t\tstd::string functionName = importName.substr(idxDot + 1);\n\t\t\tuint32 rplHandle = RPLLoader_GetHandleByModuleName(moduleName.c_str());\n\t\t\tif (rplHandle == RPL_INVALID_HANDLE)\n\t\t\t{\n\t\t\t\timportError = \" (module not found)\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tMPTR exportResult = RPLLoader_FindModuleOrHLEExport(rplHandle, false, functionName.c_str());\n\t\t\t\tif (exportResult)\n\t\t\t\t{\n\t\t\t\t\tisValidImport = true;\n\t\t\t\t\tvalue = (double)exportResult;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\timportError = \" (function not found)\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\timportError = \" (invalid import syntax)\";\n\t\t// error output\n\t\tif (!isValidImport)\n\t\t{\n\t\t\tresolverState.hasUnknownVariable = true;\n\t\t\tif (resolverState.captureUnresolvedSymbols)\n\t\t\t{\n\t\t\t\tstd::string detailedSymbolName;\n\t\t\t\tdetailedSymbolName.assign(importName);\n\t\t\t\tdetailedSymbolName.append(importError);\n\t\t\t\tresolverState.activePatchContext->unresolvedSymbols.emplace(resolverState.lineNumber, resolverState.currentGroup, detailedSymbolName);\n\t\t\t}\n\t\t\treturn 0.0;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// resolve variable\n\t\tconst auto v = resolverState.activePatchContext->map_values.find(varnameOnly);\n\t\tif (v == resolverState.activePatchContext->map_values.end())\n\t\t{\n\t\t\tresolverState.hasUnknownVariable = true;\n\t\t\tif (resolverState.captureUnresolvedSymbols)\n\t\t\t\tresolverState.activePatchContext->unresolvedSymbols.emplace(resolverState.lineNumber, resolverState.currentGroup, varnameOnly);\n\t\t\treturn 0.0;\n\t\t}\n\t\tvalue = v->second;\n\t}\n\tif (hasSuffix)\n\t{\n\t\tstd::transform(tokenOnly.cbegin(), tokenOnly.cend(), tokenOnly.begin(), tolower);\n\t\tif (tokenOnly == \"ha\")\n\t\t{\n\t\t\tvalue = _expressionFuncHA<double>(value);\n\t\t}\n\t\telse if (tokenOnly == \"h\" || tokenOnly == \"hi\")\n\t\t{\n\t\t\tvalue = _expressionFuncHI<double>(value);\n\t\t}\n\t\telse if (tokenOnly == \"l\" || tokenOnly == \"lo\")\n\t\t{\n\t\t\tvalue = _expressionFuncLO<double>(value);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// we treat unknown suffixes as unresolveable symbols\n\t\t\tresolverState.hasUnknownVariable = true;\n\t\t\tif (resolverState.captureUnresolvedSymbols)\n\t\t\t{\n\t\t\t\tstd::string detailedSymbolName;\n\t\t\t\tdetailedSymbolName.assign(varnameOnly);\n\t\t\t\tdetailedSymbolName.append(\"@\");\n\t\t\t\tdetailedSymbolName.append(tokenOnly);\n\t\t\t\tdetailedSymbolName.append(\" (invalid suffix)\");\n\t\t\t\tresolverState.activePatchContext->unresolvedSymbols.emplace(resolverState.lineNumber, resolverState.currentGroup, detailedSymbolName);\n\t\t\t}\n\t\t\treturn 0.0;\n\t\t}\n\t}\n\treturn value;\n}\n\ndouble _cbResolveFunction(std::string_view funcname, double input)\n{\n\tstd::string funcnameLC(funcname);\n\tstd::transform(funcnameLC.cbegin(), funcnameLC.cend(), funcnameLC.begin(), tolower);\n\tdouble value = input;\n\tif (funcnameLC == \"ha\" || funcnameLC == \"ha16\")\n\t\tvalue = _expressionFuncHA<double>(value);\n\telse if (funcnameLC == \"hi\" || funcnameLC == \"hi16\")\n\t\tvalue = _expressionFuncHI<double>(value);\n\telse if (funcnameLC == \"lo\" || funcnameLC == \"lo16\")\n\t\tvalue = _expressionFuncLO<double>(value);\n\telse if (funcnameLC == \"reloc\")\n\t\tvalue = _expressionFuncReloc<double>(value);\n\telse\n\t{\n\t\t// unresolvable function\n\t\tresolverState.hasUnknownVariable = true;\n\t\tif (resolverState.captureUnresolvedSymbols)\n\t\t{\n\t\t\tstd::string detailedSymbolName;\n\t\t\tdetailedSymbolName.assign(funcname);\n\t\t\tdetailedSymbolName.append(\"() (unknown function)\");\n\t\t\tresolverState.activePatchContext->unresolvedSymbols.emplace(resolverState.lineNumber, resolverState.currentGroup, detailedSymbolName);\n\t\t}\n\t\treturn 0.0;\n\t}\n\treturn value;\n}\n\ntemplate<typename T>\nEXPRESSION_RESOLVE_RESULT _resolveExpression(PatchContext_t& ctx, std::string& expressionString, T& result, sint32 associatedLineNumber = -1)\n{\n\tresolverState.lineNumber = associatedLineNumber;\n\tExpressionParser ep;\n\ttry\n\t{\n\t\t// add all the graphic pack constants\n\t\tep.AddConstantCallback(_cbResolveConstant);\n\t\tep.SetFunctionCallback(_cbResolveFunction);\n\t\tresolverState.hasUnknownVariable = false;\n\t\tresult = (T)ep.Evaluate(expressionString);\n\t\tif (resolverState.hasUnknownVariable)\n\t\t\treturn EXPRESSION_RESOLVE_RESULT::UNKNOWN_VARIABLE;\n\t}\n\tcatch (const std::exception&)\n\t{\n\t\tcemu_assert_debug(false);\n\t\tctx.errorHandler.printError(nullptr, -1, fmt::format(\"Unexpected error in expression \\\"{}\\\"\", expressionString));\n\t\treturn EXPRESSION_RESOLVE_RESULT::EXPRESSION_ERROR;\n\t}\n\treturn EXPRESSION_RESOLVE_RESULT::AVAILABLE;\n}\n\nPATCH_RESOLVE_RESULT translateExpressionResult(EXPRESSION_RESOLVE_RESULT expressionResult)\n{\n\tif (expressionResult == EXPRESSION_RESOLVE_RESULT::AVAILABLE)\n\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\telse if (expressionResult == EXPRESSION_RESOLVE_RESULT::EXPRESSION_ERROR)\n\t\treturn PATCH_RESOLVE_RESULT::EXPRESSION_ERROR;\n\telse if (expressionResult == EXPRESSION_RESOLVE_RESULT::UNKNOWN_VARIABLE)\n\t\treturn PATCH_RESOLVE_RESULT::UNKNOWN_VARIABLE;\n\tcemu_assert(false);\n\treturn PATCH_RESOLVE_RESULT::EXPRESSION_ERROR;\n}\n\nPATCH_RESOLVE_RESULT PatchEntryInstruction::resolveReloc(PatchContext_t& ctx, PPCAssemblerReloc* reloc)\n{\n\tMPTR finalRelocAddr = m_relocatedAddr + reloc->m_byteOffset;\n\tif (reloc->m_relocType == PPCASM_RELOC::FLOAT)\n\t{\n\t\t// resolve float expression\n\t\tfloat result;\n\t\tauto r = _resolveExpression<float>(ctx, reloc->m_expression, result, m_lineNumber);\n\t\tif (r == EXPRESSION_RESOLVE_RESULT::AVAILABLE)\n\t\t{\n\t\t\tcemu_assert((reloc->m_byteOffset + sizeof(betype<float>)) <= m_length);\n\t\t\t*(betype<float>*)(m_dataWithRelocs + reloc->m_byteOffset) = result;\n\t\t\tDebugSymbolStorage::StoreDataType(finalRelocAddr, DEBUG_SYMBOL_TYPE::FLOAT);\n\t\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t\t}\n\t\telse\n\t\t\treturn translateExpressionResult(r);\n\t}\n\telse if (reloc->m_relocType == PPCASM_RELOC::DOUBLE)\n\t{\n\t\t// resolve double expression\n\t\tdouble result;\n\t\tauto r = _resolveExpression<double>(ctx, reloc->m_expression, result, m_lineNumber);\n\t\tif (r == EXPRESSION_RESOLVE_RESULT::AVAILABLE)\n\t\t{\n\t\t\tcemu_assert((reloc->m_byteOffset + sizeof(betype<double>)) <= m_length);\n\t\t\t*(betype<double>*)(m_dataWithRelocs + reloc->m_byteOffset) = result;\n\t\t\tDebugSymbolStorage::StoreDataType(finalRelocAddr, DEBUG_SYMBOL_TYPE::DOUBLE);\n\t\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t\t}\n\t\telse\n\t\t\treturn translateExpressionResult(r);\n\t}\n\telse\n\t{\n\t\t// resolve uint32 expression\n\t\tuint32 result;\n\t\tauto r = _resolveExpression<uint32>(ctx, reloc->m_expression, result, m_lineNumber);\n\t\tif (r != EXPRESSION_RESOLVE_RESULT::AVAILABLE)\n\t\t\treturn translateExpressionResult(r);\n\t\tif (reloc->m_relocType == PPCASM_RELOC::U32)\n\t\t{\n\t\t\tcemu_assert((reloc->m_byteOffset + sizeof(betype<uint32>)) <= m_length);\n\t\t\t*(betype<uint32>*)(m_dataWithRelocs + reloc->m_byteOffset) = result;\n\t\t\tDebugSymbolStorage::StoreDataType(finalRelocAddr, DEBUG_SYMBOL_TYPE::U32);\n\t\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t\t}\n\t\telse if (reloc->m_relocType == PPCASM_RELOC::U16)\n\t\t{\n\t\t\tcemu_assert((reloc->m_byteOffset + sizeof(betype<uint16>)) <= m_length);\n\t\t\t*(betype<uint16>*)(m_dataWithRelocs + reloc->m_byteOffset) = (uint16)result;\n\t\t\tDebugSymbolStorage::StoreDataType(finalRelocAddr, DEBUG_SYMBOL_TYPE::U16);\n\t\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t\t}\n\t\telse if (reloc->m_relocType == PPCASM_RELOC::U8)\n\t\t{\n\t\t\tcemu_assert((reloc->m_byteOffset + sizeof(betype<uint8>)) <= m_length);\n\t\t\t*(betype<uint8>*)(m_dataWithRelocs + reloc->m_byteOffset) = (uint8)result;\n\t\t\tDebugSymbolStorage::StoreDataType(finalRelocAddr, DEBUG_SYMBOL_TYPE::U8);\n\t\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t\t}\n\t\telse if (reloc->m_relocType == PPCASM_RELOC::U32_MASKED_IMM)\n\t\t{\n\t\t\tcemu_assert((reloc->m_byteOffset + sizeof(betype<uint32>)) <= m_length);\n\t\t\tuint32 opcode = *(betype<uint32>*)(m_dataWithRelocs + reloc->m_byteOffset);\n\t\t\tcemu_assert_debug(reloc->m_bitCount != 0);\n\t\t\tuint32 mask = 0xFFFFFFFF >> (32 - reloc->m_bitCount);\n\t\t\tmask <<= reloc->m_bitOffset;\n\t\t\topcode &= ~mask;\n\t\t\topcode |= ((result << reloc->m_bitOffset) & mask);\n\t\t\t*(betype<uint32>*)(m_dataWithRelocs + reloc->m_byteOffset) = opcode;\n\t\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t\t}\n\t\telse if (reloc->m_relocType == PPCASM_RELOC::BRANCH_S26)\n\t\t{\n\t\t\tcemu_assert((reloc->m_byteOffset + sizeof(betype<uint32>)) <= m_length);\n\t\t\tuint32 opcode = *(betype<uint32>*)(m_dataWithRelocs + reloc->m_byteOffset);\n\t\t\tif (opcode & 2)\n\t\t\t{\n\t\t\t\t// absolute\n\t\t\t\tif (result >= 0x3FFFFFC)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Target \\'{}\\' for branch at line {} out of range\", reloc->m_expression, m_lineNumber);\n\t\t\t\t\treturn PATCH_RESOLVE_RESULT::VALUE_ERROR;\n\t\t\t\t}\n\t\t\t\topcode &= ~0x3FFFFFC;\n\t\t\t\topcode |= (result & 0x3FFFFFC);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// relative\n\t\t\t\tuint32 instrAddr = this->getRelocatedAddr() + reloc->m_byteOffset;\n\t\t\t\tif (result < instrAddr)\n\t\t\t\t{\n\t\t\t\t\t// jump backwards\n\t\t\t\t\tuint32 jumpB = instrAddr - result;\n\t\t\t\t\tif (jumpB > 0x1FFFFFF)\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.errorHandler.printError(nullptr, m_lineNumber, fmt::format(\"Target \\'{0}\\' for branch out of range (use MTCTR + BCTR or similar for long distance branches)\", reloc->m_expression.c_str()));\n\t\t\t\t\t\treturn PATCH_RESOLVE_RESULT::VALUE_ERROR;\n\t\t\t\t\t}\n\t\t\t\t\topcode &= ~0x3FFFFFC;\n\t\t\t\t\topcode |= ((~jumpB + 1) & 0x3FFFFFC);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// jump forwards\n\t\t\t\t\tuint32 jumpF = result - instrAddr;\n\t\t\t\t\tif (jumpF >= 0x1FFFFFF)\n\t\t\t\t\t{\n\t\t\t\t\t\tctx.errorHandler.printError(nullptr, m_lineNumber, fmt::format(\"Target \\'{0}\\' for branch out of range (use MTCTR + BCTR or similar for long distance branches)\", reloc->m_expression.c_str()));\n\t\t\t\t\t\treturn PATCH_RESOLVE_RESULT::VALUE_ERROR;\n\t\t\t\t\t}\n\t\t\t\t\topcode &= ~0x3FFFFFC;\n\t\t\t\t\topcode |= (jumpF & 0x3FFFFFC);\n\t\t\t\t}\n\t\t\t}\n\t\t\t*(betype<uint32>*)(m_dataWithRelocs + reloc->m_byteOffset) = opcode;\n\t\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t\t}\n\t\telse if (reloc->m_relocType == PPCASM_RELOC::BRANCH_S16)\n\t\t{\n\t\t\tcemu_assert((reloc->m_byteOffset + sizeof(betype<uint32>)) <= m_length);\n\t\t\tuint32 opcode = *(betype<uint32>*)(m_dataWithRelocs + reloc->m_byteOffset);\n\t\t\tuint32 instrAddr = this->getRelocatedAddr() + reloc->m_byteOffset;\n\t\t\tif (result < instrAddr)\n\t\t\t{\n\t\t\t\t// jump backwards\n\t\t\t\tuint32 jumpB = instrAddr - result;\n\t\t\t\tif (jumpB > 0x8000)\n\t\t\t\t{\n\t\t\t\t\tctx.errorHandler.printError(nullptr, m_lineNumber, fmt::format(\"Target \\'{0}\\' for branch out of range (use MTCTR + BCTR or similar for long distance branches)\", reloc->m_expression.c_str()));\n\t\t\t\t\treturn PATCH_RESOLVE_RESULT::VALUE_ERROR;\n\t\t\t\t}\n\t\t\t\topcode &= ~0xFFFC;\n\t\t\t\topcode |= ((~jumpB + 1) & 0xFFFC);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// jump forwards\n\t\t\t\tuint32 jumpF = result - instrAddr;\n\t\t\t\tif (jumpF >= 0x8000)\n\t\t\t\t{\n\t\t\t\t\tctx.errorHandler.printError(nullptr, m_lineNumber, fmt::format(\"Target \\'{0}\\' for branch out of range (use MTCTR + BCTR or similar for long distance branches)\", reloc->m_expression.c_str()));\n\t\t\t\t\treturn PATCH_RESOLVE_RESULT::VALUE_ERROR;\n\t\t\t\t}\n\t\t\t\topcode &= ~0xFFFC;\n\t\t\t\topcode |= (jumpF & 0xFFFC);\n\t\t\t}\n\t\t\t*(betype<uint32>*)(m_dataWithRelocs + reloc->m_byteOffset) = opcode;\n\t\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t\t}\n\n\n\t\t// *internalCtx.opcode |= (relativeAddr & 0xFFFC);\n\t\tcemu_assert_debug(false);\n\t}\n\treturn PATCH_RESOLVE_RESULT::UNDEFINED_ERROR;\n}\n\nPATCH_RESOLVE_RESULT PatchEntryInstruction::resolve(PatchContext_t& ctx)\n{\n\t// relocate patch address\n\tif (!m_addrRelocated)\n\t{\n\t\tif (_relocateAddress(resolverState.currentGroup, &ctx, m_addr, m_relocatedAddr) == false)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Patches: Address 0x{:08x} (line {}) is not within code cave or any module section\", this->getAddr(), this->m_lineNumber);\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn PATCH_RESOLVE_RESULT::INVALID_ADDRESS;\n\t\t}\n\t\tm_addrRelocated = true;\n\t}\n\t// apply relocations to instruction\n\tfor (auto& itr : this->m_relocs)\n\t{\n\t\tif(itr.isApplied())\n\t\t\tcontinue;\n\t\t// evaluate expression and apply reloc to internal buffer\n\t\tauto r = resolveReloc(ctx, &itr);\n\t\tif (r == PATCH_RESOLVE_RESULT::RESOLVED)\n\t\t{\n\t\t\titr.setApplied();\n\t\t\tcontinue;\n\t\t}\n\t\treturn r;\n\t}\n\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n}\n\nvoid PatchEntryInstruction::applyPatch()\n{\n\tconst uint32 addr = getRelocatedAddr();\n\tif (addr == 0)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\tuint8* patchAddr = (uint8*)memory_base + addr;\n\tmemcpy(m_dataBackup, patchAddr, m_length);\n\tmemcpy(patchAddr, m_dataWithRelocs, m_length);\n\tPPCRecompiler_invalidateRange(addr, addr + m_length);\n}\n\nvoid PatchEntryInstruction::undoPatch()\n{\n\tconst uint32 addr = getRelocatedAddr();\n\tif (addr == 0)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\tuint8* patchAddr = (uint8*)memory_base + addr;\n\tmemcpy(patchAddr, m_dataBackup, m_length);\n\tPPCRecompiler_invalidateRange(addr, addr + m_length);\n\trplSymbolStorage_removeRange(addr, m_length);\n\tDebugSymbolStorage::ClearRange(addr, m_length);\n}\n\n// returns true on success, false if variable with same name already exists\nbool registerU32Variable(PatchContext_t& ctx, std::string& name, uint32 value, PatchGroup* associatedPatchGroup, uint32 associatedLineNumber, bool isAddress)\n{\n\tcemuLog_log(LogType::Patches, \"Resolved symbol {} with value 0x{:08x}\", name.c_str(), value);\n\tif (ctx.map_values.find(name) != ctx.map_values.end())\n\t{\n\t\treturn false;\n\t}\n\tctx.map_values[name] = value;\n\t// keep track of address symbols for the debugger\n\trplSymbolStorage_store(ctx.graphicPack->GetName().data(), name.data(), value);\n\n\treturn true;\n}\n\nPATCH_RESOLVE_RESULT PatchEntryCemuhookSymbolValue::resolve(PatchContext_t& ctx)\n{\n\tuint32 addr;\n\tauto r = _resolveExpression<uint32>(ctx, m_expressionString, addr, m_lineNumber);\n\tif (r == EXPRESSION_RESOLVE_RESULT::AVAILABLE)\n\t{\n\t\tif (_relocateAddress(resolverState.currentGroup, &ctx, addr, m_resolvedValue))\n\t\t{\n\t\t\tm_isResolved = true;\n\t\t\t// register variable\n\t\t\tif (!registerU32Variable(ctx, m_symbolName, m_resolvedValue, resolverState.currentGroup, getLineNumber(), true))\n\t\t\t{\n\t\t\t\tif (resolverState.captureUnresolvedSymbols)\n\t\t\t\t\tctx.errorHandler.printError(resolverState.currentGroup, m_lineNumber, fmt::format(\"Symbol {} is already defined\", m_symbolName));\n\t\t\t\treturn PATCH_RESOLVE_RESULT::VARIABLE_CONFLICT;\n\t\t\t}\n\t\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t\t}\n\t\treturn PATCH_RESOLVE_RESULT::INVALID_ADDRESS;\n\t}\n\treturn translateExpressionResult(r);\n}\n\nPATCH_RESOLVE_RESULT PatchEntryLabel::resolve(PatchContext_t& ctx)\n{\n\tif (_relocateAddress(resolverState.currentGroup, &ctx, m_address, m_relocatedAddress))\n\t{\n\t\tm_isResolved = true;\n\t\t// register variable\n\t\tif (!registerU32Variable(ctx, m_symbolName, m_relocatedAddress, resolverState.currentGroup, getLineNumber(), true))\n\t\t{\n\t\t\tif (resolverState.captureUnresolvedSymbols)\n\t\t\t\tctx.errorHandler.printError(resolverState.currentGroup, m_lineNumber, fmt::format(\"Label {} is already defined\", m_symbolName));\n\t\t\treturn PATCH_RESOLVE_RESULT::VARIABLE_CONFLICT;\n\t\t}\n\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t}\n\tif(resolverState.captureUnresolvedSymbols)\n\t\tctx.errorHandler.printError(resolverState.currentGroup, m_lineNumber, fmt::format(\"Address {:#08x} of label {} does not point to any module section or code cave\", m_address, m_symbolName));\n\treturn PATCH_RESOLVE_RESULT::INVALID_ADDRESS;\n}\n\nPATCH_RESOLVE_RESULT PatchEntryVariableValue::resolve(PatchContext_t& ctx)\n{\n\tuint32 v;\n\tauto r = _resolveExpression<uint32>(ctx, m_expressionString, v, m_lineNumber);\n\tif (r == EXPRESSION_RESOLVE_RESULT::AVAILABLE)\n\t{\n\t\t// register variable\n\t\tif (!registerU32Variable(ctx, m_symbolName, v, resolverState.currentGroup, getLineNumber(), false))\n\t\t{\n\t\t\tif (resolverState.captureUnresolvedSymbols)\n\t\t\t\tctx.errorHandler.printError(resolverState.currentGroup, m_lineNumber, fmt::format(\"Variable {} is already defined\", m_symbolName));\n\t\t\treturn PATCH_RESOLVE_RESULT::VARIABLE_CONFLICT;\n\t\t}\n\t\treturn PATCH_RESOLVE_RESULT::RESOLVED;\n\t}\n\treturn translateExpressionResult(r);\n}\n\nstruct UnresolvedPatches_t\n{\n\tPatchGroup* patchGroup;\n\tstd::vector<PatchEntry*> list_unresolvedPatches;\n};\n\n// returns number of resolved entries\nbool _resolverPass(PatchContext_t& patchContext, std::vector<UnresolvedPatches_t>& unresolvedPatches, bool captureUnresolvedSymbols = false)\n{\n\tresolverState.captureUnresolvedSymbols = captureUnresolvedSymbols;\n\tsint32 numResolvedEntries = 0;\n\tfor (auto& unresolvedGroup : unresolvedPatches)\n\t{\n\t\tresolverState.currentGroup = unresolvedGroup.patchGroup;\n\t\tauto& list_unresolvedPatches = unresolvedGroup.list_unresolvedPatches;\n\t\tfor (auto it = list_unresolvedPatches.begin(); it != list_unresolvedPatches.end();)\n\t\t{\n\t\t\tauto r = (*it)->resolve(patchContext);\n\t\t\tif (r == PATCH_RESOLVE_RESULT::RESOLVED)\n\t\t\t{\n\t\t\t\t// remove from list\n\t\t\t\tit = list_unresolvedPatches.erase(it);\n\t\t\t\tnumResolvedEntries++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (r == PATCH_RESOLVE_RESULT::UNKNOWN_VARIABLE)\n\t\t\t{\n\t\t\t\t// dependency on other not yet resolved entry, continue iterating\n\t\t\t\tit++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (r == PATCH_RESOLVE_RESULT::INVALID_ADDRESS ||\n\t\t\t\tr == PATCH_RESOLVE_RESULT::VARIABLE_CONFLICT)\n\t\t\t{\n\t\t\t\t// errors handled and printed inside resolve()\n\t\t\t\tit++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// unknown error\n\t\t\t\tpatchContext.errorHandler.printError(resolverState.currentGroup, -1, \"Internal error\");\n\t\t\t\tit++;\n\t\t\t}\n\t\t}\n\t}\n\treturn numResolvedEntries;\n}\n\nvoid GraphicPack2::ApplyPatchGroups(std::vector<PatchGroup*>& groups, const RPLModule* rpl)\n{\n\t// init context information\n\tPatchContext_t patchContext{};\n\tpatchContext.graphicPack = this;\n\tpatchContext.matchedModule = rpl;\n\tresolverState.activePatchContext = &patchContext;\n\t// setup error handler\n\tpatchContext.errorHandler.setCurrentGraphicPack(this);\n\tpatchContext.errorHandler.setStage(PatchErrorHandler::STAGE::APPLY);\n\t// no group can be applied more than once\n\tfor (auto patchGroup : groups)\n\t{\n\t\tif (patchGroup->isApplied())\n\t\t{\n\t\t\tpatchContext.errorHandler.printError(patchGroup, -1, \"Group already applied to a different module.\");\n\t\t\treturn;\n\t\t}\n\t}\n\t// allocate code cave for every group\n\tfor (auto patchGroup : groups)\n\t{\n\t\tif (patchGroup->codeCaveSize > 0)\n\t\t{\n\t\t\tauto codeCaveMem = RPLLoader_AllocateCodeCaveMem(256, patchGroup->codeCaveSize);\n\t\t\tcemuLog_log(LogType::Force, \"Applying patch group \\'{}\\' (Codecave: {:08x}-{:08x})\", patchGroup->name, codeCaveMem.GetMPTR(), codeCaveMem.GetMPTR() + patchGroup->codeCaveSize);\n\t\t\tpatchGroup->codeCaveMem = codeCaveMem;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Applying patch group \\'{}\\'\", patchGroup->name);\n\t\t\tpatchGroup->codeCaveMem = nullptr;\n\t\t}\n\t}\n\t// resolve the patch entries\n\t// this means:\n\t// - resolving the expressions for variables and registering them\n\t// - calculating relocated addresses\n\t// - applying relocations to temporary patch buffer\n\n\t// multiple passes may be necessary since forward and backward references are allowed as well as references across group boundaries\n\n\t// create a copy of all the patch references and keep the group association intact\n\tstd::vector<UnresolvedPatches_t> unresolvedPatches;\n\tunresolvedPatches.resize(groups.size());\n\tfor (size_t i = 0; i < groups.size(); i++)\n\t{\n\t\tunresolvedPatches[i].patchGroup = groups[i];\n\t\tunresolvedPatches[i].list_unresolvedPatches = groups[i]->list_patches;\n\t}\n\n\tauto isUnresolvedPatchesEmpty = [&unresolvedPatches]()\n\t{\n\t\tfor (auto& itr : unresolvedPatches)\n\t\t\tif (!itr.list_unresolvedPatches.empty())\n\t\t\t\treturn false;\n\t\treturn true;\n\t};\n\t// resolve and relocate\n\tfor (sint32 pass = 0; pass < 30; pass++)\n\t{\n\t\tbool isLastPass = (pass == 29);\n\t\tsint32 numResolvedEntries = _resolverPass(patchContext, unresolvedPatches, false);\n\t\tif (isUnresolvedPatchesEmpty())\n\t\t\tbreak;\n\t\tif (numResolvedEntries == 0 || isLastPass)\n\t\t{\n\t\t\t// stuck due to reference to undefined variable or unresolvable cross-references\n\t\t\t// iterate all remaining expressions and output them to log\n\t\t\t// execute another resolver pass but capture all the unresolved variables this time\n\t\t\tpatchContext.unresolvedSymbols.clear();\n\t\t\t_resolverPass(patchContext, unresolvedPatches, true);\n\t\t\t// generate messages\n\t\t\tif(isLastPass)\n\t\t\t\tpatchContext.errorHandler.printError(nullptr, -1, \"Some symbols could not be resolved because the dependency chain is too deep\");\n\t\t\tfor (auto& itr : patchContext.unresolvedSymbols)\n\t\t\t\tpatchContext.errorHandler.printError(itr.patchGroup, itr.lineNumber, fmt::format(\"Unresolved symbol: {}\", itr.symbolName));\n\t\t\tpatchContext.errorHandler.showStageErrorMessageBox();\n\t\t\treturn;\n\t\t}\n\t}\n\tif (!isUnresolvedPatchesEmpty() || patchContext.errorHandler.hasError())\n\t{\n\t\tpatchContext.errorHandler.showStageErrorMessageBox();\n\t\treturn;\n\t}\n\t// apply relocated patches\n\tfor (auto patchGroup : groups)\n\t{\n\t\tfor (auto& patch : patchGroup->list_patches)\n\t\t{\n\t\t\tPatchEntryInstruction* patchInstruction = dynamic_cast<PatchEntryInstruction*>(patch);\n\t\t\tif (patchInstruction == nullptr)\n\t\t\t\tcontinue;\n\t\t\tpatchInstruction->applyPatch();\n\t\t}\n\t\t\n\t\tfor (const auto& [name, type] : patchGroup->list_callbacks)\n\t\t{\n            auto it = patchContext.map_values.find(name);\n            if (it != patchContext.map_values.end())\n            {\n                m_callbacks.push_back(std::make_pair(it->second, type));\n            }\n            else\n            {\n                patchContext.errorHandler.printError(patchGroup, -1, fmt::format(\"Failed to resolve .callback symbol: {}\", name));\n                patchContext.errorHandler.showStageErrorMessageBox();\n                return;\n            }\n\t\t}\n\t}\n\t// mark groups as applied\n\tfor (auto patchGroup : groups)\n\t\tpatchGroup->setApplied();\n}\n\nvoid GraphicPack2::UndoPatchGroups(std::vector<PatchGroup*>& groups, const RPLModule* rpl)\n{\n\t// restore original data\n\tfor (auto patchGroup : groups)\n\t{\n\t\tif (!patchGroup->isApplied())\n\t\t\tcontinue;\n\t\tfor (auto& patch : patchGroup->list_patches)\n\t\t{\n\t\t\tPatchEntryInstruction* patchInstruction = dynamic_cast<PatchEntryInstruction*>(patch);\n\t\t\tif (patchInstruction == nullptr)\n\t\t\t\tcontinue;\n\t\t\tpatchInstruction->undoPatch();\n\t\t}\n\t}\n\t// mark groups as not applied\n\tfor (auto patchGroup : groups)\n\t\tpatchGroup->resetApplied();\n}\n\nvoid GraphicPack2::NotifyModuleLoaded(const RPLModule* rpl)\n{\n\tcemuLog_log(LogType::Force, \"Loaded module \\'{}\\' with checksum 0x{:08x}\", rpl->moduleName2, rpl->patchCRC);\n\n\tstd::lock_guard<std::recursive_mutex> lock(mtx_patches);\n\tlist_modules.emplace_back(rpl);\n\n\t// todo - iterate all active graphic packs and apply any matching patch groups\n}\n\nvoid GraphicPack2::NotifyModuleUnloaded(const RPLModule* rpl)\n{\n\tstd::lock_guard<std::recursive_mutex> lock(mtx_patches);\n\tlist_modules.erase(std::remove(list_modules.begin(), list_modules.end(), rpl), list_modules.end());\n}\n"
  },
  {
    "path": "src/Cafe/GraphicPack/GraphicPack2PatchesParser.cpp",
    "content": "#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"Common/FileStream.h\"\n#include \"util/helpers/StringParser.h\"\n#include \"Cemu/PPCAssembler/ppcAssembler.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n\nsint32 GraphicPack2::GetLengthWithoutComment(const char* str, size_t length)\n{\n\tsint32 index = 0;\n\tbool isInString = false;\n\twhile (index < length)\n\t{\n\t\tconst char c = str[index];\n\t\tif (c == '\\\"')\n\t\t\tisInString = !isInString;\n\t\telse if (c == '#' || c == ';')\n\t\t{\n\t\t\tif (!isInString)\n\t\t\t\treturn index;\n\t\t}\n\t\tindex++;\n\t}\n\treturn (sint32)length;\n}\n\nvoid GraphicPack2::LogPatchesSyntaxError(sint32 lineNumber, std::string_view errorMsg)\n{\n\tcemuLog_log(LogType::Force, \"Syntax error while parsing patch for graphic pack '{}':\", _pathToUtf8(this->GetRulesPath()));\n\tif(lineNumber >= 0)\n\t\tcemuLog_log(LogType::Force, fmt::format(\"Line {0}: {1}\", lineNumber, errorMsg));\n\telse\n\t\tcemuLog_log(LogType::Force, fmt::format(\"{0}\", errorMsg));\n\tlist_patchGroups.clear();\n}\n\nvoid GraphicPack2::CancelParsingPatches()\n{\n\t// unload everything, set error flag\n\tcemu_assert_debug(false);\n}\n\nvoid GraphicPack2::AddPatchGroup(PatchGroup* group)\n{\n\tif (group->list_moduleMatches.empty() && !group->m_isRpxOnlyTarget)\n\t{\n\t\tLogPatchesSyntaxError(-1, fmt::format(\"Group \\\"{}\\\" has no moduleMatches definition\", group->name));\n\t\tCancelParsingPatches();\n\t\tdelete group;\n\t\treturn;\n\t}\n\t// calculate code cave size\n\tuint32 codeCaveMaxAddr = 0;\n\tfor (auto& itr : group->list_patches)\n\t{\n\t\tPatchEntryInstruction* patchData = dynamic_cast<PatchEntryInstruction*>(itr);\n\t\tif (patchData)\n\t\t{\n\t\t\tuint32 patchAddr = patchData->getAddr();\n\t\t\tif (patchAddr < 0x00100000)\n\t\t\t{\n\t\t\t\t// everything in low 1MB of memory we consider part of the code cave\n\t\t\t\tcodeCaveMaxAddr = std::max(codeCaveMaxAddr, patchAddr + patchData->getSize());\n\t\t\t}\n\t\t}\n\n\t}\n\tuint32 numEstimatedCodeCaveInstr = codeCaveMaxAddr / 4;\n\tif (group->list_patches.size() < (numEstimatedCodeCaveInstr / 8))\n\t{\n\t\t// if less than 1/8th of the code cave is filled print a warning\n\t\tcemuLog_log(LogType::Force, \"Graphic pack patches: Code cave for group [{}] in gfx pack \\\"{}\\\" ranges from 0 to 0x{:x} but has only few instructions. Is this intentional?\", group->name, this->m_name, codeCaveMaxAddr);\n\t}\n\tgroup->codeCaveSize = codeCaveMaxAddr;\n\tlist_patchGroups.emplace_back(group);\n}\n\nvoid GraphicPack2::ParseCemuhookPatchesTxtInternal(MemStreamReader& patchesStream)\n{\n\tsint32 lineNumber = 0;\n\tPatchGroup* currentGroup = nullptr;\n\twhile (true)\n\t{\n\t\tauto lineStr = patchesStream.readLine();\n\t\tlineNumber++;\n\t\tif (patchesStream.hasError())\n\t\t\tbreak;\n\t\t// trim comment\n\t\tsize_t lineLength = GetLengthWithoutComment(lineStr.data(), lineStr.size());\n\n\t\tStringTokenParser parser(lineStr.data(), (sint32)lineLength);\n\n\t\t// skip whitespaces at the beginning\n\t\tparser.skipWhitespaces();\n\t\t// parse line\n\t\tif (parser.isEndOfString())\n\t\t\tcontinue;\n\t\tif (parser.compareCharacter(0, '['))\n\t\t{\n\t\t\t// group\n\t\t\tparser.skipCharacters(1);\n\t\t\t// find end of group name\n\t\t\tconst char* groupNameStr = parser.getCurrentPtr();\n\t\t\tsint32 groupNameLength = parser.skipToCharacter(']');\n\t\t\tif (groupNameLength < 0)\n\t\t\t{\n\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Expected ']'\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tparser.skipCharacters(1); // skip the ']'\n\t\t\tparser.skipWhitespaces();\n\t\t\tif (!parser.isEndOfString())\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Unexpected characters after ']'\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// begin new group\n\t\t\tif (currentGroup)\n\t\t\t{\n\t\t\t\tAddPatchGroup(currentGroup);\n\t\t\t}\n\t\t\tcurrentGroup = new PatchGroup(this, groupNameStr, groupNameLength);\n\t\t}\n\t\telse if (parser.compareCharacter(0, '0') && parser.compareCharacterI(1, 'x'))\n\t\t{\n\t\t\t// if the line starts with a hex address then it is a patched location\n\t\t\tuint32 patchedAddress;\n\t\t\tif (!parser.parseU32(patchedAddress))\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Malformed address\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (parser.matchWordI(\"=\") == false)\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Expected '=' after address\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tparser.skipWhitespaces();\n\t\t\tparser.trimWhitespaces();\n\t\t\t// assemble instruction\n\t\t\tstd::string instrText(parser.getCurrentPtr(), parser.getCurrentLen());\n\t\t\tPPCAssemblerInOut ctx{};\n\t\t\tctx.virtualAddress = patchedAddress;\n\t\t\tif (!ppcAssembler_assembleSingleInstruction(instrText.c_str(), &ctx))\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, fmt::format(\"Error in assembler: {}\", ctx.errorMsg));\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcurrentGroup->list_patches.emplace_back(new PatchEntryInstruction(lineNumber, patchedAddress, { ctx.outputData.data(), ctx.outputData.size() }, ctx.list_relocs));\n\t\t}\n\t\telse if (parser.matchWordI(\"moduleMatches\"))\n\t\t{\n\t\t\tif (currentGroup == nullptr)\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Specified 'ModuleMatches' outside of a group\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (parser.matchWordI(\"=\") == false)\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Expected '=' after ModuleMatches\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// read the checksums\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tuint32 checksum = 0;\n\t\t\t\tif (parser.parseU32(checksum) == false)\n\t\t\t\t{\n\t\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Invalid value for ModuleMatches\");\n\t\t\t\t\tCancelParsingPatches();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcurrentGroup->list_moduleMatches.emplace_back(checksum);\n\t\t\t\tif (parser.matchWordI(\",\") == false)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tparser.skipWhitespaces();\n\t\t\tif (!parser.isEndOfString())\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Unexpected character in line\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Cemuhook requires that user defined symbols start with _ but we are more lenient and allow them to start with letters too\n\t\t\t// the downside is that there is some ambiguity and parsing gets a little bit more complex\n\t\t\t\n\t\t\t// check for <symbolName> = pattern\n\t\t\tStringTokenParser bakParser;\n\t\t\tconst char* symbolStr;\n\t\t\tsint32 symbolLen;\n\t\t\tparser.storeParserState(&bakParser);\n\t\t\tif (parser.parseSymbolName(symbolStr, symbolLen) && parser.matchWordI(\"=\"))\n\t\t\t{\n\t\t\t\t// matches pattern: <symbolName> = ...\n\t\t\t\tparser.skipWhitespaces();\n\t\t\t\tparser.trimWhitespaces();\n\t\t\t\tconst char* expressionStr = parser.getCurrentPtr();\n\t\t\t\tsint32 expressionLen = parser.getCurrentLen();\n\t\t\t\t// create entry for symbol value assignment\n\t\t\t\tcurrentGroup->list_patches.emplace_back(new PatchEntryCemuhookSymbolValue(lineNumber, symbolStr, symbolLen, expressionStr, expressionLen));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, fmt::format(\"Invalid syntax\"));\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\tif (currentGroup)\n\t\tAddPatchGroup(currentGroup);\n}\n\nstatic inline uint32 INVALID_ORIGIN = 0xFFFFFFFF;\n\nbool GraphicPack2::ParseCemuPatchesTxtInternal(MemStreamReader& patchesStream)\n{\n\tsint32 lineNumber = 0;\n\tPatchGroup* currentGroup = nullptr;\n\n\tstruct  \n\t{\n\t\tvoid reset()\n\t\t{\n\t\t\tcurrentOrigin = INVALID_ORIGIN;\n\t\t\tcodeCaveOrigin = 0;\n\t\t}\n\n\t\tvoid setOrigin(uint32 origin)\n\t\t{\n\t\t\tcurrentOrigin = origin;\n\t\t}\n\n\t\tvoid setOriginCodeCave()\n\t\t{\n\t\t\tcurrentOrigin = codeCaveOrigin;\n\t\t}\n\n\t\tbool isValidOrigin()\n\t\t{\n\t\t\treturn currentOrigin != INVALID_ORIGIN;\n\t\t}\n\n\t\tvoid incrementOrigin(uint32 size)\n\t\t{\n\t\t\tcurrentOrigin += size;\n\t\t\tif (currentOrigin <= 32 * 1024 * 1024)\n\t\t\t\tcodeCaveOrigin = std::max(codeCaveOrigin, currentOrigin);\n\t\t}\n\n\t\tuint32 currentOrigin{};\n\t\tuint32 codeCaveOrigin{};\n\t}originInfo;\n\t// labels dont get emitted immediately, instead they are assigned a VA after the next alignment zone\n\tstd::vector<PatchEntryLabel*> scheduledLabels; \n\t// this is to prevent code like this from putting alignment bytes after the label. (The label 'sticks' to the data after it)\n\t// .byte 123\n\t// Label:\n\t// BLR\n\n\tauto flushLabels = [&]()\n\t{\n\t\t// flush remaining labels\n\t\tfor (auto& itr : scheduledLabels)\n\t\t{\n\t\t\titr->setAssignedVA(originInfo.currentOrigin);\n\t\t\tcurrentGroup->list_patches.emplace_back(itr);\n\t\t}\n\t\tscheduledLabels.clear();\n\t};\n\n\twhile (true)\n\t{\n\t\tsize_t lineLength;\n\t\tauto lineStr = patchesStream.readLine();\n\t\tlineNumber++;\n\t\tif (patchesStream.hasError())\n\t\t\tbreak;\n\t\t// trim comment\n\t\tlineLength = GetLengthWithoutComment(lineStr.data(), lineStr.size());\n\n\t\tStringTokenParser parser(lineStr.data(), (sint32)lineLength);\n\n\t\t// skip whitespaces at the beginning\n\t\tparser.skipWhitespaces();\n\t\t// parse line\n\t\tif (parser.isEndOfString())\n\t\t\tcontinue;\n\t\tif (parser.compareCharacter(0, '['))\n\t\t{\n\t\t\t// group\n\t\t\tparser.skipCharacters(1);\n\t\t\t// find end of group name\n\t\t\tconst char* groupNameStr = parser.getCurrentPtr();\n\t\t\tsint32 groupNameLength = parser.skipToCharacter(']');\n\t\t\tif (groupNameLength < 0)\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Expected ']'\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tparser.skipCharacters(1); // skip the ']'\n\t\t\tparser.skipWhitespaces();\n\t\t\tif (!parser.isEndOfString())\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Unexpected characters after ']'\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// begin new group\n\t\t\tif (currentGroup)\n\t\t\t{\n\t\t\t\tflushLabels();\n\t\t\t\tAddPatchGroup(currentGroup);\n\t\t\t}\n\t\t\tcurrentGroup = new PatchGroup(this, groupNameStr, groupNameLength);\n\t\t\t// reset origin tracking\n\t\t\toriginInfo.reset();\n\t\t\tcontinue;\n\t\t}\n\t\telse if (parser.matchWordI(\"moduleMatches\"))\n\t\t{\n\t\t\tif (currentGroup == nullptr)\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Specified 'ModuleMatches' outside of a group\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (parser.matchWordI(\"=\") == false)\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Expected '=' after ModuleMatches\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// read the checksums\n\t\t\twhile (true)\n\t\t\t{\n                if (parser.matchWordI(\"rpx\"))\n                {\n                   \tcurrentGroup->m_isRpxOnlyTarget = true;\n                   \tbreak;\n                }\n\t\t\t\n\t\t\t\tuint32 checksum = 0;\n\t\t\t\tif (parser.parseU32(checksum) == false)\n\t\t\t\t{\n\t\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Invalid value for ModuleMatches\");\n\t\t\t\t\tCancelParsingPatches();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tcurrentGroup->list_moduleMatches.emplace_back(checksum);\n\t\t\t\tif (parser.matchWordI(\",\") == false)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tparser.skipWhitespaces();\n\t\t\tif (!parser.isEndOfString())\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Unexpected character\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// if a line starts with <hex_address> = then it temporarily overwrites the origin for the current line\n\t\tuint32 overwriteOrigin = INVALID_ORIGIN;\n\t\tif (parser.compareCharacter(0, '0') && parser.compareCharacterI(1, 'x'))\n\t\t{\n\t\t\tuint32 patchedAddress;\n\t\t\tif (!parser.parseU32(patchedAddress))\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Malformed address\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (parser.matchWordI(\"=\") == false)\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Expected '=' after address\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tparser.skipWhitespaces();\n\t\t\tparser.trimWhitespaces();\n\t\t\toverwriteOrigin = patchedAddress;\n\t\t}\n\t\t// check for known directives\n\t\tif (parser.matchWordI(\".origin\"))\n\t\t{\n\t\t\t// .origin = <origin> directive\n\t\t\tif (overwriteOrigin != INVALID_ORIGIN)\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, fmt::format(\".origin directive must appear alone without <address> = prefix.\"));\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (!parser.matchWordI(\"=\"))\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, fmt::format(\"Missing '=' after .origin\"));\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// parse origin\n\t\t\tuint32 originAddress;\n\t\t\tif (parser.matchWordI(\"codecave\"))\n\t\t\t{\n\t\t\t\t// keyword codecave means we set the origin to the end of the current known codecave size\n\t\t\t\toriginInfo.setOriginCodeCave();\n\t\t\t}\n\t\t\telse if(parser.parseU32(originAddress))\n\t\t\t{\n\t\t\t\t// hex address\n\t\t\t\toriginInfo.setOrigin(originAddress);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, fmt::format(\"\\'.origin =\\' must be followed by the keyword codecave or a valid address\"));\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\telse if (parser.matchWordI(\".callback\"))\n\t\t{\n\t\t    if (parser.matchWordI(\"entry\"))\n    \t\t{\n                const char* symbolStr;\n    \t\t\tsint32 symbolLen;\n    \t\t    if (parser.parseSymbolName(symbolStr, symbolLen))\n    \t\t    {\n    \t\t\t\tcurrentGroup->list_callbacks.push_back(std::make_pair(std::string(symbolStr, static_cast<size_t>(symbolLen)), GPCallbackType::Entry));\n    \t\t\t\tcontinue;\n    \t\t    }\n    \t\t    else\n    \t\t    {\n                    LogPatchesSyntaxError(lineNumber, \"'.callback' must reference a symbol after the type\");\n                    CancelParsingPatches();\n                    return false;\n    \t\t    }\n    \t\t}\n\t\t    else\n\t\t    {\n\t\t\t\tLogPatchesSyntaxError(lineNumber, \"Unrecognized type for '.callback'\");\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// next we attempt to parse symbol assignment\n\t\t// symbols can be labels or variables. The type is determined by what comes after the symbol name\n\t\t// <symbolName> = <expression> defines a variable\n\t\t// <symbolName>: defines a label\n\n\t\tStringTokenParser bakParser;\n\t\tconst char* symbolStr;\n\t\tsint32 symbolLen;\n\t\tparser.storeParserState(&bakParser);\n\n\t\t// check for pattern <symbolName>:\n\t\tif (parser.parseSymbolName(symbolStr, symbolLen) && parser.matchWordI(\":\"))\n\t\t{\n\t\t\t// label\n\t\t\tparser.skipWhitespaces();\n\t\t\tif (!parser.isEndOfString())\n\t\t\t{\n\t\t\t\tLogPatchesSyntaxError(lineNumber, fmt::format(\"Unexpected characters after label\"));\n\t\t\t\tCancelParsingPatches();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tuint32 labelAddress;\n\t\t\tif (overwriteOrigin != INVALID_ORIGIN)\n\t\t\t\tlabelAddress = overwriteOrigin;\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!originInfo.isValidOrigin())\n\t\t\t\t{\n\t\t\t\t\tLogPatchesSyntaxError(lineNumber, fmt::format(\"Defined label has no address assigned or there is no active .origin\"));\n\t\t\t\t\tCancelParsingPatches();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tlabelAddress = originInfo.currentOrigin;\n\t\t\t}\n\t\t\tif (overwriteOrigin == INVALID_ORIGIN)\n\t\t\t{\n\t\t\t\t// if label is part of code flow, delay emitting it until the next data instruction\n\t\t\t\t// this is so we can avoid generating alignment padding, whose size is unknown in advance, between labels and data instructions\n\t\t\t\tscheduledLabels.emplace_back(new PatchEntryLabel(lineNumber, symbolStr, symbolLen));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tPatchEntryLabel* patchLabel = new PatchEntryLabel(lineNumber, symbolStr, symbolLen);\n\t\t\t\tpatchLabel->setAssignedVA(labelAddress);\n\t\t\t\tcurrentGroup->list_patches.emplace_back(patchLabel);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tparser.restoreParserState(&bakParser);\n\t\t// check for pattern <symbolName> =\n\t\tif (parser.parseSymbolName(symbolStr, symbolLen) && parser.matchWordI(\"=\"))\n\t\t{\n\t\t\t// variable definition\n\t\t\tparser.skipWhitespaces();\n\t\t\tparser.trimWhitespaces();\n\t\t\tconst char* expressionStr = parser.getCurrentPtr();\n\t\t\tsint32 expressionLen = parser.getCurrentLen();\n\t\t\t// create entry for symbol/variable value assignment\n\t\t\tcurrentGroup->list_patches.emplace_back(new PatchEntryVariableValue(lineNumber, symbolStr, symbolLen, PATCHVARTYPE::UINT, expressionStr, expressionLen));\n\t\t\tcontinue;\n\t\t}\n\t\t// if all patterns mismatch then we assume it's an assembly instruction\n\t\tparser.restoreParserState(&bakParser);\n\t\tstd::string instrText(parser.getCurrentPtr(), parser.getCurrentLen());\n\t\tPPCAssemblerInOut ctx{};\n\t\tctx.forceNoAlignment = overwriteOrigin != INVALID_ORIGIN; // dont auto-align when a fixed address is assigned\n\t\tif (overwriteOrigin != INVALID_ORIGIN)\n\t\t\tctx.virtualAddress = overwriteOrigin;\n\t\telse if(originInfo.isValidOrigin())\n\t\t\tctx.virtualAddress = originInfo.currentOrigin;\n\t\telse\n\t\t{\n\t\t\tLogPatchesSyntaxError(lineNumber, fmt::format(\"Trying to assemble line but no address specified. (Declare .origin or prefix line with <address> = )\"));\n\t\t\tCancelParsingPatches();\n\t\t\treturn false;\n\t\t}\n\t\tif (!ppcAssembler_assembleSingleInstruction(instrText.c_str(), &ctx))\n\t\t{\n\t\t\tLogPatchesSyntaxError(lineNumber, fmt::format(\"Error in assembler: {}\", ctx.errorMsg));\n\t\t\tCancelParsingPatches();\n\t\t\treturn false;\n\t\t}\n\t\tcemu_assert_debug(ctx.alignmentRequirement != 0);\n\t\tif (overwriteOrigin == INVALID_ORIGIN)\n\t\t{\n\t\t\toriginInfo.incrementOrigin((sint32)ctx.alignmentPaddingSize); // alignment padding\t\n\t\t\toriginInfo.incrementOrigin((sint32)ctx.outputData.size()); // instruction size\n\t\t}\n\t\t// flush labels\n\t\tfor (auto& itr : scheduledLabels)\n\t\t{\n\t\t\titr->setAssignedVA(ctx.virtualAddressAligned);\n\t\t\tcurrentGroup->list_patches.emplace_back(itr);\n\t\t}\n\t\tscheduledLabels.clear();\n\t\t// append instruction\n\t\tcurrentGroup->list_patches.emplace_back(new PatchEntryInstruction(lineNumber, ctx.virtualAddressAligned, { ctx.outputData.data(), ctx.outputData.size() }, ctx.list_relocs));\n\t}\n\tflushLabels();\n\n\tif (currentGroup)\n\t\tAddPatchGroup(currentGroup);\n\treturn true;\n}\n"
  },
  {
    "path": "src/Cafe/GraphicPack/GraphicPackError.h",
    "content": "#pragma once\n\nclass PatchErrorHandler\n{\npublic:\n\tenum class STAGE\n\t{\n\t\tPARSER,\n\t\tAPPLY,\n\t};\n\n\n\tvoid setCurrentGraphicPack(class GraphicPack2* gp)\n\t{\n\t\tm_gp = gp;\n\t}\n\n\tvoid setStage(STAGE s)\n\t{\n\t\tm_stage = s;\n\t}\n\n\tvoid printError(class PatchGroup* patchGroup, sint32 lineNumber, std::string_view errorMsg);\n\tvoid showStageErrorMessageBox();\n\n\tbool hasError() const { return m_anyErrorTriggered; };\n\n\tclass GraphicPack2* m_gp{};\n\tbool m_anyErrorTriggered{};\n\tSTAGE m_stage{ STAGE::PARSER };\n\tstd::vector<std::string> errorMessages; // if patch logging is enabled also remember error msgs for the message box\n};\n"
  },
  {
    "path": "src/Cafe/HW/ACR/ACR.cpp",
    "content": "#include \"Cafe/HW/MMU/MMU.h\"\n#include \"Cafe/HW/Common/HwReg.h\"\n\nnamespace HW_ACR\n{\n\n\tstruct  \n\t{\n\t\tHWREG::ACR_VI_ADDR viAddr;\n\t\tHWREG::ACR_VI_CTRL viCtrl;\n\t}g_acr;\n\n\t/* \n\tIs this some kind of VI emulation interface? \n\tPattern seen in Twilight Princess HD:\n\t- If Hollywood hardware then read/write old 16bit GC VI register directly\n\t- Otherwise these steps are performed:\n\t\tVICONTROL |= 1\n\t\tVIADDR = registerIndex\n\t\tVIDATA = data\n\t\tVICONTROL &= ~1\n\t\tAll the register accesses here are 32bit\n\t*/\n\n\t/* 0x0D00021C | Accesses VI register currently selected by VIADDR */\n\tHWREG::ACR_VI_DATA ACR_VIDATA_R32(PAddr addr)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"ACR_VIDATA read with selected reg {:08x}\", g_acr.viAddr.get_ADDR());\n\t\treturn HWREG::ACR_VI_DATA();\n\t}\n\n\tvoid ACR_VIDATA_W32(PAddr addr, HWREG::ACR_VI_DATA newValue)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"ACR_VIDATA write {:08x} with selected reg {:08x}\", newValue.get_DATA(), g_acr.viAddr.get_ADDR());\n\t}\n\n\t/* 0x0D000224 | Controls the selected VI register? */\n\tHWREG::ACR_VI_ADDR ACR_VIADDR_R32(PAddr addr)\n\t{\n\t\treturn g_acr.viAddr;\n\t}\n\n\tvoid ACR_VIADDR_W32(PAddr addr, HWREG::ACR_VI_ADDR newValue)\n\t{\n\t\tg_acr.viAddr = newValue;\n\t}\n\n\t/* 0x0D000228 | Some kind of VI interface control? */\n\tHWREG::ACR_VI_CTRL ACR_VICONTROL_R32(PAddr addr)\n\t{\n\t\treturn g_acr.viCtrl;\n\t}\n\n\tvoid ACR_VICONTROL_W32(PAddr addr, HWREG::ACR_VI_CTRL newValue)\n\t{\n\t\tg_acr.viCtrl = newValue;\n\t}\n\n\tRunAtCemuBoot _initACR([]()\n\t{\n\t\tMMU::RegisterMMIO_32<HWREG::ACR_VI_DATA, ACR_VIDATA_R32, ACR_VIDATA_W32>(MMU::MMIOInterface::INTERFACE_0D000000, 0x21C);\n\t\tMMU::RegisterMMIO_32<HWREG::ACR_VI_ADDR, ACR_VIADDR_R32, ACR_VIADDR_W32>(MMU::MMIOInterface::INTERFACE_0D000000, 0x224);\n\t\tMMU::RegisterMMIO_32<HWREG::ACR_VI_CTRL, ACR_VICONTROL_R32, ACR_VICONTROL_W32>(MMU::MMIOInterface::INTERFACE_0D000000, 0x228);\n\n\t\t// init \n\t});\n\n}\n"
  },
  {
    "path": "src/Cafe/HW/AI/AI.cpp",
    "content": "#include \"Cafe/HW/MMU/MMU.h\"\n\n\nnamespace HW_AI\n{\n\n\tvoid AI_STATUS_W16(uint32 addr, uint16 value)\n\t{\n\n\t}\n\n\tRunAtCemuBoot _init([]()\n\t{\n\t\t//using MMIOFuncWrite16 = void (*)(uint32 addr, uint16 value);\n\t\t//using MMIOFuncWrite32 = void (*)(uint32 addr, uint32 value);\n\n\t\t//void RegisterMMIO_W16(MMIOFuncWrite16 ptr);\n\t});\n}\n"
  },
  {
    "path": "src/Cafe/HW/AI/AI.h",
    "content": ""
  },
  {
    "path": "src/Cafe/HW/Common/HwReg.h",
    "content": "#pragma once\n\nnamespace HWREG\n{\n\n#define REGISTER_FULL_FIELD(__regname) \\\nauto& set_##__regname(uint32 newValue) \\\n{\t\\\n\tv = newValue; \\\n    return *this; \\\n} \\\nuint32 get_##__regname() const \\\n{\t\\\n\treturn v; \\\n}\n\n#define REGISTER_BITFIELD(__regname, __bitIndex, __bitWidth) \\\nauto& set_##__regname(uint32 newValue) \\\n{\t\\\n\tcemu_assert_debug(newValue < (1u << (__bitWidth))); \\\n\tv &= ~((((1u << (__bitWidth)) - 1u) << (__bitIndex))); \\\n\tv |= (newValue << (__bitIndex)); \\\n    return *this; \\\n} \\\nuint32 get_##__regname() const \\\n{\t\\\n\treturn (v >> (__bitIndex))&((1u << (__bitWidth)) - 1u); \\\n}\n\n#define REGISTER_BITFIELD_SIGNED(__regname, __bitIndex, __bitWidth) \\\nauto& set_##__regname(sint32 newValue) \\\n{\t\\\n\tcemu_assert_debug(newValue < (1 << ((__bitWidth)-1))); \\\n\tcemu_assert_debug(newValue >= -(1 << ((__bitWidth)-1))); \\\n\tv &= ~((((1u << (__bitWidth)) - 1u) << (__bitIndex))); \\\n\tv |= (((uint32)newValue & ((1u << (__bitWidth)) - 1u)) << (__bitIndex)); \\\n    return *this; \\\n} \\\nsint32 get_##__regname() const \\\n{\t\\\n    sint32 r = (v >> (__bitIndex))&((1u << (__bitWidth)) - 1u); \\\n    r = (r << (32 - (__bitWidth))); \\\n    r = (r >> (32 - (__bitWidth))); \\\n\treturn r; \\\n}\n\n#define REGISTER_BITFIELD_BOOL(__regname, __bitIndex) \\\nauto& set_##__regname(bool newValue) \\\n{\t\\\n\tif(newValue) \\\n\tv |= (1u << (__bitIndex)); \\\n\telse \\\n\tv &= ~(1u << (__bitIndex)); \\\n    return *this; \\\n} \\\nbool get_##__regname() const \\\n{\t\\\n\treturn (v&(1u << (__bitIndex))) != 0; \\\n}\n\n#define REGISTER_BITFIELD_TYPED(__regname, __bitIndex, __bitWidth, __typename) \\\nauto& set_##__regname(__typename newValue) \\\n{\t\\\n\tcemu_assert_debug(static_cast<uint32>(newValue) < (1u << (__bitWidth))); \\\n\tv &= ~((((1u << (__bitWidth)) - 1u) << (__bitIndex))); \\\n\tv |= (static_cast<uint32>(newValue) << (__bitIndex)); \\\n    return *this; \\\n} \\\n__typename get_##__regname() const \\\n{\t\\\n\treturn static_cast<__typename>((v >> (__bitIndex))&((1u << (__bitWidth)) - 1u)); \\\n}\n\n#define REGISTER_BITFIELD_FLOAT(__regname) \\\nauto& set_##__regname(float newValue) \\\n{\t\\\n\t*(float*)&v = newValue; \\\n    return *this; \\\n} \\\nfloat get_##__regname() const \\\n{\t\\\n\treturn *(float*)&v; \\\n}\n\n\tclass HWREG\n\t{\n\tpublic:\n\t\tuint32 getRawValue() const\n\t\t{\n\t\t\treturn v;\n\t\t}\n\n\t\tuint32 getRawValueBE() const\n\t\t{\n\t\t\treturn _swapEndianU32(v);\n\t\t}\n\n\t\tvoid setFromRaw(uint32 regValue)\n\t\t{\n\t\t\tv = regValue;\n\t\t}\n\n\tprotected:\n\t\tuint32 v{};\n\t};\n\n\t/* ACR */\n\n\tstruct ACR_VI_DATA : HWREG // 0x0D00021C - official name unknown\n\t{\n\t\tREGISTER_FULL_FIELD(DATA);\n\t};\n\n\tstruct ACR_VI_ADDR : HWREG // 0x0D000224 - official name unknown\n\t{\n\t\tREGISTER_FULL_FIELD(ADDR);\n\t};\n\n\tstruct ACR_VI_CTRL : HWREG // 0x0D000228 - official name unknown\n\t{\n\t\tREGISTER_BITFIELD_BOOL(HAS_OWNERSHIP, 0); // exact purpose not understood\n\t\t// other fields unknown\n\t};\n\n\n\t/* SI */\n\n\tstruct SICOUTBUF : HWREG // 0x6400/0x640C/0x6418/0x6424\n\t{\n\t\tREGISTER_BITFIELD(OUTPUT1, 0, 8);\n\t\tREGISTER_BITFIELD(OUTPUT0, 8, 8);\n\t\tREGISTER_BITFIELD(CMD, 16, 8);\n\n\t};\n\n\tstruct SICINBUFH : HWREG // 0x6404/0x6410/0x641C/0x6428\n\t{\n\t\tREGISTER_BITFIELD(INPUT3, 0, 8);\n\t\tREGISTER_BITFIELD(INPUT2, 8, 8);\n\t\tREGISTER_BITFIELD(INPUT1, 16, 8);\n\t\tREGISTER_BITFIELD(INPUT0, 24, 6);\n\t\tREGISTER_BITFIELD(ERRLATCH, 30, 1);\n\t\tREGISTER_BITFIELD(ERRSTAT, 31, 1);\n\t};\n\n\tstruct SICINBUFL : HWREG // 0x6408/0x6414/0x6420/0x642C\n\t{\n\t\tREGISTER_BITFIELD(INPUT4, 0, 8);\n\t\tREGISTER_BITFIELD(INPUT5, 8, 8);\n\t\tREGISTER_BITFIELD(INPUT6, 16, 8);\n\t\tREGISTER_BITFIELD(INPUT7, 24, 8);\n\t};\n\n\tstruct SIPOLL : HWREG // 0x6430\n\t{\n\t\tREGISTER_BITFIELD(X, 16, 10);\n\t\tREGISTER_BITFIELD(Y, 8, 8);\n\t\tREGISTER_BITFIELD(EN, 4, 4);\n\t\tREGISTER_BITFIELD(VBCPY, 0, 4);\n\t};\n\n\tstruct SICOMCSR : HWREG // 0x6434\n\t{\n\t\tREGISTER_BITFIELD(TCINT, 31, 1);\n\t\tREGISTER_BITFIELD(TCINTMASK, 30, 1);\n\t\tREGISTER_BITFIELD(COMERR, 29, 1);\n\t\tREGISTER_BITFIELD(RDSTINT, 28, 1);\n\t\tREGISTER_BITFIELD(RDSTINTMSK, 27, 1);\n\t\tREGISTER_BITFIELD(UKN_CHANNEL_NUM_MAYBE, 25, 2);\n\t\tREGISTER_BITFIELD(CHANNELENABLE, 24, 1);\n\t\tREGISTER_BITFIELD(OUTLNGTH, 16, 7);\n\t\tREGISTER_BITFIELD(INLNGTH, 8, 7);\n\t\tREGISTER_BITFIELD(COMMAND_ENABLE, 7, 1);\n\t\tREGISTER_BITFIELD(CALLBACK_ENABLE, 6, 1);\n\t\tREGISTER_BITFIELD(CHANNEL, 1, 2);\n\t\tREGISTER_BITFIELD(TRANSFER_START, 0, 1);\n\t};\n\n\tstruct SISR : HWREG // 0x6438\n\t{\n\t\tREGISTER_BITFIELD(WR, 31, 1);\n\t\t// joy-channel 0\n\t\tREGISTER_BITFIELD(RDST0, 29, 1);\n\t\tREGISTER_BITFIELD(WRST0, 28, 1);\n\t\tREGISTER_BITFIELD(NOREP0, 27, 1);\n\t\tREGISTER_BITFIELD(COLL0, 26, 1);\n\t\tREGISTER_BITFIELD(OVRUN0, 25, 1);\n\t\tREGISTER_BITFIELD(UNRUN0, 24, 1);\n\t\t// joy-channel 1\n\t\tREGISTER_BITFIELD(RDST1, 21, 1);\n\t\tREGISTER_BITFIELD(WRST1, 20, 1);\n\t\tREGISTER_BITFIELD(NOREP1, 19, 1);\n\t\tREGISTER_BITFIELD(COLL1, 18, 1);\n\t\tREGISTER_BITFIELD(OVRUN1, 17, 1);\n\t\tREGISTER_BITFIELD(UNRUN1, 16, 1);\n\t\t// joy-channel 2\n\t\tREGISTER_BITFIELD(RDST2, 13, 1);\n\t\tREGISTER_BITFIELD(WRST2, 12, 1);\n\t\tREGISTER_BITFIELD(NOREP2, 11, 1);\n\t\tREGISTER_BITFIELD(COLL2, 10, 1);\n\t\tREGISTER_BITFIELD(OVRUN2, 9, 1);\n\t\tREGISTER_BITFIELD(UNRUN2, 8, 1);\n\t\t// joy-channel 3\n\t\tREGISTER_BITFIELD(RDST3, 5, 1);\n\t\tREGISTER_BITFIELD(WRST3, 4, 1);\n\t\tREGISTER_BITFIELD(NOREP3, 3, 1);\n\t\tREGISTER_BITFIELD(COLL3, 2, 1);\n\t\tREGISTER_BITFIELD(OVRUN3, 1, 1);\n\t\tREGISTER_BITFIELD(UNRUN3, 0, 1);\n\t};\n\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Const.h",
    "content": "#pragma once\n\nnamespace Espresso\n{\n\tconstexpr inline int CORE_COUNT = 3;\n\n\tconstexpr inline uint64 CORE_CLOCK = 1243125000;\n\tconstexpr inline uint64 BUS_CLOCK = 248625000;\n\tconstexpr inline uint64 TIMER_CLOCK = BUS_CLOCK / 4;\n\n\tconstexpr inline uint32 MEM_PAGE_SIZE = 0x20000;\n};"
  },
  {
    "path": "src/Cafe/HW/Espresso/Debugger/DebugSymbolStorage.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"DebugSymbolStorage.h\"\n\nFSpinlock DebugSymbolStorage::s_lock;\nstd::unordered_map<MPTR, DEBUG_SYMBOL_TYPE> DebugSymbolStorage::s_typeStorage;\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h",
    "content": "#pragma once\n#include \"util/helpers/fspinlock.h\"\n\nenum class DEBUG_SYMBOL_TYPE\n{\n\tUNDEFINED,\n\tCODE,\n\t// big-endian types\n\tU64,\n\tU32,\n\tU16,\n\tU8,\n\tS64,\n\tS32,\n\tS16,\n\tS8,\n\tFLOAT,\n\tDOUBLE,\n};\n\n\nclass DebugSymbolStorage\n{\npublic:\n\tstatic void StoreDataType(MPTR address, DEBUG_SYMBOL_TYPE type)\n\t{\n\t\ts_lock.lock();\n\t\ts_typeStorage[address] = type;\n\t\ts_lock.unlock();\n\t}\n\n\tstatic DEBUG_SYMBOL_TYPE GetDataType(MPTR address)\n\t{\n\t\ts_lock.lock();\n\t\tauto itr = s_typeStorage.find(address);\n\t\tif (itr == s_typeStorage.end())\n\t\t{\n\t\t\ts_lock.unlock();\n\t\t\treturn DEBUG_SYMBOL_TYPE::UNDEFINED;\n\t\t}\n\t\tDEBUG_SYMBOL_TYPE t = itr->second;\n\t\ts_lock.unlock();\n\t\treturn t;\n\t}\n\n\tstatic void ClearRange(MPTR address, uint32 length)\n\t{\n\t\tif (length == 0)\n\t\t\treturn;\n\t\ts_lock.lock();\n\t\tfor (;;)\n\t\t{\n\t\t\tauto itr = s_typeStorage.find(address);\n\t\t\tif (itr != s_typeStorage.end())\n\t\t\t\ts_typeStorage.erase(itr);\n\t\t\t\n\t\t\tif (length <= 4)\n\t\t\t\tbreak;\n\t\t\taddress += 4;\n\t\t\tlength -= 4;\n\t\t}\n\t\ts_lock.unlock();\n\t}\n\nprivate:\n\tstatic FSpinlock s_lock;\n\tstatic std::unordered_map<MPTR, DEBUG_SYMBOL_TYPE> s_typeStorage;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Debugger/Debugger.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"Debugger.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n#include \"Cemu/PPCAssembler/ppcAssembler.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n#include \"Cemu/ExpressionParser/ExpressionParser.h\"\n\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n#include \"OS/RPL/rpl.h\"\n#include \"util/helpers/helpers.h\"\n\n#if BOOST_OS_WINDOWS\n#include <Windows.h>\n#endif\n\nDebuggerDispatcher g_debuggerDispatcher;\n\ndebuggerState_t debuggerState{ };\n\nDebuggerBreakpoint* debugger_getFirstBP(uint32 address)\n{\n\tfor (auto& it : debuggerState.breakpoints)\n\t{\n\t\tif (it->address == address)\n\t\t\treturn it;\n\t}\n\treturn nullptr;\n}\n\nDebuggerBreakpoint* debugger_getFirstBP(uint32 address, uint8 bpType)\n{\n\tfor (auto& it : debuggerState.breakpoints)\n\t{\n\t\tif (it->address == address)\n\t\t{\n\t\t\tDebuggerBreakpoint* bpItr = it;\n\t\t\twhile (bpItr)\n\t\t\t{\n\t\t\t\tif (bpItr->bpType == bpType)\n\t\t\t\t\treturn bpItr;\n\t\t\t\tbpItr = bpItr->next;\n\t\t\t}\n\t\t\treturn nullptr;\n\t\t}\n\t}\n\treturn nullptr;\n}\n\nbool debuggerBPChain_hasType(DebuggerBreakpoint* bp, uint8 bpType)\n{\n\twhile (bp)\n\t{\n\t\tif (bp->bpType == bpType)\n\t\t\treturn true;\n\t\tbp = bp->next;\n\t}\n\treturn false;\n}\n\nvoid debuggerBPChain_add(uint32 address, DebuggerBreakpoint* bp)\n{\n\tbp->next = nullptr;\n\tDebuggerBreakpoint* existingBP = debugger_getFirstBP(address);\n\tif (existingBP)\n\t{\n\t\twhile (existingBP->next)\n\t\t\texistingBP = existingBP->next;\n\t\texistingBP->next = bp;\n\t\treturn;\n\t}\n\t// no breakpoint chain exists for this address\n\tdebuggerState.breakpoints.push_back(bp);\n}\n\nuint32 debugger_getAddressOriginalOpcode(uint32 address)\n{\n\tauto bpItr = debugger_getFirstBP(address);\n\twhile (bpItr)\n\t{\n\t\tif (bpItr->isExecuteBP())\n\t\t\treturn bpItr->originalOpcodeValue;\n\t\tbpItr = bpItr->next;\n\t}\n\treturn memory_readU32(address);\n}\n\nvoid debugger_updateMemoryU32(uint32 address, uint32 newValue)\n{\n\tbool memChanged = false;\n\tif (newValue != memory_readU32(address))\n\t\tmemChanged = true;\n\tmemory_writeU32(address, newValue);\n\tif(memChanged)\n\t\tPPCRecompiler_invalidateRange(address, address + 4);\n}\n\nvoid debugger_updateExecutionBreakpoint(uint32 address, bool forceRestore)\n{\n\tauto bpItr = debugger_getFirstBP(address);\n\tbool hasBP = false;\n\tuint32 originalOpcodeValue;\n\twhile (bpItr)\n\t{\n\t\tif (bpItr->isExecuteBP())\n\t\t{\n\t\t\tif (bpItr->enabled && forceRestore == false)\n\t\t\t{\n\t\t\t\t// write TW instruction to memory\n\t\t\t\tdebugger_updateMemoryU32(address, DEBUGGER_BP_T_DEBUGGER_TW);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\toriginalOpcodeValue = bpItr->originalOpcodeValue;\n\t\t\t\thasBP = true;\n\t\t\t}\n\t\t}\n\t\tbpItr = bpItr->next;\n\t}\n\tif (hasBP)\n\t{\n\t\t// restore instruction\n\t\tdebugger_updateMemoryU32(address, originalOpcodeValue);\n\t}\n}\n\nvoid debugger_createCodeBreakpoint(uint32 address, uint8 bpType)\n{\n\t// check if breakpoint already exists\n\tauto existingBP = debugger_getFirstBP(address);\n\tif (existingBP && debuggerBPChain_hasType(existingBP, bpType))\n\t\treturn; // breakpoint already exists\n\t// get original opcode at address\n\tuint32 originalOpcode = debugger_getAddressOriginalOpcode(address);\n\t// init breakpoint object\n\tDebuggerBreakpoint* bp = new DebuggerBreakpoint(address, originalOpcode, bpType, true);\n\tdebuggerBPChain_add(address, bp);\n\tdebugger_updateExecutionBreakpoint(address);\n}\n\nnamespace coreinit\n{\n\tstd::vector<std::thread::native_handle_type>& OSGetSchedulerThreads();\n}\n\nvoid debugger_updateMemoryBreakpoint(DebuggerBreakpoint* bp)\n{\n\tstd::vector<std::thread::native_handle_type> schedulerThreadHandles = coreinit::OSGetSchedulerThreads();\n\n#if BOOST_OS_WINDOWS\n\tdebuggerState.activeMemoryBreakpoint = bp;\n\tfor (auto& hThreadNH : schedulerThreadHandles)\n\t{\n\t\tHANDLE hThread = (HANDLE)hThreadNH;\n\t\tCONTEXT ctx{};\n\t\tctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;\n\t\tSuspendThread(hThread);\n\t\tGetThreadContext(hThread, &ctx);\n\t\tif (debuggerState.activeMemoryBreakpoint)\n\t\t{\n\t\t\tctx.Dr0 = (DWORD64)memory_getPointerFromVirtualOffset(bp->address);\n\t\t\tctx.Dr1 = (DWORD64)memory_getPointerFromVirtualOffset(bp->address);\n\t\t\t// breakpoint 0\n\t\t\tSetBits(ctx.Dr7, 0, 1, 1);  // breakpoint #0 enabled: true\n\t\t\tSetBits(ctx.Dr7, 16, 2, 1); // breakpoint #0 condition: 1 (write)\n\t\t\tSetBits(ctx.Dr7, 18, 2, 3); // breakpoint #0 length: 3 (4 bytes)\n\t\t\t// breakpoint 1\n\t\t\tSetBits(ctx.Dr7, 2, 1, 1);  // breakpoint #1 enabled: true\n\t\t\tSetBits(ctx.Dr7, 20, 2, 3); // breakpoint #1 condition: 3 (read & write)\n\t\t\tSetBits(ctx.Dr7, 22, 2, 3); // breakpoint #1 length: 3 (4 bytes)\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// breakpoint 0\n\t\t\tSetBits(ctx.Dr7, 0, 1, 0);  // breakpoint #0 enabled: false\n\t\t\tSetBits(ctx.Dr7, 16, 2, 0); // breakpoint #0 condition: 1 (write)\n\t\t\tSetBits(ctx.Dr7, 18, 2, 0); // breakpoint #0 length: 3 (4 bytes)\n\t\t\t// breakpoint 1\n\t\t\tSetBits(ctx.Dr7, 2, 1, 0);  // breakpoint #1 enabled: false\n\t\t\tSetBits(ctx.Dr7, 20, 2, 0); // breakpoint #1 condition: 3 (read & write)\n\t\t\tSetBits(ctx.Dr7, 22, 2, 0); // breakpoint #1 length: 3 (4 bytes)\n\t\t}\n\t\tSetThreadContext(hThread, &ctx);\n\t\tResumeThread(hThread);\n\t}\n\t#else\n\tcemuLog_log(LogType::Force, \"Debugger breakpoints are not supported\");\n\t#endif\n}\n\nvoid debugger_handleSingleStepException(uint64 dr6)\n{\n\tbool triggeredDR0 = GetBits(dr6, 0, 1); // write\n\tbool triggeredDR1 = GetBits(dr6, 1, 1); // read and write\n\tbool catchBP = false;\n\tif (triggeredDR0 && triggeredDR1)\n\t{\n\t\t// write (and read) access\n\t\tif (debuggerState.activeMemoryBreakpoint && debuggerState.activeMemoryBreakpoint->bpType == DEBUGGER_BP_T_MEMORY_WRITE)\n\t\t\tcatchBP = true;\n\t}\n\telse\n\t{\n\t\t// read access\n\t\tif (debuggerState.activeMemoryBreakpoint && debuggerState.activeMemoryBreakpoint->bpType == DEBUGGER_BP_T_MEMORY_READ)\n\t\t\tcatchBP = true;\n\t}\n\tif (catchBP)\n\t{\n\t\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\t\tif (debuggerState.logOnlyMemoryBreakpoints)\n\t\t{\n\t\t\tfloat memValueF = memory_readFloat(debuggerState.activeMemoryBreakpoint->address);\n\t\t\tuint32 memValue = memory_readU32(debuggerState.activeMemoryBreakpoint->address);\n\t\t\tcemuLog_log(LogType::Force, \"[Debugger] 0x{:08X} was read/written! New Value: 0x{:08X} (float {}) IP: {:08X} LR: {:08X}\",\n\t\t\t\tdebuggerState.activeMemoryBreakpoint->address,\n\t\t\t\tmemValue,\n\t\t\t\tmemValueF,\n\t\t\t\thCPU->instructionPointer,\n\t\t\t\thCPU->spr.LR\n\t\t\t);\n\t\t\tif (cemuLog_advancedPPCLoggingEnabled())\n\t\t\t\tDebugLogStackTrace(coreinit::OSGetCurrentThread(), hCPU->gpr[1]);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugger_createCodeBreakpoint(hCPU->instructionPointer + 4, DEBUGGER_BP_T_ONE_SHOT);\n\t\t}\n\t}\n}\n\nvoid debugger_createMemoryBreakpoint(uint32 address, bool onRead, bool onWrite)\n{\n\t// init breakpoint object\n\tuint8 bpType;\n\tif (onRead && onWrite)\n\t\tassert_dbg();\n\telse if (onRead)\n\t\tbpType = DEBUGGER_BP_T_MEMORY_READ;\n\telse\n\t\tbpType = DEBUGGER_BP_T_MEMORY_WRITE;\n\n\tDebuggerBreakpoint* bp = new DebuggerBreakpoint(address, 0xFFFFFFFF, bpType, true);\n\tdebuggerBPChain_add(address, bp);\n\t// disable any already existing memory breakpoint\n\tif (debuggerState.activeMemoryBreakpoint)\n\t{\n\t\tdebuggerState.activeMemoryBreakpoint->enabled = false;\n\t\tdebuggerState.activeMemoryBreakpoint = nullptr;\n\t}\n\t// activate new breakpoint\n\tdebugger_updateMemoryBreakpoint(bp);\n}\n\nvoid debugger_handleEntryBreakpoint(uint32 address)\n{\n\tif (!debuggerState.breakOnEntry)\n\t\treturn;\n\n\tdebugger_createCodeBreakpoint(address, DEBUGGER_BP_T_NORMAL);\n}\n\nvoid debugger_deleteBreakpoint(DebuggerBreakpoint* bp)\n{\n\tfor (auto& it : debuggerState.breakpoints)\n\t{\n\t\tif (it->address == bp->address)\n\t\t{\n\t\t\t// for execution breakpoints make sure the instruction is restored\n\t\t\tif (bp->isExecuteBP())\n\t\t\t{\n\t\t\t\tbp->enabled = false;\n\t\t\t\tdebugger_updateExecutionBreakpoint(bp->address);\n\t\t\t}\n\t\t\t// remove\n\t\t\tif (it == bp)\n\t\t\t{\n\t\t\t\t// remove first in list\n\t\t\t\tdebuggerState.breakpoints.erase(std::remove(debuggerState.breakpoints.begin(), debuggerState.breakpoints.end(), bp), debuggerState.breakpoints.end());\n\t\t\t\tDebuggerBreakpoint* nextBP = bp->next;\n\t\t\t\tif (nextBP)\n\t\t\t\t\tdebuggerState.breakpoints.push_back(nextBP);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// remove from list\n\t\t\t\tDebuggerBreakpoint* bpItr = it;\n\t\t\t\twhile (bpItr->next != bp)\n\t\t\t\t{\n\t\t\t\t\tbpItr = bpItr->next;\n\t\t\t\t}\n\t\t\t\tcemu_assert_debug(bpItr->next != bp);\n\t\t\t\tbpItr->next = bp->next;\n\t\t\t}\n\t\t\tdelete bp;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nvoid debugger_toggleExecuteBreakpoint(uint32 address)\n{\n\tauto existingBP = debugger_getFirstBP(address, DEBUGGER_BP_T_NORMAL);\n\tif (existingBP)\n\t{ \n\t\t// delete existing breakpoint\n\t\tdebugger_deleteBreakpoint(existingBP);\n\t}\n\telse\n\t{\n\t\t// create new execution breakpoint\n\t\tdebugger_createCodeBreakpoint(address, DEBUGGER_BP_T_NORMAL);\n\t}\n}\n\nvoid debugger_toggleLoggingBreakpoint(uint32 address)\n{\n\tauto existingBP = debugger_getFirstBP(address, DEBUGGER_BP_T_LOGGING);\n\tif (existingBP)\n\t{\n\t\t// delete existing breakpoint\n\t\tdebugger_deleteBreakpoint(existingBP);\n\t}\n\telse\n\t{\n\t\t// create new logging breakpoint\n\t\tdebugger_createCodeBreakpoint(address, DEBUGGER_BP_T_LOGGING);\n\t}\n}\n\nvoid debugger_forceBreak()\n{\n\tdebuggerState.debugSession.shouldBreak = true;\n}\n\nbool debugger_isTrapped()\n{\n\treturn debuggerState.debugSession.isTrapped;\n}\n\nvoid debugger_resume()\n{\n\t// if there is a breakpoint on the current instruction then do a single 'step into' to skip it\n\tdebuggerState.debugSession.run = true;\n}\n\nvoid debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* bp)\n{\n\tDebuggerBreakpoint* bpItr = debugger_getFirstBP(address);\n\twhile (bpItr)\n\t{\n\t\tif (bpItr == bp)\n\t\t{\n\t\t\tif (bpItr->bpType == DEBUGGER_BP_T_NORMAL || bpItr->bpType == DEBUGGER_BP_T_LOGGING)\n\t\t\t{\n\t\t\t\tbp->enabled = state;\n\t\t\t\tdebugger_updateExecutionBreakpoint(address);\n\t\t\t\tg_debuggerDispatcher.UpdateViewThreadsafe();\n\t\t\t}\n\t\t\telse if (bpItr->isMemBP())\n\t\t\t{\n\t\t\t\t// disable other memory breakpoints\n\t\t\t\tfor (auto& it : debuggerState.breakpoints)\n\t\t\t\t{\n\t\t\t\t\tDebuggerBreakpoint* bpItr2 = it;\n\t\t\t\t\twhile (bpItr2)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (bpItr2->isMemBP() && bpItr2 != bp)\n\t\t\t\t\t\t{ \n\t\t\t\t\t\t\tbpItr2->enabled = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbpItr2 = bpItr2->next;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbpItr->enabled = state;\n\t\t\t\tif (state)\n\t\t\t\t\tdebugger_updateMemoryBreakpoint(bpItr);\n\t\t\t\telse\n\t\t\t\t\tdebugger_updateMemoryBreakpoint(nullptr);\n\t\t\t\tg_debuggerDispatcher.UpdateViewThreadsafe();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tbpItr = bpItr->next;\n\t}\n}\n\nvoid debugger_createPatch(uint32 address, std::span<uint8> patchData)\n{\n\tDebuggerPatch* patch = new DebuggerPatch();\n\tpatch->address = address;\n\tpatch->length = patchData.size();\n\tpatch->data.resize(4);\n\tpatch->origData.resize(4);\n\tmemcpy(&patch->data.front(), patchData.data(), patchData.size());\n\tmemcpy(&patch->origData.front(), memory_getPointerFromVirtualOffset(address), patchData.size());\n\t// get original data from breakpoints\n\tif ((address & 3) != 0)\n\t\tcemu_assert_debug(false);\n\tfor (sint32 i = 0; i < patchData.size() / 4; i++)\n\t{\n\t\tDebuggerBreakpoint* bpItr = debugger_getFirstBP(address);\n\t\twhile (bpItr)\n\t\t{\n\t\t\tif (bpItr->isExecuteBP())\n\t\t\t{\n\t\t\t\t*(uint32*)(&patch->origData.front() + i * 4) = _swapEndianU32(bpItr->originalOpcodeValue);\n\t\t\t}\n\t\t\tbpItr = bpItr->next;\n\t\t}\n\t}\n\t// merge with existing patches if the ranges touch\n\tfor(sint32 i=0; i<debuggerState.patches.size(); i++)\n\t{\n\t\tauto& patchItr = debuggerState.patches[i];\n\t\tif (address + patchData.size() >= patchItr->address && address <= patchItr->address + patchItr->length)\n\t\t{\n\t\t\tuint32 newAddress = std::min(patch->address, patchItr->address);\n\t\t\tuint32 newEndAddress = std::max(patch->address + patch->length, patchItr->address + patchItr->length);\n\t\t\tuint32 newLength = newEndAddress - newAddress;\n\n\t\t\tDebuggerPatch* newPatch = new DebuggerPatch();\n\t\t\tnewPatch->address = newAddress;\n\t\t\tnewPatch->length = newLength;\n\t\t\tnewPatch->data.resize(newLength);\n\t\t\tnewPatch->origData.resize(newLength);\n\t\t\tmemcpy(&newPatch->data.front() + (address - newAddress), &patch->data.front(), patch->length);\n\t\t\tmemcpy(&newPatch->data.front() + (patchItr->address - newAddress), &patchItr->data.front(), patchItr->length);\n\n\t\t\tmemcpy(&newPatch->origData.front() + (address - newAddress), &patch->origData.front(), patch->length);\n\t\t\tmemcpy(&newPatch->origData.front() + (patchItr->address - newAddress), &patchItr->origData.front(), patchItr->length);\n\n\t\t\tdelete patch;\n\t\t\tpatch = newPatch;\n\t\t\tdelete patchItr;\n\t\t\t// remove currently iterated patch\n\t\t\tdebuggerState.patches.erase(debuggerState.patches.begin()+i);\n\t\t\ti--;\n\t\t}\n\t}\n\tdebuggerState.patches.push_back(patch);\n\t// apply patch (if breakpoints exist then update those instead of actual data)\n\tif ((address & 3) != 0)\n\t\tcemu_assert_debug(false);\n\tif ((patchData.size() & 3) != 0)\n\t\tcemu_assert_debug(false);\n\tfor (sint32 i = 0; i < patchData.size() / 4; i++)\n\t{\n\t\tDebuggerBreakpoint* bpItr = debugger_getFirstBP(address);\n\t\tbool hasActiveExecuteBP = false;\n\t\twhile (bpItr)\n\t\t{\n\t\t\tif (bpItr->isExecuteBP())\n\t\t\t{\n\t\t\t\tbpItr->originalOpcodeValue = *(uint32be*)(patchData.data() + i * 4);\n\t\t\t\tif (bpItr->enabled)\n\t\t\t\t\thasActiveExecuteBP = true;\n\t\t\t}\n\t\t\tbpItr = bpItr->next;\n\t\t}\n\t\tif (hasActiveExecuteBP == false)\n\t\t{\n\t\t\tmemcpy(memory_getPointerFromVirtualOffset(address + i * 4), patchData.data() + i * 4, 4);\n\t\t\tPPCRecompiler_invalidateRange(address, address + 4);\n\t\t}\n\t}\n}\n\nbool debugger_hasPatch(uint32 address)\n{\n\tfor (auto& patch : debuggerState.patches)\n\t{\n\t\tif (address + 4 > patch->address && address < patch->address + patch->length)\n\t\t\treturn true;\n\t}\n\treturn false;\n}\n\nvoid debugger_removePatch(uint32 address)\n{\n\tfor (sint32 i = 0; i < debuggerState.patches.size(); i++)\n\t{\n\t\tauto& patch = debuggerState.patches[i];\n\t\tif (address < patch->address || address >= (patch->address + patch->length))\n\t\t\tcontinue;\n\t\tMPTR startAddress = patch->address;\n\t\tMPTR endAddress = patch->address + patch->length;\n\t\t// remove any breakpoints overlapping with the patch\n\t\tfor (auto& bp : debuggerState.breakpoints)\n\t\t{\n\t\t\tif (bp->address + 4 > startAddress && bp->address < endAddress)\n\t\t\t{\n\t\t\t\tbp->enabled = false;\n\t\t\t\tdebugger_updateExecutionBreakpoint(bp->address);\n\t\t\t}\n\t\t}\n\t\t// restore original data\n\t\tmemcpy(MEMPTR<void>(startAddress).GetPtr(), patch->origData.data(), patch->length);\n\t\tPPCRecompiler_invalidateRange(startAddress, endAddress);\n\t\t// remove patch\n\t\tdelete patch;\n\t\tdebuggerState.patches.erase(debuggerState.patches.begin() + i);\n\t\treturn;\n\t}\n}\n\nvoid debugger_stepInto(PPCInterpreter_t* hCPU, bool updateDebuggerWindow = true)\n{\n\tbool isRecEnabled = ppcRecompilerEnabled;\n\tppcRecompilerEnabled = false;\n\tuint32 initialIP = debuggerState.debugSession.instructionPointer;\n\tdebugger_updateExecutionBreakpoint(initialIP, true);\n\tPPCInterpreterSlim_executeInstruction(hCPU);\n\tdebugger_updateExecutionBreakpoint(initialIP);\n\tdebuggerState.debugSession.instructionPointer = hCPU->instructionPointer;\n\tif(updateDebuggerWindow)\n\t\tg_debuggerDispatcher.MoveIP();\n\tppcRecompilerEnabled = isRecEnabled;\n}\n\nbool debugger_stepOver(PPCInterpreter_t* hCPU)\n{\n\tbool isRecEnabled = ppcRecompilerEnabled;\n\tppcRecompilerEnabled = false;\n\t// disassemble current instruction\n\tPPCDisassembledInstruction disasmInstr = { 0 };\n\tuint32 initialIP = debuggerState.debugSession.instructionPointer;\n\tdebugger_updateExecutionBreakpoint(initialIP, true);\n\tppcAssembler_disassemble(initialIP, memory_readU32(initialIP), &disasmInstr);\n\tif (disasmInstr.ppcAsmCode != PPCASM_OP_BL &&\n\t\tdisasmInstr.ppcAsmCode != PPCASM_OP_BCTRL)\n\t{\n\t\t// nothing to skip, use step-into\n\t\tdebugger_stepInto(hCPU);\n\t\tdebugger_updateExecutionBreakpoint(initialIP);\n\t\tg_debuggerDispatcher.MoveIP();\n\t\tppcRecompilerEnabled = isRecEnabled;\n\t\treturn false;\n\t}\n\t// create one-shot breakpoint at next instruction\n\tdebugger_createCodeBreakpoint(initialIP + 4, DEBUGGER_BP_T_ONE_SHOT);\n\t// step over current instruction (to avoid breakpoint)\n\tdebugger_stepInto(hCPU);\n\tg_debuggerDispatcher.MoveIP();\n\t// restore breakpoints\n\tdebugger_updateExecutionBreakpoint(initialIP);\n\t// run\n\tppcRecompilerEnabled = isRecEnabled;\n\treturn true;\n}\n\nvoid debugger_createPPCStateSnapshot(PPCInterpreter_t* hCPU)\n{\n\tmemcpy(debuggerState.debugSession.ppcSnapshot.gpr, hCPU->gpr, sizeof(uint32) * 32);\n\tmemcpy(debuggerState.debugSession.ppcSnapshot.fpr, hCPU->fpr, sizeof(FPR_t) * 32);\n\tdebuggerState.debugSession.ppcSnapshot.spr_lr = hCPU->spr.LR;\n\tfor (uint32 i = 0; i < 32; i++)\n\t\tdebuggerState.debugSession.ppcSnapshot.cr[i] = hCPU->cr[i];\n}\n\nvoid debugger_enterTW(PPCInterpreter_t* hCPU)\n{\n\t// Currently, we don't support multiple threads inside the debugger. Spin loop a thread if we already paused for another breakpoint hit.\n\twhile (debuggerState.debugSession.isTrapped)\n\t{\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t}\n\n\t// handle logging points\n\tDebuggerBreakpoint* bp = debugger_getFirstBP(hCPU->instructionPointer);\n\tbool shouldBreak = debuggerBPChain_hasType(bp, DEBUGGER_BP_T_NORMAL) || debuggerBPChain_hasType(bp, DEBUGGER_BP_T_ONE_SHOT);\n\twhile (bp)\n\t{\n\t\tif (bp->bpType == DEBUGGER_BP_T_LOGGING && bp->enabled)\n\t\t{\n\t\t\tstd::string comment = !bp->comment.empty() ? boost::nowide::narrow(bp->comment) : fmt::format(\"Breakpoint at 0x{:08X} (no comment)\", bp->address);\n\n\t\t\tauto replacePlaceholders = [&](const std::string& prefix, const auto& formatFunc)\n\t\t\t{\n\t\t\t\tsize_t pos = 0;\n\t\t\t\twhile ((pos = comment.find(prefix, pos)) != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\tsize_t endPos = comment.find('}', pos);\n\t\t\t\t\tif (endPos == std::string::npos)\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tif (int regNum = ConvertString<int>(comment.substr(pos + prefix.length(), endPos - pos - prefix.length())); regNum >= 0 && regNum < 32)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstd::string replacement = formatFunc(regNum);\n\t\t\t\t\t\t\tcomment.replace(pos, endPos - pos + 1, replacement);\n\t\t\t\t\t\t\tpos += replacement.length();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpos = endPos + 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch (...)\n\t\t\t\t\t{\n\t\t\t\t\t\tpos = endPos + 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Replace integer register placeholders {rX}\n\t\t\treplacePlaceholders(\"{r\", [&](int regNum) {\n\t\t\t\treturn fmt::format(\"0x{:08X}\", hCPU->gpr[regNum]);\n\t\t\t});\n\n\t\t\t// Replace floating point register placeholders {fX}\n\t\t\treplacePlaceholders(\"{f\", [&](int regNum) {\n\t\t\t\treturn fmt::format(\"{}\", hCPU->fpr[regNum].fpr);\n\t\t\t});\n\n\t\t\tstd::string logName = \"Breakpoint '\" + comment + \"'\";\n\t\t\tstd::string logContext = fmt::format(\"Thread: {:08x} LR: 0x{:08x}\", MEMPTR<OSThread_t>(coreinit::OSGetCurrentThread()).GetMPTR(), hCPU->spr.LR, cemuLog_advancedPPCLoggingEnabled() ? \" Stack Trace:\" : \"\");\n\t\t\tcemuLog_log(LogType::Force, \"[Debugger] {} was executed! {}\", logName, logContext);\n\t\t\tif (cemuLog_advancedPPCLoggingEnabled())\n\t\t\t\tDebugLogStackTrace(coreinit::OSGetCurrentThread(), hCPU->gpr[1]);\n\t\t\tbreak;\n\t\t}\n\t\tbp = bp->next;\n\t}\n\n\t// return early if it's only a non-pausing logging breakpoint to prevent a modified debugger state and GUI updates\n\tif (!shouldBreak)\n\t{\n\t\tuint32 backupIP = debuggerState.debugSession.instructionPointer;\n\t\tdebuggerState.debugSession.instructionPointer = hCPU->instructionPointer;\n\t\tdebugger_stepInto(hCPU, false);\n\t\tPPCInterpreterSlim_executeInstruction(hCPU);\n\t\tdebuggerState.debugSession.instructionPointer = backupIP;\n\t\treturn;\n\t}\n\n\t// handle breakpoints\n\tdebuggerState.debugSession.isTrapped = true;\n\tdebuggerState.debugSession.debuggedThreadMPTR = MEMPTR<OSThread_t>(coreinit::OSGetCurrentThread()).GetMPTR();\n\tdebuggerState.debugSession.instructionPointer = hCPU->instructionPointer;\n\tdebuggerState.debugSession.hCPU = hCPU;\n\tdebugger_createPPCStateSnapshot(hCPU);\n\t// remove one-shot breakpoint if it exists\n\tDebuggerBreakpoint* singleshotBP = debugger_getFirstBP(debuggerState.debugSession.instructionPointer, DEBUGGER_BP_T_ONE_SHOT);\n\tif (singleshotBP)\n\t\tdebugger_deleteBreakpoint(singleshotBP);\n\tg_debuggerDispatcher.NotifyDebugBreakpointHit();\n\tg_debuggerDispatcher.UpdateViewThreadsafe();\n\t// reset step control\n\tdebuggerState.debugSession.stepInto = false;\n\tdebuggerState.debugSession.stepOver = false;\n\tdebuggerState.debugSession.run = false;\n\twhile (debuggerState.debugSession.isTrapped)\n\t{\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\t// check for step commands\n\t\tif (debuggerState.debugSession.stepOver)\n\t\t{\n\t\t\tif (debugger_stepOver(hCPU))\n\t\t\t{\n\t\t\t\tdebugger_createPPCStateSnapshot(hCPU);\n\t\t\t\tbreak; // if true is returned, continue with execution\n\t\t\t}\n\t\t\tdebugger_createPPCStateSnapshot(hCPU);\n\t\t\tg_debuggerDispatcher.UpdateViewThreadsafe();\n\t\t\tdebuggerState.debugSession.stepOver = false;\n\t\t}\n\t\tif (debuggerState.debugSession.stepInto)\n\t\t{\n\t\t\tdebugger_stepInto(hCPU);\n\t\t\tdebugger_createPPCStateSnapshot(hCPU);\n\t\t\tg_debuggerDispatcher.UpdateViewThreadsafe();\n\t\t\tdebuggerState.debugSession.stepInto = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (debuggerState.debugSession.run)\n\t\t{\n\t\t\tdebugger_createPPCStateSnapshot(hCPU);\n\t\t\tdebugger_stepInto(hCPU, false);\n\t\t\tPPCInterpreterSlim_executeInstruction(hCPU);\n\t\t\tdebuggerState.debugSession.instructionPointer = hCPU->instructionPointer;\n\t\t\tdebuggerState.debugSession.run = false;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tdebuggerState.debugSession.isTrapped = false;\n\tdebuggerState.debugSession.hCPU = nullptr;\n\tg_debuggerDispatcher.UpdateViewThreadsafe();\n\tg_debuggerDispatcher.NotifyRun();\n}\n\nvoid debugger_shouldBreak(PPCInterpreter_t* hCPU)\n{\n\tif(debuggerState.debugSession.shouldBreak \n\t\t// exclude emulator trampoline area\n\t\t&& (hCPU->instructionPointer < MEMORY_CODE_TRAMPOLINE_AREA_ADDR || hCPU->instructionPointer > MEMORY_CODE_TRAMPOLINE_AREA_ADDR + MEMORY_CODE_TRAMPOLINE_AREA_SIZE))\n\t{\n\t\tdebuggerState.debugSession.shouldBreak = false;\n\n\t\tconst uint32 address = (uint32)hCPU->instructionPointer;\n\t\tassert_dbg();\n\t\t//debugger_createBreakpoint(address, DEBUGGER_BP_TYPE_ONE_SHOT);\n\t}\n}\n\nvoid debugger_addParserSymbols(class ExpressionParser& ep)\n{\n\tconst auto module_count = RPLLoader_GetModuleCount();\n\tconst auto module_list = RPLLoader_GetModuleList();\n\n\tstd::vector<double> module_tmp(module_count);\n\tfor (int i = 0; i < module_count; i++)\n\t{\n\t\tconst auto module = module_list[i];\n\t\tif (module)\n\t\t{\n\t\t\tmodule_tmp[i] = (double)module->regionMappingBase_text.GetMPTR();\n\t\t\tep.AddConstant(module->moduleName2, module_tmp[i]);\n\t\t}\n\t}\n\n\tfor (sint32 i = 0; i < 32; i++)\n\t\tep.AddConstant(fmt::format(\"r{}\", i), debuggerState.debugSession.ppcSnapshot.gpr[i]);\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Debugger/Debugger.h",
    "content": "#pragma once\n\n#include <set>\n#include \"Cafe/HW/Espresso/PPCState.h\"\n\n#define DEBUGGER_BP_T_NORMAL\t\t0 // normal breakpoint\n#define DEBUGGER_BP_T_ONE_SHOT\t\t1 // normal breakpoint, deletes itself after trigger (used for stepping)\n#define DEBUGGER_BP_T_MEMORY_READ\t2 // memory breakpoint\n#define DEBUGGER_BP_T_MEMORY_WRITE\t3 // memory breakpoint\n#define DEBUGGER_BP_T_LOGGING\t\t4 // logging breakpoint, prints the breakpoint comment and stack trace whenever hit\n\n#define DEBUGGER_BP_T_GDBSTUB\t\t1 // breakpoint created by GDBStub\n#define DEBUGGER_BP_T_DEBUGGER\t\t2 // breakpoint created by Cemu's debugger\n\n#define DEBUGGER_BP_T_GDBSTUB_TW    0x7C010008\n#define DEBUGGER_BP_T_DEBUGGER_TW   0x7C020008\n\nclass DebuggerCallbacks\n{\n  public:\n\tvirtual void UpdateViewThreadsafe() {}\n\tvirtual void NotifyDebugBreakpointHit() {}\n\tvirtual void NotifyRun() {}\n\tvirtual void MoveIP() {}\n\tvirtual void NotifyModuleLoaded(void* module) {}\n\tvirtual void NotifyModuleUnloaded(void* module) {}\n\tvirtual void NotifyGraphicPacksModified() {}\n\tvirtual ~DebuggerCallbacks() = default;\n};\n\nclass DebuggerDispatcher\n{\n  private:\n\tstatic inline class DefaultDebuggerCallbacks : public DebuggerCallbacks\n\t{\n\t} s_defaultDebuggerCallbacks;\n\tDebuggerCallbacks* m_callbacks = &s_defaultDebuggerCallbacks;\n\n  public:\n\tvoid SetDebuggerCallbacks(DebuggerCallbacks* debuggerCallbacks)\n\t{\n\t\tcemu_assert_debug(m_callbacks == &s_defaultDebuggerCallbacks);\n\t\tm_callbacks = debuggerCallbacks;\n\t}\n\n\tvoid ClearDebuggerCallbacks()\n\t{\n\t\tcemu_assert_debug(m_callbacks != &s_defaultDebuggerCallbacks);\n\t\tm_callbacks = &s_defaultDebuggerCallbacks;\n\t}\n\n\tvoid UpdateViewThreadsafe()\n\t{\n\t\tm_callbacks->UpdateViewThreadsafe();\n\t}\n\n\tvoid NotifyDebugBreakpointHit()\n\t{\n\t\tm_callbacks->NotifyDebugBreakpointHit();\n\t}\n\n\tvoid NotifyRun()\n\t{\n\t\tm_callbacks->NotifyRun();\n\t}\n\n\tvoid MoveIP()\n\t{\n\t\tm_callbacks->MoveIP();\n\t}\n\n\tvoid NotifyModuleLoaded(void* module)\n\t{\n\t\tm_callbacks->NotifyModuleLoaded(module);\n\t}\n\n\tvoid NotifyModuleUnloaded(void* module)\n\t{\n\t\tm_callbacks->NotifyModuleUnloaded(module);\n\t}\n\n\tvoid NotifyGraphicPacksModified()\n\t{\n\t\tm_callbacks->NotifyGraphicPacksModified();\n\t}\n} extern g_debuggerDispatcher;\n\nstruct DebuggerBreakpoint\n{\n\tuint32 address;\n\tuint32 originalOpcodeValue;\n\tmutable uint8 bpType;\n\tmutable bool enabled;\n\tmutable std::wstring comment;\n\tmutable uint8 dbType = DEBUGGER_BP_T_DEBUGGER;\n\n\tDebuggerBreakpoint(uint32 address, uint32 originalOpcode, uint8 bpType = 0, bool enabled = true, std::wstring comment = std::wstring())\n\t\t:address(address), originalOpcodeValue(originalOpcode), bpType(bpType), enabled(enabled), comment(std::move(comment)) \n\t{\n\t\tnext = nullptr;\n\t}\n\n\n\tbool operator<(const DebuggerBreakpoint& rhs) const\n\t{\n\t\treturn address < rhs.address;\n\t}\n\tbool operator==(const DebuggerBreakpoint& rhs) const\n\t{\n\t\treturn address == rhs.address;\n\t}\n\n\tbool isExecuteBP() const\n\t{\n\t\treturn bpType == DEBUGGER_BP_T_NORMAL || bpType == DEBUGGER_BP_T_LOGGING || bpType == DEBUGGER_BP_T_ONE_SHOT;\n\t}\n\n\tbool isMemBP() const\n\t{\n\t\treturn bpType == DEBUGGER_BP_T_MEMORY_READ || bpType == DEBUGGER_BP_T_MEMORY_WRITE;\n\t}\n\n\tDebuggerBreakpoint* next;\n};\n\nstruct DebuggerPatch \n{\n\tuint32 address;\n\tsint32 length;\n\tstd::vector<uint8> data;\n\tstd::vector<uint8> origData;\n};\n\nstruct PPCSnapshot\n{\n\tuint32 gpr[32];\n\tFPR_t fpr[32];\n\tuint8 cr[32];\n\tuint32 spr_lr;\n};\n\ntypedef struct  \n{\n\tbool breakOnEntry;\n\tbool logOnlyMemoryBreakpoints;\n\t// breakpoints\n\tstd::vector<DebuggerBreakpoint*> breakpoints;\n\tstd::vector<DebuggerPatch*> patches;\n\tDebuggerBreakpoint* activeMemoryBreakpoint;\n\t// debugging state\n\tstruct  \n\t{\n\t\tvolatile bool shouldBreak; // debugger window requests a break asap\n\t\tvolatile bool isTrapped; // if set, breakpoint is active and stepping through the code is possible\n\t\tuint32 debuggedThreadMPTR;\n\t\tvolatile uint32 instructionPointer;\n\t\tPPCInterpreter_t* hCPU;\n\t\t// step control\n\t\tvolatile bool stepOver;\n\t\tvolatile bool stepInto;\n\t\tvolatile bool run;\n\t\t// snapshot of PPC state\n\t\tPPCSnapshot ppcSnapshot;\n\t}debugSession;\n\n}debuggerState_t;\n\nextern debuggerState_t debuggerState;\n\n// new API\nDebuggerBreakpoint* debugger_getFirstBP(uint32 address);\nvoid debugger_createCodeBreakpoint(uint32 address, uint8 bpType);\nvoid debugger_toggleExecuteBreakpoint(uint32 address); // create/remove execute breakpoint\nvoid debugger_toggleLoggingBreakpoint(uint32 address); // create/remove logging breakpoint\nvoid debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* bp);\n\nvoid debugger_createMemoryBreakpoint(uint32 address, bool onRead, bool onWrite);\n\nvoid debugger_handleEntryBreakpoint(uint32 address);\n\nvoid debugger_deleteBreakpoint(DebuggerBreakpoint* bp);\n\nvoid debugger_updateExecutionBreakpoint(uint32 address, bool forceRestore = false);\n\nvoid debugger_createPatch(uint32 address, std::span<uint8> patchData);\nbool debugger_hasPatch(uint32 address);\nvoid debugger_removePatch(uint32 address);\n\nvoid debugger_forceBreak(); // force breakpoint at the next possible instruction\nbool debugger_isTrapped();\nvoid debugger_resume();\n\nvoid debugger_enterTW(PPCInterpreter_t* hCPU);\nvoid debugger_shouldBreak(PPCInterpreter_t* hCPU);\n\nvoid debugger_addParserSymbols(class ExpressionParser& ep);"
  },
  {
    "path": "src/Cafe/HW/Espresso/Debugger/GDBBreakpoints.cpp",
    "content": "#include \"GDBBreakpoints.h\"\n#include \"Debugger.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n\n#if defined(ARCH_X86_64) && BOOST_OS_LINUX\n#include <sys/ptrace.h>\n#include <sys/wait.h>\n#include <sys/user.h>\n\nDRType _GetDR(pid_t tid, int drIndex)\n{\n\tsize_t drOffset = offsetof(struct user, u_debugreg) + drIndex * sizeof(user::u_debugreg[0]);\n\n\tlong v;\n\tv = ptrace(PTRACE_PEEKUSER, tid, drOffset, nullptr);\n\tif (v == -1)\n\t\tperror(\"ptrace(PTRACE_PEEKUSER)\");\n\n\treturn (DRType)v;\n}\n\nvoid _SetDR(pid_t tid, int drIndex, DRType newValue)\n{\n\tsize_t drOffset = offsetof(struct user, u_debugreg) + drIndex * sizeof(user::u_debugreg[0]);\n\n\tlong rc = ptrace(PTRACE_POKEUSER, tid, drOffset, newValue);\n\tif (rc == -1)\n\t\tperror(\"ptrace(PTRACE_POKEUSER)\");\n}\n\nDRType _ReadDR6()\n{\n\tpid_t tid = gettid();\n\n\t// linux doesn't let us attach to the current thread / threads in the current thread group\n\t// we have to create a child process which then modifies the debug registers and quits\n\tpid_t child = fork();\n\tif (child == -1)\n\t{\n\t\tperror(\"fork\");\n\t\treturn 0;\n\t}\n\n\tif (child == 0)\n\t{\n\t\tif (ptrace(PTRACE_ATTACH, tid, nullptr, nullptr))\n\t\t{\n\t\t\tperror(\"attach\");\n\t\t\t_exit(0);\n\t\t}\n\n\t\twaitpid(tid, NULL, 0);\n\n\t\tuint64_t dr6 = _GetDR(tid, 6);\n\n\t\tif (ptrace(PTRACE_DETACH, tid, nullptr, nullptr))\n\t\t\tperror(\"detach\");\n\n\t\t// since the status code only uses the lower 8 bits, we have to discard the rest of DR6\n\t\t// this should be fine though, since the lower 4 bits of DR6 contain all the bp conditions\n\t\t_exit(dr6 & 0xff);\n\t}\n\n\t// wait for child process\n\tint wstatus;\n\twaitpid(child, &wstatus, 0);\n\n\treturn (DRType)WEXITSTATUS(wstatus);\n}\n#endif\n\nGDBServer::ExecutionBreakpoint::ExecutionBreakpoint(MPTR address, BreakpointType type, bool visible, std::string reason)\n\t: m_address(address), m_removedAfterInterrupt(false), m_reason(std::move(reason))\n{\n\tif (type == BreakpointType::BP_SINGLE)\n\t{\n\t\tthis->m_pauseThreads = true;\n\t\tthis->m_restoreAfterInterrupt = false;\n\t\tthis->m_deleteAfterAnyInterrupt = false;\n\t\tthis->m_pauseOnNextInterrupt = false;\n\t\tthis->m_visible = visible;\n\t}\n\telse if (type == BreakpointType::BP_PERSISTENT)\n\t{\n\t\tthis->m_pauseThreads = true;\n\t\tthis->m_restoreAfterInterrupt = true;\n\t\tthis->m_deleteAfterAnyInterrupt = false;\n\t\tthis->m_pauseOnNextInterrupt = false;\n\t\tthis->m_visible = visible;\n\t}\n\telse if (type == BreakpointType::BP_RESTORE_POINT)\n\t{\n\t\tthis->m_pauseThreads = false;\n\t\tthis->m_restoreAfterInterrupt = false;\n\t\tthis->m_deleteAfterAnyInterrupt = false;\n\t\tthis->m_pauseOnNextInterrupt = false;\n\t\tthis->m_visible = false;\n\t}\n\telse if (type == BreakpointType::BP_STEP_POINT)\n\t{\n\t\tthis->m_pauseThreads = false;\n\t\tthis->m_restoreAfterInterrupt = false;\n\t\tthis->m_deleteAfterAnyInterrupt = true;\n\t\tthis->m_pauseOnNextInterrupt = true;\n\t\tthis->m_visible = false;\n\t}\n\n\tthis->m_origOpCode = memory_readU32(address);\n\tmemory_writeU32(address, DEBUGGER_BP_T_GDBSTUB_TW);\n\tPPCRecompiler_invalidateRange(address, address + 4);\n}\n\nGDBServer::ExecutionBreakpoint::~ExecutionBreakpoint()\n{\n\tmemory_writeU32(this->m_address, this->m_origOpCode);\n\tPPCRecompiler_invalidateRange(this->m_address, this->m_address + 4);\n}\n\nuint32 GDBServer::ExecutionBreakpoint::GetVisibleOpCode() const\n{\n\tif (this->m_visible)\n\t\treturn memory_readU32(this->m_address);\n\telse\n\t\treturn this->m_origOpCode;\n}\n\nvoid GDBServer::ExecutionBreakpoint::RemoveTemporarily()\n{\n\tmemory_writeU32(this->m_address, this->m_origOpCode);\n\tPPCRecompiler_invalidateRange(this->m_address, this->m_address + 4);\n\tthis->m_restoreAfterInterrupt = true;\n}\n\nvoid GDBServer::ExecutionBreakpoint::Restore()\n{\n\tmemory_writeU32(this->m_address, DEBUGGER_BP_T_GDBSTUB_TW);\n\tPPCRecompiler_invalidateRange(this->m_address, this->m_address + 4);\n\tthis->m_restoreAfterInterrupt = false;\n}\n\nnamespace coreinit\n{\n#if BOOST_OS_LINUX\n\tstd::vector<pid_t>& OSGetSchedulerThreadIds();\n#endif\n\n\tstd::vector<std::thread::native_handle_type>& OSGetSchedulerThreads();\n}\n\nGDBServer::AccessBreakpoint::AccessBreakpoint(MPTR address, AccessPointType type)\n\t: m_address(address), m_type(type)\n{\n#if defined(ARCH_X86_64) && BOOST_OS_WINDOWS\n\tfor (auto& hThreadNH : coreinit::OSGetSchedulerThreads())\n\t{\n\t\tHANDLE hThread = (HANDLE)hThreadNH;\n\t\tCONTEXT ctx{};\n\t\tctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;\n\t\tSuspendThread(hThread);\n\t\tGetThreadContext(hThread, &ctx);\n\n\t\t// use BP 2/3 for gdb stub since cemu's internal debugger uses BP 0/1 already\n\t\tctx.Dr2 = (DWORD64)memory_getPointerFromVirtualOffset(address);\n\t\tctx.Dr3 = (DWORD64)memory_getPointerFromVirtualOffset(address);\n\t\t// breakpoint 2\n\t\tSetBits(ctx.Dr7, 4, 1, 1);\t// breakpoint #3 enabled: true\n\t\tSetBits(ctx.Dr7, 24, 2, 1); // breakpoint #3 condition: 1 (write)\n\t\tSetBits(ctx.Dr7, 26, 2, 3); // breakpoint #3 length: 3 (4 bytes)\n\t\t// breakpoint 3\n\t\tSetBits(ctx.Dr7, 6, 1, 1);\t// breakpoint #4 enabled: true\n\t\tSetBits(ctx.Dr7, 28, 2, 3); // breakpoint #4 condition: 3 (read & write)\n\t\tSetBits(ctx.Dr7, 30, 2, 3); // breakpoint #4 length: 3 (4 bytes)\n\n\t\tSetThreadContext(hThread, &ctx);\n\t\tResumeThread(hThread);\n\t}\n#elif defined(ARCH_X86_64) && BOOST_OS_LINUX\n\t// linux doesn't let us attach to threads which are in the same thread group as our current thread\n\t// we have to create a child process which then modifies the debug registers and quits\n\tpid_t child = fork();\n\tif (child == -1)\n\t{\n\t\tperror(\"fork\");\n\t\treturn;\n\t}\n\n\tif (child == 0)\n\t{\n\t\tfor (pid_t tid : coreinit::OSGetSchedulerThreadIds())\n\t\t{\n\t\t\tlong rc = ptrace(PTRACE_ATTACH, tid, nullptr, nullptr);\n\t\t\tif (rc == -1)\n\t\t\t\tperror(\"ptrace(PTRACE_ATTACH)\");\n\n\t\t\twaitpid(tid, nullptr, 0);\n\n\t\t\tDRType dr7 = _GetDR(tid, 7);\n\t\t\t// use BP 2/3 for gdb stub since cemu's internal debugger uses BP 0/1 already\n\t\t\tDRType dr2 = (uint64)memory_getPointerFromVirtualOffset(address);\n\t\t\tDRType dr3 = (uint64)memory_getPointerFromVirtualOffset(address);\n\t\t\t// breakpoint 2\n\t\t\tSetBits(dr7, 4, 1, 1);  // breakpoint #3 enabled: true\n\t\t\tSetBits(dr7, 24, 2, 1); // breakpoint #3 condition: 1 (write)\n\t\t\tSetBits(dr7, 26, 2, 3); // breakpoint #3 length: 3 (4 bytes)\n\t\t\t// breakpoint 3\n\t\t\tSetBits(dr7, 6, 1, 1);  // breakpoint #4 enabled: true\n\t\t\tSetBits(dr7, 28, 2, 3); // breakpoint #4 condition: 3 (read & write)\n\t\t\tSetBits(dr7, 30, 2, 3); // breakpoint #4 length: 3 (4 bytes)\n\n\t\t\t_SetDR(tid, 2, dr2);\n\t\t\t_SetDR(tid, 3, dr3);\n\t\t\t_SetDR(tid, 7, dr7);\n\n\t\t\trc = ptrace(PTRACE_DETACH, tid, nullptr, nullptr);\n\t\t\tif (rc == -1)\n\t\t\t\tperror(\"ptrace(PTRACE_DETACH)\");\n\t\t}\n\n\t\t// exit child process\n\t\t_exit(0);\n\t}\n\n\t// wait for child process\n\twaitpid(child, nullptr, 0);\n#else\n\tcemuLog_log(LogType::Force, \"Debugger read/write breakpoints are not supported on non-x86 CPUs yet.\");\n#endif\n}\n\nGDBServer::AccessBreakpoint::~AccessBreakpoint()\n{\n#if defined(ARCH_X86_64) && BOOST_OS_WINDOWS\n\tfor (auto& hThreadNH : coreinit::OSGetSchedulerThreads())\n\t{\n\t\tHANDLE hThread = (HANDLE)hThreadNH;\n\t\tCONTEXT ctx{};\n\t\tctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;\n\t\tSuspendThread(hThread);\n\t\tGetThreadContext(hThread, &ctx);\n\n\t\t// reset BP 2/3 to zero\n\t\tctx.Dr2 = (DWORD64)0;\n\t\tctx.Dr3 = (DWORD64)0;\n\t\t// breakpoint 2\n\t\tSetBits(ctx.Dr7, 4, 1, 0);\n\t\tSetBits(ctx.Dr7, 24, 2, 0);\n\t\tSetBits(ctx.Dr7, 26, 2, 0);\n\t\t// breakpoint 3\n\t\tSetBits(ctx.Dr7, 6, 1, 0);\n\t\tSetBits(ctx.Dr7, 28, 2, 0);\n\t\tSetBits(ctx.Dr7, 30, 2, 0);\n\t\tSetThreadContext(hThread, &ctx);\n\t\tResumeThread(hThread);\n\t}\n#elif defined(ARCH_X86_64) && BOOST_OS_LINUX\n\t// linux doesn't let us attach to threads which are in the same thread group as our current thread\n\t// we have to create a child process which then modifies the debug registers and quits\n\tpid_t child = fork();\n\tif (child == -1)\n\t{\n\t\tperror(\"fork\");\n\t\treturn;\n\t}\n\n\tif (child == 0)\n\t{\n\t\tfor (pid_t tid : coreinit::OSGetSchedulerThreadIds())\n\t\t{\n\t\t\tlong rc = ptrace(PTRACE_ATTACH, tid, nullptr, nullptr);\n\t\t\tif (rc == -1)\n\t\t\t\tperror(\"ptrace(PTRACE_ATTACH)\");\n\n\t\t\twaitpid(tid, nullptr, 0);\n\n\t\t\tDRType dr7 = _GetDR(tid, 7);\n\t\t\t// reset BP 2/3 to zero\n\t\t\tDRType dr2 = 0;\n\t\t\tDRType dr3 = 0;\n\t\t\t// breakpoint 2\n\t\t\tSetBits(dr7, 4, 1, 0);\n\t\t\tSetBits(dr7, 24, 2, 0);\n\t\t\tSetBits(dr7, 26, 2, 0);\n\t\t\t// breakpoint 3\n\t\t\tSetBits(dr7, 6, 1, 0);\n\t\t\tSetBits(dr7, 28, 2, 0);\n\t\t\tSetBits(dr7, 30, 2, 0);\n\n\t\t\t_SetDR(tid, 2, dr2);\n\t\t\t_SetDR(tid, 3, dr3);\n\t\t\t_SetDR(tid, 7, dr7);\n\n\t\t\trc = ptrace(PTRACE_DETACH, tid, nullptr, nullptr);\n\t\t\tif (rc == -1)\n\t\t\t\tperror(\"ptrace(PTRACE_DETACH)\");\n\t\t}\n\n\t\t// exit child process\n\t\t_exit(0);\n\t}\n\n\t// wait for child process\n\twaitpid(child, nullptr, 0);\n#endif\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Debugger/GDBBreakpoints.h",
    "content": "#pragma once\n#include \"GDBStub.h\"\n#include <utility>\n\n#if defined(ARCH_X86_64) && BOOST_OS_LINUX\n#include <sys/types.h>\n\n// helpers for accessing debug register\ntypedef unsigned long DRType;\n\nDRType _GetDR(pid_t tid, int drIndex);\nvoid _SetDR(pid_t tid, int drIndex, DRType newValue);\nDRType _ReadDR6();\n#endif\n\nenum class BreakpointType\n{\n\tBP_SINGLE,\n\tBP_PERSISTENT,\n\tBP_RESTORE_POINT,\n\tBP_STEP_POINT\n};\n\nclass GDBServer::ExecutionBreakpoint {\npublic:\n\tExecutionBreakpoint(MPTR address, BreakpointType type, bool visible, std::string reason);\n\t~ExecutionBreakpoint();\n\n\t[[nodiscard]] uint32 GetVisibleOpCode() const;\n\t[[nodiscard]] bool ShouldBreakThreads() const\n\t{\n\t\treturn this->m_pauseThreads;\n\t};\n\t[[nodiscard]] bool ShouldBreakThreadsOnNextInterrupt()\n\t{\n\t\tbool shouldPause = this->m_pauseOnNextInterrupt;\n\t\tthis->m_pauseOnNextInterrupt = false;\n\t\treturn shouldPause;\n\t};\n\t[[nodiscard]] bool IsPersistent() const\n\t{\n\t\treturn this->m_restoreAfterInterrupt;\n\t};\n\t[[nodiscard]] bool IsSkipBreakpoint() const\n\t{\n\t\treturn this->m_deleteAfterAnyInterrupt;\n\t};\n\t[[nodiscard]] bool IsRemoved() const\n\t{\n\t\treturn this->m_removedAfterInterrupt;\n\t};\n\t[[nodiscard]] std::string GetReason() const\n\t{\n\t\treturn m_reason;\n\t};\n\n\tvoid RemoveTemporarily();\n\tvoid Restore();\n\tvoid PauseOnNextInterrupt()\n\t{\n\t\tthis->m_pauseOnNextInterrupt = true;\n\t};\n\n\tvoid WriteNewOpCode(uint32 newOpCode)\n\t{\n\t\tthis->m_origOpCode = newOpCode;\n\t};\n\nprivate:\n\tconst MPTR m_address;\n\tstd::string m_reason;\n\tuint32 m_origOpCode;\n\tbool m_visible;\n\tbool m_pauseThreads;\n\t// type\n\tbool m_pauseOnNextInterrupt;\n\tbool m_restoreAfterInterrupt;\n\tbool m_deleteAfterAnyInterrupt;\n\tbool m_removedAfterInterrupt;\n};\n\nenum class AccessPointType\n{\n\tBP_WRITE = 2,\n\tBP_READ = 3,\n\tBP_BOTH = 4\n};\n\nclass GDBServer::AccessBreakpoint {\npublic:\n\tAccessBreakpoint(MPTR address, AccessPointType type);\n\t~AccessBreakpoint();\n\n\tMPTR GetAddress() const\n\t{\n\t\treturn m_address;\n\t};\n\tAccessPointType GetType() const\n\t{\n\t\treturn m_type;\n\t};\n\nprivate:\n\tconst MPTR m_address;\n\tconst AccessPointType m_type;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Debugger/GDBStub.cpp",
    "content": "#include \"GDBStub.h\"\n#include \"Debugger.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n#include \"GDBBreakpoints.h\"\n#include \"util/helpers/helpers.h\"\n#include \"util/ThreadPool/ThreadPool.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Scheduler.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"Cafe/HW/Espresso/EspressoISA.h\"\n#include \"Common/socket.h\"\n\n#define GET_THREAD_ID(threadPtr) memory_getVirtualOffsetFromPointer(threadPtr)\n#define GET_THREAD_BY_ID(threadId) (OSThread_t*)memory_getPointerFromPhysicalOffset(threadId)\n\nstatic std::vector<MPTR> findNextInstruction(MPTR currAddress, uint32 lr, uint32 ctr)\n{\n\tusing namespace Espresso;\n\n\tuint32 nextInstr = memory_readU32(currAddress);\n\tif (GetPrimaryOpcode(nextInstr) == PrimaryOpcode::B)\n\t{\n\t\tuint32 LI;\n\t\tbool AA, LK;\n\t\tdecodeOp_B(nextInstr, LI, AA, LK);\n\t\tif (!AA)\n\t\t\tLI += currAddress;\n\t\treturn {LI};\n\t}\n\tif (GetPrimaryOpcode(nextInstr) == PrimaryOpcode::BC)\n\t{\n\t\tuint32 BD, BI;\n\t\tBOField BO{};\n\t\tbool AA, LK;\n\t\tdecodeOp_BC(nextInstr, BD, BO, BI, AA, LK);\n\t\tif (!LK)\n\t\t\tBD += currAddress;\n\t\treturn {currAddress + 4, BD};\n\t}\n\tif (GetPrimaryOpcode(nextInstr) == PrimaryOpcode::GROUP_19 && GetGroup19Opcode(nextInstr) == Opcode19::BCLR)\n\t{\n\t\treturn {currAddress + 4, lr};\n\t}\n\tif (GetPrimaryOpcode(nextInstr) == PrimaryOpcode::GROUP_19 && GetGroup19Opcode(nextInstr) == Opcode19::BCCTR)\n\t{\n\t\treturn {currAddress + 4, ctr};\n\t}\n\treturn {currAddress + 4};\n}\n\ntemplate<typename F>\nstatic void selectThread(sint64 selectorId, F&& action_for_thread)\n{\n\t__OSLockScheduler();\n\tcemu_assert_debug(activeThreadCount != 0);\n\n\tif (selectorId == -1)\n\t{\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\taction_for_thread(GET_THREAD_BY_ID(activeThread[i]));\n\t\t}\n\t}\n\telse if (selectorId == 0)\n\t{\n\t\t// Use first thread if attempted to be stopped\n\t\t// todo: would this work better if it used main?\n\t\taction_for_thread(coreinit::OSGetDefaultThread(1));\n\t}\n\telse if (selectorId > 0)\n\t{\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\tauto* thread = GET_THREAD_BY_ID(activeThread[i]);\n\t\t\tif (GET_THREAD_ID(thread) == selectorId)\n\t\t\t{\n\t\t\t\taction_for_thread(thread);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t__OSUnlockScheduler();\n}\n\ntemplate<typename F>\nstatic void selectAndBreakThread(sint64 selectorId, F&& action_for_thread)\n{\n\t__OSLockScheduler();\n\tcemu_assert_debug(activeThreadCount != 0);\n\n\tstd::vector<OSThread_t*> pausedThreads;\n\tif (selectorId == -1)\n\t{\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\tcoreinit::__OSSuspendThreadNolock(GET_THREAD_BY_ID(activeThread[i]));\n\t\t\tpausedThreads.emplace_back(GET_THREAD_BY_ID(activeThread[i]));\n\t\t}\n\t}\n\telse if (selectorId == 0)\n\t{\n\t\t// Use first thread if attempted to be stopped\n\t\tOSThread_t* thread = GET_THREAD_BY_ID(activeThread[0]);\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\tif (GET_THREAD_ID(GET_THREAD_BY_ID(activeThread[i])) < GET_THREAD_ID(thread))\n\t\t\t{\n\t\t\t\tthread = GET_THREAD_BY_ID(activeThread[i]);\n\t\t\t}\n\t\t}\n\t\tcoreinit::__OSSuspendThreadNolock(thread);\n\t\tpausedThreads.emplace_back(thread);\n\t}\n\telse if (selectorId > 0)\n\t{\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\tauto* thread = GET_THREAD_BY_ID(activeThread[i]);\n\t\t\tif (GET_THREAD_ID(thread) == selectorId)\n\t\t\t{\n\t\t\t\tcoreinit::__OSSuspendThreadNolock(thread);\n\t\t\t\tpausedThreads.emplace_back(thread);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t__OSUnlockScheduler();\n\n\tfor (OSThread_t* thread : pausedThreads)\n\t{\n\t\twhile (coreinit::OSIsThreadRunning(thread))\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(50));\n\t\taction_for_thread(thread);\n\t}\n}\n\nstatic void selectAndResumeThread(sint64 selectorId)\n{\n\t__OSLockScheduler();\n\tcemu_assert_debug(activeThreadCount != 0);\n\n\tif (selectorId == -1)\n\t{\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\tcoreinit::__OSResumeThreadInternal(GET_THREAD_BY_ID(activeThread[i]), 4);\n\t\t}\n\t}\n\telse if (selectorId == 0)\n\t{\n\t\t// Use first thread if attempted to be stopped\n\t\tcoreinit::__OSResumeThreadInternal(coreinit::OSGetDefaultThread(1), 1);\n\t}\n\telse if (selectorId > 0)\n\t{\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\tauto* thread = GET_THREAD_BY_ID(activeThread[i]);\n\t\t\tif (GET_THREAD_ID(thread) == selectorId)\n\t\t\t{\n\t\t\t\tcoreinit::__OSResumeThreadInternal(thread, 1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t__OSUnlockScheduler();\n}\n\nstatic void waitForBrokenThreads(std::unique_ptr<GDBServer::CommandContext> context, std::string_view reason)\n{\n\t// This should pause all threads except trapped thread\n\t// It should however wait for the trapped thread\n\t// The trapped thread should be paused by the trap word instruction handler (aka the running thread)\n\tstd::vector<OSThread_t*> threadsList;\n\t__OSLockScheduler();\n\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t{\n\t\tthreadsList.emplace_back(GET_THREAD_BY_ID(activeThread[i]));\n\t}\n\t__OSUnlockScheduler();\n\n\tfor (OSThread_t* thread : threadsList)\n\t{\n\t\twhile (coreinit::OSIsThreadRunning(thread))\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(50));\n\t}\n\n\tcontext->QueueResponse(reason);\n}\n\nstatic void breakThreads(sint64 trappedThread)\n{\n\t__OSLockScheduler();\n\tcemu_assert_debug(activeThreadCount != 0);\n\n\t// First, break other threads\n\tOSThread_t* mainThread = nullptr;\n\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t{\n\t\tif (GET_THREAD_ID(GET_THREAD_BY_ID(activeThread[i])) == trappedThread)\n\t\t{\n\t\t\tmainThread = GET_THREAD_BY_ID(activeThread[i]);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcoreinit::__OSSuspendThreadNolock(GET_THREAD_BY_ID(activeThread[i]));\n\t\t}\n\t}\n\n\t// Second, break trapped thread itself which should also pause execution of this handler\n\t// This will temporarily lift the scheduler lock until it's resumed from its suspension\n\tcoreinit::__OSSuspendThreadNolock(mainThread);\n\n\t__OSUnlockScheduler();\n}\n\nstd::unique_ptr<GDBServer> g_gdbstub;\n\nGDBServer::GDBServer(uint16 port)\n\t: m_port(port)\n{\n#if BOOST_OS_WINDOWS\n\tWSADATA wsa;\n\tWSAStartup(MAKEWORD(2, 2), &wsa);\n#endif\n}\n\nGDBServer::~GDBServer()\n{\n\tif (m_client_socket != INVALID_SOCKET)\n\t{\n\t\t// close socket from other thread to forcefully stop accept() call\n\t\tclosesocket(m_client_socket);\n\t\tm_client_socket = INVALID_SOCKET;\n\t}\n\n\tif (m_server_socket != INVALID_SOCKET)\n\t{\n\t\tclosesocket(m_server_socket);\n\t}\n#if BOOST_OS_WINDOWS\n\tWSACleanup();\n#endif\n\n\tm_stopRequested = false;\n\tm_thread.join();\n}\n\nbool GDBServer::Initialize()\n{\n\tcemuLog_createLogFile(false);\n\n\tif (m_server_socket = socket(PF_INET, SOCK_STREAM, 0); m_server_socket == SOCKET_ERROR)\n\t\treturn false;\n\n\tint reuseEnabled = TRUE;\n\tif (setsockopt(m_server_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuseEnabled, sizeof(reuseEnabled)) == SOCKET_ERROR)\n\t{\n\t\tclosesocket(m_server_socket);\n\t\tm_server_socket = INVALID_SOCKET;\n\t\treturn false;\n\t}\n\n\tint nodelayEnabled = TRUE;\n\tif (setsockopt(m_server_socket, IPPROTO_TCP, TCP_NODELAY, (char*)&nodelayEnabled, sizeof(nodelayEnabled)) == SOCKET_ERROR)\n\t{\n\t\tclosesocket(m_server_socket);\n\t\tm_server_socket = INVALID_SOCKET;\n\t\treturn false;\n\t}\n\n\tmemset(&m_server_addr, 0, sizeof(m_server_addr));\n\tm_server_addr.sin_family = AF_INET;\n\tm_server_addr.sin_addr.s_addr = htonl(INADDR_ANY);\n\tm_server_addr.sin_port = htons(m_port);\n\n\tif (bind(m_server_socket, (sockaddr*)&m_server_addr, sizeof(m_server_addr)) == SOCKET_ERROR)\n\t{\n\t\tclosesocket(m_server_socket);\n\t\tm_server_socket = INVALID_SOCKET;\n\t\treturn false;\n\t}\n\n\tif (listen(m_server_socket, s_maxGDBClients) == SOCKET_ERROR)\n\t{\n\t\tclosesocket(m_server_socket);\n\t\tm_server_socket = INVALID_SOCKET;\n\t\treturn false;\n\t}\n\n\tm_thread = std::thread(std::bind(&GDBServer::ThreadFunc, this));\n\n\treturn true;\n}\n\nvoid GDBServer::ThreadFunc()\n{\n\tSetThreadName(\"GDBServer\");\n\n\twhile (!m_stopRequested)\n\t{\n\t\tif (!m_client_connected)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"[GDBStub] Waiting for client to connect on port {}...\", m_port);\n\t\t\tsocklen_t client_addr_size = sizeof(m_client_addr);\n\t\t\tm_client_socket = accept(m_server_socket, (struct sockaddr*)&m_client_addr, &client_addr_size);\n\t\t\tm_client_connected = m_client_socket != SOCKET_ERROR;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto receiveMessage = [&](char* buffer, const int32_t length) -> bool {\n\t\t\t\tif (recv(m_client_socket, buffer, length, 0) != SOCKET_ERROR)\n\t\t\t\t\treturn false;\n\t\t\t\treturn true;\n\t\t\t};\n\n\t\t\tauto readChar = [&]() -> char {\n\t\t\t\tchar ret = 0;\n\t\t\t\trecv(m_client_socket, &ret, 1, 0);\n\t\t\t\treturn ret;\n\t\t\t};\n\n\t\t\tchar packetPrefix = readChar();\n\n\t\t\tswitch (packetPrefix)\n\t\t\t{\n\t\t\tcase '+':\n\t\t\tcase '-':\n\t\t\t\tbreak;\n\t\t\tcase '\\x03':\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"[GDBStub] Received interrupt (pressed CTRL+C?) from client!\");\n\t\t\t\tselectAndBreakThread(-1, [](OSThread_t* thread) {\n\t\t\t\t});\n\t\t\t\tauto thread_status = fmt::format(\"T05thread:{:08X};\", GET_THREAD_ID(coreinit::OSGetDefaultThread(1)));\n\t\t\t\tif (this->m_resumed_context)\n\t\t\t\t{\n\t\t\t\t\tthis->m_resumed_context->QueueResponse(thread_status);\n\t\t\t\t\tthis->m_resumed_context.reset();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto response_full = fmt::format(\"+${}#{:02x}\", thread_status, CommandContext::CalculateChecksum(thread_status));\n\t\t\t\t\tsend(m_client_socket, response_full.c_str(), (int)response_full.size(), 0);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase '$':\n\t\t\t{\n\t\t\t\tstd::string message;\n\t\t\t\tuint8 checkedSum = 0;\n\t\t\t\tfor (uint32_t i = 1;; i++)\n\t\t\t\t{\n\t\t\t\t\tchar c = readChar();\n\t\t\t\t\tif (c == '#')\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcheckedSum += static_cast<uint8>(c);\n\t\t\t\t\tmessage.push_back(c);\n\n\t\t\t\t\tif (i >= s_maxPacketSize)\n\t\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"[GDBStub] Received too big of a buffer: {}\", message);\n\t\t\t\t}\n\t\t\t\tchar checkSumStr[2];\n\t\t\t\treceiveMessage(checkSumStr, 2);\n\t\t\t\tuint32_t checkSum = std::stoi(std::string(checkSumStr, sizeof(checkSumStr)), nullptr, 16);\n\t\t\t\tassert((checkedSum & 0xFF) == checkSum);\n\n\t\t\t\tHandleCommand(message);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\t// cemuLog_logDebug(LogType::Force, \"[GDBStub] Unknown packet start: {}\", packetPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (m_client_socket != INVALID_SOCKET)\n\t\tclosesocket(m_client_socket);\n}\n\nvoid GDBServer::HandleCommand(const std::string& command_str)\n{\n\tauto context = std::make_unique<CommandContext>(this, command_str);\n\n\tif (context->IsValid())\n\t{\n\t\t// cemuLog_logDebug(LogType::Force, \"[GDBStub] Extracted Command {}\", fmt::join(context->GetArgs(), \",\"));\n\t}\n\n\tswitch (context->GetType())\n\t{\n\t// Extended commands\n\tcase CMDType::QUERY_GET:\n\tcase CMDType::QUERY_SET:\n\t\treturn HandleQuery(context);\n\tcase CMDType::VCONT:\n\t\treturn HandleVCont(context);\n\t// Regular commands\n\tcase CMDType::IS_THREAD_RUNNING:\n\t\treturn CMDIsThreadActive(context);\n\tcase CMDType::SET_ACTIVE_THREAD:\n\t\treturn CMDSetActiveThread(context);\n\tcase CMDType::ACTIVE_THREAD_STATUS:\n\t\treturn CMDGetThreadStatus(context);\n\tcase CMDType::CONTINUE:\n\t\treturn CMDContinue(context);\n\tcase CMDType::ACTIVE_THREAD_STEP:\n\t\tbreak;\n\tcase CMDType::REGISTER_READ:\n\t\treturn CMDReadRegister(context);\n\tcase CMDType::REGISTER_SET:\n\t\treturn CMDWriteRegister(context);\n\tcase CMDType::REGISTERS_READ:\n\t\treturn CMDReadRegisters(context);\n\tcase CMDType::REGISTERS_WRITE:\n\t\treturn CMDWriteRegisters(context);\n\tcase CMDType::MEMORY_READ:\n\t\treturn CMDReadMemory(context);\n\tcase CMDType::MEMORY_WRITE:\n\t\treturn CMDWriteMemory(context);\n\tcase CMDType::BREAKPOINT_SET:\n\t\treturn CMDInsertBreakpoint(context);\n\tcase CMDType::BREAKPOINT_REMOVE:\n\t\treturn CMDDeleteBreakpoint(context);\n\tcase CMDType::INVALID:\n\tdefault:\n\t\treturn CMDNotFound(context);\n\t}\n\n\tCMDNotFound(context);\n}\n\nvoid GDBServer::HandleQuery(std::unique_ptr<CommandContext>& context) const\n{\n\tif (!context->IsValid())\n\t\treturn context->QueueResponse(RESPONSE_EMPTY);\n\n\tconst auto& query_cmd = context->GetArgs()[0];\n\tconst auto& query_args = context->GetArgs().begin() + 1;\n\n\tif (query_cmd == \"qSupported\")\n\t{\n\t\tcontext->QueueResponse(s_supportedFeatures);\n\t}\n\telse if (query_cmd == \"qAttached\")\n\t{\n\t\tcontext->QueueResponse(\"1\");\n\t}\n\telse if (query_cmd == \"qRcmd\")\n\t{\n\t}\n\telse if (query_cmd == \"qC\")\n\t{\n\t\tcontext->QueueResponse(\"QC\");\n\t\tcontext->QueueResponse(std::to_string(m_activeThreadContinueSelector));\n\t}\n\telse if (query_cmd == \"qOffsets\")\n\t{\n\t\tconst auto module_count = RPLLoader_GetModuleCount();\n\t\tconst auto module_list = RPLLoader_GetModuleList();\n\t\tfor (sint32 i = 0; i < module_count; i++)\n\t\t{\n\t\t\tconst RPLModule* rpl = module_list[i];\n\t\t\tif (rpl->entrypoint == m_entry_point)\n\t\t\t{\n\t\t\t\tcontext->QueueResponse(fmt::format(\"TextSeg={:08X};DataSeg={:08X}\", rpl->regionMappingBase_text.GetMPTR(), rpl->regionMappingBase_data));\n\t\t\t}\n\t\t}\n\t}\n\telse if (query_cmd == \"qfThreadInfo\")\n\t{\n\t\tstd::vector<std::string> threadIds;\n\t\tselectThread(-1, [&threadIds](OSThread_t* thread) {\n\t\t\tthreadIds.emplace_back(fmt::format(\"{:08X}\", memory_getVirtualOffsetFromPointer(thread)));\n\t\t});\n\t\tcontext->QueueResponse(fmt::format(\"m{}\", fmt::join(threadIds, \",\")));\n\t}\n\telse if (query_cmd == \"qsThreadInfo\")\n\t{\n\t\tcontext->QueueResponse(\"l\");\n\t}\n\telse if (query_cmd == \"qXfer\")\n\t{\n\t\tauto& type = query_args[0];\n\n\t\tif (type == \"features\")\n\t\t{\n\t\t\tauto& annex = query_args[1];\n\t\t\tsint64 read_offset = std::stoul(query_args[2], nullptr, 16);\n\t\t\tsint64 read_length = std::stoul(query_args[3], nullptr, 16);\n\t\t\tif (annex == \"target.xml\")\n\t\t\t{\n\t\t\t\tif (read_offset >= GDBTargetXML.size())\n\t\t\t\t\tcontext->QueueResponse(\"l\");\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto paginated_str = GDBTargetXML.substr(read_offset, read_length);\n\t\t\t\t\tcontext->QueueResponse((paginated_str.size() == read_length) ? \"m\" : \"l\");\n\t\t\t\t\tcontext->QueueResponse(paginated_str);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"[GDBStub] qXfer:features:read:{} isn't a known feature document\", annex);\n\t\t}\n\t\telse if (type == \"threads\")\n\t\t{\n\t\t\tsint64 read_offset = std::stoul(query_args[1], nullptr, 16);\n\t\t\tsint64 read_length = std::stoul(query_args[2], nullptr, 16);\n\n\t\t\tstd::string threads_res;\n\t\t\tthreads_res += R\"(<?xml version=\"1.0\"?>)\";\n\t\t\tthreads_res += \"<threads>\";\n\t\t\t// note: clion seems to default to the first thread\n\t\t\tstd::map<sint64, std::string> threads_list;\n\t\t\tselectThread(-1, [&threads_list](OSThread_t* thread) {\n\t\t\t\tstd::string entry;\n\t\t\t\tentry += fmt::format(R\"(<thread id=\"{:x}\" core=\"{}\")\", GET_THREAD_ID(thread), thread->context.upir.value());\n\t\t\t\tif (!thread->threadName.IsNull())\n\t\t\t\t\tentry += fmt::format(R\"( name=\"{}\")\", CommandContext::EscapeXMLString(thread->threadName.GetPtr()));\n\t\t\t\t// todo: could add a human-readable description of the thread here\n\t\t\t\tentry += fmt::format(\"></thread>\");\n\t\t\t\tthreads_list.emplace(GET_THREAD_ID(thread), entry);\n\t\t\t});\n\t\t\tfor (auto& entry : threads_list)\n\t\t\t{\n\t\t\t\tthreads_res += entry.second;\n\t\t\t}\n\t\t\tthreads_res += \"</threads>\";\n\n\t\t\tif (read_offset >= threads_res.size())\n\t\t\t\tcontext->QueueResponse(\"l\");\n\t\t\telse\n\t\t\t{\n\t\t\t\tauto paginated_str = threads_res.substr(read_offset, read_length);\n\t\t\t\tcontext->QueueResponse((paginated_str.size() == read_length) ? \"m\" : \"l\");\n\t\t\t\tcontext->QueueResponse(paginated_str);\n\t\t\t}\n\t\t}\n\t\telse if (type == \"libraries\")\n\t\t{\n\t\t\tsint64 read_offset = std::stoul(query_args[1], nullptr, 16);\n\t\t\tsint64 read_length = std::stoul(query_args[2], nullptr, 16);\n\n\t\t\tstd::string library_list;\n\t\t\tlibrary_list += R\"(<?xml version=\"1.0\"?>)\";\n\t\t\tlibrary_list += \"<library-list>\";\n\n\t\t\tconst auto module_count = RPLLoader_GetModuleCount();\n\t\t\tconst auto module_list = RPLLoader_GetModuleList();\n\t\t\tfor (sint32 i = 0; i < module_count; i++)\n\t\t\t{\n\t\t\t\tlibrary_list += fmt::format(R\"(<library name=\"{}\"><segment address=\"{:#x}\"/></library>)\", CommandContext::EscapeXMLString(module_list[i]->moduleName2), module_list[i]->regionMappingBase_text.GetMPTR());\n\t\t\t}\n\t\t\tlibrary_list += \"</library-list>\";\n\n\t\t\tif (read_offset >= library_list.size())\n\t\t\t\tcontext->QueueResponse(\"l\");\n\t\t\telse\n\t\t\t{\n\t\t\t\tauto paginated_str = library_list.substr(read_offset, read_length);\n\t\t\t\tcontext->QueueResponse((paginated_str.size() == read_length) ? \"m\" : \"l\");\n\t\t\t\tcontext->QueueResponse(paginated_str);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcontext->QueueResponse(RESPONSE_EMPTY);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcontext->QueueResponse(RESPONSE_EMPTY);\n\t}\n}\n\nvoid GDBServer::HandleVCont(std::unique_ptr<CommandContext>& context)\n{\n\tif (!context->IsValid())\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"[GDBStub] Received unsupported vCont command: {}\", context->GetCommand());\n\t\t// cemu_assert_unimplemented();\n\t\treturn context->QueueResponse(RESPONSE_EMPTY);\n\t}\n\n\tconst std::string& vcont_cmd = context->GetArgs()[0];\n\tif (vcont_cmd == \"vCont?\")\n\t\treturn context->QueueResponse(\"vCont;c;C;s;S\");\n\n\telse if (vcont_cmd != \"vCont;\")\n\t\treturn context->QueueResponse(RESPONSE_EMPTY);\n\n\tm_resumed_context = std::move(context);\n\n\tbool resumedNoThreads = true;\n\tfor (const auto operation : TokenizeView(m_resumed_context->GetArgs()[1], ';'))\n\t{\n\t\t// todo: this might have issues with the signal versions (C/S)\n\t\t// todo: test whether this works with multiple vCont;c:123123;c:123123\n\t\tstd::string_view operationType = operation.substr(0, operation.find(':'));\n\t\tsint64 threadSelector = operationType.size() == operation.size() ? -1 : std::stoll(std::string(operation.substr(operationType.size() + 1)), nullptr, 16);\n\n\t\tif (operationType == \"c\" || operationType.starts_with(\"C\"))\n\t\t{\n\t\t\tselectAndResumeThread(threadSelector);\n\t\t\tresumedNoThreads = false;\n\t\t}\n\t\telse if (operationType == \"s\" || operationType.starts_with(\"S\"))\n\t\t{\n\t\t\tselectThread(threadSelector, [this](OSThread_t* thread) {\n\t\t\t\tauto nextInstructions = findNextInstruction(thread->context.srr0, thread->context.lr, thread->context.ctr);\n\t\t\t\tfor (MPTR nextInstr : nextInstructions)\n\t\t\t\t{\n\t\t\t\t\tauto bpIt = m_patchedInstructions.find(nextInstr);\n\t\t\t\t\tif (bpIt == m_patchedInstructions.end())\n\t\t\t\t\t\tthis->m_patchedInstructions.try_emplace(nextInstr, nextInstr, BreakpointType::BP_STEP_POINT, false, \"swbreak:;\");\n\t\t\t\t\telse\n\t\t\t\t\t\tbpIt->second.PauseOnNextInterrupt();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tif (resumedNoThreads)\n\t{\n\t\tselectAndResumeThread(-1);\n\t\tcemuLog_logDebug(LogType::Force, \"[GDBStub] Resumed all threads after skip instructions\");\n\t}\n}\n\nvoid GDBServer::CMDContinue(std::unique_ptr<CommandContext>& context)\n{\n\tm_resumed_context = std::move(context);\n\tselectAndResumeThread(m_activeThreadContinueSelector);\n}\n\nvoid GDBServer::CMDNotFound(std::unique_ptr<CommandContext>& context)\n{\n\treturn context->QueueResponse(RESPONSE_EMPTY);\n}\n\nvoid GDBServer::CMDIsThreadActive(std::unique_ptr<CommandContext>& context)\n{\n\tsint64 threadSelector = std::stoll(context->GetArgs()[1], nullptr, 16);\n\tbool foundThread = false;\n\tselectThread(threadSelector, [&foundThread](OSThread_t* thread) {\n\t\tfoundThread = true;\n\t});\n\n\tif (foundThread)\n\t\treturn context->QueueResponse(RESPONSE_OK);\n\telse\n\t\treturn context->QueueResponse(RESPONSE_ERROR);\n}\n\nvoid GDBServer::CMDSetActiveThread(std::unique_ptr<CommandContext>& context)\n{\n\tsint64 threadSelector = std::stoll(context->GetArgs()[2], nullptr, 16);\n\tif (threadSelector >= 0)\n\t{\n\t\tbool foundThread = false;\n\t\tselectThread(threadSelector, [&foundThread](OSThread_t* thread) {\n\t\t\tfoundThread = true;\n\t\t});\n\t\tif (!foundThread)\n\t\t\treturn context->QueueResponse(RESPONSE_ERROR);\n\t}\n\tif (context->GetArgs()[1] == \"c\")\n\t\tm_activeThreadContinueSelector = threadSelector;\n\telse\n\t\tm_activeThreadSelector = threadSelector;\n\treturn context->QueueResponse(RESPONSE_OK);\n}\n\nvoid GDBServer::CMDGetThreadStatus(std::unique_ptr<CommandContext>& context)\n{\n\tselectThread(0, [&context](OSThread_t* thread) {\n\t\tcontext->QueueResponse(fmt::format(\"T05thread:{:08X};\", memory_getVirtualOffsetFromPointer(thread)));\n\t});\n}\n\nvoid GDBServer::CMDReadRegister(std::unique_ptr<CommandContext>& context) const\n{\n\tsint32 reg = std::stoi(context->GetArgs()[1], nullptr, 16);\n\tselectThread(m_activeThreadSelector, [reg, &context](OSThread_t* thread) {\n\t\tauto& cpu = thread->context;\n\t\tif (reg >= RegisterID::R0_START && reg <= RegisterID::R31_END)\n\t\t{\n\t\t\treturn context->QueueResponse(fmt::format(\"{:08X}\", CPU_swapEndianU32(cpu.gpr[reg])));\n\t\t}\n\t\telse if (reg >= RegisterID::F0_START && reg <= RegisterID::F31_END)\n\t\t{\n\t\t\treturn context->QueueResponse(fmt::format(\"{:016X}\", cpu.fp_ps0[reg - RegisterID::F0_START].value()));\n\t\t}\n\t\telse if (reg == RegisterID::FPSCR)\n\t\t{\n\t\t\treturn context->QueueResponse(fmt::format(\"{:08X}\", cpu.fpscr.fpscr.value()));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tswitch (reg)\n\t\t\t{\n\t\t\tcase RegisterID::PC: return context->QueueResponse(fmt::format(\"{:08X}\", cpu.srr0));\n\t\t\tcase RegisterID::MSR: return context->QueueResponse(\"xxxxxxxx\");\n\t\t\tcase RegisterID::CR: return context->QueueResponse(fmt::format(\"{:08X}\", cpu.cr));\n\t\t\tcase RegisterID::LR: return context->QueueResponse(fmt::format(\"{:08X}\", CPU_swapEndianU32(cpu.lr)));\n\t\t\tcase RegisterID::CTR: return context->QueueResponse(fmt::format(\"{:08X}\", cpu.ctr));\n\t\t\tcase RegisterID::XER: return context->QueueResponse(fmt::format(\"{:08X}\", cpu.xer));\n\t\t\tdefault: break;\n\t\t\t}\n\t\t}\n\t});\n}\n\nvoid GDBServer::CMDWriteRegister(std::unique_ptr<CommandContext>& context) const\n{\n\tsint32 reg = std::stoi(context->GetArgs()[1], nullptr, 16);\n\tuint64 value = std::stoll(context->GetArgs()[2], nullptr, 16);\n\tselectThread(m_activeThreadSelector, [reg, value, &context](OSThread_t* thread) {\n\t\tauto& cpu = thread->context;\n\t\tif (reg >= RegisterID::R0_START && reg <= RegisterID::R31_END)\n\t\t{\n\t\t\tcpu.gpr[reg] = CPU_swapEndianU32(value);\n\t\t\treturn context->QueueResponse(RESPONSE_OK);\n\t\t}\n\t\telse if (reg >= RegisterID::F0_START && reg <= RegisterID::F31_END)\n\t\t{\n\t\t\t// todo: figure out how to properly write to paired single registers\n\t\t\tcpu.fp_ps0[reg - RegisterID::F0_START] = uint64be{value};\n\t\t\treturn context->QueueResponse(RESPONSE_OK);\n\t\t}\n\t\telse if (reg == RegisterID::FPSCR)\n\t\t{\n\t\t\tcpu.fpscr.fpscr = uint32be{(uint32)value};\n\t\t\treturn context->QueueResponse(RESPONSE_OK);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tswitch (reg)\n\t\t\t{\n\t\t\tcase RegisterID::PC:\n\t\t\t\tcpu.srr0 = value;\n\t\t\t\treturn context->QueueResponse(RESPONSE_OK);\n\t\t\tcase RegisterID::MSR:\n\t\t\t\treturn context->QueueResponse(RESPONSE_ERROR);\n\t\t\tcase RegisterID::CR:\n\t\t\t\tcpu.cr = value;\n\t\t\t\treturn context->QueueResponse(RESPONSE_OK);\n\t\t\tcase RegisterID::LR:\n\t\t\t\tcpu.lr = CPU_swapEndianU32(value);\n\t\t\t\treturn context->QueueResponse(RESPONSE_OK);\n\t\t\tcase RegisterID::CTR:\n\t\t\t\tcpu.ctr = value;\n\t\t\t\treturn context->QueueResponse(RESPONSE_OK);\n\t\t\tcase RegisterID::XER:\n\t\t\t\tcpu.xer = value;\n\t\t\t\treturn context->QueueResponse(RESPONSE_OK);\n\t\t\tdefault:\n\t\t\t\treturn context->QueueResponse(RESPONSE_ERROR);\n\t\t\t}\n\t\t}\n\t});\n}\n\nvoid GDBServer::CMDReadRegisters(std::unique_ptr<CommandContext>& context) const\n{\n\tselectThread(m_activeThreadSelector, [&context](OSThread_t* thread) {\n\t\tfor (uint32& reg : thread->context.gpr)\n\t\t{\n\t\t\tcontext->QueueResponse(fmt::format(\"{:08X}\", CPU_swapEndianU32(reg)));\n\t\t}\n\t});\n}\n\nvoid GDBServer::CMDWriteRegisters(std::unique_ptr<CommandContext>& context) const\n{\n\tselectThread(m_activeThreadSelector, [&context](OSThread_t* thread) {\n\t\tauto& registers = context->GetArgs()[1];\n\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t{\n\t\t\tthread->context.gpr[i] = CPU_swapEndianU32(std::stoi(registers.substr(i * 2, 2), nullptr, 16));\n\t\t}\n\t});\n}\n\nvoid GDBServer::CMDReadMemory(std::unique_ptr<CommandContext>& context)\n{\n\tsint64 addr = std::stoul(context->GetArgs()[1], nullptr, 16);\n\tsint64 length = std::stoul(context->GetArgs()[2], nullptr, 16);\n\n\t// todo: handle cross-mmu-range memory requests\n\tif (!memory_isAddressRangeAccessible(addr, length))\n\t\treturn context->QueueResponse(RESPONSE_ERROR);\n\n\tstd::string memoryRepr;\n\tuint8* values = memory_getPointerFromVirtualOffset(addr);\n\tfor (sint64 i = 0; i < length; i++)\n\t{\n\t\tmemoryRepr += fmt::format(\"{:02X}\", values[i]);\n\t}\n\n\tauto patchesRange = m_patchedInstructions.lower_bound(addr);\n\twhile (patchesRange != m_patchedInstructions.end() && patchesRange->first < (addr + length))\n\t{\n\t\tauto replStr = fmt::format(\"{:02X}\", patchesRange->second.GetVisibleOpCode());\n\t\tmemoryRepr[(patchesRange->first - addr) * 2] = replStr[0];\n\t\tmemoryRepr[(patchesRange->first - addr) * 2 + 1] = replStr[1];\n\t\tpatchesRange++;\n\t}\n\treturn context->QueueResponse(memoryRepr);\n}\n\nvoid GDBServer::CMDWriteMemory(std::unique_ptr<CommandContext>& context)\n{\n\tsint64 addr = std::stoul(context->GetArgs()[1], nullptr, 16);\n\tsint64 length = std::stoul(context->GetArgs()[2], nullptr, 16);\n\tauto source = context->GetArgs()[3];\n\n\t// todo: handle cross-mmu-range memory requests\n\tif (!memory_isAddressRangeAccessible(addr, length))\n\t\treturn context->QueueResponse(RESPONSE_ERROR);\n\n\tuint8* values = memory_getPointerFromVirtualOffset(addr);\n\tfor (sint64 i = 0; i < length; i++)\n\t{\n\t\tuint8 hexValue;\n\t\tconst std::from_chars_result result = std::from_chars(source.data() + (i * 2), (source.data() + (i * 2) + 2), hexValue, 16);\n\t\tif (result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range)\n\t\t\treturn context->QueueResponse(RESPONSE_ERROR);\n\n\t\tif (auto it = m_patchedInstructions.find(addr + i); it != m_patchedInstructions.end())\n\t\t{\n\t\t\tuint32 newOpCode = it->second.GetVisibleOpCode();\n\t\t\tuint32 byteIndex = 3 - ((addr + i) % 4);\t\t\t// inverted because of big endian, so address 0 is the highest byte\n\t\t\tnewOpCode &= ~(0xFF << (byteIndex * 8));\t\t\t// mask out the byte\n\t\t\tnewOpCode |= ((uint32)hexValue << (byteIndex * 8)); // set new byte with OR\n\t\t\tit->second.WriteNewOpCode(newOpCode);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvalues[i] = hexValue;\n\t\t}\n\t}\n\treturn context->QueueResponse(RESPONSE_OK);\n}\n\nvoid GDBServer::CMDInsertBreakpoint(std::unique_ptr<CommandContext>& context)\n{\n\tauto type = std::stoul(context->GetArgs()[1], nullptr, 16);\n\tMPTR addr = static_cast<MPTR>(std::stoul(context->GetArgs()[2], nullptr, 16));\n\n\tif (type == 0 || type == 1)\n\t{\n\t\tauto bp = this->m_patchedInstructions.find(addr);\n\t\tif (bp != this->m_patchedInstructions.end())\n\t\t\tthis->m_patchedInstructions.erase(bp);\n\t\tthis->m_patchedInstructions.try_emplace(addr, addr, BreakpointType::BP_PERSISTENT, type == 0, type == 0 ? \"swbreak:;\" : \"hwbreak:;\");\n\t}\n\telse if (type == 2 || type == 3 || type == 4)\n\t{\n\t\tif (this->m_watch_point)\n\t\t\treturn context->QueueResponse(RESPONSE_ERROR);\n\n\t\tthis->m_watch_point = std::make_unique<AccessBreakpoint>(addr, (AccessPointType)type);\n\t}\n\n\treturn context->QueueResponse(RESPONSE_OK);\n}\n\nvoid GDBServer::CMDDeleteBreakpoint(std::unique_ptr<CommandContext>& context)\n{\n\tauto type = std::stoul(context->GetArgs()[1], nullptr, 16);\n\tMPTR addr = static_cast<MPTR>(std::stoul(context->GetArgs()[2], nullptr, 16));\n\n\tif (type == 0 || type == 1)\n\t{\n\t\tauto bp = this->m_patchedInstructions.find(addr);\n\t\tif (bp == this->m_patchedInstructions.end() || !bp->second.ShouldBreakThreads())\n\t\t\treturn context->QueueResponse(RESPONSE_ERROR);\n\t\telse\n\t\t\tthis->m_patchedInstructions.erase(bp);\n\t}\n\telse if (type == 2 || type == 3 || type == 4)\n\t{\n\t\tif (!this->m_watch_point || this->m_watch_point->GetAddress() != addr)\n\t\t\treturn context->QueueResponse(RESPONSE_ERROR);\n\n\t\tthis->m_watch_point.reset();\n\t}\n\n\treturn context->QueueResponse(RESPONSE_OK);\n}\n\n// Internal functions for control\nvoid GDBServer::HandleTrapInstruction(PPCInterpreter_t* hCPU)\n{\n\t// First, restore any removed breakpoints\n\tfor (auto& bp : m_patchedInstructions)\n\t{\n\t\tif (bp.second.IsRemoved())\n\t\t\tbp.second.Restore();\n\t}\n\n\tauto patchedBP = m_patchedInstructions.find(hCPU->instructionPointer);\n\tif (patchedBP == m_patchedInstructions.end())\n\t\treturn cemu_assert_suspicious();\n\n\t// Secondly, delete one-shot breakpoints but also temporarily delete patched instruction to run original instruction\n\tOSThread_t* currThread = coreinit::OSGetCurrentThread();\n\tstd::string pauseReason = fmt::format(\"T05thread:{:08X};core:{:02X};{}\", GET_THREAD_ID(currThread), PPCInterpreter_getCoreIndex(hCPU), patchedBP->second.GetReason());\n\tbool pauseThreads = patchedBP->second.ShouldBreakThreads() || patchedBP->second.ShouldBreakThreadsOnNextInterrupt();\n\tif (patchedBP->second.IsPersistent())\n\t{\n\t\t// Insert new restore breakpoints at next possible instructions which restores breakpoints but won't pause the CPU\n\t\tstd::vector<MPTR> nextInstructions = findNextInstruction(hCPU->instructionPointer, hCPU->spr.LR, hCPU->spr.CTR);\n\t\tfor (MPTR nextInstr : nextInstructions)\n\t\t{\n\t\t\tif (!m_patchedInstructions.contains(nextInstr))\n\t\t\t\tthis->m_patchedInstructions.try_emplace(nextInstr, nextInstr, BreakpointType::BP_STEP_POINT, false, \"\");\n\t\t}\n\t\tpatchedBP->second.RemoveTemporarily();\n\t}\n\telse\n\t{\n\t\tm_patchedInstructions.erase(patchedBP);\n\t}\n\n\t// Thirdly, delete any instructions that were generated by a skip instruction\n\tfor (auto it = m_patchedInstructions.cbegin(), next_it = it; it != m_patchedInstructions.cend(); it = next_it)\n\t{\n\t\t++next_it;\n\t\tif (it->second.IsSkipBreakpoint())\n\t\t{\n\t\t\tm_patchedInstructions.erase(it);\n\t\t}\n\t}\n\n\t// Fourthly, the stub can insert breakpoints that are just meant to restore patched instructions, in which case we just want to continue\n\tif (pauseThreads)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"[GDBStub] Got trapped by a breakpoint!\");\n\t\tif (m_resumed_context)\n\t\t{\n\t\t\t// Spin up thread to signal when another GDB stub trap is found\n\t\t\tThreadPool::FireAndForget(&waitForBrokenThreads, std::move(m_resumed_context), pauseReason);\n\t\t}\n\n\t\tbreakThreads(GET_THREAD_ID(coreinit::OSGetCurrentThread()));\n\t\tcemuLog_logDebug(LogType::Force, \"[GDBStub] Resumed from a breakpoint!\");\n\t}\n}\n\nvoid GDBServer::HandleAccessException(uint64 dr6)\n{\n\tbool triggeredWrite = GetBits(dr6, 2, 1);\n\tbool triggeredReadWrite = GetBits(dr6, 3, 1);\n\n\tstd::string response;\n\tif (m_watch_point->GetType() == AccessPointType::BP_WRITE && triggeredWrite)\n\t\tresponse = fmt::format(\"watch:{:08X};\", m_watch_point->GetAddress());\n\telse if (m_watch_point->GetType() == AccessPointType::BP_READ && triggeredReadWrite && !triggeredWrite)\n\t\tresponse = fmt::format(\"rwatch:{:08X};\", m_watch_point->GetAddress());\n\telse if (m_watch_point->GetType() == AccessPointType::BP_BOTH && triggeredReadWrite)\n\t\tresponse = fmt::format(\"awatch:{:08X};\", m_watch_point->GetAddress());\n\n\tif (!response.empty())\n\t{\n\t\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\t\tcemuLog_logDebug(LogType::Force, \"Received matching breakpoint exception: {}\", response);\n\t\tauto nextInstructions = findNextInstruction(hCPU->instructionPointer, hCPU->spr.LR, hCPU->spr.CTR);\n\t\tfor (MPTR nextInstr : nextInstructions)\n\t\t{\n\t\t\tauto bpIt = m_patchedInstructions.find(nextInstr);\n\t\t\tif (bpIt == m_patchedInstructions.end())\n\t\t\t\tthis->m_patchedInstructions.try_emplace(nextInstr, nextInstr, BreakpointType::BP_STEP_POINT, false, response);\n\t\t\telse\n\t\t\t\tbpIt->second.PauseOnNextInterrupt();\n\t\t}\n\t}\n}\n\nvoid GDBServer::HandleEntryStop(uint32 entryAddress)\n{\n\tthis->m_patchedInstructions.try_emplace(entryAddress, entryAddress, BreakpointType::BP_SINGLE, false, \"\");\n\tm_entry_point = entryAddress;\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Debugger/GDBStub.h",
    "content": "#pragma once\n\n#include \"Common/precompiled.h\"\n#include \"Common/socket.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n\n#include <numeric>\n\nclass GDBServer {\npublic:\n\texplicit GDBServer(uint16 port);\n\t~GDBServer();\n\n\tbool Initialize();\n\tbool IsConnected()\n\t{\n\t\treturn m_client_connected;\n\t}\n\n\tvoid HandleEntryStop(uint32 entryAddress);\n\tvoid HandleTrapInstruction(PPCInterpreter_t* hCPU);\n\tvoid HandleAccessException(uint64 dr6);\n\n\tenum class CMDType : char\n\t{\n\t\tINVALID = '\\0',\n\t\t// Extended commands\n\t\tQUERY_GET = 'q',\n\t\tQUERY_SET = 'Q',\n\t\tVCONT = 'v',\n\t\t// Normal commands\n\t\tCONTINUE = 'c',\n\t\tIS_THREAD_RUNNING = 'T',\n\t\tSET_ACTIVE_THREAD = 'H',\n\t\tACTIVE_THREAD_STATUS = '?',\n\t\tACTIVE_THREAD_STEP = 's',\n\t\tREGISTER_READ = 'p',\n\t\tREGISTER_SET = 'P',\n\t\tREGISTERS_READ = 'g',\n\t\tREGISTERS_WRITE = 'G',\n\t\tMEMORY_READ = 'm',\n\t\tMEMORY_WRITE = 'M',\n\t\tBREAKPOINT_SET = 'Z',\n\t\tBREAKPOINT_REMOVE = 'z',\n\t};\n\n\tclass CommandContext {\n\tpublic:\n\t\tCommandContext(const GDBServer* server, const std::string& command)\n\t\t\t: m_server(server), m_command(command)\n\t\t{\n\t\t\tstd::smatch matches;\n\t\t\tstd::regex_match(command, matches, m_regex);\n\t\t\tfor (size_t i = 1; i < matches.size(); i++)\n\t\t\t{\n\t\t\t\tauto matchStr = matches[i].str();\n\t\t\t\tif (!matchStr.empty())\n\t\t\t\t\tm_args.emplace_back(std::move(matchStr));\n\t\t\t}\n\t\t\t// send acknowledgement ahead of response\n\t\t\tsend(m_server->m_client_socket, RESPONSE_ACK.data(), (int)RESPONSE_ACK.size(), 0);\n\t\t};\n\t\t~CommandContext()\n\t\t{\n\t\t\t// cemuLog_logDebug(LogType::Force, \"[GDBStub] Received: {}\", m_command);\n\t\t\t// cemuLog_logDebug(LogType::Force, \"[GDBStub] Responded: +{}\", m_response);\n\t\t\tauto response_data = EscapeMessage(m_response);\n\t\t\tauto response_full = fmt::format(\"${}#{:02x}\", response_data, CalculateChecksum(response_data));\n\t\t\tsend(m_server->m_client_socket, response_full.c_str(), (int)response_full.size(), 0);\n\t\t}\n\t\tCommandContext(const CommandContext&) = delete;\n\n\t\t[[nodiscard]] const std::string& GetCommand() const\n\t\t{\n\t\t\treturn m_command;\n\t\t};\n\t\t[[nodiscard]] const std::vector<std::string>& GetArgs() const\n\t\t{\n\t\t\treturn m_args;\n\t\t};\n\t\t[[nodiscard]] bool IsValid() const\n\t\t{\n\t\t\treturn !m_args.empty();\n\t\t};\n\t\t[[nodiscard]] CMDType GetType() const\n\t\t{\n\t\t\treturn static_cast<CMDType>(m_command[0]);\n\t\t};\n\n\t\t// Respond Utils\n\t\tstatic uint8 CalculateChecksum(std::string_view message_data)\n\t\t{\n\t\t\treturn std::accumulate(message_data.begin(), message_data.end(), (uint8)0, std::plus<>());\n\t\t}\n\t\tstatic std::string EscapeXMLString(std::string_view xml_data)\n\t\t{\n\t\t\tstd::string escaped;\n\t\t\tescaped.reserve(xml_data.size());\n\t\t\tfor (char c : xml_data)\n\t\t\t{\n\t\t\t\tswitch (c)\n\t\t\t\t{\n\t\t\t\tcase '<': escaped += \"&lt;\"; break;\n\t\t\t\tcase '>': escaped += \"&gt;\"; break;\n\t\t\t\tcase '&': escaped += \"&amp;\"; break;\n\t\t\t\tcase '\"': escaped += \"&quot;\"; break;\n\t\t\t\tcase '\\'': escaped += \"&apos;\"; break;\n\t\t\t\tdefault: escaped += c; break;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn escaped;\n\t\t}\n\t\tstatic std::string EscapeMessage(std::string_view message)\n\t\t{\n\t\t\tstd::string escaped;\n\t\t\tescaped.reserve(message.size());\n\t\t\tfor (char c : message)\n\t\t\t{\n\t\t\t\tif (c == '#' || c == '$' || c == '}' || c == '*')\n\t\t\t\t{\n\t\t\t\t\tescaped.push_back('}');\n\t\t\t\t\tescaped.push_back((char)(c ^ 0x20));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tescaped.push_back(c);\n\t\t\t}\n\t\t\treturn escaped;\n\t\t}\n\t\tvoid QueueResponse(std::string_view data)\n\t\t{\n\t\t\tm_response += data;\n\t\t}\n\n\tprivate:\n\t\tconst std::regex m_regex{\n\t\t\tR\"((?:)\"\n\t\t\tR\"((\\?))\"\n\t\t\tR\"(|(vCont\\?))\"\n\t\t\tR\"(|(vCont;)([a-zA-Z0-9-+=,\\+:;]+))\"\n\t\t\tR\"(|(qAttached))\"\n\t\t\tR\"(|(qSupported):([a-zA-Z0-9-+=,\\+;]+))\"\n\t\t\tR\"(|(qTStatus))\"\n\t\t\tR\"(|(qC))\"\n\t\t\tR\"(|(qXfer):((?:features)|(?:threads)|(?:libraries)):read:([\\w\\.]*):([0-9a-zA-Z]+),([0-9a-zA-Z]+))\"\n\t\t\tR\"(|(qfThreadInfo))\"\n\t\t\tR\"(|(qsThreadInfo))\"\n\t\t\tR\"(|(T)((?:-1)|(?:[0-9A-Fa-f]+)))\"\n\t\t\tR\"(|(D))\"\t\t\t\t\t\t\t\t\t\t\t  // Detach\n\t\t\tR\"(|(H)(c|g)((?:-1)|(?:[0-9A-Fa-f]+)))\"\t\t\t\t  // Set active thread for other operations (not c)\n\t\t\tR\"(|(c)([0-9A-Fa-f]+)?)\"\t\t\t\t\t\t\t  // (Legacy, supported by vCont) Continue all for active thread\n\t\t\tR\"(|([Zz])([0-4]),([0-9A-Fa-f]+),([0-9]))\"\t\t\t  // Insert/delete breakpoints\n\t\t\tR\"(|(g))\"\t\t\t\t\t\t\t\t\t\t\t  // Read registers for active thread\n\t\t\tR\"(|(G)([0-9A-Fa-f]+))\"\t\t\t\t\t\t\t\t  // Write registers for active thread\n\t\t\tR\"(|(p)([0-9A-Fa-f]+))\"\t\t\t\t\t\t\t\t  // Read register for active thread\n\t\t\tR\"(|(P)([0-9A-Fa-f]+)=([0-9A-Fa-f]+))\"\t\t\t\t  // Write register for active thread\n\t\t\tR\"(|(m)([0-9A-Fa-f]+),([0-9A-Fa-f]+))\"\t\t\t\t  // Read memory\n\t\t\tR\"(|(M)([0-9A-Fa-f]+),([0-9A-Fa-f]+):([0-9A-Fa-f]+))\" // Write memory\n\t\t\t// R\"(|(X)([0-9A-Fa-f]+),([0-9A-Fa-f]+):([0-9A-Fa-f]+))\" // Write memory\n\t\t\tR\"())\"};\n\t\tconst GDBServer* m_server;\n\t\tconst std::string m_command;\n\t\tstd::vector<std::string> m_args;\n\t\tstd::string m_response;\n\t};\n\n\tclass ExecutionBreakpoint;\n\tstd::map<MPTR, ExecutionBreakpoint> m_patchedInstructions;\n\n\tclass AccessBreakpoint;\n\tstd::unique_ptr<AccessBreakpoint> m_watch_point;\n\nprivate:\n\tstatic constexpr int s_maxGDBClients = 1;\n\tstatic constexpr std::string_view s_supportedFeatures = \"PacketSize=4096;qXfer:features:read+;qXfer:threads:read+;qXfer:libraries:read+;swbreak+;hwbreak+;vContSupported+\";\n\tstatic constexpr size_t s_maxPacketSize = 1024 * 4;\n\tconst uint16 m_port;\n\n\tenum RegisterID\n\t{\n\t\tR0_START = 0,\n\t\tR31_END = R0_START + 31,\n\t\tPC = 64,\n\t\tMSR = 65,\n\t\tCR = 66,\n\t\tLR = 67,\n\t\tCTR = 68,\n\t\tXER = 69,\n\t\tF0_START = 71,\n\t\tF31_END = F0_START + 31,\n\t\tFPSCR = 103\n\t};\n\n\tstatic constexpr std::string_view RESPONSE_EMPTY = \"\";\n\tstatic constexpr std::string_view RESPONSE_ACK = \"+\";\n\tstatic constexpr std::string_view RESPONSE_NACK = \"-\";\n\tstatic constexpr std::string_view RESPONSE_OK = \"OK\";\n\tstatic constexpr std::string_view RESPONSE_ERROR = \"E01\";\n\n\tvoid ThreadFunc();\n\tstd::atomic_bool m_stopRequested;\n\tvoid HandleCommand(const std::string& command_str);\n\tvoid HandleQuery(std::unique_ptr<CommandContext>& context) const;\n\tvoid HandleVCont(std::unique_ptr<CommandContext>& context);\n\n\t// Commands\n\tsint64 m_activeThreadSelector = 0;\n\tsint64 m_activeThreadContinueSelector = 0;\n\tvoid CMDContinue(std::unique_ptr<CommandContext>& context);\n\tvoid CMDNotFound(std::unique_ptr<CommandContext>& context);\n\tvoid CMDIsThreadActive(std::unique_ptr<CommandContext>& context);\n\tvoid CMDSetActiveThread(std::unique_ptr<CommandContext>& context);\n\tvoid CMDGetThreadStatus(std::unique_ptr<CommandContext>& context);\n\n\tvoid CMDReadRegister(std::unique_ptr<CommandContext>& context) const;\n\tvoid CMDWriteRegister(std::unique_ptr<CommandContext>& context) const;\n\tvoid CMDReadRegisters(std::unique_ptr<CommandContext>& context) const;\n\tvoid CMDWriteRegisters(std::unique_ptr<CommandContext>& context) const;\n\tvoid CMDReadMemory(std::unique_ptr<CommandContext>& context);\n\tvoid CMDWriteMemory(std::unique_ptr<CommandContext>& context);\n\tvoid CMDInsertBreakpoint(std::unique_ptr<CommandContext>& context);\n\tvoid CMDDeleteBreakpoint(std::unique_ptr<CommandContext>& context);\n\n\tstd::thread m_thread;\n\tstd::atomic_bool m_resume_startup = false;\n\tMPTR m_entry_point{};\n\tstd::unique_ptr<CommandContext> m_resumed_context;\n\n\tstd::atomic_bool m_client_connected;\n\tSOCKET m_server_socket = INVALID_SOCKET;\n\tsockaddr_in m_server_addr{};\n\tSOCKET m_client_socket = INVALID_SOCKET;\n\tsockaddr_in m_client_addr{};\n};\n\nstatic constexpr std::string_view GDBTargetXML = R\"(<?xml version=\"1.0\"?>\n<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n<target version=\"1.0\">\n    <architecture>powerpc:common</architecture>\n    <feature name=\"org.gnu.gdb.power.core\">\n        <reg name=\"r0\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r1\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r2\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r3\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r4\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r5\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r6\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r7\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r8\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r9\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r10\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r11\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r12\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r13\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r14\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r15\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r16\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r17\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r18\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r19\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r20\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r21\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r22\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r23\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r24\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r25\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r26\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r27\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r28\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r29\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r30\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"r31\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"pc\" bitsize=\"32\" type=\"code_ptr\" regnum=\"64\"/>\n        <reg name=\"msr\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"cr\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"lr\" bitsize=\"32\" type=\"code_ptr\"/>\n        <reg name=\"ctr\" bitsize=\"32\" type=\"uint32\"/>\n        <reg name=\"xer\" bitsize=\"32\" type=\"uint32\"/>\n    </feature>\n    <feature name=\"org.gnu.gdb.power.fpu\">\n        <reg name=\"f0\" bitsize=\"64\" type=\"ieee_double\" regnum=\"71\"/>\n        <reg name=\"f1\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f2\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f3\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f4\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f5\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f6\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f7\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f8\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f9\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f10\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f11\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f12\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f13\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f14\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f15\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f16\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f17\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f18\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f19\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f20\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f21\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f22\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f23\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f24\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f25\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f26\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f27\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f28\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f29\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f30\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"f31\" bitsize=\"64\" type=\"ieee_double\"/>\n        <reg name=\"fpscr\" bitsize=\"32\" group=\"float\"/>\n    </feature>\n</target>)\";\n\nextern std::unique_ptr<GDBServer> g_gdbstub;\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/EspressoISA.h",
    "content": "#pragma once\n\nnamespace Espresso\n{\n\tenum CR_BIT\n\t{\n\t\tCR_BIT_INDEX_LT = 0,\n\t\tCR_BIT_INDEX_GT = 1,\n\t\tCR_BIT_INDEX_EQ = 2,\n\t\tCR_BIT_INDEX_SO = 3,\n\t};\n\n\tenum class PSQ_LOAD_TYPE // also store type\n\t{\n\t\tTYPE_F32 = 0,\n\t\tTYPE_UNUSED1 = 1,\n\t\tTYPE_UNUSED2 = 2,\n\t\tTYPE_UNUSED3 = 3,\n\t\tTYPE_U8 = 4,\n\t\tTYPE_U16 = 5,\n\t\tTYPE_S8 = 6,\n\t\tTYPE_S16 = 7,\n\t};\n\n\tenum class PrimaryOpcode\n\t{\n\t\t// underscore at the end of the name means that this instruction always updates CR0 (as if RC bit is set)\n\t\tZERO = 0,\n\t\tVIRTUAL_HLE = 1,\n\n\t\t// 3 = TWI\n\t\tGROUP_4 = 4,\n\t\tMULLI = 7,\n\t\tSUBFIC = 8,\n\t\tCMPLI = 10,\n\t\tCMPI = 11,\n\t\tADDIC = 12,\n\t\tADDIC_ = 13,\n\t\tADDI = 14,\n\t\tADDIS = 15,\n\t\tBC = 16, // conditional branch\n\t\tGROUP_17 = 17, // SC\n\t\tB = 18, // unconditional branch\n\t\tGROUP_19 = 19,\n\t\tRLWIMI = 20,\n\t\tRLWINM = 21,\n\t\t// 22 ?\n\t\tRLWNM = 23,\n\t\tORI = 24,\n\t\tORIS = 25,\n\t\tXORI = 26,\n\t\tXORIS = 27,\n\t\tANDI_ = 28,\n\t\tANDIS_ = 29,\n\t\tGROUP_31 = 31,\n\t\tLWZ = 32,\n\t\tLWZU = 33,\n\t\tLBZ = 34,\n\t\tLBZU = 35,\n\t\tSTW = 36,\n\t\tSTWU = 37,\n\t\tSTB = 38,\n\t\tSTBU = 39,\n\t\tLHZ = 40,\n\t\tLHZU = 41,\n\t\tLHA = 42,\n\t\tLHAU = 43,\n\t\tSTH = 44,\n\t\tSTHU = 45,\n\t\tLMW = 46,\n\t\tSTMW = 47,\n\t\tLFS = 48,\n\t\tLFSU = 49,\n\t\tLFD = 50,\n\t\tLFDU = 51,\n\t\tSTFS = 52,\n\t\tSTFSU = 53,\n\t\tSTFD = 54,\n\t\tSTFDU = 55,\n\t\tPSQ_L = 56,\n\t\tPSQ_LU = 57,\n\t\t// 58 ?\n\t\tGROUP_59 = 59,\n\t\tPSQ_ST = 60,\n\t\tPSQ_STU = 61,\n\t\t// 62 ?\n\t\tGROUP_63 = 63,\n\t};\n\n\tenum class Opcode19\n\t{\n\t\tMCRF = 0,\n\t\tBCLR = 16,\n\t\tCRNOR = 33,\n\t\tRFI = 50,\n\t\tCRANDC = 129,\n\t\tISYNC = 150,\n\t\tCRXOR = 193,\n\t\tCRAND = 257,\n\t\tCREQV = 289,\n\t\tCRORC = 417,\n\t\tCROR = 449,\n\t\tBCCTR = 528\n\t};\n\n\tenum class Opcode31\n\t{\n\t\tTW = 4,\n\t\tMFTB = 371,\n\t};\n\n\tinline PrimaryOpcode GetPrimaryOpcode(uint32 opcode) { return (PrimaryOpcode)(opcode >> 26); };\n\tinline Opcode19 GetGroup19Opcode(uint32 opcode) { return (Opcode19)((opcode >> 1) & 0x3FF); };\n\tinline Opcode31 GetGroup31Opcode(uint32 opcode) { return (Opcode31)((opcode >> 1) & 0x3FF); };\n\n\tstruct BOField \n\t{\n\t\tBOField() = default;\n\t\tBOField(uint8 bo) : bo(bo) {};\n\n\t\tbool conditionInverted() const\n\t\t{\n\t\t\treturn (bo & 8) == 0;\n\t\t}\n\n\t\tbool decrementerIgnore() const\n\t\t{\n\t\t\treturn (bo & 4) != 0;\n\t\t}\n\n\t\tbool decrementerMustBeZero() const\n\t\t{\n\t\t\treturn (bo & 2) != 0;\n\t\t}\n\n\t\tbool conditionIgnore() const\n\t\t{\n\t\t\treturn (bo & 16) != 0;\n\t\t}\n\n\t\tbool branchAlways()\n\t\t{\n\t\t\treturn conditionIgnore() && decrementerIgnore();\n\t\t}\n\n\t\tuint8 bo;\n\t};\n\n\t// returns true if LK bit is set, only valid for branch instructions\n\tinline bool DecodeLK(uint32 opcode)\n\t{\n\t\treturn (opcode & 1) != 0;\n\t}\n\n\tinline void _decodeForm_I(uint32 opcode, uint32& LI, bool& AA, bool& LK)\n\t{\n\t\tLI = opcode & 0x3fffffc;\n\t\tif (LI & 0x02000000)\n\t\t\tLI |= 0xfc000000;\n\t\tAA = (opcode & 2) != 0;\n\t\tLK = (opcode & 1) != 0;\n\t}\n\n\tinline void _decodeForm_D_branch(uint32 opcode, uint32& BD, BOField& BO, uint32& BI, bool& AA, bool& LK)\n\t{\n\t\tBD = opcode & 0xfffc;\n\t\tif (BD & 0x8000)\n\t\t\tBD |= 0xffff0000;\n\t\tBO = { (uint8)((opcode >> 21) & 0x1F) };\n\t\tBI = (opcode >> 16) & 0x1F;\n\t\tAA = (opcode & 2) != 0;\n\t\tLK = (opcode & 1) != 0;\n\t}\n\n\tinline void _decodeForm_D_SImm(uint32 opcode, uint32& rD, uint32& rA, uint32& imm)\n\t{\n\t\trD = (opcode >> 21) & 0x1F;\n\t\trA = (opcode >> 16) & 0x1F;\n\t\timm = (uint32)(sint32)(sint16)(opcode & 0xFFFF);\n\t}\n\n\tinline void _decodeForm_XL(uint32 opcode, BOField& BO, uint32& BI, bool& LK)\n\t{\n\t\tBO = { (uint8)((opcode >> 21) & 0x1F) };\n\t\tBI = (opcode >> 16) & 0x1F;\n\t\tLK = (opcode & 1) != 0;\n\t}\n\n\tinline void decodeOp_ADDI(uint32 opcode, uint32& rD, uint32& rA, uint32& imm)\n\t{\n\t\t_decodeForm_D_SImm(opcode, rD, rA, imm);\n\t}\n\n\tinline void decodeOp_B(uint32 opcode, uint32& LI, bool& AA, bool& LK)\n\t{\n\t\t// form I\n\t\t_decodeForm_I(opcode, LI, AA, LK);\n\t}\n\n\tinline void decodeOp_BC(uint32 opcode, uint32& BD, BOField& BO, uint32& BI, bool& AA, bool& LK)\n\t{\n\t\t// form D\n\t\t_decodeForm_D_branch(opcode, BD, BO, BI, AA, LK);\n\t}\n\n\tinline void decodeOp_BCSPR(uint32 opcode, BOField& BO, uint32& BI, bool& LK) // BCLR and BCSPR\n\t{\n\t\t// form XL (with BD field expected to be zero)\n\t\t_decodeForm_XL(opcode, BO, BI, LK);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp",
    "content": "\nstatic void PPCInterpreter_setXerOV(PPCInterpreter_t* hCPU, bool hasOverflow)\n{\n\tif (hasOverflow)\n\t{\n\t\thCPU->xer_so = 1;\n\t\thCPU->xer_ov = 1;\n\t}\n\telse\n\t{\n\t\thCPU->xer_ov = 0;\n\t}\n}\n\nstatic bool checkAdditionOverflow(uint32 x, uint32 y, uint32 r)\n{\n\n\t/*\n\t\tx\ty\tr\tresult\t(has overflow)\n\t\t0\t0\t0\t0\n\t\t1\t0\t0\t0\n\t\t0\t1\t0\t0\n\t\t1\t1\t0\t1\n\t\t0\t0\t1\t1\n\t\t1\t0\t1\t0\n\t\t0\t1\t1\t0\n\t\t1\t1\t1\t0\n\n\t*/\n\treturn (((x ^ r) & (y ^ r)) >> 31) != 0;\n}\n\nstatic void PPCInterpreter_ADD(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\thCPU->gpr[rD] = (int)hCPU->gpr[rA] + (int)hCPU->gpr[rB];\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\t// Don't Starve Giant Edition uses this instruction + BSO\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 result = hCPU->gpr[rA] + hCPU->gpr[rB];\n\tPPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(hCPU->gpr[rA], hCPU->gpr[rB], result));\n\thCPU->gpr[rD] = (uint32)result;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDC(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 a = hCPU->gpr[rA];\n\thCPU->gpr[rD] = a + hCPU->gpr[rB];\n\tif (hCPU->gpr[rD] < a)\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDCO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = hCPU->gpr[rB];\n\thCPU->gpr[rD] = a + b;\n\tif (hCPU->gpr[rD] < a)\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\t// set SO/OV\n\tPPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, b, hCPU->gpr[rD]));\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDE(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = hCPU->gpr[rB];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = a + b + ca;\n\t// update xer\n\tif (ppc_carry_3(a, b, ca))\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDEO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\t// used by DS Virtual Console (Super Mario 64 DS)\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = hCPU->gpr[rB];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = a + b + ca;\n\t// update xer carry\n\tif (ppc_carry_3(a, b, ca))\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tPPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, b, hCPU->gpr[rD]));\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDI(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tsint32 rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\thCPU->gpr[rD] = (rA ? (int)hCPU->gpr[rA] : 0) + (int)imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDIC(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tsint32 rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\tuint32 a = hCPU->gpr[rA];\n\thCPU->gpr[rD] = a + imm;\n\t// update XER\n\tif (hCPU->gpr[rD] < a)\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDIC_(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tsint32 rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\tuint32 a = hCPU->gpr[rA];\n\thCPU->gpr[rD] = a + imm;\n\t// update XER\n\tif (hCPU->gpr[rD] < a)\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDIS(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tsint32 rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_Shift16(opcode, rD, rA, imm);\n\thCPU->gpr[rD] = (rA ? hCPU->gpr[rA] : 0) + imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDZE(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = a + ca;\n\tif ((a == 0xffffffff) && ca)\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDZEO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = a + ca;\n\tPPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, 0, hCPU->gpr[rD]));\n\tif ((a == 0xffffffff) && ca)\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDME(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = a + ca + 0xffffffff;\n\tif (a || ca)\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ADDMEO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = a + ca + 0xffffffff;\n\tPPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, 0xffffffff, hCPU->gpr[rD]));\n\tif (a || ca)\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBF(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\thCPU->gpr[rD] = ~hCPU->gpr[rA] + hCPU->gpr[rB] + 1;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBFO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\t// Seen in Don't Starve Giant Edition and Teslagrad\n\t// also used by DS Virtual Console (Super Mario 64 DS)\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 result = ~hCPU->gpr[rA] + hCPU->gpr[rB] + 1;\n\tPPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~hCPU->gpr[rA], hCPU->gpr[rB], result));\n\thCPU->gpr[rD] = result;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBFC(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = hCPU->gpr[rB];\n\thCPU->gpr[rD] = ~a + b + 1;\n\t// update xer\n\tif (ppc_carry_3(~a, b, 1))\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBFCO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\t// used by DS Virtual Console (Super Mario 64 DS)\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = hCPU->gpr[rB];\n\thCPU->gpr[rD] = ~a + b + 1;\n\t// update carry\n\tif (ppc_carry_3(~a, b, 1))\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\t// update xer SO/OV\n\tPPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, b, hCPU->gpr[rD]));\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBFIC(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tsint32 rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\tuint32 a = hCPU->gpr[rA];\n\thCPU->gpr[rD] = ~a + imm + 1;\n\tif (ppc_carry_3(~a, imm, 1))\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBFE(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = hCPU->gpr[rB];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = ~a + b + ca;\n\t// update xer carry\n\tif (ppc_carry_3(~a, b, ca))\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBFEO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = hCPU->gpr[rB];\n\tuint32 ca = hCPU->xer_ca;\n\tuint32 result = ~a + b + ca;\n\thCPU->gpr[rD] = result;\n\t// update xer carry\n\tif (ppc_carry_3(~a, b, ca))\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tPPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, b, result));\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBFZE(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = ~a + ca;\n\tif (a == 0 && ca)\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBFZEO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = ~a + ca;\n\tPPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, 0, hCPU->gpr[rD]));\n\tif (a == 0 && ca)\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBFME(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = ~a + 0xFFFFFFFF + ca;\n\t// update xer carry\n\tif (ppc_carry_3(~a, 0xFFFFFFFF, ca))\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opcode & PPC_OPC_RC)\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SUBFMEO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 ca = hCPU->xer_ca;\n\thCPU->gpr[rD] = ~a + 0xFFFFFFFF + ca;\n\tPPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, 0xFFFFFFFF, hCPU->gpr[rD]));\n\t// update xer carry\n\tif (ppc_carry_3(~a, 0xFFFFFFFF, ca))\n\t\thCPU->xer_ca = 1;\n\telse\n\t\thCPU->xer_ca = 0;\n\tif (opcode & PPC_OPC_RC)\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_MULHW_(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tsint64 a = (sint32)hCPU->gpr[rA];\n\tsint64 b = (sint32)hCPU->gpr[rB];\n\tsint64 c = a * b;\n\thCPU->gpr[rD] = ((uint64)c) >> 32;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_MULHWU_(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint64 a = hCPU->gpr[rA];\n\tuint64 b = hCPU->gpr[rB];\n\tuint64 c = a * b;\n\thCPU->gpr[rD] = c >> 32;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_MULLW(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tsint64 result = (sint64)hCPU->gpr[rA] * (sint64)hCPU->gpr[rB];\n\thCPU->gpr[rD] = (uint32)result;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_MULLWO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\t// Don't Starve Giant Edition uses this instruction + BSO\n\t// also used by FullBlast when a save file exists + it uses mfxer to access overflow result\n\tPPC_OPC_TEMPL3_XO();\n\tsint64 result = (sint64)(sint32)hCPU->gpr[rA] * (sint64)(sint32)hCPU->gpr[rB];\n\thCPU->gpr[rD] = (uint32)result;\n\tPPCInterpreter_setXerOV(hCPU, result < -0x80000000ll || result > 0x7FFFFFFFLL);\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_MULLI(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tint rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\thCPU->gpr[rD] = hCPU->gpr[rA] * imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_DIVW(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tsint32 a = (sint32)hCPU->gpr[rA];\n\tsint32 b = (sint32)hCPU->gpr[rB];\n\tif (b == 0)\n\t\thCPU->gpr[rD] = a < 0 ? 0xFFFFFFFF : 0;\n\telse if (a == 0x80000000 && b == 0xFFFFFFFF)\n\t\thCPU->gpr[rD] = 0xFFFFFFFF;\n\telse\n\t\thCPU->gpr[rD] = a / b;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_DIVWO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tsint32 a = (sint32)hCPU->gpr[rA];\n\tsint32 b = (sint32)hCPU->gpr[rB];\n\tif (b == 0)\n\t{\n\t\tPPCInterpreter_setXerOV(hCPU, true);\n\t\thCPU->gpr[rD] = a < 0 ? 0xFFFFFFFF : 0;\n\t}\n\telse if(a == 0x80000000 && b == 0xFFFFFFFF)\n\t{\n\t\tPPCInterpreter_setXerOV(hCPU, true);\n\t\thCPU->gpr[rD] = 0xFFFFFFFF;\n\t}\n\telse\n\t{\n\t\thCPU->gpr[rD] = a / b;\n\t\tPPCInterpreter_setXerOV(hCPU, false);\n\t}\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_DIVWU(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = hCPU->gpr[rB];\n\tif (b == 0)\n\t\thCPU->gpr[rD] = 0;\n\telse if (a == 0x80000000 && b == 0xFFFFFFFF)\n\t\thCPU->gpr[rD] = 0;\n\telse\n\t\thCPU->gpr[rD] = a / b;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_DIVWUO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = hCPU->gpr[rB];\n\tif (b == 0)\n\t{\n\t\tPPCInterpreter_setXerOV(hCPU, true);\n\t\thCPU->gpr[rD] = 0;\n\t}\n\telse if(a == 0x80000000 && b == 0xFFFFFFFF)\n\t{\n\t\tPPCInterpreter_setXerOV(hCPU, false);\n\t\thCPU->gpr[rD] = 0;\n\t}\n\telse\n\t{\n\t\thCPU->gpr[rD] = a / b;\n\t\tPPCInterpreter_setXerOV(hCPU, false);\n\t}\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CREQV(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL_X_CR();\n\tppc_setCRBit(hCPU, crD, ppc_getCRBit(hCPU, crA) ^ ppc_getCRBit(hCPU, crB) ^ 1);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CRAND(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL_X_CR();\n\tppc_setCRBit(hCPU, crD, ppc_getCRBit(hCPU, crA)&ppc_getCRBit(hCPU, crB));\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CRANDC(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL_X_CR();\n\tppc_setCRBit(hCPU, crD, ppc_getCRBit(hCPU, crA)&(ppc_getCRBit(hCPU, crB) ^ 1));\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CRNAND(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL_X_CR();\n\tppc_setCRBit(hCPU, crD, (ppc_getCRBit(hCPU, crA)&ppc_getCRBit(hCPU, crB)) ^ 1);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CROR(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL_X_CR();\n\tppc_setCRBit(hCPU, crD, ppc_getCRBit(hCPU, crA) | ppc_getCRBit(hCPU, crB));\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CRORC(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL_X_CR();\n\tppc_setCRBit(hCPU, crD, ppc_getCRBit(hCPU, crA) | (ppc_getCRBit(hCPU, crB) ^ 1));\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CRNOR(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL_X_CR();\n\tppc_setCRBit(hCPU, crD, (ppc_getCRBit(hCPU, crA) | ppc_getCRBit(hCPU, crB)) ^ 1);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CRXOR(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL_X_CR();\n\tppc_setCRBit(hCPU, crD, ppc_getCRBit(hCPU, crA) ^ ppc_getCRBit(hCPU, crB));\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_NEG(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\thCPU->gpr[rD] = (uint32)-((sint32)hCPU->gpr[rA]);\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_NEGO(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\tPPCInterpreter_setXerOV(hCPU, hCPU->gpr[rA] == 0x80000000);\n\thCPU->gpr[rD] = (uint32)-((sint32)hCPU->gpr[rA]);\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ANDX(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\thCPU->gpr[rA] = hCPU->gpr[rD] & hCPU->gpr[rB];\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ANDCX(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\thCPU->gpr[rA] = hCPU->gpr[rD] & ~hCPU->gpr[rB];\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ANDI_(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tint rS, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);\n\thCPU->gpr[rA] = hCPU->gpr[rS] & imm;\n\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ANDIS_(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tint rS, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);\n\thCPU->gpr[rA] = hCPU->gpr[rS] & imm;\n\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_NANDX(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\thCPU->gpr[rA] = ~(hCPU->gpr[rD] & hCPU->gpr[rB]);\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_OR(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\thCPU->gpr[rA] = hCPU->gpr[rD] | hCPU->gpr[rB];\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ORC(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\thCPU->gpr[rA] = hCPU->gpr[rD] | ~hCPU->gpr[rB];\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ORI(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tint rS, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);\n\thCPU->gpr[rA] = hCPU->gpr[rS] | imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_ORIS(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tint rS, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);\n\thCPU->gpr[rA] = hCPU->gpr[rS] | imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_NORX(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\thCPU->gpr[rA] = ~(hCPU->gpr[rD] | hCPU->gpr[rB]);\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_XOR(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\thCPU->gpr[rA] = hCPU->gpr[rD] ^ hCPU->gpr[rB];\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_XORI(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tint rS, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);\n\thCPU->gpr[rA] = hCPU->gpr[rS] ^ imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_XORIS(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tint rS, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);\n\thCPU->gpr[rA] = hCPU->gpr[rS] ^ imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_EQV(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\thCPU->gpr[rA] = ~(hCPU->gpr[rD] ^ hCPU->gpr[rB]);\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_RLWIMI(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tint rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\tuint32 v = ppc_word_rotl(hCPU->gpr[rS], SH);\n\tuint32 mask = ppc_mask(MB, ME);\n\thCPU->gpr[rA] = (v & mask) | (hCPU->gpr[rA] & ~mask);\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_RLWINM(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tsint32 rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\tuint32 v = ppc_word_rotl(hCPU->gpr[rS], SH);\n\tuint32 mask = ppc_mask(MB, ME);\n\thCPU->gpr[rA] = v & mask;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_RLWNM(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tint rS, rA, rB, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, rB, MB, ME);\n\tuint32 v = ppc_word_rotl(hCPU->gpr[rS], hCPU->gpr[rB]);\n\tuint32 mask = ppc_mask(MB, ME);\n\thCPU->gpr[rA] = v & mask;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SLWX(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 s = hCPU->gpr[rB] & 0x3f;\n\tif (s > 31)\n\t\thCPU->gpr[rA] = 0;\n\telse\n\t\thCPU->gpr[rA] = hCPU->gpr[rD] << s;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SRAW(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 sh = hCPU->gpr[rB] & 0x3f;\n\thCPU->gpr[rA] = hCPU->gpr[rD];\n\tif (sh > 31)\n\t{\n\t\thCPU->xer_ca = (hCPU->gpr[rA] >> 31) & 1; // copy sign bit to ca\n\t\thCPU->gpr[rA] = (uint32)((sint32)hCPU->gpr[rA] >> 31); // fill all bits with sign bit\n\t}\n\telse\n\t{\n\t\t// ca is set when input is negative and non-zero bits are dropped by shift operation\n\t\tuint8 caBit = (hCPU->gpr[rA] >> 31) & 1;\n\t\tuint32 shiftedBits = hCPU->gpr[rA] & ~(0xFFFFFFFF << sh);\n\t\tcaBit &= (shiftedBits != 0 ? 1 : 0);\n\t\thCPU->xer_ca = caBit;\n\t\thCPU->gpr[rA] = (uint32)((sint32)hCPU->gpr[rA] >> sh);\n\t}\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SRWX(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tuint32 v = hCPU->gpr[rB] & 0x3f;\n\tif (v > 31)\n\t\thCPU->gpr[rA] = 0;\n\telse\n\t\thCPU->gpr[rA] = hCPU->gpr[rD] >> v;\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_SRAWI(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tsint32 rS, rA;\n\tuint32 SH;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, SH);\n\thCPU->gpr[rA] = hCPU->gpr[rS];\n\thCPU->xer_ca = 0;\n\tif (hCPU->gpr[rA] & 0x80000000)\n\t{\n\t\tuint32 ca = 0;\n\t\tfor (uint32 i = 0; i < SH; i++)\n\t\t{\n\t\t\tif (hCPU->gpr[rA] & 1)\n\t\t\t\tca = 1;\n\t\t\thCPU->gpr[rA] >>= 1;\n\t\t\thCPU->gpr[rA] |= 0x80000000;\n\t\t}\n\t\tif (ca)\n\t\t\thCPU->xer_ca = 1;\n\t}\n\telse\n\t{\n\t\tif (SH > 31)\n\t\t\thCPU->gpr[rA] = 0;\n\t\telse\n\t\t\thCPU->gpr[rA] >>= SH;\n\t}\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic uint32 _CNTLZW(uint32 v)\n{\n\tuint32 result = 0;\n\tif (v == 0)\n\t\treturn 32;\n\tif ((v & 0xFFFF0000) != 0) { result |= 16; v >>= 16; }\n\tif ((v & 0xFF00FF00) != 0) { result |= 8; v >>= 8; }\n\tif ((v & 0xF0F0F0F0) != 0) { result |= 4; v >>= 4; }\n\tif ((v & 0xCCCCCCCC) != 0) { result |= 2; v >>= 2; }\n\tif ((v & 0xAAAAAAAA) != 0) { result |= 1; }\n\tresult = 31 - result;\n\treturn result;\n}\n\nstatic void PPCInterpreter_CNTLZW(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\thCPU->gpr[rA] = _CNTLZW(hCPU->gpr[rD]);\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_EXTSB(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\thCPU->gpr[rA] = (uint32)(sint32)(sint8)hCPU->gpr[rD];\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_EXTSH(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tPPC_OPC_TEMPL3_XO();\n\tPPC_ASSERT(rB == 0);\n\thCPU->gpr[rA] = (uint32)(sint32)(sint16)hCPU->gpr[rD];\n\tif (opHasRC())\n\t\tppc_update_cr0(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CMP(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tuint32 cr;\n\tsint32 rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, cr, rA, rB);\n\tcr >>= 2;\n\tsint32 a = hCPU->gpr[rA];\n\tsint32 b = hCPU->gpr[rB];\n\thCPU->cr[cr * 4 + 0] = 0;\n\thCPU->cr[cr * 4 + 1] = 0;\n\thCPU->cr[cr * 4 + 2] = 0;\n\thCPU->cr[cr * 4 + 3] = 0;\n\tif (a < b)\n\t\thCPU->cr[cr * 4 + CR_BIT_LT] = 1;\n\telse if (a > b)\n\t\thCPU->cr[cr * 4 + CR_BIT_GT] = 1;\n\telse \n\t\thCPU->cr[cr * 4 + CR_BIT_EQ] = 1;\n\thCPU->cr[cr * 4 + CR_BIT_SO] = hCPU->xer_so;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CMPL(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tuint32 cr;\n\tint rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, cr, rA, rB);\n\tcr >>= 2;\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = hCPU->gpr[rB];\n\thCPU->cr[cr * 4 + 0] = 0;\n\thCPU->cr[cr * 4 + 1] = 0;\n\thCPU->cr[cr * 4 + 2] = 0;\n\thCPU->cr[cr * 4 + 3] = 0;\n\tif (a < b)\n\t\thCPU->cr[cr * 4 + CR_BIT_LT] = 1;\n\telse if (a > b)\n\t\thCPU->cr[cr * 4 + CR_BIT_GT] = 1;\n\telse\n\t\thCPU->cr[cr * 4 + CR_BIT_EQ] = 1;\n\thCPU->cr[cr * 4 + CR_BIT_SO] = hCPU->xer_so;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CMPI(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tuint32 cr;\n\tint rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, cr, rA, imm);\n\tcr >>= 2;\n\tsint32 a = hCPU->gpr[rA];\n\tsint32 b = imm;\n\thCPU->cr[cr * 4 + 0] = 0;\n\thCPU->cr[cr * 4 + 1] = 0;\n\thCPU->cr[cr * 4 + 2] = 0;\n\thCPU->cr[cr * 4 + 3] = 0;\n\tif (a < b)\n\t\thCPU->cr[cr * 4 + CR_BIT_LT] = 1;\n\telse if (a > b)\n\t\thCPU->cr[cr * 4 + CR_BIT_GT] = 1;\n\telse \n\t\thCPU->cr[cr * 4 + CR_BIT_EQ] = 1;\n\thCPU->cr[cr * 4 + CR_BIT_SO] = hCPU->xer_so;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_CMPLI(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tuint32 cr;\n\tint rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_UImm(opcode, cr, rA, imm);\n\tcr >>= 2;\n\tuint32 a = hCPU->gpr[rA];\n\tuint32 b = imm;\n\thCPU->cr[cr * 4 + 0] = 0;\n\thCPU->cr[cr * 4 + 1] = 0;\n\thCPU->cr[cr * 4 + 2] = 0;\n\thCPU->cr[cr * 4 + 3] = 0;\n\tif (a < b)\n\t\thCPU->cr[cr * 4 + CR_BIT_LT] = 1;\n\telse if (a > b)\n\t\thCPU->cr[cr * 4 + CR_BIT_GT] = 1;\n\telse\n\t\thCPU->cr[cr * 4 + CR_BIT_EQ] = 1;\n\thCPU->cr[cr * 4 + CR_BIT_SO] = hCPU->xer_so;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterFPU.cpp",
    "content": "#include \"../PPCState.h\"\n#include \"PPCInterpreterInternal.h\"\n#include \"PPCInterpreterHelper.h\"\n\n#include<math.h>\n\n// floating point utility\n\n#include <limits>\n#include <array>\n\nconst int ieee_double_e_bits = 11; // exponent bits\nconst int ieee_double_m_bits = 52; // mantissa bits\n\nconst int espresso_frsqrte_i_bits = 5; // index bits (the highest bit is the LSB of the exponent)\n\ntypedef struct\n{\n\tuint32 offset;\n\tuint32 step;\n}espresso_frsqrte_entry_t;\n\nespresso_frsqrte_entry_t frsqrteLookupTable[32] =\n{\n\t{0x1a7e800, 0x568},{0x17cb800, 0x4f3},{0x1552800, 0x48d},{0x130c000, 0x435},\n\t{0x10f2000, 0x3e7},{0xeff000, 0x3a2},{0xd2e000, 0x365},{0xb7c000, 0x32e},\n\t{0x9e5000, 0x2fc},{0x867000, 0x2d0},{0x6ff000, 0x2a8},{0x5ab800, 0x283},\n\t{0x46a000, 0x261},{0x339800, 0x243},{0x218800, 0x226},{0x105800, 0x20b},\n\t{0x3ffa000, 0x7a4},{0x3c29000, 0x700},{0x38aa000, 0x670},{0x3572000, 0x5f2},\n\t{0x3279000, 0x584},{0x2fb7000, 0x524},{0x2d26000, 0x4cc},{0x2ac0000, 0x47e},\n\t{0x2881000, 0x43a},{0x2665000, 0x3fa},{0x2468000, 0x3c2},{0x2287000, 0x38e},\n\t{0x20c1000, 0x35e},{0x1f12000, 0x332},{0x1d79000, 0x30a},{0x1bf4000, 0x2e6},\n};\n\nATTR_MS_ABI double frsqrte_espresso(double input)\n{\n\tunsigned long long x = *(unsigned long long*)&input;\n\n\t// 0.0 and -0.0\n\tif ((x << 1) == 0)\n\t{\n\t\t// result is inf or -inf\n\t\tx &= ~0x7FFFFFFFFFFFFFFF;\n\t\tx |= 0x7FF0000000000000;\n\t\treturn *(double*)&x;\n\t}\n\t// get exponent\n\tuint32 e = (x >> ieee_double_m_bits) & ((1ull << ieee_double_e_bits) - 1ull);\n\t// NaN or INF\n\tif (e == 0x7FF)\n\t{\n\t\tif ((x&((1ull << ieee_double_m_bits) - 1)) == 0)\n\t\t{\n\t\t\t// negative INF returns +NaN\n\t\t\tif ((sint64)x < 0)\n\t\t\t{\n\t\t\t\tx = 0x7FF8000000000000;\n\t\t\t\treturn *(double*)&x;\n\t\t\t}\n\t\t\t// positive INF returns +0.0\n\t\t\treturn 0.0;\n\t\t}\n\t\t// result is NaN with same sign and same mantissa (todo: verify)\n\t\treturn *(double*)&x;\n\t}\n\t// negative number (other than -0.0)\n\tif ((sint64)x < 0)\n\t{\n\t\t// result is positive NaN\n\t\tx = 0x7FF8000000000000;\n\t\treturn *(double*)&x;\n\t}\n\t// todo: handle denormals\n\n\t// get index (lsb of exponent, remaining bits of mantissa)\n\tuint32 idx = (x >> (ieee_double_m_bits - espresso_frsqrte_i_bits + 1ull))&((1 << espresso_frsqrte_i_bits) - 1);\n\t// get step multiplier\n\tuint32 stepMul = (x >> (ieee_double_m_bits - espresso_frsqrte_i_bits + 1 - 11))&((1 << 11) - 1);\n\n\tsint32 sum = frsqrteLookupTable[idx].offset - frsqrteLookupTable[idx].step * stepMul;\n\n\te = 1023 - ((e - 1021) >> 1);\n\tx &= ~(((1ull << ieee_double_e_bits) - 1ull) << ieee_double_m_bits);\n\tx |= ((unsigned long long)e << ieee_double_m_bits);\n\n\tx &= ~((1ull << ieee_double_m_bits) - 1ull);\n\tx += ((unsigned long long)sum << 26ull);\n\n\treturn *(double*)&x;\n}\n\nconst int espresso_fres_i_bits = 5; // index bits\nconst int espresso_fres_s_bits = 10; // step multiplier bits\n\ntypedef struct\n{\n\tuint32 offset;\n\tuint32 step;\n}espresso_fres_entry_t;\n\nespresso_fres_entry_t fresLookupTable[32] =\n{\n\t// table calculated by fres_gen_table()\n\t{0x7ff800, 0x3e1},\t{0x783800, 0x3a7},\t{0x70ea00, 0x371},\t{0x6a0800, 0x340},\n\t{0x638800, 0x313},\t{0x5d6200, 0x2ea},\t{0x579000, 0x2c4},\t{0x520800, 0x2a0},\n\t{0x4cc800, 0x27f},\t{0x47ca00, 0x261},\t{0x430800, 0x245},\t{0x3e8000, 0x22a},\n\t{0x3a2c00, 0x212},\t{0x360800, 0x1fb},\t{0x321400, 0x1e5},\t{0x2e4a00, 0x1d1},\n\t{0x2aa800, 0x1be},\t{0x272c00, 0x1ac},\t{0x23d600, 0x19b},\t{0x209e00, 0x18b},\n\t{0x1d8800, 0x17c},\t{0x1a9000, 0x16e},\t{0x17ae00, 0x15b},\t{0x14f800, 0x15b},\n\t{0x124400, 0x143},\t{0xfbe00, 0x143},\t{0xd3800, 0x12d},\t{0xade00, 0x12d},\n\t{0x88400, 0x11a},\t{0x65000, 0x11a},\t{0x41c00, 0x108},\t{0x20c00, 0x106}\n};\n\nATTR_MS_ABI double fres_espresso(double input)\n{\n\t// based on testing we know that fres uses only the first 15 bits of the mantissa\n\t// seee eeee eeee mmmm mmmm mmmm mmmx xxxx ....\t\t(s = sign, e = exponent, m = mantissa, x = not used)\n\t// the mantissa bits are interpreted as following:\n\t// 0000 0000 0000 iiii ifff ffff fff0 ...\t\t\t(i = table look up index , f = step multiplier)\n\tunsigned long long x = *(unsigned long long*)&input;\n\n\t// get index\n\tuint32 idx = (x >> (ieee_double_m_bits - espresso_fres_i_bits))&((1 << espresso_fres_i_bits) - 1);\n\t// get step multiplier\n\tuint32 stepMul = (x >> (ieee_double_m_bits - espresso_fres_i_bits - 10))&((1 << 10) - 1);\n\n\n\tuint32 sum = fresLookupTable[idx].offset - (fresLookupTable[idx].step * stepMul + 1) / 2;\n\n\t// get exponent\n\tuint32 e = (x >> ieee_double_m_bits) & ((1ull << ieee_double_e_bits) - 1ull);\n\tif (e == 0)\n\t{\n\t\t// todo?\n\t\t//x &= 0x7FFFFFFFFFFFFFFFull;\n\t\tx |= 0x7FF0000000000000ull;\n\t\treturn *(double*)&x;\n\t}\n\telse if (e == 0x7ff) // NaN or INF\n\t{\n\t\tif ((x&((1ull << ieee_double_m_bits) - 1)) == 0)\n\t\t{\n\t\t\t// negative INF returns -0.0\n\t\t\tif ((sint64)x < 0)\n\t\t\t{\n\t\t\t\tx = 0x8000000000000000;\n\t\t\t\treturn *(double*)&x;\n\t\t\t}\n\t\t\t// positive INF returns +0.0\n\t\t\treturn 0.0;\n\t\t}\n\t\t// result is NaN with same sign and same mantissa (todo: verify)\n\t\treturn *(double*)&x;\n\t}\n\t// todo - needs more testing (especially NaN and INF values)\n\n\te = 2045 - e;\n\tx &= ~(((1ull << ieee_double_e_bits) - 1ull) << ieee_double_m_bits);\n\tx |= ((unsigned long long)e << ieee_double_m_bits);\n\n\tx &= ~((1ull << ieee_double_m_bits) - 1ull);\n\tx += ((unsigned long long)sum << 29ull);\n\n\treturn *(double*)&x;\n}\n\nvoid fcmpu_espresso(PPCInterpreter_t* hCPU, int crfD, double a, double b)\n{\n\tuint32 c;\n\n\tppc_setCRBit(hCPU, crfD + 0, 0);\n\tppc_setCRBit(hCPU, crfD + 1, 0);\n\tppc_setCRBit(hCPU, crfD + 2, 0);\n\tppc_setCRBit(hCPU, crfD + 3, 0);\n\n\tif (IS_NAN(*(uint64*)&a) || IS_NAN(*(uint64*)&b))\n\t{\n\t\tc = 1;\n\t\tppc_setCRBit(hCPU, crfD + CR_BIT_SO, 1);\n\t}\n\telse if (a < b)\n\t{\n\t\tc = 8;\n\t\tppc_setCRBit(hCPU, crfD + CR_BIT_LT, 1);\n\t}\n\telse if (a > b)\n\t{\n\t\tc = 4;\n\t\tppc_setCRBit(hCPU, crfD + CR_BIT_GT, 1);\n\t}\n\telse\n\t{\n\t\tc = 2;\n\t\tppc_setCRBit(hCPU, crfD + CR_BIT_EQ, 1);\n\t}\n\n\tif (IS_SNAN(*(uint64*)&a) || IS_SNAN(*(uint64*)&b))\n\t\thCPU->fpscr |= FPSCR_VXSNAN;\n\n\thCPU->fpscr = (hCPU->fpscr & 0xffff0fff) | (c << 12);\n}\n\nvoid PPCInterpreter_FMR(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, rA, frB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, rA, frB);\n\tPPC_ASSERT(rA==0);\n\thCPU->fpr[frD].fpr = hCPU->fpr[frB].fpr;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FSEL(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tif ( hCPU->fpr[frA].fp0 >= -0.0f )\n\t\thCPU->fpr[frD] = hCPU->fpr[frC];\n\telse\n\t\thCPU->fpr[frD] = hCPU->fpr[frB];\n\tPPC_ASSERT((Opcode & PPC_OPC_RC) != 0); // update CR1 flags\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FCTIWZ(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tint frD, frA, frB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\n\tdouble b = hCPU->fpr[frB].fpr;\n\tuint64 v;\n\tif (b > (double)0x7FFFFFFF)\n\t{\n\t\tv = (uint64)0x7FFFFFFF;\n\t}\n\telse if (b < -(double)0x80000000)\n\t{\n\t\tv = (uint64)0x80000000;\n\t}\n\telse\n\t{\n\t\tv = (uint64)(uint32)(sint32)b;\n\t}\n\n\thCPU->fpr[frD].guint = 0xFFF8000000000000ULL | v;\n\tif (v == 0 && ((*(uint64*)&b) >> 63))\n\t\thCPU->fpr[frD].guint |= 0x100000000ull;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FCTIW(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\n\tdouble b = hCPU->fpr[frB].fpr;\n\tuint64 v;\n\tif (b > (double)0x7FFFFFFF)\n\t{\n\t\tv = (uint64)0x7FFFFFFF;\n\t}\n\telse if (b < -(double)0x80000000)\n\t{\n\t\tv = (uint64)0x80000000;\n\t}\n\telse\n\t{\n\t\t// todo: Support for other rounding modes than NEAR\n\t\tdouble t = b + 0.5;\n\t\tsint32 i = (sint32)t;\n\t\tif (t - i < 0 || (t - i == 0 && b > 0))\n\t\t{\n\t\t\ti--;\n\t\t}\n\t\tv = (uint64)i;\n\t}\n\thCPU->fpr[frD].guint = 0xFFF8000000000000ULL | v;\n\tif (v == 0 && ((*(uint64*)&b) >> 63))\n\t\thCPU->fpr[frD].guint |= 0x100000000ull;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FNEG(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\t\n\thCPU->fpr[frD].guint = hCPU->fpr[frB].guint ^ (1ULL << 63);\n\n\tPPC_ASSERT((Opcode & PPC_OPC_RC) != 0); // update CR1 flags\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FRSP(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tint frD, frA, frB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\n\tif( PPC_PSE )\n\t{\n\t\thCPU->fpr[frD].fp0 = (float)hCPU->fpr[frB].fpr;\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frD].fp0;\n\t}\n\telse\n\t{\n\t\thCPU->fpr[frD].fpr = (float)hCPU->fpr[frB].fpr;\n\t}\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FRSQRTE(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frA==0 && frC==0);\n\t\n\thCPU->fpr[frD].fpr = frsqrte_espresso(hCPU->fpr[frB].fpr);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FRES(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frA==0 && frC==0);\n\n\thCPU->fpr[frD].fpr = fres_espresso(hCPU->fpr[frB].fpr);\n\t\n\tif(PPC_PSE) \n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frD].fp0;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n// Floating point ALU\n\nvoid PPCInterpreter_FABS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\n\thCPU->fpr[frD].guint = hCPU->fpr[frB].guint & ~0x8000000000000000;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FNABS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\t\n\thCPU->fpr[frD].guint = hCPU->fpr[frB].guint | 0x8000000000000000;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FADD(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frC==0);\n\n\thCPU->fpr[frD].fpr = hCPU->fpr[frA].fpr + hCPU->fpr[frB].fpr;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FDIV(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frC==0);\n\n\thCPU->fpr[frD].fpr = hCPU->fpr[frA].fpr / hCPU->fpr[frB].fpr;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FSUB(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frC==0);\n\n\thCPU->fpr[frD].fpr = hCPU->fpr[frA].fpr - hCPU->fpr[frB].fpr;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FMUL(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frC == 0);\n\n\thCPU->fpr[frD].fpr = hCPU->fpr[frA].fpr * hCPU->fpr[frC].fpr;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FMADD(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\n\thCPU->fpr[frD].fpr = hCPU->fpr[frA].fpr * hCPU->fpr[frC].fpr + hCPU->fpr[frB].fpr;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FNMADD(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\n\thCPU->fpr[frD].fpr = -(hCPU->fpr[frA].fpr * hCPU->fpr[frC].fpr + hCPU->fpr[frB].fpr);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FMSUB(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\n\thCPU->fpr[frD].fpr = (hCPU->fpr[frA].fpr * hCPU->fpr[frC].fpr - hCPU->fpr[frB].fpr);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FNMSUB(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\n\thCPU->fpr[frD].fpr = -(hCPU->fpr[frA].fpr * hCPU->fpr[frC].fpr - hCPU->fpr[frB].fpr);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n// Move\n\nvoid PPCInterpreter_MFFS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, rA, rB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, rA, rB);\n\tPPC_ASSERT(rA==0 && rB==0);\n\thCPU->fpr[frD].guint = (uint64)hCPU->fpscr;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_MTFSF(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frB;\n\tuint32 fm, FM;\n\tPPC_OPC_TEMPL_XFL(Opcode, frB, fm);\n\tFM = ((fm&0x80)?0xf0000000:0)|((fm&0x40)?0x0f000000:0)|((fm&0x20)?0x00f00000:0)|((fm&0x10)?0x000f0000:0)|\n\t     ((fm&0x08)?0x0000f000:0)|((fm&0x04)?0x00000f00:0)|((fm&0x02)?0x000000f0:0)|((fm&0x01)?0x0000000f:0);\n\thCPU->fpscr = (hCPU->fpr[frB].guint & FM) | (hCPU->fpscr & ~FM);\n\n\tPPC_ASSERT((Opcode & PPC_OPC_RC) != 0); // update CR1 flags\n\n\tstatic bool logFPSCRWriteOnce = false;\n\tif( logFPSCRWriteOnce == false )\n\t{\n\t\tcemuLog_log(LogType::Force, \"Unsupported write to FPSCR\");\n\t\tlogFPSCRWriteOnce = true;\n\t}\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n// single precision\n\nvoid PPCInterpreter_FADDS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frB == 0);\n\t\n\t// todo: check for RC\n\n\thCPU->fpr[frD].fpr = (float)(hCPU->fpr[frA].fpr + hCPU->fpr[frB].fpr);\n\tif (PPC_PSE)\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frD].fp0;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FSUBS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frB == 0);\n\n\thCPU->fpr[frD].fpr = (float)(hCPU->fpr[frA].fpr - hCPU->fpr[frB].fpr);\n\tif (PPC_PSE)\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frD].fp0;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FDIVS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frB==0);\n\n\thCPU->fpr[frD].fpr = (float)(hCPU->fpr[frA].fpr / hCPU->fpr[frB].fpr);\n\tif( PPC_PSE )\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frD].fp0;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FMULS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frB == 0);\n\n\thCPU->fpr[frD].fpr = (float)(hCPU->fpr[frA].fpr * roundTo25BitAccuracy(hCPU->fpr[frC].fpr));\n\tif (PPC_PSE)\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frD].fp0;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FMADDS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\n\thCPU->fpr[frD].fpr = (float)(hCPU->fpr[frA].fpr * roundTo25BitAccuracy(hCPU->fpr[frC].fpr) + hCPU->fpr[frB].fpr);\n\tif (PPC_PSE)\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frD].fp0;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FNMADDS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\n\thCPU->fpr[frD].fpr = (float)-(hCPU->fpr[frA].fpr * roundTo25BitAccuracy(hCPU->fpr[frC].fpr) + hCPU->fpr[frB].fpr);\n\tif (PPC_PSE)\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frD].fp0;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FMSUBS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\n\thCPU->fpr[frD].fp0 = (float)(hCPU->fpr[frA].fp0 * roundTo25BitAccuracy(hCPU->fpr[frC].fp0) - hCPU->fpr[frB].fp0);\n\tif (PPC_PSE)\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frD].fp0;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FNMSUBS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(Opcode, frD, frA, frB, frC);\n\n\thCPU->fpr[frD].fp0 = (float)-(hCPU->fpr[frA].fp0 * roundTo25BitAccuracy(hCPU->fpr[frC].fp0) - hCPU->fpr[frB].fp0);\n\tif (PPC_PSE)\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frD].fp0;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n// Compare\n\nvoid PPCInterpreter_FCMPO(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tint crfD, frA, frB;\n\tPPC_OPC_TEMPL_X(Opcode, crfD, frA, frB);\n\tcrfD >>= 2;\n\thCPU->cr[crfD*4+0] = 0;\n\thCPU->cr[crfD*4+1] = 0;\n\thCPU->cr[crfD*4+2] = 0;\n\thCPU->cr[crfD*4+3] = 0;\n\n\tuint32 c;\n\tif(IS_NAN(hCPU->fpr[frA].guint) || IS_NAN(hCPU->fpr[frB].guint))\n\t{\n\t\tc = 1;\n\t\thCPU->cr[crfD*4+CR_BIT_SO] = 1;\n\t}\n    else if(hCPU->fpr[frA].fpr < hCPU->fpr[frB].fpr)\n\t{\n\t\tc = 8;\n\t\thCPU->cr[crfD*4+CR_BIT_LT] = 1;\n\t}\n\telse if(hCPU->fpr[frA].fpr > hCPU->fpr[frB].fpr)\n\t{\n\t\tc = 4;\n\t\thCPU->cr[crfD*4+CR_BIT_GT] = 1;\n\t}\n\telse\n\t{\n\t\tc = 2;\n\t\thCPU->cr[crfD*4+CR_BIT_EQ] = 1;\n\t}\n\n    hCPU->fpscr = (hCPU->fpscr & 0xffff0fff) | (c << 12);\n\n\tif (IS_SNAN (hCPU->fpr[frA].guint) || IS_SNAN (hCPU->fpr[frB].guint))\n\t\thCPU->fpscr |= FPSCR_VXSNAN;\n\telse if (!(hCPU->fpscr & FPSCR_VE) || IS_QNAN (hCPU->fpr[frA].guint) || IS_QNAN (hCPU->fpr[frB].guint))\n\t\thCPU->fpscr |= FPSCR_VXVC;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_FCMPU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tint crfD, frA, frB;\n\tPPC_OPC_TEMPL_X(Opcode, crfD, frA, frB);\n\tcemu_assert_debug((crfD % 4) == 0);\n\tfcmpu_espresso(hCPU, crfD, hCPU->fpr[frA].fp0, hCPU->fpr[frB].fp0);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterHLE.cpp",
    "content": "#include \"../PPCState.h\"\n#include \"PPCInterpreterInternal.h\"\n#include \"PPCInterpreterHelper.h\"\n\nstd::unordered_set<std::string> s_unsupportedHLECalls;\n\nvoid PPCInterpreter_handleUnsupportedHLECall(PPCInterpreter_t* hCPU)\n{\n\tconst char* libFuncName = (char*)memory_getPointerFromVirtualOffset(hCPU->instructionPointer + 8);\n\tstd::string tempString = fmt::format(\"Unsupported lib call: {}\", libFuncName);\n\tif (s_unsupportedHLECalls.find(tempString) == s_unsupportedHLECalls.end())\n\t{\n\t\tcemuLog_log(LogType::UnsupportedAPI, \"{}\", tempString);\n\t\ts_unsupportedHLECalls.emplace(tempString);\n\t}\n\thCPU->gpr[3] = 0;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic constexpr size_t HLE_TABLE_CAPACITY = 0x4000;\nHLECALL s_ppcHleTable[HLE_TABLE_CAPACITY]{};\nsint32 s_ppcHleTableWriteIndex = 0;\nstd::mutex s_ppcHleTableMutex;\n\nHLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall, std::string hleName)\n{\n\tstd::unique_lock _l(s_ppcHleTableMutex);\n\tif (s_ppcHleTableWriteIndex >= HLE_TABLE_CAPACITY)\n\t{\n\t\tcemuLog_log(LogType::Force, \"HLE table is full\");\n\t\tcemu_assert(false);\n\t}\n\tfor (sint32 i = 0; i < s_ppcHleTableWriteIndex; i++)\n\t{\n\t\tif (s_ppcHleTable[i] == hleCall)\n\t\t{\n\t\t\treturn i;\n\t\t}\n\t}\n\tcemu_assert(s_ppcHleTableWriteIndex < HLE_TABLE_CAPACITY);\n\ts_ppcHleTable[s_ppcHleTableWriteIndex] = hleCall;\n\tHLEIDX funcIndex = s_ppcHleTableWriteIndex;\n\ts_ppcHleTableWriteIndex++;\n\treturn funcIndex;\n}\n\nHLECALL PPCInterpreter_getHLECall(HLEIDX funcIndex)\n{\n\tif (funcIndex < 0 || funcIndex >= HLE_TABLE_CAPACITY)\n\t\treturn nullptr;\n\treturn s_ppcHleTable[funcIndex];\n}\n\nstd::mutex s_hleLogMutex;\n\nvoid PPCInterpreter_virtualHLE(PPCInterpreter_t* hCPU, unsigned int opcode)\n{\n\tuint32 hleFuncId = opcode & 0xFFFF;\n\tif (hleFuncId == 0xFFD0) [[unlikely]]\n\t{\n\t\ts_hleLogMutex.lock();\n\t\tPPCInterpreter_handleUnsupportedHLECall(hCPU);\n\t\ts_hleLogMutex.unlock();\n\t}\n\telse\n\t{\n\t\t// os lib function\n\t\tauto hleCall = PPCInterpreter_getHLECall(hleFuncId);\n\t\tcemu_assert(hleCall);\n\t\thleCall(hCPU);\n\t}\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterHelper.h",
    "content": "\nstatic uint32 ppc_cmp_and_mask[8] = {\n\t0xfffffff0,\n\t0xffffff0f,\n\t0xfffff0ff,\n\t0xffff0fff,\n\t0xfff0ffff,\n\t0xff0fffff,\n\t0xf0ffffff,\n\t0x0fffffff,\n};\n\n\n#define ppc_word_rotl(_data, _n) (std::rotl<uint32>(_data,(_n)&0x1F))\n\nstatic inline uint32 ppc_mask(int MB, int ME)\n{\n\tuint32 maskMB = 0xFFFFFFFF >> MB;\n\tuint32 maskME = 0xFFFFFFFF << (31-ME);\n\tuint32 mask2 = (MB <= ME) ? maskMB & maskME : maskMB | maskME;\n\treturn mask2;\n}\n\nstatic inline bool ppc_carry_3(uint32 a, uint32 b, uint32 c)\n{\n\tif ((a+b) < a) {\n\t\treturn true;\n\t}\n\tif ((a+b+c) < c) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n#define PPC_getBits(__value, __index, __bitCount) ((__value>>(31-__index))&((1<<__bitCount)-1))\n\nconst static float LD_SCALE[] = {\n1.000000f, 0.500000f, 0.250000f, 0.125000f, 0.062500f, 0.031250f, 0.015625f,\n0.007813f, 0.003906f, 0.001953f, 0.000977f, 0.000488f, 0.000244f, 0.000122f,\n0.000061f, 0.000031f, 0.000015f, 0.000008f, 0.000004f, 0.000002f, 0.000001f,\n0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f, 0.000000f,\n0.000000f, 0.000000f, 0.000000f, 0.000000f, 4294967296.000000f, 2147483648.000000f,\n1073741824.000000f, 536870912.000000f, 268435456.000000f, 134217728.000000f, 67108864.000000f,\n33554432.000000f, 16777216.000000f, 8388608.000000f, 4194304.000000f, 2097152.000000f, 1048576.000000f,\n524288.000000f, 262144.000000f, 131072.000000f, 65536.000000f, 32768.000000f, 16384.000000f,\n8192.000000f, 4096.000000f, 2048.000000f, 1024.000000f, 512.000000f, 256.000000f, 128.000000f, 64.000000f, 32.000000f,\n16.000000f, 8.000000f, 4.000000f, 2.000000f };\n\nconst static float ST_SCALE[] = {\n1.000000f, 2.000000f, 4.000000f, 8.000000f,\n16.000000f, 32.000000f, 64.000000f, 128.000000f,\n256.000000f, 512.000000f, 1024.000000f, 2048.000000f,\n4096.000000f, 8192.000000f, 16384.000000f, 32768.000000f,\n65536.000000f, 131072.000000f, 262144.000000f, 524288.000000f,\n1048576.000000f, 2097152.000000f, 4194304.000000f, 8388608.000000f,\n16777216.000000f, 33554432.000000f, 67108864.000000f, 134217728.000000f,\n268435456.000000f, 536870912.000000f, 1073741824.000000f, 2147483648.000000f,\n0.000000f, 0.000000f, 0.000000f, 0.000000f,\n0.000000f, 0.000000f, 0.000000f, 0.000000f,\n0.000000f, 0.000000f, 0.000000f, 0.000000f,\n0.000001f, 0.000002f, 0.000004f, 0.000008f,\n0.000015f, 0.000031f, 0.000061f, 0.000122f,\n0.000244f, 0.000488f, 0.000977f, 0.001953f,\n0.003906f, 0.007813f, 0.015625f, 0.031250f,\n0.062500f, 0.125000f, 0.250000f, 0.500000f };\n\nstatic float dequantize(uint32 data, sint32 type, uint8 scale)\n{\n\tfloat f;\n\tswitch (type)\n\t{\n\tcase 4: // u8\n\t\tf = (float)(uint8)data; \n\t\tf *= LD_SCALE[scale];\n\t\tbreak;\n\tcase 5: // u16\n\t\tf = (float)(uint16)data; \n\t\tf *= LD_SCALE[scale];\n\t\tbreak;\n\tcase 6: // s8\n\t\tf = (float)(sint8)data;\n\t\tf *= LD_SCALE[scale];\n\t\tbreak;\n\tcase 7: // float\n\t\tf = (float)(sint16)data;\n\t\tf *= LD_SCALE[scale];\n\t\tbreak;\n\tcase 0:\n\tdefault:\n\t\tf = *((float *)&data);\n\t\t// scale does not apply when loading floats\n\t\tbreak;\n\t}\n\treturn f;\n}\n\nstatic uint32 quantize(float data, sint32 type, uint8 scale)\n{\n\tuint32 val;\n\n\tswitch (type)\n\t{\n\tcase 4: // u8\n\t\tdata *= ST_SCALE[scale];\n\t\tif (data < 0) data = 0;\n\t\tif (data > 255) data = 255;\n\t\tval = (uint8)(uint32)data; \n\t\tbreak;\n\tcase 5: // u16\n\t\tdata *= ST_SCALE[scale];\n\t\tif (data < 0) data = 0;\n\t\tif (data > 65535) data = 65535;\n\t\tval = (uint16)(uint32)data; \n\t\tbreak;\n\tcase 6: // s8\n\t\tdata *= ST_SCALE[scale];\n\t\tif (data < -128) data = -128;\n\t\tif (data > 127) data = 127;\n\t\tval = (sint8)(uint8)(sint32)(uint32)data;\n\t\tbreak;\n\tcase 7: // s16\n\t\tdata *= ST_SCALE[scale];\n\t\tif (data < -32768) data = -32768;\n\t\tif (data > 32767) data = 32767;\n\t\tval = (sint16)(uint16)(sint32)(uint32)data;\n\t\tbreak;\n\tcase 0: // float\n\tdefault: \n\t\t// scale does not apply when storing floats\n\t\t*((float*)&val) = data; \n\t\tbreak;\n\t}\n\treturn val;\n}\n\n#define _uint32_fastSignExtend(__v, __bits) (uint32)(((sint32)(__v)<<(31-(__bits)))>>(31-(__bits)));\n\nstatic inline uint64 ConvertToDoubleNoFTZ(uint32 value)\n{\n\t// http://www.freescale.com/files/product/doc/MPCFPE32B.pdf\n\n\tuint64 x = value;\n\tuint64 exp = (x >> 23) & 0xff;\n\tuint64 frac = x & 0x007fffff;\n\n\tif (exp > 0 && exp < 255)\n\t{\n\t\tuint64 y = !(exp >> 7);\n\t\tuint64 z = y << 61 | y << 60 | y << 59;\n\t\treturn ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29);\n\t}\n\telse if (exp == 0 && frac != 0) // denormal\n\t{\n\t\texp = 1023 - 126;\n\t\tdo\n\t\t{\n\t\t\tfrac <<= 1;\n\t\t\texp -= 1;\n\t\t} while ((frac & 0x00800000) == 0);\n\n\t\treturn ((x & 0x80000000) << 32) | (exp << 52) | ((frac & 0x007fffff) << 29);\n\t}\n\telse  // QNaN, SNaN or Zero\n\t{\n\t\tuint64 y = exp >> 7;\n\t\tuint64 z = y << 61 | y << 60 | y << 59;\n\t\treturn ((x & 0xc0000000) << 32) | z | ((x & 0x3fffffff) << 29);\n\t}\n}\n\nstatic inline uint32 ConvertToSingleNoFTZ(uint64 x)\n{\n\tuint32 exp = (x >> 52) & 0x7ff;\n\tif (exp > 896 || (x & ~0x8000000000000000ULL) == 0)\n\t{\n\t\treturn ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff);\n\t}\n\telse if (exp >= 874)\n\t{\n\t\tuint32 t = (uint32)(0x80000000 | ((x & 0x000FFFFFFFFFFFFFULL) >> 21));\n\t\tt = t >> (905 - exp);\n\t\tt |= (x >> 32) & 0x80000000;\n\t\treturn t;\n\t}\n\telse\n\t{\n\t\treturn ((x >> 32) & 0xc0000000) | ((x >> 29) & 0x3fffffff);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp",
    "content": "#include \"PPCInterpreterInternal.h\"\n#include \"PPCInterpreterHelper.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include \"Cafe/HW/Espresso/Debugger/GDBStub.h\"\n\nclass PPCItpCafeOSUsermode\n{\npublic:\n\tstatic const bool allowSupervisorMode = false;\n\tstatic const bool allowDSI = false;\n\n\tinline static uint32 memory_readCodeU32(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\treturn _swapEndianU32(*(uint32*)(memory_base + address));\n\t}\n\n\tinline static void ppcMem_writeDataDouble(PPCInterpreter_t* hCPU, uint32 address, double vf)\n\t{\n\t\tuint64 v = *(uint64*)&vf;\n\t\tuint32 v1 = v & 0xFFFFFFFF;\n\t\tuint32 v2 = v >> 32;\n\t\tuint8* ptr = memory_getPointerFromVirtualOffset(address);\n\t\t*(uint32*)(ptr + 4) = CPU_swapEndianU32(v1);\n\t\t*(uint32*)(ptr + 0) = CPU_swapEndianU32(v2);\n\t}\n\n\tinline static void ppcMem_writeDataU64(PPCInterpreter_t* hCPU, uint32 address, uint64 v)\n\t{\n\t\t*(uint64*)(memory_getPointerFromVirtualOffset(address)) = CPU_swapEndianU64(v);\n\t}\n\n\tinline static void ppcMem_writeDataU32(PPCInterpreter_t* hCPU, uint32 address, uint32 v)\n\t{\n\t\t*(uint32*)(memory_getPointerFromVirtualOffset(address)) = CPU_swapEndianU32(v);\n\t}\n\n\tinline static void ppcMem_writeDataU16(PPCInterpreter_t* hCPU, uint32 address, uint16 v)\n\t{\n\t\t*(uint16*)(memory_getPointerFromVirtualOffset(address)) = CPU_swapEndianU16(v);\n\t}\n\n\tinline static void ppcMem_writeDataU8(PPCInterpreter_t* hCPU, uint32 address, uint8 v)\n\t{\n\t\t*(uint8*)(memory_getPointerFromVirtualOffset(address)) = v;\n\t}\n\t\n\tinline static double ppcMem_readDataDouble(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint32 v[2];\n\t\tv[1] = *(uint32*)(memory_getPointerFromVirtualOffset(address));\n\t\tv[0] = *(uint32*)(memory_getPointerFromVirtualOffset(address) + 4);\n\t\tv[0] = CPU_swapEndianU32(v[0]);\n\t\tv[1] = CPU_swapEndianU32(v[1]);\n\t\treturn *(double*)v;\n\t}\n\n\tinline static float ppcMem_readDataFloat(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint32 v = *(uint32*)(memory_getPointerFromVirtualOffset(address));\n\t\tv = CPU_swapEndianU32(v);\n\t\treturn *(float*)&v;\n\t}\n\n\tinline static uint64 ppcMem_readDataU64(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint64 v = *(uint64*)(memory_getPointerFromVirtualOffset(address));\n\t\treturn CPU_swapEndianU64(v);\n\t}\n\n\tinline static uint32 ppcMem_readDataU32(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint32 v = *(uint32*)(memory_getPointerFromVirtualOffset(address));\n\t\treturn CPU_swapEndianU32(v);\n\t}\n\n\tinline static uint16 ppcMem_readDataU16(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint16 v = *(uint16*)(memory_getPointerFromVirtualOffset(address));\n\t\treturn CPU_swapEndianU16(v);\n\t}\n\n\tinline static uint8 ppcMem_readDataU8(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\treturn *(uint8*)(memory_getPointerFromVirtualOffset(address));\n\t}\n\n\tinline static uint64 ppcMem_readDataFloatEx(PPCInterpreter_t* hCPU, uint32 addr)\n\t{\n\t\treturn ConvertToDoubleNoFTZ(_swapEndianU32(*(uint32*)(memory_base + addr)));\n\t}\n\n\tinline static void ppcMem_writeDataFloatEx(PPCInterpreter_t* hCPU, uint32 addr, uint64 value)\n\t{\n\t\t*(uint32*)(memory_base + addr) = _swapEndianU32(ConvertToSingleNoFTZ(value));\n\t}\n\n\tinline static uint64 getTB(PPCInterpreter_t* hCPU)\n\t{\n\t\treturn PPCInterpreter_getMainCoreCycleCounter();\n\t}\n};\n\nuint32 debug_lastTranslatedHit;\n\nvoid generateDSIException(PPCInterpreter_t* hCPU, uint32 dataAddress)\n{\n\t// todo - check if we are already inside an interrupt handler (in which case the DSI exception is queued and not executed immediately?)\n\n\t// set flag to cancel current instruction\n\thCPU->memoryException = true;\n\n\thCPU->sprExtended.srr0 = hCPU->instructionPointer;\n\thCPU->sprExtended.srr1 = hCPU->sprExtended.msr & 0x87C0FFFF;\n\n\thCPU->sprExtended.dar = dataAddress;\n\n\thCPU->sprExtended.msr &= ~0x04EF36;\n\n\thCPU->instructionPointer = 0xFFF00300;\n\n\n\tuint32 dsisr = 0;\n\tdsisr |= (1<<(31-1)); // set if no TLB/BAT match found\n\n\thCPU->sprExtended.dsisr = dsisr;\n\n}\n\nclass PPCItpSupervisorWithMMU\n{\npublic:\n\tstatic const bool allowSupervisorMode = true;\n\tstatic const bool allowDSI = true;\n\n\tinline static uint32 ppcMem_translateVirtualDataToPhysicalAddr(PPCInterpreter_t* hCPU, uint32 vAddr)\n\t{\n\t\t// check if address translation is disabled for data accesses\n\t\tif (GET_MSR_BIT(MSR_DR) == 0)\n\t\t{\n\t\t\treturn vAddr;\n\t\t}\n\n#ifdef CEMU_DEBUG_ASSERT\n\t\tif (hCPU->memoryException)\n\t\t\tassert_dbg(); // should not be set anymore\n#endif\n\n\t\t// how to determine if BAT is valid:\n\t\t// BAT_entry_valid = (Vs & ~MSR[PR]) | (Vp & MSR[PR]) (The entry has separate enable flags for usermode and supervisor mode)\n\t\tfor (sint32 i = 0; i < 8; i++)\n\t\t{\n\t\t\t// upper\n\t\t\tuint32 batU = hCPU->sprExtended.dbatU[i];\n\t\t\tuint32 BEPI = ((batU >> 17) & 0x7FFF) << 17;\n\t\t\tuint32 Vp = (batU >> 0) & 1;\n\t\t\tuint32 Vs = (batU >> 1) & 1;\n\t\t\tuint32 BL = (((batU >> 2) & 0x7FF) ^ 0x7FF) << 17;\n\t\t\tBL |= 0xF0000000;\n\t\t\tif (Vs == 0)\n\t\t\t\tcontinue; // todo - check if in supervisor/usermode\n\t\t\t// lower\n\t\t\tuint32 batL = hCPU->sprExtended.dbatL[i];\n\t\t\tuint32 PP = (batL >> 0) & 3;\n\t\t\tuint32 WIMG = (batL >> 3) & 0xF;\n\t\t\tuint32 BRPN = ((batL >> 17) & 0x7FFF) << 17;\n\n\t\t\t// check for match\n\t\t\tif ((vAddr&BL) == BEPI)\n\t\t\t{\n\t\t\t\t// match\n\t\t\t\tvAddr = (vAddr&~BL) | (BRPN&BL);\n\t\t\t\tdebug_lastTranslatedHit = vAddr;\n\t\t\t\treturn vAddr;\n\t\t\t}\n\t\t}\n\n\t\t// no match\n\t\tdebug_lastTranslatedHit = 0xFFFFFFFF;\n\n\t\t// find segment\n\t\tuint32 segmentIndex = (vAddr>>28);\n\t\t//uint32 pageIndex = (vAddr >> 12) & 0xFFFF; // for 4KB pages\n\t\t// uint32 byteOffset = vAddr & 0xFFF; // for 4KB pages\n\t\tuint32 pageIndex = (vAddr >> 17) & 0x7FF; // for 128KB pages \n\t\tuint32 byteOffset = vAddr & 0x1FFFF;\n\t\tuint32 srValue = hCPU->sprExtended.sr[segmentIndex];\n\t\t\n\t\tuint8 sr_ks = (srValue >> 30) & 1; // supervisor\n\t\tuint8 sr_kp = (srValue >> 29) & 1; // user mode\n\t\tuint8 sr_n = (srValue >> 28) & 1; // no-execute\n\t\tuint32 sr_vsid = (srValue & 0xFFFFFF);\n\t\t//uint32 vpn = pageIndex | (sr_vsid << 16); // 40bit virtual page number\n\n\n\t\t// look up in page table\n\t\t//uint32 lookupHash = (sr_vsid ^ pageIndex) & 0x7FFFF; // not correct for 4KB pages? sr_vsid must be shifted?\n\t\t//uint32 lookupHash = (sr_vsid ^ pageIndex) & 0x7FFFF;\n\t\t//uint32 lookupHash = ((sr_vsid>>8) ^ pageIndex) & 0x7FFFF;\n\t\tuint32 lookupHash = ((sr_vsid >> 0) ^ pageIndex) & 0x7FFFF;\n\n\t\t//lookupHash ^= 0x7FFFF;\n\n\t\tuint32 pageTableAddr = hCPU->sprExtended.sdr1&0xFFFF0000;\n\t\tuint32 pageTableMask = hCPU->sprExtended.sdr1&0x1FF;\n\n\t\tfor (uint32 ch = 0; ch < 2; ch++)\n\t\t{\n\t\t\tuint32 ptegSelectLow = (lookupHash & 0x3FF);\n\t\t\tuint32 maskOR = (lookupHash >> 10) & pageTableMask;\n\n\t\t\tuint32* pteg = (uint32*)(memory_base + (pageTableAddr | (maskOR << 16)) + ptegSelectLow * 64);\n\t\t\tfor (sint32 t = 0; t < 8; t++)\n\t\t\t{\n\t\t\t\tuint32 w0 = _swapEndianU32(pteg[0]);\n\t\t\t\tuint32 w1 = _swapEndianU32(pteg[1]);\n\t\t\t\tpteg += 2;\n\t\t\t\tif ((w0 & 0x80000000) == 0)\n\t\t\t\t\tcontinue; // entry not valid\n\n\t\t\t\tuint32 abPageIndex = (w0 >> 0) & 0x3F;\n\t\t\t\tuint8 h = (w0 >> 6) & 1;\n\t\t\t\tuint32 ptegVSID = (w0 >> 7) & 0xFFFFFF;\n\n\t\t\t\tif (abPageIndex == (pageIndex >> 5) && ptegVSID == sr_vsid && h == ch)\n\t\t\t\t{\n\t\t\t\t\tif (ch == 1)\n\t\t\t\t\t\tassert_dbg();\n\t\t\t\t\t// match\n\t\t\t\t\tuint32 ptegPhysicalPage = (w1 >> 12) & 0xFFFFF;\n\t\t\t\t\t// replace page (128KB)\n\t\t\t\t\tvAddr = (vAddr & ~0xFFFE0000) | (ptegPhysicalPage << 12);\n\t\t\t\t\treturn vAddr;\n\n\t\t\t\t}\n\t\t\t}\n\t\t\t// calculate hash 2\n\t\t\tlookupHash = ~lookupHash;\n\t\t}\n\n\t\tcemuLog_logDebug(LogType::Force, \"DSI exception at 0x{:08x} DataAddress {:08x}\", hCPU->instructionPointer, vAddr);\n\n\t\tgenerateDSIException(hCPU, vAddr);\n\n\t\t// todo: Check hash func 1\n\t\t// todo: Check protection bits\n\t\t// todo: Check supervisor/usermode bits\n\n\n\t\t// also use this function in all the mem stuff below\n\n\t\t// note: bat has higher priority than TLB\n\n\t\t// since iterating the bats and page table is too slow, we need to pre-process the data somehow.\n\n\t\treturn vAddr;\n\t}\n\n\tinline static uint32 ppcMem_translateVirtualCodeToPhysicalAddr(PPCInterpreter_t* hCPU, uint32 vAddr)\n\t{\n\t\t// check if address translation is disabled for instruction accesses\n\t\tif (GET_MSR_BIT(MSR_IR) == 0)\n\t\t{\n\t\t\treturn vAddr;\n\t\t}\n\n\t\t// how to determine if BAT is valid:\n\t\t// BAT_entry_valid = (Vs & ~MSR[PR]) | (Vp & MSR[PR]) (The entry has separate enable flags for usermode and supervisor mode)\n\t\tfor (sint32 i = 0; i < 8; i++)\n\t\t{\n\t\t\t// upper\n\t\t\tuint32 batU = hCPU->sprExtended.ibatU[i];\n\t\t\tuint32 BEPI = ((batU >> 17) & 0x7FFF) << 17;\n\t\t\tuint32 Vp = (batU >> 0) & 1;\n\t\t\tuint32 Vs = (batU >> 1) & 1;\n\t\t\tuint32 BL = (((batU >> 2) & 0x7FF) ^ 0x7FF) << 17;\n\t\t\tBL |= 0xF0000000;\n\t\t\tif (Vs == 0)\n\t\t\t\tcontinue; // todo - check if in supervisor/usermode\n\t\t\t// lower\n\t\t\tuint32 batL = hCPU->sprExtended.ibatL[i];\n\t\t\tuint32 PP = (batL >> 0) & 3;\n\t\t\tuint32 WIMG = (batL >> 3) & 0xF;\n\t\t\tuint32 BRPN = ((batL >> 17) & 0x7FFF) << 17;\n\n\t\t\t// check for match\n\t\t\tif ((vAddr&BL) == BEPI)\n\t\t\t{\n\t\t\t\t// match\n\t\t\t\tvAddr = (vAddr&~BL) | (BRPN&BL);\n\t\t\t\tdebug_lastTranslatedHit = vAddr;\n\t\t\t\treturn vAddr;\n\t\t\t}\n\t\t}\n\t\tassert_dbg();\n\n\t\t// no match\n\t\t// todo - throw exception if translation is enabled?\n\t\treturn vAddr;\n\t}\n\n\tstatic uint32 memory_readCodeU32(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\treturn _swapEndianU32(*(uint32*)(memory_base + ppcMem_translateVirtualCodeToPhysicalAddr(hCPU, address)));\n\t}\n\n\tinline static uint8* ppcMem_getDataPtr(PPCInterpreter_t* hCPU, uint32 vAddr)\n\t{\n\t\treturn memory_base + ppcMem_translateVirtualDataToPhysicalAddr(hCPU, vAddr);\n\t}\n\n\tinline static void ppcMem_writeDataDouble(PPCInterpreter_t* hCPU, uint32 address, double vf)\n\t{\n\t\tuint64 v = *(uint64*)&vf;\n\t\tuint32 v1 = v & 0xFFFFFFFF;\n\t\tuint32 v2 = v >> 32;\n\t\tuint8* ptr = ppcMem_getDataPtr(hCPU, address);\n\t\t*(uint32*)(ptr + 4) = CPU_swapEndianU32(v1);\n\t\t*(uint32*)(ptr + 0) = CPU_swapEndianU32(v2);\n\t}\n\n\tinline static void ppcMem_writeDataU64(PPCInterpreter_t* hCPU, uint32 address, uint64 v)\n\t{\n\t\t*(uint64*)(ppcMem_getDataPtr(hCPU, address)) = CPU_swapEndianU64(v);\n\t}\n\n\tinline static void ppcMem_writeDataU32(PPCInterpreter_t* hCPU, uint32 address, uint32 v)\n\t{\n\t\tuint32 pAddr = ppcMem_translateVirtualDataToPhysicalAddr(hCPU, address); \n\t\tif (hCPU->memoryException)\n\t\t\treturn;\n\n\t\tif (pAddr >= 0x0c000000 && pAddr < 0x0d100000)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t\treturn;\n\t\t}\n\t\t*(uint32*)(memory_base + pAddr) = CPU_swapEndianU32(v);\n\t}\n\n\tinline static void ppcMem_writeDataU16(PPCInterpreter_t* hCPU, uint32 address, uint16 v)\n\t{\n\t\t*(uint16*)(ppcMem_getDataPtr(hCPU, address)) = CPU_swapEndianU16(v);\n\t}\n\n\tinline static void ppcMem_writeDataU8(PPCInterpreter_t* hCPU, uint32 address, uint8 v)\n\t{\n\t\t*(uint8*)(ppcMem_getDataPtr(hCPU, address)) = v;\n\t}\n\n\tinline static double ppcMem_readDataDouble(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint32 v[2];\n\t\tv[1] = *(uint32*)(ppcMem_getDataPtr(hCPU, address));\n\t\tv[0] = *(uint32*)(ppcMem_getDataPtr(hCPU, address) + 4);\n\t\tv[0] = CPU_swapEndianU32(v[0]);\n\t\tv[1] = CPU_swapEndianU32(v[1]);\n\t\treturn *(double*)v;\n\t}\n\n\tinline static float ppcMem_readDataFloat(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint32 v = *(uint32*)(ppcMem_getDataPtr(hCPU, address));\n\t\tv = CPU_swapEndianU32(v);\n\t\treturn *(float*)&v;\n\t}\n\n\tinline static uint64 ppcMem_readDataU64(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint64 v = *(uint64*)(ppcMem_getDataPtr(hCPU, address));\n\t\treturn CPU_swapEndianU64(v);\n\t}\n\n\tinline static uint32 ppcMem_readDataU32(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint32 pAddr = ppcMem_translateVirtualDataToPhysicalAddr(hCPU, address);\n\t\tif (hCPU->memoryException)\n\t\t\treturn 0;\n\t\tif (pAddr >= 0x01FFF000 && pAddr < 0x02000000)\n\t\t{\n\t\t\tdebug_printf(\"Access u32 boot param block 0x%08x IP %08x LR %08x\\n\", pAddr, hCPU->instructionPointer, hCPU->spr.LR);\n\t\t\tcemuLog_logDebug(LogType::Force, \"Access u32 boot param block 0x{:08x} (org {:08x}) IP {:08x}\", pAddr, address, hCPU->instructionPointer);\n\t\t}\n\t\tif (pAddr >= 0xFFEB73B0 && pAddr < (0xFFEB73B0+0x40C))\n\t\t{\n\t\t\tdebug_printf(\"Access cached u32 boot param block 0x%08x IP %08x LR %08x\\n\", pAddr, hCPU->instructionPointer, hCPU->spr.LR);\n\t\t\tcemuLog_logDebug(LogType::Force, \"Access cached u32 boot param block 0x{:08x} (org {:08x}) IP {:08x}\", pAddr, address, hCPU->instructionPointer);\n\t\t}\n\n\t\tif (pAddr >= 0x0c000000 && pAddr < 0x0d100000)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t\treturn 0;\n\t\t}\n\t\tuint32 v = *(uint32*)(memory_base + pAddr);\n\t\treturn CPU_swapEndianU32(v);\n\t}\n\n\tinline static uint16 ppcMem_readDataU16(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint16 v = *(uint16*)(ppcMem_getDataPtr(hCPU, address));\n\t\treturn CPU_swapEndianU16(v);\n\t}\n\n\tinline static uint8 ppcMem_readDataU8(PPCInterpreter_t* hCPU, uint32 address)\n\t{\n\t\tuint32 pAddr = ppcMem_translateVirtualDataToPhysicalAddr(hCPU, address);\n\t\tif (pAddr >= 0x0c000000 && pAddr < 0x0d100000)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t\treturn 0;\n\t\t}\n\t\treturn *(uint8*)(memory_base + pAddr);\n\t}\n\n\tinline static uint64 ppcMem_readDataFloatEx(PPCInterpreter_t* hCPU, uint32 addr)\n\t{\n\t\treturn ConvertToDoubleNoFTZ(_swapEndianU32(*(uint32*)(memory_base + addr)));\n\t}\n\n\tinline static void ppcMem_writeDataFloatEx(PPCInterpreter_t* hCPU, uint32 addr, uint64 value)\n\t{\n\t\t*(uint32*)(memory_base + addr) = _swapEndianU32(ConvertToSingleNoFTZ(value));\n\t}\n\n\tinline static uint64 getTB(PPCInterpreter_t* hCPU)\n\t{\n\t\treturn hCPU->global->tb / 20ULL;\n\t}\n};\n\ntemplate <typename ppcItpCtrl>\nclass PPCInterpreterContainer\n{\npublic:\n#include \"PPCInterpreterSPR.hpp\"\n#include \"PPCInterpreterOPC.hpp\"\n#include \"PPCInterpreterLoadStore.hpp\"\n#include \"PPCInterpreterALU.hpp\"\n\n\tstatic void executeInstruction(PPCInterpreter_t* hCPU)\n\t{\n\t\tif constexpr(ppcItpCtrl::allowSupervisorMode)\n\t\t{\n\t\t\thCPU->global->tb++;\n\t\t}\n\n#ifdef __DEBUG_OUTPUT_INSTRUCTION\n\t\tdebug_printf(\"%08x: \", hCPU->instructionPointer);\n#endif\n\n\t\tuint32 opcode = ppcItpCtrl::memory_readCodeU32(hCPU, hCPU->instructionPointer);\n\n\t\tswitch ((opcode >> 26))\n\t\t{\n\t\tcase 0:\n\t\t\tdebug_printf(\"ZERO[NOP] | 0x%08X\\n\", (unsigned int)hCPU->instructionPointer);\n\t#ifdef CEMU_DEBUG_ASSERT\t\t\n\t\t\tassert_dbg();\n\t\t\twhile (true) std::this_thread::sleep_for(std::chrono::seconds(1));\n\t#endif\n\t\t\thCPU->instructionPointer += 4;\n\t\t\tbreak;\n\t\tcase 1: // virtual HLE\n\t\t\tPPCInterpreter_virtualHLE(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported TWI instruction executed at {:08x}\", hCPU->instructionPointer);\n\t\t\tPPCInterpreter_nextInstruction(hCPU);\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tswitch (PPC_getBits(opcode, 30, 5))\n\t\t\t{\n\t\t\tcase 0: // subcategory compare\n\t\t\t\tswitch (PPC_getBits(opcode, 25, 5))\n\t\t\t\t{\n\t\t\t\tcase 0: // Sonic All Stars Racing\n\t\t\t\t\tPPCInterpreter_PS_CMPU0(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tPPCInterpreter_PS_CMPO0(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2: // Assassin's Creed 3, Sonic All Stars Racing\n\t\t\t\t\tPPCInterpreter_PS_CMPU1(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unknown execute {:04x} as [4->0] at {:08x}\", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer);\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t\thCPU->instructionPointer += 4;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 6:\n\t\t\t\tPPCInterpreter_PSQ_LX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 7:\n\t\t\t\tPPCInterpreter_PSQ_STX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 8:\n\t\t\t\tswitch (PPC_getBits(opcode, 25, 5))\n\t\t\t\t{\n\t\t\t\tcase 1:\n\t\t\t\t\tPPCInterpreter_PS_NEG(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tPPCInterpreter_PS_MR(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tPPCInterpreter_PS_NABS(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tPPCInterpreter_PS_ABS(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unknown execute {:04x} as [4->8] at {:08x}\", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer);\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t\thCPU->instructionPointer += 4;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 10:\n\t\t\t\tPPCInterpreter_PS_SUM0(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 11:\n\t\t\t\tPPCInterpreter_PS_SUM1(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 12:\n\t\t\t\tPPCInterpreter_PS_MULS0(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 13:\n\t\t\t\tPPCInterpreter_PS_MULS1(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 14:\n\t\t\t\tPPCInterpreter_PS_MADDS0(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 15:\n\t\t\t\tPPCInterpreter_PS_MADDS1(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 16: // sub category - merge\n\t\t\t\tswitch (PPC_getBits(opcode, 25, 5))\n\t\t\t\t{\n\t\t\t\tcase 16:\n\t\t\t\t\tPPCInterpreter_PS_MERGE00(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 17:\n\t\t\t\t\tPPCInterpreter_PS_MERGE01(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 18:\n\t\t\t\t\tPPCInterpreter_PS_MERGE10(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 19:\n\t\t\t\t\tPPCInterpreter_PS_MERGE11(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unknown execute {:04x} as [4->16] at {:08x}\", PPC_getBits(opcode, 25, 5), hCPU->instructionPointer);\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t\thCPU->instructionPointer += 4;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 18:\n\t\t\t\tPPCInterpreter_PS_DIV(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 20:\n\t\t\t\tPPCInterpreter_PS_SUB(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 21:\n\t\t\t\tPPCInterpreter_PS_ADD(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 22:\n\t\t\t\tPPCInterpreter_DCBZL(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 23:\n\t\t\t\tPPCInterpreter_PS_SEL(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 24:\n\t\t\t\tPPCInterpreter_PS_RES(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 25:\n\t\t\t\tPPCInterpreter_PS_MUL(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 26: // sub category with only one entry - RSQRTE\n\t\t\t\tPPCInterpreter_PS_RSQRTE(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 28:\n\t\t\t\tPPCInterpreter_PS_MSUB(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 29:\n\t\t\t\tPPCInterpreter_PS_MADD(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 30:\n\t\t\t\tPPCInterpreter_PS_NMSUB(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 31:\n\t\t\t\tPPCInterpreter_PS_NMADD(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unknown execute {:04x} as [4] at {:08x}\", PPC_getBits(opcode, 30, 5), hCPU->instructionPointer);\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\thCPU->instructionPointer += 4;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 7:\n\t\t\tPPCInterpreter_MULLI(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 8:\n\t\t\tPPCInterpreter_SUBFIC(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 10:\n\t\t\tPPCInterpreter_CMPLI(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 11:\n\t\t\tPPCInterpreter_CMPI(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 12:\n\t\t\tPPCInterpreter_ADDIC(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 13:\n\t\t\tPPCInterpreter_ADDIC_(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 14:\n\t\t\tPPCInterpreter_ADDI(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 15:\n\t\t\tPPCInterpreter_ADDIS(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 16:\n\t\t\tPPCInterpreter_BCX(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 17:\n\t\t\tif (PPC_getBits(opcode, 30, 1) == 1)\n\t\t\t{\n\t\t\t\tPPCInterpreter_SC(hCPU, opcode);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported Opcode [0x17 --> 0x0]\");\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\thCPU->instructionPointer += 4;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 18:\n\t\t\tPPCInterpreter_BX(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 19: // opcode category\n\t\t\tswitch (PPC_getBits(opcode, 30, 10))\n\t\t\t{\n\t\t\tcase 0:\n\t\t\t\tPPCInterpreter_MCRF(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 16:\n\t\t\t\tPPCInterpreter_BCLRX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 33:\n\t\t\t\tPPCInterpreter_CRNOR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 50:\n\t\t\t\tPPCInterpreter_RFI(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 129:\n\t\t\t\tPPCInterpreter_CRANDC(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 150:\n\t\t\t\tPPCInterpreter_ISYNC(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 193:\n\t\t\t\tPPCInterpreter_CRXOR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 225:\n\t\t\t\tPPCInterpreter_CRNAND(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 257:\n\t\t\t\tPPCInterpreter_CRAND(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 289:\n\t\t\t\tPPCInterpreter_CREQV(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 417:\n\t\t\t\tPPCInterpreter_CRORC(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 449:\n\t\t\t\tPPCInterpreter_CROR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 528:\n\t\t\t\tPPCInterpreter_BCCTR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unknown execute {:04x} as [19] at {:08x}\\n\", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer);\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\thCPU->instructionPointer += 4;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 20:\n\t\t\tPPCInterpreter_RLWIMI(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 21:\n\t\t\tPPCInterpreter_RLWINM(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 23:\n\t\t\tPPCInterpreter_RLWNM(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 24:\n\t\t\tPPCInterpreter_ORI(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 25:\n\t\t\tPPCInterpreter_ORIS(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 26:\n\t\t\tPPCInterpreter_XORI(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 27:\n\t\t\tPPCInterpreter_XORIS(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 28:\n\t\t\tPPCInterpreter_ANDI_(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 29:\n\t\t\tPPCInterpreter_ANDIS_(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 31: // opcode category\n\t\t\tswitch (PPC_getBits(opcode, 30, 10))\n\t\t\t{\n\t\t\tcase 0:\n\t\t\t\tPPCInterpreter_CMP(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\tPPCInterpreter_TW(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 8:\n\t\t\t\tPPCInterpreter_SUBFC(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 10:\n\t\t\t\tPPCInterpreter_ADDC(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 11:\n\t\t\t\tPPCInterpreter_MULHWU_(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 19:\n\t\t\t\tPPCInterpreter_MFCR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 20:\n\t\t\t\tPPCInterpreter_LWARX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 23:\n\t\t\t\tPPCInterpreter_LWZX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 24:\n\t\t\t\tPPCInterpreter_SLWX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 26:\n\t\t\t\tPPCInterpreter_CNTLZW(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 28:\n\t\t\t\tPPCInterpreter_ANDX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 32:\n\t\t\t\tPPCInterpreter_CMPL(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 40:\n\t\t\t\tPPCInterpreter_SUBF(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 54:\n\t\t\t\tPPCInterpreter_DCBST(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 55:\n\t\t\t\tPPCInterpreter_LWZXU(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 60:\n\t\t\t\tPPCInterpreter_ANDCX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 75:\n\t\t\t\tPPCInterpreter_MULHW_(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 83:\n\t\t\t\tPPCInterpreter_MFMSR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 86:\n\t\t\t\tPPCInterpreter_DCBF(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 87:\n\t\t\t\tPPCInterpreter_LBZX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 104:\n\t\t\t\tPPCInterpreter_NEG(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 119: // Sonic Lost World\n\t\t\t\tPPCInterpreter_LBZXU(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 124:\n\t\t\t\tPPCInterpreter_NORX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 136:\n\t\t\t\tPPCInterpreter_SUBFE(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 138:\n\t\t\t\tPPCInterpreter_ADDE(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 144:\n\t\t\t\tPPCInterpreter_MTCRF(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 146:\n\t\t\t\tPPCInterpreter_MTMSR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 150:\n\t\t\t\tPPCInterpreter_STWCX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 151:\n\t\t\t\tPPCInterpreter_STWX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 183:\n\t\t\t\tPPCInterpreter_STWUX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 200:\n\t\t\t\tPPCInterpreter_SUBFZE(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 202:\n\t\t\t\tPPCInterpreter_ADDZE(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 210:\n\t\t\t\tPPCInterpreter_MTSR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 215:\n\t\t\t\tPPCInterpreter_STBX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 232: // Trine 2\n\t\t\t\tPPCInterpreter_SUBFME(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 234:\n\t\t\t\tPPCInterpreter_ADDME(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 235:\n\t\t\t\tPPCInterpreter_MULLW(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 247:\n\t\t\t\tPPCInterpreter_STBUX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 266:\n\t\t\t\tPPCInterpreter_ADD(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 278:\n\t\t\t\tPPCInterpreter_DCBT(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 279:\n\t\t\t\tPPCInterpreter_LHZX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 284:\n\t\t\t\tPPCInterpreter_EQV(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 306:\n\t\t\t\tPPCInterpreter_TLBIE(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 311: // Wii U Menu v177 (US)\n\t\t\t\tPPCInterpreter_LHZUX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 316:\n\t\t\t\tPPCInterpreter_XOR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 339:\n\t\t\t\tPPCInterpreter_MFSPR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 343:\n\t\t\t\tPPCInterpreter_LHAX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 371:\n\t\t\t\tPPCInterpreter_MFTB(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 375: // Wii U Menu v177 (US)\n\t\t\t\tPPCInterpreter_LHAUX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 407:\n\t\t\t\tPPCInterpreter_STHX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 412:\n\t\t\t\tPPCInterpreter_ORC(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 439:\n\t\t\t\tPPCInterpreter_STHUX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 444:\n\t\t\t\tPPCInterpreter_OR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 459:\n\t\t\t\tPPCInterpreter_DIVWU(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 467:\n\t\t\t\tPPCInterpreter_MTSPR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 470:\n\t\t\t\tPPCInterpreter_DCBI(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 476:\n\t\t\t\tPPCInterpreter_NANDX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 491:\n\t\t\t\tPPCInterpreter_DIVW(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 512:\n\t\t\t\tPPCInterpreter_MCRXR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 520: // Affordable Space Adventures + other Unity games\n\t\t\t\tPPCInterpreter_SUBFCO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 522:\n\t\t\t\tPPCInterpreter_ADDCO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 523: // 11 | OE\n\t\t\t\tPPCInterpreter_MULHWU_(hCPU, opcode); // OE is ignored\n\t\t\t\tbreak;\n\t\t\tcase 533:\n\t\t\t\tPPCInterpreter_LSWX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 534:\n\t\t\t\tPPCInterpreter_LWBRX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 535:\n\t\t\t\tPPCInterpreter_LFSX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 536:\n\t\t\t\tPPCInterpreter_SRWX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 552:\n\t\t\t\tPPCInterpreter_SUBFO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 566:\n\t\t\t\tPPCInterpreter_TLBSYNC(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 567:\n\t\t\t\tPPCInterpreter_LFSUX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 587: // 75 | OE\n\t\t\t\tPPCInterpreter_MULHW_(hCPU, opcode); // OE is ignored for MULHW\n\t\t\t\tbreak;\n\t\t\tcase 595:\n\t\t\t\tPPCInterpreter_MFSR(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 597:\n\t\t\t\tPPCInterpreter_LSWI(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 598:\n\t\t\t\tPPCInterpreter_SYNC(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 599:\n\t\t\t\tPPCInterpreter_LFDX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 616:\n\t\t\t\tPPCInterpreter_NEGO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 631:\n\t\t\t\tPPCInterpreter_LFDUX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 648: // 136 | OE\n\t\t\t\tPPCInterpreter_SUBFEO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 650: // 138 | OE\n\t\t\t\tPPCInterpreter_ADDEO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 662:\n\t\t\t\tPPCInterpreter_STWBRX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 663:\n\t\t\t\tPPCInterpreter_STFSX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 661:\n\t\t\t\tPPCInterpreter_STSWX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 695:\n\t\t\t\tPPCInterpreter_STFSUX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 712: // 200 | OE\n\t\t\t\tPPCInterpreter_SUBFZEO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 714: // 202 | OE\n\t\t\t\tPPCInterpreter_ADDZEO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 725:\n\t\t\t\tPPCInterpreter_STSWI(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 727:\n\t\t\t\tPPCInterpreter_STFDX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 744: // 232 | OE\n\t\t\t\tPPCInterpreter_SUBFMEO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 746: // 234 | OE\n\t\t\t\tPPCInterpreter_ADDMEO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 747:\n\t\t\t\tPPCInterpreter_MULLWO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 759:\n\t\t\t\tPPCInterpreter_STFDUX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 778:\n\t\t\t\tPPCInterpreter_ADDO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 790:\n\t\t\t\tPPCInterpreter_LHBRX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 792:\n\t\t\t\tPPCInterpreter_SRAW(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 824:\n\t\t\t\tPPCInterpreter_SRAWI(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 854:\n\t\t\t\tPPCInterpreter_EIEIO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 918:\n\t\t\t\tPPCInterpreter_STHBRX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 922:\n\t\t\t\tPPCInterpreter_EXTSH(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 954:\n\t\t\t\tPPCInterpreter_EXTSB(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 971:\n\t\t\t\tPPCInterpreter_DIVWUO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 982:\n\t\t\t\tPPCInterpreter_ICBI(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 983:\n\t\t\t\tPPCInterpreter_STFIWX(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 1003:\n\t\t\t\tPPCInterpreter_DIVWO(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 1014:\n\t\t\t\tPPCInterpreter_DCBZ(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unknown execute {:04x} as [31] at {:08x}\\n\", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer);\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\thCPU->instructionPointer += 4;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 32:\n\t\t\tPPCInterpreter_LWZ(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 33:\n\t\t\tPPCInterpreter_LWZU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 34:\n\t\t\tPPCInterpreter_LBZ(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 35:\n\t\t\tPPCInterpreter_LBZU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 36:\n\t\t\tPPCInterpreter_STW(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 37:\n\t\t\tPPCInterpreter_STWU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 38:\n\t\t\tPPCInterpreter_STB(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 39:\n\t\t\tPPCInterpreter_STBU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 40:\n\t\t\tPPCInterpreter_LHZ(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 41:\n\t\t\tPPCInterpreter_LHZU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 42:\n\t\t\tPPCInterpreter_LHA(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 43:\n\t\t\tPPCInterpreter_LHAU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 44:\n\t\t\tPPCInterpreter_STH(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 45:\n\t\t\tPPCInterpreter_STHU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 46:\n\t\t\tPPCInterpreter_LMW(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 47:\n\t\t\tPPCInterpreter_STMW(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 48:\n\t\t\tPPCInterpreter_LFS(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 49:\n\t\t\tPPCInterpreter_LFSU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 50:\n\t\t\tPPCInterpreter_LFD(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 51:\n\t\t\tPPCInterpreter_LFDU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 52:\n\t\t\tPPCInterpreter_STFS(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 53:\n\t\t\tPPCInterpreter_STFSU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 54:\n\t\t\tPPCInterpreter_STFD(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 55:\n\t\t\tPPCInterpreter_STFDU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 56:\n\t\t\tPPCInterpreter_PSQ_L(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 57:\n\t\t\tPPCInterpreter_PSQ_LU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 59: // opcode category\n\t\t\tswitch (PPC_getBits(opcode, 30, 5))\n\t\t\t{\n\t\t\tcase 18:\n\t\t\t\tPPCInterpreter_FDIVS(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 20:\n\t\t\t\tPPCInterpreter_FSUBS(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 21:\n\t\t\t\tPPCInterpreter_FADDS(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 24:\n\t\t\t\tPPCInterpreter_FRES(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 25:\n\t\t\t\tPPCInterpreter_FMULS(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 28:\n\t\t\t\tPPCInterpreter_FMSUBS(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 29:\n\t\t\t\tPPCInterpreter_FMADDS(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 30:\n\t\t\t\tPPCInterpreter_FNMSUBS(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 31:\n\t\t\t\tPPCInterpreter_FNMADDS(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unknown execute {:04x} as [59] at {:08x}\\n\", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer);\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\thCPU->instructionPointer += 4;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 60:\n\t\t\tPPCInterpreter_PSQ_ST(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 61:\n\t\t\tPPCInterpreter_PSQ_STU(hCPU, opcode);\n\t\t\tbreak;\n\t\tcase 63: // opcode category\n\t\t\tswitch (PPC_getBits(opcode, 30, 5))\n\t\t\t{\n\t\t\tcase 0:\n\t\t\t\tPPCInterpreter_FCMPU(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 12:\n\t\t\t\tPPCInterpreter_FRSP(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 15:\n\t\t\t\tPPCInterpreter_FCTIWZ(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 18:\n\t\t\t\tPPCInterpreter_FDIV(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 20:\n\t\t\t\tPPCInterpreter_FSUB(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 21:\n\t\t\t\tPPCInterpreter_FADD(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 23:\n\t\t\t\tPPCInterpreter_FSEL(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 25:\n\t\t\t\tPPCInterpreter_FMUL(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 26:\n\t\t\t\tPPCInterpreter_FRSQRTE(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 28:\n\t\t\t\tPPCInterpreter_FMSUB(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 29:\n\t\t\t\tPPCInterpreter_FMADD(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 30:\n\t\t\t\tPPCInterpreter_FNMSUB(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tcase 31:\n\t\t\t\tPPCInterpreter_FNMADD(hCPU, opcode);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tswitch (PPC_getBits(opcode, 30, 10))\n\t\t\t\t{\n\t\t\t\tcase 14:\n\t\t\t\t\tPPCInterpreter_FCTIW(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 32:\n\t\t\t\t\tPPCInterpreter_FCMPO(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 38:\n\t\t\t\t\tPPCInterpreter_MTFSB1X(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 40:\n\t\t\t\t\tPPCInterpreter_FNEG(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 72:\n\t\t\t\t\tPPCInterpreter_FMR(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 136: // Darksiders 2\n\t\t\t\t\tPPCInterpreter_FNABS(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 264:\n\t\t\t\t\tPPCInterpreter_FABS(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 583:\n\t\t\t\t\tPPCInterpreter_MFFS(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 711:\n\t\t\t\t\tPPCInterpreter_MTFSF(hCPU, opcode);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unknown execute {:04x} as [63] at {:08x}\\n\", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer);\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t\tPPCInterpreter_nextInstruction(hCPU);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unknown execute {:04x} at {:08x}\\n\", PPC_getBits(opcode, 5, 6), (unsigned int)hCPU->instructionPointer);\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n};\n\n// Slim interpreter, trades some features for extra performance\n// Used when emulator runs in CafeOS HLE mode\n// Assumes the following:\n// - No MMU (linear memory with 1:1 mapping of physical to virtual)\n// - No interrupts\n// - Always runs in user mode\n// - Paired single mode is always enabled\nvoid PPCInterpreterSlim_executeInstruction(PPCInterpreter_t* hCPU)\n{\n\tPPCInterpreterContainer<PPCItpCafeOSUsermode>::executeInstruction(hCPU);\n}\n\n// Full interpreter, supports most PowerPC features\n// Used when emulator runs in LLE mode\nvoid PPCInterpreterFull_executeInstruction(PPCInterpreter_t* hCPU)\n{\n\tPPCInterpreterContainer<PPCItpSupervisorWithMMU>::executeInstruction(hCPU);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Espresso/PPCState.h\"\n\n// SPR constants\n#define SPR_XER\t\t1\t\n#define SPR_LR\t\t8\t\n#define SPR_CTR\t\t9\t\n#define SPR_DEC\t\t22\t\n#define SPR_SRR0\t26\t\n#define SPR_SRR1\t27\t\n#define SPR_HID0\t1008\n#define SPR_HID1\t1009\n#define SPR_HID2\t920\t\n#define SPR_TBL\t\t268\t\n#define SPR_TBU\t\t269\t\n#define SPR_DMAU\t922\t\n#define SPR_DMAL\t923\t\n\n// graphics quantization registers\n#define SPR_GQR0 912\n#define SPR_GQR1 913\n#define SPR_GQR2 914\n#define SPR_GQR3 915\n#define SPR_GQR4 916\n#define SPR_GQR5 917\n#define SPR_GQR6 918\n#define SPR_GQR7 919\n\n// user graphics quantization registers\n#define SPR_UGQR0\t896\n#define SPR_UGQR1\t897\n#define SPR_UGQR2\t898\n#define SPR_UGQR3\t899\n#define SPR_UGQR4\t900\n#define SPR_UGQR5\t901\n#define SPR_UGQR6\t902\n#define SPR_UGQR7\t903\n\n#define SPR_FPECR\t1022\t// used by the OS to store values\n\n#define SPR_PVR\t\t287\t\t// processor version, for Wii U this must be 0x7001xxxx - this register is only readable\n#define SPR_UPIR\t1007\t// core index\n#define SPR_SCR\t\t947\t\t// core control\n#define SPR_SDR1\t25\n\n// reversed CR bit indices\n#define CR_BIT_LT\t0\n#define CR_BIT_GT\t1\n#define CR_BIT_EQ\t2\n#define CR_BIT_SO\t3\n\n#define XER_BIT_CA\t\t(29)\t// carry bit index. To accelerate frequent access, this bit is stored as a separate uint8\n#define XER_BIT_SO\t\t(31)\t// summary overflow, counterpart to CR SO\n#define XER_BIT_OV\t\t(30)\n\n// FPSCR\n#define FPSCR_VXSNAN\t(1<<24)\n#define FPSCR_VXVC\t\t(1<<19)\n\n#define MSR_SF\t\t\t(1<<31)\n#define MSR_UNKNOWN\t\t(1<<30)\n#define MSR_UNKNOWN2\t(1<<27)\n#define MSR_VEC\t\t\t(1<<25)\n#define MSR_POW\t\t\t(1<<18)\n#define MSR_TGPR\t\t(1<<15)\n#define MSR_ILE\t\t\t(1<<16)\n#define MSR_EE\t\t\t(1<<15)\n#define MSR_PR\t\t\t(1<<14)\n#define MSR_FP\t\t\t(1<<13)\n#define MSR_ME\t\t\t(1<<12)\n#define MSR_FE0\t\t\t(1<<11)\n#define MSR_SE\t\t\t(1<<10)\n#define MSR_BE\t\t\t(1<<9)\n#define MSR_FE1\t\t\t(1<<8)\n#define MSR_IP\t\t\t(1<<6)\n#define MSR_IR\t\t\t(1<<5)\n#define MSR_DR\t\t\t(1<<4)\n#define MSR_PM\t\t\t(1<<2)\n#define MSR_RI\t\t\t(1<<1)\n#define MSR_LE\t\t\t(1)\n\n// helpers\n\n#define GET_MSR_BIT(__bit) ((hCPU->sprExtended.msr&(__bit))!=0)\n\n#define opHasRC() ((opcode & PPC_OPC_RC) != 0)\n\n// assume fixed values for PSE/LSQE. This optimization is possible because Wii U applications run only in user mode (todo - handle this correctly in LLE mode)\n//#define PPC_LSQE\t(hCPU->LSQE)\n//#define PPC_PSE\t(hCPU->PSE)\n\n#define PPC_LSQE\t\t(1)\n#define PPC_PSE\t\t\t(1)\n\n#define PPC_ASSERT(v)\n\n#define PPC_OPC_RC\t\t1\n#define PPC_OPC_OE\t\t(1<<10)\n#define PPC_OPC_LK\t\t1\n#define PPC_OPC_AA\t\t(1<<1)\n\n#define PPC_OPC_TEMPL_A(opc, rD, rA, rB, rC) {rD=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;rB=((opc)>>11)&0x1f;rC=((opc)>>6)&0x1f;}\n#define PPC_OPC_TEMPL_B(opc, BO, BI, BD) {BO=((opc)>>21)&0x1f;BI=((opc)>>16)&0x1f;BD=(uint32)(sint32)(sint16)((opc)&0xfffc);}\n#define PPC_OPC_TEMPL_D_SImm(opc, rD, rA, imm) {rD=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;imm=(uint32)(sint32)(sint16)((opc)&0xffff);}\n#define PPC_OPC_TEMPL_D_UImm(opc, rD, rA, imm) {rD=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;imm=(opc)&0xffff;}\n#define PPC_OPC_TEMPL_D_Shift16(opc, rD, rA, imm) {rD=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;imm=(opc)<<16;}\n#define PPC_OPC_TEMPL_I(opc, LI) {LI=(opc)&0x3fffffc;if (LI&0x02000000) LI |= 0xfc000000;}\n#define PPC_OPC_TEMPL_M(opc, rS, rA, SH, MB, ME) {rS=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;SH=((opc)>>11)&0x1f;MB=((opc)>>6)&0x1f;ME=((opc)>>1)&0x1f;}\n#define PPC_OPC_TEMPL_X(opc, rS, rA, rB) {rS=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;rB=((opc)>>11)&0x1f;}\n#define PPC_OPC_TEMPL_XFX(opc, rS, CRM) {rS=((opc)>>21)&0x1f;CRM=((opc)>>12)&0xff;}\n#define PPC_OPC_TEMPL_XO(opc, rS, rA, rB) {rS=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;rB=((opc)>>11)&0x1f;}\n#define PPC_OPC_TEMPL_XL(opc, BO, BI, BD) {BO=((opc)>>21)&0x1f;BI=((opc)>>16)&0x1f;BD=((opc)>>11)&0x1f;}\n#define PPC_OPC_TEMPL_XFL(opc, rB, FM) {rB=((opc)>>11)&0x1f;FM=((opc)>>17)&0xff;}\n\n#define PPC_OPC_TEMPL3_XO() sint32 rD, rA, rB; rD=((opcode)>>21)&0x1f;rA=((opcode)>>16)&0x1f;rB=((opcode)>>11)&0x1f\n#define PPC_OPC_TEMPL_X_CR() sint32 crD, crA, crB; crD=((opcode)>>21)&0x1f;crA=((opcode)>>16)&0x1f;crB=((opcode)>>11)&0x1f\n\nstatic inline void ppc_update_cr0(PPCInterpreter_t* hCPU, uint32 r)\n{\n\tcemu_assert_debug(hCPU->xer_so <= 1);\n\thCPU->cr[CR_BIT_SO] = hCPU->xer_so;\n\thCPU->cr[CR_BIT_LT] = ((r != 0) ? 1 : 0) & ((r & 0x80000000) ? 1 : 0);\n\thCPU->cr[CR_BIT_EQ] = (r == 0);\n\thCPU->cr[CR_BIT_GT] = hCPU->cr[CR_BIT_EQ] ^ hCPU->cr[CR_BIT_LT] ^ 1;  // this works because EQ and LT can never be set at the same time. So the only case where GT becomes 1 is when LT=0 and EQ=0\n}\n\nstatic inline uint8 ppc_getCRBit(PPCInterpreter_t* hCPU, uint32 r)\n{\n\treturn hCPU->cr[r];\n}\n\nstatic inline bool ppc_MTCRFMaskHasCRFieldSet(const uint32 mtcrfMask, const uint32 crIndex)\n{\n\t// 1000 0000 (0x80) -> cr0\n\t// 0000 0001 (0x01) -> cr7\n\treturn (mtcrfMask & (1 << (7 - crIndex))) != 0;\n}\n\n// returns CR mask with CR0.LT in LSB\nstatic inline uint32 ppc_MTCRFMaskToCRBitMask(const uint32 mtcrfMask)\n{\n\tuint32 crMask = 0; \n\tfor (uint32 crF = 0; crF < 8; crF++)\n\t{\n\t\tif (ppc_MTCRFMaskHasCRFieldSet(mtcrfMask, crF))\n\t\t\tcrMask |= (0xF << (crF * 4));\n\t}\n\treturn crMask;\n}\n\nstatic inline void ppc_setCRBit(PPCInterpreter_t* hCPU, uint32 r, uint8 v)\n{\n\thCPU->cr[r] = v;\n}\n\nstatic inline void ppc_setCR(PPCInterpreter_t* hCPU, uint32 cr)\n{\n\tuint32 tempCr = cr;\n\tfor (sint32 i = 31; i >= 0; i--)\n\t{\n\t\tppc_setCRBit(hCPU, i, tempCr & 1);\n\t\ttempCr >>= 1;\n\t}\n}\n\nstatic inline uint32 ppc_getCR(PPCInterpreter_t* hCPU)\n{\n\tuint32 cr = 0;\n\tfor (sint32 i = 0; i < 32; i++)\n\t{\n\t\tcr <<= 1;\n\t\tif (ppc_getCRBit(hCPU, i))\n\t\t\tcr |= 1;\n\t}\n\treturn cr;\n}\n\n// FPU helper\n\n#define IS_NAN(X)\t\t\t\t((((X) & 0x000fffffffffffffULL) != 0) && (((X) & 0x7ff0000000000000ULL) == 0x7ff0000000000000ULL))\n#define IS_QNAN(X)\t\t\t\t((((X) & 0x000fffffffffffffULL) != 0) && (((X) & 0x7ff8000000000000ULL) == 0x7ff8000000000000ULL))\n#define IS_SNAN(X)\t\t\t\t((((X) & 0x000fffffffffffffULL) != 0) && (((X) & 0x7ff8000000000000ULL) == 0x7ff0000000000000ULL))\n\n#define FPSCR_VE\t\t\t\t(1 <<  7)\n\ninline double roundTo25BitAccuracy(double d)\n{\n\tuint64 v = *(uint64*)&d;\n\tv = (v & 0xFFFFFFFFF8000000ULL) + (v & 0x8000000ULL);\n\treturn *(double*)&v;\n}\n\nATTR_MS_ABI double fres_espresso(double input);\nATTR_MS_ABI double frsqrte_espresso(double input);\n\nvoid fcmpu_espresso(PPCInterpreter_t* hCPU, int crfD, double a, double b);\n\n// OPC\nvoid PPCInterpreter_virtualHLE(PPCInterpreter_t* hCPU, unsigned int opcode);\n\nvoid PPCInterpreter_MFMSR(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_MTMSR(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_MFTB(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_MTFSB1X(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_MFCR(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_MCRF(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_MTCRF(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_MCRXR(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_TLBIE(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_TLBSYNC(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_DCBT(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_DCBST(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_DCBZL(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_DCBF(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_DCBI(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_DCBZ(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_ICBI(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_EIEIO(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_SC(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_SYNC(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_ISYNC(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_RFI(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_BX(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_BCX(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_BCLRX(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_BCCTR(PPCInterpreter_t* hCPU, uint32 Opcode);\n\n// FPU\n\nvoid PPCInterpreter_FCMPO(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FCMPU(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_FMR(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FSEL(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FCTIWZ(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FCTIW(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FNEG(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FRSP(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FRSQRTE(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FRES(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_FABS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FNABS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FADD(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FMUL(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FDIV(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FSUB(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FMADD(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FMSUB(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FMSUBS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FNMADD(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FNMSUB(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_MFFS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_MTFSF(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_FDIVS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FMULS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FADDS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FSUBS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FMADDS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FNMADDS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_FNMSUBS(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_PS_MERGE00(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_MERGE01(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_MERGE10(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_MERGE11(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_MR(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_NEG(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_ABS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_NABS(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_RES(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_RSQRTE(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_PS_ADD(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_SUB(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_MUL(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_DIV(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_PS_MADD(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_NMADD(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_MADDS0(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_MADDS1(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_MSUB(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_NMSUB(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_PS_SEL(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_SUM0(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_SUM1(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_MULS0(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_MULS1(PPCInterpreter_t* hCPU, uint32 Opcode);\n\nvoid PPCInterpreter_PS_CMPO0(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_CMPU0(PPCInterpreter_t* hCPU, uint32 Opcode);\nvoid PPCInterpreter_PS_CMPU1(PPCInterpreter_t* hCPU, uint32 Opcode);\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp",
    "content": "\n#define _signExtend16To32(__v) ((uint32)(sint32)(sint16)(__v))\n\n// store\n\n#define DSI_EXIT() \\\n\tif constexpr(ppcItpCtrl::allowDSI) \\\n\t{ \\\n\t\tif (hCPU->memoryException) \\\n\t\t{ \\\n\t\t\thCPU->memoryException = false; \\\n\t\t\treturn; \\\n\t\t} \\\n\t}\n\nstatic void PPCInterpreter_STW(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm);\n\tif (rA != 0)\n\t{\n\t\tppcItpCtrl::ppcMem_writeDataU32(hCPU, hCPU->gpr[rA] + imm, hCPU->gpr[rS]);\n\t}\n\telse\n\t{\n\t\tPPC_ASSERT(true);\n\t}\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STWU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm);\n\tppcItpCtrl::ppcMem_writeDataU32(hCPU, hCPU->gpr[rA] + imm, hCPU->gpr[rS]);\n\t// check for rA != 0 ? \n\thCPU->gpr[rA] += imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STWX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\tppcItpCtrl::ppcMem_writeDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->gpr[rS]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STWCX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\t// http://www.ibm.com/developerworks/library/pa-atom/\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\t// check if we hold a reservation for the memory location\n\n\t// todo - this isnt accurate. STWCX can succeed even with a different EA if the reserved value remained untouched\n\tif (hCPU->reservedMemAddr == ea)\n\t{\n\t\tuint32be reservedValue = hCPU->reservedMemValue; // this is the value we expect in memory (if it does not match, STWCX fails)\n\t\tstd::atomic<uint32be>* wordPtr;\t\t\n\t\tif constexpr(ppcItpCtrl::allowSupervisorMode)\n\t\t{\n\t\t\twordPtr = _rawPtrToAtomic((uint32be*)(memory_base + ppcItpCtrl::ppcMem_translateVirtualDataToPhysicalAddr(hCPU, ea)));\n\t\t\tDSI_EXIT();\n\t\t}\n\t\telse\n\t\t{\n\t\t\twordPtr = _rawPtrToAtomic((uint32be*)memory_getPointerFromVirtualOffset(ea));\n\t\t}\n\t\tuint32be newValue = hCPU->gpr[rS];\n\t\tif (!wordPtr->compare_exchange_strong(reservedValue, newValue))\n\t\t{\n\t\t\t// failed\n\t\t\tppc_setCRBit(hCPU, CR_BIT_LT, 0);\n\t\t\tppc_setCRBit(hCPU, CR_BIT_GT, 0);\n\t\t\tppc_setCRBit(hCPU, CR_BIT_EQ, 0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// success, new value has been written\n\t\t\tppc_setCRBit(hCPU, CR_BIT_LT, 0);\n\t\t\tppc_setCRBit(hCPU, CR_BIT_GT, 0);\n\t\t\tppc_setCRBit(hCPU, CR_BIT_EQ, 1);\n\t\t}\n\t\tcemu_assert_debug(hCPU->xer_so <= 1);\n\t\tppc_setCRBit(hCPU, CR_BIT_SO, hCPU->xer_so);\n\t\t// remove reservation\n\t\thCPU->reservedMemAddr = 0;\n\t\thCPU->reservedMemValue = 0;\n\t}\n\telse\n\t{\n\t\t// failed\n\t\tppc_setCRBit(hCPU, CR_BIT_LT, 0);\n\t\tppc_setCRBit(hCPU, CR_BIT_GT, 0);\n\t\tppc_setCRBit(hCPU, CR_BIT_EQ, 0);\n\t}\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STWUX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\tppcItpCtrl::ppcMem_writeDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->gpr[rS]);\n\tif (rA)\n\t\thCPU->gpr[rA] += hCPU->gpr[rB];\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STWBRX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\tppcItpCtrl::ppcMem_writeDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], _swapEndianU32(hCPU->gpr[rS]));\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STMW(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rS, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm);\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + imm;\n\twhile (rS <= 31)\n\t{\n\t\tppcItpCtrl::ppcMem_writeDataU32(hCPU, ea, hCPU->gpr[rS]);\n\t\trS++;\n\t\tea += 4;\n\t}\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STH(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm);\n\tppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, (uint16)hCPU->gpr[rS]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STHU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm);\n\tppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, (uint16)hCPU->gpr[rS]);\n\tif (rA)\n\t\thCPU->gpr[rA] += imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STHX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\tppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint16)hCPU->gpr[rS]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STHUX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\tppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint16)hCPU->gpr[rS]);\n\tif (rA)\n\t\thCPU->gpr[rA] += hCPU->gpr[rB];\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STHBRX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\tppcItpCtrl::ppcMem_writeDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], _swapEndianU16((uint16)hCPU->gpr[rS]));\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STB(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm);\n\tppcItpCtrl::ppcMem_writeDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, (uint8)hCPU->gpr[rS]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STBU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rS, rA, imm);\n\tppcItpCtrl::ppcMem_writeDataU8(hCPU, hCPU->gpr[rA] + imm, (uint8)hCPU->gpr[rS]);\n\thCPU->gpr[rA] += imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STBX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\tppcItpCtrl::ppcMem_writeDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint8)hCPU->gpr[rS]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STBUX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\tppcItpCtrl::ppcMem_writeDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], (uint8)hCPU->gpr[rS]);\n\tif (rA)\n\t\thCPU->gpr[rA] += hCPU->gpr[rB];\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STSWI(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, nb;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, nb);\n\tif (nb == 0) nb = 32;\n\tuint32 ea = rA ? hCPU->gpr[rA] : 0;\n\tuint32 r = 0;\n\tint i = 0;\n\twhile (nb > 0)\n\t{\n\t\tif (i == 0)\n\t\t{\n\t\t\tr = rS < 32 ? hCPU->gpr[rS] : 0; // what happens if rS is out of bounds?\n\t\t\trS++;\n\t\t\trS %= 32;\n\t\t\ti = 4;\n\t\t}\n\t\tppcItpCtrl::ppcMem_writeDataU8(hCPU, ea, (r >> 24));\n\t\tr <<= 8;\n\t\tea++;\n\t\ti--;\n\t\tnb--;\n\t}\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STSWX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\tsint32 nb = hCPU->spr.XER&0x7F;\n\tif (nb == 0)\n\t{\n\t\tPPCInterpreter_nextInstruction(hCPU);\n\t\treturn;\n\t}\n\tuint32 ea = rA ? hCPU->gpr[rA] : 0;\n\tea += hCPU->gpr[rB];\n\tuint32 r = 0;\n\tint i = 0;\n\twhile (nb > 0)\n\t{\n\t\tif (i == 0)\n\t\t{\n\t\t\tr = rS < 32 ? hCPU->gpr[rS] : 0; // what happens if rS is out of bounds?\n\t\t\trS++;\n\t\t\trS %= 32;\n\t\t\ti = 4;\n\t\t}\n\t\tppcItpCtrl::ppcMem_writeDataU8(hCPU, ea, (r >> 24));\n\t\tr <<= 8;\n\t\tea++;\n\t\ti--;\n\t\tnb--;\n\t}\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n// load\n\nstatic void PPCInterpreter_LWZ(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rD, rA, imm);\n\tuint32 v = ppcItpCtrl::ppcMem_readDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm);\n\tDSI_EXIT();\n\thCPU->gpr[rD] = v;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LWZU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rD, rA, imm);\n\thCPU->gpr[rA] += imm;\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU32(hCPU, hCPU->gpr[rA]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LMW(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rD, rA, imm);\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + imm;\n\twhile (rD <= 31)\n\t{\n\t\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU32(hCPU, ea);\n\t\trD++;\n\t\tea += 4;\n\t}\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LWZX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LWZXU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU32(hCPU, ea);\n\tif (rA && rA != rD)\n\t\thCPU->gpr[rA] = ea;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LWBRX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\thCPU->gpr[rD] = CPU_swapEndianU32(ppcItpCtrl::ppcMem_readDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB]));\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LWARX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU32(hCPU, ea);\n\t// set reservation\t\n\thCPU->reservedMemAddr = ea;\n\thCPU->reservedMemValue = hCPU->gpr[rD];\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LHZ(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rD, rA, imm);\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LHZU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rD, rA, imm);\n\t// FIXME: rA!=0\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU16(hCPU, hCPU->gpr[rA] + imm);\n\thCPU->gpr[rA] += imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LHZX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LHZUX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU16(hCPU, ea);\n\tif (rA && rA != rD)\n\t\thCPU->gpr[rA] = ea;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LHBRX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\thCPU->gpr[rD] = CPU_swapEndianU16(ppcItpCtrl::ppcMem_readDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB]));\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LHA(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rD, rA, imm);\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm);\n\thCPU->gpr[rD] = _signExtend16To32(hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LHAU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rD, rA, imm);\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm);\n\tif (rA && rA != rD)\n\t\thCPU->gpr[rA] += imm;\n\thCPU->gpr[rD] = _signExtend16To32(hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LHAUX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU16(hCPU, ea);\n\tif (rA && rA != rD)\n\t\thCPU->gpr[rA] = ea;\n\thCPU->gpr[rD] = _signExtend16To32(hCPU->gpr[rD]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LHAX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\n\thCPU->gpr[rS] = ppcItpCtrl::ppcMem_readDataU16(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB]);\n\thCPU->gpr[rS] = _signExtend16To32(hCPU->gpr[rS]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LBZ(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rD, rA, imm);\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LBZX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU8(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LBZXU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\thCPU->gpr[rD] = ppcItpCtrl::ppcMem_readDataU8(hCPU, ea);\n\tif (rA && rA != rD)\n\t\thCPU->gpr[rA] = ea;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LBZU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, rD, rA, imm);\n\tPPC_ASSERT(rA == 0);\n\tuint8 r;\n\tuint32 ea = hCPU->gpr[rA] + imm;\n\thCPU->gpr[rA] = ea;\n\tr = ppcItpCtrl::ppcMem_readDataU8(hCPU, ea);\n\thCPU->gpr[rD] = r;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LSWI(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, nb;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, nb);\n\tif (nb == 0)\n\t\tnb = 32;\n\tuint32 ea = rA ? hCPU->gpr[rA] : 0;\n\tuint32 r = 0;\n\tint i = 4;\n\tuint8 v;\n\twhile (nb>0)\n\t{\n\t\tif (i == 0)\n\t\t{\n\t\t\ti = 4;\n\t\t\tif(rD < 32)\n\t\t\t\thCPU->gpr[rD] = r;\n\t\t\trD++;\n\t\t\trD %= 32;\n\t\t\tr = 0;\n\t\t}\n\t\tv = ppcItpCtrl::ppcMem_readDataU8(hCPU, ea);\n\t\tr <<= 8;\n\t\tr |= v;\n\t\tea++;\n\t\ti--;\n\t\tnb--;\n\t}\n\twhile (i)\n\t{\n\t\tr <<= 8;\n\t\ti--;\n\t}\n\tif(rD < 32)\n\t\thCPU->gpr[rD] = r;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LSWX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\t// byte count comes from XER\n\tuint32 nb = (hCPU->spr.XER>>0)&0x7F;\n\tif (nb == 0)\n\t{\n\t\tPPCInterpreter_nextInstruction(hCPU);\n\t\treturn; // no-op\n\t}\n\tuint32 ea = rA ? hCPU->gpr[rA] : 0;\n\tea += hCPU->gpr[rB];\n\tuint32 r = 0;\n\tint i = 4;\n\tuint8 v;\n\twhile (nb>0)\n\t{\n\t\tif (i == 0)\n\t\t{\n\t\t\ti = 4;\n\t\t\tif(rD < 32)\n\t\t\t\thCPU->gpr[rD] = r;\n\t\t\trD++;\n\t\t\trD %= 32;\n\t\t\tr = 0;\n\t\t}\n\t\tv = ppcItpCtrl::ppcMem_readDataU8(hCPU, ea);\n\t\tr <<= 8;\n\t\tr |= v;\n\t\tea++;\n\t\ti--;\n\t\tnb--;\n\t}\n\twhile (i)\n\t{\n\t\tr <<= 8;\n\t\ti--;\n\t}\n\tif(rD < 32)\n\t\thCPU->gpr[rD] = r;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n// floating point load\n\nstatic void PPCInterpreter_LFS(PPCInterpreter_t* hCPU, uint32 Opcode) //Copied\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, frD, rA, imm);\n\n\tuint64 val;\n\t//*(uint32*)&Val = ppcItpCtrl::ppcMem_readDataU32(hCPU, (rA?hCPU->gpr[rA]:0)+imm);\n\tval = ppcItpCtrl::ppcMem_readDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm);\n\n\tif (PPC_LSQE)\n\t\thCPU->fpr[frD].fp0int = hCPU->fpr[frD].fp1int = val;\n\telse\n\t\thCPU->fpr[frD].fp0int = val;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LFSX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, rA, rB);\n\n\tuint64 val;\n\tval = ppcItpCtrl::ppcMem_readDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB]);\n\n\tif (PPC_LSQE)\n\t\thCPU->fpr[frD].fp0int = hCPU->fpr[frD].fp1int = val;\n\telse\n\t\thCPU->fpr[frD].fp0int = val;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LFSUX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, rA, rB);\n\n\tuint64 Val;\n\t//*(uint32*)&Val = ppcItpCtrl::ppcMem_readDataU32(hCPU, (rA?hCPU->gpr[rA]:0)+hCPU->gpr[rB]);\n\tVal = ppcItpCtrl::ppcMem_readDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB]);\n\tif (rA)\n\t\thCPU->gpr[rA] += hCPU->gpr[rB];\n\n\tif (PPC_LSQE)\n\t\thCPU->fpr[frD].fp0int = hCPU->fpr[frD].fp1int = Val;\n\telse\n\t\thCPU->fpr[frD].fp0int = Val;//ppcItpCtrl::ppcMem_readDataFloat((rA?hCPU->gpr[rA]:0)+hCPU->gpr[rB]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LFSU(PPCInterpreter_t* hCPU, uint32 Opcode) //Copied\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, frD, rA, imm);\n\tuint64 Val;\n\n\t//(uint32*)&Val = ppcItpCtrl::ppcMem_readDataU32(hCPU, (rA?hCPU->gpr[rA]:0)+imm);\n\tVal = ppcItpCtrl::ppcMem_readDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm);\n\n\n\tif (PPC_LSQE)\n\t\thCPU->fpr[frD].fp0int = hCPU->fpr[frD].fp1int = Val;\n\telse\n\t\thCPU->fpr[frD].fp0int = Val;\n\n\tif (rA)\n\t\thCPU->gpr[rA] += imm;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LFD(PPCInterpreter_t* hCPU, uint32 Opcode) //Copied\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, frD, rA, imm);\n\thCPU->fpr[frD].fpr = ppcItpCtrl::ppcMem_readDataDouble(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm);//ppcItpCtrl::ppcMem_readDataQUAD((rA?hCPU->gpr[rA]:0)+imm);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LFDU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, frD, rA, imm);\n\n\thCPU->fpr[frD].fpr = ppcItpCtrl::ppcMem_readDataDouble(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm);//ppcItpCtrl::ppcMem_readDataQUAD((rA?hCPU->gpr[rA]:0)+imm);\n\tif (rA)\n\t\thCPU->gpr[rA] += imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LFDX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, rA, rB);\n\thCPU->fpr[frD].fpr = ppcItpCtrl::ppcMem_readDataDouble(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB]);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_LFDUX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD, rB;\n\tPPC_OPC_TEMPL_X(Opcode, frD, rA, rB);\n\thCPU->fpr[frD].fpr = ppcItpCtrl::ppcMem_readDataDouble(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB]);\n\tif (rA)\n\t\thCPU->gpr[rA] += hCPU->gpr[rB];\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STFS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, frD, rA, imm);\n\tif (PPC_LSQE)\n\t\tppcItpCtrl::ppcMem_writeDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, hCPU->fpr[frD].fp0int);\n\telse\n\t\tppcItpCtrl::ppcMem_writeDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, hCPU->fpr[frD].fp0int);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STFSU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, frD, rA, imm);\n\n\tif (PPC_LSQE)\n\t\tppcItpCtrl::ppcMem_writeDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, hCPU->fpr[frD].fp0int);\n\telse\n\t\tppcItpCtrl::ppcMem_writeDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, hCPU->fpr[frD].fp0int);\n\n\tif (rA)\n\t\thCPU->gpr[rA] += imm;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STFSX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, frS, rA, rB);\n\n\tif (PPC_LSQE)\n\t\tppcItpCtrl::ppcMem_writeDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->fpr[frS].fp0int);\n\telse\n\t\tppcItpCtrl::ppcMem_writeDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->fpr[frS].fp0int);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_STFSUX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n\n\tint rA, frS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, frS, rA, rB);\n\n\tif (PPC_LSQE)\n\t\tppcItpCtrl::ppcMem_writeDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->fpr[frS].fp0int);\n\telse\n\t\tppcItpCtrl::ppcMem_writeDataFloatEx(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->fpr[frS].fp0int);\n\n\tif (rA)\n\t\thCPU->gpr[rA] += hCPU->gpr[rB];\n}\n\n\nstatic void PPCInterpreter_STFD(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n\n\tint rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, frD, rA, imm);\n\n\tppcItpCtrl::ppcMem_writeDataDouble(hCPU, (rA ? hCPU->gpr[rA] : 0) + imm, hCPU->fpr[frD].fpr);\n\n\t// debug output\n#ifdef __DEBUG_OUTPUT_INSTRUCTION\n\tdebug_printf(\"STFD f%d, %d(r%d)\\n\", frD, imm, rA);\n#endif\n}\n\nstatic void PPCInterpreter_STFDU(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n\n\tint rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(Opcode, frD, rA, imm);\n\n\tif (rA)\n\t{\n\t\thCPU->gpr[rA] += imm;\n\t}\n\telse\n\t{\n\t\tPPC_ASSERT(true);\n\t}\n\n\tppcItpCtrl::ppcMem_writeDataDouble(hCPU, hCPU->gpr[rA], hCPU->fpr[frD].fpr);\n\n\t// debug output\n#ifdef __DEBUG_OUTPUT_INSTRUCTION\n\tdebug_printf(\"STFD f%d, %d(r%d)\\n\", frD, imm, rA);\n#endif\n}\n\nstatic void PPCInterpreter_STFDX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n\n\tint rA, frS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, frS, rA, rB);\n\n\tppcItpCtrl::ppcMem_writeDataDouble(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], hCPU->fpr[frS].fpr);\n\n\t// debug output\n#ifdef __DEBUG_OUTPUT_INSTRUCTION\n\tdebug_printf(\"STFD f%d, r%d+r%d\\n\", frS, rA, rB);\n#endif\n}\n\nstatic void PPCInterpreter_STFDUX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n\n\tint rA, frS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, frS, rA, rB);\n\n\tif (rA == 0)\n\t{\n\t\tppcItpCtrl::ppcMem_writeDataDouble(hCPU, hCPU->gpr[rB], hCPU->fpr[frS].fpr);\n\t}\n\telse\n\t{\n\t\thCPU->gpr[rA] += hCPU->gpr[rB];\n\t\tppcItpCtrl::ppcMem_writeDataDouble(hCPU, hCPU->gpr[rA], hCPU->fpr[frS].fpr);\n\t}\n\n}\n\nstatic void PPCInterpreter_STFIWX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frS, rB;\n\tPPC_OPC_TEMPL_X(Opcode, frS, rA, rB);\n\n\tuint32 val = (uint32)hCPU->fpr[frS].fp0int;\n\tppcItpCtrl::ppcMem_writeDataU32(hCPU, (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB], val);\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n// paired single\n\n// ST_TYPE:\n// 4 - uint8\n// 5 - uint16\n// 6 - sint8\n// 7 - sint16\n// 0 - float32\n\n#define LD_SCALE(n) ((hCPU->spr.UGQR[0+n] >> 24) & 0x3f)\n#define LD_TYPE(n)  ((hCPU->spr.UGQR[0+n] >> 16) & 7)\n#define ST_SCALE(n) ((hCPU->spr.UGQR[0+n] >>  8) & 0x3f)\n#define ST_TYPE(n)  ((hCPU->spr.UGQR[0+n]      ) & 7)\n#define PSW         (opcode & 0x8000)\n#define PSI         ((opcode >> 12) & 7)\n\n#define PSWX         (opcode & (1<<(7+3)))\n#define PSIX         ((opcode >> 7) & 7)\n\nstatic void PPCInterpreter_PSQ_ST(PPCInterpreter_t* hCPU, unsigned int opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, frD, rA, imm);\n\n\tuint32 ea = _uint32_fastSignExtend(imm, 11);\n\n\tea += (rA ? hCPU->gpr[rA] : 0);\n\n\tsint32 type = ST_TYPE(PSI);\n\tuint8 scale = (uint8)ST_SCALE(PSI);\n\n\tif (opcode & 0x8000) // PSW?\n\t{\n\t\tif ((type == 4) || (type == 6)) ppcItpCtrl::ppcMem_writeDataU8(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse if ((type == 5) || (type == 7)) ppcItpCtrl::ppcMem_writeDataU16(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse ppcItpCtrl::ppcMem_writeDataU32(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t}\n\telse\n\t{\n\t\tif ((type == 4) || (type == 6)) ppcItpCtrl::ppcMem_writeDataU8(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse if ((type == 5) || (type == 7)) ppcItpCtrl::ppcMem_writeDataU16(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse ppcItpCtrl::ppcMem_writeDataU32(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\n\t\tif ((type == 4) || (type == 6)) ppcItpCtrl::ppcMem_writeDataU8(hCPU, ea + 1, quantize((float)hCPU->fpr[frD].fp1, type, scale));\n\t\telse if ((type == 5) || (type == 7)) ppcItpCtrl::ppcMem_writeDataU16(hCPU, ea + 2, quantize((float)hCPU->fpr[frD].fp1, type, scale));\n\t\telse ppcItpCtrl::ppcMem_writeDataU32(hCPU, ea + 4, quantize((float)hCPU->fpr[frD].fp1, type, scale));\n\t}\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_PSQ_STU(PPCInterpreter_t* hCPU, unsigned int opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, frD, rA, imm);\n\tuint32 ea = _uint32_fastSignExtend(imm, 11);\n\n\tif (ea & 0x800)\n\t\tea |= 0xfffff000;\n\n\tea += (rA ? hCPU->gpr[rA] : 0);\n\tif (rA)\n\t\thCPU->gpr[rA] = ea;\n\n\tsint32 type = ST_TYPE((opcode >> 12) & 0x7);\n\tuint8 scale = (uint8)ST_SCALE(PSI);\n\n\tif (opcode & 0x8000) //PSW?\n\t{\n\t\tif ((type == 4) || (type == 6)) ppcItpCtrl::ppcMem_writeDataU8(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse if ((type == 5) || (type == 7)) ppcItpCtrl::ppcMem_writeDataU16(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse ppcItpCtrl::ppcMem_writeDataU32(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t}\n\telse\n\t{\n\t\tif ((type == 4) || (type == 6)) ppcItpCtrl::ppcMem_writeDataU8(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse if ((type == 5) || (type == 7)) ppcItpCtrl::ppcMem_writeDataU16(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse ppcItpCtrl::ppcMem_writeDataU32(hCPU, ea, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\n\t\tif ((type == 4) || (type == 6)) ppcItpCtrl::ppcMem_writeDataU8(hCPU, ea + 1, quantize((float)hCPU->fpr[frD].fp1, type, scale));\n\t\telse if ((type == 5) || (type == 7)) ppcItpCtrl::ppcMem_writeDataU16(hCPU, ea + 2, quantize((float)hCPU->fpr[frD].fp1, type, scale));\n\t\telse ppcItpCtrl::ppcMem_writeDataU32(hCPU, ea + 4, quantize((float)hCPU->fpr[frD].fp1, type, scale));\n\t}\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n\nstatic void PPCInterpreter_PSQ_STX(PPCInterpreter_t* hCPU, unsigned int opcode)\n{\n\tFPUCheckAvailable();\n\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n\n\tsint32 frD;\n\tuint32 rA, rB;\n\tfrD = (opcode >> (31 - 10)) & 0x1F;\n\trA = (opcode >> (31 - 15)) & 0x1F;\n\trB = (opcode >> (31 - 20)) & 0x1F;\n\tuint32 EA = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\n\tsint32 type = ST_TYPE(PSIX);\n\tuint8 scale = (uint8)ST_SCALE(PSIX);\n\n\tif (PSWX)\n\t{\n\t\tif ((type == 4) || (type == 6)) ppcItpCtrl::ppcMem_writeDataU8(hCPU, EA, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse if ((type == 5) || (type == 7)) ppcItpCtrl::ppcMem_writeDataU16(hCPU, EA, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse ppcItpCtrl::ppcMem_writeDataU32(hCPU, EA, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t}\n\telse\n\t{\n\t\tif ((type == 4) || (type == 6)) ppcItpCtrl::ppcMem_writeDataU8(hCPU, EA, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse if ((type == 5) || (type == 7)) ppcItpCtrl::ppcMem_writeDataU16(hCPU, EA, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\t\telse ppcItpCtrl::ppcMem_writeDataU32(hCPU, EA, quantize((float)hCPU->fpr[frD].fp0, type, scale));\n\n\t\tif ((type == 4) || (type == 6)) ppcItpCtrl::ppcMem_writeDataU8(hCPU, EA + 1, quantize((float)hCPU->fpr[frD].fp1, type, scale));\n\t\telse if ((type == 5) || (type == 7)) ppcItpCtrl::ppcMem_writeDataU16(hCPU, EA + 2, quantize((float)hCPU->fpr[frD].fp1, type, scale));\n\t\telse ppcItpCtrl::ppcMem_writeDataU32(hCPU, EA + 4, quantize((float)hCPU->fpr[frD].fp1, type, scale));\n\t}\n}\n\nstatic void PPCInterpreter_PSQ_L(PPCInterpreter_t* hCPU, unsigned int opcode)\n{\n\tFPUCheckAvailable();\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, frD, rA, imm);\n\n\tuint32 EA, data0 = 0, data1 = 0;\n\tsint32 type = LD_TYPE(PSI);\n\tuint8 scale = (uint8)LD_SCALE(PSI);\n\n\tEA = _uint32_fastSignExtend(opcode, 11);\n\n\tif (rA) EA += hCPU->gpr[rA];\n\n\tif (opcode & 0x8000)\n\t{\n\t\tif ((type == 4) || (type == 6)) *(uint8*)&data0 = ppcItpCtrl::ppcMem_readDataU8(hCPU, EA);\n\t\telse if ((type == 5) || (type == 7)) *(uint16*)&data0 = ppcItpCtrl::ppcMem_readDataU16(hCPU, EA);\n\t\telse *(uint32*)&data0 = ppcItpCtrl::ppcMem_readDataU32(hCPU, EA);\n\t\tif (type == 6) if (data0 & 0x80) data0 |= 0xffffff00;\n\t\tif (type == 7) if (data0 & 0x8000) data0 |= 0xffff0000;\n\n\t\thCPU->fpr[frD].fp0 = (double)dequantize(data0, type, scale);\n\t\thCPU->fpr[frD].fp1 = 1.0f;\n\t}\n\telse\n\t{\n\t\tif ((type == 4) || (type == 6))\n\t\t{\n\t\t\t*(uint8*)&data0 = ppcItpCtrl::ppcMem_readDataU8(hCPU, EA);\n\t\t\t*(uint8*)&data1 = ppcItpCtrl::ppcMem_readDataU8(hCPU, EA + 1);\n\t\t}\n\t\telse if ((type == 5) || (type == 7))\n\t\t{\n\t\t\t*(uint16*)&data0 = ppcItpCtrl::ppcMem_readDataU16(hCPU, EA);\n\t\t\t*(uint16*)&data1 = ppcItpCtrl::ppcMem_readDataU16(hCPU, EA + 2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t*(uint32*)&data0 = ppcItpCtrl::ppcMem_readDataU32(hCPU, EA);\n\t\t\t*(uint32*)&data1 = ppcItpCtrl::ppcMem_readDataU32(hCPU, EA + 4);\n\t\t}\n\t\tif (type == 6)\n\t\t{\n\t\t\tif (data0 & 0x80) data0 |= 0xffffff00;\n\t\t\tif (data1 & 0x80) data1 |= 0xffffff00;\n\t\t}\n\t\tif (type == 7)\n\t\t{\n\t\t\tif (data0 & 0x8000) data0 |= 0xffff0000;\n\t\t\tif (data1 & 0x8000) data1 |= 0xffff0000;\n\t\t}\n\n\t\thCPU->fpr[frD].fp0 = (double)dequantize(data0, type, scale);\n\t\thCPU->fpr[frD].fp1 = (double)dequantize(data1, type, scale);\n\t}\n}\n\nstatic void PPCInterpreter_PSQ_LU(PPCInterpreter_t* hCPU, unsigned int opcode)\n{\n\tFPUCheckAvailable();\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n\n\tint rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, frD, rA, imm);\n\n\tuint32 EA = opcode & 0xfff, data0 = 0, data1 = 0;\n\tsint32 type = LD_TYPE(PSI);\n\tuint8 scale = (uint8)LD_SCALE(PSI);\n\n\tif (EA & 0x800) EA |= 0xfffff000;\n\n\tif (rA)\n\t{\n\t\tEA += hCPU->gpr[rA];\n\t\thCPU->gpr[rA] = EA;\n\t}\n\n\tif (opcode & 0x8000)\n\t{\n\t\tif ((type == 4) || (type == 6)) *(uint8*)&data0 = ppcItpCtrl::ppcMem_readDataU8(hCPU, EA);\n\t\telse if ((type == 5) || (type == 7)) *(uint16*)&data0 = ppcItpCtrl::ppcMem_readDataU16(hCPU, EA);\n\t\telse *(uint32*)&data0 = ppcItpCtrl::ppcMem_readDataU32(hCPU, EA);\n\t\tif (type == 6) if (data0 & 0x80) data0 |= 0xffffff00;\n\t\tif (type == 7) if (data0 & 0x8000) data0 |= 0xffff0000;\n\n\t\thCPU->fpr[frD].fp0 = (double)dequantize(data0, type, scale);\n\t\thCPU->fpr[frD].fp1 = 1.0f;\n\t}\n\telse\n\t{\n\t\tif ((type == 4) || (type == 6)) *(uint8*)&data0 = ppcItpCtrl::ppcMem_readDataU8(hCPU, EA);\n\t\telse if ((type == 5) || (type == 7)) *(uint16*)&data0 = ppcItpCtrl::ppcMem_readDataU16(hCPU, EA);\n\t\telse *(uint32*)&data0 = ppcItpCtrl::ppcMem_readDataU32(hCPU, EA);\n\t\tif (type == 6) if (data0 & 0x80) data0 |= 0xffffff00;\n\t\tif (type == 7) if (data0 & 0x8000) data0 |= 0xffff0000;\n\n\t\tif ((type == 4) || (type == 6)) *(uint8*)&data1 = ppcItpCtrl::ppcMem_readDataU8(hCPU, EA + 1);\n\t\telse if ((type == 5) || (type == 7)) *(uint16*)&data1 = ppcItpCtrl::ppcMem_readDataU16(hCPU, EA + 2);\n\t\telse *(uint32*)&data1 = ppcItpCtrl::ppcMem_readDataU32(hCPU, EA + 4);\n\t\tif (type == 6) if (data1 & 0x80) data1 |= 0xffffff00;\n\t\tif (type == 7) if (data1 & 0x8000) data1 |= 0xffff0000;\n\n\t\thCPU->fpr[frD].fp0 = (double)dequantize(data0, type, scale);\n\t\thCPU->fpr[frD].fp1 = (double)dequantize(data1, type, scale);\n\t}\n}\n\nstatic void PPCInterpreter_PSQ_LX(PPCInterpreter_t* hCPU, unsigned int opcode)\n{\n\tFPUCheckAvailable();\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n\n\tsint32 frD;\n\tuint32 rA, rB;\n\n\tfrD = (opcode >> (32 - 11)) & 0x1F;\n\trA = (opcode >> (32 - 16)) & 0x1F;\n\trB = (opcode >> (32 - 21)) & 0x1F;\n\n\tuint32 EA = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\n\tuint32 data0 = 0, data1 = 0;\n\tsint32 type = LD_TYPE(PSIX);\n\tuint8 scale = (uint8)LD_SCALE(PSIX);\n\n\tif (PSWX)\n\t{\n\t\tif ((type == 4) || (type == 6)) *(uint8*)&data0 = ppcItpCtrl::ppcMem_readDataU8(hCPU, EA);\n\t\telse if ((type == 5) || (type == 7)) *(uint16*)&data0 = ppcItpCtrl::ppcMem_readDataU16(hCPU, EA);\n\t\telse *(uint32*)&data0 = ppcItpCtrl::ppcMem_readDataU32(hCPU, EA);\n\t\tif (type == 6) if (data0 & 0x80) data0 |= 0xffffff00;\n\t\tif (type == 7) if (data0 & 0x8000) data0 |= 0xffff0000;\n\n\t\thCPU->fpr[frD].fp0 = (double)dequantize(data0, type, scale);\n\t\thCPU->fpr[frD].fp1 = 1.0f;\n\t}\n\telse\n\t{\n\t\tif ((type == 4) || (type == 6)) *(uint8*)&data0 = ppcItpCtrl::ppcMem_readDataU8(hCPU, EA);\n\t\telse if ((type == 5) || (type == 7)) *(uint16*)&data0 = ppcItpCtrl::ppcMem_readDataU16(hCPU, EA);\n\t\telse *(uint32*)&data0 = ppcItpCtrl::ppcMem_readDataU32(hCPU, EA);\n\t\tif (type == 6) if (data0 & 0x80) data0 |= 0xffffff00;\n\t\tif (type == 7) if (data0 & 0x8000) data0 |= 0xffff0000;\n\n\t\tif ((type == 4) || (type == 6)) *(uint8*)&data1 = ppcItpCtrl::ppcMem_readDataU8(hCPU, EA + 1);\n\t\telse if ((type == 5) || (type == 7)) *(uint16*)&data1 = ppcItpCtrl::ppcMem_readDataU16(hCPU, EA + 2);\n\t\telse *(uint32*)&data1 = ppcItpCtrl::ppcMem_readDataU32(hCPU, EA + 4);\n\t\tif (type == 6) if (data1 & 0x80) data1 |= 0xffffff00;\n\t\tif (type == 7) if (data1 & 0x8000) data1 |= 0xffff0000;\n\n\t\thCPU->fpr[frD].fp0 = (double)dequantize(data0, type, scale);\n\t\thCPU->fpr[frD].fp1 = (double)dequantize(data1, type, scale);\n\t}\n}\n\n// misc\n\nstatic void PPCInterpreter_DCBZ(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tint rA, rB;\n\trA = (Opcode >> (31 - 15)) & 0x1F;\n\trB = (Opcode >> (31 - 20)) & 0x1F;\n\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\tea &= ~31;\n\tif constexpr(ppcItpCtrl::allowSupervisorMode)\n\t{\n\t\t// todo - optimize\n\t\tppcItpCtrl::ppcMem_writeDataU32(hCPU, ea + 0, 0);\n\t\tDSI_EXIT();\n\t\tppcItpCtrl::ppcMem_writeDataU32(hCPU, ea + 4, 0);\n\t\tppcItpCtrl::ppcMem_writeDataU32(hCPU, ea + 8, 0);\n\t\tppcItpCtrl::ppcMem_writeDataU32(hCPU, ea + 12, 0);\n\t\tppcItpCtrl::ppcMem_writeDataU32(hCPU, ea + 16, 0);\n\t\tppcItpCtrl::ppcMem_writeDataU32(hCPU, ea + 20, 0);\n\t\tppcItpCtrl::ppcMem_writeDataU32(hCPU, ea + 24, 0);\n\t\tppcItpCtrl::ppcMem_writeDataU32(hCPU, ea + 28, 0);\n\t}\n\telse\n\t{\n\t\tmemset((void*)memory_getPointerFromVirtualOffset(ea), 0x00, 0x20);\n\t}\n\n\t// debug output\n#ifdef __DEBUG_OUTPUT_INSTRUCTION\n\tdebug_printf(\"DCBZ\\n\");\n#endif\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterMain.cpp",
    "content": "#include \"PPCInterpreterInternal.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n\nthread_local PPCInterpreter_t* ppcInterpreterCurrentInstance;\n\n// main thread instruction counter and timing\nuint64 ppcMainThreadDECCycleValue = 0; // value that was set to dec register\nuint64 ppcMainThreadDECCycleStart = 0; // at which cycle the dec register was set, if == 0 -> dec is 0\nuint64 ppcCyclesSince2000 = 0;\nuint64 ppcCyclesSince2000TimerClock = 0;\nuint64 ppcCyclesSince2000_UTC = 0;\n\nPPCInterpreter_t* PPCInterpreter_createInstance(unsigned int Entrypoint)\n{\n\tPPCInterpreter_t* pData;\n\t// create instance\n\tuint32 prefixAreaSize = 0x6000; // we need to allocate some bytes before the interpreter struct because the recompiler will use it as stack area (specifically when the exception handler is called)\n\tpData = (PPCInterpreter_t*)((uint8*)malloc(sizeof(PPCInterpreter_t)+prefixAreaSize)+prefixAreaSize);\n\tmemset((void*)pData, 0x00, sizeof(PPCInterpreter_t));\n\t// set instruction pointer to entrypoint\n\tpData->instructionPointer = (uint32)Entrypoint;\n\t// set initial register values\n\tpData->gpr[GPR_SP] = 0x00000000;\n\tpData->spr.LR = 0;\n\t// return instance\n\treturn pData;\n}\n\nTLS_WORKAROUND_NOINLINE PPCInterpreter_t* PPCInterpreter_getCurrentInstance()\n{\n\treturn ppcInterpreterCurrentInstance;\n}\n\nTLS_WORKAROUND_NOINLINE void PPCInterpreter_setCurrentInstance(PPCInterpreter_t* hCPU)\n{\n\tppcInterpreterCurrentInstance = hCPU;\n}\n\nuint64 PPCInterpreter_getMainCoreCycleCounter()\n{\n\treturn PPCTimer_getFromRDTSC();\n}\n\nvoid PPCInterpreter_nextInstruction(PPCInterpreter_t* cpuInterpreter)\n{\n\tcpuInterpreter->instructionPointer += 4;\n}\n\nvoid PPCInterpreter_jumpToInstruction(PPCInterpreter_t* cpuInterpreter, uint32 newIP)\n{\n\tcpuInterpreter->instructionPointer = (uint32)newIP;\n}\n\nvoid PPCInterpreter_setDEC(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\thCPU->sprExtended.DEC = newValue;\n\tppcMainThreadDECCycleStart = PPCInterpreter_getMainCoreCycleCounter();\n\tppcMainThreadDECCycleValue = newValue;\n}\n\nuint32 PPCInterpreter_getXER(PPCInterpreter_t* hCPU)\n{\n\tuint32 xerValue = hCPU->spr.XER;\n\txerValue &= ~(1 << XER_BIT_CA);\n\txerValue &= ~(1 << XER_BIT_SO);\n\txerValue &= ~(1 << XER_BIT_OV);\n\tif (hCPU->xer_ca)\n\t\txerValue |= (1 << XER_BIT_CA);\n\tif (hCPU->xer_so)\n\t\txerValue |= (1 << XER_BIT_SO);\n\tif (hCPU->xer_ov)\n\t\txerValue |= (1 << XER_BIT_OV);\n\treturn xerValue;\n}\n\nvoid PPCInterpreter_setXER(PPCInterpreter_t* hCPU, uint32 v)\n{\n\tconst uint32 XER_MASK = 0xE0FFFFFF; // some bits are masked out. Figure out which ones exactly\n\thCPU->spr.XER = v & XER_MASK;\n\thCPU->xer_ca = (v >> XER_BIT_CA) & 1;\n\thCPU->xer_so = (v >> XER_BIT_SO) & 1;\n\thCPU->xer_ov = (v >> XER_BIT_OV) & 1;\n}\n\nuint32 PPCInterpreter_getCoreIndex(PPCInterpreter_t* hCPU)\n{\n\treturn hCPU->spr.UPIR;\n};\n\nuint32 PPCInterpreter_getCurrentCoreIndex()\n{\n\treturn PPCInterpreter_getCurrentInstance()->spr.UPIR;\n};\n\nuint8* PPCInterpreterGetStackPointer()\n{\n\treturn memory_getPointerFromVirtualOffset(PPCInterpreter_getCurrentInstance()->gpr[1]);\n}\n\nuint8* PPCInterpreter_PushAndReturnStackPointer(sint32 offset)\n{\n\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\tuint8* result = memory_getPointerFromVirtualOffset(hCPU->gpr[1] - offset);\n\thCPU->gpr[1] -= offset;\n\treturn result;\n}\n\nvoid PPCInterpreterModifyStackPointer(sint32 offset)\n{\n\tPPCInterpreter_getCurrentInstance()->gpr[1] -= offset;\n}\n\nuint32 RPLLoader_MakePPCCallable(void(*ppcCallableExport)(PPCInterpreter_t* hCPU));\n\n// deprecated wrapper, use RPLLoader_MakePPCCallable directly\nuint32 PPCInterpreter_makeCallableExportDepr(void (*ppcCallableExport)(PPCInterpreter_t* hCPU))\n{\n\treturn RPLLoader_MakePPCCallable(ppcCallableExport);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.cpp",
    "content": "#include \"../PPCState.h\"\n#include \"PPCInterpreterInternal.h\"\n#include \"PPCInterpreterHelper.h\"\n\n#include \"Cafe/OS/libs/coreinit/coreinit_CodeGen.h\"\n\n#include \"../Recompiler/PPCRecompiler.h\"\n\n#include <float.h>\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n\nvoid PPCInterpreter_MFMSR(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tcemuLog_logDebug(LogType::Force, \"Rare instruction: MFMSR\");\n\tif (hCPU->sprExtended.msr & MSR_PR)\n\t{\n\t\tPPC_ASSERT(true);\n\t\treturn;\n\t}\n\tint rD, rA, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\thCPU->gpr[rD] = hCPU->sprExtended.msr;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n\n}\n\nvoid PPCInterpreter_MTMSR(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tcemuLog_logDebug(LogType::Force, \"Rare instruction: MTMSR\");\n\tif (hCPU->sprExtended.msr & MSR_PR)\n\t{\n\t\tPPC_ASSERT(true);\n\t\treturn;\n\t}\n\tint rS, rA, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\n\thCPU->sprExtended.msr = hCPU->gpr[rS];\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_MTFSB1X(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tcemuLog_logDebug(LogType::Force, \"Rare instruction: MTFSB1X\");\n\tint crbD, n1, n2;\n\tPPC_OPC_TEMPL_X(Opcode, crbD, n1, n2);\n\tif (crbD != 1 && crbD != 2) \n\t{\n\t\thCPU->fpscr |= 1 << (31 - crbD);\n\t}\n\tif (Opcode & PPC_OPC_RC) \n\t{\n\t\t// update cr1 flags\n\t\tPPC_ASSERT(true);\n\t}\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_MCRF(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tuint32 crD, crS, b;\n\tPPC_OPC_TEMPL_X(Opcode, crD, crS, b);\n\tcrD >>= 2;\n\tcrS >>= 2;\n\tfor (sint32 i = 0; i<4; i++)\n\t\tppc_setCRBit(hCPU, crD * 4 + i, ppc_getCRBit(hCPU, crS * 4 + i));\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_MFCR(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\t// frequently used by GCC compiled code (e.g. SM64 port)\n\tint rD, rA, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\t\n\t// in our array: cr0.LT is entry with index 0\n\t// in GPR: cr0.LT is in MSB\n\tuint32 cr = 0;\n\tfor (sint32 i = 0; i < 32; i++)\n\t{\n\t\tcr <<= 1;\n\t\tif (ppc_getCRBit(hCPU, i) != 0)\n\t\t\tcr |= 1;\n\t}\n\thCPU->gpr[rD] = cr;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_MTCRF(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\t// frequently used by GCC compiled code (e.g. SM64 port)\n\t// tested\n\tuint32 rS;\n\tuint32 crfMask;\n\tPPC_OPC_TEMPL_XFX(Opcode, rS, crfMask);\n\n\tfor (sint32 crIndex = 0; crIndex < 8; crIndex++)\n\t{\n\t\tif (!ppc_MTCRFMaskHasCRFieldSet(crfMask, crIndex))\n\t\t\tcontinue;\n\n\t\tuint32 crBitBase = crIndex * 4;\n\t\tuint8 nibble = (uint8)(hCPU->gpr[rS] >> (28 - crIndex * 4));\n\t\tppc_setCRBit(hCPU, crBitBase + 0, (nibble >> 3) & 1);\n\t\tppc_setCRBit(hCPU, crBitBase + 1, (nibble >> 2) & 1);\n\t\tppc_setCRBit(hCPU, crBitBase + 2, (nibble >> 1) & 1);\n\t\tppc_setCRBit(hCPU, crBitBase + 3, (nibble >> 0) & 1);\n\t}\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_MCRXR(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\t\n\t// used in Dont Starve: Giant Edition\n\t// also used frequently by Web Browser (webkit?)\n\tuint32 cr;\n\tcr = (Opcode >> (31 - 8)) & 7;\n\tcr >>= 2;\n\n\tuint32 xer = PPCInterpreter_getXER(hCPU);\n\tuint32 xerBits = (xer >> 28) & 0xF;\n\n\t// todo - is the order correct?\n\tppc_setCRBit(hCPU, cr * 4 + 0, (xerBits >> 0) & 1);\n\tppc_setCRBit(hCPU, cr * 4 + 1, (xerBits >> 1) & 1);\n\tppc_setCRBit(hCPU, cr * 4 + 2, (xerBits >> 2) & 1);\n\tppc_setCRBit(hCPU, cr * 4 + 3, (xerBits >> 3) & 1);\n\n\t// reset copied bits\n\tPPCInterpreter_setXER(hCPU, xer&~0xF0000000);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_TLBIE(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tint rS, rA, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rS, rA, rB);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_TLBSYNC(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tcemu_assert_unimplemented();\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n// branch instructions\n\nvoid PPCInterpreter_BX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tuint32 li;\n\tPPC_OPC_TEMPL_I(Opcode, li);\n\tif ((Opcode & PPC_OPC_AA) == 0)\n\t\tli += (unsigned int)hCPU->instructionPointer;\n\tif (Opcode & PPC_OPC_LK) \n\t{\n\t\t// update LR and IP\n\t\thCPU->spr.LR = (unsigned int)hCPU->instructionPointer + 4;\n\t\thCPU->instructionPointer = li;\n\t\tPPCInterpreter_jumpToInstruction(hCPU, li);\n\t\tPPCRecompiler_attemptEnter(hCPU, li);\n\t\treturn;\n\t}\n\tPPCInterpreter_jumpToInstruction(hCPU, li);\n}\n\n\nvoid PPCInterpreter_BCX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tuint32 BO, BI, BD;\n\tPPC_OPC_TEMPL_B(Opcode, BO, BI, BD);\n\tif (!(BO & 4))\n\t\thCPU->spr.CTR--;\n\tbool bo2 = (BO & 2) != 0;\n\tbool bo8 = (BO & 8) != 0; // branch condition true\n\tbool cr = ppc_getCRBit(hCPU, BI) != 0;\n\tif (((BO & 4) || ((hCPU->spr.CTR != 0) ^ bo2)) \n\t\t&& ((BO & 16) || (!(cr ^ bo8)))) \n\t{\n\t\tif (!(Opcode & PPC_OPC_AA))\n\t\t{\n\t\t\tBD += (unsigned int)hCPU->instructionPointer;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// should never happen\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\tif (Opcode & PPC_OPC_LK)\n\t\t\thCPU->spr.LR = ((unsigned int)hCPU->instructionPointer) + 4;\n\t\tPPCInterpreter_jumpToInstruction(hCPU, BD);\n\t}\n\telse\n\t\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_BCLRX(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tuint32 BO, BI, BD;\n\tPPC_OPC_TEMPL_XL(Opcode, BO, BI, BD);\n\tPPC_ASSERT(BD == 0);\n\tif (!(BO & 4))\n\t{\n\t\tif (hCPU->spr.CTR == 0)\n\t\t{\n\t\t\tPPC_ASSERT(true);\n\t\t\tcemuLog_logDebug(LogType::Force, \"Decrementer underflow!\");\n\t\t}\n\t\thCPU->spr.CTR--;\n\t}\n\tbool bo2 = (BO & 2) ? true : false;\n\tbool bo8 = (BO & 8) ? true : false;\n\tbool cr = ppc_getCRBit(hCPU, BI) != 0;\n\tif (((BO & 4) || ((hCPU->spr.CTR != 0) ^ bo2))\n\t\t&& ((BO & 16) || (!(cr ^ bo8))))\n\t{\n\t\tBD = hCPU->spr.LR & 0xfffffffc;\n\t\tif (Opcode & PPC_OPC_LK)\n\t\t{\n\t\t\thCPU->spr.LR = (unsigned int)hCPU->instructionPointer + 4;\n\t\t}\n\t\tPPCInterpreter_jumpToInstruction(hCPU, BD);\n\t\tPPCRecompiler_attemptEnter(hCPU, BD);\n\t\treturn;\n\t}\n\telse\n\t{\n\t\tBD = (unsigned int)hCPU->instructionPointer + 4;\n\t\tPPCInterpreter_nextInstruction(hCPU);\n\t}\n}\n\nvoid PPCInterpreter_BCCTR(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tuint32 x = (unsigned int)hCPU->instructionPointer;\n\tuint32 BO, BI, BD;\n\tPPC_OPC_TEMPL_XL(Opcode, BO, BI, BD);\n\tPPC_ASSERT(BD == 0);\n\tPPC_ASSERT(!(BO & 2));\n\tbool bo8 = (BO & 8) ? true : false;\n\tbool cr = ppc_getCRBit(hCPU, BI) != 0;\n\tif ((BO & 16) || (!(cr ^ bo8)))\n\t{\n\t\tif (Opcode & PPC_OPC_LK)\n\t\t{\n\t\t\thCPU->spr.LR = (unsigned int)hCPU->instructionPointer + 4;\n\t\t\thCPU->instructionPointer = (unsigned int)(hCPU->spr.CTR & 0xfffffffc);\n\t\t}\n\t\telse\n\t\t{\n\t\t\thCPU->instructionPointer = (unsigned int)(hCPU->spr.CTR & 0xfffffffc);\n\t\t}\n\t\tPPCRecompiler_attemptEnter(hCPU, hCPU->instructionPointer);\n\t}\n\telse\n\t{\n\t\thCPU->instructionPointer += 4;\n\t}\n}\n\nvoid PPCInterpreter_DCBT(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rB;\n\trA = (Opcode >> (31 - 15)) & 0x1F;\n\trB = (Opcode >> (31 - 20)) & 0x1F;\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_DCBST(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rB;\n\trA = (Opcode >> (31 - 15)) & 0x1F;\n\trB = (Opcode >> (31 - 20)) & 0x1F;\n\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\n\tLatteBufferCache_notifyDCFlush(ea, 32);\n\t\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_DCBF(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rA, rB;\n\trA = (Opcode >> (31 - 15)) & 0x1F;\n\trB = (Opcode >> (31 - 20)) & 0x1F;\n\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\n\tLatteBufferCache_notifyDCFlush(ea, 32);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_DCBZL(PPCInterpreter_t* hCPU, uint32 Opcode) //Undocumented\n{\n\t// no-op\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_DCBI(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\t// no-op\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_ICBI(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_X(Opcode, rD, rA, rB);\n\tuint32 ea = (rA ? hCPU->gpr[rA] : 0) + hCPU->gpr[rB];\n\t// invalidate range\n\tcoreinit::codeGenHandleICBI(ea);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_EIEIO(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\t// no effect\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_SC(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tcemuLog_logDebug(LogType::Force, \"SC executed at 0x{:08x}\", hCPU->instructionPointer);\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_SYNC(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\t// no-op\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_ISYNC(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\t// no-op\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_RFI(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tcemuLog_logDebug(LogType::Force, \"RFI\");\n\thCPU->sprExtended.msr &= ~(0x87C0FF73 | 0x00040000);\n\thCPU->sprExtended.msr |= hCPU->sprExtended.srr1 & 0x87c0ff73;\n\thCPU->sprExtended.msr |= MSR_RI;\n\thCPU->instructionPointer = (unsigned int)(hCPU->sprExtended.srr0);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterOPC.hpp",
    "content": "\nstatic void PPCInterpreter_MFSPR(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tuint32 rD, spr1, spr2, spr;\n\tPPC_OPC_TEMPL_XO(opcode, rD, spr1, spr2);\n\tspr = spr1 | (spr2 << 5);\n\t// copy SPR\n\thCPU->gpr[rD] = PPCSpr_get(hCPU, spr);\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_MTSPR(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tuint32 rD, spr1, spr2, spr;\n\tPPC_OPC_TEMPL_XO(opcode, rD, spr1, spr2);\n\tspr = spr1 | (spr2 << 5);\n\tPPCSpr_set(hCPU, spr, hCPU->gpr[rD]);\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_MFSR(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tuint32 rD, SR, rB;\n\tPPC_OPC_TEMPL_X(opcode, rD, SR, rB);\n\thCPU->gpr[rD] = getSR(hCPU, SR & 0xF);\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_MTSR(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tuint32 rS, SR, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, SR, rB);\n\tsetSR(hCPU, SR&0xF, hCPU->gpr[rS]);\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_MFTB(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tuint32 rD, spr1, spr2, spr;\n\t// get SPR ID\n\tPPC_OPC_TEMPL_XO(opcode, rD, spr1, spr2);\n\tspr = spr1 | (spr2 << 5);\n\t// get core cycle counter\n\tuint64 coreTime = ppcItpCtrl::getTB(hCPU);\n\n\tswitch (spr)\n\t{\n\tcase 268: // TBL\n\t\thCPU->gpr[rD] = (uint32)(coreTime & 0xFFFFFFFF);\n\t\tbreak;\n\tcase 269: // TBU\n\t\thCPU->gpr[rD] = (uint32)((coreTime >> 32) & 0xFFFFFFFF);\n\t\tbreak;\n\tdefault:\n\t\tassert_dbg();\n\t}\n\t// next instruction\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nstatic void PPCInterpreter_TW(PPCInterpreter_t* hCPU, uint32 opcode)\n{\n\tsint32 to, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, to, rA, rB);\n\n\tcemu_assert_debug(to == 0);\n\tif(to != 0)\n\t\tPPCInterpreter_nextInstruction(hCPU);\n\n    if (rA == DEBUGGER_BP_T_DEBUGGER)\n\t    debugger_enterTW(hCPU);\n    else if (rA == DEBUGGER_BP_T_GDBSTUB)\n        g_gdbstub->HandleTrapInstruction(hCPU);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterPS.cpp",
    "content": "#include \"PPCInterpreterInternal.h\"\n\n// Gekko paired single math\n\nvoid PPCInterpreter_PS_ADD(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\thCPU->fpr[frD].fp0 = (float)(hCPU->fpr[frA].fp0 + hCPU->fpr[frB].fp0);\n\thCPU->fpr[frD].fp1 = (float)(hCPU->fpr[frA].fp1 + hCPU->fpr[frB].fp1);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_SUB(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\thCPU->fpr[frD].fp0 = (float)(hCPU->fpr[frA].fp0 - hCPU->fpr[frB].fp0);\n\thCPU->fpr[frD].fp1 = (float)(hCPU->fpr[frA].fp1 - hCPU->fpr[frB].fp1);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MUL(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frC;\n\tfrC = (Opcode>>6)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\thCPU->fpr[frD].fp0 = flushDenormalToZero((float)(hCPU->fpr[frA].fp0 * roundTo25BitAccuracy(hCPU->fpr[frC].fp0)));\n\thCPU->fpr[frD].fp1 = flushDenormalToZero((float)(hCPU->fpr[frA].fp1 * roundTo25BitAccuracy(hCPU->fpr[frC].fp1)));\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_DIV(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\thCPU->fpr[frD].fp0 = (float)(hCPU->fpr[frA].fp0 / hCPU->fpr[frB].fp0);\n\thCPU->fpr[frD].fp1 = (float)(hCPU->fpr[frA].fp1 / hCPU->fpr[frB].fp1);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n\nvoid PPCInterpreter_PS_MADD(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB, frC;\n\tfrC = (Opcode>>6)&0x1F;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tfloat s0 = (float)((float)(hCPU->fpr[frA].fp0 * roundTo25BitAccuracy(hCPU->fpr[frC].fp0)) + hCPU->fpr[frB].fp0);\n\tfloat s1 = (float)((float)(hCPU->fpr[frA].fp1 * roundTo25BitAccuracy(hCPU->fpr[frC].fp1)) + hCPU->fpr[frB].fp1);\n\n\thCPU->fpr[frD].fp0 = flushDenormalToZero(s0);\n\thCPU->fpr[frD].fp1 = flushDenormalToZero(s1);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_NMADD(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB, frC;\n\tfrC = (Opcode>>6)&0x1F;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tfloat s0 = (float)-(hCPU->fpr[frA].fp0 * roundTo25BitAccuracy(hCPU->fpr[frC].fp0) + hCPU->fpr[frB].fp0);\n\tfloat s1 = (float)-(hCPU->fpr[frA].fp1 * roundTo25BitAccuracy(hCPU->fpr[frC].fp1) + hCPU->fpr[frB].fp1);\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MSUB(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tsint32 frD, frA, frB, frC;\n\tfrC = (Opcode >> 6) & 0x1F;\n\tfrB = (Opcode >> 11) & 0x1F;\n\tfrA = (Opcode >> 16) & 0x1F;\n\tfrD = (Opcode >> 21) & 0x1F;\n\n\tfloat s0 = (float)(hCPU->fpr[frA].fp0 * roundTo25BitAccuracy(hCPU->fpr[frC].fp0) - hCPU->fpr[frB].fp0);\n\tfloat s1 = (float)(hCPU->fpr[frA].fp1 * roundTo25BitAccuracy(hCPU->fpr[frC].fp1) - hCPU->fpr[frB].fp1);\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_NMSUB(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tsint32 frD, frA, frB, frC;\n\tfrC = (Opcode >> 6) & 0x1F;\n\tfrB = (Opcode >> 11) & 0x1F;\n\tfrA = (Opcode >> 16) & 0x1F;\n\tfrD = (Opcode >> 21) & 0x1F;\n\n\tfloat s0 = (float)-(hCPU->fpr[frA].fp0 * roundTo25BitAccuracy(hCPU->fpr[frC].fp0) - hCPU->fpr[frB].fp0);\n\tfloat s1 = (float)-(hCPU->fpr[frA].fp1 * roundTo25BitAccuracy(hCPU->fpr[frC].fp1) - hCPU->fpr[frB].fp1);\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MADDS0(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB, frC;\n\tfrC = (Opcode>>6)&0x1F;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tdouble c = roundTo25BitAccuracy(hCPU->fpr[frC].fp0);\n\tfloat s0 = (float)(hCPU->fpr[frA].fp0 * c + hCPU->fpr[frB].fp0);\n\tfloat s1 = (float)(hCPU->fpr[frA].fp1 * c + hCPU->fpr[frB].fp1);\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MADDS1(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB, frC;\n\tfrC = (Opcode>>6)&0x1F;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tdouble c = roundTo25BitAccuracy(hCPU->fpr[frC].fp1);\n\tfloat s0 = (float)(hCPU->fpr[frA].fp0 * c + hCPU->fpr[frB].fp0);\n\tfloat s1 = (float)(hCPU->fpr[frA].fp1 * c + hCPU->fpr[frB].fp1);\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_SEL(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\t\n\tFPUCheckAvailable();\n\n\tsint32 frD, frA, frB, frC;\n\tfrC = (Opcode>>6)&0x1F;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\n\tif( hCPU->fpr[frA].fp0 >= -0.0f )\n\t\thCPU->fpr[frD].fp0 = hCPU->fpr[frC].fp0;\n\telse\n\t\thCPU->fpr[frD].fp0 = hCPU->fpr[frB].fp0;\n\n\tif( hCPU->fpr[frA].fp1 >= -0.0f )\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frC].fp1;\n\telse\n\t\thCPU->fpr[frD].fp1 = hCPU->fpr[frB].fp1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_SUM0(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB, frC;\n\tfrC = (Opcode>>6)&0x1F;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tfloat s0 = (float)(hCPU->fpr[frA].fp0 + hCPU->fpr[frB].fp1);\n\tfloat s1 = (float)hCPU->fpr[frC].fp1;\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_SUM1(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB, frC;\n\tfrC = (Opcode>>6)&0x1F;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tfloat s0 = (float)hCPU->fpr[frC].fp0;\n\tfloat s1 = (float)(hCPU->fpr[frA].fp0 + hCPU->fpr[frB].fp1);\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MULS0(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frC;\n\tfrC = (Opcode>>6)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tdouble c = roundTo25BitAccuracy(hCPU->fpr[frC].fp0);\n\tfloat s0 = (float)(hCPU->fpr[frA].fp0 * c);\n\tfloat s1 = (float)(hCPU->fpr[frA].fp1 * c);\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MULS1(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frC;\n\tfrC = (Opcode>>6)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tdouble c = roundTo25BitAccuracy(hCPU->fpr[frC].fp1);\n\tfloat s0 = (float)(hCPU->fpr[frA].fp0 * c);\n\tfloat s1 = (float)(hCPU->fpr[frA].fp1 * c);\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MR(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\t\n\thCPU->fpr[frD].fp0 = hCPU->fpr[frB].fp0;\n\thCPU->fpr[frD].fp1 = hCPU->fpr[frB].fp1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_NEG(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tsint32 frD, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\thCPU->fpr[frD].fp0 = -hCPU->fpr[frB].fp0;\n\thCPU->fpr[frD].fp1 = -hCPU->fpr[frB].fp1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_ABS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tsint32 frD, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\thCPU->fpr[frD].fp0int = hCPU->fpr[frB].fp0int & ~(1ULL << 63);\n\thCPU->fpr[frD].fp1int = hCPU->fpr[frB].fp1int & ~(1ULL << 63);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_NABS(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tsint32 frD, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\thCPU->fpr[frD].fp0int = hCPU->fpr[frB].fp0int | (1ULL << 63);\n\thCPU->fpr[frD].fp1int = hCPU->fpr[frB].fp1int | (1ULL << 63);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_RSQRTE(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\t\n\thCPU->fpr[frD].fp0 = (float)frsqrte_espresso(hCPU->fpr[frB].fp0);\n\thCPU->fpr[frD].fp1 = (float)frsqrte_espresso(hCPU->fpr[frB].fp1);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MERGE00(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\tdouble s0 = hCPU->fpr[frA].fp0;\n\tdouble s1 = hCPU->fpr[frB].fp0;\n\t\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MERGE01(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tdouble s0 = hCPU->fpr[frA].fp0;\n\tdouble s1 = hCPU->fpr[frB].fp1;\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MERGE10(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tdouble s0 = hCPU->fpr[frA].fp1;\n\tdouble s1 = hCPU->fpr[frB].fp0;\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_MERGE11(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frA, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\n\tdouble s0 = hCPU->fpr[frA].fp1;\n\tdouble s1 = hCPU->fpr[frB].fp1;\n\n\thCPU->fpr[frD].fp0 = s0;\n\thCPU->fpr[frD].fp1 = s1;\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_RES(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\t\n\tsint32 frD, frB;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrD = (Opcode>>21)&0x1F;\n\t\n\thCPU->fpr[frD].fp0 = (float)fres_espresso(hCPU->fpr[frB].fp0);\n\thCPU->fpr[frD].fp1 = (float)fres_espresso(hCPU->fpr[frB].fp1);\n\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\n// PS compare\n\nvoid PPCInterpreter_PS_CMPO0(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\n\tsint32 crfD, frA, frB;\n\tuint32 c=0;\n\tfrB = (Opcode>>11)&0x1F;\n\tfrA = (Opcode>>16)&0x1F;\n\tcrfD = (Opcode>>23)&0x7;\n\n\n\tdouble a = hCPU->fpr[frA].fp0;\n\tdouble b = hCPU->fpr[frB].fp0;\n\n\tppc_setCRBit(hCPU, crfD*4+0, 0);\n\tppc_setCRBit(hCPU, crfD*4+1, 0);\n\tppc_setCRBit(hCPU, crfD*4+2, 0);\n\tppc_setCRBit(hCPU, crfD*4+3, 0);\n\n\tif(IS_NAN(*(uint64*)&a) || IS_NAN(*(uint64*)&b))\n\t{\n\t\tc = 1;\n\t\tppc_setCRBit(hCPU, crfD*4+CR_BIT_SO, 1);\n\t}\n\telse if(a < b)\n\t{\n\t\tc = 8;\n\t\tppc_setCRBit(hCPU, crfD*4+CR_BIT_LT, 1);\n\t}\n\telse if(a > b)\n\t{\n\t\tc = 4;\n\t\tppc_setCRBit(hCPU, crfD*4+CR_BIT_GT, 1);\n\t}\n\telse\n\t{\n\t\tc = 2;\n\t\tppc_setCRBit(hCPU, crfD*4+CR_BIT_EQ, 1);\n\t}\n\n\thCPU->fpscr = (hCPU->fpscr & 0xffff0fff) | (c << 12);\n\t\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_CMPU0(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 crfD, frA, frB;\n\tfrB = (Opcode >> 11) & 0x1F;\n\tfrA = (Opcode >> 16) & 0x1F;\n\tcrfD = (Opcode >> 21) & (0x7<<2);\n\tfcmpu_espresso(hCPU, crfD, hCPU->fpr[frA].fp0, hCPU->fpr[frB].fp0);\n\tPPCInterpreter_nextInstruction(hCPU);\n}\n\nvoid PPCInterpreter_PS_CMPU1(PPCInterpreter_t* hCPU, uint32 Opcode)\n{\n\tFPUCheckAvailable();\n\tsint32 crfD, frA, frB;\n\tfrB = (Opcode >> 11) & 0x1F;\n\tfrA = (Opcode >> 16) & 0x1F;\n\tcrfD = (Opcode >> 21) & (0x7 << 2);\n\tdouble a = hCPU->fpr[frA].fp1;\n\tdouble b = hCPU->fpr[frB].fp1;\n\tfcmpu_espresso(hCPU, crfD, hCPU->fpr[frA].fp1, hCPU->fpr[frB].fp1);\n\tPPCInterpreter_nextInstruction(hCPU);\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Interpreter/PPCInterpreterSPR.hpp",
    "content": "#define SPR_TBL_WRITE\t(284)\n#define SPR_TBU_WRITE\t(285)\n\n#define SPR_DBATU_0\t\t(536)\n#define SPR_DBATU_1\t\t(538)\n#define SPR_DBATU_2\t\t(540)\n#define SPR_DBATU_3\t\t(542)\n#define SPR_DBATU_4\t\t(568)\n#define SPR_DBATU_5\t\t(570)\n#define SPR_DBATU_6\t\t(572)\n#define SPR_DBATU_7\t\t(574)\n\n#define SPR_DBATL_0\t\t(537)\n#define SPR_DBATL_1\t\t(539)\n#define SPR_DBATL_2\t\t(541)\n#define SPR_DBATL_3\t\t(543)\n#define SPR_DBATL_4\t\t(569)\n#define SPR_DBATL_5\t\t(571)\n#define SPR_DBATL_6\t\t(573)\n#define SPR_DBATL_7\t\t(575)\n\n#define SPR_IBATU_0\t\t(528)\n#define SPR_IBATU_1\t\t(530)\n#define SPR_IBATU_2\t\t(532)\n#define SPR_IBATU_3\t\t(534)\n#define SPR_IBATU_4\t\t(560)\n#define SPR_IBATU_5\t\t(562)\n#define SPR_IBATU_6\t\t(564)\n#define SPR_IBATU_7\t\t(566)\n\n#define SPR_IBATL_0\t\t(529)\n#define SPR_IBATL_1\t\t(531)\n#define SPR_IBATL_2\t\t(533)\n#define SPR_IBATL_3\t\t(535)\n#define SPR_IBATL_4\t\t(561)\n#define SPR_IBATL_5\t\t(563)\n#define SPR_IBATL_6\t\t(565)\n#define SPR_IBATL_7\t\t(567)\n\n#define SPR_DSISR\t\t(18)\n#define SPR_DAR\t\t\t(19)\n\n#define SPR_SPRG0\t\t(272)\n#define SPR_SPRG1\t\t(273)\n#define SPR_SPRG2\t\t(274)\n#define SPR_SPRG3\t\t(275)\n\n//#define SPR_HID0\t\t(1008)\n//#define SPR_HID2\t\t(920)\n#define SPR_HID4\t\t(1011)\n#define SPR_HID5\t\t(944)\n\n#define SPR_L2CR\t\t(1017) // L2 cache control\n\n#define SPR_CAR\t\t\t(948) // global\n#define SPR_BCR\t\t\t(949) // global\n\nstatic uint32 getPVR(PPCInterpreter_t* hCPU)\n{\n\treturn 0x70010101; // guessed\n}\n\nstatic uint32 getFPECR(PPCInterpreter_t* hCPU)\n{\n\treturn hCPU->sprExtended.fpecr;\n}\n\nstatic void setFPECR(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\thCPU->sprExtended.fpecr = newValue;\n}\n\nstatic void setDEC(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\tdebug_printf(\"Set DEC to 0x%08x\\n\", newValue);\n\t//hCPU->sprExtended.fpecr = newValue;\n}\n\nstatic uint32 getSPRG(PPCInterpreter_t* hCPU, uint32 sprgIndex)\n{\n\treturn hCPU->sprExtended.sprg[sprgIndex];\n}\n\nstatic void setSPRG(PPCInterpreter_t* hCPU, uint32 sprgIndex, uint32 newValue)\n{\n\thCPU->sprExtended.sprg[sprgIndex] = newValue;\n}\n\nstatic uint32 getDAR(PPCInterpreter_t* hCPU)\n{\n\treturn hCPU->sprExtended.dar;\n}\n\nstatic uint32 getDSISR(PPCInterpreter_t* hCPU)\n{\n\treturn hCPU->sprExtended.dsisr;\n}\n\nstatic uint32 getHID0(PPCInterpreter_t* hCPU)\n{\n\treturn 0; // todo\n}\n\nstatic void setHID0(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\t// todo\n\tdebug_printf(\"Set HID0 to 0x%08x\\n\", newValue);\n}\n\nstatic uint32 getHID1(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"Get HID1 IP 0x%08x\\n\", hCPU->instructionPointer);\n\treturn 0; // todo\n}\n\nstatic uint32 getHID2(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"Get HID2 IP 0x%08x\\n\", hCPU->instructionPointer);\n\treturn 0; // todo\n}\n\nstatic void setHID2(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\t// todo\n\tdebug_printf(\"Set HID2 to 0x%08x\\n\", newValue);\n}\n\nstatic uint32 getHID4(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"Get HID4 IP 0x%08x\\n\", hCPU->instructionPointer);\n\treturn 0; // todo\n}\n\nstatic void setHID4(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\t// todo\n\tdebug_printf(\"Set HID4 to 0x%08x\\n\", newValue);\n}\n\nstatic uint32 getHID5(PPCInterpreter_t* hCPU)\n{\n\t// Wii-U only\n\tdebug_printf(\"Get HID5 IP 0x%08x\\n\", hCPU->instructionPointer);\n\treturn 0; // todo\n}\n\nstatic void setHID5(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\t// Wii-U only\n\t// todo\n\tdebug_printf(\"Set HID5 to 0x%08x\\n\", newValue);\n}\n\nstatic uint32 getSCR(PPCInterpreter_t* hCPU)\n{\n\t// WiiU mode only?\n\treturn 0; // todo\n}\n\nstatic void setSCR(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\tuint32 previousSCR = hCPU->global->sprGlobal.scr;\n\tnewValue |= (previousSCR&0x80000000); // this bit always sticks?\n\tif ((previousSCR&0x80000000) == 0 && (newValue & 0x80000000) != 0)\n\t{\n\t\t// this bit is used to disable bootrom mapping, but we use it to know when to copy the decrypted ancast image into kernel memory\n\t\tdebug_printf(\"SCR MSB set. Unmap bootrom?\\n\");\n\n\t\t//memcpy(memory_base + 0xFFE00000, memory_base + 0x08000000, 0x180000);\n\t\t// hack - clear low memory (where bootrom was mapped/loaded)\n\t\tmemset(memory_base, 0, 0x4000);\n\t\t//// todo - normally IOSU sets up some stuff here (probably)\n\t\t\n\t\t// for debugging purposes make lowest page read-only\n#ifdef _WIN32\n\t\tDWORD oldProtect;\n\t\tVirtualProtect(memory_base, 0x1000, PAGE_READONLY, &oldProtect);\n#endif\n\t}\n\tdebug_printf(\"Set SCR to 0x%08x\\n\", newValue);\n\thCPU->global->sprGlobal.scr = newValue;\n}\n\n// SCR probably has bits to control following:\n// disable bootrom (bit 0x80000000)\n// disable PPC OTP\n// bits to start the extra cores\n\nstatic uint32 getCAR(PPCInterpreter_t* hCPU)\n{\n\t// global\n\t// WiiU mode only\n\treturn 0; // todo\n}\n\nstatic void setCAR(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\t// global\n\t// WiiU mode only\n\tdebug_printf(\"Set CAR to 0x%08x\\n\", newValue);\n}\n\nstatic uint32 getBCR(PPCInterpreter_t* hCPU)\n{\n\t// global\n\t// WiiU mode only\n\treturn 0; // todo\n}\n\nstatic void setBCR(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\t// global\n\t// WiiU mode only\n\tdebug_printf(\"Set BCR to 0x%08x\\n\", newValue);\n}\n\n\nstatic uint32 getL2CR(PPCInterpreter_t* hCPU)\n{\n\treturn 0; // todo\n}\n\nstatic void setL2CR(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\t// todo\n}\n\nstatic void setSRR0(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\thCPU->sprExtended.srr0 = newValue;\n}\n\nstatic void setSRR1(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\thCPU->sprExtended.srr1 = newValue;\n}\n\nstatic void setDMAU(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\thCPU->sprExtended.dmaU = newValue;\n}\n\nstatic void setDMAL(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\thCPU->sprExtended.dmaL = newValue;\n\t// LC DMA\n\tif(newValue &0x2 )\n\t{\n\t\tuint32 transferLength = (((hCPU->sprExtended.dmaU>>0)&0x1F)<<2)|((newValue>>2)&3);\n\t\tuint32 memAddr = (hCPU->sprExtended.dmaU)&0xFFFFFFE0;\n\t\tuint32 cacheAddr = (newValue)&0xFFFFFFE0;\n\t\tif( transferLength == 0 )\n\t\t\ttransferLength = 128;\n\t\ttransferLength *= 32;\n\t\tbool isLoad = ((newValue>>4)&1)!=0;\n\t\tif( (cacheAddr>>28) != 0xE )\n\t\t{\n\t\t\tdebug_printf(\"LCTransfer: Not a cache address\\n\");\n\t\t\tcacheAddr = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcacheAddr -= 0xE0000000;\n\t\t}\n\t\tif( isLoad == 0 )\n\t\t{\n\t\t\t// locked cache -> memory\n\t\t\tdebug_printf(\"L2->MEM %08x -> %08x size: 0x%x\\n\", memAddr, 0xE0000000 + cacheAddr, transferLength);\n\t\t\tmemcpy(memory_getPointerFromVirtualOffset(memAddr), memory_base+0xE0000000+cacheAddr, transferLength);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// memory -> locked cache\n\t\t\tdebug_printf(\"MEM->L2 %08x -> %08x size: 0x%x\\n\", 0xE0000000 + cacheAddr, memAddr, transferLength);\n\t\t\tmemcpy(memory_base + 0xE0000000 + cacheAddr, memory_getPointerFromVirtualOffset(memAddr), transferLength);\n\t\t}\n\t\tnewValue &= ~2;\n\t\thCPU->sprExtended.dmaL = newValue;\n\t}\n}\n\nstatic void setDBATL(PPCInterpreter_t* hCPU, uint32 index, uint32 newValue)\n{\n\tdebug_printf(\"Set DBATL%d to 0x%08x\\n\", index, newValue);\n\thCPU->sprExtended.dbatL[index] = newValue;\n}\n\nstatic void setDBATU(PPCInterpreter_t* hCPU, uint32 index, uint32 newValue)\n{\n\tdebug_printf(\"Set DBATU%d to 0x%08x\\n\", index, newValue);\n\thCPU->sprExtended.dbatU[index] = newValue;\n}\n\nstatic void setIBATL(PPCInterpreter_t* hCPU, uint32 index, uint32 newValue)\n{\n\tdebug_printf(\"Set IBATL%d to 0x%08x\\n\", index, newValue);\n\thCPU->sprExtended.ibatL[index] = newValue;\n}\n\nstatic void setIBATU(PPCInterpreter_t* hCPU, uint32 index, uint32 newValue)\n{\n\tdebug_printf(\"Set IBATU%d to 0x%08x\\n\", index, newValue);\n\thCPU->sprExtended.ibatU[index] = newValue;\n}\n\nstatic uint32 getDBATL(PPCInterpreter_t* hCPU, uint32 index)\n{\n\treturn hCPU->sprExtended.dbatL[index];\n}\n\nstatic uint32 getDBATU(PPCInterpreter_t* hCPU, uint32 index)\n{\n\treturn hCPU->sprExtended.dbatU[index];\n}\n\nstatic uint32 getIBATL(PPCInterpreter_t* hCPU, uint32 index)\n{\n\treturn hCPU->sprExtended.ibatL[index];\n}\n\nstatic uint32 getIBATU(PPCInterpreter_t* hCPU, uint32 index)\n{\n\treturn hCPU->sprExtended.ibatU[index];\n}\n\nstatic void setSR(PPCInterpreter_t* hCPU, uint32 index, uint32 newValue)\n{\n\tdebug_printf(\"Set SR%d to 0x%08x IP %08x LR %08x\\n\", index, newValue, hCPU->instructionPointer, hCPU->spr.LR);\n\thCPU->sprExtended.sr[index] = newValue;\n}\n\nstatic uint32 getSR(PPCInterpreter_t* hCPU, uint32 index)\n{\n\treturn hCPU->sprExtended.sr[index];\n}\n\nstatic void setSDR1(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\tdebug_printf(\"Set SDR1 to 0x%08x\\n\", newValue);\n\thCPU->sprExtended.sdr1 = newValue;\n}\n\nstatic void setTBL(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\tif (newValue != 0)\n\t\tassert_dbg();\n\tdebug_printf(\"Reset TB\\n\");\n\thCPU->global->tb = 0;\n}\n\nstatic void setTBU(PPCInterpreter_t* hCPU, uint32 newValue)\n{\n\tif (newValue != 0)\n\t\tassert_dbg();\n\tdebug_printf(\"Reset TB\\n\");\n\thCPU->global->tb = 0;\n}\n\nstatic void PPCSprSupervisor_set(PPCInterpreter_t* hCPU, uint32 spr, uint32 newValue)\n{\n\tswitch (spr)\n\t{\n\tcase SPR_LR:\n\t\thCPU->spr.LR = newValue;\n\t\tbreak;\n\tcase SPR_CTR:\n\t\thCPU->spr.CTR = newValue;\n\t\tbreak;\n\tcase SPR_DEC:\n\t\tsetDEC(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_XER:\n\t\tPPCInterpreter_setXER(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_UGQR0:\n\tcase SPR_UGQR1:\n\tcase SPR_UGQR2:\n\tcase SPR_UGQR3:\n\tcase SPR_UGQR4:\n\tcase SPR_UGQR5:\n\tcase SPR_UGQR6:\n\tcase SPR_UGQR7:\n\t\thCPU->spr.UGQR[spr - SPR_UGQR0] = newValue;\n\t\tbreak;\n\t// values above are user mode accessible\n\tcase SPR_TBL_WRITE: // TBL\n\t\tsetTBL(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_TBU_WRITE: // TBU\n\t\tsetTBU(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_FPECR:\n\t\tsetFPECR(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_HID0:\n\t\tsetHID0(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_HID2:\n\t\tsetHID2(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_HID4:\n\t\tsetHID4(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_HID5:\n\t\tsetHID5(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_L2CR:\n\t\tsetL2CR(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_SRR0:\n\t\tsetSRR0(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_SRR1:\n\t\tsetSRR1(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_SPRG0:\n\t\tsetSPRG(hCPU, 0, newValue);\n\t\tbreak;\n\tcase SPR_SPRG1:\n\t\tsetSPRG(hCPU, 1, newValue);\n\t\tbreak;\n\tcase SPR_SPRG2:\n\t\tsetSPRG(hCPU, 2, newValue);\n\t\tbreak;\n\tcase SPR_SPRG3:\n\t\tsetSPRG(hCPU, 3, newValue);\n\t\tbreak;\n\tcase SPR_SCR:\n\t\tsetSCR(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_CAR:\n\t\tsetCAR(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_BCR:\n\t\tsetBCR(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_DMAU:\n\t\tsetDMAU(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_DMAL:\n\t\tsetDMAL(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_DBATU_0:\n\t\tsetDBATU(hCPU, 0, newValue);\n\t\tbreak;\n\tcase SPR_DBATU_1:\n\t\tsetDBATU(hCPU, 1, newValue);\n\t\tbreak;\n\tcase SPR_DBATU_2:\n\t\tsetDBATU(hCPU, 2, newValue);\n\t\tbreak;\n\tcase SPR_DBATU_3:\n\t\tsetDBATU(hCPU, 3, newValue);\n\t\tbreak;\n\tcase SPR_DBATU_4:\n\t\tsetDBATU(hCPU, 4, newValue);\n\t\tbreak;\n\tcase SPR_DBATU_5:\n\t\tsetDBATU(hCPU, 5, newValue);\n\t\tbreak;\n\tcase SPR_DBATU_6:\n\t\tsetDBATU(hCPU, 6, newValue);\n\t\tbreak;\n\tcase SPR_DBATU_7:\n\t\tsetDBATU(hCPU, 7, newValue);\n\t\tbreak;\n\tcase SPR_DBATL_0:\n\t\tsetDBATL(hCPU, 0, newValue);\n\t\tbreak;\n\tcase SPR_DBATL_1:\n\t\tsetDBATL(hCPU, 1, newValue);\n\t\tbreak;\n\tcase SPR_DBATL_2:\n\t\tsetDBATL(hCPU, 2, newValue);\n\t\tbreak;\n\tcase SPR_DBATL_3:\n\t\tsetDBATL(hCPU, 3, newValue);\n\t\tbreak;\n\tcase SPR_DBATL_4:\n\t\tsetDBATL(hCPU, 4, newValue);\n\t\tbreak;\n\tcase SPR_DBATL_5:\n\t\tsetDBATL(hCPU, 5, newValue);\n\t\tbreak;\n\tcase SPR_DBATL_6:\n\t\tsetDBATL(hCPU, 6, newValue);\n\t\tbreak;\n\tcase SPR_DBATL_7:\n\t\tsetDBATL(hCPU, 7, newValue);\n\t\tbreak;\n\tcase SPR_IBATU_0:\n\t\tsetIBATU(hCPU, 0, newValue);\n\t\tbreak;\n\tcase SPR_IBATU_1:\n\t\tsetIBATU(hCPU, 1, newValue);\n\t\tbreak;\n\tcase SPR_IBATU_2:\n\t\tsetIBATU(hCPU, 2, newValue);\n\t\tbreak;\n\tcase SPR_IBATU_3:\n\t\tsetIBATU(hCPU, 3, newValue);\n\t\tbreak;\n\tcase SPR_IBATU_4:\n\t\tsetIBATU(hCPU, 4, newValue);\n\t\tbreak;\n\tcase SPR_IBATU_5:\n\t\tsetIBATU(hCPU, 5, newValue);\n\t\tbreak;\n\tcase SPR_IBATU_6:\n\t\tsetIBATU(hCPU, 6, newValue);\n\t\tbreak;\n\tcase SPR_IBATU_7:\n\t\tsetIBATU(hCPU, 7, newValue);\n\t\tbreak;\n\tcase SPR_IBATL_0:\n\t\tsetIBATL(hCPU, 0, newValue);\n\t\tbreak;\n\tcase SPR_IBATL_1:\n\t\tsetIBATL(hCPU, 1, newValue);\n\t\tbreak;\n\tcase SPR_IBATL_2:\n\t\tsetIBATL(hCPU, 2, newValue);\n\t\tbreak;\n\tcase SPR_IBATL_3:\n\t\tsetIBATL(hCPU, 3, newValue);\n\t\tbreak;\n\tcase SPR_IBATL_4:\n\t\tsetIBATL(hCPU, 4, newValue);\n\t\tbreak;\n\tcase SPR_IBATL_5:\n\t\tsetIBATL(hCPU, 5, newValue);\n\t\tbreak;\n\tcase SPR_IBATL_6:\n\t\tsetIBATL(hCPU, 6, newValue);\n\t\tbreak;\n\tcase SPR_IBATL_7:\n\t\tsetIBATL(hCPU, 7, newValue);\n\t\tbreak;\n\tcase SPR_SDR1:\n\t\tsetSDR1(hCPU, newValue);\n\t\tbreak;\n\tcase 0x3B8: // mmcr0\n\t\tdebug_printf(\"Write performance monitor SPR mmcr0 0x%08x\", newValue);\n\t\tbreak;\n\tcase 0x3B9: // PMC1\n\t\tdebug_printf(\"Write performance monitor SPR PMC1 0x%08x\", newValue);\n\t\tbreak;\n\tcase 0x3BA: // PMC2\n\t\tdebug_printf(\"Write performance monitor SPR PMC2 0x%08x\", newValue);\n\t\tbreak;\n\tcase 0x3BC: // mmcr1\n\t\tdebug_printf(\"Write performance monitor SPR mmcr1 0x%08x\", newValue);\n\t\tbreak;\n\tcase 0x3BD: // PMC3\n\t\tdebug_printf(\"Write performance monitor SPR PMC3 0x%08x\", newValue);\n\t\tbreak;\n\tcase 0x3BE: // PMC4\n\t\tdebug_printf(\"Write performance monitor SPR PMC4 0x%08x\", newValue);\n\t\tbreak;\n\tdefault:\n\t\tdebug_printf(\"[C%d] Set unhandled SPR 0x%x to %08x (supervisor mode)\\n\", hCPU->spr.UPIR, spr, newValue);\n#ifdef CEMU_DEBUG_ASSERT\n\t\tassert_dbg();\n#endif\n\t\tbreak;\n\t}\n}\n\nstatic void PPCSpr_set(PPCInterpreter_t* hCPU, uint32 spr, uint32 newValue)\n{\n\tif constexpr(ppcItpCtrl::allowSupervisorMode)\n\t{\n\t\t// todo - check if in supervisor mode or user mode\n\t\tPPCSprSupervisor_set(hCPU, spr, newValue);\n\t\treturn;\n\t}\n\n\tswitch (spr)\n\t{\n\tcase SPR_LR:\n\t\thCPU->spr.LR = newValue;\n\t\tbreak;\n\tcase SPR_CTR:\n\t\thCPU->spr.CTR = newValue;\n\t\tbreak;\n\tcase SPR_XER:\n\t\tPPCInterpreter_setXER(hCPU, newValue);\n\t\tbreak;\n\tcase SPR_UGQR0:\n\tcase SPR_UGQR1:\n\tcase SPR_UGQR2:\n\tcase SPR_UGQR3:\n\tcase SPR_UGQR4:\n\tcase SPR_UGQR5:\n\tcase SPR_UGQR6:\n\tcase SPR_UGQR7:\n\t\thCPU->spr.UGQR[spr - SPR_UGQR0] = newValue;\n\t\tbreak;\n\tdefault:\n\t\tdebug_printf(\"[C%d] Set unhandled SPR %d to %08x\\n\", hCPU->spr.UPIR, spr, newValue);\n#ifdef CEMU_DEBUG_ASSERT\n\t\tassert_dbg();\n#endif\n\t\tbreak;\n\t}\n}\n\nstatic uint32 PPCSprSupervisor_get(PPCInterpreter_t* hCPU, uint32 spr)\n{\n\tuint32 v = 0;\n\tswitch (spr)\n\t{\n\tcase SPR_LR:\n\t\tv = hCPU->spr.LR;\n\t\tbreak;\n\tcase SPR_CTR:\n\t\tv = hCPU->spr.CTR;\n\t\tbreak;\n\tcase SPR_XER:\n\t\tv = PPCInterpreter_getXER(hCPU);\n\t\tbreak;\n\tcase SPR_UPIR:\n\t\tv = hCPU->spr.UPIR;\n\t\tbreak;\n\tcase SPR_UGQR0:\n\tcase SPR_UGQR1:\n\tcase SPR_UGQR2:\n\tcase SPR_UGQR3:\n\tcase SPR_UGQR4:\n\tcase SPR_UGQR5:\n\tcase SPR_UGQR6:\n\tcase SPR_UGQR7:\n\t\tv = hCPU->spr.UGQR[spr - SPR_UGQR0];\n\t\tbreak;\n\t// above are registers accessible in user mode\n\tcase SPR_PVR:\n\t\tv = getPVR(hCPU);\n\t\tbreak;\n\tcase SPR_HID0:\n\t\tv = getHID0(hCPU);\n\t\tbreak;\n\tcase SPR_HID1:\n\t\tv = getHID1(hCPU);\n\t\tbreak;\n\tcase SPR_HID2:\n\t\tv = getHID2(hCPU);\n\t\tbreak;\n\tcase SPR_HID4:\n\t\tv = getHID4(hCPU);\n\t\tbreak;\n\tcase SPR_HID5:\n\t\tv = getHID5(hCPU);\n\t\tbreak;\n\tcase SPR_SCR:\n\t\tv = getSCR(hCPU);\n\t\tbreak;\n\tcase SPR_CAR:\n\t\tv = getCAR(hCPU);\n\t\tbreak;\n\tcase SPR_BCR:\n\t\tv = getBCR(hCPU);\n\t\tbreak;\n\tcase SPR_DAR:\n\t\tv = getDAR(hCPU);\n\t\tbreak;\n\tcase SPR_DSISR:\n\t\tv = getDSISR(hCPU);\n\t\tbreak;\n\tcase SPR_L2CR:\n\t\tv = getL2CR(hCPU);\n\t\tbreak;\n\tcase SPR_FPECR:\n\t\tv = getFPECR(hCPU);\n\t\tbreak;\n\tcase SPR_SPRG0:\n\t\tv = getSPRG(hCPU, 0);\n\t\tbreak;\n\tcase SPR_SPRG1:\n\t\tv = getSPRG(hCPU, 1);\n\t\tbreak;\n\tcase SPR_SPRG2:\n\t\tv = getSPRG(hCPU, 2);\n\t\tbreak;\n\tcase SPR_SPRG3:\n\t\tv = getSPRG(hCPU, 3);\n\t\tbreak;\n\tcase SPR_DBATU_0:\n\t\tv = getDBATU(hCPU, 0);\n\t\tbreak;\n\tcase SPR_DBATU_1:\n\t\tv = getDBATU(hCPU, 1);\n\t\tbreak;\n\tcase SPR_DBATU_2:\n\t\tv = getDBATU(hCPU, 2);\n\t\tbreak;\n\tcase SPR_DBATU_3:\n\t\tv = getDBATU(hCPU, 3);\n\t\tbreak;\n\tcase SPR_DBATU_4:\n\t\tv = getDBATU(hCPU, 4);\n\t\tbreak;\n\tcase SPR_DBATU_5:\n\t\tv = getDBATU(hCPU, 5);\n\t\tbreak;\n\tcase SPR_DBATU_6:\n\t\tv = getDBATU(hCPU, 6);\n\t\tbreak;\n\tcase SPR_DBATU_7:\n\t\tv = getDBATU(hCPU, 7);\n\t\tbreak;\n\tcase SPR_DBATL_0:\n\t\tv = getDBATL(hCPU, 0);\n\t\tbreak;\n\tcase SPR_DBATL_1:\n\t\tv = getDBATL(hCPU, 1);\n\t\tbreak;\n\tcase SPR_DBATL_2:\n\t\tv = getDBATL(hCPU, 2);\n\t\tbreak;\n\tcase SPR_DBATL_3:\n\t\tv = getDBATL(hCPU, 3);\n\t\tbreak;\n\tcase SPR_DBATL_4:\n\t\tv = getDBATL(hCPU, 4);\n\t\tbreak;\n\tcase SPR_DBATL_5:\n\t\tv = getDBATL(hCPU, 5);\n\t\tbreak;\n\tcase SPR_DBATL_6:\n\t\tv = getDBATL(hCPU, 6);\n\t\tbreak;\n\tcase SPR_DBATL_7:\n\t\tv = getDBATL(hCPU, 7);\n\t\tbreak;\n\tcase SPR_IBATU_0:\n\t\tv = getIBATU(hCPU, 0);\n\t\tbreak;\n\tcase SPR_IBATU_1:\n\t\tv = getIBATU(hCPU, 1);\n\t\tbreak;\n\tcase SPR_IBATU_2:\n\t\tv = getIBATU(hCPU, 2);\n\t\tbreak;\n\tcase SPR_IBATU_3:\n\t\tv = getIBATU(hCPU, 3);\n\t\tbreak;\n\tcase SPR_IBATU_4:\n\t\tv = getIBATU(hCPU, 4);\n\t\tbreak;\n\tcase SPR_IBATU_5:\n\t\tv = getIBATU(hCPU, 5);\n\t\tbreak;\n\tcase SPR_IBATU_6:\n\t\tv = getIBATU(hCPU, 6);\n\t\tbreak;\n\tcase SPR_IBATU_7:\n\t\tv = getIBATU(hCPU, 7);\n\t\tbreak;\n\tcase SPR_IBATL_0:\n\t\tv = getIBATL(hCPU, 0);\n\t\tbreak;\n\tcase SPR_IBATL_1:\n\t\tv = getIBATL(hCPU, 1);\n\t\tbreak;\n\tcase SPR_IBATL_2:\n\t\tv = getIBATL(hCPU, 2);\n\t\tbreak;\n\tcase SPR_IBATL_3:\n\t\tv = getIBATL(hCPU, 3);\n\t\tbreak;\n\tcase SPR_IBATL_4:\n\t\tv = getIBATL(hCPU, 4);\n\t\tbreak;\n\tcase SPR_IBATL_5:\n\t\tv = getIBATL(hCPU, 5);\n\t\tbreak;\n\tcase SPR_IBATL_6:\n\t\tv = getIBATL(hCPU, 6);\n\t\tbreak;\n\tcase SPR_IBATL_7:\n\t\tv = getIBATL(hCPU, 7);\n\t\tbreak;\n\tdefault:\n\t\tdebug_printf(\"[C%d] Get unhandled SPR %d\\n\", hCPU->spr.UPIR, spr);\n#ifdef CEMU_DEBUG_ASSERT\n\t\tassert_dbg();\n#endif\n\t\tbreak;\n\t}\n\treturn v;\n}\n\nstatic uint32 PPCSpr_get(PPCInterpreter_t* hCPU, uint32 spr)\n{\n\tif constexpr(ppcItpCtrl::allowSupervisorMode)\n\t{\n\t\t// todo - check if in supervisor mode or user mode\n\t\treturn PPCSprSupervisor_get(hCPU, spr);\n\t}\n\n\tuint32 v = 0;\n\tswitch (spr)\n\t{\n\tcase SPR_LR:\n\t\tv = hCPU->spr.LR;\n\t\tbreak;\n\tcase SPR_CTR:\n\t\tv = hCPU->spr.CTR;\n\t\tbreak;\n\tcase SPR_XER:\n\t\tv = PPCInterpreter_getXER(hCPU);\n\t\tbreak;\n\tcase SPR_DEC:\n\t\t// special handling for DEC register\n\t{\n\t\tassert_dbg();\n\t\tuint64 passedCycled = PPCInterpreter_getMainCoreCycleCounter() - ppcMainThreadDECCycleStart;\n\t\tif (passedCycled >= (uint64)ppcMainThreadDECCycleValue)\n\t\t\tv = 0;\n\t\telse\n\t\t\tv = (uint32)(ppcMainThreadDECCycleValue - passedCycled);\n\t}\n\tbreak;\n\tcase SPR_UPIR:\n\t\tv = hCPU->spr.UPIR;\n\t\tbreak;\n\tcase SPR_PVR:\n\t\tassert_dbg();\n\t\t//v = hCPU->sprNew.PVR;\n\t\tbreak;\n\tcase SPR_UGQR0:\n\tcase SPR_UGQR1:\n\tcase SPR_UGQR2:\n\tcase SPR_UGQR3:\n\tcase SPR_UGQR4:\n\tcase SPR_UGQR5:\n\tcase SPR_UGQR6:\n\tcase SPR_UGQR7:\n\t\tv = hCPU->spr.UGQR[spr - SPR_UGQR0];\n\t\tbreak;\n\tdefault:\n\t\tdebug_printf(\"[C%d] Get unhandled SPR %d\\n\", hCPU->spr.UPIR, spr);\n#ifdef CEMU_DEBUG_ASSERT\n\t\tassert_dbg();\n#endif\n\t\tbreak;\n\t}\n\n\n\n\t//if( spr == SPR_LR || spr == SPR_PVR || spr == SPR_UPIR || spr == SPR_SCR || (spr >= SPR_UGQR0 && spr <= SPR_UGQR7) )\n\t//{\n\t//\t// readable registers\n\t//\tv = hCPU->spr[spr];\n\t//}\n\t//else if( spr == SPR_DEC )\n\t//{\n\t//\t// special handling for DEC register\n\t//\tuint64 passedCycled = PPCInterpreter_getMainCoreCycleCounter() - ppcMainThreadDECCycleStart;\n\t//\tif( passedCycled >= (uint64)ppcMainThreadDECCycleValue )\n\t//\t\tv = 0;\n\t//\telse\n\t//\t\tv = ppcMainThreadDECCycleValue - passedCycled;\n\t//}\n\t//else if( spr == SPR_XER )\n\t//{\n\t//\tv = PPCInterpreter_getXER(hCPU);\n\t//}\n\t//else\n\t//{\n\t//\tdebug_printf(\"[C%d] Get unhandled SPR %d value: %08x\\n\", hCPU->spr[SPR_UPIR], spr, hCPU->spr[spr]);\n\t//\tv = hCPU->spr[spr];\n\t//}\n\treturn v;\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/PPCCallback.h",
    "content": "#pragma once\n#include \"PPCState.h\"\n\nstruct PPCCoreCallbackData_t\n{\n\tsint32 gprCount = 0;\n\tsint32 floatCount = 0;\n\tsint32 stackCount = 0;\n};\n\ninline void _PPCCoreCallback_writeGPRArg(PPCCoreCallbackData_t& data, PPCInterpreter_t* hCPU, uint32 value)\n{\n\tif (data.gprCount < 8)\n\t{\n\t\thCPU->gpr[3 + data.gprCount] = value;\n\t\tdata.gprCount++;\n\t}\n\telse\n\t{\n\t\tuint32 stackOffset = 8 + data.stackCount * 4;\n\n\t\t// PPCCore_executeCallbackInternal does -16*4 to save the current stack area\n\t\tstackOffset -= 16 * 4;\n\n\t\tmemory_writeU32(hCPU->gpr[1] + stackOffset, value);\n\t\tdata.stackCount++;\n\t}\n}\n\n// callback functions\ninline uint32 PPCCoreCallback(MPTR function, const PPCCoreCallbackData_t& data)\n{\n\treturn PPCCore_executeCallbackInternal(function)->gpr[3];\n}\n\ntemplate <typename T, typename... TArgs>\nuint32 PPCCoreCallback(MPTR function, PPCCoreCallbackData_t& data, T currentArg, TArgs... args)\n{\n\t// TODO float arguments on stack\n\tcemu_assert_debug(data.floatCount < 8);\n\n\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\tif constexpr (std::is_pointer_v<T>)\n\t{\n\t\t_PPCCoreCallback_writeGPRArg(data, hCPU, MEMPTR(currentArg).GetMPTR());\n\t}\n\telse if constexpr (std::is_base_of_v<MEMPTRBase, std::remove_reference_t<T>>)\n\t{\n\t\t_PPCCoreCallback_writeGPRArg(data, hCPU, currentArg.GetMPTR());\n\t}\n\telse if constexpr (std::is_reference_v<T>)\n\t{\n\t\t_PPCCoreCallback_writeGPRArg(data, hCPU, MEMPTR(&currentArg).GetMPTR());\n\t}\n\telse if constexpr(std::is_enum_v<T>)\n\t{\n\t\tusing TEnum = typename std::underlying_type<T>::type;\n\t\treturn PPCCoreCallback<TEnum>(function, data, (TEnum)currentArg, std::forward<TArgs>(args)...);\n\t}\n\telse if constexpr (std::is_floating_point_v<T>)\n\t{\n\t\thCPU->fpr[1 + data.floatCount].fpr = (double)currentArg;\n\t\tdata.floatCount++;\n\t}\n\telse if constexpr (std::is_integral_v<T> && sizeof(T) == sizeof(uint64))\n\t{\n\t\thCPU->gpr[3 + data.gprCount] = (uint32)(currentArg >> 32); // high\n\t\thCPU->gpr[3 + data.gprCount + 1] = (uint32)currentArg; // low\n\n\t\tdata.gprCount += 2;\n\t}\n\telse\n\t{\n\t\t_PPCCoreCallback_writeGPRArg(data, hCPU, (uint32)currentArg);\n\t}\n\t\n\treturn PPCCoreCallback(function, data, args...);\n}\n\ntemplate <typename... TArgs>\nuint32 PPCCoreCallback(MPTR function, TArgs... args)\n{\n\tPPCCoreCallbackData_t data{};\n\treturn PPCCoreCallback(function, data, std::forward<TArgs>(args)...);\n}\n\ntemplate <typename... TArgs>\nuint32 PPCCoreCallback(void* functionPtr, TArgs... args)\n{\n\tMEMPTR<void> _tmp{ functionPtr };\n\tPPCCoreCallbackData_t data{};\n\treturn PPCCoreCallback(_tmp.GetMPTR(), data, std::forward<TArgs>(args)...);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/PPCScheduler.cpp",
    "content": "#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n#include \"Cafe/CafeSystem.h\"\n\nuint32 ppcThreadQuantum = 45000; // execute 45000 instructions before thread reschedule happens, this value can be overwritten by game profiles\n\nvoid PPCInterpreter_relinquishTimeslice()\n{\n\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\tif( hCPU->remainingCycles >= 0 )\n\t{\n\t\thCPU->skippedCycles = hCPU->remainingCycles + 1;\n\t\thCPU->remainingCycles = -1;\n\t}\n}\n\nvoid PPCCore_boostQuantum(sint32 numCycles)\n{\n\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\thCPU->remainingCycles += numCycles;\n}\n\nvoid PPCCore_deboostQuantum(sint32 numCycles)\n{\n\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\thCPU->remainingCycles -= numCycles;\n}\n\nnamespace coreinit\n{\n\tvoid __OSThreadSwitchToNext();\n}\n\nvoid PPCCore_switchToScheduler()\n{\n\tcemu_assert_debug(__OSHasSchedulerLock() == false); // scheduler lock must not be hold past thread time slice\n\tcemu_assert_debug(PPCInterpreter_getCurrentInstance()->coreInterruptMask != 0 || CafeSystem::GetForegroundTitleId() == 0x000500001019e600);\n\t__OSLockScheduler();\n\tcoreinit::__OSThreadSwitchToNext();\n\t__OSUnlockScheduler();\n}\n\nvoid PPCCore_switchToSchedulerWithLock()\n{\n\tcemu_assert_debug(__OSHasSchedulerLock() == true); // scheduler lock must be hold\n\tcemu_assert_debug(PPCInterpreter_getCurrentInstance()->coreInterruptMask != 0 || CafeSystem::GetForegroundTitleId() == 0x000500001019e600);\n\tcoreinit::__OSThreadSwitchToNext();\n}\n\nvoid _PPCCore_callbackExit(PPCInterpreter_t* hCPU)\n{\n\tPPCInterpreter_relinquishTimeslice();\n\thCPU->instructionPointer = 0;\n}\n\nPPCInterpreter_t* PPCCore_executeCallbackInternal(uint32 functionMPTR)\n{\n\tcemu_assert_debug(functionMPTR != 0);\n\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\t// remember LR and instruction pointer\n\tuint32 lr = hCPU->spr.LR;\n\tuint32 ip = hCPU->instructionPointer;\n\t// save area\n\thCPU->gpr[1] -= 16 * 4;\n\t// set LR\n\thCPU->spr.LR = PPCInterpreter_makeCallableExportDepr(_PPCCore_callbackExit);\n\t// set instruction pointer\n\thCPU->instructionPointer = functionMPTR;\n\t// execute code until we return from the function\n\twhile (true)\n\t{\n\t\thCPU->remainingCycles = ppcThreadQuantum;\n\t\thCPU->skippedCycles = 0;\n\t\tif (hCPU->remainingCycles > 0)\n\t\t{\n\t\t\t// try to enter recompiler immediately\n\t\t\tPPCRecompiler_attemptEnter(hCPU, hCPU->instructionPointer);\n\t\t\t// execute any remaining instructions in interpreter\n\t\t\twhile ((--hCPU->remainingCycles) >= 0)\n\t\t\t{\n\t\t\t\tPPCInterpreterSlim_executeInstruction(hCPU);\n\t\t\t};\n\t\t}\n\t\tif (hCPU->instructionPointer == 0)\n\t\t{\n\t\t\t// restore remaining cycles\n\t\t\thCPU->remainingCycles += hCPU->skippedCycles;\n\t\t\thCPU->skippedCycles = 0;\n\t\t\tbreak;\n\t\t}\n\t\tcoreinit::OSYieldThread();\n\t}\n\t// save area\n\thCPU->gpr[1] += 16 * 4;\n\t// restore LR and instruction pointer\n\thCPU->spr.LR = lr;\n\thCPU->instructionPointer = ip;\n\treturn hCPU;\n}\n\nvoid PPCCore_init()\n{\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/PPCSchedulerLLE.cpp",
    "content": "\nstruct PPCInterpreterLLEContext_t\n{\n\tuint8 padding[1024 * 128]; // reserved memory for stack (for recompiler mode)\n\tPPCInterpreter_t cores[3];\n};\n\nPPCInterpreterGlobal_t globalCPUState = { 0 };\n\nvoid PPCCoreLLE_initCore(PPCInterpreter_t* hCPU, uint32 coreIndex)\n{\n\thCPU->spr.UPIR = coreIndex;\n\thCPU->global = &globalCPUState;\n}\n\n#define SCR_C2\t\t(0x200000) // enable core 2\n#define SCR_C1\t\t(0x400000) // enable core 1\n\ntypedef struct  \n{\n\tuint32be ukn000;\n\tuint32be ukn004;\n\tuint32be ukn008;\n\tuint32be ukn00C;\n\tuint32be ukn010;\n\tuint32be ukn014;\n\tuint32be busFreq;\n\tuint32be ukn01C;\n\tuint32be ukn020[4];\n\tuint32be ukn030[4];\n\tuint32be ukn040[4];\n\tuint32be ukn050[4];\n\tuint32be ukn060[4];\n\tuint32be ukn070[4];\n\tuint32be ukn080[4];\n\tuint32be ukn090[4];\n\tuint32be ukn0A0[4];\n\tuint32be ukn0B0[4];\n\tuint32be ukn0C0;\n\tstruct  \n\t{\n\t\tuint32be id;\n\t\tuint32be baseAddress;\n\t\tuint32be size;\n\t}ramInfo[3];\n\tuint32 ukn0E8;\n\tuint32 ukn0EC;\n\tuint32 ukn0F0[4];\n\tuint32 ukn100[8];\n\tuint32 ukn120[8];\n\tuint32 ukn140[8];\n\tuint32 ukn160[8];\n\tuint32 ukn180[8];\n\tuint32 ukn1A0[8];\n\tuint32 ukn1C0[8];\n\tuint32 ukn1E0[8];\n\tuint32 ukn200[8];\n\tuint32 ukn220[8];\n\tuint32 ukn240[8];\n\tuint32 ukn260[8];\n\tuint32 ukn280[8];\n\tuint32 ukn2A0[8];\n\tuint32 ukn2C0[8];\n\tuint32 ukn2E0[8];\n\tuint32 ukn300[8];\n\tuint32 ukn320[8];\n\tuint32 ukn340[8];\n\tuint32 ukn360[8];\n\tuint32 ukn380[8];\n\tuint32be ukn3A0;\n\tuint32be ukn3A4;\n\tuint32be ukn3A8;\n\tuint32be ukn3AC;\n\tuint32be ukn3B0;\n\tuint32be smdpAreaPtr;\n\tuint32be ukn3B8;\n\tuint32be ukn3BC;\n\tuint32 ukn3C0[8];\n\tuint32 ukn3E0[8];\n\tuint32 ukn400;\n\tuint32 ukn404;\n\tuint32 ukn408;\n}ppcBootParamBlock_t; // for kernel 5.5.2\n\nstatic_assert(offsetof(ppcBootParamBlock_t, ramInfo) == 0xC4, \"\");\nstatic_assert(offsetof(ppcBootParamBlock_t, busFreq) == 0x18, \"\");\nstatic_assert(offsetof(ppcBootParamBlock_t, smdpAreaPtr) == 0x3B4, \"\");\nstatic_assert(offsetof(ppcBootParamBlock_t, ukn400) == 0x400, \"\");\n\nvoid PPCCoreLLE_setupBootParamBlock()\n{\n\tppcBootParamBlock_t* bootParamBlock = (ppcBootParamBlock_t*)memory_getPointerFromPhysicalOffset(0x01FFF000);\n\tmemset(bootParamBlock, 0, sizeof(ppcBootParamBlock_t));\n\n\t// setup RAM info\n\t//PPCBaseAddress\t0x8000000\t0x00000000\t0x28000000\n\t//PPCSize\t\t\t0x120000\t0x2000000\t0xA8000000\n\n\tbootParamBlock->ukn004 = 0x40C;\n\n\tbootParamBlock->busFreq = ESPRESSO_BUS_CLOCK;\n\n\tbootParamBlock->ramInfo[0].id = 0;\n\tbootParamBlock->ramInfo[0].baseAddress = 0x8000000;\n\tbootParamBlock->ramInfo[0].size = 0x120000;\n\tbootParamBlock->ramInfo[1].id = 1;\n\tbootParamBlock->ramInfo[1].baseAddress = 0x00000000;\n\tbootParamBlock->ramInfo[1].size = 0x2000000;\n\tbootParamBlock->ramInfo[2].id = 2;\n\tbootParamBlock->ramInfo[2].baseAddress = 0x28000000;\n\tbootParamBlock->ramInfo[2].size = 0xA8000000;\n\n}\ntypedef struct\n{\n\tuint32be magic;\n\tuint32be count;\n\tuint32 _padding08[14];\n\t/* +0x0040 */ uint32be commandsReadIndex; // written by IOSU\n\tuint32 _padding44[15];\n\t/* +0x0080 */ uint32be commandsWriteIndex;\n\tuint32 _padding84[15];\n\t/* +0x00C0 */ uint32be resultsReadIndex;\n\tuint32 _paddingC4[15];\n\t/* +0x0100 */ uint32be resultsWriteIndex; // written by IOSU\n\tuint32 _padding104[15];\n\t/* +0x0140 */ uint32be commandPtrs[0xC00];\n\t/* +0x3140 */ uint32be resultPtrs[0xC00];\n}smdpArea_t;\n\nstatic_assert(offsetof(smdpArea_t, commandsReadIndex) == 0x0040, \"\");\nstatic_assert(offsetof(smdpArea_t, commandsWriteIndex) == 0x0080, \"\");\nstatic_assert(offsetof(smdpArea_t, resultsReadIndex) == 0x00C0, \"\");\nstatic_assert(offsetof(smdpArea_t, resultsWriteIndex) == 0x0100, \"\");\nstatic_assert(offsetof(smdpArea_t, resultPtrs) == 0x3140, \"\");\n\ntypedef struct  \n{\n\tuint32be type;\n\tuint32be ukn04;\n\tuint32be ukn08;\n\tuint32be ukn0C;\n\tuint32be ukn10;\n\tuint32be ukn14;\n\tuint32be ukn18;\n\tuint32be ukn1C;\n\tuint32be ukn20;\n\tuint32be ukn24;\n\tuint32be ukn28;\n\tuint32be ukn2C;\n}smdpCommand_t;\n\nvoid smdpArea_pushResult(smdpArea_t* smdpArea, MPTR result)\n{\n\t//smdpArea.\n\tsmdpArea->resultPtrs[(uint32)smdpArea->resultsWriteIndex] = result;\n\tsmdpArea->resultsWriteIndex = ((uint32)smdpArea->resultsWriteIndex + 1)%(uint32)smdpArea->count;\n}\n\nvoid smdpArea_processCommand(smdpArea_t* smdpArea, smdpCommand_t* cmd)\n{\n\tif (cmd->type == 1)\n\t{\n\t\tcmd->ukn08 = 1;\n\t\t// cmd->ukn2C ?\n\t\tcemuLog_logDebug(LogType::Force, \"SMDP command received - todo\");\n\t\tsmdpArea_pushResult(smdpArea, memory_getVirtualOffsetFromPointer(cmd));\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid smdpArea_thread()\n{\n\twhile (true)\n\t{\n\t\tppcBootParamBlock_t* bootParamBlock = (ppcBootParamBlock_t*)memory_getPointerFromPhysicalOffset(0x01FFF000);\n\t\tif(bootParamBlock->smdpAreaPtr != MPTR_NULL)\t\n\t\t{ \n\t\t\tsmdpArea_t* smdpArea = (smdpArea_t*)memory_getPointerFromPhysicalOffset(bootParamBlock->smdpAreaPtr);\n\t\t\tif (smdpArea->magic == 'smdp')\n\t\t\t{\n\t\t\t\tuint32 cmdReadIndex = smdpArea->commandsReadIndex;\n\t\t\t\tuint32 cmdWriteIndex = smdpArea->commandsWriteIndex;\n\t\t\t\tif (cmdReadIndex != cmdWriteIndex)\n\t\t\t\t{\n\t\t\t\t\t// new command\n\t\t\t\t\tsmdpArea_processCommand(smdpArea, (smdpCommand_t*)memory_getPointerFromPhysicalOffset(smdpArea->commandPtrs[cmdReadIndex]));\n\t\t\t\t\t// increment read counter\n\t\t\t\t\tcmdReadIndex = (cmdReadIndex + 1) % (uint32)smdpArea->count;\n\t\t\t\t\tsmdpArea->commandsReadIndex = cmdReadIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n        std::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t}\n}\n\nvoid PPCCoreLLE_startSingleCoreScheduler(uint32 entrypoint)\n{\n\tPPCInterpreterLLEContext_t* cpuContext = (PPCInterpreterLLEContext_t*)malloc(sizeof(PPCInterpreterLLEContext_t));\n\tmemset(cpuContext, 0, sizeof(PPCInterpreterLLEContext_t));\n\n\tPPCCoreLLE_setupBootParamBlock();\n\n\tPPCCoreLLE_initCore(cpuContext->cores + 0, 0);\n\tPPCCoreLLE_initCore(cpuContext->cores + 1, 1);\n\tPPCCoreLLE_initCore(cpuContext->cores + 2, 2);\n\t\n\tcpuContext->cores[0].instructionPointer = entrypoint;\n\tcpuContext->cores[1].instructionPointer = 0xFFF00100;\n\tcpuContext->cores[2].instructionPointer = 0xFFF00100;\n\t// todo - calculate instruction pointer when core 1/2 is enabled (because entry point is determined by MSR exception vector bit)\n\tstd::thread(smdpArea_thread).detach();\n\n\twhile (true)\n\t{\n\t\tfor (uint32 coreIndex = 0; coreIndex < 3; coreIndex++)\n\t\t{\n\t\t\tPPCInterpreter_t* hCPU = cpuContext->cores+coreIndex;\n\t\t\tPPCInterpreter_setCurrentInstance(hCPU);\n\t\t\tif (coreIndex == 1)\n\t\t\t{\n\t\t\t\t// check SCR core 1 enable bit\n\t\t\t\tif ((globalCPUState.sprGlobal.scr&SCR_C1) == 0)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (coreIndex == 2)\n\t\t\t{\n\t\t\t\t// check SCR core 2 enable bit\n\t\t\t\tif ((globalCPUState.sprGlobal.scr&SCR_C2) == 0)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\thCPU->remainingCycles = 10000;\n\t\t\twhile ((--hCPU->remainingCycles) >= 0)\n\t\t\t{\n\t\t\t\tPPCInterpreterFull_executeInstruction(hCPU);\n\t\t\t};\n\t\t}\n\t}\n\tassert_dbg();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/PPCState.h",
    "content": "#pragma once\n#include \"Cafe/HW/MMU/MMU.h\"\n\nenum\n{\n\tCPUException_NOTHING,\n\tCPUException_FPUUNAVAILABLE,\n\tCPUException_EXTERNAL,\n\tCPUException_SYSTEMCALL\n};\n\n#define PPC_LWARX_RESERVATION_MAX\t(4)\n\nunion FPR_t\n{\n\tdouble fpr;\n\tstruct\n\t{\n\t\tdouble fp0;\n\t\tdouble fp1;\n\t};\n\tstruct\n\t{\n\t\tuint64 guint; \n\t};\n\tstruct\n\t{\n\t\tuint64 fp0int;\n\t\tuint64 fp1int;\n\t};\n};\n\ntypedef struct  \n{\n\tstruct  \n\t{\n\t\tuint32 scr;\n\t\tuint32 car;\n\t\t//uint32 bcr;\n\t}sprGlobal;\n\tuint64 tb;\n}PPCInterpreterGlobal_t;\n\nstruct PPCInterpreter_t\n{\n\tuint32 instructionPointer;\n\tuint32 gpr[32];\n\tFPR_t fpr[32];\n\tuint32 fpscr;\n\tuint8 cr[32]; // 0 -> bit not set, 1 -> bit set (upper 7 bits of each byte must always be zero) (cr0 starts at index 0, cr1 at index 4 ..)\n\tuint8 xer_ca;  // carry from xer\n\tuint8 xer_so;\n\tuint8 xer_ov;\n\t// thread remaining cycles\n\tsint32 remainingCycles; // if this value goes below zero, the next thread is scheduled\n\tsint32 skippedCycles; // number of skipped cycles\n\tstruct\n\t{\n\t\tuint32 LR;\n\t\tuint32 CTR;\n\t\tuint32 XER;\n\t\tuint32 UPIR;\n\t\tuint32 UGQR[8];\n\t}spr;\n\t// LWARX and STWCX\n\tuint32 reservedMemAddr;\n\tuint32 reservedMemValue;\n\t// temporary storage for recompiler\n\tFPR_t temporaryFPR[8];\n\tuint32 temporaryGPR[4]; // deprecated, refactor backend dependency on this away\n\tuint32 temporaryGPR_reg[4];\n\t// values below this are not used by Cafe OS usermode\n\tstruct\n\t{\n\t\tuint32 fpecr; // is this the same register as fpscr ?\n\t\tuint32 DEC;\n\t\tuint32 srr0;\n\t\tuint32 srr1;\n\t\tuint32 PVR;\n\t\tuint32 msr;\n\t\tuint32 sprg[4];\n\t\t// DSI/ISI\n\t\tuint32 dar;\n\t\tuint32 dsisr;\n\t\t// DMA\n\t\tuint32 dmaU;\n\t\tuint32 dmaL;\n\t\t// MMU\n\t\tuint32 dbatU[8];\n\t\tuint32 dbatL[8];\n\t\tuint32 ibatU[8];\n\t\tuint32 ibatL[8];\n\t\tuint32 sr[16];\n\t\tuint32 sdr1;\n\t}sprExtended;\n\tuint8 LSQE;\n\tuint8 PSE;\n\t// global CPU values\n\tPPCInterpreterGlobal_t* global;\n\t// interpreter control\n\tbool memoryException;\n\t// core context (starts at 0xFFFFFF00?)\n\t/* 0xFFFFFFE4 */ uint32 coreInterruptMask;\n\n\t// extra variables for recompiler\n\tvoid* rspTemp;\n};\n\n// parameter access (legacy C style)\n\nstatic uint32 PPCInterpreter_getCallParamU32(PPCInterpreter_t* hCPU, uint32 index)\n{\n\tif (index >= 8)\n\t\treturn memory_readU32(hCPU->gpr[1] + 8 + (index - 8) * 4);\n\treturn hCPU->gpr[3 + index];\n}\n\nstatic uint64 PPCInterpreter_getCallParamU64(PPCInterpreter_t* hCPU, uint32 index)\n{\n\tuint64 v = ((uint64)PPCInterpreter_getCallParamU32(hCPU, index)) << 32ULL;\n\tv |= ((uint64)PPCInterpreter_getCallParamU32(hCPU, index+1));\n\treturn v;\n}\n\n#define ppcGetCallParamU32(__index) PPCInterpreter_getCallParamU32(hCPU, __index)\n#define ppcGetCallParamU16(__index) ((uint16)(PPCInterpreter_getCallParamU32(hCPU, __index)&0xFFFF))\n#define ppcGetCallParamU8(__index) ((uint8)(PPCInterpreter_getCallParamU32(hCPU, __index)&0xFF))\n#define ppcGetCallParamStruct(__index, __type) ((__type*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))\n\n// legacy way of accessing parameters\n#define ppcDefineParamU32(__name, __index) uint32 __name = PPCInterpreter_getCallParamU32(hCPU, __index)\n#define ppcDefineParamU16(__name, __index) uint16 __name = (uint16)PPCInterpreter_getCallParamU32(hCPU, __index)\n#define ppcDefineParamU32BEPtr(__name, __index) uint32be* __name = (uint32be*)((uint8*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))\n#define ppcDefineParamS32(__name, __index) sint32 __name = (sint32)PPCInterpreter_getCallParamU32(hCPU, __index)\n#define ppcDefineParamU64(__name, __index) uint64 __name = PPCInterpreter_getCallParamU64(hCPU, __index)\n#define ppcDefineParamMPTR(__name, __index) MPTR __name = (MPTR)PPCInterpreter_getCallParamU32(hCPU, __index)\n#define ppcDefineParamMEMPTR(__name, __type, __index) MEMPTR<__type> __name{PPCInterpreter_getCallParamU32(hCPU, __index)}\n#define ppcDefineParamU8(__name, __index) uint8 __name = (PPCInterpreter_getCallParamU32(hCPU, __index)&0xFF)\n#define ppcDefineParamStructPtr(__name, __type, __index) __type* __name = ((__type*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))\n#define ppcDefineParamTypePtr(__name, __type, __index) __type* __name = ((__type*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))\n#define ppcDefineParamPtr(__name, __type, __index) __type* __name = ((__type*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))\n#define ppcDefineParamStr(__name, __index) char* __name = ((char*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))\n#define ppcDefineParamUStr(__name, __index) uint8* __name = ((uint8*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))\n#define ppcDefineParamWStr(__name, __index) wchar_t* __name = ((wchar_t*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))\n#define ppcDefineParamWStrBE(__name, __index) uint16be* __name = ((uint16be*)memory_getPointerFromVirtualOffsetAllowNull(PPCInterpreter_getCallParamU32(hCPU, __index)))\n\n// GPR constants\n\n#define GPR_SP 1\n\n// interpreter functions\n\nPPCInterpreter_t* PPCInterpreter_createInstance(unsigned int Entrypoint);\nPPCInterpreter_t* PPCInterpreter_getCurrentInstance();\nvoid PPCInterpreter_setCurrentInstance(PPCInterpreter_t* hCPU);\n\nuint64 PPCInterpreter_getMainCoreCycleCounter();\n\nvoid PPCInterpreter_nextInstruction(PPCInterpreter_t* cpuInterpreter);\nvoid PPCInterpreter_jumpToInstruction(PPCInterpreter_t* cpuInterpreter, uint32 newIP);\n\nvoid PPCInterpreterSlim_executeInstruction(PPCInterpreter_t* hCPU);\nvoid PPCInterpreterFull_executeInstruction(PPCInterpreter_t* hCPU);\n\n// misc\n\nuint32 PPCInterpreter_getXER(PPCInterpreter_t* hCPU);\nvoid PPCInterpreter_setXER(PPCInterpreter_t* hCPU, uint32 v);\n\n// Wii U clocks (deprecated. Moved to Espresso/Const.h)\n#define ESPRESSO_CORE_CLOCK       1243125000\n#define ESPRESSO_BUS_CLOCK        248625000\n#define ESPRESSO_TIMER_CLOCK      (ESPRESSO_BUS_CLOCK/4) // 62156250\n\n#define ESPRESSO_CORE_CLOCK_TO_TIMER_CLOCK(__cc) ((__cc)/20ULL)\n\n// interrupt vectors\n#define CPU_EXCEPTION_DSI\t\t\t0x00000300\n#define CPU_EXCEPTION_INTERRUPT\t\t0x00000500 // todo: validate\n#define CPU_EXCEPTION_FPUUNAVAIL\t0x00000800 // todo: validate\n#define CPU_EXCEPTION_SYSTEMCALL\t0x00000C00 // todo: validate\n#define CPU_EXCEPTION_DECREMENTER\t0x00000900 // todo: validate\n\n// FPU available check\n//#define FPUCheckAvailable() if ((hCPU->msr & MSR_FP) == 0) { IPTException(hCPU, CPU_EXCEPTION_FPUUNAVAIL); return; }\n#define FPUCheckAvailable() // since the emulated code always runs in usermode we can assume that MSR_FP is always set\n\n// spr\nvoid PPCSpr_set(PPCInterpreter_t* hCPU, uint32 spr, uint32 newValue);\nuint32 PPCSpr_get(PPCInterpreter_t* hCPU, uint32 spr);\n\nuint32 PPCInterpreter_getCoreIndex(PPCInterpreter_t* hCPU);\nuint32 PPCInterpreter_getCurrentCoreIndex();\n\n// decrement register\nvoid PPCInterpreter_setDEC(PPCInterpreter_t* hCPU, uint32 newValue);\n\n// timing for main processor\nextern uint64 ppcCyclesSince2000; // on init this is set to the cycles that passed since 1.1.2000\nextern uint64 ppcCyclesSince2000TimerClock; // on init this is set to the cycles that passed since 1.1.2000 / 20\nextern uint64 ppcCyclesSince2000_UTC;\nextern uint64 ppcMainThreadDECCycleValue; // value that was set to dec register\nextern uint64 ppcMainThreadDECCycleStart; // at which cycle the dec register was set\n\n// PPC timer\nvoid PPCTimer_init();\nvoid PPCTimer_waitForInit();\nuint64 PPCTimer_getFromRDTSC();\n\nuint64 PPCTimer_microsecondsToTsc(uint64 us);\nuint64 PPCTimer_tscToMicroseconds(uint64 us);\nuint64 PPCTimer_getRawTsc();\n\nvoid PPCTimer_start();\n\n// core info and control\nextern uint32 ppcThreadQuantum;\n\nuint8* PPCInterpreter_PushAndReturnStackPointer(sint32 offset);\nuint8* PPCInterpreterGetStackPointer();\nvoid PPCInterpreterModifyStackPointer(sint32 offset);\n\nuint32 PPCInterpreter_makeCallableExportDepr(void (*ppcCallableExport)(PPCInterpreter_t* hCPU));\n\nstatic inline float flushDenormalToZero(float f)\n{\n\tuint32 v = *(uint32*)&f;\n\treturn *(float*)&v;\n}\n\n// HLE interface\n\nusing HLECALL = void(*)(PPCInterpreter_t*);\nusing HLEIDX = sint32;\n\nHLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall, std::string hleName);\nHLECALL PPCInterpreter_getHLECall(HLEIDX funcIndex);\n\n// HLE scheduler\n\nvoid PPCInterpreter_relinquishTimeslice();\n\nvoid PPCCore_boostQuantum(sint32 numCycles);\nvoid PPCCore_deboostQuantum(sint32 numCycles);\n\nvoid PPCCore_switchToScheduler();\nvoid PPCCore_switchToSchedulerWithLock();\n\nPPCInterpreter_t* PPCCore_executeCallbackInternal(uint32 functionMPTR);\nvoid PPCCore_init();\n\n// LLE scheduler\n\nvoid PPCCoreLLE_startSingleCoreScheduler(uint32 entrypoint);\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/PPCTimer.cpp",
    "content": "#include \"Cafe/HW/Espresso/Const.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/helpers/fspinlock.h\"\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n#include \"Common/cpu_features.h\"\n\n#if defined(ARCH_X86_64)\n#include <immintrin.h>\n#pragma intrinsic(__rdtsc)\n#endif\n\nuint64 _rdtscLastMeasure = 0;\nuint64 _rdtscFrequency = 0;\n\nstruct uint128_t\n{\n\tuint64 low;\n\tuint64 high;\n};\n\nstatic_assert(sizeof(uint128_t) == 16);\n\nuint128_t _rdtscAcc{};\n\nuint64 muldiv64(uint64 a, uint64 b, uint64 d)\n{\n\tuint64 diva = a / d;\n\tuint64 moda = a % d;\n\tuint64 divb = b / d;\n\tuint64 modb = b % d;\n\treturn diva * b + moda * divb + moda * modb / d;\n}\n\nuint64 PPCTimer_estimateRDTSCFrequency()\n{\n    #if defined(ARCH_X86_64)\n\tif (!g_CPUFeatures.x86.invariant_tsc)\n\t\tcemuLog_log(LogType::Force, \"Invariant TSC not supported\");\n    #endif\n\n\t_mm_mfence();\n\tuint64 tscStart = __rdtsc();\n\tunsigned int startTime = GetTickCount();\n\tHRTick startTick = HighResolutionTimer::now().getTick();\n\t// wait roughly 3 seconds\n\twhile (true)\n\t{\n\t\tif ((GetTickCount() - startTime) >= 3000)\n\t\t\tbreak;\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t}\n\t_mm_mfence();\n\tHRTick stopTick = HighResolutionTimer::now().getTick();\n\tuint64 tscEnd = __rdtsc();\n\t// derive frequency approximation from measured time difference\n\tuint64 tsc_diff = tscEnd - tscStart;\n\tuint64 hrtFreq = 0;\n\tuint64 hrtDiff = HighResolutionTimer::getTimeDiffEx(startTick, stopTick, hrtFreq);\n\tuint64 tsc_freq = muldiv64(tsc_diff, hrtFreq, hrtDiff);\n\n\t// uint64 freqMultiplier = tsc_freq / hrtFreq;\n\t//cemuLog_log(LogType::Force, \"RDTSC measurement test:\");\n\t//cemuLog_log(LogType::Force, \"TSC-diff:   0x{:016x}\", tsc_diff);\n\t//cemuLog_log(LogType::Force, \"TSC-freq:   0x{:016x}\", tsc_freq);\n\t//cemuLog_log(LogType::Force, \"HPC-diff:   0x{:016x}\", qpc_diff);\n\t//cemuLog_log(LogType::Force, \"HPC-freq:   0x{:016x}\", (uint64)qpc_freq.QuadPart);\n\t//cemuLog_log(LogType::Force, \"Multiplier: 0x{:016x}\", freqMultiplier);\n\n\treturn tsc_freq;\n}\n\nint PPCTimer_initThread()\n{\n\t_rdtscFrequency = PPCTimer_estimateRDTSCFrequency();\n\treturn 0;\n}\n\nvoid PPCTimer_init()\n{\n\tstd::thread t(PPCTimer_initThread);\n\tt.detach();\n\t_rdtscLastMeasure = __rdtsc();\n}\n\nuint64 _tickSummary = 0;\n\nvoid PPCTimer_start()\n{\n\t_rdtscLastMeasure = __rdtsc();\n\t_tickSummary = 0;\n}\n\nuint64 PPCTimer_getRawTsc()\n{\n\treturn __rdtsc();\n}\n\nuint64 PPCTimer_microsecondsToTsc(uint64 us)\n{\n\treturn (us * _rdtscFrequency) / 1000000ULL;\n}\n\nuint64 PPCTimer_tscToMicroseconds(uint64 us)\n{\n\tuint128_t r{};\n\tr.low = _umul128(us, 1000000ULL, &r.high);\n\n\tuint64 remainder;\n\tconst uint64 microseconds = _udiv128(r.high, r.low, _rdtscFrequency, &remainder);\n\n\treturn microseconds;\n}\n\nbool PPCTimer_isReady()\n{\n\treturn _rdtscFrequency != 0;\n}\n\nvoid PPCTimer_waitForInit()\n{\n\twhile (!PPCTimer_isReady()) std::this_thread::sleep_for(std::chrono::milliseconds(10));\n}\n\nFSpinlock sTimerSpinlock;\n\n// thread safe\nuint64 PPCTimer_getFromRDTSC()\n{\n\tsTimerSpinlock.lock();\n\t_mm_mfence();\n\tuint64 rdtscCurrentMeasure = __rdtsc();\n\tuint64 rdtscDif = rdtscCurrentMeasure - _rdtscLastMeasure;\n\t// optimized max(rdtscDif, 0) without conditionals\n\trdtscDif = rdtscDif & ~(uint64)((sint64)rdtscDif >> 63);\n\n\tuint128_t diff{};\n\tdiff.low = _umul128(rdtscDif, Espresso::CORE_CLOCK, &diff.high);\n\n\tif(rdtscCurrentMeasure > _rdtscLastMeasure)\n\t\t_rdtscLastMeasure = rdtscCurrentMeasure; // only travel forward in time\n\n\tuint8 c = 0;\n\t#if BOOST_OS_WINDOWS\n\tc = _addcarry_u64(c, _rdtscAcc.low, diff.low, &_rdtscAcc.low);\n\t_addcarry_u64(c, _rdtscAcc.high, diff.high, &_rdtscAcc.high);\n\t#else\n\t// requires casting because of long / long long nonesense\n\tc = _addcarry_u64(c, _rdtscAcc.low, diff.low, (unsigned long long*)&_rdtscAcc.low);\n\t_addcarry_u64(c, _rdtscAcc.high, diff.high, (unsigned long long*)&_rdtscAcc.high);\n\t#endif\n\n\tuint64 remainder;\n\tuint64 elapsedTick = _udiv128(_rdtscAcc.high, _rdtscAcc.low, _rdtscFrequency, &remainder);\n\n\t_rdtscAcc.low = remainder;\n\t_rdtscAcc.high = 0;\n\n\t// timer scaling\n\telapsedTick <<= 3ull; // *8\n\tuint8 timerShiftFactor = ActiveSettings::GetTimerShiftFactor();\n\telapsedTick >>= timerShiftFactor;\n\n\t_tickSummary += elapsedTick;\n\n\tsTimerSpinlock.unlock();\n\treturn _tickSummary;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.cpp",
    "content": "#include \"BackendAArch64.h\"\n\n#pragma push_macro(\"CSIZE\")\n#undef CSIZE\n#include <xbyak_aarch64.h>\n#pragma pop_macro(\"CSIZE\")\n#include <xbyak_aarch64_util.h>\n\n#include <cstddef>\n\n#include \"../PPCRecompiler.h\"\n#include \"Common/precompiled.h\"\n#include \"Common/cpu_features.h\"\n#include \"HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"HW/Espresso/Interpreter/PPCInterpreterHelper.h\"\n#include \"HW/Espresso/PPCState.h\"\n\nusing namespace Xbyak_aarch64;\n\nconstexpr uint32 TEMP_GPR_1_ID = 25;\nconstexpr uint32 TEMP_GPR_2_ID = 26;\nconstexpr uint32 PPC_RECOMPILER_INSTANCE_DATA_REG_ID = 27;\nconstexpr uint32 MEMORY_BASE_REG_ID = 28;\nconstexpr uint32 HCPU_REG_ID = 29;\n\nconstexpr uint32 TEMP_FPR_ID = 31;\n\nstruct FPReg\n{\n\texplicit FPReg(size_t index)\n\t\t: index(index), VReg(index), QReg(index), DReg(index), SReg(index), HReg(index), BReg(index)\n\t{\n\t}\n\tconst size_t index;\n\tconst VReg VReg;\n\tconst QReg QReg;\n\tconst DReg DReg;\n\tconst SReg SReg;\n\tconst HReg HReg;\n\tconst BReg BReg;\n};\n\nstruct GPReg\n{\n\texplicit GPReg(size_t index)\n\t\t: index(index), XReg(index), WReg(index)\n\t{\n\t}\n\tconst size_t index;\n\tconst XReg XReg;\n\tconst WReg WReg;\n};\n\nstatic const XReg HCPU_REG{HCPU_REG_ID}, PPC_REC_INSTANCE_REG{PPC_RECOMPILER_INSTANCE_DATA_REG_ID}, MEM_BASE_REG{MEMORY_BASE_REG_ID};\nstatic const GPReg TEMP_GPR1{TEMP_GPR_1_ID};\nstatic const GPReg TEMP_GPR2{TEMP_GPR_2_ID};\nstatic const GPReg LR{TEMP_GPR_2_ID};\n\nstatic const FPReg TEMP_FPR{TEMP_FPR_ID};\n\nstatic const util::Cpu s_cpu;\n\nclass AArch64Allocator : public Allocator\n{\n  private:\n#ifdef XBYAK_USE_MMAP_ALLOCATOR\n\tinline static MmapAllocator s_allocator;\n#else\n\tinline static Allocator s_allocator;\n#endif\n\tAllocator* m_allocatorImpl;\n\tbool m_freeDisabled = false;\n\n  public:\n\tAArch64Allocator()\n\t\t: m_allocatorImpl(reinterpret_cast<Allocator*>(&s_allocator)) {}\n\n\tuint32* alloc(size_t size) override\n\t{\n\t\treturn m_allocatorImpl->alloc(size);\n\t}\n\n\tvoid setFreeDisabled(bool disabled)\n\t{\n\t\tm_freeDisabled = disabled;\n\t}\n\n\tvoid free(uint32* p) override\n\t{\n\t\tif (!m_freeDisabled)\n\t\t\tm_allocatorImpl->free(p);\n\t}\n\n\t[[nodiscard]] bool useProtect() const override\n\t{\n\t\treturn !m_freeDisabled && m_allocatorImpl->useProtect();\n\t}\n};\n\nstruct UnconditionalJumpInfo\n{\n\tIMLSegment* target;\n};\n\nstruct ConditionalRegJumpInfo\n{\n\tIMLSegment* target;\n\tWReg regBool;\n\tbool mustBeTrue;\n};\n\nstruct NegativeRegValueJumpInfo\n{\n\tIMLSegment* target;\n\tWReg regValue;\n};\n\nusing JumpInfo = std::variant<\n\tUnconditionalJumpInfo,\n\tConditionalRegJumpInfo,\n\tNegativeRegValueJumpInfo>;\n\nstruct AArch64GenContext_t : CodeGenerator\n{\n\texplicit AArch64GenContext_t(Allocator* allocator = nullptr);\n\tvoid enterRecompilerCode();\n\tvoid leaveRecompilerCode();\n\n\tvoid r_name(IMLInstruction* imlInstruction);\n\tvoid name_r(IMLInstruction* imlInstruction);\n\tbool r_s32(IMLInstruction* imlInstruction);\n\tbool r_r(IMLInstruction* imlInstruction);\n\tbool r_r_s32(IMLInstruction* imlInstruction);\n\tbool r_r_s32_carry(IMLInstruction* imlInstruction);\n\tbool r_r_r(IMLInstruction* imlInstruction);\n\tbool r_r_r_carry(IMLInstruction* imlInstruction);\n\tvoid compare(IMLInstruction* imlInstruction);\n\tvoid compare_s32(IMLInstruction* imlInstruction);\n\tbool load(IMLInstruction* imlInstruction, bool indexed);\n\tbool store(IMLInstruction* imlInstruction, bool indexed);\n\tvoid atomic_cmp_store(IMLInstruction* imlInstruction);\n\tbool macro(IMLInstruction* imlInstruction);\n\tvoid call_imm(IMLInstruction* imlInstruction);\n\tbool fpr_load(IMLInstruction* imlInstruction, bool indexed);\n\tbool fpr_store(IMLInstruction* imlInstruction, bool indexed);\n\tvoid fpr_r_r(IMLInstruction* imlInstruction);\n\tvoid fpr_r_r_r(IMLInstruction* imlInstruction);\n\tvoid fpr_r_r_r_r(IMLInstruction* imlInstruction);\n\tvoid fpr_r(IMLInstruction* imlInstruction);\n\tvoid fpr_compare(IMLInstruction* imlInstruction);\n\tvoid cjump(IMLInstruction* imlInstruction, IMLSegment* imlSegment);\n\tvoid jump(IMLSegment* imlSegment);\n\tvoid conditionalJumpCycleCheck(IMLSegment* imlSegment);\n\n\tstatic constexpr size_t MAX_JUMP_INSTR_COUNT = 2;\n\tstd::list<std::pair<size_t, JumpInfo>> jumps;\n\tvoid prepareJump(JumpInfo&& jumpInfo)\n\t{\n\t\tjumps.emplace_back(getSize(), jumpInfo);\n\t\tfor (int i = 0; i < MAX_JUMP_INSTR_COUNT; ++i)\n\t\t\tnop();\n\t}\n\n\tstd::map<IMLSegment*, size_t> segmentStarts;\n\tvoid storeSegmentStart(IMLSegment* imlSegment)\n\t{\n\t\tsegmentStarts[imlSegment] = getSize();\n\t}\n\n\tbool processAllJumps()\n\t{\n\t\tfor (auto jump : jumps)\n\t\t{\n\t\t\tauto jumpStart = jump.first;\n\t\t\tauto jumpInfo = jump.second;\n\t\t\tbool success = std::visit(\n\t\t\t\t[&, this](const auto& jump) {\n\t\t\t\t\tsetSize(jumpStart);\n\t\t\t\t\tsint64 targetAddress = segmentStarts.at(jump.target);\n\t\t\t\t\tsint64 addressOffset = targetAddress - jumpStart;\n\t\t\t\t\treturn handleJump(addressOffset, jump);\n\t\t\t\t},\n\t\t\t\tjumpInfo);\n\t\t\tif (!success)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool handleJump(sint64 addressOffset, const UnconditionalJumpInfo& jump)\n\t{\n\t\t// in +/-128MB\n\t\tif (-0x8000000 <= addressOffset && addressOffset <= 0x7ffffff)\n\t\t{\n\t\t\tb(addressOffset);\n\t\t\treturn true;\n\t\t}\n\n\t\tcemu_assert_suspicious();\n\n\t\treturn false;\n\t}\n\n\tbool handleJump(sint64 addressOffset, const ConditionalRegJumpInfo& jump)\n\t{\n\t\tbool mustBeTrue = jump.mustBeTrue;\n\n\t\t// in +/-32KB\n\t\tif (-0x8000 <= addressOffset && addressOffset <= 0x7fff)\n\t\t{\n\t\t\tif (mustBeTrue)\n\t\t\t\ttbnz(jump.regBool, 0, addressOffset);\n\t\t\telse\n\t\t\t\ttbz(jump.regBool, 0, addressOffset);\n\t\t\treturn true;\n\t\t}\n\n\t\t// in +/-1MB\n\t\tif (-0x100000 <= addressOffset && addressOffset <= 0xfffff)\n\t\t{\n\t\t\tif (mustBeTrue)\n\t\t\t\tcbnz(jump.regBool, addressOffset);\n\t\t\telse\n\t\t\t\tcbz(jump.regBool, addressOffset);\n\t\t\treturn true;\n\t\t}\n\n\t\tLabel skipJump;\n\t\tif (mustBeTrue)\n\t\t\ttbz(jump.regBool, 0, skipJump);\n\t\telse\n\t\t\ttbnz(jump.regBool, 0, skipJump);\n\t\taddressOffset -= 4;\n\n\t\t// in +/-128MB\n\t\tif (-0x8000000 <= addressOffset && addressOffset <= 0x7ffffff)\n\t\t{\n\t\t\tb(addressOffset);\n\t\t\tL(skipJump);\n\t\t\treturn true;\n\t\t}\n\n\t\tcemu_assert_suspicious();\n\n\t\treturn false;\n\t}\n\n\tbool handleJump(sint64 addressOffset, const NegativeRegValueJumpInfo& jump)\n\t{\n\t\t// in +/-32KB\n\t\tif (-0x8000 <= addressOffset && addressOffset <= 0x7fff)\n\t\t{\n\t\t\ttbnz(jump.regValue, 31, addressOffset);\n\t\t\treturn true;\n\t\t}\n\n\t\t// in +/-1MB\n\t\tif (-0x100000 <= addressOffset && addressOffset <= 0xfffff)\n\t\t{\n\t\t\ttst(jump.regValue, 0x80000000);\n\t\t\taddressOffset -= 4;\n\t\t\tbne(addressOffset);\n\t\t\treturn true;\n\t\t}\n\n\t\tLabel skipJump;\n\t\ttbz(jump.regValue, 31, skipJump);\n\t\taddressOffset -= 4;\n\n\t\t// in +/-128MB\n\t\tif (-0x8000000 <= addressOffset && addressOffset <= 0x7ffffff)\n\t\t{\n\t\t\tb(addressOffset);\n\t\t\tL(skipJump);\n\t\t\treturn true;\n\t\t}\n\n\t\tcemu_assert_suspicious();\n\n\t\treturn false;\n\t}\n};\n\ntemplate<std::derived_from<VRegSc> T>\nT fpReg(const IMLReg& imlReg)\n{\n\tcemu_assert_debug(imlReg.GetRegFormat() == IMLRegFormat::F64);\n\tauto regId = imlReg.GetRegID();\n\tcemu_assert_debug(regId >= IMLArchAArch64::PHYSREG_FPR_BASE && regId < IMLArchAArch64::PHYSREG_FPR_BASE + IMLArchAArch64::PHYSREG_FPR_COUNT);\n\treturn T(regId - IMLArchAArch64::PHYSREG_FPR_BASE);\n}\n\ntemplate<std::derived_from<RReg> T>\nT gpReg(const IMLReg& imlReg)\n{\n\tauto regFormat = imlReg.GetRegFormat();\n\tif (std::is_same_v<T, WReg>)\n\t\tcemu_assert_debug(regFormat == IMLRegFormat::I32);\n\telse if (std::is_same_v<T, XReg>)\n\t\tcemu_assert_debug(regFormat == IMLRegFormat::I64);\n\telse\n\t\tcemu_assert_unimplemented();\n\n\tauto regId = imlReg.GetRegID();\n\tcemu_assert_debug(regId >= IMLArchAArch64::PHYSREG_GPR_BASE && regId < IMLArchAArch64::PHYSREG_GPR_BASE + IMLArchAArch64::PHYSREG_GPR_COUNT);\n\treturn T(regId - IMLArchAArch64::PHYSREG_GPR_BASE);\n}\n\ntemplate<std::derived_from<VRegSc> To, std::derived_from<VRegSc> From>\nTo aliasAs(const From& reg)\n{\n\treturn To(reg.getIdx());\n}\n\ntemplate<std::derived_from<RReg> To, std::derived_from<RReg> From>\nTo aliasAs(const From& reg)\n{\n\treturn To(reg.getIdx());\n}\n\nAArch64GenContext_t::AArch64GenContext_t(Allocator* allocator)\n\t: CodeGenerator(DEFAULT_MAX_CODE_SIZE, AutoGrow, allocator)\n{\n}\n\nconstexpr uint64 ones(uint32 size)\n{\n\treturn (size == 64) ? 0xffffffffffffffff : ((uint64)1 << size) - 1;\n}\n\nconstexpr bool isAdrImmValidFPR(sint32 imm, uint32 bits)\n{\n\tuint32 times = bits / 8;\n\tuint32 sh = std::countr_zero(times);\n\treturn (0 <= imm && imm <= 4095 * times) && ((uint64)imm & ones(sh)) == 0;\n}\n\nconstexpr bool isAdrImmValidGPR(sint32 imm, uint32 bits = 32)\n{\n\tuint32 size = std::countr_zero(bits / 8u);\n\tsint32 times = 1 << size;\n\treturn (0 <= imm && imm <= 4095 * times) && ((uint64)imm & ones(size)) == 0;\n}\n\nconstexpr bool isAdrImmRangeValid(sint32 rangeStart, sint32 rangeOffset, sint32 bits, std::invocable<sint32, uint32> auto check)\n{\n\tfor (sint32 i = rangeStart; i <= rangeStart + rangeOffset; i += bits / 8)\n\t\tif (!check(i, bits))\n\t\t\treturn false;\n\treturn true;\n}\n\nconstexpr bool isAdrImmRangeValidGPR(sint32 rangeStart, sint32 rangeOffset, sint32 bits = 32)\n{\n\treturn isAdrImmRangeValid(rangeStart, rangeOffset, bits, isAdrImmValidGPR);\n}\n\nconstexpr bool isAdrImmRangeValidFpr(sint32 rangeStart, sint32 rangeOffset, sint32 bits)\n{\n\treturn isAdrImmRangeValid(rangeStart, rangeOffset, bits, isAdrImmValidFPR);\n}\n\n// Verify that all of the offsets for the PPCInterpreter_t members that we use in r_name/name_r have a valid imm value for AdrUimm\nstatic_assert(isAdrImmRangeValidGPR(offsetof(PPCInterpreter_t, gpr), sizeof(uint32) * 31));\nstatic_assert(isAdrImmValidGPR(offsetof(PPCInterpreter_t, spr.LR)));\nstatic_assert(isAdrImmValidGPR(offsetof(PPCInterpreter_t, spr.CTR)));\nstatic_assert(isAdrImmValidGPR(offsetof(PPCInterpreter_t, spr.XER)));\nstatic_assert(isAdrImmRangeValidGPR(offsetof(PPCInterpreter_t, spr.UGQR), sizeof(PPCInterpreter_t::spr.UGQR[0]) * (SPR_UGQR7 - SPR_UGQR0)));\nstatic_assert(isAdrImmRangeValidGPR(offsetof(PPCInterpreter_t, temporaryGPR_reg), sizeof(uint32) * 3));\nstatic_assert(isAdrImmValidGPR(offsetof(PPCInterpreter_t, xer_ca), 8));\nstatic_assert(isAdrImmValidGPR(offsetof(PPCInterpreter_t, xer_so), 8));\nstatic_assert(isAdrImmRangeValidGPR(offsetof(PPCInterpreter_t, cr), PPCREC_NAME_CR_LAST - PPCREC_NAME_CR, 8));\nstatic_assert(isAdrImmValidGPR(offsetof(PPCInterpreter_t, reservedMemAddr)));\nstatic_assert(isAdrImmValidGPR(offsetof(PPCInterpreter_t, reservedMemValue)));\nstatic_assert(isAdrImmRangeValidFpr(offsetof(PPCInterpreter_t, fpr), sizeof(FPR_t) * 63, 64));\nstatic_assert(isAdrImmRangeValidFpr(offsetof(PPCInterpreter_t, temporaryFPR), sizeof(FPR_t) * 7, 128));\n\nvoid AArch64GenContext_t::r_name(IMLInstruction* imlInstruction)\n{\n\tuint32 name = imlInstruction->op_r_name.name;\n\n\tif (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::I64)\n\t{\n\t\tXReg regRXReg = gpReg<XReg>(imlInstruction->op_r_name.regR);\n\t\tWReg regR = aliasAs<WReg>(regRXReg);\n\t\tif (name >= PPCREC_NAME_R0 && name < PPCREC_NAME_R0 + 32)\n\t\t{\n\t\t\tldr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, gpr) + sizeof(uint32) * (name - PPCREC_NAME_R0)));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_SPR0 && name < PPCREC_NAME_SPR0 + 999)\n\t\t{\n\t\t\tuint32 sprIndex = (name - PPCREC_NAME_SPR0);\n\t\t\tif (sprIndex == SPR_LR)\n\t\t\t\tldr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, spr.LR)));\n\t\t\telse if (sprIndex == SPR_CTR)\n\t\t\t\tldr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, spr.CTR)));\n\t\t\telse if (sprIndex == SPR_XER)\n\t\t\t\tldr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, spr.XER)));\n\t\t\telse if (sprIndex >= SPR_UGQR0 && sprIndex <= SPR_UGQR7)\n\t\t\t\tldr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, spr.UGQR) + sizeof(PPCInterpreter_t::spr.UGQR[0]) * (sprIndex - SPR_UGQR0)));\n\t\t\telse\n\t\t\t\tcemu_assert_suspicious();\n\t\t}\n\t\telse if (name >= PPCREC_NAME_TEMPORARY && name < PPCREC_NAME_TEMPORARY + 4)\n\t\t{\n\t\t\tldr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, temporaryGPR_reg) + sizeof(uint32) * (name - PPCREC_NAME_TEMPORARY)));\n\t\t}\n\t\telse if (name == PPCREC_NAME_XER_CA)\n\t\t{\n\t\t\tldrb(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, xer_ca)));\n\t\t}\n\t\telse if (name == PPCREC_NAME_XER_SO)\n\t\t{\n\t\t\tldrb(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, xer_so)));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_CR && name <= PPCREC_NAME_CR_LAST)\n\t\t{\n\t\t\tldrb(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, cr) + (name - PPCREC_NAME_CR)));\n\t\t}\n\t\telse if (name == PPCREC_NAME_CPU_MEMRES_EA)\n\t\t{\n\t\t\tldr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, reservedMemAddr)));\n\t\t}\n\t\telse if (name == PPCREC_NAME_CPU_MEMRES_VAL)\n\t\t{\n\t\t\tldr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, reservedMemValue)));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t}\n\telse if (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::F64)\n\t{\n\t\tauto imlRegR = imlInstruction->op_r_name.regR;\n\n\t\tif (name >= PPCREC_NAME_FPR_HALF && name < (PPCREC_NAME_FPR_HALF + 64))\n\t\t{\n\t\t\tuint32 regIndex = (name - PPCREC_NAME_FPR_HALF) / 2;\n\t\t\tuint32 pairIndex = (name - PPCREC_NAME_FPR_HALF) % 2;\n\t\t\tuint32 offset = offsetof(PPCInterpreter_t, fpr) + sizeof(FPR_t) * regIndex + (pairIndex ? sizeof(double) : 0);\n\t\t\tldr(fpReg<DReg>(imlRegR), AdrUimm(HCPU_REG, offset));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_TEMPORARY_FPR0 && name < (PPCREC_NAME_TEMPORARY_FPR0 + 8))\n\t\t{\n\t\t\tldr(fpReg<QReg>(imlRegR), AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, temporaryFPR) + sizeof(FPR_t) * (name - PPCREC_NAME_TEMPORARY_FPR0)));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n}\n\nvoid AArch64GenContext_t::name_r(IMLInstruction* imlInstruction)\n{\n\tuint32 name = imlInstruction->op_r_name.name;\n\n\tif (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::I64)\n\t{\n\t\tXReg regRXReg = gpReg<XReg>(imlInstruction->op_r_name.regR);\n\t\tWReg regR = aliasAs<WReg>(regRXReg);\n\t\tif (name >= PPCREC_NAME_R0 && name < PPCREC_NAME_R0 + 32)\n\t\t{\n\t\t\tstr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, gpr) + sizeof(uint32) * (name - PPCREC_NAME_R0)));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_SPR0 && name < PPCREC_NAME_SPR0 + 999)\n\t\t{\n\t\t\tuint32 sprIndex = (name - PPCREC_NAME_SPR0);\n\t\t\tif (sprIndex == SPR_LR)\n\t\t\t\tstr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, spr.LR)));\n\t\t\telse if (sprIndex == SPR_CTR)\n\t\t\t\tstr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, spr.CTR)));\n\t\t\telse if (sprIndex == SPR_XER)\n\t\t\t\tstr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, spr.XER)));\n\t\t\telse if (sprIndex >= SPR_UGQR0 && sprIndex <= SPR_UGQR7)\n\t\t\t\tstr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, spr.UGQR) + sizeof(PPCInterpreter_t::spr.UGQR[0]) * (sprIndex - SPR_UGQR0)));\n\t\t\telse\n\t\t\t\tcemu_assert_suspicious();\n\t\t}\n\t\telse if (name >= PPCREC_NAME_TEMPORARY && name < PPCREC_NAME_TEMPORARY + 4)\n\t\t{\n\t\t\tstr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, temporaryGPR_reg) + sizeof(uint32) * (name - PPCREC_NAME_TEMPORARY)));\n\t\t}\n\t\telse if (name == PPCREC_NAME_XER_CA)\n\t\t{\n\t\t\tstrb(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, xer_ca)));\n\t\t}\n\t\telse if (name == PPCREC_NAME_XER_SO)\n\t\t{\n\t\t\tstrb(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, xer_so)));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_CR && name <= PPCREC_NAME_CR_LAST)\n\t\t{\n\t\t\tstrb(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, cr) + (name - PPCREC_NAME_CR)));\n\t\t}\n\t\telse if (name == PPCREC_NAME_CPU_MEMRES_EA)\n\t\t{\n\t\t\tstr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, reservedMemAddr)));\n\t\t}\n\t\telse if (name == PPCREC_NAME_CPU_MEMRES_VAL)\n\t\t{\n\t\t\tstr(regR, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, reservedMemValue)));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t}\n\telse if (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::F64)\n\t{\n\t\tauto imlRegR = imlInstruction->op_r_name.regR;\n\t\tif (name >= PPCREC_NAME_FPR_HALF && name < (PPCREC_NAME_FPR_HALF + 64))\n\t\t{\n\t\t\tuint32 regIndex = (name - PPCREC_NAME_FPR_HALF) / 2;\n\t\t\tuint32 pairIndex = (name - PPCREC_NAME_FPR_HALF) % 2;\n\t\t\tsint32 offset = offsetof(PPCInterpreter_t, fpr) + sizeof(FPR_t) * regIndex + pairIndex * sizeof(double);\n\t\t\tstr(fpReg<DReg>(imlRegR), AdrUimm(HCPU_REG, offset));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_TEMPORARY_FPR0 && name < (PPCREC_NAME_TEMPORARY_FPR0 + 8))\n\t\t{\n\t\t\tstr(fpReg<QReg>(imlRegR), AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, temporaryFPR) + sizeof(FPR_t) * (name - PPCREC_NAME_TEMPORARY_FPR0)));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n}\n\nbool AArch64GenContext_t::r_r(IMLInstruction* imlInstruction)\n{\n\tWReg regR = gpReg<WReg>(imlInstruction->op_r_r.regR);\n\tWReg regA = gpReg<WReg>(imlInstruction->op_r_r.regA);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_ASSIGN)\n\t{\n\t\tmov(regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_ENDIAN_SWAP)\n\t{\n\t\trev(regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_ASSIGN_S8_TO_S32)\n\t{\n\t\tsxtb(regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_ASSIGN_S16_TO_S32)\n\t{\n\t\tsxth(regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_NOT)\n\t{\n\t\tmvn(regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_NEG)\n\t{\n\t\tneg(regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_CNTLZW)\n\t{\n\t\tclz(regR, regA);\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Recompiler, \"PPCRecompilerAArch64Gen_imlInstruction_r_r(): Unsupported operation {:x}\", imlInstruction->operation);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool AArch64GenContext_t::r_s32(IMLInstruction* imlInstruction)\n{\n\tsint32 imm32 = imlInstruction->op_r_immS32.immS32;\n\tWReg reg = gpReg<WReg>(imlInstruction->op_r_immS32.regR);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_ASSIGN)\n\t{\n\t\tmov(reg, imm32);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_LEFT_ROTATE)\n\t{\n\t\tror(reg, reg, 32 - (imm32 & 0x1f));\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Recompiler, \"PPCRecompilerAArch64Gen_imlInstruction_r_s32(): Unsupported operation {:x}\", imlInstruction->operation);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool AArch64GenContext_t::r_r_s32(IMLInstruction* imlInstruction)\n{\n\tWReg regR = gpReg<WReg>(imlInstruction->op_r_r_s32.regR);\n\tWReg regA = gpReg<WReg>(imlInstruction->op_r_r_s32.regA);\n\tsint32 immS32 = imlInstruction->op_r_r_s32.immS32;\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_ADD)\n\t{\n\t\tadd_imm(regR, regA, immS32, TEMP_GPR1.WReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_SUB)\n\t{\n\t\tsub_imm(regR, regA, immS32, TEMP_GPR1.WReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_AND)\n\t{\n\t\tmov(TEMP_GPR1.WReg, immS32);\n\t\tand_(regR, regA, TEMP_GPR1.WReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_OR)\n\t{\n\t\tmov(TEMP_GPR1.WReg, immS32);\n\t\torr(regR, regA, TEMP_GPR1.WReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_XOR)\n\t{\n\t\tmov(TEMP_GPR1.WReg, immS32);\n\t\teor(regR, regA, TEMP_GPR1.WReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_SIGNED)\n\t{\n\t\tmov(TEMP_GPR1.WReg, immS32);\n\t\tmul(regR, regA, TEMP_GPR1.WReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_LEFT_SHIFT)\n\t{\n\t\tlsl(regR, regA, (uint32)immS32 & 0x1f);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_U)\n\t{\n\t\tlsr(regR, regA, (uint32)immS32 & 0x1f);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_S)\n\t{\n\t\tasr(regR, regA, (uint32)immS32 & 0x1f);\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Recompiler, \"PPCRecompilerAArch64Gen_imlInstruction_r_r_s32(): Unsupported operation {:x}\", imlInstruction->operation);\n\t\tcemu_assert_suspicious();\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool AArch64GenContext_t::r_r_s32_carry(IMLInstruction* imlInstruction)\n{\n\tWReg regR = gpReg<WReg>(imlInstruction->op_r_r_s32_carry.regR);\n\tWReg regA = gpReg<WReg>(imlInstruction->op_r_r_s32_carry.regA);\n\tWReg regCarry = gpReg<WReg>(imlInstruction->op_r_r_s32_carry.regCarry);\n\n\tsint32 immS32 = imlInstruction->op_r_r_s32_carry.immS32;\n\tif (imlInstruction->operation == PPCREC_IML_OP_ADD)\n\t{\n\t\tadds_imm(regR, regA, immS32, TEMP_GPR1.WReg);\n\t\tcset(regCarry, Cond::CS);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_ADD_WITH_CARRY)\n\t{\n\t\tmov(TEMP_GPR1.WReg, immS32);\n\t\tcmp(regCarry, 1);\n\t\tadcs(regR, regA, TEMP_GPR1.WReg);\n\t\tcset(regCarry, Cond::CS);\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nbool AArch64GenContext_t::r_r_r(IMLInstruction* imlInstruction)\n{\n\tWReg regResult = gpReg<WReg>(imlInstruction->op_r_r_r.regR);\n\tXReg reg64Result = aliasAs<XReg>(regResult);\n\tWReg regOperand1 = gpReg<WReg>(imlInstruction->op_r_r_r.regA);\n\tWReg regOperand2 = gpReg<WReg>(imlInstruction->op_r_r_r.regB);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_ADD)\n\t{\n\t\tadd(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_SUB)\n\t{\n\t\tsub(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_OR)\n\t{\n\t\torr(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_AND)\n\t{\n\t\tand_(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_XOR)\n\t{\n\t\teor(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_SIGNED)\n\t{\n\t\tmul(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_SLW)\n\t{\n\t\ttst(regOperand2, 32);\n\t\tlsl(regResult, regOperand1, regOperand2);\n\t\tcsel(regResult, regResult, wzr, Cond::EQ);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_SRW)\n\t{\n\t\ttst(regOperand2, 32);\n\t\tlsr(regResult, regOperand1, regOperand2);\n\t\tcsel(regResult, regResult, wzr, Cond::EQ);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_LEFT_ROTATE)\n\t{\n\t\tneg(TEMP_GPR1.WReg, regOperand2);\n\t\tror(regResult, regOperand1, TEMP_GPR1.WReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_S)\n\t{\n\t\tasr(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_U)\n\t{\n\t\tlsr(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_LEFT_SHIFT)\n\t{\n\t\tlsl(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_DIVIDE_SIGNED)\n\t{\n\t\tsdiv(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_DIVIDE_UNSIGNED)\n\t{\n\t\tudiv(regResult, regOperand1, regOperand2);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_HIGH_SIGNED)\n\t{\n\t\tsmull(reg64Result, regOperand1, regOperand2);\n\t\tlsr(reg64Result, reg64Result, 32);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_HIGH_UNSIGNED)\n\t{\n\t\tumull(reg64Result, regOperand1, regOperand2);\n\t\tlsr(reg64Result, reg64Result, 32);\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Recompiler, \"PPCRecompilerAArch64Gen_imlInstruction_r_r_r(): Unsupported operation {:x}\", imlInstruction->operation);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool AArch64GenContext_t::r_r_r_carry(IMLInstruction* imlInstruction)\n{\n\tWReg regR = gpReg<WReg>(imlInstruction->op_r_r_r_carry.regR);\n\tWReg regA = gpReg<WReg>(imlInstruction->op_r_r_r_carry.regA);\n\tWReg regB = gpReg<WReg>(imlInstruction->op_r_r_r_carry.regB);\n\tWReg regCarry = gpReg<WReg>(imlInstruction->op_r_r_r_carry.regCarry);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_ADD)\n\t{\n\t\tadds(regR, regA, regB);\n\t\tcset(regCarry, Cond::CS);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_ADD_WITH_CARRY)\n\t{\n\t\tcmp(regCarry, 1);\n\t\tadcs(regR, regA, regB);\n\t\tcset(regCarry, Cond::CS);\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nCond ImlCondToArm64Cond(IMLCondition condition)\n{\n\tswitch (condition)\n\t{\n\tcase IMLCondition::EQ:\n\t\treturn Cond::EQ;\n\tcase IMLCondition::NEQ:\n\t\treturn Cond::NE;\n\tcase IMLCondition::UNSIGNED_GT:\n\t\treturn Cond::HI;\n\tcase IMLCondition::UNSIGNED_LT:\n\t\treturn Cond::LO;\n\tcase IMLCondition::SIGNED_GT:\n\t\treturn Cond::GT;\n\tcase IMLCondition::SIGNED_LT:\n\t\treturn Cond::LT;\n\tdefault:\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn Cond::EQ;\n\t}\n\t}\n}\n\nvoid AArch64GenContext_t::compare(IMLInstruction* imlInstruction)\n{\n\tWReg regR = gpReg<WReg>(imlInstruction->op_compare.regR);\n\tWReg regA = gpReg<WReg>(imlInstruction->op_compare.regA);\n\tWReg regB = gpReg<WReg>(imlInstruction->op_compare.regB);\n\tCond cond = ImlCondToArm64Cond(imlInstruction->op_compare.cond);\n\tcmp(regA, regB);\n\tcset(regR, cond);\n}\n\nvoid AArch64GenContext_t::compare_s32(IMLInstruction* imlInstruction)\n{\n\tWReg regR = gpReg<WReg>(imlInstruction->op_compare.regR);\n\tWReg regA = gpReg<WReg>(imlInstruction->op_compare.regA);\n\tsint32 imm = imlInstruction->op_compare_s32.immS32;\n\tauto cond = ImlCondToArm64Cond(imlInstruction->op_compare.cond);\n\tcmp_imm(regA, imm, TEMP_GPR1.WReg);\n\tcset(regR, cond);\n}\n\nvoid AArch64GenContext_t::cjump(IMLInstruction* imlInstruction, IMLSegment* imlSegment)\n{\n\tauto regBool = gpReg<WReg>(imlInstruction->op_conditional_jump.registerBool);\n\tprepareJump(ConditionalRegJumpInfo{\n\t\t.target = imlSegment->nextSegmentBranchTaken,\n\t\t.regBool = regBool,\n\t\t.mustBeTrue = imlInstruction->op_conditional_jump.mustBeTrue,\n\t});\n}\n\nvoid AArch64GenContext_t::jump(IMLSegment* imlSegment)\n{\n\tprepareJump(UnconditionalJumpInfo{.target = imlSegment->nextSegmentBranchTaken});\n}\n\nvoid AArch64GenContext_t::conditionalJumpCycleCheck(IMLSegment* imlSegment)\n{\n\tldr(TEMP_GPR1.WReg, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, remainingCycles)));\n\tprepareJump(NegativeRegValueJumpInfo{\n\t\t.target = imlSegment->nextSegmentBranchTaken,\n\t\t.regValue = TEMP_GPR1.WReg,\n\t});\n}\n\nvoid* PPCRecompiler_virtualHLE(PPCInterpreter_t* ppcInterpreter, uint32 hleFuncId)\n{\n\tvoid* prevRSPTemp = ppcInterpreter->rspTemp;\n\tif (hleFuncId == 0xFFD0)\n\t{\n\t\tppcInterpreter->remainingCycles -= 500; // let subtract about 500 cycles for each HLE call\n\t\tppcInterpreter->gpr[3] = 0;\n\t\tPPCInterpreter_nextInstruction(ppcInterpreter);\n\t\treturn PPCInterpreter_getCurrentInstance();\n\t}\n\telse\n\t{\n\t\tauto hleCall = PPCInterpreter_getHLECall(hleFuncId);\n\t\tcemu_assert(hleCall != nullptr);\n\t\thleCall(ppcInterpreter);\n\t}\n\tppcInterpreter->rspTemp = prevRSPTemp;\n\treturn PPCInterpreter_getCurrentInstance();\n}\n\nbool AArch64GenContext_t::macro(IMLInstruction* imlInstruction)\n{\n\tif (imlInstruction->operation == PPCREC_IML_MACRO_B_TO_REG)\n\t{\n\t\tWReg branchDstReg = gpReg<WReg>(imlInstruction->op_macro.paramReg);\n\n\t\tmov(TEMP_GPR1.WReg, offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));\n\t\tadd(TEMP_GPR1.WReg, TEMP_GPR1.WReg, branchDstReg, ShMod::LSL, 1);\n\t\tldr(TEMP_GPR1.XReg, AdrExt(PPC_REC_INSTANCE_REG, TEMP_GPR1.WReg, ExtMod::UXTW));\n\t\tmov(LR.WReg, branchDstReg);\n\t\tbr(TEMP_GPR1.XReg);\n\t\treturn true;\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_MACRO_BL)\n\t{\n\t\tuint32 newLR = imlInstruction->op_macro.param + 4;\n\n\t\tmov(TEMP_GPR1.WReg, newLR);\n\t\tstr(TEMP_GPR1.WReg, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, spr.LR)));\n\n\t\tuint32 newIP = imlInstruction->op_macro.param2;\n\t\tuint64 lookupOffset = (uint64)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable) + (uint64)newIP * 2ULL;\n\t\tmov(TEMP_GPR1.XReg, lookupOffset);\n\t\tldr(TEMP_GPR1.XReg, AdrReg(PPC_REC_INSTANCE_REG, TEMP_GPR1.XReg));\n\t\tmov(LR.WReg, newIP);\n\t\tbr(TEMP_GPR1.XReg);\n\t\treturn true;\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_MACRO_B_FAR)\n\t{\n\t\tuint32 newIP = imlInstruction->op_macro.param2;\n\t\tuint64 lookupOffset = (uint64)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable) + (uint64)newIP * 2ULL;\n\t\tmov(TEMP_GPR1.XReg, lookupOffset);\n\t\tldr(TEMP_GPR1.XReg, AdrReg(PPC_REC_INSTANCE_REG, TEMP_GPR1.XReg));\n\t\tmov(LR.WReg, newIP);\n\t\tbr(TEMP_GPR1.XReg);\n\t\treturn true;\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_MACRO_LEAVE)\n\t{\n\t\tuint32 currentInstructionAddress = imlInstruction->op_macro.param;\n\t\tmov(TEMP_GPR1.XReg, (uint64)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable)); // newIP = 0 special value for recompiler exit\n\t\tldr(TEMP_GPR1.XReg, AdrReg(PPC_REC_INSTANCE_REG, TEMP_GPR1.XReg));\n\t\tmov(LR.WReg, currentInstructionAddress);\n\t\tbr(TEMP_GPR1.XReg);\n\t\treturn true;\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_MACRO_DEBUGBREAK)\n\t{\n\t\tbrk(0xf000);\n\t\treturn true;\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_MACRO_COUNT_CYCLES)\n\t{\n\t\tuint32 cycleCount = imlInstruction->op_macro.param;\n\t\tAdrUimm adrCycles = AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, remainingCycles));\n\t\tldr(TEMP_GPR1.WReg, adrCycles);\n\t\tsub_imm(TEMP_GPR1.WReg, TEMP_GPR1.WReg, cycleCount, TEMP_GPR2.WReg);\n\t\tstr(TEMP_GPR1.WReg, adrCycles);\n\t\treturn true;\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_MACRO_HLE)\n\t{\n\t\tuint32 ppcAddress = imlInstruction->op_macro.param;\n\t\tuint32 funcId = imlInstruction->op_macro.param2;\n\t\tLabel cyclesLeftLabel;\n\n\t\t// update instruction pointer\n\t\tmov(TEMP_GPR1.WReg, ppcAddress);\n\t\tstr(TEMP_GPR1.WReg, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, instructionPointer)));\n\t\t// set parameters\n\t\tstr(x30, AdrPreImm(sp, -16));\n\n\t\tmov(x0, HCPU_REG);\n\t\tmov(w1, funcId);\n\t\t// call HLE function\n\n\t\tmov(TEMP_GPR1.XReg, (uint64)PPCRecompiler_virtualHLE);\n\t\tblr(TEMP_GPR1.XReg);\n\n\t\tmov(HCPU_REG, x0);\n\n\t\tldr(x30, AdrPostImm(sp, 16));\n\n\t\t// check if cycles where decreased beyond zero, if yes -> leave recompiler\n\t\tldr(TEMP_GPR1.WReg, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, remainingCycles)));\n\t\ttbz(TEMP_GPR1.WReg, 31, cyclesLeftLabel); // check if negative\n\n\t\tmov(TEMP_GPR1.XReg, offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));\n\t\tldr(TEMP_GPR1.XReg, AdrReg(PPC_REC_INSTANCE_REG, TEMP_GPR1.XReg));\n\t\tldr(LR.WReg, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, instructionPointer)));\n\t\t// branch to recompiler exit\n\t\tbr(TEMP_GPR1.XReg);\n\n\t\tL(cyclesLeftLabel);\n\t\t// check if instruction pointer was changed\n\t\t// assign new instruction pointer to LR.WReg\n\t\tldr(LR.WReg, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, instructionPointer)));\n\t\tmov(TEMP_GPR1.XReg, offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));\n\t\tadd(TEMP_GPR1.XReg, TEMP_GPR1.XReg, LR.XReg, ShMod::LSL, 1);\n\t\tldr(TEMP_GPR1.XReg, AdrReg(PPC_REC_INSTANCE_REG, TEMP_GPR1.XReg));\n\t\t// branch to [ppcRecompilerDirectJumpTable + PPCInterpreter_t::instructionPointer * 2]\n\t\tbr(TEMP_GPR1.XReg);\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Recompiler, \"Unknown recompiler macro operation %d\\n\", imlInstruction->operation);\n\t\tcemu_assert_suspicious();\n\t}\n\treturn false;\n}\n\nbool AArch64GenContext_t::load(IMLInstruction* imlInstruction, bool indexed)\n{\n\tcemu_assert_debug(imlInstruction->op_storeLoad.registerData.GetRegFormat() == IMLRegFormat::I32);\n\tcemu_assert_debug(imlInstruction->op_storeLoad.registerMem.GetRegFormat() == IMLRegFormat::I32);\n\tif (indexed)\n\t\tcemu_assert_debug(imlInstruction->op_storeLoad.registerMem2.GetRegFormat() == IMLRegFormat::I32);\n\n\tsint32 memOffset = imlInstruction->op_storeLoad.immS32;\n\tbool signExtend = imlInstruction->op_storeLoad.flags2.signExtend;\n\tbool switchEndian = imlInstruction->op_storeLoad.flags2.swapEndian;\n\tWReg memReg = gpReg<WReg>(imlInstruction->op_storeLoad.registerMem);\n\tWReg dataReg = gpReg<WReg>(imlInstruction->op_storeLoad.registerData);\n\n\tadd_imm(TEMP_GPR1.WReg, memReg, memOffset, TEMP_GPR1.WReg);\n\tif (indexed)\n\t\tadd(TEMP_GPR1.WReg, TEMP_GPR1.WReg, gpReg<WReg>(imlInstruction->op_storeLoad.registerMem2));\n\n\tauto adr = AdrExt(MEM_BASE_REG, TEMP_GPR1.WReg, ExtMod::UXTW);\n\tif (imlInstruction->op_storeLoad.copyWidth == 32)\n\t{\n\t\tldr(dataReg, adr);\n\t\tif (switchEndian)\n\t\t\trev(dataReg, dataReg);\n\t}\n\telse if (imlInstruction->op_storeLoad.copyWidth == 16)\n\t{\n\t\tif (switchEndian)\n\t\t{\n\t\t\tldrh(dataReg, adr);\n\t\t\trev(dataReg, dataReg);\n\t\t\tif (signExtend)\n\t\t\t\tasr(dataReg, dataReg, 16);\n\t\t\telse\n\t\t\t\tlsr(dataReg, dataReg, 16);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (signExtend)\n\t\t\t\tldrsh(dataReg, adr);\n\t\t\telse\n\t\t\t\tldrh(dataReg, adr);\n\t\t}\n\t}\n\telse if (imlInstruction->op_storeLoad.copyWidth == 8)\n\t{\n\t\tif (signExtend)\n\t\t\tldrsb(dataReg, adr);\n\t\telse\n\t\t\tldrb(dataReg, adr);\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool AArch64GenContext_t::store(IMLInstruction* imlInstruction, bool indexed)\n{\n\tcemu_assert_debug(imlInstruction->op_storeLoad.registerData.GetRegFormat() == IMLRegFormat::I32);\n\tcemu_assert_debug(imlInstruction->op_storeLoad.registerMem.GetRegFormat() == IMLRegFormat::I32);\n\tif (indexed)\n\t\tcemu_assert_debug(imlInstruction->op_storeLoad.registerMem2.GetRegFormat() == IMLRegFormat::I32);\n\n\tWReg dataReg = gpReg<WReg>(imlInstruction->op_storeLoad.registerData);\n\tWReg memReg = gpReg<WReg>(imlInstruction->op_storeLoad.registerMem);\n\tsint32 memOffset = imlInstruction->op_storeLoad.immS32;\n\tbool swapEndian = imlInstruction->op_storeLoad.flags2.swapEndian;\n\n\tadd_imm(TEMP_GPR1.WReg, memReg, memOffset, TEMP_GPR1.WReg);\n\tif (indexed)\n\t\tadd(TEMP_GPR1.WReg, TEMP_GPR1.WReg, gpReg<WReg>(imlInstruction->op_storeLoad.registerMem2));\n\tAdrExt adr = AdrExt(MEM_BASE_REG, TEMP_GPR1.WReg, ExtMod::UXTW);\n\tif (imlInstruction->op_storeLoad.copyWidth == 32)\n\t{\n\t\tif (swapEndian)\n\t\t{\n\t\t\trev(TEMP_GPR2.WReg, dataReg);\n\t\t\tstr(TEMP_GPR2.WReg, adr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstr(dataReg, adr);\n\t\t}\n\t}\n\telse if (imlInstruction->op_storeLoad.copyWidth == 16)\n\t{\n\t\tif (swapEndian)\n\t\t{\n\t\t\trev(TEMP_GPR2.WReg, dataReg);\n\t\t\tlsr(TEMP_GPR2.WReg, TEMP_GPR2.WReg, 16);\n\t\t\tstrh(TEMP_GPR2.WReg, adr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstrh(dataReg, adr);\n\t\t}\n\t}\n\telse if (imlInstruction->op_storeLoad.copyWidth == 8)\n\t{\n\t\tstrb(dataReg, adr);\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nvoid AArch64GenContext_t::atomic_cmp_store(IMLInstruction* imlInstruction)\n{\n\tWReg outReg = gpReg<WReg>(imlInstruction->op_atomic_compare_store.regBoolOut);\n\tWReg eaReg = gpReg<WReg>(imlInstruction->op_atomic_compare_store.regEA);\n\tWReg valReg = gpReg<WReg>(imlInstruction->op_atomic_compare_store.regWriteValue);\n\tWReg cmpValReg = gpReg<WReg>(imlInstruction->op_atomic_compare_store.regCompareValue);\n\n\tif (s_cpu.isAtomicSupported())\n\t{\n\t\tmov(TEMP_GPR2.WReg, cmpValReg);\n\t\tadd(TEMP_GPR1.XReg, MEM_BASE_REG, eaReg, ExtMod::UXTW);\n\t\tcasal(TEMP_GPR2.WReg, valReg, AdrNoOfs(TEMP_GPR1.XReg));\n\t\tcmp(TEMP_GPR2.WReg, cmpValReg);\n\t\tcset(outReg, Cond::EQ);\n\t}\n\telse\n\t{\n\t\tLabel notEqual;\n\t\tLabel storeFailed;\n\n\t\tadd(TEMP_GPR1.XReg, MEM_BASE_REG, eaReg, ExtMod::UXTW);\n\t\tL(storeFailed);\n\t\tldaxr(TEMP_GPR2.WReg, AdrNoOfs(TEMP_GPR1.XReg));\n\t\tcmp(TEMP_GPR2.WReg, cmpValReg);\n\t\tbne(notEqual);\n\t\tstlxr(TEMP_GPR2.WReg, valReg, AdrNoOfs(TEMP_GPR1.XReg));\n\t\tcbnz(TEMP_GPR2.WReg, storeFailed);\n\n\t\tL(notEqual);\n\t\tcset(outReg, Cond::EQ);\n\t}\n}\n\nbool AArch64GenContext_t::fpr_load(IMLInstruction* imlInstruction, bool indexed)\n{\n\tconst IMLReg& dataReg = imlInstruction->op_storeLoad.registerData;\n\tSReg dataSReg = fpReg<SReg>(dataReg);\n\tDReg dataDReg = fpReg<DReg>(dataReg);\n\tWReg realRegisterMem = gpReg<WReg>(imlInstruction->op_storeLoad.registerMem);\n\tWReg indexReg = indexed ? gpReg<WReg>(imlInstruction->op_storeLoad.registerMem2) : wzr;\n\tsint32 adrOffset = imlInstruction->op_storeLoad.immS32;\n\tuint8 mode = imlInstruction->op_storeLoad.mode;\n\n\tif (mode == PPCREC_FPR_LD_MODE_SINGLE)\n\t{\n\t\tadd_imm(TEMP_GPR1.WReg, realRegisterMem, adrOffset, TEMP_GPR1.WReg);\n\t\tif (indexed)\n\t\t\tadd(TEMP_GPR1.WReg, TEMP_GPR1.WReg, indexReg);\n\t\tldr(TEMP_GPR2.WReg, AdrExt(MEM_BASE_REG, TEMP_GPR1.WReg, ExtMod::UXTW));\n\t\trev(TEMP_GPR2.WReg, TEMP_GPR2.WReg);\n\t\tfmov(dataSReg, TEMP_GPR2.WReg);\n\n\t\tif (imlInstruction->op_storeLoad.flags2.notExpanded)\n\t\t{\n\t\t\t// leave value as single\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfcvt(dataDReg, dataSReg);\n\t\t}\n\t}\n\telse if (mode == PPCREC_FPR_LD_MODE_DOUBLE)\n\t{\n\t\tadd_imm(TEMP_GPR1.WReg, realRegisterMem, adrOffset, TEMP_GPR1.WReg);\n\t\tif (indexed)\n\t\t\tadd(TEMP_GPR1.WReg, TEMP_GPR1.WReg, indexReg);\n\t\tldr(TEMP_GPR2.XReg, AdrExt(MEM_BASE_REG, TEMP_GPR1.WReg, ExtMod::UXTW));\n\t\trev(TEMP_GPR2.XReg, TEMP_GPR2.XReg);\n\t\tfmov(dataDReg, TEMP_GPR2.XReg);\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n// store to memory\nbool AArch64GenContext_t::fpr_store(IMLInstruction* imlInstruction, bool indexed)\n{\n\tconst IMLReg& dataImlReg = imlInstruction->op_storeLoad.registerData;\n\tDReg dataDReg = fpReg<DReg>(dataImlReg);\n\tSReg dataSReg = fpReg<SReg>(dataImlReg);\n\tWReg memReg = gpReg<WReg>(imlInstruction->op_storeLoad.registerMem);\n\tWReg indexReg = indexed ? gpReg<WReg>(imlInstruction->op_storeLoad.registerMem2) : wzr;\n\tsint32 memOffset = imlInstruction->op_storeLoad.immS32;\n\tuint8 mode = imlInstruction->op_storeLoad.mode;\n\n\tif (mode == PPCREC_FPR_ST_MODE_SINGLE)\n\t{\n\t\tadd_imm(TEMP_GPR1.WReg, memReg, memOffset, TEMP_GPR1.WReg);\n\t\tif (indexed)\n\t\t\tadd(TEMP_GPR1.WReg, TEMP_GPR1.WReg, indexReg);\n\n\t\tif (imlInstruction->op_storeLoad.flags2.notExpanded)\n\t\t{\n\t\t\t// value is already in single format\n\t\t\tfmov(TEMP_GPR2.WReg, dataSReg);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfcvt(TEMP_FPR.SReg, dataDReg);\n\t\t\tfmov(TEMP_GPR2.WReg, TEMP_FPR.SReg);\n\t\t}\n\t\trev(TEMP_GPR2.WReg, TEMP_GPR2.WReg);\n\t\tstr(TEMP_GPR2.WReg, AdrExt(MEM_BASE_REG, TEMP_GPR1.WReg, ExtMod::UXTW));\n\t}\n\telse if (mode == PPCREC_FPR_ST_MODE_DOUBLE)\n\t{\n\t\tadd_imm(TEMP_GPR1.WReg, memReg, memOffset, TEMP_GPR1.WReg);\n\t\tif (indexed)\n\t\t\tadd(TEMP_GPR1.WReg, TEMP_GPR1.WReg, indexReg);\n\t\tfmov(TEMP_GPR2.XReg, dataDReg);\n\t\trev(TEMP_GPR2.XReg, TEMP_GPR2.XReg);\n\t\tstr(TEMP_GPR2.XReg, AdrExt(MEM_BASE_REG, TEMP_GPR1.WReg, ExtMod::UXTW));\n\t}\n\telse if (mode == PPCREC_FPR_ST_MODE_UI32_FROM_PS0)\n\t{\n\t\tadd_imm(TEMP_GPR1.WReg, memReg, memOffset, TEMP_GPR1.WReg);\n\t\tif (indexed)\n\t\t\tadd(TEMP_GPR1.WReg, TEMP_GPR1.WReg, indexReg);\n\t\tfmov(TEMP_GPR2.WReg, dataSReg);\n\t\trev(TEMP_GPR2.WReg, TEMP_GPR2.WReg);\n\t\tstr(TEMP_GPR2.WReg, AdrExt(MEM_BASE_REG, TEMP_GPR1.WReg, ExtMod::UXTW));\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t\tcemuLog_log(LogType::Recompiler, \"PPCRecompilerAArch64Gen_imlInstruction_fpr_store(): Unsupported mode %d\\n\", mode);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n// FPR op FPR\nvoid AArch64GenContext_t::fpr_r_r(IMLInstruction* imlInstruction)\n{\n\tauto imlRegR = imlInstruction->op_fpr_r_r.regR;\n\tauto imlRegA = imlInstruction->op_fpr_r_r.regA;\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_FPR_FLOAT_TO_INT)\n\t{\n\t\tfcvtzs(gpReg<WReg>(imlRegR), fpReg<DReg>(imlRegA));\n\t\treturn;\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_INT_TO_FLOAT)\n\t{\n\t\tscvtf(fpReg<DReg>(imlRegR), gpReg<WReg>(imlRegA));\n\t\treturn;\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_BITCAST_INT_TO_FLOAT)\n\t{\n\t\tcemu_assert_debug(imlRegR.GetRegFormat() == IMLRegFormat::F64); // assuming target is always F64 for now\n\t\t// exact operation depends on size of types. Floats are automatically promoted to double if the target is F64\n\t\tDReg regFprDReg = fpReg<DReg>(imlRegR);\n\t\tSReg regFprSReg = fpReg<SReg>(imlRegR);\n\t\tif (imlRegA.GetRegFormat() == IMLRegFormat::I32)\n\t\t{\n\t\t\tfmov(regFprSReg, gpReg<WReg>(imlRegA));\n\t\t\t// float to double\n\t\t\tfcvt(regFprDReg, regFprSReg);\n\t\t}\n\t\telse if (imlRegA.GetRegFormat() == IMLRegFormat::I64)\n\t\t{\n\t\t\tfmov(regFprDReg, gpReg<XReg>(imlRegA));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\treturn;\n\t}\n\n\tDReg regR = fpReg<DReg>(imlRegR);\n\tDReg regA = fpReg<DReg>(imlRegA);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_FPR_ASSIGN)\n\t{\n\t\tfmov(regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_MULTIPLY)\n\t{\n\t\tfmul(regR, regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_DIVIDE)\n\t{\n\t\tfdiv(regR, regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_ADD)\n\t{\n\t\tfadd(regR, regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_SUB)\n\t{\n\t\tfsub(regR, regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_FCTIWZ)\n\t{\n\t\tfcvtzs(regR, regA);\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n}\n\nvoid AArch64GenContext_t::fpr_r_r_r(IMLInstruction* imlInstruction)\n{\n\tDReg regR = fpReg<DReg>(imlInstruction->op_fpr_r_r_r.regR);\n\tDReg regA = fpReg<DReg>(imlInstruction->op_fpr_r_r_r.regA);\n\tDReg regB = fpReg<DReg>(imlInstruction->op_fpr_r_r_r.regB);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_FPR_MULTIPLY)\n\t{\n\t\tfmul(regR, regA, regB);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_ADD)\n\t{\n\t\tfadd(regR, regA, regB);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_SUB)\n\t{\n\t\tfsub(regR, regA, regB);\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n}\n\n/*\n * FPR = op (fprA, fprB, fprC)\n */\nvoid AArch64GenContext_t::fpr_r_r_r_r(IMLInstruction* imlInstruction)\n{\n\tDReg regR = fpReg<DReg>(imlInstruction->op_fpr_r_r_r_r.regR);\n\tDReg regA = fpReg<DReg>(imlInstruction->op_fpr_r_r_r_r.regA);\n\tDReg regB = fpReg<DReg>(imlInstruction->op_fpr_r_r_r_r.regB);\n\tDReg regC = fpReg<DReg>(imlInstruction->op_fpr_r_r_r_r.regC);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_FPR_SELECT)\n\t{\n\t\tfcmp(regA, 0.0);\n\t\tfcsel(regR, regC, regB, Cond::GE);\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n}\n\nvoid AArch64GenContext_t::fpr_r(IMLInstruction* imlInstruction)\n{\n\tDReg regRDReg = fpReg<DReg>(imlInstruction->op_fpr_r.regR);\n\tSReg regRSReg = fpReg<SReg>(imlInstruction->op_fpr_r.regR);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_FPR_NEGATE)\n\t{\n\t\tfneg(regRDReg, regRDReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_LOAD_ONE)\n\t{\n\t\tfmov(regRDReg, 1.0);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_ABS)\n\t{\n\t\tfabs(regRDReg, regRDReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_NEGATIVE_ABS)\n\t{\n\t\tfabs(regRDReg, regRDReg);\n\t\tfneg(regRDReg, regRDReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_BOTTOM)\n\t{\n\t\t// convert to 32bit single\n\t\tfcvt(regRSReg, regRDReg);\n\t\t// convert back to 64bit double\n\t\tfcvt(regRDReg, regRSReg);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64)\n\t{\n\t\t// convert bottom to 64bit double\n\t\tfcvt(regRDReg, regRSReg);\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n}\n\nCond ImlFPCondToArm64Cond(IMLCondition cond)\n{\n\tswitch (cond)\n\t{\n\tcase IMLCondition::UNORDERED_GT:\n\t\treturn Cond::GT;\n\tcase IMLCondition::UNORDERED_LT:\n\t\treturn Cond::MI;\n\tcase IMLCondition::UNORDERED_EQ:\n\t\treturn Cond::EQ;\n\tcase IMLCondition::UNORDERED_U:\n\t\treturn Cond::VS;\n\tdefault:\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn Cond::EQ;\n\t}\n\t}\n}\n\nvoid AArch64GenContext_t::fpr_compare(IMLInstruction* imlInstruction)\n{\n\tWReg regR = gpReg<WReg>(imlInstruction->op_fpr_compare.regR);\n\tDReg regA = fpReg<DReg>(imlInstruction->op_fpr_compare.regA);\n\tDReg regB = fpReg<DReg>(imlInstruction->op_fpr_compare.regB);\n\tauto cond = ImlFPCondToArm64Cond(imlInstruction->op_fpr_compare.cond);\n\tfcmp(regA, regB);\n\tcset(regR, cond);\n}\n\nvoid AArch64GenContext_t::call_imm(IMLInstruction* imlInstruction)\n{\n\tstr(x30, AdrPreImm(sp, -16));\n\tmov(TEMP_GPR1.XReg, imlInstruction->op_call_imm.callAddress);\n\tblr(TEMP_GPR1.XReg);\n\tldr(x30, AdrPostImm(sp, 16));\n}\n\nbool PPCRecompiler_generateAArch64Code(struct PPCRecFunction_t* PPCRecFunction, struct ppcImlGenContext_t* ppcImlGenContext)\n{\n\tAArch64Allocator allocator;\n\tAArch64GenContext_t aarch64GenContext{&allocator};\n\n\t// generate iml instruction code\n\tbool codeGenerationFailed = false;\n\tfor (IMLSegment* segIt : ppcImlGenContext->segmentList2)\n\t{\n\t\tif (codeGenerationFailed)\n\t\t\tbreak;\n\t\tsegIt->x64Offset = aarch64GenContext.getSize();\n\n\t\taarch64GenContext.storeSegmentStart(segIt);\n\n\t\tfor (size_t i = 0; i < segIt->imlList.size(); i++)\n\t\t{\n\t\t\tIMLInstruction* imlInstruction = segIt->imlList.data() + i;\n\t\t\tif (imlInstruction->type == PPCREC_IML_TYPE_R_NAME)\n\t\t\t{\n\t\t\t\taarch64GenContext.r_name(imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_NAME_R)\n\t\t\t{\n\t\t\t\taarch64GenContext.name_r(imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_R)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.r_r(imlInstruction))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_S32)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.r_s32(imlInstruction))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_R_S32)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.r_r_s32(imlInstruction))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_R_S32_CARRY)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.r_r_s32_carry(imlInstruction))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_R_R)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.r_r_r(imlInstruction))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_R_R_CARRY)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.r_r_r_carry(imlInstruction))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_COMPARE)\n\t\t\t{\n\t\t\t\taarch64GenContext.compare(imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_COMPARE_S32)\n\t\t\t{\n\t\t\t\taarch64GenContext.compare_s32(imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_CONDITIONAL_JUMP)\n\t\t\t{\n\t\t\t\taarch64GenContext.cjump(imlInstruction, segIt);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_JUMP)\n\t\t\t{\n\t\t\t\taarch64GenContext.jump(segIt);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK)\n\t\t\t{\n\t\t\t\taarch64GenContext.conditionalJumpCycleCheck(segIt);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_MACRO)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.macro(imlInstruction))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_LOAD)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.load(imlInstruction, false))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_LOAD_INDEXED)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.load(imlInstruction, true))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_STORE)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.store(imlInstruction, false))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_STORE_INDEXED)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.store(imlInstruction, true))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_ATOMIC_CMP_STORE)\n\t\t\t{\n\t\t\t\taarch64GenContext.atomic_cmp_store(imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_CALL_IMM)\n\t\t\t{\n\t\t\t\taarch64GenContext.call_imm(imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_NO_OP)\n\t\t\t{\n\t\t\t\t// no op\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.fpr_load(imlInstruction, false))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.fpr_load(imlInstruction, true))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.fpr_store(imlInstruction, false))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE_INDEXED)\n\t\t\t{\n\t\t\t\tif (!aarch64GenContext.fpr_store(imlInstruction, true))\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_R_R)\n\t\t\t{\n\t\t\t\taarch64GenContext.fpr_r_r(imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_R_R_R)\n\t\t\t{\n\t\t\t\taarch64GenContext.fpr_r_r_r(imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_R_R_R_R)\n\t\t\t{\n\t\t\t\taarch64GenContext.fpr_r_r_r_r(imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_R)\n\t\t\t{\n\t\t\t\taarch64GenContext.fpr_r(imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_COMPARE)\n\t\t\t{\n\t\t\t\taarch64GenContext.fpr_compare(imlInstruction);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcodeGenerationFailed = true;\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t\tcemuLog_log(LogType::Recompiler, \"PPCRecompiler_generateAArch64Code(): Unsupported iml type {}\", imlInstruction->type);\n\t\t\t}\n\t\t}\n\t}\n\n\t// handle failed code generation\n\tif (codeGenerationFailed)\n\t{\n\t\treturn false;\n\t}\n\n\tif (!aarch64GenContext.processAllJumps())\n\t{\n\t\tcemuLog_log(LogType::Recompiler, \"PPCRecompiler_generateAArch64Code(): some jumps exceeded the +/-128MB offset.\");\n\t\treturn false;\n\t}\n\n\taarch64GenContext.readyRE();\n\n\t// set code\n\tPPCRecFunction->x86Code = aarch64GenContext.getCode<void*>();\n\tPPCRecFunction->x86Size = aarch64GenContext.getMaxSize();\n\t// set free disabled to skip freeing the code from the CodeGenerator destructor\n\tallocator.setFreeDisabled(true);\n\treturn true;\n}\n\nvoid PPCRecompiler_cleanupAArch64Code(void* code, size_t size)\n{\n\tAArch64Allocator allocator;\n\tif (allocator.useProtect())\n\t\tCodeArray::protect(code, size, CodeArray::PROTECT_RW);\n\tallocator.free(static_cast<uint32*>(code));\n}\n\nvoid AArch64GenContext_t::enterRecompilerCode()\n{\n\tconstexpr size_t STACK_SIZE = 160 /* x19 .. x30 + v8.d[0] .. v15.d[0] */;\n\tstatic_assert(STACK_SIZE % 16 == 0);\n\tsub(sp, sp, STACK_SIZE);\n\tmov(x9, sp);\n\n\tstp(x19, x20, AdrPostImm(x9, 16));\n\tstp(x21, x22, AdrPostImm(x9, 16));\n\tstp(x23, x24, AdrPostImm(x9, 16));\n\tstp(x25, x26, AdrPostImm(x9, 16));\n\tstp(x27, x28, AdrPostImm(x9, 16));\n\tstp(x29, x30, AdrPostImm(x9, 16));\n\tst4((v8.d - v11.d)[0], AdrPostImm(x9, 32));\n\tst4((v12.d - v15.d)[0], AdrPostImm(x9, 32));\n\tmov(HCPU_REG, x1); // call argument 2\n\tmov(PPC_REC_INSTANCE_REG, (uint64)ppcRecompilerInstanceData);\n\tmov(MEM_BASE_REG, (uint64)memory_base);\n\n\t// branch to recFunc\n\tblr(x0); // call argument 1\n\n\tmov(x9, sp);\n\tldp(x19, x20, AdrPostImm(x9, 16));\n\tldp(x21, x22, AdrPostImm(x9, 16));\n\tldp(x23, x24, AdrPostImm(x9, 16));\n\tldp(x25, x26, AdrPostImm(x9, 16));\n\tldp(x27, x28, AdrPostImm(x9, 16));\n\tldp(x29, x30, AdrPostImm(x9, 16));\n\tld4((v8.d - v11.d)[0], AdrPostImm(x9, 32));\n\tld4((v12.d - v15.d)[0], AdrPostImm(x9, 32));\n\n\tadd(sp, sp, STACK_SIZE);\n\n\tret();\n}\n\nvoid AArch64GenContext_t::leaveRecompilerCode()\n{\n\tstr(LR.WReg, AdrUimm(HCPU_REG, offsetof(PPCInterpreter_t, instructionPointer)));\n\tret();\n}\n\nbool initializedInterfaceFunctions = false;\nAArch64GenContext_t enterRecompilerCode_ctx{};\n\nAArch64GenContext_t leaveRecompilerCode_unvisited_ctx{};\nAArch64GenContext_t leaveRecompilerCode_visited_ctx{};\nvoid PPCRecompilerAArch64Gen_generateRecompilerInterfaceFunctions()\n{\n\tif (initializedInterfaceFunctions)\n\t\treturn;\n\tinitializedInterfaceFunctions = true;\n\n\tenterRecompilerCode_ctx.enterRecompilerCode();\n\tenterRecompilerCode_ctx.readyRE();\n\tPPCRecompiler_enterRecompilerCode = enterRecompilerCode_ctx.getCode<decltype(PPCRecompiler_enterRecompilerCode)>();\n\n\tleaveRecompilerCode_unvisited_ctx.leaveRecompilerCode();\n\tleaveRecompilerCode_unvisited_ctx.readyRE();\n\tPPCRecompiler_leaveRecompilerCode_unvisited = leaveRecompilerCode_unvisited_ctx.getCode<decltype(PPCRecompiler_leaveRecompilerCode_unvisited)>();\n\n\tleaveRecompilerCode_visited_ctx.leaveRecompilerCode();\n\tleaveRecompilerCode_visited_ctx.readyRE();\n\tPPCRecompiler_leaveRecompilerCode_visited = leaveRecompilerCode_visited_ctx.getCode<decltype(PPCRecompiler_leaveRecompilerCode_visited)>();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendAArch64/BackendAArch64.h",
    "content": "#pragma once\n\n#include \"HW/Espresso/Recompiler/IML/IMLInstruction.h\"\n#include \"../PPCRecompiler.h\"\n\nbool PPCRecompiler_generateAArch64Code(struct PPCRecFunction_t* PPCRecFunction, struct ppcImlGenContext_t* ppcImlGenContext);\nvoid PPCRecompiler_cleanupAArch64Code(void* code, size_t size);\n\nvoid PPCRecompilerAArch64Gen_generateRecompilerInterfaceFunctions();\n\n// architecture specific constants\nnamespace IMLArchAArch64\n{\n\tstatic constexpr int PHYSREG_GPR_BASE = 0;\n\tstatic constexpr int PHYSREG_GPR_COUNT = 25;\n\tstatic constexpr int PHYSREG_FPR_BASE = PHYSREG_GPR_COUNT;\n\tstatic constexpr int PHYSREG_FPR_COUNT = 31;\n}; // namespace IMLArchAArch64"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64.cpp",
    "content": "#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterHelper.h\"\n#include \"../PPCRecompiler.h\"\n#include \"../PPCRecompilerIml.h\"\n#include \"BackendX64.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"util/MemMapper/MemMapper.h\"\n#include \"Common/cpu_features.h\"\n#include <boost/container/static_vector.hpp>\n\nstatic x86Assembler64::GPR32 _reg32(IMLReg physReg)\n{\n\tcemu_assert_debug(physReg.GetRegFormat() == IMLRegFormat::I32);\n\tIMLRegID regId = physReg.GetRegID();\n\tcemu_assert_debug(regId < 16);\n\treturn (x86Assembler64::GPR32)regId;\n}\n\nstatic uint32 _reg64(IMLReg physReg)\n{\n\tcemu_assert_debug(physReg.GetRegFormat() == IMLRegFormat::I64);\n\tIMLRegID regId = physReg.GetRegID();\n\tcemu_assert_debug(regId < 16);\n\treturn regId;\n}\n\nuint32 _regF64(IMLReg physReg)\n{\n\tcemu_assert_debug(physReg.GetRegFormat() == IMLRegFormat::F64);\n\tIMLRegID regId = physReg.GetRegID();\n\tcemu_assert_debug(regId >= IMLArchX86::PHYSREG_FPR_BASE && regId < IMLArchX86::PHYSREG_FPR_BASE+16);\n\tregId -= IMLArchX86::PHYSREG_FPR_BASE;\n\treturn regId;\n}\n\nstatic x86Assembler64::GPR8_REX _reg8(IMLReg physReg)\n{\n\tcemu_assert_debug(physReg.GetRegFormat() == IMLRegFormat::I32); // for now these are represented as 32bit\n\treturn (x86Assembler64::GPR8_REX)physReg.GetRegID();\n}\n\nstatic x86Assembler64::GPR32 _reg32_from_reg8(x86Assembler64::GPR8_REX regId)\n{\n\treturn (x86Assembler64::GPR32)regId;\n}\n\nstatic x86Assembler64::GPR8_REX _reg8_from_reg32(x86Assembler64::GPR32 regId)\n{\n\treturn (x86Assembler64::GPR8_REX)regId;\n}\n\nstatic x86Assembler64::GPR8_REX _reg8_from_reg64(uint32 regId)\n{\n\treturn (x86Assembler64::GPR8_REX)regId;\n}\n\nstatic x86Assembler64::GPR64 _reg64_from_reg32(x86Assembler64::GPR32 regId)\n{\n\treturn (x86Assembler64::GPR64)regId;\n}\n\nX86Cond _x86Cond(IMLCondition imlCond)\n{\n\tswitch (imlCond)\n\t{\n\tcase IMLCondition::EQ:\n\t\treturn X86_CONDITION_Z;\n\tcase IMLCondition::NEQ:\n\t\treturn X86_CONDITION_NZ;\n\tcase IMLCondition::UNSIGNED_GT:\n\t\treturn X86_CONDITION_NBE;\n\tcase IMLCondition::UNSIGNED_LT:\n\t\treturn X86_CONDITION_B;\n\tcase IMLCondition::SIGNED_GT:\n\t\treturn X86_CONDITION_NLE;\n\tcase IMLCondition::SIGNED_LT:\n\t\treturn X86_CONDITION_L;\n\tdefault:\n\t\tbreak;\n\t}\n\tcemu_assert_suspicious();\n\treturn X86_CONDITION_Z;\n}\n\nX86Cond _x86CondInverted(IMLCondition imlCond)\n{\n\tswitch (imlCond)\n\t{\n\tcase IMLCondition::EQ:\n\t\treturn X86_CONDITION_NZ;\n\tcase IMLCondition::NEQ:\n\t\treturn X86_CONDITION_Z;\n\tcase IMLCondition::UNSIGNED_GT:\n\t\treturn X86_CONDITION_BE;\n\tcase IMLCondition::UNSIGNED_LT:\n\t\treturn X86_CONDITION_NB;\n\tcase IMLCondition::SIGNED_GT:\n\t\treturn X86_CONDITION_LE;\n\tcase IMLCondition::SIGNED_LT:\n\t\treturn X86_CONDITION_NL;\n\tdefault:\n\t\tbreak;\n\t}\n\tcemu_assert_suspicious();\n\treturn X86_CONDITION_Z;\n}\n\nX86Cond _x86Cond(IMLCondition imlCond, bool condIsInverted)\n{\n\tif (condIsInverted)\n\t\treturn _x86CondInverted(imlCond);\n\treturn _x86Cond(imlCond);\n}\n\n/*\n* Remember current instruction output offset for reloc\n* The instruction generated after this method has been called will be adjusted\n*/\nvoid PPCRecompilerX64Gen_rememberRelocatableOffset(x64GenContext_t* x64GenContext, void* extraInfo = nullptr)\n{\n\tx64GenContext->relocateOffsetTable2.emplace_back(x64GenContext->emitter->GetWriteIndex(), extraInfo);\n}\n\nvoid PPCRecompilerX64Gen_redirectRelativeJump(x64GenContext_t* x64GenContext, sint32 jumpInstructionOffset, sint32 destinationOffset)\n{\n\tuint8* instructionData = x64GenContext->emitter->GetBufferPtr() + jumpInstructionOffset;\n\tif (instructionData[0] == 0x0F && (instructionData[1] >= 0x80 && instructionData[1] <= 0x8F))\n\t{\n\t\t// far conditional jump\n\t\t*(uint32*)(instructionData + 2) = (destinationOffset - (jumpInstructionOffset + 6));\n\t}\n\telse if (instructionData[0] >= 0x70 && instructionData[0] <= 0x7F)\n\t{\n\t\t// short conditional jump\n\t\tsint32 distance = (sint32)((destinationOffset - (jumpInstructionOffset + 2)));\n\t\tcemu_assert_debug(distance >= -128 && distance <= 127);\n\t\t*(uint8*)(instructionData + 1) = (uint8)distance;\n\t}\n\telse if (instructionData[0] == 0xE9)\n\t{\n\t\t*(uint32*)(instructionData + 1) = (destinationOffset - (jumpInstructionOffset + 5));\n\t}\n\telse if (instructionData[0] == 0xEB)\n\t{\n\t\tsint32 distance = (sint32)((destinationOffset - (jumpInstructionOffset + 2)));\n\t\tcemu_assert_debug(distance >= -128 && distance <= 127);\n\t\t*(uint8*)(instructionData + 1) = (uint8)distance;\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid* ATTR_MS_ABI PPCRecompiler_virtualHLE(PPCInterpreter_t* hCPU, uint32 hleFuncId)\n{\n\tvoid* prevRSPTemp = hCPU->rspTemp;\n\tif( hleFuncId == 0xFFD0 )\n\t{\n\t\thCPU->remainingCycles -= 500; // let subtract about 500 cycles for each HLE call\n\t\thCPU->gpr[3] = 0;\n\t\tPPCInterpreter_nextInstruction(hCPU);\n\t\treturn hCPU;\n\t}\n\telse\n\t{\n\t\tauto hleCall = PPCInterpreter_getHLECall(hleFuncId);\n\t\tcemu_assert(hleCall != nullptr);\n\t\thleCall(hCPU);\n\t}\n\thCPU->rspTemp = prevRSPTemp;\n\treturn PPCInterpreter_getCurrentInstance();\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_macro(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tif (imlInstruction->operation == PPCREC_IML_MACRO_B_TO_REG)\n\t{\n\t\t//x64Gen_int3(x64GenContext);\n\t\tuint32 branchDstReg = _reg32(imlInstruction->op_macro.paramReg);\n\t\tif(X86_REG_RDX != branchDstReg)\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, X86_REG_RDX, branchDstReg);\n\t\t// potential optimization: Use branchDstReg directly if possible instead of moving to RDX/EDX\n\t\t// JMP [offset+RDX*(8/4)+R15]\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\tx64Gen_writeU8(x64GenContext, 0xA4);\n\t\tx64Gen_writeU8(x64GenContext, 0x57);\n\t\tx64Gen_writeU32(x64GenContext, (uint32)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));\n\t\treturn true;\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_MACRO_BL )\n\t{\n\t\t// MOV DWORD [SPR_LinkRegister], newLR\n\t\tuint32 newLR = imlInstruction->op_macro.param + 4;\n\t\tx64Gen_mov_mem32Reg64_imm32(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, spr.LR), newLR);\n\t\t// remember new instruction pointer in RDX\n\t\tuint32 newIP = imlInstruction->op_macro.param2;\n\t\tx64Gen_mov_reg64Low32_imm32(x64GenContext, X86_REG_RDX, newIP);\n\t\t// since RDX is constant we can use JMP [R15+const_offset] if jumpTableOffset+RDX*2 does not exceed the 2GB boundary\n\t\tuint64 lookupOffset = (uint64)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable) + (uint64)newIP * 2ULL;\n\t\tif (lookupOffset >= 0x80000000ULL)\n\t\t{\n\t\t\t// JMP [offset+RDX*(8/4)+R15]\n\t\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xA4);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x57);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xA7);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)lookupOffset);\n\t\t}\n\t\treturn true;\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_MACRO_B_FAR )\n\t{\n\t\t// remember new instruction pointer in RDX\n\t\tuint32 newIP = imlInstruction->op_macro.param2;\n\t\tx64Gen_mov_reg64Low32_imm32(x64GenContext, X86_REG_RDX, newIP);\n\t\t// Since RDX is constant we can use JMP [R15+const_offset] if jumpTableOffset+RDX*2 does not exceed the 2GB boundary\n\t\tuint64 lookupOffset = (uint64)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable) + (uint64)newIP * 2ULL;\n\t\tif (lookupOffset >= 0x80000000ULL)\n\t\t{\n\t\t\t// JMP [offset+RDX*(8/4)+R15]\n\t\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xA4);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x57);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xA7);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)lookupOffset);\n\t\t}\n\t\treturn true;\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_MACRO_LEAVE )\n\t{\n\t\tuint32 currentInstructionAddress = imlInstruction->op_macro.param;\n\t\t// remember PC value in REG_EDX\n\t\tx64Gen_mov_reg64Low32_imm32(x64GenContext, X86_REG_RDX, currentInstructionAddress);\n\n\t\tuint32 newIP = 0; // special value for recompiler exit\n\t\tuint64 lookupOffset = (uint64)&(((PPCRecompilerInstanceData_t*)NULL)->ppcRecompilerDirectJumpTable) + (uint64)newIP * 2ULL;\n\t\t// JMP [R15+offset]\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\tx64Gen_writeU8(x64GenContext, 0xA7);\n\t\tx64Gen_writeU32(x64GenContext, (uint32)lookupOffset);\n\t\treturn true;\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_MACRO_DEBUGBREAK )\n\t{\n\t\tx64Gen_mov_reg64Low32_imm32(x64GenContext, REG_RESV_TEMP, imlInstruction->op_macro.param2);\n\t\tx64Gen_int3(x64GenContext);\n\t\treturn true;\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_MACRO_COUNT_CYCLES )\n\t{\n\t\tuint32 cycleCount = imlInstruction->op_macro.param;\n\t\tx64Gen_sub_mem32reg64_imm32(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, remainingCycles), cycleCount);\n\t\treturn true;\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_MACRO_HLE )\n\t{\n\t\tuint32 ppcAddress = imlInstruction->op_macro.param;\n\t\tuint32 funcId = imlInstruction->op_macro.param2;\n\t\t// update instruction pointer\n\t\tx64Gen_mov_mem32Reg64_imm32(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, instructionPointer), ppcAddress);\n\t\t// set parameters\n\t\tx64Gen_mov_reg64_reg64(x64GenContext, X86_REG_RCX, REG_RESV_HCPU);\n\t\tx64Gen_mov_reg64_imm64(x64GenContext, X86_REG_RDX, funcId);\n\t\t// restore stackpointer from hCPU->rspTemp\n\t\tx64Emit_mov_reg64_mem64(x64GenContext, X86_REG_RSP, REG_RESV_HCPU, offsetof(PPCInterpreter_t, rspTemp));\n\t\t// reserve space on stack for call parameters\n\t\tx64Gen_sub_reg64_imm32(x64GenContext, X86_REG_RSP, 8*11); // must be uneven number in order to retain stack 0x10 alignment\n\t\tx64Gen_mov_reg64_imm64(x64GenContext, X86_REG_RBP, 0);\n\t\t// call HLE function\n\t\tx64Gen_mov_reg64_imm64(x64GenContext, X86_REG_RAX, (uint64)PPCRecompiler_virtualHLE);\n\t\tx64Gen_call_reg64(x64GenContext, X86_REG_RAX);\n\t\t// restore RSP to hCPU (from RAX, result of PPCRecompiler_virtualHLE)\n\t\tx64Gen_mov_reg64_reg64(x64GenContext, REG_RESV_HCPU, X86_REG_RAX);\n\t\t// MOV R15, ppcRecompilerInstanceData\n\t\tx64Gen_mov_reg64_imm64(x64GenContext, REG_RESV_RECDATA, (uint64)ppcRecompilerInstanceData);\n\t\t// MOV R13, memory_base\n\t\tx64Gen_mov_reg64_imm64(x64GenContext, REG_RESV_MEMBASE, (uint64)memory_base);\n\t\t// check if cycles where decreased beyond zero, if yes -> leave recompiler\n\t\tx64Gen_bt_mem8(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, remainingCycles), 31); // check if negative\n\t\tsint32 jumpInstructionOffset1 = x64GenContext->emitter->GetWriteIndex();\n\t\tx64Gen_jmpc_near(x64GenContext, X86_CONDITION_NOT_CARRY, 0);\n\n\t\tx64Emit_mov_reg64_mem32(x64GenContext, X86_REG_RDX, REG_RESV_HCPU, offsetof(PPCInterpreter_t, instructionPointer));\n\t\t// set EAX to 0 (we assume that ppcRecompilerDirectJumpTable[0] will be a recompiler escape function)\n\t\tx64Gen_xor_reg32_reg32(x64GenContext, X86_REG_RAX, X86_REG_RAX);\n\t\t// ADD RAX, REG_RESV_RECDATA\n\t\tx64Gen_add_reg64_reg64(x64GenContext, X86_REG_RAX, REG_RESV_RECDATA);\n\t\t// JMP [recompilerCallTable+EAX/4*8]\n\t\tx64Gen_jmp_memReg64(x64GenContext, X86_REG_RAX, (uint32)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));\n\t\tPPCRecompilerX64Gen_redirectRelativeJump(x64GenContext, jumpInstructionOffset1, x64GenContext->emitter->GetWriteIndex());\n\t\t// check if instruction pointer was changed\n\t\t// assign new instruction pointer to EAX\n\t\tx64Emit_mov_reg64_mem32(x64GenContext, X86_REG_RAX, REG_RESV_HCPU, offsetof(PPCInterpreter_t, instructionPointer));\n\t\t// remember instruction pointer in REG_EDX\n\t\tx64Gen_mov_reg64_reg64(x64GenContext, X86_REG_RDX, X86_REG_RAX);\n\t\t// EAX *= 2\n\t\tx64Gen_add_reg64_reg64(x64GenContext, X86_REG_RAX, X86_REG_RAX);\n\t\t// ADD RAX, REG_RESV_RECDATA\n\t\tx64Gen_add_reg64_reg64(x64GenContext, X86_REG_RAX, REG_RESV_RECDATA);\n\t\t// JMP [ppcRecompilerDirectJumpTable+RAX/4*8]\n\t\tx64Gen_jmp_memReg64(x64GenContext, X86_REG_RAX, (uint32)offsetof(PPCRecompilerInstanceData_t, ppcRecompilerDirectJumpTable));\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tdebug_printf(\"Unknown recompiler macro operation %d\\n\", imlInstruction->operation);\n\t\tassert_dbg();\n\t}\n\treturn false;\n}\n\n/*\n* Load from memory\n*/\nbool PPCRecompilerX64Gen_imlInstruction_load(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, bool indexed)\n{\n\tcemu_assert_debug(imlInstruction->op_storeLoad.registerData.GetRegFormat() == IMLRegFormat::I32);\n\tcemu_assert_debug(imlInstruction->op_storeLoad.registerMem.GetRegFormat() == IMLRegFormat::I32);\n\tif (indexed)\n\t\tcemu_assert_debug(imlInstruction->op_storeLoad.registerMem2.GetRegFormat() == IMLRegFormat::I32);\n\n\tIMLRegID realRegisterData = imlInstruction->op_storeLoad.registerData.GetRegID();\n\tIMLRegID realRegisterMem = imlInstruction->op_storeLoad.registerMem.GetRegID();\n\tIMLRegID realRegisterMem2 = PPC_REC_INVALID_REGISTER;\n\tif( indexed )\n\t\trealRegisterMem2 = imlInstruction->op_storeLoad.registerMem2.GetRegID();\n\tif( indexed && realRegisterMem == realRegisterMem2 )\n\t{\n\t\treturn false;\n\t}\n\tif( indexed && realRegisterData == realRegisterMem2 )\n\t{\n\t\t// for indexed memory access realRegisterData must not be the same register as the second memory register,\n\t\t// this can easily be worked around by swapping realRegisterMem and realRegisterMem2\n\t\tstd::swap(realRegisterMem, realRegisterMem2);\n\t}\n\n\tbool signExtend = imlInstruction->op_storeLoad.flags2.signExtend;\n\tbool switchEndian = imlInstruction->op_storeLoad.flags2.swapEndian;\n\tif( imlInstruction->op_storeLoad.copyWidth == 32 )\n\t{\n\t\tif (indexed)\n\t\t{\n\t\t\tx64Gen_lea_reg64Low32_reg64Low32PlusReg64Low32(x64GenContext, REG_RESV_TEMP, realRegisterMem, realRegisterMem2);\n\t\t}\n\t\tif( g_CPUFeatures.x86.movbe && switchEndian )\n\t\t{\n\t\t\tif (indexed)\n\t\t\t{\n\t\t\t\tx64Gen_movBEZeroExtend_reg64_mem32Reg64PlusReg64(x64GenContext, realRegisterData, REG_RESV_MEMBASE, REG_RESV_TEMP, imlInstruction->op_storeLoad.immS32);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tx64Gen_movBEZeroExtend_reg64_mem32Reg64PlusReg64(x64GenContext, realRegisterData, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (indexed)\n\t\t\t{\n\t\t\t\tx64Emit_mov_reg32_mem32(x64GenContext, realRegisterData, REG_RESV_MEMBASE, REG_RESV_TEMP, imlInstruction->op_storeLoad.immS32);\n\t\t\t\tif (switchEndian)\n\t\t\t\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, realRegisterData);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tx64Emit_mov_reg32_mem32(x64GenContext, realRegisterData, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32);\n\t\t\t\tif (switchEndian)\n\t\t\t\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, realRegisterData);\n\t\t\t}\n\t\t}\n\t}\n\telse if( imlInstruction->op_storeLoad.copyWidth == 16 )\n\t{\n\t\tif (indexed)\n\t\t{\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\t}\t\t\t\n\t\tif(g_CPUFeatures.x86.movbe && switchEndian )\n\t\t{\n\t\t\tx64Gen_movBEZeroExtend_reg64Low16_mem16Reg64PlusReg64(x64GenContext, realRegisterData, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32);\n\t\t\tif( indexed && realRegisterMem != realRegisterData )\n\t\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_movZeroExtend_reg64Low16_mem16Reg64PlusReg64(x64GenContext, realRegisterData, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32);\n\t\t\tif( indexed && realRegisterMem != realRegisterData )\n\t\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\t\tif( switchEndian )\n\t\t\t\tx64Gen_rol_reg64Low16_imm8(x64GenContext, realRegisterData, 8);\n\t\t}\n\t\tif( signExtend )\n\t\t\tx64Gen_movSignExtend_reg64Low32_reg64Low16(x64GenContext, realRegisterData, realRegisterData);\n\t\telse\n\t\t\tx64Gen_movZeroExtend_reg64Low32_reg64Low16(x64GenContext, realRegisterData, realRegisterData);\n\t}\n\telse if( imlInstruction->op_storeLoad.copyWidth == 8 )\n\t{\n\t\tif( indexed )\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\tif( signExtend )\n\t\t\tx64Gen_movSignExtend_reg64Low32_mem8Reg64PlusReg64(x64GenContext, realRegisterData, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32);\n\t\telse\n\t\t\tx64Emit_movZX_reg32_mem8(x64GenContext, realRegisterData, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32);\n\t\tif( indexed && realRegisterMem != realRegisterData )\n\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t}\n\telse\n\t\treturn false;\n\treturn true;\n}\n\n/*\n* Write to memory\n*/\nbool PPCRecompilerX64Gen_imlInstruction_store(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, bool indexed)\n{\n\tcemu_assert_debug(imlInstruction->op_storeLoad.registerData.GetRegFormat() == IMLRegFormat::I32);\n\tcemu_assert_debug(imlInstruction->op_storeLoad.registerMem.GetRegFormat() == IMLRegFormat::I32);\n\tif (indexed)\n\t\tcemu_assert_debug(imlInstruction->op_storeLoad.registerMem2.GetRegFormat() == IMLRegFormat::I32);\n\n\tIMLRegID realRegisterData = imlInstruction->op_storeLoad.registerData.GetRegID();\n\tIMLRegID realRegisterMem = imlInstruction->op_storeLoad.registerMem.GetRegID();\n\tIMLRegID realRegisterMem2 = PPC_REC_INVALID_REGISTER;\n\tif (indexed)\n\t\trealRegisterMem2 = imlInstruction->op_storeLoad.registerMem2.GetRegID();\n\n\tif (indexed && realRegisterMem == realRegisterMem2)\n\t{\n\t\treturn false;\n\t}\n\tif (indexed && realRegisterData == realRegisterMem2)\n\t{\n\t\t// for indexed memory access realRegisterData must not be the same register as the second memory register,\n\t\t// this can easily be worked around by swapping realRegisterMem and realRegisterMem2\n\t\tstd::swap(realRegisterMem, realRegisterMem2);\n\t}\n\n\tbool signExtend = imlInstruction->op_storeLoad.flags2.signExtend;\n\tbool swapEndian = imlInstruction->op_storeLoad.flags2.swapEndian;\n\tif (imlInstruction->op_storeLoad.copyWidth == 32)\n\t{\n\t\tuint32 valueRegister;\n\t\tif ((swapEndian == false || g_CPUFeatures.x86.movbe) && realRegisterMem != realRegisterData)\n\t\t{\n\t\t\tvalueRegister = realRegisterData;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, REG_RESV_TEMP, realRegisterData);\n\t\t\tvalueRegister = REG_RESV_TEMP;\n\t\t}\n\t\tif (!g_CPUFeatures.x86.movbe && swapEndian)\n\t\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, valueRegister);\n\t\tif (indexed)\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\tif (g_CPUFeatures.x86.movbe && swapEndian)\n\t\t\tx64Gen_movBETruncate_mem32Reg64PlusReg64_reg64(x64GenContext, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32, valueRegister);\n\t\telse\n\t\t\tx64Gen_movTruncate_mem32Reg64PlusReg64_reg64(x64GenContext, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32, valueRegister);\n\t\tif (indexed)\n\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t}\n\telse if (imlInstruction->op_storeLoad.copyWidth == 16)\n\t{\n\t\tx64Gen_mov_reg64_reg64(x64GenContext, REG_RESV_TEMP, realRegisterData);\n\t\tif (swapEndian)\n\t\t\tx64Gen_rol_reg64Low16_imm8(x64GenContext, REG_RESV_TEMP, 8);\n\t\tif (indexed)\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\tx64Gen_movTruncate_mem16Reg64PlusReg64_reg64(x64GenContext, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32, REG_RESV_TEMP);\n\t\tif (indexed)\n\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\t// todo: Optimize this, e.g. by using MOVBE\n\t}\n\telse if (imlInstruction->op_storeLoad.copyWidth == 8)\n\t{\n\t\tif (indexed && realRegisterMem == realRegisterData)\n\t\t{\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, REG_RESV_TEMP, realRegisterData);\n\t\t\trealRegisterData = REG_RESV_TEMP;\n\t\t}\n\t\tif (indexed)\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\tx64Gen_movTruncate_mem8Reg64PlusReg64_reg64(x64GenContext, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32, realRegisterData);\n\t\tif (indexed)\n\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t}\n\telse\n\t\treturn false;\n\treturn true;\n}\n\nvoid PPCRecompilerX64Gen_imlInstruction_atomic_cmp_store(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tauto regBoolOut = _reg32_from_reg8(_reg8(imlInstruction->op_atomic_compare_store.regBoolOut));\n\tauto regEA = _reg32(imlInstruction->op_atomic_compare_store.regEA);\n\tauto regVal = _reg32(imlInstruction->op_atomic_compare_store.regWriteValue);\n\tauto regCmp = _reg32(imlInstruction->op_atomic_compare_store.regCompareValue);\n\n\tcemu_assert_debug(regBoolOut == X86_REG_EAX);\n\tcemu_assert_debug(regEA != X86_REG_EAX);\n\tcemu_assert_debug(regVal != X86_REG_EAX);\n\tcemu_assert_debug(regCmp != X86_REG_EAX);\n\n\tx64GenContext->emitter->MOV_dd(X86_REG_EAX, regCmp);\n\tx64GenContext->emitter->LockPrefix();\n\tx64GenContext->emitter->CMPXCHG_dd_l(REG_RESV_MEMBASE, 0, _reg64_from_reg32(regEA), 1, regVal);\n\tx64GenContext->emitter->SETcc_b(X86Cond::X86_CONDITION_Z, regBoolOut);\n\tx64GenContext->emitter->AND_di32(regBoolOut, 1); // SETcc doesn't clear the upper bits so we do it manually here\n}\n\nvoid PPCRecompilerX64Gen_imlInstruction_call_imm(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\t// the register allocator takes care of spilling volatile registers and moving parameters to the right registers, so we don't need to do any special handling here\n\tx64GenContext->emitter->SUB_qi8(X86_REG_RSP, 0x20); // reserve enough space for any parameters while keeping stack alignment of 16 intact\n\tx64GenContext->emitter->MOV_qi64(X86_REG_RAX, imlInstruction->op_call_imm.callAddress);\n\tx64GenContext->emitter->CALL_q(X86_REG_RAX);\n\tx64GenContext->emitter->ADD_qi8(X86_REG_RSP, 0x20);\n\t// a note about the stack pointer:\n\t// currently the code generated by generateEnterRecompilerCode makes sure the stack is 16 byte aligned, so we don't need to fix it up here\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tauto regR = _reg32(imlInstruction->op_r_r.regR);\n\tauto regA = _reg32(imlInstruction->op_r_r.regA);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_ASSIGN)\n\t{\n\t\t// registerResult = registerA\n\t\tif (regR != regA)\n\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_ENDIAN_SWAP)\n\t{\n\t\tif (regA != regR)\n\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, regR, regA); // if movbe is available we can move and swap in a single instruction?\n\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, regR);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_ASSIGN_S8_TO_S32 )\n\t{\n\t\tx64Gen_movSignExtend_reg64Low32_reg64Low8(x64GenContext, regR, regA);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_ASSIGN_S16_TO_S32)\n\t{\n\t\tx64Gen_movSignExtend_reg64Low32_reg64Low16(x64GenContext, regR, reg32ToReg16(regA));\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_NOT )\n\t{\n\t\t// copy register content if different registers\n\t\tif( regR != regA )\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, regR, regA);\n\t\tx64Gen_not_reg64Low32(x64GenContext, regR);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_NEG)\n\t{\n\t\t// copy register content if different registers\n\t\tif (regR != regA)\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, regR, regA);\n\t\tx64Gen_neg_reg64Low32(x64GenContext, regR);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_CNTLZW )\n\t{\n\t\t// count leading zeros\n\t\t// LZCNT instruction (part of SSE4, CPUID.80000001H:ECX.ABM[Bit 5])\n\t\tif(g_CPUFeatures.x86.lzcnt)\n\t\t{\n\t\t\tx64Gen_lzcnt_reg64Low32_reg64Low32(x64GenContext, regR, regA);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_test_reg64Low32_reg64Low32(x64GenContext, regA, regA);\n\t\t\tsint32 jumpInstructionOffset1 = x64GenContext->emitter->GetWriteIndex();\n\t\t\tx64Gen_jmpc_near(x64GenContext, X86_CONDITION_EQUAL, 0);\n\t\t\tx64Gen_bsr_reg64Low32_reg64Low32(x64GenContext, regR, regA);\n\t\t\tx64Gen_neg_reg64Low32(x64GenContext, regR);\n\t\t\tx64Gen_add_reg64Low32_imm32(x64GenContext, regR, 32-1);\n\t\t\tsint32 jumpInstructionOffset2 = x64GenContext->emitter->GetWriteIndex();\n\t\t\tx64Gen_jmpc_near(x64GenContext, X86_CONDITION_NONE, 0);\n\t\t\tPPCRecompilerX64Gen_redirectRelativeJump(x64GenContext, jumpInstructionOffset1, x64GenContext->emitter->GetWriteIndex());\n\t\t\tx64Gen_mov_reg64Low32_imm32(x64GenContext, regR, 32);\n\t\t\tPPCRecompilerX64Gen_redirectRelativeJump(x64GenContext, jumpInstructionOffset2, x64GenContext->emitter->GetWriteIndex());\n\t\t}\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_X86_CMP)\n\t{\n\t\tx64GenContext->emitter->CMP_dd(regR, regA);\n\t}\n\telse\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"PPCRecompilerX64Gen_imlInstruction_r_r(): Unsupported operation 0x%x\\n\", imlInstruction->operation);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_r_s32(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tauto regR = _reg32(imlInstruction->op_r_immS32.regR);\n\n\tif( imlInstruction->operation == PPCREC_IML_OP_ASSIGN )\n\t{\n\t\tx64Gen_mov_reg64Low32_imm32(x64GenContext, regR, (uint32)imlInstruction->op_r_immS32.immS32);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_LEFT_ROTATE )\n\t{\n\t\tcemu_assert_debug((imlInstruction->op_r_immS32.immS32 & 0x80) == 0);\n\t\tx64Gen_rol_reg64Low32_imm8(x64GenContext, regR, (uint8)imlInstruction->op_r_immS32.immS32);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_X86_CMP)\n\t{\n\t\tsint32 imm = imlInstruction->op_r_immS32.immS32;\n\t\tx64GenContext->emitter->CMP_di32(regR, imm);\n\t}\n\telse\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"PPCRecompilerX64Gen_imlInstruction_r_s32(): Unsupported operation 0x%x\\n\", imlInstruction->operation);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_r_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tauto rRegResult = _reg32(imlInstruction->op_r_r_r.regR);\n\tauto rRegOperand1 = _reg32(imlInstruction->op_r_r_r.regA);\n\tauto rRegOperand2 = _reg32(imlInstruction->op_r_r_r.regB);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_ADD)\n\t{\n\t\t// registerResult = registerOperand1 + registerOperand2\n\t\tif( (rRegResult == rRegOperand1) || (rRegResult == rRegOperand2) )\n\t\t{\n\t\t\t// be careful not to overwrite the operand before we use it\n\t\t\tif( rRegResult == rRegOperand1 )\n\t\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand2);\n\t\t\telse\n\t\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// copy operand1 to destination register before doing addition\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, rRegResult, rRegOperand1);\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand2);\n\t\t}\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_SUB )\n\t{\n\t\tif( rRegOperand1 == rRegOperand2 )\n\t\t{\n\t\t\t// result = operand1 - operand1 -> 0\n\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegResult);\n\t\t}\n\t\telse if( rRegResult == rRegOperand1 )\n\t\t{\n\t\t\t// result = result - operand2\n\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand2);\n\t\t}\n\t\telse if ( rRegResult == rRegOperand2 )\n\t\t{\n\t\t\t// result = operand1 - result\n\t\t\tx64Gen_neg_reg64Low32(x64GenContext, rRegResult);\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, rRegResult, rRegOperand1);\n\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand2);\n\t\t}\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_OR || imlInstruction->operation == PPCREC_IML_OP_AND || imlInstruction->operation == PPCREC_IML_OP_XOR)\n\t{\n\t\tif (rRegResult == rRegOperand2)\n\t\t\tstd::swap(rRegOperand1, rRegOperand2);\n\n\t\tif (rRegResult != rRegOperand1)\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, rRegResult, rRegOperand1);\n\n\t\tif (imlInstruction->operation == PPCREC_IML_OP_OR)\n\t\t\tx64Gen_or_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand2);\n\t\telse if (imlInstruction->operation == PPCREC_IML_OP_AND)\n\t\t\tx64Gen_and_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand2);\n\t\telse\n\t\t\tx64Gen_xor_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand2);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_SIGNED )\n\t{\n\t\t// registerResult = registerOperand1 * registerOperand2\n\t\tif( (rRegResult == rRegOperand1) || (rRegResult == rRegOperand2) )\n\t\t{\n\t\t\t// be careful not to overwrite the operand before we use it\n\t\t\tif( rRegResult == rRegOperand1 )\n\t\t\t\tx64Gen_imul_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand2);\n\t\t\telse\n\t\t\t\tx64Gen_imul_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// copy operand1 to destination register before doing multiplication\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, rRegResult, rRegOperand1);\n\t\t\t// add operand2\n\t\t\tx64Gen_imul_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegOperand2);\n\t\t}\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_SLW || imlInstruction->operation == PPCREC_IML_OP_SRW )\n\t{\n\t\t// registerResult = registerOperand1(rA) >> registerOperand2(rB) (up to 63 bits)\n\n\t\tif (g_CPUFeatures.x86.bmi2 && imlInstruction->operation == PPCREC_IML_OP_SRW)\n\t\t{\n\t\t\t// use BMI2 SHRX if available\n\t\t\tx64Gen_shrx_reg64_reg64_reg64(x64GenContext, rRegResult, rRegOperand1, rRegOperand2);\n\t\t}\n\t\telse if (g_CPUFeatures.x86.bmi2 && imlInstruction->operation == PPCREC_IML_OP_SLW)\n\t\t{\n\t\t\t// use BMI2 SHLX if available\n\t\t\tx64Gen_shlx_reg64_reg64_reg64(x64GenContext, rRegResult, rRegOperand1, rRegOperand2);\n\t\t\tx64Gen_and_reg64Low32_reg64Low32(x64GenContext, rRegResult, rRegResult); // trim result to 32bit\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// lazy and slow way to do shift by register without relying on ECX/CL or BMI2\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, REG_RESV_TEMP, rRegOperand1);\n\t\t\tfor (sint32 b = 0; b < 6; b++)\n\t\t\t{\n\t\t\t\tx64Gen_test_reg64Low32_imm32(x64GenContext, rRegOperand2, (1 << b));\n\t\t\t\tsint32 jumpInstructionOffset = x64GenContext->emitter->GetWriteIndex();\n\t\t\t\tx64Gen_jmpc_near(x64GenContext, X86_CONDITION_EQUAL, 0); // jump if bit not set\n\t\t\t\tif (b == 5)\n\t\t\t\t{\n\t\t\t\t\tx64Gen_xor_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, REG_RESV_TEMP);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (imlInstruction->operation == PPCREC_IML_OP_SLW)\n\t\t\t\t\t\tx64Gen_shl_reg64Low32_imm8(x64GenContext, REG_RESV_TEMP, (1 << b));\n\t\t\t\t\telse\n\t\t\t\t\t\tx64Gen_shr_reg64Low32_imm8(x64GenContext, REG_RESV_TEMP, (1 << b));\n\t\t\t\t}\n\t\t\t\tPPCRecompilerX64Gen_redirectRelativeJump(x64GenContext, jumpInstructionOffset, x64GenContext->emitter->GetWriteIndex());\n\t\t\t}\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, rRegResult, REG_RESV_TEMP);\n\t\t}\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_LEFT_ROTATE )\n\t{\n\t\t// todo: Use BMI2 rotate if available\n\t\t// check if CL/ECX/RCX is available\n\t\tif( rRegResult != X86_REG_RCX && rRegOperand1 != X86_REG_RCX && rRegOperand2 != X86_REG_RCX )\n\t\t{\n\t\t\t// swap operand 2 with RCX\n\t\t\tx64Gen_xchg_reg64_reg64(x64GenContext, X86_REG_RCX, rRegOperand2);\n\t\t\t// move operand 1 to temp register\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, REG_RESV_TEMP, rRegOperand1);\n\t\t\t// rotate\n\t\t\tx64Gen_rol_reg64Low32_cl(x64GenContext, REG_RESV_TEMP);\n\t\t\t// undo swap operand 2 with RCX\n\t\t\tx64Gen_xchg_reg64_reg64(x64GenContext, X86_REG_RCX, rRegOperand2);\n\t\t\t// copy to result register\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, rRegResult, REG_RESV_TEMP);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, REG_RESV_TEMP, rRegOperand1);\n\t\t\t// lazy and slow way to do shift by register without relying on ECX/CL\n\t\t\tfor(sint32 b=0; b<5; b++)\n\t\t\t{\n\t\t\t\tx64Gen_test_reg64Low32_imm32(x64GenContext, rRegOperand2, (1<<b));\n\t\t\t\tsint32 jumpInstructionOffset = x64GenContext->emitter->GetWriteIndex();\n\t\t\t\tx64Gen_jmpc_near(x64GenContext, X86_CONDITION_EQUAL, 0); // jump if bit not set\n\t\t\t\tx64Gen_rol_reg64Low32_imm8(x64GenContext, REG_RESV_TEMP, (1<<b));\n\t\t\t\tPPCRecompilerX64Gen_redirectRelativeJump(x64GenContext, jumpInstructionOffset, x64GenContext->emitter->GetWriteIndex());\n\t\t\t}\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, rRegResult, REG_RESV_TEMP);\n\t\t}\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_S ||\n\t\timlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_U ||\n\t\timlInstruction->operation == PPCREC_IML_OP_LEFT_SHIFT)\n\t{\n\t\tif(g_CPUFeatures.x86.bmi2)\n\t\t{\n\t\t\tif (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_S)\n\t\t\t\tx64Gen_sarx_reg32_reg32_reg32(x64GenContext, rRegResult, rRegOperand1, rRegOperand2);\n\t\t\telse if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_U)\n\t\t\t\tx64Gen_shrx_reg32_reg32_reg32(x64GenContext, rRegResult, rRegOperand1, rRegOperand2);\n\t\t\telse if (imlInstruction->operation == PPCREC_IML_OP_LEFT_SHIFT)\n\t\t\t\tx64Gen_shlx_reg32_reg32_reg32(x64GenContext, rRegResult, rRegOperand1, rRegOperand2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(rRegOperand2 == X86_REG_ECX);\n\t\t\tbool useTempReg = rRegResult == X86_REG_ECX && rRegOperand1 != X86_REG_ECX;\n\t\t\tauto origRegResult = rRegResult;\n\t\t\tif(useTempReg)\n\t\t\t{\n\t\t\t\tx64GenContext->emitter->MOV_dd(REG_RESV_TEMP, rRegOperand1);\n\t\t\t\trRegResult = REG_RESV_TEMP;\n\t\t\t}\n\t\t\tif(rRegOperand1 != rRegResult)\n\t\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, rRegResult, rRegOperand1);\n\t\t\tif (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_S)\n\t\t\t\tx64GenContext->emitter->SAR_d_CL(rRegResult);\n\t\t\telse if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_U)\n\t\t\t\tx64GenContext->emitter->SHR_d_CL(rRegResult);\n\t\t\telse if (imlInstruction->operation == PPCREC_IML_OP_LEFT_SHIFT)\n\t\t\t\tx64GenContext->emitter->SHL_d_CL(rRegResult);\n\t\t\tif(useTempReg)\n\t\t\t\tx64GenContext->emitter->MOV_dd(origRegResult, REG_RESV_TEMP);\n\t\t}\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_DIVIDE_SIGNED || imlInstruction->operation == PPCREC_IML_OP_DIVIDE_UNSIGNED )\n\t{\n\t\tx64Emit_mov_mem32_reg32(x64GenContext, REG_RESV_HCPU, (uint32)offsetof(PPCInterpreter_t, temporaryGPR[0]), X86_REG_EAX);\n\t\tx64Emit_mov_mem32_reg32(x64GenContext, REG_RESV_HCPU, (uint32)offsetof(PPCInterpreter_t, temporaryGPR[1]), X86_REG_EDX);\n\t\t// mov operand 2 to temp register\n\t\tx64Gen_mov_reg64_reg64(x64GenContext, REG_RESV_TEMP, rRegOperand2);\n\t\t// mov operand1 to EAX\n\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, X86_REG_EAX, rRegOperand1);\n\t\t// sign or zero extend EAX to EDX:EAX based on division sign mode\n\t\tif( imlInstruction->operation == PPCREC_IML_OP_DIVIDE_SIGNED )\n\t\t\tx64Gen_cdq(x64GenContext);\n\t\telse\n\t\t\tx64Gen_xor_reg64Low32_reg64Low32(x64GenContext, X86_REG_EDX, X86_REG_EDX);\n\t\t// make sure we avoid division by zero\n\t\tx64Gen_test_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, REG_RESV_TEMP);\n\t\tx64Gen_jmpc_near(x64GenContext, X86_CONDITION_EQUAL, 3);\n\t\t// divide\n\t\tif( imlInstruction->operation == PPCREC_IML_OP_DIVIDE_SIGNED )\n\t\t\tx64Gen_idiv_reg64Low32(x64GenContext, REG_RESV_TEMP);\n\t\telse\n\t\t\tx64Gen_div_reg64Low32(x64GenContext, REG_RESV_TEMP);\n\t\t// result of division is now stored in EAX, move it to result register\n\t\tif( rRegResult != X86_REG_EAX )\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, rRegResult, X86_REG_EAX);\n\t\t// restore EAX / EDX\n\t\tif( rRegResult != X86_REG_RAX )\n\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, X86_REG_EAX, REG_RESV_HCPU, (uint32)offsetof(PPCInterpreter_t, temporaryGPR[0]));\n\t\tif( rRegResult != X86_REG_RDX )\n\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, X86_REG_EDX, REG_RESV_HCPU, (uint32)offsetof(PPCInterpreter_t, temporaryGPR[1]));\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_HIGH_SIGNED || imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_HIGH_UNSIGNED )\n\t{\n\t\tx64Emit_mov_mem32_reg32(x64GenContext, REG_RESV_HCPU, (uint32)offsetof(PPCInterpreter_t, temporaryGPR[0]), X86_REG_EAX);\n\t\tx64Emit_mov_mem32_reg32(x64GenContext, REG_RESV_HCPU, (uint32)offsetof(PPCInterpreter_t, temporaryGPR[1]), X86_REG_EDX);\n\t\t// mov operand 2 to temp register\n\t\tx64Gen_mov_reg64_reg64(x64GenContext, REG_RESV_TEMP, rRegOperand2);\n\t\t// mov operand1 to EAX\n\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, X86_REG_EAX, rRegOperand1);\n\t\tif( imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_HIGH_SIGNED )\n\t\t{\n\t\t\t// zero extend EAX to EDX:EAX\n\t\t\tx64Gen_xor_reg64Low32_reg64Low32(x64GenContext, X86_REG_EDX, X86_REG_EDX);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// sign extend EAX to EDX:EAX\n\t\t\tx64Gen_cdq(x64GenContext);\n\t\t}\n\t\t// multiply\n\t\tif( imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_HIGH_SIGNED )\n\t\t\tx64Gen_imul_reg64Low32(x64GenContext, REG_RESV_TEMP);\n\t\telse\n\t\t\tx64Gen_mul_reg64Low32(x64GenContext, REG_RESV_TEMP);\n\t\t// result of multiplication is now stored in EDX:EAX, move it to result register\n\t\tif( rRegResult != X86_REG_EDX )\n\t\t\tx64Gen_mov_reg64_reg64(x64GenContext, rRegResult, X86_REG_EDX);\n\t\t// restore EAX / EDX\n\t\tif( rRegResult != X86_REG_RAX )\n\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, X86_REG_EAX, REG_RESV_HCPU, (uint32)offsetof(PPCInterpreter_t, temporaryGPR[0]));\n\t\tif( rRegResult != X86_REG_RDX )\n\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, X86_REG_EDX, REG_RESV_HCPU, (uint32)offsetof(PPCInterpreter_t, temporaryGPR[1]));\n\t}\n\telse\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"PPCRecompilerX64Gen_imlInstruction_r_r_r(): Unsupported operation 0x%x\\n\", imlInstruction->operation);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_r_r_r_carry(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tauto regR = _reg32(imlInstruction->op_r_r_r_carry.regR);\n\tauto regA = _reg32(imlInstruction->op_r_r_r_carry.regA);\n\tauto regB = _reg32(imlInstruction->op_r_r_r_carry.regB);\n\tauto regCarry = _reg32(imlInstruction->op_r_r_r_carry.regCarry);\n\tbool carryRegIsShared = regCarry == regA || regCarry == regB;\n\tcemu_assert_debug(regCarry != regR); // two outputs sharing the same register is undefined behavior\n\n\tswitch (imlInstruction->operation)\n\t{\n\tcase PPCREC_IML_OP_ADD:\n\t\tif (regB == regR)\n\t\t\tstd::swap(regB, regA);\n\t\tif (regR != regA)\n\t\t\tx64GenContext->emitter->MOV_dd(regR, regA);\n\t\tif(!carryRegIsShared)\n\t\t\tx64GenContext->emitter->XOR_dd(regCarry, regCarry);\n\t\tx64GenContext->emitter->ADD_dd(regR, regB);\n\t\tx64GenContext->emitter->SETcc_b(X86_CONDITION_B, _reg8_from_reg32(regCarry)); // below condition checks carry flag\n\t\tif(carryRegIsShared)\n\t\t\tx64GenContext->emitter->AND_di8(regCarry, 1); // clear upper bits\n\t\tbreak;\n\tcase PPCREC_IML_OP_ADD_WITH_CARRY:\n\t\t// assumes that carry is already correctly initialized as 0 or 1\n\t\tif (regB == regR)\n\t\t\tstd::swap(regB, regA);\n\t\tif (regR != regA)\n\t\t\tx64GenContext->emitter->MOV_dd(regR, regA);\n\t\tx64GenContext->emitter->BT_du8(regCarry, 0); // copy carry register to x86 carry flag\n\t\tx64GenContext->emitter->ADC_dd(regR, regB);\n\t\tx64GenContext->emitter->SETcc_b(X86_CONDITION_B, _reg8_from_reg32(regCarry));\n\t\tbreak;\n\tdefault:\n\t\tcemu_assert_unimplemented();\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerX64Gen_IsSameCompare(IMLInstruction* imlInstructionA, IMLInstruction* imlInstructionB)\n{\n\tif(imlInstructionA->type != imlInstructionB->type)\n\t\treturn false;\n\tif(imlInstructionA->type == PPCREC_IML_TYPE_COMPARE)\n\t\treturn imlInstructionA->op_compare.regA == imlInstructionB->op_compare.regA && imlInstructionA->op_compare.regB == imlInstructionB->op_compare.regB;\n\telse if(imlInstructionA->type == PPCREC_IML_TYPE_COMPARE_S32)\n\t\treturn imlInstructionA->op_compare_s32.regA == imlInstructionB->op_compare_s32.regA && imlInstructionA->op_compare_s32.immS32 == imlInstructionB->op_compare_s32.immS32;\n\treturn false;\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_compare_x(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, sint32& extraInstructionsProcessed)\n{\n\textraInstructionsProcessed = 0;\n\tboost::container::static_vector<IMLInstruction*, 4> compareInstructions;\n\tcompareInstructions.push_back(imlInstruction);\n\tfor(sint32 i=1; i<4; i++)\n\t{\n\t\tIMLInstruction* nextIns = x64GenContext->GetNextInstruction(i);\n\t\tif(!nextIns || !PPCRecompilerX64Gen_IsSameCompare(imlInstruction, nextIns))\n\t\t\tbreak;\n\t\tcompareInstructions.push_back(nextIns);\n\t}\n\tauto OperandOverlapsWithR = [&](IMLInstruction* ins) -> bool\n\t{\n\t\tcemu_assert_debug(ins->type == PPCREC_IML_TYPE_COMPARE || ins->type == PPCREC_IML_TYPE_COMPARE_S32);\n\t\tif(ins->type == PPCREC_IML_TYPE_COMPARE)\n\t\t\treturn _reg32_from_reg8(_reg8(ins->op_compare.regR)) == _reg32(ins->op_compare.regA) || _reg32_from_reg8(_reg8(ins->op_compare.regR)) == _reg32(ins->op_compare.regB);\n\t\telse /* PPCREC_IML_TYPE_COMPARE_S32 */\n\t\t\treturn _reg32_from_reg8(_reg8(ins->op_compare_s32.regR)) == _reg32(ins->op_compare_s32.regA);\n\t};\n\tauto GetRegR = [](IMLInstruction* insn)\n\t{\n\t\treturn insn->type == PPCREC_IML_TYPE_COMPARE ? _reg32_from_reg8(_reg8(insn->op_compare.regR)) : _reg32_from_reg8(_reg8(insn->op_compare_s32.regR));\n\t};\n\t// prefer XOR method for zeroing out registers if possible\n\tfor(auto& it : compareInstructions)\n\t{\n\t\tif(OperandOverlapsWithR(it))\n\t\t\tcontinue;\n\t\tauto regR = GetRegR(it);\n\t\tx64GenContext->emitter->XOR_dd(regR, regR); // zero bytes unaffected by SETcc\n\t}\n\t// emit the compare instruction\n\tif(imlInstruction->type == PPCREC_IML_TYPE_COMPARE)\n\t{\n\t\tauto regA = _reg32(imlInstruction->op_compare.regA);\n\t\tauto regB = _reg32(imlInstruction->op_compare.regB);\n\t\tx64GenContext->emitter->CMP_dd(regA, regB);\n\t}\n\telse if(imlInstruction->type == PPCREC_IML_TYPE_COMPARE_S32)\n\t{\n\t\tauto regA = _reg32(imlInstruction->op_compare_s32.regA);\n\t\tsint32 imm = imlInstruction->op_compare_s32.immS32;\n\t\tx64GenContext->emitter->CMP_di32(regA, imm);\n\t}\n\t// emit the SETcc instructions\n\tfor(auto& it : compareInstructions)\n\t{\n\t\tauto regR = _reg8(it->op_compare.regR);\n\t\tX86Cond cond = _x86Cond(it->op_compare.cond);\n\t\tif(OperandOverlapsWithR(it))\n\t\t\tx64GenContext->emitter->MOV_di32(_reg32_from_reg8(regR), 0);\n\t\tx64GenContext->emitter->SETcc_b(cond, regR);\n\t}\n\textraInstructionsProcessed = (sint32)compareInstructions.size() - 1;\n\treturn true;\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_cjump2(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, IMLSegment* imlSegment)\n{\n\tauto regBool = _reg8(imlInstruction->op_conditional_jump.registerBool);\n\tbool mustBeTrue = imlInstruction->op_conditional_jump.mustBeTrue;\n\tx64GenContext->emitter->TEST_bb(regBool, regBool);\n\tPPCRecompilerX64Gen_rememberRelocatableOffset(x64GenContext, imlSegment->nextSegmentBranchTaken);\n\tx64GenContext->emitter->Jcc_j32(mustBeTrue ? X86_CONDITION_NZ : X86_CONDITION_Z, 0);\n\treturn true;\n}\n\nvoid PPCRecompilerX64Gen_imlInstruction_x86_eflags_jcc(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, IMLSegment* imlSegment)\n{\n\tX86Cond cond = _x86Cond(imlInstruction->op_x86_eflags_jcc.cond, imlInstruction->op_x86_eflags_jcc.invertedCondition);\n\tPPCRecompilerX64Gen_rememberRelocatableOffset(x64GenContext, imlSegment->nextSegmentBranchTaken);\n\tx64GenContext->emitter->Jcc_j32(cond, 0);\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_jump2(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, IMLSegment* imlSegment)\n{\n\tPPCRecompilerX64Gen_rememberRelocatableOffset(x64GenContext, imlSegment->nextSegmentBranchTaken);\n\tx64GenContext->emitter->JMP_j32(0);\n\treturn true;\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_r_r_s32(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tauto regR = _reg32(imlInstruction->op_r_r_s32.regR);\n\tauto regA = _reg32(imlInstruction->op_r_r_s32.regA);\n\tuint32 immS32 = imlInstruction->op_r_r_s32.immS32;\n\n\tif( imlInstruction->operation == PPCREC_IML_OP_ADD )\n\t{\n\t\tuint32 immU32 = (uint32)imlInstruction->op_r_r_s32.immS32;\n\t\tif(regR != regA)\n\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, regR, regA);\n\t\tx64Gen_add_reg64Low32_imm32(x64GenContext, regR, (uint32)immU32);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_SUB)\n\t{\n\t\tif (regR != regA)\n\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, regR, regA);\n\t\tx64Gen_sub_reg64Low32_imm32(x64GenContext, regR, immS32);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_AND || \n\t\timlInstruction->operation == PPCREC_IML_OP_OR ||\n\t\timlInstruction->operation == PPCREC_IML_OP_XOR)\n\t{\n\t\tif (regR != regA)\n\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, regR, regA);\n\t\tif (imlInstruction->operation == PPCREC_IML_OP_AND)\n\t\t\tx64Gen_and_reg64Low32_imm32(x64GenContext, regR, immS32);\n\t\telse if (imlInstruction->operation == PPCREC_IML_OP_OR)\n\t\t\tx64Gen_or_reg64Low32_imm32(x64GenContext, regR, immS32);\n\t\telse // XOR\n\t\t\tx64Gen_xor_reg64Low32_imm32(x64GenContext, regR, immS32);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_MULTIPLY_SIGNED )\n\t{\n\t\t// registerResult = registerOperand * immS32\n\t\tsint32 immS32 = (uint32)imlInstruction->op_r_r_s32.immS32;\n\t\tx64Gen_mov_reg64_imm64(x64GenContext, REG_RESV_TEMP, (sint64)immS32); // todo: Optimize\n\t\tif( regR != regA )\n\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, regR, regA);\n\t\tx64Gen_imul_reg64Low32_reg64Low32(x64GenContext, regR, REG_RESV_TEMP);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_LEFT_SHIFT ||\n\t\timlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_U ||\n\t\timlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_S)\n\t{\n\t\tif( regA != regR )\n\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, regR, regA);\n\t\tif (imlInstruction->operation == PPCREC_IML_OP_LEFT_SHIFT)\n\t\t\tx64Gen_shl_reg64Low32_imm8(x64GenContext, regR, imlInstruction->op_r_r_s32.immS32);\n\t\telse if (imlInstruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_U)\n\t\t\tx64Gen_shr_reg64Low32_imm8(x64GenContext, regR, imlInstruction->op_r_r_s32.immS32);\n\t\telse // RIGHT_SHIFT_S\n\t\t\tx64Gen_sar_reg64Low32_imm8(x64GenContext, regR, imlInstruction->op_r_r_s32.immS32);\n\t}\n\telse\n\t{\n\t\tdebug_printf(\"PPCRecompilerX64Gen_imlInstruction_r_r_s32(): Unsupported operation 0x%x\\n\", imlInstruction->operation);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_r_r_s32_carry(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tauto regR = _reg32(imlInstruction->op_r_r_s32_carry.regR);\n\tauto regA = _reg32(imlInstruction->op_r_r_s32_carry.regA);\n\tsint32 immS32 = imlInstruction->op_r_r_s32_carry.immS32;\n\tauto regCarry = _reg32(imlInstruction->op_r_r_s32_carry.regCarry);\n\tcemu_assert_debug(regCarry != regR); // we dont allow two different outputs sharing the same register\n\n\tbool delayCarryInit = regCarry == regA;\n\n\tswitch (imlInstruction->operation)\n\t{\n\tcase PPCREC_IML_OP_ADD:\n\t\tif(!delayCarryInit)\n\t\t\tx64GenContext->emitter->XOR_dd(regCarry, regCarry);\n\t\tif (regR != regA)\n\t\t\tx64GenContext->emitter->MOV_dd(regR, regA);\n\t\tx64GenContext->emitter->ADD_di32(regR, immS32);\n\t\tif(delayCarryInit)\n\t\t\tx64GenContext->emitter->MOV_di32(regCarry, 0);\n\t\tx64GenContext->emitter->SETcc_b(X86_CONDITION_B, _reg8_from_reg32(regCarry));\n\t\tbreak;\n\tcase PPCREC_IML_OP_ADD_WITH_CARRY:\n\t\t// assumes that carry is already correctly initialized as 0 or 1\n\t\tcemu_assert_debug(regCarry != regR);\n\t\tif (regR != regA)\n\t\t\tx64GenContext->emitter->MOV_dd(regR, regA);\n\t\tx64GenContext->emitter->BT_du8(regCarry, 0); // copy carry register to x86 carry flag\n\t\tx64GenContext->emitter->ADC_di32(regR, immS32);\n\t\tx64GenContext->emitter->SETcc_b(X86_CONDITION_B, _reg8_from_reg32(regCarry));\n\t\tbreak;\n\tdefault:\n\t\tcemu_assert_unimplemented();\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerX64Gen_imlInstruction_conditionalJumpCycleCheck(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\t// some tests (all performed on a i7-4790K)\n\t// 1) DEC [mem] + JNS has significantly worse performance than BT + JNC (probably due to additional memory write and direct dependency)\n\t// 2) CMP [mem], 0 + JG has about equal (or slightly worse) performance than BT + JNC\n\n\t// BT\n\tx64Gen_bt_mem8(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, remainingCycles), 31); // check if negative\n\tcemu_assert_debug(x64GenContext->currentSegment->GetBranchTaken());\n\tPPCRecompilerX64Gen_rememberRelocatableOffset(x64GenContext, x64GenContext->currentSegment->GetBranchTaken());\n\tx64Gen_jmpc_far(x64GenContext, X86_CONDITION_CARRY, 0);\n\treturn true;\n}\n\nvoid PPCRecompilerX64Gen_imlInstruction_r_name(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tuint32 name = imlInstruction->op_r_name.name;\n\tif (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::I64)\n\t{\n\t\tauto regR = _reg64(imlInstruction->op_r_name.regR);\n\t\tif (name >= PPCREC_NAME_R0 && name < PPCREC_NAME_R0 + 32)\n\t\t{\n\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, gpr) + sizeof(uint32) * (name - PPCREC_NAME_R0));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_SPR0 && name < PPCREC_NAME_SPR0 + 999)\n\t\t{\n\t\t\tsint32 sprIndex = (name - PPCREC_NAME_SPR0);\n\t\t\tif (sprIndex == SPR_LR)\n\t\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, spr.LR));\n\t\t\telse if (sprIndex == SPR_CTR)\n\t\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, spr.CTR));\n\t\t\telse if (sprIndex == SPR_XER)\n\t\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, spr.XER));\n\t\t\telse if (sprIndex >= SPR_UGQR0 && sprIndex <= SPR_UGQR7)\n\t\t\t{\n\t\t\t\tsint32 memOffset = offsetof(PPCInterpreter_t, spr.UGQR) + sizeof(PPCInterpreter_t::spr.UGQR[0]) * (sprIndex - SPR_UGQR0);\n\t\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, regR, REG_RESV_HCPU, memOffset);\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t}\n\t\telse if (name >= PPCREC_NAME_TEMPORARY && name < PPCREC_NAME_TEMPORARY + 4)\n\t\t{\n\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryGPR_reg) + sizeof(uint32) * (name - PPCREC_NAME_TEMPORARY));\n\t\t}\n\t\telse if (name == PPCREC_NAME_XER_CA)\n\t\t{\n\t\t\tx64Emit_movZX_reg64_mem8(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, xer_ca));\n\t\t}\n\t\telse if (name == PPCREC_NAME_XER_SO)\n\t\t{\n\t\t\tx64Emit_movZX_reg64_mem8(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, xer_so));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_CR && name <= PPCREC_NAME_CR_LAST)\n\t\t{\n\t\t\tx64Emit_movZX_reg64_mem8(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, cr) + (name - PPCREC_NAME_CR));\n\t\t}\n\t\telse if (name == PPCREC_NAME_CPU_MEMRES_EA)\n\t\t{\n\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, reservedMemAddr));\n\t\t}\n\t\telse if (name == PPCREC_NAME_CPU_MEMRES_VAL)\n\t\t{\n\t\t\tx64Emit_mov_reg64_mem32(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, reservedMemValue));\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n\telse if (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::F64)\n\t{\n\t\tauto regR = _regF64(imlInstruction->op_r_name.regR);\n\t\tif (name >= PPCREC_NAME_FPR_HALF && name < (PPCREC_NAME_FPR_HALF + 64))\n\t\t{\n\t\t\tsint32 regIndex = (name - PPCREC_NAME_FPR_HALF) / 2;\n\t\t\tsint32 pairIndex = (name - PPCREC_NAME_FPR_HALF) % 2;\n\t\t\tx64Gen_movsd_xmmReg_memReg64(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, fpr) + sizeof(FPR_t) * regIndex + pairIndex * sizeof(double));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_TEMPORARY_FPR0 && name < (PPCREC_NAME_TEMPORARY_FPR0 + 8))\n\t\t{\n\t\t\tx64Gen_movupd_xmmReg_memReg128(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR) + sizeof(FPR_t) * (name - PPCREC_NAME_TEMPORARY_FPR0));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\telse\n\t\tDEBUG_BREAK;\n\n}\n\nvoid PPCRecompilerX64Gen_imlInstruction_name_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tuint32 name = imlInstruction->op_r_name.name;\n\t\n\tif (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::I64)\n\t{\n\t\tauto regR = _reg64(imlInstruction->op_r_name.regR);\n\t\tif (name >= PPCREC_NAME_R0 && name < PPCREC_NAME_R0 + 32)\n\t\t{\n\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, gpr) + sizeof(uint32) * (name - PPCREC_NAME_R0), regR);\n\t\t}\n\t\telse if (name >= PPCREC_NAME_SPR0 && name < PPCREC_NAME_SPR0 + 999)\n\t\t{\n\t\t\tuint32 sprIndex = (name - PPCREC_NAME_SPR0);\n\t\t\tif (sprIndex == SPR_LR)\n\t\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, spr.LR), regR);\n\t\t\telse if (sprIndex == SPR_CTR)\n\t\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, spr.CTR), regR);\n\t\t\telse if (sprIndex == SPR_XER)\n\t\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, spr.XER), regR);\n\t\t\telse if (sprIndex >= SPR_UGQR0 && sprIndex <= SPR_UGQR7)\n\t\t\t{\n\t\t\t\tsint32 memOffset = offsetof(PPCInterpreter_t, spr.UGQR) + sizeof(PPCInterpreter_t::spr.UGQR[0]) * (sprIndex - SPR_UGQR0);\n\t\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, memOffset, regR);\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t}\n\t\telse if (name >= PPCREC_NAME_TEMPORARY && name < PPCREC_NAME_TEMPORARY + 4)\n\t\t{\n\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryGPR_reg) + sizeof(uint32) * (name - PPCREC_NAME_TEMPORARY), regR);\n\t\t}\n\t\telse if (name == PPCREC_NAME_XER_CA)\n\t\t{\n\t\t\tx64GenContext->emitter->MOV_bb_l(REG_RESV_HCPU, offsetof(PPCInterpreter_t, xer_ca), X86_REG_NONE, 0, _reg8_from_reg64(regR));\n\t\t}\n\t\telse if (name == PPCREC_NAME_XER_SO)\n\t\t{\n\t\t\tx64GenContext->emitter->MOV_bb_l(REG_RESV_HCPU, offsetof(PPCInterpreter_t, xer_so), X86_REG_NONE, 0, _reg8_from_reg64(regR));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_CR && name <= PPCREC_NAME_CR_LAST)\n\t\t{\n\t\t\tx64GenContext->emitter->MOV_bb_l(REG_RESV_HCPU, offsetof(PPCInterpreter_t, cr) + (name - PPCREC_NAME_CR), X86_REG_NONE, 0, _reg8_from_reg64(regR));\n\t\t}\n\t\telse if (name == PPCREC_NAME_CPU_MEMRES_EA)\n\t\t{\n\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, reservedMemAddr), regR);\n\t\t}\n\t\telse if (name == PPCREC_NAME_CPU_MEMRES_VAL)\n\t\t{\n\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, reservedMemValue), regR);\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n\telse if (imlInstruction->op_r_name.regR.GetBaseFormat() == IMLRegFormat::F64)\n\t{\n\t\tauto regR = _regF64(imlInstruction->op_r_name.regR);\n\t\tuint32 name = imlInstruction->op_r_name.name;\n\t\tif (name >= PPCREC_NAME_FPR_HALF && name < (PPCREC_NAME_FPR_HALF + 64))\n\t\t{\n\t\t\tsint32 regIndex = (name - PPCREC_NAME_FPR_HALF) / 2;\n\t\t\tsint32 pairIndex = (name - PPCREC_NAME_FPR_HALF) % 2;\n\t\t\tx64Gen_movsd_memReg64_xmmReg(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, fpr) + sizeof(FPR_t) * regIndex + (pairIndex ? sizeof(double) : 0));\n\t\t}\n\t\telse if (name >= PPCREC_NAME_TEMPORARY_FPR0 && name < (PPCREC_NAME_TEMPORARY_FPR0 + 8))\n\t\t{\n\t\t\tx64Gen_movupd_memReg128_xmmReg(x64GenContext, regR, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR) + sizeof(FPR_t) * (name - PPCREC_NAME_TEMPORARY_FPR0));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\telse\n\t\tDEBUG_BREAK;\n\n\n}\n\nuint8* codeMemoryBlock = nullptr;\nsint32 codeMemoryBlockIndex = 0;\nsint32 codeMemoryBlockSize = 0;\n\nstd::mutex mtx_allocExecutableMemory;\n\nuint8* PPCRecompilerX86_allocateExecutableMemory(sint32 size)\n{\n\tstd::lock_guard<std::mutex> lck(mtx_allocExecutableMemory);\n\tif( codeMemoryBlockIndex+size > codeMemoryBlockSize )\n\t{\n\t\t// allocate new block\n\t\tcodeMemoryBlockSize = std::max(1024*1024*4, size+1024); // 4MB (or more if the function is larger than 4MB)\n\t\tcodeMemoryBlockIndex = 0;\n\t\tcodeMemoryBlock = (uint8*)MemMapper::AllocateMemory(nullptr, codeMemoryBlockSize, MemMapper::PAGE_PERMISSION::P_RWX);\n\t}\n\tuint8* codeMem = codeMemoryBlock + codeMemoryBlockIndex;\n\tcodeMemoryBlockIndex += size;\n\t// pad to 4 byte alignment\n\twhile (codeMemoryBlockIndex & 3)\n\t{\n\t\tcodeMemoryBlock[codeMemoryBlockIndex] = 0x90;\n\t\tcodeMemoryBlockIndex++;\n\t}\n\treturn codeMem;\n}\n\nbool PPCRecompiler_generateX64Code(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext)\n{\n\tx64GenContext_t x64GenContext{};\n\n\t// generate iml instruction code\n\tbool codeGenerationFailed = false;\n\tfor (IMLSegment* segIt : ppcImlGenContext->segmentList2)\n\t{\n\t\tx64GenContext.currentSegment = segIt;\n\t\tsegIt->x64Offset = x64GenContext.emitter->GetWriteIndex();\n\t\tfor(size_t i=0; i<segIt->imlList.size(); i++)\n\t\t{\n\t\t\tx64GenContext.m_currentInstructionEmitIndex = i;\n\t\t\tIMLInstruction* imlInstruction = segIt->imlList.data() + i;\n\n\t\t\tif( imlInstruction->type == PPCREC_IML_TYPE_R_NAME )\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_r_name(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_NAME_R )\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_name_r(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_R_R )\n\t\t\t{\n\t\t\t\tif( PPCRecompilerX64Gen_imlInstruction_r_r(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false )\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_S32)\n\t\t\t{\n\t\t\t\tif (PPCRecompilerX64Gen_imlInstruction_r_s32(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false)\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_R_S32)\n\t\t\t{\n\t\t\t\tif (PPCRecompilerX64Gen_imlInstruction_r_r_s32(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false)\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_R_S32_CARRY)\n\t\t\t{\n\t\t\t\tif (PPCRecompilerX64Gen_imlInstruction_r_r_s32_carry(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false)\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_R_R)\n\t\t\t{\n\t\t\t\tif (PPCRecompilerX64Gen_imlInstruction_r_r_r(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false)\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_R_R_R_CARRY)\n\t\t\t{\n\t\t\t\tif (PPCRecompilerX64Gen_imlInstruction_r_r_r_carry(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false)\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_COMPARE || imlInstruction->type == PPCREC_IML_TYPE_COMPARE_S32)\n\t\t\t{\n\t\t\t\tsint32 extraInstructionsProcessed;\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_compare_x(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, extraInstructionsProcessed);\n\t\t\t\ti += extraInstructionsProcessed;\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_CONDITIONAL_JUMP)\n\t\t\t{\n\t\t\t\tif (PPCRecompilerX64Gen_imlInstruction_cjump2(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, segIt) == false)\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if(imlInstruction->type == PPCREC_IML_TYPE_X86_EFLAGS_JCC)\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_x86_eflags_jcc(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, segIt);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_JUMP)\n\t\t\t{\n\t\t\t\tif (PPCRecompilerX64Gen_imlInstruction_jump2(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, segIt) == false)\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK )\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_conditionalJumpCycleCheck(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_MACRO )\n\t\t\t{\n\t\t\t\tif( PPCRecompilerX64Gen_imlInstruction_macro(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction) == false )\n\t\t\t\t{\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_LOAD )\n\t\t\t{\n\t\t\t\tif( PPCRecompilerX64Gen_imlInstruction_load(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, false) == false )\n\t\t\t\t{\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_LOAD_INDEXED )\n\t\t\t{\n\t\t\t\tif( PPCRecompilerX64Gen_imlInstruction_load(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, true) == false )\n\t\t\t\t{\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_STORE )\n\t\t\t{\n\t\t\t\tif( PPCRecompilerX64Gen_imlInstruction_store(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, false) == false )\n\t\t\t\t{\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_STORE_INDEXED )\n\t\t\t{\n\t\t\t\tif( PPCRecompilerX64Gen_imlInstruction_store(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, true) == false )\n\t\t\t\t{\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_ATOMIC_CMP_STORE)\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_atomic_cmp_store(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_CALL_IMM)\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_call_imm(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_NO_OP )\n\t\t\t{\n\t\t\t\t// no op\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD )\n\t\t\t{\n\t\t\t\tif( PPCRecompilerX64Gen_imlInstruction_fpr_load(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, false) == false )\n\t\t\t\t{\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED )\n\t\t\t{\n\t\t\t\tif( PPCRecompilerX64Gen_imlInstruction_fpr_load(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, true) == false )\n\t\t\t\t{\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE )\n\t\t\t{\n\t\t\t\tif( PPCRecompilerX64Gen_imlInstruction_fpr_store(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, false) == false )\n\t\t\t\t{\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE_INDEXED )\n\t\t\t{\n\t\t\t\tif( PPCRecompilerX64Gen_imlInstruction_fpr_store(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction, true) == false )\n\t\t\t\t{\n\t\t\t\t\tcodeGenerationFailed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_FPR_R_R )\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_fpr_r_r(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);\t\t\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_FPR_R_R_R )\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_fpr_r_r_r(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);\t\t\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_FPR_R_R_R_R )\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_fpr_r_r_r_r(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);\t\t\n\t\t\t}\n\t\t\telse if( imlInstruction->type == PPCREC_IML_TYPE_FPR_R )\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_fpr_r(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);\t\t\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_COMPARE)\n\t\t\t{\n\t\t\t\tPPCRecompilerX64Gen_imlInstruction_fpr_compare(PPCRecFunction, ppcImlGenContext, &x64GenContext, imlInstruction);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdebug_printf(\"PPCRecompiler_generateX64Code(): Unsupported iml type 0x%x\\n\", imlInstruction->type);\n\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t}\n\t}\n\t// handle failed code generation\n\tif( codeGenerationFailed )\n\t{\n\t\treturn false;\n\t}\n\t// allocate executable memory\n\tuint8* executableMemory = PPCRecompilerX86_allocateExecutableMemory(x64GenContext.emitter->GetBuffer().size_bytes());\n\tsize_t baseAddress = (size_t)executableMemory;\n\t// fix relocs\n\tfor(auto& relocIt : x64GenContext.relocateOffsetTable2)\n\t{\n\t\t// search for segment that starts with this offset\n\t\tuint32 ppcOffset = (uint32)(size_t)relocIt.extraInfo;\n\t\tuint32 x64Offset = 0xFFFFFFFF;\n\n\t\tIMLSegment* destSegment = (IMLSegment*)relocIt.extraInfo;\n\t\tx64Offset = destSegment->x64Offset;\n\n\t\tuint32 relocBase = relocIt.offset;\n\t\tuint8* relocInstruction = x64GenContext.emitter->GetBufferPtr()+relocBase;\n\t\tif( relocInstruction[0] == 0x0F && (relocInstruction[1] >= 0x80 && relocInstruction[1] <= 0x8F) )\n\t\t{\n\t\t\t// Jcc relativeImm32\n\t\t\tsint32 distanceNearJump = (sint32)((baseAddress + x64Offset) - (baseAddress + relocBase + 2));\n\t\t\tif (distanceNearJump >= -128 && distanceNearJump < 127) // disabled\n\t\t\t{\n\t\t\t\t// convert to near Jcc\n\t\t\t\t*(uint8*)(relocInstruction + 0) = (uint8)(relocInstruction[1]-0x80 + 0x70);\n\t\t\t\t// patch offset\n\t\t\t\t*(uint8*)(relocInstruction + 1) = (uint8)distanceNearJump;\n\t\t\t\t// replace unused 4 bytes with NOP instruction\n\t\t\t\trelocInstruction[2] = 0x0F;\n\t\t\t\trelocInstruction[3] = 0x1F;\n\t\t\t\trelocInstruction[4] = 0x40;\n\t\t\t\trelocInstruction[5] = 0x00;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// patch offset\n\t\t\t\t*(uint32*)(relocInstruction + 2) = (uint32)((baseAddress + x64Offset) - (baseAddress + relocBase + 6));\n\t\t\t}\n\t\t}\n\t\telse if( relocInstruction[0] == 0xE9 )\n\t\t{\n\t\t\t// JMP relativeImm32\n\t\t\t*(uint32*)(relocInstruction+1) = (uint32)((baseAddress+x64Offset)-(baseAddress+relocBase+5));\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n\n\t// copy code to executable memory\n\tstd::span<uint8> codeBuffer = x64GenContext.emitter->GetBuffer();\n\tmemcpy(executableMemory, codeBuffer.data(), codeBuffer.size_bytes());\n\t// set code\n\tPPCRecFunction->x86Code = executableMemory;\n\tPPCRecFunction->x86Size = codeBuffer.size_bytes();\n\treturn true;\n}\n\nvoid PPCRecompilerX64Gen_generateEnterRecompilerCode()\n{\n\tx64GenContext_t x64GenContext{};\n\n\t// start of recompiler entry function (15 regs)\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_RAX);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_RCX);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_RDX);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_RBX);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_RBP);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_RDI);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_RSI);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_R8);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_R9);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_R10);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_R11);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_R12);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_R13);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_R14);\n\tx64Gen_push_reg64(&x64GenContext, X86_REG_R15);\n\n\t// 000000007775EF04 | E8 00 00 00 00                      call +0x00\n\tx64Gen_writeU8(&x64GenContext, 0xE8);\n\tx64Gen_writeU8(&x64GenContext, 0x00);\n\tx64Gen_writeU8(&x64GenContext, 0x00);\n\tx64Gen_writeU8(&x64GenContext, 0x00);\n\tx64Gen_writeU8(&x64GenContext, 0x00);\n\t//000000007775EF09 | 48 83 04 24 05                       add qword ptr ss:[rsp],5\n\tx64Gen_writeU8(&x64GenContext, 0x48);\n\tx64Gen_writeU8(&x64GenContext, 0x83);\n\tx64Gen_writeU8(&x64GenContext, 0x04);\n\tx64Gen_writeU8(&x64GenContext, 0x24);\n\tuint32 jmpPatchOffset = x64GenContext.emitter->GetWriteIndex();\n\tx64Gen_writeU8(&x64GenContext, 0); // skip the distance until after the JMP\n\tx64Emit_mov_mem64_reg64(&x64GenContext, X86_REG_RDX, offsetof(PPCInterpreter_t, rspTemp), X86_REG_RSP);\n\n\t// MOV RSP, RDX (ppc interpreter instance)\n\tx64Gen_mov_reg64_reg64(&x64GenContext, REG_RESV_HCPU, X86_REG_RDX);\n\t// MOV R15, ppcRecompilerInstanceData\n\tx64Gen_mov_reg64_imm64(&x64GenContext, REG_RESV_RECDATA, (uint64)ppcRecompilerInstanceData);\n\t// MOV R13, memory_base\n\tx64Gen_mov_reg64_imm64(&x64GenContext, REG_RESV_MEMBASE, (uint64)memory_base);\n\n\t//JMP recFunc\n\tx64Gen_jmp_reg64(&x64GenContext, X86_REG_RCX); // call argument 1\n\n\tx64GenContext.emitter->GetBuffer()[jmpPatchOffset] = (x64GenContext.emitter->GetWriteIndex() -(jmpPatchOffset-4));\n\n\t//recompilerExit1:\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_R15);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_R14);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_R13);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_R12);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_R11);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_R10);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_R9);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_R8);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_RSI);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_RDI);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_RBP);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_RBX);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_RDX);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_RCX);\n\tx64Gen_pop_reg64(&x64GenContext, X86_REG_RAX);\n\t// RET\n\tx64Gen_ret(&x64GenContext);\n\n\tuint8* executableMemory = PPCRecompilerX86_allocateExecutableMemory(x64GenContext.emitter->GetBuffer().size_bytes());\n\t// copy code to executable memory\n\tmemcpy(executableMemory, x64GenContext.emitter->GetBuffer().data(), x64GenContext.emitter->GetBuffer().size_bytes());\n\tPPCRecompiler_enterRecompilerCode = (void ATTR_MS_ABI (*)(uint64,uint64))executableMemory;\n}\n\n\nvoid* PPCRecompilerX64Gen_generateLeaveRecompilerCode()\n{\n\tx64GenContext_t x64GenContext{};\n\n\t// update instruction pointer\n\t// LR is in EDX\n\tx64Emit_mov_mem32_reg32(&x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, instructionPointer), X86_REG_EDX);\n\t// MOV RSP, [hCPU->rspTemp]\n\tx64Emit_mov_reg64_mem64(&x64GenContext, X86_REG_RSP, REG_RESV_HCPU, offsetof(PPCInterpreter_t, rspTemp));\n\t// RET\n\tx64Gen_ret(&x64GenContext);\n\n\tuint8* executableMemory = PPCRecompilerX86_allocateExecutableMemory(x64GenContext.emitter->GetBuffer().size_bytes());\n\t// copy code to executable memory\n\tmemcpy(executableMemory, x64GenContext.emitter->GetBuffer().data(), x64GenContext.emitter->GetBuffer().size_bytes());\n\treturn executableMemory;\n}\n\nvoid PPCRecompilerX64Gen_generateRecompilerInterfaceFunctions()\n{\n\tPPCRecompilerX64Gen_generateEnterRecompilerCode();\n\tPPCRecompiler_leaveRecompilerCode_unvisited = (void ATTR_MS_ABI (*)())PPCRecompilerX64Gen_generateLeaveRecompilerCode();\n\tPPCRecompiler_leaveRecompilerCode_visited = (void ATTR_MS_ABI (*)())PPCRecompilerX64Gen_generateLeaveRecompilerCode();\n\tcemu_assert_debug(PPCRecompiler_leaveRecompilerCode_unvisited != PPCRecompiler_leaveRecompilerCode_visited);\n}\n\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64.h",
    "content": "\n#include \"../PPCRecompiler.h\" // todo - get rid of dependency\n\n#include \"x86Emitter.h\"\n\nstruct x64RelocEntry_t\n{\n\tx64RelocEntry_t(uint32 offset, void* extraInfo) : offset(offset), extraInfo(extraInfo) {};\n\n\tuint32 offset;\n\tvoid*  extraInfo;\n};\n\nstruct x64GenContext_t\n{\n\tIMLSegment* currentSegment{};\n\tx86Assembler64* emitter;\n\tsint32 m_currentInstructionEmitIndex;\n\n\tx64GenContext_t()\n\t{\n\t\temitter = new x86Assembler64();\n\t}\n\n\t~x64GenContext_t()\n\t{\n\t\tdelete emitter;\n\t}\n\n\tIMLInstruction* GetNextInstruction(sint32 relativeIndex = 1)\n\t{\n\t\tsint32 index = m_currentInstructionEmitIndex + relativeIndex;\n\t\tif(index < 0 || index >= (sint32)currentSegment->imlList.size())\n\t\t\treturn nullptr;\n\t\treturn currentSegment->imlList.data() + index;\n\t}\n\n\t// relocate offsets\n\tstd::vector<x64RelocEntry_t> relocateOffsetTable2;\n};\n\n// reserved registers\n#define REG_RESV_TEMP\t\t(X86_REG_R14)\n#define REG_RESV_HCPU\t\t(X86_REG_RSP)\n#define REG_RESV_MEMBASE\t(X86_REG_R13)\n#define REG_RESV_RECDATA\t(X86_REG_R15)\n\n// reserved floating-point registers\n#define REG_RESV_FPR_TEMP\t(15)\n\n#define reg32ToReg16(__x)\t(__x) // deprecated\n\n// deprecated condition flags\nenum\n{\n\tX86_CONDITION_EQUAL, // or zero\n\tX86_CONDITION_NOT_EQUAL, // or not zero\n\tX86_CONDITION_SIGNED_LESS, // or not greater/equal\n\tX86_CONDITION_SIGNED_GREATER, // or not less/equal\n\tX86_CONDITION_SIGNED_LESS_EQUAL, // or not greater\n\tX86_CONDITION_SIGNED_GREATER_EQUAL, // or not less\n\tX86_CONDITION_UNSIGNED_BELOW, // or not above/equal\n\tX86_CONDITION_UNSIGNED_ABOVE, // or not below/equal\n\tX86_CONDITION_UNSIGNED_BELOW_EQUAL, // or not above\n\tX86_CONDITION_UNSIGNED_ABOVE_EQUAL, // or not below\n\tX86_CONDITION_CARRY, // carry flag must be set\n\tX86_CONDITION_NOT_CARRY, // carry flag must not be set\n\tX86_CONDITION_SIGN, // sign flag must be set\n\tX86_CONDITION_NOT_SIGN, // sign flag must not be set\n\tX86_CONDITION_PARITY, // parity flag must be set\n\tX86_CONDITION_NONE, // no condition, jump always\n};\n\nbool PPCRecompiler_generateX64Code(struct PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext);\n\nvoid PPCRecompilerX64Gen_redirectRelativeJump(x64GenContext_t* x64GenContext, sint32 jumpInstructionOffset, sint32 destinationOffset);\n\nvoid PPCRecompilerX64Gen_generateRecompilerInterfaceFunctions();\n\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_r_name(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction);\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_name_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction);\nbool PPCRecompilerX64Gen_imlInstruction_fpr_load(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, bool indexed);\nbool PPCRecompilerX64Gen_imlInstruction_fpr_store(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, bool indexed);\n\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction);\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_r_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction);\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_r_r_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction);\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction);\n\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_compare(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction);\n\n// ASM gen\nvoid x64Gen_writeU8(x64GenContext_t* x64GenContext, uint8 v);\nvoid x64Gen_writeU16(x64GenContext_t* x64GenContext, uint32 v);\nvoid x64Gen_writeU32(x64GenContext_t* x64GenContext, uint32 v);\n\nvoid x64Emit_mov_reg32_mem32(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memOffset);\nvoid x64Emit_mov_mem32_reg32(x64GenContext_t* x64GenContext, sint32 memBaseReg64, sint32 memOffset, sint32 srcReg);\nvoid x64Emit_mov_mem64_reg64(x64GenContext_t* x64GenContext, sint32 memBaseReg64, sint32 memOffset, sint32 srcReg);\nvoid x64Emit_mov_reg64_mem64(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memOffset);\nvoid x64Emit_mov_reg64_mem32(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memOffset);\nvoid x64Emit_mov_mem32_reg64(x64GenContext_t* x64GenContext, sint32 memBaseReg64, sint32 memOffset, sint32 srcReg);\nvoid x64Emit_mov_reg64_mem64(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memIndexReg64, sint32 memOffset);\nvoid x64Emit_mov_reg32_mem32(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memIndexReg64, sint32 memOffset);\nvoid x64Emit_mov_reg64b_mem8(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memIndexReg64, sint32 memOffset);\nvoid x64Emit_movZX_reg32_mem8(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memIndexReg64, sint32 memOffset);\nvoid x64Emit_movZX_reg64_mem8(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memOffset);\n\nvoid x64Gen_movSignExtend_reg64Low32_mem8Reg64PlusReg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32);\n\nvoid x64Gen_movZeroExtend_reg64Low16_mem16Reg64PlusReg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32);\nvoid x64Gen_mov_mem64Reg64PlusReg64_reg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32);\nvoid x64Gen_movTruncate_mem32Reg64PlusReg64_reg64(x64GenContext_t* x64GenContext, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32, sint32 srcRegister);\nvoid x64Gen_movTruncate_mem16Reg64PlusReg64_reg64(x64GenContext_t* x64GenContext, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32, sint32 srcRegister);\nvoid x64Gen_movTruncate_mem8Reg64PlusReg64_reg64(x64GenContext_t* x64GenContext, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32, sint32 srcRegister);\nvoid x64Gen_mov_mem32Reg64_imm32(x64GenContext_t* x64GenContext, sint32 memRegister, uint32 memImmU32, uint32 dataImmU32);\nvoid x64Gen_mov_mem64Reg64_imm32(x64GenContext_t* x64GenContext, sint32 memRegister, uint32 memImmU32, uint32 dataImmU32);\nvoid x64Gen_mov_mem8Reg64_imm8(x64GenContext_t* x64GenContext, sint32 memRegister, uint32 memImmU32, uint8 dataImmU8);\n\nvoid x64Gen_mov_reg64_imm64(x64GenContext_t* x64GenContext, sint32 destRegister, uint64 immU64);\nvoid x64Gen_mov_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 destRegister, uint64 immU32);\nvoid x64Gen_mov_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\n\nvoid x64Gen_lea_reg64Low32_reg64Low32PlusReg64Low32(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64);\n\nvoid x64Gen_cmovcc_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, uint32 conditionType, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_mov_reg64_reg64(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_xchg_reg64_reg64(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_movSignExtend_reg64Low32_reg64Low16(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_movZeroExtend_reg64Low32_reg64Low16(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_movSignExtend_reg64Low32_reg64Low8(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_movZeroExtend_reg64Low32_reg64Low8(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\n\nvoid x64Gen_or_reg64Low8_mem8Reg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegister64, sint32 memImmS32);\nvoid x64Gen_and_reg64Low8_mem8Reg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegister64, sint32 memImmS32);\nvoid x64Gen_mov_mem8Reg64_reg64Low8(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegister64, sint32 memImmS32);\n\nvoid x64Gen_add_reg64_reg64(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_add_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_add_reg64_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32);\nvoid x64Gen_add_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32);\nvoid x64Gen_sub_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_sub_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32);\nvoid x64Gen_sub_reg64_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32);\nvoid x64Gen_sub_mem32reg64_imm32(x64GenContext_t* x64GenContext, sint32 memRegister, sint32 memImmS32, uint64 immU32);\nvoid x64Gen_dec_mem32(x64GenContext_t* x64GenContext, sint32 memoryRegister, uint32 memoryImmU32);\nvoid x64Gen_imul_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 operandRegister);\nvoid x64Gen_idiv_reg64Low32(x64GenContext_t* x64GenContext, sint32 operandRegister);\nvoid x64Gen_div_reg64Low32(x64GenContext_t* x64GenContext, sint32 operandRegister);\nvoid x64Gen_imul_reg64Low32(x64GenContext_t* x64GenContext, sint32 operandRegister);\nvoid x64Gen_mul_reg64Low32(x64GenContext_t* x64GenContext, sint32 operandRegister);\nvoid x64Gen_and_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32);\nvoid x64Gen_and_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_test_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_test_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32);\nvoid x64Gen_cmp_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, sint32 immS32);\nvoid x64Gen_cmp_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_cmp_reg64Low32_mem32reg64(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 memRegister, sint32 memImmS32);\nvoid x64Gen_or_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32);\nvoid x64Gen_or_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_xor_reg32_reg32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_xor_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_xor_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32);\n\nvoid x64Gen_rol_reg64Low32_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8);\nvoid x64Gen_rol_reg64Low32_cl(x64GenContext_t* x64GenContext, sint32 srcRegister);\nvoid x64Gen_rol_reg64Low16_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8);\nvoid x64Gen_rol_reg64_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8);\nvoid x64Gen_shl_reg64Low32_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8);\nvoid x64Gen_shr_reg64Low32_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8);\nvoid x64Gen_sar_reg64Low32_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8);\n\nvoid x64Gen_not_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister);\nvoid x64Gen_neg_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister);\nvoid x64Gen_cdq(x64GenContext_t* x64GenContext);\n\nvoid x64Gen_bswap_reg64Lower32bit(x64GenContext_t* x64GenContext, sint32 destRegister);\n\nvoid x64Gen_lzcnt_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_bsr_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister);\nvoid x64Gen_cmp_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, sint32 immS32);\nvoid x64Gen_setcc_mem8(x64GenContext_t* x64GenContext, sint32 conditionType, sint32 memoryRegister, uint32 memoryImmU32);\nvoid x64Gen_setcc_reg64b(x64GenContext_t* x64GenContext, sint32 conditionType, sint32 dataRegister);\nvoid x64Gen_bt_mem8(x64GenContext_t* x64GenContext, sint32 memoryRegister, uint32 memoryImmU32, uint8 bitIndex);\nvoid x64Gen_cmc(x64GenContext_t* x64GenContext);\n\nvoid x64Gen_jmp_imm32(x64GenContext_t* x64GenContext, uint32 destImm32);\nvoid x64Gen_jmp_memReg64(x64GenContext_t* x64GenContext, sint32 memRegister, uint32 immU32);\nvoid x64Gen_jmpc_far(x64GenContext_t* x64GenContext, sint32 conditionType, sint32 relativeDest);\nvoid x64Gen_jmpc_near(x64GenContext_t* x64GenContext, sint32 conditionType, sint32 relativeDest);\n\nvoid x64Gen_push_reg64(x64GenContext_t* x64GenContext, sint32 srcRegister);\nvoid x64Gen_pop_reg64(x64GenContext_t* x64GenContext, sint32 destRegister);\nvoid x64Gen_jmp_reg64(x64GenContext_t* x64GenContext, sint32 srcRegister);\nvoid x64Gen_call_reg64(x64GenContext_t* x64GenContext, sint32 srcRegister);\nvoid x64Gen_ret(x64GenContext_t* x64GenContext);\nvoid x64Gen_int3(x64GenContext_t* x64GenContext);\n\n// floating-point (SIMD/SSE) gen\nvoid x64Gen_movaps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSource);\nvoid x64Gen_movupd_xmmReg_memReg128(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);\nvoid x64Gen_movupd_memReg128_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);\nvoid x64Gen_movddup_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);\nvoid x64Gen_movddup_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_movhlps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_movsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_movsd_memReg64_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);\nvoid x64Gen_movsd_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);\nvoid x64Gen_movlpd_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);\nvoid x64Gen_unpcklpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_unpckhpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_shufpd_xmmReg_xmmReg_imm8(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc, uint8 imm8);\nvoid x64Gen_addsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_addpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_subsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_subpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_mulsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_mulpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_mulpd_xmmReg_memReg128(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);\nvoid x64Gen_divsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_divpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_comisd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_comisd_xmmReg_mem64Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 memoryReg, sint32 memImmS32);\nvoid x64Gen_ucomisd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_comiss_xmmReg_mem64Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 memoryReg, sint32 memImmS32);\nvoid x64Gen_orps_xmmReg_mem128Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, uint32 memReg, uint32 memImmS32);\nvoid x64Gen_xorps_xmmReg_mem128Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, uint32 memReg, uint32 memImmS32);\nvoid x64Gen_andps_xmmReg_mem128Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, uint32 memReg, uint32 memImmS32);\nvoid x64Gen_andpd_xmmReg_memReg128(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);\nvoid x64Gen_andps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_pcmpeqd_xmmReg_mem128Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, uint32 memReg, uint32 memImmS32);\nvoid x64Gen_cvttpd2dq_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_cvttsd2si_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDest, sint32 xmmRegisterSrc);\nvoid x64Gen_cvtsi2sd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 registerSrc);\nvoid x64Gen_cvtsd2ss_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_cvtpd2ps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_cvtss2sd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_cvtps2pd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_cvtpi2pd_xmmReg_mem64Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 memReg, sint32 memImmS32);\nvoid x64Gen_cvtsd2si_reg64Low_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDest, sint32 xmmRegisterSrc);\nvoid x64Gen_cvttsd2si_reg64Low_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDest, sint32 xmmRegisterSrc);\nvoid x64Gen_sqrtsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_sqrtpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_rcpss_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc);\nvoid x64Gen_mulss_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32);\n\nvoid x64Gen_movd_xmmReg_reg64Low32(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 registerSrc);\nvoid x64Gen_movd_reg64Low32_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDest, sint32 xmmRegisterSrc);\nvoid x64Gen_movq_xmmReg_reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 registerSrc);\nvoid x64Gen_movq_reg64_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 xmmRegisterSrc);\n\n// AVX\n\nvoid x64Gen_avx_VPUNPCKHQDQ_xmm_xmm_xmm(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 srcRegisterA, sint32 srcRegisterB);\nvoid x64Gen_avx_VUNPCKHPD_xmm_xmm_xmm(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 srcRegisterA, sint32 srcRegisterB);\nvoid x64Gen_avx_VSUBPD_xmm_xmm_xmm(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 srcRegisterA, sint32 srcRegisterB);\n\n// BMI\nvoid x64Gen_movBEZeroExtend_reg64_mem32Reg64PlusReg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32);\nvoid x64Gen_movBEZeroExtend_reg64Low16_mem16Reg64PlusReg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32);\n\nvoid x64Gen_movBETruncate_mem32Reg64PlusReg64_reg64(x64GenContext_t* x64GenContext, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32, sint32 srcRegister);\n\nvoid x64Gen_shrx_reg64_reg64_reg64(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB);\nvoid x64Gen_shrx_reg32_reg32_reg32(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB);\nvoid x64Gen_sarx_reg64_reg64_reg64(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB);\nvoid x64Gen_sarx_reg32_reg32_reg32(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB);\nvoid x64Gen_shlx_reg64_reg64_reg64(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB);\nvoid x64Gen_shlx_reg32_reg32_reg32(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB);"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64AVX.cpp",
    "content": "#include \"BackendX64.h\"\n\nvoid _x64Gen_writeMODRMDeprecated(x64GenContext_t* x64GenContext, sint32 dataRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32);\n\nvoid _x64Gen_vex128_nds(x64GenContext_t* x64GenContext, uint8 opcodeMap, uint8 additionalOperand, uint8 pp, uint8 vex_ext, uint8 vex_r, uint8 vex_b, uint8 opcode)\n{\n\tif(vex_b != 0)\n\t\tx64Gen_writeU8(x64GenContext, 0xC4); // three byte VEX\n\telse\n\t\tx64Gen_writeU8(x64GenContext, 0xC5); // two byte VEX\n\n\tif (vex_b != 0)\n\t{\n\t\tuint8 vex_x = 0;\n\t\tx64Gen_writeU8(x64GenContext, (vex_r ? 0x00 : 0x80) | (vex_x ? 0x00 : 0x40) | (vex_b ? 0x00 : 0x20) | 1);\n\t}\n\n\tx64Gen_writeU8(x64GenContext, (vex_ext<<7) | (((~additionalOperand)&0xF)<<3) | pp);\n\n\tx64Gen_writeU8(x64GenContext, opcode);\n}\n\n#define VEX_PP_0F\t\t0\n#define VEX_PP_66_0F\t1\n#define VEX_PP_F3_0F\t2\n#define VEX_PP_F2_0F\t3\n\nvoid x64Gen_avx_VPUNPCKHQDQ_xmm_xmm_xmm(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 srcRegisterA, sint32 srcRegisterB)\n{\n\t_x64Gen_vex128_nds(x64GenContext, 0, srcRegisterA, VEX_PP_66_0F, dstRegister < 8 ? 1 : 0, (dstRegister >= 8 && srcRegisterB >= 8) ? 1 : 0, srcRegisterB < 8 ? 0 : 1, 0x6D);\n\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (srcRegisterB & 7) + (dstRegister & 7) * 8);\n}\n\nvoid x64Gen_avx_VUNPCKHPD_xmm_xmm_xmm(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 srcRegisterA, sint32 srcRegisterB)\n{\n\t_x64Gen_vex128_nds(x64GenContext, 0, srcRegisterA, VEX_PP_66_0F, dstRegister < 8 ? 1 : 0, (dstRegister >= 8 && srcRegisterB >= 8) ? 1 : 0, srcRegisterB < 8 ? 0 : 1, 0x15);\n\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (srcRegisterB & 7) + (dstRegister & 7) * 8);\n}\n\nvoid x64Gen_avx_VSUBPD_xmm_xmm_xmm(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 srcRegisterA, sint32 srcRegisterB)\n{\n\t_x64Gen_vex128_nds(x64GenContext, 0, srcRegisterA, VEX_PP_66_0F, dstRegister < 8 ? 1 : 0, (dstRegister >= 8 && srcRegisterB >= 8) ? 1 : 0, srcRegisterB < 8 ? 0 : 1, 0x5C);\n\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (srcRegisterB & 7) + (dstRegister & 7) * 8);\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64BMI.cpp",
    "content": "#include \"BackendX64.h\"\n\nvoid _x64Gen_writeMODRMDeprecated(x64GenContext_t* x64GenContext, sint32 dataRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32);\n\nvoid x64Gen_movBEZeroExtend_reg64_mem32Reg64PlusReg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32)\n{\n\t// MOVBE <dstReg64> (low dword), DWORD [<reg64> + <reg64> + <imm64>]\n\tif( dstRegister >= 8 && memRegisterA64 >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x47);\n\telse if( memRegisterA64 >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x43);\n\telse if( dstRegister >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x42);\n\telse if( dstRegister >= 8 && memRegisterA64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( dstRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( memRegisterA64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if( memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x42);\n\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x38);\n\tx64Gen_writeU8(x64GenContext, 0xF0);\n\t_x64Gen_writeMODRMDeprecated(x64GenContext, dstRegister, memRegisterA64, memRegisterB64, memImmS32);\n}\n\nvoid x64Gen_movBEZeroExtend_reg64Low16_mem16Reg64PlusReg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32)\n{\n\t// MOVBE <dstReg64> (low word), WORD [<reg64> + <reg64> + <imm64>]\n\t// note: Unlike the 32bit version this instruction does not set the upper 32bits of the 64bit register to 0\n\tx64Gen_writeU8(x64GenContext, 0x66); // 16bit prefix\n\tx64Gen_movBEZeroExtend_reg64_mem32Reg64PlusReg64(x64GenContext, dstRegister, memRegisterA64, memRegisterB64, memImmS32);\n}\n\nvoid x64Gen_movBETruncate_mem32Reg64PlusReg64_reg64(x64GenContext_t* x64GenContext, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32, sint32 srcRegister)\n{\n\t// MOVBE DWORD [<reg64> + <reg64> + <imm64>], <srcReg64> (low dword)\n\tif( srcRegister >= 8 && memRegisterA64 >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x47);\n\telse if( memRegisterA64 >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x43);\n\telse if( srcRegister >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x42);\n\telse if( srcRegister >= 8 && memRegisterA64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( memRegisterA64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if( memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x42);\n\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x38);\n\tx64Gen_writeU8(x64GenContext, 0xF1);\n\t_x64Gen_writeMODRMDeprecated(x64GenContext, srcRegister, memRegisterA64, memRegisterB64, memImmS32);\n}\n\nvoid x64Gen_shrx_reg64_reg64_reg64(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB)\n{\n\t// SHRX reg64, reg64, reg64\n\tx64Gen_writeU8(x64GenContext, 0xC4);\n\tx64Gen_writeU8(x64GenContext, 0xE2 - ((registerDst >= 8) ? 0x80 : 0) - ((registerA >= 8) ? 0x20 : 0));\n\tx64Gen_writeU8(x64GenContext, 0xFB - registerB * 8);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (registerDst & 7) * 8 + (registerA & 7));\n}\n\nvoid x64Gen_shrx_reg32_reg32_reg32(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB)\n{\n\tx64Gen_writeU8(x64GenContext, 0xC4);\n\tx64Gen_writeU8(x64GenContext, 0xE2 - ((registerDst >= 8) ? 0x80 : 0) - ((registerA >= 8) ? 0x20 : 0));\n\tx64Gen_writeU8(x64GenContext, 0x7B - registerB * 8);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (registerDst & 7) * 8 + (registerA & 7));\n}\n\nvoid x64Gen_sarx_reg64_reg64_reg64(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB)\n{\n\t// SARX reg64, reg64, reg64\n\tx64Gen_writeU8(x64GenContext, 0xC4);\n\tx64Gen_writeU8(x64GenContext, 0xE2 - ((registerDst >= 8) ? 0x80 : 0) - ((registerA >= 8) ? 0x20 : 0));\n\tx64Gen_writeU8(x64GenContext, 0xFA - registerB * 8);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (registerDst & 7) * 8 + (registerA & 7));\n}\n\nvoid x64Gen_sarx_reg32_reg32_reg32(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB)\n{\n\tx64Gen_writeU8(x64GenContext, 0xC4);\n\tx64Gen_writeU8(x64GenContext, 0xE2 - ((registerDst >= 8) ? 0x80 : 0) - ((registerA >= 8) ? 0x20 : 0));\n\tx64Gen_writeU8(x64GenContext, 0x7A - registerB * 8);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (registerDst & 7) * 8 + (registerA & 7));\n}\n\nvoid x64Gen_shlx_reg64_reg64_reg64(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB)\n{\n\t// SHLX reg64, reg64, reg64\n\tx64Gen_writeU8(x64GenContext, 0xC4);\n\tx64Gen_writeU8(x64GenContext, 0xE2 - ((registerDst >= 8) ? 0x80 : 0) - ((registerA >= 8) ? 0x20 : 0));\n\tx64Gen_writeU8(x64GenContext, 0xF9 - registerB * 8);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (registerDst & 7) * 8 + (registerA & 7));\n}\n\nvoid x64Gen_shlx_reg32_reg32_reg32(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 registerA, sint32 registerB)\n{\n\tx64Gen_writeU8(x64GenContext, 0xC4);\n\tx64Gen_writeU8(x64GenContext, 0xE2 - ((registerDst >= 8) ? 0x80 : 0) - ((registerA >= 8) ? 0x20 : 0));\n\tx64Gen_writeU8(x64GenContext, 0x79 - registerB * 8);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (registerDst & 7) * 8 + (registerA & 7));\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64FPU.cpp",
    "content": "#include \"../PPCRecompiler.h\"\n#include \"../IML/IML.h\"\n#include \"BackendX64.h\"\n#include \"Common/cpu_features.h\"\n\nuint32 _regF64(IMLReg physReg);\n\nuint32 _regI32(IMLReg r)\n{\n\tcemu_assert_debug(r.GetRegFormat() == IMLRegFormat::I32);\n\treturn (uint32)r.GetRegID();\n}\n\nstatic x86Assembler64::GPR32 _reg32(sint8 physRegId)\n{\n\treturn (x86Assembler64::GPR32)physRegId;\n}\n\nstatic x86Assembler64::GPR8_REX _reg8(IMLReg r)\n{\n\tcemu_assert_debug(r.GetRegFormat() == IMLRegFormat::I32); // currently bool regs are implemented as 32bit registers\n\treturn (x86Assembler64::GPR8_REX)r.GetRegID();\n}\n\nstatic x86Assembler64::GPR32 _reg32_from_reg8(x86Assembler64::GPR8_REX regId)\n{\n\treturn (x86Assembler64::GPR32)regId;\n}\n\nstatic x86Assembler64::GPR8_REX _reg8_from_reg32(x86Assembler64::GPR32 regId)\n{\n\treturn (x86Assembler64::GPR8_REX)regId;\n}\n\n// load from memory\nbool PPCRecompilerX64Gen_imlInstruction_fpr_load(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, bool indexed)\n{\n\tsint32 realRegisterXMM =  _regF64(imlInstruction->op_storeLoad.registerData);\n\tsint32 realRegisterMem = _regI32(imlInstruction->op_storeLoad.registerMem);\n\tsint32 realRegisterMem2 = PPC_REC_INVALID_REGISTER;\n\tif( indexed )\n\t\trealRegisterMem2 = _regI32(imlInstruction->op_storeLoad.registerMem2);\n\tuint8 mode = imlInstruction->op_storeLoad.mode;\n\n\tif( mode == PPCREC_FPR_LD_MODE_SINGLE )\n\t{\n\t\t// load byte swapped single into temporary FPR\n\t\tif( indexed )\n\t\t{\n\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, realRegisterMem2);\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, realRegisterMem);\n\t\t\tif(g_CPUFeatures.x86.movbe)\n\t\t\t\tx64Gen_movBEZeroExtend_reg64_mem32Reg64PlusReg64(x64GenContext, REG_RESV_TEMP, REG_RESV_MEMBASE, REG_RESV_TEMP, imlInstruction->op_storeLoad.immS32);\n\t\t\telse\n\t\t\t\tx64Emit_mov_reg32_mem32(x64GenContext, REG_RESV_TEMP, REG_RESV_MEMBASE, REG_RESV_TEMP, imlInstruction->op_storeLoad.immS32);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(g_CPUFeatures.x86.movbe)\n\t\t\t\tx64Gen_movBEZeroExtend_reg64_mem32Reg64PlusReg64(x64GenContext, REG_RESV_TEMP, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32);\n\t\t\telse\n\t\t\t\tx64Emit_mov_reg32_mem32(x64GenContext, REG_RESV_TEMP, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32);\n\t\t}\n\t\tif(g_CPUFeatures.x86.movbe == false )\n\t\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, REG_RESV_TEMP);\n\t\tx64Gen_movd_xmmReg_reg64Low32(x64GenContext, realRegisterXMM, REG_RESV_TEMP);\n\n\t\tif (imlInstruction->op_storeLoad.flags2.notExpanded)\n\t\t{\n\t\t\t// leave value as single\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_cvtss2sd_xmmReg_xmmReg(x64GenContext, realRegisterXMM, realRegisterXMM);\n\t\t}\n\t}\n\telse if( mode == PPCREC_FPR_LD_MODE_DOUBLE )\n\t{\n\t\tif( g_CPUFeatures.x86.avx )\n\t\t{\n\t\t\tif( indexed )\n\t\t\t{\n\t\t\t\t// calculate offset\n\t\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, realRegisterMem);\n\t\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, realRegisterMem2);\n\t\t\t\t// load value\n\t\t\t\tx64Emit_mov_reg64_mem64(x64GenContext, REG_RESV_TEMP, REG_RESV_MEMBASE, REG_RESV_TEMP, imlInstruction->op_storeLoad.immS32+0);\n\t\t\t\tx64GenContext->emitter->BSWAP_q(REG_RESV_TEMP);\n\t\t\t\tx64Gen_movq_xmmReg_reg64(x64GenContext, REG_RESV_FPR_TEMP, REG_RESV_TEMP);\n\t\t\t\tx64Gen_movsd_xmmReg_xmmReg(x64GenContext, realRegisterXMM, REG_RESV_FPR_TEMP);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tx64Emit_mov_reg64_mem64(x64GenContext, REG_RESV_TEMP, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32+0);\n\t\t\t\tx64GenContext->emitter->BSWAP_q(REG_RESV_TEMP);\n\t\t\t\tx64Gen_movq_xmmReg_reg64(x64GenContext, REG_RESV_FPR_TEMP, REG_RESV_TEMP);\n\t\t\t\tx64Gen_movsd_xmmReg_xmmReg(x64GenContext, realRegisterXMM, REG_RESV_FPR_TEMP);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif( indexed )\n\t\t\t{\n\t\t\t\t// calculate offset\n\t\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, realRegisterMem);\n\t\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, realRegisterMem2);\n\t\t\t\t// load double low part to temporaryFPR\n\t\t\t\tx64Emit_mov_reg32_mem32(x64GenContext, REG_RESV_TEMP, REG_RESV_MEMBASE, REG_RESV_TEMP, imlInstruction->op_storeLoad.immS32+0);\n\t\t\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, REG_RESV_TEMP);\n\t\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR)+4, REG_RESV_TEMP);\n\t\t\t\t// calculate offset again\n\t\t\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, realRegisterMem);\n\t\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, realRegisterMem2);\n\t\t\t\t// load double high part to temporaryFPR\n\t\t\t\tx64Emit_mov_reg32_mem32(x64GenContext, REG_RESV_TEMP, REG_RESV_MEMBASE, REG_RESV_TEMP, imlInstruction->op_storeLoad.immS32+4);\n\t\t\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, REG_RESV_TEMP);\n\t\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR)+0, REG_RESV_TEMP);\n\t\t\t\t// load double from temporaryFPR\n\t\t\t\tx64Gen_movlpd_xmmReg_memReg64(x64GenContext, realRegisterXMM, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// load double low part to temporaryFPR\n\t\t\t\tx64Emit_mov_reg32_mem32(x64GenContext, REG_RESV_TEMP, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32+0);\n\t\t\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, REG_RESV_TEMP);\n\t\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR)+4, REG_RESV_TEMP);\n\t\t\t\t// load double high part to temporaryFPR\n\t\t\t\tx64Emit_mov_reg32_mem32(x64GenContext, REG_RESV_TEMP, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32+4);\n\t\t\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, REG_RESV_TEMP);\n\t\t\t\tx64Emit_mov_mem32_reg64(x64GenContext, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR)+0, REG_RESV_TEMP);\n\t\t\t\t// load double from temporaryFPR\n\t\t\t\tx64Gen_movlpd_xmmReg_memReg64(x64GenContext, realRegisterXMM, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR));\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n// store to memory\nbool PPCRecompilerX64Gen_imlInstruction_fpr_store(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction, bool indexed)\n{\n\tsint32 realRegisterXMM = _regF64(imlInstruction->op_storeLoad.registerData);\n\tsint32 realRegisterMem = _regI32(imlInstruction->op_storeLoad.registerMem);\n\tsint32 realRegisterMem2 = PPC_REC_INVALID_REGISTER;\n\tif( indexed )\n\t\trealRegisterMem2 = _regI32(imlInstruction->op_storeLoad.registerMem2);\n\tuint8 mode = imlInstruction->op_storeLoad.mode;\n\tif( mode == PPCREC_FPR_ST_MODE_SINGLE )\n\t{\n\t\tif (imlInstruction->op_storeLoad.flags2.notExpanded)\n\t\t{\n\t\t\t// value is already in single format\n\t\t\tx64Gen_movd_reg64Low32_xmmReg(x64GenContext, REG_RESV_TEMP, realRegisterXMM);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_cvtsd2ss_xmmReg_xmmReg(x64GenContext, REG_RESV_FPR_TEMP, realRegisterXMM);\n\t\t\tx64Gen_movd_reg64Low32_xmmReg(x64GenContext, REG_RESV_TEMP, REG_RESV_FPR_TEMP);\n\t\t}\n\t\tif(g_CPUFeatures.x86.movbe == false )\n\t\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, REG_RESV_TEMP);\n\t\tif( indexed )\n\t\t{\n\t\t\tif( realRegisterMem == realRegisterMem2 )\n\t\t\t\tassert_dbg();\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\t}\n\t\tif(g_CPUFeatures.x86.movbe)\n\t\t\tx64Gen_movBETruncate_mem32Reg64PlusReg64_reg64(x64GenContext, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32, REG_RESV_TEMP);\n\t\telse\n\t\t\tx64Gen_movTruncate_mem32Reg64PlusReg64_reg64(x64GenContext, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32, REG_RESV_TEMP);\n\t\tif( indexed )\n\t\t{\n\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\t}\n\t}\n\telse if( mode == PPCREC_FPR_ST_MODE_DOUBLE )\n\t{\n\t\tif( indexed )\n\t\t{\n\t\t\tif( realRegisterMem == realRegisterMem2 )\n\t\t\t\tassert_dbg();\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\t}\n\t\tx64Gen_movsd_memReg64_xmmReg(x64GenContext, realRegisterXMM, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR));\n\t\t// store double low part\t\n\t\tx64Emit_mov_reg64_mem32(x64GenContext, REG_RESV_TEMP, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR)+0);\n\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, REG_RESV_TEMP);\n\t\tx64Gen_movTruncate_mem32Reg64PlusReg64_reg64(x64GenContext, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32+4, REG_RESV_TEMP);\n\t\t// store double high part\t\n\t\tx64Emit_mov_reg64_mem32(x64GenContext, REG_RESV_TEMP, REG_RESV_HCPU, offsetof(PPCInterpreter_t, temporaryFPR)+4);\n\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, REG_RESV_TEMP);\n\t\tx64Gen_movTruncate_mem32Reg64PlusReg64_reg64(x64GenContext, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32+0, REG_RESV_TEMP);\n\t\tif( indexed )\n\t\t{\n\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\t}\n\t}\n\telse if( mode == PPCREC_FPR_ST_MODE_UI32_FROM_PS0 )\n\t{\n\t\tx64Gen_movd_reg64Low32_xmmReg(x64GenContext, REG_RESV_TEMP, realRegisterXMM);\n\t\tx64Gen_bswap_reg64Lower32bit(x64GenContext, REG_RESV_TEMP);\n\t\tif( indexed )\n\t\t{\n\t\t\tcemu_assert_debug(realRegisterMem == realRegisterMem2);\n\t\t\tx64Gen_add_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\t\tx64Gen_movTruncate_mem32Reg64PlusReg64_reg64(x64GenContext, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32, REG_RESV_TEMP);\n\t\t\tx64Gen_sub_reg64Low32_reg64Low32(x64GenContext, realRegisterMem, realRegisterMem2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_movTruncate_mem32Reg64PlusReg64_reg64(x64GenContext, REG_RESV_MEMBASE, realRegisterMem, imlInstruction->op_storeLoad.immS32, REG_RESV_TEMP);\n\t\t}\n\t}\n\telse\n\t{\n\t\tdebug_printf(\"PPCRecompilerX64Gen_imlInstruction_fpr_store(): Unsupported mode %d\\n\", mode);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n// FPR op FPR\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tif( imlInstruction->operation == PPCREC_IML_OP_FPR_FLOAT_TO_INT )\n\t{\n\t\tuint32 regGpr = _regI32(imlInstruction->op_fpr_r_r.regR);\n\t\tuint32 regFpr = _regF64(imlInstruction->op_fpr_r_r.regA);\n\t\tx64Gen_cvttsd2si_reg64Low_xmmReg(x64GenContext, regGpr, regFpr);\n\t\treturn;\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_INT_TO_FLOAT )\n\t{\n\t\tuint32 regFpr = _regF64(imlInstruction->op_fpr_r_r.regR);\n\t\tuint32 regGpr = _regI32(imlInstruction->op_fpr_r_r.regA);\n\t\tx64Gen_cvtsi2sd_xmmReg_xmmReg(x64GenContext, regFpr, regGpr);\n\t\treturn;\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_BITCAST_INT_TO_FLOAT)\n\t{\n\t\tcemu_assert_debug(imlInstruction->op_fpr_r_r.regR.GetRegFormat() == IMLRegFormat::F64); // assuming target is always F64 for now\n\t\tcemu_assert_debug(imlInstruction->op_fpr_r_r.regA.GetRegFormat() == IMLRegFormat::I32); // supporting only 32bit floats as input for now\n\t\t// exact operation depends on size of types. Floats are automatically promoted to double if the target is F64\n\t\tuint32 regFpr = _regF64(imlInstruction->op_fpr_r_r.regR);\n\t\tif (imlInstruction->op_fpr_r_r.regA.GetRegFormat() == IMLRegFormat::I32)\n\t\t{\n\t\t\tuint32 regGpr = _regI32(imlInstruction->op_fpr_r_r.regA);\n\t\t\tx64Gen_movq_xmmReg_reg64(x64GenContext, regFpr, regGpr); // using reg32 as reg64 param here is ok. We'll refactor later\n\t\t\t// float to double\n\t\t\tx64Gen_cvtss2sd_xmmReg_xmmReg(x64GenContext, regFpr, regFpr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\treturn;\n\t}\n\n\tuint32 regR = _regF64(imlInstruction->op_fpr_r_r.regR);\n\tuint32 regA = _regF64(imlInstruction->op_fpr_r_r.regA);\n\tif( imlInstruction->operation == PPCREC_IML_OP_FPR_ASSIGN )\n\t{\n\t\tx64Gen_movsd_xmmReg_xmmReg(x64GenContext, regR, regA);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_MULTIPLY )\n\t{\n\t\tx64Gen_mulsd_xmmReg_xmmReg(x64GenContext, regR, regA);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_DIVIDE )\n\t{\n\t\tx64Gen_divsd_xmmReg_xmmReg(x64GenContext, regR, regA);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_ADD )\n\t{\n\t\tx64Gen_addsd_xmmReg_xmmReg(x64GenContext, regR, regA);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_SUB )\n\t{\n\t\tx64Gen_subsd_xmmReg_xmmReg(x64GenContext, regR, regA);\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_FCTIWZ )\n\t{\n\t\tx64Gen_cvttsd2si_xmmReg_xmmReg(x64GenContext, REG_RESV_TEMP, regA);\n\t\tx64Gen_mov_reg64Low32_reg64Low32(x64GenContext, REG_RESV_TEMP, REG_RESV_TEMP);\n\t\t// move to FPR register\n\t\tx64Gen_movq_xmmReg_reg64(x64GenContext, regR, REG_RESV_TEMP);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\n/*\n * FPR = op (fprA, fprB)\n */\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_r_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tuint32 regR = _regF64(imlInstruction->op_fpr_r_r_r.regR);\n\tuint32 regA = _regF64(imlInstruction->op_fpr_r_r_r.regA);\n\tuint32 regB = _regF64(imlInstruction->op_fpr_r_r_r.regB);\n\n\tif (imlInstruction->operation == PPCREC_IML_OP_FPR_MULTIPLY)\n\t{\n\t\tif (regR == regA)\n\t\t{\n\t\t\tx64Gen_mulsd_xmmReg_xmmReg(x64GenContext, regR, regB);\n\t\t}\n\t\telse if (regR == regB)\n\t\t{\n\t\t\tx64Gen_mulsd_xmmReg_xmmReg(x64GenContext, regR, regA);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_movsd_xmmReg_xmmReg(x64GenContext, regR, regA);\n\t\t\tx64Gen_mulsd_xmmReg_xmmReg(x64GenContext, regR, regB);\n\t\t}\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_ADD)\n\t{\n\t\t// todo: Use AVX 3-operand VADDSD if available\n\t\tif (regR == regA)\n\t\t{\n\t\t\tx64Gen_addsd_xmmReg_xmmReg(x64GenContext, regR, regB);\n\t\t}\n\t\telse if (regR == regB)\n\t\t{\n\t\t\tx64Gen_addsd_xmmReg_xmmReg(x64GenContext, regR, regA);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_movaps_xmmReg_xmmReg(x64GenContext, regR, regA);\n\t\t\tx64Gen_addsd_xmmReg_xmmReg(x64GenContext, regR, regB);\n\t\t}\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_SUB )\n\t{\n\t\tif( regR == regA )\n\t\t{\n\t\t\tx64Gen_subsd_xmmReg_xmmReg(x64GenContext, regR, regB);\n\t\t}\n\t\telse if( regR == regB )\n\t\t{\n\t\t\tx64Gen_movsd_xmmReg_xmmReg(x64GenContext, REG_RESV_FPR_TEMP, regA);\n\t\t\tx64Gen_subsd_xmmReg_xmmReg(x64GenContext, REG_RESV_FPR_TEMP, regB);\n\t\t\tx64Gen_movsd_xmmReg_xmmReg(x64GenContext, regR, REG_RESV_FPR_TEMP);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_movsd_xmmReg_xmmReg(x64GenContext, regR, regA);\n\t\t\tx64Gen_subsd_xmmReg_xmmReg(x64GenContext, regR, regB);\n\t\t}\n\t}\n\telse\n\t\tassert_dbg();\n}\n\n/*\n * FPR = op (fprA, fprB, fprC)\n */\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_r_r_r_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tuint32 regR = _regF64(imlInstruction->op_fpr_r_r_r_r.regR);\n\tuint32 regA = _regF64(imlInstruction->op_fpr_r_r_r_r.regA);\n\tuint32 regB = _regF64(imlInstruction->op_fpr_r_r_r_r.regB);\n\tuint32 regC = _regF64(imlInstruction->op_fpr_r_r_r_r.regC);\n\n\tif( imlInstruction->operation == PPCREC_IML_OP_FPR_SELECT )\n\t{\n\t\tx64Gen_comisd_xmmReg_mem64Reg64(x64GenContext, regA, REG_RESV_RECDATA, offsetof(PPCRecompilerInstanceData_t, _x64XMM_constDouble0_0));\n\t\tsint32 jumpInstructionOffset1 = x64GenContext->emitter->GetWriteIndex();\n\t\tx64Gen_jmpc_near(x64GenContext, X86_CONDITION_UNSIGNED_BELOW, 0);\n\t\t// select C\n\t\tx64Gen_movsd_xmmReg_xmmReg(x64GenContext, regR, regC);\n\t\tsint32 jumpInstructionOffset2 = x64GenContext->emitter->GetWriteIndex();\n\t\tx64Gen_jmpc_near(x64GenContext, X86_CONDITION_NONE, 0);\n\t\t// select B\n\t\tPPCRecompilerX64Gen_redirectRelativeJump(x64GenContext, jumpInstructionOffset1, x64GenContext->emitter->GetWriteIndex());\n\t\tx64Gen_movsd_xmmReg_xmmReg(x64GenContext, regR, regB);\n\t\t// end\n\t\tPPCRecompilerX64Gen_redirectRelativeJump(x64GenContext, jumpInstructionOffset2, x64GenContext->emitter->GetWriteIndex());\n\t}\n\telse\n\t\tassert_dbg();\n}\n\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_r(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tuint32 regR = _regF64(imlInstruction->op_fpr_r.regR);\n\n\tif( imlInstruction->operation == PPCREC_IML_OP_FPR_NEGATE )\n\t{\n\t\tx64Gen_xorps_xmmReg_mem128Reg64(x64GenContext, regR, REG_RESV_RECDATA, offsetof(PPCRecompilerInstanceData_t, _x64XMM_xorNegateMaskBottom));\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_LOAD_ONE )\n\t{\n\t\tx64Gen_movsd_xmmReg_memReg64(x64GenContext, regR, REG_RESV_RECDATA, offsetof(PPCRecompilerInstanceData_t, _x64XMM_constDouble1_1));\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_ABS )\n\t{\n\t\tx64Gen_andps_xmmReg_mem128Reg64(x64GenContext, regR, REG_RESV_RECDATA, offsetof(PPCRecompilerInstanceData_t, _x64XMM_andAbsMaskBottom));\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_NEGATIVE_ABS )\n\t{\n\t\tx64Gen_orps_xmmReg_mem128Reg64(x64GenContext, regR, REG_RESV_RECDATA, offsetof(PPCRecompilerInstanceData_t, _x64XMM_xorNegateMaskBottom));\n\t}\n\telse if( imlInstruction->operation == PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_BOTTOM )\n\t{\n\t\t// convert to 32bit single\n\t\tx64Gen_cvtsd2ss_xmmReg_xmmReg(x64GenContext, regR, regR);\n\t\t// convert back to 64bit double\n\t\tx64Gen_cvtss2sd_xmmReg_xmmReg(x64GenContext, regR, regR);\n\t}\n\telse if (imlInstruction->operation == PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64)\n\t{\n\t\t// convert bottom to 64bit double\n\t\tx64Gen_cvtss2sd_xmmReg_xmmReg(x64GenContext, regR, regR);\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n}\n\nvoid PPCRecompilerX64Gen_imlInstruction_fpr_compare(PPCRecFunction_t* PPCRecFunction, ppcImlGenContext_t* ppcImlGenContext, x64GenContext_t* x64GenContext, IMLInstruction* imlInstruction)\n{\n\tauto regR = _reg8(imlInstruction->op_fpr_compare.regR);\n\tauto regA = _regF64(imlInstruction->op_fpr_compare.regA);\n\tauto regB = _regF64(imlInstruction->op_fpr_compare.regB);\n\n\tx64GenContext->emitter->XOR_dd(_reg32_from_reg8(regR), _reg32_from_reg8(regR));\n\tx64Gen_ucomisd_xmmReg_xmmReg(x64GenContext, regA, regB);\n\n\tif (imlInstruction->op_fpr_compare.cond == IMLCondition::UNORDERED_GT)\n\t{\n\t\t// GT case can be covered with a single SETnbe which checks CF==0 && ZF==0 (unordered sets both)\n\t\tx64GenContext->emitter->SETcc_b(X86Cond::X86_CONDITION_NBE, regR);\n\t\treturn;\n\t}\n\telse if (imlInstruction->op_fpr_compare.cond == IMLCondition::UNORDERED_U)\n\t{\n\t\t// unordered case can be checked via PF\n\t\tx64GenContext->emitter->SETcc_b(X86Cond::X86_CONDITION_PE, regR);\n\t\treturn;\n\t}\n\n\t// remember unordered state\n\tauto regTmp = _reg32_from_reg8(_reg32(REG_RESV_TEMP));\n\tx64GenContext->emitter->SETcc_b(X86Cond::X86_CONDITION_PO, regTmp); // by reversing the parity we can avoid having to XOR the value for masking the LT/EQ conditions\n\n\tX86Cond x86Cond;\n\tswitch (imlInstruction->op_fpr_compare.cond)\n\t{\n\tcase IMLCondition::UNORDERED_LT:\n\t\tx64GenContext->emitter->SETcc_b(X86Cond::X86_CONDITION_B, regR);\n\t\tbreak;\n\tcase IMLCondition::UNORDERED_EQ:\n\t\tx64GenContext->emitter->SETcc_b(X86Cond::X86_CONDITION_Z, regR);\n\t\tbreak;\n\tdefault:\n\t\tcemu_assert_unimplemented();\n\t}\n\tx64GenContext->emitter->AND_bb(_reg8_from_reg32(regR), _reg8_from_reg32(regTmp)); // if unordered (PF=1) then force LT/GT/EQ to zero \n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64Gen.cpp",
    "content": "#include \"BackendX64.h\"\n\n// x86/x64 extension opcodes that could be useful:\n// ANDN\n// mulx, rorx, sarx, shlx, shrx\n// PDEP, PEXT\n\nvoid x64Gen_writeU8(x64GenContext_t* x64GenContext, uint8 v)\n{\n\tx64GenContext->emitter->_emitU8(v);\n}\n\nvoid x64Gen_writeU16(x64GenContext_t* x64GenContext, uint32 v)\n{\n\tx64GenContext->emitter->_emitU16(v);\n}\n\nvoid x64Gen_writeU32(x64GenContext_t* x64GenContext, uint32 v)\n{\n\tx64GenContext->emitter->_emitU32(v);\n}\n\nvoid x64Gen_writeU64(x64GenContext_t* x64GenContext, uint64 v)\n{\n\tx64GenContext->emitter->_emitU64(v);\n}\n\n#include \"X64Emit.hpp\"\n\nvoid _x64Gen_writeMODRMDeprecated(x64GenContext_t* x64GenContext, sint32 dataRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32)\n{\n\tbool forceUseOffset = false;\n\tif ((memRegisterA64 & 7) == 5)\n\t{\n\t\t// RBP and R13 have no memImmS32 == 0 encoding, therefore we need to use a 1 byte offset with the value 0\n\t\tforceUseOffset = true;\n\t}\n\n\tif (memRegisterB64 == X86_REG_NONE)\n\t{\n\t\t// memRegisterA64 + memImmS32\n\t\tuint8 modRM = (dataRegister & 7) * 8 + (memRegisterA64 & 7);\n\t\tif (forceUseOffset && memImmS32 == 0)\n\t\t{\n\t\t\t// 1 byte offset\n\t\t\tmodRM |= (1 << 6);\n\t\t}\n\t\tif (memImmS32 == 0)\n\t\t{\n\t\t\t// no offset\n\t\t\tmodRM |= (0 << 6);\n\t\t}\n\t\telse if (memImmS32 >= -128 && memImmS32 <= 127)\n\t\t{\n\t\t\t// 1 byte offset\n\t\t\tmodRM |= (1 << 6);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// 4 byte offset\n\t\t\tmodRM |= (2 << 6);\n\t\t}\n\t\tx64Gen_writeU8(x64GenContext, modRM);\n\t\t// SIB byte\n\t\tif ((memRegisterA64 & 7) == 4) // RSP and R12\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t}\n\t\t// offset\n\t\tif (((modRM >> 6) & 3) == 0)\n\t\t\t; // no offset\n\t\telse if (((modRM >> 6) & 3) == 1)\n\t\t\tx64Gen_writeU8(x64GenContext, (uint8)memImmS32);\n\t\telse if (((modRM >> 6) & 3) == 2)\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t\telse\n\t\t\tassert_dbg();\n\t\treturn;\n\t}\n\t// note: Swapping mem register A and mem register B does not work because the instruction prefix defines the register group which might not match (e.g. regA in r0-r8 range and regB in RAX-RDI range)\n\tif( (memRegisterA64&7) == 4 )\n\t{\n\t\tassert_dbg();\n\t\t//sint32 temp = memRegisterA64;\n\t\t//memRegisterA64 = memRegisterB64;\n\t\t//memRegisterB64 = temp;\n\t}\n\t//if( (memRegisterA64&7) == 5 )\n\t//{\n\t//\tsint32 temp = memRegisterA64;\n\t//\tmemRegisterA64 = memRegisterB64;\n\t//\tmemRegisterB64 = temp;\n\t//}\n\tif( (memRegisterA64&7) == 4 )\n\t\tassert_dbg();\n\tuint8 modRM = (0x04<<0)+((dataRegister&7)<<3);\n\tif( forceUseOffset && memImmS32 == 0 )\n\t{\n\t\t// 1 byte offset\n\t\tmodRM |= (1<<6);\n\t}\n\tif( memImmS32 == 0 )\n\t{\n\t\t// no offset\n\t\tmodRM |= (0<<6);\n\t}\n\telse if( memImmS32 >= -128 && memImmS32 <= 127 )\n\t{\n\t\t// 1 byte offset\n\t\tmodRM |= (1<<6);\n\t}\n\telse\n\t{\n\t\t// 4 byte offset\n\t\tmodRM |= (2<<6);\n\t}\n\tx64Gen_writeU8(x64GenContext, modRM);\n\t// sib byte\n\tx64Gen_writeU8(x64GenContext, 0x00+(memRegisterA64&7)+(memRegisterB64&7)*8);\n\t// offset\n\tif( ((modRM>>6)&3) == 0 )\n\t\t; // no offset\n\telse if( ((modRM>>6)&3) == 1 )\n\t\tx64Gen_writeU8(x64GenContext, (uint8)memImmS32);\n\telse if( ((modRM>>6)&3) == 2 )\n\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\telse\n\t\tassert_dbg();\n}\n\nvoid x64Emit_mov_reg32_mem32(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memOffset)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_1byte<0x8B>>(x64GenContext, x64MODRM_opr_reg64(destReg), x64MODRM_opr_memReg64(memBaseReg64, memOffset));\n}\n\nvoid x64Emit_mov_mem32_reg32(x64GenContext_t* x64GenContext, sint32 memBaseReg64, sint32 memOffset, sint32 srcReg)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_1byte_rev<0x89>>(x64GenContext, x64MODRM_opr_memReg64(memBaseReg64, memOffset), x64MODRM_opr_reg64(srcReg));\n}\n\nvoid x64Emit_mov_mem64_reg64(x64GenContext_t* x64GenContext, sint32 memBaseReg64, sint32 memOffset, sint32 srcReg)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_1byte_rev<0x89, true>>(x64GenContext, x64MODRM_opr_memReg64(memBaseReg64, memOffset), x64MODRM_opr_reg64(srcReg));\n}\n\nvoid x64Emit_mov_reg64_mem64(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memOffset)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_1byte<0x8B, true>>(x64GenContext, x64MODRM_opr_reg64(destReg), x64MODRM_opr_memReg64(memBaseReg64, memOffset));\n}\n\nvoid x64Emit_mov_reg64_mem32(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memOffset)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_1byte<0x8B>>(x64GenContext, x64MODRM_opr_reg64(destReg), x64MODRM_opr_memReg64(memBaseReg64, memOffset));\n}\n\nvoid x64Emit_mov_mem32_reg64(x64GenContext_t* x64GenContext, sint32 memBaseReg64, sint32 memOffset, sint32 srcReg)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_1byte_rev<0x89>>(x64GenContext, x64MODRM_opr_memReg64(memBaseReg64, memOffset), x64MODRM_opr_reg64(srcReg));\n}\n\nvoid x64Emit_mov_reg64_mem64(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memIndexReg64, sint32 memOffset)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_1byte<0x8B, true>>(x64GenContext, x64MODRM_opr_reg64(destReg), x64MODRM_opr_memRegPlusReg(memBaseReg64, memIndexReg64, memOffset));\n}\n\nvoid x64Emit_mov_reg32_mem32(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memIndexReg64, sint32 memOffset)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_1byte<0x8B>>(x64GenContext, x64MODRM_opr_reg64(destReg), x64MODRM_opr_memRegPlusReg(memBaseReg64, memIndexReg64, memOffset));\n}\n\nvoid x64Emit_mov_reg64b_mem8(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memIndexReg64, sint32 memOffset)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_1byte<0x8A>>(x64GenContext, x64MODRM_opr_reg64(destReg), x64MODRM_opr_memRegPlusReg(memBaseReg64, memIndexReg64, memOffset));\n}\n\nvoid x64Emit_movZX_reg32_mem8(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memIndexReg64, sint32 memOffset)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_2byte<0x0F,0xB6>>(x64GenContext, x64MODRM_opr_reg64(destReg), x64MODRM_opr_memRegPlusReg(memBaseReg64, memIndexReg64, memOffset));\n}\n\nvoid x64Emit_movZX_reg64_mem8(x64GenContext_t* x64GenContext, sint32 destReg, sint32 memBaseReg64, sint32 memOffset)\n{\n\tx64Gen_writeMODRM_dyn<x64_opc_2byte<0x0F, 0xB6>>(x64GenContext, x64MODRM_opr_reg64(destReg), x64MODRM_opr_memReg64(memBaseReg64, memOffset));\n}\n\nvoid x64Gen_movSignExtend_reg64Low32_mem8Reg64PlusReg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32)\n{\n\t// MOVSX <dstReg64> (low dword), BYTE [<reg64> + <reg64> + <imm64>]\n\tif (dstRegister >= 8 && memRegisterA64 >= 8 && memRegisterB64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x47);\n\telse if (memRegisterA64 >= 8 && memRegisterB64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x43);\n\telse if (dstRegister >= 8 && memRegisterB64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x42);\n\telse if (dstRegister >= 8 && memRegisterA64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if (dstRegister >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if (memRegisterA64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if (memRegisterB64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x42);\n\telse if (dstRegister >= 4)\n\t\tx64Gen_writeU8(x64GenContext, 0x40);\n\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xBE);\n\t_x64Gen_writeMODRMDeprecated(x64GenContext, dstRegister, memRegisterA64, memRegisterB64, memImmS32);\n}\n\nvoid x64Gen_mov_mem64Reg64PlusReg64_reg64(x64GenContext_t* x64GenContext, sint32 srcRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32)\n{\n\t// MOV QWORD [<reg64> + <reg64> + <imm64>], <dstReg64>\n\tif( srcRegister >= 8 && memRegisterA64 >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x47|8);\n\telse if( memRegisterA64 >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x43|8);\n\telse if( srcRegister >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x42|8);\n\telse if( srcRegister >= 8 && memRegisterA64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45|8);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44|8);\n\telse if( memRegisterA64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41|8);\n\telse if( memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x42|8);\n\telse\n\t\tx64Gen_writeU8(x64GenContext, 0x48);\n\tx64Gen_writeU8(x64GenContext, 0x89);\n\t_x64Gen_writeMODRMDeprecated(x64GenContext, srcRegister, memRegisterA64, memRegisterB64, memImmS32);\n}\n\nvoid x64Gen_movZeroExtend_reg64Low16_mem16Reg64PlusReg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32)\n{\n\t// MOV <dstReg64> (low word), WORD [<reg64> + <reg64> + <imm64>]\n\tx64Gen_writeU8(x64GenContext, 0x66); // 16bit prefix\n\tx64Emit_mov_reg32_mem32(x64GenContext, dstRegister, memRegisterA64, memRegisterB64, memImmS32);\n}\n\nvoid x64Gen_movTruncate_mem32Reg64PlusReg64_reg64(x64GenContext_t* x64GenContext, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32, sint32 srcRegister)\n{\n\t// MOV DWORD [<reg64> + <reg64> + <imm64>], <srcReg64> (low dword)\n\tif( srcRegister >= 8 && memRegisterA64 >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x47);\n\telse if( memRegisterA64 >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x43);\n\telse if( srcRegister >= 8 && memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x42);\n\telse if( srcRegister >= 8 && memRegisterA64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( memRegisterA64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if( memRegisterB64 >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x42);\n\n\tx64Gen_writeU8(x64GenContext, 0x89);\n\t_x64Gen_writeMODRMDeprecated(x64GenContext, srcRegister, memRegisterA64, memRegisterB64, memImmS32);\n}\n\nvoid x64Gen_movTruncate_mem16Reg64PlusReg64_reg64(x64GenContext_t* x64GenContext, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32, sint32 srcRegister)\n{\n\t// MOV WORD [<reg64> + <reg64> + <imm64>], <srcReg64> (low dword)\n\tx64Gen_writeU8(x64GenContext, 0x66); // 16bit prefix\t\n\tx64Gen_movTruncate_mem32Reg64PlusReg64_reg64(x64GenContext, memRegisterA64, memRegisterB64, memImmS32, srcRegister);\n}\n\nvoid x64Gen_movTruncate_mem8Reg64PlusReg64_reg64(x64GenContext_t* x64GenContext, sint32 memRegisterA64, sint32 memRegisterB64, sint32 memImmS32, sint32 srcRegister)\n{\n\t// MOV BYTE [<reg64> + <reg64> + <imm64>], <srcReg64> (low byte)\n\n\t// when no REX byte is present: Source register can range from AL to BH\n\t// when a REX byte is present: Source register can range from AL to DIL or R8B to R15B\n\t// todo: We don't need the REX byte when when the source register is AL,BL,CL or DL and neither memRegister A or B are within r8 - r15\n\n\tuint8 rexByte = 0x40;\n\tif( srcRegister >= 8 )\n\t\trexByte |= (1<<2);\n\tif( memRegisterA64 >= 8 )\n\t\trexByte |= (1<<0);\n\tif( memRegisterB64 >= 8 )\n\t\trexByte |= (1<<1);\n\tx64Gen_writeU8(x64GenContext, rexByte);\n\n\tx64Gen_writeU8(x64GenContext, 0x88);\n\t_x64Gen_writeMODRMDeprecated(x64GenContext, srcRegister, memRegisterA64, memRegisterB64, memImmS32);\n}\n\nvoid x64Gen_mov_mem32Reg64_imm32(x64GenContext_t* x64GenContext, sint32 memRegister, uint32 memImmU32, uint32 dataImmU32)\n{\n\t// MOV DWORD [<memReg>+<memImmU32>], dataImmU32\n\tif( (memRegister&7) == 4 )\n\t{\n\t\tif( memRegister >= 8 )\n\t\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\t\tsint32 memImmS32 = (sint32)memImmU32;\n\t\tif( memImmS32 >= -128 && memImmS32 <= 127 )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0xC7);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint8)memImmU32);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0xC7);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t\t}\n\t\tx64Gen_writeU32(x64GenContext, dataImmU32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_mov_mem64Reg64_imm32(x64GenContext_t* x64GenContext, sint32 memRegister, uint32 memImmU32, uint32 dataImmU32)\n{\n\t// MOV QWORD [<memReg>+<memImmU32>], dataImmU32\n\tif( memRegister == X86_REG_R14 )\n\t{\n\t\tsint32 memImmS32 = (sint32)memImmU32;\n\t\tif( memImmS32 == 0 )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x49);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xC7);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x06);\n\t\t\tx64Gen_writeU32(x64GenContext, dataImmU32);\n\t\t}\n\t\telse if( memImmS32 >= -128 && memImmS32 <= 127 )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x49);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xC7);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x46);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint8)memImmS32);\n\t\t\tx64Gen_writeU32(x64GenContext, dataImmU32);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_mov_mem8Reg64_imm8(x64GenContext_t* x64GenContext, sint32 memRegister, uint32 memImmU32, uint8 dataImmU8)\n{\n\t// MOV BYTE [<memReg64>+<memImmU32>], dataImmU8\n\tif( memRegister == X86_REG_RSP )\n\t{\n\t\tsint32 memImmS32 = (sint32)memImmU32;\n\t\tif( memImmS32 >= -128 && memImmS32 <= 127 )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0xC6);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint8)memImmU32);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0xC6);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t\t}\n\t\tx64Gen_writeU8(x64GenContext, dataImmU8);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_mov_reg64_imm64(x64GenContext_t* x64GenContext, sint32 destRegister, uint64 immU64)\n{\n\t// MOV <destReg64>, <imm64>\n\tx64Gen_writeU8(x64GenContext, 0x48+(destRegister/8));\n\tx64Gen_writeU8(x64GenContext, 0xB8+(destRegister%8));\n\tx64Gen_writeU64(x64GenContext, immU64);\n}\n\nvoid x64Gen_mov_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 destRegister, uint64 immU32)\n{\n\t// todo: Emit shorter opcode if immU32 is 0 or falls in sint8 range?\n\t// MOV <destReg64>, <imm64>\n\tif( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0xB8+(destRegister&7));\n\tx64Gen_writeU32(x64GenContext, (uint32)immU32);\n}\n\nvoid x64Gen_mov_reg64_reg64(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// MOV <destReg64>, <srcReg64>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4D);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x49);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4C);\n\telse\n\t\tx64Gen_writeU8(x64GenContext, 0x48);\n\tx64Gen_writeU8(x64GenContext, 0x89);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(destRegister&7)+(srcRegister&7)*8);\n}\n\nvoid x64Gen_xchg_reg64_reg64(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// XCHG <destReg64>, <srcReg64>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4D);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x49);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4C);\n\telse\n\t\tx64Gen_writeU8(x64GenContext, 0x48);\n\tx64Gen_writeU8(x64GenContext, 0x87);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(destRegister&7)+(srcRegister&7)*8);\n}\n\nvoid x64Gen_mov_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// MOV <destReg64_low32>, <srcReg64_low32>\n\tif (destRegister >= 8 && srcRegister >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if (destRegister >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if (srcRegister >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\tx64Gen_writeU8(x64GenContext, 0x89);\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (destRegister & 7) + (srcRegister & 7) * 8);\n}\n\nvoid x64Gen_cmovcc_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, uint32 conditionType, sint32 destRegister, sint32 srcRegister)\n{\n\t// cMOVcc <destReg64_low32>, <srcReg64_low32>\n\tif (destRegister >= 8 && srcRegister >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if (srcRegister >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if (destRegister >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tif (conditionType == X86_CONDITION_CARRY || conditionType == X86_CONDITION_UNSIGNED_BELOW)\n\t\tx64Gen_writeU8(x64GenContext, 0x42);\n\telse if (conditionType == X86_CONDITION_NOT_CARRY || conditionType == X86_CONDITION_UNSIGNED_ABOVE_EQUAL)\n\t\tx64Gen_writeU8(x64GenContext, 0x43);\n\telse if (conditionType == X86_CONDITION_EQUAL)\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if (conditionType == X86_CONDITION_NOT_EQUAL)\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if (conditionType == X86_CONDITION_UNSIGNED_BELOW_EQUAL)\n\t\tx64Gen_writeU8(x64GenContext, 0x46);\n\telse if (conditionType == X86_CONDITION_UNSIGNED_ABOVE)\n\t\tx64Gen_writeU8(x64GenContext, 0x47);\n\telse if (conditionType == X86_CONDITION_SIGN)\n\t\tx64Gen_writeU8(x64GenContext, 0x48);\n\telse if (conditionType == X86_CONDITION_NOT_SIGN)\n\t\tx64Gen_writeU8(x64GenContext, 0x49);\n\telse if (conditionType == X86_CONDITION_PARITY)\n\t\tx64Gen_writeU8(x64GenContext, 0x4A);\n\telse if (conditionType == X86_CONDITION_SIGNED_LESS)\n\t\tx64Gen_writeU8(x64GenContext, 0x4C);\n\telse if (conditionType == X86_CONDITION_SIGNED_GREATER_EQUAL)\n\t\tx64Gen_writeU8(x64GenContext, 0x4D);\n\telse if (conditionType == X86_CONDITION_SIGNED_LESS_EQUAL)\n\t\tx64Gen_writeU8(x64GenContext, 0x4E);\n\telse if (conditionType == X86_CONDITION_SIGNED_GREATER)\n\t\tx64Gen_writeU8(x64GenContext, 0x4F);\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n\tx64Gen_writeU8(x64GenContext, 0xC0 + (destRegister & 7) * 8 + (srcRegister & 7));\n}\n\nvoid x64Gen_movSignExtend_reg64Low32_reg64Low16(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// MOVSX <destReg64_lowDWORD>, <srcReg64_lowWORD>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4D);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4C);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xBF);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7)+(destRegister&7)*8);\n}\n\nvoid x64Gen_movZeroExtend_reg64Low32_reg64Low16(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// MOVZX <destReg64_lowDWORD>, <srcReg64_lowWORD>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4D);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4C);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xB7);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7)+(destRegister&7)*8);\n}\n\nvoid x64Gen_movSignExtend_reg64Low32_reg64Low8(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// MOVSX <destReg64_lowDWORD>, <srcReg64_lowBYTE>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4D);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4C);\n\telse if( srcRegister >= 4 )\n\t\tx64Gen_writeU8(x64GenContext, 0x40);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xBE);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7)+(destRegister&7)*8);\n}\n\nvoid x64Gen_movZeroExtend_reg64Low32_reg64Low8(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// MOVZX <destReg64_lowDWORD>, <srcReg64_lowBYTE>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4D);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x4C);\n\telse if( srcRegister >= 4 )\n\t\tx64Gen_writeU8(x64GenContext, 0x40);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xB6);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7)+(destRegister&7)*8);\n}\n\nvoid x64Gen_lea_reg64Low32_reg64Low32PlusReg64Low32(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegisterA64, sint32 memRegisterB64)\n{\n\t// MOV <reg32>, DWORD [<reg32> + <reg32>]\n\tif ((memRegisterA64 & 0x7) == 5)\n\t{\n\t\t// RBP\n\t\t// swap mem registers to get the shorter instruction encoding\n\t\tsint32 temp = memRegisterA64;\n\t\tmemRegisterA64 = memRegisterB64;\n\t\tmemRegisterB64 = temp;\n\t}\n\tif ((memRegisterA64 & 0x7) == 4)\n\t{\n\t\t// RSP\n\t\t// swap mem registers\n\t\tsint32 temp = memRegisterA64;\n\t\tmemRegisterA64 = memRegisterB64;\n\t\tmemRegisterB64 = temp;\n\t\tif ((memRegisterA64 & 0x7) == 4)\n\t\t\tassert_dbg(); // double RSP not supported\n\t}\n\n\tx64Gen_writeU8(x64GenContext, 0x67);\n\tif (dstRegister >= 8 && memRegisterA64 >= 8 && memRegisterB64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x47);\n\telse if (dstRegister >= 8 && memRegisterA64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if (dstRegister >= 8 && memRegisterB64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x46);\n\telse if (dstRegister >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if (memRegisterA64 >= 8 && memRegisterB64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x43);\n\telse if (memRegisterB64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x42);\n\telse if (memRegisterA64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\n\tx64Gen_writeU8(x64GenContext, 0x8D);\n\t_x64Gen_writeMODRMDeprecated(x64GenContext, dstRegister&0x7, memRegisterA64 & 0x7, memRegisterB64 & 0x7, 0);\n}\n\nvoid _x64_op_reg64Low_mem8Reg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegister64, sint32 memImmS32, uint8 opByte)\n{\n\t// OR <dstReg64> (low byte), BYTE [<reg64> + <imm64>]\n\tif (dstRegister >= 8 && memRegister64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\tif (dstRegister >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\tif (memRegister64 >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, opByte);\n\t_x64Gen_writeMODRMDeprecated(x64GenContext, dstRegister, memRegister64, X86_REG_NONE, memImmS32);\n}\n\nvoid x64Gen_or_reg64Low8_mem8Reg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegister64, sint32 memImmS32)\n{\n\t_x64_op_reg64Low_mem8Reg64(x64GenContext, dstRegister, memRegister64, memImmS32, 0x0A);\n}\n\nvoid x64Gen_and_reg64Low8_mem8Reg64(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegister64, sint32 memImmS32)\n{\n\t_x64_op_reg64Low_mem8Reg64(x64GenContext, dstRegister, memRegister64, memImmS32, 0x22);\n}\n\nvoid x64Gen_mov_mem8Reg64_reg64Low8(x64GenContext_t* x64GenContext, sint32 dstRegister, sint32 memRegister64, sint32 memImmS32)\n{\n\t_x64_op_reg64Low_mem8Reg64(x64GenContext, dstRegister, memRegister64, memImmS32, 0x88);\n}\n\nvoid x64Gen_add_reg64_reg64(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// ADD <destReg>, <srcReg>\n\tx64Gen_writeU8(x64GenContext, 0x48+(destRegister/8)+(srcRegister/8)*4);\n\tx64Gen_writeU8(x64GenContext, 0x01);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7)*8+(destRegister&7));\n}\n\nvoid x64Gen_add_reg64_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32)\n{\n\tsint32 immS32 = (sint32)immU32;\n\tif (srcRegister >= 8)\n\t\tx64Gen_writeU8(x64GenContext, 0x49);\n\telse\n\t\tx64Gen_writeU8(x64GenContext, 0x48);\n\tif (immS32 >= -128 && immS32 <= 127)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x83);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0 + (srcRegister & 7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS32);\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x81);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0 + (srcRegister & 7));\n\t\tx64Gen_writeU32(x64GenContext, immU32);\n\t}\n}\n\nvoid x64Gen_add_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// ADD <destReg64_low32>, <srcReg64_low32>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x01);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7)*8+(destRegister&7));\n}\n\nvoid x64Gen_add_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32)\n{\n\tsint32 immS32 = (sint32)immU32;\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS32 >= -128 && immS32 <= 127 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x83);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS32);\n\t}\n\telse\n\t{\n\t\tif( srcRegister == X86_REG_RAX )\n\t\t{\n\t\t\t// special EAX short form\n\t\t\tx64Gen_writeU8(x64GenContext, 0x05);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x81);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7));\n\t\t}\n\t\tx64Gen_writeU32(x64GenContext, immU32);\n\t}\n}\n\nvoid x64Gen_sub_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// SUB <destReg64_low32>, <srcReg64_low32>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x29);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7)*8+(destRegister&7));\n}\n\nvoid x64Gen_sub_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32)\n{\n\tsint32 immS32 = (sint32)immU32;\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS32 >= -128 && immS32 <= 127 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x83);\n\t\tx64Gen_writeU8(x64GenContext, 0xE8+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS32);\n\t}\n\telse\n\t{\n\t\tif( srcRegister == X86_REG_RAX )\n\t\t{\n\t\t\t// special EAX short form\n\t\t\tx64Gen_writeU8(x64GenContext, 0x2D);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x81);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xE8+(srcRegister&7));\n\t\t}\n\t\tx64Gen_writeU32(x64GenContext, immU32);\n\t}\n}\n\nvoid x64Gen_sub_reg64_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32)\n{\n\tsint32 immS32 = (sint32)immU32;\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x49);\n\telse\n\t\tx64Gen_writeU8(x64GenContext, 0x48);\n\tif( immS32 >= -128 && immS32 <= 127 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x83);\n\t\tx64Gen_writeU8(x64GenContext, 0xE8+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS32);\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x81);\n\t\tx64Gen_writeU8(x64GenContext, 0xE8+(srcRegister&7));\n\t\tx64Gen_writeU32(x64GenContext, immU32);\n\t}\n}\n\nvoid x64Gen_sub_mem32reg64_imm32(x64GenContext_t* x64GenContext, sint32 memRegister, sint32 memImmS32, uint64 immU32)\n{\n\t// SUB <mem32_memReg64>, <imm32>\n\tsint32 immS32 = (sint32)immU32;\n\tif( memRegister == X86_REG_RSP )\n\t{\n\t\tif( memImmS32 >= 128 )\n\t\t{\n\t\t\tif( immS32 >= -128 && immS32 <= 127 )\n\t\t\t{\n\t\t\t\t// 4 byte mem imm + 1 byte imm\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0x83);\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0xAC);\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t\t\t\tx64Gen_writeU8(x64GenContext, (uint8)immU32);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// 4 byte mem imm + 4 byte imm\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0x81);\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0xAC);\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t\t\t\tx64Gen_writeU32(x64GenContext, (uint32)immU32);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_dec_mem32(x64GenContext_t* x64GenContext, sint32 memoryRegister, uint32 memoryImmU32)\n{\n\t// DEC dword [<reg64>+imm]\n\tsint32 memoryImmS32 = (sint32)memoryImmU32;\n\tif (memoryRegister != X86_REG_RSP)\n\t\tassert_dbg(); // not supported yet\n\tif (memoryImmS32 >= -128 && memoryImmS32 <= 127)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\tx64Gen_writeU8(x64GenContext, 0x4C);\n\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\tx64Gen_writeU8(x64GenContext, (uint8)memoryImmU32);\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\tx64Gen_writeU8(x64GenContext, 0x8C);\n\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\tx64Gen_writeU32(x64GenContext, memoryImmU32);\n\t}\n}\n\nvoid x64Gen_imul_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 operandRegister)\n{\n\t// IMUL <destReg64_low32>, <operandReg64_low32>\n\tif( destRegister >= 8 && operandRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( operandRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xAF);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(operandRegister&7)+(destRegister&7)*8);\n}\n\nvoid x64Gen_idiv_reg64Low32(x64GenContext_t* x64GenContext, sint32 operandRegister)\n{\n\t// IDIV <destReg64_low32>\n\tif( operandRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xF8+(operandRegister&7));\n}\n\nvoid x64Gen_div_reg64Low32(x64GenContext_t* x64GenContext, sint32 operandRegister)\n{\n\t// DIV <destReg64_low32>\n\tif( operandRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xF0+(operandRegister&7));\n}\n\nvoid x64Gen_imul_reg64Low32(x64GenContext_t* x64GenContext, sint32 operandRegister)\n{\n\t// IMUL <destReg64_low32>\n\tif( operandRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xE8+(operandRegister&7));\n}\n\nvoid x64Gen_mul_reg64Low32(x64GenContext_t* x64GenContext, sint32 operandRegister)\n{\n\t// MUL <destReg64_low32>\n\tif( operandRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xE0+(operandRegister&7));\n}\n\nvoid x64Gen_and_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32)\n{\n\tsint32 immS32 = (sint32)immU32;\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS32 >= -128 && immS32 <= 127 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x83);\n\t\tx64Gen_writeU8(x64GenContext, 0xE0+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS32);\n\t}\n\telse\n\t{\n\t\tif( srcRegister == X86_REG_RAX )\n\t\t{\n\t\t\t// special EAX short form\n\t\t\tx64Gen_writeU8(x64GenContext, 0x25);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x81);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xE0+(srcRegister&7));\n\t\t}\n\t\tx64Gen_writeU32(x64GenContext, immU32);\n\t}\n}\n\nvoid x64Gen_and_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// AND <destReg64_lowDWORD>, <srcReg64_lowDWORD>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x21);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(destRegister&7)+(srcRegister&7)*8);\n}\n\nvoid x64Gen_test_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// TEST <destReg64_lowDWORD>, <srcReg64_lowDWORD>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\tx64Gen_writeU8(x64GenContext, 0x85);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(destRegister&7)*8+(srcRegister&7));\n}\n\nvoid x64Gen_test_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32)\n{\n\tsint32 immS32 = (sint32)immU32;\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( srcRegister == X86_REG_RAX )\n\t{\n\t\t// special EAX short form\n\t\tx64Gen_writeU8(x64GenContext, 0xA9);\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xF7);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7));\n\t}\n\tx64Gen_writeU32(x64GenContext, immU32);\n}\n\nvoid x64Gen_cmp_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, sint32 immS32)\n{\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS32 >= -128 && immS32 <= 127 )\n\t{\n\t\t// 83 F8 00          CMP EAX,0\n\t\tx64Gen_writeU8(x64GenContext, 0x83);\n\t\tx64Gen_writeU8(x64GenContext, 0xF8+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS32);\n\t}\n\telse\n\t{\n\t\tif( srcRegister == X86_REG_RAX )\n\t\t{\n\t\t\t// special RAX short form\n\t\t\tx64Gen_writeU8(x64GenContext, 0x3D);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x81);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xF8+(srcRegister&7));\n\t\t}\n\t\tx64Gen_writeU32(x64GenContext, (uint32)immS32);\n\t}\n}\n\nvoid x64Gen_cmp_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// CMP <destReg64_lowDWORD>, <srcReg64_lowDWORD>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x39);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(destRegister&7)+(srcRegister&7)*8);\n}\n\nvoid x64Gen_cmp_reg64Low32_mem32reg64(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 memRegister, sint32 memImmS32)\n{\n\t// CMP <destReg64_lowDWORD>, DWORD [<memRegister>+<immS32>]\n\tif( memRegister == X86_REG_RSP )\n\t{\n\t\tif( memImmS32 >= -128 && memImmS32 <= 127 )\n\t\t\tassert_dbg(); // todo -> Shorter instruction form\n\t\tif( destRegister >= 8 )\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\tx64Gen_writeU8(x64GenContext, 0x3B);\n\t\tx64Gen_writeU8(x64GenContext, 0x84+(destRegister&7)*8);\n\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_or_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32)\n{\n\tsint32 immS32 = (sint32)immU32;\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS32 >= -128 && immS32 <= 127 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x83);\n\t\tx64Gen_writeU8(x64GenContext, 0xC8+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS32);\n\t}\n\telse\n\t{\n\t\tif( srcRegister == X86_REG_RAX )\n\t\t{\n\t\t\t// special EAX short form\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0D);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x81);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xC8+(srcRegister&7));\n\t\t}\n\t\tx64Gen_writeU32(x64GenContext, immU32);\n\t}\n}\n\nvoid x64Gen_or_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// OR <destReg64_lowDWORD>, <srcReg64_lowDWORD>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x09);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(destRegister&7)+(srcRegister&7)*8);\n}\n\nvoid x64Gen_xor_reg32_reg32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// XOR <destReg>, <srcReg>\n\tx64Gen_writeU8(x64GenContext, 0x33);\n\tx64Gen_writeU8(x64GenContext, 0xC0+srcRegister+destRegister*8);\n}\n\nvoid x64Gen_xor_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// XOR <destReg64_lowDWORD>, <srcReg64_lowDWORD>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x31);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(destRegister&7)+(srcRegister&7)*8);\n}\n\nvoid x64Gen_xor_reg64Low32_imm32(x64GenContext_t* x64GenContext, sint32 srcRegister, uint32 immU32)\n{\n\tsint32 immS32 = (sint32)immU32;\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS32 >= -128 && immS32 <= 127 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x83);\n\t\tx64Gen_writeU8(x64GenContext, 0xF0+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS32);\n\t}\n\telse\n\t{\n\t\tif( srcRegister == X86_REG_RAX )\n\t\t{\n\t\t\t// special EAX short form\n\t\t\tx64Gen_writeU8(x64GenContext, 0x35);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x81);\n\t\t\tx64Gen_writeU8(x64GenContext, 0xF0+(srcRegister&7));\n\t\t}\n\t\tx64Gen_writeU32(x64GenContext, immU32);\n\t}\n}\n\nvoid x64Gen_rol_reg64Low32_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8)\n{\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS8 == 1 )\n\t{\n\t\t// short form for 1 bit ROL\n\t\tx64Gen_writeU8(x64GenContext, 0xD1);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7));\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xC1);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS8);\n\t}\n}\n\nvoid x64Gen_rol_reg64Low32_cl(x64GenContext_t* x64GenContext, sint32 srcRegister)\n{\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0xD3);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7));\n}\n\nvoid x64Gen_rol_reg64Low16_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8)\n{\n\tx64Gen_writeU8(x64GenContext, 0x66); // 16bit prefix\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS8 == 1 )\n\t{\n\t\t// short form for 1 bit ROL\n\t\tx64Gen_writeU8(x64GenContext, 0xD1);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7));\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xC1);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS8);\n\t}\n}\n\nvoid x64Gen_rol_reg64_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8)\n{\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x49);\n\telse\n\t\tx64Gen_writeU8(x64GenContext, 0x48);\n\tif( immS8 == 1 )\n\t{\n\t\t// short form for 1 bit ROL\n\t\tx64Gen_writeU8(x64GenContext, 0xD1);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7));\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xC1);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS8);\n\t}\n}\n\nvoid x64Gen_shl_reg64Low32_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8)\n{\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS8 == 1 )\n\t{\n\t\t// short form for 1 bit SHL\n\t\tx64Gen_writeU8(x64GenContext, 0xD1);\n\t\tx64Gen_writeU8(x64GenContext, 0xF0+(srcRegister&7));\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xC1);\n\t\tx64Gen_writeU8(x64GenContext, 0xF0+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS8);\n\t}\n}\n\nvoid x64Gen_shr_reg64Low32_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8)\n{\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS8 == 1 )\n\t{\n\t\t// short form for 1 bit SHR\n\t\tx64Gen_writeU8(x64GenContext, 0xD1);\n\t\tx64Gen_writeU8(x64GenContext, 0xE8+(srcRegister&7));\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xC1);\n\t\tx64Gen_writeU8(x64GenContext, 0xE8+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS8);\n\t}\n}\n\nvoid x64Gen_sar_reg64Low32_imm8(x64GenContext_t* x64GenContext, sint32 srcRegister, sint8 immS8)\n{\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tif( immS8 == 1 )\n\t{\n\t\t// short form for 1 bit ROL\n\t\tx64Gen_writeU8(x64GenContext, 0xD1);\n\t\tx64Gen_writeU8(x64GenContext, 0xF8+(srcRegister&7));\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xC1);\n\t\tx64Gen_writeU8(x64GenContext, 0xF8+(srcRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immS8);\n\t}\n}\n\nvoid x64Gen_not_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister)\n{\n\tif( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xD0+(destRegister&7));\n}\n\nvoid x64Gen_neg_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister)\n{\n\tif( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0xF7);\n\tx64Gen_writeU8(x64GenContext, 0xD8+(destRegister&7));\n}\n\nvoid x64Gen_cdq(x64GenContext_t* x64GenContext)\n{\n\tx64Gen_writeU8(x64GenContext, 0x99);\n}\n\nvoid x64Gen_bswap_reg64Lower32bit(x64GenContext_t* x64GenContext, sint32 destRegister)\n{\n\tif( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xC8+(destRegister&7));\n}\n\nvoid x64Gen_lzcnt_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// SSE4\n\t// LZCNT <destReg>, <srcReg>\n\tx64Gen_writeU8(x64GenContext, 0xF3);\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xBD);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(destRegister&7)*8+(srcRegister&7));\n}\n\nvoid x64Gen_bsr_reg64Low32_reg64Low32(x64GenContext_t* x64GenContext, sint32 destRegister, sint32 srcRegister)\n{\n\t// BSR <destReg>, <srcReg>\n\tif( destRegister >= 8 && srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x45);\n\telse if( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\telse if( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xBD);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(destRegister&7)*8+(srcRegister&7));\n}\n\nvoid x64Gen_setcc_mem8(x64GenContext_t* x64GenContext, sint32 conditionType, sint32 memoryRegister, uint32 memoryImmU32)\n{\n\t// SETcc [<reg64>+imm]\n\tsint32 memoryImmS32 = (sint32)memoryImmU32;\n\tif( memoryRegister != X86_REG_RSP )\n\t\tassert_dbg(); // not supported\n\tif( memoryRegister >= 8 )\n\t\tassert_dbg(); // not supported\n\tif( memoryImmS32 >= -128 && memoryImmS32 <= 127 )\n\t{\n\t\tif( conditionType == X86_CONDITION_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x94);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_NOT_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x95);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_UNSIGNED_ABOVE )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x97);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_UNSIGNED_ABOVE_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x93);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_UNSIGNED_BELOW )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x92);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_UNSIGNED_BELOW_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x96);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_SIGNED_GREATER )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x9F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_SIGNED_GREATER_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x9D);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_SIGNED_LESS )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x9C);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_SIGNED_LESS_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x9E);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\t\t\n\t\telse if( conditionType == X86_CONDITION_PARITY )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x9A);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU8(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n\telse\n\t{\n\t\tif( conditionType == X86_CONDITION_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x94);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_NOT_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x95);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_UNSIGNED_ABOVE )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x97);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_UNSIGNED_ABOVE_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x93);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_UNSIGNED_BELOW || conditionType == X86_CONDITION_CARRY )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x92);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_NOT_CARRY )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x93);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_UNSIGNED_BELOW_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x96);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_SIGNED_GREATER )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x9F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_SIGNED_GREATER_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x9D);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_SIGNED_LESS )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x9C);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_SIGNED_LESS_EQUAL )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x9E);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_SIGN )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x98);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse if( conditionType == X86_CONDITION_PARITY )\n\t\t{\n\t\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x9A);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\t\tx64Gen_writeU32(x64GenContext, (uint32)memoryImmU32);\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_setcc_reg64b(x64GenContext_t* x64GenContext, sint32 conditionType, sint32 dataRegister)\n{\n\t// SETcc <reg64_low8>\n\tif (conditionType == X86_CONDITION_NOT_EQUAL)\n\t{\n\t\tif (dataRegister >= 8)\n\t\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\t\telse if (dataRegister >= 4)\n\t\t\tx64Gen_writeU8(x64GenContext, 0x40);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x95);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0 + (dataRegister & 7));\n\t}\n\telse if (conditionType == X86_CONDITION_EQUAL)\n\t{\n\t\tif (dataRegister >= 8)\n\t\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\t\telse if (dataRegister >= 4)\n\t\t\tx64Gen_writeU8(x64GenContext, 0x40);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x94);\n\t\tx64Gen_writeU8(x64GenContext, 0xC0 + (dataRegister & 7));\n\t}\n\telse\n\t\tassert_dbg();\n}\n\nvoid x64Gen_bt_mem8(x64GenContext_t* x64GenContext, sint32 memoryRegister, uint32 memoryImmU32, uint8 bitIndex)\n{\n\t// BT [<reg64>+imm], bitIndex\t(bit test)\n\tsint32 memoryImmS32 = (sint32)memoryImmU32;\n\tif( memoryRegister != X86_REG_RSP )\n\t\tassert_dbg(); // not supported yet\n\tif( memoryImmS32 >= -128 && memoryImmS32 <= 127 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0xBA);\n\t\tx64Gen_writeU8(x64GenContext, 0x64);\n\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\tx64Gen_writeU8(x64GenContext, (uint8)memoryImmU32);\n\t\tx64Gen_writeU8(x64GenContext, bitIndex);\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0xBA);\n\t\tx64Gen_writeU8(x64GenContext, 0xA4);\n\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\tx64Gen_writeU32(x64GenContext, memoryImmU32);\n\t\tx64Gen_writeU8(x64GenContext, bitIndex);\n\t}\n}\n\nvoid x64Gen_cmc(x64GenContext_t* x64GenContext)\n{\n\tx64Gen_writeU8(x64GenContext, 0xF5);\n}\n\nvoid x64Gen_jmp_imm32(x64GenContext_t* x64GenContext, uint32 destImm32)\n{\n\tx64Gen_writeU8(x64GenContext, 0xE9);\n\tx64Gen_writeU32(x64GenContext, destImm32);\n}\n\nvoid x64Gen_jmp_memReg64(x64GenContext_t* x64GenContext, sint32 memRegister, uint32 immU32)\n{\n\tif( memRegister == X86_REG_NONE )\n\t{\n\t\tassert_dbg();\n\t}\n\tif( memRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tsint32 immS32 = (sint32)immU32;\n\tif( immS32 == 0 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\tx64Gen_writeU8(x64GenContext, 0x20+(memRegister&7));\n\t}\n\telse if( immS32 >= -128 && immS32 <= 127 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\tx64Gen_writeU8(x64GenContext, 0x60+(memRegister&7));\n\t\tx64Gen_writeU8(x64GenContext, (uint8)immU32);\n\t}\n\telse\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xFF);\n\t\tx64Gen_writeU8(x64GenContext, 0xA0+(memRegister&7));\n\t\tx64Gen_writeU32(x64GenContext, immU32);\n\t}\n}\n\nvoid x64Gen_jmpc_far(x64GenContext_t* x64GenContext, sint32 conditionType, sint32 relativeDest)\n{\n\t// far JMPc #+relativeDest\n\tif( conditionType == X86_CONDITION_NONE )\n\t{\n\t\t// E9 FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0xE9);\n\t}\n\telse if( conditionType == X86_CONDITION_UNSIGNED_BELOW || conditionType == X86_CONDITION_CARRY )\n\t{\n\t\t// 0F 82 FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x82);\n\t}\n\telse if( conditionType == X86_CONDITION_NOT_CARRY || conditionType == X86_CONDITION_UNSIGNED_ABOVE_EQUAL )\n\t{\n\t\t// 0F 83 FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x83);\n\t}\n\telse if( conditionType == X86_CONDITION_EQUAL )\n\t{\n\t\t// 0F 84 FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x84);\n\t}\n\telse if( conditionType == X86_CONDITION_NOT_EQUAL )\n\t{\n\t\t// 0F 85 FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x85);\n\t}\n\telse if( conditionType == X86_CONDITION_UNSIGNED_BELOW_EQUAL )\n\t{\n\t\t// 0F 86 FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x86);\n\t}\n\telse if( conditionType == X86_CONDITION_UNSIGNED_ABOVE )\n\t{\n\t\t// 0F 87 FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x87);\n\t}\n\telse if( conditionType == X86_CONDITION_SIGN )\n\t{\n\t\t// 0F 88 FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x88);\n\t}\n\telse if( conditionType == X86_CONDITION_NOT_SIGN )\n\t{\n\t\t// 0F 89 FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x89);\n\t}\n\telse if( conditionType == X86_CONDITION_PARITY )\n\t{\n\t\t// 0F 8A FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x8A);\n\t}\n\telse if( conditionType == X86_CONDITION_SIGNED_LESS )\n\t{\n\t\t// 0F 8C FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x8C);\n\t}\n\telse if( conditionType == X86_CONDITION_SIGNED_GREATER_EQUAL )\n\t{\n\t\t// 0F 8D FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x8D);\n\t}\n\telse if( conditionType == X86_CONDITION_SIGNED_LESS_EQUAL )\n\t{\n\t\t// 0F 8E FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x8E);\n\t}\n\telse if( conditionType == X86_CONDITION_SIGNED_GREATER )\n\t{\n\t\t// 0F 8F FFFFFFFF\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x8F);\n\t}\n\telse\n\t\tassert_dbg();\n\tx64Gen_writeU32(x64GenContext, (uint32)relativeDest);\n}\n\n\nvoid x64Gen_jmpc_near(x64GenContext_t* x64GenContext, sint32 conditionType, sint32 relativeDest)\n{\n\t// near JMPc #+relativeDest\n\tif (conditionType == X86_CONDITION_NONE)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xEB);\n\t}\n\telse if (conditionType == X86_CONDITION_UNSIGNED_BELOW || conditionType == X86_CONDITION_CARRY)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x72);\n\t}\n\telse if (conditionType == X86_CONDITION_NOT_CARRY || conditionType == X86_CONDITION_UNSIGNED_ABOVE_EQUAL)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x73);\n\t}\n\telse if (conditionType == X86_CONDITION_EQUAL)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x74);\n\t}\n\telse if (conditionType == X86_CONDITION_NOT_EQUAL)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x75);\n\t}\n\telse if (conditionType == X86_CONDITION_UNSIGNED_BELOW_EQUAL)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x76);\n\t}\n\telse if (conditionType == X86_CONDITION_UNSIGNED_ABOVE)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x77);\n\t}\n\telse if (conditionType == X86_CONDITION_SIGN)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x78);\n\t}\n\telse if (conditionType == X86_CONDITION_NOT_SIGN)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x79);\n\t}\n\telse if (conditionType == X86_CONDITION_PARITY)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x7A);\n\t}\n\telse if (conditionType == X86_CONDITION_SIGNED_LESS)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x7C);\n\t}\n\telse if (conditionType == X86_CONDITION_SIGNED_GREATER_EQUAL)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x7D);\n\t}\n\telse if (conditionType == X86_CONDITION_SIGNED_LESS_EQUAL)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x7E);\n\t}\n\telse if (conditionType == X86_CONDITION_SIGNED_GREATER)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x7F);\n\t}\n\telse\n\t\tassert_dbg();\n\tx64Gen_writeU8(x64GenContext, (uint8)relativeDest);\n}\n\nvoid x64Gen_push_reg64(x64GenContext_t* x64GenContext, sint32 srcRegister)\n{\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x50+(srcRegister&7));\n}\n\nvoid x64Gen_pop_reg64(x64GenContext_t* x64GenContext, sint32 destRegister)\n{\n\tif( destRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0x58+(destRegister&7));\n}\n\nvoid x64Gen_jmp_reg64(x64GenContext_t* x64GenContext, sint32 srcRegister)\n{\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0xFF);\n\tx64Gen_writeU8(x64GenContext, 0xE0+(srcRegister&7));\n}\n\nvoid x64Gen_call_reg64(x64GenContext_t* x64GenContext, sint32 srcRegister)\n{\n\tif( srcRegister >= 8 )\n\t\tx64Gen_writeU8(x64GenContext, 0x41);\n\tx64Gen_writeU8(x64GenContext, 0xFF);\n\tx64Gen_writeU8(x64GenContext, 0xD0+(srcRegister&7));\n}\n\nvoid x64Gen_ret(x64GenContext_t* x64GenContext)\n{\n\tx64Gen_writeU8(x64GenContext, 0xC3);\n}\n\nvoid x64Gen_int3(x64GenContext_t* x64GenContext)\n{\n\tx64Gen_writeU8(x64GenContext, 0xCC);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendX64/BackendX64GenFPU.cpp",
    "content": "#include \"BackendX64.h\"\n\nvoid x64Gen_genSSEVEXPrefix2(x64GenContext_t* x64GenContext, sint32 xmmRegister1, sint32 xmmRegister2, bool use64BitMode)\n{\n\tif( xmmRegister1 < 8 && xmmRegister2 < 8 && use64BitMode == false )\n\t\treturn;\n\tuint8 v = 0x40;\n\tif( xmmRegister1 >= 8 )\n\t\tv |= 0x01;\n\tif( xmmRegister2 >= 8 )\n\t\tv |= 0x04;\n\tif( use64BitMode )\n\t\tv |= 0x08;\n\tx64Gen_writeU8(x64GenContext, v);\n}\n\nvoid x64Gen_genSSEVEXPrefix1(x64GenContext_t* x64GenContext, sint32 xmmRegister, bool use64BitMode)\n{\n\tif( xmmRegister < 8 && use64BitMode == false )\n\t\treturn;\n\tuint8 v = 0x40;\n\tif( use64BitMode )\n\t\tv |= 0x01;\n\tif( xmmRegister >= 8 )\n\t\tv |= 0x04;\n\tx64Gen_writeU8(x64GenContext, v);\n}\n\nvoid x64Gen_movaps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSource)\n{\n\t// SSE\n\t// copy xmm register\n\t// MOVAPS <xmm>, <xmm>\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSource, xmmRegisterDest, false); // tested\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x28); // alternative encoding: 0x29, source and destination register are exchanged\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSource&7));\n}\n\nvoid x64Gen_movupd_xmmReg_memReg128(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)\n{\n\t// SSE2\n\t// move two doubles from memory into xmm register\n\t// MOVUPD <xmm>, [<reg>+<imm>]\n\tif( memRegister == X86_REG_ESP )\n\t{\n\t\t// todo: Short form of instruction if memImmU32 is 0 or in -128 to 127 range\n\t\t// 66 0F 10 84 E4 23 01 00 00\n\t\tx64Gen_writeU8(x64GenContext, 0x66);\n\t\tx64Gen_genSSEVEXPrefix1(x64GenContext, xmmRegister, false);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x10);\n\t\tx64Gen_writeU8(x64GenContext, 0x84+(xmmRegister&7)*8);\n\t\tx64Gen_writeU8(x64GenContext, 0xE4);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse if( memRegister == X86_REG_NONE )\n\t{\n\t\tassert_dbg();\n\t\t//x64Gen_writeU8(x64GenContext, 0x66);\n\t\t//x64Gen_writeU8(x64GenContext, 0x0F);\n\t\t//x64Gen_writeU8(x64GenContext, 0x10);\n\t\t//x64Gen_writeU8(x64GenContext, 0x05+(xmmRegister&7)*8);\n\t\t//x64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_movupd_memReg128_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)\n{\n\t// SSE2\n\t// move two doubles from memory into xmm register\n\t// MOVUPD [<reg>+<imm>], <xmm>\n\tif( memRegister == X86_REG_ESP )\n\t{\n\t\t// todo: Short form of instruction if memImmU32 is 0 or in -128 to 127 range\n\t\tx64Gen_writeU8(x64GenContext, 0x66);\n\t\tx64Gen_genSSEVEXPrefix1(x64GenContext, xmmRegister, false);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x11);\n\t\tx64Gen_writeU8(x64GenContext, 0x84+(xmmRegister&7)*8);\n\t\tx64Gen_writeU8(x64GenContext, 0xE4);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse if( memRegister == X86_REG_NONE )\n\t{\n\t\tassert_dbg();\n\t\t//x64Gen_writeU8(x64GenContext, 0x66);\n\t\t//x64Gen_writeU8(x64GenContext, 0x0F);\n\t\t//x64Gen_writeU8(x64GenContext, 0x11);\n\t\t//x64Gen_writeU8(x64GenContext, 0x05+(xmmRegister&7)*8);\n\t\t//x64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_movddup_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)\n{\n\t// SSE3\n\t// move one double from memory into lower and upper half of a xmm register\n\tif( memRegister == X86_REG_RSP )\n\t{\n\t\t// MOVDDUP <xmm>, [<reg>+<imm>]\n\t\t// todo: Short form of instruction if memImmU32 is 0 or in -128 to 127 range\n\t\tx64Gen_writeU8(x64GenContext, 0xF2);\n\t\tif( xmmRegister >= 8 )\n\t\t\tx64Gen_writeU8(x64GenContext, 0x44);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x12);\n\t\tx64Gen_writeU8(x64GenContext, 0x84+(xmmRegister&7)*8);\n\t\tx64Gen_writeU8(x64GenContext, 0xE4);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse if( memRegister == X86_REG_R15 )\n\t{\n\t\t// MOVDDUP <xmm>, [<reg>+<imm>]\n\t\t// todo: Short form of instruction if memImmU32 is 0 or in -128 to 127 range\n\t\t// F2 41 0F 12 87 - 44 33 22 11 \n\t\tx64Gen_writeU8(x64GenContext, 0xF2);\n\t\tx64Gen_genSSEVEXPrefix1(x64GenContext, xmmRegister, true);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x12);\n\t\tx64Gen_writeU8(x64GenContext, 0x87+(xmmRegister&7)*8);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse if( memRegister == X86_REG_NONE )\n\t{\n\t\t// MOVDDUP <xmm>, [<imm>]\n\t\t// 36 F2 0F 12 05 - 00 00 00 00\n\t\tassert_dbg();\n\t\t//x64Gen_writeU8(x64GenContext, 0x36);\n\t\t//x64Gen_writeU8(x64GenContext, 0xF2);\n\t\t//x64Gen_writeU8(x64GenContext, 0x0F);\n\t\t//x64Gen_writeU8(x64GenContext, 0x12);\n\t\t//x64Gen_writeU8(x64GenContext, 0x05+(xmmRegister&7)*8);\n\t\t//x64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_movddup_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE3\n\t// move low double from xmm register into lower and upper half of a different xmm register\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x12);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_movhlps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE1\n\t// move high double from xmm register into lower and upper half of a different xmm register\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x12);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_movsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// move lower double from xmm register into lower half of a different xmm register, leave other half untouched\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x10); // alternative encoding: 0x11, src and dest exchanged\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_movsd_memReg64_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)\n{\n\t// SSE2\n\t// move lower 64bits (double) of xmm register to memory location\n\tif( memRegister == X86_REG_NONE )\n\t{\n\t\t// MOVSD [<imm>], <xmm>\n\t\t// F2 0F 11 05 - 45 23 01 00\n\t\tassert_dbg();\n\t\t//x64Gen_writeU8(x64GenContext, 0xF2);\n\t\t//x64Gen_genSSEVEXPrefix(x64GenContext, xmmRegister, 0, false);\n\t\t//x64Gen_writeU8(x64GenContext, 0x0F);\n\t\t//x64Gen_writeU8(x64GenContext, 0x11);\n\t\t//x64Gen_writeU8(x64GenContext, 0x05+xmmRegister*8);\n\t\t//x64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse if( memRegister == X86_REG_RSP )\n\t{\n\t\t// MOVSD [RSP+<imm>], <xmm>\n\t\t// F2 0F 11 84 24 - 33 22 11 00\n\t\tx64Gen_writeU8(x64GenContext, 0xF2);\n\t\tx64Gen_genSSEVEXPrefix2(x64GenContext, 0, xmmRegister, false);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x11);\n\t\tx64Gen_writeU8(x64GenContext, 0x84+(xmmRegister&7)*8);\n\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_movsd_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)\n{\n\t// SSE2\n\tif( memRegister == X86_REG_RSP )\n\t{\n\t\t// MOVSD <xmm>, [RSP+<imm>]\n\t\tx64Gen_writeU8(x64GenContext, 0xF2);\n\t\tx64Gen_genSSEVEXPrefix2(x64GenContext, 0, xmmRegister, false);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x10);\n\t\tx64Gen_writeU8(x64GenContext, 0x84+(xmmRegister&7)*8);\n\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse if( memRegister == 15 )\n\t{\n\t\t// MOVSD <xmm>, [R15+<imm>]\n\t\tx64Gen_writeU8(x64GenContext, 0x36);\n\t\tx64Gen_writeU8(x64GenContext, 0xF2);\n\t\tx64Gen_genSSEVEXPrefix2(x64GenContext, memRegister, xmmRegister, false);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x10);\n\t\tx64Gen_writeU8(x64GenContext, 0x87+(xmmRegister&7)*8);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_movlpd_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)\n{\n\t// SSE3\n\t// move one double from memory into lower half of a xmm register, leave upper half unchanged(?)\n\tif( memRegister == X86_REG_NONE )\n\t{\n\t\t// MOVLPD <xmm>, [<imm>]\n\t\t//x64Gen_writeU8(x64GenContext, 0x66);\n\t\t//x64Gen_writeU8(x64GenContext, 0x0F);\n\t\t//x64Gen_writeU8(x64GenContext, 0x12);\n\t\t//x64Gen_writeU8(x64GenContext, 0x05+(xmmRegister&7)*8);\n\t\t//x64Gen_writeU32(x64GenContext, memImmU32);\n\t\tassert_dbg();\n\t}\n\telse if( memRegister == X86_REG_RSP )\n\t{\n\t\t// MOVLPD <xmm>, [<reg64>+<imm>]\n\t\t// 66 0F 12 84 24 - 33 22 11 00\n\t\tx64Gen_writeU8(x64GenContext, 0x66);\n\t\tx64Gen_genSSEVEXPrefix2(x64GenContext, 0, xmmRegister, false);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x12);\n\t\tx64Gen_writeU8(x64GenContext, 0x84+(xmmRegister&7)*8);\n\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_unpcklpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x14);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_unpckhpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x15);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_shufpd_xmmReg_xmmReg_imm8(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc, uint8 imm8)\n{\n\t// SSE2\n\t// shuffled copy source to destination\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xC6);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n\tx64Gen_writeU8(x64GenContext, imm8);\n}\n\nvoid x64Gen_addsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// add bottom double of two xmm registers, leave upper quadword unchanged\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false); // untested\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x58);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_addpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// add both doubles of two xmm registers\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x58);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_subsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// subtract bottom double of two xmm registers, leave upper quadword unchanged\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x5C);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_subpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// subtract both doubles of two xmm registers\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false); // untested\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x5C);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_mulsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// multiply bottom double of two xmm registers, leave upper quadword unchanged\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x59);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_mulpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// multiply both doubles of two xmm registers\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false); // untested\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x59);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_mulpd_xmmReg_memReg128(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)\n{\n\t// SSE2\n\tif (memRegister == X86_REG_NONE)\n\t{\n\t\tassert_dbg();\n\t}\n\telse if (memRegister == X86_REG_R14)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x66);\n\t\tx64Gen_writeU8(x64GenContext, (xmmRegister < 8) ? 0x41 : 0x45);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x59);\n\t\tx64Gen_writeU8(x64GenContext, 0x86 + (xmmRegister & 7) * 8);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_divsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// divide bottom double of two xmm registers, leave upper quadword unchanged\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x5E);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_divpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// divide bottom and top double of two xmm registers\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x5E);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_comisd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// compare bottom doubles\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false); // untested\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x2F);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_comisd_xmmReg_mem64Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 memoryReg, sint32 memImmS32)\n{\n\t// SSE2\n\t// compare bottom double with double from memory location\n\tif( memoryReg == X86_REG_R15 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x66);\n\t\tx64Gen_genSSEVEXPrefix1(x64GenContext, xmmRegisterDest, true);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x2F);\n\t\tx64Gen_writeU8(x64GenContext, 0x87+(xmmRegisterDest&7)*8);\n\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t}\n\telse\n\t\tassert_dbg();\n}\n\nvoid x64Gen_ucomisd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// compare bottom doubles\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x2E);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_comiss_xmmReg_mem64Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 memoryReg, sint32 memImmS32)\n{\n\t// SSE2\n\t// compare bottom float with float from memory location\n\tif (memoryReg == X86_REG_R15)\n\t{\n\t\tx64Gen_genSSEVEXPrefix1(x64GenContext, xmmRegisterDest, true);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x2F);\n\t\tx64Gen_writeU8(x64GenContext, 0x87 + (xmmRegisterDest & 7) * 8);\n\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t}\n\telse\n\t\tassert_dbg();\n}\n\nvoid x64Gen_orps_xmmReg_mem128Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, uint32 memReg, uint32 memImmS32)\n{\n\t// SSE2\n\t// and xmm register with 128 bit value from memory\n\tif( memReg == X86_REG_R15 )\n\t{\n\t\tx64Gen_genSSEVEXPrefix2(x64GenContext, memReg, xmmRegisterDest, false);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x56);\n\t\tx64Gen_writeU8(x64GenContext, 0x87+(xmmRegisterDest&7)*8);\n\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t}\n\telse\n\t\tassert_dbg();\n}\n\nvoid x64Gen_xorps_xmmReg_mem128Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, uint32 memReg, uint32 memImmS32)\n{\n\t// SSE2\n\t// xor xmm register with 128 bit value from memory\n\tif( memReg == X86_REG_R15 )\n\t{\n\t\tx64Gen_genSSEVEXPrefix1(x64GenContext, xmmRegisterDest, true); // todo: should be x64Gen_genSSEVEXPrefix2() with memReg?\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x57);\n\t\tx64Gen_writeU8(x64GenContext, 0x87+(xmmRegisterDest&7)*8);\n\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t}\n\telse\n\t\tassert_dbg();\n}\n\nvoid x64Gen_andpd_xmmReg_memReg128(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)\n{\n\t// SSE2\n\tif (memRegister == X86_REG_NONE)\n\t{\n\t\tassert_dbg();\n\t}\n\telse if (memRegister == X86_REG_R14)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x66);\n\t\tx64Gen_writeU8(x64GenContext, (xmmRegister < 8) ? 0x41 : 0x45);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x54);\n\t\tx64Gen_writeU8(x64GenContext, 0x86 + (xmmRegister & 7) * 8);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_andps_xmmReg_mem128Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, uint32 memReg, uint32 memImmS32)\n{\n\t// SSE2\n\t// and xmm register with 128 bit value from memory\n\tif( memReg == X86_REG_R15 )\n\t{\n\t\tx64Gen_genSSEVEXPrefix1(x64GenContext, xmmRegisterDest, true); // todo: should be x64Gen_genSSEVEXPrefix2() with memReg?\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x54);\n\t\tx64Gen_writeU8(x64GenContext, 0x87+(xmmRegisterDest&7)*8);\n\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t}\n\telse\n\t\tassert_dbg();\n}\n\nvoid x64Gen_andps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// and xmm register with xmm register\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x54);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_pcmpeqd_xmmReg_mem128Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, uint32 memReg, uint32 memImmS32)\n{\n\t// SSE2\n\t// doubleword integer compare\n\tif( memReg == X86_REG_R15 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x66);\n\t\tx64Gen_genSSEVEXPrefix1(x64GenContext, xmmRegisterDest, true);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x76);\n\t\tx64Gen_writeU8(x64GenContext, 0x87+(xmmRegisterDest&7)*8);\n\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t}\n\telse\n\t\tassert_dbg();\n}\n\nvoid x64Gen_cvttpd2dq_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// convert two doubles into two 32-bit integers in bottom part of xmm register, reset upper 64 bits of destination register\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0xE6);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_cvttsd2si_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// convert double to truncated integer in general purpose register\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, registerDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x2C);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(registerDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_cvtsi2sd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 registerSrc)\n{\n\t// SSE2\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, registerSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x2A);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(registerSrc&7));\n}\n\nvoid x64Gen_cvtsd2ss_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// converts bottom 64bit double to bottom 32bit single\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x5A);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_cvtpd2ps_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// converts two 64bit doubles to two 32bit singles in bottom half of register\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x5A);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_cvtps2pd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// converts two 32bit singles to two 64bit doubles\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x5A);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_cvtss2sd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// converts bottom 32bit single to bottom 64bit double\n\tx64Gen_writeU8(x64GenContext, 0xF3);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x5A);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_cvtpi2pd_xmmReg_mem64Reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 memReg, sint32 memImmS32)\n{\n\t// SSE2\n\t// converts two signed 32bit integers to two doubles\n\tif( memReg == X86_REG_RSP )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0x66);\n\t\tx64Gen_genSSEVEXPrefix1(x64GenContext, xmmRegisterDest, false);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x2A);\n\t\tx64Gen_writeU8(x64GenContext, 0x84+(xmmRegisterDest&7)*8);\n\t\tx64Gen_writeU8(x64GenContext, 0x24);\n\t\tx64Gen_writeU32(x64GenContext, (uint32)memImmS32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_cvtsd2si_reg64Low_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// converts bottom 64bit double to 32bit signed integer in general purpose register, round based on float-point control\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, registerDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x2D);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(registerDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_cvttsd2si_reg64Low_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// converts bottom 64bit double to 32bit signed integer in general purpose register, always truncate\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, registerDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x2C);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(registerDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_sqrtsd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// calculates square root of bottom double\n\tx64Gen_writeU8(x64GenContext, 0xF2);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x51);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_sqrtpd_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// calculates square root of bottom and top double\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x51);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_rcpss_xmmReg_xmmReg(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// approximates reciprocal of bottom 32bit single\n\tx64Gen_writeU8(x64GenContext, 0xF3);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, xmmRegisterSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x53);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(xmmRegisterSrc&7));\n}\n\nvoid x64Gen_mulss_xmmReg_memReg64(x64GenContext_t* x64GenContext, sint32 xmmRegister, sint32 memRegister, uint32 memImmU32)\n{\n\t// SSE2\n\tif( memRegister == X86_REG_NONE )\n\t{\n\t\tassert_dbg();\n\t}\n\telse if( memRegister == 15 )\n\t{\n\t\tx64Gen_writeU8(x64GenContext, 0xF3);\n\t\tx64Gen_writeU8(x64GenContext, (xmmRegister<8)?0x41:0x45);\n\t\tx64Gen_writeU8(x64GenContext, 0x0F);\n\t\tx64Gen_writeU8(x64GenContext, 0x59);\n\t\tx64Gen_writeU8(x64GenContext, 0x87+(xmmRegister&7)*8);\n\t\tx64Gen_writeU32(x64GenContext, memImmU32);\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\nvoid x64Gen_movd_xmmReg_reg64Low32(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 registerSrc)\n{\n\t// SSE2\n\t// copy low 32bit of general purpose register into xmm register\n\t// MOVD <xmm>, <reg32>\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, registerSrc, xmmRegisterDest, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x6E); // alternative encoding: 0x29, source and destination register are exchanged\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(registerSrc&7));\n}\n\nvoid x64Gen_movd_reg64Low32_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDest, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// copy low 32bit of general purpose register into xmm register\n\t// MOVD <reg32>, <xmm>\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, registerDest, xmmRegisterSrc, false);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x7E); // alternative encoding: 0x29, source and destination register are exchanged\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterSrc&7)*8+(registerDest&7));\n}\n\nvoid x64Gen_movq_xmmReg_reg64(x64GenContext_t* x64GenContext, sint32 xmmRegisterDest, sint32 registerSrc)\n{\n\t// SSE2\n\t// copy general purpose register into xmm register\n\t// MOVD <xmm>, <reg64>\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, registerSrc, xmmRegisterDest, true);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x6E); // alternative encoding: 0x29, source and destination register are exchanged\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterDest&7)*8+(registerSrc&7));\n}\n\nvoid x64Gen_movq_reg64_xmmReg(x64GenContext_t* x64GenContext, sint32 registerDst, sint32 xmmRegisterSrc)\n{\n\t// SSE2\n\t// copy general purpose register into xmm register\n\t// MOVD <xmm>, <reg64>\n\tx64Gen_writeU8(x64GenContext, 0x66);\n\tx64Gen_genSSEVEXPrefix2(x64GenContext, registerDst, xmmRegisterSrc, true);\n\tx64Gen_writeU8(x64GenContext, 0x0F);\n\tx64Gen_writeU8(x64GenContext, 0x7E);\n\tx64Gen_writeU8(x64GenContext, 0xC0+(xmmRegisterSrc&7)*8+(registerDst&7));\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendX64/X64Emit.hpp",
    "content": "\n\ntemplate<uint8 op0, bool rex64Bit = false>\nclass x64_opc_1byte\n{\npublic:\n\tstatic void emitBytes(x64GenContext_t* x64GenContext)\n\t{\n\t\t// write out op0\n\t\tx64Gen_writeU8(x64GenContext, op0);\n\t}\n\n\tstatic constexpr bool isRevOrder()\n\t{\n\t\treturn false;\n\t}\n\n\tstatic constexpr bool hasRex64BitPrefix()\n\t{\n\t\treturn rex64Bit;\n\t}\n};\n\ntemplate<uint8 op0, bool rex64Bit = false>\nclass x64_opc_1byte_rev\n{\npublic:\n\tstatic void emitBytes(x64GenContext_t* x64GenContext)\n\t{\n\t\t// write out op0\n\t\tx64Gen_writeU8(x64GenContext, op0);\n\t}\n\n\tstatic constexpr bool isRevOrder()\n\t{\n\t\treturn true;\n\t}\n\n\tstatic constexpr bool hasRex64BitPrefix()\n\t{\n\t\treturn rex64Bit;\n\t}\n};\n\ntemplate<uint8 op0, uint8 op1, bool rex64Bit = false>\nclass x64_opc_2byte\n{\npublic:\n\tstatic void emitBytes(x64GenContext_t* x64GenContext)\n\t{\n\t\tx64Gen_writeU8(x64GenContext, op0);\n\t\tx64Gen_writeU8(x64GenContext, op1);\n\t}\n\n\tstatic constexpr bool isRevOrder()\n\t{\n\t\treturn false;\n\t}\n\n\tstatic constexpr bool hasRex64BitPrefix()\n\t{\n\t\treturn rex64Bit;\n\t}\n};\n\nenum class MODRM_OPR_TYPE\n{\n\tREG,\n\tMEM\n};\n\nclass x64MODRM_opr_reg64\n{\npublic:\n\tx64MODRM_opr_reg64(uint8 reg)\n\t{\n\t\tthis->reg = reg;\n\t}\n\n\tstatic constexpr MODRM_OPR_TYPE getType()\n\t{\n\t\treturn MODRM_OPR_TYPE::REG;\n\t}\n\n\tconst uint8 getReg() const\n\t{\n\t\treturn reg;\n\t}\n\nprivate:\n\tuint8 reg;\n};\n\nclass x64MODRM_opr_memReg64\n{\npublic:\n\tx64MODRM_opr_memReg64(uint8 reg)\n\t{\n\t\tthis->reg = reg;\n\t\tthis->offset = 0;\n\t}\n\n\tx64MODRM_opr_memReg64(uint8 reg, sint32 offset)\n\t{\n\t\tthis->reg = reg;\n\t\tthis->offset = offset;\n\t}\n\n\tstatic constexpr MODRM_OPR_TYPE getType()\n\t{\n\t\treturn MODRM_OPR_TYPE::MEM;\n\t}\n\n\tconst uint8 getBaseReg() const\n\t{\n\t\treturn reg;\n\t}\n\n\tconst uint32 getOffset() const\n\t{\n\t\treturn (uint32)offset;\n\t}\n\n\tstatic constexpr bool hasBaseReg()\n\t{\n\t\treturn true;\n\t}\n\n\tstatic constexpr bool hasIndexReg()\n\t{\n\t\treturn false;\n\t}\nprivate:\n\tuint8 reg;\n\tsint32 offset;\n};\n\nclass x64MODRM_opr_memRegPlusReg\n{\npublic:\n\tx64MODRM_opr_memRegPlusReg(uint8 regBase, uint8 regIndex)\n\t{\n\t\tif ((regIndex & 7) == 4)\n\t\t{\n\t\t\t// cant encode RSP/R12 in index register, switch with base register\n\t\t\t// this only works if the scaler is 1\n\t\t\tstd::swap(regBase, regIndex);\n\t\t\tcemu_assert((regBase & 7) != 4);\n\t\t}\n\t\tthis->regBase = regBase;\n\t\tthis->regIndex = regIndex;\n\t\tthis->offset = 0;\n\t}\n\n\tx64MODRM_opr_memRegPlusReg(uint8 regBase, uint8 regIndex, sint32 offset)\n\t{\n\t\tif ((regIndex & 7) == 4)\n\t\t{\n\t\t\tstd::swap(regBase, regIndex);\n\t\t\tcemu_assert((regIndex & 7) != 4);\n\t\t}\n\t\tthis->regBase = regBase;\n\t\tthis->regIndex = regIndex;\n\t\tthis->offset = offset;\n\t}\n\n\tstatic constexpr MODRM_OPR_TYPE getType()\n\t{\nreturn MODRM_OPR_TYPE::MEM;\n\t}\n\n\tconst uint8 getBaseReg() const\n\t{\n\t\treturn regBase;\n\t}\n\n\tconst uint8 getIndexReg()\n\t{\n\t\treturn regIndex;\n\t}\n\n\tconst uint32 getOffset() const\n\t{\n\t\treturn (uint32)offset;\n\t}\n\n\tstatic constexpr bool hasBaseReg()\n\t{\n\t\treturn true;\n\t}\n\n\tstatic constexpr bool hasIndexReg()\n\t{\n\t\treturn true;\n\t}\nprivate:\n\tuint8 regBase;\n\tuint8 regIndex; // multiplied by scaler which is fixed to 1\n\tsint32 offset;\n};\n\ntemplate<class opcodeBytes, typename TA, typename TB>\nvoid _x64Gen_writeMODRM_internal(x64GenContext_t* x64GenContext, TA opA, TB opB)\n{\n\tstatic_assert(TA::getType() == MODRM_OPR_TYPE::REG);\n\t// REX prefix\n\t// 0100 WRXB\n\tif constexpr (TA::getType() == MODRM_OPR_TYPE::REG && TB::getType() == MODRM_OPR_TYPE::REG)\n\t{\n\t\tif (opA.getReg() & 8 || opB.getReg() & 8 || opcodeBytes::hasRex64BitPrefix())\n\t\t{\n\t\t\t// opA -> REX.B\n\t\t\t// baseReg -> REX.R\n\t\t\tx64Gen_writeU8(x64GenContext, 0x40 | ((opA.getReg() & 8) ? (1 << 2) : 0) | ((opB.getReg() & 8) ? (1 << 0) : 0) | (opcodeBytes::hasRex64BitPrefix() ? (1 << 3) : 0));\n\t\t}\n\t}\n\telse if constexpr (TA::getType() == MODRM_OPR_TYPE::REG && TB::getType() == MODRM_OPR_TYPE::MEM)\n\t{\n\t\tif constexpr (opB.hasBaseReg() && opB.hasIndexReg())\n\t\t{\n\t\t\tif (opA.getReg() & 8 || opB.getBaseReg() & 8 || opB.getIndexReg() & 8 || opcodeBytes::hasRex64BitPrefix())\n\t\t\t{\n\t\t\t\t// opA -> REX.B\n\t\t\t\t// baseReg -> REX.R\n\t\t\t\t// indexReg -> REX.X\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0x40 | ((opA.getReg() & 8) ? (1 << 2) : 0) | ((opB.getBaseReg() & 8) ? (1 << 0) : 0) | ((opB.getIndexReg() & 8) ? (1 << 1) : 0) | (opcodeBytes::hasRex64BitPrefix() ? (1 << 3) : 0));\n\t\t\t}\n\t\t}\n\t\telse if constexpr (opB.hasBaseReg())\n\t\t{\n\t\t\tif (opA.getReg() & 8 || opB.getBaseReg() & 8 || opcodeBytes::hasRex64BitPrefix())\n\t\t\t{\n\t\t\t\t// opA -> REX.B\n\t\t\t\t// baseReg -> REX.R\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0x40 | ((opA.getReg() & 8) ? (1 << 2) : 0) | ((opB.getBaseReg() & 8) ? (1 << 0) : 0) | (opcodeBytes::hasRex64BitPrefix() ? (1 << 3) : 0));\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (opA.getReg() & 8 || opcodeBytes::hasRex64BitPrefix())\n\t\t\t{\n\t\t\t\t// todo - verify\n\t\t\t\t// opA -> REX.B\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0x40 | ((opA.getReg() & 8) ? (1 << 2) : 0) | (opcodeBytes::hasRex64BitPrefix() ? (1 << 3) : 0));\n\t\t\t}\n\t\t}\n\t}\n\t// opcode\n\topcodeBytes::emitBytes(x64GenContext);\n\t// modrm byte\n\tif constexpr (TA::getType() == MODRM_OPR_TYPE::REG && TB::getType() == MODRM_OPR_TYPE::REG)\n\t{\n\t\t// reg, reg\n\t\tx64Gen_writeU8(x64GenContext, 0xC0 + (opB.getReg() & 7) + ((opA.getReg() & 7) << 3));\n\t}\n\telse if constexpr (TA::getType() == MODRM_OPR_TYPE::REG && TB::getType() == MODRM_OPR_TYPE::MEM)\n\t{\n\t\tif constexpr (TB::hasBaseReg() == false) // todo - also check for index reg and secondary sib reg\n\t\t{\n\t\t\t// form: [offset]\n\t\t\t// instruction is just offset\n\t\t\tcemu_assert(false);\n\t\t}\n\t\telse if constexpr (TB::hasIndexReg())\n\t\t{\n\t\t\t// form: [base+index*scaler+offset], scaler is currently fixed to 1\n\t\t\tcemu_assert((opB.getIndexReg() & 7) != 4); // RSP not allowed as index register\n\t\t\tconst uint32 offset = opB.getOffset();\n\t\t\tif (offset == 0 && (opB.getBaseReg() & 7) != 5) // RBP/R13 has special meaning in no-offset encoding\n\t\t\t{\n\t\t\t\t// [form: index*1+base]\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0x00 + (4) + ((opA.getReg() & 7) << 3));\n\t\t\t\t// SIB byte\n\t\t\t\tx64Gen_writeU8(x64GenContext, ((opB.getIndexReg()&7) << 3) + (opB.getBaseReg() & 7));\n\t\t\t}\n\t\t\telse if (offset == (uint32)(sint32)(sint8)offset)\n\t\t\t{\n\t\t\t\t// [form: index*1+base+sbyte]\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0x40 + (4) + ((opA.getReg() & 7) << 3));\n\t\t\t\t// SIB byte\n\t\t\t\tx64Gen_writeU8(x64GenContext, ((opB.getIndexReg() & 7) << 3) + (opB.getBaseReg() & 7));\n\t\t\t\tx64Gen_writeU8(x64GenContext, (uint8)offset);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// [form: index*1+base+sdword]\n\t\t\t\tx64Gen_writeU8(x64GenContext, 0x80 + (4) + ((opA.getReg() & 7) << 3));\n\t\t\t\t// SIB byte\n\t\t\t\tx64Gen_writeU8(x64GenContext, ((opB.getIndexReg() & 7) << 3) + (opB.getBaseReg() & 7));\n\t\t\t\tx64Gen_writeU32(x64GenContext, (uint32)offset);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// form: [baseReg + offset]\n\t\t\tconst uint32 offset = opB.getOffset();\n\t\t\tif (offset == 0 && (opB.getBaseReg() & 7) != 5) // RBP/R13 has special meaning in no-offset encoding\n\t\t\t{\n\t\t\t\t// form: [baseReg]\n\t\t\t\t// if base reg is RSP/R12 we need to use SIB form of instruction\n\t\t\t\tif ((opB.getBaseReg() & 7) == 4)\n\t\t\t\t{\n\t\t\t\t\tx64Gen_writeU8(x64GenContext, 0x00 + (4) + ((opA.getReg() & 7) << 3));\n\t\t\t\t\t// SIB byte [form: none*1+base]\n\t\t\t\t\tx64Gen_writeU8(x64GenContext, (4 << 3) + (opB.getBaseReg() & 7));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tx64Gen_writeU8(x64GenContext, 0x00 + (opB.getBaseReg() & 7) + ((opA.getReg() & 7) << 3));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (offset == (uint32)(sint32)(sint8)offset)\n\t\t\t{\n\t\t\t\t// form: [baseReg+sbyte]\n\t\t\t\t// if base reg is RSP/R12 we need to use SIB form of instruction\n\t\t\t\tif ((opB.getBaseReg() & 7) == 4)\n\t\t\t\t{\n\t\t\t\t\tx64Gen_writeU8(x64GenContext, 0x40 + (4) + ((opA.getReg() & 7) << 3));\n\t\t\t\t\t// SIB byte [form: none*1+base]\n\t\t\t\t\tx64Gen_writeU8(x64GenContext, (4 << 3) + (opB.getBaseReg() & 7));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tx64Gen_writeU8(x64GenContext, 0x40 + (opB.getBaseReg() & 7) + ((opA.getReg() & 7) << 3));\n\t\t\t\t}\n\t\t\t\tx64Gen_writeU8(x64GenContext, (uint8)offset);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// form: [baseReg+sdword]\n\t\t\t\t// if base reg is RSP/R12 we need to use SIB form of instruction\n\t\t\t\tif ((opB.getBaseReg() & 7) == 4)\n\t\t\t\t{\n\t\t\t\t\tx64Gen_writeU8(x64GenContext, 0x80 + (4) + ((opA.getReg() & 7) << 3));\n\t\t\t\t\t// SIB byte [form: none*1+base]\n\t\t\t\t\tx64Gen_writeU8(x64GenContext, (4 << 3) + (opB.getBaseReg() & 7));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tx64Gen_writeU8(x64GenContext, 0x80 + (opB.getBaseReg() & 7) + ((opA.getReg() & 7) << 3));\n\t\t\t\t}\n\t\t\t\tx64Gen_writeU32(x64GenContext, (uint32)offset);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tassert_dbg();\n\t}\n}\n\ntemplate<class opcodeBytes, typename TA, typename TB>\nvoid x64Gen_writeMODRM_dyn(x64GenContext_t* x64GenContext, TA opLeft, TB opRight)\n{\n\tif constexpr (opcodeBytes::isRevOrder())\n\t\t_x64Gen_writeMODRM_internal<opcodeBytes, TB, TA>(x64GenContext, opRight, opLeft);\n\telse\n\t\t_x64Gen_writeMODRM_internal<opcodeBytes, TA, TB>(x64GenContext, opLeft, opRight);\n}"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/BackendX64/x86Emitter.h",
    "content": "#pragma once\n\n// x86-64 assembler/emitter\n// auto generated. Do not edit this file manually\n\ntypedef unsigned long long u64;\ntypedef unsigned int u32;\ntypedef unsigned short u16;\ntypedef unsigned char u8;\ntypedef signed long long s64;\ntypedef signed int s32;\ntypedef signed short s16;\ntypedef signed char s8;\n\nenum X86Reg : sint8\n{\n\tX86_REG_NONE = -1,\n\tX86_REG_EAX = 0,\n\tX86_REG_ECX = 1,\n\tX86_REG_EDX = 2,\n\tX86_REG_EBX = 3,\n\tX86_REG_ESP = 4,\n\tX86_REG_EBP = 5,\n\tX86_REG_ESI = 6,\n\tX86_REG_EDI = 7,\n\tX86_REG_R8D = 8,\n\tX86_REG_R9D = 9,\n\tX86_REG_R10D = 10,\n\tX86_REG_R11D = 11,\n\tX86_REG_R12D = 12,\n\tX86_REG_R13D = 13,\n\tX86_REG_R14D = 14,\n\tX86_REG_R15D = 15,\n\tX86_REG_RAX = 0,\n\tX86_REG_RCX = 1,\n\tX86_REG_RDX = 2,\n\tX86_REG_RBX = 3,\n\tX86_REG_RSP = 4,\n\tX86_REG_RBP = 5,\n\tX86_REG_RSI = 6,\n\tX86_REG_RDI = 7,\n\tX86_REG_R8 = 8,\n\tX86_REG_R9 = 9,\n\tX86_REG_R10 = 10,\n\tX86_REG_R11 = 11,\n\tX86_REG_R12 = 12,\n\tX86_REG_R13 = 13,\n\tX86_REG_R14 = 14,\n\tX86_REG_R15 = 15\n};\n\nenum X86Cond : u8\n{\n\tX86_CONDITION_O = 0,\n\tX86_CONDITION_NO = 1,\n\tX86_CONDITION_B = 2,\n\tX86_CONDITION_NB = 3,\n\tX86_CONDITION_Z = 4,\n\tX86_CONDITION_NZ = 5,\n\tX86_CONDITION_BE = 6,\n\tX86_CONDITION_NBE = 7,\n\tX86_CONDITION_S = 8,\n\tX86_CONDITION_NS = 9,\n\tX86_CONDITION_PE = 10,\n\tX86_CONDITION_PO = 11,\n\tX86_CONDITION_L = 12,\n\tX86_CONDITION_NL = 13,\n\tX86_CONDITION_LE = 14,\n\tX86_CONDITION_NLE = 15\n};\nclass x86Assembler64\n{\nprivate:\n\tstd::vector<u8> m_buffer;\n\npublic:\n\tu8* GetBufferPtr() { return m_buffer.data(); };\n\tstd::span<u8> GetBuffer() { return m_buffer; };\n\tu32 GetWriteIndex() { return (u32)m_buffer.size(); };\n\tvoid _emitU8(u8 v) { m_buffer.emplace_back(v); };\n\tvoid _emitU16(u16 v) { size_t writeIdx = m_buffer.size(); m_buffer.resize(writeIdx + 2); *(u16*)(m_buffer.data() + writeIdx) = v; };\n\tvoid _emitU32(u32 v) { size_t writeIdx = m_buffer.size(); m_buffer.resize(writeIdx + 4); *(u32*)(m_buffer.data() + writeIdx) = v; };\n\tvoid _emitU64(u64 v) { size_t writeIdx = m_buffer.size(); m_buffer.resize(writeIdx + 8); *(u64*)(m_buffer.data() + writeIdx) = v; };\n\tusing GPR64 = X86Reg;\n\tusing GPR32 = X86Reg;\n\tusing GPR8_REX = X86Reg;\n\tvoid LockPrefix() { _emitU8(0xF0); };\n\tvoid ADD_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((src >= 4) || (dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x00);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid ADD_bb_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR8_REX src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x00);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADD_bb_r(GPR8_REX dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x02);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADD_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x01);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid ADD_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x01);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid ADD_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x01);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADD_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x01);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADD_dd_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x03);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADD_qq_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x03);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid OR_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((src >= 4) || (dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x08);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid OR_bb_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR8_REX src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x08);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid OR_bb_r(GPR8_REX dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x0a);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid OR_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x09);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid OR_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x09);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid OR_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x09);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid OR_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x09);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid OR_dd_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x0b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid OR_qq_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x0b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADC_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((src >= 4) || (dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x10);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid ADC_bb_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR8_REX src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x10);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADC_bb_r(GPR8_REX dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x12);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADC_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x11);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid ADC_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x11);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid ADC_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x11);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADC_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x11);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADC_dd_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x13);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADC_qq_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x13);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SBB_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((src >= 4) || (dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x18);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid SBB_bb_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR8_REX src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x18);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SBB_bb_r(GPR8_REX dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x1a);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SBB_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x19);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid SBB_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x19);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid SBB_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x19);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SBB_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x19);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SBB_dd_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x1b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SBB_qq_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x1b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid AND_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((src >= 4) || (dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x20);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid AND_bb_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR8_REX src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x20);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid AND_bb_r(GPR8_REX dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x22);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid AND_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x21);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid AND_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x21);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid AND_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x21);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid AND_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x21);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid AND_dd_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x23);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid AND_qq_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x23);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SUB_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((src >= 4) || (dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x28);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid SUB_bb_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR8_REX src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x28);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SUB_bb_r(GPR8_REX dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x2a);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SUB_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x29);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid SUB_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x29);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid SUB_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x29);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SUB_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x29);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SUB_dd_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x2b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SUB_qq_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x2b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid XOR_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((src >= 4) || (dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x30);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid XOR_bb_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR8_REX src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x30);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid XOR_bb_r(GPR8_REX dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x32);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid XOR_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x31);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid XOR_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x31);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid XOR_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x31);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid XOR_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x31);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid XOR_dd_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x33);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid XOR_qq_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x33);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid CMP_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((src >= 4) || (dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x38);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid CMP_bb_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR8_REX src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x38);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid CMP_bb_r(GPR8_REX dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x3a);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid CMP_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x39);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid CMP_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x39);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid CMP_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x39);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid CMP_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x39);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid CMP_dd_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x3b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid CMP_qq_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x3b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid ADD_di32(GPR32 dst, s32 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((0 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid ADD_qi32(GPR64 dst, s32 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((0 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid ADD_di32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((0 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid ADD_qi32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((0 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid OR_di32(GPR32 dst, s32 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((1 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid OR_qi32(GPR64 dst, s32 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((1 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid OR_di32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((1 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid OR_qi32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((1 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid ADC_di32(GPR32 dst, s32 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((2 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid ADC_qi32(GPR64 dst, s32 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((2 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid ADC_di32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((2 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid ADC_qi32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((2 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid SBB_di32(GPR32 dst, s32 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((3 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid SBB_qi32(GPR64 dst, s32 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((3 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid SBB_di32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((3 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid SBB_qi32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((3 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid AND_di32(GPR32 dst, s32 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((4 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid AND_qi32(GPR64 dst, s32 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((4 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid AND_di32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((4 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid AND_qi32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((4 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid SUB_di32(GPR32 dst, s32 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((5 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid SUB_qi32(GPR64 dst, s32 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((5 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid SUB_di32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((5 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid SUB_qi32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((5 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid XOR_di32(GPR32 dst, s32 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((6 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid XOR_qi32(GPR64 dst, s32 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((6 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid XOR_di32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((6 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid XOR_qi32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((6 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid CMP_di32(GPR32 dst, s32 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((7 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid CMP_qi32(GPR64 dst, s32 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x81);\n\t\t_emitU8((3 << 6) | ((7 & 7) << 3) | (dst & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid CMP_di32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((7 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid CMP_qi32_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x81);\n\t\t_emitU8((mod << 6) | ((7 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid ADD_di8(GPR32 dst, s8 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((0 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid ADD_qi8(GPR64 dst, s8 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((0 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid ADD_di8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((0 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid ADD_qi8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((0 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid OR_di8(GPR32 dst, s8 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((1 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid OR_qi8(GPR64 dst, s8 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((1 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid OR_di8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((1 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid OR_qi8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((1 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid ADC_di8(GPR32 dst, s8 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((2 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid ADC_qi8(GPR64 dst, s8 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((2 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid ADC_di8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((2 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid ADC_qi8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((2 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid SBB_di8(GPR32 dst, s8 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((3 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid SBB_qi8(GPR64 dst, s8 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((3 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid SBB_di8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((3 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid SBB_qi8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((3 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid AND_di8(GPR32 dst, s8 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((4 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid AND_qi8(GPR64 dst, s8 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((4 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid AND_di8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((4 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid AND_qi8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((4 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid SUB_di8(GPR32 dst, s8 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((5 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid SUB_qi8(GPR64 dst, s8 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((5 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid SUB_di8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((5 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid SUB_qi8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((5 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid XOR_di8(GPR32 dst, s8 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((6 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid XOR_qi8(GPR64 dst, s8 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((6 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid XOR_di8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((6 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid XOR_qi8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((6 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid CMP_di8(GPR32 dst, s8 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((7 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid CMP_qi8(GPR64 dst, s8 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x83);\n\t\t_emitU8((3 << 6) | ((7 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid CMP_di8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((7 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid CMP_qi8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x83);\n\t\t_emitU8((mod << 6) | ((7 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid TEST_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((src >= 4) || (dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x84);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid TEST_bb_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR8_REX src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x84);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid TEST_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x85);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid TEST_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x85);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid TEST_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x85);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid TEST_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x85);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid XCHG_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((dst >= 4) || (src >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 3) | ((dst & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x86);\n\t\t_emitU8((3 << 6) | ((dst & 7) << 3) | (src & 7));\n\t}\n\tvoid XCHG_bb_r(GPR8_REX dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x86);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid XCHG_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((dst & 8) != 0) || ((src & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 3) | ((dst & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x87);\n\t\t_emitU8((3 << 6) | ((dst & 7) << 3) | (src & 7));\n\t}\n\tvoid XCHG_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((src & 8) >> 3) | ((dst & 8) >> 1));\n\t\t_emitU8(0x87);\n\t\t_emitU8((3 << 6) | ((dst & 7) << 3) | (src & 7));\n\t}\n\tvoid XCHG_dd_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x87);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid XCHG_qq_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x87);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid MOV_bb(GPR8_REX dst, GPR8_REX src)\n\t{\n\t\tif ((src >= 4) || (dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x88);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid MOV_bb_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR8_REX src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x88);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid MOV_bb_r(GPR8_REX dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst >= 4) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x8a);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid MOV_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x89);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid MOV_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x89);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid MOV_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x89);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid MOV_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x89);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid MOV_dd_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x8b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid MOV_qq_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x8b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid MOV_di32(GPR32 dst, s32 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0xb8 | ((dst) & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid MOV_qi64(GPR64 dst, s64 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0xb8 | ((dst) & 7));\n\t\t_emitU64((u64)imm);\n\t}\n\tvoid CALL_q(GPR64 dst)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0xff);\n\t\t_emitU8((3 << 6) | ((2 & 7) << 3) | (dst & 7));\n\t}\n\tvoid CALL_q_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0xff);\n\t\t_emitU8((mod << 6) | ((2 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid IMUL_ddi32(GPR32 dst, GPR32 src, s32 imm)\n\t{\n\t\tif (((dst & 8) != 0) || ((src & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 3) | ((dst & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x69);\n\t\t_emitU8((3 << 6) | ((dst & 7) << 3) | (src & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid IMUL_qqi32(GPR64 dst, GPR64 src, s32 imm)\n\t{\n\t\t_emitU8(0x48 | ((src & 8) >> 3) | ((dst & 8) >> 1));\n\t\t_emitU8(0x69);\n\t\t_emitU8((3 << 6) | ((dst & 7) << 3) | (src & 7));\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid IMUL_ddi32_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x69);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid IMUL_qqi32_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s32 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x69);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid IMUL_ddi8(GPR32 dst, GPR32 src, s8 imm)\n\t{\n\t\tif (((dst & 8) != 0) || ((src & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 3) | ((dst & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x6b);\n\t\t_emitU8((3 << 6) | ((dst & 7) << 3) | (src & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid IMUL_qqi8(GPR64 dst, GPR64 src, s8 imm)\n\t{\n\t\t_emitU8(0x48 | ((src & 8) >> 3) | ((dst & 8) >> 1));\n\t\t_emitU8(0x6b);\n\t\t_emitU8((3 << 6) | ((dst & 7) << 3) | (src & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid IMUL_ddi8_r(GPR32 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((dst & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x6b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid IMUL_qqi8_r(GPR64 dst, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, s8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x6b);\n\t\t_emitU8((mod << 6) | ((dst & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid SHL_b_CL(GPR8_REX dst)\n\t{\n\t\tif ((dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0xd2);\n\t\t_emitU8((3 << 6) | ((4 & 7) << 3) | (dst & 7));\n\t}\n\tvoid SHL_b_CL_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0xd2);\n\t\t_emitU8((mod << 6) | ((4 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SHR_b_CL(GPR8_REX dst)\n\t{\n\t\tif ((dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0xd2);\n\t\t_emitU8((3 << 6) | ((5 & 7) << 3) | (dst & 7));\n\t}\n\tvoid SHR_b_CL_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0xd2);\n\t\t_emitU8((mod << 6) | ((5 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SAR_b_CL(GPR8_REX dst)\n\t{\n\t\tif ((dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0xd2);\n\t\t_emitU8((3 << 6) | ((7 & 7) << 3) | (dst & 7));\n\t}\n\tvoid SAR_b_CL_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0xd2);\n\t\t_emitU8((mod << 6) | ((7 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SHL_d_CL(GPR32 dst)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0xd3);\n\t\t_emitU8((3 << 6) | ((4 & 7) << 3) | (dst & 7));\n\t}\n\tvoid SHL_q_CL(GPR64 dst)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0xd3);\n\t\t_emitU8((3 << 6) | ((4 & 7) << 3) | (dst & 7));\n\t}\n\tvoid SHL_d_CL_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0xd3);\n\t\t_emitU8((mod << 6) | ((4 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SHL_q_CL_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0xd3);\n\t\t_emitU8((mod << 6) | ((4 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SHR_d_CL(GPR32 dst)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0xd3);\n\t\t_emitU8((3 << 6) | ((5 & 7) << 3) | (dst & 7));\n\t}\n\tvoid SHR_q_CL(GPR64 dst)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0xd3);\n\t\t_emitU8((3 << 6) | ((5 & 7) << 3) | (dst & 7));\n\t}\n\tvoid SHR_d_CL_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0xd3);\n\t\t_emitU8((mod << 6) | ((5 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SHR_q_CL_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0xd3);\n\t\t_emitU8((mod << 6) | ((5 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SAR_d_CL(GPR32 dst)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0xd3);\n\t\t_emitU8((3 << 6) | ((7 & 7) << 3) | (dst & 7));\n\t}\n\tvoid SAR_q_CL(GPR64 dst)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0xd3);\n\t\t_emitU8((3 << 6) | ((7 & 7) << 3) | (dst & 7));\n\t}\n\tvoid SAR_d_CL_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0xd3);\n\t\t_emitU8((mod << 6) | ((7 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid SAR_q_CL_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0xd3);\n\t\t_emitU8((mod << 6) | ((7 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid JMP_j32(s32 imm)\n\t{\n\t\t_emitU8(0xe9);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid Jcc_j32(X86Cond cond, s32 imm)\n\t{\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0x80 | (u8)cond);\n\t\t_emitU32((u32)imm);\n\t}\n\tvoid SETcc_b(X86Cond cond, GPR8_REX dst)\n\t{\n\t\tif ((dst >= 4))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0x90 | (u8)cond);\n\t\t_emitU8((3 << 6) | (dst & 7));\n\t}\n\tvoid SETcc_b_l(X86Cond cond, GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0x90);\n\t\t_emitU8((mod << 6) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid CMPXCHG_dd(GPR32 dst, GPR32 src)\n\t{\n\t\tif (((src & 8) != 0) || ((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0xb1);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid CMPXCHG_qq(GPR64 dst, GPR64 src)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3) | ((src & 8) >> 1));\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0xb1);\n\t\t_emitU8((3 << 6) | ((src & 7) << 3) | (dst & 7));\n\t}\n\tvoid CMPXCHG_dd_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR32 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((src & 8) || (memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0xb1);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid CMPXCHG_qq_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, GPR64 src)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((src & 8) >> 1) | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0xb1);\n\t\t_emitU8((mod << 6) | ((src & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t}\n\tvoid BSWAP_d(GPR32 dst)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0xc8 | ((dst) & 7));\n\t}\n\tvoid BSWAP_q(GPR64 dst)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0xc8 | ((dst) & 7));\n\t}\n\tvoid BT_du8(GPR32 dst, u8 imm)\n\t{\n\t\tif (((dst & 8) != 0))\n\t\t{\n\t\t\t_emitU8(0x40 | ((dst & 8) >> 3));\n\t\t}\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0xba);\n\t\t_emitU8((3 << 6) | ((4 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid BT_qu8(GPR64 dst, u8 imm)\n\t{\n\t\t_emitU8(0x48 | ((dst & 8) >> 3));\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0xba);\n\t\t_emitU8((3 << 6) | ((4 & 7) << 3) | (dst & 7));\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid BT_du8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, u8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\tif ((memReg & 8) || ((index != X86_REG_NONE) && (index & 8)))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((memReg & 8))\n\t\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1));\n\t\t}\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0xba);\n\t\t_emitU8((mod << 6) | ((4 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n\tvoid BT_qu8_l(GPR64 memReg, sint32 offset, GPR64 index, uint8 scaler, u8 imm)\n\t{\n\t\tuint8 mod;\n\t\tif (offset == 0 && (memReg & 7) != 5) mod = 0;\n\t\telse if (offset == (s32)(s8)offset) mod = 1;\n\t\telse mod = 2;\n\t\tbool sib_use = (scaler != 0 && index != X86_REG_NONE);\n\t\tif ((memReg & 7) == 4)\n\t\t{\n\t\t\tcemu_assert_debug(index == X86_REG_NONE);\n\t\t\tindex = memReg;\n\t\t\tsib_use = true;\n\t\t}\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 3) | ((index & 8) >> 2) | 0x08);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitU8(0x40 | ((memReg & 8) >> 1) | 0x08);\n\t\t}\n\t\t_emitU8(0x0f);\n\t\t_emitU8(0xba);\n\t\t_emitU8((mod << 6) | ((4 & 7) << 3) | (sib_use ? 4 : (memReg & 7)));\n\t\tif (sib_use)\n\t\t{\n\t\t\t_emitU8((0 << 6) | ((memReg & 7)) | ((index & 7) << 3));\n\t\t}\n\t\tif (mod == 1) _emitU8((u8)offset);\n\t\telse if (mod == 2) _emitU32((u32)offset);\n\t\t_emitU8((u8)imm);\n\t}\n};\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IML.h",
    "content": "#pragma once \n\n#include \"IMLInstruction.h\"\n#include \"IMLSegment.h\"\n\n// optimizer passes\nvoid IMLOptimizer_OptimizeDirectFloatCopies(struct ppcImlGenContext_t* ppcImlGenContext);\nvoid IMLOptimizer_OptimizeDirectIntegerCopies(struct ppcImlGenContext_t* ppcImlGenContext);\nvoid PPCRecompiler_optimizePSQLoadAndStore(struct ppcImlGenContext_t* ppcImlGenContext);\n\nvoid IMLOptimizer_StandardOptimizationPass(ppcImlGenContext_t& ppcImlGenContext);\n\n// debug\nvoid IMLDebug_DisassembleInstruction(const IMLInstruction& inst, std::string& disassemblyLineOut);\nvoid IMLDebug_DumpSegment(struct ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool printLivenessRangeInfo = false);\nvoid IMLDebug_Dump(struct ppcImlGenContext_t* ppcImlGenContext, bool printLivenessRangeInfo = false);\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLAnalyzer.cpp",
    "content": "#include \"IML.h\"\n//#include \"PPCRecompilerIml.h\"\n#include \"util/helpers/fixedSizeList.h\"\n\n#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLDebug.cpp",
    "content": "#include \"IML.h\"\n#include \"IMLInstruction.h\"\n#include \"IMLSegment.h\"\n#include \"IMLRegisterAllocatorRanges.h\"\n#include \"util/helpers/StringBuf.h\"\n\n#include \"../PPCRecompiler.h\"\n\nconst char* IMLDebug_GetOpcodeName(const IMLInstruction* iml)\n{\n\tstatic char _tempOpcodename[32];\n\tuint32 op = iml->operation;\n\tif (op == PPCREC_IML_OP_ASSIGN)\n\t\treturn \"MOV\";\n\telse if (op == PPCREC_IML_OP_ADD)\n\t\treturn \"ADD\";\n\telse if (op == PPCREC_IML_OP_ADD_WITH_CARRY)\n\t\treturn \"ADC\";\n\telse if (op == PPCREC_IML_OP_SUB)\n\t\treturn \"SUB\";\n\telse if (op == PPCREC_IML_OP_OR)\n\t\treturn \"OR\";\n\telse if (op == PPCREC_IML_OP_AND)\n\t\treturn \"AND\";\n\telse if (op == PPCREC_IML_OP_XOR)\n\t\treturn \"XOR\";\n\telse if (op == PPCREC_IML_OP_LEFT_SHIFT)\n\t\treturn \"LSH\";\n\telse if (op == PPCREC_IML_OP_RIGHT_SHIFT_U)\n\t\treturn \"RSH\";\n\telse if (op == PPCREC_IML_OP_RIGHT_SHIFT_S)\n\t\treturn \"ARSH\";\n\telse if (op == PPCREC_IML_OP_LEFT_ROTATE)\n\t\treturn \"LROT\";\n\telse if (op == PPCREC_IML_OP_MULTIPLY_SIGNED)\n\t\treturn \"MULS\";\n\telse if (op == PPCREC_IML_OP_DIVIDE_SIGNED)\n\t\treturn \"DIVS\";\n\telse if (op == PPCREC_IML_OP_FPR_ASSIGN)\n\t\treturn \"FMOV\";\n\telse if (op == PPCREC_IML_OP_FPR_ADD)\n\t\treturn \"FADD\";\n\telse if (op == PPCREC_IML_OP_FPR_SUB)\n\t\treturn \"FSUB\";\n\telse if (op == PPCREC_IML_OP_FPR_MULTIPLY)\n\t\treturn \"FMUL\";\n\telse if (op == PPCREC_IML_OP_FPR_DIVIDE)\n\t\treturn \"FDIV\";\n\telse if (op == PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64)\n\t\treturn \"F32TOF64\";\n\telse if (op == PPCREC_IML_OP_FPR_ABS)\n\t\treturn \"FABS\";\n\telse if (op == PPCREC_IML_OP_FPR_NEGATE)\n\t\treturn \"FNEG\";\n\telse if (op == PPCREC_IML_OP_FPR_NEGATIVE_ABS)\n\t\treturn \"FNABS\";\n\telse if (op == PPCREC_IML_OP_FPR_FLOAT_TO_INT)\n\t\treturn \"F2I\";\n\telse if (op == PPCREC_IML_OP_FPR_INT_TO_FLOAT)\n\t\treturn \"I2F\";\n\telse if (op == PPCREC_IML_OP_FPR_BITCAST_INT_TO_FLOAT)\n\t\treturn \"BITMOVE\";\n\n\tsprintf(_tempOpcodename, \"OP0%02x_T%d\", iml->operation, iml->type);\n\treturn _tempOpcodename;\n}\n\nstd::string IMLDebug_GetRegName(IMLReg r)\n{\n\tstd::string regName;\n\tuint32 regId = r.GetRegID();\n\tswitch (r.GetRegFormat())\n\t{\n\tcase IMLRegFormat::F32:\n\t\tregName.append(\"f\");\n\t\tbreak;\n\tcase IMLRegFormat::F64:\n\t\tregName.append(\"fd\");\n\t\tbreak;\n\tcase IMLRegFormat::I32:\n\t\tregName.append(\"i\");\n\t\tbreak;\n\tcase IMLRegFormat::I64:\n\t\tregName.append(\"r\");\n\t\tbreak;\n\tdefault:\n\t\tDEBUG_BREAK;\n\t}\n\tregName.append(fmt::format(\"{}\", regId));\n\treturn regName;\n}\n\nvoid IMLDebug_AppendRegisterParam(StringBuf& strOutput, IMLReg virtualRegister, bool isLast = false)\n{\n\tstrOutput.add(IMLDebug_GetRegName(virtualRegister));\n\tif (!isLast)\n\t\tstrOutput.add(\", \");\n}\n\nvoid IMLDebug_AppendS32Param(StringBuf& strOutput, sint32 val, bool isLast = false)\n{\n\tif (val < 0)\n\t{\n\t\tstrOutput.add(\"-\");\n\t\tval = -val;\n\t}\n\tstrOutput.addFmt(\"0x{:08x}\", val);\n\tif (!isLast)\n\t\tstrOutput.add(\", \");\n}\n\nvoid IMLDebug_PrintLivenessRangeInfo(StringBuf& currentLineText, IMLSegment* imlSegment, sint32 offset)\n{\n\t// pad to 70 characters\n\tsint32 index = currentLineText.getLen();\n\twhile (index < 70)\n\t{\n\t\tcurrentLineText.add(\" \");\n\t\tindex++;\n\t}\n\traLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;\n\twhile (subrangeItr)\n\t{\n\t\tif (subrangeItr->interval.start.GetInstructionIndexEx() == offset)\n\t\t{\n\t\t\tif(subrangeItr->interval.start.IsInstructionIndex() && !subrangeItr->interval.start.IsOnInputEdge())\n\t\t\t\tcurrentLineText.add(\".\");\n\t\t\telse\n\t\t\t\tcurrentLineText.add(\"|\");\n\n\t\t\tcurrentLineText.addFmt(\"{:<4}\", subrangeItr->GetVirtualRegister());\n\t\t}\n\t\telse if (subrangeItr->interval.end.GetInstructionIndexEx() == offset)\n\t\t{\n\t\t\tif(subrangeItr->interval.end.IsInstructionIndex() && !subrangeItr->interval.end.IsOnOutputEdge())\n\t\t\t\tcurrentLineText.add(\"*    \");\n\t\t\telse\n\t\t\t\tcurrentLineText.add(\"|    \");\n\t\t}\n\t\telse if (subrangeItr->interval.ContainsInstructionIndexEx(offset))\n\t\t{\n\t\t\tcurrentLineText.add(\"|    \");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcurrentLineText.add(\"     \");\n\t\t}\n\t\tindex += 5;\n\t\t// next\n\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t}\n}\n\nstd::string IMLDebug_GetSegmentName(ppcImlGenContext_t* ctx, IMLSegment* seg)\n{\n\tif (!ctx)\n\t{\n\t\treturn \"<NoNameWithoutCtx>\";\n\t}\n\t// find segment index\n\tfor (size_t i = 0; i < ctx->segmentList2.size(); i++)\n\t{\n\t\tif (ctx->segmentList2[i] == seg)\n\t\t{\n\t\t\treturn fmt::format(\"Seg{:04x}\", i);\n\t\t}\n\t}\n\treturn \"<SegmentNotInCtx>\";\n}\n\nstd::string IMLDebug_GetConditionName(IMLCondition cond)\n{\n\tswitch (cond)\n\t{\n\tcase IMLCondition::EQ:\n\t\treturn \"EQ\";\n\tcase IMLCondition::NEQ:\n\t\treturn \"NEQ\";\n\tcase IMLCondition::UNSIGNED_GT:\n\t\treturn \"UGT\";\n\tcase IMLCondition::UNSIGNED_LT:\n\t\treturn \"ULT\";\n\tcase IMLCondition::SIGNED_GT:\n\t\treturn \"SGT\";\n\tcase IMLCondition::SIGNED_LT:\n\t\treturn \"SLT\";\n\tdefault:\n\t\tcemu_assert_unimplemented();\n\t}\n\treturn \"ukn\";\n}\n\nvoid IMLDebug_DisassembleInstruction(const IMLInstruction& inst, std::string& disassemblyLineOut)\n{\n\tconst sint32 lineOffsetParameters = 10;//18;\n\n\tStringBuf strOutput(1024);\n\tstrOutput.reset();\n\tif (inst.type == PPCREC_IML_TYPE_R_NAME || inst.type == PPCREC_IML_TYPE_NAME_R)\n\t{\n\t\tif (inst.type == PPCREC_IML_TYPE_R_NAME)\n\t\t\tstrOutput.add(\"R_NAME\");\n\t\telse\n\t\t\tstrOutput.add(\"NAME_R\");\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\n\t\tif(inst.type == PPCREC_IML_TYPE_R_NAME)\n\t\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_name.regR);\n\n\t\tstrOutput.add(\"name_\");\n\t\tif (inst.op_r_name.name >= PPCREC_NAME_R0 && inst.op_r_name.name < (PPCREC_NAME_R0 + 999))\n\t\t{\n\t\t\tstrOutput.addFmt(\"r{}\", inst.op_r_name.name - PPCREC_NAME_R0);\n\t\t}\n\t\tif (inst.op_r_name.name >= PPCREC_NAME_FPR_HALF && inst.op_r_name.name < (PPCREC_NAME_FPR_HALF + 32*2))\n\t\t{\n\t\t\tstrOutput.addFmt(\"f{}\", inst.op_r_name.name - ((PPCREC_NAME_FPR_HALF - inst.op_r_name.name)/2));\n\t\t\tif ((inst.op_r_name.name-PPCREC_NAME_FPR_HALF)&1)\n\t\t\t\tstrOutput.add(\".ps1\");\n\t\t\telse\n\t\t\t\tstrOutput.add(\".ps0\");\n\t\t}\n\t\telse if (inst.op_r_name.name >= PPCREC_NAME_SPR0 && inst.op_r_name.name < (PPCREC_NAME_SPR0 + 999))\n\t\t{\n\t\t\tstrOutput.addFmt(\"spr{}\", inst.op_r_name.name - PPCREC_NAME_SPR0);\n\t\t}\n\t\telse if (inst.op_r_name.name >= PPCREC_NAME_CR && inst.op_r_name.name <= PPCREC_NAME_CR_LAST)\n\t\t\tstrOutput.addFmt(\"cr{}\", inst.op_r_name.name - PPCREC_NAME_CR);\n\t\telse if (inst.op_r_name.name == PPCREC_NAME_XER_CA)\n\t\t\tstrOutput.add(\"xer.ca\");\n\t\telse if (inst.op_r_name.name == PPCREC_NAME_XER_SO)\n\t\t\tstrOutput.add(\"xer.so\");\n\t\telse if (inst.op_r_name.name == PPCREC_NAME_XER_OV)\n\t\t\tstrOutput.add(\"xer.ov\");\n\t\telse if (inst.op_r_name.name == PPCREC_NAME_CPU_MEMRES_EA)\n\t\t\tstrOutput.add(\"cpuReservation.ea\");\n\t\telse if (inst.op_r_name.name == PPCREC_NAME_CPU_MEMRES_VAL)\n\t\t\tstrOutput.add(\"cpuReservation.value\");\n\t\telse\n\t\t{\n\t\t\tstrOutput.addFmt(\"name_ukn{}\", inst.op_r_name.name);\n\t\t}\n\t\tif (inst.type != PPCREC_IML_TYPE_R_NAME)\n\t\t{\n\t\t\tstrOutput.add(\", \");\n\t\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_name.regR, true);\n\t\t}\n\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_R_R)\n\t{\n\t\tstrOutput.addFmt(\"{}\", IMLDebug_GetOpcodeName(&inst));\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r.regR);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r.regA, true);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_R_R_R)\n\t{\n\t\tstrOutput.addFmt(\"{}\", IMLDebug_GetOpcodeName(&inst));\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_r.regR);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_r.regA);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_r.regB, true);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_R_R_R_CARRY)\n\t{\n\t\tstrOutput.addFmt(\"{}\", IMLDebug_GetOpcodeName(&inst));\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_r_carry.regR);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_r_carry.regA);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_r_carry.regB);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_r_carry.regCarry, true);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_COMPARE)\n\t{\n\t\tstrOutput.add(\"CMP \");\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_compare.regA);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_compare.regB);\n\t\tstrOutput.addFmt(\"{}\", IMLDebug_GetConditionName(inst.op_compare.cond));\n\t\tstrOutput.add(\" -> \");\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_compare.regR, true);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_COMPARE_S32)\n\t{\n\t\tstrOutput.add(\"CMP \");\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_compare_s32.regA);\n\t\tstrOutput.addFmt(\"{}\", inst.op_compare_s32.immS32);\n\t\tstrOutput.addFmt(\", {}\", IMLDebug_GetConditionName(inst.op_compare_s32.cond));\n\t\tstrOutput.add(\" -> \");\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_compare_s32.regR, true);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_CONDITIONAL_JUMP)\n\t{\n\t\tstrOutput.add(\"CJUMP \");\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_conditional_jump.registerBool, true);\n\t\tif (!inst.op_conditional_jump.mustBeTrue)\n\t\t\tstrOutput.add(\"(inverted)\");\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_JUMP)\n\t{\n\t\tstrOutput.add(\"JUMP\");\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_R_R_S32)\n\t{\n\t\tstrOutput.addFmt(\"{}\", IMLDebug_GetOpcodeName(&inst));\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_s32.regR);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_s32.regA);\n\t\tIMLDebug_AppendS32Param(strOutput, inst.op_r_r_s32.immS32, true);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_R_R_S32_CARRY)\n\t{\n\t\tstrOutput.addFmt(\"{}\", IMLDebug_GetOpcodeName(&inst));\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_s32_carry.regR);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_s32_carry.regA);\n\t\tIMLDebug_AppendS32Param(strOutput, inst.op_r_r_s32_carry.immS32);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_r_s32_carry.regCarry, true);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_R_S32)\n\t{\n\t\tstrOutput.addFmt(\"{}\", IMLDebug_GetOpcodeName(&inst));\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_r_immS32.regR);\n\t\tIMLDebug_AppendS32Param(strOutput, inst.op_r_immS32.immS32, true);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_LOAD || inst.type == PPCREC_IML_TYPE_STORE ||\n\t\t\t inst.type == PPCREC_IML_TYPE_LOAD_INDEXED || inst.type == PPCREC_IML_TYPE_STORE_INDEXED)\n\t{\n\t\tif (inst.type == PPCREC_IML_TYPE_LOAD || inst.type == PPCREC_IML_TYPE_LOAD_INDEXED)\n\t\t\tstrOutput.add(\"LD_\");\n\t\telse\n\t\t\tstrOutput.add(\"ST_\");\n\n\t\tif (inst.op_storeLoad.flags2.signExtend)\n\t\t\tstrOutput.add(\"S\");\n\t\telse\n\t\t\tstrOutput.add(\"U\");\n\t\tstrOutput.addFmt(\"{}\", inst.op_storeLoad.copyWidth);\n\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_storeLoad.registerData);\n\n\t\tif (inst.type == PPCREC_IML_TYPE_LOAD_INDEXED || inst.type == PPCREC_IML_TYPE_STORE_INDEXED)\n\t\t\tstrOutput.addFmt(\"[{}+{}]\", IMLDebug_GetRegName(inst.op_storeLoad.registerMem), IMLDebug_GetRegName(inst.op_storeLoad.registerMem2));\n\t\telse\n\t\t\tstrOutput.addFmt(\"[{}+{}]\", IMLDebug_GetRegName(inst.op_storeLoad.registerMem), inst.op_storeLoad.immS32);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_ATOMIC_CMP_STORE)\n\t{\n\t\tstrOutput.add(\"ATOMIC_ST_U32\");\n\n\t\twhile ((sint32)strOutput.getLen() < lineOffsetParameters)\n\t\t\tstrOutput.add(\" \");\n\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_atomic_compare_store.regEA);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_atomic_compare_store.regCompareValue);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_atomic_compare_store.regWriteValue);\n\t\tIMLDebug_AppendRegisterParam(strOutput, inst.op_atomic_compare_store.regBoolOut, true);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_NO_OP)\n\t{\n\t\tstrOutput.add(\"NOP\");\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_MACRO)\n\t{\n\t\tif (inst.operation == PPCREC_IML_MACRO_B_TO_REG)\n\t\t{\n\t\t\tstrOutput.addFmt(\"MACRO B_TO_REG {}\", IMLDebug_GetRegName(inst.op_macro.paramReg));\n\t\t}\n\t\telse if (inst.operation == PPCREC_IML_MACRO_BL)\n\t\t{\n\t\t\tstrOutput.addFmt(\"MACRO BL 0x{:08x} -> 0x{:08x} cycles (depr): {}\", inst.op_macro.param, inst.op_macro.param2, (sint32)inst.op_macro.paramU16);\n\t\t}\n\t\telse if (inst.operation == PPCREC_IML_MACRO_B_FAR)\n\t\t{\n\t\t\tstrOutput.addFmt(\"MACRO B_FAR 0x{:08x} -> 0x{:08x} cycles (depr): {}\", inst.op_macro.param, inst.op_macro.param2, (sint32)inst.op_macro.paramU16);\n\t\t}\n\t\telse if (inst.operation == PPCREC_IML_MACRO_LEAVE)\n\t\t{\n\t\t\tstrOutput.addFmt(\"MACRO LEAVE ppc: 0x{:08x}\", inst.op_macro.param);\n\t\t}\n\t\telse if (inst.operation == PPCREC_IML_MACRO_HLE)\n\t\t{\n\t\t\tstrOutput.addFmt(\"MACRO HLE ppcAddr: 0x{:08x} funcId: 0x{:08x}\", inst.op_macro.param, inst.op_macro.param2);\n\t\t}\n\t\telse if (inst.operation == PPCREC_IML_MACRO_COUNT_CYCLES)\n\t\t{\n\t\t\tstrOutput.addFmt(\"MACRO COUNT_CYCLES cycles: {}\", inst.op_macro.param);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstrOutput.addFmt(\"MACRO ukn operation {}\", inst.operation);\n\t\t}\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_FPR_LOAD)\n\t{\n\t\tstrOutput.addFmt(\"{} = \", IMLDebug_GetRegName(inst.op_storeLoad.registerData));\n\t\tif (inst.op_storeLoad.flags2.signExtend)\n\t\t\tstrOutput.add(\"S\");\n\t\telse\n\t\t\tstrOutput.add(\"U\");\n\t\tstrOutput.addFmt(\"{} [{}+{}] mode {}\", inst.op_storeLoad.copyWidth / 8, IMLDebug_GetRegName(inst.op_storeLoad.registerMem), inst.op_storeLoad.immS32, inst.op_storeLoad.mode);\n\t\tif (inst.op_storeLoad.flags2.notExpanded)\n\t\t{\n\t\t\tstrOutput.addFmt(\" <No expand>\");\n\t\t}\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_FPR_STORE)\n\t{\n\t\tif (inst.op_storeLoad.flags2.signExtend)\n\t\t\tstrOutput.add(\"S\");\n\t\telse\n\t\t\tstrOutput.add(\"U\");\n\t\tstrOutput.addFmt(\"{} [t{}+{}]\", inst.op_storeLoad.copyWidth / 8, inst.op_storeLoad.registerMem.GetRegID(), inst.op_storeLoad.immS32);\n\t\tstrOutput.addFmt(\" = {} mode {}\", IMLDebug_GetRegName(inst.op_storeLoad.registerData), inst.op_storeLoad.mode);\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_FPR_R)\n\t{\n\t\tstrOutput.addFmt(\"{:<6} \", IMLDebug_GetOpcodeName(&inst));\n\t\tstrOutput.addFmt(\"{}\", IMLDebug_GetRegName(inst.op_fpr_r.regR));\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_FPR_R_R)\n\t{\n\t\tstrOutput.addFmt(\"{:<6} \", IMLDebug_GetOpcodeName(&inst));\n\t\tstrOutput.addFmt(\"{}, {}\", IMLDebug_GetRegName(inst.op_fpr_r_r.regR), IMLDebug_GetRegName(inst.op_fpr_r_r.regA));\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_FPR_R_R_R_R)\n\t{\n\t\tstrOutput.addFmt(\"{:<6} \", IMLDebug_GetOpcodeName(&inst));\n\t\tstrOutput.addFmt(\"{}, {}, {}, {}\", IMLDebug_GetRegName(inst.op_fpr_r_r_r_r.regR), IMLDebug_GetRegName(inst.op_fpr_r_r_r_r.regA), IMLDebug_GetRegName(inst.op_fpr_r_r_r_r.regB), IMLDebug_GetRegName(inst.op_fpr_r_r_r_r.regC));\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_FPR_R_R_R)\n\t{\n\t\tstrOutput.addFmt(\"{:<6} \", IMLDebug_GetOpcodeName(&inst));\n\t\tstrOutput.addFmt(\"{}, {}, {}\", IMLDebug_GetRegName(inst.op_fpr_r_r_r.regR), IMLDebug_GetRegName(inst.op_fpr_r_r_r.regA), IMLDebug_GetRegName(inst.op_fpr_r_r_r.regB));\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK)\n\t{\n\t\tstrOutput.addFmt(\"CYCLE_CHECK\");\n\t}\n\telse if (inst.type == PPCREC_IML_TYPE_X86_EFLAGS_JCC)\n\t{\n\t\tstrOutput.addFmt(\"X86_JCC {}\", IMLDebug_GetConditionName(inst.op_x86_eflags_jcc.cond));\n\t}\n\telse\n\t{\n\t\tstrOutput.addFmt(\"Unknown iml type {}\", inst.type);\n\t}\n\tdisassemblyLineOut.assign(strOutput.c_str());\n}\n\nvoid IMLDebug_DumpSegment(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, bool printLivenessRangeInfo)\n{\n\tStringBuf strOutput(4096);\n\n\tstrOutput.addFmt(\"SEGMENT {} | PPC=0x{:08x} Loop-depth {}\", IMLDebug_GetSegmentName(ctx, imlSegment), imlSegment->ppcAddress, imlSegment->loopDepth);\n\tif (imlSegment->isEnterable)\n\t{\n\t\tstrOutput.addFmt(\" ENTERABLE (0x{:08x})\", imlSegment->enterPPCAddress);\n\t}\n\tif (imlSegment->deadCodeEliminationHintSeg)\n\t{\n\t\tstrOutput.addFmt(\" InheritOverwrite: {}\", IMLDebug_GetSegmentName(ctx, imlSegment->deadCodeEliminationHintSeg));\n\t}\n\tcemuLog_log(LogType::Force, \"{}\", strOutput.c_str());\n\n\tif (printLivenessRangeInfo)\n\t{\n\t\tstrOutput.reset();\n\t\tIMLDebug_PrintLivenessRangeInfo(strOutput, imlSegment, RA_INTER_RANGE_START);\n\t\tcemuLog_log(LogType::Force, \"{}\", strOutput.c_str());\n\t}\n\t//debug_printf(\"\\n\");\n\tstrOutput.reset();\n\n\tstd::string disassemblyLine;\n\tfor (sint32 i = 0; i < imlSegment->imlList.size(); i++)\n\t{\n\t\tconst IMLInstruction& inst = imlSegment->imlList[i];\n\t\t// don't log NOP instructions\n\t\tif (inst.type == PPCREC_IML_TYPE_NO_OP)\n\t\t\tcontinue;\n\t\tstrOutput.reset();\n\t\tstrOutput.addFmt(\"{:02x} \", i);\n\t\t//cemuLog_log(LogType::Force, \"{:02x} \", i);\n\t\tdisassemblyLine.clear();\n\t\tIMLDebug_DisassembleInstruction(inst, disassemblyLine);\n\t\tstrOutput.add(disassemblyLine);\n\t\tif (printLivenessRangeInfo)\n\t\t{\n\t\t\tIMLDebug_PrintLivenessRangeInfo(strOutput, imlSegment, i);\n\t\t}\n\t\tcemuLog_log(LogType::Force, \"{}\", strOutput.c_str());\n\t}\n\t// all ranges\n\tif (printLivenessRangeInfo)\n\t{\n\t\tstrOutput.reset();\n\t\tstrOutput.add(\"Ranges-VirtReg                                                        \");\n\t\traLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;\n\t\twhile (subrangeItr)\n\t\t{\n\t\t\tstrOutput.addFmt(\"v{:<4}\", (uint32)subrangeItr->GetVirtualRegister());\n\t\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t\t}\n\t\tcemuLog_log(LogType::Force, \"{}\", strOutput.c_str());\n\t\tstrOutput.reset();\n\t\tstrOutput.add(\"Ranges-PhysReg                                                        \");\n\t\tsubrangeItr = imlSegment->raInfo.linkedList_allSubranges;\n\t\twhile (subrangeItr)\n\t\t{\n\t\t\tstrOutput.addFmt(\"p{:<4}\", subrangeItr->GetPhysicalRegister());\n\t\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t\t}\n\t\tcemuLog_log(LogType::Force, \"{}\", strOutput.c_str());\n\t}\n\t// branch info\n\tstrOutput.reset();\n\tstrOutput.add(\"Links from: \");\n\tfor (sint32 i = 0; i < imlSegment->list_prevSegments.size(); i++)\n\t{\n\t\tif (i)\n\t\t\tstrOutput.add(\", \");\n\t\tstrOutput.addFmt(\"{}\", IMLDebug_GetSegmentName(ctx, imlSegment->list_prevSegments[i]).c_str());\n\t}\n\tcemuLog_log(LogType::Force, \"{}\", strOutput.c_str());\n\tif (imlSegment->nextSegmentBranchNotTaken)\n\t\tcemuLog_log(LogType::Force, \"BranchNotTaken: {}\", IMLDebug_GetSegmentName(ctx, imlSegment->nextSegmentBranchNotTaken).c_str());\n\tif (imlSegment->nextSegmentBranchTaken)\n\t\tcemuLog_log(LogType::Force, \"BranchTaken: {}\", IMLDebug_GetSegmentName(ctx, imlSegment->nextSegmentBranchTaken).c_str());\n\tif (imlSegment->nextSegmentIsUncertain)\n\t\tcemuLog_log(LogType::Force, \"Dynamic target\");\n}\n\nvoid IMLDebug_Dump(ppcImlGenContext_t* ppcImlGenContext, bool printLivenessRangeInfo)\n{\n\tfor (size_t i = 0; i < ppcImlGenContext->segmentList2.size(); i++)\n\t{\n\t\tIMLDebug_DumpSegment(ppcImlGenContext, ppcImlGenContext->segmentList2[i], printLivenessRangeInfo);\n\t\tcemuLog_log(LogType::Force, \"\");\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.cpp",
    "content": "#include \"IMLInstruction.h\"\n#include \"IML.h\"\n\n#include \"../PPCRecompiler.h\"\n#include \"../PPCRecompilerIml.h\"\n\n// return true if an instruction has side effects on top of just reading and writing registers\nbool IMLInstruction::HasSideEffects() const\n{\n\tbool hasSideEffects = true;\n\tif(type == PPCREC_IML_TYPE_R_R || type == PPCREC_IML_TYPE_R_R_S32 || type == PPCREC_IML_TYPE_COMPARE || type == PPCREC_IML_TYPE_COMPARE_S32)\n\t\thasSideEffects = false;\n\t// todo - add more cases\n\treturn hasSideEffects;\n}\n\nvoid IMLInstruction::CheckRegisterUsage(IMLUsedRegisters* registersUsed) const\n{\n\tregistersUsed->readGPR1 = IMLREG_INVALID;\n\tregistersUsed->readGPR2 = IMLREG_INVALID;\n\tregistersUsed->readGPR3 = IMLREG_INVALID;\n\tregistersUsed->readGPR4 = IMLREG_INVALID;\n\tregistersUsed->writtenGPR1 = IMLREG_INVALID;\n\tregistersUsed->writtenGPR2 = IMLREG_INVALID;\n\tif (type == PPCREC_IML_TYPE_R_NAME)\n\t{\n\t\tregistersUsed->writtenGPR1 = op_r_name.regR;\n\t}\n\telse if (type == PPCREC_IML_TYPE_NAME_R)\n\t{\n\t\tregistersUsed->readGPR1 = op_r_name.regR;\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_R)\n\t{\n\t\tif (operation == PPCREC_IML_OP_X86_CMP)\n\t\t{\n\t\t\t// both operands are read only\n\t\t\tregistersUsed->readGPR1 = op_r_r.regR;\n\t\t\tregistersUsed->readGPR2 = op_r_r.regA;\n\t\t}\n\t\telse if (\n\t\t\toperation == PPCREC_IML_OP_ASSIGN ||\n\t\t\toperation == PPCREC_IML_OP_ENDIAN_SWAP ||\n\t\t\toperation == PPCREC_IML_OP_CNTLZW ||\n\t\t\toperation == PPCREC_IML_OP_NOT ||\n\t\t\toperation == PPCREC_IML_OP_NEG ||\n\t\t\toperation == PPCREC_IML_OP_ASSIGN_S16_TO_S32 ||\n\t\t\toperation == PPCREC_IML_OP_ASSIGN_S8_TO_S32)\n\t\t{\n\t\t\t// result is written, operand is read\n\t\t\tregistersUsed->writtenGPR1 = op_r_r.regR;\n\t\t\tregistersUsed->readGPR1 = op_r_r.regA;\n\t\t}\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_S32)\n\t{\n\t\tcemu_assert_debug(operation != PPCREC_IML_OP_ADD &&\n\t\t\toperation != PPCREC_IML_OP_SUB &&\n\t\t\toperation != PPCREC_IML_OP_AND &&\n\t\t\toperation != PPCREC_IML_OP_OR &&\n\t\t\toperation != PPCREC_IML_OP_XOR); // deprecated, use r_r_s32 for these\n\n\t\tif (operation == PPCREC_IML_OP_LEFT_ROTATE)\n\t\t{\n\t\t\t// register operand is read and write\n\t\t\tregistersUsed->readGPR1 = op_r_immS32.regR;\n\t\t\tregistersUsed->writtenGPR1 = op_r_immS32.regR;\n\t\t}\n\t\telse if (operation == PPCREC_IML_OP_X86_CMP)\n\t\t{\n\t\t\t// register operand is read only\n\t\t\tregistersUsed->readGPR1 = op_r_immS32.regR;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// register operand is write only\n\t\t\t// todo - use explicit lists, avoid default cases\n\t\t\tregistersUsed->writtenGPR1 = op_r_immS32.regR;\n\t\t}\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_R_S32)\n\t{\n\t\tregistersUsed->writtenGPR1 = op_r_r_s32.regR;\n\t\tregistersUsed->readGPR1 = op_r_r_s32.regA;\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_R_S32_CARRY)\n\t{\n\t\tregistersUsed->writtenGPR1 = op_r_r_s32_carry.regR;\n\t\tregistersUsed->readGPR1 = op_r_r_s32_carry.regA;\n\t\t// some operations read carry\n\t\tswitch (operation)\n\t\t{\n\t\tcase PPCREC_IML_OP_ADD_WITH_CARRY:\n\t\t\tregistersUsed->readGPR2 = op_r_r_s32_carry.regCarry;\n\t\t\tbreak;\n\t\tcase PPCREC_IML_OP_ADD:\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\t// carry is always written\n\t\tregistersUsed->writtenGPR2 = op_r_r_s32_carry.regCarry;\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_R_R)\n\t{\n\t\t// in all cases result is written and other operands are read only\n\t\t// with the exception of XOR, where if regA == regB then all bits are zeroed out. So we don't consider it a read\n\t\tregistersUsed->writtenGPR1 = op_r_r_r.regR;\n\t\tif(!(operation == PPCREC_IML_OP_XOR && op_r_r_r.regA == op_r_r_r.regB))\n\t\t{\n\t\t\tregistersUsed->readGPR1 = op_r_r_r.regA;\n\t\t\tregistersUsed->readGPR2 = op_r_r_r.regB;\n\t\t}\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_R_R_CARRY)\n\t{\n\t\tregistersUsed->writtenGPR1 = op_r_r_r_carry.regR;\n\t\tregistersUsed->readGPR1 = op_r_r_r_carry.regA;\n\t\tregistersUsed->readGPR2 = op_r_r_r_carry.regB;\n\t\t// some operations read carry\n\t\tswitch (operation)\n\t\t{\n\t\tcase PPCREC_IML_OP_ADD_WITH_CARRY:\n\t\t\tregistersUsed->readGPR3 = op_r_r_r_carry.regCarry;\n\t\t\tbreak;\n\t\tcase PPCREC_IML_OP_ADD:\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\t// carry is always written\n\t\tregistersUsed->writtenGPR2 = op_r_r_r_carry.regCarry;\n\t}\n\telse if (type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK)\n\t{\n\t\t// no effect on registers\n\t}\n\telse if (type == PPCREC_IML_TYPE_NO_OP)\n\t{\n\t\t// no effect on registers\n\t}\n\telse if (type == PPCREC_IML_TYPE_MACRO)\n\t{\n\t\tif (operation == PPCREC_IML_MACRO_BL || operation == PPCREC_IML_MACRO_B_FAR || operation == PPCREC_IML_MACRO_LEAVE || operation == PPCREC_IML_MACRO_DEBUGBREAK || operation == PPCREC_IML_MACRO_COUNT_CYCLES || operation == PPCREC_IML_MACRO_HLE)\n\t\t{\n\t\t\t// no effect on registers\n\t\t}\n\t\telse if (operation == PPCREC_IML_MACRO_B_TO_REG)\n\t\t{\n\t\t\tcemu_assert_debug(op_macro.paramReg.IsValid());\n\t\t\tregistersUsed->readGPR1 = op_macro.paramReg;\n\t\t}\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse if (type == PPCREC_IML_TYPE_COMPARE)\n\t{\n\t\tregistersUsed->readGPR1 = op_compare.regA;\n\t\tregistersUsed->readGPR2 = op_compare.regB;\n\t\tregistersUsed->writtenGPR1 = op_compare.regR;\n\t}\n\telse if (type == PPCREC_IML_TYPE_COMPARE_S32)\n\t{\n\t\tregistersUsed->readGPR1 = op_compare_s32.regA;\n\t\tregistersUsed->writtenGPR1 = op_compare_s32.regR;\n\t}\n\telse if (type == PPCREC_IML_TYPE_CONDITIONAL_JUMP)\n\t{\n\t\tregistersUsed->readGPR1 = op_conditional_jump.registerBool;\n\t}\n\telse if (type == PPCREC_IML_TYPE_JUMP)\n\t{\n\t\t// no registers affected\n\t}\n\telse if (type == PPCREC_IML_TYPE_LOAD)\n\t{\n\t\tregistersUsed->writtenGPR1 = op_storeLoad.registerData;\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\tregistersUsed->readGPR1 = op_storeLoad.registerMem;\n\t}\n\telse if (type == PPCREC_IML_TYPE_LOAD_INDEXED)\n\t{\n\t\tregistersUsed->writtenGPR1 = op_storeLoad.registerData;\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\tregistersUsed->readGPR1 = op_storeLoad.registerMem;\n\t\tif (op_storeLoad.registerMem2.IsValid())\n\t\t\tregistersUsed->readGPR2 = op_storeLoad.registerMem2;\n\t}\n\telse if (type == PPCREC_IML_TYPE_STORE)\n\t{\n\t\tregistersUsed->readGPR1 = op_storeLoad.registerData;\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\tregistersUsed->readGPR2 = op_storeLoad.registerMem;\n\t}\n\telse if (type == PPCREC_IML_TYPE_STORE_INDEXED)\n\t{\n\t\tregistersUsed->readGPR1 = op_storeLoad.registerData;\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\tregistersUsed->readGPR2 = op_storeLoad.registerMem;\n\t\tif (op_storeLoad.registerMem2.IsValid())\n\t\t\tregistersUsed->readGPR3 = op_storeLoad.registerMem2;\n\t}\n\telse if (type == PPCREC_IML_TYPE_ATOMIC_CMP_STORE)\n\t{\n\t\tregistersUsed->readGPR1 = op_atomic_compare_store.regEA;\n\t\tregistersUsed->readGPR2 = op_atomic_compare_store.regCompareValue;\n\t\tregistersUsed->readGPR3 = op_atomic_compare_store.regWriteValue;\n\t\tregistersUsed->writtenGPR1 = op_atomic_compare_store.regBoolOut;\n\t}\n\telse if (type == PPCREC_IML_TYPE_CALL_IMM)\n\t{\n\t\tif (op_call_imm.regParam0.IsValid())\n\t\t\tregistersUsed->readGPR1 = op_call_imm.regParam0;\n\t\tif (op_call_imm.regParam1.IsValid())\n\t\t\tregistersUsed->readGPR2 = op_call_imm.regParam1;\n\t\tif (op_call_imm.regParam2.IsValid())\n\t\t\tregistersUsed->readGPR3 = op_call_imm.regParam2;\n\t\tregistersUsed->writtenGPR1 = op_call_imm.regReturn;\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_LOAD)\n\t{\n\t\t// fpr load operation\n\t\tregistersUsed->writtenGPR1 = op_storeLoad.registerData;\n\t\t// address is in gpr register\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\tregistersUsed->readGPR1 = op_storeLoad.registerMem;\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED)\n\t{\n\t\t// fpr load operation\n\t\tregistersUsed->writtenGPR1 = op_storeLoad.registerData;\n\t\t// address is in gpr registers\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\tregistersUsed->readGPR1 = op_storeLoad.registerMem;\n\t\tif (op_storeLoad.registerMem2.IsValid())\n\t\t\tregistersUsed->readGPR2 = op_storeLoad.registerMem2;\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_STORE)\n\t{\n\t\t// fpr store operation\n\t\tregistersUsed->readGPR1 = op_storeLoad.registerData;\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\tregistersUsed->readGPR2 = op_storeLoad.registerMem;\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_STORE_INDEXED)\n\t{\n\t\t// fpr store operation\n\t\tregistersUsed->readGPR1 = op_storeLoad.registerData;\n\t\t// address is in gpr registers\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\tregistersUsed->readGPR2 = op_storeLoad.registerMem;\n\t\tif (op_storeLoad.registerMem2.IsValid())\n\t\t\tregistersUsed->readGPR3 = op_storeLoad.registerMem2;\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_R_R)\n\t{\n\t\t// fpr operation\n\t\tif (\n\t\t\toperation == PPCREC_IML_OP_FPR_ASSIGN ||\n\t\t\toperation == PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64 ||\n\t\t\toperation == PPCREC_IML_OP_FPR_FCTIWZ\n\t\t\t)\n\t\t{\n\t\t\tregistersUsed->readGPR1 = op_fpr_r_r.regA;\n\t\t\tregistersUsed->writtenGPR1 = op_fpr_r_r.regR;\n\t\t}\n\t\telse if (operation == PPCREC_IML_OP_FPR_MULTIPLY ||\n\t\t\toperation == PPCREC_IML_OP_FPR_DIVIDE ||\n\t\t\toperation == PPCREC_IML_OP_FPR_ADD ||\n\t\t\toperation == PPCREC_IML_OP_FPR_SUB)\n\t\t{\n\t\t\tregistersUsed->readGPR1 = op_fpr_r_r.regA;\n\t\t\tregistersUsed->readGPR2 = op_fpr_r_r.regR;\n\t\t\tregistersUsed->writtenGPR1 = op_fpr_r_r.regR;\n\n\t\t}\n\t\telse if (operation == PPCREC_IML_OP_FPR_FLOAT_TO_INT ||\n\t\t\toperation == PPCREC_IML_OP_FPR_INT_TO_FLOAT ||\n\t\t\toperation == PPCREC_IML_OP_FPR_BITCAST_INT_TO_FLOAT)\n\t\t{\n\t\t\tregistersUsed->writtenGPR1 = op_fpr_r_r.regR;\n\t\t\tregistersUsed->readGPR1 = op_fpr_r_r.regA;\n\t\t}\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_R_R_R)\n\t{\n\t\t// fpr operation\n\t\tregistersUsed->readGPR1 = op_fpr_r_r_r.regA;\n\t\tregistersUsed->readGPR2 = op_fpr_r_r_r.regB;\n\t\tregistersUsed->writtenGPR1 = op_fpr_r_r_r.regR;\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_R_R_R_R)\n\t{\n\t\t// fpr operation\n\t\tregistersUsed->readGPR1 = op_fpr_r_r_r_r.regA;\n\t\tregistersUsed->readGPR2 = op_fpr_r_r_r_r.regB;\n\t\tregistersUsed->readGPR3 = op_fpr_r_r_r_r.regC;\n\t\tregistersUsed->writtenGPR1 = op_fpr_r_r_r_r.regR;\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_R)\n\t{\n\t\t// fpr operation\n\t\tif (operation == PPCREC_IML_OP_FPR_NEGATE ||\n\t\t\toperation == PPCREC_IML_OP_FPR_ABS ||\n\t\t\toperation == PPCREC_IML_OP_FPR_NEGATIVE_ABS ||\n\t\t\toperation == PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64 ||\n\t\t\toperation == PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_BOTTOM)\n\t\t{\n\t\t\tregistersUsed->readGPR1 = op_fpr_r.regR;\n\t\t\tregistersUsed->writtenGPR1 = op_fpr_r.regR;\n\t\t}\n\t\telse if (operation == PPCREC_IML_OP_FPR_LOAD_ONE)\n\t\t{\n\t\t\tregistersUsed->writtenGPR1 = op_fpr_r.regR;\n\t\t}\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_COMPARE)\n\t{\n\t\tregistersUsed->writtenGPR1 = op_fpr_compare.regR;\n\t\tregistersUsed->readGPR1 = op_fpr_compare.regA;\n\t\tregistersUsed->readGPR2 = op_fpr_compare.regB;\n\t}\n\telse if (type == PPCREC_IML_TYPE_X86_EFLAGS_JCC)\n\t{\n\t\t// no registers read or written (except for the implicit eflags)\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n}\n\nIMLReg replaceRegisterIdMultiple(IMLReg reg, const std::unordered_map<IMLRegID, IMLRegID>& translationTable)\n{\n\tif (reg.IsInvalid())\n\t\treturn reg;\n\tconst auto& it = translationTable.find(reg.GetRegID());\n\tcemu_assert_debug(it != translationTable.cend());\n\tIMLReg alteredReg = reg;\n\talteredReg.SetRegID(it->second);\n\treturn alteredReg;\n}\n\nvoid IMLInstruction::RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& translationTable)\n{\n\tif (type == PPCREC_IML_TYPE_R_NAME)\n\t{\n\t\top_r_name.regR = replaceRegisterIdMultiple(op_r_name.regR, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_NAME_R)\n\t{\n\t\top_r_name.regR = replaceRegisterIdMultiple(op_r_name.regR, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_R)\n\t{\n\t\top_r_r.regR = replaceRegisterIdMultiple(op_r_r.regR, translationTable);\n\t\top_r_r.regA = replaceRegisterIdMultiple(op_r_r.regA, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_S32)\n\t{\n\t\top_r_immS32.regR = replaceRegisterIdMultiple(op_r_immS32.regR, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_R_S32)\n\t{\n\t\top_r_r_s32.regR = replaceRegisterIdMultiple(op_r_r_s32.regR, translationTable);\n\t\top_r_r_s32.regA = replaceRegisterIdMultiple(op_r_r_s32.regA, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_R_S32_CARRY)\n\t{\n\t\top_r_r_s32_carry.regR = replaceRegisterIdMultiple(op_r_r_s32_carry.regR, translationTable);\n\t\top_r_r_s32_carry.regA = replaceRegisterIdMultiple(op_r_r_s32_carry.regA, translationTable);\n\t\top_r_r_s32_carry.regCarry = replaceRegisterIdMultiple(op_r_r_s32_carry.regCarry, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_R_R)\n\t{\n\t\top_r_r_r.regR = replaceRegisterIdMultiple(op_r_r_r.regR, translationTable);\n\t\top_r_r_r.regA = replaceRegisterIdMultiple(op_r_r_r.regA, translationTable);\n\t\top_r_r_r.regB = replaceRegisterIdMultiple(op_r_r_r.regB, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_R_R_R_CARRY)\n\t{\n\t\top_r_r_r_carry.regR = replaceRegisterIdMultiple(op_r_r_r_carry.regR, translationTable);\n\t\top_r_r_r_carry.regA = replaceRegisterIdMultiple(op_r_r_r_carry.regA, translationTable);\n\t\top_r_r_r_carry.regB = replaceRegisterIdMultiple(op_r_r_r_carry.regB, translationTable);\n\t\top_r_r_r_carry.regCarry = replaceRegisterIdMultiple(op_r_r_r_carry.regCarry, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_COMPARE)\n\t{\n\t\top_compare.regR = replaceRegisterIdMultiple(op_compare.regR, translationTable);\n\t\top_compare.regA = replaceRegisterIdMultiple(op_compare.regA, translationTable);\n\t\top_compare.regB = replaceRegisterIdMultiple(op_compare.regB, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_COMPARE_S32)\n\t{\n\t\top_compare_s32.regR = replaceRegisterIdMultiple(op_compare_s32.regR, translationTable);\n\t\top_compare_s32.regA = replaceRegisterIdMultiple(op_compare_s32.regA, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_CONDITIONAL_JUMP)\n\t{\n\t\top_conditional_jump.registerBool = replaceRegisterIdMultiple(op_conditional_jump.registerBool, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK || type == PPCREC_IML_TYPE_JUMP)\n\t{\n\t\t// no effect on registers\n\t}\n\telse if (type == PPCREC_IML_TYPE_NO_OP)\n\t{\n\t\t// no effect on registers\n\t}\n\telse if (type == PPCREC_IML_TYPE_MACRO)\n\t{\n\t\tif (operation == PPCREC_IML_MACRO_BL || operation == PPCREC_IML_MACRO_B_FAR || operation == PPCREC_IML_MACRO_LEAVE || operation == PPCREC_IML_MACRO_DEBUGBREAK || operation == PPCREC_IML_MACRO_HLE || operation == PPCREC_IML_MACRO_COUNT_CYCLES)\n\t\t{\n\t\t\t// no effect on registers\n\t\t}\n\t\telse if (operation == PPCREC_IML_MACRO_B_TO_REG)\n\t\t{\n\t\t\top_macro.paramReg = replaceRegisterIdMultiple(op_macro.paramReg, translationTable);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\telse if (type == PPCREC_IML_TYPE_LOAD)\n\t{\n\t\top_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t{\n\t\t\top_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);\n\t\t}\n\t}\n\telse if (type == PPCREC_IML_TYPE_LOAD_INDEXED)\n\t{\n\t\top_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\top_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);\n\t\tif (op_storeLoad.registerMem2.IsValid())\n\t\t\top_storeLoad.registerMem2 = replaceRegisterIdMultiple(op_storeLoad.registerMem2, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_STORE)\n\t{\n\t\top_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\top_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_STORE_INDEXED)\n\t{\n\t\top_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);\n\t\tif (op_storeLoad.registerMem.IsValid())\n\t\t\top_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);\n\t\tif (op_storeLoad.registerMem2.IsValid())\n\t\t\top_storeLoad.registerMem2 = replaceRegisterIdMultiple(op_storeLoad.registerMem2, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_ATOMIC_CMP_STORE)\n\t{\n\t\top_atomic_compare_store.regEA = replaceRegisterIdMultiple(op_atomic_compare_store.regEA, translationTable);\n\t\top_atomic_compare_store.regCompareValue = replaceRegisterIdMultiple(op_atomic_compare_store.regCompareValue, translationTable);\n\t\top_atomic_compare_store.regWriteValue = replaceRegisterIdMultiple(op_atomic_compare_store.regWriteValue, translationTable);\n\t\top_atomic_compare_store.regBoolOut = replaceRegisterIdMultiple(op_atomic_compare_store.regBoolOut, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_CALL_IMM)\n\t{\n\t\top_call_imm.regReturn = replaceRegisterIdMultiple(op_call_imm.regReturn, translationTable);\n\t\tif (op_call_imm.regParam0.IsValid())\n\t\t\top_call_imm.regParam0 = replaceRegisterIdMultiple(op_call_imm.regParam0, translationTable);\n\t\tif (op_call_imm.regParam1.IsValid())\n\t\t\top_call_imm.regParam1 = replaceRegisterIdMultiple(op_call_imm.regParam1, translationTable);\n\t\tif (op_call_imm.regParam2.IsValid())\n\t\t\top_call_imm.regParam2 = replaceRegisterIdMultiple(op_call_imm.regParam2, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_LOAD)\n\t{\n\t\top_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);\n\t\top_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED)\n\t{\n\t\top_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);\n\t\top_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);\n\t\top_storeLoad.registerMem2 = replaceRegisterIdMultiple(op_storeLoad.registerMem2, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_STORE)\n\t{\n\t\top_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);\n\t\top_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_STORE_INDEXED)\n\t{\n\t\top_storeLoad.registerData = replaceRegisterIdMultiple(op_storeLoad.registerData, translationTable);\n\t\top_storeLoad.registerMem = replaceRegisterIdMultiple(op_storeLoad.registerMem, translationTable);\n\t\top_storeLoad.registerMem2 = replaceRegisterIdMultiple(op_storeLoad.registerMem2, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_R)\n\t{\n\t\top_fpr_r.regR = replaceRegisterIdMultiple(op_fpr_r.regR, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_R_R)\n\t{\n\t\top_fpr_r_r.regR = replaceRegisterIdMultiple(op_fpr_r_r.regR, translationTable);\n\t\top_fpr_r_r.regA = replaceRegisterIdMultiple(op_fpr_r_r.regA, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_R_R_R)\n\t{\n\t\top_fpr_r_r_r.regR = replaceRegisterIdMultiple(op_fpr_r_r_r.regR, translationTable);\n\t\top_fpr_r_r_r.regA = replaceRegisterIdMultiple(op_fpr_r_r_r.regA, translationTable);\n\t\top_fpr_r_r_r.regB = replaceRegisterIdMultiple(op_fpr_r_r_r.regB, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_R_R_R_R)\n\t{\n\t\top_fpr_r_r_r_r.regR = replaceRegisterIdMultiple(op_fpr_r_r_r_r.regR, translationTable);\n\t\top_fpr_r_r_r_r.regA = replaceRegisterIdMultiple(op_fpr_r_r_r_r.regA, translationTable);\n\t\top_fpr_r_r_r_r.regB = replaceRegisterIdMultiple(op_fpr_r_r_r_r.regB, translationTable);\n\t\top_fpr_r_r_r_r.regC = replaceRegisterIdMultiple(op_fpr_r_r_r_r.regC, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_FPR_COMPARE)\n\t{\n\t\top_fpr_compare.regA = replaceRegisterIdMultiple(op_fpr_compare.regA, translationTable);\n\t\top_fpr_compare.regB = replaceRegisterIdMultiple(op_fpr_compare.regB, translationTable);\n\t\top_fpr_compare.regR = replaceRegisterIdMultiple(op_fpr_compare.regR, translationTable);\n\t}\n\telse if (type == PPCREC_IML_TYPE_X86_EFLAGS_JCC)\n\t{\n\t\t// no registers read or written (except for the implicit eflags)\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h",
    "content": "#pragma once\n\nusing IMLRegID = uint16; // 16 bit ID\nusing IMLPhysReg = sint32; // arbitrary value that is up to the architecture backend, usually this will be the register index. A value of -1 is reserved and means not assigned\n\n// format of IMLReg:\n// 0-15\t\t(16 bit)\tIMLRegID\n// 19-23\t(5 bit)\t\tOffset\t\t\t\tIn elements, for SIMD registers\n// 24-27\t(4 bit)\t\tIMLRegFormat\t\tRegFormat\n// 28-31\t(4 bit)\t\tIMLRegFormat\t\tBaseFormat\n\nenum class IMLRegFormat : uint8\n{\n\tINVALID_FORMAT,\n\tI64,\n\tI32,\n\tI16,\n\tI8,\n\t// I1 ?\n\tF64,\n\tF32,\n\tTYPE_COUNT,\n};\n\nclass IMLReg\n{\npublic:\n\tIMLReg()\n\t{\n\t\tm_raw = 0; // 0 is invalid\n\t}\n\n\tIMLReg(IMLRegFormat baseRegFormat, IMLRegFormat regFormat, uint8 viewOffset, IMLRegID regId)\n\t{\n\t\tm_raw = 0;\n\t\tm_raw |= ((uint8)baseRegFormat << 28);\n\t\tm_raw |= ((uint8)regFormat << 24);\n\t\tm_raw |= (uint32)regId;\n\t}\n\n\tIMLReg(IMLReg&& baseReg, IMLRegFormat viewFormat, uint8 viewOffset, IMLRegID regId)\n\t{\n\t\tDEBUG_BREAK;\n\t\t//m_raw = 0;\n\t\t//m_raw |= ((uint8)baseRegFormat << 28);\n\t\t//m_raw |= ((uint8)viewFormat << 24);\n\t\t//m_raw |= (uint32)regId;\n\t}\n\n\tIMLReg(const IMLReg& other) : m_raw(other.m_raw) {}\n\n\tIMLRegFormat GetBaseFormat() const\n\t{\n\t\treturn (IMLRegFormat)((m_raw >> 28) & 0xF);\n\t}\n\n\tIMLRegFormat GetRegFormat() const\n\t{\n\t\treturn (IMLRegFormat)((m_raw >> 24) & 0xF);\n\t}\n\n\tIMLRegID GetRegID() const\n\t{\n\t\tcemu_assert_debug(GetBaseFormat() != IMLRegFormat::INVALID_FORMAT);\n\t\tcemu_assert_debug(GetRegFormat() != IMLRegFormat::INVALID_FORMAT);\n\t\treturn (IMLRegID)(m_raw & 0xFFFF);\n\t}\n\n\tvoid SetRegID(IMLRegID regId)\n\t{\n\t\tcemu_assert_debug(regId <= 0xFFFF);\n\t\tm_raw &= ~0xFFFF;\n\t\tm_raw |= (uint32)regId;\n\t}\n\n\tbool IsInvalid() const\n\t{\n\t\treturn GetBaseFormat() == IMLRegFormat::INVALID_FORMAT;\n\t}\n\n\tbool IsValid() const\n\t{\n\t\treturn GetBaseFormat() != IMLRegFormat::INVALID_FORMAT;\n\t}\n\n\tbool IsValidAndSameRegID(IMLRegID regId) const\n\t{\n\t\treturn IsValid() && GetRegID() == regId;\n\t}\n\n\t// compare all fields\n\tbool operator==(const IMLReg& other) const\n\t{\n\t\treturn m_raw == other.m_raw;\n\t}\n\nprivate:\n\tuint32 m_raw;\n};\n\nstatic const IMLReg IMLREG_INVALID(IMLRegFormat::INVALID_FORMAT, IMLRegFormat::INVALID_FORMAT, 0, 0);\nstatic const IMLRegID IMLRegID_INVALID(0xFFFF);\n\nusing IMLName = uint32;\n\nenum\n{\n\tPPCREC_IML_OP_ASSIGN,\t\t\t// '=' operator\n\tPPCREC_IML_OP_ENDIAN_SWAP,\t\t// '=' operator with 32bit endian swap\n\tPPCREC_IML_OP_MULTIPLY_SIGNED,  // '*' operator (signed multiply)\n\tPPCREC_IML_OP_MULTIPLY_HIGH_UNSIGNED, // unsigned 64bit multiply, store only high 32bit-word of result\n\tPPCREC_IML_OP_MULTIPLY_HIGH_SIGNED, // signed 64bit multiply, store only high 32bit-word of result\n\tPPCREC_IML_OP_DIVIDE_SIGNED,\t// '/' operator (signed divide)\n\tPPCREC_IML_OP_DIVIDE_UNSIGNED,\t// '/' operator (unsigned divide)\n\n\t// binary operation\n\tPPCREC_IML_OP_OR,\t\t\t\t// '|' operator\n\tPPCREC_IML_OP_AND,\t\t\t\t// '&' operator\n\tPPCREC_IML_OP_XOR,\t\t\t\t// '^' operator\n\tPPCREC_IML_OP_LEFT_ROTATE,\t\t// left rotate operator\n\tPPCREC_IML_OP_LEFT_SHIFT,\t\t// shift left operator\n\tPPCREC_IML_OP_RIGHT_SHIFT_U,\t// right shift operator (unsigned)\n\tPPCREC_IML_OP_RIGHT_SHIFT_S,\t// right shift operator (signed)\n\t// ppc\n\tPPCREC_IML_OP_SLW,\t\t\t\t// SLW (shift based on register by up to 63 bits)\n\tPPCREC_IML_OP_SRW,\t\t\t\t// SRW (shift based on register by up to 63 bits)\n\tPPCREC_IML_OP_CNTLZW,\n\t// FPU\n\tPPCREC_IML_OP_FPR_ASSIGN,\n\tPPCREC_IML_OP_FPR_LOAD_ONE, // load constant 1.0 into register\n\tPPCREC_IML_OP_FPR_ADD,\n\tPPCREC_IML_OP_FPR_SUB,\n\tPPCREC_IML_OP_FPR_MULTIPLY,\n\tPPCREC_IML_OP_FPR_DIVIDE,\n\tPPCREC_IML_OP_FPR_EXPAND_F32_TO_F64, // expand f32 to f64 in-place\n\tPPCREC_IML_OP_FPR_NEGATE,\n\tPPCREC_IML_OP_FPR_ABS, // abs(fpr)\n\tPPCREC_IML_OP_FPR_NEGATIVE_ABS, // -abs(fpr)\n\tPPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_BOTTOM, // round 64bit double to 64bit double with 32bit float precision (in bottom half of xmm register)\n\tPPCREC_IML_OP_FPR_FCTIWZ,\n\tPPCREC_IML_OP_FPR_SELECT, // selectively copy bottom value from operand B or C based on value in operand A\n\t// Conversion (FPR_R_R)\n\tPPCREC_IML_OP_FPR_INT_TO_FLOAT, // convert integer value in gpr to floating point value in fpr\n\tPPCREC_IML_OP_FPR_FLOAT_TO_INT, // convert floating point value in fpr to integer value in gpr\n\n\t// Bitcast (FPR_R_R)\n\tPPCREC_IML_OP_FPR_BITCAST_INT_TO_FLOAT,\n\n\t// R_R_R + R_R_S32\n\tPPCREC_IML_OP_ADD, // also R_R_R_CARRY\n\tPPCREC_IML_OP_SUB,\n\n\t// R_R only\n\tPPCREC_IML_OP_NOT,\n\tPPCREC_IML_OP_NEG,\n\tPPCREC_IML_OP_ASSIGN_S16_TO_S32,\n\tPPCREC_IML_OP_ASSIGN_S8_TO_S32,\n\n\t// R_R_R_carry\n\tPPCREC_IML_OP_ADD_WITH_CARRY, // similar to ADD but also adds carry bit (0 or 1)\n\n\t// X86 extension\n\tPPCREC_IML_OP_X86_CMP, // R_R and R_S32\n\n\tPPCREC_IML_OP_INVALID\n};\n\n#define PPCREC_IML_OP_FPR_COPY_PAIR (PPCREC_IML_OP_ASSIGN)\n\nenum\n{\n\tPPCREC_IML_MACRO_B_TO_REG,\t\t// branch to PPC address in register (used for BCCTR, BCLR)\n\n\tPPCREC_IML_MACRO_BL,\t\t\t// call to different function (can be within same function)\n\tPPCREC_IML_MACRO_B_FAR,\t\t\t// branch to different function\n\tPPCREC_IML_MACRO_COUNT_CYCLES,\t// decrease current remaining thread cycles by a certain amount\n\tPPCREC_IML_MACRO_HLE,\t\t\t// HLE function call\n\tPPCREC_IML_MACRO_LEAVE,\t\t\t// leaves recompiler and switches to interpeter\n\t// debugging\n\tPPCREC_IML_MACRO_DEBUGBREAK,\t// throws a debugbreak\n};\n\nenum class IMLCondition : uint8\n{\n\tEQ,\n\tNEQ,\n\tSIGNED_GT,\n\tSIGNED_LT,\n\tUNSIGNED_GT,\n\tUNSIGNED_LT,\n\n\t// floating point conditions\n\tUNORDERED_GT, // a > b, false if either is NaN\n\tUNORDERED_LT, // a < b, false if either is NaN\n\tUNORDERED_EQ, // a == b, false if either is NaN\n\tUNORDERED_U, // unordered (true if either operand is NaN)\n\n\tORDERED_GT,\n\tORDERED_LT,\n\tORDERED_EQ,\n\tORDERED_U\n};\n\nenum\n{\n\tPPCREC_IML_TYPE_NONE,\n\tPPCREC_IML_TYPE_NO_OP,\t\t\t\t// no-op instruction\n\tPPCREC_IML_TYPE_R_R,\t\t\t\t// r* = (op) *r\t\t\t(can also be r* (op) *r) \n\tPPCREC_IML_TYPE_R_R_R,\t\t\t\t// r* = r* (op) r*\n\tPPCREC_IML_TYPE_R_R_R_CARRY,\t\t// r* = r* (op) r*\t\t(reads and/or updates carry)\n\tPPCREC_IML_TYPE_R_R_S32,\t\t\t// r* = r* (op) s32*\n\tPPCREC_IML_TYPE_R_R_S32_CARRY,\t\t// r* = r* (op) s32*\t(reads and/or updates carry)\n\tPPCREC_IML_TYPE_LOAD,\t\t\t\t// r* = [r*+s32*]\n\tPPCREC_IML_TYPE_LOAD_INDEXED,\t\t// r* = [r*+r*]\n\tPPCREC_IML_TYPE_STORE,\t\t\t\t// [r*+s32*] = r*\n\tPPCREC_IML_TYPE_STORE_INDEXED,\t\t// [r*+r*] = r*\n\tPPCREC_IML_TYPE_R_NAME,\t\t\t\t// r* = name\n\tPPCREC_IML_TYPE_NAME_R,\t\t\t\t// name* = r*\n\tPPCREC_IML_TYPE_R_S32,\t\t\t\t// r* (op) imm\n\tPPCREC_IML_TYPE_MACRO,\n\tPPCREC_IML_TYPE_CJUMP_CYCLE_CHECK,\t// jumps only if remaining thread cycles < 0\n\n\t// conditions and branches\n\tPPCREC_IML_TYPE_COMPARE,\t\t\t// r* = r* CMP[cond] r*\n\tPPCREC_IML_TYPE_COMPARE_S32,\t\t// r* = r* CMP[cond] imm\n\tPPCREC_IML_TYPE_JUMP,\t\t\t\t// jump always\n\tPPCREC_IML_TYPE_CONDITIONAL_JUMP,\t// jump conditionally based on boolean value in register\n\n\t// atomic\n\tPPCREC_IML_TYPE_ATOMIC_CMP_STORE,\n\n\t// function call\n\tPPCREC_IML_TYPE_CALL_IMM,\t\t\t// call to fixed immediate address\n\n\t// FPR\n\tPPCREC_IML_TYPE_FPR_LOAD,\t\t\t// r* = (bitdepth) [r*+s32*] (single or paired single mode)\n\tPPCREC_IML_TYPE_FPR_LOAD_INDEXED,\t// r* = (bitdepth) [r*+r*] (single or paired single mode)\n\tPPCREC_IML_TYPE_FPR_STORE,\t\t\t// (bitdepth) [r*+s32*] = r* (single or paired single mode)\n\tPPCREC_IML_TYPE_FPR_STORE_INDEXED,\t// (bitdepth) [r*+r*] = r* (single or paired single mode)\n\tPPCREC_IML_TYPE_FPR_R_R,\n\tPPCREC_IML_TYPE_FPR_R_R_R,\n\tPPCREC_IML_TYPE_FPR_R_R_R_R,\n\tPPCREC_IML_TYPE_FPR_R,\n\n\tPPCREC_IML_TYPE_FPR_COMPARE,\t\t// r* = r* CMP[cond] r*\n\n\t// X86 specific\n\tPPCREC_IML_TYPE_X86_EFLAGS_JCC,\n};\n\nenum // IMLName\n{\n\tPPCREC_NAME_NONE,\n\tPPCREC_NAME_TEMPORARY = 1000,\n\tPPCREC_NAME_R0 = 2000,\n\tPPCREC_NAME_SPR0 = 3000,\n\tPPCREC_NAME_FPR_HALF = 4800, // Counts PS0 and PS1 separately. E.g. fp3.ps1 is at offset 3 * 2 + 1\n\tPPCREC_NAME_TEMPORARY_FPR0 = 5000, // 0 to 7\n\tPPCREC_NAME_XER_CA = 6000, // carry bit from XER\n\tPPCREC_NAME_XER_OV = 6001, // overflow bit from XER\n\tPPCREC_NAME_XER_SO = 6002, // summary overflow bit from XER\n\tPPCREC_NAME_CR = 7000, // CR register bits (31 to 0)\n\tPPCREC_NAME_CR_LAST = PPCREC_NAME_CR+31,\n\tPPCREC_NAME_CPU_MEMRES_EA = 8000,\n\tPPCREC_NAME_CPU_MEMRES_VAL = 8001\n};\n\n#define PPC_REC_INVALID_REGISTER\t0xFF\t// deprecated. Use IMLREG_INVALID instead\n\nenum\n{\n\t// fpr load\n\tPPCREC_FPR_LD_MODE_SINGLE,\n\tPPCREC_FPR_LD_MODE_DOUBLE,\n\n\t// fpr store\n\tPPCREC_FPR_ST_MODE_SINGLE,\n\tPPCREC_FPR_ST_MODE_DOUBLE,\n\n\tPPCREC_FPR_ST_MODE_UI32_FROM_PS0, // store raw low-32bit of PS0\n};\n\nstruct IMLUsedRegisters\n{\n\tIMLUsedRegisters() {};\n\n\tbool IsWrittenByRegId(IMLRegID regId) const\n\t{\n\t\tif (writtenGPR1.IsValid() && writtenGPR1.GetRegID() == regId)\n\t\t\treturn true;\n\t\tif (writtenGPR2.IsValid() && writtenGPR2.GetRegID() == regId)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\tbool IsBaseGPRWritten(IMLReg imlReg) const\n\t{\n\t\tcemu_assert_debug(imlReg.IsValid());\n\t\tauto regId = imlReg.GetRegID();\n\t\treturn IsWrittenByRegId(regId);\n\t}\n\n\ttemplate<typename Fn>\n\tvoid ForEachWrittenGPR(Fn F) const\n\t{\n\t\tif (writtenGPR1.IsValid())\n\t\t\tF(writtenGPR1);\n\t\tif (writtenGPR2.IsValid())\n\t\t\tF(writtenGPR2);\n\t}\n\n\ttemplate<typename Fn>\n\tvoid ForEachReadGPR(Fn F) const\n\t{\n\t\tif (readGPR1.IsValid())\n\t\t\tF(readGPR1);\n\t\tif (readGPR2.IsValid())\n\t\t\tF(readGPR2);\n\t\tif (readGPR3.IsValid())\n\t\t\tF(readGPR3);\n\t\tif (readGPR4.IsValid())\n\t\t\tF(readGPR4);\n\t}\n\n\ttemplate<typename Fn>\n\tvoid ForEachAccessedGPR(Fn F) const\n\t{\n\t\t// GPRs\n\t\tif (readGPR1.IsValid())\n\t\t\tF(readGPR1, false);\n\t\tif (readGPR2.IsValid())\n\t\t\tF(readGPR2, false);\n\t\tif (readGPR3.IsValid())\n\t\t\tF(readGPR3, false);\n\t\tif (readGPR4.IsValid())\n\t\t\tF(readGPR4, false);\n\t\tif (writtenGPR1.IsValid())\n\t\t\tF(writtenGPR1, true);\n\t\tif (writtenGPR2.IsValid())\n\t\t\tF(writtenGPR2, true);\n\t}\n\n\tIMLReg readGPR1;\n\tIMLReg readGPR2;\n\tIMLReg readGPR3;\n\tIMLReg readGPR4;\n\tIMLReg writtenGPR1;\n\tIMLReg writtenGPR2;\n};\n\nstruct IMLInstruction\n{\n\tIMLInstruction() {}\n\tIMLInstruction(const IMLInstruction& other) \n\t{\n\t\tmemcpy(this, &other, sizeof(IMLInstruction));\n\t}\n\n\tuint8 type;\n\tuint8 operation;\n\tunion\n\t{\n\t\tstruct\n\t\t{\n\t\t\tuint8 _padding[7];\n\t\t}padding;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t\tIMLReg regA;\n\t\t}op_r_r;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t\tIMLReg regA;\n\t\t\tIMLReg regB;\n\t\t}op_r_r_r;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t\tIMLReg regA;\n\t\t\tIMLReg regB;\n\t\t\tIMLReg regCarry;\n\t\t}op_r_r_r_carry;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t\tIMLReg regA;\n\t\t\tsint32 immS32;\n\t\t}op_r_r_s32;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t\tIMLReg regA;\n\t\t\tIMLReg regCarry;\n\t\t\tsint32 immS32;\n\t\t}op_r_r_s32_carry;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t\tIMLName name;\n\t\t}op_r_name; // alias op_name_r\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t\tsint32 immS32;\n\t\t}op_r_immS32;\n\t\tstruct\n\t\t{\n\t\t\tuint32 param;\n\t\t\tuint32 param2;\n\t\t\tuint16 paramU16;\n\t\t\tIMLReg paramReg;\n\t\t}op_macro;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg registerData;\n\t\t\tIMLReg registerMem;\n\t\t\tIMLReg registerMem2;\n\t\t\tuint8 copyWidth;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tbool swapEndian : 1;\n\t\t\t\tbool signExtend : 1;\n\t\t\t\tbool notExpanded : 1; // for floats\n\t\t\t}flags2;\n\t\t\tuint8 mode; // transfer mode\n\t\t\tsint32 immS32;\n\t\t}op_storeLoad;\n\t\tstruct\n\t\t{\n\t\t\tuintptr_t callAddress;\n\t\t\tIMLReg regParam0;\n\t\t\tIMLReg regParam1;\n\t\t\tIMLReg regParam2;\n\t\t\tIMLReg regReturn;\n\t\t}op_call_imm;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t\tIMLReg regA;\n\t\t}op_fpr_r_r;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t\tIMLReg regA;\n\t\t\tIMLReg regB;\n\t\t}op_fpr_r_r_r;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t\tIMLReg regA;\n\t\t\tIMLReg regB;\n\t\t\tIMLReg regC;\n\t\t}op_fpr_r_r_r_r;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR;\n\t\t}op_fpr_r;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR; // stores the boolean result of the comparison\n\t\t\tIMLReg regA;\n\t\t\tIMLReg regB;\n\t\t\tIMLCondition cond;\n\t\t}op_fpr_compare;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR; // stores the boolean result of the comparison\n\t\t\tIMLReg regA;\n\t\t\tIMLReg regB;\n\t\t\tIMLCondition cond;\n\t\t}op_compare;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg regR; // stores the boolean result of the comparison\n\t\t\tIMLReg regA;\n\t\t\tsint32 immS32;\n\t\t\tIMLCondition cond;\n\t\t}op_compare_s32;\n\t\tstruct\n\t\t{\n\t\t\tIMLReg registerBool;\n\t\t\tbool mustBeTrue;\n\t\t}op_conditional_jump;\n\t\tstruct  \n\t\t{\n\t\t\tIMLReg regEA;\n\t\t\tIMLReg regCompareValue;\n\t\t\tIMLReg regWriteValue;\n\t\t\tIMLReg regBoolOut;\n\t\t}op_atomic_compare_store;\n\t\t// conditional operations (emitted if supported by target platform)\n\t\tstruct\n\t\t{\n\t\t\t// r_s32\n\t\t\tIMLReg regR;\n\t\t\tsint32 immS32;\n\t\t\t// condition\n\t\t\tuint8 crRegisterIndex;\n\t\t\tuint8 crBitIndex;\n\t\t\tbool  bitMustBeSet;\n\t\t}op_conditional_r_s32;\n\t\t// X86 specific\n\t\tstruct\n\t\t{\n\t\t\tIMLCondition cond;\n\t\t\tbool invertedCondition;\n\t\t}op_x86_eflags_jcc;\n\t};\n\n\tbool IsSuffixInstruction() const\n\t{\n\t\tif (type == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_BL ||\n\t\t\ttype == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_B_FAR ||\n\t\t\ttype == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_B_TO_REG ||\n\t\t\ttype == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_LEAVE ||\n\t\t\ttype == PPCREC_IML_TYPE_MACRO && operation == PPCREC_IML_MACRO_HLE ||\n\t\t\ttype == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK ||\n\t\t\ttype == PPCREC_IML_TYPE_JUMP ||\n\t\t\ttype == PPCREC_IML_TYPE_CONDITIONAL_JUMP ||\n\t\t\ttype == PPCREC_IML_TYPE_X86_EFLAGS_JCC)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\t// instruction setters\n\tvoid make_no_op()\n\t{\n\t\ttype = PPCREC_IML_TYPE_NO_OP;\n\t\toperation = 0;\n\t}\n\n\tvoid make_r_name(IMLReg regR, IMLName name)\n\t{\n\t\tcemu_assert_debug(regR.GetBaseFormat() == regR.GetRegFormat()); // for name load/store instructions the register must match the base format\n\t\ttype = PPCREC_IML_TYPE_R_NAME;\n\t\toperation = PPCREC_IML_OP_ASSIGN;\n\t\top_r_name.regR = regR;\n\t\top_r_name.name = name;\n\t}\n\n\tvoid make_name_r(IMLName name, IMLReg regR)\n\t{\n\t\tcemu_assert_debug(regR.GetBaseFormat() == regR.GetRegFormat()); // for name load/store instructions the register must match the base format\n\t\ttype = PPCREC_IML_TYPE_NAME_R;\n\t\toperation = PPCREC_IML_OP_ASSIGN;\n\t\top_r_name.regR = regR;\n\t\top_r_name.name = name;\n\t}\n\n\tvoid make_debugbreak(uint32 currentPPCAddress = 0)\n\t{\n\t\tmake_macro(PPCREC_IML_MACRO_DEBUGBREAK, 0, currentPPCAddress, 0, IMLREG_INVALID);\n\t}\n\n\tvoid make_macro(uint32 macroId, uint32 param, uint32 param2, uint16 paramU16, IMLReg regParam)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_MACRO;\n\t\tthis->operation = macroId;\n\t\tthis->op_macro.param = param;\n\t\tthis->op_macro.param2 = param2;\n\t\tthis->op_macro.paramU16 = paramU16;\n\t\tthis->op_macro.paramReg = regParam;\n\t}\n\n\tvoid make_cjump_cycle_check()\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK;\n\t\tthis->operation = 0;\n\t}\n\n\tvoid make_r_r(uint32 operation, IMLReg regR, IMLReg regA)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_R_R;\n\t\tthis->operation = operation;\n\t\tthis->op_r_r.regR = regR;\n\t\tthis->op_r_r.regA = regA;\n\t}\n\n\tvoid make_r_s32(uint32 operation, IMLReg regR, sint32 immS32)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_R_S32;\n\t\tthis->operation = operation;\n\t\tthis->op_r_immS32.regR = regR;\n\t\tthis->op_r_immS32.immS32 = immS32;\n\t}\n\n\tvoid make_r_r_r(uint32 operation, IMLReg regR, IMLReg regA, IMLReg regB)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_R_R_R;\n\t\tthis->operation = operation;\n\t\tthis->op_r_r_r.regR = regR;\n\t\tthis->op_r_r_r.regA = regA;\n\t\tthis->op_r_r_r.regB = regB;\n\t}\n\n\tvoid make_r_r_r_carry(uint32 operation, IMLReg regR, IMLReg regA, IMLReg regB, IMLReg regCarry)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_R_R_R_CARRY;\n\t\tthis->operation = operation;\n\t\tthis->op_r_r_r_carry.regR = regR;\n\t\tthis->op_r_r_r_carry.regA = regA;\n\t\tthis->op_r_r_r_carry.regB = regB;\n\t\tthis->op_r_r_r_carry.regCarry = regCarry;\n\t}\n\n\tvoid make_r_r_s32(uint32 operation, IMLReg regR, IMLReg regA, sint32 immS32)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_R_R_S32;\n\t\tthis->operation = operation;\n\t\tthis->op_r_r_s32.regR = regR;\n\t\tthis->op_r_r_s32.regA = regA;\n\t\tthis->op_r_r_s32.immS32 = immS32;\n\t}\n\n\tvoid make_r_r_s32_carry(uint32 operation, IMLReg regR, IMLReg regA, sint32 immS32, IMLReg regCarry)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_R_R_S32_CARRY;\n\t\tthis->operation = operation;\n\t\tthis->op_r_r_s32_carry.regR = regR;\n\t\tthis->op_r_r_s32_carry.regA = regA;\n\t\tthis->op_r_r_s32_carry.immS32 = immS32;\n\t\tthis->op_r_r_s32_carry.regCarry = regCarry;\n\t}\n\n\tvoid make_compare(IMLReg regA, IMLReg regB, IMLReg regR, IMLCondition cond)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_COMPARE;\n\t\tthis->operation = PPCREC_IML_OP_INVALID;\n\t\tthis->op_compare.regR = regR;\n\t\tthis->op_compare.regA = regA;\n\t\tthis->op_compare.regB = regB;\n\t\tthis->op_compare.cond = cond;\n\t}\n\n\tvoid make_compare_s32(IMLReg regA, sint32 immS32, IMLReg regR, IMLCondition cond)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_COMPARE_S32;\n\t\tthis->operation = PPCREC_IML_OP_INVALID;\n\t\tthis->op_compare_s32.regR = regR;\n\t\tthis->op_compare_s32.regA = regA;\n\t\tthis->op_compare_s32.immS32 = immS32;\n\t\tthis->op_compare_s32.cond = cond;\n\t}\n\n\tvoid make_conditional_jump(IMLReg regBool, bool mustBeTrue)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_CONDITIONAL_JUMP;\n\t\tthis->operation = PPCREC_IML_OP_INVALID;\n\t\tthis->op_conditional_jump.registerBool = regBool;\n\t\tthis->op_conditional_jump.mustBeTrue = mustBeTrue;\n\t}\n\n\tvoid make_jump()\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_JUMP;\n\t\tthis->operation = PPCREC_IML_OP_INVALID;\n\t}\n\n\t// load from memory\n\tvoid make_r_memory(IMLReg regD, IMLReg regMem, sint32 immS32, uint32 copyWidth, bool signExtend, bool switchEndian)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_LOAD;\n\t\tthis->operation = 0;\n\t\tthis->op_storeLoad.registerData = regD;\n\t\tthis->op_storeLoad.registerMem = regMem;\n\t\tthis->op_storeLoad.immS32 = immS32;\n\t\tthis->op_storeLoad.copyWidth = copyWidth;\n\t\tthis->op_storeLoad.flags2.swapEndian = switchEndian;\n\t\tthis->op_storeLoad.flags2.signExtend = signExtend;\n\t}\n\n\t// store to memory\n\tvoid make_memory_r(IMLReg regS, IMLReg regMem, sint32 immS32, uint32 copyWidth, bool switchEndian)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_STORE;\n\t\tthis->operation = 0;\n\t\tthis->op_storeLoad.registerData = regS;\n\t\tthis->op_storeLoad.registerMem = regMem;\n\t\tthis->op_storeLoad.immS32 = immS32;\n\t\tthis->op_storeLoad.copyWidth = copyWidth;\n\t\tthis->op_storeLoad.flags2.swapEndian = switchEndian;\n\t\tthis->op_storeLoad.flags2.signExtend = false;\n\t}\n\n\tvoid make_atomic_cmp_store(IMLReg regEA, IMLReg regCompareValue, IMLReg regWriteValue, IMLReg regSuccessOutput)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_ATOMIC_CMP_STORE;\n\t\tthis->operation = 0;\n\t\tthis->op_atomic_compare_store.regEA = regEA;\n\t\tthis->op_atomic_compare_store.regCompareValue = regCompareValue;\n\t\tthis->op_atomic_compare_store.regWriteValue = regWriteValue;\n\t\tthis->op_atomic_compare_store.regBoolOut = regSuccessOutput;\n\t}\n\n\tvoid make_call_imm(uintptr_t callAddress, IMLReg param0, IMLReg param1, IMLReg param2, IMLReg regReturn)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_CALL_IMM;\n\t\tthis->operation = 0;\n\t\tthis->op_call_imm.callAddress = callAddress;\n\t\tthis->op_call_imm.regParam0 = param0;\n\t\tthis->op_call_imm.regParam1 = param1;\n\t\tthis->op_call_imm.regParam2 = param2;\n\t\tthis->op_call_imm.regReturn = regReturn;\n\t}\n\n\t// FPR\n\n\t// load from memory\n\tvoid make_fpr_r_memory(IMLReg registerDestination, IMLReg registerMemory, sint32 immS32, uint32 mode, bool switchEndian)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_FPR_LOAD;\n\t\tthis->operation = 0;\n\t\tthis->op_storeLoad.registerData = registerDestination;\n\t\tthis->op_storeLoad.registerMem = registerMemory;\n\t\tthis->op_storeLoad.immS32 = immS32;\n\t\tthis->op_storeLoad.mode = mode;\n\t\tthis->op_storeLoad.flags2.swapEndian = switchEndian;\n\t}\n\n\tvoid make_fpr_r_memory_indexed(IMLReg registerDestination, IMLReg registerMemory1, IMLReg registerMemory2, uint32 mode, bool switchEndian)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_FPR_LOAD_INDEXED;\n\t\tthis->operation = 0;\n\t\tthis->op_storeLoad.registerData = registerDestination;\n\t\tthis->op_storeLoad.registerMem = registerMemory1;\n\t\tthis->op_storeLoad.registerMem2 = registerMemory2;\n\t\tthis->op_storeLoad.immS32 = 0;\n\t\tthis->op_storeLoad.mode = mode;\n\t\tthis->op_storeLoad.flags2.swapEndian = switchEndian;\n\t}\n\n\t// store to memory\n\tvoid make_fpr_memory_r(IMLReg registerSource, IMLReg registerMemory, sint32 immS32, uint32 mode, bool switchEndian)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_FPR_STORE;\n\t\tthis->operation = 0;\n\t\tthis->op_storeLoad.registerData = registerSource;\n\t\tthis->op_storeLoad.registerMem = registerMemory;\n\t\tthis->op_storeLoad.immS32 = immS32;\n\t\tthis->op_storeLoad.mode = mode;\n\t\tthis->op_storeLoad.flags2.swapEndian = switchEndian;\n\t}\n\n\tvoid make_fpr_memory_r_indexed(IMLReg registerSource, IMLReg registerMemory1, IMLReg registerMemory2, sint32 immS32, uint32 mode, bool switchEndian)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_FPR_STORE_INDEXED;\n\t\tthis->operation = 0;\n\t\tthis->op_storeLoad.registerData = registerSource;\n\t\tthis->op_storeLoad.registerMem = registerMemory1;\n\t\tthis->op_storeLoad.registerMem2 = registerMemory2;\n\t\tthis->op_storeLoad.immS32 = immS32;\n\t\tthis->op_storeLoad.mode = mode;\n\t\tthis->op_storeLoad.flags2.swapEndian = switchEndian;\n\t}\n\n\tvoid make_fpr_compare(IMLReg regA, IMLReg regB, IMLReg regR, IMLCondition cond)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_FPR_COMPARE;\n\t\tthis->operation = -999;\n\t\tthis->op_fpr_compare.regR = regR;\n\t\tthis->op_fpr_compare.regA = regA;\n\t\tthis->op_fpr_compare.regB = regB;\n\t\tthis->op_fpr_compare.cond = cond;\n\t}\n\n\tvoid make_fpr_r(sint32 operation, IMLReg registerResult)\n\t{\n\t\t// OP (fpr)\n\t\tthis->type = PPCREC_IML_TYPE_FPR_R;\n\t\tthis->operation = operation;\n\t\tthis->op_fpr_r.regR = registerResult;\n\t}\n\n\tvoid make_fpr_r_r(sint32 operation, IMLReg registerResult, IMLReg registerOperand, sint32 crRegister=PPC_REC_INVALID_REGISTER)\n\t{\n\t\t// fpr OP fpr\n\t\tthis->type = PPCREC_IML_TYPE_FPR_R_R;\n\t\tthis->operation = operation;\n\t\tthis->op_fpr_r_r.regR = registerResult;\n\t\tthis->op_fpr_r_r.regA = registerOperand;\n\t}\n\n\tvoid make_fpr_r_r_r(sint32 operation, IMLReg registerResult, IMLReg registerOperand1, IMLReg registerOperand2, sint32 crRegister=PPC_REC_INVALID_REGISTER)\n\t{\n\t\t// fpr = OP (fpr,fpr)\n\t\tthis->type = PPCREC_IML_TYPE_FPR_R_R_R;\n\t\tthis->operation = operation;\n\t\tthis->op_fpr_r_r_r.regR = registerResult;\n\t\tthis->op_fpr_r_r_r.regA = registerOperand1;\n\t\tthis->op_fpr_r_r_r.regB = registerOperand2;\n\t}\n\n\tvoid make_fpr_r_r_r_r(sint32 operation, IMLReg registerResult, IMLReg registerOperandA, IMLReg registerOperandB, IMLReg registerOperandC, sint32 crRegister=PPC_REC_INVALID_REGISTER)\n\t{\n\t\t// fpr = OP (fpr,fpr,fpr)\n\t\tthis->type = PPCREC_IML_TYPE_FPR_R_R_R_R;\n\t\tthis->operation = operation;\n\t\tthis->op_fpr_r_r_r_r.regR = registerResult;\n\t\tthis->op_fpr_r_r_r_r.regA = registerOperandA;\n\t\tthis->op_fpr_r_r_r_r.regB = registerOperandB;\n\t\tthis->op_fpr_r_r_r_r.regC = registerOperandC;\n\t}\n\n\t/* X86 specific */\n\tvoid make_x86_eflags_jcc(IMLCondition cond, bool invertedCondition)\n\t{\n\t\tthis->type = PPCREC_IML_TYPE_X86_EFLAGS_JCC;\n\t\tthis->operation = -999;\n\t\tthis->op_x86_eflags_jcc.cond = cond;\n\t\tthis->op_x86_eflags_jcc.invertedCondition = invertedCondition;\n\t}\n\n\tvoid CheckRegisterUsage(IMLUsedRegisters* registersUsed) const;\n\tbool HasSideEffects() const; // returns true if the instruction has side effects beyond just reading and writing registers. Dead code elimination uses this to know if an instruction can be dropped when the regular register outputs are not used\n\n\tvoid RewriteGPR(const std::unordered_map<IMLRegID, IMLRegID>& translationTable);\n};\n\n// architecture specific constants\nnamespace IMLArchX86\n{\n\tstatic constexpr int PHYSREG_GPR_BASE = 0;\n\tstatic constexpr int PHYSREG_FPR_BASE = 16;\n};"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLOptimizer.cpp",
    "content": "#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"Cafe/HW/Espresso/Recompiler/IML/IML.h\"\n#include \"Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h\"\n\n#include \"../PPCRecompiler.h\"\n#include \"../PPCRecompilerIml.h\"\n#include \"../BackendX64/BackendX64.h\"\n\n#include \"Common/FileStream.h\"\n\n#include <boost/container/static_vector.hpp>\n#include <boost/container/small_vector.hpp>\n\nIMLReg _FPRRegFromID(IMLRegID regId)\n{\n\treturn IMLReg(IMLRegFormat::F64, IMLRegFormat::F64, 0, regId);\n}\n\nvoid PPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 imlIndexLoad, IMLReg fprReg)\n{\n\tIMLRegID fprIndex = fprReg.GetRegID();\n\n\tIMLInstruction* imlInstructionLoad = imlSegment->imlList.data() + imlIndexLoad;\n\tif (imlInstructionLoad->op_storeLoad.flags2.notExpanded)\n\t\treturn;\n\tboost::container::static_vector<sint32, 4> trackedMoves; // only track up to 4 copies\n\tIMLUsedRegisters registersUsed;\n\tsint32 scanRangeEnd = std::min<sint32>(imlIndexLoad + 25, imlSegment->imlList.size()); // don't scan too far (saves performance and also the chances we can merge the load+store become low at high distances)\n\tbool foundMatch = false;\n\tsint32 lastStore = -1;\n\tfor (sint32 i = imlIndexLoad + 1; i < scanRangeEnd; i++)\n\t{\n\t\tIMLInstruction* imlInstruction = imlSegment->imlList.data() + i;\n\t\tif (imlInstruction->IsSuffixInstruction())\n\t\t\tbreak;\n\t\t// check if FPR is stored\n\t\tif ((imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE && imlInstruction->op_storeLoad.mode == PPCREC_FPR_ST_MODE_SINGLE) ||\n\t\t\t(imlInstruction->type == PPCREC_IML_TYPE_FPR_STORE_INDEXED && imlInstruction->op_storeLoad.mode == PPCREC_FPR_ST_MODE_SINGLE))\n\t\t{\n\t\t\tif (imlInstruction->op_storeLoad.registerData.GetRegID() == fprIndex)\n\t\t\t{\n\t\t\t\tif (foundMatch == false)\n\t\t\t\t{\n\t\t\t\t\t// flag the load-single instruction as \"don't expand\" (leave single value as-is)\n\t\t\t\t\timlInstructionLoad->op_storeLoad.flags2.notExpanded = true;\n\t\t\t\t}\n\t\t\t\t// also set the flag for the store instruction\n\t\t\t\tIMLInstruction* imlInstructionStore = imlInstruction;\n\t\t\t\timlInstructionStore->op_storeLoad.flags2.notExpanded = true;\n\n\t\t\t\tfoundMatch = true;\n\t\t\t\tlastStore = i + 1;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t// if the FPR is copied then keep track of it. We can expand the copies instead of the original\n\t\tif (imlInstruction->type == PPCREC_IML_TYPE_FPR_R_R && imlInstruction->operation == PPCREC_IML_OP_FPR_ASSIGN && imlInstruction->op_fpr_r_r.regA.GetRegID() == fprIndex)\n\t\t{\n\t\t\tif (imlInstruction->op_fpr_r_r.regR.GetRegID() == fprIndex)\n\t\t\t{\n\t\t\t\t// unexpected no-op\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (trackedMoves.size() >= trackedMoves.capacity())\n\t\t\t{\n\t\t\t\t// we cant track any more moves, expand here\n\t\t\t\tlastStore = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\ttrackedMoves.push_back(i);\n\t\t\tcontinue;\n\t\t}\n\t\t// check if FPR is overwritten\n\t\timlInstruction->CheckRegisterUsage(&registersUsed);\n\t\tif (registersUsed.writtenGPR1.IsValidAndSameRegID(fprIndex) || registersUsed.writtenGPR2.IsValidAndSameRegID(fprIndex))\n\t\t\tbreak;\n\t\tif (registersUsed.readGPR1.IsValidAndSameRegID(fprIndex))\n\t\t\tbreak;\n\t\tif (registersUsed.readGPR2.IsValidAndSameRegID(fprIndex))\n\t\t\tbreak;\n\t\tif (registersUsed.readGPR3.IsValidAndSameRegID(fprIndex))\n\t\t\tbreak;\n\t\tif (registersUsed.readGPR4.IsValidAndSameRegID(fprIndex))\n\t\t\tbreak;\n\t}\n\n\tif (foundMatch)\n\t{\n\t\t// insert expand instructions for each target register of a move\n\t\tsint32 positionBias = 0;\n\t\tfor (auto& trackedMove : trackedMoves)\n\t\t{\n\t\t\tsint32 realPosition = trackedMove + positionBias;\n\t\t\tIMLInstruction* imlMoveInstruction = imlSegment->imlList.data() + realPosition;\n\t\t\tif (realPosition >= lastStore)\n\t\t\t\tbreak; // expand is inserted before this move\n\t\t\telse\n\t\t\t\tlastStore++;\n\n\t\t\tcemu_assert_debug(imlMoveInstruction->type == PPCREC_IML_TYPE_FPR_R_R && imlMoveInstruction->op_fpr_r_r.regA.GetRegID() == fprIndex);\n\t\t\tcemu_assert_debug(imlMoveInstruction->op_fpr_r_r.regA.GetRegFormat() == IMLRegFormat::F64);\n\t\t\tauto dstReg = imlMoveInstruction->op_fpr_r_r.regR;\n\t\t\tIMLInstruction* newExpand = PPCRecompiler_insertInstruction(imlSegment, realPosition+1); // one after the move\n\t\t\tnewExpand->make_fpr_r(PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64, dstReg);\n\t\t\tpositionBias++;\n\t\t}\n\t\t// insert expand instruction after store\n\t\tIMLInstruction* newExpand = PPCRecompiler_insertInstruction(imlSegment, lastStore);\n\t\tnewExpand->make_fpr_r(PPCREC_IML_OP_FPR_EXPAND_F32_TO_F64, _FPRRegFromID(fprIndex));\n\t}\n}\n\n/*\n* Scans for patterns:\n* <Load sp float into register f>\n* <Random unrelated instructions>\n* <Store sp float from register f>\n* For these patterns the store and load is modified to work with un-extended values (float remains as float, no double conversion)\n* The float->double extension is then executed later\n* Advantages:\n* Keeps denormals and other special float values intact\n* Slightly improves performance\n*/\nvoid IMLOptimizer_OptimizeDirectFloatCopies(ppcImlGenContext_t* ppcImlGenContext)\n{\n\tfor (IMLSegment* segIt : ppcImlGenContext->segmentList2)\n\t{\n\t\tfor (sint32 i = 0; i < segIt->imlList.size(); i++)\n\t\t{\n\t\t\tIMLInstruction* imlInstruction = segIt->imlList.data() + i;\n\t\t\tif (imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD && imlInstruction->op_storeLoad.mode == PPCREC_FPR_LD_MODE_SINGLE)\n\t\t\t{\n\t\t\t\tPPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext, segIt, i, imlInstruction->op_storeLoad.registerData);\n\t\t\t}\n\t\t\telse if (imlInstruction->type == PPCREC_IML_TYPE_FPR_LOAD_INDEXED && imlInstruction->op_storeLoad.mode == PPCREC_FPR_LD_MODE_SINGLE)\n\t\t\t{\n\t\t\t\tPPCRecompiler_optimizeDirectFloatCopiesScanForward(ppcImlGenContext, segIt, i, imlInstruction->op_storeLoad.registerData);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid PPCRecompiler_optimizeDirectIntegerCopiesScanForward(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, sint32 imlIndexLoad, IMLReg gprReg)\n{\n\tcemu_assert_debug(gprReg.GetBaseFormat() == IMLRegFormat::I64); // todo - proper handling required for non-standard sizes\n\tcemu_assert_debug(gprReg.GetRegFormat() == IMLRegFormat::I32);\n\n\tIMLRegID gprIndex = gprReg.GetRegID();\n\tIMLInstruction* imlInstructionLoad = imlSegment->imlList.data() + imlIndexLoad;\n\tif ( imlInstructionLoad->op_storeLoad.flags2.swapEndian == false )\n\t\treturn;\n\tbool foundMatch = false;\n\tIMLUsedRegisters registersUsed;\n\tsint32 scanRangeEnd = std::min<sint32>(imlIndexLoad + 25, imlSegment->imlList.size()); // don't scan too far (saves performance and also the chances we can merge the load+store become low at high distances)\n\tsint32 i = imlIndexLoad + 1;\n\tfor (; i < scanRangeEnd; i++)\n\t{\n\t\tIMLInstruction* imlInstruction = imlSegment->imlList.data() + i;\n\t\tif (imlInstruction->IsSuffixInstruction())\n\t\t\tbreak;\n\t\t// check if GPR is stored\n\t\tif ((imlInstruction->type == PPCREC_IML_TYPE_STORE && imlInstruction->op_storeLoad.copyWidth == 32 ) )\n\t\t{\n\t\t\tif (imlInstruction->op_storeLoad.registerMem.GetRegID() == gprIndex)\n\t\t\t\tbreak;\n\t\t\tif (imlInstruction->op_storeLoad.registerData.GetRegID() == gprIndex)\n\t\t\t{\n\t\t\t\tIMLInstruction* imlInstructionStore = imlInstruction;\n\t\t\t\tif (foundMatch == false)\n\t\t\t\t{\n\t\t\t\t\t// switch the endian swap flag for the load instruction\n\t\t\t\t\timlInstructionLoad->op_storeLoad.flags2.swapEndian = !imlInstructionLoad->op_storeLoad.flags2.swapEndian;\n\t\t\t\t\tfoundMatch = true;\n\t\t\t\t}\n\t\t\t\t// switch the endian swap flag for the store instruction\n\t\t\t\timlInstructionStore->op_storeLoad.flags2.swapEndian = !imlInstructionStore->op_storeLoad.flags2.swapEndian;\n\t\t\t\t// keep scanning\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t// check if GPR is accessed\n\t\timlInstruction->CheckRegisterUsage(&registersUsed);\n\t\tif (registersUsed.readGPR1.IsValidAndSameRegID(gprIndex) ||\n\t\t\tregistersUsed.readGPR2.IsValidAndSameRegID(gprIndex) ||\n\t\t\tregistersUsed.readGPR3.IsValidAndSameRegID(gprIndex))\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tif (registersUsed.IsBaseGPRWritten(gprReg))\n\t\t\treturn; // GPR overwritten, we don't need to byte swap anymore\n\t}\n\tif (foundMatch)\n\t{\n\t\tPPCRecompiler_insertInstruction(imlSegment, i)->make_r_r(PPCREC_IML_OP_ENDIAN_SWAP, gprReg, gprReg);\n\t}\n}\n\n/*\n* Scans for patterns:\n* <Load sp integer into register r>\n* <Random unrelated instructions>\n* <Store sp integer from register r>\n* For these patterns the store and load is modified to work with non-swapped values\n* The big_endian->little_endian conversion is then executed later\n* Advantages:\n* Slightly improves performance\n*/\nvoid IMLOptimizer_OptimizeDirectIntegerCopies(ppcImlGenContext_t* ppcImlGenContext)\n{\n\tfor (IMLSegment* segIt : ppcImlGenContext->segmentList2)\n\t{\n\t\tfor (sint32 i = 0; i < segIt->imlList.size(); i++)\n\t\t{\n\t\t\tIMLInstruction* imlInstruction = segIt->imlList.data() + i;\n\t\t\tif (imlInstruction->type == PPCREC_IML_TYPE_LOAD && imlInstruction->op_storeLoad.copyWidth == 32 && imlInstruction->op_storeLoad.flags2.swapEndian )\n\t\t\t{\n\t\t\t\tPPCRecompiler_optimizeDirectIntegerCopiesScanForward(ppcImlGenContext, segIt, i, imlInstruction->op_storeLoad.registerData);\n\t\t\t}\n\t\t}\n\t}\n}\n\nIMLName PPCRecompilerImlGen_GetRegName(ppcImlGenContext_t* ppcImlGenContext, IMLReg reg);\n\nsint32 _getGQRIndexFromRegister(ppcImlGenContext_t* ppcImlGenContext, IMLReg gqrReg)\n{\n\tif (gqrReg.IsInvalid())\n\t\treturn -1;\n\tsint32 namedReg = PPCRecompilerImlGen_GetRegName(ppcImlGenContext, gqrReg);\n\tif (namedReg >= (PPCREC_NAME_SPR0 + SPR_UGQR0) && namedReg <= (PPCREC_NAME_SPR0 + SPR_UGQR7))\n\t{\n\t\treturn namedReg - (PPCREC_NAME_SPR0 + SPR_UGQR0);\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n\treturn -1;\n}\n\nbool PPCRecompiler_isUGQRValueKnown(ppcImlGenContext_t* ppcImlGenContext, sint32 gqrIndex, uint32& gqrValue)\n{\n\t// the default configuration is:\n\t// UGQR0 = 0x00000000\n\t// UGQR2 = 0x00040004\n\t// UGQR3 = 0x00050005\n\t// UGQR4 = 0x00060006\n\t// UGQR5 = 0x00070007\n\t// but games are free to modify UGQR2 to UGQR7 it seems.\n\t// no game modifies UGQR0 so it's safe enough to optimize for the default value\n\t// Ideally we would do some kind of runtime tracking and second recompilation to create fast paths for PSQ_L/PSQ_ST but thats todo\n\tif (gqrIndex == 0)\n\t\tgqrValue = 0x00000000;\n\telse\n\t\treturn false;\n\treturn true;\n}\n\n// analyses register dependencies across the entire function\n// per segment this will generate information about which registers need to be preserved and which ones don't (e.g. are overwritten)\nclass IMLOptimizerRegIOAnalysis\n{\n  public:\n\t// constructor with segment pointer list as span\n\tIMLOptimizerRegIOAnalysis(std::span<IMLSegment*> segmentList, uint32 maxRegId) : m_segmentList(segmentList), m_maxRegId(maxRegId)\n\t{\n\t\tm_segRegisterInOutList.resize(segmentList.size());\n\t}\n\n\tstruct IMLSegmentRegisterInOut\n\t{\n\t\t// todo - since our register ID range is usually pretty small (<64) we could use integer bitmasks to accelerate this? There is a helper class used in RA code already\n\t\tstd::unordered_set<IMLRegID> regWritten; // registers which are modified in this segment\n\t\tstd::unordered_set<IMLRegID> regImported; // registers which are read in this segment before they are written (importing value from previous segments)\n\t\tstd::unordered_set<IMLRegID> regForward; // registers which are not read or written in this segment, but are imported into a later segment (propagated info)\n\t};\n\n\t// calculate which registers are imported (read-before-written) and forwarded (read-before-written by a later segment) per segment\n\t// then in a second step propagate the dependencies across linked segments\n\tvoid ComputeDepedencies()\n\t{\n\t\tstd::vector<IMLSegmentRegisterInOut>& segRegisterInOutList = m_segRegisterInOutList;\n\t\tIMLSegmentRegisterInOut* segIO = segRegisterInOutList.data();\n\t\tuint32 index = 0;\n\t\tfor(auto& seg : m_segmentList)\n\t\t{\n\t\t\tseg->momentaryIndex = index;\n\t\t\tindex++;\n\t\t\tfor(auto& instr : seg->imlList)\n\t\t\t{\n\t\t\t\tIMLUsedRegisters registerUsage;\n\t\t\t\tinstr.CheckRegisterUsage(&registerUsage);\n\t\t\t\t// registers are considered imported if they are read before being written in this seg\n\t\t\t\tregisterUsage.ForEachReadGPR([&](IMLReg gprReg) {\n\t\t\t\t\tIMLRegID gprId = gprReg.GetRegID();\n\t\t\t\t\tif (!segIO->regWritten.contains(gprId))\n\t\t\t\t\t{\n\t\t\t\t\t\tsegIO->regImported.insert(gprId);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tregisterUsage.ForEachWrittenGPR([&](IMLReg gprReg) {\n\t\t\t\t\tIMLRegID gprId = gprReg.GetRegID();\n\t\t\t\t\tsegIO->regWritten.insert(gprId);\n\t\t\t\t});\n\t\t\t}\n\t\t\tsegIO++;\n\t\t}\n\t\t// for every exit segment, import all registers\n\t\tfor(auto& seg : m_segmentList)\n\t\t{\n\t\t\tif (!seg->nextSegmentIsUncertain)\n\t\t\t\tcontinue;\n\t\t\tif(seg->deadCodeEliminationHintSeg)\n\t\t\t\tcontinue;\n\t\t\tIMLSegmentRegisterInOut& segIO = segRegisterInOutList[seg->momentaryIndex];\n\t\t\tfor(uint32 i=0; i<=m_maxRegId; i++)\n\t\t\t{\n\t\t\t\tsegIO.regImported.insert((IMLRegID)i);\n\t\t\t}\n\t\t}\n\t\t// broadcast dependencies across segment chains\n\t\tstd::unordered_set<uint32> segIdsWhichNeedUpdate;\n\t\tfor (uint32 i = 0; i < m_segmentList.size(); i++)\n\t\t{\n\t\t\tsegIdsWhichNeedUpdate.insert(i);\n\t\t}\n\t\twhile(!segIdsWhichNeedUpdate.empty())\n\t\t{\n\t\t\tauto firstIt = segIdsWhichNeedUpdate.begin();\n\t\t\tuint32 segId = *firstIt;\n\t\t\tsegIdsWhichNeedUpdate.erase(firstIt);\n\t\t\t// forward regImported and regForward to earlier segments into their regForward, unless the register is written\n\t\t\tauto& curSeg = m_segmentList[segId];\n\t\t\tIMLSegmentRegisterInOut& curSegIO = segRegisterInOutList[segId];\n\t\t\tfor(auto& prevSeg : curSeg->list_prevSegments)\n\t\t\t{\n\t\t\t\tIMLSegmentRegisterInOut& prevSegIO = segRegisterInOutList[prevSeg->momentaryIndex];\n\t\t\t\tbool prevSegChanged = false;\n\t\t\t\tfor(auto& regId : curSegIO.regImported)\n\t\t\t\t{\n\t\t\t\t\tif (!prevSegIO.regWritten.contains(regId))\n\t\t\t\t\t\tprevSegChanged |= prevSegIO.regForward.insert(regId).second;\n\t\t\t\t}\n\t\t\t\tfor(auto& regId : curSegIO.regForward)\n\t\t\t\t{\n\t\t\t\t\tif (!prevSegIO.regWritten.contains(regId))\n\t\t\t\t\t\tprevSegChanged |= prevSegIO.regForward.insert(regId).second;\n\t\t\t\t}\n\t\t\t\tif(prevSegChanged)\n\t\t\t\t\tsegIdsWhichNeedUpdate.insert(prevSeg->momentaryIndex);\n\t\t\t}\n\t\t\t// same for hint links\n\t\t\tfor(auto& prevSeg : curSeg->list_deadCodeHintBy)\n\t\t\t{\n\t\t\t\tIMLSegmentRegisterInOut& prevSegIO = segRegisterInOutList[prevSeg->momentaryIndex];\n\t\t\t\tbool prevSegChanged = false;\n\t\t\t\tfor(auto& regId : curSegIO.regImported)\n\t\t\t\t{\n\t\t\t\t\tif (!prevSegIO.regWritten.contains(regId))\n\t\t\t\t\t\tprevSegChanged |= prevSegIO.regForward.insert(regId).second;\n\t\t\t\t}\n\t\t\t\tfor(auto& regId : curSegIO.regForward)\n\t\t\t\t{\n\t\t\t\t\tif (!prevSegIO.regWritten.contains(regId))\n\t\t\t\t\t\tprevSegChanged |= prevSegIO.regForward.insert(regId).second;\n\t\t\t\t}\n\t\t\t\tif(prevSegChanged)\n\t\t\t\t\tsegIdsWhichNeedUpdate.insert(prevSeg->momentaryIndex);\n\t\t\t}\n\t\t}\n\t}\n\n\tstd::unordered_set<IMLRegID> GetRegistersNeededAtEndOfSegment(IMLSegment& seg)\n\t{\n\t\tstd::unordered_set<IMLRegID> regsNeeded;\n\t\tif(seg.nextSegmentIsUncertain)\n\t\t{\n\t\t\tif(seg.deadCodeEliminationHintSeg)\n\t\t\t{\n\t\t\t\tauto& nextSegIO = m_segRegisterInOutList[seg.deadCodeEliminationHintSeg->momentaryIndex];\n\t\t\t\tregsNeeded.insert(nextSegIO.regImported.begin(), nextSegIO.regImported.end());\n\t\t\t\tregsNeeded.insert(nextSegIO.regForward.begin(), nextSegIO.regForward.end());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// add all regs\n\t\t\t\tfor(uint32 i = 0; i <= m_maxRegId; i++)\n\t\t\t\t\tregsNeeded.insert(i);\n\t\t\t}\n\t\t\treturn regsNeeded;\n\t\t}\n\t\tif(seg.nextSegmentBranchTaken)\n\t\t{\n\t\t\tauto& nextSegIO = m_segRegisterInOutList[seg.nextSegmentBranchTaken->momentaryIndex];\n\t\t\tregsNeeded.insert(nextSegIO.regImported.begin(), nextSegIO.regImported.end());\n\t\t\tregsNeeded.insert(nextSegIO.regForward.begin(), nextSegIO.regForward.end());\n\t\t}\n\t\tif(seg.nextSegmentBranchNotTaken)\n\t\t{\n\t\t\tauto& nextSegIO = m_segRegisterInOutList[seg.nextSegmentBranchNotTaken->momentaryIndex];\n\t\t\tregsNeeded.insert(nextSegIO.regImported.begin(), nextSegIO.regImported.end());\n\t\t\tregsNeeded.insert(nextSegIO.regForward.begin(), nextSegIO.regForward.end());\n\t\t}\n\t\treturn regsNeeded;\n\t}\n\n\tbool IsRegisterNeededAtEndOfSegment(IMLSegment& seg, IMLRegID regId)\n\t{\n\t\tif(seg.nextSegmentIsUncertain)\n\t\t{\n\t\t\tif(!seg.deadCodeEliminationHintSeg)\n\t\t\t\treturn true;\n\t\t\tauto& nextSegIO = m_segRegisterInOutList[seg.deadCodeEliminationHintSeg->momentaryIndex];\n\t\t\tif(nextSegIO.regImported.contains(regId))\n\t\t\t\treturn true;\n\t\t\tif(nextSegIO.regForward.contains(regId))\n\t\t\t\treturn true;\n\t\t\treturn false;\n\t\t}\n\t\tif(seg.nextSegmentBranchTaken)\n\t\t{\n\t\t\tauto& nextSegIO = m_segRegisterInOutList[seg.nextSegmentBranchTaken->momentaryIndex];\n\t\t\tif(nextSegIO.regImported.contains(regId))\n\t\t\t\treturn true;\n\t\t\tif(nextSegIO.regForward.contains(regId))\n\t\t\t\treturn true;\n\t\t}\n\t\tif(seg.nextSegmentBranchNotTaken)\n\t\t{\n\t\t\tauto& nextSegIO = m_segRegisterInOutList[seg.nextSegmentBranchNotTaken->momentaryIndex];\n\t\t\tif(nextSegIO.regImported.contains(regId))\n\t\t\t\treturn true;\n\t\t\tif(nextSegIO.regForward.contains(regId))\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n  private:\n\tstd::span<IMLSegment*> m_segmentList;\n\tuint32 m_maxRegId;\n\n\tstd::vector<IMLSegmentRegisterInOut> m_segRegisterInOutList;\n\n};\n\n// scan backwards starting from index and return the index of the first found instruction which writes to the given register (by id)\nsint32 IMLUtil_FindInstructionWhichWritesRegister(IMLSegment& seg, sint32 startIndex, IMLReg reg, sint32 maxScanDistance = -1)\n{\n\tsint32 endIndex = std::max<sint32>(startIndex - maxScanDistance, 0);\n\tfor (sint32 i = startIndex; i >= endIndex; i--)\n\t{\n\t\tIMLInstruction& imlInstruction = seg.imlList[i];\n\t\tIMLUsedRegisters registersUsed;\n\t\timlInstruction.CheckRegisterUsage(&registersUsed);\n\t\tif (registersUsed.IsBaseGPRWritten(reg))\n\t\t\treturn i;\n\t}\n\treturn -1;\n}\n\n// returns true if the instruction can safely be moved while keeping ordering constraints and data dependencies intact\n// initialIndex is inclusive, targetIndex is exclusive\nbool IMLUtil_CanMoveInstructionTo(IMLSegment& seg, sint32 initialIndex, sint32 targetIndex)\n{\n\tboost::container::static_vector<IMLRegID, 8> regsWritten;\n\tboost::container::static_vector<IMLRegID, 8> regsRead;\n\t// get list of read and written registers\n\tIMLUsedRegisters registersUsed;\n\tseg.imlList[initialIndex].CheckRegisterUsage(&registersUsed);\n\tregistersUsed.ForEachAccessedGPR([&](IMLReg reg, bool isWritten) {\n\t\tif (isWritten)\n\t\t\tregsWritten.push_back(reg.GetRegID());\n\t\telse\n\t\t\tregsRead.push_back(reg.GetRegID());\n\t});\n\t// check all the instructions inbetween\n\tif(initialIndex < targetIndex)\n\t{\n\t\tsint32 scanStartIndex = initialIndex+1; // +1 to skip the moving instruction itself\n\t\tsint32 scanEndIndex = targetIndex;\n\t\tfor (sint32 i = scanStartIndex; i < scanEndIndex; i++)\n\t\t{\n\t\t\tIMLUsedRegisters registersUsed;\n\t\t\tseg.imlList[i].CheckRegisterUsage(&registersUsed);\n\t\t\t// in order to be able to move an instruction past another instruction, any of the read registers must not be modified (written)\n\t\t\t// and any of it's written registers must not be read\n\t\t\tbool canMove = true;\n\t\t\tregistersUsed.ForEachAccessedGPR([&](IMLReg reg, bool isWritten) {\n\t\t\t\tIMLRegID regId = reg.GetRegID();\n\t\t\t\tif (!isWritten)\n\t\t\t\t\tcanMove = canMove && std::find(regsWritten.begin(), regsWritten.end(), regId) == regsWritten.end();\n\t\t\t\telse\n\t\t\t\t\tcanMove = canMove && std::find(regsRead.begin(), regsRead.end(), regId) == regsRead.end();\n\t\t\t});\n\t\t\tif(!canMove)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented(); // backwards scan is todo\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nsint32 IMLUtil_CountRegisterReadsInRange(IMLSegment& seg, sint32 scanStartIndex, sint32 scanEndIndex, IMLRegID regId)\n{\n\tcemu_assert_debug(scanStartIndex <= scanEndIndex);\n\tcemu_assert_debug(scanEndIndex < seg.imlList.size());\n\tsint32 count = 0;\n\tfor (sint32 i = scanStartIndex; i <= scanEndIndex; i++)\n\t{\n\t\tIMLUsedRegisters registersUsed;\n\t\tseg.imlList[i].CheckRegisterUsage(&registersUsed);\n\t\tregistersUsed.ForEachReadGPR([&](IMLReg reg) {\n\t\t\tif (reg.GetRegID() == regId)\n\t\t\t\tcount++;\n\t\t});\n\t}\n\treturn count;\n}\n\n// move instruction from one index to another\n// instruction will be inserted before the instruction at targetIndex\n// returns the new instruction index of the moved instruction\nsint32 IMLUtil_MoveInstructionTo(IMLSegment& seg, sint32 initialIndex, sint32 targetIndex)\n{\n\tcemu_assert_debug(initialIndex != targetIndex);\n\tIMLInstruction temp = seg.imlList[initialIndex];\n\tif (initialIndex < targetIndex)\n\t{\n\t\tcemu_assert_debug(targetIndex > 0);\n\t\ttargetIndex--;\n\t\tfor(size_t i=initialIndex; i<targetIndex; i++)\n\t\t\tseg.imlList[i] = seg.imlList[i+1];\n\t\tseg.imlList[targetIndex] = temp;\n\t\treturn targetIndex;\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented(); // testing needed\n\t\tstd::copy(seg.imlList.begin() + targetIndex, seg.imlList.begin() + initialIndex, seg.imlList.begin() + targetIndex + 1);\n\t\tseg.imlList[targetIndex] = temp;\n\t\treturn targetIndex;\n\t}\n}\n\n// x86 specific\nbool IMLOptimizerX86_ModifiesEFlags(IMLInstruction& inst)\n{\n\t// this is a very conservative implementation. There are more cases but this is good enough for now\n\tif(inst.type == PPCREC_IML_TYPE_NAME_R || inst.type == PPCREC_IML_TYPE_R_NAME)\n\t\treturn false;\n\tif((inst.type == PPCREC_IML_TYPE_R_R || inst.type == PPCREC_IML_TYPE_R_S32) && inst.operation == PPCREC_IML_OP_ASSIGN)\n\t\treturn false;\n\treturn true; // if we dont know for sure, assume it does\n}\n\nvoid IMLOptimizer_DebugPrintSeg(ppcImlGenContext_t& ppcImlGenContext, IMLSegment& seg)\n{\n\tprintf(\"----------------\\n\");\n\tIMLDebug_DumpSegment(&ppcImlGenContext, &seg);\n\tfflush(stdout);\n}\n\nvoid IMLOptimizer_RemoveDeadCodeFromSegment(IMLOptimizerRegIOAnalysis& regIoAnalysis, IMLSegment& seg)\n{\n\t// algorithm works like this:\n\t// Calculate which registers need to be preserved at the end of each segment\n\t// Then for each segment:\n\t// - Iterate instructions backwards\n\t// - Maintain a list of registers which are read at a later point (initially this is the list from the first step)\n\t// - If an instruction only modifies registers which are not in the read list and has no side effects, then it is dead code and can be replaced with a no-op\n\n\tstd::unordered_set<IMLRegID> regsNeeded = regIoAnalysis.GetRegistersNeededAtEndOfSegment(seg);\n\n\t// start with suffix instruction\n\tif(seg.HasSuffixInstruction())\n\t{\n\t\tIMLInstruction& imlInstruction = seg.imlList[seg.GetSuffixInstructionIndex()];\n\t\tIMLUsedRegisters registersUsed;\n\t\timlInstruction.CheckRegisterUsage(&registersUsed);\n\t\tregistersUsed.ForEachWrittenGPR([&](IMLReg reg) {\n\t\t\tregsNeeded.erase(reg.GetRegID());\n\t\t});\n\t\tregistersUsed.ForEachReadGPR([&](IMLReg reg) {\n\t\t\tregsNeeded.insert(reg.GetRegID());\n\t\t});\n\t}\n\t// iterate instructions backwards\n\tfor (sint32 i = seg.imlList.size() - (seg.HasSuffixInstruction() ? 2:1); i >= 0; i--)\n\t{\n\t\tIMLInstruction& imlInstruction = seg.imlList[i];\n\t\tIMLUsedRegisters registersUsed;\n\t\timlInstruction.CheckRegisterUsage(&registersUsed);\n\t\t// register read -> remove from overwritten list\n\t\t// register written -> add to overwritten list\n\n\t\t// check if this instruction only writes registers which will never be read\n\t\tbool onlyWritesRedundantRegisters = true;\n\t\tregistersUsed.ForEachWrittenGPR([&](IMLReg reg) {\n\t\t\tif (regsNeeded.contains(reg.GetRegID()))\n\t\t\t\tonlyWritesRedundantRegisters = false;\n\t\t});\n\t\t// check if any of the written registers are read after this point\n\t\tregistersUsed.ForEachWrittenGPR([&](IMLReg reg) {\n\t\t\tregsNeeded.erase(reg.GetRegID());\n\t\t});\n\t\tregistersUsed.ForEachReadGPR([&](IMLReg reg) {\n\t\t\tregsNeeded.insert(reg.GetRegID());\n\t\t});\n\t\tif(!imlInstruction.HasSideEffects() && onlyWritesRedundantRegisters)\n\t\t{\n\t\t\timlInstruction.make_no_op();\n\t\t}\n\t}\n}\n\nvoid IMLOptimizerX86_SubstituteCJumpForEflagsJump(IMLOptimizerRegIOAnalysis& regIoAnalysis, IMLSegment& seg)\n{\n\t// convert and optimize bool condition jumps to eflags condition jumps\n\t// - Moves eflag setter (e.g. cmp) closer to eflags consumer (conditional jump) if necessary. If not possible but required then exit early\n\t// - Since we only rely on eflags, the boolean register can be optimized out if DCE considers it unused\n\t// - Further detect and optimize patterns like DEC + CMP + JCC into fused ops (todo)\n\n\t// check if this segment ends with a conditional jump\n\tif(!seg.HasSuffixInstruction())\n\t\treturn;\n\tsint32 cjmpInstIndex = seg.GetSuffixInstructionIndex();\n\tif(cjmpInstIndex < 0)\n\t\treturn;\n\tIMLInstruction& cjumpInstr = seg.imlList[cjmpInstIndex];\n\tif( cjumpInstr.type != PPCREC_IML_TYPE_CONDITIONAL_JUMP )\n\t\treturn;\n\tIMLReg regCondBool = cjumpInstr.op_conditional_jump.registerBool;\n\tbool invertedCondition = !cjumpInstr.op_conditional_jump.mustBeTrue;\n\t// find the instruction which sets the bool\n\tsint32 cmpInstrIndex = IMLUtil_FindInstructionWhichWritesRegister(seg, cjmpInstIndex-1, regCondBool, 20);\n\tif(cmpInstrIndex < 0)\n\t\treturn;\n\t// check if its an instruction combo which can be optimized (currently only cmp + cjump) and get the condition\n\tIMLInstruction& condSetterInstr = seg.imlList[cmpInstrIndex];\n\tIMLCondition cond;\n\tif(condSetterInstr.type == PPCREC_IML_TYPE_COMPARE)\n\t\tcond = condSetterInstr.op_compare.cond;\n\telse if(condSetterInstr.type == PPCREC_IML_TYPE_COMPARE_S32)\n\t\tcond = condSetterInstr.op_compare_s32.cond;\n\telse\n\t\treturn;\n\t// check if instructions inbetween modify eflags\n\tsint32 indexEflagsSafeStart = -1; // index of the first instruction which does not modify eflags up to cjump\n\tfor(sint32 i = cjmpInstIndex-1; i > cmpInstrIndex; i--)\n\t{\n\t\tif(IMLOptimizerX86_ModifiesEFlags(seg.imlList[i]))\n\t\t{\n\t\t\tindexEflagsSafeStart = i+1;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif(indexEflagsSafeStart >= 0)\n\t{\n\t\tcemu_assert(indexEflagsSafeStart > 0);\n\t\t// there are eflags-modifying instructions inbetween the bool setter and cjump\n\t\t// try to move the eflags setter close enough to the cjump (to indexEflagsSafeStart)\n\t\tbool canMove = IMLUtil_CanMoveInstructionTo(seg, cmpInstrIndex, indexEflagsSafeStart);\n\t\tif(!canMove)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcmpInstrIndex = IMLUtil_MoveInstructionTo(seg, cmpInstrIndex, indexEflagsSafeStart);\n\t\t}\n\t}\n\t// we can turn the jump into an eflags jump\n\tcjumpInstr.make_x86_eflags_jcc(cond, invertedCondition);\n\n\tif (IMLUtil_CountRegisterReadsInRange(seg, cmpInstrIndex, cjmpInstIndex, regCondBool.GetRegID()) > 1 || regIoAnalysis.IsRegisterNeededAtEndOfSegment(seg, regCondBool.GetRegID()))\n\t\treturn; // bool register is used beyond the CMP, we can't drop it\n\n\tauto& cmpInstr = seg.imlList[cmpInstrIndex];\n\tcemu_assert_debug(cmpInstr.type == PPCREC_IML_TYPE_COMPARE || cmpInstr.type == PPCREC_IML_TYPE_COMPARE_S32);\n\tif(cmpInstr.type == PPCREC_IML_TYPE_COMPARE)\n\t{\n\t\tIMLReg regA = cmpInstr.op_compare.regA;\n\t\tIMLReg regB = cmpInstr.op_compare.regB;\n\t\tseg.imlList[cmpInstrIndex].make_r_r(PPCREC_IML_OP_X86_CMP, regA, regB);\n\t}\n\telse\n\t{\n\t\tIMLReg regA = cmpInstr.op_compare_s32.regA;\n\t\tsint32 val = cmpInstr.op_compare_s32.immS32;\n\t\tseg.imlList[cmpInstrIndex].make_r_s32(PPCREC_IML_OP_X86_CMP, regA, val);\n\t}\n\n}\n\nvoid IMLOptimizer_StandardOptimizationPassForSegment(IMLOptimizerRegIOAnalysis& regIoAnalysis, IMLSegment& seg)\n{\n\tIMLOptimizer_RemoveDeadCodeFromSegment(regIoAnalysis, seg);\n\n#ifdef ARCH_X86_64\n\t// x86 specific optimizations\n\tIMLOptimizerX86_SubstituteCJumpForEflagsJump(regIoAnalysis, seg); // this pass should be applied late since it creates invisible eflags dependencies (which would break further register dependency analysis)\n#endif\n}\n\nvoid IMLOptimizer_StandardOptimizationPass(ppcImlGenContext_t& ppcImlGenContext)\n{\n\tIMLOptimizerRegIOAnalysis regIoAnalysis(ppcImlGenContext.segmentList2, ppcImlGenContext.GetMaxRegId());\n\tregIoAnalysis.ComputeDepedencies();\n\tfor (IMLSegment* segIt : ppcImlGenContext.segmentList2)\n\t{\n\t\tIMLOptimizer_StandardOptimizationPassForSegment(regIoAnalysis, *segIt);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocator.cpp",
    "content": "#include \"IML.h\"\n\n#include \"../PPCRecompiler.h\"\n#include \"../PPCRecompilerIml.h\"\n#include \"IMLRegisterAllocator.h\"\n#include \"IMLRegisterAllocatorRanges.h\"\n\n#include \"../BackendX64/BackendX64.h\"\n#ifdef __aarch64__\n#include \"../BackendAArch64/BackendAArch64.h\"\n#endif\n\n#include <boost/container/static_vector.hpp>\n#include <boost/container/small_vector.hpp>\n\n#include \"Common/cpu_features.h\"\n\n#define DEBUG_RA_EXTRA_VALIDATION 0\t// if set to non-zero, additional expensive validation checks will be performed\n#define DEBUG_RA_INSTRUCTION_GEN 0\n\nstruct IMLRARegAbstractLiveness // preliminary liveness info. One entry per register and segment\n{\n\tIMLRARegAbstractLiveness(IMLRegFormat regBaseFormat, sint32 usageStart, sint32 usageEnd)\n\t\t: regBaseFormat(regBaseFormat), usageStart(usageStart), usageEnd(usageEnd) {};\n\n\tvoid TrackInstruction(sint32 index)\n\t{\n\t\tusageStart = std::min<sint32>(usageStart, index);\n\t\tusageEnd = std::max<sint32>(usageEnd, index + 1); // exclusive index\n\t}\n\n\tsint32 usageStart;\n\tsint32 usageEnd;\n\tbool isProcessed{false};\n\tIMLRegFormat regBaseFormat;\n};\n\nstruct IMLRegisterAllocatorContext\n{\n\tIMLRegisterAllocatorParameters* raParam;\n\tppcImlGenContext_t* deprGenContext; // deprecated. Try to decouple IMLRA from other parts of IML/PPCRec\n\n\tstd::unordered_map<IMLRegID, IMLRegFormat> regIdToBaseFormat;\n\t// first pass\n\tstd::vector<std::unordered_map<IMLRegID, IMLRARegAbstractLiveness>> perSegmentAbstractRanges;\n\n\t// helper methods\n\tinline std::unordered_map<IMLRegID, IMLRARegAbstractLiveness>& GetSegmentAbstractRangeMap(IMLSegment* imlSegment)\n\t{\n\t\treturn perSegmentAbstractRanges[imlSegment->momentaryIndex];\n\t}\n\n\tinline IMLRegFormat GetBaseFormatByRegId(IMLRegID regId) const\n\t{\n\t\tauto it = regIdToBaseFormat.find(regId);\n\t\tcemu_assert_debug(it != regIdToBaseFormat.cend());\n\t\treturn it->second;\n\t}\n};\n\nstruct IMLFixedRegisters\n{\n\tstruct Entry\n\t{\n\t\tEntry(IMLReg reg, IMLPhysRegisterSet physRegSet)\n\t\t\t: reg(reg), physRegSet(physRegSet) {}\n\n\t\tIMLReg reg;\n\t\tIMLPhysRegisterSet physRegSet;\n\t};\n\tboost::container::small_vector<Entry, 4> listInput;\t // fixed register requirements for instruction input edge\n\tboost::container::small_vector<Entry, 4> listOutput; // fixed register requirements for instruction output edge\n};\n\nstatic void SetupCallingConvention(const IMLInstruction* instruction, IMLFixedRegisters& fixedRegs, const IMLPhysReg intParamToPhysReg[3], const IMLPhysReg floatParamToPhysReg[3], const IMLPhysReg intReturnPhysReg, const IMLPhysReg floatReturnPhysReg, IMLPhysRegisterSet volatileRegisters)\n{\n\tsint32 numIntParams = 0, numFloatParams = 0;\n\n\tauto AddParameterMapping = [&](IMLReg reg) {\n\t\tif (!reg.IsValid())\n\t\t\treturn;\n\t\tif (reg.GetBaseFormat() == IMLRegFormat::I64)\n\t\t{\n\t\t\tIMLPhysRegisterSet ps;\n\t\t\tps.SetAvailable(intParamToPhysReg[numIntParams]);\n\t\t\tfixedRegs.listInput.emplace_back(reg, ps);\n\t\t\tnumIntParams++;\n\t\t}\n\t\telse if (reg.GetBaseFormat() == IMLRegFormat::F64)\n\t\t{\n\t\t\tIMLPhysRegisterSet ps;\n\t\t\tps.SetAvailable(floatParamToPhysReg[numFloatParams]);\n\t\t\tfixedRegs.listInput.emplace_back(reg, ps);\n\t\t\tnumFloatParams++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t};\n\tAddParameterMapping(instruction->op_call_imm.regParam0);\n\tAddParameterMapping(instruction->op_call_imm.regParam1);\n\tAddParameterMapping(instruction->op_call_imm.regParam2);\n\t// return value\n\tif (instruction->op_call_imm.regReturn.IsValid())\n\t{\n\t\tIMLRegFormat returnFormat = instruction->op_call_imm.regReturn.GetBaseFormat();\n\t\tbool isIntegerFormat = returnFormat == IMLRegFormat::I64 || returnFormat == IMLRegFormat::I32 || returnFormat == IMLRegFormat::I16 || returnFormat == IMLRegFormat::I8;\n\t\tIMLPhysRegisterSet ps;\n\t\tif (isIntegerFormat)\n\t\t{\n\t\t\tps.SetAvailable(intReturnPhysReg);\n\t\t\tvolatileRegisters.SetReserved(intReturnPhysReg);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tps.SetAvailable(floatReturnPhysReg);\n\t\t\tvolatileRegisters.SetReserved(floatReturnPhysReg);\n\t\t}\n\t\tfixedRegs.listOutput.emplace_back(instruction->op_call_imm.regReturn, ps);\n\t}\n\t// block volatile registers from being used on the output edge, this makes the register allocator store them during the call\n\tfixedRegs.listOutput.emplace_back(IMLREG_INVALID, volatileRegisters);\n}\n\n#if defined(__aarch64__)\n// aarch64\nstatic void GetInstructionFixedRegisters(IMLInstruction* instruction, IMLFixedRegisters& fixedRegs)\n{\n\tfixedRegs.listInput.clear();\n\tfixedRegs.listOutput.clear();\n\n\t// The purpose of GetInstructionFixedRegisters() is to constraint virtual registers to specific physical registers for instructions which need it\n\t// on x86 this is used for instructions like SHL <reg>, CL where the CL register is hardwired. On aarch it's probably only necessary for setting up the calling convention\n\tif (instruction->type == PPCREC_IML_TYPE_CALL_IMM)\n\t{\n\t\tconst IMLPhysReg intParamToPhysReg[3] = {IMLArchAArch64::PHYSREG_GPR_BASE + 0, IMLArchAArch64::PHYSREG_GPR_BASE + 1, IMLArchAArch64::PHYSREG_GPR_BASE + 2};\n\t\tconst IMLPhysReg floatParamToPhysReg[3] = {IMLArchAArch64::PHYSREG_FPR_BASE + 0, IMLArchAArch64::PHYSREG_FPR_BASE + 1, IMLArchAArch64::PHYSREG_FPR_BASE + 2};\n\t\tIMLPhysRegisterSet volatileRegs;\n\t\tfor (int i = 0; i <= 17; i++) // x0 to x17 are volatile\n\t\t\tvolatileRegs.SetAvailable(IMLArchAArch64::PHYSREG_GPR_BASE + i);\n\t\t// v0-v7 & v16-v31 are volatile. For v8-v15 only the high 64 bits are volatile.\n\t\tfor (int i = 0; i <= 7; i++)\n\t\t\tvolatileRegs.SetAvailable(IMLArchAArch64::PHYSREG_FPR_BASE + i);\n\t\tfor (int i = 16; i <= 31; i++)\n\t\t\tvolatileRegs.SetAvailable(IMLArchAArch64::PHYSREG_FPR_BASE + i);\n\t\tSetupCallingConvention(instruction, fixedRegs, intParamToPhysReg, floatParamToPhysReg, IMLArchAArch64::PHYSREG_GPR_BASE + 0, IMLArchAArch64::PHYSREG_FPR_BASE + 0, volatileRegs);\n\t}\n}\n#else\n// x86-64\nstatic void GetInstructionFixedRegisters(IMLInstruction* instruction, IMLFixedRegisters& fixedRegs)\n{\n\tfixedRegs.listInput.clear();\n\tfixedRegs.listOutput.clear();\n\n\tif (instruction->type == PPCREC_IML_TYPE_R_R_R)\n\t{\n\t\tif (instruction->operation == PPCREC_IML_OP_LEFT_SHIFT || instruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_S || instruction->operation == PPCREC_IML_OP_RIGHT_SHIFT_U)\n\t\t{\n\t\t\tif(!g_CPUFeatures.x86.bmi2)\n\t\t\t{\n\t\t\t\tIMLPhysRegisterSet ps;\n\t\t\t\tps.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_ECX);\n\t\t\t\tfixedRegs.listInput.emplace_back(instruction->op_r_r_r.regB, ps);\n\t\t\t}\n\t\t}\n\t}\n\telse if (instruction->type == PPCREC_IML_TYPE_ATOMIC_CMP_STORE)\n\t{\n\t\tIMLPhysRegisterSet ps;\n\t\tps.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_EAX);\n\t\tfixedRegs.listInput.emplace_back(IMLREG_INVALID, ps); // none of the inputs may use EAX\n\t\tfixedRegs.listOutput.emplace_back(instruction->op_atomic_compare_store.regBoolOut, ps); // but we output to EAX\n\t}\n\telse if (instruction->type == PPCREC_IML_TYPE_CALL_IMM)\n\t{\n\t\tconst IMLPhysReg intParamToPhysReg[3] = {IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RCX, IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RDX, IMLArchX86::PHYSREG_GPR_BASE + X86_REG_R8};\n\t\tconst IMLPhysReg floatParamToPhysReg[3] = {IMLArchX86::PHYSREG_FPR_BASE + 0, IMLArchX86::PHYSREG_FPR_BASE + 1, IMLArchX86::PHYSREG_FPR_BASE + 2};\n\t\tIMLPhysRegisterSet volatileRegs;\n\t\tvolatileRegs.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RAX);\n\t\tvolatileRegs.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RCX);\n\t\tvolatileRegs.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RDX);\n\t\tvolatileRegs.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_R8);\n\t\tvolatileRegs.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_R9);\n\t\tvolatileRegs.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_R10);\n\t\tvolatileRegs.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_R11);\n\t\t// YMM0-YMM5 are volatile\n\t\tfor (int i = 0; i <= 5; i++)\n\t\t\tvolatileRegs.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + i);\n\t\t// for YMM6-YMM15 only the upper 128 bits are volatile which we dont use\n\t\tSetupCallingConvention(instruction, fixedRegs, intParamToPhysReg, floatParamToPhysReg, IMLArchX86::PHYSREG_GPR_BASE + X86_REG_EAX, IMLArchX86::PHYSREG_FPR_BASE + 0, volatileRegs);\n\t}\n}\n#endif\n\nuint32 IMLRA_GetNextIterationIndex()\n{\n\tstatic uint32 recRACurrentIterationIndex = 0;\n\trecRACurrentIterationIndex++;\n\treturn recRACurrentIterationIndex;\n}\n\nbool _detectLoop(IMLSegment* currentSegment, sint32 depth, uint32 iterationIndex, IMLSegment* imlSegmentLoopBase)\n{\n\tif (currentSegment == imlSegmentLoopBase)\n\t\treturn true;\n\tif (currentSegment->raInfo.lastIterationIndex == iterationIndex)\n\t\treturn currentSegment->raInfo.isPartOfProcessedLoop;\n\tif (depth >= 9)\n\t\treturn false;\n\tcurrentSegment->raInfo.lastIterationIndex = iterationIndex;\n\tcurrentSegment->raInfo.isPartOfProcessedLoop = false;\n\n\tif (currentSegment->nextSegmentIsUncertain)\n\t\treturn false;\n\tif (currentSegment->nextSegmentBranchNotTaken)\n\t{\n\t\tif (currentSegment->nextSegmentBranchNotTaken->momentaryIndex > currentSegment->momentaryIndex)\n\t\t{\n\t\t\tcurrentSegment->raInfo.isPartOfProcessedLoop |= _detectLoop(currentSegment->nextSegmentBranchNotTaken, depth + 1, iterationIndex, imlSegmentLoopBase);\n\t\t}\n\t}\n\tif (currentSegment->nextSegmentBranchTaken)\n\t{\n\t\tif (currentSegment->nextSegmentBranchTaken->momentaryIndex > currentSegment->momentaryIndex)\n\t\t{\n\t\t\tcurrentSegment->raInfo.isPartOfProcessedLoop |= _detectLoop(currentSegment->nextSegmentBranchTaken, depth + 1, iterationIndex, imlSegmentLoopBase);\n\t\t}\n\t}\n\tif (currentSegment->raInfo.isPartOfProcessedLoop)\n\t\tcurrentSegment->loopDepth++;\n\treturn currentSegment->raInfo.isPartOfProcessedLoop;\n}\n\nvoid IMLRA_DetectLoop(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegmentLoopBase)\n{\n\tuint32 iterationIndex = IMLRA_GetNextIterationIndex();\n\timlSegmentLoopBase->raInfo.lastIterationIndex = iterationIndex;\n\tif (_detectLoop(imlSegmentLoopBase->nextSegmentBranchTaken, 0, iterationIndex, imlSegmentLoopBase))\n\t{\n\t\timlSegmentLoopBase->loopDepth++;\n\t}\n}\n\nvoid IMLRA_IdentifyLoop(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment)\n{\n\tif (imlSegment->nextSegmentIsUncertain)\n\t\treturn;\n\t// check if this segment has a branch that links to itself (tight loop)\n\tif (imlSegment->nextSegmentBranchTaken == imlSegment)\n\t{\n\t\t// segment loops over itself\n\t\timlSegment->loopDepth++;\n\t\treturn;\n\t}\n\t// check if this segment has a branch that goes backwards (potential complex loop)\n\tif (imlSegment->nextSegmentBranchTaken && imlSegment->nextSegmentBranchTaken->momentaryIndex < imlSegment->momentaryIndex)\n\t{\n\t\tIMLRA_DetectLoop(ppcImlGenContext, imlSegment);\n\t}\n}\n\n#define SUBRANGE_LIST_SIZE (128)\n\nsint32 IMLRA_CountDistanceUntilNextUse(raLivenessRange* subrange, raInstructionEdge startPosition)\n{\n\tfor (sint32 i = 0; i < subrange->list_accessLocations.size(); i++)\n\t{\n\t\tif (subrange->list_accessLocations[i].pos >= startPosition)\n\t\t{\n\t\t\tauto& it = subrange->list_accessLocations[i];\n\t\t\tcemu_assert_debug(it.IsRead() != it.IsWrite()); // an access location can be either read or write\n\t\t\tcemu_assert_debug(!startPosition.ConnectsToPreviousSegment() && !startPosition.ConnectsToNextSegment());\n\t\t\treturn it.pos.GetRaw() - startPosition.GetRaw();\n\t\t}\n\t}\n\tcemu_assert_debug(subrange->imlSegment->imlList.size() < 10000);\n\treturn 10001 * 2;\n}\n\n// returns -1 if there is no fixed register requirement on or after startPosition\nsint32 IMLRA_CountDistanceUntilFixedRegUsageInRange(IMLSegment* imlSegment, raLivenessRange* range, raInstructionEdge startPosition, sint32 physRegister, bool& hasFixedAccess)\n{\n\thasFixedAccess = false;\n\tcemu_assert_debug(startPosition.IsInstructionIndex());\n\tfor (auto& fixedReqEntry : range->list_fixedRegRequirements)\n\t{\n\t\tif (fixedReqEntry.pos < startPosition)\n\t\t\tcontinue;\n\t\tif (fixedReqEntry.allowedReg.IsAvailable(physRegister))\n\t\t{\n\t\t\thasFixedAccess = true;\n\t\t\treturn fixedReqEntry.pos.GetRaw() - startPosition.GetRaw();\n\t\t}\n\t}\n\tcemu_assert_debug(range->interval.end.IsInstructionIndex());\n\treturn range->interval.end.GetRaw() - startPosition.GetRaw();\n}\n\nsint32 IMLRA_CountDistanceUntilFixedRegUsage(IMLSegment* imlSegment, raInstructionEdge startPosition, sint32 maxDistance, IMLRegID ourRegId, sint32 physRegister)\n{\n\tcemu_assert_debug(startPosition.IsInstructionIndex());\n\traInstructionEdge lastPos2;\n\tlastPos2.Set(imlSegment->imlList.size(), false);\n\n\traInstructionEdge endPos;\n\tendPos = startPosition + maxDistance;\n\tif (endPos > lastPos2)\n\t\tendPos = lastPos2;\n\tIMLFixedRegisters fixedRegs;\n\tif (startPosition.IsOnOutputEdge())\n\t\tGetInstructionFixedRegisters(imlSegment->imlList.data() + startPosition.GetInstructionIndex(), fixedRegs);\n\tfor (raInstructionEdge currentPos = startPosition; currentPos <= endPos; ++currentPos)\n\t{\n\t\tif (currentPos.IsOnInputEdge())\n\t\t{\n\t\t\tGetInstructionFixedRegisters(imlSegment->imlList.data() + currentPos.GetInstructionIndex(), fixedRegs);\n\t\t}\n\t\tauto& fixedRegAccess = currentPos.IsOnInputEdge() ? fixedRegs.listInput : fixedRegs.listOutput;\n\t\tfor (auto& fixedRegLoc : fixedRegAccess)\n\t\t{\n\t\t\tif (fixedRegLoc.reg.IsInvalid() || fixedRegLoc.reg.GetRegID() != ourRegId)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(fixedRegLoc.reg.IsInvalid() || fixedRegLoc.physRegSet.HasExactlyOneAvailable()); // this whole function only makes sense when there is only one fixed register, otherwise there are extra permutations to consider. Except for IMLREG_INVALID which is used to indicate reserved registers\n\t\t\t\tif (fixedRegLoc.physRegSet.IsAvailable(physRegister))\n\t\t\t\t\treturn currentPos.GetRaw() - startPosition.GetRaw();\n\t\t\t}\n\t\t}\n\t}\n\treturn endPos.GetRaw() - startPosition.GetRaw();\n}\n\n// count how many instructions there are until physRegister is used by any subrange or reserved for any fixed register requirement (returns 0 if register is in use at startIndex)\nsint32 PPCRecRA_countDistanceUntilNextLocalPhysRegisterUse(IMLSegment* imlSegment, raInstructionEdge startPosition, sint32 physRegister)\n{\n\tcemu_assert_debug(startPosition.IsInstructionIndex());\n\tsint32 minDistance = (sint32)imlSegment->imlList.size() * 2 - startPosition.GetRaw();\n\t// next\n\traLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;\n\twhile (subrangeItr)\n\t{\n\t\tif (subrangeItr->GetPhysicalRegister() != physRegister)\n\t\t{\n\t\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t\t\tcontinue;\n\t\t}\n\t\tif (subrangeItr->interval.ContainsEdge(startPosition))\n\t\t\treturn 0;\n\t\tif (subrangeItr->interval.end < startPosition)\n\t\t{\n\t\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t\t\tcontinue;\n\t\t}\n\t\tcemu_assert_debug(startPosition <= subrangeItr->interval.start);\n\t\tsint32 currentDist = subrangeItr->interval.start.GetRaw() - startPosition.GetRaw();\n\t\tminDistance = std::min(minDistance, currentDist);\n\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t}\n\treturn minDistance;\n}\n\nstruct IMLRALivenessTimeline\n{\n\tIMLRALivenessTimeline()\n\t{\n\t}\n\n\t// manually add an active range\n\tvoid AddActiveRange(raLivenessRange* subrange)\n\t{\n\t\tactiveRanges.emplace_back(subrange);\n\t}\n\n\tvoid ExpireRanges(raInstructionEdge expireUpTo)\n\t{\n\t\texpiredRanges.clear();\n\t\tsize_t count = activeRanges.size();\n\t\tfor (size_t f = 0; f < count; f++)\n\t\t{\n\t\t\traLivenessRange* liverange = activeRanges[f];\n\t\t\tif (liverange->interval.end < expireUpTo) // this was <= but since end is not inclusive we need to use <\n\t\t\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\t\tif (!expireUpTo.ConnectsToNextSegment() && (liverange->subrangeBranchTaken || liverange->subrangeBranchNotTaken))\n\t\t\t\t\tassert_dbg(); // infinite subranges should not expire\n#endif\n\t\t\t\texpiredRanges.emplace_back(liverange);\n\t\t\t\t// remove entry\n\t\t\t\tactiveRanges[f] = activeRanges[count - 1];\n\t\t\t\tf--;\n\t\t\t\tcount--;\n\t\t\t}\n\t\t}\n\t\tif (count != activeRanges.size())\n\t\t\tactiveRanges.resize(count);\n\t}\n\n\tstd::span<raLivenessRange*> GetExpiredRanges()\n\t{\n\t\treturn {expiredRanges.data(), expiredRanges.size()};\n\t}\n\n\tstd::span<raLivenessRange*> GetActiveRanges()\n\t{\n\t\treturn {activeRanges.data(), activeRanges.size()};\n\t}\n\n\traLivenessRange* GetActiveRangeByVirtualRegId(IMLRegID regId)\n\t{\n\t\tfor (auto& it : activeRanges)\n\t\t\tif (it->virtualRegister == regId)\n\t\t\t\treturn it;\n\t\treturn nullptr;\n\t}\n\n\traLivenessRange* GetActiveRangeByPhysicalReg(sint32 physReg)\n\t{\n\t\tcemu_assert_debug(physReg >= 0);\n\t\tfor (auto& it : activeRanges)\n\t\t\tif (it->physicalRegister == physReg)\n\t\t\t\treturn it;\n\t\treturn nullptr;\n\t}\n\n\tboost::container::small_vector<raLivenessRange*, 64> activeRanges;\n\n  private:\n\tboost::container::small_vector<raLivenessRange*, 16> expiredRanges;\n};\n\n// mark occupied registers by any overlapping range as unavailable in physRegSet\nvoid PPCRecRA_MaskOverlappingPhysRegForGlobalRange(raLivenessRange* range2, IMLPhysRegisterSet& physRegSet)\n{\n\tauto clusterRanges = range2->GetAllSubrangesInCluster();\n\tfor (auto& subrange : clusterRanges)\n\t{\n\t\tIMLSegment* imlSegment = subrange->imlSegment;\n\t\traLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;\n\t\twhile (subrangeItr)\n\t\t{\n\t\t\tif (subrange == subrangeItr)\n\t\t\t{\n\t\t\t\t// next\n\t\t\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (subrange->interval.IsOverlapping(subrangeItr->interval))\n\t\t\t{\n\t\t\t\tif (subrangeItr->GetPhysicalRegister() >= 0)\n\t\t\t\t\tphysRegSet.SetReserved(subrangeItr->GetPhysicalRegister());\n\t\t\t}\n\t\t\t// next\n\t\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t\t}\n\t}\n}\n\nbool _livenessRangeStartCompare(raLivenessRange* lhs, raLivenessRange* rhs)\n{\n\treturn lhs->interval.start < rhs->interval.start;\n}\n\nvoid _sortSegmentAllSubrangesLinkedList(IMLSegment* imlSegment)\n{\n\traLivenessRange* subrangeList[4096 + 1];\n\tsint32 count = 0;\n\t// disassemble linked list\n\traLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;\n\twhile (subrangeItr)\n\t{\n\t\tcemu_assert(count < 4096);\n\t\tsubrangeList[count] = subrangeItr;\n\t\tcount++;\n\t\t// next\n\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t}\n\tif (count == 0)\n\t{\n\t\timlSegment->raInfo.linkedList_allSubranges = nullptr;\n\t\treturn;\n\t}\n\t// sort\n\tstd::sort(subrangeList, subrangeList + count, _livenessRangeStartCompare);\n\t// reassemble linked list\n\tsubrangeList[count] = nullptr;\n\timlSegment->raInfo.linkedList_allSubranges = subrangeList[0];\n\tsubrangeList[0]->link_allSegmentRanges.prev = nullptr;\n\tsubrangeList[0]->link_allSegmentRanges.next = subrangeList[1];\n\tfor (sint32 i = 1; i < count; i++)\n\t{\n\t\tsubrangeList[i]->link_allSegmentRanges.prev = subrangeList[i - 1];\n\t\tsubrangeList[i]->link_allSegmentRanges.next = subrangeList[i + 1];\n\t}\n\t// validate list\n#if DEBUG_RA_EXTRA_VALIDATION\n\tsint32 count2 = 0;\n\tsubrangeItr = imlSegment->raInfo.linkedList_allSubranges;\n\traInstructionEdge currentStartPosition;\n\tcurrentStartPosition.SetRaw(RA_INTER_RANGE_START);\n\twhile (subrangeItr)\n\t{\n\t\tcount2++;\n\t\tif (subrangeItr->interval2.start < currentStartPosition)\n\t\t\tassert_dbg();\n\t\tcurrentStartPosition = subrangeItr->interval2.start;\n\t\t// next\n\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t}\n\tif (count != count2)\n\t\tassert_dbg();\n#endif\n}\n\nstd::unordered_map<IMLRegID, raLivenessRange*>& IMLRA_GetSubrangeMap(IMLSegment* imlSegment)\n{\n\treturn imlSegment->raInfo.linkedList_perVirtualRegister;\n}\n\nraLivenessRange* IMLRA_GetSubrange(IMLSegment* imlSegment, IMLRegID regId)\n{\n\tauto it = imlSegment->raInfo.linkedList_perVirtualRegister.find(regId);\n\tif (it == imlSegment->raInfo.linkedList_perVirtualRegister.end())\n\t\treturn nullptr;\n\treturn it->second;\n}\n\nstruct raFixedRegRequirementWithVGPR\n{\n\traFixedRegRequirementWithVGPR(raInstructionEdge pos, IMLPhysRegisterSet allowedReg, IMLRegID regId)\n\t\t: pos(pos), allowedReg(allowedReg), regId(regId) {}\n\n\traInstructionEdge pos;\n\tIMLPhysRegisterSet allowedReg;\n\tIMLRegID regId;\n};\n\nstd::vector<raFixedRegRequirementWithVGPR> IMLRA_BuildSegmentInstructionFixedRegList(IMLSegment* imlSegment)\n{\n\tstd::vector<raFixedRegRequirementWithVGPR> frrList;\n\tsize_t index = 0;\n\twhile (index < imlSegment->imlList.size())\n\t{\n\t\tIMLFixedRegisters fixedRegs;\n\t\tGetInstructionFixedRegisters(&imlSegment->imlList[index], fixedRegs);\n\t\traInstructionEdge pos;\n\t\tpos.Set(index, true);\n\t\tfor (auto& fixedRegAccess : fixedRegs.listInput)\n\t\t{\n\t\t\tfrrList.emplace_back(pos, fixedRegAccess.physRegSet, fixedRegAccess.reg.IsValid() ? fixedRegAccess.reg.GetRegID() : IMLRegID_INVALID);\n\t\t}\n\t\tpos = pos + 1;\n\t\tfor (auto& fixedRegAccess : fixedRegs.listOutput)\n\t\t{\n\t\t\tfrrList.emplace_back(pos, fixedRegAccess.physRegSet, fixedRegAccess.reg.IsValid() ? fixedRegAccess.reg.GetRegID() : IMLRegID_INVALID);\n\t\t}\n\t\tindex++;\n\t}\n\treturn frrList;\n}\n\nboost::container::small_vector<raLivenessRange*, 8> IMLRA_GetRangeWithFixedRegReservationOverlappingPos(IMLSegment* imlSegment, raInstructionEdge pos, IMLPhysReg physReg)\n{\n\tboost::container::small_vector<raLivenessRange*, 8> rangeList;\n\tfor (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange; currentRange = currentRange->link_allSegmentRanges.next)\n\t{\n\t\tif (!currentRange->interval.ContainsEdge(pos))\n\t\t\tcontinue;\n\t\tIMLPhysRegisterSet allowedRegs;\n\t\tif (!currentRange->GetAllowedRegistersEx(allowedRegs))\n\t\t\tcontinue;\n\t\tif (allowedRegs.IsAvailable(physReg))\n\t\t\trangeList.emplace_back(currentRange);\n\t}\n\treturn rangeList;\n}\n\nvoid IMLRA_HandleFixedRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment)\n{\n\t// first pass - iterate over all ranges with fixed register requirements and split them if they cross the segment border\n\t// todo - this pass currently creates suboptimal results by splitting all ranges that cross the segment border if they have any fixed register requirement. This can be avoided in some cases\n\tfor (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange;)\n\t{\n\t\tIMLPhysRegisterSet allowedRegs;\n\t\tif(currentRange->list_fixedRegRequirements.empty())\n\t\t{\n\t\t\tcurrentRange = currentRange->link_allSegmentRanges.next;\n\t\t\tcontinue; // since we run this pass for every segment we dont need to do global checks here for clusters which may not even have fixed register requirements\n\t\t}\n\t\tif (!currentRange->GetAllowedRegistersEx(allowedRegs))\n\t\t{\n\t\t\tcurrentRange = currentRange->link_allSegmentRanges.next;\n\t\t\tcontinue;\n\t\t}\n\t\tif (currentRange->interval.ExtendsPreviousSegment() || currentRange->interval.ExtendsIntoNextSegment())\n\t\t{\n\t\t\traLivenessRange* nextRange = currentRange->link_allSegmentRanges.next;\n\t\t\tIMLRA_ExplodeRangeCluster(ppcImlGenContext, currentRange);\n\t\t\tcurrentRange = nextRange;\n\t\t\tcontinue;\n\t\t}\n\t\tcurrentRange = currentRange->link_allSegmentRanges.next;\n\t}\n\t// second pass - look for ranges with conflicting fixed register requirements and split these too (locally)\n\tfor (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange; currentRange = currentRange->link_allSegmentRanges.next)\n\t{\n\t\tIMLPhysRegisterSet allowedRegs;\n\t\tif (currentRange->list_fixedRegRequirements.empty())\n\t\t\tcontinue; // we dont need to check whole clusters because the pass above guarantees that there are no ranges with fixed register requirements that extend outside of this segment\n\t\tif (!currentRange->GetAllowedRegistersEx(allowedRegs))\n\t\t\tcontinue;\n\t\tif (allowedRegs.HasAnyAvailable())\n\t\t\tcontinue;\n\t\tcemu_assert_unimplemented();\n\t}\n\t// third pass - assign fixed registers, split ranges if needed\n\tstd::vector<raFixedRegRequirementWithVGPR> frr = IMLRA_BuildSegmentInstructionFixedRegList(imlSegment);\n\tstd::unordered_map<IMLPhysReg, IMLRegID> lastVGPR;\n\tfor (size_t i = 0; i < frr.size(); i++)\n\t{\n\t\traFixedRegRequirementWithVGPR& entry = frr[i];\n\t\t// we currently only handle fixed register requirements with a single register\n\t\t// with one exception: When regId is IMLRegID_INVALID then the entry acts as a list of reserved registers\n\t\tcemu_assert_debug(entry.regId == IMLRegID_INVALID || entry.allowedReg.HasExactlyOneAvailable());\n\t\tfor (IMLPhysReg physReg = entry.allowedReg.GetFirstAvailableReg(); physReg >= 0; physReg = entry.allowedReg.GetNextAvailableReg(physReg + 1))\n\t\t{\n\t\t\t// check if the assigned vGPR has changed\n\t\t\tbool vgprHasChanged = false;\n\t\t\tauto it = lastVGPR.find(physReg);\n\t\t\tif (it != lastVGPR.end())\n\t\t\t\tvgprHasChanged = it->second != entry.regId;\n\t\t\telse\n\t\t\t\tvgprHasChanged = true;\n\t\t\tlastVGPR[physReg] = entry.regId;\n\n\t\t\tif (!vgprHasChanged)\n\t\t\t\tcontinue;\n\n\t\t\tboost::container::small_vector<raLivenessRange*, 8> overlappingRanges = IMLRA_GetRangeWithFixedRegReservationOverlappingPos(imlSegment, entry.pos, physReg);\n\t\t\tif (entry.regId != IMLRegID_INVALID)\n\t\t\t\tcemu_assert_debug(!overlappingRanges.empty()); // there should always be at least one range that overlaps corresponding to the fixed register requirement, except for IMLRegID_INVALID which is used to indicate reserved registers\n\n\t\t\tfor (auto& range : overlappingRanges)\n\t\t\t{\n\t\t\t\tif (range->interval.start < entry.pos)\n\t\t\t\t{\n\t\t\t\t\tIMLRA_SplitRange(ppcImlGenContext, range, entry.pos, true);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// finally iterate ranges and assign fixed registers\n\tfor (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange; currentRange = currentRange->link_allSegmentRanges.next)\n\t{\n\t\tIMLPhysRegisterSet allowedRegs;\n\t\tif (currentRange->list_fixedRegRequirements.empty())\n\t\t\tcontinue; // we dont need to check whole clusters because the pass above guarantees that there are no ranges with fixed register requirements that extend outside of this segment\n\t\tif (!currentRange->GetAllowedRegistersEx(allowedRegs))\n\t\t{\n\t\t\tcemu_assert_debug(currentRange->list_fixedRegRequirements.empty());\n\t\t\tcontinue;\n\t\t}\n\t\tcemu_assert_debug(allowedRegs.HasExactlyOneAvailable());\n\t\tcurrentRange->SetPhysicalRegister(allowedRegs.GetFirstAvailableReg());\n\t}\n\t// DEBUG - check for collisions and make sure all ranges with fixed register requirements got their physical register assigned\n#if DEBUG_RA_EXTRA_VALIDATION\n\tfor (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange; currentRange = currentRange->link_allSegmentRanges.next)\n\t{\n\t\tIMLPhysRegisterSet allowedRegs;\n\t\tif (!currentRange->HasPhysicalRegister())\n\t\t\tcontinue;\n\t\tfor (raLivenessRange* currentRange2 = imlSegment->raInfo.linkedList_allSubranges; currentRange2; currentRange2 = currentRange2->link_allSegmentRanges.next)\n\t\t{\n\t\t\tif (currentRange == currentRange2)\n\t\t\t\tcontinue;\n\t\t\tif (currentRange->interval2.IsOverlapping(currentRange2->interval2))\n\t\t\t{\n\t\t\t\tcemu_assert_debug(currentRange->GetPhysicalRegister() != currentRange2->GetPhysicalRegister());\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n\n// we should not split ranges on instructions with tied registers (i.e. where a register encoded as a single parameter is both input and output)\n// otherwise the RA algorithm has to assign both ranges the same physical register (not supported yet) and the point of splitting to fit another range is nullified\nvoid IMLRA_MakeSafeSplitPosition(IMLSegment* imlSegment, raInstructionEdge& pos)\n{\n\t// we ignore the instruction for now and just always make it a safe split position\n\tcemu_assert_debug(pos.IsInstructionIndex());\n\tif (pos.IsOnOutputEdge())\n\t\tpos = pos - 1;\n}\n\n// convenience wrapper for IMLRA_MakeSafeSplitPosition\nvoid IMLRA_MakeSafeSplitDistance(IMLSegment* imlSegment, raInstructionEdge startPos, sint32& distance)\n{\n\tcemu_assert_debug(startPos.IsInstructionIndex());\n\tcemu_assert_debug(distance >= 0);\n\traInstructionEdge endPos = startPos + distance;\n\tIMLRA_MakeSafeSplitPosition(imlSegment, endPos);\n\tif (endPos < startPos)\n\t{\n\t\tdistance = 0;\n\t\treturn;\n\t}\n\tdistance = endPos.GetRaw() - startPos.GetRaw();\n}\n\nstatic void DbgVerifyAllRanges(IMLRegisterAllocatorContext& ctx);\n\nclass RASpillStrategy\n{\n  public:\n\tvirtual void Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) = 0;\n\n\tsint32 GetCost()\n\t{\n\t\treturn strategyCost;\n\t}\n\n  protected:\n\tvoid ResetCost()\n\t{\n\t\tstrategyCost = INT_MAX;\n\t}\n\n\tsint32 strategyCost;\n};\n\nclass RASpillStrategy_LocalRangeHoleCutting : public RASpillStrategy\n{\n  public:\n\tvoid Reset()\n\t{\n\t\tlocalRangeHoleCutting.distance = -1;\n\t\tlocalRangeHoleCutting.largestHoleSubrange = nullptr;\n\t\tResetCost();\n\t}\n\n\tvoid Evaluate(IMLSegment* imlSegment, raLivenessRange* currentRange, const IMLRALivenessTimeline& timeline, const IMLPhysRegisterSet& allowedRegs)\n\t{\n\t\traInstructionEdge currentRangeStart = currentRange->interval.start;\n\t\tsint32 requiredSize2 = currentRange->interval.GetPreciseDistance();\n\t\tcemu_assert_debug(localRangeHoleCutting.distance == -1);\n\t\tcemu_assert_debug(strategyCost == INT_MAX);\n\t\tif (!currentRangeStart.ConnectsToPreviousSegment())\n\t\t{\n\t\t\tcemu_assert_debug(currentRangeStart.GetRaw() >= 0);\n\t\t\tfor (auto candidate : timeline.activeRanges)\n\t\t\t{\n\t\t\t\tif (candidate->interval.ExtendsIntoNextSegment())\n\t\t\t\t\tcontinue;\n\t\t\t\t// new checks (Oct 2024):\n\t\t\t\tif (candidate == currentRange)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (candidate->GetPhysicalRegister() < 0)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (!allowedRegs.IsAvailable(candidate->GetPhysicalRegister()))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tsint32 distance2 = IMLRA_CountDistanceUntilNextUse(candidate, currentRangeStart);\n\t\t\t\tIMLRA_MakeSafeSplitDistance(imlSegment, currentRangeStart, distance2);\n\t\t\t\tif (distance2 < 2)\n\t\t\t\t\tcontinue;\n\t\t\t\tcemu_assert_debug(currentRangeStart.IsInstructionIndex());\n\t\t\t\tdistance2 = std::min<sint32>(distance2, imlSegment->imlList.size() * 2 - currentRangeStart.GetRaw()); // limit distance to end of segment\n\t\t\t\t// calculate split cost of candidate\n\t\t\t\tsint32 cost = IMLRA_CalculateAdditionalCostAfterSplit(candidate, currentRangeStart + distance2);\n\t\t\t\t// calculate additional split cost of currentRange if hole is not large enough\n\t\t\t\tif (distance2 < requiredSize2)\n\t\t\t\t{\n\t\t\t\t\tcost += IMLRA_CalculateAdditionalCostAfterSplit(currentRange, currentRangeStart + distance2);\n\t\t\t\t\t// we also slightly increase cost in relation to the remaining length (in order to make the algorithm prefer larger holes)\n\t\t\t\t\tcost += (requiredSize2 - distance2) / 10;\n\t\t\t\t}\n\t\t\t\t// compare cost with previous candidates\n\t\t\t\tif (cost < strategyCost)\n\t\t\t\t{\n\t\t\t\t\tstrategyCost = cost;\n\t\t\t\t\tlocalRangeHoleCutting.distance = distance2;\n\t\t\t\t\tlocalRangeHoleCutting.largestHoleSubrange = candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override\n\t{\n\t\tcemu_assert_debug(strategyCost != INT_MAX);\n\t\tsint32 requiredSize2 = currentRange->interval.GetPreciseDistance();\n\t\traInstructionEdge currentRangeStart = currentRange->interval.start;\n\n\t\traInstructionEdge holeStartPosition = currentRangeStart;\n\t\traInstructionEdge holeEndPosition = currentRangeStart + localRangeHoleCutting.distance;\n\t\traLivenessRange* collisionRange = localRangeHoleCutting.largestHoleSubrange;\n\n\t\tif (collisionRange->interval.start < holeStartPosition)\n\t\t{\n\t\t\tcollisionRange = IMLRA_SplitRange(nullptr, collisionRange, holeStartPosition, true);\n\t\t\tcemu_assert_debug(!collisionRange || collisionRange->interval.start >= holeStartPosition); // verify if splitting worked at all, tail must be on or after the split point\n\t\t\tcemu_assert_debug(!collisionRange || collisionRange->interval.start >= holeEndPosition);\t// also verify that the trimmed hole is actually big enough\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented(); // we still need to trim?\n\t\t}\n\t\t// we may also have to cut the current range to fit partially into the hole\n\t\tif (requiredSize2 > localRangeHoleCutting.distance)\n\t\t{\n\t\t\traLivenessRange* tailRange = IMLRA_SplitRange(nullptr, currentRange, currentRangeStart + localRangeHoleCutting.distance, true);\n\t\t\tif (tailRange)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(tailRange->list_fixedRegRequirements.empty()); // we are not allowed to unassign fixed registers\n\t\t\t\ttailRange->UnsetPhysicalRegister();\n\t\t\t}\n\t\t}\n\t\t// verify that the hole is large enough\n\t\tif (collisionRange)\n\t\t{\n\t\t\tcemu_assert_debug(!collisionRange->interval.IsOverlapping(currentRange->interval));\n\t\t}\n\t}\n\n  private:\n\tstruct\n\t{\n\t\tsint32 distance;\n\t\traLivenessRange* largestHoleSubrange;\n\t} localRangeHoleCutting;\n};\n\nclass RASpillStrategy_AvailableRegisterHole : public RASpillStrategy\n{\n\t// split current range (this is generally only a good choice when the current range is long but has few usages)\n  public:\n\tvoid Reset()\n\t{\n\t\tResetCost();\n\t\tavailableRegisterHole.distance = -1;\n\t\tavailableRegisterHole.physRegister = -1;\n\t}\n\n\tvoid Evaluate(IMLSegment* imlSegment, raLivenessRange* currentRange, const IMLRALivenessTimeline& timeline, const IMLPhysRegisterSet& localAvailableRegsMask, const IMLPhysRegisterSet& allowedRegs)\n\t{\n\t\tsint32 requiredSize2 = currentRange->interval.GetPreciseDistance();\n\n\t\traInstructionEdge currentRangeStart = currentRange->interval.start;\n\t\tcemu_assert_debug(strategyCost == INT_MAX);\n\t\tavailableRegisterHole.distance = -1;\n\t\tavailableRegisterHole.physRegister = -1;\n\t\tif (currentRangeStart.GetRaw() >= 0)\n\t\t{\n\t\t\tif (localAvailableRegsMask.HasAnyAvailable())\n\t\t\t{\n\t\t\t\tsint32 physRegItr = -1;\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\tphysRegItr = localAvailableRegsMask.GetNextAvailableReg(physRegItr + 1);\n\t\t\t\t\tif (physRegItr < 0)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tif (!allowedRegs.IsAvailable(physRegItr))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t// get size of potential hole for this register\n\t\t\t\t\tsint32 distance = PPCRecRA_countDistanceUntilNextLocalPhysRegisterUse(imlSegment, currentRangeStart, physRegItr);\n\n\t\t\t\t\t// some instructions may require the same register for another range, check the distance here\n\t\t\t\t\tsint32 distUntilFixedReg = IMLRA_CountDistanceUntilFixedRegUsage(imlSegment, currentRangeStart, distance, currentRange->GetVirtualRegister(), physRegItr);\n\t\t\t\t\tif (distUntilFixedReg < distance)\n\t\t\t\t\t\tdistance = distUntilFixedReg;\n\n\t\t\t\t\tIMLRA_MakeSafeSplitDistance(imlSegment, currentRangeStart, distance);\n\t\t\t\t\tif (distance < 2)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t// calculate additional cost due to split\n\t\t\t\t\tcemu_assert_debug(distance < requiredSize2); // should always be true otherwise previous step would have selected this register?\n\t\t\t\t\tsint32 cost = IMLRA_CalculateAdditionalCostAfterSplit(currentRange, currentRangeStart + distance);\n\t\t\t\t\t// add small additional cost for the remaining range (prefer larger holes)\n\t\t\t\t\tcost += ((requiredSize2 - distance) / 2) / 10;\n\t\t\t\t\tif (cost < strategyCost)\n\t\t\t\t\t{\n\t\t\t\t\t\tstrategyCost = cost;\n\t\t\t\t\t\tavailableRegisterHole.distance = distance;\n\t\t\t\t\t\tavailableRegisterHole.physRegister = physRegItr;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override\n\t{\n\t\tcemu_assert_debug(strategyCost != INT_MAX);\n\t\traInstructionEdge currentRangeStart = currentRange->interval.start;\n\t\t// use available register\n\t\traLivenessRange* tailRange = IMLRA_SplitRange(nullptr, currentRange, currentRangeStart + availableRegisterHole.distance, true);\n\t\tif (tailRange)\n\t\t{\n\t\t\tcemu_assert_debug(tailRange->list_fixedRegRequirements.empty()); // we are not allowed to unassign fixed registers\n\t\t\ttailRange->UnsetPhysicalRegister();\n\t\t}\n\t}\n\n  private:\n\tstruct\n\t{\n\t\tsint32 physRegister;\n\t\tsint32 distance; // size of hole\n\t} availableRegisterHole;\n};\n\nclass RASpillStrategy_ExplodeRange : public RASpillStrategy\n{\n  public:\n\tvoid Reset()\n\t{\n\t\tResetCost();\n\t\texplodeRange.range = nullptr;\n\t\texplodeRange.distance = -1;\n\t}\n\n\tvoid Evaluate(IMLSegment* imlSegment, raLivenessRange* currentRange, const IMLRALivenessTimeline& timeline, const IMLPhysRegisterSet& allowedRegs)\n\t{\n\t\traInstructionEdge currentRangeStart = currentRange->interval.start;\n\t\tif (currentRangeStart.ConnectsToPreviousSegment())\n\t\t\tcurrentRangeStart.Set(0, true);\n\t\tsint32 requiredSize2 = currentRange->interval.GetPreciseDistance();\n\t\tcemu_assert_debug(strategyCost == INT_MAX);\n\t\texplodeRange.range = nullptr;\n\t\texplodeRange.distance = -1;\n\t\tfor (auto candidate : timeline.activeRanges)\n\t\t{\n\t\t\tif (!candidate->interval.ExtendsIntoNextSegment())\n\t\t\t\tcontinue;\n\t\t\t// new checks (Oct 2024):\n\t\t\tif (candidate == currentRange)\n\t\t\t\tcontinue;\n\t\t\tif (candidate->GetPhysicalRegister() < 0)\n\t\t\t\tcontinue;\n\t\t\tif (!allowedRegs.IsAvailable(candidate->GetPhysicalRegister()))\n\t\t\t\tcontinue;\n\n\t\t\tsint32 distance = IMLRA_CountDistanceUntilNextUse(candidate, currentRangeStart);\n\t\t\tIMLRA_MakeSafeSplitDistance(imlSegment, currentRangeStart, distance);\n\t\t\tif (distance < 2)\n\t\t\t\tcontinue;\n\t\t\tsint32 cost = IMLRA_CalculateAdditionalCostOfRangeExplode(candidate);\n\t\t\t// if the hole is not large enough, add cost of splitting current subrange\n\t\t\tif (distance < requiredSize2)\n\t\t\t{\n\t\t\t\tcost += IMLRA_CalculateAdditionalCostAfterSplit(currentRange, currentRangeStart + distance);\n\t\t\t\t// add small additional cost for the remaining range (prefer larger holes)\n\t\t\t\tcost += ((requiredSize2 - distance) / 2) / 10;\n\t\t\t}\n\t\t\t// compare with current best candidate for this strategy\n\t\t\tif (cost < strategyCost)\n\t\t\t{\n\t\t\t\tstrategyCost = cost;\n\t\t\t\texplodeRange.distance = distance;\n\t\t\t\texplodeRange.range = candidate;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override\n\t{\n\t\traInstructionEdge currentRangeStart = currentRange->interval.start;\n\t\tif (currentRangeStart.ConnectsToPreviousSegment())\n\t\t\tcurrentRangeStart.Set(0, true);\n\t\tsint32 requiredSize2 = currentRange->interval.GetPreciseDistance();\n\t\t// explode range\n\t\tIMLRA_ExplodeRangeCluster(nullptr, explodeRange.range);\n\t\t// split current subrange if necessary\n\t\tif (requiredSize2 > explodeRange.distance)\n\t\t{\n\t\t\traLivenessRange* tailRange = IMLRA_SplitRange(nullptr, currentRange, currentRangeStart + explodeRange.distance, true);\n\t\t\tif (tailRange)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(tailRange->list_fixedRegRequirements.empty()); // we are not allowed to unassign fixed registers\n\t\t\t\ttailRange->UnsetPhysicalRegister();\n\t\t\t}\n\t\t}\n\t}\n\n  private:\n\tstruct\n\t{\n\t\traLivenessRange* range;\n\t\tsint32 distance; // size of hole\n\t\t// note: If we explode a range, we still have to check the size of the hole that becomes available, if too small then we need to add cost of splitting local subrange\n\t} explodeRange;\n};\n\nclass RASpillStrategy_ExplodeRangeInter : public RASpillStrategy\n{\n  public:\n\tvoid Reset()\n\t{\n\t\tResetCost();\n\t\texplodeRange.range = nullptr;\n\t\texplodeRange.distance = -1;\n\t}\n\n\tvoid Evaluate(IMLSegment* imlSegment, raLivenessRange* currentRange, const IMLRALivenessTimeline& timeline, const IMLPhysRegisterSet& allowedRegs)\n\t{\n\t\t// explode the range with the least cost\n\t\tcemu_assert_debug(strategyCost == INT_MAX);\n\t\tcemu_assert_debug(explodeRange.range == nullptr && explodeRange.distance == -1);\n\t\tfor (auto candidate : timeline.activeRanges)\n\t\t{\n\t\t\tif (!candidate->interval.ExtendsIntoNextSegment())\n\t\t\t\tcontinue;\n\t\t\t// only select candidates that clash with current subrange\n\t\t\tif (candidate->GetPhysicalRegister() < 0 && candidate != currentRange)\n\t\t\t\tcontinue;\n\t\t\t// and also filter any that dont meet fixed register requirements\n\t\t\tif (!allowedRegs.IsAvailable(candidate->GetPhysicalRegister()))\n\t\t\t\tcontinue;\n\t\t\tsint32 cost;\n\t\t\tcost = IMLRA_CalculateAdditionalCostOfRangeExplode(candidate);\n\t\t\t// compare with current best candidate for this strategy\n\t\t\tif (cost < strategyCost)\n\t\t\t{\n\t\t\t\tstrategyCost = cost;\n\t\t\t\texplodeRange.distance = INT_MAX;\n\t\t\t\texplodeRange.range = candidate;\n\t\t\t}\n\t\t}\n\t\t// add current range as a candidate too\n\t\tsint32 ownCost;\n\t\townCost = IMLRA_CalculateAdditionalCostOfRangeExplode(currentRange);\n\t\tif (ownCost < strategyCost)\n\t\t{\n\t\t\tstrategyCost = ownCost;\n\t\t\texplodeRange.distance = INT_MAX;\n\t\t\texplodeRange.range = currentRange;\n\t\t}\n\t}\n\n\tvoid Apply(ppcImlGenContext_t* ctx, IMLSegment* imlSegment, raLivenessRange* currentRange) override\n\t{\n\t\tcemu_assert_debug(strategyCost != INT_MAX);\n\t\tIMLRA_ExplodeRangeCluster(ctx, explodeRange.range);\n\t}\n\n  private:\n\tstruct\n\t{\n\t\traLivenessRange* range;\n\t\tsint32 distance; // size of hole\n\t\t// note: If we explode a range, we still have to check the size of the hole that becomes available, if too small then we need to add cost of splitting local subrange\n\t}explodeRange;\n};\n\n// filter any registers from candidatePhysRegSet which cannot be used by currentRange due to fixed register requirements within the range that it occupies\nvoid IMLRA_FilterReservedFixedRegisterRequirementsForSegment(IMLRegisterAllocatorContext& ctx, raLivenessRange* currentRange, IMLPhysRegisterSet& candidatePhysRegSet)\n{\n\tIMLSegment* seg = currentRange->imlSegment;\n\tif (seg->imlList.empty())\n\t\treturn; // there can be no fixed register requirements if there are no instructions\n\n\traInstructionEdge firstPos = currentRange->interval.start;\n\tif (currentRange->interval.start.ConnectsToPreviousSegment())\n\t\tfirstPos.SetRaw(0);\n\telse if (currentRange->interval.start.ConnectsToNextSegment())\n\t\tfirstPos.Set(seg->imlList.size() - 1, false);\n\n\traInstructionEdge lastPos = currentRange->interval.end;\n\tif (currentRange->interval.end.ConnectsToPreviousSegment())\n\t\tlastPos.SetRaw(0);\n\telse if (currentRange->interval.end.ConnectsToNextSegment())\n\t\tlastPos.Set(seg->imlList.size() - 1, false);\n\tcemu_assert_debug(firstPos <= lastPos);\n\n\tIMLRegID ourRegId = currentRange->GetVirtualRegister();\n\n\tIMLFixedRegisters fixedRegs;\n\tif (firstPos.IsOnOutputEdge())\n\t\tGetInstructionFixedRegisters(seg->imlList.data() + firstPos.GetInstructionIndex(), fixedRegs);\n\tfor (raInstructionEdge currentPos = firstPos; currentPos <= lastPos; ++currentPos)\n\t{\n\t\tif (currentPos.IsOnInputEdge())\n\t\t{\n\t\t\tGetInstructionFixedRegisters(seg->imlList.data() + currentPos.GetInstructionIndex(), fixedRegs);\n\t\t}\n\t\tauto& fixedRegAccess = currentPos.IsOnInputEdge() ? fixedRegs.listInput : fixedRegs.listOutput;\n\t\tfor (auto& fixedRegLoc : fixedRegAccess)\n\t\t{\n\t\t\tif (fixedRegLoc.reg.IsInvalid() || fixedRegLoc.reg.GetRegID() != ourRegId)\n\t\t\t\tcandidatePhysRegSet.RemoveRegisters(fixedRegLoc.physRegSet);\n\t\t}\n\t}\n}\n\n// filter out any registers along the range cluster\nvoid IMLRA_FilterReservedFixedRegisterRequirementsForCluster(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment, raLivenessRange* currentRange, IMLPhysRegisterSet& candidatePhysRegSet)\n{\n\tcemu_assert_debug(currentRange->imlSegment == imlSegment);\n\tif (currentRange->interval.ExtendsPreviousSegment() || currentRange->interval.ExtendsIntoNextSegment())\n\t{\n\t\tauto clusterRanges = currentRange->GetAllSubrangesInCluster();\n\t\tfor (auto& rangeIt : clusterRanges)\n\t\t{\n\t\t\tIMLRA_FilterReservedFixedRegisterRequirementsForSegment(ctx, rangeIt, candidatePhysRegSet);\n\t\t\tif (!candidatePhysRegSet.HasAnyAvailable())\n\t\t\t\tbreak;\n\t\t}\n\t\treturn;\n\t}\n\tIMLRA_FilterReservedFixedRegisterRequirementsForSegment(ctx, currentRange, candidatePhysRegSet);\n}\n\nbool IMLRA_AssignSegmentRegisters(IMLRegisterAllocatorContext& ctx, ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment)\n{\n\t// sort subranges ascending by start index\n\t_sortSegmentAllSubrangesLinkedList(imlSegment);\n\n\tIMLRALivenessTimeline livenessTimeline;\n\traLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;\n\traInstructionEdge lastInstructionEdge;\n\tlastInstructionEdge.SetRaw(RA_INTER_RANGE_END);\n\n\tstruct\n\t{\n\t\tRASpillStrategy_LocalRangeHoleCutting localRangeHoleCutting;\n\t\tRASpillStrategy_AvailableRegisterHole availableRegisterHole;\n\t\tRASpillStrategy_ExplodeRange explodeRange;\n\t\t// for ranges that connect to follow up segments:\n\t\tRASpillStrategy_ExplodeRangeInter explodeRangeInter;\n\t} strategy;\n\n\twhile (subrangeItr)\n\t{\n\t\traInstructionEdge currentRangeStart = subrangeItr->interval.start; // used to be currentIndex before refactor\n\t\tPPCRecRA_debugValidateSubrange(subrangeItr);\n\n\t\tlivenessTimeline.ExpireRanges((currentRangeStart > lastInstructionEdge) ? lastInstructionEdge : currentRangeStart); // expire up to currentIndex (inclusive), but exclude infinite ranges\n\n\t\t// if subrange already has register assigned then add it to the active list and continue\n\t\tif (subrangeItr->GetPhysicalRegister() >= 0)\n\t\t{\n\t\t\t// verify if register is actually available\n#if DEBUG_RA_EXTRA_VALIDATION\n\t\t\tfor (auto& liverangeItr : livenessTimeline.activeRanges)\n\t\t\t{\n\t\t\t\t// check for register mismatch\n\t\t\t\tcemu_assert_debug(liverangeItr->GetPhysicalRegister() != subrangeItr->GetPhysicalRegister());\n\t\t\t}\n#endif\n\t\t\tlivenessTimeline.AddActiveRange(subrangeItr);\n\t\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t\t\tcontinue;\n\t\t}\n\t\t// ranges with fixed register requirements should already have a phys register assigned\n\t\tif (!subrangeItr->list_fixedRegRequirements.empty())\n\t\t{\n\t\t\tcemu_assert_debug(subrangeItr->HasPhysicalRegister());\n\t\t}\n\t\t// find free register for current subrangeItr and segment\n\t\tIMLRegFormat regBaseFormat = ctx.GetBaseFormatByRegId(subrangeItr->GetVirtualRegister());\n\t\tIMLPhysRegisterSet candidatePhysRegSet = ctx.raParam->GetPhysRegPool(regBaseFormat);\n\t\tcemu_assert_debug(candidatePhysRegSet.HasAnyAvailable()); // no valid pool provided for this register type\n\n\t\tIMLPhysRegisterSet allowedRegs = subrangeItr->GetAllowedRegisters(candidatePhysRegSet);\n\t\tcemu_assert_debug(allowedRegs.HasAnyAvailable()); // if zero regs are available, then this range needs to be split to avoid mismatching register requirements (do this in the initial pass to keep the code here simpler)\n\t\tcandidatePhysRegSet &= allowedRegs;\n\n\t\tfor (auto& liverangeItr : livenessTimeline.activeRanges)\n\t\t{\n\t\t\tcemu_assert_debug(liverangeItr->GetPhysicalRegister() >= 0);\n\t\t\tcandidatePhysRegSet.SetReserved(liverangeItr->GetPhysicalRegister());\n\t\t}\n\t\t// check intersections with other ranges and determine allowed registers\n\t\tIMLPhysRegisterSet localAvailableRegsMask = candidatePhysRegSet; // mask of registers that are currently not used (does not include range checks in other segments)\n\t\tif (candidatePhysRegSet.HasAnyAvailable())\n\t\t{\n\t\t\t// check for overlaps on a global scale (subrangeItr can be part of a larger range cluster across multiple segments)\n\t\t\tPPCRecRA_MaskOverlappingPhysRegForGlobalRange(subrangeItr, candidatePhysRegSet);\n\t\t}\n\t\t// some target instructions may enforce specific registers (e.g. common on X86 where something like SHL <reg>, CL forces CL as the count register)\n\t\t// we determine the list of allowed registers here\n\t\t// this really only works if we assume single-register requirements (otherwise its better not to filter out early and instead allow register corrections later but we don't support this yet)\n\t\tif (candidatePhysRegSet.HasAnyAvailable())\n\t\t{\n\t\t\tIMLRA_FilterReservedFixedRegisterRequirementsForCluster(ctx, imlSegment, subrangeItr, candidatePhysRegSet);\n\t\t}\n\t\tif (candidatePhysRegSet.HasAnyAvailable())\n\t\t{\n\t\t\t// use free register\n\t\t\tsubrangeItr->SetPhysicalRegisterForCluster(candidatePhysRegSet.GetFirstAvailableReg());\n\t\t\tlivenessTimeline.AddActiveRange(subrangeItr);\n\t\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next; // next\n\t\t\tcontinue;\n\t\t}\n\t\t// there is no free register for the entire range\n\t\t// evaluate different strategies of splitting ranges to free up another register or shorten the current range\n\t\tstrategy.localRangeHoleCutting.Reset();\n\t\tstrategy.availableRegisterHole.Reset();\n\t\tstrategy.explodeRange.Reset();\n\t\t// cant assign register\n\t\t// there might be registers available, we just can't use them due to range conflicts\n\t\tRASpillStrategy* selectedStrategy = nullptr;\n\t\tauto SelectStrategyIfBetter = [&selectedStrategy](RASpillStrategy& newStrategy) {\n\t\t\tif (newStrategy.GetCost() == INT_MAX)\n\t\t\t\treturn;\n\t\t\tif (selectedStrategy == nullptr || newStrategy.GetCost() < selectedStrategy->GetCost())\n\t\t\t\tselectedStrategy = &newStrategy;\n\t\t};\n\n\t\tif (!subrangeItr->interval.ExtendsIntoNextSegment())\n\t\t{\n\t\t\t// range ends in current segment, use local strategies\n\t\t\t// evaluate strategy: Cut hole into local subrange\n\t\t\tstrategy.localRangeHoleCutting.Evaluate(imlSegment, subrangeItr, livenessTimeline, allowedRegs);\n\t\t\tSelectStrategyIfBetter(strategy.localRangeHoleCutting);\n\t\t\t// evaluate strategy: Split current range to fit in available holes\n\t\t\t// todo - are checks required to avoid splitting on the suffix instruction?\n\t\t\tstrategy.availableRegisterHole.Evaluate(imlSegment, subrangeItr, livenessTimeline, localAvailableRegsMask, allowedRegs);\n\t\t\tSelectStrategyIfBetter(strategy.availableRegisterHole);\n\t\t\t// evaluate strategy: Explode inter-segment ranges\n\t\t\tstrategy.explodeRange.Evaluate(imlSegment, subrangeItr, livenessTimeline, allowedRegs);\n\t\t\tSelectStrategyIfBetter(strategy.explodeRange);\n\t\t}\n\t\telse // if subrangeItr->interval2.ExtendsIntoNextSegment()\n\t\t{\n\t\t\tstrategy.explodeRangeInter.Reset();\n\t\t\tstrategy.explodeRangeInter.Evaluate(imlSegment, subrangeItr, livenessTimeline, allowedRegs);\n\t\t\tSelectStrategyIfBetter(strategy.explodeRangeInter);\n\t\t}\n\t\t// choose strategy\n\t\tif (selectedStrategy)\n\t\t{\n\t\t\tselectedStrategy->Apply(ppcImlGenContext, imlSegment, subrangeItr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// none of the evulated strategies can be applied, this should only happen if the segment extends into the next segment(s) for which we have no good strategy\n\t\t\tcemu_assert_debug(subrangeItr->interval.ExtendsPreviousSegment());\n\t\t\t// alternative strategy if we have no other choice: explode current range\n\t\t\tIMLRA_ExplodeRangeCluster(ppcImlGenContext, subrangeItr);\n\t\t}\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nvoid IMLRA_AssignRegisters(IMLRegisterAllocatorContext& ctx, ppcImlGenContext_t* ppcImlGenContext)\n{\n\t// start with frequently executed segments first\n\tsint32 maxLoopDepth = 0;\n\tfor (IMLSegment* segIt : ppcImlGenContext->segmentList2)\n\t{\n\t\tmaxLoopDepth = std::max(maxLoopDepth, segIt->loopDepth);\n\t}\n\t// assign fixed registers first\n\tfor (IMLSegment* segIt : ppcImlGenContext->segmentList2)\n\t\tIMLRA_HandleFixedRegisters(ppcImlGenContext, segIt);\n#if DEBUG_RA_EXTRA_VALIDATION\n\t// fixed registers are currently handled per-segment, but here we validate that they are assigned correctly on a global scope as well\n\tfor (IMLSegment* imlSegment : ppcImlGenContext->segmentList2)\n\t{\n\t\tfor (raLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges; currentRange; currentRange = currentRange->link_allSegmentRanges.next)\n\t\t{\n\t\t\tIMLPhysRegisterSet allowedRegs;\n\t\t\tif (!currentRange->GetAllowedRegistersEx(allowedRegs))\n\t\t\t{\n\t\t\t\tcemu_assert_debug(currentRange->list_fixedRegRequirements.empty());\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcemu_assert_debug(currentRange->HasPhysicalRegister() && allowedRegs.IsAvailable(currentRange->GetPhysicalRegister()));\n\t\t}\n\t}\n#endif\n\n\twhile (true)\n\t{\n\t\tbool done = false;\n\t\tfor (sint32 d = maxLoopDepth; d >= 0; d--)\n\t\t{\n\t\t\tfor (IMLSegment* segIt : ppcImlGenContext->segmentList2)\n\t\t\t{\n\t\t\t\tif (segIt->loopDepth != d)\n\t\t\t\t\tcontinue;\n\t\t\t\tdone = IMLRA_AssignSegmentRegisters(ctx, ppcImlGenContext, segIt);\n\t\t\t\tif (done == false)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (done == false)\n\t\t\t\tbreak;\n\t\t}\n\t\tif (done)\n\t\t\tbreak;\n\t}\n}\n\nvoid IMLRA_ReshapeForRegisterAllocation(ppcImlGenContext_t* ppcImlGenContext)\n{\n\t// insert empty segments after every non-taken branch if the linked segment has more than one input\n\t// this gives the register allocator more room to create efficient spill code\n\tsize_t segmentIndex = 0;\n\twhile (segmentIndex < ppcImlGenContext->segmentList2.size())\n\t{\n\t\tIMLSegment* imlSegment = ppcImlGenContext->segmentList2[segmentIndex];\n\t\tif (imlSegment->nextSegmentIsUncertain)\n\t\t{\n\t\t\tsegmentIndex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (imlSegment->nextSegmentBranchTaken == nullptr || imlSegment->nextSegmentBranchNotTaken == nullptr)\n\t\t{\n\t\t\tsegmentIndex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (imlSegment->nextSegmentBranchNotTaken->list_prevSegments.size() <= 1)\n\t\t{\n\t\t\tsegmentIndex++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (imlSegment->nextSegmentBranchNotTaken->isEnterable)\n\t\t{\n\t\t\tsegmentIndex++;\n\t\t\tcontinue;\n\t\t}\n\t\tPPCRecompilerIml_insertSegments(ppcImlGenContext, segmentIndex + 1, 1);\n\t\tIMLSegment* imlSegmentP0 = ppcImlGenContext->segmentList2[segmentIndex + 0];\n\t\tIMLSegment* imlSegmentP1 = ppcImlGenContext->segmentList2[segmentIndex + 1];\n\t\tIMLSegment* nextSegment = imlSegment->nextSegmentBranchNotTaken;\n\t\tIMLSegment_RemoveLink(imlSegmentP0, nextSegment);\n\t\tIMLSegment_SetLinkBranchNotTaken(imlSegmentP1, nextSegment);\n\t\tIMLSegment_SetLinkBranchNotTaken(imlSegmentP0, imlSegmentP1);\n\t\tsegmentIndex++;\n\t}\n\t// detect loops\n\tfor (size_t s = 0; s < ppcImlGenContext->segmentList2.size(); s++)\n\t{\n\t\tIMLSegment* imlSegment = ppcImlGenContext->segmentList2[s];\n\t\timlSegment->momentaryIndex = s;\n\t}\n\tfor (size_t s = 0; s < ppcImlGenContext->segmentList2.size(); s++)\n\t{\n\t\tIMLSegment* imlSegment = ppcImlGenContext->segmentList2[s];\n\t\tIMLRA_IdentifyLoop(ppcImlGenContext, imlSegment);\n\t}\n}\n\nIMLRARegAbstractLiveness* _GetAbstractRange(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment, IMLRegID regId)\n{\n\tauto& segMap = ctx.GetSegmentAbstractRangeMap(imlSegment);\n\tauto it = segMap.find(regId);\n\treturn it != segMap.end() ? &it->second : nullptr;\n}\n\n// scan instructions and establish register usage range for segment\nvoid IMLRA_CalculateSegmentMinMaxAbstractRanges(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment)\n{\n\tsize_t instructionIndex = 0;\n\tIMLUsedRegisters gprTracking;\n\tauto& segDistMap = ctx.GetSegmentAbstractRangeMap(imlSegment);\n\twhile (instructionIndex < imlSegment->imlList.size())\n\t{\n\t\timlSegment->imlList[instructionIndex].CheckRegisterUsage(&gprTracking);\n\t\tgprTracking.ForEachAccessedGPR([&](IMLReg gprReg, bool isWritten) {\n\t\t\tIMLRegID gprId = gprReg.GetRegID();\n\t\t\tauto it = segDistMap.find(gprId);\n\t\t\tif (it == segDistMap.end())\n\t\t\t{\n\t\t\t\tsegDistMap.try_emplace(gprId, gprReg.GetBaseFormat(), (sint32)instructionIndex, (sint32)instructionIndex + 1);\n\t\t\t\tctx.regIdToBaseFormat.try_emplace(gprId, gprReg.GetBaseFormat());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tit->second.TrackInstruction(instructionIndex);\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\t\tcemu_assert_debug(ctx.regIdToBaseFormat[gprId] == gprReg.GetBaseFormat()); // the base type per register always has to be the same\n#endif\n\t\t\t}\n\t\t});\n\t\tinstructionIndex++;\n\t}\n}\n\nvoid IMLRA_CalculateLivenessRanges(IMLRegisterAllocatorContext& ctx)\n{\n\t// for each register calculate min/max index of usage range within each segment\n\tsize_t dbgIndex = 0;\n\tfor (IMLSegment* segIt : ctx.deprGenContext->segmentList2)\n\t{\n\t\tcemu_assert_debug(segIt->momentaryIndex == dbgIndex);\n\t\tIMLRA_CalculateSegmentMinMaxAbstractRanges(ctx, segIt);\n\t\tdbgIndex++;\n\t}\n}\n\nraLivenessRange* PPCRecRA_convertToMappedRanges(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment, IMLRegID vGPR, IMLName name)\n{\n\tIMLRARegAbstractLiveness* abstractRange = _GetAbstractRange(ctx, imlSegment, vGPR);\n\tif (!abstractRange)\n\t\treturn nullptr;\n\tif (abstractRange->isProcessed)\n\t{\n\t\t// return already existing segment\n\t\traLivenessRange* existingRange = IMLRA_GetSubrange(imlSegment, vGPR);\n\t\tcemu_assert_debug(existingRange);\n\t\treturn existingRange;\n\t}\n\tabstractRange->isProcessed = true;\n\t// create subrange\n\tcemu_assert_debug(IMLRA_GetSubrange(imlSegment, vGPR) == nullptr);\n\tcemu_assert_debug(\n\t\t(abstractRange->usageStart == abstractRange->usageEnd && (abstractRange->usageStart == RA_INTER_RANGE_START || abstractRange->usageStart == RA_INTER_RANGE_END)) ||\n\t\tabstractRange->usageStart < abstractRange->usageEnd); // usageEnd is exclusive so it should always be larger\n\tsint32 inclusiveEnd = abstractRange->usageEnd;\n\tif (inclusiveEnd != RA_INTER_RANGE_START && inclusiveEnd != RA_INTER_RANGE_END)\n\t\tinclusiveEnd--; // subtract one, because usageEnd is exclusive, but the end value of the interval passed to createSubrange is inclusive\n\traInterval interval;\n\tinterval.SetInterval(abstractRange->usageStart, true, inclusiveEnd, true);\n\traLivenessRange* subrange = IMLRA_CreateRange(ctx.deprGenContext, imlSegment, vGPR, name, interval.start, interval.end);\n\t// traverse forward\n\tif (abstractRange->usageEnd == RA_INTER_RANGE_END)\n\t{\n\t\tif (imlSegment->nextSegmentBranchTaken)\n\t\t{\n\t\t\tIMLRARegAbstractLiveness* branchTakenRange = _GetAbstractRange(ctx, imlSegment->nextSegmentBranchTaken, vGPR);\n\t\t\tif (branchTakenRange && branchTakenRange->usageStart == RA_INTER_RANGE_START)\n\t\t\t{\n\t\t\t\tsubrange->subrangeBranchTaken = PPCRecRA_convertToMappedRanges(ctx, imlSegment->nextSegmentBranchTaken, vGPR, name);\n\t\t\t\tsubrange->subrangeBranchTaken->previousRanges.push_back(subrange);\n\t\t\t\tcemu_assert_debug(subrange->subrangeBranchTaken->interval.ExtendsPreviousSegment());\n\t\t\t}\n\t\t}\n\t\tif (imlSegment->nextSegmentBranchNotTaken)\n\t\t{\n\t\t\tIMLRARegAbstractLiveness* branchNotTakenRange = _GetAbstractRange(ctx, imlSegment->nextSegmentBranchNotTaken, vGPR);\n\t\t\tif (branchNotTakenRange && branchNotTakenRange->usageStart == RA_INTER_RANGE_START)\n\t\t\t{\n\t\t\t\tsubrange->subrangeBranchNotTaken = PPCRecRA_convertToMappedRanges(ctx, imlSegment->nextSegmentBranchNotTaken, vGPR, name);\n\t\t\t\tsubrange->subrangeBranchNotTaken->previousRanges.push_back(subrange);\n\t\t\t\tcemu_assert_debug(subrange->subrangeBranchNotTaken->interval.ExtendsPreviousSegment());\n\t\t\t}\n\t\t}\n\t}\n\t// traverse backward\n\tif (abstractRange->usageStart == RA_INTER_RANGE_START)\n\t{\n\t\tfor (auto& it : imlSegment->list_prevSegments)\n\t\t{\n\t\t\tIMLRARegAbstractLiveness* prevRange = _GetAbstractRange(ctx, it, vGPR);\n\t\t\tif (!prevRange)\n\t\t\t\tcontinue;\n\t\t\tif (prevRange->usageEnd == RA_INTER_RANGE_END)\n\t\t\t\tPPCRecRA_convertToMappedRanges(ctx, it, vGPR, name);\n\t\t}\n\t}\n\treturn subrange;\n}\n\nvoid IMLRA_UpdateOrAddSubrangeLocation(raLivenessRange* subrange, raInstructionEdge pos)\n{\n\tif (subrange->list_accessLocations.empty())\n\t{\n\t\tsubrange->list_accessLocations.emplace_back(pos);\n\t\treturn;\n\t}\n\tif(subrange->list_accessLocations.back().pos == pos)\n\t\treturn;\n\tcemu_assert_debug(subrange->list_accessLocations.back().pos < pos);\n\tsubrange->list_accessLocations.emplace_back(pos);\n}\n\n// take abstract range data and create LivenessRanges\nvoid IMLRA_ConvertAbstractToLivenessRanges(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment)\n{\n\tconst std::unordered_map<IMLRegID, raLivenessRange*>& regToSubrange = IMLRA_GetSubrangeMap(imlSegment);\n\n\tauto AddOrUpdateFixedRegRequirement = [&](IMLRegID regId, sint32 instructionIndex, bool isInput, const IMLPhysRegisterSet& physRegSet) {\n\t\traLivenessRange* subrange = regToSubrange.find(regId)->second;\n\t\tcemu_assert_debug(subrange);\n\t\traFixedRegRequirement tmp;\n\t\ttmp.pos.Set(instructionIndex, isInput);\n\t\ttmp.allowedReg = physRegSet;\n\t\tif (subrange->list_fixedRegRequirements.empty() || subrange->list_fixedRegRequirements.back().pos != tmp.pos)\n\t\t\tsubrange->list_fixedRegRequirements.push_back(tmp);\n\t};\n\n\t// convert abstract min-max ranges to liveness range objects\n\tauto& segMap = ctx.GetSegmentAbstractRangeMap(imlSegment);\n\tfor (auto& it : segMap)\n\t{\n\t\tif (it.second.isProcessed)\n\t\t\tcontinue;\n\t\tIMLRegID regId = it.first;\n\t\tPPCRecRA_convertToMappedRanges(ctx, imlSegment, regId, ctx.raParam->regIdToName.find(regId)->second);\n\t}\n\t// fill created ranges with read/write location indices\n\t// note that at this point there is only one range per register per segment\n\t// and the algorithm below relies on this\n\tsize_t index = 0;\n\tIMLUsedRegisters gprTracking;\n\twhile (index < imlSegment->imlList.size())\n\t{\n\t\timlSegment->imlList[index].CheckRegisterUsage(&gprTracking);\n\t\traInstructionEdge pos((sint32)index, true);\n\t\tgprTracking.ForEachReadGPR([&](IMLReg gprReg) {\n\t\t\tIMLRegID gprId = gprReg.GetRegID();\n\t\t\traLivenessRange* subrange = regToSubrange.find(gprId)->second;\n\t\t\tIMLRA_UpdateOrAddSubrangeLocation(subrange, pos);\n\t\t});\n\t\tpos = {(sint32)index, false};\n\t\tgprTracking.ForEachWrittenGPR([&](IMLReg gprReg) {\n\t\t\tIMLRegID gprId = gprReg.GetRegID();\n\t\t\traLivenessRange* subrange = regToSubrange.find(gprId)->second;\n\t\t\tIMLRA_UpdateOrAddSubrangeLocation(subrange, pos);\n\t\t});\n\t\t// check fixed register requirements\n\t\tIMLFixedRegisters fixedRegs;\n\t\tGetInstructionFixedRegisters(&imlSegment->imlList[index], fixedRegs);\n\t\tfor (auto& fixedRegAccess : fixedRegs.listInput)\n\t\t{\n\t\t\tif (fixedRegAccess.reg != IMLREG_INVALID)\n\t\t\t\tAddOrUpdateFixedRegRequirement(fixedRegAccess.reg.GetRegID(), index, true, fixedRegAccess.physRegSet);\n\t\t}\n\t\tfor (auto& fixedRegAccess : fixedRegs.listOutput)\n\t\t{\n\t\t\tif (fixedRegAccess.reg != IMLREG_INVALID)\n\t\t\t\tAddOrUpdateFixedRegRequirement(fixedRegAccess.reg.GetRegID(), index, false, fixedRegAccess.physRegSet);\n\t\t}\n\t\tindex++;\n\t}\n}\n\nvoid IMLRA_extendAbstractRangeToEndOfSegment(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment, IMLRegID regId)\n{\n\tauto& segDistMap = ctx.GetSegmentAbstractRangeMap(imlSegment);\n\tauto it = segDistMap.find(regId);\n\tif (it == segDistMap.end())\n\t{\n\t\tsint32 startIndex;\n\t\tif (imlSegment->HasSuffixInstruction())\n\t\t\tstartIndex = imlSegment->GetSuffixInstructionIndex();\n\t\telse\n\t\t\tstartIndex = RA_INTER_RANGE_END;\n\t\tsegDistMap.try_emplace((IMLRegID)regId, IMLRegFormat::INVALID_FORMAT, startIndex, RA_INTER_RANGE_END);\n\t}\n\telse\n\t{\n\t\tit->second.usageEnd = RA_INTER_RANGE_END;\n\t}\n}\n\nvoid IMLRA_extendAbstractRangeToBeginningOfSegment(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment, IMLRegID regId)\n{\n\tauto& segDistMap = ctx.GetSegmentAbstractRangeMap(imlSegment);\n\tauto it = segDistMap.find(regId);\n\tif (it == segDistMap.end())\n\t{\n\t\tsegDistMap.try_emplace((IMLRegID)regId, IMLRegFormat::INVALID_FORMAT, RA_INTER_RANGE_START, RA_INTER_RANGE_START);\n\t}\n\telse\n\t{\n\t\tit->second.usageStart = RA_INTER_RANGE_START;\n\t}\n\t// propagate backwards\n\tfor (auto& it : imlSegment->list_prevSegments)\n\t{\n\t\tIMLRA_extendAbstractRangeToEndOfSegment(ctx, it, regId);\n\t}\n}\n\nvoid IMLRA_connectAbstractRanges(IMLRegisterAllocatorContext& ctx, IMLRegID regId, IMLSegment** route, sint32 routeDepth)\n{\n#ifdef CEMU_DEBUG_ASSERT\n\tif (routeDepth < 2)\n\t\tassert_dbg();\n#endif\n\t// extend starting range to end of segment\n\tIMLRA_extendAbstractRangeToEndOfSegment(ctx, route[0], regId);\n\t// extend all the connecting segments in both directions\n\tfor (sint32 i = 1; i < (routeDepth - 1); i++)\n\t{\n\t\tIMLRA_extendAbstractRangeToEndOfSegment(ctx, route[i], regId);\n\t\tIMLRA_extendAbstractRangeToBeginningOfSegment(ctx, route[i], regId);\n\t}\n\t// extend the final segment towards the beginning\n\tIMLRA_extendAbstractRangeToBeginningOfSegment(ctx, route[routeDepth - 1], regId);\n}\n\nvoid _IMLRA_checkAndTryExtendRange(IMLRegisterAllocatorContext& ctx, IMLSegment* currentSegment, IMLRegID regID, sint32 distanceLeft, IMLSegment** route, sint32 routeDepth)\n{\n\tif (routeDepth >= 64)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Recompiler RA route maximum depth exceeded\\n\");\n\t\treturn;\n\t}\n\troute[routeDepth] = currentSegment;\n\n\tIMLRARegAbstractLiveness* range = _GetAbstractRange(ctx, currentSegment, regID);\n\n\tif (!range)\n\t{\n\t\t// measure distance over entire segment\n\t\tdistanceLeft -= (sint32)currentSegment->imlList.size();\n\t\tif (distanceLeft > 0)\n\t\t{\n\t\t\tif (currentSegment->nextSegmentBranchNotTaken)\n\t\t\t\t_IMLRA_checkAndTryExtendRange(ctx, currentSegment->nextSegmentBranchNotTaken, regID, distanceLeft, route, routeDepth + 1);\n\t\t\tif (currentSegment->nextSegmentBranchTaken)\n\t\t\t\t_IMLRA_checkAndTryExtendRange(ctx, currentSegment->nextSegmentBranchTaken, regID, distanceLeft, route, routeDepth + 1);\n\t\t}\n\t\treturn;\n\t}\n\telse\n\t{\n\t\t// measure distance to range\n\t\tif (range->usageStart == RA_INTER_RANGE_END)\n\t\t{\n\t\t\tif (distanceLeft < (sint32)currentSegment->imlList.size())\n\t\t\t\treturn; // range too far away\n\t\t}\n\t\telse if (range->usageStart != RA_INTER_RANGE_START && range->usageStart > distanceLeft)\n\t\t\treturn; // out of range\n\t\t// found close range -> connect ranges\n\t\tIMLRA_connectAbstractRanges(ctx, regID, route, routeDepth + 1);\n\t}\n}\n\nvoid PPCRecRA_checkAndTryExtendRange(IMLRegisterAllocatorContext& ctx, IMLSegment* currentSegment, IMLRARegAbstractLiveness* range, IMLRegID regID)\n{\n\tcemu_assert_debug(range->usageEnd >= 0);\n\t// count instructions to end of initial segment\n\tsint32 instructionsUntilEndOfSeg;\n\tif (range->usageEnd == RA_INTER_RANGE_END)\n\t\tinstructionsUntilEndOfSeg = 0;\n\telse\n\t\tinstructionsUntilEndOfSeg = (sint32)currentSegment->imlList.size() - range->usageEnd;\n\tcemu_assert_debug(instructionsUntilEndOfSeg >= 0);\n\tsint32 remainingScanDist = 45 - instructionsUntilEndOfSeg;\n\tif (remainingScanDist <= 0)\n\t\treturn; // can't reach end\n\n\tIMLSegment* route[64];\n\troute[0] = currentSegment;\n\tif (currentSegment->nextSegmentBranchNotTaken)\n\t\t_IMLRA_checkAndTryExtendRange(ctx, currentSegment->nextSegmentBranchNotTaken, regID, remainingScanDist, route, 1);\n\tif (currentSegment->nextSegmentBranchTaken)\n\t\t_IMLRA_checkAndTryExtendRange(ctx, currentSegment->nextSegmentBranchTaken, regID, remainingScanDist, route, 1);\n}\n\nvoid PPCRecRA_mergeCloseRangesForSegmentV2(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment)\n{\n\tauto& segMap = ctx.GetSegmentAbstractRangeMap(imlSegment);\n\tfor (auto& it : segMap)\n\t{\n\t\tPPCRecRA_checkAndTryExtendRange(ctx, imlSegment, &(it.second), it.first);\n\t}\n#ifdef CEMU_DEBUG_ASSERT\n\tif (imlSegment->list_prevSegments.empty() == false && imlSegment->isEnterable)\n\t\tassert_dbg();\n\tif ((imlSegment->nextSegmentBranchNotTaken != nullptr || imlSegment->nextSegmentBranchTaken != nullptr) && imlSegment->nextSegmentIsUncertain)\n\t\tassert_dbg();\n#endif\n}\n\nvoid PPCRecRA_followFlowAndExtendRanges(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment)\n{\n\tstd::vector<IMLSegment*> list_segments;\n\tstd::vector<bool> list_processedSegment;\n\tsize_t segmentCount = ctx.deprGenContext->segmentList2.size();\n\tlist_segments.reserve(segmentCount + 1);\n\tlist_processedSegment.resize(segmentCount);\n\n\tauto markSegProcessed = [&list_processedSegment](IMLSegment* seg) {\n\t\tlist_processedSegment[seg->momentaryIndex] = true;\n\t};\n\tauto isSegProcessed = [&list_processedSegment](IMLSegment* seg) -> bool {\n\t\treturn list_processedSegment[seg->momentaryIndex];\n\t};\n\tmarkSegProcessed(imlSegment);\n\n\tsint32 index = 0;\n\tlist_segments.push_back(imlSegment);\n\twhile (index < list_segments.size())\n\t{\n\t\tIMLSegment* currentSegment = list_segments[index];\n\t\tPPCRecRA_mergeCloseRangesForSegmentV2(ctx, currentSegment);\n\t\t// follow flow\n\t\tif (currentSegment->nextSegmentBranchNotTaken && !isSegProcessed(currentSegment->nextSegmentBranchNotTaken))\n\t\t{\n\t\t\tmarkSegProcessed(currentSegment->nextSegmentBranchNotTaken);\n\t\t\tlist_segments.push_back(currentSegment->nextSegmentBranchNotTaken);\n\t\t}\n\t\tif (currentSegment->nextSegmentBranchTaken && !isSegProcessed(currentSegment->nextSegmentBranchTaken))\n\t\t{\n\t\t\tmarkSegProcessed(currentSegment->nextSegmentBranchTaken);\n\t\t\tlist_segments.push_back(currentSegment->nextSegmentBranchTaken);\n\t\t}\n\t\tindex++;\n\t}\n}\n\nvoid IMLRA_MergeCloseAbstractRanges(IMLRegisterAllocatorContext& ctx)\n{\n\tfor (size_t s = 0; s < ctx.deprGenContext->segmentList2.size(); s++)\n\t{\n\t\tIMLSegment* imlSegment = ctx.deprGenContext->segmentList2[s];\n\t\tif (!imlSegment->list_prevSegments.empty())\n\t\t\tcontinue; // not an entry/standalone segment\n\t\tPPCRecRA_followFlowAndExtendRanges(ctx, imlSegment);\n\t}\n}\n\nvoid IMLRA_ExtendAbstractRangesOutOfLoops(IMLRegisterAllocatorContext& ctx)\n{\n\tfor (size_t s = 0; s < ctx.deprGenContext->segmentList2.size(); s++)\n\t{\n\t\tIMLSegment* imlSegment = ctx.deprGenContext->segmentList2[s];\n\t\tauto localLoopDepth = imlSegment->loopDepth;\n\t\tif (localLoopDepth <= 0)\n\t\t\tcontinue; // not inside a loop\n\t\t// look for loop exit\n\t\tbool hasLoopExit = false;\n\t\tif (imlSegment->nextSegmentBranchTaken && imlSegment->nextSegmentBranchTaken->loopDepth < localLoopDepth)\n\t\t{\n\t\t\thasLoopExit = true;\n\t\t}\n\t\tif (imlSegment->nextSegmentBranchNotTaken && imlSegment->nextSegmentBranchNotTaken->loopDepth < localLoopDepth)\n\t\t{\n\t\t\thasLoopExit = true;\n\t\t}\n\t\tif (hasLoopExit == false)\n\t\t\tcontinue;\n\n\t\t// extend looping ranges into all exits (this allows the data flow analyzer to move stores out of the loop)\n\t\tauto& segMap = ctx.GetSegmentAbstractRangeMap(imlSegment);\n\t\tfor (auto& it : segMap)\n\t\t{\n\t\t\tif (it.second.usageEnd != RA_INTER_RANGE_END)\n\t\t\t\tcontinue;\n\t\t\tif (imlSegment->nextSegmentBranchTaken)\n\t\t\t\tIMLRA_extendAbstractRangeToBeginningOfSegment(ctx, imlSegment->nextSegmentBranchTaken, it.first);\n\t\t\tif (imlSegment->nextSegmentBranchNotTaken)\n\t\t\t\tIMLRA_extendAbstractRangeToBeginningOfSegment(ctx, imlSegment->nextSegmentBranchNotTaken, it.first);\n\t\t}\n\t}\n}\n\nvoid IMLRA_ProcessFlowAndCalculateLivenessRanges(IMLRegisterAllocatorContext& ctx)\n{\n\tIMLRA_MergeCloseAbstractRanges(ctx);\n\t// extra pass to move register loads and stores out of loops\n\tIMLRA_ExtendAbstractRangesOutOfLoops(ctx);\n\t// calculate liveness ranges\n\tfor (auto& segIt : ctx.deprGenContext->segmentList2)\n\t\tIMLRA_ConvertAbstractToLivenessRanges(ctx, segIt);\n}\n\nvoid IMLRA_AnalyzeSubrangeDataDependency(raLivenessRange* subrange)\n{\n\tbool isRead = false;\n\tbool isWritten = false;\n\tbool isOverwritten = false;\n\tfor (auto& location : subrange->list_accessLocations)\n\t{\n\t\tif (location.IsRead())\n\t\t{\n\t\t\tisRead = true;\n\t\t}\n\t\tif (location.IsWrite())\n\t\t{\n\t\t\tif (isRead == false)\n\t\t\t\tisOverwritten = true;\n\t\t\tisWritten = true;\n\t\t}\n\t}\n\tsubrange->_noLoad = isOverwritten;\n\tsubrange->hasStore = isWritten;\n\n\tif (subrange->interval.ExtendsPreviousSegment())\n\t\tsubrange->_noLoad = true;\n}\n\nstruct subrangeEndingInfo_t\n{\n\traLivenessRange* subrangeList[SUBRANGE_LIST_SIZE];\n\tsint32 subrangeCount;\n\n\tbool hasUndefinedEndings;\n};\n\nvoid _findSubrangeWriteEndings(raLivenessRange* subrange, uint32 iterationIndex, sint32 depth, subrangeEndingInfo_t* info)\n{\n\tif (depth >= 30)\n\t{\n\t\tinfo->hasUndefinedEndings = true;\n\t\treturn;\n\t}\n\tif (subrange->lastIterationIndex == iterationIndex)\n\t\treturn; // already processed\n\tsubrange->lastIterationIndex = iterationIndex;\n\tif (subrange->hasStoreDelayed)\n\t\treturn; // no need to traverse this subrange\n\tIMLSegment* imlSegment = subrange->imlSegment;\n\tif (!subrange->interval.ExtendsIntoNextSegment())\n\t{\n\t\t// ending segment\n\t\tif (info->subrangeCount >= SUBRANGE_LIST_SIZE)\n\t\t{\n\t\t\tinfo->hasUndefinedEndings = true;\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tinfo->subrangeList[info->subrangeCount] = subrange;\n\t\t\tinfo->subrangeCount++;\n\t\t}\n\t\treturn;\n\t}\n\n\t// traverse next subranges in flow\n\tif (imlSegment->nextSegmentBranchNotTaken)\n\t{\n\t\tif (subrange->subrangeBranchNotTaken == nullptr)\n\t\t{\n\t\t\tinfo->hasUndefinedEndings = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_findSubrangeWriteEndings(subrange->subrangeBranchNotTaken, iterationIndex, depth + 1, info);\n\t\t}\n\t}\n\tif (imlSegment->nextSegmentBranchTaken)\n\t{\n\t\tif (subrange->subrangeBranchTaken == nullptr)\n\t\t{\n\t\t\tinfo->hasUndefinedEndings = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_findSubrangeWriteEndings(subrange->subrangeBranchTaken, iterationIndex, depth + 1, info);\n\t\t}\n\t}\n}\n\nstatic void IMLRA_AnalyzeRangeDataFlow(raLivenessRange* subrange)\n{\n\tif (!subrange->interval.ExtendsIntoNextSegment())\n\t\treturn;\n\t// analyze data flow across segments (if this segment has writes)\n\tif (subrange->hasStore)\n\t{\n\t\tsubrangeEndingInfo_t writeEndingInfo;\n\t\twriteEndingInfo.subrangeCount = 0;\n\t\twriteEndingInfo.hasUndefinedEndings = false;\n\t\t_findSubrangeWriteEndings(subrange, IMLRA_GetNextIterationIndex(), 0, &writeEndingInfo);\n\t\tif (writeEndingInfo.hasUndefinedEndings == false)\n\t\t{\n\t\t\t// get cost of delaying store into endings\n\t\t\tsint32 delayStoreCost = 0;\n\t\t\tbool alreadyStoredInAllEndings = true;\n\t\t\tfor (sint32 i = 0; i < writeEndingInfo.subrangeCount; i++)\n\t\t\t{\n\t\t\t\traLivenessRange* subrangeItr = writeEndingInfo.subrangeList[i];\n\t\t\t\tif (subrangeItr->hasStore)\n\t\t\t\t\tcontinue; // this ending already stores, no extra cost\n\t\t\t\talreadyStoredInAllEndings = false;\n\t\t\t\tsint32 storeCost = IMLRA_GetSegmentReadWriteCost(subrangeItr->imlSegment);\n\t\t\t\tdelayStoreCost = std::max(storeCost, delayStoreCost);\n\t\t\t}\n\t\t\tif (alreadyStoredInAllEndings)\n\t\t\t{\n\t\t\t\tsubrange->hasStore = false;\n\t\t\t\tsubrange->hasStoreDelayed = true;\n\t\t\t}\n\t\t\telse if (delayStoreCost <= IMLRA_GetSegmentReadWriteCost(subrange->imlSegment))\n\t\t\t{\n\t\t\t\tsubrange->hasStore = false;\n\t\t\t\tsubrange->hasStoreDelayed = true;\n\t\t\t\tfor (sint32 i = 0; i < writeEndingInfo.subrangeCount; i++)\n\t\t\t\t{\n\t\t\t\t\traLivenessRange* subrangeItr = writeEndingInfo.subrangeList[i];\n\t\t\t\t\tsubrangeItr->hasStore = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid IMLRA_AnalyzeRangeDataFlow(ppcImlGenContext_t* ppcImlGenContext)\n{\n\t// this function is called after _AssignRegisters(), which means that all liveness ranges are already final and must not be modified anymore\n\t// track read/write dependencies per segment\n\tfor (auto& seg : ppcImlGenContext->segmentList2)\n\t{\n\t\traLivenessRange* subrange = seg->raInfo.linkedList_allSubranges;\n\t\twhile (subrange)\n\t\t{\n\t\t\tIMLRA_AnalyzeSubrangeDataDependency(subrange);\n\t\t\tsubrange = subrange->link_allSegmentRanges.next;\n\t\t}\n\t}\n\t// propagate information across segment boundaries\n\tfor (auto& seg : ppcImlGenContext->segmentList2)\n\t{\n\t\traLivenessRange* subrange = seg->raInfo.linkedList_allSubranges;\n\t\twhile (subrange)\n\t\t{\n\t\t\tIMLRA_AnalyzeRangeDataFlow(subrange);\n\t\t\tsubrange = subrange->link_allSegmentRanges.next;\n\t\t}\n\t}\n}\n\n/* Generate move instructions */\n\ninline IMLReg _MakeNativeReg(IMLRegFormat baseFormat, IMLRegID regId)\n{\n\treturn IMLReg(baseFormat, baseFormat, 0, regId);\n}\n\n// prepass for IMLRA_GenerateSegmentMoveInstructions which updates all virtual registers to their physical counterparts\nvoid IMLRA_RewriteRegisters(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment)\n{\n\tstd::unordered_map<IMLRegID, IMLRegID> virtId2PhysReg;\n\tboost::container::small_vector<raLivenessRange*, 64> activeRanges;\n\traLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges;\n\traInstructionEdge currentEdge;\n\tfor (size_t i = 0; i < imlSegment->imlList.size(); i++)\n\t{\n\t\tcurrentEdge.Set(i, false); // set to instruction index on output edge\n\t\t// activate ranges which begin before or during this instruction\n\t\twhile (currentRange && currentRange->interval.start <= currentEdge)\n\t\t{\n\t\t\tcemu_assert_debug(virtId2PhysReg.find(currentRange->GetVirtualRegister()) == virtId2PhysReg.end() || virtId2PhysReg[currentRange->GetVirtualRegister()] == currentRange->GetPhysicalRegister()); // check for register conflict\n\n\t\t\tvirtId2PhysReg[currentRange->GetVirtualRegister()] = currentRange->GetPhysicalRegister();\n\t\t\tactiveRanges.push_back(currentRange);\n\t\t\tcurrentRange = currentRange->link_allSegmentRanges.next;\n\t\t}\n\t\t// rewrite registers\n\t\timlSegment->imlList[i].RewriteGPR(virtId2PhysReg);\n\t\t// deactivate ranges which end during this instruction\n\t\tauto it = activeRanges.begin();\n\t\twhile (it != activeRanges.end())\n\t\t{\n\t\t\tif ((*it)->interval.end <= currentEdge)\n\t\t\t{\n\t\t\t\tvirtId2PhysReg.erase((*it)->GetVirtualRegister());\n\t\t\t\tit = activeRanges.erase(it);\n\t\t\t}\n\t\t\telse\n\t\t\t\t++it;\n\t\t}\n\t}\n}\n\nvoid IMLRA_GenerateSegmentMoveInstructions2(IMLRegisterAllocatorContext& ctx, IMLSegment* imlSegment)\n{\n\tIMLRA_RewriteRegisters(ctx, imlSegment);\n\n#if DEBUG_RA_INSTRUCTION_GEN\n\tcemuLog_log(LogType::Force, \"\");\n\tcemuLog_log(LogType::Force, \"[Seg before RA]\");\n\tIMLDebug_DumpSegment(nullptr, imlSegment, true);\n#endif\n\n\tbool hadSuffixInstruction = imlSegment->HasSuffixInstruction();\n\n\tstd::vector<IMLInstruction> rebuiltInstructions;\n\tsint32 numInstructionsWithoutSuffix = (sint32)imlSegment->imlList.size() - (imlSegment->HasSuffixInstruction() ? 1 : 0);\n\n\tif (imlSegment->imlList.empty())\n\t{\n\t\t// empty segments need special handling (todo - look into merging this with the core logic below eventually)\n\t\t// store all ranges\n\t\traLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges;\n\t\twhile (currentRange)\n\t\t{\n\t\t\tif (currentRange->hasStore)\n\t\t\t\trebuiltInstructions.emplace_back().make_name_r(currentRange->GetName(), _MakeNativeReg(ctx.regIdToBaseFormat[currentRange->GetVirtualRegister()], currentRange->GetPhysicalRegister()));\n\t\t\tcurrentRange = currentRange->link_allSegmentRanges.next;\n\t\t}\n\t\t// load ranges\n\t\tcurrentRange = imlSegment->raInfo.linkedList_allSubranges;\n\t\twhile (currentRange)\n\t\t{\n\t\t\tif (!currentRange->_noLoad)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(currentRange->interval.ExtendsIntoNextSegment());\n\t\t\t\trebuiltInstructions.emplace_back().make_r_name(_MakeNativeReg(ctx.regIdToBaseFormat[currentRange->GetVirtualRegister()], currentRange->GetPhysicalRegister()), currentRange->GetName());\n\t\t\t}\n\t\t\tcurrentRange = currentRange->link_allSegmentRanges.next;\n\t\t}\n\t\timlSegment->imlList = std::move(rebuiltInstructions);\n\t\treturn;\n\t}\n\n\t// make sure that no range exceeds the suffix instruction input edge except if they need to be loaded for the next segment (todo - for those, set the start point accordingly?)\n\t{\n\t\traLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges;\n\t\traInstructionEdge edge;\n\t\tif (imlSegment->HasSuffixInstruction())\n\t\t\tedge.Set(numInstructionsWithoutSuffix, true);\n\t\telse\n\t\t\tedge.Set(numInstructionsWithoutSuffix - 1, false);\n\n\t\twhile (currentRange)\n\t\t{\n\t\t\tif (!currentRange->interval.IsNextSegmentOnly() && currentRange->interval.end > edge)\n\t\t\t{\n\t\t\t\tcurrentRange->interval.SetEnd(edge);\n\t\t\t}\n\t\t\tcurrentRange = currentRange->link_allSegmentRanges.next;\n\t\t}\n\t}\n\n#if DEBUG_RA_INSTRUCTION_GEN\n\tcemuLog_log(LogType::Force, \"\");\n\tcemuLog_log(LogType::Force, \"--- Intermediate liveness info ---\");\n\t{\n\t\traLivenessRange* dbgRange = imlSegment->raInfo.linkedList_allSubranges;\n\t\twhile (dbgRange)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Range i{}: {}-{}\", dbgRange->GetVirtualRegister(), dbgRange->interval2.start.GetDebugString(), dbgRange->interval2.end.GetDebugString());\n\t\t\tdbgRange = dbgRange->link_allSegmentRanges.next;\n\t\t}\n\t}\n#endif\n\n\tboost::container::small_vector<raLivenessRange*, 64> activeRanges;\n\t// first we add all the ranges that extend from the previous segment, some of these will end immediately at the first instruction so we might need to store them early\n\traLivenessRange* currentRange = imlSegment->raInfo.linkedList_allSubranges;\n\t// make all ranges active that start on RA_INTER_RANGE_START\n\twhile (currentRange && currentRange->interval.start.ConnectsToPreviousSegment())\n\t{\n\t\tactiveRanges.push_back(currentRange);\n\t\tcurrentRange = currentRange->link_allSegmentRanges.next;\n\t}\n\t// store all ranges that end before the first output edge (includes RA_INTER_RANGE_START)\n\tauto it = activeRanges.begin();\n\traInstructionEdge firstOutputEdge;\n\tfirstOutputEdge.Set(0, false);\n\twhile (it != activeRanges.end())\n\t{\n\t\tif ((*it)->interval.end < firstOutputEdge)\n\t\t{\n\t\t\traLivenessRange* storedRange = *it;\n\t\t\tif (storedRange->hasStore)\n\t\t\t\trebuiltInstructions.emplace_back().make_name_r(storedRange->GetName(), _MakeNativeReg(ctx.regIdToBaseFormat[storedRange->GetVirtualRegister()], storedRange->GetPhysicalRegister()));\n\t\t\tit = activeRanges.erase(it);\n\t\t\tcontinue;\n\t\t}\n\t\t++it;\n\t}\n\n\tsint32 numInstructions = (sint32)imlSegment->imlList.size();\n\tfor (sint32 i = 0; i < numInstructions; i++)\n\t{\n\t\traInstructionEdge curEdge;\n\t\t// input edge\n\t\tcurEdge.SetRaw(i * 2 + 1); // +1 to include ranges that start at the output of the instruction\n\t\twhile (currentRange && currentRange->interval.start <= curEdge)\n\t\t{\n\t\t\tif (!currentRange->_noLoad)\n\t\t\t{\n\t\t\t\trebuiltInstructions.emplace_back().make_r_name(_MakeNativeReg(ctx.regIdToBaseFormat[currentRange->GetVirtualRegister()], currentRange->GetPhysicalRegister()), currentRange->GetName());\n\t\t\t}\n\t\t\tactiveRanges.push_back(currentRange);\n\t\t\tcurrentRange = currentRange->link_allSegmentRanges.next;\n\t\t}\n\t\t// copy instruction\n\t\trebuiltInstructions.push_back(imlSegment->imlList[i]);\n\t\t// output edge\n\t\tcurEdge.SetRaw(i * 2 + 1 + 1);\n\t\t// also store ranges that end on the next input edge, we handle this by adding an extra 1 above\n\t\tauto it = activeRanges.begin();\n\t\twhile (it != activeRanges.end())\n\t\t{\n\t\t\tif ((*it)->interval.end <= curEdge)\n\t\t\t{\n\t\t\t\t// range expires\n\t\t\t\t// todo - check hasStore\n\t\t\t\traLivenessRange* storedRange = *it;\n\t\t\t\tif (storedRange->hasStore)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(i != numInstructionsWithoutSuffix); // not allowed to emit after suffix\n\t\t\t\t\trebuiltInstructions.emplace_back().make_name_r(storedRange->GetName(), _MakeNativeReg(ctx.regIdToBaseFormat[storedRange->GetVirtualRegister()], storedRange->GetPhysicalRegister()));\n\t\t\t\t}\n\t\t\t\tit = activeRanges.erase(it);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t++it;\n\t\t}\n\t}\n\t// if there is no suffix instruction we currently need to handle the final loads here\n\tcemu_assert_debug(hadSuffixInstruction == imlSegment->HasSuffixInstruction());\n\tif (imlSegment->HasSuffixInstruction())\n\t{\n\t\tif (currentRange)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"[DEBUG] GenerateSegmentMoveInstructions() hit suffix path with non-null currentRange. Segment: {:08x}\", imlSegment->ppcAddress);\n\t\t}\n\t\tfor (auto& remainingRange : activeRanges)\n\t\t{\n\t\t\tcemu_assert_debug(!remainingRange->hasStore);\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (auto& remainingRange : activeRanges)\n\t\t{\n\t\t\tcemu_assert_debug(!remainingRange->hasStore); // this range still needs to be stored\n\t\t}\n\t\twhile (currentRange)\n\t\t{\n\t\t\tcemu_assert_debug(currentRange->interval.IsNextSegmentOnly());\n\t\t\tcemu_assert_debug(!currentRange->_noLoad);\n\t\t\trebuiltInstructions.emplace_back().make_r_name(_MakeNativeReg(ctx.regIdToBaseFormat[currentRange->GetVirtualRegister()], currentRange->GetPhysicalRegister()), currentRange->GetName());\n\t\t\tcurrentRange = currentRange->link_allSegmentRanges.next;\n\t\t}\n\t}\n\n\timlSegment->imlList = std::move(rebuiltInstructions);\n\tcemu_assert_debug(hadSuffixInstruction == imlSegment->HasSuffixInstruction());\n\n#if DEBUG_RA_INSTRUCTION_GEN\n\tcemuLog_log(LogType::Force, \"\");\n\tcemuLog_log(LogType::Force, \"[Seg after RA]\");\n\tIMLDebug_DumpSegment(nullptr, imlSegment, false);\n#endif\n}\n\nvoid IMLRA_GenerateMoveInstructions(IMLRegisterAllocatorContext& ctx)\n{\n\tfor (size_t s = 0; s < ctx.deprGenContext->segmentList2.size(); s++)\n\t{\n\t\tIMLSegment* imlSegment = ctx.deprGenContext->segmentList2[s];\n\t\tIMLRA_GenerateSegmentMoveInstructions2(ctx, imlSegment);\n\t}\n}\n\nstatic void DbgVerifyFixedRegRequirements(IMLSegment* imlSegment)\n{\n#if DEBUG_RA_EXTRA_VALIDATION\n\tstd::vector<raFixedRegRequirementWithVGPR> frr = IMLRA_BuildSegmentInstructionFixedRegList(imlSegment);\n\tfor(auto& fixedReq : frr)\n\t{\n\t\tfor (raLivenessRange* range = imlSegment->raInfo.linkedList_allSubranges; range; range = range->link_allSegmentRanges.next)\n\t\t{\n\t\t\tif (!range->interval2.ContainsEdge(fixedReq.pos))\n\t\t\t\tcontinue;\n\t\t\t// verify if the requirement is compatible\n\t\t\tif(range->GetVirtualRegister() == fixedReq.regId)\n\t\t\t{\n\t\t\t\tcemu_assert(range->HasPhysicalRegister());\n\t\t\t\tcemu_assert(fixedReq.allowedReg.IsAvailable(range->GetPhysicalRegister())); // virtual register matches, but not assigned the right physical register\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert(!fixedReq.allowedReg.IsAvailable(range->GetPhysicalRegister())); // virtual register does not match, but using the reserved physical register\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n\nstatic void DbgVerifyAllRanges(IMLRegisterAllocatorContext& ctx)\n{\n#if DEBUG_RA_EXTRA_VALIDATION\n\tfor (size_t s = 0; s < ctx.deprGenContext->segmentList2.size(); s++)\n\t{\n\t\tIMLSegment* imlSegment = ctx.deprGenContext->segmentList2[s];\n\t\traLivenessRange* subrangeItr = imlSegment->raInfo.linkedList_allSubranges;\n\t\twhile (subrangeItr)\n\t\t{\n\t\t\tPPCRecRA_debugValidateSubrange(subrangeItr);\n\t\t\tsubrangeItr = subrangeItr->link_allSegmentRanges.next;\n\t\t}\n\t}\n\t// check that no range validates register requirements\n\tfor (size_t s = 0; s < ctx.deprGenContext->segmentList2.size(); s++)\n\t{\n\t\tDbgVerifyFixedRegRequirements(ctx.deprGenContext->segmentList2[s]);\n\t}\n#endif\n}\n\nvoid IMLRegisterAllocator_AllocateRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLRegisterAllocatorParameters& raParam)\n{\n\tIMLRegisterAllocatorContext ctx;\n\tctx.raParam = &raParam;\n\tctx.deprGenContext = ppcImlGenContext;\n\n\tIMLRA_ReshapeForRegisterAllocation(ppcImlGenContext);\n\tppcImlGenContext->UpdateSegmentIndices(); // update momentaryIndex of each segment\n\tctx.perSegmentAbstractRanges.resize(ppcImlGenContext->segmentList2.size());\n\tIMLRA_CalculateLivenessRanges(ctx);\n\tIMLRA_ProcessFlowAndCalculateLivenessRanges(ctx);\n\tIMLRA_AssignRegisters(ctx, ppcImlGenContext);\n\tDbgVerifyAllRanges(ctx);\n\tIMLRA_AnalyzeRangeDataFlow(ppcImlGenContext);\n\tIMLRA_GenerateMoveInstructions(ctx);\n\n\tIMLRA_DeleteAllRanges(ppcImlGenContext);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocator.h",
    "content": "#pragma once\n\n// container for storing a set of register indices\n// specifically optimized towards storing typical range of physical register indices (expected to be below 64)\nclass IMLPhysRegisterSet\n{\npublic:\n\tvoid SetAvailable(uint32 index)\n\t{\n\t\tcemu_assert_debug(index < 64);\n\t\tm_regBitmask |= ((uint64)1 << index);\n\t}\n\n\tvoid SetReserved(uint32 index)\n\t{\n\t\tcemu_assert_debug(index < 64);\n\t\tm_regBitmask &= ~((uint64)1 << index);\n\t}\n\n\tvoid SetAllAvailable()\n\t{\n\t\tm_regBitmask = ~0ull;\n\t}\n\n\tbool HasAllAvailable() const\n\t{\n\t\treturn m_regBitmask == ~0ull;\n\t}\n\n\tbool IsAvailable(uint32 index) const\n\t{\n\t\treturn (m_regBitmask & ((uint64)1 << index)) != 0;\n\t}\n\n\tIMLPhysRegisterSet& operator&=(const IMLPhysRegisterSet& other)\n\t{\n\t\tthis->m_regBitmask &= other.m_regBitmask;\n\t\treturn *this;\n\t}\n\n\tIMLPhysRegisterSet& operator=(const IMLPhysRegisterSet& other)\n\t{\n\t\tthis->m_regBitmask = other.m_regBitmask;\n\t\treturn *this;\n\t}\n\n\tvoid RemoveRegisters(const IMLPhysRegisterSet& other)\n\t{\n\t\tthis->m_regBitmask &= ~other.m_regBitmask;\n\t}\n\n\tbool HasAnyAvailable() const\n\t{\n\t\treturn m_regBitmask != 0;\n\t}\n\n\tbool HasExactlyOneAvailable() const\n\t{\n\t\treturn m_regBitmask != 0 && (m_regBitmask & (m_regBitmask - 1)) == 0;\n\t}\n\n\t// returns index of first available register. Do not call when HasAnyAvailable() == false\n\tIMLPhysReg GetFirstAvailableReg()\n\t{\n\t\tcemu_assert_debug(m_regBitmask != 0);\n\t\tsint32 regIndex = 0;\n\t\tauto tmp = m_regBitmask;\n\t\twhile ((tmp & 0xFF) == 0)\n\t\t{\n\t\t\tregIndex += 8;\n\t\t\ttmp >>= 8;\n\t\t}\n\t\twhile ((tmp & 0x1) == 0)\n\t\t{\n\t\t\tregIndex++;\n\t\t\ttmp >>= 1;\n\t\t}\n\t\treturn regIndex;\n\t}\n\n\t// returns index of next available register (search includes any register index >= startIndex)\n\t// returns -1 if there is no more register\n\tIMLPhysReg GetNextAvailableReg(sint32 startIndex) const\n\t{\n\t\tif (startIndex >= 64)\n\t\t\treturn -1;\n\t\tuint32 regIndex = startIndex;\n\t\tauto tmp = m_regBitmask;\n\t\ttmp >>= regIndex;\n\t\tif (!tmp)\n\t\t\treturn -1;\n\t\twhile ((tmp & 0xFF) == 0)\n\t\t{\n\t\t\tregIndex += 8;\n\t\t\ttmp >>= 8;\n\t\t}\n\t\twhile ((tmp & 0x1) == 0)\n\t\t{\n\t\t\tregIndex++;\n\t\t\ttmp >>= 1;\n\t\t}\n\t\treturn regIndex;\n\t}\n\n\tsint32 CountAvailableRegs() const\n\t{\n\t\treturn std::popcount(m_regBitmask);\n\t}\n\nprivate:\n\tuint64 m_regBitmask{ 0 };\n};\n\nstruct IMLRegisterAllocatorParameters\n{\n\tinline IMLPhysRegisterSet& GetPhysRegPool(IMLRegFormat regFormat)\n\t{\n\t\treturn perTypePhysPool[stdx::to_underlying(regFormat)];\n\t}\n\n\tIMLPhysRegisterSet perTypePhysPool[stdx::to_underlying(IMLRegFormat::TYPE_COUNT)];\n\tstd::unordered_map<IMLRegID, IMLName> regIdToName;\n};\n\nvoid IMLRegisterAllocator_AllocateRegisters(ppcImlGenContext_t* ppcImlGenContext, IMLRegisterAllocatorParameters& raParam);"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocatorRanges.cpp",
    "content": "#include \"../PPCRecompiler.h\"\n#include \"../PPCRecompilerIml.h\"\n#include \"IMLRegisterAllocatorRanges.h\"\n#include \"util/helpers/MemoryPool.h\"\n\nuint32 IMLRA_GetNextIterationIndex();\n\nIMLRegID raLivenessRange::GetVirtualRegister() const\n{\n\treturn virtualRegister;\n}\n\nsint32 raLivenessRange::GetPhysicalRegister() const\n{\n\treturn physicalRegister;\n}\n\nIMLName raLivenessRange::GetName() const\n{\n\treturn name;\n}\n\nvoid raLivenessRange::SetPhysicalRegister(IMLPhysReg physicalRegister)\n{\n\tthis->physicalRegister = physicalRegister;\n}\n\nvoid raLivenessRange::SetPhysicalRegisterForCluster(IMLPhysReg physicalRegister)\n{\n\tauto clusterRanges = GetAllSubrangesInCluster();\n\tfor(auto& range : clusterRanges)\n\t\trange->physicalRegister = physicalRegister;\n}\n\nboost::container::small_vector<raLivenessRange*, 128> raLivenessRange::GetAllSubrangesInCluster()\n{\n\tuint32 iterationIndex = IMLRA_GetNextIterationIndex();\n\tboost::container::small_vector<raLivenessRange*, 128> subranges;\n\tsubranges.push_back(this);\n\tthis->lastIterationIndex = iterationIndex;\n\tsize_t i = 0;\n\twhile(i<subranges.size())\n\t{\n\t\traLivenessRange* cur = subranges[i];\n\t\ti++;\n\t\t// check successors\n\t\tif(cur->subrangeBranchTaken && cur->subrangeBranchTaken->lastIterationIndex != iterationIndex)\n\t\t{\n\t\t\tcur->subrangeBranchTaken->lastIterationIndex = iterationIndex;\n\t\t\tsubranges.push_back(cur->subrangeBranchTaken);\n\t\t}\n\t\tif(cur->subrangeBranchNotTaken && cur->subrangeBranchNotTaken->lastIterationIndex != iterationIndex)\n\t\t{\n\t\t\tcur->subrangeBranchNotTaken->lastIterationIndex = iterationIndex;\n\t\t\tsubranges.push_back(cur->subrangeBranchNotTaken);\n\t\t}\n\t\t// check predecessors\n\t\tfor(auto& prev : cur->previousRanges)\n\t\t{\n\t\t\tif(prev->lastIterationIndex != iterationIndex)\n\t\t\t{\n\t\t\t\tprev->lastIterationIndex = iterationIndex;\n\t\t\t\tsubranges.push_back(prev);\n\t\t\t}\n\t\t}\n\t}\n\treturn subranges;\n}\n\nvoid raLivenessRange::GetAllowedRegistersExRecursive(raLivenessRange* range, uint32 iterationIndex, IMLPhysRegisterSet& allowedRegs)\n{\n\trange->lastIterationIndex = iterationIndex;\n\tfor (auto& it : range->list_fixedRegRequirements)\n\t\tallowedRegs &= it.allowedReg;\n\t// check successors\n\tif (range->subrangeBranchTaken && range->subrangeBranchTaken->lastIterationIndex != iterationIndex)\n\t\tGetAllowedRegistersExRecursive(range->subrangeBranchTaken, iterationIndex, allowedRegs);\n\tif (range->subrangeBranchNotTaken && range->subrangeBranchNotTaken->lastIterationIndex != iterationIndex)\n\t\tGetAllowedRegistersExRecursive(range->subrangeBranchNotTaken, iterationIndex, allowedRegs);\n\t// check predecessors\n\tfor (auto& prev : range->previousRanges)\n\t{\n\t\tif (prev->lastIterationIndex != iterationIndex)\n\t\t\tGetAllowedRegistersExRecursive(prev, iterationIndex, allowedRegs);\n\t}\n};\n\nbool raLivenessRange::GetAllowedRegistersEx(IMLPhysRegisterSet& allowedRegisters)\n{\n\tuint32 iterationIndex = IMLRA_GetNextIterationIndex();\n\tallowedRegisters.SetAllAvailable();\n\tGetAllowedRegistersExRecursive(this, iterationIndex, allowedRegisters);\n\treturn !allowedRegisters.HasAllAvailable();\n}\n\nIMLPhysRegisterSet raLivenessRange::GetAllowedRegisters(IMLPhysRegisterSet regPool)\n{\n\tIMLPhysRegisterSet fixedRegRequirements = regPool;\n\tif(interval.ExtendsPreviousSegment() || interval.ExtendsIntoNextSegment())\n\t{\n\t\tauto clusterRanges = GetAllSubrangesInCluster();\n\t\tfor(auto& subrange : clusterRanges)\n\t\t{\n\t\t\tfor(auto& fixedRegLoc : subrange->list_fixedRegRequirements)\n\t\t\t\tfixedRegRequirements &= fixedRegLoc.allowedReg;\n\t\t}\n\t\treturn fixedRegRequirements;\n\t}\n\tfor(auto& fixedRegLoc : list_fixedRegRequirements)\n\t\tfixedRegRequirements &= fixedRegLoc.allowedReg;\n\treturn fixedRegRequirements;\n}\n\nvoid PPCRecRARange_addLink_perVirtualGPR(std::unordered_map<IMLRegID, raLivenessRange*>& root, raLivenessRange* subrange)\n{\n\tIMLRegID regId = subrange->GetVirtualRegister();\n\tauto it = root.find(regId);\n\tif (it == root.end())\n\t{\n\t\t// new single element\n\t\troot.try_emplace(regId, subrange);\n\t\tsubrange->link_sameVirtualRegister.prev = nullptr;\n\t\tsubrange->link_sameVirtualRegister.next = nullptr;\n\t}\n\telse\n\t{\n\t\t// insert in first position\n\t\traLivenessRange* priorFirst = it->second;\n\t\tsubrange->link_sameVirtualRegister.next = priorFirst;\n\t\tit->second = subrange;\n\t\tsubrange->link_sameVirtualRegister.prev = nullptr;\n\t\tpriorFirst->link_sameVirtualRegister.prev = subrange;\n\t}\n}\n\nvoid PPCRecRARange_addLink_allSegmentRanges(raLivenessRange** root, raLivenessRange* subrange)\n{\n\tsubrange->link_allSegmentRanges.next = *root;\n\tif (*root)\n\t\t(*root)->link_allSegmentRanges.prev = subrange;\n\tsubrange->link_allSegmentRanges.prev = nullptr;\n\t*root = subrange;\n}\n\nvoid PPCRecRARange_removeLink_perVirtualGPR(std::unordered_map<IMLRegID, raLivenessRange*>& root, raLivenessRange* subrange)\n{\n#ifdef CEMU_DEBUG_ASSERT\n\traLivenessRange* cur = root.find(subrange->GetVirtualRegister())->second;\n\tbool hasRangeFound = false;\n\twhile(cur)\n\t{\n\t\tif(cur == subrange)\n\t\t{\n\t\t\thasRangeFound = true;\n\t\t\tbreak;\n\t\t}\n\t\tcur = cur->link_sameVirtualRegister.next;\n\t}\n\tcemu_assert_debug(hasRangeFound);\n#endif\n\tIMLRegID regId = subrange->GetVirtualRegister();\n\traLivenessRange* nextRange = subrange->link_sameVirtualRegister.next;\n\traLivenessRange* prevRange = subrange->link_sameVirtualRegister.prev;\n\traLivenessRange* newBase = prevRange ? prevRange : nextRange;\n\tif (prevRange)\n\t\tprevRange->link_sameVirtualRegister.next = subrange->link_sameVirtualRegister.next;\n\tif (nextRange)\n\t\tnextRange->link_sameVirtualRegister.prev = subrange->link_sameVirtualRegister.prev;\n\n\tif (!prevRange)\n\t{\n\t\tif (nextRange)\n\t\t{\n\t\t\troot.find(regId)->second = nextRange;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(root.find(regId)->second == subrange);\n\t\t\troot.erase(regId);\n\t\t}\n\t}\n#ifdef CEMU_DEBUG_ASSERT\n\tsubrange->link_sameVirtualRegister.prev = (raLivenessRange*)1;\n\tsubrange->link_sameVirtualRegister.next = (raLivenessRange*)1;\n#endif\n}\n\nvoid PPCRecRARange_removeLink_allSegmentRanges(raLivenessRange** root, raLivenessRange* subrange)\n{\n\traLivenessRange* tempPrev = subrange->link_allSegmentRanges.prev;\n\tif (subrange->link_allSegmentRanges.prev)\n\t\tsubrange->link_allSegmentRanges.prev->link_allSegmentRanges.next = subrange->link_allSegmentRanges.next;\n\telse\n\t\t(*root) = subrange->link_allSegmentRanges.next;\n\tif (subrange->link_allSegmentRanges.next)\n\t\tsubrange->link_allSegmentRanges.next->link_allSegmentRanges.prev = tempPrev;\n#ifdef CEMU_DEBUG_ASSERT\n\tsubrange->link_allSegmentRanges.prev = (raLivenessRange*)1;\n\tsubrange->link_allSegmentRanges.next = (raLivenessRange*)1;\n#endif\n}\n\nMemoryPoolPermanentObjects<raLivenessRange> memPool_livenessSubrange(4096);\n\n// startPosition and endPosition are inclusive\nraLivenessRange* IMLRA_CreateRange(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, IMLRegID virtualRegister, IMLName name, raInstructionEdge startPosition, raInstructionEdge endPosition)\n{\n\traLivenessRange* range = memPool_livenessSubrange.acquireObj();\n\trange->previousRanges.clear();\n\trange->list_accessLocations.clear();\n\trange->list_fixedRegRequirements.clear();\n\trange->imlSegment = imlSegment;\n\n\tcemu_assert_debug(startPosition <= endPosition);\n\trange->interval.start = startPosition;\n\trange->interval.end = endPosition;\n\n\t// register mapping\n\trange->virtualRegister = virtualRegister;\n\trange->name = name;\n\trange->physicalRegister = -1;\n\t// default values\n\trange->hasStore = false;\n\trange->hasStoreDelayed = false;\n\trange->lastIterationIndex = 0;\n\trange->subrangeBranchNotTaken = nullptr;\n\trange->subrangeBranchTaken = nullptr;\n\tcemu_assert_debug(range->previousRanges.empty());\n\trange->_noLoad = false;\n\t// add to segment linked lists\n\tPPCRecRARange_addLink_perVirtualGPR(imlSegment->raInfo.linkedList_perVirtualRegister, range);\n\tPPCRecRARange_addLink_allSegmentRanges(&imlSegment->raInfo.linkedList_allSubranges, range);\n\treturn range;\n}\n\nvoid _unlinkSubrange(raLivenessRange* range)\n{\n\tIMLSegment* imlSegment = range->imlSegment;\n\tPPCRecRARange_removeLink_perVirtualGPR(imlSegment->raInfo.linkedList_perVirtualRegister, range);\n\tPPCRecRARange_removeLink_allSegmentRanges(&imlSegment->raInfo.linkedList_allSubranges, range);\n\t// unlink reverse references\n\tif(range->subrangeBranchTaken)\n\t\trange->subrangeBranchTaken->previousRanges.erase(std::find(range->subrangeBranchTaken->previousRanges.begin(), range->subrangeBranchTaken->previousRanges.end(), range));\n\tif(range->subrangeBranchNotTaken)\n\t\trange->subrangeBranchNotTaken->previousRanges.erase(std::find(range->subrangeBranchNotTaken->previousRanges.begin(), range->subrangeBranchNotTaken->previousRanges.end(), range));\n\trange->subrangeBranchTaken = (raLivenessRange*)(uintptr_t)-1;\n\trange->subrangeBranchNotTaken = (raLivenessRange*)(uintptr_t)-1;\n\t// remove forward references\n\tfor(auto& prev : range->previousRanges)\n\t{\n\t\tif(prev->subrangeBranchTaken == range)\n\t\t\tprev->subrangeBranchTaken = nullptr;\n\t\tif(prev->subrangeBranchNotTaken == range)\n\t\t\tprev->subrangeBranchNotTaken = nullptr;\n\t}\n\trange->previousRanges.clear();\n}\n\nvoid IMLRA_DeleteRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* range)\n{\n\t_unlinkSubrange(range);\n\trange->list_accessLocations.clear();\n\trange->list_fixedRegRequirements.clear();\n\tmemPool_livenessSubrange.releaseObj(range);\n}\n\nvoid IMLRA_DeleteRangeCluster(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* range)\n{\n\tauto clusterRanges = range->GetAllSubrangesInCluster();\n\tfor (auto& subrange : clusterRanges)\n\t\tIMLRA_DeleteRange(ppcImlGenContext, subrange);\n}\n\nvoid IMLRA_DeleteAllRanges(ppcImlGenContext_t* ppcImlGenContext)\n{\n\tfor(auto& seg : ppcImlGenContext->segmentList2)\n\t{\n\t\traLivenessRange* cur;\n\t\twhile ((cur = seg->raInfo.linkedList_allSubranges))\n\t\t\tIMLRA_DeleteRange(ppcImlGenContext, cur);\n\t\tseg->raInfo.linkedList_allSubranges = nullptr;\n\t\tseg->raInfo.linkedList_perVirtualRegister.clear();\n\t}\n}\n\nvoid IMLRA_MergeSubranges(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange, raLivenessRange* absorbedSubrange)\n{\n#ifdef CEMU_DEBUG_ASSERT\n\tPPCRecRA_debugValidateSubrange(subrange);\n\tPPCRecRA_debugValidateSubrange(absorbedSubrange);\n\tif (subrange->imlSegment != absorbedSubrange->imlSegment)\n\t\tassert_dbg();\n\tcemu_assert_debug(subrange->interval.end == absorbedSubrange->interval.start);\n\n\tif (subrange->subrangeBranchTaken || subrange->subrangeBranchNotTaken)\n\t\tassert_dbg();\n\tif (subrange == absorbedSubrange)\n\t\tassert_dbg();\n#endif\n\t// update references\n\tsubrange->subrangeBranchTaken = absorbedSubrange->subrangeBranchTaken;\n\tsubrange->subrangeBranchNotTaken = absorbedSubrange->subrangeBranchNotTaken;\n\tabsorbedSubrange->subrangeBranchTaken = nullptr;\n\tabsorbedSubrange->subrangeBranchNotTaken = nullptr;\n\tif(subrange->subrangeBranchTaken)\n\t\t*std::find(subrange->subrangeBranchTaken->previousRanges.begin(), subrange->subrangeBranchTaken->previousRanges.end(), absorbedSubrange) = subrange;\n\tif(subrange->subrangeBranchNotTaken)\n\t\t*std::find(subrange->subrangeBranchNotTaken->previousRanges.begin(), subrange->subrangeBranchNotTaken->previousRanges.end(), absorbedSubrange) = subrange;\n\n\t// merge usage locations\n\tfor (auto& accessLoc : absorbedSubrange->list_accessLocations)\n\t\tsubrange->list_accessLocations.push_back(accessLoc);\n\tabsorbedSubrange->list_accessLocations.clear();\n\t// merge fixed reg locations\n#ifdef CEMU_DEBUG_ASSERT\n\tif(!subrange->list_fixedRegRequirements.empty() && !absorbedSubrange->list_fixedRegRequirements.empty())\n\t{\n\t\tcemu_assert_debug(subrange->list_fixedRegRequirements.back().pos < absorbedSubrange->list_fixedRegRequirements.front().pos);\n\t}\n#endif\n\tfor (auto& fixedReg : absorbedSubrange->list_fixedRegRequirements)\n\t\tsubrange->list_fixedRegRequirements.push_back(fixedReg);\n\tabsorbedSubrange->list_fixedRegRequirements.clear();\n\n\tsubrange->interval.end = absorbedSubrange->interval.end;\n\n\tPPCRecRA_debugValidateSubrange(subrange);\n\n\tIMLRA_DeleteRange(ppcImlGenContext, absorbedSubrange);\n}\n\n// remove all inter-segment connections from the range cluster and split it into local ranges. Ranges are trimmed and if they have no access location they will be removed\nvoid IMLRA_ExplodeRangeCluster(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* originRange)\n{\n\tcemu_assert_debug(originRange->interval.ExtendsPreviousSegment() || originRange->interval.ExtendsIntoNextSegment()); // only call this on ranges that span multiple segments\n\tauto clusterRanges = originRange->GetAllSubrangesInCluster();\n\tfor (auto& subrange : clusterRanges)\n\t{\n\t\tif (subrange->list_accessLocations.empty())\n\t\t\tcontinue;\n\t\traInterval interval;\n\t\tinterval.SetInterval(subrange->list_accessLocations.front().pos, subrange->list_accessLocations.back().pos);\n\t\traLivenessRange* newSubrange = IMLRA_CreateRange(ppcImlGenContext, subrange->imlSegment, subrange->GetVirtualRegister(), subrange->GetName(), interval.start, interval.end);\n\t\t// copy locations and fixed reg indices\n\t\tnewSubrange->list_accessLocations = subrange->list_accessLocations;\n\t\tnewSubrange->list_fixedRegRequirements = subrange->list_fixedRegRequirements;\n\t\tif(originRange->HasPhysicalRegister())\n\t\t{\n\t\t\tcemu_assert_debug(subrange->list_fixedRegRequirements.empty()); // avoid unassigning a register from a range with a fixed register requirement\n\t\t}\n\t\t// validate\n\t\tif(!newSubrange->list_accessLocations.empty())\n\t\t{\n\t\t\tcemu_assert_debug(newSubrange->list_accessLocations.front().pos >= newSubrange->interval.start);\n\t\t\tcemu_assert_debug(newSubrange->list_accessLocations.back().pos <= newSubrange->interval.end);\n\t\t}\n\t\tif(!newSubrange->list_fixedRegRequirements.empty())\n\t\t{\n\t\t\tcemu_assert_debug(newSubrange->list_fixedRegRequirements.front().pos >= newSubrange->interval.start); // fixed register requirements outside of the actual access range probably means there is a mistake in GetInstructionFixedRegisters()\n\t\t\tcemu_assert_debug(newSubrange->list_fixedRegRequirements.back().pos <= newSubrange->interval.end);\n\t\t}\n\t}\n\t// delete the original range cluster\n\tIMLRA_DeleteRangeCluster(ppcImlGenContext, originRange);\n}\n\n#ifdef CEMU_DEBUG_ASSERT\nvoid PPCRecRA_debugValidateSubrange(raLivenessRange* range)\n{\n\t// validate subrange\n\tif (range->subrangeBranchTaken && range->subrangeBranchTaken->imlSegment != range->imlSegment->nextSegmentBranchTaken)\n\t\tassert_dbg();\n\tif (range->subrangeBranchNotTaken && range->subrangeBranchNotTaken->imlSegment != range->imlSegment->nextSegmentBranchNotTaken)\n\t\tassert_dbg();\n\n\tif(range->subrangeBranchTaken || range->subrangeBranchNotTaken)\n\t{\n\t\tcemu_assert_debug(range->interval.end.ConnectsToNextSegment());\n\t}\n\tif(!range->previousRanges.empty())\n\t{\n\t\tcemu_assert_debug(range->interval.start.ConnectsToPreviousSegment());\n\t}\n\t// validate locations\n\tif (!range->list_accessLocations.empty())\n\t{\n\t\tcemu_assert_debug(range->list_accessLocations.front().pos >= range->interval.start);\n\t\tcemu_assert_debug(range->list_accessLocations.back().pos <= range->interval.end);\n\t}\n\t// validate fixed reg requirements\n\tif (!range->list_fixedRegRequirements.empty())\n\t{\n\t\tcemu_assert_debug(range->list_fixedRegRequirements.front().pos >= range->interval.start);\n\t\tcemu_assert_debug(range->list_fixedRegRequirements.back().pos <= range->interval.end);\n\t\tfor(sint32 i = 0; i < (sint32)range->list_fixedRegRequirements.size()-1; i++)\n\t\t\tcemu_assert_debug(range->list_fixedRegRequirements[i].pos < range->list_fixedRegRequirements[i+1].pos);\n\t}\n\n}\n#else\nvoid PPCRecRA_debugValidateSubrange(raLivenessRange* range) {}\n#endif\n\n// trim start and end of range to match first and last read/write locations\n// does not trim start/endpoints which extend into the next/previous segment\nvoid IMLRA_TrimRangeToUse(raLivenessRange* range)\n{\n\tif(range->list_accessLocations.empty())\n\t{\n\t\t// special case where we trim ranges extending from other segments to a single instruction edge\n\t\tcemu_assert_debug(!range->interval.start.IsInstructionIndex() || !range->interval.end.IsInstructionIndex());\n\t\tif(range->interval.start.IsInstructionIndex())\n\t\t\trange->interval.start = range->interval.end;\n\t\tif(range->interval.end.IsInstructionIndex())\n\t\t\trange->interval.end = range->interval.start;\n\t\treturn;\n\t}\n\t// trim start and end\n\traInterval prevInterval = range->interval;\n\tif(range->interval.start.IsInstructionIndex())\n\t\trange->interval.start = range->list_accessLocations.front().pos;\n\tif(range->interval.end.IsInstructionIndex())\n\t\trange->interval.end = range->list_accessLocations.back().pos;\n\t// extra checks\n#ifdef CEMU_DEBUG_ASSERT\n\tcemu_assert_debug(range->interval.start <= range->interval.end);\n\tfor(auto& loc : range->list_accessLocations)\n\t{\n\t\tcemu_assert_debug(range->interval.ContainsEdge(loc.pos));\n\t}\n\tcemu_assert_debug(prevInterval.ContainsWholeInterval(range->interval));\n#endif\n}\n\n// split range at the given position\n// After the split there will be two ranges:\n// head -> subrange is shortened to end at splitIndex (exclusive)\n// tail -> a new subrange that ranges from splitIndex (inclusive) to the end of the original subrange\n// if head has a physical register assigned it will not carry over to tail\n// The return value is the tail range\n// If trimToUsage is true, the end of the head subrange and the start of the tail subrange will be shrunk to fit the read/write locations within. If there are no locations then the range will be deleted\nraLivenessRange* IMLRA_SplitRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange*& subrange, raInstructionEdge splitPosition, bool trimToUsage)\n{\n\tcemu_assert_debug(splitPosition.IsInstructionIndex());\n\tcemu_assert_debug(!subrange->interval.IsNextSegmentOnly() && !subrange->interval.IsPreviousSegmentOnly());\n\tcemu_assert_debug(subrange->interval.ContainsEdge(splitPosition));\n\t// determine new intervals\n\traInterval headInterval, tailInterval;\n\theadInterval.SetInterval(subrange->interval.start, splitPosition-1);\n\ttailInterval.SetInterval(splitPosition, subrange->interval.end);\n\tcemu_assert_debug(headInterval.start <= headInterval.end);\n\tcemu_assert_debug(tailInterval.start <= tailInterval.end);\n\t// create tail\n\traLivenessRange* tailSubrange = IMLRA_CreateRange(ppcImlGenContext, subrange->imlSegment, subrange->GetVirtualRegister(), subrange->GetName(), tailInterval.start, tailInterval.end);\n\ttailSubrange->SetPhysicalRegister(subrange->GetPhysicalRegister());\n\t// carry over branch targets and update reverse references\n\ttailSubrange->subrangeBranchTaken = subrange->subrangeBranchTaken;\n\ttailSubrange->subrangeBranchNotTaken = subrange->subrangeBranchNotTaken;\n\tsubrange->subrangeBranchTaken = nullptr;\n\tsubrange->subrangeBranchNotTaken = nullptr;\n\tif(tailSubrange->subrangeBranchTaken)\n\t\t*std::find(tailSubrange->subrangeBranchTaken->previousRanges.begin(), tailSubrange->subrangeBranchTaken->previousRanges.end(), subrange) = tailSubrange;\n\tif(tailSubrange->subrangeBranchNotTaken)\n\t\t*std::find(tailSubrange->subrangeBranchNotTaken->previousRanges.begin(), tailSubrange->subrangeBranchNotTaken->previousRanges.end(), subrange) = tailSubrange;\n\t// we assume that list_locations is ordered by instruction index and contains no duplicate indices, so lets check that here just in case\n#ifdef CEMU_DEBUG_ASSERT\n\tif(subrange->list_accessLocations.size() > 1)\n\t{\n\t\tfor(size_t i=0; i<subrange->list_accessLocations.size()-1; i++)\n\t\t{\n\t\t\tcemu_assert_debug(subrange->list_accessLocations[i].pos < subrange->list_accessLocations[i+1].pos);\n\t\t}\n\t}\n#endif\n\t// split locations\n\tauto it = std::lower_bound(\n\t\tsubrange->list_accessLocations.begin(), subrange->list_accessLocations.end(), splitPosition,\n\t\t[](const raAccessLocation& accessLoc, raInstructionEdge value) { return accessLoc.pos < value; }\n\t);\n\tsize_t originalCount = subrange->list_accessLocations.size();\n\ttailSubrange->list_accessLocations.insert(tailSubrange->list_accessLocations.end(), it, subrange->list_accessLocations.end());\n\tsubrange->list_accessLocations.erase(it, subrange->list_accessLocations.end());\n\tcemu_assert_debug(subrange->list_accessLocations.empty() || subrange->list_accessLocations.back().pos < splitPosition);\n\tcemu_assert_debug(tailSubrange->list_accessLocations.empty() || tailSubrange->list_accessLocations.front().pos >= splitPosition);\n\tcemu_assert_debug(subrange->list_accessLocations.size() + tailSubrange->list_accessLocations.size() == originalCount);\n\t// split fixed reg requirements\n\tfor (sint32 i = 0; i < subrange->list_fixedRegRequirements.size(); i++)\n\t{\n\t\traFixedRegRequirement* fixedReg = subrange->list_fixedRegRequirements.data() + i;\n\t\tif (tailInterval.ContainsEdge(fixedReg->pos))\n\t\t{\n\t\t\ttailSubrange->list_fixedRegRequirements.push_back(*fixedReg);\n\t\t}\n\t}\n\t// remove tail fixed reg requirements from head\n\tfor (sint32 i = 0; i < subrange->list_fixedRegRequirements.size(); i++)\n\t{\n\t\traFixedRegRequirement* fixedReg = subrange->list_fixedRegRequirements.data() + i;\n\t\tif (!headInterval.ContainsEdge(fixedReg->pos))\n\t\t{\n\t\t\tsubrange->list_fixedRegRequirements.resize(i);\n\t\t\tbreak;\n\t\t}\n\t}\n\t// adjust intervals\n\tsubrange->interval = headInterval;\n\ttailSubrange->interval = tailInterval;\n\t// trim to hole\n\tif(trimToUsage)\n\t{\n\t\tif(subrange->list_accessLocations.empty() && (subrange->interval.start.IsInstructionIndex() && subrange->interval.end.IsInstructionIndex()))\n\t\t{\n\t\t\tIMLRA_DeleteRange(ppcImlGenContext, subrange);\n\t\t\tsubrange = nullptr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tIMLRA_TrimRangeToUse(subrange);\n\t\t}\n\t\tif(tailSubrange->list_accessLocations.empty() && (tailSubrange->interval.start.IsInstructionIndex() && tailSubrange->interval.end.IsInstructionIndex()))\n\t\t{\n\t\t\tIMLRA_DeleteRange(ppcImlGenContext, tailSubrange);\n\t\t\ttailSubrange = nullptr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tIMLRA_TrimRangeToUse(tailSubrange);\n\t\t}\n\t}\n\t// validation\n\tcemu_assert_debug(!subrange || subrange->interval.start <= subrange->interval.end);\n\tcemu_assert_debug(!tailSubrange || tailSubrange->interval.start <= tailSubrange->interval.end);\n\tcemu_assert_debug(!tailSubrange || tailSubrange->interval.start >= splitPosition);\n\tif (!trimToUsage)\n\t\tcemu_assert_debug(!tailSubrange || tailSubrange->interval.start == splitPosition);\n\n\tif(subrange)\n\t\tPPCRecRA_debugValidateSubrange(subrange);\n\tif(tailSubrange)\n\t\tPPCRecRA_debugValidateSubrange(tailSubrange);\n\treturn tailSubrange;\n}\n\nsint32 IMLRA_GetSegmentReadWriteCost(IMLSegment* imlSegment)\n{\n\tsint32 v = imlSegment->loopDepth + 1;\n\tv *= 5;\n\treturn v*v; // 25, 100, 225, 400\n}\n\n// calculate additional cost of range that it would have after calling _ExplodeRange() on it\nsint32 IMLRA_CalculateAdditionalCostOfRangeExplode(raLivenessRange* subrange)\n{\n\tauto ranges = subrange->GetAllSubrangesInCluster();\n\tsint32 cost = 0;//-PPCRecRARange_estimateTotalCost(ranges);\n\tfor (auto& subrange : ranges)\n\t{\n\t\tif (subrange->list_accessLocations.empty())\n\t\t\tcontinue; // this range would be deleted and thus has no cost\n\t\tsint32 segmentLoadStoreCost = IMLRA_GetSegmentReadWriteCost(subrange->imlSegment);\n\t\tbool hasAdditionalLoad = subrange->interval.ExtendsPreviousSegment();\n\t\tbool hasAdditionalStore = subrange->interval.ExtendsIntoNextSegment();\n\t\tif(hasAdditionalLoad && subrange->list_accessLocations.front().IsWrite()) // if written before read then a load isn't necessary\n\t\t{\n\t\t\tcemu_assert_debug(!subrange->list_accessLocations.front().IsRead());\n\t\t\tcost += segmentLoadStoreCost;\n\t\t}\n\t\tif(hasAdditionalStore)\n\t\t{\n\t\t\tbool hasWrite = std::find_if(subrange->list_accessLocations.begin(), subrange->list_accessLocations.end(), [](const raAccessLocation& loc) { return loc.IsWrite(); }) != subrange->list_accessLocations.end();\n\t\t\tif(!hasWrite) // ranges which don't modify their value do not need to be stored\n\t\t\t\tcost += segmentLoadStoreCost;\n\t\t}\n\t}\n\t// todo - properly calculating all the data-flow dependency based costs is more complex so this currently is an approximation\n\treturn cost;\n}\n\nsint32 IMLRA_CalculateAdditionalCostAfterSplit(raLivenessRange* subrange, raInstructionEdge splitPosition)\n{\n\t// validation\n#ifdef CEMU_DEBUG_ASSERT\n\tif (subrange->interval.ExtendsIntoNextSegment())\n\t\tassert_dbg();\n#endif\n\tcemu_assert_debug(splitPosition.IsInstructionIndex());\n\n\tsint32 cost = 0;\n\t// find split position in location list\n\tif (subrange->list_accessLocations.empty())\n\t\treturn 0;\n\tif (splitPosition <= subrange->list_accessLocations.front().pos)\n\t\treturn 0;\n\tif (splitPosition > subrange->list_accessLocations.back().pos)\n\t\treturn 0;\n\n\tsize_t firstTailLocationIndex = 0;\n\tfor (size_t i = 0; i < subrange->list_accessLocations.size(); i++)\n\t{\n\t\tif (subrange->list_accessLocations[i].pos >= splitPosition)\n\t\t{\n\t\t\tfirstTailLocationIndex = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\tstd::span<raAccessLocation> headLocations{subrange->list_accessLocations.data(), firstTailLocationIndex};\n\tstd::span<raAccessLocation> tailLocations{subrange->list_accessLocations.data() + firstTailLocationIndex, subrange->list_accessLocations.size() - firstTailLocationIndex};\n\tcemu_assert_debug(headLocations.empty() || headLocations.back().pos < splitPosition);\n\tcemu_assert_debug(tailLocations.empty() || tailLocations.front().pos >= splitPosition);\n\n\tsint32 segmentLoadStoreCost = IMLRA_GetSegmentReadWriteCost(subrange->imlSegment);\n\n\tauto CalculateCostFromLocationRange = [segmentLoadStoreCost](std::span<raAccessLocation> locations, bool trackLoadCost = true, bool trackStoreCost = true) -> sint32\n\t{\n\t\tif(locations.empty())\n\t\t\treturn 0;\n\t\tsint32 cost = 0;\n\t\tif(locations.front().IsRead() && trackLoadCost)\n\t\t\tcost += segmentLoadStoreCost; // not overwritten, so there is a load cost\n\t\tbool hasWrite = std::find_if(locations.begin(), locations.end(), [](const raAccessLocation& loc) { return loc.IsWrite(); }) != locations.end();\n\t\tif(hasWrite && trackStoreCost)\n\t\t\tcost += segmentLoadStoreCost; // modified, so there is a store cost\n\t\treturn cost;\n\t};\n\n\tsint32 baseCost = CalculateCostFromLocationRange(subrange->list_accessLocations);\n\n\tbool tailOverwritesValue = !tailLocations.empty() && !tailLocations.front().IsRead() && tailLocations.front().IsWrite();\n\n\tsint32 newCost = CalculateCostFromLocationRange(headLocations) + CalculateCostFromLocationRange(tailLocations, !tailOverwritesValue, true);\n\tcemu_assert_debug(newCost >= baseCost);\n\tcost = newCost - baseCost;\n\n\treturn cost;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLRegisterAllocatorRanges.h",
    "content": "#pragma once\n#include \"IMLRegisterAllocator.h\"\n\nstruct raLivenessSubrangeLink\n{\n\tstruct raLivenessRange* prev;\n\tstruct raLivenessRange* next;\n};\n\nstruct raInstructionEdge\n{\n\tfriend struct raInterval;\npublic:\n\traInstructionEdge()\n\t{\n\t\tindex = 0;\n\t}\n\n\traInstructionEdge(sint32 instructionIndex, bool isInputEdge)\n\t{\n\t\tSet(instructionIndex, isInputEdge);\n\t}\n\n\tvoid Set(sint32 instructionIndex, bool isInputEdge)\n\t{\n\t\tif(instructionIndex == RA_INTER_RANGE_START || instructionIndex == RA_INTER_RANGE_END)\n\t\t{\n\t\t\tindex = instructionIndex;\n\t\t\treturn;\n\t\t}\n\t\tindex = instructionIndex * 2 + (isInputEdge ? 0 : 1);\n\t\tcemu_assert_debug(index >= 0 && index < 0x100000*2); // make sure index value is sane\n\t}\n\n\tvoid SetRaw(sint32 index)\n\t{\n\t\tthis->index = index;\n\t\tcemu_assert_debug(index == RA_INTER_RANGE_START || index == RA_INTER_RANGE_END || (index >= 0 && index < 0x100000*2)); // make sure index value is sane\n\t}\n\n\t// sint32 GetRaw()\n\t// {\n\t// \tthis->index = index;\n\t// }\n\n\tstd::string GetDebugString()\n\t{\n\t\tif(index == RA_INTER_RANGE_START)\n\t\t\treturn \"RA_START\";\n\t\telse if(index == RA_INTER_RANGE_END)\n\t\t\treturn \"RA_END\";\n\t\tstd::string str = fmt::format(\"{}\", GetInstructionIndex());\n\t\tif(IsOnInputEdge())\n\t\t\tstr += \"i\";\n\t\telse if(IsOnOutputEdge())\n\t\t\tstr += \"o\";\n\t\treturn str;\n\t}\n\n\tsint32 GetInstructionIndex() const\n\t{\n\t\tcemu_assert_debug(index != RA_INTER_RANGE_START && index != RA_INTER_RANGE_END);\n\t\treturn index >> 1;\n\t}\n\n\t// returns instruction index or RA_INTER_RANGE_START/RA_INTER_RANGE_END\n\tsint32 GetInstructionIndexEx() const\n\t{\n\t\tif(index == RA_INTER_RANGE_START || index == RA_INTER_RANGE_END)\n\t\t\treturn index;\n\t\treturn index >> 1;\n\t}\n\n\tsint32 GetRaw() const\n\t{\n\t\treturn index;\n\t}\n\n\tbool IsOnInputEdge() const\n\t{\n\t\tcemu_assert_debug(index != RA_INTER_RANGE_START && index != RA_INTER_RANGE_END);\n\t\treturn (index&1) == 0;\n\t}\n\n\tbool IsOnOutputEdge() const\n\t{\n\t\tcemu_assert_debug(index != RA_INTER_RANGE_START && index != RA_INTER_RANGE_END);\n\t\treturn (index&1) != 0;\n\t}\n\n\tbool ConnectsToPreviousSegment() const\n\t{\n\t\treturn index == RA_INTER_RANGE_START;\n\t}\n\n\tbool ConnectsToNextSegment() const\n\t{\n\t\treturn index == RA_INTER_RANGE_END;\n\t}\n\n\tbool IsInstructionIndex() const\n\t{\n\t\treturn index != RA_INTER_RANGE_START && index != RA_INTER_RANGE_END;\n\t}\n\n\t// comparison operators\n\tbool operator>(const raInstructionEdge& other) const\n\t{\n\t\treturn index > other.index;\n\t}\n\tbool operator<(const raInstructionEdge& other) const\n\t{\n\t\treturn index < other.index;\n\t}\n\tbool operator<=(const raInstructionEdge& other) const\n\t{\n\t\treturn index <= other.index;\n\t}\n\tbool operator>=(const raInstructionEdge& other) const\n\t{\n\t\treturn index >= other.index;\n\t}\n\tbool operator==(const raInstructionEdge& other) const\n\t{\n\t\treturn index == other.index;\n\t}\n\n\traInstructionEdge operator+(sint32 offset) const\n\t{\n\t\tcemu_assert_debug(IsInstructionIndex());\n\t\tcemu_assert_debug(offset >= 0 && offset < RA_INTER_RANGE_END);\n\t\traInstructionEdge edge;\n\t\tedge.index = index + offset;\n\t\treturn edge;\n\t}\n\n\traInstructionEdge operator-(sint32 offset) const\n\t{\n\t\tcemu_assert_debug(IsInstructionIndex());\n\t\tcemu_assert_debug(offset >= 0 && offset < RA_INTER_RANGE_END);\n\t\traInstructionEdge edge;\n\t\tedge.index = index - offset;\n\t\treturn edge;\n\t}\n\n\traInstructionEdge& operator++()\n\t{\n\t\tcemu_assert_debug(IsInstructionIndex());\n\t\tindex++;\n\t\treturn *this;\n\t}\n\nprivate:\n\tsint32 index; // can also be RA_INTER_RANGE_START or RA_INTER_RANGE_END, otherwise contains instruction index * 2\n\n};\n\nstruct raAccessLocation\n{\n\traAccessLocation(raInstructionEdge pos) : pos(pos) {}\n\n\tbool IsRead() const\n\t{\n\t\treturn pos.IsOnInputEdge();\n\t}\n\n\tbool IsWrite() const\n\t{\n\t\treturn pos.IsOnOutputEdge();\n\t}\n\n\traInstructionEdge pos;\n};\n\nstruct raInterval\n{\n\traInterval()\n\t{\n\n\t}\n\n\traInterval(raInstructionEdge start, raInstructionEdge end)\n\t{\n\t\tSetInterval(start, end);\n\t}\n\n\t// isStartOnInput = Input+Output edge on first instruction. If false then only output\n\t// isEndOnOutput = Input+Output edge on last instruction. If false then only input\n\tvoid SetInterval(sint32 start, bool isStartOnInput, sint32 end, bool isEndOnOutput)\n\t{\n\t\tthis->start.Set(start, isStartOnInput);\n\t\tthis->end.Set(end, !isEndOnOutput);\n\t}\n\n\tvoid SetInterval(raInstructionEdge start, raInstructionEdge end)\n\t{\n\t\tcemu_assert_debug(start <= end);\n\t\tthis->start = start;\n\t\tthis->end = end;\n\t}\n\n\tvoid SetStart(const raInstructionEdge& edge)\n\t{\n\t\tstart = edge;\n\t}\n\n\tvoid SetEnd(const raInstructionEdge& edge)\n\t{\n\t\tend = edge;\n\t}\n\n\tsint32 GetStartIndex() const\n\t{\n\t\treturn start.GetInstructionIndex();\n\t}\n\n\tsint32 GetEndIndex() const\n\t{\n\t\treturn end.GetInstructionIndex();\n\t}\n\n\tbool ExtendsPreviousSegment() const\n\t{\n\t\treturn start.ConnectsToPreviousSegment();\n\t}\n\n\tbool ExtendsIntoNextSegment() const\n\t{\n\t\treturn end.ConnectsToNextSegment();\n\t}\n\n\tbool IsNextSegmentOnly() const\n\t{\n\t\treturn start.ConnectsToNextSegment() && end.ConnectsToNextSegment();\n\t}\n\n\tbool IsPreviousSegmentOnly() const\n\t{\n\t\treturn start.ConnectsToPreviousSegment() && end.ConnectsToPreviousSegment();\n\t}\n\n\t// returns true if range is contained within a single segment\n\tbool IsLocal() const\n\t{\n\t\treturn start.GetRaw() > RA_INTER_RANGE_START && end.GetRaw() < RA_INTER_RANGE_END;\n\t}\n\n\tbool ContainsInstructionIndex(sint32 instructionIndex) const\n\t{\n\t\tcemu_assert_debug(instructionIndex != RA_INTER_RANGE_START && instructionIndex != RA_INTER_RANGE_END);\n\t\treturn instructionIndex >= start.GetInstructionIndexEx() && instructionIndex <= end.GetInstructionIndexEx();\n\t}\n\n\t// similar to ContainsInstructionIndex, but allows RA_INTER_RANGE_START/END as input\n\tbool ContainsInstructionIndexEx(sint32 instructionIndex) const\n\t{\n\t\tif(instructionIndex == RA_INTER_RANGE_START)\n\t\t\treturn start.ConnectsToPreviousSegment();\n\t\tif(instructionIndex == RA_INTER_RANGE_END)\n\t\t\treturn end.ConnectsToNextSegment();\n\t\treturn instructionIndex >= start.GetInstructionIndexEx() && instructionIndex <= end.GetInstructionIndexEx();\n\t}\n\n\tbool ContainsEdge(const raInstructionEdge& edge) const\n\t{\n\t\treturn edge >= start && edge <= end;\n\t}\n\n\tbool ContainsWholeInterval(const raInterval& other) const\n\t{\n\t\treturn other.start >= start && other.end <= end;\n\t}\n\n\tbool IsOverlapping(const raInterval& other) const\n\t{\n\t\treturn start <= other.end && end >= other.start;\n\t}\n\n\tsint32 GetPreciseDistance()\n\t{\n\t\tcemu_assert_debug(!start.ConnectsToNextSegment()); // how to handle this?\n\t\tif(start == end)\n\t\t\treturn 1;\n\t\tcemu_assert_debug(!end.ConnectsToPreviousSegment() && !end.ConnectsToNextSegment());\n\t\tif(start.ConnectsToPreviousSegment())\n\t\t\treturn end.GetRaw() + 1;\n\n\t\treturn end.GetRaw() - start.GetRaw() + 1; // +1 because end is inclusive\n\t}\n\n//private: not making these directly accessible only forces us to create loads of verbose getters and setters\n\traInstructionEdge start;\n\traInstructionEdge end;\n};\n\nstruct raFixedRegRequirement\n{\n\traInstructionEdge pos;\n\tIMLPhysRegisterSet allowedReg;\n};\n\nstruct raLivenessRange\n{\n\tIMLSegment* imlSegment;\n\traInterval interval;\n\n\t// dirty state tracking\n\tbool _noLoad;\n\tbool hasStore;\n\tbool hasStoreDelayed;\n\t// next\n\traLivenessRange* subrangeBranchTaken;\n\traLivenessRange* subrangeBranchNotTaken;\n\t// reverse counterpart of BranchTaken/BranchNotTaken\n\tboost::container::small_vector<raLivenessRange*, 4> previousRanges;\n\t// processing\n\tuint32 lastIterationIndex;\n\t// instruction read/write locations\n\tstd::vector<raAccessLocation> list_accessLocations;\n\t// ordered list of all raInstructionEdge indices which require a fixed register\n\tstd::vector<raFixedRegRequirement> list_fixedRegRequirements;\n\t// linked list (subranges with same GPR virtual register)\n\traLivenessSubrangeLink link_sameVirtualRegister;\n\t// linked list (all subranges for this segment)\n\traLivenessSubrangeLink link_allSegmentRanges;\n\t// register info\n\tIMLRegID virtualRegister;\n\tIMLName name;\n\t// register allocator result\n\tIMLPhysReg physicalRegister;\n\n\tboost::container::small_vector<raLivenessRange*, 128> GetAllSubrangesInCluster();\n\tbool GetAllowedRegistersEx(IMLPhysRegisterSet& allowedRegisters); // if the cluster has fixed register requirements in any instruction this returns the combined register mask. Otherwise returns false in which case allowedRegisters is left undefined\n\tIMLPhysRegisterSet GetAllowedRegisters(IMLPhysRegisterSet regPool); // return regPool with fixed register requirements filtered out\n\n\tIMLRegID GetVirtualRegister() const;\n\tsint32 GetPhysicalRegister() const;\n\tbool HasPhysicalRegister() const { return physicalRegister >= 0; }\n\tIMLName GetName() const;\n\tvoid SetPhysicalRegister(IMLPhysReg physicalRegister);\n\tvoid SetPhysicalRegisterForCluster(IMLPhysReg physicalRegister);\n\tvoid UnsetPhysicalRegister() { physicalRegister = -1; }\n\n  private:\n\tvoid GetAllowedRegistersExRecursive(raLivenessRange* range, uint32 iterationIndex, IMLPhysRegisterSet& allowedRegs);\n};\n\nraLivenessRange* IMLRA_CreateRange(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* imlSegment, IMLRegID virtualRegister, IMLName name, raInstructionEdge startPosition, raInstructionEdge endPosition);\nvoid IMLRA_DeleteRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange);\nvoid IMLRA_DeleteAllRanges(ppcImlGenContext_t* ppcImlGenContext);\n\nvoid IMLRA_ExplodeRangeCluster(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* originRange);\n\nvoid IMLRA_MergeSubranges(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange* subrange, raLivenessRange* absorbedSubrange);\n\nraLivenessRange* IMLRA_SplitRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange*& subrange, raInstructionEdge splitPosition, bool trimToUsage = false);\n\nvoid PPCRecRA_debugValidateSubrange(raLivenessRange* subrange);\n\n// cost estimation\nsint32 IMLRA_GetSegmentReadWriteCost(IMLSegment* imlSegment);\nsint32 IMLRA_CalculateAdditionalCostOfRangeExplode(raLivenessRange* subrange);\n//sint32 PPCRecRARange_estimateAdditionalCostAfterSplit(raLivenessRange* subrange, sint32 splitIndex);\nsint32 IMLRA_CalculateAdditionalCostAfterSplit(raLivenessRange* subrange, raInstructionEdge splitPosition);"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLSegment.cpp",
    "content": "#include \"IMLInstruction.h\"\n#include \"IMLSegment.h\"\n\nvoid IMLSegment::SetEnterable(uint32 enterAddress)\n{\n\tcemu_assert_debug(!isEnterable || enterPPCAddress == enterAddress);\n\tisEnterable = true;\n\tenterPPCAddress = enterAddress;\n}\n\nbool IMLSegment::HasSuffixInstruction() const\n{\n\tif (imlList.empty())\n\t\treturn false;\n\tconst IMLInstruction& imlInstruction = imlList.back();\n\treturn imlInstruction.IsSuffixInstruction();\n}\n\nsint32 IMLSegment::GetSuffixInstructionIndex() const\n{\n\tcemu_assert_debug(HasSuffixInstruction());\n\treturn (sint32)(imlList.size() - 1);\n}\n\nIMLInstruction* IMLSegment::GetLastInstruction()\n{\n\tif (imlList.empty())\n\t\treturn nullptr;\n\treturn &imlList.back();\n}\n\nvoid IMLSegment::SetLinkBranchNotTaken(IMLSegment* imlSegmentDst)\n{\n\tif (nextSegmentBranchNotTaken)\n\t\tnextSegmentBranchNotTaken->list_prevSegments.erase(std::find(nextSegmentBranchNotTaken->list_prevSegments.begin(), nextSegmentBranchNotTaken->list_prevSegments.end(), this));\n\tnextSegmentBranchNotTaken = imlSegmentDst;\n\tif(imlSegmentDst)\n\t\timlSegmentDst->list_prevSegments.push_back(this);\n}\n\nvoid IMLSegment::SetLinkBranchTaken(IMLSegment* imlSegmentDst)\n{\n\tif (nextSegmentBranchTaken)\n\t\tnextSegmentBranchTaken->list_prevSegments.erase(std::find(nextSegmentBranchTaken->list_prevSegments.begin(), nextSegmentBranchTaken->list_prevSegments.end(), this));\n\tnextSegmentBranchTaken = imlSegmentDst;\n\tif (imlSegmentDst)\n\t\timlSegmentDst->list_prevSegments.push_back(this);\n}\n\nIMLInstruction* IMLSegment::AppendInstruction()\n{\n\tIMLInstruction& inst = imlList.emplace_back();\n\tmemset(&inst, 0, sizeof(IMLInstruction));\n\treturn &inst;\n}\n\nvoid IMLSegment_SetLinkBranchNotTaken(IMLSegment* imlSegmentSrc, IMLSegment* imlSegmentDst)\n{\n\t// make sure segments aren't already linked\n\tif (imlSegmentSrc->nextSegmentBranchNotTaken == imlSegmentDst)\n\t\treturn;\n\t// add as next segment for source\n\tif (imlSegmentSrc->nextSegmentBranchNotTaken != nullptr)\n\t\tassert_dbg();\n\timlSegmentSrc->nextSegmentBranchNotTaken = imlSegmentDst;\n\t// add as previous segment for destination\n\timlSegmentDst->list_prevSegments.push_back(imlSegmentSrc);\n}\n\nvoid IMLSegment_SetLinkBranchTaken(IMLSegment* imlSegmentSrc, IMLSegment* imlSegmentDst)\n{\n\t// make sure segments aren't already linked\n\tif (imlSegmentSrc->nextSegmentBranchTaken == imlSegmentDst)\n\t\treturn;\n\t// add as next segment for source\n\tif (imlSegmentSrc->nextSegmentBranchTaken != nullptr)\n\t\tassert_dbg();\n\timlSegmentSrc->nextSegmentBranchTaken = imlSegmentDst;\n\t// add as previous segment for destination\n\timlSegmentDst->list_prevSegments.push_back(imlSegmentSrc);\n}\n\nvoid IMLSegment_RemoveLink(IMLSegment* imlSegmentSrc, IMLSegment* imlSegmentDst)\n{\n\tif (imlSegmentSrc->nextSegmentBranchNotTaken == imlSegmentDst)\n\t{\n\t\timlSegmentSrc->nextSegmentBranchNotTaken = nullptr;\n\t}\n\telse if (imlSegmentSrc->nextSegmentBranchTaken == imlSegmentDst)\n\t{\n\t\timlSegmentSrc->nextSegmentBranchTaken = nullptr;\n\t}\n\telse\n\t\tassert_dbg();\n\n\tbool matchFound = false;\n\tfor (sint32 i = 0; i < imlSegmentDst->list_prevSegments.size(); i++)\n\t{\n\t\tif (imlSegmentDst->list_prevSegments[i] == imlSegmentSrc)\n\t\t{\n\t\t\timlSegmentDst->list_prevSegments.erase(imlSegmentDst->list_prevSegments.begin() + i);\n\t\t\tmatchFound = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (matchFound == false)\n\t\tassert_dbg();\n}\n\n/*\n * Replaces all links to segment orig with linkts to segment new\n */\nvoid IMLSegment_RelinkInputSegment(IMLSegment* imlSegmentOrig, IMLSegment* imlSegmentNew)\n{\n\twhile (imlSegmentOrig->list_prevSegments.size() != 0)\n\t{\n\t\tIMLSegment* prevSegment = imlSegmentOrig->list_prevSegments[0];\n\t\tif (prevSegment->nextSegmentBranchNotTaken == imlSegmentOrig)\n\t\t{\n\t\t\tIMLSegment_RemoveLink(prevSegment, imlSegmentOrig);\n\t\t\tIMLSegment_SetLinkBranchNotTaken(prevSegment, imlSegmentNew);\n\t\t}\n\t\telse if (prevSegment->nextSegmentBranchTaken == imlSegmentOrig)\n\t\t{\n\t\t\tIMLSegment_RemoveLink(prevSegment, imlSegmentOrig);\n\t\t\tIMLSegment_SetLinkBranchTaken(prevSegment, imlSegmentNew);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/IML/IMLSegment.h",
    "content": "#pragma once\n#include \"IMLInstruction.h\"\n\n#include <boost/container/small_vector.hpp>\n\n// special values to mark the index of ranges that reach across the segment border\n#define RA_INTER_RANGE_START\t(-1)\n#define RA_INTER_RANGE_END\t\t(0x70000000)\n\nstruct IMLSegmentPoint\n{\n\tfriend struct IMLSegmentInterval;\n\n\tsint32 index;\n\tstruct IMLSegment* imlSegment; // do we really need to track this? SegmentPoints are always accessed via the segment that they are part of\n\tIMLSegmentPoint* next;\n\tIMLSegmentPoint* prev;\n\n\t// the index is the instruction index times two.\n\t// this gives us the ability to cover half an instruction with RA ranges\n\t// covering only the first half of an instruction (0-0) means that the register is read, but not preserved\n\t// covering first and the second half means the register is read and preserved\n\t// covering only the second half means the register is written but not read\n\n\tsint32 GetInstructionIndex() const\n\t{\n\t\treturn index;\n\t}\n\n\tvoid SetInstructionIndex(sint32 index)\n\t{\n\t\tthis->index = index;\n\t}\n\n\tvoid ShiftIfAfter(sint32 instructionIndex, sint32 shiftCount)\n\t{\n\t\tif (!IsPreviousSegment() && !IsNextSegment())\n\t\t{\n\t\t\tif (GetInstructionIndex() >= instructionIndex)\n\t\t\t\tindex += shiftCount;\n\t\t}\n\t}\n\n\tvoid DecrementByOneInstruction()\n\t{\n\t\tindex--;\n\t}\n\n\t// the segment point can point beyond the first and last instruction which indicates that it is an infinite range reaching up to the previous or next segment\n\tbool IsPreviousSegment() const { return index == RA_INTER_RANGE_START; }\n\tbool IsNextSegment() const { return index == RA_INTER_RANGE_END; }\n\n\t// overload operand > and <\n\tbool operator>(const IMLSegmentPoint& other) const { return index > other.index; }\n\tbool operator<(const IMLSegmentPoint& other) const { return index < other.index; }\n\tbool operator==(const IMLSegmentPoint& other) const { return index == other.index; }\n\tbool operator!=(const IMLSegmentPoint& other) const { return index != other.index; }\n\n\t// overload comparison operands for sint32\n\tbool operator>(const sint32 other) const { return index > other; }\n\tbool operator<(const sint32 other) const { return index < other; }\n\tbool operator<=(const sint32 other) const { return index <= other; }\n\tbool operator>=(const sint32 other) const { return index >= other; }\n};\n\nstruct IMLSegmentInterval\n{\n\tIMLSegmentPoint start;\n\tIMLSegmentPoint end;\n\n\tbool ContainsInstructionIndex(sint32 offset) const { return start <= offset && end > offset; }\n\n\tbool IsRangeOverlapping(const IMLSegmentInterval& other)\n\t{\n\t\t// todo - compare the raw index\n\t\tsint32 r1start = this->start.GetInstructionIndex();\n\t\tsint32 r1end = this->end.GetInstructionIndex();\n\t\tsint32 r2start = other.start.GetInstructionIndex();\n\t\tsint32 r2end = other.end.GetInstructionIndex();\n\t\tif (r1start < r2end && r1end > r2start)\n\t\t\treturn true;\n\t\tif (this->start.IsPreviousSegment() && r1start == r2start)\n\t\t\treturn true;\n\t\tif (this->end.IsNextSegment() && r1end == r2end)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\tbool ExtendsIntoPreviousSegment() const\n\t{\n\t\treturn start.IsPreviousSegment();\n\t}\n\n\tbool ExtendsIntoNextSegment() const\n\t{\n\t\treturn end.IsNextSegment();\n\t}\n\n\tbool IsNextSegmentOnly() const\n\t{\n\t\tif(!start.IsNextSegment())\n\t\t\treturn false;\n\t\tcemu_assert_debug(end.IsNextSegment());\n\t\treturn true;\n\t}\n\n\tbool IsPreviousSegmentOnly() const\n\t{\n\t\tif (!end.IsPreviousSegment())\n\t\t\treturn false;\n\t\tcemu_assert_debug(start.IsPreviousSegment());\n\t\treturn true;\n\t}\n\n\tsint32 GetDistance() const\n\t{\n\t\t// todo - assert if either start or end is outside the segment\n\t\t// we may also want to switch this to raw indices?\n\t\treturn end.GetInstructionIndex() - start.GetInstructionIndex();\n\t}\n};\n\nstruct PPCSegmentRegisterAllocatorInfo_t\n{\n\t// used during loop detection\n\tbool isPartOfProcessedLoop{}; \n\tsint32 lastIterationIndex{};\n\t// linked lists\n\tstruct raLivenessRange* linkedList_allSubranges{};\n\tstd::unordered_map<IMLRegID, struct raLivenessRange*> linkedList_perVirtualRegister;\n};\n\nstruct IMLSegment\n{\n\tsint32 momentaryIndex{}; // index in segment list, generally not kept up to date except if needed (necessary for loop detection)\n\tsint32 loopDepth{};\n\tuint32 ppcAddress{}; // ppc address (0xFFFFFFFF if not associated with an address)\n\tuint32 x64Offset{}; // x64 code offset of segment start\n\t// list of intermediate instructions in this segment\n\tstd::vector<IMLInstruction> imlList;\n\t// segment link\n\tIMLSegment* nextSegmentBranchNotTaken{}; // this is also the default for segments where there is no branch\n\tIMLSegment* nextSegmentBranchTaken{};\n\tbool nextSegmentIsUncertain{};\n\tstd::vector<IMLSegment*> list_prevSegments{};\n\t// source for overwrite analysis (if nextSegmentIsUncertain is true)\n\t// sometimes a segment is marked as an exit point, but for the purposes of dead code elimination we know the next segment\n\tIMLSegment* deadCodeEliminationHintSeg{};\n\tstd::vector<IMLSegment*> list_deadCodeHintBy{};\n\t// enterable segments\n\tbool isEnterable{}; // this segment can be entered from outside the recompiler (no preloaded registers necessary)\n\tuint32 enterPPCAddress{}; // used if isEnterable is true\n\t// register allocator info\n\tPPCSegmentRegisterAllocatorInfo_t raInfo{};\n\t// segment state API\n\tvoid SetEnterable(uint32 enterAddress);\n\tvoid SetLinkBranchNotTaken(IMLSegment* imlSegmentDst);\n\tvoid SetLinkBranchTaken(IMLSegment* imlSegmentDst);\n\n\tIMLSegment* GetBranchTaken()\n\t{\n\t\treturn nextSegmentBranchTaken;\n\t}\n\n\tIMLSegment* GetBranchNotTaken()\n\t{\n\t\treturn nextSegmentBranchNotTaken;\n\t}\n\n\tvoid SetNextSegmentForOverwriteHints(IMLSegment* seg)\n\t{\n\t\tcemu_assert_debug(!deadCodeEliminationHintSeg);\n\t\tdeadCodeEliminationHintSeg = seg;\n\t\tif (seg)\n\t\t\tseg->list_deadCodeHintBy.push_back(this);\n\t}\n\n\t// instruction API\n\tIMLInstruction* AppendInstruction();\n\n\tbool HasSuffixInstruction() const;\n\tsint32 GetSuffixInstructionIndex() const;\n\tIMLInstruction* GetLastInstruction();\n\n\t// segment points\n\tIMLSegmentPoint* segmentPointList{};\n};\n\n\nvoid IMLSegment_SetLinkBranchNotTaken(IMLSegment* imlSegmentSrc, IMLSegment* imlSegmentDst);\nvoid IMLSegment_SetLinkBranchTaken(IMLSegment* imlSegmentSrc, IMLSegment* imlSegmentDst);\nvoid IMLSegment_RelinkInputSegment(IMLSegment* imlSegmentOrig, IMLSegment* imlSegmentNew);\nvoid IMLSegment_RemoveLink(IMLSegment* imlSegmentSrc, IMLSegment* imlSegmentDst);\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h",
    "content": "#pragma once\n#include \"Cafe/HW/Espresso/EspressoISA.h\"\n#include \"Cafe/HW/MMU/MMU.h\"\n\nbool GamePatch_IsNonReturnFunction(uint32 hleIndex);\n\n// utility class to determine shape of a function\nclass PPCFunctionBoundaryTracker\n{\npublic:\n\tstruct PPCRange_t\n\t{\n\t\tPPCRange_t() = default;\n\t\tPPCRange_t(uint32 _startAddress) : startAddress(_startAddress) {};\n\n\t\tuint32 startAddress{};\n\t\tuint32 length{};\n\t\t//bool isProcessed{false};\n\n\t\tuint32 getEndAddress() const { return startAddress + length; };\n\t};\n\npublic:\n\t~PPCFunctionBoundaryTracker()\n\t{\n\t\twhile (!map_ranges.empty())\n\t\t{\n\t\t\tPPCRange_t* range = *map_ranges.begin();\n\t\t\tdelete range;\n\t\t\tmap_ranges.erase(map_ranges.begin());\n\t\t}\n\t}\n\n\tvoid trackStartPoint(MPTR startAddress)\n\t{\n\t\tprocessRange(startAddress, nullptr, nullptr);\n\t\tprocessBranchTargets();\n\t}\n\n\tbool getRangeForAddress(uint32 address, PPCRange_t& range)\n\t{\n\t\tfor (auto itr : map_ranges)\n\t\t{\n\t\t\tif (address >= itr->startAddress && address < (itr->startAddress + itr->length))\n\t\t\t{\n\t\t\t\trange = *itr;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tstd::vector<PPCRange_t> GetRanges()\n\t{\n\t\tstd::vector<PPCRange_t> r;\n\t\tfor (auto& it : map_ranges)\n\t\t\tr.emplace_back(*it);\n\t\treturn r;\n\t}\n\n\tbool ContainsAddress(uint32 addr) const\n\t{\n\t\tfor (auto& it : map_ranges)\n\t\t{\n\t\t\tif (addr >= it->startAddress && addr < it->getEndAddress())\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tconst std::set<uint32>& GetBranchTargets() const\n\t{\n\t\treturn map_branchTargetsAll;\n\t}\n\nprivate:\n\tvoid addBranchDestination(PPCRange_t* sourceRange, MPTR address)\n\t{\n\t\tmap_queuedBranchTargets.emplace(address);\n\t\tmap_branchTargetsAll.emplace(address);\n\t}\n\n\t// process flow of instruction\n\t// returns false if the IP cannot increment past the current instruction\n\tbool processInstruction(PPCRange_t* range, MPTR address)\n\t{\n\t\t// parse instructions\n\t\tuint32 opcode = memory_readU32(address);\n\t\tswitch (Espresso::GetPrimaryOpcode(opcode))\n\t\t{\n\t\tcase Espresso::PrimaryOpcode::ZERO:\n\t\t{\n\t\t\tif (opcode == 0)\n\t\t\t\treturn false; // invalid instruction\n\t\t\tbreak;\n\t\t}\n\t\tcase Espresso::PrimaryOpcode::VIRTUAL_HLE:\n\t\t{\n\t\t\t// end of function\n\t\t\t// is there a jump to a instruction after this one?\n\t\t\tuint32 hleFuncId = opcode & 0xFFFF;\n\t\t\tif (hleFuncId >= 0x1000 && hleFuncId < 0x4000)\n\t\t\t{\n\t\t\t\tif (GamePatch_IsNonReturnFunction(hleFuncId - 0x1000) == false)\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\tcase Espresso::PrimaryOpcode::BC:\n\t\t{\n\t\t\tuint32 BD, BI;\n\t\t\tEspresso::BOField BO;\n\t\t\tbool AA, LK;\n\t\t\tEspresso::decodeOp_BC(opcode, BD, BO, BI, AA, LK);\n\t\t\tuint32 branchTarget = AA ? BD : BD + address;\n\t\t\tif (!LK)\n\t\t\t\taddBranchDestination(range, branchTarget);\n\t\t\tbreak;\n\t\t}\n\t\tcase Espresso::PrimaryOpcode::B:\t\n\t\t{\n\t\t\tuint32 LI;\n\t\t\tbool AA, LK;\n\t\t\tEspresso::decodeOp_B(opcode, LI, AA, LK);\n\t\t\tuint32 branchTarget = AA ? LI : LI + address;\n\t\t\tif (!LK)\n\t\t\t{\n\t\t\t\taddBranchDestination(range, branchTarget);\n\t\t\t\t// if the next two or previous two instructions are branch instructions, we assume that they are destinations of a jump table\n\t\t\t\t// todo - can we make this more reliable by checking for BCTR or similar instructions first?\n\t\t\t\t// example: The Swapper 0x01B1FC04\n\t\t\t\tif (PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(memory_readU32(address + 4)) && PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(memory_readU32(address + 8)) ||\n\t\t\t\t\tPPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(memory_readU32(address - 8)) && PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(memory_readU32(address - 4)))\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false; // current flow ends at unconditional branch instruction\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase Espresso::PrimaryOpcode::GROUP_19:\n\t\t\tswitch (Espresso::GetGroup19Opcode(opcode))\n\t\t\t{\n\t\t\tcase Espresso::Opcode19::BCLR:\n\t\t\t{\n\t\t\t\tEspresso::BOField BO;\n\t\t\t\tuint32 BI;\n\t\t\t\tbool LK;\n\t\t\t\tEspresso::decodeOp_BCSPR(opcode, BO, BI, LK);\n\t\t\t\tif (BO.branchAlways() && !LK)\n\t\t\t\t{\n\t\t\t\t\t// unconditional BLR\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Espresso::Opcode19::BCCTR:\n\t\t\t\tif (opcode == 0x4E800420)\n\t\t\t\t{\n\t\t\t\t\t// unconditional BCTR\n\t\t\t\t\t// this instruction is often used for switch statements, therefore we should be wary of ending the function here\n\t\t\t\t\t// It's better to overestimate function size than to predict sizes that are too short\n\n\t\t\t\t\t// Currently we only end the function if the BCTR is followed by a NOP (alignment) or invalid instruction\n\t\t\t\t\t// todo: improve robustness, find better ways to handle false positives\n\t\t\t\t\tuint32 nextOpcode = memory_readU32(address + 4);\n\n\t\t\t\t\tif (nextOpcode == 0x60000000 || PPCRecompilerCalcFuncSize_isValidInstruction(nextOpcode) == false)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t// conditional BCTR\n\t\t\t\treturn true;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid checkForCollisions()\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tuint32 endOfPrevious = 0;\n\t\tfor (auto itr : map_ranges)\n\t\t{\n\t\t\tif (endOfPrevious > itr->startAddress)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t\tendOfPrevious = itr->startAddress + itr->length;\n\t\t}\n#endif\n\t}\n\n\t// nextRange must point to the closest range after startAddress, or NULL if there is none\n\tvoid processRange(MPTR startAddress, PPCRange_t* previousRange, PPCRange_t* nextRange)\n\t{\n\t\tcheckForCollisions();\n\t\tcemu_assert_debug(previousRange == nullptr || (startAddress == (previousRange->startAddress + previousRange->length)));\n\t\tPPCRange_t* newRange;\n\t\tif (previousRange && (previousRange->startAddress + previousRange->length) == startAddress)\n\t\t{\n\t\t\tnewRange = previousRange;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(previousRange == nullptr);\n\t\t\tnewRange = new PPCRange_t(startAddress);\n\t\t\tmap_ranges.emplace(newRange);\n\t\t}\n\t\t// process instruction flow until it is interrupted by a non-conditional branch\n\t\tMPTR currentAddress = startAddress;\n\t\tMPTR endAddress = 0xFFFFFFFF;\n\t\tif (nextRange)\n\t\t\tendAddress = nextRange->startAddress;\n\t\twhile (currentAddress < endAddress)\n\t\t{\n\t\t\tif (!processInstruction(newRange, currentAddress))\n\t\t\t{\n\t\t\t\tcurrentAddress += 4;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcurrentAddress += 4;\n\t\t}\n\t\tnewRange->length = currentAddress - newRange->startAddress;\n\n\t\tif (nextRange && currentAddress >= nextRange->startAddress)\n\t\t{\n\t\t\t// merge with next range\n\t\t\tnewRange->length = (nextRange->startAddress + nextRange->length) - newRange->startAddress;\n\t\t\tmap_ranges.erase(nextRange);\n\t\t\tdelete nextRange;\n\t\t\tcheckForCollisions();\n\t\t\treturn;\n\t\t}\n\t\tcheckForCollisions();\n\t}\n\n\t// find first unvisited branch target and start a new range there\n\t// return true if method should be called again\n\tbool processBranchTargetsSinglePass()\n\t{\n\t\tcemu_assert_debug(!map_ranges.empty());\n\t\tauto rangeItr = map_ranges.begin();\n\n\t\tPPCRange_t* previousRange = nullptr;\n\t\tfor (std::set<uint32_t>::const_iterator targetItr = map_queuedBranchTargets.begin() ; targetItr != map_queuedBranchTargets.end(); )\n\t\t{\n\t\t\twhile (rangeItr != map_ranges.end() && ((*rangeItr)->startAddress + (*rangeItr)->length) <= (*targetItr))\n\t\t\t{\n\t\t\t\tpreviousRange = *rangeItr;\n\t\t\t\trangeItr++;\n\t\t\t\tif (rangeItr == map_ranges.end())\n\t\t\t\t{\n\t\t\t\t\t// last range reached\n\t\t\t\t\tif ((previousRange->startAddress + previousRange->length) == *targetItr)\n\t\t\t\t\t\tprocessRange(*targetItr, previousRange, nullptr);\n\t\t\t\t\telse\n\t\t\t\t\t\tprocessRange(*targetItr, nullptr, nullptr);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ((*targetItr) >= (*rangeItr)->startAddress &&\n\t\t\t\t(*targetItr) < ((*rangeItr)->startAddress + (*rangeItr)->length))\n\t\t\t{\n\t\t\t\t// delete visited targets\n\t\t\t\ttargetItr = map_queuedBranchTargets.erase(targetItr);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcemu_assert_debug((*rangeItr)->startAddress > (*targetItr));\n\t\t\tif (previousRange && (previousRange->startAddress + previousRange->length) == *targetItr)\n\t\t\t\tprocessRange(*targetItr, previousRange, *rangeItr); // extend previousRange\n\t\t\telse\n\t\t\t\tprocessRange(*targetItr, nullptr, *rangeItr);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tvoid processBranchTargets()\n\t{\n\t\twhile (processBranchTargetsSinglePass());\n\t}\n\n\tprivate:\n\tbool PPCRecompilerCalcFuncSize_isUnconditionalBranchInstruction(uint32 opcode)\n\t{\n\t\tif (Espresso::GetPrimaryOpcode(opcode) == Espresso::PrimaryOpcode::B)\n\t\t{\n\t\t\tuint32 LI;\n\t\t\tbool AA, LK;\n\t\t\tEspresso::decodeOp_B(opcode, LI, AA, LK);\n\t\t\tif (!LK)\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool PPCRecompilerCalcFuncSize_isValidInstruction(uint32 opcode)\n\t{\n\t\tif ((opcode >> 26) == 0)\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\nprivate:\n\tstruct RangePtrCmp\n\t{\n\t\tbool operator()(const PPCRange_t* lhs, const PPCRange_t* rhs) const\n\t\t{\n\t\t\treturn lhs->startAddress < rhs->startAddress;\n\t\t}\n\t};\n\n\tstd::set<PPCRange_t*, RangePtrCmp> map_ranges;\n\tstd::set<uint32> map_queuedBranchTargets;\n\tstd::set<uint32> map_branchTargetsAll;\n};"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp",
    "content": "#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"PPCFunctionBoundaryTracker.h\"\n#include \"PPCRecompiler.h\"\n#include \"PPCRecompilerIml.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"util/containers/RangeStore.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_CodeGen.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/LaunchSettings.h\"\n#include \"Common/ExceptionHandler/ExceptionHandler.h\"\n#include \"Common/cpu_features.h\"\n#include \"util/helpers/fspinlock.h\"\n#include \"util/helpers/helpers.h\"\n#include \"util/MemMapper/MemMapper.h\"\n\n#include \"IML/IML.h\"\n#include \"IML/IMLRegisterAllocator.h\"\n#include \"BackendX64/BackendX64.h\"\n#ifdef __aarch64__\n#include \"BackendAArch64/BackendAArch64.h\"\n#endif\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n\n#define PPCREC_FORCE_SYNCHRONOUS_COMPILATION\t0 // if 1, then function recompilation will block and execute on the thread that called PPCRecompiler_visitAddressNoBlock\n#define PPCREC_LOG_RECOMPILATION_RESULTS\t\t0\n\nstruct PPCInvalidationRange\n{\n\tMPTR startAddress;\n\tuint32 size;\n\n\tPPCInvalidationRange(MPTR _startAddress, uint32 _size) : startAddress(_startAddress), size(_size) {};\n};\n\nstruct\n{\n\tFSpinlock recompilerSpinlock;\n\tstd::queue<MPTR> targetQueue;\n\tstd::vector<PPCInvalidationRange> invalidationRanges;\n}PPCRecompilerState;\n\nRangeStore<PPCRecFunction_t*, uint32, 7703, 0x2000> rangeStore_ppcRanges;\n\nvoid ATTR_MS_ABI (*PPCRecompiler_enterRecompilerCode)(uint64 codeMem, uint64 ppcInterpreterInstance);\nvoid ATTR_MS_ABI (*PPCRecompiler_leaveRecompilerCode_visited)();\nvoid ATTR_MS_ABI (*PPCRecompiler_leaveRecompilerCode_unvisited)();\n\nPPCRecompilerInstanceData_t* ppcRecompilerInstanceData;\n\n#if PPCREC_FORCE_SYNCHRONOUS_COMPILATION\nstatic std::mutex s_singleRecompilationMutex;\n#endif\n\nbool ppcRecompilerEnabled = false;\n\nvoid PPCRecompiler_recompileAtAddress(uint32 address);\n\n// this function does never block and can fail if the recompiler lock cannot be acquired immediately\nvoid PPCRecompiler_visitAddressNoBlock(uint32 enterAddress)\n{\n#if PPCREC_FORCE_SYNCHRONOUS_COMPILATION\n\tif (ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4] != PPCRecompiler_leaveRecompilerCode_unvisited)\n\t\treturn;\n\tPPCRecompilerState.recompilerSpinlock.lock();\n\tif (ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4] != PPCRecompiler_leaveRecompilerCode_unvisited)\n\t{\n\t\tPPCRecompilerState.recompilerSpinlock.unlock();\n\t\treturn;\n\t}\n\tppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4] = PPCRecompiler_leaveRecompilerCode_visited;\n\tPPCRecompilerState.recompilerSpinlock.unlock();\n\ts_singleRecompilationMutex.lock();\n\tif (ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4] == PPCRecompiler_leaveRecompilerCode_visited)\n\t{\n\t\tPPCRecompiler_recompileAtAddress(enterAddress);\n\t}\n\ts_singleRecompilationMutex.unlock();\n\treturn;\n#endif\n\t// quick read-only check without lock\n\tif (ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4] != PPCRecompiler_leaveRecompilerCode_unvisited)\n\t\treturn;\n\t// try to acquire lock\n\tif (!PPCRecompilerState.recompilerSpinlock.try_lock())\n\t\treturn;\n\tauto funcPtr = ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4];\n\tif (funcPtr != PPCRecompiler_leaveRecompilerCode_unvisited)\n\t{\n\t\t// was visited since previous check\n\t\tPPCRecompilerState.recompilerSpinlock.unlock();\n\t\treturn;\n\t}\n\t// add to recompilation queue and flag as visited\n\tPPCRecompilerState.targetQueue.emplace(enterAddress);\n\tppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4] = PPCRecompiler_leaveRecompilerCode_visited;\n\n\tPPCRecompilerState.recompilerSpinlock.unlock();\n}\n\nvoid PPCRecompiler_recompileIfUnvisited(uint32 enterAddress)\n{\n\tif (ppcRecompilerEnabled == false)\n\t\treturn;\n\tPPCRecompiler_visitAddressNoBlock(enterAddress);\n}\n\nvoid PPCRecompiler_enter(PPCInterpreter_t* hCPU, PPCREC_JUMP_ENTRY funcPtr)\n{\n#if BOOST_OS_WINDOWS\n\tuint32 prevState = _controlfp(0, 0);\n\t_controlfp(_RC_NEAR, _MCW_RC);\n\tPPCRecompiler_enterRecompilerCode((uint64)funcPtr, (uint64)hCPU);\n\t_controlfp(prevState, _MCW_RC);\n\t// debug recompiler exit - useful to find frequently executed functions which couldn't be recompiled\n\t#ifdef CEMU_DEBUG_ASSERT\n\tif (hCPU->remainingCycles > 0 && GetAsyncKeyState(VK_F4))\n\t{\n\t\tauto t = std::chrono::high_resolution_clock::now();\n\t\tauto dur = std::chrono::duration_cast<std::chrono::microseconds>(t.time_since_epoch()).count();\n\t\tcemuLog_log(LogType::Force, \"Recompiler exit: 0x{:08x} LR: 0x{:08x} Timestamp {}.{:04}\", hCPU->instructionPointer, hCPU->spr.LR, dur / 1000LL, (dur % 1000LL));\n\t}\n\t#endif\n#else\n\tPPCRecompiler_enterRecompilerCode((uint64)funcPtr, (uint64)hCPU);\n#endif\n\t// after leaving recompiler prematurely attempt to recompile the code at the new location\n\tif (hCPU->remainingCycles > 0)\n\t{\n\t\tPPCRecompiler_visitAddressNoBlock(hCPU->instructionPointer);\n\t}\n}\n\nvoid PPCRecompiler_attemptEnterWithoutRecompile(PPCInterpreter_t* hCPU, uint32 enterAddress)\n{\n\tcemu_assert_debug(hCPU->instructionPointer == enterAddress);\n\tif (ppcRecompilerEnabled == false)\n\t\treturn;\n\tauto funcPtr = ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4];\n\tif (funcPtr != PPCRecompiler_leaveRecompilerCode_unvisited && funcPtr != PPCRecompiler_leaveRecompilerCode_visited)\n\t{\n\t\tcemu_assert_debug(ppcRecompilerInstanceData != nullptr);\n\t\tPPCRecompiler_enter(hCPU, funcPtr);\n\t}\n}\n\nvoid PPCRecompiler_attemptEnter(PPCInterpreter_t* hCPU, uint32 enterAddress)\n{\n\tcemu_assert_debug(hCPU->instructionPointer == enterAddress);\n\tif (ppcRecompilerEnabled == false)\n\t\treturn;\n\tif (hCPU->remainingCycles <= 0)\n\t\treturn;\n\tauto funcPtr = ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4];\n\tif (funcPtr == PPCRecompiler_leaveRecompilerCode_unvisited)\n\t{\n\t\tPPCRecompiler_visitAddressNoBlock(enterAddress);\n\t}\n\telse if (funcPtr != PPCRecompiler_leaveRecompilerCode_visited)\n\t{\n\t\t// enter\n\t\tcemu_assert_debug(ppcRecompilerInstanceData != nullptr);\n\t\tPPCRecompiler_enter(hCPU, funcPtr);\n\t}\n}\nbool PPCRecompiler_ApplyIMLPasses(ppcImlGenContext_t& ppcImlGenContext);\n\nPPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PPCRange_t range, std::set<uint32>& entryAddresses, std::vector<std::pair<MPTR, uint32>>& entryPointsOut, PPCFunctionBoundaryTracker& boundaryTracker)\n{\n\tif (range.startAddress >= PPC_REC_CODE_AREA_END)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Attempting to recompile function outside of allowed code area\");\n\t\treturn nullptr;\n\t}\n\tuint32 codeGenRangeStart;\n\tuint32 codeGenRangeSize = 0;\n\tcoreinit::OSGetCodegenVirtAddrRangeInternal(codeGenRangeStart, codeGenRangeSize);\n\tif (codeGenRangeSize != 0)\n\t{\n\t\tif (range.startAddress >= codeGenRangeStart && range.startAddress < (codeGenRangeStart + codeGenRangeSize))\n\t\t{\n\t\t\tif (coreinit::codeGenShouldAvoid())\n\t\t\t{\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t}\n\t}\n\n\tPPCRecFunction_t* ppcRecFunc = new PPCRecFunction_t();\n\tppcRecFunc->ppcAddress = range.startAddress;\n\tppcRecFunc->ppcSize = range.length;\n\n#if PPCREC_LOG_RECOMPILATION_RESULTS\n\tBenchmarkTimer bt;\n\tbt.Start();\n#endif\n\n\t// generate intermediate code\n\tppcImlGenContext_t ppcImlGenContext = { 0 };\n\tppcImlGenContext.debug_entryPPCAddress = range.startAddress;\n\tbool compiledSuccessfully = PPCRecompiler_generateIntermediateCode(ppcImlGenContext, ppcRecFunc, entryAddresses, boundaryTracker);\n\tif (compiledSuccessfully == false)\n\t{\n\t\tdelete ppcRecFunc;\n\t\treturn nullptr;\n\t}\n\n\tuint32 ppcRecLowerAddr = LaunchSettings::GetPPCRecLowerAddr();\n\tuint32 ppcRecUpperAddr = LaunchSettings::GetPPCRecUpperAddr();\n\n\tif (ppcRecLowerAddr != 0 && ppcRecUpperAddr != 0)\n\t{\n\t\tif (ppcRecFunc->ppcAddress < ppcRecLowerAddr || ppcRecFunc->ppcAddress > ppcRecUpperAddr)\n\t\t{\n\t\t\tdelete ppcRecFunc;\n\t\t\treturn nullptr;\n\t\t}\n\t}\n\n\t// apply passes\n\tif (!PPCRecompiler_ApplyIMLPasses(ppcImlGenContext))\n\t{\n\t\tdelete ppcRecFunc;\n\t\treturn nullptr;\n\t}\n\n#if defined(ARCH_X86_64)\n\t// emit x64 code\n\tbool x64GenerationSuccess = PPCRecompiler_generateX64Code(ppcRecFunc, &ppcImlGenContext);\n\tif (x64GenerationSuccess == false)\n\t{\n\t\treturn nullptr;\n\t}\n#elif defined(__aarch64__)\n\tbool aarch64GenerationSuccess = PPCRecompiler_generateAArch64Code(ppcRecFunc, &ppcImlGenContext);\n\tif (aarch64GenerationSuccess == false)\n\t{\n\t\treturn nullptr;\n\t}\n#endif\n\tif (ActiveSettings::DumpRecompilerFunctionsEnabled())\n\t{\n\t\tFileStream* fs = FileStream::createFile2(ActiveSettings::GetUserDataPath(fmt::format(\"dump/recompiler/ppc_{:08x}.bin\", ppcRecFunc->ppcAddress)));\n\t\tif (fs)\n\t\t{\n\t\t\tfs->writeData(ppcRecFunc->x86Code, ppcRecFunc->x86Size);\n\t\t\tdelete fs;\n\t\t}\n\t}\n\n\t// collect list of PPC-->x64 entry points\n\tentryPointsOut.clear();\n\tfor(IMLSegment* imlSegment : ppcImlGenContext.segmentList2)\n\t{\n\t\tif (imlSegment->isEnterable == false)\n\t\t\tcontinue;\n\n\t\tuint32 ppcEnterOffset = imlSegment->enterPPCAddress;\n\t\tuint32 x64Offset = imlSegment->x64Offset;\n\n\t\tentryPointsOut.emplace_back(ppcEnterOffset, x64Offset);\n\t}\n\n#if PPCREC_LOG_RECOMPILATION_RESULTS\n\tbt.Stop();\n\tuint32 codeHash = 0;\n\tfor (uint32 i = 0; i < ppcRecFunc->x86Size; i++)\n\t{\n\t\tcodeHash = _rotr(codeHash, 3);\n\t\tcodeHash += ((uint8*)ppcRecFunc->x86Code)[i];\n\t}\n\tcemuLog_log(LogType::Force, \"[Recompiler] PPC 0x{:08x} -> x64: 0x{:x} Took {:.4}ms | Size {:04x} CodeHash {:08x}\", (uint32)ppcRecFunc->ppcAddress, (uint64)(uintptr_t)ppcRecFunc->x86Code, bt.GetElapsedMilliseconds(), ppcRecFunc->x86Size, codeHash);\n#endif\n\n\treturn ppcRecFunc;\n}\n\nvoid PPCRecompiler_NativeRegisterAllocatorPass(ppcImlGenContext_t& ppcImlGenContext)\n{\n\tIMLRegisterAllocatorParameters raParam;\n\n\tfor (auto& it : ppcImlGenContext.mappedRegs)\n\t\traParam.regIdToName.try_emplace(it.second.GetRegID(), it.first);\n\n#if defined(ARCH_X86_64)\n\tauto& gprPhysPool = raParam.GetPhysRegPool(IMLRegFormat::I64);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RAX);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RDX);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RBX);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RBP);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RSI);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RDI);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_R8);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_R9);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_R10);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_R11);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_R12);\n\tgprPhysPool.SetAvailable(IMLArchX86::PHYSREG_GPR_BASE + X86_REG_RCX);\n\n\t// add XMM registers, except XMM15 which is the temporary register\n\tauto& fprPhysPool = raParam.GetPhysRegPool(IMLRegFormat::F64);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 0);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 1);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 2);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 3);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 4);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 5);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 6);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 7);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 8);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 9);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 10);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 11);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 12);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 13);\n\tfprPhysPool.SetAvailable(IMLArchX86::PHYSREG_FPR_BASE + 14);\n#elif defined(__aarch64__)\n\tauto& gprPhysPool = raParam.GetPhysRegPool(IMLRegFormat::I64);\n\tfor (auto i = IMLArchAArch64::PHYSREG_GPR_BASE; i < IMLArchAArch64::PHYSREG_GPR_BASE + IMLArchAArch64::PHYSREG_GPR_COUNT; i++)\n\t{\n\t\tif (i == IMLArchAArch64::PHYSREG_GPR_BASE + 18)\n\t\t\tcontinue; // Skip reserved platform register\n\t\tgprPhysPool.SetAvailable(i);\n\t}\n\n\tauto& fprPhysPool = raParam.GetPhysRegPool(IMLRegFormat::F64);\n\tfor (auto i = IMLArchAArch64::PHYSREG_FPR_BASE; i < IMLArchAArch64::PHYSREG_FPR_BASE + IMLArchAArch64::PHYSREG_FPR_COUNT; i++)\n\t\tfprPhysPool.SetAvailable(i);\n#endif\n\n\tIMLRegisterAllocator_AllocateRegisters(&ppcImlGenContext, raParam);\n}\n\nbool PPCRecompiler_ApplyIMLPasses(ppcImlGenContext_t& ppcImlGenContext)\n{\n\t// isolate entry points from function flow (enterable segments must not be the target of any other segment)\n\t// this simplifies logic during register allocation\n\tPPCRecompilerIML_isolateEnterableSegments(&ppcImlGenContext);\n\n\t// merge certain float load+store patterns\n\tIMLOptimizer_OptimizeDirectFloatCopies(&ppcImlGenContext);\n\t// delay byte swapping for certain load+store patterns\n\tIMLOptimizer_OptimizeDirectIntegerCopies(&ppcImlGenContext);\n\n\tIMLOptimizer_StandardOptimizationPass(ppcImlGenContext);\n\n\tPPCRecompiler_NativeRegisterAllocatorPass(ppcImlGenContext);\n\n\treturn true;\n}\n\nbool PPCRecompiler_makeRecompiledFunctionActive(uint32 initialEntryPoint, PPCFunctionBoundaryTracker::PPCRange_t& range, PPCRecFunction_t* ppcRecFunc, std::vector<std::pair<MPTR, uint32>>& entryPoints)\n{\n\t// update jump table\n\tPPCRecompilerState.recompilerSpinlock.lock();\n\n\t// check if the initial entrypoint is still flagged for recompilation\n\t// its possible that the range has been invalidated during the time it took to translate the function\n\tif (ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[initialEntryPoint / 4] != PPCRecompiler_leaveRecompilerCode_visited)\n\t{\n\t\tPPCRecompilerState.recompilerSpinlock.unlock();\n\t\treturn false;\n\t}\n\n\t// check if the current range got invalidated during the time it took to recompile it\n\tbool isInvalidated = false;\n\tfor (auto& invRange : PPCRecompilerState.invalidationRanges)\n\t{\n\t\tMPTR rStartAddr = invRange.startAddress;\n\t\tMPTR rEndAddr = rStartAddr + invRange.size;\n\t\tfor (auto& recFuncRange : ppcRecFunc->list_ranges)\n\t\t{\n\t\t\tif (recFuncRange.ppcAddress < (rEndAddr) && (recFuncRange.ppcAddress + recFuncRange.ppcSize) >= rStartAddr)\n\t\t\t{\n\t\t\t\tisInvalidated = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tPPCRecompilerState.invalidationRanges.clear();\n\tif (isInvalidated)\n\t{\n\t\tPPCRecompilerState.recompilerSpinlock.unlock();\n\t\treturn false;\n\t}\n\n\n\t// update jump table\n\tfor (auto& itr : entryPoints)\n\t{\n\t\tppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[itr.first / 4] = (PPCREC_JUMP_ENTRY)((uint8*)ppcRecFunc->x86Code + itr.second);\n\t}\n\n\n\t// due to inlining, some entrypoints can get optimized away\n\t// therefore we reset all addresses that are still marked as visited (but not recompiled)\n\t// we dont remove the points from the queue but any address thats not marked as visited won't get recompiled\n\t// if they are reachable, the interpreter will queue them again\n\tfor (uint32 v = range.startAddress; v <= (range.startAddress + range.length); v += 4)\n\t{\n\t\tauto funcPtr = ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[v / 4];\n\t\tif (funcPtr == PPCRecompiler_leaveRecompilerCode_visited)\n\t\t\tppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[v / 4] = PPCRecompiler_leaveRecompilerCode_unvisited;\n\t}\n\n\t// register ranges\n\tfor (auto& r : ppcRecFunc->list_ranges)\n\t{\n\t\tr.storedRange = rangeStore_ppcRanges.storeRange(ppcRecFunc, r.ppcAddress, r.ppcAddress + r.ppcSize);\n\t}\n\tPPCRecompilerState.recompilerSpinlock.unlock();\n\n\n\treturn true;\n}\n\nvoid PPCRecompiler_recompileAtAddress(uint32 address)\n{\n\tcemu_assert_debug(ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[address / 4] == PPCRecompiler_leaveRecompilerCode_visited);\n\n\t// get size\n\tPPCFunctionBoundaryTracker funcBoundaries;\n\tfuncBoundaries.trackStartPoint(address);\n\t// get range that encompasses address\n\tPPCFunctionBoundaryTracker::PPCRange_t range;\n\tif (funcBoundaries.getRangeForAddress(address, range) == false)\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n\n\t// todo - use info from previously compiled ranges to determine full size of this function (and merge all the entryAddresses)\n\n\t// collect all currently known entry points for this range\n\tPPCRecompilerState.recompilerSpinlock.lock();\n\n\tstd::set<uint32> entryAddresses;\n\n\tentryAddresses.emplace(address);\n\n\tPPCRecompilerState.recompilerSpinlock.unlock();\n\n\tstd::vector<std::pair<MPTR, uint32>> functionEntryPoints;\n\tauto func = PPCRecompiler_recompileFunction(range, entryAddresses, functionEntryPoints, funcBoundaries);\n\n\tif (!func)\n\t{\n\t\treturn; // recompilation failed\n\t}\n\tbool r = PPCRecompiler_makeRecompiledFunctionActive(address, range, func, functionEntryPoints);\n}\n\nstd::thread s_threadRecompiler;\nstd::atomic_bool s_recompilerThreadStopSignal{false};\n\nvoid PPCRecompiler_thread()\n{\n\tSetThreadName(\"PPCRecompiler\");\n#if PPCREC_FORCE_SYNCHRONOUS_COMPILATION\n\treturn;\n#endif\n\n\twhile (true)\n\t{\n        if(s_recompilerThreadStopSignal)\n            return;\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t// asynchronous recompilation:\n\t\t// 1) take address from queue\n\t\t// 2) check if address is still marked as visited\n\t\t// 3) if yes -> calculate size, gather all entry points, recompile and update jump table\n\t\twhile (true)\n\t\t{\n\t\t\tPPCRecompilerState.recompilerSpinlock.lock();\n\t\t\tif (PPCRecompilerState.targetQueue.empty())\n\t\t\t{\n\t\t\t\tPPCRecompilerState.recompilerSpinlock.unlock();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tauto enterAddress = PPCRecompilerState.targetQueue.front();\n\t\t\tPPCRecompilerState.targetQueue.pop();\n\n\t\t\tauto funcPtr = ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4];\n\t\t\tif (funcPtr != PPCRecompiler_leaveRecompilerCode_visited)\n\t\t\t{\n\t\t\t\t// only recompile functions if marked as visited\n\t\t\t\tPPCRecompilerState.recompilerSpinlock.unlock();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tPPCRecompilerState.recompilerSpinlock.unlock();\n\n\t\t\tPPCRecompiler_recompileAtAddress(enterAddress);\n\t\t\tif(s_recompilerThreadStopSignal)\n\t\t\t\treturn;\n\t\t}\n\t}\n}\n\n#define PPC_REC_ALLOC_BLOCK_SIZE\t(4*1024*1024) // 4MB\n\nconstexpr uint32 PPCRecompiler_GetNumAddressSpaceBlocks()\n{\n    return (MEMORY_CODEAREA_ADDR + MEMORY_CODEAREA_SIZE + PPC_REC_ALLOC_BLOCK_SIZE - 1) / PPC_REC_ALLOC_BLOCK_SIZE;\n}\n\nstd::bitset<PPCRecompiler_GetNumAddressSpaceBlocks()> ppcRecompiler_reservedBlockMask;\n\nvoid PPCRecompiler_reserveLookupTableBlock(uint32 offset)\n{\n\tuint32 blockIndex = offset / PPC_REC_ALLOC_BLOCK_SIZE;\n\toffset = blockIndex * PPC_REC_ALLOC_BLOCK_SIZE;\n\n\tif (ppcRecompiler_reservedBlockMask[blockIndex])\n\t\treturn;\n\tppcRecompiler_reservedBlockMask[blockIndex] = true;\n\n\tvoid* p1 = MemMapper::AllocateMemory(&(ppcRecompilerInstanceData->ppcRecompilerFuncTable[offset/4]), (PPC_REC_ALLOC_BLOCK_SIZE/4)*sizeof(void*), MemMapper::PAGE_PERMISSION::P_RW, true);\n\tvoid* p3 = MemMapper::AllocateMemory(&(ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[offset/4]), (PPC_REC_ALLOC_BLOCK_SIZE/4)*sizeof(void*), MemMapper::PAGE_PERMISSION::P_RW, true);\n\tif( !p1 || !p3 )\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to allocate memory for recompiler (0x{:08x})\", offset);\n\t\tcemu_assert(false);\n\t\treturn;\n\t}\n\tfor(uint32 i=0; i<PPC_REC_ALLOC_BLOCK_SIZE/4; i++)\n\t{\n\t\tppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[offset/4+i] = PPCRecompiler_leaveRecompilerCode_unvisited;\n\t}\n}\n\nvoid PPCRecompiler_allocateRange(uint32 startAddress, uint32 size)\n{\n\tif (ppcRecompilerInstanceData == nullptr)\n\t\treturn;\n\tuint32 endAddress = (startAddress + size + PPC_REC_ALLOC_BLOCK_SIZE - 1) & ~(PPC_REC_ALLOC_BLOCK_SIZE-1);\n\tstartAddress = (startAddress) & ~(PPC_REC_ALLOC_BLOCK_SIZE-1);\n\tstartAddress = std::min(startAddress, (uint32)MEMORY_CODEAREA_ADDR + MEMORY_CODEAREA_SIZE);\n\tendAddress = std::min(endAddress, (uint32)MEMORY_CODEAREA_ADDR + MEMORY_CODEAREA_SIZE);\n\tfor (uint32 i = startAddress; i < endAddress; i += PPC_REC_ALLOC_BLOCK_SIZE)\n\t{\n\t\tPPCRecompiler_reserveLookupTableBlock(i);\n\t}\n}\n\nstruct ppcRecompilerFuncRange_t\n{\n\tMPTR\tppcStart;\n\tuint32  ppcSize;\n\tvoid*   x86Start;\n\tsize_t  x86Size;\n};\n\nbool PPCRecompiler_findFuncRanges(uint32 addr, ppcRecompilerFuncRange_t* rangesOut, size_t* countInOut)\n{\n\tPPCRecompilerState.recompilerSpinlock.lock();\n\tsize_t countIn = *countInOut;\n\tsize_t countOut = 0;\n\n\trangeStore_ppcRanges.findRanges(addr, addr + 4, [rangesOut, countIn, &countOut](uint32 start, uint32 end, PPCRecFunction_t* func)\n\t{\n\t\tif (countOut < countIn)\n\t\t{\n\t\t\trangesOut[countOut].ppcStart = start;\n\t\t\trangesOut[countOut].ppcSize = (end-start);\n\t\t\trangesOut[countOut].x86Start = func->x86Code;\n\t\t\trangesOut[countOut].x86Size = func->x86Size;\n\t\t}\n\t\tcountOut++;\n\t}\n\t);\n\tPPCRecompilerState.recompilerSpinlock.unlock();\n\t*countInOut = countOut;\n\tif (countOut > countIn)\n\t\treturn false;\n\treturn true;\n}\n\nextern \"C\" DLLEXPORT uintptr_t * PPCRecompiler_getJumpTableBase()\n{\n\tif (ppcRecompilerInstanceData == nullptr)\n\t\treturn nullptr;\n\treturn (uintptr_t*)ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable;\n}\n\nvoid PPCRecompiler_invalidateTableRange(uint32 offset, uint32 size)\n{\n\tif (ppcRecompilerInstanceData == nullptr)\n\t\treturn;\n\tfor (uint32 i = 0; i < size / 4; i++)\n\t{\n\t\tppcRecompilerInstanceData->ppcRecompilerFuncTable[offset / 4 + i] = nullptr;\n\t\tppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[offset / 4 + i] = PPCRecompiler_leaveRecompilerCode_unvisited;\n\t}\n}\n\nvoid PPCRecompiler_deleteFunction(PPCRecFunction_t* func)\n{\n\t// assumes PPCRecompilerState.recompilerSpinlock is already held\n\tcemu_assert_debug(PPCRecompilerState.recompilerSpinlock.is_locked());\n\tfor (auto& r : func->list_ranges)\n\t{\n\t\tPPCRecompiler_invalidateTableRange(r.ppcAddress, r.ppcSize);\n\t\tif(r.storedRange)\n\t\t\trangeStore_ppcRanges.deleteRange(r.storedRange);\n\t\tr.storedRange = nullptr;\n\t}\n\t// todo - free x86 code\n}\n\nvoid PPCRecompiler_invalidateRange(uint32 startAddr, uint32 endAddr)\n{\n\tif (ppcRecompilerEnabled == false)\n\t\treturn;\n\tif (startAddr >= PPC_REC_CODE_AREA_SIZE)\n\t\treturn;\n\tcemu_assert_debug(endAddr >= startAddr);\n\n\tPPCRecompilerState.recompilerSpinlock.lock();\n\n\tuint32 rStart;\n\tuint32 rEnd;\n\tPPCRecFunction_t* rFunc;\n\n\t// mark range as unvisited\n\tfor (uint64 currentAddr = (uint64)startAddr&~3; currentAddr < (uint64)(endAddr&~3); currentAddr += 4)\n\t\tppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[currentAddr / 4] = PPCRecompiler_leaveRecompilerCode_unvisited;\n\n\t// add entry to invalidation queue\n\tPPCRecompilerState.invalidationRanges.emplace_back(startAddr, endAddr-startAddr);\n\n\n\twhile (rangeStore_ppcRanges.findFirstRange(startAddr, endAddr, rStart, rEnd, rFunc) )\n\t{\n\t\tPPCRecompiler_deleteFunction(rFunc);\n\t}\n\n\tPPCRecompilerState.recompilerSpinlock.unlock();\n}\n\n#if defined(ARCH_X86_64)\nvoid PPCRecompiler_initPlatform()\n{\n\tppcRecompilerInstanceData->_x64XMM_xorNegateMaskBottom[0] = 1ULL << 63ULL;\n\tppcRecompilerInstanceData->_x64XMM_xorNegateMaskBottom[1] = 0ULL;\n\tppcRecompilerInstanceData->_x64XMM_xorNegateMaskPair[0] = 1ULL << 63ULL;\n\tppcRecompilerInstanceData->_x64XMM_xorNegateMaskPair[1] = 1ULL << 63ULL;\n\tppcRecompilerInstanceData->_x64XMM_xorNOTMask[0] = 0xFFFFFFFFFFFFFFFFULL;\n\tppcRecompilerInstanceData->_x64XMM_xorNOTMask[1] = 0xFFFFFFFFFFFFFFFFULL;\n\tppcRecompilerInstanceData->_x64XMM_andAbsMaskBottom[0] = ~(1ULL << 63ULL);\n\tppcRecompilerInstanceData->_x64XMM_andAbsMaskBottom[1] = ~0ULL;\n\tppcRecompilerInstanceData->_x64XMM_andAbsMaskPair[0] = ~(1ULL << 63ULL);\n\tppcRecompilerInstanceData->_x64XMM_andAbsMaskPair[1] = ~(1ULL << 63ULL);\n\tppcRecompilerInstanceData->_x64XMM_andFloatAbsMaskBottom[0] = ~(1 << 31);\n\tppcRecompilerInstanceData->_x64XMM_andFloatAbsMaskBottom[1] = 0xFFFFFFFF;\n\tppcRecompilerInstanceData->_x64XMM_andFloatAbsMaskBottom[2] = 0xFFFFFFFF;\n\tppcRecompilerInstanceData->_x64XMM_andFloatAbsMaskBottom[3] = 0xFFFFFFFF;\n\tppcRecompilerInstanceData->_x64XMM_singleWordMask[0] = 0xFFFFFFFFULL;\n\tppcRecompilerInstanceData->_x64XMM_singleWordMask[1] = 0ULL;\n\tppcRecompilerInstanceData->_x64XMM_constDouble1_1[0] = 1.0;\n\tppcRecompilerInstanceData->_x64XMM_constDouble1_1[1] = 1.0;\n\tppcRecompilerInstanceData->_x64XMM_constDouble0_0[0] = 0.0;\n\tppcRecompilerInstanceData->_x64XMM_constDouble0_0[1] = 0.0;\n\tppcRecompilerInstanceData->_x64XMM_constFloat0_0[0] = 0.0f;\n\tppcRecompilerInstanceData->_x64XMM_constFloat0_0[1] = 0.0f;\n\tppcRecompilerInstanceData->_x64XMM_constFloat1_1[0] = 1.0f;\n\tppcRecompilerInstanceData->_x64XMM_constFloat1_1[1] = 1.0f;\n\t*(uint32*)&ppcRecompilerInstanceData->_x64XMM_constFloatMin[0] = 0x00800000;\n\t*(uint32*)&ppcRecompilerInstanceData->_x64XMM_constFloatMin[1] = 0x00800000;\n\tppcRecompilerInstanceData->_x64XMM_flushDenormalMask1[0] = 0x7F800000;\n\tppcRecompilerInstanceData->_x64XMM_flushDenormalMask1[1] = 0x7F800000;\n\tppcRecompilerInstanceData->_x64XMM_flushDenormalMask1[2] = 0x7F800000;\n\tppcRecompilerInstanceData->_x64XMM_flushDenormalMask1[3] = 0x7F800000;\n\tppcRecompilerInstanceData->_x64XMM_flushDenormalMaskResetSignBits[0] = ~0x80000000;\n\tppcRecompilerInstanceData->_x64XMM_flushDenormalMaskResetSignBits[1] = ~0x80000000;\n\tppcRecompilerInstanceData->_x64XMM_flushDenormalMaskResetSignBits[2] = ~0x80000000;\n\tppcRecompilerInstanceData->_x64XMM_flushDenormalMaskResetSignBits[3] = ~0x80000000;\n\n\t// mxcsr\n\tppcRecompilerInstanceData->_x64XMM_mxCsr_ftzOn = 0x1F80 | 0x8000;\n\tppcRecompilerInstanceData->_x64XMM_mxCsr_ftzOff = 0x1F80;\n}\n#else\nvoid PPCRecompiler_initPlatform()\n{\n    \n}\n#endif\n\nvoid PPCRecompiler_init()\n{\n\tif (ActiveSettings::GetCPUMode() == CPUMode::SinglecoreInterpreter)\n\t{\n\t\tppcRecompilerEnabled = false;\n\t\treturn;\n\t}\n\tif (LaunchSettings::ForceInterpreter() || LaunchSettings::ForceMultiCoreInterpreter())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Recompiler disabled. Command line --force-interpreter or force-multicore-interpreter was passed\");\n\t\treturn;\n\t}\n\tif (ppcRecompilerInstanceData)\n\t{\n\t\tMemMapper::FreeReservation(ppcRecompilerInstanceData, sizeof(PPCRecompilerInstanceData_t));\n\t\tppcRecompilerInstanceData = nullptr;\n\t}\n\tdebug_printf(\"Allocating %dMB for recompiler instance data...\\n\", (sint32)(sizeof(PPCRecompilerInstanceData_t) / 1024 / 1024));\n\tppcRecompilerInstanceData = (PPCRecompilerInstanceData_t*)MemMapper::ReserveMemory(nullptr, sizeof(PPCRecompilerInstanceData_t), MemMapper::PAGE_PERMISSION::P_RW);\n\tMemMapper::AllocateMemory(&(ppcRecompilerInstanceData->_x64XMM_xorNegateMaskBottom), sizeof(PPCRecompilerInstanceData_t) - offsetof(PPCRecompilerInstanceData_t, _x64XMM_xorNegateMaskBottom), MemMapper::PAGE_PERMISSION::P_RW, true);\n#ifdef ARCH_X86_64\n\tPPCRecompilerX64Gen_generateRecompilerInterfaceFunctions();\n#elif defined(__aarch64__)\n\tPPCRecompilerAArch64Gen_generateRecompilerInterfaceFunctions();\n#endif\n    PPCRecompiler_allocateRange(0, 0x1000); // the first entry is used for fallback to interpreter\n    PPCRecompiler_allocateRange(mmuRange_TRAMPOLINE_AREA.getBase(), mmuRange_TRAMPOLINE_AREA.getSize());\n    PPCRecompiler_allocateRange(mmuRange_CODECAVE.getBase(), mmuRange_CODECAVE.getSize());\n\n    PPCRecompiler_initPlatform();\n    \n\tcemuLog_log(LogType::Force, \"Recompiler initialized\");\n\n\tppcRecompilerEnabled = true;\n\n\t// launch recompilation thread\n    s_recompilerThreadStopSignal = false;\n    s_threadRecompiler = std::thread(PPCRecompiler_thread);\n}\n\nvoid PPCRecompiler_Shutdown()\n{\n    // shut down recompiler thread\n    s_recompilerThreadStopSignal = true;\n    if(s_threadRecompiler.joinable())\n        s_threadRecompiler.join();\n    // clean up queues\n    while(!PPCRecompilerState.targetQueue.empty())\n        PPCRecompilerState.targetQueue.pop();\n    PPCRecompilerState.invalidationRanges.clear();\n    // clean range store\n    rangeStore_ppcRanges.clear();\n    // clean up memory\n    uint32 numBlocks = PPCRecompiler_GetNumAddressSpaceBlocks();\n    for(uint32 i=0; i<numBlocks; i++)\n    {\n        if(!ppcRecompiler_reservedBlockMask[i])\n            continue;\n        // deallocate\n        uint64 offset = i * PPC_REC_ALLOC_BLOCK_SIZE;\n        MemMapper::FreeMemory(&(ppcRecompilerInstanceData->ppcRecompilerFuncTable[offset/4]), (PPC_REC_ALLOC_BLOCK_SIZE/4)*sizeof(void*), true);\n        MemMapper::FreeMemory(&(ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[offset/4]), (PPC_REC_ALLOC_BLOCK_SIZE/4)*sizeof(void*), true);\n        // mark as unmapped\n        ppcRecompiler_reservedBlockMask[i] = false;\n    }\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.h",
    "content": "#pragma once\n\n#define PPC_REC_CODE_AREA_START\t\t(0x00000000) // lower bound of executable memory area. Recompiler expects this address to be 0\n#define PPC_REC_CODE_AREA_END\t\t(0x10000000) // upper bound of executable memory area\n#define PPC_REC_CODE_AREA_SIZE\t\t(PPC_REC_CODE_AREA_END - PPC_REC_CODE_AREA_START)\n\n#define PPC_REC_ALIGN_TO_4MB(__v)\t(((__v)+4*1024*1024-1)&~(4*1024*1024-1))\n\n#define PPC_REC_MAX_VIRTUAL_GPR\t\t(40 + 32) // enough to store 32 GPRs + a few SPRs + temp registers (usually only 1-2)\n\nstruct ppcRecRange_t\n{\n\tuint32 ppcAddress;\n\tuint32 ppcSize;\n\tvoid* storedRange;\n};\n\nstruct PPCRecFunction_t\n{\n\tuint32 ppcAddress;\n\tuint32 ppcSize; // ppc code size of function\n\tvoid*  x86Code; // pointer to x86 code\n\tsize_t x86Size;\n\tstd::vector<ppcRecRange_t> list_ranges;\n};\n\n#include \"Cafe/HW/Espresso/Recompiler/IML/IMLInstruction.h\"\n#include \"Cafe/HW/Espresso/Recompiler/IML/IMLSegment.h\"\n\nstruct IMLInstruction* PPCRecompilerImlGen_generateNewEmptyInstruction(struct ppcImlGenContext_t* ppcImlGenContext);\n\nstruct ppcImlGenContext_t\n{\n\tclass PPCFunctionBoundaryTracker* boundaryTracker;\n\tuint32* currentInstruction;\n\tuint32  ppcAddressOfCurrentInstruction;\n\tIMLSegment* currentOutputSegment;\n\tstruct PPCBasicBlockInfo* currentBasicBlock{};\n\t// fpr mode\n\tbool LSQE{ true };\n\tbool PSE{ true };\n\t// cycle counter\n\tuint32 cyclesSinceLastBranch; // used to track ppc cycles\n\tstd::unordered_map<IMLName, IMLReg> mappedRegs;\n\n\tuint32 GetMaxRegId() const\n\t{\n\t\tif (mappedRegs.empty())\n\t\t\treturn 0;\n\t\treturn mappedRegs.size()-1;\n\t}\n\n\t// list of segments\n\tstd::vector<IMLSegment*> segmentList2;\n\t// code generation control\n\tbool hasFPUInstruction; // if true, PPCEnter macro will create FP_UNAVAIL checks -> Not needed in user mode\n\t// analysis info\n\tstruct  \n\t{\n\t\tbool modifiesGQR[8];\n\t}tracking;\n\t// debug helpers\n\tuint32 debug_entryPPCAddress{0};\n\n\t~ppcImlGenContext_t()\n\t{\n\t\tfor (IMLSegment* imlSegment : segmentList2)\n\t\t\tdelete imlSegment;\n\t\tsegmentList2.clear();\n\t}\n\n\t// append raw instruction\n\tIMLInstruction& emitInst()\n\t{\n\t\treturn *PPCRecompilerImlGen_generateNewEmptyInstruction(this);\n\t}\n\n\tIMLSegment* NewSegment()\n\t{\n\t\tIMLSegment* seg = new IMLSegment();\n\t\tsegmentList2.emplace_back(seg);\n\t\treturn seg;\n\t}\n\n\tsize_t GetSegmentIndex(IMLSegment* seg)\n\t{\n\t\tfor (size_t i = 0; i < segmentList2.size(); i++)\n\t\t{\n\t\t\tif (segmentList2[i] == seg)\n\t\t\t\treturn i;\n\t\t}\n\t\tcemu_assert_error();\n\t\treturn 0;\n\t}\n\n\tIMLSegment* InsertSegment(size_t index)\n\t{\n\t\tIMLSegment* newSeg = new IMLSegment();\n\t\tsegmentList2.insert(segmentList2.begin() + index, 1, newSeg);\n\t\treturn newSeg;\n\t}\n\n\tstd::span<IMLSegment*> InsertSegments(size_t index, size_t count)\n\t{\n\t\tsegmentList2.insert(segmentList2.begin() + index, count, {});\n\t\tfor (size_t i = index; i < (index + count); i++)\n\t\t\tsegmentList2[i] = new IMLSegment();\n\t\treturn { segmentList2.data() + index, count};\n\t}\n\n\tvoid UpdateSegmentIndices()\n\t{\n\t\tfor (size_t i = 0; i < segmentList2.size(); i++)\n\t\t\tsegmentList2[i]->momentaryIndex = (sint32)i;\n\t}\n};\n\ntypedef void ATTR_MS_ABI (*PPCREC_JUMP_ENTRY)();\n\ntypedef struct  \n{\n\tPPCRecFunction_t* ppcRecompilerFuncTable[PPC_REC_ALIGN_TO_4MB(PPC_REC_CODE_AREA_SIZE/4)]; // one virtual-function pointer for each potential ppc instruction\n\tPPCREC_JUMP_ENTRY ppcRecompilerDirectJumpTable[PPC_REC_ALIGN_TO_4MB(PPC_REC_CODE_AREA_SIZE/4)]; // lookup table for ppc offset to native code function\n\t// x64 data\n\talignas(16) uint64 _x64XMM_xorNegateMaskBottom[2];\n\talignas(16) uint64 _x64XMM_xorNegateMaskPair[2];\n\talignas(16) uint64 _x64XMM_xorNOTMask[2];\n\talignas(16) uint64 _x64XMM_andAbsMaskBottom[2];\n\talignas(16) uint64 _x64XMM_andAbsMaskPair[2];\n\talignas(16) uint32 _x64XMM_andFloatAbsMaskBottom[4];\n\talignas(16) uint64 _x64XMM_singleWordMask[2];\n\talignas(16) double _x64XMM_constDouble1_1[2];\n\talignas(16) double _x64XMM_constDouble0_0[2];\n\talignas(16) float  _x64XMM_constFloat0_0[2];\n\talignas(16) float  _x64XMM_constFloat1_1[2];\n\talignas(16) float  _x64XMM_constFloatMin[2];\n\talignas(16) uint32 _x64XMM_flushDenormalMask1[4];\n\talignas(16) uint32 _x64XMM_flushDenormalMaskResetSignBits[4];\n\t// MXCSR\n\tuint32 _x64XMM_mxCsr_ftzOn;\n\tuint32 _x64XMM_mxCsr_ftzOff;\n}PPCRecompilerInstanceData_t;\n\nextern PPCRecompilerInstanceData_t* ppcRecompilerInstanceData;\nextern bool ppcRecompilerEnabled;\n\nvoid PPCRecompiler_init();\nvoid PPCRecompiler_Shutdown();\n\nvoid PPCRecompiler_allocateRange(uint32 startAddress, uint32 size);\n\nvoid PPCRecompiler_invalidateRange(uint32 startAddr, uint32 endAddr);\n\nextern void ATTR_MS_ABI (*PPCRecompiler_enterRecompilerCode)(uint64 codeMem, uint64 ppcInterpreterInstance);\nextern void ATTR_MS_ABI (*PPCRecompiler_leaveRecompilerCode_visited)();\nextern void ATTR_MS_ABI (*PPCRecompiler_leaveRecompilerCode_unvisited)();\n\n#define PPC_REC_INVALID_FUNCTION\t((PPCRecFunction_t*)-1)\n\n// recompiler interface\n\nvoid PPCRecompiler_recompileIfUnvisited(uint32 enterAddress);\nvoid PPCRecompiler_attemptEnter(struct PPCInterpreter_t* hCPU, uint32 enterAddress);\nvoid PPCRecompiler_attemptEnterWithoutRecompile(struct PPCInterpreter_t* hCPU, uint32 enterAddress);\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/PPCRecompilerIml.h",
    "content": "bool PPCRecompiler_generateIntermediateCode(ppcImlGenContext_t& ppcImlGenContext, PPCRecFunction_t* PPCRecFunction, std::set<uint32>& entryAddresses, class PPCFunctionBoundaryTracker& boundaryTracker);\n\nIMLSegment* PPCIMLGen_CreateSplitSegmentAtEnd(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo);\nIMLSegment* PPCIMLGen_CreateNewSegmentAsBranchTarget(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo);\n\nvoid PPCIMLGen_AssertIfNotLastSegmentInstruction(ppcImlGenContext_t& ppcImlGenContext);\n\nIMLInstruction* PPCRecompilerImlGen_generateNewEmptyInstruction(ppcImlGenContext_t* ppcImlGenContext);\nvoid PPCRecompiler_pushBackIMLInstructions(IMLSegment* imlSegment, sint32 index, sint32 shiftBackCount);\nIMLInstruction* PPCRecompiler_insertInstruction(IMLSegment* imlSegment, sint32 index);\n\nvoid PPCRecompilerIml_insertSegments(ppcImlGenContext_t* ppcImlGenContext, sint32 index, sint32 count);\n\nvoid PPCRecompilerIml_setSegmentPoint(IMLSegmentPoint* segmentPoint, IMLSegment* imlSegment, sint32 index);\nvoid PPCRecompilerIml_removeSegmentPoint(IMLSegmentPoint* segmentPoint);\n\n// Register management\nIMLReg PPCRecompilerImlGen_LookupReg(ppcImlGenContext_t* ppcImlGenContext, IMLName mappedName, IMLRegFormat regFormat);\n\nIMLReg PPCRecompilerImlGen_loadRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName);\n\n// IML instruction generation\nvoid PPCRecompilerImlGen_generateNewInstruction_conditional_r_s32(ppcImlGenContext_t* ppcImlGenContext, IMLInstruction* imlInstruction, uint32 operation, IMLReg registerIndex, sint32 immS32, uint32 crRegisterIndex, uint32 crBitIndex, bool bitMustBeSet);\n\n// IML generation - FPU\nbool PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate, bool isDouble);\nbool PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate, bool isDouble);\nbool PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate, bool isDouble);\nbool PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool hasUpdate, bool isDouble);\nbool PPCRecompilerImlGen_STFIWX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FMUL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FDIV(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FMADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FMSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FNMSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FMULS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FDIVS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FADDS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FSUBS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FMADDS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FMSUBS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FNMSUBS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FCMPO(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FCMPU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FMR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FABS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FNABS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FRES(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FRSP(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FNEG(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FSEL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FRSQRTE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_FCTIWZ(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PSQ_L(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate);\nbool PPCRecompilerImlGen_PSQ_ST(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate);\nbool PPCRecompilerImlGen_PS_MULSX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isVariant1);\nbool PPCRecompilerImlGen_PS_MADDSX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isVariant1);\nbool PPCRecompilerImlGen_PS_ADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_SUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_MUL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_DIV(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_MADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_NMADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_MSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withNegative);\nbool PPCRecompilerImlGen_PS_SUM0(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_SUM1(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_NEG(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_ABS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_RES(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_RSQRTE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_MR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_SEL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_MERGE00(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_MERGE01(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_MERGE10(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_MERGE11(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_CMPO0(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_CMPU0(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\nbool PPCRecompilerImlGen_PS_CMPU1(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode);\n\n// IML general\n\nvoid PPCRecompilerIML_isolateEnterableSegments(ppcImlGenContext_t* ppcImlGenContext);\n\nvoid PPCIMLGen_CreateSegmentBranchedPath(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchTaken, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchNotTaken);\nvoid PPCIMLGen_CreateSegmentBranchedPath(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchNotTaken); // no else segment\nvoid PPCIMLGen_CreateSegmentBranchedPathMultiple(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, IMLSegment** segmentsOut, IMLReg compareReg, sint32* compareValues, sint32 count, sint32 defaultCaseIndex);\n\nclass IMLRedirectInstOutput\n{\npublic:\n\tIMLRedirectInstOutput(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* outputSegment);\n\t~IMLRedirectInstOutput();\n\n\nprivate:\n\tppcImlGenContext_t* m_context;\n\tIMLSegment* m_prevSegment;\n};"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp",
    "content": "#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterHelper.h\"\n#include \"Cafe/HW/Espresso/EspressoISA.h\"\n#include \"PPCRecompiler.h\"\n#include \"PPCRecompilerIml.h\"\n#include \"IML/IML.h\"\n#include \"IML/IMLRegisterAllocatorRanges.h\"\n#include \"PPCFunctionBoundaryTracker.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n\nbool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext);\n\nstruct PPCBasicBlockInfo\n{\n\tPPCBasicBlockInfo(uint32 startAddress, const std::set<uint32>& entryAddresses) : startAddress(startAddress), lastAddress(startAddress)\n\t{\n\t\tisEnterable = entryAddresses.find(startAddress) != entryAddresses.end();\n\t}\n\n\tuint32 startAddress;\n\tuint32 lastAddress; // inclusive\n\tbool isEnterable{ false };\n\tbool hasContinuedFlow{ true }; // non-branch path goes to next segment, assumed by default\n\tbool hasBranchTarget{ false };\n\tuint32 branchTarget{};\n\n\t// associated IML segments\n\tIMLSegment* firstSegment{}; // first segment in chain, used as branch target for other segments\n\tIMLSegment* appendSegment{}; // last segment in chain, additional instructions should be appended to this segment\n\n\tvoid SetInitialSegment(IMLSegment* seg)\n\t{\n\t\tcemu_assert_debug(!firstSegment);\n\t\tcemu_assert_debug(!appendSegment);\n\t\tfirstSegment = seg;\n\t\tappendSegment = seg;\n\t}\n\n\tIMLSegment* GetFirstSegmentInChain()\n\t{\n\t\treturn firstSegment;\n\t}\n\n\tIMLSegment* GetSegmentForInstructionAppend()\n\t{\n\t\treturn appendSegment;\n\t}\n};\n\nIMLInstruction* PPCRecompilerImlGen_generateNewEmptyInstruction(ppcImlGenContext_t* ppcImlGenContext)\n{\n\tIMLInstruction& inst = ppcImlGenContext->currentOutputSegment->imlList.emplace_back();\n\tmemset(&inst, 0x00, sizeof(IMLInstruction));\n\treturn &inst;\n}\n\nvoid PPCRecompilerImlGen_generateNewInstruction_r_memory_indexed(ppcImlGenContext_t* ppcImlGenContext, IMLReg registerDestination, IMLReg registerMemory1, IMLReg registerMemory2, uint32 copyWidth, bool signExtend, bool switchEndian)\n{\n\tcemu_assert_debug(registerMemory1.IsValid());\n\tcemu_assert_debug(registerMemory2.IsValid());\n\tcemu_assert_debug(registerDestination.IsValid());\n\tIMLInstruction* imlInstruction = PPCRecompilerImlGen_generateNewEmptyInstruction(ppcImlGenContext);\n\timlInstruction->type = PPCREC_IML_TYPE_LOAD_INDEXED;\n\timlInstruction->operation = 0;\n\timlInstruction->op_storeLoad.registerData = registerDestination;\n\timlInstruction->op_storeLoad.registerMem = registerMemory1;\n\timlInstruction->op_storeLoad.registerMem2 = registerMemory2;\n\timlInstruction->op_storeLoad.copyWidth = copyWidth;\n\timlInstruction->op_storeLoad.flags2.swapEndian = switchEndian;\n\timlInstruction->op_storeLoad.flags2.signExtend = signExtend;\n}\n\nvoid PPCRecompilerImlGen_generateNewInstruction_memory_r_indexed(ppcImlGenContext_t* ppcImlGenContext, IMLReg registerDestination, IMLReg registerMemory1, IMLReg registerMemory2, uint32 copyWidth, bool signExtend, bool switchEndian)\n{\n\tcemu_assert_debug(registerMemory1.IsValid());\n\tcemu_assert_debug(registerMemory2.IsValid());\n\tcemu_assert_debug(registerDestination.IsValid());\n\tIMLInstruction* imlInstruction = PPCRecompilerImlGen_generateNewEmptyInstruction(ppcImlGenContext);\n\timlInstruction->type = PPCREC_IML_TYPE_STORE_INDEXED;\n\timlInstruction->operation = 0;\n\timlInstruction->op_storeLoad.registerData = registerDestination;\n\timlInstruction->op_storeLoad.registerMem = registerMemory1;\n\timlInstruction->op_storeLoad.registerMem2 = registerMemory2;\n\timlInstruction->op_storeLoad.copyWidth = copyWidth;\n\timlInstruction->op_storeLoad.flags2.swapEndian = switchEndian;\n\timlInstruction->op_storeLoad.flags2.signExtend = signExtend;\n}\n\n// create and fill two segments (branch taken and branch not taken) as a follow up to the current segment and then merge flow afterwards\nvoid PPCIMLGen_CreateSegmentBranchedPath(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchTaken, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchNotTaken)\n{\n\tIMLSegment* currentWriteSegment = basicBlockInfo.GetSegmentForInstructionAppend();\n\n\tstd::span<IMLSegment*> segments = ppcImlGenContext.InsertSegments(ppcImlGenContext.GetSegmentIndex(currentWriteSegment) + 1, 3);\n\tIMLSegment* segBranchNotTaken = segments[0];\n\tIMLSegment* segBranchTaken = segments[1];\n\tIMLSegment* segMerge = segments[2];\n\n\t// link the segments\n\tsegMerge->SetLinkBranchTaken(currentWriteSegment->GetBranchTaken());\n\tsegMerge->SetLinkBranchNotTaken(currentWriteSegment->GetBranchNotTaken());\n\tcurrentWriteSegment->SetLinkBranchTaken(segBranchTaken);\n\tcurrentWriteSegment->SetLinkBranchNotTaken(segBranchNotTaken);\n\tsegBranchTaken->SetLinkBranchNotTaken(segMerge);\n\tsegBranchNotTaken->SetLinkBranchTaken(segMerge);\n\t// generate code for branch taken segment\n\tppcImlGenContext.currentOutputSegment = segBranchTaken;\n\tgenSegmentBranchTaken(ppcImlGenContext);\n\tcemu_assert_debug(ppcImlGenContext.currentOutputSegment == segBranchTaken);\n\t// generate code for branch not taken segment\n\tppcImlGenContext.currentOutputSegment = segBranchNotTaken;\n\tgenSegmentBranchNotTaken(ppcImlGenContext);\n\tcemu_assert_debug(ppcImlGenContext.currentOutputSegment == segBranchNotTaken);\n\tppcImlGenContext.emitInst().make_jump();\n\t// make merge segment the new write segment\n\tppcImlGenContext.currentOutputSegment = segMerge;\n\tbasicBlockInfo.appendSegment = segMerge;\n}\n\nvoid PPCIMLGen_CreateSegmentBranchedPath(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, const std::function<void(ppcImlGenContext_t&)>& genSegmentBranchNotTaken)\n{\n\tIMLSegment* currentWriteSegment = basicBlockInfo.GetSegmentForInstructionAppend();\n\n\tstd::span<IMLSegment*> segments = ppcImlGenContext.InsertSegments(ppcImlGenContext.GetSegmentIndex(currentWriteSegment) + 1, 2);\n\tIMLSegment* segBranchNotTaken = segments[0];\n\tIMLSegment* segMerge = segments[1];\n\n\t// link the segments\n\tsegMerge->SetLinkBranchTaken(currentWriteSegment->GetBranchTaken());\n\tsegMerge->SetLinkBranchNotTaken(currentWriteSegment->GetBranchNotTaken());\n\tcurrentWriteSegment->SetLinkBranchTaken(segMerge);\n\tcurrentWriteSegment->SetLinkBranchNotTaken(segBranchNotTaken);\n\tsegBranchNotTaken->SetLinkBranchNotTaken(segMerge);\n\t// generate code for branch not taken segment\n\tppcImlGenContext.currentOutputSegment = segBranchNotTaken;\n\tgenSegmentBranchNotTaken(ppcImlGenContext);\n\tcemu_assert_debug(ppcImlGenContext.currentOutputSegment == segBranchNotTaken);\n\t// make merge segment the new write segment\n\tppcImlGenContext.currentOutputSegment = segMerge;\n\tbasicBlockInfo.appendSegment = segMerge;\n}\n\nIMLReg _GetRegTemporaryS8(ppcImlGenContext_t* ppcImlGenContext, uint32 index);\n\nIMLRedirectInstOutput::IMLRedirectInstOutput(ppcImlGenContext_t* ppcImlGenContext, IMLSegment* outputSegment) : m_context(ppcImlGenContext)\n{\n\tm_prevSegment = ppcImlGenContext->currentOutputSegment;\n\tcemu_assert_debug(ppcImlGenContext->currentOutputSegment == ppcImlGenContext->currentBasicBlock->appendSegment);\n\tif (outputSegment == ppcImlGenContext->currentOutputSegment)\n\t{\n\t\tm_prevSegment = nullptr;\n\t\treturn;\n\t}\n\tm_context->currentBasicBlock->appendSegment = outputSegment;\n\tm_context->currentOutputSegment = outputSegment;\n}\n\nIMLRedirectInstOutput::~IMLRedirectInstOutput()\n{\n\tif (m_prevSegment)\n\t{\n\t\tm_context->currentBasicBlock->appendSegment = m_prevSegment;\n\t\tm_context->currentOutputSegment = m_prevSegment;\n\t}\n}\n\n// compare values and branch to segment with same index in segmentsOut. The last segment doesn't actually have any comparison and just is the default case. Thus compareValues is one shorter than count\nvoid PPCIMLGen_CreateSegmentBranchedPathMultiple(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo, IMLSegment** segmentsOut, IMLReg compareReg, sint32* compareValues, sint32 count, sint32 defaultCaseIndex)\n{\n\tIMLSegment* currentWriteSegment = basicBlockInfo.GetSegmentForInstructionAppend();\n\tcemu_assert_debug(!currentWriteSegment->HasSuffixInstruction()); // must not already have a suffix instruction\n\n\tconst sint32 numBranchSegments = count + 1;\n\tconst sint32 numCaseSegments = count;\n\n\tstd::span<IMLSegment*> segments = ppcImlGenContext.InsertSegments(ppcImlGenContext.GetSegmentIndex(currentWriteSegment) + 1, numBranchSegments - 1 + numCaseSegments + 1);\n\tIMLSegment** extraBranchSegments = segments.data();\n\tIMLSegment** caseSegments = segments.data() + numBranchSegments - 1;\n\tIMLSegment* mergeSegment = segments[numBranchSegments - 1 + numCaseSegments];\n\n\t// move links to the merge segment\n\tmergeSegment->SetLinkBranchTaken(currentWriteSegment->GetBranchTaken());\n\tmergeSegment->SetLinkBranchNotTaken(currentWriteSegment->GetBranchNotTaken());\n\tcurrentWriteSegment->SetLinkBranchTaken(nullptr);\n\tcurrentWriteSegment->SetLinkBranchNotTaken(nullptr);\n\n\tfor (sint32 i=0; i<numCaseSegments; i++)\n\t\tsegmentsOut[i] = caseSegments[i];\n\n\tIMLReg tmpBoolReg = _GetRegTemporaryS8(&ppcImlGenContext, 2);\n\n\t// the first branch segment is the original current write segment\n\tauto GetBranchSegment = [&](sint32 index) {\n\t\tif (index == 0)\n\t\t\treturn currentWriteSegment;\n\t\telse\n\t\t\treturn extraBranchSegments[index - 1];\n\t};\n\t// link branch segments (taken: Link to case segment. NotTaken: Link to next branch segment. For the last one use a non-conditional jump)\n\tfor (sint32 i=0; i<numBranchSegments; i++)\n\t{\n\t\tIMLSegment* seg = GetBranchSegment(i);\n\t\tif (i < numBranchSegments - 1)\n\t\t{\n\t\t\tcemu_assert_debug(i < numCaseSegments);\n\t\t\tseg->SetLinkBranchTaken(caseSegments[i]);\n\t\t\tseg->SetLinkBranchNotTaken(GetBranchSegment(i + 1));\n\t\t\tseg->AppendInstruction()->make_compare_s32(compareReg, compareValues[i], tmpBoolReg, IMLCondition::EQ);\n\t\t\tseg->AppendInstruction()->make_conditional_jump(tmpBoolReg, true);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(defaultCaseIndex < numCaseSegments);\n\t\t\tseg->SetLinkBranchTaken(caseSegments[defaultCaseIndex]);\n\t\t\tseg->AppendInstruction()->make_jump();\n\t\t}\n\t}\n\t// link case segments\n\tfor (sint32 i=0; i<numCaseSegments; i++)\n\t{\n\t\tIMLSegment* seg = caseSegments[i];\n\t\tif (i < numCaseSegments - 1)\n\t\t{\n\t\t\tseg->SetLinkBranchTaken(mergeSegment);\n\t\t\t// -> Jumps are added after the instructions\n\t\t}\n\t\telse\n\t\t{\n\t\t\tseg->SetLinkBranchTaken(mergeSegment);\n\t\t}\n\t}\n\tppcImlGenContext.currentOutputSegment = mergeSegment;\n\tbasicBlockInfo.appendSegment = mergeSegment;\n}\n\nIMLReg PPCRecompilerImlGen_LookupReg(ppcImlGenContext_t* ppcImlGenContext, IMLName mappedName, IMLRegFormat regFormat)\n{\n\tauto it = ppcImlGenContext->mappedRegs.find(mappedName);\n\tif (it != ppcImlGenContext->mappedRegs.end())\n\t\treturn it->second;\n\t// create new reg entry\n\tIMLRegFormat baseFormat;\n\tif (regFormat == IMLRegFormat::F64)\n\t\tbaseFormat = IMLRegFormat::F64;\n\telse if (regFormat == IMLRegFormat::I32)\n\t\tbaseFormat = IMLRegFormat::I64;\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n\tIMLRegID newRegId = ppcImlGenContext->mappedRegs.size();\n\tIMLReg newReg(baseFormat, regFormat, 0, newRegId);\n\tppcImlGenContext->mappedRegs.try_emplace(mappedName, newReg);\n\treturn newReg;\n}\n\nIMLName PPCRecompilerImlGen_GetRegName(ppcImlGenContext_t* ppcImlGenContext, IMLReg reg)\n{\n\tfor (auto& it : ppcImlGenContext->mappedRegs)\n\t{\n\t\tif (it.second.GetRegID() == reg.GetRegID())\n\t\t\treturn it.first;\n\t}\n\tcemu_assert(false);\n\treturn 0;\n}\n\nuint32 PPCRecompilerImlGen_getAndLockFreeTemporaryFPR(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName)\n{\n\tDEBUG_BREAK;\n\t//if( mappedName == PPCREC_NAME_NONE )\n\t//{\n\t//\tdebug_printf(\"PPCRecompilerImlGen_getAndLockFreeTemporaryFPR(): Invalid mappedName parameter\\n\");\n\t//\treturn PPC_REC_INVALID_REGISTER;\n\t//}\n\t//for(uint32 i=0; i<255; i++)\n\t//{\n\t//\tif( ppcImlGenContext->mappedFPRRegister[i] == PPCREC_NAME_NONE )\n\t//\t{\n\t//\t\tppcImlGenContext->mappedFPRRegister[i] = mappedName;\n\t//\t\treturn i;\n\t//\t}\n\t//}\n\treturn 0;\n}\n\nuint32 PPCRecompilerImlGen_findFPRRegisterByMappedName(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName)\n{\n\tDEBUG_BREAK;\n\t//for(uint32 i=0; i<255; i++)\n\t//{\n\t//\tif( ppcImlGenContext->mappedFPRRegister[i] == mappedName )\n\t//\t{\n\t//\t\treturn i;\n\t//\t}\n\t//}\n\treturn PPC_REC_INVALID_REGISTER;\n}\n\nIMLReg PPCRecompilerImlGen_loadRegister(ppcImlGenContext_t* ppcImlGenContext, uint32 mappedName)\n{\n\treturn PPCRecompilerImlGen_LookupReg(ppcImlGenContext, mappedName, IMLRegFormat::I32);\n}\n\nIMLReg _GetRegGPR(ppcImlGenContext_t* ppcImlGenContext, uint32 index)\n{\n\tcemu_assert_debug(index < 32);\n\treturn PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + index);\n}\n\nIMLReg _GetRegCR(ppcImlGenContext_t* ppcImlGenContext, uint32 index)\n{\n\tcemu_assert_debug(index < 32);\n\treturn PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_CR + index);\n}\n\nIMLReg _GetRegCR(ppcImlGenContext_t* ppcImlGenContext, uint8 crReg, uint8 crBit)\n{\n\tcemu_assert_debug(crReg < 8);\n\tcemu_assert_debug(crBit < 4);\n\treturn _GetRegCR(ppcImlGenContext, (crReg * 4) + crBit);\n}\n\nIMLReg _GetRegTemporary(ppcImlGenContext_t* ppcImlGenContext, uint32 index)\n{\n\tcemu_assert_debug(index < 4);\n\treturn PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + index);\n}\n\n// get throw-away register\n// be careful to not collide with other temporary register\nIMLReg _GetRegTemporaryS8(ppcImlGenContext_t* ppcImlGenContext, uint32 index)\n{\n\tcemu_assert_debug(index < 4);\n\treturn PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + index);\n}\n\nbool PPCRecompiler_canInlineFunction(MPTR functionPtr, sint32* functionInstructionCount)\n{\n\tfor (sint32 i = 0; i < 6; i++)\n\t{\n\t\tuint32 opcode = memory_readU32(functionPtr + i * 4);\n\t\tswitch ((opcode >> 26))\n\t\t{\n\t\tcase 14: // ADDI\n\t\tcase 15: // ADDIS\n\t\t\tcontinue;\n\t\tcase 19: // opcode category 19\n\t\t\tswitch (PPC_getBits(opcode, 30, 10))\n\t\t\t{\n\t\t\tcase 16:\n\t\t\t\tif (opcode == 0x4E800020)\n\t\t\t\t{\n\t\t\t\t\t*functionInstructionCount = i;\n\t\t\t\t\treturn true; // BLR\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn false;\n\t\tcase 32: // LWZ\n\t\tcase 33: // LWZU\n\t\tcase 34: // LBZ\n\t\tcase 35: // LBZU\n\t\tcase 36: // STW\n\t\tcase 37: // STWU\n\t\tcase 38: // STB\n\t\tcase 39: // STBU\n\t\tcase 40: // LHZ\n\t\tcase 41: // LHZU\n\t\tcase 42: // LHA\n\t\tcase 43: // LHAU\n\t\tcase 44: // STH\n\t\tcase 45: // STHU\n\t\tcase 46: // LMW\n\t\tcase 47: // STMW\n\t\tcase 48: // LFS\n\t\tcase 49: // LFSU\n\t\tcase 50: // LFD\n\t\tcase 51: // LFDU\n\t\tcase 52: // STFS\n\t\tcase 53: // STFSU\n\t\tcase 54: // STFD\n\t\tcase 55: // STFDU\n\t\t\tcontinue;\n\t\tdefault:\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn false;\n}\n\nvoid PPCRecompiler_generateInlinedCode(ppcImlGenContext_t* ppcImlGenContext, uint32 startAddress, sint32 instructionCount)\n{\n\tfor (sint32 i = 0; i < instructionCount; i++)\n\t{\n\t\tppcImlGenContext->ppcAddressOfCurrentInstruction = startAddress + i * 4;\n\t\tppcImlGenContext->cyclesSinceLastBranch++;\n\t\tif (PPCRecompiler_decodePPCInstruction(ppcImlGenContext))\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t}\n\t// add range\n\tcemu_assert_unimplemented();\n\t//ppcRecRange_t recRange;\n\t//recRange.ppcAddress = startAddress;\n\t//recRange.ppcSize = instructionCount*4 + 4; // + 4 because we have to include the BLR\n\t//ppcImlGenContext->functionRef->list_ranges.push_back(recRange);\n}\n\n// for handling RC bit of many instructions\nvoid PPCImlGen_UpdateCR0(ppcImlGenContext_t* ppcImlGenContext, IMLReg regR)\n{\n\tIMLReg crBitRegLT = _GetRegCR(ppcImlGenContext, 0, Espresso::CR_BIT::CR_BIT_INDEX_LT);\n\tIMLReg crBitRegGT = _GetRegCR(ppcImlGenContext, 0, Espresso::CR_BIT::CR_BIT_INDEX_GT);\n\tIMLReg crBitRegEQ = _GetRegCR(ppcImlGenContext, 0, Espresso::CR_BIT::CR_BIT_INDEX_EQ);\n\t// todo - SO bit\n\n\tppcImlGenContext->emitInst().make_compare_s32(regR, 0, crBitRegLT, IMLCondition::SIGNED_LT);\n\tppcImlGenContext->emitInst().make_compare_s32(regR, 0, crBitRegGT, IMLCondition::SIGNED_GT);\n\tppcImlGenContext->emitInst().make_compare_s32(regR, 0, crBitRegEQ, IMLCondition::EQ);\n\n\t//ppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, crBitRegSO, 0); // todo - copy from XER\n\n\t//ppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, registerR, registerR, 0, PPCREC_CR_MODE_LOGICAL);\n}\n\nvoid PPCRecompilerImlGen_TW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// split before and after to make sure the macro is in an isolated segment that we can make enterable\n\tPPCIMLGen_CreateSplitSegmentAtEnd(*ppcImlGenContext, *ppcImlGenContext->currentBasicBlock);\n\tppcImlGenContext->currentOutputSegment->SetEnterable(ppcImlGenContext->ppcAddressOfCurrentInstruction);\n\tPPCRecompilerImlGen_generateNewEmptyInstruction(ppcImlGenContext)->make_macro(PPCREC_IML_MACRO_LEAVE, ppcImlGenContext->ppcAddressOfCurrentInstruction, 0, 0, IMLREG_INVALID);\n\tIMLSegment* middleSeg = PPCIMLGen_CreateSplitSegmentAtEnd(*ppcImlGenContext, *ppcImlGenContext->currentBasicBlock);\n\tmiddleSeg->SetLinkBranchTaken(nullptr);\n\tmiddleSeg->SetLinkBranchNotTaken(nullptr);\n}\n\nbool PPCRecompilerImlGen_MTSPR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tuint32 rD, spr1, spr2, spr;\n\tPPC_OPC_TEMPL_XO(opcode, rD, spr1, spr2);\n\tspr = spr1 | (spr2<<5);\n\tIMLReg gprReg = _GetRegGPR(ppcImlGenContext, rD);\n\tif (spr == SPR_CTR || spr == SPR_LR)\n\t{\n\t\tIMLReg sprReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + spr);\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, sprReg, gprReg);\n\t}\n\telse if (spr >= SPR_UGQR0 && spr <= SPR_UGQR7)\n\t{\n\t\tIMLReg sprReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + spr);\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, sprReg, gprReg);\n\t\tppcImlGenContext->tracking.modifiesGQR[spr - SPR_UGQR0] = true;\n\t}\n\telse\n\t\treturn false;\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_MFSPR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tuint32 rD, spr1, spr2, spr;\n\tPPC_OPC_TEMPL_XO(opcode, rD, spr1, spr2);\n\tspr = spr1 | (spr2<<5);\n\tIMLReg gprReg = _GetRegGPR(ppcImlGenContext, rD);\n\tif (spr == SPR_LR || spr == SPR_CTR)\n\t{\n\t\tIMLReg sprReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + spr);\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprReg, sprReg);\n\t}\n\telse if (spr >= SPR_UGQR0 && spr <= SPR_UGQR7)\n\t{\n\t\tIMLReg sprReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + spr);\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, gprReg, sprReg);\n\t}\n\telse\n\t\treturn false;\n\treturn true;\n}\n\nATTR_MS_ABI uint32 PPCRecompiler_GetTBL()\n{\n\treturn (uint32)coreinit::OSGetSystemTime();\n}\n\nATTR_MS_ABI uint32 PPCRecompiler_GetTBU()\n{\n\treturn (uint32)(coreinit::OSGetSystemTime() >> 32);\n}\n\nbool PPCRecompilerImlGen_MFTB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tuint32 rD, spr1, spr2, spr;\n\tPPC_OPC_TEMPL_XO(opcode, rD, spr1, spr2);\n\tspr = spr1 | (spr2<<5);\n\n\tif( spr == SPR_TBL || spr == SPR_TBU )\n\t{\n\t\tIMLReg resultReg = _GetRegGPR(ppcImlGenContext, rD);\n\t\tppcImlGenContext->emitInst().make_call_imm(spr == SPR_TBL ? (uintptr_t)PPCRecompiler_GetTBL : (uintptr_t)PPCRecompiler_GetTBU, IMLREG_INVALID, IMLREG_INVALID, IMLREG_INVALID, resultReg);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nvoid PPCRecompilerImlGen_MCRF(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tuint32 crD, crS, b;\n\tPPC_OPC_TEMPL_X(opcode, crD, crS, b);\n\tcemu_assert_debug((crD&3) == 0);\n\tcemu_assert_debug((crS&3) == 0);\n\tcrD >>= 2;\n\tcrS >>= 2;\n\tfor (sint32 i = 0; i<4; i++)\n\t{\n\t\tIMLReg regCrSrcBit = _GetRegCR(ppcImlGenContext, crS * 4 + i);\n\t\tIMLReg regCrDstBit = _GetRegCR(ppcImlGenContext, crD * 4 + i);\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regCrDstBit, regCrSrcBit);\n\t}\n}\n\nbool PPCRecompilerImlGen_MFCR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rD, rA, rB);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regD, 0);\n\tfor (sint32 i = 0; i < 32; i++)\n\t{\n\t\tIMLReg regCrBit = _GetRegCR(ppcImlGenContext, i);\n\t\tcemu_assert_debug(regCrBit.GetRegFormat() == IMLRegFormat::I32); // addition is only allowed between same-format regs\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_LEFT_SHIFT, regD, regD, 1);\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_ADD, regD, regD, regCrBit);\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_MTCRF(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tuint32 rS;\n\tuint32 crMask;\n\tPPC_OPC_TEMPL_XFX(opcode, rS, crMask);\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regTmp = _GetRegTemporary(ppcImlGenContext, 0);\n\tuint32 crBitMask = ppc_MTCRFMaskToCRBitMask(crMask);\n\tfor (sint32 f = 0; f < 32; f++)\n\t{\n\t\tif(((crBitMask >> f) & 1) == 0)\n\t\t\tcontinue;\n\t\tIMLReg regCrBit = _GetRegCR(ppcImlGenContext, f);\n\t\tcemu_assert_debug(regCrBit.GetRegFormat() == IMLRegFormat::I32);\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_U, regTmp, regS, (31-f));\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regCrBit, regTmp, 1);\n\t}\n\treturn true;\n}\n\nvoid PPCRecompilerImlGen_CMP(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isUnsigned)\n{\n\tuint32 cr;\n\tint rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, cr, rA, rB);\n\tcr >>= 2;\n\n\tIMLReg gprRegisterA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg gprRegisterB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regXerSO = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_SO);\n\n\tIMLReg crBitRegLT = _GetRegCR(ppcImlGenContext, cr, Espresso::CR_BIT::CR_BIT_INDEX_LT);\n\tIMLReg crBitRegGT = _GetRegCR(ppcImlGenContext, cr, Espresso::CR_BIT::CR_BIT_INDEX_GT);\n\tIMLReg crBitRegEQ = _GetRegCR(ppcImlGenContext, cr, Espresso::CR_BIT::CR_BIT_INDEX_EQ);\n\tIMLReg crBitRegSO = _GetRegCR(ppcImlGenContext, cr, Espresso::CR_BIT::CR_BIT_INDEX_SO);\n\n\tppcImlGenContext->emitInst().make_compare(gprRegisterA, gprRegisterB, crBitRegLT, isUnsigned ? IMLCondition::UNSIGNED_LT : IMLCondition::SIGNED_LT);\n\tppcImlGenContext->emitInst().make_compare(gprRegisterA, gprRegisterB, crBitRegGT, isUnsigned ? IMLCondition::UNSIGNED_GT : IMLCondition::SIGNED_GT);\n\tppcImlGenContext->emitInst().make_compare(gprRegisterA, gprRegisterB, crBitRegEQ, IMLCondition::EQ);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, crBitRegSO, regXerSO);\n}\n\nbool PPCRecompilerImlGen_CMPI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isUnsigned)\n{\n\tuint32 cr;\n\tint rA;\n\tuint32 imm;\n\tif (isUnsigned)\n\t{\n\t\tPPC_OPC_TEMPL_D_UImm(opcode, cr, rA, imm);\n\t}\n\telse\n\t{\n\t\tPPC_OPC_TEMPL_D_SImm(opcode, cr, rA, imm);\n\t}\n\tcr >>= 2;\n\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regXerSO = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_SO);\n\n\tIMLReg crBitRegLT = _GetRegCR(ppcImlGenContext, cr, Espresso::CR_BIT::CR_BIT_INDEX_LT);\n\tIMLReg crBitRegGT = _GetRegCR(ppcImlGenContext, cr, Espresso::CR_BIT::CR_BIT_INDEX_GT);\n\tIMLReg crBitRegEQ = _GetRegCR(ppcImlGenContext, cr, Espresso::CR_BIT::CR_BIT_INDEX_EQ);\n\tIMLReg crBitRegSO = _GetRegCR(ppcImlGenContext, cr, Espresso::CR_BIT::CR_BIT_INDEX_SO);\n\n\tppcImlGenContext->emitInst().make_compare_s32(regA, (sint32)imm, crBitRegLT, isUnsigned ? IMLCondition::UNSIGNED_LT : IMLCondition::SIGNED_LT);\n\tppcImlGenContext->emitInst().make_compare_s32(regA, (sint32)imm, crBitRegGT, isUnsigned ? IMLCondition::UNSIGNED_GT : IMLCondition::SIGNED_GT);\n\tppcImlGenContext->emitInst().make_compare_s32(regA, (sint32)imm, crBitRegEQ, IMLCondition::EQ);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, crBitRegSO, regXerSO);\n\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_B(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tuint32 li;\n\tPPC_OPC_TEMPL_I(opcode, li);\n\tuint32 jumpAddressDest = li;\n\tif( (opcode&PPC_OPC_AA) == 0 )\n\t{\n\t\tjumpAddressDest = li + (unsigned int)ppcImlGenContext->ppcAddressOfCurrentInstruction;\n\t}\n\tif( opcode&PPC_OPC_LK )\n\t{\n\t\t// function call\n\t\tppcImlGenContext->emitInst().make_macro(PPCREC_IML_MACRO_BL, ppcImlGenContext->ppcAddressOfCurrentInstruction, jumpAddressDest, ppcImlGenContext->cyclesSinceLastBranch, IMLREG_INVALID);\n\t\treturn true;\n\t}\n\t// is jump destination within recompiled function?\n\tif (ppcImlGenContext->boundaryTracker->ContainsAddress(jumpAddressDest))\n\t\tppcImlGenContext->emitInst().make_jump();\n\telse\n\t\tppcImlGenContext->emitInst().make_macro(PPCREC_IML_MACRO_B_FAR, ppcImlGenContext->ppcAddressOfCurrentInstruction, jumpAddressDest, ppcImlGenContext->cyclesSinceLastBranch, IMLREG_INVALID);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_BC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tPPCIMLGen_AssertIfNotLastSegmentInstruction(*ppcImlGenContext);\n\n\tuint32 BO, BI, BD;\n\tPPC_OPC_TEMPL_B(opcode, BO, BI, BD);\n\n\tEspresso::BOField boField(BO);\n\n\tuint32 crRegister = BI/4;\n\tuint32 crBit = BI%4;\n\tuint32 jumpCondition = 0;\n\tbool conditionMustBeTrue = (BO&8)!=0;\n\tbool useDecrementer = (BO&4)==0; // bit not set -> decrement\n\tbool decrementerMustBeZero = (BO&2)!=0; // bit set -> branch if CTR = 0, bit not set -> branch if CTR != 0\n\tbool ignoreCondition = (BO&16)!=0;\n\n\tIMLReg regCRBit;\n\tif (!ignoreCondition)\n\t\tregCRBit = _GetRegCR(ppcImlGenContext, crRegister, crBit);\n\n\tuint32 jumpAddressDest = BD;\n\tif( (opcode&PPC_OPC_AA) == 0 )\n\t{\n\t\tjumpAddressDest = BD + (unsigned int)ppcImlGenContext->ppcAddressOfCurrentInstruction;\n\t}\n\n\tif( opcode&PPC_OPC_LK )\n\t{\n\t\tif (useDecrementer)\n\t\t\treturn false;\n\t\t// conditional function calls are not supported\n\t\tif( ignoreCondition == false )\n\t\t{\n\t\t\tPPCBasicBlockInfo* currentBasicBlock = ppcImlGenContext->currentBasicBlock;\n\t\t\tIMLSegment* blSeg = PPCIMLGen_CreateNewSegmentAsBranchTarget(*ppcImlGenContext, *currentBasicBlock);\n\t\t\tppcImlGenContext->emitInst().make_conditional_jump(regCRBit, conditionMustBeTrue);\n\t\t\tblSeg->AppendInstruction()->make_macro(PPCREC_IML_MACRO_BL, ppcImlGenContext->ppcAddressOfCurrentInstruction, jumpAddressDest, ppcImlGenContext->cyclesSinceLastBranch, IMLREG_INVALID);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t// generate iml instructions depending on flags\n\tif( useDecrementer )\n\t{\n\t\tif( ignoreCondition == false )\n\t\t\treturn false; // not supported for the moment\n\t\tIMLReg ctrRegister = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0+SPR_CTR);\n\t\tIMLReg tmpBoolReg = _GetRegTemporaryS8(ppcImlGenContext, 1);\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_SUB, ctrRegister, ctrRegister, 1);\n\t\tppcImlGenContext->emitInst().make_compare_s32(ctrRegister, 0, tmpBoolReg, decrementerMustBeZero ? IMLCondition::EQ : IMLCondition::NEQ);\n\t\tppcImlGenContext->emitInst().make_conditional_jump(tmpBoolReg, true);\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tif( ignoreCondition )\n\t\t{\n\t\t\t// branch always, no condition and no decrementer\n\t\t\t// not supported\n\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (ppcImlGenContext->boundaryTracker->ContainsAddress(jumpAddressDest))\n\t\t\t{\n\t\t\t\t// near jump\n\t\t\t\tppcImlGenContext->emitInst().make_conditional_jump(regCRBit, conditionMustBeTrue);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// far jump\n\t\t\t\tdebug_printf(\"PPCRecompilerImlGen_BC(): Far jump not supported yet\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\n// BCCTR or BCLR\nbool PPCRecompilerImlGen_BCSPR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, uint32 sprReg)\n{\n\tPPCIMLGen_AssertIfNotLastSegmentInstruction(*ppcImlGenContext);\n\n\tEspresso::BOField BO;\n\tuint32 BI;\n\tbool LK;\n\tEspresso::decodeOp_BCSPR(opcode, BO, BI, LK);\n\tuint32 crRegister = BI/4;\n\tuint32 crBit = BI%4;\n\n\tIMLReg regCRBit;\n\tif (!BO.conditionIgnore())\n\t\tregCRBit = _GetRegCR(ppcImlGenContext, crRegister, crBit);\n\n\tIMLReg branchDestReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + sprReg);\n\tif (LK)\n\t{\n\t\tif (sprReg == SPR_LR)\n\t\t{\n\t\t\t// if the branch target is LR, then preserve it in a temporary\n\t\t\tcemu_assert_suspicious(); // this case needs testing\n\t\t\tIMLReg tmpRegister = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY);\n\t\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, tmpRegister, branchDestReg);\n\t\t\tbranchDestReg = tmpRegister;\n\t\t}\n\t\tIMLReg registerLR = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + SPR_LR);\n\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, registerLR, ppcImlGenContext->ppcAddressOfCurrentInstruction + 4);\n\t}\n\n\tif (!BO.decrementerIgnore())\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn false;\n\t}\n\telse if (!BO.conditionIgnore())\n\t{\n\t\t// no decrementer but CR check\n\t\tcemu_assert_debug(ppcImlGenContext->currentBasicBlock->hasContinuedFlow);\n\t\tcemu_assert_debug(!ppcImlGenContext->currentBasicBlock->hasBranchTarget);\n\t\tPPCBasicBlockInfo* currentBasicBlock = ppcImlGenContext->currentBasicBlock;\n\t\tIMLSegment* bctrSeg = PPCIMLGen_CreateNewSegmentAsBranchTarget(*ppcImlGenContext, *currentBasicBlock);\n\t\tppcImlGenContext->emitInst().make_conditional_jump(regCRBit, !BO.conditionInverted());\n\t\tbctrSeg->AppendInstruction()->make_macro(PPCREC_IML_MACRO_B_TO_REG, 0, 0, 0, branchDestReg);\n\t}\n\telse\n\t{\n\t\t// branch always, no condition and no decrementer check\n\t\tcemu_assert_debug(!ppcImlGenContext->currentBasicBlock->hasContinuedFlow);\n\t\tcemu_assert_debug(!ppcImlGenContext->currentBasicBlock->hasBranchTarget);\n\t\tppcImlGenContext->emitInst().make_macro(PPCREC_IML_MACRO_B_TO_REG, 0, 0, 0, branchDestReg);\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ISYNC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_SYNC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_ADD, regD, regA, regB);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ADDI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tif (rA != 0)\n\t{\n\t\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_ADD, regD, regA, imm);\n\t}\n\telse\n\t{\n\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regD, imm);\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ADDIS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_Shift16(opcode, rD, rA, imm);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tif (rA != 0)\n\t{\n\t\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_ADD, regD, regA, (sint32)imm);\n\t}\n\telse\n\t{\n\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regD, (sint32)imm);\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ADDC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// r = a + b -> update carry\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regRA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regRB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regRD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regCa = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\tppcImlGenContext->emitInst().make_r_r_r_carry(PPCREC_IML_OP_ADD, regRD, regRA, regRB, regCa);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regRD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ADDIC_(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool updateCR0)\n{\n\tsint32 rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regCa = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\tppcImlGenContext->emitInst().make_r_r_s32_carry(PPCREC_IML_OP_ADD, regD, regA, (sint32)imm, regCa);\n\tif(updateCR0)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ADDE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// r = a + b + carry -> update carry\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regRA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regRB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regRD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regCa = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\tppcImlGenContext->emitInst().make_r_r_r_carry(PPCREC_IML_OP_ADD_WITH_CARRY, regRD, regRA, regRB, regCa);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regRD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ADDZE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// r = a + carry -> update carry\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regRA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regRD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regCa = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\tppcImlGenContext->emitInst().make_r_r_s32_carry(PPCREC_IML_OP_ADD_WITH_CARRY, regRD, regRA, 0, regCa);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regRD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ADDME(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// r = a + 0xFFFFFFFF + carry -> update carry\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regRA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regRD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regCa = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\tppcImlGenContext->emitInst().make_r_r_s32_carry(PPCREC_IML_OP_ADD_WITH_CARRY, regRD, regRA, -1, regCa);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regRD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_SUBF(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\t// rD = ~rA + rB + 1\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_SUB, regD, regB, regA);\n\tif ((opcode & PPC_OPC_RC))\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_SUBFE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// d = ~a + b + ca;\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\tIMLReg regCa = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regTmp, regA);\n\tppcImlGenContext->emitInst().make_r_r_r_carry(PPCREC_IML_OP_ADD_WITH_CARRY, regD, regTmp, regB, regCa);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_SUBFZE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// d = ~a + ca;\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\tIMLReg regCa = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regTmp, regA);\n\tppcImlGenContext->emitInst().make_r_r_s32_carry(PPCREC_IML_OP_ADD_WITH_CARRY, regD, regTmp, 0, regCa);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_SUBFC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// d = ~a + b + 1;\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\tIMLReg regCa = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regTmp, regA);\n\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regCa, 1); // set input carry to simulate offset of 1\n\tppcImlGenContext->emitInst().make_r_r_r_carry(PPCREC_IML_OP_ADD_WITH_CARRY, regD, regTmp, regB, regCa);\n\tif ((opcode & PPC_OPC_RC))\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_SUBFIC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// d = ~a + imm + 1\n\tsint32 rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regCa = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\tIMLReg regTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regTmp, regA);\n\tppcImlGenContext->emitInst().make_r_r_s32_carry(PPCREC_IML_OP_ADD, regD, regTmp, (sint32)imm + 1, regCa);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_MULLI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_MULTIPLY_SIGNED, regD, regA, (sint32)imm);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_MULLW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tif (opcode & PPC_OPC_OE)\n\t{\n\t\treturn false;\n\t}\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_MULTIPLY_SIGNED, regD, regA, regB);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_MULHW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_MULTIPLY_HIGH_SIGNED, regD, regA, regB);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_MULHWU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_MULTIPLY_HIGH_UNSIGNED, regD, regA, regB);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_DIVW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regR = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_DIVIDE_SIGNED, regR, regA, regB);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regR);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_DIVWU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_DIVIDE_UNSIGNED, regD, regA, regB);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_RLWINM(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\tuint32 mask = ppc_mask(MB, ME);\n\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tif( ME == (31-SH) && MB == 0 )\n\t{\n\t\t// SLWI\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_LEFT_SHIFT, regA, regS, SH);\n\t}\n\telse if( SH == (32-MB) && ME == 31 )\n\t{\n\t\t// SRWI\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_U, regA, regS, MB);\n\t}\n\telse\n\t{\n\t\t// general handler\n\t\tif (rA != rS)\n\t\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regA, regS);\n\t\tif (SH != 0)\n\t\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_LEFT_ROTATE, regA, SH);\n\t\tif (mask != 0xFFFFFFFF)\n\t\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regA, regA, (sint32)mask);\n\t}\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_RLWIMI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regR = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regTmp = _GetRegTemporary(ppcImlGenContext, 0);\n\tuint32 mask = ppc_mask(MB, ME);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regTmp, regS);\n\tif (SH)\n\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_LEFT_ROTATE, regTmp, SH);\n\tif (mask != 0)\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regR, regR, (sint32)~mask);\n\tif (mask != 0xFFFFFFFF)\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regTmp, regTmp, (sint32)mask);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_OR, regR, regR, regTmp);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regR);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_RLWNM(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rS, rA, rB, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, rB, MB, ME);\n\tuint32 mask = ppc_mask(MB, ME);\n\tIMLReg regS = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rS);\n\tIMLReg regB = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rB);\n\tIMLReg regA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_LEFT_ROTATE, regA, regS, regB);\n\tif( mask != 0xFFFFFFFF )\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regA, regA, (sint32)mask);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_SRAW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// unlike SRAWI, for SRAW the shift range is 0-63 (masked to 6 bits)\n\t// but only shifts up to register bitwidth minus one are well defined in IML so this requires special handling for shifts >= 32\n\tsint32 rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\tIMLReg regS = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rS);\n\tIMLReg regB = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rB);\n\tIMLReg regA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);\n\tIMLReg regCarry = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\n\tIMLReg regTmpShiftAmount = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\tIMLReg regTmpCondBool = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 1);\n\tIMLReg regTmp1 = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 2);\n\tIMLReg regTmp2 = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 3);\n\n\t// load masked shift factor into temporary register\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regTmpShiftAmount, regB, 0x3F);\n\tppcImlGenContext->emitInst().make_compare_s32(regTmpShiftAmount, 31, regTmpCondBool, IMLCondition::UNSIGNED_GT);\n\tppcImlGenContext->emitInst().make_conditional_jump(regTmpCondBool, true);\n\n\tPPCIMLGen_CreateSegmentBranchedPath(*ppcImlGenContext, *ppcImlGenContext->currentBasicBlock,\n\t\t[&](ppcImlGenContext_t& genCtx)\n\t\t{\n\t\t\t/* branch taken, shift size 32 or above */\n\t\t\tgenCtx.emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_S, regA, regS, 31); // shift the sign bit into all the bits\n\t\t\tgenCtx.emitInst().make_compare_s32(regA, 0, regCarry, IMLCondition::NEQ);\n\t\t},\n\t\t[&](ppcImlGenContext_t& genCtx) \n\t\t{\n\t\t\t/* branch not taken, shift size below 32 */\n\t\t\tgenCtx.emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_S, regTmp1, regS, 31); // signMask = input >> 31 (arithmetic shift)\n\t\t\tgenCtx.emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regTmp2, 1); // shiftMask = ((1<<SH)-1)\n\t\t\tgenCtx.emitInst().make_r_r_r(PPCREC_IML_OP_LEFT_SHIFT, regTmp2, regTmp2, regTmpShiftAmount);\n\t\t\tgenCtx.emitInst().make_r_r_s32(PPCREC_IML_OP_SUB, regTmp2, regTmp2, 1);\n\t\t\tgenCtx.emitInst().make_r_r_r(PPCREC_IML_OP_AND, regTmp1, regTmp1, regTmp2); // signMask & shiftMask & input\n\t\t\tgenCtx.emitInst().make_r_r_r(PPCREC_IML_OP_AND, regTmp1, regTmp1, regS);\n\t\t\tgenCtx.emitInst().make_compare_s32(regTmp1, 0, regCarry, IMLCondition::NEQ);\n\t\t\tgenCtx.emitInst().make_r_r_r(PPCREC_IML_OP_RIGHT_SHIFT_S, regA, regS, regTmpShiftAmount);\n\t\t}\n\t);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_SRAWI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint rS, rA;\n\tuint32 SH;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, SH);\n\tcemu_assert_debug(SH < 32);\n\tif (SH == 0)\n\t\treturn false; // becomes a no-op (unless RC bit is set) but also sets ca bit to 0?\n\tIMLReg regS = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rS);\n\tIMLReg regA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rA);\n\tIMLReg regCarry = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_XER_CA);\n\tIMLReg regTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\t// calculate CA first\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_S, regTmp, regS, 31); // signMask = input >> 31 (arithmetic shift)\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_AND, regTmp, regTmp, regS); // testValue = input & signMask & ((1<<SH)-1)\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regTmp, regTmp, ((1 << SH) - 1));\n\tppcImlGenContext->emitInst().make_compare_s32(regTmp, 0, regCarry, IMLCondition::NEQ); // ca = (testValue != 0)\n\t// do the actual shift\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_S, regA, regS, (sint32)SH);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_SLW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_SLW, regA, regS, regB);\n\tif ((opcode & PPC_OPC_RC))\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_SRW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_SRW, regA, regS, regB);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_EXTSH(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN_S16_TO_S32, regA, regS);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_EXTSB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN_S8_TO_S32, regA, regS);\n\tif ((opcode & PPC_OPC_RC))\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_CNTLZW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_CNTLZW, regA, regS);\n\tif ((opcode & PPC_OPC_RC))\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_NEG(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA, rB;\n\tPPC_OPC_TEMPL_XO(opcode, rD, rA, rB);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NEG, regD, regA);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_LOAD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, uint32 bitWidth, bool signExtend, bool isBigEndian, bool updateAddrReg)\n{\n\tint rA, rD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\tIMLReg regMemAddr;\n\tif (rA == 0)\n\t{\n\t\tif (updateAddrReg)\n\t\t\treturn false; // invalid instruction form\n\t\tregMemAddr = _GetRegTemporary(ppcImlGenContext, 0);\n\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regMemAddr, 0);\n\t}\n\telse\n\t{\n\t\tif (updateAddrReg && rA == rD)\n\t\t\treturn false; // invalid instruction form\n\t\tregMemAddr = _GetRegGPR(ppcImlGenContext, rA);\n\t}\n\tif (updateAddrReg)\n\t{\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_ADD, regMemAddr, regMemAddr, (sint32)imm);\n\t\timm = 0;\n\t}\n\tIMLReg regDst = _GetRegGPR(ppcImlGenContext, rD);\n\tppcImlGenContext->emitInst().make_r_memory(regDst, regMemAddr, (sint32)imm, bitWidth, signExtend, isBigEndian);\n\treturn true;\n}\n\nvoid PPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, uint32 bitWidth, bool signExtend, bool isBigEndian, bool updateAddrReg)\n{\n\t// if rA == rD, then the EA wont be stored to rA. We could set updateAddrReg to false in such cases but the end result is the same since the loaded value would overwrite rA\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(opcode, rD, rA, rB);\n\tupdateAddrReg = updateAddrReg && (rA != 0);\n\tIMLReg regA = rA != 0 ? _GetRegGPR(ppcImlGenContext, rA) : IMLREG_INVALID;\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regDst = _GetRegGPR(ppcImlGenContext, rD);\n\tif (updateAddrReg)\n\t{\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_ADD, regA, regA, regB);\n\t\t// use single register addressing\n\t\tregB = regA;\n\t\tregA = IMLREG_INVALID;\n\t}\n\tif(regA.IsValid())\n\t\tPPCRecompilerImlGen_generateNewInstruction_r_memory_indexed(ppcImlGenContext, regDst, regA, regB, bitWidth, signExtend, isBigEndian);\n\telse\n\t\tppcImlGenContext->emitInst().make_r_memory(regDst, regB, 0, bitWidth, signExtend, isBigEndian);\n}\n\nbool PPCRecompilerImlGen_STORE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, uint32 bitWidth, bool isBigEndian, bool updateAddrReg)\n{\n\tint rA, rD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\tIMLReg regA;\n\tif (rA != 0)\n\t{\n\t\tregA = _GetRegGPR(ppcImlGenContext, rA);\n\t}\n\telse\n\t{\n\t\tif (updateAddrReg)\n\t\t\treturn false; // invalid instruction form\n\t\tregA = _GetRegTemporary(ppcImlGenContext, 0);\n\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regA, 0);\n\t}\n\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\tif (updateAddrReg)\n\t{\n\t\tif (rD == rA)\n\t\t{\n\t\t\t// make sure to keep source data intact\n\t\t\tregD = _GetRegTemporary(ppcImlGenContext, 0);\n\t\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regD, regA);\n\t\t}\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_ADD, regA, regA, (sint32)imm);\n\t\timm = 0;\n\t}\n\tppcImlGenContext->emitInst().make_memory_r(regD, regA, (sint32)imm, bitWidth, isBigEndian);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, uint32 bitWidth, bool isBigEndian, bool updateAddrReg)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\tIMLReg regA = rA != 0 ? _GetRegGPR(ppcImlGenContext, rA) : IMLREG_INVALID;\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regSrc = _GetRegGPR(ppcImlGenContext, rS);\n\tif (updateAddrReg)\n\t{\n\t\tif(rA == 0)\n\t\t\treturn false; // invalid instruction form\n\t\tif (regSrc == regA)\n\t\t{\n\t\t\t// make sure to keep source data intact\n\t\t\tregSrc = _GetRegTemporary(ppcImlGenContext, 0);\n\t\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regSrc, regA);\n\t\t}\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_ADD, regA, regA, regB);\n\t\t// use single register addressing\n\t\tregB = regA;\n\t\tregA = IMLREG_INVALID;\n\t}\n\tif (regA.IsInvalid())\n\t\tppcImlGenContext->emitInst().make_memory_r(regSrc, regB, 0, bitWidth, isBigEndian);\n\telse\n\t\tPPCRecompilerImlGen_generateNewInstruction_memory_r_indexed(ppcImlGenContext, regSrc, regA, regB, bitWidth, false, isBigEndian);\n\treturn true;\n}\n\nvoid PPCRecompilerImlGen_LMW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rD, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\tcemu_assert_debug(rA != 0);\n\tsint32 index = 0;\n\twhile (rD <= 31)\n\t{\n\t\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\t\tIMLReg regD = _GetRegGPR(ppcImlGenContext, rD);\n\t\t// load word\n\t\tppcImlGenContext->emitInst().make_r_memory(regD, regA, (sint32)imm + index * 4, 32, false, true);\n\t\t// next\n\t\trD++;\n\t\tindex++;\n\t}\n}\n\nvoid PPCRecompilerImlGen_STMW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rS, rA;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, rS, rA, imm);\n\tcemu_assert_debug(rA != 0);\n\tsint32 index = 0;\n\twhile( rS <= 31 )\n\t{\n\t\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\t\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\t\t// store word\n\t\tppcImlGenContext->emitInst().make_memory_r(regS, regA, (sint32)imm + index * 4, 32, true);\n\t\t// next\n\t\trS++;\n\t\tindex++;\n\t}\n}\n\nbool PPCRecompilerImlGen_LSWI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint rA, rD, nb;\n\tPPC_OPC_TEMPL_X(opcode, rD, rA, nb);\n\tif( nb == 0 )\n\t\tnb = 32;\n\n\tif (rA == 0)\n\t{\n\t\tcemu_assert_unimplemented(); // special form where gpr is ignored and EA is 0\n\t\treturn false;\n\t}\n\n\t// potential optimization: On x86 unaligned access is allowed and we could handle the case nb==4 with a single memory read, and nb==2 with a memory read and shift\n\n\tIMLReg memReg = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regTmp = _GetRegTemporary(ppcImlGenContext, 0);\n\tuint32 memOffset = 0;\n\twhile (nb > 0)\n\t{\n\t\tif (rD == rA)\n\t\t\treturn false;\n\t\tcemu_assert(rD < 32);\n\t\tIMLReg regDst = _GetRegGPR(ppcImlGenContext, rD);\n\t\t// load bytes one-by-one\n\t\tfor (sint32 b = 0; b < 4; b++)\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_r_memory(regTmp, memReg, memOffset + b, 8, false, false);\n\t\t\tsint32 shiftAmount = (3 - b) * 8;\n\t\t\tif(shiftAmount)\n\t\t\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_LEFT_SHIFT, regTmp, regTmp, shiftAmount);\n\t\t\tif(b == 0)\n\t\t\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regDst, regTmp);\n\t\t\telse\n\t\t\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_OR, regDst, regDst, regTmp);\n\t\t\tnb--;\n\t\t\tif (nb == 0)\n\t\t\t\tbreak;\n\t\t}\n\t\tmemOffset += 4;\n\t\trD++;\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_STSWI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint rA, rS, nb;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, nb);\n\tif( nb == 0 )\n\t\tnb = 32;\n\n\tIMLReg regMem = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regTmp = _GetRegTemporary(ppcImlGenContext, 0);\n\tuint32 memOffset = 0;\n\twhile (nb > 0)\n\t{\n\t\tif (rS == rA)\n\t\t\treturn false;\n\t\tcemu_assert(rS < 32);\n\t\tIMLReg regSrc = _GetRegGPR(ppcImlGenContext, rS);\n\t\t// store bytes one-by-one\n\t\tfor (sint32 b = 0; b < 4; b++)\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regTmp, regSrc);\n\t\t\tsint32 shiftAmount = (3 - b) * 8;\n\t\t\tif (shiftAmount)\n\t\t\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_U, regTmp, regTmp, shiftAmount);\n\t\t\tppcImlGenContext->emitInst().make_memory_r(regTmp, regMem, memOffset + b, 8, false);\n\t\t\tnb--;\n\t\t\tif (nb == 0)\n\t\t\t\tbreak;\n\t\t}\n\t\tmemOffset += 4;\n\t\trS++;\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_LWARX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rA, rD, rB;\n\tPPC_OPC_TEMPL_X(opcode, rD, rA, rB);\n\n\tIMLReg regA = rA != 0 ? PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rA) : IMLREG_INVALID;\n\tIMLReg regB = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rB);\n\tIMLReg regD = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rD);\n\tIMLReg regMemResEA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_CPU_MEMRES_EA);\n\tIMLReg regMemResVal = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_CPU_MEMRES_VAL);\n\t// calculate EA\n\tif (regA.IsValid())\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_ADD, regMemResEA, regA, regB);\n\telse\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regMemResEA, regB);\n\t// load word\n\tppcImlGenContext->emitInst().make_r_memory(regD, regMemResEA, 0, 32, false, true);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regMemResVal, regD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_STWCX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rA, rS, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\tIMLReg regA = rA != 0 ? PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rA) : IMLREG_INVALID;\n\tIMLReg regB = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rB);\n\tIMLReg regData = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0 + rS);\n\tIMLReg regTmpDataBE = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 2);\n\tIMLReg regTmpCompareBE = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 3);\n\t// calculate EA\n\tIMLReg regCalcEA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY);\n\tif (regA.IsValid())\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_ADD, regCalcEA, regA, regB);\n\telse\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regCalcEA, regB);\n\t// get  CR bit regs and set LT, GT and SO immediately\n\tIMLReg regCrLT = _GetRegCR(ppcImlGenContext, 0, Espresso::CR_BIT_INDEX_LT);\n\tIMLReg regCrGT = _GetRegCR(ppcImlGenContext, 0, Espresso::CR_BIT_INDEX_GT);\n\tIMLReg regCrEQ = _GetRegCR(ppcImlGenContext, 0, Espresso::CR_BIT_INDEX_EQ);\n\tIMLReg regCrSO = _GetRegCR(ppcImlGenContext, 0, Espresso::CR_BIT_INDEX_SO);\n\tIMLReg regXerSO = _GetRegCR(ppcImlGenContext, 0, Espresso::CR_BIT_INDEX_SO);\n\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regCrLT, 0);\n\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regCrGT, 0);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regCrSO, regXerSO);\n\t// get regs for reservation address and value\n\tIMLReg regMemResEA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_CPU_MEMRES_EA);\n\tIMLReg regMemResVal = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_CPU_MEMRES_VAL);\n\t// compare calculated EA with reservation\n\tIMLReg regTmpBool = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 1);\n\tppcImlGenContext->emitInst().make_compare(regCalcEA, regMemResEA, regTmpBool, IMLCondition::EQ);\n\tppcImlGenContext->emitInst().make_conditional_jump(regTmpBool, true);\n\n\tPPCIMLGen_CreateSegmentBranchedPath(*ppcImlGenContext, *ppcImlGenContext->currentBasicBlock,\n\t\t[&](ppcImlGenContext_t& genCtx)\n\t\t{\n\t\t\t/* branch taken, EA matching */\n\t\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ENDIAN_SWAP, regTmpDataBE, regData);\n\t\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ENDIAN_SWAP, regTmpCompareBE, regMemResVal);\n\t\t\tppcImlGenContext->emitInst().make_atomic_cmp_store(regMemResEA, regTmpCompareBE, regTmpDataBE, regCrEQ);\n\t\t},\n\t\t[&](ppcImlGenContext_t& genCtx)\n\t\t{\n\t\t\t/* branch not taken, EA mismatching */\n\t\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regCrEQ, 0);\n\t\t}\n\t);\n\n\t// reset reservation\n\t// I found contradictory information of whether the reservation is cleared in all cases, so unit testing would be required\n\t// Most sources state that it is cleared on successful store. They don't explicitly mention what happens on failure\n\t// \"The PowerPC 600 series, part 7: Atomic memory access and cache coherency\" states that it is always cleared\n\t// There may also be different behavior between individual PPC architectures\n\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regMemResEA, 0);\n\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regMemResVal, 0);\n\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_DCBZ(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rA, rB;\n\trA = (opcode>>16)&0x1F;\n\trB = (opcode>>11)&0x1F;\n\t// prepare registers\n\tIMLReg regA = rA!=0?PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA):IMLREG_INVALID;\n\tIMLReg regB = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rB);\n\t// load zero into a temporary register\n\tIMLReg regZero = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regZero, 0);\n\t// prepare EA and align it to cacheline\n\tIMLReg regMemResEA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 1);\n\tif(rA != 0)\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_ADD, regMemResEA, regA, regB);\n\telse\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regMemResEA, regB);\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regMemResEA, regMemResEA, ~31);\n\t// zero out the cacheline\n\tfor(sint32 i = 0; i < 32; i += 4)\n\t\tppcImlGenContext->emitInst().make_memory_r(regZero, regMemResEA, i, 32, false);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_OR_NOR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool complementResult)\n{\n\tint rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tif(rS == rB) // check for MR mnemonic\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regA, regS);\n\telse\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_OR, regA, regS, regB);\n\tif(complementResult)\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regA, regA);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ORC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\t// rA = rS | ~rB;\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regTmp = _GetRegTemporary(ppcImlGenContext, 0);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regTmp, regB);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_OR, regA, regS, regTmp);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_AND_NAND(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool complementResult)\n{\n\tint rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tif (regS == regB)\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_ASSIGN, regA, regS);\n\telse\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_AND, regA, regS, regB);\n\tif (complementResult)\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regA, regA);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_ANDC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\t// rA = rS & ~rB;\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\tIMLReg regTmp = _GetRegTemporary(ppcImlGenContext, 0);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regTmp, regB);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_AND, regA, regS, regTmp);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_XOR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool complementResult)\n{\n\tsint32 rS, rA, rB;\n\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tif( rS == rB )\n\t{\n\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regA, 0);\n\t}\n\telse\n\t{\n\t\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\t\tIMLReg regB = _GetRegGPR(ppcImlGenContext, rB);\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_XOR, regA, regS, regB);\n\t}\n\tif (complementResult)\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NOT, regA, regA);\n\tif (opcode & PPC_OPC_RC)\n\t\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n\treturn true;\n}\n\nvoid PPCRecompilerImlGen_ANDI_ANDIS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isShifted)\n{\n\tsint32 rS, rA;\n\tuint32 imm;\n\tif (isShifted)\n\t{\n\t\tPPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);\n\t}\n\telse\n\t{\n\t\tPPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);\n\t}\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, regA, regS, (sint32)imm);\n\t// ANDI/ANDIS always updates cr0\n\tPPCImlGen_UpdateCR0(ppcImlGenContext, regA);\n}\n\nvoid PPCRecompilerImlGen_ORI_ORIS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isShifted)\n{\n\tsint32 rS, rA;\n\tuint32 imm;\n\tif (isShifted)\n\t{\n\t\tPPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);\n\t}\n\telse\n\t{\n\t\tPPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);\n\t}\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_OR, regA, regS, (sint32)imm);\n}\n\nvoid PPCRecompilerImlGen_XORI_XORIS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isShifted)\n{\n\tsint32 rS, rA;\n\tuint32 imm;\n\tif (isShifted)\n\t{\n\t\tPPC_OPC_TEMPL_D_Shift16(opcode, rS, rA, imm);\n\t}\n\telse\n\t{\n\t\tPPC_OPC_TEMPL_D_UImm(opcode, rS, rA, imm);\n\t}\n\tIMLReg regS = _GetRegGPR(ppcImlGenContext, rS);\n\tIMLReg regA = _GetRegGPR(ppcImlGenContext, rA);\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_XOR, regA, regS, (sint32)imm);\n}\n\nbool PPCRecompilerImlGen_CROR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint crD, crA, crB;\n\tPPC_OPC_TEMPL_X(opcode, crD, crA, crB);\n\tIMLReg regCrA = _GetRegCR(ppcImlGenContext, crA);\n\tIMLReg regCrB = _GetRegCR(ppcImlGenContext, crB);\n\tIMLReg regCrR = _GetRegCR(ppcImlGenContext, crD);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_OR, regCrR, regCrA, regCrB);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_CRORC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint crD, crA, crB;\n\tPPC_OPC_TEMPL_X(opcode, crD, crA, crB);\n\tIMLReg regCrA = _GetRegCR(ppcImlGenContext, crA);\n\tIMLReg regCrB = _GetRegCR(ppcImlGenContext, crB);\n\tIMLReg regCrR = _GetRegCR(ppcImlGenContext, crD);\n\tIMLReg regTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY);\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_XOR, regTmp, regCrB, 1); // invert crB\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_OR, regCrR, regCrA, regTmp);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_CRAND(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint crD, crA, crB;\n\tPPC_OPC_TEMPL_X(opcode, crD, crA, crB);\n\tIMLReg regCrA = _GetRegCR(ppcImlGenContext, crA);\n\tIMLReg regCrB = _GetRegCR(ppcImlGenContext, crB);\n\tIMLReg regCrR = _GetRegCR(ppcImlGenContext, crD);\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_AND, regCrR, regCrA, regCrB);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_CRANDC(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint crD, crA, crB;\n\tPPC_OPC_TEMPL_X(opcode, crD, crA, crB);\n\tIMLReg regCrA = _GetRegCR(ppcImlGenContext, crA);\n\tIMLReg regCrB = _GetRegCR(ppcImlGenContext, crB);\n\tIMLReg regCrR = _GetRegCR(ppcImlGenContext, crD);\n\tIMLReg regTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY);\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_XOR, regTmp, regCrB, 1); // invert crB\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_AND, regCrR, regCrA, regTmp);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_CRXOR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint crD, crA, crB;\n\tPPC_OPC_TEMPL_X(opcode, crD, crA, crB);\n\tIMLReg regCrA = _GetRegCR(ppcImlGenContext, crA);\n\tIMLReg regCrB = _GetRegCR(ppcImlGenContext, crB);\n\tIMLReg regCrR = _GetRegCR(ppcImlGenContext, crD);\n\tif (regCrA == regCrB)\n\t{\n\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regCrR, 0);\n\t\treturn true;\n\t}\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_XOR, regCrR, regCrA, regCrB);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_CREQV(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint crD, crA, crB;\n\tPPC_OPC_TEMPL_X(opcode, crD, crA, crB);\n\tIMLReg regCrA = _GetRegCR(ppcImlGenContext, crA);\n\tIMLReg regCrB = _GetRegCR(ppcImlGenContext, crB);\n\tIMLReg regCrR = _GetRegCR(ppcImlGenContext, crD);\n\tif (regCrA == regCrB)\n\t{\n\t\tppcImlGenContext->emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, regCrR, 1);\n\t\treturn true;\n\t}\n\tIMLReg regTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY);\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_XOR, regTmp, regCrB, 1); // invert crB\n\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_XOR, regCrR, regCrA, regTmp);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_HLE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tuint32 hleFuncId = opcode&0xFFFF;\n\tppcImlGenContext->emitInst().make_macro(PPCREC_IML_MACRO_HLE, ppcImlGenContext->ppcAddressOfCurrentInstruction, hleFuncId, 0, IMLREG_INVALID);\n\treturn true;\n}\n\nuint32 PPCRecompiler_iterateCurrentInstruction(ppcImlGenContext_t* ppcImlGenContext)\n{\n\tuint32 v = CPU_swapEndianU32(*(ppcImlGenContext->currentInstruction));\n\tppcImlGenContext->currentInstruction += 1;\n\treturn v;\n}\n\nuint32 PPCRecompiler_getCurrentInstruction(ppcImlGenContext_t* ppcImlGenContext)\n{\n\tuint32 v = CPU_swapEndianU32(*(ppcImlGenContext->currentInstruction));\n\treturn v;\n}\n\nuint32 PPCRecompiler_getPreviousInstruction(ppcImlGenContext_t* ppcImlGenContext)\n{\n\tuint32 v = CPU_swapEndianU32(*(ppcImlGenContext->currentInstruction-1));\n\treturn v;\n}\n\nvoid PPCRecompilerIml_setSegmentPoint(IMLSegmentPoint* segmentPoint, IMLSegment* imlSegment, sint32 index)\n{\n\tsegmentPoint->imlSegment = imlSegment;\n\tsegmentPoint->SetInstructionIndex(index);\n\tif (imlSegment->segmentPointList)\n\t\timlSegment->segmentPointList->prev = segmentPoint;\n\tsegmentPoint->prev = nullptr;\n\tsegmentPoint->next = imlSegment->segmentPointList;\n\timlSegment->segmentPointList = segmentPoint;\n}\n\nvoid PPCRecompilerIml_removeSegmentPoint(IMLSegmentPoint* segmentPoint)\n{\n\tif (segmentPoint->prev)\n\t\tsegmentPoint->prev->next = segmentPoint->next;\n\telse\n\t\tsegmentPoint->imlSegment->segmentPointList = segmentPoint->next;\n\tif (segmentPoint->next)\n\t\tsegmentPoint->next->prev = segmentPoint->prev;\n}\n\n/*\n* Insert multiple no-op instructions\n* Warning: Can invalidate any previous instruction pointers from the same segment\n*/\nvoid PPCRecompiler_pushBackIMLInstructions(IMLSegment* imlSegment, sint32 index, sint32 shiftBackCount)\n{\n\tcemu_assert_debug(index >= 0 && index <= imlSegment->imlList.size());\n\n\timlSegment->imlList.insert(imlSegment->imlList.begin() + index, shiftBackCount, {});\n\n\tmemset(imlSegment->imlList.data() + index, 0, sizeof(IMLInstruction) * shiftBackCount);\n\n\t// fill empty space with NOP instructions\n\tfor (sint32 i = 0; i < shiftBackCount; i++)\n\t{\n\t\timlSegment->imlList[index + i].type = PPCREC_IML_TYPE_NONE;\n\t}\n\n\t// update position of segment points\n\tif (imlSegment->segmentPointList)\n\t{\n\t\tIMLSegmentPoint* segmentPoint = imlSegment->segmentPointList;\n\t\twhile (segmentPoint)\n\t\t{\n\t\t\tsegmentPoint->ShiftIfAfter(index, shiftBackCount);\n\t\t\tsegmentPoint = segmentPoint->next;\n\t\t}\n\t}\n}\n\nIMLInstruction* PPCRecompiler_insertInstruction(IMLSegment* imlSegment, sint32 index)\n{\n\tPPCRecompiler_pushBackIMLInstructions(imlSegment, index, 1);\n\treturn imlSegment->imlList.data() + index;\n}\n\nIMLInstruction* PPCRecompiler_appendInstruction(IMLSegment* imlSegment)\n{\n\tsize_t index = imlSegment->imlList.size();\n\timlSegment->imlList.emplace_back();\n\tmemset(imlSegment->imlList.data() + index, 0, sizeof(IMLInstruction));\n\treturn imlSegment->imlList.data() + index;\n}\n\nIMLSegment* PPCRecompilerIml_appendSegment(ppcImlGenContext_t* ppcImlGenContext)\n{\n\tIMLSegment* segment = new IMLSegment();\n\tppcImlGenContext->segmentList2.emplace_back(segment);\n\treturn segment;\n}\n\nvoid PPCRecompilerIml_insertSegments(ppcImlGenContext_t* ppcImlGenContext, sint32 index, sint32 count)\n{\n\tppcImlGenContext->segmentList2.insert(ppcImlGenContext->segmentList2.begin() + index, count, nullptr);\n\tfor (sint32 i = 0; i < count; i++)\n\t\tppcImlGenContext->segmentList2[index + i] = new IMLSegment();\n}\n\nbool PPCRecompiler_decodePPCInstruction(ppcImlGenContext_t* ppcImlGenContext)\n{\n\tbool unsupportedInstructionFound = false;\n\n\tuint32 opcode = PPCRecompiler_iterateCurrentInstruction(ppcImlGenContext);\n\tswitch ((opcode >> 26))\n\t{\n\tcase 1:\n\t\tif (PPCRecompilerImlGen_HLE(ppcImlGenContext, opcode) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 4: // opcode category - paired single\n\t\tswitch (PPC_getBits(opcode, 30, 5))\n\t\t{\n\t\tcase 0: // subcategory compare\n\t\t\tswitch (PPC_getBits(opcode, 25, 5))\n\t\t\t{\n\t\t\tcase 0:\n\t\t\t\tif( !PPCRecompilerImlGen_PS_CMPU0(ppcImlGenContext, opcode) )\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tif( !PPCRecompilerImlGen_PS_CMPO0(ppcImlGenContext, opcode) )\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tif( !PPCRecompilerImlGen_PS_CMPU1(ppcImlGenContext, opcode) )\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 8: //Sub category - move/negate\n\t\t\tswitch (PPC_getBits(opcode, 25, 5))\n\t\t\t{\n\t\t\tcase 1: // PS negate\n\t\t\t\tif (PPCRecompilerImlGen_PS_NEG(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 2: // PS move register\n\t\t\t\tif (PPCRecompilerImlGen_PS_MR(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 8: // PS abs\n\t\t\t\tif (PPCRecompilerImlGen_PS_ABS(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 10:\n\t\t\tif (PPCRecompilerImlGen_PS_SUM0(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 11:\n\t\t\tif (PPCRecompilerImlGen_PS_SUM1(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 12: // PS_MULS0\n\t\t\tif (PPCRecompilerImlGen_PS_MULSX(ppcImlGenContext, opcode, false) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 13: // PS_MULS1\n\t\t\tif (PPCRecompilerImlGen_PS_MULSX(ppcImlGenContext, opcode, true) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 14: // PS_MADDS0\n\t\t\tif (PPCRecompilerImlGen_PS_MADDSX(ppcImlGenContext, opcode, false) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 15: // PS_MADDS1\n\t\t\tif (PPCRecompilerImlGen_PS_MADDSX(ppcImlGenContext, opcode, true) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 16: // sub category - merge\n\t\t\tswitch (PPC_getBits(opcode, 25, 5))\n\t\t\t{\n\t\t\tcase 16:\n\t\t\t\tif (PPCRecompilerImlGen_PS_MERGE00(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 17:\n\t\t\t\tif (PPCRecompilerImlGen_PS_MERGE01(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 18:\n\t\t\t\tif (PPCRecompilerImlGen_PS_MERGE10(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 19:\n\t\t\t\tif (PPCRecompilerImlGen_PS_MERGE11(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 18: // divide paired\n\t\t\tif (PPCRecompilerImlGen_PS_DIV(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 20: // sub paired\n\t\t\tif (PPCRecompilerImlGen_PS_SUB(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 21: // add paired\n\t\t\tif (PPCRecompilerImlGen_PS_ADD(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 23: // select paired\n\t\t\tif (PPCRecompilerImlGen_PS_SEL(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 25: // multiply paired\n\t\t\tif (PPCRecompilerImlGen_PS_MUL(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 24: // reciprocal paired\n\t\t\tif (PPCRecompilerImlGen_PS_RES(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 26: // reciprocal squareroot paired\n\t\t\tif (PPCRecompilerImlGen_PS_RSQRTE(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 28: // PS_MSUB\n\t\t\tif (PPCRecompilerImlGen_PS_MSUB(ppcImlGenContext, opcode, false) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 29: // PS_MADD\n\t\t\tif (PPCRecompilerImlGen_PS_MADD(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 30: // PS_NMSUB\n\t\t\tif (PPCRecompilerImlGen_PS_MSUB(ppcImlGenContext, opcode, true) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 31: // PS_NMADD\n\t\t\tif (PPCRecompilerImlGen_PS_NMADD(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase 7: // MULLI\n\t\tPPCRecompilerImlGen_MULLI(ppcImlGenContext, opcode);\n\t\tbreak;\n\tcase 8: // SUBFIC\n\t\tif (!PPCRecompilerImlGen_SUBFIC(ppcImlGenContext, opcode))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 10: // CMPLI\n\t\tif (!PPCRecompilerImlGen_CMPI(ppcImlGenContext, opcode, true))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 11: // CMPI\n\t\tif (!PPCRecompilerImlGen_CMPI(ppcImlGenContext, opcode, false))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 12: // ADDIC\n\t\tif (PPCRecompilerImlGen_ADDIC_(ppcImlGenContext, opcode, false) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 13: // ADDIC.\n\t\tif (PPCRecompilerImlGen_ADDIC_(ppcImlGenContext, opcode, true) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 14: // ADDI\n\t\tif (PPCRecompilerImlGen_ADDI(ppcImlGenContext, opcode) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 15: // ADDIS\n\t\tif (PPCRecompilerImlGen_ADDIS(ppcImlGenContext, opcode) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 16: // BC\n\t\tif (PPCRecompilerImlGen_BC(ppcImlGenContext, opcode) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 17:\n\t\tif (PPC_getBits(opcode, 30, 1) == 1)\n\t\t{\n\t\t\t// SC -> no-op\n\t\t}\n\t\telse\n\t\t{\n\t\t\tunsupportedInstructionFound = true;\n\t\t}\n\t\tbreak;\n\tcase 18: // B\n\t\tif (PPCRecompilerImlGen_B(ppcImlGenContext, opcode) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 19: // opcode category 19\n\t\tswitch (PPC_getBits(opcode, 30, 10))\n\t\t{\n\t\tcase 0:\n\t\t\tPPCRecompilerImlGen_MCRF(ppcImlGenContext, opcode);\n\t\t\tbreak;\n\t\tcase 16: // BCLR\n\t\t\tif (PPCRecompilerImlGen_BCSPR(ppcImlGenContext, opcode, SPR_LR) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 129:\n\t\t\tif (PPCRecompilerImlGen_CRANDC(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 150:\n\t\t\tif (PPCRecompilerImlGen_ISYNC(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 193:\n\t\t\tif (PPCRecompilerImlGen_CRXOR(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 257:\n\t\t\tif (PPCRecompilerImlGen_CRAND(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 289:\n\t\t\tif (PPCRecompilerImlGen_CREQV(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 417:\n\t\t\tif (PPCRecompilerImlGen_CRORC(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 449:\n\t\t\tif (PPCRecompilerImlGen_CROR(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 528: // BCCTR\n\t\t\tif (PPCRecompilerImlGen_BCSPR(ppcImlGenContext, opcode, SPR_CTR) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase 20:\n\t\tif (PPCRecompilerImlGen_RLWIMI(ppcImlGenContext, opcode) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 21:\n\t\tif (PPCRecompilerImlGen_RLWINM(ppcImlGenContext, opcode) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 23:\n\t\tif (PPCRecompilerImlGen_RLWNM(ppcImlGenContext, opcode) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 24: // ORI\n\t\tPPCRecompilerImlGen_ORI_ORIS(ppcImlGenContext, opcode, false);\n\t\tbreak;\n\tcase 25: // ORIS\n\t\tPPCRecompilerImlGen_ORI_ORIS(ppcImlGenContext, opcode, true);\n\t\tbreak;\n\tcase 26: // XORI\n\t\tPPCRecompilerImlGen_XORI_XORIS(ppcImlGenContext, opcode, false);\n\t\tbreak;\n\tcase 27: // XORIS\n\t\tPPCRecompilerImlGen_XORI_XORIS(ppcImlGenContext, opcode, true);\n\t\tbreak;\n\tcase 28: // ANDI\n\t\tPPCRecompilerImlGen_ANDI_ANDIS(ppcImlGenContext, opcode, false);\n\t\tbreak;\n\tcase 29: // ANDIS\n\t\tPPCRecompilerImlGen_ANDI_ANDIS(ppcImlGenContext, opcode, true);\n\t\tbreak;\n\tcase 31: // opcode category\n\t\tswitch (PPC_getBits(opcode, 30, 10))\n\t\t{\n\t\tcase 0:\n\t\t\tPPCRecompilerImlGen_CMP(ppcImlGenContext, opcode, false);\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tPPCRecompilerImlGen_TW(ppcImlGenContext, opcode);\n\t\t\tbreak;\n\t\tcase 8:\n\t\tif (PPCRecompilerImlGen_SUBFC(ppcImlGenContext, opcode) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\t\tcase 10:\n\t\t\tif (PPCRecompilerImlGen_ADDC(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 11:\n\t\t\tif (PPCRecompilerImlGen_MULHWU(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 19:\n\t\t\tif (PPCRecompilerImlGen_MFCR(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 20:\n\t\t\tif (PPCRecompilerImlGen_LWARX(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 23: // LWZX\n\t\t\tPPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 32, false, true, false);\n\t\t\tbreak;\n\t\tcase 24:\n\t\t\tif (PPCRecompilerImlGen_SLW(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 26:\n\t\t\tif (PPCRecompilerImlGen_CNTLZW(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 28: // AND\n\t\t\tif (!PPCRecompilerImlGen_AND_NAND(ppcImlGenContext, opcode, false))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 32:\n\t\t\tPPCRecompilerImlGen_CMP(ppcImlGenContext, opcode, true); // CMPL\n\t\t\tbreak;\n\t\tcase 40:\n\t\t\tif (PPCRecompilerImlGen_SUBF(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 54:\n\t\t\t// DBCST - Generates no code\n\t\t\tbreak;\n\t\tcase 55: // LWZUX\n\t\t\tPPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 32, false, true, true);\n\t\t\tbreak;\n\t\tcase 60: // ANDC\n\t\t\tif (!PPCRecompilerImlGen_ANDC(ppcImlGenContext, opcode))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 75:\n\t\t\tif (PPCRecompilerImlGen_MULHW(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 86:\n\t\t\t// DCBF -> No-Op\n\t\t\tbreak;\n\t\tcase 87: // LBZX\n\t\t\tPPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 8, false, true, false);\n\t\t\tbreak;\n\t\tcase 104:\n\t\t\tif (PPCRecompilerImlGen_NEG(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 119: // LBZUX\n\t\t\tPPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 8, false, true, true);\n\t\t\tbreak;\n\t\tcase 124: // NOR\n\t\t\tif (!PPCRecompilerImlGen_OR_NOR(ppcImlGenContext, opcode, true))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 136:\n\t\t\tif (PPCRecompilerImlGen_SUBFE(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 138:\n\t\t\tif (PPCRecompilerImlGen_ADDE(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 144:\n\t\t\tif( !PPCRecompilerImlGen_MTCRF(ppcImlGenContext, opcode))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 150:\n\t\t\tif (!PPCRecompilerImlGen_STWCX(ppcImlGenContext, opcode))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 151: // STWX\n\t\t\tif (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 32, true, false))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 183: // STWUX\n\t\t\tif (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 32, true, true))\n\t\t\t\tunsupportedInstructionFound = true;\t\t\t\n\t\t\tbreak;\n\t\tcase 200:\n\t\t\tif (PPCRecompilerImlGen_SUBFZE(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 202:\n\t\t\tif (PPCRecompilerImlGen_ADDZE(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 215: // STBX\n\t\t\tif (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 8, true, false))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 234:\n\t\t\tif (PPCRecompilerImlGen_ADDME(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 235:\n\t\t\tif (PPCRecompilerImlGen_MULLW(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 247: // STBUX\n\t\t\tif (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 8, true, true))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 266:\n\t\t\tif (PPCRecompilerImlGen_ADD(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 279: // LHZX\n\t\t\tPPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 16, false, true, false);\n\t\t\tbreak;\n\t\tcase 284: // EQV (alias to NXOR)\n\t\t\tif (!PPCRecompilerImlGen_XOR(ppcImlGenContext, opcode, true))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 311: // LHZUX\n\t\t\tPPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 16, false, true, true);\n\t\t\tbreak;\n\t\tcase 316: // XOR\n\t\t\tif (!PPCRecompilerImlGen_XOR(ppcImlGenContext, opcode, false))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 339:\n\t\t\tif (PPCRecompilerImlGen_MFSPR(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 343: // LHAX\n\t\t\tPPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 16, true, true, false);\n\t\t\tbreak;\n\t\tcase 371:\n\t\t\tif (PPCRecompilerImlGen_MFTB(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 375: // LHAUX\n\t\t\tPPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 16, true, true, true);\n\t\t\tbreak;\n\t\tcase 407: // STHX\n\t\t\tif (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 16, true, false))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 412:\n\t\t\tif (PPCRecompilerImlGen_ORC(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 439: // STHUX\n\t\t\tif (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 16, true, true))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 444: // OR\n\t\t\tif (!PPCRecompilerImlGen_OR_NOR(ppcImlGenContext, opcode, false))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 459:\n\t\t\tPPCRecompilerImlGen_DIVWU(ppcImlGenContext, opcode);\n\t\t\tbreak;\n\t\tcase 467:\n\t\t\tif (PPCRecompilerImlGen_MTSPR(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 476: // NAND\n\t\t\tif (!PPCRecompilerImlGen_AND_NAND(ppcImlGenContext, opcode, true))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 491:\n\t\t\tif (PPCRecompilerImlGen_DIVW(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 534: // LWBRX\n\t\t\tPPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 32, false, false, false);\n\t\t\tbreak;\n\t\tcase 535: // LFSX\n\t\t\tif (PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext, opcode, false, false) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 536:\n\t\t\tif (PPCRecompilerImlGen_SRW(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 567: // LFSUX\n\t\t\tif (PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext, opcode, true, false) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 597:\n\t\t\tif (PPCRecompilerImlGen_LSWI(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 598:\n\t\t\tPPCRecompilerImlGen_SYNC(ppcImlGenContext, opcode);\n\t\t\tbreak;\n\t\tcase 599: // LFDX\n\t\t\tif (PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext, opcode, false, true) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 631: // LFDUX\n\t\t\tif (PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext, opcode, true, true) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 662: // STWBRX\n\t\t\tif (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 32, false, false))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 663: // STFSX\n\t\t\tif (PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext, opcode, false, false) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 695: // STFSUX\n\t\t\tif (PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext, opcode, true, false) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 725:\n\t\t\tif (PPCRecompilerImlGen_STSWI(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 727: // STFDX\n\t\t\tif (PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext, opcode, false, true) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 759: // STFDUX\n\t\t\tif (PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext, opcode, true, true) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 790: // LHBRX\n\t\t\tPPCRecompilerImlGen_LOAD_INDEXED(ppcImlGenContext, opcode, 16, false, false, false);\n\t\t\tbreak;\n\t\tcase 792:\n\t\t\tif (PPCRecompilerImlGen_SRAW(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 824:\n\t\t\tif (PPCRecompilerImlGen_SRAWI(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 918: // STHBRX\n\t\t\tif (!PPCRecompilerImlGen_STORE_INDEXED(ppcImlGenContext, opcode, 16, false, true))\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 922:\n\t\t\tif (PPCRecompilerImlGen_EXTSH(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 954:\n\t\t\tif (PPCRecompilerImlGen_EXTSB(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 983:\n\t\t\tif (PPCRecompilerImlGen_STFIWX(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tcase 1014:\n\t\t\tif (PPCRecompilerImlGen_DCBZ(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase 32: // LWZ\n\t\tif(!PPCRecompilerImlGen_LOAD(ppcImlGenContext, opcode, 32, false, true, false))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 33: // LWZU\n\t\tif (!PPCRecompilerImlGen_LOAD(ppcImlGenContext, opcode, 32, false, true, true))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 34: // LBZ\n\t\tif (!PPCRecompilerImlGen_LOAD(ppcImlGenContext, opcode, 8, false, true, false))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 35: // LBZU\n\t\tif (!PPCRecompilerImlGen_LOAD(ppcImlGenContext, opcode, 8, false, true, true))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 36: // STW\n\t\tif(!PPCRecompilerImlGen_STORE(ppcImlGenContext, opcode, 32, true, false))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 37: // STWU\n\t\tif (!PPCRecompilerImlGen_STORE(ppcImlGenContext, opcode, 32, true, true))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 38: // STB\n\t\tif (!PPCRecompilerImlGen_STORE(ppcImlGenContext, opcode, 8, true, false))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 39: // STBU\n\t\tif (!PPCRecompilerImlGen_STORE(ppcImlGenContext, opcode, 8, true, true))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 40: // LHZ\n\t\tif (!PPCRecompilerImlGen_LOAD(ppcImlGenContext, opcode, 16, false, true, false))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 41: // LHZU\n\t\tif (!PPCRecompilerImlGen_LOAD(ppcImlGenContext, opcode, 16, false, true, true))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 42: // LHA\n\t\tif (!PPCRecompilerImlGen_LOAD(ppcImlGenContext, opcode, 16, true, true, false))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 43: // LHAU\n\t\tif (!PPCRecompilerImlGen_LOAD(ppcImlGenContext, opcode, 16, true, true, true))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 44: // STH\n\t\tif (!PPCRecompilerImlGen_STORE(ppcImlGenContext, opcode, 16, true, false))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 45: // STHU\n\t\tif (!PPCRecompilerImlGen_STORE(ppcImlGenContext, opcode, 16, true, true))\n\t\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\tcase 46:\n\t\tPPCRecompilerImlGen_LMW(ppcImlGenContext, opcode);\n\t\tbreak;\n\tcase 47:\n\t\tPPCRecompilerImlGen_STMW(ppcImlGenContext, opcode);\n\t\tbreak;\n\tcase 48: // LFS\n\t\tif (PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext, opcode, false, false) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 49: // LFSU\n\t\tif (PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext, opcode, true, false) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 50: // LFD\n\t\tif (PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext, opcode, false, true) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 51: // LFDU\n\t\tif (PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext, opcode, true, true) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 52: // STFS\n\t\tif (PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext, opcode, false, false) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 53: // STFSU\n\t\tif (PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext, opcode, true, false) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 54: // STFD\n\t\tif (PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext, opcode, false, true) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 55: // STFDU\n\t\tif (PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext, opcode, true, true) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 56:\n\t\tif (PPCRecompilerImlGen_PSQ_L(ppcImlGenContext, opcode, false) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 57:\n\t\tif (PPCRecompilerImlGen_PSQ_L(ppcImlGenContext, opcode, true) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 59: // opcode category\n\t\tswitch (PPC_getBits(opcode, 30, 5))\n\t\t{\n\t\tcase 18:\n\t\t\tif (PPCRecompilerImlGen_FDIVS(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 20:\n\t\t\tif (PPCRecompilerImlGen_FSUBS(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 21:\n\t\t\tif (PPCRecompilerImlGen_FADDS(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 24:\n\t\t\tif (PPCRecompilerImlGen_FRES(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 25:\n\t\t\tif (PPCRecompilerImlGen_FMULS(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 28:\n\t\t\tif (PPCRecompilerImlGen_FMSUBS(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 29:\n\t\t\tif (PPCRecompilerImlGen_FMADDS(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 30:\n\t\t\tif (PPCRecompilerImlGen_FNMSUBS(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tunsupportedInstructionFound = true;\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase 60:\n\t\tif (PPCRecompilerImlGen_PSQ_ST(ppcImlGenContext, opcode, false) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 61:\n\t\tif (PPCRecompilerImlGen_PSQ_ST(ppcImlGenContext, opcode, true) == false)\n\t\t\tunsupportedInstructionFound = true;\n\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\tbreak;\n\tcase 63: // opcode category\n\t\tswitch (PPC_getBits(opcode, 30, 5))\n\t\t{\n\t\tcase 0:\n\t\t\tif (PPCRecompilerImlGen_FCMPU(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 12:\n\t\t\tif (PPCRecompilerImlGen_FRSP(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 15:\n\t\t\tif (PPCRecompilerImlGen_FCTIWZ(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 18:\n\t\t\tif (PPCRecompilerImlGen_FDIV(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 20:\n\t\t\tif (PPCRecompilerImlGen_FSUB(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 21:\n\t\t\tif (PPCRecompilerImlGen_FADD(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 23:\n\t\t\tif (PPCRecompilerImlGen_FSEL(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 25:\n\t\t\tif (PPCRecompilerImlGen_FMUL(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 26:\n\t\t\tif (PPCRecompilerImlGen_FRSQRTE(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 28:\n\t\t\tif (PPCRecompilerImlGen_FMSUB(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 29:\n\t\t\tif (PPCRecompilerImlGen_FMADD(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tcase 30:\n\t\t\tif (PPCRecompilerImlGen_FNMSUB(ppcImlGenContext, opcode) == false)\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tswitch (PPC_getBits(opcode, 30, 10))\n\t\t\t{\n\t\t\tcase 32:\n\t\t\t\tif (PPCRecompilerImlGen_FCMPO(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 40:\n\t\t\t\tif (PPCRecompilerImlGen_FNEG(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 72:\n\t\t\t\tif (PPCRecompilerImlGen_FMR(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 136:\n\t\t\t\tif (PPCRecompilerImlGen_FNABS(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tcase 264:\n\t\t\t\tif (PPCRecompilerImlGen_FABS(ppcImlGenContext, opcode) == false)\n\t\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tppcImlGenContext->hasFPUInstruction = true;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tunsupportedInstructionFound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tunsupportedInstructionFound = true;\n\t\tbreak;\n\t}\n\treturn unsupportedInstructionFound;\n}\n\n// returns false if code flow is not interrupted\nbool PPCRecompiler_CheckIfInstructionEndsSegment(PPCFunctionBoundaryTracker& boundaryTracker, uint32 instructionAddress, uint32 opcode, bool& makeNextInstEnterable, bool& continueDefaultPath, bool& hasBranchTarget, uint32& branchTarget)\n{\n\thasBranchTarget = false;\n\tbranchTarget = 0xFFFFFFFF;\n\tmakeNextInstEnterable = false;\n\tcontinueDefaultPath = false;\n\tswitch (Espresso::GetPrimaryOpcode(opcode))\n\t{\n\tcase Espresso::PrimaryOpcode::VIRTUAL_HLE:\n\t{\n\t\tmakeNextInstEnterable = true;\n\t\thasBranchTarget = false;\n\t\tcontinueDefaultPath = false;\n\t\treturn true;\n\t}\n\tcase Espresso::PrimaryOpcode::BC:\n\t{\n\t\tuint32 BD, BI;\n\t\tEspresso::BOField BO;\n\t\tbool AA, LK;\n\t\tEspresso::decodeOp_BC(opcode, BD, BO, BI, AA, LK);\n\t\tif (!LK)\n\t\t{\n\t\t\thasBranchTarget = true;\n\t\t\tbranchTarget = (AA ? BD : BD) + instructionAddress;\n\t\t\tif (!boundaryTracker.ContainsAddress(branchTarget))\n\t\t\t\thasBranchTarget = false; // far jump\n\t\t}\n\t\tmakeNextInstEnterable = LK;\n\t\tcontinueDefaultPath = true;\n\t\treturn true;\n\t}\n\tcase Espresso::PrimaryOpcode::B:\n\t{\n\t\tuint32 LI;\n\t\tbool AA, LK;\n\t\tEspresso::decodeOp_B(opcode, LI, AA, LK);\n\t\tif (!LK)\n\t\t{\n\t\t\thasBranchTarget = true;\n\t\t\tbranchTarget = AA ? LI : LI + instructionAddress;\n\t\t\tif (!boundaryTracker.ContainsAddress(branchTarget))\n\t\t\t\thasBranchTarget = false; // far jump\n\t\t}\n\t\tmakeNextInstEnterable = LK;\n\t\tcontinueDefaultPath = false;\n\t\treturn true;\n\t}\n\tcase Espresso::PrimaryOpcode::GROUP_19:\n\t\tswitch (Espresso::GetGroup19Opcode(opcode))\n\t\t{\n\t\tcase Espresso::Opcode19::BCLR:\n\t\tcase Espresso::Opcode19::BCCTR:\n\t\t{\n\t\t\tEspresso::BOField BO;\n\t\t\tuint32 BI;\n\t\t\tbool LK;\n\t\t\tEspresso::decodeOp_BCSPR(opcode, BO, BI, LK);\n\t\t\tcontinueDefaultPath = !BO.conditionIgnore() || !BO.decrementerIgnore(); // if branch is always taken then there is no continued path\n\t\t\tmakeNextInstEnterable = Espresso::DecodeLK(opcode);\n\t\t\treturn true;\n\t\t}\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase Espresso::PrimaryOpcode::GROUP_31:\n\t\tswitch (Espresso::GetGroup31Opcode(opcode))\n\t\t{\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\treturn false;\n}\n\nvoid PPCRecompiler_DetermineBasicBlockRange(std::vector<PPCBasicBlockInfo>& basicBlockList, PPCFunctionBoundaryTracker& boundaryTracker, uint32 ppcStart, uint32 ppcEnd, const std::set<uint32>& combinedBranchTargets, const std::set<uint32>& entryAddresses)\n{\n\tcemu_assert_debug(ppcStart <= ppcEnd);\n\n\tuint32 currentAddr = ppcStart;\n\n\tPPCBasicBlockInfo* curBlockInfo = &basicBlockList.emplace_back(currentAddr, entryAddresses);\n\n\tuint32 basicBlockStart = currentAddr;\t\n\twhile (currentAddr <= ppcEnd)\n\t{\n\t\tcurBlockInfo->lastAddress = currentAddr;\n\t\tuint32 opcode = memory_readU32(currentAddr);\n\t\tbool nextInstIsEnterable = false;\n\t\tbool hasBranchTarget = false;\n\t\tbool hasContinuedFlow = false;\n\t\tuint32 branchTarget = 0;\n\t\tif (PPCRecompiler_CheckIfInstructionEndsSegment(boundaryTracker, currentAddr, opcode, nextInstIsEnterable, hasContinuedFlow, hasBranchTarget, branchTarget))\n\t\t{\n\t\t\tcurBlockInfo->hasBranchTarget = hasBranchTarget;\n\t\t\tcurBlockInfo->branchTarget = branchTarget;\n\t\t\tcurBlockInfo->hasContinuedFlow = hasContinuedFlow;\n\t\t\t// start new basic block, except if this is the last instruction\n\t\t\tif (currentAddr >= ppcEnd)\n\t\t\t\tbreak;\n\t\t\tcurBlockInfo = &basicBlockList.emplace_back(currentAddr + 4, entryAddresses);\n\t\t\tcurBlockInfo->isEnterable = curBlockInfo->isEnterable || nextInstIsEnterable;\n\t\t\tcurrentAddr += 4;\n\t\t\tcontinue;\n\t\t}\n\t\tcurrentAddr += 4;\n\t\tif (currentAddr <= ppcEnd)\n\t\t{\n\t\t\tif (combinedBranchTargets.find(currentAddr) != combinedBranchTargets.end())\n\t\t\t{\n\t\t\t\t// instruction is branch target, start new basic block\n\t\t\t\tcurBlockInfo = &basicBlockList.emplace_back(currentAddr, entryAddresses);\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nstd::vector<PPCBasicBlockInfo> PPCRecompiler_DetermineBasicBlockRange(PPCFunctionBoundaryTracker& boundaryTracker, const std::set<uint32>& entryAddresses)\n{\n\tcemu_assert(!entryAddresses.empty());\n\tstd::vector<PPCBasicBlockInfo> basicBlockList;\n\n\tconst std::set<uint32> branchTargets = boundaryTracker.GetBranchTargets();\n\tauto funcRanges = boundaryTracker.GetRanges();\n\n\tstd::set<uint32> combinedBranchTargets = branchTargets;\n\tcombinedBranchTargets.insert(entryAddresses.begin(), entryAddresses.end());\n\n\tfor (auto& funcRangeIt : funcRanges)\n\t\tPPCRecompiler_DetermineBasicBlockRange(basicBlockList, boundaryTracker, funcRangeIt.startAddress, funcRangeIt.startAddress + funcRangeIt.length - 4, combinedBranchTargets, entryAddresses);\n\n\t// mark all segments that start at entryAddresses as enterable (debug code for verification, can be removed)\n\tsize_t numMarkedEnterable = 0;\n\tfor (auto& basicBlockIt : basicBlockList)\n\t{\n\t\tif (entryAddresses.find(basicBlockIt.startAddress) != entryAddresses.end())\n\t\t{\n\t\t\tcemu_assert_debug(basicBlockIt.isEnterable);\n\t\t\tnumMarkedEnterable++;\n\t\t}\n\t}\n\tcemu_assert_debug(numMarkedEnterable == entryAddresses.size());\n\n\t// todo - inline BL, currently this is done in the instruction handler of BL but this will mean that instruction cycle increasing is ignored\n\n\treturn basicBlockList;\n}\n\nbool PPCIMLGen_FillBasicBlock(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo)\n{\n\tppcImlGenContext.currentOutputSegment = basicBlockInfo.GetSegmentForInstructionAppend();\n\tppcImlGenContext.currentInstruction = (uint32*)(memory_base + basicBlockInfo.startAddress);\n\n\tuint32* firstCurrentInstruction = ppcImlGenContext.currentInstruction;\n\tuint32* endCurrentInstruction = (uint32*)(memory_base + basicBlockInfo.lastAddress);\n\n\twhile (ppcImlGenContext.currentInstruction <= endCurrentInstruction)\n\t{\n\t\tuint32 addressOfCurrentInstruction = (uint32)((uint8*)ppcImlGenContext.currentInstruction - memory_base);\n\t\tppcImlGenContext.ppcAddressOfCurrentInstruction = addressOfCurrentInstruction;\n\n\t\tif (PPCRecompiler_decodePPCInstruction(&ppcImlGenContext))\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"PPCRecompiler: Unsupported instruction at 0x{:08x}\", addressOfCurrentInstruction);\n\t\t\tppcImlGenContext.currentOutputSegment = nullptr;\n\t\t\treturn false;\n\t\t}\n\t}\n\tppcImlGenContext.currentOutputSegment = nullptr;\n\treturn true;\n}\n\n// returns split segment from which the continued segment is available via seg->GetBranchNotTaken()\nIMLSegment* PPCIMLGen_CreateSplitSegmentAtEnd(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo)\n{\n\tIMLSegment* writeSegment = basicBlockInfo.GetSegmentForInstructionAppend();\n\n\tIMLSegment* continuedSegment = ppcImlGenContext.InsertSegment(ppcImlGenContext.GetSegmentIndex(writeSegment) + 1);\n\n\tcontinuedSegment->SetLinkBranchTaken(writeSegment->GetBranchTaken());\n\tcontinuedSegment->SetLinkBranchNotTaken(writeSegment->GetBranchNotTaken());\n\n\twriteSegment->SetLinkBranchNotTaken(continuedSegment);\n\twriteSegment->SetLinkBranchTaken(nullptr);\n\n\tif (ppcImlGenContext.currentOutputSegment == writeSegment)\n\t\tppcImlGenContext.currentOutputSegment = continuedSegment;\n\n\tcemu_assert_debug(basicBlockInfo.appendSegment == writeSegment);\n\tbasicBlockInfo.appendSegment = continuedSegment;\n\n\treturn writeSegment;\n}\n\n// generates a new segment and sets it as branch target for the current write segment. Returns the created segment\nIMLSegment* PPCIMLGen_CreateNewSegmentAsBranchTarget(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo)\n{\n\tIMLSegment* writeSegment = basicBlockInfo.GetSegmentForInstructionAppend();\n\tIMLSegment* branchTargetSegment = ppcImlGenContext.NewSegment();\n\tcemu_assert_debug(!writeSegment->GetBranchTaken()); // must not have a target already\n\twriteSegment->SetLinkBranchTaken(branchTargetSegment);\n\treturn branchTargetSegment;\n}\n\n// verify that current instruction is the last instruction of the active basic block\nvoid PPCIMLGen_AssertIfNotLastSegmentInstruction(ppcImlGenContext_t& ppcImlGenContext)\n{\n\tcemu_assert_debug(ppcImlGenContext.currentBasicBlock->lastAddress == ppcImlGenContext.ppcAddressOfCurrentInstruction);\n}\n\nbool PPCRecompiler_IsBasicBlockATightFiniteLoop(IMLSegment* imlSegment, PPCBasicBlockInfo& basicBlockInfo)\n{\n\t// if we detect a finite loop we can skip generating the cycle check\n\t// currently we only check for BDNZ loops since thats reasonably safe to rely on\n\t// however there are other forms of loops that can be classified as finite,\n\t// but detecting those involves analyzing PPC code and we dont have the infrastructure for that (e.g. IML has CheckRegisterUsage but we dont have an equivalent for PPC code)\n\n\t// base criteria, must jump to beginning of same segment\n\tif (imlSegment->nextSegmentBranchTaken != imlSegment)\n\t\treturn false;\n\n\tuint32 opcode = *(uint32be*)(memory_base + basicBlockInfo.lastAddress);\n\tif (Espresso::GetPrimaryOpcode(opcode) != Espresso::PrimaryOpcode::BC)\n\t\treturn false;\n\tuint32 BO, BI, BD;\n\tPPC_OPC_TEMPL_B(opcode, BO, BI, BD);\n\tEspresso::BOField boField(BO);\n\tif(!boField.conditionIgnore() || boField.branchAlways())\n\t\treturn false;\n\tif(boField.decrementerIgnore())\n\t\treturn false;\n\treturn true;\n}\n\nvoid PPCRecompiler_HandleCycleCheckCount(ppcImlGenContext_t& ppcImlGenContext, PPCBasicBlockInfo& basicBlockInfo)\n{\n\tIMLSegment* imlSegment = basicBlockInfo.GetFirstSegmentInChain();\n\tif (!basicBlockInfo.hasBranchTarget)\n\t\treturn;\n\tif (basicBlockInfo.branchTarget > basicBlockInfo.startAddress)\n\t\treturn;\n\n\tif (PPCRecompiler_IsBasicBlockATightFiniteLoop(imlSegment, basicBlockInfo))\n\t\treturn;\n\n\t// make the segment enterable so execution can return after passing a check\n\tbasicBlockInfo.GetFirstSegmentInChain()->SetEnterable(basicBlockInfo.startAddress);\n\n\tIMLSegment* splitSeg = PPCIMLGen_CreateSplitSegmentAtEnd(ppcImlGenContext, basicBlockInfo);\n\tsplitSeg->AppendInstruction()->make_cjump_cycle_check();\n\n\tIMLSegment* exitSegment = ppcImlGenContext.NewSegment();\n\tsplitSeg->SetLinkBranchTaken(exitSegment);\n\n\texitSegment->AppendInstruction()->make_macro(PPCREC_IML_MACRO_LEAVE, basicBlockInfo.startAddress, 0, 0, IMLREG_INVALID);\n\n\tcemu_assert_debug(splitSeg->nextSegmentBranchNotTaken);\n\t// let the IML optimizer and RA know that the original segment should be used during analysis for dead code elimination\n\texitSegment->SetNextSegmentForOverwriteHints(splitSeg->nextSegmentBranchNotTaken);\n}\n\nvoid PPCRecompiler_SetSegmentsUncertainFlow(ppcImlGenContext_t& ppcImlGenContext)\n{\n\tfor (IMLSegment* segIt : ppcImlGenContext.segmentList2)\n\t{\n\t\t// handle empty segment\n\t\tif (segIt->imlList.empty())\n\t\t{\n\t\t\tcemu_assert_debug(segIt->GetBranchNotTaken());\n\t\t\tcontinue;\n\t\t}\n\t\t// check last instruction of segment\n\t\tIMLInstruction* imlInstruction = segIt->GetLastInstruction();\n\t\tif (imlInstruction->type == PPCREC_IML_TYPE_MACRO)\n\t\t{\n\t\t\tauto macroType = imlInstruction->operation;\n\t\t\tswitch (macroType)\n\t\t\t{\n\t\t\t\tcase PPCREC_IML_MACRO_B_TO_REG:\n\t\t\t\tcase PPCREC_IML_MACRO_BL:\n\t\t\t\tcase PPCREC_IML_MACRO_B_FAR:\n\t\t\t\tcase PPCREC_IML_MACRO_HLE:\n\t\t\t\tcase PPCREC_IML_MACRO_LEAVE:\n\t\t\t\t\tsegIt->nextSegmentIsUncertain = true;\n\t\t\t\t\tbreak;\n\t\t\t\tcase PPCREC_IML_MACRO_DEBUGBREAK:\n\t\t\t\tcase PPCREC_IML_MACRO_COUNT_CYCLES:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t}\n}\n\nbool PPCRecompiler_GenerateIML(ppcImlGenContext_t& ppcImlGenContext, PPCFunctionBoundaryTracker& boundaryTracker, std::set<uint32>& entryAddresses)\n{\n\tstd::vector<PPCBasicBlockInfo> basicBlockList = PPCRecompiler_DetermineBasicBlockRange(boundaryTracker, entryAddresses);\n\n\t// create segments\n\tstd::unordered_map<uint32, PPCBasicBlockInfo*> addrToBB;\n\tppcImlGenContext.segmentList2.resize(basicBlockList.size());\n\tfor (size_t i = 0; i < basicBlockList.size(); i++)\n\t{\n\t\tPPCBasicBlockInfo& basicBlockInfo = basicBlockList[i];\n\t\tIMLSegment* seg = new IMLSegment();\n\t\tseg->ppcAddress = basicBlockInfo.startAddress;\n\t\tif(basicBlockInfo.isEnterable)\n\t\t\tseg->SetEnterable(basicBlockInfo.startAddress);\n\t\tppcImlGenContext.segmentList2[i] = seg;\n\t\tcemu_assert_debug(addrToBB.find(basicBlockInfo.startAddress) == addrToBB.end());\n\t\tbasicBlockInfo.SetInitialSegment(seg);\n\t\taddrToBB.emplace(basicBlockInfo.startAddress, &basicBlockInfo);\n\t}\n\t// link segments\n\tfor (size_t i = 0; i < basicBlockList.size(); i++)\n\t{\n\t\tPPCBasicBlockInfo& bbInfo = basicBlockList[i];\n\t\tcemu_assert_debug(bbInfo.GetFirstSegmentInChain() == bbInfo.GetSegmentForInstructionAppend());\n\t\tIMLSegment* seg = ppcImlGenContext.segmentList2[i];\n\t\tif (bbInfo.hasBranchTarget)\n\t\t{\n\t\t\tPPCBasicBlockInfo* targetBB = addrToBB[bbInfo.branchTarget];\n\t\t\tcemu_assert_debug(targetBB);\n\t\t\tIMLSegment_SetLinkBranchTaken(seg, targetBB->GetFirstSegmentInChain());\n\t\t}\n\t\tif (bbInfo.hasContinuedFlow)\n\t\t{\n\t\t\tPPCBasicBlockInfo* targetBB = addrToBB[bbInfo.lastAddress + 4];\n\t\t\tif (!targetBB)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Recompiler, \"Recompiler was unable to link segment [0x{:08x}-0x{:08x}] to 0x{:08x}\", bbInfo.startAddress, bbInfo.lastAddress, bbInfo.lastAddress + 4);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tcemu_assert_debug(targetBB);\n\t\t\tIMLSegment_SetLinkBranchNotTaken(seg, targetBB->GetFirstSegmentInChain());\n\t\t}\n\t}\n\t// we assume that all unreachable segments are potentially enterable\n\t// todo - mark them as such\n\n\n\t// generate cycle counters\n\t// in theory we could generate these as part of FillBasicBlock() but in the future we might use more complex logic to emit fewer operations\n\tfor (size_t i = 0; i < basicBlockList.size(); i++)\n\t{\n\t\tPPCBasicBlockInfo& basicBlockInfo = basicBlockList[i];\n\t\tIMLSegment* seg = basicBlockInfo.GetSegmentForInstructionAppend();\n\n\t\tuint32 ppcInstructionCount = (basicBlockInfo.lastAddress - basicBlockInfo.startAddress + 4) / 4;\n\t\tcemu_assert_debug(ppcInstructionCount > 0);\n\n\t\tPPCRecompiler_pushBackIMLInstructions(seg, 0, 1);\n\t\tseg->imlList[0].type = PPCREC_IML_TYPE_MACRO;\n\t\tseg->imlList[0].operation = PPCREC_IML_MACRO_COUNT_CYCLES;\n\t\tseg->imlList[0].op_macro.param = ppcInstructionCount;\n\t}\n\n\t// generate cycle check instructions\n\t// note: Introduces new segments\n\tfor (size_t i = 0; i < basicBlockList.size(); i++)\n\t{\n\t\tPPCBasicBlockInfo& basicBlockInfo = basicBlockList[i];\n\t\tPPCRecompiler_HandleCycleCheckCount(ppcImlGenContext, basicBlockInfo);\n\t}\n\n\t// fill in all the basic blocks\n\t// note: This step introduces new segments as is necessary for some instructions\n\tfor (size_t i = 0; i < basicBlockList.size(); i++)\n\t{\n\t\tPPCBasicBlockInfo& basicBlockInfo = basicBlockList[i];\n\t\tppcImlGenContext.currentBasicBlock = &basicBlockInfo;\n\t\tif (!PPCIMLGen_FillBasicBlock(ppcImlGenContext, basicBlockInfo))\n\t\t\treturn false;\n\t\tppcImlGenContext.currentBasicBlock = nullptr;\n\t}\n\n\t// mark segments with unknown jump destination (e.g. BLR and most macros)\n\tPPCRecompiler_SetSegmentsUncertainFlow(ppcImlGenContext);\n\n\t// debug - check segment graph\n#ifdef CEMU_DEBUG_ASSERT\n\t//for (size_t i = 0; i < basicBlockList.size(); i++)\n\t//{\n\t//\tIMLSegment* seg = ppcImlGenContext.segmentList2[i];\n\t//\tif (seg->list_prevSegments.empty())\n\t//\t{\n\t//\t\tcemu_assert_debug(seg->isEnterable);\n\t//\t}\n\t//}\n\t// debug - check if suffix instructions are at the end of segments and if they are present for branching segments\n\tfor (size_t segIndex = 0; segIndex < ppcImlGenContext.segmentList2.size(); segIndex++)\n\t{\n\t\tIMLSegment* seg = ppcImlGenContext.segmentList2[segIndex];\n\t\tIMLSegment* nextSeg = (segIndex+1) < ppcImlGenContext.segmentList2.size() ? ppcImlGenContext.segmentList2[segIndex + 1] : nullptr;\n\n\t\tif (seg->imlList.size() > 0)\n\t\t{\n\t\t\tfor (size_t f = 0; f < seg->imlList.size() - 1; f++)\n\t\t\t{\n\t\t\t\tif (seg->imlList[f].IsSuffixInstruction())\n\t\t\t\t{\n\t\t\t\t\tdebug_printf(\"---------------- SegmentDump (Suffix instruction at wrong pos in segment 0x%x):\\n\", (int)segIndex);\n\t\t\t\t\tIMLDebug_Dump(&ppcImlGenContext);\n\t\t\t\t\tDEBUG_BREAK;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (seg->nextSegmentBranchTaken)\n\t\t{\n\t\t\tif (!seg->HasSuffixInstruction())\n\t\t\t{\n\t\t\t\tdebug_printf(\"---------------- SegmentDump (NoSuffixInstruction in segment 0x%x):\\n\", (int)segIndex);\n\t\t\t\tIMLDebug_Dump(&ppcImlGenContext);\n\t\t\t\tDEBUG_BREAK;\n\t\t\t}\n\t\t}\n\t\tif (seg->nextSegmentBranchNotTaken)\n\t\t{\n\t\t\t// if branch not taken, flow must continue to next segment in sequence\n\t\t\tcemu_assert_debug(seg->nextSegmentBranchNotTaken == nextSeg);\n\t\t}\n\t\t// more detailed checks based on actual suffix instruction\n\t\tif (seg->imlList.size() > 0)\n\t\t{\n\t\t\tIMLInstruction* inst = seg->GetLastInstruction();\n\t\t\tif (inst->type == PPCREC_IML_TYPE_MACRO && inst->op_macro.param == PPCREC_IML_MACRO_B_FAR)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(!seg->GetBranchTaken());\n\t\t\t\tcemu_assert_debug(!seg->GetBranchNotTaken());\n\t\t\t}\n\t\t\tif (inst->type == PPCREC_IML_TYPE_CJUMP_CYCLE_CHECK)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(seg->GetBranchTaken());\n\t\t\t\tcemu_assert_debug(seg->GetBranchNotTaken());\n\t\t\t}\n\t\t\tif (inst->type == PPCREC_IML_TYPE_CONDITIONAL_JUMP)\n\t\t\t{\n\t\t\t\tif (!seg->GetBranchTaken() || !seg->GetBranchNotTaken())\n\t\t\t\t{\n\t\t\t\t\tdebug_printf(\"---------------- SegmentDump (Missing branch for conditional jump in segment 0x%x):\\n\", (int)segIndex);\n\t\t\t\t\tIMLDebug_Dump(&ppcImlGenContext);\n\t\t\t\t\tcemu_assert_error();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tsegIndex++;\n\t}\n#endif\n\n\n\t// todos:\n\t// - basic block determination should look for the B(L) B(L) pattern. Or maybe just mark every bb without any input segments as an entry segment\n\n\treturn true;\n}\n\nbool PPCRecompiler_generateIntermediateCode(ppcImlGenContext_t& ppcImlGenContext, PPCRecFunction_t* ppcRecFunc, std::set<uint32>& entryAddresses, PPCFunctionBoundaryTracker& boundaryTracker)\n{\n\tppcImlGenContext.boundaryTracker = &boundaryTracker;\n\tif (!PPCRecompiler_GenerateIML(ppcImlGenContext, boundaryTracker, entryAddresses))\n\t\treturn false;\n\n\t// set range\n\t// todo - support non-continuous functions for the range tracking?\n\tppcRecRange_t recRange;\n\trecRange.ppcAddress = ppcRecFunc->ppcAddress;\n\trecRange.ppcSize = ppcRecFunc->ppcSize;\n\tppcRecFunc->list_ranges.push_back(recRange);\n\n\t\n\treturn true;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlGenFPU.cpp",
    "content": "#include \"Cafe/HW/Espresso/EspressoISA.h\"\n#include \"../Interpreter/PPCInterpreterInternal.h\"\n#include \"PPCRecompiler.h\"\n#include \"PPCRecompilerIml.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"IML/IML.h\"\n\nATTR_MS_ABI double frsqrte_espresso(double input);\nATTR_MS_ABI double fres_espresso(double input);\n\nIMLReg _GetRegCR(ppcImlGenContext_t* ppcImlGenContext, uint8 crReg, uint8 crBit);\n\n#define DefinePS0(name, regIndex) IMLReg name = _GetFPRRegPS0(ppcImlGenContext, regIndex);\n#define DefinePS1(name, regIndex) IMLReg name = _GetFPRRegPS1(ppcImlGenContext, regIndex);\n#define DefinePSX(name, regIndex, isPS1) IMLReg name = isPS1 ? _GetFPRRegPS1(ppcImlGenContext, regIndex) : _GetFPRRegPS0(ppcImlGenContext, regIndex);\n#define DefineTempFPR(name, index) IMLReg name = _GetFPRTemp(ppcImlGenContext, index);\n\nIMLReg _GetFPRRegPS0(ppcImlGenContext_t* ppcImlGenContext, uint32 regIndex)\n{\n\tcemu_assert_debug(regIndex < 32);\n\treturn PPCRecompilerImlGen_LookupReg(ppcImlGenContext, PPCREC_NAME_FPR_HALF + regIndex * 2 + 0, IMLRegFormat::F64);\n}\n\nIMLReg _GetFPRRegPS1(ppcImlGenContext_t* ppcImlGenContext, uint32 regIndex)\n{\n\tcemu_assert_debug(regIndex < 32);\n\treturn PPCRecompilerImlGen_LookupReg(ppcImlGenContext, PPCREC_NAME_FPR_HALF + regIndex * 2 + 1, IMLRegFormat::F64);\n}\n\nIMLReg _GetFPRTemp(ppcImlGenContext_t* ppcImlGenContext, uint32 index)\n{\n\tcemu_assert_debug(index < 4);\n\treturn PPCRecompilerImlGen_LookupReg(ppcImlGenContext, PPCREC_NAME_TEMPORARY_FPR0 + index, IMLRegFormat::F64);\n}\n\nIMLReg _GetFPRReg(ppcImlGenContext_t* ppcImlGenContext, uint32 regIndex, bool selectPS1)\n{\n\tcemu_assert_debug(regIndex < 32);\n\treturn PPCRecompilerImlGen_LookupReg(ppcImlGenContext, PPCREC_NAME_FPR_HALF + regIndex * 2 + (selectPS1 ? 1 : 0), IMLRegFormat::F64);\n}\n\nvoid PPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext_t* ppcImlGenContext, IMLReg fprRegister, bool flushDenormals=false)\n{\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_BOTTOM, fprRegister);\n\tif( flushDenormals )\n\t\tassert_dbg();\n}\n\nbool PPCRecompilerImlGen_LFS_LFSU_LFD_LFDU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate, bool isDouble)\n{\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, frD, rA, imm);\n\tIMLReg gprRegister = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);\n\tif (withUpdate)\n\t{\n\t\t// add imm to memory register\n\t\tcemu_assert_debug(rA != 0);\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_ADD, gprRegister, gprRegister, (sint32)imm);\n\t\timm = 0; // set imm to 0 so we dont add it twice\n\t}\n\tDefinePS0(fpPs0, frD);\n\tif (isDouble)\n\t{\n\t\t// LFD/LFDU\n\t\tppcImlGenContext->emitInst().make_fpr_r_memory(fpPs0, gprRegister, imm, PPCREC_FPR_LD_MODE_DOUBLE, true);\n\t}\n\telse\n\t{\n\t\t// LFS/LFSU\n\t\tppcImlGenContext->emitInst().make_fpr_r_memory(fpPs0, gprRegister, imm, PPCREC_FPR_LD_MODE_SINGLE, true);\n\t\tif( ppcImlGenContext->LSQE )\n\t\t{\n\t\t\tDefinePS1(fpPs1, frD);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fpPs1, fpPs0);\n\t\t}\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_LFSX_LFSUX_LFDX_LFDUX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate, bool isDouble)\n{\n\tsint32 rA, frD, rB;\n\tPPC_OPC_TEMPL_X(opcode, frD, rA, rB);\n\tif( rA == 0 )\n\t{\n\t\tdebugBreakpoint();\n\t\treturn false;\n\t}\n\t// get memory gpr registers\n\tIMLReg gprRegister1 = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);\n\tIMLReg gprRegister2 = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rB);\n\tif (withUpdate)\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_ADD, gprRegister1, gprRegister1, gprRegister2);\n\tDefinePS0(fpPs0, frD);\n\tif (isDouble)\n\t{\n\t\tif (withUpdate)\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_memory(fpPs0, gprRegister1, 0, PPCREC_FPR_LD_MODE_DOUBLE, true);\n\t\telse\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_memory_indexed(fpPs0, gprRegister1, gprRegister2, PPCREC_FPR_LD_MODE_DOUBLE, true);\n\t}\n\telse\n\t{\n\t\tif (withUpdate)\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_memory( fpPs0, gprRegister1, 0, PPCREC_FPR_LD_MODE_SINGLE, true);\n\t\telse\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_memory_indexed( fpPs0, gprRegister1, gprRegister2, PPCREC_FPR_LD_MODE_SINGLE, true);\n\t\tif( ppcImlGenContext->LSQE )\n\t\t{\n\t\t\tDefinePS1(fpPs1, frD);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fpPs1, fpPs0);\n\t\t}\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_STFS_STFSU_STFD_STFDU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate, bool isDouble)\n{\n\tsint32 rA, frD;\n\tuint32 imm;\n\tPPC_OPC_TEMPL_D_SImm(opcode, frD, rA, imm);\n\tIMLReg gprRegister = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);\n\tDefinePS0(fpPs0, frD);\n\tif (withUpdate)\n\t{\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_ADD, gprRegister, gprRegister, (sint32)imm);\n\t\timm = 0;\n\t}\n\tif (isDouble)\n\t\tppcImlGenContext->emitInst().make_fpr_memory_r(fpPs0, gprRegister, imm, PPCREC_FPR_ST_MODE_DOUBLE, true);\n\telse\n\t\tppcImlGenContext->emitInst().make_fpr_memory_r(fpPs0, gprRegister, imm, PPCREC_FPR_ST_MODE_SINGLE, true);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_STFSX_STFSUX_STFDX_STFDUX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool hasUpdate, bool isDouble)\n{\n\tsint32 rA, frS, rB;\n\tPPC_OPC_TEMPL_X(opcode, frS, rA, rB);\n\tif( rA == 0 )\n\t{\n\t\tdebugBreakpoint();\n\t\treturn false;\n\t}\n\t// get memory gpr registers\n\tIMLReg gprRegister1 = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);\n\tIMLReg gprRegister2 = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rB);\n\tif (hasUpdate)\n\t{\n\t\tppcImlGenContext->emitInst().make_r_r_r(PPCREC_IML_OP_ADD, gprRegister1, gprRegister1, gprRegister2);\n\t}\n\tDefinePS0(fpPs0, frS);\n\tauto mode = isDouble ? PPCREC_FPR_ST_MODE_DOUBLE : PPCREC_FPR_ST_MODE_SINGLE;\n\tif( ppcImlGenContext->LSQE )\n\t{\n\t\tif (hasUpdate)\n\t\t\tppcImlGenContext->emitInst().make_fpr_memory_r(fpPs0, gprRegister1, 0, mode, true);\n\t\telse\n\t\t\tppcImlGenContext->emitInst().make_fpr_memory_r_indexed(fpPs0, gprRegister1, gprRegister2, 0, mode, true);\n\t}\n\telse\n\t{\n\t\tif (hasUpdate)\n\t\t\tppcImlGenContext->emitInst().make_fpr_memory_r(fpPs0, gprRegister1, 0, mode, true);\n\t\telse\n\t\t\tppcImlGenContext->emitInst().make_fpr_memory_r_indexed(fpPs0, gprRegister1, gprRegister2, 0, mode, true);\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_STFIWX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 rA, frS, rB;\n\tPPC_OPC_TEMPL_X(opcode, frS, rA, rB);\n\tDefinePS0(fpPs0, frS);\n\tIMLReg gprRegister1;\n\tIMLReg gprRegister2;\n\tif( rA != 0 )\n\t{\n\t\tgprRegister1 = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);\n\t\tgprRegister2 = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rB);\n\t}\n\telse\n\t{\n\t\t// rA is not used\n\t\tgprRegister1 = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rB);\n\t\tgprRegister2 = IMLREG_INVALID;\n\t}\n\tif( rA != 0 )\n\t\tppcImlGenContext->emitInst().make_fpr_memory_r_indexed(fpPs0, gprRegister1, gprRegister2, 0, PPCREC_FPR_ST_MODE_UI32_FROM_PS0, true);\n\telse\n\t\tppcImlGenContext->emitInst().make_fpr_memory_r(fpPs0, gprRegister1, 0, PPCREC_FPR_ST_MODE_UI32_FROM_PS0, true);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frC==0);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_ADD, fprD, fprA, fprB);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frC==0);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_SUB, fprD, fprA, fprB);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FMUL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB_unused, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB_unused, frC);\n\tif( frD == frC )\n\t{\n\t\t// swap frA and frB\n\t\tsint32 temp = frA;\n\t\tfrA = frC;\n\t\tfrC = temp;\n\t}\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprC, frC);\n\tDefinePS0(fprD, frD);\n\t// move frA to frD (if different register)\n\tif( frD != frA )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprA);\n\t// multiply bottom double of frD with bottom double of frB\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprD, fprC);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FDIV(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC_unused;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC_unused);\n\tPPC_ASSERT(frB==0);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tif( frB == frD && frA != frB )\n\t{\n\t\tDefineTempFPR(fprTemp, 0);\n\t\t// move frA to temporary register\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp, fprA);\n\t\t// divide bottom double of temporary register by bottom double of frB\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_DIVIDE, fprTemp, fprB);\n\t\t// move result to frD\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprTemp);\n\t\treturn true;\n\t}\n\t// move frA to frD (if different register)\n\tif( frD != frA )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprA); // copy ps0\n\t// divide bottom double of frD by bottom double of frB\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_DIVIDE, fprD, fprB);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FMADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprC, frC);\n\tDefinePS0(fprD, frD);\n\t// if frB is already in frD we need a temporary register to store the product of frA*frC\n\tif( frB == frD )\n\t{\n\t\tDefineTempFPR(fprTemp, 0);\n\t\t// move frA to temporary register\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp, fprA);\n\t\t// multiply bottom double of temporary register with bottom double of frC\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp, fprC);\n\t\t// add result to frD\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprD, fprTemp);\n\t\treturn true;\n\t}\n\t// if frC == frD -> swap registers, we assume that frC != frD\n\tif( frD == frC )\n\t{\n\t\t// swap frA and frC\n\t\tIMLReg temp = fprA;\n\t\tfprA = fprC;\n\t\tfprC = temp;\n\t}\n\t// move frA to frD (if different register)\n\tif( frD != frA )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprA); // always copy ps0 and ps1\n\t// multiply bottom double of frD with bottom double of frC\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprD, fprC);\n\t// add frB\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprD, fprB);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FMSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprC, frC);\n\tDefinePS0(fprD, frD);\n\tif( frB == frD )\n\t{\n\t\t// if frB is already in frD we need a temporary register to store the product of frA*frC\n\t\tDefineTempFPR(fprTemp, 0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp, fprA);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp, fprC);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprTemp, fprB);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprTemp);\n\t\treturn false;\n\t}\n\tif( frD == frC )\n\t{\n\t\t// swap frA and frC\n\t\tIMLReg temp = fprA;\n\t\tfprA = fprC;\n\t\tfprC = temp;\n\t}\n\t// move frA to frD\n\tif( frD != frA )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprA);\n\t// multiply bottom double of frD with bottom double of frC\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprD, fprC);\n\t// sub frB\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprD, fprB);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FNMSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprC, frC);\n\tDefinePS0(fprD, frD);\n\t// if frB is already in frD we need a temporary register to store the product of frA*frC\n\tif( frB == frD )\n\t{\n\t\tDefineTempFPR(fprTemp, 0);\n\t\t// move frA to temporary register\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp, fprA);\n\t\t// multiply bottom double of temporary register with bottom double of frC\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp, fprC);\n\t\t// sub frB from temporary register\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprTemp, fprB);\n\t\t// negate result\n\t\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATE, fprTemp);\n\t\t// move result to frD\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprTemp);\n\t\treturn true;\n\t}\n\t// if frC == frD -> swap registers, we assume that frC != frD\n\tif( frD == frC )\n\t{\n\t\t// swap frA and frC\n\t\tIMLReg temp = fprA;\n\t\tfprA = fprC;\n\t\tfprC = temp;\n\t}\n\t// move frA to frD (if different register)\n\tif( frD != frA )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprA);\n\t// multiply bottom double of frD with bottom double of frC\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprD, fprC);\n\t// sub frB\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprD, fprB);\n\t// negate result\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATE, fprD);\n\treturn true;\n}\n\n#define PSE_CopyResultToPs1() \tif( ppcImlGenContext->PSE ) \\\n\t\t\t\t\t\t\t\t{ \\\n\t\t\t\t\t\t\t\t\tDefinePS1(fprDPS1, frD); \\\n\t\t\t\t\t\t\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDPS1, fprD); \\\n\t\t\t\t\t\t\t\t}\n\nbool PPCRecompilerImlGen_FMULS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB_unused, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB_unused, frC);\n\n\tif( frD == frC )\n\t{\n\t\t// swap frA and frC\n\t\tsint32 temp = frA;\n\t\tfrA = frC;\n\t\tfrC = temp;\n\t}\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprC, frC);\n\tDefinePS0(fprD, frD);\n\t// move frA to frD (if different register)\n\tif( frD != frA )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprA);\n\t// multiply bottom double of frD with bottom double of frB\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprD, fprC);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprD);\n\t// if paired single mode, copy frD ps0 to ps1\n\tPSE_CopyResultToPs1();\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FDIVS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC_unused;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC_unused);\n\tPPC_ASSERT(frB==0);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tif( frB == frD && frA != frB )\n\t{\n\t\tDefineTempFPR(fprTemp, 0);\n\t\t// move frA to temporary register\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp, fprA);\n\t\t// divide bottom double of temporary register by bottom double of frB\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_DIVIDE, fprTemp, fprB);\n\t\t// move result to frD\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprTemp);\n\t\t// adjust accuracy\n\t\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprD);\n\t\tPSE_CopyResultToPs1();\n\t\treturn true;\n\t}\n\t// move frA to frD (if different register)\n\tif( frD != frA )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprA);\n\t// subtract bottom double of frB from bottom double of frD\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_DIVIDE, fprD, fprB);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprD);\n\tPSE_CopyResultToPs1();\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FADDS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\n\tif( frD == frB )\n\t{\n\t\t// swap frA and frB\n\t\tsint32 temp = frA;\n\t\tfrA = frB;\n\t\tfrB = temp;\n\t}\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\t// move frA to frD (if different register)\n\tif( frD != frA )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprA);\n\t// add bottom double of frD and bottom double of frB\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprD, fprB);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprD);\n\tPSE_CopyResultToPs1();\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FSUBS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tint frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tPPC_ASSERT(frB==0);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_SUB, fprD, fprA, fprB);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprD);\n\tPSE_CopyResultToPs1();\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FMADDS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprC, frC);\n\tDefinePS0(fprD, frD);\n\t// if none of the operand registers overlap with the result register then we can avoid the usage of a temporary register\n\tIMLReg fprRegisterTemp;\n\tif( frD != frA && frD != frB && frD != frC )\n\t\tfprRegisterTemp = fprD;\n\telse\n\t\tfprRegisterTemp = _GetFPRTemp(ppcImlGenContext, 0);\n\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprRegisterTemp, fprA, fprC);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprRegisterTemp, fprB);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprRegisterTemp);\n\t// set result\n\tif( fprD != fprRegisterTemp )\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprRegisterTemp);\n\t}\n\tPSE_CopyResultToPs1();\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FMSUBS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprC, frC);\n\tDefinePS0(fprD, frD);\n\n\tIMLReg fprRegisterTemp;\n\t// if none of the operand registers overlap with the result register then we can avoid the usage of a temporary register\n\tif( frD != frA && frD != frB && frD != frC )\n\t\tfprRegisterTemp = fprD;\n\telse\n\t\tfprRegisterTemp = _GetFPRTemp(ppcImlGenContext, 0);\n\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprRegisterTemp, fprA, fprC);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprRegisterTemp, fprB);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprRegisterTemp);\n\t// set result\n\tif( fprD != fprRegisterTemp )\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprRegisterTemp);\n\t}\n\tPSE_CopyResultToPs1();\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FNMSUBS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprC, frC);\n\tDefinePS0(fprD, frD);\n\tIMLReg fprRegisterTemp;\n\t// if none of the operand registers overlap with the result register then we can avoid the usage of a temporary register\n\tif( frD != frA && frD != frB && frD != frC )\n\t\tfprRegisterTemp = fprD;\n\telse\n\t\tfprRegisterTemp = _GetFPRTemp(ppcImlGenContext, 0);\n\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprRegisterTemp, fprA, fprC);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprRegisterTemp, fprB);\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATE, fprRegisterTemp);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprRegisterTemp);\n\t// set result\n\tif( fprD != fprRegisterTemp )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprRegisterTemp);\n\tPSE_CopyResultToPs1();\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FCMPO(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// Not implemented\n\treturn false;\n}\n\nbool PPCRecompilerImlGen_FCMPU(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 crfD, frA, frB;\n\tPPC_OPC_TEMPL_X(opcode, crfD, frA, frB);\n\tcrfD >>= 2;\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\n\tIMLReg crBitRegLT = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_LT);\n\tIMLReg crBitRegGT = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_GT);\n\tIMLReg crBitRegEQ = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_EQ);\n\tIMLReg crBitRegSO = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_SO);\n\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegLT, IMLCondition::UNORDERED_LT);\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegGT, IMLCondition::UNORDERED_GT);\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegEQ, IMLCondition::UNORDERED_EQ);\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegSO, IMLCondition::UNORDERED_U);\n\n\t// todo: set fpscr\n\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FMR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, rA, frB;\n\tPPC_OPC_TEMPL_X(opcode, frD, rA, frB);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprB);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FABS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tPPC_OPC_TEMPL_X(opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tif( frD != frB )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprB);\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_ABS, fprD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FNABS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tPPC_OPC_TEMPL_X(opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tif( frD != frB )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprB);\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATIVE_ABS, fprD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FRES(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tPPC_OPC_TEMPL_X(opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tppcImlGenContext->emitInst().make_call_imm((uintptr_t)fres_espresso, fprB, IMLREG_INVALID, IMLREG_INVALID, fprD);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprD);\n\tPSE_CopyResultToPs1();\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FRSP(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tPPC_OPC_TEMPL_X(opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tif( fprD != fprB )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprB);\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_ROUND_TO_SINGLE_PRECISION_BOTTOM, fprD);\n\tPSE_CopyResultToPs1();\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FNEG(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tPPC_OPC_TEMPL_X(opcode, frD, frA, frB);\n\tPPC_ASSERT(frA==0);\n\tif( opcode&PPC_OPC_RC )\n\t\treturn false;\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tif( frD != frB )\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprD, fprB);\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATE, fprD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FSEL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tif( opcode&PPC_OPC_RC )\n\t{\n\t\treturn false;\n\t}\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprC, frC);\n\tDefinePS0(fprD, frD);\n\tppcImlGenContext->emitInst().make_fpr_r_r_r_r(PPCREC_IML_OP_FPR_SELECT, fprD, fprA, fprB, fprC);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FRSQRTE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tPPC_OPC_TEMPL_A(opcode, frD, frA, frB, frC);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tppcImlGenContext->emitInst().make_call_imm((uintptr_t)frsqrte_espresso, fprB, IMLREG_INVALID, IMLREG_INVALID, fprD);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprD);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_FCTIWZ(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tPPC_OPC_TEMPL_X(opcode, frD, frA, frB);\n\tDefinePS0(fprB, frB);\n\tDefinePS0(fprD, frD);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_FCTIWZ, fprD, fprB);\n\treturn true;\n}\n\nbool PPCRecompiler_isUGQRValueKnown(ppcImlGenContext_t* ppcImlGenContext, sint32 gqrIndex, uint32& gqrValue);\n\nvoid PPCRecompilerImlGen_ClampInteger(ppcImlGenContext_t* ppcImlGenContext, IMLReg reg, sint32 clampMin, sint32 clampMax)\n{\n\tIMLReg regTmpCondBool = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 1);\n\t// min(reg, clampMax)\n\tppcImlGenContext->emitInst().make_compare_s32(reg, clampMax, regTmpCondBool, IMLCondition::SIGNED_GT);\n\tppcImlGenContext->emitInst().make_conditional_jump(regTmpCondBool, false); // condition needs to be inverted because we skip if the condition is true\n\tPPCIMLGen_CreateSegmentBranchedPath(*ppcImlGenContext, *ppcImlGenContext->currentBasicBlock,\n\t\t[&](ppcImlGenContext_t& genCtx)\n\t\t{\n\t\t\t/* branch not taken */\n\t\t\tgenCtx.emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, reg, clampMax);\n\t\t}\n\t);\n\t// max(reg, clampMin)\n\tppcImlGenContext->emitInst().make_compare_s32(reg, clampMin, regTmpCondBool, IMLCondition::SIGNED_LT);\n\tppcImlGenContext->emitInst().make_conditional_jump(regTmpCondBool, false);\n\tPPCIMLGen_CreateSegmentBranchedPath(*ppcImlGenContext, *ppcImlGenContext->currentBasicBlock,\n\t\t[&](ppcImlGenContext_t& genCtx)\n\t\t{\n\t\t\t/* branch not taken */\n\t\t\tgenCtx.emitInst().make_r_s32(PPCREC_IML_OP_ASSIGN, reg, clampMin);\n\t\t}\n\t);\n}\n\nvoid PPCRecompilerIMLGen_GetPSQScale(ppcImlGenContext_t* ppcImlGenContext, IMLReg gqrRegister, IMLReg fprRegScaleOut, bool isLoad)\n{\n\tIMLReg gprTmp2 = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 2);\n\t// extract scale factor and sign extend it\n\tconstexpr sint32 scaleBitWidth = 6;\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_LEFT_SHIFT, gprTmp2, gqrRegister, 32 - ((isLoad ? 24 : 8) + scaleBitWidth));\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_S, gprTmp2, gprTmp2, (32 - 23) - scaleBitWidth);\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, gprTmp2, gprTmp2, 0x1FF<<23);\n\tif (isLoad)\n\t\tppcImlGenContext->emitInst().make_r_r(PPCREC_IML_OP_NEG, gprTmp2, gprTmp2);\n\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_ADD, gprTmp2, gprTmp2, 0x7F<<23);\n\t// gprTmp2 now holds the scale float bits, bitcast to float\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_BITCAST_INT_TO_FLOAT, fprRegScaleOut, gprTmp2);\n}\n\nvoid PPCRecompilerImlGen_EmitPSQLoadCase(ppcImlGenContext_t* ppcImlGenContext, sint32 gqrIndex, Espresso::PSQ_LOAD_TYPE loadType, bool readPS1, IMLReg gprA, sint32 imm, IMLReg fprDPS0, IMLReg fprDPS1)\n{\n\tif (loadType == Espresso::PSQ_LOAD_TYPE::TYPE_F32)\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_memory(fprDPS0, gprA, imm, PPCREC_FPR_LD_MODE_SINGLE, true);\n\t\tif(readPS1)\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_memory(fprDPS1, gprA, imm + 4, PPCREC_FPR_LD_MODE_SINGLE, true);\n\t\t}\n\t}\n\tif (loadType == Espresso::PSQ_LOAD_TYPE::TYPE_U16 || loadType == Espresso::PSQ_LOAD_TYPE::TYPE_S16)\n\t{\n\t\t// get scale factor\n\t\tIMLReg gqrRegister = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + SPR_UGQR0 + gqrIndex);\n\t\tIMLReg fprScaleReg = _GetFPRTemp(ppcImlGenContext, 2);\n\t\tPPCRecompilerIMLGen_GetPSQScale(ppcImlGenContext, gqrRegister, fprScaleReg, true);\n\n\t\tbool isSigned = (loadType == Espresso::PSQ_LOAD_TYPE::TYPE_S16);\n\t\tIMLReg gprTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\t\tppcImlGenContext->emitInst().make_r_memory(gprTmp, gprA, imm, 16, isSigned, true);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_INT_TO_FLOAT, fprDPS0, gprTmp);\n\n\t\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDPS0, fprDPS0, fprScaleReg);\n\n\t\tif(readPS1)\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_r_memory(gprTmp, gprA, imm + 2, 16, isSigned, true);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_INT_TO_FLOAT, fprDPS1, gprTmp);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDPS1, fprDPS1, fprScaleReg);\n\t\t}\n\t}\n\telse if (loadType == Espresso::PSQ_LOAD_TYPE::TYPE_U8 || loadType == Espresso::PSQ_LOAD_TYPE::TYPE_S8)\n\t{\n\t\t// get scale factor\n\t\tIMLReg gqrRegister = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + SPR_UGQR0 + gqrIndex);\n\t\tIMLReg fprScaleReg = _GetFPRTemp(ppcImlGenContext, 2);\n\t\tPPCRecompilerIMLGen_GetPSQScale(ppcImlGenContext, gqrRegister, fprScaleReg, true);\n\n\t\tbool isSigned = (loadType == Espresso::PSQ_LOAD_TYPE::TYPE_S8);\n\t\tIMLReg gprTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\t\tppcImlGenContext->emitInst().make_r_memory(gprTmp, gprA, imm, 8, isSigned, true);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_INT_TO_FLOAT, fprDPS0, gprTmp);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDPS0, fprDPS0, fprScaleReg);\n\t\tif(readPS1)\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_r_memory(gprTmp, gprA, imm + 1, 8, isSigned, true);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_INT_TO_FLOAT, fprDPS1, gprTmp);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDPS1, fprDPS1, fprScaleReg);\n\t\t}\n\t}\n}\n\n// PSQ_L and PSQ_LU\nbool PPCRecompilerImlGen_PSQ_L(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate)\n{\n\tint rA, frD;\n\tuint32 immUnused;\n\tPPC_OPC_TEMPL_D_SImm(opcode, frD, rA, immUnused);\n\tsint32 gqrIndex = ((opcode >> 12) & 7);\n\tuint32 imm = opcode & 0xFFF;\n\tif (imm & 0x800)\n\t\timm |= ~0xFFF;\n\tbool readPS1 = (opcode & 0x8000) == false;\n\n\tIMLReg gprA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);\n\tDefinePS0(fprDPS0, frD);\n\tDefinePS1(fprDPS1, frD);\n\tif (!readPS1)\n\t{\n\t\t// if PS1 is not explicitly read then set it to 1.0\n\t\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_LOAD_ONE, fprDPS1);\n\t}\n\tif (withUpdate)\n\t{\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_ADD, gprA, gprA, (sint32)imm);\n\t\timm = 0;\n\t}\n\tuint32 knownGQRValue = 0;\n\tif ( !PPCRecompiler_isUGQRValueKnown(ppcImlGenContext, gqrIndex, knownGQRValue) )\n\t{\n\t\t// generate complex dynamic handler when we dont know the GQR value ahead of time\n\t\tIMLReg gqrRegister = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + SPR_UGQR0 + gqrIndex);\n\t\tIMLReg loadTypeReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\t\t// extract the load type from the GQR register\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_RIGHT_SHIFT_U, loadTypeReg, gqrRegister, 16);\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, loadTypeReg, loadTypeReg, 0x7);\n\t\tIMLSegment* caseSegment[6];\n\t\tsint32 compareValues[6] = {0, 4, 5, 6, 7};\n\t\tPPCIMLGen_CreateSegmentBranchedPathMultiple(*ppcImlGenContext, *ppcImlGenContext->currentBasicBlock, caseSegment, loadTypeReg, compareValues, 5, 0);\n\t\tfor (sint32 i=0; i<5; i++)\n\t\t{\n\t\t\tIMLRedirectInstOutput outputToCase(ppcImlGenContext, caseSegment[i]); // while this is in scope, instructions go to caseSegment[i]\n\t\t\tPPCRecompilerImlGen_EmitPSQLoadCase(ppcImlGenContext, gqrIndex, static_cast<Espresso::PSQ_LOAD_TYPE>(compareValues[i]), readPS1, gprA, imm, fprDPS0, fprDPS1);\n\t\t\t// create the case jump instructions here because we need to add it last\n\t\t\tcaseSegment[i]->AppendInstruction()->make_jump();\n\t\t}\n\t\treturn true;\n\t}\n\n\tEspresso::PSQ_LOAD_TYPE type = static_cast<Espresso::PSQ_LOAD_TYPE>((knownGQRValue >> 16) & 0x7);\n\tsint32 scale = (knownGQRValue >> 24) & 0x3F;\n\tcemu_assert_debug(scale == 0); // known GQR values always use a scale of 0 (1.0f)\n\tif (scale != 0)\n\t\treturn false;\n\n\tif (type == Espresso::PSQ_LOAD_TYPE::TYPE_UNUSED1 ||\n\t\ttype == Espresso::PSQ_LOAD_TYPE::TYPE_UNUSED2 ||\n\t\ttype == Espresso::PSQ_LOAD_TYPE::TYPE_UNUSED3)\n\t{\n\t\treturn false;\n\t}\n\n\tPPCRecompilerImlGen_EmitPSQLoadCase(ppcImlGenContext, gqrIndex, type, readPS1, gprA, imm, fprDPS0, fprDPS1);\n\treturn true;\n}\n\nvoid PPCRecompilerImlGen_EmitPSQStoreCase(ppcImlGenContext_t* ppcImlGenContext, sint32 gqrIndex, Espresso::PSQ_LOAD_TYPE storeType, bool storePS1, IMLReg gprA, sint32 imm, IMLReg fprDPS0, IMLReg fprDPS1)\n{\n\tcemu_assert_debug(!storePS1 || fprDPS1.IsValid());\n\tif (storeType == Espresso::PSQ_LOAD_TYPE::TYPE_F32)\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_memory_r(fprDPS0, gprA, imm, PPCREC_FPR_ST_MODE_SINGLE, true);\n\t\tif(storePS1)\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_memory_r(fprDPS1, gprA, imm + 4, PPCREC_FPR_ST_MODE_SINGLE, true);\n\t\t}\n\t}\n\telse if (storeType == Espresso::PSQ_LOAD_TYPE::TYPE_U16 || storeType == Espresso::PSQ_LOAD_TYPE::TYPE_S16)\n\t{\n\t\t// get scale factor\n\t\tIMLReg gqrRegister = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + SPR_UGQR0 + gqrIndex);\n\t\tIMLReg fprScaleReg = _GetFPRTemp(ppcImlGenContext, 2);\n\t\tPPCRecompilerIMLGen_GetPSQScale(ppcImlGenContext, gqrRegister, fprScaleReg, false);\n\n\t\tbool isSigned = (storeType == Espresso::PSQ_LOAD_TYPE::TYPE_S16);\n\t\tIMLReg fprTmp = _GetFPRTemp(ppcImlGenContext, 0);\n\n\t\tIMLReg gprTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTmp, fprDPS0, fprScaleReg);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_FLOAT_TO_INT, gprTmp, fprTmp);\n\n\t\tif (isSigned)\n\t\t\tPPCRecompilerImlGen_ClampInteger(ppcImlGenContext, gprTmp, -32768, 32767);\n\t\telse\n\t\t\tPPCRecompilerImlGen_ClampInteger(ppcImlGenContext, gprTmp, 0, 65535);\n\t\tppcImlGenContext->emitInst().make_memory_r(gprTmp, gprA, imm, 16, true);\n\t\tif(storePS1)\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTmp, fprDPS1, fprScaleReg);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_FLOAT_TO_INT, gprTmp, fprTmp);\n\t\t\tif (isSigned)\n\t\t\t\tPPCRecompilerImlGen_ClampInteger(ppcImlGenContext, gprTmp, -32768, 32767);\n\t\t\telse\n\t\t\t\tPPCRecompilerImlGen_ClampInteger(ppcImlGenContext, gprTmp, 0, 65535);\n\t\t\tppcImlGenContext->emitInst().make_memory_r(gprTmp, gprA, imm + 2, 16, true);\n\t\t}\n\t}\n\telse if (storeType == Espresso::PSQ_LOAD_TYPE::TYPE_U8 || storeType == Espresso::PSQ_LOAD_TYPE::TYPE_S8)\n\t{\n\t\t// get scale factor\n\t\tIMLReg gqrRegister = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + SPR_UGQR0 + gqrIndex);\n\t\tIMLReg fprScaleReg = _GetFPRTemp(ppcImlGenContext, 2);\n\t\tPPCRecompilerIMLGen_GetPSQScale(ppcImlGenContext, gqrRegister, fprScaleReg, false);\n\n\t\tbool isSigned = (storeType == Espresso::PSQ_LOAD_TYPE::TYPE_S8);\n\t\tIMLReg fprTmp = _GetFPRTemp(ppcImlGenContext, 0);\n\t\tIMLReg gprTmp = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTmp, fprDPS0, fprScaleReg);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_FLOAT_TO_INT, gprTmp, fprTmp);\n\t\tif (isSigned)\n\t\t\tPPCRecompilerImlGen_ClampInteger(ppcImlGenContext, gprTmp, -128, 127);\n\t\telse\n\t\t\tPPCRecompilerImlGen_ClampInteger(ppcImlGenContext, gprTmp, 0, 255);\n\t\tppcImlGenContext->emitInst().make_memory_r(gprTmp, gprA, imm, 8, true);\n\t\tif(storePS1)\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTmp, fprDPS1, fprScaleReg);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_FLOAT_TO_INT, gprTmp, fprTmp);\n\t\t\tif (isSigned)\n\t\t\t\tPPCRecompilerImlGen_ClampInteger(ppcImlGenContext, gprTmp, -128, 127);\n\t\t\telse\n\t\t\t\tPPCRecompilerImlGen_ClampInteger(ppcImlGenContext, gprTmp, 0, 255);\n\t\t\tppcImlGenContext->emitInst().make_memory_r(gprTmp, gprA, imm + 1, 8, true);\n\t\t}\n\t}\n}\n\n// PSQ_ST and PSQ_STU\nbool PPCRecompilerImlGen_PSQ_ST(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withUpdate)\n{\n\tint rA, frD;\n\tuint32 immUnused;\n\tPPC_OPC_TEMPL_D_SImm(opcode, frD, rA, immUnused);\n\tuint32 imm = opcode & 0xFFF;\n\tif (imm & 0x800)\n\t\timm |= ~0xFFF;\n\tsint32 gqrIndex = ((opcode >> 12) & 7);\n\tbool storePS1 = (opcode & 0x8000) == false;\n\n\tIMLReg gprA = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_R0+rA);\n\tDefinePS0(fprDPS0, frD);\n\tIMLReg fprDPS1 = storePS1 ? _GetFPRRegPS1(ppcImlGenContext, frD) : IMLREG_INVALID;\n\n\tif (withUpdate)\n\t{\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_ADD, gprA, gprA, (sint32)imm);\n\t\timm = 0;\n\t}\n\n\tuint32 gqrValue = 0;\n\tif ( !PPCRecompiler_isUGQRValueKnown(ppcImlGenContext, gqrIndex, gqrValue) )\n\t{\n\t\t// generate complex dynamic handler when we dont know the GQR value ahead of time\n\t\tIMLReg gqrRegister = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_SPR0 + SPR_UGQR0 + gqrIndex);\n\t\tIMLReg loadTypeReg = PPCRecompilerImlGen_loadRegister(ppcImlGenContext, PPCREC_NAME_TEMPORARY + 0);\n\t\t// extract the load type from the GQR register\n\t\tppcImlGenContext->emitInst().make_r_r_s32(PPCREC_IML_OP_AND, loadTypeReg, gqrRegister, 0x7);\n\n\t\tIMLSegment* caseSegment[5];\n\t\tsint32 compareValues[5] = {0, 4, 5, 6, 7};\n\t\tPPCIMLGen_CreateSegmentBranchedPathMultiple(*ppcImlGenContext, *ppcImlGenContext->currentBasicBlock, caseSegment, loadTypeReg, compareValues, 5, 0);\n\t\tfor (sint32 i=0; i<5; i++)\n\t\t{\n\t\t\tIMLRedirectInstOutput outputToCase(ppcImlGenContext, caseSegment[i]); // while this is in scope, instructions go to caseSegment[i]\n\t\t\tPPCRecompilerImlGen_EmitPSQStoreCase(ppcImlGenContext, gqrIndex, static_cast<Espresso::PSQ_LOAD_TYPE>(compareValues[i]), storePS1, gprA, imm, fprDPS0, fprDPS1);\n\t\t\tppcImlGenContext->emitInst().make_jump(); // finalize case\n\t\t}\n\t\treturn true;\n\t}\n\n\tEspresso::PSQ_LOAD_TYPE type = static_cast<Espresso::PSQ_LOAD_TYPE>((gqrValue >> 0) & 0x7);\n\tsint32 scale = (gqrValue >> 24) & 0x3F;\n\tcemu_assert_debug(scale == 0); // known GQR values always use a scale of 0 (1.0f)\n\n\tif (type == Espresso::PSQ_LOAD_TYPE::TYPE_UNUSED1 ||\n\t\ttype == Espresso::PSQ_LOAD_TYPE::TYPE_UNUSED2 ||\n\t\ttype == Espresso::PSQ_LOAD_TYPE::TYPE_UNUSED3)\n\t{\n\t\treturn false;\n\t}\n\n\tPPCRecompilerImlGen_EmitPSQStoreCase(ppcImlGenContext, gqrIndex, type, storePS1, gprA, imm, fprDPS0, fprDPS1);\n\treturn true;\n}\n\n// PS_MULS0 and PS_MULS1\nbool PPCRecompilerImlGen_PS_MULSX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isVariant1)\n{\n\tsint32 frD, frA, frC;\n\tfrC = (opcode>>6)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprAps1, frA);\n\tDefinePSX(fprC, frC, isVariant1);\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\n\tDefineTempFPR(fprTmp0, 0);\n\tDefineTempFPR(fprTmp1, 1);\n\n\t// todo - optimize cases where a temporary is not necessary\n\t// todo - round fprC to 25bit accuracy\n\n\t// copy ps0 and ps1 to temporary\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTmp0, fprAps0);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTmp1, fprAps1);\n\n\t// multiply\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTmp0, fprC);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTmp1, fprC);\n\n\t// copy back to result\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprTmp0);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprTmp1);\n\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\n\treturn true;\n}\n\n// PS_MADDS0 and PS_MADDS1\nbool PPCRecompilerImlGen_PS_MADDSX(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool isVariant1)\n{\n\tsint32 frD, frA, frB, frC;\n\tfrC = (opcode>>6)&0x1F;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprAps1, frA);\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\tDefinePSX(fprC, frC, isVariant1);\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\n\tDefineTempFPR(fprTmp0, 0);\n\tDefineTempFPR(fprTmp1, 1);\n\n\t// todo - round C to 25bit\n\t// todo - optimize cases where a temporary is not necessary\n\n\t// copy ps0 and ps1 to temporary\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTmp0, fprAps0);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTmp1, fprAps1);\n\n\t// multiply\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTmp0, fprC);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTmp1, fprC);\n\n\t// add\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprTmp0, fprBps0);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprTmp1, fprBps1);\n\n\t// copy back to result\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprTmp0);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprTmp1);\n\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_ADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\t//hCPU->fpr[frD].fp0 = hCPU->fpr[frA].fp0 + hCPU->fpr[frB].fp0;\n\t//hCPU->fpr[frD].fp1 = hCPU->fpr[frA].fp1 + hCPU->fpr[frB].fp1;\n\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprAps1, frA);\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\n\tif( frD == frA )\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps0, fprBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps1, fprBps1);\n\t}\n\telse if( frD == frB )\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps0, fprAps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps1, fprAps1);\n\t}\n\telse\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprAps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprAps1);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps0, fprBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps1, fprBps1);\n\t}\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_SUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\t//hCPU->fpr[frD].fp0 = hCPU->fpr[frA].fp0 - hCPU->fpr[frB].fp0;\n\t//hCPU->fpr[frD].fp1 = hCPU->fpr[frA].fp1 - hCPU->fpr[frB].fp1;\n\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprAps1, frA);\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\n\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_SUB, fprDps0, fprAps0, fprBps0);\n\tppcImlGenContext->emitInst().make_fpr_r_r_r(PPCREC_IML_OP_FPR_SUB, fprDps1, fprAps1, fprBps1);\n\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_MUL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frC;\n\tfrC = (opcode >> 6) & 0x1F;\n\tfrA = (opcode >> 16) & 0x1F;\n\tfrD = (opcode >> 21) & 0x1F;\n\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprAps1, frA);\n\tDefinePS0(fprCps0, frC);\n\tDefinePS1(fprCps1, frC);\n\n\tDefineTempFPR(fprTemp0, 0);\n\tDefineTempFPR(fprTemp1, 1);\n\n\t// todo: Optimize for when a temporary isnt necessary\n\t// todo: Round to 25bit?\n\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp0, fprCps0);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp1, fprCps1);\n\tif (frD == frA)\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps0, fprTemp0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps1, fprTemp1);\n\t}\n\telse\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp0, fprAps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp1, fprAps1);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprTemp0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprTemp1);\n\t}\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_DIV(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tfrB = (opcode >> 11) & 0x1F;\n\tfrA = (opcode >> 16) & 0x1F;\n\tfrD = (opcode >> 21) & 0x1F;\n\t//hCPU->fpr[frD].fp0 = hCPU->fpr[frA].fp0 / hCPU->fpr[frB].fp0;\n\t//hCPU->fpr[frD].fp1 = hCPU->fpr[frA].fp1 / hCPU->fpr[frB].fp1;\n\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprAps1, frA);\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\n\tif (frD == frA)\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_DIVIDE, fprDps0, fprBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_DIVIDE, fprDps1, fprBps1);\n\t}\n\telse\n\t{\n\t\tDefineTempFPR(fprTemp0, 0);\n\t\tDefineTempFPR(fprTemp1, 1);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp0, fprAps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp1, fprAps1);\n\t\t// we divide temporary by frB\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_DIVIDE, fprTemp0, fprBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_DIVIDE, fprTemp1, fprBps1);\n\t\t// copy result to frD\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprTemp0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprTemp1);\n\t}\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_MADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tfrC = (opcode>>6)&0x1F;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\t//float s0 = (float)(hCPU->fpr[frA].fp0 * hCPU->fpr[frC].fp0 + hCPU->fpr[frB].fp0);\n\t//float s1 = (float)(hCPU->fpr[frA].fp1 * hCPU->fpr[frC].fp1 + hCPU->fpr[frB].fp1);\n\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprAps1, frA);\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\tDefinePS0(fprCps0, frC);\n\tDefinePS1(fprCps1, frC);\n\n\tif (frD != frA && frD != frB)\n\t{\n\t\tif (frD == frC)\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprCps0, fprAps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprCps1, fprAps1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprAps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprAps1);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps0, fprCps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps1, fprCps1);\n\t\t}\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps0, fprBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps1, fprBps1);\n\t}\n\telse\n\t{\n\t\tDefineTempFPR(fprTemp0, 0);\n\t\tDefineTempFPR(fprTemp1, 1);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp0, fprCps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp1, fprCps1);\n\t\tif( frD == frA && frD != frB )\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps0, fprTemp0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps1, fprTemp1);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps0, fprBps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps1, fprBps1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// we multiply temporary by frA\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp0, fprAps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp1, fprAps1);\n\t\t\t// add frB\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprTemp0, fprBps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprTemp1, fprBps1);\n\t\t\t// copy result to frD\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprTemp0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprTemp1);\n\t\t}\n\t}\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_NMADD(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tfrC = (opcode>>6)&0x1F;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprAps1, frA);\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\tDefinePS0(fprCps0, frC);\n\tDefinePS1(fprCps1, frC);\n\n\tDefineTempFPR(fprTemp0, 0);\n\tDefineTempFPR(fprTemp1, 1);\n\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp0, fprCps0);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp1, fprCps1);\n\t// todo-optimize: This instruction can be optimized so that it doesn't always use a temporary register\n\t// if frD == frA and frD != frB we can multiply frD immediately and save a copy instruction\n\tif( frD == frA && frD != frB )\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps0, fprTemp0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps1, fprTemp1);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps0, fprBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps1, fprBps1);\n\t}\n\telse\n\t{\n\t\t// we multiply temporary by frA\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp0, fprAps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp1, fprAps1);\n\t\t// add frB\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprTemp0, fprBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprTemp1, fprBps1);\n\t\t// copy result to frD\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprTemp0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprTemp1);\n\t}\n\n\t// negate\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATE, fprDps0);\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATE, fprDps1);\n\t// adjust accuracy\n\t//PPRecompilerImmGen_optionalRoundPairFPRToSinglePrecision(ppcImlGenContext, fprRegisterD);\n\t// Splatoon requires that we emulate flush-to-denormals for this instruction\n\t//ppcImlGenContext->emitInst().make_fpr_r(NULL,PPCREC_IML_OP_FPR_ROUND_FLDN_TO_SINGLE_PRECISION_PAIR, fprRegisterD, false);\n\treturn true;\n}\n\n// PS_MSUB and PS_NMSUB\nbool PPCRecompilerImlGen_PS_MSUB(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode, bool withNegative)\n{\n\tsint32 frD, frA, frB, frC;\n\tfrC = (opcode>>6)&0x1F;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprAps1, frA);\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\tDefinePS0(fprCps0, frC);\n\tDefinePS1(fprCps1, frC);\n\n\tif (frD != frA && frD != frB)\n\t{\n\t\tif (frD == frC)\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprCps0, fprAps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprCps1, fprAps1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprAps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprAps1);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps0, fprCps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps1, fprCps1);\n\t\t}\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprDps0, fprBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprDps1, fprBps1);\n\t}\n\telse\n\t{\n\t\tDefineTempFPR(fprTemp0, 0);\n\t\tDefineTempFPR(fprTemp1, 1);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp0, fprCps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprTemp1, fprCps1);\n\t\tif( frD == frA && frD != frB )\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps0, fprTemp0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprDps1, fprTemp1);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprDps0, fprBps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprDps1, fprBps1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp0, fprAps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_MULTIPLY, fprTemp1, fprAps1);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprTemp0, fprBps0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_SUB, fprTemp1, fprBps1);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprTemp0);\n\t\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprTemp1);\n\t\t}\n\t}\n\t// negate result\n\tif (withNegative)\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATE, fprDps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATE, fprDps1);\n\t}\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_SUM0(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tfrC = (opcode>>6)&0x1F;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprBps1, frB);\n\tDefinePS1(fprCps1, frC);\n\n\tif( frD == frA )\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps0, fprBps1);\n\t}\n\telse\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprAps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps0, fprBps1);\n\t}\n\tif (fprDps1 != fprCps1)\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprCps1);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_SUM1(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tfrC = (opcode>>6)&0x1F;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprBps1, frB);\n\tDefinePS0(fprCps0, frC);\n\n\tif (frB != frD)\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprAps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps1, fprBps1);\n\t}\n\telse\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ADD, fprDps1, fprAps0);\n\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprCps0);\n\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_NEG(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\n\tif (frB != frD)\n\t{\n\t\t// copy\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprBps1);\n\t}\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATE, fprDps0);\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_NEGATE, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_ABS(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprBps0);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprBps1);\n\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_ABS, fprDps0);\n\tppcImlGenContext->emitInst().make_fpr_r(PPCREC_IML_OP_FPR_ABS, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_RES(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\t//hCPU->fpr[frD].fp0 = (float)(1.0f / (float)hCPU->fpr[frB].fp0);\n\t//hCPU->fpr[frD].fp1 = (float)(1.0f / (float)hCPU->fpr[frB].fp1);\n\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\n\tppcImlGenContext->emitInst().make_call_imm((uintptr_t)fres_espresso, fprBps0, IMLREG_INVALID, IMLREG_INVALID, fprDps0);\n\tppcImlGenContext->emitInst().make_call_imm((uintptr_t)fres_espresso, fprBps1, IMLREG_INVALID, IMLREG_INVALID, fprDps1);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_RSQRTE(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\n\tppcImlGenContext->emitInst().make_call_imm((uintptr_t)frsqrte_espresso, fprBps0, IMLREG_INVALID, IMLREG_INVALID, fprDps0);\n\tppcImlGenContext->emitInst().make_call_imm((uintptr_t)frsqrte_espresso, fprBps1, IMLREG_INVALID, IMLREG_INVALID, fprDps1);\n\t// adjust accuracy\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps0);\n\tPPRecompilerImmGen_roundToSinglePrecision(ppcImlGenContext, fprDps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_MR(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\tif( frB != frD )\n\t{\n\t\tDefinePS0(fprBps0, frB);\n\t\tDefinePS1(fprBps1, frB);\n\t\tDefinePS0(fprDps0, frD);\n\t\tDefinePS1(fprDps1, frD);\n\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps0, fprBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, fprDps1, fprBps1);\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_SEL(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB, frC;\n\tfrC = (opcode>>6)&0x1F;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS0(fprAps0, frA);\n\tDefinePS1(fprAps1, frA);\n\tDefinePS0(fprBps0, frB);\n\tDefinePS1(fprBps1, frB);\n\tDefinePS0(fprCps0, frC);\n\tDefinePS1(fprCps1, frC);\n\tDefinePS0(fprDps0, frD);\n\tDefinePS1(fprDps1, frD);\n\n\tppcImlGenContext->emitInst().make_fpr_r_r_r_r(PPCREC_IML_OP_FPR_SELECT, fprDps0, fprAps0, fprBps0, fprCps0);\n\tppcImlGenContext->emitInst().make_fpr_r_r_r_r(PPCREC_IML_OP_FPR_SELECT, fprDps1, fprAps1, fprBps1, fprCps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_MERGE00(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\tDefinePS0(frpAps0, frA);\n\tDefinePS0(frpBps0, frB);\n\tDefinePS0(frpDps0, frD);\n\tDefinePS1(frpDps1, frD);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpDps1, frpBps0);\n\tif (frpDps0 != frpAps0)\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpDps0, frpAps0);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_MERGE01(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\tDefinePS0(frpAps0, frA);\n\tDefinePS1(frpBps1, frB);\n\tDefinePS0(frpDps0, frD);\n\tDefinePS1(frpDps1, frD);\n\n\tif (frpDps0 != frpAps0)\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpDps0, frpAps0);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpDps1, frpBps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_MERGE10(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS1(frpAps1, frA);\n\tDefinePS0(frpBps0, frB);\n\tDefinePS0(frpDps0, frD);\n\tDefinePS1(frpDps1, frD);\n\n\tif (frD != frB)\n\t{\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpDps0, frpAps1);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpDps1, frpBps0);\n\t}\n\telse\n\t{\n\t\tDefineTempFPR(frpTemp, 0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpTemp, frpBps0);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpDps0, frpAps1);\n\t\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpDps1, frpTemp);\n\t}\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_MERGE11(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 frD, frA, frB;\n\tfrB = (opcode>>11)&0x1F;\n\tfrA = (opcode>>16)&0x1F;\n\tfrD = (opcode>>21)&0x1F;\n\n\tDefinePS1(frpAps1, frA);\n\tDefinePS1(frpBps1, frB);\n\tDefinePS0(frpDps0, frD);\n\tDefinePS1(frpDps1, frD);\n\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpDps0, frpAps1);\n\tppcImlGenContext->emitInst().make_fpr_r_r(PPCREC_IML_OP_FPR_ASSIGN, frpDps1, frpBps1);\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_CMPO0(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\t// Not implemented\n\treturn false;\n}\n\nbool PPCRecompilerImlGen_PS_CMPU0(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 crfD, frA, frB;\n\tfrB = (opcode >> 11) & 0x1F;\n\tfrA = (opcode >> 16) & 0x1F;\n\tcrfD = (opcode >> 23) & 0x7;\n\n\tDefinePS0(fprA, frA);\n\tDefinePS0(fprB, frB);\n\n\tIMLReg crBitRegLT = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_LT);\n\tIMLReg crBitRegGT = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_GT);\n\tIMLReg crBitRegEQ = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_EQ);\n\tIMLReg crBitRegSO = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_SO);\n\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegLT, IMLCondition::UNORDERED_LT);\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegGT, IMLCondition::UNORDERED_GT);\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegEQ, IMLCondition::UNORDERED_EQ);\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegSO, IMLCondition::UNORDERED_U);\n\n\t// todo: set fpscr\n\treturn true;\n}\n\nbool PPCRecompilerImlGen_PS_CMPU1(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode)\n{\n\tsint32 crfD, frA, frB;\n\tfrB = (opcode >> 11) & 0x1F;\n\tfrA = (opcode >> 16) & 0x1F;\n\tcrfD = (opcode >> 23) & 0x7;\n\n\tDefinePS1(fprA, frA);\n\tDefinePS1(fprB, frB);\n\n\tIMLReg crBitRegLT = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_LT);\n\tIMLReg crBitRegGT = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_GT);\n\tIMLReg crBitRegEQ = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_EQ);\n\tIMLReg crBitRegSO = _GetRegCR(ppcImlGenContext, crfD, Espresso::CR_BIT::CR_BIT_INDEX_SO);\n\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegLT, IMLCondition::UNORDERED_LT);\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegGT, IMLCondition::UNORDERED_GT);\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegEQ, IMLCondition::UNORDERED_EQ);\n\tppcImlGenContext->emitInst().make_fpr_compare(fprA, fprB, crBitRegSO, IMLCondition::UNORDERED_U);\n\treturn true;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Espresso/Recompiler/PPCRecompilerIntermediate.cpp",
    "content": "#include \"PPCRecompiler.h\"\n#include \"PPCRecompilerIml.h\"\n\nvoid PPCRecompilerIML_isolateEnterableSegments(ppcImlGenContext_t* ppcImlGenContext)\n{\n\tsize_t initialSegmentCount = ppcImlGenContext->segmentList2.size();\n\tfor (size_t i = 0; i < initialSegmentCount; i++)\n\t{\n\t\tIMLSegment* imlSegment = ppcImlGenContext->segmentList2[i];\n\t\tif (imlSegment->list_prevSegments.empty() == false && imlSegment->isEnterable)\n\t\t{\n\t\t\t// spawn new segment at end\n\t\t\tPPCRecompilerIml_insertSegments(ppcImlGenContext, ppcImlGenContext->segmentList2.size(), 1);\n\t\t\tIMLSegment* entrySegment = ppcImlGenContext->segmentList2[ppcImlGenContext->segmentList2.size()-1];\n\t\t\tentrySegment->isEnterable = true;\n\t\t\tentrySegment->enterPPCAddress = imlSegment->enterPPCAddress;\n\t\t\t// create jump instruction\n\t\t\tPPCRecompiler_pushBackIMLInstructions(entrySegment, 0, 1);\n\t\t\tentrySegment->imlList.data()[0].make_jump();\n\t\t\tIMLSegment_SetLinkBranchTaken(entrySegment, imlSegment);\n\t\t\t// remove enterable flag from original segment\n\t\t\timlSegment->isEnterable = false;\n\t\t\timlSegment->enterPPCAddress = 0;\n\t\t}\n\t}\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Common/RegisterSerializer.cpp",
    "content": "#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Common/RegisterSerializer.h\"\n#include \"Common/FileStream.h\"\n\n#include <zstd.h>\n#include <zlib.h>\n\n// compression dictionary for pipeline Latte register data, initialized on boot\nZSTD_CDict* s_c_regDict{};\nZSTD_DDict* s_d_regDict{};\n\nstruct GPURegSerializerMapping\n{\n\tuint32 regAddr;\n\tuint32 regCount;\n};\n\nGPURegSerializerMapping g_gpuRegSerializerMapping_v1[] =\n{\n\t// tied to GPUCompactedRegisterState - DO NOT MODIFY\n\t// this list is based on the same list used internally by GX2ContextState, excluding ALU constants\n\t// Config register\n\t{0x2232, 0x2},\n\t{0x2235, 0x1},\n\t{0x223A, 0x1},\n\t{0x2256, 0x1},\n\t{0x22C8, 0x1},\n\t{0x2300, 0x6},\n\t{0x2310, 0xC},\n\t{0x2363, 0x1},\n\t{0x2404, 0x2},\n\t{0x2542, 0x1},\n\t{0x25C5, 0x1},\n\t{0x260C, 0x1},\n\t{0x2900, 0x48}, // sampler border color VS\n\t{0x2980, 0x48}, // sampler border color PS\n\t{0x2A00, 0x48}, // sampler border color GS\n\t// Context register\n\t{0xA000, 0x2},\n\t{0xA003, 0x3},\n\t{0xA00A, 0x4},\n\t{0xA010, 0x38}, // color buffer registers + others\n\t{0xA050, 0x34}, // SQ_ALU_CONST_BUFFER_SIZE_PS_0\n\t{0xA08C, 0x1},\n\t{0xA08E, 0x4},\n\t{0xA094, 0x40},\n\t{0xA0D5, 0x1},\n\t{0xA0E0, 0x20},\n\t{0xA100, 0x9},\n\t{0xA10C, 0x3},\n\t{0xA10F, 0x60}, // mostly PA_CL_VPORT_* registers\n\t{0xA185, 0xA},\n\t{0xA191, 0x27},\n\t{0xA1E0, 0x9},\n\t{0xA200, 0x1},\n\t{0xA202, 0x7},\n\t{0xA210, 0x29},\n\t{0xA250, 0x34},\n\t{0xA284, 0xC},\n\t{0xA290, 0x1},\n\t{0xA292, 0x2},\n\t{0xA29B, 0x1},\n\t{0xA2A1, 0x1},\n\t{0xA2A5, 0x1},\n\t{0xA2A8, 0x2},\n\t{0xA2AC, 0x3},\n\t{0xA2B4, 0x3},\n\t{0xA2B8, 0x3},\n\t{0xA2BC, 0x3},\n\t{0xA2C0, 0x3},\n\t{0xA2C8, 0x1},\n\t{0xA2CA, 0x1},\n\t{0xA2CC, 0x1},\n\t{0xA2CE, 0x1},\n\t{0xA300, 0x9},\n\t{0xA30C, 0x1},\n\t{0xA312, 0x1},\n\t{0xA316, 0x2},\n\t{0xA343, 0x2},\n\t{0xA349, 0x3},\n\t{0xA34C, 0x2},\n\t{0xA351, 0x1},\n\t{0xA37E, 0x6},\n\t// Resource registers\n\t{0xE000, 0x70},\n\t{0xE380, 0x70},\n\t{0xE460, 0x70},\n\t{0xE7E0, 0x70},\n\t{0xE8B9, 0x7},\n\t{0xE8C0, 0x70},\n\t{0xE930, 0x70},\n\t{0xECB0, 0x70},\n\t{0xED89, 0x7},\n\t// Sampler registers\n\t{0xF000, 0x36},\n\t{0xF036, 0x36},\n\t{0xF06C, 0x36},\n\t// Loop const registers\n\t{0xF880, 0x60}\n};\n\nnamespace Latte\n{\n\tvoid StoreGPURegisterState(const LatteContextRegister& contextRegister, GPUCompactedRegisterState& registerStateOut)\n\t{\n\t\tuint32* regView = contextRegister.GetRawView();\n\t\t// read mapped registers into linear array\n\t\tuint32* writePtr = registerStateOut.rawArray;\n\t\tfor (auto& itr : g_gpuRegSerializerMapping_v1)\n\t\t{\n\t\t\tuint32* readPtr = contextRegister.GetRawView() + itr.regAddr;\n\t\t\tfor (uint32 i = 0; i < itr.regCount; i++)\n\t\t\t{\n\t\t\t\t*writePtr = *readPtr;\n\t\t\t\treadPtr++;\n\t\t\t\twritePtr++;\n\t\t\t}\n\t\t}\n\t\tuint32 numStoredRegs = (uint32)(writePtr - registerStateOut.rawArray);\n\t\tcemu_assert(numStoredRegs * 4 == sizeof(registerStateOut.rawArray));\n\t}\n\n\tvoid LoadGPURegisterState(LatteContextRegister& contextRegisterOut, const GPUCompactedRegisterState& registerState)\n\t{\n\t\tuint32* regView = contextRegisterOut.GetRawView();\n\t\t// read mapped registers into linear array\n\t\tconst uint32* readPtr = registerState.rawArray;\n\t\tfor (auto& itr : g_gpuRegSerializerMapping_v1)\n\t\t{\n\t\t\tuint32* writePtr = contextRegisterOut.GetRawView() + itr.regAddr;\n\t\t\tfor (uint32 i = 0; i < itr.regCount; i++)\n\t\t\t{\n\t\t\t\t*writePtr = *readPtr;\n\t\t\t\twritePtr++;\n\t\t\t\treadPtr++;\n\t\t\t}\n\t\t}\n\t\tuint32 numStoredRegs = (uint32)(readPtr - registerState.rawArray);\n\t\tcemu_assert(numStoredRegs * 4 == sizeof(registerState.rawArray));\n\t}\n\n\t// register data is mostly zero words\n\t// this very simple RLE compression will collapse all the zero-byte ranges giving a pretty substantial compression ratio on its own\n\t// we can then further use zstd-dictionary compression on it to end up with ultra compact serialized data (50-300 bytes)\n\tvoid _CompressZeros(uint32* regArray, uint32 regCount, MemStreamWriter& memWriter)\n\t{\n\t\tuint32 index = 0;\n\t\tuint8 numZeroWords = 0;\n\t\twhile (index < regCount)\n\t\t{\n\t\t\tif (regArray[index] == 0)\n\t\t\t{\n\t\t\t\tnumZeroWords++;\n\t\t\t\tif (numZeroWords == 0x7F)\n\t\t\t\t{\n\t\t\t\t\tmemWriter.writeBE<uint8>(0x80 | numZeroWords);\n\t\t\t\t\tnumZeroWords = 0;\n\t\t\t\t}\n\t\t\t\tindex++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (numZeroWords != 0)\n\t\t\t{\n\t\t\t\tmemWriter.writeBE<uint8>(0x80 | numZeroWords);\n\t\t\t\tnumZeroWords = 0;\n\t\t\t}\n\t\t\t// count how many set words follow\n\t\t\tuint32 tempIndex = index + 1;\n\t\t\tuint32 scanEnd = std::min(index + 0x7F, regCount);\n\t\t\twhile (tempIndex < scanEnd)\n\t\t\t{\n\t\t\t\tif (regArray[tempIndex] == 0)\n\t\t\t\t\tbreak;\n\t\t\t\ttempIndex++;\n\t\t\t}\n\t\t\tuint32 numSetWords = tempIndex - index;\n\t\t\tmemWriter.writeBE<uint8>((uint8)numSetWords);\n\t\t\t// store word data\n\t\t\twhile (index < tempIndex)\n\t\t\t{\n\t\t\t\tmemWriter.writeBE<uint32>(regArray[index]);\n\t\t\t\tindex++;\n\t\t\t}\n\t\t}\n\t\tif (numZeroWords != 0)\n\t\t\tmemWriter.writeBE<uint8>(0x80 | numZeroWords);\n\t}\n\n\tbool _UncompressZeros(uint32* regArray, uint32 regCount, MemStreamReader& memReader)\n\t{\n\t\tuint32 index = 0;\n\t\twhile (index < regCount)\n\t\t{\n\t\t\tuint8 pattern = memReader.readBE<uint8>();\n\t\t\tuint8 count = pattern & 0x7F;\n\t\t\tif (count == 0)\n\t\t\t\treturn false;\n\t\t\tif ((index + count) > regCount)\n\t\t\t\treturn false;\n\t\t\tif (pattern & 0x80)\n\t\t\t{\n\t\t\t\t// zero words\n\t\t\t\twhile (count--)\n\t\t\t\t{\n\t\t\t\t\tregArray[index] = 0;\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// data words\n\t\t\t\twhile (count--)\n\t\t\t\t{\n\t\t\t\t\tregArray[index] = memReader.readBE<uint32>();\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn !memReader.hasError() && memReader.isEndOfStream();\n\t}\n\n\tvoid SerializeRegisterState(GPUCompactedRegisterState& regState, MemStreamWriter& memWriter)\n\t{\n\t\t// convert regState into a platform independent representation in memory (we use a big-endian array)\n\t\tuint32be regArray[GPUCompactedRegisterState::NUM_REGS];\n\t\tfor (uint32 i = 0; i < GPUCompactedRegisterState::NUM_REGS; i++)\n\t\t\tregArray[i] = regState.rawArray[i];\n\t\t// first, use simple RLE-style compression to get a more compact data representation\n\t\tMemStreamWriter tmpBufferWriter(1024 * 4);\n\t\t_CompressZeros(regState.rawArray, GPUCompactedRegisterState::NUM_REGS, tmpBufferWriter);\n\t\tauto rleCompressedData = tmpBufferWriter.getResult();\n\t\t// second, compress using dictionary trained for RLE compressed register state\n\t\tuint8 buffer[8 * 1024];\n\t\tZSTD_CCtx* const cctx = ZSTD_createCCtx();\n\t\tsize_t compressedSize = ZSTD_compress_usingCDict(cctx, buffer, sizeof(buffer), rleCompressedData.data(), rleCompressedData.size(), s_c_regDict);\n\t\tZSTD_freeCCtx(cctx);\n\t\tcemu_assert(!ZSTD_isError(compressedSize));\n\t\t// serialize\n\t\tmemWriter.writeBE<uint8>(0x01); // version\n\t\tmemWriter.writeBE<uint16>((uint16)compressedSize);\n\t\tmemWriter.writeData(buffer, compressedSize);\n\t}\n\n\tbool DeserializeRegisterState(GPUCompactedRegisterState& regState, MemStreamReader& memReader)\n\t{\n\t\tif (memReader.readBE<uint8>() != 1)\n\t\t\treturn false; // unknown version\n\t\t// read compressed register data into buffer\n\t\tuint8 buffer[8 * 1024];\n\t\tuint16 compressedSize = memReader.readBE<uint16>();\n\t\tif (compressedSize >= sizeof(buffer))\n\t\t\treturn false;\n\t\tmemReader.readData(buffer, compressedSize);\n\t\tif (memReader.hasError())\n\t\t\treturn false;\n\t\t// decompress using zstd with dictionary\n\t\tuint8 rleDataBuffer[8 * 1024];\n\t\tZSTD_DCtx* const dctx = ZSTD_createDCtx();\n\t\tsize_t rleDecompressedSize = ZSTD_decompress_usingDDict(dctx, rleDataBuffer, sizeof(rleDataBuffer), buffer, compressedSize, s_d_regDict);\n\t\tZSTD_freeDCtx(dctx);\n\t\tif (rleDecompressedSize == 0 || rleDecompressedSize > sizeof(rleDataBuffer))\n\t\t\treturn false;\n\t\t// decompress RLE\n\t\tMemStreamReader rleReader(rleDataBuffer, (sint32)rleDecompressedSize);\n\t\tif (!_UncompressZeros(regState.rawArray, GPUCompactedRegisterState::NUM_REGS, rleReader))\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\tvoid UnitTestPipelineSerialization()\n\t{\n\t\tGPUCompactedRegisterState inputState{};\n\t\tGPUCompactedRegisterState outputState{};\n\t\tfor (int i = 0; i < inputState.NUM_REGS; i++)\n\t\t{\n\t\t\tif ((0x1037778e >> ((i / 3) & 31)) & 1)\n\t\t\t\tinputState.rawArray[i] = i + i * 17 + i * 23;\n\t\t\telse\n\t\t\t\tinputState.rawArray[i] = 0;\n\t\t}\n\t\t// serialize and deserialize\n\t\tMemStreamWriter writer(1024 * 8);\n\t\tSerializeRegisterState(inputState, writer);\n\t\tauto writerRes = writer.getResult();\n\t\tMemStreamReader reader(writerRes.data(), (sint32)writerRes.size());\n\t\tbool r = DeserializeRegisterState(outputState, reader);\n\t\tcemu_assert_debug(r);\n\t\tcemu_assert_debug(memcmp(&inputState, &outputState, sizeof(GPUCompactedRegisterState)) == 0);\n\t}\n}\n\nextern const uint8 s_regDataDict[];\n\nRunAtCemuBoot _loadPipelineCompressionDictionary([]()\n{\n\t// decompress and load dict\n\tstatic std::vector<uint8> s_dictData;\n\ts_dictData.resize(0x1B800);\n\tZSTD_decompress(s_dictData.data(), s_dictData.size(), s_regDataDict, 0x5AD2);\n\ts_c_regDict = ZSTD_createCDict(s_dictData.data(), s_dictData.size(), 9);\n\ts_d_regDict = ZSTD_createDDict(s_dictData.data(), s_dictData.size());\n\tcemu_assert_debug(s_c_regDict);\n\tcemu_assert_debug(s_d_regDict);\n\n\tLatte::UnitTestPipelineSerialization();\n});\n\nconst uint8 s_regDataDict[] = // 0x5AD2 Uncompressed: 0x1B800\n{\n\t0x28, 0xB5, 0x2F, 0xFD, 0xA4, 0x00, 0xB8, 0x01, 0x00, 0x15, 0xD6, 0x02,\n\t0xFA, 0x09, 0x2B, 0xA7, 0x4C, 0x10, 0x10, 0x4A, 0xE9, 0xB4, 0x06, 0xCA,\n\t0xEB, 0xF5, 0x42, 0x3A, 0x7D, 0x5B, 0xF2, 0x57, 0x32, 0x13, 0x5C, 0x42,\n\t0x9E, 0xFD, 0xC4, 0x0B, 0x41, 0xFD, 0xB8, 0x0E, 0xBF, 0x59, 0x28, 0xC3,\n\t0x3A, 0xFA, 0x93, 0x0C, 0xC1, 0xA1, 0x65, 0x6E, 0x85, 0x63, 0x6E, 0xC6,\n\t0x1A, 0x1B, 0xB7, 0xDD, 0x75, 0xCC, 0x29, 0xFE, 0x4F, 0x86, 0xAC, 0x64,\n\t0x09, 0x23, 0xA1, 0xC4, 0x54, 0xD5, 0xCC, 0xA2, 0x7A, 0xA0, 0xCA, 0x6C,\n\t0x23, 0xE2, 0xA2, 0x26, 0xB4, 0xC9, 0xDE, 0x5B, 0xA6, 0xEB, 0x09, 0x53,\n\t0x0A, 0x9B, 0x0A, 0x60, 0xA6, 0x5E, 0xCB, 0xDE, 0x0F, 0x53, 0xEF, 0xE5,\n\t0x90, 0xC2, 0x18, 0x63, 0xB3, 0x4C, 0xCD, 0x5E, 0x99, 0x9A, 0x79, 0x0D,\n\t0x4C, 0x68, 0x82, 0x5C, 0xE8, 0x90, 0x49, 0x0B, 0xB7, 0x8C, 0x7B, 0x49,\n\t0x73, 0x65, 0xE1, 0x42, 0x43, 0xD5, 0xC4, 0x9F, 0x8B, 0xDA, 0xA7, 0x35,\n\t0x08, 0x83, 0x6E, 0xA8, 0x52, 0x17, 0xD3, 0x31, 0x07, 0xB9, 0x0C, 0x2E,\n\t0x24, 0x4F, 0x71, 0xD5, 0x7B, 0xA7, 0xA4, 0x5F, 0xD4, 0xC8, 0x0D, 0x21,\n\t0x1D, 0x98, 0xD7, 0x8E, 0xB9, 0xD1, 0x77, 0xFF, 0xE6, 0xFA, 0x4E, 0xEF,\n\t0x9D, 0x3D, 0xFE, 0xD6, 0xF2, 0xC4, 0x1F, 0xC3, 0xB8, 0x87, 0xE7, 0x08,\n\t0xC6, 0x8C, 0xDD, 0xE3, 0xE2, 0x83, 0x99, 0xE5, 0xFD, 0xEF, 0x96, 0xEA,\n\t0xCF, 0x65, 0xFC, 0x21, 0xFA, 0xA6, 0x4D, 0xE8, 0xC3, 0x78, 0xDA, 0x6A,\n\t0x9C, 0x48, 0x65, 0x5A, 0x96, 0x21, 0x51, 0xD2, 0x93, 0xE6, 0xFE, 0x7A,\n\t0x25, 0x28, 0xA1, 0x71, 0x35, 0xF0, 0xD8, 0x30, 0xE4, 0xC8, 0x43, 0x11,\n\t0xB7, 0x21, 0x56, 0x2C, 0xEF, 0x0D, 0x25, 0x28, 0xA5, 0x4A, 0x86, 0x20,\n\t0xD2, 0x01, 0x69, 0xDA, 0x4B, 0x82, 0xA2, 0xF9, 0x40, 0x13, 0xFA, 0x64,\n\t0x14, 0xEE, 0x2B, 0x6C, 0xB8, 0xA9, 0x30, 0x36, 0xC1, 0x38, 0x1B, 0x33,\n\t0x4C, 0xDC, 0x5D, 0x20, 0x1F, 0xF0, 0x23, 0x3B, 0x32, 0x13, 0xDB, 0xAD,\n\t0x30, 0x71, 0x9B, 0xA4, 0x32, 0x9A, 0xF8, 0x4C, 0xD1, 0xC4, 0x3E, 0xCE,\n\t0xA0, 0xF6, 0x11, 0x03, 0x4A, 0xEF, 0x9B, 0x38, 0x9E, 0x96, 0x7A, 0xCC,\n\t0xA7, 0xE4, 0xF2, 0x25, 0x72, 0x39, 0x96, 0xA6, 0xE5, 0x5B, 0x3C, 0x94,\n\t0xEF, 0x69, 0x2A, 0x5F, 0x4E, 0xB6, 0x43, 0xD3, 0x64, 0x6D, 0x9A, 0x56,\n\t0xD9, 0x35, 0x15, 0x79, 0xF1, 0x22, 0xDB, 0xAB, 0x30, 0x22, 0xEB, 0x32,\n\t0xBF, 0xAC, 0x97, 0x5A, 0x7F, 0x43, 0x21, 0x9F, 0xE2, 0x9F, 0x95, 0x12,\n\t0x35, 0xEC, 0x5F, 0xB9, 0x7F, 0x0D, 0x47, 0xB8, 0x92, 0xA8, 0x66, 0xCC,\n\t0x47, 0x1A, 0x3E, 0x53, 0x4C, 0x38, 0x95, 0xC0, 0x5D, 0x3B, 0xA6, 0x21,\n\t0x21, 0x0A, 0x5E, 0xF2, 0xE9, 0x04, 0x3D, 0xEB, 0x45, 0x4E, 0x8A, 0xC9,\n\t0xD7, 0x3F, 0xD3, 0xE4, 0xA4, 0x52, 0x14, 0x54, 0x23, 0x7A, 0x5C, 0x37,\n\t0xB4, 0x75, 0x7D, 0xFF, 0x13, 0x90, 0xE0, 0x42, 0x5F, 0x0C, 0x7F, 0xA8,\n\t0x03, 0xE1, 0xC4, 0xF2, 0x4E, 0x10, 0x03, 0xAD, 0xF2, 0xE8, 0x5A, 0x9C,\n\t0xF4, 0xDD, 0x2A, 0x2F, 0x22, 0x41, 0xE8, 0xDC, 0x4D, 0xF8, 0xC3, 0x76,\n\t0x59, 0xB2, 0x01, 0xB3, 0x44, 0xF9, 0xC2, 0x75, 0x50, 0xF0, 0xEF, 0x60,\n\t0x95, 0x3E, 0xF7, 0xD9, 0x3C, 0x60, 0x39, 0x32, 0xFD, 0xFB, 0xF3, 0xB4,\n\t0xB0, 0x26, 0xBB, 0xC2, 0xD2, 0xCB, 0xE2, 0xE6, 0xEA, 0x2C, 0x6A, 0xAE,\n\t0x6E, 0xD1, 0xB4, 0x3F, 0x24, 0x0B, 0x20, 0x38, 0xDA, 0x02, 0x1E, 0x47,\n\t0xFF, 0xEC, 0xE1, 0x61, 0xF4, 0x9E, 0x31, 0xA3, 0xDB, 0x60, 0xFB, 0xB7,\n\t0x7C, 0x5B, 0x22, 0xF5, 0x9B, 0x07, 0x52, 0x3F, 0x3D, 0x50, 0xFA, 0x99,\n\t0x44, 0x29, 0x55, 0x62, 0x75, 0x9A, 0xC4, 0x0A, 0x8B, 0x03, 0x4A, 0xCB,\n\t0x01, 0xA2, 0xF4, 0xDD, 0xA3, 0x61, 0x3A, 0x9B, 0x17, 0x1C, 0x6F, 0xD3,\n\t0xD1, 0xD8, 0x05, 0xA0, 0x68, 0x3B, 0xB6, 0xA2, 0x83, 0x1A, 0x30, 0x3A,\n\t0xE9, 0xE0, 0x01, 0xEC, 0x4A, 0x9E, 0x4E, 0x03, 0x06, 0x6F, 0x80, 0x39,\n\t0x19, 0xD9, 0xCC, 0x15, 0x64, 0xB7, 0xED, 0x8D, 0x06, 0x09, 0x8B, 0x0E,\n\t0xE3, 0x70, 0x84, 0x6B, 0x20, 0xA1, 0x2F, 0x30, 0x43, 0x43, 0xDD, 0x77,\n\t0x72, 0xA6, 0xE7, 0xB8, 0xFA, 0x22, 0x45, 0xA3, 0x85, 0x55, 0xA0, 0x10,\n\t0xD1, 0x28, 0x14, 0x14, 0x64, 0xBC, 0xFD, 0xA2, 0xED, 0xCB, 0xA0, 0xDB,\n\t0x75, 0xDA, 0x80, 0x06, 0xCD, 0x8B, 0x9F, 0x02, 0x64, 0x79, 0xA1, 0x42,\n\t0x01, 0xFA, 0x87, 0xCE, 0xBB, 0xA6, 0x78, 0x7C, 0x42, 0x3B, 0xB9, 0x30,\n\t0xB6, 0x9D, 0x33, 0x66, 0x73, 0x61, 0x23, 0x64, 0x63, 0x47, 0xDF, 0x6B,\n\t0x12, 0x33, 0xF9, 0x1C, 0x8F, 0xE8, 0xE8, 0x77, 0xEA, 0x33, 0xF3, 0x48,\n\t0x40, 0x91, 0xBE, 0x39, 0x75, 0x82, 0x47, 0xC6, 0x17, 0xCE, 0x02, 0x62,\n\t0x3F, 0x78, 0x64, 0xA0, 0x3A, 0xD2, 0x37, 0x31, 0x74, 0x93, 0x16, 0xBE,\n\t0x2A, 0x7C, 0xF4, 0x69, 0x07, 0xC5, 0xCF, 0x3A, 0x28, 0x06, 0x72, 0x7B,\n\t0x3B, 0xB2, 0x67, 0x92, 0xA1, 0x7A, 0xCA, 0xB6, 0x94, 0x69, 0x38, 0x9C,\n\t0xE8, 0xED, 0xEA, 0xF1, 0x02, 0xC5, 0xD2, 0x41, 0x36, 0x8C, 0x47, 0xE8,\n\t0xE8, 0x2B, 0x7A, 0x50, 0x4E, 0x05, 0xB6, 0xED, 0xB7, 0x6D, 0xCD, 0xFC,\n\t0x66, 0x40, 0x58, 0xD6, 0x9B, 0x97, 0xB2, 0xF9, 0x81, 0x2E, 0x11, 0xE3,\n\t0x01, 0x39, 0x7A, 0xE4, 0xB3, 0xA0, 0xBE, 0xD9, 0x58, 0x3F, 0x54, 0x8E,\n\t0xCE, 0xE9, 0x7B, 0x1B, 0x9F, 0xF6, 0x2C, 0x7F, 0x83, 0x4B, 0x8F, 0x2B,\n\t0x09, 0xB2, 0xBB, 0xB0, 0x71, 0xA2, 0xBB, 0x81, 0x84, 0x53, 0x09, 0xE4,\n\t0xE1, 0xF4, 0xB7, 0x62, 0x8E, 0xF8, 0x9A, 0x00, 0xDC, 0x08, 0x4D, 0xC3,\n\t0x18, 0x37, 0xC8, 0x53, 0xA0, 0x89, 0xA9, 0x0A, 0x6C, 0x2F, 0xFA, 0x9A,\n\t0x2A, 0x49, 0x09, 0x3A, 0x51, 0xE0, 0x2D, 0x73, 0x45, 0x02, 0xD6, 0x54,\n\t0xF2, 0x7B, 0x4F, 0x4B, 0xDF, 0x49, 0x39, 0xC2, 0xFB, 0xD6, 0xB4, 0x3A,\n\t0xA0, 0x1E, 0x5D, 0x95, 0x5C, 0x17, 0x74, 0x53, 0x0D, 0xC8, 0xE4, 0x92,\n\t0x12, 0x49, 0x2D, 0x03, 0x5E, 0x6F, 0x05, 0x22, 0xAF, 0x74, 0x07, 0x39,\n\t0x16, 0x51, 0xB7, 0xBD, 0x22, 0x13, 0x78, 0x60, 0x15, 0x66, 0x10, 0xAE,\n\t0xB9, 0x44, 0xC0, 0xB5, 0xC6, 0xC4, 0xBA, 0xF9, 0x02, 0x6B, 0x3A, 0x37,\n\t0x55, 0xEB, 0x4D, 0x60, 0xE3, 0x4D, 0xD5, 0xC6, 0x21, 0x5E, 0x0F, 0xF9,\n\t0x40, 0xD0, 0x9A, 0x4E, 0x4C, 0xD6, 0xC9, 0x35, 0x5B, 0x8F, 0xC3, 0xD6,\n\t0x42, 0x30, 0x20, 0xB0, 0x4E, 0xB2, 0x21, 0xCC, 0xB8, 0x82, 0xD3, 0x41,\n\t0xA3, 0x1D, 0xAC, 0xD7, 0xDA, 0x64, 0x01, 0x19, 0xB1, 0xFA, 0x80, 0x33,\n\t0x94, 0xDE, 0x16, 0x70, 0x4E, 0x74, 0x56, 0x6D, 0x28, 0xC6, 0xD2, 0xFD,\n\t0xA2, 0x35, 0x89, 0x7A, 0x9C, 0x50, 0x4E, 0x0E, 0x49, 0xDB, 0xC6, 0x9D,\n\t0xC9, 0x49, 0xE2, 0x45, 0xDB, 0xA7, 0xCF, 0x8B, 0x21, 0x5C, 0x90, 0x4A,\n\t0xD0, 0x17, 0x2F, 0xB8, 0x9A, 0x6A, 0x23, 0xCC, 0x06, 0x9D, 0x5F, 0x9C,\n\t0xF6, 0xDB, 0xDC, 0x72, 0xC0, 0xC9, 0xFB, 0x1B, 0x22, 0x8F, 0xA6, 0x81,\n\t0x1D, 0x14, 0x6D, 0x0D, 0xCC, 0x81, 0x1A, 0x53, 0x06, 0xAA, 0x81, 0x96,\n\t0x08, 0xF4, 0x51, 0x23, 0x6D, 0x17, 0x18, 0xCB, 0xBB, 0x98, 0xC9, 0x29,\n\t0x5B, 0x2E, 0x67, 0x8C, 0x8B, 0xEB, 0x47, 0x17, 0x07, 0xB2, 0xEE, 0x02,\n\t0x24, 0xEB, 0x22, 0x26, 0x8F, 0xE0, 0x50, 0x0A, 0xB6, 0x73, 0xC8, 0x1D,\n\t0x14, 0xEC, 0x40, 0xE7, 0xCD, 0x7B, 0x8D, 0xB7, 0xBF, 0x78, 0x83, 0x8C,\n\t0x99, 0xDE, 0xA6, 0x81, 0xD5, 0x43, 0x85, 0x85, 0x09, 0xF7, 0x80, 0x85,\n\t0x11, 0x91, 0x73, 0x11, 0x94, 0xB2, 0x5C, 0xB6, 0x33, 0x99, 0x61, 0xC5,\n\t0x9D, 0x02, 0xE0, 0x82, 0x69, 0xC4, 0xC5, 0x41, 0x62, 0x7F, 0x42, 0x77,\n\t0x68, 0x87, 0xA7, 0x99, 0x20, 0xD9, 0x54, 0xF4, 0x78, 0x85, 0xBC, 0x2D,\n\t0x45, 0x8F, 0x26, 0xA4, 0x6E, 0x83, 0x40, 0x2D, 0x47, 0xF8, 0x10, 0xDB,\n\t0xF8, 0xCC, 0x24, 0x46, 0x68, 0x01, 0xBC, 0x64, 0x48, 0x9C, 0xE9, 0x5D,\n\t0x4D, 0x8A, 0xB8, 0xD0, 0x13, 0x5C, 0x7B, 0xBD, 0x20, 0xC0, 0xBD, 0x39,\n\t0xDD, 0xE6, 0xE4, 0xEE, 0x07, 0xE5, 0xDC, 0xDE, 0xE0, 0x5A, 0xB9, 0x39,\n\t0xB7, 0x16, 0x0D, 0x06, 0xCD, 0xFC, 0x9A, 0x99, 0x93, 0x65, 0xC5, 0xD6,\n\t0x23, 0x42, 0x3F, 0x4A, 0x45, 0x4D, 0x83, 0x3F, 0xD0, 0x79, 0x51, 0x3C,\n\t0x36, 0x08, 0xA6, 0xCE, 0xE6, 0x47, 0xDC, 0x3D, 0x69, 0xE7, 0x74, 0x3C,\n\t0x7C, 0x96, 0xB8, 0x57, 0x4F, 0xAB, 0xAE, 0x40, 0xFC, 0xE3, 0xB0, 0xED,\n\t0x67, 0xD3, 0x41, 0x00, 0xB6, 0x5A, 0x74, 0x08, 0x25, 0x30, 0x84, 0x63,\n\t0xC7, 0xE5, 0x06, 0x58, 0x60, 0xAC, 0xE0, 0x60, 0x0B, 0x4D, 0x7B, 0xD9,\n\t0xD1, 0x8F, 0x1D, 0x35, 0x6B, 0x1C, 0xDD, 0xA4, 0x71, 0x74, 0x7B, 0xB7,\n\t0xEE, 0x2C, 0xD9, 0xFF, 0xF9, 0x2C, 0x9E, 0x12, 0x9E, 0x0A, 0xC5, 0xC1,\n\t0xD6, 0x0F, 0xBA, 0xBC, 0x9F, 0x74, 0xAE, 0x77, 0x0E, 0x56, 0x0F, 0x29,\n\t0x98, 0xE8, 0x6F, 0xAD, 0x0B, 0x4D, 0x09, 0xBE, 0xCA, 0x05, 0xBF, 0x40,\n\t0x54, 0x4D, 0xD7, 0x3C, 0x32, 0xE1, 0x7F, 0xCB, 0xB0, 0xB3, 0x69, 0x58,\n\t0x22, 0x13, 0x57, 0x37, 0x15, 0xEE, 0x02, 0xFD, 0x14, 0x1F, 0xA1, 0x8B,\n\t0x7C, 0xD2, 0xE5, 0x3C, 0x80, 0xB1, 0x91, 0x4A, 0xDF, 0x76, 0x5E, 0x7D,\n\t0x6B, 0x12, 0x16, 0x72, 0x89, 0xDD, 0x2C, 0xA1, 0x2B, 0x0E, 0xCF, 0xBB,\n\t0xD6, 0x8F, 0x67, 0x2E, 0x20, 0xC4, 0x54, 0x2A, 0xE6, 0xAA, 0x49, 0xB1,\n\t0x5A, 0x12, 0x39, 0x04, 0x7C, 0x43, 0xF3, 0x08, 0x87, 0x42, 0xA8, 0xA8,\n\t0xF8, 0x50, 0x83, 0x60, 0x88, 0x24, 0x32, 0xF4, 0xD1, 0xFC, 0xE5, 0xFE,\n\t0x6B, 0xDC, 0x17, 0x0E, 0x48, 0x05, 0x28, 0xA7, 0x8E, 0xA6, 0x6C, 0x8B,\n\t0x87, 0x79, 0x37, 0xC1, 0xEA, 0x7C, 0xF4, 0x76, 0xAD, 0xCE, 0xFF, 0xEC,\n\t0x51, 0x06, 0x33, 0xEE, 0x92, 0x10, 0xD0, 0x01, 0x6B, 0xDB, 0x80, 0x40,\n\t0x5A, 0x3A, 0x72, 0x10, 0xB9, 0x2B, 0x28, 0x1F, 0x72, 0xC5, 0x83, 0x73,\n\t0xE1, 0x6C, 0x73, 0x72, 0xF7, 0x11, 0x23, 0x33, 0xF0, 0xA8, 0x4F, 0x74,\n\t0x34, 0xD2, 0xEE, 0x5F, 0x80, 0xB5, 0x19, 0xA8, 0x9D, 0xF6, 0x0A, 0x7F,\n\t0x6E, 0xD1, 0x84, 0xE3, 0x77, 0x7B, 0xC7, 0x62, 0xCA, 0xE0, 0xEF, 0xC4,\n\t0x01, 0xCC, 0xB6, 0xEF, 0x2F, 0xF5, 0x1F, 0x4E, 0x78, 0xFE, 0xC4, 0xD6,\n\t0xE0, 0x5C, 0xBC, 0xBC, 0x4F, 0x9C, 0x84, 0x05, 0xC8, 0xFE, 0x41, 0x07,\n\t0xD9, 0x4A, 0xA0, 0x2A, 0x5A, 0x8A, 0xA9, 0x9D, 0xD9, 0x96, 0xF0, 0x3B,\n\t0x19, 0x6C, 0x73, 0xDB, 0xF0, 0x29, 0x82, 0x49, 0x85, 0xCC, 0xA9, 0x9A,\n\t0xF4, 0x26, 0x3E, 0xB9, 0x38, 0x93, 0x2F, 0x5F, 0x6F, 0x22, 0x2D, 0x6F,\n\t0x45, 0xC2, 0x36, 0x32, 0x79, 0x08, 0x3B, 0x6A, 0xA3, 0x22, 0x11, 0xDE,\n\t0x2A, 0x68, 0x9C, 0xE9, 0x3A, 0xB4, 0xA0, 0x31, 0x10, 0xEE, 0x85, 0x17,\n\t0x18, 0xA7, 0x02, 0x8F, 0xBA, 0x70, 0xE9, 0x17, 0x41, 0xA9, 0xFB, 0x80,\n\t0x8E, 0x49, 0x11, 0x68, 0x38, 0x31, 0xEE, 0xCD, 0x48, 0xDB, 0x5E, 0x62,\n\t0xDB, 0x0E, 0xBF, 0x6D, 0xFA, 0x26, 0xAE, 0xCC, 0xF3, 0x95, 0x01, 0x8D,\n\t0x6C, 0xA3, 0x8C, 0x8C, 0xEB, 0x04, 0x42, 0x9F, 0x04, 0x01, 0x01, 0x83,\n\t0xF2, 0x9E, 0xA9, 0x09, 0x95, 0x8D, 0x5A, 0x91, 0x51, 0x78, 0x99, 0xC4,\n\t0xFD, 0xEC, 0xC0, 0xEF, 0xB2, 0x64, 0xFC, 0x32, 0x28, 0xD2, 0xF6, 0x15,\n\t0x73, 0xF7, 0xC6, 0x94, 0x4B, 0x0E, 0xDD, 0x2A, 0x44, 0xFF, 0x85, 0xA3,\n\t0xA1, 0x3D, 0xA6, 0x68, 0x5A, 0x27, 0xAC, 0x0B, 0xFE, 0xC3, 0x87, 0x45,\n\t0xD7, 0x0F, 0xF6, 0x61, 0x8F, 0x40, 0x14, 0xCA, 0x4C, 0xDB, 0x16, 0x9B,\n\t0x5D, 0x76, 0x77, 0x15, 0x3F, 0x9B, 0x01, 0x78, 0x48, 0x7D, 0x6F, 0x91,\n\t0x7E, 0x87, 0x95, 0x24, 0x30, 0x52, 0x36, 0x48, 0x17, 0x58, 0x35, 0x9E,\n\t0x60, 0x10, 0xD5, 0xC6, 0x03, 0x08, 0xA8, 0xD1, 0x9F, 0x81, 0x39, 0x50,\n\t0x28, 0xDF, 0xB5, 0xE3, 0x03, 0x7A, 0xD0, 0xAE, 0x77, 0x69, 0xF9, 0x55,\n\t0x3A, 0xC8, 0x95, 0xB4, 0x9C, 0xEB, 0x68, 0x79, 0xF1, 0xD6, 0xCF, 0x6E,\n\t0x8D, 0xC8, 0xB2, 0xF1, 0x4B, 0x3A, 0x91, 0x49, 0x19, 0x8D, 0x8D, 0x8B,\n\t0xE5, 0xAC, 0x71, 0x81, 0xC6, 0x49, 0xCD, 0x0C, 0x2E, 0xCC, 0x34, 0xC1,\n\t0x56, 0x03, 0xD2, 0x0D, 0x21, 0xC0, 0xD8, 0x6D, 0xAB, 0x1C, 0x1E, 0x15,\n\t0x90, 0x99, 0x21, 0xD2, 0x82, 0xB7, 0xC6, 0x6F, 0xA0, 0x9F, 0x0D, 0xF3,\n\t0xE9, 0x47, 0x26, 0x2C, 0x4C, 0x01, 0x2D, 0x37, 0xE7, 0x54, 0x77, 0xB2,\n\t0x04, 0xEE, 0x05, 0xFA, 0x41, 0x34, 0xA7, 0x88, 0x5B, 0x13, 0xA6, 0xFF,\n\t0x6A, 0x44, 0xBD, 0xE9, 0x3A, 0x71, 0xF8, 0x0A, 0x1C, 0xBD, 0xC2, 0x61,\n\t0xDB, 0xDE, 0x14, 0xBD, 0xAA, 0x1A, 0x8F, 0x17, 0x1B, 0x54, 0x10, 0x43,\n\t0xDC, 0xA7, 0xAD, 0x19, 0x00, 0xDF, 0xF2, 0xD0, 0x5D, 0xEB, 0x3F, 0xEB,\n\t0x21, 0x66, 0x24, 0xFA, 0x2C, 0x04, 0x31, 0xBC, 0xBC, 0xBF, 0x47, 0xC1,\n\t0x9A, 0x30, 0x1A, 0x40, 0x24, 0xD3, 0xB8, 0x3B, 0xA3, 0x1D, 0x00, 0x88,\n\t0x24, 0x13, 0x89, 0x36, 0x8A, 0x7D, 0xAD, 0xA6, 0xFF, 0x4D, 0x1B, 0x95,\n\t0x2E, 0x49, 0xFB, 0x05, 0x21, 0x28, 0x98, 0x38, 0x57, 0x6A, 0x0C, 0x59,\n\t0x9B, 0x0B, 0x0A, 0xB0, 0x18, 0x53, 0x07, 0x79, 0x27, 0xB0, 0x7B, 0x31,\n\t0x4A, 0x56, 0x23, 0x78, 0x86, 0x95, 0xBC, 0x32, 0xB4, 0xC1, 0x9A, 0x16,\n\t0x4B, 0x10, 0xC8, 0x90, 0xB5, 0xE8, 0x90, 0x18, 0x48, 0x24, 0x06, 0x40,\n\t0x16, 0xE7, 0xBF, 0x08, 0x1E, 0x5A, 0xAC, 0x4E, 0xE4, 0xF0, 0xA7, 0xB1,\n\t0xA6, 0x05, 0xFA, 0xE4, 0xBE, 0x3A, 0x8B, 0x64, 0xEC, 0xA2, 0x28, 0x2D,\n\t0xB0, 0x9F, 0x74, 0xE2, 0x68, 0x39, 0xBC, 0x7C, 0x34, 0x65, 0xF0, 0xEF,\n\t0x12, 0xC5, 0x5D, 0xA7, 0x1F, 0x17, 0xDF, 0x7D, 0xD1, 0x10, 0xF9, 0x07,\n\t0x5C, 0xF7, 0x92, 0x68, 0x71, 0xFB, 0xCF, 0x4E, 0x34, 0xEA, 0x29, 0x37,\n\t0x9E, 0x51, 0xDE, 0xA6, 0xEB, 0x39, 0x05, 0xFD, 0x8B, 0x61, 0xB8, 0x60,\n\t0x31, 0x72, 0x2F, 0x55, 0x23, 0x06, 0xFF, 0x0E, 0x0A, 0x8E, 0xBA, 0x6D,\n\t0xDD, 0x2C, 0x53, 0xE1, 0xB6, 0xE4, 0x66, 0xA2, 0x8A, 0x7F, 0x6F, 0x95,\n\t0x90, 0xC2, 0xED, 0xDE, 0x45, 0xA2, 0x90, 0x7F, 0xC1, 0x22, 0x3E, 0x34,\n\t0x3B, 0xDC, 0x80, 0x9D, 0xBE, 0xDA, 0xD0, 0x49, 0x03, 0xF9, 0xEE, 0xDF,\n\t0x5C, 0xB1, 0x35, 0x97, 0xA4, 0x0A, 0x2F, 0xD7, 0xCD, 0x38, 0xB5, 0x6C,\n\t0x2F, 0xF8, 0x76, 0xCE, 0x0A, 0x7F, 0xA4, 0xA0, 0xF9, 0xAD, 0xC0, 0x9B,\n\t0x70, 0x42, 0xFA, 0x53, 0xE5, 0x44, 0x19, 0x0D, 0xF1, 0x11, 0x36, 0x2E,\n\t0xD9, 0xDA, 0x06, 0x0C, 0x15, 0x6E, 0xCB, 0x88, 0x66, 0xA2, 0xDA, 0xFE,\n\t0x90, 0x72, 0x72, 0x2B, 0x5D, 0x9D, 0x0A, 0x33, 0x5B, 0x72, 0xC4, 0xAE,\n\t0x21, 0x17, 0xFF, 0x68, 0x43, 0x17, 0xED, 0x34, 0xE8, 0x60, 0x58, 0xAE,\n\t0xFC, 0x4D, 0xAD, 0xC9, 0x1F, 0x26, 0xD0, 0xEF, 0x07, 0xEE, 0x60, 0x4E,\n\t0x35, 0xFE, 0x88, 0x86, 0xFF, 0x74, 0x66, 0x94, 0xD3, 0xE5, 0x29, 0x6F,\n\t0xEF, 0x7A, 0x4E, 0x2F, 0xF4, 0xAC, 0xDC, 0x6A, 0x1C, 0x01, 0x85, 0x5B,\n\t0x39, 0xAB, 0x45, 0x2D, 0xFF, 0x8A, 0x45, 0xCE, 0xDD, 0xE4, 0x56, 0x3B,\n\t0x16, 0x5A, 0x5C, 0x7C, 0xD6, 0x29, 0x65, 0x9B, 0xEF, 0xD9, 0xD5, 0x39,\n\t0x9B, 0xFC, 0xD1, 0xA2, 0x42, 0x8B, 0x91, 0xAF, 0x3A, 0x15, 0xFF, 0x52,\n\t0x20, 0x09, 0x33, 0x8E, 0x31, 0x26, 0x6C, 0xF5, 0x07, 0xFB, 0xD7, 0x29,\n\t0xC2, 0x85, 0x5F, 0x2E, 0xED, 0x65, 0x72, 0x27, 0xBE, 0x80, 0x4A, 0xAD,\n\t0x22, 0x59, 0x6F, 0x07, 0x41, 0x18, 0x70, 0x0E, 0xFF, 0x37, 0x5E, 0xC2,\n\t0x1B, 0x14, 0xC4, 0x06, 0xBE, 0x91, 0xA1, 0x54, 0x1B, 0xFF, 0x47, 0xF3,\n\t0x8A, 0x7F, 0x15, 0xA8, 0x46, 0x09, 0xC1, 0xA9, 0x5F, 0x74, 0x9D, 0xC2,\n\t0xFF, 0x3E, 0x31, 0x16, 0x85, 0x84, 0x41, 0x35, 0x05, 0x7E, 0xFF, 0x27,\n\t0xAE, 0x08, 0x6C, 0xDB, 0x76, 0x75, 0x4D, 0xD3, 0x3C, 0xB2, 0x7F, 0x59,\n\t0x74, 0x52, 0x14, 0x0A, 0xFA, 0x21, 0x1E, 0xFC, 0xD7, 0x7F, 0x28, 0x74,\n\t0x5E, 0x20, 0x3C, 0xE6, 0xCC, 0x8B, 0x27, 0x11, 0x11, 0x3A, 0x85, 0x47,\n\t0x4E, 0xBA, 0xD3, 0x77, 0x9D, 0x1B, 0xB6, 0x36, 0x6B, 0x5A, 0x04, 0xF9,\n\t0xFC, 0xF5, 0xA0, 0x35, 0xF3, 0x2F, 0x55, 0x10, 0xF2, 0xB4, 0x47, 0xB6,\n\t0xEE, 0xBF, 0xBF, 0xCA, 0xA1, 0x2A, 0x70, 0x45, 0xDD, 0xBC, 0x2C, 0x7B,\n\t0x17, 0xCA, 0x7C, 0xD2, 0x6C, 0x75, 0xFE, 0xEC, 0x52, 0xFD, 0x5B, 0xA1,\n\t0x1D, 0x7A, 0x7F, 0x34, 0x6F, 0xA0, 0x1E, 0xFA, 0xB3, 0xC5, 0xF6, 0x57,\n\t0x6D, 0xB0, 0xE0, 0x0A, 0x26, 0xA2, 0x11, 0x99, 0x18, 0xDC, 0xFB, 0xF5,\n\t0xF9, 0x40, 0xBB, 0x57, 0xD9, 0x4F, 0x9B, 0x8F, 0x32, 0xFF, 0x26, 0xBF,\n\t0x28, 0xB7, 0x13, 0x07, 0xCA, 0x66, 0x7B, 0x72, 0x69, 0x31, 0x18, 0x19,\n\t0xFC, 0x86, 0x6E, 0xCF, 0x2E, 0xAF, 0x53, 0x08, 0xD5, 0xF7, 0x3A, 0x3A,\n\t0xEA, 0x76, 0x85, 0xCF, 0xDE, 0x97, 0xAF, 0x75, 0xAA, 0xFF, 0x85, 0xCB,\n\t0xD2, 0x7E, 0x24, 0x43, 0xD3, 0x37, 0x18, 0x9A, 0xC0, 0x09, 0xAD, 0x54,\n\t0xD2, 0x23, 0x48, 0x67, 0xDD, 0x64, 0x07, 0xCD, 0x1E, 0x7D, 0x40, 0x1F,\n\t0xF2, 0x29, 0x7E, 0xAC, 0x43, 0x7F, 0xF6, 0x85, 0xAE, 0x3B, 0x9A, 0xA1,\n\t0x46, 0x3B, 0x6D, 0xF3, 0x5B, 0xAC, 0x67, 0xF2, 0x9D, 0x38, 0xA6, 0x4F,\n\t0xEE, 0x51, 0xDA, 0x47, 0xE0, 0x42, 0x52, 0xA4, 0x3B, 0x1E, 0x3B, 0x4D,\n\t0xC2, 0x22, 0x90, 0xDF, 0x09, 0x2A, 0x31, 0xBF, 0x05, 0xAA, 0x09, 0x1E,\n\t0xCD, 0x98, 0x9C, 0xD8, 0x9F, 0x67, 0x4F, 0x34, 0xDD, 0xFC, 0x38, 0xC2,\n\t0x67, 0xD6, 0x39, 0x71, 0x4C, 0x3E, 0x13, 0xE3, 0x8F, 0x67, 0x26, 0xA9,\n\t0xBE, 0xFD, 0x1D, 0xA9, 0xFE, 0x9A, 0x10, 0x19, 0x20, 0xA5, 0x4F, 0xFE,\n\t0x67, 0xD7, 0xD1, 0x86, 0x14, 0xAE, 0x93, 0xC9, 0x77, 0x84, 0xEA, 0x5D,\n\t0x89, 0x91, 0x05, 0xA6, 0x96, 0x0C, 0x50, 0x86, 0x08, 0x26, 0x3E, 0xFC,\n\t0x41, 0xC6, 0xEA, 0x7A, 0xC8, 0x25, 0x8D, 0xC5, 0x28, 0xDA, 0x32, 0x03,\n\t0xC4, 0xA4, 0xC1, 0xC4, 0x19, 0x5E, 0x19, 0xB2, 0x1F, 0x23, 0xD6, 0x59,\n\t0x17, 0x3A, 0x65, 0xDE, 0x66, 0x08, 0xC6, 0x25, 0x09, 0xA6, 0x6F, 0x32,\n\t0x98, 0xB1, 0xEA, 0x1C, 0xC0, 0x70, 0x80, 0x09, 0xA8, 0x33, 0xE6, 0x4E,\n\t0x38, 0x20, 0xE3, 0xAB, 0x97, 0x2A, 0x28, 0x47, 0x8C, 0xC1, 0x83, 0xC1,\n\t0x0B, 0x2D, 0x7C, 0x29, 0x51, 0xE2, 0x4B, 0x8F, 0x27, 0x15, 0x14, 0x30,\n\t0x3A, 0xE0, 0xE5, 0x83, 0x0D, 0xB6, 0x98, 0xD8, 0x50, 0xE4, 0x49, 0x65,\n\t0x22, 0xEB, 0x80, 0x0A, 0x8E, 0x72, 0x5E, 0x8C, 0x65, 0x68, 0x44, 0xC5,\n\t0x31, 0x91, 0x03, 0x95, 0xA1, 0x0D, 0x23, 0x5E, 0x38, 0x7A, 0x18, 0x50,\n\t0x36, 0xBC, 0x21, 0x6C, 0xCB, 0xC8, 0xF5, 0x36, 0x25, 0x01, 0x12, 0x21,\n\t0xB4, 0x29, 0xB5, 0xCC, 0xD8, 0x9C, 0xB8, 0x4E, 0xC8, 0x02, 0x33, 0x9E,\n\t0xF9, 0x48, 0xB2, 0x60, 0x87, 0x21, 0xB6, 0x46, 0xF8, 0x0A, 0x4A, 0xDB,\n\t0x05, 0x41, 0xBD, 0xD7, 0x26, 0xF5, 0x1E, 0x07, 0x52, 0xB7, 0x5F, 0xFD,\n\t0x78, 0x36, 0x1D, 0x54, 0xD9, 0xFD, 0xA0, 0x88, 0x6A, 0xC8, 0x60, 0x28,\n\t0xF9, 0x5A, 0x46, 0x9B, 0x18, 0x1A, 0x25, 0xF8, 0x1D, 0x06, 0x5B, 0xF4,\n\t0xBE, 0x2C, 0x5A, 0x11, 0x42, 0x5A, 0x83, 0xE6, 0xEC, 0x43, 0xF7, 0xF6,\n\t0x7B, 0x65, 0x06, 0x7D, 0x6F, 0xFF, 0xAD, 0xA7, 0x06, 0x43, 0xA8, 0x50,\n\t0x88, 0xAC, 0x0F, 0x22, 0xEB, 0x67, 0xD5, 0xA1, 0x38, 0xE8, 0x2A, 0x7E,\n\t0xA8, 0x0D, 0xA5, 0x51, 0x36, 0xEE, 0x5D, 0xBD, 0x53, 0x36, 0x12, 0x3C,\n\t0x72, 0x81, 0xFF, 0x90, 0x22, 0x7C, 0x6E, 0x9D, 0xF8, 0x0B, 0xD5, 0x74,\n\t0xF6, 0x56, 0xE8, 0xD9, 0xB4, 0xB0, 0xB1, 0x94, 0x00, 0xCB, 0x3D, 0x26,\n\t0x8E, 0xDA, 0x8E, 0xA2, 0xB7, 0xE7, 0x86, 0xEB, 0xA8, 0x31, 0x5A, 0xFD,\n\t0xE1, 0xD8, 0x18, 0xA1, 0x7C, 0x0F, 0x18, 0x21, 0xA2, 0xD2, 0xF6, 0xA8,\n\t0xC2, 0xE2, 0x1E, 0x54, 0x58, 0xBC, 0x97, 0x17, 0x85, 0x05, 0x1A, 0x11,\n\t0x9E, 0xB4, 0x58, 0x4C, 0xC5, 0x62, 0x3B, 0x25, 0x8B, 0xEB, 0xA4, 0x35,\n\t0xC0, 0x1C, 0x9F, 0x22, 0x84, 0x09, 0x13, 0x22, 0x88, 0xD1, 0x1F, 0xBC,\n\t0xBA, 0xC0, 0xC6, 0x2B, 0x3B, 0x1B, 0x8F, 0xEC, 0xB4, 0x8E, 0xCE, 0x81,\n\t0xB3, 0x83, 0x83, 0xF1, 0xF9, 0x41, 0xB6, 0x22, 0xD0, 0x42, 0xCD, 0x6C,\n\t0xAC, 0x25, 0xD3, 0xE1, 0x6C, 0x32, 0x36, 0x67, 0xEF, 0xE6, 0x6C, 0x3D,\n\t0x3B, 0x9C, 0x4D, 0x4C, 0xA2, 0x0A, 0x90, 0x9D, 0x07, 0x37, 0x76, 0x5E,\n\t0x91, 0xB1, 0xB7, 0xF4, 0x66, 0xF0, 0x2B, 0xC2, 0x82, 0xCA, 0xF9, 0x80,\n\t0xB4, 0x1A, 0x1D, 0xA4, 0xB5, 0x66, 0xBB, 0x41, 0x07, 0x18, 0x59, 0xB0,\n\t0x13, 0x5C, 0x1E, 0x35, 0x84, 0x21, 0x51, 0xD1, 0xD0, 0xAF, 0x20, 0x4E,\n\t0xC9, 0x75, 0xD5, 0x28, 0x20, 0xE1, 0x11, 0x61, 0x9B, 0xB6, 0x2D, 0xDA,\n\t0xAA, 0x3F, 0x45, 0x98, 0xA2, 0xA7, 0x7A, 0x68, 0x41, 0x31, 0x6B, 0xC1,\n\t0x83, 0x74, 0x13, 0xC5, 0x12, 0xED, 0xE8, 0x7B, 0xEF, 0xF1, 0x12, 0x96,\n\t0x82, 0x51, 0xB5, 0xF0, 0xC9, 0xA0, 0x07, 0xA4, 0xE6, 0xD2, 0x6A, 0x40,\n\t0x32, 0x35, 0xAC, 0x33, 0xF1, 0x6A, 0x30, 0x23, 0x40, 0x0D, 0x5D, 0x6F,\n\t0x59, 0x41, 0xE7, 0xBE, 0x42, 0xD6, 0xEF, 0x0C, 0x8C, 0xDF, 0x97, 0xA8,\n\t0xEE, 0xAF, 0x7B, 0x24, 0xB4, 0x3B, 0x1B, 0xF4, 0xA6, 0x62, 0xF6, 0x6E,\n\t0x34, 0xBE, 0x66, 0x01, 0x41, 0xC2, 0x0B, 0x5C, 0x3F, 0xE0, 0x08, 0x8B,\n\t0x23, 0x70, 0x22, 0x68, 0xD0, 0x8E, 0x6A, 0x90, 0x7A, 0x8A, 0x04, 0x89,\n\t0x18, 0xDA, 0xB6, 0xA9, 0xF3, 0xAE, 0x6F, 0x2A, 0xFE, 0x62, 0x98, 0x7A,\n\t0xBD, 0xED, 0x8A, 0x31, 0x89, 0xEC, 0xF0, 0x4E, 0x58, 0x83, 0x55, 0xF1,\n\t0x3F, 0x02, 0x1F, 0xB8, 0x9A, 0xAF, 0xF5, 0xB3, 0x10, 0xF8, 0xC0, 0xE5,\n\t0x02, 0x89, 0x3B, 0x1D, 0xE0, 0xC8, 0xF3, 0x0F, 0x11, 0xC0, 0x18, 0x3D,\n\t0x80, 0xCD, 0x13, 0xA6, 0x04, 0x58, 0x33, 0x7D, 0x94, 0x61, 0x00, 0xEB,\n\t0x32, 0x39, 0xEC, 0xE6, 0xEC, 0xA0, 0x64, 0x63, 0xB5, 0xB2, 0x06, 0xAB,\n\t0x9B, 0x7A, 0xAC, 0x6E, 0xBE, 0x45, 0x2D, 0xFD, 0x06, 0xB5, 0x34, 0x4C,\n\t0x06, 0x61, 0xB5, 0xDD, 0x1D, 0xAB, 0x85, 0x18, 0xCC, 0x9A, 0xE2, 0xEF,\n\t0xE6, 0x9E, 0xF4, 0x86, 0xD2, 0xA4, 0xE5, 0x92, 0x1C, 0xC0, 0x18, 0xA5,\n\t0x63, 0x93, 0x3C, 0x8D, 0x7C, 0x13, 0x49, 0x6F, 0x6C, 0x5D, 0xC5, 0xDD,\n\t0xD2, 0xF7, 0xE1, 0x64, 0xEB, 0x1A, 0x08, 0xB7, 0x75, 0xD5, 0x1B, 0x04,\n\t0x97, 0x12, 0xFF, 0x89, 0x53, 0x89, 0xB7, 0x57, 0x88, 0xA6, 0x44, 0xA1,\n\t0x8B, 0xA6, 0x6E, 0x42, 0xB4, 0x13, 0x30, 0x56, 0xA2, 0xB9, 0xB0, 0xCF,\n\t0xAA, 0xB5, 0x48, 0xE9, 0x9D, 0x3C, 0x27, 0xA1, 0x7C, 0x20, 0x8C, 0xE9,\n\t0x5B, 0xD3, 0x5A, 0x41, 0xDA, 0x2E, 0x04, 0x24, 0xA1, 0x18, 0x4E, 0xEA,\n\t0x61, 0xE4, 0x44, 0xEF, 0x62, 0x7A, 0x52, 0x44, 0xD6, 0xDE, 0xEB, 0xA4,\n\t0x5E, 0xD5, 0x49, 0x08, 0xCA, 0x0A, 0x7A, 0x87, 0x1E, 0x9D, 0xBB, 0xE8,\n\t0x6C, 0x0E, 0x65, 0x3F, 0x96, 0x9B, 0x87, 0x40, 0xBA, 0x77, 0x95, 0x54,\n\t0x30, 0x8A, 0xA6, 0x3A, 0xDD, 0x96, 0x33, 0x02, 0x69, 0x2B, 0x63, 0xFA,\n\t0x5E, 0xC1, 0x70, 0xD0, 0xF7, 0xAA, 0xA7, 0x5D, 0x81, 0x60, 0x4A, 0xAC,\n\t0x50, 0x82, 0x0A, 0x97, 0x30, 0xF6, 0x8B, 0xF7, 0x89, 0x74, 0xB9, 0xE0,\n\t0xAC, 0x38, 0x35, 0xE5, 0xC7, 0xEB, 0x59, 0x07, 0xC4, 0x2C, 0x6D, 0xA9,\n\t0x00, 0xCD, 0x71, 0xF2, 0x91, 0x0F, 0x39, 0x7A, 0x46, 0x19, 0x1F, 0x06,\n\t0xFA, 0x4C, 0xA5, 0xDC, 0xD4, 0x58, 0x04, 0x98, 0x5A, 0xE3, 0x43, 0xB1,\n\t0x08, 0x1F, 0x1F, 0x8E, 0xEA, 0x52, 0xC5, 0xC5, 0xAC, 0x85, 0x1E, 0xC6,\n\t0x06, 0x2A, 0x71, 0xE0, 0x48, 0x9B, 0x6C, 0xAD, 0x4E, 0x1A, 0x61, 0xF5,\n\t0xF6, 0x36, 0x1D, 0x0F, 0xA6, 0xA6, 0xA3, 0x64, 0x4A, 0xC9, 0x44, 0xB4,\n\t0xD2, 0x88, 0xE8, 0x16, 0xF5, 0xE1, 0xC2, 0x71, 0x3A, 0x26, 0x1C, 0x07,\n\t0x82, 0x5E, 0x69, 0x4A, 0xD1, 0x41, 0x72, 0x34, 0x1D, 0xB9, 0x14, 0x40,\n\t0x60, 0xD1, 0x6D, 0xB0, 0x6D, 0xB3, 0x6C, 0x16, 0x50, 0xB4, 0x0C, 0x4D,\n\t0x06, 0x8A, 0xA6, 0x72, 0x47, 0x13, 0xB5, 0x4C, 0x0A, 0x5A, 0xE3, 0x60,\n\t0x4B, 0x49, 0xDF, 0xD4, 0xBA, 0x5A, 0x93, 0x3D, 0x77, 0xA9, 0x28, 0x7B,\n\t0x8C, 0x4B, 0x19, 0xAE, 0xC0, 0xDB, 0x32, 0x65, 0x53, 0x84, 0xAB, 0xDB,\n\t0x7A, 0x4F, 0x6F, 0x50, 0x8D, 0x6E, 0x46, 0x35, 0x18, 0xA3, 0xA1, 0x19,\n\t0x03, 0xC1, 0x8F, 0x09, 0xDD, 0x51, 0x65, 0xDA, 0xFB, 0x2F, 0x59, 0x4F,\n\t0x17, 0x00, 0x1E, 0x50, 0x64, 0x49, 0x42, 0xE9, 0xDA, 0xE8, 0x44, 0xC8,\n\t0x25, 0x19, 0x23, 0xC5, 0x49, 0x0A, 0xB8, 0xE6, 0x9B, 0x80, 0xCB, 0x86,\n\t0x96, 0xAE, 0x99, 0x25, 0x74, 0x6D, 0x43, 0x0A, 0x6B, 0x1B, 0x41, 0x68,\n\t0x7D, 0xE5, 0xB4, 0x10, 0xCD, 0xCF, 0x46, 0x0F, 0x28, 0x7E, 0xF2, 0x80,\n\t0x42, 0x98, 0x81, 0xFA, 0x52, 0xC7, 0x06, 0x64, 0x08, 0x6C, 0x00, 0x43,\n\t0x4A, 0x12, 0x24, 0x46, 0xE2, 0xE2, 0x8C, 0x04, 0x8F, 0x54, 0x01, 0xA6,\n\t0x1D, 0x01, 0xD5, 0xEC, 0x83, 0x0A, 0x80, 0xEA, 0x64, 0xDC, 0x03, 0x85,\n\t0x44, 0x75, 0x42, 0x8D, 0x68, 0xDF, 0x22, 0x9A, 0x4B, 0xEA, 0x3D, 0xDD,\n\t0xCC, 0x90, 0xD3, 0x19, 0xE5, 0x92, 0x1F, 0x39, 0xF1, 0x96, 0x40, 0x61,\n\t0x46, 0x08, 0xF2, 0xB2, 0x09, 0x90, 0x97, 0x8D, 0x25, 0x2F, 0x5B, 0x26,\n\t0x47, 0xEF, 0x9A, 0x46, 0xC3, 0x34, 0xCD, 0xBE, 0xD0, 0x34, 0x73, 0x0B,\n\t0xFA, 0x34, 0x9D, 0x13, 0x7F, 0xB9, 0xCD, 0x89, 0xB3, 0xA0, 0x36, 0x86,\n\t0xD6, 0x27, 0x8E, 0x84, 0xE8, 0xA4, 0x89, 0x98, 0x08, 0xAD, 0x60, 0x04,\n\t0xB3, 0xD7, 0xE7, 0x06, 0x6A, 0x84, 0x3F, 0x0C, 0x85, 0xE2, 0x4D, 0x15,\n\t0x92, 0xFF, 0xA0, 0x2B, 0xA4, 0x08, 0x2F, 0xF0, 0x16, 0x4D, 0xD5, 0x95,\n\t0x2D, 0x53, 0x43, 0x50, 0xD1, 0x51, 0x60, 0xDA, 0xE2, 0xDB, 0xBC, 0x49,\n\t0xCE, 0x8C, 0x93, 0xDC, 0x08, 0x95, 0x64, 0xB6, 0xE4, 0xB3, 0x9C, 0x0B,\n\t0x72, 0xD6, 0x69, 0x89, 0xF9, 0x8B, 0x44, 0x5E, 0x3A, 0x4A, 0x17, 0x61,\n\t0x58, 0x78, 0xF6, 0xBA, 0x82, 0x23, 0x09, 0x05, 0x00, 0x84, 0x47, 0x53,\n\t0x88, 0xD3, 0x18, 0x28, 0xC0, 0x7D, 0xE6, 0x02, 0x55, 0x62, 0x69, 0xC1,\n\t0x7F, 0xE2, 0xA8, 0x12, 0x4B, 0xC1, 0xCA, 0x9B, 0x15, 0x25, 0x14, 0x06,\n\t0x19, 0x36, 0x4E, 0xF5, 0x0E, 0x14, 0xF2, 0x49, 0x0E, 0x4A, 0xA3, 0x51,\n\t0x08, 0x50, 0x4D, 0xEC, 0x32, 0x80, 0xF2, 0x21, 0xDF, 0x01, 0x54, 0xCF,\n\t0x23, 0x8A, 0x6E, 0xA7, 0x2E, 0x8A, 0xD2, 0x5B, 0x72, 0x3A, 0xC2, 0x8E,\n\t0x5C, 0x9B, 0xE4, 0x38, 0x84, 0x40, 0x5E, 0xE6, 0x0E, 0xF2, 0x2C, 0x4A,\n\t0x19, 0x9A, 0xDE, 0x13, 0x81, 0x83, 0x2B, 0x36, 0xCB, 0x19, 0xC3, 0xC4,\n\t0x26, 0x40, 0xD3, 0x6C, 0x0C, 0x4D, 0xB7, 0x3D, 0x40, 0xD3, 0xC3, 0x68,\n\t0xFA, 0x61, 0x00, 0xA2, 0xE2, 0xE2, 0x7F, 0xD7, 0xB9, 0xD1, 0xDB, 0xA1,\n\t0xEB, 0xF6, 0xF5, 0x33, 0xB4, 0xE9, 0x63, 0xF9, 0x96, 0x91, 0x14, 0xF7,\n\t0xD9, 0xBB, 0xBB, 0x33, 0x2C, 0x6D, 0x6B, 0x40, 0xA6, 0x09, 0x43, 0x17,\n\t0x93, 0xD0, 0x31, 0x92, 0x92, 0x08, 0x77, 0xA2, 0x4C, 0x92, 0xC0, 0xAF,\n\t0xA8, 0x93, 0xD8, 0xE7, 0x14, 0x78, 0xA1, 0x10, 0x85, 0x68, 0x8F, 0xFF,\n\t0x66, 0xF7, 0x69, 0x02, 0x50, 0x7F, 0x1A, 0x90, 0x65, 0x28, 0xAD, 0x6B,\n\t0xAD, 0x7C, 0xB9, 0xB2, 0x72, 0x4F, 0x08, 0x8C, 0x13, 0xEE, 0x4C, 0xCE,\n\t0x83, 0x4D, 0xDE, 0xFE, 0x19, 0x23, 0x51, 0x09, 0xAA, 0x6F, 0x1C, 0x41,\n\t0x25, 0x14, 0x17, 0x27, 0x08, 0x98, 0x25, 0xE3, 0xD0, 0x59, 0x41, 0xD5,\n\t0x3C, 0x86, 0x54, 0xFD, 0x57, 0xA7, 0x28, 0xB8, 0x0C, 0xAB, 0xD2, 0x28,\n\t0x45, 0x17, 0x2A, 0x23, 0x33, 0x2F, 0x46, 0x6C, 0xCC, 0xDE, 0x07, 0xCE,\n\t0xB1, 0x6E, 0x6D, 0x7B, 0xD7, 0xCA, 0xBC, 0x0E, 0x65, 0x4E, 0x96, 0x6D,\n\t0x21, 0x54, 0x2C, 0x3E, 0x84, 0x43, 0xAD, 0x08, 0xD5, 0x3C, 0xB4, 0x74,\n\t0xEF, 0x0A, 0xA7, 0x6B, 0x0B, 0xD2, 0x02, 0xC8, 0x1A, 0x5C, 0x98, 0x43,\n\t0x6B, 0x49, 0x77, 0x57, 0x42, 0x40, 0x08, 0x31, 0xB4, 0x76, 0xC0, 0x11,\n\t0x23, 0x96, 0x83, 0x87, 0x13, 0x81, 0x2E, 0x5C, 0x3B, 0x70, 0x75, 0xC9,\n\t0x61, 0x48, 0x9B, 0xE5, 0x43, 0x74, 0xB8, 0x79, 0xD8, 0x2C, 0xCF, 0x83,\n\t0x83, 0x16, 0x14, 0x8A, 0xBD, 0x57, 0x3A, 0xFD, 0x08, 0x5D, 0x6A, 0x98,\n\t0x15, 0xD3, 0x84, 0x89, 0x41, 0xAB, 0xC7, 0x10, 0x3C, 0x2A, 0xE6, 0x78,\n\t0x53, 0x5C, 0x7D, 0x96, 0xB7, 0x0F, 0x69, 0xC1, 0x7C, 0x88, 0xD8, 0x90,\n\t0x18, 0xF3, 0x21, 0x16, 0x6B, 0x97, 0x30, 0xE6, 0x5D, 0xC0, 0x98, 0xB7,\n\t0x17, 0x8B, 0x73, 0x8D, 0x79, 0x9B, 0x56, 0x12, 0xA1, 0x9C, 0x21, 0xC4,\n\t0x73, 0xF8, 0x30, 0x24, 0x0B, 0x9A, 0x1C, 0x55, 0x40, 0x01, 0x05, 0xEE,\n\t0xCA, 0xA2, 0x50, 0x35, 0xEC, 0xA5, 0xFB, 0x48, 0xFF, 0x19, 0x23, 0xCF,\n\t0x12, 0x0E, 0xA5, 0x3B, 0x11, 0x19, 0x24, 0x9C, 0xE1, 0xB1, 0x41, 0x2B,\n\t0xEA, 0xFF, 0x16, 0x82, 0xA2, 0x6E, 0x8A, 0x2D, 0x27, 0xD6, 0x72, 0xA7,\n\t0xD5, 0x75, 0xB1, 0xFC, 0x8A, 0xB1, 0x00, 0xE3, 0x41, 0xB5, 0x9C, 0x07,\n\t0x94, 0x0B, 0x2D, 0x5D, 0x74, 0x78, 0x32, 0xD0, 0x34, 0xE2, 0x54, 0x1A,\n\t0x86, 0xFB, 0x72, 0x74, 0x5C, 0x9C, 0x65, 0x15, 0x2E, 0x74, 0xD1, 0x54,\n\t0x18, 0xEC, 0xD1, 0x24, 0x85, 0x5D, 0x5D, 0x8A, 0xF5, 0x68, 0xC0, 0xB2,\n\t0xA9, 0x78, 0x3E, 0xE9, 0xBA, 0x4D, 0xD7, 0x8C, 0x2E, 0xB6, 0x23, 0xE4,\n\t0xE2, 0x48, 0x06, 0x35, 0x4F, 0xB0, 0x25, 0x74, 0xEE, 0x82, 0x60, 0x31,\n\t0xE0, 0x33, 0x31, 0x61, 0x9B, 0x15, 0x91, 0xA4, 0x04, 0x74, 0xD1, 0x13,\n\t0x01, 0x62, 0xEB, 0x70, 0x5E, 0x82, 0x88, 0x31, 0x51, 0xAA, 0x9F, 0xB7,\n\t0x65, 0x3C, 0x10, 0x0D, 0xF6, 0xF9, 0x07, 0x28, 0x6C, 0xD7, 0xD5, 0x54,\n\t0x28, 0x0A, 0x3A, 0xE4, 0xFB, 0x96, 0x8F, 0x6F, 0x13, 0xF7, 0xC8, 0x75,\n\t0x4E, 0xA5, 0x49, 0xD9, 0x42, 0x39, 0xB4, 0x59, 0xDA, 0xA6, 0x21, 0x11,\n\t0xDC, 0x1C, 0x93, 0x39, 0xC7, 0xCC, 0xF1, 0x0E, 0x47, 0x30, 0x7D, 0xE8,\n\t0x91, 0xE3, 0xE3, 0xD8, 0x58, 0x52, 0xCD, 0x68, 0x73, 0x7B, 0x7B, 0xC3,\n\t0xB3, 0xCE, 0xDD, 0x7D, 0x56, 0xB5, 0x73, 0x9B, 0xFA, 0xDF, 0xE9, 0xF1,\n\t0x02, 0x4F, 0x31, 0x8F, 0x86, 0xA3, 0x07, 0xAE, 0xFE, 0x05, 0x80, 0x40,\n\t0x62, 0x3E, 0x1E, 0x13, 0x2F, 0x80, 0x40, 0xBA, 0x51, 0x85, 0xE2, 0x8A,\n\t0x30, 0x29, 0x0C, 0x99, 0x07, 0x6E, 0xF8, 0x0A, 0x18, 0x41, 0x89, 0x03,\n\t0x20, 0xA6, 0x8C, 0x09, 0x62, 0x8C, 0x59, 0x5B, 0x04, 0xB4, 0x54, 0x76,\n\t0x81, 0x0F, 0x5E, 0xC0, 0x9E, 0x9C, 0x34, 0x50, 0xD8, 0x70, 0x3A, 0x53,\n\t0x1B, 0xE3, 0x00, 0x59, 0xB9, 0x77, 0x2E, 0x4E, 0xD5, 0x8A, 0x81, 0x43,\n\t0xB4, 0x44, 0x46, 0x8C, 0x47, 0x98, 0x6E, 0x2B, 0xF0, 0x5D, 0xA9, 0xAA,\n\t0x9F, 0xC9, 0xFC, 0xC9, 0x31, 0x06, 0x0C, 0xB4, 0x9B, 0x22, 0x22, 0x67,\n\t0xBA, 0x03, 0x56, 0x7B, 0x33, 0xBC, 0x8C, 0x02, 0x57, 0x22, 0xF0, 0xA6,\n\t0x4F, 0x51, 0x7F, 0xD5, 0x99, 0xAA, 0xC5, 0x97, 0xB4, 0x47, 0x52, 0x25,\n\t0xCF, 0xAD, 0x44, 0x1D, 0xE0, 0xC8, 0x44, 0x8F, 0x6F, 0xAF, 0xCE, 0x1D,\n\t0x55, 0xD4, 0x68, 0x4D, 0xCB, 0x06, 0xC4, 0xE8, 0xC7, 0x56, 0x96, 0x11,\n\t0x90, 0x00, 0xEA, 0xED, 0x51, 0x82, 0xA4, 0x68, 0x23, 0x40, 0x84, 0xE6,\n\t0x5F, 0x11, 0x9F, 0x29, 0x05, 0x82, 0xAE, 0x83, 0x9E, 0x89, 0x07, 0x82,\n\t0xAE, 0x34, 0xAE, 0xCD, 0x04, 0xE2, 0x6C, 0x08, 0x34, 0xBC, 0xD2, 0x25,\n\t0x38, 0xAC, 0x5C, 0x5B, 0xFE, 0x87, 0xD8, 0x49, 0x81, 0xC6, 0xB5, 0x4C,\n\t0x00, 0xC0, 0x62, 0x8F, 0x0A, 0x61, 0x76, 0x48, 0x71, 0x0C, 0x40, 0x16,\n\t0x1B, 0x53, 0x10, 0x02, 0x69, 0x88, 0x30, 0x20, 0xBC, 0x84, 0xA1, 0x71,\n\t0x17, 0xAA, 0x6F, 0xE1, 0x40, 0x60, 0x95, 0xE0, 0x93, 0xCB, 0xE6, 0x36,\n\t0x56, 0xC2, 0xFE, 0x95, 0x0C, 0xFD, 0xC0, 0x3E, 0x7C, 0x22, 0x78, 0xCD,\n\t0xF7, 0x64, 0xF1, 0xAC, 0xF8, 0xE8, 0x36, 0x16, 0x0E, 0xDB, 0x7B, 0x1A,\n\t0x84, 0xFD, 0x83, 0x09, 0x83, 0x7F, 0x17, 0x18, 0x47, 0xBC, 0x99, 0xE4,\n\t0xF5, 0xDE, 0x91, 0xD7, 0xCA, 0x85, 0xBF, 0x40, 0xF5, 0x9E, 0x0B, 0x54,\n\t0x17, 0xD7, 0xE6, 0x8E, 0x99, 0x79, 0x1B, 0x78, 0x9D, 0x17, 0xC4, 0x8B,\n\t0x7D, 0x2F, 0x26, 0x78, 0xED, 0x85, 0x04, 0x2F, 0xBD, 0xAD, 0x29, 0x5E,\n\t0x6F, 0x49, 0xF1, 0x5A, 0x8A, 0x61, 0xC9, 0x4C, 0x93, 0x85, 0xD2, 0x55,\n\t0xEE, 0x2F, 0x71, 0x06, 0xFD, 0xDC, 0xF3, 0x46, 0x0A, 0x2D, 0x12, 0x3F,\n\t0x3E, 0x54, 0xDB, 0x96, 0x78, 0xBA, 0xA2, 0xC1, 0x2B, 0x5C, 0x8B, 0x6A,\n\t0x90, 0x18, 0x04, 0x3A, 0x5D, 0x57, 0xD5, 0x30, 0xE7, 0x5A, 0x90, 0x22,\n\t0x67, 0x77, 0x35, 0x18, 0x92, 0xAB, 0xC1, 0xDC, 0xAE, 0xFE, 0xC9, 0xD5,\n\t0x7B, 0x70, 0x65, 0x86, 0xA8, 0x03, 0x86, 0xA2, 0xA0, 0x89, 0x16, 0x38,\n\t0xD7, 0x8F, 0x24, 0xE9, 0xA0, 0x68, 0xC6, 0x6A, 0x14, 0x05, 0xF8, 0x30,\n\t0x0E, 0xFD, 0xA6, 0xED, 0x8A, 0xAA, 0x40, 0xD5, 0x4A, 0x3A, 0xF0, 0x8B,\n\t0xB3, 0x3A, 0x8E, 0xE8, 0x31, 0x75, 0xFE, 0x7C, 0x26, 0x5F, 0xC2, 0x8C,\n\t0xDE, 0x6E, 0x91, 0x19, 0x70, 0x5F, 0xAE, 0x7F, 0x53, 0x96, 0x52, 0x1B,\n\t0xE2, 0x1C, 0x43, 0xCF, 0x95, 0x1E, 0xB6, 0xB8, 0xC9, 0x83, 0x95, 0xC6,\n\t0x4C, 0x0F, 0x16, 0xBA, 0xE5, 0x8D, 0x72, 0x36, 0xD3, 0xD3, 0x52, 0xA4,\n\t0xCD, 0x90, 0xA9, 0xDB, 0x40, 0x60, 0x57, 0x84, 0xC8, 0x94, 0xF0, 0x67,\n\t0xCB, 0x08, 0xF9, 0x16, 0x10, 0xB9, 0x64, 0xC4, 0x54, 0x96, 0x8C, 0xCF,\n\t0x70, 0x06, 0x51, 0x39, 0x65, 0xAB, 0x64, 0x00, 0x0B, 0x1B, 0x07, 0x83,\n\t0x4A, 0xC6, 0x87, 0xC4, 0x60, 0x0A, 0xBC, 0x55, 0xD4, 0xF4, 0x06, 0xDB,\n\t0xE2, 0xAB, 0x38, 0x14, 0x29, 0x32, 0xAE, 0xF6, 0xC3, 0x28, 0x4C, 0x3D,\n\t0x48, 0x8D, 0xAC, 0x67, 0x03, 0xEC, 0xBE, 0x54, 0x0A, 0x12, 0x57, 0xA7,\n\t0x42, 0xB4, 0x46, 0x32, 0xD4, 0x87, 0xE2, 0xEC, 0x71, 0x34, 0x89, 0xBD,\n\t0x33, 0x49, 0x9F, 0xB9, 0x42, 0xD9, 0x54, 0x70, 0x09, 0xE3, 0xB4, 0x86,\n\t0x29, 0x57, 0xCF, 0x93, 0x33, 0x1C, 0x9E, 0x9C, 0xA1, 0x58, 0xDA, 0xF6,\n\t0xF9, 0x43, 0xEA, 0x67, 0x8F, 0xEF, 0xD1, 0x94, 0x42, 0x57, 0xA5, 0x3E,\n\t0x95, 0x7A, 0x74, 0xCF, 0x0E, 0x09, 0xA9, 0xDB, 0xD2, 0xAD, 0xA8, 0x93,\n\t0x58, 0x51, 0x43, 0x8D, 0x02, 0x09, 0x82, 0xE9, 0x24, 0x9F, 0xA9, 0x29,\n\t0x19, 0x13, 0xA8, 0xD7, 0x02, 0xBF, 0xB1, 0x92, 0x10, 0x9B, 0x8A, 0x42,\n\t0x64, 0x00, 0x21, 0x29, 0x3F, 0x3F, 0xB7, 0x69, 0x08, 0x2B, 0x8A, 0xF4,\n\t0xAB, 0x6B, 0xCE, 0xF3, 0x63, 0x79, 0x9E, 0x1E, 0x5C, 0x3D, 0x96, 0x73,\n\t0x35, 0xC7, 0xB4, 0x96, 0x8F, 0x65, 0x39, 0xBF, 0x96, 0x3B, 0xBD, 0x82,\n\t0x78, 0x5D, 0xCB, 0xF1, 0x52, 0x2C, 0x57, 0x99, 0x17, 0x05, 0xE6, 0xED,\n\t0x28, 0x9F, 0x9C, 0x13, 0x98, 0x39, 0x4E, 0x85, 0x90, 0x04, 0x97, 0xC1,\n\t0xC4, 0x84, 0xDE, 0x15, 0x4D, 0x4C, 0x36, 0x50, 0x34, 0x7B, 0x41, 0x93,\n\t0xA3, 0xE9, 0x2A, 0x30, 0x78, 0x81, 0xC0, 0x55, 0xBE, 0xA4, 0xDB, 0xD4,\n\t0x67, 0xAD, 0x98, 0x0A, 0x20, 0xE4, 0x35, 0x43, 0x7F, 0x52, 0x92, 0x28,\n\t0x2A, 0xA5, 0xD0, 0xF5, 0x8B, 0x8D, 0x09, 0xDB, 0xA2, 0xAE, 0x50, 0xF4,\n\t0x64, 0xBA, 0x33, 0x7E, 0x5A, 0x10, 0xC8, 0x25, 0xEB, 0x59, 0x64, 0x99,\n\t0x13, 0x2C, 0x51, 0xB0, 0xD0, 0xC2, 0xDD, 0x0F, 0x56, 0x78, 0x60, 0x90,\n\t0xD4, 0x36, 0x77, 0x06, 0xD5, 0x43, 0x76, 0xD1, 0x31, 0xA7, 0x43, 0x03,\n\t0x1D, 0x22, 0xD8, 0x3D, 0x2D, 0x42, 0x95, 0x27, 0x32, 0xA8, 0xF7, 0x98,\n\t0x50, 0x7B, 0x54, 0xE5, 0x7B, 0x52, 0xE5, 0xED, 0xCA, 0x3C, 0xE5, 0xA9,\n\t0x18, 0xE5, 0x40, 0x52, 0x21, 0x54, 0x4C, 0xC4, 0x35, 0x3A, 0xA0, 0x5E,\n\t0x83, 0x00, 0xD4, 0x6D, 0x6A, 0xC1, 0x1E, 0x2E, 0x5B, 0x5C, 0xB2, 0x92,\n\t0x43, 0x30, 0x5C, 0xBA, 0x64, 0x2D, 0xF6, 0x7A, 0x43, 0x41, 0x30, 0xD7,\n\t0x00, 0x2A, 0x3A, 0xC4, 0x69, 0xA0, 0x78, 0x19, 0x28, 0x6E, 0x53, 0xB6,\n\t0x0D, 0x90, 0x9E, 0x7D, 0xB2, 0x20, 0xE3, 0xE2, 0x21, 0x25, 0x11, 0x3A,\n\t0x87, 0x21, 0xA5, 0xD5, 0x6B, 0x4C, 0x29, 0x9F, 0x8B, 0x9B, 0xE4, 0x49,\n\t0xCD, 0x1D, 0x77, 0x74, 0xD4, 0x79, 0x93, 0xDF, 0xF2, 0x69, 0x53, 0xB4,\n\t0x84, 0x96, 0xC9, 0x3A, 0x97, 0x2A, 0x09, 0xFA, 0x03, 0xF2, 0xA9, 0x5B,\n\t0xE2, 0x88, 0x38, 0x39, 0xB9, 0xBF, 0x8E, 0x9E, 0x39, 0xC3, 0x90, 0x83,\n\t0x44, 0x2B, 0x90, 0x1D, 0x0B, 0xCC, 0x7C, 0x19, 0x30, 0x60, 0x4F, 0xF0,\n\t0x21, 0xF6, 0x53, 0xA0, 0xE3, 0x38, 0x11, 0xCF, 0x64, 0x15, 0x38, 0x5E,\n\t0x21, 0xA1, 0x4C, 0xE2, 0x19, 0xF4, 0xCC, 0x9A, 0x7C, 0x60, 0x66, 0xC1,\n\t0xC5, 0x4A, 0x2E, 0xE5, 0xAC, 0xB0, 0xB6, 0x73, 0x1A, 0x8D, 0xD2, 0x04,\n\t0xD6, 0x4A, 0x22, 0xAC, 0x8F, 0x3D, 0x14, 0x7D, 0x7C, 0x53, 0xB4, 0x5D,\n\t0x0F, 0x25, 0x8E, 0x7E, 0xC2, 0xE1, 0x68, 0x11, 0xD4, 0x5C, 0xA6, 0xCF,\n\t0xF1, 0x32, 0x45, 0x1C, 0xF7, 0xF4, 0x8E, 0xDE, 0xBB, 0x21, 0x4C, 0x38,\n\t0xDC, 0x7B, 0x22, 0xBA, 0x2D, 0x22, 0xD1, 0xB6, 0xAA, 0xF9, 0xD1, 0xD3,\n\t0x3C, 0x8D, 0x16, 0x65, 0xC3, 0x80, 0xE5, 0x7C, 0x05, 0x34, 0x01, 0x7D,\n\t0x59, 0x22, 0x69, 0x78, 0x23, 0xE8, 0xC0, 0x29, 0xF4, 0xDF, 0x18, 0x35,\n\t0xA4, 0x9F, 0x6E, 0x9F, 0xD5, 0x15, 0x98, 0x12, 0x47, 0x7F, 0x2E, 0x12,\n\t0x79, 0x4B, 0x56, 0xF9, 0x0D, 0xFC, 0xF6, 0xE1, 0x71, 0x0A, 0x67, 0x5E,\n\t0xCC, 0x06, 0x79, 0xE0, 0xE8, 0x21, 0x93, 0xC1, 0x5A, 0x44, 0x5B, 0xB7,\n\t0x11, 0xF3, 0xEF, 0x70, 0x34, 0x49, 0x53, 0x75, 0xBF, 0x7B, 0x2A, 0x6D,\n\t0xA8, 0x4A, 0xEF, 0x2C, 0xD5, 0xDF, 0x04, 0x02, 0xA4, 0x50, 0x2D, 0x6D,\n\t0x7B, 0x75, 0x55, 0xD3, 0x71, 0xAB, 0xDA, 0x88, 0x82, 0x10, 0xF5, 0x0F,\n\t0x1B, 0xB4, 0x34, 0x6B, 0x83, 0x12, 0x9A, 0x53, 0x54, 0x91, 0x72, 0xCB,\n\t0x40, 0x31, 0xFA, 0xCD, 0x89, 0xD1, 0x6D, 0xC9, 0x26, 0x46, 0x27, 0x99,\n\t0x18, 0x6D, 0xC7, 0x84, 0x25, 0x2B, 0xA2, 0xCA, 0xB1, 0xFC, 0x0C, 0x0E,\n\t0xA4, 0xF1, 0x26, 0xE0, 0x9B, 0xD8, 0xA4, 0x07, 0x9C, 0x4A, 0x10, 0x95,\n\t0x89, 0x99, 0xBE, 0xFD, 0xF5, 0x2A, 0xEA, 0xE4, 0xA7, 0xCF, 0x40, 0x71,\n\t0xA9, 0x4A, 0xBC, 0xE8, 0x4F, 0x88, 0x40, 0xAD, 0x05, 0x44, 0x67, 0x0A,\n\t0x77, 0xDF, 0x88, 0x36, 0xB4, 0x75, 0x6E, 0x80, 0x56, 0x3C, 0x39, 0x73,\n\t0x19, 0x16, 0x77, 0x6D, 0x1B, 0x8A, 0xA7, 0x08, 0xAD, 0x61, 0x10, 0x3A,\n\t0xEB, 0x8F, 0x21, 0x6E, 0x69, 0x3F, 0x4F, 0x67, 0x77, 0x42, 0x19, 0x50,\n\t0x82, 0xB0, 0x30, 0x20, 0x17, 0x82, 0x21, 0x52, 0x18, 0xD1, 0xCA, 0xE3,\n\t0x44, 0x56, 0x40, 0x06, 0x70, 0xCE, 0x4C, 0x89, 0x20, 0x79, 0x91, 0xD4,\n\t0x44, 0x52, 0x40, 0xBD, 0x67, 0x91, 0xD4, 0xC8, 0x25, 0x2D, 0x47, 0x8A,\n\t0x88, 0x5D, 0x54, 0xF7, 0xA5, 0xB8, 0x14, 0xF5, 0x1D, 0xF8, 0x42, 0xF7,\n\t0xE5, 0xEE, 0xB4, 0x84, 0xE8, 0xFC, 0xE1, 0x1F, 0xD5, 0xD1, 0x27, 0x9C,\n\t0xBB, 0xA5, 0xA5, 0xE0, 0xB9, 0x23, 0xF4, 0x21, 0xC0, 0xAE, 0x0F, 0x01,\n\t0xE8, 0x1C, 0x39, 0x02, 0x72, 0xB4, 0x04, 0xFC, 0xAB, 0x29, 0xD5, 0x0B,\n\t0xA0, 0x08, 0xAD, 0x0C, 0x3C, 0xA4, 0x65, 0xB8, 0x80, 0x80, 0xA4, 0xFD,\n\t0x68, 0x24, 0x49, 0x3D, 0x91, 0x96, 0xBA, 0x43, 0x62, 0x23, 0xB7, 0x1D,\n\t0x0C, 0x2B, 0x4E, 0xBE, 0xB0, 0x62, 0xAF, 0x99, 0xB7, 0xE4, 0x06, 0xC3,\n\t0xD7, 0x6E, 0x2D, 0x7C, 0x95, 0x71, 0xFA, 0xBA, 0xCC, 0x89, 0xAF, 0x9F,\n\t0xC8, 0x2C, 0xFD, 0x34, 0x86, 0x6A, 0x21, 0xA3, 0xA6, 0x1A, 0x42, 0x6F,\n\t0x08, 0x20, 0xB9, 0x5B, 0x9A, 0x61, 0xA3, 0xBD, 0x20, 0x04, 0xE5, 0xD0,\n\t0x74, 0xE0, 0x65, 0xDB, 0x17, 0xA3, 0x70, 0xF7, 0x75, 0x8D, 0x1A, 0x7A,\n\t0x64, 0x39, 0x02, 0xFC, 0xD0, 0x33, 0x30, 0x26, 0x17, 0xDF, 0x1E, 0x45,\n\t0x81, 0xD6, 0xBA, 0xCE, 0x47, 0x29, 0x18, 0x1C, 0xCE, 0x10, 0xB8, 0xE0,\n\t0x66, 0x39, 0x0D, 0xD9, 0x45, 0x24, 0xA4, 0xB1, 0x1D, 0x15, 0x19, 0xBF,\n\t0xE4, 0x26, 0xD6, 0x08, 0x1A, 0x2D, 0x60, 0xC5, 0xD6, 0x27, 0x9F, 0x36,\n\t0xA0, 0x21, 0xE0, 0x39, 0xC4, 0x3B, 0x92, 0x1E, 0x01, 0xFF, 0xF1, 0x80,\n\t0xD3, 0x1B, 0x19, 0x2D, 0x7E, 0x4A, 0x3A, 0x57, 0x74, 0xE0, 0xFA, 0x13,\n\t0x65, 0xD4, 0xA5, 0x38, 0x7D, 0x75, 0x28, 0x05, 0x33, 0x98, 0x70, 0x4B,\n\t0x8B, 0x8B, 0xB3, 0xCD, 0x94, 0x24, 0xC2, 0x93, 0x91, 0x48, 0xB9, 0xE5,\n\t0x94, 0xFE, 0x70, 0x1C, 0x02, 0x34, 0x85, 0x92, 0x62, 0xA8, 0x7E, 0x2E,\n\t0xC1, 0x81, 0x75, 0x07, 0x16, 0x40, 0x7F, 0x84, 0x5E, 0x87, 0x2A, 0xD0,\n\t0x9A, 0xD6, 0x09, 0xA1, 0xB4, 0x04, 0x9B, 0xD2, 0x86, 0x30, 0x1D, 0xC6,\n\t0x04, 0xE4, 0xD6, 0xC4, 0x9C, 0x1F, 0xC7, 0x2B, 0xF8, 0xA7, 0x90, 0x1F,\n\t0x47, 0xA7, 0x14, 0x54, 0x58, 0x4E, 0x74, 0x66, 0x7B, 0xD0, 0xBE, 0x9D,\n\t0x40, 0xF4, 0x1B, 0x09, 0xF7, 0xCD, 0xE8, 0x68, 0x1C, 0x49, 0x18, 0x9D,\n\t0x22, 0x88, 0x87, 0x2E, 0x6C, 0xEB, 0x69, 0xEA, 0x26, 0x8C, 0xA2, 0xBF,\n\t0x13, 0x3E, 0x7C, 0x14, 0xED, 0xA3, 0x47, 0x91, 0xB2, 0x2E, 0xEA, 0x22,\n\t0x23, 0x1E, 0x91, 0x08, 0xB9, 0xB4, 0x9E, 0xF6, 0x5B, 0xA9, 0x92, 0x74,\n\t0x02, 0x21, 0x24, 0x0D, 0x49, 0xE0, 0xB5, 0x9A, 0xBB, 0x7C, 0x10, 0xC4,\n\t0xEB, 0x2A, 0xA1, 0x10, 0xD8, 0x9A, 0xCF, 0x1F, 0x2D, 0x64, 0x9D, 0x65,\n\t0x45, 0x0F, 0x1B, 0x05, 0x06, 0x57, 0x25, 0x4C, 0xB4, 0xC5, 0x69, 0x6D,\n\t0xDC, 0x80, 0x09, 0x41, 0x6B, 0x54, 0x69, 0x51, 0x98, 0xD3, 0x62, 0x79,\n\t0xFF, 0x02, 0x14, 0x60, 0x81, 0x12, 0xC1, 0x83, 0xB0, 0x07, 0x21, 0x60,\n\t0x5C, 0x95, 0x55, 0x0B, 0x15, 0x5B, 0x94, 0xD1, 0xFE, 0x2E, 0x70, 0x0A,\n\t0x52, 0xCF, 0x50, 0x36, 0x7A, 0x38, 0x28, 0xD9, 0xE8, 0xE1, 0x29, 0xD7,\n\t0xBB, 0x63, 0xFA, 0x0B, 0x0E, 0x18, 0x7A, 0x14, 0x94, 0x0E, 0xB0, 0xAF,\n\t0xB7, 0xAA, 0xA8, 0x29, 0x70, 0x6D, 0xBB, 0xCA, 0xBC, 0x5D, 0x19, 0x8B,\n\t0xAA, 0xDD, 0xD6, 0xE9, 0x5C, 0x2F, 0x02, 0xE3, 0x17, 0xDB, 0x4C, 0x46,\n\t0x3D, 0x7D, 0x00, 0xB5, 0x18, 0x29, 0xC2, 0x62, 0x13, 0x38, 0xDC, 0x1E,\n\t0xCC, 0x38, 0x55, 0x3D, 0x23, 0x66, 0xFC, 0xDD, 0xE9, 0x2E, 0xF1, 0x60,\n\t0x5D, 0xB2, 0xC4, 0xAD, 0x6D, 0x57, 0xE2, 0x17, 0x0A, 0xD0, 0x5F, 0x01,\n\t0x03, 0xA4, 0x51, 0x5F, 0xD4, 0xB8, 0xBF, 0x17, 0x23, 0xA8, 0xC4, 0xCE,\n\t0xE0, 0xC2, 0xC5, 0x60, 0x89, 0xAB, 0x38, 0x3F, 0x2F, 0xF0, 0x00, 0xFF,\n\t0x09, 0xB6, 0x26, 0xC5, 0x12, 0x00, 0x65, 0x1D, 0x4F, 0xA2, 0x7C, 0xE8,\n\t0x79, 0xF6, 0x01, 0x27, 0x51, 0x4C, 0x66, 0x48, 0x7F, 0x86, 0x40, 0x17,\n\t0xA5, 0x42, 0x09, 0x70, 0x25, 0xC8, 0x70, 0x2B, 0xA1, 0x02, 0x20, 0x54,\n\t0x31, 0x51, 0xC3, 0x19, 0xF7, 0x85, 0x89, 0x8A, 0x9B, 0x52, 0x9E, 0x4C,\n\t0xB1, 0x2E, 0x19, 0x01, 0xEC, 0x92, 0x61, 0xAE, 0xDE, 0x7B, 0x1E, 0x61,\n\t0xFD, 0x96, 0x1E, 0x41, 0xEE, 0xE6, 0x77, 0x62, 0x37, 0xE6, 0xED, 0x3B,\n\t0x31, 0xB3, 0x68, 0xE2, 0x8F, 0x1A, 0x5B, 0xCC, 0x36, 0x2B, 0x71, 0x4A,\n\t0xFF, 0x06, 0x63, 0x93, 0x9C, 0x02, 0x02, 0x08, 0x2F, 0xDE, 0x8E, 0x6C,\n\t0x58, 0x63, 0x1A, 0x7F, 0x55, 0x78, 0x18, 0x85, 0x89, 0x9A, 0xCE, 0x00,\n\t0xA2, 0x96, 0x0E, 0x3A, 0x72, 0xA2, 0x40, 0x7A, 0x1F, 0xA4, 0xD8, 0xAE,\n\t0x07, 0x2E, 0x33, 0xCD, 0xB6, 0x1E, 0xFB, 0xDB, 0x92, 0xD2, 0x95, 0xA9,\n\t0x98, 0x89, 0x42, 0x0B, 0x41, 0x44, 0x26, 0x5D, 0x52, 0x85, 0x74, 0xA1,\n\t0xB7, 0x81, 0xC2, 0x42, 0x1B, 0x27, 0xDC, 0xD2, 0xB9, 0xA8, 0x69, 0x66,\n\t0x10, 0x2D, 0x46, 0xEE, 0x5D, 0x96, 0x05, 0x15, 0x09, 0x2F, 0x6C, 0x82,\n\t0x0E, 0x67, 0x37, 0x28, 0x87, 0xD2, 0xF0, 0x23, 0x3C, 0x9C, 0x10, 0xC9,\n\t0x91, 0x36, 0x19, 0xAA, 0xEA, 0x6B, 0xAA, 0x0E, 0x7F, 0x9C, 0x29, 0x12,\n\t0x1F, 0xE1, 0x60, 0x90, 0x90, 0x9D, 0xD4, 0xA1, 0x85, 0xD0, 0xF1, 0xFE,\n\t0x54, 0x71, 0x40, 0x95, 0xBD, 0x57, 0x31, 0xC4, 0xBA, 0x89, 0xF7, 0x18,\n\t0x69, 0x87, 0xDC, 0x58, 0x3E, 0xA4, 0x46, 0x50, 0x93, 0x4E, 0xDF, 0x4C,\n\t0xC6, 0xE3, 0x53, 0x9E, 0x09, 0x52, 0xA3, 0x47, 0x79, 0xD0, 0xC9, 0x09,\n\t0x30, 0xCC, 0x9C, 0xE8, 0x66, 0xBF, 0x0C, 0x3B, 0xCA, 0xA3, 0x5C, 0x15,\n\t0x88, 0xB6, 0xB7, 0x2F, 0x07, 0x00, 0xBA, 0xA9, 0xA9, 0x1E, 0x9F, 0x39,\n\t0x39, 0x63, 0xDA, 0xEE, 0x6F, 0x42, 0x8F, 0x17, 0x65, 0x63, 0x96, 0x63,\n\t0x4E, 0xBB, 0x28, 0xC6, 0x9C, 0xF6, 0x6B, 0x09, 0x1B, 0x13, 0xC6, 0x04,\n\t0x53, 0x67, 0x26, 0xEC, 0x97, 0x3A, 0xC2, 0x0F, 0x41, 0xFD, 0xD3, 0xA8,\n\t0x98, 0xF0, 0xAC, 0xFF, 0x3C, 0xB6, 0x2D, 0x65, 0x90, 0x3E, 0xB3, 0xD8,\n\t0xB6, 0xC4, 0x05, 0x88, 0x11, 0x64, 0x9A, 0xD0, 0x40, 0x43, 0xCA, 0x83,\n\t0x22, 0x96, 0xE4, 0xC8, 0x90, 0x5A, 0x9B, 0x12, 0xA3, 0x8A, 0xEA, 0xEF,\n\t0x24, 0x2A, 0x2A, 0xE0, 0x09, 0xE4, 0x7F, 0xAB, 0xBB, 0xA0, 0xEB, 0xBA,\n\t0x38, 0xDB, 0x5C, 0x84, 0x7A, 0xD6, 0x54, 0xCC, 0x27, 0x84, 0xCA, 0x4D,\n\t0xB4, 0x00, 0x29, 0xD0, 0xB6, 0x24, 0x9C, 0x2E, 0xA9, 0x0C, 0x83, 0x2C,\n\t0x1D, 0x2C, 0xAE, 0x80, 0xD7, 0xA8, 0xB6, 0x2A, 0x30, 0x5D, 0x4D, 0x1F,\n\t0x16, 0xFD, 0xE5, 0xA0, 0xE6, 0x79, 0x45, 0x69, 0x0D, 0x8C, 0xD2, 0x09,\n\t0xA1, 0x12, 0x15, 0x25, 0xA2, 0x22, 0xAD, 0x16, 0xBD, 0xC3, 0x0C, 0x1A,\n\t0xBA, 0x4D, 0xFD, 0xFB, 0xEE, 0x84, 0x9E, 0x89, 0x67, 0x4B, 0x56, 0x0B,\n\t0xA4, 0x63, 0x3C, 0x96, 0xB1, 0x42, 0x66, 0xC8, 0x04, 0x2C, 0x6D, 0x05,\n\t0xE8, 0x11, 0x13, 0xB7, 0x96, 0x97, 0x97, 0x2C, 0x2A, 0x40, 0x9A, 0xEE,\n\t0x0A, 0xE8, 0x13, 0x3B, 0xCB, 0x1E, 0x31, 0x26, 0x0C, 0x14, 0x3F, 0xCD,\n\t0x8C, 0x2E, 0xC4, 0xE6, 0x6B, 0x21, 0x36, 0x0E, 0x0A, 0x96, 0xFB, 0x98,\n\t0x60, 0x29, 0x26, 0xC6, 0x62, 0x90, 0x35, 0x4B, 0x41, 0xD6, 0x5B, 0x3B,\n\t0x28, 0xDF, 0x33, 0xA3, 0x4C, 0xF3, 0xC7, 0x35, 0xCA, 0x32, 0x85, 0xCD,\n\t0x64, 0x8C, 0x09, 0x20, 0x00, 0x12, 0x29, 0xC0, 0x6B, 0x9E, 0x8C, 0x88,\n\t0x3B, 0x32, 0xA9, 0x3F, 0x24, 0x09, 0xEC, 0x9F, 0x91, 0x28, 0x00, 0xF6,\n\t0xCF, 0x1B, 0xFA, 0x75, 0x02, 0x04, 0xD4, 0xA4, 0x98, 0x97, 0xB6, 0x18,\n\t0xCD, 0x80, 0xA6, 0xF9, 0x5A, 0xA6, 0xD1, 0x90, 0x90, 0x71, 0x5A, 0x3E,\n\t0xE8, 0xDC, 0xEB, 0x5E, 0x55, 0x6D, 0x17, 0x30, 0xED, 0x43, 0x0C, 0x01,\n\t0x90, 0xD1, 0x42, 0xAB, 0x0C, 0xD6, 0x72, 0x48, 0x46, 0x70, 0x04, 0x95,\n\t0xCC, 0x0E, 0xD7, 0x3D, 0x7A, 0x60, 0xE1, 0x76, 0x8C, 0x68, 0x86, 0xA8,\n\t0x4A, 0x8A, 0x2D, 0xC8, 0x81, 0x8B, 0x8D, 0x39, 0x5D, 0x68, 0x6C, 0x30,\n\t0x48, 0xD8, 0x13, 0x86, 0x88, 0x30, 0x51, 0x4B, 0xA8, 0xE0, 0x6C, 0x88,\n\t0x58, 0x41, 0xEC, 0xEE, 0xD4, 0x00, 0x0B, 0x31, 0x16, 0x54, 0x1B, 0x7F,\n\t0x55, 0x7D, 0x0D, 0x3A, 0x32, 0x54, 0xD1, 0xB2, 0x9F, 0x20, 0x3C, 0x3D,\n\t0x54, 0x0F, 0x05, 0x23, 0x32, 0x7A, 0x26, 0x01, 0xBF, 0xD3, 0xF8, 0x1C,\n\t0x19, 0xFD, 0x63, 0x47, 0x05, 0x80, 0xE4, 0x1A, 0xBF, 0x80, 0x64, 0xF5,\n\t0xB6, 0xA4, 0x1D, 0x73, 0x7F, 0x79, 0xBE, 0x70, 0x9F, 0x75, 0x01, 0xC9,\n\t0xD5, 0xFD, 0x3D, 0x0D, 0xCE, 0x8C, 0xF5, 0xF9, 0x6B, 0x83, 0xC1, 0x25,\n\t0xCB, 0x33, 0x06, 0x63, 0xC7, 0x99, 0x31, 0xF6, 0x71, 0xD8, 0x62, 0x35,\n\t0x00, 0x52, 0xB0, 0xD2, 0x7B, 0x7B, 0x62, 0xF5, 0x9B, 0x12, 0xAB, 0x9F,\n\t0x40, 0xAE, 0x7E, 0xEE, 0xB8, 0x9A, 0x87, 0x19, 0xAA, 0x79, 0x94, 0xA1,\n\t0xDA, 0x46, 0x09, 0x56, 0xDB, 0xB0, 0x52, 0x56, 0xE7, 0x78, 0x19, 0x10,\n\t0xC7, 0xB7, 0xB6, 0x62, 0x35, 0x93, 0x62, 0x9B, 0x94, 0xCA, 0x06, 0x8C,\n\t0x9F, 0x35, 0xFE, 0x80, 0xFC, 0x92, 0xD2, 0x5F, 0x4D, 0x0A, 0x10, 0x09,\n\t0x61, 0xFE, 0x0B, 0x12, 0xAE, 0xD5, 0xBF, 0xE8, 0x39, 0x72, 0x50, 0x39,\n\t0x1D, 0x90, 0x56, 0xCB, 0xE1, 0x33, 0x6C, 0x90, 0xD6, 0xB2, 0xA6, 0x99,\n\t0x1C, 0x40, 0x18, 0xD8, 0xAF, 0x5D, 0x17, 0xC2, 0xE5, 0x94, 0xB8, 0x0B,\n\t0x0B, 0x5E, 0x28, 0x44, 0xCF, 0xB0, 0x6D, 0xA8, 0x03, 0xFD, 0x4C, 0x4C,\n\t0x55, 0xA0, 0x50, 0xFD, 0xAE, 0x41, 0x21, 0x9A, 0xAA, 0x43, 0xB8, 0x95,\n\t0x4A, 0x90, 0xEA, 0x02, 0xBD, 0x82, 0x9F, 0xF0, 0x05, 0xBF, 0xEF, 0x91,\n\t0x14, 0x95, 0xDB, 0xED, 0xAC, 0xB0, 0xBF, 0x32, 0xA1, 0xD2, 0x73, 0x09,\n\t0xE6, 0x23, 0x9F, 0x9E, 0x7D, 0x53, 0x1C, 0xA2, 0x41, 0x88, 0x14, 0x0B,\n\t0xCF, 0xB4, 0x57, 0x50, 0x9E, 0x68, 0xBB, 0x29, 0x28, 0x4F, 0xC0, 0x95,\n\t0xE0, 0x56, 0x42, 0x01, 0x45, 0xFC, 0xEA, 0xB0, 0x59, 0x44, 0x40, 0xB5,\n\t0xF8, 0x01, 0xAA, 0x84, 0x69, 0x98, 0x83, 0x01, 0x0D, 0xE5, 0x92, 0xCB,\n\t0x25, 0x4B, 0x17, 0xE4, 0x43, 0x0B, 0xE4, 0xA4, 0xB6, 0x20, 0xEE, 0x0E,\n\t0xF3, 0xF2, 0x36, 0xB8, 0xC6, 0x38, 0xA9, 0x8D, 0x47, 0xA0, 0x1C, 0x08,\n\t0xA2, 0x59, 0xD6, 0x23, 0xEA, 0x34, 0x14, 0x87, 0x53, 0xEA, 0x35, 0xAC,\n\t0xD4, 0x4F, 0x15, 0x48, 0xFD, 0x34, 0xC4, 0xEE, 0x89, 0xBC, 0x79, 0x87,\n\t0x1C, 0xCF, 0x9B, 0x69, 0xE2, 0x70, 0xA2, 0x59, 0x77, 0xE2, 0xE6, 0xD1,\n\t0xE9, 0xE6, 0xEA, 0xD4, 0x24, 0x16, 0xFC, 0x0A, 0x3E, 0x8F, 0xC8, 0x41,\n\t0x8A, 0x07, 0x5A, 0x88, 0xEF, 0xD5, 0x69, 0x49, 0xDE, 0xE3, 0x7E, 0x7E,\n\t0x8F, 0x8C, 0x04, 0x5E, 0xC6, 0x32, 0x5A, 0xB3, 0x79, 0xC5, 0x75, 0xAB,\n\t0x08, 0x8A, 0xED, 0x36, 0x40, 0x71, 0xF2, 0x8A, 0xD6, 0x49, 0x18, 0x5B,\n\t0x74, 0x6B, 0xC8, 0x75, 0x6F, 0x8D, 0x0D, 0xC5, 0xCB, 0xFB, 0x44, 0x54,\n\t0x82, 0x82, 0x3C, 0x5C, 0x44, 0x28, 0x0A, 0xF5, 0x85, 0x8A, 0x5C, 0x4F,\n\t0x43, 0x6B, 0x92, 0x24, 0x71, 0x46, 0x90, 0xBC, 0x04, 0x0E, 0x4C, 0xD1,\n\t0x8B, 0x27, 0xB4, 0xD7, 0xA5, 0x7F, 0x7F, 0x56, 0xC1, 0x07, 0xE8, 0x62,\n\t0x38, 0x2D, 0xC7, 0x39, 0xB0, 0x8C, 0xF7, 0x29, 0x27, 0xF9, 0x4B, 0x36,\n\t0x4E, 0x06, 0xD7, 0x60, 0xB5, 0xE7, 0x94, 0xE2, 0x82, 0x36, 0x10, 0x90,\n\t0x18, 0xD8, 0x42, 0x95, 0x2F, 0xFF, 0x3E, 0x44, 0x00, 0x03, 0xCD, 0x72,\n\t0x51, 0x58, 0x33, 0xDA, 0x30, 0x16, 0x53, 0x30, 0x4A, 0xA7, 0x6C, 0x4A,\n\t0x65, 0x53, 0x45, 0x97, 0x29, 0x8B, 0x0E, 0xB3, 0xBB, 0x72, 0xD9, 0x9A,\n\t0x2E, 0xD4, 0xD2, 0x57, 0xB9, 0x1A, 0x01, 0x62, 0x01, 0xED, 0xAA, 0x7D,\n\t0xAC, 0x6E, 0x32, 0x4A, 0x9F, 0xD5, 0x87, 0x80, 0xDF, 0x23, 0x2B, 0xAA,\n\t0x96, 0x44, 0x64, 0x62, 0xF6, 0xC8, 0x84, 0xD0, 0xF3, 0xA1, 0xBB, 0xC3,\n\t0x43, 0x0A, 0x2C, 0x74, 0xCD, 0x0E, 0x08, 0x40, 0x8A, 0x85, 0x12, 0xB6,\n\t0xA5, 0x3F, 0x18, 0x21, 0x94, 0xB6, 0xE4, 0x19, 0x82, 0x67, 0x88, 0x9D,\n\t0x91, 0xDF, 0x65, 0x65, 0x5C, 0x60, 0x98, 0x9A, 0xEF, 0x85, 0xA9, 0x7F,\n\t0xA8, 0x32, 0x70, 0x9A, 0xEA, 0xCB, 0x89, 0x8D, 0xD0, 0x0E, 0xBA, 0x99,\n\t0xE5, 0xCE, 0x52, 0xAA, 0x91, 0x4E, 0x40, 0x62, 0x84, 0x28, 0xCE, 0x02,\n\t0x88, 0xC8, 0x49, 0x1C, 0x4A, 0x54, 0x1C, 0xA5, 0xB3, 0xB7, 0x1F, 0xF8,\n\t0xA0, 0xD1, 0x45, 0xE8, 0x10, 0xA8, 0x0E, 0xD1, 0xA0, 0xFA, 0x4D, 0x3F,\n\t0xF8, 0x80, 0xCA, 0x6A, 0x96, 0x1A, 0x79, 0x0F, 0x49, 0xDF, 0x52, 0x76,\n\t0xF4, 0xA5, 0x67, 0x28, 0xC0, 0x1C, 0xC4, 0x67, 0xEE, 0xC8, 0xD6, 0x21,\n\t0xA1, 0xC8, 0x30, 0x01, 0x81, 0xCC, 0x74, 0xAE, 0xFC, 0x6C, 0x9E, 0x9D,\n\t0x64, 0xB0, 0xCC, 0x48, 0x20, 0x12, 0xAC, 0x5D, 0x5E, 0x1B, 0x39, 0x79,\n\t0x57, 0x2E, 0x73, 0xE7, 0x7C, 0xBC, 0x98, 0x88, 0x08, 0xA8, 0x9E, 0x5D,\n\t0xA8, 0x82, 0x50, 0x15, 0xC5, 0xFE, 0xD9, 0x25, 0x02, 0xAA, 0x3C, 0x20,\n\t0x49, 0x80, 0x40, 0xE1, 0x01, 0x21, 0x63, 0x41, 0x1E, 0x9C, 0xA4, 0x6B,\n\t0x84, 0x09, 0x08, 0x86, 0xBF, 0x15, 0xB5, 0x14, 0x69, 0x95, 0xE5, 0x1A,\n\t0x58, 0xA1, 0x86, 0x6F, 0x87, 0xD9, 0x8E, 0xC0, 0x23, 0xB2, 0x73, 0xD3,\n\t0x9E, 0x15, 0x7B, 0xEE, 0xD8, 0xCD, 0xF0, 0x84, 0x42, 0x35, 0xF3, 0x09,\n\t0x95, 0xD1, 0x92, 0xFB, 0x84, 0xBA, 0x74, 0x7C, 0x78, 0xA1, 0x52, 0x93,\n\t0xE0, 0x22, 0x56, 0x8C, 0x06, 0xB1, 0x82, 0x8D, 0x5E, 0x19, 0x3D, 0x2E,\n\t0x76, 0x3F, 0x56, 0x1C, 0x8B, 0x3D, 0x84, 0x51, 0x6D, 0x80, 0x16, 0x03,\n\t0x43, 0x9B, 0x75, 0xE2, 0xC3, 0xB8, 0xE0, 0x6B, 0xDB, 0x5E, 0x54, 0x05,\n\t0xAA, 0xC4, 0x55, 0xA5, 0x4B, 0xC2, 0x84, 0x74, 0xCE, 0x10, 0xA6, 0x19,\n\t0x1B, 0xF6, 0x44, 0xB1, 0xE3, 0x3B, 0x22, 0xD4, 0x8E, 0x5B, 0xAB, 0x05,\n\t0x6E, 0x93, 0xBC, 0x1A, 0x8C, 0xCE, 0x2B, 0x63, 0xA4, 0x7C, 0x52, 0xB4,\n\t0xB2, 0x49, 0x11, 0x8E, 0xA3, 0xF7, 0xA4, 0x71, 0x46, 0x75, 0xD8, 0xAA,\n\t0x29, 0x10, 0x10, 0x48, 0x65, 0x87, 0xB8, 0xDD, 0xE4, 0x5B, 0x8D, 0x22,\n\t0x61, 0x07, 0x85, 0x6B, 0xA1, 0xF2, 0xBB, 0x09, 0xB7, 0xA5, 0x80, 0xDF,\n\t0x14, 0x0C, 0xB9, 0x88, 0x22, 0x44, 0xFB, 0xEB, 0x00, 0x3A, 0x8E, 0x26,\n\t0xD9, 0x61, 0xEF, 0x6D, 0x47, 0xFF, 0x34, 0x22, 0xE3, 0x74, 0xE1, 0xDA,\n\t0x20, 0xC1, 0xE7, 0xC3, 0x77, 0x94, 0x16, 0x81, 0xBF, 0x08, 0x28, 0x90,\n\t0xDE, 0xAC, 0x68, 0x41, 0x18, 0x0F, 0xDA, 0xD0, 0xF4, 0x73, 0x86, 0xA6,\n\t0x67, 0x95, 0xFC, 0x6E, 0x83, 0x17, 0x61, 0x01, 0x3E, 0x99, 0x51, 0x82,\n\t0xBC, 0xB4, 0x30, 0x74, 0xF1, 0xD5, 0x86, 0x41, 0xB6, 0x99, 0x57, 0x90,\n\t0x80, 0x31, 0x14, 0xED, 0x89, 0x63, 0x24, 0x0E, 0x47, 0x02, 0x28, 0xA4,\n\t0xF3, 0xA2, 0xEE, 0xCC, 0xAF, 0x73, 0x46, 0x70, 0xED, 0x4C, 0x46, 0x0C,\n\t0x18, 0x66, 0x65, 0x64, 0x63, 0xCC, 0x18, 0x64, 0xCC, 0xB1, 0x17, 0x82,\n\t0x30, 0x54, 0xA3, 0x2A, 0x51, 0xE1, 0x5E, 0x9B, 0x71, 0x74, 0xF2, 0x78,\n\t0x34, 0x9F, 0x96, 0xBE, 0xC1, 0xE4, 0xF4, 0xA9, 0x60, 0x7D, 0xEB, 0x6B,\n\t0xFA, 0x36, 0x27, 0x3C, 0x92, 0x0D, 0x00, 0x43, 0x1D, 0x9C, 0x90, 0x0E,\n\t0xE2, 0xCC, 0x99, 0x1B, 0xA0, 0x02, 0x0C, 0xE5, 0xD2, 0xDE, 0x1B, 0xC5,\n\t0x4B, 0xC3, 0x0B, 0xAD, 0x4C, 0x4C, 0x58, 0x8A, 0xC2, 0x7F, 0xD1, 0xD2,\n\t0xE0, 0x3A, 0xC5, 0x7F, 0x86, 0xA0, 0x81, 0x52, 0xAA, 0x02, 0x39, 0x03,\n\t0x30, 0xA4, 0xED, 0x37, 0x00, 0x19, 0x76, 0xE0, 0x81, 0x06, 0x90, 0x15,\n\t0x4C, 0x4C, 0x80, 0x90, 0x33, 0x46, 0x0D, 0x8D, 0x04, 0x7A, 0x68, 0xAB,\n\t0x92, 0xF6, 0xB7, 0x21, 0xB3, 0xF6, 0x34, 0x70, 0xA3, 0x0B, 0x9E, 0xB2,\n\t0xC0, 0x74, 0x20, 0x86, 0x09, 0xC6, 0x15, 0x14, 0x4D, 0xE7, 0xD0, 0x76,\n\t0xEE, 0xEF, 0xCB, 0x9F, 0xDF, 0x87, 0xA7, 0x6F, 0x48, 0xD2, 0x13, 0x13,\n\t0xC2, 0x81, 0x67, 0x85, 0x30, 0xFE, 0x05, 0x2A, 0xC0, 0xA4, 0x60, 0x75,\n\t0x9D, 0xA7, 0x14, 0xA4, 0x01, 0x33, 0xF6, 0x54, 0xB5, 0x81, 0xDD, 0x3F,\n\t0xEA, 0xA9, 0x92, 0x81, 0x05, 0xA7, 0x95, 0x8B, 0xB8, 0xEB, 0xE0, 0x0A,\n\t0x9E, 0xB6, 0x1D, 0x6E, 0x48, 0x31, 0x07, 0x72, 0xB8, 0x21, 0x9F, 0x80,\n\t0x7D, 0x70, 0xD2, 0x67, 0xD4, 0x8C, 0xAF, 0xE2, 0xCD, 0xD5, 0x2A, 0xD6,\n\t0x5C, 0x5D, 0x06, 0x05, 0xD4, 0x65, 0xB0, 0x98, 0xCB, 0xAB, 0x59, 0x17,\n\t0x57, 0xDF, 0x05, 0xBD, 0xB9, 0xAD, 0xB5, 0x29, 0x5F, 0xCB, 0x40, 0xF9,\n\t0xA7, 0x7C, 0xCF, 0x11, 0xCA, 0xBC, 0x02, 0x94, 0xE7, 0x11, 0xF0, 0x14,\n\t0x62, 0xF5, 0x33, 0x88, 0x11, 0xCA, 0xB9, 0xF8, 0x29, 0x37, 0x00, 0x01,\n\t0xA0, 0xBF, 0xC9, 0xC7, 0xE9, 0x26, 0x95, 0xD3, 0xC1, 0xA0, 0xD9, 0x18,\n\t0x8F, 0x5F, 0xF3, 0x0D, 0x7D, 0xCD, 0x32, 0x81, 0x77, 0x7E, 0x50, 0xBF,\n\t0x46, 0x3E, 0x9A, 0x9F, 0x3F, 0x5E, 0x94, 0x9A, 0xDF, 0xC4, 0xBF, 0xD6,\n\t0x19, 0xE3, 0xF8, 0xB8, 0x21, 0x17, 0x68, 0x81, 0xFE, 0x50, 0xFF, 0x32,\n\t0x69, 0xF5, 0x0F, 0x0A, 0xA5, 0xCF, 0x77, 0xA0, 0x23, 0x40, 0xAB, 0x70,\n\t0xF8, 0xB3, 0x9B, 0x0F, 0x76, 0x91, 0xF0, 0x83, 0x42, 0x78, 0x91, 0x0E,\n\t0x28, 0x56, 0x20, 0x5F, 0xCD, 0x9E, 0xD7, 0x6A, 0xE2, 0xAC, 0x37, 0x24,\n\t0x8E, 0xD7, 0x43, 0xE0, 0xDC, 0x78, 0xE3, 0xF5, 0x0D, 0x37, 0x79, 0x76,\n\t0xF0, 0x3A, 0x4F, 0x1B, 0xAF, 0x9F, 0x80, 0xAC, 0x04, 0xB3, 0x9C, 0x43,\n\t0x1F, 0xDD, 0xE7, 0x62, 0xB1, 0x02, 0xB8, 0x10, 0x6D, 0xD5, 0xAB, 0x81,\n\t0x06, 0x1A, 0x04, 0x85, 0x4E, 0x35, 0xBD, 0x3F, 0xB4, 0x6F, 0xEC, 0xF1,\n\t0x1A, 0xBF, 0x99, 0xB8, 0x21, 0x63, 0x0A, 0x27, 0xFC, 0xD9, 0x9B, 0xDB,\n\t0x44, 0x5C, 0x52, 0xCE, 0x9E, 0x16, 0xB9, 0x33, 0x7D, 0x7D, 0x67, 0xFD,\n\t0xB0, 0xA1, 0x74, 0x7B, 0xFA, 0x56, 0x80, 0xE8, 0x4F, 0xDD, 0x2B, 0xA2,\n\t0x6F, 0x2F, 0x8F, 0xE6, 0x34, 0xF5, 0x37, 0x04, 0x5E, 0x70, 0xC2, 0x54,\n\t0x94, 0x19, 0x58, 0x0C, 0x3A, 0xCA, 0xD1, 0xBC, 0x86, 0x26, 0x07, 0x86,\n\t0x10, 0x44, 0x27, 0xCB, 0x2B, 0x43, 0x99, 0xD7, 0x85, 0xED, 0x6E, 0xD4,\n\t0x79, 0xF2, 0xC7, 0x67, 0x85, 0xB6, 0xCE, 0x69, 0x4B, 0x98, 0x1A, 0x1E,\n\t0x80, 0xF1, 0x81, 0x08, 0x00, 0x84, 0xE3, 0xEC, 0x4A, 0x75, 0x25, 0x45,\n\t0x01, 0x2B, 0xD5, 0xCC, 0x25, 0x80, 0x52, 0x7B, 0xFE, 0x3E, 0x48, 0xE3,\n\t0x65, 0x65, 0x8F, 0x29, 0x37, 0x4D, 0xD0, 0x7F, 0xBF, 0x07, 0xA8, 0x95,\n\t0x14, 0xC8, 0xFC, 0x8A, 0x73, 0xE3, 0x67, 0x36, 0xB6, 0xA3, 0x18, 0x42,\n\t0xDA, 0xF2, 0x90, 0xA9, 0x21, 0xE5, 0x00, 0x67, 0x9C, 0xE5, 0x17, 0x0F,\n\t0x9C, 0xE5, 0x79, 0x82, 0x58, 0xF1, 0x7A, 0x58, 0x2E, 0xE7, 0x0E, 0x0F,\n\t0x1E, 0x96, 0xAB, 0xF9, 0xE1, 0x2C, 0x88, 0x58, 0xD0, 0x55, 0xC4, 0x80,\n\t0x2B, 0x05, 0x99, 0x73, 0xA3, 0x76, 0xBF, 0x26, 0x05, 0x00, 0x1B, 0xA5,\n\t0xB8, 0xFB, 0xAC, 0x0D, 0x36, 0x4A, 0x77, 0xD6, 0xEA, 0x28, 0xA0, 0xC7,\n\t0x89, 0x95, 0x04, 0x65, 0x80, 0x92, 0xC8, 0x74, 0x03, 0xB5, 0xAF, 0xE7,\n\t0x8C, 0x21, 0x6D, 0x72, 0x70, 0xAB, 0x35, 0x9D, 0x64, 0x5F, 0xF9, 0x22,\n\t0x01, 0x68, 0x42, 0xA6, 0x36, 0xFC, 0x59, 0xF3, 0x80, 0xCC, 0x04, 0x00,\n\t0x72, 0x74, 0x4D, 0x77, 0xA3, 0x6B, 0x2B, 0x66, 0xD8, 0x2D, 0x5D, 0xA7,\n\t0xA1, 0x76, 0x05, 0x68, 0x11, 0x04, 0x0B, 0x8B, 0x18, 0xBA, 0x62, 0x58,\n\t0xC2, 0x46, 0x29, 0x4A, 0x0F, 0x1C, 0xC8, 0xF1, 0x01, 0xB5, 0x58, 0x05,\n\t0x5E, 0xA7, 0x9E, 0xA1, 0x61, 0x25, 0xEB, 0xAA, 0x4C, 0x99, 0x97, 0xAB,\n\t0xE5, 0x6E, 0x56, 0xCB, 0x45, 0x78, 0x32, 0xEE, 0x3D, 0x99, 0xB6, 0x98,\n\t0xAC, 0x66, 0x2E, 0x59, 0x8D, 0xFC, 0xC9, 0xDB, 0x73, 0xE2, 0xE2, 0x1C,\n\t0xAA, 0xAB, 0xE7, 0x4C, 0x5D, 0x6D, 0xB4, 0x21, 0x6A, 0x3A, 0x34, 0x51,\n\t0xF3, 0xCD, 0xA4, 0xCA, 0x0C, 0xD3, 0x49, 0x84, 0xA6, 0x3E, 0xE4, 0x4C,\n\t0x3D, 0xC8, 0x0F, 0x88, 0xD1, 0x63, 0xCB, 0x29, 0x45, 0x00, 0x14, 0x6C,\n\t0x01, 0x59, 0x57, 0xC6, 0x87, 0x50, 0x02, 0xEB, 0xEA, 0x34, 0xEB, 0x6A,\n\t0x6C, 0xED, 0xF3, 0x37, 0x45, 0xD5, 0xE9, 0xE8, 0x88, 0x2A, 0x93, 0x8F,\n\t0x4A, 0x82, 0x33, 0x26, 0x6E, 0x33, 0x37, 0xA8, 0x71, 0x06, 0xAB, 0xB7,\n\t0x29, 0x8E, 0x3B, 0xA3, 0x24, 0x9A, 0x9F, 0x06, 0x3D, 0xA2, 0x05, 0xAF,\n\t0xBB, 0xD4, 0xE8, 0xC5, 0xEB, 0xF4, 0xB6, 0xA8, 0x4F, 0x52, 0xA1, 0x19,\n\t0x5B, 0xED, 0xBE, 0x65, 0x87, 0x02, 0x18, 0x23, 0x38, 0x3D, 0xBD, 0x86,\n\t0x45, 0x44, 0xC0, 0x47, 0x48, 0x8C, 0x37, 0x14, 0xE0, 0x50, 0x83, 0x30,\n\t0x08, 0xE8, 0xEF, 0x69, 0x5B, 0xC2, 0x73, 0xE8, 0x59, 0xB3, 0x0B, 0x33,\n\t0x5A, 0x47, 0x60, 0x34, 0xB0, 0xF2, 0xB0, 0x62, 0x2E, 0xC7, 0xA9, 0x8A,\n\t0xB9, 0xD3, 0x0D, 0x1B, 0xCC, 0xD5, 0x7C, 0x30, 0x54, 0x83, 0x6A, 0x6D,\n\t0xD5, 0x88, 0x0E, 0x1C, 0x60, 0x80, 0xD9, 0x90, 0x5C, 0x4F, 0xA2, 0xA3,\n\t0x12, 0xF4, 0xC4, 0xF2, 0xB4, 0xB0, 0xC1, 0x99, 0xA2, 0x8D, 0x8F, 0xA7,\n\t0xC0, 0x86, 0x46, 0x40, 0x54, 0xCC, 0xB5, 0xDC, 0x55, 0xF9, 0xA0, 0x32,\n\t0xBC, 0x71, 0x0E, 0xD3, 0xBD, 0xFB, 0x43, 0x44, 0x71, 0x09, 0xBF, 0xC2,\n\t0x21, 0x11, 0xA5, 0x12, 0xFC, 0x11, 0xB3, 0xD0, 0xD9, 0xB7, 0x97, 0xBF,\n\t0x37, 0xA9, 0xA6, 0xCE, 0xFB, 0xBF, 0x9C, 0x3D, 0x44, 0x2C, 0x81, 0x9E,\n\t0xD9, 0x40, 0x9F, 0x15, 0xAD, 0xCF, 0xEB, 0x03, 0x2A, 0x00, 0xA0, 0x3E,\n\t0xB0, 0x87, 0x01, 0x11, 0x66, 0x4E, 0x94, 0x42, 0x98, 0x1B, 0x3B, 0xBB,\n\t0xF3, 0x01, 0x0F, 0x4D, 0x6B, 0x03, 0x27, 0x62, 0x38, 0x69, 0x8F, 0x42,\n\t0x46, 0x75, 0x4A, 0x8A, 0x46, 0x8D, 0x14, 0xDD, 0x02, 0xBA, 0x85, 0xEA,\n\t0x2A, 0x79, 0xAC, 0x2B, 0x52, 0x95, 0x77, 0xC7, 0x8B, 0xB3, 0xBD, 0x47,\n\t0x08, 0xD2, 0x7B, 0x26, 0xA8, 0x00, 0x69, 0x2E, 0x6B, 0x48, 0x7F, 0x86,\n\t0xEC, 0xD9, 0x31, 0x23, 0x9E, 0x50, 0xF5, 0x42, 0x55, 0x44, 0x20, 0x47,\n\t0x0B, 0x54, 0x03, 0xA7, 0x08, 0xD1, 0x55, 0x8F, 0x8D, 0xC8, 0x28, 0xD5,\n\t0x17, 0xB3, 0x95, 0x79, 0x9D, 0xF0, 0xBF, 0x2A, 0x8E, 0xA2, 0x2C, 0x69,\n\t0xAB, 0x6C, 0x79, 0x9F, 0x85, 0x2A, 0xDE, 0x22, 0x5B, 0xF8, 0x72, 0x5A,\n\t0xFE, 0xA8, 0x28, 0x7E, 0x77, 0xAB, 0x8A, 0xD3, 0xB9, 0xFF, 0x44, 0x23,\n\t0x42, 0x58, 0x1A, 0xFA, 0x3F, 0x15, 0x2F, 0x82, 0x03, 0x16, 0x5E, 0x28,\n\t0xB2, 0x94, 0x61, 0x03, 0x16, 0xDE, 0xD6, 0xF2, 0x63, 0xD1, 0xB6, 0x56,\n\t0x9C, 0x1B, 0x84, 0x6D, 0x29, 0xC8, 0x82, 0xB3, 0xAD, 0x71, 0xA0, 0x4D,\n\t0x66, 0x6C, 0xDD, 0x24, 0x78, 0xCF, 0xD0, 0x2C, 0x0D, 0x6C, 0x5D, 0x86,\n\t0xC5, 0xE5, 0x76, 0x1B, 0x4F, 0x97, 0xD5, 0x71, 0xE1, 0xFB, 0x80, 0xCB,\n\t0xC0, 0x33, 0x17, 0xB3, 0x31, 0x5C, 0xE8, 0xB1, 0x28, 0xFE, 0xC9, 0x28,\n\t0x42, 0xC2, 0xA2, 0xC4, 0x72, 0x0A, 0xD0, 0x06, 0xB5, 0x53, 0x07, 0x09,\n\t0x68, 0x02, 0xF8, 0x58, 0x16, 0x5D, 0x03, 0xD0, 0x0F, 0xF2, 0xF1, 0x14,\n\t0x5C, 0x68, 0x0D, 0x02, 0xD5, 0x51, 0xE1, 0x10, 0x3D, 0x08, 0x0D, 0x84,\n\t0xF5, 0xEF, 0x01, 0x34, 0x37, 0xD6, 0x1F, 0xA1, 0x4D, 0x11, 0x8A, 0x2D,\n\t0x3F, 0x62, 0x48, 0x93, 0x16, 0x43, 0xD4, 0xD8, 0x1D, 0x0B, 0x0F, 0x1F,\n\t0x8F, 0xF5, 0xF0, 0x7A, 0xAC, 0xE9, 0xB5, 0x3A, 0xD3, 0xBC, 0x76, 0x36,\n\t0xE0, 0xE5, 0x16, 0x65, 0x65, 0x3B, 0x61, 0x68, 0x37, 0x1F, 0x44, 0x13,\n\t0x14, 0x05, 0x53, 0xE8, 0xE7, 0xE3, 0x75, 0xDF, 0x7A, 0x11, 0x67, 0x93,\n\t0x6C, 0x70, 0x62, 0x87, 0x98, 0xD6, 0x66, 0xF0, 0xE9, 0xB5, 0x71, 0xBA,\n\t0xE3, 0x74, 0x72, 0x07, 0x3A, 0x23, 0x9C, 0xA6, 0x2B, 0xC2, 0x69, 0xF8,\n\t0x74, 0x13, 0x09, 0xA7, 0x9D, 0xF0, 0xC0, 0x31, 0x02, 0xFD, 0x00, 0xFA,\n\t0x65, 0x4E, 0x3B, 0x5B, 0x54, 0x38, 0xB2, 0xF1, 0x15, 0xB7, 0x06, 0xC2,\n\t0x11, 0x23, 0x41, 0x39, 0x33, 0x66, 0xDB, 0x32, 0xC9, 0xCA, 0xC6, 0x50,\n\t0x2C, 0x76, 0xC9, 0x17, 0x0B, 0xE1, 0xD4, 0x55, 0xCB, 0x5A, 0x9D, 0x5A,\n\t0x44, 0xA7, 0xF9, 0x6B, 0xC6, 0x34, 0x5D, 0x2C, 0x58, 0x13, 0x55, 0xB1,\n\t0xDE, 0x3D, 0x0A, 0x1E, 0x51, 0xF1, 0xD3, 0x88, 0x8A, 0xDB, 0x0E, 0x62,\n\t0x16, 0xA0, 0xEB, 0xAD, 0x1C, 0xB6, 0xA2, 0x54, 0x6C, 0xCC, 0xA1, 0xAB,\n\t0xC8, 0x4E, 0x4D, 0xD7, 0x74, 0x69, 0x80, 0x84, 0x38, 0x18, 0xBE, 0x01,\n\t0x8B, 0x65, 0xD1, 0x58, 0x4E, 0x39, 0x14, 0x41, 0x25, 0x22, 0x12, 0x23,\n\t0x73, 0x71, 0xAB, 0x6F, 0xC2, 0x99, 0x0F, 0x93, 0x78, 0x85, 0xB4, 0x16,\n\t0x72, 0x84, 0x78, 0x8D, 0x31, 0x6F, 0xA8, 0x55, 0xC4, 0x23, 0x72, 0x6B,\n\t0xCE, 0x74, 0x00, 0x5C, 0x90, 0xA2, 0x4A, 0x6E, 0xF4, 0xB6, 0x28, 0xBA,\n\t0xEA, 0x4C, 0xE7, 0x8E, 0xC3, 0xB7, 0x35, 0xCD, 0xFA, 0xDD, 0x6D, 0x9D,\n\t0x3C, 0x97, 0x4B, 0x81, 0xBB, 0xED, 0xA4, 0xD8, 0xE2, 0x76, 0xC2, 0xCE,\n\t0x46, 0xEA, 0x50, 0x07, 0x25, 0x38, 0x77, 0x82, 0x4F, 0xFA, 0xB0, 0x71,\n\t0x8C, 0xE2, 0x84, 0x4F, 0xB6, 0xBD, 0xA3, 0xD7, 0xCD, 0x21, 0xD6, 0xC7,\n\t0x16, 0x34, 0xF8, 0x64, 0x7A, 0x29, 0xE7, 0x8E, 0xF7, 0x29, 0xD8, 0xEC,\n\t0x88, 0x9B, 0x0A, 0xF4, 0x8D, 0x22, 0x24, 0x57, 0x62, 0x49, 0xEA, 0xD9,\n\t0xE9, 0x40, 0x9E, 0x87, 0x86, 0xFC, 0x2D, 0xA5, 0xE3, 0xC3, 0xCC, 0x0E,\n\t0x34, 0x68, 0x59, 0x92, 0x52, 0x8E, 0x62, 0x83, 0x43, 0xDC, 0xCB, 0xDB,\n\t0xC2, 0x10, 0x54, 0x48, 0x2E, 0x09, 0x05, 0xA7, 0x08, 0x83, 0x69, 0xDE,\n\t0x54, 0x21, 0xD4, 0xF1, 0x08, 0x64, 0x91, 0x5D, 0x4B, 0x54, 0xE8, 0x8B,\n\t0xD4, 0xC5, 0x67, 0xE1, 0x40, 0x79, 0xFE, 0xF3, 0x83, 0x19, 0xAA, 0xF0,\n\t0x6C, 0x80, 0x97, 0x2E, 0x5D, 0x08, 0xF0, 0xC2, 0x77, 0x47, 0x6A, 0x3E,\n\t0x20, 0x94, 0x6D, 0xBA, 0x54, 0xDD, 0x66, 0x4B, 0x15, 0xD1, 0xEA, 0x64,\n\t0x86, 0x2A, 0xE2, 0x53, 0xB2, 0x10, 0x39, 0x51, 0x34, 0x07, 0x0C, 0x67,\n\t0xAA, 0x36, 0x06, 0xD7, 0xBE, 0xA9, 0x33, 0xBD, 0x38, 0x98, 0x3C, 0x3F,\n\t0x60, 0x12, 0xC6, 0x3A, 0x14, 0x4B, 0x4E, 0x4A, 0x6E, 0xF5, 0xB6, 0xE7,\n\t0x3A, 0x43, 0x8F, 0xBE, 0x81, 0xCF, 0x0E, 0x4D, 0x25, 0x87, 0x16, 0x14,\n\t0x04, 0x44, 0x95, 0x5C, 0x72, 0x9C, 0x0E, 0x0E, 0x36, 0x10, 0x09, 0x51,\n\t0x66, 0x92, 0x5E, 0xAA, 0x0C, 0x52, 0xBC, 0x85, 0xF0, 0xF5, 0x10, 0x06,\n\t0x3F, 0xD0, 0x29, 0x8C, 0x62, 0x14, 0x2A, 0x1A, 0xD5, 0xE7, 0x33, 0xCA,\n\t0x4F, 0xDE, 0xF3, 0xE7, 0x3F, 0x8B, 0xA6, 0x31, 0xC1, 0x67, 0x02, 0x59,\n\t0x92, 0xD0, 0xC5, 0xF7, 0x3B, 0xF4, 0x4E, 0xC5, 0x89, 0x20, 0x20, 0x88,\n\t0x62, 0xCA, 0x41, 0xAE, 0x64, 0x8E, 0xF5, 0xA1, 0x39, 0x47, 0x79, 0xFC,\n\t0x7A, 0x73, 0x09, 0xC7, 0x30, 0x4D, 0x3E, 0x50, 0x82, 0x4E, 0x97, 0x34,\n\t0x1A, 0xAC, 0xB7, 0x3E, 0x8C, 0xCC, 0x48, 0x5B, 0xEB, 0x67, 0x92, 0x99,\n\t0x00, 0x07, 0xD0, 0x9D, 0x80, 0x21, 0x1E, 0xEE, 0xED, 0x0D, 0x73, 0x7E,\n\t0xCA, 0xC9, 0xE2, 0x97, 0x5C, 0xCF, 0x17, 0x47, 0x8F, 0xEC, 0x27, 0x89,\n\t0xD0, 0x8A, 0x05, 0x4E, 0xAB, 0x18, 0xA3, 0x78, 0x87, 0x69, 0xA3, 0x80,\n\t0x26, 0xB5, 0xEB, 0x7C, 0x76, 0xAC, 0x6D, 0xDB, 0xDA, 0xD0, 0x2C, 0x55,\n\t0x4E, 0x2F, 0x60, 0x42, 0x16, 0x5A, 0x30, 0xF1, 0x38, 0xEF, 0xE9, 0xEF,\n\t0xA7, 0x81, 0x0B, 0x32, 0x54, 0xB8, 0x11, 0x86, 0xE0, 0x5A, 0xF2, 0xBA,\n\t0xBD, 0xB9, 0xB5, 0x2D, 0x30, 0x2E, 0xF8, 0x4F, 0x74, 0x12, 0xD1, 0x1C,\n\t0x5E, 0xB5, 0xB3, 0x6A, 0xE7, 0x78, 0x44, 0xDB, 0xEE, 0x33, 0xFF, 0xD0,\n\t0x50, 0xA7, 0x8C, 0x17, 0xBF, 0x00, 0xE5, 0x8D, 0x0A, 0x05, 0xCA, 0x14,\n\t0xA9, 0x9F, 0x52, 0x96, 0x22, 0xF5, 0x50, 0x9A, 0x5B, 0x50, 0x3B, 0x1E,\n\t0x5C, 0xB4, 0x92, 0x42, 0xA0, 0xDE, 0xA3, 0x00, 0xEA, 0xB6, 0x69, 0xE3,\n\t0x4B, 0xD6, 0xC8, 0xAF, 0x18, 0x98, 0x3A, 0xB9, 0x63, 0x0A, 0x0D, 0x31,\n\t0x49, 0xC8, 0x12, 0x14, 0x1E, 0x40, 0x8F, 0x29, 0x66, 0x0A, 0xC7, 0xBA,\n\t0xAD, 0x2A, 0x8A, 0x87, 0x54, 0x37, 0x43, 0xD3, 0x70, 0x4E, 0xD6, 0xD1,\n\t0x73, 0xB0, 0xEE, 0xD0, 0x87, 0x9C, 0xE3, 0x3E, 0xE2, 0x5C, 0x16, 0xEB,\n\t0x68, 0xF6, 0x8A, 0x89, 0xB4, 0x00, 0xAA, 0xF4, 0x95, 0xA0, 0x81, 0xC8,\n\t0xF2, 0x8A, 0xE0, 0xF7, 0xCB, 0x1A, 0x6F, 0x9F, 0xBA, 0x3D, 0x22, 0x7B,\n\t0xDF, 0x06, 0xE5, 0xED, 0x90, 0x04, 0x61, 0xB4, 0x3D, 0x11, 0xC2, 0x35,\n\t0xC4, 0x3A, 0x1D, 0xB1, 0xDC, 0x69, 0x0F, 0x5E, 0x9E, 0xE5, 0x78, 0x44,\n\t0x8C, 0x0D, 0xB1, 0x7C, 0xCC, 0x4E, 0x55, 0x59, 0x09, 0x63, 0xC0, 0x53,\n\t0x21, 0x88, 0x14, 0x41, 0xE4, 0xC5, 0x40, 0x38, 0x20, 0x71, 0x4D, 0xD1,\n\t0x95, 0x0C, 0xCD, 0x6A, 0xD3, 0x67, 0x89, 0x10, 0xD5, 0x08, 0xD2, 0x08,\n\t0xAE, 0xB5, 0x2E, 0x11, 0xBE, 0xE5, 0x4A, 0x11, 0x8A, 0x11, 0x25, 0xD0,\n\t0xF3, 0x00, 0xC6, 0x4F, 0x00, 0x8D, 0x31, 0x97, 0xC5, 0xE4, 0x42, 0xAE,\n\t0x0C, 0x24, 0x11, 0xB1, 0xC3, 0xC7, 0xB3, 0x73, 0x3B, 0xC6, 0x62, 0x65,\n\t0xCE, 0x0A, 0x90, 0x3E, 0x70, 0xA8, 0xA0, 0x41, 0xAA, 0x10, 0xA6, 0x98,\n\t0x01, 0x79, 0x76, 0x06, 0xA9, 0xE4, 0xCD, 0x04, 0xE5, 0x6F, 0x57, 0xD2,\n\t0xB4, 0xA7, 0xD1, 0x1A, 0x4F, 0x6C, 0x9E, 0xA2, 0xFC, 0x3A, 0xA8, 0xAB,\n\t0xD9, 0x24, 0xDB, 0x3C, 0x2A, 0xED, 0xCC, 0x9C, 0x66, 0x02, 0x94, 0x11,\n\t0xAC, 0x53, 0x91, 0xE7, 0xF5, 0xD0, 0x74, 0xDE, 0x0E, 0x68, 0x43, 0x26,\n\t0xFE, 0x33, 0x9A, 0x28, 0x20, 0x38, 0x40, 0xD0, 0xCC, 0x1D, 0x03, 0x40,\n\t0x45, 0x17, 0xA0, 0x98, 0x17, 0xCA, 0x3A, 0x6C, 0x55, 0x27, 0x44, 0xE1,\n\t0xCD, 0xFB, 0x06, 0x2F, 0x2A, 0x98, 0x70, 0xD9, 0x3A, 0x42, 0x46, 0x93,\n\t0xA9, 0xF5, 0x95, 0xBC, 0xFA, 0xDA, 0xCE, 0xEA, 0x6B, 0xD4, 0x8E, 0x4D,\n\t0xB1, 0x84, 0xFC, 0x2E, 0x38, 0xA2, 0x79, 0xEA, 0xAB, 0xCD, 0xF0, 0xF5,\n\t0x44, 0x03, 0xEC, 0x9F, 0xBB, 0xD4, 0x85, 0x3F, 0x03, 0x55, 0xA1, 0x10,\n\t0x0D, 0x0C, 0x91, 0x89, 0x93, 0x48, 0x26, 0x88, 0xD8, 0x21, 0x1F, 0xA8,\n\t0xBD, 0xAF, 0xE1, 0x67, 0xCE, 0x52, 0xC8, 0x4E, 0x5A, 0x95, 0x14, 0x13,\n\t0x48, 0x05, 0x79, 0x10, 0x79, 0xCD, 0x63, 0xC8, 0xEB, 0x3C, 0x3F, 0x5E,\n\t0xE7, 0x51, 0xA2, 0x8B, 0x4D, 0x97, 0x25, 0xA8, 0x80, 0x44, 0x56, 0x0D,\n\t0x86, 0x33, 0xDD, 0x81, 0x01, 0xE6, 0x50, 0x45, 0x19, 0xC6, 0x09, 0xD3,\n\t0x15, 0xB5, 0x5B, 0x23, 0x82, 0x5B, 0x9F, 0x38, 0x14, 0x8B, 0xFE, 0x58,\n\t0xEC, 0xAC, 0xD6, 0xEC, 0x06, 0x7E, 0x07, 0x02, 0x70, 0xF6, 0x8A, 0x1A,\n\t0x19, 0x9E, 0xBB, 0x46, 0xB0, 0xB3, 0xD2, 0x5A, 0xEB, 0xAA, 0x06, 0xB2,\n\t0x69, 0xB5, 0x1E, 0x50, 0x0C, 0x07, 0xA3, 0x1B, 0x38, 0x18, 0x01, 0x9F,\n\t0xF4, 0x31, 0xC2, 0xD0, 0xF7, 0x07, 0x48, 0x07, 0x07, 0x9B, 0xCC, 0xE9,\n\t0xEC, 0xBC, 0xE4, 0x67, 0x71, 0x90, 0xA6, 0x82, 0xB3, 0xD7, 0x8C, 0xD2,\n\t0x52, 0xA5, 0xEB, 0xEC, 0x83, 0x6C, 0x77, 0x2B, 0xE8, 0x65, 0xD6, 0xDF,\n\t0x4D, 0x12, 0x9D, 0x9D, 0x2C, 0x9E, 0x2D, 0xE6, 0xEC, 0x5D, 0x38, 0xBB,\n\t0x4D, 0x85, 0x5C, 0x50, 0x20, 0x74, 0xF9, 0x68, 0xE0, 0x04, 0x5E, 0x41,\n\t0xDD, 0x8A, 0xB3, 0xEB, 0x74, 0x27, 0x22, 0x02, 0x83, 0xA8, 0xAA, 0xFE,\n\t0x56, 0xF0, 0x98, 0xF0, 0x82, 0x4C, 0x9F, 0x11, 0xCF, 0xE3, 0x11, 0x57,\n\t0x6D, 0x3C, 0x9E, 0x16, 0x68, 0xDE, 0x33, 0x28, 0x3E, 0x53, 0xF5, 0xBB,\n\t0xC2, 0x55, 0x41, 0x5B, 0x70, 0x88, 0xBE, 0x3E, 0x7D, 0xCE, 0xE5, 0x7E,\n\t0xF4, 0xB2, 0x9A, 0xD6, 0xB3, 0x01, 0x89, 0x34, 0xBA, 0x5B, 0x35, 0x1D,\n\t0x1F, 0xAA, 0xAF, 0x2E, 0xD1, 0x48, 0x7E, 0x23, 0x69, 0xE2, 0x44, 0xEF,\n\t0x08, 0x3D, 0x48, 0xF9, 0x21, 0xC6, 0xF0, 0xC3, 0xB0, 0xB2, 0x1E, 0x9D,\n\t0x28, 0x9E, 0xB1, 0x78, 0x91, 0x6A, 0x7C, 0xBD, 0x20, 0x5F, 0x69, 0x9B,\n\t0x20, 0x61, 0xDF, 0xDB, 0x25, 0xDA, 0x22, 0x99, 0x16, 0x86, 0xA5, 0x10,\n\t0x9C, 0x20, 0x46, 0x84, 0xE1, 0x0B, 0xD3, 0x27, 0x0C, 0x10, 0xDB, 0x82,\n\t0xEF, 0x2B, 0x05, 0x5F, 0x32, 0x8D, 0xEC, 0xD9, 0x18, 0x43, 0x30, 0x21,\n\t0x8F, 0x9E, 0xB9, 0x35, 0x04, 0xD3, 0x0C, 0x3A, 0x16, 0x28, 0x86, 0x91,\n\t0x41, 0x07, 0x0B, 0x22, 0x34, 0xE0, 0x80, 0x83, 0x41, 0x42, 0xCA, 0x04,\n\t0x41, 0xDB, 0x04, 0x65, 0x66, 0x10, 0x31, 0x66, 0x4C, 0xA2, 0x63, 0xE2,\n\t0x80, 0x08, 0xA6, 0xE0, 0x6C, 0xC2, 0xB2, 0x9F, 0xA1, 0x48, 0x25, 0xA0,\n\t0xAE, 0xE9, 0x63, 0x01, 0xA1, 0x0C, 0xBA, 0x2E, 0xF4, 0xE9, 0x62, 0xC5,\n\t0x04, 0xAE, 0x32, 0xC7, 0xC8, 0xA2, 0xFC, 0xAC, 0xDE, 0xE7, 0xCF, 0xA4,\n\t0xA2, 0x46, 0xCE, 0x95, 0x95, 0x13, 0x46, 0xD3, 0x43, 0xCC, 0x9A, 0xF0,\n\t0x54, 0x54, 0x8D, 0xE5, 0xAA, 0xEA, 0xF6, 0x7E, 0xC6, 0x4F, 0x1D, 0x00,\n\t0x66, 0x7F, 0x45, 0x47, 0x57, 0x29, 0xFE, 0x0E, 0xAB, 0xA0, 0xAB, 0x5B,\n\t0xF9, 0x39, 0x75, 0xA6, 0x6B, 0x12, 0x7F, 0x74, 0x47, 0x36, 0x5A, 0xEB,\n\t0x6D, 0x41, 0x0F, 0x93, 0x26, 0xA0, 0xFC, 0x9B, 0x90, 0xA0, 0xC4, 0x02,\n\t0xF3, 0x1F, 0x20, 0xFA, 0x60, 0xED, 0x34, 0x52, 0x7F, 0x02, 0x6B, 0x21,\n\t0x84, 0x79, 0x31, 0xCC, 0xC1, 0x08, 0xB9, 0x04, 0x6B, 0x93, 0xE3, 0x5B,\n\t0x50, 0x62, 0x74, 0x0B, 0x12, 0xAC, 0x67, 0xE4, 0xE8, 0xA7, 0xF3, 0xA8,\n\t0x2E, 0x68, 0x74, 0x5D, 0x5B, 0x34, 0x71, 0x8C, 0x8C, 0xD2, 0x63, 0x61,\n\t0xC2, 0x9E, 0x3C, 0x39, 0xAE, 0x44, 0x6B, 0xA0, 0x0D, 0xAD, 0xCE, 0x2A,\n\t0x4A, 0x3B, 0xA7, 0x28, 0xE9, 0xFD, 0x2C, 0x6D, 0x63, 0xB8, 0xB4, 0xD3,\n\t0xFA, 0xDD, 0xCA, 0x25, 0x6E, 0x46, 0xEA, 0x36, 0xFA, 0xCF, 0x80, 0xFA,\n\t0x1B, 0x45, 0x61, 0xE9, 0x93, 0x07, 0xE2, 0x54, 0x4C, 0x80, 0x05, 0xC3,\n\t0x88, 0xD4, 0xB2, 0x58, 0x36, 0x83, 0x8C, 0x06, 0xA3, 0x1A, 0x8C, 0xA2,\n\t0x0E, 0x50, 0xB3, 0xB3, 0x32, 0xD3, 0x29, 0x06, 0x50, 0x4B, 0x9F, 0x8F,\n\t0x30, 0xBA, 0x2E, 0x29, 0x1B, 0xB8, 0x78, 0xBD, 0x49, 0x0F, 0x8C, 0x10,\n\t0xE3, 0xE8, 0xDA, 0xB6, 0x35, 0x92, 0x0A, 0xE1, 0x50, 0x35, 0xF5, 0x93,\n\t0x76, 0x2E, 0xB3, 0xF5, 0x62, 0x31, 0xA7, 0x3D, 0xF1, 0xCC, 0x30, 0x3B,\n\t0xFE, 0x4A, 0x70, 0x86, 0x99, 0xE3, 0xE0, 0x90, 0xA1, 0xCC, 0x71, 0x8E,\n\t0x1E, 0x0C, 0x95, 0x99, 0xE7, 0x0F, 0x69, 0x6B, 0x1C, 0x19, 0x3F, 0xF3,\n\t0xF9, 0x86, 0x83, 0xA5, 0x25, 0xBA, 0x03, 0x07, 0x4B, 0x7E, 0x5E, 0x01,\n\t0xD8, 0xA3, 0x00, 0x8B, 0x38, 0xAA, 0x8E, 0x17, 0x6A, 0xFE, 0xDE, 0x88,\n\t0x3D, 0xC5, 0x94, 0xCA, 0x67, 0x93, 0xBE, 0xAE, 0x94, 0x26, 0x8C, 0x16,\n\t0xAA, 0x20, 0x39, 0xD3, 0xAF, 0x67, 0x48, 0x72, 0x84, 0x12, 0xAC, 0x94,\n\t0xB0, 0x1D, 0x2B, 0x32, 0x10, 0x79, 0x76, 0xD0, 0x9E, 0x64, 0x01, 0x72,\n\t0x04, 0x21, 0x5B, 0x44, 0x0A, 0x90, 0xAB, 0x31, 0x55, 0x60, 0x09, 0xE3,\n\t0xB3, 0x2B, 0xBB, 0x7A, 0x6F, 0xAC, 0x87, 0xD8, 0xD5, 0x3D, 0xBE, 0xAE,\n\t0xCE, 0xA2, 0xC4, 0x83, 0xCA, 0x50, 0x8E, 0xC6, 0x50, 0xD2, 0xF1, 0x41,\n\t0x39, 0x9D, 0x39, 0x2D, 0x94, 0xBB, 0x81, 0x29, 0x4F, 0xCE, 0x51, 0x9E,\n\t0xDC, 0x53, 0xCE, 0x94, 0x5B, 0xD1, 0x08, 0xA1, 0x46, 0xE2, 0x95, 0x0C,\n\t0x5F, 0xF8, 0x5D, 0xA2, 0x3E, 0xBB, 0x82, 0x7A, 0x79, 0x64, 0x13, 0x51,\n\t0x32, 0xFC, 0x71, 0x15, 0x95, 0x99, 0x30, 0x81, 0xD4, 0x3C, 0xC7, 0x0B,\n\t0xB0, 0xBB, 0xA7, 0x25, 0x02, 0xE4, 0xCF, 0x28, 0x0C, 0x70, 0xBC, 0x45,\n\t0xEE, 0xD3, 0xB0, 0x42, 0x09, 0x37, 0xF6, 0x19, 0xBD, 0xEB, 0xA9, 0x0A,\n\t0x0C, 0xAA, 0x4D, 0x84, 0xFE, 0xB4, 0xE8, 0xD0, 0xB4, 0xD1, 0x4D, 0x53,\n\t0xD0, 0x09, 0x74, 0x0A, 0x9D, 0x75, 0x47, 0x48, 0xE4, 0x8D, 0xF1, 0x26,\n\t0x3C, 0x47, 0xD6, 0x77, 0x24, 0x95, 0xA2, 0xF7, 0x0A, 0x50, 0x2E, 0x91,\n\t0x39, 0x86, 0xE4, 0x60, 0x3E, 0x04, 0x87, 0xCA, 0x05, 0x4B, 0x07, 0xCC,\n\t0xEF, 0x0D, 0xCB, 0xE5, 0xD8, 0xB0, 0xFC, 0xF2, 0xB0, 0xFC, 0xBE, 0xE1,\n\t0x53, 0x73, 0xFA, 0xC4, 0xD2, 0x66, 0xAD, 0xD3, 0xE1, 0x14, 0xC4, 0x01,\n\t0x03, 0xFA, 0x08, 0x1D, 0xB0, 0xB5, 0x6D, 0xEF, 0x40, 0x94, 0x38, 0x14,\n\t0x32, 0x43, 0xF9, 0x0C, 0x47, 0x5F, 0x02, 0xE1, 0x0D, 0xA5, 0x3D, 0xAE,\n\t0xA0, 0x6A, 0x16, 0x10, 0xEB, 0x40, 0xEE, 0x86, 0x9C, 0xB1, 0x4C, 0xD6,\n\t0xC6, 0x30, 0x59, 0xC7, 0xA9, 0x29, 0x35, 0xB7, 0xA9, 0xD1, 0xF7, 0x9F,\n\t0xD6, 0x6A, 0x40, 0x5C, 0xA2, 0x66, 0x6E, 0x45, 0xE9, 0x5D, 0x9D, 0xEC,\n\t0x4B, 0x72, 0x62, 0x5E, 0xF0, 0x04, 0x04, 0xAA, 0xE0, 0x07, 0xD0, 0x6D,\n\t0x92, 0x46, 0xC6, 0x59, 0x58, 0x1A, 0xA5, 0xF7, 0xAB, 0xAE, 0x2D, 0x10,\n\t0x8E, 0xBD, 0x2D, 0xD2, 0x2A, 0x1A, 0x9C, 0x9E, 0xF6, 0xAE, 0x2A, 0xE9,\n\t0xD2, 0xBC, 0x87, 0x49, 0xF2, 0x52, 0xA8, 0x78, 0x40, 0x55, 0xE3, 0xC8,\n\t0xAF, 0x88, 0x3A, 0x7B, 0x71, 0xB7, 0xEB, 0x0E, 0x71, 0xB7, 0x4C, 0xFF,\n\t0x1C, 0x13, 0x77, 0x22, 0xB5, 0xC1, 0x8E, 0x1D, 0x3F, 0x3A, 0x74, 0x90,\n\t0xF0, 0x9A, 0xA1, 0x7C, 0x83, 0x04, 0x14, 0x6A, 0x44, 0x7B, 0xA6, 0x08,\n\t0x2C, 0x35, 0xA7, 0xA6, 0x5C, 0xD4, 0x7B, 0x71, 0x51, 0x97, 0xD5, 0x41,\n\t0x5E, 0x06, 0x08, 0xB7, 0xB2, 0xA6, 0xDD, 0x96, 0xF7, 0x45, 0xD3, 0x97,\n\t0xC5, 0x60, 0x52, 0x33, 0xBF, 0xA4, 0xAE, 0x12, 0x1A, 0x73, 0xF4, 0xDD,\n\t0x3E, 0x8B, 0x94, 0x84, 0x2F, 0xAD, 0x07, 0xA8, 0xA0, 0x45, 0x10, 0x40,\n\t0x0A, 0xC9, 0x31, 0xD0, 0x92, 0xBC, 0x51, 0xD4, 0xFB, 0x63, 0xA6, 0x8A,\n\t0x2A, 0x5C, 0x88, 0xD6, 0x5C, 0x67, 0x32, 0x35, 0x00, 0xF3, 0x85, 0x60,\n\t0x99, 0xF8, 0x62, 0xD2, 0x00, 0xC7, 0x1B, 0x17, 0x00, 0x38, 0x4E, 0x08,\n\t0x37, 0x32, 0x40, 0x67, 0x52, 0xD5, 0x78, 0x49, 0x58, 0x50, 0x8A, 0x24,\n\t0x03, 0x48, 0x42, 0xF7, 0xA5, 0xEA, 0x24, 0x0B, 0x55, 0x01, 0x99, 0x30,\n\t0xA8, 0x84, 0x8A, 0x51, 0xEA, 0xF5, 0x2C, 0x50, 0x5A, 0x54, 0x44, 0x00,\n\t0x00, 0x14, 0x09, 0x63, 0xF6, 0x61, 0x18, 0x4D, 0x41, 0x0C, 0x83, 0x81,\n\t0x34, 0x4C, 0x24, 0xDF, 0x01, 0x64, 0x45, 0x0B, 0x02, 0xC2, 0x86, 0x02,\n\t0x83, 0x11, 0x60, 0x34, 0x40, 0x1C, 0x14, 0x06, 0x08, 0x60, 0x32, 0x10,\n\t0xC9, 0x52, 0x01, 0x03, 0x31, 0x2C, 0x60, 0x00, 0x50, 0x08, 0x38, 0xC3,\n\t0x98, 0xAA, 0xA2, 0x01, 0xB3, 0x94, 0x5C, 0x47, 0x1B, 0x3D, 0x1F, 0x18,\n\t0x64, 0x4C, 0x44, 0x22, 0x31, 0x32, 0x44, 0x61, 0x54, 0x1F, 0xC8, 0x56,\n\t0x86, 0x98, 0xBC, 0xC5, 0x53, 0x92, 0xF7, 0x36, 0x10, 0xE0, 0x2E, 0x91,\n\t0x48, 0x77, 0xE3, 0x0C, 0x7F, 0x8A, 0x7E, 0xE3, 0xE7, 0x69, 0x94, 0xAC,\n\t0x23, 0xB0, 0x3C, 0x45, 0x7A, 0x5A, 0x22, 0xC3, 0xA3, 0x5B, 0xC3, 0x93,\n\t0x3E, 0xEA, 0x3B, 0xEC, 0xB8, 0xD3, 0xEF, 0xD5, 0x8D, 0x19, 0xE6, 0x2E,\n\t0x52, 0x84, 0x2F, 0x73, 0x03, 0x39, 0x52, 0xFB, 0x0C, 0x20, 0x60, 0x85,\n\t0x54, 0xAF, 0x16, 0x46, 0xF0, 0x8F, 0xEC, 0xFD, 0x58, 0x18, 0xEA, 0x14,\n\t0x1D, 0x3E, 0xD2, 0x79, 0x61, 0xC5, 0x2E, 0x5B, 0x8A, 0x2A, 0xF6, 0x53,\n\t0xDD, 0x33, 0x6E, 0xF8, 0x87, 0x00, 0x09, 0x68, 0x4C, 0x19, 0x22, 0xC6,\n\t0x79, 0x8A, 0x2B, 0x8F, 0xEB, 0x45, 0x22, 0xC0, 0x01, 0x5F, 0x42, 0x5A,\n\t0x76, 0x24, 0xF8, 0x24, 0x95, 0x39, 0x81, 0xF0, 0x30, 0x1E, 0xD8, 0x48,\n\t0x6D, 0xE9, 0x0B, 0x15, 0x86, 0xAF, 0x6A, 0x5B, 0x44, 0x5E, 0xFE, 0x6F,\n\t0x03, 0x38, 0xB3, 0x0D, 0x56, 0xE3, 0x9E, 0xBB, 0xED, 0x0A, 0x8F, 0x3B,\n\t0xB1, 0x32, 0x4C, 0xAE, 0xC7, 0x2E, 0xA9, 0xE8, 0xD6, 0xC4, 0x61, 0x4D,\n\t0xD0, 0x0D, 0xA9, 0x96, 0xAF, 0x3F, 0xF3, 0x9C, 0xA9, 0xBD, 0x03, 0x72,\n\t0x38, 0x1E, 0x6B, 0x99, 0x41, 0xB0, 0xCB, 0x84, 0xD9, 0xBC, 0x43, 0x6E,\n\t0xBB, 0x34, 0xA4, 0xC2, 0x92, 0xEF, 0xBD, 0xEA, 0x9C, 0x52, 0x88, 0x3B,\n\t0x18, 0x25, 0xFF, 0x9C, 0x55, 0xAC, 0x9D, 0x36, 0x5B, 0xCD, 0x18, 0xE6,\n\t0x96, 0x52, 0x93, 0x87, 0xEA, 0x6D, 0xFB, 0xAE, 0x9F, 0xB5, 0xB8, 0xDE,\n\t0xF8, 0x50, 0x02, 0x44, 0xF0, 0x1F, 0x02, 0xC0, 0x09, 0xF5, 0x98, 0xCE,\n\t0xC7, 0x11, 0xC8, 0xD5, 0x8F, 0xEE, 0xA8, 0x50, 0x42, 0xAA, 0x60, 0x9D,\n\t0x70, 0x56, 0x0A, 0xF6, 0x54, 0x45, 0xCB, 0xF9, 0x71, 0x1D, 0xCA, 0xE7,\n\t0x80, 0xC7, 0xB0, 0xAE, 0x33, 0x3E, 0x11, 0x00, 0x5D, 0x6F, 0xA7, 0x43,\n\t0xDC, 0x7E, 0x33, 0xAD, 0xA4, 0xE2, 0x9B, 0xC0, 0x09, 0xD5, 0x6B, 0xA4,\n\t0x49, 0x1A, 0xD4, 0xF7, 0xFC, 0x3E, 0x00, 0x70, 0xD8, 0x3E, 0xFE, 0x6A,\n\t0x60, 0x5C, 0x58, 0xC3, 0xE9, 0xC6, 0x4E, 0x16, 0x6F, 0xB2, 0xC6, 0x79,\n\t0x4D, 0x14, 0x37, 0x79, 0x28, 0xD5, 0xE5, 0xE7, 0xF6, 0x66, 0xE5, 0x22,\n\t0x1D, 0x7D, 0xC1, 0xFD, 0x1B, 0x32, 0xB9, 0x45, 0x01, 0x00, 0x3D, 0x26,\n\t0x25, 0x35, 0x00, 0x33, 0xA0, 0x83, 0xCF, 0xCC, 0xCD, 0xA7, 0x8E, 0x48,\n\t0xC5, 0xFA, 0x67, 0x2D, 0x87, 0xB9, 0xA1, 0x0E, 0x01, 0xA4, 0x33, 0x8A,\n\t0x0D, 0x98, 0xDC, 0xA1, 0x99, 0xCA, 0x5C, 0x75, 0xEE, 0x3B, 0xB3, 0x9A,\n\t0x4E, 0xDB, 0x66, 0x48, 0xA2, 0x3B, 0x0E, 0x6C, 0x87, 0xF9, 0xA0, 0x64,\n\t0x86, 0xA0, 0x99, 0x50, 0xAC, 0xB3, 0xF3, 0xC9, 0xDE, 0x76, 0x59, 0xC6,\n\t0x3B, 0xB1, 0x78, 0x47, 0x9F, 0xFA, 0xCF, 0x86, 0x2B, 0xBB, 0x3C, 0x23,\n\t0x60, 0x5A, 0x7E, 0xD3, 0x7A, 0xB3, 0xE3, 0xEE, 0xE7, 0xEE, 0x2F, 0xD1,\n\t0x44, 0x6C, 0xD0, 0x1A, 0x61, 0x12, 0x17, 0x18, 0x18, 0x36, 0x5F, 0x98,\n\t0x40, 0x86, 0x59, 0xF3, 0x31, 0x6D, 0xB3, 0xCD, 0xDB, 0x16, 0x2C, 0x3E,\n\t0x5F, 0x39, 0x59, 0xC0, 0x51, 0xE5, 0x19, 0x41, 0xAD, 0x41, 0x83, 0x54,\n\t0x5F, 0xB6, 0x9F, 0xB4, 0xA4, 0x74, 0x79, 0xD6, 0xF8, 0x4B, 0x5C, 0x7F,\n\t0xFF, 0x4F, 0x32, 0x7E, 0xF1, 0xB8, 0xD1, 0x2F, 0x1A, 0x59, 0x7C, 0x2C,\n\t0x89, 0x39, 0xDF, 0xD6, 0x1A, 0x45, 0xDB, 0x16, 0x05, 0x24, 0x24, 0x3F,\n\t0x27, 0xC9, 0xEE, 0x2D, 0xCE, 0x82, 0x09, 0xD6, 0x4B, 0x0C, 0xC7, 0x4D,\n\t0xBF, 0x17, 0x9C, 0xFD, 0xFE, 0x88, 0x07, 0x3C, 0x4F, 0xE9, 0x3C, 0x42,\n\t0x64, 0xF5, 0x70, 0xD4, 0x00, 0x08, 0x51, 0x4D, 0x22, 0x4B, 0x90, 0xEA,\n\t0x93, 0x17, 0x87, 0x6B, 0x32, 0x93, 0x40, 0xC5, 0x8F, 0xFB, 0x16, 0x12,\n\t0xC7, 0x7F, 0x70, 0xD0, 0x92, 0xC7, 0xAE, 0x18, 0x10, 0xEB, 0xD0, 0x1C,\n\t0xAB, 0xD2, 0x28, 0x27, 0xFE, 0x65, 0x41, 0x8F, 0x8A, 0x93, 0x79, 0xC3,\n\t0xE4, 0xC3, 0xD8, 0xAA, 0x2F, 0x7C, 0x0B, 0x2B, 0x04, 0xFA, 0xC5, 0x3F,\n\t0x42, 0x47, 0x15, 0x96, 0x1C, 0x14, 0x57, 0x39, 0x30, 0x14, 0xD3, 0xD0,\n\t0x9C, 0x95, 0x91, 0x85, 0xE5, 0xEF, 0x98, 0xBC, 0xDF, 0xAC, 0x8A, 0x62,\n\t0x81, 0x50, 0x68, 0x50, 0xA2, 0x48, 0x41, 0xE6, 0x35, 0xEB, 0x7F, 0x31,\n\t0xDB, 0xD5, 0x16, 0xE1, 0x2E, 0x2F, 0x36, 0x1C, 0x7A, 0xF3, 0xFF, 0x9A,\n\t0x5F, 0x10, 0xA4, 0x7A, 0x8F, 0xF0, 0x4B, 0xCE, 0xFF, 0xDD, 0x67, 0x7D,\n\t0x1D, 0x6F, 0x1A, 0x5B, 0x06, 0x86, 0xC6, 0x3C, 0x47, 0x3B, 0xC3, 0x03,\n\t0x70, 0xBA, 0x3A, 0xBE, 0xF0, 0x4C, 0xA5, 0x32, 0xE0, 0x28, 0xB9, 0x3E,\n\t0x5B, 0xBD, 0xE1, 0x0D, 0xD7, 0xB3, 0xE7, 0xC8, 0xEB, 0x18, 0x59, 0x53,\n\t0xC7, 0x26, 0xEB, 0xEC, 0x23, 0xBE, 0x07, 0x29, 0x04, 0x88, 0x77, 0x27,\n\t0xBF, 0x62, 0x25, 0x24, 0xB4, 0x1B, 0x6E, 0x4B, 0xEF, 0x6E, 0xE5, 0x32,\n\t0xE9, 0x29, 0xEA, 0x88, 0xCF, 0x2D, 0x00, 0x8D, 0xCB, 0x6D, 0x34, 0x6E,\n\t0xE9, 0x28, 0x33, 0x68, 0xB1, 0x5B, 0x11, 0xDE, 0x60, 0x02, 0x45, 0x05,\n\t0x2B, 0x89, 0xE8, 0x9A, 0x01, 0x62, 0x17, 0x44, 0x1D, 0x1C, 0x34, 0xA4,\n\t0xD9, 0x92, 0x90, 0xE7, 0xAF, 0x3A, 0xFC, 0xA0, 0x57, 0x32, 0x4E, 0x2F,\n\t0x7A, 0x2C, 0xF1, 0xF2, 0x93, 0x15, 0xD8, 0xCB, 0x8B, 0x7B, 0x1A, 0x57,\n\t0x48, 0x58, 0xBA, 0x19, 0x34, 0x44, 0x9D, 0xD1, 0x34, 0x09, 0x36, 0xB3,\n\t0xFC, 0x76, 0x43, 0x57, 0x31, 0x19, 0x5E, 0xFA, 0xD6, 0x48, 0x31, 0xD3,\n\t0xCA, 0x95, 0x77, 0x8B, 0x99, 0xD4, 0x68, 0xB9, 0xBE, 0x4C, 0x5E, 0x8E,\n\t0x9E, 0xD1, 0x0A, 0xE3, 0x2F, 0xA9, 0x8E, 0xBE, 0x77, 0xC9, 0x5C, 0xB9,\n\t0xD9, 0xF5, 0xA1, 0x86, 0xBF, 0x75, 0x96, 0xF3, 0x8D, 0x26, 0x5D, 0x4D,\n\t0x7B, 0x96, 0x9D, 0x1F, 0x4D, 0x11, 0x3A, 0xC9, 0xF7, 0xA6, 0xBD, 0xE2,\n\t0xBC, 0xD4, 0x5B, 0xDB, 0x7D, 0xF3, 0xAA, 0xE8, 0x3B, 0xC9, 0xD9, 0x20,\n\t0x4A, 0x2A, 0x09, 0x1B, 0x36, 0x9B, 0xA0, 0x0C, 0x0A, 0x33, 0x4C, 0x82,\n\t0xB7, 0x6B, 0xD5, 0xC7, 0x30, 0x61, 0x12, 0xC9, 0xA7, 0x7D, 0x81, 0x95,\n\t0x87, 0x63, 0x3F, 0xCE, 0x7D, 0x9B, 0xD0, 0x4F, 0xE3, 0x42, 0x39, 0xFD,\n\t0xE4, 0x8D, 0x3C, 0x12, 0x5F, 0x6E, 0x24, 0xD3, 0xE6, 0x97, 0xA3, 0x68,\n\t0x4E, 0xFB, 0xDA, 0x4A, 0x56, 0x31, 0xB7, 0x88, 0xF1, 0x20, 0x51, 0x97,\n\t0x3A, 0x51, 0xB5, 0x3E, 0x52, 0x61, 0x36, 0x12, 0xC3, 0xFF, 0x07, 0x11,\n\t0xD2, 0x33, 0x8B, 0x82, 0xD6, 0x8C, 0x45, 0x02, 0x89, 0xB7, 0x7B, 0x13,\n\t0x3E, 0x50, 0xBB, 0x7E, 0xEC, 0x24, 0xC4, 0x77, 0x56, 0x7D, 0x74, 0x86,\n\t0x61, 0x0E, 0x46, 0xCF, 0x7B, 0x7B, 0xAA, 0x3B, 0x79, 0x8B, 0x7C, 0xDD,\n\t0xE7, 0xB0, 0x22, 0xCC, 0xCE, 0x3E, 0xA6, 0x63, 0xBA, 0x9F, 0xEA, 0xC7,\n\t0x65, 0x4B, 0xF7, 0xAB, 0x90, 0xFE, 0xE7, 0x34, 0x08, 0x8D, 0xE2, 0x81,\n\t0x91, 0x07, 0xB9, 0xE4, 0x34, 0x28, 0x6E, 0x83, 0xFC, 0xD0, 0x34, 0x8D,\n\t0xC3, 0x10, 0x7C, 0x1A, 0x3C, 0xF3, 0x44, 0x45, 0x2C, 0x23, 0xE5, 0xAF,\n\t0x43, 0xA7, 0x42, 0x61, 0x3F, 0xD7, 0xBB, 0xE5, 0x85, 0x9F, 0xF5, 0xE0,\n\t0xBB, 0x89, 0xF2, 0xD6, 0xF5, 0xFA, 0x4C, 0x8D, 0xC0, 0x30, 0x5E, 0x4F,\n\t0x15, 0x8E, 0x67, 0xF7, 0x45, 0xAD, 0xE4, 0xBD, 0x28, 0x8E, 0xE7, 0xDA,\n\t0x0E, 0x56, 0x84, 0xE8, 0xFA, 0x5D, 0xF7, 0x49, 0x3E, 0x9F, 0x6C, 0x96,\n\t0xDF, 0xFD, 0x23, 0x9F, 0xC5, 0x58, 0x0C, 0x44, 0xAD, 0x96, 0x54, 0xC4,\n\t0x4B, 0x0D, 0x76, 0x3E, 0x3E, 0xAD, 0xA3, 0x27, 0x66, 0x97, 0x9C, 0x41,\n\t0x0A, 0x61, 0x07, 0x14, 0x35, 0x26, 0xF4, 0xE8, 0xCF, 0xC6, 0x94, 0xDA,\n\t0x69, 0xB1, 0x93, 0x6C, 0xC7, 0x01, 0x17, 0x89, 0x7F, 0x8E, 0x9B, 0x6B,\n\t0xDA, 0xC7, 0xE5, 0x00, 0xBD, 0xD7, 0x01, 0x20, 0x6A, 0x0B, 0x7F, 0x6B,\n\t0x0E, 0x4E, 0x12, 0xB2, 0x6E, 0x16, 0x77, 0x86, 0x3E, 0x3D, 0xF7, 0x08,\n\t0x80, 0xA9, 0x71, 0xA3, 0xCE, 0x10, 0xA3, 0xEE, 0xBB, 0x19, 0xBA, 0x73,\n\t0x94, 0x98, 0x6D, 0x0A, 0x7A, 0x7F, 0xE0, 0x80, 0xE5, 0x6E, 0xC1, 0xE0,\n\t0x86, 0x31, 0xD9, 0xB3, 0xA5, 0x57, 0x6D, 0x62, 0xED, 0x7D, 0xF1, 0x19,\n\t0x7F, 0xD7, 0xCC, 0xA0, 0xDF, 0xC7, 0x0C, 0x43, 0x6C, 0x75, 0x99, 0x59,\n\t0x8F, 0xA6, 0xEE, 0x2C, 0x2E, 0xE7, 0x3E, 0x31, 0xC6, 0x36, 0xC1, 0x69,\n\t0x8E, 0xED, 0x42, 0xBB, 0x62, 0xFC, 0xA5, 0x25, 0x29, 0xAF, 0xBE, 0x4D,\n\t0x4B, 0x91, 0x5B, 0x94, 0xAD, 0x5B, 0x1C, 0xFD, 0x39, 0x8E, 0xA5, 0x94,\n\t0xD1, 0xD2, 0xE8, 0xE8, 0xB1, 0xB0, 0xA4, 0x29, 0x58, 0xBB, 0xDA, 0x7E,\n\t0xFC, 0x24, 0xA1, 0x21, 0x3A, 0x69, 0xEE, 0x5C, 0xE4, 0x08, 0x58, 0x3D,\n\t0xBC, 0xF9, 0xB8, 0xE4, 0xBF, 0x4A, 0xC5, 0x51, 0x70, 0xAE, 0x03, 0x81,\n\t0x93, 0xD5, 0x62, 0xB9, 0xB7, 0x96, 0x92, 0x17, 0x5E, 0xAF, 0xE8, 0xAA,\n\t0x82, 0x60, 0x30, 0xB0, 0xE3, 0xF8, 0xFB, 0xA5, 0xBE, 0x62, 0x4E, 0xB5,\n\t0x2B, 0xC2, 0x1D, 0x1F, 0xEA, 0xC3, 0x09, 0xB6, 0x6E, 0xAC, 0xE0, 0xCE,\n\t0x01, 0x9F, 0x97, 0xDE, 0xD0, 0x52, 0x92, 0xDC, 0xD4, 0xFC, 0x8A, 0xA2,\n\t0x7E, 0xDB, 0x10, 0x4E, 0x37, 0xD6, 0x83, 0xD9, 0x36, 0xFB, 0xA8, 0xC7,\n\t0xD6, 0xD3, 0x0F, 0xB4, 0x32, 0x05, 0x4E, 0x9B, 0x47, 0x89, 0x5E, 0x0D,\n\t0xF0, 0x9A, 0x49, 0x05, 0x38, 0xDF, 0xDD, 0x3E, 0x33, 0x35, 0x41, 0x64,\n\t0x17, 0xCD, 0xE6, 0xC1, 0x85, 0xA4, 0xBB, 0xC6, 0x43, 0x90, 0x71, 0x9A,\n\t0x5B, 0x5A, 0xE2, 0x97, 0x2D, 0x0F, 0xCC, 0xE0, 0xA6, 0x8E, 0x22, 0x51,\n\t0x38, 0xFB, 0x54, 0xBC, 0x92, 0x27, 0x4C, 0x2E, 0x44, 0x33, 0xE0, 0xE3,\n\t0xD5, 0xE0, 0xA8, 0xAB, 0x9B, 0xDC, 0xEF, 0x11, 0x3D, 0x86, 0x4E, 0xF4,\n\t0x83, 0xEB, 0x27, 0xF4, 0x55, 0x21, 0x0C, 0x49, 0x26, 0xB4, 0x42, 0x3B,\n\t0x81, 0x46, 0x8B, 0x6C, 0x3A, 0x29, 0xB3, 0x61, 0x34, 0x22, 0x65, 0xAB,\n\t0x56, 0x0D, 0xD9, 0xC3, 0x9E, 0x33, 0xFD, 0xD5, 0xFC, 0xF1, 0xDD, 0xDA,\n\t0xD6, 0xA9, 0x32, 0x21, 0x0E, 0x9E, 0x5C, 0x5A, 0xFF, 0x15, 0x07, 0x37,\n\t0x96, 0x74, 0x1F, 0x67, 0x89, 0x2D, 0x91, 0xD5, 0x50, 0x07, 0x65, 0x07,\n\t0x4F, 0x1E, 0x04, 0xDF, 0x56, 0xD8, 0x30, 0x98, 0x6F, 0xCD, 0xE0, 0x79,\n\t0xF3, 0xE4, 0x6A, 0xEA, 0x22, 0xD9, 0x7E, 0x7F, 0x6E, 0x87, 0x04, 0x6C,\n\t0x6F, 0x5A, 0x88, 0x62, 0x12, 0xB0, 0x3A, 0x68, 0xA3, 0xB5, 0x96, 0x2A,\n\t0x26, 0x98, 0x36, 0x54, 0x07, 0x83, 0x14, 0x3C, 0xC8, 0x30, 0x09, 0xE2,\n\t0xE0, 0xE2, 0x79, 0xFA, 0x7B, 0xC5, 0x85, 0x6E, 0xE9, 0x1C, 0xF9, 0xC6,\n\t0xC9, 0xDE, 0xCB, 0xA8, 0x02, 0x09, 0x24, 0x84, 0x8E, 0x45, 0xE4, 0x72,\n\t0x81, 0x13, 0x89, 0x24, 0xD2, 0x66, 0x6F, 0xD9, 0xF0, 0x9A, 0xF8, 0x82,\n\t0x02, 0x71, 0x6C, 0x83, 0x7F, 0x2F, 0xC9, 0x4A, 0x88, 0xA1, 0x2A, 0x8C,\n\t0x04, 0x38, 0xB4, 0xEF, 0x98, 0x4B, 0x54, 0x4A, 0xC1, 0xCE, 0x29, 0x43,\n\t0x73, 0xA1, 0x23, 0x70, 0xFC, 0xDA, 0x44, 0x15, 0x37, 0xFC, 0x53, 0x4D,\n\t0xB3, 0x52, 0xD1, 0x8A, 0x2B, 0x2D, 0x60, 0xE7, 0xDE, 0x29, 0x0A, 0xC6,\n\t0x67, 0x64, 0x8C, 0x2A, 0xD7, 0x79, 0x0B, 0x44, 0x95, 0x3A, 0xF7, 0x6E,\n\t0x02, 0x24, 0xAE, 0x6E, 0xB8, 0x64, 0x45, 0xD8, 0xD6, 0xE7, 0xCA, 0x1C,\n\t0x27, 0x0E, 0x48, 0xC0, 0x38, 0xC0, 0x9D, 0x6A, 0xFB, 0x91, 0x7B, 0x1D,\n\t0xF7, 0x90, 0xA0, 0x77, 0xA0, 0x9B, 0x4B, 0xE5, 0xDE, 0x60, 0xC4, 0x53,\n\t0xF0, 0x28, 0xC8, 0x9E, 0xB5, 0x77, 0x5B, 0x61, 0x84, 0xAC, 0xEA, 0x59,\n\t0x89, 0x3F, 0x6E, 0x03, 0x8A, 0xEB, 0x37, 0x69, 0xC8, 0x68, 0x74, 0x10,\n\t0xBD, 0xE9, 0xB1, 0x1F, 0x25, 0x38, 0xBD, 0x26, 0x05, 0x66, 0xB8, 0x44,\n\t0x70, 0x34, 0xBD, 0x2A, 0xEE, 0x5D, 0x81, 0xB1, 0x2D, 0x13, 0xE1, 0x04,\n\t0x7D, 0x82, 0xE3, 0x68, 0x67, 0x91, 0x60, 0xB9, 0x7B, 0x36, 0x89, 0x80,\n\t0x84, 0x3D, 0x85, 0x0A, 0xFE, 0xC3, 0xFF, 0x94, 0xAA, 0x7B, 0x86, 0x07,\n\t0x74, 0x22, 0xC1, 0x8B, 0x56, 0x67, 0xC7, 0xEC, 0x41, 0x4F, 0x17, 0xC1,\n\t0x02, 0x77, 0x42, 0x36, 0x4B, 0x0D, 0xF3, 0xC3, 0xB5, 0x71, 0x52, 0x86,\n\t0x54, 0x0A, 0xB6, 0x60, 0x00, 0x85, 0x76, 0xC3, 0x40, 0x42, 0xBA, 0x15,\n\t0x21, 0x08, 0x3D, 0xC8, 0xD5, 0x09, 0x53, 0xCC, 0x21, 0xFF, 0x19, 0x95,\n\t0xF0, 0x52, 0xBC, 0x4A, 0x5A, 0xEC, 0x4A, 0xB7, 0x21, 0x9E, 0x03, 0x4A,\n\t0x72, 0xF5, 0x90, 0xE4, 0x61, 0xC8, 0x8F, 0x3A, 0x3F, 0xE3, 0x5D, 0x2B,\n\t0xE9, 0x7A, 0x48, 0xA4, 0xDC, 0x0B, 0x78, 0xEC, 0x7E, 0x8B, 0xBF, 0x14,\n\t0x40, 0xFF, 0x26, 0x75, 0x07, 0x5E, 0x9A, 0xFC, 0xCD, 0xCD, 0x9C, 0xC5,\n\t0x02, 0xC6, 0x72, 0xB4, 0xA9, 0x4C, 0x06, 0x6E, 0x9B, 0xD4, 0xE2, 0x5F,\n\t0x22, 0x04, 0x13, 0x86, 0x6D, 0x39, 0xDB, 0x63, 0x4B, 0xF6, 0x07, 0x83,\n\t0xEA, 0x80, 0xC9, 0xAC, 0x83, 0xA9, 0x6D, 0x14, 0x30, 0x53, 0x73, 0x62,\n\t0x79, 0x40, 0xB8, 0x7D, 0x0D, 0x8D, 0x03, 0xA6, 0x21, 0xA0, 0x4F, 0x90,\n\t0x0D, 0xC4, 0xA0, 0x3C, 0xEB, 0x0E, 0xD1, 0xB0, 0x7A, 0xCD, 0x3A, 0x49,\n\t0xC9, 0x8D, 0x20, 0xE4, 0x94, 0x68, 0x8D, 0x94, 0xA7, 0x50, 0x67, 0xB6,\n\t0xF4, 0xC8, 0x40, 0x7E, 0x58, 0xAD, 0xB8, 0x8E, 0xBA, 0xCE, 0x08, 0x5D,\n\t0x54, 0xFE, 0xB3, 0xD1, 0x90, 0xB1, 0x5D, 0xDF, 0x21, 0xFA, 0x50, 0x46,\n\t0x7A, 0x88, 0xD3, 0x96, 0x17, 0x01, 0xE8, 0xC9, 0xD3, 0xCA, 0x1F, 0x23,\n\t0x2C, 0xD4, 0xF8, 0x62, 0xE5, 0xB3, 0x78, 0x59, 0xB8, 0xF6, 0x69, 0x85,\n\t0x48, 0xC5, 0xE4, 0xC1, 0x73, 0x47, 0xB4, 0x92, 0xAE, 0xDD, 0xD1, 0xEC,\n\t0xBE, 0x57, 0xCA, 0x51, 0xAB, 0xAF, 0xAD, 0xA8, 0x19, 0x84, 0xB5, 0xCF,\n\t0xA4, 0xD7, 0xAF, 0xE6, 0xF5, 0xFA, 0xBE, 0x3B, 0x6A, 0xE2, 0x37, 0x03,\n\t0x44, 0xDD, 0x02, 0x93, 0x05, 0x74, 0x9F, 0xD0, 0x98, 0xD9, 0x49, 0x3E,\n\t0x2D, 0x4E, 0xA6, 0x6F, 0x2C, 0x05, 0xDF, 0x45, 0xC8, 0xCA, 0xD1, 0x84,\n\t0xF6, 0x32, 0xA8, 0x1F, 0x7A, 0xF9, 0xF4, 0xBF, 0xC1, 0x03, 0x61, 0x47,\n\t0x65, 0xEA, 0xAE, 0x74, 0x1D, 0x91, 0xD2, 0x40, 0x9D, 0x54, 0x5F, 0x55,\n\t0xCA, 0x4F, 0xF0, 0x3A, 0x9A, 0x74, 0xD4, 0x92, 0x67, 0xA7, 0x82, 0x3B,\n\t0xAA, 0xBF, 0x49, 0xFF, 0x11, 0x4B, 0x3E, 0xF5, 0x59, 0x12, 0xB1, 0x19,\n\t0xEC, 0xC3, 0xCD, 0x9D, 0x28, 0x4D, 0x46, 0x37, 0x2A, 0x56, 0xC6, 0x27,\n\t0x21, 0x5D, 0x3F, 0x86, 0x0A, 0x1F, 0xEE, 0xFF, 0x0B, 0x28, 0x38, 0xD9,\n\t0x67, 0xA3, 0x80, 0x28, 0x6F, 0x71, 0x9E, 0xA6, 0x6B, 0x1E, 0x91, 0x72,\n\t0xEF, 0x0F, 0xB3, 0x60, 0x2D, 0x5B, 0xF4, 0x1C, 0xFC, 0x09, 0x8B, 0x72,\n\t0x3C, 0x41, 0x27, 0x19, 0x65, 0xAD, 0x32, 0x28, 0x6E, 0x8E, 0x46, 0xFA,\n\t0xA1, 0x48, 0x63, 0xD2, 0x64, 0x1B, 0xD4, 0x3B, 0xD3, 0xB9, 0x31, 0xE1,\n\t0x10, 0xAA, 0x3A, 0x46, 0x19, 0xF4, 0x8E, 0xD7, 0xF9, 0x40, 0x11, 0xE2,\n\t0x6A, 0x62, 0xCE, 0x83, 0xD3, 0x8A, 0xE4, 0xD0, 0x97, 0xC0, 0x50, 0x8A,\n\t0x3E, 0x92, 0x34, 0x26, 0x9C, 0x58, 0x54, 0x70, 0xAE, 0x13, 0x23, 0xFD,\n\t0x8E, 0x95, 0xBC, 0xF6, 0xA9, 0x4A, 0x59, 0xDC, 0xD6, 0x8C, 0x2C, 0xCF,\n\t0x97, 0x49, 0x1B, 0x13, 0xB9, 0x0E, 0x1B, 0xBC, 0x62, 0x34, 0xE4, 0x3E,\n\t0x84, 0xD8, 0x63, 0x92, 0x2F, 0x46, 0xB4, 0xDA, 0x5C, 0xB6, 0x63, 0xD0,\n\t0x86, 0x24, 0x8C, 0x50, 0xB3, 0x18, 0xE1, 0xFE, 0x70, 0x65, 0x54, 0xCD,\n\t0xC6, 0x0C, 0x14, 0x57, 0x74, 0xFA, 0x60, 0xB1, 0xE3, 0xE4, 0xBA, 0x0C,\n\t0x36, 0xA2, 0x8D, 0x48, 0x2F, 0x8F, 0x59, 0xAF, 0xD1, 0xC8, 0xC8, 0x60,\n\t0x2F, 0x4C, 0x42, 0xF4, 0x1F, 0xCD, 0x8C, 0x5C, 0xB2, 0xCA, 0xB3, 0xBE,\n\t0x1F, 0xF9, 0x76, 0xEC, 0x84, 0xA7, 0x3C, 0x36, 0xCB, 0x6F, 0x3D, 0x58,\n\t0x6A, 0x19, 0xE1, 0x2A, 0x34, 0xFA, 0xE0, 0xB0, 0x65, 0xDF, 0x90, 0x61,\n\t0xC1, 0x21, 0x3B, 0xE5, 0x84, 0xCD, 0x8A, 0x32, 0xFE, 0x0F, 0x68, 0x78,\n\t0x8F, 0x77, 0xCD, 0xE4, 0x3B, 0xBC, 0x38, 0xCE, 0x3E, 0x32, 0x97, 0x70,\n\t0x7F, 0xFA, 0x63, 0x6C, 0x2C, 0x50, 0xD7, 0x54, 0x4A, 0x83, 0x7A, 0xCA,\n\t0x51, 0x46, 0xFE, 0x8B, 0xB5, 0xCC, 0x6B, 0x64, 0x82, 0xF8, 0x17, 0xE1,\n\t0xE0, 0x48, 0x25, 0xD2, 0x0E, 0x0D, 0x29, 0xBD, 0x79, 0x50, 0x57, 0x11,\n\t0xD1, 0x48, 0x8D, 0x19, 0xF7, 0x9D, 0x56, 0xA4, 0x01, 0xCE, 0x3A, 0x2F,\n\t0x6B, 0x6F, 0x14, 0xF8, 0x59, 0x68, 0x4C, 0x16, 0xDE, 0x33, 0x09, 0x4D,\n\t0xB5, 0xD7, 0x14, 0xC0, 0xAB, 0x4D, 0x90, 0x19, 0x3E, 0x6C, 0x97, 0x85,\n\t0x2F, 0x5E, 0x81, 0xB0, 0x52, 0x2B, 0x7D, 0xCC, 0xF1, 0x3A, 0xC0, 0x95,\n\t0x9D, 0xF2, 0xB2, 0x97, 0xE2, 0x42, 0x26, 0xEA, 0xC2, 0xD7, 0x96, 0xA0,\n\t0x24, 0x47, 0xA3, 0xBB, 0x2C, 0x8F, 0xC6, 0x7B, 0x3F, 0xDF, 0x0C, 0x08,\n\t0x6D, 0x93, 0x2F, 0x26, 0xB8, 0x8C, 0xE5, 0x30, 0x72, 0x8D, 0x8A, 0x2D,\n\t0xE6, 0x29, 0x95, 0x2F, 0x43, 0x75, 0xFC, 0xD9, 0x6B, 0xCF, 0x1A, 0x29,\n\t0xBB, 0xF3, 0xE6, 0x8F, 0x43, 0x0E, 0x12, 0x07, 0x9F, 0xB1, 0x76, 0x45,\n\t0xB3, 0xEC, 0x6B, 0x5A, 0xD6, 0x77, 0x89, 0xCF, 0x7A, 0x9A, 0x26, 0x34,\n\t0xA6, 0x69, 0x51, 0x7C, 0x07, 0x3D, 0xA3, 0xA2, 0xAA, 0x57, 0xF5, 0x5A,\n\t0x9E, 0x85, 0x4F, 0x37, 0x53, 0x9D, 0x6A, 0x44, 0x26, 0x54, 0xE2, 0x7D,\n\t0x1D, 0xD5, 0xD7, 0x50, 0x00, 0xF9, 0x5B, 0x9D, 0x8D, 0x25, 0xA4, 0x78,\n\t0xF3, 0x14, 0x87, 0xBA, 0x89, 0xBB, 0x54, 0x72, 0xEC, 0xA7, 0xE9, 0xF3,\n\t0x07, 0xE1, 0x5E, 0x3A, 0xCC, 0x91, 0x9E, 0x8F, 0x61, 0x41, 0xCC, 0x28,\n\t0xBA, 0x98, 0xC8, 0x98, 0xFC, 0x13, 0x24, 0x44, 0x48, 0x7F, 0x5E, 0x46,\n\t0x45, 0x22, 0x44, 0x51, 0x1D, 0xF2, 0x02, 0x0C, 0x19, 0x47, 0x5B, 0xE4,\n\t0x7B, 0xE8, 0x7D, 0xE9, 0xB0, 0x9D, 0xB8, 0x6C, 0xF7, 0x7B, 0x04, 0x6F,\n\t0x24, 0xD7, 0x58, 0xF6, 0x09, 0x50, 0x0D, 0x2B, 0xCC, 0x85, 0x81, 0xD3,\n\t0xD4, 0x02, 0x8E, 0xFC, 0xFD, 0xC0, 0x04, 0x5C, 0x39, 0x48, 0x08, 0xB1,\n\t0x5D, 0xF1, 0xF0, 0x37, 0xCC, 0xD4, 0x0D, 0x78, 0xE9, 0x6F, 0xA2, 0x8B,\n\t0x02, 0xC7, 0xA0, 0x1D, 0xD8, 0x8F, 0xA6, 0xC3, 0x4E, 0x44, 0x0D, 0xF5,\n\t0x0E, 0xDE, 0x9E, 0x6A, 0xBE, 0xC9, 0xE1, 0x7B, 0x71, 0x42, 0x1F, 0x2D,\n\t0x37, 0x29, 0xCC, 0xCE, 0xE7, 0x38, 0x0C, 0xF2, 0x73, 0x1C, 0x5C, 0x45,\n\t0xA3, 0x2E, 0x94, 0xB1, 0x24, 0x94, 0x9D, 0x65, 0xAA, 0xB7, 0x87, 0x47,\n\t0x41, 0x3A, 0x85, 0xDE, 0x05, 0xB7, 0x4A, 0xAF, 0x9E, 0x15, 0x94, 0xA1,\n\t0x87, 0xE1, 0x91, 0x70, 0x40, 0x71, 0x56, 0x39, 0xCE, 0xC9, 0x47, 0x1D,\n\t0x8D, 0x80, 0x95, 0x7D, 0x3B, 0x9E, 0xA9, 0xA6, 0x93, 0x19, 0xEB, 0x23,\n\t0x1D, 0x3B, 0x72, 0xBA, 0x6F, 0x01, 0xFE, 0xC9, 0x56, 0x50, 0xE2, 0xFD,\n\t0x55, 0x04, 0x41, 0xA7, 0x75, 0x34, 0xC9, 0x58, 0xBE, 0x43, 0x12, 0x63,\n\t0x54, 0x20, 0xA8, 0x5E, 0x24, 0xE4, 0x92, 0x4D, 0x28, 0x55, 0x45, 0x32,\n\t0x65, 0xCF, 0x12, 0x1E, 0x50, 0x37, 0xE0, 0x86, 0xCD, 0xA7, 0xDD, 0x91,\n\t0x9E, 0xC6, 0xD1, 0xDE, 0xA9, 0xCA, 0x57, 0x70, 0x06, 0xEE, 0xD8, 0x90,\n\t0x61, 0xF0, 0x79, 0x84, 0x4E, 0xCC, 0x19, 0xCA, 0xDC, 0x1E, 0xB7, 0x78,\n\t0x90, 0x23, 0x0D, 0x83, 0xDB, 0x48, 0xA0, 0xD7, 0x86, 0x38, 0x6B, 0x6A,\n\t0x55, 0xFE, 0x89, 0x4F, 0xE5, 0xDA, 0x0C, 0x5B, 0xB3, 0x8C, 0x35, 0x00,\n\t0x0A, 0x17, 0xFD, 0x77, 0x00, 0x0E, 0x1F, 0x22, 0x67, 0xCB, 0x80, 0x21,\n\t0xC9, 0x4E, 0x57, 0xAB, 0x50, 0x0A, 0xBA, 0x9B, 0xF6, 0x15, 0x97, 0xEC,\n\t0x72, 0xDA, 0x5F, 0xF7, 0x5E, 0x28, 0x82, 0xD9, 0xDE, 0x86, 0x05, 0xB8,\n\t0x7A, 0xF6, 0x8D, 0x7B, 0x4F, 0x76, 0x35, 0xB9, 0x85, 0x6A, 0xF2, 0xDD,\n\t0x12, 0xC1, 0x44, 0xE5, 0xDC, 0xC7, 0x74, 0xF3, 0x55, 0x7D, 0x74, 0x18,\n\t0x5A, 0x41, 0x3D, 0xE9, 0xEA, 0x90, 0x37, 0x22, 0x77, 0x47, 0x61, 0xD2,\n\t0x02, 0x91, 0x4C, 0x8B, 0x24, 0x36, 0x00, 0xD7, 0xD1, 0x89, 0xF3, 0x4E,\n\t0x5D, 0x60, 0x7B, 0x36, 0xF7, 0x0F, 0x9A, 0x72, 0x51, 0x3D, 0xD7, 0x8B,\n\t0xE5, 0x8F, 0xEB, 0x09, 0x65, 0x96, 0xC5, 0x2B, 0x0D, 0x25, 0xC3, 0xF0,\n\t0x89, 0x86, 0xD4, 0xBA, 0xB6, 0x7B, 0x4F, 0x2A, 0x8A, 0xAB, 0x10, 0xC4,\n\t0x2E, 0xE5, 0x8C, 0xE2, 0x91, 0xB9, 0x9D, 0x09, 0x08, 0x45, 0x8B, 0xB3,\n\t0xFC, 0xED, 0x44, 0x38, 0xE8, 0xA5, 0x90, 0x00, 0x48, 0x76, 0xA7, 0x6C,\n\t0x44, 0x60, 0x10, 0xE2, 0x7F, 0x05, 0xD0, 0x91, 0x30, 0xDE, 0x3D, 0xE2,\n\t0xBC, 0xCC, 0xED, 0xEE, 0x53, 0xA3, 0xEF, 0xAA, 0x29, 0xE1, 0x1E, 0xFC,\n\t0x45, 0x7E, 0x98, 0x7C, 0x13, 0xB1, 0xF4, 0x92, 0x0A, 0x92, 0x4E, 0xDD,\n\t0x90, 0xD1, 0x07, 0x45, 0xA3, 0x2B, 0x5F, 0xDB, 0xBF, 0x53, 0x18, 0xDC,\n\t0x9F, 0x62, 0x64, 0xF1, 0x64, 0x6A, 0xF6, 0xCC, 0x8B, 0x10, 0x21, 0x72,\n\t0xD2, 0x12, 0x22, 0xDA, 0xA4, 0xAE, 0xE0, 0x14, 0x9D, 0x01, 0xDD, 0x5F,\n\t0x63, 0x71, 0x41, 0x21, 0x76, 0x43, 0x22, 0x63, 0xE0, 0xBF, 0x70, 0x2B,\n\t0xA2, 0x7D, 0x42, 0xEE, 0x2B, 0x23, 0x19, 0x7C, 0x7A, 0xA3, 0xCC, 0xFE,\n\t0xC6, 0x7E, 0x94, 0xC6, 0xF8, 0xD2, 0xE2, 0xB1, 0x54, 0xEE, 0xD7, 0xEA,\n\t0x9A, 0x20, 0x89, 0x2B, 0x8C, 0x70, 0x64, 0x39, 0x01, 0x64, 0x13, 0x72,\n\t0xE8, 0xCC, 0xC8, 0xC0, 0x89, 0x1A, 0x64, 0x30, 0xF7, 0x33, 0x62, 0xE4,\n\t0x09, 0x24, 0x0A, 0x83, 0x56, 0x18, 0x7A, 0x6C, 0x5A, 0x9E, 0x43, 0x3A,\n\t0x6E, 0xC6, 0xF3, 0x0B, 0x6B, 0xEE, 0x07, 0x6C, 0x08, 0x64, 0x28, 0xEF,\n\t0xA1, 0x72, 0xDA, 0x56, 0x36, 0x5E, 0xE7, 0xBD, 0x31, 0x0C, 0x58, 0x7F,\n\t0x46, 0x07, 0x9A, 0x9B, 0x74, 0x84, 0x7E, 0x7F, 0x11, 0x05, 0x04, 0x87,\n\t0x40, 0xB3, 0xA6, 0xB9, 0x18, 0x6B, 0x4F, 0xE5, 0xD9, 0x8E, 0xF2, 0x44,\n\t0x33, 0xBE, 0x14, 0x48, 0x30, 0x6A, 0x9D, 0x7A, 0x8B, 0xED, 0xFE, 0x6C,\n\t0xA1, 0x0C, 0x55, 0xC5, 0xB4, 0x43, 0xCD, 0xEC, 0x72, 0x88, 0x5E, 0xD5,\n\t0x6B, 0xCF, 0xB8, 0xBE, 0x6C, 0xC7, 0xFA, 0xFE, 0x6A, 0x97, 0xB9, 0x59,\n\t0x01, 0xE5, 0xD3, 0xDE, 0x82, 0xB8, 0x3E, 0x9B, 0xF6, 0xDC, 0x66, 0x62,\n\t0xA8, 0x29, 0xBA, 0x05, 0x0E, 0x67, 0x64, 0x0B, 0x5F, 0xAB, 0x29, 0xC9,\n\t0x18, 0x14, 0x23, 0x54, 0x52, 0x25, 0xF4, 0x69, 0xBB, 0xAB, 0xC3, 0x14,\n\t0x53, 0x99, 0x96, 0x94, 0x40, 0x03, 0x3C, 0x96, 0x42, 0x19, 0xAC, 0x2B,\n\t0xA6, 0x83, 0x60, 0xD1, 0xC8, 0xA7, 0x1C, 0x6C, 0x62, 0x4D, 0xD8, 0xA4,\n\t0x6E, 0x5E, 0xC1, 0x57, 0x7B, 0x17, 0x33, 0xB6, 0xCF, 0x91, 0x18, 0x94,\n\t0x8F, 0x2C, 0x14, 0xE5, 0x6F, 0x60, 0x5B, 0x41, 0xCB, 0x5F, 0xDA, 0x17,\n\t0x23, 0xB6, 0xE4, 0x4B, 0x6F, 0xD9, 0xFC, 0x16, 0xB3, 0x24, 0x1C, 0x98,\n\t0x40, 0x41, 0x2B, 0xBE, 0x15, 0x6D, 0xF3, 0x6A, 0x98, 0x3A, 0x7A, 0x99,\n\t0xE8, 0xB4, 0x62, 0x51, 0xBA, 0x01, 0x43, 0x19, 0x2E, 0xDB, 0xFB, 0x21,\n\t0x36, 0x70, 0x6C, 0xEE, 0xEC, 0x41, 0xD4, 0x4B, 0x9C, 0xE7, 0xE8, 0x82,\n\t0xB1, 0xFB, 0xAE, 0x17, 0x28, 0x48, 0xCE, 0xCF, 0xE3, 0xCF, 0x2A, 0xF2,\n\t0x9E, 0x9D, 0x24, 0xE8, 0x84, 0x1E, 0x05, 0xDD, 0x73, 0x57, 0x52, 0x79,\n\t0xC7, 0xD6, 0xA8, 0xBF, 0xB3, 0x03, 0x3E, 0xD4, 0x5E, 0xCE, 0x74, 0xC3,\n\t0x59, 0x69, 0x27, 0x5C, 0xE7, 0x5A, 0xE5, 0x82, 0x15, 0x5B, 0xD8, 0x18,\n\t0x98, 0x36, 0x47, 0xBF, 0x16, 0x8D, 0x0D, 0xD1, 0x43, 0x9F, 0xE4, 0x4E,\n\t0xAD, 0x42, 0x92, 0xE1, 0x0B, 0xA1, 0x81, 0x36, 0x38, 0xAA, 0x2F, 0x78,\n\t0xC7, 0x9B, 0x41, 0xB1, 0xF3, 0x30, 0xE1, 0x42, 0x61, 0x10, 0xF5, 0x8F,\n\t0xFB, 0xEC, 0xA9, 0xEC, 0xB8, 0x10, 0xAD, 0xC6, 0xC4, 0xA7, 0xA6, 0x4B,\n\t0x6A, 0x6C, 0xDC, 0x02, 0x20, 0x42, 0x08, 0xBD, 0x6F, 0xC5, 0xF6, 0x8F,\n\t0xC9, 0x2C, 0xA3, 0x18, 0x8C, 0x0B, 0xA1, 0x9D, 0x29, 0x25, 0x3E, 0xFE,\n\t0x7C, 0xF4, 0xDD, 0xEF, 0x39, 0xE1, 0x96, 0x85, 0x9C, 0xA1, 0xE6, 0x6E,\n\t0xC6, 0x0A, 0x31, 0xEC, 0xFB, 0x45, 0x85, 0xA0, 0x23, 0xFE, 0xCD, 0x1C,\n\t0x49, 0x4F, 0xA0, 0x10, 0xD7, 0xFC, 0x74, 0x5B, 0xF9, 0xB6, 0xB2, 0x11,\n\t0xD9, 0x9E, 0x8B, 0x26, 0xB1, 0x36, 0x8F, 0xA0, 0x6E, 0xC7, 0x39, 0xED,\n\t0x88, 0xF3, 0x21, 0x7B, 0xBB, 0x9A, 0xF9, 0x65, 0x76, 0x8F, 0x68, 0x72,\n\t0xB3, 0xEE, 0x0D, 0xAA, 0xCD, 0xB7, 0xFA, 0x0A, 0x47, 0x6F, 0xB0, 0x21,\n\t0x4A, 0xB9, 0xC8, 0x7A, 0xA1, 0x6D, 0x88, 0x50, 0xF7, 0xE9, 0x2E, 0xF5,\n\t0x64, 0x51, 0x44, 0xDE, 0x21, 0x3C, 0xC8, 0x31, 0x68, 0x42, 0x73, 0x41,\n\t0x32, 0xC5, 0xFD, 0xCE, 0xE7, 0x16, 0xD9, 0x34, 0xFF, 0xAC, 0x20, 0x1B,\n\t0x52, 0x2A, 0x9F, 0xD8, 0x71, 0xC3, 0x96, 0xB9, 0x88, 0x81, 0x28, 0x22,\n\t0x07, 0x76, 0xB8, 0x0E, 0x0A, 0x49, 0xA0, 0x15, 0x67, 0xF8, 0x75, 0x88,\n\t0xA2, 0xC3, 0x1F, 0xCB, 0xFD, 0x5F, 0x83, 0x28, 0x51, 0xA5, 0x77, 0xCB,\n\t0x21, 0x39, 0x43, 0x93, 0xB6, 0x9F, 0x00, 0x7D, 0x07, 0x1A, 0xF3, 0x98,\n\t0x23, 0x4B, 0x73, 0x96, 0xB1, 0xAA, 0x39, 0x24, 0x7C, 0x3D, 0xAD, 0x2C,\n\t0xFE, 0xB9, 0x91, 0x18, 0xE1, 0x4B, 0x4D, 0x83, 0x72, 0x5C, 0x7B, 0xCE,\n\t0xFC, 0x4F, 0xAC, 0x9C, 0x0F, 0xC5, 0x0B, 0x3B, 0x40, 0x0E, 0xB8, 0x6C,\n\t0x65, 0xF7, 0x16, 0xF2, 0x5D, 0x40, 0x1F, 0xE9, 0x4E, 0xFD, 0x7A, 0x9E,\n\t0x86, 0xDC, 0x6D, 0xFD, 0x0E, 0x4F, 0x72, 0xCB, 0x3E, 0x77, 0xCA, 0x33,\n\t0xB7, 0xB3, 0xA0, 0xF0, 0xE2, 0x5C, 0xA9, 0xF0, 0x7D, 0xC0, 0x53, 0x0A,\n\t0x0D, 0x27, 0x67, 0x62, 0x98, 0x7D, 0x9C, 0xEA, 0x76, 0xDF, 0x30, 0x1A,\n\t0x57, 0x8C, 0xEA, 0x04, 0x0F, 0x48, 0x35, 0x1F, 0x26, 0x82, 0x6A, 0x87,\n\t0x89, 0xCA, 0x49, 0xAF, 0xEC, 0x44, 0x1E, 0xD0, 0xDF, 0x33, 0x77, 0x03,\n\t0xA7, 0xEA, 0x7E, 0x63, 0x82, 0x8C, 0xC7, 0x57, 0x7A, 0x49, 0x52, 0x21,\n\t0xF5, 0x14, 0x98, 0x51, 0x8B, 0x6C, 0xBE, 0x3E, 0xC3, 0xF4, 0xE8, 0x86,\n\t0x6C, 0xDE, 0x28, 0xEB, 0x1A, 0xE2, 0x20, 0x80, 0xB0, 0xDA, 0x7A, 0x5E,\n\t0x9C, 0xDC, 0x95, 0x1C, 0x7B, 0xD7, 0xFA, 0x4B, 0xE9, 0x0C, 0xE6, 0x69,\n\t0x72, 0xA6, 0x61, 0x08, 0xCF, 0x89, 0xE6, 0x25, 0xEE, 0x4C, 0x2C, 0x0D,\n\t0x88, 0x71, 0x63, 0x72, 0x25, 0x2E, 0xB7, 0x6A, 0x55, 0x48, 0x22, 0x41,\n\t0xA6, 0x1D, 0x0F, 0x98, 0x8C, 0xA3, 0x04, 0x08, 0x73, 0x87, 0x77, 0x8F,\n\t0xA0, 0xA5, 0x33, 0xC9, 0xB6, 0x32, 0x3D, 0xE3, 0xD9, 0x41, 0x1D, 0x4B,\n\t0x98, 0x29, 0x59, 0xEF, 0x1F, 0xC6, 0x87, 0xC5, 0x9F, 0x40, 0xD4, 0xB2,\n\t0x47, 0x85, 0x03, 0x7F, 0x45, 0x1F, 0x9B, 0x65, 0x12, 0x19, 0xEB, 0xDD,\n\t0xFA, 0x85, 0x5F, 0x39, 0x44, 0x66, 0x00, 0x29, 0x98, 0x2C, 0x60, 0xD2,\n\t0x41, 0x38, 0x41, 0xA8, 0x17, 0xD3, 0x05, 0xC6, 0xB3, 0xBD, 0x8F, 0x38,\n\t0x82, 0x0F, 0x18, 0xDC, 0xF9, 0xB2, 0xF1, 0xE2, 0x81, 0xA8, 0x61, 0x07,\n\t0x37, 0x92, 0x5C, 0x85, 0xA8, 0xAE, 0x97, 0x76, 0xD5, 0xB8, 0x71, 0x3F,\n\t0xF4, 0x17, 0x8B, 0x78, 0x5B, 0xBE, 0xD9, 0x7D, 0x63, 0xFD, 0xFD, 0xD8,\n\t0xCA, 0x88, 0x00, 0x10, 0xA3, 0x9D, 0xF1, 0x42, 0xEE, 0x19, 0xFE, 0x2D,\n\t0xB8, 0x73, 0x48, 0x48, 0xC9, 0x77, 0xD2, 0x67, 0xA7, 0xDB, 0xD1, 0x7C,\n\t0xAC, 0x39, 0xD8, 0x44, 0xB6, 0x63, 0x19, 0x4C, 0xE6, 0x46, 0xEA, 0x36,\n\t0x78, 0xDC, 0x9F, 0x58, 0x21, 0xF3, 0xCB, 0x3E, 0xD8, 0xCB, 0x94, 0x10,\n\t0x3E, 0x51, 0xC9, 0x76, 0x71, 0x0D, 0xAF, 0xB5, 0x91, 0x42, 0x44, 0x99,\n\t0xE8, 0x68, 0x41, 0x70, 0x37, 0x47, 0x0A, 0xFE, 0x9C, 0x4F, 0x36, 0x2B,\n\t0x85, 0xAA, 0xFD, 0x49, 0xC5, 0xFB, 0x65, 0x2B, 0x31, 0x9A, 0x3D, 0x3E,\n\t0xE7, 0x9E, 0xF5, 0x09, 0x72, 0xB5, 0xD1, 0xC2, 0xE2, 0x1B, 0x21, 0x9A,\n\t0xDE, 0x5A, 0x2F, 0x96, 0xCC, 0x74, 0x10, 0xDE, 0x7C, 0x7D, 0xC9, 0xB8,\n\t0x4D, 0xF1, 0x1D, 0x6C, 0xB4, 0x56, 0x29, 0x3E, 0x58, 0x7E, 0x6D, 0xDF,\n\t0x7E, 0x7D, 0x53, 0xD2, 0xAD, 0x76, 0x40, 0x8D, 0xAC, 0xF4, 0x6B, 0x9F,\n\t0x82, 0x0E, 0xCD, 0xAE, 0x1E, 0x89, 0x94, 0x8B, 0x2F, 0xD2, 0x7B, 0x89,\n\t0xAE, 0x3C, 0xC7, 0x1B, 0x74, 0x85, 0xA7, 0x2E, 0x7B, 0x93, 0x17, 0xE9,\n\t0xF0, 0xCD, 0x6D, 0x93, 0x3D, 0x1C, 0xA0, 0x7B, 0xCA, 0xA5, 0x18, 0x0B,\n\t0x39, 0xE9, 0x39, 0x3D, 0x11, 0xFB, 0x03, 0xA5, 0xD1, 0x34, 0xBA, 0x25,\n\t0x2D, 0xF3, 0xE3, 0x23, 0x82, 0x5A, 0x9D, 0x0A, 0x57, 0x60, 0x76, 0x8D,\n\t0x7E, 0xA5, 0x5C, 0x9B, 0x64, 0xBD, 0x82, 0x97, 0x6A, 0x7C, 0x0B, 0xC5,\n\t0xA4, 0xF9, 0x87, 0x70, 0xCC, 0x3A, 0xFE, 0x6A, 0x2B, 0x11, 0x5D, 0x5E,\n\t0xF2, 0x7F, 0x85, 0xDC, 0x54, 0x37, 0xF7, 0x1E, 0x34, 0xC8, 0x0E, 0xC5,\n\t0x3C, 0x81, 0x82, 0xAE, 0x4B, 0xA7, 0xCB, 0x34, 0x19, 0xF0, 0xCD, 0xD5,\n\t0x29, 0x1C, 0x6F, 0xF6, 0x74, 0xE1, 0xF3, 0x51, 0x36, 0x6D, 0x26, 0xFF,\n\t0xB6, 0xC6, 0xCD, 0xCE, 0x71, 0x15, 0xC0, 0x8A, 0xCC, 0xD0, 0xAF, 0x61,\n\t0x97, 0x7B, 0xB0, 0xB8, 0x27, 0x56, 0x20, 0x16, 0x06, 0x94, 0xFF, 0xF1,\n\t0x99, 0x57, 0xB4, 0xCA, 0xB9, 0x9B, 0x83, 0x7C, 0x9B, 0x57, 0xDB, 0xB7,\n\t0x74, 0xC1, 0x66, 0x61, 0xD3, 0xCE, 0x3B, 0xBF, 0xD3, 0x0D, 0xF3, 0xB3,\n\t0x3B, 0xC8, 0x40, 0xE0, 0xCB, 0xED, 0x9D, 0xF0, 0x9B, 0x31, 0xC6, 0xCB,\n\t0x8F, 0xBB, 0xFB, 0xF3, 0x41, 0xF5, 0x35, 0xFA, 0xBC, 0xAA, 0xD6, 0x2B,\n\t0x68, 0x47, 0x82, 0x38, 0xBB, 0x4F, 0xC6, 0x79, 0xD9, 0x9D, 0x46, 0xE2,\n\t0x20, 0xF4, 0xA8, 0x6A, 0x0A, 0x46, 0xCA, 0x4F, 0x29, 0x68, 0xF3, 0x9E,\n\t0xDB, 0x7C, 0x01, 0x1A, 0xBA, 0xCB, 0x16, 0xC1, 0x6C, 0x7A, 0x83, 0xDE,\n\t0xE3, 0x20, 0xEA, 0xF8, 0xC7, 0x7B, 0x28, 0x39, 0x20, 0xFB, 0xEC, 0xED,\n\t0xAB, 0xB0, 0x1F, 0x06, 0xE2, 0x93, 0xFE, 0x7A, 0x9D, 0x2C, 0x79, 0xF6,\n\t0xE8, 0xAF, 0xFF, 0xD3, 0x3A, 0xAF, 0xA3, 0xE7, 0x47, 0xA4, 0x62, 0xAF,\n\t0xCD, 0x1E, 0xB0, 0x62, 0x4C, 0xBA, 0xB9, 0x0A, 0x98, 0xDC, 0x95, 0x94,\n\t0xEB, 0x5F, 0x55, 0xA6, 0xE9, 0xD2, 0xF1, 0xEA, 0xD5, 0x2F, 0x84, 0x95,\n\t0xAD, 0x50, 0xDF, 0x31, 0x16, 0x8A, 0xA3, 0x14, 0x4B, 0x9A, 0x49, 0x92,\n\t0xE0, 0x1A, 0x09, 0x64, 0x27, 0x4E, 0x56, 0xEF, 0x15, 0x12, 0x3F, 0x41,\n\t0x7E, 0xB7, 0x79, 0x26, 0xD0, 0xB3, 0x07, 0xF6, 0x5A, 0x36, 0x94, 0xDF,\n\t0x88, 0x0A, 0x4F, 0x54, 0x70, 0xCE, 0x30, 0x22, 0x01, 0x6D, 0x49, 0xCC,\n\t0x19, 0xB1, 0xFA, 0x1A, 0x9E, 0x78, 0xDA, 0x2E, 0x14, 0xC5, 0xED, 0xC9,\n\t0x05, 0x8C, 0x62, 0xD2, 0x3D, 0x99, 0x16, 0x2C, 0x5A, 0x59, 0x17, 0xDC,\n\t0x0B, 0xC7, 0x06, 0x1B, 0x89, 0xDA, 0x51, 0x0D, 0xAA, 0x95, 0x3D, 0x8E,\n\t0x38, 0xBC, 0x34, 0xA6, 0xCB, 0x6A, 0x9A, 0x71, 0x80, 0xD8, 0x8A, 0xE1,\n\t0x79, 0x03, 0x97, 0x9F, 0xCC, 0xFF, 0xE2, 0xB3, 0xC2, 0x87, 0x57, 0xDA,\n\t0x8A, 0xAD, 0x15, 0x2A, 0x8D, 0x05, 0xA9, 0xBA, 0x7A, 0x50, 0x48, 0x7E,\n\t0x02, 0x43, 0x34, 0xC6, 0xE1, 0xB3, 0x02, 0x8C, 0x8B, 0xB2, 0x18, 0x22,\n\t0xDD, 0xDC, 0x8C, 0xA4, 0x56, 0xAA, 0x7E, 0x20, 0xDA, 0x38, 0x49, 0xFC,\n\t0x2F, 0x91, 0x3F, 0x29, 0x48, 0xEA, 0x56, 0xEF, 0x26, 0x15, 0x5F, 0xFF,\n\t0x30, 0x49, 0x72, 0x8C, 0x8E, 0x39, 0x6D, 0x64, 0x5A, 0x83, 0x69, 0x46,\n\t0x90, 0x88, 0xBA, 0x06, 0x58, 0x02, 0xE5, 0x36, 0xF6, 0xE4, 0x58, 0x97,\n\t0xF2, 0xA8, 0xB0, 0x42, 0x7B, 0xFA, 0x80, 0xEE, 0x14, 0xC5, 0x83, 0x1A,\n\t0xE5, 0x9A, 0xB0, 0x64, 0x50, 0xB8, 0xE4, 0xBC, 0xAA, 0xA7, 0xBF, 0xD5,\n\t0x24, 0x44, 0x77, 0xAE, 0x4D, 0x09, 0x8D, 0xE0, 0x8E, 0xD2, 0xAD, 0x6B,\n\t0xC7, 0x4E, 0xBE, 0x40, 0xF1, 0xB6, 0xCA, 0x76, 0x57, 0xEF, 0x06, 0x2C,\n\t0x05, 0x0B, 0x01, 0x9A, 0x3F, 0x52, 0x9A, 0xA0, 0xB3, 0x9B, 0x0D, 0xAD,\n\t0x0C, 0xD2, 0x95, 0x3D, 0x5D, 0xAA, 0x7E, 0x40, 0x3B, 0xCA, 0x4D, 0x85,\n\t0x28, 0x75, 0x97, 0x53, 0x9D, 0x1D, 0x6C, 0xE2, 0xEA, 0x01, 0xE0, 0x61,\n\t0x52, 0xF0, 0xB6, 0xAC, 0x7D, 0x81, 0xE5, 0x78, 0x27, 0xC4, 0xC2, 0x9F,\n\t0xB4, 0x13, 0x21, 0x87, 0xC8, 0xEF, 0x88, 0xCB, 0xB5, 0x72, 0x6B, 0x11,\n\t0xFA, 0xA3, 0xA7, 0x96, 0x76, 0x92, 0x8B, 0x7E, 0x47, 0x6A, 0x7E, 0x64,\n\t0x70, 0x1A, 0xE5, 0x1D, 0x69, 0x76, 0x73, 0x7D, 0x58, 0x07, 0x27, 0x9C,\n\t0x33, 0x5A, 0xDA, 0xD5, 0xBA, 0xD5, 0xBA, 0x79, 0x45, 0x0E, 0x20, 0x27,\n\t0xD1, 0xEA, 0xE4, 0x24, 0x69, 0x8E, 0x52, 0xCF, 0xF4, 0x1C, 0xEF, 0xFE,\n\t0x54, 0x48, 0xC0, 0x01, 0x8D, 0xA3, 0xF5, 0x3B, 0x7C, 0x1D, 0xB2, 0x18,\n\t0x17, 0x15, 0x70, 0x38, 0xF4, 0x7D, 0xE9, 0xCE, 0xEB, 0xC0, 0xD0, 0x03,\n\t0x59, 0xE8, 0x65, 0x03, 0x8F, 0xB0, 0x43, 0xCF, 0xC3, 0x42, 0x59, 0xE7,\n\t0x24, 0x17, 0x42, 0x30, 0x55, 0xCB, 0xCA, 0xA6, 0x44, 0x10, 0xE5, 0x71,\n\t0x8E, 0x34, 0x22, 0xF7, 0x64, 0x23, 0x3C, 0xE0, 0xC8, 0x2D, 0xC5, 0xCA,\n\t0x21, 0x0A, 0x43, 0xD1, 0x8B, 0x40, 0x20, 0x3E, 0x6B, 0xBB, 0xC0, 0x1C,\n\t0xC1, 0xF0, 0x02, 0x13, 0x4E, 0xF8, 0xEF, 0x9A, 0xA3, 0x63, 0x8B, 0x0A,\n\t0xD6, 0xCB, 0x68, 0xB2, 0xC6, 0x13, 0xC2, 0x95, 0xF9, 0x80, 0x7A, 0x5C,\n\t0x3B, 0xDD, 0x50, 0xDE, 0xCD, 0x57, 0x14, 0x4E, 0xB0, 0x34, 0x83, 0x89,\n\t0xF5, 0xC5, 0xCF, 0x2A, 0x3F, 0x56, 0x4F, 0xE2, 0x8A, 0x54, 0x77, 0x55,\n\t0x6B, 0x27, 0xC7, 0xFA, 0x04, 0x95, 0x8F, 0xF9, 0x47, 0x0A, 0xA0, 0x88,\n\t0xD4, 0x46, 0x2A, 0x67, 0xAA, 0xC2, 0xEF, 0x2A, 0xC4, 0xCE, 0x7F, 0xA0,\n\t0xB1, 0x52, 0x33, 0x4B, 0x7C, 0x7E, 0x1C, 0x17, 0xFB, 0xCC, 0xE1, 0x92,\n\t0x53, 0xB3, 0x9F, 0x02, 0xA0, 0xF2, 0x7B, 0x89, 0x7C, 0x11, 0xC0, 0x93,\n\t0xBB, 0x8C, 0x3F, 0x80, 0x5E, 0x24, 0xCB, 0xDA, 0xD0, 0xAF, 0xBA, 0xB8,\n\t0x90, 0xFD, 0x8F, 0xAA, 0xF2, 0x36, 0x5A, 0x14, 0xD1, 0xEB, 0x7F, 0xA9,\n\t0x21, 0x7F, 0x6E, 0xAB, 0xB4, 0x70, 0xCF, 0x21, 0x10, 0x78, 0x04, 0xE7,\n\t0x32, 0xAA, 0x60, 0x1B, 0xEC, 0xF0, 0x1C, 0x07, 0xE6, 0xAF, 0x42, 0xBD,\n\t0x8B, 0x2A, 0xA7, 0x3C, 0xB2, 0xFD, 0xE7, 0xCF, 0x8F, 0x19, 0x3D, 0x09,\n\t0x8B, 0x9A, 0x98, 0xF7, 0x38, 0x42, 0x59, 0x98, 0x56, 0x3D, 0xD1, 0xCB,\n\t0x9C, 0x6C, 0x2F, 0x45, 0xF6, 0x0A, 0x4E, 0x92, 0x89, 0xD3, 0xAF, 0x6E,\n\t0xBF, 0x1C, 0xB4, 0xC1, 0x5B, 0x41, 0x21, 0x6D, 0xD4, 0x95, 0x17, 0x8B,\n\t0xDB, 0x20, 0xA1, 0x16, 0x76, 0xFA, 0xFF, 0xB7, 0xEC, 0x1D, 0x70, 0x04,\n\t0x45, 0xFD, 0x18, 0xD4, 0x7D, 0x9A, 0x17, 0x55, 0x01, 0x0A, 0xE3, 0x1B,\n\t0xDB, 0x8C, 0x5F, 0x3F, 0x48, 0x18, 0x99, 0x08, 0x93, 0xA6, 0xAD, 0xED,\n\t0x48, 0xDA, 0xFE, 0x8F, 0xF2, 0xEF, 0x4C, 0x8E, 0xFE, 0x6C, 0xC2, 0x46,\n\t0xE3, 0xEC, 0x73, 0xD9, 0x77, 0x83, 0x6F, 0xE9, 0x5C, 0xA6, 0xB6, 0x60,\n\t0x10, 0xD8, 0x03, 0x0A, 0xD0, 0xC7, 0xB4, 0x7D, 0xFE, 0x85, 0xDA, 0xE1,\n\t0xF3, 0x85, 0xB4, 0xC3, 0x67, 0xAA, 0xFB, 0x6C, 0x84, 0xB8, 0x7E, 0xDA,\n\t0x13, 0x95, 0x18, 0x2A, 0x0E, 0xF1, 0xAC, 0x3F, 0x93, 0x50, 0x20, 0xF6,\n\t0x84, 0x0C, 0xAE, 0x0A, 0x6C, 0x42, 0xDE, 0xA5, 0x97, 0x9C, 0x74, 0xEC,\n\t0xED, 0xBE, 0x11, 0xE2, 0xBE, 0x57, 0x02, 0x3E, 0xDB, 0xD1, 0x1C, 0xC4,\n\t0x4B, 0xB7, 0x4B, 0xA7, 0xB9, 0x74, 0xC8, 0xC2, 0x6C, 0x39, 0x79, 0x6B,\n\t0x17, 0x21, 0xCB, 0xDB, 0xB3, 0x71, 0xB1, 0xD2, 0xA4, 0x06, 0x11, 0x98,\n\t0x6D, 0xE8, 0x85, 0x30, 0x1A, 0x46, 0x47, 0x7D, 0x87, 0x7D, 0x03, 0xBD,\n\t0x64, 0xCD, 0x7C, 0x5C, 0x54, 0xBB, 0xE3, 0x2A, 0x3C, 0x4C, 0xB0, 0xAF,\n\t0x6A, 0xBF, 0x18, 0x40, 0xC4, 0x3A, 0x9E, 0x84, 0x01, 0x56, 0xB0, 0xF5,\n\t0xD4, 0xE0, 0xD2, 0x95, 0x7E, 0x85, 0x34, 0xDF, 0xC3, 0xAB, 0xFE, 0x5C,\n\t0xA6, 0x8C, 0xA5, 0x96, 0xAB, 0x51, 0x53, 0xEE, 0x80, 0x18, 0x8A, 0x87,\n\t0x61, 0x91, 0x3E, 0x93, 0x01, 0x85, 0xE8, 0x85, 0x84, 0x7A, 0x12, 0x29,\n\t0x58, 0xFF, 0xE7, 0xE0, 0x3D, 0x97, 0x1C, 0x94, 0x29, 0xFB, 0xB2, 0x1B,\n\t0xEB, 0xD1, 0x20, 0xAA, 0x52, 0x12, 0xA0, 0x0B, 0xC5, 0xB4, 0xBF, 0x4C,\n\t0xFB, 0xBF, 0x98, 0xCF, 0xD9, 0xE7, 0x96, 0xEE, 0xD2, 0x26, 0x0B, 0x04,\n\t0x0E, 0xE5, 0x37, 0xA5, 0xF7, 0x36, 0x35, 0x97, 0xFA, 0x35, 0xD2, 0xC0,\n\t0xA2, 0x5B, 0x2B, 0x25, 0x29, 0xF0, 0x18, 0x3B, 0xE6, 0x0C, 0xE4, 0x52,\n\t0x7F, 0x48, 0x15, 0xD0, 0x68, 0x3D, 0x6F, 0x68, 0x32, 0xB8, 0xF1, 0xCD,\n\t0x96, 0x6D, 0x48, 0x33, 0xEA, 0x57, 0x84, 0xCE, 0x1C, 0x93, 0x22, 0x8E,\n\t0xC0, 0x6E, 0x76, 0x0D, 0x87, 0x2E, 0x36, 0xCE, 0x2C, 0x65, 0xBD, 0xA9,\n\t0xBF, 0xB4, 0x88, 0xAB, 0x83, 0x74, 0x15, 0xC4, 0xDF, 0xA7, 0x4B, 0x7D,\n\t0xB3, 0xB8, 0x72, 0x8C, 0x57, 0x9C, 0xE8, 0xBB, 0xB3, 0x1D, 0xF1, 0xE4,\n\t0x11, 0x64, 0xEA, 0xB4, 0x17, 0xCF, 0x1F, 0xBF, 0x1D, 0xC0, 0xDE, 0x70,\n\t0xF8, 0xAF, 0x39, 0xFF, 0x30, 0x41, 0x7F, 0x5F, 0x21, 0x06, 0x09, 0x08,\n\t0x95, 0x1E, 0x6D, 0x47, 0x01, 0xF5, 0xA0, 0xD5, 0xF7, 0xA9, 0xF3, 0xB4,\n\t0x63, 0x8D, 0xB3, 0xBC, 0x0F, 0xC8, 0x83, 0xAD, 0x22, 0x31, 0x74, 0x1C,\n\t0xD7, 0xAB, 0x23, 0x74, 0x89, 0xBF, 0x3D, 0xBD, 0xF5, 0x47, 0xAB, 0x82,\n\t0x75, 0x81, 0x3D, 0x8C, 0xC9, 0x6E, 0x6F, 0x36, 0x45, 0x9E, 0x36, 0x1D,\n\t0xE2, 0xF8, 0x92, 0x27, 0xAB, 0x4B, 0x5B, 0xDD, 0xC2, 0x55, 0x3A, 0x1C,\n\t0x3E, 0xE4, 0xFA, 0xEF, 0xE5, 0xCB, 0xE6, 0x6A, 0xB3, 0xF8, 0x6E, 0x9C,\n\t0x65, 0x08, 0x92, 0x78, 0xF9, 0x27, 0x34, 0x40, 0xDE, 0xF3, 0xA3, 0xDC,\n\t0x2B, 0xD8, 0x68, 0x15, 0x61, 0xF1, 0x1E, 0xBA, 0xA4, 0x7A, 0x74, 0x13,\n\t0x48, 0x84, 0xA5, 0x79, 0x4F, 0xDE, 0xBD, 0xFE, 0xF1, 0xBE, 0xB1, 0x1B,\n\t0xE9, 0x85, 0x7B, 0x5D, 0xFA, 0x34, 0x2D, 0x53, 0xA7, 0xEE, 0x71, 0x9D,\n\t0xC8, 0xF6, 0xFA, 0xB1, 0x5D, 0xAD, 0x06, 0x76, 0x2C, 0xE5, 0x04, 0x3F,\n\t0x0F, 0x5F, 0x19, 0xD6, 0x56, 0x7B, 0xAB, 0xFB, 0x5E, 0xFB, 0x2B, 0x0A,\n\t0x52, 0xAB, 0x5B, 0xBB, 0x71, 0x69, 0x7C, 0xB4, 0x57, 0x29, 0x4D, 0x08,\n\t0x86, 0x2B, 0x9E, 0xFE, 0xAC, 0x9F, 0x73, 0xBE, 0x93, 0x23, 0x2A, 0xC4,\n\t0x7B, 0xEE, 0xF2, 0x9A, 0x71, 0xC1, 0x65, 0x14, 0xD6, 0xDC, 0x8A, 0x7E,\n\t0x32, 0x28, 0x68, 0xB7, 0xD0, 0x0E, 0xE7, 0x29, 0xBC, 0xD4, 0x54, 0x60,\n\t0xB2, 0xC4, 0x7B, 0x3A, 0x92, 0x1B, 0xF0, 0x61, 0xDB, 0x01, 0x13, 0xE7,\n\t0xF2, 0x9A, 0xFE, 0xB8, 0x8E, 0x3A, 0xC8, 0x09, 0x9A, 0x3E, 0x70, 0x05,\n\t0x60, 0x81, 0x64, 0xDF, 0x84, 0xEF, 0x29, 0x92, 0xEF, 0xA4, 0x32, 0x53,\n\t0x27, 0x52, 0xE2, 0x7B, 0x81, 0x0B, 0x0A, 0x83, 0xE8, 0x73, 0xF2, 0x36,\n\t0xC7, 0xA4, 0xDC, 0xBF, 0xB6, 0xBB, 0x60, 0x61, 0x7B, 0xD0, 0x3B, 0xA8,\n\t0xB1, 0x5A, 0x0C, 0x46, 0xEB, 0x68, 0x68, 0x1F, 0xA9, 0x70, 0xA9, 0x5A,\n\t0xBB, 0xAF, 0xDD, 0xFD, 0xEC, 0xEB, 0xB8, 0x75, 0x8D, 0x2A, 0x82, 0xD2,\n\t0xF0, 0xA6, 0x75, 0xB7, 0xEF, 0x33, 0x5D, 0x6B, 0xA2, 0x6A, 0x6A, 0xA1,\n\t0x22, 0x7A, 0x08, 0xA5, 0x7B, 0xAD, 0x52, 0x5E, 0xB6, 0x0E, 0x5F, 0xF6,\n\t0xD6, 0xB9, 0xD5, 0x30, 0x4C, 0xFB, 0xF1, 0x80, 0xA2, 0x24, 0x4A, 0xA0,\n\t0x9E, 0x61, 0xAB, 0xC2, 0xD3, 0x99, 0x4C, 0xB4, 0xBE, 0xC1, 0x64, 0xD1,\n\t0xF2, 0xF1, 0x61, 0xB8, 0x74, 0x45, 0x0C, 0xAD, 0xD0, 0x38, 0x9A, 0x7B,\n\t0xB7, 0x1F, 0x59, 0x20, 0x46, 0x85, 0x63, 0x8C, 0xA2, 0x25, 0xB4, 0x81,\n\t0x8C, 0x11, 0x13, 0xE7, 0x3A, 0x4A, 0x24, 0x94, 0x6F, 0x34, 0x0E, 0x13,\n\t0x8E, 0x5A, 0xED, 0xC5, 0x4E, 0x9E, 0x2C, 0x2E, 0xEF, 0x4C, 0x00, 0xD6,\n\t0xB4, 0x96, 0xE4, 0x1F, 0xCF, 0x66, 0x4B, 0xA0, 0xC2, 0xD3, 0xF3, 0x18,\n\t0x05, 0xBA, 0xAB, 0x7E, 0x32, 0xF7, 0x54, 0xBA, 0x64, 0xE7, 0xC3, 0x44,\n\t0x95, 0x4C, 0x62, 0xF9, 0x6F, 0x50, 0x27, 0xEB, 0xB1, 0xFE, 0xD8, 0xBD,\n\t0xD8, 0x44, 0x4D, 0x48, 0xC4, 0xBC, 0xB5, 0x4E, 0xF7, 0x2B, 0x3F, 0xC8,\n\t0x15, 0x34, 0xC7, 0x8E, 0x83, 0x91, 0xFD, 0x73, 0xBA, 0x27, 0x4D, 0xA3,\n\t0x4B, 0x4A, 0x3E, 0x13, 0xCE, 0x7B, 0xBF, 0xDD, 0x2F, 0x25, 0x22, 0xEA,\n\t0xC7, 0x24, 0x41, 0x0B, 0x23, 0xFD, 0x1F, 0x2E, 0x57, 0x19, 0xF8, 0xD6,\n\t0x87, 0x3E, 0x3A, 0xE8, 0x57, 0x00, 0xB7, 0xF2, 0xC2, 0xC5, 0x79, 0x5B,\n\t0x4D, 0x7F, 0xE5, 0xF8, 0x10, 0x8D, 0xFC, 0x02, 0xC8, 0x0D, 0xDA, 0x9A,\n\t0x85, 0xF0, 0xBD, 0xA2, 0x8D, 0x5A, 0x6A, 0x94, 0xB6, 0x96, 0x2B, 0xD4,\n\t0x4E, 0x77, 0x2F, 0x4F, 0x94, 0xAB, 0xD1, 0x4F, 0xDD, 0xA7, 0x53, 0x65,\n\t0xB1, 0x6B, 0x95, 0x4C, 0x3F, 0x41, 0x50, 0x62, 0x49, 0x54, 0x2D, 0x1D,\n\t0x4A, 0xE5, 0x45, 0x19, 0xBF, 0x37, 0xE8, 0x25, 0xE1, 0xF6, 0x77, 0x2B,\n\t0x59, 0x17, 0x72, 0x58, 0xE6, 0x42, 0x39, 0x9F, 0x8D, 0xB1, 0x62, 0x42,\n\t0xE1, 0x31, 0x4C, 0x2F, 0x00, 0xCB, 0x1F, 0xFB, 0x30, 0x1C, 0x8A, 0x4C,\n\t0x2A, 0xF9, 0x6E, 0x63, 0x90, 0x2B, 0x41, 0xC5, 0x3C, 0x87, 0xB6, 0x3F,\n\t0x83, 0xC8, 0x16, 0x9D, 0x9E, 0x15, 0x8D, 0x8F, 0xB7, 0x75, 0xB7, 0x1E,\n\t0x8B, 0xA5, 0x08, 0xBE, 0x26, 0x74, 0xF0, 0x8D, 0x10, 0x0C, 0x4C, 0x2E,\n\t0x33, 0x79, 0x85, 0x30, 0xF2, 0xC3, 0xD1, 0x3F, 0x11, 0x4A, 0x02, 0x35,\n\t0x33, 0x67, 0xAE, 0x38, 0x01, 0x9A, 0x88, 0xC9, 0x08, 0x50, 0x9C, 0x70,\n\t0x66, 0x4B, 0xB8, 0xF7, 0x0D, 0x83, 0xA8, 0x0C, 0x04, 0xD2, 0xFD, 0x7E,\n\t0x77, 0xAE, 0xCD, 0xAC, 0x47, 0xBD, 0x6E, 0x53, 0x5D, 0xC5, 0xB9, 0xB3,\n\t0x1A, 0x66, 0x7D, 0x27, 0xE4, 0x14, 0xA3, 0xF2, 0xF2, 0x98, 0xD3, 0x37,\n\t0x70, 0xD1, 0xDE, 0x27, 0x72, 0x2B, 0x2A, 0xA6, 0xB1, 0x1B, 0x50, 0x8F,\n\t0x82, 0xB1, 0x86, 0x26, 0x0A, 0x30, 0x76, 0xA3, 0x82, 0x89, 0x22, 0x48,\n\t0x5E, 0xA2, 0xCF, 0x3B, 0xC7, 0x1E, 0x0D, 0x41, 0x10, 0x6F, 0xF2, 0x53,\n\t0x17, 0x42, 0x7F, 0x83, 0xB3, 0xC9, 0x39, 0x6B, 0x69, 0x18, 0xF3, 0x41,\n\t0x5A, 0x97, 0xD9, 0x54, 0x1A, 0x70, 0x5F, 0x8C, 0x94, 0xB0, 0x83, 0x32,\n\t0xF4, 0x5B, 0x3A, 0x19, 0xD1, 0x8E, 0xF1, 0x3B, 0x4B, 0x07, 0x58, 0x16,\n\t0x0F, 0x2F, 0xB6, 0x55, 0xDC, 0xCD, 0x76, 0xDC, 0xF7, 0x0B, 0xE5, 0xAC,\n\t0x55, 0x03, 0x84, 0xAE, 0xD0, 0xEE, 0x9D, 0x74, 0x92, 0xA1, 0xA3, 0x97,\n\t0x3B, 0x22, 0x82, 0xDF, 0x93, 0x26, 0x2A, 0x2E, 0xD2, 0xF9, 0xF3, 0x24,\n\t0x5F, 0x6B, 0x13, 0x50, 0x54, 0x7C, 0x75, 0xF4, 0x34, 0x2C, 0x56, 0xA7,\n\t0x03, 0x8E, 0xAA, 0xBE, 0xA5, 0x0C, 0xD4, 0xAA, 0x15, 0x8C, 0xEC, 0x1E,\n\t0xB1, 0xCA, 0x67, 0x8D, 0x91, 0x0C, 0xB3, 0x09, 0xC4, 0xE5, 0xBE, 0x9F,\n\t0xFA, 0x35, 0x21, 0x0C, 0x10, 0xDD, 0x5A, 0xB1, 0x40, 0xE9, 0xC1, 0x53,\n\t0xD1, 0x84, 0x13, 0x7F, 0x36, 0x49, 0xEC, 0xAF, 0x63, 0x46, 0x72, 0x13,\n\t0xD0, 0x35, 0x90, 0xFB, 0xF9, 0x95, 0xCB, 0xF3, 0xB1, 0x24, 0x3C, 0x3A,\n\t0xC2, 0x20, 0x89, 0x27, 0xCB, 0x28, 0x92, 0xCB, 0x1F, 0x6F, 0x0F, 0x05,\n\t0x55, 0x8A, 0x50, 0xE9, 0x9E, 0x54, 0x69, 0x8A, 0x74, 0xC2, 0x98, 0x01,\n\t0x30, 0x7B, 0x25, 0x61, 0xF3, 0xF5, 0x60, 0xFF, 0x1A, 0xFA, 0x3E, 0x11,\n\t0xDB, 0xCC, 0x9D, 0x17, 0xCC, 0x42, 0xED, 0x10, 0xE2, 0x23, 0x0B, 0x7B,\n\t0x9E, 0x9B, 0x7A, 0x52, 0xD5, 0xFE, 0x51, 0xD3, 0x2E, 0x14, 0xF5, 0x58,\n\t0xF6, 0x9E, 0x0D, 0x2B, 0xA6, 0x4F, 0x51, 0xB2, 0xE4, 0xC7, 0x96, 0x83,\n\t0x26, 0xC4, 0xD9, 0x86, 0xF8, 0x7B, 0x65, 0xA2, 0x93, 0xF1, 0xEB, 0x00,\n\t0xBA, 0x20, 0x23, 0x9C, 0x59, 0xBC, 0x79, 0x95, 0xFF, 0xA7, 0xD9, 0xAF,\n\t0x3C, 0xF7, 0xBF, 0x63, 0x15, 0xA1, 0xDD, 0xFA, 0x41, 0x39, 0xE4, 0xAA,\n\t0xBA, 0xB5, 0x9E, 0x14, 0x86, 0x9D, 0x05, 0x56, 0x81, 0x6A, 0x22, 0x7C,\n\t0x3D, 0x76, 0x89, 0x06, 0xC4, 0x61, 0xE4, 0x39, 0xF0, 0x4E, 0x66, 0x95,\n\t0x1B, 0x09, 0x0D, 0x74, 0x5C, 0x6C, 0x03, 0x4E, 0xCA, 0xD5, 0x32, 0xD0,\n\t0x03, 0x2F, 0x09, 0xB9, 0x12, 0x32, 0x29, 0x44, 0x38, 0x97, 0x7E, 0xC0,\n\t0x5F, 0x66, 0x74, 0x3B, 0xB9, 0x98, 0x53, 0x94, 0x83, 0x7C, 0xAA, 0xC7,\n\t0xCE, 0x74, 0xC8, 0x80, 0x97, 0xB3, 0x80, 0x97, 0x7A, 0x66, 0xE5, 0xC9,\n\t0x50, 0x20, 0xC9, 0xD1, 0x84, 0xDC, 0xDC, 0x5C, 0x07, 0x43, 0x60, 0x97,\n\t0xD9, 0xA5, 0x6E, 0x8A, 0x7B, 0x98, 0xDB, 0x1C, 0x75, 0xE5, 0x58, 0x7F,\n\t0x61, 0x68, 0xFC, 0xEE, 0x32, 0x58, 0x6C, 0xF7, 0xA9, 0x0B, 0x56, 0x41,\n\t0x2C, 0x65, 0x16, 0xBD, 0xE1, 0xD6, 0xC1, 0xA0, 0xE2, 0x10, 0x61, 0xDB,\n\t0xC2, 0x8D, 0x5A, 0x9A, 0x70, 0x95, 0xD8, 0x72, 0xB0, 0x41, 0x88, 0x40,\n\t0xFD, 0x7D, 0xDE, 0x9E, 0x07, 0x79, 0xBA, 0xFD, 0x9E, 0xF9, 0x67, 0xB7,\n\t0x07, 0x13, 0x27, 0x13, 0xDC, 0xD9, 0x5A, 0xAD, 0x0D, 0x42, 0xA9, 0x7B,\n\t0x52, 0x17, 0x85, 0x49, 0x23, 0xE0, 0x10, 0x7D, 0xB3, 0xF5, 0x36, 0x21,\n\t0x2F, 0x01, 0xE9, 0x7B, 0x32, 0x75, 0x3C, 0xEC, 0x83, 0x4C, 0xA3, 0x56,\n\t0xD6, 0x4F, 0x84, 0xE2, 0xF5, 0xF9, 0x7D, 0x0D, 0x12, 0x0A, 0x7D, 0xA2,\n\t0xAA, 0x19, 0xF4, 0x53, 0x4C, 0x2F, 0x4A, 0xB4, 0x03, 0x22, 0x2E, 0xBE,\n\t0x6D, 0x1F, 0x2A, 0xD1, 0x98, 0x81, 0xC1, 0xEF, 0xEB, 0x0E, 0xD6, 0x8B,\n\t0x27, 0x47, 0x73, 0x61, 0x78, 0x3D, 0xBB, 0xE1, 0x92, 0xAA, 0x07, 0xF5,\n\t0x9F, 0x62, 0x51, 0xFB, 0xDC, 0x1C, 0x74, 0x6B, 0x9E, 0x0E, 0xDF, 0xCF,\n\t0xB6, 0x71, 0x8A, 0x5E, 0x8E, 0x83, 0x00, 0xEA, 0x43, 0xF8, 0x48, 0xCF,\n\t0xCA, 0x71, 0x3F, 0x85, 0xB8, 0x00, 0xAE, 0x5D, 0xC1, 0xD9, 0x3B, 0xAE,\n\t0x60, 0xB8, 0x0F, 0xE3, 0xE6, 0xDB, 0x23, 0x10, 0x93, 0x6C, 0x04, 0xE4,\n\t0xFB, 0x36, 0x24, 0xF4, 0xB8, 0xE0, 0xA0, 0xBF, 0x8D, 0xA6, 0x34, 0x46,\n\t0x0B, 0x37, 0x9C, 0x67, 0xE7, 0x5A, 0x65, 0xE7, 0x2D, 0x64, 0x4B, 0x5D,\n\t0x83, 0x86, 0xEC, 0xA2, 0x64, 0x3C, 0xB7, 0x78, 0xEE, 0xD3, 0x29, 0xAF,\n\t0x86, 0x0C, 0xB4, 0xDF, 0x69, 0x8F, 0xAF, 0x33, 0x4B, 0x52, 0x82, 0xCF,\n\t0x2A, 0xB2, 0x5B, 0x5F, 0x18, 0x26, 0xA7, 0x23, 0x1F, 0x8B, 0x3C, 0x90,\n\t0xCD, 0x75, 0x6B, 0x07, 0x4A, 0x1F, 0xF3, 0x60, 0xB6, 0x7D, 0xE0, 0x0A,\n\t0xBD, 0x99, 0x8B, 0xEA, 0x3F, 0xF9, 0x03, 0x10, 0x0B, 0x36, 0xBD, 0xBC,\n\t0x5A, 0xA3, 0x86, 0x37, 0x8F, 0x8D, 0x74, 0x44, 0x39, 0xAB, 0xC1, 0x35,\n\t0x30, 0x92, 0xB3, 0xB5, 0xDA, 0xD4, 0xC6, 0x05, 0x3E, 0xB6, 0xAD, 0x09,\n\t0x19, 0x27, 0x89, 0x25, 0xFB, 0x17, 0x0C, 0xE4, 0x8A, 0xE1, 0x0A, 0xF1,\n\t0xBA, 0x3A, 0x88, 0x6D, 0x0F, 0xF7, 0x8A, 0x9F, 0xE0, 0x96, 0x74, 0x19,\n\t0xFF, 0xC4, 0x09, 0xFB, 0xA3, 0x4F, 0x2B, 0x50, 0xCD, 0x7F, 0x1A, 0x71,\n\t0x17, 0x59, 0x81, 0xC1, 0x1A, 0xA4, 0x0A, 0x50, 0xB0, 0x82, 0x5F, 0x7C,\n\t0x26, 0xD7, 0xEB, 0xBC, 0x91, 0xF2, 0x05, 0xEF, 0xCC, 0x04, 0xED, 0x61,\n\t0xC5, 0x46, 0xF7, 0x0E, 0x0D, 0xBB, 0x3B, 0x60, 0x27, 0x95, 0x40, 0xCD,\n\t0xA8, 0xE1, 0xCA, 0xEA, 0x9F, 0x70, 0x06, 0x23, 0xDA, 0x1D, 0xDB, 0x93,\n\t0x3C, 0x9F, 0x7A, 0x95, 0x34, 0x63, 0xB1, 0xEF, 0x8C, 0xB5, 0x24, 0xD5,\n\t0x0B, 0xA3, 0xBA, 0x64, 0x76, 0x7B, 0x17, 0xD7, 0xE9, 0x19, 0xF4, 0xBE,\n\t0xCA, 0x65, 0x7D, 0x39, 0x54, 0x07, 0x2E, 0xE4, 0xD3, 0x2E, 0x95, 0x32,\n\t0x9F, 0x76, 0x1B, 0x89, 0x69, 0xD3, 0x4C, 0x1E, 0x44, 0xBC, 0x81, 0xCA,\n\t0xB8, 0xD2, 0xDC, 0x6D, 0x46, 0xD3, 0xC9, 0xF8, 0xA2, 0xD4, 0x30, 0xD9,\n\t0xF4, 0x30, 0xA0, 0x36, 0xBE, 0x92, 0x2C, 0x65, 0x6B, 0x7F, 0x7A, 0x6B,\n\t0xB7, 0x4E, 0xF1, 0x69, 0xDD, 0x02, 0x44, 0xCB, 0xB5, 0x36, 0x20, 0x23,\n\t0x21, 0xA4, 0x48, 0x15, 0xA0, 0x53, 0xAE, 0x98, 0x93, 0x6C, 0x74, 0xFA,\n\t0xCD, 0x9C, 0x42, 0x6B, 0x59, 0xC8, 0x3B, 0x2F, 0xDA, 0xFF, 0xEA, 0x6D,\n\t0xBD, 0xF2, 0xBA, 0xA4, 0xFA, 0x8E, 0xCC, 0x23, 0x34, 0x9E, 0x49, 0x78,\n\t0x83, 0x8E, 0x02, 0xB4, 0xEB, 0x13, 0x27, 0x06, 0xB3, 0x27, 0xD3, 0x14,\n\t0x44, 0x2E, 0x55, 0x16, 0x73, 0x7C, 0x03, 0x47, 0x1F, 0x77, 0xC7, 0x6A,\n\t0xF6, 0x79, 0xA9, 0xE9, 0x29, 0xEA, 0x84, 0x9D, 0x57, 0x16, 0xF3, 0x76,\n\t0x9F, 0x6B, 0xD6, 0x5D, 0xB2, 0xC8, 0x46, 0x0C, 0x56, 0x4B, 0x5E, 0x04,\n\t0xA3, 0xA6, 0xBB, 0x37, 0x81, 0x7D, 0xC8, 0x49, 0xF4, 0xC1, 0x0A, 0x64,\n\t0x13, 0x67, 0x1A, 0x5D, 0xB5, 0x16, 0x74, 0xB1, 0x28, 0x12, 0xE1, 0xF6,\n\t0xED, 0x62, 0x23, 0x4B, 0x08, 0x77, 0x7C, 0x30, 0xAF, 0x8D, 0xAA, 0x91,\n\t0xEF, 0xE0, 0x88, 0x4F, 0xA1, 0xB9, 0x44, 0xA8, 0x15, 0x7B, 0xC3, 0xE9,\n\t0xA5, 0x60, 0x11, 0x53, 0x54, 0x18, 0xFF, 0xB2, 0x48, 0x8C, 0xC2, 0x03,\n\t0x9D, 0x0C, 0x82, 0xB7, 0x3D, 0x0B, 0x7D, 0xAA, 0xEA, 0x50, 0x00, 0x53,\n\t0x41, 0xF5, 0xF7, 0xDA, 0xF4, 0x61, 0x5B, 0x8C, 0x89, 0x63, 0x89, 0xFB,\n\t0x97, 0xCA, 0xCE, 0xAE, 0x80, 0xB9, 0x6C, 0x46, 0xE1, 0x31, 0x8A, 0xF9,\n\t0xA9, 0xFE, 0x3C, 0xC5, 0xB0, 0xE3, 0x04, 0xA8, 0x14, 0x06, 0x54, 0x52,\n\t0x3E, 0x9E, 0x5A, 0x47, 0x67, 0x43, 0x2F, 0x09, 0xAF, 0xB0, 0x67, 0x69,\n\t0x87, 0x1F, 0xEF, 0xDF, 0x91, 0xC4, 0x48, 0x21, 0x41, 0xB0, 0xC5, 0x91,\n\t0x8F, 0xE3, 0x48, 0xA7, 0x4E, 0x3A, 0xBF, 0x22, 0x3F, 0xCC, 0xAE, 0x70,\n\t0x94, 0x8A, 0xAB, 0x34, 0xFC, 0x1A, 0x83, 0x8B, 0xAE, 0x1B, 0xA7, 0xC7,\n\t0x99, 0x7C, 0x45, 0x60, 0x6F, 0x81, 0x07, 0xE2, 0x95, 0x7D, 0xE1, 0x55,\n\t0x79, 0xC3, 0xA0, 0x0D, 0xBA, 0x9F, 0x22, 0x5A, 0x44, 0x79, 0x6F, 0x06,\n\t0x57, 0x89, 0x06, 0x97, 0x7F, 0x67, 0x71, 0xBB, 0xEF, 0xFF, 0xE4, 0x3E,\n\t0x9F, 0x63, 0x36, 0xFD, 0x74, 0xDB, 0x90, 0x49, 0x0D, 0xA5, 0xF8, 0xAD,\n\t0x60, 0x78, 0x08, 0x05, 0x8C, 0xFF, 0xF5, 0xD6, 0x5C, 0xEA, 0x1E, 0x7E,\n\t0x3A, 0x7B, 0xDE, 0xD7, 0x7F, 0xE8, 0x66, 0xFD, 0x53, 0x3F, 0x98, 0x2C,\n\t0x2B, 0xBC, 0x5D, 0x36, 0x40, 0xAF, 0xCC, 0xFC, 0x08, 0x00, 0x2D, 0x39,\n\t0xA6, 0x8B, 0x03, 0xFC, 0x3F, 0x94, 0x72, 0x34, 0xC0, 0x7E, 0xB8, 0x68,\n\t0x83, 0xB6, 0x5B, 0x90, 0x15, 0x32, 0x65, 0x7E, 0x36, 0x71, 0x4B, 0x15,\n\t0x54, 0x7E, 0x0D, 0x71, 0x92, 0xB7, 0xF9, 0x35, 0x90, 0x28, 0x89, 0x8D,\n\t0x29, 0x47, 0x78, 0xBF, 0xDC, 0x4F, 0x15, 0x51, 0x23, 0xBF, 0x7F, 0xBB,\n\t0x0A, 0xAB, 0xD6, 0xC3, 0xAF, 0x50, 0xE7, 0x58, 0x8E, 0x31, 0x93, 0x47,\n\t0xAF, 0xF8, 0xCE, 0xC6, 0xA8, 0x8F, 0xC2, 0x89, 0xE9, 0x69, 0x23, 0x5A,\n\t0xDA, 0x11, 0x6F, 0x2A, 0x74, 0x17, 0xE2, 0x9D, 0x53, 0x36, 0x14, 0xE4,\n\t0x6E, 0xCF, 0xC5, 0x26, 0x06, 0x96, 0x3A, 0xC4, 0xED, 0x1A, 0x8B, 0xF6,\n\t0xF4, 0x7E, 0x9D, 0x6D, 0x24, 0x81, 0x23, 0xCA, 0xAB, 0x07, 0xB4, 0x11,\n\t0x8E, 0x14, 0xCE, 0x63, 0x82, 0x6C, 0xF4, 0x64, 0x02, 0xA3, 0x32, 0x81,\n\t0x07, 0x82, 0xBC, 0x1D, 0xB0, 0x04, 0xB4, 0x4C, 0xD8, 0x83, 0x48, 0xFE,\n\t0xA5, 0x89, 0xD4, 0xF6, 0xBD, 0xB6, 0xBF, 0xB6, 0x0D, 0xFE, 0x7B, 0x2B,\n\t0x29, 0x62, 0x91, 0xE6, 0x13, 0xA8, 0x4C, 0xC2, 0xBB, 0x01, 0x27, 0x0C,\n\t0xF4, 0x91, 0xC8, 0xD2, 0x25, 0xF8, 0x2C, 0xE9, 0xE9, 0x25, 0x59, 0x92,\n\t0xB0, 0xEB, 0x19, 0xBF, 0xD1, 0x02, 0x9E, 0x08, 0x44, 0xAB, 0x54, 0xBE,\n\t0x54, 0x1E, 0xBB, 0x17, 0x29, 0xD8, 0xDF, 0x65, 0x79, 0x01, 0x0B, 0x5D,\n\t0x32, 0xB2, 0xA5, 0x32, 0x6E, 0x7B, 0x0F, 0x7E, 0xB5, 0x45, 0x52, 0xD3,\n\t0x12, 0x11, 0xE0, 0xDD, 0x82, 0x24, 0x70, 0xD1, 0x9C, 0x46, 0xBB, 0x42,\n\t0xB0, 0x35, 0x09, 0x5B, 0xAC, 0xC9, 0x99, 0x21, 0x64, 0xF9, 0xD1, 0x0E,\n\t0xCA, 0xB0, 0xB8, 0x21, 0x5B, 0xF0, 0xA0, 0x4D, 0x64, 0x42, 0xCD, 0x00,\n\t0x40, 0xB6, 0xD7, 0x32, 0x0B, 0x49, 0x8C, 0xB1, 0x34, 0x81, 0x97, 0x32,\n\t0xA9, 0xB8, 0x69, 0xC4, 0x45, 0x5E, 0x06, 0xD1, 0x76, 0x6F, 0xB2, 0x81,\n\t0x8F, 0x35, 0xD6, 0xDD, 0x64, 0x3D, 0x38, 0xA3, 0x17, 0x05, 0xAF, 0x57,\n\t0x1C, 0xDD, 0xA1, 0x73, 0x39, 0x6E, 0x1E, 0xFA, 0x8A, 0x5C, 0xEC, 0x92,\n\t0x83, 0xB7, 0xC0, 0x51, 0xA4, 0x13, 0xE2, 0xCA, 0x2F, 0x38, 0x11, 0xFE,\n\t0x81, 0x88, 0x01, 0x06, 0x98, 0x5E, 0xCF, 0xFD, 0xC7, 0x69, 0x1D, 0xE5,\n\t0xEF, 0x86, 0x52, 0x46, 0x74, 0x3F, 0xCF, 0x09, 0xBD, 0xED, 0x03, 0x45,\n\t0x7C, 0x8A, 0xBB, 0x25, 0x2B, 0x4C, 0x0F, 0xE7, 0xC9, 0x04, 0x24, 0x6C,\n\t0xDE, 0xF2, 0x79, 0xDA, 0xC9, 0xAD, 0x2A, 0xF9, 0xDC, 0x6B, 0xAF, 0x54,\n\t0xDC, 0x60, 0x7F, 0x9F, 0x20, 0x65, 0x03, 0x26, 0xAD, 0xE7, 0x94, 0xCB,\n\t0xDA, 0x7E, 0x9A, 0xC5, 0x48, 0xD2, 0x9E, 0x4D, 0x66, 0x0D, 0x0C, 0xEA,\n\t0x90, 0x7A, 0xCB, 0x3F, 0x98, 0x18, 0x51, 0xFD, 0xC8, 0x29, 0x35, 0xF6,\n\t0xCD, 0x7D, 0xDB, 0x28, 0xD2, 0x6D, 0x7F, 0xC9, 0x31, 0x0A, 0x5D, 0x78,\n\t0xE9, 0xFE, 0x2D, 0x66, 0x52, 0x23, 0xC4, 0xD2, 0x1B, 0xFC, 0x6B, 0x50,\n\t0xD1, 0xF3, 0xE5, 0x50, 0xB0, 0x14, 0xDD, 0xFF, 0x8A, 0xAE, 0x09, 0x4D,\n\t0x13, 0x6D, 0xEF, 0xBA, 0xB1, 0x79, 0xD9, 0x0B, 0x21, 0x6D, 0x2C, 0xA0,\n\t0x85, 0x6B, 0x49, 0x6B, 0x87, 0x13, 0x20, 0x03, 0x5F, 0xAC, 0xAF, 0xF1,\n\t0xFC, 0x28, 0x0D, 0x37, 0x97, 0x37, 0xC7, 0x7A, 0x97, 0xBE, 0x50, 0x6E,\n\t0x41, 0xB0, 0xEA, 0xA7, 0xD7, 0x44, 0x23, 0x62, 0xD9, 0xA8, 0x23, 0x12,\n\t0x5D, 0x37, 0xDF, 0xC7, 0x6B, 0x43, 0xE6, 0xA8, 0x50, 0xF5, 0x46, 0x03,\n\t0x53, 0x24, 0x4E, 0x82, 0x84, 0xB5, 0x25, 0xD6, 0x9F, 0x51, 0x96, 0x1C,\n\t0xCE, 0xA1, 0x93, 0x04, 0xAA, 0x25, 0x54, 0xA9, 0x66, 0xF4, 0xBE, 0xBD,\n\t0x9D, 0xF5, 0xEA, 0xE5, 0x24, 0x52, 0x26, 0xDC, 0xBF, 0x50, 0x4B, 0x2C,\n\t0xA2, 0x65, 0x1B, 0x5B, 0x53, 0x9F, 0xFD, 0xA2, 0x81, 0x0C, 0xDD, 0xAF,\n\t0xD1, 0xF6, 0xB8, 0x7D, 0x88, 0xD2, 0xBB, 0x85, 0xD6, 0x58, 0x11, 0x42,\n\t0x57, 0x1E, 0x25, 0x50, 0xD9, 0xD1, 0x0F, 0x9A, 0x54, 0xB8, 0x29, 0x1F,\n\t0x23, 0x99, 0x15, 0xBF, 0xF6, 0xED, 0x47, 0xC8, 0x5F, 0x72, 0xC0, 0x89,\n\t0xD5, 0xD3, 0x00, 0xFD, 0x60, 0x4D, 0x42, 0xFB, 0x61, 0xE6, 0x4D, 0xA1,\n\t0xF8, 0x78, 0x9D, 0xDF, 0x9D, 0x06, 0x36, 0xC4, 0x0A, 0x27, 0x45, 0xB1,\n\t0x6F, 0xA8, 0xE3, 0x94, 0x0E, 0x33, 0x5A, 0x1F, 0xE8, 0x3A, 0x7F, 0xB7,\n\t0x09, 0xC6, 0x91, 0xDF, 0xF3, 0x6E, 0x12, 0x69, 0xE3, 0xCF, 0xDA, 0xF1,\n\t0x12, 0x5A, 0x6B, 0xDE, 0x65, 0x45, 0x0A, 0xD9, 0xE7, 0x24, 0x1C, 0xD4,\n\t0x09, 0x7D, 0x1E, 0x15, 0xBD, 0xB8, 0x44, 0x79, 0xF3, 0x84, 0x5E, 0x51,\n\t0xBF, 0x2C, 0x15, 0xA4, 0x02, 0x23, 0x21, 0x22, 0x0D, 0x2B, 0xA5, 0xB7,\n\t0xFC, 0x3B, 0xE4, 0x7A, 0xAA, 0x0C, 0x8E, 0x5C, 0x55, 0xE2, 0x34, 0xE6,\n\t0x02, 0xD1, 0x7F, 0x3D, 0x25, 0x35, 0x99, 0xC0, 0xDD, 0x57, 0x0C, 0x62,\n\t0x5C, 0xDB, 0x80, 0x06, 0x18, 0x31, 0x3A, 0x0E, 0xCC, 0x4A, 0x3B, 0x4C,\n\t0x8D, 0xD9, 0x0E, 0x98, 0x1C, 0xE8, 0x27, 0x75, 0x53, 0xBC, 0x44, 0xAC,\n\t0x26, 0xCC, 0x62, 0x21, 0x45, 0x5D, 0x24, 0x70, 0xB3, 0x70, 0x82, 0xFA,\n\t0x54, 0xB5, 0x1A, 0x08, 0x82, 0x30, 0x25, 0x01, 0x49, 0x00, 0x76, 0xC6,\n\t0xFB, 0xED, 0x14, 0x23, 0x15, 0x3D, 0x5A, 0x85, 0xB7, 0x88, 0x91, 0x2E,\n\t0x04, 0xB7, 0xCC, 0x62, 0x0A, 0x89, 0x6B, 0xD6, 0x43, 0xBD, 0x82, 0x6F,\n\t0xEB, 0xB1, 0x2E, 0x25, 0x48, 0xC6, 0x3A, 0x47, 0xA2, 0xA1, 0xBA, 0xCC,\n\t0x71, 0x85, 0xD6, 0xBC, 0x4C, 0x51, 0x11, 0x24, 0x32, 0xF3, 0x08, 0x16,\n\t0xD7, 0x67, 0xC9, 0x1E, 0x64, 0xCA, 0x7D, 0x39, 0xAD, 0xF9, 0x05, 0x70,\n\t0x4C, 0x7B, 0x85, 0x50, 0x98, 0x0C, 0x51, 0x1B, 0xB9, 0xA2, 0xD0, 0x1D,\n\t0x6E, 0xA8, 0xF3, 0x8E, 0x28, 0x68, 0x3A, 0xC5, 0x57, 0x9A, 0x88, 0x1B,\n\t0xC5, 0xF9, 0x12, 0x85, 0x52, 0xDA, 0x92, 0x79, 0x05, 0x3F, 0x9E, 0xCD,\n\t0x03, 0xC1, 0xCC, 0xB4, 0x71, 0xE9, 0x41, 0xFD, 0xB1, 0x16, 0xF1, 0xB6,\n\t0x7C, 0x18, 0x38, 0x91, 0x50, 0xF0, 0xA9, 0xA5, 0x6F, 0xA9, 0xF3, 0x09,\n\t0x57, 0x2E, 0xDC, 0xF6, 0x08, 0x6C, 0xC7, 0xF0, 0x7E, 0x68, 0x48, 0x68,\n\t0x3C, 0x66, 0x4A, 0xDA, 0x76, 0xC6, 0xE9, 0x72, 0x61, 0xDF, 0x4D, 0x53,\n\t0x70, 0x17, 0xEC, 0x46, 0xC2, 0x64, 0x04, 0xB1, 0x68, 0x8D, 0x42, 0x0C,\n\t0xFE, 0x6D, 0xCC, 0xFE, 0x2D, 0xA7, 0x19, 0x48, 0xAC, 0x96, 0x97, 0x1D,\n\t0x09, 0x38, 0x7E, 0x7A, 0xE2, 0x84, 0x63, 0xA3, 0xD0, 0xD4, 0x7E, 0x9C,\n\t0x92, 0xE7, 0x3F, 0xFD, 0x01, 0xF7, 0x86, 0x4C, 0xDF, 0x4B, 0x01, 0x5F,\n\t0x93, 0xEA, 0x5D, 0xFB, 0xB2, 0x8E, 0xEB, 0xEA, 0x72, 0x2A, 0xB2, 0xA7,\n\t0x19, 0xD8, 0x8E, 0x80, 0xD4, 0x84, 0x05, 0x8C, 0xD9, 0x2B, 0xCF, 0xCC,\n\t0x36, 0x6C, 0xBD, 0xCD, 0xEF, 0x55, 0x90, 0x38, 0x66, 0xDF, 0x4F, 0x0C,\n\t0x5E, 0x66, 0x75, 0x44, 0x6C, 0xD3, 0xD7, 0x8F, 0xE7, 0xF9, 0x66, 0x13,\n\t0xDE, 0xA0, 0x5F, 0xAE, 0x57, 0x2B, 0x13, 0x8E, 0xAE, 0x56, 0xBB, 0x90,\n\t0xB9, 0xFB, 0x98, 0x11, 0x83, 0x33, 0x2B, 0xF1, 0x65, 0x91, 0x7A, 0x15,\n\t0xFB, 0x74, 0x3C, 0xEF, 0x1F, 0x25, 0x34, 0xB0, 0x07, 0x05, 0x37, 0xD1,\n\t0xF7, 0xF2, 0xC0, 0x8D, 0x47, 0x82, 0xD6, 0x5E, 0x13, 0x08, 0x58, 0x90,\n\t0xF2, 0x3A, 0x88, 0xC0, 0x8F, 0x27, 0xAA, 0x84, 0x03, 0x20, 0x71, 0xE1,\n\t0xF3, 0x34, 0x25, 0xBE, 0xC5, 0x3F, 0x6F, 0x0C, 0x95, 0x36, 0xDB, 0x77,\n\t0x3A, 0xF7, 0xA9, 0x51, 0x24, 0x7E, 0x04, 0xB0, 0x13, 0xD7, 0xC4, 0x29,\n\t0x20, 0x38, 0x42, 0x5B, 0x1E, 0x9A, 0xEB, 0x3C, 0xB1, 0xC9, 0xCF, 0x48,\n\t0x1F, 0xF1, 0x86, 0xD2, 0x6B, 0x83, 0xF9, 0x63, 0x6D, 0xEE, 0xB1, 0x8A,\n\t0x5C, 0x28, 0x69, 0x96, 0x9A, 0x38, 0x53, 0x25, 0xF5, 0xAC, 0x61, 0xD8,\n\t0x0A, 0x60, 0xC8, 0xD5, 0xA6, 0xFB, 0xA6, 0x10, 0x27, 0x55, 0x6C, 0xAE,\n\t0xEA, 0x8E, 0x65, 0x7A, 0x11, 0x94, 0x17, 0x5F, 0x90, 0x3E, 0x28, 0x48,\n\t0x08, 0xC0, 0x35, 0x9B, 0x3E, 0xE8, 0x42, 0xC0, 0x94, 0x9D, 0xDD, 0x83,\n\t0xCD, 0xED, 0xB3, 0x52, 0xD3, 0xE9, 0xD8, 0x89, 0x98, 0xA0, 0xC3, 0xFE,\n\t0x49, 0x17, 0x80, 0x99, 0x56, 0x84, 0xB9, 0x4E, 0x02, 0x4B, 0x27, 0xC6,\n\t0xA8, 0xD8, 0x11, 0xFB, 0x89, 0xE0, 0xB0, 0x5A, 0xA8, 0xC1, 0xC9, 0x0B,\n\t0x04, 0xC5, 0x23, 0xA4, 0x35, 0x5A, 0x5E, 0xB7, 0x24, 0xA6, 0x4E, 0x92,\n\t0x15, 0x00, 0x2B, 0xF9, 0x9F, 0xBC, 0x6F, 0x16, 0xF4, 0xFE, 0xBF, 0xDD,\n\t0x09, 0xB1, 0x36, 0x9D, 0xFF, 0x1F, 0x91, 0x8B, 0xAC, 0xAD, 0x44, 0x19,\n\t0x19, 0xEF, 0xAD, 0x2A, 0xE8, 0xF3, 0x85, 0x5C, 0xDB, 0xF8, 0x27, 0xFD,\n\t0xAC, 0x71, 0xB0, 0x5E, 0x20, 0x53, 0xAE, 0xA4, 0x3C, 0xFE, 0x8A, 0xC0,\n\t0xEB, 0xDB, 0x45, 0xBA, 0x09, 0xCC, 0xA5, 0x0B, 0x02, 0xBE, 0xEC, 0x60,\n\t0x55, 0x76, 0x0D, 0x6F, 0xB7, 0x07, 0xBF, 0xA7, 0xCD, 0x8D, 0xB4, 0x6A,\n\t0x33, 0xF7, 0xCB, 0x2C, 0x9D, 0xA0, 0x14, 0x13, 0xC4, 0x6C, 0xD7, 0xE5,\n\t0x8D, 0xE4, 0x0F, 0x76, 0x22, 0x99, 0x6B, 0x9D, 0xF6, 0xFC, 0x7E, 0x51,\n\t0x90, 0xBF, 0x9D, 0xD2, 0xF1, 0xC8, 0x5B, 0xFE, 0x59, 0x52, 0x5C, 0x41,\n\t0x7F, 0x81, 0xB3, 0xE6, 0xBC, 0x46, 0x0B, 0xB4, 0xFA, 0xC0, 0xA2, 0x1D,\n\t0x4B, 0xE8, 0x2F, 0x01, 0x16, 0x01, 0x72, 0xB4, 0x43, 0x30, 0x22, 0xD5,\n\t0xF2, 0xD8, 0x1B, 0x36, 0xD9, 0x09, 0x49, 0x46, 0x6E, 0xBF, 0x09, 0x93,\n\t0x8C, 0xAB, 0x68, 0xF5, 0xF8, 0xC1, 0xAD, 0xA8, 0x52, 0xD9, 0x11, 0x00,\n\t0x23, 0x1F, 0x25, 0x26, 0xC5, 0x65, 0x06, 0x11, 0xA5, 0xB3, 0xF7, 0x61,\n\t0xCF, 0x71, 0xFA, 0xFD, 0xEC, 0xD6, 0x5A, 0x06, 0xB4, 0xF6, 0xD5, 0x0A,\n\t0xE5, 0x3E, 0xE1, 0xC1, 0xC7, 0xD9, 0xF0, 0xB2, 0xD9, 0xB5, 0xF4, 0x82,\n\t0x09, 0xD1, 0xED, 0x29, 0xA9, 0xF2, 0xD0, 0x52, 0xD5, 0x5C, 0x0A, 0x20,\n\t0xB5, 0x9E, 0xEF, 0xDF, 0x40, 0xB4, 0x91, 0x97, 0xAB, 0x31, 0x3F, 0x72,\n\t0x88, 0xF3, 0xFD, 0x11, 0xD2, 0xDF, 0x29, 0xBC, 0x41, 0x71, 0xF5, 0x1E,\n\t0x55, 0xB8, 0xED, 0xEC, 0x74, 0x0A, 0x22, 0x6E, 0x4B, 0xD9, 0x53, 0xE5,\n\t0x2F, 0xCF, 0x8A, 0xD7, 0xA0, 0x0F, 0x3B, 0x36, 0x17, 0x68, 0xF3, 0x9C,\n\t0x98, 0xA7, 0x4D, 0x21, 0xCE, 0x9A, 0xA0, 0xB2, 0xCA, 0x3F, 0x0D, 0xF5,\n\t0x7F, 0x6B, 0x8C, 0x9E, 0xCC, 0x20, 0xB0, 0x7C, 0xAE, 0x16, 0xC0, 0xBA,\n\t0x09, 0x1B, 0xDD, 0x07, 0x07, 0xF6, 0xC3, 0x8A, 0x0B, 0x38, 0x08, 0xD3,\n\t0xE0, 0x30, 0x46, 0x6E, 0x7C, 0x03, 0x5E, 0x62, 0xFB, 0xCE, 0x1F, 0x85,\n\t0x84, 0xF7, 0xFF, 0xEB, 0xAE, 0x9A, 0xDC, 0x6E, 0xAC, 0xAC, 0x38, 0x9A,\n\t0x5B, 0xCA, 0x7D, 0x6E, 0x40, 0x27, 0x7D, 0x9F, 0x72, 0x38, 0xEE, 0xC6,\n\t0x3D, 0xE7, 0x4F, 0x8A, 0x45, 0xBE, 0x38, 0xE6, 0x06, 0x87, 0x61, 0x0A,\n\t0x1D, 0x0A, 0x4C, 0x57, 0x82, 0x75, 0x40, 0x1A, 0x44, 0x7E, 0x79, 0xF2,\n\t0x13, 0x90, 0xAB, 0xF6, 0xDE, 0x4C, 0xBA, 0x48, 0x34, 0xF1, 0x92, 0x1F,\n\t0xA0, 0xE8, 0x57, 0x68, 0x33, 0xB5, 0x07, 0xCA, 0x95, 0x00, 0xEC, 0xD8,\n\t0xE1, 0x94, 0x44, 0x85, 0xD6, 0x61, 0x6C, 0x32, 0xBB, 0x37, 0x9C, 0x79,\n\t0x6D, 0xBF, 0x8E, 0x54, 0x31, 0xDB, 0x4C, 0xB7, 0x6D, 0x34, 0xC0, 0xEA,\n\t0x94, 0xF0, 0x50, 0xC5, 0xE5, 0xA6, 0x24, 0xDB, 0x72, 0x55, 0x9A, 0x50,\n\t0x23, 0xE9, 0x71, 0xC7, 0x7C, 0x05, 0xAA, 0x03, 0x86, 0x5E, 0x37, 0x65,\n\t0xF9, 0x07, 0x4F, 0x6E, 0x09, 0x9D, 0x11, 0x44, 0x19, 0xAD, 0xAC, 0xC6,\n\t0x66, 0x23, 0x60, 0x3A, 0xBD, 0x12, 0xEA, 0x47, 0x26, 0x11, 0x20, 0xAA,\n\t0x7B, 0xF3, 0xF2, 0xFE, 0xDA, 0x42, 0x77, 0x14, 0xFD, 0x90, 0xC7, 0xD5,\n\t0xF4, 0xB2, 0x9A, 0xD5, 0x15, 0x4E, 0x0C, 0x1E, 0x9B, 0x08, 0x3C, 0xA8,\n\t0x3D, 0xB3, 0x05, 0x8C, 0xA6, 0x90, 0x36, 0x22, 0xCE, 0x3D, 0x48, 0x30,\n\t0xCE, 0xDF, 0xD4, 0xE7, 0x5D, 0x78, 0xA8, 0x0B, 0x7D, 0x4A, 0xFE, 0x0F,\n\t0x48, 0xCE, 0x35, 0xE3, 0xB1, 0x71, 0x9F, 0x06, 0x82, 0xA5, 0xCD, 0xC2,\n\t0x85, 0xF0, 0xBC, 0x82, 0x5C, 0xE0, 0x54, 0x4E, 0x3B, 0x0B, 0x0D, 0x20,\n\t0x1F, 0xD3, 0x1F, 0x3A, 0x7A, 0xD3, 0x11, 0xBE, 0x37, 0x99, 0x5C, 0x93,\n\t0x79, 0x85, 0xC5, 0x69, 0xAC, 0x58, 0x1D, 0x4E, 0x61, 0xAB, 0xB8, 0xDF,\n\t0x5B, 0xB8, 0x81, 0x3A, 0x1A, 0x88, 0xFC, 0x1A, 0x73, 0x67, 0xB5, 0x68,\n\t0x5F, 0xEB, 0x7F, 0x4D, 0xAD, 0xB1, 0xEC, 0x88, 0x2F, 0xB3, 0xC0, 0xB4,\n\t0x5B, 0xBF, 0x01, 0x51, 0x06, 0x0B, 0xF6, 0x1A, 0x80, 0x7A, 0xF1, 0xB9,\n\t0xFB, 0x3B, 0xDE, 0xAA, 0xCA, 0x07, 0x51, 0x04, 0x74, 0x95, 0x08, 0xED,\n\t0x1B, 0xA1, 0xD6, 0x87, 0xBC, 0x4D, 0xCC, 0x71, 0x49, 0x7B, 0x68, 0x39,\n\t0x0B, 0x3D, 0xFF, 0x4C, 0x10, 0xD1, 0x77, 0x1A, 0x6F, 0xAE, 0xA2, 0xA4,\n\t0x6B, 0x83, 0x55, 0xC9, 0x94, 0x2F, 0xC5, 0x5C, 0x74, 0xF5, 0xB1, 0x31,\n\t0x5C, 0x8F, 0xD0, 0x77, 0xCC, 0xCF, 0x62, 0xDD, 0x68, 0xB6, 0xCD, 0x95,\n\t0x1B, 0xA6, 0x3E, 0x61, 0xCC, 0x1F, 0xC0, 0xC7, 0xFC, 0x24, 0xD6, 0x1E,\n\t0xF3, 0x2E, 0x98, 0x79, 0x3D, 0xDF, 0x15, 0x58, 0x62, 0xD1, 0xE6, 0x1F,\n\t0x7F, 0x39, 0x86, 0x1A, 0x39, 0x17, 0xCE, 0x53, 0x27, 0x5A, 0x43, 0x39,\n\t0xDD, 0x88, 0x03, 0xDB, 0xDA, 0x55, 0x5B, 0xB6, 0x9C, 0x20, 0xF5, 0xBD,\n\t0xEF, 0xD6, 0xB2, 0xCC, 0x98, 0xF9, 0xC1, 0xB6, 0x53, 0xCB, 0xE7, 0xDA,\n\t0x0D, 0x1C, 0x58, 0x07, 0xFB, 0x1A, 0xF1, 0x4C, 0x1E, 0x0C, 0xA6, 0x2A,\n\t0x1B, 0x73, 0xE2, 0xAC, 0xE3, 0x16, 0x2D, 0x54, 0x3E, 0x29, 0x6B, 0x8C,\n\t0xB3, 0x78, 0x9A, 0xD6, 0xCE, 0x66, 0xBB, 0x80, 0x5E, 0x48, 0x1B, 0x24,\n\t0xC1, 0x9E, 0x92, 0x9C, 0xAB, 0xB2, 0x08, 0x0F, 0xD8, 0xAD, 0xDA, 0xC5,\n\t0xB9, 0x1E, 0x4A, 0x19, 0xB4, 0xCB, 0x40, 0xB1, 0x7B, 0x10, 0x5B, 0x80,\n\t0x46, 0x06, 0x8A, 0xED, 0xFB, 0xB6, 0x6D, 0xDA, 0xF1, 0x03, 0xAA, 0xDD,\n\t0x9A, 0xC6, 0xFB, 0x26, 0xDE, 0x82, 0x4F, 0x55, 0x54, 0xF8, 0x38, 0xDF,\n\t0xC9, 0xDB, 0x8A, 0x1B, 0x81, 0x15, 0x51, 0x6F, 0x0B, 0xFC, 0xF9, 0x72,\n\t0x71, 0x82, 0xC3, 0x37, 0xC2, 0xFB, 0xDD, 0x61, 0x01, 0xBC, 0xBB, 0x85,\n\t0xAF, 0xC3, 0x36, 0x34, 0xE5, 0xA2, 0xF8, 0x9F, 0xEF, 0x1E, 0xAA, 0xE1,\n\t0xE6, 0x2A, 0xE7, 0xBA, 0x87, 0xB1, 0x8E, 0xE5, 0x4F, 0x36, 0x0D, 0xF9,\n\t0x85, 0x34, 0x9A, 0x1D, 0xDE, 0xFD, 0xC5, 0x8C, 0xB5, 0xCC, 0x7E, 0x4E,\n\t0xEE, 0x84, 0x5E, 0x03, 0x18, 0x01, 0xB5, 0x2F, 0xF1, 0xD9, 0x84, 0xBB,\n\t0x2F, 0x10, 0x85, 0xFF, 0xA6, 0x01, 0x9B, 0xF8, 0xB0, 0x22, 0x09, 0x3D,\n\t0x9D, 0x78, 0x02, 0x14, 0x52, 0xDB, 0x7D, 0xAB, 0x7C, 0x22, 0xC8, 0x16,\n\t0x3C, 0x1B, 0x2F, 0xB7, 0xC7, 0x9B, 0xE4, 0x27, 0xB2, 0xD6, 0xB5, 0x2D,\n\t0xB4, 0x3E, 0xE2, 0xE5, 0x65, 0x93, 0x78, 0x1B, 0x1D, 0xB5, 0x2F, 0xDF,\n\t0x8E, 0xAA, 0xBF, 0xD8, 0x4A, 0xF0, 0x54, 0x0A, 0x1A, 0x96, 0x37, 0xE3,\n\t0xFF, 0x3B, 0x2B, 0xD4, 0xE2, 0x81, 0x85, 0xE8, 0xD6, 0xFE, 0x90, 0xFE,\n\t0x0D, 0xB9, 0x18, 0x86, 0x40, 0x93, 0xB3, 0x8C, 0xBD, 0xCF, 0xB4, 0x5A,\n\t0x99, 0x14, 0xBD, 0x85, 0xE8, 0x22, 0x9C, 0x3E, 0x25, 0x3A, 0xE1, 0x82,\n\t0x59, 0x27, 0x16, 0x4C, 0x01, 0x7A, 0x8A, 0x04, 0xED, 0xEA, 0x19, 0xF9,\n\t0x11, 0xC9, 0x11, 0x65, 0x0C, 0x9F, 0xEA, 0xF0, 0xE2, 0x9F, 0xD1, 0x43,\n\t0xF2, 0xC0, 0x83, 0xAF, 0x46, 0x9A, 0x47, 0xD8, 0xE5, 0x35, 0xC1, 0xC7,\n\t0x74, 0x7F, 0x2A, 0xE5, 0x46, 0x80, 0x43, 0x67, 0x83, 0xE0, 0xFB, 0x54,\n\t0x44, 0x76, 0xEB, 0x55, 0xE3, 0xD7, 0xAE, 0x9F, 0x11, 0xF6, 0xB8, 0x51,\n\t0x87, 0x66, 0x2B, 0x32, 0x6D, 0x0E, 0x72, 0xC0, 0xAD, 0x63, 0x08, 0x1C,\n\t0x78, 0xFF, 0x1B, 0xD9, 0xBF, 0x0D, 0x9B, 0x05, 0xA3, 0xCA, 0x47, 0x69,\n\t0x93, 0x9B, 0x2C, 0x41, 0x25, 0x19, 0x5E, 0xC1, 0x22, 0x34, 0x04, 0x4F,\n\t0xB3, 0x6C, 0x1F, 0x40, 0x26, 0x54, 0xED, 0x4B, 0x77, 0xD6, 0x11, 0xCE,\n\t0xC3, 0x9E, 0x8B, 0x75, 0xDD, 0x73, 0xDD, 0x65, 0x38, 0xFC, 0xA8, 0x34,\n\t0x48, 0x3E, 0x5A, 0x08, 0xED, 0xA1, 0x17, 0x45, 0x30, 0x99, 0xEA, 0x99,\n\t0x4A, 0xDF, 0x3C, 0x53, 0x78, 0xE4, 0x39, 0xF7, 0xEA, 0xBF, 0x97, 0xB0,\n\t0x34, 0x70, 0x00, 0x03, 0x23, 0xC5, 0xA6, 0x6F, 0xCF, 0xB4, 0x00, 0xA2,\n\t0xFA, 0xDA, 0xEF, 0x7F, 0x80, 0xF1, 0xCD, 0x7B, 0x30, 0x7A, 0xEE, 0xB4,\n\t0x88, 0x37, 0x26, 0x33, 0xCD, 0x5B, 0x9E, 0x38, 0x42, 0x09, 0xC5, 0x64,\n\t0x87, 0x34, 0x40, 0x80, 0x3F, 0x79, 0xE9, 0xA2, 0x4A, 0x51, 0x5F, 0x5D,\n\t0x86, 0x6C, 0x9E, 0x56, 0x5B, 0x07, 0x07, 0x93, 0x3F, 0x60, 0x27, 0xA5,\n\t0xA8, 0x00, 0x0B, 0x44, 0xB7, 0x19, 0x1D, 0xE9, 0x70, 0x72, 0x7B, 0x61,\n\t0x90, 0xA6, 0xCD, 0xB1, 0xFF, 0x8B, 0x0B, 0x9A, 0x60, 0x66, 0xBE, 0xB8,\n\t0x19, 0x95, 0x40, 0x31, 0x65, 0x3B, 0x37, 0x03, 0x8A, 0x9F, 0x86, 0x27,\n\t0x38, 0xB1, 0x08, 0xDF, 0x09, 0xF8, 0xE5, 0x82, 0x4E, 0x9C, 0x93, 0x90,\n\t0xB1, 0x44, 0x7B, 0xA1, 0xB1, 0x38, 0x64, 0xC0, 0x61, 0xF9, 0x85, 0xE2,\n\t0xAC, 0x94, 0xE5, 0xA8, 0xA1, 0x4E, 0x18, 0xFC, 0xA5, 0x5F, 0xF2, 0x38,\n\t0xE3, 0x1D, 0xDD, 0x0B, 0x5B, 0x61, 0x92, 0x46, 0xB5, 0xA1, 0x46, 0x1D,\n\t0xE3, 0x89, 0xB6, 0xD4, 0x8B, 0x2E, 0x43, 0x0A, 0x68, 0xA9, 0xF4, 0x5A,\n\t0xC1, 0xEE, 0x5A, 0xDC, 0xC1, 0x93, 0x50, 0x9A, 0x11, 0x12, 0x91, 0x6C,\n\t0xD4, 0x6F, 0x19, 0x72, 0x33, 0xA7, 0x56, 0xAD, 0x5E, 0x16, 0xAC, 0xAA,\n\t0xBE, 0x33, 0x1C, 0xBC, 0x92, 0x64, 0x31, 0xA6, 0xF3, 0xE4, 0x2C, 0x55,\n\t0xA7, 0x84, 0x59, 0x9A, 0xD6, 0x22, 0xAF, 0x55, 0x5F, 0x64, 0x69, 0x3D,\n\t0xC7, 0xED, 0x70, 0x0A, 0x76, 0xE9, 0xE8, 0x10, 0xB2, 0x84, 0x6F, 0x19,\n\t0x2A, 0xC4, 0x2D, 0xA7, 0x2C, 0x5D, 0xE0, 0xA0, 0x4C, 0x6B, 0x51, 0x9F,\n\t0x5A, 0xC0, 0xF4, 0xC5, 0x63, 0x0B, 0x41, 0xA0, 0x6C, 0xCD, 0x2D, 0x99,\n\t0xD7, 0xBA, 0x7E, 0x87, 0xC5, 0x09, 0x0B, 0x6E, 0x16, 0x10, 0x31, 0x73,\n\t0x09, 0x8F, 0x8F, 0x15, 0xC1, 0x3F, 0x54, 0x6D, 0x78, 0xCF, 0xAE, 0x42,\n\t0xFC, 0x11, 0x6E, 0x2E, 0xE6, 0x44, 0xE3, 0xC6, 0x96, 0xAD, 0xC9, 0x08,\n\t0x90, 0x37, 0xF0, 0xFA, 0xF7, 0x11, 0xB8, 0x2B, 0x60, 0xAB, 0x24, 0x3D,\n\t0xC3, 0x38, 0x72, 0x5F, 0x48, 0x6C, 0x6F, 0x72, 0x1E, 0xB6, 0x3F, 0xE1,\n\t0x75, 0xF9, 0xE2, 0x53, 0x9E, 0xE3, 0x63, 0x62, 0xF7, 0x22, 0x7A, 0xB6,\n\t0xF4, 0xB8, 0x59, 0xDA, 0x3A, 0x3E, 0x8E, 0x01, 0xC6, 0xB2, 0x65, 0xBC,\n\t0xAF, 0x5B, 0x2C, 0xCE, 0x9F, 0x66, 0x70, 0xFA, 0x83, 0x1E, 0xBB, 0x5E,\n\t0x33, 0xCD, 0xDF, 0xFB, 0xEB, 0xDE, 0x58, 0x70, 0xEB, 0x2A, 0x09, 0x50,\n\t0xC3, 0xF1, 0x8E, 0x6A, 0xAA, 0x31, 0x17, 0x37, 0x92, 0x01, 0xA2, 0x58,\n\t0x68, 0xF4, 0xF4, 0x48, 0xE1, 0xFA, 0xC7, 0xD6, 0x73, 0xEC, 0x8E, 0x24,\n\t0x69, 0xF6, 0x34, 0x49, 0x2A, 0x25, 0x28, 0xE2, 0x1D, 0x03, 0x10, 0xC2,\n\t0xF2, 0xB1, 0x67, 0x0A, 0xE1, 0x07, 0xF0, 0xAC, 0x0A, 0x65, 0x71, 0x1D,\n\t0x2F, 0x40, 0x3E, 0x96, 0x47, 0xF0, 0x8F, 0x17, 0x28, 0x6B, 0xB0, 0x8F,\n\t0xF2, 0xE8, 0xD0, 0x54, 0x7E, 0x38, 0x26, 0xF3, 0xD8, 0x30, 0xCD, 0xC0,\n\t0x47, 0x66, 0x45, 0x1C, 0x3F, 0xC0, 0xCD, 0xCC, 0x94, 0x9C, 0xE7, 0x55,\n\t0x1D, 0x6F, 0x80, 0xEE, 0x23, 0x69, 0xE2, 0xCC, 0xDB, 0x27, 0x76, 0x80,\n\t0x52, 0xAD, 0x27, 0xF6, 0xB3, 0xFB, 0x43, 0x26, 0x1D, 0x1F, 0x68, 0xBB,\n\t0x20, 0x4D, 0x02, 0x4C, 0xF9, 0xFE, 0x7C, 0xE5, 0xDD, 0xC7, 0xF9, 0x5B,\n\t0xB6, 0x3D, 0xF2, 0xB6, 0x2F, 0xBF, 0xE1, 0xFB, 0x58, 0xEF, 0x6E, 0x82,\n\t0x95, 0xA7, 0x03, 0x47, 0xD1, 0x72, 0x2D, 0xDE, 0x2E, 0x4C, 0xC0, 0x3D,\n\t0x4B, 0xEE, 0xF5, 0xAB, 0x7A, 0x5E, 0xCD, 0xEC, 0x19, 0x46, 0xCF, 0x72,\n\t0xD9, 0x47, 0x3A, 0x28, 0x2A, 0xEA, 0x1F, 0x84, 0x36, 0x00, 0x95, 0xF0,\n\t0x22, 0xD7, 0x11, 0x31, 0x9C, 0xDE, 0xDB, 0x5E, 0x6C, 0x98, 0x53, 0x1F,\n\t0xC5, 0x14, 0x03, 0x59, 0xFE, 0xD0, 0x91, 0x42, 0xA3, 0x45, 0xBB, 0x37,\n\t0xFB, 0x55, 0xC3, 0x97, 0x84, 0x5F, 0x4E, 0x42, 0x17, 0x3B, 0x51, 0xCF,\n\t0xAD, 0x41, 0xC6, 0x57, 0x25, 0xFC, 0xB7, 0xF2, 0xA6, 0xEE, 0x23, 0xB7,\n\t0x73, 0x77, 0x44, 0x5B, 0xFC, 0xDD, 0x41, 0x71, 0x7C, 0x3E, 0xDB, 0x73,\n\t0x71, 0x21, 0x89, 0x62, 0x11, 0x49, 0xCD, 0xFC, 0x34, 0x82, 0x5C, 0x1D,\n\t0xD4, 0xAD, 0x20, 0xBF, 0x5E, 0xE2, 0xA8, 0xB2, 0x96, 0xB2, 0xAB, 0xC3,\n\t0x5A, 0x7F, 0xBB, 0x86, 0x22, 0xD2, 0xF9, 0x69, 0xA2, 0x95, 0x14, 0x64,\n\t0x86, 0x87, 0x37, 0x1F, 0x81, 0x64, 0xC2, 0x95, 0x87, 0x43, 0x5C, 0xE0,\n\t0xDD, 0x7B, 0x9E, 0xE4, 0xCE, 0x73, 0xF5, 0xF0, 0x5A, 0xF5, 0x7E, 0xC3,\n\t0x66, 0x27, 0x40, 0xF5, 0xCC, 0xDB, 0xD3, 0x43, 0x69, 0x49, 0x6D, 0x30,\n\t0xF6, 0xAD, 0xB8, 0x5F, 0xA8, 0xDB, 0x34, 0x47, 0x0A, 0x86, 0x4D, 0x05,\n\t0x4C, 0x11, 0x80, 0x51, 0x96, 0x5B, 0xF9, 0x9E, 0x9B, 0x40, 0x49, 0x2D,\n\t0xE1, 0x83, 0x9C, 0xD3, 0xCA, 0xE3, 0x7E, 0x1F, 0x58, 0x52, 0x34, 0x10,\n\t0xF5, 0x00, 0x08, 0xF0, 0xF8, 0xF5, 0x53, 0x71, 0xFA, 0x67, 0xC3, 0xB1,\n\t0xFF, 0x91, 0xFC, 0xE8, 0x52, 0x31, 0xA9, 0x09, 0x76, 0xF8, 0x62, 0x8E,\n\t0x61, 0x94, 0x3C, 0x21, 0x4C, 0xD0, 0xB5, 0x84, 0xE9, 0x25, 0x6C, 0xD3,\n\t0x57, 0x2D, 0xD0, 0x66, 0xC0, 0x76, 0x45, 0x78, 0x25, 0xDA, 0xC6, 0xAD,\n\t0x02, 0x6F, 0xD5, 0x65, 0x7A, 0x27, 0x47, 0x6B, 0xB6, 0x9C, 0xF6, 0x64,\n\t0x61, 0x89, 0x95, 0x58, 0xBD, 0x13, 0x7C, 0xD8, 0x6A, 0xB0, 0x17, 0x91,\n\t0xD7, 0x08, 0x8C, 0x69, 0x44, 0x40, 0x29, 0xDF, 0x51, 0x9D, 0x1D, 0x59,\n\t0xF0, 0x28, 0x74, 0x58, 0x7A, 0x97, 0xE2, 0x88, 0x04, 0x87, 0x18, 0xA7,\n\t0x1C, 0xEB, 0xB3, 0x72, 0x3A, 0x3A, 0x4F, 0x8F, 0x66, 0x53, 0xFB, 0xCA,\n\t0xC8, 0x5D, 0x7F, 0x98, 0x98, 0x6F, 0x36, 0x0A, 0x6D, 0x3D, 0x49, 0xA0,\n\t0xD2, 0x47, 0x81, 0x84, 0x3C, 0x24, 0x7E, 0xC8, 0xD8, 0x87, 0x62, 0xA0,\n\t0x3F, 0x34, 0xA7, 0x95, 0xAD, 0x18, 0x7C, 0x05, 0xAF, 0xD2, 0x6C, 0x11,\n\t0x0F, 0x4F, 0x54, 0xD4, 0xC8, 0x6E, 0x11, 0xA9, 0x19, 0x9F, 0x20, 0xB8,\n\t0xED, 0xB6, 0x11, 0xFF, 0x67, 0xF5, 0xF6, 0x93, 0x2D, 0xED, 0x9C, 0xEC,\n\t0x6D, 0xAF, 0xEF, 0xBC, 0xC2, 0x3F, 0xDF, 0xB1, 0xBB, 0x34, 0xB3, 0xF5,\n\t0xC1, 0x2A, 0xBC, 0x8F, 0x74, 0xC1, 0x57, 0xD5, 0xA3, 0xB8, 0x6C, 0x1F,\n\t0x7E, 0x9F, 0x69, 0x15, 0xF0, 0x6B, 0x76, 0xEE, 0x5E, 0xCE, 0x4D, 0x63,\n\t0x19, 0xC8, 0xD3, 0x03, 0x76, 0x62, 0x72, 0xCF, 0xF7, 0x44, 0xF4, 0x0D,\n\t0x1B, 0x39, 0x25, 0x02, 0x9D, 0x0A, 0x98, 0xD6, 0x84, 0x44, 0x15, 0x18,\n\t0x1D, 0x27, 0x37, 0x99, 0x97, 0xE3, 0x89, 0xD8, 0x57, 0x1D, 0xF8, 0xC9,\n\t0x1C, 0xD5, 0x48, 0x2C, 0x73, 0xD9, 0x6E, 0x33, 0xDD, 0xAB, 0x6A, 0x97,\n\t0x53, 0x2E, 0xDF, 0x5D, 0xEE, 0xF4, 0x55, 0x34, 0x88, 0x17, 0x41, 0x2C,\n\t0x85, 0xE3, 0xFE, 0x02, 0xFE, 0xD1, 0xF6, 0xBF, 0x63, 0xA1, 0xEE, 0xAF,\n\t0xF9, 0x7E, 0xDE, 0xD4, 0x75, 0xA1, 0x23, 0x23, 0x76, 0x78, 0x71, 0x02,\n\t0xBD, 0x43, 0xA3, 0xC2, 0x10, 0x84, 0xFE, 0x1A, 0x7D, 0x98, 0x10, 0x8D,\n\t0x30, 0x69, 0x50, 0x68, 0x9B, 0x8E, 0x8A, 0x75, 0x18, 0x6D, 0x35, 0x9E,\n\t0xF0, 0xB9, 0x10, 0xF1, 0x42, 0x24, 0x4A, 0x9A, 0xA8, 0xC0, 0x91, 0xE5,\n\t0xC6, 0x7F, 0xE0, 0x13, 0x6E, 0x81, 0xBD, 0xA5, 0x9B, 0x3D, 0xA5, 0xEE,\n\t0x88, 0x60, 0x32, 0x2E, 0xF5, 0xA2, 0x06, 0x3E, 0x62, 0xCC, 0x0A, 0x48,\n\t0xB4, 0x70, 0xE8, 0xC5, 0xA6, 0xF5, 0x7E, 0x99, 0x74, 0xDB, 0x6E, 0xFD,\n\t0x88, 0x8C, 0x03, 0x5D, 0x19, 0x28, 0xB8, 0xCF, 0x0A, 0xA4, 0xEE, 0xCD,\n\t0x02, 0xD5, 0x62, 0xCE, 0x0C, 0x7B, 0xE5, 0x8B, 0xD8, 0x43, 0xEE, 0xF6,\n\t0x00, 0xDB, 0xFF, 0x2A, 0xB9, 0x8E, 0x5D, 0x71, 0x58, 0x70, 0xAA, 0x13,\n\t0x84, 0xC7, 0xC8, 0x76, 0x22, 0xD0, 0x3B, 0xD7, 0xB8, 0x90, 0xAD, 0xC0,\n\t0x2D, 0xC1, 0xDD, 0x6F, 0x90, 0xAC, 0xB0, 0x77, 0xD6, 0xA9, 0xAC, 0x06,\n\t0x92, 0x5E, 0x7B, 0x2E, 0x1D, 0x96, 0x74, 0xD9, 0x20, 0x96, 0xD6, 0x2F,\n\t0xFD, 0xCD, 0x3F, 0xE2, 0x3A, 0xCD, 0xD6, 0x1C, 0x17, 0x61, 0xCE, 0xC3,\n\t0xF2, 0xBC, 0xAB, 0xA8, 0xE7, 0xE9, 0xC2, 0xD5, 0x4F, 0x9D, 0x3E, 0xD3,\n\t0x08, 0xC4, 0xDD, 0x45, 0x61, 0xEB, 0xB8, 0xDE, 0x07, 0xD5, 0x7D, 0x25,\n\t0xAF, 0x2C, 0x7C, 0x82, 0x9D, 0xD8, 0x33, 0x52, 0xD8, 0x51, 0x7F, 0x7E,\n\t0x2C, 0xDF, 0xDD, 0xCE, 0x59, 0x30, 0x9C, 0x7C, 0x52, 0x39, 0xCD, 0x19,\n\t0x2A, 0x31, 0x5C, 0xDA, 0x35, 0xC8, 0x05, 0x2A, 0x28, 0xCD, 0x1E, 0x86,\n\t0xCC, 0xD8, 0x65, 0x04, 0x65, 0xFE, 0x76, 0x4F, 0xA8, 0x31, 0xBB, 0x65,\n\t0x1C, 0xD0, 0xB7, 0x00, 0x99, 0xFC, 0x1B, 0x62, 0xC6, 0xE9, 0x3C, 0xAE,\n\t0xC4, 0xBA, 0x84, 0x22, 0xC9, 0x0D, 0x06, 0x10, 0xE6, 0x02, 0x3C, 0x51,\n\t0x55, 0x75, 0xB3, 0x0F, 0x45, 0x9E, 0x4A, 0xCB, 0xA5, 0x8C, 0x1A, 0x7D,\n\t0x78, 0x58, 0x5C, 0x33, 0x17, 0x38, 0x1D, 0xA3, 0x33, 0x58, 0x31, 0x55,\n\t0xE6, 0x08, 0xB0, 0x89, 0xF8, 0xAD, 0xF6, 0x11, 0x79, 0xC3, 0xB7, 0x2E,\n\t0x15, 0x78, 0xFE, 0x93, 0x45, 0x5F, 0xDC, 0x15, 0xFC, 0xF7, 0x2B, 0xA4,\n\t0x43, 0xB4, 0x62, 0xDF, 0xC4, 0xDE, 0xB5, 0xFA, 0xA1, 0x99, 0xD6, 0x82,\n\t0xE1, 0xE8, 0x71, 0xB9, 0xCF, 0x6B, 0x22, 0xAA, 0x22, 0xA0, 0x7E, 0x62,\n\t0x4B, 0x8E, 0x4A, 0x3D, 0x37, 0x86, 0xA2, 0x65, 0xB2, 0x73, 0x49, 0x22,\n\t0xBC, 0x27, 0xAD, 0x0D, 0xC5, 0x69, 0xC3, 0x3C, 0x00, 0xAF, 0x8E, 0x44,\n\t0xE4, 0xCA, 0x8B, 0xB2, 0x33, 0x7D, 0x33, 0xA3, 0x2D, 0xE6, 0xB2, 0x1C,\n\t0xD8, 0x8C, 0xF1, 0x6E, 0x30, 0x0E, 0x13, 0x5C, 0x60, 0xC8, 0x99, 0xBC,\n\t0x8B, 0xED, 0x61, 0xEA, 0x35, 0xF4, 0xA9, 0x59, 0xAF, 0x69, 0x9B, 0x81,\n\t0x79, 0x03, 0xC4, 0x36, 0x46, 0x3F, 0x92, 0x78, 0x99, 0x50, 0x09, 0xD4,\n\t0x90, 0xB0, 0x08, 0xAB, 0x22, 0x46, 0xB5, 0xFF, 0x14, 0xC1, 0x43, 0x00,\n\t0xAA, 0xE3, 0xBC, 0x30, 0x38, 0x39, 0x0E, 0x71, 0xAD, 0xFC, 0x01, 0x44,\n\t0x7F, 0x32, 0x0F, 0xEE, 0xB8, 0xAE, 0xB2, 0x73, 0x6F, 0xD4, 0x7E, 0xCB,\n\t0xA7, 0x04, 0x85, 0xEA, 0x36, 0xFD, 0x73, 0x60, 0xFC, 0x85, 0xE5, 0x9B,\n\t0xCE, 0x94, 0xFD, 0xF2, 0x12, 0x11, 0x2C, 0xCC, 0x4F, 0x4E, 0xA5, 0x95,\n\t0x32, 0x81, 0x76, 0xD8, 0xEC, 0x88, 0x50, 0x0F, 0x93, 0x76, 0xF0, 0x59,\n\t0x39, 0x8E, 0xB3, 0x96, 0x3F, 0x50, 0x13, 0x36, 0xD8, 0xB9, 0xD8, 0xBA,\n\t0x17, 0x59, 0xD1, 0xCF, 0x66, 0x83, 0x23, 0x38, 0xE7, 0xEB, 0x61, 0xAC,\n\t0x13, 0x3E, 0xD6, 0xB4, 0xAA, 0x5C, 0xD0, 0xB2, 0xEC, 0xCB, 0xE3, 0x6D,\n\t0x42, 0xEA, 0xD1, 0xE7, 0xBE, 0x8A, 0x59, 0x6E, 0x34, 0x7E, 0x44, 0x00,\n\t0x99, 0x47, 0xA2, 0x45, 0x4D, 0xBA, 0x5F, 0x99, 0x13, 0x31, 0x4D, 0x11,\n\t0x8D, 0x01, 0xBA, 0x6B, 0x88, 0x7C, 0xEE, 0x87, 0xF2, 0xE7, 0x0F, 0x73,\n\t0xEB, 0x57, 0x4B, 0x77, 0x40, 0x52, 0xD3, 0xAC, 0x81, 0x1A, 0x3B, 0xFD,\n\t0xA4, 0x2C, 0x83, 0x11, 0x2A, 0xF7, 0x53, 0xDF, 0x28, 0x15, 0xE2, 0xCA,\n\t0xAC, 0x2B, 0xAC, 0xDA, 0x68, 0xE0, 0x19, 0x42, 0x8E, 0xC8, 0x78, 0xD4,\n\t0x11, 0x8B, 0xEF, 0xF6, 0xDC, 0x26, 0xEA, 0x67, 0x93, 0xEC, 0xC7, 0xEA,\n\t0xEF, 0x8D, 0xF7, 0xE1, 0xA8, 0x94, 0xD3, 0x35, 0xF1, 0x14, 0x38, 0x8A,\n\t0x63, 0xD1, 0x42, 0xD1, 0x7B, 0x26, 0xBF, 0x3C, 0xB2, 0x8A, 0x6E, 0xBC,\n\t0xA2, 0x73, 0x63, 0x6A, 0x95, 0x2A, 0x9B, 0x5F, 0xC3, 0x85, 0x38, 0x29,\n\t0xDD, 0xF5, 0x68, 0x43, 0xBE, 0xC2, 0x6A, 0x56, 0x28, 0xC8, 0x20, 0xCA,\n\t0x84, 0x0E, 0x23, 0xE4, 0x3D, 0x5F, 0x80, 0xBE, 0xE4, 0xDA, 0x0E, 0xBC,\n\t0x76, 0x84, 0x48, 0x15, 0x05, 0xA3, 0x56, 0x8C, 0xAE, 0x5E, 0x41, 0xE7,\n\t0x57, 0x6D, 0xF8, 0xD1, 0x1C, 0x9A, 0xC7, 0x41, 0x1D, 0xE2, 0xA9, 0x03,\n\t0x45, 0xDA, 0x88, 0x69, 0x99, 0x1B, 0x45, 0xF8, 0x28, 0x72, 0xCC, 0xD8,\n\t0xCE, 0x79, 0x10, 0xA7, 0x33, 0xF1, 0xC9, 0xD5, 0x01, 0x5A, 0x7A, 0x4F,\n\t0xE7, 0xDC, 0x71, 0x47, 0x1C, 0xB3, 0x86, 0x62, 0x08, 0xA2, 0x6D, 0x19,\n\t0xD7, 0xD3, 0x14, 0xEF, 0x84, 0x86, 0x9C, 0xAC, 0xAE, 0x03, 0x9A, 0xA5,\n\t0xD1, 0x91, 0x8E, 0x02, 0x4A, 0x70, 0x94, 0x51, 0x92, 0xD9, 0xAF, 0x7A,\n\t0x32, 0x91, 0xD2, 0x1F, 0x0B, 0x16, 0xA0, 0x52, 0xF8, 0x3B, 0x98, 0xD2,\n\t0xC2, 0x4B, 0xC0, 0xC2, 0x6B, 0x2E, 0xDE, 0xD6, 0x98, 0xC0, 0x1F, 0x6E,\n\t0x13, 0x56, 0xCC, 0x37, 0x8B, 0x31, 0x26, 0x5E, 0xC8, 0x53, 0xC6, 0xD2,\n\t0x1F, 0xAB, 0x79, 0x40, 0xE8, 0xFD, 0x25, 0xE1, 0x7F, 0x9E, 0xE4, 0xC0,\n\t0x3F, 0xCF, 0xBF, 0x74, 0x7A, 0x80, 0x9D, 0x1F, 0x86, 0xD3, 0xEA, 0x9D,\n\t0xB9, 0x88, 0x0F, 0x34, 0x82, 0x28, 0xD4, 0xB1, 0xF2, 0x86, 0xE4, 0x8D,\n\t0xF0, 0xFE, 0xBD, 0xEF, 0x86, 0xD3, 0xE0, 0xB9, 0x60, 0xBE, 0xC4, 0x77,\n\t0x70, 0x04, 0x7B, 0xD4, 0xCB, 0xA6, 0x25, 0x5E, 0xF4, 0x50, 0x35, 0x27,\n\t0xF7, 0x57, 0xAA, 0xEA, 0x29, 0x04, 0x1E, 0xC1, 0xB1, 0xE4, 0xC3, 0x8C,\n\t0x85, 0xF8, 0x69, 0xEF, 0xC0, 0x04, 0x18, 0x32, 0x66, 0xDD, 0x9B, 0x60,\n\t0x8F, 0x9F, 0x2D, 0xC1, 0x00, 0xDD, 0x84, 0x39, 0x38, 0x51, 0xA4, 0xCC,\n\t0xC2, 0x0E, 0x3C, 0xC3, 0x7B, 0x70, 0xBF, 0xC1, 0x73, 0x2E, 0x3C, 0x98,\n\t0x15, 0x63, 0x20, 0x33, 0x61, 0x9C, 0x39, 0x85, 0x1D, 0x26, 0xFD, 0x45,\n\t0xC0, 0x16, 0x55, 0x29, 0x63, 0xA7, 0x07, 0x48, 0x5C, 0x0B, 0x54, 0xE7,\n\t0xBD, 0xF0, 0x1A, 0x53, 0x13, 0xA7, 0xDD, 0x08, 0xF1, 0x02, 0x1E, 0x19,\n\t0x4E, 0x3E, 0xE3, 0xF8, 0x10, 0x1F, 0x71, 0x4D, 0xB8, 0x80, 0x55, 0x09,\n\t0x7B, 0x20, 0xF3, 0x31, 0xD1, 0x66, 0x90, 0xFF, 0x72, 0x41, 0x04, 0xAA,\n\t0xEB, 0x72, 0xA7, 0x8F, 0x79, 0x4B, 0xFF, 0x9B, 0xF8, 0x61, 0x2A, 0x96,\n\t0xB4, 0xB1, 0x3D, 0x08, 0x52, 0x6F, 0x1F, 0xB3, 0xD8, 0x9E, 0xEC, 0x39,\n\t0xCF, 0x7A, 0xF9, 0x09, 0x02, 0xBF, 0xCA, 0x8B, 0x5C, 0xD0, 0xBB, 0xA7,\n\t0x64, 0xE3, 0x0D, 0x95, 0xE8, 0x74, 0xE4, 0xD5, 0xDD, 0x37, 0xC0, 0xCB,\n\t0xDD, 0x67, 0xD7, 0xEF, 0x41, 0x51, 0x26, 0x77, 0x60, 0x93, 0xB2, 0xE7,\n\t0x9E, 0x76, 0x0C, 0xDA, 0x75, 0x4D, 0x31, 0x5F, 0x64, 0xD4, 0xA7, 0x9A,\n\t0x0A, 0x36, 0x29, 0x0F, 0x66, 0xC2, 0x3E, 0x9D, 0x38, 0xFE, 0x36, 0xC3,\n\t0x46, 0x1D, 0xB0, 0x2B, 0xE4, 0x49, 0x17, 0xC6, 0x10, 0x19, 0x03, 0xEF,\n\t0x54, 0x72, 0xFD, 0x0A, 0x98, 0x88, 0x56, 0xE6, 0x5D, 0xC1, 0xB1, 0x99,\n\t0x76, 0xE4, 0xDE, 0x95, 0x6E, 0x22, 0xB1, 0xA6, 0xAB, 0xD0, 0x17, 0xA3,\n\t0x50, 0x39, 0x0F, 0x2F, 0x24, 0xBD, 0x0F, 0x88, 0xCE, 0xE0, 0x60, 0x09,\n\t0x62, 0xF2, 0x4F, 0x5B, 0x2E, 0x98, 0x15, 0x29, 0x7C, 0xE7, 0xAF, 0x38,\n\t0x71, 0xAC, 0xE2, 0xA4, 0x37, 0x17, 0x91, 0xF1, 0xEB, 0x90, 0xA7, 0xAE,\n\t0x6A, 0xA8, 0x27, 0x49, 0xB8, 0x30, 0x29, 0x56, 0x6F, 0x44, 0x4A, 0x92,\n\t0xE4, 0x85, 0xFA, 0x88, 0xFE, 0xAD, 0x0A, 0xC1, 0x2C, 0x04, 0x56, 0xD9,\n\t0x82, 0xC2, 0x78, 0x55, 0xDB, 0x62, 0xB3, 0xCE, 0xDA, 0xCE, 0x12, 0xB2,\n\t0xBD, 0x5A, 0xA0, 0x5F, 0xFE, 0x10, 0xA1, 0x06, 0x43, 0xB2, 0xF3, 0x1C,\n\t0x86, 0x75, 0xFF, 0xE8, 0x72, 0xFB, 0xCC, 0xEB, 0x89, 0xBE, 0x77, 0x0D,\n\t0xBE, 0x98, 0x04, 0x16, 0x36, 0x59, 0x22, 0x7E, 0x83, 0x94, 0xE3, 0xE8,\n\t0x32, 0x9D, 0x94, 0x1B, 0x3D, 0x62, 0x57, 0x41, 0x3F, 0x1C, 0x4F, 0x89,\n\t0xE9, 0x4D, 0x2F, 0x17, 0xC1, 0x2B, 0xA1, 0x62, 0xE3, 0x95, 0xEA, 0x5A,\n\t0x9D, 0x1C, 0xD7, 0x10, 0xE6, 0x26, 0xDF, 0xD5, 0x75, 0xB4, 0xF9, 0x21,\n\t0xFA, 0x44, 0x6B, 0x51, 0xD5, 0x53, 0x3F, 0x0C, 0x7F, 0xE1, 0x3F, 0xEB,\n\t0x5E, 0x52, 0x29, 0xD9, 0x6D, 0xF9, 0xC2, 0xD4, 0xDC, 0x0B, 0x22, 0xD3,\n\t0x28, 0xBC, 0xDD, 0xD4, 0x71, 0x1C, 0xB5, 0xFF, 0xC4, 0xEE, 0xBD, 0x1A,\n\t0x9F, 0xF9, 0x4D, 0x4D, 0x57, 0x07, 0xF8, 0xFD, 0x21, 0x32, 0x08, 0xE7,\n\t0xB2, 0x75, 0x1C, 0xEC, 0x1C, 0x63, 0x32, 0x4C, 0x7C, 0x75, 0xB0, 0x27,\n\t0xD5, 0xCB, 0x6C, 0xF3, 0x88, 0x21, 0x61, 0x77, 0xDC, 0x8A, 0x26, 0xD6,\n\t0x32, 0xF3, 0xAB, 0x69, 0xFB, 0xB6, 0x8C, 0xC2, 0x61, 0x8D, 0xC2, 0x78,\n\t0x91, 0xD3, 0x15, 0x16, 0x48, 0xFA, 0xF6, 0x4F, 0xBE, 0x81, 0xB8, 0x3D,\n\t0x52, 0xD8, 0xEE, 0x92, 0x42, 0xE1, 0xEC, 0xA8, 0x79, 0x96, 0x2F, 0x7F,\n\t0xFD, 0xC5, 0x2E, 0xC5, 0xBA, 0xC1, 0xD1, 0x0B, 0x39, 0x28, 0xBC, 0x5F,\n\t0x05, 0xE3, 0x73, 0xDF, 0x3D, 0xDF, 0x5B, 0xDB, 0x85, 0x8E, 0x4B, 0x52,\n\t0x98, 0x76, 0x68, 0xE9, 0xBE, 0xFE, 0x14, 0x28, 0x00, 0x67, 0x6E, 0xB2,\n\t0x7D, 0x67, 0xCB, 0xF6, 0xFF, 0xFF, 0xAB, 0x42, 0x83, 0x35, 0x61, 0x65,\n\t0x64, 0x79, 0x15, 0x93, 0xE1, 0x97, 0xF8, 0x3F, 0xC8, 0xAB, 0x1D, 0x7F,\n\t0xBF, 0xD0, 0x22, 0x8A, 0x94, 0x6E, 0xF3, 0xCF, 0x74, 0x93, 0xEE, 0xA1,\n\t0xFB, 0xDC, 0xAE, 0x9F, 0x6F, 0x84, 0x10, 0x42, 0xD6, 0xE7, 0x78, 0xC5,\n\t0x02, 0x68, 0xC9, 0x17, 0x66, 0x50, 0xD3, 0xE9, 0x2E, 0x98, 0x77, 0x20,\n\t0x50, 0x24, 0x4A, 0x71, 0x91, 0x2E, 0x11, 0x6E, 0x98, 0x7A, 0xB3, 0x55,\n\t0x7B, 0xF5, 0x5D, 0x81, 0x45, 0xEC, 0x79, 0x90, 0x54, 0x7C, 0x12, 0x41,\n\t0x23, 0xEF, 0xB8, 0x07, 0x6F, 0x0D, 0x40, 0x01, 0x7D, 0x45, 0x76, 0x80,\n\t0x50, 0x34, 0x16, 0x47, 0x50, 0x4C, 0xD1, 0x35, 0xC4, 0x86, 0x36, 0x2E,\n\t0xAC, 0xA0, 0xEF, 0x5E, 0x67, 0xD7, 0x91, 0xCE, 0x56, 0xA0, 0xE5, 0x53,\n\t0xBB, 0x5A, 0x8C, 0x63, 0x15, 0x06, 0xE0, 0x01, 0xA9, 0x1C, 0xDF, 0xAC,\n\t0x7A, 0xE7, 0x8D, 0x3B, 0x87, 0xE5, 0x1B, 0x47, 0x4C, 0x69, 0x96, 0xB1,\n\t0x52, 0xE8, 0xAE, 0x21, 0x45, 0x6E, 0x60, 0x67, 0x82, 0x41, 0x0F, 0x8C,\n\t0x5D, 0x77, 0xDB, 0x8B, 0xF4, 0x95, 0x16, 0xD1, 0x62, 0x12, 0xB6, 0x8D,\n\t0x7D, 0xF3, 0x05, 0xCF, 0xA1, 0xA4, 0xE0, 0xCA, 0x75, 0x11, 0x01, 0xA1,\n\t0x6F, 0x60, 0x31, 0xD6, 0x94, 0x54, 0xE3, 0x1B, 0xE6, 0x1C, 0xD6, 0x05,\n\t0xA6, 0xBF, 0x1F, 0xF1, 0xEC, 0x6B, 0x9F, 0x28, 0x89, 0x7B, 0x92, 0x59,\n\t0xD2, 0xF7, 0x69, 0x7C, 0xCE, 0xA3, 0x9B, 0x78, 0xDE, 0x15, 0x21, 0x1F,\n\t0x77, 0x0E, 0xF9, 0x33, 0x96, 0x44, 0x76, 0x90, 0x3E, 0x3E, 0xBF, 0x0C,\n\t0xBC, 0x01, 0x0D, 0x61, 0x0C, 0x8F, 0x55, 0xA4, 0xC4, 0x0E, 0xC2, 0xF7,\n\t0x23, 0x1A, 0x85, 0x33, 0x53, 0xAA, 0x54, 0x1D, 0xEC, 0xFA, 0x0F, 0xD4,\n\t0x89, 0x87, 0x15, 0xB5, 0x74, 0xB8, 0xA0, 0x74, 0x1D, 0xA0, 0x29, 0xE3,\n\t0x16, 0x0B, 0x6C, 0x3F, 0x2D, 0xA6, 0xFD, 0x90, 0x63, 0x27, 0x7E, 0x0C,\n\t0xC0, 0x2E, 0x84, 0x81, 0x9C, 0xBC, 0x06, 0x06, 0xA2, 0x11, 0x49, 0x3B,\n\t0xC5, 0x13, 0xF7, 0x33, 0x24, 0x54, 0x89, 0x1E, 0x16, 0x01, 0x0B, 0x30,\n\t0xBD, 0xBD, 0x9B, 0x7D, 0xB1, 0x1B, 0xFA, 0x3F, 0x59, 0x94, 0xA6, 0xF9,\n\t0x27, 0x84, 0x30, 0x4E, 0x3A, 0x72, 0x61, 0x73, 0x56, 0x1E, 0xFE, 0xA9,\n\t0x32, 0x7E, 0x34, 0xDF, 0xF2, 0xCF, 0x9F, 0x32, 0x59, 0x87, 0xC8, 0x93,\n\t0x7C, 0x3F, 0x26, 0x6B, 0x34, 0xE0, 0xB3, 0xC3, 0xEE, 0x38, 0xF3, 0x50,\n\t0x30, 0xB4, 0xC1, 0x60, 0x48, 0xA6, 0x37, 0xD3, 0xE1, 0x77, 0xB6, 0x54,\n\t0x79, 0x8F, 0x2A, 0xBF, 0xDA, 0x43, 0xC6, 0xCE, 0x03, 0xFE, 0xDE, 0x08,\n\t0x2B, 0x18, 0x6C, 0x94, 0x6E, 0x0E, 0x7D, 0xDD, 0xFD, 0xB2, 0xD8, 0x85,\n\t0xAD, 0x75, 0xC9, 0x2C, 0x6E, 0x40, 0xAA, 0xC1, 0x28, 0x9D, 0x52, 0x21,\n\t0xEA, 0x19, 0xB8, 0x56, 0x2E, 0x0B, 0xE9, 0x4A, 0xF8, 0xFD, 0x28, 0xD3,\n\t0xDF, 0xA7, 0x1E, 0x77, 0xB1, 0x76, 0x29, 0x9A, 0xA9, 0x7C, 0xD6, 0x99,\n\t0xF9, 0xCE, 0x7A, 0x38, 0x96, 0xFF, 0x90, 0xF4, 0xAE, 0x04, 0x59, 0x9D,\n\t0x57, 0x49, 0x63, 0x71, 0x7A, 0xA8, 0x3A, 0x68, 0xF5, 0x8D, 0xAC, 0x19,\n\t0x36, 0xD8, 0x12, 0xE6, 0x6A, 0x58, 0x96, 0x0F, 0xC1, 0x4C, 0xF0, 0x6B,\n\t0xBE, 0xF2, 0x92, 0xFA, 0x1A, 0xC5, 0x43, 0x72, 0x3E, 0x9A, 0x09, 0x0D,\n\t0x16, 0xAA, 0xDF, 0x43, 0x42, 0x95, 0x1F, 0x14, 0x25, 0xFA, 0x05, 0x45,\n\t0x41, 0xE1, 0x7C, 0x00, 0xDC, 0x9D, 0x34, 0x51, 0x27, 0x27, 0xBE, 0x7A,\n\t0xE2, 0x63, 0x2E, 0xAC, 0x4A, 0xDA, 0x0E, 0x80, 0x34, 0x9A, 0x43, 0x2D,\n\t0xC8, 0xCF, 0x52, 0x23, 0x10, 0xCC, 0x3D, 0x30, 0x76, 0x85, 0xA7, 0x36,\n\t0xE7, 0x22, 0x5C, 0xC1, 0x00, 0x31, 0x31, 0x30, 0x61, 0xB9, 0xA7, 0xE9,\n\t0xCB, 0x19, 0x0F, 0x68, 0x86, 0x1E, 0x9E, 0xAE, 0xB6, 0x63, 0xF2, 0x7E,\n\t0x50, 0xAC, 0x4B, 0x96, 0x07, 0x2A, 0x5A, 0x9F, 0xE7, 0x10, 0x2F, 0x1F,\n\t0xE0, 0xEA, 0xE4, 0xB0, 0x03, 0x31, 0xEB, 0xF4, 0x40, 0x16, 0x97, 0x4E,\n\t0x40, 0x85, 0xD7, 0x1B, 0xB7, 0x50, 0xF8, 0xD4, 0x04, 0x0E, 0xFA, 0x89,\n\t0x30, 0x85, 0x61, 0x69, 0xCD, 0xC1, 0x2A, 0xAE, 0xC2, 0x9A, 0xAF, 0xA6,\n\t0x55, 0x41, 0xCD, 0x51, 0xCB, 0xFD, 0x0E, 0x3F, 0xEA, 0x93, 0x7C, 0x9A,\n\t0x1D, 0x0B, 0xEF, 0x75, 0x92, 0xB9, 0xD6, 0x6C, 0x29, 0x53, 0xDF, 0x7D,\n\t0x69, 0xDB, 0x0D, 0x97, 0xF1, 0x66, 0x74, 0x22, 0x0B, 0x34, 0x12, 0x69,\n\t0x88, 0xB2, 0x0D, 0xD4, 0xD3, 0xFB, 0xC1, 0xAA, 0x2C, 0x74, 0xB2, 0x20,\n\t0x2C, 0x42, 0x55, 0x01, 0x4D, 0x46, 0xAA, 0xEB, 0x62, 0xF1, 0x71, 0x4C,\n\t0xA7, 0xA9, 0xCE, 0x23, 0x4C, 0x63, 0xB8, 0x13, 0xF8, 0x2F, 0xE6, 0x22,\n\t0x4D, 0x2A, 0x7D, 0x45, 0xFC, 0xC5, 0x6C, 0xA7, 0x2A, 0x75, 0xBB, 0x2D,\n\t0xA0, 0x85, 0x87, 0xCA, 0x47, 0xB3, 0x15, 0xFB, 0xC4, 0x6C, 0x0E, 0x1B,\n\t0x54, 0xEF, 0x03, 0x4C, 0x43, 0xD9, 0xD9, 0x73, 0xC8, 0x10, 0x46, 0xE5,\n\t0x19, 0x38, 0x32, 0xCD, 0xB2, 0xDB, 0x8F, 0xBD, 0x08, 0xA3, 0x33, 0x01,\n\t0x41, 0x1F, 0x6A, 0x02, 0x07, 0x88, 0xAE, 0x98, 0x6C, 0x26, 0x05, 0xF0,\n\t0xA6, 0x46, 0x95, 0xE0, 0xD8, 0xB6, 0xF9, 0x56, 0xFF, 0xB7, 0xBD, 0x5D,\n\t0x77, 0xFC, 0x16, 0xF2, 0xEF, 0xDE, 0xFF, 0x15, 0x14, 0x28, 0xDB, 0x67,\n\t0x69, 0xA6, 0x7B, 0xFA, 0x17, 0xAE, 0x35, 0x1A, 0x6E, 0x4C, 0x08, 0x16,\n\t0x7E, 0x31, 0x4E, 0xF5, 0x67, 0x9F, 0x35, 0x8C, 0x7A, 0x78, 0xFC, 0x4F,\n\t0x7B, 0x1B, 0x97, 0xED, 0x08, 0x68, 0xFB, 0xE6, 0x6D, 0x7E, 0xDE, 0xBC,\n\t0x30, 0xA1, 0xD1, 0xB9, 0x46, 0xEA, 0xC2, 0x4D, 0x1B, 0x9B, 0xDA, 0x35,\n\t0x9F, 0x84, 0x47, 0x0E, 0x3E, 0x3C, 0xC2, 0x47, 0x33, 0x84, 0xEA, 0x94,\n\t0x0A, 0x0D, 0xDA, 0x1F, 0xCB, 0xF3, 0x0E, 0xDC, 0x33, 0x82, 0xDF, 0xF9,\n\t0x6A, 0x06, 0x78, 0xDE, 0xFA, 0x0F, 0xB9, 0xD8, 0xF0, 0xE8, 0x62, 0x25,\n\t0x7A, 0x40, 0x4F, 0x5F, 0xC3, 0x5E, 0x45, 0x20, 0x9D, 0x45, 0x43, 0x46,\n\t0xC8, 0x3D, 0x2B, 0x06, 0x33, 0x02, 0x7E, 0x40, 0xFF, 0x63, 0x11, 0x7D,\n\t0xE4, 0x49, 0xFB, 0xB2, 0xEB, 0x45, 0xEA, 0x3E, 0x43, 0x92, 0x67, 0xBD,\n\t0xD1, 0xF0, 0x6C, 0xE0, 0x71, 0x07, 0x87, 0xD5, 0xFF, 0x72, 0x37, 0xD9,\n\t0x6C, 0x54, 0x64, 0x92, 0x25, 0xEE, 0x13, 0x3C, 0x78, 0xBE, 0x63, 0x47,\n\t0xA1, 0xE0, 0x54, 0x9E, 0x64, 0xE7, 0x81, 0x02, 0xD7, 0x6E, 0xC5, 0xA3,\n\t0xE7, 0xA4, 0x8E, 0x3C, 0xC4, 0x80, 0xAD, 0xDC, 0xE6, 0x60, 0x25, 0x4D,\n\t0xE9, 0xFD, 0xF9, 0xC2, 0x04, 0x46\n};"
  },
  {
    "path": "src/Cafe/HW/Latte/Common/RegisterSerializer.h",
    "content": "#pragma once\n#include \"util/helpers/Serializer.h\"\n\nnamespace Latte\n{\n\tstruct GPUCompactedRegisterState\n\t{\n\t\tstatic constexpr int const NUM_REGS = 1854;\n\n\t\t// tied to g_gpuRegSerializerMapping_v1\n\t\tuint32 rawArray[NUM_REGS];\n\t};\n\n\t// convert GPU register state into compacted representation. Stores almost all registers, excluding ALU consts\n\tvoid StoreGPURegisterState(const LatteContextRegister& contextRegister, GPUCompactedRegisterState& registerStateOut);\n\tvoid LoadGPURegisterState(LatteContextRegister& contextRegisterOut, const GPUCompactedRegisterState& registerState);\n\n\tvoid SerializeRegisterState(GPUCompactedRegisterState& regState, MemStreamWriter& memWriter);\n\tbool DeserializeRegisterState(GPUCompactedRegisterState& regState, MemStreamReader& memReader);\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Common/ShaderSerializer.cpp",
    "content": "#include \"Cafe/HW/Latte/Common/ShaderSerializer.h\"\n#include <boost/container/small_vector.hpp>\n#include <zstd.h>\n#include <zlib.h>\n\n// compression dictionary for Latte shader code, initialized on boot\nZSTD_CDict* s_c_shaderDict{};\nZSTD_DDict* s_d_shaderDict{};\n\nnamespace Latte\n{\n\tvoid SerializeShaderProgram(void* shaderProg, uint32 size, MemStreamWriter& memWriter)\n\t{\n\t\tmemWriter.writeBE<uint8>(1); // version\n\t\t// compress shader using zstd level 6\n\t\tboost::container::small_vector<uint8, 4096> compressedBuf;\n\t\tcompressedBuf.resize(ZSTD_compressBound(size));\n\t\tZSTD_CCtx* const cctx = ZSTD_createCCtx();\n\t\tsize_t compressedSize = ZSTD_compress_usingCDict(cctx, compressedBuf.data(), compressedBuf.size(), shaderProg, size, s_c_shaderDict);\n\t\tZSTD_freeCCtx(cctx);\n\t\tcemu_assert(!ZSTD_isError(compressedSize));\n\t\tmemWriter.writeBE<uint32>(size);\n\t\tmemWriter.writeBE<uint32>((uint32)compressedSize);\n\t\tmemWriter.writeData(compressedBuf.data(), compressedSize);\n\t}\n\n\tbool DeserializeShaderProgram(std::vector<uint8>& progData, MemStreamReader& memReader)\n\t{\n\t\tif (memReader.readBE<uint8>() != 1)\n\t\t\treturn false; // unknown version\n\t\tuint32 progSize = memReader.readBE<uint32>();\n\t\tuint32 compressedShaderSize = memReader.readBE<uint32>();\n\t\tif (memReader.hasError())\n\t\t\treturn false;\n\t\tif (progSize == 0 || progSize >= 1024 * 1024 * 128)\n\t\t\treturn false;\n\t\tif (compressedShaderSize == 0 || compressedShaderSize >= 1024 * 1024 * 128)\n\t\t\treturn false;\n\t\tprogData.resize(progSize);\n\t\tauto compressedShaderData = memReader.readDataNoCopy(compressedShaderSize);\n\t\tif (memReader.hasError())\n\t\t\treturn false;\n\t\t// decompress\n\t\tZSTD_DCtx* const dctx = ZSTD_createDCtx();\n\t\tsize_t decompressedSize = ZSTD_decompress_usingDDict(dctx, progData.data(), progData.size(), compressedShaderData.data(), compressedShaderData.size(), s_d_shaderDict);\n\t\tZSTD_freeDCtx(dctx);\n\t\tif (decompressedSize != progSize)\n\t\t\treturn false;\n\t\treturn true;\n\t}\n};\n\nextern const uint8 s_shaderDict[];\n\nRunAtCemuBoot _loadShaderCompressionDictionary([]()\n{\n\t// decompress and load dict\n\tstatic std::vector<uint8> s_shaderDictData;\n\ts_shaderDictData.resize(0x1B800);\n\tZSTD_decompress(s_shaderDictData.data(), s_shaderDictData.size(), s_shaderDict, 0xA985);\n\ts_c_shaderDict = ZSTD_createCDict(s_shaderDictData.data(), s_shaderDictData.size(), 6);\n\ts_d_shaderDict = ZSTD_createDDict(s_shaderDictData.data(), s_shaderDictData.size());\n\tcemu_assert_debug(s_c_shaderDict);\n\tcemu_assert_debug(s_d_shaderDict);\n});\n\nconst uint8 s_shaderDict[0xA985] = // 0xA985 Uncompressed: 0x1B800\n{\n\t0x28, 0xB5, 0x2F, 0xFD, 0xA4, 0x00, 0xB8, 0x01, 0x00, 0x54, 0xD4, 0x02,\n\t0x9A, 0xE6, 0xF3, 0xBF, 0x54, 0x20, 0x9C, 0x11, 0x6D, 0x3A, 0x8F, 0x30,\n\t0xAF, 0xC4, 0x16, 0xAE, 0x9D, 0x11, 0xC3, 0x09, 0x13, 0xCD, 0xE1, 0x18,\n\t0xAB, 0xC1, 0x05, 0xD6, 0x62, 0x83, 0x83, 0xE3, 0x80, 0x9F, 0x58, 0x48,\n\t0x33, 0xD7, 0x72, 0xE6, 0x42, 0x40, 0x91, 0x79, 0x32, 0xFE, 0x24, 0xD4,\n\t0xDA, 0x80, 0x21, 0xFE, 0x5C, 0x06, 0xA3, 0x44, 0x05, 0x2A, 0x0C, 0x87,\n\t0x01, 0x8D, 0x01, 0xD0, 0x98, 0xD0, 0x33, 0x17, 0xC6, 0xCD, 0x33, 0x4C,\n\t0xC8, 0x8A, 0xBB, 0x0E, 0x18, 0x70, 0x25, 0x4C, 0x59, 0x51, 0xD4, 0xB6,\n\t0xFF, 0x7F, 0x5B, 0xDB, 0x29, 0xCB, 0x0B, 0x3A, 0x0C, 0xB1, 0x0B, 0xA7,\n\t0xCF, 0x4E, 0x5F, 0x7E, 0x07, 0x71, 0x26, 0xA6, 0x14, 0x31, 0x8F, 0xB3,\n\t0x2E, 0x78, 0x3A, 0xCD, 0xC7, 0xBF, 0x54, 0xB1, 0x4B, 0x66, 0x16, 0xA3,\n\t0x5D, 0x0B, 0x83, 0x55, 0xEE, 0x66, 0x63, 0x3C, 0x77, 0x52, 0xFA, 0x57,\n\t0xE6, 0x6A, 0x95, 0xDA, 0xBD, 0xB2, 0xB9, 0xB7, 0xD5, 0xBC, 0xB3, 0x7F,\n\t0xED, 0x6C, 0x89, 0x5C, 0xA8, 0x0F, 0xAE, 0x56, 0x49, 0xBF, 0xF3, 0x67,\n\t0x0D, 0x8F, 0x5A, 0x43, 0xA9, 0x0F, 0x20, 0xE5, 0x52, 0xAA, 0xAA, 0x82,\n\t0x83, 0x54, 0x53, 0x17, 0x73, 0x06, 0xC4, 0xF8, 0x9D, 0x96, 0x12, 0xAB,\n\t0xF7, 0xFD, 0x2E, 0x4B, 0x39, 0xA9, 0x0B, 0x0E, 0x5E, 0x22, 0x1F, 0xCC,\n\t0x8C, 0x83, 0x17, 0xF5, 0xC1, 0xA4, 0x2A, 0x22, 0x9C, 0x12, 0x43, 0xF1,\n\t0x46, 0x45, 0x77, 0xDB, 0x6E, 0xD8, 0x51, 0x94, 0xF3, 0xF6, 0xEC, 0x38,\n\t0x58, 0x34, 0xF8, 0x25, 0xAA, 0xF4, 0x98, 0x5D, 0x2E, 0x62, 0x4B, 0x50,\n\t0x80, 0x4B, 0xBF, 0xFB, 0x51, 0x23, 0xB6, 0x05, 0xE8, 0x93, 0xE9, 0x88,\n\t0xD7, 0x95, 0xFD, 0x95, 0xD1, 0xFE, 0x19, 0x75, 0xE8, 0x0F, 0x7E, 0xB4,\n\t0x53, 0x08, 0x91, 0xC9, 0xF7, 0x75, 0x8A, 0x29, 0xDE, 0xD0, 0xB3, 0x05,\n\t0xE9, 0x19, 0x9D, 0xFF, 0x25, 0x3F, 0xED, 0xD2, 0xCD, 0x2E, 0xB7, 0x46,\n\t0xCC, 0x4F, 0x04, 0xA6, 0x06, 0x36, 0xA9, 0x1C, 0xE0, 0x41, 0x5D, 0xE3,\n\t0x9A, 0x8E, 0xCF, 0x49, 0xC0, 0xE6, 0x26, 0xB2, 0x62, 0x32, 0x73, 0x80,\n\t0xE7, 0xD7, 0xB8, 0xC9, 0xA5, 0x4D, 0x2A, 0x6D, 0xA2, 0x7D, 0x12, 0xBF,\n\t0x1D, 0xF6, 0x44, 0x6B, 0xB0, 0x50, 0x95, 0x1F, 0x8D, 0x23, 0x52, 0x4D,\n\t0x28, 0xD8, 0xE3, 0x99, 0xD6, 0xB0, 0x14, 0xE3, 0xF1, 0xE2, 0xD3, 0xF1,\n\t0xF8, 0x2A, 0xA6, 0xC6, 0xAF, 0x24, 0x72, 0xEF, 0xF5, 0x10, 0xF9, 0xFF,\n\t0x6F, 0xDD, 0xA5, 0x4E, 0x04, 0x3F, 0x7A, 0x5F, 0x9E, 0xEE, 0x9D, 0xB4,\n\t0x3D, 0x93, 0x85, 0xF5, 0x55, 0xEB, 0xD4, 0xE7, 0xCE, 0xF1, 0x9C, 0x49,\n\t0x7D, 0xB4, 0x33, 0xCB, 0xB2, 0x87, 0x5A, 0xE6, 0x95, 0x59, 0xA6, 0x44,\n\t0x1F, 0x2C, 0xEB, 0x92, 0x2C, 0xE3, 0xCE, 0xEC, 0x2A, 0x39, 0x9B, 0x4D,\n\t0x0B, 0x49, 0x7D, 0x5D, 0x2F, 0xCD, 0xB1, 0x36, 0x3D, 0xA3, 0xAB, 0xD7,\n\t0xF5, 0xF4, 0x2E, 0xB5, 0x72, 0xE5, 0xCF, 0x8A, 0x4B, 0x71, 0x85, 0x62,\n\t0x1A, 0x2C, 0x2B, 0xFF, 0xA5, 0x33, 0xE5, 0xE8, 0x43, 0x63, 0xF7, 0xF9,\n\t0xC1, 0x93, 0xCE, 0x80, 0x43, 0xAA, 0xFD, 0x05, 0x87, 0xD4, 0xFF, 0xD4,\n\t0x65, 0x04, 0xC1, 0x21, 0x30, 0x94, 0x46, 0xCC, 0x87, 0xE0, 0x4C, 0x03,\n\t0x53, 0x17, 0x18, 0xBD, 0x2C, 0xDD, 0x6F, 0x56, 0x4C, 0x52, 0xAE, 0x09,\n\t0xFF, 0x96, 0x56, 0x93, 0xDF, 0x9B, 0x54, 0x50, 0x5D, 0x4D, 0x40, 0x7B,\n\t0x83, 0x9F, 0x82, 0xF3, 0x0D, 0x8C, 0x09, 0x67, 0xA6, 0x60, 0x13, 0x35,\n\t0xDF, 0xFD, 0xF8, 0x35, 0xB5, 0x50, 0xBC, 0xC2, 0xD2, 0x51, 0xCA, 0x42,\n\t0xAE, 0x5C, 0xCD, 0x06, 0x2D, 0xA4, 0x45, 0x6E, 0xD4, 0x6A, 0x2A, 0x98,\n\t0xAC, 0xDA, 0xE9, 0x35, 0xAF, 0xC7, 0xDA, 0xA0, 0x67, 0x94, 0x22, 0xDA,\n\t0x3F, 0xF4, 0x31, 0xAD, 0x7D, 0x34, 0xAE, 0x59, 0xBA, 0xFF, 0xD4, 0x3E,\n\t0xD3, 0x15, 0x3C, 0x0E, 0xC2, 0xA6, 0x0D, 0xEE, 0x6D, 0x7E, 0x7F, 0xB8,\n\t0xA6, 0x44, 0xFF, 0xF8, 0x0E, 0x28, 0x29, 0x88, 0xB7, 0x20, 0xF7, 0x7E,\n\t0xC9, 0xEF, 0xCB, 0x1B, 0xE1, 0x78, 0x54, 0xB2, 0xFC, 0x18, 0x1F, 0x08,\n\t0x41, 0x5E, 0x4D, 0xD1, 0x08, 0x87, 0x28, 0xAE, 0xA6, 0x26, 0xC2, 0x59,\n\t0xC8, 0xA4, 0x3D, 0xB4, 0xF9, 0x9B, 0x8B, 0x54, 0xA7, 0x65, 0x8E, 0x22,\n\t0xB1, 0x67, 0x16, 0xF8, 0x5B, 0xBA, 0xAD, 0x59, 0xB6, 0xFC, 0xD8, 0xFC,\n\t0x25, 0xF5, 0xFF, 0xFF, 0x46, 0x88, 0x39, 0x56, 0xA8, 0x41, 0x8C, 0x25,\n\t0xE4, 0x10, 0x6B, 0x82, 0x0E, 0x29, 0xE3, 0x2B, 0x03, 0x1D, 0x80, 0xB8,\n\t0xE8, 0x99, 0xB6, 0x82, 0x22, 0xD4, 0x67, 0xD9, 0xB5, 0x6B, 0x6F, 0xDA,\n\t0x9D, 0x00, 0x22, 0xD5, 0xB3, 0x7E, 0x91, 0xFA, 0x8A, 0xBA, 0x5D, 0xC1,\n\t0x08, 0x66, 0xA4, 0x41, 0x0A, 0x3A, 0xA8, 0xC0, 0x0F, 0xEC, 0xB0, 0x86,\n\t0x95, 0x1D, 0x19, 0x58, 0xE9, 0x11, 0x00, 0x12, 0x98, 0xDC, 0xE4, 0x3F,\n\t0x69, 0x3B, 0xE9, 0xC7, 0xED, 0x4F, 0x44, 0x0F, 0x1D, 0xA5, 0x92, 0x25,\n\t0x31, 0xB4, 0x96, 0xF1, 0x8F, 0xFA, 0x27, 0xA1, 0xFA, 0xA1, 0xD0, 0x6D,\n\t0x77, 0xFC, 0xB2, 0x8D, 0x64, 0xDF, 0x7C, 0x5F, 0x3E, 0xD2, 0x5E, 0xC9,\n\t0x7F, 0xB9, 0x48, 0x36, 0x4B, 0xBE, 0x2F, 0x7A, 0x0D, 0x07, 0x46, 0x5F,\n\t0x59, 0xC9, 0xA4, 0x9C, 0x78, 0x32, 0xBE, 0x04, 0x33, 0x79, 0x34, 0x2F,\n\t0x91, 0xCB, 0x1F, 0x67, 0x9E, 0x84, 0x4F, 0x5C, 0xC9, 0x39, 0x98, 0xF6,\n\t0x9D, 0x59, 0xF4, 0xD7, 0xAB, 0x86, 0x5F, 0x14, 0x55, 0x3C, 0x0E, 0x8C,\n\t0xE4, 0x99, 0x2C, 0x51, 0x70, 0xC7, 0x31, 0x49, 0xA1, 0xE9, 0x83, 0xAF,\n\t0x67, 0xBC, 0x94, 0x2B, 0x77, 0xB0, 0x32, 0x43, 0x40, 0x63, 0x48, 0x07,\n\t0x5A, 0x83, 0xF2, 0x4D, 0x81, 0x7B, 0x89, 0x1E, 0xE5, 0x81, 0xF2, 0xBF,\n\t0x29, 0x8B, 0x67, 0x8B, 0x0F, 0x75, 0x20, 0x92, 0x82, 0x28, 0xE1, 0xEB,\n\t0x1D, 0xA5, 0x58, 0xFC, 0x60, 0x32, 0x48, 0x98, 0x91, 0x5B, 0x75, 0xE1,\n\t0x83, 0xAF, 0x1C, 0x41, 0xFA, 0x99, 0x54, 0xA6, 0x64, 0xCA, 0xE0, 0x64,\n\t0xBC, 0x6F, 0x58, 0xAC, 0x08, 0x69, 0x0E, 0xFE, 0x29, 0x2C, 0x56, 0x78,\n\t0x3D, 0xB5, 0xE6, 0xDC, 0x8E, 0xCD, 0x94, 0xF2, 0x78, 0xB8, 0x83, 0x37,\n\t0xEC, 0x54, 0x11, 0xED, 0x21, 0x49, 0xC6, 0xB6, 0x56, 0x6B, 0x7F, 0x52,\n\t0xB5, 0xD6, 0x85, 0xAC, 0xD1, 0x45, 0x9E, 0xC1, 0x7D, 0x15, 0xF3, 0x65,\n\t0xBB, 0x74, 0xAF, 0xB8, 0x4D, 0x56, 0x5A, 0xB9, 0x02, 0xFC, 0x9B, 0xBC,\n\t0xD1, 0x21, 0x6F, 0x45, 0x41, 0x39, 0x31, 0xC9, 0x73, 0x7C, 0x7B, 0xA2,\n\t0x42, 0x7F, 0xC3, 0x1E, 0x22, 0x36, 0x5F, 0xE3, 0xED, 0x53, 0x2C, 0xDF,\n\t0x9D, 0xBE, 0x05, 0xF5, 0xC1, 0x9A, 0x1C, 0x96, 0xC3, 0x97, 0xE8, 0xA3,\n\t0x37, 0x45, 0x9E, 0x79, 0x98, 0x88, 0x7B, 0x35, 0x4C, 0xF4, 0xBF, 0x71,\n\t0x50, 0x4D, 0x66, 0xEE, 0xC6, 0xC5, 0x49, 0xE5, 0xDA, 0x4C, 0x6F, 0x12,\n\t0x3C, 0x3C, 0x58, 0x68, 0x1F, 0xFE, 0xFC, 0x11, 0x81, 0xE6, 0x5C, 0x90,\n\t0x5C, 0xAE, 0xB7, 0x73, 0x25, 0x2F, 0xA5, 0xB8, 0xE0, 0x68, 0x2A, 0x17,\n\t0x2F, 0x8D, 0xC1, 0x45, 0x1F, 0x87, 0xE9, 0xC3, 0xFD, 0xD0, 0xF1, 0x2B,\n\t0x9F, 0x83, 0x8B, 0x99, 0x63, 0x95, 0xF3, 0x58, 0x7A, 0xFB, 0x0F, 0x79,\n\t0x59, 0x4A, 0x03, 0x66, 0xFF, 0xF7, 0x69, 0x98, 0xD6, 0xEB, 0xA9, 0x62,\n\t0x87, 0x60, 0x6C, 0x66, 0xBF, 0xFB, 0x65, 0x4C, 0x94, 0xD3, 0x22, 0xF7,\n\t0xFF, 0xBB, 0x94, 0x4A, 0xC0, 0xEE, 0x3F, 0x36, 0x4F, 0x5E, 0x0F, 0x97,\n\t0xE9, 0xC7, 0x11, 0xEA, 0x97, 0xF8, 0x95, 0x1E, 0xF7, 0xF5, 0x0C, 0x99,\n\t0xD3, 0x1D, 0x57, 0xC6, 0xB3, 0x45, 0x9E, 0xF9, 0xBB, 0x46, 0xA7, 0x56,\n\t0xB9, 0xFA, 0xEC, 0xC1, 0x32, 0xCE, 0xEE, 0xAA, 0xF8, 0xD7, 0xE6, 0x47,\n\t0x95, 0x5E, 0xF9, 0x36, 0x8D, 0x09, 0xFD, 0x3F, 0x74, 0x9D, 0xC1, 0xFF,\n\t0xF4, 0x5D, 0x6A, 0x59, 0xAD, 0x4B, 0xAA, 0xFF, 0x07, 0x8E, 0x99, 0x41,\n\t0xF2, 0xA0, 0xD5, 0x7E, 0x95, 0xAD, 0x4B, 0x36, 0x84, 0xCB, 0x67, 0x4E,\n\t0xC7, 0x4A, 0x46, 0xE1, 0x78, 0x21, 0x8A, 0xE4, 0x7F, 0xF0, 0x43, 0x52,\n\t0xB3, 0xD9, 0xBF, 0x38, 0x21, 0x1D, 0xDC, 0xBF, 0xD8, 0xA5, 0x23, 0xDD,\n\t0xA5, 0xFE, 0x31, 0x38, 0x7E, 0xF7, 0x27, 0x43, 0xEE, 0xCC, 0x9E, 0x0E,\n\t0x9B, 0x49, 0x8E, 0x67, 0xFC, 0x74, 0xB4, 0xE4, 0x1F, 0x38, 0x61, 0x10,\n\t0x43, 0x1D, 0x2B, 0x63, 0x97, 0xBA, 0x18, 0xFF, 0xD3, 0xD1, 0xFB, 0x62,\n\t0xCB, 0x0D, 0xFE, 0x5E, 0x8C, 0xF8, 0xA1, 0x8C, 0x72, 0x3D, 0x75, 0x24,\n\t0xB9, 0x3B, 0x64, 0xF0, 0xF6, 0x3F, 0xD9, 0xA5, 0x98, 0x78, 0x3F, 0x7A,\n\t0x7F, 0x10, 0xAE, 0xF9, 0x3B, 0xC3, 0xB3, 0x01, 0xDD, 0x3D, 0xFD, 0x4B,\n\t0x3F, 0x19, 0x7C, 0x05, 0x4F, 0xBA, 0x15, 0xFD, 0x37, 0x6C, 0xC8, 0x1F,\n\t0xA8, 0xE2, 0xDB, 0xE8, 0xBA, 0x54, 0x96, 0x2E, 0xF7, 0x9D, 0xC6, 0x92,\n\t0x19, 0xDD, 0xD2, 0x96, 0xF8, 0xDC, 0xC4, 0x70, 0x29, 0x73, 0x20, 0x64,\n\t0xC6, 0xF4, 0xC1, 0xA3, 0x06, 0x94, 0x19, 0x5D, 0xE8, 0x8C, 0x18, 0x18,\n\t0xDC, 0x32, 0xB2, 0x98, 0x54, 0x84, 0xAC, 0x8C, 0xBF, 0xE2, 0xB3, 0x35,\n\t0xD5, 0x91, 0x9A, 0x2C, 0xDD, 0x67, 0x5C, 0x0C, 0x4F, 0x96, 0x8E, 0x14,\n\t0xF2, 0x13, 0xF3, 0x39, 0x4F, 0x2E, 0xAF, 0xE5, 0xB7, 0x2A, 0xB3, 0xCA,\n\t0x18, 0x42, 0x28, 0x97, 0x44, 0x88, 0xD7, 0x5C, 0xF3, 0xC0, 0x5E, 0xE6,\n\t0x89, 0x5C, 0x9D, 0x99, 0x0A, 0xD1, 0x71, 0xB5, 0xCA, 0x13, 0x48, 0x0A,\n\t0xB1, 0x11, 0x61, 0x3A, 0x43, 0x35, 0x5E, 0x21, 0x29, 0x96, 0x7F, 0x46,\n\t0x9F, 0xB0, 0x59, 0x44, 0x89, 0x63, 0x8E, 0x62, 0x23, 0xAE, 0xDF, 0x8D,\n\t0x4E, 0x96, 0xE8, 0x2A, 0x76, 0x1C, 0x98, 0x16, 0x5C, 0xCE, 0x4D, 0xF7,\n\t0x50, 0x35, 0x93, 0x25, 0xD8, 0xC1, 0xBB, 0x42, 0x38, 0x45, 0xE7, 0xB7,\n\t0x5B, 0xA6, 0x5F, 0x67, 0xCB, 0x8D, 0xC3, 0x73, 0x0A, 0xCF, 0x77, 0x94,\n\t0xE3, 0x81, 0x88, 0xFF, 0xD3, 0xD5, 0x69, 0xF2, 0x5A, 0x60, 0x33, 0xE5,\n\t0x7E, 0x4E, 0xDC, 0x0D, 0x9E, 0xBF, 0xFA, 0x39, 0x81, 0xE5, 0x09, 0xC4,\n\t0x25, 0x98, 0x76, 0xED, 0xFB, 0x2B, 0xD7, 0xE9, 0x7F, 0x6B, 0x5F, 0x8B,\n\t0x61, 0x18, 0x3D, 0x1B, 0xE2, 0x71, 0x5E, 0xA3, 0x57, 0x7E, 0xC4, 0x69,\n\t0x33, 0x88, 0xEB, 0xA0, 0x9B, 0x41, 0xDF, 0xC7, 0xEF, 0xBC, 0x4F, 0x1D,\n\t0x43, 0xD3, 0x47, 0x8C, 0xD5, 0xD1, 0x33, 0xB7, 0xF1, 0xFF, 0x57, 0x6E,\n\t0xAE, 0x50, 0x7F, 0x95, 0x32, 0x71, 0x25, 0x0B, 0x8B, 0xF6, 0xF6, 0x83,\n\t0x5D, 0xB2, 0x5A, 0x88, 0x7F, 0xCF, 0x95, 0x5B, 0xB8, 0x46, 0x6B, 0x61,\n\t0xF9, 0x4F, 0x27, 0x7B, 0x65, 0xF7, 0xFF, 0x4D, 0x24, 0xA5, 0x81, 0xCF,\n\t0x98, 0x87, 0x23, 0x46, 0xD7, 0xDA, 0xBF, 0x6F, 0x40, 0xC4, 0x08, 0xB4,\n\t0xEF, 0xCE, 0x03, 0x8E, 0xD1, 0x57, 0x86, 0x3C, 0x57, 0x88, 0x6B, 0x85,\n\t0x5E, 0x8A, 0x5A, 0xB0, 0x38, 0xFD, 0xD6, 0x37, 0xE5, 0x60, 0x95, 0xA3,\n\t0xD9, 0x4E, 0x94, 0xD3, 0x79, 0x0E, 0x21, 0xC0, 0x60, 0xE2, 0x81, 0xF1,\n\t0xDC, 0x25, 0x1D, 0x2D, 0x4C, 0xE7, 0x54, 0x26, 0x1F, 0xF7, 0xCA, 0xDE,\n\t0xCE, 0x26, 0x52, 0x1C, 0x58, 0xFE, 0x8F, 0xE8, 0x76, 0x04, 0x53, 0xDE,\n\t0xF4, 0xE6, 0xF8, 0xC5, 0x60, 0x23, 0x9D, 0x4B, 0x99, 0x8C, 0xE7, 0xDA,\n\t0xE4, 0xAF, 0x63, 0x98, 0x73, 0xA0, 0xAF, 0xCA, 0xB3, 0xBC, 0x30, 0x1A,\n\t0xDB, 0x1E, 0x3F, 0x73, 0x33, 0x85, 0x3B, 0xA3, 0x8F, 0x0A, 0x58, 0x96,\n\t0x12, 0x43, 0xE1, 0xBA, 0x0C, 0x32, 0x73, 0xE3, 0x40, 0xE4, 0xEA, 0x95,\n\t0x85, 0x3D, 0x07, 0xCA, 0xF0, 0xFF, 0xB7, 0xCB, 0xE4, 0xBD, 0x25, 0x72,\n\t0x3C, 0x23, 0x88, 0xDF, 0xF5, 0xCB, 0x1C, 0xA6, 0xCE, 0xFA, 0x61, 0x5A,\n\t0x7C, 0x1D, 0xA3, 0xC5, 0x63, 0x5A, 0x28, 0xB9, 0x90, 0x30, 0x8C, 0x61,\n\t0x89, 0x83, 0x45, 0x57, 0xC4, 0x0F, 0xB5, 0xBD, 0x36, 0x6F, 0xA7, 0xC2,\n\t0x36, 0xCE, 0xDC, 0x56, 0x3E, 0x41, 0xC0, 0x6A, 0xD2, 0x42, 0xEC, 0x5D,\n\t0x56, 0x32, 0xB5, 0x6B, 0xC7, 0xF7, 0x7F, 0x24, 0xC2, 0x70, 0x01, 0x0B,\n\t0x94, 0xA8, 0xD1, 0x22, 0x44, 0x12, 0x56, 0x98, 0x64, 0xCF, 0xFC, 0x01,\n\t0x02, 0xB8, 0x2D, 0xC1, 0xB4, 0xE4, 0xCA, 0x17, 0xA7, 0xC5, 0xF2, 0x97,\n\t0x4A, 0x1C, 0x3B, 0x57, 0x42, 0xBB, 0x24, 0xDA, 0x17, 0x13, 0x51, 0x9C,\n\t0x17, 0x89, 0x3B, 0x79, 0x48, 0x9E, 0xC9, 0x8A, 0x14, 0x2E, 0x3F, 0x8B,\n\t0x52, 0x98, 0x0C, 0xAF, 0xBC, 0x48, 0xC0, 0x44, 0x7C, 0x50, 0xC0, 0x46,\n\t0xC1, 0xA0, 0x4A, 0xC6, 0x2D, 0xCB, 0x13, 0x84, 0x95, 0x5E, 0x32, 0x28,\n\t0x8E, 0x29, 0x03, 0xFC, 0x1B, 0x97, 0x5E, 0xFF, 0x7F, 0x83, 0xF8, 0x63,\n\t0x78, 0x9E, 0xE7, 0x79, 0x33, 0x34, 0xA9, 0x16, 0x85, 0x7B, 0x15, 0x6A,\n\t0xE9, 0x0D, 0xBF, 0x7B, 0xDA, 0x27, 0x3D, 0x08, 0x72, 0x2E, 0xF8, 0x1C,\n\t0xE2, 0xC3, 0xD1, 0x73, 0x60, 0x99, 0x79, 0xE8, 0x35, 0x49, 0x2F, 0x49,\n\t0x29, 0x59, 0x65, 0xE5, 0x2C, 0xD2, 0xC1, 0x23, 0x6F, 0x30, 0xDF, 0x75,\n\t0x69, 0x65, 0xA4, 0xAB, 0x31, 0xB2, 0x8F, 0xEC, 0x8D, 0xB1, 0x89, 0x5F,\n\t0x75, 0x91, 0x39, 0x16, 0x9D, 0x70, 0x87, 0xCD, 0xB4, 0x61, 0x32, 0xC6,\n\t0x4A, 0x3C, 0x9A, 0xD7, 0x48, 0xAE, 0xE8, 0x5C, 0x9B, 0xBF, 0x52, 0x8D,\n\t0x33, 0x70, 0xD0, 0x47, 0xEE, 0x2C, 0x1D, 0x31, 0x0A, 0x4F, 0xCC, 0x93,\n\t0x3D, 0xAE, 0x65, 0xF4, 0xCE, 0x98, 0x28, 0x34, 0x4F, 0xD1, 0x27, 0x5A,\n\t0x61, 0xC9, 0x39, 0x8C, 0x9D, 0xB6, 0x14, 0xEB, 0xB4, 0xD7, 0x93, 0xE4,\n\t0xD5, 0xA1, 0xE7, 0xA1, 0xBD, 0x59, 0x8E, 0x31, 0xE9, 0x40, 0x33, 0xC7,\n\t0xA8, 0x1A, 0xAB, 0xB7, 0xC1, 0xD5, 0xFF, 0x37, 0x4E, 0x92, 0xD5, 0x49,\n\t0x31, 0x8D, 0xCD, 0x1E, 0xCD, 0x69, 0xB6, 0xE5, 0xF0, 0x2C, 0xA2, 0xA3,\n\t0xA9, 0x1F, 0xCD, 0x2F, 0x11, 0x27, 0xB7, 0x4D, 0x2B, 0x5D, 0xD1, 0x6B,\n\t0x1D, 0x9E, 0xA5, 0x1E, 0xF6, 0xEB, 0xB1, 0x9D, 0x56, 0x78, 0xBD, 0xF8,\n\t0x38, 0xF4, 0xF9, 0x17, 0xFB, 0xFD, 0xFF, 0xFF, 0x3F, 0xBE, 0x10, 0x3C,\n\t0x13, 0x68, 0xBB, 0x5F, 0xC0, 0x97, 0x73, 0x25, 0x34, 0xA5, 0x8B, 0x7A,\n\t0xFF, 0xA6, 0x2F, 0x87, 0xDC, 0x73, 0xFB, 0xF9, 0x6F, 0xAC, 0x2D, 0x3C,\n\t0xE1, 0x2B, 0xB9, 0x76, 0x3B, 0x1D, 0x0D, 0x2E, 0xD2, 0xC7, 0xF1, 0x49,\n\t0xC1, 0xCD, 0xA4, 0xC2, 0xB9, 0x4C, 0xC2, 0x94, 0xE9, 0x2B, 0xB9, 0x36,\n\t0x79, 0x2D, 0x95, 0x89, 0x2B, 0x55, 0x26, 0x95, 0x2B, 0xCE, 0xAC, 0x5A,\n\t0x26, 0x2E, 0xB7, 0x46, 0x8C, 0x74, 0x6B, 0xFE, 0xF3, 0xFF, 0x2B, 0x61,\n\t0xFE, 0x78, 0x13, 0x67, 0x6C, 0x8D, 0x93, 0x84, 0x55, 0x67, 0x9D, 0x88,\n\t0x0F, 0xC9, 0x3B, 0xC7, 0x92, 0xCF, 0xF8, 0x0F, 0x41, 0x57, 0xB8, 0xC0,\n\t0x78, 0x63, 0x7D, 0x65, 0x9A, 0x70, 0x25, 0x0B, 0x17, 0x20, 0xF8, 0x53,\n\t0xF8, 0x1A, 0x3F, 0x5A, 0x32, 0x47, 0x8F, 0x8B, 0x65, 0xEE, 0x34, 0x40,\n\t0xF7, 0x55, 0x2C, 0xE3, 0x72, 0x01, 0xA1, 0x8A, 0x88, 0xD0, 0x07, 0x44,\n\t0xF6, 0x70, 0x70, 0xB9, 0xE0, 0x4C, 0x2A, 0x0A, 0x4D, 0xD1, 0x78, 0x0E,\n\t0x88, 0x25, 0x7B, 0x3D, 0x17, 0x29, 0xD7, 0x63, 0x43, 0x94, 0x2B, 0x29,\n\t0xAB, 0xC1, 0x73, 0xFB, 0x68, 0x3E, 0x5E, 0x1A, 0xB1, 0x93, 0xEE, 0x77,\n\t0x2F, 0xE1, 0xD8, 0x02, 0x34, 0xCF, 0xEA, 0x21, 0x3E, 0x27, 0xA0, 0xEB,\n\t0xAC, 0xD3, 0x38, 0x4F, 0x5C, 0x9A, 0x74, 0xFB, 0xAC, 0x23, 0x1C, 0x4D,\n\t0x8B, 0x1F, 0x2A, 0x7C, 0xFE, 0xCC, 0x9A, 0x2F, 0x2C, 0xC4, 0x9D, 0xDB,\n\t0x91, 0x63, 0xF3, 0x07, 0x71, 0xB9, 0x45, 0xC8, 0x92, 0xB5, 0x40, 0x0F,\n\t0x93, 0xBD, 0x96, 0xCC, 0xF5, 0x6F, 0xCF, 0x88, 0xC9, 0xE0, 0xDF, 0xF8,\n\t0xEF, 0xD1, 0xFD, 0xDF, 0x27, 0xC2, 0x56, 0xF0, 0x19, 0xB6, 0xFF, 0x4B,\n\t0x47, 0xD0, 0xE6, 0x21, 0xA2, 0x5D, 0x23, 0x3A, 0x2E, 0x7F, 0x8A, 0x9A,\n\t0x05, 0x96, 0x2F, 0xCE, 0x2B, 0xDF, 0xCC, 0x20, 0x48, 0x04, 0x2B, 0x83,\n\t0xBD, 0xB1, 0x5E, 0x3A, 0x10, 0xEE, 0xD9, 0x62, 0xF5, 0xA2, 0xEE, 0x53,\n\t0x8F, 0xAA, 0xE3, 0x4B, 0x67, 0xED, 0xFF, 0xA5, 0x2F, 0xC1, 0xF4, 0x30,\n\t0xD1, 0xED, 0x97, 0xE8, 0x67, 0xE9, 0xDF, 0x14, 0x99, 0xF8, 0x1D, 0x39,\n\t0x23, 0xF6, 0xB0, 0xE7, 0x41, 0x27, 0x6D, 0x36, 0xFF, 0xBF, 0x94, 0x23,\n\t0x7B, 0x61, 0x7C, 0xE4, 0x7A, 0x6A, 0x3E, 0xB9, 0x89, 0x4D, 0xAD, 0x16,\n\t0x3E, 0xF1, 0xF1, 0x64, 0xB5, 0xF8, 0x56, 0xED, 0x7F, 0x9F, 0x5E, 0x0B,\n\t0xCD, 0xB3, 0x48, 0x1C, 0x1E, 0x2D, 0xA4, 0x25, 0x1E, 0xED, 0xEB, 0x51,\n\t0xC7, 0x37, 0x4B, 0xBB, 0xB1, 0xB3, 0x46, 0x3F, 0xCF, 0x1A, 0xDD, 0x8E,\n\t0xC2, 0x1E, 0x36, 0xFF, 0x39, 0xD0, 0xBE, 0x27, 0xB6, 0x4C, 0x7F, 0xA3,\n\t0xA9, 0xF8, 0x64, 0xB4, 0x69, 0xF7, 0x0F, 0xF1, 0x2E, 0x6D, 0x19, 0x68,\n\t0xDF, 0x6F, 0x95, 0x86, 0xBB, 0x37, 0x7D, 0x6B, 0xDE, 0x53, 0x1A, 0x47,\n\t0x6F, 0x7F, 0x73, 0x45, 0xAA, 0x8B, 0xFA, 0xE5, 0x11, 0xB7, 0xD8, 0xFC,\n\t0x14, 0xCA, 0x23, 0x5D, 0x48, 0x8A, 0xDF, 0x0A, 0x37, 0x14, 0x39, 0xE2,\n\t0xA2, 0x26, 0xFA, 0x4C, 0xB4, 0x59, 0xFF, 0x3F, 0x8C, 0xB2, 0xF5, 0x8A,\n\t0xCD, 0xDF, 0x36, 0xBB, 0xFF, 0x3F, 0xC1, 0x30, 0x7A, 0x00, 0x16, 0x04,\n\t0x25, 0x1F, 0x20, 0x8D, 0xE1, 0xD4, 0x80, 0x2B, 0xC6, 0xB0, 0xC3, 0x0A,\n\t0x6E, 0xA0, 0x1C, 0x25, 0x13, 0x5D, 0x44, 0x2D, 0xF9, 0x1F, 0x09, 0xA2,\n\t0x93, 0x71, 0x19, 0x19, 0x8F, 0x7E, 0x17, 0x3A, 0xE9, 0x33, 0x9E, 0xFF,\n\t0xD0, 0x65, 0x6C, 0xA8, 0xFE, 0x11, 0x94, 0x2E, 0x7B, 0x16, 0x22, 0x51,\n\t0x56, 0x60, 0x2F, 0x43, 0xEB, 0xD1, 0x47, 0xA3, 0x1F, 0xDB, 0x2F, 0xBA,\n\t0xC9, 0x47, 0x36, 0x88, 0xEE, 0xE4, 0x3F, 0x41, 0xA1, 0x3C, 0x54, 0xA1,\n\t0x38, 0xE9, 0x23, 0x93, 0x0E, 0x25, 0x8C, 0x33, 0xFC, 0x74, 0xA9, 0xBE,\n\t0x18, 0x25, 0x96, 0xFD, 0x49, 0xF9, 0xFE, 0x7F, 0x49, 0x35, 0xFE, 0x67,\n\t0xDD, 0x07, 0x9E, 0x2C, 0xEC, 0x77, 0xA8, 0x52, 0xE7, 0xB0, 0xC7, 0x9E,\n\t0x28, 0x4B, 0x86, 0x7E, 0x39, 0x9B, 0xE9, 0x6D, 0xC3, 0xE4, 0xED, 0x54,\n\t0xF1, 0xA5, 0x13, 0x0A, 0x0E, 0xB5, 0xE5, 0x73, 0x37, 0x50, 0xFC, 0x0D,\n\t0x38, 0x4D, 0x35, 0x9D, 0xD5, 0x42, 0x3F, 0x24, 0xBD, 0x32, 0x7A, 0x3D,\n\t0xCF, 0xB4, 0x93, 0xA1, 0xDC, 0xCE, 0xC5, 0xDF, 0x9A, 0x72, 0xA8, 0xE3,\n\t0x8E, 0x9F, 0x1A, 0x6C, 0xF2, 0xCF, 0x32, 0x7A, 0x3B, 0x40, 0x8C, 0xEF,\n\t0x72, 0xD0, 0x6B, 0x21, 0xFE, 0x9E, 0x6B, 0x1D, 0x2C, 0xFA, 0x5F, 0xD3,\n\t0x57, 0x6A, 0x31, 0x7A, 0x9C, 0x8E, 0x9A, 0xBF, 0xD2, 0x79, 0xF7, 0x5F,\n\t0x0C, 0xBB, 0xF4, 0x63, 0xFA, 0x4E, 0x1B, 0xED, 0xE9, 0x60, 0xC9, 0x5A,\n\t0xA9, 0x8B, 0x13, 0x67, 0x9E, 0xF5, 0xDE, 0x4C, 0xBF, 0x11, 0xAC, 0x31,\n\t0x64, 0xD5, 0xFC, 0xF8, 0x74, 0xDC, 0x13, 0xC5, 0x49, 0x72, 0xA2, 0xF7,\n\t0xF1, 0x83, 0x2B, 0xC1, 0x1F, 0xF7, 0x46, 0xD8, 0x0C, 0xDA, 0xD3, 0x97,\n\t0x78, 0xFE, 0xFD, 0x50, 0x99, 0xDE, 0x2D, 0x3F, 0x42, 0x6F, 0x7F, 0x70,\n\t0xA6, 0xAD, 0x5E, 0xBF, 0x23, 0xB9, 0x23, 0xA7, 0xD0, 0xE7, 0x1D, 0x5D,\n\t0x75, 0x31, 0x7E, 0xE7, 0x59, 0x2F, 0x95, 0xF9, 0x56, 0x7A, 0xCA, 0xFD,\n\t0x64, 0xCE, 0x88, 0xCD, 0x74, 0xE5, 0x93, 0x71, 0x15, 0x38, 0x32, 0x98,\n\t0x14, 0xE0, 0xC8, 0xC0, 0x9D, 0xA9, 0x2C, 0xA4, 0xB1, 0xE2, 0x4B, 0x9D,\n\t0xF1, 0x4F, 0x29, 0x8E, 0x17, 0xBF, 0x0F, 0x65, 0xB4, 0xB7, 0xCC, 0xD1,\n\t0x7C, 0xC9, 0x71, 0x5A, 0x99, 0x6B, 0x11, 0xAB, 0x4B, 0x9D, 0x85, 0x60,\n\t0x5C, 0xFC, 0x2A, 0x0C, 0xF9, 0x2B, 0xDF, 0x9D, 0x25, 0x43, 0xDE, 0xDB,\n\t0x67, 0x38, 0x66, 0xFE, 0xFF, 0x24, 0x6E, 0x28, 0xF9, 0xF1, 0x9D, 0x43,\n\t0x74, 0x34, 0xBF, 0xC3, 0x4B, 0x5A, 0x64, 0x7C, 0xBB, 0xE5, 0x7B, 0x02,\n\t0xFD, 0xB5, 0x3F, 0x73, 0x04, 0x7F, 0xF2, 0x25, 0x9F, 0x13, 0xD6, 0x3A,\n\t0x3B, 0xD7, 0x27, 0x8F, 0xC6, 0xE6, 0x77, 0x36, 0x94, 0x2B, 0x7F, 0x84,\n\t0x72, 0x2F, 0xD4, 0x3F, 0x04, 0x7D, 0x68, 0xBE, 0x7B, 0x17, 0x43, 0xE2,\n\t0xFF, 0xE7, 0x92, 0x64, 0xEF, 0xFC, 0x91, 0xAF, 0x4E, 0x14, 0xE7, 0x95,\n\t0x40, 0x52, 0xA7, 0x7F, 0x45, 0xC4, 0xDC, 0x79, 0xF2, 0xCC, 0x4D, 0xC8,\n\t0xFF, 0x97, 0x2F, 0xC1, 0x52, 0xE0, 0x1B, 0xD0, 0x75, 0xE9, 0x41, 0x21,\n\t0x1B, 0x1A, 0xE8, 0x38, 0xE6, 0xF8, 0x21, 0xF1, 0x4A, 0xE6, 0x89, 0xD3,\n\t0x91, 0xCA, 0x28, 0x8E, 0x79, 0xBA, 0x85, 0x22, 0x3C, 0x41, 0x67, 0xF4,\n\t0xFB, 0x42, 0x95, 0xBD, 0x63, 0xB2, 0x77, 0x82, 0x0E, 0xFA, 0x6B, 0x46,\n\t0xEE, 0x47, 0x2A, 0xFB, 0x63, 0xF2, 0xFF, 0x67, 0x39, 0x2C, 0x6D, 0x74,\n\t0xB4, 0x54, 0x36, 0x7E, 0x10, 0x7F, 0x09, 0x07, 0x79, 0xA6, 0x8D, 0xEE,\n\t0x38, 0x65, 0x73, 0x65, 0x10, 0xDD, 0x4B, 0x65, 0xD0, 0x5F, 0x44, 0x77,\n\t0x69, 0x4B, 0x81, 0x7F, 0xBF, 0x74, 0x66, 0xDF, 0x8F, 0x1B, 0xFA, 0x6E,\n\t0xC9, 0x9E, 0x11, 0x16, 0xFD, 0x59, 0x32, 0x67, 0xBE, 0xA3, 0x5D, 0x2A,\n\t0xF5, 0xFF, 0x76, 0x6F, 0xC0, 0xBB, 0x54, 0x35, 0x30, 0x95, 0xE1, 0x8B,\n\t0xFA, 0xA5, 0xFF, 0xF6, 0x7F, 0xFD, 0x4F, 0xCF, 0x80, 0x97, 0x21, 0x52,\n\t0x68, 0x00, 0xC0, 0xA2, 0xC0, 0x4A, 0xE7, 0x12, 0xFB, 0xB6, 0x90, 0x44,\n\t0x0D, 0x30, 0xFF, 0x0D, 0x20, 0x44, 0x48, 0x47, 0xFF, 0x0D, 0xFF, 0x74,\n\t0xA3, 0xE9, 0x5E, 0x0C, 0x90, 0xE1, 0xC4, 0x17, 0x54, 0xB8, 0x44, 0xD1,\n\t0x81, 0x1F, 0xB8, 0x5C, 0x48, 0x6E, 0xA5, 0x63, 0xB0, 0x61, 0xC8, 0x0F,\n\t0x2D, 0x47, 0xAC, 0x20, 0x0A, 0x2F, 0x51, 0x88, 0xB6, 0x2E, 0xA4, 0x81,\n\t0xCC, 0x8A, 0xD0, 0x04, 0x35, 0x48, 0xC1, 0x0C, 0xD0, 0x96, 0x05, 0x8D,\n\t0x17, 0x0B, 0xA0, 0xC1, 0x06, 0x56, 0x43, 0x19, 0x62, 0x31, 0xC8, 0xB1,\n\t0x01, 0x0A, 0xFC, 0x70, 0x09, 0x22, 0x0C, 0x20, 0xEC, 0xF8, 0x10, 0xA4,\n\t0x81, 0x19, 0x31, 0x28, 0xB9, 0xC3, 0x69, 0x0D, 0x01, 0x78, 0xA9, 0x80,\n\t0x8E, 0x07, 0x9C, 0x94, 0x80, 0x73, 0x85, 0x48, 0x48, 0xE0, 0xC3, 0x44,\n\t0x87, 0x95, 0x20, 0x48, 0x43, 0xC8, 0x31, 0x60, 0x02, 0x1B, 0x5A, 0x50,\n\t0x64, 0x0A, 0x27, 0x52, 0x30, 0x13, 0x00, 0x22, 0xC2, 0x1C, 0xCA, 0xA0,\n\t0x31, 0x41, 0x6D, 0xBC, 0x90, 0x40, 0x77, 0x4D, 0xA4, 0xE0, 0x28, 0x00,\n\t0x03, 0x3F, 0x38, 0x5A, 0x46, 0x04, 0x8F, 0xA9, 0xE0, 0xEB, 0xB7, 0xA3,\n\t0xE6, 0x37, 0x4C, 0xBD, 0x65, 0xED, 0x9A, 0x7A, 0xEB, 0xBB, 0x8F, 0xFB,\n\t0x07, 0xEB, 0xFF, 0x04, 0xFC, 0x47, 0xC0, 0xFF, 0x03, 0xFC, 0x6F, 0xC1,\n\t0x27, 0x09, 0xC4, 0xF4, 0xE2, 0xFC, 0xCF, 0x32, 0x78, 0x07, 0x1C, 0xFF,\n\t0x87, 0xB6, 0xF1, 0x2E, 0xC9, 0xE4, 0x07, 0xBC, 0x76, 0x70, 0x05, 0x78,\n\t0x51, 0xF7, 0x0C, 0x27, 0xEA, 0xDD, 0xF9, 0x4F, 0x92, 0xAD, 0x84, 0xEC,\n\t0x2E, 0xB2, 0xCB, 0x82, 0xCA, 0x33, 0x60, 0x8B, 0x5C, 0x72, 0x2C, 0x0A,\n\t0xC9, 0xBA, 0x59, 0x25, 0xA7, 0xAE, 0x1C, 0x85, 0xE2, 0xA3, 0xDC, 0x2E,\n\t0x50, 0x1E, 0x06, 0x94, 0x93, 0x2C, 0xF1, 0xE4, 0xF2, 0x95, 0x3B, 0xDC,\n\t0x11, 0x84, 0x63, 0x66, 0x8E, 0xC6, 0x8E, 0x49, 0x40, 0x21, 0x80, 0x2D,\n\t0x92, 0xE8, 0x3F, 0x89, 0x1F, 0xC7, 0xB9, 0x45, 0xC6, 0x5A, 0xE4, 0x97,\n\t0xB4, 0x18, 0x95, 0x00, 0x80, 0x15, 0x3A, 0x48, 0x42, 0x86, 0x00, 0x3B,\n\t0x76, 0x24, 0x71, 0x84, 0x21, 0x86, 0xD8, 0xF2, 0xD7, 0x63, 0x79, 0x96,\n\t0x78, 0x3B, 0x5F, 0x72, 0xEE, 0xB5, 0xE4, 0x57, 0xEC, 0xD8, 0x81, 0x04,\n\t0xBE, 0x3F, 0xF8, 0xB7, 0xD7, 0x53, 0x97, 0xBC, 0x64, 0xDE, 0x81, 0x3B,\n\t0x5F, 0x2A, 0x51, 0x03, 0x01, 0x29, 0x48, 0xC2, 0x0A, 0x92, 0x8F, 0x7F,\n\t0x01, 0xFF, 0x71, 0x5A, 0x28, 0xA5, 0x12, 0x25, 0x09, 0x24, 0xC2, 0x60,\n\t0xC2, 0x86, 0x3B, 0x6D, 0x5D, 0x72, 0x8F, 0x72, 0xFF, 0xCE, 0xA6, 0x4B,\n\t0x1B, 0xE9, 0x12, 0xDE, 0xD1, 0xE9, 0x5F, 0xF0, 0x9C, 0xC8, 0x15, 0xEC,\n\t0x84, 0x79, 0x68, 0x88, 0xC4, 0x1C, 0xFB, 0x3E, 0xE3, 0x47, 0xB9, 0xF3,\n\t0x33, 0x7F, 0xFF, 0x3B, 0xB2, 0xA3, 0x6E, 0x9F, 0x1C, 0x96, 0x9F, 0x4C,\n\t0xE6, 0x5C, 0x20, 0x93, 0x4F, 0xFF, 0xFF, 0x9E, 0x23, 0x7F, 0x7C, 0xF0,\n\t0xE7, 0x4F, 0xCC, 0xE7, 0xE4, 0xA1, 0xF8, 0x84, 0xBD, 0x4C, 0x1D, 0x17,\n\t0xBD, 0x67, 0xAB, 0xB4, 0x51, 0xA5, 0xFE, 0xB3, 0x5F, 0x82, 0x40, 0xA0,\n\t0x39, 0x5E, 0x33, 0xE8, 0x5E, 0x5A, 0x44, 0xC7, 0xD5, 0x12, 0xDD, 0x2C,\n\t0x45, 0xE0, 0x8B, 0xF0, 0x88, 0x54, 0x60, 0xA2, 0x22, 0x2F, 0x91, 0x8A,\n\t0x69, 0x33, 0x92, 0x2B, 0x1F, 0x91, 0x72, 0xAF, 0xF1, 0x9C, 0x8F, 0xD8,\n\t0xAB, 0x2F, 0x6C, 0x32, 0x89, 0x64, 0xBC, 0xDC, 0x17, 0xAA, 0x4C, 0x43,\n\t0xF2, 0xE3, 0xC9, 0xDE, 0x17, 0x29, 0xD1, 0x9B, 0x27, 0x73, 0x3C, 0x19,\n\t0x3D, 0xF9, 0x79, 0x57, 0x64, 0x22, 0x39, 0x95, 0x88, 0x91, 0xA8, 0x46,\n\t0xF2, 0x22, 0x69, 0xF1, 0x5C, 0x4C, 0x3C, 0x12, 0x98, 0xE8, 0xF5, 0xCA,\n\t0x75, 0xC2, 0xF5, 0xEF, 0xD5, 0xEB, 0xAB, 0x33, 0xDB, 0xCF, 0xF4, 0x8C,\n\t0xF0, 0x8C, 0xDC, 0x17, 0x9D, 0x5F, 0x82, 0x9D, 0xBE, 0x1F, 0x1D, 0xD4,\n\t0xA5, 0xD8, 0x29, 0xFF, 0xAF, 0xF1, 0x93, 0x83, 0x4D, 0xF6, 0x44, 0x4E,\n\t0x87, 0x2A, 0x73, 0x4B, 0x74, 0xEE, 0x50, 0x47, 0x2A, 0xE3, 0x92, 0x19,\n\t0xF4, 0x5F, 0xD1, 0xA7, 0x86, 0x94, 0xA8, 0x43, 0x1D, 0xAD, 0xFD, 0x38,\n\t0x7F, 0x5D, 0x48, 0x69, 0x6F, 0x9C, 0x3D, 0x1D, 0x2A, 0x11, 0xFD, 0x2B,\n\t0x73, 0x3A, 0x6C, 0x44, 0xB4, 0x5F, 0xB9, 0xFE, 0x21, 0x49, 0x71, 0x6C,\n\t0xFC, 0xDD, 0x17, 0xE8, 0x16, 0xC9, 0xEE, 0x92, 0x81, 0xA4, 0x11, 0x1F,\n\t0x3C, 0x6A, 0x40, 0x19, 0x8A, 0xA9, 0x10, 0x31, 0x30, 0xB8, 0x85, 0x85,\n\t0xDE, 0x1B, 0x11, 0xE2, 0x9E, 0x34, 0xB2, 0x51, 0x21, 0x8C, 0xD4, 0x5F,\n\t0x88, 0xFF, 0x82, 0x40, 0x33, 0x5C, 0x8A, 0xCB, 0x49, 0x8A, 0xCA, 0x28,\n\t0x85, 0x5E, 0x4B, 0x39, 0x97, 0xCD, 0x64, 0xCF, 0xED, 0x92, 0x89, 0x2A,\n\t0x99, 0x15, 0x29, 0xF7, 0x33, 0x8A, 0x77, 0xE5, 0x23, 0xFE, 0x9F, 0xC9,\n\t0xBD, 0xC4, 0x7F, 0x3D, 0xB1, 0xD1, 0xCB, 0x89, 0x8D, 0x5C, 0x4F, 0x6C,\n\t0x0C, 0x5F, 0xE2, 0xCB, 0xF1, 0xE5, 0xD8, 0xDF, 0x6F, 0xC0, 0x32, 0xCD,\n\t0x81, 0x8D, 0x60, 0xE3, 0xDF, 0x1B, 0xDD, 0x34, 0xA7, 0xB3, 0x97, 0x73,\n\t0xB8, 0x63, 0xC7, 0xC6, 0x31, 0xE9, 0xD7, 0x53, 0xC7, 0x97, 0x5E, 0x94,\n\t0xC4, 0xF1, 0x62, 0x7C, 0x92, 0x11, 0x3C, 0x11, 0x39, 0xEC, 0xF2, 0x06,\n\t0x7D, 0x27, 0xED, 0x7E, 0x6F, 0x90, 0xC7, 0x9D, 0x98, 0x8E, 0xC0, 0x35,\n\t0x50, 0xDC, 0x06, 0xFA, 0xD0, 0x08, 0xE5, 0xA0, 0x91, 0x3E, 0x91, 0xD8,\n\t0x48, 0x6A, 0xA4, 0xD7, 0x88, 0xEA, 0xF4, 0x96, 0xCD, 0x6E, 0xC4, 0xC6,\n\t0xF4, 0x15, 0x9B, 0x81, 0x5F, 0xA8, 0x46, 0xD2, 0x88, 0x2A, 0xC3, 0x54,\n\t0x08, 0x55, 0x76, 0xBF, 0x68, 0xF1, 0x46, 0x54, 0xFF, 0x59, 0x2C, 0xF9,\n\t0x37, 0x93, 0xAC, 0x5A, 0x39, 0x9A, 0x5A, 0x5F, 0xCD, 0x5B, 0xBE, 0x62,\n\t0xD1, 0x26, 0x92, 0x29, 0x98, 0x7E, 0x34, 0x37, 0xFD, 0x8E, 0xBF, 0x22,\n\t0x3B, 0x92, 0x29, 0x77, 0xBC, 0x17, 0x6D, 0x27, 0x32, 0xE5, 0xF4, 0xA5,\n\t0x2B, 0x7A, 0xA7, 0x15, 0xFF, 0x13, 0x77, 0xAE, 0x9C, 0xC2, 0x9D, 0xE7,\n\t0x0F, 0x8C, 0x2A, 0x72, 0xA8, 0x9A, 0x9F, 0x82, 0x4F, 0xDC, 0x4D, 0xCD,\n\t0x61, 0xCE, 0x96, 0x7F, 0x53, 0x47, 0x98, 0x7C, 0x99, 0x53, 0x4A, 0x4B,\n\t0x06, 0xB7, 0xFC, 0xC1, 0x4E, 0x5E, 0x29, 0x3E, 0x2C, 0x47, 0xEF, 0x1C,\n\t0x7F, 0x63, 0xFD, 0x3E, 0x67, 0x8A, 0x2F, 0x4F, 0xD9, 0xDB, 0xB1, 0x94,\n\t0xA3, 0xE9, 0xA0, 0xAF, 0x7C, 0xC6, 0x9F, 0x9E, 0x2C, 0xC1, 0xAA, 0x78,\n\t0xD6, 0xCE, 0x96, 0xA9, 0xD8, 0xAC, 0x4A, 0xBF, 0x30, 0x7E, 0xE2, 0x72,\n\t0xEC, 0x48, 0xBB, 0x9E, 0x2D, 0x93, 0x3D, 0x56, 0x0C, 0x69, 0x7E, 0xEA,\n\t0x2F, 0x8C, 0x8D, 0x7A, 0x97, 0x72, 0x39, 0x35, 0x77, 0x98, 0x7E, 0x3B,\n\t0xDB, 0xE9, 0x5A, 0x8D, 0x33, 0x29, 0x48, 0x0E, 0x91, 0x89, 0x81, 0xC1,\n\t0x2D, 0x22, 0xC6, 0xE2, 0x1D, 0xB2, 0x89, 0xE2, 0xC5, 0xE2, 0x8F, 0x78,\n\t0x66, 0xF1, 0x58, 0xFC, 0x4C, 0x11, 0x93, 0xA2, 0x67, 0x8E, 0x23, 0xF8,\n\t0x6D, 0xD3, 0xC6, 0x67, 0xAE, 0xBB, 0xDB, 0x5D, 0xFB, 0x4C, 0xAF, 0x04,\n\t0x13, 0xB9, 0x9F, 0x6C, 0xBE, 0x05, 0x75, 0xFF, 0x9F, 0x72, 0x67, 0x6E,\n\t0x21, 0xDF, 0x5E, 0xD0, 0x69, 0xC7, 0x02, 0xFE, 0xA7, 0x25, 0x33, 0xE3,\n\t0xF0, 0xE4, 0x0B, 0x93, 0x1D, 0x67, 0x07, 0x57, 0x32, 0xFC, 0xEE, 0x66,\n\t0x5D, 0xB3, 0xD2, 0xC6, 0x69, 0x13, 0xE6, 0x6F, 0x4C, 0xCA, 0x73, 0x1A,\n\t0x83, 0x2F, 0x05, 0xD4, 0x04, 0xDA, 0xA0, 0x82, 0x17, 0x0A, 0x64, 0x11,\n\t0xF3, 0x49, 0xC2, 0x72, 0xC4, 0x17, 0xB0, 0x00, 0x81, 0xC9, 0x56, 0x76,\n\t0xC9, 0x14, 0x71, 0x66, 0xCD, 0xF1, 0x66, 0xB5, 0x7C, 0xF6, 0xF2, 0x32,\n\t0x3C, 0x58, 0xF8, 0xE9, 0xFB, 0xE5, 0xFE, 0x9C, 0x59, 0x86, 0x38, 0xCA,\n\t0x8F, 0x88, 0xB2, 0x7B, 0xE9, 0x88, 0x12, 0xFF, 0x6F, 0x56, 0x0D, 0x09,\n\t0xDE, 0xC0, 0x37, 0x9E, 0xE9, 0xBD, 0x71, 0xFA, 0x1B, 0x5F, 0x59, 0x59,\n\t0x59, 0xA1, 0xE4, 0x85, 0xC4, 0xD0, 0x19, 0x31, 0xB4, 0x25, 0xC8, 0x0D,\n\t0x12, 0x24, 0xC8, 0x9F, 0x5D, 0xFC, 0x04, 0x2B, 0xAC, 0xD0, 0x81, 0x77,\n\t0x1A, 0x11, 0xD2, 0xD4, 0x25, 0xB4, 0xCF, 0x99, 0xD9, 0xEC, 0xF1, 0x5F,\n\t0x99, 0x3F, 0x9A, 0xD6, 0xE8, 0xB9, 0x52, 0x38, 0xEC, 0xF9, 0x1D, 0x48,\n\t0xAC, 0x95, 0x60, 0xFF, 0x37, 0xB3, 0xB4, 0xC9, 0x37, 0x2F, 0x11, 0x44,\n\t0x8A, 0x8E, 0xF3, 0x5E, 0x19, 0x0A, 0x7D, 0x3D, 0x7E, 0x07, 0x5A, 0x72,\n\t0x89, 0xFE, 0x77, 0x7D, 0x8E, 0x24, 0xB4, 0x28, 0xC6, 0x71, 0x55, 0xD0,\n\t0x75, 0x1C, 0x58, 0xCE, 0x2D, 0x73, 0x5E, 0x66, 0xD0, 0xCA, 0x54, 0xEC,\n\t0x45, 0x4E, 0x91, 0xD1, 0xBE, 0x02, 0x92, 0xD1, 0x01, 0xDC, 0x3A, 0x22,\n\t0x78, 0x69, 0xCA, 0xB9, 0xD8, 0x48, 0x57, 0x3F, 0x25, 0x59, 0xEA, 0x22,\n\t0x83, 0x2D, 0xA3, 0xBD, 0xC0, 0xFE, 0x50, 0xFC, 0xB8, 0x33, 0xE8, 0xE6,\n\t0xF9, 0xE6, 0x9A, 0xE0, 0x07, 0x65, 0xF8, 0xDF, 0xAC, 0x2D, 0x74, 0xAD,\n\t0xB3, 0x59, 0xE8, 0x72, 0x71, 0x78, 0xCA, 0xD2, 0x2C, 0xC1, 0x6F, 0xE7,\n\t0x8F, 0x63, 0xF6, 0x93, 0xE8, 0xA2, 0x07, 0x2C, 0x2C, 0x51, 0x85, 0x2F,\n\t0x50, 0xC1, 0xE5, 0x40, 0x76, 0x09, 0xA6, 0x17, 0x47, 0xA7, 0xB9, 0x52,\n\t0xC3, 0x5A, 0x56, 0x84, 0xE5, 0x34, 0x02, 0xFF, 0xAB, 0x48, 0x13, 0x4E,\n\t0x9A, 0xE9, 0x6F, 0xA0, 0x87, 0xCE, 0xEC, 0x33, 0x4C, 0x6F, 0xBE, 0xDB,\n\t0xD2, 0xAE, 0xE4, 0xB1, 0xF4, 0x03, 0xFF, 0x3D, 0x08, 0x86, 0x08, 0xC0,\n\t0x18, 0x58, 0xE0, 0xBD, 0x96, 0x0C, 0xD9, 0x81, 0x0D, 0x94, 0xD0, 0x83,\n\t0x16, 0x5B, 0x28, 0x72, 0x30, 0x86, 0xA5, 0x23, 0xAB, 0x78, 0xC1, 0x5E,\n\t0x66, 0xAB, 0xF6, 0xE0, 0x1A, 0x5B, 0x65, 0x4A, 0x35, 0xDE, 0x2A, 0x52,\n\t0x63, 0x0F, 0x3D, 0x56, 0x51, 0xD3, 0x03, 0x98, 0xEF, 0xAB, 0xA8, 0x19,\n\t0x8F, 0x7B, 0x00, 0x47, 0x5C, 0xBF, 0x13, 0x06, 0xDF, 0x9A, 0x79, 0xA7,\n\t0x76, 0x92, 0xF5, 0x9A, 0x69, 0xDC, 0x59, 0xE2, 0x69, 0x4C, 0xBB, 0xEC,\n\t0x7F, 0x77, 0x76, 0x3C, 0x37, 0x14, 0xFE, 0xBD, 0x63, 0x5B, 0xD4, 0x9F,\n\t0xE1, 0x95, 0xF1, 0x26, 0xE5, 0x26, 0xE5, 0xA4, 0x2C, 0x37, 0x29, 0x37,\n\t0x60, 0xCA, 0x89, 0x10, 0x9E, 0xE6, 0xB7, 0x46, 0xDD, 0x6E, 0xCD, 0xCC,\n\t0xEC, 0x35, 0x4C, 0x8F, 0x9F, 0x1D, 0x81, 0x04, 0x17, 0x4B, 0x87, 0x0D,\n\t0x6A, 0x82, 0xD4, 0xD4, 0x60, 0x04, 0xA1, 0x0E, 0x0E, 0x1A, 0x97, 0x08,\n\t0x32, 0x26, 0x3E, 0x90, 0x4D, 0x00, 0x04, 0x59, 0x04, 0x40, 0x50, 0xE6,\n\t0x28, 0xE2, 0x2D, 0x06, 0xD0, 0x89, 0xA9, 0xE1, 0x32, 0xD1, 0xE1, 0x6B,\n\t0x59, 0x39, 0x64, 0x15, 0x0E, 0x4D, 0x94, 0x39, 0xD0, 0xF0, 0x53, 0x02,\n\t0xAE, 0x94, 0x31, 0xF0, 0xC0, 0x08, 0x4B, 0xB4, 0x4C, 0x32, 0x02, 0xE5,\n\t0x4D, 0x08, 0x92, 0x40, 0x22, 0x07, 0x04, 0x80, 0xFC, 0x99, 0x0B, 0xC7,\n\t0x05, 0x28, 0x60, 0xC4, 0x04, 0x1C, 0xF0, 0x32, 0x04, 0xB6, 0x48, 0x78,\n\t0x10, 0x78, 0x80, 0x11, 0x08, 0x28, 0x62, 0x5B, 0x40, 0x01, 0x3C, 0x08,\n\t0x1C, 0x40, 0x08, 0x16, 0x21, 0x4A, 0x2A, 0x39, 0x80, 0x08, 0xC0, 0x0F,\n\t0x34, 0x6A, 0x0F, 0x47, 0xA2, 0xEC, 0x64, 0xF4, 0xD0, 0x3A, 0x8A, 0xA5,\n\t0x26, 0x5C, 0x0B, 0x2B, 0x51, 0xA2, 0x95, 0x22, 0x07, 0x09, 0x94, 0xDD,\n\t0xEF, 0x06, 0xD7, 0x16, 0x50, 0xB0, 0x65, 0x0E, 0x22, 0x88, 0x5A, 0xF6,\n\t0x3A, 0xA4, 0xFF, 0x53, 0x40, 0x51, 0x05, 0x6A, 0x07, 0x0C, 0x8E, 0x90,\n\t0xE1, 0x88, 0x4D, 0x55, 0xA0, 0x7A, 0x60, 0x0D, 0x6A, 0xF8, 0x51, 0xDE,\n\t0xFF, 0x6F, 0x07, 0xBD, 0xC7, 0x55, 0x4C, 0xEC, 0x68, 0xE9, 0x83, 0x47,\n\t0x0D, 0x48, 0x7F, 0x70, 0xE7, 0x28, 0xD3, 0xD1, 0x1B, 0x03, 0x83, 0xA9,\n\t0x77, 0xAE, 0x4E, 0xA0, 0x96, 0xF1, 0x96, 0xF7, 0xD2, 0xCF, 0xAC, 0x62,\n\t0x80, 0x2F, 0xB7, 0x7C, 0xCB, 0x4A, 0x7F, 0x96, 0xEE, 0xF7, 0x61, 0xFF,\n\t0x02, 0x79, 0x94, 0x3B, 0xAB, 0x18, 0x2F, 0x9D, 0x42, 0x20, 0xE5, 0xF5,\n\t0x3C, 0x26, 0xF0, 0xA0, 0x0E, 0x74, 0xA1, 0xC8, 0x8C, 0x1F, 0x10, 0xA1,\n\t0xC8, 0x07, 0x52, 0x5C, 0xA4, 0xE1, 0x0D, 0x59, 0xE8, 0xA6, 0x14, 0xB8,\n\t0x0F, 0xD5, 0xCB, 0xB0, 0xD9, 0x37, 0x93, 0x67, 0x59, 0x1C, 0x42, 0xCF,\n\t0xFE, 0xD6, 0x81, 0x81, 0x9E, 0xC2, 0xA7, 0x27, 0xDB, 0xCC, 0x42, 0xF0,\n\t0xFD, 0x8C, 0x85, 0xEA, 0x12, 0x11, 0x4D, 0x96, 0x4C, 0x14, 0xBE, 0x3D,\n\t0x7D, 0x73, 0x3E, 0xF9, 0x92, 0xDC, 0x4F, 0x36, 0xB3, 0xEF, 0x30, 0xA8,\n\t0x1F, 0xE8, 0xF8, 0x3F, 0x88, 0x23, 0xE3, 0x98, 0xA8, 0xFB, 0xAC, 0x51,\n\t0xA5, 0xD3, 0x88, 0x97, 0x38, 0xF6, 0x5D, 0xB2, 0x34, 0x3A, 0x19, 0xB6,\n\t0x3A, 0xF3, 0xBF, 0x13, 0xF5, 0x32, 0x28, 0x49, 0x45, 0x95, 0x99, 0x77,\n\t0x9E, 0xD4, 0x7D, 0xA0, 0xDF, 0xDB, 0x89, 0x40, 0x54, 0x3E, 0xE5, 0x66,\n\t0x55, 0x34, 0xA6, 0x65, 0x13, 0x3F, 0x36, 0x35, 0x3A, 0x98, 0xBF, 0x39,\n\t0x11, 0x56, 0x14, 0x83, 0xB5, 0x98, 0x17, 0x2C, 0x08, 0x03, 0xCF, 0x13,\n\t0x2F, 0x26, 0x28, 0x40, 0x00, 0x25, 0x7A, 0x20, 0x91, 0x63, 0x85, 0x01,\n\t0x15, 0x87, 0x77, 0x63, 0x00, 0xA0, 0xB6, 0xA2, 0x09, 0x11, 0x82, 0xAB,\n\t0x01, 0xE0, 0x03, 0x6D, 0xE8, 0x11, 0xC6, 0x1A, 0x04, 0x70, 0x06, 0x0D,\n\t0x94, 0xC1, 0x0B, 0x20, 0xB8, 0x70, 0x81, 0x24, 0x5A, 0xF8, 0x41, 0x0A,\n\t0x14, 0x78, 0x21, 0x81, 0xA9, 0x36, 0xB8, 0x78, 0xC1, 0x01, 0x90, 0x24,\n\t0xA2, 0xC8, 0x41, 0x6A, 0x40, 0x3C, 0x19, 0x61, 0xAA, 0xD1, 0x82, 0x22,\n\t0x56, 0x10, 0xA6, 0x98, 0x00, 0x87, 0x0E, 0x1A, 0x1E, 0x9C, 0x40, 0x80,\n\t0x07, 0x3A, 0x40, 0x80, 0xDA, 0xC9, 0xAC, 0x64, 0x03, 0x28, 0x22, 0xBB,\n\t0x91, 0x55, 0x38, 0x04, 0xD1, 0xD2, 0x91, 0x42, 0x91, 0x18, 0x13, 0xD4,\n\t0x03, 0x00, 0xBD, 0x3E, 0x50, 0xEE, 0x0E, 0x29, 0x6F, 0xE0, 0xE1, 0xC4,\n\t0x02, 0x67, 0xA2, 0xB4, 0x56, 0x92, 0xE0, 0xC2, 0x81, 0x85, 0xC9, 0x15,\n\t0xAE, 0x15, 0x1E, 0x8C, 0x6E, 0x85, 0x4B, 0xE6, 0x16, 0x0A, 0xDA, 0xFD,\n\t0xE4, 0x27, 0x59, 0xF6, 0xEC, 0x2B, 0x2C, 0x93, 0xA3, 0x94, 0x6E, 0x8E,\n\t0x90, 0x0C, 0xD6, 0x90, 0xB8, 0x52, 0x9C, 0x90, 0x82, 0x16, 0x11, 0x44,\n\t0x30, 0xC2, 0xA3, 0xB5, 0xDD, 0xD5, 0xA2, 0x55, 0x61, 0x82, 0x16, 0x10,\n\t0xB7, 0xDD, 0x5A, 0x90, 0x22, 0x3E, 0x36, 0x8B, 0x69, 0x6D, 0x46, 0x27,\n\t0xD2, 0x44, 0x33, 0x5A, 0xD5, 0xB4, 0xAA, 0x44, 0x04, 0x75, 0xA0, 0x43,\n\t0xF6, 0xE3, 0x01, 0x36, 0x84, 0x91, 0x81, 0xFA, 0xB3, 0x89, 0x96, 0x8E,\n\t0x16, 0x33, 0x45, 0xD0, 0xF9, 0x91, 0x7C, 0x45, 0xC6, 0x44, 0xCB, 0xC8,\n\t0x1D, 0xAC, 0x88, 0x00, 0x0E, 0x88, 0xD8, 0xC1, 0x06, 0x07, 0x99, 0x02,\n\t0x02, 0x40, 0xED, 0x80, 0x56, 0x8A, 0x04, 0xAE, 0x1C, 0x17, 0x28, 0xA2,\n\t0xBC, 0x05, 0x86, 0x68, 0x75, 0x31, 0x4C, 0xB4, 0xEC, 0x8F, 0x3B, 0x8B,\n\t0x00, 0x8C, 0x02, 0x96, 0xA0, 0x83, 0x03, 0x5A, 0x8C, 0x68, 0xC0, 0x18,\n\t0x2D, 0x05, 0x68, 0xD5, 0x03, 0x18, 0x20, 0x0E, 0xA5, 0x1B, 0xAD, 0x0B,\n\t0xC0, 0xF5, 0x20, 0x82, 0xE8, 0xD6, 0xC4, 0x28, 0x57, 0xB2, 0x1E, 0x02,\n\t0xD0, 0xCA, 0xC1, 0xFF, 0xD3, 0x9F, 0x96, 0x96, 0xBD, 0xC5, 0x4D, 0xD7,\n\t0x50, 0xBE, 0xE0, 0x34, 0xD5, 0xF4, 0x0A, 0xAE, 0x18, 0x4C, 0xB7, 0xA0,\n\t0xFF, 0x53, 0x5A, 0xAD, 0xCF, 0x90, 0x69, 0x4A, 0x45, 0x91, 0xF3, 0xA4,\n\t0x98, 0xE6, 0x61, 0x87, 0xAE, 0x3C, 0x82, 0x0D, 0x32, 0x5A, 0x78, 0x0C,\n\t0x54, 0x38, 0x59, 0x02, 0xA9, 0x75, 0x84, 0x10, 0x5C, 0x31, 0x39, 0x88,\n\t0xA2, 0x4F, 0xFF, 0x8B, 0x4A, 0x1C, 0xEF, 0x70, 0x3F, 0x08, 0x14, 0x7F,\n\t0x6D, 0xB1, 0x74, 0x34, 0xC6, 0x7C, 0x9F, 0xCC, 0x9E, 0x65, 0x2A, 0x38,\n\t0x22, 0xBA, 0x0C, 0x94, 0x6E, 0xF4, 0x6B, 0xD9, 0x7E, 0xA4, 0x1D, 0x01,\n\t0x42, 0xB4, 0xB7, 0xD4, 0x06, 0xEE, 0xB1, 0x23, 0xD9, 0x2D, 0xF9, 0xBE,\n\t0xE7, 0xE0, 0xFF, 0x1F, 0x25, 0x18, 0x35, 0x5F, 0x34, 0x04, 0xA3, 0x8A,\n\t0x5F, 0x4F, 0x3D, 0xBD, 0xC4, 0x23, 0x72, 0x3D, 0xDB, 0x68, 0x02, 0xB9,\n\t0x2F, 0x20, 0x30, 0x20, 0x30, 0xD2, 0xF7, 0x22, 0x79, 0x3D, 0xA4, 0x73,\n\t0x3E, 0x19, 0xFF, 0xA7, 0x10, 0x2E, 0x95, 0xC9, 0xF7, 0x3F, 0x40, 0xBC,\n\t0x9C, 0xE7, 0x30, 0x0C, 0x11, 0xB6, 0x19, 0x8E, 0x69, 0x5F, 0xB3, 0x67,\n\t0x97, 0xEB, 0xB9, 0x92, 0x0F, 0xF1, 0xC2, 0xF6, 0xE6, 0x33, 0x7A, 0xE7,\n\t0x88, 0xF1, 0xC9, 0xD7, 0x68, 0xF7, 0xA1, 0x35, 0x0F, 0xED, 0xF6, 0xF9,\n\t0xF3, 0xFC, 0xCF, 0x88, 0x8D, 0x40, 0xCC, 0x43, 0x57, 0x0F, 0x9A, 0x39,\n\t0xAB, 0xCB, 0xF4, 0x67, 0x5D, 0x88, 0xCF, 0xA8, 0xFF, 0x87, 0x3D, 0x5B,\n\t0x46, 0x39, 0x31, 0xB2, 0x16, 0x68, 0x6A, 0x3E, 0x0D, 0x99, 0xEC, 0xF5,\n\t0x3C, 0xA3, 0x2B, 0x31, 0x32, 0xF7, 0x25, 0x97, 0x87, 0x58, 0xD6, 0x9C,\n\t0xDE, 0xB1, 0xFC, 0x17, 0x34, 0x65, 0x31, 0x06, 0x7D, 0x22, 0x01, 0x62,\n\t0x90, 0x3C, 0x39, 0xA4, 0x46, 0xEF, 0x2F, 0x7A, 0xF4, 0x9B, 0x99, 0xBB,\n\t0xA2, 0xE6, 0xCE, 0x42, 0x45, 0x0A, 0x73, 0xAE, 0x22, 0x7D, 0x21, 0xAF,\n\t0x0C, 0x3D, 0xF4, 0x04, 0xD7, 0xE3, 0x7F, 0x44, 0xF6, 0x35, 0x8E, 0xEC,\n\t0x5E, 0x05, 0xBF, 0x0A, 0xB8, 0x13, 0x91, 0x81, 0xD9, 0x33, 0xC5, 0x59,\n\t0xCD, 0xF4, 0x66, 0x26, 0xE9, 0x99, 0x49, 0xF2, 0xFA, 0x2B, 0x2D, 0x3E,\n\t0x3A, 0x3E, 0xA4, 0xEF, 0x37, 0x0B, 0x3F, 0x1A, 0x9B, 0xEF, 0xD1, 0x24,\n\t0xC0, 0x92, 0xB2, 0xB0, 0xA4, 0x66, 0xC9, 0x40, 0x15, 0x14, 0xE0, 0x01,\n\t0xA0, 0xE0, 0x1A, 0x00, 0x05, 0x4F, 0x00, 0x0A, 0x70, 0xDF, 0xDF, 0x8B,\n\t0x75, 0xBC, 0x56, 0x3C, 0x16, 0xCF, 0x59, 0xEB, 0x9D, 0xDF, 0x3D, 0xF3,\n\t0xA1, 0x2D, 0x07, 0x5D, 0x04, 0x8F, 0xFF, 0x56, 0x09, 0xA2, 0x6F, 0x12,\n\t0xC9, 0xDA, 0x9B, 0x49, 0xDC, 0xE3, 0xFD, 0xCA, 0xFC, 0x07, 0x5D, 0xFB,\n\t0x4E, 0x1D, 0xED, 0xFE, 0x87, 0xBF, 0x24, 0xA3, 0xE1, 0x1B, 0xF5, 0x74,\n\t0x6F, 0xD8, 0xD3, 0x39, 0x9E, 0xFF, 0x37, 0x36, 0xB1, 0x57, 0x21, 0xFC,\n\t0xB2, 0x85, 0xEE, 0xCB, 0xC5, 0xDB, 0xFF, 0xA5, 0x8E, 0xA7, 0x96, 0xE5,\n\t0xBF, 0x67, 0x05, 0xCD, 0xC6, 0x05, 0xC7, 0x4B, 0xDC, 0xDE, 0x36, 0xF8,\n\t0xDF, 0x28, 0x5E, 0xCE, 0x43, 0xA1, 0x5A, 0x55, 0x1A, 0x07, 0x36, 0xDA,\n\t0xDB, 0x36, 0xEC, 0x39, 0xA5, 0x3F, 0x68, 0xD6, 0x4B, 0x61, 0x49, 0xD6,\n\t0x7E, 0x39, 0xBF, 0xB7, 0xE7, 0x6E, 0x50, 0x28, 0xF4, 0x37, 0x14, 0x35,\n\t0x04, 0xC2, 0xB4, 0x5A, 0xC9, 0x93, 0xBF, 0x64, 0xE9, 0xD7, 0xE3, 0x41,\n\t0x0D, 0x9A, 0x21, 0xAF, 0xE7, 0x40, 0xF4, 0x9E, 0x93, 0x40, 0x0D, 0x9D,\n\t0x03, 0x4D, 0xED, 0xE4, 0xA9, 0x28, 0x20, 0xAC, 0xDE, 0x73, 0x03, 0xCD,\n\t0xCA, 0x81, 0xF1, 0xB1, 0xCF, 0x97, 0x16, 0xC6, 0x6C, 0x07, 0xC2, 0x42,\n\t0x59, 0x9E, 0xE9, 0xAC, 0xBB, 0xA7, 0xFD, 0x53, 0x3C, 0x96, 0xAE, 0x09,\n\t0x77, 0x57, 0xBB, 0xE0, 0x8A, 0x76, 0xF0, 0x2C, 0xAE, 0xBC, 0x08, 0x76,\n\t0xE0, 0x7F, 0xBF, 0x42, 0x38, 0xE6, 0x2C, 0xDA, 0xD9, 0xEC, 0xBE, 0xD8,\n\t0xD1, 0x3B, 0x0C, 0xA2, 0xFF, 0xAC, 0xB3, 0x6A, 0x76, 0xFC, 0xB3, 0xBA,\n\t0x7B, 0x56, 0xB9, 0x23, 0x99, 0x72, 0x5D, 0x88, 0x2B, 0xD6, 0xE9, 0x33,\n\t0x42, 0xA8, 0xDE, 0xA4, 0x0D, 0xA9, 0x83, 0x85, 0xAE, 0x85, 0xBD, 0x40,\n\t0x24, 0x36, 0xA2, 0xA6, 0xA9, 0xBB, 0x42, 0x9E, 0x39, 0xC4, 0x45, 0xA2,\n\t0xD1, 0x22, 0xFD, 0x6B, 0x55, 0xB5, 0x34, 0x54, 0xA1, 0x21, 0x2A, 0x12,\n\t0x8D, 0x14, 0xE9, 0x76, 0x0D, 0x93, 0x6C, 0xD9, 0x67, 0x56, 0xAF, 0x43,\n\t0xAC, 0x16, 0xED, 0xBF, 0xDD, 0xE9, 0x9D, 0xB9, 0xF8, 0x7C, 0x85, 0xEE,\n\t0x7F, 0x16, 0xD8, 0x39, 0x29, 0xA6, 0x77, 0x39, 0x50, 0xB0, 0xD6, 0xA6,\n\t0xCB, 0xD2, 0x19, 0xBF, 0x63, 0xC5, 0xB3, 0x5A, 0x50, 0x2E, 0x78, 0x85,\n\t0x16, 0x71, 0xA9, 0x2A, 0x72, 0xCF, 0x26, 0x9C, 0x7E, 0xBE, 0xFB, 0x2A,\n\t0xC9, 0x88, 0x4D, 0x51, 0x68, 0x85, 0xEE, 0x0E, 0xEF, 0x5A, 0xA3, 0x4B,\n\t0xAA, 0x88, 0xCA, 0x2D, 0xC2, 0x75, 0x8A, 0xF4, 0x3E, 0x85, 0xA5, 0xCE,\n\t0x8F, 0xCF, 0x33, 0xCF, 0xFD, 0x45, 0x5C, 0x0C, 0xE5, 0x90, 0x12, 0x4F,\n\t0xDA, 0x8C, 0x1C, 0x6B, 0xF4, 0x28, 0xE7, 0x85, 0x48, 0x57, 0xAA, 0x1F,\n\t0x07, 0x9B, 0x08, 0x55, 0xED, 0x54, 0xFD, 0xCB, 0x90, 0xF9, 0xD2, 0x14,\n\t0x96, 0xA8, 0xCF, 0x43, 0x62, 0x63, 0x4F, 0xAA, 0x44, 0xEE, 0xFC, 0x11,\n\t0x14, 0xA6, 0xC2, 0x8A, 0xE8, 0x4D, 0x15, 0x2B, 0xBD, 0xB1, 0x26, 0x0E,\n\t0xC9, 0x47, 0xFA, 0x16, 0x7F, 0xC5, 0x45, 0xE4, 0x4D, 0xE8, 0x3B, 0x6D,\n\t0xEA, 0xED, 0x1F, 0xFE, 0xE8, 0xB0, 0x05, 0x9D, 0xE8, 0x9B, 0x22, 0xA5,\n\t0x7A, 0x3B, 0x36, 0x44, 0xDC, 0x17, 0x2D, 0x59, 0xC3, 0x09, 0x43, 0xC5,\n\t0x7F, 0x7E, 0x69, 0x8C, 0xF1, 0x73, 0x59, 0x6B, 0x73, 0x3A, 0x55, 0x9D,\n\t0x38, 0xD4, 0x47, 0x73, 0x65, 0xF3, 0x97, 0xF8, 0xDB, 0x87, 0x67, 0x88,\n\t0xA4, 0x49, 0xB4, 0xCD, 0xD3, 0xE7, 0x43, 0x3B, 0xBA, 0x7A, 0xE5, 0xDB,\n\t0xEE, 0xA5, 0x63, 0x23, 0x2A, 0x52, 0xAF, 0xCA, 0xD3, 0x4B, 0x49, 0xC4,\n\t0x73, 0x66, 0x2E, 0xA5, 0xF2, 0x16, 0xB9, 0x43, 0x21, 0xA4, 0x7E, 0xAA,\n\t0x12, 0x3F, 0x1B, 0x94, 0x6B, 0xA5, 0x57, 0xE6, 0xC0, 0xA8, 0x23, 0x0D,\n\t0xCD, 0x21, 0xBA, 0x67, 0x7C, 0xB9, 0x31, 0xEA, 0xC3, 0xB3, 0xFC, 0xCA,\n\t0xFB, 0x9F, 0xFC, 0x45, 0xD0, 0x16, 0xC1, 0x2F, 0xE2, 0x71, 0x3A, 0x4A,\n\t0xE6, 0x09, 0xF7, 0x41, 0x24, 0x2A, 0xD2, 0xC9, 0x16, 0xCF, 0x48, 0x8A,\n\t0x74, 0xEE, 0x04, 0x4D, 0xA2, 0xB4, 0x25, 0x9F, 0xAB, 0x23, 0xF8, 0x99,\n\t0xA2, 0x26, 0x79, 0x5D, 0x24, 0x6C, 0xBA, 0x82, 0x4C, 0xCE, 0x20, 0x7B,\n\t0xA6, 0xCC, 0x9D, 0xF7, 0x4E, 0x28, 0xC0, 0xAE, 0x62, 0x1B, 0xBA, 0xDF,\n\t0xFE, 0xAD, 0x5F, 0xDA, 0x44, 0x21, 0x17, 0x4D, 0x65, 0x49, 0x5A, 0x47,\n\t0x15, 0x2D, 0x65, 0x4F, 0xD6, 0x91, 0x6A, 0xFD, 0xFE, 0xF3, 0x9F, 0x6D,\n\t0x05, 0x3F, 0xA2, 0xFF, 0xFD, 0x10, 0x24, 0xAF, 0x0F, 0x74, 0xAD, 0x83,\n\t0xFA, 0x36, 0x63, 0x3E, 0xF8, 0x26, 0x1D, 0xDC, 0x4E, 0xC2, 0xFF, 0x29,\n\t0x60, 0xED, 0x1C, 0x56, 0x34, 0x46, 0xD9, 0x98, 0xED, 0xA2, 0x2A, 0x0E,\n\t0x7E, 0xCC, 0xA1, 0x8E, 0x83, 0x7E, 0x8C, 0x08, 0x67, 0xD2, 0xEB, 0x9B,\n\t0xF4, 0x2E, 0x06, 0x06, 0xB3, 0x68, 0x2A, 0x97, 0xD5, 0x5D, 0xAD, 0x63,\n\t0x55, 0x13, 0xDA, 0x5D, 0x03, 0x3B, 0x15, 0x2B, 0xD5, 0xF5, 0xA6, 0xF2,\n\t0xC4, 0xC7, 0xEE, 0xF0, 0xF6, 0x16, 0xCD, 0xDC, 0xB8, 0x92, 0xBE, 0x49,\n\t0x65, 0xDA, 0xDD, 0x8D, 0x03, 0xE3, 0x41, 0xCD, 0x82, 0xD9, 0x58, 0xCE,\n\t0x5A, 0xD9, 0x38, 0x09, 0x3C, 0x88, 0xEC, 0x62, 0x28, 0x7E, 0xF6, 0x8E,\n\t0x85, 0x9E, 0x85, 0x45, 0x60, 0x97, 0x5D, 0x4E, 0x15, 0x93, 0xE7, 0x84,\n\t0x75, 0x45, 0xA7, 0x54, 0xE6, 0x84, 0x96, 0x60, 0x19, 0xCE, 0xAB, 0xD6,\n\t0x7B, 0x8B, 0x98, 0x71, 0x4D, 0x51, 0xAF, 0x0F, 0xA5, 0x9F, 0x81, 0xCD,\n\t0xB0, 0x22, 0x86, 0x89, 0x65, 0x57, 0xE5, 0x53, 0xFF, 0x62, 0xD2, 0x55,\n\t0x55, 0x57, 0xE8, 0xEF, 0xEF, 0x72, 0xFF, 0xEF, 0x24, 0xE2, 0x65, 0x0B,\n\t0xF3, 0x38, 0x35, 0x15, 0x93, 0x83, 0x31, 0x9D, 0xAA, 0xEF, 0xFA, 0x19,\n\t0x5C, 0x7F, 0x50, 0x23, 0x4B, 0x66, 0x7E, 0x89, 0xF9, 0x5D, 0xF0, 0x66,\n\t0x12, 0xEE, 0x90, 0x3E, 0x73, 0x0A, 0xAF, 0x7C, 0x97, 0x09, 0x71, 0xA2,\n\t0x72, 0x3D, 0x56, 0x0B, 0xD5, 0x44, 0x6F, 0x6A, 0x55, 0xE1, 0x72, 0xB6,\n\t0x91, 0xA6, 0xD4, 0x3A, 0x73, 0x93, 0x10, 0x4E, 0x63, 0x13, 0xC2, 0x87,\n\t0xA4, 0xBC, 0xDE, 0xBC, 0xBE, 0x01, 0x55, 0xAD, 0x0D, 0xC2, 0xE7, 0x89,\n\t0x88, 0x8C, 0x09, 0xE8, 0x24, 0x52, 0xE3, 0x92, 0x35, 0x58, 0x4E, 0xEF,\n\t0x79, 0xD0, 0x6B, 0xFC, 0xC4, 0x49, 0x60, 0xCB, 0x4D, 0xA4, 0x9A, 0xAE,\n\t0x79, 0xBA, 0xF9, 0xED, 0x14, 0xF6, 0xD8, 0x4E, 0xF8, 0xFE, 0xDE, 0x9F,\n\t0x91, 0x12, 0xD9, 0x4C, 0xB1, 0xD3, 0xD5, 0x56, 0x2F, 0xD3, 0xC1, 0x77,\n\t0xD9, 0xCA, 0x3C, 0x3D, 0x8B, 0xB0, 0x64, 0x61, 0x9D, 0x72, 0x30, 0xB1,\n\t0x75, 0xBA, 0x29, 0x3E, 0x34, 0x75, 0x4E, 0x16, 0x56, 0x6C, 0x04, 0x3F,\n\t0x2B, 0x5C, 0xF3, 0x4C, 0x21, 0xDC, 0x67, 0x61, 0x18, 0xFF, 0xC2, 0xA8,\n\t0x5E, 0x4E, 0x15, 0xE9, 0x14, 0xB6, 0xCC, 0x63, 0x55, 0x3A, 0x82, 0x97,\n\t0x7E, 0x56, 0xA8, 0x2B, 0x1A, 0xD7, 0x73, 0xEF, 0x14, 0xCF, 0xAA, 0xEF,\n\t0x4E, 0xE9, 0xFF, 0x90, 0x3B, 0x5B, 0xC6, 0x95, 0x6B, 0x7F, 0xC6, 0x58,\n\t0xB5, 0x96, 0x1B, 0xB2, 0x8D, 0xD5, 0xFE, 0x76, 0xAC, 0xD6, 0x65, 0x34,\n\t0x9D, 0x54, 0x6E, 0x3A, 0xE1, 0x7E, 0x36, 0x9D, 0x4C, 0xF4, 0x27, 0xD0,\n\t0x94, 0x31, 0xC5, 0xE4, 0x9C, 0x3F, 0x33, 0x49, 0x79, 0xAF, 0xCF, 0x95,\n\t0xDC, 0x79, 0xA2, 0xFE, 0xE2, 0xE8, 0xE5, 0xFE, 0xEE, 0xFE, 0xDA, 0xCF,\n\t0xA9, 0x4C, 0x53, 0x24, 0x3B, 0x3B, 0xB6, 0x48, 0x02, 0x12, 0x6A, 0x84,\n\t0x40, 0xB1, 0x70, 0xD1, 0x50, 0x1F, 0x50, 0x80, 0xF6, 0x80, 0xF2, 0x00,\n\t0x06, 0xA4, 0x37, 0x78, 0xA1, 0x3B, 0x34, 0x40, 0x75, 0xD0, 0x90, 0xC0,\n\t0x89, 0x1C, 0x1D, 0xE0, 0x80, 0x08, 0x2A, 0x60, 0x04, 0xA5, 0x40, 0x0C,\n\t0x08, 0x92, 0x60, 0x00, 0x45, 0x82, 0xE6, 0x48, 0x40, 0xE6, 0x04, 0x65,\n\t0x00, 0x02, 0x68, 0x47, 0x5F, 0x80, 0x07, 0x0D, 0xE0, 0x76, 0xC8, 0xF1,\n\t0x3A, 0x9C, 0x0E, 0x77, 0x0E, 0x1D, 0x60, 0x83, 0x00, 0xD6, 0x10, 0xDB,\n\t0x80, 0x19, 0x00, 0x70, 0x2F, 0xC8, 0x90, 0x81, 0x2D, 0xA4, 0x3C, 0xC9,\n\t0xB5, 0xC0, 0x65, 0x4D, 0x5C, 0x0A, 0x28, 0xF7, 0x81, 0x00, 0x5A, 0x1B,\n\t0xB0, 0x34, 0x06, 0x5F, 0x55, 0xE2, 0x78, 0x16, 0x63, 0xBE, 0x06, 0x2E,\n\t0x3B, 0x83, 0x1C, 0x3C, 0x80, 0x38, 0x49, 0xA6, 0x0F, 0xBE, 0xC5, 0xA0,\n\t0xA7, 0xF4, 0x48, 0x89, 0x8A, 0xEC, 0x19, 0x10, 0xE2, 0xB5, 0xFC, 0x9F,\n\t0x76, 0x24, 0xE9, 0xD7, 0x46, 0xBF, 0xE8, 0x55, 0xF4, 0x87, 0xBA, 0x83,\n\t0x97, 0xE2, 0x4B, 0xEF, 0xA5, 0xBF, 0x14, 0xC4, 0x21, 0x8C, 0xB3, 0x8B,\n\t0xB3, 0x63, 0x11, 0x08, 0x1E, 0x83, 0xBF, 0xE0, 0x0F, 0x3E, 0xC3, 0xB6,\n\t0xD6, 0x5A, 0x73, 0xBE, 0xA4, 0xF1, 0xFF, 0x2E, 0xB9, 0xC4, 0x97, 0xFE,\n\t0xEF, 0xDF, 0x80, 0xED, 0x1A, 0xF8, 0x23, 0xF2, 0xF9, 0xDB, 0xF8, 0x49,\n\t0x10, 0x5C, 0x62, 0xC4, 0xC7, 0xFF, 0xEF, 0x0D, 0xFD, 0xFF, 0x4D, 0x69,\n\t0xA1, 0x8E, 0x0E, 0xE1, 0x9B, 0xE0, 0x8B, 0x6C, 0x56, 0xA2, 0xDF, 0x24,\n\t0x12, 0x38, 0x8E, 0x14, 0xE1, 0x65, 0xFC, 0x9F, 0xB5, 0xA6, 0xE4, 0x43,\n\t0x62, 0xB3, 0x44, 0x47, 0xEA, 0x7F, 0xFF, 0x3B, 0x7F, 0x80, 0x5D, 0x0D,\n\t0x61, 0x2B, 0xEA, 0x97, 0x32, 0x8D, 0x25, 0x93, 0x71, 0xE7, 0x93, 0xBC,\n\t0xD4, 0xB2, 0x18, 0x65, 0x2B, 0xE9, 0x72, 0x49, 0xCE, 0x67, 0x09, 0xEA,\n\t0xF5, 0x38, 0x66, 0x96, 0x05, 0x5C, 0x04, 0x8F, 0xC6, 0xFE, 0x2C, 0x59,\n\t0xF2, 0x29, 0x01, 0xC6, 0x8E, 0x1D, 0xFF, 0xFF, 0xD7, 0x68, 0xDA, 0x56,\n\t0xC3, 0xD9, 0xF6, 0x7E, 0x4B, 0xEA, 0xDA, 0xD0, 0x7F, 0x13, 0x43, 0x95,\n\t0xAF, 0x4D, 0x4A, 0xEA, 0x45, 0x31, 0x8C, 0xDE, 0x16, 0xBF, 0x9E, 0x67,\n\t0x72, 0xE5, 0xCA, 0xBE, 0x82, 0x65, 0xCA, 0xC5, 0x4E, 0xA4, 0x47, 0xF3,\n\t0x91, 0x72, 0xA6, 0xF8, 0xD5, 0x99, 0xAD, 0x90, 0x2F, 0x8D, 0x9A, 0x9F,\n\t0x18, 0x37, 0xE7, 0x99, 0xBC, 0x4B, 0xF3, 0x7A, 0x5E, 0x4F, 0x4B, 0xED,\n\t0x95, 0x85, 0x34, 0x1F, 0x79, 0x47, 0xDE, 0x2D, 0x8D, 0x6B, 0xFB, 0x32,\n\t0x28, 0x89, 0xC6, 0xD1, 0xDC, 0x04, 0x6A, 0x33, 0x2C, 0x55, 0xBC, 0x60,\n\t0x2F, 0x73, 0x6C, 0x89, 0x5C, 0xAE, 0x58, 0x8E, 0xA1, 0x4F, 0x96, 0x12,\n\t0x89, 0x2A, 0xB7, 0x87, 0xA6, 0xB7, 0x8A, 0x1A, 0x91, 0x48, 0x2F, 0xF7,\n\t0x42, 0xAE, 0x60, 0xFB, 0x99, 0xE2, 0xB5, 0x18, 0xB3, 0x68, 0x60, 0x77,\n\t0xAD, 0xE8, 0xC1, 0xAE, 0x78, 0x7A, 0x4F, 0xA5, 0xAC, 0xDB, 0x7C, 0x31,\n\t0x73, 0x28, 0x9B, 0xC3, 0x9E, 0x7F, 0xB0, 0xD3, 0xED, 0x4A, 0xF1, 0xA8,\n\t0x8B, 0x4D, 0xB6, 0xB4, 0x0C, 0x5B, 0xED, 0x3E, 0xE3, 0xCC, 0x31, 0xEB,\n\t0xBB, 0xBA, 0xF5, 0xB2, 0x7A, 0xE5, 0x39, 0xF2, 0x50, 0x5C, 0x61, 0x2F,\n\t0xB3, 0x7A, 0xE7, 0xF3, 0x46, 0xBF, 0x97, 0xAD, 0xFF, 0xCD, 0x5E, 0x99,\n\t0x67, 0x52, 0x2E, 0xE7, 0xA2, 0xB7, 0x0F, 0xA5, 0x94, 0xA3, 0x2E, 0x4D,\n\t0x87, 0xBA, 0x5A, 0x65, 0xC5, 0x37, 0xA3, 0x17, 0xAC, 0x37, 0x1F, 0xD3,\n\t0xE8, 0x6F, 0x09, 0xDE, 0x45, 0xF1, 0xBD, 0xB7, 0xA4, 0xF7, 0xE5, 0x4F,\n\t0xC1, 0x7B, 0x4D, 0x1A, 0x05, 0xF3, 0x7D, 0x23, 0x54, 0x2F, 0xFE, 0xEE,\n\t0x3F, 0xA0, 0xFB, 0x2C, 0x57, 0x0E, 0xC4, 0xFF, 0x27, 0x29, 0x73, 0x04,\n\t0x71, 0x01, 0x6B, 0xB2, 0xC0, 0xC9, 0x05, 0x0B, 0x10, 0x21, 0x45, 0x07,\n\t0x99, 0x17, 0xA6, 0x80, 0x42, 0xCA, 0x36, 0xFA, 0xA8, 0xBE, 0xD2, 0x96,\n\t0xAE, 0x43, 0x0F, 0xD1, 0x1E, 0x6A, 0x54, 0x32, 0x90, 0x66, 0x3C, 0x6A,\n\t0x40, 0x10, 0xAC, 0xA9, 0xE1, 0x11, 0xCA, 0xCE, 0xC3, 0x8A, 0x2C, 0x18,\n\t0xCA, 0x6A, 0xEC, 0xE8, 0x96, 0x07, 0x8F, 0x1A, 0xB0, 0x92, 0xAA, 0xB5,\n\t0x35, 0xA0, 0x25, 0x69, 0x40, 0xFA, 0xD2, 0xAB, 0x26, 0x94, 0x81, 0x27,\n\t0xAF, 0xD1, 0xC2, 0x7F, 0x62, 0xF8, 0x50, 0x1E, 0xA1, 0x7F, 0xA1, 0x5A,\n\t0x5D, 0x3E, 0xE2, 0x8B, 0x4F, 0xB7, 0x7A, 0x98, 0x7F, 0x2E, 0xEA, 0xC5,\n\t0x50, 0xAE, 0x75, 0x22, 0x57, 0x37, 0xAA, 0xF8, 0xDF, 0xB0, 0x27, 0xF7,\n\t0x68, 0x6E, 0x53, 0x61, 0xDB, 0xFF, 0xC5, 0x9A, 0xAC, 0xC9, 0x37, 0xF1,\n\t0x06, 0x85, 0x6C, 0xB0, 0x69, 0x9A, 0xF6, 0x4D, 0xE1, 0x62, 0x7B, 0x3B,\n\t0xA7, 0x39, 0x5B, 0x46, 0xE2, 0x84, 0x42, 0xA1, 0x94, 0xCB, 0xAA, 0xBC,\n\t0xCA, 0xFD, 0xED, 0x53, 0xFD, 0x50, 0x96, 0x36, 0x8A, 0x65, 0x39, 0xCA,\n\t0xB6, 0x9D, 0x83, 0x82, 0x47, 0x0D, 0xA8, 0x85, 0xE5, 0x59, 0x24, 0xA5,\n\t0xFF, 0xF1, 0x46, 0xEF, 0xED, 0xC9, 0xDB, 0x4D, 0x3B, 0x7D, 0xF9, 0xC9,\n\t0x76, 0xF4, 0x96, 0xE5, 0x17, 0x3D, 0x48, 0xE5, 0x81, 0x1A, 0x4C, 0x0C,\n\t0x59, 0x4E, 0x93, 0x02, 0xE4, 0xA1, 0xF9, 0xE0, 0x51, 0x03, 0x56, 0xD0,\n\t0x9E, 0xDC, 0x85, 0x26, 0xB3, 0x01, 0xC1, 0x10, 0x97, 0xF3, 0xD3, 0xFF,\n\t0xD7, 0x6C, 0x73, 0xD6, 0x6C, 0xA5, 0x87, 0x70, 0xFD, 0x29, 0xA7, 0x0A,\n\t0xE2, 0xE2, 0x52, 0x2F, 0xE2, 0xB1, 0xF2, 0xF4, 0xE9, 0xB0, 0xC9, 0x2F,\n\t0x99, 0x9A, 0x6B, 0x14, 0x5B, 0x48, 0x4D, 0x05, 0xCF, 0xC5, 0x6C, 0x3E,\n\t0xD5, 0x59, 0xFF, 0xC9, 0xDC, 0x09, 0x52, 0x23, 0x9D, 0x61, 0x23, 0x62,\n\t0x11, 0xD4, 0xC2, 0xE6, 0x33, 0x73, 0x4E, 0xE0, 0xA8, 0xA3, 0xEF, 0xFE,\n\t0xC7, 0x72, 0x7E, 0xA9, 0xB4, 0xAB, 0xD2, 0x74, 0x31, 0x34, 0x45, 0x2C,\n\t0xDA, 0x2D, 0xE2, 0x85, 0xE4, 0x20, 0xC8, 0xD8, 0x53, 0xE6, 0x50, 0xC3,\n\t0x6F, 0xD1, 0xCC, 0xF5, 0x3B, 0x8D, 0xE3, 0xA1, 0xFF, 0x1B, 0x3C, 0xDD,\n\t0xC2, 0xE6, 0xA5, 0xFD, 0xDA, 0x77, 0xFE, 0x4D, 0x71, 0x7D, 0x7B, 0x3A,\n\t0x4A, 0x3A, 0x83, 0x07, 0x41, 0x9E, 0xE9, 0x4B, 0xE6, 0xF8, 0xA5, 0xE0,\n\t0xE6, 0xF4, 0x95, 0xCE, 0xF8, 0x93, 0xFD, 0x9B, 0xA1, 0x93, 0xCD, 0xB0,\n\t0xC9, 0x3E, 0xBA, 0x32, 0x55, 0xF9, 0x2B, 0xD8, 0xF8, 0xD3, 0xFF, 0xF6,\n\t0x0F, 0xCF, 0x7F, 0x3A, 0x6E, 0x46, 0x4F, 0x07, 0x0F, 0xC4, 0x5C, 0xD6,\n\t0xFF, 0xAA, 0xAC, 0x84, 0x01, 0xE1, 0x4E, 0x51, 0x0B, 0x90, 0x1C, 0x9A,\n\t0x40, 0x5E, 0xFA, 0xA1, 0x26, 0x90, 0xD3, 0x19, 0x36, 0x03, 0x92, 0xCA,\n\t0x80, 0x5C, 0x21, 0xB5, 0x3F, 0xE3, 0xD9, 0x38, 0x8E, 0xE3, 0x38, 0xE6,\n\t0x9C, 0xBF, 0x11, 0x6C, 0xC4, 0xC1, 0x46, 0xA5, 0xD0, 0x7D, 0x42, 0xEF,\n\t0x56, 0xA8, 0xFF, 0x32, 0xD4, 0xC1, 0x5E, 0xA6, 0xEB, 0x97, 0xD5, 0x2A,\n\t0x47, 0xAA, 0xA7, 0x46, 0xEF, 0xD1, 0xFF, 0xD7, 0xB8, 0x6B, 0x84, 0x9F,\n\t0xF3, 0x0F, 0x1C, 0x58, 0xBD, 0x19, 0xCE, 0xEB, 0x3F, 0xDF, 0x69, 0xBF,\n\t0xC5, 0x1D, 0x0B, 0xDD, 0x33, 0xF4, 0x3F, 0xE4, 0xD2, 0xDC, 0x4F, 0x56,\n\t0xA1, 0xF4, 0x3C, 0xDD, 0x76, 0x04, 0x39, 0x0E, 0x46, 0xDE, 0x9F, 0xE4,\n\t0x68, 0x7E, 0x5F, 0x6C, 0x39, 0x03, 0xDF, 0x60, 0xBB, 0x3C, 0xD3, 0x3F,\n\t0xFF, 0x07, 0xFB, 0x7E, 0x15, 0xEB, 0xB3, 0x4B, 0x3E, 0xE4, 0xFF, 0xF3,\n\t0xA5, 0x93, 0xF4, 0x4E, 0x17, 0x29, 0xF0, 0xDF, 0xFD, 0xDB, 0xDF, 0x2F,\n\t0x6C, 0x44, 0x3F, 0x05, 0x9F, 0xF1, 0xBB, 0xAF, 0x46, 0x9F, 0xF9, 0x12,\n\t0xFF, 0xD4, 0x93, 0xDE, 0x3C, 0xE8, 0xBB, 0x26, 0xF2, 0xDD, 0x71, 0x9B,\n\t0x95, 0xFF, 0x4D, 0x3A, 0xCB, 0xAA, 0xA3, 0xBF, 0xBB, 0x0A, 0x67, 0x83,\n\t0x5A, 0xD9, 0xA0, 0xF0, 0x45, 0x15, 0xB9, 0x99, 0x66, 0x0F, 0xB2, 0x9C,\n\t0x04, 0x9E, 0x59, 0x46, 0x23, 0x70, 0x74, 0xAA, 0x3A, 0x09, 0x61, 0x27,\n\t0x2E, 0xA5, 0x97, 0x3A, 0x11, 0x5D, 0x96, 0x8F, 0x0C, 0xC6, 0xA8, 0x58,\n\t0x42, 0x97, 0xE2, 0xD0, 0x3F, 0xC5, 0x6B, 0xD3, 0xDA, 0x02, 0x1F, 0xC2,\n\t0xF6, 0xFF, 0x2A, 0x95, 0xA9, 0xD0, 0xD5, 0x8B, 0x74, 0xFC, 0x7A, 0x7A,\n\t0x83, 0x34, 0xD3, 0xFF, 0x29, 0xF9, 0x4C, 0xA5, 0x5F, 0x69, 0xAF, 0x62,\n\t0xF5, 0x33, 0x48, 0x33, 0x5B, 0xFC, 0x70, 0x01, 0x55, 0x40, 0xD0, 0x65,\n\t0xC6, 0xC6, 0xF4, 0xA9, 0x7C, 0x66, 0x5A, 0x27, 0x97, 0xCB, 0x95, 0x27,\n\t0x95, 0xEB, 0x3A, 0xD1, 0xEB, 0x3A, 0x7D, 0xFD, 0x56, 0x16, 0x9A, 0xE2,\n\t0x67, 0x9A, 0xA2, 0xC7, 0xC1, 0x32, 0x67, 0x92, 0xE4, 0x33, 0xF0, 0x7E,\n\t0xE6, 0xB5, 0x11, 0x7F, 0x7B, 0xF4, 0x5A, 0x0B, 0x5B, 0x60, 0x29, 0xF5,\n\t0x76, 0xAA, 0x49, 0xE6, 0x76, 0xAE, 0x9D, 0xDB, 0x22, 0x87, 0x4D, 0xDB,\n\t0x27, 0xC3, 0xFF, 0xEF, 0x55, 0x23, 0x77, 0xFE, 0x27, 0x6F, 0x23, 0x8A,\n\t0xA7, 0xD3, 0x57, 0x66, 0x30, 0xC9, 0x56, 0x35, 0x7C, 0x7F, 0x44, 0x2A,\n\t0x31, 0xDB, 0xC1, 0x13, 0x97, 0xF6, 0x99, 0x31, 0x91, 0x36, 0x8F, 0xE8,\n\t0xDA, 0xD4, 0x76, 0xFA, 0xF2, 0x7D, 0x42, 0x3B, 0xFB, 0x76, 0x2A, 0x2C,\n\t0xD3, 0x12, 0x0F, 0xF9, 0x95, 0xAC, 0x7B, 0xFF, 0x3C, 0xAC, 0xB7, 0xA3,\n\t0x8E, 0x17, 0x6F, 0x8E, 0x46, 0x5F, 0x92, 0xBF, 0xC6, 0x84, 0xAE, 0x68,\n\t0x2B, 0x22, 0x92, 0x45, 0xE4, 0x9D, 0xB4, 0x45, 0xA3, 0x97, 0xBC, 0xA2,\n\t0xD8, 0xE8, 0x1C, 0xA9, 0xDC, 0x18, 0xC9, 0x85, 0xE5, 0x2C, 0x93, 0x0B,\n\t0x9E, 0x24, 0x7A, 0x49, 0x3F, 0xF8, 0x9D, 0x77, 0x39, 0x0B, 0x89, 0x5C,\n\t0x21, 0xD1, 0x4B, 0xC2, 0x9D, 0x41, 0x1B, 0xF9, 0xD2, 0x7E, 0xC0, 0x7F,\n\t0x07, 0xF4, 0x4F, 0xC1, 0x77, 0x33, 0xCF, 0x30, 0x98, 0xDD, 0x9F, 0xEC,\n\t0x47, 0xE4, 0x83, 0xE6, 0x3B, 0x8D, 0x06, 0xEC, 0xF9, 0x2A, 0x7F, 0xA5,\n\t0xAF, 0x28, 0xF0, 0x29, 0xAC, 0xC2, 0xE3, 0x5D, 0x46, 0x83, 0x62, 0x93,\n\t0x5F, 0x88, 0x37, 0xD9, 0x3C, 0x1A, 0xC8, 0xAA, 0xB6, 0xCF, 0x7A, 0x9F,\n\t0x70, 0x0F, 0x29, 0xF1, 0x2B, 0x9E, 0xD3, 0xD5, 0x54, 0xE3, 0xDF, 0x40,\n\t0xE1, 0x99, 0x75, 0xCF, 0xEE, 0x95, 0x2B, 0x36, 0x85, 0x85, 0x5A, 0xDA,\n\t0xFF, 0x4D, 0x0D, 0xA5, 0xFC, 0x41, 0xBF, 0x41, 0xE0, 0x12, 0x36, 0x21,\n\t0xDA, 0x3A, 0x19, 0x2F, 0xA1, 0xCA, 0xF4, 0x2E, 0xF1, 0x93, 0xBF, 0x44,\n\t0x8F, 0xFE, 0x1F, 0x9B, 0x85, 0xAE, 0x51, 0x47, 0x5B, 0x86, 0x62, 0xCB,\n\t0x52, 0x8D, 0x52, 0xEC, 0xB9, 0xF3, 0x66, 0x9B, 0xA2, 0x57, 0x3E, 0xF9,\n\t0xDA, 0x8C, 0xED, 0x8F, 0xEA, 0x2D, 0xBB, 0x11, 0xC1, 0x14, 0xDF, 0x48,\n\t0x78, 0x89, 0xCE, 0xE4, 0x10, 0x3C, 0x72, 0x34, 0x36, 0x08, 0x7D, 0x63,\n\t0x43, 0x9C, 0x08, 0x02, 0x25, 0xFF, 0x9F, 0x95, 0xDD, 0xAC, 0x4A, 0x41,\n\t0x72, 0xB1, 0x7C, 0xD6, 0xFC, 0xC5, 0xDE, 0xA1, 0xBA, 0x25, 0x9B, 0xB1,\n\t0x01, 0x29, 0xBA, 0x5B, 0x48, 0x49, 0xC0, 0x37, 0x09, 0x2A, 0x35, 0x09,\n\t0x3F, 0xD7, 0xA3, 0x5B, 0xD6, 0x21, 0x7C, 0x08, 0x77, 0xD5, 0x1A, 0xFD,\n\t0x43, 0x00, 0x77, 0x6C, 0xA1, 0xCB, 0x22, 0xC3, 0x13, 0xC2, 0x3B, 0xAC,\n\t0xA8, 0x4B, 0x75, 0x94, 0x82, 0xC2, 0xAA, 0x92, 0x0D, 0x8A, 0xEB, 0x4D,\n\t0x8C, 0x51, 0x07, 0xF5, 0x10, 0x96, 0x0C, 0x76, 0x5F, 0xD4, 0x66, 0xA2,\n\t0x47, 0xD5, 0x91, 0x72, 0x47, 0x4C, 0xDC, 0xCB, 0xB1, 0x20, 0x81, 0x23,\n\t0x25, 0x59, 0x4C, 0x5D, 0x4C, 0xF1, 0xBF, 0x73, 0x88, 0x4A, 0xC9, 0x74,\n\t0x75, 0x03, 0x85, 0xCF, 0x58, 0x42, 0xF1, 0x1E, 0x4D, 0x1F, 0x4B, 0x66,\n\t0x0C, 0x28, 0xB8, 0xD4, 0xE9, 0xF6, 0x61, 0xBF, 0xFB, 0xCA, 0x52, 0x0F,\n\t0xC1, 0x81, 0xC5, 0x4B, 0x67, 0x4E, 0x1D, 0xE9, 0xAA, 0xC5, 0x6F, 0xE7,\n\t0xA7, 0xB3, 0x5A, 0xA8, 0xB7, 0xC3, 0x86, 0xF8, 0x2E, 0x07, 0xE5, 0x50,\n\t0xF6, 0xF4, 0x77, 0x62, 0xFE, 0x7C, 0x56, 0x47, 0x46, 0xCF, 0x88, 0x2A,\n\t0xFF, 0x2D, 0x23, 0xD7, 0x37, 0xFF, 0xEB, 0xB3, 0x48, 0x1A, 0x2D, 0x59,\n\t0xA8, 0xE3, 0xF9, 0x4B, 0x01, 0x8B, 0xFE, 0x2D, 0xA2, 0xA7, 0xE3, 0xBF,\n\t0x8D, 0x1F, 0xBF, 0x88, 0xF0, 0x2B, 0x6F, 0x4F, 0x19, 0x4E, 0x12, 0x13,\n\t0xC7, 0xF3, 0xC3, 0x3B, 0x41, 0xCB, 0x89, 0x96, 0xBC, 0x38, 0x71, 0x5D,\n\t0x48, 0xD5, 0x77, 0x4B, 0x67, 0x0F, 0x33, 0x95, 0xFD, 0x82, 0xBF, 0x43,\n\t0x20, 0xD4, 0x4C, 0x39, 0x9E, 0x2D, 0x74, 0xF2, 0x2B, 0xFD, 0x57, 0x31,\n\t0x0C, 0xFE, 0xFB, 0x29, 0x2D, 0x85, 0xC1, 0xF4, 0x87, 0x32, 0xCA, 0xA9,\n\t0xF2, 0x05, 0x65, 0xB4, 0x93, 0x57, 0xFE, 0x9B, 0x77, 0x5A, 0xD3, 0x11,\n\t0x6B, 0xF3, 0x3D, 0x53, 0x0C, 0x61, 0x9D, 0x91, 0x2F, 0x9D, 0xA6, 0x7B,\n\t0x1F, 0x54, 0x67, 0x43, 0x4D, 0x61, 0x69, 0x9E, 0xF3, 0x22, 0x73, 0x48,\n\t0x56, 0xE5, 0x89, 0xB3, 0x19, 0xFC, 0x8C, 0xD8, 0x88, 0x3F, 0x3A, 0xFB,\n\t0xEA, 0x3C, 0x71, 0x67, 0x7F, 0xD1, 0x40, 0x48, 0x70, 0x4A, 0x6F, 0x98,\n\t0xFC, 0xE9, 0x80, 0xC9, 0x9E, 0x1A, 0x52, 0xD9, 0x0F, 0x93, 0x39, 0x1D,\n\t0x1F, 0x6F, 0x73, 0xD8, 0xDF, 0x0D, 0x91, 0xB0, 0xE8, 0xBF, 0x92, 0xF1,\n\t0xBD, 0xA1, 0xF0, 0xBC, 0x9D, 0x71, 0x1B, 0xCB, 0x67, 0xC4, 0xA7, 0x38,\n\t0xB6, 0x8B, 0x1D, 0x67, 0x7A, 0xFC, 0xCE, 0x25, 0x31, 0x7D, 0x05, 0x34,\n\t0x72, 0x5E, 0x8C, 0xB4, 0xB7, 0xF7, 0x28, 0x8A, 0xBF, 0xF8, 0x9A, 0xC3,\n\t0xED, 0x72, 0x4D, 0x6F, 0x1F, 0x9A, 0x31, 0xEB, 0x8D, 0x71, 0x72, 0x1F,\n\t0x7B, 0x7C, 0x12, 0xC1, 0x62, 0xB5, 0xCF, 0xE8, 0x97, 0x52, 0x6B, 0xC9,\n\t0x9A, 0x13, 0x17, 0xD4, 0x26, 0xAA, 0xF0, 0x70, 0x7A, 0x4E, 0xF5, 0xDF,\n\t0xB8, 0x88, 0x72, 0xB1, 0xBB, 0x64, 0x3F, 0xB9, 0x8A, 0xFD, 0xD2, 0x8B,\n\t0xFD, 0x33, 0xF4, 0xF5, 0xFC, 0xD4, 0xB4, 0x43, 0x63, 0xD3, 0x6B, 0x2A,\n\t0x34, 0xB0, 0x73, 0xA8, 0x53, 0x33, 0x35, 0xED, 0x7F, 0x6E, 0x38, 0xEF,\n\t0x81, 0x51, 0xFE, 0xD9, 0xB9, 0x6E, 0x9F, 0x90, 0x47, 0xF3, 0xD3, 0x29,\n\t0x18, 0xE2, 0x8C, 0xF0, 0x7C, 0x32, 0x15, 0x0A, 0x85, 0x3B, 0xAF, 0xA7,\n\t0xA0, 0x16, 0xE2, 0x50, 0xCF, 0x4D, 0xA6, 0xB4, 0xB0, 0xE7, 0xD9, 0x29,\n\t0xD6, 0xBE, 0x2F, 0xD8, 0x90, 0x67, 0x84, 0x07, 0x59, 0xED, 0x31, 0x2D,\n\t0xCC, 0xB9, 0xE9, 0xF4, 0x86, 0x70, 0x0A, 0x59, 0xB5, 0x77, 0x6F, 0x4A,\n\t0x55, 0x1A, 0x97, 0xF3, 0xA0, 0x26, 0x6B, 0x42, 0x33, 0x42, 0x64, 0x62,\n\t0x60, 0xF0, 0x89, 0xA4, 0x3C, 0x42, 0x2D, 0x9A, 0x4B, 0x39, 0x83, 0x45,\n\t0xC8, 0xCA, 0x3D, 0x7D, 0xE7, 0xBC, 0x90, 0x6D, 0x86, 0x1D, 0x55, 0x84,\n\t0xD4, 0xD3, 0x3F, 0xE3, 0xA7, 0xDF, 0x38, 0x50, 0xAF, 0xCC, 0xFF, 0x68,\n\t0xA7, 0xCF, 0x89, 0x9E, 0xA7, 0xA6, 0x58, 0xE6, 0x23, 0xAB, 0xC3, 0x23,\n\t0x47, 0x63, 0x5A, 0x3E, 0x7A, 0xE5, 0x78, 0x3B, 0x92, 0x94, 0x25, 0xF4,\n\t0xCC, 0xAA, 0x63, 0xF7, 0x91, 0x84, 0x09, 0x81, 0x2B, 0xA1, 0x4F, 0x8C,\n\t0x20, 0x94, 0xC6, 0x91, 0x2B, 0x1A, 0xD8, 0xBD, 0xB5, 0xD8, 0x61, 0xB7,\n\t0xF5, 0xF5, 0x83, 0x3D, 0xAB, 0x36, 0xAA, 0x54, 0xD7, 0xBF, 0x7C, 0x6C,\n\t0x12, 0x86, 0xB2, 0xD8, 0x73, 0x3F, 0x40, 0x3E, 0x78, 0xD4, 0x80, 0xF5,\n\t0x2D, 0x1C, 0x8D, 0xD1, 0x28, 0x29, 0x93, 0x51, 0x92, 0xE2, 0x9A, 0xA9,\n\t0xFC, 0xC4, 0x37, 0x5B, 0x23, 0x78, 0xAF, 0x59, 0x2D, 0xFD, 0xFF, 0x6B,\n\t0xF8, 0x3A, 0x80, 0x05, 0xBB, 0xC5, 0x31, 0xA3, 0x7B, 0x45, 0xA3, 0x5F,\n\t0xD1, 0xDF, 0x79, 0xF4, 0x1D, 0xF8, 0xFF, 0xF0, 0xFF, 0x07, 0xFF, 0x1F,\n\t0x0E, 0x84, 0xFF, 0x03, 0xD5, 0x25, 0x61, 0x63, 0xA0, 0xAF, 0x2F, 0x90,\n\t0x77, 0x82, 0x0B, 0xC4, 0xE9, 0x68, 0xA0, 0x1F, 0xBF, 0xF1, 0xF9, 0x4E,\n\t0x74, 0x4B, 0xD1, 0x4D, 0x51, 0xD3, 0xD2, 0x4B, 0xF5, 0x3E, 0x07, 0xBE,\n\t0xEF, 0x8F, 0x7D, 0xF2, 0x78, 0x83, 0xFE, 0xA0, 0x31, 0x28, 0xE8, 0xDE,\n\t0x17, 0x36, 0xDB, 0x5C, 0x89, 0x05, 0xB4, 0xC0, 0x06, 0xFE, 0x02, 0xBE,\n\t0x00, 0xB2, 0x4B, 0xB7, 0xC1, 0x41, 0xEE, 0x2B, 0xC8, 0xCD, 0x20, 0xE0,\n\t0x83, 0xFC, 0x3F, 0xC9, 0xDB, 0x97, 0x1E, 0x02, 0x6F, 0xF3, 0x52, 0xD4,\n\t0xBD, 0x74, 0x6D, 0x58, 0x64, 0x4A, 0xCD, 0xF8, 0xF3, 0xE8, 0x9E, 0xFF,\n\t0x77, 0x21, 0xF0, 0x19, 0xFE, 0xBB, 0x26, 0x65, 0x72, 0xBC, 0x33, 0xF4,\n\t0xFA, 0x19, 0x1B, 0xF9, 0x92, 0xFE, 0x2A, 0x9B, 0x76, 0x10, 0xCC, 0x4E,\n\t0xDB, 0x05, 0x7C, 0x0B, 0xA5, 0x42, 0x41, 0x12, 0x03, 0x5D, 0x09, 0xA8,\n\t0x82, 0xB3, 0x94, 0x5B, 0xB1, 0x26, 0x1A, 0x85, 0xCA, 0x1C, 0x3A, 0xA6,\n\t0x0D, 0x4A, 0x82, 0x67, 0x60, 0x28, 0xC2, 0x93, 0x42, 0xEA, 0x81, 0x99,\n\t0xE9, 0xE8, 0x4A, 0x2D, 0xBE, 0xB9, 0x98, 0x59, 0x11, 0x45, 0x72, 0xF0,\n\t0x8C, 0x04, 0xA7, 0x59, 0x28, 0x6F, 0x52, 0x50, 0x7A, 0x60, 0x52, 0x57,\n\t0x59, 0x43, 0xA9, 0x28, 0xCD, 0xCB, 0xB0, 0xC2, 0xA4, 0x23, 0x70, 0x39,\n\t0xF1, 0x14, 0x17, 0x93, 0x4A, 0x00, 0x88, 0xD6, 0x16, 0xD4, 0x87, 0x22,\n\t0x3E, 0xA7, 0x3D, 0x08, 0x62, 0x23, 0x8A, 0x1A, 0x2D, 0x22, 0x66, 0xE0,\n\t0x82, 0xD9, 0xD1, 0x43, 0xD9, 0xCD, 0xCC, 0x70, 0x31, 0x4F, 0x82, 0x12,\n\t0x88, 0x03, 0x60, 0xC6, 0x7C, 0x07, 0x32, 0x0E, 0xB8, 0xBE, 0x13, 0xFA,\n\t0x0A, 0xB8, 0xCE, 0x44, 0xCA, 0xAB, 0x4B, 0x1F, 0x66, 0xFB, 0x5F, 0x7E,\n\t0x7C, 0x1F, 0x25, 0xC0, 0xA2, 0x08, 0x1B, 0x6D, 0xA0, 0x42, 0x11, 0x20,\n\t0x40, 0x39, 0xD0, 0x43, 0x1C, 0x58, 0x2D, 0x24, 0xFF, 0x49, 0xDD, 0xF1,\n\t0x4A, 0xFE, 0x0D, 0x96, 0x3C, 0xFA, 0x8C, 0xE7, 0xFB, 0xF3, 0x7C, 0xB2,\n\t0x0C, 0x7C, 0x11, 0xDF, 0xC0, 0x7B, 0xD5, 0xB9, 0x58, 0x1D, 0xDF, 0xF3,\n\t0xA0, 0x6E, 0xCE, 0x87, 0xBE, 0xC7, 0x0F, 0x0E, 0x0F, 0x35, 0x69, 0xB8,\n\t0x01, 0x6A, 0x06, 0xBD, 0x9B, 0xA0, 0x77, 0x82, 0xE2, 0x93, 0x99, 0x12,\n\t0x64, 0x56, 0x0F, 0x43, 0xC3, 0x30, 0x8E, 0xB7, 0xF7, 0x3B, 0x86, 0xDE,\n\t0xEE, 0x4D, 0x8F, 0x29, 0xD7, 0x03, 0x33, 0x02, 0xDA, 0x3F, 0x2B, 0xF1,\n\t0x88, 0x42, 0xDA, 0xFF, 0xCE, 0x5C, 0x60, 0x26, 0x76, 0x33, 0xFF, 0xD3,\n\t0x94, 0x9B, 0x35, 0x68, 0x03, 0xEE, 0x0C, 0xFA, 0x9F, 0xCB, 0xD0, 0xA5,\n\t0xED, 0x43, 0x3B, 0xE6, 0x7A, 0x3A, 0x25, 0x8D, 0xA3, 0xF3, 0x98, 0x0A,\n\t0x53, 0x8F, 0xAB, 0x02, 0xC8, 0x00, 0x46, 0xD0, 0x05, 0x55, 0xA7, 0xE6,\n\t0xCE, 0x46, 0xBE, 0xD3, 0x09, 0x9D, 0xE6, 0x4A, 0x34, 0x25, 0xAA, 0x80,\n\t0xD2, 0x52, 0xC2, 0x3C, 0x1D, 0xC7, 0x1C, 0xCB, 0xA0, 0x5B, 0x66, 0xDD,\n\t0xCF, 0x20, 0x1F, 0x20, 0x22, 0xF5, 0x17, 0x71, 0x17, 0xA7, 0xCA, 0xE6,\n\t0x48, 0xFF, 0x26, 0x58, 0xF1, 0x04, 0x0E, 0x24, 0x72, 0x50, 0x83, 0x00,\n\t0x27, 0xDB, 0xA6, 0x86, 0x1F, 0x8D, 0x8F, 0x20, 0xDC, 0xFF, 0xE7, 0x37,\n\t0xD0, 0xA4, 0xD8, 0x7C, 0x46, 0x0E, 0x2A, 0xA5, 0x2D, 0x94, 0x32, 0x88,\n\t0xB3, 0xC9, 0xA7, 0x15, 0xB4, 0x94, 0xB8, 0xB5, 0xE0, 0xE9, 0x49, 0x4B,\n\t0x47, 0x82, 0x10, 0x41, 0xC7, 0xE4, 0x57, 0xB8, 0x4C, 0xFE, 0x3F, 0x7C,\n\t0x06, 0x69, 0x52, 0x5A, 0x26, 0xF8, 0xA5, 0x13, 0x9D, 0x78, 0x41, 0x48,\n\t0xFF, 0x1F, 0xF0, 0x83, 0x87, 0xF0, 0xFF, 0x7F, 0xD0, 0x16, 0xCB, 0xE1,\n\t0xDB, 0x4B, 0xC7, 0x63, 0x1B, 0x55, 0xAA, 0xED, 0x7D, 0x9C, 0x47, 0x0D,\n\t0x68, 0xAD, 0x8E, 0x8B, 0xFB, 0x4D, 0x4B, 0xC6, 0x4B, 0xAB, 0x44, 0xFF,\n\t0x10, 0x30, 0x02, 0x06, 0x13, 0x07, 0x68, 0x3C, 0x84, 0x47, 0x6C, 0x41,\n\t0x09, 0x3E, 0x10, 0xA1, 0x27, 0x65, 0x0A, 0xD7, 0x16, 0xF5, 0xE2, 0xB8,\n\t0xB8, 0x67, 0x16, 0xDC, 0xA9, 0x23, 0x92, 0xEC, 0x3C, 0x3A, 0x3D, 0x1D,\n\t0xBD, 0xE4, 0x46, 0x14, 0x40, 0x0A, 0x3A, 0xBF, 0x68, 0x09, 0x4E, 0x17,\n\t0xA2, 0x7B, 0x8E, 0x3F, 0x73, 0xFE, 0x4F, 0xED, 0x9F, 0x7D, 0x3B, 0x36,\n\t0x5B, 0x3D, 0x57, 0xE5, 0xB4, 0x70, 0xC7, 0x96, 0xBB, 0x6B, 0xFD, 0x68,\n\t0x5A, 0xD5, 0xDB, 0xF1, 0x4C, 0xCF, 0xC3, 0x66, 0x1A, 0x03, 0x58, 0x59,\n\t0xF9, 0xC1, 0x02, 0x36, 0x7C, 0xB8, 0x81, 0x12, 0x93, 0x6D, 0xD9, 0xC9,\n\t0x12, 0x37, 0xA3, 0x2E, 0x5E, 0xC8, 0x00, 0x17, 0xB6, 0x20, 0x00, 0x2A,\n\t0x40, 0x40, 0x0A, 0x2F, 0x20, 0x96, 0xD0, 0x80, 0x2D, 0x94, 0xF0, 0x43,\n\t0x16, 0x0B, 0xD0, 0x11, 0x42, 0x8B, 0x66, 0xA3, 0xC8, 0x01, 0xC6, 0x90,\n\t0x00, 0x4F, 0xAC, 0xA0, 0x00, 0x02, 0x3B, 0x4C, 0x50, 0xAA, 0xA9, 0x01,\n\t0x82, 0x20, 0x9C, 0xF0, 0x40, 0x8A, 0x05, 0x6C, 0x54, 0x80, 0x09, 0x1E,\n\t0x70, 0x0F, 0x4A, 0x24, 0x21, 0x43, 0xEB, 0xCA, 0x29, 0xEE, 0xC1, 0x2A,\n\t0x52, 0xAE, 0x99, 0x21, 0x0D, 0xD7, 0xCC, 0xD4, 0x4A, 0xD3, 0xAB, 0xCB,\n\t0xEF, 0x82, 0x8C, 0xBA, 0x2A, 0xB5, 0xE9, 0xC7, 0xBC, 0xE4, 0xC1, 0x43,\n\t0x30, 0xE6, 0x45, 0x20, 0xE0, 0x21, 0x03, 0xA3, 0x08, 0x28, 0xC0, 0x09,\n\t0x29, 0xE4, 0x28, 0x00, 0x0A, 0x7A, 0xE0, 0xF4, 0x00, 0xC6, 0x49, 0x96,\n\t0x4C, 0x16, 0x23, 0x82, 0xC1, 0x26, 0x60, 0x37, 0x98, 0x7F, 0x73, 0x5B,\n\t0x4E, 0x2F, 0xCB, 0xB3, 0x68, 0xEC, 0x89, 0xDE, 0xC0, 0x88, 0x6E, 0x49,\n\t0x03, 0x23, 0xC2, 0x65, 0x4A, 0x0D, 0x89, 0x5C, 0xCE, 0x33, 0xBD, 0xA9,\n\t0xA1, 0x30, 0x26, 0xFA, 0x5C, 0x58, 0xF4, 0x86, 0x9D, 0xD0, 0xC8, 0xAE,\n\t0x8C, 0x2C, 0x22, 0x15, 0xD0, 0x9A, 0xE4, 0x1A, 0x44, 0xAA, 0xA5, 0x60,\n\t0x8D, 0x9B, 0x5C, 0x9B, 0xB9, 0x1D, 0xCB, 0xB2, 0xDB, 0xEF, 0x7E, 0xAC,\n\t0x5E, 0x16, 0xBC, 0x31, 0xC1, 0x3F, 0xDD, 0x8F, 0xFF, 0x79, 0x7A, 0x16,\n\t0x18, 0x63, 0x1C, 0x13, 0x39, 0xD7, 0xC9, 0x67, 0x7C, 0x79, 0x7A, 0x83,\n\t0x57, 0xFB, 0x82, 0x50, 0x4F, 0xD9, 0x2F, 0xC7, 0xA3, 0x85, 0x71, 0xB0,\n\t0x5C, 0xB8, 0x62, 0x1B, 0xB1, 0xA5, 0x60, 0xEC, 0xCB, 0xBC, 0x1D, 0x19,\n\t0xB7, 0x23, 0x7E, 0x3B, 0xA9, 0x31, 0xFB, 0x82, 0x90, 0x9D, 0x6A, 0x0D,\n\t0xCD, 0x6E, 0x0C, 0x7B, 0x6A, 0x96, 0x55, 0x8F, 0x04, 0x43, 0xA3, 0x73,\n\t0xA1, 0xD1, 0xC1, 0x2F, 0x74, 0xC1, 0xD1, 0x4F, 0x43, 0x1F, 0x33, 0xD1,\n\t0x3D, 0xAD, 0x09, 0x2E, 0x33, 0x91, 0x35, 0xA9, 0x19, 0x77, 0x86, 0x35,\n\t0x34, 0x2B, 0x56, 0xF9, 0x48, 0x71, 0xAC, 0x57, 0xA7, 0x56, 0xD2, 0x34,\n\t0x18, 0xAC, 0x1D, 0xC4, 0xD7, 0x33, 0x47, 0xA1, 0x8E, 0x3E, 0x89, 0xB8,\n\t0xDA, 0xDC, 0xCA, 0x95, 0xB1, 0x6C, 0x5E, 0x0C, 0x73, 0x8E, 0x97, 0x1C,\n\t0x27, 0xEC, 0x51, 0xFD, 0x43, 0x1F, 0xCE, 0xC7, 0xF4, 0x6D, 0xD9, 0x73,\n\t0xD5, 0xD1, 0xB6, 0xC4, 0x4F, 0x25, 0x5E, 0x9E, 0x20, 0xF7, 0xC0, 0xD7,\n\t0x4F, 0xE4, 0xA5, 0x74, 0xEA, 0x1B, 0xF4, 0xC9, 0x9E, 0x29, 0xFA, 0x45,\n\t0x1E, 0x98, 0x2F, 0xA7, 0x43, 0xA7, 0xFB, 0xDE, 0x60, 0x53, 0x29, 0x0E,\n\t0xEB, 0x14, 0xF2, 0xCA, 0x10, 0x58, 0xE9, 0xCF, 0xC5, 0xF2, 0x17, 0xF2,\n\t0xBE, 0xE8, 0x4C, 0x39, 0x9E, 0xCC, 0xBD, 0xC6, 0x7F, 0x21, 0x10, 0x7B,\n\t0x2E, 0x60, 0x89, 0xE7, 0x60, 0x23, 0xE7, 0x82, 0x1C, 0x88, 0x94, 0x83,\n\t0xE5, 0x9A, 0x43, 0xFC, 0x90, 0xC7, 0x95, 0x33, 0x6C, 0xE8, 0xA3, 0xF7,\n\t0x95, 0x3B, 0xF8, 0xD0, 0x17, 0xBA, 0x21, 0xEE, 0xE4, 0x62, 0x2B, 0x1F,\n\t0xEE, 0x2C, 0xC1, 0x70, 0x4A, 0x26, 0xCA, 0xEB, 0xAF, 0xBF, 0x6E, 0xAD,\n\t0x3D, 0x59, 0x6D, 0xDF, 0xE5, 0xE4, 0xE4, 0x64, 0x53, 0xF9, 0xF6, 0x6F,\n\t0xB7, 0x28, 0x28, 0xF4, 0x3F, 0x4A, 0xEB, 0xF7, 0x23, 0x15, 0xF3, 0x9D,\n\t0x56, 0xEA, 0x32, 0x1C, 0xD3, 0xE4, 0xF8, 0xBF, 0x07, 0x6F, 0x31, 0xB6,\n\t0x94, 0xC2, 0x58, 0x7C, 0x4F, 0x0A, 0xAA, 0x27, 0xE1, 0x5F, 0xD2, 0x7F,\n\t0x97, 0x25, 0x6C, 0x48, 0x5D, 0x32, 0x7B, 0x65, 0xA2, 0x82, 0x39, 0x1F,\n\t0x13, 0x8A, 0x4D, 0x3C, 0xF3, 0x2F, 0x67, 0x56, 0xDE, 0xD1, 0xE6, 0x01,\n\t0xEA, 0xAB, 0xD6, 0xB3, 0x7D, 0xEB, 0x82, 0x31, 0xAE, 0x2F, 0xFF, 0x4C,\n\t0x6F, 0xCF, 0x4D, 0xBF, 0x41, 0x1D, 0x3D, 0xAB, 0xA3, 0xF0, 0xCC, 0x61,\n\t0x45, 0x8A, 0x63, 0xAE, 0xB8, 0x28, 0xEC, 0xD8, 0x37, 0x68, 0x09, 0x99,\n\t0xCE, 0x43, 0x4B, 0x08, 0x9B, 0x1C, 0x07, 0xE0, 0xB3, 0x93, 0x42, 0x7C,\n\t0xF2, 0xB3, 0x7C, 0x03, 0xFC, 0xF3, 0x80, 0xFF, 0x2D, 0xE3, 0x21, 0x06,\n\t0x04, 0x15, 0x2D, 0xC4, 0x06, 0x15, 0x9F, 0x61, 0x8E, 0xB0, 0x79, 0x9A,\n\t0x54, 0x99, 0xEB, 0xE3, 0x29, 0x84, 0xE0, 0x3D, 0xEC, 0xAC, 0xB4, 0xC5,\n\t0x77, 0x36, 0x13, 0x1D, 0xE9, 0xCE, 0x4D, 0x3B, 0xD5, 0xF4, 0xEE, 0x3D,\n\t0xC4, 0xC7, 0x14, 0x21, 0xEA, 0xEB, 0xB9, 0x22, 0x0F, 0x75, 0x45, 0x1C,\n\t0xEA, 0x8A, 0x3E, 0x9A, 0x77, 0x31, 0xE7, 0x62, 0x0E, 0x92, 0xD4, 0xC7,\n\t0xCF, 0xF2, 0x71, 0x1C, 0x04, 0x3B, 0x92, 0x97, 0x09, 0x7B, 0xED, 0xD9,\n\t0x4F, 0xBB, 0x67, 0xE0, 0x10, 0xEA, 0xA8, 0x59, 0xCF, 0x3E, 0xED, 0x86,\n\t0x61, 0xB3, 0x77, 0xD7, 0xBA, 0x5B, 0xA9, 0xA2, 0xDF, 0x97, 0x5A, 0x4C,\n\t0x7D, 0x83, 0x38, 0xB3, 0x22, 0xA5, 0xE1, 0x52, 0xDA, 0x77, 0x9E, 0xDF,\n\t0xA5, 0x06, 0x9A, 0x1A, 0x4B, 0x7B, 0x9C, 0x4D, 0x69, 0xBD, 0xF2, 0xD1,\n\t0xC0, 0xFE, 0x9E, 0x78, 0xFE, 0xCA, 0xA5, 0xDD, 0x7E, 0xDF, 0xFF, 0xFE,\n\t0xE0, 0x62, 0xDA, 0x5D, 0xF9, 0x71, 0xC1, 0xB0, 0x62, 0x87, 0x4D, 0x66,\n\t0xAF, 0x49, 0xAE, 0xC9, 0x77, 0x2B, 0x19, 0xE5, 0x7C, 0xB0, 0xA0, 0x1D,\n\t0x0D, 0x16, 0x72, 0xBC, 0x31, 0x19, 0xEA, 0x8B, 0xC9, 0xBC, 0x8A, 0xE2,\n\t0x50, 0x20, 0x86, 0x65, 0x1F, 0x16, 0x9E, 0x46, 0x83, 0x05, 0xF5, 0x96,\n\t0x1F, 0xF8, 0x7F, 0x36, 0xE4, 0x07, 0xCD, 0x54, 0xA7, 0x37, 0xAF, 0xB9,\n\t0x98, 0xB4, 0x45, 0x67, 0x05, 0xE7, 0xE0, 0xD0, 0x43, 0x6B, 0x6B, 0x43,\n\t0x4C, 0x69, 0xC3, 0xC8, 0x54, 0x3F, 0x15, 0x5C, 0x2F, 0xC0, 0x62, 0x6B,\n\t0xBD, 0x94, 0x1D, 0x4E, 0x8E, 0xFF, 0x05, 0x7F, 0xD5, 0x14, 0x97, 0x3C,\n\t0x4E, 0x43, 0x48, 0xFF, 0x05, 0xE5, 0x0B, 0xCC, 0x77, 0xA0, 0xEC, 0xE2,\n\t0x54, 0x04, 0xDD, 0x2D, 0x39, 0x64, 0xD5, 0x7A, 0x6F, 0x22, 0x53, 0x64,\n\t0x4E, 0xA3, 0x48, 0xA6, 0xB4, 0x8C, 0x75, 0x24, 0x53, 0xB6, 0x93, 0x1D,\n\t0xC5, 0x70, 0x0A, 0x3C, 0x7E, 0x56, 0xD8, 0x4C, 0xBF, 0xB9, 0x16, 0xFF,\n\t0xE6, 0xE3, 0x61, 0xC6, 0xB0, 0x57, 0xCC, 0x8B, 0xA7, 0xCF, 0x96, 0xC3,\n\t0x1E, 0x9D, 0x9B, 0xFE, 0x5C, 0x79, 0xA2, 0xA7, 0x9B, 0xC8, 0xC4, 0xC0,\n\t0x60, 0x13, 0x95, 0xFE, 0x7C, 0x44, 0xCF, 0x3C, 0x4F, 0xB2, 0x1D, 0x99,\n\t0xD0, 0x90, 0x82, 0x27, 0x19, 0xAB, 0x35, 0x1A, 0x71, 0xA6, 0xBD, 0xA9,\n\t0xA3, 0x94, 0x9B, 0x1C, 0x26, 0x86, 0x30, 0xFB, 0xE5, 0x6C, 0xA3, 0x73,\n\t0x3D, 0xF5, 0x84, 0xFE, 0xA4, 0x90, 0xE6, 0x63, 0xD3, 0x16, 0xE1, 0xB3,\n\t0x92, 0xBC, 0x9D, 0xCD, 0x24, 0x74, 0x5C, 0xBE, 0x57, 0x44, 0xBF, 0xA2,\n\t0x6A, 0xC3, 0x9E, 0xFA, 0x4D, 0xA1, 0x66, 0xD7, 0xE6, 0xFE, 0xAD, 0x2D,\n\t0x2C, 0xBF, 0xA1, 0x99, 0xD2, 0x7E, 0x2D, 0xE8, 0x15, 0x15, 0x68, 0xDF,\n\t0xC7, 0x2C, 0x75, 0xF4, 0x8F, 0x54, 0x2E, 0xB0, 0x85, 0x28, 0xFE, 0x69,\n\t0x8B, 0x68, 0xE9, 0x27, 0x44, 0xBB, 0xD6, 0x10, 0x38, 0x9E, 0x4C, 0x55,\n\t0x32, 0x25, 0x9A, 0xC9, 0xC0, 0x81, 0x28, 0x16, 0x71, 0x2F, 0x55, 0x04,\n\t0xFE, 0xF7, 0x22, 0xF1, 0x7F, 0xBD, 0xAA, 0x86, 0x53, 0x38, 0xD0, 0x31,\n\t0x7E, 0xE2, 0x40, 0x94, 0x33, 0x4F, 0x38, 0xB2, 0x52, 0x12, 0x86, 0xE2,\n\t0x92, 0x79, 0x91, 0xE8, 0xB7, 0xA2, 0x99, 0x87, 0x51, 0xC7, 0x53, 0x5C,\n\t0x69, 0x8C, 0xE8, 0xDE, 0x79, 0xB2, 0xD9, 0xFA, 0xE3, 0x9A, 0x45, 0xDC,\n\t0x4E, 0x0D, 0xCF, 0xE3, 0x63, 0x91, 0x47, 0x63, 0x2A, 0xD7, 0x82, 0x07,\n\t0xD5, 0xEC, 0x31, 0x24, 0x4C, 0xD5, 0xA1, 0xF5, 0xE4, 0x5E, 0x19, 0xDA,\n\t0x8F, 0x81, 0xC1, 0xA1, 0x83, 0x17, 0xFF, 0x5E, 0x17, 0xF9, 0xA6, 0xEF,\n\t0xD2, 0x59, 0xFA, 0x0F, 0xDC, 0x04, 0x1A, 0xA8, 0x1B, 0x03, 0x81, 0xF8,\n\t0x02, 0xD1, 0x1F, 0x52, 0x2E, 0x82, 0x6D, 0xAC, 0x6B, 0xE6, 0x49, 0x90,\n\t0x8B, 0x4C, 0x93, 0x1E, 0xBA, 0x92, 0x32, 0xD3, 0x8E, 0x4A, 0x98, 0xD3,\n\t0x0F, 0x60, 0x6A, 0x6B, 0x76, 0x0D, 0x6B, 0x25, 0x11, 0x76, 0xC8, 0xE8,\n\t0x43, 0x62, 0x9C, 0x62, 0x00, 0xFF, 0xC4, 0x52, 0xA4, 0x3B, 0xA2, 0x7B,\n\t0xA3, 0xB7, 0x14, 0xC1, 0x0D, 0x1E, 0xE1, 0xD1, 0xCC, 0xB3, 0xCB, 0x53,\n\t0x1E, 0xFA, 0xB3, 0x68, 0x1A, 0xA5, 0x28, 0x8B, 0x0F, 0x69, 0x89, 0x40,\n\t0x1E, 0x27, 0x95, 0x4C, 0x44, 0x33, 0x11, 0x08, 0x93, 0x31, 0x78, 0xC1,\n\t0x83, 0x44, 0xC8, 0xD1, 0xB4, 0xEC, 0xD2, 0x27, 0xED, 0xB2, 0xFC, 0x32,\n\t0x22, 0x8D, 0xE2, 0x5A, 0x56, 0x41, 0xD9, 0xFC, 0x1A, 0x57, 0xFB, 0xCD,\n\t0x88, 0xD4, 0x13, 0x91, 0x95, 0xD3, 0xB5, 0x61, 0x33, 0x73, 0xCF, 0x2C,\n\t0xE3, 0x68, 0x7E, 0x6F, 0x8B, 0xF8, 0x8B, 0xF8, 0xC6, 0xC4, 0xC0, 0x60,\n\t0x4B, 0x0E, 0x59, 0x19, 0xB5, 0x95, 0x5B, 0xEB, 0xA8, 0x69, 0xBF, 0x75,\n\t0x01, 0x4F, 0x63, 0xD6, 0x8E, 0x4D, 0x13, 0x78, 0xAC, 0x52, 0xE3, 0x73,\n\t0xA2, 0xA5, 0x76, 0xFB, 0x32, 0x31, 0x27, 0xCF, 0x84, 0xC1, 0xDA, 0xFB,\n\t0x22, 0xBE, 0xE0, 0x49, 0xFB, 0xCC, 0xF0, 0xD4, 0xC1, 0xF6, 0x17, 0x4F,\n\t0xDA, 0xB9, 0x9C, 0x0E, 0x22, 0xB9, 0xD8, 0xC8, 0x9D, 0x63, 0x77, 0x5E,\n\t0xBD, 0xC4, 0xB0, 0xDC, 0xB1, 0xD9, 0xDB, 0x34, 0x43, 0xBF, 0x1E, 0x35,\n\t0x53, 0xC1, 0x95, 0x72, 0x3D, 0xCF, 0x5E, 0x41, 0x17, 0x6C, 0xA9, 0x77,\n\t0xD2, 0xD4, 0xEC, 0x61, 0x18, 0x5B, 0xF6, 0x9A, 0xBD, 0xA0, 0xEC, 0xA3,\n\t0xD9, 0x60, 0xAA, 0x57, 0x6F, 0x8A, 0x59, 0xFD, 0x7A, 0xAA, 0x57, 0xFE,\n\t0xFF, 0x8F, 0x6B, 0x48, 0x53, 0xCD, 0xF1, 0x1E, 0x3C, 0x0B, 0x26, 0x96,\n\t0xB1, 0x1D, 0x3D, 0x13, 0xC5, 0x99, 0x31, 0xDD, 0x5D, 0xCD, 0x23, 0x39,\n\t0x96, 0xEE, 0x35, 0xEC, 0xCE, 0xB2, 0xBA, 0x6B, 0x5C, 0x68, 0x26, 0xC9,\n\t0x8E, 0x42, 0x58, 0x54, 0x71, 0xA8, 0x56, 0x53, 0x2B, 0x57, 0x70, 0xDA,\n\t0x04, 0x3E, 0x0F, 0x4E, 0x33, 0x99, 0xBE, 0x0E, 0x2C, 0xC6, 0xF8, 0x02,\n\t0x07, 0x00, 0xA4, 0xE0, 0x62, 0x00, 0x4B, 0x14, 0x96, 0x10, 0x85, 0x32,\n\t0x5C, 0x80, 0x75, 0x8A, 0x2F, 0xBD, 0x97, 0xBE, 0x64, 0x52, 0x10, 0xB3,\n\t0xAC, 0xE4, 0x9F, 0xFF, 0xC9, 0xDF, 0x05, 0x45, 0x62, 0x4E, 0x51, 0xD0,\n\t0xBF, 0xAC, 0x0D, 0x95, 0xD3, 0x84, 0x8C, 0x4A, 0xE9, 0x48, 0x17, 0xBE,\n\t0x08, 0x80, 0x90, 0x17, 0xDE, 0x01, 0x0D, 0x2D, 0x09, 0x19, 0x28, 0x39,\n\t0xB4, 0xED, 0x24, 0x09, 0x6A, 0x92, 0xC4, 0x49, 0x48, 0x68, 0x16, 0x09,\n\t0x3A, 0x42, 0xE2, 0x22, 0x25, 0xB2, 0x90, 0x12, 0x27, 0xB1, 0xFD, 0x9F,\n\t0x80, 0xAE, 0xE6, 0x38, 0x89, 0xBF, 0xA3, 0x94, 0x02, 0xD3, 0xDC, 0x24,\n\t0xC5, 0xED, 0x61, 0x4A, 0x31, 0x13, 0x83, 0x2A, 0xAA, 0x5C, 0x7A, 0xD8,\n\t0x51, 0xA5, 0x12, 0x83, 0xCD, 0xA4, 0x3A, 0xCD, 0x36, 0xFE, 0xA0, 0x14,\n\t0xB4, 0xC7, 0xC5, 0x3E, 0xA8, 0x02, 0x33, 0x60, 0x4F, 0x40, 0xF0, 0x0B,\n\t0x90, 0xCB, 0x04, 0x90, 0xBF, 0x54, 0xD3, 0x0F, 0x02, 0xE1, 0xAE, 0xB8,\n\t0x89, 0x24, 0x5B, 0x52, 0x84, 0x71, 0xD8, 0x46, 0x29, 0x3E, 0x94, 0x35,\n\t0x49, 0xE1, 0xA9, 0xC8, 0x1A, 0x29, 0xBE, 0x30, 0xAA, 0x2A, 0x44, 0x6D,\n\t0x9A, 0xEA, 0x44, 0xC9, 0x16, 0x10, 0x8F, 0xC8, 0x33, 0x20, 0xDC, 0xCE,\n\t0xB9, 0xD3, 0x96, 0x2A, 0x9C, 0xC2, 0x66, 0x6A, 0xB2, 0x06, 0x08, 0x67,\n\t0x8E, 0x9E, 0x6B, 0xE4, 0x0E, 0x03, 0xE4, 0xE0, 0xBB, 0x0E, 0xAF, 0xE9,\n\t0x63, 0x31, 0x79, 0xE5, 0xCA, 0xC6, 0xA1, 0x6C, 0x27, 0x05, 0xA7, 0x02,\n\t0x41, 0x6B, 0xFA, 0x72, 0x2C, 0x07, 0xC4, 0xEB, 0xBA, 0xD1, 0xF3, 0xA6,\n\t0xB0, 0xF3, 0xD9, 0xC2, 0x7F, 0x66, 0xD7, 0xFC, 0x35, 0x5C, 0x17, 0x33,\n\t0xCD, 0x94, 0xA9, 0x13, 0x1C, 0x73, 0x52, 0x01, 0x5D, 0x62, 0x77, 0x9A,\n\t0x28, 0x0E, 0x8F, 0x78, 0xCE, 0x1C, 0xBF, 0xB3, 0xC4, 0x33, 0x7A, 0x2F,\n\t0x0E, 0xFC, 0xFB, 0x2F, 0xEE, 0xC5, 0xBD, 0xBE, 0x69, 0x2B, 0x65, 0xFA,\n\t0x54, 0xA5, 0x55, 0xE9, 0x77, 0x96, 0x73, 0x35, 0xE9, 0xCA, 0xC2, 0xD5,\n\t0x29, 0x7E, 0x49, 0x64, 0x4C, 0x2A, 0x3E, 0x78, 0x6C, 0x77, 0xEA, 0x63,\n\t0xC4, 0x7D, 0x3E, 0x26, 0xEF, 0xC5, 0xC5, 0x4E, 0x9C, 0x8E, 0x38, 0x33,\n\t0x43, 0x3F, 0xEA, 0x95, 0x60, 0x8A, 0xA3, 0xF8, 0x2C, 0x32, 0x24, 0x79,\n\t0x64, 0xD4, 0x13, 0x83, 0x47, 0xC6, 0xFD, 0x94, 0x59, 0xF8, 0xFA, 0xCA,\n\t0x9B, 0x79, 0x14, 0x26, 0xE3, 0x3A, 0x03, 0xCD, 0x93, 0xCB, 0x53, 0xA2,\n\t0xD7, 0x27, 0x7A, 0xD5, 0x69, 0xE6, 0xEF, 0xC2, 0xFE, 0x18, 0xEF, 0xFE,\n\t0xA6, 0xA7, 0x36, 0xC3, 0xDB, 0x9B, 0x5E, 0xFB, 0xA6, 0x1C, 0x8B, 0xB4,\n\t0x19, 0xE7, 0x93, 0x85, 0xED, 0xE3, 0x93, 0xFD, 0x37, 0xB3, 0x36, 0xB3,\n\t0xD0, 0x55, 0xD6, 0xF7, 0xDB, 0xE6, 0x5C, 0xEB, 0xDD, 0x5B, 0x45, 0xC1,\n\t0x12, 0xA4, 0xB8, 0xBB, 0x95, 0xDD, 0x3E, 0xEB, 0x6F, 0x65, 0x4F, 0x9D,\n\t0x45, 0xC1, 0x67, 0xAE, 0x77, 0x76, 0xC1, 0x77, 0x1F, 0x93, 0x25, 0x1D,\n\t0xBA, 0x04, 0x1F, 0x04, 0x5F, 0x2E, 0x05, 0x55, 0xE1, 0x63, 0x97, 0xF3,\n\t0xAC, 0x22, 0xF9, 0x2F, 0x2F, 0x58, 0x2A, 0x9D, 0x3C, 0xF8, 0x93, 0x2E,\n\t0x46, 0x54, 0x28, 0xA4, 0x8A, 0x91, 0x14, 0xCA, 0xE6, 0x12, 0xCB, 0xD7,\n\t0x48, 0xA3, 0xBC, 0xF4, 0xDA, 0x56, 0x3E, 0x5F, 0xC5, 0xFE, 0x97, 0xA0,\n\t0xFF, 0x0D, 0x26, 0x0E, 0x8C, 0x87, 0x92, 0x87, 0x3E, 0x0F, 0x60, 0x63,\n\t0x22, 0xE0, 0x6B, 0xAD, 0x0D, 0x9F, 0x9E, 0xAE, 0xCE, 0xA0, 0x17, 0xF1,\n\t0xFF, 0xF8, 0xAC, 0x7F, 0x2D, 0x99, 0xE2, 0x1B, 0x96, 0xDE, 0xA8, 0xF4,\n\t0xC6, 0xE9, 0x9F, 0x9D, 0xC4, 0xE1, 0x19, 0x8D, 0x70, 0x4A, 0x26, 0xA5,\n\t0xCF, 0x7A, 0x85, 0xE5, 0xD9, 0xEF, 0xE8, 0xFF, 0xFB, 0xC7, 0x59, 0x46,\n\t0x4D, 0xCF, 0x42, 0x57, 0x7E, 0xC3, 0x86, 0x34, 0x73, 0x47, 0xA3, 0x1F,\n\t0x51, 0x6F, 0x13, 0x41, 0x3A, 0x0E, 0x9B, 0xDD, 0xFE, 0x03, 0x58, 0x4D,\n\t0x7B, 0x09, 0xAE, 0x23, 0x10, 0x6C, 0x0D, 0x1F, 0xD1, 0x97, 0x88, 0x3E,\n\t0xD8, 0x35, 0x03, 0xCB, 0xF2, 0xB2, 0x6A, 0x44, 0x07, 0x45, 0x2F, 0x87,\n\t0xC8, 0xA0, 0x6E, 0x49, 0x23, 0x06, 0xE5, 0x32, 0x03, 0xFE, 0x34, 0x30,\n\t0x6A, 0x08, 0x0C, 0xAA, 0x64, 0x92, 0x48, 0x15, 0xB0, 0x86, 0x25, 0xF1,\n\t0xDF, 0x5D, 0xE3, 0xE4, 0xFD, 0x9B, 0xA4, 0x29, 0xC7, 0x97, 0xD6, 0x78,\n\t0xE3, 0xBA, 0xC6, 0xEC, 0xEA, 0x88, 0x2F, 0x17, 0xA8, 0x94, 0xDE, 0x60,\n\t0xA2, 0x9E, 0x6A, 0xC6, 0x44, 0xAD, 0x2F, 0xA2, 0x2A, 0x92, 0x34, 0x7F,\n\t0xA7, 0x35, 0x0F, 0xEA, 0xD2, 0xF3, 0xD3, 0x8D, 0xCC, 0x56, 0x2D, 0xCB,\n\t0xB6, 0xAA, 0xA9, 0x80, 0x51, 0xC7, 0x26, 0xF2, 0x93, 0x17, 0x87, 0x5B,\n\t0x5A, 0xE3, 0xA7, 0xB0, 0x1C, 0x9F, 0x72, 0x7B, 0xDB, 0x38, 0x08, 0x07,\n\t0xDF, 0xFD, 0x35, 0x41, 0xF0, 0xA6, 0xF0, 0x8C, 0xAC, 0x71, 0xC5, 0xD7,\n\t0x10, 0x4F, 0xE4, 0xD2, 0x7B, 0x80, 0x8B, 0x94, 0xDB, 0xD9, 0x46, 0x7A,\n\t0xC5, 0x4D, 0x4D, 0xA4, 0x85, 0x86, 0x54, 0x6C, 0x26, 0xFA, 0xE5, 0xD4,\n\t0xF1, 0x35, 0x5A, 0x4E, 0x5E, 0x8F, 0x3D, 0x9D, 0x48, 0xCB, 0x89, 0x03,\n\t0xE3, 0xF6, 0xEB, 0xB1, 0xE3, 0x57, 0x48, 0x47, 0xEC, 0x1F, 0x63, 0x84,\n\t0xF0, 0xC3, 0x46, 0xF0, 0xCC, 0xC3, 0x18, 0x81, 0x87, 0x11, 0x6A, 0x8C,\n\t0x10, 0x1E, 0x34, 0xC2, 0x57, 0x12, 0x89, 0xA9, 0x11, 0x23, 0xD2, 0x9B,\n\t0x15, 0x52, 0xDF, 0x43, 0xD5, 0xCA, 0x95, 0x1A, 0x4E, 0xB9, 0x8D, 0x3F,\n\t0xD9, 0x7D, 0xA8, 0x4A, 0xD8, 0x05, 0xC9, 0xE5, 0x1C, 0x18, 0x1F, 0xD1,\n\t0x9B, 0x98, 0x4A, 0x8D, 0x34, 0x90, 0x99, 0xE2, 0x43, 0xF4, 0xA5, 0xEE,\n\t0xD7, 0x5B, 0xD4, 0x90, 0xFD, 0x2D, 0xBB, 0x0C, 0xE2, 0x14, 0x36, 0x7F,\n\t0xE8, 0x52, 0x17, 0x3D, 0x47, 0xC7, 0xEA, 0x7E, 0x4C, 0x41, 0xE0, 0x39,\n\t0xFC, 0xAD, 0x8E, 0xB4, 0x97, 0x40, 0x1D, 0xEA, 0xAD, 0xFC, 0x3F, 0xE6,\n\t0xDE, 0x09, 0x83, 0x0F, 0xFE, 0xFF, 0xFF, 0x0B, 0x99, 0xF1, 0xDF, 0xD2,\n\t0x1E, 0xC1, 0xF5, 0x08, 0x08, 0x1E, 0xF9, 0xCB, 0xFF, 0x3F, 0x4B, 0x66,\n\t0x04, 0xDA, 0x8F, 0x46, 0x5A, 0x0D, 0x85, 0xC0, 0xC7, 0x7C, 0x4E, 0x9E,\n\t0x63, 0x10, 0xF6, 0x32, 0x75, 0xFE, 0xFF, 0x9F, 0xD1, 0xCF, 0xAC, 0xE9,\n\t0x66, 0xCF, 0x59, 0xE9, 0x34, 0xFD, 0x6F, 0x92, 0xD3, 0x39, 0x81, 0xF5,\n\t0x3F, 0x77, 0x07, 0xF1, 0x2B, 0xED, 0xA8, 0x3E, 0x26, 0xEE, 0x65, 0x5A,\n\t0x9D, 0x38, 0x5C, 0xEB, 0x74, 0xCF, 0x99, 0xB1, 0x2F, 0x96, 0x22, 0xDE,\n\t0xFF, 0xEF, 0x62, 0xFC, 0x70, 0xC9, 0x79, 0xE2, 0x29, 0x2C, 0x6D, 0xCC,\n\t0xC7, 0x8E, 0x9F, 0x77, 0x1A, 0x96, 0x2D, 0x17, 0x2E, 0x45, 0x2C, 0x32,\n\t0x05, 0x54, 0x02, 0x66, 0x57, 0xE2, 0xE9, 0x64, 0x8E, 0xEB, 0x8B, 0x6E,\n\t0xBB, 0x6B, 0xED, 0x67, 0xA5, 0x34, 0x57, 0x69, 0x9A, 0xB4, 0x4C, 0xF9,\n\t0xB1, 0x99, 0xA9, 0x00, 0x5F, 0x0A, 0x07, 0x31, 0x88, 0x80, 0x81, 0x01,\n\t0x9F, 0x2F, 0x6E, 0xC4, 0x20, 0x03, 0x86, 0x2F, 0xDC, 0x80, 0x67, 0x02,\n\t0x57, 0xB0, 0xC2, 0x0B, 0xCB, 0xC4, 0x37, 0x18, 0x10, 0xC2, 0xA2, 0x22,\n\t0x8A, 0x07, 0xA4, 0x7E, 0xD8, 0xD0, 0xA0, 0x08, 0x19, 0xC4, 0x60, 0x0A,\n\t0x1F, 0x38, 0x52, 0xD0, 0x43, 0x05, 0x1A, 0x20, 0x09, 0x05, 0x0C, 0xA0,\n\t0x7C, 0x02, 0x3A, 0x96, 0x07, 0x0C, 0x60, 0x45, 0x00, 0xAE, 0x0B, 0x11,\n\t0x05, 0x00, 0x2A, 0xF5, 0xC1, 0xB5, 0x75, 0x14, 0xE6, 0xA9, 0x49, 0x79,\n\t0x44, 0x03, 0x39, 0x65, 0xCB, 0x27, 0xD0, 0x26, 0x10, 0x37, 0x38, 0x5F,\n\t0x60, 0x00, 0x28, 0xB0, 0x6D, 0xDD, 0xDB, 0xAC, 0x6E, 0x07, 0x55, 0x74,\n\t0x2E, 0x45, 0x52, 0x90, 0xD9, 0x60, 0xE6, 0x88, 0x07, 0xCC, 0x10, 0xE1,\n\t0x03, 0xF0, 0xF7, 0x2C, 0xCF, 0x20, 0xF0, 0x28, 0xB6, 0xEB, 0xD2, 0x1C,\n\t0xF1, 0xCD, 0xA0, 0xFB, 0xF3, 0x1C, 0x88, 0xBC, 0x2A, 0x7A, 0xDE, 0xBC,\n\t0xA8, 0xBC, 0xA8, 0x2F, 0xE2, 0xBA, 0x4C, 0xE5, 0xDF, 0x3E, 0xBD, 0x0F,\n\t0xBA, 0x2C, 0xEF, 0x5E, 0x6E, 0xE2, 0xDD, 0xC6, 0x73, 0x2F, 0x24, 0x12,\n\t0xA9, 0x02, 0x23, 0x86, 0x3B, 0x21, 0x52, 0x17, 0xC1, 0x39, 0xEC, 0xA1,\n\t0xA4, 0xAB, 0xE0, 0xCC, 0x9D, 0x55, 0x38, 0x69, 0x29, 0x9C, 0xFC, 0x51,\n\t0x00, 0x9F, 0x80, 0xD0, 0x47, 0x2A, 0xC0, 0x06, 0xF5, 0x86, 0x90, 0x42,\n\t0x15, 0xD0, 0x51, 0x30, 0xC7, 0x66, 0x12, 0xE7, 0x34, 0xBD, 0x39, 0x4D,\n\t0x9F, 0xD3, 0x94, 0x6C, 0xB5, 0x5A, 0x34, 0x44, 0x69, 0x02, 0x60, 0xF4,\n\t0x59, 0xC0, 0xE8, 0x31, 0x68, 0x80, 0x10, 0x27, 0x20, 0xBC, 0x2A, 0xE1,\n\t0x1F, 0x62, 0xF3, 0xD7, 0xBC, 0x59, 0xC7, 0xFF, 0x6F, 0x5C, 0xF3, 0x9B,\n\t0xE6, 0xE3, 0xFD, 0xC6, 0x9D, 0x65, 0x0D, 0xCD, 0x9F, 0xDE, 0xBF, 0xF3,\n\t0x9D, 0x9F, 0xB4, 0xDB, 0xBC, 0xC3, 0x73, 0x8C, 0xE3, 0x5C, 0x8F, 0x8B,\n\t0xC7, 0xDB, 0x7D, 0x37, 0x86, 0x42, 0xB5, 0x82, 0xEF, 0xF9, 0xB8, 0x51,\n\t0xFA, 0xA3, 0x5C, 0xA5, 0x69, 0x9A, 0x88, 0xCB, 0xF9, 0x53, 0xB5, 0x56,\n\t0x28, 0x66, 0x54, 0xDA, 0x2F, 0x6C, 0xEC, 0x99, 0xD6, 0xCE, 0x73, 0xEF,\n\t0x7C, 0x46, 0xD9, 0xB6, 0x99, 0x46, 0x43, 0x4A, 0x7B, 0xD0, 0x36, 0xDE,\n\t0x34, 0x49, 0x68, 0xB0, 0xA9, 0xA4, 0x19, 0x8B, 0x06, 0x3B, 0xD3, 0x35,\n\t0x0C, 0xA1, 0xE1, 0x23, 0x99, 0x85, 0xF8, 0xB5, 0x5F, 0x95, 0x73, 0x0D,\n\t0x48, 0xA2, 0xC9, 0x61, 0x4F, 0xC6, 0xDF, 0xBA, 0x9C, 0x7D, 0x3D, 0xB6,\n\t0x2C, 0x7A, 0x48, 0x6B, 0x74, 0xCF, 0xFF, 0xBF, 0x8E, 0xED, 0x57, 0xA1,\n\t0x4B, 0xFC, 0x31, 0x30, 0xB8, 0x25, 0xBB, 0x24, 0x52, 0xC8, 0x46, 0xB3,\n\t0xFB, 0x8C, 0x84, 0xCD, 0x8B, 0x34, 0x96, 0xB3, 0x9F, 0xF4, 0x97, 0x73,\n\t0xC3, 0x37, 0x7A, 0x36, 0x9D, 0x0F, 0x49, 0x8D, 0xB2, 0x1E, 0xAB, 0x73,\n\t0x1A, 0x3D, 0xA2, 0x7F, 0x87, 0xD2, 0xFE, 0x83, 0x4C, 0x0C, 0x4C, 0x87,\n\t0x7F, 0x58, 0x42, 0x35, 0xB6, 0xB0, 0xB0, 0x56, 0x50, 0x7E, 0x7F, 0x10,\n\t0xA2, 0x57, 0x29, 0x1A, 0x86, 0x61, 0xB3, 0x38, 0x8D, 0x72, 0x84, 0x4D,\n\t0xF7, 0x9E, 0x7E, 0x7D, 0x78, 0xAD, 0x28, 0x3F, 0x5C, 0xBB, 0x3F, 0x49,\n\t0xD9, 0xE9, 0x83, 0x17, 0xF4, 0x93, 0x7D, 0xAD, 0x4A, 0x71, 0x2F, 0x4D,\n\t0xA2, 0xAE, 0x55, 0x8B, 0xBB, 0x40, 0x07, 0x75, 0x5F, 0xE3, 0x76, 0x9E,\n\t0x9F, 0x95, 0xDA, 0x4F, 0xDF, 0x59, 0xD7, 0x51, 0xE3, 0x62, 0x5C, 0x67,\n\t0x8D, 0x4A, 0xD5, 0x54, 0x87, 0xFE, 0xF5, 0x64, 0x60, 0xE8, 0x19, 0x98,\n\t0xF1, 0xD0, 0xBE, 0x24, 0x2A, 0xCD, 0x43, 0x3D, 0xE8, 0xD9, 0xE5, 0xE1,\n\t0xA8, 0xA3, 0x56, 0x3A, 0xCF, 0x44, 0xAD, 0x64, 0x37, 0x63, 0xE1, 0x5A,\n\t0x21, 0xAE, 0xCB, 0xFE, 0x4A, 0x66, 0xBE, 0xCC, 0x1C, 0x17, 0x4A, 0x88,\n\t0x4C, 0x25, 0xA1, 0x1D, 0x9A, 0xB1, 0xEF, 0x7E, 0x74, 0x0D, 0x8A, 0x4B,\n\t0xF7, 0x2E, 0x6B, 0x5B, 0xBD, 0x9C, 0xDB, 0xFF, 0x34, 0xB3, 0x37, 0x14,\n\t0xFA, 0x4D, 0xA8, 0x57, 0x88, 0xE2, 0xCC, 0x0C, 0x65, 0xDC, 0xEA, 0x95,\n\t0x65, 0x9C, 0x99, 0x3D, 0xDB, 0xC6, 0xCE, 0x4C, 0x5C, 0xB9, 0x58, 0x46,\n\t0xBF, 0x92, 0xF5, 0x7D, 0x6E, 0x8A, 0x43, 0x6F, 0x31, 0xCE, 0xA2, 0x19,\n\t0x4C, 0xFB, 0x76, 0x7E, 0xFF, 0x73, 0x2F, 0x35, 0x77, 0x57, 0xAD, 0xA3,\n\t0x57, 0x03, 0x2F, 0xFE, 0x0F, 0x59, 0x4D, 0x7B, 0x66, 0x9A, 0x9A, 0x13,\n\t0x46, 0x8A, 0xE4, 0xD0, 0x40, 0x7D, 0x09, 0xA3, 0xC2, 0x05, 0x2A, 0x50,\n\t0xF9, 0x08, 0xA9, 0xC1, 0x02, 0x68, 0x78, 0x22, 0x08, 0x0B, 0x9B, 0x0E,\n\t0x7C, 0x60, 0x02, 0xD8, 0xF8, 0xFE, 0xFF, 0x7F, 0xD1, 0x70, 0xFB, 0x86,\n\t0xE5, 0x44, 0xEF, 0x3B, 0xD5, 0xE9, 0xA2, 0xB6, 0x20, 0x7C, 0x08, 0x4C,\n\t0xE8, 0x28, 0x1B, 0x84, 0xD3, 0xC0, 0x21, 0xFA, 0x29, 0xC0, 0x2F, 0x27,\n\t0x96, 0xA9, 0xA8, 0x84, 0x84, 0x95, 0x13, 0x53, 0xAB, 0x5A, 0x50, 0x39,\n\t0x85, 0x48, 0x00, 0x86, 0x04, 0x01, 0x00, 0x73, 0xB5, 0x01, 0x1C, 0x10,\n\t0x8D, 0x46, 0x82, 0x28, 0xCB, 0x33, 0x51, 0x7E, 0xC4, 0x04, 0xCB, 0x5E,\n\t0x4B, 0x1F, 0x68, 0x46, 0x01, 0xA5, 0x98, 0x21, 0x00, 0x20, 0x20, 0x00,\n\t0x01, 0x04, 0x12, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x82, 0x81, 0xEA,\n\t0x39, 0x44, 0xC2, 0xF2, 0x59, 0xD3, 0x1C, 0xB0, 0xF7, 0x45, 0xF7, 0x8F,\n\t0x49, 0xE0, 0xF9, 0x60, 0xB4, 0x8C, 0x56, 0x81, 0x2F, 0xF9, 0xC4, 0x5E,\n\t0xD4, 0x1C, 0x36, 0xD4, 0xA1, 0xBB, 0x6A, 0x81, 0xDB, 0x65, 0x4A, 0xAA,\n\t0xAF, 0xB3, 0x94, 0x1D, 0x68, 0x74, 0x01, 0xDB, 0xE4, 0x91, 0x4F, 0x5A,\n\t0x5E, 0x1C, 0x19, 0xE4, 0x6C, 0xA4, 0x67, 0x13, 0x01, 0xF7, 0x09, 0x4D,\n\t0xB0, 0x61, 0x7D, 0xE8, 0xA7, 0xBE, 0x50, 0x99, 0x55, 0x97, 0x31, 0xC7,\n\t0x6C, 0xC9, 0xB4, 0xE7, 0xEC, 0x55, 0x3F, 0x39, 0x75, 0x53, 0x36, 0xDA,\n\t0xC8, 0x7E, 0x4E, 0xFB, 0xE2, 0x8E, 0x0D, 0xF8, 0x92, 0xB5, 0x69, 0x07,\n\t0x86, 0x00, 0x82, 0x75, 0x52, 0x1E, 0x9F, 0x7A, 0x70, 0xBA, 0xC4, 0x20,\n\t0xB5, 0xD5, 0xA9, 0xF5, 0x85, 0xD9, 0x60, 0x81, 0xD2, 0xB0, 0x76, 0x23,\n\t0x42, 0xDA, 0x82, 0x25, 0x8A, 0x7C, 0xE1, 0x02, 0xDB, 0xBA, 0xEE, 0x15,\n\t0x59, 0xC0, 0x29, 0x45, 0xEC, 0x6B, 0x37, 0xD8, 0xAF, 0x7D, 0x2C, 0xB0,\n\t0xEB, 0xF1, 0x89, 0xD0, 0x36, 0xBB, 0x87, 0x1D, 0xAB, 0xD8, 0xD4, 0x4D,\n\t0xE7, 0x3A, 0xB8, 0xCD, 0x84, 0x6E, 0x59, 0x5D, 0x94, 0x21, 0x4D, 0xEF,\n\t0x6C, 0x8E, 0x76, 0x10, 0x72, 0xAB, 0xDF, 0xEA, 0xD5, 0x14, 0x70, 0x36,\n\t0xBB, 0xA3, 0x82, 0x9D, 0xF3, 0x58, 0xA5, 0x7B, 0x0B, 0x14, 0x6A, 0x83,\n\t0xCD, 0xED, 0x00, 0x40, 0xEC, 0xF2, 0xDA, 0xD2, 0x7F, 0xCA, 0x04, 0xB7,\n\t0x92, 0x0B, 0xB7, 0x57, 0xA4, 0x3D, 0x36, 0x7D, 0xF5, 0xEF, 0x7B, 0xBA,\n\t0xFF, 0xED, 0x62, 0xFE, 0xC1, 0xE8, 0x7E, 0x32, 0xBE, 0x7F, 0x24, 0x5B,\n\t0x94, 0xCD, 0xBB, 0x4A, 0xF6, 0xEA, 0x67, 0x4E, 0xF6, 0x49, 0x25, 0x87,\n\t0x82, 0xB2, 0x27, 0x2C, 0x46, 0xD2, 0xEB, 0xD6, 0x81, 0xB4, 0x8B, 0xF1,\n\t0x0E, 0xF5, 0x70, 0xBA, 0x3A, 0xF5, 0xFF, 0x21, 0xB8, 0x51, 0x7F, 0x94,\n\t0x59, 0x88, 0xD5, 0xBA, 0x16, 0x1C, 0x17, 0x35, 0x65, 0xD2, 0x64, 0xC5,\n\t0x93, 0x56, 0x02, 0x3B, 0xDE, 0x4A, 0xB0, 0xE0, 0xEB, 0x55, 0x4B, 0x25,\n\t0x7C, 0x8E, 0xA6, 0x04, 0x68, 0xA3, 0x43, 0xDA, 0x12, 0xDB, 0x33, 0x1B,\n\t0xB2, 0xC8, 0x8D, 0xB3, 0xB2, 0x17, 0x16, 0xF6, 0x13, 0xF5, 0xE6, 0x09,\n\t0xD0, 0xED, 0x87, 0x06, 0x79, 0x9A, 0x02, 0x8D, 0x52, 0xC7, 0xD0, 0x2B,\n\t0x48, 0xD1, 0x94, 0x8D, 0x7C, 0x68, 0x38, 0x3E, 0x72, 0xD4, 0x1D, 0x34,\n\t0xCB, 0x0C, 0xF6, 0xA8, 0x21, 0xA5, 0x95, 0xD6, 0x34, 0xE6, 0x60, 0xA9,\n\t0x48, 0x19, 0x1C, 0xC6, 0x8B, 0x82, 0xF8, 0xA9, 0xAE, 0x23, 0x41, 0xCA,\n\t0x18, 0x34, 0x3D, 0x34, 0x16, 0x05, 0x96, 0x52, 0xA1, 0x07, 0x4D, 0xD4,\n\t0xDE, 0xB1, 0x24, 0x0F, 0x8D, 0xBA, 0xB7, 0x6C, 0xD0, 0x83, 0x86, 0x05,\n\t0xC9, 0x5D, 0x3B, 0xF7, 0xC1, 0xD0, 0x00, 0xB2, 0xF1, 0x7B, 0xD1, 0x50,\n\t0x50, 0xD4, 0x48, 0xC5, 0x28, 0xEA, 0xC7, 0x2B, 0x64, 0x58, 0x01, 0xB6,\n\t0x60, 0x4B, 0x99, 0xA4, 0x8B, 0x26, 0x33, 0xC7, 0x85, 0xA0, 0x60, 0x0D,\n\t0xB3, 0x79, 0x74, 0xD6, 0xC8, 0x15, 0x41, 0x5C, 0xA3, 0xB2, 0x16, 0x7A,\n\t0xD0, 0x1C, 0x7E, 0xCF, 0x4A, 0xDB, 0x9C, 0x51, 0x78, 0x2F, 0xE0, 0x87,\n\t0xA6, 0xF5, 0xA4, 0x81, 0xE5, 0xC4, 0x73, 0x3B, 0x5E, 0xD1, 0x0B, 0x33,\n\t0x33, 0x27, 0x88, 0xAD, 0x2D, 0x3E, 0x1A, 0x41, 0xDA, 0x83, 0xC6, 0xB1,\n\t0x53, 0x34, 0xE3, 0xC9, 0x2E, 0x4F, 0x2D, 0x68, 0xA5, 0x39, 0x0B, 0xA0,\n\t0xCE, 0xDF, 0xDA, 0xE1, 0xCC, 0x6B, 0x7F, 0xF2, 0x4A, 0x1E, 0x1A, 0xA9,\n\t0xCB, 0x38, 0xAD, 0x1D, 0xC2, 0xD0, 0x79, 0x3B, 0xD3, 0xDA, 0xE4, 0x97,\n\t0x72, 0xAD, 0x92, 0x7E, 0x9F, 0xFB, 0xF5, 0xF5, 0xD6, 0x7C, 0x6B, 0xE6,\n\t0x34, 0x73, 0x24, 0x65, 0xDD, 0xC7, 0xCF, 0x1E, 0x9A, 0x62, 0xED, 0x50,\n\t0xC3, 0x69, 0x5B, 0xCB, 0xC1, 0xFB, 0xEE, 0x5F, 0xD1, 0x0F, 0xC8, 0xCD,\n\t0x68, 0x45, 0x54, 0x5F, 0x67, 0x1E, 0xC9, 0xC0, 0x79, 0x43, 0x96, 0x24,\n\t0xF4, 0xD0, 0x08, 0xAB, 0x50, 0x4C, 0x99, 0x10, 0x54, 0xDC, 0x31, 0xB2,\n\t0xF3, 0xA9, 0x99, 0x99, 0x23, 0x43, 0xA9, 0xE6, 0xC7, 0xF7, 0x2E, 0x26,\n\t0xF5, 0x8C, 0xB9, 0x75, 0xB9, 0xB8, 0x6A, 0x62, 0x6F, 0xAB, 0x36, 0x9C,\n\t0x99, 0x33, 0xD4, 0x14, 0xC2, 0xA5, 0x06, 0xC8, 0x5C, 0xD8, 0x45, 0x3A,\n\t0x21, 0x94, 0x5B, 0x30, 0x74, 0xFA, 0xE7, 0x8B, 0x7E, 0x7B, 0x11, 0x06,\n\t0x86, 0x47, 0xE2, 0x00, 0xF5, 0x40, 0x86, 0x89, 0xD1, 0xD7, 0x79, 0xD4,\n\t0xE5, 0x5E, 0xAC, 0x65, 0x24, 0xBD, 0x81, 0x50, 0x79, 0xE1, 0xD4, 0xBA,\n\t0xC8, 0xA1, 0xFD, 0x84, 0xDA, 0x26, 0x56, 0x64, 0x02, 0x1A, 0xCA, 0xE4,\n\t0xC5, 0x55, 0x11, 0x5C, 0x60, 0xC1, 0xB5, 0xB2, 0xB9, 0xB8, 0x03, 0xAA,\n\t0x1E, 0x08, 0xD6, 0x1F, 0x08, 0x61, 0x47, 0x1D, 0xC3, 0xA1, 0xE2, 0x29,\n\t0x2C, 0x59, 0x8B, 0xDC, 0x76, 0xEB, 0x88, 0x87, 0x3A, 0xB6, 0x1E, 0x84,\n\t0x5C, 0xD4, 0xEF, 0xC0, 0xA7, 0xBE, 0xE8, 0x91, 0xC2, 0x83, 0xB0, 0x7A,\n\t0x03, 0xD6, 0x6B, 0xCC, 0x48, 0x88, 0xA5, 0xB5, 0x6F, 0xB3, 0x34, 0x8C,\n\t0x3B, 0x33, 0x8E, 0xC0, 0x2F, 0xE7, 0x43, 0xF4, 0xA5, 0xE7, 0xD0, 0x98,\n\t0xAB, 0xEF, 0xBF, 0xB5, 0xA5, 0x17, 0x6B, 0x9A, 0x8D, 0x98, 0xAD, 0x10,\n\t0x8E, 0x43, 0xB7, 0x22, 0x0E, 0x87, 0xFB, 0xBD, 0xAD, 0x98, 0xDD, 0xA2,\n\t0x0C, 0x9F, 0x00, 0xAC, 0xD8, 0x44, 0x96, 0x50, 0x43, 0xC4, 0x09, 0x1D,\n\t0xFC, 0xD0, 0x7A, 0xCA, 0x6E, 0x97, 0xCD, 0xBE, 0xBA, 0x3E, 0x31, 0x1B,\n\t0xB1, 0x1D, 0x83, 0xE5, 0x79, 0xEC, 0xA2, 0x41, 0xC9, 0x6C, 0x33, 0x0E,\n\t0x7B, 0x0C, 0x3F, 0x31, 0xCD, 0x80, 0x97, 0x5E, 0xD8, 0xE8, 0x6D, 0xA2,\n\t0xAE, 0xB4, 0x35, 0xF7, 0x79, 0x28, 0x6B, 0xF3, 0xB2, 0x00, 0x32, 0x97,\n\t0xB3, 0x8C, 0xA1, 0xC2, 0x6E, 0xAF, 0xB8, 0xDF, 0xE5, 0x3A, 0x0E, 0x80,\n\t0xA3, 0xB3, 0xBA, 0x1C, 0x67, 0xB0, 0x72, 0xDE, 0x70, 0x7A, 0x68, 0x1D,\n\t0x73, 0xE8, 0xBA, 0xA7, 0xC9, 0x3A, 0xD8, 0x90, 0x45, 0xFE, 0xE6, 0xE4,\n\t0x7A, 0xE1, 0x75, 0xF6, 0xB8, 0x5A, 0x38, 0x97, 0xF3, 0x40, 0xF4, 0x43,\n\t0x3F, 0x4B, 0x20, 0xB6, 0xEE, 0x65, 0x8D, 0x9F, 0x51, 0x19, 0xC1, 0xB9,\n\t0x66, 0x29, 0x91, 0x8D, 0x89, 0xFF, 0x3E, 0x86, 0x9F, 0xD9, 0xDD, 0x27,\n\t0xCB, 0x42, 0x52, 0x6D, 0x42, 0x68, 0x22, 0x5A, 0xAB, 0x79, 0x75, 0x94,\n\t0x53, 0xBD, 0xA0, 0xD8, 0x1D, 0xF3, 0x6A, 0x07, 0xB1, 0xDE, 0x29, 0x36,\n\t0xDE, 0x96, 0x22, 0x17, 0x63, 0x74, 0xAF, 0xFD, 0x46, 0x43, 0x95, 0xE2,\n\t0xD2, 0xC6, 0x74, 0xF8, 0x47, 0x8C, 0xA2, 0x86, 0x56, 0x7F, 0xEA, 0x1F,\n\t0xE5, 0xE6, 0x91, 0xB3, 0x95, 0x15, 0xA9, 0x5E, 0x55, 0xDB, 0x17, 0x6D,\n\t0xCB, 0x7A, 0xAB, 0xB0, 0xB8, 0x69, 0x0A, 0x43, 0x93, 0xA2, 0xDE, 0x6A,\n\t0x13, 0x78, 0xC9, 0x2A, 0xAE, 0xC9, 0x6C, 0xDD, 0xC8, 0x0D, 0x29, 0xD4,\n\t0xBA, 0x1B, 0x07, 0xEF, 0x9B, 0x49, 0x34, 0xA6, 0x0E, 0xF3, 0xC1, 0x54,\n\t0xC8, 0x7C, 0x26, 0x14, 0x4F, 0x2D, 0x17, 0xED, 0xCD, 0x05, 0x47, 0xBF,\n\t0x77, 0xF4, 0x8F, 0x80, 0x72, 0xCE, 0x2A, 0x83, 0xFC, 0x85, 0x78, 0xFB,\n\t0x40, 0xE9, 0x28, 0xF6, 0xAC, 0x47, 0x5F, 0x3D, 0x75, 0x19, 0xC9, 0xBE,\n\t0x15, 0x94, 0x03, 0x61, 0xD6, 0x46, 0xBC, 0xF1, 0xE2, 0x8D, 0xCC, 0x6B,\n\t0xF5, 0x2B, 0xFB, 0xA3, 0x25, 0xD2, 0x53, 0x1A, 0x8E, 0x28, 0x92, 0x32,\n\t0x3A, 0xC0, 0x6F, 0x53, 0xDB, 0x86, 0x3A, 0x36, 0x35, 0xFD, 0x5C, 0xD0,\n\t0x4A, 0xDC, 0x19, 0xEC, 0x50, 0xCE, 0x5D, 0x31, 0x6C, 0x24, 0xCE, 0x0D,\n\t0x57, 0x53, 0x58, 0xC1, 0x9F, 0xBD, 0xF9, 0x08, 0xC9, 0xBF, 0x42, 0x7C,\n\t0x04, 0xF4, 0xA6, 0xCF, 0xF3, 0xFB, 0x7C, 0xEC, 0xF2, 0x30, 0x2C, 0x2D,\n\t0x32, 0xD8, 0x02, 0x2E, 0x1D, 0xB6, 0x64, 0x7E, 0x0B, 0x98, 0x05, 0x3C,\n\t0x5C, 0x06, 0x51, 0x28, 0x9D, 0x31, 0x9A, 0x15, 0x79, 0x22, 0x74, 0xDC,\n\t0x48, 0x4A, 0x1D, 0x83, 0x19, 0xD8, 0x91, 0xF4, 0x05, 0xF6, 0xBC, 0x85,\n\t0x5E, 0x6C, 0x44, 0xAD, 0x3B, 0xE5, 0x12, 0xA7, 0xE2, 0x95, 0xD4, 0xB9,\n\t0xC0, 0xB0, 0x1C, 0x44, 0xBC, 0x2D, 0x24, 0xD6, 0xBB, 0xB6, 0x39, 0x8C,\n\t0x15, 0x91, 0xF0, 0xCB, 0x77, 0x82, 0x19, 0xB1, 0x66, 0x06, 0xD3, 0x85,\n\t0x38, 0xEE, 0x06, 0x8E, 0x37, 0x70, 0xA3, 0x14, 0xCF, 0x33, 0x73, 0x1A,\n\t0xF2, 0xDA, 0x0E, 0xA7, 0x68, 0xA3, 0x7D, 0xF6, 0xE9, 0xCC, 0xBE, 0xDB,\n\t0xC7, 0x4E, 0xDD, 0x36, 0xC5, 0x3B, 0x15, 0x2D, 0x31, 0x1F, 0x21, 0xBA,\n\t0xC1, 0xD8, 0x1C, 0x44, 0x21, 0x37, 0x3B, 0xC0, 0x26, 0x69, 0x5A, 0xE9,\n\t0xCC, 0xD7, 0x54, 0xA3, 0x26, 0x97, 0x61, 0x3D, 0x65, 0x07, 0x6B, 0xDE,\n\t0xC4, 0x70, 0x99, 0x69, 0x79, 0x5B, 0xFB, 0xC2, 0x2E, 0x77, 0xF2, 0xD1,\n\t0x13, 0xA7, 0x9E, 0x61, 0xDA, 0xB4, 0x31, 0x59, 0x7C, 0x80, 0x63, 0xE2,\n\t0xB7, 0x22, 0x65, 0x4E, 0x85, 0xB4, 0x5E, 0xE3, 0xC0, 0xB7, 0x62, 0x30,\n\t0x87, 0xDD, 0x53, 0x83, 0x36, 0xCE, 0x1D, 0xCF, 0x99, 0x72, 0x37, 0xCD,\n\t0x1C, 0x2F, 0x25, 0xF0, 0x0B, 0xC2, 0x30, 0x45, 0x0D, 0x9E, 0x4B, 0x82,\n\t0x56, 0xC8, 0xA3, 0xFE, 0xDD, 0xC5, 0x98, 0x16, 0x98, 0x3B, 0x68, 0xC0,\n\t0x38, 0xF2, 0x9F, 0x48, 0xEA, 0x2B, 0x3A, 0x2D, 0x25, 0x25, 0x81, 0xEA,\n\t0x10, 0xE8, 0x30, 0x73, 0x89, 0xA5, 0x8B, 0x6B, 0xDF, 0xAA, 0x37, 0xB8,\n\t0xD3, 0x52, 0x78, 0xCF, 0x2F, 0xF7, 0x76, 0x98, 0x97, 0xF8, 0xC9, 0x57,\n\t0x41, 0x91, 0xAA, 0x31, 0xE3, 0x2D, 0x28, 0x2E, 0x33, 0xD1, 0x39, 0x92,\n\t0x9D, 0xFC, 0xF0, 0xF1, 0x63, 0x50, 0x20, 0x0E, 0xC4, 0xA6, 0x76, 0x00,\n\t0xEE, 0xA3, 0x56, 0xC7, 0x5A, 0xEF, 0xA9, 0x7F, 0x6F, 0x08, 0x84, 0xB3,\n\t0x75, 0x01, 0x45, 0x7B, 0x89, 0x88, 0x7A, 0x32, 0x71, 0x35, 0x28, 0x7D,\n\t0x58, 0xF4, 0x6C, 0x9B, 0x96, 0x69, 0x9B, 0x3D, 0x48, 0xA8, 0x72, 0x5A,\n\t0x14, 0xE2, 0x11, 0x77, 0x71, 0x85, 0x41, 0xB3, 0x79, 0x69, 0x0A, 0x0D,\n\t0x91, 0xC1, 0xD4, 0x63, 0x20, 0x80, 0x01, 0x76, 0xE7, 0x0A, 0x52, 0x92,\n\t0x66, 0x68, 0x2F, 0xE5, 0x2E, 0xEC, 0xAE, 0x8F, 0xC0, 0x43, 0x02, 0x8A,\n\t0x5D, 0x52, 0x9B, 0x08, 0xB7, 0x6C, 0x90, 0x74, 0x57, 0x79, 0x59, 0x9D,\n\t0x6E, 0x6B, 0x32, 0x93, 0x5B, 0x5E, 0x58, 0x14, 0xDA, 0xD0, 0xF5, 0xC0,\n\t0x3F, 0x6A, 0x07, 0x84, 0x57, 0x2E, 0xAA, 0x48, 0x84, 0xF5, 0x96, 0x88,\n\t0xB9, 0x42, 0x78, 0xB7, 0xF2, 0x31, 0x4F, 0xF8, 0x81, 0x7E, 0xD5, 0x3E,\n\t0xD8, 0xB9, 0xAC, 0xF3, 0x7E, 0xFC, 0x7A, 0xBA, 0x09, 0xE7, 0x4B, 0x18,\n\t0x59, 0x58, 0x1F, 0x4E, 0xFC, 0xF5, 0x55, 0x77, 0xCA, 0x2C, 0x65, 0xB3,\n\t0x5C, 0xF4, 0x1D, 0x64, 0x98, 0xA1, 0x32, 0x31, 0x33, 0x88, 0x80, 0xCE,\n\t0xEC, 0x22, 0x3E, 0xDE, 0x56, 0x83, 0x2B, 0xAF, 0x49, 0xA9, 0x71, 0xB0,\n\t0x7A, 0x1E, 0x9D, 0x57, 0x0E, 0xC0, 0x23, 0xC5, 0x1E, 0x7A, 0xE3, 0xD0,\n\t0x5E, 0x23, 0x12, 0xED, 0x8E, 0x90, 0xBB, 0xFB, 0xF4, 0xDA, 0xAF, 0x1B,\n\t0x07, 0x22, 0x2D, 0x76, 0xE5, 0x70, 0x09, 0x30, 0x11, 0x5B, 0xED, 0x90,\n\t0xD3, 0xC2, 0x91, 0x14, 0x71, 0xE5, 0x5E, 0xFC, 0x08, 0xFA, 0x46, 0x31,\n\t0x1D, 0xA3, 0xDC, 0xEC, 0x0A, 0x5F, 0xFA, 0xDB, 0xB8, 0xAF, 0x52, 0xD6,\n\t0x5C, 0xAE, 0x44, 0x91, 0xA8, 0x32, 0x8E, 0x21, 0x49, 0x04, 0x06, 0x0E,\n\t0x10, 0x9E, 0x74, 0x25, 0x39, 0xD1, 0x27, 0xD4, 0xB1, 0x8D, 0x85, 0x36,\n\t0xC5, 0x49, 0x9F, 0x05, 0xF4, 0x4D, 0x80, 0xD6, 0x75, 0x8D, 0x87, 0xB7,\n\t0xA8, 0xD6, 0x30, 0xA5, 0x8B, 0x96, 0x8A, 0xA6, 0x47, 0xCC, 0x2D, 0x76,\n\t0x29, 0x13, 0x2E, 0xF5, 0xB3, 0x23, 0x70, 0x4B, 0xE9, 0xDC, 0x72, 0xA8,\n\t0x94, 0x98, 0x05, 0xAE, 0x69, 0x1A, 0x2D, 0xA1, 0x1F, 0x59, 0xBD, 0xD2,\n\t0x28, 0xA3, 0x5C, 0xCA, 0x0A, 0x25, 0x1E, 0x97, 0x95, 0x96, 0xC9, 0x05,\n\t0x59, 0x8C, 0xDF, 0x12, 0x11, 0x68, 0x81, 0x62, 0x02, 0xB7, 0x06, 0x78,\n\t0x11, 0x44, 0x9C, 0x04, 0x2D, 0xAE, 0x91, 0xD6, 0x87, 0xEE, 0x20, 0xF5,\n\t0xD0, 0x15, 0xB4, 0xD6, 0xFB, 0x96, 0x88, 0xF9, 0x00, 0x3B, 0xAE, 0xDE,\n\t0xD3, 0xA0, 0xD5, 0xAA, 0x7C, 0x60, 0xE0, 0x7B, 0x76, 0xE0, 0xE5, 0xDF,\n\t0x18, 0x3D, 0x83, 0xB9, 0x01, 0x35, 0xEC, 0x68, 0x01, 0x7E, 0x03, 0xB0,\n\t0xE9, 0xC3, 0x61, 0xAD, 0x93, 0xE4, 0xDB, 0x1B, 0xAF, 0xE9, 0xE0, 0xAD,\n\t0xF3, 0x90, 0x99, 0xDD, 0x0C, 0x9E, 0x32, 0xBB, 0x48, 0x7E, 0xBA, 0x67,\n\t0x1E, 0x21, 0x73, 0xB7, 0xC5, 0x60, 0x5E, 0x2F, 0x33, 0x1E, 0x63, 0x64,\n\t0xD8, 0x49, 0x73, 0x88, 0x9A, 0x8F, 0xE1, 0x74, 0xAA, 0x69, 0x08, 0xE8,\n\t0xAD, 0xB1, 0x41, 0xC4, 0x9A, 0x70, 0x3F, 0x37, 0x5F, 0x4B, 0x47, 0x7B,\n\t0xCC, 0xAE, 0x0D, 0x19, 0x5A, 0x17, 0x4D, 0xC9, 0x3B, 0xB4, 0x9C, 0x33,\n\t0x57, 0xC0, 0xDD, 0x96, 0x79, 0xCC, 0xA2, 0x53, 0xF8, 0xDD, 0x75, 0xE7,\n\t0xA5, 0x2A, 0x19, 0x9E, 0x4D, 0xBD, 0x5A, 0x85, 0x01, 0x19, 0x3E, 0x6C,\n\t0xE0, 0x58, 0x4B, 0x6F, 0xCD, 0x47, 0xB0, 0x2C, 0x5F, 0x0E, 0xA2, 0xBD,\n\t0xDF, 0xA8, 0xF1, 0xDA, 0x89, 0x43, 0x8E, 0xF9, 0x19, 0xA3, 0x17, 0xBD,\n\t0x5C, 0x2B, 0x23, 0x11, 0xD5, 0xB4, 0xCF, 0x95, 0x60, 0xDC, 0xEF, 0xB4,\n\t0x79, 0xA4, 0x3D, 0x01, 0xFE, 0x77, 0x73, 0x4B, 0x2F, 0xF6, 0x00, 0xBC,\n\t0x18, 0xD1, 0x24, 0x6F, 0xD5, 0x6E, 0x97, 0x3E, 0xDE, 0x9A, 0xE2, 0x5D,\n\t0x0C, 0x92, 0xA1, 0x7F, 0xF5, 0xFB, 0x75, 0x7D, 0x8E, 0x16, 0xB6, 0x49,\n\t0x70, 0x5A, 0x45, 0x77, 0x6E, 0xAC, 0x41, 0xC0, 0x67, 0x3C, 0xB1, 0x0F,\n\t0xC1, 0x5A, 0x7C, 0x6F, 0x66, 0x11, 0xE8, 0x3F, 0x70, 0xCC, 0x1E, 0x40,\n\t0xE2, 0x1C, 0x70, 0xF0, 0x06, 0x65, 0x33, 0x95, 0x00, 0x35, 0x23, 0x6A,\n\t0x23, 0xB7, 0xF8, 0x58, 0x0F, 0xAD, 0x2D, 0x6B, 0x61, 0x39, 0x4B, 0xAF,\n\t0x4F, 0x24, 0xAC, 0x74, 0x3E, 0x30, 0x70, 0xD2, 0x66, 0x0A, 0xC1, 0x98,\n\t0xB7, 0x22, 0xBB, 0x70, 0x05, 0x09, 0x2F, 0xB6, 0xCE, 0xC5, 0xB6, 0x3B,\n\t0x88, 0x7A, 0xAA, 0x77, 0x10, 0xE9, 0xE3, 0xA7, 0x13, 0x3E, 0x9E, 0x50,\n\t0xE0, 0x1D, 0x22, 0x61, 0x70, 0xAD, 0x1F, 0xC7, 0x8F, 0x85, 0xF1, 0x36,\n\t0x2C, 0xEA, 0xBC, 0x6D, 0x3D, 0xC4, 0xB3, 0x12, 0xD1, 0x92, 0xAF, 0xA7,\n\t0x74, 0x4A, 0x16, 0x7A, 0x4B, 0xE0, 0x07, 0x6A, 0x6D, 0x50, 0xFD, 0x99,\n\t0x83, 0x06, 0xCC, 0x17, 0x4E, 0x05, 0xBC, 0x97, 0x79, 0x63, 0x10, 0x8D,\n\t0x5D, 0xAA, 0x62, 0xE5, 0xBB, 0x1B, 0x4C, 0xFA, 0x5D, 0xF4, 0x89, 0x90,\n\t0xBD, 0xD1, 0xD5, 0xE1, 0x2A, 0xCC, 0x02, 0x47, 0x4E, 0x26, 0xC0, 0xBD,\n\t0x86, 0xA0, 0xCA, 0xFA, 0x92, 0x1C, 0xB9, 0xDE, 0x65, 0xF7, 0x8F, 0xAC,\n\t0xCE, 0x4B, 0x36, 0x6A, 0x05, 0x5D, 0x8E, 0xFA, 0x77, 0xB2, 0x89, 0x57,\n\t0x62, 0x66, 0xE7, 0x28, 0x3D, 0x7D, 0x72, 0xE0, 0x51, 0x20, 0x9D, 0xDB,\n\t0xD7, 0x39, 0x27, 0x89, 0x02, 0xAA, 0x5E, 0x64, 0x4F, 0xD4, 0x9E, 0xB8,\n\t0x1D, 0x0F, 0x58, 0xEC, 0x34, 0x00, 0xCD, 0x81, 0xA3, 0xD7, 0xDE, 0xE0,\n\t0xC2, 0x17, 0x61, 0xBB, 0x71, 0x38, 0xCB, 0x86, 0xCB, 0xBD, 0xFB, 0x3B,\n\t0x7F, 0x4E, 0xB7, 0x01, 0xDF, 0x84, 0x6E, 0x2A, 0xEE, 0x15, 0x3C, 0x53,\n\t0x20, 0x65, 0x2B, 0xC5, 0xDA, 0x40, 0x85, 0xE9, 0xC2, 0x53, 0x25, 0x95,\n\t0x15, 0xEB, 0xB7, 0x70, 0xA0, 0x85, 0x60, 0x06, 0xFE, 0x0F, 0x61, 0x30,\n\t0x00, 0x77, 0x19, 0x27, 0xED, 0xB7, 0xBA, 0x5C, 0x92, 0xD7, 0xEF, 0xE1,\n\t0xBE, 0x0D, 0xB4, 0x4C, 0x45, 0x17, 0x2C, 0xD5, 0x6C, 0x74, 0xC7, 0x9C,\n\t0xE9, 0x3C, 0x2B, 0x28, 0xD0, 0xBA, 0x03, 0xD0, 0x6F, 0x3C, 0x11, 0xBA,\n\t0xEB, 0x8B, 0xA7, 0x16, 0x1B, 0xFB, 0x71, 0x59, 0x42, 0x93, 0xB8, 0x86,\n\t0xEA, 0xE4, 0xE0, 0xB5, 0xBA, 0xD9, 0x08, 0xA9, 0x3B, 0xB4, 0x6D, 0xCE,\n\t0xD7, 0xD8, 0x8A, 0x35, 0x70, 0x7D, 0x63, 0x34, 0x57, 0x25, 0xD4, 0x6D,\n\t0x63, 0x26, 0x17, 0xF4, 0x66, 0x5B, 0x10, 0x0F, 0x97, 0x04, 0xCF, 0xD5,\n\t0x76, 0xB6, 0xF4, 0x32, 0x8F, 0xF7, 0x2B, 0x34, 0x26, 0xBA, 0xF1, 0xE0,\n\t0xF3, 0x9A, 0x9A, 0x38, 0xE4, 0xE9, 0xF5, 0xD1, 0xDC, 0x69, 0xDA, 0x78,\n\t0x27, 0xCC, 0x74, 0x4A, 0xA0, 0x7F, 0x5B, 0x16, 0x9B, 0xEF, 0x97, 0xEF,\n\t0xCE, 0xEC, 0x5C, 0xE5, 0x4D, 0xA4, 0x41, 0xBA, 0xD9, 0x99, 0xAE, 0x41,\n\t0x14, 0xA8, 0x91, 0x1E, 0xC4, 0x1C, 0xF1, 0x98, 0xA0, 0x49, 0x67, 0xFC,\n\t0x79, 0x0C, 0x1C, 0x2B, 0xAB, 0xF6, 0xF1, 0xBD, 0x46, 0x45, 0x80, 0xEF,\n\t0x58, 0x91, 0x71, 0x9A, 0x6A, 0x99, 0xEC, 0xA7, 0x91, 0xB1, 0x49, 0xAD,\n\t0x58, 0xE2, 0xA6, 0xE9, 0x3E, 0x36, 0x6F, 0x9D, 0x9B, 0x1F, 0x52, 0x54,\n\t0xED, 0x25, 0xEE, 0x6E, 0x7E, 0xEB, 0xEC, 0xD1, 0x97, 0x08, 0x7A, 0x5A,\n\t0x47, 0x57, 0xF0, 0x45, 0x0A, 0x79, 0xF8, 0x87, 0x9F, 0x6E, 0x1D, 0xF4,\n\t0x5B, 0xDE, 0x8C, 0x17, 0x34, 0x74, 0x12, 0x3B, 0x4C, 0xDB, 0x9B, 0xBE,\n\t0x5E, 0x2D, 0x2C, 0x74, 0x5A, 0x10, 0xB9, 0x72, 0x75, 0x7F, 0x1C, 0x2B,\n\t0xA2, 0x6B, 0x13, 0x40, 0x4C, 0xE1, 0xAC, 0x68, 0xA0, 0x35, 0x2E, 0xA4,\n\t0xEE, 0x71, 0x95, 0x19, 0x31, 0x50, 0xA3, 0xE3, 0x52, 0x38, 0x17, 0x96,\n\t0x26, 0xF0, 0x85, 0xEE, 0xFE, 0x69, 0x60, 0xF4, 0xE0, 0x6D, 0x6E, 0x00,\n\t0x0B, 0x36, 0x3B, 0x1E, 0x67, 0xF9, 0x0F, 0xED, 0x2B, 0x14, 0xF1, 0x64,\n\t0xAB, 0xB8, 0x83, 0x0D, 0xB2, 0x0C, 0x53, 0x73, 0xD9, 0x7E, 0x35, 0x4C,\n\t0x40, 0xA6, 0x90, 0x69, 0x68, 0xF6, 0x8E, 0xC7, 0xE5, 0xBB, 0x7E, 0x51,\n\t0x21, 0x66, 0xFD, 0xC3, 0x69, 0x35, 0xDC, 0x86, 0x76, 0x4B, 0x0D, 0x08,\n\t0x4C, 0xA2, 0xE9, 0xF1, 0x61, 0xAA, 0x9E, 0x0C, 0xAD, 0x8C, 0xAB, 0x2E,\n\t0x16, 0x04, 0x2F, 0xC4, 0xDA, 0x88, 0xE4, 0x30, 0x4F, 0x66, 0xB9, 0x13,\n\t0xFC, 0xA1, 0x26, 0xF8, 0x61, 0xFD, 0xB0, 0x62, 0x0A, 0x1F, 0xA1, 0x94,\n\t0x46, 0x4A, 0xAF, 0x3B, 0x06, 0x72, 0x23, 0x01, 0xAF, 0xAF, 0x75, 0x4A,\n\t0x1F, 0x97, 0x17, 0x3E, 0xAA, 0x6C, 0x21, 0x5C, 0xA9, 0xE5, 0x03, 0xBC,\n\t0xEF, 0x7C, 0x5C, 0xD6, 0xFA, 0xE8, 0x1C, 0x90, 0x8F, 0xDC, 0xE8, 0x52,\n\t0xA9, 0x48, 0x3C, 0x4F, 0x17, 0x49, 0x2C, 0x9B, 0xBC, 0x36, 0xF7, 0xCC,\n\t0x02, 0x7B, 0x45, 0xA7, 0x38, 0x46, 0xA7, 0xA4, 0x96, 0x3F, 0xBA, 0x6F,\n\t0x1F, 0xB1, 0x3E, 0xA5, 0x93, 0x54, 0x0B, 0x7E, 0xDA, 0xD5, 0x8F, 0x5D,\n\t0x5C, 0x61, 0x13, 0x4B, 0xA4, 0x39, 0xD0, 0x40, 0x8A, 0x8D, 0x09, 0x04,\n\t0x5D, 0x90, 0xE2, 0x37, 0xAD, 0x0E, 0x1C, 0xCD, 0x5C, 0xF9, 0x3A, 0x82,\n\t0xBA, 0x09, 0x3A, 0x54, 0xC6, 0xF7, 0x05, 0x2A, 0x62, 0xB3, 0xCC, 0xCA,\n\t0x28, 0xD0, 0x9E, 0x35, 0x73, 0xF8, 0xDE, 0xE4, 0x77, 0x8C, 0x2D, 0xA9,\n\t0xF0, 0xE6, 0x0A, 0x42, 0xCC, 0x93, 0xF6, 0x6A, 0xC7, 0x47, 0x0D, 0x7C,\n\t0xDE, 0xD5, 0x4A, 0x84, 0xFA, 0x36, 0xEF, 0xBF, 0x0C, 0x7E, 0xDF, 0x5D,\n\t0x61, 0xB9, 0x4F, 0x2F, 0x53, 0x28, 0x72, 0x0C, 0x73, 0x26, 0x5E, 0xD7,\n\t0xA2, 0x9E, 0xD5, 0x43, 0xDA, 0x0B, 0xC7, 0xB8, 0x4A, 0xF9, 0x71, 0x59,\n\t0xB5, 0x06, 0x19, 0xE3, 0xEE, 0xFD, 0xDE, 0x18, 0x5B, 0x19, 0x00, 0x27,\n\t0xB6, 0x31, 0x10, 0x6F, 0x05, 0xA0, 0x9C, 0xE0, 0xB4, 0x9F, 0x06, 0x51,\n\t0x4D, 0xD1, 0xBC, 0x3F, 0x92, 0x09, 0x20, 0x2F, 0x34, 0xEA, 0x2C, 0x6C,\n\t0x4F, 0x51, 0x47, 0x09, 0x32, 0xC1, 0x0A, 0xBB, 0x6D, 0x45, 0x41, 0x7F,\n\t0xCE, 0xC1, 0x08, 0xB3, 0x62, 0x7D, 0xF7, 0x2B, 0xFD, 0xA1, 0xD8, 0xD4,\n\t0x2D, 0x79, 0x64, 0x4E, 0xD0, 0xE1, 0xF6, 0x54, 0xAE, 0x2E, 0xB3, 0x8D,\n\t0x03, 0x40, 0x5C, 0xFA, 0x7B, 0xB3, 0xD1, 0x65, 0x0A, 0xF3, 0x13, 0x5B,\n\t0xFE, 0x21, 0x3A, 0xDB, 0x2A, 0xEA, 0x65, 0xF0, 0xB0, 0xC5, 0x46, 0xD3,\n\t0x41, 0xC1, 0x57, 0x80, 0x0B, 0x1B, 0xF7, 0xE9, 0x95, 0xF8, 0xC5, 0xCF,\n\t0x03, 0x18, 0xC1, 0x7A, 0xA1, 0x8F, 0x96, 0xB4, 0xA2, 0xAF, 0x56, 0x30,\n\t0x34, 0x6E, 0x6D, 0x81, 0xBA, 0x25, 0x30, 0xF7, 0xC8, 0x5D, 0xB9, 0xD5,\n\t0x42, 0x99, 0x40, 0x56, 0xA3, 0xCD, 0x11, 0x5B, 0x42, 0x80, 0x81, 0xDE,\n\t0xCB, 0x27, 0x9E, 0xA3, 0xEF, 0xB6, 0x6F, 0xD9, 0x5A, 0x5E, 0xBD, 0x94,\n\t0xAC, 0xA5, 0x01, 0x58, 0x07, 0x10, 0x4F, 0xC7, 0xBC, 0xDC, 0x6D, 0x87,\n\t0x31, 0x6A, 0x18, 0xC9, 0xA5, 0xBE, 0x20, 0x98, 0x97, 0xA5, 0xFA, 0xA5,\n\t0xD9, 0x4E, 0xBB, 0x5F, 0x66, 0xB3, 0x53, 0x5F, 0x35, 0xB9, 0x9B, 0xCF,\n\t0xAD, 0xB1, 0x8C, 0xDA, 0x60, 0x8B, 0x88, 0x69, 0x09, 0x4E, 0x75, 0x6A,\n\t0x2F, 0x92, 0x89, 0xBE, 0x7A, 0x6A, 0xFF, 0x1C, 0x70, 0xBB, 0x97, 0xD4,\n\t0x5E, 0x12, 0x7C, 0x8B, 0x4C, 0x65, 0xBB, 0x54, 0x55, 0xE8, 0x39, 0x94,\n\t0xEE, 0xDE, 0xEF, 0xD6, 0x0E, 0x8F, 0xEB, 0x73, 0x53, 0x83, 0xAD, 0xDF,\n\t0xB3, 0xB9, 0x1D, 0x49, 0xC1, 0x69, 0x89, 0xCF, 0x61, 0x05, 0x15, 0x3C,\n\t0x85, 0x48, 0x62, 0x0B, 0x9B, 0x12, 0x0D, 0x81, 0x41, 0x8B, 0xE1, 0x9F,\n\t0x2D, 0x5A, 0xF8, 0x1D, 0x58, 0xA6, 0x20, 0x38, 0xD5, 0x36, 0x1B, 0xB6,\n\t0xF4, 0x7E, 0x75, 0xEC, 0xBE, 0xAD, 0x88, 0x5D, 0xB5, 0x14, 0x65, 0x00,\n\t0xA1, 0x0C, 0x7C, 0x95, 0x49, 0xA1, 0xB1, 0x94, 0x20, 0x2E, 0x56, 0x5E,\n\t0x03, 0xE9, 0x45, 0x49, 0x1E, 0xA5, 0x08, 0xEE, 0xFC, 0x6A, 0x4B, 0x98,\n\t0xC5, 0x11, 0xC0, 0x65, 0xEF, 0x4D, 0x5D, 0xB3, 0xD4, 0xAB, 0x57, 0x7B,\n\t0x3B, 0x74, 0xD7, 0x16, 0x6E, 0x0F, 0x15, 0xDF, 0xB9, 0x70, 0xCE, 0x17,\n\t0xD6, 0x18, 0xE4, 0xC4, 0xC9, 0xD3, 0x74, 0x66, 0x8D, 0xCB, 0x5A, 0x63,\n\t0x38, 0xAC, 0x40, 0x85, 0x10, 0xD2, 0xA1, 0x6D, 0x42, 0xAD, 0xA2, 0xBE,\n\t0x97, 0x80, 0xE7, 0x7E, 0x3F, 0x88, 0x8F, 0xF4, 0xB2, 0x9B, 0xA7, 0xA6,\n\t0x2D, 0x46, 0xE2, 0x1A, 0x3E, 0x40, 0xBB, 0xDF, 0x18, 0xC0, 0xED, 0xA7,\n\t0x6E, 0xF0, 0x6D, 0x85, 0xE0, 0x6E, 0x53, 0xCB, 0xDF, 0x6D, 0xB8, 0xB9,\n\t0xA9, 0xDB, 0x3B, 0xBC, 0xD4, 0x54, 0x1E, 0xE3, 0x8E, 0xA3, 0xB9, 0x54,\n\t0x6F, 0xC3, 0x00, 0xEF, 0x39, 0x4C, 0x48, 0xD5, 0x35, 0x27, 0xA0, 0xDC,\n\t0xB3, 0x86, 0xDE, 0x04, 0x1E, 0x6A, 0xC7, 0xE2, 0x18, 0x7D, 0xA7, 0x89,\n\t0xFE, 0x1A, 0x15, 0xDF, 0x47, 0xC8, 0x30, 0x77, 0x5C, 0xBB, 0x3A, 0x82,\n\t0x23, 0x5E, 0xAD, 0x63, 0xBA, 0x5D, 0x56, 0x46, 0x86, 0x29, 0xC9, 0x40,\n\t0xFE, 0x2B, 0xB2, 0x28, 0x50, 0xF3, 0xE5, 0x59, 0x8A, 0xD6, 0xDB, 0x91,\n\t0xB6, 0x48, 0x4C, 0xD1, 0x54, 0x69, 0x00, 0x9A, 0xE5, 0x26, 0x92, 0xF5,\n\t0x73, 0xDF, 0x28, 0x3A, 0xB0, 0x2C, 0xDD, 0x6A, 0xC4, 0xA2, 0xC1, 0x7B,\n\t0x95, 0x5B, 0x99, 0x16, 0x6D, 0x29, 0xB9, 0x53, 0x76, 0x99, 0xCC, 0xB9,\n\t0xDB, 0x10, 0xE8, 0x4D, 0x23, 0x3D, 0x4F, 0xEC, 0xF7, 0x18, 0xEC, 0x09,\n\t0xD7, 0xDA, 0x85, 0x2C, 0x85, 0xE9, 0xAE, 0x25, 0xC3, 0x18, 0xFC, 0x46,\n\t0x32, 0xDE, 0xCC, 0x15, 0x68, 0x6A, 0x6F, 0xD0, 0x31, 0xCD, 0x5D, 0xD8,\n\t0xF8, 0x3B, 0x4E, 0x41, 0x9F, 0xC0, 0x5F, 0xBA, 0x11, 0xF0, 0xC1, 0xAF,\n\t0x68, 0x06, 0x98, 0x15, 0xB7, 0x75, 0x45, 0xCD, 0xE3, 0x8E, 0xBA, 0x1A,\n\t0x01, 0x43, 0xCE, 0x73, 0x90, 0x3E, 0x90, 0x0B, 0x48, 0x6E, 0xD6, 0x08,\n\t0x82, 0x0B, 0x51, 0x2C, 0x3A, 0xE2, 0x0C, 0xD6, 0xA2, 0x4D, 0x43, 0xE1,\n\t0xD9, 0x9F, 0x41, 0x5B, 0x93, 0x6C, 0xE1, 0xAE, 0x55, 0x0B, 0xBC, 0x25,\n\t0x86, 0x1F, 0xCA, 0x32, 0xDE, 0x1B, 0x16, 0x07, 0x91, 0x50, 0x12, 0x16,\n\t0xB5, 0x3C, 0x55, 0x1A, 0x73, 0x64, 0x11, 0x5C, 0xE4, 0x5D, 0x27, 0x69,\n\t0xAF, 0x74, 0x4A, 0xE2, 0xDF, 0x99, 0x0D, 0x10, 0x3B, 0x5C, 0x89, 0x31,\n\t0x9B, 0x7F, 0xA2, 0xB0, 0x38, 0x87, 0x69, 0xD0, 0x89, 0x30, 0x92, 0x3A,\n\t0x84, 0xC0, 0x56, 0x4C, 0xCD, 0x4C, 0x49, 0x06, 0x5E, 0x72, 0x1E, 0xC6,\n\t0x01, 0xCF, 0xCD, 0x43, 0xB9, 0x4B, 0x38, 0x42, 0xB6, 0x9D, 0x20, 0x9C,\n\t0x15, 0x88, 0x7C, 0xEA, 0x8A, 0xE3, 0x2A, 0xDC, 0x09, 0x20, 0x16, 0x63,\n\t0x58, 0x02, 0x7D, 0x02, 0x72, 0x97, 0x2D, 0x46, 0x59, 0xEB, 0xE9, 0x33,\n\t0x59, 0xA9, 0xCF, 0x7C, 0x73, 0xCD, 0xC6, 0xB3, 0x29, 0xD6, 0xB4, 0xD1,\n\t0x19, 0xF7, 0xF6, 0x4D, 0x8E, 0xDB, 0xD9, 0xFA, 0xDC, 0x7C, 0x7F, 0x26,\n\t0x9E, 0xFA, 0x53, 0xD0, 0xA3, 0x3B, 0xB6, 0x6F, 0xEC, 0x03, 0x40, 0x12,\n\t0xE3, 0xCE, 0x94, 0x6F, 0x38, 0xEC, 0x42, 0x7B, 0xC5, 0x71, 0x09, 0x33,\n\t0xC5, 0xF1, 0x66, 0xA4, 0x8D, 0xAB, 0xF5, 0xE5, 0x32, 0xDE, 0x64, 0x3B,\n\t0xFF, 0xA2, 0x8C, 0x58, 0xD0, 0x29, 0xF3, 0x33, 0xFF, 0x7D, 0xEF, 0x37,\n\t0x9B, 0xF8, 0xF8, 0x0D, 0xCC, 0xE5, 0x0D, 0x3B, 0x15, 0xAD, 0x25, 0xE7,\n\t0x14, 0x2A, 0xD8, 0xD8, 0x67, 0xD3, 0x91, 0xBE, 0xEB, 0x5F, 0x74, 0x4A,\n\t0x83, 0x60, 0x30, 0x61, 0x61, 0x20, 0x6A, 0x1E, 0xF7, 0xDA, 0x31, 0x4C,\n\t0xA9, 0xED, 0x2B, 0x1A, 0xFD, 0x7E, 0x03, 0xDB, 0xFE, 0x39, 0xED, 0x51,\n\t0x58, 0x4C, 0x3D, 0xCF, 0xFB, 0xFA, 0xAC, 0x76, 0xF2, 0xCA, 0x73, 0x4F,\n\t0x2A, 0x0B, 0x7C, 0xB0, 0xF0, 0xD1, 0xB2, 0x0D, 0xA6, 0xCE, 0x33, 0xEC,\n\t0x71, 0x1E, 0xF3, 0x31, 0xAF, 0x02, 0x32, 0xA8, 0x5B, 0x38, 0x47, 0x29,\n\t0xE9, 0x0E, 0xB2, 0x2B, 0x8A, 0xC4, 0xA4, 0x0B, 0x6F, 0xFB, 0xFC, 0x6C,\n\t0x6F, 0x5C, 0xE6, 0xB8, 0x8B, 0x5C, 0xF3, 0x23, 0x76, 0xB4, 0x99, 0xCF,\n\t0xE7, 0xA4, 0x0F, 0xBA, 0x88, 0x73, 0x18, 0xA5, 0xE7, 0xDF, 0x7D, 0x7C,\n\t0x9B, 0x5E, 0x1E, 0xCD, 0xFA, 0x61, 0x8D, 0x4C, 0x1D, 0xF6, 0xF1, 0xFD,\n\t0x59, 0xF5, 0xB8, 0xE4, 0x1B, 0x36, 0x2D, 0x7A, 0xD5, 0xC3, 0x7E, 0xD0,\n\t0x53, 0x76, 0x14, 0x0F, 0x0B, 0xE4, 0x43, 0x53, 0x4D, 0x3E, 0x2C, 0xD4,\n\t0x62, 0xF2, 0x8B, 0x38, 0x40, 0xF6, 0x81, 0xB8, 0x54, 0x93, 0x4A, 0x6B,\n\t0x1C, 0xA4, 0x82, 0xEF, 0xA3, 0xD1, 0x04, 0x4E, 0xDF, 0xB8, 0x1B, 0x01,\n\t0xB1, 0xFF, 0xFA, 0x55, 0xFB, 0x01, 0xD5, 0xC4, 0x34, 0x4A, 0xE3, 0xE7,\n\t0xE2, 0x25, 0xBD, 0x78, 0xA5, 0x84, 0x1A, 0x0E, 0xF5, 0xE3, 0x2B, 0xAA,\n\t0x70, 0x17, 0x14, 0x91, 0x1C, 0xE4, 0x92, 0xD5, 0xAF, 0x38, 0x13, 0xB8,\n\t0x85, 0xF5, 0x31, 0x59, 0xE9, 0x3B, 0x2C, 0xD8, 0xE9, 0x13, 0x53, 0x02,\n\t0xB5, 0x87, 0x4D, 0xE6, 0x8A, 0x35, 0x8D, 0xE3, 0xD0, 0x70, 0x0F, 0xA1,\n\t0xD9, 0x03, 0x60, 0x3E, 0x1A, 0x81, 0x4A, 0xFB, 0xDA, 0x32, 0x77, 0x3A,\n\t0xFF, 0x30, 0x11, 0xF4, 0x86, 0xBC, 0xBB, 0x85, 0x65, 0xA5, 0xB7, 0x15,\n\t0x35, 0x79, 0x8E, 0xF3, 0x41, 0x2F, 0xB9, 0xB6, 0xFF, 0x9C, 0x99, 0x86,\n\t0x02, 0x00, 0xA4, 0x64, 0x97, 0x52, 0x83, 0xC1, 0x4B, 0xDE, 0xD8, 0x6C,\n\t0xAC, 0x21, 0xF9, 0x47, 0xA5, 0xAB, 0xD5, 0xD3, 0x70, 0xBC, 0x49, 0xC6,\n\t0x4B, 0x5A, 0x01, 0x01, 0x71, 0xFD, 0x89, 0x8B, 0xDF, 0x6B, 0xB4, 0xEA,\n\t0x27, 0xDC, 0x2E, 0xEA, 0x47, 0x77, 0xCB, 0x73, 0x55, 0x93, 0x36, 0xA1,\n\t0xE5, 0xCE, 0xED, 0x92, 0x92, 0x29, 0x6A, 0x7B, 0x12, 0x62, 0x0B, 0xC1,\n\t0x48, 0x17, 0x14, 0x27, 0xCB, 0x07, 0x9C, 0x93, 0x2D, 0xC8, 0xE5, 0x03,\n\t0x5F, 0x55, 0x82, 0x04, 0x36, 0x06, 0x30, 0x66, 0xE8, 0xC9, 0x9A, 0xD5,\n\t0xBE, 0xD5, 0x1A, 0xF1, 0x86, 0x9E, 0xFD, 0x36, 0xE7, 0xC3, 0x87, 0x92,\n\t0x79, 0xD5, 0xF8, 0x3A, 0xAC, 0x5B, 0x98, 0x63, 0xDE, 0x87, 0x6C, 0xC2,\n\t0x84, 0x0E, 0xC0, 0x4D, 0x15, 0x8C, 0xC8, 0x09, 0xE9, 0xED, 0x24, 0x77,\n\t0x6D, 0x10, 0xEF, 0x2A, 0x63, 0x58, 0xD4, 0x91, 0x01, 0xA1, 0x0D, 0x91,\n\t0xC3, 0x60, 0x44, 0x08, 0x69, 0x07, 0x78, 0xAA, 0x0F, 0x50, 0x06, 0x0A,\n\t0xAF, 0xC1, 0xB8, 0xD4, 0xDE, 0x6C, 0x0D, 0x94, 0x47, 0x04, 0xB2, 0xC3,\n\t0x6A, 0x03, 0x2C, 0x75, 0x19, 0xDA, 0x31, 0x8B, 0x57, 0xD7, 0xA7, 0x53,\n\t0x7A, 0x2B, 0xCF, 0xD8, 0xC7, 0x14, 0xDF, 0xB6, 0xE2, 0x82, 0x3E, 0xF4,\n\t0x4A, 0x01, 0xCB, 0xD0, 0xF4, 0xE0, 0x91, 0x83, 0x57, 0x54, 0xB3, 0x77,\n\t0x5D, 0x74, 0xCC, 0x01, 0xCB, 0x2B, 0x43, 0x72, 0x3D, 0xAE, 0x63, 0x18,\n\t0x26, 0x02, 0x0F, 0xE5, 0x7E, 0xB1, 0xAA, 0x94, 0x8D, 0xE7, 0x3A, 0xC2,\n\t0x79, 0x19, 0xB2, 0xF1, 0xBC, 0x17, 0x58, 0xEB, 0x82, 0xC3, 0xD1, 0x00,\n\t0xF0, 0x01, 0xDC, 0xF6, 0x82, 0x04, 0xD1, 0xEC, 0xCE, 0xD3, 0x44, 0x6E,\n\t0x49, 0x70, 0xF0, 0x74, 0x5C, 0xA7, 0x95, 0xDF, 0xBB, 0x97, 0x7A, 0x76,\n\t0x56, 0xBC, 0x06, 0x39, 0xEB, 0x4E, 0xAC, 0xBB, 0x56, 0x57, 0xF6, 0x3F,\n\t0x47, 0xE6, 0xDC, 0x53, 0x59, 0x18, 0xBC, 0xA7, 0x0B, 0x27, 0x39, 0x59,\n\t0xFC, 0xDB, 0x97, 0xA5, 0x47, 0xCB, 0x7C, 0x7B, 0x51, 0xAF, 0xAE, 0x24,\n\t0xA1, 0xF0, 0x64, 0xDB, 0x0B, 0xDE, 0xBF, 0xC6, 0x99, 0x6D, 0x82, 0xC1,\n\t0xD2, 0xAC, 0x83, 0x10, 0xF8, 0x98, 0xE7, 0x31, 0x62, 0x80, 0x2A, 0x83,\n\t0x9D, 0x97, 0xA2, 0xF6, 0xF2, 0xF4, 0x03, 0xCB, 0x04, 0x02, 0x5C, 0xE5,\n\t0xAC, 0x94, 0x4C, 0x45, 0x6D, 0x16, 0x20, 0x2E, 0x95, 0xA8, 0x29, 0x65,\n\t0x13, 0x37, 0x17, 0xC9, 0xCB, 0x85, 0xE1, 0xA1, 0x00, 0x5D, 0x08, 0x36,\n\t0xE2, 0x1A, 0x3D, 0xD0, 0xD9, 0xB1, 0x3E, 0x90, 0xD8, 0x69, 0xD0, 0x2E,\n\t0xDD, 0x90, 0x14, 0x53, 0xC7, 0x78, 0x3A, 0xFD, 0x13, 0xB9, 0xA2, 0x11,\n\t0xA0, 0x0C, 0xFC, 0x29, 0x30, 0x1E, 0x97, 0x8F, 0xAB, 0x35, 0x6B, 0x69,\n\t0x87, 0x8B, 0x9F, 0xB9, 0x38, 0xD6, 0x31, 0x89, 0xEF, 0xE0, 0x36, 0xAC,\n\t0x17, 0x97, 0x22, 0xD5, 0xDC, 0x3B, 0x0C, 0x00, 0xFB, 0x63, 0xBA, 0x07,\n\t0x59, 0x9A, 0x2E, 0xE0, 0x52, 0x13, 0x4C, 0xCD, 0x10, 0x2C, 0x4E, 0x8D,\n\t0x14, 0x0F, 0x8B, 0x8F, 0x22, 0x4D, 0xAC, 0x24, 0x01, 0xA4, 0xE7, 0x01,\n\t0x35, 0x93, 0xDE, 0x07, 0x2A, 0xDF, 0x13, 0x59, 0x23, 0xEF, 0x51, 0xD9,\n\t0xF3, 0xF7, 0x41, 0x43, 0x7B, 0x10, 0xA5, 0xA0, 0x94, 0xE5, 0x36, 0x48,\n\t0xF1, 0x65, 0xB3, 0xAB, 0xE6, 0x01, 0x5C, 0x3A, 0x90, 0x65, 0xF7, 0xF3,\n\t0xEE, 0x8B, 0x89, 0xB9, 0xBB, 0x40, 0xBE, 0xEA, 0x9E, 0xB8, 0xFD, 0xEF,\n\t0xA1, 0xBF, 0x75, 0x55, 0x54, 0xB7, 0xB6, 0x58, 0x2D, 0xDA, 0x95, 0xA5,\n\t0xD8, 0xF7, 0x96, 0x53, 0x0B, 0xD9, 0xAF, 0xC0, 0x51, 0x9B, 0x51, 0x9D,\n\t0x57, 0x9A, 0xD0, 0x98, 0x4F, 0xDE, 0x07, 0x24, 0x79, 0x07, 0x14, 0xB4,\n\t0xE6, 0xC2, 0x1E, 0x59, 0x85, 0xE2, 0x33, 0xAB, 0xD7, 0x62, 0x46, 0xB4,\n\t0x76, 0x06, 0x6C, 0xC3, 0xB6, 0xC4, 0x7C, 0x26, 0x77, 0x46, 0x25, 0x17,\n\t0xC1, 0x22, 0x55, 0x68, 0x30, 0xB7, 0xC6, 0xBF, 0x24, 0x86, 0xE7, 0x3D,\n\t0xF8, 0x00, 0x60, 0xA6, 0x95, 0xA9, 0x89, 0xA1, 0xB8, 0xF4, 0x94, 0x9C,\n\t0x4B, 0xF7, 0x1D, 0x2C, 0x4C, 0x30, 0xE4, 0xD3, 0x36, 0x38, 0xBB, 0xB2,\n\t0x6E, 0xE9, 0x79, 0x03, 0x62, 0x3D, 0xB3, 0xBF, 0x76, 0xE8, 0x2E, 0x5C,\n\t0xC0, 0x70, 0xE8, 0xEA, 0x00, 0xC6, 0xCD, 0x8C, 0x34, 0xA6, 0x39, 0x16,\n\t0x1F, 0x85, 0xC9, 0x88, 0x81, 0x1F, 0x1F, 0x3D, 0x2C, 0x35, 0xC4, 0x62,\n\t0x64, 0x26, 0xF1, 0xDF, 0x45, 0x49, 0x1A, 0xBE, 0x68, 0x62, 0x83, 0xA1,\n\t0x34, 0x70, 0x68, 0x4E, 0x73, 0x6A, 0x0C, 0x0E, 0xDA, 0x8D, 0x61, 0x13,\n\t0x7C, 0x62, 0x8C, 0x5C, 0xC6, 0xFD, 0x47, 0x63, 0x54, 0x4A, 0xB8, 0x4F,\n\t0x33, 0xDC, 0xDC, 0x99, 0xE5, 0x0A, 0xFF, 0x0E, 0x42, 0x51, 0xC2, 0xC4,\n\t0xDD, 0x28, 0xEE, 0x2D, 0xC7, 0xFE, 0x5C, 0xA2, 0xDB, 0xB2, 0xCE, 0x10,\n\t0x66, 0x90, 0x23, 0x22, 0x89, 0xA4, 0x74, 0x00, 0x1A, 0x1F, 0x27, 0x8F,\n\t0xA8, 0x36, 0xD7, 0x05, 0x76, 0x51, 0xD9, 0xBC, 0xB0, 0x35, 0x3D, 0xD1,\n\t0x0D, 0xC8, 0xB1, 0x17, 0x96, 0x51, 0xDF, 0x7A, 0x68, 0x26, 0x04, 0x03,\n\t0xDD, 0x78, 0xCD, 0x13, 0x7C, 0x0D, 0xD8, 0x64, 0xB5, 0xD9, 0x9F, 0xC0,\n\t0xC0, 0xBE, 0x12, 0xD6, 0x12, 0xE9, 0xB7, 0x65, 0xA3, 0xB2, 0x9B, 0x14,\n\t0xFA, 0x77, 0x4B, 0x9D, 0xDD, 0xE9, 0x43, 0x8E, 0x8C, 0xBE, 0xAD, 0x32,\n\t0x03, 0x24, 0xC4, 0x33, 0x16, 0x12, 0x3C, 0xDD, 0x78, 0x63, 0xDD, 0x6E,\n\t0x2B, 0x32, 0x4D, 0x22, 0x19, 0x04, 0xF2, 0xD6, 0xC1, 0x46, 0x59, 0xF0,\n\t0x46, 0x7A, 0x38, 0x17, 0xD0, 0xE3, 0x40, 0x2E, 0xC7, 0x8A, 0xC6, 0x7D,\n\t0xDA, 0x4A, 0x41, 0x26, 0xC5, 0x1A, 0xF6, 0xC3, 0xC7, 0x9C, 0x23, 0xD7,\n\t0x64, 0x39, 0xC1, 0x50, 0x68, 0xB2, 0xC2, 0xF8, 0x27, 0xEA, 0x22, 0xFC,\n\t0x12, 0xA2, 0x27, 0x5F, 0x9B, 0xDE, 0x5C, 0x99, 0x8D, 0x72, 0x9C, 0x09,\n\t0x19, 0xEF, 0x7F, 0xDB, 0x35, 0xB6, 0x84, 0xCD, 0x2F, 0x80, 0xA2, 0x24,\n\t0xAF, 0x1A, 0x71, 0x0D, 0x09, 0xE0, 0xBC, 0x6C, 0x1D, 0x30, 0x22, 0xF6,\n\t0x50, 0xA4, 0x65, 0x3E, 0xB2, 0x6A, 0xCC, 0x45, 0xB3, 0x06, 0x4A, 0x67,\n\t0xA5, 0x6F, 0x21, 0x1E, 0x9B, 0x6C, 0x4D, 0x08, 0x32, 0x8D, 0x17, 0xED,\n\t0x78, 0x04, 0x98, 0x17, 0x6C, 0xB3, 0x51, 0x18, 0xDF, 0xF0, 0x79, 0xDA,\n\t0x3F, 0x13, 0xDF, 0x32, 0x38, 0x85, 0x98, 0x64, 0xBD, 0x5A, 0x37, 0x39,\n\t0x58, 0x56, 0x83, 0x3B, 0x84, 0xB8, 0x71, 0x42, 0x7F, 0xBC, 0xCB, 0x82,\n\t0xA9, 0xDB, 0x0E, 0x8A, 0xB4, 0x05, 0x24, 0x4B, 0xC4, 0x0F, 0x09, 0xC3,\n\t0x35, 0x0A, 0x96, 0x6B, 0x46, 0xF0, 0x0F, 0x18, 0xC3, 0xFB, 0x5C, 0xC6,\n\t0x22, 0x2A, 0xC1, 0x2C, 0xE6, 0x2E, 0xDB, 0xC5, 0x8A, 0x8F, 0x65, 0xD5,\n\t0x63, 0x97, 0x8F, 0x5B, 0x77, 0xED, 0x96, 0x78, 0x83, 0x0C, 0x0A, 0xCE,\n\t0xD1, 0xF2, 0x4C, 0xA4, 0xA4, 0xD0, 0x09, 0x33, 0x66, 0xE9, 0xD2, 0x98,\n\t0x59, 0x66, 0xBA, 0x76, 0x72, 0x3E, 0x89, 0xCB, 0xA4, 0x4A, 0xE6, 0x84,\n\t0x4D, 0x1A, 0x20, 0x8E, 0xDE, 0x0B, 0x04, 0x85, 0x33, 0x2C, 0xBE, 0xF4,\n\t0xDB, 0x3B, 0x2B, 0x64, 0xD9, 0x76, 0xD4, 0xF4, 0x6F, 0x0F, 0xF3, 0x83,\n\t0x29, 0x3F, 0xA5, 0xCC, 0x8C, 0xE7, 0x93, 0x46, 0x0E, 0xFD, 0x1F, 0xA6,\n\t0xD5, 0x04, 0xD1, 0x85, 0x17, 0xB2, 0xD5, 0xBE, 0x3D, 0xC0, 0x33, 0xC0,\n\t0x52, 0x8A, 0x5C, 0xF6, 0x73, 0xBD, 0x85, 0xE0, 0x02, 0xA7, 0x47, 0x4E,\n\t0x60, 0x2F, 0x76, 0x94, 0x02, 0x01, 0xC7, 0x27, 0x81, 0x0B, 0xEB, 0xEA,\n\t0x49, 0x29, 0xFA, 0x02, 0x73, 0x6E, 0xB1, 0xEC, 0x82, 0x29, 0x29, 0x6F,\n\t0x3E, 0xF2, 0xB2, 0x1F, 0xD5, 0x66, 0x54, 0x00, 0x52, 0xE1, 0x1C, 0xDA,\n\t0xF0, 0xCF, 0x90, 0x83, 0x6B, 0xFF, 0xED, 0x3D, 0x69, 0x91, 0xA4, 0x47,\n\t0x82, 0x88, 0x09, 0x5A, 0x63, 0x75, 0x44, 0x88, 0xF4, 0x51, 0x85, 0xE0,\n\t0x6F, 0x85, 0x2A, 0x48, 0x14, 0x3B, 0x09, 0x8F, 0x80, 0xE6, 0xF8, 0x09,\n\t0x5C, 0xC6, 0x7B, 0x45, 0x85, 0x4F, 0x57, 0x9E, 0x58, 0x9A, 0x35, 0x5F,\n\t0x94, 0x70, 0x3B, 0x11, 0x49, 0x1D, 0xB8, 0x46, 0xB7, 0x79, 0x8E, 0x2C,\n\t0x48, 0xDB, 0x3C, 0x34, 0x4E, 0xD2, 0x17, 0x19, 0xA1, 0xDA, 0x48, 0x40,\n\t0x08, 0x6E, 0xCE, 0x66, 0xC3, 0x70, 0xB0, 0x01, 0x21, 0xD5, 0x97, 0x9B,\n\t0xAB, 0x65, 0x96, 0x05, 0x75, 0x97, 0xFB, 0x2E, 0x4B, 0x0C, 0x31, 0xFD,\n\t0x8E, 0x67, 0x76, 0xF4, 0x5B, 0x06, 0xF2, 0xB3, 0xA6, 0xDF, 0x56, 0xF6,\n\t0x5D, 0xA5, 0xDF, 0xBE, 0x01, 0x6A, 0x71, 0xC6, 0x1D, 0xFE, 0xBB, 0x08,\n\t0xA8, 0x06, 0x59, 0x4F, 0x6D, 0x92, 0x13, 0xD3, 0xCA, 0xCA, 0xFF, 0xBA,\n\t0x3A, 0xF2, 0xEA, 0xFD, 0xEE, 0x37, 0xA8, 0xB5, 0x4C, 0x42, 0xBA, 0x48,\n\t0x4A, 0x98, 0xA6, 0x92, 0x75, 0xB7, 0xE6, 0x77, 0x2A, 0xA9, 0x6A, 0xE3,\n\t0x6B, 0xC4, 0x72, 0x98, 0xE4, 0xA1, 0x6F, 0x44, 0x0E, 0x42, 0x2C, 0xAD,\n\t0x80, 0xE8, 0xA7, 0x5B, 0x82, 0xA4, 0x2D, 0x7A, 0x09, 0xFD, 0xB8, 0xBE,\n\t0x9E, 0x64, 0xE7, 0x18, 0x21, 0xBB, 0x7D, 0x58, 0xE7, 0xC7, 0x02, 0x8A,\n\t0x54, 0xCA, 0xCA, 0xEF, 0xBC, 0xD0, 0x0D, 0xFE, 0xCB, 0x79, 0x06, 0x38,\n\t0xEE, 0xD2, 0xB8, 0xF9, 0x40, 0x08, 0x6C, 0x80, 0xCE, 0xDC, 0xDA, 0xA0,\n\t0x2E, 0x22, 0x4B, 0x10, 0xCC, 0xEE, 0x01, 0xDA, 0x9F, 0xD7, 0x31, 0x84,\n\t0x26, 0xDD, 0xE0, 0x92, 0x60, 0xA5, 0xB9, 0xA7, 0x23, 0xF7, 0xF2, 0x07,\n\t0x06, 0x07, 0x80, 0x9F, 0x20, 0x5A, 0x1C, 0x68, 0x81, 0xE8, 0x27, 0xC4,\n\t0xF0, 0x54, 0x03, 0x9B, 0x1A, 0xAB, 0xD6, 0x43, 0x6B, 0xDB, 0x23, 0x10,\n\t0x79, 0x94, 0x3F, 0xB6, 0xDF, 0xAA, 0x43, 0x53, 0xF0, 0x16, 0x8F, 0x31,\n\t0xDA, 0xB7, 0xB3, 0xC5, 0x1E, 0xE5, 0x7B, 0x1F, 0x12, 0x38, 0x4D, 0x6A,\n\t0x41, 0x06, 0x0E, 0x32, 0x1C, 0x12, 0x61, 0x91, 0x2C, 0x95, 0x87, 0xE2,\n\t0x04, 0x2E, 0x34, 0x7C, 0x81, 0x43, 0x82, 0x2D, 0xC6, 0xA1, 0x15, 0x83,\n\t0xEB, 0xC7, 0x29, 0x14, 0x8F, 0x03, 0xDB, 0xC8, 0x3A, 0x79, 0x38, 0x99,\n\t0x06, 0xF2, 0x4C, 0x8A, 0xF2, 0x1D, 0x51, 0x5A, 0x06, 0xE7, 0xDB, 0x6C,\n\t0x86, 0x54, 0xFE, 0x59, 0x97, 0x6A, 0x59, 0x54, 0xD4, 0x6D, 0xE5, 0xE8,\n\t0xCD, 0x25, 0xE2, 0xA5, 0xF8, 0x1D, 0x58, 0xC9, 0x97, 0xA1, 0x08, 0x2E,\n\t0xE7, 0xEE, 0x80, 0x1B, 0xE2, 0x75, 0x42, 0x6C, 0x6D, 0xEF, 0x4C, 0xA3,\n\t0x79, 0xB1, 0xB8, 0x41, 0x76, 0x0D, 0x62, 0xD7, 0x18, 0x00, 0xE0, 0x9B,\n\t0x42, 0xA7, 0x48, 0x43, 0x39, 0x84, 0x54, 0xB0, 0xCB, 0x43, 0x03, 0xB5,\n\t0xCB, 0x38, 0x87, 0x7C, 0xD9, 0xB2, 0x87, 0x4F, 0x46, 0xB4, 0x3F, 0x5F,\n\t0x32, 0xC1, 0xFA, 0x8D, 0x1C, 0x9C, 0x9D, 0xE1, 0x71, 0xF4, 0xE0, 0x90,\n\t0xE4, 0x44, 0x87, 0xA1, 0x38, 0x8E, 0x80, 0xA0, 0xED, 0xCC, 0x21, 0xC0,\n\t0x0F, 0x27, 0xE4, 0x60, 0xDA, 0xE7, 0xC4, 0x94, 0x85, 0x50, 0x5B, 0x48,\n\t0x9A, 0x03, 0x4B, 0x4E, 0x67, 0x2B, 0x09, 0xAE, 0xA2, 0xF7, 0xB8, 0x91,\n\t0xB0, 0x3A, 0x72, 0x98, 0xEC, 0xDD, 0x9D, 0x87, 0xA2, 0xA4, 0x43, 0x57,\n\t0xE4, 0xEE, 0xFB, 0xA2, 0x1E, 0x03, 0x38, 0x65, 0x0E, 0x66, 0xBC, 0x81,\n\t0xC8, 0x9D, 0x6F, 0x70, 0x30, 0xDF, 0xF5, 0x31, 0x95, 0x26, 0x85, 0xDB,\n\t0x64, 0x08, 0x5A, 0x1F, 0xCF, 0xF5, 0x4E, 0x1F, 0xD7, 0x6B, 0xCA, 0x76,\n\t0xCC, 0xEE, 0xF9, 0x8C, 0x6E, 0xB7, 0x40, 0xCA, 0xF2, 0xD6, 0x63, 0xBF,\n\t0x43, 0x88, 0x92, 0x99, 0x6B, 0xCB, 0x11, 0xCC, 0x8D, 0x63, 0xE3, 0x4D,\n\t0x30, 0x0C, 0x05, 0x2C, 0xAA, 0x0F, 0x92, 0x7E, 0xA5, 0xF1, 0xB4, 0x21,\n\t0x87, 0xE7, 0x9D, 0x41, 0x9F, 0xFD, 0x88, 0x7B, 0x8C, 0xFA, 0xD2, 0xCC,\n\t0xAE, 0xDD, 0x97, 0x38, 0xAD, 0x4C, 0xE7, 0x9C, 0x3D, 0xE4, 0x64, 0x40,\n\t0xF2, 0xD0, 0x0E, 0x48, 0xCB, 0xD7, 0x0E, 0xFD, 0x32, 0x54, 0x42, 0x2D,\n\t0x76, 0x87, 0xA2, 0xEC, 0x62, 0x7C, 0xB7, 0x0E, 0x4F, 0x39, 0x25, 0x9C,\n\t0x0F, 0x47, 0xCF, 0x22, 0x84, 0x35, 0x18, 0x5A, 0x6C, 0x85, 0x48, 0x15,\n\t0xD0, 0x7C, 0x7D, 0x56, 0xB0, 0xC9, 0x42, 0x94, 0x11, 0xDB, 0xB8, 0x59,\n\t0x36, 0xE6, 0x06, 0x38, 0x71, 0xF0, 0xE6, 0x62, 0x60, 0x11, 0xB4, 0xB3,\n\t0xEA, 0xB9, 0x62, 0x12, 0x6F, 0x8D, 0xAC, 0xD8, 0x6B, 0xAD, 0x9E, 0x65,\n\t0xA5, 0x4A, 0x33, 0x25, 0xFA, 0x33, 0xDD, 0x0D, 0x9A, 0x80, 0xCA, 0xBB,\n\t0x78, 0x54, 0xCF, 0xDA, 0x6C, 0xAF, 0xBC, 0x07, 0x43, 0x12, 0xCE, 0x60,\n\t0x56, 0xB0, 0x64, 0x52, 0x37, 0xD3, 0x39, 0xF7, 0xB5, 0x24, 0x66, 0x94,\n\t0x05, 0x4F, 0xEA, 0xA2, 0x95, 0x0C, 0x97, 0x15, 0xD0, 0x00, 0x80, 0x87,\n\t0xBE, 0x27, 0xAA, 0x2C, 0x80, 0x77, 0xDC, 0xFA, 0xBA, 0xDB, 0xA1, 0x1C,\n\t0xFB, 0x2B, 0xB4, 0xFA, 0x61, 0x53, 0xD5, 0xD3, 0xA7, 0x9D, 0x99, 0xAC,\n\t0xC9, 0xBE, 0x27, 0x0A, 0x9C, 0xB0, 0xF2, 0x1E, 0x96, 0xF3, 0xCD, 0xA4,\n\t0xE9, 0x36, 0x30, 0xB9, 0xF3, 0xE3, 0x7E, 0x80, 0x62, 0x20, 0xFF, 0xA5,\n\t0xC9, 0x26, 0x40, 0xB5, 0x9E, 0x04, 0x96, 0x4C, 0xDD, 0x98, 0xA1, 0x22,\n\t0x53, 0x7E, 0x5D, 0x32, 0x4D, 0x34, 0x57, 0xDD, 0xE1, 0x44, 0xF6, 0x8C,\n\t0x07, 0x04, 0x86, 0x75, 0xB2, 0x7E, 0x09, 0x35, 0x06, 0x50, 0x84, 0x72,\n\t0xE9, 0xA2, 0x56, 0x79, 0xBC, 0x11, 0x3E, 0x7D, 0x5D, 0x02, 0x18, 0x27,\n\t0x4F, 0x41, 0x58, 0x02, 0x21, 0x52, 0x22, 0x8D, 0x0E, 0xF1, 0xB6, 0x4F,\n\t0x82, 0xE6, 0x60, 0x0E, 0x04, 0xD1, 0x53, 0xF5, 0x1A, 0xF0, 0xA4, 0x5B,\n\t0xF5, 0x04, 0x99, 0xE4, 0x19, 0xA2, 0xE7, 0x8C, 0x98, 0x75, 0x0A, 0x8E,\n\t0x02, 0x70, 0x52, 0x33, 0x18, 0x9B, 0x55, 0x20, 0x0B, 0xD0, 0x49, 0x44,\n\t0x23, 0x89, 0x42, 0x45, 0x26, 0xA7, 0x2C, 0x5B, 0x6B, 0xEF, 0xD9, 0x6F,\n\t0xE2, 0x5A, 0x59, 0x78, 0xB3, 0xAF, 0x61, 0x79, 0x94, 0x57, 0xD7, 0x05,\n\t0x27, 0xB5, 0xD4, 0x95, 0xAE, 0x8F, 0xA0, 0x4C, 0xFA, 0xC1, 0x52, 0x6B,\n\t0xDC, 0xA0, 0x1D, 0xBD, 0x04, 0x06, 0x9D, 0xAF, 0xDC, 0xB1, 0x29, 0x2A,\n\t0x18, 0xE1, 0x15, 0x11, 0xC0, 0xEF, 0xA6, 0x94, 0xB6, 0x35, 0xDC, 0x8E,\n\t0xA6, 0x9B, 0x45, 0x20, 0xCF, 0x1C, 0x7A, 0xDE, 0x78, 0xF4, 0x9E, 0xB5,\n\t0x59, 0x3D, 0xFE, 0x91, 0xBA, 0xA9, 0x5A, 0x1C, 0x53, 0xBD, 0x05, 0xCA,\n\t0x9A, 0x1B, 0x53, 0x7B, 0x41, 0x99, 0x63, 0xD6, 0xD2, 0x0F, 0x81, 0x03,\n\t0xA6, 0xA6, 0x1E, 0x49, 0xF7, 0x88, 0x89, 0x4E, 0x83, 0xC8, 0x60, 0xE2,\n\t0x61, 0x56, 0xC2, 0x7A, 0xC3, 0xA6, 0xA9, 0x36, 0x95, 0x4F, 0x4F, 0x5B,\n\t0x08, 0x82, 0x0B, 0xDF, 0xA6, 0x14, 0x7B, 0x4A, 0xDA, 0x42, 0xB4, 0x9B,\n\t0x42, 0x77, 0xEF, 0xB6, 0x10, 0xB4, 0x00, 0x56, 0x3E, 0x63, 0xD6, 0xBA,\n\t0x06, 0xE4, 0x95, 0x60, 0xAB, 0xFF, 0x49, 0x8F, 0xFC, 0x12, 0xB2, 0x90,\n\t0x20, 0xA8, 0x26, 0x39, 0xBE, 0xA1, 0x1C, 0xB7, 0xCB, 0xD4, 0xEE, 0xA6,\n\t0x6C, 0xDB, 0x1A, 0x62, 0x0B, 0x65, 0x3D, 0xC0, 0xA4, 0xBD, 0x50, 0xA8,\n\t0x52, 0xEB, 0xB5, 0x4F, 0x16, 0xD6, 0x9F, 0x72, 0xBF, 0xA8, 0x5C, 0xC9,\n\t0xCF, 0xAA, 0x54, 0x8D, 0xC4, 0x84, 0x8C, 0x16, 0x2F, 0x8E, 0x6A, 0xC6,\n\t0x61, 0xE1, 0x2D, 0x08, 0x4C, 0xB4, 0x71, 0x6F, 0x97, 0xD4, 0xE9, 0xFD,\n\t0xA2, 0x89, 0xBE, 0xEC, 0xCE, 0x48, 0xD1, 0x16, 0xFD, 0xFA, 0x82, 0xA5,\n\t0x8D, 0xBA, 0xC0, 0xB4, 0x97, 0xB6, 0x80, 0xA6, 0x81, 0x01, 0x70, 0x2D,\n\t0xA1, 0xE1, 0x90, 0xA0, 0xDE, 0x3B, 0xA4, 0xA7, 0xCD, 0xAC, 0xF9, 0xAA,\n\t0x47, 0xE2, 0x84, 0x60, 0x37, 0x51, 0x9C, 0x19, 0xBE, 0x6F, 0x0C, 0x88,\n\t0x42, 0xC5, 0x1F, 0xA3, 0x68, 0x57, 0xB9, 0x7B, 0x5C, 0x10, 0x94, 0xA2,\n\t0x89, 0xF0, 0x31, 0xB9, 0x72, 0x52, 0x61, 0x62, 0x8E, 0x7D, 0xC5, 0xEF,\n\t0xB4, 0xA0, 0x72, 0xA5, 0x18, 0xA1, 0x1F, 0xA5, 0x0A, 0x8C, 0x0B, 0x7A,\n\t0x5B, 0xDA, 0xB2, 0x72, 0xE9, 0xB9, 0x5E, 0x5C, 0xA3, 0xF8, 0x4C, 0xD1,\n\t0x5D, 0xC9, 0x13, 0xC5, 0x8C, 0xB7, 0x2F, 0x43, 0x0F, 0x5B, 0x7B, 0xE5,\n\t0x56, 0x9A, 0xAF, 0x79, 0xFA, 0x00, 0x12, 0x3D, 0x21, 0x6F, 0xC7, 0x54,\n\t0xD5, 0x4C, 0x30, 0x94, 0xF7, 0x4C, 0x5C, 0xB8, 0xB8, 0x11, 0xF7, 0xBD,\n\t0x0E, 0xC3, 0x2D, 0x8A, 0x2A, 0xD6, 0xC5, 0x7C, 0xDE, 0x9E, 0x26, 0x86,\n\t0x4D, 0x50, 0x78, 0x66, 0xA8, 0xAF, 0x4C, 0xBB, 0x8A, 0x45, 0x5E, 0x90,\n\t0xFA, 0x42, 0xB6, 0xAD, 0x54, 0x36, 0x80, 0xD8, 0xBE, 0x06, 0xE3, 0x7E,\n\t0x3E, 0xC5, 0x10, 0xFE, 0xEC, 0x26, 0xFC, 0x0E, 0x75, 0x39, 0x6B, 0x16,\n\t0xE7, 0x52, 0xAD, 0xEB, 0x62, 0x35, 0x25, 0xEB, 0x26, 0x3C, 0x1F, 0xFE,\n\t0xD2, 0xFE, 0x7C, 0x0E, 0x39, 0x01, 0x6B, 0x25, 0x5D, 0xBA, 0xF5, 0xB2,\n\t0xDB, 0x73, 0x6A, 0x67, 0x8E, 0xEC, 0x9E, 0x09, 0xA5, 0xD1, 0xD2, 0xB6,\n\t0xA7, 0xC2, 0x34, 0x62, 0x2B, 0x1E, 0x17, 0x07, 0x65, 0x80, 0xCB, 0x60,\n\t0xA9, 0x8D, 0x8C, 0xBD, 0x0B, 0x58, 0x1B, 0x66, 0xF1, 0x16, 0xD5, 0x9A,\n\t0xF0, 0xAA, 0x54, 0xCE, 0xF6, 0x84, 0x8F, 0x45, 0xC6, 0xA3, 0xF6, 0x1C,\n\t0x16, 0xFD, 0xF4, 0xBE, 0x0E, 0x15, 0xF1, 0x7C, 0xFC, 0x90, 0xDE, 0x47,\n\t0xA7, 0xD0, 0xB3, 0x00, 0x59, 0x88, 0xCB, 0xBD, 0x65, 0x1B, 0xF2, 0x12,\n\t0xB4, 0x92, 0xDF, 0xC0, 0xA1, 0xCE, 0xE3, 0xB2, 0x92, 0x41, 0xE6, 0xFB,\n\t0x18, 0x2F, 0x60, 0x9B, 0xCD, 0x48, 0xBA, 0x65, 0x07, 0xFE, 0x3F, 0xB6,\n\t0x14, 0x37, 0x3D, 0x22, 0x9C, 0x9A, 0x7F, 0x48, 0xED, 0xAA, 0x25, 0x41,\n\t0xF3, 0x0C, 0xCD, 0xC5, 0x87, 0x99, 0x89, 0xF3, 0xEB, 0x87, 0xC9, 0x38,\n\t0x5D, 0x41, 0xF3, 0x3D, 0x32, 0x78, 0xAE, 0xB9, 0x4B, 0xC1, 0xC8, 0x4B,\n\t0x30, 0x5D, 0x24, 0x00, 0x15, 0x37, 0x45, 0x59, 0x16, 0xED, 0xAC, 0x0B,\n\t0x8F, 0x7D, 0x02, 0xFB, 0xD9, 0x97, 0xF3, 0xAD, 0x6A, 0x3B, 0x25, 0xB7,\n\t0x9E, 0xF9, 0x30, 0x34, 0x4A, 0xCF, 0xBE, 0x3E, 0x13, 0x4F, 0xA7, 0x5C,\n\t0xF3, 0x84, 0x68, 0x5B, 0xC2, 0xD5, 0xF7, 0x67, 0x80, 0x43, 0x44, 0xA6,\n\t0xC1, 0x96, 0xCB, 0x52, 0xB4, 0xD6, 0x9B, 0xCD, 0x37, 0x5B, 0xB6, 0x46,\n\t0x61, 0x07, 0x17, 0x4E, 0x35, 0xAC, 0x52, 0x18, 0x67, 0x63, 0xCC, 0x4C,\n\t0x0C, 0x3A, 0x5B, 0xFC, 0x8B, 0x20, 0x31, 0x58, 0xA7, 0xF2, 0xC5, 0x24,\n\t0x88, 0x00, 0x61, 0xC3, 0x27, 0x0D, 0x7A, 0x27, 0x7B, 0x4D, 0x69, 0x97,\n\t0xE3, 0xA6, 0xB8, 0x17, 0x6E, 0xEA, 0x4E, 0xBA, 0x3B, 0x71, 0xDB, 0x08,\n\t0x50, 0xD8, 0x11, 0xD7, 0x1A, 0x53, 0xAA, 0xBA, 0xFC, 0x03, 0x57, 0x9C,\n\t0xC5, 0x73, 0x26, 0xCB, 0xD7, 0xD6, 0xD9, 0x01, 0xD5, 0x9D, 0xEF, 0x97,\n\t0x1B, 0xE3, 0xB0, 0x7D, 0x7A, 0x3A, 0xD8, 0xAB, 0xD4, 0x17, 0x9F, 0x8D,\n\t0x18, 0x97, 0x65, 0xFD, 0x1A, 0x62, 0x56, 0x96, 0x9B, 0x4D, 0xFB, 0xDB,\n\t0xAD, 0x39, 0x8C, 0x11, 0x76, 0xEB, 0xB0, 0x67, 0x9D, 0xD1, 0x90, 0x43,\n\t0x02, 0x1E, 0xD8, 0xC8, 0x86, 0x40, 0x9C, 0x83, 0x0B, 0x6F, 0x2E, 0x36,\n\t0xE5, 0xD6, 0x26, 0x58, 0xC3, 0x77, 0x8C, 0x06, 0x20, 0xB3, 0xFA, 0xBF,\n\t0xA7, 0xB4, 0x9E, 0xEE, 0x86, 0x25, 0x9A, 0x95, 0xB0, 0x42, 0xC4, 0xEF,\n\t0xC1, 0xCC, 0xF1, 0x5F, 0xDC, 0xF4, 0x3D, 0x6C, 0x8B, 0x9C, 0xBA, 0x22,\n\t0x65, 0xB2, 0xC9, 0x46, 0x0C, 0x17, 0xB9, 0xF3, 0xC1, 0xBE, 0xA5, 0xC4,\n\t0x4C, 0xC1, 0x31, 0x52, 0xD4, 0xB5, 0x37, 0xFF, 0xD1, 0xC2, 0xAA, 0xD4,\n\t0xB5, 0xE0, 0x22, 0xAC, 0xBC, 0xE4, 0x77, 0x99, 0xB7, 0x20, 0x97, 0x8E,\n\t0x57, 0xA0, 0x60, 0x03, 0xDA, 0x39, 0xAD, 0x36, 0xC1, 0xF0, 0x81, 0x5C,\n\t0x53, 0x26, 0xC4, 0xA5, 0xC0, 0xE4, 0x7B, 0x17, 0xAC, 0x78, 0xF2, 0x48,\n\t0x95, 0x9A, 0xD0, 0x7A, 0x3B, 0xB5, 0x34, 0x49, 0x53, 0xD6, 0x59, 0x58,\n\t0xAE, 0x6A, 0x58, 0xB4, 0x99, 0x87, 0xC3, 0xE0, 0x00, 0x33, 0x1C, 0x00,\n\t0x53, 0xAF, 0x18, 0xC3, 0x43, 0x5E, 0xF8, 0x2A, 0xF8, 0x01, 0xD7, 0x38,\n\t0xB5, 0x69, 0x48, 0xB9, 0xE8, 0x76, 0x52, 0xD2, 0x8D, 0x70, 0x35, 0xA0,\n\t0x0C, 0x8E, 0x3C, 0xE0, 0xA8, 0x73, 0x5E, 0x2A, 0x20, 0xA2, 0xF3, 0x17,\n\t0x9B, 0xB0, 0xF7, 0x3F, 0x5A, 0x9F, 0x0A, 0x1F, 0x5E, 0x5E, 0x95, 0x3F,\n\t0x88, 0xEA, 0x56, 0xD6, 0xD9, 0xD9, 0x5B, 0x9E, 0x34, 0x82, 0x4B, 0xC6,\n\t0x72, 0xCB, 0x63, 0x4B, 0x22, 0xC0, 0x02, 0x10, 0x87, 0x91, 0xCB, 0x4D,\n\t0x85, 0x20, 0x4F, 0x81, 0xFE, 0x35, 0xD1, 0x74, 0xEE, 0x81, 0x6D, 0xB9,\n\t0x9A, 0xB6, 0x04, 0x4C, 0x39, 0xAE, 0x15, 0x5C, 0xF7, 0x05, 0x96, 0x28,\n\t0x6B, 0x4B, 0x6B, 0x0C, 0xA8, 0x9B, 0x6B, 0xD2, 0xF0, 0x11, 0xA4, 0x1A,\n\t0x87, 0xC6, 0x10, 0x15, 0x12, 0x4D, 0x10, 0x5E, 0xB3, 0xB1, 0x37, 0x73,\n\t0x0A, 0xFB, 0x9F, 0x6F, 0xAB, 0xE8, 0x93, 0x30, 0xA0, 0x9F, 0xF9, 0x05,\n\t0xFE, 0x28, 0x99, 0x8C, 0x1E, 0x0A, 0xD8, 0x01, 0x0B, 0xF7, 0xD7, 0xCE,\n\t0x7C, 0xA3, 0xC4, 0x55, 0x07, 0x1A, 0x94, 0xB4, 0xA2, 0x12, 0x72, 0x9E,\n\t0x9C, 0x80, 0x37, 0x68, 0xA8, 0xB7, 0x87, 0x65, 0x4C, 0x6D, 0x58, 0xAA,\n\t0x57, 0x34, 0x67, 0x5E, 0x9D, 0xAD, 0x25, 0x34, 0x86, 0xA5, 0xE1, 0x4E,\n\t0x0E, 0xA1, 0x81, 0x82, 0x66, 0xFE, 0x63, 0x76, 0xCE, 0x09, 0xDF, 0x65,\n\t0xD3, 0xDB, 0x03, 0xB5, 0x88, 0xA5, 0xD5, 0x44, 0x4C, 0xD1, 0xC5, 0x80,\n\t0x22, 0x76, 0xD1, 0x9F, 0x6E, 0x9E, 0xF3, 0x84, 0xB1, 0x21, 0x6F, 0x8A,\n\t0x35, 0x61, 0x3A, 0x27, 0x91, 0x82, 0xA6, 0xC3, 0x82, 0xE0, 0xD7, 0xC9,\n\t0xAA, 0x5A, 0x47, 0x9C, 0x7C, 0xD3, 0x68, 0x8E, 0x4A, 0x04, 0xF3, 0x0F,\n\t0x65, 0xC0, 0xFB, 0x89, 0x35, 0xFE, 0x51, 0x61, 0x69, 0xDF, 0xC0, 0x44,\n\t0x32, 0x26, 0x80, 0xF2, 0xD7, 0xF8, 0x36, 0xC1, 0x78, 0x53, 0x54, 0xD4,\n\t0xD0, 0x4E, 0xB3, 0x1B, 0xB3, 0x09, 0xBF, 0x2C, 0xF2, 0xC6, 0x43, 0x3C,\n\t0x0F, 0x68, 0x70, 0x15, 0x1F, 0xC6, 0x17, 0xB7, 0xA3, 0xA3, 0x9D, 0x8E,\n\t0xC7, 0x70, 0xB9, 0x91, 0xCC, 0x59, 0xA8, 0x57, 0x4E, 0xF6, 0x2E, 0xD7,\n\t0x69, 0x01, 0xBA, 0xAA, 0xEC, 0x42, 0x80, 0x39, 0xE5, 0x5F, 0x00, 0x75,\n\t0x0A, 0xF4, 0xA5, 0xB6, 0x7A, 0x37, 0x06, 0x6E, 0x3E, 0xFE, 0x6C, 0x7B,\n\t0x26, 0x4C, 0x0D, 0xFF, 0xA6, 0x31, 0x4F, 0x63, 0x7E, 0x4F, 0x61, 0x5E,\n\t0xB8, 0x26, 0xED, 0x70, 0xE2, 0x4F, 0x4E, 0xEF, 0x7E, 0x55, 0x97, 0x1B,\n\t0x0B, 0x08, 0xB3, 0x80, 0x18, 0xEE, 0xB5, 0x9E, 0x0F, 0x86, 0xB5, 0xDA,\n\t0x38, 0x56, 0x75, 0x56, 0x08, 0xB6, 0x8E, 0x1A, 0xCB, 0x60, 0xE5, 0x16,\n\t0xC3, 0x67, 0xB5, 0x2D, 0xF5, 0x10, 0x22, 0x18, 0x85, 0xBC, 0x6F, 0x65,\n\t0xE0, 0x07, 0x22, 0x82, 0xB1, 0xFC, 0x56, 0xF1, 0xEA, 0x1D, 0xE2, 0xE5,\n\t0x39, 0x9E, 0x8F, 0x23, 0x9F, 0x9A, 0x4B, 0x11, 0xB0, 0xA2, 0x77, 0x9E,\n\t0x79, 0x84, 0xBC, 0xC4, 0x7C, 0xC6, 0x32, 0x5D, 0x19, 0x15, 0xFB, 0x41,\n\t0x94, 0xFD, 0xCC, 0x48, 0xBC, 0x73, 0x29, 0x77, 0x64, 0x66, 0xA3, 0xDB,\n\t0xA3, 0x65, 0x6D, 0xDE, 0x4B, 0x60, 0xA1, 0xA1, 0xDF, 0x3A, 0x74, 0x99,\n\t0x0A, 0x04, 0x17, 0xAF, 0x30, 0x26, 0xB1, 0xC4, 0xC3, 0xC6, 0xA1, 0x99,\n\t0x5D, 0x7C, 0xF4, 0xCD, 0xEF, 0x27, 0x6E, 0xFB, 0x13, 0xBE, 0x5F, 0x59,\n\t0x9C, 0x71, 0x6F, 0x51, 0x49, 0x7A, 0x5F, 0x03, 0xE8, 0x83, 0x97, 0x33,\n\t0xFB, 0x0B, 0x27, 0xE4, 0x0A, 0xF3, 0xA8, 0x7A, 0x10, 0x4A, 0x0C, 0xF3,\n\t0x1F, 0xA6, 0x0E, 0xBF, 0x40, 0x84, 0x72, 0x8D, 0x57, 0xB2, 0xD9, 0xB5,\n\t0x88, 0xDB, 0x80, 0x1A, 0x2A, 0x34, 0xB8, 0x5E, 0xC2, 0x86, 0x7B, 0x94,\n\t0x1F, 0xE0, 0xCC, 0xA2, 0x16, 0x4D, 0x1A, 0xF7, 0xF6, 0x48, 0x1B, 0x40,\n\t0x5A, 0x2B, 0xEF, 0xA5, 0x31, 0x98, 0x61, 0xE5, 0x16, 0x32, 0xEB, 0x58,\n\t0x8F, 0x51, 0xF2, 0x6F, 0xE1, 0x27, 0x28, 0x43, 0x18, 0x5D, 0xD2, 0x30,\n\t0x3C, 0x25, 0xD6, 0x6E, 0x00, 0x3B, 0x7F, 0xED, 0x43, 0x1E, 0xD8, 0x1F,\n\t0x07, 0x91, 0xEE, 0x3B, 0x30, 0x89, 0x14, 0x9B, 0xDD, 0x62, 0xD0, 0xA1,\n\t0xE2, 0xF3, 0x9A, 0xC9, 0x52, 0xCF, 0x14, 0x13, 0xB3, 0x24, 0x75, 0x97,\n\t0xB7, 0xF6, 0x52, 0x36, 0xFC, 0x66, 0x82, 0x10, 0xBF, 0xB2, 0x22, 0x0D,\n\t0x64, 0x78, 0x1F, 0x4F, 0x61, 0x5E, 0x6C, 0xC6, 0x60, 0x5B, 0x6E, 0x38,\n\t0x5D, 0xCF, 0xA9, 0x6F, 0x2B, 0x8D, 0x73, 0x78, 0xB8, 0xE3, 0x0F, 0xDE,\n\t0xC1, 0xA5, 0x71, 0xD9, 0x15, 0x31, 0x3A, 0x4F, 0xA9, 0x5A, 0x4A, 0xB1,\n\t0x97, 0x7D, 0x87, 0x4B, 0x45, 0xA3, 0x45, 0x9B, 0xFA, 0xF6, 0x62, 0x5E,\n\t0x2C, 0xC3, 0xC8, 0x93, 0x42, 0x8A, 0xA8, 0x8F, 0x83, 0x57, 0xC4, 0x63,\n\t0xD8, 0x0F, 0xA9, 0x16, 0x6C, 0x06, 0xF9, 0xEA, 0x75, 0x99, 0x95, 0x12,\n\t0xB4, 0x46, 0x0D, 0x24, 0xF5, 0x8C, 0x67, 0x70, 0x22, 0x42, 0x35, 0x5E,\n\t0x6F, 0xC3, 0x3F, 0xA4, 0xD6, 0xBC, 0xA9, 0xB7, 0xB9, 0x6F, 0x34, 0xD5,\n\t0x5A, 0x88, 0x54, 0xDC, 0x03, 0x17, 0xF7, 0xDE, 0xE6, 0x65, 0x2E, 0xF7,\n\t0x5E, 0xFF, 0xFE, 0xEE, 0x58, 0x62, 0x16, 0xE6, 0x32, 0xC3, 0x62, 0x2E,\n\t0xD9, 0xF4, 0x34, 0x9D, 0x0E, 0x33, 0x07, 0x59, 0xFD, 0x75, 0x0C, 0x98,\n\t0x01, 0xC3, 0x65, 0xED, 0xEA, 0x1E, 0xB2, 0xA3, 0x74, 0x90, 0xFF, 0xE7,\n\t0x16, 0xC8, 0x3F, 0x75, 0xC3, 0xA5, 0x9D, 0xB8, 0x8F, 0x5B, 0x82, 0xDC,\n\t0x64, 0xA8, 0x49, 0x52, 0x4A, 0xD4, 0xCD, 0x8F, 0x4D, 0x33, 0x6E, 0x05,\n\t0x6F, 0x64, 0x5C, 0x0F, 0x30, 0x96, 0x74, 0xA5, 0xB6, 0x6F, 0x52, 0xD3,\n\t0x0C, 0xFA, 0x41, 0x9E, 0x4E, 0x45, 0x7B, 0xBD, 0x3E, 0x0F, 0x69, 0x84,\n\t0xA4, 0xF8, 0x11, 0xD2, 0x14, 0x43, 0xCC, 0xDA, 0xFE, 0xE1, 0xD0, 0x54,\n\t0x5A, 0x45, 0xC4, 0x31, 0xA9, 0xDF, 0x07, 0xB6, 0x69, 0x9C, 0x63, 0xDE,\n\t0x6A, 0xB4, 0xE5, 0xB9, 0x92, 0xDA, 0x1B, 0xD4, 0xD3, 0x2C, 0x06, 0xCD,\n\t0xD1, 0xEA, 0x01, 0x44, 0xB1, 0x15, 0x35, 0x64, 0x9F, 0x21, 0xF7, 0x6B,\n\t0xAA, 0x97, 0x99, 0x29, 0xC7, 0x91, 0x3D, 0x6F, 0x35, 0x77, 0x71, 0x9F,\n\t0x35, 0xC2, 0xBE, 0xFC, 0x48, 0xE0, 0xB2, 0xED, 0x0E, 0x6D, 0xE8, 0x3F,\n\t0xB8, 0x04, 0x73, 0xC5, 0x24, 0x3D, 0x26, 0xF3, 0x1E, 0x5C, 0x1C, 0xD4,\n\t0x39, 0x1A, 0x7F, 0x8F, 0xA8, 0x68, 0x1E, 0xDB, 0xF2, 0x92, 0x0F, 0x8F,\n\t0x34, 0x6B, 0x82, 0x3A, 0xEF, 0x94, 0x80, 0xCE, 0xCB, 0xEF, 0xF3, 0x22,\n\t0x6C, 0x99, 0x7B, 0x6C, 0xCC, 0x27, 0x0F, 0x84, 0xEC, 0x1C, 0x56, 0x14,\n\t0x3C, 0xD9, 0x84, 0x1B, 0x26, 0x5A, 0x88, 0xF1, 0xA6, 0x0C, 0x86, 0xF8,\n\t0x62, 0xED, 0x64, 0xB5, 0x8D, 0xD4, 0x06, 0x98, 0xD6, 0xF2, 0xB5, 0xEC,\n\t0xB7, 0x40, 0x96, 0xEC, 0xAA, 0xAA, 0x5B, 0x0E, 0xC9, 0x7F, 0x84, 0xDB,\n\t0xB2, 0x91, 0x15, 0x86, 0xA3, 0xFA, 0x1D, 0xE8, 0xEF, 0xBA, 0x87, 0xFD,\n\t0x70, 0xE3, 0x89, 0xFE, 0x2A, 0xA5, 0x41, 0x74, 0xB9, 0xF2, 0x70, 0xED,\n\t0x12, 0xB6, 0xA2, 0x42, 0x00, 0x9F, 0x17, 0xFB, 0x43, 0xB3, 0x6A, 0x59,\n\t0xEA, 0x20, 0xD9, 0xD1, 0x9C, 0x5C, 0x84, 0x71, 0x57, 0x01, 0x7C, 0x3C,\n\t0x20, 0x61, 0x08, 0xAC, 0xB7, 0xB0, 0xEE, 0x29, 0x45, 0xBF, 0x87, 0xDB,\n\t0xC8, 0x33, 0xB1, 0x8A, 0xCC, 0x96, 0xC8, 0xB2, 0xF8, 0x89, 0x0B, 0x81,\n\t0xEF, 0xAA, 0x67, 0xFB, 0xC9, 0xD5, 0xFC, 0xFE, 0x3D, 0xEC, 0x78, 0x83,\n\t0x3A, 0xF6, 0x13, 0x43, 0x6E, 0x47, 0xA2, 0xDE, 0x48, 0x5B, 0x79, 0xCF,\n\t0x1F, 0x1C, 0xAD, 0xA4, 0x2C, 0x15, 0x81, 0x12, 0xDC, 0x2F, 0x80, 0x6F,\n\t0x7A, 0x32, 0x03, 0x52, 0x3B, 0xB0, 0x97, 0x41, 0xD5, 0xAB, 0x55, 0x2E,\n\t0xEA, 0xE9, 0xBB, 0xEB, 0x5B, 0x3E, 0xD5, 0x2E, 0xBC, 0xCE, 0x7E, 0x2D,\n\t0x52, 0xF3, 0x37, 0xF2, 0x53, 0x89, 0x5E, 0x56, 0x66, 0x74, 0xBF, 0xE2,\n\t0x35, 0xAA, 0xEA, 0x45, 0xE9, 0x6F, 0xFC, 0x1E, 0x15, 0x8E, 0x13, 0x5A,\n\t0xC6, 0xA2, 0x0B, 0x72, 0x89, 0x2B, 0x5E, 0x14, 0xC6, 0x41, 0x36, 0x0B,\n\t0xA0, 0xA4, 0x2B, 0x7F, 0x7E, 0xD0, 0x90, 0xFE, 0x4F, 0x4E, 0x7B, 0xD8,\n\t0x5B, 0x06, 0xEE, 0x0F, 0x62, 0xB6, 0x54, 0xDB, 0x17, 0x9B, 0x16, 0xEA,\n\t0x72, 0xAC, 0x58, 0x9D, 0x88, 0xD0, 0xE6, 0x14, 0x82, 0x57, 0x89, 0xEA,\n\t0x3A, 0x3D, 0x23, 0xE9, 0x14, 0x14, 0x0D, 0x95, 0x24, 0x7E, 0xAF, 0x4F,\n\t0x39, 0x3E, 0x51, 0x74, 0x06, 0xCC, 0x58, 0xA6, 0x50, 0xF0, 0xF8, 0x1B,\n\t0xD6, 0x48, 0xEB, 0xBD, 0x68, 0x34, 0xD8, 0x19, 0xA6, 0x83, 0x41, 0x37,\n\t0xDD, 0x41, 0x42, 0x1E, 0x5F, 0xFF, 0x0D, 0xEA, 0x25, 0x42, 0x55, 0x39,\n\t0xAA, 0x75, 0x88, 0x0F, 0xC8, 0x04, 0x47, 0x7A, 0xCA, 0xD0, 0x88, 0x72,\n\t0x74, 0x95, 0x1B, 0xCA, 0xEB, 0xF6, 0x11, 0x03, 0xA1, 0x0C, 0x61, 0x9E,\n\t0x4F, 0x2E, 0x6A, 0x60, 0x64, 0x7E, 0x5B, 0x12, 0xC4, 0x38, 0xFD, 0x66,\n\t0xBA, 0xBB, 0xAC, 0x1B, 0xF4, 0xAB, 0x7D, 0x35, 0x4E, 0xAB, 0x47, 0x3F,\n\t0xDA, 0xD5, 0x0C, 0x0D, 0x61, 0x85, 0xEF, 0x78, 0x74, 0x27, 0x1D, 0x39,\n\t0x07, 0x2B, 0x8C, 0x45, 0x24, 0xC6, 0x3A, 0xD4, 0x29, 0x71, 0xEE, 0xF0,\n\t0xAA, 0xDB, 0xE0, 0x4A, 0x5E, 0xB2, 0xEC, 0x91, 0xA6, 0xA6, 0xC8, 0xBC,\n\t0x60, 0x24, 0x58, 0x77, 0xBB, 0x5C, 0x07, 0x14, 0x39, 0x52, 0xE0, 0xA0,\n\t0xCC, 0x15, 0xA2, 0xC9, 0xA7, 0x69, 0x6F, 0xBC, 0x61, 0x38, 0xD3, 0x36,\n\t0xBC, 0xFC, 0x22, 0x96, 0x07, 0xB5, 0xE7, 0xFA, 0xA8, 0x9E, 0x99, 0x8F,\n\t0xDB, 0x62, 0xB0, 0x49, 0xF4, 0xD3, 0xC9, 0xFF, 0x7D, 0xA3, 0x12, 0xEF,\n\t0x61, 0x13, 0xF3, 0x81, 0x80, 0xB3, 0xCD, 0x74, 0x21, 0x12, 0x0F, 0x36,\n\t0x67, 0x52, 0xCE, 0xD1, 0x1D, 0x23, 0xA5, 0x35, 0x6B, 0x5F, 0x74, 0x62,\n\t0x8A, 0xAD, 0xED, 0x36, 0x27, 0xF8, 0x7D, 0xE6, 0xED, 0x78, 0xE4, 0xD2,\n\t0x4D, 0x56, 0xC5, 0xE1, 0x29, 0x54, 0x2D, 0x3E, 0x80, 0x97, 0xD0, 0xDC,\n\t0x1F, 0x89, 0x05, 0xAE, 0xE8, 0xB3, 0x21, 0xD5, 0xF4, 0x0B, 0xBB, 0x73,\n\t0xF6, 0x1A, 0x6A, 0xD5, 0x2E, 0xD4, 0xE3, 0x37, 0x93, 0x04, 0x91, 0x52,\n\t0x5E, 0xCC, 0x8E, 0xC5, 0xD5, 0x0A, 0xB7, 0x11, 0xA7, 0xB3, 0xA1, 0xB1,\n\t0xE0, 0x06, 0x61, 0xF7, 0xD6, 0xB4, 0x0C, 0x07, 0x27, 0x55, 0x67, 0x51,\n\t0xC0, 0x17, 0xD5, 0x44, 0xFB, 0xF7, 0xE6, 0x40, 0xAD, 0x58, 0x78, 0x6D,\n\t0xA5, 0x81, 0x60, 0x84, 0x9A, 0xB0, 0xEC, 0x9A, 0x7A, 0xEF, 0x5F, 0xEF,\n\t0xD6, 0x86, 0x8C, 0x66, 0xC6, 0xFE, 0x1B, 0x12, 0x4F, 0x87, 0xC1, 0xB1,\n\t0x1A, 0x85, 0x65, 0xE0, 0x44, 0xC6, 0x7F, 0xD3, 0xA4, 0x2C, 0x84, 0xF6,\n\t0x77, 0x70, 0x98, 0x43, 0xB2, 0x83, 0xB8, 0xD4, 0x6B, 0xAD, 0xD1, 0xC8,\n\t0x38, 0x98, 0x06, 0x43, 0xA9, 0xAB, 0x01, 0x02, 0x7D, 0x69, 0x01, 0x12,\n\t0x65, 0x58, 0x5E, 0x3C, 0xE7, 0xCD, 0x57, 0xD9, 0x18, 0x24, 0xA1, 0x96,\n\t0x8B, 0x64, 0x92, 0x5E, 0xBF, 0x6D, 0x8D, 0x8C, 0xF4, 0xE2, 0x35, 0x28,\n\t0xBB, 0xE2, 0x9A, 0x26, 0x08, 0xA6, 0xBD, 0x66, 0x09, 0x06, 0x41, 0x7D,\n\t0x43, 0x52, 0xBC, 0x17, 0x97, 0x7D, 0x98, 0x34, 0x9D, 0x84, 0x62, 0x57,\n\t0xC8, 0xDE, 0x7F, 0x85, 0xEE, 0xE9, 0x54, 0xD7, 0x11, 0x99, 0xFB, 0xA6,\n\t0xB6, 0x4F, 0x4B, 0x06, 0x9D, 0xDC, 0x3C, 0xF6, 0x6E, 0xB6, 0xAC, 0x93,\n\t0x6F, 0x4E, 0x1E, 0x9E, 0x5A, 0xB2, 0xC3, 0x6F, 0xC6, 0x99, 0x9C, 0xDA,\n\t0x25, 0x7D, 0x2E, 0x98, 0xDE, 0x0A, 0x7D, 0x75, 0xFF, 0xEE, 0xC9, 0x1E,\n\t0xC2, 0x1E, 0x49, 0xE2, 0xCD, 0x06, 0x2D, 0x42, 0x27, 0x12, 0xC2, 0x73,\n\t0x2B, 0x4A, 0x72, 0x8A, 0x70, 0x92, 0x91, 0x26, 0xE1, 0xDD, 0x30, 0xCA,\n\t0x1D, 0x27, 0x88, 0x99, 0x18, 0x8B, 0xBA, 0x05, 0xC6, 0x8C, 0x46, 0x01,\n\t0xE2, 0x83, 0x84, 0xBE, 0xE7, 0x71, 0x56, 0xD2, 0xF9, 0xDF, 0x66, 0x45,\n\t0xAB, 0x05, 0x30, 0x78, 0xE7, 0xE9, 0xCB, 0xF4, 0x10, 0x80, 0xB6, 0x50,\n\t0x7F, 0xD7, 0x9E, 0x5D, 0x93, 0xD0, 0x6F, 0xD7, 0x1E, 0x99, 0xC3, 0xC7,\n\t0xA0, 0x96, 0x7F, 0xE3, 0xAF, 0xF3, 0x71, 0x8A, 0x3A, 0x7B, 0xE0, 0xA9,\n\t0x77, 0x0E, 0x9F, 0xB2, 0xD7, 0x31, 0x34, 0x25, 0xE9, 0x2B, 0x4A, 0x5C,\n\t0x44, 0xAC, 0x27, 0x49, 0xFF, 0xAE, 0x91, 0x17, 0xB3, 0xFA, 0xF6, 0x72,\n\t0x96, 0xC8, 0x5C, 0x4F, 0x78, 0x1C, 0x55, 0x74, 0xD3, 0x78, 0xD9, 0x2E,\n\t0xE6, 0xA7, 0xEA, 0x29, 0x0E, 0xAA, 0x71, 0xAC, 0x77, 0xF6, 0xA2, 0x5A,\n\t0x00, 0x4C, 0xF8, 0xAA, 0x2E, 0xC7, 0x48, 0xD1, 0xC7, 0x0C, 0xB2, 0x4F,\n\t0xC7, 0xCA, 0xCC, 0xC7, 0xDF, 0xDC, 0x18, 0x8C, 0x29, 0x5B, 0x22, 0xB1,\n\t0x01, 0x1B, 0x54, 0x47, 0x5B, 0x98, 0x88, 0x49, 0x65, 0xB6, 0x55, 0xF5,\n\t0x7B, 0xD3, 0x5D, 0x37, 0x1A, 0xD5, 0x23, 0xF0, 0x5C, 0x2F, 0x96, 0xAB,\n\t0xD9, 0xCE, 0x6A, 0xA5, 0x9A, 0xAE, 0xDE, 0xB2, 0x46, 0x55, 0xF6, 0x6F,\n\t0x4E, 0xA1, 0x4C, 0x4E, 0xF2, 0x32, 0xCC, 0x89, 0xA3, 0x0F, 0x16, 0xFD,\n\t0x6C, 0x73, 0x07, 0x84, 0x9B, 0x6D, 0xC7, 0x3A, 0x9F, 0x04, 0xFA, 0x31,\n\t0xB8, 0x31, 0xD2, 0x9E, 0x1A, 0xE8, 0x36, 0x05, 0xEA, 0xD5, 0x88, 0x83,\n\t0x56, 0xB4, 0x2B, 0x87, 0xFD, 0xDF, 0x52, 0xFB, 0xBA, 0x6E, 0x7B, 0x6C,\n\t0x18, 0xCE, 0xAD, 0xD1, 0xF0, 0xBD, 0xC5, 0xF7, 0x42, 0x96, 0x83, 0xD9,\n\t0x70, 0x24, 0xF9, 0x32, 0x26, 0x2F, 0x69, 0x94, 0x05, 0xB2, 0x92, 0xB9,\n\t0x00, 0x68, 0x8F, 0x25, 0xF2, 0x33, 0x3D, 0x6D, 0x3E, 0x58, 0xE0, 0x0B,\n\t0x33, 0xA8, 0x0A, 0x58, 0x2F, 0x46, 0x49, 0x52, 0x2D, 0x7C, 0x5B, 0xF8,\n\t0x51, 0x29, 0x6C, 0xE1, 0xB4, 0x80, 0xAF, 0x31, 0x03, 0xCC, 0xF5, 0xCD,\n\t0x80, 0x13, 0x07, 0x96, 0xB4, 0x92, 0x29, 0x60, 0xBB, 0x95, 0xF4, 0x21,\n\t0xA3, 0x82, 0xB2, 0x33, 0x70, 0x19, 0x24, 0x9E, 0xA0, 0x53, 0xBE, 0x0C,\n\t0xC7, 0x0F, 0x36, 0x7B, 0xC7, 0xFA, 0xB5, 0x2C, 0xC8, 0xA4, 0x61, 0xD6,\n\t0xA4, 0x79, 0x11, 0x98, 0x47, 0x43, 0xF0, 0xA5, 0x33, 0x3C, 0xF3, 0xFB,\n\t0x7D, 0xF2, 0x22, 0x22, 0x80, 0x48, 0xE3, 0xFA, 0x2D, 0x5B, 0x73, 0xCB,\n\t0x60, 0xE6, 0x2A, 0xCB, 0x1A, 0xF8, 0x66, 0xC0, 0x7D, 0xB0, 0xEE, 0x36,\n\t0x9C, 0xD5, 0x00, 0x10, 0x9A, 0x6A, 0xF1, 0xB9, 0x32, 0x99, 0xF7, 0xEA,\n\t0xB8, 0x29, 0xCB, 0xFA, 0x9E, 0xC6, 0xB1, 0x2C, 0x4F, 0x9A, 0x54, 0xC8,\n\t0x96, 0x86, 0x1E, 0xCF, 0x79, 0x32, 0x4E, 0x81, 0x6C, 0x70, 0x7C, 0x68,\n\t0x68, 0x91, 0xFC, 0x17, 0xF7, 0xBC, 0x12, 0x4C, 0x6F, 0xB3, 0x23, 0xBF,\n\t0xF1, 0xDE, 0xEE, 0x47, 0x0E, 0xD4, 0xC3, 0xD5, 0x2C, 0x56, 0xA2, 0x0E,\n\t0x96, 0xF2, 0x79, 0x34, 0x52, 0x53, 0xB8, 0x63, 0xD0, 0x6D, 0x53, 0x3E,\n\t0x82, 0xD9, 0x2A, 0xB8, 0xE6, 0xC0, 0x9E, 0x43, 0x36, 0xEA, 0xE2, 0xD3,\n\t0xD6, 0xB3, 0x81, 0x1C, 0x53, 0xD7, 0x9A, 0xEC, 0xDD, 0x19, 0x23, 0x5A,\n\t0x64, 0x17, 0xE9, 0x87, 0xF8, 0x2B, 0xCF, 0x77, 0xAB, 0x09, 0x8A, 0x3B,\n\t0xD2, 0xF1, 0x0B, 0x6D, 0xE0, 0x28, 0xA7, 0x04, 0x36, 0x2C, 0x66, 0xBB,\n\t0x6A, 0x9E, 0xAD, 0x6B, 0xA3, 0xE6, 0x9E, 0x14, 0xFA, 0x25, 0xAE, 0xA6,\n\t0x7E, 0x59, 0xFD, 0x2A, 0x2C, 0x6C, 0x6D, 0x42, 0xF7, 0xF7, 0x2C, 0x6B,\n\t0xEB, 0xC3, 0xA0, 0xB1, 0x07, 0x2C, 0x86, 0xA9, 0xD1, 0x2D, 0xEB, 0x3D,\n\t0x02, 0xF2, 0xD0, 0x33, 0x79, 0xE4, 0x72, 0x0A, 0x4A, 0xCC, 0xBC, 0x5A,\n\t0x22, 0xCD, 0xB5, 0x35, 0x61, 0xEA, 0xB6, 0x7D, 0xEE, 0xA5, 0xAD, 0xE2,\n\t0x49, 0x5B, 0x94, 0xE4, 0x67, 0x72, 0x87, 0x8A, 0xC9, 0xAC, 0xE2, 0x96,\n\t0xE0, 0x7B, 0x0A, 0x8D, 0xB5, 0xFF, 0x35, 0x99, 0xF1, 0x71, 0xFA, 0x77,\n\t0x00, 0x60, 0x1A, 0x39, 0x64, 0x3F, 0x86, 0x86, 0x5A, 0xEC, 0xD3, 0xD7,\n\t0xCF, 0xC1, 0xA0, 0x3E, 0xDB, 0xA7, 0xED, 0xC6, 0x24, 0x63, 0x96, 0x29,\n\t0xAF, 0xCB, 0x49, 0x24, 0x08, 0xC5, 0x0D, 0xE0, 0x52, 0x95, 0x89, 0xB3,\n\t0xA8, 0xDD, 0x4D, 0x66, 0xAC, 0x7C, 0x7A, 0x15, 0xA5, 0x81, 0xBE, 0xB9,\n\t0x7E, 0x1C, 0x82, 0xA5, 0xD5, 0x45, 0x86, 0xE6, 0x06, 0x5C, 0x60, 0xC7,\n\t0x0F, 0xD3, 0x51, 0xF1, 0x17, 0x34, 0x6D, 0x43, 0xB1, 0x98, 0x52, 0x11,\n\t0x24, 0x3B, 0x9E, 0x5A, 0xE9, 0xD1, 0xEE, 0x7C, 0x64, 0xF5, 0xBB, 0x4B,\n\t0xBC, 0xC3, 0x43, 0x5F, 0x80, 0x27, 0xF2, 0x1A, 0xFC, 0xEA, 0xA0, 0x5C,\n\t0x25, 0xA4, 0x63, 0x16, 0x0B, 0xAA, 0x30, 0x2E, 0x4E, 0x68, 0x9D, 0xE0,\n\t0xEE, 0x38, 0x28, 0x80, 0xC7, 0x22, 0x10, 0x19, 0x55, 0x7F, 0x4C, 0xFE,\n\t0xD0, 0xBA, 0x38, 0x4A, 0x1E, 0xD0, 0x42, 0xE3, 0x57, 0x57, 0xD5, 0x3B,\n\t0xC3, 0xE7, 0x58, 0xA4, 0x7E, 0x29, 0x83, 0x9B, 0xDF, 0x16, 0x45, 0x1D,\n\t0xE1, 0xDC, 0xE2, 0xE2, 0xAB, 0x0E, 0x45, 0x3F, 0x34, 0x0C, 0x47, 0x88,\n\t0xEB, 0x0A, 0xF0, 0x55, 0x38, 0x7D, 0xCD, 0x73, 0x73, 0xEA, 0x59, 0xAB,\n\t0xA2, 0xFA, 0xF5, 0x20, 0x9B, 0x64, 0xCE, 0xB5, 0x6B, 0x0C, 0x40, 0x25,\n\t0xC7, 0x3B, 0x03, 0xED, 0xA9, 0x4C, 0x8F, 0x47, 0x44, 0x2B, 0x18, 0x6B,\n\t0x96, 0xF0, 0x1B, 0xAD, 0x6B, 0x3C, 0x7E, 0xA7, 0x60, 0xB5, 0x1F, 0x51,\n\t0x17, 0x05, 0xF3, 0xD1, 0xF5, 0x2A, 0x5C, 0xE6, 0xC4, 0x81, 0xBF, 0x91,\n\t0xBB, 0x52, 0xA5, 0x7B, 0x4B, 0xB3, 0x19, 0x8D, 0x13, 0xDB, 0xA6, 0x31,\n\t0xF8, 0x9F, 0x36, 0x21, 0x83, 0xF3, 0x0E, 0xF5, 0x13, 0x3B, 0xD4, 0x87,\n\t0xE2, 0xE1, 0x83, 0x3D, 0x56, 0x1A, 0x75, 0x4B, 0x80, 0x33, 0x22, 0xF1,\n\t0x5F, 0xCA, 0x53, 0xD0, 0x36, 0x6E, 0x4D, 0x4B, 0x95, 0xA2, 0x15, 0xB5,\n\t0x73, 0x5F, 0x97, 0x6B, 0xCE, 0xE1, 0x16, 0x3B, 0x8E, 0xBD, 0xF3, 0x54,\n\t0x8B, 0xC4, 0x10, 0x47, 0x10, 0x3B, 0x5D, 0xA4, 0xC9, 0x2E, 0xCB, 0x32,\n\t0x21, 0x1D, 0x1E, 0xE2, 0x03, 0xA1, 0x5F, 0x8B, 0x0B, 0x65, 0xCC, 0x11,\n\t0x46, 0x73, 0xF8, 0x51, 0x4F, 0xBA, 0x27, 0xAD, 0x85, 0xC7, 0xAB, 0xD0,\n\t0xA2, 0x90, 0x79, 0x27, 0x23, 0xF8, 0x1A, 0x94, 0x79, 0x82, 0xC3, 0x17,\n\t0x2B, 0xA8, 0x3E, 0x59, 0x2A, 0x64, 0xCD, 0x16, 0xDD, 0xBB, 0xA3, 0x0C,\n\t0x34, 0xDE, 0xAE, 0xAF, 0x5D, 0xDE, 0x90, 0x31, 0x7F, 0x9A, 0x69, 0x14,\n\t0x65, 0xAC, 0xC0, 0xED, 0xE9, 0xB8, 0xDD, 0x59, 0x4F, 0x37, 0xA7, 0xEC,\n\t0x5A, 0xA8, 0x96, 0xC2, 0xF8, 0x2A, 0xE6, 0xB4, 0xDD, 0xE7, 0xF8, 0x44,\n\t0x5B, 0x39, 0x4B, 0x47, 0xCE, 0x0C, 0x33, 0xB1, 0x99, 0xB2, 0x32, 0x05,\n\t0x7E, 0xFD, 0x12, 0x5B, 0xF8, 0xD2, 0x9D, 0x20, 0x94, 0x8D, 0x19, 0xFA,\n\t0x82, 0x61, 0xB3, 0x99, 0x7C, 0x8C, 0x15, 0x0E, 0x0D, 0x9C, 0xFC, 0xC1,\n\t0xDC, 0x0C, 0x79, 0x69, 0x07, 0xD8, 0x13, 0x86, 0xDA, 0xA4, 0xF0, 0xCF,\n\t0x5B, 0xDE, 0xF7, 0xB9, 0x71, 0x7C, 0x13, 0xA6, 0xAF, 0x31, 0x88, 0x1E,\n\t0x3B, 0xFC, 0x96, 0xDF, 0xE5, 0x63, 0x80, 0x69, 0x87, 0x09, 0xD8, 0x46,\n\t0xBB, 0x28, 0x18, 0x34, 0x1A, 0x03, 0xE8, 0xF4, 0x46, 0x46, 0x8B, 0xD5,\n\t0x3C, 0xD6, 0x02, 0xE3, 0xE2, 0x1A, 0x9A, 0xC7, 0x97, 0x2A, 0x62, 0x60,\n\t0x6A, 0xBD, 0x60, 0xFD, 0x5D, 0x4A, 0x68, 0x92, 0x56, 0x8F, 0x86, 0xAD,\n\t0x57, 0x36, 0x1B, 0xD6, 0x6C, 0x57, 0xB8, 0x41, 0x13, 0x1D, 0x13, 0xB8,\n\t0xB1, 0x60, 0xE2, 0xB5, 0x9A, 0x8F, 0xE3, 0x56, 0xAC, 0xD2, 0xC6, 0x62,\n\t0xBA, 0xA8, 0x66, 0x4D, 0xDA, 0x58, 0x9A, 0xCE, 0x8F, 0xCD, 0x55, 0xF6,\n\t0x19, 0xF1, 0x2C, 0xED, 0x38, 0x66, 0xAD, 0x88, 0x56, 0x2F, 0xA3, 0x42,\n\t0x93, 0x55, 0x33, 0x06, 0x35, 0x2B, 0xDE, 0x1E, 0xD9, 0x1B, 0x07, 0x5C,\n\t0x98, 0xD0, 0x74, 0xE7, 0x56, 0x97, 0x4F, 0xD1, 0xA4, 0x17, 0xB2, 0xB3,\n\t0x32, 0x70, 0xDF, 0x91, 0xEC, 0xC2, 0xA6, 0x86, 0xBC, 0x4E, 0xFC, 0x17,\n\t0xA6, 0x13, 0x50, 0x0C, 0x1E, 0x3C, 0x50, 0xDF, 0x6C, 0x14, 0x74, 0xBE,\n\t0xF5, 0x20, 0xB8, 0xBF, 0xA0, 0xF7, 0x3E, 0x32, 0x5F, 0x22, 0x9B, 0x15,\n\t0x74, 0xBC, 0xD5, 0x42, 0xCE, 0x19, 0xAA, 0x5C, 0x01, 0xB1, 0x77, 0xC3,\n\t0x50, 0x56, 0xCD, 0x8C, 0x61, 0xBA, 0x20, 0xFB, 0xD5, 0x76, 0x1D, 0x57,\n\t0xA3, 0xBB, 0xFC, 0xFB, 0x07, 0x1F, 0x43, 0x07, 0x39, 0x70, 0xAC, 0x82,\n\t0x6A, 0x41, 0xDE, 0x41, 0x3B, 0xE4, 0xC4, 0x3A, 0xD6, 0x4D, 0xF0, 0x77,\n\t0x54, 0xC7, 0x35, 0x26, 0x98, 0x47, 0x71, 0xEC, 0x2F, 0x02, 0x5F, 0x89,\n\t0x4B, 0xB0, 0xF3, 0xA5, 0xC7, 0x99, 0xB7, 0x2D, 0x65, 0xE3, 0x42, 0x07,\n\t0x17, 0x22, 0xD8, 0x96, 0x0A, 0x01, 0xB3, 0x26, 0xA1, 0x64, 0xCF, 0x4D,\n\t0xFA, 0x59, 0x54, 0xD9, 0x52, 0x6D, 0xAE, 0x62, 0x3D, 0x96, 0x1B, 0x49,\n\t0x6C, 0x38, 0x30, 0x16, 0xE9, 0xAE, 0xB8, 0x8E, 0xDF, 0x2A, 0x11, 0x33,\n\t0x09, 0x79, 0x60, 0x0E, 0xCC, 0xB8, 0x7D, 0xDF, 0x80, 0x76, 0x05, 0x89,\n\t0xDF, 0x96, 0xD6, 0x0E, 0x89, 0x5E, 0x72, 0x1D, 0x31, 0x9B, 0xA2, 0xED,\n\t0x41, 0x7F, 0x41, 0x2F, 0xCB, 0x31, 0xD9, 0x8A, 0x36, 0x90, 0xDB, 0xD1,\n\t0x26, 0xE5, 0x29, 0x7C, 0x37, 0x99, 0xFA, 0xDF, 0x6C, 0xF1, 0x49, 0x0B,\n\t0xE2, 0xD8, 0xB7, 0x53, 0x34, 0xEF, 0xDF, 0x9A, 0xBC, 0xCF, 0x23, 0x32,\n\t0xD1, 0x3C, 0xA7, 0x4A, 0xF4, 0x48, 0x1A, 0xE6, 0x4C, 0x8D, 0x04, 0x3D,\n\t0x7B, 0x1D, 0x63, 0xAB, 0xB4, 0xB8, 0xA1, 0x23, 0x71, 0xAB, 0x15, 0x01,\n\t0x00, 0xC6, 0x02, 0xAD, 0x86, 0x31, 0xDA, 0x07, 0x1C, 0x17, 0xBD, 0xED,\n\t0xF0, 0x2E, 0x7C, 0xA2, 0x64, 0x7B, 0x45, 0x4E, 0x5E, 0x76, 0x8E, 0x07,\n\t0x26, 0x2B, 0x4E, 0x4B, 0x8B, 0x31, 0xE4, 0xB1, 0xD8, 0xCD, 0x5C, 0xE7,\n\t0x68, 0xEF, 0x87, 0x5D, 0x57, 0xA6, 0x02, 0xDE, 0x64, 0xE5, 0x04, 0xB2,\n\t0xC8, 0x6F, 0xE6, 0x4B, 0xE0, 0x30, 0x38, 0x94, 0xFE, 0xC0, 0x0D, 0xE7,\n\t0x10, 0xCB, 0x98, 0x59, 0x9F, 0xE8, 0xBC, 0x78, 0x3C, 0x67, 0xDE, 0x4B,\n\t0x72, 0x6A, 0x40, 0x85, 0xFF, 0xCE, 0x72, 0xC9, 0x74, 0x44, 0x6F, 0xC8,\n\t0x4D, 0xA5, 0xC9, 0x6B, 0xBB, 0x0E, 0xF5, 0x26, 0x89, 0x06, 0x23, 0xA2,\n\t0xF0, 0x30, 0x01, 0xD4, 0x0C, 0xE9, 0xE9, 0x8D, 0x71, 0x77, 0x41, 0x1D,\n\t0x7A, 0x71, 0x79, 0x63, 0x86, 0xC9, 0x0D, 0x17, 0x67, 0x62, 0x6A, 0x24,\n\t0x64, 0xC8, 0xBD, 0xA4, 0xED, 0x7B, 0xF2, 0x35, 0x59, 0x53, 0x09, 0x70,\n\t0x56, 0xF2, 0xBB, 0x9B, 0x33, 0xEF, 0xFE, 0x25, 0x31, 0x65, 0x74, 0x5A,\n\t0xC8, 0x54, 0xD7, 0xE9, 0x10, 0x88, 0x16, 0x60, 0xB7, 0x4C, 0x9E, 0x8F,\n\t0x9F, 0xFA, 0x02, 0x5E, 0x78, 0xF2, 0x4D, 0x07, 0x42, 0x35, 0xAE, 0x55,\n\t0x3E, 0xA2, 0xBA, 0x6C, 0xB6, 0xBD, 0x87, 0xD8, 0xD8, 0xC8, 0x1F, 0xCA,\n\t0xD5, 0xA8, 0xCD, 0x5D, 0x05, 0xF5, 0xFA, 0x69, 0xDE, 0x0E, 0x0C, 0x5F,\n\t0x24, 0x0C, 0x4C, 0x36, 0xB1, 0x00, 0x3B, 0x61, 0x74, 0xDB, 0x81, 0xFB,\n\t0x41, 0x8D, 0x16, 0xDB, 0x46, 0x8C, 0x75, 0x53, 0x31, 0x87, 0x48, 0x03,\n\t0x26, 0xE7, 0xDA, 0x56, 0xD5, 0x59, 0x13, 0xAC, 0x49, 0x25, 0x6E, 0xE7,\n\t0x9F, 0xCD, 0xDE, 0x17, 0xC7, 0xA0, 0x04, 0x3E, 0x80, 0x3B, 0x61, 0x28,\n\t0x1F, 0xDA, 0xA7, 0x97, 0xE2, 0x99, 0x0D, 0x9B, 0x34, 0xDB, 0x67, 0x41,\n\t0x0E, 0xC1, 0x65, 0x6F, 0xE8, 0xD4, 0x92, 0x02, 0xBF, 0x86, 0xC2, 0x99,\n\t0x31, 0x58, 0xB2, 0x16, 0xBE, 0x8D, 0xAA, 0x7C, 0xF8, 0xC2, 0xF1, 0x93,\n\t0xBB, 0x06, 0x2B, 0xE8, 0x59, 0x77, 0x49, 0xDD, 0x71, 0x62, 0xC3, 0xBC,\n\t0x9F, 0x3E, 0x6D, 0x7B, 0x04, 0x4D, 0x96, 0x60, 0x86, 0xDB, 0xDB, 0x70,\n\t0xCA, 0x04, 0x2A, 0x21, 0xBA, 0xFF, 0x9A, 0x6D, 0xC8, 0x31, 0x04, 0xA0,\n\t0x1D, 0xE7, 0x34, 0xE5, 0xD6, 0x21, 0xF7, 0x55, 0x2B, 0xCE, 0x01, 0x62,\n\t0x4E, 0xCF, 0x2E, 0xAC, 0x5F, 0x6A, 0xAD, 0xE3, 0x72, 0xC1, 0x65, 0x34,\n\t0xF1, 0xB5, 0xF3, 0x37, 0xDE, 0x52, 0xB2, 0x89, 0x0C, 0xA5, 0x12, 0x96,\n\t0x46, 0xCE, 0x2E, 0x2E, 0x0C, 0xAA, 0x2E, 0xA2, 0x96, 0xFF, 0xDA, 0xDE,\n\t0x1A, 0x2D, 0x02, 0x65, 0x5A, 0xA1, 0x87, 0x3B, 0x09, 0x3C, 0x7D, 0x44,\n\t0xCD, 0x4A, 0x36, 0xEC, 0xA5, 0x25, 0x4D, 0x17, 0x49, 0x03, 0xD4, 0xEE,\n\t0xB7, 0x80, 0x8D, 0x70, 0xD7, 0x2F, 0x42, 0xE7, 0x65, 0x16, 0x99, 0x02,\n\t0xAF, 0x85, 0xC5, 0x91, 0x82, 0xBE, 0x37, 0x93, 0x5B, 0x2B, 0x2C, 0x6E,\n\t0x49, 0x71, 0x17, 0x4E, 0xBA, 0xA7, 0x64, 0x63, 0x16, 0x53, 0xF5, 0x66,\n\t0xB9, 0xE6, 0xCC, 0x49, 0xC6, 0xDE, 0x8C, 0xC6, 0x26, 0x85, 0xDD, 0x49,\n\t0x4E, 0xF6, 0x67, 0x93, 0xEA, 0xC5, 0xF2, 0x5B, 0x61, 0xC7, 0x3B, 0xBC,\n\t0x36, 0x51, 0xB1, 0x79, 0x7C, 0x17, 0xE9, 0x80, 0x3D, 0xE2, 0xDC, 0x99,\n\t0xB8, 0xA7, 0x74, 0x0C, 0xEB, 0xE0, 0xE6, 0xC6, 0x32, 0xA6, 0xE3, 0x03,\n\t0xB3, 0xE5, 0xEF, 0x33, 0x48, 0xE7, 0x03, 0x74, 0xEC, 0x55, 0x6C, 0x3C,\n\t0x7A, 0x93, 0x3D, 0x8C, 0x00, 0xD3, 0xB0, 0x58, 0x31, 0x89, 0x26, 0xC3,\n\t0x66, 0x8B, 0xDC, 0xAC, 0xCF, 0x46, 0x38, 0xBE, 0xE2, 0xB7, 0x4B, 0xB5,\n\t0xCB, 0xF4, 0x48, 0x64, 0x24, 0x48, 0x3D, 0x73, 0x89, 0x2F, 0x36, 0xC8,\n\t0x49, 0x09, 0xEC, 0x8C, 0x9E, 0x39, 0xDC, 0xA7, 0x41, 0x50, 0x7E, 0x8C,\n\t0xA4, 0x08, 0xB7, 0x54, 0xCB, 0x50, 0x63, 0xD2, 0xB6, 0x52, 0x27, 0xEA,\n\t0x80, 0x54, 0x2F, 0xB9, 0xE5, 0x30, 0x3B, 0x03, 0x07, 0x1A, 0x90, 0x14,\n\t0x72, 0x98, 0xC7, 0x99, 0xF8, 0x54, 0xA8, 0x57, 0xDB, 0x0F, 0x1A, 0x47,\n\t0x63, 0xE2, 0xDD, 0xC7, 0x98, 0x6A, 0xEC, 0x6C, 0xDA, 0x01, 0x92, 0xA8,\n\t0x62, 0x12, 0xD9, 0xBA, 0x36, 0x4C, 0x3B, 0x83, 0x39, 0xEE, 0xD7, 0x9C,\n\t0x7E, 0x66, 0x1D, 0x7A, 0xBC, 0xFF, 0x4D, 0x2E, 0xC0, 0x1A, 0x95, 0x31,\n\t0x29, 0xC2, 0xA2, 0xEA, 0x1E, 0xFA, 0x16, 0x70, 0xE1, 0xB6, 0x18, 0xF7,\n\t0x65, 0x90, 0x0C, 0x6C, 0xB0, 0x47, 0xB1, 0x5C, 0xE3, 0xC7, 0x66, 0xF5,\n\t0xEC, 0xE5, 0x79, 0x68, 0xC1, 0x72, 0x4F, 0xFC, 0xEA, 0x1A, 0xC5, 0xB3,\n\t0x0A, 0xC4, 0x81, 0xF1, 0xA2, 0x44, 0xCC, 0xE8, 0x57, 0x4A, 0xD2, 0xB2,\n\t0x71, 0x04, 0xA4, 0x1E, 0x21, 0xEA, 0x50, 0xFF, 0x62, 0x1B, 0x7C, 0xA6,\n\t0x8F, 0xE8, 0x38, 0x02, 0xC6, 0xE0, 0xFE, 0x08, 0x5A, 0x9B, 0x9C, 0x32,\n\t0x08, 0x60, 0xD8, 0xBE, 0x2A, 0xBA, 0x71, 0x53, 0x03, 0x84, 0x36, 0x45,\n\t0x59, 0x6D, 0xE4, 0x6C, 0x06, 0xFC, 0x45, 0x6B, 0xDE, 0x47, 0x89, 0x72,\n\t0xD5, 0x66, 0x62, 0xD4, 0xDA, 0x74, 0x91, 0xE9, 0x93, 0x2F, 0xEA, 0x78,\n\t0x8F, 0x0A, 0x7C, 0xFC, 0x77, 0xFA, 0x17, 0x68, 0x96, 0xD0, 0xC6, 0xF5,\n\t0x32, 0x70, 0xD3, 0xFA, 0xE6, 0x4A, 0x2A, 0x52, 0x1F, 0xEF, 0x20, 0x2E,\n\t0xE9, 0xBC, 0x58, 0xCF, 0x17, 0xCB, 0xC0, 0xF1, 0x46, 0x32, 0x02, 0x6F,\n\t0xB3, 0xA1, 0x72, 0x55, 0x58, 0x5B, 0x75, 0x94, 0xBA, 0xD7, 0xCB, 0xA5,\n\t0xFD, 0x82, 0xDF, 0x4E, 0x29, 0xCB, 0x4B, 0xD7, 0x5C, 0xCE, 0xA7, 0x69,\n\t0x10, 0xFF, 0xDD, 0xD0, 0xB5, 0x8E, 0xC0, 0x27, 0xE4, 0x5A, 0xD3, 0x4A,\n\t0xBB, 0x43, 0xEB, 0x6D, 0xF7, 0xEF, 0x57, 0x86, 0x3D, 0xC7, 0x42, 0xB2,\n\t0x8D, 0x62, 0x65, 0xEB, 0x7C, 0xD1, 0x76, 0xFE, 0x47, 0x65, 0x7F, 0xC8,\n\t0xF7, 0x29, 0x10, 0xDC, 0xEF, 0x94, 0xFF, 0x75, 0x07, 0xFA, 0x75, 0x22,\n\t0xCF, 0xAC, 0x66, 0xBC, 0x7D, 0xBB, 0x6B, 0x57, 0x37, 0xEA, 0x8A, 0x20,\n\t0x27, 0xC8, 0x8E, 0x5E, 0xCA, 0x33, 0x33, 0xB9, 0x5F, 0x42, 0x18, 0x9A,\n\t0x1C, 0xEC, 0x6D, 0x8E, 0x63, 0xCF, 0xD7, 0x1F, 0x01, 0xD5, 0x1C, 0x0B,\n\t0x7A, 0x12, 0xE3, 0x26, 0xC4, 0x0B, 0xE7, 0x7C, 0x5B, 0xF3, 0xC9, 0x9B,\n\t0xD3, 0x97, 0xF1, 0x2C, 0x25, 0xF4, 0x29, 0xE0, 0xAE, 0x61, 0xC1, 0x24,\n\t0xE2, 0xDD, 0x26, 0xCC, 0xD4, 0x7D, 0xCA, 0x27, 0x07, 0xE5, 0x64, 0xE3,\n\t0xE9, 0x95, 0x8C, 0x1E, 0xE1, 0xF7, 0x32, 0x3D, 0x13, 0xF5, 0x3F, 0xC9,\n\t0x93, 0x57, 0xC7, 0x0E, 0xC2, 0x41, 0x37, 0x53, 0x41, 0x74, 0x90, 0xFF,\n\t0x7C, 0xD3, 0x07, 0x14, 0x6A, 0xC3, 0x66, 0xA7, 0x25, 0x20, 0x2C, 0xC9,\n\t0x5E, 0x69, 0x79, 0x38, 0xAF, 0xF0, 0xDE, 0x86, 0x2F, 0x89, 0xB8, 0xCA,\n\t0x2C, 0xFC, 0x2F, 0x66, 0x3A, 0xF2, 0x8D, 0x1B, 0x4C, 0x0E, 0xF7, 0x42,\n\t0x1A, 0xF2, 0x3D, 0xD6, 0xFF, 0x5F, 0xA6, 0x31, 0x70, 0xFC, 0x90, 0x14,\n\t0xDC, 0x79, 0xE6, 0xDC, 0x09, 0xC2, 0x45, 0x50, 0xF3, 0x6E, 0x25, 0xED,\n\t0x50, 0xDB, 0xDE, 0xBE, 0x3E, 0xF7, 0xBE, 0xF2, 0xA1, 0xCE, 0x08, 0xF6,\n\t0xB1, 0x49, 0xED, 0xC5, 0xB3, 0xF7, 0x4F, 0x6D, 0x1C, 0x70, 0x62, 0xFC,\n\t0xAF, 0x03, 0x0B, 0x33, 0x95, 0x53, 0x48, 0x78, 0x48, 0x7B, 0x0A, 0x3E,\n\t0xC3, 0xEC, 0xF8, 0x7F, 0xF6, 0x13, 0x29, 0x9E, 0xCE, 0x63, 0x25, 0xE9,\n\t0x68, 0x75, 0xCF, 0xBC, 0x3C, 0xFF, 0x4C, 0x6E, 0x6C, 0xD7, 0x7D, 0xF0,\n\t0xF5, 0xD1, 0xEF, 0x5F, 0x98, 0xE4, 0x53, 0x52, 0x34, 0x7E, 0xF6, 0x40,\n\t0xE6, 0x7D, 0xC9, 0x67, 0x8C, 0xE5, 0x3E, 0xC8, 0xF7, 0x10, 0x07, 0x04,\n\t0x76, 0xBC, 0xDB, 0xB1, 0xE9, 0xF5, 0xAF, 0xCE, 0xA7, 0x21, 0xBF, 0xE7,\n\t0xE8, 0x3F, 0xAA, 0xEA, 0x81, 0x54, 0x69, 0xBD, 0x0F, 0x36, 0x46, 0xB6,\n\t0xA5, 0xDD, 0xB2, 0x3E, 0x03, 0xFE, 0xDF, 0x2D, 0xCD, 0xE0, 0x3D, 0xEA,\n\t0xE8, 0x25, 0xA0, 0xCE, 0x0A, 0x9B, 0x1C, 0x99, 0xE7, 0x52, 0x46, 0xF2,\n\t0x46, 0x11, 0x1F, 0x47, 0x7B, 0xF4, 0xC0, 0x7B, 0x75, 0x68, 0x5E, 0xD1,\n\t0x32, 0x20, 0xEB, 0xFA, 0x21, 0xBD, 0x6A, 0xB1, 0x79, 0x2C, 0x02, 0x3B,\n\t0x98, 0x6B, 0x27, 0xD4, 0x49, 0x85, 0xD7, 0x19, 0x53, 0x2D, 0xF3, 0xAA,\n\t0x0B, 0xED, 0x6B, 0x5B, 0x5E, 0x6E, 0x7C, 0xC9, 0x3D, 0xCB, 0xC4, 0xCA,\n\t0x7E, 0xC9, 0x86, 0xA9, 0xF1, 0x9D, 0xB1, 0x7A, 0xE4, 0x49, 0xFB, 0xBE,\n\t0x9A, 0x28, 0x83, 0x1C, 0xF3, 0x80, 0x9E, 0x15, 0x33, 0xEB, 0xBE, 0x63,\n\t0xE2, 0x3C, 0xDC, 0xFE, 0x79, 0x8F, 0x04, 0xAB, 0xDA, 0x36, 0xA5, 0x27,\n\t0xBF, 0x90, 0x3A, 0xCB, 0xA7, 0xBA, 0xAC, 0x98, 0xA0, 0x36, 0x88, 0x7B,\n\t0xED, 0x2A, 0xF7, 0xDF, 0x78, 0xD0, 0x16, 0x86, 0x31, 0xEC, 0xA4, 0x29,\n\t0xCC, 0x72, 0xE9, 0x68, 0x50, 0x54, 0x43, 0x7E, 0xB7, 0xEE, 0x54, 0xBA,\n\t0xB8, 0xD0, 0x44, 0x08, 0x4B, 0xBB, 0xB6, 0x6C, 0x96, 0x62, 0xD7, 0xAE,\n\t0x61, 0xCE, 0x61, 0x9F, 0x89, 0xDD, 0x54, 0xB6, 0x69, 0xBC, 0xF6, 0xC5,\n\t0x72, 0x03, 0x32, 0x71, 0xB6, 0xD7, 0x7D, 0x48, 0x20, 0x18, 0x30, 0x68,\n\t0xD9, 0x58, 0x7B, 0x8B, 0xAE, 0x59, 0x5D, 0x98, 0xA6, 0x2F, 0x92, 0x47,\n\t0x2D, 0xDD, 0x94, 0x4E, 0x65, 0xC1, 0x57, 0x8D, 0xC7, 0xE9, 0x15, 0x13,\n\t0xB2, 0x58, 0x30, 0x5A, 0x6B, 0x87, 0x75, 0x9B, 0xA7, 0xD4, 0x0A, 0x88,\n\t0x02, 0x62, 0x22, 0xB6, 0x04, 0xB3, 0xC8, 0xC3, 0x1F, 0x82, 0x96, 0x79,\n\t0x08, 0xBF, 0xE9, 0xA6, 0xEB, 0x09, 0x0B, 0x18, 0x57, 0x7A, 0x7B, 0x49,\n\t0x7E, 0xCB, 0xF2, 0x5D, 0x2C, 0xC7, 0xD9, 0xE1, 0x26, 0x6F, 0x56, 0x87,\n\t0x15, 0x99, 0xC2, 0x76, 0xDF, 0x56, 0xA5, 0xB3, 0x2E, 0xAD, 0xFC, 0xDF,\n\t0xB4, 0xB3, 0x1B, 0xF3, 0xB9, 0xA1, 0xA8, 0x65, 0x14, 0xDE, 0x25, 0xE3,\n\t0x5C, 0x0B, 0x80, 0x69, 0x65, 0x77, 0xC6, 0x78, 0xDC, 0x29, 0x87, 0x2C,\n\t0x24, 0xBF, 0xEB, 0xD1, 0x24, 0x69, 0x56, 0x5C, 0xFC, 0x67, 0x3B, 0xB2,\n\t0x77, 0x27, 0x6F, 0xBF, 0x80, 0x8E, 0xFB, 0x2D, 0x96, 0xC1, 0xC2, 0xAF,\n\t0xEF, 0xF4, 0x3A, 0x8E, 0x2E, 0xCD, 0x59, 0x3E, 0x07, 0xF3, 0xED, 0xC4,\n\t0x2E, 0xAF, 0x4B, 0xD4, 0x27, 0x86, 0x38, 0xEB, 0xC2, 0x8B, 0xDF, 0x7B,\n\t0xBD, 0x9C, 0x91, 0xC1, 0xF7, 0x03, 0x45, 0x77, 0x02, 0x5A, 0xD8, 0x3E,\n\t0x89, 0x54, 0x20, 0xA0, 0x4D, 0x49, 0x3A, 0xA7, 0x58, 0x4E, 0x19, 0xE6,\n\t0xC0, 0x69, 0x69, 0x0B, 0x72, 0x28, 0xEE, 0x0C, 0xB0, 0xC0, 0x1B, 0xC6,\n\t0x80, 0x3F, 0x5E, 0x71, 0xCC, 0x85, 0xA1, 0x51, 0x16, 0xB7, 0x9D, 0x08,\n\t0x59, 0xFB, 0xE1, 0x87, 0x1E, 0xA0, 0x63, 0x93, 0x84, 0xFC, 0x0F, 0x83,\n\t0x54, 0xD1, 0x99, 0x03, 0x64, 0xCD, 0x51, 0x28, 0x28, 0x95, 0x9B, 0xD8,\n\t0x87, 0xA6, 0x86, 0xC4, 0x82, 0x62, 0x58, 0xBE, 0x03, 0x9B, 0x2E, 0xE4,\n\t0xBF, 0xB4, 0xB5, 0xEF, 0x1E, 0xA5, 0xD0, 0xDF, 0xAD, 0x91, 0x4D, 0xB6,\n\t0x4C, 0x01, 0x84, 0x08, 0x85, 0x08, 0xA4, 0x08, 0xE7, 0xA7, 0x58, 0x4A,\n\t0x6D, 0xE7, 0x23, 0xDC, 0x2A, 0x23, 0x4F, 0xB9, 0x50, 0x94, 0x73, 0xB4,\n\t0x44, 0x6A, 0x79, 0xFA, 0x92, 0x65, 0xBD, 0xE8, 0x68, 0x78, 0x82, 0x12,\n\t0x39, 0x9E, 0x9F, 0x2C, 0x70, 0x02, 0x3D, 0xDE, 0xFA, 0x77, 0x7E, 0x4A,\n\t0x35, 0x8F, 0x35, 0xFF, 0xF7, 0x68, 0x5C, 0x9C, 0x9B, 0x3F, 0x1F, 0x9A,\n\t0xA7, 0x97, 0xA5, 0x71, 0xA9, 0xA9, 0xDA, 0xDC, 0xA6, 0xFA, 0xA0, 0x25,\n\t0x71, 0xB4, 0xB7, 0xCD, 0x54, 0x81, 0x3E, 0xA0, 0xED, 0xFD, 0x6D, 0xA7,\n\t0x6B, 0x41, 0xA8, 0x17, 0x17, 0x94, 0x96, 0x52, 0xB9, 0xCE, 0xA4, 0x12,\n\t0x6A, 0x45, 0x52, 0x41, 0x99, 0xF8, 0xD7, 0x2F, 0xB9, 0x88, 0x6A, 0xB6,\n\t0x97, 0x89, 0xE7, 0xA5, 0xEE, 0x66, 0x70, 0xF8, 0xD0, 0x9B, 0xE7, 0x4A,\n\t0x45, 0xAE, 0xEF, 0x5D, 0xDD, 0x3D, 0x0E, 0x64, 0x7A, 0xC5, 0x5C, 0x5A,\n\t0x07, 0x69, 0xE4, 0x81, 0xBF, 0x34, 0xAF, 0x57, 0xE0, 0x4B, 0xB1, 0x55,\n\t0x4E, 0xE5, 0xE5, 0xC1, 0x99, 0x7A, 0xCF, 0xD5, 0x3E, 0xEF, 0x69, 0x9E,\n\t0x7B, 0x71, 0xF6, 0x65, 0xBB, 0xFE, 0x7C, 0xD5, 0xDB, 0x57, 0xD1, 0x5F,\n\t0xAD, 0xAE, 0x26, 0xF2, 0xCA, 0x7B, 0x08, 0x3C, 0xE6, 0xDA, 0xDD, 0xE8,\n\t0xBA, 0x28, 0x83, 0xCA, 0x0E, 0x08, 0x00, 0x06, 0x8E, 0x12, 0x1C, 0x0D,\n\t0x59, 0x17, 0xA4, 0x50, 0x86, 0x19, 0x80, 0xF0, 0xC4, 0xFF, 0xA3, 0xC7,\n\t0xD1, 0x8C, 0xAF, 0x22, 0x26, 0x23, 0xC6, 0xF5, 0xEB, 0xFA, 0xC8, 0x3B,\n\t0x9C, 0x9C, 0xAB, 0x65, 0x3F, 0x74, 0x86, 0xD0, 0x91, 0x5B, 0x77, 0xD0,\n\t0xE9, 0xFD, 0x61, 0xDB, 0x5B, 0x68, 0x88, 0xDB, 0x3F, 0x78, 0x5C, 0x83,\n\t0xB1, 0x71, 0xF9, 0xBE, 0x84, 0xC7, 0x4D, 0x3B, 0xB1, 0x74, 0xE2, 0x56,\n\t0xD9, 0xB8, 0x57, 0x3C, 0x86, 0x36, 0x3C, 0x3D, 0xAC, 0xF5, 0xCD, 0xBE,\n\t0x9A, 0x3B, 0x9B, 0xA4, 0x7B, 0x87, 0xE4, 0xB6, 0x37, 0x32, 0xD3, 0xF0,\n\t0x88, 0x68, 0x8F, 0x8F, 0xC8, 0x04, 0x83, 0xF8, 0x14, 0x29, 0x67, 0x46,\n\t0x06, 0x83, 0xE1, 0x8C, 0x98, 0x94, 0x13, 0x69, 0x6C, 0xD0, 0x3D, 0x91,\n\t0x89, 0xA7, 0xCF, 0xBE, 0x97, 0x79, 0x64, 0xBE, 0x14, 0x62, 0xC4, 0x5F,\n\t0x55, 0x85, 0x8D, 0x7E, 0x3A, 0x4D, 0xF8, 0x16, 0xA7, 0xEC, 0xB3, 0x50,\n\t0xF0, 0xC0, 0x15, 0x3C, 0x81, 0xDB, 0x6C, 0xB8, 0xB2, 0xCE, 0xD2, 0xF2,\n\t0x22, 0x3D, 0x3B, 0xDA, 0x18, 0xC9, 0xD2, 0x23, 0xD4, 0x5A, 0x13, 0x26,\n\t0x87, 0x7B, 0xCD, 0x4C, 0x74, 0x4C, 0x7A, 0x30, 0x6D, 0x87, 0x44, 0xC6,\n\t0x4D, 0x3A, 0x54, 0xD6, 0x49, 0xEE, 0xD3, 0x9B, 0x62, 0x7E, 0x23, 0xAB,\n\t0x1C, 0x54, 0xE5, 0xAC, 0xB1, 0x37, 0xC6, 0x02, 0x53, 0x72, 0xDB, 0xA4,\n\t0x27, 0xFE, 0x28, 0xF9, 0xA8, 0x32, 0x36, 0x78, 0x22, 0x95, 0x19, 0xE2,\n\t0xFE, 0x25, 0x25, 0x1F, 0xB6, 0x5B, 0xCE, 0xB0, 0xDE, 0xA8, 0xD2, 0xFF,\n\t0x3D, 0xB7, 0xC6, 0x19, 0x74, 0x67, 0x46, 0x14, 0xB7, 0xDA, 0x12, 0x92,\n\t0xE4, 0x3C, 0xB7, 0x7D, 0x6E, 0x34, 0x45, 0x92, 0xDA, 0x27, 0xB9, 0xCD,\n\t0x90, 0x8F, 0x4C, 0x5D, 0x88, 0x81, 0xDA, 0xCF, 0x4F, 0x45, 0x8F, 0xF5,\n\t0xEF, 0x18, 0xA1, 0x70, 0xC8, 0xB5, 0xB5, 0xFE, 0x84, 0xBE, 0x47, 0x56,\n\t0xA9, 0xDB, 0x1F, 0x3E, 0x59, 0xBC, 0x2B, 0x15, 0xE1, 0x7C, 0x45, 0x0F,\n\t0xF5, 0x13, 0x38, 0x2A, 0x4F, 0x7E, 0x99, 0x64, 0xB0, 0x69, 0xDF, 0x46,\n\t0x63, 0xCE, 0xD4, 0xAA, 0x57, 0x09, 0xE5, 0xD4, 0x31, 0x84, 0x00, 0x04,\n\t0x1E, 0x3C, 0x19, 0x9E, 0xED, 0xAB, 0x01, 0xCD, 0x9E, 0x3E, 0x3E, 0x14,\n\t0xD3, 0x62, 0x33, 0xC1, 0xB1, 0x94, 0x60, 0xB5, 0x78, 0xDF, 0x04, 0xE7,\n\t0xB6, 0xFE, 0xCD, 0x71, 0xFF, 0x55, 0x1B, 0x26, 0x6A, 0x71, 0x93, 0x31,\n\t0xB4, 0x30, 0x29, 0x6D, 0x18, 0x0A, 0x97, 0x52, 0xB8, 0x00, 0x29, 0xDD,\n\t0x8D, 0x20, 0xBE, 0x42, 0xA2, 0xF3, 0x62, 0x87, 0x9C, 0x53, 0x19, 0xA4,\n\t0x17, 0x30, 0x0C, 0x01, 0xE8, 0x6E, 0xEC, 0xD4, 0xC0, 0x79, 0x16, 0x78,\n\t0xF0, 0xAE, 0x07, 0x1F, 0x60, 0x57, 0xCC, 0x9C, 0xAE, 0x81, 0x0D, 0x18,\n\t0xB8, 0x40, 0x62, 0x61, 0x68, 0x0D, 0x23, 0x4C, 0x94, 0x40, 0x0C, 0x16,\n\t0x0C, 0x55, 0x80, 0x29, 0xC1, 0x04, 0x5A, 0xBE, 0x88, 0xF9, 0x69, 0xC4,\n\t0x26, 0xFD, 0xAE, 0xE2, 0x3D, 0x49, 0x5E, 0x4C, 0xC6, 0x7B, 0x7F, 0xF7,\n\t0xFF, 0xAB, 0x97, 0xD8, 0x4C, 0xCA, 0xC1, 0x3D, 0xB0, 0xA0, 0x53, 0x68,\n\t0x51, 0x5F, 0x29, 0x4A, 0x49, 0xF4, 0xB2, 0xD7, 0xD2, 0x7A, 0xDA, 0x56,\n\t0x00, 0xDD, 0x57, 0xA0, 0x54, 0xAF, 0x44, 0x1D, 0xBF, 0x55, 0x24, 0x55,\n\t0x98, 0xAE, 0x5C, 0xFE, 0x73, 0xC4, 0x1F, 0x1E, 0x0A, 0xFD, 0x92, 0x65,\n\t0x83, 0xA1, 0xA0, 0x30, 0x42, 0xE1, 0x5F, 0xF9, 0xF4, 0xE0, 0x89, 0x96,\n\t0x2E, 0x90, 0x87, 0x52, 0xF5, 0x6C, 0x55, 0xC5, 0x73, 0xE2, 0x3E, 0xBD,\n\t0x0F, 0x75, 0x6F, 0xF6, 0xFF, 0xA0, 0xB7, 0xBF, 0x47, 0x8D, 0xA0, 0x2C,\n\t0xBC, 0xFF, 0x16, 0x65, 0x46, 0xFB, 0xFE, 0x67, 0xDE, 0x87, 0xE0, 0xCE,\n\t0xDA, 0xF4, 0x70, 0xB6, 0xDA, 0xD0, 0xB4, 0xC5, 0x40, 0xEE, 0x3D, 0xB3,\n\t0x41, 0xDA, 0x2C, 0xBF, 0xA4, 0x20, 0x98, 0xAD, 0x80, 0xB8, 0xD9, 0x9D,\n\t0x04, 0x49, 0x1F, 0x57, 0xBD, 0x4B, 0xAB, 0xA8, 0x56, 0xEB, 0xBB, 0x54,\n\t0x74, 0xB1, 0x50, 0x5E, 0x5D, 0xF4, 0x7B, 0xBD, 0xFE, 0x1D, 0x84, 0x90,\n\t0x3E, 0x5A, 0x36, 0xFE, 0x3D, 0x79, 0xEE, 0xA7, 0x50, 0x10, 0x8E, 0x2D,\n\t0xA5, 0x75, 0x43, 0x5D, 0xAC, 0xDE, 0x4F, 0xCF, 0x42, 0xFA, 0xE5, 0xB8,\n\t0x29, 0x01, 0x17, 0x20, 0x14, 0x61, 0x02, 0x50, 0xE0, 0x88, 0x01, 0x0E,\n\t0x3A, 0xEC, 0xAC, 0x6A, 0xFD, 0xA7, 0x67, 0xD2, 0xC9, 0x2E, 0xCF, 0x5C,\n\t0xEC, 0x6D, 0x72, 0x7B, 0xEC, 0x76, 0x2D, 0xB1, 0xAB, 0xE2, 0x39, 0x77,\n\t0xE3, 0x65, 0x62, 0x26, 0xAA, 0x3E, 0xFB, 0x17, 0x00, 0xE3, 0x94, 0x49,\n\t0x37, 0x63, 0x83, 0xC3, 0xA9, 0xEE, 0xFF, 0x8C, 0xA5, 0xF4, 0xB5, 0x52,\n\t0x14, 0x2D, 0xCD, 0x8E, 0x7B, 0xFD, 0xBD, 0x09, 0x26, 0x87, 0xCB, 0x98,\n\t0xF8, 0x4D, 0xBC, 0xEF, 0x6D, 0xFA, 0xA0, 0x38, 0x0F, 0xA3, 0xC0, 0xCB,\n\t0x6F, 0xE3, 0xED, 0x97, 0x61, 0xEA, 0xB0, 0x25, 0x78, 0xF7, 0xFB, 0xEF,\n\t0xB1, 0xD8, 0xBF, 0x7A, 0x7F, 0x96, 0xA2, 0xBF, 0x82, 0x10, 0x17, 0x5C,\n\t0xEB, 0x6C, 0xCA, 0x66, 0xA2, 0x23, 0xE4, 0xE5, 0xA7, 0xC0, 0x15, 0x3F,\n\t0x12, 0xF5, 0x67, 0xF9, 0xAF, 0xA5, 0xFE, 0xDB, 0x74, 0x36, 0x3E, 0x1D,\n\t0xE7, 0x85, 0xFE, 0xA7, 0x27, 0xEA, 0x61, 0x2F, 0x6A, 0x5E, 0xD9, 0x22,\n\t0x1A, 0x4C, 0xA6, 0x83, 0xBA, 0x9E, 0x15, 0x70, 0xA8, 0x4E, 0x70, 0x80,\n\t0xCD, 0xB4, 0xE3, 0xDD, 0xA1, 0x79, 0x73, 0x2C, 0xD4, 0x1D, 0xF9, 0xB7,\n\t0xD0, 0x47, 0xCE, 0x04, 0x86, 0xD4, 0x29, 0x63, 0xCB, 0xC0, 0x38, 0x4E,\n\t0x19, 0x13, 0xE6, 0xFB, 0xFF, 0x07, 0xFC, 0x0A, 0x11, 0xE2, 0x43, 0x16,\n\t0xC6, 0x32, 0x58, 0x95, 0x53, 0x86, 0xF7, 0x8C, 0xD3, 0xE9, 0x5B, 0x16,\n\t0x02, 0x7F, 0x0A, 0xD0, 0xFF, 0x09, 0xD3, 0x17, 0x2C, 0x53, 0xE7, 0x00,\n\t0xEC, 0x1E, 0x76, 0x8F, 0x15, 0x8F, 0x1E, 0x26, 0xAF, 0xA7, 0x3E, 0x75,\n\t0x9B, 0x83, 0xC3, 0x54, 0x9E, 0x7F, 0x1F, 0x82, 0xBC, 0x84, 0x87, 0x08,\n\t0x56, 0x90, 0x34, 0x3E, 0xE8, 0x67, 0x58, 0x2E, 0x4F, 0xCE, 0x23, 0x99,\n\t0xA5, 0xFB, 0xBF, 0x94, 0x11, 0x46, 0x18, 0xD1, 0x49, 0x1C, 0x87, 0x43,\n\t0xE2, 0x08, 0x0F, 0x08, 0xD5, 0x25, 0x96, 0x58, 0x82, 0xDA, 0x7A, 0x2B,\n\t0xCE, 0xEA, 0x7D, 0x93, 0x20, 0x1C, 0xFE, 0x99, 0x4F, 0x5D, 0xF8, 0xB7,\n\t0x98, 0x4A, 0x7E, 0x64, 0x4A, 0x4B, 0xB7, 0x87, 0xC9, 0x17, 0x1B, 0x97,\n\t0x22, 0x22, 0x6B, 0x8C, 0x5C, 0xCD, 0x4C, 0x5E, 0x86, 0xDD, 0x94, 0xE9,\n\t0x0B, 0x6E, 0xDB, 0x84, 0x44, 0xA1, 0x20, 0x2F, 0xB8, 0x2D, 0xA5, 0xF2,\n\t0xE2, 0xD2, 0x4F, 0x6F, 0x68, 0x7A, 0x77, 0x5E, 0x89, 0xDE, 0xB2, 0x5F,\n\t0x08, 0x93, 0x67, 0xFA, 0xE2, 0xA5, 0xA7, 0xE7, 0x44, 0x0C, 0x67, 0x6D,\n\t0x12, 0x86, 0xD9, 0xFB, 0x58, 0xF2, 0xB2, 0xEA, 0xFC, 0x8F, 0x1C, 0xF9,\n\t0x4D, 0x73, 0xFC, 0xB7, 0x22, 0x77, 0xD3, 0xC8, 0xB7, 0x1F, 0xC2, 0xBD,\n\t0xEA, 0x5C, 0x13, 0x91, 0xE9, 0xE5, 0xE4, 0x68, 0x3B, 0x18, 0x47, 0xA9,\n\t0xE9, 0xD3, 0x78, 0x38, 0x6D, 0xC8, 0x96, 0xD9, 0x74, 0xC1, 0x59, 0x9E,\n\t0x78, 0x53, 0x17, 0x6C, 0x15, 0xB3, 0x29, 0x35, 0xC7, 0xB8, 0x14, 0xBB,\n\t0x36, 0x28, 0x6A, 0xF2, 0x5A, 0x56, 0xDB, 0x0B, 0xCA, 0xA5, 0x4C, 0xBA,\n\t0xE0, 0x6A, 0x6A, 0x02, 0xA5, 0x68, 0xD0, 0xD5, 0x54, 0x4F, 0x35, 0xC6,\n\t0xCD, 0x2C, 0xC3, 0xB8, 0xA6, 0x9A, 0xE2, 0xE1, 0x47, 0xC1, 0x52, 0xAD,\n\t0x72, 0x7A, 0x0E, 0x22, 0x19, 0x82, 0xFD, 0x4B, 0xFA, 0xFF, 0x58, 0x8C,\n\t0x37, 0x51, 0x41, 0x7D, 0x74, 0x2A, 0xB2, 0x6C, 0x94, 0x16, 0xED, 0x89,\n\t0x0C, 0x7F, 0x5F, 0xF2, 0xC6, 0x2E, 0x1D, 0x15, 0xBB, 0x5E, 0x73, 0x4D,\n\t0x98, 0xAB, 0xA3, 0xE4, 0xF2, 0xED, 0xA4, 0x5E, 0x0C, 0x19, 0x13, 0xAA,\n\t0x72, 0x16, 0xBA, 0x71, 0xE7, 0x8A, 0x89, 0x11, 0xBF, 0x9D, 0x50, 0xEE,\n\t0x40, 0xE7, 0x98, 0xB6, 0x68, 0x5E, 0xD6, 0xD1, 0x97, 0xC8, 0xFA, 0xE2,\n\t0x52, 0x45, 0x28, 0xD9, 0x4F, 0x4B, 0x2A, 0x54, 0x04, 0xC3, 0xD2, 0xF2,\n\t0xF3, 0x17, 0x7D, 0x5C, 0xE5, 0xF8, 0x27, 0x25, 0x54, 0xC4, 0x4B, 0x94,\n\t0x5C, 0x74, 0x8D, 0x8B, 0xAF, 0xAC, 0x94, 0x8D, 0xA6, 0x41, 0xFC, 0x11,\n\t0x79, 0x64, 0x95, 0x3F, 0xE8, 0x23, 0x2A, 0x55, 0x22, 0xAF, 0xA3, 0x24,\n\t0xE7, 0x56, 0xDB, 0xA8, 0x5B, 0x6B, 0x5F, 0xE5, 0x4F, 0xBE, 0xBD, 0xB7,\n\t0x97, 0xEE, 0xC7, 0xC5, 0x51, 0x3D, 0x2B, 0x81, 0x08, 0xDC, 0x3F, 0x7E,\n\t0xCD, 0x3B, 0x95, 0x3F, 0xFC, 0x81, 0x33, 0x9A, 0x30, 0x33, 0x5B, 0x77,\n\t0x5D, 0x97, 0x89, 0x5E, 0xD9, 0xC7, 0xCD, 0xAF, 0x54, 0xAE, 0x78, 0xFD,\n\t0x57, 0x3D, 0xF9, 0x3E, 0x2E, 0xC6, 0x67, 0xD8, 0x8B, 0xC5, 0xE2, 0x7D,\n\t0x67, 0x6F, 0x34, 0xBD, 0xAF, 0x70, 0x25, 0x15, 0x1A, 0x27, 0x18, 0x92,\n\t0x13, 0xD5, 0x20, 0xD1, 0x49, 0xB7, 0xFE, 0xDB, 0xAB, 0x68, 0xDD, 0x18,\n\t0xE3, 0xAF, 0xD1, 0x8B, 0x21, 0x8A, 0xCB, 0x4A, 0x63, 0xE4, 0x8D, 0xEA,\n\t0x0F, 0x6E, 0x79, 0x24, 0xA2, 0x28, 0x6E, 0xD5, 0xD1, 0xC5, 0xF7, 0xAC,\n\t0x5A, 0xCF, 0x05, 0xC8, 0x7F, 0xBF, 0xA3, 0x46, 0xB4, 0xF7, 0xBB, 0x74,\n\t0x2F, 0x27, 0xB5, 0xD4, 0xD3, 0xD7, 0x30, 0x76, 0xCA, 0xA8, 0x31, 0x06,\n\t0x13, 0x60, 0x18, 0xA0, 0x17, 0xA0, 0x50, 0xA2, 0x01, 0x1C, 0x50, 0x21,\n\t0x00, 0x92, 0x93, 0xFC, 0x9F, 0xF1, 0x5F, 0x42, 0x4B, 0x74, 0x91, 0x25,\n\t0x43, 0x83, 0x84, 0xFD, 0x97, 0xFC, 0x47, 0x26, 0xAB, 0xB3, 0xDC, 0x60,\n\t0x5B, 0xAA, 0x8F, 0xE2, 0x8E, 0x32, 0x36, 0x1E, 0x7B, 0x43, 0x1E, 0x6A,\n\t0x76, 0x77, 0xB6, 0xDC, 0x04, 0x03, 0x79, 0xAA, 0x41, 0xCD, 0x9B, 0x39,\n\t0x73, 0x2D, 0xD0, 0x27, 0x9F, 0xB8, 0xA9, 0x53, 0x79, 0xC2, 0x24, 0x73,\n\t0x4E, 0xB3, 0xE9, 0x21, 0x79, 0x62, 0xFE, 0xC4, 0xED, 0xD9, 0xCF, 0xEC,\n\t0x21, 0x68, 0xF3, 0x1B, 0x99, 0x0D, 0x04, 0x55, 0x4B, 0x9E, 0x68, 0xBA,\n\t0x82, 0xE6, 0xF5, 0x6F, 0x8C, 0x5E, 0x35, 0x73, 0xAD, 0xEF, 0x9B, 0xCF,\n\t0xE3, 0xDD, 0x0C, 0x08, 0x1A, 0x0F, 0xCC, 0x7A, 0xE0, 0x84, 0x39, 0x49,\n\t0xC6, 0x35, 0x86, 0xC8, 0x29, 0xD3, 0x83, 0x21, 0x92, 0x7A, 0xBF, 0xF7,\n\t0x4E, 0xF3, 0x3B, 0xD5, 0xEA, 0x99, 0x52, 0xDD, 0x2D, 0x2F, 0x47, 0xED,\n\t0x03, 0xB2, 0xAA, 0x9A, 0x1C, 0x20, 0x7B, 0x95, 0x4E, 0x8E, 0xBD, 0x71,\n\t0xE3, 0xE7, 0xF0, 0x79, 0xB0, 0xB3, 0xFC, 0xDE, 0x48, 0xA6, 0x2A, 0x72,\n\t0xE7, 0x2C, 0x72, 0x69, 0x37, 0x66, 0xEA, 0x15, 0x2B, 0xA2, 0xEC, 0xFF,\n\t0x9F, 0xDE, 0x05, 0xE2, 0x52, 0x45, 0xB3, 0x69, 0x47, 0x58, 0x57, 0xF9,\n\t0x6C, 0xB3, 0x5F, 0xE2, 0x28, 0xC7, 0x36, 0xDE, 0x55, 0x29, 0x71, 0xA6,\n\t0xAE, 0x74, 0x35, 0xEF, 0xEA, 0xAE, 0xFB, 0xF0, 0x72, 0x47, 0xA3, 0xCB,\n\t0xA0, 0x87, 0xFE, 0x4E, 0x94, 0x15, 0x61, 0xB5, 0xD4, 0xBC, 0x1B, 0xE7,\n\t0x92, 0xF1, 0xCD, 0x24, 0xAE, 0xDE, 0xAA, 0x24, 0x05, 0x52, 0x49, 0x0A,\n\t0xB0, 0x7E, 0x84, 0x8C, 0x35, 0xE0, 0xA4, 0x6A, 0x5E, 0x7B, 0x22, 0x64,\n\t0xFA, 0x43, 0x27, 0xD5, 0xFD, 0x3A, 0x7C, 0x4C, 0xA0, 0x51, 0xAD, 0x3F,\n\t0xF1, 0x3F, 0xD2, 0xE3, 0x6C, 0xD0, 0xBD, 0x09, 0xCF, 0x88, 0x19, 0x8B,\n\t0x03, 0xFD, 0xB3, 0xAE, 0x6A, 0x1B, 0x3C, 0x8B, 0x30, 0x5C, 0x63, 0x42,\n\t0x5E, 0xFA, 0x4B, 0x91, 0xA9, 0xCA, 0x77, 0xD3, 0x40, 0xEE, 0xDD, 0xC9,\n\t0x3E, 0x42, 0x9A, 0xC3, 0x9D, 0x26, 0x17, 0x67, 0xDB, 0x7D, 0x7F, 0x81,\n\t0x13, 0x8C, 0xB3, 0xD4, 0xC8, 0x9D, 0x4E, 0xEA, 0x48, 0xAD, 0x71, 0x24,\n\t0x72, 0x1D, 0x89, 0xD9, 0x37, 0x12, 0x53, 0x3F, 0xFE, 0x3B, 0x32, 0x3B,\n\t0xCE, 0xEE, 0x85, 0x5F, 0x1B, 0x42, 0x58, 0x62, 0x78, 0x42, 0xE1, 0x0F,\n\t0x49, 0x92, 0x21, 0x7C, 0x43, 0xFB, 0xFB, 0x6A, 0x6F, 0x63, 0xDB, 0xA6,\n\t0xF2, 0x5A, 0x1D, 0x95, 0x46, 0xEB, 0x51, 0xC6, 0x7E, 0x5F, 0xDD, 0xFA,\n\t0xDF, 0x6A, 0x79, 0xB9, 0x8C, 0xFD, 0x8F, 0x40, 0x9B, 0x81, 0x4A, 0xCE,\n\t0x55, 0x8E, 0xBA, 0x2A, 0x86, 0x1E, 0x0B, 0x72, 0x87, 0x03, 0x8C, 0x57,\n\t0xFD, 0x2D, 0x20, 0xD0, 0xE1, 0x4B, 0x7D, 0x04, 0xEA, 0xBB, 0x1D, 0x91,\n\t0x37, 0xB0, 0x06, 0xFB, 0xC8, 0x42, 0x2F, 0x49, 0x12, 0xAF, 0x13, 0x4A,\n\t0x47, 0xA8, 0x27, 0x14, 0x3F, 0x9F, 0x58, 0x3D, 0x1E, 0x4F, 0x27, 0x5E,\n\t0xD4, 0xEB, 0x6A, 0x68, 0x66, 0xE4, 0x9B, 0x14, 0xB3, 0xC3, 0x92, 0xB8,\n\t0x54, 0x12, 0x5D, 0x45, 0xD2, 0x49, 0x27, 0xA9, 0x82, 0x47, 0xCC, 0x0E,\n\t0x9B, 0x23, 0xD6, 0x78, 0x71, 0xA9, 0x2B, 0xA5, 0xAB, 0x8A, 0x1A, 0x94,\n\t0x24, 0x55, 0x05, 0x16, 0x6B, 0x54, 0x11, 0xE5, 0x6B, 0x9C, 0xE4, 0xC4,\n\t0x5E, 0xB6, 0x25, 0x3F, 0x62, 0x2C, 0x89, 0xD1, 0xD6, 0xF8, 0xE3, 0xB1,\n\t0xE4, 0x48, 0x68, 0xEB, 0xF9, 0x70, 0x14, 0xC2, 0x1C, 0xB7, 0x7A, 0x9E,\n\t0x17, 0x45, 0x22, 0x7B, 0x29, 0xB4, 0x1E, 0x15, 0xCF, 0x8C, 0x59, 0x63,\n\t0xEA, 0x29, 0xB4, 0x31, 0x48, 0xB2, 0x4F, 0x34, 0x45, 0x5A, 0x27, 0xD2,\n\t0xBC, 0x19, 0x99, 0x57, 0x33, 0xBB, 0x28, 0x85, 0xC9, 0x7E, 0x42, 0x41,\n\t0x40, 0x5F, 0x9C, 0x53, 0x8C, 0xA2, 0x17, 0x33, 0x29, 0x46, 0x91, 0x7E,\n\t0x31, 0xD6, 0x30, 0x15, 0x35, 0xA3, 0x18, 0xFF, 0xF8, 0xCA, 0xE3, 0x54,\n\t0xE6, 0xF7, 0x29, 0x1E, 0x3F, 0xF3, 0x78, 0x85, 0x27, 0x83, 0x33, 0x9D,\n\t0x27, 0xD2, 0xAE, 0xE3, 0x89, 0xEF, 0xEC, 0xCF, 0xC9, 0xB8, 0x47, 0x42,\n\t0x42, 0x22, 0x63, 0x52, 0xEA, 0x46, 0x38, 0x23, 0x7A, 0xD1, 0x8A, 0x49,\n\t0x96, 0x8C, 0xFF, 0xFD, 0x96, 0x92, 0xA5, 0x55, 0x33, 0xA8, 0xEA, 0x7D,\n\t0xA8, 0x28, 0x70, 0x5C, 0x37, 0xCA, 0xD2, 0xC4, 0xFC, 0x42, 0xC5, 0xC3,\n\t0xB1, 0xFD, 0x3C, 0xF7, 0x21, 0x93, 0xD7, 0xA9, 0xBA, 0xA1, 0xEC, 0x1B,\n\t0x9A, 0xDE, 0x59, 0xFA, 0x33, 0x7D, 0xA8, 0x6C, 0x9E, 0xF0, 0xDF, 0xE1,\n\t0x5C, 0x8D, 0x5A, 0x33, 0x33, 0xCE, 0x3B, 0x38, 0xA0, 0x19, 0x3A, 0x8E,\n\t0xE5, 0xDC, 0x29, 0x6F, 0xE3, 0xCD, 0x88, 0xBF, 0xD9, 0x7B, 0x35, 0x23,\n\t0x49, 0x2D, 0x49, 0x32, 0x1C, 0x92, 0x49, 0xC2, 0x5E, 0xB4, 0x7A, 0xD0,\n\t0xD1, 0x20, 0x0E, 0x9D, 0xCE, 0xD9, 0xC5, 0x83, 0x42, 0xE2, 0xD5, 0x81,\n\t0x86, 0x17, 0xC8, 0x59, 0x91, 0x40, 0x08, 0x70, 0x20, 0x03, 0x16, 0x50,\n\t0x00, 0x03, 0x7C, 0x20, 0x7C, 0x7F, 0x93, 0x57, 0x13, 0xC5, 0xFC, 0x66,\n\t0x00, 0xBD, 0xD1, 0x5F, 0x90, 0xC5, 0x63, 0xAC, 0x1E, 0x5B, 0x7F, 0x11,\n\t0xE7, 0x19, 0x1F, 0x20, 0x98, 0xA0, 0x8C, 0x20, 0x70, 0x31, 0x6A, 0x00,\n\t0x15, 0x04, 0xE0, 0x40, 0x0E, 0x7E, 0x20, 0x03, 0x1B, 0x36, 0xA0, 0x27,\n\t0xEE, 0xC4, 0x9D, 0x4E, 0x14, 0x85, 0xE2, 0x50, 0x9F, 0x8F, 0x0A, 0xA8,\n\t0x3F, 0xAF, 0xC9, 0xF4, 0x33, 0xBB, 0x54, 0xA6, 0xF3, 0xA6, 0x8E, 0x99,\n\t0x5F, 0x84, 0x12, 0xCF, 0xEA, 0x0A, 0xF4, 0xE0, 0x8F, 0xAB, 0x5B, 0x5F,\n\t0x42, 0xB7, 0x62, 0x42, 0x10, 0x70, 0x28, 0xA1, 0x04, 0x00, 0x68, 0xC2,\n\t0x02, 0xC2, 0x10, 0x01, 0x0E, 0xD2, 0x80, 0x06, 0x29, 0x18, 0x00, 0xC4,\n\t0x6F, 0x30, 0x0E, 0x8E, 0x13, 0x38, 0x12, 0x37, 0x18, 0xC7, 0x53, 0xF5,\n\t0xC5, 0x45, 0xAA, 0xC8, 0x5A, 0xA9, 0x88, 0x92, 0xA3, 0x75, 0xE3, 0x64,\n\t0xFD, 0xAA, 0xA4, 0x92, 0x4B, 0xAD, 0x2E, 0x7B, 0x50, 0x9D, 0xCD, 0x20,\n\t0xAD, 0xBB, 0x10, 0x9C, 0x1E, 0x26, 0xE3, 0x79, 0x3C, 0x6B, 0x7E, 0x7D,\n\t0x6A, 0xB5, 0x0E, 0x4C, 0x75, 0x0D, 0xB4, 0x2C, 0x8B, 0xFE, 0xA7, 0x2D,\n\t0xF8, 0xF1, 0x39, 0xF4, 0x4E, 0x8C, 0xBF, 0xF6, 0x57, 0xBA, 0x4B, 0xFE,\n\t0xBF, 0x89, 0x6E, 0xC5, 0x07, 0x3E, 0x78, 0x20, 0xE1, 0x07, 0x33, 0x90,\n\t0xC0, 0x1B, 0x34, 0x00, 0x44, 0xC3, 0x46, 0xB6, 0x01, 0x94, 0x22, 0x48,\n\t0x4E, 0xF2, 0x5F, 0x5E, 0xCE, 0xF8, 0x0C, 0x0B, 0xDE, 0xA2, 0xD1, 0xC4,\n\t0x2F, 0xAF, 0x5F, 0xA2, 0xAB, 0xDE, 0x60, 0x1C, 0xFD, 0x4D, 0x44, 0xFD,\n\t0x44, 0x2B, 0x95, 0xDD, 0x60, 0xDE, 0x9D, 0x37, 0x52, 0xC4, 0x26, 0x54,\n\t0x44, 0x41, 0x54, 0xE5, 0x68, 0x0B, 0xEB, 0x3E, 0x54, 0x41, 0x14, 0x07,\n\t0x18, 0x6C, 0x8A, 0xF6, 0x41, 0x48, 0x5A, 0xEF, 0x56, 0xAF, 0xE7, 0xDA,\n\t0x78, 0x28, 0x78, 0xEE, 0xDF, 0x2F, 0xFE, 0x7F, 0x06, 0xF3, 0x67, 0x4D,\n\t0xA2, 0x11, 0x88, 0x9B, 0x16, 0x28, 0xC5, 0x8D, 0xF4, 0x78, 0x19, 0xBF,\n\t0x68, 0x7B, 0x5C, 0x5E, 0x5C, 0xAA, 0x0A, 0x49, 0xF5, 0x46, 0x23, 0x2B,\n\t0x22, 0xC9, 0x88, 0x7A, 0x23, 0x20, 0x92, 0xEB, 0x8D, 0x6A, 0x06, 0xC6,\n\t0xB9, 0x9F, 0x6F, 0x2F, 0x2E, 0x2E, 0x23, 0xFF, 0x7E, 0x47, 0x57, 0x19,\n\t0x49, 0xFD, 0xC0, 0x46, 0x71, 0x44, 0x25, 0xAE, 0x62, 0xDC, 0x91, 0xA3,\n\t0xAF, 0x62, 0x09, 0x5A, 0xB6, 0x7A, 0x56, 0xFD, 0xED, 0x09, 0x15, 0x5D,\n\t0xD2, 0x9E, 0x7F, 0x33, 0xC1, 0xAC, 0x5C, 0x0D, 0x88, 0xE7, 0xD2, 0xA7,\n\t0x3E, 0x7B, 0x9A, 0x54, 0xBA, 0x2C, 0x26, 0xEF, 0xB5, 0x8B, 0xDB, 0xE7,\n\t0x49, 0x3D, 0xE7, 0xE5, 0xF2, 0x8C, 0xD4, 0xFF, 0xE7, 0x91, 0xC7, 0x80,\n\t0xB8, 0x53, 0xFA, 0x21, 0x1C, 0x4C, 0x4C, 0x31, 0xDC, 0xD8, 0xAC, 0x04,\n\t0x2A, 0x89, 0xBF, 0x9C, 0xC9, 0xB3, 0xC9, 0xE1, 0xBA, 0x6B, 0xDD, 0x50,\n\t0x36, 0x3D, 0xEE, 0xFF, 0xAF, 0xD7, 0x59, 0xCE, 0x35, 0x69, 0x3F, 0x2F,\n\t0xA3, 0xAD, 0x3C, 0xE6, 0xDD, 0x24, 0xFE, 0x12, 0x3B, 0xCD, 0xB5, 0x6E,\n\t0x94, 0x05, 0x89, 0x46, 0xFF, 0x7F, 0xEF, 0xF0, 0x79, 0xE0, 0xFA, 0x4B,\n\t0x3F, 0xEE, 0xB5, 0xFB, 0x86, 0xEC, 0x90, 0x4B, 0xBD, 0xFB, 0x3C, 0x98,\n\t0xBE, 0x1C, 0xEE, 0x54, 0xC8, 0xC7, 0xC6, 0x7E, 0x43, 0xDA, 0x4B, 0xF7,\n\t0x4A, 0xA4, 0x77, 0x51, 0x72, 0x29, 0x79, 0x44, 0xD6, 0x08, 0x3D, 0x0B,\n\t0x56, 0xBE, 0xA8, 0xBB, 0xB1, 0x02, 0x8F, 0x77, 0x88, 0xC0, 0x3C, 0x28,\n\t0xE1, 0x1E, 0x41, 0xDC, 0x40, 0x30, 0x12, 0x34, 0x38, 0x02, 0x3F, 0x1D,\n\t0x3B, 0x00, 0x08, 0x9C, 0xF8, 0xB7, 0x54, 0x36, 0xA2, 0xCB, 0x71, 0x46,\n\t0xC1, 0xD9, 0x04, 0x48, 0x89, 0x19, 0xBE, 0x6E, 0x8B, 0x12, 0x98, 0x84,\n\t0x77, 0x24, 0x00, 0xC9, 0x71, 0xC2, 0xBA, 0x35, 0xE3, 0x87, 0xFE, 0x83,\n\t0xF4, 0xA8, 0xA9, 0x55, 0x62, 0x06, 0x76, 0xE9, 0xDE, 0x07, 0xE1, 0x07,\n\t0xE9, 0x7B, 0x6E, 0xD1, 0x3F, 0x83, 0x1A, 0xD6, 0xDA, 0x20, 0xF9, 0x5C,\n\t0x55, 0xA2, 0xE6, 0x32, 0x35, 0xF1, 0xE1, 0x39, 0x83, 0xEE, 0x52, 0xA2,\n\t0xC6, 0xE2, 0xB6, 0x97, 0xA6, 0x84, 0x77, 0x65, 0x42, 0x3A, 0xB2, 0x8D,\n\t0x77, 0x4D, 0x22, 0x33, 0x7C, 0x13, 0xEF, 0xBA, 0x49, 0xC8, 0x0C, 0xD7,\n\t0xAA, 0xEF, 0xEA, 0x6E, 0xF6, 0xC5, 0xD5, 0xA1, 0x8E, 0xD6, 0xD1, 0xF3,\n\t0xD0, 0x44, 0xF6, 0xF0, 0xFF, 0x5F, 0xB8, 0xE4, 0x3D, 0xFC, 0xEF, 0xBF,\n\t0xB2, 0xE9, 0x27, 0x5A, 0xFD, 0x26, 0xAC, 0x4B, 0x44, 0x25, 0x49, 0x49,\n\t0x09, 0xDA, 0x12, 0xC9, 0xB5, 0xB4, 0x02, 0xBD, 0x7B, 0x6A, 0xDD, 0xFE,\n\t0x12, 0x91, 0xC8, 0xF8, 0x5F, 0xA2, 0x38, 0xAA, 0xD9, 0x52, 0x34, 0xCE,\n\t0x33, 0x68, 0xB6, 0x53, 0x8B, 0xE6, 0x87, 0x1A, 0x8E, 0x55, 0x74, 0xD4,\n\t0x95, 0x49, 0xA9, 0x49, 0xF2, 0x8A, 0x6C, 0x71, 0x2F, 0xB6, 0xB0, 0x7D,\n\t0x69, 0xFD, 0x9A, 0x48, 0xC3, 0xBF, 0x5E, 0x5E, 0x6C, 0x41, 0x7F, 0x93,\n\t0x10, 0xEF, 0xD2, 0xFA, 0x57, 0xD6, 0x16, 0xFF, 0xD7, 0x8F, 0x7D, 0xBF,\n\t0xCB, 0xC5, 0x3C, 0x2E, 0x10, 0x31, 0x17, 0x10, 0x96, 0x6F, 0xAD, 0x15,\n\t0x73, 0x05, 0xCD, 0xE9, 0xFF, 0xAF, 0xBA, 0x78, 0xE2, 0x5D, 0x4C, 0xF4,\n\t0xF1, 0x18, 0x2B, 0x15, 0xD4, 0x47, 0x6C, 0xCE, 0x56, 0xFA, 0xD5, 0x59,\n\t0x48, 0xAF, 0xBA, 0xA6, 0xD0, 0x5C, 0x2A, 0x64, 0xE6, 0x76, 0x4D, 0xCA,\n\t0x87, 0x15, 0xAB, 0x08, 0x1F, 0xF4, 0xA3, 0xF3, 0x85, 0xA2, 0x4A, 0xA5,\n\t0x7A, 0x0D, 0x1B, 0xAA, 0x1A, 0x24, 0x15, 0xFC, 0xF9, 0x63, 0xC8, 0x47,\n\t0xA6, 0x29, 0xDD, 0x29, 0x2C, 0x9E, 0x66, 0x04, 0x74, 0x12, 0xEC, 0x95,\n\t0x98, 0x12, 0xB5, 0x88, 0x53, 0xF0, 0x22, 0x48, 0xFA, 0x59, 0xE8, 0x75,\n\t0x42, 0x2F, 0xA6, 0xD7, 0xFF, 0xEB, 0x38, 0x64, 0x39, 0x3C, 0x39, 0xE4,\n\t0x43, 0x1D, 0x22, 0x16, 0xD1, 0x89, 0x88, 0x75, 0x48, 0xEB, 0x24, 0x5A,\n\t0x6C, 0x53, 0xA7, 0x69, 0xDA, 0x33, 0x6D, 0xA1, 0x2D, 0xC2, 0x5D, 0xD3,\n\t0xB5, 0x56, 0xBE, 0xC8, 0x16, 0xE9, 0x77, 0x9B, 0x60, 0xE4, 0xCB, 0xB3,\n\t0x25, 0x5E, 0x3F, 0x61, 0xE2, 0xE8, 0x24, 0x97, 0xDB, 0xDA, 0x90, 0xD4,\n\t0x7D, 0x13, 0x0C, 0x0D, 0xB6, 0x56, 0x55, 0xE1, 0x6A, 0x30, 0x4D, 0x9C,\n\t0x3E, 0xBF, 0xF8, 0x37, 0xD4, 0x7F, 0x3B, 0xE4, 0x74, 0x1B, 0x93, 0x2E,\n\t0x4E, 0xAF, 0xF6, 0x1D, 0x8A, 0xCB, 0x6C, 0x50, 0x8C, 0x31, 0x88, 0xA3,\n\t0x32, 0x33, 0xE7, 0xF4, 0x8E, 0xF7, 0x7E, 0xB0, 0xEE, 0x66, 0x4C, 0x88,\n\t0xDB, 0xDC, 0x91, 0xDC, 0x94, 0xA7, 0x4F, 0x9C, 0x4D, 0x5B, 0x62, 0x76,\n\t0xDB, 0xA7, 0xCE, 0xA4, 0x01, 0xFA, 0x76, 0xCA, 0xCD, 0x6E, 0x00, 0x90,\n\t0x85, 0x05, 0x59, 0xD3, 0xFB, 0x2C, 0xF9, 0xFF, 0x9C, 0xA9, 0xE7, 0xD2,\n\t0x3A, 0x07, 0x75, 0x5D, 0xFD, 0xCF, 0x6B, 0x1D, 0x89, 0x0D, 0x4B, 0x0E,\n\t0xAC, 0x19, 0x2C, 0x59, 0x34, 0x48, 0x15, 0x01, 0x48, 0xFF, 0x55, 0x76,\n\t0x5F, 0xB4, 0x8C, 0xA8, 0x40, 0x0B, 0x1A, 0x88, 0xC1, 0x11, 0x02, 0xF8,\n\t0xC1, 0x05, 0x65, 0x98, 0xEC, 0xC8, 0x46, 0x50, 0xC2, 0x82, 0xA7, 0x87,\n\t0xC7, 0xC3, 0x41, 0x55, 0xCA, 0xE1, 0x74, 0x33, 0x28, 0x8E, 0xD2, 0x0D,\n\t0x8B, 0x1D, 0xA8, 0x6A, 0xEF, 0x76, 0x8A, 0xAA, 0x9B, 0xF6, 0x71, 0x74,\n\t0xAB, 0x2F, 0xC9, 0x6E, 0xF4, 0x0F, 0xFD, 0x3A, 0x9F, 0x8B, 0x88, 0x30,\n\t0x78, 0xD1, 0x85, 0xC1, 0x28, 0xE3, 0x48, 0x5E, 0xD6, 0xE5, 0x6D, 0x1B,\n\t0xEC, 0xFE, 0xDD, 0x8B, 0x5C, 0xA3, 0xA7, 0x4C, 0x78, 0xF8, 0x37, 0x1F,\n\t0x61, 0x1B, 0x8F, 0xFF, 0x72, 0xDA, 0x4B, 0xF8, 0x3B, 0xBE, 0xAD, 0xA3,\n\t0xDA, 0x35, 0x60, 0xC4, 0xB4, 0x01, 0x57, 0xAD, 0xE7, 0x31, 0xAE, 0xD3,\n\t0xEF, 0x0D, 0x7C, 0xCF, 0x0D, 0xF4, 0xDD, 0xE9, 0xAD, 0xD7, 0xDD, 0x7D,\n\t0x76, 0x17, 0x4A, 0x7A, 0xC4, 0x75, 0x34, 0xCB, 0xC9, 0x4F, 0xA7, 0xD3,\n\t0xE9, 0x74, 0x3A, 0x9D, 0xC8, 0x0C, 0xEA, 0x29, 0x34, 0x27, 0x2B, 0xA4,\n\t0xB9, 0x54, 0x15, 0x32, 0xB3, 0x31, 0x15, 0x42, 0xB3, 0x3D, 0x88, 0x3C,\n\t0x5D, 0x48, 0x0D, 0xF7, 0x14, 0x79, 0x32, 0xF5, 0x48, 0x9D, 0xA4, 0x3A,\n\t0x9E, 0x4E, 0xF8, 0xE4, 0x2A, 0xA0, 0xD3, 0xC9, 0x27, 0xCE, 0x89, 0x88,\n\t0x14, 0x11, 0x3C, 0x85, 0x4E, 0x44, 0x5C, 0xA5, 0x73, 0x22, 0xE2, 0xD3,\n\t0xE7, 0x14, 0x80, 0x54, 0x00, 0x78, 0xFA, 0x6C, 0x01, 0x08, 0xC0, 0xA7,\n\t0xD0, 0x96, 0x11, 0xF1, 0x81, 0x92, 0x9A, 0x41, 0xA4, 0x40, 0x61, 0x6B,\n\t0xA5, 0x50, 0x5A, 0x65, 0x07, 0xA7, 0x05, 0x71, 0x02, 0xE5, 0x38, 0x3B,\n\t0x38, 0x53, 0x10, 0x1F, 0x03, 0x48, 0x69, 0x44, 0xA4, 0x18, 0x00, 0x07,\n\t0x49, 0x0D, 0xA0, 0x53, 0x82, 0xB8, 0x29, 0xC4, 0x89, 0x01, 0x3C, 0x48,\n\t0x10, 0x97, 0x09, 0xF1, 0x21, 0x44, 0x2A, 0xC5, 0x72, 0x93, 0x88, 0x14,\n\t0x42, 0x70, 0x10, 0xCB, 0x99, 0x88, 0xA4, 0x84, 0xE8, 0x14, 0x7B, 0x35,\n\t0x21, 0x4E, 0x08, 0xF1, 0x20, 0xF6, 0x66, 0x7D, 0xFA, 0x4F, 0x04, 0xA9,\n\t0x4D, 0xDE, 0xCB, 0xD5, 0xB2, 0xF9, 0x11, 0x91, 0x73, 0xB5, 0x16, 0xE2,\n\t0xE7, 0xD7, 0xC8, 0xB6, 0xEB, 0xBA, 0xEE, 0xFB, 0xBE, 0x5B, 0xE3, 0xF9,\n\t0xF5, 0xF4, 0xC4, 0x02, 0x49, 0xFD, 0x40, 0x2B, 0x10, 0x27, 0x7E, 0x38,\n\t0x49, 0xFD, 0x60, 0x1B, 0x08, 0x8F, 0x98, 0x1D, 0x36, 0x07, 0x77, 0x02,\n\t0xC4, 0xA5, 0xAE, 0x94, 0x80, 0x9C, 0x50, 0x20, 0x18, 0x77, 0xF2, 0x0B,\n\t0x24, 0x9E, 0x9C, 0xEB, 0x68, 0xC7, 0x73, 0xDA, 0xD1, 0x0E, 0xE7, 0xB4,\n\t0xA3, 0x34, 0xDC, 0xCD, 0xD0, 0xFE, 0x2D, 0xBD, 0xB9, 0xD9, 0xC1, 0x28,\n\t0x96, 0x8C, 0x97, 0xF0, 0xFF, 0x3E, 0x8A, 0xE5, 0xBF, 0x8A, 0x12, 0x55,\n\t0xF6, 0xFD, 0x6D, 0x63, 0xF4, 0xD4, 0x31, 0x11, 0xCF, 0x2B, 0x8C, 0x9C,\n\t0x82, 0xC2, 0x44, 0xA0, 0x7B, 0x98, 0x4F, 0x71, 0x3E, 0xF7, 0xBF, 0xC8,\n\t0x14, 0x3E, 0x88, 0x31, 0x05, 0x15, 0x63, 0x4C, 0x91, 0x05, 0x35, 0xF6,\n\t0x21, 0x7E, 0x9A, 0xBA, 0xE2, 0x8A, 0x2B, 0xA6, 0x98, 0x62, 0x8A, 0x5B,\n\t0x33, 0xF7, 0x6F, 0x93, 0x4F, 0x61, 0xE3, 0x59, 0xF4, 0xA2, 0xE6, 0xEE,\n\t0xB9, 0x89, 0xD0, 0x0F, 0x3E, 0xBF, 0x9C, 0xE9, 0x81, 0x0F, 0x6C, 0x2F,\n\t0x88, 0x50, 0x92, 0xD3, 0xB7, 0x7A, 0x71, 0x84, 0xBB, 0x6C, 0xFD, 0xD2,\n\t0xCC, 0xE5, 0xDE, 0x74, 0xA8, 0x4D, 0x2C, 0xA0, 0xE1, 0x7E, 0x7A, 0x6B,\n\t0xA6, 0x04, 0xCD, 0xFD, 0xEF, 0x4D, 0x44, 0x54, 0xB8, 0x6A, 0xD3, 0x75,\n\t0x2F, 0x77, 0xF9, 0x6D, 0xFD, 0x14, 0xB2, 0xC2, 0x59, 0x1E, 0x4C, 0xB2,\n\t0xD7, 0x84, 0xFC, 0xE0, 0x6E, 0xBA, 0x71, 0x07, 0x34, 0x22, 0x2B, 0xEE,\n\t0x53, 0x4E, 0xDE, 0x78, 0x5F, 0x7F, 0xB3, 0xCF, 0x14, 0xF4, 0x48, 0xBD,\n\t0x38, 0xE1, 0xAB, 0xBC, 0x45, 0x2F, 0x9A, 0x5F, 0x33, 0x6D, 0xEB, 0x7D,\n\t0x4B, 0x99, 0x2D, 0xAE, 0xCD, 0x16, 0x33, 0x6D, 0x8B, 0xD9, 0x7A, 0xFF,\n\t0x56, 0x4A, 0x9E, 0x2B, 0xDE, 0xE7, 0x56, 0x4A, 0x9C, 0x2B, 0x5E, 0xE7,\n\t0x72, 0x26, 0x92, 0x6A, 0x7E, 0xFB, 0xEB, 0xC4, 0x14, 0xBD, 0x7F, 0x4E,\n\t0xC7, 0xC8, 0x70, 0xE3, 0xC8, 0xA8, 0xBC, 0xFB, 0xAF, 0x66, 0x48, 0xCD,\n\t0xB6, 0x45, 0x40, 0x28, 0xCE, 0x2F, 0x15, 0xCE, 0x65, 0xAD, 0xFA, 0x9A,\n\t0xFB, 0xFB, 0x95, 0xC8, 0x73, 0x2B, 0xE9, 0xA7, 0x82, 0xE6, 0x4A, 0xCC,\n\t0x70, 0xFF, 0xEC, 0xA9, 0xA1, 0xE7, 0xFF, 0x51, 0xFC, 0x7D, 0x9A, 0xC8,\n\t0x59, 0x2A, 0x76, 0x58, 0xDE, 0xF6, 0xAB, 0xD2, 0xE7, 0x8C, 0x48, 0x9F,\n\t0x42, 0xCF, 0x11, 0x7F, 0x4D, 0x3D, 0x56, 0xCC, 0x35, 0xF1, 0x81, 0xCF,\n\t0x7C, 0xE2, 0x7D, 0xA2, 0x56, 0x33, 0xDB, 0x9B, 0x41, 0x8F, 0x85, 0x17,\n\t0x97, 0x51, 0x82, 0xF0, 0xA2, 0xFE, 0xCD, 0xAF, 0xB9, 0xD6, 0x67, 0xA3,\n\t0x3F, 0xBD, 0xFB, 0x55, 0x3A, 0xD7, 0x3E, 0xE7, 0x14, 0x68, 0x0A, 0xBF,\n\t0xAD, 0x2A, 0x72, 0x42, 0xA1, 0xEE, 0x17, 0x6C, 0xBC, 0xB8, 0x2A, 0x98,\n\t0x93, 0xC1, 0x26, 0x43, 0xAE, 0x76, 0xC5, 0xFC, 0xAE, 0xEC, 0x67, 0x7E,\n\t0x27, 0x15, 0xD0, 0xA5, 0x01, 0x6D, 0xD4, 0xDA, 0x93, 0x09, 0xD5, 0x23,\n\t0x6A, 0xEC, 0xA2, 0x3E, 0xBD, 0x08, 0x14, 0x64, 0x4D, 0xCB, 0xD4, 0xE9,\n\t0xA0, 0xB4, 0x2E, 0xEB, 0x66, 0x97, 0x83, 0xBA, 0xE9, 0xDB, 0xE8, 0xEF,\n\t0x6D, 0xE9, 0xDB, 0xB7, 0x56, 0x1C, 0x60, 0xAE, 0xC5, 0x6D, 0x72, 0x30,\n\t0x4E, 0xDB, 0x81, 0xE9, 0xED, 0xBD, 0xC3, 0x3A, 0x1F, 0xE7, 0xEA, 0xAE,\n\t0x3F, 0xE7, 0xCA, 0x79, 0xEA, 0x31, 0x96, 0x0E, 0x1A, 0xE3, 0x6F, 0xF2,\n\t0x46, 0x6A, 0x67, 0x03, 0x88, 0x8F, 0x30, 0x1D, 0xF1, 0x5A, 0x93, 0x91,\n\t0x22, 0x56, 0x75, 0x71, 0xE9, 0x4D, 0xDC, 0xFE, 0xD9, 0x45, 0x5B, 0xF9,\n\t0x6B, 0x1D, 0x77, 0x89, 0xB0, 0x0C, 0x67, 0x9B, 0xDE, 0x8F, 0x0B, 0x67,\n\t0x5A, 0x61, 0x13, 0x8F, 0x56, 0xAF, 0x44, 0x45, 0xB3, 0x45, 0x32, 0x0B,\n\t0xBA, 0x3C, 0xED, 0x6B, 0x45, 0x86, 0xAD, 0x32, 0xF2, 0x1E, 0xFA, 0x78,\n\t0xFB, 0xA8, 0x91, 0x08, 0x44, 0xD0, 0x98, 0x88, 0xF7, 0x13, 0x48, 0x9E,\n\t0x40, 0x8C, 0xE1, 0xAB, 0xF7, 0x39, 0xE0, 0x43, 0x3E, 0xE8, 0x94, 0xE7,\n\t0xCF, 0xF9, 0x85, 0x1B, 0x57, 0x06, 0xBF, 0x5D, 0x18, 0xE3, 0x2B, 0xED,\n\t0x7C, 0x19, 0xFF, 0xCE, 0xE5, 0x67, 0xF9, 0xD7, 0xD0, 0x05, 0x21, 0xF6,\n\t0x40, 0xE3, 0x5D, 0x0A, 0xED, 0x91, 0xFE, 0x33, 0xA9, 0xA3, 0x98, 0x28,\n\t0x47, 0x7F, 0x09, 0x40, 0x7E, 0x44, 0xD1, 0x8B, 0xF7, 0x0C, 0xC8, 0x0E,\n\t0xE7, 0x57, 0x07, 0xFA, 0xB4, 0x3D, 0xEC, 0x3F, 0x9F, 0x93, 0xE0, 0xC0,\n\t0x0F, 0x3E, 0x40, 0x83, 0x51, 0x10, 0x12, 0xAC, 0x68, 0xD0, 0x02, 0x31,\n\t0xD0, 0xA1, 0x88, 0xCD, 0x03, 0xDD, 0xFF, 0x93, 0x48, 0xD6, 0x0F, 0x47,\n\t0x70, 0x64, 0x64, 0x44, 0xFE, 0x23, 0x2C, 0x28, 0x72, 0xC4, 0x1A, 0xB1,\n\t0x18, 0xE5, 0x23, 0x96, 0x65, 0x59, 0xD6, 0xC8, 0xC8, 0x88, 0xC5, 0x25,\n\t0x4B, 0xEA, 0xB8, 0xC5, 0xC2, 0x47, 0x8C, 0x4E, 0x52, 0x0D, 0x80, 0xCC,\n\t0x45, 0x8C, 0x6E, 0xFD, 0x15, 0x72, 0xB6, 0x76, 0xF4, 0x3D, 0x2E, 0xDF,\n\t0xDD, 0xDD, 0xC9, 0x3A, 0xE4, 0xD2, 0x8F, 0xA9, 0x7E, 0xAA, 0x1F, 0x63,\n\t0xF5, 0x3B, 0xBE, 0xFF, 0x0A, 0xAB, 0x05, 0x62, 0xEC, 0x63, 0x9D, 0x0D,\n\t0xE2, 0x17, 0x97, 0xD0, 0xD7, 0xF7, 0x10, 0x7D, 0xE2, 0xF1, 0x97, 0xDD,\n\t0xC5, 0x3F, 0xE8, 0x61, 0x4E, 0xE1, 0xB7, 0xFF, 0xA6, 0xE6, 0xCE, 0x85,\n\t0xDC, 0x6E, 0xFA, 0x07, 0x3D, 0x68, 0xF2, 0xE0, 0x48, 0x68, 0x33, 0xC2,\n\t0x4D, 0xA7, 0xFF, 0x06, 0x05, 0x12, 0xA6, 0x4A, 0xF6, 0xD1, 0x7B, 0xBF,\n\t0x76, 0x27, 0x72, 0x50, 0x9E, 0x6E, 0x27, 0xFD, 0xFF, 0x8E, 0xB6, 0x93,\n\t0xFD, 0xAC, 0xC0, 0xB9, 0x43, 0x5A, 0x81, 0xCD, 0x2B, 0x52, 0xF3, 0x6A,\n\t0xC7, 0x88, 0xB4, 0x63, 0x54, 0xC3, 0xC0, 0xB6, 0x96, 0x6F, 0x24, 0xF2,\n\t0x46, 0x92, 0x0F, 0x5D, 0xD4, 0x30, 0x38, 0xFC, 0xFD, 0xCF, 0xB5, 0x60,\n\t0xF7, 0x7D, 0xAB, 0x42, 0xCF, 0xA2, 0x73, 0xC6, 0x6A, 0x15, 0xF7, 0xF9,\n\t0x13, 0x37, 0x7E, 0x6A, 0x3E, 0xC7, 0x8A, 0xDD, 0x59, 0x5B, 0x55, 0x90,\n\t0x95, 0xCD, 0xEF, 0x93, 0x8B, 0xB8, 0xA5, 0x48, 0x2A, 0xA6, 0x9D, 0x73,\n\t0x29, 0x8D, 0xCE, 0x9F, 0x88, 0x62, 0x91, 0xF9, 0x90, 0xCC, 0x89, 0x8C,\n\t0xE4, 0x3E, 0x7B, 0x52, 0xDB, 0xA7, 0x05, 0x7E, 0x92, 0xB9, 0x16, 0xC6,\n\t0x4C, 0xCA, 0x6A, 0x1D, 0xE9, 0xDC, 0xF9, 0x09, 0xEC, 0xF6, 0xEC, 0x69,\n\t0x26, 0xC9, 0x55, 0xEC, 0xAC, 0x5B, 0xB9, 0xA8, 0x3C, 0x99, 0xCC, 0x4B,\n\t0xD9, 0xF7, 0xC7, 0xF3, 0x33, 0x8D, 0x04, 0xC9, 0xAB, 0xF0, 0x7F, 0x4F,\n\t0xF4, 0x9C, 0x0A, 0xE2, 0x41, 0x5C, 0x00, 0x29, 0x01, 0x70, 0x90, 0x94,\n\t0x00, 0x3A, 0xA5, 0x39, 0x01, 0x3C, 0x48, 0x73, 0x26, 0x22, 0x3E, 0x00,\n\t0x90, 0x4A, 0x91, 0x1C, 0x00, 0x38, 0x88, 0x4C, 0x01, 0xA0, 0x53, 0xE4,\n\t0x05, 0xC0, 0x83, 0xC8, 0xFB, 0xD6, 0xB2, 0xAE, 0x76, 0x77, 0x76, 0x41,\n\t0xB7, 0xD6, 0xF7, 0xAD, 0xDD, 0xCD, 0x96, 0x92, 0x51, 0xA9, 0xA5, 0x36,\n\t0x48, 0x7D, 0xE3, 0x38, 0x58, 0x06, 0x89, 0xCB, 0xC8, 0xDC, 0xB8, 0x4C,\n\t0x95, 0x75, 0xB2, 0x58, 0x58, 0x57, 0x38, 0x78, 0x62, 0x49, 0x87, 0x24,\n\t0xB6, 0xFF, 0x67, 0x15, 0x74, 0xB6, 0x04, 0x61, 0x28, 0x40, 0x16, 0xAC,\n\t0x97, 0x1B, 0x4C, 0xE9, 0x2B, 0x4A, 0x3F, 0x85, 0x62, 0xB5, 0xB7, 0xD5,\n\t0xD2, 0x80, 0x97, 0x9B, 0xAA, 0x2F, 0x72, 0x1C, 0x0A, 0x28, 0x4E, 0x0E,\n\t0x15, 0x81, 0x26, 0xC7, 0xBD, 0x51, 0x96, 0x4E, 0x0E, 0xA5, 0x79, 0xA1,\n\t0x67, 0xD8, 0x76, 0x99, 0x1C, 0xAA, 0x7A, 0x1B, 0x9D, 0x24, 0x12, 0xBD,\n\t0xF6, 0x09, 0x49, 0x9F, 0x3F, 0x0D, 0xBB, 0x77, 0x58, 0x13, 0x92, 0x66,\n\t0xCF, 0x2B, 0x63, 0xB5, 0xE4, 0x71, 0x47, 0xC3, 0x5B, 0x02, 0xDB, 0x4E,\n\t0x97, 0x80, 0x01, 0x82, 0xAF, 0xD2, 0xB2, 0xF8, 0xE6, 0x9B, 0x65, 0xB1,\n\t0xC8, 0x48, 0x49, 0x63, 0xCD, 0x58, 0x6D, 0x9D, 0xA2, 0x60, 0x3A, 0x6D,\n\t0xC5, 0xCC, 0xA8, 0x87, 0xC7, 0x63, 0x98, 0xE7, 0xE0, 0x5C, 0x97, 0x9D,\n\t0xC9, 0x7B, 0xF6, 0xC5, 0xEC, 0xB0, 0xD3, 0x7B, 0x71, 0xA9, 0x5A, 0xD6,\n\t0xD5, 0x3E, 0x49, 0xA6, 0xE5, 0xBD, 0x68, 0x54, 0xA1, 0xD7, 0x51, 0xA4,\n\t0x4E, 0x03, 0xD1, 0x23, 0x58, 0x2B, 0x64, 0x92, 0xF5, 0x7A, 0x51, 0x28,\n\t0x14, 0xB6, 0x85, 0xA2, 0xC8, 0xED, 0x7F, 0xD6, 0xF1, 0xBC, 0x34, 0xC3,\n\t0x07, 0x94, 0x19, 0x2D, 0x96, 0x0F, 0xD0, 0xF2, 0xC1, 0xE4, 0x39, 0xA1,\n\t0x84, 0x93, 0x47, 0x27, 0x9C, 0x80, 0x82, 0x15, 0x4F, 0x00, 0x11, 0x74,\n\t0xB3, 0xF8, 0xC4, 0x9F, 0x08, 0x22, 0x28, 0x26, 0xA1, 0xAD, 0xE0, 0x99,\n\t0x31, 0x61, 0x6C, 0x24, 0xE1, 0x40, 0x78, 0x33, 0x74, 0xB0, 0x60, 0x3F,\n\t0xF9, 0xC1, 0xCE, 0xD8, 0xB3, 0x92, 0x68, 0x96, 0x44, 0x27, 0xB9, 0xC8,\n\t0xE9, 0x22, 0x6D, 0xD7, 0x53, 0x92, 0x1D, 0x8D, 0x52, 0x3F, 0x68, 0x70,\n\t0x50, 0x5A, 0x66, 0x70, 0x2E, 0xF3, 0x22, 0xFC, 0xA3, 0x71, 0xEC, 0xBB,\n\t0x22, 0xF4, 0x1B, 0xB2, 0xD6, 0x2B, 0x52, 0x69, 0x6C, 0xC1, 0x4E, 0x2F,\n\t0xF9, 0x8C, 0x1F, 0x9F, 0x71, 0x03, 0xE7, 0xF1, 0x31, 0x97, 0x6A, 0x76,\n\t0x17, 0x5D, 0x22, 0xDE, 0x96, 0x89, 0xDB, 0x4B, 0x54, 0x66, 0xFC, 0x87,\n\t0xCA, 0x0C, 0xCA, 0x1D, 0x01, 0x18, 0x7F, 0x1F, 0x26, 0xEF, 0x55, 0x09,\n\t0xD9, 0xD2, 0x03, 0xBD, 0xC6, 0x4C, 0x19, 0x79, 0xDF, 0x41, 0x82, 0x00,\n\t0xA1, 0x81, 0xCC, 0xF3, 0xE3, 0x52, 0x7D, 0xA8, 0xE3, 0xC4, 0x19, 0x17,\n\t0xB7, 0x0E, 0x23, 0xB9, 0x77, 0x11, 0xD6, 0x04, 0xE3, 0x5B, 0x93, 0x6E,\n\t0x59, 0x2E, 0xE4, 0x89, 0xAB, 0x8C, 0x44, 0xF1, 0xC9, 0x23, 0x3F, 0x66,\n\t0x32, 0x18, 0xF7, 0x8F, 0xB0, 0x4C, 0x53, 0xC4, 0x11, 0xBF, 0x2D, 0xDF,\n\t0x93, 0x54, 0x54, 0x56, 0x6C, 0x61, 0xD4, 0x76, 0xAC, 0x2D, 0xC6, 0x39,\n\t0x13, 0xDF, 0x8F, 0x27, 0x30, 0x72, 0xF1, 0xF3, 0x46, 0x6E, 0xA9, 0x37,\n\t0xC0, 0xDA, 0x3E, 0x73, 0xE2, 0x4C, 0xBC, 0x17, 0xA3, 0x8C, 0x5E, 0x9D,\n\t0x41, 0x91, 0x27, 0x52, 0xED, 0x09, 0x79, 0x53, 0x2B, 0x95, 0x68, 0xD2,\n\t0x6E, 0xB0, 0x98, 0xFD, 0x9C, 0x7B, 0xBC, 0x16, 0x26, 0xEB, 0x25, 0xD2,\n\t0x1F, 0x2C, 0x6A, 0x99, 0x16, 0x3F, 0xD6, 0xEF, 0xC7, 0xB0, 0xFD, 0x0E,\n\t0xA6, 0xD3, 0x67, 0xF3, 0x82, 0xDC, 0x3E, 0x0C, 0xE3, 0xB8, 0x4D, 0xBA,\n\t0x80, 0xC9, 0x9D, 0x1D, 0xC9, 0xB1, 0x06, 0xF3, 0xDE, 0xA6, 0x29, 0x8C,\n\t0xC8, 0xDA, 0x0E, 0x66, 0x65, 0x3F, 0xE5, 0xE9, 0x95, 0x6C, 0x56, 0x5A,\n\t0x9A, 0x45, 0x7F, 0xD2, 0x39, 0x95, 0x79, 0x5A, 0xBD, 0xB2, 0x36, 0xEA,\n\t0x84, 0xF2, 0x9A, 0x67, 0x9B, 0xDD, 0x14, 0xFA, 0x5A, 0x25, 0x74, 0x65,\n\t0x9E, 0x59, 0x6D, 0x08, 0x42, 0x48, 0xA2, 0x10, 0xC2, 0xFF, 0x67, 0xA9,\n\t0x57, 0x42, 0xAD, 0xCF, 0x22, 0x8A, 0x73, 0x16, 0xBF, 0xF7, 0x45, 0x06,\n\t0xD4, 0xC0, 0x86, 0x6A, 0x85, 0xEF, 0x08, 0x1F, 0x2C, 0xE1, 0x80, 0x14,\n\t0x94, 0x0C, 0x41, 0x04, 0x03, 0x22, 0x88, 0x37, 0xF8, 0x38, 0x6E, 0x3D,\n\t0x87, 0x37, 0xAE, 0xDD, 0xC6, 0xDD, 0xC6, 0x1D, 0xA9, 0x5E, 0xF4, 0x7A,\n\t0x3C, 0x57, 0xC3, 0x34, 0x33, 0x8D, 0xB1, 0x84, 0xD9, 0x17, 0x53, 0xCD,\n\t0x83, 0x1F, 0xD3, 0x3B, 0x6E, 0xE1, 0x29, 0x4D, 0xC2, 0x88, 0x11, 0x78,\n\t0x80, 0x03, 0x46, 0x6C, 0x20, 0x87, 0x05, 0x4A, 0xB2, 0x8B, 0x63, 0x3B,\n\t0x8E, 0x21, 0x7C, 0x02, 0xF7, 0x71, 0x24, 0xC4, 0x38, 0x8E, 0xFB, 0xA8,\n\t0x14, 0x96, 0x70, 0x46, 0xD5, 0x4A, 0x56, 0x81, 0xA7, 0x90, 0x5A, 0xB6,\n\t0xDD, 0x32, 0xE7, 0x50, 0xB7, 0x25, 0x67, 0x19, 0x8C, 0x6B, 0x6B, 0xE1,\n\t0x89, 0x7E, 0xBC, 0xEA, 0xAB, 0xC6, 0x80, 0xE2, 0x67, 0x54, 0x95, 0xDF,\n\t0xE6, 0x0F, 0xE9, 0xF2, 0x1C, 0xC3, 0x09, 0x13, 0x18, 0x9E, 0x13, 0xA6,\n\t0x6E, 0xAE, 0x66, 0xDF, 0x0C, 0x37, 0x61, 0x62, 0x34, 0xC1, 0x5C, 0x0B,\n\t0x42, 0x65, 0x37, 0x92, 0xE6, 0x72, 0x11, 0x4F, 0x4C, 0xCA, 0x31, 0xD2,\n\t0xC8, 0x10, 0x51, 0xAC, 0x5A, 0xA1, 0xB2, 0x1D, 0x6C, 0x1B, 0x4D, 0x98,\n\t0x92, 0xD1, 0xE5, 0x37, 0x6A, 0x0C, 0xEE, 0xCD, 0xE3, 0x31, 0xA7, 0x0F,\n\t0x02, 0xAA, 0x35, 0x25, 0xB0, 0xCB, 0x1D, 0x4F, 0xD6, 0x44, 0xFD, 0xA4,\n\t0xD3, 0x76, 0x00, 0xBD, 0xD0, 0xE4, 0x8B, 0xF7, 0x0C, 0xAA, 0x9E, 0x33,\n\t0x7D, 0x7D, 0xA1, 0x1E, 0x53, 0x89, 0xD2, 0xE9, 0x36, 0x43, 0x4E, 0xA6,\n\t0x5F, 0xD3, 0x2F, 0xE5, 0x79, 0x36, 0x0F, 0xD4, 0x7B, 0xAE, 0x50, 0x16,\n\t0xBB, 0x5A, 0x8F, 0xDF, 0xAB, 0x7C, 0x54, 0x5E, 0xD4, 0xEE, 0x17, 0xBC,\n\t0x6A, 0xE6, 0x6A, 0xDB, 0xCF, 0xA7, 0xD9, 0xB7, 0x76, 0xE4, 0xE9, 0x72,\n\t0xC6, 0x93, 0xD5, 0xAA, 0x70, 0xE9, 0x87, 0x1E, 0xEF, 0x8C, 0x1B, 0xA9,\n\t0x66, 0xA4, 0x79, 0x91, 0x0A, 0x7D, 0x76, 0x13, 0x48, 0xE6, 0xF1, 0x64,\n\t0x6A, 0xC3, 0x4C, 0xE4, 0x39, 0xC3, 0x69, 0x9D, 0xB1, 0xEA, 0x93, 0xF9,\n\t0x90, 0x6B, 0x1F, 0xAF, 0xA9, 0x66, 0x4A, 0xA0, 0x41, 0xFD, 0x31, 0xDB,\n\t0xAD, 0x8E, 0x9F, 0x40, 0x5C, 0xA6, 0x11, 0x31, 0xE1, 0xE9, 0x22, 0xD1,\n\t0xD4, 0x43, 0x3F, 0xC6, 0x69, 0x3D, 0x68, 0xE2, 0xBB, 0x23, 0xBF, 0xEF,\n\t0xE3, 0x35, 0x75, 0x5E, 0xF6, 0xF5, 0xF8, 0x61, 0x3D, 0x88, 0xBD, 0x71,\n\t0xD4, 0x4D, 0x1F, 0xFF, 0x68, 0x3D, 0xDB, 0xB9, 0x6C, 0xBE, 0xCD, 0xB7,\n\t0xAD, 0xB5, 0x36, 0xBB, 0xF5, 0xCC, 0x94, 0x0D, 0xCB, 0x66, 0x49, 0xEF,\n\t0x6B, 0x9F, 0x56, 0xC6, 0x52, 0x39, 0x8C, 0xB3, 0x94, 0xB3, 0x92, 0xAB,\n\t0xE9, 0x9C, 0x8E, 0x9F, 0xC4, 0x9D, 0x04, 0xA4, 0x37, 0x69, 0x2E, 0x37,\n\t0xF3, 0x46, 0x4C, 0x41, 0x99, 0x4D, 0x0E, 0xCE, 0x61, 0x45, 0xB9, 0xAE,\n\t0xFA, 0x73, 0x5D, 0xD7, 0x4F, 0xCE, 0x10, 0x66, 0x47, 0x81, 0xD6, 0xA3,\n\t0x27, 0xDD, 0xF3, 0xBA, 0xFB, 0x6B, 0x7D, 0xC7, 0x2C, 0xB2, 0x18, 0xD7,\n\t0x94, 0x4B, 0xA6, 0x39, 0xFF, 0xAD, 0x1E, 0xBA, 0x89, 0xBC, 0xB5, 0xF5,\n\t0x24, 0x08, 0xEB, 0x45, 0x0C, 0x77, 0xC4, 0x7B, 0x57, 0xB5, 0xE7, 0xC1,\n\t0x21, 0xC9, 0x04, 0x72, 0xC5, 0xD9, 0x0A, 0x92, 0x16, 0x3E, 0x7C, 0x32,\n\t0xD2, 0x09, 0xB1, 0x01, 0x08, 0xD0, 0x08, 0x47, 0x28, 0x3B, 0xA2, 0x87,\n\t0xCD, 0x84, 0x85, 0x34, 0x4C, 0x23, 0x50, 0xA1, 0x48, 0x6A, 0xC7, 0x04,\n\t0x52, 0xC0, 0x85, 0x94, 0x3A, 0xD4, 0x21, 0xFE, 0xD6, 0x2F, 0xFF, 0x4A,\n\t0x4F, 0xAB, 0xBC, 0xB5, 0x4B, 0xF7, 0x2D, 0x2B, 0xD7, 0x56, 0x1A, 0x6F,\n\t0xAD, 0x9A, 0x18, 0x74, 0xEB, 0xBD, 0x50, 0x7C, 0xFF, 0xCD, 0xD2, 0xB1,\n\t0xB0, 0x04, 0x59, 0x2C, 0x41, 0x90, 0x25, 0xE8, 0x27, 0x5D, 0x4F, 0x20,\n\t0xEB, 0x04, 0x08, 0x9E, 0x00, 0xF1, 0x24, 0xE1, 0xA6, 0xC1, 0xF6, 0x32,\n\t0x5B, 0x8B, 0x1B, 0x32, 0x3F, 0xCE, 0xA0, 0xAF, 0x3D, 0xDB, 0x4F, 0xAC,\n\t0x03, 0x48, 0xFF, 0xDF, 0xF1, 0xA7, 0x4C, 0x3A, 0xC1, 0x88, 0xD6, 0x85,\n\t0x95, 0x49, 0x38, 0x59, 0x8B, 0x96, 0x29, 0x28, 0xC2, 0x2A, 0x6F, 0xD1,\n\t0x1F, 0x46, 0x86, 0xB0, 0xB3, 0xB6, 0x90, 0x53, 0x92, 0x05, 0x19, 0xE0,\n\t0xD0, 0x28, 0x00, 0x09, 0x92, 0x8C, 0xE3, 0x86, 0x88, 0x01, 0x30, 0x28,\n\t0x22, 0x8B, 0x04, 0x68, 0x41, 0x0A, 0x0A, 0xB4, 0xB1, 0x03, 0x00, 0x41,\n\t0xA8, 0xE0, 0x18, 0x0A, 0x3E, 0x18, 0xA4, 0xE1, 0x8B, 0x1B, 0x86, 0x11,\n\t0x74, 0xF1, 0x85, 0x3C, 0x68, 0xE1, 0x03, 0x42, 0x76, 0xEE, 0x10, 0x85,\n\t0x0D, 0x40, 0xE1, 0x09, 0x2F, 0x56, 0x11, 0x1D, 0x0B, 0x40, 0xA1, 0x83,\n\t0x96, 0x1C, 0x54, 0x1A, 0x8C, 0x20, 0x06, 0x4D, 0x48, 0xC0, 0x54, 0x87,\n\t0x15, 0x40, 0x40, 0x09, 0x98, 0x31, 0x92, 0x68, 0x80, 0x08, 0x42, 0x30,\n\t0x07, 0x0D, 0x64, 0x19, 0xC0, 0x00, 0x02, 0x2C, 0x31, 0x90, 0x28, 0xD9,\n\t0x80, 0x00, 0x10, 0x5D, 0x0E, 0x87, 0xD1, 0xFD, 0xE0, 0x01, 0x22, 0xC6,\n\t0x05, 0x7E, 0x5E, 0x31, 0xF9, 0x99, 0x08, 0x22, 0x30, 0x32, 0x84, 0x10,\n\t0xB2, 0x91, 0x86, 0x2E, 0x00, 0x61, 0x85, 0x1F, 0x9A, 0xB0, 0x04, 0x92,\n\t0x4E, 0x0F, 0x48, 0xC8, 0x99, 0x81, 0x33, 0x82, 0xF3, 0x07, 0xE9, 0xB0,\n\t0x20, 0xF0, 0xF8, 0xAB, 0x77, 0xD8, 0xD6, 0x0F, 0xD9, 0x67, 0xDD, 0x87,\n\t0x86, 0x3F, 0x35, 0x7F, 0x96, 0x68, 0xC2, 0x01, 0x07, 0x25, 0x21, 0x10,\n\t0xF4, 0x20, 0xCC, 0xA5, 0x4C, 0xB4, 0x44, 0xD7, 0xBC, 0xA6, 0xF1, 0xBA,\n\t0xB0, 0xCF, 0x9B, 0xE1, 0xCD, 0x8E, 0x44, 0x89, 0x0B, 0x83, 0xF0, 0xE7,\n\t0x1E, 0xD2, 0xC8, 0x69, 0x2D, 0x82, 0xBF, 0xEB, 0x34, 0x23, 0x4A, 0xAF,\n\t0xD7, 0xEB, 0xF0, 0xB7, 0xE1, 0x6D, 0x7C, 0x2C, 0x68, 0x2D, 0x13, 0x77,\n\t0x17, 0x25, 0x05, 0xC9, 0xC4, 0x0B, 0xA2, 0x60, 0x9C, 0x55, 0x45, 0xCF,\n\t0x96, 0x38, 0xEA, 0xE2, 0x1A, 0x91, 0x63, 0xCE, 0xB1, 0xFE, 0xA1, 0x1B,\n\t0x2D, 0xFE, 0xA5, 0x25, 0x13, 0x2D, 0x2D, 0x85, 0x23, 0xAD, 0x2E, 0x91,\n\t0xDE, 0x96, 0xEC, 0x81, 0x59, 0xB2, 0x47, 0xB4, 0x1E, 0xB9, 0xA1, 0x0C,\n\t0x94, 0x81, 0x5F, 0x64, 0xDB, 0xE3, 0xD3, 0xC3, 0xE3, 0x45, 0xAE, 0x39,\n\t0x3A, 0x39, 0x38, 0x1D, 0x53, 0x9A, 0x1A, 0x9A, 0x99, 0x8E, 0xA7, 0x41,\n\t0x42, 0x1C, 0x04, 0xF4, 0xC5, 0x7F, 0x2F, 0x39, 0x64, 0x5C, 0x60, 0x85,\n\t0xF2, 0x92, 0x81, 0x32, 0xF0, 0xD1, 0x02, 0x41, 0xAB, 0xCE, 0x0F, 0xCE,\n\t0xEE, 0xB2, 0xE2, 0x65, 0x69, 0xDF, 0x2F, 0xAF, 0xB6, 0x2C, 0x7E, 0x84,\n\t0x65, 0xBC, 0x70, 0x2D, 0x80, 0x14, 0xFD, 0x5F, 0xE4, 0xF3, 0x73, 0xF8,\n\t0x95, 0xEA, 0xB0, 0xAD, 0x0F, 0xBA, 0x28, 0xCA, 0x75, 0xFA, 0xFA, 0xFA,\n\t0x53, 0x96, 0x7F, 0x77, 0x04, 0xE9, 0xCA, 0xF1, 0x22, 0x88, 0x58, 0xC2,\n\t0x0A, 0x4B, 0x05, 0x4F, 0xC0, 0x22, 0x00, 0x10, 0xCB, 0x40, 0x12, 0x65,\n\t0x9C, 0x21, 0x08, 0x97, 0x8F, 0xB8, 0x89, 0x25, 0x5C, 0xB7, 0x8E, 0xA1,\n\t0xFC, 0x1F, 0xCD, 0x91, 0xFC, 0xE1, 0x47, 0xA2, 0xD4, 0x08, 0xF2, 0x47,\n\t0x17, 0x49, 0x6E, 0x8D, 0x82, 0xA1, 0x6C, 0x0F, 0x47, 0x8F, 0x72, 0xEF,\n\t0xC3, 0xA1, 0x54, 0x2E, 0xF7, 0x4B, 0xEE, 0x5D, 0xDD, 0xE8, 0xA4, 0x75,\n\t0xFB, 0x89, 0xFC, 0xC6, 0x4E, 0xDA, 0x8F, 0xFC, 0x5B, 0xDE, 0x0C, 0x66,\n\t0x84, 0x99, 0x5A, 0xD4, 0xEC, 0xF8, 0xCC, 0xA7, 0xF6, 0xD9, 0xCF, 0x9D,\n\t0x3F, 0x17, 0xBF, 0xB3, 0x43, 0xB3, 0x33, 0x75, 0x17, 0x08, 0xE0, 0xE9,\n\t0xE2, 0xDE, 0x3F, 0x8F, 0xC0, 0xF3, 0x23, 0x80, 0xE7, 0x9E, 0xB3, 0xF4,\n\t0x59, 0x9F, 0xF4, 0x6B, 0x3D, 0x54, 0xA2, 0xB2, 0xF7, 0x10, 0x9D, 0xBC,\n\t0x1A, 0x95, 0x1C, 0x0A, 0xA5, 0xDD, 0x5C, 0x03, 0x78, 0x8A, 0xCF, 0xED,\n\t0xE0, 0x35, 0x82, 0x23, 0xA0, 0xC8, 0xA5, 0x9A, 0x39, 0xDD, 0x96, 0xBC,\n\t0xC1, 0x88, 0xF7, 0xB7, 0x23, 0xD9, 0x8E, 0x1C, 0xE1, 0xC7, 0x8C, 0xDC,\n\t0xA4, 0x47, 0x5A, 0xD2, 0x99, 0x78, 0x91, 0xCC, 0x93, 0xF3, 0x87, 0x86,\n\t0xC5, 0x9D, 0xCB, 0xC9, 0x24, 0x9F, 0x73, 0x92, 0xDC, 0xD3, 0xE3, 0x4C,\n\t0xB8, 0x00, 0x81, 0xCC, 0x46, 0x0B, 0x26, 0x59, 0x80, 0x80, 0xF6, 0x13,\n\t0xB9, 0x4D, 0x73, 0x78, 0xFD, 0x5B, 0x44, 0xE5, 0xFB, 0x22, 0x99, 0x5D,\n\t0x0F, 0x4A, 0x2B, 0x5D, 0x09, 0x3F, 0x34, 0x46, 0xC0, 0x08, 0x00, 0x12,\n\t0x09, 0x49, 0x13, 0x1E, 0xEB, 0x43, 0x44, 0xB0, 0xB7, 0xB8, 0xDE, 0x01,\n\t0x92, 0x5F, 0xE5, 0xF4, 0x41, 0x56, 0x4E, 0x0C, 0x71, 0x93, 0x2E, 0xA5,\n\t0xC6, 0x7A, 0x9F, 0x0C, 0x0C, 0x40, 0x80, 0x3E, 0xB5, 0x02, 0x08, 0xFC,\n\t0x2C, 0x10, 0xF8, 0xBD, 0xD0, 0x08, 0xFD, 0x65, 0x94, 0xC8, 0x28, 0xE7,\n\t0xD4, 0x57, 0x7C, 0xA2, 0xC3, 0x07, 0xA2, 0xB3, 0x9D, 0xE8, 0xDC, 0x86,\n\t0x07, 0x9A, 0x3E, 0x5E, 0x99, 0x3C, 0x48, 0xDA, 0xB6, 0xED, 0x26, 0xD6,\n\t0x0C, 0x22, 0x81, 0x70, 0x7E, 0xF0, 0xB4, 0x1B, 0xB2, 0x34, 0x6F, 0x94,\n\t0x79, 0x24, 0x1E, 0x16, 0x85, 0x23, 0x48, 0xC0, 0xFE, 0x5D, 0xE4, 0x63,\n\t0x5C, 0x0C, 0xEC, 0x5D, 0x15, 0xF8, 0x09, 0xB8, 0x52, 0x28, 0x51, 0x10,\n\t0xFD, 0x66, 0x0B, 0x94, 0x25, 0x90, 0x54, 0x18, 0x69, 0x51, 0x98, 0x68,\n\t0xC1, 0xDC, 0xCA, 0xBE, 0x8B, 0xF8, 0x63, 0xCE, 0xBA, 0xD9, 0x44, 0xC9,\n\t0x6F, 0xDC, 0x52, 0x48, 0x6A, 0x0A, 0x29, 0x85, 0x3F, 0x85, 0xF6, 0xE3,\n\t0xFF, 0x3B, 0xDB, 0xF4, 0x7C, 0x05, 0xDA, 0xCF, 0xD4, 0xEF, 0xC7, 0xD8,\n\t0x5A, 0x2B, 0x6D, 0xD7, 0x07, 0x22, 0xC7, 0x6D, 0x6E, 0x6F, 0x9A, 0x0B,\n\t0x6A, 0xB6, 0xF7, 0x8E, 0x99, 0x1E, 0x9A, 0x14, 0xA8, 0xE1, 0xFA, 0x3B,\n\t0x36, 0x2B, 0x6F, 0xD1, 0x36, 0x09, 0xF9, 0x61, 0x75, 0x5B, 0xEE, 0xD2,\n\t0xA2, 0xA4, 0xF8, 0xFF, 0x97, 0xCF, 0x3E, 0x13, 0x57, 0x7B, 0x07, 0xF7,\n\t0xAC, 0xEB, 0xEC, 0x35, 0x25, 0x7E, 0x58, 0xEF, 0x98, 0x8D, 0x3E, 0x23,\n\t0xB2, 0xB2, 0xFA, 0x31, 0x9C, 0xED, 0xBB, 0xC3, 0xDE, 0xF9, 0x99, 0xAA,\n\t0xBD, 0x6C, 0x78, 0xAE, 0x2B, 0x5A, 0x2D, 0x52, 0xD9, 0x9D, 0x76, 0x7F,\n\t0xF7, 0xEB, 0xBA, 0x7E, 0x5D, 0xD7, 0x45, 0x7F, 0x5D, 0xD7, 0xF5, 0x7A,\n\t0x23, 0xA2, 0x37, 0xF3, 0x46, 0x74, 0x9C, 0xCD, 0x9E, 0xF3, 0x11, 0xF2,\n\t0x39, 0x4D, 0xA1, 0xAD, 0x3B, 0x09, 0x71, 0x24, 0x54, 0x17, 0x5B, 0xC7,\n\t0x2A, 0xEF, 0xAA, 0xAF, 0xF3, 0xBC, 0x53, 0xE4, 0x66, 0x84, 0xB5, 0xC4,\n\t0x92, 0xD1, 0xE1, 0xDC, 0x7B, 0x37, 0x55, 0x8A, 0xDD, 0x47, 0x9C, 0xAB,\n\t0xFE, 0xD9, 0xFC, 0x13, 0x7E, 0xDC, 0x93, 0x1D, 0xC6, 0x04, 0x78, 0x75,\n\t0x49, 0x00, 0x21, 0x8A, 0xC3, 0x2C, 0x6E, 0xF1, 0x73, 0x40, 0xE0, 0x0C,\n\t0x54, 0xFC, 0xE0, 0x8A, 0x0F, 0x38, 0x61, 0x0D, 0x28, 0x2C, 0xBA, 0x70,\n\t0x42, 0x53, 0x01, 0x07, 0x31, 0x95, 0xDE, 0x60, 0x35, 0xA7, 0x62, 0xE6,\n\t0xFA, 0x8D, 0xAC, 0xB9, 0x0F, 0x7D, 0x65, 0x30, 0xD7, 0x84, 0xA1, 0x02,\n\t0xE7, 0xDA, 0x58, 0x28, 0x84, 0x50, 0x07, 0x8A, 0xBC, 0x5D, 0x83, 0x42,\n\t0x7A, 0x46, 0xF9, 0xD0, 0x6B, 0xBC, 0x8A, 0x08, 0xAB, 0x50, 0x81, 0x19,\n\t0xCD, 0xBD, 0xC7, 0x37, 0x55, 0xA3, 0x04, 0x4D, 0x30, 0xB3, 0x86, 0xAC,\n\t0x02, 0xDB, 0xAA, 0x58, 0xD9, 0x98, 0xD9, 0x9E, 0xE5, 0x27, 0x59, 0xF1,\n\t0x08, 0xBF, 0xC9, 0x8F, 0x20, 0xC5, 0x6F, 0xFB, 0xBE, 0x7A, 0xDB, 0x0E,\n\t0xBB, 0xD5, 0xA6, 0x5C, 0xA5, 0xDB, 0xC6, 0x1F, 0x17, 0xB4, 0xA1, 0x4E,\n\t0x4F, 0x0E, 0x74, 0x6E, 0xA3, 0x74, 0x2B, 0x55, 0x6E, 0xAB, 0xF7, 0xBC,\n\t0xD5, 0xAC, 0xD3, 0xB6, 0x18, 0xB7, 0x4C, 0x58, 0x0F, 0xEF, 0x0E, 0xDA,\n\t0xD8, 0x43, 0xAA, 0x75, 0x7A, 0xC8, 0x21, 0xBA, 0x8E, 0xC8, 0xA3, 0xB4,\n\t0x6D, 0xDF, 0x56, 0xFA, 0x8E, 0x75, 0x9C, 0xB0, 0x15, 0xEF, 0xFE, 0x11,\n\t0x4C, 0x58, 0x40, 0xF7, 0x12, 0xDE, 0x75, 0xD5, 0x87, 0x1B, 0xC8, 0xC1,\n\t0x88, 0x32, 0xA4, 0x40, 0x06, 0x07, 0x09, 0x36, 0xA0, 0x21, 0x02, 0x1D,\n\t0x06, 0x12, 0x20, 0x04, 0x24, 0xE0, 0x71, 0xD4, 0xB8, 0x01, 0x27, 0x70,\n\t0x28, 0x56, 0xD8, 0x04, 0x1E, 0x45, 0x9D, 0x24, 0x2C, 0x2D, 0x98, 0xC4,\n\t0x4E, 0x5A, 0x1E, 0x49, 0x6C, 0x81, 0xC8, 0x91, 0x58, 0xF9, 0xD5, 0x88,\n\t0x0E, 0x4F, 0xEF, 0x4D, 0xD2, 0x61, 0x13, 0x3B, 0x91, 0x7D, 0xCC, 0x83,\n\t0x53, 0x3C, 0x98, 0x05, 0x46, 0xF2, 0x09, 0x4C, 0x64, 0x98, 0x5B, 0x23,\n\t0x23, 0x23, 0x15, 0xD6, 0x57, 0x08, 0x6B, 0x8B, 0x84, 0x35, 0x68, 0x4B,\n\t0x84, 0x35, 0xDE, 0x72, 0x58, 0xA3, 0x46, 0x8D, 0x1A, 0x35, 0x20, 0x84,\n\t0x2E, 0x35, 0x5E, 0x6B, 0xBC, 0xC7, 0x5F, 0x6A, 0xBC, 0x40, 0x17, 0x78,\n\t0xAB, 0xD6, 0x24, 0x48, 0x68, 0x05, 0xC1, 0x7C, 0xED, 0xC0, 0x94, 0x3D,\n\t0xB0, 0xD4, 0xC3, 0x3B, 0x04, 0x51, 0xA0, 0xEA, 0x98, 0x03, 0x15, 0x60,\n\t0xAC, 0x21, 0x02, 0x66, 0x80, 0x81, 0x00, 0x0A, 0x60, 0x80, 0x00, 0xFC,\n\t0x94, 0xD6, 0x96, 0xA0, 0x1B, 0xDA, 0x12, 0x04, 0xE4, 0xF4, 0x84, 0xBA,\n\t0x29, 0xE1, 0x80, 0x94, 0x7C, 0x06, 0x75, 0xA6, 0x2E, 0x91, 0xDD, 0x8F,\n\t0xAE, 0x6F, 0xB2, 0x0F, 0x48, 0xE7, 0x79, 0xDD, 0x9F, 0xDF, 0xF6, 0x78,\n\t0x82, 0x89, 0xBC, 0xC5, 0xCB, 0xC9, 0xFC, 0x6A, 0x5D, 0x80, 0xC1, 0x4E,\n\t0x32, 0x5A, 0x59, 0x0F, 0x5B, 0xB6, 0x39, 0xAE, 0x36, 0xD7, 0x5C, 0xC7,\n\t0x3F, 0x72, 0x75, 0x33, 0xF5, 0x77, 0xCE, 0x83, 0x95, 0x3E, 0x8B, 0x57,\n\t0x98, 0x05, 0xC3, 0x2F, 0x54, 0x67, 0xD0, 0xE2, 0x94, 0x05, 0x11, 0x3B,\n\t0xF8, 0x01, 0x0F, 0x62, 0x70, 0x24, 0xC1, 0x08, 0xA8, 0x94, 0x15, 0xA7,\n\t0x2F, 0x2E, 0xF5, 0x74, 0xDB, 0x7E, 0xDF, 0xFF, 0xFF, 0xBB, 0xC0, 0xFF,\n\t0x87, 0xB4, 0x72, 0x1E, 0xB7, 0x71, 0x1C, 0x11, 0x31, 0x68, 0x3D, 0xA7,\n\t0xC9, 0x29, 0x31, 0x93, 0xE4, 0x7A, 0xFA, 0x95, 0xDB, 0xDF, 0x0B, 0x8D,\n\t0x44, 0x69, 0x6D, 0xF7, 0x5B, 0xEC, 0xD8, 0xB9, 0x5F, 0x7F, 0xCB, 0x3E,\n\t0x60, 0x4F, 0xF5, 0xB1, 0xFF, 0xEF, 0xEE, 0x04, 0xA2, 0xDF, 0xE2, 0x52,\n\t0xFB, 0xE9, 0x0D, 0xD9, 0xA6, 0xF5, 0x2E, 0xC4, 0x26, 0x31, 0xEC, 0x99,\n\t0x62, 0xD7, 0xAB, 0xF5, 0xDE, 0xBF, 0x71, 0x5F, 0x57, 0xD6, 0xE5, 0x7F,\n\t0xBD, 0xFD, 0x78, 0xC4, 0x7C, 0x87, 0x7D, 0xE9, 0xF4, 0xBF, 0xBC, 0xF1,\n\t0xFE, 0x37, 0x52, 0x8A, 0x45, 0x97, 0x56, 0xBF, 0xB5, 0x72, 0x22, 0x85,\n\t0x22, 0xE2, 0x44, 0x3E, 0xC9, 0x65, 0xBD, 0x30, 0xF1, 0xC6, 0x3B, 0x83,\n\t0xFE, 0x21, 0xA0, 0xF9, 0x59, 0x96, 0x95, 0xC1, 0xF4, 0xB3, 0xE0, 0x7C,\n\t0xB6, 0x93, 0x18, 0xB6, 0x41, 0x3B, 0xB2, 0x69, 0xAC, 0x4C, 0xE8, 0xD2,\n\t0xEA, 0x03, 0xC1, 0x86, 0xD0, 0x1E, 0xE9, 0x02, 0xC9, 0x71, 0x59, 0xA4,\n\t0xC3, 0xC1, 0xAE, 0x9A, 0x8B, 0x51, 0xE1, 0x6F, 0x97, 0xD4, 0x73, 0x25,\n\t0x14, 0x45, 0x7B, 0x43, 0xA1, 0xB8, 0x90, 0x37, 0x55, 0x52, 0xDA, 0x5E,\n\t0xB6, 0x5A, 0x42, 0xB7, 0x6F, 0x5B, 0x89, 0xBC, 0x25, 0xA5, 0xDB, 0x71,\n\t0xB3, 0xE3, 0x32, 0x6F, 0xDB, 0x3E, 0xCE, 0xA4, 0xE7, 0x7A, 0xB7, 0x49,\n\t0xF5, 0x43, 0x9D, 0x22, 0xBD, 0x44, 0x2E, 0xC6, 0xA8, 0x81, 0xF1, 0x53,\n\t0xEF, 0x1C, 0x65, 0x63, 0x36, 0x91, 0x48, 0xB4, 0x55, 0x2B, 0x12, 0x89,\n\t0x36, 0x11, 0xB5, 0x22, 0xD1, 0x76, 0x45, 0xA2, 0xF9, 0xC4, 0x4F, 0x6D,\n\t0x72, 0x89, 0xA8, 0x7A, 0x6F, 0xE3, 0x38, 0x6E, 0x3B, 0x37, 0x1B, 0x72,\n\t0xB3, 0xBB, 0x65, 0x59, 0xA2, 0xF3, 0x88, 0x59, 0xF3, 0xFB, 0xFF, 0xFD,\n\t0x0A, 0xBB, 0x26, 0x1C, 0xD1, 0xEA, 0x3D, 0x9F, 0x1D, 0xD7, 0x6B, 0x41,\n\t0xC7, 0x62, 0xD6, 0x75, 0x8B, 0x44, 0xA2, 0x18, 0xE3, 0xFB, 0xA2, 0xBE,\n\t0xE8, 0x6F, 0x91, 0xA8, 0x7A, 0x16, 0xBD, 0xE8, 0xDE, 0x68, 0x34, 0x4A,\n\t0xB5, 0x8C, 0xDC, 0x8F, 0xDC, 0x31, 0xD6, 0xEF, 0xFB, 0xAE, 0xAB, 0x7E,\n\t0xFF, 0x77, 0xFA, 0x5D, 0x8F, 0x57, 0x9B, 0xF0, 0xB4, 0xAA, 0xE7, 0xD6,\n\t0x5B, 0x11, 0xF5, 0x44, 0xA2, 0xCC, 0xFB, 0xFF, 0xEE, 0x24, 0xEE, 0x1B,\n\t0x32, 0x9A, 0x8C, 0x59, 0x8C, 0x8F, 0xD5, 0xF3, 0x3C, 0x96, 0xE7, 0x7B,\n\t0x9E, 0xC7, 0x8F, 0xBF, 0x55, 0xC3, 0x4D, 0x53, 0x53, 0x28, 0x5E, 0xED,\n\t0xA3, 0x9D, 0xBD, 0xEA, 0x3B, 0xFA, 0xCE, 0x83, 0x57, 0xEB, 0xB0, 0x80,\n\t0xBC, 0x2D, 0x18, 0xBC, 0xB4, 0xB8, 0x05, 0xDB, 0x74, 0xDC, 0x83, 0x0D,\n\t0x33, 0x1C, 0xD8, 0x31, 0xC4, 0x78, 0xAE, 0x54, 0x67, 0x45, 0xF8, 0x3D,\n\t0xDF, 0x62, 0x6A, 0xA5, 0x54, 0x2C, 0xDB, 0x73, 0x69, 0x37, 0xE7, 0xCE,\n\t0xF4, 0xA2, 0x41, 0xD7, 0x94, 0x41, 0xBC, 0x4F, 0xC5, 0x19, 0xA0, 0xAB,\n\t0xC6, 0xF7, 0xA7, 0xCC, 0x4F, 0xE7, 0x5F, 0xD7, 0x08, 0x85, 0x42, 0x79,\n\t0x70, 0x84, 0x42, 0xA1, 0xE6, 0x0E, 0x16, 0x33, 0x42, 0xA1, 0x50, 0xA6,\n\t0x9D, 0xEF, 0xA2, 0x3E, 0x5B, 0xE2, 0x4B, 0x1D, 0x69, 0x1D, 0x8A, 0xCA,\n\t0x8D, 0x34, 0x42, 0x65, 0xDD, 0x76, 0xB9, 0xC5, 0x6B, 0x74, 0xB7, 0x4D,\n\t0xE5, 0x32, 0x7D, 0xF6, 0xD2, 0x74, 0x6E, 0xE6, 0x62, 0xE5, 0xBB, 0xB5,\n\t0x30, 0xBE, 0xBD, 0xE3, 0x15, 0xF4, 0xD4, 0xF4, 0x6E, 0xE4, 0xFE, 0x2F,\n\t0x0D, 0xCE, 0x20, 0x1E, 0xA8, 0x3D, 0xB3, 0x2C, 0xB6, 0x4E, 0xA1, 0x55,\n\t0xA3, 0xA5, 0xB7, 0x2E, 0xEB, 0x61, 0x5E, 0x3D, 0x6E, 0x45, 0x2F, 0xFD,\n\t0x14, 0xDD, 0x14, 0x45, 0xBF, 0x25, 0x5D, 0x44, 0x0F, 0x65, 0x65, 0x20,\n\t0xD4, 0x0A, 0xF0, 0xB5, 0xCF, 0xD2, 0x83, 0x8E, 0x50, 0xDC, 0xAA, 0xE7,\n\t0x3F, 0xA0, 0x7B, 0x88, 0x27, 0x71, 0x85, 0x79, 0xE3, 0xE3, 0x3D, 0xD0,\n\t0x11, 0x71, 0xF9, 0xCF, 0xC1, 0x5F, 0x39, 0xC6, 0xE7, 0x2E, 0xC4, 0xDC,\n\t0xEF, 0x52, 0x57, 0xCE, 0x4C, 0xA2, 0xCC, 0x93, 0x74, 0xA6, 0xF5, 0xAF,\n\t0xFF, 0x50, 0xEA, 0x47, 0x84, 0x25, 0x11, 0xFE, 0x10, 0xD6, 0x53, 0xFA,\n\t0x53, 0x4B, 0x55, 0x5F, 0x8F, 0x89, 0xF7, 0x52, 0xF2, 0xB1, 0x3F, 0xFF,\n\t0x25, 0x94, 0xDE, 0xE8, 0x23, 0xD1, 0xE1, 0xE0, 0x9C, 0x63, 0xC8, 0x90,\n\t0x49, 0xCD, 0x06, 0x72, 0x30, 0x44, 0x88, 0x2D, 0x4C, 0x00, 0x93, 0x01,\n\t0x05, 0x04, 0x51, 0x03, 0x89, 0xFF, 0x92, 0xF4, 0xDA, 0xD2, 0xD2, 0xC2,\n\t0xD1, 0xC0, 0x09, 0xE9, 0x87, 0xD8, 0xE4, 0x19, 0xCC, 0x2F, 0x99, 0x2B,\n\t0xED, 0x3F, 0xB2, 0xC9, 0x06, 0x7F, 0x12, 0xDC, 0xF1, 0x1D, 0xE0, 0xEC,\n\t0xFB, 0xF9, 0x2E, 0x5C, 0x65, 0xC9, 0x9B, 0x5F, 0xB9, 0xDF, 0x2F, 0xCC,\n\t0x7F, 0x47, 0x43, 0xDB, 0xEB, 0x40, 0xD3, 0x8E, 0xEF, 0x08, 0x64, 0xD5,\n\t0xA0, 0x5F, 0x9E, 0x2F, 0xAB, 0x85, 0x5D, 0x11, 0x36, 0xE0, 0xC0, 0x13,\n\t0x8A, 0x94, 0x01, 0x08, 0x16, 0x73, 0x78, 0xC2, 0x90, 0x9D, 0xD6, 0x86,\n\t0x2A, 0x8C, 0xBE, 0x8C, 0xBC, 0xBC, 0xE6, 0x47, 0xF1, 0x30, 0xD5, 0x23,\n\t0x1F, 0xB1, 0x7C, 0xE8, 0x19, 0xA7, 0xC1, 0x13, 0x23, 0xDD, 0xB7, 0xA0,\n\t0xC0, 0x43, 0x18, 0xAF, 0x71, 0x19, 0x37, 0x79, 0xA6, 0x06, 0x23, 0x27,\n\t0x7F, 0xB2, 0x75, 0xA1, 0x5F, 0x8D, 0x79, 0x68, 0x52, 0x3C, 0x34, 0x50,\n\t0x83, 0xC9, 0x60, 0x0E, 0x6F, 0x02, 0x84, 0xA9, 0x52, 0xDD, 0xFD, 0x8C,\n\t0x11, 0x77, 0x8D, 0x3A, 0x9A, 0xE5, 0x84, 0xE4, 0x64, 0xA8, 0x9A, 0xF4,\n\t0xC4, 0x93, 0x9D, 0x48, 0x83, 0x77, 0x4E, 0x23, 0x8A, 0xDF, 0x53, 0x0F,\n\t0xC8, 0xB2, 0x2F, 0xF7, 0x0E, 0xBB, 0x8F, 0x3A, 0x92, 0x48, 0xA5, 0x9F,\n\t0x72, 0xC0, 0x5A, 0x56, 0xEA, 0xA0, 0xB6, 0x4C, 0xA8, 0x44, 0xFA, 0xD5,\n\t0x3D, 0x13, 0x4D, 0x1F, 0x90, 0x26, 0x4E, 0xE2, 0x33, 0x95, 0x5A, 0x0F,\n\t0x95, 0x10, 0x6B, 0x5D, 0x90, 0x8F, 0x68, 0x7E, 0x70, 0xC5, 0x69, 0xA2,\n\t0xCE, 0x21, 0xAA, 0x25, 0x37, 0xE3, 0xC7, 0x9B, 0xB2, 0x4F, 0x35, 0x41,\n\t0x42, 0xE3, 0x85, 0xCE, 0x4D, 0x90, 0xB0, 0xCC, 0x87, 0x6A, 0x0F, 0x77,\n\t0x62, 0xE2, 0x83, 0x04, 0xB6, 0xE9, 0x41, 0x42, 0x8C, 0x05, 0x73, 0x6C,\n\t0x85, 0x91, 0x9C, 0x54, 0x20, 0xEC, 0xD5, 0x7E, 0x2C, 0x19, 0x97, 0x76,\n\t0xD7, 0xBB, 0xEB, 0xB2, 0xAB, 0x31, 0x20, 0xA9, 0x08, 0x3C, 0xA1, 0x67,\n\t0x4A, 0x06, 0x8B, 0x37, 0x22, 0x06, 0x4C, 0x45, 0x94, 0xD8, 0xEF, 0x56,\n\t0x2B, 0xC8, 0xA2, 0xCB, 0x79, 0xAC, 0xDD, 0x2B, 0x17, 0xEF, 0x54, 0x06,\n\t0xE2, 0x78, 0xD7, 0xD7, 0xFF, 0x9C, 0x3B, 0xE9, 0xF0, 0x54, 0x5A, 0x8D,\n\t0x5E, 0xF4, 0xE7, 0x43, 0x97, 0xE7, 0x96, 0xF8, 0x76, 0xD2, 0x1F, 0x23,\n\t0x62, 0x66, 0x51, 0xB5, 0xCC, 0x2C, 0x62, 0x6A, 0x99, 0x45, 0x97, 0x6F,\n\t0x79, 0x7E, 0x37, 0xBD, 0x52, 0x9A, 0xAF, 0x2E, 0x6A, 0xFD, 0xA7, 0x2A,\n\t0xF4, 0xF3, 0xAF, 0x3F, 0xBD, 0x6E, 0x5C, 0xAD, 0x28, 0x8A, 0x7A, 0x77,\n\t0xBA, 0xBC, 0xC2, 0xB9, 0x2E, 0x13, 0x37, 0x1B, 0x9F, 0xF8, 0xAA, 0x8B,\n\t0xDC, 0xCE, 0x9F, 0x68, 0x52, 0x77, 0xDD, 0x99, 0xD3, 0xDC, 0x4C, 0x60,\n\t0xC8, 0xED, 0xD2, 0xE0, 0x70, 0x54, 0xCC, 0x7E, 0x80, 0xAE, 0x39, 0xFB,\n\t0x84, 0x83, 0x2A, 0xC5, 0xAC, 0x63, 0x9C, 0x45, 0xF8, 0x50, 0xA4, 0x25,\n\t0x8F, 0xB1, 0xA4, 0xC2, 0x1F, 0x31, 0xFE, 0x87, 0x0B, 0xCC, 0x3A, 0x08,\n\t0x3F, 0x3B, 0x19, 0x21, 0x84, 0xD3, 0x7B, 0x81, 0xD6, 0xA5, 0x5A, 0x25,\n\t0xC8, 0x59, 0xF4, 0x96, 0x15, 0xAF, 0x65, 0xFD, 0x34, 0xBD, 0xFA, 0xAE,\n\t0x9F, 0xD3, 0x9C, 0xF4, 0x5D, 0xD4, 0xFB, 0xAD, 0x6A, 0x41, 0xFE, 0xFE,\n\t0x5A, 0xBF, 0xE3, 0xB0, 0x1E, 0x08, 0x76, 0xFE, 0x40, 0x4D, 0x99, 0x41,\n\t0xB5, 0x4A, 0x67, 0xB3, 0x29, 0x7D, 0x37, 0x9A, 0xB2, 0xFD, 0xD6, 0x0C,\n\t0xD7, 0xD6, 0xEA, 0xA1, 0xAD, 0x5A, 0xCD, 0x7D, 0x83, 0x1E, 0xFC, 0xE1,\n\t0x9F, 0x2A, 0x91, 0x6C, 0x3F, 0xF4, 0x2C, 0x88, 0xFB, 0x87, 0x6C, 0x90,\n\t0x1A, 0xE6, 0x1A, 0x04, 0xBB, 0x34, 0xC8, 0x83, 0x34, 0xFF, 0x2B, 0x31,\n\t0x9A, 0x7A, 0x74, 0x64, 0x7D, 0x79, 0xD6, 0x95, 0xE0, 0xFC, 0x4E, 0x65,\n\t0x54, 0x4A, 0x2E, 0xC2, 0xB0, 0x63, 0xF0, 0x50, 0x65, 0x35, 0x3A, 0x66,\n\t0x5D, 0xEB, 0xD8, 0x10, 0x9B, 0x75, 0xFD, 0x23, 0x27, 0x9A, 0xC6, 0x3F,\n\t0xC3, 0x03, 0x41, 0x2E, 0x11, 0xC9, 0xAF, 0x27, 0x8E, 0x91, 0x5E, 0x21,\n\t0xC4, 0x36, 0xC8, 0x73, 0x69, 0x1F, 0xC9, 0xEC, 0xB9, 0x4C, 0xA9, 0xEE,\n\t0xB9, 0x1A, 0xCF, 0xC9, 0xE0, 0xF6, 0x68, 0x8A, 0xAA, 0xA4, 0xFE, 0x14,\n\t0xD7, 0x93, 0xBE, 0xD4, 0x15, 0x2A, 0x57, 0xCD, 0x39, 0x89, 0x9A, 0x4E,\n\t0x17, 0x87, 0x3A, 0x7D, 0x24, 0x75, 0xC6, 0x08, 0x94, 0xE6, 0x7D, 0x55,\n\t0x1B, 0x81, 0x33, 0x91, 0x81, 0x27, 0x6A, 0x57, 0x01, 0xF5, 0x30, 0x7D,\n\t0xA2, 0x49, 0x46, 0x5E, 0xD3, 0x97, 0x2A, 0x6D, 0x91, 0xDD, 0xFC, 0x24,\n\t0x83, 0xCD, 0x48, 0xC9, 0x2D, 0x4C, 0x40, 0x18, 0x96, 0xB5, 0xAA, 0xA3,\n\t0x98, 0x32, 0x1F, 0x66, 0xEA, 0x97, 0xAB, 0x7D, 0xB1, 0x91, 0xF8, 0x2E,\n\t0xCF, 0x71, 0x4D, 0x0D, 0xF3, 0x6F, 0xA4, 0x01, 0x8D, 0x82, 0x46, 0xA7,\n\t0xE1, 0x1E, 0x07, 0xEF, 0x55, 0x9E, 0xE2, 0xE9, 0xDA, 0x17, 0xC6, 0x17,\n\t0x96, 0xD6, 0x23, 0xB7, 0xF1, 0xB9, 0x44, 0x33, 0xBE, 0xA7, 0x74, 0x4E,\n\t0xFF, 0xF7, 0x53, 0xD4, 0x09, 0xB4, 0x3B, 0x67, 0xBD, 0xAB, 0x76, 0x3A,\n\t0x28, 0x77, 0xAA, 0x25, 0x29, 0x64, 0x4C, 0x9C, 0xF8, 0xF2, 0x26, 0xC9,\n\t0x3D, 0xC9, 0x35, 0xAC, 0xEA, 0x93, 0xC7, 0x18, 0x4F, 0xAC, 0x3D, 0xF9,\n\t0x09, 0x8D, 0xFF, 0x1F, 0x0D, 0x16, 0x4A, 0x83, 0x69, 0xCE, 0xC8, 0xB5,\n\t0x13, 0x67, 0xC4, 0x5E, 0x95, 0x37, 0xA2, 0xF2, 0x9E, 0x75, 0x33, 0x0F,\n\t0xD7, 0xC3, 0x7E, 0xEE, 0xEE, 0x66, 0x60, 0xE4, 0xE1, 0x1B, 0xCF, 0x2F,\n\t0xAE, 0xA6, 0xA2, 0x63, 0xEA, 0xE1, 0x58, 0x9A, 0xEA, 0xCC, 0x25, 0x30,\n\t0x95, 0x6B, 0x35, 0x26, 0x8E, 0x8A, 0xF1, 0x5A, 0xA6, 0xEF, 0x43, 0x5A,\n\t0xD6, 0xA5, 0x6B, 0xEA, 0x95, 0xAB, 0x89, 0xB2, 0xCE, 0x13, 0xFD, 0x37,\n\t0xF9, 0xA4, 0xB4, 0x50, 0xF4, 0xFB, 0x2A, 0x53, 0x81, 0x83, 0xE2, 0x1B,\n\t0x25, 0xEC, 0xD4, 0xC8, 0xB1, 0x9D, 0xDE, 0xA6, 0x4C, 0x7C, 0xA4, 0xAC,\n\t0x5F, 0x47, 0xB3, 0x7D, 0x34, 0x8A, 0x23, 0x2E, 0xC0, 0xCB, 0x25, 0xAF,\n\t0x1C, 0x28, 0xD4, 0xCA, 0xB6, 0xDD, 0x4B, 0x42, 0xD4, 0x05, 0x24, 0xFF,\n\t0xC9, 0xCF, 0xCF, 0x2B, 0xAD, 0xB8, 0x94, 0xDC, 0x6C, 0x5E, 0x04, 0x8C,\n\t0xBB, 0xF9, 0x12, 0x9C, 0x4D, 0x98, 0x68, 0xFA, 0xD1, 0xBA, 0x70, 0xFA,\n\t0x9F, 0xE8, 0xB1, 0x65, 0xF1, 0x68, 0x34, 0x1A, 0x8D, 0x46, 0x23, 0x96,\n\t0x8A, 0xBA, 0x24, 0xEA, 0x92, 0xFF, 0x24, 0xAA, 0x7A, 0x1B, 0xDF, 0x44,\n\t0x66, 0xD2, 0xC3, 0x49, 0xAA, 0xF0, 0xFE, 0x5F, 0xA9, 0x5C, 0x1E, 0xE9,\n\t0x17, 0x08, 0xBC, 0x5B, 0xE1, 0x07, 0xF6, 0xAE, 0xD8, 0x03, 0xAB, 0xAB,\n\t0xF1, 0x01, 0xCD, 0xD7, 0xCD, 0x7C, 0xFE, 0x88, 0x7E, 0xBF, 0xBC, 0xDA,\n\t0x27, 0x63, 0xF2, 0x05, 0xB7, 0x51, 0xEF, 0xB7, 0x55, 0x13, 0xA8, 0x0B,\n\t0x2E, 0xFB, 0x91, 0x5B, 0xAA, 0x9B, 0xA7, 0x17, 0xAF, 0xD6, 0xB3, 0x4D,\n\t0xAB, 0xFE, 0x9A, 0xFE, 0xD1, 0x25, 0x77, 0xA0, 0x78, 0xCD, 0xEB, 0xF3,\n\t0xA9, 0x10, 0xA3, 0xD1, 0x3F, 0x29, 0xC4, 0xE8, 0x8B, 0xA3, 0xD2, 0x90,\n\t0x9C, 0xAB, 0xA9, 0x76, 0xE4, 0x27, 0x39, 0xCD, 0xA4, 0xF1, 0x70, 0x2A,\n\t0x21, 0x13, 0x76, 0x93, 0x65, 0x7B, 0xBC, 0xD8, 0xB4, 0x1E, 0x79, 0xAB,\n\t0xCD, 0x10, 0x53, 0x91, 0x5B, 0xAD, 0xBC, 0x66, 0x59, 0x6B, 0xFF, 0x78,\n\t0xE9, 0x37, 0x92, 0xD6, 0xFB, 0xBF, 0x14, 0xE2, 0xFF, 0xFF, 0x8F, 0xDE,\n\t0x09, 0x71, 0x02, 0xE4, 0xE4, 0xE3, 0xDE, 0x43, 0x68, 0x0B, 0x6A, 0x93,\n\t0x1B, 0x44, 0xE6, 0x0C, 0xC3, 0x9F, 0x99, 0xFF, 0x48, 0x7B, 0xF4, 0x98,\n\t0x79, 0x8C, 0xDD, 0x33, 0x97, 0x99, 0x99, 0xFB, 0xF6, 0xCC, 0xB6, 0x6B,\n\t0x4E, 0xF3, 0x99, 0xFE, 0x5F, 0x4E, 0xDB, 0xA5, 0xAE, 0xBC, 0x74, 0x95,\n\t0xBF, 0x29, 0xA5, 0x35, 0x4C, 0xC3, 0x33, 0x7C, 0xDA, 0xAC, 0xC3, 0x39,\n\t0x8C, 0xC3, 0x5D, 0x4A, 0x4A, 0x0A, 0xA7, 0x7A, 0x65, 0x85, 0xDF, 0x2B,\n\t0xCC, 0x5F, 0x61, 0xE6, 0x7B, 0x6C, 0x53, 0x52, 0x52, 0x52, 0x58, 0xC5,\n\t0x63, 0xEE, 0x56, 0x61, 0xBE, 0x0A, 0x73, 0xAB, 0x30, 0xF3, 0x6F, 0xE3,\n\t0xBF, 0xAD, 0xFC, 0xCA, 0x36, 0x15, 0x04, 0x7B, 0x8A, 0x7C, 0x90, 0xF8,\n\t0x94, 0x0B, 0xBD, 0x32, 0x4A, 0x10, 0xD0, 0xE7, 0xD3, 0x73, 0x7A, 0x83,\n\t0x72, 0xA3, 0x73, 0x94, 0x9C, 0xDF, 0xE0, 0x1C, 0x85, 0xD6, 0x22, 0xB6,\n\t0x47, 0xED, 0x41, 0x7B, 0x50, 0xD4, 0x7B, 0xD4, 0x50, 0x94, 0x4D, 0xA1,\n\t0xE1, 0x52, 0x35, 0xA5, 0x86, 0x63, 0x9A, 0xD2, 0xDB, 0x6F, 0x3A, 0xD4,\n\t0x53, 0x66, 0xB8, 0xA3, 0x74, 0x28, 0x21, 0x52, 0x2A, 0x1C, 0x14, 0x4F,\n\t0x1E, 0xD4, 0x55, 0x3C, 0xA8, 0x4F, 0x20, 0x54, 0x10, 0xA9, 0x20, 0x02,\n\t0x96, 0xAA, 0xA8, 0x64, 0x26, 0xD6, 0x54, 0xB1, 0x8C, 0x90, 0xA1, 0x91,\n\t0x01, 0x80, 0x09, 0x10, 0x00, 0xF3, 0x85, 0x01, 0x14, 0x0A, 0x89, 0x83,\n\t0x51, 0x18, 0x05, 0xE2, 0x44, 0x9A, 0x7E, 0x94, 0xE3, 0x87, 0xDB, 0x09,\n\t0x26, 0x50, 0x0D, 0xC6, 0x90, 0x24, 0x0F, 0x21, 0x03, 0x8C, 0x01, 0x8A,\n\t0x08, 0x40, 0x30, 0x00, 0x03, 0x00, 0x08, 0x80, 0x00, 0x0C, 0x44, 0x3B,\n\t0x95, 0xDE, 0x98, 0x71, 0xE3, 0xE0, 0x3E, 0x45, 0x4C, 0x2B, 0x47, 0x4C,\n\t0x4E, 0x64, 0xEA, 0xDB, 0xCA, 0x12, 0x15, 0xCB, 0xB4, 0x1B, 0xF7, 0x96,\n\t0x90, 0xA3, 0xC5, 0xD1, 0x0C, 0x66, 0x2C, 0x10, 0xBB, 0x18, 0xB4, 0x2D,\n\t0x0F, 0x06, 0x48, 0x7B, 0x95, 0xE1, 0x1A, 0x05, 0x7B, 0x95, 0x53, 0x71,\n\t0xC1, 0x34, 0xE9, 0xA9, 0x2B, 0x31, 0x8D, 0x97, 0xC9, 0x33, 0xE0, 0x4C,\n\t0x71, 0x03, 0x79, 0x55, 0xF0, 0x80, 0x90, 0x8F, 0x0A, 0x65, 0xC5, 0xCC,\n\t0x7B, 0xCD, 0xB1, 0x03, 0x43, 0xE3, 0x8D, 0x36, 0x99, 0x6D, 0x72, 0xB7,\n\t0x90, 0x50, 0xEE, 0x71, 0x27, 0x6A, 0xB1, 0x99, 0x53, 0x77, 0x1D, 0xC3,\n\t0xAB, 0xA3, 0x9D, 0xAC, 0x72, 0xD5, 0x39, 0x7B, 0x8E, 0xB4, 0xD8, 0xC2,\n\t0x71, 0x25, 0x8B, 0xBB, 0x9E, 0xA2, 0x71, 0x91, 0x67, 0xD3, 0x3A, 0xDB,\n\t0xAF, 0xE8, 0x50, 0x09, 0x7C, 0x67, 0x27, 0x9B, 0xB4, 0x4E, 0x1C, 0x18,\n\t0x2A, 0xD8, 0x8F, 0x05, 0x21, 0x07, 0xAD, 0x44, 0x0B, 0x68, 0xDE, 0xC5,\n\t0xF6, 0xC8, 0x52, 0x3A, 0x8C, 0xE7, 0xC3, 0x42, 0xD1, 0xBC, 0x78, 0xC9,\n\t0x0B, 0xF7, 0xC3, 0x82, 0x52, 0xFF, 0x13, 0xD3, 0x83, 0xA1, 0x8D, 0x23,\n\t0x9A, 0xA3, 0x94, 0x46, 0x88, 0xE4, 0x83, 0x77, 0xE1, 0xC2, 0x60, 0x32,\n\t0x8E, 0x25, 0x4D, 0xEC, 0x9D, 0x50, 0xE5, 0xE5, 0x4E, 0x98, 0x5C, 0x8D,\n\t0xCD, 0x70, 0x81, 0x95, 0x58, 0xA5, 0xD6, 0x22, 0xAC, 0x96, 0x70, 0x5B,\n\t0x44, 0x25, 0xD4, 0x2E, 0x43, 0x33, 0xDD, 0x6D, 0x7C, 0x62, 0x38, 0x03,\n\t0xA8, 0x02, 0x32, 0xF7, 0xD9, 0xB0, 0xBC, 0x59, 0x89, 0x59, 0x74, 0x14,\n\t0xEE, 0x8D, 0x84, 0x58, 0xE4, 0xD4, 0x2A, 0xEC, 0x6C, 0xCA, 0xAB, 0x72,\n\t0x50, 0x58, 0x7C, 0x04, 0x48, 0xF8, 0x7F, 0x6D, 0x02, 0x6F, 0x29, 0x0E,\n\t0xA0, 0x61, 0x85, 0x4A, 0x88, 0x31, 0x54, 0x9F, 0xE7, 0x30, 0x91, 0xF9,\n\t0x28, 0xDF, 0x86, 0xCD, 0x17, 0x0A, 0xA2, 0xA1, 0xDF, 0x27, 0xF0, 0xDF,\n\t0x04, 0xA0, 0x02, 0x22, 0xF7, 0xA4, 0xA5, 0xDD, 0x12, 0x52, 0xBF, 0x34,\n\t0xF9, 0x56, 0x80, 0x09, 0xFB, 0x7F, 0xAA, 0x93, 0x06, 0xA0, 0xAB, 0x9B,\n\t0xB6, 0x02, 0x3D, 0x70, 0x2F, 0x20, 0x76, 0x07, 0xB8, 0xF6, 0x22, 0x4C,\n\t0x76, 0xC5, 0x33, 0x66, 0xA1, 0xFC, 0x8A, 0x0C, 0xAF, 0x97, 0x29, 0xD4,\n\t0xAB, 0x02, 0x9C, 0x4E, 0x6A, 0xF6, 0x0E, 0x7F, 0xB8, 0x26, 0x71, 0x49,\n\t0xD9, 0x64, 0x88, 0x20, 0xA4, 0xC6, 0x21, 0xEA, 0x6E, 0xED, 0x68, 0x92,\n\t0xB5, 0x08, 0x08, 0x23, 0x31, 0x18, 0x33, 0x7D, 0x62, 0x6D, 0x13, 0xE5,\n\t0xF0, 0x98, 0x05, 0x7C, 0x5A, 0xBE, 0xF6, 0x8D, 0xFD, 0x9F, 0x44, 0x2B,\n\t0xFC, 0x47, 0xD6, 0x20, 0xE1, 0x2D, 0xAA, 0x3F, 0x99, 0x12, 0xF0, 0x75,\n\t0x9D, 0xD4, 0x65, 0xF6, 0xEE, 0xFB, 0xA7, 0xD4, 0x53, 0x34, 0xE6, 0xC8,\n\t0x5C, 0x8C, 0xDC, 0x01, 0x5A, 0xC5, 0x27, 0x31, 0xC9, 0xD2, 0x3B, 0x2D,\n\t0x1B, 0x68, 0x92, 0x22, 0x4A, 0xBF, 0x77, 0x78, 0x51, 0xAD, 0x20, 0xBC,\n\t0x97, 0xAB, 0x0B, 0xFA, 0xF1, 0xA6, 0xDC, 0x91, 0x47, 0x5B, 0x27, 0xCC,\n\t0x22, 0xAA, 0xF1, 0xCF, 0xCD, 0x5D, 0x18, 0xFA, 0x73, 0xEB, 0xF4, 0xCE,\n\t0xF4, 0x50, 0x30, 0x6C, 0x2D, 0xD4, 0xF6, 0xA6, 0x0A, 0xB6, 0xB3, 0x13,\n\t0xDF, 0xD6, 0x6F, 0x82, 0x0A, 0xBC, 0x41, 0x87, 0x71, 0x7E, 0x4D, 0xF4,\n\t0x29, 0x85, 0xDC, 0x24, 0xD4, 0x58, 0xF8, 0x80, 0x0A, 0x35, 0x11, 0x84,\n\t0xDC, 0xFE, 0xF8, 0x41, 0x62, 0x9D, 0x10, 0x65, 0x84, 0xB4, 0x55, 0x74,\n\t0xCF, 0x52, 0xBE, 0x2E, 0xB7, 0x2A, 0xA6, 0x8A, 0xB1, 0xDD, 0xE2, 0xEB,\n\t0x95, 0x3E, 0xDA, 0x19, 0xC8, 0x09, 0xD4, 0x9A, 0xDA, 0xE0, 0x94, 0x97,\n\t0xDB, 0x80, 0x63, 0x19, 0xEC, 0xB3, 0xCA, 0x71, 0x6E, 0xBA, 0x28, 0xA6,\n\t0xA4, 0x18, 0x19, 0x46, 0xB6, 0x84, 0x38, 0x4B, 0xD3, 0x84, 0xBF, 0x08,\n\t0x20, 0x86, 0x1E, 0xEC, 0xEC, 0x54, 0x05, 0xBC, 0x49, 0x2E, 0x51, 0xE4,\n\t0x7F, 0x44, 0x46, 0xFB, 0xB9, 0xD5, 0xCA, 0xCC, 0x18, 0x55, 0xBC, 0x8A,\n\t0x34, 0x39, 0xED, 0x92, 0x2C, 0x39, 0x0A, 0x36, 0xB7, 0x05, 0xCD, 0xF6,\n\t0x47, 0x92, 0x03, 0xE4, 0x3A, 0x3C, 0x1F, 0x5A, 0x85, 0xD5, 0x32, 0x1D,\n\t0x89, 0xCA, 0xCD, 0xDB, 0xEB, 0xCE, 0x87, 0xE0, 0x41, 0x9B, 0xB9, 0xA0,\n\t0xEC, 0x53, 0x96, 0x3D, 0xC5, 0x86, 0xD8, 0x22, 0x47, 0xA8, 0x99, 0x7D,\n\t0xEF, 0x47, 0xC3, 0xB6, 0xDD, 0xA0, 0xD1, 0x44, 0x7B, 0xAD, 0xB2, 0x31,\n\t0xA1, 0xE7, 0x91, 0x54, 0xD3, 0x93, 0xB9, 0x32, 0x07, 0xDC, 0xF2, 0xC2,\n\t0x9C, 0x69, 0x02, 0x1C, 0x47, 0x21, 0x59, 0x0E, 0x5E, 0x16, 0x49, 0x7D,\n\t0x52, 0x95, 0xE7, 0xB4, 0x5A, 0x97, 0x13, 0xA5, 0x20, 0xB3, 0x0A, 0x82,\n\t0x58, 0x98, 0xD3, 0x5E, 0x25, 0x45, 0xF6, 0xF1, 0x07, 0x0A, 0x6B, 0xF6,\n\t0xDA, 0xE4, 0x6C, 0x4F, 0xA3, 0x84, 0x9B, 0xE9, 0x90, 0xED, 0x79, 0x22,\n\t0xB9, 0x26, 0x0D, 0x10, 0xB9, 0xA3, 0x9B, 0x4B, 0x9B, 0x10, 0xE9, 0x15,\n\t0xEE, 0xC2, 0xE6, 0xE2, 0x14, 0x8D, 0x43, 0xA7, 0x96, 0xDD, 0xA0, 0x41,\n\t0x9F, 0xE2, 0x1D, 0x03, 0xB0, 0x43, 0x80, 0x37, 0x5E, 0x97, 0xEB, 0x16,\n\t0xE4, 0x22, 0xA3, 0xA8, 0x77, 0x16, 0xBC, 0xF1, 0xD1, 0xA9, 0x9B, 0x11,\n\t0xEB, 0xA3, 0x81, 0x02, 0x5E, 0xDD, 0x0C, 0xA4, 0xF5, 0x85, 0x65, 0x06,\n\t0x11, 0x76, 0xF0, 0x6A, 0x37, 0x6F, 0x28, 0x6F, 0x94, 0xC5, 0x25, 0x9A,\n\t0x63, 0xD5, 0xB2, 0xBD, 0xC6, 0xCB, 0x51, 0xEF, 0x0C, 0x61, 0x45, 0x11,\n\t0xC1, 0x9D, 0x3C, 0x9D, 0xEB, 0x12, 0x25, 0x83, 0xED, 0xD2, 0xC5, 0xAE,\n\t0xDC, 0x6F, 0x44, 0xA8, 0xE0, 0xBC, 0xA2, 0x77, 0xB8, 0x0F, 0x18, 0x22,\n\t0x67, 0x7B, 0xCD, 0xE2, 0x89, 0x67, 0x67, 0x17, 0xFD, 0x63, 0x64, 0x80,\n\t0xF6, 0xBE, 0xB2, 0xCA, 0xF8, 0xD1, 0x1B, 0x39, 0xD7, 0x66, 0xB8, 0x7E,\n\t0x25, 0x9C, 0x2C, 0x0B, 0xC3, 0xCE, 0xE5, 0xA1, 0x74, 0x79, 0x7C, 0xDF,\n\t0x07, 0xC1, 0x84, 0x82, 0x56, 0xB7, 0x34, 0x80, 0xDF, 0xBB, 0x85, 0x81,\n\t0x0C, 0x04, 0x30, 0x78, 0x1F, 0x44, 0x64, 0x03, 0xB9, 0x89, 0x48, 0x92,\n\t0x1E, 0xC8, 0x9F, 0xC5, 0x6D, 0x63, 0x0D, 0x8E, 0xF7, 0x71, 0x09, 0x41,\n\t0xD1, 0x25, 0x58, 0x35, 0xDE, 0x4E, 0x8E, 0xBA, 0x8D, 0x38, 0x54, 0xAF,\n\t0x80, 0x75, 0x54, 0x69, 0x6E, 0x4E, 0x4B, 0xE4, 0xCB, 0x89, 0xFE, 0x05,\n\t0x7A, 0x59, 0xB2, 0xB9, 0xA7, 0xD3, 0x61, 0x89, 0xDB, 0x7D, 0x08, 0x79,\n\t0xFE, 0xE6, 0x0F, 0x1E, 0x80, 0x95, 0xCD, 0x02, 0x4A, 0xA0, 0xC6, 0xCC,\n\t0x55, 0x93, 0x96, 0xA2, 0xFA, 0x29, 0x45, 0xC7, 0xCF, 0x43, 0x2C, 0x2D,\n\t0x9F, 0x33, 0xC8, 0x54, 0x72, 0xAC, 0x69, 0xAF, 0xF7, 0xCA, 0xFF, 0x43,\n\t0x94, 0x78, 0xDE, 0xAF, 0xF3, 0x84, 0xFB, 0xBB, 0x9F, 0x65, 0x8E, 0x52,\n\t0x14, 0x44, 0xF1, 0x30, 0x16, 0x42, 0xFA, 0x89, 0x8D, 0x8D, 0x0D, 0x3A,\n\t0x66, 0x93, 0x27, 0x5C, 0x4D, 0x32, 0x3D, 0x7C, 0xD2, 0x7B, 0xDA, 0xFC,\n\t0xD1, 0xE0, 0xB0, 0xB6, 0x40, 0xD1, 0xB9, 0xAD, 0x8D, 0xC4, 0xBF, 0x09,\n\t0x9E, 0xE8, 0x25, 0xC2, 0xEA, 0x36, 0xC2, 0xAD, 0x07, 0x7F, 0x51, 0xBD,\n\t0xD9, 0x4F, 0x8B, 0x2D, 0x60, 0xB6, 0xA7, 0x0A, 0x1E, 0x8E, 0xFD, 0x79,\n\t0x80, 0x77, 0x39, 0x39, 0x3F, 0x92, 0xED, 0x95, 0x6A, 0xFB, 0x11, 0x71,\n\t0x18, 0xA4, 0x3C, 0x37, 0x3D, 0xBB, 0xAD, 0x12, 0x81, 0x81, 0xA2, 0xDF,\n\t0x6C, 0x3C, 0xE4, 0xAE, 0x74, 0x3B, 0x7F, 0x4F, 0x3B, 0x2A, 0x16, 0xB9,\n\t0xA8, 0xA7, 0xB4, 0xD1, 0xF1, 0x5F, 0x4D, 0xA0, 0x97, 0xF2, 0x6B, 0x00,\n\t0x4D, 0x8E, 0xFF, 0xDE, 0x97, 0xD9, 0x2E, 0x49, 0x8A, 0x99, 0x07, 0xDB,\n\t0xEE, 0x26, 0x7B, 0xAC, 0x1A, 0xFB, 0x04, 0xD1, 0x44, 0xA9, 0xAC, 0x1A,\n\t0xCA, 0x1F, 0x66, 0x41, 0xD5, 0x51, 0xEB, 0x3C, 0xD8, 0xCC, 0x66, 0x14,\n\t0x0D, 0xCF, 0xAD, 0x1A, 0x8C, 0x4E, 0xE4, 0x3A, 0xF5, 0xD7, 0xC6, 0x2E,\n\t0x8F, 0xEB, 0xE7, 0x43, 0xB7, 0x46, 0x30, 0xDD, 0x44, 0x8F, 0xB2, 0x90,\n\t0x2B, 0xCE, 0xC3, 0x0F, 0x4E, 0xD0, 0x8E, 0xA9, 0xC0, 0xCD, 0x96, 0x69,\n\t0xB1, 0xA4, 0x8F, 0x1F, 0x6E, 0x43, 0x1F, 0x17, 0x13, 0xDE, 0xEB, 0xD2,\n\t0xB1, 0xED, 0x01, 0xD5, 0x58, 0x22, 0xD7, 0x93, 0x77, 0x37, 0x25, 0x29,\n\t0x0D, 0x07, 0x1E, 0x28, 0xA6, 0x96, 0x03, 0xD4, 0x4A, 0xCD, 0x5A, 0x4B,\n\t0x3D, 0x28, 0x5A, 0xF2, 0xB3, 0xC1, 0x6E, 0x99, 0xAA, 0x78, 0x08, 0x8D,\n\t0x77, 0xB3, 0x0A, 0x86, 0xBF, 0x41, 0x42, 0x96, 0x4E, 0x35, 0xA1, 0xC5,\n\t0x43, 0xB5, 0xAE, 0x38, 0xE7, 0xBB, 0x46, 0xB7, 0x79, 0x19, 0x56, 0x7C,\n\t0x0B, 0x4F, 0xFC, 0x97, 0xFD, 0xD4, 0xCC, 0x5E, 0xFD, 0x51, 0xB5, 0x7A,\n\t0xD7, 0x6C, 0x5C, 0x45, 0x7E, 0x20, 0x3A, 0xA7, 0x6F, 0xF8, 0xD4, 0x30,\n\t0xBB, 0x78, 0xB5, 0xA2, 0x25, 0x9E, 0x75, 0x93, 0x3B, 0xB0, 0x05, 0x90,\n\t0x55, 0xCA, 0x57, 0xDB, 0x97, 0xC5, 0x87, 0xF8, 0x6C, 0xA1, 0x20, 0x9F,\n\t0xBB, 0xD5, 0x54, 0xB1, 0xD4, 0xD6, 0xD6, 0xCA, 0xF3, 0xBA, 0xE6, 0x0B,\n\t0x66, 0xFA, 0x40, 0xFD, 0xAB, 0xE6, 0x87, 0xC2, 0x80, 0x0F, 0xAE, 0xA4,\n\t0x33, 0xC0, 0xC3, 0x58, 0x42, 0x51, 0xC8, 0x23, 0xA0, 0x4C, 0x2A, 0x62,\n\t0x05, 0x1B, 0x97, 0x26, 0x66, 0x1D, 0x81, 0x2B, 0x1B, 0xA8, 0x4D, 0x69,\n\t0x9E, 0x16, 0xB0, 0x4A, 0xDA, 0x78, 0xF2, 0x00, 0x78, 0x71, 0x9E, 0xB4,\n\t0x9E, 0x9C, 0xE8, 0xE7, 0xDC, 0x28, 0xE1, 0x92, 0xC6, 0xDB, 0xBB, 0xAE,\n\t0x36, 0x81, 0x51, 0x65, 0x3E, 0xFF, 0xD4, 0x5E, 0x22, 0x07, 0x16, 0x6A,\n\t0xA8, 0x01, 0x20, 0x0B, 0x14, 0xB7, 0x50, 0xAF, 0xE7, 0x89, 0x6C, 0x0D,\n\t0x6D, 0xA8, 0x5F, 0x32, 0x41, 0xA2, 0xD6, 0x0A, 0x8B, 0x1E, 0xDB, 0xEB,\n\t0x1C, 0xC0, 0x12, 0x5B, 0xBF, 0x19, 0xAF, 0x4E, 0x7D, 0x34, 0x33, 0x8E,\n\t0x33, 0x71, 0x1F, 0xF1, 0x45, 0x69, 0x68, 0x7D, 0xC1, 0x66, 0x07, 0xC5,\n\t0x58, 0xEF, 0x78, 0x58, 0x0A, 0x87, 0x9B, 0x6C, 0xA6, 0xF2, 0xF7, 0x9A,\n\t0x70, 0x93, 0xFE, 0x2D, 0x6E, 0xAE, 0x0F, 0x43, 0x7F, 0x70, 0xCF, 0x86,\n\t0x95, 0x41, 0x26, 0xAC, 0xA1, 0xC1, 0x87, 0xBE, 0x74, 0x68, 0xC2, 0x94,\n\t0xEC, 0x51, 0x5D, 0xFA, 0xB0, 0x32, 0x34, 0xA7, 0x3F, 0x17, 0x1C, 0xA4,\n\t0xB3, 0x42, 0x6C, 0x76, 0xF2, 0x3D, 0x11, 0x51, 0x57, 0x9F, 0xEF, 0x36,\n\t0x73, 0x0A, 0xD3, 0x1E, 0x09, 0xD1, 0x74, 0x62, 0xC4, 0xB8, 0xF4, 0x1C,\n\t0x14, 0x7B, 0xAC, 0x12, 0x4D, 0x8D, 0x1C, 0xCD, 0x67, 0xF6, 0x2D, 0x0F,\n\t0x2F, 0x0C, 0x54, 0x78, 0x0C, 0x39, 0xCD, 0xBC, 0x50, 0x2C, 0xCB, 0x1F,\n\t0xA8, 0x93, 0xFF, 0x77, 0x38, 0x8B, 0x19, 0xEF, 0x56, 0x7A, 0xD8, 0xB8,\n\t0xB4, 0x9F, 0x4D, 0xDD, 0xC9, 0x1F, 0x09, 0x2B, 0x0E, 0xC0, 0x84, 0x95,\n\t0x0B, 0xCF, 0xB3, 0x6C, 0x83, 0xCD, 0x1E, 0x4E, 0x1B, 0x3A, 0x55, 0x81,\n\t0xA7, 0x48, 0x9B, 0x74, 0x93, 0xEC, 0x9B, 0x65, 0x62, 0x11, 0x2C, 0x92,\n\t0x01, 0x54, 0xB6, 0x9E, 0x63, 0x56, 0xA4, 0x0F, 0xCB, 0x82, 0xE0, 0x9B,\n\t0x3A, 0x33, 0x6E, 0x86, 0x0C, 0x4C, 0xB3, 0x02, 0xF8, 0x0F, 0x43, 0xC5,\n\t0x81, 0xF0, 0x50, 0x39, 0xB6, 0x1D, 0xD7, 0xEF, 0xEF, 0xB1, 0xF6, 0x00,\n\t0x53, 0x56, 0x48, 0xE7, 0x44, 0x6A, 0x1F, 0xCB, 0xC9, 0x98, 0x57, 0xA4,\n\t0xE5, 0xBE, 0xD4, 0x64, 0xD8, 0x6B, 0xBF, 0x4D, 0x7A, 0x74, 0xE1, 0x36,\n\t0x08, 0xC8, 0x19, 0xF4, 0xC0, 0x28, 0xCA, 0xB3, 0x9E, 0x87, 0xFA, 0x78,\n\t0x83, 0x49, 0xED, 0x3E, 0x84, 0xF9, 0x54, 0xD6, 0x8D, 0x4F, 0x8C, 0xC8,\n\t0xC4, 0x77, 0xCB, 0x56, 0xE9, 0x1E, 0x73, 0x26, 0x81, 0xFE, 0xE0, 0x9E,\n\t0xF0, 0x3E, 0x32, 0x42, 0x06, 0x29, 0x20, 0xC7, 0x88, 0xE6, 0x7F, 0x75,\n\t0x1F, 0xED, 0x4F, 0x87, 0x82, 0x2C, 0x35, 0x06, 0x20, 0x12, 0x80, 0x27,\n\t0x5A, 0x44, 0x1C, 0x34, 0x66, 0xE2, 0x2E, 0x2D, 0xD5, 0xAB, 0x33, 0xC0,\n\t0xDD, 0x4A, 0xE3, 0x30, 0x75, 0x19, 0xF8, 0x7F, 0xF8, 0x16, 0x04, 0xD6,\n\t0xBE, 0xFA, 0xF6, 0x37, 0xF1, 0xFB, 0x55, 0x76, 0x84, 0xBE, 0x90, 0x7F,\n\t0xDF, 0x49, 0x9A, 0x84, 0xD6, 0x4D, 0x0D, 0x2B, 0x1F, 0x5D, 0x94, 0xD4,\n\t0x4A, 0x66, 0x26, 0x66, 0x52, 0x36, 0x15, 0xF8, 0x69, 0x4E, 0x9B, 0x5E,\n\t0xAE, 0x35, 0x60, 0x43, 0x92, 0xF8, 0x8A, 0xF3, 0x19, 0xED, 0xCA, 0x48,\n\t0xFE, 0x60, 0x15, 0x55, 0x68, 0x37, 0x7A, 0xF7, 0xA1, 0xE5, 0x12, 0x5A,\n\t0xDC, 0x32, 0xFE, 0x65, 0x43, 0x7D, 0x9F, 0xE8, 0x6C, 0x92, 0xDD, 0xD3,\n\t0x3F, 0x1A, 0x0B, 0x95, 0xAD, 0x74, 0xDE, 0x16, 0x77, 0xA5, 0xBA, 0x88,\n\t0x67, 0x35, 0x1C, 0xA3, 0xBE, 0xB9, 0x0C, 0xC1, 0x38, 0x6E, 0x31, 0x0A,\n\t0x16, 0xD0, 0x43, 0x03, 0xE3, 0x3B, 0xF0, 0xFA, 0x1E, 0xCE, 0xB2, 0x0A,\n\t0x92, 0x60, 0x85, 0x1F, 0xBB, 0xD7, 0xBB, 0x73, 0xD7, 0xA8, 0x29, 0x09,\n\t0x4E, 0x19, 0x58, 0x35, 0x7C, 0x4F, 0x52, 0x2C, 0x1F, 0xA6, 0xE1, 0x13,\n\t0x5A, 0x9F, 0x34, 0x6A, 0xB5, 0x44, 0x7D, 0xC0, 0xE5, 0x47, 0xF8, 0x79,\n\t0x4D, 0xBC, 0xBF, 0xB9, 0xD0, 0x7D, 0xD9, 0xA9, 0x83, 0x6F, 0xAB, 0xBB,\n\t0xF9, 0xAE, 0xFE, 0x0D, 0x85, 0xE2, 0x98, 0x22, 0x84, 0x58, 0xC1, 0xD8,\n\t0xF3, 0x7F, 0xC0, 0x40, 0xA8, 0xE3, 0xFB, 0x1C, 0x9D, 0xE7, 0xA5, 0xE7,\n\t0xEC, 0x33, 0x75, 0x25, 0x52, 0xC4, 0xC6, 0x5B, 0x71, 0xFD, 0x69, 0x20,\n\t0xA5, 0x42, 0x1C, 0x54, 0xCF, 0x5B, 0x21, 0x30, 0x4E, 0xE3, 0x71, 0xAA,\n\t0x76, 0x34, 0x1D, 0x2F, 0x80, 0xCF, 0xCB, 0x83, 0xEF, 0x04, 0xF4, 0xC5,\n\t0x0F, 0x53, 0x42, 0x03, 0xFD, 0xF2, 0x47, 0xD0, 0xB9, 0x0B, 0x53, 0xEB,\n\t0xC1, 0x11, 0xBA, 0xCB, 0x73, 0x60, 0x75, 0xE5, 0xF8, 0x43, 0x50, 0xBE,\n\t0xCB, 0xF6, 0xC7, 0xA5, 0x18, 0xD4, 0xD9, 0x0F, 0xA8, 0x2B, 0xC7, 0x2E,\n\t0x5F, 0xF8, 0x6F, 0xCD, 0x2D, 0xD2, 0x78, 0x6F, 0xCD, 0x78, 0x0B, 0x70,\n\t0x22, 0xFA, 0x85, 0x93, 0xB5, 0x44, 0xB6, 0x4B, 0x65, 0x1F, 0x49, 0x07,\n\t0x2E, 0x77, 0xE9, 0xF0, 0x5A, 0xBC, 0xE6, 0x76, 0xDD, 0x03, 0xF1, 0x86,\n\t0x66, 0x4B, 0x34, 0x72, 0x75, 0x89, 0x02, 0x31, 0x27, 0xC7, 0x9A, 0x39,\n\t0x91, 0xBE, 0xBC, 0xC9, 0x5F, 0x83, 0xE1, 0x29, 0x43, 0x73, 0x6C, 0x4E,\n\t0xB9, 0x4B, 0x0F, 0xD6, 0xD5, 0x5C, 0x55, 0xA1, 0x26, 0x95, 0xAA, 0x29,\n\t0xD0, 0xD4, 0x2C, 0xBC, 0x94, 0x9C, 0xEA, 0xED, 0x02, 0x68, 0x7D, 0x67,\n\t0xB0, 0xC0, 0xF4, 0x9D, 0x19, 0xA7, 0x6D, 0x6B, 0x5C, 0xEC, 0x5F, 0x44,\n\t0xCF, 0xC9, 0x07, 0x66, 0x70, 0xD6, 0x78, 0x86, 0x36, 0xA7, 0x19, 0x09,\n\t0xC6, 0x83, 0x61, 0xF2, 0xAD, 0x24, 0x52, 0x02, 0x6B, 0x2C, 0x33, 0xEE,\n\t0x39, 0x2F, 0x41, 0xD8, 0x15, 0x28, 0xA1, 0x33, 0x8A, 0x58, 0x9D, 0x01,\n\t0x7C, 0xB2, 0x28, 0xB1, 0x2D, 0x93, 0x4F, 0xCD, 0x46, 0xA2, 0x59, 0xB4,\n\t0x18, 0xBB, 0xE5, 0x08, 0xC1, 0xC9, 0x23, 0x00, 0x73, 0xB3, 0x1A, 0xF9,\n\t0x01, 0xC9, 0x22, 0xF2, 0xDB, 0xEA, 0x01, 0xD2, 0x35, 0x7C, 0x2C, 0x69,\n\t0x12, 0xB8, 0x0C, 0x2C, 0x3C, 0x4E, 0xA7, 0x04, 0xD4, 0x80, 0x8C, 0xF2,\n\t0x2A, 0x79, 0x88, 0x6E, 0x86, 0x64, 0x21, 0xF2, 0x56, 0x13, 0xC2, 0x6C,\n\t0x41, 0xB6, 0xB8, 0xC5, 0xFA, 0xC1, 0x78, 0xB3, 0x28, 0x1E, 0x1B, 0xA8,\n\t0x17, 0xC8, 0xDC, 0x8F, 0x5B, 0x83, 0x41, 0xED, 0x81, 0x32, 0x6C, 0x03,\n\t0x91, 0x3B, 0xCA, 0x3A, 0xD3, 0x3A, 0x9D, 0x87, 0x74, 0x33, 0x6D, 0xAD,\n\t0x4C, 0x3E, 0x39, 0x65, 0xDF, 0x00, 0x50, 0x4D, 0x5D, 0x18, 0x25, 0x8E,\n\t0xAF, 0xE7, 0xEE, 0x22, 0x43, 0xEA, 0x30, 0x20, 0x98, 0x58, 0xEB, 0x21,\n\t0x5E, 0xE2, 0x54, 0xB8, 0x1A, 0x51, 0xA6, 0x79, 0x83, 0xD4, 0xE6, 0xD0,\n\t0x73, 0xDA, 0xC9, 0xD1, 0x53, 0xFC, 0x0A, 0x0C, 0xDA, 0x35, 0x0F, 0x0A,\n\t0xC4, 0xDF, 0x65, 0x60, 0xD2, 0x96, 0x4B, 0x16, 0xE5, 0x99, 0xAB, 0x71,\n\t0x27, 0x43, 0xDF, 0x48, 0xB6, 0x2F, 0xFB, 0x3F, 0x7E, 0x0C, 0x46, 0xE9,\n\t0x3E, 0x1C, 0x07, 0xBA, 0xB2, 0x6E, 0x2A, 0x77, 0xB4, 0x46, 0x3A, 0x6E,\n\t0x22, 0x8C, 0x29, 0xA6, 0x55, 0x0C, 0xC6, 0x3E, 0x42, 0x26, 0x5B, 0xF5,\n\t0x14, 0x38, 0xF5, 0x26, 0x1E, 0xA4, 0xC1, 0x9A, 0x87, 0xA5, 0xCB, 0x4C,\n\t0x8E, 0x22, 0x72, 0x43, 0x8A, 0xF8, 0x65, 0x25, 0x17, 0xBD, 0xAB, 0x07,\n\t0xAF, 0x55, 0x9C, 0x7D, 0x24, 0xA2, 0x16, 0x82, 0xA7, 0xBA, 0xB2, 0x20,\n\t0x8D, 0xA8, 0x4D, 0x99, 0x87, 0x85, 0xE1, 0x2E, 0x2E, 0x2F, 0xA7, 0xC8,\n\t0x23, 0xDA, 0x4A, 0xEE, 0x24, 0xFE, 0x53, 0x27, 0xB9, 0x3F, 0x4C, 0x4F,\n\t0x1C, 0x92, 0xF7, 0xA1, 0x2A, 0x0A, 0xB3, 0xE9, 0x58, 0xA0, 0xD9, 0x38,\n\t0x13, 0x9E, 0x6A, 0xC2, 0x70, 0x72, 0xDA, 0x0A, 0xDC, 0xD1, 0x75, 0x92,\n\t0x7B, 0xE2, 0x58, 0xBC, 0xB8, 0xA9, 0xBD, 0xE8, 0xA3, 0x50, 0x6D, 0x0F,\n\t0x28, 0x34, 0xEA, 0x2D, 0x90, 0x56, 0x48, 0x25, 0xFE, 0xC8, 0xF4, 0x92,\n\t0xD3, 0xB7, 0x22, 0x77, 0xAD, 0x7E, 0xDD, 0xEF, 0x1F, 0x82, 0x03, 0x9E,\n\t0x17, 0x94, 0xFC, 0x84, 0xCC, 0x42, 0xDE, 0x4B, 0x3D, 0x06, 0xAA, 0x7B,\n\t0x8D, 0x63, 0xA5, 0x63, 0x27, 0x77, 0xD3, 0xB2, 0xD3, 0x69, 0x15, 0xC2,\n\t0x6E, 0x05, 0xBC, 0x34, 0x94, 0x6B, 0xAC, 0xEF, 0xDA, 0x9D, 0xBA, 0x45,\n\t0xC4, 0xDC, 0x94, 0xF0, 0x86, 0xDB, 0x38, 0x35, 0x28, 0x23, 0xB9, 0x90,\n\t0x3F, 0xDE, 0x4C, 0xEE, 0xB2, 0x9D, 0x43, 0x72, 0x58, 0xBD, 0xE4, 0xA2,\n\t0xBA, 0x62, 0x98, 0x59, 0xB5, 0x59, 0x19, 0xD2, 0x66, 0x7A, 0x27, 0x90,\n\t0xD9, 0x02, 0xD8, 0xAC, 0xC6, 0x59, 0x39, 0x4F, 0x7A, 0x31, 0x4E, 0x23,\n\t0xC2, 0x83, 0x8E, 0x72, 0xA4, 0xAD, 0xAD, 0x76, 0x95, 0xE4, 0xD0, 0x3A,\n\t0xF1, 0xBC, 0x54, 0x6E, 0xC2, 0x6F, 0x65, 0xAA, 0x31, 0xC4, 0x6D, 0x73,\n\t0xAB, 0x42, 0x15, 0x74, 0x90, 0x68, 0xDC, 0x6D, 0xEF, 0x72, 0xB1, 0xB4,\n\t0xA5, 0x30, 0xF4, 0xEA, 0x8B, 0x18, 0x1D, 0xCE, 0xD8, 0x66, 0xA1, 0x88,\n\t0x74, 0x8F, 0x47, 0x80, 0x2A, 0x8D, 0x95, 0xF0, 0x86, 0x23, 0x89, 0xB1,\n\t0xA3, 0x34, 0x83, 0xF8, 0x89, 0x8C, 0xF9, 0xEB, 0x26, 0xCA, 0x3E, 0x64,\n\t0x03, 0x61, 0xFB, 0x85, 0xCC, 0x0B, 0x1C, 0xA6, 0x05, 0xEA, 0x09, 0x9C,\n\t0xA8, 0x50, 0xB6, 0x8B, 0x5E, 0x9E, 0x3E, 0x3B, 0x8E, 0xAD, 0x7D, 0x0D,\n\t0x5A, 0x6E, 0x27, 0xC9, 0x4E, 0xFF, 0x53, 0x06, 0xAB, 0x40, 0x1F, 0x32,\n\t0x57, 0xCA, 0xD6, 0x3E, 0x1F, 0xF1, 0xED, 0x21, 0xF6, 0xAF, 0x6D, 0x65,\n\t0x14, 0xF5, 0x47, 0x26, 0xDC, 0x9B, 0x90, 0x66, 0xE5, 0x32, 0x4D, 0x92,\n\t0xB5, 0xD9, 0x85, 0x48, 0x18, 0x17, 0x96, 0x5F, 0xC2, 0xD5, 0xF7, 0xD0,\n\t0x11, 0xBE, 0xE5, 0x55, 0x00, 0x94, 0xBD, 0x69, 0x7B, 0x17, 0x7B, 0xF1,\n\t0xB9, 0xA8, 0x46, 0x5E, 0xD1, 0x6D, 0x2F, 0x36, 0xB1, 0x60, 0x0C, 0x96,\n\t0x3C, 0x0D, 0x35, 0x17, 0x70, 0x74, 0x5B, 0xA5, 0x1B, 0x99, 0x8E, 0x74,\n\t0xED, 0x89, 0x25, 0x29, 0x97, 0xBF, 0x7A, 0x91, 0x45, 0x69, 0xA1, 0x6B,\n\t0x61, 0xB4, 0x47, 0x50, 0xED, 0x15, 0xC0, 0xB6, 0x06, 0x36, 0x33, 0x12,\n\t0x16, 0xDA, 0x0A, 0x46, 0x4F, 0xCC, 0x7B, 0xC7, 0x8A, 0x45, 0x96, 0x27,\n\t0x1C, 0x46, 0x85, 0x08, 0xD7, 0x36, 0xB7, 0xC7, 0xA0, 0xD7, 0xC0, 0x60,\n\t0x2B, 0x6C, 0x6B, 0x6F, 0xD1, 0xBF, 0x5B, 0xF7, 0xA5, 0xC0, 0x48, 0xE2,\n\t0x88, 0xA3, 0x4C, 0x06, 0xDC, 0x97, 0xD2, 0x91, 0xF8, 0x85, 0x1C, 0x72,\n\t0x7F, 0x37, 0x05, 0x70, 0x4E, 0xEA, 0x0A, 0x89, 0x04, 0xA7, 0x64, 0x7D,\n\t0x95, 0x85, 0x35, 0x81, 0x0F, 0xBC, 0xA0, 0x04, 0x80, 0xD9, 0x58, 0x43,\n\t0x8F, 0x51, 0xEB, 0x29, 0x72, 0xA3, 0xEB, 0xB8, 0x0E, 0x2C, 0x94, 0x0E,\n\t0xAD, 0xCF, 0x29, 0xA5, 0xF0, 0xDF, 0x6D, 0xCA, 0x88, 0x7B, 0x2E, 0xDD,\n\t0x3C, 0x26, 0x79, 0xED, 0x67, 0x71, 0xAC, 0x44, 0xA5, 0xFA, 0xA8, 0x79,\n\t0x7C, 0x79, 0x35, 0x5D, 0xCB, 0x79, 0xA4, 0x56, 0xEB, 0x76, 0xD8, 0x4D,\n\t0x98, 0xFF, 0x71, 0xA8, 0x46, 0x7F, 0x26, 0x98, 0x4F, 0xA0, 0xC8, 0x47,\n\t0x00, 0xFB, 0x21, 0xE6, 0xD1, 0x11, 0x3C, 0xD4, 0xCF, 0x89, 0xF4, 0x68,\n\t0xAA, 0x2A, 0xFA, 0x48, 0xE7, 0x48, 0x10, 0xC7, 0xB8, 0x90, 0x17, 0xA3,\n\t0x0C, 0x0F, 0x08, 0x6E, 0xE4, 0xC9, 0x75, 0xA0, 0x89, 0x4F, 0xE1, 0x0A,\n\t0x83, 0xE3, 0x6E, 0x10, 0x80, 0xE4, 0xC2, 0x05, 0xF5, 0x29, 0x31, 0x30,\n\t0x57, 0xA7, 0xDC, 0x5F, 0x99, 0xD5, 0x1E, 0x1E, 0x07, 0x8C, 0xD1, 0x61,\n\t0x1B, 0xB2, 0xB3, 0x2C, 0xA8, 0x33, 0xC9, 0x4C, 0x39, 0x56, 0xBA, 0xFC,\n\t0x65, 0xE2, 0xB9, 0xB6, 0x1C, 0x56, 0x24, 0x59, 0xA0, 0x0F, 0x62, 0xB4,\n\t0xE3, 0xE6, 0xF4, 0x24, 0x08, 0xA6, 0x4B, 0xC7, 0xA5, 0x09, 0xB2, 0x0E,\n\t0xD6, 0x41, 0x4F, 0x89, 0x97, 0x0D, 0xA1, 0xE4, 0x10, 0x3D, 0x2E, 0x36,\n\t0xC2, 0x7A, 0x73, 0xD6, 0x30, 0x05, 0xA1, 0xC7, 0x08, 0x27, 0x28, 0x79,\n\t0x8C, 0xC8, 0xE3, 0xE5, 0x1B, 0x7F, 0x22, 0xCD, 0x9C, 0x6A, 0x66, 0xE9,\n\t0x63, 0xB2, 0x42, 0x72, 0x23, 0x3B, 0xB6, 0xF5, 0x08, 0xF5, 0x26, 0xD4,\n\t0x22, 0x8E, 0x9B, 0xFA, 0x42, 0x5C, 0x47, 0x33, 0x0F, 0x7C, 0xDF, 0x0A,\n\t0x97, 0x80, 0xF0, 0x84, 0xC6, 0xBB, 0xDA, 0x09, 0xD7, 0xBA, 0x79, 0x17,\n\t0x06, 0xD2, 0xDA, 0x34, 0x0A, 0x95, 0x83, 0x65, 0xFA, 0x92, 0xC3, 0x52,\n\t0xF9, 0xFA, 0x96, 0xCB, 0xC0, 0xE7, 0x53, 0x7F, 0xFF, 0x3F, 0x7C, 0x8B,\n\t0x92, 0xA3, 0x69, 0xBC, 0x46, 0xBD, 0x0E, 0xC9, 0xE7, 0x1E, 0x28, 0x62,\n\t0xEB, 0xE4, 0xB8, 0x28, 0x0C, 0x82, 0x1C, 0xA4, 0xC9, 0x92, 0x4F, 0xDE,\n\t0x66, 0x87, 0x9C, 0x7A, 0x1A, 0x77, 0x16, 0xD1, 0x78, 0xCB, 0x98, 0x2F,\n\t0xFA, 0x2B, 0x06, 0xF0, 0x30, 0x73, 0xE7, 0xD8, 0xB3, 0x0D, 0xAE, 0x57,\n\t0xCB, 0xB6, 0xF1, 0x1B, 0xCB, 0xA5, 0xCB, 0x2C, 0xDC, 0x09, 0xEB, 0x9F,\n\t0xCB, 0xBF, 0x81, 0x8F, 0x8B, 0x2E, 0xD0, 0x3A, 0x01, 0x2E, 0xF8, 0xB5,\n\t0x3E, 0xC8, 0x19, 0xB6, 0x1B, 0x44, 0xF9, 0xB4, 0x10, 0x6E, 0xC6, 0x8D,\n\t0xDB, 0x9F, 0xB5, 0x38, 0xCF, 0x3D, 0x50, 0x8A, 0xC0, 0x93, 0xA5, 0x7A,\n\t0x71, 0x69, 0x2A, 0xFF, 0x83, 0xBE, 0xDC, 0xC7, 0xBE, 0xAD, 0xED, 0x15,\n\t0x0E, 0xB6, 0xEF, 0x13, 0xD8, 0x75, 0x72, 0xC1, 0xEF, 0x2F, 0x14, 0x96,\n\t0x1E, 0x03, 0x6F, 0x49, 0x60, 0x45, 0xA6, 0x47, 0x37, 0x31, 0xCE, 0x7F,\n\t0x7C, 0x60, 0x06, 0x3C, 0xB8, 0x8B, 0x14, 0x64, 0xF6, 0xFD, 0xA6, 0xA0,\n\t0xC5, 0x17, 0xCD, 0x5E, 0xF5, 0xFE, 0x25, 0x5E, 0xA7, 0xAA, 0xAB, 0x1F,\n\t0x1D, 0xC1, 0xEC, 0xEE, 0x63, 0x57, 0x5A, 0xFC, 0xA7, 0x33, 0x5D, 0x9E,\n\t0x04, 0xB3, 0xE0, 0x50, 0x2A, 0x7F, 0x2C, 0x0A, 0xB4, 0xAA, 0x12, 0x6A,\n\t0xD0, 0x54, 0xA7, 0x0A, 0xCE, 0x98, 0x5A, 0x1C, 0xA1, 0xF4, 0x51, 0x03,\n\t0xEA, 0xAD, 0x89, 0xCA, 0xB9, 0x0D, 0x19, 0x9F, 0x37, 0xD7, 0x67, 0x98,\n\t0xBF, 0xE8, 0xA2, 0x98, 0xC1, 0x9F, 0x7E, 0xF7, 0x0F, 0x9B, 0x5B, 0x91,\n\t0xD1, 0x3D, 0xC1, 0x06, 0x17, 0x81, 0xFA, 0x54, 0x95, 0xC4, 0xEB, 0xBA,\n\t0xEA, 0x46, 0x82, 0xEA, 0xDA, 0x2A, 0x7E, 0xD0, 0xE7, 0x8C, 0xDA, 0x78,\n\t0xA1, 0xB2, 0xF4, 0xE5, 0x4A, 0xD3, 0x75, 0x68, 0xBE, 0xEB, 0x7E, 0x98,\n\t0x58, 0x83, 0xC1, 0xD6, 0x68, 0x37, 0xF3, 0x09, 0xF6, 0x53, 0x25, 0x0A,\n\t0x71, 0xDA, 0x29, 0x5F, 0x4A, 0xCD, 0x14, 0x33, 0x06, 0x88, 0xD0, 0x83,\n\t0xC6, 0x4D, 0x09, 0x1D, 0xFC, 0xDF, 0x59, 0x4F, 0x94, 0xB5, 0xA3, 0xF7,\n\t0x02, 0x04, 0x86, 0x41, 0x3A, 0xE7, 0x74, 0xF4, 0xFA, 0xB7, 0xF5, 0xB3,\n\t0xD6, 0x9B, 0x9D, 0x58, 0xB8, 0xE7, 0xFF, 0x00, 0xD4, 0xB1, 0xAB, 0x96,\n\t0x62, 0x15, 0x1D, 0x26, 0xB0, 0x10, 0x42, 0x47, 0x29, 0xD3, 0x67, 0x93,\n\t0xC7, 0x34, 0xD4, 0xBB, 0x08, 0x2A, 0x54, 0x45, 0x39, 0x77, 0x92, 0x7B,\n\t0x7C, 0xEC, 0xF2, 0x55, 0xCF, 0x0F, 0xAA, 0x22, 0x87, 0xFF, 0xF3, 0x45,\n\t0xA7, 0xA5, 0x2F, 0xB6, 0xF4, 0x89, 0xE3, 0xE2, 0x38, 0xC4, 0x7A, 0xA6,\n\t0x38, 0x6D, 0xCB, 0x5E, 0x28, 0x58, 0x46, 0xBF, 0x58, 0xE0, 0xD7, 0xA6,\n\t0x23, 0x43, 0xCE, 0x3F, 0x0D, 0x7F, 0x26, 0xAF, 0x9A, 0x8B, 0x4C, 0x92,\n\t0x6E, 0xBB, 0xFD, 0x92, 0x56, 0x70, 0xAB, 0xB6, 0xF3, 0x8C, 0x08, 0xF2,\n\t0xA9, 0x03, 0x96, 0x03, 0x1F, 0xFB, 0xBB, 0xCB, 0xAE, 0x69, 0xA6, 0x0D,\n\t0x5A, 0x0A, 0x71, 0x05, 0xB0, 0xE6, 0x3F, 0x24, 0x1D, 0xC6, 0xCB, 0xCC,\n\t0x3F, 0x33, 0xF5, 0xE8, 0x3F, 0x10, 0x36, 0x0E, 0xB5, 0x11, 0x0D, 0xFD,\n\t0x27, 0xDC, 0x1A, 0xEB, 0x2D, 0x0E, 0x62, 0xCF, 0xD4, 0x59, 0x03, 0x57,\n\t0xB2, 0x71, 0x11, 0x39, 0x5A, 0xCD, 0x8A, 0xDD, 0xA8, 0x63, 0x1B, 0xE9,\n\t0xFF, 0x8A, 0x1D, 0x71, 0xC0, 0xAF, 0xC2, 0xB2, 0x69, 0x88, 0xE0, 0xB5,\n\t0xA7, 0x03, 0x10, 0x95, 0x64, 0xC5, 0x3C, 0xF2, 0xBC, 0xC9, 0x20, 0xF5,\n\t0x25, 0x5B, 0x1B, 0xAE, 0x5E, 0x4A, 0x5D, 0xB0, 0xA6, 0xCA, 0x68, 0x41,\n\t0x89, 0x2C, 0xE6, 0x2D, 0xAF, 0xD2, 0x04, 0xC9, 0x88, 0x89, 0xDC, 0x39,\n\t0xED, 0xC9, 0xB6, 0xDD, 0xEC, 0xE7, 0x6D, 0xA0, 0x83, 0x0F, 0xCE, 0xB4,\n\t0xC1, 0x80, 0x3D, 0x2B, 0x21, 0xC1, 0x4D, 0xC6, 0x27, 0x13, 0xA2, 0xB9,\n\t0x92, 0xDD, 0xB9, 0xBD, 0xE5, 0x65, 0xAF, 0xA1, 0xBF, 0x9F, 0x04, 0x7D,\n\t0x02, 0x33, 0xE8, 0x9F, 0x25, 0x8D, 0x7C, 0xA5, 0x35, 0x80, 0x58, 0xF1,\n\t0xF2, 0x1B, 0x9D, 0xDF, 0x48, 0xA3, 0x9B, 0x3F, 0x8E, 0xCF, 0xAB, 0x54,\n\t0x03, 0x78, 0xFC, 0x1B, 0x8F, 0xA3, 0xDD, 0x28, 0x99, 0x4B, 0xEB, 0x89,\n\t0x4E, 0xAF, 0x60, 0xB6, 0x75, 0x7D, 0x89, 0x78, 0x0D, 0x9D, 0x80, 0x82,\n\t0x95, 0x50, 0x4B, 0xBF, 0xBA, 0xF7, 0x58, 0x8B, 0x62, 0x88, 0x68, 0xE5,\n\t0x59, 0xE4, 0xDF, 0xE8, 0x6C, 0xA3, 0xF6, 0xA4, 0xEB, 0x15, 0x8F, 0xE6,\n\t0xCB, 0x3E, 0xD3, 0x1E, 0xEC, 0x59, 0x34, 0x7C, 0x8B, 0x16, 0xD7, 0x3C,\n\t0x16, 0x17, 0x4B, 0xAC, 0x8D, 0xEF, 0x38, 0x63, 0x9A, 0xF7, 0x42, 0x64,\n\t0xA0, 0x80, 0x1B, 0x60, 0xDA, 0x2B, 0x5E, 0x31, 0x20, 0x3F, 0x96, 0xFD,\n\t0x9B, 0xCD, 0x27, 0x7D, 0x44, 0x72, 0x12, 0xCF, 0xA2, 0xDB, 0x2F, 0x1F,\n\t0x20, 0xB9, 0x1F, 0x75, 0x68, 0x7E, 0xAB, 0x40, 0xD7, 0xCD, 0xB7, 0xC8,\n\t0x85, 0x73, 0x58, 0x3D, 0x16, 0x35, 0x6F, 0x45, 0x45, 0x9D, 0xCB, 0x98,\n\t0x5A, 0x94, 0x66, 0xA0, 0x4E, 0x39, 0x22, 0x2E, 0xAB, 0x35, 0x1F, 0x1D,\n\t0x5D, 0x32, 0xA8, 0xD6, 0x9B, 0x97, 0x9B, 0x4C, 0xF6, 0x20, 0x2A, 0x80,\n\t0xB0, 0xC8, 0x4F, 0x9B, 0x64, 0xAE, 0x96, 0x8C, 0xEA, 0xA3, 0x67, 0x38,\n\t0x20, 0xDA, 0xFF, 0xF5, 0xA1, 0xFD, 0xA8, 0xF4, 0x97, 0xB5, 0x02, 0xF8,\n\t0x37, 0xE8, 0xB7, 0xB2, 0xBA, 0x38, 0x1E, 0xD5, 0x6C, 0x0A, 0x67, 0x29,\n\t0x0B, 0x32, 0xB5, 0x90, 0x73, 0xDA, 0x0B, 0xD2, 0xC1, 0x59, 0x19, 0xBE,\n\t0x25, 0x99, 0x77, 0xE9, 0xD4, 0x10, 0x33, 0x13, 0xD2, 0x92, 0xB1, 0x09,\n\t0x47, 0x3A, 0xBD, 0x4A, 0x66, 0xEA, 0x07, 0x9F, 0xC4, 0xE5, 0x55, 0x8E,\n\t0x55, 0xB2, 0x55, 0x3A, 0xEB, 0x1F, 0xD1, 0x3A, 0x65, 0xAF, 0x3E, 0xF4,\n\t0x0B, 0x34, 0xA5, 0x02, 0xBB, 0xD3, 0x86, 0x4D, 0x54, 0xE1, 0xEA, 0x14,\n\t0x83, 0x40, 0x19, 0x80, 0x68, 0x17, 0x22, 0xF6, 0x52, 0x25, 0x46, 0xB5,\n\t0x0C, 0x7F, 0xE3, 0xC7, 0xF8, 0x42, 0x59, 0x95, 0x65, 0x4D, 0x1A, 0x7C,\n\t0x6B, 0x45, 0xB9, 0xC5, 0x7F, 0x9A, 0x96, 0xD7, 0xA3, 0x5B, 0xC5, 0x90,\n\t0x8B, 0xBC, 0x7E, 0x31, 0x07, 0x44, 0x4B, 0xE2, 0xEE, 0xB4, 0x33, 0xCD,\n\t0x0D, 0x0F, 0x6B, 0x88, 0x4E, 0x57, 0x24, 0x1C, 0x00, 0xAE, 0x7D, 0x28,\n\t0xEB, 0x0E, 0x4C, 0x8E, 0xAA, 0xA0, 0xB3, 0xA3, 0xAF, 0x9C, 0x86, 0x7F,\n\t0xE3, 0x7F, 0x2D, 0x25, 0xA4, 0x09, 0xD6, 0x73, 0x95, 0x49, 0x98, 0x37,\n\t0xF3, 0x58, 0xE6, 0x5C, 0x24, 0x34, 0x87, 0xEA, 0x87, 0xCE, 0x76, 0x2F,\n\t0x0A, 0xAC, 0x0F, 0x9D, 0x85, 0xAA, 0x09, 0x6E, 0x06, 0x9C, 0x28, 0x9A,\n\t0xCB, 0x91, 0xEF, 0x19, 0xF0, 0x7A, 0x0C, 0xC0, 0xCE, 0xAC, 0x6A, 0xA7,\n\t0x20, 0x51, 0x35, 0xD7, 0x7B, 0xFB, 0xD1, 0x1C, 0x0F, 0xC4, 0xCE, 0x65,\n\t0x21, 0x63, 0x41, 0x35, 0x55, 0x2E, 0x20, 0x07, 0x43, 0x39, 0xBB, 0x86,\n\t0x60, 0xB8, 0x87, 0x4C, 0x0B, 0x78, 0x35, 0xBA, 0x91, 0x96, 0xAF, 0x0D,\n\t0xAA, 0x79, 0x6B, 0x1B, 0x75, 0xC2, 0x5B, 0x2F, 0x85, 0x04, 0x40, 0xED,\n\t0x96, 0x63, 0xF2, 0x36, 0xF1, 0x0A, 0x94, 0x6D, 0x01, 0x90, 0x7D, 0x1F,\n\t0x8B, 0x7D, 0x08, 0xD7, 0x9F, 0xA1, 0x23, 0xB2, 0xBF, 0xA3, 0x80, 0x6C,\n\t0x90, 0x67, 0x70, 0xF0, 0xC7, 0x0A, 0x6D, 0xAD, 0x40, 0x8B, 0x33, 0xA6,\n\t0xAD, 0x6F, 0x2A, 0xBE, 0xE2, 0x70, 0x4A, 0xFA, 0x31, 0x6B, 0x3B, 0x62,\n\t0x47, 0xDE, 0x5B, 0x13, 0xD0, 0x85, 0x63, 0x18, 0xE0, 0x9C, 0x61, 0x29,\n\t0x2B, 0x13, 0x64, 0x44, 0x36, 0x01, 0x97, 0xED, 0xB6, 0xF0, 0xCC, 0x8E,\n\t0xAD, 0xDE, 0x6B, 0xC7, 0x7B, 0xF5, 0x84, 0x08, 0xA3, 0xB7, 0x96, 0xBA,\n\t0x0F, 0x20, 0xC1, 0xE2, 0x40, 0x31, 0x6A, 0x25, 0x06, 0xC4, 0x35, 0x4F,\n\t0x04, 0x19, 0xD6, 0x86, 0xDC, 0x07, 0x48, 0x5F, 0xC3, 0xEA, 0x3B, 0x20,\n\t0xBB, 0x59, 0xFE, 0x05, 0x45, 0xC3, 0xDE, 0x08, 0x44, 0xF6, 0x19, 0xE9,\n\t0x95, 0x8A, 0xDE, 0xA6, 0xD9, 0x96, 0x59, 0x7E, 0x7C, 0xBF, 0x00, 0x48,\n\t0x36, 0xBD, 0xB0, 0xB4, 0x22, 0xBE, 0xD0, 0xE5, 0x40, 0x8C, 0x3B, 0x6E,\n\t0x11, 0xDA, 0x24, 0xBA, 0x09, 0xEE, 0x6C, 0xB0, 0xD5, 0x87, 0x01, 0xD9,\n\t0xBE, 0x02, 0xE1, 0x80, 0x89, 0x3F, 0x57, 0xB1, 0xF6, 0x53, 0xF8, 0x59,\n\t0x6F, 0x99, 0x25, 0xF0, 0x10, 0xD9, 0x8F, 0x56, 0xC7, 0x05, 0x4B, 0xE8,\n\t0xE2, 0x3C, 0xE0, 0x6C, 0x42, 0xA2, 0x08, 0x92, 0xED, 0x06, 0x64, 0xBF,\n\t0x0C, 0x91, 0x7D, 0xAE, 0x64, 0x0B, 0xEE, 0x88, 0x54, 0xB2, 0xC8, 0xE6,\n\t0xF1, 0x42, 0x75, 0x40, 0x64, 0x7B, 0x23, 0x75, 0x81, 0x17, 0x90, 0x7D,\n\t0x21, 0x79, 0xF2, 0x39, 0xD1, 0xD6, 0x26, 0xDE, 0xFB, 0xF4, 0x7B, 0x2A,\n\t0xFC, 0x00, 0xD0, 0x16, 0x8B, 0x0B, 0x62, 0x95, 0xC9, 0x86, 0xE1, 0xB2,\n\t0x0D, 0x7B, 0x04, 0x2D, 0xE2, 0x33, 0x4F, 0x48, 0x7D, 0x06, 0x94, 0x67,\n\t0x0F, 0x01, 0x40, 0x7B, 0xFA, 0x50, 0x25, 0x2C, 0xBA, 0xB5, 0x65, 0x0E,\n\t0x00, 0xAA, 0x60, 0x08, 0xD6, 0xE1, 0xB8, 0x55, 0xF3, 0x41, 0x21, 0xF9,\n\t0x1F, 0xE3, 0x71, 0x00, 0x6B, 0x8D, 0x59, 0x7A, 0xA3, 0xD1, 0x48, 0x6B,\n\t0x29, 0x82, 0x55, 0x3F, 0x7A, 0x62, 0x3A, 0xC5, 0xFE, 0x23, 0x0E, 0xFC,\n\t0xAA, 0x1D, 0xC3, 0x7A, 0xD6, 0x2B, 0xB0, 0xDD, 0x36, 0x8D, 0x3B, 0x78,\n\t0x15, 0x08, 0xB1, 0x3F, 0xC4, 0xD2, 0x46, 0xCD, 0x18, 0x4F, 0xAC, 0x73,\n\t0x0D, 0xE3, 0x63, 0xB1, 0xF2, 0xB9, 0xDA, 0x5A, 0x4A, 0x09, 0xCD, 0x6E,\n\t0x8D, 0xBA, 0x14, 0x6A, 0x3A, 0xC5, 0xA3, 0x5A, 0x2F, 0x30, 0xE4, 0xD4,\n\t0xFE, 0xB0, 0xC4, 0x33, 0xF3, 0xDF, 0xA8, 0xD4, 0x40, 0xD2, 0xB8, 0x78,\n\t0x2B, 0xC8, 0x03, 0x45, 0x6A, 0x14, 0x7A, 0xCA, 0x77, 0x1B, 0xCE, 0x09,\n\t0x64, 0x74, 0x9E, 0xAB, 0x0A, 0x00, 0x9B, 0xCC, 0x2B, 0xF4, 0x6E, 0xD0,\n\t0xD3, 0xC0, 0xEA, 0xC6, 0x3F, 0x88, 0xDE, 0x39, 0xF8, 0xA9, 0x62, 0x3C,\n\t0xCD, 0x1C, 0x00, 0x75, 0x8B, 0xA7, 0xB3, 0x02, 0x7F, 0xEB, 0x34, 0xBA,\n\t0x46, 0xF0, 0xCC, 0xC9, 0xB3, 0xB3, 0xF8, 0xBD, 0xEB, 0x18, 0x9F, 0x35,\n\t0x1A, 0xFE, 0xFE, 0x6F, 0xB7, 0x38, 0xC4, 0x30, 0xA0, 0xB7, 0xA8, 0xE0,\n\t0x03, 0x58, 0xE4, 0x79, 0x93, 0x0F, 0xD6, 0xAD, 0x8B, 0x05, 0xDE, 0x6D,\n\t0xA1, 0x79, 0x34, 0xA8, 0x0F, 0x49, 0x23, 0x46, 0xE5, 0xFA, 0x24, 0x4F,\n\t0xD7, 0x1F, 0xAD, 0xCF, 0xA4, 0x81, 0x06, 0x3C, 0x27, 0x41, 0x8C, 0xFA,\n\t0x7C, 0x87, 0xAF, 0xBD, 0x76, 0xD1, 0x7C, 0x03, 0x8B, 0x46, 0x60, 0x62,\n\t0x72, 0xCB, 0xC6, 0xF0, 0xD2, 0x6C, 0xDA, 0x22, 0xED, 0xF0, 0xBF, 0xE8,\n\t0x90, 0x6F, 0x29, 0xB4, 0x87, 0x73, 0x4D, 0x64, 0x96, 0x06, 0x91, 0x7E,\n\t0x4F, 0xE4, 0xAF, 0x04, 0x0D, 0xEE, 0x6E, 0xD3, 0x86, 0x7E, 0x77, 0x83,\n\t0x1E, 0x6B, 0xCD, 0xA1, 0x7D, 0x01, 0x19, 0x9B, 0x31, 0x36, 0x8F, 0x71,\n\t0xEE, 0xFA, 0x7B, 0xB6, 0xDF, 0xA4, 0x3F, 0x4E, 0x25, 0xE9, 0x21, 0x37,\n\t0xFB, 0xBE, 0x8E, 0x7D, 0x05, 0x8A, 0x27, 0x38, 0x92, 0x11, 0xC9, 0xCC,\n\t0x7B, 0x4F, 0x13, 0x81, 0x86, 0xE1, 0xC2, 0x37, 0xBA, 0xA1, 0xBA, 0xF0,\n\t0x37, 0x95, 0x59, 0xD1, 0x67, 0xA2, 0xC7, 0x2B, 0xEB, 0xFE, 0xBA, 0x10,\n\t0x07, 0x02, 0x6E, 0x8D, 0x3E, 0xB4, 0x09, 0x69, 0xEA, 0x5B, 0xC4, 0x40,\n\t0x9E, 0xF6, 0xDB, 0x8D, 0xFE, 0xF2, 0xF6, 0x34, 0x8A, 0xFC, 0x33, 0x7E,\n\t0x8D, 0x95, 0x24, 0xD8, 0xA3, 0xE0, 0xC2, 0x5F, 0x04, 0xA0, 0x93, 0x1A,\n\t0x13, 0x2B, 0x58, 0xB2, 0x4A, 0x80, 0x75, 0x4A, 0x4F, 0x62, 0xB4, 0x9D,\n\t0x04, 0xA3, 0xF3, 0x9E, 0xF1, 0xBF, 0x19, 0x19, 0xE9, 0x56, 0x0B, 0x5C,\n\t0x32, 0x5A, 0xAA, 0x8A, 0xF0, 0xC9, 0x18, 0x15, 0x84, 0xDF, 0xF8, 0x0F,\n\t0x3A, 0x0C, 0x27, 0x8C, 0x19, 0xC7, 0xEF, 0x75, 0x35, 0x09, 0x27, 0x7E,\n\t0xD3, 0xF2, 0x21, 0x6A, 0xB5, 0x4E, 0x27, 0xC0, 0x48, 0x3D, 0x68, 0x1F,\n\t0x8C, 0x4F, 0x2B, 0xEA, 0xC8, 0x77, 0x32, 0x71, 0x7D, 0xAA, 0x3E, 0x0E,\n\t0xE9, 0x62, 0x0F, 0xA9, 0xFA, 0x4D, 0x98, 0xE5, 0x47, 0xEB, 0x04, 0x61,\n\t0xB3, 0x04, 0xD2, 0xE5, 0x83, 0xBF, 0x4D, 0x74, 0xF4, 0xCA, 0x37, 0xB7,\n\t0x0E, 0x3B, 0x4E, 0x1B, 0x6B, 0xD1, 0xB7, 0xD2, 0xAB, 0x3F, 0xC1, 0x71,\n\t0xCE, 0xB4, 0x0D, 0x1B, 0x06, 0x35, 0x6F, 0x43, 0x2A, 0xC9, 0x35, 0x2B,\n\t0x91, 0x0C, 0xDD, 0xB7, 0x35, 0xF6, 0x33, 0xB7, 0x1B, 0xFF, 0xE8, 0x06,\n\t0x35, 0x4B, 0x42, 0x28, 0x85, 0x35, 0x2D, 0x41, 0x99, 0x86, 0x8C, 0x1C,\n\t0xE6, 0xF7, 0xC0, 0x06, 0x43, 0x84, 0xC0, 0x9D, 0xBF, 0x5E, 0x2D, 0xE0,\n\t0x22, 0x9C, 0x55, 0xF1, 0x89, 0xCC, 0xAB, 0xBF, 0x43, 0x71, 0x8F, 0xEE,\n\t0xD9, 0x24, 0x65, 0x09, 0x28, 0xF8, 0x64, 0xAC, 0xCE, 0x3E, 0x0C, 0x44,\n\t0x9C, 0x33, 0xE7, 0xCF, 0x2D, 0x73, 0x97, 0x94, 0xE3, 0x90, 0x55, 0xD9,\n\t0x00, 0x72, 0x75, 0xA8, 0x54, 0x92, 0x81, 0xC6, 0x52, 0xCB, 0x63, 0x03,\n\t0xBA, 0x13, 0x94, 0xCB, 0x18, 0xAC, 0x38, 0xD3, 0x5B, 0x6D, 0x5E, 0xB3,\n\t0x29, 0xB6, 0x06, 0x8E, 0xED, 0xB4, 0xEF, 0x43, 0x6D, 0x8F, 0x84, 0xF6,\n\t0x44, 0xB4, 0xA2, 0xBE, 0xBE, 0x90, 0x96, 0xAB, 0x51, 0x69, 0xDB, 0x93,\n\t0x4E, 0xE5, 0xE0, 0xF1, 0x9F, 0x05, 0x40, 0x70, 0xDA, 0x7B, 0x96, 0x77,\n\t0x6E, 0xD3, 0xF4, 0x6F, 0x6B, 0x59, 0x93, 0x32, 0x1C, 0x0B, 0xB0, 0xDD,\n\t0x5F, 0x7A, 0x8A, 0x6C, 0x42, 0x31, 0x3C, 0xB2, 0x91, 0x73, 0x43, 0x5D,\n\t0xAC, 0x53, 0x05, 0x22, 0xD2, 0x63, 0xFB, 0x41, 0xFE, 0xFA, 0xC3, 0xBE,\n\t0xD0, 0x72, 0x53, 0xC6, 0x57, 0x34, 0xDB, 0xDB, 0xD2, 0x05, 0xB2, 0x07,\n\t0x23, 0x3D, 0xEB, 0x16, 0xBF, 0x28, 0x41, 0x50, 0x8C, 0x43, 0x22, 0x82,\n\t0x1C, 0x69, 0x89, 0x38, 0x09, 0xE4, 0x78, 0xBF, 0x5C, 0x72, 0xC0, 0xCA,\n\t0x1B, 0xDC, 0xE5, 0xDE, 0x89, 0xA2, 0x7F, 0x9F, 0x01, 0xAB, 0x5C, 0x29,\n\t0xE8, 0x95, 0xDA, 0x0D, 0xEB, 0xA1, 0x42, 0xFE, 0x2E, 0x47, 0x93, 0x14,\n\t0x1B, 0x99, 0x07, 0x64, 0xFA, 0xD3, 0xB9, 0x5D, 0x44, 0xC1, 0x74, 0x39,\n\t0x47, 0x46, 0x80, 0x31, 0x5D, 0x66, 0x35, 0x2B, 0x0B, 0xDE, 0x2F, 0x7F,\n\t0x51, 0x31, 0xF0, 0x6C, 0x9A, 0xD9, 0xE3, 0xE4, 0x99, 0x8F, 0x2F, 0xB3,\n\t0xBC, 0x87, 0x27, 0xF3, 0x78, 0x8C, 0xC9, 0xF5, 0x9A, 0x6B, 0x23, 0xF5,\n\t0xC1, 0x91, 0x74, 0x04, 0x04, 0x7C, 0xDD, 0x4D, 0x23, 0x6C, 0xE4, 0x1C,\n\t0x67, 0xA2, 0x6B, 0x90, 0x73, 0xE7, 0xD2, 0x85, 0x59, 0x92, 0xA3, 0xF6,\n\t0x1E, 0x5B, 0xB6, 0x73, 0x9B, 0xFB, 0xD6, 0x2B, 0x6C, 0x60, 0xB0, 0x7F,\n\t0xE6, 0x9C, 0xB6, 0x09, 0x2F, 0xD6, 0x91, 0x64, 0xE5, 0x14, 0x65, 0x98,\n\t0xE2, 0x87, 0x9E, 0x3E, 0x14, 0xD2, 0x69, 0x5B, 0x3E, 0x5C, 0x0E, 0xC1,\n\t0x3F, 0x6E, 0xF5, 0xE6, 0xB7, 0x3B, 0x02, 0x7D, 0xCC, 0xCD, 0x8B, 0x43,\n\t0xBD, 0x11, 0x37, 0xCB, 0x70, 0x23, 0xA6, 0xCA, 0x34, 0x0A, 0x30, 0x43,\n\t0x40, 0xB7, 0x63, 0x95, 0x7F, 0x11, 0xC5, 0x4F, 0x85, 0x1A, 0x7C, 0x39,\n\t0x71, 0xBC, 0xA2, 0x24, 0x20, 0xA6, 0x12, 0x6F, 0x5A, 0x0C, 0x69, 0x0C,\n\t0x9D, 0x37, 0x01, 0x35, 0xBD, 0x1E, 0x18, 0xE1, 0xE7, 0x18, 0x78, 0xFC,\n\t0xAE, 0xC8, 0x67, 0xF1, 0x1E, 0xB7, 0xB1, 0x4D, 0x79, 0xF1, 0x94, 0xDC,\n\t0x3D, 0x67, 0xA8, 0xB7, 0xDC, 0x26, 0xC4, 0xF8, 0x9A, 0x83, 0xBC, 0x24,\n\t0x3A, 0x0A, 0xB3, 0xF4, 0x46, 0x61, 0x04, 0x2E, 0x03, 0x55, 0x18, 0xC5,\n\t0x28, 0xB5, 0x68, 0x8D, 0x74, 0x51, 0x5A, 0xC6, 0x4D, 0x5F, 0xAA, 0x58,\n\t0x86, 0x99, 0xC9, 0x63, 0x6E, 0xB2, 0xC8, 0x87, 0xE5, 0x36, 0xC1, 0xA3,\n\t0x66, 0xAF, 0x79, 0x77, 0x2C, 0xB9, 0x11, 0xD2, 0x1B, 0xF5, 0x21, 0xFE,\n\t0x21, 0x89, 0x6A, 0xEC, 0x71, 0x83, 0x27, 0x0E, 0xD1, 0x31, 0x6E, 0x24,\n\t0x20, 0x9F, 0x6E, 0x28, 0x95, 0x17, 0x7F, 0x76, 0x15, 0x70, 0xE9, 0x44,\n\t0x22, 0xDD, 0x84, 0x61, 0x10, 0x3F, 0x5C, 0x5B, 0xF6, 0xC6, 0x4C, 0x4E,\n\t0xE3, 0xCF, 0x6C, 0xF5, 0x50, 0x44, 0x29, 0x89, 0x04, 0xED, 0xA9, 0xC1,\n\t0x2F, 0xE2, 0x65, 0x2B, 0x87, 0xCA, 0xD9, 0x9B, 0xFA, 0xAA, 0xE7, 0x5B,\n\t0x87, 0x2B, 0x9C, 0x88, 0x84, 0xA3, 0x27, 0x6B, 0xF9, 0xFE, 0x1E, 0xD3,\n\t0xC7, 0x41, 0x36, 0xFA, 0xC7, 0xDA, 0x46, 0x9E, 0x68, 0xD9, 0x64, 0xF8,\n\t0x11, 0x0D, 0xA3, 0x12, 0x6C, 0x38, 0x97, 0x4D, 0xDE, 0xF9, 0xEE, 0xE3,\n\t0xB5, 0x8F, 0x17, 0x6F, 0x82, 0x65, 0x0F, 0x17, 0x79, 0x3D, 0x97, 0x38,\n\t0x1C, 0x41, 0x73, 0xCA, 0xD9, 0x10, 0xCC, 0xFB, 0xD8, 0xB6, 0x97, 0x90,\n\t0x42, 0x36, 0xAA, 0x9B, 0x45, 0x56, 0x5B, 0x16, 0xF0, 0xA2, 0x3E, 0x36,\n\t0x8E, 0x84, 0x0B, 0x08, 0xB8, 0xC5, 0x9F, 0x53, 0xB6, 0x06, 0xA9, 0x12,\n\t0x75, 0x61, 0xDB, 0x95, 0x26, 0x8F, 0x7C, 0x04, 0x86, 0x1E, 0x6E, 0x27,\n\t0x96, 0xB0, 0x27, 0xA0, 0x1E, 0x20, 0xBD, 0x9F, 0x6E, 0x89, 0x31, 0x8F,\n\t0x87, 0xB1, 0x96, 0x49, 0xB4, 0x8D, 0x0D, 0x7D, 0x87, 0xDC, 0xAF, 0x15,\n\t0xC4, 0xEA, 0x28, 0x47, 0xBA, 0x7A, 0xDF, 0x5F, 0x49, 0xC4, 0xC2, 0xDC,\n\t0xDA, 0xFD, 0x7B, 0xF3, 0xC5, 0x8F, 0x41, 0xFF, 0xE5, 0x1D, 0x96, 0x25,\n\t0xC7, 0x9A, 0x54, 0xC8, 0x02, 0x40, 0x50, 0x7E, 0xCE, 0x37, 0x5C, 0x3C,\n\t0xD5, 0xB4, 0xB4, 0x4B, 0x9C, 0x50, 0x4D, 0xC3, 0xD2, 0x88, 0xE8, 0x6A,\n\t0xDF, 0x18, 0x81, 0xD4, 0x0D, 0x18, 0x6E, 0x1F, 0x69, 0x80, 0x22, 0x29,\n\t0x03, 0xBE, 0xFB, 0x0F, 0x61, 0x98, 0x3F, 0x37, 0x1C, 0x94, 0x87, 0xA8,\n\t0x5E, 0x89, 0x52, 0x2A, 0xBC, 0x88, 0xC7, 0xE6, 0xA9, 0x25, 0xF3, 0x96,\n\t0x72, 0x6E, 0xB6, 0x2F, 0x49, 0x50, 0xE4, 0xEE, 0x85, 0xC2, 0x7E, 0x87,\n\t0xBF, 0x2C, 0x7A, 0x40, 0xFE, 0xBB, 0x34, 0x85, 0xB4, 0xEF, 0x3B, 0xDD,\n\t0xB3, 0x50, 0x03, 0x7F, 0x0A, 0x1B, 0x25, 0x64, 0x23, 0x64, 0x63, 0x46,\n\t0xF0, 0xD8, 0xBB, 0x3F, 0xA3, 0x5C, 0x91, 0x6F, 0xAA, 0x2C, 0x42, 0xF2,\n\t0x7C, 0x43, 0xB7, 0x20, 0xAF, 0x00, 0xB7, 0xD8, 0xA8, 0x13, 0x69, 0x61,\n\t0x2B, 0xC5, 0x8C, 0xDB, 0xE5, 0x1F, 0x17, 0xE7, 0x52, 0xD0, 0xFD, 0x87,\n\t0x0B, 0xE8, 0x62, 0xEA, 0x11, 0x42, 0xDB, 0x14, 0x1F, 0xEA, 0xE2, 0x25,\n\t0x6A, 0xA6, 0x6F, 0x50, 0xDB, 0xB0, 0xC7, 0x7E, 0x5C, 0x58, 0x70, 0xE7,\n\t0x32, 0xA0, 0x04, 0x20, 0x7C, 0xBF, 0x29, 0x74, 0x4D, 0xA7, 0x72, 0x78,\n\t0xF8, 0x34, 0x9D, 0x25, 0xCA, 0x45, 0xE2, 0xF9, 0xDC, 0xD5, 0x6A, 0xD9,\n\t0x39, 0x98, 0x8B, 0x3F, 0xB6, 0x8E, 0x2B, 0x9F, 0xE0, 0x92, 0x75, 0xE2,\n\t0x51, 0xDC, 0xC9, 0x10, 0x73, 0x0A, 0x03, 0x06, 0x8C, 0x7B, 0xA8, 0x09,\n\t0x76, 0x92, 0x70, 0xCE, 0x10, 0xC9, 0x5E, 0xDB, 0xE4, 0x1C, 0x7A, 0x7E,\n\t0x8B, 0x33, 0xD7, 0xEA, 0x55, 0xA5, 0x32, 0xAF, 0xF1, 0x95, 0x1C, 0x23,\n\t0x21, 0xCE, 0x25, 0x06, 0x30, 0xA9, 0x7D, 0xC2, 0x30, 0x17, 0x0D, 0xCC,\n\t0xF0, 0x60, 0x81, 0x50, 0xC8, 0x66, 0xC0, 0x84, 0x35, 0x12, 0x6C, 0xC2,\n\t0xFE, 0x1B, 0xA0, 0xC1, 0x71, 0xFE, 0xA5, 0x65, 0x3B, 0x0D, 0xD5, 0x24,\n\t0xFE, 0x78, 0x36, 0x9A, 0xCD, 0xD5, 0x0A, 0x58, 0x07, 0xFF, 0x1A, 0x63,\n\t0x44, 0x94, 0x2B, 0x78, 0x81, 0x37, 0x23, 0x28, 0x96, 0x37, 0x83, 0x85,\n\t0xEC, 0x3B, 0xA0, 0xBE, 0xA0, 0xCF, 0xB1, 0xEB, 0xB1, 0x63, 0x93, 0xD0,\n\t0xA1, 0xBD, 0xE6, 0xD4, 0xD3, 0xDA, 0x90, 0x13, 0xBF, 0x55, 0x6A, 0x7A,\n\t0x87, 0x55, 0xF0, 0xE1, 0x0F, 0x21, 0x21, 0x5E, 0x8C, 0xFE, 0xA3, 0x35,\n\t0xA9, 0x17, 0x9A, 0x52, 0xE3, 0xEB, 0x30, 0x11, 0x07, 0xA6, 0x0C, 0xF2,\n\t0x5E, 0xE2, 0x91, 0x31, 0xFB, 0x68, 0xFC, 0x82, 0xA2, 0xCC, 0xC0, 0x92,\n\t0x2C, 0x01, 0xB8, 0x58, 0xF4, 0x45, 0xD0, 0x46, 0x58, 0xA6, 0x40, 0x5F,\n\t0x03, 0x3A, 0x28, 0x3E, 0x8D, 0x67, 0xE7, 0xEA, 0xB7, 0xED, 0xBE, 0xBF,\n\t0x21, 0xDA, 0xDB, 0xD2, 0xB7, 0x0A, 0x61, 0x43, 0x88, 0xC8, 0x3B, 0x69,\n\t0x0E, 0x3D, 0x8E, 0xD0, 0x6B, 0xC1, 0xAC, 0x33, 0x81, 0x6B, 0xC5, 0xB3,\n\t0x6E, 0x21, 0x3F, 0xC1, 0x03, 0x94, 0x9C, 0x55, 0x6B, 0x74, 0x33, 0x4E,\n\t0x41, 0x76, 0x7B, 0xB2, 0x47, 0x05, 0xC3, 0x9F, 0xD0, 0x82, 0xA2, 0xB7,\n\t0x9B, 0xE1, 0x86, 0xD0, 0x59, 0x57, 0x25, 0xB0, 0x0A, 0x77, 0x53, 0x2A,\n\t0x0E, 0x27, 0x11, 0xCD, 0xC9, 0xF7, 0x45, 0xFD, 0xDC, 0x49, 0x99, 0xC2,\n\t0xBB, 0xA2, 0x48, 0x5C, 0x01, 0xBE, 0x2F, 0xBE, 0x6C, 0x68, 0xC1, 0x8E,\n\t0x81, 0x10, 0x47, 0xB6, 0x80, 0x70, 0x1D, 0x18, 0x3C, 0xF6, 0x4B, 0xBA,\n\t0x98, 0xB5, 0x13, 0xD8, 0xEF, 0x2A, 0xA4, 0x89, 0xFA, 0xEA, 0xB3, 0x08,\n\t0x72, 0xE2, 0x26, 0x40, 0xD4, 0x19, 0xE4, 0x93, 0xB9, 0xA2, 0x21, 0x47,\n\t0x00, 0x02, 0xCD, 0xD0, 0xA2, 0x89, 0xD7, 0x2F, 0x8D, 0xDA, 0xCF, 0xB2,\n\t0x8B, 0x31, 0x91, 0xA5, 0x5F, 0x5E, 0x09, 0x2F, 0xAF, 0x13, 0x8B, 0x2A,\n\t0x23, 0x86, 0x82, 0xCD, 0x67, 0x9B, 0x46, 0x1D, 0x91, 0xA8, 0x6B, 0x41,\n\t0x32, 0x1A, 0x8F, 0x8A, 0x53, 0xD1, 0x05, 0xB2, 0x02, 0x09, 0xC8, 0x88,\n\t0xBB, 0xF6, 0x15, 0xF2, 0xF9, 0xD5, 0xC3, 0x64, 0x7F, 0x5D, 0x2F, 0xCC,\n\t0xA7, 0xD6, 0x03, 0xCD, 0x6A, 0x6B, 0xDA, 0xA3, 0xC5, 0x07, 0xA4, 0x8E,\n\t0x53, 0x04, 0xFC, 0x8A, 0xFD, 0x12, 0x13, 0x8A, 0x7D, 0x41, 0x6D, 0x4A,\n\t0xF1, 0x43, 0xC7, 0xC9, 0xF5, 0xDB, 0x8A, 0xE1, 0x43, 0xAD, 0xB8, 0xA4,\n\t0x51, 0xCA, 0x7A, 0x12, 0x8B, 0x02, 0x47, 0x1F, 0x54, 0x8B, 0x1A, 0x8C,\n\t0x27, 0x9F, 0xE4, 0x22, 0xE2, 0x1D, 0x8C, 0x04, 0x23, 0x21, 0x84, 0xFA,\n\t0x68, 0xB6, 0x8A, 0xE9, 0xC2, 0xB2, 0x98, 0xDE, 0x41, 0x0C, 0x17, 0x5A,\n\t0xEF, 0x2F, 0xB3, 0x74, 0x02, 0x0B, 0xDC, 0x4B, 0xC8, 0xE9, 0xDE, 0xE2,\n\t0x94, 0xE5, 0x62, 0x2D, 0x59, 0x63, 0x74, 0x10, 0xBE, 0xDA, 0x36, 0xD9,\n\t0x2A, 0x14, 0x22, 0xD0, 0x25, 0x1F, 0xEE, 0xC4, 0x45, 0x28, 0xD1, 0x34,\n\t0x02, 0xF8, 0xFA, 0xDC, 0xE0, 0xF2, 0xB5, 0xA3, 0xB1, 0xAC, 0xB6, 0xE1,\n\t0xA6, 0x4C, 0x90, 0x76, 0xF4, 0xFB, 0xEC, 0x83, 0x45, 0xEF, 0xE5, 0xEC,\n\t0x0C, 0xDE, 0xE6, 0xAD, 0xB5, 0x85, 0x68, 0xDB, 0x63, 0xE6, 0x32, 0x6E,\n\t0xE1, 0x2C, 0xE8, 0xF0, 0x52, 0xC4, 0xB9, 0xB7, 0x13, 0x7D, 0xE8, 0x5F,\n\t0x9D, 0x74, 0xE1, 0x1C, 0x06, 0x3B, 0x49, 0x58, 0x0C, 0x17, 0x19, 0x75,\n\t0xB1, 0x96, 0x9D, 0xCF, 0x09, 0x9A, 0xFC, 0xD8, 0x45, 0x70, 0x48, 0x96,\n\t0x15, 0x69, 0xBD, 0xAC, 0x7D, 0x79, 0xD3, 0x52, 0xE7, 0xED, 0xC4, 0x33,\n\t0x5E, 0x26, 0x82, 0x89, 0xAA, 0x71, 0x53, 0xFE, 0x0B, 0x12, 0x84, 0x81,\n\t0x94, 0x6B, 0x45, 0x47, 0x32, 0x8C, 0x7B, 0xFC, 0x56, 0xD1, 0xEC, 0xFD,\n\t0x1F, 0x9D, 0x16, 0x5A, 0x84, 0xDC, 0xE0, 0xA9, 0x3C, 0x9D, 0x34, 0x11,\n\t0xBE, 0x16, 0x02, 0x90, 0x38, 0x3F, 0x5B, 0x85, 0x1D, 0x4E, 0x99, 0x46,\n\t0x24, 0x51, 0x32, 0x5F, 0xF2, 0x35, 0xB3, 0xC9, 0x4A, 0x58, 0x5D, 0x3A,\n\t0x0E, 0xEA, 0xC8, 0x0C, 0xED, 0xF6, 0x67, 0x0C, 0xAF, 0xD8, 0x42, 0x0C,\n\t0xEC, 0xAF, 0x72, 0x86, 0x28, 0x2A, 0x41, 0xAE, 0xED, 0xA2, 0x0A, 0x53,\n\t0x7C, 0xE7, 0x04, 0xA5, 0x28, 0x6E, 0x90, 0xAF, 0xF4, 0x02, 0x79, 0x3D,\n\t0x3A, 0x58, 0xB9, 0x33, 0x3A, 0x56, 0x7E, 0x79, 0xDB, 0x17, 0x42, 0xB1,\n\t0x85, 0xBB, 0xD1, 0x1C, 0xC7, 0x92, 0x0B, 0x04, 0x5C, 0xF9, 0x4B, 0xF6,\n\t0x94, 0x2B, 0x53, 0x30, 0xD4, 0x33, 0x5E, 0x35, 0x7B, 0x1B, 0x26, 0x22,\n\t0xCD, 0x16, 0xAE, 0x2D, 0xC6, 0x4E, 0x7A, 0xC3, 0xC5, 0xF8, 0x46, 0x51,\n\t0x28, 0xB2, 0xA7, 0x39, 0x4E, 0x80, 0xBD, 0x66, 0x2B, 0xD8, 0xDB, 0xAC,\n\t0x41, 0x50, 0xED, 0xDE, 0xD8, 0xB5, 0xFF, 0xCC, 0xF4, 0x2C, 0x90, 0x99,\n\t0xD8, 0x90, 0x65, 0xD6, 0x46, 0xCC, 0x9C, 0xC5, 0x7B, 0x0A, 0x1B, 0x2D,\n\t0xF5, 0x08, 0xDC, 0xF7, 0xE3, 0x23, 0x47, 0x5F, 0x58, 0x56, 0x74, 0x6F,\n\t0xBD, 0x42, 0x92, 0x15, 0x81, 0x0F, 0x75, 0x2C, 0xD2, 0x73, 0xEB, 0xD6,\n\t0x49, 0xDF, 0xB4, 0x44, 0xF0, 0x19, 0xC1, 0x65, 0x6F, 0x3E, 0x85, 0x8B,\n\t0xD2, 0x50, 0xBC, 0xB4, 0xD6, 0xFC, 0x39, 0x83, 0xB8, 0xB2, 0x8D, 0xD1,\n\t0x71, 0x0F, 0x32, 0xE3, 0x22, 0x3C, 0xD8, 0xE6, 0x96, 0xBC, 0xB9, 0xCF,\n\t0xE4, 0xA6, 0x7A, 0x43, 0xCA, 0xA8, 0xB7, 0xB4, 0x3B, 0xB4, 0xAA, 0xA7,\n\t0x5D, 0xEE, 0xB4, 0xD5, 0xDF, 0x6C, 0xE0, 0x80, 0x93, 0x75, 0x12, 0xD5,\n\t0x25, 0xA6, 0x20, 0x49, 0x6E, 0xD2, 0x04, 0x3A, 0xFB, 0x21, 0x5B, 0x5B,\n\t0x90, 0xEB, 0xB8, 0xD3, 0xD0, 0xB2, 0x51, 0xB9, 0xDF, 0xA6, 0x9A, 0xD6,\n\t0x46, 0x48, 0x72, 0x8F, 0x9B, 0x8D, 0x05, 0x7F, 0x99, 0xB0, 0x2E, 0xD4,\n\t0x50, 0x72, 0x97, 0x0F, 0x80, 0x0D, 0x6C, 0x74, 0x6C, 0x41, 0x4C, 0x4D,\n\t0xEE, 0xF4, 0x1F, 0xB3, 0xA7, 0x94, 0xB9, 0x65, 0xF2, 0xA3, 0x90, 0xAB,\n\t0x99, 0xD5, 0xEF, 0x1B, 0xD5, 0xD7, 0xE4, 0xC6, 0x2A, 0x73, 0x67, 0x47,\n\t0xFA, 0x92, 0xD2, 0x56, 0x1A, 0xF8, 0x1B, 0xFF, 0xB5, 0x39, 0x70, 0x06,\n\t0xC7, 0xE9, 0xE4, 0x16, 0x62, 0xEC, 0x56, 0x29, 0x79, 0xC1, 0x38, 0x17,\n\t0x8B, 0x14, 0x6C, 0xE9, 0x99, 0x08, 0xF6, 0xBC, 0xFE, 0xEF, 0x61, 0x55,\n\t0x51, 0x99, 0x9B, 0xC4, 0x7B, 0x71, 0xC5, 0xF5, 0xE0, 0x2D, 0xDA, 0xB5,\n\t0xD1, 0xCD, 0x00, 0x2E, 0xFF, 0xA0, 0xDF, 0xBB, 0xC7, 0x0A, 0xBB, 0x37,\n\t0x36, 0xEF, 0xDD, 0xE5, 0x51, 0xC7, 0x73, 0xC0, 0x35, 0xD2, 0x05, 0x89,\n\t0x3D, 0x61, 0x79, 0xD9, 0xD5, 0x9C, 0xD8, 0xA1, 0xE8, 0x43, 0x4F, 0x91,\n\t0xD4, 0xF3, 0x8F, 0x32, 0x2F, 0x42, 0xF9, 0xA5, 0x84, 0x0B, 0x23, 0xEC,\n\t0xC3, 0x69, 0x1A, 0xE7, 0xCB, 0x9F, 0x44, 0xD9, 0x7B, 0xAD, 0x7B, 0x6F,\n\t0x48, 0x55, 0xCE, 0x21, 0x0E, 0x73, 0x59, 0xD6, 0x28, 0xA3, 0xE8, 0x67,\n\t0xA7, 0x55, 0xEC, 0xE3, 0x39, 0xAF, 0x8A, 0x0E, 0x9F, 0x2E, 0xDF, 0x9E,\n\t0xBC, 0x40, 0x0C, 0x4C, 0x92, 0x70, 0xB6, 0x68, 0xD5, 0x59, 0xAB, 0x5E,\n\t0xF4, 0x6F, 0x9D, 0xB5, 0xE7, 0x52, 0x73, 0xAC, 0xE9, 0x39, 0x3A, 0x9E,\n\t0xD4, 0x98, 0xB7, 0x22, 0x01, 0x46, 0x83, 0x9A, 0xA4, 0x62, 0x0C, 0xA8,\n\t0x80, 0x22, 0xF7, 0x93, 0x40, 0x10, 0x23, 0x53, 0x04, 0xB1, 0x00, 0x51,\n\t0xA7, 0xFF, 0x84, 0x1C, 0x47, 0x3C, 0xEF, 0xEE, 0x65, 0xB1, 0xBC, 0x04,\n\t0xEC, 0xB9, 0x20, 0x24, 0xD5, 0x1B, 0x9A, 0xAE, 0x36, 0x0F, 0x0D, 0x6A,\n\t0x4D, 0x0A, 0x31, 0x91, 0xD1, 0x1C, 0x05, 0x4C, 0x3A, 0x20, 0xA7, 0xC1,\n\t0x8C, 0xD3, 0xF6, 0xC6, 0xBB, 0x82, 0xD1, 0x48, 0xF2, 0x06, 0x8D, 0x28,\n\t0xC8, 0xE9, 0x6C, 0xAB, 0xB7, 0xD1, 0x9D, 0x72, 0x92, 0xA0, 0xC7, 0x09,\n\t0x81, 0x7B, 0x6A, 0x2A, 0xF7, 0xE5, 0x88, 0xE9, 0xEF, 0x82, 0xD3, 0xEC,\n\t0x0B, 0xAA, 0x77, 0x4E, 0x32, 0xFF, 0x50, 0x47, 0xEA, 0x81, 0x49, 0xAA,\n\t0x81, 0xD5, 0x7E, 0x7B, 0x41, 0xED, 0x99, 0x4B, 0xCB, 0x9A, 0x2F, 0x9C,\n\t0xFE, 0x86, 0x98, 0x5E, 0xB3, 0x4A, 0x81, 0xFE, 0x66, 0xFA, 0xCF, 0x40,\n\t0x77, 0xBE, 0xE2, 0x90, 0xD5, 0xB9, 0xA2, 0x0E, 0xDD, 0xB0, 0x3C, 0xB9,\n\t0xCE, 0xE0, 0xC0, 0xA3, 0xA4, 0x09, 0xA2, 0x06, 0xB5, 0x31, 0x46, 0xF6,\n\t0x9E, 0x3E, 0x33, 0xB0, 0x1A, 0x71, 0xDD, 0x6A, 0x36, 0x1D, 0x2A, 0x23,\n\t0x18, 0x9F, 0xAD, 0x67, 0x5A, 0x9F, 0x94, 0x0C, 0xA0, 0xB4, 0x19, 0xA7,\n\t0x68, 0xF6, 0xEE, 0x76, 0x5B, 0xBC, 0xC1, 0x9C, 0x4D, 0x02, 0xB9, 0x74,\n\t0xC5, 0x32, 0xC4, 0x82, 0xE7, 0x71, 0xA1, 0x73, 0x8A, 0xCD, 0xAC, 0x8C,\n\t0x86, 0xF6, 0x41, 0xB6, 0xAD, 0x89, 0xFB, 0x02, 0x29, 0xAB, 0xE3, 0xE0,\n\t0x90, 0x6B, 0x1A, 0xE1, 0xF4, 0xDA, 0xFD, 0x1C, 0xAE, 0x8B, 0x51, 0x23,\n\t0x8C, 0x10, 0x0B, 0xD7, 0x50, 0xFB, 0x95, 0x08, 0xC1, 0x3E, 0x70, 0x56,\n\t0xFE, 0x0D, 0x49, 0xC7, 0x93, 0x99, 0xC5, 0x9A, 0xF7, 0x55, 0xC8, 0xEB,\n\t0x28, 0xDF, 0x57, 0x3C, 0x8B, 0x23, 0x1B, 0x29, 0xA2, 0x98, 0x33, 0xEC,\n\t0xF9, 0x7B, 0xE4, 0x1B, 0xEA, 0x2E, 0xAB, 0x31, 0xC2, 0xBB, 0x8B, 0x1D,\n\t0x6C, 0x6D, 0x47, 0x2A, 0xBA, 0xFD, 0xF8, 0x9E, 0x48, 0x86, 0x24, 0x73,\n\t0x0D, 0x61, 0x14, 0xEE, 0x19, 0x56, 0x2F, 0xC5, 0xC2, 0x02, 0x2A, 0x5E,\n\t0xC5, 0xAC, 0x64, 0xBF, 0xF8, 0xAF, 0xB4, 0x43, 0xB6, 0x3D, 0xAC, 0xFB,\n\t0x29, 0x25, 0x56, 0x3A, 0x16, 0x5B, 0x7C, 0x70, 0x27, 0x2C, 0xA6, 0xB8,\n\t0x5C, 0x59, 0x3B, 0xDC, 0x89, 0x41, 0xE3, 0x32, 0x30, 0x9C, 0x50, 0xEB,\n\t0xF3, 0xC1, 0x11, 0xD6, 0x0B, 0xF3, 0x6C, 0xC0, 0x38, 0xE8, 0x57, 0x20,\n\t0x99, 0xC6, 0x66, 0x52, 0xA6, 0xEB, 0x70, 0xF2, 0xE5, 0xE9, 0x3A, 0xE4,\n\t0x8E, 0x99, 0xEA, 0xC4, 0x4D, 0x67, 0x69, 0xEE, 0xF1, 0xEE, 0x79, 0x02,\n\t0x6B, 0xBC, 0xEF, 0xA9, 0x54, 0x99, 0x43, 0xF2, 0x2F, 0xB7, 0xD5, 0x0E,\n\t0xF3, 0x18, 0x4A, 0x67, 0xCD, 0xEE, 0x86, 0x67, 0x18, 0xA1, 0x30, 0x5A,\n\t0xFB, 0x08, 0xA3, 0x99, 0x93, 0xD6, 0x70, 0x4C, 0x0A, 0x3C, 0xC0, 0x5B,\n\t0x45, 0x06, 0xD3, 0x88, 0x5F, 0x37, 0xC5, 0x43, 0x7D, 0x8A, 0x3B, 0xC1,\n\t0x50, 0xEA, 0x94, 0x45, 0xE8, 0x25, 0x9E, 0xE3, 0xDE, 0xC1, 0x82, 0xA9,\n\t0x69, 0xD2, 0x72, 0x16, 0xAD, 0x29, 0x3A, 0x8D, 0xF8, 0xAD, 0x48, 0x81,\n\t0x15, 0xF9, 0xE8, 0x28, 0xB9, 0x3D, 0x75, 0x7A, 0x89, 0x67, 0x62, 0x6A,\n\t0x13, 0x6E, 0x06, 0x64, 0x97, 0xBE, 0x50, 0x33, 0xCD, 0xAC, 0x87, 0xAD,\n\t0xA8, 0xE0, 0x06, 0xAC, 0x22, 0x50, 0x04, 0x9A, 0x72, 0xED, 0xBE, 0xE3,\n\t0x31, 0x3B, 0x43, 0x59, 0x33, 0xEF, 0xF7, 0x8B, 0x15, 0xDD, 0xE9, 0xAC,\n\t0x4D, 0xAE, 0xAC, 0x86, 0x19, 0x9C, 0xA4, 0xD9, 0xDE, 0x9B, 0x81, 0x44,\n\t0x25, 0xA1, 0x76, 0x2F, 0x80, 0xF6, 0x63, 0x71, 0xE0, 0x33, 0x41, 0x5D,\n\t0xE6, 0x02, 0x3F, 0x7A, 0x4B, 0xFE, 0xB6, 0x83, 0xB2, 0x19, 0x66, 0xAF,\n\t0x6D, 0x8D, 0x71, 0x63, 0xE2, 0x80, 0x8A, 0x68, 0xB5, 0x57, 0x14, 0x09,\n\t0x75, 0x80, 0x0D, 0x98, 0xD8, 0xB1, 0x32, 0xED, 0xCE, 0xE7, 0x62, 0x95,\n\t0x6B, 0x40, 0x69, 0x96, 0x99, 0x8F, 0xF8, 0x55, 0xE1, 0x5D, 0xDC, 0x82,\n\t0xB9, 0xEB, 0xB8, 0xB4, 0x29, 0x10, 0x44, 0x77, 0x93, 0xCD, 0x41, 0x6A,\n\t0xF3, 0x02, 0xC6, 0x94, 0x91, 0x9B, 0x79, 0x7B, 0x72, 0x6E, 0x9A, 0xC0,\n\t0xB9, 0xBD, 0xD1, 0x94, 0x20, 0xF2, 0x79, 0x13, 0x66, 0x1B, 0x68, 0x3B,\n\t0xF3, 0x67, 0xE6, 0x3B, 0xBE, 0xB8, 0xD9, 0x85, 0x1C, 0xB7, 0x2D, 0xB8,\n\t0x54, 0xAE, 0x9C, 0x6C, 0x42, 0xA1, 0xB1, 0x45, 0x03, 0x70, 0x15, 0x19,\n\t0x17, 0xDE, 0x42, 0x6D, 0x32, 0x7A, 0xEF, 0x4A, 0xE5, 0xEC, 0x6C, 0xA6,\n\t0xFC, 0x98, 0x15, 0xE1, 0xB4, 0x1D, 0xFA, 0x87, 0xA0, 0xC7, 0x49, 0xEC,\n\t0x97, 0x84, 0xC6, 0x6B, 0x85, 0xDD, 0xD6, 0xDA, 0x3E, 0xD9, 0x02, 0x63,\n\t0xE8, 0xF7, 0x7B, 0x54, 0xCC, 0x3C, 0x62, 0xED, 0x30, 0x77, 0x7A, 0x5C,\n\t0xE8, 0x26, 0xA9, 0xC5, 0x18, 0xF0, 0x28, 0xC0, 0x3E, 0xF1, 0x0C, 0x3D,\n\t0x66, 0x1C, 0x40, 0x79, 0xEE, 0x4F, 0x5E, 0xA7, 0xE1, 0xA0, 0x4E, 0xBF,\n\t0x81, 0xBE, 0x8F, 0x59, 0xB6, 0xDD, 0x2F, 0xD7, 0x66, 0x8D, 0x45, 0xE9,\n\t0x03, 0xDF, 0x41, 0x86, 0x46, 0x58, 0x26, 0xE4, 0xE8, 0x6D, 0xFD, 0xB9,\n\t0xD6, 0xB9, 0xD1, 0x31, 0xD8, 0xC1, 0xCC, 0x23, 0x45, 0xB1, 0x08, 0x9A,\n\t0xB0, 0xA6, 0x0C, 0xE7, 0xB6, 0x2F, 0x2B, 0xC9, 0x08, 0xCC, 0xC5, 0x9E,\n\t0x32, 0x92, 0xA2, 0xE7, 0x27, 0x86, 0xFD, 0x6E, 0x42, 0x80, 0xC0, 0xFD,\n\t0xC8, 0x87, 0xAA, 0x30, 0x30, 0x9E, 0x58, 0x46, 0x08, 0xA2, 0x40, 0xD7,\n\t0x7B, 0xE2, 0xCF, 0x00, 0x46, 0x02, 0x64, 0x42, 0x36, 0x72, 0x0E, 0x61,\n\t0xE0, 0xC5, 0x10, 0x04, 0x99, 0x9B, 0xB5, 0xED, 0x0C, 0x70, 0x8C, 0xEA,\n\t0x72, 0x38, 0x99, 0x37, 0xD8, 0xE0, 0x51, 0xF1, 0x30, 0xA3, 0x44, 0xED,\n\t0x4B, 0x7C, 0x9B, 0x9C, 0xA8, 0xAC, 0x6C, 0x63, 0xD8, 0xB9, 0x2C, 0x0F,\n\t0xA3, 0xBA, 0xA5, 0xDD, 0x54, 0x0C, 0x13, 0xA8, 0xBF, 0xF1, 0x38, 0x50,\n\t0xCF, 0xAE, 0xA1, 0xC5, 0xBD, 0x1E, 0x8E, 0xE1, 0xE5, 0xC0, 0xAA, 0x93,\n\t0x6C, 0xC5, 0xB1, 0xB9, 0xC9, 0x69, 0xBC, 0xA7, 0xC6, 0xAA, 0xE0, 0x95,\n\t0xC5, 0xCE, 0xAD, 0x36, 0x19, 0xAF, 0x39, 0x2F, 0xE7, 0xDA, 0xCF, 0x83,\n\t0x99, 0x22, 0x91, 0x73, 0xD1, 0x69, 0xDF, 0x28, 0x3E, 0x44, 0x6C, 0x3D,\n\t0x05, 0xB2, 0x3C, 0x1A, 0x69, 0x29, 0x54, 0x9A, 0x25, 0x3C, 0x7B, 0x81,\n\t0x19, 0xBF, 0x7F, 0xF7, 0xFC, 0x74, 0xD7, 0xFD, 0xBF, 0x7F, 0x9A, 0x6B,\n\t0x8A, 0x04, 0xE2, 0xE0, 0x9E, 0x23, 0x13, 0x63, 0xC6, 0x64, 0xFB, 0x85,\n\t0x0E, 0xDA, 0x2D, 0xC9, 0x32, 0x58, 0xD1, 0x30, 0x64, 0xFA, 0x49, 0xD7,\n\t0x54, 0x21, 0x1B, 0xDF, 0x25, 0x33, 0x00, 0xFB, 0xDC, 0x5B, 0x49, 0xC1,\n\t0x57, 0x12, 0xDB, 0xEE, 0xFA, 0xEB, 0x80, 0x0F, 0xBF, 0xD8, 0xF3, 0xB2,\n\t0x33, 0xE6, 0xF7, 0x1F, 0xD7, 0x3E, 0x97, 0x69, 0x8E, 0xF1, 0x07, 0xB1,\n\t0x0B, 0x37, 0xC1, 0xCD, 0x5D, 0xCE, 0x93, 0x43, 0x87, 0xE7, 0x75, 0x1B,\n\t0x77, 0x43, 0xED, 0x73, 0x0B, 0x5A, 0x17, 0x55, 0xB7, 0xA2, 0xD5, 0x56,\n\t0xE8, 0xFA, 0xC8, 0x96, 0xB1, 0x41, 0x6E, 0x8B, 0xB1, 0x39, 0x5F, 0xD6,\n\t0x6C, 0x89, 0x1D, 0x9E, 0x8F, 0x11, 0xBB, 0x3F, 0x0F, 0xD4, 0x27, 0xA7,\n\t0x8C, 0x08, 0xF2, 0xF0, 0x95, 0x14, 0xF8, 0x3D, 0xBC, 0x39, 0xF2, 0xBA,\n\t0xEE, 0x3C, 0x39, 0xB6, 0x7A, 0xE0, 0x7B, 0x0E, 0xF0, 0x4D, 0x24, 0x13,\n\t0x98, 0xFB, 0x76, 0x9D, 0x4C, 0x94, 0xB1, 0xE0, 0xAF, 0xC3, 0x15, 0x18,\n\t0xFA, 0x77, 0x26, 0x01, 0xB4, 0x64, 0x02, 0xE5, 0xCA, 0x80, 0x5A, 0x5F,\n\t0xC2, 0x59, 0x2C, 0x84, 0x6B, 0x20, 0x48, 0xA6, 0xB4, 0x08, 0xAB, 0x51,\n\t0x7A, 0xF4, 0x78, 0xEC, 0x37, 0xB7, 0x3E, 0xAC, 0x6A, 0x6B, 0x9B, 0x36,\n\t0x2F, 0x91, 0x98, 0xD4, 0xC9, 0xC1, 0x69, 0xC2, 0xB5, 0x4F, 0xB0, 0x88,\n\t0x08, 0xFB, 0x71, 0xD9, 0x51, 0x0C, 0x08, 0x7F, 0x1F, 0x66, 0x9E, 0xDA,\n\t0xC5, 0xA5, 0x26, 0x6A, 0x86, 0x6C, 0xBA, 0xA7, 0xC8, 0x5A, 0x4F, 0x8E,\n\t0x50, 0x3B, 0xE1, 0xB7, 0x68, 0xBA, 0x34, 0x36, 0x54, 0x56, 0x10, 0xEA,\n\t0x1A, 0x7C, 0x9E, 0xA9, 0xBD, 0x16, 0x3B, 0x39, 0xA0, 0x7B, 0x6E, 0xD3,\n\t0xA4, 0xF3, 0xC9, 0x87, 0x0D, 0xD0, 0x11, 0xE7, 0x9F, 0x95, 0xAA, 0x2E,\n\t0x66, 0xF7, 0x06, 0xF3, 0x43, 0xC0, 0x29, 0x15, 0xCF, 0xEA, 0xC8, 0x8D,\n\t0x21, 0x23, 0x8D, 0x5D, 0x64, 0x1C, 0xBF, 0xEA, 0x4B, 0x2C, 0xDC, 0x1A,\n\t0x44, 0x94, 0x10, 0x30, 0xE4, 0x6F, 0x20, 0xFA, 0x5E, 0x41, 0x8D, 0x49,\n\t0xE4, 0x8F, 0x25, 0xA0, 0x1B, 0x3E, 0x02, 0x98, 0x84, 0xC6, 0x62, 0xF7,\n\t0xD6, 0xC1, 0x16, 0x13, 0x39, 0xB3, 0xC4, 0x3A, 0xB4, 0xBC, 0xA6, 0x9B,\n\t0x27, 0x0A, 0x1C, 0x6A, 0x4F, 0x4F, 0x01, 0xEB, 0x38, 0x3C, 0xCD, 0xAD,\n\t0x6B, 0x53, 0xC4, 0xBE, 0xB4, 0xEE, 0x41, 0x8F, 0x69, 0xD7, 0x02, 0xB3,\n\t0x75, 0x08, 0x96, 0xC6, 0xB3, 0xB6, 0xC4, 0x88, 0xA9, 0x58, 0xD1, 0xE4,\n\t0x4C, 0x8A, 0x39, 0x83, 0x79, 0xEF, 0x02, 0x2C, 0x2F, 0xF5, 0x43, 0x2D,\n\t0x35, 0xAE, 0x27, 0x93, 0xF3, 0x6D, 0x46, 0x22, 0x66, 0xC5, 0x55, 0x71,\n\t0x8C, 0x68, 0xA8, 0xE6, 0x16, 0x94, 0xDB, 0xBA, 0x51, 0x90, 0x59, 0xBC,\n\t0x77, 0x45, 0xE4, 0xBE, 0x82, 0x21, 0x6C, 0x3A, 0x73, 0x93, 0xCF, 0x7E,\n\t0xC5, 0xC5, 0x64, 0x2C, 0x47, 0x93, 0x27, 0x1F, 0x7B, 0xED, 0x55, 0x16,\n\t0xC1, 0x6D, 0x89, 0x0F, 0xC5, 0x09, 0xD8, 0x44, 0xB4, 0x4F, 0x01, 0xA8,\n\t0x5A, 0x2B, 0xEF, 0xF5, 0x84, 0x11, 0x8E, 0x45, 0xD7, 0x96, 0x9A, 0x6F,\n\t0x60, 0x5A, 0x30, 0x42, 0x78, 0x66, 0xC3, 0x57, 0x88, 0x25, 0x8B, 0xF3,\n\t0xEA, 0xDA, 0xAA, 0xF4, 0xBD, 0x5C, 0x9D, 0xB2, 0x81, 0xE0, 0x88, 0x78,\n\t0xCB, 0x4D, 0xC2, 0xFB, 0x1B, 0xDD, 0x79, 0x5F, 0xBD, 0x08, 0x2F, 0x79,\n\t0x91, 0xAB, 0x62, 0xC3, 0xED, 0x72, 0xA5, 0xD2, 0x61, 0xE4, 0x08, 0xE2,\n\t0x6D, 0x48, 0xD7, 0xD7, 0x65, 0x0A, 0xB1, 0xB5, 0x06, 0xCD, 0x9A, 0x36,\n\t0x51, 0x92, 0x03, 0x46, 0x55, 0x2E, 0x24, 0x94, 0x0C, 0x44, 0x35, 0x28,\n\t0xC4, 0x0F, 0xC2, 0xF5, 0xB3, 0xB4, 0x2D, 0x5D, 0x16, 0xF0, 0x27, 0x87,\n\t0xC7, 0xA5, 0x48, 0x0B, 0x9A, 0x93, 0x69, 0x0B, 0x8E, 0xCF, 0xF6, 0xBF,\n\t0xE4, 0x67, 0x8F, 0x4A, 0x63, 0x9E, 0x6C, 0x74, 0x4A, 0x1F, 0xAD, 0x21,\n\t0xFE, 0x51, 0xD7, 0x6A, 0x65, 0x9F, 0x31, 0x6B, 0x34, 0x72, 0x18, 0xBF,\n\t0x09, 0x37, 0x09, 0x7F, 0x4C, 0x63, 0x79, 0xD4, 0x5C, 0x57, 0xF2, 0x71,\n\t0xD1, 0x8B, 0xBD, 0xC0, 0x35, 0xB8, 0xA4, 0x25, 0x80, 0xFF, 0x7D, 0x16,\n\t0x52, 0x0F, 0x0E, 0x14, 0xCE, 0x4F, 0xF8, 0xCB, 0x9C, 0x50, 0xD4, 0x17,\n\t0x8A, 0x7F, 0x4C, 0x9F, 0x82, 0x40, 0x61, 0x28, 0x95, 0xB2, 0x1A, 0x63,\n\t0x30, 0xC3, 0x5B, 0x6C, 0x3A, 0xDB, 0x5F, 0xEC, 0x5F, 0x30, 0xF0, 0x81,\n\t0x05, 0xFC, 0xFD, 0xE8, 0x7D, 0x3A, 0xFF, 0xBB, 0xF7, 0x53, 0x91, 0x44,\n\t0x27, 0x05, 0x1E, 0x4E, 0x34, 0xDF, 0x03, 0x25, 0x09, 0x71, 0x53, 0x9A,\n\t0x70, 0xE3, 0xAC, 0x34, 0x12, 0x7A, 0xC3, 0xB9, 0xC2, 0x1C, 0x48, 0x68,\n\t0x39, 0x88, 0x71, 0x26, 0x44, 0xE9, 0x98, 0x69, 0xE6, 0x6F, 0x5C, 0x56,\n\t0x97, 0xAA, 0xD0, 0x5D, 0xC0, 0xAA, 0x95, 0xEC, 0x0D, 0xC1, 0x65, 0xB1,\n\t0xEA, 0x69, 0x66, 0xC4, 0xBA, 0x0A, 0x9F, 0xEA, 0x64, 0xB9, 0xF3, 0xFB,\n\t0x1F, 0x26, 0xDB, 0x9F, 0xD7, 0x02, 0x9E, 0x42, 0x33, 0xEB, 0x56, 0xAB,\n\t0x1D, 0xB5, 0xFB, 0xC5, 0x6D, 0x20, 0x98, 0xA4, 0x3E, 0xE7, 0xE5, 0xC1,\n\t0x3C, 0xB1, 0x05, 0xA0, 0x25, 0x1A, 0x1E, 0x28, 0x6D, 0x08, 0xE1, 0xD5,\n\t0xAE, 0x90, 0xEF, 0x6F, 0xFA, 0xB5, 0x42, 0x58, 0xEE, 0xD4, 0xA2, 0x90,\n\t0xA0, 0x65, 0xFC, 0xCA, 0xA2, 0x64, 0x00, 0xB7, 0x69, 0x72, 0xEF, 0xFD,\n\t0x2A, 0x44, 0xF5, 0xAF, 0x64, 0x80, 0x0F, 0x79, 0x20, 0x9A, 0xB8, 0x6B,\n\t0x7F, 0x9E, 0x0F, 0xB3, 0x18, 0x1A, 0xCC, 0x19, 0x17, 0x2B, 0xB8, 0x2C,\n\t0xCA, 0xA5, 0x8E, 0xC5, 0x1B, 0xB1, 0xEC, 0xF6, 0x9C, 0x3C, 0x20, 0x10,\n\t0x04, 0x6F, 0x35, 0x26, 0x8D, 0x0C, 0x3B, 0xB3, 0x8C, 0x08, 0xE3, 0xDE,\n\t0x2C, 0x09, 0x1E, 0xEB, 0x33, 0x08, 0x38, 0x28, 0xA3, 0x4F, 0x32, 0xD1,\n\t0xDD, 0x1C, 0x51, 0x38, 0x94, 0x07, 0xC0, 0xF8, 0x4C, 0x0E, 0x88, 0x95,\n\t0x6B, 0x24, 0xC3, 0xE3, 0x24, 0xD1, 0xD8, 0xF8, 0xD0, 0xA0, 0x5A, 0xFE,\n\t0xF0, 0x1C, 0xDF, 0x03, 0x62, 0xE1, 0x61, 0xFF, 0x43, 0x19, 0xA6, 0x85,\n\t0x6E, 0xE3, 0xF6, 0xF7, 0x6A, 0xF9, 0x48, 0x42, 0xA2, 0xC5, 0x04, 0xB5,\n\t0x42, 0xC2, 0xFB, 0xC0, 0xF8, 0xC1, 0x60, 0x95, 0xFE, 0x87, 0xA9, 0xE1,\n\t0xBD, 0x05, 0x03, 0xB4, 0xB0, 0xC7, 0x60, 0x7C, 0x1C, 0x62, 0xBC, 0x0B,\n\t0x0C, 0x6D, 0xE3, 0x8E, 0x98, 0x93, 0x2B, 0xF4, 0x75, 0xF8, 0x3F, 0x18,\n\t0xF3, 0x07, 0x62, 0xEE, 0x7E, 0x38, 0x26, 0x76, 0x40, 0xEC, 0x17, 0x93,\n\t0xC2, 0xD1, 0xC5, 0x5A, 0xD9, 0xA3, 0x15, 0x74, 0x3F, 0xF0, 0xA8, 0x54,\n\t0xEA, 0x8C, 0x3A, 0xDF, 0x51, 0xC7, 0xFD, 0xF5, 0xFA, 0x0F, 0x83, 0x9C,\n\t0x58, 0x5D, 0x81, 0x64, 0xFA, 0xED, 0x82, 0x80, 0x1C, 0x5B, 0x36, 0xA5,\n\t0x44, 0x5B, 0x77, 0x91, 0x7E, 0x42, 0x05, 0xF5, 0x33, 0x95, 0xCC, 0xC8,\n\t0x09, 0x96, 0xC3, 0x4D, 0x72, 0x1D, 0xA3, 0x4C, 0x57, 0x40, 0xDA, 0xB8,\n\t0x7E, 0xF8, 0xCF, 0xFA, 0xF0, 0xB7, 0x13, 0xD0, 0xCF, 0x86, 0xAF, 0x60,\n\t0x6F, 0xCE, 0x74, 0x5E, 0xC3, 0xC5, 0x5F, 0xB6, 0x2D, 0x99, 0xBA, 0x2D,\n\t0x68, 0x5C, 0xFA, 0x89, 0x44, 0xFB, 0xDD, 0x58, 0x6D, 0x5F, 0xB9, 0xBE,\n\t0xC6, 0x83, 0xEC, 0xAA, 0x1B, 0x95, 0x66, 0x53, 0xA3, 0x6F, 0xCD, 0x08,\n\t0x58, 0x09, 0xB4, 0x2D, 0xF7, 0x14, 0x31, 0x03, 0xEA, 0xB5, 0x87, 0xE1,\n\t0x87, 0xE5, 0x1F, 0x06, 0x42, 0xAD, 0xE0, 0x1A, 0x76, 0x95, 0x8C, 0x72,\n\t0x8A, 0xDD, 0x41, 0xD5, 0xB3, 0x6D, 0x55, 0x6C, 0xAB, 0x38, 0x0A, 0x0F,\n\t0xE4, 0xC2, 0x08, 0xA6, 0x91, 0xE2, 0x2A, 0x49, 0x29, 0x1F, 0x24, 0x98,\n\t0x6F, 0x43, 0x81, 0xD5, 0x9C, 0x15, 0xE7, 0x7B, 0x14, 0x84, 0x74, 0xC9,\n\t0x92, 0x59, 0xE6, 0xA2, 0xB4, 0xF0, 0xE2, 0x8E, 0x56, 0xA6, 0x8F, 0xB1,\n\t0xAE, 0x8E, 0x83, 0x55, 0xB2, 0x56, 0xB9, 0xCA, 0x17, 0x05, 0x2D, 0x46,\n\t0x3A, 0x6B, 0x32, 0xC2, 0x89, 0x56, 0xFB, 0x65, 0x59, 0x2B, 0xA9, 0x38,\n\t0xD6, 0xE9, 0x51, 0xB8, 0x33, 0x4E, 0x3E, 0x30, 0x41, 0x30, 0x8D, 0x8A,\n\t0xF5, 0x2C, 0xEC, 0xC0, 0xDA, 0xA7, 0x30, 0x24, 0x23, 0x5F, 0x2B, 0x5D,\n\t0xE6, 0x9A, 0x27, 0xF6, 0x91, 0x0A, 0x78, 0x26, 0xFE, 0xA5, 0xA3, 0xFD,\n\t0x81, 0xDB, 0x8D, 0xA8, 0x24, 0xE6, 0xD2, 0xEA, 0xBA, 0xD0, 0xD3, 0x93,\n\t0x29, 0x7A, 0x16, 0xA8, 0x77, 0xD8, 0xE9, 0x56, 0x2C, 0xB8, 0x72, 0x69,\n\t0x65, 0x99, 0x8B, 0x9D, 0x00, 0xA0, 0x0D, 0x81, 0x6C, 0xC2, 0x3A, 0x2F,\n\t0x62, 0x13, 0xC6, 0xFA, 0x5A, 0x1E, 0x97, 0x5B, 0x66, 0xD3, 0xD5, 0xD4,\n\t0x33, 0x0B, 0x47, 0xC0, 0x62, 0x92, 0x7E, 0x8A, 0x31, 0x56, 0xCD, 0x61,\n\t0x5C, 0x98, 0xE8, 0x5F, 0x01, 0x6F, 0xA1, 0x10, 0xB0, 0x90, 0xC4, 0xF0,\n\t0xC5, 0x66, 0x69, 0x62, 0x51, 0x09, 0x57, 0x59, 0x3D, 0x66, 0xFF, 0x9F,\n\t0x7C, 0x0C, 0x48, 0x23, 0x19, 0xCC, 0x5A, 0x73, 0x66, 0x30, 0x95, 0xCB,\n\t0xE8, 0x88, 0xD3, 0xB2, 0x8D, 0xD6, 0x72, 0x8D, 0xDB, 0x33, 0x40, 0x91,\n\t0x77, 0xCD, 0x54, 0x51, 0xAF, 0x8C, 0xBE, 0x63, 0x86, 0x18, 0x01, 0x4D,\n\t0xAF, 0xF7, 0x09, 0xF0, 0xD8, 0x92, 0x33, 0x7A, 0x46, 0x6A, 0x68, 0x4E,\n\t0x4F, 0x64, 0x22, 0xB2, 0xC5, 0x0D, 0x58, 0x66, 0x29, 0xA9, 0x62, 0x14,\n\t0x58, 0x4F, 0x2D, 0xAC, 0xE3, 0x2B, 0xF6, 0x9F, 0x76, 0x26, 0x3F, 0x2C,\n\t0x3B, 0xE0, 0x42, 0x53, 0xED, 0x37, 0x48, 0x51, 0x87, 0x2C, 0x38, 0x3B,\n\t0x27, 0xA9, 0x98, 0xAE, 0xAD, 0xD6, 0xA7, 0x09, 0xCB, 0x14, 0x2A, 0x7A,\n\t0xB7, 0x27, 0x82, 0x6E, 0x0E, 0xA2, 0xA6, 0xB9, 0xEF, 0x61, 0x2D, 0x2A,\n\t0xC6, 0x35, 0xC2, 0x1B, 0xE4, 0xCE, 0x3F, 0x2E, 0x3F, 0x42, 0x18, 0x0D,\n\t0x63, 0xED, 0x9B, 0x60, 0x3E, 0xE8, 0x14, 0x16, 0x0B, 0x21, 0x4C, 0x8E,\n\t0x2E, 0x67, 0x23, 0x07, 0x43, 0xD7, 0xBD, 0xC1, 0x67, 0xD8, 0x65, 0xAE,\n\t0x8F, 0x60, 0xE8, 0x2E, 0x1F, 0x34, 0x92, 0xBA, 0x11, 0x9F, 0xF3, 0xDA,\n\t0x63, 0xC2, 0xD5, 0x28, 0xF0, 0x81, 0x52, 0x5D, 0x4D, 0x3A, 0xFC, 0x1B,\n\t0xED, 0xFD, 0x15, 0x6F, 0xC0, 0xBB, 0xED, 0xFF, 0xAF, 0x20, 0xBE, 0x80,\n\t0xA9, 0xDD, 0xED, 0x41, 0x92, 0x74, 0x32, 0x41, 0xC3, 0x1C, 0x4D, 0x36,\n\t0x36, 0xBC, 0x60, 0x77, 0x61, 0xB5, 0xE1, 0x61, 0x7D, 0xD1, 0x38, 0x20,\n\t0x63, 0x57, 0x1C, 0x9F, 0x86, 0xAC, 0x0E, 0x79, 0xAA, 0x4D, 0x88, 0xCD,\n\t0x2F, 0xCF, 0x4E, 0x03, 0x0E, 0xF3, 0x21, 0x1B, 0xAA, 0x01, 0x88, 0x97,\n\t0x71, 0x86, 0xD6, 0xAB, 0xD3, 0x15, 0x7F, 0xCF, 0x9E, 0xF5, 0xB6, 0x91,\n\t0x84, 0x61, 0xB5, 0xBF, 0xC2, 0x74, 0xC7, 0x33, 0x0F, 0x74, 0x1D, 0xDE,\n\t0xF9, 0x86, 0x69, 0x9C, 0x5B, 0xFB, 0x52, 0xA6, 0xBE, 0xD5, 0xBC, 0xD1,\n\t0xE3, 0x40, 0x05, 0xC6, 0x17, 0x11, 0x87, 0xBE, 0x08, 0xDA, 0xBD, 0x9D,\n\t0xFF, 0x89, 0x3B, 0x63, 0x77, 0xE5, 0xB8, 0x30, 0x41, 0x09, 0x70, 0x79,\n\t0xB1, 0x1E, 0x57, 0x58, 0xD7, 0xEF, 0xEF, 0xD0, 0x8C, 0x63, 0xD2, 0xEA,\n\t0xB1, 0xEA, 0x0A, 0x70, 0x56, 0x92, 0x14, 0xCF, 0xA5, 0x95, 0x5E, 0xFA,\n\t0xEA, 0x0B, 0xA3, 0x1B, 0x76, 0x0E, 0x8C, 0x0A, 0x69, 0x3B, 0x86, 0x78,\n\t0x32, 0xDF, 0x5D, 0x10, 0x23, 0x7E, 0x69, 0xD8, 0x3C, 0x1C, 0xD8, 0x8B,\n\t0x50, 0x95, 0x7B, 0x11, 0x76, 0xFC, 0xB7, 0x1B, 0xDB, 0xF8, 0x8A, 0xBF,\n\t0x76, 0x8E, 0x21, 0xCB, 0x58, 0x39, 0x73, 0x07, 0x78, 0x75, 0x85, 0xD4,\n\t0xEE, 0x60, 0x57, 0xDF, 0xE5, 0xFB, 0xEF, 0x66, 0x38, 0xC6, 0xA6, 0x01,\n\t0xAD, 0x13, 0x5F, 0x16, 0x04, 0x33, 0xDD, 0x9C, 0x21, 0xE1, 0xD4, 0xFD,\n\t0x72, 0x26, 0x0C, 0xA4, 0x2D, 0x22, 0x80, 0x56, 0x24, 0x69, 0x0E, 0xD4,\n\t0x5E, 0xB3, 0x2B, 0x79, 0x6A, 0xE4, 0x9D, 0x70, 0x66, 0xFA, 0x73, 0xA2,\n\t0xDD, 0x90, 0x51, 0x33, 0xB0, 0x0C, 0x4A, 0xAF, 0x0B, 0xDE, 0x62, 0x8B,\n\t0x45, 0x8F, 0xA1, 0x1E, 0xE4, 0xEA, 0xE2, 0x42, 0xAA, 0x43, 0x11, 0xA3,\n\t0x84, 0xE8, 0x7D, 0x91, 0x88, 0x15, 0x72, 0xDD, 0x50, 0x31, 0xA9, 0xA5,\n\t0x17, 0x1B, 0x8C, 0xC8, 0x68, 0x7D, 0xCF, 0x0F, 0xE4, 0x66, 0xFF, 0x63,\n\t0x30, 0xAA, 0x19, 0x4F, 0x50, 0xF6, 0xA4, 0xEC, 0x45, 0xD0, 0x69, 0x5A,\n\t0x22, 0x0A, 0x0F, 0xA6, 0x9C, 0x74, 0x0D, 0x4B, 0x12, 0x14, 0xC0, 0x5B,\n\t0xFB, 0xCE, 0x0D, 0xAD, 0xB1, 0xBD, 0x92, 0x1C, 0x98, 0x80, 0xDA, 0xD1,\n\t0xAE, 0x5D, 0x7C, 0xE6, 0x4B, 0x52, 0x37, 0xDE, 0x70, 0x67, 0x14, 0x04,\n\t0x5C, 0xEF, 0x9D, 0xD3, 0xAF, 0x05, 0x8E, 0xA8, 0x9D, 0x97, 0xDE, 0x9D,\n\t0xD9, 0x19, 0xBE, 0x34, 0x95, 0x4D, 0x02, 0x15, 0x95, 0x79, 0xDD, 0x59,\n\t0x0B, 0x89, 0x60, 0x71, 0xC3, 0x64, 0x40, 0x21, 0x26, 0x90, 0xA6, 0x80,\n\t0xDE, 0x06, 0x91, 0xC7, 0x94, 0x58, 0x11, 0x5C, 0x64, 0x5F, 0xB5, 0x0D,\n\t0x6A, 0x11, 0xE0, 0x54, 0xF0, 0x5C, 0xC8, 0x4D, 0xEA, 0x52, 0x2B, 0xCE,\n\t0x3F, 0x1E, 0xFF, 0x21, 0x1A, 0xAF, 0x28, 0x17, 0x69, 0xC8, 0x8F, 0x1C,\n\t0xC5, 0x72, 0x8A, 0x5C, 0x36, 0xCF, 0x40, 0x68, 0xDE, 0x3D, 0x9F, 0xED,\n\t0x4A, 0x16, 0xCD, 0x5B, 0x54, 0x03, 0xD8, 0x9B, 0x07, 0x36, 0xB2, 0x40,\n\t0xD0, 0x73, 0x6D, 0xCA, 0x6E, 0xEA, 0xAD, 0xA4, 0x90, 0x25, 0xFE, 0x7F,\n\t0xCA, 0x1E, 0xF2, 0xF2, 0xC1, 0xDA, 0xAE, 0x4A, 0x7F, 0x60, 0xE2, 0xE0,\n\t0xE3, 0xD5, 0x69, 0xD3, 0xF9, 0xE1, 0x8F, 0x4F, 0xBB, 0x5F, 0xF6, 0xAA,\n\t0x74, 0x32, 0x69, 0x42, 0x88, 0x6E, 0xB9, 0x22, 0x2D, 0xF6, 0xE2, 0x17,\n\t0xAA, 0xC5, 0x3E, 0x6E, 0xB5, 0x45, 0x05, 0xE5, 0x59, 0x26, 0xAC, 0x94,\n\t0x61, 0x70, 0xFC, 0x72, 0xA3, 0xCE, 0x68, 0x9F, 0xAA, 0x3E, 0xB1, 0x49,\n\t0x7F, 0x02, 0x4C, 0x9B, 0xCA, 0x72, 0xFF, 0x46, 0x46, 0x11, 0xF9, 0x3D,\n\t0x29, 0x43, 0x27, 0xD3, 0x7A, 0x40, 0x5D, 0xFC, 0x52, 0x91, 0xC2, 0xD9,\n\t0x94, 0x16, 0x13, 0xF3, 0x9C, 0xD3, 0x36, 0x1A, 0x0A, 0xD8, 0x5A, 0x50,\n\t0x06, 0xD4, 0xF9, 0xDC, 0x2B, 0x6A, 0xE7, 0x71, 0x33, 0x07, 0xBD, 0xDB,\n\t0x97, 0x6D, 0xB8, 0x23, 0x73, 0x80, 0xF1, 0x17, 0x6C, 0xF5, 0x47, 0x11,\n\t0x68, 0x66, 0xCD, 0x4A, 0x14, 0xDB, 0x76, 0x14, 0xE0, 0x52, 0x8A, 0xB2,\n\t0x6A, 0x18, 0x4E, 0xC7, 0xB5, 0x90, 0xC1, 0x2A, 0xB2, 0xD6, 0xA7, 0xAD,\n\t0x53, 0xBE, 0xA6, 0xDF, 0xCB, 0xC6, 0xC5, 0xF1, 0x4D, 0x76, 0x69, 0xC1,\n\t0x91, 0x0A, 0xA2, 0x86, 0x42, 0xAC, 0xFA, 0xD1, 0x79, 0x35, 0xDB, 0x5F,\n\t0xB8, 0x50, 0xC7, 0x4E, 0xB7, 0xD6, 0x22, 0xD5, 0x1D, 0x1B, 0xCB, 0xE7,\n\t0xCA, 0x21, 0x06, 0x25, 0xB7, 0x73, 0xCE, 0xA2, 0x0D, 0x33, 0xE5, 0xAA,\n\t0xDD, 0x59, 0xB7, 0x9F, 0x89, 0x42, 0xEE, 0xE7, 0xB6, 0x82, 0xDA, 0x36,\n\t0x18, 0x21, 0xC8, 0x89, 0x61, 0x30, 0x0F, 0xD1, 0x8D, 0xE0, 0xF1, 0x8E,\n\t0x9B, 0xE9, 0x16, 0x76, 0x49, 0x77, 0x30, 0x3D, 0x85, 0xE9, 0xDC, 0x52,\n\t0x28, 0x0D, 0x38, 0xEE, 0x2D, 0x7F, 0xBD, 0x08, 0x54, 0x87, 0x71, 0x91,\n\t0x73, 0x30, 0xCC, 0x58, 0xAD, 0x67, 0xDC, 0xF8, 0x12, 0x55, 0xC2, 0x14,\n\t0xBA, 0x15, 0xFA, 0xD2, 0x79, 0xC6, 0xB6, 0x3A, 0x5C, 0x52, 0x10, 0xCE,\n\t0xE9, 0xBC, 0xF6, 0xFA, 0xAA, 0x0E, 0xB3, 0x37, 0x23, 0x1E, 0x16, 0x75,\n\t0x57, 0x62, 0xF5, 0x67, 0x2E, 0xC6, 0x3E, 0x46, 0x17, 0x77, 0xE1, 0x33,\n\t0x85, 0x52, 0x08, 0x82, 0xF6, 0xA4, 0xE1, 0xD8, 0x8E, 0x83, 0xA7, 0x7B,\n\t0xB1, 0xBE, 0x7D, 0x4C, 0xE8, 0x2E, 0x67, 0x58, 0x4C, 0x3E, 0x82, 0x85,\n\t0x78, 0xBB, 0x7C, 0xDA, 0xC9, 0xB0, 0xBF, 0x6B, 0x17, 0x14, 0x8A, 0x0F,\n\t0xB3, 0x76, 0x21, 0xAF, 0x54, 0x9C, 0x35, 0xE1, 0x02, 0x35, 0x3B, 0x85,\n\t0xC6, 0x25, 0x67, 0x43, 0xA5, 0x07, 0x60, 0x81, 0x52, 0x66, 0x57, 0x4C,\n\t0xF2, 0x81, 0x55, 0x9E, 0xED, 0xCF, 0x12, 0x8D, 0x79, 0x02, 0x8A, 0x80,\n\t0xE4, 0xBC, 0x75, 0xCC, 0xE3, 0x61, 0x6B, 0xFA, 0x2F, 0xF0, 0x8A, 0xB7,\n\t0xDD, 0x9E, 0xBD, 0x48, 0xC5, 0x9F, 0x12, 0xCD, 0x32, 0x96, 0x35, 0x1D,\n\t0x87, 0xC1, 0x79, 0xFD, 0xE3, 0x5E, 0x2B, 0x70, 0x65, 0x1B, 0x89, 0x00,\n\t0xA6, 0x82, 0xE0, 0xB6, 0xD1, 0x2C, 0xC6, 0x42, 0xB0, 0x2E, 0x36, 0x79,\n\t0x01, 0x7F, 0xFA, 0xF1, 0x99, 0x33, 0x5D, 0x8B, 0xD6, 0x16, 0xE1, 0x75,\n\t0x70, 0x0A, 0x51, 0xC7, 0xED, 0x1C, 0x23, 0x85, 0xC9, 0xB0, 0x74, 0xFF,\n\t0x47, 0x15, 0x8E, 0xE9, 0x21, 0x80, 0x64, 0x17, 0x96, 0xA1, 0xC6, 0xA1,\n\t0xF2, 0xCD, 0x79, 0xF1, 0x00, 0x3C, 0x14, 0x45, 0xA1, 0x49, 0x12, 0x0E,\n\t0xFD, 0xD9, 0x56, 0x23, 0xA5, 0x58, 0xB2, 0x9B, 0x27, 0xBF, 0x75, 0xFA,\n\t0xC2, 0x14, 0xBB, 0xD9, 0x0E, 0x98, 0x28, 0x59, 0x55, 0xF1, 0xC0, 0xD5,\n\t0x27, 0x62, 0xE6, 0xFE, 0x82, 0x0E, 0xD8, 0xBF, 0xE4, 0xB7, 0x9E, 0x45,\n\t0x74, 0x89, 0x01, 0x35, 0x14, 0x6E, 0xBE, 0x14, 0x44, 0x0B, 0x3A, 0x60,\n\t0x1B, 0x18, 0xF0, 0x18, 0x88, 0xAD, 0x5A, 0xD4, 0xF1, 0xCC, 0x25, 0x74,\n\t0x8F, 0xF4, 0x9E, 0x47, 0x96, 0xB5, 0xC7, 0xFE, 0xCE, 0x62, 0xA3, 0x98,\n\t0xBD, 0x35, 0x55, 0xF5, 0x64, 0x2F, 0x62, 0x97, 0x6C, 0x25, 0x82, 0xC6,\n\t0x3C, 0xCE, 0xD9, 0x16, 0xB9, 0x4F, 0x4C, 0x3A, 0xFB, 0xF9, 0x7F, 0x6C,\n\t0x9A, 0x90, 0x3C, 0x80, 0xB2, 0x86, 0x5B, 0x0B, 0xC9, 0x7B, 0x2A, 0x06,\n\t0xA7, 0xCC, 0xBB, 0xD6, 0x31, 0x9F, 0xDD, 0x0D, 0x76, 0x53, 0xD2, 0x66,\n\t0x7C, 0xE3, 0x0E, 0xE7, 0x0B, 0x18, 0xFF, 0x59, 0x5C, 0xF2, 0xEC, 0x21,\n\t0xDE, 0x6B, 0xF0, 0x5A, 0x36, 0xF9, 0xA3, 0x9A, 0xE7, 0xFB, 0xE8, 0xC0,\n\t0x2D, 0x0B, 0x65, 0x47, 0xC4, 0x25, 0x81, 0x13, 0xFC, 0x0E, 0x41, 0x0E,\n\t0x1B, 0xE1, 0x19, 0x58, 0x06, 0x3E, 0x41, 0xF3, 0xF7, 0x82, 0x84, 0x70,\n\t0x30, 0x93, 0x7F, 0x52, 0x59, 0xC0, 0xF5, 0xDF, 0x06, 0x40, 0xF3, 0xB8,\n\t0x60, 0x60, 0x9F, 0x01, 0x58, 0xFF, 0x9F, 0x1B, 0x88, 0x7B, 0xF9, 0x68,\n\t0x6F, 0xC1, 0x12, 0x30, 0x9C, 0x4B, 0x52, 0x4B, 0x58, 0x82, 0x27, 0xCD,\n\t0x66, 0xE7, 0x58, 0x6C, 0xA1, 0xB9, 0x25, 0x6C, 0x06, 0x02, 0x39, 0xA4,\n\t0x4E, 0xA0, 0xCC, 0x4C, 0x07, 0x76, 0x62, 0x39, 0xB9, 0x28, 0xBD, 0xAE,\n\t0x64, 0x59, 0xEB, 0xCD, 0xFC, 0x64, 0x3A, 0x84, 0x56, 0xDE, 0x9A, 0xB3,\n\t0xE8, 0x06, 0xC3, 0xBA, 0x30, 0xED, 0x4A, 0x01, 0x5B, 0x26, 0xE4, 0xFB,\n\t0xAE, 0x81, 0x8E, 0xFF, 0xF9, 0x75, 0x4A, 0xDE, 0x77, 0xF4, 0xFD, 0x45,\n\t0x93, 0xBE, 0x43, 0x57, 0xE3, 0x87, 0x0F, 0x3A, 0xE9, 0x9A, 0x8A, 0x30,\n\t0x0C, 0xBC, 0x4E, 0x62, 0x89, 0x83, 0x89, 0x93, 0x5F, 0xE1, 0x39, 0x68,\n\t0x9A, 0x04, 0x9E, 0x87, 0xF5, 0xA1, 0x5A, 0x7C, 0x96, 0x22, 0x1F, 0x86,\n\t0x71, 0x9D, 0xCC, 0xB9, 0x4A, 0x7B, 0xF8, 0x19, 0xFF, 0x50, 0x66, 0xDB,\n\t0xE4, 0x26, 0x54, 0xD9, 0xEE, 0x78, 0x00, 0xA0, 0x73, 0x71, 0x10, 0xB5,\n\t0x1A, 0x31, 0x62, 0x22, 0xE7, 0xC6, 0xC2, 0x12, 0x09, 0xDC, 0xB5, 0x05,\n\t0x0A, 0x0F, 0xA1, 0x5D, 0x4A, 0x52, 0x50, 0xB0, 0xB8, 0x47, 0x4F, 0x3D,\n\t0x10, 0xC9, 0x05, 0xEE, 0x22, 0x86, 0xC6, 0x83, 0xD0, 0xAC, 0x28, 0x4D,\n\t0x30, 0xE9, 0xD9, 0xAD, 0x9F, 0xDA, 0xA3, 0x9C, 0xDB, 0xE2, 0x32, 0x64,\n\t0x4A, 0xD6, 0xE8, 0xD3, 0x99, 0x07, 0x8F, 0x17, 0x76, 0x6F, 0x69, 0x93,\n\t0xB4, 0x65, 0x37, 0xE2, 0x5E, 0xC4, 0xCD, 0xC1, 0x5E, 0xE7, 0xB9, 0xFD,\n\t0xD0, 0xEC, 0xCD, 0x9F, 0x99, 0x0B, 0xEE, 0x6B, 0xB3, 0x24, 0x06, 0x0F,\n\t0x99, 0x5E, 0x87, 0x73, 0xAE, 0xA7, 0x4E, 0x56, 0x35, 0x6B, 0xB5, 0x22,\n\t0x38, 0x10, 0x36, 0xEB, 0xCC, 0xF7, 0xDA, 0x84, 0x07, 0x6A, 0x0A, 0xE5,\n\t0xA8, 0x34, 0xB6, 0x5D, 0xDC, 0xB3, 0x0D, 0xBE, 0xC8, 0xB1, 0x3A, 0x7A,\n\t0xA7, 0x96, 0x8B, 0x19, 0xFB, 0x26, 0xD4, 0xE9, 0x43, 0x59, 0x0C, 0x31,\n\t0x92, 0xB7, 0x46, 0xD7, 0xB6, 0x03, 0x56, 0xA7, 0x25, 0x11, 0xA2, 0x37,\n\t0x9E, 0xBC, 0x2B, 0xB7, 0xE6, 0xC5, 0x64, 0xBD, 0x16, 0x56, 0x88, 0x3E,\n\t0xBB, 0x8C, 0x20, 0x63, 0x4F, 0x3C, 0x4C, 0x8A, 0x19, 0x63, 0x4B, 0xAB,\n\t0x0B, 0xF9, 0x6F, 0xDF, 0x62, 0x0B, 0x9D, 0x5B, 0x07, 0x33, 0xC6, 0xFC,\n\t0xAD, 0x8C, 0xAE, 0x03, 0x98, 0x44, 0xDC, 0x34, 0x26, 0x39, 0x99, 0xCB,\n\t0x8C, 0xCC, 0xE9, 0xCE, 0x77, 0x00, 0x09, 0x48, 0xEA, 0xE2, 0xDC, 0x11,\n\t0x1C, 0xE5, 0x20, 0x30, 0xA1, 0x3E, 0xB7, 0x96, 0x19, 0xFA, 0x78, 0x33,\n\t0x79, 0x2B, 0xA8, 0xCC, 0x69, 0x2C, 0x8D, 0x1B, 0x61, 0xF6, 0x3E, 0x68,\n\t0xBF, 0xCF, 0x95, 0xCC, 0x4A, 0x5C, 0x25, 0x92, 0xE9, 0x6F, 0x1D, 0xCB,\n\t0xE8, 0x9F, 0x37, 0x8E, 0x59, 0x1A, 0x72, 0xCC, 0x35, 0x53, 0xFE, 0x4F,\n\t0x50, 0xCA, 0x13, 0x22, 0x32, 0x1D, 0x77, 0x3A, 0xEA, 0x12, 0xE6, 0x8A,\n\t0xF3, 0x31, 0x5B, 0x27, 0x53, 0x32, 0x3F, 0xCB, 0x86, 0x5D, 0xC3, 0xEE,\n\t0xD3, 0x66, 0x19, 0xCF, 0xAE, 0x21, 0xE0, 0x21, 0xD4, 0x97, 0xD7, 0x52,\n\t0x93, 0xB7, 0xDD, 0x67, 0xEC, 0xFA, 0x99, 0x71, 0x07, 0x1C, 0x95, 0x07,\n\t0x70, 0xFA, 0xE5, 0x55, 0x1A, 0xF3, 0xF8, 0x53, 0x48, 0x43, 0x93, 0xAB,\n\t0x0B, 0xA2, 0x4B, 0x08, 0xB4, 0xE3, 0xFC, 0x4F, 0x94, 0xFB, 0x8C, 0xA3,\n\t0x1E, 0x49, 0xF3, 0x90, 0x31, 0xCE, 0x0E, 0x6C, 0x4E, 0x6C, 0x15, 0x74,\n\t0x57, 0x64, 0x35, 0xF6, 0x77, 0x83, 0x6E, 0xB2, 0x8F, 0xFE, 0xA2, 0x31,\n\t0x09, 0xBA, 0x77, 0xBB, 0xBF, 0x03, 0x4E, 0x8D, 0xC9, 0x7E, 0x25, 0xA2,\n\t0x80, 0xEA, 0xBA, 0xB2, 0x7C, 0x11, 0x93, 0xB3, 0x5C, 0xCC, 0x2C, 0xC3,\n\t0x24, 0xBC, 0x51, 0x4F, 0x08, 0xE7, 0x98, 0x87, 0x73, 0x64, 0x7D, 0xE9,\n\t0xA9, 0x18, 0x16, 0x9C, 0x48, 0x12, 0x6E, 0x18, 0x57, 0x20, 0xA9, 0xBD,\n\t0xD0, 0xEE, 0xDD, 0x22, 0xF9, 0xAC, 0xC7, 0x6C, 0xBA, 0x08, 0xAB, 0xA7,\n\t0xFB, 0x7F, 0x1B, 0x03, 0x24, 0x7F, 0xE4, 0x2E, 0x6C, 0x22, 0xBD, 0x5E,\n\t0x7A, 0x36, 0xD5, 0x41, 0x4D, 0x37, 0x4F, 0xDA, 0x86, 0xDA, 0x84, 0x72,\n\t0x45, 0x0D, 0x9E, 0xE4, 0x79, 0xA6, 0x8F, 0xF6, 0x01, 0x1A, 0x6E, 0xFE,\n\t0xC3, 0x3E, 0x9A, 0x02, 0xBD, 0x67, 0x91, 0x6B, 0xF0, 0x32, 0x81, 0xF7,\n\t0x7D, 0xED, 0x63, 0x0B, 0xA2, 0x18, 0x83, 0xE1, 0x7B, 0x08, 0x46, 0x6E,\n\t0xD4, 0x05, 0x77, 0xA1, 0xE1, 0xFF, 0xFE, 0x9D, 0x1A, 0x0E, 0x43, 0x6D,\n\t0x0E, 0xFE, 0x30, 0x75, 0x92, 0x91, 0x8A, 0xFD, 0xD5, 0x57, 0xAD, 0xD4,\n\t0x4E, 0x3A, 0x6B, 0xBF, 0x0F, 0x32, 0x2B, 0xAF, 0x65, 0x8E, 0xED, 0xC3,\n\t0xD0, 0xED, 0x9E, 0x9C, 0x16, 0xAF, 0x5B, 0x1D, 0xAB, 0xDD, 0x68, 0xA8,\n\t0x93, 0xFA, 0xA2, 0xC6, 0xE7, 0x67, 0x63, 0x27, 0xDB, 0x1C, 0x87, 0x2E,\n\t0x9A, 0xCE, 0x73, 0xB0, 0xF3, 0x85, 0xE1, 0x13, 0x4E, 0x62, 0xF0, 0x85,\n\t0xBD, 0x1D, 0x51, 0x9D, 0xD0, 0x09, 0x56, 0x47, 0x27, 0x04, 0x07, 0x3B,\n\t0xA8, 0x51, 0x26, 0x4F, 0xA0, 0xFB, 0xB2, 0x96, 0x96, 0xFF, 0xB3, 0xB9,\n\t0xC2, 0x24, 0xAD, 0x33, 0x68, 0xBF, 0x4D, 0xC7, 0x79, 0x2F, 0xDB, 0xF4,\n\t0x4E, 0x4D, 0x88, 0x0B, 0xF2, 0x46, 0x6A, 0x2F, 0x7A, 0xFD, 0x8C, 0x23,\n\t0x91, 0x07, 0x4B, 0x7A, 0x70, 0x59, 0x4C, 0x72, 0x7C, 0x94, 0x02, 0xC3,\n\t0xDB, 0x0F, 0xED, 0x83, 0x9D, 0x31, 0xDB, 0x38, 0x8E, 0xDF, 0x9A, 0x64,\n\t0x82, 0x22, 0x6E, 0x47, 0x6C, 0x98, 0x9E, 0x9C, 0xB3, 0x79, 0xE6, 0x11,\n\t0x19, 0x5E, 0x04, 0xE7, 0x0F, 0x03, 0x4E, 0xEC, 0x40, 0x86, 0x08, 0xF5,\n\t0xF5, 0x51, 0x9E, 0x1F, 0x08, 0xEE, 0x52, 0xB3, 0xBD, 0xD9, 0x3C, 0xAA,\n\t0x3C, 0xA2, 0x0A, 0x58, 0xB2, 0x75, 0xEF, 0xDB, 0x07, 0xCF, 0xE2, 0x68,\n\t0x3A, 0x58, 0x2A, 0xF1, 0xB6, 0xA8, 0xDB, 0x4C, 0xA7, 0x4F, 0xA8, 0xD3,\n\t0x6B, 0x97, 0xB1, 0xDC, 0xC9, 0x64, 0xAA, 0x4C, 0xF8, 0x44, 0x9C, 0x46,\n\t0x37, 0xB6, 0xC3, 0x26, 0x3C, 0x2A, 0x5D, 0x13, 0x70, 0xFD, 0x81, 0x0C,\n\t0x75, 0xA2, 0x91, 0x4E, 0x3A, 0x4E, 0xF1, 0xA0, 0x0C, 0xB2, 0x8D, 0xC9,\n\t0x81, 0x90, 0xEC, 0x3C, 0x2B, 0xD5, 0x79, 0x95, 0x8F, 0x66, 0xAC, 0x85,\n\t0x3D, 0xA1, 0x59, 0xDE, 0x86, 0x3A, 0x2F, 0xCE, 0x46, 0xB3, 0xF8, 0xDB,\n\t0x0E, 0xFE, 0x09, 0xD0, 0xA9, 0x68, 0x0D, 0xC0, 0x19, 0xB9, 0x2A, 0xB5,\n\t0x4A, 0xF6, 0x91, 0x7E, 0x04, 0x50, 0x72, 0x5D, 0x68, 0x70, 0x24, 0x47,\n\t0x49, 0xC9, 0x4E, 0xD6, 0xB1, 0xE3, 0x04, 0x09, 0x9A, 0xC2, 0x5A, 0x2C,\n\t0x36, 0x6D, 0xEA, 0x9A, 0x60, 0x16, 0x3E, 0x27, 0xC4, 0x1C, 0x39, 0x03,\n\t0xAB, 0x21, 0x5B, 0x0A, 0x5F, 0xBA, 0x9D, 0xDD, 0x80, 0xFC, 0x67, 0xFC,\n\t0xCE, 0x72, 0xCF, 0x42, 0xC9, 0x41, 0xA1, 0xF2, 0x4B, 0x77, 0x75, 0xFC,\n\t0x7A, 0xEA, 0x3C, 0xBF, 0x39, 0x8E, 0xB1, 0x4E, 0xCD, 0x34, 0x36, 0xF1,\n\t0x4D, 0xEE, 0x92, 0x55, 0xC8, 0xAA, 0xD6, 0x64, 0x60, 0x8B, 0x0B, 0xB5,\n\t0xBF, 0xBB, 0x76, 0x5D, 0xF2, 0x36, 0xC9, 0x88, 0x29, 0x89, 0x02, 0x1E,\n\t0xEB, 0xF6, 0x05, 0x63, 0x28, 0xED, 0x4B, 0x94, 0x49, 0xE8, 0x0D, 0xD9,\n\t0xAD, 0x1B, 0x26, 0x0A, 0x12, 0xDC, 0x37, 0xF8, 0xBB, 0x34, 0x16, 0xE4,\n\t0xF2, 0xD2, 0xFD, 0xAD, 0x59, 0x71, 0xD2, 0x02, 0xA5, 0x03, 0x80, 0x40,\n\t0x4B, 0xA3, 0xED, 0x89, 0x0F, 0x6A, 0x89, 0x22, 0x8B, 0x16, 0xB9, 0x24,\n\t0x0E, 0xAE, 0x3C, 0xDB, 0x4F, 0xB0, 0x37, 0x49, 0x73, 0xE3, 0x4F, 0x41,\n\t0xB5, 0x74, 0x40, 0xDD, 0xED, 0xC3, 0xA7, 0xE6, 0xB6, 0x75, 0x7A, 0xC8,\n\t0xDD, 0x60, 0x37, 0x75, 0x5D, 0x38, 0x6A, 0x8B, 0x64, 0x46, 0xF3, 0xAD,\n\t0x82, 0x0D, 0x50, 0x24, 0x63, 0x53, 0x3A, 0xDD, 0x53, 0x2D, 0x8E, 0x75,\n\t0xA2, 0x91, 0x6D, 0x45, 0x08, 0xE3, 0xE7, 0xE5, 0xEA, 0x39, 0x98, 0xEF,\n\t0x34, 0x44, 0x5F, 0x36, 0x7E, 0x4F, 0xE6, 0x07, 0xD4, 0x4A, 0x89, 0x98,\n\t0x19, 0xB8, 0x87, 0x3B, 0x52, 0x0C, 0x67, 0xD9, 0x0E, 0xC4, 0x6A, 0x47,\n\t0x25, 0xF9, 0xB4, 0x6E, 0x2E, 0x65, 0x06, 0x09, 0xB3, 0xA6, 0x80, 0x87,\n\t0x68, 0xCF, 0x80, 0x71, 0x27, 0x24, 0xAD, 0x26, 0xF5, 0xF9, 0x66, 0x2B,\n\t0x0D, 0x07, 0xC0, 0xDA, 0xE4, 0x85, 0xA6, 0xA6, 0x30, 0xBE, 0x7C, 0xA9,\n\t0xB7, 0x18, 0x41, 0x78, 0xFD, 0x54, 0xDF, 0xB8, 0xB7, 0x30, 0x2D, 0x43,\n\t0xB2, 0xEA, 0x90, 0x40, 0xB5, 0x40, 0x10, 0x12, 0x67, 0xDD, 0xA3, 0xDA,\n\t0x98, 0x3E, 0x74, 0xCE, 0xAC, 0x5E, 0x0C, 0xCF, 0x4E, 0x7A, 0x68, 0x75,\n\t0x7E, 0x3A, 0xB8, 0xAB, 0x78, 0x4D, 0x44, 0x78, 0x87, 0x63, 0x6D, 0x4E,\n\t0x53, 0xB4, 0x2B, 0x97, 0x42, 0xAE, 0xD5, 0x44, 0xDD, 0xB5, 0x74, 0x79,\n\t0xC9, 0x7E, 0x72, 0xA1, 0x6A, 0xC0, 0x36, 0xBA, 0xC2, 0x7A, 0xD8, 0xEA,\n\t0x12, 0xD0, 0x66, 0x14, 0x36, 0x82, 0xA7, 0xD8, 0x34, 0x1D, 0xB8, 0xD8,\n\t0xE2, 0x95, 0x48, 0x22, 0x90, 0x7E, 0xF6, 0x7E, 0x80, 0x51, 0xAF, 0x0C,\n\t0x65, 0xD6, 0xE1, 0x9F, 0xB2, 0x4D, 0xDB, 0xF6, 0x6C, 0xD2, 0x08, 0x13,\n\t0x47, 0xDF, 0x64, 0x14, 0xCA, 0xDE, 0x2C, 0x89, 0xBB, 0x9C, 0x07, 0xCE,\n\t0x99, 0xF7, 0x0E, 0x39, 0xCE, 0x9F, 0xF8, 0x9B, 0x87, 0xCA, 0xA2, 0xF0,\n\t0xDB, 0x91, 0x71, 0x1C, 0x32, 0x57, 0xAF, 0xEB, 0x2D, 0xB5, 0xA4, 0xF7,\n\t0x8C, 0xEB, 0xC7, 0xEA, 0xA9, 0xF2, 0x0E, 0x36, 0xD5, 0x57, 0x57, 0x79,\n\t0x30, 0x39, 0x8D, 0x60, 0x00, 0x94, 0xF3, 0x9E, 0xF0, 0x43, 0xD7, 0xE4,\n\t0x48, 0xE6, 0xF3, 0xC9, 0x89, 0x3B, 0x9E, 0x38, 0x59, 0x8F, 0xC8, 0x22,\n\t0x80, 0xBE, 0x9B, 0x4A, 0xDF, 0x52, 0xF5, 0x01, 0x50, 0x1B, 0x72, 0xE3,\n\t0xD2, 0xF7, 0x0B, 0x4C, 0xD7, 0x23, 0x62, 0x11, 0x9C, 0x74, 0x48, 0xF4,\n\t0xCD, 0xBA, 0xD4, 0x7C, 0x88, 0x9E, 0xF6, 0xFB, 0x34, 0xFA, 0x30, 0x73,\n\t0x35, 0x2D, 0xE3, 0x85, 0x09, 0x14, 0x7A, 0x14, 0x3E, 0xC2, 0xEF, 0xA2,\n\t0x89, 0x3D, 0x79, 0x01, 0x43, 0x4E, 0x1C, 0x84, 0x08, 0xB8, 0x65, 0xE6,\n\t0x21, 0x81, 0x33, 0xC3, 0x8A\n};"
  },
  {
    "path": "src/Cafe/HW/Latte/Common/ShaderSerializer.h",
    "content": "#pragma once\n#include \"util/helpers/Serializer.h\"\n\nnamespace Latte\n{\n\tvoid SerializeShaderProgram(void* shaderProg, uint32 size, MemStreamWriter& memWriter);\n\tbool DeserializeShaderProgram(std::vector<uint8>& progData, MemStreamReader& memReader);\n};"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/FetchShader.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/ISA/LatteInstructions.h\"\n#include \"HW/Latte/Renderer/Renderer.h\"\n#include \"util/containers/LookupTableL3.h\"\n#include \"util/helpers/fspinlock.h\"\n#if ENABLE_METAL\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n#endif\n#include <openssl/sha.h> /* SHA1_DIGEST_LENGTH */\n#include <openssl/evp.h> /* EVP_Digest */\n\nuint32 LatteShaderRecompiler_getAttributeSize(LatteParsedFetchShaderAttribute_t* attrib)\n{\n\tif (attrib->format == FMT_32_32_32_32 || attrib->format == FMT_32_32_32_32_FLOAT)\n\t\treturn 4 * 4;\n\telse if (attrib->format == FMT_32_32_32 || attrib->format == FMT_32_32_32_FLOAT)\n\t\treturn 3 * 4;\n\telse if (attrib->format == FMT_32_32 || attrib->format == FMT_32_32_FLOAT)\n\t\treturn 2 * 4;\n\telse if (attrib->format == FMT_32 || attrib->format == FMT_32_FLOAT)\n\t\treturn 1 * 4;\n\telse if (attrib->format == FMT_16_16_16_16 || attrib->format == FMT_16_16_16_16_FLOAT)\n\t\treturn 4 * 2;\n\telse if (attrib->format == FMT_16_16 || attrib->format == FMT_16_16_FLOAT)\n\t\treturn 2 * 2;\n\telse if (attrib->format == FMT_16 || attrib->format == FMT_16_FLOAT)\n\t\treturn 1 * 2;\n\telse if (attrib->format == FMT_8_8_8_8)\n\t\treturn 4 * 1;\n\telse if (attrib->format == FMT_8_8)\n\t\treturn 2 * 1;\n\telse if (attrib->format == FMT_8)\n\t\treturn 1 * 1;\n\telse if (attrib->format == FMT_2_10_10_10)\n\t\treturn 4;\n\telse\n\t\tcemu_assert_unimplemented();\n\treturn 0;\n}\n\nuint32 LatteShaderRecompiler_getAttributeAlignment(LatteParsedFetchShaderAttribute_t* attrib)\n{\n\tif (attrib->format == FMT_32_32_32_32 || attrib->format == FMT_32_32_32_32_FLOAT)\n\t\treturn 4;\n\telse if (attrib->format == FMT_32_32_32 || attrib->format == FMT_32_32_32_FLOAT)\n\t\treturn 4;\n\telse if (attrib->format == FMT_32_32 || attrib->format == FMT_32_32_FLOAT)\n\t\treturn 4;\n\telse if (attrib->format == FMT_32 || attrib->format == FMT_32_FLOAT)\n\t\treturn 4;\n\telse if (attrib->format == FMT_16_16_16_16 || attrib->format == FMT_16_16_16_16_FLOAT)\n\t\treturn 2;\n\telse if (attrib->format == FMT_16_16 || attrib->format == FMT_16_16_FLOAT)\n\t\treturn 2;\n\telse if (attrib->format == FMT_16 || attrib->format == FMT_16_FLOAT)\n\t\treturn 2;\n\telse if (attrib->format == FMT_8_8_8_8)\n\t\treturn 1;\n\telse if (attrib->format == FMT_8_8)\n\t\treturn 1;\n\telse if (attrib->format == FMT_8)\n\t\treturn 1;\n\telse if (attrib->format == FMT_2_10_10_10)\n\t\treturn 4;\n\telse\n\t\tcemu_assert_unimplemented();\n\treturn 4;\n}\n\nvoid LatteShader_calculateFSKey(LatteFetchShader* fetchShader)\n{\n\tuint64 key = 0;\n\tfor (sint32 g = 0; g < fetchShader->bufferGroups.size(); g++)\n\t{\n\t\tLatteParsedFetchShaderBufferGroup_t& group = fetchShader->bufferGroups[g];\n\t\tfor (sint32 f = 0; f < group.attribCount; f++)\n\t\t{\n\t\t\tLatteParsedFetchShaderAttribute_t* attrib = group.attrib + f;\n\t\t\tkey += (uint64)attrib->endianSwap;\n\t\t\tkey = std::rotl<uint64>(key, 3);\n\t\t\tkey += (uint64)attrib->nfa;\n\t\t\tkey = std::rotl<uint64>(key, 3);\n\t\t\tkey += (uint64)(attrib->isSigned?1:0);\n\t\t\tkey = std::rotl<uint64>(key, 1);\n\t\t\tkey += (uint64)attrib->format;\n\t\t\tkey = std::rotl<uint64>(key, 7);\n\t\t\tkey += (uint64)attrib->fetchType;\n\t\t\tkey = std::rotl<uint64>(key, 8);\n\t\t\tkey += (uint64)attrib->ds[0];\n\t\t\tkey = std::rotl<uint64>(key, 2);\n\t\t\tkey += (uint64)attrib->ds[1];\n\t\t\tkey = std::rotl<uint64>(key, 2);\n\t\t\tkey += (uint64)attrib->ds[2];\n\t\t\tkey = std::rotl<uint64>(key, 2);\n\t\t\tkey += (uint64)attrib->ds[3];\n\t\t\tkey = std::rotl<uint64>(key, 2);\n\t\t\tkey += (uint64)(attrib->aluDivisor+1);\n\t\t\tkey = std::rotl<uint64>(key, 2);\n\t\t\tkey += (uint64)attrib->attributeBufferIndex;\n\t\t\tkey = std::rotl<uint64>(key, 8);\n\t\t\tkey += (uint64)attrib->semanticId;\n\t\t\tkey = std::rotl<uint64>(key, 8);\n\t\t\tif (g_renderer->GetType() == RendererAPI::Metal)\n\t\t\t{\n\t\t\t    key += (uint64)attrib->offset;\n\t\t\t\tkey = std::rotl<uint64>(key, 7);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tkey += (uint64)(attrib->offset & 3);\n\t\t\t\tkey = std::rotl<uint64>(key, 2);\n\t\t\t}\n\t\t}\n\t}\n\t// todo - also hash invalid buffer groups?\n\n#if ENABLE_METAL\n\tif (g_renderer->GetType() == RendererAPI::Metal)\n\t{\n\t\tfor (sint32 g = 0; g < fetchShader->bufferGroups.size(); g++)\n\t{\n\t\t\tLatteParsedFetchShaderBufferGroup_t& group = fetchShader->bufferGroups[g];\n\t\t\tkey += (uint64)group.attributeBufferIndex;\n\t\t\tkey = std::rotl<uint64>(key, 5);\n\t\t}\n\t}\n#endif\n\n\tfetchShader->key = key;\n}\n\nuint32 LatteParsedFetchShaderBufferGroup_t::getCurrentBufferStride(uint32* contextRegister) const\n{\n\tuint32 bufferIndex = this->attributeBufferIndex;\n\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n\tuint32 bufferStride = (contextRegister[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;\n\treturn bufferStride;\n}\n\nvoid LatteFetchShader::CalculateFetchShaderVkHash()\n{\n\t// calculate SHA1 of all states that are part of the Vulkan graphics pipeline\n\tEVP_MD_CTX *ctx = EVP_MD_CTX_new();\n\tEVP_DigestInit(ctx, EVP_sha1());\n\tfor(auto& group : bufferGroups)\n\t{\n\t\t// offsets\n\t\tfor (sint32 t = 0; t < group.attribCount; t++)\n\t\t{\n\t\t\tuint32 offset = group.attrib[t].offset;\n\t\t\tEVP_DigestUpdate(ctx, &t, sizeof(t));\n\t\t\tEVP_DigestUpdate(ctx, &offset, sizeof(offset));\n\t\t}\n\t}\n\tuint8 shaDigest[SHA_DIGEST_LENGTH];\n\tEVP_DigestFinal_ex(ctx, shaDigest, NULL);\n\tEVP_MD_CTX_free(ctx);\n\n\t// fold SHA1 hash into a 64bit value\n\tuint64 h = *(uint64*)(shaDigest + 0);\n\th += *(uint64*)(shaDigest + 8);\n\th += (uint64)*(uint32*)(shaDigest + 16);\n\tthis->vkPipelineHashFragment = h;\n}\n\n#if ENABLE_METAL\nvoid LatteFetchShader::CheckIfVerticesNeedManualFetchMtl(uint32* contextRegister)\n{\n\tfor (sint32 g = 0; g < bufferGroups.size(); g++)\n\t{\n\t    LatteParsedFetchShaderBufferGroup_t& group = bufferGroups[g];\n\t\tuint32 bufferIndex = group.attributeBufferIndex;\n\t\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n\t\tuint32 bufferStride = (contextRegister[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;\n\n  \t\tif (bufferStride % 4 != 0)\n  \t\t    mtlFetchVertexManually = true;\n\n  \t\tfor (sint32 f = 0; f < group.attribCount; f++)\n  \t\t{\n  \t\t    auto& attr = group.attrib[f];\n  \t\t    if (attr.offset + GetMtlVertexFormatSize(attr.format) > bufferStride)\n \t\t\t    mtlFetchVertexManually = true;\n  \t\t}\n\t}\n}\n#endif\n\nvoid _fetchShaderDecompiler_parseInstruction_VTX_SEMANTIC(LatteFetchShader* parsedFetchShader, uint32* contextRegister, const LatteClauseInstruction_VTX* instr)\n{\n\tuint32 semanticId = instr->getFieldSEM_SEMANTIC_ID(); // location (attribute index inside shader)\n\tuint32 bufferId = instr->getField_BUFFER_ID(); // the index used for GX2SetAttribBuffer (+0xA0)\n\tLatteConst::VertexFetchType2 fetchType = instr->getField_FETCH_TYPE();\n\tauto srcSelX = instr->getField_SRC_SEL_X();\n\tauto dsx = instr->getField_DST_SEL(0);\n\tauto dsy = instr->getField_DST_SEL(1);\n\tauto dsz = instr->getField_DST_SEL(2);\n\tauto dsw = instr->getField_DST_SEL(3);\n\tauto dataFormat = instr->getField_DATA_FORMAT();\n\tuint32 offset = instr->getField_OFFSET();\n\tauto nfa = instr->getField_NUM_FORMAT_ALL();\n\tbool isSigned = instr->getField_FORMAT_COMP_ALL() == LatteClauseInstruction_VTX::FORMAT_COMP::COMP_SIGNED;\n\tauto endianSwap = instr->getField_ENDIAN_SWAP();\n\n\t// get buffer\n\tcemu_assert_debug(bufferId >= 0xA0 && bufferId < 0xB0);\n\tuint32 bufferIndex = (bufferId - 0xA0);\n\n\t// get or add new attribute group (by buffer index)\n\tLatteParsedFetchShaderBufferGroup_t* attribGroup = nullptr;\n\tif (LatteFetchShader::isValidBufferIndex(bufferIndex))\n\t{\n\t\tauto bufferGroupItr = std::find_if(parsedFetchShader->bufferGroups.begin(), parsedFetchShader->bufferGroups.end(), [bufferIndex](LatteParsedFetchShaderBufferGroup_t& bufferGroup) {return bufferGroup.attributeBufferIndex == bufferIndex; });\n\t\tif (bufferGroupItr != parsedFetchShader->bufferGroups.end())\n\t\t\tattribGroup = &(*bufferGroupItr);\n\t}\n\telse\n\t{\n\t\tauto bufferGroupItr = std::find_if(parsedFetchShader->bufferGroupsInvalid.begin(), parsedFetchShader->bufferGroupsInvalid.end(), [bufferIndex](LatteParsedFetchShaderBufferGroup_t& bufferGroup) {return bufferGroup.attributeBufferIndex == bufferIndex; });\n\t\tif (bufferGroupItr != parsedFetchShader->bufferGroupsInvalid.end())\n\t\t\tattribGroup = &(*bufferGroupItr);\n\t}\n\t// create new group if none found\n\tif (attribGroup == nullptr)\n\t{\n\t\tif (LatteFetchShader::isValidBufferIndex(bufferIndex))\n\t\t\tattribGroup = &parsedFetchShader->bufferGroups.emplace_back();\n\t\telse\n\t\t\tattribGroup = &parsedFetchShader->bufferGroupsInvalid.emplace_back();\n\n\t\tattribGroup->attributeBufferIndex = bufferIndex;\n\t\tattribGroup->minOffset = offset;\n\t\tattribGroup->maxOffset = offset;\n\t}\n\t// add attribute\n\tsint32 groupAttribIndex = attribGroup->attribCount;\n\tif (attribGroup->attribCount < (groupAttribIndex + 1))\n\t{\n\t\tattribGroup->attribCount = (groupAttribIndex + 1);\n\t\tattribGroup->attrib = (LatteParsedFetchShaderAttribute_t*)realloc(attribGroup->attrib, sizeof(LatteParsedFetchShaderAttribute_t) * attribGroup->attribCount);\n\t}\n\tattribGroup->attrib[groupAttribIndex].semanticId = semanticId;\n\tattribGroup->attrib[groupAttribIndex].format = (uint8)dataFormat;\n\tattribGroup->attrib[groupAttribIndex].fetchType = fetchType;\n\tattribGroup->attrib[groupAttribIndex].nfa = (uint8)nfa;\n\tattribGroup->attrib[groupAttribIndex].isSigned = isSigned;\n\tattribGroup->attrib[groupAttribIndex].offset = offset;\n\tattribGroup->attrib[groupAttribIndex].ds[0] = (uint8)dsx;\n\tattribGroup->attrib[groupAttribIndex].ds[1] = (uint8)dsy;\n\tattribGroup->attrib[groupAttribIndex].ds[2] = (uint8)dsz;\n\tattribGroup->attrib[groupAttribIndex].ds[3] = (uint8)dsw;\n\tattribGroup->attrib[groupAttribIndex].attributeBufferIndex = bufferIndex;\n\tattribGroup->attrib[groupAttribIndex].endianSwap = endianSwap;\n\tattribGroup->minOffset = (std::min)(attribGroup->minOffset, offset);\n\tattribGroup->maxOffset = (std::max)(attribGroup->maxOffset, offset);\n\t// get alu divisor\n\tif (srcSelX == LatteClauseInstruction_VTX::SRC_SEL::SEL_X)\n\t{\n\t\tcemu_assert_debug(fetchType != LatteConst::VertexFetchType2::INSTANCE_DATA); // aluDivisor 0 in combination with instanced data is not allowed?\n\t\tattribGroup->attrib[groupAttribIndex].aluDivisor = -1;\n\t}\n\telse if (srcSelX == LatteClauseInstruction_VTX::SRC_SEL::SEL_W)\n\t{\n\t\tcemu_assert_debug(fetchType == LatteConst::VertexFetchType2::INSTANCE_DATA); // using constant divisor 1 with per-vertex data seems strange? (divisor is instance-only)\n\t\t// aluDivisor is constant 1\n\t\tattribGroup->attrib[groupAttribIndex].aluDivisor = 1;\n\t}\n\telse if (srcSelX == LatteClauseInstruction_VTX::SRC_SEL::SEL_Y)\n\t{\n\t\t// use alu divisor 1\n\t\tattribGroup->attrib[groupAttribIndex].aluDivisor = (sint32)contextRegister[Latte::REGADDR::VGT_INSTANCE_STEP_RATE_0];\n\t\tcemu_assert_debug(attribGroup->attrib[groupAttribIndex].aluDivisor > 0);\n\t}\n\telse if (srcSelX == LatteClauseInstruction_VTX::SRC_SEL::SEL_Z)\n\t{\n\t\t// use alu divisor 2\n\t\tattribGroup->attrib[groupAttribIndex].aluDivisor = (sint32)contextRegister[Latte::REGADDR::VGT_INSTANCE_STEP_RATE_1];\n\t\tcemu_assert_debug(attribGroup->attrib[groupAttribIndex].aluDivisor > 0);\n\t}\n}\n\nvoid _fetchShaderDecompiler_parseVTXClause(LatteFetchShader* parsedFetchShader, uint32* contextRegister, std::span<uint8> clauseCode, size_t numInstructions)\n{\n\tconst LatteClauseInstruction_VTX* instr = (LatteClauseInstruction_VTX*)clauseCode.data();\n\tconst LatteClauseInstruction_VTX* end = instr + numInstructions;\n\twhile (instr < end)\n\t{\n\t\tif (instr->getField_VTX_INST() == LatteClauseInstruction_VTX::VTX_INST::_VTX_INST_SEMANTIC)\n\t\t{\n\t\t\t_fetchShaderDecompiler_parseInstruction_VTX_SEMANTIC(parsedFetchShader, contextRegister, instr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t\tinstr++;\n\t}\n}\n\nvoid _fetchShaderDecompiler_parseCF(LatteFetchShader* parsedFetchShader, uint32* contextRegister, std::span<uint8> programCode)\n{\n\tsize_t maxCountCFInstructions = programCode.size_bytes() / sizeof(LatteCFInstruction);\n\tconst LatteCFInstruction* cfInstruction = (LatteCFInstruction*)programCode.data();\n\tconst LatteCFInstruction* end = cfInstruction + maxCountCFInstructions;\n\twhile (cfInstruction < end)\n\t{\n\t\tif (cfInstruction->getField_Opcode() == LatteCFInstruction::INST_VTX_TC)\n\t\t{\n\t\t\tauto vtxInstruction = cfInstruction->getParserIfOpcodeMatch<LatteCFInstruction_DEFAULT>();\n\t\t\tcemu_assert_debug(vtxInstruction->getField_COND() == LatteCFInstruction::CF_COND::CF_COND_ACTIVE);\n\t\t\t_fetchShaderDecompiler_parseVTXClause(parsedFetchShader, contextRegister, vtxInstruction->getClauseCode(programCode), vtxInstruction->getField_COUNT());\n\t\t}\n\t\telse if (cfInstruction->getField_Opcode() == LatteCFInstruction::INST_RETURN)\n\t\t{\n\t\t\tcemu_assert_debug(!cfInstruction->getField_END_OF_PROGRAM());\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false); // unhandled / unexpected CF instruction\n\t\t}\n\t\tif (cfInstruction->getField_END_OF_PROGRAM())\n\t\t{\n\t\t\tcemu_assert_debug(false); // unusual for fetch shader? They should end with a return instruction\n\t\t\tbreak;\n\t\t}\n\t\tcfInstruction++;\n\t}\n\tcemu_assert_debug(false); // program must be terminated with an instruction that has EOP set?\n}\n\n// parse fetch shader and create LatteFetchShader object\n// also registers the fs in the cache (s_fetchShaderByHash)\n// can be assumed to be thread-safe, if called simultaneously on the same fetch shader only one shader will become registered. The others will be destroyed\nLatteFetchShader* LatteShaderRecompiler_createFetchShader(LatteFetchShader::CacheHash fsHash, uint32* contextRegister, uint32* fsProgramCode, uint32 fsProgramSize)\n{\n\tLatteFetchShader* newFetchShader = new LatteFetchShader();\n\tnewFetchShader->m_cacheHash = fsHash;\n\tif( (fsProgramSize&0xF) != 0 )\n\t\tdebugBreakpoint();\n\tuint32 index = 0;\n\n\t// if the first instruction is a CF instruction then parse shader properly\n\t// otherwise fall back to our broken legacy method (where we assumed fetch shaders had no CF program)\n\t// this workaround is required to make sure old shader caches dont break\n\n\t// from old fetch shader gen (CF part missing):\n\t//\t\t\t{0x0000a001, 0x27961000, 0x00020000, 0x00000000}\n\t//\t\t\t{0x0000a001, 0x2c151002, 0x00020000, 0x00000000, 0x0000a001, 0x068d1000, 0x0000000c, ...}\n\t//\t\t\t{0x0000a001, 0x2c151000, 0x00020000, 0x00000000}\n\t//          {0x0300aa21, 0x28cd1006, 0x00000000, 0x00000000, 0x0300ab21, 0x28cd1007, 0x00000000, ...}\n\n\t// shaders shipped with games (e.g. BotW):\n\t//\t\t\t{0x00000002, 0x01800400, 0x00000000, 0x8a000000, 0x1c00a001, 0x280d1000, 0x00090000, ...}\n\t//\t\t\t{0x00000002, 0x01800000, 0x00000000, 0x8a000000, 0x1c00a001, 0x27961000, 0x000a0000, ...}\n\t//\t\t\t{0x00000002, 0x01800c00, 0x00000000, 0x8a000000, 0x2c00a001, 0x2c151000, 0x000a0000, ...} // size 0x50\n\t//          {0x00000002, 0x01801000, 0x00000000, 0x8a000000, 0x1c00a001, 0x280d1000, 0x00090000, ...} // size 0x60\n\t//\t\t\t{0x00000002, 0x01801c00, 0x00000000, 0x8a000000, 0x1c00a001, 0x280d1000, 0x00090000, ...} // size 0x90\n\n\t// our new implementation:\n\t//\t\t\t{0x00000002, 0x01800400, 0x00000000, 0x8a000000, 0x0000a001, 0x2c151000, 0x00020000, ...}\n\n\t// for ALU instructions everything except the 01 is dynamic\n\tnewFetchShader->bufferGroups.reserve(16);\n\tif (fsProgramSize == 0)\n\t{\n\t\t// empty fetch shader, seen in Minecraft\n\t\t// these only make sense when vertex shader does not call FS?\n\t\tLatteShader_calculateFSKey(newFetchShader);\n\t\tnewFetchShader->CalculateFetchShaderVkHash();\n#if ENABLE_METAL\n\t\tnewFetchShader->CheckIfVerticesNeedManualFetchMtl(contextRegister);\n#endif\n\t\treturn newFetchShader;\n\t}\n\n\tif ((fsProgramCode[0] & 1) == 0 && fsProgramCode[0] <= 0x30 && (fsProgramCode[1]&~((3 << 10)| (1 << 19))) == 0x01800000)\n\t{\n\t\t// very likely a CF instruction\n\t\t_fetchShaderDecompiler_parseCF(newFetchShader, contextRegister, { (uint8*)fsProgramCode, fsProgramSize });\n\t}\n\telse\n\t{\n\t\twhile (index < (fsProgramSize / 4))\n\t\t{\n\t\t\tuint32 dword0 = fsProgramCode[index];\n\t\t\tuint32 opcode = dword0 & 0x1F;\n\t\t\tindex++;\n\t\t\tif (opcode == VTX_INST_MEM)\n\t\t\t{\n\t\t\t\t// this might be the clause initialization instruction? (Seems to be the first instruction always)\n\t\t\t\t// todo - upon further investigation, it seems like fetch shaders also start with a CF program. Our implementation doesnt emit one right now\n\t\t\t\tuint32 opcode2 = (dword0 >> 8) & 7;\n\n\t\t\t\tindex += 3;\n\t\t\t}\n\t\t\telse if (opcode == VTX_INST_SEMANTIC)\n\t\t\t{\n\t\t\t\t_fetchShaderDecompiler_parseInstruction_VTX_SEMANTIC(newFetchShader, contextRegister, (const LatteClauseInstruction_VTX*)(fsProgramCode + index - 1));\n\t\t\t\tindex += 3;\n\t\t\t}\n\t\t}\n\t}\n\tnewFetchShader->bufferGroups.shrink_to_fit();\n\t// calculate group information\n\t// VBO offsets and stride\n\tuint32 vboOffset = 0;\n\tfor (auto& bufferGroup : newFetchShader->bufferGroups)\n\t{\n\t\tfor(sint32 i=0; i< bufferGroup.attribCount; i++)\n\t\t{\n\t\t\tuint32 attribSize = LatteShaderRecompiler_getAttributeSize(bufferGroup.attrib+i);\n\t\t\tuint32 attribAlignment = LatteShaderRecompiler_getAttributeAlignment(bufferGroup.attrib+i);\n\t\t\t// fix alignment\n\t\t\tvboOffset = (vboOffset+attribAlignment-1)&~(attribAlignment-1);\n\t\t\tvboOffset += attribSize;\n\t\t\t// index type\n\t\t\tif(bufferGroup.attrib[i].fetchType == LatteConst::VERTEX_DATA)\n\t\t\t\tbufferGroup.hasVtxIndexAccess = true;\n\t\t\telse if (bufferGroup.attrib[i].fetchType == LatteConst::INSTANCE_DATA)\n\t\t\t\tbufferGroup.hasInstanceIndexAccess = true;\n\t\t}\n\t\t// fix alignment of whole vertex\n\t\tif(bufferGroup.attribCount > 0 )\n\t\t{\n\t\t\tuint32 attribAlignment = LatteShaderRecompiler_getAttributeAlignment(bufferGroup.attrib+0);\n\t\t\tvboOffset = (vboOffset+attribAlignment-1)&~(attribAlignment-1);\n\t\t}\n\t\tbufferGroup.vboStride = vboOffset;\n\t}\n\tLatteShader_calculateFSKey(newFetchShader);\n\tnewFetchShader->CalculateFetchShaderVkHash();\n#if ENABLE_METAL\n\tnewFetchShader->CheckIfVerticesNeedManualFetchMtl(contextRegister);\n#endif\n\n\t// register in cache\n\t// its possible that during multi-threaded shader cache loading, two identical (same hash) fetch shaders get created simultaneously\n\t// we catch and handle this case here. RegisterInCache() is atomic and if another fetch shader is already registered, we abandon the local instance\n\tLatteFetchShader* registeredFS = newFetchShader->RegisterInCache(fsHash);\n\tif (registeredFS)\n\t{\n\t\tdelete newFetchShader;\n\t\tnewFetchShader = registeredFS;\n\t}\n\telse\n\t{\n\t\tnewFetchShader->m_isRegistered = true;\n\t}\n\n\n\treturn newFetchShader;\n}\n\nLatteFetchShader::~LatteFetchShader()\n{\n\tUnregisterInCache();\n}\n\nstruct FetchShaderLookupInfo\n{\n\tLatteFetchShader* fetchShader;\n\tuint32 programSize;\n\tuint32 lastFrameAccessed;\n};\n\nLookupTableL3<8, 8, 8, FetchShaderLookupInfo*> g_fetchShaderLookupCache;\n\nLatteFetchShader::CacheHash LatteFetchShader::CalculateCacheHash(void* programCode, uint32 programSize)\n{\n\tuint32* programCodeU32 = (uint32*)programCode;\n\tuint64 progHash1 = 0;\n\tuint64 progHash2 = 0;\n\tfor (uint32 i = 0; i < programSize / 4; i++)\n\t{\n\t\tuint32 temp = programCodeU32[i];\n\t\tprogHash1 += (uint64)temp;\n\t\tprogHash2 ^= (uint64)temp;\n\t\tprogHash1 = (progHash1 << 3) | (progHash1 >> 61);\n\t\tprogHash2 = (progHash2 >> 7) | (progHash2 << 57);\n\t}\n\n\t// todo - we should incorporate the value of VGT_INSTANCE_STEP_RATE_0/1 into the hash since it affects the generated LatteFetchShader object\n\t//        However, this would break compatibility with shader caches and gfx packs due to altering the shader base hashes\n\n\treturn progHash1 + progHash2;\n}\n\nLatteFetchShader* LatteFetchShader::FindInCacheByHash(LatteFetchShader::CacheHash fsHash)\n{\n\t// does not hold s_fetchShaderCache for better performance. Be careful not to call this while another thread invokes RegisterInCache()\n\tauto itr = s_fetchShaderByHash.find(fsHash);\n\tif (itr == s_fetchShaderByHash.end())\n\t\treturn nullptr;\n\treturn itr->second;\n}\n\nvoid* _getFSProgramPtr()\n{\n\treturn memory_getPointerFromPhysicalOffset(LatteGPUState.contextRegister[mmSQ_PGM_START_FS + 0] << 8);\n}\n\nuint32 _getFSProgramSize()\n{\n\treturn LatteGPUState.contextRegister[mmSQ_PGM_START_FS + 1] << 3;\n}\n\nLatteFetchShader* LatteFetchShader::FindByGPUState()\n{\n\t// retrieve fetch shader that matches the currently set GPU context registers\n\tuint32 fsPhysAddr24 = LatteGPUState.contextRegister[mmSQ_PGM_START_FS + 0];\n\tcemu_assert_debug(fsPhysAddr24 < 0x1000000); // should only contain the upper 24 bit of the address in the lower 24 bit of the register\n\n\tFetchShaderLookupInfo* lookupInfo = g_fetchShaderLookupCache.lookup(fsPhysAddr24);\n\tif (lookupInfo)\n\t{\n\t\t// return fetch shader if still the same\n\t\tuint32 fsSize = _getFSProgramSize();\n\t\tuint32 framesSinceLastAccess = LatteGPUState.frameCounter - lookupInfo->lastFrameAccessed;\n\t\tif (lookupInfo->programSize == fsSize && framesSinceLastAccess == 0)\n\t\t{\n\t\t\tlookupInfo->lastFrameAccessed = LatteGPUState.frameCounter;\n\t\t\treturn lookupInfo->fetchShader;\n\t\t}\n\t\t// update lookup info\n\t\tCacheHash fsHash = CalculateCacheHash(_getFSProgramPtr(), _getFSProgramSize());\n\t\tLatteFetchShader* fetchShader = FindInCacheByHash(fsHash);\n\t\tif (!fetchShader)\n\t\t{\n\t\t\tfetchShader = LatteShaderRecompiler_createFetchShader(fsHash, LatteGPUState.contextNew.GetRawView(), (uint32*)_getFSProgramPtr(), _getFSProgramSize());\n\t\t\tcemu_assert(fetchShader);\n\t\t}\n\t\tlookupInfo->fetchShader = fetchShader;\n\t\tlookupInfo->programSize = fsSize;\n\t\tlookupInfo->lastFrameAccessed = LatteGPUState.frameCounter;\n\t\treturn fetchShader;\n\t}\n\telse\n\t{\n\t\t// try to find fetch shader by data hash\n\t\tCacheHash fsHash = CalculateCacheHash(_getFSProgramPtr(), _getFSProgramSize());\n\t\tLatteFetchShader* fetchShader = FindInCacheByHash(fsHash);\n\t\tif (!fetchShader)\n\t\t{\n\t\t\tfetchShader = LatteShaderRecompiler_createFetchShader(fsHash, LatteGPUState.contextNew.GetRawView(), (uint32*)_getFSProgramPtr(), _getFSProgramSize());\n\t\t\tcemu_assert(fetchShader);\n\t\t}\n\t\t// create new lookup entry\n\t\tlookupInfo = new FetchShaderLookupInfo();\n\t\tlookupInfo->fetchShader = fetchShader;\n\t\tlookupInfo->programSize = _getFSProgramSize();\n\t\tlookupInfo->lastFrameAccessed = LatteGPUState.frameCounter;\n\t\tg_fetchShaderLookupCache.store(fsPhysAddr24, lookupInfo);\n#ifdef CEMU_DEBUG_ASSERT\n\t\tcemu_assert_debug(g_fetchShaderLookupCache.lookup(fsPhysAddr24) == lookupInfo);\n#endif\n\t}\n\treturn lookupInfo->fetchShader;\n}\n\nFSpinlock s_spinlockFetchShaderCache;\n\nLatteFetchShader* LatteFetchShader::RegisterInCache(CacheHash fsHash)\n{\n\ts_spinlockFetchShaderCache.lock();\n\tauto itr = s_fetchShaderByHash.find(fsHash);\n\tif (itr != s_fetchShaderByHash.end())\n\t{\n\t\tLatteFetchShader* fs = itr->second;\n\t\ts_spinlockFetchShaderCache.unlock();\n\t\treturn fs;\n\t}\n\ts_fetchShaderByHash.emplace(fsHash, this);\n\ts_spinlockFetchShaderCache.unlock();\n\treturn nullptr;\n}\n\nvoid LatteFetchShader::UnregisterInCache()\n{\n\tif (!m_isRegistered)\n\t\treturn;\n\ts_spinlockFetchShaderCache.lock();\n\tauto itr = s_fetchShaderByHash.find(m_cacheHash);\n\tcemu_assert(itr == s_fetchShaderByHash.end());\n\ts_fetchShaderByHash.erase(itr);\n\ts_spinlockFetchShaderCache.unlock();\n}\n\nstd::unordered_map<LatteFetchShader::CacheHash, LatteFetchShader*> LatteFetchShader::s_fetchShaderByHash;\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/FetchShader.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n\nstruct LatteParsedFetchShaderAttribute_t\n{\n\tuint8\t\t\t\t\tsemanticId;\n\tuint8\t\t\t\t\tformat;\n\tLatteConst::VertexFetchType2\tfetchType;\n\tuint8\t\t\t\t\tnfa;\n\tuint8\t\t\t\t\tisSigned;\n\tLatteConst::VertexFetchEndianMode\tendianSwap;\n\tuint8\t\t\t\t\tds[4]; // destination component select\n\tsint32\t\t\t\t\taluDivisor;\n\tuint32\t\t\t\t\toffset;\n\tuint32\t\t\t\t\tattributeBufferIndex;\n};\n\nstruct LatteParsedFetchShaderBufferGroup_t\n{\n\tuint32 attributeBufferIndex{}; // index of buffer (0 to 15 are valid)\n\tLatteParsedFetchShaderAttribute_t* attrib{}; // attributes for this buffer\n\tsint32 attribCount{};\n\t// offset range of attributes\n\tuint32 minOffset{};\n\tuint32 maxOffset{};\n\t// output\n\tuint32  vboStride{};\n\t// calculated info\n\tbool hasVtxIndexAccess{};\n\tbool hasInstanceIndexAccess{};\n\n\tuint32 getCurrentBufferStride(uint32* contextRegister) const;\n};\n\nstruct LatteFetchShader\n{\n\tusing CacheHash = uint64;\n\n\t~LatteFetchShader();\n\n\tstd::vector<LatteParsedFetchShaderBufferGroup_t> bufferGroups;\n\tstd::vector<LatteParsedFetchShaderBufferGroup_t> bufferGroupsInvalid; // groups with buffer index not being a valid buffer (dst components of these can affect shader code, but no actual vertex imports are done)\n\n\tuint64 key{};\n\n\t// Vulkan\n\tuint64 vkPipelineHashFragment{}; // hash of all fetch shader state that influences the Vulkan graphics pipeline\n\n\t// Metal\n\tbool mtlFetchVertexManually{};\n\n\t// cache info\n\tCacheHash m_cacheHash{};\n\tbool m_isRegistered{}; // if true, fetch shader is referenced by cache (RegisterInCache() succeeded)\n\n\tvoid CalculateFetchShaderVkHash();\n\n#if ENABLE_METAL\n\tvoid CheckIfVerticesNeedManualFetchMtl(uint32* contextRegister);\n#endif\n\n\tuint64 getVkPipelineHashFragment() const { return vkPipelineHashFragment; };\n\n\tstatic bool isValidBufferIndex(const uint32 index) { return index < 0x10; };\n\n\t// cache\n\tLatteFetchShader* RegisterInCache(CacheHash fsHash); // Fails if another fetch shader object is already registered with the same fsHash. Returns the previously registered fetch shader or null\n\tvoid UnregisterInCache();\n\n\t// fetch shader cache (move these to separate Cache class?)\n\tstatic CacheHash CalculateCacheHash(void* programCode, uint32 programSize);\n\tstatic LatteFetchShader* FindInCacheByHash(CacheHash fsHash);\n\tstatic LatteFetchShader* FindByGPUState();\n\n\tstatic std::unordered_map<CacheHash, LatteFetchShader*> s_fetchShaderByHash;\n};\n\nLatteFetchShader* LatteShaderRecompiler_createFetchShader(LatteFetchShader::CacheHash fsHash, uint32* contextRegister, uint32* fsProgramCode, uint32 fsProgramSize);\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/Latte.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"util/VirtualHeap/VirtualHeap.h\"\n\nstruct LatteTextureDefinition;\nclass LatteTexture;\nclass LatteTextureView;\n\nstruct gx2GPUSharedArea_t\n{\n\tvolatile uint32 flipRequestCountBE; // counts how many buffer swaps were requested\n\tvolatile uint32 flipExecuteCountBE; // counts how many buffer swaps were executed\n\tvolatile uint32 swapInterval; // vsync swap interval (0 means vsync is deactivated)\n};\n\nstruct LatteGPUState_t\n{\n\tunion\n\t{\n\t\tuint32 contextRegister[LATTE_MAX_REGISTER];\n\t\tLatteContextRegister contextNew;\n\t};\n\tMPTR contextRegisterShadowAddr[LATTE_MAX_REGISTER];\n\t// context control\n\tuint32 contextControl0;\n\tuint32 contextControl1;\n\t// optional features\n\tbool allowFramebufferSizeOptimization{false}; // allow using scissor box as size hint to determine non-padded rendertarget size\n\t// stats\n\tuint32 frameCounter;\n\tuint32 flipCounter; // increased by one everytime a vsync + flip happens\n\tuint32 currentDrawCallTick; // set to current time at the beginning of a drawcall\n\tuint32 drawCallCounter; // increased after every drawcall\n\tuint32 textureBindCounter; // increased at the beginning of _updateTextures()\n\tstd::atomic<uint64> flipRequestCount;\n\t// timer & vsync\n\tuint64 timer_frequency; // contains frequency of HPC\n\tuint64 timer_bootUp; // contains the timestamp of when the GPU thread timer was initialized\n\tuint64 timer_nextVSync;\n\t// shared\n\tgx2GPUSharedArea_t* sharedArea; // quick reference to shared area\n\tMPTR sharedAreaAddr;\n\t// other\n\tuint32 gx2InitCalled; // incremented every time GX2Init() is called\n\t// OpenGL control\n\tuint32 glVendor; // GLVENDOR_*\n\tbool isDRCPrimary = false;\n\t// temporary (replace with proper solution later)\n\tbool tvBufferUsesSRGB;\n\tbool drcBufferUsesSRGB;\n\tfloat tvGamma = 0.0f;\n\tfloat drcGamma = 0.0f;\n\t// draw state\n\tbool activeShaderHasError; // if try, at least one currently bound shader stage has an error and cannot be used for drawing\n\tbool repeatTextureInitialization; // if set during rendertarget or texture initialization, repeat the process (textures likely have been invalidated)\n\tbool requiresTextureBarrier; // set if glTextureBarrier should be called\n\t// OSScreen\n\tstruct  \n\t{\n\t\tstruct  \n\t\t{\n\t\t\tbool isEnabled;\n\t\t\tMPTR physPtr;\n\t\t\tstd::atomic<uint32> flipRequestCount;\n\t\t\tstd::atomic<uint32> flipExecuteCount;\n\t\t}screen[2];\n\t}osScreen;\n};\n\nextern LatteGPUState_t LatteGPUState;\n\n// texture\n\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n\n// texture loader\n\nvoid LatteTextureLoader_estimateAccessedDataRange(LatteTexture* texture, sint32 sliceIndex, sint32 mipIndex, uint32& addrStart, uint32& addrEnd);\n\n// render target\n\n#define RENDER_TARGET_TV (1 << 0)\n#define RENDER_TARGET_DRC (1 << 2)\n\nvoid LatteRenderTarget_updateScissorBox();\n\nvoid LatteRenderTarget_trackUpdates();\n\nvoid LatteRenderTarget_getScreenImageArea(sint32* x, sint32* y, sint32* width, sint32* height, sint32* fullWidth, sint32* fullHeight, bool padView = false);\nvoid LatteRenderTarget_copyToBackbuffer(LatteTextureView* textureView, bool isPadView);\n\nvoid LatteRenderTarget_GetCurrentVirtualViewportSize(sint32* viewportWidth, sint32* viewportHeight);\n\nvoid LatteRenderTarget_itHLESwapScanBuffer();\nvoid LatteRenderTarget_itHLEClearColorDepthStencil(uint32 clearMask, MPTR colorBufferMPTR, Latte::E_GX2SURFFMT colorBufferFormat, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferPitch, uint32 colorBufferViewFirstSlice, uint32 colorBufferViewNumSlice, MPTR depthBufferMPTR, Latte::E_GX2SURFFMT depthBufferFormat, Latte::E_HWTILEMODE depthBufferTileMode, sint32 depthBufferWidth, sint32 depthBufferHeight, sint32 depthBufferPitch, sint32 depthBufferViewFirstSlice, sint32 depthBufferViewNumSlice, float r, float g, float b, float a, float clearDepth, uint32 clearStencil);\nvoid LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferSliceIndex, uint32 colorBufferFormat, uint32 colorBufferPitch, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferSwizzle, uint32 renderTarget);\n\nvoid LatteRenderTarget_unloadAll();\n\n// surface copy\n\nvoid LatteSurfaceCopy_copySurfaceNew(MPTR srcPhysAddr, MPTR srcMipAddr, uint32 srcSwizzle, Latte::E_GX2SURFFMT srcSurfaceFormat, sint32 srcWidth, sint32 srcHeight, sint32 srcDepth, uint32 srcPitch, sint32 srcSlice, Latte::E_DIM srcDim, Latte::E_HWTILEMODE srcTilemode, sint32 srcAA, sint32 srcLevel, MPTR dstPhysAddr, MPTR dstMipAddr, uint32 dstSwizzle, Latte::E_GX2SURFFMT dstSurfaceFormat, sint32 dstWidth, sint32 dstHeight, sint32 dstDepth, uint32 dstPitch, sint32 dstSlice, Latte::E_DIM dstDim, Latte::E_HWTILEMODE dstTilemode, sint32 dstAA, sint32 dstLevel);\n\n// texture cache\n\nvoid LatteTC_Init();\n\nvoid LatteTC_RegisterTexture(LatteTexture* tex);\nvoid LatteTC_UnregisterTexture(LatteTexture* tex);\n\nuint32 LatteTexture_CalculateTextureDataHash(LatteTexture* hostTexture);\nvoid LatteTexture_ReloadData(LatteTexture* hostTexture);\n\nbool LatteTC_HasTextureChanged(LatteTexture* hostTexture, bool force = false);\nvoid LatteTC_ResetTextureChangeTracker(LatteTexture* hostTexture, bool force = false);\n\nvoid LatteTC_MarkTextureStillInUse(LatteTexture* texture); // lets the texture garbage collector know the texture is still in use at the time of this function call\nvoid LatteTC_CleanupUnusedTextures();\n\nstd::vector<LatteTexture*> LatteTC_GetDeleteableTextures();\n\nvoid LatteTC_UnloadAllTextures();\n\n// texture readback\n\nvoid LatteTextureReadback_Initate(LatteTextureView* textureView);\nvoid LatteTextureReadback_StartTransfer(LatteTextureView* textureView);\nbool LatteTextureReadback_Update(bool forceStart = false);\nvoid LatteTextureReadback_NotifyTextureDeletion(LatteTexture* texture);\nvoid LatteTextureReadback_UpdateFinishedTransfers(bool forceFinish);\n\n// query\n\nvoid LatteQuery_Init();\nvoid LatteQuery_BeginOcclusionQuery(MPTR queryMPTR);\nvoid LatteQuery_EndOcclusionQuery(MPTR queryMPTR);\nvoid LatteQuery_UpdateFinishedQueries();\nvoid LatteQuery_UpdateFinishedQueriesForceFinishAll();\nvoid LatteQuery_CancelActiveGPU7Queries();\n\n// streamout\n\nvoid LatteStreamout_InitCache();\nsint32 LatteStreamout_GetRingBufferSize();\nvoid LatteStreamout_PrepareDrawcall(uint32 count, uint32 instanceCount);\nvoid LatteStreamout_FinishDrawcall(bool useDirectMemoryMode);\n\n// timing\n\nvoid LatteTiming_Init();\nvoid LatteTiming_HandleTimedVsync();\n\n// command processor\n\nvoid LatteCP_ProcessRingbuffer();\n\n// buffer cache\n\nbool LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount);\nvoid LatteBufferCache_LoadRemappedUniforms(struct LatteDecompilerShader* shader, float* uniformData);\n\nvoid LatteRenderTarget_updateViewport();\n\n#define LATTE_GLSL_DYNAMIC_UNIFORM_BLOCK_SIZE\t(4096) // maximum size for uniform blocks (in vec4s). On Nvidia hardware 4096 is the maximum (64K / 16 = 4096) all other vendors have much higher limits\n\n//static uint32 glTempError;\n//#define catchOpenGLError() glFinish(); if( (glTempError = glGetError()) != 0 ) { printf(\"OpenGL error 0x%x: %s : %d timestamp %08x\\n\", glTempError, __FILE__, __LINE__, GetTickCount()); __debugbreak(); }\n\n#define catchOpenGLError()\n\n// Latte emulation control\nvoid Latte_Start();\nvoid Latte_Stop();\nbool Latte_GetStopSignal(); // returns true if stop was requested or if in stopped state\nvoid LatteThread_Exit();"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteAsyncCommands.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteAsyncCommands.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n\nvoid LatteThread_Exit();\n\nSlimRWLock swl_gpuAsyncCommands;\n\ntypedef struct  \n{\n\tuint32 type;\n\tunion\n\t{\n\t\tstruct\n\t\t{\n\t\t\tMPTR physAddr;\n\t\t\tMPTR mipAddr;\n\t\t\tuint32 swizzle;\n\t\t\tsint32 format;\n\t\t\tsint32 width;\n\t\t\tsint32 height;\n\t\t\tsint32 depth;\n\t\t\tuint32 pitch;\n\t\t\tuint32 slice;\n\t\t\tsint32 dim;\n\t\t\tLatte::E_HWTILEMODE tilemode;\n\t\t\tsint32 aa;\n\t\t\tsint32 level;\n\t\t}forceTextureReadback;\n\n\t\tstruct\n\t\t{\n\t\t\tuint64 shaderBaseHash; \n\t\t\tuint64 shaderAuxHash; \n\t\t\tLatteConst::ShaderType shaderType;\n\t\t}deleteShader;\n\t};\n}LatteAsyncCommand_t;\n\n#define ASYNC_CMD_FORCE_TEXTURE_READBACK\t\t1\n#define ASYNC_CMD_DELETE_SHADER\t\t\t\t\t2\n\nstd::queue<LatteAsyncCommand_t> LatteAsyncCommandQueue;\n\nvoid LatteAsyncCommands_queueForceTextureReadback(MPTR physAddr, MPTR mipAddr, uint32 swizzle, sint32 format, sint32 width, sint32 height, sint32 depth, uint32 pitch, uint32 slice, sint32 dim, Latte::E_HWTILEMODE tilemode, sint32 aa, sint32 level)\n{\n\tLatteAsyncCommand_t asyncCommand = {};\n\t// setup command\n\tasyncCommand.type = ASYNC_CMD_FORCE_TEXTURE_READBACK;\n\t\n\tasyncCommand.forceTextureReadback.physAddr = physAddr;\n\tasyncCommand.forceTextureReadback.mipAddr = mipAddr;\n\tasyncCommand.forceTextureReadback.swizzle = swizzle;\n\tasyncCommand.forceTextureReadback.format = format;\n\tasyncCommand.forceTextureReadback.width = width;\n\tasyncCommand.forceTextureReadback.height = height;\n\tasyncCommand.forceTextureReadback.depth = depth;\n\tasyncCommand.forceTextureReadback.pitch = pitch;\n\tasyncCommand.forceTextureReadback.slice = slice;\n\tasyncCommand.forceTextureReadback.dim = dim;\n\tasyncCommand.forceTextureReadback.tilemode = tilemode;\n\tasyncCommand.forceTextureReadback.aa = aa;\n\tasyncCommand.forceTextureReadback.level = level;\n\tswl_gpuAsyncCommands.LockWrite();\n\tLatteAsyncCommandQueue.push(asyncCommand);\n\tswl_gpuAsyncCommands.UnlockWrite();\n}\n\nvoid LatteAsyncCommands_queueDeleteShader(uint64 shaderBaseHash, uint64 shaderAuxHash, LatteConst::ShaderType shaderType)\n{\n\tLatteAsyncCommand_t asyncCommand = {};\n\t// setup command\n\tasyncCommand.type = ASYNC_CMD_DELETE_SHADER;\n\n\tasyncCommand.deleteShader.shaderBaseHash = shaderBaseHash;\n\tasyncCommand.deleteShader.shaderAuxHash = shaderAuxHash;\n\tasyncCommand.deleteShader.shaderType = shaderType;\n\n\tswl_gpuAsyncCommands.LockWrite();\n\tLatteAsyncCommandQueue.push(asyncCommand);\n\tswl_gpuAsyncCommands.UnlockWrite();\n}\n\nvoid LatteAsyncCommands_waitUntilAllProcessed()\n{\n\twhile (LatteAsyncCommandQueue.empty() == false)\n\t{\n\t\t_mm_pause();\n\t}\n}\n\n/*\n * Called by the GPU command processor frequently\n */\nvoid LatteAsyncCommands_checkAndExecute()\n{\n\t// quick check if queue is empty (requires no lock)\n\tif (Latte_GetStopSignal())\n\t\tLatteThread_Exit();\n\tif (LatteAsyncCommandQueue.empty())\n\t\treturn;\n\tswl_gpuAsyncCommands.LockWrite();\n\twhile (LatteAsyncCommandQueue.empty() == false)\n\t{\n\t\t// get first command in queue\n\t\tLatteAsyncCommand_t asyncCommand = LatteAsyncCommandQueue.front();\n\t\tswl_gpuAsyncCommands.UnlockWrite();\n\t\tif (asyncCommand.type == ASYNC_CMD_FORCE_TEXTURE_READBACK)\n\t\t{\n\t\t\tcemu_assert_debug(asyncCommand.forceTextureReadback.level == 0); // implement mip swizzle and verify\n\t\t\tLatteTextureView* textureView = LatteTC_GetTextureSliceViewOrTryCreate(asyncCommand.forceTextureReadback.physAddr, asyncCommand.forceTextureReadback.mipAddr, (Latte::E_GX2SURFFMT)asyncCommand.forceTextureReadback.format, asyncCommand.forceTextureReadback.tilemode, asyncCommand.forceTextureReadback.width, asyncCommand.forceTextureReadback.height, asyncCommand.forceTextureReadback.depth, asyncCommand.forceTextureReadback.pitch, 0, asyncCommand.forceTextureReadback.slice, asyncCommand.forceTextureReadback.level);\n\t\t\tif (textureView != nullptr)\n\t\t\t{\n\t\t\t\tLatteTexture_UpdateDataToLatest(textureView->baseTexture);\n\t\t\t\t// start transfer\n\t\t\t\tLatteTextureReadback_StartTransfer(textureView);\n\t\t\t\t// wait until finished\n\t\t\t\tLatteTextureReadback_UpdateFinishedTransfers(true);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Texture not found for readback\");\n\t\t\t}\n\t\t}\n\t\telse if (asyncCommand.type == ASYNC_CMD_DELETE_SHADER)\n\t\t{\n\t\t\tLatteSHRC_RemoveFromCacheByHash(asyncCommand.deleteShader.shaderBaseHash, asyncCommand.deleteShader.shaderAuxHash, asyncCommand.deleteShader.shaderType);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\tswl_gpuAsyncCommands.LockWrite();\n\t\tLatteAsyncCommandQueue.pop();\n\t}\n\tswl_gpuAsyncCommands.UnlockWrite();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteAsyncCommands.h",
    "content": "#pragma once\n\nvoid LatteAsyncCommands_queueForceTextureReadback(MPTR physAddr, MPTR mipAddr, uint32 swizzle, sint32 format, sint32 width, sint32 height, sint32 depth, uint32 pitch, uint32 slice, sint32 dim, Latte::E_HWTILEMODE tilemode, sint32 aa, sint32 level);\nvoid LatteAsyncCommands_queueDeleteShader(uint64 shaderBaseHash, uint64 shaderAuxHash, LatteConst::ShaderType shaderType);\nvoid LatteAsyncCommands_waitUntilAllProcessed();\n\nvoid LatteAsyncCommands_checkAndExecute();"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteBufferCache.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"util/ChunkedHeap/ChunkedHeap.h\"\n#include \"util/helpers/fspinlock.h\"\n#include \"config/ActiveSettings.h\"\n\n#define CACHE_PAGE_SIZE\t\t0x400\n#define CACHE_PAGE_SIZE_M1\t(CACHE_PAGE_SIZE-1)\n\nuint32 g_currentCacheChronon = 0;\n\ntemplate<typename TRangeData, typename TNodeObject>\nclass IntervalTree2\n{\n\t// TNodeObject will be interfaced with via callbacks to static methods\n\n\t// static TNodeObject* Create(TRangeData rangeBegin, TRangeData rangeEnd, std::span<TNodeObject*> overlappingObjects)\n\t// Create a new node with the given range. overlappingObjects contains all the nodes that are replaced by this operation. The callee has to delete all objects in overlappingObjects (Delete callback wont be invoked)\n\n\t// static void Delete(TNodeObject* nodeObject)\n\t// Delete a node object. Replacement operations won't trigger this callback and instead pass the objects to Create()\n\n\t// static void Resize(TNodeObject* nodeObject, TRangeData rangeBegin, TRangeData rangeEnd)\n\t// Shrink or extend an existing range\n\n\t// static TNodeObject* Split(TNodeObject* nodeObject, TRangeData firstRangeBegin, TRangeData firstRangeEnd, TRangeData secondRangeBegin, TRangeData secondRangeEnd)\n\t// Cut a hole into an existing range and split it in two. Should return the newly created node object after the hole\n\n\tstatic_assert(!std::is_pointer_v<TNodeObject>, \"TNodeObject must be a non-pointer type\");\n\n\tstruct InternalRange\n\t{\n\t\tInternalRange() = default;\n\t\tInternalRange(TRangeData _rangeBegin, TRangeData _rangeEnd) : rangeBegin(_rangeBegin), rangeEnd(_rangeEnd) { cemu_assert_debug(_rangeBegin < _rangeEnd); };\n\n\t\tTRangeData rangeBegin;\n\t\tTRangeData rangeEnd;\n\n\t\tbool operator<(const InternalRange& rhs) const\n\t\t{\n\t\t\t// use <= instead of < because ranges are allowed to touch (e.g. 10-20 and 20-30 dont get merged)\n\t\t\treturn this->rangeEnd <= rhs.rangeBegin;\n\t\t}\n\n\t};\n\n\tstd::map<InternalRange, TNodeObject*> m_map;\n\tstd::vector<TNodeObject*> m_tempObjectArray;\n\npublic:\n\tTNodeObject* getRange(TRangeData rangeBegin, TRangeData rangeEnd)\n\t{\n\t\tauto itr = m_map.find(InternalRange(rangeBegin, rangeEnd));\n\t\tif (itr == m_map.cend())\n\t\t\treturn nullptr;\n\t\tif (rangeBegin < (*itr).first.rangeBegin)\n\t\t\treturn nullptr;\n\t\tif (rangeEnd > (*itr).first.rangeEnd)\n\t\t\treturn nullptr;\n\t\treturn (*itr).second;\n\t}\n\n\tTNodeObject* getRangeByPoint(TRangeData rangeOffset)\n\t{\n\t\tauto itr = m_map.find(InternalRange(rangeOffset, rangeOffset+1)); // todo - better to use custom comparator instead of +1?\n\t\tif (itr == m_map.cend())\n\t\t\treturn nullptr;\n\t\tcemu_assert_debug(rangeOffset >= (*itr).first.rangeBegin);\n\t\tcemu_assert_debug(rangeOffset < (*itr).first.rangeEnd);\n\t\treturn (*itr).second;\n\t}\n\n\tvoid addRange(TRangeData rangeBegin, TRangeData rangeEnd)\n\t{\n\t\tif (rangeEnd == rangeBegin)\n\t\t\treturn;\n\t\tInternalRange range(rangeBegin, rangeEnd);\n\t\tauto itr = m_map.find(range);\n\t\tif (itr == m_map.cend())\n\t\t{\n\t\t\t// new entry\n\t\t\tm_map.emplace(range, TNodeObject::Create(rangeBegin, rangeEnd, std::span<TNodeObject*>()));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// overlap detected\n\t\t\tif (rangeBegin >= (*itr).first.rangeBegin && rangeEnd <= (*itr).first.rangeEnd)\n\t\t\t\treturn; // do nothing if added range is already covered\n\t\t\trangeBegin = (std::min)(rangeBegin, (*itr).first.rangeBegin);\n\t\t\t// DEBUG - make sure this is the start point of the merge process (the first entry that starts below minValue)\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tif (itr != m_map.cbegin())\n\t\t\t{\n\t\t\t\t// check previous result\n\t\t\t\tauto itrCopy = itr;\n\t\t\t\t--itrCopy;\n\t\t\t\tif ((*itrCopy).first.rangeEnd > rangeBegin)\n\t\t\t\t{\n\t\t\t\t\tassert_dbg(); // n-1 entry is also overlapping\n\t\t\t\t\trangeBegin = (std::min)(rangeBegin, (*itrCopy).first.rangeBegin);\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t\t// DEBUG - END\n\t\t\t// collect and remove all overlapping ranges\n\t\t\tsize_t count = 0;\n\t\t\twhile (itr != m_map.cend() && (*itr).first.rangeBegin < rangeEnd)\n\t\t\t{\n\t\t\t\trangeEnd = (std::max)(rangeEnd, (*itr).first.rangeEnd);\n\t\t\t\tif (m_tempObjectArray.size() <= count)\n\t\t\t\t\tm_tempObjectArray.resize(count + 8);\n\t\t\t\tm_tempObjectArray[count] = (*itr).second;\n\t\t\t\tcount++;\n\t\t\t\tauto tempItr = itr;\n\t\t\t\t++itr;\n\t\t\t\tm_map.erase(tempItr);\n\t\t\t}\n\n\t\t\t// create callback\n\t\t\tTNodeObject* newObject = TNodeObject::Create(rangeBegin, rangeEnd, std::span<TNodeObject*>(m_tempObjectArray.data(), count));\n\t\t\tm_map.emplace(InternalRange(rangeBegin, rangeEnd), newObject);\n\t\t}\n\t}\n\n\tvoid removeRange(TRangeData rangeBegin, TRangeData rangeEnd)\n\t{\n\t\tInternalRange range(rangeBegin, rangeEnd);\n\t\tauto itr = m_map.find(range);\n\t\tif (itr == m_map.cend())\n\t\t\treturn;\n\t\tcemu_assert_debug(itr == m_map.lower_bound(range));\n\t\twhile (itr != m_map.cend() && (*itr).first.rangeBegin < rangeEnd)\n\t\t{\n\t\t\tif ((*itr).first.rangeBegin >= rangeBegin && (*itr).first.rangeEnd <= rangeEnd)\n\t\t\t{\n\t\t\t\t// delete entire range\n\t\t\t\tauto itrCopy = itr;\n\t\t\t\tTNodeObject* t = (*itr).second;\n\t\t\t\t++itr;\n\t\t\t\tm_map.erase(itrCopy);\n\t\t\t\tTNodeObject::Delete(t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (rangeBegin > (*itr).first.rangeBegin && rangeEnd < (*itr).first.rangeEnd)\n\t\t\t{\n\t\t\t\t// cut hole into existing range\n\t\t\t\tTRangeData firstRangeBegin = (*itr).first.rangeBegin;\n\t\t\t\tTRangeData firstRangeEnd = rangeBegin;\n\t\t\t\tTRangeData secondRangeBegin = rangeEnd;\n\t\t\t\tTRangeData secondRangeEnd = (*itr).first.rangeEnd;\n\t\t\t\tTNodeObject* newObject = TNodeObject::Split((*itr).second, firstRangeBegin, firstRangeEnd, secondRangeBegin, secondRangeEnd);\n\t\t\t\t// modify key\n\t\t\t\tauto nh = m_map.extract(itr);\n\t\t\t\tnh.key().rangeBegin = firstRangeBegin;\n\t\t\t\tnh.key().rangeEnd = firstRangeEnd;\n\t\t\t\tm_map.insert(std::move(nh));\n\t\t\t\t// insert new object after hole\n\t\t\t\tm_map.emplace(InternalRange(secondRangeBegin, secondRangeEnd), newObject);\n\t\t\t\treturn; // done\n\t\t\t}\n\t\t\t// shrink (trim either beginning or end)\n\t\t\tTRangeData newRangeBegin;\n\t\t\tTRangeData newRangeEnd;\n\t\t\tif ((rangeBegin <= (*itr).first.rangeBegin && rangeEnd < (*itr).first.rangeEnd))\n\t\t\t{\n\t\t\t\t// trim from beginning\n\t\t\t\tnewRangeBegin = (std::max)((*itr).first.rangeBegin, rangeEnd);\n\t\t\t\tnewRangeEnd = (*itr).first.rangeEnd;\n\t\t\t}\n\t\t\telse if ((rangeBegin > (*itr).first.rangeBegin && rangeEnd >= (*itr).first.rangeEnd))\n\t\t\t{\n\t\t\t\t// trim from end\n\t\t\t\tnewRangeBegin = (*itr).first.rangeBegin;\n\t\t\t\tnewRangeEnd = (std::min)((*itr).first.rangeEnd, rangeBegin);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tassert_dbg(); // should not happen\n\t\t\t}\n\t\t\tTNodeObject::Resize((*itr).second, newRangeBegin, newRangeEnd);\n\t\t\t// modify key and increment iterator\n\t\t\tauto itrCopy = itr;\n\t\t\t++itr;\n\t\t\tauto nh = m_map.extract(itrCopy);\n\t\t\tnh.key().rangeBegin = newRangeBegin;\n\t\t\tnh.key().rangeEnd = newRangeEnd;\n\t\t\tm_map.insert(std::move(nh));\n\t\t}\n\t}\n\n\t// remove existing range that matches given begin and end\n\tvoid removeRangeSingle(TRangeData rangeBegin, TRangeData rangeEnd)\n\t{\n\t\tInternalRange range(rangeBegin, rangeEnd);\n\t\tauto itr = m_map.find(range);\n\t\tcemu_assert_debug(itr != m_map.cend());\n\t\tif (itr == m_map.cend())\n\t\t\treturn;\n\t\tcemu_assert_debug((*itr).first.rangeBegin == rangeBegin && (*itr).first.rangeEnd == rangeEnd);\n\t\t// delete entire range\n\t\tTNodeObject* t = (*itr).second;\n\t\tm_map.erase(itr);\n\t\tTNodeObject::Delete(t);\n\t}\n\n\t// remove existing range that matches given begin and end without calling delete callback\n\tvoid removeRangeSingleWithoutCallback(TRangeData rangeBegin, TRangeData rangeEnd)\n\t{\n\t\tInternalRange range(rangeBegin, rangeEnd);\n\t\tauto itr = m_map.find(range);\n\t\tcemu_assert_debug(itr != m_map.cend());\n\t\tif (itr == m_map.cend())\n\t\t\treturn;\n\t\tcemu_assert_debug((*itr).first.rangeBegin == rangeBegin && (*itr).first.rangeEnd == rangeEnd);\n\t\t// delete entire range\n\t\tTNodeObject* t = (*itr).second;\n\t\tm_map.erase(itr);\n\t}\n\n\tvoid splitRange(TRangeData rangeOffset)\n\t{\n\t\t// not well tested\n\t\tremoveRange(rangeOffset, rangeOffset+1);\n\t}\n\n\ttemplate<typename TFunc>\n\tvoid forEachOverlapping(TRangeData rangeBegin, TRangeData rangeEnd, TFunc f)\n\t{\n\t\tInternalRange range(rangeBegin, rangeEnd);\n\t\tauto itr = m_map.find(range);\n\t\tif (itr == m_map.cend())\n\t\t\treturn;\n\t\tcemu_assert_debug(itr == m_map.lower_bound(range));\n\t\twhile (itr != m_map.cend() && (*itr).first.rangeBegin < rangeEnd)\n\t\t{\n\t\t\tf((*itr).second, rangeBegin, rangeEnd);\n\t\t\t++itr;\n\t\t}\n\t}\n\n\tvoid validate()\n\t{\n\t\tif (m_map.empty())\n\t\t\treturn;\n\t\tauto itr = m_map.begin();\n\t\tif ((*itr).first.rangeBegin > (*itr).first.rangeEnd)\n\t\t\tassert_dbg();\n\t\tTRangeData currentLoc = (*itr).first.rangeEnd;\n\t\t++itr;\n\t\twhile (itr != m_map.end())\n\t\t{\n\t\t\tif ((*itr).first.rangeBegin >= (*itr).first.rangeEnd)\n\t\t\t\tassert_dbg(); // negative or zero size ranges are not allowed\n\t\t\tif (currentLoc > (*itr).first.rangeBegin)\n\t\t\t\tassert_dbg(); // stored ranges must not overlap\n\t\t\tcurrentLoc = (*itr).first.rangeEnd;\n\t\t\t++itr;\n\t\t}\n\t}\n\n    bool empty() const\n    {\n        return m_map.empty();\n    }\n\n\tconst std::map<InternalRange, TNodeObject*>& getAll() const { return m_map; };\n};\n\nstd::unique_ptr<VHeap> g_gpuBufferHeap = nullptr;\nstd::vector<uint8> s_pageUploadBuffer;\nstd::vector<class BufferCacheNode*> s_allCacheNodes;\n\nvoid LatteBufferCache_removeSingleNodeFromTree(BufferCacheNode* node);\n\nclass BufferCacheNode\n{\n\tstatic inline constexpr uint64 c_streamoutSig0 = 0xF0F0F0F0155C5B6Aull;\n\tstatic inline constexpr uint64 c_streamoutSig1 = 0x8BE6336411814F4Full;\n\npublic:\n\t// returns false if not enough space is available\n\tbool allocateCacheMemory()\n\t{\n\t\tcemu_assert_debug(m_hasCacheAlloc == false);\n\t\tcemu_assert_debug(m_rangeEnd > m_rangeBegin);\n\t\tm_hasCacheAlloc = g_gpuBufferHeap->allocOffset(m_rangeEnd - m_rangeBegin, CACHE_PAGE_SIZE, m_cacheOffset);\n\t\treturn m_hasCacheAlloc;\n\t}\n\n\tvoid ReleaseCacheMemoryImmediately()\n\t{\n\t\tif (m_hasCacheAlloc)\n\t\t{\n\t\t\tg_gpuBufferHeap->freeOffset(m_cacheOffset);\n\t\t\tm_hasCacheAlloc = false;\n\t\t}\n\t}\n\n\tuint32 getBufferOffset(MPTR physAddr) const\n\t{\n\t\tcemu_assert_debug(m_hasCacheAlloc);\n\t\tcemu_assert_debug(physAddr >= m_rangeBegin);\n\t\tcemu_assert_debug(physAddr < m_rangeEnd);\n\t\tuint32 relOffset = physAddr - m_rangeBegin;\n\t\treturn m_cacheOffset + relOffset;\n\t}\n\n\tvoid writeStreamout(MPTR rangeBegin, MPTR rangeEnd)\n\t{\n\t\tif ((rangeBegin & 0xF))\n\t\t{\n\t\t\tcemuLog_logDebugOnce(LogType::Force, \"writeStreamout(): RangeBegin not aligned to 16. Begin {:08x} End {:08x}\", rangeBegin, rangeEnd);\n\t\t\trangeBegin = (rangeBegin + 0xF) & ~0xF;\n\t\t\trangeEnd = std::max(rangeBegin, rangeEnd);\n\t\t}\n\t\tif (rangeEnd & 0xF)\n\t\t{\n\t\t\t// todo - add support for 4 byte granularity for streamout writes and cache\n\t\t\t// used by Affordable Space Adventures and YWW Level 1-8\n\t\t\t// also used by CoD Ghosts (8 byte granularity)\n\t\t\t//cemuLog_logDebug(LogType::Force, \"Streamout write size is not aligned to 16 bytes\");\n\t\t\trangeEnd &= ~0xF;\n\t\t}\n\t\t//cemu_assert_debug((rangeEnd & 0xF) == 0);\n\t\trangeBegin = std::max(rangeBegin, m_rangeBegin);\n\t\trangeEnd = std::min(rangeEnd, m_rangeEnd);\n\t\tif (rangeBegin >= rangeEnd)\n\t\t\treturn;\n\t\tsint32 numPages = getPageCountFromRange(rangeBegin, rangeEnd);\n\t\tsint32 pageIndex = getPageIndexFromAddr(rangeBegin);\n\n\t\tcemu_assert_debug((m_rangeBegin + pageIndex * CACHE_PAGE_SIZE) <= rangeBegin);\n\t\tcemu_assert_debug((m_rangeBegin + (pageIndex + numPages) * CACHE_PAGE_SIZE) >= rangeEnd);\n\n\t\tfor (sint32 i = 0; i < numPages; i++)\n\t\t{\n\t\t\tpageWriteStreamoutSignatures(pageIndex, rangeBegin, rangeEnd);\n\t\t\tpageIndex++;\n\t\t\t//pageInfo->hasStreamoutData = true;\n\t\t\t//pageInfo++;\n\t\t}\n\t\tif (numPages > 0)\n\t\t\tm_hasStreamoutData = true;\n\t}\n\n\tvoid checkAndSyncModifications(MPTR rangeBegin, MPTR rangeEnd, bool uploadData)\n\t{\n\t\tcemu_assert_debug(rangeBegin >= m_rangeBegin);\n\t\tcemu_assert_debug(rangeEnd <= m_rangeEnd);\n\t\tcemu_assert_debug(rangeBegin < m_rangeEnd);\n\t\tcemu_assert_debug((rangeBegin % CACHE_PAGE_SIZE) == 0);\n\t\tcemu_assert_debug((rangeEnd % CACHE_PAGE_SIZE) == 0);\n\n\t\tsint32 basePageIndex = getPageIndexFromAddrAligned(rangeBegin);\n\t\tsint32 numPages = getPageCountFromRangeAligned(rangeBegin, rangeEnd);\n\t\tuint8* pagePtr = memory_getPointerFromPhysicalOffset(rangeBegin);\n\t\tsint32 uploadPageBegin = -1;\n\t\tCachePageInfo* pageInfo = m_pageInfo.data() + basePageIndex;\n\t\tfor (sint32 i = 0; i < numPages; i++)\n\t\t{\n\t\t\tif (pageInfo->hasStreamoutData)\n\t\t\t{\n\t\t\t\t// first upload any pending sequence of pages\n\t\t\t\tif (uploadPageBegin != -1)\n\t\t\t\t{\n\t\t\t\t\t// upload range\n\t\t\t\t\tif (uploadData)\n\t\t\t\t\t\tuploadPages(uploadPageBegin, basePageIndex + i);\n\t\t\t\t\tuploadPageBegin = -1;\n\t\t\t\t}\n\t\t\t\t// check if hash changed\n\t\t\t\tuint64 pageHash = hashPage(pagePtr);\n\t\t\t\tif (pageInfo->hash != pageHash)\n\t\t\t\t{\n\t\t\t\t\tpageInfo->hash = pageHash;\n\t\t\t\t\t// for pages that contain streamout data we do uploads with a much smaller granularity\n\t\t\t\t\t// and skip uploading any data that is marked with streamout filler bytes\n\t\t\t\t\tif (!uploadPageWithStreamoutFiltered(basePageIndex + i))\n\t\t\t\t\t\tpageInfo->hasStreamoutData = false; // all streamout data was replaced\n\t\t\t\t}\n\t\t\t\tpagePtr += CACHE_PAGE_SIZE;\n\t\t\t\tpageInfo++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tuint64 pageHash = hashPage(pagePtr);\n\t\t\tpagePtr += CACHE_PAGE_SIZE;\n\t\t\tif (pageInfo->hash != pageHash)\n\t\t\t{\n\t\t\t\tif (uploadPageBegin == -1)\n\t\t\t\t\tuploadPageBegin = i + basePageIndex;\n\t\t\t\tpageInfo->hash = pageHash;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (uploadPageBegin != -1)\n\t\t\t\t{\n\t\t\t\t\t// upload range\n\t\t\t\t\tif (uploadData)\n\t\t\t\t\t\tuploadPages(uploadPageBegin, basePageIndex + i);\n\t\t\t\t\tuploadPageBegin = -1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tpageInfo++;\n\t\t}\n\t\tif (uploadPageBegin != -1)\n\t\t{\n\t\t\tif (uploadData)\n\t\t\t\tuploadPages(uploadPageBegin, basePageIndex + numPages);\n\t\t}\n\t}\n\n\tvoid checkAndSyncModifications(bool uploadData)\n\t{\n\t\tcheckAndSyncModifications(m_rangeBegin, m_rangeEnd, uploadData);\n\t\tm_lastModifyCheckCronon = g_currentCacheChronon;\n\t\tm_hasInvalidation = false;\n\t}\n\n\tvoid checkAndSyncModificationsIfChrononChanged(MPTR reservePhysAddress, uint32 reserveSize)\n\t{\n\t\tif (m_lastModifyCheckCronon != g_currentCacheChronon)\n\t\t{\n\t\t\tm_lastModifyCheckCronon = g_currentCacheChronon;\n\t\t\tcheckAndSyncModifications(m_rangeBegin, m_rangeEnd, true);\n\t\t\tm_hasInvalidation = false;\n\t\t}\n\t\tif (m_hasInvalidation)\n\t\t{\n\t\t\t// ideally we would only upload the pages that intersect both the reserve range and the invalidation range\n\t\t\t// but this would require complex per-page tracking of invalidation. Since this is on a hot path we do a cheap approximation\n\t\t\t// where we only track one continous invalidation range\n\n\t\t\t// try to bound uploads to the reserve range within the invalidation\n\t\t\tuint32 resRangeBegin = reservePhysAddress & ~CACHE_PAGE_SIZE_M1;\n\t\t\tuint32 resRangeEnd = ((reservePhysAddress + reserveSize) + CACHE_PAGE_SIZE_M1) & ~CACHE_PAGE_SIZE_M1;\n\n\t\t\tuint32 uploadBegin = std::max(m_invalidationRangeBegin, resRangeBegin);\n\t\t\tuint32 uploadEnd = std::min(resRangeEnd, m_invalidationRangeEnd);\n\n\t\t\tif (uploadBegin >= uploadEnd)\n\t\t\t\treturn; // reserve range not within invalidation or range is zero sized\n\n\n\t\t\tif (uploadBegin == m_invalidationRangeBegin)\n\t\t\t{\n\t\t\t\tm_invalidationRangeBegin = uploadEnd;\n\t\t\t\tcheckAndSyncModifications(uploadBegin, uploadEnd, true);\n\t\t\t}\n\t\t\tif (uploadEnd == m_invalidationRangeEnd)\n\t\t\t{\n\t\t\t\tm_invalidationRangeEnd = uploadBegin;\n\t\t\t\tcheckAndSyncModifications(uploadBegin, uploadEnd, true);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// upload all of invalidation\n\t\t\t\tcheckAndSyncModifications(m_invalidationRangeBegin, m_invalidationRangeEnd, true);\n\t\t\t\tm_invalidationRangeBegin = m_invalidationRangeEnd;\n\t\t\t}\n\t\t\tif(m_invalidationRangeEnd <= m_invalidationRangeBegin)\n\t\t\t\tm_hasInvalidation = false;\n\t\t}\n\t}\n\n\tvoid invalidate(MPTR rangeBegin, MPTR rangeEnd)\n\t{\n\t\trangeBegin = std::max(rangeBegin, m_rangeBegin);\n\t\trangeEnd = std::min(rangeEnd, m_rangeEnd);\n\t\tif (rangeBegin >= rangeEnd)\n\t\t\treturn;\n\t\tif (m_hasInvalidation)\n\t\t{\n\t\t\tm_invalidationRangeBegin = std::min(m_invalidationRangeBegin, rangeBegin);\n\t\t\tm_invalidationRangeEnd = std::max(m_invalidationRangeEnd, rangeEnd);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_invalidationRangeBegin = rangeBegin;\n\t\t\tm_invalidationRangeEnd = rangeEnd;\n\t\t\tm_hasInvalidation = true;\n\t\t}\n\t\tcemu_assert_debug(m_invalidationRangeBegin >= m_rangeBegin);\n\t\tcemu_assert_debug(m_invalidationRangeEnd <= m_rangeEnd);\n\t\tcemu_assert_debug(m_invalidationRangeBegin < m_invalidationRangeEnd);\n\t\tm_invalidationRangeBegin = m_invalidationRangeBegin & ~CACHE_PAGE_SIZE_M1;\n\t\tm_invalidationRangeEnd = (m_invalidationRangeEnd + CACHE_PAGE_SIZE_M1) & ~CACHE_PAGE_SIZE_M1;\n\t}\n\n\tvoid flagInUse()\n\t{\n\t\tm_lastDrawcall = LatteGPUState.drawCallCounter;\n\t\tm_lastFrame = LatteGPUState.frameCounter;\n\t}\n\n\tbool isInUse() const\n\t{\n\t\treturn m_lastDrawcall == LatteGPUState.drawCallCounter;\n\t}\n\n\t// returns true if the range does not contain any GPU-cache-only data and can be fully restored from RAM\n\tbool isRAMOnly() const\n\t{\n\t\treturn !m_hasStreamoutData;\n\t}\n\n\tMPTR GetRangeBegin() const { return m_rangeBegin; }\n\tMPTR GetRangeEnd() const { return m_rangeEnd; }\n\n\tuint32 GetDrawcallAge() const { return LatteGPUState.drawCallCounter - m_lastDrawcall; };\n\tuint32 GetFrameAge() const { return LatteGPUState.frameCounter - m_lastFrame; };\n\n\tbool HasStreamoutData() const { return m_hasStreamoutData; };\n\nprivate:\n\tstruct CachePageInfo\n\t{\n\t\tuint64 hash{ 0 };\n\t\tbool hasStreamoutData{ false };\n\t};\n\n\tMPTR m_rangeBegin;\n\tMPTR m_rangeEnd; // (exclusive)\n\tbool m_hasCacheAlloc{ false };\n\tuint32 m_cacheOffset{ 0 };\n\t// usage\n\tuint32 m_lastDrawcall;\n\tuint32 m_lastFrame;\n\tuint32 m_arrayIndex;\n\t// state tracking\n\tuint32 m_lastModifyCheckCronon{ g_currentCacheChronon - 1 };\n\tstd::vector<CachePageInfo> m_pageInfo;\n\tbool m_hasStreamoutData{ false };\n\t// invalidation\n\tbool m_hasInvalidation{false};\n\tMPTR m_invalidationRangeBegin;\n\tMPTR m_invalidationRangeEnd;\n\n\tBufferCacheNode(MPTR rangeBegin, MPTR rangeEnd): m_rangeBegin(rangeBegin), m_rangeEnd(rangeEnd)\n\t{\n\t\tflagInUse();\n\t\tcemu_assert_debug(rangeBegin < rangeEnd);\n\t\tsize_t numPages = getPageCountFromRangeAligned(rangeBegin, rangeEnd);\n\t\tm_pageInfo.resize(numPages);\n\t\t// append to array\n\t\tm_arrayIndex = (uint32)s_allCacheNodes.size();\n\t\ts_allCacheNodes.emplace_back(this);\n\t};\n\n\t~BufferCacheNode()\n\t{\n\t\tif (m_hasCacheAlloc)\n\t\t\tg_deallocateQueue.emplace_back(m_cacheOffset); // release after current drawcall\n\t\t// remove from array\n\t\tauto temp = s_allCacheNodes.back();\n\t\ts_allCacheNodes.pop_back();\n\t\tif (this != temp)\n\t\t{\n\t\t\ts_allCacheNodes[m_arrayIndex] = temp;\n\t\t\ttemp->m_arrayIndex = m_arrayIndex;\n\t\t}\n\t}\n\n\tuint32 getPageIndexFromAddrAligned(uint32 offset) const\n\t{\n\t\tcemu_assert_debug((offset % CACHE_PAGE_SIZE) == 0);\n\t\treturn (offset - m_rangeBegin) / CACHE_PAGE_SIZE;\n\t}\n\n\tuint32 getPageIndexFromAddr(uint32 offset) const\n\t{\n\t\toffset &= ~CACHE_PAGE_SIZE_M1;\n\t\treturn (offset - m_rangeBegin) / CACHE_PAGE_SIZE;\n\t}\n\n\tuint32 getPageCountFromRangeAligned(MPTR rangeBegin, MPTR rangeEnd) const\n\t{\n\t\tcemu_assert_debug((rangeBegin % CACHE_PAGE_SIZE) == 0);\n\t\tcemu_assert_debug((rangeEnd % CACHE_PAGE_SIZE) == 0);\n\t\tcemu_assert_debug(rangeBegin <= rangeEnd);\n\t\treturn (rangeEnd - rangeBegin) / CACHE_PAGE_SIZE;\n\t}\n\n\tuint32 getPageCountFromRange(MPTR rangeBegin, MPTR rangeEnd) const\n\t{\n\t\trangeEnd = (rangeEnd + CACHE_PAGE_SIZE_M1) & ~CACHE_PAGE_SIZE_M1;\n\t\trangeBegin &= ~CACHE_PAGE_SIZE_M1;\n\t\tcemu_assert_debug(rangeBegin <= rangeEnd);\n\t\treturn (rangeEnd - rangeBegin) / CACHE_PAGE_SIZE;\n\t}\n\n\tvoid syncFromRAM(MPTR rangeBegin, MPTR rangeEnd)\n\t{\n\t\tcemu_assert_debug(rangeBegin >= m_rangeBegin);\n\t\tcemu_assert_debug(rangeEnd <= m_rangeEnd);\n\t\tcemu_assert_debug(rangeEnd > rangeBegin);\n\t\tcemu_assert_debug(m_hasCacheAlloc);\n\n\t\t// reset write tracking\n\t\tcheckAndSyncModifications(rangeBegin, rangeEnd, false);\n\n\t\tg_renderer->bufferCache_upload(memory_getPointerFromPhysicalOffset(rangeBegin), rangeEnd - rangeBegin, getBufferOffset(rangeBegin));\n\t}\n\n\tvoid syncFromNode(BufferCacheNode* srcNode)\n\t{\n\t\t// get shared range\n\t\tMPTR rangeBegin = std::max(m_rangeBegin, srcNode->m_rangeBegin);\n\t\tMPTR rangeEnd = std::min(m_rangeEnd, srcNode->m_rangeEnd);\n\t\tcemu_assert_debug(rangeBegin < rangeEnd);\n\t\tg_renderer->bufferCache_copy(srcNode->getBufferOffset(rangeBegin), this->getBufferOffset(rangeBegin), rangeEnd - rangeBegin);\n\t\t// copy page checksums and information\n\t\tsint32 numPages = getPageCountFromRangeAligned(rangeBegin, rangeEnd);\n\t\tCachePageInfo* pageInfoDst = this->m_pageInfo.data() + this->getPageIndexFromAddrAligned(rangeBegin);\n\t\tCachePageInfo* pageInfoSrc = srcNode->m_pageInfo.data() + srcNode->getPageIndexFromAddrAligned(rangeBegin);\n\t\tfor (sint32 i = 0; i < numPages; i++)\n\t\t{\n\t\t\tpageInfoDst[i] = pageInfoSrc[i];\n\t\t\tif (pageInfoSrc[i].hasStreamoutData)\n\t\t\t\tm_hasStreamoutData = true;\n\t\t}\n\t}\n\n\tvoid uploadPages(uint32 firstPage, uint32 lastPagePlusOne)\n\t{\n\t\tcemu_assert_debug(lastPagePlusOne > firstPage);\n\t\tuint32 uploadRangeBegin = m_rangeBegin + firstPage * CACHE_PAGE_SIZE;\n\t\tuint32 uploadRangeEnd = m_rangeBegin + lastPagePlusOne * CACHE_PAGE_SIZE;\n\t\tcemu_assert_debug(uploadRangeEnd > uploadRangeBegin);\n\t\t// make sure uploaded pages and hashes match\n\t\tuint32 numPages = lastPagePlusOne - firstPage;\n\t\tif (s_pageUploadBuffer.size() < (numPages * CACHE_PAGE_SIZE))\n\t\t\ts_pageUploadBuffer.resize(numPages * CACHE_PAGE_SIZE);\n\t\t// todo - improve performance by merging memcpy + hashPage() ?\n\t\tmemcpy(s_pageUploadBuffer.data(), memory_getPointerFromPhysicalOffset(uploadRangeBegin), numPages * CACHE_PAGE_SIZE);\n\t\tfor (uint32 i = 0; i < numPages; i++)\n\t\t{\n\t\t\tm_pageInfo[firstPage + i].hash = hashPage(s_pageUploadBuffer.data() + i * CACHE_PAGE_SIZE);\n\t\t}\n\t\tg_renderer->bufferCache_upload(s_pageUploadBuffer.data(), uploadRangeEnd - uploadRangeBegin, getBufferOffset(uploadRangeBegin));\n\t}\n\n\t// upload only non-streamout data of a single page\n\t// returns true if at least one streamout 16-byte block is present\n\t// also updates the page hash to match the uploaded data (strict match)\n\tsint32 uploadPageWithStreamoutFiltered(uint32 pageIndex)\n\t{\n\t\tuint8 pageCopy[CACHE_PAGE_SIZE];\n\t\tmemcpy(pageCopy, memory_getPointerFromPhysicalOffset(m_rangeBegin + pageIndex * CACHE_PAGE_SIZE), CACHE_PAGE_SIZE);\n\n\t\tMPTR pageBase = m_rangeBegin + pageIndex * CACHE_PAGE_SIZE;\n\n\t\tsint32 blockBegin = -1;\n\t\tuint64* pagePtrU64 = (uint64*)pageCopy;\n\t\tm_pageInfo[pageIndex].hash = hashPage(pageCopy);\n\t\tbool hasStreamoutBlocks = false;\n\t\tfor (sint32 i = 0; i < CACHE_PAGE_SIZE / 16; i++)\n\t\t{\n\t\t\tif (pagePtrU64[0] == c_streamoutSig0 && pagePtrU64[1] == c_streamoutSig1)\n\t\t\t{\n\t\t\t\thasStreamoutBlocks = true;\n\t\t\t\tif (blockBegin != -1)\n\t\t\t\t{\n\t\t\t\t\tuint32 uploadRelRangeBegin = blockBegin * 16;\n\t\t\t\t\tuint32 uploadRelRangeEnd = i * 16;\n\t\t\t\t\tcemu_assert_debug(uploadRelRangeEnd > uploadRelRangeBegin);\n\t\t\t\t\tg_renderer->bufferCache_upload(pageCopy + uploadRelRangeBegin, uploadRelRangeEnd - uploadRelRangeBegin, getBufferOffset(pageBase + uploadRelRangeBegin));\n\t\t\t\t\tblockBegin = -1;\n\t\t\t\t}\n\t\t\t\tpagePtrU64 += 2;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (blockBegin == -1)\n\t\t\t\tblockBegin = i;\n\t\t\tpagePtrU64 += 2;\n\t\t}\n\t\tif (blockBegin != -1)\n\t\t{\n\t\t\tuint32 uploadRelRangeBegin = blockBegin * 16;\n\t\t\tuint32 uploadRelRangeEnd = CACHE_PAGE_SIZE;\n\t\t\tcemu_assert_debug(uploadRelRangeEnd > uploadRelRangeBegin);\n\t\t\tg_renderer->bufferCache_upload(pageCopy + uploadRelRangeBegin, uploadRelRangeEnd - uploadRelRangeBegin, getBufferOffset(pageBase + uploadRelRangeBegin));\n\t\t\tblockBegin = -1;\n\t\t}\n\t\treturn hasStreamoutBlocks;\n\t}\n\n\tvoid shrink(MPTR newRangeBegin, MPTR newRangeEnd)\n\t{\n\t\tcemu_assert_debug(newRangeBegin >= m_rangeBegin);\n\t\tcemu_assert_debug(newRangeEnd >= m_rangeEnd);\n\t\tcemu_assert_debug(newRangeEnd > m_rangeBegin);\n\t\tassert_dbg(); // todo (resize page array)\n\t\tm_rangeBegin = newRangeBegin;\n\t\tm_rangeEnd = newRangeEnd;\n\t}\n\n\tstatic uint64 hashPage(uint8* mem)\n\t{\n\t\tstatic const uint64 k0 = 0x55F23EAD;\n\t\tstatic const uint64 k1 = 0x185FDC6D;\n\t\tstatic const uint64 k2 = 0xF7431F49;\n\t\tstatic const uint64 k3 = 0xA4C7AE9D;\n\n\t\tcemu_assert_debug((CACHE_PAGE_SIZE % 32) == 0);\n\t\tconst uint64* ptr = (const uint64*)mem;\n\t\tconst uint64* end = ptr + (CACHE_PAGE_SIZE / sizeof(uint64));\n\n\t\tuint64 h0 = 0;\n\t\tuint64 h1 = 0;\n\t\tuint64 h2 = 0;\n\t\tuint64 h3 = 0;\n\t\twhile (ptr < end)\n\t\t{\n\t\t\th0 = std::rotr(h0, 7);\n\t\t\th1 = std::rotr(h1, 7);\n\t\t\th2 = std::rotr(h2, 7);\n\t\t\th3 = std::rotr(h3, 7);\n\n\t\t\th0 += ptr[0] * k0;\n\t\t\th1 += ptr[1] * k1;\n\t\t\th2 += ptr[2] * k2;\n\t\t\th3 += ptr[3] * k3;\n\t\t\tptr += 4;\n\t\t}\n\n\t\treturn h0 + h1 + h2 + h3;\n\t}\n\n\t// flag page as having streamout data, also write streamout signatures to page memory\n\t// also incrementally updates the page hash to include the written signatures, this prevents signature writes from triggering a data upload\n\tvoid pageWriteStreamoutSignatures(uint32 pageIndex, MPTR rangeBegin, MPTR rangeEnd)\n\t{\n\t\tuint32 pageRangeBegin = m_rangeBegin + pageIndex * CACHE_PAGE_SIZE;\n\t\tuint32 pageRangeEnd = pageRangeBegin + CACHE_PAGE_SIZE;\n\t\trangeBegin = std::max(pageRangeBegin, rangeBegin);\n\t\trangeEnd = std::min(pageRangeEnd, rangeEnd);\n\t\tcemu_assert_debug(rangeEnd > rangeBegin);\n\t\tcemu_assert_debug(rangeBegin >= pageRangeBegin);\n\t\tcemu_assert_debug(rangeEnd <= pageRangeEnd);\n\t\tcemu_assert_debug((rangeBegin & 0xF) == 0);\n\t\tcemu_assert_debug((rangeEnd & 0xF) == 0);\n\n\t\tauto pageInfo = m_pageInfo.data() + pageIndex;\n\t\tpageInfo->hasStreamoutData = true;\n\n\t\t// if the whole page is replaced we can use a cached hash\n\t\tif (pageRangeBegin == rangeBegin && pageRangeEnd == rangeEnd)\n\t\t{\n\t\t\tuint64* pageMem = (uint64*)memory_getPointerFromPhysicalOffset(rangeBegin);\n\t\t\tuint32 numBlocks = (rangeEnd - rangeBegin) / 16;\n\t\t\tfor (uint32 i = 0; i < numBlocks; i++)\n\t\t\t{\n\t\t\t\tpageMem[0] = c_streamoutSig0;\n\t\t\t\tpageMem[1] = c_streamoutSig1;\n\t\t\t\tpageMem += 2;\n\t\t\t}\n\n\t\t\tpageInfo->hash = c_fullStreamoutPageHash;\n\t\t\treturn;\n\t\t}\n\n\t\tuint64* pageMem = (uint64*)memory_getPointerFromPhysicalOffset(rangeBegin);\n\t\tuint32 numBlocks = (rangeEnd - rangeBegin) / 16;\n\t\tuint32 indexHashBlock = (rangeBegin - pageRangeBegin) / sizeof(uint64);\n\t\tfor (uint32 i = 0; i < numBlocks; i++)\n\t\t{\n\t\t\tpageMem[0] = c_streamoutSig0;\n\t\t\tpageMem[1] = c_streamoutSig1;\n\t\t\tpageMem += 2;\n\t\t}\n\t\tpageInfo->hash = 0; // reset hash\n\t}\n\n\tstatic uint64 genStreamoutPageHash()\n\t{\n\t\tuint8 pageMem[CACHE_PAGE_SIZE];\n\t\tuint64* pageMemU64 = (uint64*)pageMem;\n\t\tfor (uint32 i = 0; i < sizeof(pageMem) / sizeof(uint64) / 2; i++)\n\t\t{\n\t\t\tpageMemU64[0] = c_streamoutSig0;\n\t\t\tpageMemU64[1] = c_streamoutSig1;\n\t\t\tpageMemU64 += 2;\n\t\t}\n\n\t\treturn hashPage(pageMem);\n\t}\n\n\tstatic inline uint64 c_fullStreamoutPageHash = genStreamoutPageHash();\n\tstatic std::vector<uint32> g_deallocateQueue;\n\npublic:\n    static void UnloadAll()\n    {\n        size_t i = 0;\n        while (i < s_allCacheNodes.size())\n        {\n            BufferCacheNode* node = s_allCacheNodes[i];\n            node->ReleaseCacheMemoryImmediately();\n            LatteBufferCache_removeSingleNodeFromTree(node);\n            delete node;\n        }\n        for(auto& it : s_allCacheNodes)\n            delete it;\n        s_allCacheNodes.clear();\n        g_deallocateQueue.clear();\n    }\n\n\tstatic void ProcessDeallocations()\n\t{\n\t\tfor(auto& itr : g_deallocateQueue)\n\t\t\tg_gpuBufferHeap->freeOffset(itr);\n\t\tg_deallocateQueue.clear();\n\t}\n\n\t// drops everything from the cache that isn't considered in use or unrestorable (ranges with streamout)\n\tstatic void CleanupCacheAggressive(MPTR excludedRangeBegin, MPTR excludedRangeEnd)\n\t{\n\t\tsize_t i = 0;\n\t\twhile (i < s_allCacheNodes.size())\n\t\t{\n\t\t\tBufferCacheNode* node = s_allCacheNodes[i];\n\t\t\tif (node->isInUse())\n\t\t\t{\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(!node->isRAMOnly())\n\t\t\t{\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(node->GetRangeBegin() < excludedRangeEnd && node->GetRangeEnd() > excludedRangeBegin)\n\t\t\t{\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// delete range\n\t\t\tif (node->m_hasCacheAlloc)\n\t\t\t\tcemu_assert_debug(!node->isInUse());\n\t\t\tnode->ReleaseCacheMemoryImmediately();\n\t\t\tLatteBufferCache_removeSingleNodeFromTree(node);\n\t\t\tdelete node;\n\t\t}\n\t}\n\n\t/* callbacks from IntervalTree */\n\n\tstatic BufferCacheNode* Create(MPTR rangeBegin, MPTR rangeEnd, std::span<BufferCacheNode*> overlappingObjects)\n\t{\n\t\tauto newRange = new BufferCacheNode(rangeBegin, rangeEnd);\n\t\tif (!newRange->allocateCacheMemory())\n\t\t{\n\t\t\t// not enough memory available, try to drop ram-only ranges from the ones we replace\n\t\t\tfor (size_t i = 0; i < overlappingObjects.size(); i++)\n\t\t\t{\n\t\t\t\tBufferCacheNode* nodeItr = overlappingObjects[i];\n\t\t\t\tif (!nodeItr->isInUse() && nodeItr->isRAMOnly())\n\t\t\t\t{\n\t\t\t\t\tnodeItr->ReleaseCacheMemoryImmediately();\n\t\t\t\t\tdelete nodeItr;\n\t\t\t\t\toverlappingObjects[i] = nullptr;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// retry allocation\n\t\t\tif (!newRange->allocateCacheMemory())\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Out-of-memory in GPU buffer (trying to allocate: {}KB) Cleaning up cache...\", (rangeEnd - rangeBegin + 1023) / 1024);\n\t\t\t\tCleanupCacheAggressive(rangeBegin, rangeEnd);\n\t\t\t\tif (!newRange->allocateCacheMemory())\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Failed to free enough memory in GPU buffer\");\n\t\t\t\t\tcemu_assert(false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tnewRange->syncFromRAM(rangeBegin, rangeEnd); // possible small optimization: only load the ranges from RAM which are not overwritten by ->syncFromNode()\n\t\tfor (auto itr : overlappingObjects)\n\t\t{\n\t\t\tif(itr == nullptr)\n\t\t\t\tcontinue;\n\t\t\tnewRange->syncFromNode(itr);\n\t\t\tdelete itr;\n\t\t}\n\t\treturn newRange;\n\t}\n\n\tstatic void Delete(BufferCacheNode* nodeObject)\n\t{\n\t\tdelete nodeObject;\n\t}\n\n\tstatic void Resize(BufferCacheNode* nodeObject, MPTR rangeBegin, MPTR rangeEnd)\n\t{\n\t\tnodeObject->shrink(rangeBegin, rangeEnd);\n\t}\n\n\tstatic BufferCacheNode* Split(BufferCacheNode* nodeObject, MPTR firstRangeBegin, MPTR firstRangeEnd, MPTR secondRangeBegin, MPTR secondRangeEnd)\n\t{\n\t\tauto newRange = new BufferCacheNode(secondRangeBegin, secondRangeEnd);\n\t\t// todo - add support for splitting BufferCacheNode memory allocations, then we dont need to do a separate allocation\n\t\tif (!newRange->allocateCacheMemory())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Out-of-memory in GPU buffer during split operation\");\n\t\t\tcemu_assert(false);\n\t\t}\n\t\tnewRange->syncFromNode(nodeObject);\n\t\tnodeObject->shrink(firstRangeBegin, firstRangeEnd);\n\t\treturn newRange;\n\t}\n};\n\nstd::vector<uint32> BufferCacheNode::g_deallocateQueue;\nIntervalTree2<MPTR, BufferCacheNode> g_gpuBufferCache;\n\nvoid LatteBufferCache_removeSingleNodeFromTree(BufferCacheNode* node)\n{\n\tg_gpuBufferCache.removeRangeSingleWithoutCallback(node->GetRangeBegin(), node->GetRangeEnd());\n}\n\nBufferCacheNode* LatteBufferCache_reserveRange(MPTR physAddress, uint32 size)\n{\n\tMPTR rangeStart = physAddress - (physAddress % CACHE_PAGE_SIZE);\n\tMPTR rangeEnd = (physAddress + size + CACHE_PAGE_SIZE_M1) & ~CACHE_PAGE_SIZE_M1;\n\n\tauto range = g_gpuBufferCache.getRange(rangeStart, rangeEnd);\n\tif (!range)\n\t{\n\t\tg_gpuBufferCache.addRange(rangeStart, rangeEnd);\n\t\trange = g_gpuBufferCache.getRange(rangeStart, rangeEnd);\n\t\tcemu_assert_debug(range);\n\t}\n\tcemu_assert_debug(range->GetRangeBegin() <= physAddress);\n\tcemu_assert_debug(range->GetRangeEnd() >= (physAddress + size));\n\treturn range;\n}\n\n\nuint32 LatteBufferCache_retrieveDataInCache(MPTR physAddress, uint32 size)\n{\n\tauto range = LatteBufferCache_reserveRange(physAddress, size);\n\trange->flagInUse();\n\n\trange->checkAndSyncModificationsIfChrononChanged(physAddress, size);\n\n\treturn range->getBufferOffset(physAddress);\n}\n\nvoid LatteBufferCache_copyStreamoutDataToCache(MPTR physAddress, uint32 size, uint32 streamoutBufferOffset)\n{\n\tif (size == 0)\n\t\treturn;\n\tcemu_assert_debug(size >= 16);\n\n\tauto range = LatteBufferCache_reserveRange(physAddress, size);\n\trange->flagInUse();\n\n\tg_renderer->bufferCache_copyStreamoutToMainBuffer(streamoutBufferOffset, range->getBufferOffset(physAddress), size);\n\n\t// write streamout signatures, flag affected pages\n\trange->writeStreamout(physAddress, (physAddress + size));\n}\n\nvoid LatteBufferCache_invalidate(MPTR physAddress, uint32 size)\n{\n\tif (size == 0)\n\t\treturn;\n\tg_gpuBufferCache.forEachOverlapping(physAddress, physAddress + size, [](BufferCacheNode* node, MPTR invalidationRangeBegin, MPTR invalidationRangeEnd)\n\t\t{\n\t\t\tnode->invalidate(invalidationRangeBegin, invalidationRangeEnd);\n\t\t}\n\t);\n}\n\n// optimized version of LatteBufferCache_invalidate() if physAddress points to the beginning of a page\nvoid LatteBufferCache_invalidatePage(MPTR physAddress)\n{\n\tcemu_assert_debug((physAddress & CACHE_PAGE_SIZE_M1) == 0);\n\tBufferCacheNode* node = g_gpuBufferCache.getRangeByPoint(physAddress);\n\tif (node)\n\t\tnode->invalidate(physAddress, physAddress+CACHE_PAGE_SIZE);\n}\n\nvoid LatteBufferCache_processDeallocations()\n{\n\tBufferCacheNode::ProcessDeallocations();\n}\n\nvoid LatteBufferCache_init(size_t bufferSize)\n{\n    cemu_assert_debug(g_gpuBufferCache.empty());\n\tg_gpuBufferHeap.reset(new VHeap(nullptr, (uint32)bufferSize));\n\tg_renderer->bufferCache_init((uint32)bufferSize);\n}\n\nvoid LatteBufferCache_UnloadAll()\n{\n    BufferCacheNode::UnloadAll();\n}\n\nvoid LatteBufferCache_getStats(uint32& heapSize, uint32& allocationSize, uint32& allocNum)\n{\n\tg_gpuBufferHeap->getStats(heapSize, allocationSize, allocNum);\n}\n\nFSpinlock g_spinlockDCFlushQueue;\n\nclass SparseBitset\n{\n\tstatic inline constexpr size_t TABLE_MASK = 0xFF;\n\npublic:\n\tbool Empty() const\n\t{\n\t\treturn m_numNonEmptyVectors == 0;\n\t}\n\n\tvoid Set(uint32 index)\n\t{\n\t\tauto& v = m_bits[index & TABLE_MASK];\n\t\tif (std::find(v.cbegin(), v.cend(), index) != v.end())\n\t\t\treturn;\n\t\tif (v.empty())\n\t\t{\n\t\t\tm_nonEmptyVectors[m_numNonEmptyVectors] = &v;\n\t\t\tm_numNonEmptyVectors++;\n\t\t}\n\t\tv.emplace_back(index);\n\t}\n\n\ttemplate<typename TFunc>\n\tvoid ForAllAndClear(TFunc callbackFunc)\n\t{\n\t\tauto vCurrent = m_nonEmptyVectors + 0;\n\t\tauto vEnd = m_nonEmptyVectors + m_numNonEmptyVectors;\n\t\twhile (vCurrent < vEnd)\n\t\t{\n\t\t\tstd::vector<uint32>* vec = *vCurrent;\n\t\t\tvCurrent++;\n\t\t\tfor (const auto& it : *vec)\n\t\t\t\tcallbackFunc(it);\n\t\t\tvec->clear();\n\t\t}\n\t\tm_numNonEmptyVectors = 0;\n\t}\n\n\tvoid Clear()\n\t{\n\t\tauto vCurrent = m_nonEmptyVectors + 0;\n\t\tauto vEnd = m_nonEmptyVectors + m_numNonEmptyVectors;\n\t\twhile (vCurrent < vEnd)\n\t\t{\n\t\t\tstd::vector<uint32>* vec = *vCurrent;\n\t\t\tvCurrent++;\n\t\t\tvec->clear();\n\t\t}\n\t\tm_numNonEmptyVectors = 0;\n\t}\n\nprivate:\n\tstd::vector<uint32> m_bits[TABLE_MASK + 1];\n\tstd::vector<uint32>* m_nonEmptyVectors[TABLE_MASK + 1];\n\tsize_t m_numNonEmptyVectors{ 0 };\n};\n\nSparseBitset* s_DCFlushQueue = new SparseBitset();\nSparseBitset* s_DCFlushQueueAlternate = new SparseBitset();\n\nvoid LatteBufferCache_notifyDCFlush(MPTR address, uint32 size)\n{\n\tif (address == 0 || size == 0xFFFFFFFF)\n\t\treturn; // global flushes are ignored for now\n\n\tuint32 firstPage = address / CACHE_PAGE_SIZE;\n\tuint32 lastPage = (address + size - 1) / CACHE_PAGE_SIZE;\n\tg_spinlockDCFlushQueue.lock();\n\tfor (uint32 i = firstPage; i <= lastPage; i++)\n\t\ts_DCFlushQueue->Set(i);\n\tg_spinlockDCFlushQueue.unlock();\n}\n\nvoid LatteBufferCache_processDCFlushQueue()\n{\n\tif (s_DCFlushQueue->Empty()) // quick check to avoid locking if there is no work to do\n\t\treturn;\n\tg_spinlockDCFlushQueue.lock();\n\tstd::swap(s_DCFlushQueue, s_DCFlushQueueAlternate);\n\tg_spinlockDCFlushQueue.unlock();\n\ts_DCFlushQueueAlternate->ForAllAndClear([](uint32 index) {LatteBufferCache_invalidatePage(index * CACHE_PAGE_SIZE); });\n}\n\nvoid LatteBufferCache_notifyDrawDone()\n{\n\n}\n\nvoid LatteBufferCache_notifySwapTVScanBuffer()\n{\n\tif( ActiveSettings::FlushGPUCacheOnSwap() )\n\t\tg_currentCacheChronon++;\n}\n\nvoid LatteBufferCache_incrementalCleanup()\n{\n\tstatic uint32 s_counter = 0;\n\n\tif (s_allCacheNodes.empty())\n\t\treturn;\n\n\ts_counter++;\n\ts_counter %= (uint32)s_allCacheNodes.size();\n\n\tauto range = s_allCacheNodes[s_counter];\n\n\tif (range->HasStreamoutData())\n\t{\n\t\t// currently we never delete streamout ranges\n\t\t// todo - check if streamout pages got overwritten + if the range would lose the hasStreamoutData flag\n\t\treturn;\n\t}\n\n\tuint32 heapSize;\n\tuint32 allocationSize;\n\tuint32 allocNum;\n\tg_gpuBufferHeap->getStats(heapSize, allocationSize, allocNum);\n\n\tif (allocationSize >= (heapSize * 4 / 5))\n\t{\n\t\t// heap is 80% filled\n\t\tif (range->GetFrameAge() >= 2)\n\t\t{\n\t\t\tg_gpuBufferCache.removeRangeSingle(range->GetRangeBegin(), range->GetRangeEnd());\n\t\t}\n\t}\n\telse if (allocationSize >= (heapSize * 3 / 4))\n\t{\n\t\t// heap is 75-100% filled\n\t\tif (range->GetFrameAge() >= 4)\n\t\t{\n\t\t\tg_gpuBufferCache.removeRangeSingle(range->GetRangeBegin(), range->GetRangeEnd());\n\t\t}\n\t}\n\telse if (allocationSize >= (heapSize / 2))\n\t{\n\t\t// if heap is 50-75% filled\n\t\tif (range->GetFrameAge() >= 20)\n\t\t{\n\t\t\tg_gpuBufferCache.removeRangeSingle(range->GetRangeBegin(), range->GetRangeEnd());\n\t\t}\n\t}\n\telse\n\t{\n\t\t// heap is under 50% capacity\n\t\tif (range->GetFrameAge() >= 500)\n\t\t{\n\t\t\tg_gpuBufferCache.removeRangeSingle(range->GetRangeBegin(), range->GetRangeEnd());\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteBufferCache.h",
    "content": "#pragma once\n\nvoid LatteBufferCache_init(size_t bufferSize);\nvoid LatteBufferCache_UnloadAll();\n\nuint32 LatteBufferCache_retrieveDataInCache(MPTR physAddress, uint32 size);\nvoid LatteBufferCache_copyStreamoutDataToCache(MPTR physAddress, uint32 size, uint32 streamoutBufferOffset);\nvoid LatteBufferCache_invalidate(MPTR physAddress, uint32 size);\n\nvoid LatteBufferCache_notifyDCFlush(MPTR address, uint32 size);\nvoid LatteBufferCache_processDCFlushQueue();\n\nvoid LatteBufferCache_processDeallocations();\nvoid LatteBufferCache_incrementalCleanup();\n\nvoid LatteBufferCache_getStats(uint32& heapSize, uint32& allocationSize, uint32& allocNum);\n\nvoid LatteBufferCache_notifySwapTVScanBuffer();"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteBufferData.cpp",
    "content": "#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n\ntemplate<int vectorLen>\nvoid rectGenerate4thVertex(uint32be* output, uint32be* input0, uint32be* input1, uint32be* input2)\n{\n\tfloat* v = (float*)output;\n\n\tfor (sint32 i = 0; i < vectorLen; i++)\n\t\toutput[vectorLen * 0 + i] = _swapEndianU32(input0[i]);\n\tfor (sint32 i = 0; i < vectorLen; i++)\n\t\toutput[vectorLen * 1 + i] = _swapEndianU32(input1[i]);\n\tfor (sint32 i = 0; i < vectorLen; i++)\n\t\toutput[vectorLen * 2 + i] = _swapEndianU32(input2[i]);\n\n\tfloat minX = std::min(v[vectorLen * 0 + 0], std::min(v[vectorLen * 1 + 0], v[vectorLen * 2 + 0]));\n\tfloat maxX = std::max(v[vectorLen * 0 + 0], std::max(v[vectorLen * 1 + 0], v[vectorLen * 2 + 0]));\n\tfloat minY = std::min(v[vectorLen * 0 + 1], std::min(v[vectorLen * 1 + 1], v[vectorLen * 2 + 1]));;\n\tfloat maxY = std::max(v[vectorLen * 0 + 1], std::max(v[vectorLen * 1 + 1], v[vectorLen * 2 + 1]));;\n\n\tfloat totalX = minX;\n\ttotalX += maxY;\n\tfloat halfX = totalX / 2.0f;\n\n\tfloat totalY = minY;\n\ttotalY += maxY;\n\tfloat halfY = totalY / 2.0f;\n\n\tsint32 countX =\n\t\t((v[vectorLen * 0 + 0] < halfX) ? 1 : 0) +\n\t\t((v[vectorLen * 1 + 0] < halfX) ? 1 : 0) +\n\t\t((v[vectorLen * 2 + 0] < halfX) ? 1 : 0);\n\n\tsint32 countY =\n\t\t((v[vectorLen * 0 + 1] < halfY) ? 1 : 0) +\n\t\t((v[vectorLen * 1 + 1] < halfY) ? 1 : 0) +\n\t\t((v[vectorLen * 2 + 1] < halfY) ? 1 : 0);\n\n\tif (countX < 2)\n\t\tv[vectorLen * 3 + 0] = minX;\n\telse\n\t\tv[vectorLen * 3 + 0] = maxX;\n\tif (countY < 2)\n\t\tv[vectorLen * 3 + 1] = minY;\n\telse\n\t\tv[vectorLen * 3 + 1] = maxY;\n\n\tif (vectorLen >= 3)\n\t\tv[vectorLen * 3 + 2] = v[vectorLen * 0 + 2]; // z from v0\n\tif (vectorLen >= 4)\n\t\tv[vectorLen * 3 + 3] = v[vectorLen * 0 + 3]; // w from v0\n\n\t// order of rectangle vertices is\n\t// v0 v1\n\t// v2 v3\n\n\tfor (sint32 f = 0; f < vectorLen*4; f++)\n\t\toutput[f] = _swapEndianU32(output[f]);\n}\n\n#define ATTRIBUTE_CACHE_RING_SIZE\t\t(128) // up to 128 entries can be cached\n\nvoid LatteBufferCache_LoadRemappedUniforms(LatteDecompilerShader* shader, float* uniformData)\n{\n\tuint32 shaderAluConst;\n\tuint32 shaderUniformRegisterOffset;\n\n\tswitch (shader->shaderType)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t\tshaderAluConst = 0x400;\n\t\tshaderUniformRegisterOffset = mmSQ_VTX_UNIFORM_BLOCK_START;\n\t\tbreak;\n\tcase LatteConst::ShaderType::Pixel:\n\t\tshaderAluConst = 0;\n\t\tshaderUniformRegisterOffset = mmSQ_PS_UNIFORM_BLOCK_START;\n\t\tbreak;\n\tcase LatteConst::ShaderType::Geometry:\n\t\tshaderAluConst = 0; // geometry shader has no ALU const\n\t\tshaderUniformRegisterOffset = mmSQ_GS_UNIFORM_BLOCK_START;\n\t\tbreak;\n\tdefault:\n\t\tcemu_assert_debug(false);\n\t}\n\n\t// sourced from uniform registers\n\tuint32* aluConstBase = LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst;\n\tfor (auto it : shader->list_remappedUniformEntries_register)\n\t{\n\t\tuint64* uniformRegData = (uint64*)(aluConstBase + it.indexOffset / 4);\n\t\tuint64* regDest = (uint64*)((uint8*)uniformData + it.mappedIndexOffset);\n\t\tregDest[0] = uniformRegData[0];\n\t\tregDest[1] = uniformRegData[1];\n\t}\n\t// sourced from uniform buffers\n\tfor (auto& bufferGroup : shader->list_remappedUniformEntries_bufferGroups)\n\t{\n\t\tMPTR physicalAddr = LatteGPUState.contextRegister[shaderUniformRegisterOffset + bufferGroup.kcacheBankIdOffset / 4];\n\t\tif (physicalAddr)\n\t\t{\n\t\t\tuint8* uniformBase = memory_base + physicalAddr;\n\t\t\tfor (auto& it : bufferGroup.entries)\n\t\t\t{\n\t\t\t\tuint64* regDest = (uint64*)((uint8*)uniformData + it.mappedIndexOffset);\n\t\t\t\tuint64* uniformEntrySrc = (uint64*)(uniformBase + it.indexOffset);\n\t\t\t\tmemcpy(regDest, uniformEntrySrc, 16);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (auto& it : bufferGroup.entries)\n\t\t\t{\n\t\t\t\tuint64* regDest = (uint64*)((uint8*)uniformData + it.mappedIndexOffset);\n\t\t\t\tregDest[0] = 0;\n\t\t\t\tregDest[1] = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid LatteBufferCache_syncGPUUniformBuffers(LatteDecompilerShader* shader, const uint32 uniformBufferRegOffset, LatteConst::ShaderType shaderType)\n{\n\tif (shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)\n\t{\n\t\tfor(const auto& buf : shader->list_quickBufferList)\n\t\t{\n\t\t\tsint32 i = buf.index;\n\t\t\tMPTR physicalAddr = LatteGPUState.contextRegister[uniformBufferRegOffset + i * 7 + 0];\n\t\t\tuint32 uniformSize = LatteGPUState.contextRegister[uniformBufferRegOffset + i * 7 + 1] + 1;\n\t\t\tif (physicalAddr == MPTR_NULL) [[unlikely]]\n\t\t\t{\n\t\t\t\tg_renderer->buffer_bindUniformBuffer(shaderType, i, 0, 0);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tuniformSize = std::min<uint32>(uniformSize, buf.size);\n\t\t\tuint32 bindOffset = LatteBufferCache_retrieveDataInCache(physicalAddr, uniformSize);\n\t\t\tg_renderer->buffer_bindUniformBuffer(shaderType, i, bindOffset, uniformSize);\n\t\t}\n\t}\n}\n\n// upload vertex and uniform buffers\nbool LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount)\n{\n\tstatic uint32 s_syncBufferCounter = 0;\n\n\ts_syncBufferCounter++;\n\tif (s_syncBufferCounter >= 30)\n\t{\n\t\tLatteBufferCache_incrementalCleanup();\n\t\ts_syncBufferCounter = 0;\n\t}\n\n\tLatteBufferCache_processDCFlushQueue();\n\t// process queued deallocations from previous drawcall\n\tLatteBufferCache_processDeallocations();\n\n\t// sync and bind vertex buffers\n\tLatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader();\n\tif (!parsedFetchShader)\n\t\treturn false;\n\tfor (auto& bufferGroup : parsedFetchShader->bufferGroups)\n\t{\n\t\tuint32 bufferIndex = bufferGroup.attributeBufferIndex;\n\t\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n\t\tMPTR bufferAddress = LatteGPUState.contextRegister[bufferBaseRegisterIndex + 0];\n\t\tuint32 bufferSize = LatteGPUState.contextRegister[bufferBaseRegisterIndex + 1] + 1;\n\t\tuint32 bufferStride = (LatteGPUState.contextRegister[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;\n\n\t\tif (bufferAddress == MPTR_NULL)\n\t\t{\n\t\t\tg_renderer->buffer_bindVertexBuffer(bufferIndex, 0, 0);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// dont rely on buffer size given by game\n\t\tuint32 fixedBufferSize = 0;\n\t\tif (bufferGroup.hasVtxIndexAccess)\n\t\t\tfixedBufferSize = bufferStride * (maxIndex + 1) + bufferGroup.maxOffset;\n\t\tif (bufferGroup.hasInstanceIndexAccess)\n\t\t{\n\t\t\tuint32 fixedBufferSizeInstance = bufferStride * ((baseInstance + instanceCount) + 1) + bufferGroup.maxOffset;\n\t\t\tfixedBufferSize = std::max(fixedBufferSize, fixedBufferSizeInstance);\n\t\t}\n\t\tif (fixedBufferSize == 0 || bufferStride == 0)\n\t\t\tfixedBufferSize += 128;\n\n\n#if BOOST_OS_MACOS\n\t\tif(bufferStride % 4 != 0)\n\t\t{\n\t\t    if (g_renderer->GetType() == RendererAPI::Vulkan)\n\t\t\t{\n    \t\t\tif (VulkanRenderer* vkRenderer = VulkanRenderer::GetInstance())\n    \t\t\t{\n    \t\t\t\tauto fixedBuffer = vkRenderer->buffer_genStrideWorkaroundVertexBuffer(bufferAddress, fixedBufferSize, bufferStride);\n    \t\t\t\tvkRenderer->buffer_bindVertexStrideWorkaroundBuffer(fixedBuffer.first, fixedBuffer.second, bufferIndex, fixedBufferSize);\n    \t\t\t\tcontinue;\n    \t\t\t}\n\t\t\t}\n\t\t}\n#endif\n\n\t\tuint32 bindOffset = LatteBufferCache_retrieveDataInCache(bufferAddress, fixedBufferSize);\n\t\tg_renderer->buffer_bindVertexBuffer(bufferIndex, bindOffset, fixedBufferSize);\n\t}\n\t// sync uniform buffers\n\tLatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();\n\tif (vertexShader)\n\t\tLatteBufferCache_syncGPUUniformBuffers(vertexShader, mmSQ_VTX_UNIFORM_BLOCK_START, LatteConst::ShaderType::Vertex);\n\tLatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader();\n\tif (geometryShader)\n\t\tLatteBufferCache_syncGPUUniformBuffers(geometryShader, mmSQ_GS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Geometry);\n\tLatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();\n\tif (pixelShader)\n\t\tLatteBufferCache_syncGPUUniformBuffers(pixelShader, mmSQ_PS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Pixel);\n\treturn true;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteCachedFBO.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"util/math/vector2.h\"\n\nclass LatteCachedFBO\n{\npublic:\n\tLatteCachedFBO(uint64 key);\n\n\tuint32 calculateNumColorBuffers()\n\t{\n\t\tuint32 n = 0;\n\t\tfor (sint32 i = 0; i < 8; i++)\n\t\t\tif (colorBuffer[i].texture)\n\t\t\t\tn++;\n\t\treturn n;\n\t}\n\n\tbool hasDepthBuffer()\n\t{\n\t\treturn depthBuffer.texture;\n\t}\n\n\tstd::vector<LatteTexture*>& GetTextures()\n\t{\n\t\treturn m_referencedTextures;\n\t}\n\n\tvirtual ~LatteCachedFBO() {};\n\nprivate:\n\tvoid calculateEffectiveRenderAreaSize()\n\t{\n\t\tVector2i rtEffectiveSize;\n\t\trtEffectiveSize.x = 0;\n\t\trtEffectiveSize.y = 0;\n\t\tsint32 numViews = 0;\n\t\t// derive extent from color buffers\n\t\tfor (sint32 i = 0; i < 8; i++)\n\t\t{\n\t\t\tif(colorBuffer[i].texture == nullptr)\n\t\t\t\tcontinue;\n\t\t\tsint32 effectiveWidth, effectiveHeight;\n\t\t\tcolorBuffer[i].texture->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, colorBuffer[i].texture->firstMip);\n\t\t\tif (rtEffectiveSize.x == 0 && rtEffectiveSize.y == 0)\n\t\t\t{\n\t\t\t\trtEffectiveSize.x = effectiveWidth;\n\t\t\t\trtEffectiveSize.y = effectiveHeight;\n\t\t\t}\n\t\t\tif (effectiveWidth < rtEffectiveSize.x)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Framebuffer has color texture with smaller effective width ({} -> {})\", rtEffectiveSize.x, effectiveWidth);\n\t\t\t\trtEffectiveSize.x = effectiveWidth;\n\t\t\t}\n\t\t\tif (effectiveHeight < rtEffectiveSize.y)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Framebuffer has color texture with smaller effective height ({} -> {})\", rtEffectiveSize.y, effectiveHeight);\n\t\t\t\trtEffectiveSize.y = effectiveHeight;\n\t\t\t}\n\t\t\tnumViews++;\n\t\t}\n\t\t// derive extent from depth buffer\n\t\tif (depthBuffer.texture)\n\t\t{\n\t\t\tsint32 effectiveWidth, effectiveHeight;\n\t\t\tdepthBuffer.texture->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, depthBuffer.texture->firstMip);\n\t\t\tif (rtEffectiveSize.x == 0 && rtEffectiveSize.y == 0)\n\t\t\t{\n\t\t\t\trtEffectiveSize.x = effectiveWidth;\n\t\t\t\trtEffectiveSize.y = effectiveHeight;\n\t\t\t}\n\t\t\tif (effectiveWidth < rtEffectiveSize.x)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Framebuffer has depth texture with smaller effective width ({} -> {})\", rtEffectiveSize.x, effectiveWidth);\n\t\t\t\trtEffectiveSize.x = effectiveWidth;\n\t\t\t}\n\t\t\tif (effectiveHeight < rtEffectiveSize.y)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Framebuffer has depth texture with smaller effective height ({} -> {})\", rtEffectiveSize.y, effectiveHeight);\n\t\t\t\trtEffectiveSize.y = effectiveHeight;\n\t\t\t}\n\t\t\tnumViews++;\n\t\t}\n\t\tif (numViews == 0)\n\t\t{\n\t\t\t// empty FBO\n\t\t\tm_size = Vector2i(32, 32);\n\t\t\treturn;\n\t\t}\n\t\tcemu_assert_debug(rtEffectiveSize.x != 0);\n\t\tcemu_assert_debug(rtEffectiveSize.y != 0);\n\t\tm_size = rtEffectiveSize;\n\t}\n\npublic:\n\tuint64 key;\n\tVector2i m_size;\n\n\tstruct\n\t{\n\t\tLatteTextureView* texture{};\n\t}colorBuffer[8]{};\n\tstruct\n\t{\n\t\tLatteTextureView* texture{};\n\t\tbool hasStencil{};\n\t}depthBuffer{};\n\tuint32 drawBuffersMask{};\n\n\tstd::vector<LatteTexture*> m_referencedTextures; // color and depth views combined\n};\n\nclass LatteMRT\n{\npublic:\n\tstatic void NotifyTextureDeletion(LatteTexture* texture);\n\n\t// GPU state\n\tstatic LatteTextureView* GetColorAttachmentTexture(uint32 index, bool createNew, bool checkForTextureChanges);\n\tstatic uint8 GetActiveColorBufferMask(const LatteDecompilerShader* pixelShader, const struct LatteContextRegister& lcr);\n\tstatic bool GetActiveDepthBufferMask(const struct LatteContextRegister& lcr);\n\tstatic Latte::E_GX2SURFFMT GetColorBufferFormat(const uint32 index, const LatteContextRegister& lcr);\n\tstatic Latte::E_GX2SURFFMT GetDepthBufferFormat(const struct LatteContextRegister& lcr);\n\n\t// FBO state management\n\tstatic void SetColorAttachment(uint32 index, LatteTextureView* view);\n\tstatic void SetDepthAndStencilAttachment(LatteTextureView* view, bool hasStencil);\n\tstatic LatteTextureView* GetColorAttachment(uint32 index);\n\tstatic LatteTextureView* GetDepthAttachment();\n\n\tstatic void ApplyCurrentState();\n\n\tstatic bool UpdateCurrentFBO(); // update FBO with info from current GPU state\n\n\t// helper functions\n\tstatic void BindColorBufferOnly(LatteTextureView* view);\n\tstatic void BindDepthBufferOnly(LatteTextureView* view);\n\n\tstatic void GetCurrentFragCoordScale(float* coordScale);\n\tstatic void GetVirtualViewportDimensions(sint32& width, sint32& height); // returns the width and height of the current GPU viewport (unaffected by graphic pack rules)\n\n\t// todo - move this into FBO destructor (?)\n\tstatic void DeleteCachedFBO(LatteCachedFBO* cfbo);\n\nprivate:\n\tstatic LatteCachedFBO* CreateCachedFBO(uint64 key);\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp",
    "content": "#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\" // for write gatherer and special state. Get rid of dependency\n#include \"Cafe/OS/libs/gx2/GX2_Misc.h\" // for GX2::sGX2MainCoreIndex. Legacy dependency\n#include \"Cafe/OS/libs/gx2/GX2_Event.h\" // for notification callbacks\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteAsyncCommands.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Core/LatteIndices.h\"\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/TCL/TCL.h\" // TCL currently handles the GPU command ringbuffer\n\n#include \"Cafe/CafeSystem.h\"\n\n#include <boost/container/small_vector.hpp>\n\nvoid LatteCP_DebugPrintCmdBuffer(uint32be* bufferPtr, uint32 size);\n\n#define CP_TIMER_RECHECK\t1024\n\n//#define LATTE_CP_LOGGING\n\ntypedef uint32be* LatteCMDPtr;\n#define LatteReadCMD() ((uint32)*(cmd++))\n#define LatteSkipCMD(_nWords) cmd += (_nWords)\n\nvoid LatteThread_HandleOSScreen();\n\nvoid LatteThread_Exit();\n\nclass DrawPassContext\n{\n\tstruct CmdQueuePos\n\t{\n\t\tCmdQueuePos(LatteCMDPtr current, LatteCMDPtr start, LatteCMDPtr end) : current(current), start(start), end(end) {};\n\n\t\tLatteCMDPtr current;\n\t\tLatteCMDPtr start;\n\t\tLatteCMDPtr end;\n\t};\npublic:\n\tbool isWithinDrawPass() const\n\t{\n\t\treturn m_drawPassActive;\n\t}\n\n\tvoid beginDrawPass()\n\t{\n\t\tm_drawPassActive = true;\n\t\tm_isFirstDraw = true;\n\t\tm_vertexBufferChanged = true;\n\t\tm_uniformBufferChanged = true;\n\t\tg_renderer->draw_beginSequence();\n\t}\n\n\tvoid executeDraw(uint32 count, bool isAutoIndex, MPTR physIndices)\n\t{\n\t\tuint32 baseVertex = LatteGPUState.contextRegister[mmSQ_VTX_BASE_VTX_LOC];\n\t\tuint32 baseInstance = LatteGPUState.contextRegister[mmSQ_VTX_START_INST_LOC];\n\t\tuint32 numInstances = LatteGPUState.contextNew.VGT_DMA_NUM_INSTANCES.get_NUM_INSTANCES();\n\n\t\tif (!isAutoIndex)\n\t\t{\n\t\t\tcemu_assert_debug(physIndices != MPTR_NULL);\n\t\t\tif (physIndices == MPTR_NULL)\n\t\t\t\treturn;\n\t\t\tauto indexType = LatteGPUState.contextNew.VGT_DMA_INDEX_TYPE.get_INDEX_TYPE();\n\t\t\tg_renderer->draw_execute(baseVertex, baseInstance, numInstances, count, physIndices, indexType, m_isFirstDraw);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tg_renderer->draw_execute(baseVertex, baseInstance, numInstances, count, MPTR_NULL, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE::AUTO, m_isFirstDraw);\n\t\t}\n\t\tperformanceMonitor.cycle[performanceMonitor.cycleIndex].drawCallCounter++;\n\t\tif (!m_isFirstDraw)\n\t\t\tperformanceMonitor.cycle[performanceMonitor.cycleIndex].fastDrawCallCounter++;\n\t\tm_isFirstDraw = false;\n\t\tm_vertexBufferChanged = false;\n\t\tm_uniformBufferChanged = false;\n\t}\n\n\tvoid endDrawPass()\n\t{\n\t\tg_renderer->draw_endSequence();\n\t\tm_drawPassActive = false;\n\t}\n\n\tvoid notifyModifiedVertexBuffer() \n\t{\n\t\tm_vertexBufferChanged = true;\n\t}\n\n\tvoid notifyModifiedUniformBuffer()\n\t{\n\t\tm_uniformBufferChanged = true;\n\t}\n\n\t// command buffer processing position\n\tvoid PushCurrentCommandQueuePos(LatteCMDPtr current, LatteCMDPtr start, LatteCMDPtr end)\n\t{\n\t\tm_queuePosStack.emplace_back(current, start, end);\n\t}\n\n\tbool PopCurrentCommandQueuePos(LatteCMDPtr& current, LatteCMDPtr& start, LatteCMDPtr& end)\n\t{\n\t\tif (m_queuePosStack.empty())\n\t\t\treturn false;\n\t\tconst auto& it = m_queuePosStack.back();\n\t\tcurrent = it.current;\n\t\tstart = it.start;\n\t\tend = it.end;\n\t\tm_queuePosStack.pop_back();\n\t\treturn true;\n\t}\n\nprivate:\n\tbool m_drawPassActive{ false };\n\tbool m_isFirstDraw{false};\n\tbool m_vertexBufferChanged{ false };\n\tbool m_uniformBufferChanged{ false };\n\tboost::container::small_vector<CmdQueuePos, 4> m_queuePosStack;\n};\n\nvoid LatteCP_processCommandBuffer(DrawPassContext& drawPassCtx);\n\n// called whenever the GPU runs out of commands or hits a wait condition (semaphores, HLE waits)\nvoid LatteCP_signalEnterWait()\n{\n\t// based on the assumption that games won't do a rugpull and swap out buffer data in the middle of an uninterrupted sequence of drawcalls,\n\t// we only flush caches when the GPU goes idle or has to wait for any operation\n\tLatteIndices_invalidateAll();\n}\n\n/*\n* Read a U32 from the command buffer\n* If no data is available then wait in a busy loop\n*/\nuint32 LatteCP_readU32Deprc()\n{\n\t// no display list active\n\twhile (true)\n\t{\n\t\tuint32 cmdWord;\n\t\tif ( TCL::TCLGPUReadRBWord(cmdWord) )\n\t\t\treturn cmdWord;\n\n\t\tg_renderer->NotifyLatteCommandProcessorIdle(); // let the renderer know in case it wants to flush any commands\n\t\tperformanceMonitor.gpuTime_idleTime.beginMeasuring();\n\t\t// no command data available, spin in a busy loop for a bit then check again\n\t\tfor (sint32 busy = 0; busy < 80; busy++)\n\t\t{\n\t\t\t_mm_pause();\n\t\t}\n\t\tLatteThread_HandleOSScreen(); // check if new frame was presented via OSScreen API\n\n\t\tif ( TCL::TCLGPUReadRBWord(cmdWord) )\n\t\t\treturn cmdWord;\n\t\tif (Latte_GetStopSignal())\n\t\t\tLatteThread_Exit();\n\n\t\t// still no command data available, do some other tasks\n\t\tLatteTiming_HandleTimedVsync();\n\t\tLatteAsyncCommands_checkAndExecute();\n\t\tstd::this_thread::yield();\n\t\tperformanceMonitor.gpuTime_idleTime.endMeasuring();\n\t}\n\tUNREACHABLE;\n}\n\ntemplate<uint32 readU32()>\nvoid LatteCP_skipWords(uint32 wordsToSkip)\n{\n\twhile (wordsToSkip)\n\t{\n\t\treadU32();\n\t\twordsToSkip--;\n\t}\n}\n\nLatteCMDPtr LatteCP_itSurfaceSync(LatteCMDPtr cmd)\n{\n\tuint32 invalidationFlags = LatteReadCMD();\n\tuint32 size = LatteReadCMD() << 8;\n\tMPTR addressPhys = LatteReadCMD() << 8;\n\tuint32 pollInterval = LatteReadCMD();\n\n\tif (addressPhys == MPTR_NULL || size == 0xFFFFFFFF)\n\t\treturn cmd; // block global invalidations because they are too expensive\n\n\tif (invalidationFlags & 0x800000)\n\t{\n\t\t// invalidate uniform or attribute buffer\n\t\tLatteBufferCache_invalidate(addressPhys, size);\n\t}\n\treturn cmd;\n}\n\n// called from TCL command queue. Executes a memory command buffer\nvoid LatteCP_itIndirectBufferDepr(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 3);\n\tuint32 physicalAddress = LatteReadCMD();\n\tuint32 physicalAddressHigh = LatteReadCMD(); // unused\n\tuint32 sizeInU32s = LatteReadCMD();\n\n#ifdef LATTE_CP_LOGGING\n\tif (GetAsyncKeyState('A'))\n\t\tLatteCP_DebugPrintCmdBuffer(MEMPTR<uint32be>(physicalAddress), displayListSize);\n#endif\n\n\tif (sizeInU32s > 0)\n\t{\n\t\tDrawPassContext drawPassCtx;\n\t\tuint32be* buf = MEMPTR<uint32be>(physicalAddress).GetPtr();\n\t\tdrawPassCtx.PushCurrentCommandQueuePos(buf, buf, buf + sizeInU32s);\n\n\t\tLatteCP_processCommandBuffer(drawPassCtx);\n\t\tif (drawPassCtx.isWithinDrawPass())\n\t\t\tdrawPassCtx.endDrawPass();\n\t}\n}\n\n// pushes the command buffer to the stack\nvoid LatteCP_itIndirectBuffer(LatteCMDPtr cmd, uint32 nWords, DrawPassContext& drawPassCtx)\n{\n\tcemu_assert_debug(nWords == 3);\n\tuint32 physicalAddress = LatteReadCMD();\n\tuint32 physicalAddressHigh = LatteReadCMD(); // unused\n\tuint32 sizeInDWords = LatteReadCMD();\n\tif (sizeInDWords > 0)\n\t{\n\t\tuint32 displayListSize = sizeInDWords * 4;\n\t\tuint32be* buf = MEMPTR<uint32be>(physicalAddress).GetPtr();\n\t\tdrawPassCtx.PushCurrentCommandQueuePos(buf, buf, buf + sizeInDWords);\n\t}\n}\n\nLatteCMDPtr LatteCP_itStreamoutBufferUpdate(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 5);\n\tuint32 updateControl = LatteReadCMD();\n\tuint32 physicalAddressWrite = LatteReadCMD();\n\tuint32 ukn1 = LatteReadCMD();\n\tuint32 physicalAddressRead = LatteReadCMD();\n\tuint32 ukn3 = LatteReadCMD();\n\n\tuint32 mode = (updateControl >> 1) & 3;\n\tuint32 soIndex = (updateControl >> 8) & 3;\n\n\tif (mode == 0)\n\t{\n\t\t// reset pointer\n\t\tMPTR virtualAddress = memory_physicalToVirtual(physicalAddressRead);\n\t\tuint32 bufferOffset = 0;\n\t\tLatteGPUState.contextRegister[mmVGT_STRMOUT_BUFFER_OFFSET_0 + 4 * soIndex] = bufferOffset;\n\t}\n\telse if (mode == 3)\n\t{\n\t\t// store current offset to memory\n\t\tMPTR virtualAddress = memory_physicalToVirtual(physicalAddressWrite);\n\t\tuint32 bufferOffset = LatteGPUState.contextRegister[mmVGT_STRMOUT_BUFFER_OFFSET_0 + 4 * soIndex];\n\t\tmemory_writeU32(virtualAddress + 0x00, bufferOffset);\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\treturn cmd;\n}\n\ntemplate<uint32 registerBaseMode>\nvoid LatteCP_itSetRegistersGeneric_handleSpecialRanges(uint32 registerStartIndex, uint32 registerEndIndex)\n{\n\tif constexpr (registerBaseMode == IT_SET_CONTEXT_REG)\n\t{\n\t\tif (registerStartIndex <= mmSQ_VTX_SEMANTIC_CLEAR && registerEndIndex >= mmSQ_VTX_SEMANTIC_CLEAR)\n\t\t{\n\t\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t\t{\n\t\t\t\tLatteGPUState.contextRegister[mmSQ_VTX_SEMANTIC_0 + i] = 0xFF;\n\t\t\t}\n\t\t}\n\t}\n}\n\ntemplate<uint32 TRegisterBase>\nLatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords)\n{\n\tuint32 registerOffset = LatteReadCMD();\n\tuint32 registerIndex = TRegisterBase + registerOffset;\n\tuint32 registerStartIndex = registerIndex;\n\tuint32 registerEndIndex = registerStartIndex + nWords;\n#ifdef CEMU_DEBUG_ASSERT\n\tcemu_assert_debug((registerIndex + nWords) <= LATTE_MAX_REGISTER);\n#endif\n\tuint32* outputReg = (uint32*)(LatteGPUState.contextRegister + registerIndex);\n\tif (LatteGPUState.contextControl0 == 0x80000077)\n\t{\n\t\t// state shadowing enabled\n\t\tuint32* shadowAddrs = LatteGPUState.contextRegisterShadowAddr + registerIndex;\n\t\tsint32 indexCounter = 0;\n\t\twhile (--nWords)\n\t\t{\n\t\t\tuint32 dataWord = LatteReadCMD();\n\t\t\tMPTR regShadowAddr = shadowAddrs[indexCounter];\n\t\t\tif (regShadowAddr)\n\t\t\t\t*(uint32*)(memory_base + regShadowAddr) = _swapEndianU32(dataWord);\n\t\t\toutputReg[indexCounter] = dataWord;\n\t\t\tindexCounter++;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// state shadowing disabled\n\t\tsint32 indexCounter = 0;\n\t\twhile (--nWords)\n\t\t{\n\t\t\t*outputReg = LatteReadCMD();\n\t\t\toutputReg++;\n\t\t}\n\t}\n\t// some register writes trigger special behavior\n\tLatteCP_itSetRegistersGeneric_handleSpecialRanges<TRegisterBase>(registerStartIndex, registerEndIndex);\n\treturn cmd;\n}\n\ntemplate<uint32 TRegisterBase, typename TRegRangeCallback>\nLatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords, TRegRangeCallback cbRegRange)\n{\n\tuint32 registerOffset = LatteReadCMD();\n\tuint32 registerIndex = TRegisterBase + registerOffset;\n\tuint32 registerStartIndex = registerIndex;\n\tuint32 registerEndIndex = registerStartIndex + nWords;\n#ifdef CEMU_DEBUG_ASSERT\n\tcemu_assert_debug((registerIndex + nWords) <= LATTE_MAX_REGISTER);\n#endif\n\tcbRegRange(registerStartIndex, registerEndIndex);\n\n\tuint32* outputReg = (uint32*)(LatteGPUState.contextRegister + registerIndex);\n\tif (LatteGPUState.contextControl0 == 0x80000077)\n\t{\n\t\t// state shadowing enabled\n\t\tuint32* shadowAddrs = LatteGPUState.contextRegisterShadowAddr + registerIndex;\n\t\tsint32 indexCounter = 0;\n\t\twhile (--nWords)\n\t\t{\n\t\t\tuint32 dataWord = LatteReadCMD();\n\t\t\tMPTR regShadowAddr = shadowAddrs[indexCounter];\n\t\t\tif (regShadowAddr)\n\t\t\t\t*(uint32*)(memory_base + regShadowAddr) = _swapEndianU32(dataWord);\n\t\t\toutputReg[indexCounter] = dataWord;\n\t\t\tindexCounter++;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// state shadowing disabled\n\t\tsint32 indexCounter = 0;\n\t\twhile (--nWords)\n\t\t{\n\t\t\t*outputReg = LatteReadCMD();\n\t\t\toutputReg++;\n\t\t}\n\t}\n\t// some register writes trigger special behavior\n\tLatteCP_itSetRegistersGeneric_handleSpecialRanges<TRegisterBase>(registerStartIndex, registerEndIndex);\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itIndexType(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 1);\n\tLatteGPUState.contextNew.VGT_DMA_INDEX_TYPE.set_INDEX_TYPE((Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE)LatteReadCMD());\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itNumInstances(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 1);\n\tuint32 numInstances = LatteReadCMD();\n\tif (numInstances == 0)\n\t\tnumInstances = 1;\n\tLatteGPUState.contextNew.VGT_DMA_NUM_INSTANCES.set_NUM_INSTANCES(numInstances);\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itWaitRegMem(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 6);\n\tuint32 word0 = LatteReadCMD();\n\tuint32 word1 = LatteReadCMD();\n\tuint32 word2 = LatteReadCMD();\n\tuint32 word3 = LatteReadCMD();\n\tuint32 word4 = LatteReadCMD();\n\tuint32 word5 = LatteReadCMD();\n\n\tuint32 compareOp = (word0) & 7;\n\tuint32 physAddr = word1 & ~3;\n\tcemu_assert_debug((physAddr&3) == 0);\n\tuint32 fenceValue = word3;\n\tuint32 fenceMask = word4;\n\n\tuint32* fencePtr = (uint32*)memory_getPointerFromPhysicalOffset(physAddr);\n\n\tconst uint32 GPU7_WAIT_MEM_OP_ALWAYS = 0;\n\tconst uint32 GPU7_WAIT_MEM_OP_LESS = 1;\n\tconst uint32 GPU7_WAIT_MEM_OP_LEQUAL = 2;\n\tconst uint32 GPU7_WAIT_MEM_OP_EQUAL = 3;\n\tconst uint32 GPU7_WAIT_MEM_OP_NOTEQUAL = 4;\n\tconst uint32 GPU7_WAIT_MEM_OP_GEQUAL = 5;\n\tconst uint32 GPU7_WAIT_MEM_OP_GREATER = 6;\n\tconst uint32 GPU7_WAIT_MEM_OP_NEVER = 7;\n\n\tLatteCP_signalEnterWait();\n\n\tbool stalls = false;\n\tif ((word0 & 0x10) != 0)\n\t{\n\t\t// wait for memory address\n\t\tperformanceMonitor.gpuTime_fenceTime.beginMeasuring();\n\t\twhile (true)\n\t\t{\n\t\t\tuint32 fenceMemValue = _swapEndianU32(*fencePtr);\n\t\t\tfenceMemValue &= fenceMask;\n\t\t\tif (compareOp == GPU7_WAIT_MEM_OP_LESS)\n\t\t\t{\n\t\t\t\tif (fenceMemValue < fenceValue)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (compareOp == GPU7_WAIT_MEM_OP_LEQUAL)\n\t\t\t{\n\t\t\t\tif (fenceMemValue <= fenceValue)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (compareOp == GPU7_WAIT_MEM_OP_EQUAL)\n\t\t\t{\n\t\t\t\tif (fenceMemValue == fenceValue)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (compareOp == GPU7_WAIT_MEM_OP_NOTEQUAL)\n\t\t\t{\n\t\t\t\tif (fenceMemValue != fenceValue)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (compareOp == GPU7_WAIT_MEM_OP_GEQUAL)\n\t\t\t{\n\t\t\t\tif (fenceMemValue >= fenceValue)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (compareOp == GPU7_WAIT_MEM_OP_GREATER)\n\t\t\t{\n\t\t\t\tif (fenceMemValue > fenceValue)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (compareOp == GPU7_WAIT_MEM_OP_ALWAYS)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (compareOp == GPU7_WAIT_MEM_OP_NEVER)\n\t\t\t{\n\t\t\t\tcemuLog_logOnce(LogType::Force, \"Latte: WAIT_MEM_OP_NEVER encountered\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t\tif (!stalls)\n\t\t\t{\n\t\t\t\tg_renderer->NotifyLatteCommandProcessorIdle();\n\t\t\t\tstalls = true;\n\t\t\t}\n\n\t\t\t// check if any GPU events happened\n\t\t\tLatteTiming_HandleTimedVsync();\n\t\t\tLatteAsyncCommands_checkAndExecute();\n\t\t}\n\t\tperformanceMonitor.gpuTime_fenceTime.endMeasuring();\n\t}\n\telse\n\t{\n\t\t// wait for register\n\t\tdebugBreakpoint();\n\t}\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itMemWrite(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 4);\n\tuint32 word0 = LatteReadCMD();\n\tuint32 word1 = LatteReadCMD();\n\tuint32 word2 = LatteReadCMD();\n\tuint32 word3 = LatteReadCMD();\n\n\tMPTR valuePhysAddr = (word0 & ~3);\n\tif (valuePhysAddr == 0)\n\t{\n\t\tcemuLog_log(LogType::Force, \"GPU: Invalid itMemWrite to null pointer\");\n\t\treturn cmd;\n\t}\n\tuint32be* memPtr = (uint32be*)memory_getPointerFromPhysicalOffset(valuePhysAddr);\n\n\tif (word1 == 0x40000)\n\t{\n\t\t// write U32\n\t\tstdx::atomic_ref<uint32be> atomicRef(*memPtr);\n\t\tatomicRef.store(word2);\n\t}\n\telse if (word1 == 0x00000)\n\t{\n\t\t// write U64\n\t\t// note: The U32s are swapped here, but needs verification. Also, it seems like the two U32 halves are written independently and the U64 as a whole is not atomic -> investiagte\n\t\tstdx::atomic_ref<uint64be> atomicRef(*(uint64be*)memPtr);\n\t\tatomicRef.store(((uint64le)word2 << 32) | word3);\n\t}\n\telse if (word1 == 0x20000)\n\t{\n\t\t// write U64 (little endian)\n\t\tstdx::atomic_ref<uint64le> atomicRef(*(uint64le*)memPtr);\n\t\tatomicRef.store(((uint64le)word3 << 32) | word2);\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itEventWriteEOP(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 5);\n\tuint32 word0 = LatteReadCMD();\n\tuint32 word1 = LatteReadCMD();\n\tuint32 word2 = LatteReadCMD();\n\tuint32 word3 = LatteReadCMD(); // value low bits\n\tuint32 word4 = LatteReadCMD(); // value high bits\n\n\tcemu_assert_debug(word2 == 0x40000000 || word2 == 0x42000000);\n\n\tif (word0 == 0x504 && (word2&0x40000000)) // todo - figure out the flags\n\t{\n\t\tstdx::atomic_ref<uint64be> atomicRef(*(uint64be*)memory_getPointerFromPhysicalOffset(word1));\n\t\tuint64 val = ((uint64)word4 << 32) | word3;\n\t\tatomicRef.store(val);\n\t}\n\telse\n\t{\tcemu_assert_unimplemented();\n\t}\n\tbool triggerInterrupt = (word2 & 0x2000000) != 0;\n\tif (triggerInterrupt)\n\t{\n\t\t// todo - timestamp interrupt\n\t}\n\tTCL::TCLGPUNotifyNewRetirementTimestamp();\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itMemSemaphore(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 2);\n\tMPTR semaphorePhysicalAddress = LatteReadCMD();\n\tuint32 semaphoreControl = LatteReadCMD();\n\tuint8 SEM_SIGNAL = (semaphoreControl >> 29) & 7;\n\n\tstd::atomic<uint64le>* semaphoreData = _rawPtrToAtomic((uint64le*)memory_getPointerFromPhysicalOffset(semaphorePhysicalAddress));\n\tstatic_assert(sizeof(std::atomic<uint64le>) == sizeof(uint64le));\n\n\tif (SEM_SIGNAL == 6)\n\t{\n\t\t// signal\n\t\tsemaphoreData->fetch_add(1);\n\t}\n\telse if(SEM_SIGNAL == 7)\n\t{\n\t\t// wait\n\t\tLatteCP_signalEnterWait();\n\t\tsize_t loopCount = 0;\n\t\twhile (true)\n\t\t{\n\t\t\tuint64le oldVal = semaphoreData->load();\n\t\t\tif (oldVal == 0)\n\t\t\t{\n\t\t\t\tloopCount++;\n\t\t\t\tif (loopCount > 2000)\n\t\t\t\t\tstd::this_thread::yield();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (semaphoreData->compare_exchange_strong(oldVal, oldVal - 1))\n\t\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itContextControl(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 2);\n\tuint32 word0 = LatteReadCMD();\n\tuint32 word1 = LatteReadCMD();\n\tLatteGPUState.contextControl0 = word0;\n\tLatteGPUState.contextControl1 = word1;\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itLoadReg(LatteCMDPtr cmd, uint32 nWords, uint32 regBase)\n{\n\tif (nWords < 2 || (nWords & 1) != 0)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"itLoadReg: Invalid nWords value\");\n\t\treturn cmd;\n\t}\n\tMPTR physAddressRegArea = LatteReadCMD();\n\tuint32 waitForIdle = LatteReadCMD();\n\tuint32 loadEntries = (nWords - 2) / 2;\n\tuint32 regShadowMemAddr = physAddressRegArea;\n\tfor (uint32 i = 0; i < loadEntries; i++)\n\t{\n\t\tuint32 regOffset = LatteReadCMD();\n\t\tuint32 regCount = LatteReadCMD();\n\t\tcemu_assert_debug(regCount != 0);\n\t\tuint32 regAddr = regBase + regOffset;\n\t\tfor (uint32 f = 0; f < regCount; f++)\n\t\t{\n\t\t\tLatteGPUState.contextRegisterShadowAddr[regAddr] = regShadowMemAddr;\n\t\t\tLatteGPUState.contextRegister[regAddr] = memory_read<uint32>(regShadowMemAddr);\n\t\t\tregAddr++;\n\t\t\tregShadowMemAddr += 4;\n\t\t}\n\t}\n\treturn cmd;\n}\n\nbool conditionalRenderActive = false;\n\nLatteCMDPtr LatteCP_itSetPredication(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 2);\n\tMPTR physQueryInfo = LatteReadCMD();\n\tuint32 flags = LatteReadCMD();\n\n\tuint32 queryTypeFlag = (flags >> 13) & 7;\n\tuint32 pixelsMustPassFlag = (flags >> 31) & 1;\n\tuint32 dontWaitFlag = (flags >> 1) & 19;\n\n\tif (queryTypeFlag == 0)\n\t{\n\t\t// disable conditional render\n\t\tif (conditionalRenderActive == false)\n\t\t\tdebug_printf(\"conditionalRenderActive already inactive\\n\");\n\t\tconditionalRenderActive = false;\n\t}\n\telse\n\t{\n\t\t// enable conditonal render\n\t\tif (conditionalRenderActive == true)\n\t\t\tdebug_printf(\"conditionalRenderActive already active\\n\");\n\t\tconditionalRenderActive = true;\n\t}\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itDrawIndex2(LatteCMDPtr cmd, uint32 nWords, DrawPassContext& drawPassCtx)\n{\n\tcemu_assert_debug(nWords == 5);\n\tuint32 ukn1 = LatteReadCMD();\n\tMPTR physIndices = LatteReadCMD();\n\tuint32 ukn2 = LatteReadCMD();\n\tuint32 count = LatteReadCMD();\n\tuint32 ukn3 = LatteReadCMD();\n\n\tLatteGPUState.currentDrawCallTick = GetTickCount();\n\tdrawPassCtx.executeDraw(count, false, physIndices);\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itDrawIndexAuto(LatteCMDPtr cmd, uint32 nWords, DrawPassContext& drawPassCtx)\n{\n\tcemu_assert_debug(nWords == 2);\n\tuint32 count = LatteReadCMD();\n\tuint32 ukn = LatteReadCMD();\n\tLatteGPUState.currentDrawCallTick = GetTickCount();\n\t// todo - better way to identify compute drawcalls\n\tif ((LatteGPUState.contextRegister[mmSQ_CONFIG] >> 24) == 0xE4)\n\t{\n\t\tuint32 vsProgramCode = ((LatteGPUState.contextRegister[mmSQ_PGM_START_ES] & 0xFFFFFF) << 8);\n\t\tuint32 vsProgramSize = LatteGPUState.contextRegister[mmSQ_PGM_START_ES + 1] << 3;\n\t\tcemuLog_logDebug(LogType::Force, \"Compute {} {:08x} {:08x} (unsupported)\", count, vsProgramCode, vsProgramSize);\n\t}\n\telse\n\t{\n\t\tdrawPassCtx.executeDraw(count, true, MPTR_NULL);\n\t}\n\treturn cmd;\n}\n\nMPTR _tempIndexArrayMPTR = MPTR_NULL;\n\nLatteCMDPtr LatteCP_itDrawImmediate(LatteCMDPtr cmd, uint32 nWords, DrawPassContext& drawPassCtx)\n{\n\tuint32 count = LatteReadCMD();\n\tuint32 ukn1 = LatteReadCMD();\n\t// reserve array for index data\t\n\tif (_tempIndexArrayMPTR == MPTR_NULL)\n\t\t_tempIndexArrayMPTR = coreinit_allocFromSysArea(0x4000 * sizeof(uint32), 0x4);\n\n\tLatteGPUState.currentDrawCallTick = GetTickCount();\n\t// calculate size of index data in packet and read indices\n\tuint32 numIndexU32s;\n\tauto indexType = LatteGPUState.contextNew.VGT_DMA_INDEX_TYPE.get_INDEX_TYPE();\n\tif (indexType == Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE::U16_BE)\n\t{\n\t\t// 16bit indices\n\t\tnumIndexU32s = (count + 1) / 2;\n\t\tmemcpy(memory_getPointerFromVirtualOffset(_tempIndexArrayMPTR), cmd, numIndexU32s * sizeof(uint32));\n\t\tLatteSkipCMD(numIndexU32s);\n\t\t// swap pairs\n\t\tuint32* indexDataU32 = (uint32*)memory_getPointerFromVirtualOffset(_tempIndexArrayMPTR);\n\t\tfor (uint32 i = 0; i < numIndexU32s; i++)\n\t\t{\n\t\t\tindexDataU32[i] = (indexDataU32[i] >> 16) | (indexDataU32[i] << 16);\n\t\t}\n\t\tLatteIndices_invalidate(memory_getPointerFromVirtualOffset(_tempIndexArrayMPTR), numIndexU32s * sizeof(uint32));\n\t}\n\telse if (indexType == Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE::U32_BE)\n\t{\n\t\t// 32bit indices\n\t\tcemu_assert_debug(false); // testing needed\n\t\tnumIndexU32s = count;\n\t\tmemcpy(memory_getPointerFromVirtualOffset(_tempIndexArrayMPTR), cmd, numIndexU32s * sizeof(uint32));\n\t\tLatteSkipCMD(numIndexU32s);\n\t\tLatteIndices_invalidate(memory_getPointerFromVirtualOffset(_tempIndexArrayMPTR), numIndexU32s * sizeof(uint32));\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"itDrawImmediate - Unsupported index type\");\n\t\treturn cmd;\n\t}\n\tcemu_assert_debug(nWords == (2 + numIndexU32s)); // verify packet size\n\n\tdrawPassCtx.executeDraw(count, false, _tempIndexArrayMPTR);\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itHLESampleTimer(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 1);\n\tMPTR timerMPTR = (MPTR)LatteReadCMD();\n\tmemory_writeU64(timerMPTR, coreinit::OSGetSystemTime());\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itHLESpecialState(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 2);\n\tuint32 stateId = LatteReadCMD();\n\tuint32 stateValue = LatteReadCMD();\n\tif (stateId > GX2_SPECIAL_STATE_COUNT)\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n\telse\n\t{\n\t\tLatteGPUState.contextNew.GetSpecialStateValues()[stateId] = stateValue;\n\t}\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itHLEBeginOcclusionQuery(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 1);\n\tMPTR queryMPTR = (MPTR)LatteReadCMD();\n\tLatteQuery_BeginOcclusionQuery(queryMPTR);\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itHLEEndOcclusionQuery(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 1);\n\tMPTR queryMPTR = (MPTR)LatteReadCMD();\n\tLatteQuery_EndOcclusionQuery(queryMPTR);\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itHLEBottomOfPipeCB(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 3);\n\tMPTR timestampMPTR = (uint32)LatteReadCMD();\n\tuint32 timestampHigh = (uint32)LatteReadCMD();\n\tuint32 timestampLow = (uint32)LatteReadCMD();\n\tuint64 timestamp = ((uint64)timestampHigh << 32ULL) | (uint64)timestampLow;\n\t// write timestamp\n\t*(uint32*)memory_getPointerFromPhysicalOffset(timestampMPTR) = _swapEndianU32((uint32)(timestamp >> 32));\n\t*(uint32*)memory_getPointerFromPhysicalOffset(timestampMPTR + 4) = _swapEndianU32((uint32)timestamp);\n\t// send event\n\tGX2::__GX2NotifyEvent(GX2::GX2CallbackEventType::TIMESTAMP_BOTTOM);\n\treturn cmd;\n}\n\n// GPU-side handler for GX2CopySurface/GX2CopySurfaceEx and similar\nLatteCMDPtr LatteCP_itHLECopySurfaceNew(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 26);\n\t// src\n\tMPTR srcPhysAddr = LatteReadCMD();\n\tMPTR srcMipAddr = LatteReadCMD();\n\tuint32 srcSwizzle = LatteReadCMD();\n\tLatte::E_GX2SURFFMT srcSurfaceFormat = (Latte::E_GX2SURFFMT)LatteReadCMD();\n\tsint32 srcWidth = LatteReadCMD();\n\tsint32 srcHeight = LatteReadCMD();\n\tsint32 srcDepth = LatteReadCMD();\n\tuint32 srcPitch = LatteReadCMD();\n\tuint32 srcSlice = LatteReadCMD();\n\tLatte::E_DIM srcDim = (Latte::E_DIM)LatteReadCMD();\n\tLatte::E_HWTILEMODE srcTilemode = (Latte::E_HWTILEMODE)LatteReadCMD();\n\tsint32 srcAA = LatteReadCMD();\n\tsint32 srcLevel = LatteReadCMD();\n\t// dst\n\tMPTR dstPhysAddr = LatteReadCMD();\n\tMPTR dstMipAddr = LatteReadCMD();\n\tuint32 dstSwizzle = LatteReadCMD();\n\tLatte::E_GX2SURFFMT dstSurfaceFormat = (Latte::E_GX2SURFFMT)LatteReadCMD();\n\tsint32 dstWidth = LatteReadCMD();\n\tsint32 dstHeight = LatteReadCMD();\n\tsint32 dstDepth = LatteReadCMD();\n\tuint32 dstPitch = LatteReadCMD();\n\tuint32 dstSlice = LatteReadCMD();\n\tLatte::E_DIM dstDim = (Latte::E_DIM)LatteReadCMD();\n\tLatte::E_HWTILEMODE dstTilemode = (Latte::E_HWTILEMODE)LatteReadCMD();\n\tsint32 dstAA = LatteReadCMD();\n\tsint32 dstLevel = LatteReadCMD();\n\n\tLatteSurfaceCopy_copySurfaceNew(srcPhysAddr, srcMipAddr, srcSwizzle, srcSurfaceFormat, srcWidth, srcHeight, srcDepth, srcPitch, srcSlice, srcDim, srcTilemode, srcAA, srcLevel, dstPhysAddr, dstMipAddr, dstSwizzle, dstSurfaceFormat, dstWidth, dstHeight, dstDepth, dstPitch, dstSlice, dstDim, dstTilemode, dstAA, dstLevel);\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itHLEClearColorDepthStencil(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcemu_assert_debug(nWords == 23);\n\tuint32 clearMask = LatteReadCMD(); // color (1), depth (2), stencil (4)\n\t// color buffer\n\tMPTR colorBufferMPTR = LatteReadCMD(); // physical address for color buffer\n\tLatte::E_GX2SURFFMT colorBufferFormat = (Latte::E_GX2SURFFMT)LatteReadCMD();\n\tLatte::E_HWTILEMODE colorBufferTilemode = (Latte::E_HWTILEMODE)LatteReadCMD();\n\tuint32 colorBufferWidth = LatteReadCMD();\n\tuint32 colorBufferHeight = LatteReadCMD();\n\tuint32 colorBufferPitch = LatteReadCMD();\n\tuint32 colorBufferViewFirstSlice = LatteReadCMD();\n\tuint32 colorBufferViewNumSlice = LatteReadCMD();\n\t// depth buffer\n\tMPTR depthBufferMPTR = LatteReadCMD(); // physical address for depth buffer\n\tLatte::E_GX2SURFFMT depthBufferFormat = (Latte::E_GX2SURFFMT)LatteReadCMD();\n\tLatte::E_HWTILEMODE depthBufferTileMode = (Latte::E_HWTILEMODE)LatteReadCMD();\n\tuint32 depthBufferWidth = LatteReadCMD();\n\tuint32 depthBufferHeight = LatteReadCMD();\n\tuint32 depthBufferPitch = LatteReadCMD();\n\tuint32 depthBufferViewFirstSlice = LatteReadCMD();\n\tuint32 depthBufferViewNumSlice = LatteReadCMD();\n\n\tfloat r = (float)LatteReadCMD() / 255.0f;\n\tfloat g = (float)LatteReadCMD() / 255.0f;\n\tfloat b = (float)LatteReadCMD() / 255.0f;\n\tfloat a = (float)LatteReadCMD() / 255.0f;\n\n\tfloat clearDepth;\n\t*(uint32*)&clearDepth = LatteReadCMD();\n\tuint32 clearStencil = LatteReadCMD();\n\n\tLatteRenderTarget_itHLEClearColorDepthStencil(\n\t\tclearMask, \n\t\tcolorBufferMPTR, colorBufferFormat, colorBufferTilemode, colorBufferWidth, colorBufferHeight, colorBufferPitch, colorBufferViewFirstSlice, colorBufferViewNumSlice,\n\t\tdepthBufferMPTR, depthBufferFormat, depthBufferTileMode, depthBufferWidth, depthBufferHeight, depthBufferPitch, depthBufferViewFirstSlice, depthBufferViewNumSlice,\n\t\tr, g, b, a,\n\t\tclearDepth, clearStencil);\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itHLERequestSwapBuffers(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcatchOpenGLError();\n\tcemu_assert_debug(nWords == 1);\n\tMPTR reserved1 = LatteReadCMD();\n\t// request flip counter increase (will be increased on next flip)\n\tLatteGPUState.flipRequestCount.fetch_add(1);\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itHLESwapScanBuffer(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcatchOpenGLError();\n\tcemu_assert_debug(nWords == 1);\n\tMPTR reserved1 = LatteReadCMD(); // reserved\n\tLatteRenderTarget_itHLESwapScanBuffer();\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itHLEWaitForFlip(LatteCMDPtr cmd, uint32 nWords)\n{\n\tcatchOpenGLError();\n\tcemu_assert_debug(nWords == 1);\n\tMPTR reserved1 = LatteReadCMD(); // reserved\n\t// wait for flip\n\tuint32 currentFlipCount = LatteGPUState.flipCounter;\n\twhile (true)\n\t{\n\t\t_mm_pause();\n\t\tif (currentFlipCount != LatteGPUState.flipCounter)\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\t// check if any GPU events happened\n\t\tLatteTiming_HandleTimedVsync();\n\t\tstd::this_thread::yield();\n\t}\n\treturn cmd;\n}\n\nLatteCMDPtr LatteCP_itHLECopyColorBufferToScanBuffer(LatteCMDPtr cmd, uint32 nWords)\n{\n\tMPTR colorBufferPtr = LatteReadCMD(); // physical address\n\tuint32 colorBufferWidth = LatteReadCMD();\n\tuint32 colorBufferHeight = LatteReadCMD();\n\tuint32 colorBufferPitch = LatteReadCMD();\n\tLatte::E_HWTILEMODE colorBufferTilemode = (Latte::E_HWTILEMODE)LatteReadCMD();\n\tuint32 colorBufferSwizzle = LatteReadCMD();\n\tuint32 colorBufferSliceIndex = LatteReadCMD();\n\tuint32 colorBufferFormat = LatteReadCMD();\n\tuint32 renderTarget = LatteReadCMD();\n\n\tLatteRenderTarget_itHLECopyColorBufferToScanBuffer(colorBufferPtr, colorBufferWidth, colorBufferHeight, colorBufferSliceIndex, colorBufferFormat, colorBufferPitch, colorBufferTilemode, colorBufferSwizzle, renderTarget);\n\n\treturn cmd;\n}\n\nvoid LatteCP_dumpCommandBufferError(LatteCMDPtr cmdStart, LatteCMDPtr cmdEnd, LatteCMDPtr cmdError)\n{\n\tcemuLog_log(LogType::Force, \"Detected error in GPU command buffer\");\n\tcemuLog_log(LogType::Force, \"Dumping contents and info\");\n\tcemuLog_log(LogType::Force, \"Buffer 0x{0:08x} Size 0x{1:08x}\", memory_getVirtualOffsetFromPointer(cmdStart), memory_getVirtualOffsetFromPointer(cmdEnd));\n\tcemuLog_log(LogType::Force, \"Error at 0x{0:08x}\", memory_getVirtualOffsetFromPointer(cmdError));\n\tfor (LatteCMDPtr p = cmdStart; p < cmdEnd; p += 4)\n\t{\n\t\tif(cmdError >= p && cmdError < (p+4) )\n\t\t\tcemuLog_log(LogType::Force, \"0x{0:08x}: {1:08x} {2:08x} {3:08x} {4:08x} <<<<<\", memory_getVirtualOffsetFromPointer(p), p[0], p[1], p[2], p[3]);\n\t\telse\n\t\t\tcemuLog_log(LogType::Force, \"0x{0:08x}: {1:08x} {2:08x} {3:08x} {4:08x}\", memory_getVirtualOffsetFromPointer(p), p[0], p[1], p[2], p[3]);\n\t}\n\tcemuLog_waitForFlush();\n\tcemu_assert_debug(false);\n}\n\n// any drawcalls issued without changing textures, framebuffers, shader or other complex states can be done quickly without having to reinitialize the entire pipeline state\n// we implement this optimization by having a specialized version of LatteCP_processCommandBuffer, called right after drawcalls, which only implements commands that dont interfere with fast drawing. Other commands will cause this function to return to the complex and generic parser\nvoid LatteCP_processCommandBuffer_continuousDrawPass(DrawPassContext& drawPassCtx)\n{\n\tcemu_assert_debug(drawPassCtx.isWithinDrawPass());\n\t// quit early if there are parameters set which are generally incompatible with fast drawing\n\tif (LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] != 0)\n\t{\n\t\tdrawPassCtx.endDrawPass();\n\t\treturn;\n\t}\n\t// check for other special states?\n\n\twhile (true)\n\t{\n\t\tLatteCMDPtr cmd, cmdStart, cmdEnd;\n\t\tif (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd))\n\t\t{\n\t\t\tdrawPassCtx.endDrawPass();\n\t\t\treturn;\n\t\t}\n\n\t\twhile (cmd < cmdEnd)\n\t\t{\n\t\t\tLatteCMDPtr cmdBeforeCommand = cmd;\n\t\t\tuint32 itHeader = LatteReadCMD();\n\t\t\tuint32 itHeaderType = (itHeader >> 30) & 3;\n\t\t\tif (itHeaderType == 3)\n\t\t\t{\n\t\t\t\tuint32 itCode = (itHeader >> 8) & 0xFF;\n\t\t\t\tuint32 nWords = ((itHeader >> 16) & 0x3FFF) + 1;\n\t\t\t\tLatteCMDPtr cmdData = cmd;\n\t\t\t\tcmd += nWords;\n\t\t\t\tswitch (itCode)\n\t\t\t\t{\n\t\t\t\tcase IT_SET_RESOURCE: // attribute buffers, uniform buffers or texture units\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_RESOURCE>(cmdData, nWords, [&drawPassCtx](uint32 registerStart, uint32 registerEnd)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ((registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)) ||\n\t\t\t\t\t\t\t\t(registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)) ||\n\t\t\t\t\t\t\t\t(registerStart >= Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS && registerStart < (Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS + Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7)))\n\t\t\t\t\t\t\t\tdrawPassCtx.endDrawPass(); // texture updates end the current draw sequence\n\t\t\t\t\t\t\telse if (registerStart >= mmSQ_VTX_ATTRIBUTE_BLOCK_START && registerEnd <= mmSQ_VTX_ATTRIBUTE_BLOCK_END)\n\t\t\t\t\t\t\t\tdrawPassCtx.notifyModifiedVertexBuffer();\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tdrawPassCtx.notifyModifiedUniformBuffer();\n\t\t\t\t\t\t});\n\t\t\t\t\tif (!drawPassCtx.isWithinDrawPass())\n\t\t\t\t\t{\n\t\t\t\t\t\tdrawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_SET_ALU_CONST: // uniform register\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_ALU_CONST>(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_SET_CTL_CONST:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetRegistersGeneric<mmSQ_VTX_BASE_VTX_LOC>(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_SET_CONFIG_REG:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_CONFIG>(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_INDEX_TYPE:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itIndexType(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_NUM_INSTANCES:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itNumInstances(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_DRAW_INDEX_2:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itDrawIndex2(cmdData, nWords, drawPassCtx);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_SET_CONTEXT_REG:\n\t\t\t\t{\n\t\t\t\t\tdrawPassCtx.endDrawPass();\n\t\t\t\t\tdrawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcase IT_INDIRECT_BUFFER_PRIV:\n\t\t\t\t{\n\t\t\t\t\tdrawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);\n\t\t\t\t\tLatteCP_itIndirectBuffer(cmdData, nWords, drawPassCtx);\n\t\t\t\t\tif (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd)) // switch to sub buffer\n\t\t\t\t\t\tcemu_assert_debug(false);\n\n\t\t\t\t\t//if (!drawPassCtx.isWithinDrawPass())\n\t\t\t\t\t//\treturn cmdData;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\t// unsupported command for fast draw\n\t\t\t\t\tdrawPassCtx.endDrawPass();\n\t\t\t\t\tdrawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (itHeaderType == 2)\n\t\t\t{\n\t\t\t\t// filler packet\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// unsupported command for fast draw\n\t\t\t\tdrawPassCtx.endDrawPass();\n\t\t\t\tdrawPassCtx.PushCurrentCommandQueuePos(cmdBeforeCommand, cmdStart, cmdEnd);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\tif (drawPassCtx.isWithinDrawPass())\n\t\tdrawPassCtx.endDrawPass();\n}\n\nvoid LatteCP_processCommandBuffer(DrawPassContext& drawPassCtx)\n{\n\twhile (true)\n\t{\n\t\tLatteCMDPtr cmd, cmdStart, cmdEnd;\n\t\tif (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd))\n\t\t\tbreak;\n\t\tuint32 itHeader;\n\t\twhile (cmd < cmdEnd)\n\t\t{\n\t\t\titHeader = LatteReadCMD();\n\t\t\tuint32 itHeaderType = (itHeader >> 30) & 3;\n\t\t\tif (itHeaderType == 3)\n\t\t\t{\n\t\t\t\tuint32 itCode = (itHeader >> 8) & 0xFF;\n\t\t\t\tuint32 nWords = ((itHeader >> 16) & 0x3FFF) + 1;\n\t\t\t\tLatteCMDPtr cmdData = cmd;\n\t\t\t\tcmd += nWords;\n\t\t\t\tswitch (itCode)\n\t\t\t\t{\n\t\t\t\tcase IT_SET_CONTEXT_REG:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_CONTEXT>(cmdData, nWords);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_SET_RESOURCE:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_RESOURCE>(cmdData, nWords);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_SET_ALU_CONST:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_ALU_CONST>(cmdData, nWords);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_SET_CTL_CONST:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetRegistersGeneric<mmSQ_VTX_BASE_VTX_LOC>(cmdData, nWords);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_SET_SAMPLER:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_SAMPLER>(cmdData, nWords);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_SET_CONFIG_REG:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_CONFIG>(cmdData, nWords);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_SET_LOOP_CONST:\n\t\t\t\t{\n\t\t\t\t\t// todo\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_SURFACE_SYNC:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSurfaceSync(cmdData);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_INDIRECT_BUFFER_PRIV:\n\t\t\t\t{\n\t\t\t\t\tdrawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);\n\t\t\t\t\tLatteCP_itIndirectBuffer(cmdData, nWords, drawPassCtx);\n\t\t\t\t\tif (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd)) // switch to sub buffer\n\t\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_STRMOUT_BUFFER_UPDATE:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itStreamoutBufferUpdate(cmdData, nWords);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_INDEX_TYPE:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itIndexType(cmdData, nWords);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_NUM_INSTANCES:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itNumInstances(cmdData, nWords);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_DRAW_INDEX_2:\n\t\t\t\t{\n\t\t\t\t\tdrawPassCtx.beginDrawPass();\n\t\t\t\t\tLatteCP_itDrawIndex2(cmdData, nWords, drawPassCtx);\n\t\t\t\t\t// enter fast draw mode\n\t\t\t\t\tdrawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);\n\t\t\t\t\tLatteCP_processCommandBuffer_continuousDrawPass(drawPassCtx);\n\t\t\t\t\tcemu_assert_debug(!drawPassCtx.isWithinDrawPass());\n\t\t\t\t\tif (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd))\n\t\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_DRAW_INDEX_AUTO:\n\t\t\t\t{\n\t\t\t\t\tdrawPassCtx.beginDrawPass();\n\t\t\t\t\tLatteCP_itDrawIndexAuto(cmdData, nWords, drawPassCtx);\n\t\t\t\t\t// enter fast draw mode\n\t\t\t\t\tdrawPassCtx.PushCurrentCommandQueuePos(cmd, cmdStart, cmdEnd);\n\t\t\t\t\tLatteCP_processCommandBuffer_continuousDrawPass(drawPassCtx);\n\t\t\t\t\tcemu_assert_debug(!drawPassCtx.isWithinDrawPass());\n\t\t\t\t\tif (!drawPassCtx.PopCurrentCommandQueuePos(cmd, cmdStart, cmdEnd))\n\t\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\tcase IT_DRAW_INDEX_IMMD:\n\t\t\t\t{\n\t\t\t\t\tDrawPassContext drawPassCtx;\n\t\t\t\t\tdrawPassCtx.beginDrawPass();\n\t\t\t\t\tLatteCP_itDrawImmediate(cmdData, nWords, drawPassCtx);\n\t\t\t\t\tdrawPassCtx.endDrawPass();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_WAIT_REG_MEM:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itWaitRegMem(cmdData, nWords);\n\t\t\t\t\tLatteTiming_HandleTimedVsync();\n\t\t\t\t\tLatteAsyncCommands_checkAndExecute();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_MEM_WRITE:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itMemWrite(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_CONTEXT_CONTROL:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itContextControl(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_MEM_SEMAPHORE:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itMemSemaphore(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_LOAD_CONFIG_REG:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itLoadReg(cmdData, nWords, LATTE_REG_BASE_CONFIG);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_LOAD_CONTEXT_REG:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itLoadReg(cmdData, nWords, LATTE_REG_BASE_CONTEXT);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_LOAD_ALU_CONST:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itLoadReg(cmdData, nWords, LATTE_REG_BASE_ALU_CONST);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_LOAD_LOOP_CONST:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itLoadReg(cmdData, nWords, LATTE_REG_BASE_LOOP_CONST);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_LOAD_RESOURCE:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itLoadReg(cmdData, nWords, LATTE_REG_BASE_RESOURCE);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_LOAD_SAMPLER:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itLoadReg(cmdData, nWords, LATTE_REG_BASE_SAMPLER);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_SET_PREDICATION:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itSetPredication(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_COPY_COLORBUFFER_TO_SCANBUFFER:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itHLECopyColorBufferToScanBuffer(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_TRIGGER_SCANBUFFER_SWAP:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_signalEnterWait();\n\t\t\t\t\tLatteCP_itHLESwapScanBuffer(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_WAIT_FOR_FLIP:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_signalEnterWait();\n\t\t\t\t\tLatteCP_itHLEWaitForFlip(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_REQUEST_SWAP_BUFFERS:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itHLERequestSwapBuffers(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_CLEAR_COLOR_DEPTH_STENCIL:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itHLEClearColorDepthStencil(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_COPY_SURFACE_NEW:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itHLECopySurfaceNew(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_SAMPLE_TIMER:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itHLESampleTimer(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_SPECIAL_STATE:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itHLESpecialState(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_BEGIN_OCCLUSION_QUERY:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itHLEBeginOcclusionQuery(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_END_OCCLUSION_QUERY:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itHLEEndOcclusionQuery(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_BOTTOM_OF_PIPE_CB:\n\t\t\t\t{\n\t\t\t\t\tLatteCP_itHLEBottomOfPipeCB(cmdData, nWords);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IT_HLE_SYNC_ASYNC_OPERATIONS:\n\t\t\t\t{\n\t\t\t\t\tLatteTextureReadback_UpdateFinishedTransfers(true);\n\t\t\t\t\tLatteQuery_UpdateFinishedQueriesForceFinishAll();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tdebug_printf(\"Unhandled IT %02x\\n\", itCode);\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (itHeaderType == 2)\n\t\t\t{\n\t\t\t\t// filler packet\n\t\t\t\t// has no body\n\t\t\t}\n\t\t\telse if (itHeaderType == 0)\n\t\t\t{\n\t\t\t\tuint32 registerBase = (itHeader & 0xFFFF);\n\t\t\t\tuint32 registerCount = ((itHeader >> 16) & 0x3FFF) + 1;\n\t\t\t\tif (registerBase == 0x304A)\n\t\t\t\t{\n\t\t\t\t\tGX2::__GX2NotifyEvent(GX2::GX2CallbackEventType::TIMESTAMP_TOP);\n\t\t\t\t\tLatteSkipCMD(registerCount);\n\t\t\t\t}\n\t\t\t\telse if (registerBase == 0x304B)\n\t\t\t\t{\n\t\t\t\t\tLatteSkipCMD(registerCount);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tLatteCP_dumpCommandBufferError(cmdStart, cmdEnd, cmd);\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdebug_printf(\"invalid itHeaderType %08x\\n\", itHeaderType);\n\t\t\t\tLatteCP_dumpCommandBufferError(cmdStart, cmdEnd, cmd);\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t}\n\t\tcemu_assert_debug(cmd == cmdEnd);\n\t}\n}\n\nvoid LatteCP_ProcessRingbuffer()\n{\n\tsint32 timerRecheck = 0; // estimates how much CP processing time has elapsed based on the executed commands, if the value exceeds CP_TIMER_RECHECK then _handleTimers() is called\n\tuint32be tmpBuffer[128];\n\twhile (true)\n\t{\n\t\tuint32 itHeader = LatteCP_readU32Deprc();\n\t\tuint32 itHeaderType = (itHeader >> 30) & 3;\n\t\tif (itHeaderType == 3)\n\t\t{\n\t\t\tuint32 itCode = (itHeader >> 8) & 0xFF;\n\t\t\tuint32 nWords = ((itHeader >> 16) & 0x3FFF) + 1;\n\t\t\tcemu_assert(nWords < 128);\n\t\t\tfor (sint32 i=0; i<nWords; i++)\n\t\t\t{\n\t\t\t\tuint32 word = LatteCP_readU32Deprc();\n\t\t\t\ttmpBuffer[i] = word;\n\t\t\t}\n\t\t\tLatteCMDPtr cmd = (LatteCMDPtr)tmpBuffer;\n\t\t\tswitch (itCode)\n\t\t\t{\n\t\t\tcase IT_SURFACE_SYNC:\n\t\t\t{\n\t\t\t\tLatteCP_itSurfaceSync(cmd);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t}\n\t\t\tbreak;\n\t\t\tcase IT_SET_CONTEXT_REG:\n\t\t\t{\n\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_CONTEXT>(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t}\n\t\t\tbreak;\n\t\t\tcase IT_SET_RESOURCE:\n\t\t\t{\n\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_RESOURCE>(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t}\n\t\t\tbreak;\n\t\t\tcase IT_SET_ALU_CONST:\n\t\t\t{\n\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_ALU_CONST>(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_CTL_CONST:\n\t\t\t{\n\t\t\t\tLatteCP_itSetRegistersGeneric<mmSQ_VTX_BASE_VTX_LOC>(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_SAMPLER:\n\t\t\t{\n\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_SAMPLER>(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_CONFIG_REG:\n\t\t\t{\n\t\t\t\tLatteCP_itSetRegistersGeneric<LATTE_REG_BASE_CONFIG>(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_INDIRECT_BUFFER_PRIV:\n\t\t\t{\n\t\t\t\tLatteCP_itIndirectBufferDepr(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_STRMOUT_BUFFER_UPDATE:\n\t\t\t{\n\t\t\t\tLatteCP_itStreamoutBufferUpdate(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_INDEX_TYPE:\n\t\t\t{\n\t\t\t\tLatteCP_itIndexType(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 1024;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_NUM_INSTANCES:\n\t\t\t{\n\t\t\t\tLatteCP_itNumInstances(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 1024;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_DRAW_INDEX_2:\n\t\t\t{\n\t\t\t\tDrawPassContext drawPassCtx;\n\t\t\t\tdrawPassCtx.beginDrawPass();\n\t\t\t\tLatteCP_itDrawIndex2(cmd, nWords, drawPassCtx);\n\t\t\t\tdrawPassCtx.endDrawPass();\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_DRAW_INDEX_AUTO:\n\t\t\t{\n\t\t\t\tDrawPassContext drawPassCtx;\n\t\t\t\tdrawPassCtx.beginDrawPass();\n\t\t\t\tLatteCP_itDrawIndexAuto(cmd, nWords, drawPassCtx);\n\t\t\t\tdrawPassCtx.endDrawPass();\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_DRAW_INDEX_IMMD:\n\t\t\t{\n\t\t\t\tDrawPassContext drawPassCtx;\n\t\t\t\tdrawPassCtx.beginDrawPass();\n\t\t\t\tLatteCP_itDrawImmediate(cmd, nWords, drawPassCtx);\n\t\t\t\tdrawPassCtx.endDrawPass();\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_WAIT_REG_MEM:\n\t\t\t{\n\t\t\t\tLatteCP_itWaitRegMem(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 16;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_MEM_WRITE:\n\t\t\t{\n\t\t\t\tLatteCP_itMemWrite(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 128;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_CONTEXT_CONTROL:\n\t\t\t{\n\t\t\t\tLatteCP_itContextControl(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 128;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_MEM_SEMAPHORE:\n\t\t\t{\n\t\t\t\tLatteCP_itMemSemaphore(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 128;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_CONFIG_REG:\n\t\t\t{\n\t\t\t\tLatteCP_itLoadReg(cmd, nWords, LATTE_REG_BASE_CONFIG);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_CONTEXT_REG:\n\t\t\t{\n\t\t\t\tLatteCP_itLoadReg(cmd, nWords, LATTE_REG_BASE_CONTEXT);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_ALU_CONST:\n\t\t\t{\n\t\t\t\tLatteCP_itLoadReg(cmd, nWords, LATTE_REG_BASE_ALU_CONST);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_LOOP_CONST:\n\t\t\t{\n\t\t\t\tLatteCP_itLoadReg(cmd, nWords, LATTE_REG_BASE_LOOP_CONST);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_RESOURCE:\n\t\t\t{\n\t\t\t\tLatteCP_itLoadReg(cmd, nWords, LATTE_REG_BASE_RESOURCE);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_SAMPLER:\n\t\t\t{\n\t\t\t\tLatteCP_itLoadReg(cmd, nWords, LATTE_REG_BASE_SAMPLER);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_LOOP_CONST:\n\t\t\t{\n\t\t\t\t// todo\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_PREDICATION:\n\t\t\t{\n\t\t\t\tLatteCP_itSetPredication(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_EVENT_WRITE_EOP:\n\t\t\t{\n\t\t\t\tLatteCP_itEventWriteEOP(cmd, nWords);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_COPY_COLORBUFFER_TO_SCANBUFFER:\n\t\t\t{\n\t\t\t\tLatteCP_itHLECopyColorBufferToScanBuffer(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_TRIGGER_SCANBUFFER_SWAP:\n\t\t\t{\n\t\t\t\tLatteCP_signalEnterWait();\n\t\t\t\tLatteCP_itHLESwapScanBuffer(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 64;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_WAIT_FOR_FLIP:\n\t\t\t{\n\t\t\t\tLatteCP_signalEnterWait();\n\t\t\t\tLatteCP_itHLEWaitForFlip(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_REQUEST_SWAP_BUFFERS:\n\t\t\t{\n\t\t\t\tLatteCP_itHLERequestSwapBuffers(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 32;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_CLEAR_COLOR_DEPTH_STENCIL:\n\t\t\t{\n\t\t\t\tLatteCP_itHLEClearColorDepthStencil(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 128;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_COPY_SURFACE_NEW:\n\t\t\t{\n\t\t\t\tLatteCP_itHLECopySurfaceNew(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 128;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_SAMPLE_TIMER:\n\t\t\t{\n\t\t\t\tLatteCP_itHLESampleTimer(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_SPECIAL_STATE:\n\t\t\t{\n\t\t\t\tLatteCP_itHLESpecialState(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_BEGIN_OCCLUSION_QUERY:\n\t\t\t{\n\t\t\t\tLatteCP_itHLEBeginOcclusionQuery(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_END_OCCLUSION_QUERY:\n\t\t\t{\n\t\t\t\tLatteCP_itHLEEndOcclusionQuery(cmd, nWords);\n\t\t\t\ttimerRecheck += CP_TIMER_RECHECK / 512;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_BOTTOM_OF_PIPE_CB:\n\t\t\t{\n\t\t\t\tLatteCP_itHLEBottomOfPipeCB(cmd, nWords);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_SYNC_ASYNC_OPERATIONS:\n\t\t\t{\n\t\t\t\t//LatteCP_skipWords<LatteCP_readU32Deprc>(nWords);\n\t\t\t\tLatteTextureReadback_UpdateFinishedTransfers(true);\n\t\t\t\tLatteQuery_UpdateFinishedQueriesForceFinishAll();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t}\n\t\telse if (itHeaderType == 2)\n\t\t{\n\t\t\t// filler packet, skip this\n\t\t\tcemu_assert_debug(itHeader == 0x80000000);\n\t\t}\n\t\telse if (itHeaderType == 0)\n\t\t{\n\t\t\tuint32 registerBase = (itHeader & 0xFFFF);\n\t\t\tuint32 registerCount = ((itHeader >> 16) & 0x3FFF) + 1;\n\t\t\tif (registerBase == 0x304A)\n\t\t\t{\n\t\t\t\tGX2::__GX2NotifyEvent(GX2::GX2CallbackEventType::TIMESTAMP_TOP);\n\t\t\t\tLatteCP_skipWords<LatteCP_readU32Deprc>(registerCount);\n\t\t\t}\n\t\t\telse if (registerBase == 0x304B)\n\t\t\t{\n\t\t\t\tLatteCP_skipWords<LatteCP_readU32Deprc>(registerCount);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebug_printf(\"invalid itHeaderType %08x\\n\", itHeaderType);\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\tif (timerRecheck >= CP_TIMER_RECHECK)\n\t\t{\n\t\t\tLatteTiming_HandleTimedVsync();\n\t\t\tLatteAsyncCommands_checkAndExecute();\n\t\t\ttimerRecheck = 0;\n\t\t}\n\t}\n}\n\n#ifdef LATTE_CP_LOGGING\nvoid LatteCP_DebugPrintCmdBuffer(uint32be* bufferPtr, uint32 size)\n{\n\tuint32be* bufferPtrInitial = bufferPtr;\n\tuint32be* bufferPtrEnd = bufferPtr + (size/4);\n\twhile (bufferPtr < bufferPtrEnd)\n\t{\n\t\tstd::string strPrefix = fmt::format(\"[PM4 Buf {:08x} Offs {:04x}]\", MEMPTR<void>(bufferPtr).GetMPTR(), (bufferPtr - bufferPtrInitial) * 4);\n\t\tuint32 itHeader = *bufferPtr;\n\t\tbufferPtr++;\n\t\tuint32 itHeaderType = (itHeader >> 30) & 3;\n\t\tif (itHeaderType == 3)\n\t\t{\n\t\t\tuint32 itCode = (itHeader >> 8) & 0xFF;\n\t\t\tuint32 nWords = ((itHeader >> 16) & 0x3FFF) + 1;\n\t\t\tuint32be* cmdData = bufferPtr;\n\t\t\tbufferPtr += nWords;\n\t\t\tswitch (itCode)\n\t\t\t{\n\t\t\tcase IT_SURFACE_SYNC:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_SURFACE_SYNC\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_CONTEXT_REG:\n\t\t\t{\n\t\t\t\tstd::string regVals;\n\t\t\t\tfor (uint32 i = 0; i < std::min<uint32>(nWords - 1, 8); i++)\n\t\t\t\t\tregVals.append(fmt::format(\"{:08x} \", cmdData[1 + i].value()));\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_SET_CONTEXT_REG Reg {:04x} RegValues {}\", strPrefix, cmdData[0].value(), regVals);\n\t\t\t}\n\t\t\tcase IT_SET_RESOURCE:\n\t\t\t{\n\t\t\t\tstd::string regVals;\n\t\t\t\tfor (uint32 i = 0; i < std::min<uint32>(nWords - 1, 8); i++)\n\t\t\t\t\tregVals.append(fmt::format(\"{:08x} \", cmdData[1+i].value()));\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_SET_RESOURCE Reg {:04x} RegValues {}\", strPrefix, cmdData[0].value(), regVals);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_ALU_CONST:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_SET_ALU_CONST\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_CTL_CONST:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_SET_CTL_CONST\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_SAMPLER:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_SET_SAMPLER\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_CONFIG_REG:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_SET_CONFIG_REG\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_INDIRECT_BUFFER_PRIV:\n\t\t\t{\n\t\t\t\tif (nWords != 3)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_INDIRECT_BUFFER_PRIV (malformed!)\", strPrefix);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tuint32 physicalAddress = cmdData[0];\n\t\t\t\t\tuint32 physicalAddressHigh = cmdData[1];\n\t\t\t\t\tuint32 sizeInDWords = cmdData[2];\n\t\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_INDIRECT_BUFFER_PRIV Addr {:08x} Size {:08x}\", strPrefix, physicalAddress, sizeInDWords*4);\n\t\t\t\t\tLatteCP_DebugPrintCmdBuffer(MEMPTR<uint32be>(physicalAddress), sizeInDWords * 4);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_STRMOUT_BUFFER_UPDATE:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_STRMOUT_BUFFER_UPDATE\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_INDEX_TYPE:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_INDEX_TYPE\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_NUM_INSTANCES:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_NUM_INSTANCES\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_DRAW_INDEX_2:\n\t\t\t{\n\t\t\t\tif (nWords != 5)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_DRAW_INDEX_2 (malformed!)\", strPrefix);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tuint32 ukn1 = cmdData[0];\n\t\t\t\t\tMPTR physIndices = cmdData[1];\n\t\t\t\t\tuint32 ukn2 = cmdData[2];\n\t\t\t\t\tuint32 count = cmdData[3];\n\t\t\t\t\tuint32 ukn3 = cmdData[4];\n\t\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_DRAW_INDEX_2 | Count {}\", strPrefix, count);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_DRAW_INDEX_AUTO:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_DRAW_INDEX_AUTO\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_DRAW_INDEX_IMMD:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_DRAW_INDEX_IMMD\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_WAIT_REG_MEM:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_WAIT_REG_MEM\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_MEM_WRITE:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_MEM_WRITE\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_CONTEXT_CONTROL:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_CONTEXT_CONTROL\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_MEM_SEMAPHORE:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_MEM_SEMAPHORE\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_CONFIG_REG:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_LOAD_CONFIG_REG\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_CONTEXT_REG:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_LOAD_CONTEXT_REG\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_ALU_CONST:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_LOAD_ALU_CONST\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_LOOP_CONST:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_LOAD_LOOP_CONST\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_RESOURCE:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_LOAD_RESOURCE\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_LOAD_SAMPLER:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_LOAD_SAMPLER\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_LOOP_CONST:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_SET_LOOP_CONST\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_SET_PREDICATION:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_SET_PREDICATION\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_COPY_COLORBUFFER_TO_SCANBUFFER:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_COPY_COLORBUFFER_TO_SCANBUFFER\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_TRIGGER_SCANBUFFER_SWAP:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_TRIGGER_SCANBUFFER_SWAP\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_WAIT_FOR_FLIP:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_WAIT_FOR_FLIP\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_REQUEST_SWAP_BUFFERS:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_REQUEST_SWAP_BUFFERS\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_CLEAR_COLOR_DEPTH_STENCIL:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_CLEAR_COLOR_DEPTH_STENCIL\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_COPY_SURFACE_NEW:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_COPY_SURFACE_NEW\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_SAMPLE_TIMER:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_SAMPLE_TIMER\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_SPECIAL_STATE:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_SPECIAL_STATE\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_BEGIN_OCCLUSION_QUERY:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_BEGIN_OCCLUSION_QUERY\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_END_OCCLUSION_QUERY:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_END_OCCLUSION_QUERY\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_BOTTOM_OF_PIPE_CB:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_BOTTOM_OF_PIPE_CB\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IT_HLE_SYNC_ASYNC_OPERATIONS:\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"{} IT_HLE_SYNC_ASYNC_OPERATIONS\", strPrefix);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tcemuLog_log(LogType::Force, \"{} Unsupported operation code\", strPrefix);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse if (itHeaderType == 2)\n\t\t{\n\t\t\t// filler packet\n\t\t}\n\t\telse if (itHeaderType == 0)\n\t\t{\n\t\t\tuint32 registerBase = (itHeader & 0xFFFF);\n\t\t\tuint32 registerCount = ((itHeader >> 16) & 0x3FFF) + 1;\n\t\t\tLatteCP_skipWords<LatteCP_readU32Deprc>(registerCount);\n\t\t\tcemuLog_log(LogType::Force, \"[LatteCP] itType=0 registerBase={:04x}\", registerBase);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Invalid itHeaderType %08x\\n\", itHeaderType);\n\t\t\treturn;\n\t\t}\n\t}\n}\n#endif"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteConst.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n\n// todo - this file contains legacy C-style defines, modernize and merge into LatteReg.h\n\n// GPU7/Latte hardware info\n\n#define LATTE_NUM_GPR\t\t\t\t\t\t128\n#define LATTE_NUM_STREAMOUT_BUFFER\t\t\t4\n#define LATTE_NUM_COLOR_TARGET\t\t\t\t8\n\n#define LATTE_NUM_MAX_TEX_UNITS\t\t\t\t18 // number of available texture units per shader stage (this might be higher than 18? BotW is the only game which uses more than 16?)\n#define LATTE_NUM_MAX_UNIFORM_BUFFERS\t\t16 // number of supported uniform buffer binding locations\n\n#define LATTE_VS_ATTRIBUTE_LIMIT\t\t\t32 // todo: verify\n#define\tLATTE_NUM_MAX_ATTRIBUTE_LOCATIONS\t256 // should this be 128 since there are only 128 GPRs?\n\n#define LATTE_MAX_VERTEX_BUFFERS\t\t\t16\n\n// Cemu-specific constants\n\n#define LATTE_CEMU_PS_TEX_UNIT_BASE \t\t0\n#define LATTE_CEMU_VS_TEX_UNIT_BASE \t\t32\n#define LATTE_CEMU_GS_TEX_UNIT_BASE \t\t64\n\n// vertex formats\n\n#define\tFMT_INVALID\t\t\t\t0x00\n#define\tFMT_8\t\t\t\t\t0x01\n#define\tFMT_4_4\t\t\t\t\t0x02\n#define\tFMT_3_3_2\t\t\t\t0x03\n#define\tFMT_16\t\t\t\t\t0x05\n#define\tFMT_16_FLOAT\t\t\t0x06\n#define\tFMT_8_8\t\t\t\t\t0x07\n#define\tFMT_5_6_5\t\t\t\t0x08\n#define\tFMT_6_5_5\t\t\t\t0x09\n#define\tFMT_1_5_5_5\t\t\t\t0x0A\n#define\tFMT_4_4_4_4\t\t\t\t0x0B\n#define\tFMT_5_5_5_1\t\t\t\t0x0C\n#define\tFMT_32\t\t\t\t\t0x0D\n#define\tFMT_32_FLOAT\t\t\t0x0E\n#define\tFMT_16_16\t\t\t\t0x0F\n#define\tFMT_16_16_FLOAT\t\t\t0x10\n#define\tFMT_8_24\t\t\t\t0x11\n#define\tFMT_8_24_FLOAT\t\t\t0x12\n#define\tFMT_24_8\t\t\t\t0x13\n#define\tFMT_24_8_FLOAT\t\t\t0x14\n#define\tFMT_10_11_11\t\t\t0x15\n#define\tFMT_10_11_11_FLOAT\t\t0x16\n#define\tFMT_11_11_10\t\t\t0x17\n#define\tFMT_11_11_10_FLOAT\t\t0x18\n#define\tFMT_2_10_10_10\t\t\t0x19\n#define\tFMT_8_8_8_8\t\t\t\t0x1A\n#define\tFMT_10_10_10_2\t\t\t0x1B\n#define\tFMT_X24_8_32_FLOAT\t\t0x1C\n#define\tFMT_32_32\t\t\t\t0x1D\n#define\tFMT_32_32_FLOAT\t\t\t0x1E\n#define\tFMT_16_16_16_16\t\t\t0x1F\n#define\tFMT_16_16_16_16_FLOAT\t0x20\n#define\tFMT_32_32_32_32\t\t\t0x22\n#define\tFMT_32_32_32_32_FLOAT\t0x23\n#define\tFMT_1\t\t\t\t\t0x25\n#define\tFMT_GB_GR\t\t\t\t0x27\n#define\tFMT_BG_RG\t\t\t\t0x28\n#define\tFMT_32_AS_8\t\t\t\t0x29\n#define\tFMT_32_AS_8_8\t\t\t0x2A\n#define\tFMT_5_9_9_9_SHAREDEXP\t0x2B\n#define\tFMT_8_8_8\t\t\t\t0x2C\n#define\tFMT_16_16_16\t\t\t0x2D\n#define\tFMT_16_16_16_FLOAT\t\t0x2E\n#define\tFMT_32_32_32\t\t\t0x2F\n#define\tFMT_32_32_32_FLOAT\t\t0x30\n\n#define LATTE_NFA_2\t\t\t\t2\n#define LATTE_NFA_3\t\t\t\t3\n\n#define LATTE_VTX_UNSIGNED\t\t0\n#define LATTE_VTX_SIGNED\t\t1\n\n// OpenGL constants\n\n#define GLVENDOR_UNKNOWN\t\t\t(0)\n#define GLVENDOR_AMD\t\t\t\t(1)\t // AMD/ATI\n#define GLVENDOR_NVIDIA\t\t\t\t(2)\n#define GLVENDOR_INTEL\t\t\t\t(5)\n#define GLVENDOR_APPLE\t\t\t\t(6)\n\n// decompiler\n\n#define LATTE_DECOMPILER_DTYPE_UNDETERMINED\t\t\t(0) // data type is unknown\n#define LATTE_DECOMPILER_DTYPE_UNSIGNED_INT\t\t\t(1) // 32bit unsigned integer\n#define LATTE_DECOMPILER_DTYPE_SIGNED_INT\t\t\t(2) // 32bit signed integer\n#define LATTE_DECOMPILER_DTYPE_FLOAT\t\t\t\t(3) // 32bit IEEE float\n\n#define LATTE_DECOMPILER_UNIFORM_MODE_NONE\t\t\t(0) // no uniform access at all\n#define LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED\t\t(1)\t// use remapped uniform array\n#define LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE\t(2) // load full cfile (uniform registers)\n#define LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK\t(3) // load full uniform banks (uniform buffers)\n\n#define LATTE_ANALYZER_IMPORT_INDEX_PARAM_MAX\t\t(0xFF)\n#define LATTE_ANALYZER_IMPORT_INDEX_SPIPOSITION\t\t(0x40000000) // gl_FragCoord\n\n#define LATTE_DECOMPILER_SAMPLER_NONE\t\t\t\t(0xFF)\n\nusing LattePrimitiveMode = Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE;\nusing LatteIndexType = Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE;\n\nnamespace LatteConst\n{\n\tenum class ShaderType : uint32\n\t{\n\t\tReserved = 0,\n\t\t// shaders for drawing\n\t\tFirstRender = 1,\n\t\tVertex = 1,\n\t\tPixel = 2,\n\t\tGeometry = 3,\n\t\tLastRender = 3,\n\t\t// compute shader\n\t\tCompute = 4,\n\t\tTotalCount = 5\n\t};\n\n\tenum class VertexFetchNFA\n\t{\n\t\tNUM_FORMAT_NORMALIZED,\n\t\tNUM_FORMAT_INT,\n\t\tNUM_FORMAT_SCALED,\n\t};\n\n\tenum class VertexFetchEndianMode\n\t{\n\t\tSWAP_NONE = 0, // little endian\n\t\tSWAP_U16 = 1, // U16 big endian\n\t\tSWAP_U32 = 2, // U32 big endian\n\t\t// helper for GX2 API\n\t\tSWAP_DEFAULT = 3,\n\t};\n\n\tenum class VertexFetchFormat : uint32\n\t{\n\t\t// some formats are for texture fetches only\n\n\t\tVTX_FMT_INVALID\t\t\t\t\t= 0x00,\n\n\t\tVTX_FMT_8\t\t\t\t\t\t= 0x01,\n\t\tVTX_FMT_8_8\t\t\t\t\t\t= 0x07,\n\t\tVTX_FMT_8_8_8\t\t\t\t\t= 0x2C,\n\t\tVTX_FMT_8_8_8_8\t\t\t\t\t= 0x1A,\n\n\t\tVTX_FMT_32_32\t\t\t\t\t= 0x1D,\n\t\tVTX_FMT_32_32_FLOAT\t\t\t\t= 0x1E,\n\n\t\tVTX_FMT_16_16_16\t\t\t\t= 0x2D,\n\t\tVTX_FMT_16_16_16_FLOAT\t\t\t= 0x2E,\n\t\tVTX_FMT_32_32_32\t\t\t\t= 0x2F,\n\t\tVTX_FMT_32_32_32_FLOAT\t\t\t= 0x30\n\t};\n\n\tenum class VertexFetchDstSel : uint8\n\t{\n\t\tX = 0,\n\t\tY = 1,\n\t\tZ = 2,\n\t\tW = 3,\n\t\tCONST_0F = 4,\n\t\tCONST_1F = 5,\n\t\tUNUSED = 6,\n\t\tMASKED = 7\n\t};\n\n\t// used in VTX_WORD0\n\tenum VertexFetchType2 : uint8\n\t{\n\t\tVERTEX_DATA = 0,\n\t\tINSTANCE_DATA = 1,\n\t\tNO_INDEX_OFFSET_DATA = 2,\n\t};\n\n};\n\n#define LATTE_MAX_REGISTER\t\t\t(0x10000)"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteDefaultShaders.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteDefaultShaders.h\"\n#include \"util/helpers/StringBuf.h\"\n\nLatteDefaultShader_t* _copyShader_depthToColor;\nLatteDefaultShader_t* _copyShader_colorToDepth;\n\nvoid LatteDefaultShader_pixelCopyShader_generateVSBody(StringBuf* vs)\n{\n\tvs->add(\"#version 420\\r\\n\");\n\tvs->add(\"out vec2 passUV;\\r\\n\");\n\tvs->add(\"uniform vec4 uf_vertexOffsets[4];\\r\\n\");\n\tvs->add(\"\\r\\n\");\n\tvs->add(\"void main(){\\r\\n\");\n\tvs->add(\"int vID = gl_VertexID;\\r\\n\");\n\tvs->add(\"passUV = uf_vertexOffsets[vID].zw;\\r\\n\");\n\tvs->add(\"gl_Position = vec4(uf_vertexOffsets[vID].xy, 0.0, 1.0);\\r\\n\");\n\tvs->add(\"}\\r\\n\");\n}\n\nGLuint gxShaderDepr_compileRaw(StringBuf* strSourceVS, StringBuf* strSourceFS);\nGLuint gxShaderDepr_compileRaw(const std::string& vertex_source, const std::string& fragment_source);\n\nLatteDefaultShader_t* LatteDefaultShader_getPixelCopyShader_depthToColor()\n{\n\tif (_copyShader_depthToColor != 0)\n\t\treturn _copyShader_depthToColor;\n\tcatchOpenGLError();\n\tLatteDefaultShader_t* defaultShader = (LatteDefaultShader_t*)malloc(sizeof(LatteDefaultShader_t));\n\tmemset(defaultShader, 0, sizeof(LatteDefaultShader_t));\n\n\tStringBuf fCStr_vertexShader(1024 * 16);\n\tLatteDefaultShader_pixelCopyShader_generateVSBody(&fCStr_vertexShader);\n\n\tStringBuf fCStr_defaultFragShader(1024 * 16);\n\tfCStr_defaultFragShader.add(\"#version 420\\r\\n\");\n\tfCStr_defaultFragShader.add(\"in vec2 passUV;\\r\\n\");\n\tfCStr_defaultFragShader.add(\"uniform sampler2D textureSrc;\\r\\n\");\n\tfCStr_defaultFragShader.add(\"layout(location = 0) out vec4 colorOut0;\\r\\n\");\n\tfCStr_defaultFragShader.add(\"\\r\\n\");\n\tfCStr_defaultFragShader.add(\"void main(){\\r\\n\");\n\tfCStr_defaultFragShader.add(\"colorOut0 = vec4(texture(textureSrc, passUV).r,0.0,0.0,1.0);\\r\\n\");\n\tfCStr_defaultFragShader.add(\"}\\r\\n\");\n\n\tdefaultShader->glProgamId = gxShaderDepr_compileRaw(&fCStr_vertexShader, &fCStr_defaultFragShader);\n\tcatchOpenGLError();\n\n\tdefaultShader->copyShaderUniforms.uniformLoc_textureSrc = glGetUniformLocation(defaultShader->glProgamId, \"textureSrc\");\n\tdefaultShader->copyShaderUniforms.uniformLoc_vertexOffsets = glGetUniformLocation(defaultShader->glProgamId, \"uf_vertexOffsets\");\n\n\t_copyShader_depthToColor = defaultShader;\n\tcatchOpenGLError();\n\treturn defaultShader;\n}\n\nLatteDefaultShader_t* LatteDefaultShader_getPixelCopyShader_colorToDepth()\n{\n\tif (_copyShader_colorToDepth != 0)\n\t\treturn _copyShader_colorToDepth;\n\tcatchOpenGLError();\n\tLatteDefaultShader_t* defaultShader = (LatteDefaultShader_t*)malloc(sizeof(LatteDefaultShader_t));\n\tmemset(defaultShader, 0, sizeof(LatteDefaultShader_t));\n\n\tStringBuf fCStr_vertexShader(1024 * 16);\n\tLatteDefaultShader_pixelCopyShader_generateVSBody(&fCStr_vertexShader);\n\n\tStringBuf fCStr_defaultFragShader(1024 * 16);\n\tfCStr_defaultFragShader.add(\"#version 420\\r\\n\");\n\tfCStr_defaultFragShader.add(\"in vec2 passUV;\\r\\n\");\n\tfCStr_defaultFragShader.add(\"uniform sampler2D textureSrc;\\r\\n\");\n\tfCStr_defaultFragShader.add(\"layout(location = 0) out vec4 colorOut0;\\r\\n\");\n\tfCStr_defaultFragShader.add(\"\\r\\n\");\n\tfCStr_defaultFragShader.add(\"void main(){\\r\\n\");\n\tfCStr_defaultFragShader.add(\"gl_FragDepth = texture(textureSrc, passUV).r;\\r\\n\");\n\tfCStr_defaultFragShader.add(\"}\\r\\n\");\n\n\n\tdefaultShader->glProgamId = gxShaderDepr_compileRaw(&fCStr_vertexShader, &fCStr_defaultFragShader);\n\tdefaultShader->copyShaderUniforms.uniformLoc_textureSrc = glGetUniformLocation(defaultShader->glProgamId, \"textureSrc\");\n\tdefaultShader->copyShaderUniforms.uniformLoc_vertexOffsets = glGetUniformLocation(defaultShader->glProgamId, \"uf_vertexOffsets\");\n\n\t_copyShader_colorToDepth = defaultShader;\n\tcatchOpenGLError();\n\treturn defaultShader;\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteDefaultShaders.h",
    "content": "\ntypedef struct\n{\n\tGLuint glProgamId;\n\tstruct\n\t{\n\t\tGLuint uniformLoc_textureSrc;\n\t\tGLuint uniformLoc_vertexOffsets;\n\t}copyShaderUniforms;\n}LatteDefaultShader_t;\n\nLatteDefaultShader_t* LatteDefaultShader_getPixelCopyShader_depthToColor();\nLatteDefaultShader_t* LatteDefaultShader_getPixelCopyShader_colorToDepth();"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteDraw.h",
    "content": "#pragma once\n#include \"Common/GLInclude/GLInclude.h\"\n\nvoid LatteDraw_cleanupAfterFrame();"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteGSCopyShaderParser.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n\nvoid LatteGSCopyShaderParser_addFetchedParam(LatteParsedGSCopyShader* shaderContext, uint32 offset, uint32 gprIndex)\n{\n\tif( shaderContext->numParam >= GPU7_COPY_SHADER_MAX_PARAMS )\n\t{\n\t\tdebug_printf(\"Copy shader: Too many fetched parameters\\n\");\n\t\tcemu_assert_suspicious();\n\t\treturn;\n\t}\n\tshaderContext->paramMapping[shaderContext->numParam].exportParam = 0xFF;\n\tshaderContext->paramMapping[shaderContext->numParam].offset = offset;\n\tshaderContext->paramMapping[shaderContext->numParam].gprIndex = gprIndex;\n\tshaderContext->numParam++;\n}\n\nvoid LatteGSCopyShaderParser_assignRegisterParameterOutput(LatteParsedGSCopyShader* shaderContext, uint32 gprIndex, uint32 exportType, uint32 exportParam)\n{\n\t// scan backwards to catch the most recently added entry in case a register has multiple entries\n\tfor(sint32 i=shaderContext->numParam-1; i>=0; i--)\n\t{\n\t\tif( shaderContext->paramMapping[i].gprIndex == gprIndex )\n\t\t{\n\t\t\tif( shaderContext->paramMapping[i].exportParam != 0xFF )\n\t\t\t\tcemu_assert_debug(false);\n\t\t\tif( exportParam >= 0x100 )\n\t\t\t\tcemu_assert_debug(false);\n\t\t\tshaderContext->paramMapping[i].exportType = (uint8)exportType;\n\t\t\tshaderContext->paramMapping[i].exportParam = (uint8)exportParam;\n\t\t\treturn;\n\t\t}\n\t}\n\tcemu_assert_debug(false); // register is exported but never initialized?\n}\n\nvoid LatteGSCopyShaderParser_addStreamWrite(LatteParsedGSCopyShader* shaderContext, uint32 bufferIndex, uint32 exportSourceGPR, uint32 exportArrayBase, uint32 memWriteArraySize, uint32 memWriteCompMask)\n{\n\t// get info about current state of GPR\n\tfor (sint32 i = shaderContext->numParam - 1; i >= 0; i--)\n\t{\n\t\tif (shaderContext->paramMapping[i].gprIndex == exportSourceGPR)\n\t\t{\n\t\t\tLatteGSCopyShaderStreamWrite_t streamWrite;\n\t\t\tstreamWrite.bufferIndex = (uint8)bufferIndex;\n\t\t\tstreamWrite.offset = shaderContext->paramMapping[i].offset;\n\t\t\tstreamWrite.exportArrayBase = exportArrayBase;\n\t\t\tstreamWrite.memWriteArraySize = memWriteArraySize;\n\t\t\tstreamWrite.memWriteCompMask = memWriteCompMask;\n\t\t\tshaderContext->list_streamWrites.push_back(streamWrite);\n\t\t\treturn;\n\t\t}\n\t}\n\tcemu_assert_debug(false); // GPR not initialized?\n}\n\nbool LatteGSCopyShaderParser_getExportTypeByOffset(LatteParsedGSCopyShader* shaderContext, uint32 offset, uint32* exportType, uint32* exportParam)\n{\n\tfor(sint32 i=0; i<shaderContext->numParam; i++)\n\t{\n\t\tif( shaderContext->paramMapping[i].offset == offset )\n\t\t{\n\t\t\t*exportType = shaderContext->paramMapping[i].exportType;\n\t\t\t*exportParam = shaderContext->paramMapping[i].exportParam;\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nbool LatteGSCopyShaderParser_parseClauseVtx(LatteParsedGSCopyShader* shaderContext, uint8* programData, uint32 programSize, uint32 addr, uint32 count)\n{\n\tfor(uint32 i=0; i<count; i++)\n\t{\n\t\tuint32 instructionAddr = addr*2+i*4;\n\t\tuint32 word0 = *(uint32*)(programData+instructionAddr*4+0);\n\t\tuint32 word1 = *(uint32*)(programData+instructionAddr*4+4);\n\t\tuint32 word2 = *(uint32*)(programData+instructionAddr*4+8);\n\t\tuint32 word3 = *(uint32*)(programData+instructionAddr*4+12);\n\t\tuint32 inst0_4 = (word0>>0)&0x1F;\n\t\tif( inst0_4 == GPU7_TEX_INST_VFETCH )\n\t\t{\n\t\t\t// data fetch\n\t\t\tuint32 fetchType = (word0>>5)&3;\n\t\t\tuint32 bufferId = (word0>>8)&0xFF;\n\t\t\tuint32 offset = (word2>>0)&0xFFFF;\n\t\t\tuint32 endianSwap = (word2>>16)&0x3;\n\t\t\tuint32 constNoStride = (word2>>18)&0x1;\n\t\t\tuint32 srcGpr = (word0>>16)&0x7F;\n\t\t\tuint32 srcRel = (word0>>23)&1;\n\t\t\tif( srcRel != 0 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 destGpr = (word1>>0)&0x7F;\n\t\t\tuint32 destRel = (word1>>7)&1;\n\t\t\tif( destRel != 0 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 dstSelX = (word1>>9)&0x7;\n\t\t\tuint32 dstSelY = (word1>>12)&0x7;\n\t\t\tuint32 dstSelZ = (word1>>15)&0x7;\n\t\t\tuint32 dstSelW = (word1>>18)&0x7;\n\n\t\t\tuint32 srcSelX = (word0>>24)&0x3;\n\t\t\tuint32 srcSelY = 0;\n\t\t\tuint32 srcSelZ = 0;\n\t\t\tuint32 srcSelW = 0;\n\n\t\t\tif( bufferId != 0x9F )\n\t\t\t{\n\t\t\t\tdebugBreakpoint(); // data not fetched from GS ring buffer\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif( endianSwap != 0 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tif( fetchType != 2 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tif( srcSelX != 0 || srcGpr != 0 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tif( dstSelX != 0 || dstSelY != 1 || dstSelZ != 2 || dstSelW != 3 )\n\t\t\t\tdebugBreakpoint();\n\t\t\t// remember imported parameter\n\t\t\tLatteGSCopyShaderParser_addFetchedParam(shaderContext, offset, destGpr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nLatteParsedGSCopyShader* LatteGSCopyShaderParser_parse(uint8* programData, uint32 programSize)\n{\n\tcemu_assert_debug((programSize & 3) == 0);\n\tLatteParsedGSCopyShader* shaderContext = new LatteParsedGSCopyShader();\n\tshaderContext->numParam = 0;\n\t// parse control flow instructions\n\tfor(uint32 i=0; i<programSize/8; i++)\n\t{\n\t\tuint32 cfWord0 = *(uint32*)(programData+i*8+0);\n\t\tuint32 cfWord1 = *(uint32*)(programData+i*8+4);\n\t\tuint32 cf_inst23_7 = (cfWord1>>23)&0x7F;\n\t\t// check the bigger opcode fields first\n\t\tif( cf_inst23_7 < 0x40 ) // at 0x40 the bits overlap with the ALU instruction encoding\n\t\t{\n\t\t\tbool isEndOfProgram = ((cfWord1>>21)&1)!=0;\n\t\t\tuint32 addr = cfWord0&0xFFFFFFFF;\n\t\t\tuint32 count = (cfWord1>>10)&7;\n\t\t\tif( ((cfWord1>>19)&1) != 0 )\n\t\t\t\tcount |= 0x8;\n\t\t\tcount++;\n\t\t\tif( cf_inst23_7 == GPU7_CF_INST_CALL_FS )\n\t\t\t{\n\t\t\t\t// nop\n\t\t\t}\n\t\t\telse if( cf_inst23_7 == GPU7_CF_INST_NOP )\n\t\t\t{\n\t\t\t\t// nop\n\t\t\t\tif( ((cfWord1>>0)&7) != 0 )\n\t\t\t\t\tdebugBreakpoint(); // pop count is not zero, \n\t\t\t}\n\t\t\telse if( cf_inst23_7 == GPU7_CF_INST_EXPORT || cf_inst23_7 == GPU7_CF_INST_EXPORT_DONE )\n\t\t\t{\n\t\t\t\t// export\n\t\t\t\tuint32 edType = (cfWord0>>13)&0x3;\n\t\t\t\tuint32 edIndexGpr = (cfWord0>>23)&0x7F;\n\t\t\t\tuint32 edRWRel = (cfWord0>>22)&1;\n\t\t\t\tif( edRWRel != 0 || edIndexGpr != 0 )\n\t\t\t\t\tdebugBreakpoint();\n\t\t\t\t// set export component selection\n\t\t\t\tuint8 exportComponentSel[4];\n\t\t\t\texportComponentSel[0] = (cfWord1>>0)&0x7;\n\t\t\t\texportComponentSel[1] = (cfWord1>>3)&0x7;\n\t\t\t\texportComponentSel[2] = (cfWord1>>6)&0x7;\n\t\t\t\texportComponentSel[3] = (cfWord1>>9)&0x7;\n\t\t\t\t// set export array base, index and burstcount (export field)\n\t\t\t\tuint32 exportArrayBase = (cfWord0>>0)&0x1FFF;\n\t\t\t\tuint32 exportBurstCount = (cfWord1>>17)&0xF;\n\t\t\t\t// set export source GPR and type\n\t\t\t\tuint32 exportSourceGPR = (cfWord0>>15)&0x7F;\n\t\t\t\tuint32 exportType = edType;\n\t\t\t\tif (exportArrayBase == GPU7_DECOMPILER_CF_EXPORT_BASE_POSITION && exportComponentSel[0] == 4 && exportComponentSel[1] == 4 && exportComponentSel[2] == 4 && exportComponentSel[3] == 4)\n\t\t\t\t{\n\t\t\t\t\t// aka gl_Position = vec4(0.0)\n\t\t\t\t\t// this instruction form is generated when the original shader doesn't assign gl_Position a value?\n\t\t\t\t}\n\t\t\t\telse if (exportComponentSel[0] != 0 || exportComponentSel[1] != 1 || exportComponentSel[2] != 2 || exportComponentSel[3] != 3)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// register as param\n\t\t\t\t\tfor (uint32 f = 0; f < exportBurstCount + 1; f++)\n\t\t\t\t\t{\n\t\t\t\t\t\tLatteGSCopyShaderParser_assignRegisterParameterOutput(shaderContext, exportSourceGPR + f, exportType, exportArrayBase + f);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( cf_inst23_7 == GPU7_CF_INST_VTX )\n\t\t\t{\n\t\t\t\tLatteGSCopyShaderParser_parseClauseVtx(shaderContext, programData, programSize, addr, count);\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_MEM_STREAM0_WRITE ||\n\t\t\t\tcf_inst23_7 == GPU7_CF_INST_MEM_STREAM1_WRITE )\n\t\t\t{\n\t\t\t\t// streamout\n\t\t\t\tuint32 bufferIndex;\n\t\t\t\tif (cf_inst23_7 == GPU7_CF_INST_MEM_STREAM0_WRITE)\n\t\t\t\t\tbufferIndex = 0;\n\t\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_MEM_STREAM1_WRITE)\n\t\t\t\t\tbufferIndex = 1;\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_debug(false);\n\n\t\t\t\tuint32 exportArrayBase = (cfWord0 >> 0) & 0x1FFF;\n\t\t\t\tuint32 memWriteArraySize = (cfWord1 >> 0) & 0xFFF;\n\t\t\t\tuint32 memWriteCompMask = (cfWord1 >> 12) & 0xF;\n\t\t\t\tuint32 exportSourceGPR = (cfWord0 >> 15) & 0x7F;\n\n\t\t\t\tLatteGSCopyShaderParser_addStreamWrite(shaderContext, bufferIndex, exportSourceGPR, exportArrayBase, memWriteArraySize, memWriteCompMask);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Copyshader: Unknown 23_7 clause 0x{:x} found\", cf_inst23_7);\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t\tif( isEndOfProgram )\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// ALU clauses not supported\n\t\t\tdebug_printf(\"Copyshader has ALU clause?\\n\");\n\t\t\tcemu_assert_debug(false);\n\t\t\tdelete shaderContext;\n\t\t\treturn nullptr;\n\t\t}\n\t}\n\t// verify if all registers are exported\n\tfor(sint32 i=0; i<shaderContext->numParam; i++)\n\t{\n\t\tif( shaderContext->paramMapping[i].exportParam == 0xFF )\n\t\t\tdebugBreakpoint();\n\t}\n\treturn shaderContext;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteIndices.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Common/cpu_features.h\"\n\n#if defined(ARCH_X86_64) && defined(__GNUC__)\n#include <immintrin.h>\n#elif defined(__aarch64__)\n#include <arm_neon.h>\n#endif\n\nstruct\n{\n\tstruct CacheEntry\n\t{\n\t\t// input data\n\t\tconst void* lastPtr;\n\t\tuint32 lastCount;\n\t\tLattePrimitiveMode lastPrimitiveMode;\n\t\tLatteIndexType lastIndexType;\n\t\tuint64 lastUsed;\n\t\t// output\n\t\tuint32 indexMin;\n\t\tuint32 indexMax;\n\t\tRenderer::INDEX_TYPE renderIndexType;\n\t\tuint32 outputCount;\n\t\tRenderer::IndexAllocation indexAllocation;\n\t};\n\tstd::array<CacheEntry, 8> entry;\n\tuint64 currentUsageCounter{0};\n}LatteIndexCache{};\n\nvoid LatteIndices_invalidate(const void* memPtr, uint32 size)\n{\n\tfor(auto& entry : LatteIndexCache.entry)\n\t{\n\t\tif (entry.lastPtr >= memPtr && (entry.lastPtr < ((uint8*)memPtr + size)) )\n\t\t{\n\t\t\tif(entry.lastPtr != nullptr)\n\t\t\t\tg_renderer->indexData_releaseIndexMemory(entry.indexAllocation);\n\t\t\tentry.lastPtr = nullptr;\n\t\t\tentry.lastCount = 0;\n\t\t}\n\t}\n}\n\nvoid LatteIndices_invalidateAll()\n{\n\tfor(auto& entry : LatteIndexCache.entry)\n\t{\n\t\tif (entry.lastPtr != nullptr)\n\t\t\tg_renderer->indexData_releaseIndexMemory(entry.indexAllocation);\n\t\tentry.lastPtr = nullptr;\n\t\tentry.lastCount = 0;\n\t}\n}\n\nuint64 LatteIndices_GetNextUsageIndex()\n{\n\treturn LatteIndexCache.currentUsageCounter++;\n}\n\nuint32 LatteIndices_calculateIndexOutputSize(LattePrimitiveMode primitiveMode, LatteIndexType indexType, uint32 count)\n{\n\tif (primitiveMode == LattePrimitiveMode::QUADS)\n\t{\n\t\tsint32 numQuads = count / 4;\n\t\tif (indexType == LatteIndexType::AUTO)\n\t\t{\n\t\t\tif(count <= 0xFFFF)\n\t\t\t\treturn numQuads * 6 * sizeof(uint16);\n\t\t\treturn numQuads * 6 * sizeof(uint32);\n\t\t}\n\t\tif (indexType == LatteIndexType::U16_BE || indexType == LatteIndexType::U16_LE)\n\t\t\treturn numQuads * 6 * sizeof(uint16);\n\t\tif (indexType == LatteIndexType::U32_BE || indexType == LatteIndexType::U32_LE)\n\t\t\treturn numQuads * 6 * sizeof(uint32);\n\t\tcemu_assert_suspicious();\n\t\treturn 0;\n\t}\n\telse if (primitiveMode == LattePrimitiveMode::QUAD_STRIP)\n\t{\n\t\tif (count <= 3)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\t\tsint32 numQuads = (count-2) / 2;\n\t\tif (indexType == LatteIndexType::AUTO)\n\t\t{\n\t\t\tif (count <= 0xFFFF)\n\t\t\t\treturn numQuads * 6 * sizeof(uint16);\n\t\t\treturn numQuads * 6 * sizeof(uint32);\n\t\t}\n\t\tif (indexType == LatteIndexType::U16_BE || indexType == LatteIndexType::U16_LE)\n\t\t\treturn numQuads * 6 * sizeof(uint16);\n\t\tif (indexType == LatteIndexType::U32_BE || indexType == LatteIndexType::U32_LE)\n\t\t\treturn numQuads * 6 * sizeof(uint32);\n\t\tcemu_assert_suspicious();\n\t\treturn 0;\n\t}\n\telse if (primitiveMode == LattePrimitiveMode::LINE_LOOP)\n\t{\n\t\tcount++; // one extra vertex to reconnect the LINE_STRIP to the beginning\n\t\tif (indexType == LatteIndexType::AUTO)\n\t\t{\n\t\t\tif (count <= 0xFFFF)\n\t\t\t\treturn count * sizeof(uint16);\n\t\t\treturn count * sizeof(uint32);\n\t\t}\n\t\tif (indexType == LatteIndexType::U16_BE || indexType == LatteIndexType::U16_LE)\n\t\t\treturn count * sizeof(uint16);\n\t\tif (indexType == LatteIndexType::U32_BE || indexType == LatteIndexType::U32_LE)\n\t\t\treturn count * sizeof(uint32);\n\t\tcemu_assert_suspicious();\n\t\treturn 0;\n\t}\n\telse if (primitiveMode == LattePrimitiveMode::TRIANGLE_FAN && g_renderer->GetType() == RendererAPI::Metal)\n\t{\n\t\tif (indexType == LatteIndexType::AUTO)\n\t\t{\n\t\t\tif (count <= 0xFFFF)\n\t\t\t\treturn count * sizeof(uint16);\n\t\t\treturn count * sizeof(uint32);\n\t\t}\n\t\tif (indexType == LatteIndexType::U16_BE || indexType == LatteIndexType::U16_LE)\n\t\t\treturn count * sizeof(uint16);\n\t\tif (indexType == LatteIndexType::U32_BE || indexType == LatteIndexType::U32_LE)\n\t\t\treturn count * sizeof(uint32);\n\t\tcemu_assert_suspicious();\n\t\treturn 0;\n\t}\n\telse if(indexType == LatteIndexType::AUTO)\n\t\treturn 0;\n\telse if (indexType == LatteIndexType::U16_BE || indexType == LatteIndexType::U16_LE)\n\t\treturn count * sizeof(uint16);\n\telse if (indexType == LatteIndexType::U32_BE || indexType == LatteIndexType::U32_LE)\n\t\treturn count * sizeof(uint32);\n\treturn 0;\n}\n\ntemplate<typename T>\nvoid LatteIndices_convertBE(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tconst betype<T>* src = (betype<T>*)indexDataInput;\n\tT* dst = (T*)indexDataOutput;\n\tfor (uint32 i = 0; i < count; i++)\n\t{\n\t\tT v = *src;\n\t\t*dst = v;\n\t\tindexMin = std::min(indexMin, (uint32)v);\n\t\tindexMax = std::max(indexMax, (uint32)v);\n\t\tdst++;\n\t\tsrc++;\n\t}\n}\n\ntemplate<typename T>\nvoid LatteIndices_convertLE(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tconst T* src = (T*)indexDataInput;\n\tT* dst = (T*)indexDataOutput;\n\tfor (uint32 i = 0; i < count; i++)\n\t{\n\t\tT v = *src;\n\t\t*dst = v;\n\t\tindexMin = std::min(indexMin, (uint32)v);\n\t\tindexMax = std::max(indexMax, (uint32)v);\n\t\tdst++;\n\t\tsrc++;\n\t}\n}\n\ntemplate<typename T>\nvoid LatteIndices_unpackQuadsAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tsint32 numQuads = count / 4;\n\tconst betype<T>* src = (betype<T>*)indexDataInput;\n\tT* dst = (T*)indexDataOutput;\n\tfor (sint32 i = 0; i < numQuads; i++)\n\t{\n\t\tT idx0 = src[0];\n\t\tT idx1 = src[1];\n\t\tT idx2 = src[2];\n\t\tT idx3 = src[3];\n\t\tindexMin = std::min(indexMin, (uint32)idx0);\n\t\tindexMax = std::max(indexMax, (uint32)idx0);\n\t\tindexMin = std::min(indexMin, (uint32)idx1);\n\t\tindexMax = std::max(indexMax, (uint32)idx1);\n\t\tindexMin = std::min(indexMin, (uint32)idx2);\n\t\tindexMax = std::max(indexMax, (uint32)idx2);\n\t\tindexMin = std::min(indexMin, (uint32)idx3);\n\t\tindexMax = std::max(indexMax, (uint32)idx3);\n\t\tdst[0] = idx0;\n\t\tdst[1] = idx1;\n\t\tdst[2] = idx2;\n\t\tdst[3] = idx0;\n\t\tdst[4] = idx2;\n\t\tdst[5] = idx3;\n\t\tsrc += 4;\n\t\tdst += 6;\n\t}\n}\n\ntemplate<typename T>\nvoid LatteIndices_generateAutoQuadIndices(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tsint32 numQuads = count / 4;\n\tconst betype<T>* src = (betype<T>*)indexDataInput;\n\tT* dst = (T*)indexDataOutput;\n\tfor (sint32 i = 0; i < numQuads; i++)\n\t{\n\t\tT idx0 = i * 4 + 0;\n\t\tT idx1 = i * 4 + 1;\n\t\tT idx2 = i * 4 + 2;\n\t\tT idx3 = i * 4 + 3;\n\t\tdst[0] = idx0;\n\t\tdst[1] = idx1;\n\t\tdst[2] = idx2;\n\t\tdst[3] = idx0;\n\t\tdst[4] = idx2;\n\t\tdst[5] = idx3;\n\t\tsrc += 4;\n\t\tdst += 6;\n\t}\n\tindexMin = 0;\n\tindexMax = std::max(count, 1u) - 1;\n}\n\ntemplate<typename T>\nvoid LatteIndices_unpackQuadStripAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tif (count <= 3)\n\t\treturn;\n\tsint32 numQuads = (count - 2) / 2;\n\tconst betype<T>* src = (betype<T>*)indexDataInput;\n\tT* dst = (T*)indexDataOutput;\n\tfor (sint32 i = 0; i < numQuads; i++)\n\t{\n\t\tT idx0 = src[0];\n\t\tT idx1 = src[1];\n\t\tT idx2 = src[2];\n\t\tT idx3 = src[3];\n\t\tindexMin = std::min(indexMin, (uint32)idx0);\n\t\tindexMax = std::max(indexMax, (uint32)idx0);\n\t\tindexMin = std::min(indexMin, (uint32)idx1);\n\t\tindexMax = std::max(indexMax, (uint32)idx1);\n\t\tindexMin = std::min(indexMin, (uint32)idx2);\n\t\tindexMax = std::max(indexMax, (uint32)idx2);\n\t\tindexMin = std::min(indexMin, (uint32)idx3);\n\t\tindexMax = std::max(indexMax, (uint32)idx3);\n\t\tdst[0] = idx0;\n\t\tdst[1] = idx1;\n\t\tdst[2] = idx2;\n\t\tdst[3] = idx2;\n\t\tdst[4] = idx1;\n\t\tdst[5] = idx3;\n\t\tsrc += 2;\n\t\tdst += 6;\n\t}\n}\n\ntemplate<typename T>\nvoid LatteIndices_unpackLineLoopAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tif (count <= 0)\n\t\treturn;\n\tconst betype<T>* src = (betype<T>*)indexDataInput;\n\tT firstIndex = *src;\n\tT* dst = (T*)indexDataOutput;\n\tfor (sint32 i = 0; i < (sint32)count; i++)\n\t{\n\t\tT idx = *src;\n\t\tindexMin = std::min(indexMin, (uint32)idx);\n\t\tindexMax = std::max(indexMax, (uint32)idx);\n\t\t*dst = idx;\n\t\tsrc++;\n\t\tdst++;\n\t}\n\t*dst = firstIndex;\n}\n\ntemplate<typename T>\nvoid LatteIndices_generateAutoQuadStripIndices(void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tif (count <= 3)\n\t\treturn;\n\tsint32 numQuads = (count - 2) / 2;\n\tT* dst = (T*)indexDataOutput;\n\tfor (sint32 i = 0; i < numQuads; i++)\n\t{\n\t\tT idx0 = i * 2 + 0;\n\t\tT idx1 = i * 2 + 1;\n\t\tT idx2 = i * 2 + 2;\n\t\tT idx3 = i * 2 + 3;\n\t\tdst[0] = idx0;\n\t\tdst[1] = idx1;\n\t\tdst[2] = idx2;\n\t\tdst[3] = idx2;\n\t\tdst[4] = idx1;\n\t\tdst[5] = idx3;\n\t\tdst += 6;\n\t}\n\tindexMin = 0;\n\tindexMax = std::max(count, 1u) - 1;\n}\n\n\ntemplate<typename T>\nvoid LatteIndices_generateAutoLineLoopIndices(void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tif (count == 0)\n\t\treturn;\n\tT* dst = (T*)indexDataOutput;\n\tfor (sint32 i = 0; i < (sint32)count; i++)\n\t{\n\t\t*dst = (T)i;\n\t\tdst++;\n\t}\n\t*dst = 0;\n\tdst++;\n\tindexMin = 0;\n\tindexMax = std::max(count, 1u) - 1;\n}\n\ntemplate<typename T>\nvoid LatteIndices_unpackTriangleFanAndConvert(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tconst betype<T>* src = (betype<T>*)indexDataInput;\n\tT* dst = (T*)indexDataOutput;\n\t// TODO: check this\n\tfor (sint32 i = 0; i < count; i++)\n\t{\n\t    uint32 i0;\n\t\tif (i % 2 == 0)\n\t\t    i0 = i / 2;\n        else\n            i0 = count - 1 - i / 2;\n        T idx = src[i0];\n\t\tindexMin = std::min(indexMin, (uint32)idx);\n\t\tindexMax = std::max(indexMax, (uint32)idx);\n\t\tdst[i] = idx;\n\t}\n}\n\ntemplate<typename T>\nvoid LatteIndices_generateAutoTriangleFanIndices(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tconst betype<T>* src = (betype<T>*)indexDataInput;\n\tT* dst = (T*)indexDataOutput;\n\tfor (sint32 i = 0; i < count; i++)\n\t{\n\t\tT idx = i;\n\t\tif (idx % 2 == 0)\n            idx = idx / 2;\n        else\n            idx = count - 1 - idx / 2;\n\t\tdst[i] = idx;\n\t}\n\tindexMin = 0;\n\tindexMax = std::max(count, 1u) - 1;\n}\n\n#if defined(ARCH_X86_64)\nATTRIBUTE_AVX2\nvoid LatteIndices_fastConvertU16_AVX2(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\t// using AVX + AVX2 we can process 16 indices at a time\n\tconst uint16* indicesU16BE = (const uint16*)indexDataInput;\n\tuint16* indexOutput = (uint16*)indexDataOutput;\n\tsint32 count16 = count >> 4;\n\tsint32 countRemaining = count & 15;\n\tif (count16)\n\t{\n\t\t__m256i mMin = _mm256_set_epi16((sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF,\n\t\t\t\t\t\t           \t\t(sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF, (sint16)0xFFFF);\n\t\t__m256i mMax = _mm256_set_epi16(0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000);\n\t\t__m256i mShuffle16Swap = _mm256_set_epi8(30, 31, 28, 29, 26, 27, 24, 25, 22, 23, 20, 21, 18, 19, 16, 17, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);\n\n\t\tdo\n\t\t{\n\t\t\t__m256i mIndexData = _mm256_loadu_si256((const __m256i*)indicesU16BE);\n\t\t\tindicesU16BE += 16;\n\t\t\t_mm_prefetch((const char*)indicesU16BE, _MM_HINT_T0);\n\t\t\t// endian swap\n\t\t\tmIndexData = _mm256_shuffle_epi8(mIndexData, mShuffle16Swap);\n\t\t\t_mm256_store_si256((__m256i*)indexOutput, mIndexData);\n\t\t\tmMin = _mm256_min_epu16(mIndexData, mMin);\n\t\t\tmMax = _mm256_max_epu16(mIndexData, mMax);\n\t\t\tindexOutput += 16;\n\t\t} while (--count16);\n\n\t\t// fold 32 to 16 byte\n\t\tmMin = _mm256_min_epu16(mMin, _mm256_permute2x128_si256(mMin, mMin, 1));\n\t\tmMax = _mm256_max_epu16(mMax, _mm256_permute2x128_si256(mMax, mMax, 1));\n\t\t// fold 16 to 8 byte\n\t\tmMin = _mm256_min_epu16(mMin, _mm256_shuffle_epi32(mMin, (2 << 0) | (3 << 2) | (2 << 4) | (3 << 6)));\n\t\tmMax = _mm256_max_epu16(mMax, _mm256_shuffle_epi32(mMax, (2 << 0) | (3 << 2) | (2 << 4) | (3 << 6)));\n\n\t\tuint16* mMinU16 = (uint16*)&mMin;\n\t\tuint16* mMaxU16 = (uint16*)&mMax;\n\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[0]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[1]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[2]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[3]);\n\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[0]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[1]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[2]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[3]);\n\t}\n\t// process remaining indices\n\tuint32 _minIndex = 0xFFFFFFFF;\n\tuint32 _maxIndex = 0;\n\tfor (sint32 i = countRemaining; (--i) >= 0;)\n\t{\n\t\tuint16 idx = _swapEndianU16(*indicesU16BE);\n\t\t*indexOutput = idx;\n\t\tindexOutput++;\n\t\tindicesU16BE++;\n\t\t_maxIndex = std::max(_maxIndex, (uint32)idx);\n\t\t_minIndex = std::min(_minIndex, (uint32)idx);\n\t}\n\t// update min/max\n\tindexMax = std::max(indexMax, _maxIndex);\n\tindexMin = std::min(indexMin, _minIndex);\n}\n\nATTRIBUTE_SSE41\nvoid LatteIndices_fastConvertU16_SSE41(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\t// SSSE3 & SSE4.1 optimized decoding\n\tconst uint16* indicesU16BE = (const uint16*)indexDataInput;\n\tuint16* indexOutput = (uint16*)indexDataOutput;\n\tsint32 count8 = count >> 3;\n\tsint32 countRemaining = count & 7;\n\tif (count8)\n\t{\n\t\t__m128i mMin = _mm_set_epi16((short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF, (short)0xFFFF);\n\t\t__m128i mMax = _mm_set_epi16(0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000);\n\t\t__m128i mTemp;\n\t\t__m128i* mRawIndices = (__m128i*)indicesU16BE;\n\t\tindicesU16BE += count8 * 8;\n\t\t__m128i* mOutputIndices = (__m128i*)indexOutput;\n\t\tindexOutput += count8 * 8;\n\t\t__m128i shufmask = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);\n\t\twhile (count8--)\n\t\t{\n\t\t\tmTemp = _mm_loadu_si128(mRawIndices);\n\t\t\tmRawIndices++;\n\t\t\tmTemp = _mm_shuffle_epi8(mTemp, shufmask);\n\t\t\tmMin = _mm_min_epu16(mMin, mTemp);\n\t\t\tmMax = _mm_max_epu16(mMax, mTemp);\n\t\t\t_mm_store_si128(mOutputIndices, mTemp);\n\t\t\tmOutputIndices++;\n\t\t}\n\n\t\tuint16* mMaxU16 = (uint16*)&mMax;\n\t\tuint16* mMinU16 = (uint16*)&mMin;\n\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[0]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[1]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[2]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[3]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[4]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[5]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[6]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[7]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[0]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[1]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[2]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[3]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[4]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[5]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[6]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU16[7]);\n\t}\n\tuint32 _minIndex = 0xFFFFFFFF;\n\tuint32 _maxIndex = 0;\n\tfor (sint32 i = countRemaining; (--i) >= 0;)\n\t{\n\t\tuint16 idx = _swapEndianU16(*indicesU16BE);\n\t\t*indexOutput = idx;\n\t\tindexOutput++;\n\t\tindicesU16BE++;\n\t\t_maxIndex = std::max(_maxIndex, (uint32)idx);\n\t\t_minIndex = std::min(_minIndex, (uint32)idx);\n\t}\n\tindexMax = std::max(indexMax, _maxIndex);\n\tindexMin = std::min(indexMin, _minIndex);\n}\n\nATTRIBUTE_AVX2\nvoid LatteIndices_fastConvertU32_AVX2(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\t// using AVX + AVX2 we can process 8 indices at a time\n\tconst uint32* indicesU32BE = (const uint32*)indexDataInput;\n\tuint32* indexOutput = (uint32*)indexDataOutput;\n\tsint32 count8 = count >> 3;\n\tsint32 countRemaining = count & 7;\n\tif (count8)\n\t{\n\t\t__m256i mMin = _mm256_set_epi32((sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF, (sint32)0xFFFFFFFF);\n\t\t__m256i mMax = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, 0);\n\t\t__m256i mShuffle32Swap = _mm256_set_epi8(28,29,30,31,\n\t\t\t24,25,26,27,\n\t\t\t20,21,22,23,\n\t\t\t16,17,18,19,\n\t\t\t12,13,14,15,\n\t\t\t8,9,10,11,\n\t\t\t4,5,6,7,\n\t\t\t0,1,2,3);\n\t\t// unaligned\n\t\tdo\n\t\t{\n\t\t\t__m256i mIndexData = _mm256_loadu_si256((const __m256i*)indicesU32BE);\n\t\t\tindicesU32BE += 8;\n\t\t\t_mm_prefetch((const char*)indicesU32BE, _MM_HINT_T0);\n\t\t\t// endian swap\n\t\t\tmIndexData = _mm256_shuffle_epi8(mIndexData, mShuffle32Swap);\n\t\t\t_mm256_store_si256((__m256i*)indexOutput, mIndexData);\n\t\t\tmMin = _mm256_min_epu32(mIndexData, mMin);\n\t\t\tmMax = _mm256_max_epu32(mIndexData, mMax);\n\t\t\tindexOutput += 8;\n\t\t} while (--count8);\n\n\t\t// fold 32 to 16 byte\n\t\tmMin = _mm256_min_epu32(mMin, _mm256_permute2x128_si256(mMin, mMin, 1));\n\t\tmMax = _mm256_max_epu32(mMax, _mm256_permute2x128_si256(mMax, mMax, 1));\n\t\t// fold 16 to 8 byte\n\t\tmMin = _mm256_min_epu32(mMin, _mm256_shuffle_epi32(mMin, (2 << 0) | (3 << 2) | (2 << 4) | (3 << 6)));\n\t\tmMax = _mm256_max_epu32(mMax, _mm256_shuffle_epi32(mMax, (2 << 0) | (3 << 2) | (2 << 4) | (3 << 6)));\n\n\t\tuint32* mMinU32 = (uint32*)&mMin;\n\t\tuint32* mMaxU32 = (uint32*)&mMax;\n\n\t\tindexMin = std::min(indexMin, (uint32)mMinU32[0]);\n\t\tindexMin = std::min(indexMin, (uint32)mMinU32[1]);\n\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU32[0]);\n\t\tindexMax = std::max(indexMax, (uint32)mMaxU32[1]);\n\t}\n\t// process remaining indices\n\tuint32 _minIndex = 0xFFFFFFFF;\n\tuint32 _maxIndex = 0;\n\tfor (sint32 i = countRemaining; (--i) >= 0;)\n\t{\n\t\tuint32 idx = _swapEndianU32(*indicesU32BE);\n\t\t*indexOutput = idx;\n\t\tindexOutput++;\n\t\tindicesU32BE++;\n\t\t_maxIndex = std::max(_maxIndex, (uint32)idx);\n\t\t_minIndex = std::min(_minIndex, (uint32)idx);\n\t}\n\t// update min/max\n\tindexMax = std::max(indexMax, _maxIndex);\n\tindexMin = std::min(indexMin, _minIndex);\n}\n#elif defined(__aarch64__)\n\nvoid LatteIndices_fastConvertU16_NEON(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tconst uint16* indicesU16BE = (const uint16*)indexDataInput;\n\tuint16* indexOutput = (uint16*)indexDataOutput;\n\tsint32 count8 = count >> 3;\n\tsint32 countRemaining = count & 7;\n\n\tif (count8)\n\t{\n\t\tuint16x8_t mMin = vdupq_n_u16(0xFFFF);\n\t\tuint16x8_t mMax = vdupq_n_u16(0x0000);\n\t\tuint16x8_t mTemp;\n\t\tuint16x8_t* mRawIndices = (uint16x8_t*) indicesU16BE;\n\t\tindicesU16BE += count8 * 8;\n\t\tuint16x8_t* mOutputIndices = (uint16x8_t*) indexOutput;\n\t\tindexOutput += count8 * 8;\n\n\t\twhile (count8--)\n\t\t{\n\t\t\tmTemp = vld1q_u16((uint16*)mRawIndices);\n\t\t\tmRawIndices++;\n\t\t\tmTemp = vrev16q_u8(mTemp);\n\t\t\tmMin = vminq_u16(mMin, mTemp);\n\t\t\tmMax = vmaxq_u16(mMax, mTemp);\n\t\t\tvst1q_u16((uint16*)mOutputIndices, mTemp);\n\t\t\tmOutputIndices++;\n\t\t}\n\n\t\tuint16* mMaxU16 = (uint16*)&mMax;\n\t\tuint16* mMinU16 = (uint16*)&mMin;\n\n\t\tfor (int i = 0; i < 8; ++i) {\n\t\t\tindexMax = std::max(indexMax, (uint32)mMaxU16[i]);\n\t\t\tindexMin = std::min(indexMin, (uint32)mMinU16[i]);\n\t\t}\n\t}\n\t// process remaining indices\n\tuint32 _minIndex = 0xFFFFFFFF;\n\tuint32 _maxIndex = 0;\n\tfor (sint32 i = countRemaining; (--i) >= 0;)\n\t{\n\t\tuint16 idx = _swapEndianU16(*indicesU16BE);\n\t\t*indexOutput = idx;\n\t\tindexOutput++;\n\t\tindicesU16BE++;\n\t\t_maxIndex = std::max(_maxIndex, (uint32)idx);\n\t\t_minIndex = std::min(_minIndex, (uint32)idx);\n\t}\n\t// update min/max\n\tindexMax = std::max(indexMax, _maxIndex);\n\tindexMin = std::min(indexMin, _minIndex);\n}\n\nvoid LatteIndices_fastConvertU32_NEON(const void* indexDataInput, void* indexDataOutput, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tconst uint32* indicesU32BE = (const uint32*)indexDataInput;\n\tuint32* indexOutput = (uint32*)indexDataOutput;\n\tsint32 count8 = count >> 2;\n\tsint32 countRemaining = count & 3;\n\n\tif (count8)\n\t{\n\t\tuint32x4_t mMin = vdupq_n_u32(0xFFFFFFFF);\n\t\tuint32x4_t mMax = vdupq_n_u32(0x00000000);\n\t\tuint32x4_t mTemp;\n\t\tuint32x4_t* mRawIndices = (uint32x4_t*) indicesU32BE;\n\t\tindicesU32BE += count8 * 4;\n\t\tuint32x4_t* mOutputIndices = (uint32x4_t*) indexOutput;\n\t\tindexOutput += count8 * 4;\n\n\t\twhile (count8--)\n\t\t{\n\t\t\tmTemp = vld1q_u32((uint32*)mRawIndices);\n\t\t\tmRawIndices++;\n\t\t\tmTemp = vrev32q_u8(mTemp);\n\t\t\tmMin = vminq_u32(mMin, mTemp);\n\t\t\tmMax = vmaxq_u32(mMax, mTemp);\n\t\t\tvst1q_u32((uint32*)mOutputIndices, mTemp);\n\t\t\tmOutputIndices++;\n\t\t}\n\n\t\tuint32* mMaxU32 = (uint32*)&mMax;\n\t\tuint32* mMinU32 = (uint32*)&mMin;\n\n\t\tfor (int i = 0; i < 4; ++i) {\n\t\t\tindexMax = std::max(indexMax, mMaxU32[i]);\n\t\t\tindexMin = std::min(indexMin, mMinU32[i]);\n\t\t}\n\t}\n\t// process remaining indices\n\tuint32 _minIndex = 0xFFFFFFFF;\n\tuint32 _maxIndex = 0;\n\tfor (sint32 i = countRemaining; (--i) >= 0;)\n\t{\n\t\tuint32 idx = _swapEndianU32(*indicesU32BE);\n\t\t*indexOutput = idx;\n\t\tindexOutput++;\n\t\tindicesU32BE++;\n\t\t_maxIndex = std::max(_maxIndex, idx);\n\t\t_minIndex = std::min(_minIndex, idx);\n\t}\n\t// update min/max\n\tindexMax = std::max(indexMax, _maxIndex);\n\tindexMin = std::min(indexMin, _minIndex);\n}\n\n#endif\n\ntemplate<typename T>\nvoid _LatteIndices_alternativeCalculateIndexMinMax(const void* indexData, uint32 count, uint32 primitiveRestartIndex, uint32& indexMin, uint32& indexMax)\n{\n\tcemu_assert_debug(count != 0);\n\tconst betype<T>* idxPtrT = (betype<T>*)indexData;\n\tT _indexMin = *idxPtrT;\n\tT _indexMax = *idxPtrT;\n\tcemu_assert_debug(primitiveRestartIndex <= std::numeric_limits<T>::max());\n\tT restartIndexT = (T)primitiveRestartIndex;\n\twhile (count)\n\t{\n\t\tT idx = *idxPtrT;\n\t\tif (idx != restartIndexT)\n\t\t{\n\t\t\t_indexMin = std::min(_indexMin, idx);\n\t\t\t_indexMax = std::max(_indexMax, idx);\n\t\t}\n\t\tidxPtrT++;\n\t\tcount--;\n\t}\n\tindexMin = _indexMin;\n\tindexMax = _indexMax;\n}\n\n// calculate min and max index while taking primitive restart into account\n// fallback implementation in case the fast path gives us invalid results\nvoid LatteIndices_alternativeCalculateIndexMinMax(const void* indexData, LatteIndexType indexType, uint32 count, uint32& indexMin, uint32& indexMax)\n{\n\tif (count == 0)\n\t{\n\t\tindexMin = 0;\n\t\tindexMax = 0;\n\t\treturn;\n\t}\n\tuint32 primitiveRestartIndex = LatteGPUState.contextNew.VGT_MULTI_PRIM_IB_RESET_INDX.get_RESTART_INDEX();\n\n\tif (indexType == LatteIndexType::U16_BE)\n\t{\n\t\t_LatteIndices_alternativeCalculateIndexMinMax<uint16>(indexData, count, primitiveRestartIndex, indexMin, indexMax);\n\t}\n\telse if (indexType == LatteIndexType::U32_BE)\n\t{\n\t\t_LatteIndices_alternativeCalculateIndexMinMax<uint32>(indexData, count, primitiveRestartIndex, indexMin, indexMax);\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n}\n\nvoid LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32 count, LattePrimitiveMode primitiveMode, uint32& indexMin, uint32& indexMax, Renderer::INDEX_TYPE& renderIndexType, uint32& outputCount, Renderer::IndexAllocation& indexAllocation)\n{\n\t// what this should do:\n\t// [x] use fast SIMD-based index decoding\n\t// [x] unpack QUAD indices to triangle indices\n\t// [x] calculate min and max index, be careful about primitive restart index\n\t// [x] decode data directly into coherent memory buffer?\n\t// [ ] better cache implementation, allow to cache across frames\n\n\t// reuse from cache if data didn't change\n\tauto cacheEntry = std::find_if(LatteIndexCache.entry.begin(), LatteIndexCache.entry.end(), [indexData, count, primitiveMode, indexType](const auto& entry)\n\t{\n\t\treturn entry.lastPtr == indexData && entry.lastCount == count && entry.lastPrimitiveMode == primitiveMode && entry.lastIndexType == indexType;\n\t});\n\tif (cacheEntry != LatteIndexCache.entry.end())\n\t{\n\t\tindexMin = cacheEntry->indexMin;\n\t\tindexMax = cacheEntry->indexMax;\n\t\trenderIndexType = cacheEntry->renderIndexType;\n\t\toutputCount = cacheEntry->outputCount;\n\t\tindexAllocation = cacheEntry->indexAllocation;\n\t\tcacheEntry->lastUsed = LatteIndices_GetNextUsageIndex();\n\t\treturn;\n\t}\n\n\toutputCount = 0;\n\tif (indexType == LatteIndexType::AUTO)\n\t\trenderIndexType = Renderer::INDEX_TYPE::NONE;\n\telse if (indexType == LatteIndexType::U16_BE || indexType == LatteIndexType::U16_LE)\n\t\trenderIndexType = Renderer::INDEX_TYPE::U16;\n\telse if (indexType == LatteIndexType::U32_BE)\n\t\trenderIndexType = Renderer::INDEX_TYPE::U32;\n\telse\n\t\tcemu_assert_debug(false);\n\n\tuint32 primitiveRestartIndex = LatteGPUState.contextNew.VGT_MULTI_PRIM_IB_RESET_INDX.get_RESTART_INDEX();\n\n\t// calculate index output size\n\tuint32 indexOutputSize = LatteIndices_calculateIndexOutputSize(primitiveMode, indexType, count);\n\tif (indexOutputSize == 0)\n\t{\n\t\toutputCount = count;\n\t\tindexMin = 0;\n\t\tindexMax = std::max(count, 1u)-1;\n\t\trenderIndexType = Renderer::INDEX_TYPE::NONE;\n\t\tindexAllocation = {};\n\t\treturn; // no indices\n\t}\n\t// query index buffer from renderer\n\tindexAllocation = g_renderer->indexData_reserveIndexMemory(indexOutputSize);\n\tvoid* indexOutputPtr = indexAllocation.mem;\n\n\t// decode indices\n\tindexMin = std::numeric_limits<uint32>::max();\n\tindexMax = std::numeric_limits<uint32>::min();\n\tif (primitiveMode == LattePrimitiveMode::QUADS)\n\t{\n\t\t// unpack quads into triangles\n\t\tif (indexType == LatteIndexType::AUTO)\n\t\t{\n\t\t\tif (count <= 0xFFFF)\n\t\t\t{\n\t\t\t\tLatteIndices_generateAutoQuadIndices<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\t\t\trenderIndexType = Renderer::INDEX_TYPE::U16;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tLatteIndices_generateAutoQuadIndices<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\t\t\trenderIndexType = Renderer::INDEX_TYPE::U32;\n\t\t\t}\n\t\t}\n\t\telse if (indexType == LatteIndexType::U16_BE)\n\t\t\tLatteIndices_unpackQuadsAndConvert<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\telse if (indexType == LatteIndexType::U32_BE)\n\t\t\tLatteIndices_unpackQuadsAndConvert<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\t\toutputCount = count / 4 * 6;\n\t}\n\telse if (primitiveMode == LattePrimitiveMode::QUAD_STRIP)\n\t{\n\t\t// unpack quad strip into triangles\n\t\tif (indexType == LatteIndexType::AUTO)\n\t\t{\n\t\t\tif (count <= 0xFFFF)\n\t\t\t{\n\t\t\t\tLatteIndices_generateAutoQuadStripIndices<uint16>(indexOutputPtr, count, indexMin, indexMax);\n\t\t\t\trenderIndexType = Renderer::INDEX_TYPE::U16;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tLatteIndices_generateAutoQuadStripIndices<uint32>(indexOutputPtr, count, indexMin, indexMax);\n\t\t\t\trenderIndexType = Renderer::INDEX_TYPE::U32;\n\t\t\t}\n\t\t}\n\t\telse if (indexType == LatteIndexType::U16_BE)\n\t\t\tLatteIndices_unpackQuadStripAndConvert<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\telse if (indexType == LatteIndexType::U32_BE)\n\t\t\tLatteIndices_unpackQuadStripAndConvert<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\t\tif (count >= 2)\n\t\t\toutputCount = (count - 2) / 2 * 6;\n\t\telse\n\t\t\toutputCount = 0;\n\t}\n\telse if (primitiveMode == LattePrimitiveMode::LINE_LOOP)\n\t{\n\t\t// unpack line loop into line strip with extra reconnecting vertex\n\t\tif (indexType == LatteIndexType::AUTO)\n\t\t{\n\t\t\tif (count <= 0xFFFF)\n\t\t\t{\n\t\t\t\tLatteIndices_generateAutoLineLoopIndices<uint16>(indexOutputPtr, count, indexMin, indexMax);\n\t\t\t\trenderIndexType = Renderer::INDEX_TYPE::U16;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tLatteIndices_generateAutoLineLoopIndices<uint32>(indexOutputPtr, count, indexMin, indexMax);\n\t\t\t\trenderIndexType = Renderer::INDEX_TYPE::U32;\n\t\t\t}\n\t\t}\n\t\telse if (indexType == LatteIndexType::U16_BE)\n\t\t\tLatteIndices_unpackLineLoopAndConvert<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\telse if (indexType == LatteIndexType::U32_BE)\n\t\t\tLatteIndices_unpackLineLoopAndConvert<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\t\toutputCount = count + 1;\n\t}\n\telse if (primitiveMode == LattePrimitiveMode::TRIANGLE_FAN && g_renderer->GetType() == RendererAPI::Metal)\n\t{\n        if (indexType == LatteIndexType::AUTO)\n    \t{\n    \t\tif (count <= 0xFFFF)\n    \t\t{\n    \t\t\tLatteIndices_generateAutoTriangleFanIndices<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax);\n    \t\t\trenderIndexType = Renderer::INDEX_TYPE::U16;\n    \t\t}\n    \t\telse\n    \t\t{\n    \t\t\tLatteIndices_generateAutoTriangleFanIndices<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax);\n    \t\t\trenderIndexType = Renderer::INDEX_TYPE::U32;\n    \t\t}\n    \t}\n    \telse if (indexType == LatteIndexType::U16_BE)\n    \t\tLatteIndices_unpackTriangleFanAndConvert<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax);\n    \telse if (indexType == LatteIndexType::U32_BE)\n    \t\tLatteIndices_unpackTriangleFanAndConvert<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax);\n    \telse\n    \t\tcemu_assert_debug(false);\n    \toutputCount = count;\n\t}\n\telse\n\t{\n\t\tif (indexType == LatteIndexType::U16_BE)\n\t\t{\n#if defined(ARCH_X86_64)\n\t\t\tif (g_CPUFeatures.x86.avx2)\n\t\t\t\tLatteIndices_fastConvertU16_AVX2(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\t\telse if (g_CPUFeatures.x86.sse4_1 && g_CPUFeatures.x86.ssse3)\n\t\t\t\tLatteIndices_fastConvertU16_SSE41(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\t\telse\n\t\t\t\tLatteIndices_convertBE<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax);\n#elif defined(__aarch64__)\n\t\t\tLatteIndices_fastConvertU16_NEON(indexData, indexOutputPtr, count, indexMin, indexMax);\n#else\n\t\t\tLatteIndices_convertBE<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax);            \n#endif\n\t\t}\n\t\telse if (indexType == LatteIndexType::U32_BE)\n\t\t{\n#if defined(ARCH_X86_64)\n\t\t\tif (g_CPUFeatures.x86.avx2)\n\t\t\t\tLatteIndices_fastConvertU32_AVX2(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\t\telse\n\t\t\t\tLatteIndices_convertBE<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax);\n#elif defined(__aarch64__)\n\t\t\tLatteIndices_fastConvertU32_NEON(indexData, indexOutputPtr, count, indexMin, indexMax);\n#else\n\t\t\tLatteIndices_convertBE<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax);            \n#endif\n\t\t}\n\t\telse if (indexType == LatteIndexType::U16_LE)\n\t\t{\n\t\t\tLatteIndices_convertLE<uint16>(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\t}\n\t\telse if (indexType == LatteIndexType::U32_LE)\n\t\t{\n\t\t\tLatteIndices_convertLE<uint32>(indexData, indexOutputPtr, count, indexMin, indexMax);\n\t\t}\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\t\toutputCount = count;\n\t}\n\t// the above algorithms use a simplistic approach to get indexMin/indexMax\n\t// here we make sure primitive restart indices dont influence the index range\n\tif (primitiveRestartIndex == indexMin || primitiveRestartIndex == indexMax)\n\t{\n\t\t// recalculate index range but filter out primitive restart index\n\t\tLatteIndices_alternativeCalculateIndexMinMax(indexData, indexType, count, indexMin, indexMax);\n\t}\n\tg_renderer->indexData_uploadIndexMemory(indexAllocation);\n\tperformanceMonitor.cycle[performanceMonitor.cycleIndex].indexDataUploaded += indexOutputSize;\n\t// get least recently used cache entry\n\tauto lruEntry = std::min_element(LatteIndexCache.entry.begin(), LatteIndexCache.entry.end(), [](const auto& a, const auto& b)\n\t{\n\t\treturn a.lastUsed < b.lastUsed;\n\t});\n\t// invalidate previous allocation\n\tif(lruEntry->lastPtr != nullptr)\n\t\tg_renderer->indexData_releaseIndexMemory(lruEntry->indexAllocation);\n\t// update cache\n\tlruEntry->lastPtr = indexData;\n\tlruEntry->lastCount = count;\n\tlruEntry->lastPrimitiveMode = primitiveMode;\n\tlruEntry->lastIndexType = indexType;\n\tlruEntry->indexMin = indexMin;\n\tlruEntry->indexMax = indexMax;\n\tlruEntry->renderIndexType = renderIndexType;\n\tlruEntry->outputCount = outputCount;\n\tlruEntry->indexAllocation = indexAllocation;\n\tlruEntry->lastUsed = LatteIndices_GetNextUsageIndex();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteIndices.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n\nvoid LatteIndices_invalidate(const void* memPtr, uint32 size);\nvoid LatteIndices_invalidateAll();\nvoid LatteIndices_decode(const void* indexData, LatteIndexType indexType, uint32 count, LattePrimitiveMode primitiveMode, uint32& indexMin, uint32& indexMax, Renderer::INDEX_TYPE& renderIndexType, uint32& outputCount, Renderer::IndexAllocation& indexAllocation);"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteOverlay.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteOverlay.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"WindowSystem.h\"\n\n#include \"config/CemuConfig.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"config/ActiveSettings.h\"\n\n#include <imgui.h>\n#include \"resource/IconsFontAwesome5.h\"\n#include \"imgui/imgui_extension.h\"\n\n#include \"input/InputManager.h\"\n#include \"util/SystemInfo/SystemInfo.h\"\n\n#include <cinttypes>\n\nstruct OverlayStats\n{\n\tOverlayStats() {};\n\n\tint processor_count = 1;\n\tProcessorTime processor_time_cemu;\n\tstd::vector<ProcessorTime> processor_times;\n\n\tdouble fps{};\n\tuint32 draw_calls_per_frame{};\n\tuint32 fast_draw_calls_per_frame{};\n\tfloat cpu_usage{}; // cemu cpu usage in %\n\tstd::vector<float> cpu_per_core; // global cpu usage in % per core\n\tuint32 ram_usage{}; // ram usage in MB\n\n\tint vramUsage{}, vramTotal{}; // vram usage in mb\n} g_state{};\n\nextern std::atomic_int g_compiled_shaders_total;\nextern std::atomic_int g_compiled_shaders_async;\n\nstd::atomic_int g_compiling_pipelines;\nstd::atomic_int g_compiling_pipelines_async;\nstd::atomic_uint64_t g_compiling_pipelines_syncTimeSum;\n\nextern std::mutex g_friend_notification_mutex;\nextern std::vector< std::pair<std::string, int> > g_friend_notifications;\n\nstd::mutex g_notification_mutex;\nstd::vector< std::pair<std::string, int> > g_notifications;\n\nvoid LatteOverlay_pushNotification(const std::string& text, sint32 duration)\n{\n\tstd::unique_lock lock(g_notification_mutex);\n\tg_notifications.emplace_back(text, duration);\n}\n\nstruct OverlayList\n{\n\tstd::wstring text;\n\tfloat pos_x = 0;\n\tfloat pos_y = 0;\n\tfloat width;\n\n\tOverlayList(std::wstring text, float width)\n\t\t: text(std::move(text)), width(width) {}\n};\n\nconst auto kPopupFlags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;\n\nconst float kBackgroundAlpha = 0.65f;\nvoid LatteOverlay_renderOverlay(ImVec2& position, ImVec2& pivot, sint32 direction, float fontSize, bool pad)\n{\n\tauto& config = GetConfig();\n\n\tconst auto font = ImGui_GetFont(fontSize);\n\tImGui::PushFont(font);\n\n\tconst ImVec4 color = ImGui::ColorConvertU32ToFloat4(config.overlay.text_color);\n\tImGui::PushStyleColor(ImGuiCol_Text, color);\n\t// stats overlay\n\tif (config.overlay.fps || config.overlay.drawcalls || config.overlay.cpu_usage || config.overlay.cpu_per_core_usage || config.overlay.ram_usage)\n\t{\n\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\tImGui::SetNextWindowBgAlpha(kBackgroundAlpha);\n\t\tif (ImGui::Begin(\"Stats overlay\", nullptr, kPopupFlags))\n\t\t{\n\t\t\tif (config.overlay.fps)\n\t\t\t\tImGui::Text(\"FPS: %.2lf\", g_state.fps);\n\n\t\t\tif (config.overlay.drawcalls)\n\t\t\t\tImGui::Text(\"Draws/f: %d (fast: %d)\", g_state.draw_calls_per_frame, g_state.fast_draw_calls_per_frame);\n\n\t\t\tif (config.overlay.cpu_usage)\n\t\t\t\tImGui::Text(\"CPU: %.2lf%%\", g_state.cpu_usage);\n\n\t\t\tif (config.overlay.cpu_per_core_usage)\n\t\t\t{\n\t\t\t\tfor (sint32 i = 0; i < g_state.processor_count; ++i)\n\t\t\t\t{\n\t\t\t\t\tImGui::Text(\"CPU #%d: %.2lf%%\", i + 1, g_state.cpu_per_core[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (config.overlay.ram_usage)\n\t\t\t\tImGui::Text(\"RAM: %dMB\", g_state.ram_usage);\n\n\t\t\tif(config.overlay.vram_usage && g_state.vramUsage != -1 && g_state.vramTotal != -1)\n\t\t\t\tImGui::Text(\"VRAM: %dMB / %dMB\", g_state.vramUsage, g_state.vramTotal);\n\n\t\t\tif (config.overlay.debug)\n\t\t\t{\n\t\t\t\t// general debug info\n\t\t\t\tImGui::Text(\"--- Debug info ---\");\n\t\t\t\tImGui::Text(\"IndexUploadPerFrame: %dKB\", (performanceMonitor.stats.indexDataUploadPerFrame+1023)/1024);\n\t\t\t\t// backend specific info\n\t\t\t\tg_renderer->AppendOverlayDebugInfo();\n\t\t\t}\n\n\t\t\tposition.y += (ImGui::GetWindowSize().y + 10.0f) * direction;\n\t\t}\n\t\tImGui::End();\n\t}\n\n\tImGui::PopStyleColor();\n\tImGui::PopFont();\n}\n\nvoid LatteOverlay_RenderNotifications(ImVec2& position, ImVec2& pivot, sint32 direction, float fontSize, bool pad)\n{\n\tauto& config = GetConfig();\n\n\tconst auto font = ImGui_GetFont(fontSize);\n\tImGui::PushFont(font);\n\n\tconst ImVec4 color = ImGui::ColorConvertU32ToFloat4(config.notification.text_color);\n\tImGui::PushStyleColor(ImGuiCol_Text, color);\n\n\t// selected controller profiles in the beginning\n\tif (config.notification.controller_profiles)\n\t{\n\t\tstatic bool s_init_overlay = false;\n\t\tif (!s_init_overlay)\n\t\t{\n\t\t\tstatic std::chrono::steady_clock::time_point s_started = tick_cached();\n\n\t\t\tconst auto now = tick_cached();\n\t\t\tif (std::chrono::duration_cast<std::chrono::milliseconds>(now - s_started).count() <= 5000)\n\t\t\t{\n\t\t\t\t// active account\n\t\t\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\t\t\tImGui::SetNextWindowBgAlpha(kBackgroundAlpha);\n\t\t\t\tif (ImGui::Begin(\"Active account\", nullptr, kPopupFlags))\n\t\t\t\t{\n\t\t\t\t\tImGui::TextUnformatted((const char*)ICON_FA_USER);\n\t\t\t\t\tImGui::SameLine();\n\n\t\t\t\t\tstatic std::string s_mii_name;\n\t\t\t\t\tif (s_mii_name.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tauto tmp_view = Account::GetAccount(ActiveSettings::GetPersistentId()).GetMiiName();\n\t\t\t\t\t\tstd::wstring tmp{ tmp_view };\n\t\t\t\t\t\ts_mii_name = boost::nowide::narrow(tmp);\n\t\t\t\t\t}\n\t\t\t\t\tImGui::TextUnformatted(s_mii_name.c_str());\n\n\t\t\t\t\tposition.y += (ImGui::GetWindowSize().y + 10.0f) * direction;\n\t\t\t\t}\n\t\t\t\tImGui::End();\n\t\t\t\t\n\t\t\t\t// controller\n\t\t\t\tstd::vector<std::pair<int, std::string>> profiles;\n\t\t\t\tauto& input_manager = InputManager::instance();\n\t\t\t\tfor (int i = 0; i < InputManager::kMaxController; ++i)\n\t\t\t\t{\n\t\t\t\t\tconst auto controller = input_manager.get_controller(i);\n\t\t\t\t\tif (!controller)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tconst auto& profile_name = controller->get_profile_name();\n\t\t\t\t\tif (profile_name.empty())\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tprofiles.emplace_back(i, profile_name);\n\t\t\t\t}\n\n\t\t\t\tif (!profiles.empty())\n\t\t\t\t{\n\t\t\t\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\t\t\t\tImGui::SetNextWindowBgAlpha(kBackgroundAlpha);\n\t\t\t\t\tif (ImGui::Begin(\"Controller profile names\", nullptr, kPopupFlags))\n\t\t\t\t\t{\n\t\t\t\t\t\tauto it = profiles.cbegin();\n\t\t\t\t\t\tImGui::TextUnformatted((const char*)ICON_FA_GAMEPAD);\n\t\t\t\t\t\tImGui::SameLine();\n\t\t\t\t\t\tImGui::Text(\"Player %d: %s\", it->first + 1, it->second.c_str());\n\n\t\t\t\t\t\tfor (++it; it != profiles.cend(); ++it)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tImGui::Separator();\n\t\t\t\t\t\t\tImGui::TextUnformatted((const char*)ICON_FA_GAMEPAD);\n\t\t\t\t\t\t\tImGui::SameLine();\n\t\t\t\t\t\t\tImGui::Text(\"Player %d: %s\", it->first + 1, it->second.c_str());\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tposition.y += (ImGui::GetWindowSize().y + 10.0f) * direction;\n\t\t\t\t\t}\n\t\t\t\t\tImGui::End();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\ts_init_overlay = true;\n\t\t\t}\n\t\t\telse\n\t\t\t\ts_init_overlay = true;\n\t\t}\n\t}\n\n\tif (config.notification.friends)\n\t{\n\t\tstatic std::vector< std::pair<std::string, std::chrono::steady_clock::time_point> > s_friend_list;\n\n\t\tstd::unique_lock lock(g_friend_notification_mutex);\n\t\tif (!g_friend_notifications.empty())\n\t\t{\n\t\t\tconst auto tick = tick_cached();\n\n\t\t\tfor (const auto& entry : g_friend_notifications)\n\t\t\t{\n\t\t\t\ts_friend_list.emplace_back(entry.first, tick + std::chrono::milliseconds(entry.second));\n\t\t\t}\n\n\t\t\tg_friend_notifications.clear();\n\t\t}\n\n\t\tif (!s_friend_list.empty())\n\t\t{\n\t\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\t\tImGui::SetNextWindowBgAlpha(kBackgroundAlpha);\n\t\t\tif (ImGui::Begin(\"Friends overlay\", nullptr, kPopupFlags))\n\t\t\t{\n\t\t\t\tconst auto tick = tick_cached();\n\t\t\t\tfor (auto it = s_friend_list.cbegin(); it != s_friend_list.cend();)\n\t\t\t\t{\n\t\t\t\t\tImGui::TextUnformatted(it->first.c_str(), it->first.c_str() + it->first.size());\n\t\t\t\t\tif (tick >= it->second)\n\t\t\t\t\t\tit = s_friend_list.erase(it);\n\t\t\t\t\telse\n\t\t\t\t\t\t++it;\n\t\t\t\t}\n\n\t\t\t\tposition.y += (ImGui::GetWindowSize().y + 10.0f) * direction;\n\t\t\t}\n\t\t\tImGui::End();\n\t\t}\n\t}\n\n\t// low battery warning\n\tif (config.notification.controller_battery)\n\t{\n\t\tstd::vector<int> batteries;\n\t\tauto& input_manager = InputManager::instance();\n\t\tfor (int i = 0; i < InputManager::kMaxController; ++i)\n\t\t{\n\t\t\tconst auto controller = input_manager.get_controller(i);\n\t\t\tif (!controller)\n\t\t\t\tcontinue;\n\n\t\t\tif (controller->is_battery_low())\n\t\t\t\tbatteries.emplace_back(i);\n\t\t}\n\n\t\tif (!batteries.empty())\n\t\t{\n\t\t\tstatic std::chrono::steady_clock::time_point s_last_tick = tick_cached();\n\t\t\tstatic bool s_blink_state = false;\n\t\t\tconst auto now = tick_cached();\n\n\t\t\tif (std::chrono::duration_cast<std::chrono::milliseconds>(now - s_last_tick).count() >= 750)\n\t\t\t{\n\t\t\t\ts_blink_state = !s_blink_state;\n\t\t\t\ts_last_tick = now;\n\t\t\t}\n\n\t\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\t\tImGui::SetNextWindowBgAlpha(kBackgroundAlpha);\n\t\t\tif (ImGui::Begin(\"Low battery overlay\", nullptr, kPopupFlags))\n\t\t\t{\n\t\t\t\tauto it = batteries.cbegin();\n\t\t\t\tImGui::TextUnformatted((const char*)(s_blink_state ? ICON_FA_BATTERY_EMPTY : ICON_FA_BATTERY_QUARTER));\n\t\t\t\tImGui::SameLine();\n\t\t\t\tImGui::Text(\"Player %d\", *it + 1);\n\n\t\t\t\tfor (++it; it != batteries.cend(); ++it)\n\t\t\t\t{\n\t\t\t\t\tImGui::Separator();\n\t\t\t\t\tImGui::TextUnformatted((const char*)(s_blink_state ? ICON_FA_BATTERY_EMPTY : ICON_FA_BATTERY_QUARTER));\n\t\t\t\t\tImGui::SameLine();\n\t\t\t\t\tImGui::Text(\"Player %d\", *it + 1);\n\t\t\t\t}\n\n\t\t\t\tposition.y += (ImGui::GetWindowSize().y + 10.0f) * direction;\n\t\t\t}\n\t\t\tImGui::End();\n\t\t}\n\t}\n\n\tif (config.notification.shader_compiling)\n\t{\n\t\tstatic int32_t s_shader_count = 0;\n\t\tstatic int32_t s_shader_count_async = 0;\n\t\tif (s_shader_count > 0 || g_compiled_shaders_total > 0)\n\t\t{\n\t\t\tconst int tmp = g_compiled_shaders_total.exchange(0);\n\t\t\tconst int tmpAsync = g_compiled_shaders_async.exchange(0);\n\t\t\ts_shader_count += tmp;\n\t\t\ts_shader_count_async += tmpAsync;\n\n\t\t\tstatic std::chrono::steady_clock::time_point s_last_tick = tick_cached();\n\t\t\tconst auto now = tick_cached();\n\n\t\t\tif (tmp > 0)\n\t\t\t\ts_last_tick = now;\n\n\t\t\tif (std::chrono::duration_cast<std::chrono::milliseconds>(now - s_last_tick).count() >= 2500)\n\t\t\t{\n\t\t\t\ts_shader_count = 0;\n\t\t\t\ts_shader_count_async = 0;\n\t\t\t}\n\n\t\t\tif (s_shader_count > 0)\n\t\t\t{\n\t\t\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\t\t\tImGui::SetNextWindowBgAlpha(kBackgroundAlpha);\n\t\t\t\tif (ImGui::Begin(\"Compiling shaders overlay\", nullptr, kPopupFlags))\n\t\t\t\t{\n\t\t\t\t\tImRotateStart();\n\t\t\t\t\tImGui::TextUnformatted((const char*)ICON_FA_SPINNER);\n\n\t\t\t\t\tconst auto ticks = std::chrono::time_point_cast<std::chrono::milliseconds>(now);\n\t\t\t\t\tImRotateEnd(0.001f * ticks.time_since_epoch().count());\n\t\t\t\t\tImGui::SameLine();\n\n\t\t\t\t\tif (s_shader_count_async > 0 && GetConfig().async_compile) // the latter condition is to never show async count when async isn't enabled. Since it can be confusing to the user\n\t\t\t\t\t{\n\t\t\t\t\t\tif(s_shader_count > 1)\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new shaders... (%d async)\", s_shader_count, s_shader_count_async);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new shader... (%d async)\", s_shader_count, s_shader_count_async);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (s_shader_count > 1)\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new shaders...\", s_shader_count);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new shader...\", s_shader_count);\n\t\t\t\t\t}\n\n\t\t\t\t\tposition.y += (ImGui::GetWindowSize().y + 10.0f) * direction;\n\t\t\t\t}\n\t\t\t\tImGui::End();\n\t\t\t}\n\t\t}\n\t\t\n\t\tstatic int32_t s_pipeline_count = 0;\n\t\tstatic int32_t s_pipeline_count_async = 0;\n\t\tif (s_pipeline_count > 0 || g_compiling_pipelines > 0)\n\t\t{\n\t\t\tconst int tmp = g_compiling_pipelines.exchange(0);\n\t\t\tconst int tmpAsync = g_compiling_pipelines_async.exchange(0);\n\t\t\ts_pipeline_count += tmp;\n\t\t\ts_pipeline_count_async += tmpAsync;\n\n\t\t\tstatic std::chrono::steady_clock::time_point s_last_tick = tick_cached();\n\t\t\tconst auto now = tick_cached();\n\n\t\t\tif (tmp > 0)\n\t\t\t\ts_last_tick = now;\n\n\t\t\tif (std::chrono::duration_cast<std::chrono::milliseconds>(now - s_last_tick).count() >= 2500)\n\t\t\t{\n\t\t\t\ts_pipeline_count = 0;\n\t\t\t\ts_pipeline_count_async = 0;\n\t\t\t}\n\n\t\t\tif (s_pipeline_count > 0)\n\t\t\t{\n\t\t\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\t\t\tImGui::SetNextWindowBgAlpha(kBackgroundAlpha);\n\t\t\t\tif (ImGui::Begin(\"Compiling pipeline overlay\", nullptr, kPopupFlags))\n\t\t\t\t{\n\t\t\t\t\tImRotateStart();\n\t\t\t\t\tImGui::TextUnformatted((const char*)ICON_FA_SPINNER);\n\n\t\t\t\t\tconst auto ticks = std::chrono::time_point_cast<std::chrono::milliseconds>(now);\n\t\t\t\t\tImRotateEnd(0.001f * ticks.time_since_epoch().count());\n\t\t\t\t\tImGui::SameLine();\n\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\t\t\tuint64 totalTime = g_compiling_pipelines_syncTimeSum / 1000000ull;\n\t\t\t\t\tif (s_pipeline_count_async > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (s_pipeline_count > 1)\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new pipelines... (%d async) TotalSync: %\" PRIu64 \"ms\", s_pipeline_count, s_pipeline_count_async, totalTime);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new pipeline... (%d async) TotalSync: %\" PRIu64 \"ms\", s_pipeline_count, s_pipeline_count_async, totalTime);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (s_pipeline_count > 1)\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new pipelines... TotalSync: %\" PRIu64 \"ms\", s_pipeline_count, totalTime);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new pipeline... TotalSync: %\" PRIu64 \"ms\", s_pipeline_count, totalTime);\n\t\t\t\t\t}\n#else\n\t\t\t\t\tif (s_pipeline_count_async > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (s_pipeline_count > 1)\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new pipelines... (%d async)\", s_pipeline_count, s_pipeline_count_async);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new pipeline... (%d async)\", s_pipeline_count, s_pipeline_count_async);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (s_pipeline_count > 1)\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new pipelines...\", s_pipeline_count);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tImGui::Text(\"Compiled %d new pipeline...\", s_pipeline_count);\n\t\t\t\t\t}\n#endif\n\t\t\t\t\tposition.y += (ImGui::GetWindowSize().y + 10.0f) * direction;\n\t\t\t\t}\n\t\t\t\tImGui::End();\n\t\t\t}\n\t\t}\n\t}\n\n\t// misc notifications\n\tstatic std::vector< std::pair<std::string, std::chrono::steady_clock::time_point> > s_misc_notifications;\n\n\tstd::unique_lock misc_lock(g_notification_mutex);\n\tif (!g_notifications.empty())\n\t{\n\t\tconst auto tick = tick_cached();\n\n\t\tfor (const auto& entry : g_notifications)\n\t\t{\n\t\t\ts_misc_notifications.emplace_back(entry.first, tick + std::chrono::milliseconds(entry.second));\n\t\t}\n\n\t\tg_notifications.clear();\n\t}\n\tmisc_lock.unlock();\n\n\tif (!s_misc_notifications.empty())\n\t{\n\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\tImGui::SetNextWindowBgAlpha(kBackgroundAlpha);\n\t\tif (ImGui::Begin(\"Misc notifications\", nullptr, kPopupFlags))\n\t\t{\n\t\t\tconst auto tick = tick_cached();\n\t\t\tfor (auto it = s_misc_notifications.cbegin(); it != s_misc_notifications.cend();)\n\t\t\t{\n\t\t\t\tImGui::TextUnformatted(it->first.c_str(), it->first.c_str() + it->first.size());\n\t\t\t\tif (tick >= it->second)\n\t\t\t\t\tit = s_misc_notifications.erase(it);\n\t\t\t\telse\n\t\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tposition.y += (ImGui::GetWindowSize().y + 10.0f) * direction;\n\t\t}\n\t\tImGui::End();\n\t}\n\tImGui::PopStyleColor();\n\tImGui::PopFont();\n}\n\nvoid LatteOverlay_translateScreenPosition(ScreenPosition pos, const Vector2f& window_size, ImVec2& position, ImVec2& pivot, sint32& direction)\n{\n\tswitch (pos)\n\t{\n\tcase ScreenPosition::kTopLeft:\n\t\tposition = { 10, 10 };\n\t\tpivot = { 0, 0 };\n\t\tdirection = 1;\n\t\tbreak;\n\tcase ScreenPosition::kTopCenter:\n\t\tposition = { window_size.x / 2.0f, 10 };\n\t\tpivot = { 0.5f, 0 };\n\t\tdirection = 1;\n\t\tbreak;\n\tcase ScreenPosition::kTopRight:\n\t\tposition = { window_size.x - 10, 10 };\n\t\tpivot = { 1, 0 };\n\t\tdirection = 1;\n\t\tbreak;\n\tcase ScreenPosition::kBottomLeft:\n\t\tposition = { 10, window_size.y - 10 };\n\t\tpivot = { 0, 1 };\n\t\tdirection = -1;\n\t\tbreak;\n\tcase ScreenPosition::kBottomCenter:\n\t\tposition = { window_size.x / 2.0f, window_size.y - 10 };\n\t\tpivot = { 0.5f, 1 };\n\t\tdirection = -1;\n\t\tbreak;\n\tcase ScreenPosition::kBottomRight:\n\t\tposition = { window_size.x - 10, window_size.y - 10 };\n\t\tpivot = { 1, 1 };\n\t\tdirection = -1;\n\t\tbreak;\n\tdefault:\n\t\tUNREACHABLE;\n\t}\n}\n\nvoid LatteOverlay_render(bool pad_view)\n{\n\tconst auto& config = GetConfig();\n\tif(config.overlay.position == ScreenPosition::kDisabled && config.notification.position == ScreenPosition::kDisabled)\n\t\treturn;\n\n\tsint32 w = 0, h = 0;\n\tif (pad_view && WindowSystem::IsPadWindowOpen())\n\t\tWindowSystem::GetPadWindowPhysSize(w, h);\n\telse\n\t\tWindowSystem::GetWindowPhysSize(w, h);\n\n\tif (w == 0 || h == 0)\n\t\treturn;\n\n\tconst Vector2f window_size{ (float)w,(float)h };\n\n\tfloat fontDPIScale = !pad_view ? WindowSystem::GetWindowDPIScale() : WindowSystem::GetPadDPIScale();\n\n\tfloat overlayFontSize = 14.0f * (float)config.overlay.text_scale / 100.0f * fontDPIScale;\n\n\t// test if fonts are already precached\n\tif (!ImGui_GetFont(overlayFontSize))\n\t\treturn;\n\n\tfloat notificationsFontSize = 14.0f * (float)config.notification.text_scale / 100.0f * fontDPIScale;\n\t\n\tif (!ImGui_GetFont(notificationsFontSize))\n\t\treturn;\n\n\tImVec2 position{}, pivot{};\n\tsint32 direction{};\n\n\tif (config.overlay.position != ScreenPosition::kDisabled)\n\t{\n\t\tLatteOverlay_translateScreenPosition(config.overlay.position, window_size, position, pivot, direction);\n\t\tLatteOverlay_renderOverlay(position, pivot, direction, overlayFontSize, pad_view);\n\t}\n\t\n\n\tif (config.notification.position != ScreenPosition::kDisabled)\n\t{\n\t\tif(config.overlay.position != config.notification.position)\n\t\t\tLatteOverlay_translateScreenPosition(config.notification.position, window_size, position, pivot, direction);\n\n\t\tLatteOverlay_RenderNotifications(position, pivot, direction, notificationsFontSize, pad_view);\n\t}\n}\n\nvoid LatteOverlay_init()\n{\n\tg_state.processor_count = GetProcessorCount();\n\n\tg_state.processor_times.resize(g_state.processor_count);\n\tg_state.cpu_per_core.resize(g_state.processor_count);\n}\n\nstatic void UpdateStats_CemuCpu()\n{\n\tProcessorTime now;\n\tQueryProcTime(now);\n\t\n\tdouble cpu = ProcessorTime::Compare(g_state.processor_time_cemu, now);\n\tcpu /= g_state.processor_count;\n\t\n\tg_state.cpu_usage = cpu * 100;\n\tg_state.processor_time_cemu = now;\n}\n\nstatic void UpdateStats_CpuPerCore()\n{\n\tstd::vector<ProcessorTime> now(g_state.processor_count);\n\tQueryCoreTimes(g_state.processor_count, now);\n\n\tfor (int32_t i = 0; i < g_state.processor_count; ++i)\n\t{\n\t\tdouble cpu = ProcessorTime::Compare(g_state.processor_times[i], now[i]);\n\n\t\tg_state.cpu_per_core[i] = cpu * 100;\n\t\tg_state.processor_times[i] = now[i];\n\t}\n}\n\nvoid LatteOverlay_updateStats(double fps, sint32 drawcalls, sint32 fastDrawcalls)\n{\n\tif (GetConfig().overlay.position == ScreenPosition::kDisabled)\n\t\treturn;\n\n\tg_state.fps = fps;\n\tg_state.draw_calls_per_frame = drawcalls;\n\tg_state.fast_draw_calls_per_frame = fastDrawcalls;\n\tUpdateStats_CemuCpu();\n\tUpdateStats_CpuPerCore();\n\n\t// update ram\n\tg_state.ram_usage = (QueryRamUsage() / 1000) / 1000;\n\n\t// update vram\n\tg_renderer->GetVRAMInfo(g_state.vramUsage, g_state.vramTotal);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteOverlay.h",
    "content": "#pragma once\n\nvoid LatteOverlay_init();\nvoid LatteOverlay_render(bool pad_view);\nvoid LatteOverlay_updateStats(double fps, sint32 drawcalls, sint32 fastDrawcalls);\n\nvoid LatteOverlay_pushNotification(const std::string& text, sint32 duration);"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LattePM4.h",
    "content": "#pragma once\n\n#define IT_SET_PREDICATION\t\t\t0x20\n#define IT_DRAW_INDEX_2\t\t\t\t0x27\n#define IT_CONTEXT_CONTROL\t\t\t0x28\n#define IT_INDEX_TYPE\t\t\t\t0x2A\n#define IT_DRAW_INDEX_AUTO\t\t\t0x2D\n#define IT_DRAW_INDEX_IMMD\t\t\t0x2E\n#define IT_NUM_INSTANCES\t\t\t0x2F\n#define IT_INDIRECT_BUFFER_PRIV\t\t0x32\n#define IT_STRMOUT_BUFFER_UPDATE\t0x34\n#define IT_MEM_SEMAPHORE\t\t\t0x39\n#define IT_WAIT_REG_MEM\t\t\t\t0x3C\n#define IT_MEM_WRITE\t\t\t\t0x3D\n#define IT_SURFACE_SYNC\t\t\t\t0x43\n#define IT_EVENT_WRITE\t\t\t\t0x46\n#define IT_EVENT_WRITE_EOP\t\t\t0x47\t// end of pipe\n\n#define IT_LOAD_CONFIG_REG\t\t\t0x60\n#define IT_LOAD_CONTEXT_REG\t\t\t0x61\n#define IT_LOAD_ALU_CONST\t\t\t0x62\n#define IT_LOAD_BOOL_CONST\t\t\t0x63 // not used?\n#define IT_LOAD_LOOP_CONST\t\t\t0x64\n#define IT_LOAD_RESOURCE\t\t\t0x65\n#define IT_LOAD_SAMPLER\t\t\t\t0x66\n\n#define IT_SET_CONFIG_REG\t\t\t0x68\n#define IT_SET_CONTEXT_REG\t\t\t0x69\n#define IT_SET_ALU_CONST\t\t\t0x6A\n#define IT_SET_LOOP_CONST\t\t\t0x6C\n#define IT_SET_RESOURCE\t\t\t\t0x6D\n#define IT_SET_SAMPLER\t\t\t\t0x6E\n#define IT_SET_CTL_CONST\t\t\t0x6F\n#define IT_STRMOUT_BASE_UPDATE\t\t0x72\n#define IT_SET_ALL_CONTEXTS\t\t\t0x74\n\n#define LATTE_REG_BASE_CONFIG\t\t0x2000\n#define LATTE_REG_BASE_CONTEXT\t\t0xA000\n#define LATTE_REG_BASE_ALU_CONST\t0xC000\n#define LATTE_REG_BASE_LOOP_CONST\t0xF880\n#define LATTE_REG_BASE_RESOURCE\t\t0xE000\n#define LATTE_REG_BASE_SAMPLER\t\t0xF000\n\n// emulator only\n#define IT_HLE_COPY_SURFACE_NEW\t\t\t\t\t0xEE\n#define IT_HLE_SYNC_ASYNC_OPERATIONS\t\t\t0xEF\n#define IT_HLE_REQUEST_SWAP_BUFFERS\t\t\t\t0xF0\n#define IT_HLE_WAIT_FOR_FLIP\t\t\t\t\t0xF1\n#define IT_HLE_BOTTOM_OF_PIPE_CB\t\t\t\t0xF2\n#define IT_HLE_COPY_COLORBUFFER_TO_SCANBUFFER\t0xF3\n#define IT_HLE_CLEAR_COLOR_DEPTH_STENCIL\t\t0xF5\n#define IT_HLE_SAMPLE_TIMER\t\t\t\t\t\t0xF7\n#define IT_HLE_TRIGGER_SCANBUFFER_SWAP\t\t\t0xF8\n#define IT_HLE_SPECIAL_STATE\t\t\t\t\t0xF9\n#define IT_HLE_BEGIN_OCCLUSION_QUERY\t\t\t0xFA\n#define IT_HLE_END_OCCLUSION_QUERY\t\t\t\t0xFB\n\n#define pm4HeaderType3(__itCode, __dataDWordCount) (0xC0000000|((uint32)(__itCode)<<8)|((uint32)((__dataDWordCount)-1)<<16))\n#define pm4HeaderType2Filler() (0x80000000)\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LattePerformanceMonitor.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Core/LatteOverlay.h\"\n#include \"WindowSystem.h\"\n\nperformanceMonitor_t performanceMonitor{};\n\nvoid LattePerformanceMonitor_frameEnd()\n{\n\t// per-frame stats\n\tperformanceMonitor.gpuTime_shaderCreate.frameFinished();\n\tperformanceMonitor.gpuTime_frameTime.frameFinished();\n\tperformanceMonitor.gpuTime_idleTime.frameFinished();\n\tperformanceMonitor.gpuTime_fenceTime.frameFinished();\n\n\tperformanceMonitor.gpuTime_dcStageTextures.frameFinished();\n\tperformanceMonitor.gpuTime_dcStageVertexMgr.frameFinished();\n\tperformanceMonitor.gpuTime_dcStageShaderAndUniformMgr.frameFinished();\n\tperformanceMonitor.gpuTime_dcStageIndexMgr.frameFinished();\n\tperformanceMonitor.gpuTime_dcStageMRT.frameFinished();\n\tperformanceMonitor.gpuTime_dcStageDrawcallAPI.frameFinished();\n\tperformanceMonitor.gpuTime_waitForAsync.frameFinished();\n\n\tuint32 elapsedTime = GetTickCount() - performanceMonitor.cycle[performanceMonitor.cycleIndex].lastUpdate;\n\tif (elapsedTime >= 1000)\n\t{\n\t\tbool isFirstUpdate = performanceMonitor.cycle[performanceMonitor.cycleIndex].lastUpdate == 0;\n\t\t// sum up raw stats\n\t\tuint32 totalElapsedTime = GetTickCount() - performanceMonitor.cycle[(performanceMonitor.cycleIndex + 1) % PERFORMANCE_MONITOR_TRACK_CYCLES].lastUpdate;\n\t\tuint32 totalElapsedTimeFPS = GetTickCount() - performanceMonitor.cycle[(performanceMonitor.cycleIndex + PERFORMANCE_MONITOR_TRACK_CYCLES - 1) % PERFORMANCE_MONITOR_TRACK_CYCLES].lastUpdate;\n\t\tuint32 elapsedFrames = 0;\n\t\tuint32 elapsedFrames2S = 0; // elapsed frames for last two entries (seconds)\n\t\tuint64 skippedCycles = 0;\n\t\tuint64 vertexDataUploaded = 0;\n\t\tuint64 vertexDataCached = 0;\n\t\tuint64 uniformBankUploadedData = 0;\n\t\tuint64 uniformBankUploadedCount = 0;\n\t\tuint64 indexDataUploaded = 0;\n\t\tuint64 indexDataCached = 0;\n\t\tuint32 frameCounter = 0;\n\t\tuint32 drawCallCounter = 0;\n\t\tuint32 fastDrawCallCounter = 0;\n\t\tuint32 shaderBindCounter = 0;\n\t\tuint32 recompilerLeaveCount = 0;\n\t\tuint32 threadLeaveCount = 0;\n\t\tfor (sint32 i = 0; i < PERFORMANCE_MONITOR_TRACK_CYCLES; i++)\n\t\t{\n\t\t\telapsedFrames += performanceMonitor.cycle[i].frameCounter;\n\t\t\tskippedCycles += performanceMonitor.cycle[i].skippedCycles;\n\t\t\tvertexDataUploaded += performanceMonitor.cycle[i].vertexDataUploaded;\n\t\t\tvertexDataCached += performanceMonitor.cycle[i].vertexDataCached;\n\t\t\tuniformBankUploadedData += performanceMonitor.cycle[i].uniformBankUploadedData;\n\t\t\tuniformBankUploadedCount += performanceMonitor.cycle[i].uniformBankUploadedCount;\n\t\t\tindexDataUploaded += performanceMonitor.cycle[i].indexDataUploaded;\n\t\t\tindexDataCached += performanceMonitor.cycle[i].indexDataCached;\n\t\t\tframeCounter += performanceMonitor.cycle[i].frameCounter;\n\t\t\tdrawCallCounter += performanceMonitor.cycle[i].drawCallCounter;\n\t\t\tfastDrawCallCounter += performanceMonitor.cycle[i].fastDrawCallCounter;\n\t\t\tshaderBindCounter += performanceMonitor.cycle[i].shaderBindCount;\n\t\t\trecompilerLeaveCount += performanceMonitor.cycle[i].recompilerLeaveCount;\n\t\t\tthreadLeaveCount += performanceMonitor.cycle[i].threadLeaveCount;\n\t\t}\n\t\telapsedFrames = std::max<uint32>(elapsedFrames, 1);\n\t\telapsedFrames2S = performanceMonitor.cycle[(performanceMonitor.cycleIndex + PERFORMANCE_MONITOR_TRACK_CYCLES - 0) % PERFORMANCE_MONITOR_TRACK_CYCLES].frameCounter;\n\t\telapsedFrames2S += performanceMonitor.cycle[(performanceMonitor.cycleIndex + PERFORMANCE_MONITOR_TRACK_CYCLES - 1) % PERFORMANCE_MONITOR_TRACK_CYCLES].frameCounter;\n\t\telapsedFrames2S = std::max<uint32>(elapsedFrames2S, 1);\n\t\t// calculate stats\n\t\tuint64 passedCycles = PPCInterpreter_getMainCoreCycleCounter() - performanceMonitor.cycle[(performanceMonitor.cycleIndex + 1) % PERFORMANCE_MONITOR_TRACK_CYCLES].lastCycleCount;\n\t\tpassedCycles -= skippedCycles;\n\t\tuint64 vertexDataUploadPerFrame = (vertexDataUploaded / (uint64)elapsedFrames);\n\t\tvertexDataUploadPerFrame /= 1024ULL;\n\t\tuint64 vertexDataCachedPerFrame = (vertexDataCached / (uint64)elapsedFrames);\n\t\tvertexDataCachedPerFrame /= 1024ULL;\n\t\tuint64 uniformBankDataUploadedPerFrame = (uniformBankUploadedData / (uint64)elapsedFrames);\n\t\tuniformBankDataUploadedPerFrame /= 1024ULL;\n\t\tuint32 uniformBankCountUploadedPerFrame = (uint32)(uniformBankUploadedCount / (uint64)elapsedFrames);\n\t\tuint64 indexDataUploadPerFrame = (indexDataUploaded / (uint64)elapsedFrames);\n\n\t\tdouble fps = (double)elapsedFrames2S * 1000.0 / (double)totalElapsedTimeFPS;\n\t\tuint32 shaderBindsPerFrame = shaderBindCounter / elapsedFrames;\n\t\tpassedCycles = passedCycles * 1000ULL / totalElapsedTime;\n\t\tuint32 rlps = (uint32)((uint64)recompilerLeaveCount * 1000ULL / (uint64)totalElapsedTime);\n\t\tuint32 tlps = (uint32)((uint64)threadLeaveCount * 1000ULL / (uint64)totalElapsedTime);\n\t\t// set stats\n\t\tperformanceMonitor.stats.indexDataUploadPerFrame = indexDataUploadPerFrame;\n\t\t// next counter cycle\n\t\tsint32 nextCycleIndex = (performanceMonitor.cycleIndex + 1) % PERFORMANCE_MONITOR_TRACK_CYCLES;\n\t\tperformanceMonitor.cycle[nextCycleIndex].drawCallCounter = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].fastDrawCallCounter = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].frameCounter = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].shaderBindCount = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].lastCycleCount = PPCInterpreter_getMainCoreCycleCounter();\n\t\tperformanceMonitor.cycle[nextCycleIndex].skippedCycles = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].vertexDataUploaded = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].vertexDataCached = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].uniformBankUploadedData = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].uniformBankUploadedCount = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].indexDataUploaded = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].indexDataCached = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].recompilerLeaveCount = 0;\n\t\tperformanceMonitor.cycle[nextCycleIndex].threadLeaveCount = 0;\n\t\tperformanceMonitor.cycleIndex = nextCycleIndex;\n\n\t\t// next update in 1 second\n\t\tperformanceMonitor.cycle[performanceMonitor.cycleIndex].lastUpdate = GetTickCount();\n\n\t\tif (isFirstUpdate)\n\t\t{\n\t\t\tLatteOverlay_updateStats(0.0, 0, 0);\n\t\t\tWindowSystem::UpdateWindowTitles(false, false, 0.0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tLatteOverlay_updateStats(fps, drawCallCounter / elapsedFrames, fastDrawCallCounter / elapsedFrames);\n\t\t\tWindowSystem::UpdateWindowTitles(false, false, fps);\n\t\t}\n\t}\n}\n\nvoid LattePerformanceMonitor_frameBegin()\n{\n\tperformanceMonitor.vk.numDrawBarriersPerFrame.reset();\n\tperformanceMonitor.vk.numBeginRenderpassPerFrame.reset();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LattePerformanceMonitor.h",
    "content": "#pragma once\n\n#define PERFORMANCE_MONITOR_TRACK_CYCLES\t(5) // one cycle lasts one second\n\n// todo - replace PPCTimer with HighResolutionTimer.h\nuint64 PPCTimer_getRawTsc();\nuint64 PPCTimer_tscToMicroseconds(uint64 us);\n\nclass LattePerfStatTimer\n{\npublic:\n\tvoid beginMeasuring()\n\t{\n\t\ttimerStart = PPCTimer_getRawTsc();\n\t}\n\n\tvoid endMeasuring()\n\t{\n\t\tuint64 dif = PPCTimer_getRawTsc() - timerStart;\n\t\tcurrentSum += dif;\n\t}\n\n\tvoid frameFinished()\n\t{\n\t\tpreviousFrame = currentSum;\n\t\tcurrentSum = 0;\n\t}\n\n\tuint64 getPreviousFrameValue()\n\t{\n\t\treturn previousFrame;\n\t}\n\nprivate:\n\tuint64 currentSum{};\n\tuint64 previousFrame{};\n\tuint64 timerStart{};\n};\n\nclass LattePerfStatCounter\n{\npublic:\n\tvoid increment()\n\t{\n\t\tm_value++;\n\t}\n\n\tvoid decrement()\n\t{\n\t\tcemu_assert_debug(m_value > 0);\n\t\tm_value--;\n\t}\n\n\tvoid decrement(uint32 count)\n\t{\n\t\tcemu_assert_debug(count <= m_value);\n\t\tm_value -= count;\n\t}\n\n\tuint32 get()\n\t{\n\t\treturn m_value;\n\t}\n\n\tvoid reset()\n\t{\n\t\tm_value = 0;\n\t}\n\nprivate:\n\tstd::atomic_uint32_t m_value{};\n};\n\ntypedef struct\n{\n\tstruct\n\t{\n\t\t// CPU\n\t\tuint64 lastCycleCount;\n\t\tuint64 skippedCycles;\n\t\tuint32 recompilerLeaveCount; // increased everytime the recompiler switches back to interpreter\n\t\tuint32 threadLeaveCount; // increased everytime a thread gives up it's timeslice\n\t\t// GPU\n\t\tuint32 lastUpdate;\n\t\tuint32 frameCounter;\n\t\tuint32 drawCallCounter;\n\t\tuint32 fastDrawCallCounter;\n\t\tuint32 shaderBindCount;\n\t\tuint64 vertexDataUploaded; // amount of vertex data uploaded to GPU (bytes)\n\t\tuint64 vertexDataCached; // amount of vertex data reused from GPU cache (bytes)\n\t\tuint64 uniformBankUploadedData; // amount of uniform buffer data (excluding remapped uniforms) uploaded to GPU\n\t\tuint64 uniformBankUploadedCount; // number of separate uploads for uniformBankDataUploaded\n\t\tuint64 indexDataUploaded;\n\t\tuint64 indexDataCached;\n\t}cycle[PERFORMANCE_MONITOR_TRACK_CYCLES];\n\tsint32 cycleIndex;\n\t// new stats\n\tLattePerfStatTimer gpuTime_frameTime;\n\tLattePerfStatTimer gpuTime_shaderCreate;\n\tLattePerfStatTimer gpuTime_idleTime; // time spent waiting for new commands from CPU\n\tLattePerfStatTimer gpuTime_fenceTime; // time spent waiting for fence condition\n\n\tLattePerfStatTimer gpuTime_dcStageTextures; // drawcall texture/mrt setup\n\tLattePerfStatTimer gpuTime_dcStageVertexMgr; // drawcall vertex setup and upload\n\tLattePerfStatTimer gpuTime_dcStageShaderAndUniformMgr; // drawcall shader setup and uniform management/upload\n\tLattePerfStatTimer gpuTime_dcStageIndexMgr; // drawcall index data setup and upload\n\tLattePerfStatTimer gpuTime_dcStageMRT; // drawcall render target API\n\n\tLattePerfStatTimer gpuTime_dcStageDrawcallAPI; // drawcall api call\n\tLattePerfStatTimer gpuTime_waitForAsync; // waiting for operations to complete (e.g. GX2DrawDone or force texture readback) Also includes texture readback and occlusion query polling logic\n\n\t// generic\n\tuint32 numCompiledVS; // number of compiled vertex shader programs\n\tuint32 numCompiledGS; // number of compiled geometry shader programs\n\tuint32 numCompiledPS; // number of compiled pixel shader programs\n\n\t// Vulkan\n\tstruct  \n\t{\n\t\tLattePerfStatCounter numDescriptorSets;\n\t\tLattePerfStatCounter numDescriptorDynUniformBuffers;\n\t\tLattePerfStatCounter numDescriptorStorageBuffers;\n\t\tLattePerfStatCounter numDescriptorSamplerTextures;\n\t\tLattePerfStatCounter numGraphicPipelines;\n\t\tLattePerfStatCounter numImages;\n\t\tLattePerfStatCounter numImageViews;\n\t\tLattePerfStatCounter numSamplers;\n\t\tLattePerfStatCounter numRenderPass;\n\t\tLattePerfStatCounter numFramebuffer;\n\n\t\t// per frame\n\t\tLattePerfStatCounter numDrawBarriersPerFrame;\n\t\tLattePerfStatCounter numBeginRenderpassPerFrame;\n\t}vk;\n\n\t// calculated stats (per frame)\n\tstruct\n\t{\n\t\tuint32 indexDataUploadPerFrame;\n\t}stats;\n}performanceMonitor_t;\n\nextern performanceMonitor_t performanceMonitor;\n\nvoid LattePerformanceMonitor_frameEnd();\nvoid LattePerformanceMonitor_frameBegin();\n\n#define beginPerfMonProfiling(__obj) if( THasProfiling ) __obj.beginMeasuring()\n#define endPerfMonProfiling(__obj) if( THasProfiling ) __obj.endMeasuring()"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteQuery.cpp",
    "content": "#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteQueryObject.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n\n#define GPU7_QUERY_TYPE_OCCLUSION\t(1)\n\nuint64 queryEventCounter = 1;\n\nstruct LatteGX2QueryInformation\n{\n\tMPTR queryMPTR;\n\tuint64 queryEventStart;\n\tuint64 queryEventEnd;\n\tuint64 sampleSum;\n\tbool queryEnded;\n};\n\nstd::vector<LatteGX2QueryInformation*> list_activeGX2Queries2;\n\nstd::vector<LatteQueryObject*> list_queriesInFlight;\n\nuint64 latestQueryFinishedEventId = 0;\n\nLatteQueryObject* _currentlyActiveRendererQuery = {0};\n\nuint64 LatteQuery_getNextEventId()\n{\n\tuint64 ev = queryEventCounter;\n\tqueryEventCounter++;\n\treturn ev;\n}\n\nvoid LatteQuery_begin(LatteQueryObject* queryObject, uint64 eventId)\n{\n\tqueryObject->queryEventStart = eventId;\n\tqueryObject->begin();\n}\n\nvoid LatteQuery_end(LatteQueryObject* queryObject, uint64 eventId)\n{\n\tcemu_assert_debug(!queryObject->queryEnded);\n\tqueryObject->queryEnded = true;\n\tqueryObject->queryEventEnd = eventId;\n\tqueryObject->end();\n}\n\nLatteQueryObject* LatteQuery_createSamplePassedQuery()\n{\n\treturn g_renderer->occlusionQuery_create();\n}\n\nvoid LatteQuery_finishGX2Query(LatteGX2QueryInformation* gx2Query)\n{\n\tuint32* queryObjectData = (uint32*)memory_getPointerFromVirtualOffset(gx2Query->queryMPTR);\n\t*(uint64*)(queryObjectData + 0) = 0;\n\t*(uint64*)(queryObjectData + 2) = gx2Query->sampleSum;\n\t*(uint64*)(queryObjectData + 4) = 0;\n\t*(uint64*)(queryObjectData + 6) = 0;\n\n\t*(uint64*)(queryObjectData + 8) = 0; // overwrites the 'OCPU' magic constant letting GX2QueryGetOcclusionResult know that the query is finished (for CPU queries)\n}\n\nvoid LatteQuery_UpdateFinishedQueries()\n{\n\tg_renderer->occlusionQuery_updateState();\n\tfor(uint32 i=0; i<list_queriesInFlight.size(); i++)\n\t{\n\t\tLatteQueryObject* queryObject = list_queriesInFlight[i];\n\t\tcemu_assert_debug(queryObject->queryEnded);\n\t\tif( queryObject->queryEnded == false )\n\t\t\tcontinue;\n\t\t// check if result is available\n\t\tuint64 numSamplesPassed;\n\t\tif (!queryObject->getResult(numSamplesPassed))\n\t\t\tbreak;\n\n\t\tcemu_assert_debug(latestQueryFinishedEventId < queryObject->queryEventEnd);\n\t\tlatestQueryFinishedEventId = queryObject->queryEventEnd;\n\n\t\t// add number of passed samples to all gx2 queries that were active at the time\n\t\tfor (auto& it : list_activeGX2Queries2)\n\t\t{\n\t\t\tif (queryObject->queryEventStart >= it->queryEventStart && queryObject->queryEventEnd <= it->queryEventEnd)\n\t\t\t\tit->sampleSum += numSamplesPassed;\n\t\t}\n\n\t\tlist_queriesInFlight.erase(list_queriesInFlight.begin() + i);\n\t\ti--;\n\t\tg_renderer->occlusionQuery_destroy(queryObject);\n\t}\n\t// check for finished GX2 queries\n\tfor (sint32 i = 0; i < list_activeGX2Queries2.size(); i++)\n\t{\n\t\tauto gx2Query = list_activeGX2Queries2[i];\n\t\tif (gx2Query->queryEnded && latestQueryFinishedEventId >= gx2Query->queryEventEnd)\n\t\t{\n\t\t\tLatteQuery_finishGX2Query(gx2Query);\n\t\t\tfree(gx2Query);\n\t\t\tlist_activeGX2Queries2.erase(list_activeGX2Queries2.begin() + i);\n\t\t\ti--;\n\t\t}\n\t}\n}\n\nvoid LatteQuery_UpdateFinishedQueriesForceFinishAll()\n{\n\tcemu_assert_debug(_currentlyActiveRendererQuery == nullptr);\n\tg_renderer->occlusionQuery_flush(); // guarantees that all query commands have been submitted and finished processing\n\twhile (true)\n\t{\n\t\tLatteQuery_UpdateFinishedQueries();\n\t\tif (list_queriesInFlight.empty())\n\t\t\tbreak;\n\t}\n}\n\nsint32 checkQueriesCounter = 0;\n\nvoid LatteQuery_endActiveRendererQuery(uint64 currentEventId)\n{\n\tif (_currentlyActiveRendererQuery != nullptr)\n\t{\n\t\tLatteQuery_end(_currentlyActiveRendererQuery, currentEventId);\n\t\tlist_queriesInFlight.emplace_back(_currentlyActiveRendererQuery);\n\t\t_currentlyActiveRendererQuery = nullptr;\n\t}\n}\n\nvoid LatteQuery_BeginOcclusionQuery(MPTR queryMPTR)\n{\n\tif (checkQueriesCounter < 7)\n\t{\n\t\tcheckQueriesCounter++;\n\t}\n\telse\n\t{\n\t\tLatteQuery_UpdateFinishedQueries();\n\t\tcheckQueriesCounter = 0;\n\t}\n\n\tfor(auto& it : list_activeGX2Queries2)\n\t{\n\t\tif (it->queryMPTR == queryMPTR)\n\t\t{\n\t\t\tdebug_printf(\"itHLEBeginOcclusionQuery: Query 0x%08x is already active\\n\", queryMPTR);\n\t\t\treturn;\n\t\t}\n\t}\n\tuint64 currentEventId = LatteQuery_getNextEventId();\n\t// end any currently active query\n\tLatteQuery_endActiveRendererQuery(currentEventId);\n\t// create GX2 query binding\n\tLatteGX2QueryInformation* queryBinding = (LatteGX2QueryInformation*)malloc(sizeof(LatteGX2QueryInformation));\n\tmemset(queryBinding, 0x00, sizeof(LatteGX2QueryInformation));\n\tqueryBinding->queryEventStart = currentEventId;\n\tqueryBinding->queryMPTR = queryMPTR;\n\tlist_activeGX2Queries2.emplace_back(queryBinding);\n\t// start renderer query\n\tLatteQueryObject* queryObject = LatteQuery_createSamplePassedQuery();\n\tLatteQuery_begin(queryObject, currentEventId);\n\t_currentlyActiveRendererQuery = queryObject;\n}\n\nvoid LatteQuery_EndOcclusionQuery(MPTR queryMPTR)\n{\n\tif (queryMPTR == MPTR_NULL)\n\t\treturn;\n\tuint64 currentEventId = LatteQuery_getNextEventId();\n\t// mark query binding as ended\n\tfor(auto& it : list_activeGX2Queries2)\n\t{\n\t\tif (it->queryMPTR == queryMPTR)\n\t\t{\n\t\t\tit->queryEventEnd = currentEventId;\n\t\t\tit->queryEnded = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\t// end currently active renderer query\n\tLatteQuery_endActiveRendererQuery(currentEventId);\n\t// check if there are still active GX2 queries\n\tbool hasActiveGX2Query = false;\n\tfor (auto& it : list_activeGX2Queries2)\n\t{\n\t\tif (!it->queryEnded)\n\t\t{\n\t\t\thasActiveGX2Query = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\t// start a new renderer query if there are still active GX2 queries\n\tif (hasActiveGX2Query)\n\t{\n\t\tLatteQueryObject* queryObject = LatteQuery_createSamplePassedQuery();\n\t\tLatteQuery_begin(queryObject, currentEventId);\n\t\tlist_queriesInFlight.emplace_back(queryObject);\n\t\t_currentlyActiveRendererQuery = queryObject;\n\t\tcatchOpenGLError();\n\t}\n}\n\nvoid LatteQuery_CancelActiveGPU7Queries()\n{\n\tcemu_assert_debug(_currentlyActiveRendererQuery == nullptr);\n}\n\nvoid LatteQuery_Init()\n{\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteQueryObject.h",
    "content": "#pragma once\n\nclass LatteQueryObject\n{\npublic:\n\tvirtual bool getResult(uint64& numSamplesPassed) = 0;\n\tvirtual void begin() = 0;\n\tvirtual void end() = 0;\n\n\tuint32 index{};\n\tbool queryEnded{}; // set to true once the query is ended, but the result may not be available for some time after this\n\tuint64 queryEventStart{};\n\tuint64 queryEventEnd{};\n};"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp",
    "content": "#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteOverlay.h\"\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"Cafe/HW/Latte/Core/LatteCachedFBO.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"config/ActiveSettings.h\"\n#include \"WindowSystem.h\"\n#include \"Cafe/OS/libs/erreula/erreula.h\"\n#include \"input/InputManager.h\"\n#include \"Cafe/OS/libs/swkbd/swkbd.h\"\n\nuint32 prevScissorX = 0;\nuint32 prevScissorY = 0;\nuint32 prevScissorWidth = 0;\nuint32 prevScissorHeight = 0;\n\nbool hasValidFramebufferAttached = false;\n\nstruct LatteMRTQuad\n{\n\tsint32 width;\n\tsint32 height;\n};\n\nstruct\n{\n\tLatteMRTQuad currentRenderSize;\n\tLatteMRTQuad currentEffectiveSize;\n\tstruct\n\t{\n\t\tsint32 width;\n\t\tsint32 height;\n\t}currentGuestViewport;\n\tbool renderTargetIsResized;\n\t// tracking\n\tsint32 rtUpdateListCount;\n\tLatteTextureView* rtUpdateList[64];\n\tsint32 rtUpdateListSlice[64];\n\tsint32 rtUpdateListMip[64];\n}sLatteRenderTargetState;\n\nstruct\n{\n\tstruct\n\t{\n\t\tLatteTextureView* view{};\n\t}colorBuffer[8];\n\tstruct\n\t{\n\t\tLatteTextureView* view{};\n\t\tbool hasStencil{false};\n\t}depthBuffer;\n}sLatteCurrentRendertargets{};\n\nLatteCachedFBO::LatteCachedFBO(uint64 key) : key(key)\n{\n\tfor (sint32 i = 0; i < 8; i++)\n\t{\n\t\tLatteTextureView* colorTexView = sLatteCurrentRendertargets.colorBuffer[i].view;\n\t\tcolorBuffer[i].texture = colorTexView;\n\t\tif (colorTexView)\n\t\t{\n\t\t\tvectorAppendUnique(colorTexView->list_associatedFbo, this);\n\t\t\tm_referencedTextures.emplace_back(colorTexView->baseTexture);\n\t\t}\n\t}\n\n\tif (sLatteCurrentRendertargets.depthBuffer.view)\n\t{\n\t\tLatteTextureView* depthTexView = sLatteCurrentRendertargets.depthBuffer.view;\n\t\tdepthBuffer.texture = depthTexView;\n\t\tdepthBuffer.hasStencil = sLatteCurrentRendertargets.depthBuffer.hasStencil;\n\t\tif (depthTexView)\n\t\t{\n\t\t\tvectorAppendUnique(depthTexView->list_associatedFbo, this);\n\t\t\tm_referencedTextures.emplace_back(depthTexView->baseTexture);\n\t\t}\n\t}\n\n\tcalculateEffectiveRenderAreaSize();\n}\n\nvoid LatteMRT::NotifyTextureDeletion(LatteTexture* texture)\n{\n\tfor (sint32 i = 0; i < Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS; i++)\n\t{\n\t\tif (sLatteCurrentRendertargets.colorBuffer[i].view && sLatteCurrentRendertargets.colorBuffer[i].view->baseTexture == texture)\n\t\t{\n\t\t\tsLatteCurrentRendertargets.colorBuffer[i].view = nullptr;\n\t\t}\n\t}\n}\n\nLatteCachedFBO* LatteMRT::CreateCachedFBO(uint64 key)\n{\n\treturn g_renderer->rendertarget_createCachedFBO(key);\n}\n\nvoid LatteMRT::DeleteCachedFBO(LatteCachedFBO* cfbo)\n{\n\t// color textures\n\tfor (sint32 i = 0; i < 8; i++)\n\t{\n\t\tif (cfbo->colorBuffer[i].texture == NULL)\n\t\t\tcontinue;\n\t\tcfbo->colorBuffer[i].texture->list_fboLookup.erase(std::remove(cfbo->colorBuffer[i].texture->list_fboLookup.begin(), cfbo->colorBuffer[i].texture->list_fboLookup.end(), cfbo), cfbo->colorBuffer[i].texture->list_fboLookup.end());\n\t\tcfbo->colorBuffer[i].texture->list_associatedFbo.erase(std::remove(cfbo->colorBuffer[i].texture->list_associatedFbo.begin(), cfbo->colorBuffer[i].texture->list_associatedFbo.end(), cfbo), cfbo->colorBuffer[i].texture->list_associatedFbo.end());\n\t}\n\t// depth texture\n\tif (cfbo->depthBuffer.texture)\n\t{\n\t\tcfbo->depthBuffer.texture->list_fboLookup.erase(std::remove(cfbo->depthBuffer.texture->list_fboLookup.begin(), cfbo->depthBuffer.texture->list_fboLookup.end(), cfbo), cfbo->depthBuffer.texture->list_fboLookup.end());\n\t\tcfbo->depthBuffer.texture->list_associatedFbo.erase(std::remove(cfbo->depthBuffer.texture->list_associatedFbo.begin(), cfbo->depthBuffer.texture->list_associatedFbo.end(), cfbo), cfbo->depthBuffer.texture->list_associatedFbo.end());\n\t}\n\tg_renderer->rendertarget_deleteCachedFBO(cfbo);\n\tdelete cfbo;\n}\n\nLatteCachedFBO* g_emptyFBO = nullptr;\n\nvoid LatteMRT::SetColorAttachment(uint32 index, LatteTextureView* view)\n{\n\tsLatteCurrentRendertargets.colorBuffer[index].view = view;\n}\n\nvoid LatteMRT::SetDepthAndStencilAttachment(LatteTextureView* view, bool hasStencil)\n{\n\tsLatteCurrentRendertargets.depthBuffer.view = view;\n\tsLatteCurrentRendertargets.depthBuffer.hasStencil = hasStencil;\n}\n\nLatteTextureView* LatteMRT::GetColorAttachment(uint32 index)\n{\n\tcemu_assert_debug(index < 8);\n\treturn sLatteCurrentRendertargets.colorBuffer[index].view;\n}\n\nLatteTextureView* LatteMRT::GetDepthAttachment()\n{\n\treturn sLatteCurrentRendertargets.depthBuffer.view;\n}\n\nvoid LatteMRT::ApplyCurrentState()\n{\n\tuint64 key = 0;\n\tLatteTextureView* fboLookupView = NULL;\n\tfor (sint32 i = 0; i < 8; i++)\n\t{\n\t\tLatteTextureView* colorView = sLatteCurrentRendertargets.colorBuffer[i].view;\n\t\tif (colorView)\n\t\t{\n\t\t\tkey += ((uint64)colorView);\n\t\t\tkey = std::rotl<uint64>(key, 5);\n\t\t\tfboLookupView = colorView;\n\t\t}\n\t\tkey = std::rotl<uint64>(key, 7);\n\t}\n\tif (sLatteCurrentRendertargets.depthBuffer.view)\n\t{\n\t\tkey += ((uint64)sLatteCurrentRendertargets.depthBuffer.view);\n\t\tkey = std::rotl<uint64>(key, 5);\n\t\tkey += (sLatteCurrentRendertargets.depthBuffer.hasStencil);\n\t\tif (fboLookupView == NULL)\n\t\t{\n\t\t\tfboLookupView = sLatteCurrentRendertargets.depthBuffer.view;\n\t\t}\n\t}\n\t// use fboLookupTexture to find cached FBO\n\tif (fboLookupView == nullptr)\n\t{\n\t\tif (!g_emptyFBO)\n\t\t\tg_emptyFBO = CreateCachedFBO(key);\n\t\tg_renderer->rendertarget_bindFramebufferObject(g_emptyFBO);\n\t\treturn;\n\t}\n\t// look for FBO\n\tfor (auto& fbo : fboLookupView->list_fboLookup)\n\t{\n\t\tif (fbo->key == key)\n\t\t{\n\t\t\t// found matching FBO\n\t\t\tg_renderer->rendertarget_bindFramebufferObject(fbo);\n\t\t\treturn;\n\t\t}\n\t}\n\t// create new cached FBO\n\tLatteCachedFBO* cfbo = CreateCachedFBO(key);\n\tg_renderer->rendertarget_bindFramebufferObject(cfbo);\n\tfboLookupView->list_fboLookup.push_back(cfbo);\n\t// some extra checks to verify that looked up fbo matches active buffers\n\tcemu_assert_debug(cfbo->colorBuffer[0].texture == sLatteCurrentRendertargets.colorBuffer[0].view);\n\tcemu_assert_debug(cfbo->colorBuffer[1].texture == sLatteCurrentRendertargets.colorBuffer[1].view);\n\tcemu_assert_debug(cfbo->colorBuffer[2].texture == sLatteCurrentRendertargets.colorBuffer[2].view);\n\tcemu_assert_debug(cfbo->depthBuffer.texture == sLatteCurrentRendertargets.depthBuffer.view);\n}\n\nvoid LatteMRT::BindColorBufferOnly(LatteTextureView* view)\n{\n\tcemu_assert_debug(!view->baseTexture->isDepth);\n\tSetColorAttachment(0, view);\n\tfor (sint32 i = 1; i < 8; i++)\n\t\tSetColorAttachment(i, nullptr);\n\tSetDepthAndStencilAttachment(nullptr, false);\n\tApplyCurrentState();\n}\n\nvoid LatteMRT::BindDepthBufferOnly(LatteTextureView* view)\n{\n\tcemu_assert_debug(view->baseTexture->isDepth);\n\tfor (sint32 i = 0; i < 8; i++)\n\t\tSetColorAttachment(i, nullptr);\n\tSetDepthAndStencilAttachment(view, view->baseTexture->hasStencil);\n\tApplyCurrentState();\n}\n\nLatteTextureView* LatteMRT_CreateDepthBuffer(MPTR depthBufferPhysMem, uint32 width, uint32 height, uint32 pitch, Latte::E_HWTILEMODE tileMode, Latte::E_GX2SURFFMT format, uint32 swizzle, sint32 viewSlice)\n{\n\tLatteTextureView* textureView = LatteTexture_CreateMapping(depthBufferPhysMem, MPTR_NULL, width, height, viewSlice+1, pitch, tileMode, swizzle, 0, 1, viewSlice, 1, format, viewSlice > 0 ? Latte::E_DIM::DIM_2D_ARRAY : Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, true);\n\tLatteMRT::SetDepthAndStencilAttachment(textureView, textureView->baseTexture->hasStencil);\n\treturn textureView;\n}\n\nsint32 _depthBufferSizeWarningCount = 0;\n\nLatteTextureView* LatteMRT::GetColorAttachmentTexture(uint32 index, bool createNew, bool checkForTextureChanges)\n{\n\tuint32* colorBufferRegBase = LatteGPUState.contextRegister+(mmCB_COLOR0_BASE + index);\n\tuint32 regColorBufferBase = colorBufferRegBase[mmCB_COLOR0_BASE - mmCB_COLOR0_BASE] & 0xFFFFFF00; // the low 8 bits are ignored? How to Survive seems to rely on this\n\tuint32 regColorSize = colorBufferRegBase[mmCB_COLOR0_SIZE - mmCB_COLOR0_BASE];\n\tuint32 regColorInfo = colorBufferRegBase[mmCB_COLOR0_INFO - mmCB_COLOR0_BASE];\n\tuint32 regColorView = colorBufferRegBase[mmCB_COLOR0_VIEW - mmCB_COLOR0_BASE];\n\t// decode color buffer reg info\n\tLatte::E_HWTILEMODE colorBufferTileMode = (Latte::E_HWTILEMODE)((regColorInfo >> 8) & 0xF);\n\tuint32 numberType = (regColorInfo >> 12) & 7;\n\tLatte::E_GX2SURFFMT colorBufferFormat = GetColorBufferFormat(index, LatteGPUState.contextNew);\n\n\tMPTR colorBufferPhysMem = regColorBufferBase;\n\n\tuint32 colorBufferSwizzle = 0;\n\tif ( Latte::TM_IsMacroTiled(colorBufferTileMode) )\n\t{\n\t\tcolorBufferSwizzle = colorBufferPhysMem & 0x700;\n\t\tcolorBufferPhysMem = colorBufferPhysMem & ~(7 << 8);\n\t}\n\n\t// get view slice and view slice num\n\tuint32 viewFirstSlice = (regColorView & 0x7FF);\n\tuint32 viewNumSlices = ((regColorView >> 13) & 0x7FF) - viewFirstSlice + 1;\n\tif (viewNumSlices != 1)\n\t{\n\t\tdebug_printf(\"viewNumSlices is not 1! (%d)\\n\", viewNumSlices);\n\t}\n\tuint32 colorBufferPitch = (((regColorSize >> 0) & 0x3FF) + 1);\n\tcolorBufferPitch <<= 3;\n\tuint32 pitchHeight = (((regColorSize >> 10) & 0xFFFFF) + 1);\n\tpitchHeight <<= 6;\n\tuint32 colorBufferHeight = pitchHeight / colorBufferPitch;\n\tuint32 colorBufferWidth = colorBufferPitch;\n\n\t// colorbuffer width/height has to be padded to 8/32 alignment but the actual resolution might be smaller\n\t// use the scissor box as a clue to figure out the original resolution if possible\n\tif(LatteGPUState.allowFramebufferSizeOptimization)\n\t{\n\t\tuint32 scissorBoxWidth = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_BR.get_BR_X();\n\t\tuint32 scissorBoxHeight = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_BR.get_BR_Y();\n\t\tif (((scissorBoxWidth + 7) & ~7) == colorBufferWidth)\n\t\t\tcolorBufferWidth = scissorBoxWidth;\n\t\tif (((colorBufferHeight + 31) & ~31) == colorBufferHeight)\n\t\t\tcolorBufferHeight = scissorBoxHeight;\n\t}\n\n\t// log resolution changes if the above heuristic takes effect\n\t// this is useful to find resolutions which need to be updated in gfx pack texture rules\n#if 0\n\tuint32 colorBufferHeight2 = pitchHeight / colorBufferPitch;\n\tstatic std::unordered_set<uint64> s_foundColorBufferResMappings;\n\tif (colorBufferPitch != colorBufferWidth || colorBufferHeight != colorBufferHeight2)\n\t{\n\t\t// only log unique, source and dest resolution. Encode into a key with 16 bits per component\n\t\tuint64 resHash = (uint64)colorBufferWidth | ((uint64)colorBufferHeight << 16) | ((uint64)colorBufferPitch << 32) | ((uint64)colorBufferHeight2 << 48);\n\t\tif( !s_foundColorBufferResMappings.contains(resHash) )\n\t\t{\n\t\t\ts_foundColorBufferResMappings.insert(resHash);\n\t\t\tcemuLog_log(LogType::Force, \"[COLORBUFFER-DBG] Using res {}x{} instead of {}x{}\", colorBufferWidth, colorBufferHeight, colorBufferPitch, colorBufferHeight2);\n\t\t}\n\t}\n#endif\n\n\tbool colorBufferWasFound = false;\n\tsint32 viewFirstMip = 0; // todo\n\n\tcemu_assert_debug(viewNumSlices == 1);\n\n\tLatteTextureView* colorBufferView = LatteTextureViewLookupCache::lookupSliceEx(colorBufferPhysMem, colorBufferWidth, colorBufferHeight, colorBufferPitch, viewFirstMip, viewFirstSlice, colorBufferFormat, false);\n\n\tif (colorBufferView == nullptr)\n\t{\n\t\t// create color buffer view\n\t\tcolorBufferView = LatteTexture_CreateMapping(colorBufferPhysMem, 0, colorBufferWidth, colorBufferHeight, (viewFirstSlice + viewNumSlices), colorBufferPitch, colorBufferTileMode, colorBufferSwizzle>>8, viewFirstMip, 1, viewFirstSlice, viewNumSlices, (Latte::E_GX2SURFFMT)colorBufferFormat, (viewFirstSlice + viewNumSlices)>1? Latte::E_DIM::DIM_2D_ARRAY: Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, false, true);\n\t\tLatteGPUState.repeatTextureInitialization = true;\n\t\tcheckForTextureChanges = false;\n\t}\n\n\tif (colorBufferView->baseTexture->swizzle != colorBufferSwizzle)\n\t{\n\t\tcolorBufferView->baseTexture->lastRenderTargetSwizzle = colorBufferSwizzle;\n\t}\n\n\t// check for texture changes\n\tif (checkForTextureChanges)\n\t\tLatteTexture_UpdateDataToLatest(colorBufferView->baseTexture);\n\t// mark as used\n\tLatteTC_MarkTextureStillInUse(colorBufferView->baseTexture);\n\treturn colorBufferView;\n}\n\n// get mask of all used color buffers\nuint8 LatteMRT::GetActiveColorBufferMask(const LatteDecompilerShader* pixelShader, const LatteContextRegister& lcr)\n{\n\tconst uint32* regView = lcr.GetRawView();\n\n\tuint8 colorBufferMask = 0;\n\tfor (uint32 i = 0; i < 8; i++)\n\t{\n\t\tif (regView[mmCB_COLOR0_BASE + i] != MPTR_NULL)\n\t\t\tcolorBufferMask |= (1 << i);\n\t}\n\t// check if color buffer output is active\n\tconst Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = lcr.CB_COLOR_CONTROL;\n\tuint32 colorBufferDisable = colorControlReg.get_SPECIAL_OP() == Latte::LATTE_CB_COLOR_CONTROL::E_SPECIALOP::DISABLE;\n\tif (colorBufferDisable)\n\t\treturn 0;\n\tcemu_assert_debug(colorControlReg.get_DEGAMMA_ENABLE() == false); // not supported\n\t// combine color buffer mask with pixel output mask from pixel shader\n\tcolorBufferMask &= (pixelShader ? pixelShader->pixelColorOutputMask : 0);\n\t// combine color buffer mask with color channel mask from mmCB_TARGET_MASK (disable render buffer if all colors are blocked)\n\tuint32 channelTargetMask = lcr.CB_TARGET_MASK.get_MASK();\n\tfor (uint32 i = 0; i < 8; i++)\n\t{\n\t\tif (((channelTargetMask >> (i * 4)) & 0xF) == 0)\n\t\t\tcolorBufferMask &= ~(1 << i);\n\t}\n\n\t// render targets smaller than the scissor size are not allowed\n\t// this fixes a few render issues in Cemu but we dont know if this matches HW behavior\n\tcemu_assert_debug(lcr.PA_SC_GENERIC_SCISSOR_TL.get_WINDOW_OFFSET_DISABLE() == true); // todo (not exposed by GX2 API)\n\tuint32 scissorAccessWidth = lcr.PA_SC_GENERIC_SCISSOR_BR.get_BR_X();\n\tuint32 scissorAccessHeight = lcr.PA_SC_GENERIC_SCISSOR_BR.get_BR_Y();\n\tfor (uint32 i = 0; i < 8; i++)\n\t{\n\t\tif( (colorBufferMask&(1<<i)) == 0 )\n\t\t\tcontinue;\n\t\t// get width/height\n\t\tuint32 regColorSize = regView[mmCB_COLOR0_SIZE + i];\n\t\tuint32 regColorInfo = regView[mmCB_COLOR0_INFO + i];\n\t\t// decode color buffer reg info\n\t\tuint32 colorBufferPitch = (((regColorSize >> 0) & 0x3FF) + 1);\n\t\tcolorBufferPitch <<= 3;\n\t\tuint32 pitchHeight = (((regColorSize >> 10) & 0xFFFFF) + 1);\n\t\tpitchHeight <<= 6;\n\t\tuint32 colorBufferHeight = pitchHeight / colorBufferPitch;\n\t\tuint32 colorBufferWidth = colorBufferPitch;\n\n\t\tif ((colorBufferWidth < (sint32)scissorAccessWidth) ||\n\t\t\t(colorBufferHeight < (sint32)scissorAccessHeight))\n\t\t{\n            // log this?\n\t\t\tcolorBufferMask &= ~(1<<i);\n\t\t}\n\n\t}\n\n\treturn colorBufferMask;\n}\n\n// returns true if depth/stencil buffer is used\nbool LatteMRT::GetActiveDepthBufferMask(const LatteContextRegister& lcr)\n{\n\tbool depthBufferMask = true;\n\t// if depth test is not used then detach the depth buffer\n\tbool depthEnable = lcr.DB_DEPTH_CONTROL.get_Z_ENABLE();\n\tbool stencilTestEnable = lcr.DB_DEPTH_CONTROL.get_STENCIL_ENABLE();\n\tbool backStencilEnable = lcr.DB_DEPTH_CONTROL.get_BACK_STENCIL_ENABLE();\n\n\tif (!depthEnable && !stencilTestEnable && !backStencilEnable)\n\t\tdepthBufferMask = false;\n\n\treturn depthBufferMask;\n}\n\nconst uint32 _colorBufferFormatBits[] =\n{\n\t0, // 0\n\t0x200, // 1\n\t0, // 2\n\t0, // 3\n\t0x100, // 4\n\t0x300, // 5\n\t0x400, // 6\n\t0x800, // 7\n};\n\nLatte::E_GX2SURFFMT LatteMRT::GetColorBufferFormat(const uint32 index, const LatteContextRegister& lcr)\n{\n\tcemu_assert_debug(index < Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS);\n\tuint32 regColorInfo = lcr.GetRawView()[mmCB_COLOR0_INFO + index];\n\tuint32 colorBufferFormat = (regColorInfo >> 2) & 0x3F; // base HW format\n\tuint32 numberType = (regColorInfo >> 12) & 7;\n\tcolorBufferFormat |= _colorBufferFormatBits[numberType];\n\treturn (Latte::E_GX2SURFFMT)colorBufferFormat;\n}\n\n// return GX2 format of current depth buffer\nLatte::E_GX2SURFFMT LatteMRT::GetDepthBufferFormat(const LatteContextRegister& lcr)\n{\n\tuint32 regDepthBufferInfo = lcr.GetRawView()[mmDB_DEPTH_INFO];\n\tswitch (regDepthBufferInfo & 7)\n\t{\n\tcase 1:\n\t\treturn Latte::E_GX2SURFFMT::D16_UNORM;\n\tcase 3:\n\t\treturn Latte::E_GX2SURFFMT::D24_S8_UNORM;\n\tcase 5:\n\t\treturn Latte::E_GX2SURFFMT::D24_S8_FLOAT;\n\tcase 6:\n\t\treturn Latte::E_GX2SURFFMT::D32_FLOAT;\n\tcase 7:\n\t\treturn Latte::E_GX2SURFFMT::D32_S8_FLOAT;\n\tdefault:\n\t\tdebug_printf(\"Invalid DB_DEPTH_INFO depthbuffer format (%d)\\n\", (regDepthBufferInfo & 7));\n\t\tbreak;\n\t}\n\treturn Latte::E_GX2SURFFMT::D16_UNORM;\n}\n\nbool LatteMRT::UpdateCurrentFBO()\n{\n\tcatchOpenGLError();\n\tsLatteRenderTargetState.rtUpdateListCount = 0;\n\t// combine color buffer mask with pixel output mask from pixel shader\n\tLatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();\n\tuint8 colorBufferMask = GetActiveColorBufferMask(pixelShader, LatteGPUState.contextNew);\n\tbool depthBufferMask = GetActiveDepthBufferMask(LatteGPUState.contextNew);\n\n\tbool hasResizedTexture = false; // set to true if any of the color buffers or the depth buffer reference a resized texture (via graphic pack texture rules)\n\tsLatteRenderTargetState.renderTargetIsResized = false;\n\t// real size\n\tLatteMRTQuad* rtRealSize = &sLatteRenderTargetState.currentRenderSize;\n\trtRealSize->width = 0;\n\trtRealSize->height = 0;\n\t// effective size (differs from real size only if graphic pack rules overwrite texture sizes)\n\tLatteMRTQuad* rtEffectiveSize = &sLatteRenderTargetState.currentEffectiveSize;\n\trtEffectiveSize->width = 0;\n\trtEffectiveSize->height = 0;\n\t// get scissor box\n\tcemu_assert_debug(LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_TL.get_WINDOW_OFFSET_DISABLE() == true); // todo (not exposed by GX2 API?)\n\tuint32 scissorX = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_TL.get_TL_X();\n\tuint32 scissorY = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_TL.get_TL_Y();\n\tuint32 scissorWidth = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_BR.get_BR_X() - scissorX;\n\tuint32 scissorHeight = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_BR.get_BR_Y() - scissorY;\n\tuint32 scissorAccessWidth = scissorX + scissorWidth;\n\tuint32 scissorAccessHeight = scissorY + scissorHeight;\n\t// color buffers\n\tfor (uint32 i = 0; i < Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS; i++)\n\t{\n\t\tif (((colorBufferMask)&(1 << i)) == 0)\n\t\t{\n\t\t\t// unbind\n\t\t\tSetColorAttachment(i, nullptr);\n\t\t\tcontinue;\n\t\t}\n\t\tLatteTextureView* colorAttachmentView = GetColorAttachmentTexture(i, true, true);\n\t\tSetColorAttachment(i, colorAttachmentView);\n\t\t// after the drawcall mark the texture as updated\n\t\tsLatteRenderTargetState.rtUpdateList[sLatteRenderTargetState.rtUpdateListCount] = colorAttachmentView;\n\t\tsLatteRenderTargetState.rtUpdateListCount++;\n\n\t\tsint32 colorAttachmentWidth, colorAttachmentHeight;\n\t\tcolorAttachmentView->baseTexture->GetSize(colorAttachmentWidth, colorAttachmentHeight, colorAttachmentView->firstMip);\n\n\t\t// set effective size\n\t\tsint32 effectiveWidth, effectiveHeight;\n\t\tcolorAttachmentView->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, colorAttachmentView->firstMip);\n\t\tif (rtEffectiveSize->width == 0 && rtEffectiveSize->height == 0)\n\t\t{\n\t\t\trtEffectiveSize->width = effectiveWidth;\n\t\t\trtEffectiveSize->height = effectiveHeight;\n\t\t}\n\t\telse if (rtEffectiveSize->width != effectiveWidth && rtEffectiveSize->height != effectiveHeight)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Color buffer size mismatch ({}x{}). Effective size: {}x{} Real size: {}x{} Mismatching texture: {:08x} {}x{} fmt {:04x}\", rtEffectiveSize->width, rtEffectiveSize->height, effectiveWidth, effectiveHeight, colorAttachmentView->baseTexture->width, colorAttachmentView->baseTexture->height, colorAttachmentView->baseTexture->physAddress, colorAttachmentView->baseTexture->width, colorAttachmentView->baseTexture->height, (uint32)colorAttachmentView->baseTexture->format);\n\t\t}\n\t\t// currently the first color attachment defines the size of the current render target\n\t\tif (rtRealSize->width == 0 && rtRealSize->height == 0)\n\t\t{\n\t\t\trtRealSize->width = colorAttachmentWidth;\n\t\t\trtRealSize->height = colorAttachmentHeight;\n\t\t}\n\n\t\tif (colorAttachmentView)\n\t\t\tcontinue;\n\t}\n\t// depth buffer\n\tif (depthBufferMask)\n\t{\n\t\tuint32 regDepthBuffer = LatteGPUState.contextRegister[mmDB_HTILE_DATA_BASE];\n\t\tuint32 regDepthSize = LatteGPUState.contextRegister[mmDB_DEPTH_SIZE];\n\t\tuint32 regDepthBufferInfo = LatteGPUState.contextRegister[mmDB_DEPTH_INFO];\n\n\t\t// get format and tileMode from info reg\n\t\tLatte::E_GX2SURFFMT depthBufferFormat = GetDepthBufferFormat(LatteGPUState.contextNew);\n\t\tLatte::E_HWTILEMODE depthBufferTileMode = (Latte::E_HWTILEMODE)((regDepthBufferInfo >> 15) & 0xF);\n\t\tMPTR depthBufferPhysMem = regDepthBuffer << 8;\n\n\t\tuint32 depthBufferPitch = (((regDepthSize >> 0) & 0x3FF) + 1);\n\t\tuint32 depthBufferHeight = ((((regDepthSize >> 10) & 0xFFFFF) + 1) / depthBufferPitch);\n\t\tdepthBufferPitch <<= 3;\n\t\tdepthBufferHeight <<= 3;\n\t\tuint32 depthBufferWidth = depthBufferPitch;\n\n\t\tif (depthBufferWidth < 2)\n\t\t{\n\t\t\tdebug_printf(\"depthBufferWidth has invalid value %d\\n\", depthBufferWidth);\n\t\t\tdepthBufferWidth = 2;\n\t\t}\n\t\tif (depthBufferHeight < 2)\n\t\t{\n\t\t\tdebug_printf(\"depthBufferHeight has invalid value %d\\n\", depthBufferHeight);\n\t\t\tdepthBufferHeight = 2;\n\t\t}\n\n\t\tbool blockDepthBuffer = false;\n\t\tif (scissorAccessWidth > depthBufferPitch || scissorAccessHeight > depthBufferHeight)\n\t\t{\n\t\t\tSetDepthAndStencilAttachment(nullptr, false);\n\t\t\tblockDepthBuffer = true;\n\t\t\t// set effective size\n\t\t\tif( rtEffectiveSize->width == 0 && rtEffectiveSize->height == 0 )\n\t\t\t{\n\t\t\t\trtEffectiveSize->width = rtRealSize->width;\n\t\t\t\trtEffectiveSize->height = rtRealSize->height;\n\t\t\t}\n\t\t}\n\n\t\tif (blockDepthBuffer == false)\n\t\t{\n\t\t\tif (rtRealSize->width == 0)\n\t\t\t{\n\t\t\t\trtRealSize->width = depthBufferWidth;\n\t\t\t\trtRealSize->height = depthBufferHeight;\n\t\t\t}\n\t\t\tuint32 regDepthView = LatteGPUState.contextRegister[mmDB_DEPTH_VIEW];\n\t\t\tuint32 depthBufferViewFirstSlice = (regDepthView & 0x7FF);\n\t\t\tuint32 depthBufferViewNumSlices = ((regDepthView >> 13) & 0x7FF) - depthBufferViewFirstSlice + 1;\n\t\t\tcemu_assert_debug(depthBufferViewNumSlices == 1); // binding multiple layers makes no sense?\n\n\t\t\tuint32 depthBufferSwizzle = 0;\n\t\t\tif (Latte::TM_IsMacroTiled(depthBufferTileMode))\n\t\t\t{\n\t\t\t\tdepthBufferSwizzle = (depthBufferPhysMem >> 8) & 7;\n\t\t\t\tdepthBufferPhysMem = depthBufferPhysMem & ~(7 << 8);\n\t\t\t}\n\n\t\t\tif (depthBufferPhysMem != MPTR_NULL)\n\t\t\t{\n\t\t\t\tLatteTextureView* depthBufferView = LatteTextureViewLookupCache::lookupSliceEx(depthBufferPhysMem, depthBufferWidth, depthBufferHeight, depthBufferPitch, 0, depthBufferViewFirstSlice, depthBufferFormat, true);\n\t\t\t\tif (!depthBufferView)\n\t\t\t\t{\n\t\t\t\t\t// create new depth buffer view and if it doesn't exist then also create the texture\n\t\t\t\t\tdepthBufferView = LatteTexture_CreateMapping(depthBufferPhysMem, 0, depthBufferWidth, depthBufferHeight, depthBufferViewFirstSlice+1, depthBufferPitch, depthBufferTileMode, depthBufferSwizzle, 0, 1, depthBufferViewFirstSlice, 1, depthBufferFormat, depthBufferViewFirstSlice > 0 ? Latte::E_DIM::DIM_2D_ARRAY : Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, true, true);\n\t\t\t\t\tLatteGPUState.repeatTextureInitialization = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// check for texture changes\n\t\t\t\t\tLatteTexture_UpdateDataToLatest(depthBufferView->baseTexture);\n\t\t\t\t}\n\t\t\t\t// set effective size\n\t\t\t\tsint32 effectiveWidth, effectiveHeight;\n\t\t\t\tdepthBufferView->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, depthBufferView->firstMip);\n\t\t\t\tif (rtEffectiveSize->width == 0 && rtEffectiveSize->height == 0)\n\t\t\t\t{\n\t\t\t\t\trtEffectiveSize->width = effectiveWidth;\n\t\t\t\t\trtEffectiveSize->height = effectiveHeight;\n\t\t\t\t}\n\t\t\t\telse if (rtEffectiveSize->width > effectiveWidth && rtEffectiveSize->height > effectiveHeight)\n\t\t\t\t{\n\t\t\t\t\tif (_depthBufferSizeWarningCount < 100)\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"Depth buffer size too small. Effective size: {}x{} Real size: {}x{} Mismatching texture: {:08x} {}x{} fmt {:04x}\", effectiveWidth, effectiveHeight, depthBufferView->baseTexture->width, depthBufferView->baseTexture->height, depthBufferView->baseTexture->physAddress, depthBufferView->baseTexture->width, depthBufferView->baseTexture->height, (uint32)depthBufferView->baseTexture->format);\n\t\t\t\t\t\t_depthBufferSizeWarningCount++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tLatteTC_MarkTextureStillInUse(depthBufferView->baseTexture);\n\t\t\t\t// after the drawcall mark the texture as updated\n\t\t\t\tsLatteRenderTargetState.rtUpdateList[sLatteRenderTargetState.rtUpdateListCount] = depthBufferView;\n\t\t\t\tsLatteRenderTargetState.rtUpdateListCount++;\n\t\t\t\tSetDepthAndStencilAttachment(depthBufferView, depthBufferView->baseTexture->hasStencil);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tSetDepthAndStencilAttachment(nullptr, false);\n\t\t}\n\t}\n\telse\n\t{\n\t\tSetDepthAndStencilAttachment(nullptr, false);\n\t}\n\tcatchOpenGLError();\n\tif (colorBufferMask || depthBufferMask)\n\t{\n\t\thasValidFramebufferAttached = true;\n\t}\n\telse\n\t{\n\t\thasValidFramebufferAttached = false;\n\t\treturn true;\n\t}\n\tif( rtEffectiveSize->width != rtRealSize->width || rtEffectiveSize->height != rtRealSize->height )\n\t{\n\t\t//debug_printf(\"RenderTarget rescaled. Real: %dx%d Resized: %dx%d\\n\", rtRealSize->width, rtRealSize->height, rtEffectiveSize->width, rtEffectiveSize->height);\n\t\tsLatteRenderTargetState.renderTargetIsResized = true;\n\t}\n\tif (sLatteRenderTargetState.currentEffectiveSize.width == 0)\n\t{\n\t\tdebug_printf(\"Render target effective size is 0. May indicate a bug in Cemu or invalid color/depth buffers\\n\");\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n// return a vec4 with xy being the scale ratio for render target extend and zw being the virtual viewport dimensions\nvoid LatteMRT::GetCurrentFragCoordScale(float* coordScale)\n{\n\tif (sLatteRenderTargetState.renderTargetIsResized)\n\t{\n\t\tcoordScale[0] = (float)sLatteRenderTargetState.currentRenderSize.width / (float)sLatteRenderTargetState.currentEffectiveSize.width;\n\t\tcoordScale[1] = (float)sLatteRenderTargetState.currentRenderSize.height / (float)sLatteRenderTargetState.currentEffectiveSize.height;\n\t\tcoordScale[2] = sLatteRenderTargetState.currentGuestViewport.width;\n\t\tcoordScale[3] = sLatteRenderTargetState.currentGuestViewport.height;\n\t}\n\telse\n\t{\n\t\tcoordScale[0] = 1.0f;\n\t\tcoordScale[1] = 1.0f;\n\t\tcoordScale[2] = sLatteRenderTargetState.currentGuestViewport.width;\n\t\tcoordScale[3] = sLatteRenderTargetState.currentGuestViewport.height;\n\t}\n}\n\nvoid LatteMRT::GetVirtualViewportDimensions(sint32& width, sint32& height)\n{\n\twidth = sLatteRenderTargetState.currentGuestViewport.width;\n\theight = sLatteRenderTargetState.currentGuestViewport.height;\n}\n\n// flag all FBO textures as updated via GPU\n// also handle texture readback\nvoid LatteRenderTarget_trackUpdates()\n{\n\t// after the drawcall, mark the render target textures as dynamically updated\n\tuint64 eventCounter = LatteTexture_getNextUpdateEventCounter();\n\tfor (sint32 i = 0; i < sLatteRenderTargetState.rtUpdateListCount; i++)\n\t{\n\t\tLatteTextureView* texView = sLatteRenderTargetState.rtUpdateList[i];\n\t\tLatteTexture* baseTexture = texView->baseTexture;\n\t\tLatteTexture_TrackTextureGPUWrite(baseTexture, texView->firstSlice, texView->firstMip, eventCounter);\n\t\t// texture readback\n\t\tif (baseTexture->enableReadback)\n\t\t{\n\t\t\tLatteTextureReadback_Initate(texView);\n\t\t}\n\t}\n}\n\nvoid LatteRenderTarget_itHLESwapScanBuffer()\n{\n\tperformanceMonitor.cycle[performanceMonitor.cycleIndex].frameCounter++;\n\tif(LatteGPUState.frameCounter > 5)\n\t\tperformanceMonitor.gpuTime_frameTime.endMeasuring();\n\tLattePerformanceMonitor_frameEnd();\n\tLatteGPUState.frameCounter++;\n\tg_renderer->SwapBuffers(true, true);\n\n\tcatchOpenGLError();\n\tperformanceMonitor.gpuTime_frameTime.beginMeasuring();\n\n\tLatteTC_CleanupUnusedTextures();\n\tLatteDraw_cleanupAfterFrame();\n\tLatteQuery_CancelActiveGPU7Queries();\n\tLatteBufferCache_notifySwapTVScanBuffer();\n\tLattePerformanceMonitor_frameBegin();\n}\n\nvoid LatteRenderTarget_applyTextureColorClear(LatteTexture* texture, uint32 sliceIndex, uint32 mipIndex, float r, float g, float b, float a, uint64 eventCounter)\n{\n\tif (texture->isDepth)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Unsupported clear depth as color\");\n\t}\n\telse\n\t{\n\t\tg_renderer->texture_clearColorSlice(texture, sliceIndex, mipIndex, r, g, b, a);\n\t\tLatteTexture_MarkDynamicTextureAsChanged(texture->baseView, sliceIndex, mipIndex, eventCounter);\n\t}\n}\n\nvoid LatteRenderTarget_applyTextureDepthClear(LatteTexture* texture, uint32 sliceIndex, uint32 mipIndex, bool hasDepthClear, bool hasStencilClear, float depthValue, uint8 stencilValue, uint64 eventCounter)\n{\n\tif(texture->isDepth)\n\t{\n\t\tg_renderer->texture_clearDepthSlice(texture, sliceIndex, mipIndex, hasDepthClear, hasStencilClear, depthValue, stencilValue);\n\t}\n\telse\n\t{\n\t\t// clearing a color texture using depth clear\n\t\tif (hasStencilClear)\n\t\t\treturn; // operation likely not intended as a color clear\n\t\t//cemu_assert_debug(!hasStencilClear);\n\t\tif (hasDepthClear)\n\t\t{\n\t\t\tg_renderer->texture_clearColorSlice(texture, sliceIndex, mipIndex, depthValue, depthValue, depthValue, depthValue);\n\t\t}\n\n\t}\n\tLatteTexture_MarkDynamicTextureAsChanged(texture->baseView, sliceIndex, mipIndex, eventCounter);\n}\n\nvoid LatteRenderTarget_itHLEClearColorDepthStencil(uint32 clearMask,\n\t\t\t\t\t\t\t\t\t\t\t\t   MPTR colorBufferMPTR, Latte::E_GX2SURFFMT colorBufferFormat, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferPitch, uint32 colorBufferViewFirstSlice, uint32 colorBufferViewNumSlice,\n\t\t\t\t\t\t\t\t\t\t\t\t   MPTR depthBufferMPTR, Latte::E_GX2SURFFMT depthBufferFormat, Latte::E_HWTILEMODE depthBufferTileMode, sint32 depthBufferWidth, sint32 depthBufferHeight, sint32 depthBufferPitch, sint32 depthBufferViewFirstSlice, sint32 depthBufferViewNumSlice,\n\t\t\t\t\t\t\t\t\t\t\t\t   float r, float g, float b, float a, float clearDepth, uint32 clearStencil)\n{\n\tuint32 depthBufferMipIndex = 0; // todo\n\tuint32 colorBufferMipIndex = 0; // todo\n\n\tbool hasColorClear = (clearMask & 1);\n\tbool hasDepthClear = (clearMask & 2);\n\tbool hasStencilClear = (clearMask & 4);\n\n\t// extract swizzle offset from pointer\n\tuint32 colorBufferSwizzle = 0;\n\tuint32 depthBufferSwizzle = 0;\n\tif (Latte::TM_IsMacroTiled(colorBufferTilemode))\n\t{\n\t\tcolorBufferSwizzle = (colorBufferMPTR >> 8) & 7;\n\t\tcolorBufferMPTR = colorBufferMPTR & ~(7 << 8);\n\t}\n\tif (Latte::TM_IsMacroTiled(depthBufferTileMode))\n\t{\n\t\tdepthBufferSwizzle = (depthBufferMPTR >> 8) & 7;\n\t\tdepthBufferMPTR = depthBufferMPTR & ~(7 << 8);\n\t}\n\n\tcemu_assert_debug(colorBufferViewNumSlice <= 1);\n\tcemu_assert_debug(depthBufferViewNumSlice <= 1);\n\n\t// clear color buffer (if flag set)\n\tuint64 eventCounter = LatteTexture_getNextUpdateEventCounter();\n\tif ((clearMask & 1) != 0 && colorBufferMPTR != MPTR_NULL && colorBufferWidth > 0 && colorBufferHeight > 0)\n\t{\n\t\t// clear color\n\t\tsint32 searchIndex = 0;\n\t\tbool targetFound = false;\n\t\twhile (true)\n\t\t{\n\t\t\tLatteTextureView* colorView = LatteTC_LookupTextureByData(colorBufferMPTR, colorBufferWidth, colorBufferHeight, colorBufferPitch, 0, 1, colorBufferViewFirstSlice, 1, &searchIndex);\n\t\t\tif (!colorView)\n\t\t\t\tbreak;\n\t\t\tif (Latte::GetFormatBits(colorBufferFormat) != Latte::GetFormatBits(colorView->baseTexture->format))\n\t\t\t\tcontinue;\n\n\t\t\tif (colorView->baseTexture->pitch == colorBufferPitch && colorView->baseTexture->height == colorBufferHeight)\n\t\t\t\ttargetFound = true;\n\n\t\t\tLatteRenderTarget_applyTextureColorClear(colorView->baseTexture, colorBufferViewFirstSlice, colorBufferMipIndex, r, g, b, a, eventCounter);\n\n\t\t}\n\t\tif (targetFound == false)\n\t\t{\n\t\t\t// create new texture with matching format\n\t\t\tcemu_assert_debug(colorBufferViewNumSlice <= 1);\n\t\t\tLatteTextureView* newColorView = LatteTexture_CreateMapping(colorBufferMPTR, MPTR_NULL, colorBufferWidth, colorBufferHeight, colorBufferViewFirstSlice+1, colorBufferPitch, colorBufferTilemode, colorBufferSwizzle, 0, 1, colorBufferViewFirstSlice, 1, colorBufferFormat, colorBufferViewFirstSlice > 0 ? Latte::E_DIM::DIM_2D_ARRAY : Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, false);\n\t\t\tLatteRenderTarget_applyTextureColorClear(newColorView->baseTexture, colorBufferViewFirstSlice, colorBufferMipIndex, r, g, b, a, eventCounter);\n\t\t}\n\t}\n\t// clear depth or stencil buffer (if flag set)\n\tif ((hasDepthClear || hasStencilClear) && depthBufferMPTR != MPTR_NULL)\n\t{\n\t\tstd::vector<LatteTexture*> list_depthClearTextures;\n\t\tLatteTC_LookupTexturesByPhysAddr(depthBufferMPTR, list_depthClearTextures);\n\t\tbool foundMatchingDepthBuffer = false;\n\t\t// todo - support for clearing depth mips?\n\t\tcemu_assert_debug(depthBufferViewNumSlice == 1);\n\n\t\tfor (auto& texItr : list_depthClearTextures)\n\t\t{\n\t\t\t// only clear depth buffers if they are smaller\n\t\t\tif (texItr->pitch > depthBufferPitch)\n\t\t\t\tcontinue;\n\t\t\tif (depthBufferViewFirstSlice >= texItr->depth)\n\t\t\t\tcontinue; // slice out of range\n\n\t\t\tif (texItr->pitch == depthBufferPitch && texItr->height == depthBufferHeight)\n\t\t\t\tfoundMatchingDepthBuffer = true;\n\n\t\t\t// todo - calculate actual sliceIndex and mipIndex since the textures in list_depthClearTextures dont necessarily share the same base\n\t\t\tLatteRenderTarget_applyTextureDepthClear(texItr, depthBufferViewFirstSlice, depthBufferMipIndex, hasDepthClear, hasStencilClear, clearDepth, clearStencil, eventCounter);\n\t\t}\n\n\t\tif (foundMatchingDepthBuffer == false)\n\t\t{\n\t\t\tLatteTextureView* newDepthBufferView = LatteMRT_CreateDepthBuffer(depthBufferMPTR, depthBufferWidth, depthBufferHeight, depthBufferPitch, depthBufferTileMode, (Latte::E_GX2SURFFMT)depthBufferFormat, depthBufferSwizzle, depthBufferViewFirstSlice);\n\t\t\tLatteRenderTarget_applyTextureDepthClear(newDepthBufferView->baseTexture, depthBufferViewFirstSlice, depthBufferMipIndex, hasDepthClear, hasStencilClear, clearDepth, clearStencil, eventCounter);\n\t\t}\n\t}\n}\n\nsint32 _currentOutputImageWidth = 0;\nsint32 _currentOutputImageHeight = 0;\n\nvoid LatteRenderTarget_getScreenImageArea(sint32* x, sint32* y, sint32* width, sint32* height, sint32* fullWidth, sint32* fullHeight, bool padView)\n{\n\tint w, h;\n\tif(padView && WindowSystem::IsPadWindowOpen())\n\t\tWindowSystem::GetPadWindowPhysSize(w, h);\n\telse\n\t\tWindowSystem::GetWindowPhysSize(w, h);\n\n\tsint32 scaledOutputX;\n\tsint32 scaledOutputY;\n\tif (GetConfig().fullscreen_scaling == kKeepAspectRatio)\n\t{\n\t\t// calculate maximum possible resolution with intact aspect ratio\n\t\tscaledOutputX = w;\n\t\tscaledOutputY = _currentOutputImageHeight * w / std::max(_currentOutputImageWidth, 1);\n\t\tif (scaledOutputY > h)\n\t\t{\n\t\t\tscaledOutputX = _currentOutputImageWidth * h / std::max(_currentOutputImageHeight, 1);\n\t\t\tscaledOutputY = h;\n\t\t}\n\t}\n\telse\n\t{\n\t\tscaledOutputX = w;\n\t\tscaledOutputY = h;\n\t}\n\n\t*x = (w - scaledOutputX) / 2;\n\t*y = (h - scaledOutputY) / 2;\n\t*width = scaledOutputX;\n\t*height = scaledOutputY;\n\tif (fullWidth)\n\t\t*fullWidth = w;\n\tif (fullHeight)\n\t\t*fullHeight = h;\n}\n\nvoid LatteRenderTarget_copyToBackbuffer(LatteTextureView* textureView, bool isPadView)\n{\n\t// make sure texture is updated to latest data in cache\n\tLatteTexture_UpdateDataToLatest(textureView->baseTexture);\n\t// mark source texture as still in use\n\tLatteTC_MarkTextureStillInUse(textureView->baseTexture);\n\n\tsint32 effectiveWidth, effectiveHeight;\n\ttextureView->baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, 0);\n\t_currentOutputImageWidth = effectiveWidth;\n\t_currentOutputImageHeight = effectiveHeight;\n\n\tsint32 imageX, imageY;\n\tsint32 imageWidth, imageHeight;\n\tsint32 fullscreenWidth, fullscreenHeight;\n\n\tLatteRenderTarget_getScreenImageArea(&imageX, &imageY, &imageWidth, &imageHeight, &fullscreenWidth, &fullscreenHeight, isPadView);\n\n\tbool clearBackground = false;\n\tif (imageWidth != fullscreenWidth || imageHeight != fullscreenHeight)\n\t\tclearBackground = true;\n\n\tconst bool renderUpsideDown = ActiveSettings::RenderUpsideDownEnabled();\n\t// force disable bicubic scaling if output resolution is equal/smaller than input resolution\n\tconst bool downscaling = (imageWidth <= effectiveWidth || imageHeight <= effectiveHeight);\n\t// check for graphic pack shaders\n\tRendererOutputShader* shader = nullptr;\n\tLatteTextureView::MagFilter filter = LatteTextureView::MagFilter::kLinear;\n\tfor(const auto& gp : GraphicPack2::GetActiveGraphicPacks())\n\t{\n\t\tif(downscaling)\n\t\t{\n\t\t\tshader = gp->GetDownscalingShader(renderUpsideDown);\n\t\t\tif (shader)\n\t\t\t{\n\t\t\t\tfilter = gp->GetDownscalingMagFilter();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tshader = gp->GetUpscalingShader(renderUpsideDown);\n\t\t\tif (shader)\n\t\t\t{\n\t\t\t\tfilter = gp->GetUpscalingMagFilter();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tshader = gp->GetOuputShader(renderUpsideDown);\n\t\tif (shader)\n\t\t{\n\t\t\tfilter = downscaling ? gp->GetDownscalingMagFilter() : gp->GetUpscalingMagFilter();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (shader == nullptr)\n\t{\n\t\tsint32 scaling_filter = downscaling ? GetConfig().downscale_filter : GetConfig().upscale_filter;\n\n\t\tif (scaling_filter == kLinearFilter)\n\t\t{\n\t\t\tif(renderUpsideDown)\n\t\t\t\tshader = RendererOutputShader::s_copy_shader_ud;\n\t\t\telse\n\t\t\t\tshader = RendererOutputShader::s_copy_shader;\n\n\t\t\tfilter = LatteTextureView::MagFilter::kLinear;\n\t\t}\n\t\telse if (scaling_filter == kBicubicFilter)\n\t\t{\n\t\t\tif (renderUpsideDown)\n\t\t\t\tshader = RendererOutputShader::s_bicubic_shader_ud;\n\t\t\telse\n\t\t\t\tshader = RendererOutputShader::s_bicubic_shader;\n\n\t\t\tfilter = LatteTextureView::MagFilter::kLinear;\n\t\t}\n\t\telse if (scaling_filter == kBicubicHermiteFilter)\n\t\t{\n\t\t\tif (renderUpsideDown)\n\t\t\t\tshader = RendererOutputShader::s_hermit_shader_ud;\n\t\t\telse\n\t\t\t\tshader = RendererOutputShader::s_hermit_shader;\n\n\t\t\tfilter = LatteTextureView::MagFilter::kLinear;\n\t\t}\n\t\telse if (scaling_filter == kNearestNeighborFilter)\n\t\t{\n\t\t\tif (renderUpsideDown)\n\t\t\t\tshader = RendererOutputShader::s_copy_shader_ud;\n\t\t\telse\n\t\t\t\tshader = RendererOutputShader::s_copy_shader;\n\n\t\t\tfilter = LatteTextureView::MagFilter::kNearestNeighbor;\n\t\t}\n\t}\n\tcemu_assert(shader);\n\tg_renderer->DrawBackbufferQuad(textureView, shader, filter==LatteTextureView::MagFilter::kLinear, imageX, imageY, imageWidth, imageHeight, isPadView, clearBackground);\n\tg_renderer->HandleScreenshotRequest(textureView, isPadView);\n\tif (!g_renderer->ImguiBegin(!isPadView))\n\t\treturn;\n\tswkbd_render(!isPadView);\n\tnn::erreula::render(!isPadView);\n\tLatteOverlay_render(isPadView);\n\tg_renderer->ImguiEnd();\n}\n\nvoid LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uint32 colorBufferWidth, uint32 colorBufferHeight, uint32 colorBufferSliceIndex, uint32 colorBufferFormat, uint32 colorBufferPitch, Latte::E_HWTILEMODE colorBufferTilemode, uint32 colorBufferSwizzle, uint32 renderTarget)\n{\n\tcemu_assert_debug(colorBufferSliceIndex == 0); // todo - support for non-zero slice\n\tLatteTextureView* texView = LatteTC_GetTextureSliceViewOrTryCreate(colorBufferPtr, MPTR_NULL, (Latte::E_GX2SURFFMT)colorBufferFormat, colorBufferTilemode, colorBufferWidth, colorBufferHeight, 1, colorBufferPitch, colorBufferSwizzle, 0, 0, true);\n\tif (!texView)\n\t{\n\t\treturn;\n\t}\n\n\tauto getVPADScreenActive = [](size_t n) -> std::pair<bool, bool> {\n\t\tauto controller = InputManager::instance().get_vpad_controller(n);\n\t\tif (!controller)\n\t\t\treturn {false,false};\n\t\tauto pressed = controller->is_screen_active();\n\t\tauto toggle = controller->is_screen_active_toggle();\n\t\treturn {pressed && !toggle, pressed && toggle};\n\t};\n\n\tconst bool tabPressed = WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::TAB);\n\tconst bool ctrlPressed = WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::LCONTROL);\n\tconst auto [vpad0Active, vpad0Toggle] = getVPADScreenActive(0);\n\tconst auto [vpad1Active, vpad1Toggle] = getVPADScreenActive(1);\n\n\tconst bool altScreenRequested = (!ctrlPressed && tabPressed) || vpad0Active || vpad1Active;\n\tconst bool togglePressed = (ctrlPressed && tabPressed) || vpad0Toggle || vpad1Toggle;\n\tstatic bool togglePressedLast = false;\n\n\tbool& isDRCPrimary = LatteGPUState.isDRCPrimary;\n\n\tif(togglePressed && !togglePressedLast)\n\t\tisDRCPrimary = !isDRCPrimary;\n\ttogglePressedLast = togglePressed;\n\n\tbool showDRC = swkbd_hasKeyboardInputHook() == false && (isDRCPrimary ^ altScreenRequested);\n\n\tif ((renderTarget & RENDER_TARGET_DRC) && g_renderer->IsPadWindowActive())\n\t\tLatteRenderTarget_copyToBackbuffer(texView, true);\n\tif (((renderTarget & RENDER_TARGET_TV) && !showDRC) || ((renderTarget & RENDER_TARGET_DRC) && showDRC))\n\t\tLatteRenderTarget_copyToBackbuffer(texView, false);\n}\n\n\n\n// returns the current size of the virtual viewport (not the same as effective size, which can be influenced by texture rules)\nvoid LatteRenderTarget_GetCurrentVirtualViewportSize(sint32* viewportWidth, sint32* viewportHeight)\n{\n\t*viewportWidth = sLatteRenderTargetState.currentGuestViewport.width;\n\t*viewportHeight = sLatteRenderTargetState.currentGuestViewport.height;\n}\n\nvoid LatteRenderTarget_updateViewport()\n{\n\tfloat vpWidth = LatteGPUState.contextNew.PA_CL_VPORT_XSCALE.get_SCALE() / 0.5f;\n\tfloat vpX = LatteGPUState.contextNew.PA_CL_VPORT_XOFFSET.get_OFFSET() - LatteGPUState.contextNew.PA_CL_VPORT_XSCALE.get_SCALE();\n\tfloat vpHeight = LatteGPUState.contextNew.PA_CL_VPORT_YSCALE.get_SCALE() / -0.5f;\n\tfloat vpY = LatteGPUState.contextNew.PA_CL_VPORT_YOFFSET.get_OFFSET() + LatteGPUState.contextNew.PA_CL_VPORT_YSCALE.get_SCALE();\n\n\tbool halfZ = LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_DX_CLIP_SPACE_DEF();\n\n\t// calculate near/far\n\tfloat farZ;\n\tfloat nearZ;\n\tfloat s = LatteGPUState.contextNew.PA_CL_VPORT_ZSCALE.get_SCALE();\n\tfloat b = LatteGPUState.contextNew.PA_CL_VPORT_ZOFFSET.get_OFFSET();\n\tif (halfZ == false)\n\t{\n\t\tfarZ = s + b;\n\t\tnearZ = b - s;\n\t}\n\telse\n\t{\n\t\tfarZ = s + b;\n\t\tnearZ = b;\n\t}\n\n\tsLatteRenderTargetState.currentGuestViewport.width = vpWidth;\n\tsLatteRenderTargetState.currentGuestViewport.height = vpHeight;\n\tif (sLatteRenderTargetState.renderTargetIsResized)\n\t{\n\t\tvpX *= ((float)sLatteRenderTargetState.currentEffectiveSize.width / (float)sLatteRenderTargetState.currentRenderSize.width);\n\t\tvpY *= ((float)sLatteRenderTargetState.currentEffectiveSize.height / (float)sLatteRenderTargetState.currentRenderSize.height);\n\t\tvpWidth *= ((float)sLatteRenderTargetState.currentEffectiveSize.width / (float)sLatteRenderTargetState.currentRenderSize.width);\n\t\tvpHeight *= ((float)sLatteRenderTargetState.currentEffectiveSize.height / (float)sLatteRenderTargetState.currentRenderSize.height);\n\t}\n\tg_renderer->renderTarget_setViewport(vpX, vpY, vpWidth, vpHeight, nearZ, farZ, halfZ);\n}\n\nvoid LatteRenderTarget_updateScissorBox()\n{\n\t// update scissor box\n\tuint32 scissorX = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_TL.get_TL_X();\n\tuint32 scissorY = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_TL.get_TL_Y();\n\tuint32 scissorWidth = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_BR.get_BR_X() - scissorX;\n\tuint32 scissorHeight = LatteGPUState.contextNew.PA_SC_GENERIC_SCISSOR_BR.get_BR_Y() - scissorY;\n\tif( sLatteRenderTargetState.renderTargetIsResized )\n\t{\n\t\tscissorX = (sint32)((float)scissorX * ((float)sLatteRenderTargetState.currentEffectiveSize.width / (float)sLatteRenderTargetState.currentRenderSize.width));\n\t\tscissorY = (sint32)((float)scissorY * ((float)sLatteRenderTargetState.currentEffectiveSize.height / (float)sLatteRenderTargetState.currentRenderSize.height));\n\t\tscissorWidth = (sint32)((float)scissorWidth * ((float)sLatteRenderTargetState.currentEffectiveSize.width / (float)sLatteRenderTargetState.currentRenderSize.width));\n\t\tscissorHeight = (sint32)((float)scissorHeight * ((float)sLatteRenderTargetState.currentEffectiveSize.height / (float)sLatteRenderTargetState.currentRenderSize.height));\n\t}\n\n\tif( scissorX != prevScissorX || scissorY != prevScissorY || scissorWidth != prevScissorWidth || scissorHeight != prevScissorHeight )\n\t{\n\t\tg_renderer->renderTarget_setScissor(scissorX, scissorY, scissorWidth, scissorHeight);\n\t\tprevScissorX = scissorX;\n\t\tprevScissorY = scissorY;\n\t\tprevScissorWidth = scissorWidth;\n\t\tprevScissorHeight = scissorHeight;\n\t}\n}\n\nvoid LatteRenderTarget_unloadAll()\n{\n\tif (g_emptyFBO)\n\t{\n\t\tLatteMRT::DeleteCachedFBO(g_emptyFBO);\n\t\tg_emptyFBO = nullptr;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteRingBuffer.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteRingBuffer.h\"\n\nLatteRingBuffer_t* LatteRingBuffer_create(uint8* data, uint32 size)\n{\n\tLatteRingBuffer_t* rb = (LatteRingBuffer_t*)malloc(sizeof(LatteRingBuffer_t));\n\trb->data = data;\n\trb->size = size;\n\trb->writeIndex = 0;\n\treturn rb;\n}\n\nuint8* LatteRingBuffer_allocate(LatteRingBuffer_t* rb, sint32 size, sint32 alignment)\n{\n#ifdef CEMU_DEBUG_ASSERT\n\tcemu_assert_debug(size < rb->size);\n#endif\n\t// align\n\trb->writeIndex = (rb->writeIndex + alignment - 1)&~(alignment-1);\n\t// handle wrap-around\n\tif ((rb->writeIndex + size) >= rb->size)\n\t\trb->writeIndex = 0;\n\t// allocate range\n\tuint8* data = rb->data + rb->writeIndex;\n\trb->writeIndex += size;\n\treturn data;\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteRingBuffer.h",
    "content": "\ntypedef struct\n{\n\tuint8* data;\n\tsint32 size;\n\tsint32 writeIndex;\n}LatteRingBuffer_t;\n\nLatteRingBuffer_t* LatteRingBuffer_create(uint8* data, uint32 size);\nuint8* LatteRingBuffer_allocate(LatteRingBuffer_t* rb, sint32 size, sint32 alignment);"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteShader.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\" // todo - remove dependency\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"HW/Latte/Core/Latte.h\"\n#include \"HW/Latte/Renderer/Renderer.h\"\n#include \"util/helpers/StringParser.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"util/containers/flat_hash_map.hpp\"\n#if ENABLE_METAL\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n#endif\n#include <cinttypes>\n\n// experimental new decompiler (WIP)\n#include \"util/Zir/EmitterGLSL/ZpIREmitGLSL.h\"\n#include \"util/Zir/Core/ZpIRDebug.h\"\n#include \"Cafe/HW/Latte/Transcompiler/LatteTC.h\"\n#include \"Cafe/HW/Latte/ShaderInfo/ShaderInfo.h\"\n\nstruct _ShaderHashCache\n{\n\tuint64 prevHash1;\n\tuint64 prevHash2;\n\tuint32* prevProgramCode;\n\tuint32 prevProgramSize;\n};\n\n_ShaderHashCache hashCacheVS = { 0 };\n_ShaderHashCache hashCacheGS = { 0 };\n_ShaderHashCache hashCachePS = { 0 };\n\nLatteFetchShader* _activeFetchShader = nullptr;\nLatteDecompilerShader* _activeVertexShader = nullptr;\nLatteDecompilerShader* _activeGeometryShader = nullptr;\nLatteDecompilerShader* _activePixelShader = nullptr;\n\n// runtime shader cache\nusing SHRC_CACHE_TYPE = ska::flat_hash_map<uint64, LatteDecompilerShader*>;\n\nSHRC_CACHE_TYPE sVertexShaders(512);\nSHRC_CACHE_TYPE sGeometryShaders(512);\nSHRC_CACHE_TYPE sPixelShaders(512);\n\nuint64 _shaderBaseHash_vs;\nuint64 _shaderBaseHash_gs;\nuint64 _shaderBaseHash_ps;\n\nstd::atomic_int g_compiled_shaders_total = 0;\nstd::atomic_int g_compiled_shaders_async = 0;\n\nLatteFetchShader* LatteSHRC_GetActiveFetchShader()\n{\n\treturn _activeFetchShader;\n}\n\nLatteDecompilerShader* LatteSHRC_GetActiveVertexShader()\n{\n\treturn _activeVertexShader;\n}\n\nLatteDecompilerShader* LatteSHRC_GetActiveGeometryShader()\n{\n\treturn _activeGeometryShader;\n}\n\nLatteDecompilerShader* LatteSHRC_GetActivePixelShader()\n{\n\treturn _activePixelShader;\n}\n\ninline ska::flat_hash_map<uint64, LatteDecompilerShader*>& LatteSHRC_GetCacheByType(LatteConst::ShaderType shaderType)\n{\n\tif (shaderType == LatteConst::ShaderType::Vertex)\n\t\treturn sVertexShaders;\n\telse if (shaderType == LatteConst::ShaderType::Geometry)\n\t\treturn sGeometryShaders;\n\tcemu_assert_debug(shaderType == LatteConst::ShaderType::Pixel);\n\treturn sPixelShaders;\n}\n\n// calculate hash from shader binary\n// this algorithm could be more efficient since we could leverage the fact that the size is always aligned to 8 byte\n// but since this is baked into the shader names used for gfx packs and shader caches we can't really change this\nvoid _calcShaderHashGeneric(uint32* programCode, uint32 programSize, uint64& outputHash1, uint64& outputHash2)\n{\n\toutputHash1 = 0;\n\toutputHash2 = 0;\n\tfor (uint32 i = 0; i < programSize / 4; i++)\n\t{\n\t\tuint32 temp = programCode[i];\n\t\toutputHash1 += (uint64)temp;\n\t\toutputHash2 ^= (uint64)temp;\n\t\toutputHash1 = (outputHash1 << 3) | (outputHash1 >> 61);\n\t\toutputHash2 = (outputHash2 >> 7) | (outputHash2 << 57);\n\t}\n}\n\nvoid _calculateShaderProgramHash(uint32* programCode, uint32 programSize, _ShaderHashCache* hashCache, uint64* outputHash1, uint64* outputHash2)\n{\n\tuint64 progHash1 = 0;\n\tuint64 progHash2 = 0;\n\tif (!programCode)\n\t{\n\t\thashCache->prevProgramCode = NULL;\n\t\thashCache->prevProgramSize = 0;\n\t\thashCache->prevHash1 = 0;\n\t\thashCache->prevHash2 = 0;\n\t}\n\telse if (hashCache->prevProgramCode != programCode || hashCache->prevProgramSize != programSize)\n\t{\n\t\t_calcShaderHashGeneric(programCode, programSize, progHash1, progHash2);\n\t\thashCache->prevProgramCode = programCode;\n\t\thashCache->prevProgramSize = programSize;\n\t\thashCache->prevHash1 = progHash1;\n\t\thashCache->prevHash2 = progHash2;\n\t}\n\telse\n\t{\n\t\tprogHash1 = hashCache->prevHash1;\n\t\tprogHash2 = hashCache->prevHash2;\n\t}\n\t*outputHash1 = progHash1;\n\t*outputHash2 = progHash2;\n}\n\nvoid LatteSHRC_ResetCachedShaderHash()\n{\n\thashCacheVS.prevProgramCode = 0;\n\thashCacheVS.prevProgramSize = 0;\n\thashCacheGS.prevProgramCode = 0;\n\thashCacheGS.prevProgramSize = 0;\n\thashCachePS.prevProgramCode = 0;\n\thashCachePS.prevProgramSize = 0;\n}\n\nLatteShaderPSInputTable _activePSImportTable;\n\nLatteShaderPSInputTable* LatteSHRC_GetPSInputTable()\n{\n\treturn &_activePSImportTable;\n}\n\nvoid LatteSHRC_RemoveFromCache(LatteDecompilerShader* shader)\n{\n\tbool removed = false;\n\tauto& cache = LatteSHRC_GetCacheByType(shader->shaderType);\n\t// remove from hashtable\n\tauto baseIt = cache.find(shader->baseHash);\n\tif (baseIt == cache.end())\n\t{\n\t\tcemu_assert_suspicious(); // deleting from runtime cache but shader is not present?\n\t}\n\telse if (baseIt->second == shader)\n\t{\n        cemu_assert_debug(baseIt->second == shader);\n        cache.erase(baseIt);\n\t\tif (shader->next)\n        {\n            cemu_assert_debug(shader->baseHash == shader->next->baseHash);\n            cache.emplace(shader->baseHash, shader->next);\n        }\n        shader->next = 0;\n\t\tremoved = true;\n\t}\n\telse\n\t{\n\t\t// remove from chain\n\t\tLatteDecompilerShader* shaderChain = baseIt->second;\n\t\twhile (shaderChain->next)\n\t\t{\n\t\t\tif (shaderChain->next == shader)\n\t\t\t{\n\t\t\t\tshaderChain->next = shaderChain->next->next;\n\t\t\t\tremoved = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tcemu_assert(removed);\n}\n\nvoid LatteSHRC_RemoveFromCacheByHash(uint64 shader_base_hash, uint64 shader_aux_hash, LatteConst::ShaderType type)\n{\n\tLatteDecompilerShader* shader = nullptr;\n\tif (type == LatteConst::ShaderType::Vertex)\n\t\tshader = LatteSHRC_FindVertexShader(shader_base_hash, shader_aux_hash);\n\telse if (type == LatteConst::ShaderType::Geometry)\n\t\tshader = LatteSHRC_FindGeometryShader(shader_base_hash, shader_aux_hash);\n\telse if (type == LatteConst::ShaderType::Pixel)\n\t\tshader = LatteSHRC_FindPixelShader(shader_base_hash, shader_aux_hash);\n\tif (shader)\n\t\tLatteSHRC_RemoveFromCache(shader);\n}\n\nvoid LatteShader_free(LatteDecompilerShader* shader)\n{\n\tLatteSHRC_RemoveFromCache(shader);\n\tif (shader->shader)\n\t\tdelete shader->shader;\n\tshader->shader = nullptr;\n\tdelete shader;\n}\n\nvoid LatteShader_CreatePSInputTable(LatteShaderPSInputTable* psInputTable, uint32* contextRegisters)\n{\n    // PS control\n\tuint32 psControl0 = contextRegisters[mmSPI_PS_IN_CONTROL_0];\n\tuint32 spi0_positionEnable = (psControl0 >> 8) & 1;\n\tuint32 spi0_positionCentroid = (psControl0 >> 9) & 1;\n\tcemu_assert_debug(spi0_positionCentroid == 0); // controls gl_FragCoord\n\tuint32 spi0_positionAddr = (psControl0 >> 10) & 0x1F; // controls gl_FragCoord\n\tuint32 spi0_paramGen = (psControl0 >> 15) & 0xF; // used for gl_PointCoords\n\tuint32 spi0_paramGenAddr = (psControl0 >> 19) & 0x7F;\n\tsint32 importIndex = 0;\n\n\t//cemu_assert_debug(((psControl0>>26)&3) == 1); // BARYC_SAMPLE_CNTL\n\t//cemu_assert_debug((psControl0&(1 << 28)) == 0); // PERSP_GRADIENT_ENA\n\t//cemu_assert_debug((psControl0&(1 << 29)) == 0); // LINEAR_GRADIENT_ENA\n\t// if LINEAR_GRADIENT_ENA_bit is enabled, the pixel shader accesses gl_ClipSize?\n\n\t// VS/GS parameters\n\tuint32 numPSInputs = contextRegisters[mmSPI_PS_IN_CONTROL_0] & 0x3F;\n\tuint64 key = 0;\n\n\tif (spi0_positionEnable)\n\t{\n\t\tkey += (uint64)spi0_positionAddr + 1;\n\t}\n\n\t// parameter gen\n\tif (spi0_paramGen != 0)\n\t{\n\t\tkey += std::rotr<uint64>(spi0_paramGen, 7);\n\t\tkey += std::rotr<uint64>(spi0_paramGenAddr, 3);\n\t\tpsInputTable->paramGen = spi0_paramGen;\n\t\tpsInputTable->paramGenGPR = spi0_paramGenAddr;\n\t}\n\telse\n\t{\n\t\tpsInputTable->paramGen = 0;\n\t}\n\n\t// semantic imports from vertex shader\n#ifdef CEMU_DEBUG_ASSERT\n\tuint8 semanticMask[256 / 8] = { 0 };\n#endif\n\tcemu_assert_debug(numPSInputs <= GPU7_PS_MAX_INPUTS);\n\tnumPSInputs = std::min<uint32>(numPSInputs, GPU7_PS_MAX_INPUTS);\n\n\tfor (uint32 f = 0; f < numPSInputs; f++)\n\t{\n\t\tuint32 psInputControl = contextRegisters[mmSPI_PS_INPUT_CNTL_0 + f];\n\t\tuint32 psSemanticId = (psInputControl & 0xFF);\n\n\t\tuint8 defaultValue = (psInputControl>>8)&3;\n\t\t// default:\n\t\t// 0 -> 0.0 0.0 0.0 0.0\n\t\t// 1 -> 0.0 0.0 0.0 1.0\n\t\t// 2 -> 1.0 1.0 1.0 0.0\n\t\t// 3 -> 1.0 1.0 1.0 1.0\n\t\tcemu_assert_debug(defaultValue <= 1);\n\n\t\tuint32 uknBits = psInputControl & ~((0xFF)|(0x3<<8) | (1 << 10) | (1 << 12));\n\t\tuknBits &= ~0x800; // FLAT_SHADE\n\t\t//cemu_assert_debug(uknBits == 0);\n\t\t//cemu_assert_debug(((psInputControl >> 11) & 1) == 0); // centroid\n\t\t//cemu_assert_debug(((psInputControl >> 17) & 1) == 0); // point sprite coord\n\t\tcemu_assert_debug(psSemanticId != 0xFF);\n\n\t\tkey += (uint64)psInputControl;\n\t\tkey = std::rotl<uint64>(key, 7);\n\t\tif (spi0_positionEnable && f == spi0_positionAddr)\n\t\t{\n\t\t\tpsInputTable->import[f].semanticId = LATTE_ANALYZER_IMPORT_INDEX_SPIPOSITION;\n\t\t\tpsInputTable->import[f].isFlat = false;\n\t\t\tpsInputTable->import[f].isNoPerspective = false;\n\t\t\tkey += (uint64)0x33;\n\t\t}\n\t\telse\n\t\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tif (semanticMask[psSemanticId >> 3] & (1 << (psSemanticId & 7)))\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"SemanticId already used\");\n\t\t\t}\n\t\t\tsemanticMask[psSemanticId >> 3] |= (1 << (psSemanticId & 7));\n#endif\n\n\t\t\tpsInputTable->import[f].semanticId = psSemanticId;\n\t\t\tpsInputTable->import[f].isFlat = (psInputControl&(1 << 10)) != 0;\n\t\t\tpsInputTable->import[f].isNoPerspective = (psInputControl&(1 << 12)) != 0;\n\t\t}\n\t}\n\tpsInputTable->key = key;\n\tpsInputTable->count = numPSInputs;\n}\n\n// both vertex and geometry/pixel shader depend on PS inputs\n// we prepare the PS import info in advance\nvoid LatteShader_UpdatePSInputs(uint32* contextRegisters)\n{\n\tLatteShader_CreatePSInputTable(&_activePSImportTable, contextRegisters);\n}\n\nvoid LatteShader_CreateRendererShader(LatteDecompilerShader* shader, bool compileAsync)\n{\n\tif (shader->hasError )\n\t{\n\t\tcemuLog_log(LogType::Force, \"Unable to compile shader {:016x}\", shader->baseHash);\n\t\treturn;\n\t}\n\n\tGraphicPack2::GP_SHADER_TYPE gpShaderType;\n\tRendererShader::ShaderType shaderType;\n\tif (shader->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n\t\tshaderType = RendererShader::ShaderType::kVertex;\n\t\tgpShaderType = GraphicPack2::GP_SHADER_TYPE::VERTEX;\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Geometry)\n\t{\n\t\tshaderType = RendererShader::ShaderType::kGeometry;\n\t\tgpShaderType = GraphicPack2::GP_SHADER_TYPE::GEOMETRY;\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t{\n\t\tshaderType = RendererShader::ShaderType::kFragment;\n\t\tgpShaderType = GraphicPack2::GP_SHADER_TYPE::PIXEL;\n\t}\n\n\t// check if a custom shader is present\n\tstd::string shaderSrc;\n\n\tconst std::string* customShaderSrc = GraphicPack2::FindCustomShaderSource(shader->baseHash, shader->auxHash, gpShaderType, g_renderer->GetType() == RendererAPI::Vulkan, g_renderer->GetType() == RendererAPI::Metal);\n\tif (customShaderSrc)\n\t{\n\t\tshaderSrc.assign(*customShaderSrc);\n\t\tshader->isCustomShader = true;\n\t}\n\telse\n\t\tshaderSrc.assign(shader->strBuf_shaderSource->c_str());\n\n\tif (shaderType == RendererShader::ShaderType::kVertex &&\n\t\t(shader->baseHash == 0x15bc7edf9de2ed30 || shader->baseHash == 0x83a697d61a3b9202 ||\n\t\t shader->baseHash == 0x97bc44a5028381c6 || shader->baseHash == 0x24838b84d15a1da1))\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Filtered shader to avoid AMD crash\");\n\t\tshader->shader = nullptr;\n\t\tshader->hasError = true;\n\t\treturn;\n\t}\n\n\t// create shader\n\tshader->shader = g_renderer->shader_create(shaderType, shader->baseHash, shader->auxHash, shaderSrc, true, shader->isCustomShader);\n\tif (shader->shader == nullptr)\n\t\tshader->hasError = true;\n\t// after renderer shader creation we can throw away any intermediate info\n\tLatteShader_CleanupAfterCompile(shader);\n}\n\nvoid LatteShader_FinishCompilation(LatteDecompilerShader* shader)\n{\n\tif (shader->hasError)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"LatteShader_finishCompilation(): Skipped because of error in shader {:x}\", shader->baseHash);\n\t\treturn;\n\t}\n\tshader->shader->WaitForCompiled();\n\n\tLatteShader_prepareSeparableUniforms(shader);\n\tLatteShader_CleanupAfterCompile(shader);\n}\n\nvoid LatteSHRC_RegisterShader(LatteDecompilerShader* shader, uint64 baseHash, uint64 auxHash)\n{\n\tauto& cache = LatteSHRC_GetCacheByType(shader->shaderType);\n\tshader->baseHash = baseHash;\n\tshader->auxHash = auxHash;\n\n\tauto it = cache.find(baseHash);\n\tif (it == cache.end())\n\t{\n\t\tshader->next = nullptr;\n\t\tcache.emplace(shader->baseHash, shader);\n\t}\n\telse\n\t{\n\t\tshader->next = it->second->next;\n\t\tit->second->next = shader;\n\t}\n}\n\nLatteDecompilerShader* LatteSHRC_GetFromChain(LatteDecompilerShader* baseShader, uint64 baseHash, uint64 auxHash)\n{\n\twhile (baseShader && baseShader->auxHash != auxHash)\n\t\tbaseShader = baseShader->next;\n\treturn baseShader;\n}\n\nLatteDecompilerShader* LatteSHRC_Get(SHRC_CACHE_TYPE& cache, uint64 baseHash, uint64 auxHash)\n{\n\tauto it = cache.find(baseHash);\n\tif (it == cache.end())\n\t\treturn nullptr;\n\tLatteDecompilerShader* baseShader = it->second;\n\tif (!baseShader)\n\t\treturn nullptr;\n\twhile (baseShader && baseShader->auxHash != auxHash)\n\t\tbaseShader = baseShader->next;\n\treturn baseShader;\n}\n\nLatteDecompilerShader* LatteSHRC_FindVertexShader(uint64 baseHash, uint64 auxHash)\n{\n\treturn LatteSHRC_Get(sVertexShaders, baseHash, auxHash);\n}\n\nLatteDecompilerShader* LatteSHRC_FindGeometryShader(uint64 baseHash, uint64 auxHash)\n{\n\treturn LatteSHRC_Get(sGeometryShaders, baseHash, auxHash);\n}\n\nLatteDecompilerShader* LatteSHRC_FindPixelShader(uint64 baseHash, uint64 auxHash)\n{\n\treturn LatteSHRC_Get(sPixelShaders, baseHash, auxHash);\n}\n\n// update the currently active fetch shader\nvoid LatteShaderSHRC_UpdateFetchShader()\n{\n\t_activeFetchShader = LatteFetchShader::FindByGPUState();\n}\n\nvoid LatteShader_CleanupAfterCompile(LatteDecompilerShader* shader)\n{\n\tif (shader->strBuf_shaderSource)\n\t{\n\t\tdelete shader->strBuf_shaderSource;\n\t\tshader->strBuf_shaderSource = nullptr;\n\t}\n}\n\nvoid LatteShader_DumpShader(uint64 baseHash, uint64 auxHash, LatteDecompilerShader* shader)\n{\n\tif (!ActiveSettings::DumpShadersEnabled())\n\t\treturn;\n\n\tconst char* suffix = \"\";\n\tif (shader->shaderType == LatteConst::ShaderType::Vertex)\n\t\tsuffix = \"vs\";\n\telse if (shader->shaderType == LatteConst::ShaderType::Geometry)\n\t\tsuffix = \"gs\";\n\telse if (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t\tsuffix = \"ps\";\n\n\tFileStream* fs = FileStream::createFile2(ActiveSettings::GetUserDataPath(\"dump/shaders/{:016x}_{:016x}_{}.txt\", baseHash, auxHash, suffix));\n\tif (fs)\n\t{\n\t\tif (shader->strBuf_shaderSource)\n\t\t\tfs->writeData(shader->strBuf_shaderSource->c_str(), shader->strBuf_shaderSource->getLen());\n\t\tdelete fs;\n\t}\n}\n\nvoid LatteShader_DumpRawShader(uint64 baseHash, uint64 auxHash, uint32 type, uint8* programCode, uint32 programLen)\n{\n\tif (!ActiveSettings::DumpShadersEnabled())\n\t\treturn;\n\tconst char* suffix = \"\";\n\tif (type == SHADER_DUMP_TYPE_FETCH)\n\t\tsuffix = \"fs\";\n\telse if (type == SHADER_DUMP_TYPE_VERTEX)\n\t\tsuffix = \"vs\";\n\telse if (type == SHADER_DUMP_TYPE_GEOMETRY)\n\t\tsuffix = \"gs\";\n\telse if (type == SHADER_DUMP_TYPE_PIXEL)\n\t\tsuffix = \"ps\";\n\telse if (type == SHADER_DUMP_TYPE_COPY)\n\t\tsuffix = \"copy\";\n\telse if (type == SHADER_DUMP_TYPE_COMPUTE)\n\t\tsuffix = \"compute\";\n\n\tFileStream* fs = FileStream::createFile2(ActiveSettings::GetUserDataPath(\"dump/shaders/{:016x}_{:016x}_{}.bin\", baseHash, auxHash, suffix));\n\tif (fs)\n\t{\n\t\tfs->writeData(programCode, programLen);\n\t\tdelete fs;\n\t}\n}\n\nvoid LatteSHRC_UpdateVSBaseHash(uint8* vertexShaderPtr, uint32 vertexShaderSize, bool usesGeometryShader)\n{\n\tuint32* vsProgramCode = (uint32*)vertexShaderPtr;\n\t// update hash from vertex shader data\n\tuint64 vsHash1 = 0;\n\tuint64 vsHash2 = 0;\n\t_calculateShaderProgramHash(vsProgramCode, vertexShaderSize, &hashCacheVS, &vsHash1, &vsHash2);\n\tuint64 vsHash = vsHash1 + vsHash2 + _activeFetchShader->key + _activePSImportTable.key + (usesGeometryShader ? 0x1111ULL : 0ULL);\n\n\tuint32 tmp = LatteGPUState.contextNew.PA_CL_VTE_CNTL.getRawValue() ^ 0x43F;\n\tvsHash += tmp;\n\n\tauto primitiveType = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();\n\t// TODO: include always in the hash in case of geometry shader or rect shader on Metal\n\tif (primitiveType == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS)\n\t{\n\t\tvsHash += 13ULL;\n\t}\n\telse if (primitiveType == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::POINTS)\n\t{\n\t\t// required for Vulkan since we have to write the pointsize in the shader\n\t\tvsHash += 71ULL;\n\t}\n\tvsHash += (LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] ? 21 : 0);\n\t// halfZ\n\tif (LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_DX_CLIP_SPACE_DEF())\n\t\tvsHash += 0x1537;\n\n#if ENABLE_METAL\n\tif (g_renderer->GetType() == RendererAPI::Metal)\n\t{\n\t    bool isRectVertexShader = (primitiveType == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS);\n\n\t    if ((usesGeometryShader || isRectVertexShader) || _activeFetchShader->mtlFetchVertexManually)\n\t\t{\n      \t\tfor (sint32 g = 0; g < _activeFetchShader->bufferGroups.size(); g++)\n            {\n           \t    LatteParsedFetchShaderBufferGroup_t& group = _activeFetchShader->bufferGroups[g];\n          \t\tuint32 bufferIndex = group.attributeBufferIndex;\n          \t\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n          \t\tuint32 bufferStride = (LatteGPUState.contextRegister[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;\n\n                vsHash += (uint64)bufferStride;\n          \t\tvsHash = std::rotl<uint64>(vsHash, 7);\n            }\n\t\t}\n\n\t    if (!(usesGeometryShader || isRectVertexShader))\n\t\t{\n      \t\tif (LatteGPUState.contextNew.IsRasterizationEnabled())\n      \t\t    vsHash += 51ULL;\n\n            // Vertex fetch\n            if (_activeFetchShader->mtlFetchVertexManually)\n                vsHash += 349ULL;\n\t\t}\n\t}\n#endif\n\n\t_shaderBaseHash_vs = vsHash;\n}\n\nvoid LatteSHRC_UpdateGSBaseHash(uint8* geometryShaderPtr, uint32 geometryShaderSize, uint8* geometryCopyShader, uint32 geometryCopyShaderSize)\n{\n\t// update hash from geometry shader data\n\tuint64 gsHash1 = 0;\n\tuint64 gsHash2 = 0;\n\t_calculateShaderProgramHash((uint32*)geometryShaderPtr, geometryShaderSize, &hashCacheGS, &gsHash1, &gsHash2);\n\t// get geometry shader\n\tuint64 gsHash = gsHash1 + gsHash2;\n\tgsHash += (uint64)_activeVertexShader->ringParameterCount;\n\tgsHash += (LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] ? 21 : 0);\n\t_shaderBaseHash_gs = gsHash;\n}\n\nvoid LatteSHRC_UpdatePSBaseHash(uint8* pixelShaderPtr, uint32 pixelShaderSize, bool usesGeometryShader)\n{\n\tuint32* psProgramCode = (uint32*)pixelShaderPtr;\n\t// update hash from pixel shader data\n\tuint64 psHash1 = 0;\n\tuint64 psHash2 = 0;\n\t_calculateShaderProgramHash(psProgramCode, pixelShaderSize, &hashCachePS, &psHash1, &psHash2);\n\t// get vertex shader\n\tuint64 psHash = psHash1 + psHash2 + _activePSImportTable.key + (usesGeometryShader ? hashCacheGS.prevHash1 : 0ULL);\n\n\t_shaderBaseHash_ps = psHash;\n}\n\nuint64 LatteSHRC_CalcVSAuxHash(LatteDecompilerShader* vertexShader, uint32* contextRegisters)\n{\n\t// todo - include texture types in aux hash similar to how it is already done in pixel shader\n\t//        or maybe there is a way to figure out the proper texture types?\n\tuint64 auxHash = 0;\n\tif(vertexShader->hasStreamoutBufferWrite)\n\t{\n\t\t// hash stride for streamout buffers\n\t\tfor (uint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t{\n\t\t\tif(!vertexShader->streamoutBufferWriteMask[i])\n\t\t\t\tcontinue;\n\t\t\tuint32 bufferStride = contextRegisters[mmVGT_STRMOUT_VTX_STRIDE_0 + i * 4];\n\t\t\tauxHash = std::rotl<uint64>(auxHash, 7);\n\t\t\tauxHash += (uint64)bufferStride;\n\t\t}\n\t}\n\t// textures can affect the shader. Either by their type (2D, 3D, cubemap) or by their format (float vs integer)\n\tuint64 auxHashTex = 0;\n\tfor (uint8 i = 0; i < vertexShader->textureUnitListCount; i++)\n\t{\n\t\tuint8 t = vertexShader->textureUnitList[i];\n\t\tuint32 word4 = contextRegisters[Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS + t * 7 + 4];\n\t\tif ((word4 & 0x300) == 0x100)\n\t\t{\n\t\t\t// integer format\n\t\t\tauxHashTex = std::rotl<uint64>(auxHashTex, 7);\n\t\t\tauxHashTex += 0x333;\n\t\t}\n\t}\n\n\treturn auxHash + auxHashTex;\n}\n\nuint64 LatteSHRC_CalcGSAuxHash(LatteDecompilerShader* geometryShader)\n{\n\t// todo - include texture types in aux hash similar to how it is already done in pixel shader\n\treturn 0;\n}\n\nuint64 LatteSHRC_CalcPSAuxHash(LatteDecompilerShader* pixelShader, uint32* contextRegisters)\n{\n\tuint64 auxHash = 0;\n\t// CB_SHADER_MASK can remap pixel shader outputs\n\tauxHash = (auxHash >> 3) | (auxHash << 61);\n\tauxHash += (uint64)contextRegisters[mmCB_SHADER_MASK];\n\t// alpha test\n\tuint8 alphaTestFunc = contextRegisters[Latte::REGADDR::SX_ALPHA_TEST_CONTROL] & 0x7;\n\tuint8 alphaTestEnable = (contextRegisters[Latte::REGADDR::SX_ALPHA_TEST_CONTROL] >> 3) & 1;\n\tif (alphaTestEnable)\n\t{\n\t\tauxHash += (uint64)alphaTestFunc;\n\t\tauxHash = (auxHash >> 3) | (auxHash << 61);\n\t\tauxHash += 1;\n\t}\n\t// texture types (2D, 3D, cubemap etc.) affect the shader too\n\tfor (uint8 i = 0; i < pixelShader->textureUnitListCount; i++)\n\t{\n\t\tuint8 t = pixelShader->textureUnitList[i];\n\t\tuint32 word0 = contextRegisters[Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS + t * 7 + 0];\n\t\tuint32 dim = (word0 & 7);\n\t\tauxHash = (auxHash << 3) | (auxHash >> 61);\n\t\tauxHash += (uint64)dim;\n\t}\n\n#if ENABLE_METAL\n\tif (g_renderer->GetType() == RendererAPI::Metal)\n\t{\n\t\t// Textures as render targets\n\t\tfor (uint32 i = 0; i < pixelShader->textureUnitListCount; i++)\n\t\t{\n\t\t    uint8 t = pixelShader->textureUnitList[i];\n\t\t    auxHash = std::rotl<uint64>(auxHash, 11);\n\t\t\tauxHash += (uint64)pixelShader->textureRenderTargetIndex[t];\n\t\t}\n\n\t\t// Color buffers\n        for (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)\n        {\n            auto format = LatteMRT::GetColorBufferFormat(i, LatteGPUState.contextNew);\n            uint8 dataType = (uint8)GetMtlPixelFormatInfo(format, false).dataType;\n            auxHash = std::rotl<uint64>(auxHash, 7);\n            auxHash += (uint64)dataType;\n        }\n\n        // Depth buffer\n        bool hasDepthBuffer = LatteMRT::GetActiveDepthBufferMask(LatteGPUState.contextNew);\n        if (hasDepthBuffer)\n        {\n            auxHash = std::rotl<uint64>(auxHash, 5);\n            auxHash += 13u;\n        }\n\t}\n#endif\n\n\treturn auxHash;\n}\n\nLatteDecompilerShader* LatteShader_CreateShaderFromDecompilerOutput(LatteDecompilerOutput_t& decompilerOutput, uint64 baseHash, bool calculateAuxHash, uint64 optionalAuxHash, uint32* contextRegister)\n{\n\tLatteDecompilerShader* shader = decompilerOutput.shader;\n\tshader->baseHash = baseHash;\n\t// copy resource mapping\n\t// HACK\n\tif (g_renderer->GetType() == RendererAPI::OpenGL)\n\t\tshader->resourceMapping = decompilerOutput.resourceMappingGL;\n\telse if (g_renderer->GetType() == RendererAPI::Vulkan)\n\t\tshader->resourceMapping = decompilerOutput.resourceMappingVK;\n#if ENABLE_METAL\n\telse\n\t\tshader->resourceMapping = decompilerOutput.resourceMappingMTL;\n#endif\n\t// copy texture info\n\tshader->textureUnitMask2 = decompilerOutput.textureUnitMask;\n\t// copy streamout info\n\tshader->streamoutBufferWriteMask = decompilerOutput.streamoutBufferWriteMask;\n\tshader->hasStreamoutBufferWrite = decompilerOutput.streamoutBufferWriteMask.any();\n\t// copy uniform offsets\n\t// for OpenGL these are retrieved in _prepareSeparableUniforms()\n\t// HACK\n\tif (g_renderer->GetType() == RendererAPI::Vulkan || g_renderer->GetType() == RendererAPI::Metal)\n\t{\n\t\tshader->uniform.loc_remapped = decompilerOutput.uniformOffsetsVK.offset_remapped;\n\t\tshader->uniform.loc_uniformRegister = decompilerOutput.uniformOffsetsVK.offset_uniformRegister;\n\t\tshader->uniform.count_uniformRegister = decompilerOutput.uniformOffsetsVK.count_uniformRegister;\n\t\tshader->uniform.loc_windowSpaceToClipSpaceTransform = decompilerOutput.uniformOffsetsVK.offset_windowSpaceToClipSpaceTransform;\n\t\tshader->uniform.loc_alphaTestRef = decompilerOutput.uniformOffsetsVK.offset_alphaTestRef;\n\t\tshader->uniform.loc_pointSize = decompilerOutput.uniformOffsetsVK.offset_pointSize;\n\t\tshader->uniform.loc_fragCoordScale = decompilerOutput.uniformOffsetsVK.offset_fragCoordScale;\n\t\tfor (sint32 t = 0; t < LATTE_NUM_MAX_TEX_UNITS; t++)\n\t\t{\n\t\t\tif (decompilerOutput.uniformOffsetsVK.offset_texScale[t] >= 0)\n\t\t\t{\n\t\t\t\tLatteUniformTextureScaleEntry_t entry = { 0 };\n\t\t\t\tentry.texUnit = t;\n\t\t\t\tentry.uniformLocation = decompilerOutput.uniformOffsetsVK.offset_texScale[t];\n\t\t\t\tshader->uniform.list_ufTexRescale.push_back(entry);\n\t\t\t}\n\t\t}\n\t\tshader->uniform.loc_verticesPerInstance = decompilerOutput.uniformOffsetsVK.offset_verticesPerInstance;\n\t\tfor (sint32 t = 0; t < LATTE_NUM_STREAMOUT_BUFFER; t++)\n\t\t\tshader->uniform.loc_streamoutBufferBase[t] = decompilerOutput.uniformOffsetsVK.offset_streamoutBufferBase[t];\n\t\tshader->uniform.uniformRangeSize = decompilerOutput.uniformOffsetsVK.offset_endOfBlock;\n\t}\n\telse\n\t{\n\t\tshader->uniform.count_uniformRegister = decompilerOutput.uniformOffsetsGL.count_uniformRegister;\n\t}\n\t// calculate aux hash\n\tif (calculateAuxHash)\n\t{\n\t\tif (decompilerOutput.shaderType == LatteConst::ShaderType::Vertex)\n\t\t{\n\t\t\tuint64 vsAuxHash = LatteSHRC_CalcVSAuxHash(shader, contextRegister);\n\t\t\tshader->auxHash = vsAuxHash;\n\t\t}\n\t\telse if (decompilerOutput.shaderType == LatteConst::ShaderType::Geometry)\n\t\t{\n\t\t\tuint64 gsAuxHash = LatteSHRC_CalcGSAuxHash(shader);\n\t\t\tshader->auxHash = gsAuxHash;\n\t\t}\n\t\telse if (decompilerOutput.shaderType == LatteConst::ShaderType::Pixel)\n\t\t{\n\t\t\tuint64 psAuxHash = LatteSHRC_CalcPSAuxHash(shader, contextRegister);\n\t\t\tshader->auxHash = psAuxHash;\n\t\t}\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\t}\n\telse\n\t{\n\t\tshader->auxHash = optionalAuxHash;\n\t}\n\treturn shader;\n}\n\nvoid LatteShader_GetDecompilerOptions(LatteDecompilerOptions& options, LatteConst::ShaderType shaderType, bool geometryShaderEnabled)\n{\n\toptions.usesGeometryShader = geometryShaderEnabled;\n\toptions.spirvInstrinsics.hasRoundingModeRTEFloat32 = false;\n\toptions.useTFViaSSBO = g_renderer->UseTFViaSSBO();\n\tif (g_renderer->GetType() == RendererAPI::Vulkan)\n\t{\n\t\toptions.spirvInstrinsics.hasRoundingModeRTEFloat32 = VulkanRenderer::GetInstance()->HasSPRIVRoundingModeRTE32();\n\t}\n\toptions.strictMul = g_current_game_profile->GetAccurateShaderMul() != AccurateShaderMulOption::False;\n}\n\nLatteDecompilerShader* LatteShader_CompileSeparableVertexShader2(uint64 baseHash, uint64& vsAuxHash, uint8* vertexShaderPtr, uint32 vertexShaderSize, bool usesGeometryShader, LatteFetchShader* fetchShader)\n{\n\t/* Analyze shader to gather general information about inputs/outputs */\n\tLatte::ShaderDescription shaderDescription;\n\tif (!shaderDescription.analyzeShaderCode(vertexShaderPtr, vertexShaderSize, LatteConst::ShaderType::Vertex))\n\t{\n\t\tassert_dbg();\n\t\treturn nullptr;\n\t}\n\t/* Create context dependent IO info for this shader */\n\t//Latte::ShaderInstanceInfo\n\tassert_dbg();\n\n\t// todo - Use ShaderInstanceInfo when generating the GLSL (GLSL::Emit() should take a 'GLSLInfoSource' class which has a bunch of virtual methods for retrieving uniform names etc. We then override this class and plug in logic using ShaderInstanceInfo\n\n\t/* Translate R600Plus to GLSL */\n\tZpIR::DebugPrinter irDebugPrinter;\n\tLatteTCGenIR genIR;\n\tgenIR.setVertexShaderContext(fetchShader, LatteGPUState.contextRegister + mmSQ_VTX_SEMANTIC_0);\n\tauto irObj = genIR.transcompileLatteToIR(vertexShaderPtr, vertexShaderSize, LatteTCGenIR::VERTEX);\n\t// debug output (before register allocation)\n\tirDebugPrinter.setShowPhysicalRegisters(false);\n\tirDebugPrinter.debugPrint(irObj);\n\t// register allocation\n\tZirPass::RegisterAllocatorForGLSL ra(irObj);\n\tra.applyPass();\n\t// debug output (after register allocation)\n\tirDebugPrinter.setShowPhysicalRegisters(true);\n\tirDebugPrinter.setPhysicalRegisterNameSource(ZirPass::RegisterAllocatorForGLSL::DebugPrintHelper_getPhysRegisterName);\n\tirDebugPrinter.debugPrint(irObj);\n\t// gen GLSL\n\tStringBuf glslSourceBuffer(64 * 1024);\n\t// emit GLSL header\n\tassert_dbg(); // todo\n\t// emit main\n\tZirEmitter::GLSL emitter;\n\temitter.Emit(irObj, &glslSourceBuffer);\n\n\t// debug copy to string\n\tstd::string dbg;\n\tdbg.insert(0, glslSourceBuffer.c_str(), glslSourceBuffer.getLen());\n\tassert_dbg();\n\n\n\treturn nullptr;\n}\n\n// compile new vertex shader (relies partially on current state)\nLatteDecompilerShader* LatteShader_CompileSeparableVertexShader(uint64 baseHash, uint64& vsAuxHash, uint8* vertexShaderPtr, uint32 vertexShaderSize, bool usesGeometryShader, LatteFetchShader* fetchShader)\n{\n\t// new decompiler test\n\t//LatteShader_CompileSeparableVertexShader2(baseHash, vsAuxHash, vertexShaderPtr, vertexShaderSize, usesGeometryShader, fetchShader);\n\n\t// legacy decompiler\n\tLatteDecompilerOptions options;\n\tLatteShader_GetDecompilerOptions(options, LatteConst::ShaderType::Vertex, usesGeometryShader);\n\n\tLatteDecompilerOutput_t decompilerOutput{};\n\tLatteDecompiler_DecompileVertexShader(_shaderBaseHash_vs, LatteGPUState.contextRegister, vertexShaderPtr, vertexShaderSize, fetchShader, options, &decompilerOutput);\n\tLatteDecompilerShader* vertexShader = LatteShader_CreateShaderFromDecompilerOutput(decompilerOutput, baseHash, true, 0, LatteGPUState.contextRegister);\n\tvsAuxHash = vertexShader->auxHash;\n\tif (vertexShader->hasError == false)\n\t{\n\t\tuint8* fsProgramCode = (uint8*)memory_getPointerFromPhysicalOffset(LatteGPUState.contextRegister[mmSQ_PGM_START_FS + 0] << 8);\n\t\tuint32 fsProgramSize = LatteGPUState.contextRegister[mmSQ_PGM_START_FS + 1] << 3;\n\t\tLatteShaderCache_writeSeparableVertexShader(vertexShader->baseHash, vertexShader->auxHash, fsProgramCode, fsProgramSize, vertexShaderPtr, vertexShaderSize, LatteGPUState.contextRegister, usesGeometryShader);\n\t}\n\tLatteShader_DumpShader(vertexShader->baseHash, vertexShader->auxHash, vertexShader);\n\tLatteShader_DumpRawShader(vertexShader->baseHash, vertexShader->auxHash, SHADER_DUMP_TYPE_VERTEX, vertexShaderPtr, vertexShaderSize);\n\tLatteShader_CreateRendererShader(vertexShader, false);\n\tperformanceMonitor.numCompiledVS++;\n\n\tif (g_renderer->GetType() == RendererAPI::OpenGL)\n\t{\n\t\tif (vertexShader->shader)\n\t\t\tvertexShader->shader->PreponeCompilation(true);\n\t\tLatteShader_FinishCompilation(vertexShader);\n\t}\n\n\tLatteSHRC_RegisterShader(vertexShader, vertexShader->baseHash, vertexShader->auxHash);\n\treturn vertexShader;\n}\n\nLatteDecompilerShader* LatteShader_CompileSeparableGeometryShader(uint64 baseHash, uint8* geometryShaderPtr, uint32 geometryShaderSize, uint8* geometryCopyShader, uint32 geometryCopyShaderSize)\n{\n\tLatteDecompilerOptions options;\n\tLatteShader_GetDecompilerOptions(options, LatteConst::ShaderType::Geometry, true);\n\n\tLatteDecompilerOutput_t decompilerOutput{};\n\tLatteDecompiler_DecompileGeometryShader(_shaderBaseHash_gs, LatteGPUState.contextRegister, geometryShaderPtr, geometryShaderSize, geometryCopyShader, geometryCopyShaderSize, _activeVertexShader->ringParameterCount, options, &decompilerOutput);\n\tLatteDecompilerShader* geometryShader = LatteShader_CreateShaderFromDecompilerOutput(decompilerOutput, baseHash, true, 0, LatteGPUState.contextRegister);\n\tif (geometryShader->hasError == false)\n\t{\n\t\tLatteShaderCache_writeSeparableGeometryShader(geometryShader->baseHash, geometryShader->auxHash, geometryShaderPtr, geometryShaderSize, geometryCopyShader, geometryCopyShaderSize, LatteGPUState.contextRegister, LatteGPUState.contextNew.GetSpecialStateValues(), _activeVertexShader->ringParameterCount);\n\t}\n\tLatteShader_DumpShader(geometryShader->baseHash, geometryShader->auxHash, geometryShader);\n\tLatteShader_DumpRawShader(geometryShader->baseHash, geometryShader->auxHash, SHADER_DUMP_TYPE_GEOMETRY, geometryShaderPtr, geometryShaderSize);\n\tLatteShader_DumpRawShader(geometryShader->baseHash, geometryShader->auxHash, SHADER_DUMP_TYPE_COPY, geometryCopyShader, geometryCopyShaderSize);\n\tLatteShader_CreateRendererShader(geometryShader, false);\n\tperformanceMonitor.numCompiledGS++;\n\n\tif (g_renderer->GetType() == RendererAPI::OpenGL)\n\t{\n\t\tif (geometryShader->shader)\n\t\t\tgeometryShader->shader->PreponeCompilation(true);\n\t\tLatteShader_FinishCompilation(geometryShader);\n\t}\n\n\tLatteSHRC_RegisterShader(geometryShader, geometryShader->baseHash, geometryShader->auxHash);\n\treturn geometryShader;\n}\n\nLatteDecompilerShader* LatteShader_CompileSeparablePixelShader(uint64 baseHash, uint64& psAuxHash, uint8* pixelShaderPtr, uint32 pixelShaderSize, bool usesGeometryShader)\n{\n\tLatteDecompilerOptions options;\n\tLatteShader_GetDecompilerOptions(options, LatteConst::ShaderType::Pixel, usesGeometryShader);\n\n\tLatteDecompilerOutput_t decompilerOutput{};\n\tLatteDecompiler_DecompilePixelShader(baseHash, LatteGPUState.contextRegister, pixelShaderPtr, pixelShaderSize, options, &decompilerOutput);\n\tLatteDecompilerShader* pixelShader = LatteShader_CreateShaderFromDecompilerOutput(decompilerOutput, baseHash, true, 0, LatteGPUState.contextRegister);\n\tpsAuxHash = pixelShader->auxHash;\n\tLatteShader_DumpShader(_shaderBaseHash_ps, psAuxHash, pixelShader);\n\tLatteShader_DumpRawShader(_shaderBaseHash_ps, psAuxHash, SHADER_DUMP_TYPE_PIXEL, pixelShaderPtr, pixelShaderSize);\n\tLatteShader_CreateRendererShader(pixelShader, false);\n\tperformanceMonitor.numCompiledPS++;\n\tif (pixelShader->hasError == false)\n\t{\n\t\tLatteShaderCache_writeSeparablePixelShader(_shaderBaseHash_ps, psAuxHash, pixelShaderPtr, pixelShaderSize, LatteGPUState.contextRegister, usesGeometryShader);\n\t}\n\n\tif (g_renderer->GetType() == RendererAPI::OpenGL)\n\t{\n\t\tif (pixelShader->shader)\n\t\t\tpixelShader->shader->PreponeCompilation(true);\n\t\tLatteShader_FinishCompilation(pixelShader);\n\t}\n\n\tLatteSHRC_RegisterShader(pixelShader, _shaderBaseHash_ps, psAuxHash);\n\treturn pixelShader;\n}\n\nvoid LatteSHRC_UpdateVertexShader(uint8* vertexShaderPtr, uint32 vertexShaderSize, bool usesGeometryShader)\n{\n\t// todo - should include VTX_SEMANTIC table in state\n\tLatteSHRC_UpdateVSBaseHash(vertexShaderPtr, vertexShaderSize, usesGeometryShader);\n\tuint64 vsAuxHash = 0;\n\tauto itBaseShader = sVertexShaders.find(_shaderBaseHash_vs);\n\tLatteDecompilerShader* vertexShader = nullptr;\n\tif (itBaseShader != sVertexShaders.end())\n\t{\n\t\tvsAuxHash = LatteSHRC_CalcVSAuxHash(itBaseShader->second, LatteGPUState.contextRegister);\n\t\tvertexShader = LatteSHRC_GetFromChain(itBaseShader->second, _shaderBaseHash_vs, vsAuxHash);\n\t}\n\tif (!vertexShader)\n\t\tvertexShader = LatteShader_CompileSeparableVertexShader(_shaderBaseHash_vs, vsAuxHash, vertexShaderPtr, vertexShaderSize, usesGeometryShader, _activeFetchShader);\n\tif (vertexShader->hasError)\n\t{\n\t\tLatteGPUState.activeShaderHasError = true;\n\t\treturn;\n\t}\n\t_activeVertexShader = vertexShader;\n}\n\nvoid LatteSHRC_UpdateGeometryShader(bool usesGeometryShader, uint8* geometryShaderPtr, uint32 geometryShaderSize, uint8* geometryCopyShader, uint32 geometryCopyShaderSize)\n{\n\tif (!usesGeometryShader || !_activeVertexShader)\n\t{\n\t\t_shaderBaseHash_gs = 0;\n\t\t_activeGeometryShader = nullptr;\n\t\treturn;\n\t}\n\tLatteSHRC_UpdateGSBaseHash(geometryShaderPtr, geometryShaderSize, geometryCopyShader, geometryCopyShaderSize);\n\tauto itBaseShader = sGeometryShaders.find(_shaderBaseHash_gs);\n\tLatteDecompilerShader* geometryShader;\n\tif (itBaseShader != sGeometryShaders.end())\n\t{\n\t\t// geometry shader already known\n\t\tgeometryShader = itBaseShader->second;\n\t\tcemu_assert_debug(LatteSHRC_CalcGSAuxHash(geometryShader) == 0);\n\t}\n\telse\n\t{\n\t\t// decompile geometry shader\n\t\tgeometryShader = LatteShader_CompileSeparableGeometryShader(_shaderBaseHash_gs, geometryShaderPtr, geometryShaderSize, geometryCopyShader, geometryCopyShaderSize);\n\t}\n\tif (geometryShader->hasError)\n\t{\n\t\tLatteGPUState.activeShaderHasError = true;\n\t\treturn;\n\t}\n\t_activeGeometryShader = geometryShader;\n}\n\nvoid LatteSHRC_UpdatePixelShader(uint8* pixelShaderPtr, uint32 pixelShaderSize, bool usesGeometryShader)\n{\n\tLatteSHRC_UpdatePSBaseHash(pixelShaderPtr, pixelShaderSize, usesGeometryShader);\n\tuint64 psAuxHash = 0;\n\tauto itBaseShader = sPixelShaders.find(_shaderBaseHash_ps);\n\tLatteDecompilerShader* pixelShader = nullptr;\n\tif (itBaseShader != sPixelShaders.end())\n\t{\n\t\tpsAuxHash = LatteSHRC_CalcPSAuxHash(itBaseShader->second, LatteGPUState.contextRegister);\n\t\tpixelShader = LatteSHRC_GetFromChain(itBaseShader->second, _shaderBaseHash_ps, psAuxHash);\n\t}\n\tif (!pixelShader)\n\t\tpixelShader = LatteShader_CompileSeparablePixelShader(_shaderBaseHash_ps, psAuxHash, pixelShaderPtr, pixelShaderSize, usesGeometryShader);\n\tif (pixelShader->hasError)\n\t{\n\t\tLatteGPUState.activeShaderHasError = true;\n\t\treturn;\n\t}\n\t_activePixelShader = pixelShader;\n}\n\nvoid LatteSHRC_UpdateActiveShaders()\n{\n\t// check if geometry shader is used\n\tauto gsMode = LatteGPUState.contextNew.VGT_GS_MODE.get_MODE();\n\n\tcemu_assert_debug(LatteGPUState.contextNew.VGT_GS_MODE.get_ES_PASSTHRU() == false);\n\t// todo: Support for ES passthrough and cut mode in mmVGT_GS_MODE\n\n\tbool geometryShaderUsed = false;\n\tif (gsMode == Latte::LATTE_VGT_GS_MODE::E_MODE::OFF)\n\t{\n\t\tgeometryShaderUsed = false;\n\t}\n\telse if (gsMode == Latte::LATTE_VGT_GS_MODE::E_MODE::SCENARIO_G)\n\t{\n\t\t// could also be compute shader?\n\t\tgeometryShaderUsed = true;\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n\t// get shader programs\n\tuint8* psProgramCode = (uint8*)memory_getPointerFromPhysicalOffset((LatteGPUState.contextRegister[mmSQ_PGM_START_PS] & 0xFFFFFF) << 8);\n\tuint32 psProgramSize = LatteGPUState.contextRegister[mmSQ_PGM_START_PS + 1] << 3;\n\tuint8* gsProgramCode = (uint8*)memory_getPointerFromPhysicalOffset((LatteGPUState.contextRegister[mmSQ_PGM_START_GS] & 0xFFFFFF) << 8);\n\tuint32 gsProgramSize = LatteGPUState.contextRegister[mmSQ_PGM_START_GS + 1] << 3;\n\n\tuint8* vsProgramCode;\n\tuint32 vsProgramSize;\n\tuint8* copyProgramCode = NULL;\n\tuint32 copyProgramSize = 0;\n\tif (geometryShaderUsed)\n\t{\n\t\tvsProgramCode = (uint8*)memory_getPointerFromPhysicalOffset((LatteGPUState.contextRegister[mmSQ_PGM_START_ES] & 0xFFFFFF) << 8);\n\t\tvsProgramSize = LatteGPUState.contextRegister[mmSQ_PGM_START_ES + 1] << 3;\n\t\tcopyProgramCode = (uint8*)memory_getPointerFromPhysicalOffset((LatteGPUState.contextRegister[mmSQ_PGM_START_VS] & 0xFFFFFF) << 8);\n\t\tif (LatteGPUState.contextRegister[mmSQ_PGM_START_VS] == 0)\n\t\t{\n\t\t\tcopyProgramCode = NULL;\n\t\t\tdebug_printf(\"copyProgram is NULL but used. Might be because of unsupported vertex/geometry mode?\");\n\t\t}\n\t\tcopyProgramSize = LatteGPUState.contextRegister[mmSQ_PGM_START_VS + 1] << 3;\n\t}\n\telse\n\t{\n\t\tif (LatteGPUState.contextRegister[mmSQ_PGM_START_VS] == 0)\n\t\t{\n\t\t\tdebug_printf(\"No vertex shader program set\\n\");\n\t\t\tLatteGPUState.activeShaderHasError = true;\n\t\t\treturn;\n\t\t}\n\t\tvsProgramCode = (uint8*)memory_getPointerFromPhysicalOffset((LatteGPUState.contextRegister[mmSQ_PGM_START_VS] & 0xFFFFFF) << 8);\n\t\tvsProgramSize = LatteGPUState.contextRegister[mmSQ_PGM_START_VS + 1] << 3;\n\t}\n\t// set new shaders\n\tLatteGPUState.activeShaderHasError = false;\n\tLatteShader_UpdatePSInputs(LatteGPUState.contextRegister);\n\tLatteShaderSHRC_UpdateFetchShader();\n\tLatteSHRC_UpdateVertexShader(vsProgramCode, vsProgramSize, geometryShaderUsed);\n\tif (LatteGPUState.activeShaderHasError)\n\t\treturn;\n\tLatteSHRC_UpdateGeometryShader(geometryShaderUsed, gsProgramCode, gsProgramSize, copyProgramCode, copyProgramSize);\n\tif (LatteGPUState.activeShaderHasError)\n\t\treturn;\n\tLatteSHRC_UpdatePixelShader(psProgramCode, psProgramSize, geometryShaderUsed);\n\tif (LatteGPUState.activeShaderHasError)\n\t\treturn;\n}\n\n// returns the sampler base index for the given shader type\nsint32 LatteDecompiler_getTextureSamplerBaseIndex(LatteConst::ShaderType shaderType)\n{\n\tuint32 samplerId = LATTE_DECOMPILER_SAMPLER_NONE;\n\tif (shaderType == LatteConst::ShaderType::Vertex)\n\t\treturn Latte::SAMPLER_BASE_INDEX_VERTEX;\n\telse if (shaderType == LatteConst::ShaderType::Pixel)\n\t\treturn Latte::SAMPLER_BASE_INDEX_PIXEL;\n\telse if (shaderType == LatteConst::ShaderType::Geometry)\n\t\treturn Latte::SAMPLER_BASE_INDEX_GEOMETRY;\n\telse\n\t\tcemu_assert_suspicious();\n\treturn 0;\n}\n\nvoid LatteSHRC_Init()\n{\n\tcemu_assert_debug(sVertexShaders.empty());\n\tcemu_assert_debug(sGeometryShaders.empty());\n\tcemu_assert_debug(sPixelShaders.empty());\n}\n\nvoid LatteSHRC_UnloadAll()\n{\n    while(!sVertexShaders.empty())\n        LatteShader_free(sVertexShaders.begin()->second);\n    cemu_assert_debug(sVertexShaders.empty());\n    while(!sGeometryShaders.empty())\n        LatteShader_free(sGeometryShaders.begin()->second);\n    cemu_assert_debug(sGeometryShaders.empty());\n    while(!sPixelShaders.empty())\n        LatteShader_free(sPixelShaders.begin()->second);\n    cemu_assert_debug(sPixelShaders.empty());\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteShader.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n\nvoid LatteSHRC_Init();\nvoid LatteSHRC_UnloadAll();\n\nvoid LatteSHRC_ResetCachedShaderHash();\nvoid LatteShaderSHRC_UpdateFetchShader();\n\nvoid LatteSHRC_UpdateActiveShaders();\n\nstruct LatteFetchShader* LatteSHRC_GetActiveFetchShader();\nLatteDecompilerShader* LatteSHRC_GetActiveVertexShader();\nLatteDecompilerShader* LatteSHRC_GetActiveGeometryShader();\nLatteDecompilerShader* LatteSHRC_GetActivePixelShader();\n\nLatteDecompilerShader* LatteSHRC_FindVertexShader(uint64 baseHash, uint64 auxHash);\nLatteDecompilerShader* LatteSHRC_FindGeometryShader(uint64 baseHash, uint64 auxHash);\nLatteDecompilerShader* LatteSHRC_FindPixelShader(uint64 baseHash, uint64 auxHash);\n\n\n#define GPU7_PS_MAX_INPUTS\t32\n\nstruct LatteShaderPSInputTable\n{\n\tstruct psImport_t\n\t{\n\t\tuint32 semanticId;\n\t\tbool isFlat;\n\t\tbool isNoPerspective;\n\t};\n\tpsImport_t import[GPU7_PS_MAX_INPUTS]{}; // GPR is index\n\tsint32 count;\n\tuint64 key;\n\tuint8 paramGen;\n\tuint8 paramGenGPR;\n\n\t// returns semantic id of vertex shader output by index\n\t// the returned semanticId may not have a match in the pixel shader (use hasPSImportForSemanticId to determine matched exports)\n\tstatic sint32 getVertexShaderOutParamSemanticId(uint32* contextRegisters, sint32 index)\n\t{\n\t\tcemu_assert_debug(index >= 0 && index < 32);\n\t\tuint32 vsSemanticId = (contextRegisters[mmSPI_VS_OUT_ID_0 + (index / 4)] >> (8 * (index % 4))) & 0xFF;\n\t\treturn (sint32)vsSemanticId;\n\t}\n\n\tbool hasPSImportForSemanticId(sint32 semanticId)\n\t{\n\t\tfor (sint32 i = 0; i < this->count; i++)\n\t\t{\n\t\t\tif (this->import[i].semanticId == semanticId)\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpsImport_t* getPSImportBySemanticId(sint32 semanticId)\n\t{\n\t\tif (semanticId > LATTE_ANALYZER_IMPORT_INDEX_PARAM_MAX)\n\t\t\treturn nullptr;\n\t\t// get import based on semanticId\n\t\tsint32 psInputIndex = -1;\n\t\tfor (sint32 f = 0; f < this->count; f++)\n\t\t{\n\t\t\tif (this->import[f].semanticId == semanticId)\n\t\t\t\treturn this->import + f;\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tsint32 getPSImportLocationBySemanticId(sint32 semanticId)\n\t{\n\t\tif (semanticId > LATTE_ANALYZER_IMPORT_INDEX_PARAM_MAX)\n\t\t\treturn -1;\n\t\t// get import based on semanticId\n\t\tsint32 psInputIndex = -1;\n\t\tfor (sint32 f = 0; f < this->count; f++)\n\t\t{\n\t\t\tif (this->import[f].semanticId == semanticId)\n\t\t\t\treturn f;\n\t\t}\n\t\treturn -1;\n\t}\n};\n\nvoid LatteShader_CreatePSInputTable(LatteShaderPSInputTable* psInputTable, uint32* contextRegisters);\nvoid LatteShader_UpdatePSInputs(uint32* contextRegisters);\nLatteShaderPSInputTable* LatteSHRC_GetPSInputTable();\n\nvoid LatteShader_free(LatteDecompilerShader* shader);\nvoid LatteSHRC_RemoveFromCacheByHash(uint64 shader_base_hash, uint64 shader_aux_hash, LatteConst::ShaderType type);\n\nextern uint64 _shaderBaseHash_fs;\nextern uint64 _shaderBaseHash_vs;\nextern uint64 _shaderBaseHash_gs;\nextern uint64 _shaderBaseHash_ps;\n\nvoid LatteShader_GetDecompilerOptions(struct LatteDecompilerOptions& options, LatteConst::ShaderType shaderType, bool geometryShaderEnabled);\nLatteDecompilerShader* LatteShader_CreateShaderFromDecompilerOutput(LatteDecompilerOutput_t& decompilerOutput, uint64 baseHash, bool calculateAuxHash, uint64 optionalAuxHash, uint32* contextRegister);\n\nvoid LatteShader_CreateRendererShader(LatteDecompilerShader* shader, bool compileAsync);\nvoid LatteShader_FinishCompilation(LatteDecompilerShader* shader);\n\nvoid LatteShader_prepareSeparableUniforms(LatteDecompilerShader* shader);\n\nvoid LatteSHRC_RegisterShader(LatteDecompilerShader* shader, uint64 baseHash, uint64 auxHash);\n\nvoid LatteShader_CleanupAfterCompile(LatteDecompilerShader* shader);\n\n#define SHADER_DUMP_TYPE_FETCH\t\t0\n#define SHADER_DUMP_TYPE_VERTEX\t\t1\n#define SHADER_DUMP_TYPE_GEOMETRY\t2\n#define SHADER_DUMP_TYPE_PIXEL\t\t3\n#define SHADER_DUMP_TYPE_COPY\t\t4\n#define SHADER_DUMP_TYPE_COMPUTE\t5\n\nvoid LatteShader_DumpShader(uint64 baseHash, uint64 auxHash, LatteDecompilerShader* shader);\nvoid LatteShader_DumpRawShader(uint64 baseHash, uint64 auxHash, uint32 type, uint8* programCode, uint32 programLen);\n\n// shader cache file\nvoid LatteShaderCache_Load();\nvoid LatteShaderCache_Close();\n\nvoid LatteShaderCache_writeSeparableVertexShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* fetchShader, uint32 fetchShaderSize, uint8* vertexShader, uint32 vertexShaderSize, uint32* contextRegisters, bool usesGeometryShader);\nvoid LatteShaderCache_writeSeparableGeometryShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* geometryShader, uint32 geometryShaderSize, uint8* gsCopyShader, uint32 gsCopyShaderSize, uint32* contextRegisters, uint32* hleSpecialState, uint32 vsRingParameterCount);\nvoid LatteShaderCache_writeSeparablePixelShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* pixelShader, uint32 pixelShaderSize, uint32* contextRegisters, bool usesGeometryShader);\n\n// todo - refactor this\nsint32 LatteDecompiler_getTextureSamplerBaseIndex(LatteConst::ShaderType shaderType);\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteShaderAssembly.h",
    "content": "#pragma once\n\n// CF export\n\n#define GPU7_DECOMPILER_CF_EXPORT_BASE_POSITION\t(60)\n#define GPU7_DECOMPILER_CF_EXPORT_POINT_SIZE\t(61)\n\n// CF instruction set\n\n#define GPU7_CF_INST_NOP\t\t\t\t(0x00)\n#define GPU7_CF_INST_TEX\t\t\t\t(0x01) \n#define GPU7_CF_INST_VTX\t\t\t\t(0x02) // used only in GS copy program?\n#define GPU7_CF_INST_LOOP_END\t\t\t(0x05)\n#define GPU7_CF_INST_LOOP_START_DX10\t(0x06)\n#define GPU7_CF_INST_LOOP_START_NO_AL\t(0x07) // (Seen in Project Zero, Injustice: Gods Among Us)\n\n#define GPU7_CF_INST_LOOP_BREAK\t\t\t(0x09)\n#define GPU7_CF_INST_JUMP\t\t\t\t(0x0A)\n#define GPU7_CF_INST_ELSE\t\t\t\t(0x0D)\n#define GPU7_CF_INST_POP\t\t\t\t(0x0E)\n#define GPU7_CF_INST_ELSE_AFTER\t\t\t(0x0F)\n#define GPU7_CF_INST_CALL\t\t\t\t(0x12)\n#define GPU7_CF_INST_CALL_FS\t\t\t(0x13)\n#define GPU7_CF_INST_RETURN\t\t\t\t(0x14)\n#define GPU7_CF_INST_EMIT_VERTEX\t\t(0x15) // only available in geometry shader\n#define GPU7_CF_INST_MEM_STREAM0_WRITE\t(0x20) // for stream out\n#define GPU7_CF_INST_MEM_STREAM1_WRITE\t(0x21) // for stream out\n#define GPU7_CF_INST_MEM_RING_WRITE\t\t(0x26) // used to pass data to/from geometry shader\n#define GPU7_CF_INST_EXPORT\t\t\t\t(0x27)\n#define GPU7_CF_INST_EXPORT_DONE\t\t(0x28)\n\n#define GPU7_CF_INST_ALU_MASK\t\t\t(0x10000) // this mask is used to make sure that there is no collision between any GPU7_CF_INST_* values (e.g. GPU7_CF_INST_ALU_BREAK and GPU7_CF_INST_POP would collide due to different encoding but identical value)\n#define GPU7_CF_INST_ALU\t\t\t\t(0x08 | GPU7_CF_INST_ALU_MASK)\n#define GPU7_CF_INST_ALU_PUSH_BEFORE\t(0x09 | GPU7_CF_INST_ALU_MASK)\n#define GPU7_CF_INST_ALU_POP_AFTER\t\t(0x0A | GPU7_CF_INST_ALU_MASK)\n#define GPU7_CF_INST_ALU_POP2_AFTER\t\t(0x0B | GPU7_CF_INST_ALU_MASK)\n#define GPU7_CF_INST_ALU_BREAK\t\t\t(0x0E | GPU7_CF_INST_ALU_MASK)\n#define GPU7_CF_INST_ALU_ELSE_AFTER\t\t(0x0F | GPU7_CF_INST_ALU_MASK)\n\n\n//#define INDEX_NONE\t\t\t\t\t\t(-1) // used to indicate absolute access\n#define GPU7_INDEX_AR_X\t\t\t\t\t\t(0)\n#define GPU7_INDEX_AR_Y\t\t\t\t\t\t(1)\n#define GPU7_INDEX_AR_Z\t\t\t\t\t\t(2)\n#define GPU7_INDEX_AR_W\t\t\t\t\t\t(3)\n#define GPU7_INDEX_LOOP\t\t\t\t\t\t(4)\n#define GPU7_INDEX_GLOBAL\t\t\t\t\t(5)\n#define GPU7_INDEX_GLOBAL_AR_X\t\t\t\t(6)\n\n#define GPU7_TEX_INST_VFETCH\t\t\t\t(0x00)\n#define GPU7_TEX_INST_MEM\t\t\t\t\t(0x02)\n#define GPU7_TEX_INST_LD\t\t\t\t\t(0x03)\n#define GPU7_TEX_INST_GET_TEXTURE_RESINFO\t(0x04)\n#define GPU7_TEX_INST_GET_COMP_TEX_LOD\t\t(0x06)\n#define GPU7_TEX_INST_GET_GRADIENTS_H\t\t(0x07)\n#define GPU7_TEX_INST_GET_GRADIENTS_V\t\t(0x08)\n#define GPU7_TEX_INST_SET_GRADIENTS_H\t\t(0x0B)\n#define GPU7_TEX_INST_SET_GRADIENTS_V\t\t(0x0C)\n#define GPU7_TEX_INST_SET_CUBEMAP_INDEX\t\t(0x0E)\n#define GPU7_TEX_INST_FETCH4\t\t\t\t(0x0F)\n#define GPU7_TEX_INST_SAMPLE\t\t\t\t(0x10) // LOD from hw\n#define GPU7_TEX_INST_SAMPLE_L\t\t\t\t(0x11) // LOD from srcGpr.w\n#define GPU7_TEX_INST_SAMPLE_LB\t\t\t\t(0x12) // todo: Accesses LOD_BIAS field of instruction\n#define GPU7_TEX_INST_SAMPLE_LZ\t\t\t\t(0x13) // LOD is 0.0\n#define GPU7_TEX_INST_SAMPLE_G\t\t\t\t(0x14)\n#define GPU7_TEX_INST_SAMPLE_C\t\t\t\t(0x18) // sample & compare, LOD from hw\n#define GPU7_TEX_INST_SAMPLE_C_L\t\t\t(0x19) // sample & compare, LOD from srcGpr.w\n#define GPU7_TEX_INST_SAMPLE_C_LZ\t\t\t(0x1B) // sample & compare, LOD is 0.0\n\n#define GPU7_TEX_UNNORMALIZED\t\t\t\t(0)\n#define GPU7_TEX_NORMALIZED\t\t\t\t\t(1)\n\n\n#define GPU7_ALU_SRC_UNUSED\t\t\t\t\t(-1) // special value which indicates that the ALU operand is not used\n#define GPU7_ALU_SRC_IS_GPR(__v)\t\t\t((__v)>=0 && (__v)<128)\t// 0-127\n#define GPU7_ALU_SRC_IS_CBANK0(__v)\t\t\t((__v)>=128 && (__v)<160)\t// 128-159\n#define GPU7_ALU_SRC_IS_CBANK1(__v)\t\t\t((__v)>=160 && (__v)<192)\t// 160-191\n#define GPU7_ALU_SRC_IS_CONST_0F(__v)\t\t((__v)==248)\t// 248\n#define GPU7_ALU_SRC_IS_CONST_1F(__v)\t\t((__v)==249)\t// 249\n#define GPU7_ALU_SRC_IS_CONST_1I(__v)\t\t((__v)==250)\t// 250\n#define GPU7_ALU_SRC_IS_CONST_M1I(__v)\t\t((__v)==251)\t// 251 (0xFB)\n#define GPU7_ALU_SRC_IS_CONST_0_5F(__v)\t\t((__v)==252)\t// 252 (0xFC)\n#define GPU7_ALU_SRC_IS_LITERAL(__v)\t\t((__v)==253)\t// 253 (0xFD)\n#define GPU7_ALU_SRC_IS_PV(__v)\t\t\t\t((__v)==254)\t// 254 (0xFE)\n#define GPU7_ALU_SRC_IS_PS(__v)\t\t\t\t((__v)==255)\t// 255 (0xFF)\n#define GPU7_ALU_SRC_IS_CFILE(__v)\t\t\t((__v)>=256 && (__v)<512) // 256-511 (uniform register)\n\n#define GPU7_ALU_SRC_IS_ANY_CONST(__v)\t\t((__v)>=248 && (__v)<253) // special macro to handle all GPU7_ALU_SRC_IS_CONST_*\n\n#define GPU7_ALU_SRC_GET_GPR_INDEX(__v)\t\t((__v))\n#define GPU7_ALU_SRC_GET_CFILE_INDEX(__v)\t((__v)-256)\n#define GPU7_ALU_SRC_GET_CBANK0_INDEX(__v)\t((__v)-128)\n#define GPU7_ALU_SRC_GET_CBANK1_INDEX(__v)\t((__v)-160)\n\n#define GPU7_ALU_SRC_LITERAL\t\t\t\t\t(0xFD)\t\t\t\t\t\t\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteShaderCache.cpp",
    "content": "#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cemu/FileCache/FileCache.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"WindowSystem.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h\"\n#if ENABLE_METAL\n#include \"Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h\"\n#endif\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h\"\n\n#include <imgui.h>\n#include \"imgui/imgui_extension.h\"\n\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/TitleList/GameInfo.h\"\n\n#include \"util/helpers/SystemException.h\"\n#include \"Cafe/HW/Latte/Common/RegisterSerializer.h\"\n#include \"Cafe/HW/Latte/Common/ShaderSerializer.h\"\n#include \"util/helpers/Serializer.h\"\n\n#include <audio/IAudioAPI.h>\n#include <util/bootSound/BootSoundReader.h>\n#include <thread>\n\n#if BOOST_OS_WINDOWS\n#include <psapi.h>\n#endif\n\n#define SHADER_CACHE_COMPILE_QUEUE_SIZE\t\t(32)\n\nstruct\n{\n\tsint32 compiledShaderCount;\n\t// number of loaded shaders\n\tsint32 vertexShaderCount;\n\tsint32 geometryShaderCount;\n\tsint32 pixelShaderCount;\n}shaderCacheScreenStats;\n\nstruct\n{\n\tImTextureID textureTVId;\n\tImTextureID textureDRCId;\n\t// shader loading\n\tsint32 loadedShaderFiles;\n\tsint32 shaderFileCount;\n\t// pipeline loading\n\tuint32 loadedPipelines;\n\tsint32 pipelineFileCount;\n}g_shaderCacheLoaderState;\n\nFileCache* s_shaderCacheGeneric = nullptr;\t// contains hardware and version independent shader information\n\n#define SHADER_CACHE_GENERIC_EXTRA_VERSION\t\t2 // changing this constant will invalidate all hardware-independent cache files\n\n#define SHADER_CACHE_TYPE_VERTEX\t\t\t\t(0)\n#define SHADER_CACHE_TYPE_GEOMETRY\t\t\t\t(1)\n#define SHADER_CACHE_TYPE_PIXEL\t\t\t\t\t(2)\n\nbool LatteShaderCache_readSeparableShader(uint8* shaderInfoData, sint32 shaderInfoSize);\nvoid LatteShaderCache_LoadPipelineCache(uint64 cacheTitleId);\nbool LatteShaderCache_updatePipelineLoadingProgress();\nvoid LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateFunc, bool isPipelines);\n\nstruct\n{\n\tstruct\n\t{\n\t\tLatteDecompilerShader* shader;\n\t}entry[SHADER_CACHE_COMPILE_QUEUE_SIZE];\n\tsint32 count;\n}shaderCompileQueue;\n\nvoid LatteShaderCache_initCompileQueue()\n{\n\tshaderCompileQueue.count = 0;\n}\n\nvoid LatteShaderCache_addToCompileQueue(LatteDecompilerShader* shader)\n{\n\tcemu_assert(shaderCompileQueue.count < SHADER_CACHE_COMPILE_QUEUE_SIZE);\n\tshaderCompileQueue.entry[shaderCompileQueue.count].shader = shader;\n\tshaderCompileQueue.count++;\n}\n\nvoid LatteShaderCache_removeFromCompileQueue(sint32 index)\n{\n\tfor (sint32 i = index; i<shaderCompileQueue.count-1; i++)\n\t\tshaderCompileQueue.entry[i].shader = shaderCompileQueue.entry[i + 1].shader;\n\tshaderCompileQueue.count--;\n}\n\n/*\n * Process entries from compile queue until there are equal or less entries\n * left than specified by maxRemainingEntries\n */\nvoid LatteShaderCache_updateCompileQueue(sint32 maxRemainingEntries)\n{\n\twhile (true)\n\t{\n\t\tif (shaderCompileQueue.count <= maxRemainingEntries)\n\t\t\tbreak;\n\t\tauto shader = shaderCompileQueue.entry[0].shader;\n\t\tif (shader)\n\t\t\tLatteShader_FinishCompilation(shader);\n\t\tLatteShaderCache_removeFromCompileQueue(0);\n\t}\n}\n\ntypedef struct\n{\n\tunsigned char imageTypeCode;\n\tshort int imageWidth;\n\tshort int imageHeight;\n\tunsigned char bitCount;\n\tstd::vector<uint8> imageData;\n} TGAFILE;\n\nbool LoadTGAFile(const std::vector<uint8>& buffer, TGAFILE *tgaFile)\n{\n\tif (buffer.size() <= 18)\n\t\treturn false;\n\n\ttgaFile->imageTypeCode = buffer[2];\n\tif (tgaFile->imageTypeCode != 2 && tgaFile->imageTypeCode != 3)\n\t\treturn false;\n\n\ttgaFile->imageWidth = *(uint16*)(buffer.data() + 12);\n\ttgaFile->imageHeight = *(uint16*)(buffer.data() + 14);\n\ttgaFile->bitCount = buffer[16];\n\n\t// Color mode -> 3 = BGR, 4 = BGRA.\n\tconst uint8 colorMode = tgaFile->bitCount / 8;\n\tif (colorMode != 3)\n\t\treturn false;\n\n\tconst uint32 imageSize = tgaFile->imageWidth * tgaFile->imageHeight * colorMode;\n\tif (imageSize + 18 >= buffer.size())\n\t\treturn false;\n\n\ttgaFile->imageData.resize(imageSize);\n\tstd::copy(buffer.data() + 18, buffer.data() + 18 + imageSize, tgaFile->imageData.begin());\n\t// Change from BGR to RGB so OpenGL can read the image data.\n\tfor (uint32 imageIdx = 0; imageIdx < imageSize; imageIdx += colorMode)\n\t{\n\t\tstd::swap(tgaFile->imageData[imageIdx], tgaFile->imageData[imageIdx + 2]);\n\t}\n\n\treturn true;\n}\n\nclass BootSoundPlayer\n{\n  public:\n\tBootSoundPlayer() = default;\n\t~BootSoundPlayer()\n\t{\n\t\tm_stopRequested = true;\n\t}\n\n\tvoid StartSound()\n\t{\n\t\tif (!m_bootSndPlayThread.joinable())\n\t\t{\n\t\t\tm_fadeOutRequested = false;\n\t\t\tm_stopRequested = false;\n\t\t\tm_bootSndPlayThread = std::thread{[this]() {\n\t\t\t\tStreamBootSound();\n\t\t\t}};\n\t\t}\n\t}\n\n\tvoid FadeOutSound()\n\t{\n\t\tm_fadeOutRequested = true;\n\t}\n\n\tvoid ApplyFadeOutEffect(std::span<sint16> samples, uint64& fadeOutSample, uint64 fadeOutDuration)\n\t{\n\t\tfor (size_t i = 0; i < samples.size(); i += 2)\n\t\t{\n\t\t\tconst float decibel = (float)fadeOutSample / fadeOutDuration * -60.0f;\n\t\t\tconst float volumeFactor = pow(10, decibel / 20);\n\t\t\tsamples[i] *= volumeFactor;\n\t\t\tsamples[i + 1] *= volumeFactor;\n\t\t\tfadeOutSample++;\n\t\t}\n\t}\n\n\tvoid StreamBootSound()\n\t{\n\t\tSetThreadName(\"bootsnd\");\n\t\tconstexpr sint32 sampleRate = 48'000;\n\t\tconstexpr sint32 bitsPerSample = 16;\n\t\tconstexpr sint32 samplesPerBlock = sampleRate / 10; // block is 1/10th of a second\n\t\tconstexpr sint32 nChannels = 2;\n\t\tstatic_assert(bitsPerSample % 8 == 0, \"bits per sample is not a multiple of 8\");\n\n\t\tAudioAPIPtr bootSndAudioDev;\n\n\t\ttry\n\t\t{\n\t\t\tbootSndAudioDev = IAudioAPI::CreateDeviceFromConfig(IAudioAPI::AudioType::TV, sampleRate, nChannels, samplesPerBlock, bitsPerSample);\n\t\t\tif(!bootSndAudioDev)\n\t\t\t\treturn;\n\t\t}\n\t\tcatch (const std::runtime_error& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to initialise audio device for bootup sound\");\n\t\t\treturn;\n\t\t}\n\t\tbootSndAudioDev->SetAudioDelayOverride(4);\n\t\tbootSndAudioDev->Play();\n\n\t\tstd::string sndPath = fmt::format(\"{}/meta/{}\", CafeSystem::GetMlcStoragePath(CafeSystem::GetForegroundTitleId()), \"bootSound.btsnd\");\n\t\tsint32 fscStatus = FSC_STATUS_UNDEFINED;\n\n\t\tif(!fsc_doesFileExist(sndPath.c_str()))\n\t\t\treturn;\n\n\t\tFSCVirtualFile* bootSndFileHandle = fsc_open(sndPath.c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);\n\t\tif(!bootSndFileHandle)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"failed to open bootSound.btsnd\");\n\t\t\treturn;\n\t\t}\n\n\t\tconstexpr sint32 audioBlockSize = samplesPerBlock * (bitsPerSample/8) * nChannels;\n\t\tBootSoundReader bootSndFileReader(bootSndFileHandle, audioBlockSize);\n\n\t\tuint64 fadeOutSample = 0; // track how far into the fadeout\n\t\tconstexpr uint64 fadeOutDuration = sampleRate * 2; // fadeout should last 2 seconds\n\t\twhile(fadeOutSample < fadeOutDuration && !m_stopRequested)\n\t\t{\n\t\t\twhile (bootSndAudioDev->NeedAdditionalBlocks())\n\t\t\t{\n\t\t\t\tsint16* data = bootSndFileReader.getSamples();\n\t\t\t\tif(data == nullptr)\n\t\t\t\t{\n\t\t\t\t\t// break outer loop\n\t\t\t\t\tm_stopRequested = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif(m_fadeOutRequested)\n\t\t\t\t\tApplyFadeOutEffect({data, samplesPerBlock * nChannels}, fadeOutSample, fadeOutDuration);\n\n\t\t\t\tbootSndAudioDev->FeedBlock(data);\n\t\t\t}\n\t\t\t// sleep for the duration of a single block\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(samplesPerBlock / (sampleRate/ 1'000)));\n\t\t}\n\n\t\tif(bootSndFileHandle)\n\t\t\tfsc_close(bootSndFileHandle);\n\t}\n\n  private:\n\tstd::thread m_bootSndPlayThread;\n\tstd::atomic_bool m_fadeOutRequested = false;\n\tstd::atomic_bool m_stopRequested = false;\n};\nstatic BootSoundPlayer g_bootSndPlayer;\n\nvoid LatteShaderCache_finish()\n{\n    if (g_renderer->GetType() == RendererAPI::Vulkan)\n\t\tRendererShaderVk::ShaderCacheLoading_end();\n\telse if (g_renderer->GetType() == RendererAPI::OpenGL)\n\t\tRendererShaderGL::ShaderCacheLoading_end();\n#if ENABLE_METAL\n\telse if (g_renderer->GetType() == RendererAPI::Metal)\n\t    RendererShaderMtl::ShaderCacheLoading_end();\n#endif\n}\n\nuint32 LatteShaderCache_getShaderCacheExtraVersion(uint64 titleId)\n{\n\t// encode the titleId in the version to prevent users from swapping caches between titles\n\tconst uint32 cacheFileVersion = 1;\n\tuint32 extraVersion = ((uint32)(titleId >> 32) + ((uint32)titleId) * 3) + cacheFileVersion + 0xe97af1ad;\n\treturn extraVersion;\n}\n\nuint32 LatteShaderCache_getPipelineCacheExtraVersion(uint64 titleId)\n{\n\tconst uint32 cacheFileVersion = 1;\n\tuint32 extraVersion = ((uint32)(titleId >> 32) + ((uint32)titleId) * 3) + cacheFileVersion;\n\treturn extraVersion;\n}\n\nvoid LatteShaderCache_drawBackgroundImage(ImTextureID texture, int width, int height)\n{\n\t// clear framebuffers and clean up\n\tconst auto kPopupFlags =\n\t\t\tImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings |\n\t\t\tImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_AlwaysAutoResize |\n\t\t\tImGuiWindowFlags_NoBringToFrontOnFocus;\n\tauto& io = ImGui::GetIO();\n\tImGui::SetNextWindowPos({0, 0}, ImGuiCond_Always);\n\tImGui::SetNextWindowSize(io.DisplaySize, ImGuiCond_Always);\n\tImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);\n\tImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0, 0});\n\tif (ImGui::Begin(\"Background texture\", nullptr, kPopupFlags))\n\t{\n\t\tif (texture)\n\t\t{\n\t\t\tfloat imageDisplayWidth = io.DisplaySize.x;\n\t\t\tfloat imageDisplayHeight = height * imageDisplayWidth / width;\n\n\t\t\tfloat paddingLeftAndRight = 0.0f;\n\t\t\tfloat paddingTopAndBottom = (io.DisplaySize.y - imageDisplayHeight) / 2.0f;\n\t\t\tif (imageDisplayHeight > io.DisplaySize.y)\n\t\t\t{\n\t\t\t\timageDisplayHeight = io.DisplaySize.y;\n\t\t\t\timageDisplayWidth = width * imageDisplayHeight / height;\n\t\t\t\tpaddingLeftAndRight = (io.DisplaySize.x - imageDisplayWidth) / 2.0f;\n\t\t\t\tpaddingTopAndBottom = 0.0f;\n\t\t\t}\n\n\t\t\tImGui::GetWindowDrawList()->AddImage(texture, ImVec2(paddingLeftAndRight, paddingTopAndBottom),\n\t\t\t\t\t\t\t\t\t\t\t\t ImVec2(io.DisplaySize.x - paddingLeftAndRight,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tio.DisplaySize.y - paddingTopAndBottom), {0, 1}, {1, 0});\n\t\t}\n\t}\n\tImGui::End();\n\tImGui::PopStyleVar(2);\n}\n\nvoid LatteShaderCache_Load()\n{\n\tshaderCacheScreenStats.compiledShaderCount = 0;\n\tshaderCacheScreenStats.vertexShaderCount = 0;\n\tshaderCacheScreenStats.geometryShaderCount = 0;\n\tshaderCacheScreenStats.pixelShaderCount = 0;\n\n\tuint64 cacheTitleId = CafeSystem::GetForegroundTitleId();\n\n\tconst auto timeLoadStart = now_cached();\n\t// remember current amount of committed memory\n#if BOOST_OS_WINDOWS\n\tPROCESS_MEMORY_COUNTERS pmc1;\n\tGetProcessMemoryInfo(GetCurrentProcess(), &pmc1, sizeof(PROCESS_MEMORY_COUNTERS));\n\tLONGLONG totalMem1 = pmc1.PagefileUsage;\n#endif\n\t// init shader parallel compile queue\n\tLatteShaderCache_initCompileQueue();\n\t// create directories\n\tstd::error_code ec;\n\tfs::create_directories(ActiveSettings::GetCachePath(\"shaderCache/transferable\"), ec);\n\tfs::create_directories(ActiveSettings::GetCachePath(\"shaderCache/precompiled\"), ec);\n\t// initialize renderer specific caches\n\tif (g_renderer->GetType() == RendererAPI::Vulkan)\n\t\tRendererShaderVk::ShaderCacheLoading_begin(cacheTitleId);\n\telse if (g_renderer->GetType() == RendererAPI::OpenGL)\n\t\tRendererShaderGL::ShaderCacheLoading_begin(cacheTitleId);\n#if ENABLE_METAL\n\telse if (g_renderer->GetType() == RendererAPI::Metal)\n\t    RendererShaderMtl::ShaderCacheLoading_begin(cacheTitleId);\n#endif\n\n\t// get cache file name\n\tfs::path pathGeneric;\n\tif (g_renderer->GetType() == RendererAPI::Metal)\n\t    pathGeneric = ActiveSettings::GetCachePath(\"shaderCache/transferable/{:016x}_mtlshaders.bin\", cacheTitleId);\n\telse\n\t    pathGeneric = ActiveSettings::GetCachePath(\"shaderCache/transferable/{:016x}_shaders.bin\", cacheTitleId);\n\n\t// calculate extraVersion for transferable and precompiled shader cache\n\tuint32 transferableExtraVersion = SHADER_CACHE_GENERIC_EXTRA_VERSION;\n    s_shaderCacheGeneric = FileCache::Open(pathGeneric, false, transferableExtraVersion); // legacy extra version (1.25.0 - 1.25.1b)\n\tif(!s_shaderCacheGeneric)\n        s_shaderCacheGeneric = FileCache::Open(pathGeneric, true, LatteShaderCache_getShaderCacheExtraVersion(cacheTitleId));\n\tif(!s_shaderCacheGeneric)\n\t{\n\t\t// no shader cache available yet\n\t\tcemuLog_log(LogType::Force, \"Unable to open or create shader cache file \\\"{}\\\"\", _pathToUtf8(pathGeneric));\n\t\tLatteShaderCache_finish();\n\t\treturn;\n\t}\n\ts_shaderCacheGeneric->UseCompression(false);\n\n\t// load/compile cached shaders\n\tsint32 entryCount = s_shaderCacheGeneric->GetMaximumFileIndex();\n\tg_shaderCacheLoaderState.shaderFileCount = s_shaderCacheGeneric->GetFileCount();\n\tg_shaderCacheLoaderState.loadedShaderFiles = 0;\n\n\t// get game background loading image\n\tauto loadBackgroundTexture = [](bool isTV, ImTextureID& out)\n\t{\n\t\tTGAFILE file{};\n\t\tout = nullptr;\n\n\t\tstd::string fileName = isTV ? \"bootTvTex.tga\" : \"bootDRCTex.tga\";\n\n\t\tstd::string texPath = fmt::format(\"{}/meta/{}\", CafeSystem::GetMlcStoragePath(CafeSystem::GetForegroundTitleId()), fileName);\n\t\tsint32 status;\n\t\tauto fscfile = fsc_open(texPath.c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &status);\n\t\tif (fscfile)\n\t\t{\n\t\t\tuint32 size = fsc_getFileSize(fscfile);\n\t\t\tif (size > 0)\n\t\t\t{\n\t\t\t\tstd::vector<uint8> tmpData(size);\n\t\t\t\tfsc_readFile(fscfile, tmpData.data(), size);\n\t\t\t\tconst bool backgroundLoaded = LoadTGAFile(tmpData, &file);\n\n\t\t\t\tif (backgroundLoaded)\n\t\t\t\t\tout = g_renderer->GenerateTexture(file.imageData, { file.imageWidth, file.imageHeight });\n\t\t\t}\n\n\t\t\tfsc_close(fscfile);\n\t\t}\n\t};\n\n\tloadBackgroundTexture(true, g_shaderCacheLoaderState.textureTVId);\n\tloadBackgroundTexture(false, g_shaderCacheLoaderState.textureDRCId);\n\n\tif(GetConfig().play_boot_sound)\n\t\tg_bootSndPlayer.StartSound();\n\n\tsint32 numLoadedShaders = 0;\n\tuint32 loadIndex = 0;\n\n\tauto LoadShadersUpdate = [&]() -> bool\n\t{\n\t\tif (loadIndex >= (uint32)s_shaderCacheGeneric->GetMaximumFileIndex())\n\t\t\treturn false;\n\t\tLatteShaderCache_updateCompileQueue(SHADER_CACHE_COMPILE_QUEUE_SIZE - 2);\n\t\tuint64 name1;\n\t\tuint64 name2;\n\t\tstd::vector<uint8> fileData;\n\t\tif (!s_shaderCacheGeneric->GetFileByIndex(loadIndex, &name1, &name2, fileData))\n\t\t{\n\t\t\tloadIndex++;\n\t\t\treturn true;\n\t\t}\n\t\tg_shaderCacheLoaderState.loadedShaderFiles++;\n\t\tif (LatteShaderCache_readSeparableShader(fileData.data(), fileData.size()) == false)\n\t\t{\n\t\t\t// something is wrong with the stored shader, remove entry from shader cache files\n\t\t\tcemuLog_log(LogType::Force, \"Shader cache entry {} invalid, deleting...\", loadIndex);\n\t\t\ts_shaderCacheGeneric->DeleteFile({name1, name2 });\n\t\t}\n\t\tnumLoadedShaders++;\n\t\tloadIndex++;\n\t\treturn true;\n\t};\n\n\tLatteShaderCache_ShowProgress(LoadShadersUpdate, false);\n\n\tLatteShaderCache_updateCompileQueue(0);\n\t// write load time and RAM usage to log file (in dev build)\n#if BOOST_OS_WINDOWS\n\tconst auto timeLoadEnd = now_cached();\n\tconst auto timeLoad = std::chrono::duration_cast<std::chrono::milliseconds>(timeLoadEnd - timeLoadStart).count();\n\tPROCESS_MEMORY_COUNTERS pmc2;\n\tGetProcessMemoryInfo(GetCurrentProcess(), &pmc2, sizeof(PROCESS_MEMORY_COUNTERS));\n\tLONGLONG totalMem2 = pmc2.PagefileUsage;\n\tLONGLONG memCommited = totalMem2 - totalMem1;\n\tcemuLog_log(LogType::Force, \"Shader cache loaded with {} shaders. Commited mem {}MB. Took {}ms\", numLoadedShaders, (sint32)(memCommited/1024/1024), timeLoad);\n#endif\n\tLatteShaderCache_finish();\n\t// if Vulkan or Metal then also load pipeline cache\n\tif (g_renderer->GetType() == RendererAPI::Vulkan || g_renderer->GetType() == RendererAPI::Metal)\n        LatteShaderCache_LoadPipelineCache(cacheTitleId);\n\n\n\tg_renderer->BeginFrame(true);\n\tif (g_renderer->ImguiBegin(true))\n\t{\n\t\tLatteShaderCache_drawBackgroundImage(g_shaderCacheLoaderState.textureTVId, 1280, 720);\n\t\tg_renderer->ImguiEnd();\n\t}\n\tg_renderer->BeginFrame(false);\n\tif (g_renderer->ImguiBegin(false))\n\t{\n\t\tLatteShaderCache_drawBackgroundImage(g_shaderCacheLoaderState.textureDRCId, 854, 480);\n\t\tg_renderer->ImguiEnd();\n\t}\n\n\tg_renderer->SwapBuffers(true, true);\n\n\tif (g_shaderCacheLoaderState.textureTVId)\n\t\tg_renderer->DeleteTexture(g_shaderCacheLoaderState.textureTVId);\n\tif (g_shaderCacheLoaderState.textureDRCId)\n\t\tg_renderer->DeleteTexture(g_shaderCacheLoaderState.textureDRCId);\n\n\tg_bootSndPlayer.FadeOutSound();\n\n\tif(Latte_GetStopSignal())\n\t\tLatteThread_Exit();\n}\n\nvoid LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateFunc, bool isPipelines)\n{\n\tconst auto kPopupFlags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_AlwaysAutoResize;\n\tconst auto textColor = 0xFF888888;\n\n\tauto lastFrameUpdate = tick_cached();\n\n\twhile (true)\n\t{\n        if (Latte_GetStopSignal())\n            break; // thread stop requested, cancel shader loading\n\t\tbool r = loadUpdateFunc();\n\t\tif (!r)\n\t\t\tbreak;\n\n\t\t// in order to slightly speed up shader loading, we don't update the display if little time passed\n\t\t// this also avoids delayed loading in case third party software caps the framerate at 30\n\t\tif ((tick_cached() - lastFrameUpdate) < std::chrono::milliseconds(1000 / 20)) // -> aim for 20 FPS\n\t\t\tcontinue;\n\n\t\tint w, h;\n\t\tWindowSystem::GetWindowPhysSize(w, h);\n\t\tconst Vector2f window_size{ (float)w,(float)h };\n\n\t\tImGui_GetFont(window_size.y / 32.0f); // = 24 by default\n\t\tImGui_GetFont(window_size.y / 48.0f); // = 16\n\n\t\tg_renderer->BeginFrame(true);\n\t\tif (g_renderer->ImguiBegin(true))\n\t\t{\n\t\t\tauto& io = ImGui::GetIO();\n\n\t\t\t// render background texture\n\t\t\tLatteShaderCache_drawBackgroundImage(g_shaderCacheLoaderState.textureTVId, 1280, 720);\n\n\t\t\tconst auto progress_font = ImGui_GetFont(window_size.y / 32.0f); // = 24 by default\n\t\t\tconst auto shader_count_font = ImGui_GetFont(window_size.y / 48.0f); // = 16\n\n\t\t\tImVec2 position = { window_size.x / 2.0f, window_size.y / 2.0f };\n\t\t\tImVec2 pivot = { 0.5f, 0.5f };\n\t\t\tImVec2 progress_size = { io.DisplaySize.x * 0.5f, 0 };\n\t\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\t\tImGui::SetNextWindowSize(progress_size, ImGuiCond_Always);\n\t\t\tImGui::SetNextWindowBgAlpha(0.8f);\n\t\t\tImGui::PushStyleColor(ImGuiCol_PlotHistogram, textColor);\n\t\t\tImGui::PushStyleColor(ImGuiCol_WindowBg, 0);\n\t\t\tImGui::PushFont(progress_font);\n\n\t\t\tstd::string titleText = \"Shader progress\";\n\n\t\t\tif (ImGui::Begin(titleText.c_str(), nullptr, kPopupFlags))\n\t\t\t{\n\t\t\t\tconst float width = ImGui::GetWindowSize().x / 2.0f;\n\n\t\t\t\tstd::string text;\n\t\t\t\tif (isPipelines)\n\t\t\t\t{\n\t\t\t\t\ttext = \"Loading cached pipelines...\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (shaderCacheScreenStats.compiledShaderCount >= 3)\n\t\t\t\t\t\ttext = \"Compiling cached shaders...\";\n\t\t\t\t\telse\n\t\t\t\t\t\ttext = \"Loading cached shaders...\";\n\t\t\t\t}\n\n\t\t\t\tImGui::SetCursorPosX(width - ImGui::CalcTextSize(text.c_str()).x / 2);\n\t\t\t\tImGui::Text(\"%s\", text.c_str());\n\n\t\t\t\tfloat percentLoaded;\n\t\t\t\tif(isPipelines)\n\t\t\t\t\tpercentLoaded = (float)g_shaderCacheLoaderState.loadedPipelines / (float)g_shaderCacheLoaderState.pipelineFileCount;\n\t\t\t\telse\n\t\t\t\t\tpercentLoaded = (float)g_shaderCacheLoaderState.loadedShaderFiles / (float)g_shaderCacheLoaderState.shaderFileCount;\n\t\t\t\tImGui::ProgressBar(percentLoaded, { -1, 0 }, \"\");\n\n\t\t\t\tif (isPipelines)\n\t\t\t\t\ttext = fmt::format(\"{}/{} ({}%)\", g_shaderCacheLoaderState.loadedPipelines, g_shaderCacheLoaderState.pipelineFileCount, (int)(percentLoaded * 100));\n\t\t\t\telse\n\t\t\t\t\ttext = fmt::format(\"{}/{} ({}%)\", g_shaderCacheLoaderState.loadedShaderFiles, g_shaderCacheLoaderState.shaderFileCount, (int)(percentLoaded * 100));\n\t\t\t\tImGui::SetCursorPosX(width - ImGui::CalcTextSize(text.c_str()).x / 2);\n\t\t\t\tImGui::Text(\"%s\", text.c_str());\n\t\t\t}\n\t\t\tImGui::End();\n\t\t\tImGui::PopFont();\n\t\t\tImGui::PopStyleColor(2);\n\n\t\t\tif (!isPipelines)\n\t\t\t{\n\t\t\t\tposition = { 10, window_size.y - 10 };\n\t\t\t\tpivot = { 0, 1 };\n\t\t\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\t\t\tImGui::SetNextWindowBgAlpha(0.8f);\n\t\t\t\tImGui::PushStyleColor(ImGuiCol_WindowBg, 0);\n\t\t\t\tImGui::PushFont(shader_count_font);\n\t\t\t\tif (ImGui::Begin(\"Shader count\", nullptr, kPopupFlags))\n\t\t\t\t{\n\t\t\t\t\tconst float offset = shader_count_font->FallbackAdvanceX * 25.f;\n\t\t\t\t\tImGui::Text(\"Vertex shaders\");\n\t\t\t\t\tImGui::SameLine(offset);\n\t\t\t\t\tImGui::Text(\"%d\", shaderCacheScreenStats.vertexShaderCount);\n\n\t\t\t\t\tImGui::Text(\"Pixel shaders\");\n\t\t\t\t\tImGui::SameLine(offset);\n\t\t\t\t\tImGui::Text(\"%d\", shaderCacheScreenStats.pixelShaderCount);\n\n\t\t\t\t\tImGui::Text(\"Geometry shaders\");\n\t\t\t\t\tImGui::SameLine(offset);\n\t\t\t\t\tImGui::Text(\"%d\", shaderCacheScreenStats.geometryShaderCount);\n\t\t\t\t}\n\t\t\t\tImGui::End();\n\t\t\t\tImGui::PopStyleColor();\n\t\t\t\tImGui::PopFont();\n\t\t\t}\n\t\t\tg_renderer->ImguiEnd();\n\t\t\tlastFrameUpdate = tick_cached();\n\t\t}\n\n\t\tg_renderer->BeginFrame(false);\n\t\tif (g_renderer->ImguiBegin(false))\n\t\t{\n\t\t\tLatteShaderCache_drawBackgroundImage(g_shaderCacheLoaderState.textureDRCId, 854, 480);\n\t\t\tg_renderer->ImguiEnd();\n\t\t}\n\n\t\t// finish frame\n\t\tg_renderer->SwapBuffers(true, true);\n\t}\n}\n\nvoid LatteShaderCache_LoadPipelineCache(uint64 cacheTitleId)\n{\n\tif (g_renderer->GetType() == RendererAPI::Vulkan)\n\t    g_shaderCacheLoaderState.pipelineFileCount = VulkanPipelineStableCache::GetInstance().BeginLoading(cacheTitleId);\n#if ENABLE_METAL\n\telse if (g_renderer->GetType() == RendererAPI::Metal)\n\t\tg_shaderCacheLoaderState.pipelineFileCount = MetalPipelineCache::GetInstance().BeginLoading(cacheTitleId);\n#endif\n\tg_shaderCacheLoaderState.loadedPipelines = 0;\n\tLatteShaderCache_ShowProgress(LatteShaderCache_updatePipelineLoadingProgress, true);\n\tif (g_renderer->GetType() == RendererAPI::Vulkan)\n\t    VulkanPipelineStableCache::GetInstance().EndLoading();\n#if ENABLE_METAL\n\telse if (g_renderer->GetType() == RendererAPI::Metal)\n\t\tMetalPipelineCache::GetInstance().EndLoading();\n#endif\n}\n\nbool LatteShaderCache_updatePipelineLoadingProgress()\n{\n\tuint32 pipelinesMissingShaders = 0;\n\tif (g_renderer->GetType() == RendererAPI::Vulkan)\n\t    return VulkanPipelineStableCache::GetInstance().UpdateLoading(g_shaderCacheLoaderState.loadedPipelines, pipelinesMissingShaders);\n#if ENABLE_METAL\n\telse if (g_renderer->GetType() == RendererAPI::Metal)\n\t\treturn MetalPipelineCache::GetInstance().UpdateLoading(g_shaderCacheLoaderState.loadedPipelines, pipelinesMissingShaders);\n#endif\n\n\treturn false;\n}\n\nuint64 LatteShaderCache_getShaderNameInTransferableCache(uint64 baseHash, uint32 shaderType)\n{\n\tbaseHash &= ~(7ULL << 61ULL);\n\tbaseHash |= ((uint64)shaderType << 61ULL);\n\treturn baseHash;\n}\n\nvoid LatteShaderCache_writeSeparableVertexShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* fetchShader, uint32 fetchShaderSize, uint8* vertexShader, uint32 vertexShaderSize, uint32* contextRegisters, bool usesGeometryShader)\n{\n\tif (!s_shaderCacheGeneric)\n\t\treturn;\n\tMemStreamWriter streamWriter(128 * 1024);\n\t// header\n\tstreamWriter.writeBE<uint8>(1 | (SHADER_CACHE_TYPE_VERTEX << 4)); // version and type (shared field)\n\tstreamWriter.writeBE<uint64>(shaderBaseHash);\n\tstreamWriter.writeBE<uint64>(shaderAuxHash);\n\tstreamWriter.writeBE<uint8>(usesGeometryShader ? 1 : 0);\n\t// register state\n\tLatte::GPUCompactedRegisterState compactRegState;\n\tLatte::StoreGPURegisterState(*(LatteContextRegister*)contextRegisters, compactRegState);\n\tLatte::SerializeRegisterState(compactRegState, streamWriter);\n\t// fetch shader\n\tLatte::SerializeShaderProgram(fetchShader, fetchShaderSize, streamWriter);\n\t// vertex shader\n\tLatte::SerializeShaderProgram(vertexShader, vertexShaderSize, streamWriter);\n\t// write to cache\n\tuint64 shaderCacheName = LatteShaderCache_getShaderNameInTransferableCache(shaderBaseHash, SHADER_CACHE_TYPE_VERTEX);\n\tstd::span<uint8> dataBlob = streamWriter.getResult();\n\ts_shaderCacheGeneric->AddFileAsync({shaderCacheName, shaderAuxHash }, dataBlob.data(), dataBlob.size());\n}\n\nvoid LatteShaderCache_writeSeparableGeometryShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* geometryShader, uint32 geometryShaderSize, uint8* gsCopyShader, uint32 gsCopyShaderSize, uint32* contextRegisters, uint32* hleSpecialState, uint32 vsRingParameterCount)\n{\n\tif (!s_shaderCacheGeneric)\n\t\treturn;\n\tMemStreamWriter streamWriter(128 * 1024);\n\t// header\n\tstreamWriter.writeBE<uint8>(1 | (SHADER_CACHE_TYPE_GEOMETRY << 4)); // version and type (shared field)\n\tstreamWriter.writeBE<uint64>(shaderBaseHash);\n\tstreamWriter.writeBE<uint64>(shaderAuxHash);\n\tcemu_assert_debug(vsRingParameterCount < 0x10000);\n\tstreamWriter.writeBE<uint16>(vsRingParameterCount);\n\t// register state\n\tLatte::GPUCompactedRegisterState compactRegState;\n\tLatte::StoreGPURegisterState(*(LatteContextRegister*)contextRegisters, compactRegState);\n\tLatte::SerializeRegisterState(compactRegState, streamWriter);\n\t// geometry copy shader\n\tLatte::SerializeShaderProgram(gsCopyShader, gsCopyShaderSize, streamWriter);\n\t// geometry shader\n\tLatte::SerializeShaderProgram(geometryShader, geometryShaderSize, streamWriter);\n\t// write to cache\n\tuint64 shaderCacheName = LatteShaderCache_getShaderNameInTransferableCache(shaderBaseHash, SHADER_CACHE_TYPE_GEOMETRY);\n\tstd::span<uint8> dataBlob = streamWriter.getResult();\n\ts_shaderCacheGeneric->AddFileAsync({shaderCacheName, shaderAuxHash }, dataBlob.data(), dataBlob.size());\n}\n\nvoid LatteShaderCache_writeSeparablePixelShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* pixelShader, uint32 pixelShaderSize, uint32* contextRegisters, bool usesGeometryShader)\n{\n\tif (!s_shaderCacheGeneric)\n\t\treturn;\n\tMemStreamWriter streamWriter(128 * 1024);\n\tstreamWriter.writeBE<uint8>(1 | (SHADER_CACHE_TYPE_PIXEL << 4)); // version and type (shared field)\n\tstreamWriter.writeBE<uint64>(shaderBaseHash);\n\tstreamWriter.writeBE<uint64>(shaderAuxHash);\n\tstreamWriter.writeBE<uint8>(usesGeometryShader ? 1 : 0);\n\t// register state\n\tLatte::GPUCompactedRegisterState compactRegState;\n\tLatte::StoreGPURegisterState(*(LatteContextRegister*)contextRegisters, compactRegState);\n\tLatte::SerializeRegisterState(compactRegState, streamWriter);\n\t// pixel shader\n\tLatte::SerializeShaderProgram(pixelShader, pixelShaderSize, streamWriter);\n\t// write to cache\n\tuint64 shaderCacheName = LatteShaderCache_getShaderNameInTransferableCache(shaderBaseHash, SHADER_CACHE_TYPE_PIXEL);\n\tstd::span<uint8> dataBlob = streamWriter.getResult();\n\ts_shaderCacheGeneric->AddFileAsync({shaderCacheName, shaderAuxHash }, dataBlob.data(), dataBlob.size());\n}\n\nvoid LatteShaderCache_loadOrCompileSeparableShader(LatteDecompilerShader* shader, uint64 shaderBaseHash, uint64 shaderAuxHash)\n{\n\tRendererShader::ShaderType shaderType;\n\tif (shader->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n\t\tshaderType = RendererShader::ShaderType::kVertex;\n\t\tshaderCacheScreenStats.vertexShaderCount++;\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Geometry)\n\t{\n\t\tshaderType = RendererShader::ShaderType::kGeometry;\n\t\tshaderCacheScreenStats.geometryShaderCount++;\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t{\n\t\tshaderType = RendererShader::ShaderType::kFragment;\n\t\tshaderCacheScreenStats.pixelShaderCount++;\n\t}\n\t// compile shader\n\tshaderCacheScreenStats.compiledShaderCount++;\n\tLatteShader_CreateRendererShader(shader, true);\n\tif (shader->shader == nullptr)\n\t\treturn;\n\tLatteShaderCache_addToCompileQueue(shader);\n}\n\nbool LatteShaderCache_readSeparableVertexShader(MemStreamReader& streamReader, uint8 version)\n{\n\tauto lcr = std::make_unique<LatteContextRegister>();\n\tif (version != 1)\n\t\treturn false;\n\tuint64 shaderBaseHash = streamReader.readBE<uint64>();\n\tuint64 shaderAuxHash = streamReader.readBE<uint64>();\n\tbool usesGeometryShader = streamReader.readBE<uint8>() != 0;\n\t// context registers\n\tLatte::GPUCompactedRegisterState regState;\n\tif (!Latte::DeserializeRegisterState(regState, streamReader))\n\t\treturn false;\n\tLatte::LoadGPURegisterState(*lcr, regState);\n\tif (streamReader.hasError())\n\t\treturn false;\n\t// fetch shader\n\tstd::vector<uint8> fetchShaderData;\n\tif (!Latte::DeserializeShaderProgram(fetchShaderData, streamReader))\n\t\treturn false;\n\tif (streamReader.hasError())\n\t\treturn false;\n\t// vertex shader\n\tstd::vector<uint8> vertexShaderData;\n\tif (!Latte::DeserializeShaderProgram(vertexShaderData, streamReader))\n\t\treturn false;\n\tif (streamReader.hasError() || !streamReader.isEndOfStream())\n\t\treturn false;\n\t// update PS inputs (affects VS shader outputs)\n\tLatteShader_UpdatePSInputs(lcr->GetRawView());\n\t// get fetch shader\n\tLatteFetchShader::CacheHash fsHash = LatteFetchShader::CalculateCacheHash((uint32*)fetchShaderData.data(), fetchShaderData.size());\n\tLatteFetchShader* fetchShader = LatteShaderRecompiler_createFetchShader(fsHash, lcr->GetRawView(), (uint32*)fetchShaderData.data(), fetchShaderData.size());\n\t// determine decompiler options\n\tLatteDecompilerOptions options;\n\tLatteShader_GetDecompilerOptions(options, LatteConst::ShaderType::Vertex, usesGeometryShader);\n\t// decompile vertex shader\n\tLatteDecompilerOutput_t decompilerOutput{};\n\tLatteDecompiler_DecompileVertexShader(shaderBaseHash, lcr->GetRawView(), vertexShaderData.data(), vertexShaderData.size(), fetchShader, options, &decompilerOutput);\n\tLatteDecompilerShader* vertexShader = LatteShader_CreateShaderFromDecompilerOutput(decompilerOutput, shaderBaseHash, false, shaderAuxHash, lcr->GetRawView());\n\t// compile\n\tLatteShader_DumpShader(shaderBaseHash, shaderAuxHash, vertexShader);\n\tLatteShader_DumpRawShader(shaderBaseHash, shaderAuxHash, SHADER_DUMP_TYPE_VERTEX, vertexShaderData.data(), vertexShaderData.size());\n\tLatteShaderCache_loadOrCompileSeparableShader(vertexShader, shaderBaseHash, shaderAuxHash);\n\tLatteSHRC_RegisterShader(vertexShader, shaderBaseHash, shaderAuxHash);\n\treturn true;\n}\n\nbool LatteShaderCache_readSeparableGeometryShader(MemStreamReader& streamReader, uint8 version)\n{\n\tif (version != 1)\n\t\treturn false;\n\tauto lcr = std::make_unique<LatteContextRegister>();\n\tuint64 shaderBaseHash = streamReader.readBE<uint64>();\n\tuint64 shaderAuxHash = streamReader.readBE<uint64>();\n\tuint32 vsRingParameterCount = streamReader.readBE<uint16>();\n\t// context registers\n\tLatte::GPUCompactedRegisterState regState;\n\tif (!Latte::DeserializeRegisterState(regState, streamReader))\n\t\treturn false;\n\tLatte::LoadGPURegisterState(*lcr, regState);\n\tif (streamReader.hasError())\n\t\treturn false;\n\t// geometry copy shader\n\tstd::vector<uint8> geometryCopyShaderData;\n\tif (!Latte::DeserializeShaderProgram(geometryCopyShaderData, streamReader))\n\t\treturn false;\n\t// geometry shader\n\tstd::vector<uint8> geometryShaderData;\n\tif (!Latte::DeserializeShaderProgram(geometryShaderData, streamReader))\n\t\treturn false;\n\tif (streamReader.hasError() || !streamReader.isEndOfStream())\n\t\treturn false;\n\t// update PS inputs\n\tLatteShader_UpdatePSInputs(lcr->GetRawView());\n\t// determine decompiler options\n\tLatteDecompilerOptions options;\n\tLatteShader_GetDecompilerOptions(options, LatteConst::ShaderType::Geometry, true);\n\t// decompile geometry shader\n\tLatteDecompilerOutput_t decompilerOutput{};\n\tLatteDecompiler_DecompileGeometryShader(shaderBaseHash, lcr->GetRawView(), geometryShaderData.data(), geometryShaderData.size(), geometryCopyShaderData.data(), geometryCopyShaderData.size(), vsRingParameterCount, options, &decompilerOutput);\n\tLatteDecompilerShader* geometryShader = LatteShader_CreateShaderFromDecompilerOutput(decompilerOutput, shaderBaseHash, false, shaderAuxHash, lcr->GetRawView());\n\t// compile\n\tLatteShader_DumpShader(shaderBaseHash, shaderAuxHash, geometryShader);\n\tLatteShader_DumpRawShader(shaderBaseHash, shaderAuxHash, SHADER_DUMP_TYPE_GEOMETRY, geometryShaderData.data(), geometryShaderData.size());\n\tLatteShaderCache_loadOrCompileSeparableShader(geometryShader, shaderBaseHash, shaderAuxHash);\n\tLatteSHRC_RegisterShader(geometryShader, shaderBaseHash, shaderAuxHash);\n\treturn true;\n}\n\nbool LatteShaderCache_readSeparablePixelShader(MemStreamReader& streamReader, uint8 version)\n{\n\tif (version != 1)\n\t\treturn false;\n\tauto lcr = std::make_unique<LatteContextRegister>();\n\tuint64 shaderBaseHash = streamReader.readBE<uint64>();\n\tuint64 shaderAuxHash = streamReader.readBE<uint64>();\n\tbool usesGeometryShader = streamReader.readBE<uint8>() != 0;\n\t// context registers\n\tLatte::GPUCompactedRegisterState regState;\n\tif (!Latte::DeserializeRegisterState(regState, streamReader))\n\t\treturn false;\n\tLatte::LoadGPURegisterState(*lcr, regState);\n\tif (streamReader.hasError())\n\t\treturn false;\n\t// pixel shader\n\tstd::vector<uint8> pixelShaderData;\n\tif (!Latte::DeserializeShaderProgram(pixelShaderData, streamReader))\n\t\treturn false;\n\tif (streamReader.hasError() || !streamReader.isEndOfStream())\n\t\treturn false;\n\t// update PS inputs\n\tLatteShader_UpdatePSInputs(lcr->GetRawView());\n\t// determine decompiler options\n\tLatteDecompilerOptions options;\n\tLatteShader_GetDecompilerOptions(options, LatteConst::ShaderType::Pixel, usesGeometryShader);\n\t// decompile pixel shader\n\tLatteDecompilerOutput_t decompilerOutput{};\n\tLatteDecompiler_DecompilePixelShader(shaderBaseHash, lcr->GetRawView(), pixelShaderData.data(), pixelShaderData.size(), options, &decompilerOutput);\n\tLatteDecompilerShader* pixelShader = LatteShader_CreateShaderFromDecompilerOutput(decompilerOutput, shaderBaseHash, false, shaderAuxHash, lcr->GetRawView());\n\t// compile\n\tLatteShader_DumpShader(shaderBaseHash, shaderAuxHash, pixelShader);\n\tLatteShader_DumpRawShader(shaderBaseHash, shaderAuxHash, SHADER_DUMP_TYPE_PIXEL, pixelShaderData.data(), pixelShaderData.size());\n\tLatteShaderCache_loadOrCompileSeparableShader(pixelShader, shaderBaseHash, shaderAuxHash);\n\tLatteSHRC_RegisterShader(pixelShader, shaderBaseHash, shaderAuxHash);\n\treturn true;\n}\n\n// read shader info from shader cache\nbool LatteShaderCache_readSeparableShader(uint8* shaderInfoData, sint32 shaderInfoSize)\n{\n\tif (shaderInfoSize < 8)\n\t\treturn false;\n\tMemStreamReader streamReader(shaderInfoData, shaderInfoSize);\n\tuint8 versionAndType = streamReader.readBE<uint8>();\n\tuint8 version = versionAndType & 0xF;\n\tuint8 type = (versionAndType >> 4) & 0xF;\n\tif (type == SHADER_CACHE_TYPE_VERTEX)\n\t\treturn LatteShaderCache_readSeparableVertexShader(streamReader, version);\n\telse if (type == SHADER_CACHE_TYPE_GEOMETRY)\n\t\treturn LatteShaderCache_readSeparableGeometryShader(streamReader, version);\n\telse if (type == SHADER_CACHE_TYPE_PIXEL)\n\t\treturn LatteShaderCache_readSeparablePixelShader(streamReader, version);\n\treturn false;\n}\n\nvoid LatteShaderCache_Close()\n{\n    if(s_shaderCacheGeneric)\n    {\n        delete s_shaderCacheGeneric;\n        s_shaderCacheGeneric = nullptr;\n    }\n    if (g_renderer->GetType() == RendererAPI::Vulkan)\n\t\tRendererShaderVk::ShaderCacheLoading_Close();\n\telse if (g_renderer->GetType() == RendererAPI::OpenGL)\n\t\tRendererShaderGL::ShaderCacheLoading_Close();\n#if ENABLE_METAL\n\telse if (g_renderer->GetType() == RendererAPI::Metal)\n\t    RendererShaderMtl::ShaderCacheLoading_Close();\n#endif\n\n    // if Vulkan or Metal then also close pipeline cache\n    if (g_renderer->GetType() == RendererAPI::Vulkan)\n        VulkanPipelineStableCache::GetInstance().Close();\n#if ENABLE_METAL\n    else if (g_renderer->GetType() == RendererAPI::Metal)\n        MetalPipelineCache::GetInstance().Close();\n#endif\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteShaderCache.h",
    "content": "#pragma once\n\nuint32 LatteShaderCache_getShaderCacheExtraVersion(uint64 titleId);\nuint32 LatteShaderCache_getPipelineCacheExtraVersion(uint64 titleId);"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteShaderGL.cpp",
    "content": "#include \"Common/GLInclude/GLInclude.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h\"\n#include \"util/helpers/StringBuf.h\"\n\nbool gxShader_checkIfSuccessfullyLinked(GLuint glProgram)\n{\n\tint status = -1;\n\tglGetProgramiv(glProgram, GL_LINK_STATUS, &status);\n\tif( status == GL_TRUE )\n\t\treturn true;\n\t// in debug mode, get and print shader error log\n\tchar infoLog[48*1024];\n\tuint32 infoLogLength, tempLength;\n\tglGetProgramiv(glProgram, GL_INFO_LOG_LENGTH, (GLint *)&infoLogLength);\n\ttempLength = sizeof(infoLog)-1;\n\tglGetProgramInfoLog(glProgram, std::min(tempLength, infoLogLength), (GLsizei*)&tempLength, (GLcharARB*)infoLog);\n\tinfoLog[tempLength] = '\\0';\n\tcemuLog_log(LogType::Force, \"Link error in raw shader\");\n\tcemuLog_log(LogType::Force, infoLog);\n\treturn false;\n}\n\nvoid LatteShader_prepareSeparableUniforms(LatteDecompilerShader* shader)\n{\n\tif (g_renderer->GetType() != RendererAPI::OpenGL)\n\t\treturn;\n\n\tauto shaderGL = (RendererShaderGL*)shader->shader;\n\t// setup uniform info\n\tif (shader->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n\t\tshader->uniform.loc_remapped = glGetUniformLocation(shaderGL->GetProgram(), \"uf_remappedVS\");\n\t\tshader->uniform.loc_uniformRegister = glGetUniformLocation(shaderGL->GetProgram(), \"uf_uniformRegisterVS\");\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Geometry)\n\t{\n\t\tshader->uniform.loc_remapped = glGetUniformLocation(shaderGL->GetProgram(), \"uf_remappedGS\");\n\t\tshader->uniform.loc_uniformRegister = glGetUniformLocation(shaderGL->GetProgram(), \"uf_uniformRegisterGS\");\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t{\n\t\tshader->uniform.loc_remapped = glGetUniformLocation(shaderGL->GetProgram(), \"uf_remappedPS\");\n\t\tshader->uniform.loc_uniformRegister = glGetUniformLocation(shaderGL->GetProgram(), \"uf_uniformRegisterPS\");\n\t}\n\tcatchOpenGLError();\n\tshader->uniform.loc_windowSpaceToClipSpaceTransform = glGetUniformLocation(shaderGL->GetProgram(), \"uf_windowSpaceToClipSpaceTransform\");\n\tshader->uniform.loc_alphaTestRef = glGetUniformLocation(shaderGL->GetProgram(), \"uf_alphaTestRef\");\n\tshader->uniform.loc_pointSize = glGetUniformLocation(shaderGL->GetProgram(), \"uf_pointSize\");\n\tshader->uniform.loc_fragCoordScale = glGetUniformLocation(shaderGL->GetProgram(), \"uf_fragCoordScale\");\n\tcemu_assert_debug(shader->uniform.list_ufTexRescale.empty());\n\tfor (sint32 t = 0; t < LATTE_NUM_MAX_TEX_UNITS; t++)\n\t{\n\t\tchar ufName[64];\n\t\tsprintf(ufName, \"uf_tex%dScale\", t);\n\t\tGLint uniformLocation = glGetUniformLocation(shaderGL->GetProgram(), ufName);\n\t\tif (uniformLocation >= 0)\n\t\t{\n\t\t\tLatteUniformTextureScaleEntry_t entry = { 0 };\n\t\t\tentry.texUnit = t;\n\t\t\tentry.uniformLocation = uniformLocation;\n\t\t\tshader->uniform.list_ufTexRescale.push_back(entry);\n\t\t}\n\t}\n}\nGLuint gpu7ShaderGLDepr_compileShader(const std::string& source, uint32_t type)\n{\n\tcemu_assert(type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER);\n\tconst GLuint shader_object = glCreateShader(type);\n\n\tconst char *c_str = source.c_str();\n\tconst GLint size = (GLint)source.size();\n\tglShaderSource(shader_object, 1, &c_str, &size);\n\tglCompileShader(shader_object);\n\n\tGLint log_length;\n\tglGetShaderiv(shader_object, GL_INFO_LOG_LENGTH, &log_length);\n\tif (log_length > 0)\n\t{\n\t\tchar log[2048]{};\n\t\tGLsizei log_size;\n\t\tglGetShaderInfoLog(shader_object, std::min(log_length, (GLint)sizeof(log) - 1), &log_size, log);\n\t\tcemuLog_log(LogType::Force, \"Error/Warning in vertex shader:\");\n\t\tcemuLog_log(LogType::Force, log);\n\t}\n\n\treturn shader_object;\n}\nGLuint gpu7ShaderGLDepr_compileVertexShader(const std::string& source)\n{\n\treturn gpu7ShaderGLDepr_compileShader(source, GL_VERTEX_SHADER);\n}\n\nGLuint gpu7ShaderGLDepr_compileFragmentShader(const std::string& source)\n{\n\treturn gpu7ShaderGLDepr_compileShader(source, GL_FRAGMENT_SHADER);\n}\n\nGLuint gpu7ShaderGLDepr_compileVertexShader(const char* shaderSource, sint32 shaderSourceLength)\n{\n\tuint32 shaderObject = glCreateShader(GL_VERTEX_SHADER);\n\tGLchar* srcPtr = (GLchar*)shaderSource;\n\tGLint srcLen = shaderSourceLength;\n\tglShaderSource(shaderObject, 1, &srcPtr, &srcLen);\n\tglCompileShader(shaderObject);\n\tuint32 shaderLogLengthInfo, shaderLogLen;\n\tglGetShaderiv(shaderObject, GL_INFO_LOG_LENGTH, (GLint *)&shaderLogLengthInfo);\n\tif (shaderLogLengthInfo > 0)\n\t{\n\t\tchar messageLog[2048]{};\n\t\tglGetShaderInfoLog(shaderObject, std::min<uint32>(shaderLogLengthInfo, sizeof(messageLog) - 1), (GLsizei*)&shaderLogLen, (GLcharARB*)messageLog);\n\t\tcemuLog_log(LogType::Force, \"Error/Warning in vertex shader:\");\n\t\tcemuLog_log(LogType::Force, messageLog);\n\t}\n\treturn shaderObject;\n}\n\nGLuint gpu7ShaderGLDepr_compileFragmentShader(const char* shaderSource, sint32 shaderSourceLength)\n{\n\tuint32 shaderObject = glCreateShader(GL_FRAGMENT_SHADER);\n\tGLchar* srcPtr = (GLchar*)shaderSource;\n\tGLint srcLen = shaderSourceLength;\n\tglShaderSource(shaderObject, 1, &srcPtr, &srcLen);\n\tglCompileShader(shaderObject);\n\tuint32 shaderLogLengthInfo, shaderLogLen;\n\tchar messageLog[2048];\n\tglGetShaderiv(shaderObject, GL_INFO_LOG_LENGTH, (GLint *)&shaderLogLengthInfo);\n\tif (shaderLogLengthInfo > 0)\n\t{\n\t\tmemset(messageLog, 0, sizeof(messageLog));\n\t\tglGetShaderInfoLog(shaderObject, std::min<uint32>(shaderLogLengthInfo, sizeof(messageLog) - 1), (GLsizei*)&shaderLogLen, (GLcharARB*)messageLog);\n\t\tcemuLog_log(LogType::Force, \"Error/Warning in fragment shader:\");\n\t\tcemuLog_log(LogType::Force, messageLog);\n\t}\n\treturn shaderObject;\n}\n\nGLuint gxShaderDepr_compileRaw(StringBuf* strSourceVS, StringBuf* strSourceFS)\n{\n\tGLuint glShaderProgram = glCreateProgram();\n\tGLuint vertexShader = gpu7ShaderGLDepr_compileVertexShader(strSourceVS->c_str(), strSourceVS->getLen());\n\tglAttachShader(glShaderProgram, vertexShader);\n\tGLuint fragmentShader = gpu7ShaderGLDepr_compileFragmentShader(strSourceFS->c_str(), strSourceFS->getLen());\n\tglAttachShader(glShaderProgram, fragmentShader);\n\tglLinkProgram(glShaderProgram);\n\tif( gxShader_checkIfSuccessfullyLinked(glShaderProgram) == false )\n\t{\n\t\treturn 0;\n\t}\n\treturn glShaderProgram;\n}\n\nGLuint gxShaderDepr_compileRaw(const std::string& vertex_source, const std::string& fragment_source)\n{\n\tconst GLuint programm = glCreateProgram();\n\n\tauto vertex_shader = std::async(std::launch::deferred, gpu7ShaderGLDepr_compileShader, vertex_source, GL_VERTEX_SHADER);\n\tauto fragment_shader = std::async(std::launch::deferred, gpu7ShaderGLDepr_compileShader, fragment_source, GL_FRAGMENT_SHADER);\n\n\tglAttachShader(programm, vertex_shader.get());\n\tglAttachShader(programm, fragment_shader.get());\n\n\tglLinkProgram(programm);\n\treturn gxShader_checkIfSuccessfullyLinked(programm) ? programm : 0;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteSoftware.cpp",
    "content": "#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n\n#define GPU7_ENDIAN_8IN32 2\n\ntypedef struct  \n{\n\tunion\n\t{\n\t\tfloat f[4];\n\t\tuint32 u32[4];\n\t\tsint32 s32[4];\n\t};\n}LatteReg_t;\n\n#define REG_AR\t(128)\n\ntypedef struct  \n{\n\tLatteReg_t reg[128+1];\n\tunion\n\t{\n\t\tuint32 u32[5];\n\t\tsint32 s32[5];\n\t\tfloat f[5];\n\t}pvps;\n\tunion\n\t{\n\t\tuint32 u32[5];\n\t\tsint32 s32[5];\n\t\tfloat f[5];\n\t}pvpsUpdate;\n\tvoid* cfilePtr;\n\tLatteReg_t* literalPtr;\n\t// cbank\n\tLatteReg_t* cbank0;\n\tLatteReg_t* cbank1;\n\t// vertex shader exports\n\tLatteReg_t export_pos;\n\n\tuint32* shaderBase;\n\tsint32 shaderSize;\n\t// shaders\n\tLatteFetchShader* fetchShader;\n}LatteSoftwareExecContext_t;\n\nLatteSoftwareExecContext_t LatteSWCtx;\n\nchar _tempStringBuf[2048];\nsint32 tempStringIndex = 0;\n\nchar* getTempString()\n{\n\ttempStringIndex = (tempStringIndex + 1) % 10;\n\treturn _tempStringBuf + tempStringIndex * (sizeof(_tempStringBuf) / 10);\n}\n\nconst char* _getSrcName(uint32 srcSel, uint32 srcChan)\n{\n\tif (GPU7_ALU_SRC_IS_GPR(srcSel))\n\t{\n\t\tchar* tempStr = getTempString();\n\t\tsprintf(tempStr, \"R%d\", srcSel & 0x7F);\n\t\tif (srcChan == 0)\n\t\t\tstrcat(tempStr, \".x\");\n\t\telse if (srcChan == 1)\n\t\t\tstrcat(tempStr, \".y\");\n\t\telse if (srcChan == 2)\n\t\t\tstrcat(tempStr, \".z\");\n\t\telse\n\t\t\tstrcat(tempStr, \".w\");\n\t\treturn tempStr;\n\t}\n\telse if (GPU7_ALU_SRC_IS_CFILE(srcSel))\n\t{\n\t\treturn \"CFILE\";\n\t}\n\telse if (GPU7_ALU_SRC_IS_PV(srcSel))\n\t{\n\t\treturn \"PV\";\n\t}\n\telse if (GPU7_ALU_SRC_IS_PS(srcSel))\n\t{\n\t\treturn \"PS\";\n\t}\n\telse if (GPU7_ALU_SRC_IS_CBANK0(srcSel))\n\t{\n\t\treturn \"CBANK0\";\n\t}\n\telse if (GPU7_ALU_SRC_IS_CBANK1(srcSel))\n\t{\n\t\treturn \"CBANK1\";\n\t}\n\telse if (GPU7_ALU_SRC_IS_CONST_0F(srcSel))\n\t{\n\t\treturn \"0.0\";\n\t}\n\telse if (GPU7_ALU_SRC_IS_CONST_1F(srcSel))\n\t{\n\t\treturn \"1.0\";\n\t}\n\telse if (GPU7_ALU_SRC_IS_CONST_0_5F(srcSel))\n\t{\n\t\treturn \"0.5\";\n\t}\n\telse if (GPU7_ALU_SRC_IS_LITERAL(srcSel))\n\t{\n\t\treturn \"LITERAL\";\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\treturn \"UKN\";\n}\n\nsint32 _getSrc_genericS32(uint32 srcSel, uint32 srcChan, uint32 srcRel, uint32 indexMode)\n{\n\tsint32 v = 0;\n\tif (GPU7_ALU_SRC_IS_GPR(srcSel))\n\t{\n\t\tcemu_assert_debug(srcRel == 0);\n\t\tv = LatteSWCtx.reg[GPU7_ALU_SRC_GET_GPR_INDEX(srcSel)].s32[srcChan];\n\t}\n\telse if (GPU7_ALU_SRC_IS_CFILE(srcSel))\n\t{\n\t\tif (srcRel)\n\t\t{\n\t\t\tif (indexMode <= GPU7_INDEX_AR_W)\n\t\t\t{\n\t\t\t\tv = ((sint32*)LatteSWCtx.cfilePtr)[LatteSWCtx.reg[REG_AR].s32[indexMode] * 4 + GPU7_ALU_SRC_GET_CFILE_INDEX(srcSel) * 4 + srcChan];\n\t\t\t}\n\t\t\telse\n\t\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tv = ((sint32*)LatteSWCtx.cfilePtr)[GPU7_ALU_SRC_GET_CFILE_INDEX(srcSel) * 4 + srcChan];\n\t\t}\n\t}\n\telse if (GPU7_ALU_SRC_IS_PV(srcSel))\n\t{\n\t\tcemu_assert_debug(srcRel == 0);\n\t\tv = LatteSWCtx.pvps.s32[srcChan];\n\t}\n\telse if (GPU7_ALU_SRC_IS_PS(srcSel))\n\t{\n\t\tcemu_assert_debug(srcRel == 0);\n\t\tv = LatteSWCtx.pvps.s32[4];\n\t}\n\telse if (GPU7_ALU_SRC_IS_CBANK0(srcSel))\n\t{\n\t\tif (srcRel)\n\t\t{\n\t\t\tif (indexMode <= GPU7_INDEX_AR_W)\n\t\t\t{\n\t\t\t\tv = LatteSWCtx.cbank0[LatteSWCtx.reg[REG_AR].s32[indexMode] + GPU7_ALU_SRC_GET_CBANK0_INDEX(srcSel)].s32[srcChan];\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tv = LatteSWCtx.cbank0[GPU7_ALU_SRC_GET_CBANK0_INDEX(srcSel)].s32[srcChan];\n\t\t}\n\t}\n\telse if (GPU7_ALU_SRC_IS_CBANK1(srcSel))\n\t{\n\t\tif (srcRel)\n\t\t{\n\t\t\tif (indexMode <= GPU7_INDEX_AR_W)\n\t\t\t{\n\t\t\t\tv = LatteSWCtx.cbank1[LatteSWCtx.reg[REG_AR].s32[indexMode] + GPU7_ALU_SRC_GET_CBANK1_INDEX(srcSel)].s32[srcChan];\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tv = LatteSWCtx.cbank1[GPU7_ALU_SRC_GET_CBANK1_INDEX(srcSel)].s32[srcChan];\n\t\t}\n\t}\n\telse if (GPU7_ALU_SRC_IS_CONST_0F(srcSel))\n\t{\n\t\tcemu_assert_debug(srcRel == 0);\n\t\tv = 0; // 0.0f\n\t}\n\telse if (GPU7_ALU_SRC_IS_CONST_1F(srcSel))\n\t{\n\t\tcemu_assert_debug(srcRel == 0);\n\t\tv = 0x3f800000; // 1.0f\n\t}\n\telse if (GPU7_ALU_SRC_IS_CONST_0_5F(srcSel))\n\t{\n\t\tcemu_assert_debug(srcRel == 0);\n\t\tv = 0x3f000000; // 0.5f\n\t}\n\telse if (GPU7_ALU_SRC_IS_LITERAL(srcSel))\n\t{\n\t\tv = LatteSWCtx.literalPtr->s32[srcChan];\n\t}\n\telse\n\t\tassert_dbg();\n\treturn v;\n}\n\nsint32 _getSrc_s32(uint32 srcSel, uint32 srcChan, uint32 srcNeg, uint32 srcAbs, uint32 srcRel, uint32 indexMode)\n{\n\tsint32 v = _getSrc_genericS32(srcSel, srcChan, srcRel, indexMode);\n\tcemu_assert_debug(srcNeg == 0);\n\tcemu_assert_debug(srcAbs == 0);\n\treturn v;\n}\n\nfloat _getSrc_f(uint32 srcSel, uint32 srcChan, uint32 srcNeg, uint32 srcAbs, uint32 srcRel, uint32 indexMode)\n{\n\tfloat v = 0;\n\t*(sint32*)&v = _getSrc_genericS32(srcSel, srcChan, srcRel, indexMode);\n\tif (srcAbs) // todo - how does this interact with srcNeg\n\t\tv = fabs(v);\n\tif (srcNeg)\n\t\tv = -v;\n\treturn v;\n}\n\n#define _updateGPR_S32(__gprIdx,__channel,__v) {gprUpdate[updateQueueLength].gprIndex = __gprIdx; gprUpdate[updateQueueLength].channel = __channel; gprUpdate[updateQueueLength].s32 = __v; updateQueueLength++;}\n#define _updateGPR_F(__gprIdx,__channel,__v) {gprUpdate[updateQueueLength].gprIndex = __gprIdx; gprUpdate[updateQueueLength].channel = __channel; gprUpdate[updateQueueLength].f = __v; updateQueueLength++;}\n\n#define _updatePVPS_S32(__pvIndex, __v) {LatteSWCtx.pvpsUpdate.s32[__pvIndex] = __v;}\n#define _updatePVPS_F(__pvIndex, __v) {LatteSWCtx.pvpsUpdate.f[__pvIndex] = __v;}\n\nfloat LatteSoftware_omod(uint32 omod, float f)\n{\n\tswitch (omod)\n\t{\n\tcase ALU_OMOD_NONE:\n\t\treturn f;\n\tcase ALU_OMOD_MUL2:\n\t\treturn f * 2.0f;\n\tcase ALU_OMOD_MUL4:\n\t\treturn f * 4.0f;\n\tcase ALU_OMOD_DIV2:\n\t\treturn f / 2.0f;\n\t}\n\tcemu_assert_debug(false);\n\treturn 0.0f;\n}\n\n#ifdef CEMU_DEBUG_ASSERT\n#define _clamp(__v) if(destClamp != 0) cemu_assert_unimplemented()\n#else\n#define _clamp(__v) // todo\n#endif\n\n#define _omod(__v) __v = LatteSoftware_omod(omod, __v)\n\nbool LatteDecompiler_IsALUTransInstruction(bool isOP3, uint32 opcode);\n\nvoid LatteSoftware_setupCBankPointers(uint32 cBank0Index, uint32 cBank1Index, uint32 cBank0AddrBase, uint32 cBank1AddrBase)\n{\n\tMPTR cBank0Ptr = LatteGPUState.contextRegister[mmSQ_VTX_UNIFORM_BLOCK_START + cBank0Index * 7 + 0];\n\tMPTR cBank1Ptr = LatteGPUState.contextRegister[mmSQ_VTX_UNIFORM_BLOCK_START + cBank1Index * 7 + 0];\n\tLatteSWCtx.cbank0 = (LatteReg_t*)memory_getPointerFromPhysicalOffset(cBank0Ptr + cBank0AddrBase);\n\tLatteSWCtx.cbank1 = (LatteReg_t*)memory_getPointerFromPhysicalOffset(cBank1Ptr + cBank1AddrBase);\n}\n\nvoid LatteSoftware_executeALUClause(uint32 cfType, uint32 addr, uint32 count, uint32 cBank0Index, uint32 cBank1Index, uint32 cBank0AddrBase, uint32 cBank1AddrBase)\n{\n\tcemu_assert_debug(cfType == GPU7_CF_INST_ALU); // todo - handle other ALU clauses\n\tuint32* aluWordPtr = LatteSWCtx.shaderBase + addr * 2;\n\tuint32* aluWordPtrEnd = aluWordPtr + count * 2;\n\n\tLatteSoftware_setupCBankPointers(cBank0Index, cBank1Index, cBank0AddrBase, cBank1AddrBase);\n\n\tstruct  \n\t{\n\t\tsint16 gprIndex;\n\t\tsint16 channel;\n\t\tunion\n\t\t{\n\t\t\tfloat f;\n\t\t\tuint32 u32;\n\t\t\tsint32 s32;\n\t\t};\n\t}gprUpdate[16];\n\n\tsint32 updateQueueLength = 0;\n\tuint32 aluUnitWriteMask = 0;\n\tuint8 literalAccessMask = 0;\n\twhile (aluWordPtr < aluWordPtrEnd)\n\t{\n\t\t// calculate number of instructions in group\n\t\tsint32 groupInstructionCount;\n\t\tfor (sint32 i = 0; i < 6; i++)\n\t\t{\n\t\t\tif (aluWordPtr[i * 2] & 0x80000000)\n\t\t\t{\n\t\t\t\tgroupInstructionCount = i + 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcemu_assert_debug(i < 5);\n\t\t}\n\t\tLatteSWCtx.literalPtr = (LatteReg_t*)(aluWordPtr + groupInstructionCount*2);\n\t\t// process group\n\t\tbool hasReductionInstruction = false;\n\t\tfloat reductionResult = 0.0f;\n\t\tfor (sint32 s = 0; s < groupInstructionCount; s++)\n\t\t{\n\t\t\tuint32 aluWord0 = aluWordPtr[0];\n\t\t\tuint32 aluWord1 = aluWordPtr[1];\n\t\t\taluWordPtr += 2;\n\t\t\tuint32 alu_inst13_5 = (aluWord1 >> 13) & 0x1F;\n\t\t\t// parameters from ALU word 0 (shared for ALU OP2 and OP3)\n\t\t\tuint32 src0Sel = (aluWord0 >> 0) & 0x1FF; // source selection\n\t\t\tuint32 src1Sel = (aluWord0 >> 13) & 0x1FF;\n\t\t\tuint32 src0Rel = (aluWord0 >> 9) & 0x1; // relative addressing mode\n\t\t\tuint32 src1Rel = (aluWord0 >> 22) & 0x1;\n\t\t\tuint32 src0Chan = (aluWord0 >> 10) & 0x3; // component selection x/y/z/w\n\t\t\tuint32 src1Chan = (aluWord0 >> 23) & 0x3;\n\t\t\tuint32 src0Neg = (aluWord0 >> 12) & 0x1; // negate input\n\t\t\tuint32 src1Neg = (aluWord0 >> 25) & 0x1;\n\t\t\tuint32 indexMode = (aluWord0 >> 26) & 7;\n\t\t\tuint32 predSel = (aluWord0 >> 29) & 3;\n\t\t\tif (GPU7_ALU_SRC_IS_LITERAL(src0Sel))\n\t\t\t\tliteralAccessMask |= (1 << src0Chan);\n\t\t\tif (GPU7_ALU_SRC_IS_LITERAL(src1Sel))\n\t\t\t\tliteralAccessMask |= (1 << src1Chan);\n\n\t\t\tif (alu_inst13_5 >= 0x8)\n\t\t\t{\n\t\t\t\t// op3\n\t\t\t\t// parameters from ALU word 1\n\t\t\t\tuint32 src2Sel = (aluWord1 >> 0) & 0x1FF; // source selection\n\t\t\t\tuint32 src2Rel = (aluWord1 >> 9) & 0x1; // relative addressing mode\n\t\t\t\tuint32 src2Chan = (aluWord1 >> 10) & 0x3; // component selection x/y/z/w\n\t\t\t\tuint32 src2Neg = (aluWord1 >> 12) & 0x1; // negate input\n\t\t\t\tif (GPU7_ALU_SRC_IS_LITERAL(src2Sel))\n\t\t\t\t\tliteralAccessMask |= (1 << src2Chan);\n\n\t\t\t\tuint32 destGpr = (aluWord1 >> 21) & 0x7F;\n\t\t\t\tuint32 destRel = (aluWord1 >> 28) & 1;\n\t\t\t\tuint32 destElem = (aluWord1 >> 29) & 3;\n\t\t\t\tuint32 destClamp = (aluWord1 >> 31) & 1;\n\n\t\t\t\tuint32 aluUnit = destElem;\n\t\t\t\tif (aluUnitWriteMask&(1 << destElem))\n\t\t\t\t{\n\t\t\t\t\taluUnit = 4; // PV\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\taluUnitWriteMask |= (1 << destElem);\n\n\t\t\t\tswitch (alu_inst13_5)\n\t\t\t\t{\n\t\t\t\tcase ALU_OP3_INST_CMOVE:\n\t\t\t\t{\n\t\t\t\t\tfloat f = _getSrc_f(src0Sel, src0Chan, src0Neg, 0, src0Rel, indexMode);\n\t\t\t\t\tsint32 result;\n\t\t\t\t\tif (f == 0.0f)\n\t\t\t\t\t\tresult = _getSrc_s32(src1Sel, src1Chan, src1Neg, 0, src1Rel, indexMode);\n\t\t\t\t\telse\n\t\t\t\t\t\tresult = _getSrc_s32(src2Sel, src2Chan, src2Neg, 0, src2Rel, indexMode);\n\t\t\t\t\tcemu_assert_debug(destClamp == 0);\n\t\t\t\t\t_updateGPR_S32(destGpr, destElem, result);\n\t\t\t\t\t_updatePVPS_S32(aluUnit, result);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP3_INST_CMOVGT:\n\t\t\t\t{\n\t\t\t\t\tfloat f = _getSrc_f(src0Sel, src0Chan, src0Neg, 0, src0Rel, indexMode);\n\t\t\t\t\tsint32 result;\n\t\t\t\t\tif (f > 0.0f)\n\t\t\t\t\t\tresult = _getSrc_s32(src1Sel, src1Chan, src1Neg, 0, src1Rel, indexMode);\n\t\t\t\t\telse\n\t\t\t\t\t\tresult = _getSrc_s32(src2Sel, src2Chan, src2Neg, 0, src2Rel, indexMode);\n\t\t\t\t\tcemu_assert_debug(destClamp == 0);\n\t\t\t\t\t_updateGPR_S32(destGpr, destElem, result);\n\t\t\t\t\t_updatePVPS_S32(aluUnit, result);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP3_INST_MULADD:\n\t\t\t\t{\n\t\t\t\t\tfloat f0 = _getSrc_f(src0Sel, src0Chan, src0Neg, 0, src0Rel, indexMode);\n\t\t\t\t\tfloat f1 = _getSrc_f(src1Sel, src1Chan, src1Neg, 0, src1Rel, indexMode);\n\t\t\t\t\tfloat f2 = _getSrc_f(src2Sel, src2Chan, src2Neg, 0, src2Rel, indexMode);\n\t\t\t\t\tfloat f = f0*f1+f2;\n\t\t\t\t\t_updateGPR_F(destGpr, destElem, f);\n\t\t\t\t\t_updatePVPS_F(aluUnit, f);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint32 alu_inst7_11 = (aluWord1 >> 7) & 0x7FF;\n\n\t\t\t\tuint32 src0Abs = (aluWord1 >> 0) & 1;\n\t\t\t\tuint32 src1Abs = (aluWord1 >> 1) & 1;\n\t\t\t\tuint32 updateExecuteMask = (aluWord1 >> 2) & 1;\n\t\t\t\tuint32 updatePredicate = (aluWord1 >> 3) & 1;\n\t\t\t\tuint32 writeMask = (aluWord1 >> 4) & 1;\n\t\t\t\tuint32 omod = (aluWord1 >> 5) & 3;\n\n\t\t\t\tuint32 destGpr = (aluWord1 >> 21) & 0x7F;\n\t\t\t\tuint32 destRel = (aluWord1 >> 28) & 1;\n\t\t\t\tuint32 destElem = (aluWord1 >> 29) & 3;\n\t\t\t\tuint32 destClamp = (aluWord1 >> 31) & 1;\n\n\t\t\t\tuint32 aluUnit = destElem;\n\t\t\t\tif (LatteDecompiler_IsALUTransInstruction(false, alu_inst7_11))\n\t\t\t\t\taluUnit = 4;\n\n\t\t\t\tif (aluUnitWriteMask&(1 << destElem))\n\t\t\t\t{\n\t\t\t\t\taluUnit = 4; // PV\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\taluUnitWriteMask |= (1 << destElem);\n\n\t\t\t\tswitch (alu_inst7_11)\n\t\t\t\t{\n\t\t\t\tcase ALU_OP2_INST_NOP:\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_MOV:\n\t\t\t\t{\n\t\t\t\t\tif (src0Neg || src0Abs || omod != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tfloat v = _getSrc_f(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\t\t_omod(v);\n\t\t\t\t\t\t_clamp(f);\n\t\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t\t_updateGPR_F(destGpr, destElem, v);\n\t\t\t\t\t\t_updatePVPS_F(aluUnit, v);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tsint32 v = _getSrc_s32(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\t\t// todo - omod/clamp for float moves\n\t\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t\t_updateGPR_S32(destGpr, destElem, v);\n\t\t\t\t\t\t_updatePVPS_S32(aluUnit, v);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_ADD:\n\t\t\t\t{\n\t\t\t\t\tfloat f0 = _getSrc_f(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\tfloat f1 = _getSrc_f(src1Sel, src1Chan, src1Neg, src1Abs, src1Rel, indexMode);\n\t\t\t\t\tfloat f = f0 + f1;\n\t\t\t\t\t_omod(f);\n\t\t\t\t\t_clamp(f);\n\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t_updateGPR_F(destGpr, destElem, f);\n\t\t\t\t\t_updatePVPS_F(aluUnit, f);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_MUL:\n\t\t\t\tcase ALU_OP2_INST_MUL_IEEE:\n\t\t\t\t{\n\t\t\t\t\tfloat f0 = _getSrc_f(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\tfloat f1 = _getSrc_f(src1Sel, src1Chan, src1Neg, src1Abs, src1Rel, indexMode);\n\t\t\t\t\tfloat f = f0 * f1;\n\t\t\t\t\tif (f0 == 0.0f || f1 == 0.0f)\n\t\t\t\t\t\tf = 0.0f;\n\t\t\t\t\t_omod(f);\n\t\t\t\t\t_clamp(f);\n\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t_updateGPR_F(destGpr, destElem, f);\n\t\t\t\t\t_updatePVPS_F(aluUnit, f);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_TRUNC:\n\t\t\t\t{\n\t\t\t\t\tfloat f0 = _getSrc_f(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\tfloat f = truncf(f0);\n\t\t\t\t\t_omod(f);\n\t\t\t\t\t_clamp(f);\n\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t_updateGPR_F(destGpr, destElem, f);\n\t\t\t\t\t_updatePVPS_F(aluUnit, f);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_RECIP_IEEE:\n\t\t\t\t{\n\t\t\t\t\tfloat f0 = _getSrc_f(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\tfloat f = 1.0f / f0;\n\t\t\t\t\t_omod(f);\n\t\t\t\t\t_clamp(f);\n\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t_updateGPR_F(destGpr, destElem, f);\n\t\t\t\t\t_updatePVPS_F(aluUnit, f);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_SETGT:\n\t\t\t\t{\n\t\t\t\t\tfloat f0 = _getSrc_f(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\tfloat f1 = _getSrc_f(src1Sel, src1Chan, src1Neg, src1Abs, src1Rel, indexMode);\n\t\t\t\t\tfloat f = (f0 > f1) ? 1.0f : 0.0f;\n\t\t\t\t\t_omod(f);\n\t\t\t\t\t_clamp(f);\n\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t_updateGPR_F(destGpr, destElem, f);\n\t\t\t\t\t_updatePVPS_F(aluUnit, f);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_SETGE:\n\t\t\t\t{\n\t\t\t\t\tfloat f0 = _getSrc_f(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\tfloat f1 = _getSrc_f(src1Sel, src1Chan, src1Neg, src1Abs, src1Rel, indexMode);\n\t\t\t\t\tfloat f = (f0 >= f1) ? 1.0f : 0.0f;\n\t\t\t\t\t_omod(f);\n\t\t\t\t\t_clamp(f);\n\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t_updateGPR_F(destGpr, destElem, f);\n\t\t\t\t\t_updatePVPS_F(aluUnit, f);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_INT_TO_FLOAT:\n\t\t\t\t{\n\t\t\t\t\tsint32 v = _getSrc_s32(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\tfloat f = (float)v;\n\t\t\t\t\t_omod(f);\n\t\t\t\t\t_clamp(f);\n\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t_updateGPR_F(destGpr, destElem, f);\n\t\t\t\t\t_updatePVPS_F(aluUnit, f);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_FLT_TO_INT:\n\t\t\t\t{\n\t\t\t\t\tfloat v = _getSrc_f(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\tsint32 f = (sint32)v;\n\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t_updateGPR_S32(destGpr, destElem, f);\n\t\t\t\t\t_updatePVPS_S32(aluUnit, f);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_MOVA_FLOOR:\n\t\t\t\t{\n\t\t\t\t\tfloat f = _getSrc_f(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\tf = floor(f);\n\t\t\t\t\tf = std::min(std::max(f, -256.0f), 255.0f);\n\t\t\t\t\t// omod, clamp?\n\t\t\t\t\t_updateGPR_S32(REG_AR, destElem, (sint32)f);\n\t\t\t\t\tif (writeMask)\n\t\t\t\t\t\t_updateGPR_F(destGpr, destElem, f);\n\t\t\t\t\t_updatePVPS_F(aluUnit, f);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ALU_OP2_INST_DOT4:\n\t\t\t\t{\n\t\t\t\t\tfloat f0 = _getSrc_f(src0Sel, src0Chan, src0Neg, src0Abs, src0Rel, indexMode);\n\t\t\t\t\tfloat f1 = _getSrc_f(src1Sel, src1Chan, src1Neg, src1Abs, src1Rel, indexMode);\n\t\t\t\t\tfloat f = f0 * f1;\n\t\t\t\t\treductionResult += f;\n\t\t\t\t\t_omod(f);\n\t\t\t\t\t_clamp(f);\n\t\t\t\t\tif (writeMask)\n\t\t\t\t\t{\n\t\t\t\t\t\t_updateGPR_F(destGpr, destElem, f);\n\t\t\t\t\t}\n\t\t\t\t\t_updatePVPS_F(aluUnit, f);\n\t\t\t\t\thasReductionInstruction = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// apply updates\n\t\tif (hasReductionInstruction == false)\n\t\t{\n\t\t\tfor (sint32 i = 0; i < updateQueueLength; i++)\n\t\t\t{\n\t\t\t\tLatteSWCtx.reg[gprUpdate[i].gprIndex].s32[gprUpdate[i].channel] = gprUpdate[i].s32;\n\t\t\t}\n\t\t\tLatteSWCtx.pvps.s32[0] = LatteSWCtx.pvpsUpdate.s32[0];\n\t\t\tLatteSWCtx.pvps.s32[1] = LatteSWCtx.pvpsUpdate.s32[1];\n\t\t\tLatteSWCtx.pvps.s32[2] = LatteSWCtx.pvpsUpdate.s32[2];\n\t\t\tLatteSWCtx.pvps.s32[3] = LatteSWCtx.pvpsUpdate.s32[3];\n\t\t\tLatteSWCtx.pvps.s32[4] = LatteSWCtx.pvpsUpdate.s32[4];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (sint32 i = 0; i < updateQueueLength; i++)\n\t\t\t{\n\t\t\t\tLatteSWCtx.reg[gprUpdate[i].gprIndex].f[gprUpdate[i].channel] = reductionResult;\n\t\t\t}\n\t\t\tLatteSWCtx.pvps.f[0] = reductionResult;\n\t\t\tLatteSWCtx.pvps.f[1] = reductionResult;\n\t\t\tLatteSWCtx.pvps.f[2] = reductionResult;\n\t\t\tLatteSWCtx.pvps.f[3] = reductionResult;\n\t\t}\n\t\tupdateQueueLength = 0;\n\t\t// skip literals\n\t\tif (literalAccessMask&(3 << 0))\n\t\t\taluWordPtr += 2;\n\t\tif (literalAccessMask&(3 << 2))\n\t\t{\n\t\t\tcemu_assert_debug((literalAccessMask &3) != 0);\n\t\t\taluWordPtr += 2;\n\t\t}\n\t\t// reset group state tracking variables\n\t\taluUnitWriteMask = 0;\n\t\tliteralAccessMask = 0;\n\t}\n}\n\nsint32 _getRegValueByCompSel(uint32 gprIndex, uint32 compSel)\n{\n\tif (compSel < 4)\n\t\treturn LatteSWCtx.reg[gprIndex].s32[compSel];\n\tcemu_assert_unimplemented();\n\treturn 0;\n}\n\nvoid LatteSoftware_singleRun()\n{\n\tuint32* cfWords = LatteSWCtx.shaderBase;\n\tsint32 instructionIndex = 0;\n\twhile (true)\n\t{\n\t\tuint32 cfWord0 = cfWords[instructionIndex + 0];\n\t\tuint32 cfWord1 = cfWords[instructionIndex + 1];\n\t\tinstructionIndex += 2;\n\n\t\tuint32 cf_inst23_7 = (cfWord1 >> 23) & 0x7F;\n\t\tif (cf_inst23_7 < 0x40) // starting at 0x40 the bits overlap with the ALU instruction encoding\n\t\t{\n\t\t\tbool isEndOfProgram = ((cfWord1 >> 21) & 1) != 0;\n\t\t\tuint32 addr = cfWord0 & 0xFFFFFFFF;\n\t\t\tuint32 count = (cfWord1 >> 10) & 7;\n\t\t\tif (((cfWord1 >> 19) & 1) != 0)\n\t\t\t\tcount |= 0x8;\n\t\t\tcount++;\n\t\t\tif (cf_inst23_7 == GPU7_CF_INST_CALL_FS)\n\t\t\t{\n\t\t\t\t\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_NOP)\n\t\t\t{\n\t\t\t\t// nop\n\t\t\t\tif (((cfWord1 >> 0) & 7) != 0)\n\t\t\t\t\tcemu_assert_debug(false); // pop count is not zero\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_EXPORT || cf_inst23_7 == GPU7_CF_INST_EXPORT_DONE)\n\t\t\t{\n\t\t\t\t// export\n\t\t\t\tuint32 edType = (cfWord0 >> 13) & 0x3;\n\t\t\t\tuint32 edIndexGpr = (cfWord0 >> 23) & 0x7F;\n\t\t\t\tuint32 edRWRel = (cfWord0 >> 22) & 1;\n\t\t\t\tif (edRWRel != 0 || edIndexGpr != 0)\n\t\t\t\t\tcemu_assert_debug(false);\n\n\t\t\t\tuint8 exportComponentSel[4];\n\t\t\t\texportComponentSel[0] = (cfWord1 >> 0) & 0x7;\n\t\t\t\texportComponentSel[1] = (cfWord1 >> 3) & 0x7;\n\t\t\t\texportComponentSel[2] = (cfWord1 >> 6) & 0x7;\n\t\t\t\texportComponentSel[3] = (cfWord1 >> 9) & 0x7;\n\t\t\t\tuint32 exportArrayBase = (cfWord0 >> 0) & 0x1FFF;\n\t\t\t\tuint32 exportBurstCount = (cfWord1 >> 17) & 0xF;\n\t\t\t\tuint32 exportSourceGPR = (cfWord0 >> 15) & 0x7F;\n\t\t\t\tuint32 memWriteElemSize = (cfWord0>>29)&3; // unused\n\n\t\t\t\tcemu_assert_debug(exportBurstCount == 0);\n\t\t\t\tif (edType == 1 && exportArrayBase == GPU7_DECOMPILER_CF_EXPORT_BASE_POSITION)\n\t\t\t\t{\n\t\t\t\t\tLatteSWCtx.export_pos.s32[0] = _getRegValueByCompSel(exportSourceGPR, exportComponentSel[0]);\n\t\t\t\t\tLatteSWCtx.export_pos.s32[1] = _getRegValueByCompSel(exportSourceGPR, exportComponentSel[1]);\n\t\t\t\t\tLatteSWCtx.export_pos.s32[2] = _getRegValueByCompSel(exportSourceGPR, exportComponentSel[2]);\n\t\t\t\t\tLatteSWCtx.export_pos.s32[3] = _getRegValueByCompSel(exportSourceGPR, exportComponentSel[3]);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// unhandled export\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_TEX)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_ELSE ||\n\t\t\t\tcf_inst23_7 == GPU7_CF_INST_POP)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_JUMP)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_LOOP_START_DX10 || cf_inst23_7 == GPU7_CF_INST_LOOP_END)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_LOOP_BREAK)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_MEM_STREAM0_WRITE ||\n\t\t\t\tcf_inst23_7 == GPU7_CF_INST_MEM_STREAM1_WRITE)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_MEM_RING_WRITE)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse if (cf_inst23_7 == GPU7_CF_INST_EMIT_VERTEX)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\tif (isEndOfProgram)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// ALU instruction\n\t\t\tuint32 cf_inst26_4 = ((cfWord1 >> 26) & 0xF) | GPU7_CF_INST_ALU_MASK;\n\t\t\tif (cf_inst26_4 == GPU7_CF_INST_ALU || cf_inst26_4 == GPU7_CF_INST_ALU_PUSH_BEFORE || cf_inst26_4 == GPU7_CF_INST_ALU_POP_AFTER || cf_inst26_4 == GPU7_CF_INST_ALU_POP2_AFTER || cf_inst26_4 == GPU7_CF_INST_ALU_BREAK || cf_inst26_4 == GPU7_CF_INST_ALU_ELSE_AFTER)\n\t\t\t{\n\t\t\t\tuint32 addr = (cfWord0 >> 0) & 0x3FFFFF;\n\t\t\t\tuint32 count = ((cfWord1 >> 18) & 0x7F) + 1;\n\t\t\t\tuint32 cBank0Index = (cfWord0 >> 22) & 0xF;\n\t\t\t\tuint32 cBank1Index = (cfWord0 >> 26) & 0xF;\n\t\t\t\tuint32 cBank0AddrBase = ((cfWord1 >> 2) & 0xFF) * 16;\n\t\t\t\tuint32 cBank1AddrBase = ((cfWord1 >> 10) & 0xFF) * 16;\n\t\t\t\tLatteSoftware_executeALUClause(cf_inst26_4, addr, count, cBank0Index, cBank1Index, cBank0AddrBase, cBank1AddrBase);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t}\n\tcemu_assert_debug(false);\n}\n\ntemplate<int endianMode>\nuint32 _readVtxU32(void* ptr)\n{\n\tuint32 v = *(uint32*)ptr;\n\tif constexpr (endianMode == GPU7_ENDIAN_8IN32)\n\t\tv = _swapEndianU32(v);\n\treturn v;\n}\n\ntemplate<int endianMode, int nfa>\nvoid _readAttr_FLOAT_32_32(void* ptr, LatteReg_t& output)\n{\n\toutput.s32[0] = _readVtxU32<endianMode>((uint32*)ptr);\n\toutput.s32[1] = _readVtxU32<endianMode>((uint32*)ptr + 1);\n\toutput.s32[2] = 0;\n\toutput.s32[3] = 0;\n}\n\ntemplate<int endianMode, int nfa>\nvoid _readAttr_FLOAT_32_32_32(void* ptr, LatteReg_t& output)\n{\n\toutput.s32[0] = _readVtxU32<endianMode>((uint32*)ptr);\n\toutput.s32[1] = _readVtxU32<endianMode>((uint32*)ptr + 1);\n\toutput.s32[2] = _readVtxU32<endianMode>((uint32*)ptr + 2);\n\toutput.s32[3] = 0;\n}\n\ntemplate<int endianMode, int nfa>\nvoid _readAttr_FLOAT_32_32_32_32(void* ptr, LatteReg_t& output)\n{\n\toutput.s32[0] = _readVtxU32<endianMode>((uint32*)ptr);\n\toutput.s32[1] = _readVtxU32<endianMode>((uint32*)ptr + 1);\n\toutput.s32[2] = _readVtxU32<endianMode>((uint32*)ptr + 2);\n\toutput.s32[3] = _readVtxU32<endianMode>((uint32*)ptr + 3);\n}\n\n#define _fmtKey(__fmt, __endianSwap, __nfa, __isSigned) ((__endianSwap)|((__nfa)<<2)|((__isSigned)<<4)|((__fmt)<<5))\n\nvoid LatteSoftware_loadVertexAttributes(sint32 index)\n{\n\tLatteSWCtx.reg[0].s32[0] = index;\n\tfor (auto& bufferGroup : LatteSWCtx.fetchShader->bufferGroups)\n\t{\n\t\tfor (sint32 f = 0; f < bufferGroup.attribCount; f++)\n\t\t{\n\t\t\tauto attrib = bufferGroup.attrib + f;\n\t\t\t// calculate element index\n\t\t\tsint32 elementIndex = index;\n\t\t\t// todo - handle instance index and attr divisor\n\t\t\t\n\t\t\t// get buffer\n\t\t\tuint32 bufferIndex = attrib->attributeBufferIndex;\n\t\t\tif (bufferIndex >= 0x10)\n\t\t\t{\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n\t\t\tMPTR bufferAddress = LatteGPUState.contextRegister[bufferBaseRegisterIndex + 0];\n\t\t\tuint32 bufferSize = LatteGPUState.contextRegister[bufferBaseRegisterIndex + 1] + 1;\n\t\t\tuint32 bufferStride = (LatteGPUState.contextRegister[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;\n\t\t\tif (bufferAddress == MPTR_NULL)\n\t\t\t{\n\t\t\t\tdebug_printf(\"Warning: Attribute uses NULL buffer during software emulation\\n\");\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// translate semanticId to gpr index\n\t\t\tuint32 gprIndex = 0xFFFFFFFF;\n\t\t\tfor (sint32 f = 0; f < 32; f++)\n\t\t\t{\n\t\t\t\tif (LatteGPUState.contextRegister[mmSQ_VTX_SEMANTIC_0 + f] == attrib->semanticId)\n\t\t\t\t{\n\t\t\t\t\tgprIndex = f;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (gprIndex == 0xFFFFFFFF)\n\t\t\t\tcontinue; // attribute is not mapped to VS input\n\t\t\tgprIndex = gprIndex + 1;\n\n\t\t\tsint32 formatKey = _fmtKey((sint32)attrib->format, (sint32)attrib->endianSwap, (sint32)attrib->nfa, (sint32)attrib->isSigned);\n\n\t\t\tvoid* inputData = memory_getPointerFromPhysicalOffset(bufferAddress + elementIndex * bufferStride);\n\n\t\t\tLatteReg_t attrData;\n\n\t\t\tswitch (formatKey)\n\t\t\t{\n\t\t\tcase _fmtKey(FMT_32_32_FLOAT, GPU7_ENDIAN_8IN32, LATTE_NFA_2, LATTE_VTX_UNSIGNED):\n\t\t\t\t_readAttr_FLOAT_32_32<GPU7_ENDIAN_8IN32, LATTE_NFA_2>(inputData, attrData);\n\t\t\t\tbreak;\n\t\t\tcase _fmtKey(FMT_32_32_32_FLOAT, GPU7_ENDIAN_8IN32, LATTE_NFA_2, LATTE_VTX_UNSIGNED):\n\t\t\t\t_readAttr_FLOAT_32_32_32<GPU7_ENDIAN_8IN32, LATTE_NFA_2>(inputData, attrData);\n\t\t\t\tbreak;\n\t\t\tcase _fmtKey(FMT_32_32_32_32_FLOAT, GPU7_ENDIAN_8IN32, LATTE_NFA_2, LATTE_VTX_UNSIGNED):\n\t\t\t\t_readAttr_FLOAT_32_32_32_32<GPU7_ENDIAN_8IN32, LATTE_NFA_2>(inputData, attrData);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\n\t\t\tLatteReg_t* gprOutput = LatteSWCtx.reg+gprIndex;\n\t\t\tfor (uint32 f = 0; f < 4; f++)\n\t\t\t{\n\t\t\t\tif (attrib->ds[f] < 4)\n\t\t\t\t\tgprOutput->s32[f] = attrData.s32[f];\n\t\t\t\telse if (attrib->ds[f] == 4)\n\t\t\t\t\tgprOutput->s32[f] = 0;\n\t\t\t\telse if (attrib->ds[f] == 5)\n\t\t\t\t\tgprOutput->f[f] = 1.0;\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfloat* LatteSoftware_getPositionExport()\n{\n\treturn LatteSWCtx.export_pos.f;\n}\n\nvoid LatteSoftware_executeVertex(sint32 index)\n{\n\tLatteSoftware_loadVertexAttributes(index);\n\tLatteSoftware_singleRun();\n}\n\nvoid LatteSoftware_setupVertexShader(LatteFetchShader* fetchShader, void* shaderPtr, sint32 size)\n{\n\tLatteSWCtx.fetchShader = fetchShader;\n\tLatteSWCtx.shaderBase = (uint32*)shaderPtr;\n\tLatteSWCtx.shaderSize = size;\n\tLatteSWCtx.cfilePtr = (void*)(LatteGPUState.contextRegister + LATTE_REG_BASE_ALU_CONST + 0x400);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteSoftware.h",
    "content": "#pragma once\n\nvoid LatteSoftware_setupVertexShader(struct LatteFetchShader* fetchShader, void* shaderPtr, sint32 size);\nvoid LatteSoftware_executeVertex(sint32 index);\n\nfloat* LatteSoftware_getPositionExport();"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteStreamoutGPU.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n\n#include \"util/containers/IntervalBucketContainer.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Core/LatteRingBuffer.h\"\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n\nstruct\n{\n\tsint32 currentRingbufferOffset;\n\tVirtualBufferHeap_t* mainBufferHeap;\n}streamoutManager;\n\nsint32 LatteStreamout_GetRingBufferSize()\n{\n\treturn 8 * 1024 * 1024; // 8MB\n}\n\nsint32 LatteStreamout_allocateGPURingbufferMem(sint32 size)\n{\n\t// pad size to 256 byte alignment\n\tsize = (size + 255)&~255;\n\t// get next offset\n\tif ((streamoutManager.currentRingbufferOffset + size) > LatteStreamout_GetRingBufferSize())\n\t{\n\t\tstreamoutManager.currentRingbufferOffset = 0;\n\t}\n\tsint32 allocOffset = streamoutManager.currentRingbufferOffset;\n\tstreamoutManager.currentRingbufferOffset += size;\n\treturn allocOffset;\n}\n\nvoid LatteStreamout_InitCache()\n{\n\tstreamoutManager.currentRingbufferOffset = 0;\n\tstreamoutManager.mainBufferHeap = nullptr;\n}\n\nbool _transformFeedbackIsActive = false;\nstruct\n{\n\tuint32 vertexCount;\n\tuint32 instanceCount;\n\tuint32 streamoutWriteMask;\n\tstruct\n\t{\n\t\tbool isActive;\n\t\tsint32 ringBufferOffset;\n\t\tuint32 rangeAddr;\n\t\tuint32 rangeSize; // size of written streamout data, bounded by buffer size\n\t}streamoutBufferWrite[LATTE_NUM_STREAMOUT_BUFFER];\n}activeStreamoutOperation;\n\nuint32 LatteStreamout_getNumberOfWrittenVertices()\n{\n\t// todo: Currently we only handle GX2_POINTS\n\treturn activeStreamoutOperation.vertexCount * activeStreamoutOperation.instanceCount;\n}\n\n// returns the number of bytes that are written into the buffer by the current draw operation (ignoring buffer maximum size)\nuint32 LatteStreamout_getBufferWriteRangeSize(uint32 streamoutBufferIndex)\n{\n\tuint32 bufferStride = LatteGPUState.contextRegister[mmVGT_STRMOUT_VTX_STRIDE_0 + streamoutBufferIndex * 4] << 2;\n\tuint32 bufferSize = LatteGPUState.contextRegister[mmVGT_STRMOUT_BUFFER_SIZE_0 + streamoutBufferIndex * 4] << 2;\n\tuint32 writeSize = LatteStreamout_getNumberOfWrittenVertices() * bufferStride;\n\tif (bufferSize < writeSize)\n\t\twriteSize = bufferSize;\n\treturn writeSize;\n}\n\nvoid LatteStreamout_PrepareDrawcall(uint32 count, uint32 instanceCount)\n{\n\tif (LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] == 0)\n\t{\n\t\t_transformFeedbackIsActive = false;\n\t\treturn; // streamout inactive\n\t}\n\t// get active vertex shader\n\tLatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();\n\t// if a geometry shader is used calculate how many vertices it outputs\n\tLatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader();\n\tsint32 maxVerticesInGS = 1;\n\tif (geometryShader)\n\t{\n\t\tuint32 gsOutPrimType = LatteGPUState.contextRegister[mmVGT_GS_OUT_PRIM_TYPE];\n\t\tuint32 bytesPerVertex = LatteGPUState.contextRegister[mmSQ_GS_VERT_ITEMSIZE] * 4;\n\t\tmaxVerticesInGS = ((LatteGPUState.contextRegister[mmSQ_GSVS_RING_ITEMSIZE] & 0x7FFF) * 4) / bytesPerVertex;\n\t\tcemu_assert_debug(maxVerticesInGS > 0);\n\t}\n\t// setup active streamout operation struct\n\tactiveStreamoutOperation.vertexCount = count * maxVerticesInGS;\n\tactiveStreamoutOperation.instanceCount = instanceCount;\n\t// get mask of all written streamout buffers\n\tuint32 streamoutWriteMask = 0;\n\tif (geometryShader)\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tcemu_assert_debug(vertexShader->streamoutBufferWriteMask.any() == false);\n#endif\n\t\tfor (sint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t\tif (geometryShader->streamoutBufferWriteMask[i])\n\t\t\t\tstreamoutWriteMask |= (1 << i);\n\t}\n\telse\n\t{\n\t\tfor (sint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t\tif (vertexShader->streamoutBufferWriteMask[i])\n\t\t\t\tstreamoutWriteMask |= (1 << i);\n\t}\n\tactiveStreamoutOperation.streamoutWriteMask = streamoutWriteMask;\n\t// bind streamout buffers\n\tfor (uint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t{\n\t\tif ((streamoutWriteMask&(1 << i)) == 0)\n\t\t{\n\t\t\tactiveStreamoutOperation.streamoutBufferWrite[i].isActive = false;\n\t\t\tcontinue;\n\t\t}\n\t\tuint32 bufferBaseMPTR = LatteGPUState.contextRegister[mmVGT_STRMOUT_BUFFER_BASE_0 + i * 4] << 8;\n\t\tuint32 bufferSize = LatteGPUState.contextRegister[mmVGT_STRMOUT_BUFFER_SIZE_0 + i * 4] << 2;\n\t\tuint32 bufferOffset = LatteGPUState.contextRegister[mmVGT_STRMOUT_BUFFER_OFFSET_0 + i * 4];\n\t\tuint32 streamoutWriteSize = LatteStreamout_getBufferWriteRangeSize(i);\n\t\tuint32 rangeAddr = bufferBaseMPTR + bufferOffset;\n\t\tsint32 ringBufferOffset = LatteStreamout_allocateGPURingbufferMem(streamoutWriteSize); // allocate memory for the entire streamout write\n\t\t// calculate write size after bounding it to the buffer\n\t\tuint32 remainingBytesToWrite = bufferOffset > bufferSize ? 0 : (bufferSize - bufferOffset);\n\t\tuint32 rangeSize = std::min(streamoutWriteSize, remainingBytesToWrite);\n\n\t\tactiveStreamoutOperation.streamoutBufferWrite[i].isActive = true;\n\t\tactiveStreamoutOperation.streamoutBufferWrite[i].ringBufferOffset = ringBufferOffset;\n\t\tactiveStreamoutOperation.streamoutBufferWrite[i].rangeAddr = rangeAddr;\n\t\tactiveStreamoutOperation.streamoutBufferWrite[i].rangeSize = rangeSize;\n\n\t\tg_renderer->streamout_setupXfbBuffer(i, ringBufferOffset, rangeAddr, rangeSize);\n\t}\n\tg_renderer->streamout_begin();\n\t_transformFeedbackIsActive = true;\n}\n\nvoid LatteStreamout_FinishDrawcall(bool useDirectMemoryMode)\n{\n\tif (_transformFeedbackIsActive)\n\t{\n\t\t_transformFeedbackIsActive = false;\n\t\tfor (uint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t{\n\t\t\tif ((activeStreamoutOperation.streamoutWriteMask&(1 << i)) == 0)\n\t\t\t\tcontinue;\n\t\t\tif (activeStreamoutOperation.streamoutBufferWrite[i].rangeSize > 0)\n\t\t\t{\n\t\t\t\tif(useDirectMemoryMode)\n\t\t\t\t\tg_renderer->bufferCache_copyStreamoutToMainBuffer(activeStreamoutOperation.streamoutBufferWrite[i].ringBufferOffset, activeStreamoutOperation.streamoutBufferWrite[i].rangeAddr, activeStreamoutOperation.streamoutBufferWrite[i].rangeSize);\n\t\t\t\telse\n\t\t\t\t\tLatteBufferCache_copyStreamoutDataToCache(activeStreamoutOperation.streamoutBufferWrite[i].rangeAddr, activeStreamoutOperation.streamoutBufferWrite[i].rangeSize, activeStreamoutOperation.streamoutBufferWrite[i].ringBufferOffset);\n\t\t\t}\n\t\t\t// advance streamout offset\n\t\t\tuint32 newOffset = LatteGPUState.contextRegister[mmVGT_STRMOUT_BUFFER_OFFSET_0 + i * 4] + activeStreamoutOperation.streamoutBufferWrite[i].rangeSize;\n\t\t\tLatteGPUState.contextRegister[mmVGT_STRMOUT_BUFFER_OFFSET_0 + i * 4] = newOffset;\n\t\t}\n\t\tg_renderer->streamout_rendererFinishDrawcall();\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteSurfaceCopy.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteDefaultShaders.h\"\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n\nvoid LatteSurfaceCopy_copySurfaceNew(MPTR srcPhysAddr, MPTR srcMipAddr, uint32 srcSwizzle, Latte::E_GX2SURFFMT srcSurfaceFormat, sint32 srcWidth, sint32 srcHeight, sint32 srcDepth, uint32 srcPitch, sint32 srcSlice, Latte::E_DIM srcDim, Latte::E_HWTILEMODE srcTilemode, sint32 srcAA, sint32 srcLevel, MPTR dstPhysAddr, MPTR dstMipAddr, uint32 dstSwizzle, Latte::E_GX2SURFFMT dstSurfaceFormat, sint32 dstWidth, sint32 dstHeight, sint32 dstDepth, uint32 dstPitch, sint32 dstSlice, Latte::E_DIM dstDim, Latte::E_HWTILEMODE dstTilemode, sint32 dstAA, sint32 dstLevel)\n{\n\t// check if source is within valid mip range\n\tif (srcDim == Latte::E_DIM::DIM_3D && (srcDepth >> srcLevel) == 0 && (srcWidth >> srcLevel) == 0 && (srcHeight >> srcLevel) == 0)\n\t\treturn;\n\telse if ((srcWidth >> srcLevel) == 0 && (srcHeight >> srcLevel) == 0)\n\t\treturn;\n\t// look up source texture\n\tLatteTexture* sourceTexture = nullptr;\n\tLatteTextureView* sourceView = LatteTC_GetTextureSliceViewOrTryCreate(srcPhysAddr, srcMipAddr, srcSurfaceFormat, srcTilemode, srcWidth, srcHeight, srcDepth, srcPitch, srcSwizzle, srcSlice, srcLevel);\n\tif (sourceView == nullptr)\n\t{\n\t\tdebug_printf(\"HLECopySurface(): Source texture is not in list of dynamic textures\\n\");\n\t\treturn;\n\t}\n\tsourceTexture = sourceView->baseTexture;\n\tif (sourceTexture->reloadFromDynamicTextures)\n\t{\n\t\tLatteTexture_UpdateCacheFromDynamicTextures(sourceTexture);\n\t\tsourceTexture->reloadFromDynamicTextures = false;\n\t}\n\t// look up destination texture\n\tLatteTexture* destinationTexture = nullptr;\n\tLatteTextureView* destinationView = LatteTextureViewLookupCache::lookupSlice(dstPhysAddr, dstWidth, dstHeight, dstPitch, dstLevel, dstSlice, dstSurfaceFormat);\n\tif (destinationView)\n\t\tdestinationTexture = destinationView->baseTexture;\n\n\t// create destination texture if it doesnt exist\n\tif (!destinationTexture)\n\t{\n\t\tLatteTexture* renderTargetConf = nullptr;\n\t\tdestinationView = LatteTexture_CreateMapping(dstPhysAddr, dstMipAddr, dstWidth, dstHeight, dstDepth, dstPitch, dstTilemode, dstSwizzle, dstLevel, 1, dstSlice, 1, dstSurfaceFormat, dstDim, Latte::IsMSAA(dstDim) ? Latte::E_DIM::DIM_2D_MSAA : Latte::E_DIM::DIM_2D, false);\n\t\tdestinationTexture = destinationView->baseTexture;\n\t}\n\t// copy texture\n\tif (sourceTexture && destinationTexture)\n\t{\n\t\t// mark source and destination texture as still in use\n\t\tLatteTC_MarkTextureStillInUse(destinationTexture);\n\t\tLatteTC_MarkTextureStillInUse(sourceTexture);\n\t\tsint32 realSrcSlice = srcSlice;\n\t\tif (LatteTexture_doesEffectiveRescaleRatioMatch(sourceTexture, sourceView->firstMip, destinationTexture, destinationView->firstMip))\n\t\t{\n\t\t\t// adjust copy size\n\t\t\tsint32 copyWidth = std::max(srcWidth >> srcLevel, 1);\n\t\t\tsint32 copyHeight = std::max(srcHeight >> srcLevel, 1);\n\t\t\t// use the smaller width/height as copy size\n\t\t\tcopyWidth = std::min(copyWidth, std::max(dstWidth >> dstLevel, 1));\n\t\t\tcopyHeight = std::min(copyHeight, std::max(dstHeight >> dstLevel, 1));\n\t\t\tsint32 effectiveCopyWidth = copyWidth;\n\t\t\tsint32 effectiveCopyHeight = copyHeight;\n\t\t\tLatteTexture_scaleToEffectiveSize(sourceTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0);\n\t\t\t// copy slice\n\t\t\tif (sourceView->baseTexture->isDepth != destinationView->baseTexture->isDepth)\n\t\t\t\tg_renderer->surfaceCopy_copySurfaceWithFormatConversion(sourceTexture, sourceView->firstMip, sourceView->firstSlice, destinationTexture, destinationView->firstMip, destinationView->firstSlice, copyWidth, copyHeight);\n\t\t\telse\n\t\t\t\tg_renderer->texture_copyImageSubData(sourceTexture, sourceView->firstMip, 0, 0, realSrcSlice, destinationTexture, destinationView->firstMip, 0, 0, destinationView->firstSlice, effectiveCopyWidth, effectiveCopyHeight, 1);\n\t\t\tconst uint64 eventCounter = LatteTexture_getNextUpdateEventCounter();\n\t\t\tLatteTexture_MarkDynamicTextureAsChanged(destinationTexture->baseView, destinationView->firstSlice, destinationView->firstMip, eventCounter);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebug_printf(\"gx2CP_itHLECopySurface(): Copy texture with non-matching effective size\\n\");\n\t\t}\n\t\tLatteTC_ResetTextureChangeTracker(destinationTexture);\n\t\t// flag texture as updated\n\t\tdestinationTexture->lastUpdateEventCounter = LatteTexture_getNextUpdateEventCounter();\n\t\tdestinationTexture->isUpdatedOnGPU = true; // todo - also track update flag per-slice\n\t}\n\telse\n\t\tdebug_printf(\"Source or destination texture does not exist\\n\");\n\n\t// download destination texture if it matches known accessed formats\n\tif (destinationTexture->width == 8 && destinationTexture->height == 8 && destinationTexture->tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THIN1)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Texture readback after copy for Bayonetta 2 (phys: 0x{:08x})\", destinationTexture->physAddress);\n\t\tLatteTextureReadback_Initate(destinationView);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTexture.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n\n#include <boost/container/small_vector.hpp>\n\nstruct TexMemOccupancyEntry\n{\n\tuint32 addrStart;\n\tuint32 addrEnd;\n\tLatteTextureSliceMipInfo* sliceMipInfo;\n};\n\n#define TEX_OCCUPANCY_BUCKET_COUNT\t\t(0x800) // each bucket covers a range of 2MB\n#define TEX_OCCUPANCY_BUCKET_SIZE\t\t(0x100000000/TEX_OCCUPANCY_BUCKET_COUNT)\n\n#define loopItrMemOccupancyBuckets(__startAddr, __endAddr)\t\tfor(sint32 startBucketIndex = ((__startAddr)/TEX_OCCUPANCY_BUCKET_SIZE), bucketIndex=startBucketIndex; bucketIndex<=((__endAddr-1)/TEX_OCCUPANCY_BUCKET_SIZE); bucketIndex++)\n\nstd::vector<TexMemOccupancyEntry> list_texMemOccupancyBucket[TEX_OCCUPANCY_BUCKET_COUNT];\n\nstd::atomic_bool s_refreshTextureQueryList;\nstd::vector<LatteTextureInformation> s_cacheInfoList;\n\nstd::vector<LatteTextureInformation> LatteTexture_QueryCacheInfo()\n{\n\t// raise request flag to refresh cache\n\ts_refreshTextureQueryList.store(true);\n\t// wait until cleared or until timeout occurred\n\tauto begin = std::chrono::high_resolution_clock::now();\n\twhile (true)\n\t{\n\t\tif (!s_refreshTextureQueryList)\n\t\t\tbreak;\n\t\tauto dur = std::chrono::high_resolution_clock::now() - begin;\n\t\tauto ms = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();\n\t\tif (ms >= 1000) // dont stall more than one second\n\t\t\treturn std::vector<LatteTextureInformation>();\n\t}\n\treturn s_cacheInfoList;\n}\n\nvoid LatteTexture_RefreshInfoCache()\n{\n\tif (!s_refreshTextureQueryList)\n\t\treturn;\n\tstd::vector<LatteTextureInformation> infoCache;\n\tstd::set<LatteTexture*> visitedTextures;\n\n\tstd::unordered_set<LatteTextureView*> allViews = LatteTextureViewLookupCache::GetAllViews();\n\tfor (auto& it : allViews)\n\t{\n\t\tLatteTexture* baseTexture = it->baseTexture;\n\t\tif(visitedTextures.find(baseTexture) != visitedTextures.end())\n\t\t\tcontinue;\n\t\tvisitedTextures.emplace(baseTexture);\n\t\t// add cache info\n\t\tauto& entry = infoCache.emplace_back();\n\t\tentry.physAddress = baseTexture->physAddress;\n\t\tentry.physMipAddress = baseTexture->physMipAddress;\n\t\tentry.width = baseTexture->width;\n\t\tentry.height = baseTexture->height;\n\t\tentry.depth = baseTexture->depth;\n\t\tentry.pitch = baseTexture->pitch;\n\t\tentry.mipLevels = baseTexture->mipLevels;\n\t\tentry.format = baseTexture->format;\n\t\tentry.isDepth = baseTexture->isDepth;\n\t\tentry.dim = baseTexture->dim;\n\t\tentry.tileMode = baseTexture->tileMode;\n\t\tentry.lastAccessTick = baseTexture->lastAccessTick;\n\t\tentry.lastAccessFrameCount = baseTexture->lastAccessFrameCount;\n\t\tentry.isUpdatedOnGPU = baseTexture->isUpdatedOnGPU;\n\t\t// overwrite info\n\t\tentry.overwriteInfo.hasResolutionOverwrite = baseTexture->overwriteInfo.hasResolutionOverwrite;\n\t\tentry.overwriteInfo.width = baseTexture->overwriteInfo.width;\n\t\tentry.overwriteInfo.height = baseTexture->overwriteInfo.height;\n\t\tentry.overwriteInfo.depth = baseTexture->overwriteInfo.depth;\n\t\t// count number of alternative views\n\t\tentry.alternativeViewCount = 0;\n\t\t// views\n\t\tfor (auto& viewItr : baseTexture->views)\n\t\t{\n\t\t\tif(viewItr == baseTexture->baseView)\n\t\t\t\tcontinue;\n\t\t\tauto& viewEntry = entry.views.emplace_back();\n\t\t\tviewEntry.physAddress = viewItr->baseTexture->physAddress;\n\t\t\tviewEntry.physMipAddress = viewItr->baseTexture->physMipAddress;\n\t\t\tviewEntry.width = viewItr->baseTexture->width;\n\t\t\tviewEntry.height = viewItr->baseTexture->height;\n\t\t\tviewEntry.pitch = viewItr->baseTexture->pitch;\n\t\t\tviewEntry.firstMip = viewItr->firstMip;\n\t\t\tviewEntry.numMip = viewItr->numMip;\n\t\t\tviewEntry.firstSlice = viewItr->firstSlice;\n\t\t\tviewEntry.numSlice = viewItr->numSlice;\n\t\t\tviewEntry.format = viewItr->format;\n\t\t\tviewEntry.dim = viewItr->dim;\n\t\t}\n\t}\n\tstd::swap(s_cacheInfoList, infoCache);\n\ts_refreshTextureQueryList.store(false);\n}\n\nvoid LatteTexture_AddTexMemOccupancyInterval(LatteTextureSliceMipInfo* sliceMipInfo)\n{\n\tTexMemOccupancyEntry entry;\n\tentry.addrStart = sliceMipInfo->addrStart;\n\tentry.addrEnd = sliceMipInfo->addrEnd;\n\tentry.sliceMipInfo = sliceMipInfo;\n\tloopItrMemOccupancyBuckets(entry.addrStart, entry.addrEnd)\n\t\tlist_texMemOccupancyBucket[bucketIndex].push_back(entry);\n}\n\nvoid LatteTexture_RegisterTextureMemoryOccupancy(LatteTexture* texture)\n{\n\tsint32 mipLevels = texture->mipLevels;\n\tsint32 sliceCount = texture->depth;\n\tfor (sint32 mipIndex = 0; mipIndex < mipLevels; mipIndex++)\n\t{\n\t\tsint32 mipSliceCount;\n\t\tif (texture->Is3DTexture())\n\t\t\tmipSliceCount = std::max(1, sliceCount >> mipIndex);\n\t\telse\n\t\t\tmipSliceCount = sliceCount;\n\t\tfor (sint32 sliceIndex = 0; sliceIndex < mipSliceCount; sliceIndex++)\n\t\t{\n\t\t\tLatteTextureSliceMipInfo* sliceMipInfo = texture->sliceMipInfo + texture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tLatteTexture_AddTexMemOccupancyInterval(sliceMipInfo);\n\t\t}\n\t}\n}\n\nvoid LatteTexture_RemoveTexMemOccupancyInterval(LatteTexture* texture, LatteTextureSliceMipInfo* sliceMipInfo)\n{\n\tloopItrMemOccupancyBuckets(sliceMipInfo->addrStart, sliceMipInfo->addrEnd)\n\t{\n\t\tfor (sint32 i = 0; i < list_texMemOccupancyBucket[bucketIndex].size(); i++)\n\t\t{\n\t\t\tif (list_texMemOccupancyBucket[bucketIndex][i].sliceMipInfo->texture == texture)\n\t\t\t{\n\t\t\t\tlist_texMemOccupancyBucket[bucketIndex].erase(list_texMemOccupancyBucket[bucketIndex].begin() + i);\n\t\t\t\ti--;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid LatteTexture_UnregisterTextureMemoryOccupancy(LatteTexture* texture)\n{\n\tsint32 mipLevels = texture->mipLevels;\n\tsint32 sliceCount = texture->depth;\n\tfor (sint32 mipIndex = 0; mipIndex < mipLevels; mipIndex++)\n\t{\n\t\tsint32 mipSliceCount;\n\t\tif (texture->Is3DTexture())\n\t\t\tmipSliceCount = std::max(1, sliceCount >> mipIndex);\n\t\telse\n\t\t\tmipSliceCount = sliceCount;\n\t\tfor (sint32 sliceIndex = 0; sliceIndex < mipSliceCount; sliceIndex++)\n\t\t{\n\t\t\tLatteTextureSliceMipInfo* sliceMipInfo = texture->sliceMipInfo + texture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tLatteTexture_RemoveTexMemOccupancyInterval(texture, sliceMipInfo);\n\t\t}\n\t}\n}\n\n// calculate the actually accessed data range\n// the resulting range is an estimate and may be smaller than the actual slice size (but not larger)\nvoid LatteTexture_EstimateMipSliceAccessedDataRange(LatteTexture* texture, sint32 sliceIndex, sint32 mipIndex, LatteTextureSliceMipInfo* sliceMipInfo)\n{\n\tuint32 estAddrStart;\n\tuint32 estAddrEnd;\n\tLatteTextureLoader_estimateAccessedDataRange(texture, sliceIndex, mipIndex, estAddrStart, estAddrEnd);\n\n\tcemu_assert_debug(estAddrStart >= sliceMipInfo->addrStart);\n\tcemu_assert_debug(estAddrEnd <= sliceMipInfo->addrEnd);\n\tcemu_assert_debug(estAddrStart <= estAddrEnd);\n\n\tsliceMipInfo->estDataAddrStart = estAddrStart;\n\tsliceMipInfo->estDataAddrEnd = estAddrEnd;\n}\n\nvoid LatteTexture_InitSliceAndMipInfo(LatteTexture* texture)\n{\n\tcemu_assert_debug(texture->mipLevels > 0);\n\tcemu_assert_debug(texture->depth > 0);\n\tsint32 mipSliceCount = texture->GetSliceMipArraySize();\n\ttexture->sliceMipInfo = new LatteTextureSliceMipInfo[mipSliceCount]();\n\t// todo - mipLevels can be greater than maximum possible mip count. How to handle this? Probably should differentiate between mipLevels and effective mip levels\n\tsint32 mipLevels = texture->mipLevels;\n\tsint32 sliceCount = texture->depth;\n\n\tfor (sint32 mipIndex = 0; mipIndex < mipLevels; mipIndex++)\n\t{\n\t\tsint32 mipSliceCount;\n\t\tif (texture->Is3DTexture())\n\t\t{\n\t\t\tmipSliceCount = std::max(1, sliceCount >> mipIndex);\n\t\t}\n\t\telse\n\t\t\tmipSliceCount = sliceCount;\n\t\tfor (sint32 sliceIndex = 0; sliceIndex < mipSliceCount; sliceIndex++)\n\t\t{\n\t\t\tuint32 calcSliceAddr;\n\t\t\tuint32 calcSliceSize;\n\t\t\tsint32 calcSubSliceIndex;\n\t\t\tLatteAddrLib::CalculateMipAndSliceAddr(texture->physAddress, texture->physMipAddress, texture->format, texture->width, texture->height, texture->depth, texture->dim, texture->tileMode, texture->swizzle, 0, mipIndex, sliceIndex, &calcSliceAddr, &calcSliceSize, &calcSubSliceIndex);\n\t\t\tLatteTextureSliceMipInfo* sliceMipInfo = texture->sliceMipInfo + texture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tsliceMipInfo->addrStart = calcSliceAddr;\n\t\t\tsliceMipInfo->addrEnd = calcSliceAddr + calcSliceSize;\n\t\t\tsliceMipInfo->subIndex = calcSubSliceIndex;\n\t\t\tsliceMipInfo->dataChecksum = 0;\n\t\t\tsliceMipInfo->sliceIndex = sliceIndex;\n\t\t\tsliceMipInfo->mipIndex = mipIndex;\n\t\t\tsliceMipInfo->texture = texture;\n\t\t\t// get additional slice/mip info\n\t\t\tLatteAddrLib::AddrSurfaceInfo_OUT surfaceInfo;\n\t\t\tLatteAddrLib::GX2CalculateSurfaceInfo(texture->format, texture->width, texture->height, texture->depth, texture->dim, Latte::MakeGX2TileMode(texture->tileMode), 0, mipIndex, &surfaceInfo);\n\t\t\tsliceMipInfo->tileMode = surfaceInfo.hwTileMode;\n\n\t\t\tif (mipIndex == 0)\n\t\t\t\tsliceMipInfo->pitch = texture->pitch; // for the base level, use the pitch value configured in hardware\n\t\t\telse\n\t\t\t\tsliceMipInfo->pitch = surfaceInfo.pitch;\n\t\t\tLatteTexture_EstimateMipSliceAccessedDataRange(texture, sliceIndex, mipIndex, sliceMipInfo);\n\t\t}\n\t}\n}\n\n// if this function returns false, textures will not be synchronized even if their data overlaps\nbool LatteTexture_IsFormatViewCompatible(Latte::E_GX2SURFFMT formatA, Latte::E_GX2SURFFMT formatB)\n{\n\tif(formatA == formatB)\n\t\treturn true; // if the format is identical then compatibility must be guaranteed (otherwise we can't create the necessary default view of a texture)\n\n\t// todo - find a better way to handle this\n\tfor (sint32 swap = 0; swap < 2; swap++)\n\t{\n\t\t// other formats\n\t\t// seems like format 0x19 (RGB10_A2) has issues on OpenGL Intel and AMD when copying texture data\n\t\tLatte::E_HWSURFFMT hwFormatA = Latte::GetHWFormat(formatA);\n\t\tLatte::E_HWSURFFMT hwFormatB = Latte::GetHWFormat(formatB);\n\t\tif (hwFormatA == Latte::E_HWSURFFMT::HWFMT_2_10_10_10 && formatB == Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT)\n\t\t\treturn false;\n\t\tif (formatA == Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT && hwFormatB == Latte::E_HWSURFFMT::HWFMT_2_10_10_10)\n\t\t\treturn false;\n\n\t\tif (hwFormatA == Latte::E_HWSURFFMT::HWFMT_2_10_10_10 && formatB == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM)\n\t\t\treturn false;\n\t\tif (formatA == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM && hwFormatB == Latte::E_HWSURFFMT::HWFMT_2_10_10_10)\n\t\t\treturn false;\n\n\t\t// format A1B5G5R5 views are not compatible with other 16-bit formats in OpenGL\n\t\tif (formatA == Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM || formatB == Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM)\n\t\t\treturn false;\n\t\t// used in N64 VC (E.g. Super Mario 64)\n\n\t\t// used in Smash\n\t\tif (formatA == Latte::E_GX2SURFFMT::D24_S8_UNORM && formatB == Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM)\n\t\t\treturn false;\n\t\tif (formatA == Latte::E_GX2SURFFMT::R32_FLOAT && formatB == Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM)\n\t\t\treturn false;\n\n\t\t// loop again with swapped vars\n\t\tLatte::E_GX2SURFFMT temp = formatA;\n\t\tformatA = formatB;\n\t\tformatB = temp;\n\t}\n\treturn true;\n}\n\nbool LatteTexture_IsTexelSizeCompatibleFormat(Latte::E_GX2SURFFMT formatA, Latte::E_GX2SURFFMT formatB)\n{\n\t// handle some special cases where formats are incompatible regardless of equal bpp\n\tif (formatA == Latte::E_GX2SURFFMT::D24_S8_UNORM && formatB == Latte::E_GX2SURFFMT::D32_FLOAT)\n\t\treturn false;\n\tif (Latte::IsCompressedFormat(formatA) && Latte::IsCompressedFormat(formatB))\n\t{\n\t\tif (Latte::GetHWFormat(formatA) != Latte::GetHWFormat(formatB))\n\t\t\treturn false; // compressed formats with different encodings are considered incompatible\n\t}\n\treturn Latte::GetFormatBits((Latte::E_GX2SURFFMT)formatA) == Latte::GetFormatBits((Latte::E_GX2SURFFMT)formatB);\n}\n\nvoid LatteTexture_copyData(LatteTexture* srcTexture, LatteTexture* dstTexture, sint32 mipCount, sint32 sliceCount)\n{\n\tcemu_assert_debug(mipCount != 0);\n\tcemu_assert_debug(sliceCount != 0);\n\tsint32 effectiveCopyWidth = srcTexture->width;\n\tsint32 effectiveCopyHeight = srcTexture->height;\n\tif (LatteTexture_doesEffectiveRescaleRatioMatch(dstTexture, 0, srcTexture, 0))\n\t{\n\t\t// adjust copy size\n\t\tLatteTexture_scaleToEffectiveSize(dstTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0);\n\t}\n\telse\n\t{\n\t\tsint32 effectiveWidth_dst, effectiveHeight_dst;\n\t\tsrcTexture->GetEffectiveSize(effectiveWidth_dst, effectiveHeight_dst, 0);\n\t\tsint32 effectiveWidth_src, effectiveHeight_src;\n\t\tdstTexture->GetEffectiveSize(effectiveWidth_src, effectiveHeight_src, 0);\n\n\t\tdebug_printf(\"texture_copyData(): Effective size mismatch\\n\");\n\t\tcemuLog_logDebug(LogType::Force, \"texture_copyData(): Effective size mismatch (due to texture rule)\");\n\t\tcemuLog_logDebug(LogType::Force, \"Destination: origResolution {:04}x{:04} effectiveResolution {:04}x{:04} fmt {:04x} mipIndex {}\", srcTexture->width, srcTexture->height, effectiveWidth_dst, effectiveHeight_dst, (uint32)dstTexture->format, 0);\n\t\tcemuLog_logDebug(LogType::Force, \"Source:      origResolution {:04}x{:04} effectiveResolution {:04}x{:04} fmt {:04x} mipIndex {}\", srcTexture->width, srcTexture->height, effectiveWidth_src, effectiveHeight_src, (uint32)srcTexture->format, 0);\n\t\treturn;\n\t}\n\tfor (sint32 mipIndex = 0; mipIndex < mipCount; mipIndex++)\n\t{\n\t\tsint32 sliceCopyWidth = std::max(effectiveCopyWidth >> mipIndex, 1);\n\t\tsint32 sliceCopyHeight = std::max(effectiveCopyHeight >> mipIndex, 1);\n\t\tg_renderer->texture_copyImageSubData(srcTexture, mipIndex, 0, 0, 0, dstTexture, mipIndex, 0, 0, 0, sliceCopyWidth, sliceCopyHeight, sliceCount);\n\t\tsint32 mipSliceCount = sliceCount;\n\t\tif (dstTexture->Is3DTexture())\n\t\t\tmipSliceCount >>= mipIndex;\n\t\tfor (sint32 sliceIndex = 0; sliceIndex < mipSliceCount; sliceIndex++)\n\t\t{\n\t\t\tLatteTextureSliceMipInfo* srcTexSliceInfo = srcTexture->sliceMipInfo + srcTexture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tLatteTextureSliceMipInfo* dstTexSliceInfo = dstTexture->sliceMipInfo + dstTexture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tdstTexSliceInfo->lastDynamicUpdate = srcTexSliceInfo->lastDynamicUpdate;\n\t\t}\n\t}\n}\n\ntemplate<bool bothMustMatch>\nbool LatteTexture_DoesWidthHeightMatch(Latte::E_GX2SURFFMT format1, uint32 width1, uint32 height1, Latte::E_GX2SURFFMT format2, uint32 width2, uint32 height2)\n{\n\tif (Latte::IsCompressedFormat(format1))\n\t{\n\t\twidth1 <<= 2;\n\t\theight1 <<= 2;\n\t}\n\tif (Latte::IsCompressedFormat(format2))\n\t{\n\t\twidth2 <<= 2;\n\t\theight2 <<= 2;\n\t}\n\tif constexpr(bothMustMatch)\n\t\treturn width1 == width2 && height1 == height2;\n\telse\n\t\treturn width1 == width2 || height1 == height2;\n}\n\nvoid LatteTexture_CopySlice(LatteTexture* srcTexture, sint32 srcSlice, sint32 srcMip, LatteTexture* dstTexture, sint32 dstSlice, sint32 dstMip, sint32 srcX, sint32 srcY, sint32 dstX, sint32 dstY, sint32 width, sint32 height)\n{\n\tif (srcTexture->isDepth != dstTexture->isDepth)\n\t{\n\t\tg_renderer->surfaceCopy_copySurfaceWithFormatConversion(srcTexture, srcMip, srcSlice, dstTexture, dstMip, dstSlice, width, height);\n\t\treturn;\n\t}\n\t// rescale copy size\n\tsint32 effectiveCopyWidth = width;\n\tsint32 effectiveCopyHeight = height;\n\tLatteTexture_scaleToEffectiveSize(srcTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0);\n\n\tsint32 effectiveSrcX = srcX;\n\tsint32 effectiveSrcY = srcY;\n\tLatteTexture_scaleToEffectiveSize(srcTexture, &effectiveSrcX, &effectiveSrcY, 0);\n\n\tsint32 effectiveDstX = dstX;\n\tsint32 effectiveDstY = dstY;\n\tLatteTexture_scaleToEffectiveSize(dstTexture, &effectiveDstX, &effectiveDstY, 0);\n\n\t// check if rescale is compatible\n\tif (LatteTexture_doesEffectiveRescaleRatioMatch(dstTexture, 0, srcTexture, 0) == false)\n\t{\n\t\tsint32 effectiveWidth_src = srcTexture->overwriteInfo.hasResolutionOverwrite ? srcTexture->overwriteInfo.width : srcTexture->width;\n\t\tsint32 effectiveHeight_src = srcTexture->overwriteInfo.hasResolutionOverwrite ? srcTexture->overwriteInfo.height : srcTexture->height;\n\t\tsint32 effectiveWidth_dst = dstTexture->overwriteInfo.hasResolutionOverwrite ? dstTexture->overwriteInfo.width : dstTexture->width;\n\t\tsint32 effectiveHeight_dst = dstTexture->overwriteInfo.hasResolutionOverwrite ? dstTexture->overwriteInfo.height : dstTexture->height;\n\t\tif (cemuLog_isLoggingEnabled(LogType::TextureCache))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"_copySlice(): Unable to sync textures with mismatching scale ratio (due to texture rule)\");\n\t\t\tfloat ratioWidth_src = (float)effectiveWidth_src / (float)srcTexture->width;\n\t\t\tfloat ratioHeight_src = (float)effectiveHeight_src / (float)srcTexture->height;\n\t\t\tfloat ratioWidth_dst = (float)effectiveWidth_dst / (float)dstTexture->width;\n\t\t\tfloat ratioHeight_dst = (float)effectiveHeight_dst / (float)dstTexture->height;\n\t\t\tcemuLog_log(LogType::Force, \"Source:      {:08x} origResolution {:4}/{:4} effectiveResolution {:4}/{:4} fmt {:04x} mipIndex {} ratioW/H: {:.4}/{:.4}\", srcTexture->physAddress, srcTexture->width, srcTexture->height, effectiveWidth_src, effectiveHeight_src, (uint32)srcTexture->format, srcMip, ratioWidth_src, ratioHeight_src);\n\t\t\tcemuLog_log(LogType::Force, \"Destination: {:08x} origResolution {:4}/{:4} effectiveResolution {:4}/{:4} fmt {:04x} mipIndex {} ratioW/H: {:.4}/{:.4}\", dstTexture->physAddress, dstTexture->width, dstTexture->height, effectiveWidth_dst, effectiveHeight_dst, (uint32)dstTexture->format, dstMip, ratioWidth_dst, ratioHeight_dst);\n\t\t}\n\t\t//cemuLog_logDebug(LogType::Force, \"If these textures are not meant to share data you can ignore this\");\n\t\treturn;\n\t}\n\t// todo - store 'lastUpdated' value per slice/mip and copy it's value when copying the slice data\n\tg_renderer->texture_copyImageSubData(srcTexture, srcMip, effectiveSrcX, effectiveSrcY, srcSlice, dstTexture, dstMip, effectiveDstX, effectiveDstY, dstSlice, effectiveCopyWidth, effectiveCopyHeight, 1);\n}\n\nbool LatteTexture_GetSubtextureSliceAndMip(LatteTexture* baseTexture, LatteTexture* mipTexture, sint32* baseSliceIndex, sint32* baseMipIndex)\n{\n\tLatteTextureSliceMipInfo* mipTextureSliceInfo = mipTexture->sliceMipInfo + mipTexture->GetSliceMipArrayIndex(0, 0);\n\t// todo - this can be optimized by first determining the mip level from pitch\n\tfor (sint32 mipIndex = 0; mipIndex < baseTexture->mipLevels; mipIndex++)\n\t{\n\t\tsint32 sliceCount;\n\t\tif (baseTexture->Is3DTexture())\n\t\t\tsliceCount = std::max(baseTexture->depth >> mipIndex, 1);\n\t\telse\n\t\t\tsliceCount = baseTexture->depth;\n\t\tfor (sint32 sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++)\n\t\t{\n\t\t\tLatteTextureSliceMipInfo* sliceMipInfo = baseTexture->sliceMipInfo + baseTexture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tif (sliceMipInfo->addrStart == mipTextureSliceInfo->addrStart && sliceMipInfo->subIndex == mipTextureSliceInfo->subIndex)\n\t\t\t{\n\t\t\t\t*baseSliceIndex = sliceIndex;\n\t\t\t\t*baseMipIndex = mipIndex;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// todo - support overlapping textures with a non-zero y-offset\n\t\t}\n\t}\n\treturn false;\n}\n\n// if a texture shares memory with another texture then flag those textures as invalidated (on next use, synchronize data)\nvoid LatteTexture_MarkDynamicTextureAsChanged(LatteTextureView* textureView, sint32 sliceIndex, sint32 mipIndex, uint64 eventCounter)\n{\n\tLatteTexture* baseTexture = textureView->baseTexture;\n\tbaseTexture->lastWriteEventCounter = eventCounter;\n\n\tsint32 aSliceIndex = textureView->firstSlice + sliceIndex;\n\tsint32 aMipIndex = textureView->firstMip + mipIndex;\n\tLatteTextureSliceMipInfo* baseSliceMipInfo = baseTexture->sliceMipInfo + baseTexture->GetSliceMipArrayIndex(aSliceIndex, aMipIndex);\n\tbaseSliceMipInfo->lastDynamicUpdate = eventCounter;\n\n\tLatteTexture_MarkConnectedTexturesForReloadFromDynamicTextures(textureView->baseTexture);\n}\n\nvoid LatteTexture_SyncSlice(LatteTexture* srcTexture, sint32 srcSliceIndex, sint32 srcMipIndex, LatteTexture* dstTexture, sint32 dstSliceIndex, sint32 dstMipIndex)\n{\n\tsint32 srcWidth = srcTexture->width;\n\tsint32 srcHeight = srcTexture->height;\n\tsint32 dstWidth = dstTexture->width;\n\tsint32 dstHeight = dstTexture->height;\n\n\tif(srcTexture->overwriteInfo.hasFormatOverwrite != dstTexture->overwriteInfo.hasFormatOverwrite)\n\t\treturn; // dont sync: format overwrite state needs to match. Not strictly necessary but it simplifies logic down the road\n\telse if(srcTexture->overwriteInfo.hasFormatOverwrite && srcTexture->overwriteInfo.format != dstTexture->overwriteInfo.format)\n\t\treturn; // both are overwritten but with different formats\n\n\tif (srcMipIndex == 0 && dstMipIndex == 0 && (srcTexture->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED || srcTexture->tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THIN1) && srcTexture->height > dstTexture->height && (srcTexture->height % dstTexture->height) == 0)\n\t{\n\t\tbool isMatch = srcTexture->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED;\n\t\tif (srcTexture->tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THIN1 && srcTexture->width == 32)\n\t\t{\n\t\t\t// special case for CoD BO2, where 1024x32 and 32x32x32 textures share memory\n\t\t\tisMatch = true;\n\t\t}\n\n\t\tif (isMatch && srcTexture->IsCompressedFormat() == false && dstTexture->IsCompressedFormat() == false)\n\t\t{\n\t\t\tsint32 virtualSlices = srcTexture->height / dstTexture->height;\n\t\t\tif (dstTexture->depth == virtualSlices)\n\t\t\t{\n\t\t\t\t// special case for Ninja Gaiden\n\t\t\t\t// it initializes a 24x24x24 texture array as a 24x576x1 2D texture (using tilemode 1)\n\t\t\t\tsint32 copyWidth = std::min(srcWidth, dstWidth);\n\t\t\t\tsint32 copyHeight = std::min(srcHeight, dstHeight);\n\t\t\t\tfor (sint32 slice = 0; slice < virtualSlices; slice++)\n\t\t\t\t\tLatteTexture_CopySlice(srcTexture, srcSliceIndex, srcMipIndex, dstTexture, dstSliceIndex + slice, dstMipIndex, 0, slice * dstTexture->height, 0, 0, copyWidth, copyHeight);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\n\tbool srcIsCompressed = srcTexture->IsCompressedFormat();\n\tbool dstIsCompressed = dstTexture->IsCompressedFormat();\n\n\tif (srcIsCompressed != dstIsCompressed)\n\t{\n\t\t// convert into unit of source texture\n\t\tif (srcIsCompressed == false)\n\t\t{\n\t\t\t// destination compressed, source uncompressed (integer format)\n\t\t\tdstWidth >>= 2;\n\t\t\tdstHeight >>= 2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// destination uncompressed (integer format), source compressed\n\t\t\tdstWidth <<= 2;\n\t\t\tdstHeight <<= 2;\n\t\t}\n\t}\n\n\tsrcWidth = std::max(srcWidth >> srcMipIndex, 1);\n\tsrcHeight = std::max(srcHeight >> srcMipIndex, 1);\n\tdstWidth = std::max(dstWidth >> dstMipIndex, 1);\n\tdstHeight = std::max(dstHeight >> dstMipIndex, 1);\n\n\tsint32 copyWidth = std::min(srcWidth, dstWidth);\n\tsint32 copyHeight = std::min(srcHeight, dstHeight);\n\n\tLatteTexture_CopySlice(srcTexture, srcSliceIndex, srcMipIndex, dstTexture, dstSliceIndex, dstMipIndex, 0, 0, 0, 0, copyWidth, copyHeight);\n\n}\n\nvoid LatteTexture_UpdateTextureFromDynamicChanges(LatteTexture* texture)\n{\n\t// note: Currently this function assumes that only one other texture is updated per slice/mip (if multiple overlap, we should merge the one with the latest timestamp the latest of each individually)\n\tfor (auto& texRel : texture->list_compatibleRelations)\n\t{\n\t\tLatteTexture* baseTexture = texRel->baseTexture;\n\t\tLatteTexture* subTexture = texRel->subTexture;\n\t\tfor (sint32 cMipIndex = 0; cMipIndex < texRel->mipCount; cMipIndex++)\n\t\t{\n\t\t\tsint32 mipSliceCount = texRel->sliceCount;\n\t\t\tif (texRel->baseTexture->Is3DTexture())\n\t\t\t{\n\t\t\t\tcemu_assert_debug(cMipIndex == 0); // values above 0 need testing\n\t\t\t\tmipSliceCount >>= cMipIndex;\n\t\t\t}\n\n\t\t\tfor (sint32 cSliceIndex = 0; cSliceIndex < mipSliceCount; cSliceIndex++)\n\t\t\t{\n\t\t\t\tLatteTextureSliceMipInfo* baseSliceMipInfo = baseTexture->sliceMipInfo + baseTexture->GetSliceMipArrayIndex(texRel->baseSliceIndex + cSliceIndex, texRel->baseMipIndex + cMipIndex);\n\t\t\t\tLatteTextureSliceMipInfo* subSliceMipInfo = subTexture->sliceMipInfo + subTexture->GetSliceMipArrayIndex(cSliceIndex, cMipIndex);\n\t\t\t\tif (texture == baseTexture)\n\t\t\t\t{\n\t\t\t\t\t// baseTexture is target texture\n\t\t\t\t\tif (baseSliceMipInfo->lastDynamicUpdate < subSliceMipInfo->lastDynamicUpdate)\n\t\t\t\t\t{\n\t\t\t\t\t\tLatteTexture_SyncSlice(subTexture, cSliceIndex, cMipIndex, baseTexture, texRel->baseSliceIndex + cSliceIndex, texRel->baseMipIndex + cMipIndex);\n\t\t\t\t\t\tbaseSliceMipInfo->lastDynamicUpdate = subSliceMipInfo->lastDynamicUpdate;\n\t\t\t\t\t\tif(subTexture->isUpdatedOnGPU)\n\t\t\t\t\t\t\ttexture->isUpdatedOnGPU = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// subTexture is target texture\n\t\t\t\t\tif (subSliceMipInfo->lastDynamicUpdate < baseSliceMipInfo->lastDynamicUpdate)\n\t\t\t\t\t{\n\t\t\t\t\t\tLatteTexture_SyncSlice(baseTexture, texRel->baseSliceIndex + cSliceIndex, texRel->baseMipIndex + cMipIndex, subTexture, cSliceIndex, cMipIndex);\n\t\t\t\t\t\tsubSliceMipInfo->lastDynamicUpdate = baseSliceMipInfo->lastDynamicUpdate;\n\t\t\t\t\t\tif (baseTexture->isUpdatedOnGPU)\n\t\t\t\t\t\t\ttexture->isUpdatedOnGPU = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nbool _LatteTexture_IsTileModeCompatible(LatteTexture* texture1, sint32 mipIndex1, LatteTexture* texture2, sint32 mipIndex2)\n{\n\tif (mipIndex1 == 0 && mipIndex2 == 0)\n\t\treturn texture1->tileMode == texture2->tileMode;\n\n\tLatteTextureSliceMipInfo* texture1SliceInfo = texture1->sliceMipInfo + texture1->GetSliceMipArrayIndex(0, mipIndex1);\n\tLatteTextureSliceMipInfo* texture2SliceInfo = texture2->sliceMipInfo + texture2->GetSliceMipArrayIndex(0, mipIndex2);\n\tif (texture1SliceInfo->tileMode == texture2SliceInfo->tileMode)\n\t\treturn true;\n\treturn false;\n}\n\nbool __LatteTexture_IsBlockedFormatRelation(LatteTexture* texture1, LatteTexture* texture2)\n{\n\tif (texture1->isDepth && texture2->isDepth == false)\n\t{\n\t\t// necessary for Smash? (currently our depth to color copy always converts and the depth ends up in R only)\n\t\tif (texture1->format == Latte::E_GX2SURFFMT::D32_FLOAT && Latte::GetHWFormat(texture2->format) == Latte::E_HWSURFFMT::HWFMT_8_8_8_8)\n\t\t\treturn true;\n\t}\n\t// Vulkan has stricter rules\n\tif (g_renderer->GetType() == RendererAPI::Vulkan)\n\t{\n\t\t// found in Smash (Wii Fit Stage)\n\t\tif (texture1->format == Latte::E_GX2SURFFMT::D32_FLOAT && Latte::GetHWFormat(texture2->format) == Latte::E_HWSURFFMT::HWFMT_8_24)\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nbool LatteTexture_IsBlockedFormatRelation(LatteTexture* texture1, LatteTexture* texture2)\n{\n\tif (__LatteTexture_IsBlockedFormatRelation(texture1, texture2))\n\t\treturn true;\n\treturn __LatteTexture_IsBlockedFormatRelation(texture2, texture1);\n}\n\n// called if two textures are known to overlap in memory\n// this function then tries to figure out the details and registers the relation in texture*->list_compatibleRelations\nvoid LatteTexture_TrackTextureRelation(LatteTexture* texture1, LatteTexture* texture2)\n{\n\t// make sure texture 2 is always at texture 1 mip level 0 or beyond\n\tif (texture1->physAddress > texture2->physAddress)\n\t\treturn LatteTexture_TrackTextureRelation(texture2, texture1);\n\t// check if this texture relation is already tracked\n\tcemu_assert_debug(texture1->physAddress != 0);\n\tcemu_assert_debug(texture2->physAddress != 0);\n\tfor (auto& it : texture1->list_compatibleRelations)\n\t{\n\t\tif (it->baseTexture == texture1 && it->subTexture == texture2)\n\t\t\treturn; // association already known\n\t}\n\t// check for blocked format combination\n\tif (LatteTexture_IsBlockedFormatRelation(texture1, texture2))\n\t\treturn;\n\n\tif (texture1->physAddress == texture2->physAddress && false)\n\t{\n\t\t// both textures overlap at mip level 0\n\t\tcemu_assert_debug(texture1->swizzle == texture2->swizzle);\n\t\tcemu_assert_debug(texture1->tileMode == texture2->tileMode);\n\t\tif (LatteTexture_DoesWidthHeightMatch<false>(texture1->format, texture1->width, texture1->height, texture2->format, texture2->width, texture2->height))\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\telse\n\t{\n\t\tsint32 baseSliceIndex;\n\t\tsint32 baseMipIndex;\n\t\tif (texture1->physAddress == texture2->physAddress)\n\t\t{\n\t\t\tbaseSliceIndex = 0;\n\t\t\tbaseMipIndex = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (LatteTexture_GetSubtextureSliceAndMip(texture1, texture2, &baseSliceIndex, &baseMipIndex) == false)\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tsint32 sharedMipLevels = 1;\n\t\t// todo - support for multiple shared mip levels\n\t\t// check if pitch is compatible\n\t\tLatteTextureSliceMipInfo* texture1SliceInfo = texture1->sliceMipInfo + texture1->GetSliceMipArrayIndex(baseSliceIndex, baseMipIndex);\n\t\tLatteTextureSliceMipInfo* texture2SliceInfo = texture2->sliceMipInfo + texture2->GetSliceMipArrayIndex(0, 0);\n\t\tif (_LatteTexture_IsTileModeCompatible(texture1, baseMipIndex, texture2, 0) == false)\n\t\t\treturn; // not compatible\n\t\tif (texture1SliceInfo->pitch != texture2SliceInfo->pitch)\n\t\t\treturn; // not compatible\n\t\t// calculate compatible depth range\n\t\tsint32 baseRemainingDepth = texture1->GetMipDepth(baseMipIndex) - baseSliceIndex;\n\t\tcemu_assert_debug(baseRemainingDepth >= 0);\n\t\tsint32 compatibleDepthRange = std::min(baseRemainingDepth, texture2->depth);\n\t\tcemu_assert_debug(compatibleDepthRange > 0);\n\n\t\t// create association\n\t\tLatteTextureRelation* rel = (LatteTextureRelation*)malloc(sizeof(LatteTextureRelation));\n\t\tmemset(rel, 0, sizeof(LatteTextureRelation));\n\t\trel->baseTexture = texture1;\n\t\trel->subTexture = texture2;\n\t\trel->baseMipIndex = baseMipIndex;\n\t\trel->baseSliceIndex = baseSliceIndex;\n\t\trel->mipCount = sharedMipLevels;\n\t\trel->sliceCount = compatibleDepthRange;\n\t\trel->yOffset = 0; // todo\n\t\ttexture1->list_compatibleRelations.push_back(rel);\n\t\ttexture2->list_compatibleRelations.push_back(rel);\n\t}\n}\n\nvoid LatteTexture_TrackDataOverlap(LatteTexture* texture, LatteTextureSliceMipInfo* sliceMipInfo, TexMemOccupancyEntry& occupancy)\n{\n\t// todo - handle tile thickness and z offset\n\n\t// todo - check address range overlap\n\tauto& occMipSliceInfo = occupancy.sliceMipInfo;\n\n\tif ((sliceMipInfo->addrEnd > occMipSliceInfo->addrStart && sliceMipInfo->addrStart < occMipSliceInfo->addrEnd) == false)\n\t\treturn;\n\n\t// check if this overlap is already tracked\n\tfor (auto& it : sliceMipInfo->list_dataOverlap)\n\t{\n\t\tif (it.destMipSliceInfo == occupancy.sliceMipInfo)\n\t\t\treturn;\n\t}\n\t// register texture->dest\n\tLatteTextureSliceMipDataOverlap_t overlapEntry;\n\toverlapEntry.destMipSliceInfo = occupancy.sliceMipInfo;\n\toverlapEntry.destTexture = occupancy.sliceMipInfo->texture;\n\tsliceMipInfo->list_dataOverlap.push_back(overlapEntry);\n\t// register dest->texture\n\tLatteTextureSliceMipDataOverlap_t overlapEntry2;\n\toverlapEntry2.destMipSliceInfo = sliceMipInfo;\n\toverlapEntry2.destTexture = sliceMipInfo->texture;\n\toccupancy.sliceMipInfo->list_dataOverlap.push_back(overlapEntry2);\n}\n\nvoid _LatteTexture_RemoveDataOverlapTracking(LatteTexture* texture, LatteTextureSliceMipInfo* sliceMipInfo, LatteTextureSliceMipDataOverlap_t& dataOverlap)\n{\n\tLatteTexture* destTexture = dataOverlap.destTexture;\n\tLatteTextureSliceMipInfo* destSliceMipInfo = dataOverlap.destMipSliceInfo;\n\t// delete from dest\n\tfor (auto it = destSliceMipInfo->list_dataOverlap.begin(); it != destSliceMipInfo->list_dataOverlap.end();)\n\t{\n\t\tif (it->destTexture == texture)\n\t\t\tit = destSliceMipInfo->list_dataOverlap.erase(it);\n\t\telse if (it->destTexture == destTexture)\n\t\t\tcemu_assert_unimplemented();\n\t\telse\n\t\t\tit++;\n\t}\n}\n\nvoid LatteTexture_DeleteDataOverlapTracking(LatteTexture* texture, LatteTextureSliceMipInfo* sliceMipInfo)\n{\n\tfor(auto& it : sliceMipInfo->list_dataOverlap)\n\t\t_LatteTexture_RemoveDataOverlapTracking(texture, sliceMipInfo, it);\n\tsliceMipInfo->list_dataOverlap.resize(0);\n}\n\nvoid LatteTexture_DeleteDataOverlapTracking(LatteTexture* texture)\n{\n\tsint32 mipLevels = texture->mipLevels;\n\tsint32 sliceCount = texture->depth;\n\tfor (sint32 mipIndex = 0; mipIndex < mipLevels; mipIndex++)\n\t{\n\t\tsint32 mipSliceCount;\n\t\tif (texture->Is3DTexture())\n\t\t\tmipSliceCount = std::max(1, sliceCount >> mipIndex);\n\t\telse\n\t\t\tmipSliceCount = sliceCount;\n\t\tfor (sint32 sliceIndex = 0; sliceIndex < mipSliceCount; sliceIndex++)\n\t\t{\n\t\t\tLatteTextureSliceMipInfo* sliceMipInfo = texture->sliceMipInfo + texture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tLatteTexture_DeleteDataOverlapTracking(texture, sliceMipInfo);\n\t\t}\n\t}\n}\n\nvoid LatteTexture_GatherTextureRelations(LatteTexture* texture)\n{\n\tfor (sint32 mipIndex = 0; mipIndex < texture->mipLevels; mipIndex++)\n\t{\n\t\tsint32 mipSliceCount;\n\t\tif (texture->Is3DTexture())\n\t\t\tmipSliceCount = std::max(1, texture->depth >> mipIndex);\n\t\telse\n\t\t\tmipSliceCount = texture->depth;\n\t\tfor (sint32 sliceIndex = 0; sliceIndex < mipSliceCount; sliceIndex++)\n\t\t{\n\t\t\tLatteTextureSliceMipInfo* sliceMipInfo = texture->sliceMipInfo + texture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tloopItrMemOccupancyBuckets(sliceMipInfo->addrStart, sliceMipInfo->addrEnd)\n\t\t\t{\n\t\t\t\tfor (auto& occupancy : list_texMemOccupancyBucket[bucketIndex])\n\t\t\t\t{\n\t\t\t\t\tLatteTexture* itrTexture = occupancy.sliceMipInfo->texture;\n\t\t\t\t\tif (itrTexture == texture)\n\t\t\t\t\t\tcontinue; // ignore self\n\t\t\t\t\tif (sliceMipInfo->addrEnd >= occupancy.addrStart && sliceMipInfo->addrStart < occupancy.addrEnd)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (sliceMipInfo->addrStart == occupancy.addrStart && sliceMipInfo->subIndex == occupancy.sliceMipInfo->subIndex)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// overlapping with zero x/y offset\n\t\t\t\t\t\t\tif (sliceMipInfo->pitch == occupancy.sliceMipInfo->pitch && LatteTexture_IsTexelSizeCompatibleFormat(texture->format, itrTexture->format)\n\t\t\t\t\t\t\t\t&& sliceMipInfo->tileMode == occupancy.sliceMipInfo->tileMode &&\n\t\t\t\t\t\t\t\tLatteTexture_IsFormatViewCompatible(texture->format, itrTexture->format))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tLatteTexture_TrackTextureRelation(texture, itrTexture);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// pitch not compatible or format not compatible\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLatteTexture_TrackDataOverlap(texture, sliceMipInfo, occupancy);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid LatteTexture_DeleteTextureRelations(LatteTexture* texture)\n{\n\twhile (texture->list_compatibleRelations.empty() == false)\n\t{\n\t\tLatteTextureRelation* rel = texture->list_compatibleRelations[0];\n\t\trel->baseTexture->list_compatibleRelations.erase(std::find(rel->baseTexture->list_compatibleRelations.begin(), rel->baseTexture->list_compatibleRelations.end(), rel));\n\t\trel->subTexture->list_compatibleRelations.erase(std::find(rel->subTexture->list_compatibleRelations.begin(), rel->subTexture->list_compatibleRelations.end(), rel));\n\t\tfree(rel);\n\t}\n\ttexture->list_compatibleRelations.clear();\n}\n\nenum VIEWCOMPATIBILITY\n{\n\tVIEW_COMPATIBLE, // subtexture can be represented as view into base texture\n\tVIEW_BASE_TOO_SMALL, // base texture must be extended (depth or mip levels) to fit sub texture\n\tVIEW_NOT_COMPATIBLE,\n};\n\nbool IsDimensionCompatibleForGX2View(Latte::E_DIM baseDim, Latte::E_DIM viewDim)\n{\n\t// Note that some combinations depend on the exact view/slice index and count which we currently ignore (like a 3D view of a 3D texture)\n\tbool isCompatible =\n\t\t(baseDim == viewDim) ||\n\t\t(baseDim == Latte::E_DIM::DIM_CUBEMAP && viewDim == Latte::E_DIM::DIM_2D) ||\n\t\t(baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_2D_ARRAY) ||\n\t\t(baseDim == Latte::E_DIM::DIM_2D_ARRAY && viewDim == Latte::E_DIM::DIM_2D) ||\n\t\t(baseDim == Latte::E_DIM::DIM_CUBEMAP && viewDim == Latte::E_DIM::DIM_2D_ARRAY) ||\n\t\t(baseDim == Latte::E_DIM::DIM_2D_ARRAY && viewDim == Latte::E_DIM::DIM_CUBEMAP) ||\n\t\t(baseDim == Latte::E_DIM::DIM_3D && viewDim == Latte::E_DIM::DIM_2D_ARRAY);\n\tif(isCompatible)\n\t\treturn true;\n\t// these combinations have been seen in use by games and are considered incompatible:\n\t// (baseDim == Latte::E_DIM::DIM_2D_ARRAY && viewDim == Latte::E_DIM::DIM_3D) -> Not allowed on OpenGL\n\t// (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_2D_MSAA)\n\t// (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_1D)\n\t// (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_3D)\n\t// (baseDim == Latte::E_DIM::DIM_3D && viewDim == Latte::E_DIM::DIM_2D)\n\t// (baseDim == Latte::E_DIM::DIM_3D && viewDim == Latte::E_DIM::DIM_3D) -> Only compatible if the same depth and shared at mip/slice 0\n\t// (baseDim == Latte::E_DIM::DIM_2D && viewDim == Latte::E_DIM::DIM_CUBEMAP)\n\t// (baseDim == Latte::E_DIM::DIM_2D_MSAA && viewDim == Latte::E_DIM::DIM_2D)\n\t// (baseDim == Latte::E_DIM::DIM_1D && viewDim == Latte::E_DIM::DIM_2D)\n\treturn false;\n}\n\nVIEWCOMPATIBILITY LatteTexture_CanTextureBeRepresentedAsView(LatteTexture* baseTexture, uint32 physAddr, sint32 width, sint32 height, sint32 pitch, Latte::E_DIM dimView, Latte::E_GX2SURFFMT format, bool isDepth, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, sint32& relativeMipIndex, sint32& relativeSliceIndex)\n{\n\trelativeMipIndex = 0;\n\trelativeSliceIndex = 0;\n\tif (baseTexture->overwriteInfo.hasFormatOverwrite)\n\t{\n\t\t// if the base format is overwritten, then we only allow aliasing if the view format matches the base format\n\t\tif (baseTexture->format != format)\n\t\t\treturn VIEW_NOT_COMPATIBLE;\n\t}\n\tif (LatteTexture_IsFormatViewCompatible(baseTexture->format, format) == false)\n\t\treturn VIEW_NOT_COMPATIBLE;\n\tif (baseTexture->physAddress == physAddr && baseTexture->pitch == pitch)\n\t{\n\t\tif (baseTexture->isDepth != isDepth)\n\t\t\treturn VIEW_NOT_COMPATIBLE; // depth and non-depth formats are never compatible (on OpenGL)\n\t\tif (!LatteTexture_IsTexelSizeCompatibleFormat(baseTexture->format, format) || baseTexture->width != width || baseTexture->height != height)\n\t\t\treturn VIEW_NOT_COMPATIBLE;\n\t\t// 3D views are only compatible on Vulkan if they match the base texture in regards to mip and slice count\n\t\tbool isCompatible3DView = dimView == Latte::E_DIM::DIM_3D && baseTexture->dim == dimView && firstSlice == 0 && firstMip == 0 && baseTexture->mipLevels == numMip && baseTexture->depth == numSlice;\n\t\tif (!isCompatible3DView && !IsDimensionCompatibleForGX2View(baseTexture->dim, dimView))\n\t\t\treturn VIEW_NOT_COMPATIBLE;\n\t\tif (baseTexture->isDepth && baseTexture->format != format)\n\t\t{\n\t\t\t// depth view with different format\n\t\t\tcemuLog_logDebug(LogType::Force, \"_createMapping(): Incompatible depth view format\");\n\t\t\treturn VIEW_NOT_COMPATIBLE;\n\t\t}\n\n\t\t// AMD has a bug on OpenGL where it ignores the internal format of texture views when they are bound as render targets,\n\t\t// as a result we cant use texture views when they have a different format\n\t\tif (baseTexture->format != format)\n\t\t\treturn VIEW_NOT_COMPATIBLE;\n\n\t\tif ((firstMip + numMip) > baseTexture->mipLevels || (firstSlice + numSlice) > baseTexture->depth)\n\t\t{\n\t\t\t// view has more slices or mips than existing texture\n\t\t\treturn VIEW_BASE_TOO_SMALL;\n\n\t\t}\n\t\treturn VIEW_COMPATIBLE;\n\t}\n\telse\n\t{\n\t\tif (numMip > 1)\n\t\t\treturn VIEW_NOT_COMPATIBLE;\n\t\tif (baseTexture->Is3DTexture())\n\t\t\treturn VIEW_NOT_COMPATIBLE; // todo - add support for mapping views into 3D textures\n\n\t\t// if phys address or pitch differs then it might be pointing to a mip\n\t\tfor (sint32 m = 0; m < baseTexture->mipLevels; m++)\n\t\t{\n\t\t\tauto sliceMipInfo = baseTexture->sliceMipInfo + baseTexture->GetSliceMipArrayIndex(0, m);\n\t\t\t// check pitch\n\t\t\tif(sliceMipInfo->pitch != pitch)\n\t\t\t\tcontinue;\n\t\t\t// check all slices\n\t\t\tif(LatteAddrLib::TM_IsThickAndMacroTiled(baseTexture->tileMode))\n\t\t\t\tcontinue; // todo - check only every 4th slice?\n\t\t\tfor (sint32 s=0; s<baseTexture->GetMipDepth(m); s++)\n\t\t\t{\n\t\t\t\tsliceMipInfo = baseTexture->sliceMipInfo + baseTexture->GetSliceMipArrayIndex(s, m);\n\t\t\t\tif (sliceMipInfo->addrStart != physAddr || sliceMipInfo->pitch != pitch)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (baseTexture->isDepth != isDepth)\n\t\t\t\t\treturn VIEW_NOT_COMPATIBLE;\n\t\t\t\tif (baseTexture->GetMipWidth(m) != width || baseTexture->GetMipHeight(m) != height)\n\t\t\t\t\treturn VIEW_NOT_COMPATIBLE;\n\t\t\t\tif (!LatteTexture_IsTexelSizeCompatibleFormat(baseTexture->format, format) )\n\t\t\t\t\treturn VIEW_NOT_COMPATIBLE;\n\n\t\t\t\tif (!IsDimensionCompatibleForGX2View(baseTexture->dim, dimView))\n\t\t\t\t\treturn VIEW_NOT_COMPATIBLE;\n\t\t\t\tif (baseTexture->isDepth && baseTexture->format != format)\n\t\t\t\t{\n\t\t\t\t\t// depth view with different format\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"_createMapping(): Incompatible depth view format\");\n\t\t\t\t\treturn VIEW_NOT_COMPATIBLE;\n\t\t\t\t}\n\n\t\t\t\t// AMD has a bug on OpenGL where it ignores the internal format of texture views when they are bound as render targets,\n\t\t\t\t// as a result we cant use texture views when they have a different format\n\t\t\t\tif (baseTexture->format != format)\n\t\t\t\t\treturn VIEW_NOT_COMPATIBLE;\n\n\t\t\t\tif ((m + firstMip + numMip) > baseTexture->mipLevels || (s + firstSlice + numSlice) > baseTexture->depth)\n\t\t\t\t{\n\t\t\t\t\trelativeMipIndex = m;\n\t\t\t\t\trelativeSliceIndex = s;\n\t\t\t\t\treturn VIEW_BASE_TOO_SMALL;\n\t\t\t\t}\n\t\t\t\trelativeMipIndex = m;\n\t\t\t\trelativeSliceIndex = s;\n\t\t\t\treturn VIEW_COMPATIBLE;\n\t\t\t}\n\t\t}\n\t}\n\treturn VIEW_NOT_COMPATIBLE;\n}\n\n// deletes any related textures that have become redundant (aka textures that can also be represented entirely as a view into the new texture)\nvoid LatteTexture_DeleteAbsorbedSubtextures(LatteTexture* texture)\n{\n\tfor(size_t i=0; i<texture->list_compatibleRelations.size(); i++)\n\t{\n\t\tLatteTextureRelation* textureRelation = texture->list_compatibleRelations[i];\n\t\tLatteTexture* relatedTexture = (textureRelation->baseTexture!=texture)? textureRelation->baseTexture:textureRelation->subTexture;\n\n\t\tsint32 relativeMipIndex;\n\t\tsint32 relativeSliceIndex;\n\t\tif (LatteTexture_CanTextureBeRepresentedAsView(texture, relatedTexture->physAddress, relatedTexture->width, relatedTexture->height, relatedTexture->pitch, relatedTexture->dim, relatedTexture->format, relatedTexture->isDepth, 0, relatedTexture->mipLevels, 0, relatedTexture->depth, relativeMipIndex, relativeSliceIndex) == VIEW_COMPATIBLE)\n\t\t{\n\t\t\tLatteTexture_Delete(relatedTexture);\n\t\t\tLatteGPUState.repeatTextureInitialization = true;\n\t\t}\n\t}\n}\n\nvoid LatteTexture_RecreateTextureWithDifferentMipSliceCount(LatteTexture* texture, MPTR physMipAddr, sint32 newMipCount, sint32 newDepth)\n{\n\tLatte::E_DIM newDim = texture->dim;\n\tif (newDim == Latte::E_DIM::DIM_2D && newDepth > 1)\n\t\tnewDim = Latte::E_DIM::DIM_2D_ARRAY;\n\telse if (newDim == Latte::E_DIM::DIM_1D && newDepth > 1)\n\t\tnewDim = Latte::E_DIM::DIM_1D_ARRAY;\n\tLatteTextureView* view = LatteTexture_CreateTexture(newDim, texture->physAddress, physMipAddr, texture->format, texture->width, texture->height, newDepth, texture->pitch, newMipCount, texture->swizzle, texture->tileMode, texture->isDepth);\n\tcemu_assert(!(view->baseTexture->mipLevels <= 1 && physMipAddr == MPTR_NULL && newMipCount > 1));\n\t// copy data from old texture if its dynamically updated\n\tif (texture->isUpdatedOnGPU)\n\t{\n\t\tLatteTexture_copyData(texture, view->baseTexture, texture->mipLevels, texture->depth);\n\t\tview->baseTexture->isUpdatedOnGPU = true;\n\t}\n\t// remove old texture\n\tLatteTexture_Delete(texture);\n\t// gather texture relations for new texture\n\tLatteTexture_GatherTextureRelations(view->baseTexture);\n\tLatteTexture_UpdateTextureFromDynamicChanges(view->baseTexture);\n\t// todo - inherit 'isUpdatedOnGPU' flag for each mip/slice\n\n\t// delete any individual smaller slices/mips that have become redundant\n\tLatteTexture_DeleteAbsorbedSubtextures(view->baseTexture);\n}\n\n// create new texture representation\n// if allowCreateNewDataTexture is true, a new texture will be created if necessary. If it is false, only existing textures may be used, except if a data-compatible version of the requested texture already exists and it's not view compatible (todo - we should differentiate between Latte compatible views and renderer compatible)\n// the returned view will map to the provided mip and slice range within the created texture, this is to match the behavior of lookupSliceEx\nLatteTextureView* LatteTexture_CreateMapping(MPTR physAddr, MPTR physMipAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dimBase, Latte::E_DIM dimView, bool isDepth, bool allowCreateNewDataTexture)\n{\n\tif (format == Latte::E_GX2SURFFMT::INVALID_FORMAT)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"LatteTexture_CreateMapping(): Invalid format\");\n\t\treturn nullptr;\n\t}\n\t// note: When creating an existing texture, we only allow mip and slice expansion at the end\n\tcemu_assert_debug(depth);\n\n\tcemu_assert_debug(!(depth > 1 && dimBase == Latte::E_DIM::DIM_2D));\n\tcemu_assert_debug(!(numSlice > 1 && dimView == Latte::E_DIM::DIM_2D));\n\t// todo, depth and numSlice are redundant\n\n\tsint32 sliceCount = firstSlice + numSlice;\n\tboost::container::small_vector<LatteTexture*, 16> list_overlappingTextures;\n\tfor (sint32 sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++)\n\t{\n\t\tsint32 mipIndex = 0;\n\t\tuint32 calcSliceAddrStart;\n\t\tuint32 calcSliceSize;\n\t\tsint32 calcSubSliceIndex;\n\t\tLatteAddrLib::CalculateMipAndSliceAddr(physAddr, physMipAddr, format, width, height, depth, dimBase, tileMode, swizzle, 0, mipIndex, sliceIndex, &calcSliceAddrStart, &calcSliceSize, &calcSubSliceIndex);\n\t\tuint32 calcSliceAddrEnd = calcSliceAddrStart + calcSliceSize;\n\t\t// attempt to create view in already existing texture first (we may have to recreate the texture with new specifications)\n\t\tloopItrMemOccupancyBuckets(calcSliceAddrStart, calcSliceAddrEnd)\n\t\t{\n\t\t\tfor (auto& occupancy : list_texMemOccupancyBucket[bucketIndex])\n\t\t\t{\n\t\t\t\tif (calcSliceAddrEnd >= occupancy.addrStart && calcSliceAddrStart < occupancy.addrEnd)\n\t\t\t\t{\n\t\t\t\t\tif (calcSliceAddrStart == occupancy.addrStart)\n\t\t\t\t\t{\n\t\t\t\t\t\t// overlapping with zero x/y offset\n\t\t\t\t\t\tif (std::find(list_overlappingTextures.begin(), list_overlappingTextures.end(), occupancy.sliceMipInfo->texture) == list_overlappingTextures.end())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlist_overlappingTextures.push_back(occupancy.sliceMipInfo->texture);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// overlapping but not matching directly\n\t\t\t\t\t\t// todo - check if they match with a y offset\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// try to merge textures if possible\n\tfor (auto& tex : list_overlappingTextures)\n\t{\n\t\tsint32 relativeMipIndex;\n\t\tsint32 relativeSliceIndex;\n\t\tVIEWCOMPATIBILITY viewCompatibility = LatteTexture_CanTextureBeRepresentedAsView(tex, physAddr, width, height, pitch, dimView, format, isDepth, firstMip, numMip, firstSlice, numSlice, relativeMipIndex, relativeSliceIndex);\n\t\tif (viewCompatibility == VIEW_NOT_COMPATIBLE)\n\t\t{\n\t\t\tallowCreateNewDataTexture = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (viewCompatibility == VIEW_BASE_TOO_SMALL)\n\t\t{\n\t\t\tif (relativeMipIndex != 0 || relativeSliceIndex != 0)\n\t\t\t{\n\t\t\t\t// not yet supported\n\t\t\t\tallowCreateNewDataTexture = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// new mapping has more slices/mips than known texture -> expand texture\n\t\t\tsint32 newDepth = std::max(relativeSliceIndex + firstSlice + numSlice, std::max(depth, tex->depth));\n\t\t\tsint32 newMipCount = std::max(relativeMipIndex + firstMip + numMip, tex->mipLevels);\n\t\t\tuint32 newPhysMipAddr;\n\t\t\tif ((relativeMipIndex + firstMip + numMip) > 1)\n\t\t\t{\n\t\t\t\tnewPhysMipAddr = physMipAddr;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnewPhysMipAddr = tex->physMipAddress;\n\t\t\t}\n\t\t\tLatteTexture_RecreateTextureWithDifferentMipSliceCount(tex, newPhysMipAddr, newMipCount, newDepth);\n\t\t\treturn LatteTexture_CreateMapping(physAddr, physMipAddr, width, height, depth, pitch, tileMode, swizzle, firstMip, numMip, firstSlice, numSlice, format, dimBase, dimView, isDepth);\n\t\t}\n\t\telse if(viewCompatibility == VIEW_COMPATIBLE)\n\t\t{\n\t\t\tLatteTextureView* view = tex->GetOrCreateView(dimView, format, relativeMipIndex + firstMip, numMip, relativeSliceIndex + firstSlice, numSlice);\n\t\t\tif (relativeMipIndex != 0 || relativeSliceIndex != 0)\n\t\t\t{\n\t\t\t\t// for accesses to mips/slices using a physAddress offset we manually need to create a new view lookup\n\t\t\t\t// by default views only create a lookup for the base texture physAddress\n\t\t\t\tview->CreateLookupForSubTexture(relativeMipIndex, relativeSliceIndex);\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\t\tLatteTextureView* testView = LatteTextureViewLookupCache::lookup(physAddr, width, height, depth, pitch, firstMip, numMip, firstSlice, numSlice, format, dimView);\n\t\t\t\tcemu_assert(testView);\n#endif\n\t\t\t}\n\t\t\treturn view;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\t// create new texture\n\tif (allowCreateNewDataTexture == false)\n\t\treturn nullptr;\n\tLatteTextureView* view = LatteTexture_CreateTexture(dimBase, physAddr, physMipAddr, format, width, height, depth, pitch, firstMip + numMip, swizzle, tileMode, isDepth);\n\tLatteTexture* newTexture = view->baseTexture;\n\tLatteTexture_GatherTextureRelations(view->baseTexture);\n\tLatteTexture_UpdateTextureFromDynamicChanges(view->baseTexture);\n\t// delete any individual smaller slices/mips that have become redundant\n\tLatteTexture_DeleteAbsorbedSubtextures(view->baseTexture);\n\t// create view\n\tsint32 relativeMipIndex;\n\tsint32 relativeSliceIndex;\n\tVIEWCOMPATIBILITY viewCompatibility = LatteTexture_CanTextureBeRepresentedAsView(newTexture, physAddr, width, height, pitch, dimView, format, isDepth, firstMip, numMip, firstSlice, numSlice, relativeMipIndex, relativeSliceIndex);\n\tcemu_assert(viewCompatibility == VIEW_COMPATIBLE);\n\treturn view->baseTexture->GetOrCreateView(dimView, format, relativeMipIndex + firstMip, numMip, relativeSliceIndex + firstSlice, numSlice);\n}\n\nLatteTextureView* LatteTC_LookupTextureByData(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, sint32* searchIndex)\n{\n\tcemu_assert_debug(firstMip == 0);\n\tsint32 cSearchIndex = 0;\n\tloopItrMemOccupancyBuckets(physAddr, physAddr+1)\n\t{\n\t\tauto& bucket = list_texMemOccupancyBucket[bucketIndex];\n\t\tfor (sint32 i = 0; i < bucket.size(); i++)\n\t\t{\n\t\t\tif (bucket[i].addrStart == physAddr)\n\t\t\t{\n\t\t\t\tLatteTexture* tex = bucket[i].sliceMipInfo->texture;\n\t\t\t\tif (tex->physAddress == physAddr && tex->pitch == pitch)\n\t\t\t\t{\n\t\t\t\t\tif (firstSlice >= 0 && firstSlice < (tex->depth))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (cSearchIndex >= *searchIndex)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t(*searchIndex)++;\n\t\t\t\t\t\t\treturn tex->baseView;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcSearchIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nullptr;\n}\n\nvoid LatteTC_LookupTexturesByPhysAddr(MPTR physAddr, std::vector<LatteTexture*>& list_textures)\n{\n\tsint32 cSearchIndex = 0;\n\tloopItrMemOccupancyBuckets(physAddr, physAddr + 1)\n\t{\n\t\tfor (sint32 i = 0; i < list_texMemOccupancyBucket[bucketIndex].size(); i++)\n\t\t{\n\t\t\tif (list_texMemOccupancyBucket[bucketIndex][i].addrStart == physAddr)\n\t\t\t{\n\t\t\t\tLatteTexture* tex = list_texMemOccupancyBucket[bucketIndex][i].sliceMipInfo->texture;\n\t\t\t\tif (tex->physAddress == physAddr)\n\t\t\t\t{\n\t\t\t\t\tvectorAppendUnique(list_textures, tex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nLatteTextureView* LatteTC_GetTextureSliceViewOrTryCreate(MPTR srcImagePtr, MPTR srcMipPtr, Latte::E_GX2SURFFMT srcFormat, Latte::E_HWTILEMODE srcTileMode, uint32 srcWidth, uint32 srcHeight, uint32 srcDepth, uint32 srcPitch, uint32 srcSwizzle, uint32 srcSlice, uint32 srcMip, const bool requireExactResolution)\n{\n\tLatteTextureView* sourceView;\n\tif(requireExactResolution == false)\n\t\tsourceView = LatteTextureViewLookupCache::lookupSliceMinSize(srcImagePtr, srcWidth, srcHeight, srcPitch, srcMip, srcSlice, srcFormat);\n\telse\n\t\tsourceView = LatteTextureViewLookupCache::lookupSlice(srcImagePtr, srcWidth, srcHeight, srcPitch, srcMip, srcSlice, srcFormat);\n\tif (sourceView)\n\t\treturn sourceView;\n\treturn LatteTexture_CreateMapping(srcImagePtr, srcMipPtr, srcWidth, srcHeight, srcDepth, srcPitch, srcTileMode, srcSwizzle, srcMip, 1, srcSlice, 1, srcFormat, srcDepth > 1 ? Latte::E_DIM::DIM_2D_ARRAY : Latte::E_DIM::DIM_2D, Latte::E_DIM::DIM_2D, false, false);\n}\n\nvoid LatteTexture_UpdateDataToLatest(LatteTexture* texture)\n{\n\tif (LatteTC_HasTextureChanged(texture))\n\t\tLatteTexture_ReloadData(texture);\n\n\tif (texture->reloadFromDynamicTextures)\n\t{\n\t\tLatteTexture_UpdateCacheFromDynamicTextures(texture);\n\t\ttexture->reloadFromDynamicTextures = false;\n\t}\n}\n\nLatteTextureSliceMipInfo* LatteTexture::GetSliceMipArrayEntry(sint32 sliceIndex, sint32 mipIndex)\n{\n\treturn sliceMipInfo + GetSliceMipArrayIndex(sliceIndex, mipIndex);\n}\n\nstd::vector<LatteTexture*> sAllTextures; // entries can be nullptr\nstd::vector<size_t> sAllTextureFreeIndices;\n\nvoid _AddTextureToGlobalList(LatteTexture* tex)\n{\n\tif (sAllTextureFreeIndices.empty())\n\t{\n\t\ttex->globalListIndex = sAllTextures.size();\n\t\tsAllTextures.emplace_back(tex);\n\t\treturn;\n\t}\n\tsize_t index = sAllTextureFreeIndices.back();\n\tsAllTextureFreeIndices.pop_back();\n\tsAllTextures[index] = tex;\n\ttex->globalListIndex = index;\n}\n\nvoid _RemoveTextureFromGlobalList(LatteTexture* tex)\n{\n\tcemu_assert_debug(tex->globalListIndex >= 0 && tex->globalListIndex < sAllTextures.size());\n\tcemu_assert_debug(sAllTextures[tex->globalListIndex] == tex);\n\tif (tex->globalListIndex + 1 == sAllTextures.size())\n\t{\n\t\t// if the index is at the end, make the list smaller instead of freeing the index\n\t\tsAllTextures.pop_back();\n\t\treturn;\n\t}\n\tsAllTextures[tex->globalListIndex] = nullptr;\n\tsAllTextureFreeIndices.emplace_back(tex->globalListIndex);\n}\n\nstd::vector<LatteTexture*>& LatteTexture::GetAllTextures()\n{\n\treturn sAllTextures;\n}\n\nbool LatteTexture_GX2FormatHasStencil(bool isDepth, Latte::E_GX2SURFFMT format)\n{\n\tif (!isDepth)\n\t\treturn false;\n\treturn format == Latte::E_GX2SURFFMT::D24_S8_UNORM ||\n\t\t   format == Latte::E_GX2SURFFMT::D24_S8_FLOAT ||\n\t\t   format == Latte::E_GX2SURFFMT::D32_S8_FLOAT;\n}\n\nLatteTexture::LatteTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle,\n\tLatte::E_HWTILEMODE tileMode, bool isDepth)\n{\n\t_AddTextureToGlobalList(this);\n\tif (depth < 1)\n\t\tdepth = 1;\n\t// setup texture object\n\tthis->physAddress = physAddress;\n\tthis->dim = dim;\n\tthis->format = format;\n\tthis->width = width;\n\tthis->height = height;\n\tthis->depth = depth;\n\tthis->swizzle = swizzle;\n\tthis->pitch = pitch;\n\tthis->mipLevels = mipLevels;\n\tthis->tileMode = tileMode;\n\tthis->isDepth = isDepth;\n\tthis->hasStencil = LatteTexture_GX2FormatHasStencil(isDepth, format);\n\tthis->physMipAddress = physMipAddress;\n\tthis->lastUpdateEventCounter = LatteTexture_getNextUpdateEventCounter();\n\tthis->lastWriteEventCounter = LatteTexture_getNextUpdateEventCounter();\n\n\t// handle graphic pack overwrite rules\n\tfor (const auto& gp : GraphicPack2::GetActiveGraphicPacks())\n\t{\n\t\tfor (const auto& rule : gp->GetTextureRules())\n\t\t{\n\t\t\tif (!rule.filter_settings.format_whitelist.empty() && std::find(rule.filter_settings.format_whitelist.begin(), rule.filter_settings.format_whitelist.end(), (uint32)format) == rule.filter_settings.format_whitelist.end())\n\t\t\t\tcontinue;\n\n\t\t\tif (!rule.filter_settings.format_blacklist.empty() && std::find(rule.filter_settings.format_blacklist.begin(), rule.filter_settings.format_blacklist.end(), (uint32)format) != rule.filter_settings.format_blacklist.end())\n\t\t\t\tcontinue;\n\n\t\t\tif (!rule.filter_settings.tilemode_whitelist.empty() && std::find(rule.filter_settings.tilemode_whitelist.begin(), rule.filter_settings.tilemode_whitelist.end(), (int)tileMode) == rule.filter_settings.tilemode_whitelist.end())\n\t\t\t\tcontinue;\n\n\t\t\tif (!rule.filter_settings.tilemode_blacklist.empty() && std::find(rule.filter_settings.tilemode_blacklist.begin(), rule.filter_settings.tilemode_blacklist.end(), (int)tileMode) != rule.filter_settings.tilemode_blacklist.end())\n\t\t\t\tcontinue;\n\n\t\t\tif (rule.filter_settings.width != -1 && rule.filter_settings.width != width)\n\t\t\t\tcontinue;\n\t\t\tif (rule.filter_settings.height != -1 && rule.filter_settings.height != height)\n\t\t\t\tcontinue;\n\t\t\tif (rule.filter_settings.depth != -1 && rule.filter_settings.depth != depth)\n\t\t\t\tcontinue;\n\t\t\tif (rule.filter_settings.inMEM1 == GraphicPack2::TextureRule::FILTER_SETTINGS::MEM1_FILTER::OUTSIDE && mmuRange_MEM1.containsAddress(this->physAddress))\n\t\t\t\tcontinue;\n\t\t\tif (rule.filter_settings.inMEM1 == GraphicPack2::TextureRule::FILTER_SETTINGS::MEM1_FILTER::INSIDE && !mmuRange_MEM1.containsAddress(this->physAddress))\n\t\t\t\tcontinue;\n\n\t\t\tthis->overwriteInfo.width = width;\n\t\t\tthis->overwriteInfo.height = height;\n\t\t\tthis->overwriteInfo.depth = depth;\n\n\t\t\tif (rule.overwrite_settings.width != -1)\n\t\t\t{\n\t\t\t\tthis->overwriteInfo.hasResolutionOverwrite = true;\n\t\t\t\tthis->overwriteInfo.width = rule.overwrite_settings.width;\n\t\t\t}\n\t\t\tif (rule.overwrite_settings.height != -1)\n\t\t\t{\n\t\t\t\tthis->overwriteInfo.hasResolutionOverwrite = true;\n\t\t\t\tthis->overwriteInfo.height = rule.overwrite_settings.height;\n\t\t\t}\n\t\t\tif (rule.overwrite_settings.depth != -1)\n\t\t\t{\n\t\t\t\tthis->overwriteInfo.hasResolutionOverwrite = true;\n\t\t\t\tthis->overwriteInfo.depth = rule.overwrite_settings.depth;\n\t\t\t}\n\t\t\tif (rule.overwrite_settings.format != -1)\n\t\t\t{\n\t\t\t\tthis->overwriteInfo.hasFormatOverwrite = true;\n\t\t\t\tthis->overwriteInfo.format = rule.overwrite_settings.format;\n\t\t\t}\n\t\t\tif (rule.overwrite_settings.lod_bias != -1)\n\t\t\t{\n\t\t\t\tthis->overwriteInfo.hasLodBias = true;\n\t\t\t\tthis->overwriteInfo.lodBias = rule.overwrite_settings.lod_bias;\n\t\t\t}\n\t\t\tif (rule.overwrite_settings.relative_lod_bias != -1)\n\t\t\t{\n\t\t\t\tthis->overwriteInfo.hasRelativeLodBias = true;\n\t\t\t\tthis->overwriteInfo.relativeLodBias = rule.overwrite_settings.relative_lod_bias;\n\t\t\t}\n\t\t\tif (rule.overwrite_settings.anistropic_value != -1)\n\t\t\t{\n\t\t\t\tthis->overwriteInfo.anisotropicLevel = rule.overwrite_settings.anistropic_value;\n\t\t\t}\n\t\t}\n\t}\n\t// determine if this texture should ever be mirrored to CPU RAM\n\tif (this->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED)\n\t{\n\t\tthis->enableReadback = true;\n\t}\n\n\t// calculate number of potential mip levels (from effective size)\n\tsint32 effectiveWidth = width;\n\tsint32 effectiveHeight = height;\n\tsint32 effectiveDepth = depth;\n\tif (this->overwriteInfo.hasResolutionOverwrite)\n\t{\n\t\teffectiveWidth = this->overwriteInfo.width;\n\t\teffectiveHeight = this->overwriteInfo.height;\n\t\teffectiveDepth = this->overwriteInfo.depth;\n\t}\n\tthis->maxPossibleMipLevels = 1;\n\tif (dim != Latte::E_DIM::DIM_3D)\n\t{\n\t\tfor (sint32 i = 0; i < 20; i++)\n\t\t{\n\t\t\tif ((effectiveWidth >> i) <= 1 && (effectiveHeight >> i) <= 1)\n\t\t\t{\n\t\t\t\tthis->maxPossibleMipLevels = i + 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (sint32 i = 0; i < 20; i++)\n\t\t{\n\t\t\tif ((effectiveWidth >> i) <= 1 && (effectiveHeight >> i) <= 1 && (effectiveDepth >> i) <= 1)\n\t\t\t{\n\t\t\t\tthis->maxPossibleMipLevels = i + 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nLatteTexture::~LatteTexture()\n{\n\t_RemoveTextureFromGlobalList(this);\n\tcemu_assert_debug(baseView == nullptr);\n\tcemu_assert_debug(views.empty());\n};\n\n// sync texture data between overlapping textures\nvoid LatteTexture_UpdateCacheFromDynamicTextures(LatteTexture* textureDest)\n{\n\tLatteTexture_UpdateTextureFromDynamicChanges(textureDest);\n}\n\nvoid LatteTexture_MarkConnectedTexturesForReloadFromDynamicTextures(LatteTexture* texture)\n{\n\tfor (auto& it : texture->list_compatibleRelations)\n\t{\n\t\tif (texture == it->baseTexture)\n\t\t\tit->subTexture->reloadFromDynamicTextures = true;\n\t\telse\n\t\t\tit->baseTexture->reloadFromDynamicTextures = true;\n\t}\n}\n\nvoid LatteTexture_TrackTextureGPUWrite(LatteTexture* texture, uint32 slice, uint32 mip, uint64 eventCounter)\n{\n\tLatteTexture_MarkDynamicTextureAsChanged(texture->baseView, slice, mip, eventCounter);\n\tLatteTC_ResetTextureChangeTracker(texture);\n\ttexture->isUpdatedOnGPU = true;\n\ttexture->lastUnflushedRTDrawcallIndex = LatteGPUState.drawCallCounter;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTexture.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n\nstruct LatteSamplerState\n{\n\tuint8 clampS;\n\tuint8 clampT;\n\tuint8 clampR;\n\tuint32 filterMag; // openGL constant\n\tuint32 filterMin; // openGL constant\n\tuint8 maxAniso;\n\tuint8 maxMipLevels;\n\tuint8 depthCompareMode;\n\tuint8 depthCompareFunc;\n\tuint16 minLod;\n\tuint16 maxLod;\n\tsint16 lodBias;\n\tuint8 borderType;\n\tfloat borderColor[4];\n};\n\n#include \"Cafe/HW/Latte/Core/LatteTextureView.h\"\n\nclass LatteTexture\n{\npublic:\n\tLatteTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth);\n\tvirtual ~LatteTexture();\n\n\tvirtual void AllocateOnHost() = 0;\n\n\tLatteTextureView* GetOrCreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)\n\t{\n\t\tfor (auto& itr : views)\n\t\t{\n\t\t\tif (itr->firstMip == firstMip && itr->numMip == mipCount && itr->firstSlice == firstSlice && itr->numSlice == sliceCount &&\n\t\t\t\titr->dim == dim && itr->format == format)\n\t\t\t\treturn itr;\n\t\t}\n\t\treturn CreateView(dim, format, firstMip, mipCount, firstSlice, sliceCount);\n\t}\n\n\tLatteTextureView* GetOrCreateView(sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)\n\t{\n\t\treturn GetOrCreateView(this->dim, this->format, firstMip, mipCount, firstSlice, sliceCount);\n\t}\n\n\tbool IsCompressedFormat() const\n\t{\n\t\treturn Latte::IsCompressedFormat(format);\n\t}\n\n\tuint32 GetBPP() const\n\t{\n\t\treturn Latte::GetFormatBits(format);\n\t}\n\n\tbool Is3DTexture() const { return dim == Latte::E_DIM::DIM_3D; };\n\n\tvoid GetSize(sint32& width, sint32& height, sint32 mipLevel) const\n\t{\n\t\twidth = std::max(1, this->width >> mipLevel);\n\t\theight = std::max(1, this->height >> mipLevel);\n\t}\n\n\t// similar to GetSize, but returns the real size of the texture taking into account any resolution overwrite by gfx pack rules\n\tvoid GetEffectiveSize(sint32& effectiveWidth, sint32& effectiveHeight, sint32 mipLevel) const\n\t{\n\t\tif( overwriteInfo.hasResolutionOverwrite )\n\t\t{\n\t\t\teffectiveWidth = overwriteInfo.width;\n\t\t\teffectiveHeight = overwriteInfo.height;\n\t\t}\n\t\telse\n\t\t{\n\t\t\teffectiveWidth = this->width;\n\t\t\teffectiveHeight = this->height;\n\t\t}\n\t\teffectiveWidth = std::max(1, effectiveWidth >> mipLevel);\n\t\teffectiveHeight = std::max(1, effectiveHeight >> mipLevel);\n\t}\n\n\tsint32 GetMipDepth(sint32 mipIndex)\n\t{\n\t\tcemu_assert_debug(mipIndex >= 0 && mipIndex < this->mipLevels);\n\t\tif (Is3DTexture())\n\t\t\treturn std::max(depth >> mipIndex, 1);\n\t\treturn depth;\n\t}\n\n\tsint32 GetMipWidth(sint32 mipIndex)\n\t{\n\t\tcemu_assert_debug(mipIndex >= 0 && mipIndex < this->mipLevels);\n\t\treturn std::max(width >> mipIndex, 1);\n\t}\n\n\tsint32 GetMipHeight(sint32 mipIndex)\n\t{\n\t\tcemu_assert_debug(mipIndex >= 0 && mipIndex < this->mipLevels);\n\t\treturn std::max(height >> mipIndex, 1);\n\t}\n\n\t// return the size necessary for a 1D array to store one entry per slice/mip combo (using getSliceMipArrayIndex)\n\tsint32 GetSliceMipArraySize()\n\t{\n\t\tcemu_assert_debug(this->depth > 0);\n\t\tcemu_assert_debug(this->mipLevels > 0);\n\t\treturn this->depth * this->mipLevels;\n\t}\n\n\t// calculate index within slice/mip array\n\tsint32 GetSliceMipArrayIndex(sint32 sliceIndex, sint32 mipIndex)\n\t{\n\t\tcemu_assert_debug(sliceIndex < depth);\n\t\tcemu_assert_debug(mipIndex < mipLevels);\n\t\t// to keep the computation fast, we ignore that 3D textures have decreasing slice count per mip and leave some indices empty\n\t\treturn this->depth * mipIndex + sliceIndex;\n\t}\n\n\tstruct LatteTextureSliceMipInfo* GetSliceMipArrayEntry(sint32 sliceIndex, sint32 mipIndex);\n\tstatic std::vector<LatteTexture*>& GetAllTextures(); // note: can contain nullptr entries\n\nprotected:\n\tvirtual LatteTextureView* CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) = 0;\n\npublic:\n\n\t// Latte texture info\n\tMPTR physAddress;\n\tMPTR physMipAddress;\n\tLatte::E_DIM dim;\n\tLatte::E_GX2SURFFMT format;\n\tLatte::E_HWTILEMODE tileMode;\n\tsint32 width;\n\tsint32 height;\n\tsint32 depth;\n\tsint32 pitch;\n\tsint32 mipLevels; // number of used mip levels (must be at least 1)\n\tsint32 maxPossibleMipLevels{}; // number of mips that can potentially be used (uses resolution from texture rules)\n\tuint32 swizzle;\n\tuint32 lastRenderTargetSwizzle{}; // set to rt swizzle bits whenever the texture is being rendered to\n\t// data info\n\tbool isDataDefined{};\n\tbool isDepth;\n\tbool hasStencil{}; // for depth textures\n\t// info per mip/slice\n\tstruct LatteTextureSliceMipInfo* sliceMipInfo{};\n\t// physical offsets for start and end of data (calculated on texture load)\n\tMPTR texDataPtrLow{};\n\tMPTR texDataPtrHigh{};\n\tuint32 texDataHash2{};\n\t// state\n\tbool isUpdatedOnGPU{ false }; // set if any GPU-side operation modified this texture and strict one-way RAM->VRAM memory mirroring no longer applies\n\tbool enableReadback{ false }; // if true, texture will be mirrored back to CPU RAM under specific circumstances\n\t// invalidation\n\tbool forceInvalidate{};\n\t// cache control\n\tbool reloadFromDynamicTextures{};\n\t// last update (dynamic)\n\tuint64 lastWriteEventCounter;\n\tuint64 lastUpdateEventCounter;\n\tuint32 lastUpdateFrameCounter{};\n\tuint32 reloadCount{};\n\t// last update (from RAM data)\n\tuint32 lastDataUpdateFrameCounter{};\n\t// optimization\n\tbool useLightHash{};\n\t// overwrite info\n\tstruct\n\t{\n\t\t// resolution\n\t\tbool hasResolutionOverwrite;\n\t\tsint32 width;\n\t\tsint32 height;\n\t\tsint32 depth;\n\t\t// format\n\t\tbool hasFormatOverwrite;\n\t\tsint32 format;\n\t\t// lod bias\n\t\tsint16 lodBias; // in 1/64th steps\n\t\tbool hasLodBias;\n\t\t// relative lod bias\n\t\tsint16 relativeLodBias; // in 1/64th steps\n\t\tbool hasRelativeLodBias;\n\t\t// anisotropic\n\t\tsint8 anisotropicLevel{ -1 }; // 1<<n, 0 is disabled\n\t}overwriteInfo{};\n\t// for detecting multiple references during the same drawcall\n\tuint32 lockTextureUpdateId{}; // set to current texture update id whenever texture is bound and used\n\tuint32 lockCount{};\n\t// usage\n\tuint32 lastAccessTick{};\n\tuint32 lastAccessFrameCount{};\n\t// detection of render feedback loops (see OpenGL 4.5 spec, 9.3)\n\tuint32 lastUnflushedRTDrawcallIndex{};\n\t// views\n\tLatteTextureView* baseView{};\n\tstd::vector<LatteTextureView*> views; // list of all views created for this texture, including baseView\n\t// texture relations (overlapping memory)\n\tstd::vector<struct LatteTextureRelation*> list_compatibleRelations; // list of other data-compatible textures that share the same memory ranges\n\t// index in global texture list\n\tsize_t globalListIndex;\n};\n\nstruct LatteTextureDefinition // todo - actually use this in LatteTexture class\n{\n\tMPTR physAddress;\n\tMPTR physMipAddress;\n\tLatte::E_DIM dim;\n\tLatte::E_GX2SURFFMT format;\n\tuint32 width;\n\tuint32 height;\n\tuint32 depth;\n\tuint32 pitch;\n\tuint32 mipLevels;\n\tuint32 swizzle;\n\tLatte::E_HWTILEMODE tileMode;\n\tbool isDepth;\n\n\tLatteTextureDefinition() = default;\n\tLatteTextureDefinition(const LatteTexture* tex)\n\t{\n\t\tphysAddress = tex->physAddress;\n\t\tphysMipAddress = tex->physMipAddress;\n\t\tdim = tex->dim;\n\t\tformat = tex->format;\n\t\twidth = tex->width;\n\t\theight = tex->height;\n\t\tdepth = tex->depth;\n\t\tpitch = tex->pitch;\n\t\tmipLevels = tex->mipLevels;\n\t\tswizzle = tex->swizzle;\n\t\ttileMode = tex->tileMode;\n\t\tisDepth = tex->isDepth;\n\t}\n};\n\nclass LatteTextureView;\n\nstruct LatteTextureSliceMipDataOverlap_t\n{\n\tLatteTexture* destTexture;\n\tstruct LatteTextureSliceMipInfo* destMipSliceInfo;\n};\n\nstruct LatteTextureSliceMipInfo\n{\n\tuint32 addrStart; // same as physAddr if this mip were it's own texture\n\tuint32 addrEnd;\n\tuint32 subIndex; // for thick tiles, multiple (4) slices can be interleaved into the same data range. This stores the index\n\tLatteTexture* texture;\n\tsint32 sliceIndex;\n\tsint32 mipIndex;\n\t// change tracking\n\tuint32 dataChecksum;\n\tuint64 lastDynamicUpdate;\n\t// format info\n\tLatte::E_HWTILEMODE tileMode;\n\tsint32 pitch;\n\t// data overlap tracking\n\tuint32 estDataAddrStart;\n\tuint32 estDataAddrEnd;\n\tstd::vector<LatteTextureSliceMipDataOverlap_t> list_dataOverlap;\n};\n\nstruct LatteTextureRelation\n{\n\tLatteTexture* baseTexture;\n\tLatteTexture* subTexture; // texture which is contained within baseTexture\n\tsint32 baseSliceIndex;\n\tsint32 baseMipIndex;\n\tsint32 sliceCount;\n\tsint32 mipCount;\n\t//sint32 xOffset;\n\tsint32 yOffset;\n};\n\n// used if external modules want to retrieve texture cache information\nstruct LatteTextureViewInformation\n{\n\tMPTR physAddress;\n\tMPTR physMipAddress;\n\tsint32 width;\n\tsint32 height;\n\tsint32 pitch;\n\tsint32 firstMip;\n\tsint32 numMip;\n\tsint32 firstSlice;\n\tsint32 numSlice;\n\tLatte::E_GX2SURFFMT format;\n\tLatte::E_DIM dim;\n};\n\nstruct LatteTextureInformation \n{\n\tMPTR physAddress;\n\tMPTR physMipAddress;\n\tsint32 width;\n\tsint32 height;\n\tsint32 depth;\n\tsint32 pitch;\n\tsint32 mipLevels;\n\tLatte::E_GX2SURFFMT format;\n\tbool isDepth;\n\tLatte::E_DIM dim;\n\tLatte::E_HWTILEMODE tileMode;\n\t// access\n\tuint32 lastAccessTick;\n\tuint32 lastAccessFrameCount;\n\tbool isUpdatedOnGPU;\n\t// misc\n\tuint32 alternativeViewCount;\n\t// overwrite info\n\tstruct\n\t{\n\t\t// resolution\n\t\tbool hasResolutionOverwrite;\n\t\tsint32 width;\n\t\tsint32 height;\n\t\tsint32 depth;\n\t}overwriteInfo{};\n\n\tstd::vector<LatteTextureViewInformation> views;\n};\n\nvoid LatteTexture_init();\nvoid LatteTexture_updateTextures();\n\nstd::vector<LatteTextureInformation> LatteTexture_QueryCacheInfo();\n\nfloat* LatteTexture_getEffectiveTextureScale(LatteConst::ShaderType shaderType, sint32 texUnit);\n\nLatteTextureView* LatteTexture_CreateTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth);\nvoid LatteTexture_Delete(LatteTexture* texture);\n\nvoid LatteTextureLoader_writeReadbackTextureToMemory(LatteTextureDefinition* textureData, uint32 sliceIndex, uint32 mipIndex, uint8* linearPixelData);\n\nsint32 LatteTexture_getEffectiveWidth(LatteTexture* texture);\nbool LatteTexture_doesEffectiveRescaleRatioMatch(LatteTexture* texture1, sint32 mipLevel1, LatteTexture* texture2, sint32 mipLevel2);\nvoid LatteTexture_scaleToEffectiveSize(LatteTexture* texture, sint32* x, sint32* y, sint32 mipLevel);\nuint64 LatteTexture_getNextUpdateEventCounter();\n\nvoid LatteTexture_UpdateCacheFromDynamicTextures(LatteTexture* texture);\nvoid LatteTexture_MarkConnectedTexturesForReloadFromDynamicTextures(LatteTexture* texture);\nvoid LatteTexture_TrackTextureGPUWrite(LatteTexture* texture, uint32 slice, uint32 mip, uint64 eventCounter);\n\nvoid LatteTexture_InitSliceAndMipInfo(LatteTexture* texture);\nvoid LatteTexture_RegisterTextureMemoryOccupancy(LatteTexture* texture);\nvoid LatteTexture_UnregisterTextureMemoryOccupancy(LatteTexture* texture);\n\nvoid LatteTexture_DeleteTextureRelations(LatteTexture* texture);\nvoid LatteTexture_DeleteDataOverlapTracking(LatteTexture* texture);\n\nLatteTextureView* LatteTexture_CreateMapping(MPTR physAddr, MPTR physMipAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dimBase, Latte::E_DIM dimView, bool isDepth, bool allowCreateNewDataTexture = true);\n\nLatteTextureView* LatteTC_LookupTextureByData(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, sint32* searchIndex);\nvoid LatteTC_LookupTexturesByPhysAddr(MPTR physAddr, std::vector<LatteTexture*>& list_textures);\n\nLatteTextureView* LatteTC_GetTextureSliceViewOrTryCreate(MPTR srcImagePtr, MPTR srcMipPtr, Latte::E_GX2SURFFMT srcFormat, Latte::E_HWTILEMODE srcTileMode, uint32 srcWidth, uint32 srcHeight, uint32 srcDepth, uint32 srcPitch, uint32 srcSwizzle, uint32 srcSlice, uint32 srcMip, const bool requireExactResolution = false);\n\nvoid LatteTexture_MarkDynamicTextureAsChanged(LatteTextureView* textureView, sint32 sliceIndex, sint32 mipIndex, uint64 eventCounter);\nvoid LatteTexture_UpdateTextureFromDynamicChanges(LatteTexture* texture);\n\nvoid LatteTexture_UpdateDataToLatest(LatteTexture* texture);"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTextureCache.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Common/cpu_features.h\"\n\nstd::unordered_set<LatteTexture*> g_allTextures;\n\nvoid LatteTC_Init()\n{\n\tcemu_assert_debug(g_allTextures.empty());\n}\n\nvoid LatteTC_RegisterTexture(LatteTexture* tex)\n{\n\tg_allTextures.emplace(tex);\n}\n\nvoid LatteTC_UnregisterTexture(LatteTexture* tex)\n{\n\tg_allTextures.erase(tex);\n}\n\n// sample few uint64s uniformly over memory range\nuint32 _quickStochasticHash(void* texData, uint32 memRange)\n{\n\tuint64* texDataU64 = (uint64*)texData;\n\n\tuint64 hashVal = 0;\n\tmemRange /= sizeof(uint64);\n\n\tuint32 memStep = memRange / 37; // use prime here to avoid memStep aligning nicely with pitch of texture, leading to sampling only along the border of a texture\n\tfor (sint32 i = 0; i < 37; i++)\n\t{\n\t\thashVal += *texDataU64;\n\t\thashVal = (hashVal << 3) | (hashVal >> 61);\n\t\ttexDataU64 += memStep;\n\t}\n\treturn (uint32)hashVal ^ (uint32)(hashVal >> 32);\n}\n\nuint32 LatteTexture_CalculateTextureDataHash(LatteTexture* hostTexture)\n{\n\tif( hostTexture->texDataPtrHigh == hostTexture->texDataPtrLow )\n\t{\n\t\treturn 0;\n\t}\n\tif (hostTexture->format == Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT)\n\t{\n\t\t// this is an exotic format that usually isn't generated or updated CPU-side\n\t\t// therefore as an optimization we can risk to only check a minimal amount of bytes at the beginning of the texture data\n\t\t// updates which change the entire texture should still be detected this way\n\t\t// this also helps with a bug in BotW which seems to fill the empty areas of the textures with other data which causes unnecessary invalidations and texture reloads\n\n\t\t// Wonderful 101 generates this format in a 8x8x8 3D texture using tiling aperture\n\t\tif (hostTexture->tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THICK && hostTexture->depth == 8 && hostTexture->width == 8 && hostTexture->height == 8)\n\t\t{\n\t\t\t// special case for Wonderful 101\n\t\t\tuint32* texDataU32 = (uint32*)memory_getPointerFromPhysicalOffset(hostTexture->texDataPtrLow);\n\t\t\treturn texDataU32[0] ^ texDataU32[0x100/4] ^ texDataU32[0x200/4] ^ texDataU32[0x300/4]; // check the first thick slice (each slice has 0x400 bytes, with 0x100 bytes between layers)\n\t\t}\n\t\tuint32* texDataU32 = (uint32*)memory_getPointerFromPhysicalOffset(hostTexture->texDataPtrLow);\n\t\treturn texDataU32[0] ^ texDataU32[1] ^ texDataU32[2] ^ texDataU32[3];\n\t}\n\n\tuint32 memRange = hostTexture->texDataPtrHigh - hostTexture->texDataPtrLow;\n\tuint32* texDataU32 = (uint32*)memory_getPointerFromPhysicalOffset(hostTexture->texDataPtrLow);\n\tuint32 hashVal = 0;\n\tuint32 pixelCount = hostTexture->width*hostTexture->height;\n\n\tbool isCompressedFormat = hostTexture->IsCompressedFormat();\n\tif (isCompressedFormat || hostTexture->useLightHash)\n\t{\n\t\t// check only 32 samples of the texture\n\t\tif (memRange < 256)\n\t\t{\n\t\t\tmemRange /= sizeof(uint32);\n\t\t\twhile (memRange--)\n\t\t\t{\n\t\t\t\thashVal += *texDataU32;\n\t\t\t\thashVal = (hashVal << 3) | (hashVal >> 29);\n\t\t\t\ttexDataU32++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\thashVal = _quickStochasticHash(texDataU32, memRange);\n\t\t}\n\t\treturn hashVal;\n\t}\n\n\n\tif( pixelCount <= (700*700) )\n\t{\n\t\t// small texture size\n\t\tbool isCompressedFormat = hostTexture->IsCompressedFormat();\n\t\tif( isCompressedFormat == false || memRange < 0x200 )\n\t\t{\n\t\t\tmemRange /= (4*sizeof(uint32));\n\t\t\twhile( memRange-- )\n\t\t\t{\n\t\t\t\thashVal += *texDataU32;\n\t\t\t\thashVal = (hashVal<<3)|(hashVal>>29);\n\t\t\t\ttexDataU32 += 4;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmemRange /= (32*sizeof(uint32));\n\t\t\twhile( memRange-- )\n\t\t\t{\n\t\t\t\thashVal += *texDataU32;\n\t\t\t\thashVal = (hashVal<<3)|(hashVal>>29);\n\t\t\t\ttexDataU32 += 32;\n\t\t\t}\n\t\t}\n\t}\n\telse if( pixelCount <= (1200*1200) )\n\t{\n\t\t// medium texture size\n\t\tbool isCompressedFormat = hostTexture->IsCompressedFormat();\n\t\tif( isCompressedFormat == false )\n\t\t{\n\t\t\tmemRange /= (12*sizeof(uint32));\n\t\t\twhile( memRange-- )\n\t\t\t{\n\t\t\t\thashVal += *texDataU32;\n\t\t\t\thashVal = (hashVal<<3)|(hashVal>>29);\n\t\t\t\ttexDataU32 += 12;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmemRange /= (96*sizeof(uint32));\n\t\t\twhile( memRange-- )\n\t\t\t{\n\t\t\t\thashVal += *texDataU32;\n\t\t\t\thashVal = (hashVal<<3)|(hashVal>>29);\n\t\t\t\ttexDataU32 += 96;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// huge texture size\n\t\tbool isCompressedFormat = hostTexture->IsCompressedFormat();\n\t\tif( isCompressedFormat == false )\n\t\t{\n#if BOOST_OS_WINDOWS\n\t\t\tif (g_CPUFeatures.x86.avx2)\n\t\t\t{\n\t\t\t\t__m256i h256 = { 0 };\n\t\t\t\t__m256i* readPtr = (__m256i*)texDataU32;\n\t\t\t\tmemRange /= (288);\n\t\t\t\twhile (memRange--)\n\t\t\t\t{\n\t\t\t\t\t__m256i temp = _mm256_load_si256(readPtr);\n\t\t\t\t\treadPtr += (288 / 32);\n\t\t\t\t\th256 = _mm256_xor_si256(h256, temp);\n\t\t\t\t}\n#ifdef __clang__\n\t\t\t\thashVal = h256[0] + h256[1] + h256[2] + h256[3] + h256[4] + h256[5] + h256[6] + h256[7];\n#else\n\t\t\t\thashVal = h256.m256i_u32[0] + h256.m256i_u32[1] + h256.m256i_u32[2] + h256.m256i_u32[3] + h256.m256i_u32[4] + h256.m256i_u32[5] + h256.m256i_u32[6] + h256.m256i_u32[7];\n#endif\n\t\t\t}\n#else\n\t\t\tif( false ) {}\n#endif\n\t\t\telse\n\t\t\t{\n\t\t\t\tmemRange /= (32 * sizeof(uint64));\n\t\t\t\tuint64 h64 = 0;\n\t\t\t\tuint64* texDataU64 = (uint64*)texDataU32;\n\t\t\t\twhile (memRange--)\n\t\t\t\t{\n\t\t\t\t\th64 += *texDataU64;\n\t\t\t\t\th64 = (h64 << 3) | (h64 >> 61);\n\t\t\t\t\ttexDataU64 += 32;\n\t\t\t\t}\n\t\t\t\thashVal = (h64 & 0xFFFFFFFF) + (h64 >> 32);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmemRange /= (512*sizeof(uint32));\n\t\t\twhile( memRange-- )\n\t\t\t{\n\t\t\t\thashVal += *texDataU32;\n\t\t\t\thashVal = (hashVal<<3)|(hashVal>>29);\n\t\t\t\ttexDataU32 += 512;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn hashVal;\n}\n\nuint64 _botwLargeTexHax = 0;\n\nbool LatteTC_HasTextureChanged(LatteTexture* hostTexture, bool force)\n{\n\tif (hostTexture->forceInvalidate)\n\t{\n\t\tforce = true;\n\t\tdebug_printf(\"Force invalidate 0x%08x\\n\", hostTexture->physAddress);\n\t\thostTexture->forceInvalidate = false;\n\t}\n\t// if texture is written by GPU operations we switch to a faster hash implementation\n\tif (hostTexture->isUpdatedOnGPU && hostTexture->useLightHash == false)\n\t{\n\t\thostTexture->useLightHash = true;\n\t\t// update hash\n\t\thostTexture->texDataHash2 = LatteTexture_CalculateTextureDataHash(hostTexture);\n\t}\n\t// only check each texture for updates once a frame\n\t// todo: Instead of relying on frames, it would be better to recheck only after any GPU wait operation occurred.\n\tif( hostTexture->lastDataUpdateFrameCounter == LatteGPUState.frameCounter && force == false)\n\t\treturn false;\n\thostTexture->lastDataUpdateFrameCounter = LatteGPUState.frameCounter;\n\t// we assume that certain texture properties indicate that the texture will never be written by the CPU\n\tif (hostTexture->width == 1280 && hostTexture->format != Latte::E_GX2SURFFMT::R8_UNORM && force == false)\n\t{\n\t\t// todo - remove this or find a better way to handle excluded texture invalidation checks (maybe via game profile?)\n\t\treturn false;\n\t}\n\t// workaround for corrupted terrain texture in BotW after video playback\n\t// probably would be fixed if we added support for invalidating individual slices/mips of a texture\n\tuint32 texDataHash = LatteTexture_CalculateTextureDataHash(hostTexture);\n\tif( texDataHash != hostTexture->texDataHash2 )\n\t{\n\t\thostTexture->texDataHash2 = texDataHash;\n\t\tif (hostTexture->depth == 83 && hostTexture->width == 1024 && hostTexture->height == 1024)\n\t\t{\n\t\t\t_botwLargeTexHax = LatteGPUState.frameCounter;\n\t\t}\n\t\treturn true;\n\t}\n\tif (_botwLargeTexHax != 0 && hostTexture->depth == 83 && hostTexture->width == 1024 && hostTexture->height == 1024 && _botwLargeTexHax != LatteGPUState.frameCounter)\n\t{\n\t\t_botwLargeTexHax = 0;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nvoid LatteTC_ResetTextureChangeTracker(LatteTexture* hostTexture, bool force)\n{\n\tif( hostTexture->lastDataUpdateFrameCounter == LatteGPUState.frameCounter && force == false)\n\t\treturn;\n\thostTexture->lastDataUpdateFrameCounter = LatteGPUState.frameCounter;\n\tLatteTC_HasTextureChanged(hostTexture, true);\n}\n\n/*\n * This function should be called whenever the texture is still used in some form (any kind of access counts)\n * The purpose of this function is to prevent garbage collection of textures that are still actively used\n */\nvoid LatteTC_MarkTextureStillInUse(LatteTexture* texture)\n{\n\ttexture->lastAccessTick = LatteGPUState.currentDrawCallTick;\n\ttexture->lastAccessFrameCount = LatteGPUState.frameCounter;\n}\n\n// check if a texture has been overwritten by another texture using GPU-writes\nbool LatteTC_IsTextureDataOverwritten(LatteTexture* texture)\n{\n\t// check overlaps\n\tsint32 mipLevels = texture->mipLevels;\n\tsint32 sliceCount = texture->depth;\n\tmipLevels = std::min(mipLevels, 3); // only check first 3 mip levels\n\tfor (sint32 mipIndex = 0; mipIndex < mipLevels; mipIndex++)\n\t{\n\t\tsint32 mipSliceCount;\n\t\tif (texture->Is3DTexture())\n\t\t\tmipSliceCount = std::max(1, sliceCount >> mipIndex);\n\t\telse\n\t\t\tmipSliceCount = sliceCount;\n\t\tfor (sint32 sliceIndex = 0; sliceIndex < mipSliceCount; sliceIndex++)\n\t\t{\n\t\t\tLatteTextureSliceMipInfo* sliceMipInfo = texture->sliceMipInfo + texture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tbool isSliceMipOutdated = false;\n\t\t\tfor (auto& overlapData : sliceMipInfo->list_dataOverlap)\n\t\t\t{\n\t\t\t\tif (sliceMipInfo->lastDynamicUpdate < overlapData.destMipSliceInfo->lastDynamicUpdate)\n\t\t\t\t{\n\t\t\t\t\tisSliceMipOutdated = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (isSliceMipOutdated == false)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nvoid LatteTexture_Delete(LatteTexture* texture)\n{\n\tLatteTC_UnregisterTexture(texture);\n\tLatteMRT::NotifyTextureDeletion(texture);\n\tLatteTextureReadback_NotifyTextureDeletion(texture);\n\tLatteTexture_DeleteTextureRelations(texture);\n\t// delete views\n\twhile (!texture->views.empty())\n\t\tdelete texture->views[0];\n\tcemu_assert_debug(texture->views.empty());\n\tcemu_assert_debug(texture->baseView == nullptr);\n\t// free data overlap tracking\n\tLatteTexture_DeleteDataOverlapTracking(texture);\n\t// remove from lists\n\tLatteTexture_UnregisterTextureMemoryOccupancy(texture);\n\t// free memory\n\tif (texture->sliceMipInfo)\n\t{\n\t\tdelete[] texture->sliceMipInfo;\n\t\ttexture->sliceMipInfo = nullptr;\n\t}\n\tdelete texture;\n}\n\n/*\n * Checks if the texture can be dropped from the cache and if yes, delete it\n * Returns true if the texture was deleted\n */\nbool LatteTC_CleanupCheckTexture(LatteTexture* texture, uint32 currentTick)\n{\n\tuint32 currentFrameCount = LatteGPUState.frameCounter;\n\tuint32 ticksSinceLastAccess = currentTick - texture->lastAccessTick;\n\tuint32 framesSinceLastAccess = currentFrameCount - texture->lastAccessFrameCount;\n\tif( !texture->isUpdatedOnGPU )\n\t{\n\t\t// RAM-only textures are safe to be deleted since we can always restore them from RAM\n\t\tif( ticksSinceLastAccess >= (120*1000) && framesSinceLastAccess >= 2000 )\n\t\t{\n\t\t\tLatteTexture_Delete(texture);\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tif ((LatteGPUState.currentDrawCallTick - texture->lastAccessTick) >= 100 && \n\t\tLatteTC_IsTextureDataOverwritten(texture))\n\t{\n\t\tLatteTexture_Delete(texture);\n\t\treturn true;\n\t}\n\t// if unused for more than 5 seconds, start deleting views since they are cheap to recreate\n\tif (ticksSinceLastAccess >= 5 * 1000 && framesSinceLastAccess >= 30)\n\t{\n\t\tfor (sint32 i = 0; i < 3; i++)\n\t\t{\n\t\t\tif (texture->views.size() <= 1)\n\t\t\t\tbreak;\n\t\t\tLatteTextureView* view = texture->views[0];\n\t\t\tif (view == texture->baseView)\n\t\t\t\tview = texture->views[1];\n\t\t\tdelete view;\n\t\t}\n\t}\n\treturn false;\n}\n\nvoid LatteTexture_RefreshInfoCache();\n\n/*\n * Scans for unused textures and deletes them\n * Called at the end of every frame\n */\nvoid LatteTC_CleanupUnusedTextures()\n{\n\tstatic size_t currentScanIndex = 0;\n\tuint32 currentTick = GetTickCount();\n\tsint32 maxDelete = 10;\n\tstd::vector<LatteTexture*>& allTextures = LatteTexture::GetAllTextures();\n\tif (!allTextures.empty())\n\t{\n\t\tfor (sint32 c = 0; c < 25; c++)\n\t\t{\n\t\t\tif (currentScanIndex >= allTextures.size())\n\t\t\t\tcurrentScanIndex = 0;\n\t\t\tLatteTexture* texItr = allTextures[currentScanIndex];\n\t\t\tcurrentScanIndex++;\n\t\t\tif (!texItr)\n\t\t\t\tcontinue;\n\t\t\tif (LatteTC_CleanupCheckTexture(texItr, currentTick))\n\t\t\t{\n\t\t\t\tmaxDelete--;\n\t\t\t\tif (maxDelete <= 0)\n\t\t\t\t\tbreak; // deleting can be an expensive operation, dont delete too many at once to avoid micro stutter\n\t\t\t\tif (allTextures.empty())\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tLatteTexture_RefreshInfoCache(); // find a better place to call this from?\n}\n\nstd::vector<LatteTexture*> LatteTC_GetDeleteableTextures()\n{\n\tstd::vector<LatteTexture*> texList;\n\tuint32 currentFrameCount = LatteGPUState.frameCounter;\n\n\tfor (auto& itr : g_allTextures)\n\t{\n\t\tif(itr->lastAccessFrameCount == 0)\n\t\t\tcontinue; // not initialized\n\t\tuint32 framesSinceLastAccess = currentFrameCount - itr->lastAccessFrameCount;\n\t\tif(framesSinceLastAccess < 3)\n\t\t\tcontinue;\n\t\tif (itr->isUpdatedOnGPU)\n\t\t{\n\t\t\tif (LatteTC_IsTextureDataOverwritten(itr))\n\t\t\t\ttexList.emplace_back(itr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttexList.emplace_back(itr);\n\t\t}\n\t}\n\n\treturn texList;\n}\n\nvoid LatteTC_UnloadAllTextures()\n{\n\tstd::vector<LatteTexture*> allTexturesCopy = LatteTexture::GetAllTextures();\n\tfor (auto& itr : allTexturesCopy)\n\t{\n\t\tif(itr)\n\t\t\tLatteTexture_Delete(itr);\n\t}\n\tLatteRenderTarget_unloadAll();\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTextureLegacy.cpp",
    "content": "#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h\"\n\nstruct TexScaleXY\n{\n\tfloat xy[2];\n};\n\nstruct\n{\n\tTexScaleXY perUnit[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE]; // stores actualResolution/effectiveResolution ratio for each texture\n}LatteTextureScale[static_cast<size_t>(LatteConst::ShaderType::TotalCount)] = { };\n\nfloat* LatteTexture_getEffectiveTextureScale(LatteConst::ShaderType shaderType, sint32 texUnit)\n{\n\tcemu_assert_debug(texUnit >= 0 && texUnit < Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE);\n\treturn LatteTextureScale[static_cast<size_t>(shaderType)].perUnit[texUnit].xy;\n}\n\nvoid LatteTexture_setEffectiveTextureScale(LatteConst::ShaderType shaderType, sint32 texUnit, float u, float v)\n{\n\tcemu_assert_debug(texUnit >= 0 && texUnit < Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE);\n\tfloat* t = LatteTextureScale[static_cast<size_t>(shaderType)].perUnit[texUnit].xy;\n\tt[0] = u;\n\tt[1] = v;\n}\n\nvoid LatteTextureLoader_UpdateTextureSliceData(LatteTexture* tex, uint32 sliceIndex, uint32 mipIndex, MPTR physImagePtr, MPTR physMipPtr, Latte::E_DIM dim, uint32 width, uint32 height, uint32 depth, uint32 mipLevels, uint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle, bool dumpTex);\n\nvoid LatteTexture_ReloadData(LatteTexture* tex)\n{\n\ttex->reloadCount++;\n\tfor(sint32 mip=0; mip<tex->mipLevels; mip++)\n\t{\n\t\tif(tex->dim == Latte::E_DIM::DIM_2D_ARRAY ||\n\t\t\ttex->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA )\n\t\t{\n\t\t\tsint32 numSlices = std::max(tex->depth, 1);\n\t\t\tfor(sint32 s=0; s<numSlices; s++)\n\t\t\t\tLatteTextureLoader_UpdateTextureSliceData(tex, s, mip, tex->physAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true);\n\t\t}\n\t\telse if( tex->dim == Latte::E_DIM::DIM_CUBEMAP )\n\t\t{\n\t\t\tcemu_assert_debug((tex->depth % 6) == 0);\n\t\t\tsint32 numFullCubeMaps = tex->depth/6; // number of cubemaps (if numFullCubeMaps is >1 then this texture is a cubemap array)\n\t\t\tfor(sint32 s=0; s<numFullCubeMaps*6; s++)\n\t\t\t\tLatteTextureLoader_UpdateTextureSliceData(tex, s, mip, tex->physAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true);\n\t\t}\n\t\telse if( tex->dim == Latte::E_DIM::DIM_3D )\n\t\t{\n\t\t\tsint32 mipDepth = std::max(tex->depth>>mip, 1);\n\t\t\tfor(sint32 s=0; s<mipDepth; s++)\n\t\t\t{\n\t\t\t\tLatteTextureLoader_UpdateTextureSliceData(tex, s, mip, tex->physAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// load slice 0\n\t\t\tLatteTextureLoader_UpdateTextureSliceData(tex, 0, mip, tex->physAddress, tex->physMipAddress, tex->dim, tex->width, tex->height, tex->depth, tex->mipLevels, tex->pitch, tex->tileMode, tex->swizzle, true);\n\t\t}\n\t}\n\ttex->lastUpdateEventCounter = LatteTexture_getNextUpdateEventCounter();\n}\n\nLatteTextureView* LatteTexture_CreateTexture(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth)\n{\n\tconst auto tex = g_renderer->texture_createTextureEx(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth);\n\n\t// init slice/mip info array\n\tLatteTexture_InitSliceAndMipInfo(tex);\n\tLatteTexture_RegisterTextureMemoryOccupancy(tex);\n\tcemu_assert_debug(mipLevels != 0);\n\n\tLatteTexture_ReloadData(tex);\n\tLatteTC_MarkTextureStillInUse(tex);\n\tLatteTC_RegisterTexture(tex);\n\n\t// create initial view that maps to the whole texture\n\ttex->baseView = tex->GetOrCreateView(0, tex->mipLevels, 0, tex->depth);\n\treturn tex->baseView;\n}\n\nLatte::E_GX2SURFFMT LatteTexture_ReconstructGX2Format(const Latte::LATTE_SQ_TEX_RESOURCE_WORD1_N& texUnitWord1, const Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N& texUnitWord4)\n{\n\tLatte::E_GX2SURFFMT gx2Format = (Latte::E_GX2SURFFMT)texUnitWord1.get_DATA_FORMAT();\n\tauto nfa = texUnitWord4.get_NUM_FORM_ALL();\n\tif (nfa == Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N::E_NUM_FORMAT_ALL::NUM_FORMAT_SCALED)\n\t\tgx2Format |= Latte::E_GX2SURFFMT::FMT_BIT_FLOAT;\n\telse if (nfa == Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N::E_NUM_FORMAT_ALL::NUM_FORMAT_INT)\n\t\tgx2Format |= Latte::E_GX2SURFFMT::FMT_BIT_INT;\n\n\tif(texUnitWord4.get_FORCE_DEGAMMA())\n\t\tgx2Format |= Latte::E_GX2SURFFMT::FMT_BIT_SRGB;\n\n\tif (texUnitWord4.get_FORMAT_COMP_X() == Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N::E_FORMAT_COMP::COMP_SIGNED)\n\t\tgx2Format |= Latte::E_GX2SURFFMT::FMT_BIT_SIGNED;\n\n\treturn gx2Format;\n}\n\nvoid LatteTexture_updateTexturesForStage(LatteDecompilerShader* shaderContext, uint32 glBackendBaseTexUnit, _LatteRegisterSetTextureUnit* texRegBase)\n{\n\tfor (sint32 z = 0; z < shaderContext->textureUnitListCount; z++)\n\t{\n\t\tsint32 textureIndex = shaderContext->textureUnitList[z];\n\t\tconst auto& texRegister = texRegBase[textureIndex];\n\n\t\t// get physical address of texture data\n\t\tMPTR physAddr = (texRegister.word2.get_BASE_ADDRESS() << 8);\n\t\tif (physAddr == MPTR_NULL)\n\t\t\tcontinue; // invalid data\n\t\tMPTR physMipAddr = (texRegister.word3.get_MIP_ADDRESS() << 8);\n\n\t\t// word0\n\t\tconst auto word0 = texRegister.word0;\n\t\tauto dim = word0.get_DIM();\n\t\tuint32 pitch = (word0.get_PITCH() + 1) << 3;\n\t\tuint32 width = word0.get_WIDTH() + 1;\n\t\tauto tileMode = word0.get_TILE_MODE();\n\t\t// word1\n\t\tconst auto word1 = texRegister.word1;\n\t\tuint32 depth = word1.get_DEPTH();\n\t\tif (dim == Latte::E_DIM::DIM_2D_ARRAY || dim == Latte::E_DIM::DIM_3D || dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA || dim == Latte::E_DIM::DIM_1D_ARRAY)\n\t\t{\n\t\t\tdepth = depth + 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (dim == Latte::E_DIM::DIM_CUBEMAP)\n\t\t\t\tdepth = 6 * (depth + 1);\n\t\t\tif (depth == 0)\n\t\t\t\tdepth = 1;\n\t\t}\n\t\tuint32 height = word1.get_HEIGHT() + 1;\n\t\tif (dim == Latte::E_DIM::DIM_1D || dim == Latte::E_DIM::DIM_1D_ARRAY)\n\t\t\theight = 1;\n\t\tif (Latte::IsCompressedFormat(word1.get_DATA_FORMAT()))\n\t\t\tpitch /= 4;\n\t\t// view slice\n\t\tconst auto word4 = texRegister.word4;\n\t\tconst auto word5 = texRegister.word5;\n\n\t\tuint32 viewFirstSlice = word5.get_BASE_ARRAY();\n\t\tuint32 viewNumSlices = word5.get_LAST_ARRAY() + 1 - viewFirstSlice;\n\n\t\tuint32 viewFirstMip = word4.get_BASE_LEVEL();\n\t\tuint32 viewNumMips = word5.get_LAST_LEVEL() + 1 - viewFirstMip;\n\n\t\tcemu_assert_debug(viewNumMips != 0);\n\n\t\tLatte::E_GX2SURFFMT format = LatteTexture_ReconstructGX2Format(word1, word4);\n\n\t\t// todo - AA\n\t\tif (dim == Latte::E_DIM::DIM_2D_MSAA)\n\t\t{\n\t\t\t// MSAA only supports one mip level?\n\t\t\t// without this we encounter a crash in The Mysterious Cities of Gold: Secret Paths due to it setting mip count to 2 and leaving mip pointer on an invalid uninitialized value\n\t\t\tviewFirstMip = 0;\n\t\t\tviewNumMips = 1;\n\t\t}\n\n\t\t// swizzle\n\t\tuint32 swizzle = 0;\n\t\tif (Latte::TM_IsMacroTiled(tileMode))\n\t\t{\n\t\t\t// extract swizzle bits from pointer if macro-tiled\n\t\t\tswizzle = (physAddr & 0x700);\n\t\t\tphysAddr &= ~0x700;\n\t\t}\n\n\t\tbool isDepthSampler = shaderContext->textureUsesDepthCompare[textureIndex];\n\t\t// look for already existing texture\n\t\tLatteTextureView* textureView;\n\t\tif (!isDepthSampler)\n\t\t\ttextureView = LatteTextureViewLookupCache::lookup(physAddr, width, height, depth, pitch, viewFirstMip, viewNumMips, viewFirstSlice, viewNumSlices, format, dim);\n\t\telse\n\t\t\ttextureView = LatteTextureViewLookupCache::lookupWithColorOrDepthType(physAddr, width, height, depth, pitch, viewFirstMip, viewNumMips, viewFirstSlice, viewNumSlices, format, dim, true);\n\t\tif (!textureView)\n\t\t{\n\t\t\t// view not found, create a new mapping which will also create a new texture if necessary\n\t\t\ttextureView = LatteTexture_CreateMapping(physAddr, physMipAddr, width, height, depth, pitch, tileMode, swizzle, viewFirstMip, viewNumMips, viewFirstSlice, viewNumSlices, format, dim, dim, isDepthSampler);\n\t\t\tif (textureView == nullptr)\n\t\t\t\tcontinue;\n\t\t\tLatteGPUState.repeatTextureInitialization = true;\n\t\t}\n\n\t\tif (g_renderer->GetType() == RendererAPI::OpenGL)\n\t\t{\n\t\t\t// on OpenGL, texture views and sampler parameters are tied together (we are avoiding sampler objects due to driver bugs)\n\t\t\t// in order to emulate different sampler parameters when a texture is bound multiple times we create extra views\n\t\t\tOpenGLRenderer* rendererGL = static_cast<OpenGLRenderer*>(g_renderer.get());\n\n\t\t\t// if this texture is bound multiple times then use alternative views\n\t\t\tif (textureView->lastTextureBindIndex == LatteGPUState.textureBindCounter)\n\t\t\t{\n\t\t\t\tLatteTextureViewGL* textureViewGL = (LatteTextureViewGL*)textureView;\n\t\t\t\t// get next unused alternative texture view\n\t\t\t\twhile (true)\n\t\t\t\t{\n\t\t\t\t\ttextureViewGL = textureViewGL->GetAlternativeView();\n\t\t\t\t\tif (textureViewGL->lastTextureBindIndex != LatteGPUState.textureBindCounter)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\ttextureView = textureViewGL;\n\t\t}\n\t\t\ttextureView->lastTextureBindIndex = LatteGPUState.textureBindCounter;\n\t\t\trendererGL->renderstate_updateTextureSettingsGL(shaderContext, textureView, textureIndex + glBackendBaseTexUnit, word4, textureIndex, isDepthSampler);\n\t\t}\n\t\tg_renderer->texture_setLatteTexture(textureView, textureIndex + glBackendBaseTexUnit);\n\t\t// update if data changed\n\t\tbool swizzleChanged = false;\n\t\tif (textureView->baseTexture->swizzle != swizzle)\n\t\t{\n\t\t\tdebug_printf(\"BaseSwizzle diff prev %08x new %08x rt %08x tm %d\\n\", textureView->baseTexture->swizzle, swizzle, textureView->baseTexture->lastRenderTargetSwizzle, textureView->baseTexture->tileMode);\n\t\t\tif (swizzle == textureView->baseTexture->lastRenderTargetSwizzle)\n\t\t\t{\n\t\t\t\t// last render to texture updated the swizzle and we can assume the texture data is still valid\n\t\t\t\ttextureView->baseTexture->swizzle = textureView->baseTexture->lastRenderTargetSwizzle;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// reload texture\n\t\t\t\tswizzleChanged = true;\n\t\t\t}\n\t\t}\n\t\telse if ((viewFirstMip + viewNumMips) > 1 && (textureView->baseTexture->physMipAddress != physMipAddr))\n\t\t{\n\t\t\tdebug_printf(\"MipPhys/Swizzle change diff prev %08x new %08x tm %d\\n\", textureView->baseTexture->physMipAddress, physMipAddr, textureView->baseTexture->tileMode);\n\t\t\tswizzleChanged = true;\n\t\t\tcemu_assert_debug(physMipAddr != MPTR_NULL);\n\t\t}\n\t\t// check for changes\n\t\tif (LatteTC_HasTextureChanged(textureView->baseTexture) || swizzleChanged)\n\t\t{\n\t\t\tdebug_printf(\"Reload texture 0x%08x res %dx%d memRange %08x-%08x SwizzleChange: %s\\n\", textureView->baseTexture->physAddress, textureView->baseTexture->width, textureView->baseTexture->height, textureView->baseTexture->texDataPtrLow, textureView->baseTexture->texDataPtrHigh, swizzleChanged ? \"yes\" : \"no\");\n\t\t\t// update swizzle / changed mip address\n\t\t\tif (swizzleChanged)\n\t\t\t{\n\t\t\t\ttextureView->baseTexture->swizzle = swizzle;\n\t\t\t\tif ((viewFirstMip + viewNumMips) > 1)\n\t\t\t\t{\n\t\t\t\t\ttextureView->baseTexture->physMipAddress = physMipAddr;\n\t\t\t\t}\n\t\t\t}\n\t\t\tdebug_printf(\"Reload reason: Data-change when bound as texture (new hash 0x%08x)\\n\", textureView->baseTexture->texDataHash2);\n\t\t\tLatteTexture_ReloadData(textureView->baseTexture);\n\t\t}\n\t\tLatteTexture* baseTexture = textureView->baseTexture;\n\t\tif (baseTexture->reloadFromDynamicTextures)\n\t\t{\n\t\t\tLatteTexture_UpdateCacheFromDynamicTextures(baseTexture);\n\t\t\tbaseTexture->reloadFromDynamicTextures = false;\n\t\t}\n\t\tLatteTC_MarkTextureStillInUse(baseTexture);\n\n\t\t// check if barrier is necessary\n\t\tif ((sint32)(LatteGPUState.drawCallCounter - baseTexture->lastUnflushedRTDrawcallIndex) < 2)\n\t\t{\n\t\t\tLatteGPUState.requiresTextureBarrier = true;\n\t\t\tbaseTexture->lastUnflushedRTDrawcallIndex = 0;\n\t\t}\n\t\t// update scale\n\t\tfloat texScaleU, texScaleV;\n\t\tif (baseTexture->overwriteInfo.hasResolutionOverwrite == false)\n\t\t{\n\t\t\ttexScaleU = 1.0f;\n\t\t\ttexScaleV = 1.0f;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttexScaleU = (float)baseTexture->overwriteInfo.width / (float)baseTexture->width;\n\t\t\ttexScaleV = (float)baseTexture->overwriteInfo.height / (float)baseTexture->height;\n\t\t}\n\t\tLatteTexture_setEffectiveTextureScale(shaderContext->shaderType, textureIndex, texScaleU, texScaleV);\n\t}\n}\n\n// initialize textures used by the current drawcall\n// Sets LatteGPUState.repeatTextureInitialization to true if a new texture mapping was created (indicating that this function must be called again)\n// also sets LatteGPUState.requiresTextureBarrier to true if texture barrier is required\nvoid LatteTexture_updateTextures()\n{\n\tLatteGPUState.textureBindCounter++;\n\t// pixel shader\n\tLatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();\n\tif (pixelShader)\n\t\tLatteTexture_updateTexturesForStage(pixelShader, LATTE_CEMU_PS_TEX_UNIT_BASE, LatteGPUState.contextNew.SQ_TEX_START_PS);\n\t// vertex shader\n\tLatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();\n\tcemu_assert_debug(vertexShader != nullptr);\n\tLatteTexture_updateTexturesForStage(vertexShader, LATTE_CEMU_VS_TEX_UNIT_BASE, LatteGPUState.contextNew.SQ_TEX_START_VS);\n\t// geometry shader\n\tLatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader();\n\tif (geometryShader)\n\t\tLatteTexture_updateTexturesForStage(geometryShader, LATTE_CEMU_GS_TEX_UNIT_BASE, LatteGPUState.contextNew.SQ_TEX_START_GS);\n}\n\nsint32 LatteTexture_getEffectiveWidth(LatteTexture* texture)\n{\n\tif (texture->overwriteInfo.hasResolutionOverwrite)\n\t\treturn texture->overwriteInfo.width;\n\treturn texture->width;\n}\n\n// returns true if the two textures have the same rescale factor\nbool LatteTexture_doesEffectiveRescaleRatioMatch(LatteTexture* texture1, sint32 mipLevel1, LatteTexture* texture2, sint32 mipLevel2)\n{\n\tdouble widthRatio1 = (double)LatteTexture_getEffectiveWidth(texture1) / (double)texture1->width;\n\tdouble widthRatio2 = (double)LatteTexture_getEffectiveWidth(texture2) / (double)texture2->width;\n\t// the difference between the factors must be less than 5%\n\tdouble diff = widthRatio1 / widthRatio2;\n\tif (abs(1.0 - diff) > 0.05)\n\t{\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nvoid LatteTexture_scaleToEffectiveSize(LatteTexture* texture, sint32* x, sint32* y, sint32 mipLevel)\n{\n\tif( texture->overwriteInfo.hasResolutionOverwrite == false )\n\t\treturn;\n\t*x = *x * std::max(1,texture->overwriteInfo.width>>mipLevel) / std::max(1,texture->width>>mipLevel);\n\t*y = *y * std::max(1,texture->overwriteInfo.height>>mipLevel) / std::max(1, texture->height>>mipLevel);\n}\n\nuint64 _textureUpdateEventCounter = 1;\n\nuint64 LatteTexture_getNextUpdateEventCounter()\n{\n\tuint64 counter = _textureUpdateEventCounter;\n\t_textureUpdateEventCounter++;\n\treturn counter;\n}\n\nvoid LatteTexture_init()\n{\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/CafeSystem.h\"\n\n//#define BENCHMARK_TEXTURE_DECODING\t\t// if defined, time it takes to decode textures will be measured and logged to log.txt\n\n#ifdef BENCHMARK_TEXTURE_DECODING\nuint64 textureDecodeBenchmark_perFormatSum[0x40] = { 0 }; // duration sum per texture format (hw format) - in microseconds\nuint64 textureDecodeBenchmark_totalSum = 0;\n#endif\n\nvoid LatteTextureLoader_begin(LatteTextureLoaderCtx* textureLoader, uint32 sliceIndex, uint32 mipIndex, MPTR physImagePtr, MPTR physMipPtr, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, uint32 width, uint32 height, uint32 depth, uint32 mipLevels, uint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle)\n{\n\ttextureLoader->physAddress = physImagePtr;\n\ttextureLoader->physMipAddress = physMipPtr;\n\ttextureLoader->sliceIndex = sliceIndex;\n\tcemu_assert_debug(mipLevels != 0);\n\ttextureLoader->mipLevels = std::max<uint32>(1, mipLevels);\n\ttextureLoader->tileMode = tileMode;\n\ttextureLoader->bpp = Latte::GetFormatBits(format);\n\ttextureLoader->stepX = 1;\n\ttextureLoader->stepY = 1;\n\tif (Latte::IsCompressedFormat(format))\n\t{\n\t\ttextureLoader->stepX = 4;\n\t\ttextureLoader->stepY = 4;\n\t}\n\n\ttextureLoader->pipeSwizzle = (swizzle >> 8) & 1;\n\ttextureLoader->bankSwizzle = ((swizzle >> 9) & 3);\n\n\tuint32 surfaceAA = 0; // todo\n\n\tif (mipIndex > 0 && Latte::TM_IsMacroTiled(tileMode))\n\t{\n\t\t// separate swizzle from mip pointer if mip chain is not macro-tiled (and thus not swizzled)\n\t\tLatteAddrLib::AddrSurfaceInfo_OUT surfaceInfo;\n\t\tLatteAddrLib::GX2CalculateSurfaceInfo(format, width, height, depth, dim, Latte::MakeGX2TileMode(tileMode), surfaceAA, 1, &surfaceInfo);\n\t\tif (Latte::TM_IsMacroTiled(surfaceInfo.hwTileMode))\n\t\t{\n\t\t\tuint32 mipSwizzle = physMipPtr&0x700;\n\t\t\tphysMipPtr &= ~0x700;\n\t\t\ttextureLoader->physMipAddress = physMipPtr;\n\t\t\ttextureLoader->pipeSwizzle = (mipSwizzle >> 8) & 1;\n\t\t\ttextureLoader->bankSwizzle = ((mipSwizzle >> 9) & 3);\n\t\t}\n\t}\n\n\t// calculate surface info\n\tuint32 level = mipIndex;\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfaceInfo;\n\tLatteAddrLib::GX2CalculateSurfaceInfo(format, width, height, depth, dim, Latte::MakeGX2TileMode(tileMode), surfaceAA, level, &surfaceInfo);\n\ttextureLoader->levelOffset = LatteAddrLib::CalculateMipOffset(format, width, height, depth, dim, (Latte::E_HWTILEMODE)tileMode, swizzle, surfaceAA, level);\n\ttextureLoader->tileMode = surfaceInfo.hwTileMode;\n\n\ttextureLoader->minOffsetOutdated = 0;\n\ttextureLoader->maxOffsetOutdated = (sint32)surfaceInfo.surfSize;\n\n\ttextureLoader->surfaceInfoHeight = surfaceInfo.height;\n\ttextureLoader->surfaceInfoDepth = surfaceInfo.depth;\n\n\t// correct handling for LINEAR_ALIGNED pitch alignment is still not fully understood:\n\t//seems like sometimes there is a conditional pitch alignment to 0x40 OR there is no pitch alignment at all and we have a bug somewhere else\n\n\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\ttitleId &= ~0x300ULL;\n\n\tif (tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED && titleId == (0x000500301001200aULL))\n\t{\n\t\t// examples of titles that use linear textures:\n\t\t// Minecraft - Uses sprite atlases with mips and linear tilemode. Expects padding of pitch for smaller mips to be 0x40\n\t\t// Browser - Linear pitch must be used as-is, padding/alignment will break textures (uses a weird way to calculate pitch by using GX2CalcSurface on a texture with tileMode 0/4)\n\t\t// BotW - uses linear textures as render targets. With the smallest resolution being 3x3 with no pitch alignment expected at all (pitch = 3)? -> Not possible because both textures and rendertargets require a minimum alignment of 8 for pitch?\n\t\tsurfaceInfo.pitch = std::max<uint32>(1, pitch >> mipIndex);\n\t}\n\n\n\ttextureLoader->width = width >> (mipIndex);\n\ttextureLoader->width = std::max(textureLoader->width, 1);\n\ttextureLoader->height = height >> (mipIndex);\n\ttextureLoader->height = std::max(textureLoader->height, 1);\n\n\ttextureLoader->pitch = surfaceInfo.pitch;\n\t// calculate start address\n\tif (level == 0)\n\t\ttextureLoader->inputData = (uint8*)memory_getPointerFromPhysicalOffset(physImagePtr);\n\telse\n\t\ttextureLoader->inputData = (uint8*)memory_getPointerFromPhysicalOffset(physMipPtr) + textureLoader->levelOffset;\n\n\tSetupCachedSurfaceAddrInfo(&textureLoader->computeAddrInfo, textureLoader->sliceIndex, 0, textureLoader->bpp, textureLoader->pitch, surfaceInfo.height, depth, 1 * 1, textureLoader->tileMode, false, textureLoader->pipeSwizzle, textureLoader->bankSwizzle);\n}\n\nuint8* LatteTextureLoader_GetInput(LatteTextureLoaderCtx* textureLoader, sint32 x, sint32 y)\n{\n\t// calculate address of input tile\n\tuint32 offset = 0;\n\tif (textureLoader->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_GENERAL || textureLoader->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED)\n\t\toffset = LatteAddrLib::ComputeSurfaceAddrFromCoordLinear(x / textureLoader->stepX, y / textureLoader->stepY, textureLoader->sliceIndex, 0, textureLoader->bpp, textureLoader->pitch, textureLoader->surfaceInfoHeight, textureLoader->surfaceInfoDepth);\n\telse if (textureLoader->tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THIN1 || textureLoader->tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THICK)\n\t\toffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMicroTiled(x / textureLoader->stepX, y / textureLoader->stepY, textureLoader->sliceIndex, textureLoader->bpp, textureLoader->pitch, textureLoader->surfaceInfoHeight, (Latte::E_HWTILEMODE)textureLoader->tileMode, false);\n\telse\n\t\toffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMacroTiledCached(x / textureLoader->stepX, y / textureLoader->stepY, &textureLoader->computeAddrInfo);\n\tuint8* blockData = textureLoader->inputData + offset;\n\treturn blockData;\n}\n\n/*\n * Optimized version which assumes tileMode == 1\n * Also does not do any min/max offset tracking\n */\nuint8* LatteTextureLoader_getInputLinearOptimized(LatteTextureLoaderCtx* textureLoader, sint32 x, sint32 y)\n{\n\t// calculate address of input tile\n\tuint32 bitPos = 0;\n\tuint32 offset = 0;\n\toffset = LatteAddrLib::ComputeSurfaceAddrFromCoordLinear(x / textureLoader->stepX, y / textureLoader->stepY, textureLoader->sliceIndex, 0, textureLoader->bpp, textureLoader->pitch, textureLoader->surfaceInfoHeight, textureLoader->surfaceInfoDepth);\n\treturn textureLoader->inputData + offset;\n}\n\n#define LatteTextureLoader_getInputLinearOptimized_(__textureLoader,__x,__y,__stepX,__stepY,__bpp,__sliceIndex,__numSlices,__sample,__pitch,__height) (textureLoader->inputData+((__x/__stepX) + __pitch * (__y/__stepY) + (__sliceIndex + __numSlices * __sample) * __height * __pitch)*(__bpp/8))\n\nvoid decodeBC1Block(uint8* inputData, float* output4x4RGBA)\n{\n\t// read colors\n\tuint16 c0 = *(uint16*)(inputData + 0);\n\tuint16 c1 = *(uint16*)(inputData + 2);\n\t// decode colors (RGB565 -> RGB888)\n\tfloat r[4];\n\tfloat g[4];\n\tfloat b[4];\n\tfloat a[4];\n\tb[0] = (float)((c0 >> 0) & 0x1F) / 31.0f;\n\tb[1] = (float)((c1 >> 0) & 0x1F) / 31.0f;\n\tg[0] = (float)((c0 >> 5) & 0x3F) / 63.0f;\n\tg[1] = (float)((c1 >> 5) & 0x3F) / 63.0f;\n\tr[0] = (float)((c0 >> 11) & 0x1F) / 31.0f;\n\tr[1] = (float)((c1 >> 11) & 0x1F) / 31.0f;\n\ta[0] = 1.0f;\n\ta[1] = 1.0f;\n\ta[2] = 1.0f;\n\n\tif (c0 > c1)\n\t{\n\t\tr[2] = (r[0] * 2.0f + r[1]) / 3.0f;\n\t\tr[3] = (r[0] * 1.0f + r[1] * 2.0f) / 3.0f;\n\t\tg[2] = (g[0] * 2.0f + g[1]) / 3.0f;\n\t\tg[3] = (g[0] * 1.0f + g[1] * 2.0f) / 3.0f;\n\t\tb[2] = (b[0] * 2.0f + b[1]) / 3.0f;\n\t\tb[3] = (b[0] * 1.0f + b[1] * 2.0f) / 3.0f;\n\t\ta[3] = 1.0f;\n\t}\n\telse\n\t{\n\t\tr[2] = (r[0] + r[1]) / 2.0f;\n\t\tr[3] = 0.0f;\n\t\tg[2] = (g[0] + g[1]) / 2.0f;\n\t\tg[3] = 0.0f;\n\t\tb[2] = (b[0] + b[1]) / 2.0f;\n\t\tb[3] = 0.0f;\n\t\ta[3] = 0.0f;\n\t}\n\n\tuint8* indexData = inputData + 4;\n\tfloat* colorOutputRGBA = output4x4RGBA;\n\tfor (sint32 row = 0; row < 4; row++)\n\t{\n\t\tuint8 i0 = ((*indexData) >> 0) & 3;\n\t\tuint8 i1 = ((*indexData) >> 2) & 3;\n\t\tuint8 i2 = ((*indexData) >> 4) & 3;\n\t\tuint8 i3 = ((*indexData) >> 6) & 3;\n\t\tcolorOutputRGBA[0] = r[i0];\n\t\tcolorOutputRGBA[1] = g[i0];\n\t\tcolorOutputRGBA[2] = b[i0];\n\t\tcolorOutputRGBA[3] = a[i0];\n\t\tcolorOutputRGBA += 4;\n\t\tcolorOutputRGBA[0] = r[i1];\n\t\tcolorOutputRGBA[1] = g[i1];\n\t\tcolorOutputRGBA[2] = b[i1];\n\t\tcolorOutputRGBA[3] = a[i1];\n\t\tcolorOutputRGBA += 4;\n\t\tcolorOutputRGBA[0] = r[i2];\n\t\tcolorOutputRGBA[1] = g[i2];\n\t\tcolorOutputRGBA[2] = b[i2];\n\t\tcolorOutputRGBA[3] = a[i2];\n\t\tcolorOutputRGBA += 4;\n\t\tcolorOutputRGBA[0] = r[i3];\n\t\tcolorOutputRGBA[1] = g[i3];\n\t\tcolorOutputRGBA[2] = b[i3];\n\t\tcolorOutputRGBA[3] = a[i3];\n\t\tcolorOutputRGBA += 4;\n\t\tindexData++;\n\t}\n}\n\nvoid decodeBC2Block_UNORM(uint8* inputData, float* imageRGBA)\n{\n\tuint32 color0 = *(uint16*)(inputData + 8);\n\tuint32 color1 = *(uint16*)(inputData + 10);\n\tuint32 colorIndices = *(uint32*)(inputData + 12);\n\n\tuint8 r0 = (color0 >> 11) & 0x1F;\n\tuint8 g0 = (color0 >> 5) & 0x3F;\n\tuint8 b0 = (color0 >> 0) & 0x1F;\n\n\tuint8 r1 = (color1 >> 11) & 0x1F;\n\tuint8 g1 = (color1 >> 5) & 0x3F;\n\tuint8 b1 = (color1 >> 0) & 0x1F;\n\n\tfloat r[4];\n\tfloat g[4];\n\tfloat b[4];\n\tr[0] = (float)r0 / 31.0f;\n\tr[1] = (float)r1 / 31.0f;\n\tr[2] = (r[0] * 2.0f + r[1]) / 3.0f;\n\tr[3] = (r[0] + r[1] * 2.0f) / 3.0f;\n\tg[0] = (float)g0 / 63.0f;\n\tg[1] = (float)g1 / 63.0f;\n\tg[2] = (g[0] * 2.0f + g[1]) / 3.0f;\n\tg[3] = (g[0] + g[1] * 2.0f) / 3.0f;\n\tb[0] = (float)b0 / 31.0f;\n\tb[1] = (float)b1 / 31.0f;\n\tb[2] = (b[0] * 2.0f + b[1]) / 3.0f;\n\tb[3] = (b[0] + b[1] * 2.0f) / 3.0f;\n\n\tfor (sint32 py = 0; py < 4; py++)\n\t{\n\t\tfor (sint32 px = 0; px < 4; px++)\n\t\t{\n\t\t\tuint8 colorIndex = (colorIndices >> (2 * (px + 4 * py))) & 0x03;\n\t\t\tsint32 pixelOffset = (px + py * 4) * 4;\n\t\t\timageRGBA[pixelOffset + 0] = r[colorIndex];\n\t\t\timageRGBA[pixelOffset + 1] = g[colorIndex];\n\t\t\timageRGBA[pixelOffset + 2] = b[colorIndex];\n\t\t}\n\t}\n\n\t// decode alpha\n\tuint8* alphaData = (uint8*)(inputData + 0);\n\tfor (sint32 py = 0; py < 4; py++)\n\t{\n\t\tfor (sint32 px = 0; px < 4; px++)\n\t\t{\n\t\t\tuint32 alphaIndex = (px + py * 4);\n\t\t\tuint8 alphaCode = (alphaData[alphaIndex / 2] >> ((alphaIndex & 1) * 4)) & 0xF;\n\t\t\talphaCode |= (alphaCode << 4);\n\t\t\tsint32 pixelOffset = (px + py * 4) * 4;\n\t\t\timageRGBA[pixelOffset + 3] = (float)alphaCode / 255.0f; // alpha\n\t\t}\n\t}\n}\n\nvoid decodeBC3Block_UNORM(uint8* inputData, float* imageRGBA)\n{\n\tuint32 color0 = *(uint16*)(inputData + 8);\n\tuint32 color1 = *(uint16*)(inputData + 10);\n\tuint32 colorIndices = *(uint32*)(inputData + 12);\n\n\tuint8 r0 = (color0 >> 11) & 0x1F;\n\tuint8 g0 = (color0 >> 5) & 0x3F;\n\tuint8 b0 = (color0 >> 0) & 0x1F;\n\n\tuint8 r1 = (color1 >> 11) & 0x1F;\n\tuint8 g1 = (color1 >> 5) & 0x3F;\n\tuint8 b1 = (color1 >> 0) & 0x1F;\n\n\tfloat r[4];\n\tfloat g[4];\n\tfloat b[4];\n\tr[0] = (float)r0 / 31.0f;\n\tr[1] = (float)r1 / 31.0f;\n\tr[2] = (r[0] * 2.0f + r[1]) / 3.0f;\n\tr[3] = (r[0] + r[1] * 2.0f) / 3.0f;\n\tg[0] = (float)g0 / 63.0f;\n\tg[1] = (float)g1 / 63.0f;\n\tg[2] = (g[0] * 2.0f + g[1]) / 3.0f;\n\tg[3] = (g[0] + g[1] * 2.0f) / 3.0f;\n\tb[0] = (float)b0 / 31.0f;\n\tb[1] = (float)b1 / 31.0f;\n\tb[2] = (b[0] * 2.0f + b[1]) / 3.0f;\n\tb[3] = (b[0] + b[1] * 2.0f) / 3.0f;\n\n\tfor (sint32 py = 0; py < 4; py++)\n\t{\n\t\tfor (sint32 px = 0; px < 4; px++)\n\t\t{\n\t\t\tuint8 colorIndex = (colorIndices >> (2 * (px + 4 * py))) & 0x03;\n\t\t\tsint32 pixelOffset = (px + py * 4) * 4;\n\t\t\timageRGBA[pixelOffset + 0] = r[colorIndex];\n\t\t\timageRGBA[pixelOffset + 1] = g[colorIndex];\n\t\t\timageRGBA[pixelOffset + 2] = b[colorIndex];\n\t\t\t//imageRGBA[pixelOffset+3] = 1.0f; // alpha\n\t\t}\n\t}\n\n\t// decode alpha\n\tuint8 alpha0 = *(uint8*)(inputData + 0);\n\tuint8 alpha1 = *(uint8*)(inputData + 1);\n\tuint32 alphaCodeRow[2] = { 0 };\n\talphaCodeRow[0] |= ((*(uint8*)(inputData + 2)) << 0);\n\talphaCodeRow[0] |= ((*(uint8*)(inputData + 3)) << 8);\n\talphaCodeRow[0] |= ((*(uint8*)(inputData + 4)) << 16);\n\talphaCodeRow[1] |= ((*(uint8*)(inputData + 5)) << 0);\n\talphaCodeRow[1] |= ((*(uint8*)(inputData + 6)) << 8);\n\talphaCodeRow[1] |= ((*(uint8*)(inputData + 7)) << 16);\n\n\tfloat a[8];\n\ta[0] = (float)alpha0 / 255.0f;\n\ta[1] = (float)alpha1 / 255.0f;\n\n\tif (alpha0 > alpha1)\n\t{\n\t\t// 6 interpolated alpha values.\n\t\ta[2] = (a[0] * 6.0f + a[1] * 1.0f) / 7.0f;\n\t\ta[3] = (a[0] * 5.0f + a[1] * 2.0f) / 7.0f;\n\t\ta[4] = (a[0] * 4.0f + a[1] * 3.0f) / 7.0f;\n\t\ta[5] = (a[0] * 3.0f + a[1] * 4.0f) / 7.0f;\n\t\ta[6] = (a[0] * 2.0f + a[1] * 5.0f) / 7.0f;\n\t\ta[7] = (a[0] * 1.0f + a[1] * 6.0f) / 7.0f;\n\t}\n\telse\n\t{\n\t\t// 4 interpolated alpha values.\n\t\ta[2] = (a[0] * 4.0f + a[1] * 1.0f) / 5.0f;\n\t\ta[3] = (a[0] * 3.0f + a[1] * 2.0f) / 5.0f;\n\t\ta[4] = (a[0] * 2.0f + a[1] * 3.0f) / 5.0f;\n\t\ta[5] = (a[0] * 1.0f + a[1] * 4.0f) / 5.0f;\n\t\ta[6] = 0.0f;\n\t\ta[7] = 1.0f;\n\t}\n\n\tfor (sint32 py = 0; py < 4; py++)\n\t{\n\t\tfor (sint32 px = 0; px < 4; px++)\n\t\t{\n\t\t\tuint8 alphaCode = (alphaCodeRow[py / 2] >> 3 * (px + 4 * (py & 1))) & 0x07;\n\t\t\tsint32 pixelOffset = (px + py * 4) * 4;\n\t\t\timageRGBA[pixelOffset + 3] = a[alphaCode]; // alpha\n\t\t}\n\t}\n}\n\nvoid decodeBC4Block_UNORM(uint8* blockStorage, float* rOutput)\n{\n\tuint8* blockInput = (uint8*)blockStorage;\n\tfloat red[8];\n\n\tred[0] = ((float)(*(uint8*)(blockInput + 0))) / 255.0f;\n\tred[1] = ((float)(*(uint8*)(blockInput + 1))) / 255.0f;\n\n\tif (blockInput[0] > blockInput[1])\n\t{\n\t\t// 6 interpolated color values\n\t\tred[2] = (6 * red[0] + 1 * red[1]) / 7.0f; // bit code 010\n\t\tred[3] = (5 * red[0] + 2 * red[1]) / 7.0f; // bit code 011\n\t\tred[4] = (4 * red[0] + 3 * red[1]) / 7.0f; // bit code 100\n\t\tred[5] = (3 * red[0] + 4 * red[1]) / 7.0f; // bit code 101\n\t\tred[6] = (2 * red[0] + 5 * red[1]) / 7.0f; // bit code 110\n\t\tred[7] = (1 * red[0] + 6 * red[1]) / 7.0f; // bit code 111\n\t}\n\telse\n\t{\n\t\t// 4 interpolated color values\n\t\tred[2] = (4 * red[0] + 1 * red[1]) / 5.0f; // bit code 010\n\t\tred[3] = (3 * red[0] + 2 * red[1]) / 5.0f; // bit code 011\n\t\tred[4] = (2 * red[0] + 3 * red[1]) / 5.0f; // bit code 100\n\t\tred[5] = (1 * red[0] + 4 * red[1]) / 5.0f; // bit code 101\n\t\tred[6] = 0.0f;                       // bit code 110\n\t\tred[7] = 1.0f;                       // bit code 111\n\t}\n\n\tuint8* bitIndices = blockInput + 2;\n\tuint32 redRow0 = (((uint32)bitIndices[2]) << 16) | (((uint32)bitIndices[1]) << 8) | (((uint32)bitIndices[0]) << 0);\n\tuint32 redRow1 = (((uint32)bitIndices[5]) << 16) | (((uint32)bitIndices[4]) << 8) | (((uint32)bitIndices[3]) << 0);\n\n\tuint8 pRed[16];\n\tfor (sint32 i = 0; i < 8; i++)\n\t{\n\t\tpRed[i] = (redRow0 >> (i * 3)) & 7;\n\t\tpRed[i + 8] = (redRow1 >> (i * 3)) & 7;\n\t}\n\n\tfloat* pixelOutput = rOutput;\n\tfor (sint32 py = 0; py < 4; py++)\n\t{\n\t\tfor (sint32 px = 0; px < 4; px++)\n\t\t{\n\t\t\tfloat c = red[pRed[px + py * 4]];\n\t\t\t*pixelOutput = c;\n\t\t\tpixelOutput++;\n\t\t}\n\t}\n}\n\nvoid decodeBC5Block_UNORM(uint8* blockStorage, float* rgOutput)\n{\n\tuint8* blockInput = (uint8*)blockStorage;\n\tfloat red[8];\n\tfloat green[8];\n\n\tred[0] = ((float)(*(uint8*)(blockInput + 0))) / 255.0f;\n\tred[1] = ((float)(*(uint8*)(blockInput + 1))) / 255.0f;\n\n\tif (red[0] > red[1])\n\t{\n\t\t// 6 interpolated color values\n\t\tred[2] = (6 * red[0] + 1 * red[1]) / 7.0f; // bit code 010\n\t\tred[3] = (5 * red[0] + 2 * red[1]) / 7.0f; // bit code 011\n\t\tred[4] = (4 * red[0] + 3 * red[1]) / 7.0f; // bit code 100\n\t\tred[5] = (3 * red[0] + 4 * red[1]) / 7.0f; // bit code 101\n\t\tred[6] = (2 * red[0] + 5 * red[1]) / 7.0f; // bit code 110\n\t\tred[7] = (1 * red[0] + 6 * red[1]) / 7.0f; // bit code 111\n\t}\n\telse\n\t{\n\t\t// 4 interpolated color values\n\t\tred[2] = (4 * red[0] + 1 * red[1]) / 5.0f; // bit code 010\n\t\tred[3] = (3 * red[0] + 2 * red[1]) / 5.0f; // bit code 011\n\t\tred[4] = (2 * red[0] + 3 * red[1]) / 5.0f; // bit code 100\n\t\tred[5] = (1 * red[0] + 4 * red[1]) / 5.0f; // bit code 101\n\t\tred[6] = 0.0f;                       // bit code 110\n\t\tred[7] = 1.0f;                       // bit code 111\n\t}\n\n\tgreen[0] = ((float)(*(uint8*)(blockInput + 8))) / 255.0f;\n\tgreen[1] = ((float)(*(uint8*)(blockInput + 9))) / 255.0f;\n\n\tif (green[0] > green[1])\n\t{\n\t\t// 6 interpolated color values\n\t\tgreen[2] = (6 * green[0] + 1 * green[1]) / 7.0f; // bit code 010\n\t\tgreen[3] = (5 * green[0] + 2 * green[1]) / 7.0f; // bit code 011\n\t\tgreen[4] = (4 * green[0] + 3 * green[1]) / 7.0f; // bit code 100\n\t\tgreen[5] = (3 * green[0] + 4 * green[1]) / 7.0f; // bit code 101\n\t\tgreen[6] = (2 * green[0] + 5 * green[1]) / 7.0f; // bit code 110\n\t\tgreen[7] = (1 * green[0] + 6 * green[1]) / 7.0f; // bit code 111\n\t}\n\telse\n\t{\n\t\t// 4 interpolated color values\n\t\tgreen[2] = (4 * green[0] + 1 * green[1]) / 5.0f; // bit code 010\n\t\tgreen[3] = (3 * green[0] + 2 * green[1]) / 5.0f; // bit code 011\n\t\tgreen[4] = (2 * green[0] + 3 * green[1]) / 5.0f; // bit code 100\n\t\tgreen[5] = (1 * green[0] + 4 * green[1]) / 5.0f; // bit code 101\n\t\tgreen[6] = 0.0f;\t\t\t\t\t\t   // bit code 110\n\t\tgreen[7] = 1.0f;                           // bit code 111\n\t}\n\n\n\tuint8* bitIndices = blockInput + 2;\n\tuint32 redRow0 = (((uint32)bitIndices[2]) << 16) | (((uint32)bitIndices[1]) << 8) | (((uint32)bitIndices[0]) << 0);\n\tuint32 redRow1 = (((uint32)bitIndices[5]) << 16) | (((uint32)bitIndices[4]) << 8) | (((uint32)bitIndices[3]) << 0);\n\tbitIndices = blockInput + 8 + 2;\n\tuint32 greenRow0 = (((uint32)bitIndices[2]) << 16) | (((uint32)bitIndices[1]) << 8) | (((uint32)bitIndices[0]) << 0);\n\tuint32 greenRow1 = (((uint32)bitIndices[5]) << 16) | (((uint32)bitIndices[4]) << 8) | (((uint32)bitIndices[3]) << 0);\n\n\tuint8 pRed[16];\n\tuint8 pGreen[16];\n\tfor (sint32 i = 0; i < 8; i++)\n\t{\n\t\tpRed[i] = (redRow0 >> (i * 3)) & 7;\n\t\tpRed[i + 8] = (redRow1 >> (i * 3)) & 7;\n\t\tpGreen[i] = (greenRow0 >> (i * 3)) & 7;\n\t\tpGreen[i + 8] = (greenRow1 >> (i * 3)) & 7;\n\t}\n\n\tfloat* pixelOutput = rgOutput;\n\tfor (sint32 py = 0; py < 4; py++)\n\t{\n\t\tfor (sint32 px = 0; px < 4; px++)\n\t\t{\n\t\t\tfloat c = red[pRed[px + py * 4]];\n\t\t\t*pixelOutput = c;\n\t\t\tpixelOutput++;\n\t\t\tc = green[pGreen[px + py * 4]];\n\t\t\t*pixelOutput = c;\n\t\t\tpixelOutput++;\n\t\t}\n\t}\n}\n\nvoid decodeBC5Block_SNORM(uint8* blockStorage, float* rgOutput) // todo - can merge this with the UNORM implementation by using a template?\n{\n\tuint8* blockInput = (uint8*)blockStorage;\n\tfloat red[8];\n\tfloat green[8];\n\n\tred[0] = ((float)(*(sint8*)(blockInput + 0)) + 128.0f) / 255.0f;\n\tred[1] = ((float)(*(sint8*)(blockInput + 1)) + 128.0f) / 255.0f;\n\tred[0] = (red[0] * 2.0f - 1.0f);\n\tred[1] = (red[1] * 2.0f - 1.0f);\n\n\tif (red[0] > red[1])\n\t{\n\t\t// 6 interpolated color values\n\t\tred[2] = (6 * red[0] + 1 * red[1]) / 7.0f; // bit code 010\n\t\tred[3] = (5 * red[0] + 2 * red[1]) / 7.0f; // bit code 011\n\t\tred[4] = (4 * red[0] + 3 * red[1]) / 7.0f; // bit code 100\n\t\tred[5] = (3 * red[0] + 4 * red[1]) / 7.0f; // bit code 101\n\t\tred[6] = (2 * red[0] + 5 * red[1]) / 7.0f; // bit code 110\n\t\tred[7] = (1 * red[0] + 6 * red[1]) / 7.0f; // bit code 111\n\t}\n\telse\n\t{\n\t\t// 4 interpolated color values\n\t\tred[2] = (4 * red[0] + 1 * red[1]) / 5.0f; // bit code 010\n\t\tred[3] = (3 * red[0] + 2 * red[1]) / 5.0f; // bit code 011\n\t\tred[4] = (2 * red[0] + 3 * red[1]) / 5.0f; // bit code 100\n\t\tred[5] = (1 * red[0] + 4 * red[1]) / 5.0f; // bit code 101\n\t\tred[6] = -1.0f;                       // bit code 110\n\t\tred[7] = 1.0f;                       // bit code 111\n\t}\n\n\tgreen[0] = ((float)(*(sint8*)(blockInput + 8)) + 128.0f) / 255.0f;\n\tgreen[1] = ((float)(*(sint8*)(blockInput + 9)) + 128.0f) / 255.0f;\n\tgreen[0] = (green[0] * 2.0f - 1.0f);\n\tgreen[1] = (green[1] * 2.0f - 1.0f);\n\n\tif (green[0] > green[1])\n\t{\n\t\t// 6 interpolated color values\n\t\tgreen[2] = (6 * green[0] + 1 * green[1]) / 7.0f; // bit code 010\n\t\tgreen[3] = (5 * green[0] + 2 * green[1]) / 7.0f; // bit code 011\n\t\tgreen[4] = (4 * green[0] + 3 * green[1]) / 7.0f; // bit code 100\n\t\tgreen[5] = (3 * green[0] + 4 * green[1]) / 7.0f; // bit code 101\n\t\tgreen[6] = (2 * green[0] + 5 * green[1]) / 7.0f; // bit code 110\n\t\tgreen[7] = (1 * green[0] + 6 * green[1]) / 7.0f; // bit code 111\n\t}\n\telse\n\t{\n\t\t// 4 interpolated color values\n\t\tgreen[2] = (4 * green[0] + 1 * green[1]) / 5.0f; // bit code 010\n\t\tgreen[3] = (3 * green[0] + 2 * green[1]) / 5.0f; // bit code 011\n\t\tgreen[4] = (2 * green[0] + 3 * green[1]) / 5.0f; // bit code 100\n\t\tgreen[5] = (1 * green[0] + 4 * green[1]) / 5.0f; // bit code 101\n\t\tgreen[6] = -1.0f;                       // bit code 110\n\t\tgreen[7] = 1.0f;                       // bit code 111\n\t}\n\n\n\tuint8* bitIndices = blockInput + 2;\n\tuint32 redRow0 = (((uint32)bitIndices[2]) << 16) | (((uint32)bitIndices[1]) << 8) | (((uint32)bitIndices[0]) << 0);\n\tuint32 redRow1 = (((uint32)bitIndices[5]) << 16) | (((uint32)bitIndices[4]) << 8) | (((uint32)bitIndices[3]) << 0);\n\tbitIndices = blockInput + 8 + 2;\n\tuint32 greenRow0 = (((uint32)bitIndices[2]) << 16) | (((uint32)bitIndices[1]) << 8) | (((uint32)bitIndices[0]) << 0);\n\tuint32 greenRow1 = (((uint32)bitIndices[5]) << 16) | (((uint32)bitIndices[4]) << 8) | (((uint32)bitIndices[3]) << 0);\n\n\tuint8 pRed[16];\n\tuint8 pGreen[16];\n\tfor (sint32 i = 0; i < 8; i++)\n\t{\n\t\tpRed[i] = (redRow0 >> (i * 3)) & 7;\n\t\tpRed[i + 8] = (redRow1 >> (i * 3)) & 7;\n\t\tpGreen[i] = (greenRow0 >> (i * 3)) & 7;\n\t\tpGreen[i + 8] = (greenRow1 >> (i * 3)) & 7;\n\t}\n\n\tfor (sint32 py = 0; py < 4; py++)\n\t{\n\t\tfloat* pixelOutput = rgOutput + (py * 4) * 2;\n\t\tfor (sint32 px = 0; px < 4; px++)\n\t\t{\n\t\t\tfloat c = red[pRed[px + py * 4]];\n\t\t\tpixelOutput[0] = c;\n\t\t\tc = green[pGreen[px + py * 4]];\n\t\t\tpixelOutput[1] = c;\n\t\t\tpixelOutput += 2;\n\t\t}\n\t}\n}\n\nvoid LatteTextureLoader_loadTextureDataIntoSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, sint32 mipLevels, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize)\n{\n\tif (mipIndex == 0)\n\t{\n\t\tcemu_assert_debug(width == hostTexture->width);\n\t\tcemu_assert_debug(height == hostTexture->height);\n\t\tcemu_assert_debug(depth == hostTexture->depth);\n\t}\n\tcemu_assert_debug(mipLevels == hostTexture->mipLevels);\n\tif (hostTexture->overwriteInfo.hasResolutionOverwrite || hostTexture->overwriteInfo.hasFormatOverwrite)\n\t{\n\t\t// todo - ideally, we should scale/convert the data to the new format and resolution\n\t\tg_renderer->texture_clearSlice(hostTexture, sliceIndex, mipIndex);\n\t}\n\telse\n\t{\n\t\tg_renderer->texture_loadSlice(hostTexture, width, height, depth, pixelData, sliceIndex, mipIndex, compressedImageSize);\n\t}\n}\n\nvoid LatteTextureLoader_UpdateTextureSliceData(LatteTexture* tex, uint32 sliceIndex, uint32 mipIndex, MPTR physImagePtr, MPTR physMipPtr, Latte::E_DIM dim, uint32 width, uint32 height, uint32 depth, uint32 mipLevels, uint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle, bool dumpTex)\n{\n\tLatteTextureLoaderCtx textureLoader = { 0 };\n\n\tLatte::E_GX2SURFFMT format = tex->format;\n\tLatteTextureLoader_begin(&textureLoader, sliceIndex, mipIndex, physImagePtr, physMipPtr, format, dim, width, height, depth, mipLevels, pitch, tileMode, swizzle);\n\n\t// enable texture dumping\n\ttextureLoader.dump = ActiveSettings::DumpTexturesEnabled();\n\tif (textureLoader.dump)\n\t{\n\t\tuint32 dumpSize = (((textureLoader.width + 4)&~4) * ((textureLoader.height + 4)&~4)) * 4;\n\t\ttextureLoader.dumpRGBA = (uint8*)malloc(dumpSize);\n\t\tmemset(textureLoader.dumpRGBA, 0x00, dumpSize);\n\t}\n\n\t// query texture decoder from renderer\n\tTextureDecoder* texDecoder = nullptr;\n\ttexDecoder = g_renderer->texture_chooseDecodedFormat(format, tex->isDepth, dim, width, height);\n\n\tif (tex->isDataDefined == false)\n\t{\n\t\ttex->AllocateOnHost();\n\t\ttex->isDataDefined = true;\n\t\t// if decoder is not set then clear texture\n\t\t// on Vulkan this is used to make sure the texture is no longer in UNDEFINED layout\n\t\tif (!texDecoder)\n\t\t{\n\t\t\tif(tex->isDepth)\n\t\t\t\tg_renderer->texture_clearDepthSlice(tex, 0, 0, true, tex->hasStencil, 0.0f, 0);\n\t\t\telse\n\t\t\t\tg_renderer->texture_clearColorSlice(tex, 0, 0, 0.0f, 0.0f, 0.0f, 0.0f);\n\t\t}\n\t}\n\n\tif (texDecoder == nullptr)\n\t\treturn;\n\n\ttextureLoader.decodedTexelCountX = texDecoder->getTexelCountX(&textureLoader);\n\ttextureLoader.decodedTexelCountY = texDecoder->getTexelCountY(&textureLoader);\n\n\t// allocate memory for decoded texture\n\tuint32 imageSize = texDecoder->calculateImageSize(&textureLoader);\n\n\tuint8* pixelData = (uint8*)g_renderer->texture_acquireTextureUploadBuffer(imageSize);\n\t// decode texture (if data is required)\n#ifdef BENCHMARK_TEXTURE_DECODING\n\tLARGE_INTEGER benchmark_begin;\n\tLARGE_INTEGER benchmark_end;\n\tLARGE_INTEGER benchmark_freq;\n\tQueryPerformanceCounter(&benchmark_begin);\n#endif\n\tif (tex->overwriteInfo.hasFormatOverwrite == false && tex->overwriteInfo.hasResolutionOverwrite == false)\n\t{\n\t\ttexDecoder->decode(&textureLoader, pixelData);\n\t}\n#ifdef BENCHMARK_TEXTURE_DECODING\n\tQueryPerformanceCounter(&benchmark_end);\n\tQueryPerformanceFrequency(&benchmark_freq);\n\tuint64 benchmarkResultMicroSeconds = (benchmark_end.QuadPart - benchmark_begin.QuadPart) * 1000000ULL / benchmark_freq.QuadPart;\n\ttextureDecodeBenchmark_perFormatSum[(int)tex->format & 0x3F] += benchmarkResultMicroSeconds;\n\ttextureDecodeBenchmark_totalSum += benchmarkResultMicroSeconds;\n\tcemuLog_log(LogType::Force, \"TexDecode {:04}x{:04}x{:04} Fmt {:04x} Dim {} TileMode {:02x} Took {:03}.{:03}ms Sum(format) {:06}ms Sum(total) {:06}ms\", textureLoader.width, textureLoader.height, textureLoader.surfaceInfoDepth, (int)tex->format, (int)tex->dim, textureLoader.tileMode, (uint32)(benchmarkResultMicroSeconds / 1000ULL), (uint32)(benchmarkResultMicroSeconds % 1000ULL), (uint32)(textureDecodeBenchmark_perFormatSum[tex->gx2Format & 0x3F] / 1000ULL), (uint32)(textureDecodeBenchmark_totalSum / 1000ULL));\n#endif\n\n\t// convert texture to RGBA when dumping is enabled\n\tif (textureLoader.dump)\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader.height; y++)\n\t\t{\n\t\t\tsint32 pixelOffset = (y * textureLoader.width) * 4;\n\t\t\tuint8* pixelOutput = textureLoader.dumpRGBA + pixelOffset;\n\t\t\tfor (sint32 x = 0; x < textureLoader.width; x++)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(&textureLoader, x, y);\n\t\t\t\ttexDecoder->decodePixelToRGBA(blockData, pixelOutput, x % textureLoader.stepX, y % textureLoader.stepY);\n\t\t\t\tpixelOutput += 4;\n\t\t\t}\n\t\t}\n\t}\n\n\t// update texture data offsets and hashes\n\t// this has to be done before the texture data is decoded & uploaded to prevent a race condition where updates during upload are missed\n\tif (mipIndex == 0 || (tex->texDataPtrLow == 0 && tex->texDataPtrHigh == 0))\n\t{\n\t\ttex->texDataPtrLow = physImagePtr + textureLoader.minOffsetOutdated; // always zero\n\t\ttex->texDataPtrHigh = physImagePtr + textureLoader.maxOffsetOutdated; // currently set to surface size\n\t\tLatteTC_ResetTextureChangeTracker(tex, true);\n\t}\n\t// load slice\n\t//debug_printf(\"[Load Slice] Addr: %08x MIP: %02d Slice: %02d Res %04x/%04x Texel Res %04x/%04x Fmt %04x Tm %d\\n\", textureLoader.physAddress, mipIndex, sliceIndex, textureLoader.width, textureLoader.height, textureLoader.texelCountX, textureLoader.texelCountY, (int)format, tileMode);\n\tLatteTextureLoader_loadTextureDataIntoSlice(tex, textureLoader.width, textureLoader.height, depth, mipLevels, pixelData, sliceIndex, mipIndex, imageSize);\n\t// write texture dump\n\tif (textureLoader.dump)\n\t{\n\t\tfs::path path = ActiveSettings::GetUserDataPath(\"dump/textures\");\n\t\tpath /= fmt::format(\"{:08x}_fmt{:04x}_slice{:d}_mip{:02d}_{:d}x{:d}_tm{:02d}.tga\", physImagePtr, (uint32)tex->format, sliceIndex, mipIndex, tex->width, tex->height, tileMode);\n\t\ttga_write_rgba(path, textureLoader.width, textureLoader.height, textureLoader.dumpRGBA);\n\t\tfree(textureLoader.dumpRGBA);\n\t}\n\t// clean up\n\tg_renderer->texture_releaseTextureUploadBuffer(pixelData);\n\tcatchOpenGLError();\n}\n\ntemplate<typename copyType>\nvoid optimizedLinearReadbackWriteLoop(LatteTextureLoaderCtx* textureLoader, uint8* linearPixelData)\n{\n\tuint32 pitch = textureLoader->width;\n\t// optimized for linear\n\tfor (sint32 y = 0; y < textureLoader->height; y++)\n\t{\n\t\tsint32 yc = y;\n\t\tsint32 pixelOffset = yc * pitch;\n\t\tcopyType* rowPixelData = (copyType*)(linearPixelData + pixelOffset * sizeof(copyType));\n\t\tcopyType* blockData = (copyType*)LatteTextureLoader_getInputLinearOptimized_(textureLoader, 0, y, 1, 1, sizeof(copyType) * 8, 0, 1, 0, textureLoader->pitch, textureLoader->height);\n\t\tif constexpr (sizeof(copyType) == 4)\n\t\t{\n\t\t\tmemcpy_dwords(blockData, rowPixelData, textureLoader->width);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x++)\n\t\t\t{\n\t\t\t\t*blockData = *rowPixelData;\n\t\t\t\trowPixelData++;\n\t\t\t\tblockData++;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid LatteTextureLoader_writeReadbackTextureToMemory(LatteTextureDefinition* textureData, uint32 sliceIndex, uint32 mipIndex, uint8* linearPixelData)\n{\n\tLatteTextureLoaderCtx textureLoader = { 0 };\n\tLatteTextureLoader_begin(&textureLoader, sliceIndex, mipIndex, textureData->physAddress, textureData->physMipAddress, textureData->format, textureData->dim, textureData->width, textureData->height, textureData->depth, textureData->mipLevels, textureData->pitch, textureData->tileMode, textureData->swizzle);\n\n#ifdef CEMU_DEBUG_ASSERT\n\tif (textureData->depth != 1)\n\t\tcemuLog_log(LogType::Force, \"_writeReadbackTextureToMemory(): Texture has multiple slices (not supported)\");\n#endif\n\tif (textureLoader.physAddress == MPTR_NULL)\n\t{\n\t\tcemuLog_log(LogType::Force, \"_writeReadbackTextureToMemory(): Texture has invalid address\");\n\t\treturn;\n\t}\n\n\tcemuLog_log(LogType::TextureReadback, \"[TextureReadback-Write] PhysAddr {:08x} Res {}x{} Fmt {} Slice {} Mip {}\", textureData->physAddress, textureData->width, textureData->height, textureData->format, sliceIndex, mipIndex);\n\n\tif (textureData->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED)\n\t{\n\t\tuint32 pitch = textureLoader.width;\n\t\tif (textureData->format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM ||\n\t\t\ttextureData->format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB)\n\t\t{\n\t\t\toptimizedLinearReadbackWriteLoop<uint32>(&textureLoader, linearPixelData);\n\t\t}\n\t\telse if (textureData->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM)\n\t\t{\n\t\t\toptimizedLinearReadbackWriteLoop<uint64>(&textureLoader, linearPixelData);\n\t\t}\n\t\telse if (textureData->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT)\n\t\t{\n\t\t\tfor (sint32 y = 0; y < textureLoader.height; y += textureLoader.stepY)\n\t\t\t{\n\t\t\t\tsint32 yc = y;\n\t\t\t\tsint32 pixelOffset = (0 + yc * pitch) * 16;\n\t\t\t\tfor (sint32 x = 0; x < textureLoader.width; x += textureLoader.stepX)\n\t\t\t\t{\n\t\t\t\t\tuint8* blockData = LatteTextureLoader_getInputLinearOptimized(&textureLoader, x, y);\n\t\t\t\t\t(*(uint32*)(blockData + 0)) = *(uint32*)(linearPixelData + pixelOffset + 0);\n\t\t\t\t\t(*(uint32*)(blockData + 4)) = *(uint32*)(linearPixelData + pixelOffset + 4);\n\t\t\t\t\t(*(uint32*)(blockData + 8)) = *(uint32*)(linearPixelData + pixelOffset + 8);\n\t\t\t\t\t(*(uint32*)(blockData + 12)) = *(uint32*)(linearPixelData + pixelOffset + 12);\n\t\t\t\t\tpixelOffset += 16;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (textureData->format == Latte::E_GX2SURFFMT::R32_FLOAT)\n\t\t{\n\t\t\tfor (sint32 y = 0; y < textureLoader.height; y += textureLoader.stepY)\n\t\t\t{\n\t\t\t\tsint32 yc = y;\n\t\t\t\tfor (sint32 x = 0; x < textureLoader.width; x += textureLoader.stepX)\n\t\t\t\t{\n\t\t\t\t\tuint8* blockData = LatteTextureLoader_getInputLinearOptimized(&textureLoader, x, y);\n\t\t\t\t\tsint32 pixelOffset = (x + yc * pitch) * 4;\n\t\t\t\t\t(*(uint32*)(blockData + 0)) = *(uint32*)(linearPixelData + pixelOffset + 0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (textureData->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT)\n\t\t{\n\t\t\tfor (sint32 y = 0; y < textureLoader.height; y += textureLoader.stepY)\n\t\t\t{\n\t\t\t\tsint32 yc = y;\n\t\t\t\tfor (sint32 x = 0; x < textureLoader.width; x += textureLoader.stepX)\n\t\t\t\t{\n\t\t\t\t\tuint8* blockData = LatteTextureLoader_getInputLinearOptimized(&textureLoader, x, y);\n\t\t\t\t\tsint32 pixelOffset = (x + yc * pitch) * 8;\n\t\t\t\t\t(*(uint32*)(blockData + 0)) = *(uint32*)(linearPixelData + pixelOffset + 0);\n\t\t\t\t\t(*(uint32*)(blockData + 4)) = *(uint32*)(linearPixelData + pixelOffset + 4);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (textureData->format == Latte::E_GX2SURFFMT::R8_G8_UNORM)\n\t\t{\n\t\t\toptimizedLinearReadbackWriteLoop<uint16>(&textureLoader, linearPixelData);\n\t\t}\n\t\telse if (textureData->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\telse if (textureData->format == Latte::E_GX2SURFFMT::R16_UNORM)\n\t\t{\n\t\t\toptimizedLinearReadbackWriteLoop<uint16>(&textureLoader, linearPixelData);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Linear texture readback unsupported for format 0x{:04x}\", (uint32)textureData->format);\n\t\t\tdebugBreakpoint();\n\t\t}\n\t\treturn;\n\t}\n\t// generic and slow decode loops\n\tLatte::E_HWSURFFMT hwFormat = Latte::GetHWFormat(textureData->format);\n\tif (hwFormat == Latte::E_HWSURFFMT::HWFMT_8_8_8_8)\n\t{\n\t\t// used in Bayonetta 2\n\t\tfor (sint32 y = 0; y < textureLoader.height; y++)\n\t\t{\n\t\t\tuint8* pixelInput = linearPixelData + (y * textureLoader.width) * 4;\n\t\t\tfor (sint32 x = 0; x < textureLoader.width; x++)\n\t\t\t{\n\t\t\t\tuint8* outputData = LatteTextureLoader_GetInput(&textureLoader, x, y);\n\t\t\t\t*(uint32*)(outputData + 0) = *(uint32*)pixelInput;\n\t\t\t\tpixelInput += 4;\n\t\t\t}\n\t\t}\n\t}\n\telse if (hwFormat == Latte::E_HWSURFFMT::HWFMT_32_FLOAT)\n\t{\n\t\t// required by Wind Waker for direct access to depth buffer\n\t\t// Bayonetta 2 also uses this but it converts the depth buffer to a color texture first\n\t\tfor (sint32 y = 0; y < textureLoader.height; y++)\n\t\t{\n\t\t\tuint8* pixelInput = linearPixelData + (y * textureLoader.width) * 4;\n\t\t\tfor (sint32 x = 0; x < textureLoader.width; x++)\n\t\t\t{\n\t\t\t\tuint8* outputData = LatteTextureLoader_GetInput(&textureLoader, x, y);\n\t\t\t\t*(uint32*)(outputData + 0) = *(uint32*)pixelInput;\n\t\t\t\tpixelInput += 4;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Texture readback unsupported format {:04x} for tileMode 0x{:02x}\", (uint32)textureData->format, textureData->tileMode);\n\t}\n\n}\n\nvoid LatteTextureLoader_estimateAccessedDataRange(LatteTexture* texture, sint32 sliceIndex, sint32 mipIndex, uint32& addrStart, uint32& addrEnd)\n{\n\tLatteTextureLoaderCtx textureLoader = { 0 };\n\tLatteTextureLoader_begin(&textureLoader, sliceIndex, mipIndex, texture->physAddress, texture->physMipAddress, texture->format, texture->dim, texture->width, texture->height, texture->depth, texture->mipLevels, texture->pitch, texture->tileMode, texture->swizzle);\n\n\tcemu_assert_debug(textureLoader.width > 0);\n\tcemu_assert_debug(textureLoader.height > 0);\n\n\t// estimate data range by checking addresses of corner pixels\n\t// this isn't very reliable, find a better solution\n\tuint32 estimatedMinAddr = 0xFFFFFFFF;\n\tuint32 estimatedMaxAddr = 0x00000000;\n\tuint32 tempAddr;\n\ttempAddr = memory_getVirtualOffsetFromPointer(LatteTextureLoader_GetInput(&textureLoader, 0, 0));\n\testimatedMinAddr = std::min(estimatedMinAddr, tempAddr);\n\testimatedMaxAddr = std::max(estimatedMaxAddr, tempAddr);\n\ttempAddr = memory_getVirtualOffsetFromPointer(LatteTextureLoader_GetInput(&textureLoader, textureLoader.width - 1, 0));\n\testimatedMinAddr = std::min(estimatedMinAddr, tempAddr);\n\testimatedMaxAddr = std::max(estimatedMaxAddr, tempAddr);\n\ttempAddr = memory_getVirtualOffsetFromPointer(LatteTextureLoader_GetInput(&textureLoader, 0, textureLoader.height - 1));\n\testimatedMinAddr = std::min(estimatedMinAddr, tempAddr);\n\testimatedMaxAddr = std::max(estimatedMaxAddr, tempAddr);\n\ttempAddr = memory_getVirtualOffsetFromPointer(LatteTextureLoader_GetInput(&textureLoader, textureLoader.width - 1, textureLoader.height - 1));\n\testimatedMinAddr = std::min(estimatedMinAddr, tempAddr);\n\testimatedMaxAddr = std::max(estimatedMaxAddr, tempAddr);\n\n\taddrStart = estimatedMinAddr;\n\taddrEnd = estimatedMaxAddr;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTextureLoader.h",
    "content": "#pragma once\n#include \"util/helpers/ClassWrapper.h\"\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n#include \"util/ImageWriter/tga.h\"\n\nstruct LatteTextureLoaderCtx\n{\n\tuint32 physAddress;\n\tuint32 physMipAddress;\n\tsint32 width;\n\tsint32 height;\n\tsint32 pitch; // stored elements per row\n\tuint32 mipLevels;\n\tuint32 sliceIndex;\n\tsint32 stepX;\n\tsint32 stepY;\n\tuint32 pipeSwizzle;\n\tuint32 bankSwizzle;\n\tLatte::E_HWTILEMODE tileMode;\n\tuint32 bpp;\n\tuint8* inputData;\n\tsint32 minOffsetOutdated;\n\tsint32 maxOffsetOutdated;\n\t// calculated info\n\tuint32 surfaceInfoHeight;\n\tuint32 surfaceInfoDepth;\n\t// mip\n\tuint32 levelOffset; // relative to physMipAddress\n\t// info for decoded texture\n\tsint32 decodedTexelCountX;\n\tsint32 decodedTexelCountY;\n\t// decoder\n\tLatteAddrLib::CachedSurfaceAddrInfo computeAddrInfo;\n\t// debug dump texture\n\tbool dump;\n\tuint8* dumpRGBA;\n};\n\nuint8* LatteTextureLoader_GetInput(LatteTextureLoaderCtx* textureLoader, sint32 x, sint32 y);\n\n#include \"Cafe/HW/Latte/LatteAddrLib/AddrLibFastDecode.h\"\n\nvoid decodeBC1Block(uint8* inputData, float* output4x4RGBA);\nvoid decodeBC2Block_UNORM(uint8* inputData, float* imageRGBA);\nvoid decodeBC3Block_UNORM(uint8* inputData, float* imageRGBA);\nvoid decodeBC4Block_UNORM(uint8* blockStorage, float* rOutput);\nvoid decodeBC5Block_UNORM(uint8* blockStorage, float* rgOutput);\nvoid decodeBC5Block_SNORM(uint8* blockStorage, float* rgOutput);\n\ninline void BC1_GetPixel(uint8* inputData, sint32 x, sint32 y, uint8 rgba[4])\n{\n\t// read colors\n\tuint16 c0 = *(uint16*)(inputData + 0);\n\tuint16 c1 = *(uint16*)(inputData + 2);\n\t// decode colors (RGB565 -> RGB888)\n\tfloat r[4];\n\tfloat g[4];\n\tfloat b[4];\n\tfloat a[4];\n\tb[0] = (float)((c0 >> 0) & 0x1F) / 31.0f;\n\tb[1] = (float)((c1 >> 0) & 0x1F) / 31.0f;\n\tg[0] = (float)((c0 >> 5) & 0x3F) / 63.0f;\n\tg[1] = (float)((c1 >> 5) & 0x3F) / 63.0f;\n\tr[0] = (float)((c0 >> 11) & 0x1F) / 31.0f;\n\tr[1] = (float)((c1 >> 11) & 0x1F) / 31.0f;\n\ta[0] = 1.0f;\n\ta[1] = 1.0f;\n\ta[2] = 1.0f;\n\n\tif (c0 > c1)\n\t{\n\t\tr[2] = (r[0] * 2.0f + r[1]) / 3.0f;\n\t\tr[3] = (r[0] * 1.0f + r[1] * 2.0f) / 3.0f;\n\t\tg[2] = (g[0] * 2.0f + g[1]) / 3.0f;\n\t\tg[3] = (g[0] * 1.0f + g[1] * 2.0f) / 3.0f;\n\t\tb[2] = (b[0] * 2.0f + b[1]) / 3.0f;\n\t\tb[3] = (b[0] * 1.0f + b[1] * 2.0f) / 3.0f;\n\t\ta[3] = 1.0f;\n\t}\n\telse\n\t{\n\t\tr[2] = (r[0] + r[1]) / 2.0f;\n\t\tr[3] = 0.0f;\n\t\tg[2] = (g[0] + g[1]) / 2.0f;\n\t\tg[3] = 0.0f;\n\t\tb[2] = (b[0] + b[1]) / 2.0f;\n\t\tb[3] = 0.0f;\n\t\ta[3] = 0.0f;\n\t}\n\n\tuint8* indexData = inputData + 4;\n\n\tuint8 i = (indexData[y] >> (x * 2)) & 3;\n\trgba[0] = (uint8)(r[i] * 255.0f);\n\trgba[1] = (uint8)(g[i] * 255.0f);\n\trgba[2] = (uint8)(b[i] * 255.0f);\n\trgba[3] = (uint8)(a[i] * 255.0f);\n}\n\n// decodes a specific GPU7 texture format into a native linear format that can be used by the render API\nclass TextureDecoder\n{\npublic:\n\t// properties\n\tvirtual sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) = 0;\n\tvirtual sint32 getTexelCountX(LatteTextureLoaderCtx* textureLoader)\n\t{\n\t\treturn textureLoader->width;\n\t}\n\n\tvirtual sint32 getTexelCountY(LatteTextureLoaderCtx* textureLoader)\n\t{\n\t\treturn textureLoader->height;\n\t}\n\n\t// image size\n\tvirtual sint32 calculateImageSize(LatteTextureLoaderCtx* textureLoader)\n\t{\n\t\treturn getTexelCountX(textureLoader) * getTexelCountY(textureLoader) * getBytesPerTexel(textureLoader);\n\t}\n\n\t// decode loop\n\tvirtual void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) = 0;\n\n\tvirtual void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) = 0;\n};\n\nclass TextureDecoder_R16_G16_B16_A16_FLOAT : public TextureDecoder, public SingletonClass<TextureDecoder_R16_G16_B16_A16_FLOAT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t// todo: dump 16 bit float formats properly\n\t\tfloat r16f = (float)(*((uint16*)blockData + 0));\n\t\tfloat g16f = (float)(*((uint16*)blockData + 1));\n\t\tfloat b16f = (float)(*((uint16*)blockData + 2));\n\t\tfloat a16f = (float)(*((uint16*)blockData + 3));\n\t\t*(outputPixel + 0) = (uint8)(r16f * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(g16f * 255.0f);\n\t\t*(outputPixel + 2) = (uint8)(b16f * 255.0f);\n\t\t*(outputPixel + 3) = (uint8)(a16f * 255.0f);\n\t}\n};\n\nclass TextureDecoder_R16_G16_FLOAT : public TextureDecoder, public SingletonClass<TextureDecoder_R16_G16_FLOAT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2 * 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint32, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t// todo: dump 16 bit float formats properly\n\t\tfloat r16f = (float)(*((uint16*)blockData + 0));\n\t\tfloat g16f = (float)(*((uint16*)blockData + 1));\n\t\t*(outputPixel + 0) = (uint8)(r16f * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(g16f * 255.0f);\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R16_SNORM : public TextureDecoder, public SingletonClass<TextureDecoder_R16_SNORM>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 1 * 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint16, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = (uint8)(*(((uint16*)blockData) + 0) >> 8) / 2 + 128;\n\t\t*(outputPixel + 1) = 0;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R16_FLOAT : public TextureDecoder, public SingletonClass<TextureDecoder_R16_FLOAT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 1 * 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint16, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t// todo: dump 16 bit float formats properly\n\t\tfloat r16f = (float)(*((uint16*)blockData + 0));\n\t\t*(outputPixel + 0) = (uint8)(r16f * 255.0f);\n\t\t*(outputPixel + 1) = 0;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R32_FLOAT : public TextureDecoder, public SingletonClass<TextureDecoder_R32_FLOAT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 1 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint32, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat r32f = *((float*)blockData + 0);\n\t\t*(outputPixel + 0) = (uint8)(r32f * 255.0f);\n\t\t*(outputPixel + 1) = 0;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R32_G32_FLOAT : public TextureDecoder, public SingletonClass<TextureDecoder_R32_G32_FLOAT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat r32f = *((float*)blockData + 0);\n\t\tfloat g32f = *((float*)blockData + 1);\n\t\t*(outputPixel + 0) = (uint8)(r32f * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(g32f * 255.0f);\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R32_G32_UINT : public TextureDecoder, public SingletonClass<TextureDecoder_R32_G32_UINT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = (uint8)(*(((uint32*)blockData) + 0) >> 24);\n\t\t*(outputPixel + 1) = (uint8)(*(((uint32*)blockData) + 1) >> 24);\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\n\nclass TextureDecoder_R32_UINT : public TextureDecoder, public SingletonClass<TextureDecoder_R32_UINT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 1 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint32, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = (uint8)(*(((uint32*)blockData) + 0) >> 24);\n\t\t*(outputPixel + 1) = 0;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R16_UINT : public TextureDecoder, public SingletonClass<TextureDecoder_R16_UINT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 1 * 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint16, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = (uint8)(*(((uint16*)blockData) + 0) >> 8);\n\t\t*(outputPixel + 1) = 0;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R8_UINT : public TextureDecoder, public SingletonClass<TextureDecoder_R8_UINT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 1;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint8, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = *(blockData + 0);\n\t\t*(outputPixel + 1) = 0;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R32_G32_B32_A32_FLOAT : public TextureDecoder, public SingletonClass<TextureDecoder_R32_G32_B32_A32_FLOAT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 2, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat r32f = *((float*)blockData + 0);\n\t\tfloat g32f = *((float*)blockData + 1);\n\t\tfloat b32f = *((float*)blockData + 2);\n\t\tfloat a32f = *((float*)blockData + 3);\n\t\t*(outputPixel + 0) = (uint8)(r32f * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(g32f * 255.0f);\n\t\t*(outputPixel + 2) = (uint8)(b32f * 255.0f);\n\t\t*(outputPixel + 3) = (uint8)(a32f * 255.0f);\n\t}\n};\n\nclass TextureDecoder_R32_G32_B32_A32_UINT : public TextureDecoder, public SingletonClass<TextureDecoder_R32_G32_B32_A32_UINT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\t// note - before 1.15.4 this format was implemented as big-endian\n\t\t//optimizedDecodeLoops<uint64, 2, false>(textureLoader, outputData);\n\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 4 * sizeof(uint32); // write to target buffer\n\t\t\t\t*(uint32*)(outputData + pixelOffset + 0) = _swapEndianU32(*(uint32*)(blockData + 0));\n\t\t\t\t*(uint32*)(outputData + pixelOffset + 4) = _swapEndianU32(*(uint32*)(blockData + 4));\n\t\t\t\t*(uint32*)(outputData + pixelOffset + 8) = _swapEndianU32(*(uint32*)(blockData + 8));\n\t\t\t\t*(uint32*)(outputData + pixelOffset + 12) = _swapEndianU32(*(uint32*)(blockData + 12));\n\t\t\t\t// todo: Verify if this format is big-endian\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = (uint8)(*(((uint32*)blockData) + 0) >> 24);\n\t\t*(outputPixel + 1) = (uint8)(*(((uint32*)blockData) + 1) >> 24);\n\t\t*(outputPixel + 2) = (uint8)(*(((uint32*)blockData) + 2) >> 24);\n\t\t*(outputPixel + 3) = (uint8)(*(((uint32*)blockData) + 3) >> 24);\n\t}\n};\n\nclass TextureDecoder_R16_G16_B16_A16_UINT : public TextureDecoder, public SingletonClass<TextureDecoder_R16_G16_B16_A16_UINT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\t// note - before 1.15.4 this format was implemented as big-endian\n\t\t//optimizedDecodeLoops<uint64, 1, false>(textureLoader, outputData);\n\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 4 * sizeof(uint16); // write to target buffer\n\t\t\t\t*(uint16*)(outputData + pixelOffset + 0) = _swapEndianU16(*(uint16*)(blockData + 0));\n\t\t\t\t*(uint16*)(outputData + pixelOffset + 2) = _swapEndianU16(*(uint16*)(blockData + 2));\n\t\t\t\t*(uint16*)(outputData + pixelOffset + 4) = _swapEndianU16(*(uint16*)(blockData + 4));\n\t\t\t\t*(uint16*)(outputData + pixelOffset + 6) = _swapEndianU16(*(uint16*)(blockData + 6));\n\t\t\t\t// todo: Verify if this format is big-endian\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = (uint8)(*(((uint16*)blockData) + 0) >> 8);\n\t\t*(outputPixel + 1) = (uint8)(*(((uint16*)blockData) + 1) >> 8);\n\t\t*(outputPixel + 2) = (uint8)(*(((uint16*)blockData) + 2) >> 8);\n\t\t*(outputPixel + 3) = (uint8)(*(((uint16*)blockData) + 3) >> 8);\n\t}\n};\n\n\nclass TextureDecoder_R8_G8_B8_A8_UINT : public TextureDecoder, public SingletonClass<TextureDecoder_R8_G8_B8_A8_UINT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 1;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint32, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = *(blockData + 0);\n\t\t*(outputPixel + 1) = *(blockData + 1);\n\t\t*(outputPixel + 2) = *(blockData + 2);\n\t\t*(outputPixel + 3) = *(blockData + 3);\n\t}\n};\n\nclass TextureDecoder_R24_X8 : public TextureDecoder, public SingletonClass<TextureDecoder_R24_X8>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 1 * sizeof(uint32);\n\t\t\t\t*(uint32*)(outputData + pixelOffset + 0) = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t}\n};\n\nclass TextureDecoder_X24_G8_UINT : public TextureDecoder, public SingletonClass<TextureDecoder_X24_G8_UINT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 1 * sizeof(uint32);\n\t\t\t\t*(uint32*)(outputData + pixelOffset + 0) = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t}\n};\n\nclass TextureDecoder_D32_S8_UINT_X24 : public TextureDecoder, public SingletonClass<TextureDecoder_D32_S8_UINT_X24>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 8;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t}\n};\n\nclass TextureDecoder_R4_G4_UNORM_To_RGBA4 : public TextureDecoder, public SingletonClass<TextureDecoder_R4_G4_UNORM_To_RGBA4>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 2;\n\t\t\t\tuint8 v = (*(uint8*)(blockData + 0));\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 0) = 0; // OpenGL has no RG4 format so we use RGBA4 instead and these two values (blue + alpha) are always set to zero\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 1) = ((v >> 4) & 0xF) | ((v << 4) & 0xF0); // todo: Is this nibble swap correct?\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint8 v0 = *(blockData + 0);\n\t\tuint8 c0 = (v0 & 0xF);\n\t\tuint8 c1 = (v0 >> 4) & 0xF;\n\t\tc0 = (c0 << 4) | c0;\n\t\tc1 = (c1 << 4) | c1;\n\t\t*(outputPixel + 0) = c0;\n\t\t*(outputPixel + 1) = c1;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R4_G4_UNORM_To_ABGR4 : public TextureDecoder, public SingletonClass<TextureDecoder_R4_G4_UNORM_To_ABGR4>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 2;\n\t\t\t\tuint8 v = (*(uint8*)(blockData + 0));\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 0) = 0;\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 1) = v;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint8 v0 = *(blockData + 0);\n\t\tuint8 c0 = (v0 & 0xF);\n\t\tuint8 c1 = (v0 >> 4) & 0xF;\n\t\tc0 = (c0 << 4) | c0;\n\t\tc1 = (c1 << 4) | c1;\n\t\t*(outputPixel + 0) = c0;\n\t\t*(outputPixel + 1) = c1;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R4G4_UNORM_To_RGBA8 : public TextureDecoder, public SingletonClass<TextureDecoder_R4G4_UNORM_To_RGBA8>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 4;\n\t\t\t\tuint8 v0 = (*(uint8*)(blockData + 0));\n\n\t\t\t\tuint8 red4 = (v0 >> 4) & 0xF;\n\t\t\t\tuint8 green4 = (v0 & 0xF);\n\n\t\t\t\tred4 = (red4 << 4) | red4;\n\t\t\t\tgreen4 = (green4 << 4) | green4;\n\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 0) = red4;\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 1) = green4;\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 2) = 0;\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 3) = 255;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint8 v0 = *(blockData + 0);\n\t\tuint8 red4 = (v0 >> 4) & 0xF;\n\t\tuint8 green4 = (v0 & 0xF);\n\t\tred4 = (red4 << 4) | red4;\n\t\tgreen4 = (green4 << 4) | green4;\n\t\t*(outputPixel + 0) = red4;\n\t\t*(outputPixel + 1) = green4;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R4G4_UNORM_To_RG8 : public TextureDecoder, public SingletonClass<TextureDecoder_R4G4_UNORM_To_RG8>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 2;\n\t\t\t\tuint8 v0 = (*(uint8*)(blockData + 0));\n\n\t\t\t\tuint8 red4 = (v0 >> 4) & 0xF;\n\t\t\t\tuint8 green4 = (v0 & 0xF);\n\n\t\t\t\tred4 = (red4 << 4) | red4;\n\t\t\t\tgreen4 = (green4 << 4) | green4;\n\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 0) = red4;\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 1) = green4;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint8 v0 = *(blockData + 0);\n\t\tuint8 red4 = (v0 >> 4) & 0xF;\n\t\tuint8 green4 = (v0 & 0xF);\n\t\tred4 = (red4 << 4) | red4;\n\t\tgreen4 = (green4 << 4) | green4;\n\t\t*(outputPixel + 0) = red4;\n\t\t*(outputPixel + 1) = green4;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R4_G4_B4_A4_UNORM : public TextureDecoder, public SingletonClass<TextureDecoder_R4_G4_B4_A4_UNORM>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 2;\n\t\t\t\tuint8 v0 = (*(uint8*)(blockData + 0));\n\t\t\t\tuint8 v1 = (*(uint8*)(blockData + 1));\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 0) = ((v1 >> 4) & 0xF) | ((v1 << 4) & 0xF0); // todo: Verify\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 1) = ((v0 >> 4) & 0xF) | ((v0 << 4) & 0xF0); // todo: Verify\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint8 v0 = *(blockData + 0);\n\t\tuint8 v1 = *(blockData + 1);\n\t\tuint8 c0 = (v0 & 0xF);\n\t\tuint8 c1 = (v0 >> 4) & 0xF;\n\t\tuint8 c2 = (v1 & 0xF);\n\t\tuint8 c3 = (v1 >> 4) & 0xF;\n\t\tc0 = (c0 << 4) | c0;\n\t\tc1 = (c1 << 4) | c1;\n\t\tc2 = (c2 << 4) | c2;\n\t\tc3 = (c3 << 4) | c3;\n\t\t*(outputPixel + 0) = c0;\n\t\t*(outputPixel + 1) = c1;\n\t\t*(outputPixel + 2) = c2;\n\t\t*(outputPixel + 3) = c3;\n\t}\n};\n\nclass TextureDecoder_R4G4B4A4_UNORM_To_RGBA8 : public TextureDecoder, public SingletonClass<TextureDecoder_R4G4B4A4_UNORM_To_RGBA8>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 4;\n\t\t\t\tuint8 v0 = (*(uint8*)(blockData + 0));\n\t\t\t\tuint8 v1 = (*(uint8*)(blockData + 1));\n\n\t\t\t\tuint8 red4 = (v0 & 0xF);\n\t\t\t\tuint8 green4 = (v0 >> 4) & 0xF;\n\t\t\t\tuint8 blue4 = (v1) & 0xF;\n\t\t\t\tuint8 alpha4 = (v1 >> 4) & 0xF;\n\n\t\t\t\tred4 = (red4 << 4) | red4;\n\t\t\t\tgreen4 = (green4 << 4) | green4;\n\t\t\t\tblue4 = (blue4 << 4) | blue4;\n\t\t\t\talpha4 = (alpha4 << 4) | alpha4;\n\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 0) = red4;\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 1) = green4;\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 2) = blue4;\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 3) = alpha4;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint8 v0 = *(blockData + 0);\n\t\tuint8 v1 = *(blockData + 1);\n\n\t\tuint8 red4 = (v0 & 0xF);\n\t\tuint8 green4 = (v0 >> 4) & 0xF;\n\t\tuint8 blue4 = (v1) & 0xF;\n\t\tuint8 alpha4 = (v1 >> 4) & 0xF;\n\n\t\tred4 = (red4 << 4) | red4;\n\t\tgreen4 = (green4 << 4) | green4;\n\t\tblue4 = (blue4 << 4) | blue4;\n\t\talpha4 = (alpha4 << 4) | alpha4;\n\n\t\t*(outputPixel + 0) = red4;\n\t\t*(outputPixel + 1) = green4;\n\t\t*(outputPixel + 2) = blue4;\n\t\t*(outputPixel + 3) = alpha4;\n\t}\n};\n\nclass TextureDecoder_R8_G8_B8_A8 : public TextureDecoder, public SingletonClass<TextureDecoder_R8_G8_B8_A8>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint32, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = *(blockData + 0);\n\t\t*(outputPixel + 1) = *(blockData + 1);\n\t\t*(outputPixel + 2) = *(blockData + 2);\n\t\t*(outputPixel + 3) = *(blockData + 3);\n\t}\n};\n\nclass TextureDecoder_D24_S8 : public TextureDecoder, public SingletonClass<TextureDecoder_D24_S8>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint32, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint32 d24 = (*(uint32*)blockData) & 0xFFFFFF;\n\t\tuint8 s8 = (*(uint32*)blockData >> 24) & 0xFF;\n\t\t*(outputPixel + 0) = (uint8)(d24 >> 16);\n\t\t*(outputPixel + 1) = (uint8)(d24 >> 16);\n\t\t*(outputPixel + 2) = (uint8)(d24 >> 16);\n\t\t*(outputPixel + 3) = s8;\n\t}\n};\n\nclass TextureDecoder_NullData32 : public TextureDecoder, public SingletonClass<TextureDecoder_NullData32>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tmemset(outputData, 0, sizeof(uint32) * getTexelCountX(textureLoader) * getTexelCountY(textureLoader));\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t}\n};\n\nclass TextureDecoder_NullData64 : public TextureDecoder, public SingletonClass<TextureDecoder_NullData64>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 8;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tmemset(outputData, 0, sizeof(uint64) * getTexelCountX(textureLoader) * getTexelCountY(textureLoader));\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t}\n};\n\nclass TextureDecoder_R8 : public TextureDecoder, public SingletonClass<TextureDecoder_R8>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 1;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint8, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = *(blockData + 0);\n\t\t*(outputPixel + 1) = 0;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R8_G8 : public TextureDecoder, public SingletonClass<TextureDecoder_R8_G8>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint16, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = *(blockData + 0);\n\t\t*(outputPixel + 1) = *(blockData + 1);\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R4_G4 : public TextureDecoder, public SingletonClass<TextureDecoder_R4_G4>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 1;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint8, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint8 v0 = (*(uint8*)(blockData + 0));\n\t\tuint8 c0 = (v0 & 0xF);\n\t\tuint8 c1 = (v0 >> 4) & 0xF;\n\t\tc0 = (c0 << 4) | c0;\n\t\tc1 = (c1 << 4) | c1;\n\t\t*(outputPixel + 0) = c0;\n\t\t*(outputPixel + 1) = c1;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R16_UNORM : public TextureDecoder, public SingletonClass<TextureDecoder_R16_UNORM>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint16, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = (uint8)(*(((uint16*)blockData) + 0) >> 8);\n\t\t*(outputPixel + 1) = 0;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R16_G16_B16_A16 : public TextureDecoder, public SingletonClass<TextureDecoder_R16_G16_B16_A16>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = (uint8)(*(((uint16*)blockData) + 0) >> 8);\n\t\t*(outputPixel + 1) = (uint8)(*(((uint16*)blockData) + 1) >> 8);\n\t\t*(outputPixel + 2) = (uint8)(*(((uint16*)blockData) + 2) >> 8);\n\t\t*(outputPixel + 3) = (uint8)(*(((uint16*)blockData) + 3) >> 8);\n\t}\n};\n\nclass TextureDecoder_R16_G16 : public TextureDecoder, public SingletonClass<TextureDecoder_R16_G16>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2 * 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint32, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t*(outputPixel + 0) = (uint8)(*(((uint16*)blockData) + 0) >> 8);\n\t\t*(outputPixel + 1) = (uint8)(*(((uint16*)blockData) + 1) >> 8);\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R5_G6_B5 : public TextureDecoder, public SingletonClass<TextureDecoder_R5_G6_B5>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint16, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint16 colorData = (*(uint16*)blockData);\n\t\tuint8 red5 = (colorData >> 0) & 0x1F;\n\t\tuint8 green6 = (colorData >> 5) & 0x3F;\n\t\tuint8 blue5 = (colorData >> 11) & 0x1F;\n\t\t*(outputPixel + 0) = (red5 << 3) | (red5 >> 2);\n\t\t*(outputPixel + 1) = (green6 << 2) | (green6 >> 4);\n\t\t*(outputPixel + 2) = (blue5 << 3) | (blue5 >> 2);\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R5_G6_B5_swappedRB : public TextureDecoder, public SingletonClass<TextureDecoder_R5_G6_B5_swappedRB>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 2;\n\t\t\t\tuint16 colorData = (*(uint16*)(blockData + 0));\n\n\t\t\t\t// colorData >> 0 -> red\n\t\t\t\t// colorData >> 5 -> green\n\t\t\t\t// colorData >> 11 -> blue\n\n\t\t\t\tcolorData = ((colorData >> 11) & 0x1F) | (colorData & (0x3F << 5)) | ((colorData << 11) & (0x1F << 11));\n\n\t\t\t\t//// swap order of components\n\t\t\t\t////uint8 red5 = (colorData>>0)&0x1F;\n\t\t\t\t////uint8 green5 = (colorData>>5)&0x1F;\n\t\t\t\t////uint8 blue5 = (colorData>>10)&0x1F;\n\t\t\t\t////uint8 alpha1 = (colorData>>15)&0x1;\n\t\t\t\t////colorData = blue5|(green5<<5)|(red5<<10)|(alpha1<<15);\n\t\t\t\t////*(uint16*)(outputData+pixelOffset+0) = colorData;\n\t\t\t\t//uint8 red5 = (colorData >> 11) & 0x1F;\n\t\t\t\t//uint8 green5 = (colorData >> 6) & 0x1F;\n\t\t\t\t//uint8 blue5 = (colorData >> 1) & 0x1F;\n\t\t\t\t//uint8 alpha1 = (colorData >> 0) & 0x1;\n\t\t\t\t////colorData = blue5|(green5<<5)|(red5<<10)|(alpha1<<15);\n\t\t\t\t////colorData = (blue5<<11)|(green5<<6)|(red5<<1)|(alpha1<<0);\n\t\t\t\t* (uint16*)(outputData + pixelOffset + 0) = colorData;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint16 colorData = (*(uint16*)blockData);\n\t\tuint8 red5 = (colorData >> 0) & 0x1F;\n\t\tuint8 green6 = (colorData >> 5) & 0x3F;\n\t\tuint8 blue5 = (colorData >> 11) & 0x1F;\n\t\t*(outputPixel + 0) = (red5 << 3) | (red5 >> 2);\n\t\t*(outputPixel + 1) = (green6 << 2) | (green6 >> 4);\n\t\t*(outputPixel + 2) = (blue5 << 3) | (blue5 >> 2);\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_R5G6B5_UNORM_To_RGBA8 : public TextureDecoder, public SingletonClass<TextureDecoder_R5G6B5_UNORM_To_RGBA8>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 4;\n\t\t\t\tuint16 v0 = (*(uint16*)(blockData + 0));\n\n\t\t\t\tuint8 c0 = (v0 & 0x1F);\n\t\t\t\tuint8 c1 = (v0 >> 5) & 0x3F;\n\t\t\t\tuint8 c2 = (v0 >> 11) & 0x1F;\n\n\t\t\t\tc0 = (c0 << 3) | c0 >> 3;// blue\n\t\t\t\tc1 = (c1 << 2) | c1 >> 4;// green\n\t\t\t\tc2 = (c2 << 3) | c2 >> 3;// red\n\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 0) = c0;// blue\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 1) = c1;// green\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 2) = c2;// red\n\t\t\t\t*(uint8*)(outputData + pixelOffset + 3) = 255;//alpha\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint16 v0 = *(uint16*)(blockData + 0);\n\t\tuint8 c0 = (v0 & 0x1F);// red\n\t\tuint8 c1 = (v0 >> 5) & 0x3F;// green\n\t\tuint8 c2 = (v0 >> 11) & 0x1F; // blue\n\t\tc0 = (c0 << 3) | c0 >> 3;\n\t\tc1 = (c1 << 2) | c1 >> 4;\n\t\tc2 = (c2 << 3) | c2 >> 3;\n\t\t*(outputPixel + 0) = c0;// red\n\t\t*(outputPixel + 1) = c1;// green\n\t\t*(outputPixel + 2) = c2;// blue\n\t\t*(outputPixel + 3) = 255;// alpha\n\t}\n};\n\nclass TextureDecoder_R5_G5_B5_A1_UNORM : public TextureDecoder, public SingletonClass<TextureDecoder_R5_G5_B5_A1_UNORM>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint16, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint16 colorData = (*(uint16*)blockData);\n\t\tuint8 red5 = (colorData >> 0) & 0x1F;\n\t\tuint8 green5 = (colorData >> 5) & 0x1F;\n\t\tuint8 blue5 = (colorData >> 10) & 0x1F;\n\t\tuint8 alpha1 = (colorData >> 11) & 0x1;\n\t\t*(outputPixel + 0) = (red5 << 3) | (red5 >> 2);\n\t\t*(outputPixel + 1) = (green5 << 3) | (green5 >> 2);\n\t\t*(outputPixel + 2) = (blue5 << 3) | (blue5 >> 2);\n\t\t*(outputPixel + 3) = (alpha1 << 3);\n\t}\n};\n\nclass uint16_R5_G5_B5_A1_swapRB\n{\npublic:\n\tvoid operator=(const uint16_R5_G5_B5_A1_swapRB& v)\n\t{\n\t\tinternalVal = ((v.internalVal >> 10) & (0x1F << 0)) | ((v.internalVal << 10) & (0x1F << 10)) | (v.internalVal & ((0x1F << 5) | 0x8000));\n\t}\n\n\tuint16 internalVal;\n};\n\nstatic_assert(sizeof(uint16_R5_G5_B5_A1_swapRB) == 2);\n\nclass TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB : public TextureDecoder, public SingletonClass<TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint16_R5_G5_B5_A1_swapRB, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint16 colorData = (*(uint16*)blockData);\n\t\tuint8 red5 = (colorData >> 0) & 0x1F;\n\t\tuint8 green5 = (colorData >> 5) & 0x1F;\n\t\tuint8 blue5 = (colorData >> 10) & 0x1F;\n\t\tuint8 alpha1 = (colorData >> 11) & 0x1;\n\t\t*(outputPixel + 0) = (red5 << 3) | (red5 >> 2);\n\t\t*(outputPixel + 1) = (green5 << 3) | (green5 >> 2);\n\t\t*(outputPixel + 2) = (blue5 << 3) | (blue5 >> 2);\n\t\t*(outputPixel + 3) = (alpha1 << 3);\n\t}\n};\n\nclass TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB_To_RGBA8 : public TextureDecoder, public SingletonClass<TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB_To_RGBA8>\n{\npublic:\n//2656\n    sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n    {\n        return 4;\n    }\n\n    void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n    {\n        for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n        {\n            sint32 yc = y;\n            for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n            {\n                uint16* blockData = (uint16*)LatteTextureLoader_GetInput(textureLoader, x, y);\n                sint32 pixelOffset = (x + yc * textureLoader->width) * 4;\n                uint32 colorData = (*(uint16*)(blockData + 0));\n                // swap order of components\n                uint8 red = (colorData >> 0) & 0x1F;\n                uint8 green = (colorData >> 5) & 0x1F;\n                uint8 blue = (colorData >> 10) & 0x1F;\n                uint8 alpha = (colorData >> 15) & 0x1;\n\n                red = red << 3 | red >> 2;\n                green = green << 3 | green >> 2;\n                blue = blue << 3 | blue >> 2;\n                alpha = alpha * 0xff;\n\n                // MSB...LSB : ABGR\n                colorData = (alpha << 24) | (blue << 16) | (green << 8) | red;\n                *(uint32*)(outputData + pixelOffset + 0) = colorData;\n            }\n        }\n    }\n\n    void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n    {\n        uint16 colorData = (*(uint16*)blockData);\n        uint8 red = (colorData >> 0) & 0x1F;\n        uint8 green = (colorData >> 5) & 0x1F;\n        uint8 blue = (colorData >> 10) & 0x1F;\n        uint8 alpha = (colorData >> 15) & 0x1;\n        *(outputPixel + 0) = (red << 3) | (red >> 2);\n        *(outputPixel + 1) = (green << 3) | (green >> 2);\n        *(outputPixel + 2) = (blue << 3) | (blue >> 2);\n        *(outputPixel + 3) = alpha * 0xff;\n    }\n\n};\n\nclass uint16_R5_G5_B5_A1_swapOpenGL\n{\npublic:\n\tvoid operator=(const uint16_R5_G5_B5_A1_swapOpenGL& v)\n\t{\n\t\tuint16 red = (v.internalVal >> 0) & 0x1F;\n\t\tuint16 green = (v.internalVal >> 5) & 0x1F;\n\t\tuint16 blue = (v.internalVal >> 10) & 0x1F;\n\t\tuint16 alpha = (v.internalVal >> 15) & 0x1;\n\t\tinternalVal = (red << 11) | (green << 6) | (blue << 1) | alpha;\n\t}\n\tuint16 internalVal;\n};\n\nstatic_assert(sizeof(uint16_R5_G5_B5_A1_swapOpenGL) == 2);\n\nclass TextureDecoder_R5_G5_B5_A1_UNORM_swappedOpenGL : public TextureDecoder, public SingletonClass<TextureDecoder_R5_G5_B5_A1_UNORM_swappedOpenGL>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint16_R5_G5_B5_A1_swapOpenGL, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint16 colorData = (*(uint16*)blockData);\n\t\tuint8 red5 = (colorData >> 0) & 0x1F;\n\t\tuint8 green5 = (colorData >> 5) & 0x1F;\n\t\tuint8 blue5 = (colorData >> 10) & 0x1F;\n\t\tuint8 alpha1 = (colorData >> 11) & 0x1;\n\t\t*(outputPixel + 0) = (red5 << 3) | (red5 >> 2);\n\t\t*(outputPixel + 1) = (green5 << 3) | (green5 >> 2);\n\t\t*(outputPixel + 2) = (blue5 << 3) | (blue5 >> 2);\n\t\t*(outputPixel + 3) = (alpha1 << 3);\n\t}\n};\n\nclass TextureDecoder_A1_B5_G5_R5_UNORM : public TextureDecoder, public SingletonClass<TextureDecoder_A1_B5_G5_R5_UNORM>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint16, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint16 colorData = (*(uint16*)blockData);\n\t\tuint8 red5 = (colorData >> 11) & 0x1F;\n\t\tuint8 green5 = (colorData >> 6) & 0x1F;\n\t\tuint8 blue5 = (colorData >> 1) & 0x1F;\n\t\tuint8 alpha1 = (colorData >> 0) & 0x1;\n\t\t*(outputPixel + 0) = (red5 << 3) | (red5 >> 2);\n\t\t*(outputPixel + 1) = (green5 << 3) | (green5 >> 2);\n\t\t*(outputPixel + 2) = (blue5 << 3) | (blue5 >> 2);\n\t\t*(outputPixel + 3) = (alpha1 << 3);\n\t}\n};\n\nclass TextureDecoder_A1_B5_G5_R5_UNORM_vulkan : public TextureDecoder, public SingletonClass<TextureDecoder_A1_B5_G5_R5_UNORM_vulkan>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 pixelOffset = (x + yc * textureLoader->width) * 2;\n\t\t\t\tuint16 colorData = (*(uint16*)(blockData + 0));\n\t\t\t\t// swap order of components\n\t\t\t\tuint8 red5 = (colorData >> 11) & 0x1F;\n\t\t\t\tuint8 green5 = (colorData >> 6) & 0x1F;\n\t\t\t\tuint8 blue5 = (colorData >> 1) & 0x1F;\n\t\t\t\tuint8 alpha1 = (colorData >> 0) & 0x1;\n\t\t\t\tcolorData = blue5 | (green5 << 5) | (red5 << 10) | (alpha1 << 15);\n\t\t\t\t*(uint16*)(outputData + pixelOffset + 0) = colorData;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint16 colorData = (*(uint16*)blockData);\n\t\tuint8 red5 = (colorData >> 11) & 0x1F;\n\t\tuint8 green5 = (colorData >> 6) & 0x1F;\n\t\tuint8 blue5 = (colorData >> 1) & 0x1F;\n\t\tuint8 alpha1 = (colorData >> 0) & 0x1;\n\t\t*(outputPixel + 0) = (red5 << 3) | (red5 >> 2);\n\t\t*(outputPixel + 1) = (green5 << 3) | (green5 >> 2);\n\t\t*(outputPixel + 2) = (blue5 << 3) | (blue5 >> 2);\n\t\t*(outputPixel + 3) = (alpha1 << 3);\n\t}\n};\n\nclass TextureDecoder_A1_B5_G5_R5_UNORM_vulkan_To_RGBA8 : public TextureDecoder, public SingletonClass<TextureDecoder_A1_B5_G5_R5_UNORM_vulkan_To_RGBA8>\n{\npublic:\n    sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n    {\n        return 4;\n    }\n\n    void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n    {\n        for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n        {\n            sint32 yc = y;\n            for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n            {\n                uint16* blockData = (uint16*)LatteTextureLoader_GetInput(textureLoader, x, y);\n                sint32 pixelOffset = (x + yc * textureLoader->width) * 4;\n                uint32 colorData = (*(uint16*)(blockData + 0));\n                // swap order of components\n                uint8 red = (colorData >> 11) & 0x1F;\n                uint8 green = (colorData >> 6) & 0x1F;\n                uint8 blue = (colorData >> 1) & 0x1F;\n                uint8 alpha = (colorData >> 0) & 0x1;\n\n                red = red << 3 | red >> 2;\n                green = green << 3 | green >> 2;\n                blue = blue << 3 | blue >> 2;\n                alpha = alpha * 0xff;\n\n                // MSB...LSB ABGR\n                colorData = red | (green << 8) | (blue << 16) | (alpha << 24);\n                *(uint32*)(outputData + pixelOffset + 0) = colorData;\n            }\n        }\n    }\n\n    void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n    {\n        uint16 colorData = (*(uint16*)blockData);\n        uint8 red5 = (colorData >> 11) & 0x1F;\n        uint8 green5 = (colorData >> 6) & 0x1F;\n        uint8 blue5 = (colorData >> 1) & 0x1F;\n        uint8 alpha1 = (colorData >> 0) & 0x1;\n        *(outputPixel + 0) = (red5 << 3) | (red5 >> 2);\n        *(outputPixel + 1) = (green5 << 3) | (green5 >> 2);\n        *(outputPixel + 2) = (blue5 << 3) | (blue5 >> 2);\n        *(outputPixel + 3) = (alpha1 << 3);\n    }\n};\n\n\nclass TextureDecoder_R10_G10_B10_A2_UNORM : public TextureDecoder, public SingletonClass<TextureDecoder_R10_G10_B10_A2_UNORM>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint32, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint16 r10 = ((*(uint32*)blockData) >> 0) & 0x3FF;\n\t\tuint16 g10 = ((*(uint32*)blockData) >> 10) & 0x3FF;\n\t\tuint16 b10 = ((*(uint32*)blockData) >> 20) & 0x3FF;\n\t\tuint8 a2 = ((*(uint32*)blockData) >> 30) & 0x3;\n\t\t*(outputPixel + 0) = (uint8)(r10 >> 6);\n\t\t*(outputPixel + 1) = (uint8)(g10 >> 6);\n\t\t*(outputPixel + 2) = (uint8)(b10 >> 6);\n\t\t*(outputPixel + 3) = a2;\n\t}\n};\n\nclass TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16 : public TextureDecoder, public SingletonClass<TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\t// todo - implement\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tsint32 pixelOffset = (yc * textureLoader->width) * (2 * 4);\n\t\t\tsint16* pixelOutput = (sint16*)(outputData + pixelOffset);\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tuint32 v = (*(uint32*)(blockData + 0));\n\t\t\t\t*pixelOutput = 0;\n\t\t\t\tpixelOffset++;\n\t\t\t\t*pixelOutput = 0;\n\t\t\t\tpixelOffset++;\n\t\t\t\t*pixelOutput = 0;\n\t\t\t\tpixelOffset++;\n\t\t\t\t*pixelOutput = 0;\n\t\t\t\tpixelOffset++;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint16 r10 = ((*(uint32*)blockData) >> 0) & 0x3FF;\n\t\tuint16 g10 = ((*(uint32*)blockData) >> 10) & 0x3FF;\n\t\tuint16 b10 = ((*(uint32*)blockData) >> 20) & 0x3FF;\n\t\tuint8 a2 = ((*(uint32*)blockData) >> 30) & 0x3;\n\t\t*(outputPixel + 0) = (uint8)(r10 >> 6) / 2 + 128;\n\t\t*(outputPixel + 1) = (uint8)(g10 >> 6) / 2 + 128;\n\t\t*(outputPixel + 2) = (uint8)(b10 >> 6) / 2 + 128;\n\t\t*(outputPixel + 3) = a2 / 2 + 128;\n\t}\n};\n\nclass TextureDecoder_A2_B10_G10_R10_UNORM_To_RGBA16 : public TextureDecoder, public SingletonClass<TextureDecoder_A2_B10_G10_R10_UNORM_To_RGBA16>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 2;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\t// todo - implement\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 yc = y;\n\t\t\tsint32 pixelOffset = (yc * textureLoader->width) * (2 * 4);\n\t\t\tsint16* pixelOutput = (sint16*)(outputData + pixelOffset);\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tuint32 v = (*(uint32*)(blockData + 0));\n\t\t\t\t*pixelOutput = 0;\n\t\t\t\tpixelOffset++;\n\t\t\t\t*pixelOutput = 0;\n\t\t\t\tpixelOffset++;\n\t\t\t\t*pixelOutput = 0;\n\t\t\t\tpixelOffset++;\n\t\t\t\t*pixelOutput = 0;\n\t\t\t\tpixelOffset++;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tuint8 a2 = ((*(uint32*)blockData) >> 0) & 0x3;\n\t\tuint16 r10 = ((*(uint32*)blockData) >> 2) & 0x3FF;\n\t\tuint16 g10 = ((*(uint32*)blockData) >> 12) & 0x3FF;\n\t\tuint16 b10 = ((*(uint32*)blockData) >> 22) & 0x3FF;\n\t\t*(outputPixel + 0) = (uint8)(r10 >> 6);\n\t\t*(outputPixel + 1) = (uint8)(g10 >> 6);\n\t\t*(outputPixel + 2) = (uint8)(b10 >> 6);\n\t\t*(outputPixel + 3) = a2;\n\t}\n};\n\nclass TextureDecoder_R11_G11_B10_FLOAT : public TextureDecoder, public SingletonClass<TextureDecoder_R11_G11_B10_FLOAT>\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint32, 1, false, false>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t// todo: add dumping support\n\t}\n};\n\nclass TextureDecoder_BC1_UNORM_uncompress_generic : public TextureDecoder\n{\npublic:\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 blockSizeX = (std::min)(4, textureLoader->width - x);\n\t\t\t\tsint32 blockSizeY = (std::min)(4, textureLoader->height - y);\n\t\t\t\t// decode 4x4 pixels at once\n\t\t\t\tfloat rgbaBlock[4 * 4 * 4];\n\t\t\t\tdecodeBC1Block(blockData, rgbaBlock);\n\t\t\t\tfor (sint32 py = 0; py < blockSizeY; py++)\n\t\t\t\t{\n\t\t\t\t\tsint32 yc = y + py;\n\t\t\t\t\tfor (sint32 px = 0; px < blockSizeX; px++)\n\t\t\t\t\t{\n\t\t\t\t\t\tsint32 pixelOffset = (x + px + yc * textureLoader->width) * 16; // write to target buffer\n\t\t\t\t\t\tfloat red = rgbaBlock[(px + py * 4) * 4 + 0];\n\t\t\t\t\t\tfloat green = rgbaBlock[(px + py * 4) * 4 + 1];\n\t\t\t\t\t\tfloat blue = rgbaBlock[(px + py * 4) * 4 + 2];\n\t\t\t\t\t\tfloat alpha = rgbaBlock[(px + py * 4) * 4 + 3];\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 0) = red;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 4) = green;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 8) = blue;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 12) = alpha;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tBC1_GetPixel(blockData, blockOffsetX, blockOffsetY, outputPixel);\n\t}\n};\n\nclass TextureDecoder_BC1_UNORM_uncompress : public TextureDecoder_BC1_UNORM_uncompress_generic, public SingletonClass<TextureDecoder_BC1_UNORM_uncompress>\n{\n\t// reuse TextureDecoder_BC1_UNORM_uncompress_generic\n};\n\nclass TextureDecoder_BC1_SRGB_uncompress : public TextureDecoder_BC1_UNORM_uncompress_generic, public SingletonClass<TextureDecoder_BC1_SRGB_uncompress>\n{\n\t// reuse TextureDecoder_BC1_UNORM_uncompress_generic\n};\n\nclass TextureDecoder_BC1 : public TextureDecoder, public SingletonClass<TextureDecoder_BC1>\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 8;\n\t}\n\n\tsint32 getTexelCountX(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn (textureLoader->width + 3) / 4;\n\t}\n\n\tsint32 getTexelCountY(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn (textureLoader->height + 3) / 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 1, false, true>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tBC1_GetPixel(blockData, blockOffsetX, blockOffsetY, outputPixel);\n\t}\n};\n\nclass TextureDecoder_BC2 : public TextureDecoder, public SingletonClass<TextureDecoder_BC2>\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 4;\n\t}\n\n\tsint32 getTexelCountX(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn (textureLoader->width + 3) / 4;\n\t}\n\n\tsint32 getTexelCountY(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn (textureLoader->height + 3) / 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 2, false, true>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat rgbaBlock[4 * 4 * 4];\n\t\tdecodeBC2Block_UNORM(blockData, rgbaBlock);\n\t\tfloat red = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 0];\n\t\tfloat green = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 1];\n\t\tfloat blue = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 2];\n\t\tfloat alpha = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 3];\n\t\t*(outputPixel + 0) = (uint8)(red * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(green * 255.0f);\n\t\t*(outputPixel + 2) = (uint8)(blue * 255.0f);\n\t\t*(outputPixel + 3) = (uint8)(alpha * 255.0f);\n\t}\n};\n\nclass TextureDecoder_BC2_UNORM_uncompress : public TextureDecoder, public SingletonClass<TextureDecoder_BC2_UNORM_uncompress>\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 blockSizeX = (std::min)(4, textureLoader->width - x);\n\t\t\t\tsint32 blockSizeY = (std::min)(4, textureLoader->height - y);\n\t\t\t\t// decode 4x4 pixels at once\n\t\t\t\tfloat rgbaBlock[4 * 4 * 4];\n\t\t\t\tdecodeBC2Block_UNORM(blockData, rgbaBlock);\n\t\t\t\tfor (sint32 py = 0; py < blockSizeY; py++)\n\t\t\t\t{\n\t\t\t\t\tsint32 yc = y + py;\n\t\t\t\t\tfor (sint32 px = 0; px < blockSizeX; px++)\n\t\t\t\t\t{\n\t\t\t\t\t\tsint32 pixelOffset = (x + px + yc * textureLoader->width) * 16; // write to target buffer\n\t\t\t\t\t\tfloat red = rgbaBlock[(px + py * 4) * 4 + 0];\n\t\t\t\t\t\tfloat green = rgbaBlock[(px + py * 4) * 4 + 1];\n\t\t\t\t\t\tfloat blue = rgbaBlock[(px + py * 4) * 4 + 2];\n\t\t\t\t\t\tfloat alpha = rgbaBlock[(px + py * 4) * 4 + 3];\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 0) = red;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 4) = green;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 8) = blue;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 12) = alpha;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat rgbaBlock[4 * 4 * 4];\n\t\tdecodeBC2Block_UNORM(blockData, rgbaBlock);\n\t\tfloat red = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 0];\n\t\tfloat green = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 1];\n\t\tfloat blue = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 2];\n\t\tfloat alpha = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 3];\n\t\t*(outputPixel + 0) = (uint8)(red * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(green * 255.0f);\n\t\t*(outputPixel + 2) = (uint8)(blue * 255.0f);\n\t\t*(outputPixel + 3) = (uint8)(alpha * 255.0f);\n\t}\n};\n\nclass TextureDecoder_BC2_SRGB_uncompress : public TextureDecoder, public SingletonClass<TextureDecoder_BC2_SRGB_uncompress>\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\t// todo - apply srgb conversion\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 blockSizeX = (std::min)(4, textureLoader->width - x);\n\t\t\t\tsint32 blockSizeY = (std::min)(4, textureLoader->height - y);\n\t\t\t\t// decode 4x4 pixels at once\n\t\t\t\tfloat rgbaBlock[4 * 4 * 4];\n\t\t\t\tdecodeBC2Block_UNORM(blockData, rgbaBlock);\n\t\t\t\tfor (sint32 py = 0; py < blockSizeY; py++)\n\t\t\t\t{\n\t\t\t\t\tsint32 yc = y + py;\n\t\t\t\t\tfor (sint32 px = 0; px < blockSizeX; px++)\n\t\t\t\t\t{\n\t\t\t\t\t\tsint32 pixelOffset = (x + px + yc * textureLoader->width) * 16; // write to target buffer\n\t\t\t\t\t\tfloat red = rgbaBlock[(px + py * 4) * 4 + 0];\n\t\t\t\t\t\tfloat green = rgbaBlock[(px + py * 4) * 4 + 1];\n\t\t\t\t\t\tfloat blue = rgbaBlock[(px + py * 4) * 4 + 2];\n\t\t\t\t\t\tfloat alpha = rgbaBlock[(px + py * 4) * 4 + 3];\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 0) = red;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 4) = green;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 8) = blue;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 12) = alpha;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t// todo - apply srgb conversion\n\t\tfloat rgbaBlock[4 * 4 * 4];\n\t\tdecodeBC2Block_UNORM(blockData, rgbaBlock);\n\t\tfloat red = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 0];\n\t\tfloat green = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 1];\n\t\tfloat blue = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 2];\n\t\tfloat alpha = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 3];\n\t\t*(outputPixel + 0) = (uint8)(red * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(green * 255.0f);\n\t\t*(outputPixel + 2) = (uint8)(blue * 255.0f);\n\t\t*(outputPixel + 3) = (uint8)(alpha * 255.0f);\n\t}\n};\n\nclass TextureDecoder_BC3_uncompress_generic : public TextureDecoder\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 4 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 blockSizeX = (std::min)(4, textureLoader->width - x);\n\t\t\t\tsint32 blockSizeY = (std::min)(4, textureLoader->height - y);\n\t\t\t\t// decode 4x4 pixels at once\n\t\t\t\tfloat rgbaBlock[4 * 4 * 4];\n\t\t\t\tdecodeBC3Block_UNORM(blockData, rgbaBlock);\n\t\t\t\tfor (sint32 py = 0; py < blockSizeY; py++)\n\t\t\t\t{\n\t\t\t\t\tsint32 yc = y + py;\n\t\t\t\t\tfor (sint32 px = 0; px < blockSizeX; px++)\n\t\t\t\t\t{\n\t\t\t\t\t\tsint32 pixelOffset = (x + px + yc * textureLoader->width) * 16; // write to target buffer\n\t\t\t\t\t\tfloat red = rgbaBlock[(px + py * 4) * 4 + 0];\n\t\t\t\t\t\tfloat green = rgbaBlock[(px + py * 4) * 4 + 1];\n\t\t\t\t\t\tfloat blue = rgbaBlock[(px + py * 4) * 4 + 2];\n\t\t\t\t\t\tfloat alpha = rgbaBlock[(px + py * 4) * 4 + 3];\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 0) = red;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 4) = green;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 8) = blue;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 12) = alpha;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat rgbaBlock[4 * 4 * 4];\n\t\tdecodeBC3Block_UNORM(blockData, rgbaBlock);\n\t\tfloat red = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 0];\n\t\tfloat green = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 1];\n\t\tfloat blue = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 2];\n\t\tfloat alpha = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 3];\n\t\t*(outputPixel + 0) = (uint8)(red * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(green * 255.0f);\n\t\t*(outputPixel + 2) = (uint8)(blue * 255.0f);\n\t\t*(outputPixel + 3) = (uint8)(alpha * 255.0f);\n\t}\n};\n\nclass TextureDecoder_BC3_UNORM_uncompress : public TextureDecoder_BC3_uncompress_generic, public SingletonClass<TextureDecoder_BC3_UNORM_uncompress>\n{\n\t// reuse TextureDecoder_BC3_uncompress_generic\n};\n\nclass TextureDecoder_BC3_SRGB_uncompress : public TextureDecoder_BC3_uncompress_generic, public SingletonClass<TextureDecoder_BC3_SRGB_uncompress>\n{\n\t// reuse TextureDecoder_BC3_uncompress_generic\n};\n\nclass TextureDecoder_BC3 : public TextureDecoder, public SingletonClass<TextureDecoder_BC3>\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 16;\n\t}\n\n\tsint32 getTexelCountX(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn (textureLoader->width + 3) / 4;\n\t}\n\n\tsint32 getTexelCountY(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn (textureLoader->height + 3) / 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 2, false, true>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat rgbaBlock[4 * 4 * 4];\n\t\tdecodeBC3Block_UNORM(blockData, rgbaBlock);\n\t\tfloat red = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 0];\n\t\tfloat green = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 1];\n\t\tfloat blue = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 2];\n\t\tfloat alpha = rgbaBlock[(blockOffsetX + blockOffsetY * 4) * 4 + 3];\n\t\t*(outputPixel + 0) = (uint8)(red * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(green * 255.0f);\n\t\t*(outputPixel + 2) = (uint8)(blue * 255.0f);\n\t\t*(outputPixel + 3) = (uint8)(alpha * 255.0f);\n\t}\n};\n\nclass TextureDecoder_BC4_UNORM_uncompress : public TextureDecoder, public SingletonClass<TextureDecoder_BC4_UNORM_uncompress>\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 blockSizeX = (std::min)(4, textureLoader->width - x);\n\t\t\t\tsint32 blockSizeY = (std::min)(4, textureLoader->height - y);\n\t\t\t\t// decode 4x4 pixels at once\n\t\t\t\tfloat rBlock[4 * 4 * 1];\n\t\t\t\tdecodeBC4Block_UNORM(blockData, rBlock);\n\n\t\t\t\tfor (sint32 py = 0; py < blockSizeY; py++)\n\t\t\t\t{\n\t\t\t\t\tsint32 yc = y + py;\n\t\t\t\t\tfor (sint32 px = 0; px < blockSizeX; px++)\n\t\t\t\t\t{\n\t\t\t\t\t\tsint32 pixelOffset = (x + px + yc * textureLoader->width) * 8; // write to target buffer\n\t\t\t\t\t\tfloat red = rBlock[(px + py * 4) * 1 + 0];\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 0) = red;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 4) = 0.0f;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat rBlock[4 * 4 * 1];\n\t\tdecodeBC4Block_UNORM(blockData, rBlock);\n\t\tfloat red = rBlock[(blockOffsetX + blockOffsetY * 4) * 1 + 0];\n\t\t*(outputPixel + 0) = (uint8)(red * 255.0f);\n\t\t*(outputPixel + 1) = 0;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_BC4 : public TextureDecoder, public SingletonClass<TextureDecoder_BC4>\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 8;\n\t}\n\n\tsint32 getTexelCountX(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn (textureLoader->width + 3) / 4;\n\t}\n\n\tsint32 getTexelCountY(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn (textureLoader->height + 3) / 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 1, false, true>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat rBlock[4 * 4 * 1];\n\t\tdecodeBC4Block_UNORM(blockData, rBlock);\n\t\tfloat red = rBlock[(blockOffsetX + blockOffsetY * 4) * 1 + 0];\n\t\t*(outputPixel + 0) = (uint8)(red * 255.0f);\n\t\t*(outputPixel + 1) = 0;\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_BC5_UNORM_uncompress : public TextureDecoder, public SingletonClass<TextureDecoder_BC5_UNORM_uncompress>\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 blockSizeX = (std::min)(4, textureLoader->width - x);\n\t\t\t\tsint32 blockSizeY = (std::min)(4, textureLoader->height - y);\n\t\t\t\t// decode 4x4 pixels at once\n\t\t\t\tfloat rgBlock[4 * 4 * 2];\n\t\t\t\tdecodeBC5Block_UNORM(blockData, rgBlock);\n\n\t\t\t\tfor (sint32 py = 0; py < blockSizeY; py++)\n\t\t\t\t{\n\t\t\t\t\tsint32 yc = y + py;\n\t\t\t\t\tfor (sint32 px = 0; px < blockSizeX; px++)\n\t\t\t\t\t{\n\t\t\t\t\t\tsint32 pixelOffset = (x + px + yc * textureLoader->width) * 8; // write to target buffer\n\t\t\t\t\t\tfloat red = rgBlock[(px + py * 4) * 2 + 0];\n\t\t\t\t\t\tfloat green = rgBlock[(px + py * 4) * 2 + 1];\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 0) = red;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 4) = green;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat rgBlock[4 * 4 * 2];\n\t\tdecodeBC5Block_UNORM(blockData, rgBlock);\n\t\tfloat red = rgBlock[(blockOffsetX + blockOffsetY * 4) * 2 + 0];\n\t\tfloat green = rgBlock[(blockOffsetX + blockOffsetY * 4) * 2 + 1];\n\t\t*(outputPixel + 0) = (uint8)(red * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(green * 255.0f);\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_BC5_SNORM_uncompress : public TextureDecoder, public SingletonClass<TextureDecoder_BC5_SNORM_uncompress>\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 2 * 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\tsint32 blockSizeX = (std::min)(4, textureLoader->width - x);\n\t\t\t\tsint32 blockSizeY = (std::min)(4, textureLoader->height - y);\n\t\t\t\t// decode 4x4 pixels at once\n\t\t\t\tfloat rgBlock[4 * 4 * 2];\n\t\t\t\tdecodeBC5Block_SNORM(blockData, rgBlock);\n\n\t\t\t\tfor (sint32 py = 0; py < blockSizeY; py++)\n\t\t\t\t{\n\t\t\t\t\tsint32 yc = y + py;\n\t\t\t\t\tfor (sint32 px = 0; px < blockSizeX; px++)\n\t\t\t\t\t{\n\t\t\t\t\t\tsint32 pixelOffset = (x + px + yc * textureLoader->width) * 8; // write to target buffer\n\t\t\t\t\t\tfloat red = rgBlock[(px + py * 4) * 2 + 0];\n\t\t\t\t\t\tfloat green = rgBlock[(px + py * 4) * 2 + 1];\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 0) = red;\n\t\t\t\t\t\t*(float*)(outputData + pixelOffset + 4) = green;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\t// todo: fix BC5 SNORM dumping\n\t\tfloat rgBlock[4 * 4 * 2];\n\t\tdecodeBC5Block_SNORM(blockData, rgBlock);\n\t\tfloat red = rgBlock[(blockOffsetX + blockOffsetY * 4) * 2 + 0];\n\t\tfloat green = rgBlock[(blockOffsetX + blockOffsetY * 4) * 2 + 1];\n\t\t*(outputPixel + 0) = (uint8)((0.5f + red * 0.5f) * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)((0.5f + green * 0.5f) * 255.0f);\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n\nclass TextureDecoder_BC5 : public TextureDecoder, public SingletonClass<TextureDecoder_BC5>\n{\npublic:\n\n\tsint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn 16;\n\t}\n\n\tsint32 getTexelCountX(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn (textureLoader->width + 3) / 4;\n\t}\n\n\tsint32 getTexelCountY(LatteTextureLoaderCtx* textureLoader) override\n\t{\n\t\treturn (textureLoader->height + 3) / 4;\n\t}\n\n\tvoid decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override\n\t{\n\t\toptimizedDecodeLoops<uint64, 2, false, true>(textureLoader, outputData);\n\t}\n\n\tvoid decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override\n\t{\n\t\tfloat rgBlock[4 * 4 * 2];\n\t\tdecodeBC5Block_UNORM(blockData, rgBlock);\n\t\tfloat red = rgBlock[(blockOffsetX + blockOffsetY * 4) * 2 + 0];\n\t\tfloat green = rgBlock[(blockOffsetX + blockOffsetY * 4) * 2 + 1];\n\t\t*(outputPixel + 0) = (uint8)(red * 255.0f);\n\t\t*(outputPixel + 1) = (uint8)(green * 255.0f);\n\t\t*(outputPixel + 2) = 0;\n\t\t*(outputPixel + 3) = 255;\n\t}\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTextureReadback.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n\n#include \"Common/GLInclude/GLInclude.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h\"\n\n#define LOG_READBACK_TIME\n\nstruct LatteTextureReadbackQueueEntry\n{\n\tHRTick initiateTime;\n\tuint32 lastUpdateDrawcallIndex;\n\tLatteTextureView* textureView;\n};\n\nstd::vector<LatteTextureReadbackQueueEntry> sTextureScheduledReadbacks; // readbacks that have been queued but the actual transfer has not yet been started\nstd::queue<LatteTextureReadbackInfo*> sTextureActiveReadbackQueue; // readbacks in flight\n\nvoid LatteTextureReadback_StartTransfer(LatteTextureView* textureView)\n{\n\tcemuLog_log(LogType::TextureReadback, \"[TextureReadback-Start] PhysAddr {:08x} Res {}x{} Fmt {} Slice {} Mip {}\", textureView->baseTexture->physAddress, textureView->baseTexture->width, textureView->baseTexture->height, textureView->baseTexture->format, textureView->firstSlice, textureView->firstMip);\n\tHRTick currentTick = HighResolutionTimer().now().getTick();\n\t// create info entry and store in ordered linked list\n\tLatteTextureReadbackInfo* readbackInfo = g_renderer->texture_createReadback(textureView);\n\tsTextureActiveReadbackQueue.push(readbackInfo);\n\treadbackInfo->StartTransfer();\n\treadbackInfo->transferStartTime = currentTick;\n}\n\n/*\n * Checks for queued transfers and starts them if at least five drawcalls have passed since the last write\n * Called after a draw sequence is completed\n * Returns true if at least one transfer was started\n */\nbool LatteTextureReadback_Update(bool forceStart)\n{\n\tbool hasStartedTransfer = false;\n\tfor (size_t i = 0; i < sTextureScheduledReadbacks.size(); i++)\n\t{\n\t\tLatteTextureReadbackQueueEntry& entry = sTextureScheduledReadbacks[i];\n\t\tuint32 numElapsedDrawcalls = LatteGPUState.drawCallCounter - entry.lastUpdateDrawcallIndex;\n\t\tif (forceStart || numElapsedDrawcalls >= 5)\n\t\t{\n#ifdef LOG_READBACK_TIME\n\t\t\tdouble elapsedSecondsSinceInitiate = HighResolutionTimer::getTimeDiff(entry.initiateTime, HighResolutionTimer().now().getTick());\n\t\t\tcemuLog_log(LogType::TextureReadback, \"[TextureReadback-Update] Starting transfer for {:08x} after {} elapsed drawcalls. Time since initiate: {:.4} Force-start: {}\", entry.textureView->baseTexture->physAddress, numElapsedDrawcalls, elapsedSecondsSinceInitiate, forceStart?\"yes\":\"no\");\n#endif\n\t\t\tLatteTextureReadback_StartTransfer(entry.textureView);\n\t\t\t// remove element\n\t\t\tvectorRemoveByIndex(sTextureScheduledReadbacks, i);\n\t\t\ti--;\n\t\t\thasStartedTransfer = true;\n\t\t}\n\t}\n\treturn hasStartedTransfer;\n}\n\n/*\n * Called when a texture is deleted\n */\nvoid LatteTextureReadback_NotifyTextureDeletion(LatteTexture* texture)\n{\n\t// delete from queue\n\tfor (size_t i = 0; i < sTextureScheduledReadbacks.size(); i++)\n\t{\n\t\tLatteTextureReadbackQueueEntry& entry = sTextureScheduledReadbacks[i];\n\t\tif (entry.textureView->baseTexture == texture)\n\t\t{\n\t\t\tvectorRemoveByIndex(sTextureScheduledReadbacks, i);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid LatteTextureReadback_Initate(LatteTextureView* textureView)\n{\n\t// currently we don't support readback for resized textures\n\tif (textureView->baseTexture->overwriteInfo.hasResolutionOverwrite)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Texture readback is not supported for textures with modified resolution. Texture: {:08x} {}x{}\", textureView->baseTexture->physAddress, textureView->baseTexture->width, textureView->baseTexture->height);\n\t\treturn;\n\t}\n\t// check if texture isn't already queued for transfer\n\tfor (size_t i = 0; i < sTextureScheduledReadbacks.size(); i++)\n\t{\n\t\tLatteTextureReadbackQueueEntry& entry = sTextureScheduledReadbacks[i];\n\t\tif (entry.textureView == textureView)\n\t\t{\n\t\t\tentry.lastUpdateDrawcallIndex = LatteGPUState.drawCallCounter;\n\t\t\treturn;\n\t\t}\n\t}\n\t// queue\n\tLatteTextureReadbackQueueEntry queueEntry;\n\tqueueEntry.initiateTime = HighResolutionTimer().now().getTick();\n\tqueueEntry.textureView = textureView;\n\tqueueEntry.lastUpdateDrawcallIndex = LatteGPUState.drawCallCounter;\n\tsTextureScheduledReadbacks.emplace_back(queueEntry);\n}\n\nvoid LatteTextureReadback_UpdateFinishedTransfers(bool forceFinish)\n{\n\tif (forceFinish)\n\t{\n\t\t// start any delayed transfers\n\t\tLatteTextureReadback_Update(true);\n\t}\n\tperformanceMonitor.gpuTime_waitForAsync.beginMeasuring();\n\twhile (!sTextureActiveReadbackQueue.empty())\n\t{\n\t\tLatteTextureReadbackInfo* readbackInfo = sTextureActiveReadbackQueue.front();\n\t\tif (forceFinish)\n\t\t{\n\t\t\tif (!readbackInfo->IsFinished())\n\t\t\t{\n\t\t\t\treadbackInfo->waitStartTime = HighResolutionTimer().now().getTick();\n#ifdef LOG_READBACK_TIME\n\t\t\t\tif (cemuLog_isLoggingEnabled(LogType::TextureReadback))\n\t\t\t\t{\n\t\t\t\t\tdouble elapsedSecondsTransfer = HighResolutionTimer::getTimeDiff(readbackInfo->transferStartTime, HighResolutionTimer().now().getTick());\n\t\t\t\t\tcemuLog_log(LogType::TextureReadback, \"[Texture-Readback] Force-finish: {:08x} Res {:}/{:} TM {:} FMT {:04x} Transfer time so far: {:.4}ms\", readbackInfo->hostTextureCopy.physAddress, readbackInfo->hostTextureCopy.width, readbackInfo->hostTextureCopy.height, readbackInfo->hostTextureCopy.tileMode, (uint32)readbackInfo->hostTextureCopy.format, elapsedSecondsTransfer * 1000.0);\n\t\t\t\t}\n#endif\n\t\t\t\treadbackInfo->forceFinish = true;\n\t\t\t\treadbackInfo->ForceFinish();\n\t\t\t\t// rerun logic since ->ForceFinish() can recurively call this function and thus modify the queue\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!readbackInfo->IsFinished())\n\t\t\t\tbreak;\n\t\t\treadbackInfo->waitStartTime = HighResolutionTimer().now().getTick();\n\t\t}\n\t\t// performance testing\n#ifdef LOG_READBACK_TIME\n\t\tif (cemuLog_isLoggingEnabled(LogType::TextureReadback))\n\t\t{\n\t\t\tHRTick currentTick = HighResolutionTimer().now().getTick();\n\t\t\tdouble elapsedSecondsTransfer = HighResolutionTimer::getTimeDiff(readbackInfo->transferStartTime, currentTick);\n\t\t\tdouble elapsedSecondsWaiting = HighResolutionTimer::getTimeDiff(readbackInfo->waitStartTime, currentTick);\n\t\t\tcemuLog_log(LogType::TextureReadback, \"[Texture-Readback] {:08x} Res {}/{} TM {} FMT {:04x} ReadbackLatency: {:6.3}ms WaitTime: {:6.3}ms ForcedWait {}\", readbackInfo->hostTextureCopy.physAddress, readbackInfo->hostTextureCopy.width, readbackInfo->hostTextureCopy.height, readbackInfo->hostTextureCopy.tileMode, (uint32)readbackInfo->hostTextureCopy.format, elapsedSecondsTransfer * 1000.0, elapsedSecondsWaiting * 1000.0, readbackInfo->forceFinish ? \"yes\" : \"no\");\n\t\t}\n#endif\n\t\tuint8* pixelData = readbackInfo->GetData();\n\t\tLatteTextureLoader_writeReadbackTextureToMemory(&readbackInfo->hostTextureCopy, 0, 0, pixelData);\n\t\treadbackInfo->ReleaseData();\n\t\t// get the original texture if it still exists and invalidate the current data hash\n\t\tLatteTextureView* origTexView = LatteTextureViewLookupCache::lookupSlice(readbackInfo->hostTextureCopy.physAddress, readbackInfo->hostTextureCopy.width, readbackInfo->hostTextureCopy.height, readbackInfo->hostTextureCopy.pitch, 0, 0, readbackInfo->hostTextureCopy.format);\n\t\tif (origTexView)\n\t\t\tLatteTC_ResetTextureChangeTracker(origTexView->baseTexture, true);\n\t\tdelete readbackInfo;\n\t\t// remove from queue\n\t\tcemu_assert_debug(!sTextureActiveReadbackQueue.empty());\n\t\tcemu_assert_debug(readbackInfo == sTextureActiveReadbackQueue.front());\n\t\tsTextureActiveReadbackQueue.pop();\n\t}\n\tperformanceMonitor.gpuTime_waitForAsync.endMeasuring();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTextureReadbackInfo.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n\nclass LatteTextureReadbackInfo\n{\npublic:\n\tLatteTextureReadbackInfo(LatteTextureView* textureView)\n\t\t: hostTextureCopy(textureView->baseTexture), m_textureView(textureView)\n\t{}\n\n\tvirtual ~LatteTextureReadbackInfo() = default;\n\n\tvirtual void StartTransfer() = 0;\n\tvirtual bool IsFinished() = 0;\n\tvirtual void ForceFinish() {};\n\n\tvirtual uint8* GetData() = 0;\n\tvirtual void ReleaseData() {};\n\n\tHRTick transferStartTime;\n\tHRTick waitStartTime;\n\tbool forceFinish{ false }; // set to true if not finished in time for dependent operation\n\t// texture info\n\tLatteTextureDefinition hostTextureCopy{};\n\nprotected:\n\tLatteTextureView* m_textureView;\n\tuint32 m_image_size = 0;\n};"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTextureView.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"Cafe/HW/Latte/Core/LatteTextureView.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n\nLatteTextureView::LatteTextureView(LatteTexture* texture, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, bool registerView)\n{\n\tthis->baseTexture = texture;\n\tthis->firstMip = firstMip;\n\tthis->numMip = mipCount;\n\tthis->firstSlice = firstSlice;\n\tthis->numSlice = sliceCount;\n\tthis->dim = dim;\n\tthis->format = format;\n\tif (registerView)\n\t{\n\t\ttexture->views.emplace_back(this);\n\t\tLatteTextureViewLookupCache::Add(this);\n\t}\n}\n\nLatteTextureView::~LatteTextureView()\n{\n\t// unregister view\n\tLatteTextureViewLookupCache::RemoveAll(this);\n\t// remove from texture\n\tvectorRemoveByValue(baseTexture->views, this);\n\tif (baseTexture->baseView == this)\n\t\tbaseTexture->baseView = nullptr;\n\t// delete all associated FBOs\n\twhile (!list_associatedFbo.empty())\n\t\tLatteMRT::DeleteCachedFBO(list_associatedFbo[0]);\n}\n\nvoid LatteTextureView::CreateLookupForSubTexture(uint32 mipStart, uint32 sliceStart)\n{\n\tcemu_assert_debug(mipStart != 0 || sliceStart != 0); // This function should never be called with both parameters zero. Every view creates a base lookup on construction\n\tLatteTextureViewLookupCache::Add(this, mipStart, sliceStart);\n}\n\n/* View lookup cache */\n\nstruct LatteTexViewLookupDesc\n{\n\tLatteTexViewLookupDesc(LatteTextureView* view) : view(view)\n\t{\n\t\tthis->physAddr = view->baseTexture->physAddress;\n\t\tthis->physMipAddr = view->baseTexture->physMipAddress;\n\t\tthis->width = view->baseTexture->width;\n\t\tthis->height = view->baseTexture->height;\n\t\tthis->pitch = view->baseTexture->pitch;\n\t\tthis->firstMip = view->firstMip;\n\t\tthis->numMip = view->numMip;\n\t\tthis->firstSlice = view->firstSlice;\n\t\tthis->numSlice = view->numSlice;\n\t\tthis->format = view->format;\n\t\tthis->dim = view->dim;\n\t\tthis->isDepth = view->baseTexture->isDepth;\n\t}\n\n\tvoid SetParametersForSubTexture(sint32 baseMip, sint32 baseSlice)\n\t{\n\t\tcemu_assert_debug(baseMip >= 0);\n\t\tcemu_assert_debug(baseSlice >= 0);\n\t\tLatteTextureSliceMipInfo* sliceMipInfo = view->baseTexture->GetSliceMipArrayEntry(baseSlice, baseMip);\n\t\tphysAddr = sliceMipInfo->addrStart;\n\t\tpitch = sliceMipInfo->pitch;\n\t\tcemu_assert_debug(format == view->baseTexture->format); // if the format is different then width/height calculation might differ. This only affects the case where an integer format is mapped onto a compressed format or vice versa.\n\t\twidth = view->baseTexture->GetMipWidth(baseMip);\n\t\theight = view->baseTexture->GetMipHeight(baseMip);\n\t\t// adjust firstMip and firstSlice to be relative to base of subtexture\n\t\tcemu_assert(firstMip >= baseMip);\n\t\tcemu_assert(firstSlice >= baseSlice);\n\t\tfirstMip -= baseMip;\n\t\tfirstSlice -= baseSlice;\n\t}\n\n\t// key data for looking up views\n\tMPTR physAddr;\n\tMPTR physMipAddr;\n\tsint32 width;\n\tsint32 height;\n\tsint32 pitch;\n\tsint32 firstMip;\n\tsint32 numMip;\n\tsint32 firstSlice;\n\tsint32 numSlice;\n\tLatte::E_GX2SURFFMT format;\n\tLatte::E_DIM dim;\n\tbool isDepth;\n\t// associated view\n\tLatteTextureView* view;\n};\n\nstruct LatteTexViewBucket\n{\n\tstd::vector<LatteTexViewLookupDesc> list;\n};\n\n#define TEXTURE_VIEW_BUCKETS\t(1061)\n\ninline uint32 _getViewBucketKey(MPTR physAddress, uint32 width, uint32 height, uint32 pitch)\n{\n\treturn (physAddress + width * 7 + height * 11 + pitch * 13) % TEXTURE_VIEW_BUCKETS;\n}\n\ninline uint32 _getViewBucketKeyNoRes(MPTR physAddress, uint32 pitch)\n{\n\treturn (physAddress + pitch * 13) % TEXTURE_VIEW_BUCKETS;\n}\n\nLatteTexViewBucket texViewBucket[TEXTURE_VIEW_BUCKETS] = { };\nLatteTexViewBucket texViewBucket_nores[TEXTURE_VIEW_BUCKETS] = { };\n\nvoid LatteTextureViewLookupCache::Add(LatteTextureView* view, uint32 baseMip, uint32 baseSlice)\n{\n\tLatteTexViewLookupDesc desc(view);\n\tif (baseMip != 0 || baseSlice != 0)\n\t\tdesc.SetParametersForSubTexture(baseMip, baseSlice);\n\t// generic bucket\n\tuint32 key = _getViewBucketKey(desc.physAddr, desc.width, desc.height, desc.pitch);\n\ttexViewBucket[key].list.emplace_back(desc);\n\tvectorAppendUnique(view->viewLookUpCacheKeys, key);\n\t// resolution-independent bucket\n\tkey = _getViewBucketKeyNoRes(desc.physAddr, desc.pitch);\n\ttexViewBucket_nores[key].list.push_back(desc);\n\tvectorAppendUnique(view->viewLookUpCacheKeysNoRes, key);\n}\n\nvoid LatteTextureViewLookupCache::RemoveAll(LatteTextureView* view)\n{\n\tfor (auto& key : view->viewLookUpCacheKeys)\n\t{\n\t\tauto& bucket = texViewBucket[key].list;\n\t\tbucket.erase(std::remove_if(bucket.begin(), bucket.end(), [view](const LatteTexViewLookupDesc& v) {\n\t\t\treturn v.view == view; }), bucket.end());\n\t}\n\tfor (auto& key : view->viewLookUpCacheKeysNoRes)\n\t{\n\t\tauto& bucket = texViewBucket_nores[key].list;\n\t\tbucket.erase(std::remove_if(bucket.begin(), bucket.end(), [view](const LatteTexViewLookupDesc& v) {\n\t\t\treturn v.view == view; }), bucket.end());\n\t}\n}\n\nLatteTextureView* LatteTextureViewLookupCache::lookup(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim)\n{\n\t// todo - add tileMode param to this and the other lookup functions?\n\tuint32 key = _getViewBucketKey(physAddr, width, height, pitch);\n\tkey %= TEXTURE_VIEW_BUCKETS;\n\tfor (auto& it : texViewBucket[key].list)\n\t{\n\t\tif (it.format == format && it.dim == dim &&\n\t\t\tit.width == width && it.height == height && it.pitch == pitch && it.physAddr == physAddr\n\t\t\t&& it.firstMip == firstMip && it.numMip == numMip\n\t\t\t&& it.firstSlice == firstSlice && it.numSlice == numSlice\n\t\t\t)\n\t\t{\n\t\t\treturn it.view;\n\t\t}\n\t}\n\treturn nullptr;\n}\n\nLatteTextureView* LatteTextureViewLookupCache::lookupWithColorOrDepthType(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, bool isDepth)\n{\n\tcemu_assert_debug(firstSlice == 0);\n\tuint32 key = _getViewBucketKey(physAddr, width, height, pitch);\n\tkey %= TEXTURE_VIEW_BUCKETS;\n\tfor (auto& it : texViewBucket[key].list)\n\t{\n\t\tif (it.format == format && it.dim == dim && it.width == width && it.height == height && it.pitch == pitch && it.physAddr == physAddr\n\t\t\t&& it.firstMip == firstMip && it.numMip == numMip\n\t\t\t&& it.firstSlice == firstSlice && it.numSlice == numSlice &&\n\t\t\tit.isDepth == isDepth\n\t\t\t)\n\t\t{\n\t\t\treturn it.view;\n\t\t}\n\t}\n\treturn nullptr;\n}\n\n// look up view with unspecified mipCount and sliceCount\nLatteTextureView* LatteTextureViewLookupCache::lookupSlice(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format)\n{\n\tuint32 key = _getViewBucketKey(physAddr, width, height, pitch);\n\tkey %= TEXTURE_VIEW_BUCKETS;\n\tfor (auto& it : texViewBucket[key].list)\n\t{\n\t\tif (it.width == width && it.height == height && it.pitch == pitch && it.physAddr == physAddr && it.format == format)\n\t\t{\n\t\t\tif (firstSlice == it.firstSlice && firstMip == it.firstMip)\n\t\t\t\treturn it.view;\n\t\t}\n\t}\n\treturn nullptr;\n}\n\n// look up view with unspecified mipCount/sliceCount and only minimum width and height given\nLatteTextureView* LatteTextureViewLookupCache::lookupSliceMinSize(MPTR physAddr, sint32 minWidth, sint32 minHeight, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format)\n{\n\tuint32 key = _getViewBucketKeyNoRes(physAddr, pitch);\n\tkey %= TEXTURE_VIEW_BUCKETS;\n\tfor (auto& it : texViewBucket_nores[key].list)\n\t{\n\t\tif (it.width >= minWidth && it.height >= minHeight && it.pitch == pitch && it.physAddr == physAddr && it.format == format)\n\t\t{\n\t\t\tif (firstSlice == it.firstSlice && firstMip == it.firstMip)\n\t\t\t\treturn it.view;\n\t\t}\n\t}\n\treturn nullptr;\n}\n\n// similar to lookupSlice but also compares isDepth\nLatteTextureView* LatteTextureViewLookupCache::lookupSliceEx(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format, bool isDepth)\n{\n\tcemu_assert_debug(firstMip == 0);\n\tuint32 key = _getViewBucketKey(physAddr, width, height, pitch);\n\tkey %= TEXTURE_VIEW_BUCKETS;\n\tfor (auto& it : texViewBucket[key].list)\n\t{\n\t\tif (it.width == width && it.height == height && it.pitch == pitch && it.physAddr == physAddr && it.format == format && it.isDepth == isDepth)\n\t\t{\n\t\t\tif (firstSlice == it.firstSlice && firstMip == it.firstMip)\n\t\t\t\treturn it.view;\n\t\t}\n\t}\n\treturn nullptr;\n}\n\nstd::unordered_set<LatteTextureView*> LatteTextureViewLookupCache::GetAllViews()\n{\n\tstd::unordered_set<LatteTextureView*> viewSet;\n\tfor (uint32 i = 0; i < TEXTURE_VIEW_BUCKETS; i++)\n\t{\n\t\tfor (auto& it : texViewBucket[i].list)\n\t\t\tviewSet.emplace(it.view);\n\t}\n\treturn viewSet;\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTextureView.h",
    "content": "#pragma once\n\nclass LatteTextureView\n{\npublic:\n\tenum class MagFilter\n\t{\n\t\tkLinear,\n\t\tkNearestNeighbor,\n\t};\n\n\tLatteTextureView(class LatteTexture* texture, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, bool registerView = true);\n\tvirtual ~LatteTextureView();\n\n\tvoid CreateLookupForSubTexture(uint32 mipStart, uint32 sliceStart);\n\n\tclass LatteTexture* baseTexture;\n\t// view definition\n\t// note that a view can be addressed by more than one combination of physAddress/firstMip/firstSlice\n\t// thus the firstMip and firstSlice members of this class may not match the ones that were set in the GPU registers when this view was looked up\n\tsint32 firstMip;\n\tsint32 numMip;\n\tsint32 firstSlice;\n\tsint32 numSlice;\n\tLatte::E_GX2SURFFMT format; // format of view, can differ from base texture\n\tLatte::E_DIM dim; // dimension of view\n\t// state\n\tuint32 lastTextureBindIndex = 0;\n\t// FBO association\n\tstd::vector<class LatteCachedFBO*> list_fboLookup; // only set for the first color texture of each FBO, or the depth texture if no color textures are present\n\tstd::vector<class LatteCachedFBO*> list_associatedFbo; // list of cached fbos that reference this texture view\n\t// view lookup cache\n\tstd::vector<uint32> viewLookUpCacheKeys;\n\tstd::vector<uint32> viewLookUpCacheKeysNoRes;\n};\n\nclass LatteTextureViewLookupCache\n{\npublic:\n\tstatic void Add(LatteTextureView* view, uint32 baseMip = 0, uint32 baseSlice = 0);\n\tstatic void RemoveAll(LatteTextureView* view);\n\n\tstatic LatteTextureView* lookup(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim);\n\tstatic LatteTextureView* lookupWithColorOrDepthType(MPTR physAddr, sint32 width, sint32 height, sint32 depth, sint32 pitch, sint32 firstMip, sint32 numMip, sint32 firstSlice, sint32 numSlice, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, bool isDepth);\n\tstatic LatteTextureView* lookupSlice(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format);\n\tstatic LatteTextureView* lookupSliceMinSize(MPTR physAddr, sint32 minWidth, sint32 minHeight, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format);\n\tstatic LatteTextureView* lookupSliceEx(MPTR physAddr, sint32 width, sint32 height, sint32 pitch, sint32 firstMip, sint32 firstSlice, Latte::E_GX2SURFFMT format, bool isDepth);\n\n\tstatic std::unordered_set<LatteTextureView*> GetAllViews();\n\n\t\n};"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteThread.cpp",
    "content": "#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\" // todo - remove dependency\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteAsyncCommands.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"WindowSystem.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"util/helpers/helpers.h\"\n\n#include <imgui.h>\n#include \"config/ActiveSettings.h\"\n\n#include \"Cafe/CafeSystem.h\"\n\nLatteGPUState_t LatteGPUState = {};\n\nstd::atomic_bool sLatteThreadRunning = false;\nstd::atomic_bool sLatteThreadFinishedInit = false;\n\nvoid LatteThread_Exit();\n\nvoid Latte_LoadInitialRegisters()\n{\n\tLatteGPUState.contextNew.CB_TARGET_MASK.set_MASK(0xFFFFFFFF);\n\tLatteGPUState.contextNew.VGT_MULTI_PRIM_IB_RESET_INDX.set_RESTART_INDEX(0xFFFFFFFF);\n\tLatteGPUState.contextNew.VGT_DMA_NUM_INSTANCES.set_NUM_INSTANCES(1);\n\tLatteGPUState.contextRegister[Latte::REGADDR::PA_CL_CLIP_CNTL] = 0;\n\t*(float*)&LatteGPUState.contextRegister[mmDB_DEPTH_CLEAR] = 1.0f;\n}\n\nextern bool gx2WriteGatherInited;\n\nLatteTextureView* osScreenTVTex[2] = { nullptr };\nLatteTextureView* osScreenDRCTex[2] = { nullptr };\n\nLatteTextureView* LatteHandleOSScreen_getOrCreateScreenTex(MPTR physAddress, uint32 width, uint32 height, uint32 pitch)\n{\n\tLatteTextureView* texView = LatteTextureViewLookupCache::lookup(physAddress, width, height, 1, pitch, 0, 1, 0, 1, Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM, Latte::E_DIM::DIM_2D);\n\tif (texView)\n\t\treturn texView;\n\treturn LatteTexture_CreateTexture(Latte::E_DIM::DIM_2D, physAddress, 0, Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM, width, height, 1, pitch, 1, 0, Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED, false);\n}\n\nvoid LatteHandleOSScreen_prepareTextures()\n{\n\tosScreenTVTex[0] = LatteHandleOSScreen_getOrCreateScreenTex(LatteGPUState.osScreen.screen[0].physPtr, 1280, 720, 1280);\n\tosScreenTVTex[1] = LatteHandleOSScreen_getOrCreateScreenTex(LatteGPUState.osScreen.screen[0].physPtr + 1280 * 720 * 4, 1280, 720, 1280);\n\tosScreenDRCTex[0] = LatteHandleOSScreen_getOrCreateScreenTex(LatteGPUState.osScreen.screen[1].physPtr, 854, 480, 0x380);\n\tosScreenDRCTex[1] = LatteHandleOSScreen_getOrCreateScreenTex(LatteGPUState.osScreen.screen[1].physPtr + 896 * 480 * 4, 854, 480, 0x380);\n}\n\nvoid LatteRenderTarget_copyToBackbuffer(LatteTextureView* textureView, bool isPadView);\n\nbool LatteHandleOSScreen_TV()\n{\n\tif (!LatteGPUState.osScreen.screen[0].isEnabled)\n\t\treturn false;\n\tif (LatteGPUState.osScreen.screen[0].flipExecuteCount == LatteGPUState.osScreen.screen[0].flipRequestCount)\n\t\treturn false;\n\tLatteHandleOSScreen_prepareTextures();\n\n\tsint32 bufferDisplayTV = (LatteGPUState.osScreen.screen[0].flipRequestCount & 1) ^ 1;\n\tsint32 bufferDisplayDRC = (LatteGPUState.osScreen.screen[1].flipRequestCount & 1) ^ 1;\n\n\tconst uint32 bufferIndexTV = (bufferDisplayTV);\n\tconst uint32 bufferIndexDRC = bufferDisplayDRC;\n\n\tLatteTexture_ReloadData(osScreenTVTex[bufferIndexTV]->baseTexture);\n\n\t// TV screen\n\tLatteRenderTarget_copyToBackbuffer(osScreenTVTex[bufferIndexTV]->baseTexture->baseView, false);\n\t\n\tif (LatteGPUState.osScreen.screen[0].flipExecuteCount != LatteGPUState.osScreen.screen[0].flipRequestCount)\n\t\tLatteGPUState.osScreen.screen[0].flipExecuteCount.store(LatteGPUState.osScreen.screen[0].flipRequestCount);\n\treturn true;\n}\n\nbool LatteHandleOSScreen_DRC()\n{\n\tif (!LatteGPUState.osScreen.screen[1].isEnabled)\n\t\treturn false;\n\tif (LatteGPUState.osScreen.screen[1].flipExecuteCount == LatteGPUState.osScreen.screen[1].flipRequestCount)\n\t\treturn false;\n\tLatteHandleOSScreen_prepareTextures();\n\n\tsint32 bufferDisplayDRC = (LatteGPUState.osScreen.screen[1].flipRequestCount & 1) ^ 1;\n\n\tconst uint32 bufferIndexDRC = bufferDisplayDRC;\n\n\tLatteTexture_ReloadData(osScreenDRCTex[bufferIndexDRC]->baseTexture);\n\n\t// GamePad screen\n\tLatteRenderTarget_copyToBackbuffer(osScreenDRCTex[bufferIndexDRC]->baseTexture->baseView, true);\n\n\tif (LatteGPUState.osScreen.screen[1].flipExecuteCount != LatteGPUState.osScreen.screen[1].flipRequestCount)\n\t\tLatteGPUState.osScreen.screen[1].flipExecuteCount.store(LatteGPUState.osScreen.screen[1].flipRequestCount);\n\treturn true;\n}\n\nvoid LatteThread_HandleOSScreen()\n{\n\tbool swapTV = LatteHandleOSScreen_TV();\n\tbool swapDRC = LatteHandleOSScreen_DRC();\n\tif(swapTV || swapDRC)\n\t\tg_renderer->SwapBuffers(swapTV, swapDRC);\n}\n\nint Latte_ThreadEntry()\n{\n\tSetThreadName(\"LatteThread\");\n\tsint32 w,h;\n\tWindowSystem::GetWindowPhysSize(w,h);\n\n\t// renderer\n\tg_renderer->Initialize();\n\tRendererOutputShader::InitializeStatic();\n\n\tLatteTiming_Init();\n\tLatteTexture_init();\n\tLatteTC_Init();\n\tLatteBufferCache_init(164 * 1024 * 1024);\n\tLatteQuery_Init();\n\tLatteSHRC_Init();\n\tLatteStreamout_InitCache();\n\n\tg_renderer->renderTarget_setViewport(0, 0, w, h, 0.0f, 1.0f);\n\t\n\t// enable GLSL gl_PointSize support\n\t// glEnable(GL_PROGRAM_POINT_SIZE); // breaks shader caching on AMD (as of 2018)\n\t\n\tLatteGPUState.glVendor = GLVENDOR_UNKNOWN;\n\tswitch(g_renderer->GetVendor())\n\t{\n\tcase GfxVendor::AMD: \n\t\tLatteGPUState.glVendor = GLVENDOR_AMD;\n\t\tbreak;\n\tcase GfxVendor::Intel:\n\t\tLatteGPUState.glVendor = GLVENDOR_INTEL; \n\t\tbreak;\n\tcase GfxVendor::Nvidia: \n\t\tLatteGPUState.glVendor = GLVENDOR_NVIDIA; \n\t\tbreak;\n\tcase GfxVendor::Apple:\n\t\tLatteGPUState.glVendor = GLVENDOR_APPLE;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tsLatteThreadFinishedInit = true;\n\n\t// register debug handler\n\tif (cemuLog_isLoggingEnabled(LogType::OpenGLLogging))\n\t\tg_renderer->EnableDebugMode();\n\n\t// wait till a game is started\n\twhile( true )\n\t{\n\t\tif( CafeSystem::IsTitleRunning() )\n\t\t\tbreak;\n\n\t\tg_renderer->DrawEmptyFrame(true);\n\t\tg_renderer->DrawEmptyFrame(false);\n\t\tg_renderer->CancelScreenshotRequest(); // keep the screenshot request queue empty\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1000/60));\n\t}\n\n\tg_renderer->DrawEmptyFrame(true);\n\n\t// before doing anything with game specific shaders, we need to wait for graphic packs to finish loading\n\tGraphicPack2::WaitUntilReady();\n\t// if legacy packs are enabled we cannot use the colorbuffer resolution optimization\n\tLatteGPUState.allowFramebufferSizeOptimization = true;\n\tfor(auto& pack : GraphicPack2::GetActiveGraphicPacks())\n\t{\n\t\tif(pack->AllowRendertargetSizeOptimization())\n\t\t\tcontinue;\n\t\tfor(auto& rule : pack->GetTextureRules())\n\t\t{\n\t\t\tif(rule.filter_settings.width >= 0 || rule.filter_settings.height >= 0 || rule.filter_settings.depth >= 0 ||\n\t\t\t\trule.overwrite_settings.width >= 0 || rule.overwrite_settings.height >= 0 || rule.overwrite_settings.depth >= 0)\n\t\t\t{\n\t\t\t\tLatteGPUState.allowFramebufferSizeOptimization = false;\n\t\t\t\tcemuLog_log(LogType::Force, \"Graphic pack \\\"{}\\\" prevents rendertarget size optimization. This warning can be ignored and is intended for graphic pack developers\", pack->GetName());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t// load disk shader cache\n    LatteShaderCache_Load();\n\t// init registers\n\tLatte_LoadInitialRegisters();\n\t// let CPU thread know the GPU is done initializing\n\tg_isGPUInitFinished = true;\n\t// wait until CPU has called GX2Init()\n\twhile (LatteGPUState.gx2InitCalled == 0)\n\t{\n\t\tstd::this_thread::yield();\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\tLatteThread_HandleOSScreen();\n\t\tif (Latte_GetStopSignal())\n\t\t\tLatteThread_Exit();\n\t}\n\tLatteCP_ProcessRingbuffer();\n\tcemu_assert_debug(false); // should never reach\n\treturn 0;\n}\n\nstd::thread sLatteThread;\nstd::mutex sLatteThreadStateMutex;\n\n// initializes GPU thread which in turn also activates graphic packs\n// does not return until the thread finished initialization\nvoid Latte_Start()\n{\n\tstd::unique_lock _lock(sLatteThreadStateMutex);\n\tcemu_assert_debug(!sLatteThreadRunning);\n\tsLatteThreadRunning = true;\n\tsLatteThreadFinishedInit = false;\n\tsLatteThread = std::thread(Latte_ThreadEntry);\n\t// wait until initialized\n\twhile (!sLatteThreadFinishedInit)\n\t{\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t}\n}\n\nvoid Latte_Stop()\n{\n\tstd::unique_lock _lock(sLatteThreadStateMutex);\n\tif (!sLatteThreadRunning)\n\t\treturn;\n\tsLatteThreadRunning = false;\n\t_lock.unlock();\n\tsLatteThread.join();\n}\n\nbool Latte_GetStopSignal()\n{\n\treturn !sLatteThreadRunning;\n}\n\nvoid LatteThread_Exit()\n{\n\tif (g_renderer)\n\t\tg_renderer->Shutdown();\n    // clean up vertex/uniform cache\n    LatteBufferCache_UnloadAll();\n\t// clean up texture cache\n\tLatteTC_UnloadAllTextures();\n\t// clean up runtime shader cache\n    LatteSHRC_UnloadAll();\n    // close disk cache\n    LatteShaderCache_Close();\n\tRendererOutputShader::ShutdownStatic();\n    // destroy renderer but make sure that g_renderer remains valid until the destructor has finished\n\tif (g_renderer)\n\t{\n\t\tRenderer* renderer = g_renderer.get();\n\t\tdelete renderer;\n\t\tg_renderer.release();\n\t}\n\t// reset GPU7 state\n\tstd::memset(&LatteGPUState, 0, sizeof(LatteGPUState));\n\t#if BOOST_OS_WINDOWS\n\tExitThread(0);\n\t#else\n\tpthread_exit(nullptr);\n\t#endif\n\tcemu_assert_unimplemented();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTiming.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/OS/libs/gx2/GX2_Event.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.h\"\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n#include \"config/CemuConfig.h\"\n#include \"Cafe/CafeSystem.h\"\n\nsint32 s_customVsyncFrequency = -1;\n\nvoid LatteTiming_NotifyHostVSync();\n\n// calculate time between vsync events in timer units\n// standard rate on Wii U is 59.94, however to prevent tearing and microstutter on ~60Hz displays it is better if we slightly overshoot 60 Hz\n// can be modified by graphic packs\nHRTick LatteTime_CalculateTimeBetweenVSync()\n{\n\t// 59.94 -> 60 * 0.999\n\n\tHRTick tick = HighResolutionTimer::getFrequency();\n\tif (s_customVsyncFrequency > 0)\n\t{\n\t\ttick /= (uint64)s_customVsyncFrequency;\n\t}\n\telse\n\t{\n\t\ttick *= 1000ull;\n\t\ttick /= 1002ull;\n\t\ttick /= 60ull;\n\t}\n\treturn tick;\n}\n\nvoid LatteTiming_setCustomVsyncFrequency(sint32 frequency)\n{\n\ts_customVsyncFrequency = frequency;\n}\n\nvoid LatteTiming_disableCustomVsyncFrequency()\n{\n\ts_customVsyncFrequency = -1;\n}\n\nbool LatteTiming_getCustomVsyncFrequency(sint32& customFrequency)\n{\n\tsint32 t = s_customVsyncFrequency;\n\tif (t <= 0)\n\t\treturn false;\n\tcustomFrequency = t;\n\treturn true;\n}\n\nbool s_usingHostDrivenVSync = false;\n\nvoid LatteTiming_EnableHostDrivenVSync()\n{\n\tif (s_usingHostDrivenVSync)\n\t\treturn;\n\tVsyncDriver_startThread(LatteTiming_NotifyHostVSync);\n\ts_usingHostDrivenVSync = true;\n}\n\nbool LatteTiming_IsUsingHostDrivenVSync()\n{\n\treturn s_usingHostDrivenVSync;\n}\n\nvoid LatteTiming_Init()\n{\n\tLatteGPUState.timer_frequency = HighResolutionTimer::getFrequency();\n\tLatteGPUState.timer_bootUp = HighResolutionTimer::now().getTick();\n\tLatteGPUState.timer_nextVSync = LatteGPUState.timer_bootUp + LatteTime_CalculateTimeBetweenVSync();\n}\n\nvoid LatteTiming_signalVsync()\n{\n\tstatic uint32 s_vsyncIntervalCounter = 0;\n\n\tif (!LatteGPUState.gx2InitCalled)\n\t\treturn;\n\ts_vsyncIntervalCounter++;\n\tuint32 swapInterval = 1;\n\tif (LatteGPUState.sharedArea)\n\t\tswapInterval = LatteGPUState.sharedArea->swapInterval;\n\n\t// flip\n\tif (s_vsyncIntervalCounter >= swapInterval)\n\t{\n\t\tif (LatteGPUState.sharedArea)\n\t\t{\n\t\t\t// hack/workaround - only execute flip if GX2SwapScanBuffers() isn't lagging behind\n\t\t\tuint64 currentTitleId = CafeSystem::GetForegroundTitleId();\n\t\t\tif (currentTitleId == 0x00050000101c9500 || currentTitleId == 0x00050000101c9400 || currentTitleId == 0x0005000e101c9300)\n\t\t\t{\n\t\t\t\tuint32 currentFlipRequestCount = _swapEndianU32(LatteGPUState.sharedArea->flipRequestCountBE);\n\t\t\t\tuint32 currentFlipExecuteCount = _swapEndianU32(LatteGPUState.sharedArea->flipExecuteCountBE);\n\n\t\t\t\tif ((currentFlipRequestCount >= currentFlipExecuteCount) || (currentFlipExecuteCount - currentFlipRequestCount < 4))\n\t\t\t\t{\n\t\t\t\t\tLatteGPUState.sharedArea->flipExecuteCountBE = _swapEndianU32(_swapEndianU32(LatteGPUState.sharedArea->flipExecuteCountBE) + 1);\n\t\t\t\t}\n\n\t\t\t\tLatteGPUState.flipCounter++;\n\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// old code for all other games\n\t\t\t\tif (LatteGPUState.flipRequestCount > 0)\n\t\t\t\t{\n\t\t\t\t\tLatteGPUState.flipRequestCount.fetch_sub(1);\n\t\t\t\t\tLatteGPUState.sharedArea->flipExecuteCountBE = _swapEndianU32(_swapEndianU32(LatteGPUState.sharedArea->flipExecuteCountBE) + 1);\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\tGX2::__GX2NotifyEvent(GX2::GX2CallbackEventType::FLIP);\n\t\ts_vsyncIntervalCounter = 0;\n\t}\n\t// vsync\n\tGX2::__GX2NotifyEvent(GX2::GX2CallbackEventType::VSYNC);\n}\n\nHRTick s_lastHostVsync = 0;\n\n// notify when host vsync event is triggered (on renderer canvas)\nvoid LatteTiming_NotifyHostVSync()\n{\n\tif (!LatteTiming_IsUsingHostDrivenVSync())\n\t\treturn;\n\tauto nowTimePoint = HighResolutionTimer::now().getTick();\n\tauto dif = nowTimePoint - s_lastHostVsync;\n\tauto vsyncPeriod = LatteTime_CalculateTimeBetweenVSync();\n\n\n\tif (dif < vsyncPeriod)\n\t{\n\t\t// skip\n\t\treturn;\n\t}\n\tuint64 elapsedPeriods = dif / vsyncPeriod;\n\tif (elapsedPeriods >= 10)\n\t{\n\t\ts_lastHostVsync = nowTimePoint;\n\t}\n\telse\n\t\ts_lastHostVsync += vsyncPeriod;\n\n\tLatteTiming_signalVsync();\n}\n\n// handle timed vsync event\nvoid LatteTiming_HandleTimedVsync()\n{\n\t// simulate VSync\n\tuint64 currentTimer = HighResolutionTimer::now().getTick();\n\tif( currentTimer >= LatteGPUState.timer_nextVSync )\n\t{\n\t\tif(!LatteTiming_IsUsingHostDrivenVSync())\n\t\t\tLatteTiming_signalVsync();\n\t\t// even if vsync is delegated to the host device, we still use this virtual vsync timer to check finished states\n\t\tLatteQuery_UpdateFinishedQueries();\n\t\tLatteTextureReadback_UpdateFinishedTransfers(false);\n\t\t// update vsync timer\n\t\tuint64 vsyncTime = LatteTime_CalculateTimeBetweenVSync();\n\t\tuint64 missedVsyncCount = (currentTimer - LatteGPUState.timer_nextVSync) / vsyncTime;\n\t\tif (missedVsyncCount >= 2)\n\t\t{\n\t\t\tLatteGPUState.timer_nextVSync += vsyncTime*(missedVsyncCount+1ULL);\n\t\t}\n\t\telse\t\n\t\t\tLatteGPUState.timer_nextVSync += vsyncTime;\n\t}\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Core/LatteTiming.h",
    "content": "#pragma once\n\nvoid LatteTiming_setCustomVsyncFrequency(sint32 frequency);\nvoid LatteTiming_disableCustomVsyncFrequency();\nbool LatteTiming_getCustomVsyncFrequency(sint32& customFrequency);\n\nvoid LatteTiming_EnableHostDrivenVSync();"
  },
  {
    "path": "src/Cafe/HW/Latte/ISA/LatteInstructions.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n\nnamespace Latte\n{\n\tusing GPRType = uint8;\n};\n\nclass LatteCFInstruction\n{\npublic:\n\tenum class CF_COND\n\t{\n\t\tCF_COND_ACTIVE = 0,\n\t\tCF_COND_FALSE = 1,\n\t\tCF_COND_BOOL = 2,\n\t\tCF_COND_NOT_BOOL = 3,\n\t};\n\n\tenum OPCODE\n\t{\n\t\t// SQ_CF_INST_*\n\t\tINST_NOP = 0x00,\n\t\tINST_TEX = 0x01,\n\t\tINST_VTX = 0x02, // vertex fetch clause, used only in GS copy program?\n\t\tINST_VTX_TC = 0x03, // vertex fetch clause, through texture cache\n\t\tINST_LOOP_START = 0x04, // DX9 style loop\n\t\tINST_LOOP_END = 0x05,\n\t\tINST_LOOP_START_DX10 = 0x06,\n\t\tINST_LOOP_BREAK = 0x09,\n\t\tINST_JUMP = 0x0A,\n\t\tINST_ELSE = 0x0D,\n\t\tINST_POP = 0x0E,\n\t\tINST_ELSE_AFTER = 0x0F,\n\t\tINST_CALL = 0x12,\n\t\tINST_CALL_FS = 0x13,\n\t\tINST_RETURN = 0x14,\n\t\tINST_EMIT_VERTEX = 0x15, // only available in geometry shader\n\t\tINST_MEM_STREAM0_WRITE = 0x20, // for stream out (index selects buffer)\n\t\tINST_MEM_STREAM1_WRITE = 0x21,\n\t\tINST_MEM_STREAM2_WRITE = 0x22,\n\t\tINST_MEM_STREAM3_WRITE = 0x23,\n\t\tINST_MEM_RING_WRITE = 0x26, // used to pass data to/from geometry shader\n\t\tINST_EXPORT = 0x27,\n\t\tINST_EXPORT_DONE = 0x28, // last export\n\n\t\t// ALU instructions\n\t\tMASK_ALU = 0x40, // mask to differentiate ALU instructions\n\t\tINST_ALU = (0x08 | MASK_ALU),\n\t\tINST_ALU_PUSH_BEFORE = (0x09 | MASK_ALU),\n\t\tINST_ALU_POP_AFTER = (0x0A | MASK_ALU),\n\t\tINST_ALU_POP2_AFTER = (0x0B | MASK_ALU),\n\t\t// reserved\n\t\tINST_ALU_CONTINUE = (0x0D | MASK_ALU),\n\t\tINST_ALU_BREAK = (0x0E | MASK_ALU),\n\t\tINST_ALU_ELSE_AFTER = (0x0F | MASK_ALU),\n\t};\n\n\tOPCODE getField_Opcode() const\n\t{\n\t\tuint32 cf_inst23_7 = (word1 >> 23) & 0x7F;\n\t\t// check the bigger opcode fields first\n\t\tif (cf_inst23_7 < 0x40) // starting at 0x40 the bits overlap with the ALU instruction encoding\n\t\t{\n\t\t\t// cf_inst23_7 is opcode\n\t\t\treturn (OPCODE)cf_inst23_7;\n\t\t}\n\t\tuint32 cf_inst26_4 = ((word1 >> 26) & 0xF);\n\t\t// cf_inst26_4 is ALU opcode\n\t\treturn (OPCODE)(cf_inst26_4 | OPCODE::MASK_ALU);\n\t}\n\n\tbool getField_END_OF_PROGRAM() const\n\t{\n\t\t// shared by all CF instruction types except ALU\n\t\tcemu_assert_debug((getField_Opcode() & OPCODE::MASK_ALU) != OPCODE::MASK_ALU);\n\t\treturn ((word1 >> 21) & 1) != 0;\n\t}\n\n\tconst class LatteCFInstruction_ALU* getParser_ALU() const\n\t{\n\t\tcemu_assert_debug((getField_Opcode() & OPCODE::MASK_ALU) == OPCODE::MASK_ALU);\n\t\treturn (const LatteCFInstruction_ALU*)this;\n\t}\n\n\t// EXPORT is for:\n\t// SQ_CF_INST_MEM_STREAM0 - SQ_CF_INST_MEM_STREAM3\n\t// SQ_CF_INST_MEM_SCRATCH\n\t// SQ_CF_INST_MEM_REDUCTION\n\t// SQ_CF_INST_MEM_RING\n\t// SQ_CF_INST_EXPORT\n\t// SQ_CF_INST_EXPORT_DONE\n\tconst class LatteCFInstruction_EXPORT_IMPORT* getParser_EXPORT() const\n\t{\n\t\treturn (const LatteCFInstruction_EXPORT_IMPORT*)this;\n\t}\n\n\ttemplate<typename TCFEncoding>\n\tconst TCFEncoding* getParserIfOpcodeMatch() const\n\t{\n\t\tauto opcode = getField_Opcode();\n\t\tif (TCFEncoding::MatchesOpcode(opcode))\n\t\t\treturn (const TCFEncoding*)this;\n\t\treturn nullptr;\n\t}\n\n\t// writing\n\tvoid setField_Opcode(OPCODE opcode)\n\t{\n\t\tcemu_assert_debug(((uint32)opcode & (uint32)OPCODE::MASK_ALU) == 0);\n\t\tword1 &= ~(0xF << 23);\n\t\tword1 |= ((uint32)opcode << 23);\n\t}\n\nprotected:\n\tuint32 word0;\n\tuint32 word1;\n};\n\n// default encoding, CF_DWORD0 + CF_DWORD1\n// used for opcodes: See list in MatchesOpcode()\nclass LatteCFInstruction_DEFAULT : public LatteCFInstruction\n{\npublic:\n\tLatteCFInstruction_DEFAULT()\n\t{\n\t\tword0 = 0;\n\t\tword1 = 0;\n\t}\n\n\tstatic bool MatchesOpcode(const OPCODE opcode)\n\t{\n\t\treturn opcode == OPCODE::INST_NOP ||\n\t\t\topcode == OPCODE::INST_VTX ||\n\t\t\topcode == OPCODE::INST_VTX_TC ||\n\t\t\topcode == OPCODE::INST_TEX ||\n\t\t\topcode == OPCODE::INST_CALL_FS ||\n\t\t\topcode == OPCODE::INST_CALL ||\n\t\t\topcode == OPCODE::INST_RETURN ||\n\t\t\topcode == OPCODE::INST_LOOP_START ||\n\t\t\topcode == OPCODE::INST_LOOP_END ||\n\t\t\topcode == OPCODE::INST_LOOP_START_DX10 ||\n\t\t\t//opcode == OPCODE::INST_LOOP_CONTINUE ||\n\t\t\t//opcode == OPCODE::INST_LOOP_BREAK ||\n\t\t\topcode == OPCODE::INST_JUMP ||\n\t\t\t//opcode == OPCODE::INST_PUSH ||\n\t\t\t//opcode == OPCODE::INST_PUSH_ELSE ||\n\t\t\topcode == OPCODE::INST_ELSE ||\n\t\t\topcode == OPCODE::INST_POP ||\n\t\t\t//opcode == OPCODE::INST_POP_JUMP ||\n\t\t\topcode == OPCODE::INST_JUMP ||\n\t\t\t//opcode == OPCODE::INST_POP_PUSH ||\n\t\t\t//opcode == OPCODE::INST_PUSH ||\n\t\t\t//opcode == OPCODE::INST_POP_PUSH_ELSE ||\n\t\t\t//opcode == OPCODE::INST_PUSH_ELSE ||\n\t\t\topcode == OPCODE::INST_EMIT_VERTEX\n\t\t\t//opcode == OPCODE::INST_EMIT_CUT_VERTEX ||\n\t\t\t//opcode == OPCODE::INST_CUT_VERTEX ||\n\t\t\t//opcode == OPCODE::INST_KILL\n\t\t\t;\n\t}\n\n\t// returns offset in bytes\n\tuint32 getField_ADDR() const // returns offset in bytes\n\t{\n\t\treturn word0 << 3;\n\t}\n\n\tuint32 getField_POP_COUNT() const\n\t{\n\t\treturn (word1 >> 0) & 7;\n\t}\n\n\tuint32 getField_CF_CONST() const\n\t{\n\t\treturn (word1 >> 3) & 0x1F;\n\t}\n\n\tCF_COND getField_COND() const\n\t{\n\t\treturn (CF_COND)((word1 >> 8) & 0x3);\n\t}\n\n\tuint32 getField_COUNT() const\n\t{\t\t\n\t\tuint32 count = (word1 >> 10) & 0x7; // R600 field\n\t\tcount |= ((word1 >> 16)&0x8); // R700 has an extra bit at 19\n\t\treturn count + 1;\n\t}\n\n\tuint32 getField_CALL_COUNT() const\n\t{\n\t\treturn (word1 >> 13) & 0x3F;\n\t}\n\n\tuint32 getField_VALID_PIXEL_MODE() const\n\t{\n\t\treturn (word1 >> 22) & 1;\n\t}\n\n\tuint32 getField_WHOLE_QUAD_MODE() const\n\t{\n\t\treturn (word1 >> 30) & 1;\n\t}\n\n\tuint32 getField_BARRIER() const\n\t{\n\t\treturn (word1 >> 31) & 1;\n\t}\n\n\tstd::span<uint8> getClauseCode(std::span<uint8> programCode) const\n\t{\n\t\tcemu_assert_debug(getField_Opcode() == LatteCFInstruction::INST_VTX || getField_Opcode() == LatteCFInstruction::INST_VTX_TC);\n\t\tcemu_assert_debug(getField_ADDR() <= programCode.size());\n\t\tcemu_assert_debug((programCode.size() - getField_ADDR()) >= getField_COUNT() * 16);\n\t\treturn programCode.subspan(getField_ADDR(), getField_COUNT() * 16);\n\t}\n\n\t// writing\n\tvoid setField_ADDR(uint32 addrInBytes) // in bytes\n\t{\n\t\tword0 = addrInBytes >> 3;\n\t}\n\n\tvoid setField_COUNT(uint32 count)\n\t{\n\t\tcemu_assert_debug(count > 0 && count <= 16);\n\t\tcount--;\n\t\tword1 &= ~((0x7 << 10) | (1 << 19));\n\t\tword1 |= ((count & 0x7) << 10);\n\t\tword1 |= ((count << 16) & (1<<19));\n\t}\n\n\tvoid setField_BARRIER(bool isEnabled)\n\t{\n\t\tif (isEnabled)\n\t\t\tword1 |= (1 << 31);\n\t\telse\n\t\t\tword1 &= ~(1 << 31);\n\t}\n\n};\n\n// CF_ALLOC_EXPORT_DWORD0 + CF_ALLOC_EXPORT_DWORD1_BUF / CF_ALLOC_EXPORT_DWORD1_SWIZ\n// this has two different encoding. Use isEncodingBUF() to determine which fields are valid\nclass LatteCFInstruction_EXPORT_IMPORT : public LatteCFInstruction // CF_ALLOC_EXPORT_DWORD1_SWIZ\n{\npublic:\n\tstatic bool MatchesOpcode(const OPCODE opcode)\n\t{\n\t\treturn opcode == OPCODE::INST_MEM_STREAM0_WRITE ||\n\t\t\topcode == OPCODE::INST_MEM_STREAM1_WRITE ||\n\t\t\topcode == OPCODE::INST_MEM_STREAM2_WRITE ||\n\t\t\topcode == OPCODE::INST_MEM_STREAM3_WRITE ||\n\t\t\t//opcode == OPCODE::INST_MEM_SCRATCH ||\n\t\t\t//opcode == OPCODE::INST_MEM_REDUCTION ||\n\t\t\topcode == OPCODE::INST_MEM_RING_WRITE ||\n\t\t\topcode == OPCODE::INST_EXPORT ||\n\t\t\topcode == OPCODE::INST_EXPORT_DONE;\n\t}\n\n\tenum EXPORT_TYPE : uint8\n\t{\n\t\tPIXEL = 0,\n\t\tPOSITION = 1,\n\t\tPARAMETER = 2,\n\t\tUNUSED_VAL = 3\n\t};\n\n\tenum COMPSEL : uint8\n\t{\n\t\tX,\n\t\tY,\n\t\tZ,\n\t\tW,\n\t\tCONST_0F,\n\t\tCONST_1F,\n\t\tRESERVED,\n\t\tMASKED\n\t};\n\n\tEXPORT_TYPE getField_TYPE() const\n\t{\n\t\treturn (EXPORT_TYPE)((word0 >> 13) & 0x3);\n\t}\n\n\tuint32 getField_ARRAY_BASE() const\n\t{\n\t\treturn (word0 >> 0) & 0x1FFF;\n\t}\n\n\tuint32 getField_INDEX_GPR() const\n\t{\n\t\treturn (word0 >> 23) & 0x7F;\n\t}\n\n\t// read/write GPR (source/destination)\n\tuint32 getField_RW_GPR() const\n\t{\n\t\treturn (word0 >> 15) & 0x7F;\n\t}\n\n\t// if true, RW_GPR is indexed\n\tbool getField_RW_REL() const\n\t{\n\t\treturn ((word0 >> 22) & 0x1) != 0;\n\t}\n\n\tuint8 getField_BURST_COUNT() const\n\t{\n\t\treturn ((word1 >> 17) & 0xF) + 1;\n\t}\n\n\tuint8 getField_ELEM_SIZE() const\n\t{\n\t\treturn ((word0 >> 30) & 0x3) + 1;\n\t}\n\n\t// word1 bits 0-15 differ depending on BUF/SWIZ encoding\n\t// returns true if BUF encoding is used (BUF fields valid, SWIZ invalid). Otherwise SWIZ encoding is used (BUF fields invalid, SWIZ fields valid)\n\tbool isEncodingBUF() const\n\t{\n\t\treturn ((word1 >> 12) & 0xF) != 0;\n\t}\n\n\t// fields specific to SWIZ encoding \n\n\tCOMPSEL getSwizField_SEL_X() const { cemu_assert_debug(!isEncodingBUF()); return (COMPSEL)((word1 >> 0) & 0x7); }\n\tCOMPSEL getSwizField_SEL_Y() const { cemu_assert_debug(!isEncodingBUF()); return (COMPSEL)((word1 >> 3) & 0x7); }\n\tCOMPSEL getSwizField_SEL_Z() const { cemu_assert_debug(!isEncodingBUF()); return (COMPSEL)((word1 >> 6) & 0x7); }\n\tCOMPSEL getSwizField_SEL_W() const { cemu_assert_debug(!isEncodingBUF()); return (COMPSEL)((word1 >> 9) & 0x7); }\n\n\t// fields specific to BUF encoding (word1 bits 0-15)\n\t\n\tuint32 getBufField_ARRAY_SIZE() const\n\t{\n\t\tcemu_assert_debug(isEncodingBUF());\n\t\treturn (word1 >> 0) & 0xFFF;\n\t}\n\n\t// applies only to writes\n\tuint32 getBufField_COMP_MASK() const\n\t{\n\t\tcemu_assert_debug(isEncodingBUF());\n\t\treturn (word1 >> 12) & 0xF;\n\t}\n\n\t// these are not specific to EXPORT instr? Move to LatteCFInstruction?\n\tbool getValidPixelMode() const\n\t{\n\t\treturn ((word1 >> 22) & 0x1) != 0;\n\t}\n\n\tbool getWholeQuadMode() const\n\t{\n\t\treturn ((word1 >> 30) & 0x1) != 0;\n\n\t}\n};\n\n// encoding for CF_ALU_DWORD0 + CF_ALU_DWORD1\n// used for: \n// CF_INST_ALU\n// CF_INST_ALU_PUSH_BEFORE\n// CF_INST_ALU_POP_AFTER\n// CF_INST_ALU_POP2_AFTER\n// CF_INST_ALU_CONTINUE\n// CF_INST_ALU_BREAK\n// CF_INST_ALU_ELSE_AFTER\nclass LatteCFInstruction_ALU : public LatteCFInstruction\n{\npublic:\n\tstatic bool MatchesOpcode(const OPCODE opcode)\n\t{\n\t\treturn opcode == OPCODE::INST_ALU ||\n\t\t\topcode == OPCODE::INST_ALU_PUSH_BEFORE ||\n\t\t\topcode == OPCODE::INST_ALU_POP_AFTER ||\n\t\t\topcode == OPCODE::INST_ALU_POP2_AFTER ||\n\t\t\topcode == OPCODE::INST_ALU_CONTINUE ||\n\t\t\topcode == OPCODE::INST_ALU_BREAK ||\n\t\t\topcode == OPCODE::INST_ALU_ELSE_AFTER;\n\t}\n\n\tuint32 getField_ADDR() const\n\t{\n\t\treturn (word0 >> 0) & 0x3FFFFF;\n\t}\n\n\tuint32 getField_COUNT() const\n\t{\n\t\treturn ((word1 >> 18) & 0x7F) + 1;\n\t}\n\n\tuint32 getField_KCACHE_BANK0() const\n\t{\n\t\treturn (word0 >> 22) & 0xF;\n\t}\n\n\tuint32 getField_KCACHE_BANK1() const\n\t{\n\t\treturn (word0 >> 26) & 0xF;\n\t}\n\n\tuint32 getField_KCACHE_ADDR0() const\n\t{\n\t\treturn (word1 >> 2) & 0xFF;\n\t}\n\n\tuint32 getField_KCACHE_ADDR1() const\n\t{\n\t\treturn (word1 >> 10) & 0xFF;\n\t}\n\n\tbool getField_USES_WATERFALL() const\n\t{\n\t\treturn ((word1 >> 25)&1) !=0;\n\t}\n\n\t// todo - KCACHE_MODE0, KCACHE_MODE1, WHOLE_QUAD_MODE, BARRIER\n};\n\nstatic_assert(sizeof(LatteCFInstruction) == 8);\nstatic_assert(sizeof(LatteCFInstruction_DEFAULT) == 8);\nstatic_assert(sizeof(LatteCFInstruction_EXPORT_IMPORT) == 8);\nstatic_assert(sizeof(LatteCFInstruction_ALU) == 8);\n\n/* Latte instructions */\n\nclass LatteClauseInstruction_VTX // used by CF VTX and VTX_TC clauses\n{\npublic:\n\tLatteClauseInstruction_VTX()\n\t{\n\t\tword0 = 0;\n\t\tword1 = 0;\n\t\tword2 = 0;\n\t\tword3 = 0;\n\t}\n\n\t// VTX_DWORD0\n\tenum class VTX_INST\n\t{\n\t\t_VTX_INST_FETCH = 0,\n\t\t_VTX_INST_SEMANTIC = 1,\n\t\t_VTX_INST_MEM = 2\n\t};\n\n\tenum class SRC_SEL\n\t{\n\t\tSEL_X = 0,\n\t\tSEL_Y = 1,\n\t\tSEL_Z = 2,\n\t\tSEL_W = 3,\n\t};\n\n\tenum class DST_SEL\n\t{\n\t\tSEL_X = 0,\n\t\tSEL_Y = 1,\n\t\tSEL_Z = 2,\n\t\tSEL_W = 3,\n\t\tSEL_0 = 4, // constant 0.0\n\t\tSEL_1 = 5, // constant 1.0\n\t\tSEL_RESERVED = 6,\n\t\tSEL_MASK = 7,\n\t};\n\n\tenum class NUM_FORMAT_ALL // NFA\n\t{\n\t\tNUM_FORMAT_NORM = 0, // normalized to float (-1.0 to 1.0 for signed, 0.0 to 1.0 for unsigned)\n\t\tNUM_FORMAT_INT = 1, // interpreted as integer\n\t\tNUM_FORMAT_SCALED = 2,\n\t};\n\n\tenum class FORMAT_COMP\n\t{\n\t\tCOMP_UNSIGNED = 0,\n\t\tCOMP_SIGNED = 1,\n\t};\n\n\tenum class SRF_MODE\n\t{\n\t\tSRF_MODE_ZERO_CLAMP_MINUS_ONE = 0,\n\t\tSRF_MODE_NO_ZERO = 1,\n\t};\n\n\t// fields todo:\n\t// FETCH_WHOLE_QUAD\n\t// MEGA_FETCH_COUNT\n\t// MEGA_FETCH (word2)\n\t// ALT_CONST (word2)\n\n\tVTX_INST getField_VTX_INST() const // alias opcode\n\t{\n\t\treturn (VTX_INST)((word0 >> 0) & 0x1F);\n\t}\n\n\tLatteConst::VertexFetchType2 getField_FETCH_TYPE() const\n\t{\n\t\treturn (LatteConst::VertexFetchType2)((word0 >> 5) & 0x3);\n\t}\n\n\tuint32 getField_BUFFER_ID() const\n\t{\n\t\treturn (word0 >> 8) & 0xFF;\n\t}\n\n\tuint32 getField_SRC_GPR() const\n\t{\n\t\treturn (word0 >> 16) & 0x7F;\n\t}\n\t\n\tbool getField_SRC_REL() const\n\t{\n\t\treturn ((word0 >> 23) & 1) != 0;\n\t}\n\n\tSRC_SEL getField_SRC_SEL_X() const\n\t{\n\t\treturn (SRC_SEL)((word0 >> 24) & 0x3);\n\t}\n\n\t// WORD1 depends on instruction type but some fields are shared\n\t// VTX_DWORD1 / VTX_DWORD1_GPR / VTX_DWORD1_SEM\n\n\tDST_SEL getField_DST_SEL(uint32 index) const // shared field\n\t{\n\t\tcemu_assert_debug(index <= 3);\n\t\treturn (DST_SEL)((word1 >> (9 + index*3)) & 0x7);\n\t}\n\n\tbool getField_USE_CONST_FIELDS() const  // shared field\n\t{\n\t\treturn ((word1 >> 21) & 1) != 0;\n\t}\n\n\tLatteConst::VertexFetchFormat getField_DATA_FORMAT() const // shared field\n\t{\n\t\treturn (LatteConst::VertexFetchFormat)((word1 >> 22) & 0x3F);\n\t}\n\n\tNUM_FORMAT_ALL getField_NUM_FORMAT_ALL() const // shared field\n\t{\n\t\treturn (NUM_FORMAT_ALL)((word1 >> 28) & 3);\n\t}\n\n\tFORMAT_COMP getField_FORMAT_COMP_ALL() const // shared field\n\t{\n\t\treturn (FORMAT_COMP)((word1 >> 30) & 1);\n\t}\n\n\tSRF_MODE getField_SRF_MODE_ALL() const // shared field\n\t{\n\t\treturn (SRF_MODE)((word1 >> 30) & 1);\n\t}\n\n\t// VTX_DWORD1_SEM specific fields (VTX_INST_SEMANTIC)\n\tuint32 getFieldSEM_SEMANTIC_ID() const\n\t{\n\t\treturn ((word1 >> 0) & 0xFF);\n\t}\n\n\t// VTX_DWORD1_GPR specific fields (VTX_INST_FETCH?)\n\t// todo\n\n\t// VTX_DWORD2\n\tuint32 getField_OFFSET() const // shared field\n\t{\n\t\treturn ((word2 >> 0) & 0xFFFF);\n\t}\n\n\tLatteConst::VertexFetchEndianMode getField_ENDIAN_SWAP() const // shared field\n\t{\n\t\treturn (LatteConst::VertexFetchEndianMode)((word2 >> 16) & 0x3);\n\t}\n\n\tbool getField_CONST_BUF_NO_STRIDE() const // shared field\n\t{\n\t\treturn ((word2 >> 18) & 0x1) != 0;\n\t}\n\n\t// writing\n\tLatteClauseInstruction_VTX& setField_VTX_INST(VTX_INST inst)\n\t{\n\t\tword0 &= ~(0x1F << 0);\n\t\tword0 |= ((uint32)inst << 0);\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_FETCH_TYPE(LatteConst::VertexFetchType2 fetchType)\n\t{\n\t\tword0 &= ~(0x3 << 5);\n\t\tword0 |= ((uint32)fetchType << 5);\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_BUFFER_ID(uint32 bufferId)\n\t{\n\t\tword0 &= ~(0xFF << 8);\n\t\tword0 |= (bufferId << 8);\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_SRC_GPR(uint32 srcGPR)\n\t{\n\t\tword0 &= ~(0x7F << 16);\n\t\tword0 |= (srcGPR << 16);\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_SRC_REL(bool isRel)\n\t{\n\t\tif(isRel)\n\t\t\tword0 |= (1 << 23);\n\t\telse\n\t\t\tword0 &= ~(0x1 << 23);\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_SRC_SEL_X(SRC_SEL srcSel)\n\t{\n\t\tword0 &= ~(0x3 << 24);\n\t\tword0 |= ((uint32)srcSel << 24);\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setFieldSEM_SEMANTIC_ID(uint32 semanticId)\n\t{\n\t\tcemu_assert_debug(semanticId <= 0xFF);\n\t\tword1 &= ~(0xFF);\n\t\tword1 |= ((uint32)semanticId);\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_OFFSET(uint32 offset)\n\t{\n\t\tcemu_assert_debug(offset < 0x10000);\n\t\tword2 &= ~(0xFFFF << 0);\n\t\tword2 |= ((uint32)offset);\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_DATA_FORMAT(LatteConst::VertexFetchFormat fetchFormat)\n\t{\n\t\t word1 &= ~(0x3F << 22);\n\t\t word1 |= ((uint32)fetchFormat << 22);\n\t\t return *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_NUM_FORMAT_ALL(NUM_FORMAT_ALL nfa)\n\t{\n\t\tword1 &= ~(0x3 << 28);\n\t\tword1 |= ((uint32)nfa << 28);\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_FORMAT_COMP_ALL(FORMAT_COMP componentFormat)\n\t{\n\t\tword1 &= ~(0x1 << 30);\n\t\tword1 |= ((uint32)componentFormat << 30);\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_DST_SEL(uint32 index, DST_SEL dstSel)\n\t{\n\t\tcemu_assert_debug(index <= 3);\n\t\tword1 &= ~(0x7 << (9 + index * 3));\n\t\tword1 |= ((uint32)dstSel << (9 + index * 3));\n\t\treturn *this;\n\t}\n\n\tLatteClauseInstruction_VTX& setField_ENDIAN_SWAP(LatteConst::VertexFetchEndianMode endianSwap)\n\t{\n\t\tword2 &= ~(0x3 << 16);\n\t\tword2 |= ((uint32)endianSwap << 16);\n\t\treturn *this;\n\t}\n\n\nprotected:\n\tuint32 word0;\n\tuint32 word1;\n\tuint32 word2;\n\tuint32 word3; // not used\n};\n\nstatic_assert(sizeof(LatteClauseInstruction_VTX) == 16);\n\nclass LatteClauseInstruction_ALU\n{\npublic:\n\tenum OPCODE_OP2\n\t{\n\t\tADD = 0x00,\n\t\tMUL = 0x01,\n\t\tMUL_IEEE = 0x02,\n\t\t//#define ALU_OP2_INST_MAX\t\t\t(0x003)\n\t\t//#define ALU_OP2_INST_MIN\t\t\t(0x004)\n\t\t//#define ALU_OP2_INST_MAX_DX10\t\t(0x005)\n\t\t//#define ALU_OP2_INST_SETE\t\t\t(0x008)\n\t\t//#define ALU_OP2_INST_SETGT\t\t\t(0x009)\n\t\t//#define ALU_OP2_INST_SETGE\t\t\t(0x00A)\n\t\t//#define ALU_OP2_INST_SETNE\t\t\t(0x00B)\n\t\t//#define ALU_OP2_INST_SETE_DX10\t\t(0x00C)\n\t\t//#define ALU_OP2_INST_SETGT_DX10\t\t(0x00D)\n\t\t//#define ALU_OP2_INST_SETGE_DX10\t\t(0x00E)\n\t\t//#define ALU_OP2_INST_SETNE_DX10\t\t(0x00F)\n\t\t//#define ALU_OP2_INST_FLOOR\t\t\t(0x014)\n\t\t//#define ALU_OP2_INST_FRACT\t\t\t(0x010)\n\t\t//#define ALU_OP2_INST_TRUNC\t\t\t(0x011)\n\t\t//#define ALU_OP2_INST_RNDNE\t\t\t(0x013)\n\t\t//#define ALU_OP2_INST_MOVA_FLOOR\t\t(0x016) // changes address register\n\t\t//#define ALU_OP2_INST_MOVA_INT\t\t(0x018) // changes address register\n\t\tMOV = 0x19,\n\t\t//#define ALU_OP2_INST_NOP\t\t\t(0x01A)\n\t\t//#define ALU_OP2_INST_PRED_SETE\t\t(0x020)\n\t\t//#define ALU_OP2_INST_PRED_SETGT\t\t(0x021)\n\t\t//#define ALU_OP2_INST_PRED_SETGE\t\t(0x022)\n\t\t//#define ALU_OP2_INST_PRED_SETNE\t\t(0x023)\n\t\t//#define ALU_OP2_INST_AND_INT\t\t(0x030) // integer instruction\n\t\t//#define ALU_OP2_INST_OR_INT\t\t\t(0x031) // integer instruction\n\t\t//#define ALU_OP2_INST_XOR_INT\t\t(0x032) // integer instruction\n\t\t//#define ALU_OP2_INST_NOT_INT\t\t(0x033) // integer instruction\n\t\t//#define ALU_OP2_INST_ADD_INT\t\t(0x034) // integer instruction\n\t\t//#define ALU_OP2_INST_SUB_INT\t\t(0x035) // integer instruction\n\t\t//#define ALU_OP2_INST_MAX_INT\t\t(0x036) // integer instruction\n\t\t//#define ALU_OP2_INST_MIN_INT\t\t(0x037) // integer instruction\n\t\t//#define ALU_OP2_INST_SETE_INT\t\t(0x03A) // integer instruction\n\t\t//#define ALU_OP2_INST_SETGT_INT\t\t(0x03B) // integer instruction\n\t\t//#define ALU_OP2_INST_SETGE_INT\t\t(0x03C) // integer instruction\n\t\t//#define ALU_OP2_INST_SETNE_INT\t\t(0x03D) // integer instruction\n\t\t//#define ALU_OP2_INST_SETGT_UINT\t\t(0x03E) // integer instruction\n\t\t//#define ALU_OP2_INST_SETGE_UINT\t\t(0x03F) // integer instruction\n\t\t//#define ALU_OP2_INST_PRED_SETE_INT\t(0x042) // integer instruction \n\t\t//#define ALU_OP2_INST_PRED_SETGT_INT\t(0x043) // integer instruction\n\t\t//#define ALU_OP2_INST_PRED_SETGE_INT\t(0x044) // integer instruction\n\t\t//#define ALU_OP2_INST_PRED_SETNE_INT\t(0x045) // integer instruction \n\t\t//#define ALU_OP2_INST_KILLE\t\t\t(0x02C)\n\t\t//#define ALU_OP2_INST_KILLGT\t\t\t(0x02D)\n\t\t//#define ALU_OP2_INST_KILLGE\t\t\t(0x02E)\n\t\t//#define ALU_OP2_INST_KILLE_INT\t\t(0x046)\n\t\t//#define ALU_OP2_INST_KILLGT_INT\t\t(0x047)\n\t\t//#define ALU_OP2_INST_KILLNE_INT\t\t(0x049)\n\t\tDOT4 = 0x50,\n\t\t//#define ALU_OP2_INST_DOT4_IEEE\t\t(0x051)\n\t\tCUBE = 0x52,\n\t\tEXP_IEEE = 0x61,\n\t\tLOG_CLAMPED = 0x62,\n\t\tLOG_IEEE = 0x63,\n\t\tSQRT_IEEE = 0x6A,\n\t\tSIN = 0x06E,\n\t\tCOS = 0x06F,\n\t\tRECIP_FF = 0x65,\n\t\tRECIP_IEEE = 0x66,\n\t\tRECIPSQRT_CLAMPED = 0x67,\n\t\tRECIPSQRT_FF = 0x68,\n\t\tRECIPSQRT_IEEE = 0x69,\n\t\tFLT_TO_INT = 0x6B,\n\t\tINT_TO_FLOAT = 0x6C,\n\t\tUINT_TO_FLOAT = 0x6D,\n\t\tASHR_INT = 0x70,\n\t\tLSHR_INT = 0x71,\n\t\tLSHL_INT = 0x72,\n\t\tMULLO_INT = 0x73,\n\t\tMULLO_UINT = 0x75,\n\t\tFLT_TO_UINT = 0x79,\n\t};\n\n\tbool isOP3() const\n\t{\n\t\tuint32 alu_inst13_5 = (word1 >> 13) & 0x1F;\n\t\treturn alu_inst13_5 >= 0x8;\n\t}\n\n\tOPCODE_OP2 getOP2Code() const\n\t{\n\t\tuint32 alu_inst7_11 = (word1 >> 7) & 0x7FF;\n\t\treturn (OPCODE_OP2)alu_inst7_11;\n\t}\n\n\tbool isLastInGroup() const\n\t{\n\t\treturn (word0 & 0x80000000) != 0;\n\t}\n\n\tconst class LatteClauseInstruction_ALU_OP2* getOP2Instruction() const\n\t{\n\t\treturn (const class LatteClauseInstruction_ALU_OP2*)this;\n\t}\n\nprotected:\n\tconst uint32 word0 = 0;\n\tconst uint32 word1 = 0;\n};\n\nclass LatteALUSrcSel\n{\npublic:\n\tLatteALUSrcSel(const uint16 op) : m_op(op) {};\n\n\tbool isGPR() const { return m_op < 128; };\n\tbool isAnyConst() const { return m_op >= 248 && m_op <= 252; };\n\tbool isConst_0F() const { return m_op == 248; };\n\tbool isLiteral() const { return m_op == 253; };\n\tbool isCFile() const { return m_op >= 256; };\n\n\tuint32 getGPR() const { return m_op; };\n\tuint32 getCFile() const { return (m_op & 0xFF); };\n\nprivate:\n\tconst uint16 m_op; // 0 - 511\n};\n\nclass LatteClauseInstruction_ALU_OP2 : public LatteClauseInstruction_ALU\n{\npublic:\n\tuint32 getDestGpr() const\n\t{\n\t\treturn (word1 >> 21) & 0x7F;\n\t}\n\n\tuint32 getDestElem() const\n\t{\n\t\treturn (word1 >> 29) & 3;\n\t}\n\n\tbool getDestRel() const\n\t{\n\t\treturn ((word1 >> 28) & 1) != 0;\n\t}\n\n\tbool getDestClamp() const\n\t{\n\t\treturn ((word1 >> 31) & 1) != 0;\n\t}\n\n\tbool getWriteMask() const\n\t{\n\t\treturn ((word1 >> 4) & 1) != 0;\n\t}\n\n\tuint8 getOMod() const // use enum?\n\t{\n\t\treturn (word1 >> 5) & 3;\n\t}\n\n\tconst LatteALUSrcSel getSrc0Sel() const\n\t{\n\t\treturn LatteALUSrcSel((word0 >> 0) & 0x1FF);\n\t}\n\n\tconst uint8 getSrc0Chan() const\n\t{\n\t\treturn (word0 >> 10) & 0x3;\n\t}\n\n\tconst LatteALUSrcSel getSrc1Sel() const\n\t{\n\t\treturn LatteALUSrcSel((word0 >> 13) & 0x1FF);\n\t}\n\n\tconst uint8 getSrc1Chan() const\n\t{\n\t\treturn (word0 >> 23) & 0x3;\n\t}\n\n\tbool isSrc0Neg() const\n\t{\n\t\treturn ((word0 >> 12) & 0x1) != 0;\n\t}\n\n\tbool isSrc1Neg() const\n\t{\n\t\treturn ((word0 >> 25) & 0x1) != 0;\n\t}\n\n\tbool isSrc0Rel() const\n\t{\n\t\treturn ((word0 >> 9) & 0x1) != 0;\n\t}\n\n\tbool isSrc1Rel() const\n\t{\n\t\treturn ((word0 >> 22) & 0x1) != 0;\n\t}\n\n\tuint8 getIndexMode() const\n\t{\n\t\treturn (word0 >> 26) & 7;;\n\t}\n\n\tbool isTranscedentalUnit() const\n\t{\n\t\tconst uint32 op2 = this->getOP2Code();\n\t\tswitch (op2)\n\t\t{\n\t\tcase COS:\n\t\tcase SIN:\n\t\tcase RECIP_FF: // todo: verify\n\t\tcase RECIP_IEEE: // todo: verify\n\t\tcase RECIPSQRT_IEEE: // todo: verify\n\t\tcase RECIPSQRT_CLAMPED: // todo: verify\n\t\tcase RECIPSQRT_FF: // todo: verify\n\t\tcase MULLO_INT:\n\t\tcase MULLO_UINT:\n\t\tcase FLT_TO_INT:\n\t\tcase FLT_TO_UINT:\n\t\tcase INT_TO_FLOAT:\n\t\tcase UINT_TO_FLOAT:\n\t\tcase LOG_CLAMPED:\n\t\tcase LOG_IEEE:\n\t\tcase EXP_IEEE:\n\t\tcase SQRT_IEEE:\n\t\t\treturn true;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\treturn false;\n\t}\n\n};\n\nstatic_assert(sizeof(LatteClauseInstruction_ALU) == 8);\n\n"
  },
  {
    "path": "src/Cafe/HW/Latte/ISA/LatteReg.h",
    "content": "#pragma once\n\nnamespace Latte\n{\n\t// common enums\n\tenum class E_DIM : uint32 // shared between Latte backend and GX2 code\n\t{\n\t\tDIM_1D = 0,\n\t\tDIM_2D = 1,\n\t\tDIM_3D = 2,\n\t\tDIM_CUBEMAP = 3,\n\t\tDIM_1D_ARRAY = 4,\n\t\tDIM_2D_ARRAY = 5,\n\t\tDIM_2D_MSAA = 6,\n\t\tDIM_2D_ARRAY_MSAA = 7\n\t};\n\n\tenum class E_AAMODE : uint32 // shared between Latte backend and GX2 code\n\t{\n\t\tAA_1X = 0,\n\t\tAA_2X = 1,\n\t\tAA_4X = 2,\n\t\tAA_8X = 3,\n\t};\n\n\tenum class E_HWTILEMODE\n\t{\n\t\tTM_LINEAR_GENERAL = 0,  // linear (pitch must be aligned to 8?)\n\t\tTM_LINEAR_ALIGNED = 1,  // pitch must be multiple of 64 pixels?\n\n\t\tTM_1D_TILED_THIN1 = 2,  // no macro tiling, 8x8 micro tiles\n\t\tTM_1D_TILED_THICK = 3,  // no macro tiling, 8x8x4 micro tiles\n\n\t\tTM_2D_TILED_THIN1 = 4,  // 4x2\n\t\tTM_2D_TILED_THIN2 = 5,  // 2x4\n\t\tTM_2D_TILED_THIN4 = 6,  // 1x8\n\t\tTM_2D_TILED_THICK = 7,  // 4x2x1\n\n\t\tTM_2B_TILED_THIN1 = 8,  // 4x2\n\t\tTM_2B_TILED_THIN2 = 9,  // 2x4\n\t\tTM_2B_TILED_THIN4 = 10, // 1x8\n\t\tTM_2B_TILED_THICK = 11, // 4x2x1\n\n\t\tTM_3D_TILED_THIN1 = 12, // 4x2\n\t\tTM_3D_TILED_THICK = 13, // 4x2x1\n\n\t\tTM_3B_TILED_THIN1 = 14, // 4x2\n\t\tTM_3B_TILED_THICK = 15, // 4x2x1\n\t};\n\n\tenum class E_GX2TILEMODE : uint32\n\t{\n\t\t// same as E_TILEMODE but contains additional options with special meaning\n\t\tTM_LINEAR_GENERAL = 0,\n\t\tTM_LINEAR_ALIGNED = 1,\n\n\t\t// micro-tiled\n\t\tTM_1D_TILED_THIN1 = 2,\n\t\tTM_1D_TILED_THICK = 3,\n\n\t\t// macro-tiled\n\t\tTM_2D_TILED_THIN1 = 4,\n\t\tTM_2D_TILED_THIN2 = 5,\n\t\tTM_2D_TILED_THIN4 = 6,\n\t\tTM_2D_TILED_THICK = 7,\n\n\t\tTM_2B_TILED_THIN1 = 8,\n\t\tTM_2B_TILED_THIN2 = 9,\n\t\tTM_2B_TILED_THIN4 = 10,\n\t\tTM_2B_TILED_THICK = 11,\n\n\t\tTM_3D_TILED_THIN1 = 12,\n\t\tTM_3D_TILED_THICK = 13,\n\n\t\tTM_3B_TILED_THIN1 = 14,\n\t\tTM_3B_TILED_THICK = 15,\n\n\t\t// special\n\t\tTM_LINEAR_SPECIAL = 16,\n\t\tTM_32_SPECIAL\t  = 32,\n\t};\n\n\tinline E_HWTILEMODE MakeHWTileMode(const E_GX2TILEMODE gx2Tilemode)\n\t{\n\t\treturn (E_HWTILEMODE)((uint32)gx2Tilemode & 0xF);\n\t}\n\n\tinline E_GX2TILEMODE MakeGX2TileMode(const E_HWTILEMODE hwTilemode)\n\t{\n\t\treturn (E_GX2TILEMODE)hwTilemode;\n\t}\n\n\tinline bool TM_IsMacroTiled(const E_HWTILEMODE tm)\n\t{\n\t\treturn (uint32)tm >= 4;\n\t}\n\n\tinline bool TM_IsMacroTiled(const E_GX2TILEMODE tm)\n\t{\n\t\treturn (uint32)tm >= 4 && (uint32)tm != 16;\n\t}\n\n\tinline bool TM_IsBankSwapped(const E_HWTILEMODE tileMode)\n\t{\n\t\treturn\n\t\t\ttileMode == E_HWTILEMODE::TM_2B_TILED_THIN1 ||\n\t\t\ttileMode == E_HWTILEMODE::TM_2B_TILED_THIN2 ||\n\t\t\ttileMode == E_HWTILEMODE::TM_2B_TILED_THIN4 ||\n\t\t\ttileMode == E_HWTILEMODE::TM_2B_TILED_THICK ||\n\t\t\ttileMode == E_HWTILEMODE::TM_3B_TILED_THIN1 ||\n\t\t\ttileMode == E_HWTILEMODE::TM_3B_TILED_THICK;\n\t}\n\n\tenum class E_HWSURFFMT\n\t{\n\t\tINVALID_FORMAT = 0,\n\t\t// hardware formats only\n\t\tHWFMT_8 = 0x1,\n\t\tHWFMT_4_4 = 0x2,\n\t\tHWFMT_3_3_2 = 0x3,\n\t\tHWFMT_16 = 0x5,\n\t\tHWFMT_16_FLOAT = 0x6,\n\t\tHWFMT_8_8 = 0x7,\n\t\tHWFMT_5_6_5 = 0x8,\n\t\tHWFMT_6_5_5 = 0x9,\n\t\tHWFMT_1_5_5_5 = 0xA,\n\t\tHWFMT_4_4_4_4 = 0xB,\n\t\tHWFMT_5_5_5_1 = 0xC,\n\t\tHWFMT_32 = 0xD,\n\t\tHWFMT_32_FLOAT = 0xE,\n\t\tHWFMT_16_16 = 0xF,\n\t\tHWFMT_16_16_FLOAT = 0x10,\n\t\tHWFMT_8_24 = 0x11,\n\t\tHWFMT_8_24_FLOAT = 0x12,\n\t\tHWFMT_24_8 = 0x13,\n\t\tHWFMT_24_8_FLOAT = 0x14,\n\t\tHWFMT_10_11_11 = 0x15,\n\t\tHWFMT_10_11_11_FLOAT = 0x16,\n\t\tHWFMT_11_11_10 = 0x17,\n\t\tHWFMT_11_11_10_FLOAT = 0x18,\n\t\tHWFMT_2_10_10_10 = 0x19,\n\t\tHWFMT_8_8_8_8 = 0x1A,\n\t\tHWFMT_10_10_10_2 = 0x1B,\n\t\tHWFMT_X24_8_32_FLOAT = 0x1C,\n\t\tHWFMT_32_32 = 0x1D,\n\t\tHWFMT_32_32_FLOAT = 0x1E,\n\t\tHWFMT_16_16_16_16 = 0x1F,\n\t\tHWFMT_16_16_16_16_FLOAT = 0x20,\n\t\tHWFMT_32_32_32_32 = 0x22,\n\t\tHWFMT_32_32_32_32_FLOAT = 0x23,\n\t\tHWFMT_BC1 = 0x31,\n\t\tHWFMT_BC2 = 0x32,\n\t\tHWFMT_BC3 = 0x33,\n\t\tHWFMT_BC4 = 0x34,\n\t\tHWFMT_BC5 = 0x35,\n\n\t\t// these formats exist in R600/R700 documentation, but GX2 doesn't seem to handle them. Are they supported?\n\t\tU_HWFMT_BC6 = 0x36,\n\t\tU_HWFMT_BC7 = 0x37,\n\t\tU_HWFMT_32_32_32 = 0x2F,\n\t\tU_HWFMT_32_32_32_FLOAT = 0x30,\n\n\n\t};\n\n\tenum class E_GX2SURFFMT // GX2 surface format\n\t{\n\t\tINVALID_FORMAT = 0,\n\t\t// base hardware formats (shared with E_HWSURFFMT)\n\t\tHWFMT_8 = 0x1,\n\t\tHWFMT_4_4 = 0x2,\n\t\tHWFMT_3_3_2 = 0x3,\n\t\tHWFMT_16 = 0x5,\n\t\tHWFMT_16_FLOAT = 0x6,\n\t\tHWFMT_8_8 = 0x7,\n\t\tHWFMT_5_6_5 = 0x8,\n\t\tHWFMT_6_5_5 = 0x9,\n\t\tHWFMT_1_5_5_5 = 0xA,\n\t\tHWFMT_4_4_4_4 = 0xB,\n\t\tHWFMT_5_5_5_1 = 0xC,\n\t\tHWFMT_32 = 0xD,\n\t\tHWFMT_32_FLOAT = 0xE,\n\t\tHWFMT_16_16 = 0xF,\n\t\tHWFMT_16_16_FLOAT = 0x10,\n\t\tHWFMT_8_24 = 0x11,\n\t\tHWFMT_8_24_FLOAT = 0x12,\n\t\tHWFMT_24_8 = 0x13,\n\t\tHWFMT_24_8_FLOAT = 0x14,\n\t\tHWFMT_10_11_11 = 0x15,\n\t\tHWFMT_10_11_11_FLOAT = 0x16,\n\t\tHWFMT_11_11_10 = 0x17,\n\t\tHWFMT_11_11_10_FLOAT = 0x18,\n\t\tHWFMT_2_10_10_10 = 0x19,\n\t\tHWFMT_8_8_8_8 = 0x1A,\n\t\tHWFMT_10_10_10_2 = 0x1B,\n\t\tHWFMT_X24_8_32_FLOAT = 0x1C,\n\t\tHWFMT_32_32 = 0x1D,\n\t\tHWFMT_32_32_FLOAT = 0x1E,\n\t\tHWFMT_16_16_16_16 = 0x1F,\n\t\tHWFMT_16_16_16_16_FLOAT = 0x20,\n\t\tHWFMT_32_32_32_32 = 0x22,\n\t\tHWFMT_32_32_32_32_FLOAT = 0x23,\n\t\tHWFMT_BC1 = 0x31,\n\t\tHWFMT_BC2 = 0x32,\n\t\tHWFMT_BC3 = 0x33,\n\t\tHWFMT_BC4 = 0x34,\n\t\tHWFMT_BC5 = 0x35,\n\n\t\t// GX2 extra format bits\n\t\tFMT_BIT_INT = 0x100,\n\t\tFMT_BIT_SIGNED = 0x200,\n\t\tFMT_BIT_SRGB = 0x400,\n\t\tFMT_BIT_FLOAT = 0x800,\n\n\t\t// GX2 formats\n\t\tR4_G4_UNORM = HWFMT_4_4,\n\n\t\tR5_G6_B5_UNORM = HWFMT_5_6_5,\n\t\tR5_G5_B5_A1_UNORM = HWFMT_1_5_5_5,\n\t\tR4_G4_B4_A4_UNORM = HWFMT_4_4_4_4,\n\t\tA1_B5_G5_R5_UNORM = HWFMT_5_5_5_1,\n\n\t\tR8_UNORM = HWFMT_8,\n\t\tR8_SNORM = (HWFMT_8 | FMT_BIT_SIGNED),\n\t\tR8_UINT = (HWFMT_8 | FMT_BIT_INT),\n\t\tR8_SINT = (HWFMT_8 | FMT_BIT_INT | FMT_BIT_SIGNED),\n\n\t\tR8_G8_UNORM = HWFMT_8_8,\n\t\tR8_G8_SNORM = (HWFMT_8_8 | FMT_BIT_SIGNED),\n\t\tR8_G8_UINT = (HWFMT_8_8 | FMT_BIT_INT),\n\t\tR8_G8_SINT = (HWFMT_8_8 | FMT_BIT_INT | FMT_BIT_SIGNED),\n\n\t\tR8_G8_B8_A8_UNORM = HWFMT_8_8_8_8,\n\t\tR8_G8_B8_A8_SNORM = (HWFMT_8_8_8_8 | FMT_BIT_SIGNED),\n\t\tR8_G8_B8_A8_UINT = (HWFMT_8_8_8_8 | FMT_BIT_INT),\n\t\tR8_G8_B8_A8_SINT = (HWFMT_8_8_8_8 | FMT_BIT_INT | FMT_BIT_SIGNED),\n\t\tR8_G8_B8_A8_SRGB = (HWFMT_8_8_8_8 | FMT_BIT_SRGB),\n\n\t\tR10_G10_B10_A2_UNORM = HWFMT_2_10_10_10,\n\t\tR10_G10_B10_A2_SNORM = (HWFMT_2_10_10_10 | FMT_BIT_SIGNED),\n\t\tR10_G10_B10_A2_UINT = (HWFMT_2_10_10_10 | FMT_BIT_INT),\n\t\tR10_G10_B10_A2_SINT = (HWFMT_2_10_10_10 | FMT_BIT_INT | FMT_BIT_SIGNED),\n\t\tR10_G10_B10_A2_SRGB = (HWFMT_2_10_10_10 | FMT_BIT_SRGB),\n\n\t\tA2_B10_G10_R10_UNORM = HWFMT_10_10_10_2,\n\t\tA2_B10_G10_R10_UINT = (HWFMT_10_10_10_2 | FMT_BIT_INT),\n\n\t\tR16_UNORM = HWFMT_16,\n\t\tR16_SNORM = (HWFMT_16 | FMT_BIT_SIGNED),\n\t\tR16_UINT = (HWFMT_16 | FMT_BIT_INT),\n\t\tR16_SINT = (HWFMT_16 | FMT_BIT_INT | FMT_BIT_SIGNED),\n\t\tR16_FLOAT = (HWFMT_16_FLOAT | FMT_BIT_FLOAT),\n\n\t\tR16_G16_UNORM = HWFMT_16_16,\n\t\tR16_G16_SNORM = (HWFMT_16_16 | FMT_BIT_SIGNED),\n\t\tR16_G16_UINT = (HWFMT_16_16 | FMT_BIT_INT),\n\t\tR16_G16_SINT = (HWFMT_16_16 | FMT_BIT_INT | FMT_BIT_SIGNED),\n\t\tR16_G16_FLOAT = (HWFMT_16_16_FLOAT | FMT_BIT_FLOAT),\n\n\t\tR16_G16_B16_A16_UNORM = HWFMT_16_16_16_16,\n\t\tR16_G16_B16_A16_SNORM = (HWFMT_16_16_16_16 | FMT_BIT_SIGNED),\n\t\tR16_G16_B16_A16_UINT = (HWFMT_16_16_16_16 | FMT_BIT_INT),\n\t\tR16_G16_B16_A16_SINT = (HWFMT_16_16_16_16 | FMT_BIT_INT | FMT_BIT_SIGNED),\n\t\tR16_G16_B16_A16_FLOAT = (HWFMT_16_16_16_16_FLOAT | FMT_BIT_FLOAT),\n\n\n\t\tR24_X8_UNORM = (HWFMT_8_24),\n\t\tR24_X8_FLOAT = (HWFMT_8_24 | FMT_BIT_FLOAT),\n\t\tX24_G8_UINT = (HWFMT_8_24 | FMT_BIT_INT),\n\t\tR32_X8_FLOAT = (HWFMT_X24_8_32_FLOAT | FMT_BIT_FLOAT), // R32_X8_FLOAT\n\t\tX32_G8_UINT_X24 = (HWFMT_X24_8_32_FLOAT | FMT_BIT_INT), // X32_G8_UINT\n\n\t\tR11_G11_B10_FLOAT = (HWFMT_10_11_11_FLOAT | FMT_BIT_FLOAT),\n\n\t\t// 32bit component formats do not support SNORM/UNORM (at least GX2 doesnt expose it)\n\t\tR32_UINT = (HWFMT_32 | FMT_BIT_INT),\n\t\tR32_SINT = (HWFMT_32 | FMT_BIT_INT | FMT_BIT_SIGNED),\n\t\tR32_FLOAT = (HWFMT_32_FLOAT | FMT_BIT_FLOAT),\n\n\t\tR32_G32_UINT = (HWFMT_32_32 | FMT_BIT_INT),\n\t\tR32_G32_SINT = (HWFMT_32_32 | FMT_BIT_INT | FMT_BIT_SIGNED),\n\t\tR32_G32_FLOAT = (HWFMT_32_32_FLOAT | FMT_BIT_FLOAT),\n\n\t\tR32_G32_B32_A32_UINT = (HWFMT_32_32_32_32 | FMT_BIT_INT),\n\t\tR32_G32_B32_A32_SINT = (HWFMT_32_32_32_32 | FMT_BIT_INT | FMT_BIT_SIGNED),\n\t\tR32_G32_B32_A32_FLOAT = (HWFMT_32_32_32_32_FLOAT | FMT_BIT_FLOAT),\n\n\t\t// depth\n\t\tD24_S8_UNORM = (HWFMT_8_24),\n\t\tD24_S8_FLOAT = (HWFMT_8_24 | FMT_BIT_FLOAT),\n\t\tD32_S8_FLOAT = (HWFMT_X24_8_32_FLOAT | FMT_BIT_FLOAT),\n\t\tD16_UNORM = HWFMT_16,\n\t\tD32_FLOAT = (HWFMT_32_FLOAT | FMT_BIT_FLOAT),\n\n\t\t// compressed formats\n\t\tBC1_UNORM = (HWFMT_BC1),\n\t\tBC1_SRGB = (HWFMT_BC1 | FMT_BIT_SRGB),\n\t\tBC2_UNORM = (HWFMT_BC2),\n\t\tBC2_SRGB = (HWFMT_BC2 | FMT_BIT_SRGB),\n\t\tBC3_UNORM = (HWFMT_BC3),\n\t\tBC3_SRGB = (HWFMT_BC3 | FMT_BIT_SRGB),\n\t\tBC4_UNORM = (HWFMT_BC4),\n\t\tBC4_SNORM = (HWFMT_BC4 | FMT_BIT_SIGNED),\n\t\tBC5_UNORM = (HWFMT_BC5),\n\t\tBC5_SNORM = (HWFMT_BC5 | FMT_BIT_SIGNED),\n\n\t\t// special\n\t\tNV12_UNORM = 0x81,\n\t};\n\tDEFINE_ENUM_FLAG_OPERATORS(E_GX2SURFFMT);\n\n\tinline uint32 GetFormatBits(const Latte::E_HWSURFFMT hwFmt)\n\t{\n\t\tconst uint8 sBitsTable[0x40] = {\n\t\t0x00,0x08,0x08,0x00,0x00,0x10,0x10,0x10,\n\t\t0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x20,\n\t\t0x20,0x20,0x00,0x20,0x00,0x00,0x20,0x00,\n\t\t0x00,0x20,0x20,0x20,0x40,0x40,0x40,0x40,\n\t\t0x40,0x00,0x80,0x80,0x00,0x00,0x00,0x10,\n\t\t0x10,0x20,0x20,0x20,0x00,0x00,0x00,0x60,\n\t\t0x60,0x40,0x80,0x80,0x40,0x80,0x00,0x00,\n\t\t0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\n\t\t};\n\t\tcemu_assert((uint32)hwFmt < 0x40);\n\t\treturn sBitsTable[(uint32)hwFmt];\n\t}\n\n\tinline uint32 GetFormatBits(const Latte::E_GX2SURFFMT gx2Fmt)\n\t{\n\t\treturn GetFormatBits((Latte::E_HWSURFFMT)((uint32)gx2Fmt & 0x3F));\n\t}\n\n\tinline E_HWSURFFMT GetHWFormat(E_GX2SURFFMT format)\n\t{\n\t\treturn (E_HWSURFFMT)((uint32)format & 0x3F);\n\t}\n\n\tinline bool IsCompressedFormat(Latte::E_HWSURFFMT format)\n\t{\n\t\treturn (uint32)format >= 0x31 && (uint32)format <= 0x35;\n\t}\n\n\tinline bool IsCompressedFormat(Latte::E_GX2SURFFMT format)\n\t{\n\t\treturn IsCompressedFormat((Latte::E_HWSURFFMT)((uint32)format & 0x3F));\n\t}\n\n\tinline bool IsMSAA(Latte::E_DIM dim)\n\t{\n\t\treturn dim == E_DIM::DIM_2D_MSAA || dim == E_DIM::DIM_2D_ARRAY_MSAA;\n\t}\n\n\tenum GPU_LIMITS\n\t{\n\t\tNUM_VERTEX_BUFFERS = 16,\n\t\tNUM_TEXTURES_PER_STAGE = 18,\n\t\tNUM_SAMPLERS_PER_STAGE = 18, // is this 16 or 18?\n\t\tNUM_COLOR_ATTACHMENTS = 8,\n\t};\n\n\tenum REGADDR\n\t{\n\t\tVGT_PRIMITIVE_TYPE\t\t\t\t\t= 0x2256,\n\n\t\t// each stage has 12 sets of 4 border color registers\n\t\tTD_PS_SAMPLER0_BORDER_RED\t\t\t= 0x2900,\n\t\tTD_PS_SAMPLER0_BORDER_GREEN\t\t\t= 0x2901,\n\t\tTD_PS_SAMPLER0_BORDER_BLUE\t\t\t= 0x2902,\n\t\tTD_PS_SAMPLER0_BORDER_ALPHA\t\t\t= 0x2903,\n\n\t\tTD_VS_SAMPLER0_BORDER_RED\t\t\t= 0x2980,\n\t\tTD_VS_SAMPLER0_BORDER_GREEN\t\t\t= 0x2981,\n\t\tTD_VS_SAMPLER0_BORDER_BLUE\t\t\t= 0x2982,\n\t\tTD_VS_SAMPLER0_BORDER_ALPHA\t\t\t= 0x2983,\n\n\t\tTD_GS_SAMPLER0_BORDER_RED\t\t\t= 0x2A00,\n\t\tTD_GS_SAMPLER0_BORDER_GREEN\t\t\t= 0x2A01,\n\t\tTD_GS_SAMPLER0_BORDER_BLUE\t\t\t= 0x2A02,\n\t\tTD_GS_SAMPLER0_BORDER_ALPHA\t\t\t= 0x2A03,\n\n\t\tDB_STENCIL_CLEAR\t\t\t\t\t= 0xA00A,\n\t\tDB_DEPTH_CLEAR\t\t\t\t\t\t= 0xA00B,\n\n\t\tCB_TARGET_MASK                      = 0xA08E,\n\n\t\tPA_SC_GENERIC_SCISSOR_TL\t\t\t= 0xA090,\n\t\tPA_SC_GENERIC_SCISSOR_BR\t\t\t= 0xA091,\n\n\t\tSQ_VTX_SEMANTIC_0\t\t\t\t\t= 0xA0E0,\n\t\tSQ_VTX_SEMANTIC_31\t\t\t\t\t= 0xA0FF,\n\n\t\tVGT_MULTI_PRIM_IB_RESET_INDX\t\t= 0xA103,\n\t\tSX_ALPHA_TEST_CONTROL\t\t\t\t= 0xA104,\n\t\tCB_BLEND_RED\t\t\t\t\t\t= 0xA105,\n\t\tCB_BLEND_GREEN\t\t\t\t\t\t= 0xA106,\n\t\tCB_BLEND_BLUE\t\t\t\t\t\t= 0xA107,\n\t\tCB_BLEND_ALPHA\t\t\t\t\t\t= 0xA108,\n\n\t\tDB_STENCILREFMASK\t\t\t\t\t= 0xA10C,\n\t\tDB_STENCILREFMASK_BF\t\t\t\t= 0xA10D,\n\t\tSX_ALPHA_REF\t\t\t\t\t\t= 0xA10E,\n\t\tPA_CL_VPORT_XSCALE\t\t\t\t\t= 0xA10F,\n\t\tPA_CL_VPORT_XOFFSET\t\t\t\t\t= 0xA110,\n\t\tPA_CL_VPORT_YSCALE\t\t\t\t\t= 0xA111,\n\t\tPA_CL_VPORT_YOFFSET\t\t\t\t\t= 0xA112,\n\t\tPA_CL_VPORT_ZSCALE\t\t\t\t\t= 0xA113,\n\t\tPA_CL_VPORT_ZOFFSET\t\t\t\t\t= 0xA114,\n\n\t\tSPI_VS_OUT_ID_0\t\t\t\t\t\t= 0xA185,\n\n\t\tSPI_VS_OUT_CONFIG\t\t\t\t\t= 0xA1B1,\n\n\t\tCB_BLEND0_CONTROL\t\t\t\t\t= 0xA1E0, // first\n\t\tCB_BLEND7_CONTROL\t\t\t\t\t= 0xA1E7, // last\n\n\t\tDB_DEPTH_CONTROL\t\t\t\t\t= 0xA200,\n\n\t\tCB_COLOR_CONTROL\t\t\t\t\t= 0xA202,\n\n\t\tPA_CL_CLIP_CNTL\t\t\t\t\t\t= 0xA204,\n\t\tPA_SU_SC_MODE_CNTL\t\t\t\t\t= 0xA205,\n\t\tPA_CL_VTE_CNTL\t\t\t\t\t\t= 0xA206,\n\t\tPA_CL_VS_OUT_CNTL\t\t\t\t\t= 0xA207,\n\n\t\t// shader program descriptors:\n\t\tSQ_PGM_START_PS\t\t\t\t\t\t= 0xA210,\n\t\tSQ_PGM_RESOURCES_PS\t\t\t\t\t= 0xA214,\n\t\tSQ_PGM_EXPORTS_PS\t\t\t\t\t= 0xA215,\n\t\tSQ_PGM_START_VS\t\t\t\t\t\t= 0xA216,\n\t\tSQ_PGM_RESOURCES_VS\t\t\t\t\t= 0xA21A,\n\t\tSQ_PGM_START_GS \t\t\t\t\t= 0xA21B,\n\t\tSQ_PGM_RESOURCES_GS\t\t\t\t\t= 0xA21F,\n\t\tSQ_PGM_START_ES\t\t\t\t\t\t= 0xA220,\n\t\tSQ_PGM_RESOURCES_ES\t\t\t\t\t= 0xA224,\n\t\tSQ_PGM_START_FS\t\t\t\t\t\t= 0xA225,\n\t\tSQ_PGM_RESOURCES_FS\t\t\t\t\t= 0xA229,\n\n\t\tSQ_VTX_SEMANTIC_CLEAR\t\t\t\t= 0xA238,\n\n\t\tPA_SU_POINT_SIZE\t\t\t\t\t= 0xA280,\n\t\tPA_SU_POINT_MINMAX\t\t\t\t\t= 0xA281,\n\n\t\tVGT_GS_MODE\t\t\t\t\t\t\t= 0xA290,\n\n\t\tVGT_DMA_INDEX_TYPE\t\t\t\t\t= 0xA29F, // todo - verify offset\n\n\t\tVGT_PRIMITIVEID_EN\t\t\t\t\t= 0xA2A1,\n\t\tVGT_DMA_NUM_INSTANCES\t\t\t\t= 0xA2A2,\n\n\t\tVGT_MULTI_PRIM_IB_RESET_EN \t\t\t= 0xA2A5,\n\n\t\tVGT_INSTANCE_STEP_RATE_0\t\t\t= 0xA2A8,\n\t\tVGT_INSTANCE_STEP_RATE_1\t\t\t= 0xA2A9,\n\n\t\tVGT_STRMOUT_BUFFER_SIZE_0\t\t\t= 0xA2B4,\n\t\tVGT_STRMOUT_VTX_STRIDE_0\t\t\t= 0xA2B5,\n\t\tVGT_STRMOUT_BUFFER_BASE_0\t\t\t= 0xA2B6,\n\t\tVGT_STRMOUT_BUFFER_OFFSET_0\t\t\t= 0xA2B7,\n\t\tVGT_STRMOUT_BUFFER_SIZE_1\t\t\t= 0xA2B8,\n\t\tVGT_STRMOUT_VTX_STRIDE_1\t\t\t= 0xA2B9,\n\t\tVGT_STRMOUT_BUFFER_BASE_1\t\t\t= 0xA2BA,\n\t\tVGT_STRMOUT_BUFFER_OFFSET_1\t\t\t= 0xA2BB,\n\t\tVGT_STRMOUT_BUFFER_SIZE_2\t\t\t= 0xA2BC,\n\t\tVGT_STRMOUT_VTX_STRIDE_2\t\t\t= 0xA2BD,\n\t\tVGT_STRMOUT_BUFFER_BASE_2\t\t\t= 0xA2BE,\n\t\tVGT_STRMOUT_BUFFER_OFFSET_2\t\t\t= 0xA2BF,\n\t\tVGT_STRMOUT_BUFFER_SIZE_3\t\t\t= 0xA2C0,\n\t\tVGT_STRMOUT_VTX_STRIDE_3\t\t\t= 0xA2C1,\n\t\tVGT_STRMOUT_BUFFER_BASE_3\t\t\t= 0xA2C2,\n\t\tVGT_STRMOUT_BUFFER_OFFSET_3\t\t\t= 0xA2C3,\n\t\tVGT_STRMOUT_BASE_OFFSET_0\t\t\t= 0xA2C4,\n\t\tVGT_STRMOUT_BASE_OFFSET_1\t\t\t= 0xA2C5,\n\t\tVGT_STRMOUT_BASE_OFFSET_2\t\t\t= 0xA2C6,\n\t\tVGT_STRMOUT_BASE_OFFSET_3\t\t\t= 0xA2C7,\n\t\tVGT_STRMOUT_BUFFER_EN\t\t\t\t= 0xA2C8,\n\n\t\t// HiZ early stencil test?\n\t\tDB_SRESULTS_COMPARE_STATE0\t\t\t= 0xA34A,\n\t\tDB_SRESULTS_COMPARE_STATE1\t\t\t= 0xA34B,\n\n\t\tPA_SU_POLY_OFFSET_CLAMP\t\t\t\t= 0xA37F,\n\t\tPA_SU_POLY_OFFSET_FRONT_SCALE\t\t= 0xA380,\n\t\tPA_SU_POLY_OFFSET_FRONT_OFFSET\t\t= 0xA381,\n\t\tPA_SU_POLY_OFFSET_BACK_SCALE\t\t= 0xA382,\n\t\tPA_SU_POLY_OFFSET_BACK_OFFSET\t\t= 0xA383,\n\n\t\t// texture units\n\t\tSQ_TEX_RESOURCE_WORD0_N_PS\t\t\t= 0xE000,\n\t\tSQ_TEX_RESOURCE_WORD0_N_VS\t\t\t= 0xE460,\n\t\tSQ_TEX_RESOURCE_WORD0_N_GS\t\t\t= 0xE930,\n\t\tSQ_TEX_RESOURCE_WORD_FIRST\t\t\t= SQ_TEX_RESOURCE_WORD0_N_PS,\n\t\tSQ_TEX_RESOURCE_WORD_LAST\t\t\t= (SQ_TEX_RESOURCE_WORD0_N_GS + GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 7 - 1),\n\t\t// there are 54 samplers with 3 registers each. 18 (actually only 16?) per stage. For stage indices see SAMPLER_BASE_INDEX_*\n\t\tSQ_TEX_SAMPLER_WORD0_0\t\t\t\t= 0xF000,\n\t\tSQ_TEX_SAMPLER_WORD1_0\t\t\t\t= 0xF001,\n\t\tSQ_TEX_SAMPLER_WORD2_0\t\t\t\t= 0xF002,\n\n\n\t};\n\n\tinline constexpr int SAMPLER_BASE_INDEX_PIXEL = 0;\n\tinline constexpr int SAMPLER_BASE_INDEX_VERTEX = 18;\n\tinline constexpr int SAMPLER_BASE_INDEX_GEOMETRY = 36;\n\n#define LATTE_BITFIELD(__regname, __bitIndex, __bitWidth) \\\nauto& set_##__regname(uint32 newValue) \\\n{\t\\\n\tcemu_assert_debug(newValue < (1u << (__bitWidth))); \\\n\tv &= ~((((1u << (__bitWidth)) - 1u) << (__bitIndex))); \\\n\tv |= (newValue << (__bitIndex)); \\\n    return *this; \\\n} \\\nuint32 get_##__regname() const \\\n{\t\\\n\treturn (v >> (__bitIndex))&((1u << (__bitWidth)) - 1u); \\\n}\n\n#define LATTE_BITFIELD_SIGNED(__regname, __bitIndex, __bitWidth) \\\nauto& set_##__regname(sint32 newValue) \\\n{\t\\\n\tcemu_assert_debug(newValue < (1 << ((__bitWidth)-1))); \\\n\tcemu_assert_debug(newValue >= -(1 << ((__bitWidth)-1))); \\\n\tv &= ~((((1u << (__bitWidth)) - 1u) << (__bitIndex))); \\\n\tv |= (((uint32)newValue & ((1u << (__bitWidth)) - 1u)) << (__bitIndex)); \\\n    return *this; \\\n} \\\nsint32 get_##__regname() const \\\n{\t\\\n    sint32 r = (v >> (__bitIndex))&((1u << (__bitWidth)) - 1u); \\\n    r = (r << (32 - (__bitWidth))); \\\n    r = (r >> (32 - (__bitWidth))); \\\n\treturn r; \\\n}\n\n#define LATTE_BITFIELD_BOOL(__regname, __bitIndex) \\\nauto& set_##__regname(bool newValue) \\\n{\t\\\n\tif(newValue) \\\n\tv |= (1u << (__bitIndex)); \\\n\telse \\\n\tv &= ~(1u << (__bitIndex)); \\\n    return *this; \\\n} \\\nbool get_##__regname() const \\\n{\t\\\n\treturn (v&(1u << (__bitIndex))) != 0; \\\n}\n\n#define LATTE_BITFIELD_TYPED(__regname, __bitIndex, __bitWidth, __typename) \\\nauto& set_##__regname(__typename newValue) \\\n{\t\\\n\tcemu_assert_debug(static_cast<uint32>(newValue) < (1u << (__bitWidth))); \\\n\tv &= ~((((1u << (__bitWidth)) - 1u) << (__bitIndex))); \\\n\tv |= (static_cast<uint32>(newValue) << (__bitIndex)); \\\n    return *this; \\\n} \\\n__typename get_##__regname() const \\\n{\t\\\n\treturn static_cast<__typename>((v >> (__bitIndex))&((1u << (__bitWidth)) - 1u)); \\\n}\n\n#define LATTE_BITFIELD_FULL_TYPED(__regname, __typename) \\\nauto& set_##__regname(__typename newValue) \\\n{\t\\\n\tv = (static_cast<uint32>(newValue)); \\\n    return *this; \\\n} \\\n__typename get_##__regname() const \\\n{\t\\\n\treturn static_cast<__typename>(v); \\\n}\n\n#define LATTE_BITFIELD_FLOAT(__regname) \\\nauto& set_##__regname(float newValue) \\\n{\t\\\n\t*(float*)&v = newValue; \\\n    return *this; \\\n} \\\nfloat get_##__regname() const \\\n{\t\\\n\treturn *(float*)&v; \\\n}\n\n\tclass LATTEREG\n\t{\n\tpublic:\n\t\tuint32 getRawValue() const\n\t\t{\n\t\t\treturn v;\n\t\t}\n\n\t\tuint32 getRawValueBE() const\n\t\t{\n\t\t\treturn _swapEndianU32(v);\n\t\t}\n\n\tprotected:\n\t\tuint32 v{};\n\t};\n\n\t// shared enums\n\tenum class E_COMPAREFUNC // used by depth test func and alpha test func\n\t{\n\t\tNEVER,\n\t\tLESS,\n\t\tEQUAL,\n\t\tLEQUAL,\n\t\tGREATER,\n\t\tNOTEQUAL,\n\t\tGEQUAL,\n\t\tALWAYS\n\t};\n\n\tenum class E_ENDIAN_SWAP\n\t{\n\t\tSWAP_NONE = 0,\n\t};\n\n\tstruct LATTE_VGT_PRIMITIVE_TYPE : LATTEREG // 0x2256\n\t{\n\t\tenum class E_PRIMITIVE_TYPE\n\t\t{\n\t\t\tNONE = 0x0,\n\t\t\tPOINTS = 0x1,\n\t\t\tLINES = 0x2,\n\t\t\tLINE_STRIP = 0x3,\n\t\t\tTRIANGLES = 0x4,\n\t\t\tTRIANGLE_FAN = 0x5,\n\t\t\tTRIANGLE_STRIP = 0x6,\n\n\t\t\tLINES_ADJACENT = 0xA,\n\t\t\tLINE_STRIP_ADJACENT = 0xB,\n\t\t\tTRIANGLES_ADJACENT = 0xC,\n\t\t\tTRIANGLE_STRIP_ADJACENT = 0xD,\n\n\t\t\tRECTS = 0x11,\n\t\t\tLINE_LOOP = 0x12,\n\t\t\tQUADS = 0x13,\n\t\t\tQUAD_STRIP = 0x14,\n\t\t};\n\n\t\tLATTE_BITFIELD_FULL_TYPED(PRIMITIVE_MODE, E_PRIMITIVE_TYPE);\n\t};\n\n\tstruct LATTE_TD_BORDER_COLOR : LATTEREG // 0x2900 - 0x2A47\n\t{\n\t\tLATTE_BITFIELD_FLOAT(channelValue);\n\t};\n\n\tstruct LATTE_DB_STENCIL_CLEAR : LATTEREG // 0xA00A\n\t{\n\t\tLATTE_BITFIELD(clearValue, 0, 8);\n\t};\n\n\tstruct LATTE_DB_DEPTH_CLEAR : LATTEREG // 0xA00B\n\t{\n\t\tLATTE_BITFIELD_FLOAT(clearValue);\n\t};\n\n\tstruct LATTE_CB_TARGET_MASK : LATTEREG // 0xA08E\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(MASK, uint32);\n\t};\n\n\tstruct LATTE_PA_SC_GENERIC_SCISSOR_TL : LATTEREG // 0xA090\n\t{\n\t\tLATTE_BITFIELD(TL_X, 0, 15);\n\t\tLATTE_BITFIELD(TL_Y, 16, 15);\n\t\tLATTE_BITFIELD_BOOL(WINDOW_OFFSET_DISABLE, 31);\n\t};\n\n\tstruct LATTE_PA_SC_GENERIC_SCISSOR_BR : LATTEREG // 0xA091\n\t{\n\t\tLATTE_BITFIELD(BR_X, 0, 15);\n\t\tLATTE_BITFIELD(BR_Y, 16, 15);\n\t};\n\n\tstruct LATTE_VGT_MULTI_PRIM_IB_RESET_INDX : LATTEREG // 0xA103\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(RESTART_INDEX, uint32);\n\t};\n\n\tstruct LATTE_SX_ALPHA_TEST_CONTROL : LATTEREG // 0xA104\n\t{\n\t\tusing E_ALPHA_FUNC = E_COMPAREFUNC;\n\n\t\tLATTE_BITFIELD_TYPED(ALPHA_FUNC, 0, 3, E_ALPHA_FUNC);\n\t\tLATTE_BITFIELD_BOOL(ALPHA_TEST_ENABLE, 3);\n\t\tLATTE_BITFIELD_BOOL(ALPHA_TEST_BYPASS, 8);\n\t};\n\n\tstruct LATTE_CB_BLEND_RED : LATTEREG // 0xA105\n\t{\n\t\tLATTE_BITFIELD_FLOAT(RED);\n\t};\n\n\tstruct LATTE_CB_BLEND_GREEN : LATTEREG // 0xA106\n\t{\n\t\tLATTE_BITFIELD_FLOAT(GREEN);\n\t};\n\n\tstruct LATTE_CB_BLEND_BLUE : LATTEREG // 0xA107\n\t{\n\t\tLATTE_BITFIELD_FLOAT(BLUE);\n\t};\n\n\tstruct LATTE_CB_BLEND_ALPHA : LATTEREG // 0xA108\n\t{\n\t\tLATTE_BITFIELD_FLOAT(ALPHA);\n\t};\n\n\tstruct LATTE_DB_STENCILREFMASK : LATTEREG // 0xA10C\n\t{\n\t\tLATTE_BITFIELD(STENCILREF_F, 0, 8);\n\t\tLATTE_BITFIELD(STENCILMASK_F, 8, 8);\n\t\tLATTE_BITFIELD(STENCILWRITEMASK_F, 16, 8);\n\t};\n\n\tstruct LATTE_DB_STENCILREFMASK_BF : LATTEREG // 0xA10D\n\t{\n\t\tLATTE_BITFIELD(STENCILREF_B, 0, 8);\n\t\tLATTE_BITFIELD(STENCILMASK_B, 8, 8);\n\t\tLATTE_BITFIELD(STENCILWRITEMASK_B, 16, 8);\n\t};\n\n\tstruct LATTE_SX_ALPHA_REF : LATTEREG // 0xA10E\n\t{\n\t\tLATTE_BITFIELD_FLOAT(ALPHA_TEST_REF);\n\t};\n\n\tstruct LATTE_PA_CL_VPORT_XSCALE : LATTEREG // 0xA10F\n\t{\n\t\tLATTE_BITFIELD_FLOAT(SCALE);\n\t};\n\n\tstruct LATTE_PA_CL_VPORT_XOFFSET : LATTEREG // 0xA110\n\t{\n\t\tLATTE_BITFIELD_FLOAT(OFFSET);\n\t};\n\n\tstruct LATTE_PA_CL_VPORT_YSCALE : LATTEREG // 0xA111\n\t{\n\t\tLATTE_BITFIELD_FLOAT(SCALE);\n\t};\n\n\tstruct LATTE_PA_CL_VPORT_YOFFSET : LATTEREG // 0xA112\n\t{\n\t\tLATTE_BITFIELD_FLOAT(OFFSET);\n\t};\n\n\tstruct LATTE_PA_CL_VPORT_ZSCALE : LATTEREG // 0xA113\n\t{\n\t\tLATTE_BITFIELD_FLOAT(SCALE);\n\t};\n\n\tstruct LATTE_PA_CL_VPORT_ZOFFSET : LATTEREG // 0xA114\n\t{\n\t\tLATTE_BITFIELD_FLOAT(OFFSET);\n\t};\n\n\tstruct LATTE_CB_BLENDN_CONTROL : LATTEREG // 0xA1E0 - 0xA1E7\n\t{\n\t\tenum class E_BLENDFACTOR\n\t\t{\n\t\t\tBLEND_ZERO\t\t\t\t\t\t= 0x00,\n\t\t\tBLEND_ONE\t\t\t\t\t\t= 0x01,\n\t\t\tBLEND_SRC_COLOR\t\t\t\t\t= 0x02,\n\t\t\tBLEND_ONE_MINUS_SRC_COLOR\t\t= 0x03,\n\t\t\tBLEND_SRC_ALPHA\t\t\t\t\t= 0x04,\n\t\t\tBLEND_ONE_MINUS_SRC_ALPHA\t\t= 0x05,\n\t\t\tBLEND_DST_ALPHA\t\t\t\t\t= 0x06,\n\t\t\tBLEND_ONE_MINUS_DST_ALPHA\t\t= 0x07,\n\t\t\tBLEND_DST_COLOR\t\t\t\t\t= 0x08,\n\t\t\tBLEND_ONE_MINUS_DST_COLOR\t\t= 0x09,\n\t\t\tBLEND_SRC_ALPHA_SATURATE\t\t= 0x0A,\n\t\t\tBLEND_BOTH_SRC_ALPHA\t\t\t= 0x0B,\n\t\t\tBLEND_BOTH_INV_SRC_ALPHA\t\t= 0x0C,\n\t\t\tBLEND_CONST_COLOR\t\t\t\t= 0x0D,\n\t\t\tBLEND_ONE_MINUS_CONST_COLOR\t\t= 0x0E,\n\t\t\tBLEND_SRC1_COLOR\t\t\t\t= 0x0F,\n\t\t\tBLEND_INV_SRC1_COLOR\t\t\t= 0x10,\n\t\t\tBLEND_SRC1_ALPHA\t\t\t\t= 0x11,\n\t\t\tBLEND_INV_SRC1_ALPHA\t\t\t= 0x12,\n\t\t\tBLEND_CONST_ALPHA\t\t\t\t= 0x13,\n\t\t\tBLEND_ONE_MINUS_CONST_ALPHA\t\t= 0x14\n\t\t};\n\n\t\tenum class E_COMBINEFUNC\n\t\t{\n\t\t\tDST_PLUS_SRC\t\t\t\t\t= 0,\n\t\t\tSRC_MINUS_DST\t\t\t\t\t= 1,\n\t\t\tMIN_DST_SRC\t\t\t\t\t\t= 2,\n\t\t\tMAX_DST_SRC\t\t\t\t\t\t= 3,\n\t\t\tDST_MINUS_SRC\t\t\t\t\t= 4\n\t\t};\n\n\t\tLATTE_BITFIELD_TYPED(COLOR_SRCBLEND, 0, 5, E_BLENDFACTOR);\n\t\tLATTE_BITFIELD_TYPED(COLOR_COMB_FCN, 5, 3, E_COMBINEFUNC);\n\t\tLATTE_BITFIELD_TYPED(COLOR_DSTBLEND, 8, 5, E_BLENDFACTOR);\n\t\tLATTE_BITFIELD_BOOL(OPACITY_WEIGHT, 13);\n\t\tLATTE_BITFIELD_TYPED(ALPHA_SRCBLEND, 16, 5, E_BLENDFACTOR);\n\t\tLATTE_BITFIELD_TYPED(ALPHA_COMB_FCN, 21, 3, E_COMBINEFUNC);\n\t\tLATTE_BITFIELD_TYPED(ALPHA_DSTBLEND, 24, 5, E_BLENDFACTOR);\n\t\tLATTE_BITFIELD_BOOL(SEPARATE_ALPHA_BLEND, 29);\n\t};\n\n\tstruct LATTE_DB_DEPTH_CONTROL : LATTEREG // 0xA200\n\t{\n\t\tusing E_ZFUNC = E_COMPAREFUNC;\n\t\tusing E_STENCILFUNC = E_COMPAREFUNC;\n\n\t\tenum class E_STENCILACTION\n\t\t{\n\t\t\tKEEP,\n\t\t\tZERO,\n\t\t\tREPLACE,\n\t\t\tINCR,\n\t\t\tDECR,\n\t\t\tINVERT,\n\t\t\tINCR_WRAP,\n\t\t\tDECR_WRAP,\n\t\t};\n\n\t\tLATTE_BITFIELD_BOOL(STENCIL_ENABLE, 0);\n\t\tLATTE_BITFIELD_BOOL(Z_ENABLE, 1);\n\t\tLATTE_BITFIELD_BOOL(Z_WRITE_ENABLE, 2);\n\t\t// bit 3 is unused?\n\t\tLATTE_BITFIELD_TYPED(Z_FUNC, 4, 3, E_ZFUNC);\n\t\tLATTE_BITFIELD_BOOL(BACK_STENCIL_ENABLE, 7);\n\n\t\tLATTE_BITFIELD_TYPED(STENCIL_FUNC_F, 8, 3, E_STENCILFUNC);\n\t\tLATTE_BITFIELD_TYPED(STENCIL_FAIL_F, 11, 3, E_STENCILACTION);\n\t\tLATTE_BITFIELD_TYPED(STENCIL_ZPASS_F, 14, 3, E_STENCILACTION);\n\t\tLATTE_BITFIELD_TYPED(STENCIL_ZFAIL_F, 17, 3, E_STENCILACTION);\n\n\t\tLATTE_BITFIELD_TYPED(STENCIL_FUNC_B, 20, 3, E_STENCILFUNC);\n\t\tLATTE_BITFIELD_TYPED(STENCIL_FAIL_B, 23, 3, E_STENCILACTION);\n\t\tLATTE_BITFIELD_TYPED(STENCIL_ZPASS_B, 26, 3, E_STENCILACTION);\n\t\tLATTE_BITFIELD_TYPED(STENCIL_ZFAIL_B, 29, 3, E_STENCILACTION);\n\t};\n\n\tstruct LATTE_CB_COLOR_CONTROL : LATTEREG // 0xA202\n\t{\n\t\tenum class E_SPECIALOP\n\t\t{\n\t\t\tNORMAL = 0, // use state to render\n\t\t\tDISABLE = 1, // dont write color results\n\t\t};\n\n\t\tenum class E_LOGICOP\n\t\t{\n\t\t\tCLEAR = 0x00,\n\t\t\tCOPY = 0xCC,\n\t\t\tOR = 0xEE,\n\t\t\tSET = 0xFF,\n\t\t};\n\n\t\tLATTE_BITFIELD_BOOL(FOG_ENABLE, 0);\n\t\tLATTE_BITFIELD_BOOL(MULTIWRITE_ENABLE, 1);\n\t\tLATTE_BITFIELD_BOOL(DITHER_ENABLE, 2);\n\t\tLATTE_BITFIELD_BOOL(DEGAMMA_ENABLE, 3);\n\t\tLATTE_BITFIELD_TYPED(SPECIAL_OP, 4, 3, E_SPECIALOP);\n\t\tLATTE_BITFIELD_BOOL(PER_MRT_BLEND, 7);\n\t\tLATTE_BITFIELD(BLEND_MASK, 8, 8);\n\t\tLATTE_BITFIELD_TYPED(ROP, 16, 8, E_LOGICOP); // aka logic op\n\t};\n\n\tstruct LATTE_PA_CL_CLIP_CNTL : LATTEREG // 0xA204\n\t{\n\t\t// todo - other fields\n\t\t// see R6xx_3D_Registers.pdf\n\n\t\tLATTE_BITFIELD_BOOL(CLIP_DISABLE, 16);\n\n\t\tLATTE_BITFIELD_BOOL(DX_CLIP_SPACE_DEF, 19); // GX2 calls this flag HalfZ\n\n\n\t\tLATTE_BITFIELD_BOOL(DX_RASTERIZATION_KILL, 22);\n\n\t\tLATTE_BITFIELD_BOOL(DX_LINEAR_ATTR_CLIP_ENA, 24); // what does this do?\n\n\t\tLATTE_BITFIELD_BOOL(ZCLIP_NEAR_DISABLE, 26);\n\t\tLATTE_BITFIELD_BOOL(ZCLIP_FAR_DISABLE, 27);\n\n\t};\n\n\tstruct LATTE_PA_CL_VTE_CNTL : LATTEREG // 0xA206\n\t{\n\t\tLATTE_BITFIELD_BOOL(VPORT_X_SCALE_ENA, 0);\n\t\tLATTE_BITFIELD_BOOL(VPORT_X_OFFSET_ENA, 1);\n\n\t\tLATTE_BITFIELD_BOOL(VPORT_Y_SCALE_ENA, 2);\n\t\tLATTE_BITFIELD_BOOL(VPORT_Y_OFFSET_ENA, 3);\n\n\t\tLATTE_BITFIELD_BOOL(VPORT_Z_SCALE_ENA, 4);\n\t\tLATTE_BITFIELD_BOOL(VPORT_Z_OFFSET_ENA, 5);\n\n\t\tLATTE_BITFIELD_BOOL(VTX_XY_FMT, 8);\n\t\tLATTE_BITFIELD_BOOL(VTX_Z_FMT, 9);\n\t\tLATTE_BITFIELD_BOOL(VTX_W0_FMT, 10);\n\t};\n\n\tstruct LATTE_PA_CL_VS_OUT_CNTL : LATTEREG // 0xA207\n\t{\n\t\tLATTE_BITFIELD(CLIP_DIST_ENA_MASK, 0, 8);\n\t\tLATTE_BITFIELD(CULL_DIST_ENA_MASK, 8, 8);\n\t};\n\n\tstruct LATTE_PA_SU_POINT_SIZE : LATTEREG // 0xA280\n\t{\n\t\tLATTE_BITFIELD(HEIGHT, 0, 16);\n\t\tLATTE_BITFIELD(WIDTH, 16, 16);\n\t};\n\n\tstruct LATTE_PA_SU_POINT_MINMAX : LATTEREG // 0xA281\n\t{\n\t\tLATTE_BITFIELD(MIN_SIZE, 0, 16);\n\t\tLATTE_BITFIELD(MAX_SIZE, 16, 16);\n\t};\n\n\tstruct LATTE_VGT_GS_MODE : LATTEREG // 0xA290\n\t{\n\t\tenum class E_MODE\n\t\t{\n\t\t\tOFF = 0,\n\t\t\tSCENARIO_A = 1,\n\t\t\tSCENARIO_B = 2,\n\t\t\tSCENARIO_G = 3\n\t\t};\n\n\t\tenum class E_CUT_MODE\n\t\t{\n\t\t\tCUT_1024 = 0,\n\t\t\tCUT_512 = 1,\n\t\t\tCUT_256 = 2,\n\t\t\tCUT_128 = 3,\n\t\t};\n\n\t\tenum class E_COMPUTE_MODE\n\t\t{\n\t\t\tOFF = 0,\n\t\t\tUKN_1 = 1,\n\t\t\tUKN_2 = 2,\n\t\t\tON = 3,\n\t\t};\n\n\t\tLATTE_BITFIELD_TYPED(MODE, 0, 2, E_MODE);\n\t\tLATTE_BITFIELD_BOOL(ES_PASSTHRU, 2);\n\t\tLATTE_BITFIELD_TYPED(CUT_MODE, 3, 2, E_CUT_MODE);\n\t\tLATTE_BITFIELD_TYPED(COMPUTE_MODE, 14, 2, E_COMPUTE_MODE);\n\t\tLATTE_BITFIELD_BOOL(PARTIAL_THD_AT_EOI, 17);\n\t};\n\n\tstruct LATTE_VGT_DMA_INDEX_TYPE : LATTEREG // 0xA29F\n\t{\n\t\tenum class E_INDEX_TYPE\n\t\t{\n\t\t\tU16_LE = 0, // U16\n\t\t\tU32_LE = 1, // U32\n\n\t\t\tU16_BE = 4, // U16 + SwapU16\n\t\t\tU32_BE = 9, // U32 + SwapU32\n\n\t\t\t// index 0 -> U16\n\t\t\t// index 1 -> U32\n\t\t\t// bit 0x2 -> swap U16\n\t\t\t// bit 0x4 -> swap U32\n\t\t\t// bit 0x8 -> swap U32 (machine word?)\n\n\t\t\tAUTO = 0xFFFF, // helper value for tracking auto-generated indices. Not part of the actual enum\n\t\t};\n\n\t\tLATTE_BITFIELD_FULL_TYPED(INDEX_TYPE, E_INDEX_TYPE);\n\t};\n\n\tstruct LATTE_VGT_PRIMITIVEID_EN : LATTEREG // 0xA2A1\n\t{\n\t\tLATTE_BITFIELD_BOOL(PRIMITIVEID_EN, 0);\n\t};\n\n\tstruct LATTE_VGT_DMA_NUM_INSTANCES : LATTEREG // 0xA2A2\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(NUM_INSTANCES, uint32);\n\t};\n\n\tstruct LATTE_VGT_MULTI_PRIM_IB_RESET_EN : LATTEREG // 0xA2A5\n\t{\n\t\tLATTE_BITFIELD_BOOL(RESET_EN, 0);\n\t};\n\n\tstruct LATTE_VGT_INSTANCE_STEP_RATE_X : LATTEREG // 0xA2A8-0xA2A9\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(STEP_RATE, uint32);\n\t};\n\n\tstruct LATTE_VGT_STRMOUT_BUFFER_SIZE_X : LATTEREG // 0xA2B4 + index * 4\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(SIZE, uint32);\n\t};\n\n\tstruct LATTE_VGT_STRMOUT_STRIDE_X : LATTEREG // 0xA2B5 + index * 4\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(STRIDE, uint32);\n\t};\n\n\tstruct LATTE_VGT_STRMOUT_BUFFER_BASE_X : LATTEREG // 0xA2B6 + index * 4\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(BASE, uint32);\n\t};\n\n\tstruct LATTE_VGT_STRMOUT_BUFFER_OFFSET_X : LATTEREG // 0xA2B7 + index * 4\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(BUFFER_OFFSET, uint32);\n\t};\n\n\tstruct LATTE_VGT_STRMOUT_BASE_OFFSET_X : LATTEREG // 0xA2C4-0xA2C7\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(BASE_OFFSET, uint32);\n\t};\n\n\tstruct LATTE_VGT_STRMOUT_BUFFER_EN : LATTEREG // 0xA2C8\n\t{\n\t\tLATTE_BITFIELD_BOOL(BUFFER_ENABLE_0, 0);\n\t\tLATTE_BITFIELD_BOOL(BUFFER_ENABLE_1, 1);\n\t\tLATTE_BITFIELD_BOOL(BUFFER_ENABLE_2, 2);\n\t\tLATTE_BITFIELD_BOOL(BUFFER_ENABLE_3, 3);\n\t};\n\n\tstruct LATTE_PA_SU_POLY_OFFSET_CLAMP : LATTEREG // 0xA37F\n\t{\n\t\tLATTE_BITFIELD_FLOAT(CLAMP);\n\t};\n\n\tstruct LATTE_PA_SU_POLY_OFFSET_FRONT_SCALE : LATTEREG // 0xA380\n\t{\n\t\tLATTE_BITFIELD_FLOAT(SCALE);\n\t};\n\n\tstruct LATTE_PA_SU_POLY_OFFSET_FRONT_OFFSET : LATTEREG // 0xA381\n\t{\n\t\tLATTE_BITFIELD_FLOAT(OFFSET);\n\t};\n\n\tstruct LATTE_PA_SU_POLY_OFFSET_BACK_SCALE : LATTEREG // 0xA382\n\t{\n\t\tLATTE_BITFIELD_FLOAT(SCALE);\n\t};\n\n\tstruct LATTE_PA_SU_POLY_OFFSET_BACK_OFFSET : LATTEREG // 0xA383\n\t{\n\t\tLATTE_BITFIELD_FLOAT(OFFSET);\n\t};\n\n\tstruct LATTE_SQ_VTX_SEMANTIC_CLEAR : LATTEREG // 0xA238\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(CLEAR_MASK, uint32); // probably a bitmask\n\t};\n\n\tstruct LATTE_SQ_VTX_SEMANTIC_X : LATTEREG // 0xA0E0 - 0xA0FF\n\t{\n\t\tLATTE_BITFIELD(SEMANTIC_ID, 0, 8);\n\t};\n\n\tstruct LATTE_SQ_TEX_RESOURCE_WORD0_N : LATTEREG // 0xE000 + index * 7\n\t{\n\t\tLATTE_BITFIELD_TYPED(DIM, 0, 3, E_DIM);\n\t\tLATTE_BITFIELD_TYPED(TILE_MODE, 3, 4, E_HWTILEMODE);\n\n\t\tLATTE_BITFIELD_BOOL(TILE_TYPE, 7);\n\n\t\tLATTE_BITFIELD(PITCH, 8, 11);\n\t\tLATTE_BITFIELD(WIDTH, 19, 13);\n\t};\n\n\tstruct LATTE_SQ_TEX_RESOURCE_WORD1_N : LATTEREG // 0xE001 + index * 7\n\t{\n\t\tLATTE_BITFIELD(HEIGHT, 0, 13);\n\t\tLATTE_BITFIELD(DEPTH, 13, 13);\n\t\tLATTE_BITFIELD_TYPED(DATA_FORMAT, 26, 6, E_HWSURFFMT);\n\t};\n\n\tstruct LATTE_SQ_TEX_RESOURCE_WORD2_N : LATTEREG // 0xE002 + index * 7\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(BASE_ADDRESS, uint32);\n\t};\n\n\tstruct LATTE_SQ_TEX_RESOURCE_WORD3_N : LATTEREG // 0xE003 + index * 7\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(MIP_ADDRESS, uint32);\n\t};\n\n\tstruct LATTE_SQ_TEX_RESOURCE_WORD4_N : LATTEREG // 0xE004 + index * 7\n\t{\n\t\tenum class E_FORMAT_COMP\n\t\t{\n\t\t\tCOMP_UNSIGNED = 0,\n\t\t\tCOMP_SIGNED = 1,\n\t\t\tCOMP_UNSIGNED_BIASED = 2,\n\t\t};\n\n\t\tenum class E_NUM_FORMAT_ALL\n\t\t{\n\t\t\tNUM_FORMAT_NORM = 0,\n\t\t\tNUM_FORMAT_INT = 1,\n\t\t\tNUM_FORMAT_SCALED = 2,\n\t\t};\n\n\t\tenum class E_SRF_MODE_ALL\n\t\t{\n\t\t\tSRF_MODE_ZERO_CLAMP_MINUS_ONE = 0,\n\t\t\tSRF_MODE_NO_ZERO = 1,\n\t\t};\n\n\t\t// using E_ENDIAN_SWAP = E_ENDIAN_SWAP;\n\n\t\tenum class E_SEL\n\t\t{\n\t\t\tSEL_X = 0,\n\t\t\tSEL_Y = 1,\n\t\t\tSEL_Z = 2,\n\t\t\tSEL_W = 3,\n\t\t\tSEL_0 = 4,\n\t\t\tSEL_1 = 5\n\t\t};\n\n\t\tLATTE_BITFIELD_TYPED(FORMAT_COMP_X, 0, 2, E_FORMAT_COMP);\n\t\tLATTE_BITFIELD_TYPED(FORMAT_COMP_Y, 2, 2, E_FORMAT_COMP);\n\t\tLATTE_BITFIELD_TYPED(FORMAT_COMP_Z, 4, 2, E_FORMAT_COMP);\n\t\tLATTE_BITFIELD_TYPED(FORMAT_COMP_W, 6, 2, E_FORMAT_COMP);\n\t\tLATTE_BITFIELD_TYPED(NUM_FORM_ALL, 8, 2, E_NUM_FORMAT_ALL);\n\t\tLATTE_BITFIELD_TYPED(SRF_MODE_ALL, 10, 1, E_SRF_MODE_ALL);\n\t\tLATTE_BITFIELD_BOOL(FORCE_DEGAMMA, 11);\n\t\tLATTE_BITFIELD_TYPED(ENDIAN_SWAP, 12, 2, E_ENDIAN_SWAP);\n\t\tLATTE_BITFIELD(REQUEST_SIZE, 14, 2);\n\t\tLATTE_BITFIELD_TYPED(DST_SEL_X, 16, 3, E_SEL);\n\t\tLATTE_BITFIELD_TYPED(DST_SEL_Y, 19, 3, E_SEL);\n\t\tLATTE_BITFIELD_TYPED(DST_SEL_Z, 22, 3, E_SEL);\n\t\tLATTE_BITFIELD_TYPED(DST_SEL_W, 25, 3, E_SEL);\n\t\tLATTE_BITFIELD(BASE_LEVEL, 28, 4);\n\t};\n\n\tstruct LATTE_SQ_TEX_RESOURCE_WORD5_N : LATTEREG // 0xE005 + index * 7\n\t{\n\t\tLATTE_BITFIELD(LAST_LEVEL, 0, 4); // for MSAA textures, this stores the AA level\n\t\tLATTE_BITFIELD(BASE_ARRAY, 4, 13);\n\t\tLATTE_BITFIELD(LAST_ARRAY, 17, 13);\n\t\tLATTE_BITFIELD_BOOL(UKN_BIT_30, 30); // may be a 2 bit value?\n\t};\n\n\tstruct LATTE_SQ_TEX_RESOURCE_WORD6_N : LATTEREG // 0xE006 + index * 7\n\t{\n\t\tenum class E_MPEG_CLAMP\n\t\t{\n\t\t\tUKN = 0,\n\t\t};\n\n\t\tenum class E_TYPE\n\t\t{\n\t\t\tVTX_INVALID_TEXTURE = 0,\n\t\t\tVTX_INVALID_BUFFER = 1,\n\t\t\tVTX_VALID_TEXTURE = 2,\n\t\t\tVTX_VALID_BUFFER = 3,\n\t\t};\n\n\t\t// unsure if these are correct\n\n\t\tLATTE_BITFIELD_TYPED(MPEG_CLAMP, 0, 2, E_MPEG_CLAMP);\n\t\tLATTE_BITFIELD(MAX_ANISO, 2, 3);\n\t\tLATTE_BITFIELD(PERF_MODULATION, 5, 3);\n\t\tLATTE_BITFIELD_BOOL(INTERLACED, 8);\n\t\tLATTE_BITFIELD_TYPED(TYPE, 30, 2, E_TYPE);\n\t};\n\n\tstruct LATTE_SQ_TEX_SAMPLER_WORD0_0 : LATTEREG // 0xF000+n*3 - 0xF???\n\t{\n\t\tenum class E_CLAMP\n\t\t{\n\t\t\tWRAP = 0,\n\t\t\tMIRROR = 1,\n\t\t\tCLAMP_LAST_TEXEL = 2,\n\t\t\tMIRROR_ONCE_LAST_TEXEL = 3,\n\t\t\tCLAMP_HALF_BORDER = 4,\n\t\t\tMIRROR_ONCE_HALF_BORDER = 5,\n\t\t\tCLAMP_BORDER = 6,\n\t\t\tMIRROR_ONCE_BORDER = 7,\n\t\t};\n\n\t\tenum class E_XY_FILTER\n\t\t{\n\t\t\tPOINT = 0,\n\t\t\tBILINEAR = 1,\n\t\t\tBICUBIC = 2,\n\t\t\t// 3 unused ?\n\t\t\tANISO_POINT = 4,\n\t\t\tANISO_BILINEAR = 5,\n\t\t\t// 6, 7 unused ?\n\t\t};\n\n\t\tenum class E_Z_FILTER\n\t\t{\n\t\t\tNONE = 0,\n\t\t\tPOINT = 1,\n\t\t\tLINEAR = 2,\n\t\t\t// 3 is unused ?\n\t\t};\n\n\t\tenum class E_BORDER_COLOR_TYPE\n\t\t{\n\t\t\tTRANSPARENT_BLACK = 0,\n\t\t\tOPAQUE_BLACK = 1,\n\t\t\tOPAQUE_WHITE = 2,\n\t\t\tREGISTER = 3,\n\t\t};\n\n\t\tenum class E_DEPTH_COMPARE\n\t\t{\n\t\t\tNEVER = 0,\n\t\t\tLESS = 1,\n\t\t\tEQUAL = 2,\n\t\t\tLEQUAL = 3,\n\t\t\tGREATER = 4,\n\t\t\tNOTEQUAL = 5,\n\t\t\tGEQUAL = 6,\n\t\t\tALWAYS = 7\n\t\t};\n\n\n\t\tenum class E_CHROMA_KEY\n\t\t{\n\t\t\tDISABLE = 0,\n\t\t\tKILL = 1,\n\t\t\tBLEND = 2,\n\t\t\t// 3 is unused\n\t\t};\n\n\t\tLATTE_BITFIELD_TYPED(CLAMP_X, 0, 3, E_CLAMP);\n\t\tLATTE_BITFIELD_TYPED(CLAMP_Y, 3, 3, E_CLAMP);\n\t\tLATTE_BITFIELD_TYPED(CLAMP_Z, 6, 3, E_CLAMP);\n\t\tLATTE_BITFIELD_TYPED(XY_MAG_FILTER, 9, 3, E_XY_FILTER);\n\t\tLATTE_BITFIELD_TYPED(XY_MIN_FILTER, 12, 3, E_XY_FILTER);\n\t\tLATTE_BITFIELD_TYPED(Z_FILTER, 15, 2, E_Z_FILTER);\n\t\tLATTE_BITFIELD_TYPED(MIP_FILTER, 17, 2, E_Z_FILTER);\n\t\tLATTE_BITFIELD(MAX_ANISO_RATIO, 19, 3);\n\t\tLATTE_BITFIELD_TYPED(BORDER_COLOR_TYPE, 22, 2, E_BORDER_COLOR_TYPE);\n\t\tLATTE_BITFIELD_BOOL(POINT_SAMPLING_CLAMP, 24);\n\t\tLATTE_BITFIELD_BOOL(TEX_ARRAY_OVERRIDE, 25);\n\t\tLATTE_BITFIELD_TYPED(DEPTH_COMPARE_FUNCTION, 26, 3, E_DEPTH_COMPARE);\n\t\tLATTE_BITFIELD_TYPED(CHROMA_KEY, 28, 2, E_CHROMA_KEY);\n\t\tLATTE_BITFIELD_BOOL(LOD_USES_MINOR_AXIS, 25);\n\t};\n\n\tstruct LATTE_SQ_TEX_SAMPLER_WORD1_0 : LATTEREG // 0xF001+n*3 - 0xF???\n\t{\n\t\tLATTE_BITFIELD(MIN_LOD, 0, 10);\n\t\tLATTE_BITFIELD(MAX_LOD, 10, 10);\n\t\tLATTE_BITFIELD_SIGNED(LOD_BIAS, 20, 12);\n\t};\n\n\tstruct LATTE_SQ_TEX_SAMPLER_WORD2_0 : LATTEREG // 0xF002+n*3 - 0xF???\n\t{\n\t\tenum E_SAMPLER_TYPE\n\t\t{\n\t\t\tUKN0 = 0,\n\t\t\tUKN1 = 1,\n\t\t};\n\n\t\tLATTE_BITFIELD(LOD_BIAS_SECONDARY, 0, 12);\n\t\tLATTE_BITFIELD_BOOL(MC_COORD_TRUNCATE, 12);\n\t\tLATTE_BITFIELD_BOOL(FORCE_DEGAMMA, 13);\n\t\tLATTE_BITFIELD_BOOL(HIGH_PRECISION_FILTER, 14);\n\n\t\t// PERF_MIP at 15, 3 bits\n\t\t// PERF_Z at 18, 3 bits\n\t\t// bit 21 is unused?\n\n\t\tLATTE_BITFIELD(ANISO_BIAS, 22, 6); // is size correct?\n\n\t\t//LATTE_BITFIELD_BOOL(FETCH_4, 26); overlaps with ANISO_BIAS\n\t\t//LATTE_BITFIELD_BOOL(SAMPLE_IS_PCF, 27); overlaps with ANISO_BIAS\n\n\t\tLATTE_BITFIELD_TYPED(TYPE, 31, 1, E_SAMPLER_TYPE);\n\t};\n\n\tstruct LATTE_SQ_PGM_START_X : LATTEREG // 0xA210 / 0xA216 / 0xA21B / 0xA220 / 0xA225\n\t{\n\t\tLATTE_BITFIELD_FULL_TYPED(PGM_START, uint32);\n\t};\n\n\tstruct LATTE_SQ_PGM_RESOURCES_PS : LATTEREG // 0xA214\n\t{\n\t\tLATTE_BITFIELD(NUM_GPRS, 0, 8);\n\t\tLATTE_BITFIELD(NUM_STACK_ENTRIES, 8, 8);\n\t\tLATTE_BITFIELD_BOOL(DX10_CLAMP, 21); // if true, CLAMP modifier in shaders will return 0 for NaN\n\t\tLATTE_BITFIELD(FETCH_CACHE_LINES, 24, 3);\n\t\tLATTE_BITFIELD_BOOL(UNCACHED_FIRST_INST, 28);\n\t\tLATTE_BITFIELD_BOOL(CLAMP_CONSTS, 31);\n\t};\n\n\tstruct LATTE_SQ_PGM_RESOURCES_VS : LATTEREG // 0xA21A\n\t{\n\t\tLATTE_BITFIELD(NUM_GPRS, 0, 8);\n\t\tLATTE_BITFIELD(NUM_STACK_ENTRIES, 8, 8);\n\t\tLATTE_BITFIELD_BOOL(DX10_CLAMP, 21); // if true, CLAMP modifier in shaders will return 0 for NaN\n\t\tLATTE_BITFIELD(FETCH_CACHE_LINES, 24, 3);\n\t\tLATTE_BITFIELD_BOOL(UNCACHED_FIRST_INST, 28);\n\t};\n\n\tstruct LATTE_SQ_PGM_RESOURCES_GS : LATTEREG // 0xA21F\n\t{\n\t\tLATTE_BITFIELD(NUM_GPRS, 0, 8);\n\t\tLATTE_BITFIELD(NUM_STACK_ENTRIES, 8, 8);\n\t\tLATTE_BITFIELD_BOOL(DX10_CLAMP, 21); // if true, CLAMP modifier in shaders will return 0 for NaN\n\t};\n\n\tstruct LATTE_SQ_PGM_RESOURCES_ES : LATTEREG // 0xA224\n\t{\n\t\tLATTE_BITFIELD(NUM_GPRS, 0, 8);\n\t\tLATTE_BITFIELD(NUM_STACK_ENTRIES, 8, 8);\n\t\tLATTE_BITFIELD_BOOL(DX10_CLAMP, 21); // if true, CLAMP modifier in shaders will return 0 for NaN\n\t};\n\n\tstruct LATTE_SQ_PGM_RESOURCES_FS : LATTEREG // 0xA229\n\t{\n\t\tLATTE_BITFIELD(NUM_GPRS, 0, 8);\n\t\tLATTE_BITFIELD(NUM_STACK_ENTRIES, 8, 8);\n\t\tLATTE_BITFIELD_BOOL(DX10_CLAMP, 21); // if true, CLAMP modifier in shaders will return 0 for NaN\n\t};\n\n\tstruct LATTE_SQ_XX_ITEMSIZE : LATTEREG // 0xA227 - 0xA2XX\n\t{\n\t\t// used by:\n\t\t// SQ_ESGS_RING_ITEMSIZE\n\t\t// SQ_GSVS_RING_ITEMSIZE\n\t\t// SQ_ESTMP_RING_ITEMSIZE\n\t\t// SQ_GSTMP_RING_ITEMSIZE\n\t\t// SQ_VSTMP_RING_ITEMSIZE\n\t\t// SQ_PSTMP_RING_ITEMSIZE\n\t\t// SQ_FBUF_RING_ITEMSIZE\n\t\t// SQ_REDUC_RING_ITEMSIZE\n\t\tLATTE_BITFIELD(ITEMSIZE, 0, 15);\n\t};\n\n\tstruct LATTE_PA_SU_SC_MODE_CNTL : LATTEREG // 0xA205\n\t{\n\t\tenum class E_FRONTFACE\n\t\t{\n\t\t\tCCW = 0,\n\t\t\tCW = 1\n\t\t};\n\n\t\tenum class E_POLYGONMODE\n\t\t{\n\t\t\tUKN0 = 0, // default - render triangles\n\t\t};\n\n\t\tenum class E_PTYPE\n\t\t{\n\t\t\tPOINTS = 0,\n\t\t\tLINES = 1,\n\t\t\tTRIANGLES = 2,\n\t\t};\n\n\t\tLATTE_BITFIELD_BOOL(CULL_FRONT, 0);\n\t\tLATTE_BITFIELD_BOOL(CULL_BACK, 1);\n\t\tLATTE_BITFIELD_TYPED(FRONT_FACE, 2, 1, E_FRONTFACE);\n\t\tLATTE_BITFIELD_TYPED(POLYGON_MODE, 3, 2, E_POLYGONMODE);\n\t\tLATTE_BITFIELD_TYPED(FRONT_POLY_MODE, 5, 3, E_PTYPE);\n\t\tLATTE_BITFIELD_TYPED(BACK_POLY_MODE, 8, 3, E_PTYPE);\n\t\tLATTE_BITFIELD_BOOL(OFFSET_FRONT_ENABLED, 11);\n\t\tLATTE_BITFIELD_BOOL(OFFSET_BACK_ENABLED, 12);\n\t\tLATTE_BITFIELD_BOOL(OFFSET_PARA_ENABLED, 13); // offset enable for lines and points?\n\t\t// additional fields?\n\t};\n\n\tstruct LATTE_SPI_VS_OUT_CONFIG : LATTEREG // 0xA1B1\n\t{\n\t\tLATTE_BITFIELD_BOOL(VS_PER_COMPONENT, 0);\n\t\tLATTE_BITFIELD(VS_EXPORT_COUNT, 1, 5);\n\t\tLATTE_BITFIELD_BOOL(EXPORTS_FOG, 8);\n\t\tLATTE_BITFIELD(VS_OUT_FOG_VEC_ADDR, 9, 5);\n\t};\n\n\tstruct LATTE_SPI_VS_OUT_ID_N : LATTEREG // 0xA185 - 0xA18E(?) - 0xA1B2 - 0xA1B3\n\t{\n\t\tuint8 get_SEMANTIC(sint32 index)\n\t\t{\n\t\t\tcemu_assert_debug(index < 4);\n\t\t\treturn (uint8)((v >> (index * 8)) & 0xFF);\n\t\t}\n\n\t\tvoid set_SEMANTIC(sint32 index, uint8 value)\n\t\t{\n\t\t\tcemu_assert_debug(index < 4);\n\t\t\tv &= ~(0xFF << (index * 8));\n\t\t\tv |= (value & 0xFF) << (index * 8);\n\t\t}\n\t};\n\n};\n\nstruct _LatteRegisterSetTextureUnit\n{\n\tLatte::LATTE_SQ_TEX_RESOURCE_WORD0_N word0;\n\tLatte::LATTE_SQ_TEX_RESOURCE_WORD1_N word1;\n\tLatte::LATTE_SQ_TEX_RESOURCE_WORD2_N word2;\n\tLatte::LATTE_SQ_TEX_RESOURCE_WORD3_N word3;\n\tLatte::LATTE_SQ_TEX_RESOURCE_WORD4_N word4;\n\tLatte::LATTE_SQ_TEX_RESOURCE_WORD5_N word5;\n\tLatte::LATTE_SQ_TEX_RESOURCE_WORD6_N word6;\n};\n\nstatic_assert(sizeof(_LatteRegisterSetTextureUnit) == 28);\n\nstruct _LatteRegisterSetSampler\n{\n\tLatte::LATTE_SQ_TEX_SAMPLER_WORD0_0 WORD0;\n\tLatte::LATTE_SQ_TEX_SAMPLER_WORD1_0 WORD1;\n\tLatte::LATTE_SQ_TEX_SAMPLER_WORD2_0 WORD2;\n};\n\nstatic_assert(sizeof(_LatteRegisterSetSampler) == 12);\n\nstruct _LatteRegisterSetSamplerBorderColor\n{\n\tLatte::LATTE_TD_BORDER_COLOR red;\n\tLatte::LATTE_TD_BORDER_COLOR green;\n\tLatte::LATTE_TD_BORDER_COLOR blue;\n\tLatte::LATTE_TD_BORDER_COLOR alpha;\n};\n\nstatic_assert(sizeof(_LatteRegisterSetSamplerBorderColor) == 16);\n\nstruct _LatteRegisterSetStreamoutBuffer\n{\n\tLatte::LATTE_VGT_STRMOUT_BUFFER_SIZE_X SIZE;\n\tLatte::LATTE_VGT_STRMOUT_STRIDE_X STRIDE;\n\tLatte::LATTE_VGT_STRMOUT_BUFFER_BASE_X BASE;\n\tLatte::LATTE_VGT_STRMOUT_BUFFER_OFFSET_X BUFFER_OFFSET;\n};\n\nstatic_assert(sizeof(_LatteRegisterSetStreamoutBuffer) == 16);\n\nstruct LatteContextRegister\n{\n\tuint8 padding0[0x08958];\n\n\t/* +0x08958 */ Latte::LATTE_VGT_PRIMITIVE_TYPE VGT_PRIMITIVE_TYPE;\n\tuint8 padding5[0x0A400 - 0x0895C];\n\t/* +0x0A400 */ _LatteRegisterSetSamplerBorderColor TD_PS_SAMPLER_BORDER_COLOR[Latte::GPU_LIMITS::NUM_SAMPLERS_PER_STAGE];\n\tuint8 padding6[0x0A600 - 0x0A520];\n\t/* +0x0A600 */ _LatteRegisterSetSamplerBorderColor TD_VS_SAMPLER_BORDER_COLOR[Latte::GPU_LIMITS::NUM_SAMPLERS_PER_STAGE];\n\tuint8 padding7[0x0A800 - 0x0A720];\n\t/* +0x0A800 */ _LatteRegisterSetSamplerBorderColor TD_GS_SAMPLER_BORDER_COLOR[Latte::GPU_LIMITS::NUM_SAMPLERS_PER_STAGE];\n\tuint8 padding8[0x28238 - 0x0A920];\n\t/* +0x28238 */ Latte::LATTE_CB_TARGET_MASK CB_TARGET_MASK;\n\tuint8 padding_2823C[4];\n\t/* +0x28240 */ Latte::LATTE_PA_SC_GENERIC_SCISSOR_TL PA_SC_GENERIC_SCISSOR_TL;\n\t/* +0x28244 */ Latte::LATTE_PA_SC_GENERIC_SCISSOR_BR PA_SC_GENERIC_SCISSOR_BR;\n\tuint8 padding_28248[0x28380 - 0x28248];\n\t/* +0x28380 */ Latte::LATTE_SQ_VTX_SEMANTIC_X SQ_VTX_SEMANTIC_X[32];\n\t/* +0x28400 */ uint8 padding_28400[0x2840C - 0x28400];\n\t/* +0x2840C */ Latte::LATTE_VGT_MULTI_PRIM_IB_RESET_INDX VGT_MULTI_PRIM_IB_RESET_INDX;\n\t/* +0x28410 */ Latte::LATTE_SX_ALPHA_TEST_CONTROL SX_ALPHA_TEST_CONTROL;\n\t/* +0x28414 */ Latte::LATTE_CB_BLEND_RED CB_BLEND_RED;\n\t/* +0x28418 */ Latte::LATTE_CB_BLEND_GREEN CB_BLEND_GREEN;\n\t/* +0x2841C */ Latte::LATTE_CB_BLEND_BLUE CB_BLEND_BLUE;\n\t/* +0x28420 */ Latte::LATTE_CB_BLEND_ALPHA CB_BLEND_ALPHA;\n\tuint8 padding_28424[0x28430 - 0x28424];\n\t/* +0x28430 */ Latte::LATTE_DB_STENCILREFMASK DB_STENCILREFMASK;\n\t/* +0x28434 */ Latte::LATTE_DB_STENCILREFMASK_BF DB_STENCILREFMASK_BF;\n\t/* +0x28438 */ Latte::LATTE_SX_ALPHA_REF SX_ALPHA_REF;\n\t/* +0x2843C */ Latte::LATTE_PA_CL_VPORT_XSCALE\tPA_CL_VPORT_XSCALE;\n\t/* +0x28440 */ Latte::LATTE_PA_CL_VPORT_XOFFSET PA_CL_VPORT_XOFFSET;\n\t/* +0x28444 */ Latte::LATTE_PA_CL_VPORT_YSCALE\tPA_CL_VPORT_YSCALE;\n\t/* +0x28448 */ Latte::LATTE_PA_CL_VPORT_YOFFSET PA_CL_VPORT_YOFFSET;\n\t/* +0x2844C */ Latte::LATTE_PA_CL_VPORT_ZSCALE\tPA_CL_VPORT_ZSCALE;\n\t/* +0x28450 */ Latte::LATTE_PA_CL_VPORT_ZOFFSET PA_CL_VPORT_ZOFFSET;\n\n\tuint8 padding_28450[0x28614 - 0x28454];\n\n\t/* +0x28614 */ Latte::LATTE_SPI_VS_OUT_ID_N LATTE_SPI_VS_OUT_ID_N[10];\n\n\tuint8 padding_2863C[0x286C4 - 0x2863C];\n\n\t/* +0x286C4 */ Latte::LATTE_SPI_VS_OUT_CONFIG SPI_VS_OUT_CONFIG;\n\n\tuint8 padding_286C8[0x28780 - 0x286C8];\n\n\t/* +0x28780 */ Latte::LATTE_CB_BLENDN_CONTROL CB_BLENDN_CONTROL[8];\n\n\tuint8 padding_287A0[0x28800 - 0x287A0];\n\n\t/* +0x28800 */ Latte::LATTE_DB_DEPTH_CONTROL DB_DEPTH_CONTROL;\n\tuint8 padding_28804[4];\n\t/* +0x28808 */ Latte::LATTE_CB_COLOR_CONTROL CB_COLOR_CONTROL;\n\tuint8 padding_2880C[4];\n\t/* +0x28810 */ Latte::LATTE_PA_CL_CLIP_CNTL PA_CL_CLIP_CNTL;\n\t/* +0x28814 */ Latte::LATTE_PA_SU_SC_MODE_CNTL PA_SU_SC_MODE_CNTL;\n\t/* +0x28818 */ Latte::LATTE_PA_CL_VTE_CNTL PA_CL_VTE_CNTL;\n\t/* +0x2881C */ Latte::LATTE_PA_CL_VS_OUT_CNTL PA_CL_VS_OUT_CNTL;\n\n\tuint8 padding_2881C[0x28840 - 0x28820];\n\n\t/* +0x28840 */ Latte::LATTE_SQ_PGM_START_X SQ_PGM_START_PS;\n\t/* +0x28844 */ uint32 ukn28844; // PS size\n\t/* +0x28848 */ uint32 ukn28848;\n\t/* +0x2884C */ uint32 ukn2884C;\n\t/* +0x28850 */ Latte::LATTE_SQ_PGM_RESOURCES_PS SQ_PGM_RESOURCES_PS;\n\t/* +0x28854 */ uint32 ukn28854; // SQ_PGM_EXPORTS_PS\n\t/* +0x28858 */ Latte::LATTE_SQ_PGM_START_X SQ_PGM_START_VS;\n\t/* +0x2885C */ uint32 ukn2885C; // VS size\n\t/* +0x28860 */ uint32 ukn28860;\n\t/* +0x28864 */ uint32 ukn28864;\n\t/* +0x28868 */ Latte::LATTE_SQ_PGM_RESOURCES_VS SQ_PGM_RESOURCES_VS;\n\t/* +0x2886C */ Latte::LATTE_SQ_PGM_START_X SQ_PGM_START_GS;\n\t/* +0x28870 */ uint32 ukn28870; // GS size\n\t/* +0x28874 */ uint32 ukn28874;\n\t/* +0x28878 */ uint32 ukn28878;\n\t/* +0x2887C */ Latte::LATTE_SQ_PGM_RESOURCES_GS SQ_PGM_RESOURCES_GS;\n\t/* +0x28880 */ Latte::LATTE_SQ_PGM_START_X SQ_PGM_START_ES;\n\t/* +0x28884 */ uint32 ukn28884; // ES size\n\t/* +0x28888 */ uint32 ukn28888;\n\t/* +0x2888C */ uint32 ukn2888C;\n\t/* +0x28890 */ Latte::LATTE_SQ_PGM_RESOURCES_ES SQ_PGM_RESOURCES_ES;\n\t/* +0x28894 */ Latte::LATTE_SQ_PGM_START_X SQ_PGM_START_FS;\n\t/* +0x28898 */ uint32 ukn28898; // FS size\n\t/* +0x2889C */ uint32 ukn2889C;\n\t/* +0x288A0 */ uint32 ukn288A0;\n\t/* +0x288A4 */ Latte::LATTE_SQ_PGM_RESOURCES_FS SQ_PGM_RESOURCES_FS;\n\t/* +0x288A8 */ Latte::LATTE_SQ_XX_ITEMSIZE SQ_ESGS_RING_ITEMSIZE;\n\t/* +0x288AC */ Latte::LATTE_SQ_XX_ITEMSIZE SQ_GSVS_RING_ITEMSIZE;\n\t/* +0x288B0 */ Latte::LATTE_SQ_XX_ITEMSIZE SQ_ESTMP_RING_ITEMSIZE;\n\t/* +0x288B4 */ Latte::LATTE_SQ_XX_ITEMSIZE SQ_GSTMP_RING_ITEMSIZE;\n\t/* +0x288B8 */ Latte::LATTE_SQ_XX_ITEMSIZE SQ_VSTMP_RING_ITEMSIZE;\n\tuint8 padding_288BC[0x288E0 - 0x288BC];\n\t/* +0x288E0 */ Latte::LATTE_SQ_VTX_SEMANTIC_CLEAR SQ_VTX_SEMANTIC_CLEAR;\n\tuint8 padding_288E4[0x28A00 - 0x288E4];\n\t/* +0x28A00 */ Latte::LATTE_PA_SU_POINT_SIZE PA_SU_POINT_SIZE;\n\t/* +0x28A04 */ Latte::LATTE_PA_SU_POINT_MINMAX PA_SU_POINT_MINMAX;\n\n\tuint8 padding_28A08[0x28A40 - 0x28A08];\n\n\t/* +0x28A40 */ Latte::LATTE_VGT_GS_MODE VGT_GS_MODE;\n\n\tuint8 padding_28A44[0x28A7C - 0x28A44];\n\n\t/* +0x28A7C */ Latte::LATTE_VGT_DMA_INDEX_TYPE VGT_DMA_INDEX_TYPE;\n\t/* +0x28A80 */ uint32 ukn28A80;\n\t/* +0x28A84 */ Latte::LATTE_VGT_PRIMITIVEID_EN VGT_PRIMITIVEID_EN;\n\t/* +0x28A88 */ Latte::LATTE_VGT_DMA_NUM_INSTANCES VGT_DMA_NUM_INSTANCES;\n\t/* +0x28A8C */ uint32 ukn28A8C;\n\t/* +0x28A90 */ uint32 ukn28A90;\n\t/* +0x28A94 */ Latte::LATTE_VGT_MULTI_PRIM_IB_RESET_EN VGT_MULTI_PRIM_IB_RESET_EN;\n\t/* +0x28A98 */ uint32 ukn28A98;\n\t/* +0x28A9C */ uint32 ukn28A9C;\n\t/* +0x28AA0 */ Latte::LATTE_VGT_INSTANCE_STEP_RATE_X VGT_INSTANCE_STEP_RATE_0;\n\t/* +0x28AA4 */ Latte::LATTE_VGT_INSTANCE_STEP_RATE_X VGT_INSTANCE_STEP_RATE_1;\n\n\tuint8 padding_28AA8[0x28AD0 - 0x28AA8];\n\n\t/* +0x28AD0 */ _LatteRegisterSetStreamoutBuffer VGT_STRMOUT_BUFFER_X[4];\n\t/* +0x28B10 */ Latte::LATTE_VGT_STRMOUT_BASE_OFFSET_X VGT_STRMOUT_BASE_OFFSET_X[4];\n\t/* +0x28B20 */ Latte::LATTE_VGT_STRMOUT_BUFFER_EN VGT_STRMOUT_BUFFER_EN;\n\n\tuint8 padding_28B24[0x28DFC - 0x28B24];\n\n\t/* +0x28DFC */ Latte::LATTE_PA_SU_POLY_OFFSET_CLAMP PA_SU_POLY_OFFSET_CLAMP;\n\t/* +0x28E00 */ Latte::LATTE_PA_SU_POLY_OFFSET_FRONT_SCALE PA_SU_POLY_OFFSET_FRONT_SCALE;\n\t/* +0x28E04 */ Latte::LATTE_PA_SU_POLY_OFFSET_FRONT_OFFSET PA_SU_POLY_OFFSET_FRONT_OFFSET;\n\t/* +0x28E08 */ Latte::LATTE_PA_SU_POLY_OFFSET_BACK_SCALE PA_SU_POLY_OFFSET_BACK_SCALE;\n\t/* +0x28E0C */ Latte::LATTE_PA_SU_POLY_OFFSET_BACK_OFFSET PA_SU_POLY_OFFSET_BACK_OFFSET;\n\n\tuint8 padding_28E10[0x38000 - 0x28E10];\n\n\t// texture units are mapped as following (18 sets each):\n\t// 0xE000 0x38000 -> pixel shader\n\t// 0xE460 0x39180 -> vertex shader / compute shader\n\t// 0xE930 0x3A4C0 -> geometry shader\n\t// there is register space for exactly 160 ps tex units and 176 vs tex units. It's unknown how many GS units there are.\n\n\t/* +0x38000 */ _LatteRegisterSetTextureUnit SQ_TEX_START_PS[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE];\n\t_LatteRegisterSetTextureUnit _DUMMY_TEX_UNITS_PS[160 - Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE];\n\t/* +0x39180 */ _LatteRegisterSetTextureUnit SQ_TEX_START_VS[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE];\n\t_LatteRegisterSetTextureUnit _DUMMY_TEX_UNITS_VS[176 - Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE];\n\t/* +0x3A4C0 */ _LatteRegisterSetTextureUnit SQ_TEX_START_GS[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE];\n\n\tuint8 padding_3A6B8[0x3C000 - 0x3A6B8];\n\n\t/* +0x3C000 */ _LatteRegisterSetSampler SQ_TEX_SAMPLER[18 * 3];\n\n\t/* +0x3C288 */\n\tuint8 padding_3C288[0x40000 - 0x3C288];\n\n\t/* +0x40000 */\n\t// special state registers\n\tuint32 hleSpecialState[9]; // deprecated\n\n\tuint32* GetRawView() const\n\t{\n\t\treturn (uint32*)padding0;\n\t}\n\n\tuint32* GetSpecialStateValues() const\n\t{\n\t\treturn (uint32*)hleSpecialState;\n\t}\n\n\tbool IsRasterizationEnabled() const\n    {\n        bool rasterizationEnabled = !PA_CL_CLIP_CNTL.get_DX_RASTERIZATION_KILL();\n\n       \t// GX2SetSpecialState(0, true) enables DX_RASTERIZATION_KILL, but still expects depth writes to happen? -> Research which stages are disabled by DX_RASTERIZATION_KILL exactly\n        // for now we use a workaround:\n    \tif (!PA_CL_VTE_CNTL.get_VPORT_X_OFFSET_ENA())\n    \t\trasterizationEnabled = true;\n\n        // Culling both front and back faces effectively disables rasterization\n    \tuint32 cullFront = PA_SU_SC_MODE_CNTL.get_CULL_FRONT();\n    \tuint32 cullBack = PA_SU_SC_MODE_CNTL.get_CULL_BACK();\n    \tif (cullFront && cullBack)\n    \t    rasterizationEnabled = false;\n\n        return rasterizationEnabled;\n    }\n};\n\nstatic_assert(sizeof(LatteContextRegister) == 0x10000 * 4 + 9 * 4);\n\nstatic_assert(offsetof(LatteContextRegister, VGT_PRIMITIVE_TYPE) == Latte::REGADDR::VGT_PRIMITIVE_TYPE * 4);\nstatic_assert(offsetof(LatteContextRegister, TD_PS_SAMPLER_BORDER_COLOR) == Latte::REGADDR::TD_PS_SAMPLER0_BORDER_RED * 4);\nstatic_assert(offsetof(LatteContextRegister, TD_VS_SAMPLER_BORDER_COLOR) == Latte::REGADDR::TD_VS_SAMPLER0_BORDER_RED * 4);\nstatic_assert(offsetof(LatteContextRegister, TD_GS_SAMPLER_BORDER_COLOR) == Latte::REGADDR::TD_GS_SAMPLER0_BORDER_RED * 4);\nstatic_assert(offsetof(LatteContextRegister, CB_TARGET_MASK) == Latte::REGADDR::CB_TARGET_MASK * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_SC_GENERIC_SCISSOR_TL) == Latte::REGADDR::PA_SC_GENERIC_SCISSOR_TL * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_SC_GENERIC_SCISSOR_BR) == Latte::REGADDR::PA_SC_GENERIC_SCISSOR_BR * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_MULTI_PRIM_IB_RESET_INDX) == Latte::REGADDR::VGT_MULTI_PRIM_IB_RESET_INDX * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_PRIMITIVEID_EN) == Latte::REGADDR::VGT_PRIMITIVEID_EN * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_DMA_NUM_INSTANCES) == Latte::REGADDR::VGT_DMA_NUM_INSTANCES * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_MULTI_PRIM_IB_RESET_EN) == Latte::REGADDR::VGT_MULTI_PRIM_IB_RESET_EN * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_INSTANCE_STEP_RATE_0) == Latte::REGADDR::VGT_INSTANCE_STEP_RATE_0 * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_INSTANCE_STEP_RATE_1) == Latte::REGADDR::VGT_INSTANCE_STEP_RATE_1 * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_STRMOUT_BUFFER_X) == Latte::REGADDR::VGT_STRMOUT_BUFFER_SIZE_0 * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_STRMOUT_BASE_OFFSET_X) == Latte::REGADDR::VGT_STRMOUT_BASE_OFFSET_0 * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_STRMOUT_BUFFER_EN) == Latte::REGADDR::VGT_STRMOUT_BUFFER_EN * 4);\nstatic_assert(offsetof(LatteContextRegister, SX_ALPHA_TEST_CONTROL) == Latte::REGADDR::SX_ALPHA_TEST_CONTROL * 4);\nstatic_assert(offsetof(LatteContextRegister, DB_STENCILREFMASK) == Latte::REGADDR::DB_STENCILREFMASK * 4);\nstatic_assert(offsetof(LatteContextRegister, DB_STENCILREFMASK_BF) == Latte::REGADDR::DB_STENCILREFMASK_BF * 4);\nstatic_assert(offsetof(LatteContextRegister, SX_ALPHA_REF) == Latte::REGADDR::SX_ALPHA_REF * 4);\nstatic_assert(offsetof(LatteContextRegister, CB_BLEND_RED) == Latte::REGADDR::CB_BLEND_RED * 4);\nstatic_assert(offsetof(LatteContextRegister, CB_BLEND_GREEN) == Latte::REGADDR::CB_BLEND_GREEN * 4);\nstatic_assert(offsetof(LatteContextRegister, CB_BLEND_BLUE) == Latte::REGADDR::CB_BLEND_BLUE * 4);\nstatic_assert(offsetof(LatteContextRegister, CB_BLEND_ALPHA) == Latte::REGADDR::CB_BLEND_ALPHA * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_CL_VPORT_XSCALE) == Latte::REGADDR::PA_CL_VPORT_XSCALE * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_CL_VPORT_XOFFSET) == Latte::REGADDR::PA_CL_VPORT_XOFFSET * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_CL_VPORT_YSCALE) == Latte::REGADDR::PA_CL_VPORT_YSCALE * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_CL_VPORT_YOFFSET) == Latte::REGADDR::PA_CL_VPORT_YOFFSET * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_CL_VPORT_ZSCALE) == Latte::REGADDR::PA_CL_VPORT_ZSCALE * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_CL_VPORT_ZOFFSET) == Latte::REGADDR::PA_CL_VPORT_ZOFFSET * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_CL_CLIP_CNTL) == Latte::REGADDR::PA_CL_CLIP_CNTL * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_SU_SC_MODE_CNTL) == Latte::REGADDR::PA_SU_SC_MODE_CNTL * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_CL_VTE_CNTL) == Latte::REGADDR::PA_CL_VTE_CNTL * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_CL_VS_OUT_CNTL) == Latte::REGADDR::PA_CL_VS_OUT_CNTL * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_SU_POINT_SIZE) == Latte::REGADDR::PA_SU_POINT_SIZE * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_SU_POINT_MINMAX) == Latte::REGADDR::PA_SU_POINT_MINMAX * 4);\nstatic_assert(offsetof(LatteContextRegister, CB_BLENDN_CONTROL) == Latte::REGADDR::CB_BLEND0_CONTROL * 4);\nstatic_assert(offsetof(LatteContextRegister, DB_DEPTH_CONTROL) == Latte::REGADDR::DB_DEPTH_CONTROL * 4);\nstatic_assert(offsetof(LatteContextRegister, CB_COLOR_CONTROL) == Latte::REGADDR::CB_COLOR_CONTROL * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_GS_MODE) == Latte::REGADDR::VGT_GS_MODE * 4);\nstatic_assert(offsetof(LatteContextRegister, VGT_DMA_INDEX_TYPE) == Latte::REGADDR::VGT_DMA_INDEX_TYPE * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_SU_POLY_OFFSET_CLAMP) == Latte::REGADDR::PA_SU_POLY_OFFSET_CLAMP * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_SU_POLY_OFFSET_FRONT_SCALE) == Latte::REGADDR::PA_SU_POLY_OFFSET_FRONT_SCALE * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_SU_POLY_OFFSET_FRONT_OFFSET) == Latte::REGADDR::PA_SU_POLY_OFFSET_FRONT_OFFSET * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_SU_POLY_OFFSET_BACK_SCALE) == Latte::REGADDR::PA_SU_POLY_OFFSET_BACK_SCALE * 4);\nstatic_assert(offsetof(LatteContextRegister, PA_SU_POLY_OFFSET_BACK_OFFSET) == Latte::REGADDR::PA_SU_POLY_OFFSET_BACK_OFFSET * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_VTX_SEMANTIC_X) == Latte::REGADDR::SQ_VTX_SEMANTIC_0 * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_VTX_SEMANTIC_CLEAR) == Latte::REGADDR::SQ_VTX_SEMANTIC_CLEAR * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_TEX_START_PS) == Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_TEX_START_VS) == Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_TEX_START_GS) == Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_TEX_SAMPLER) == Latte::REGADDR::SQ_TEX_SAMPLER_WORD0_0 * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_PGM_START_PS) == Latte::REGADDR::SQ_PGM_START_PS * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_PGM_RESOURCES_PS) == Latte::REGADDR::SQ_PGM_RESOURCES_PS * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_PGM_START_VS) == Latte::REGADDR::SQ_PGM_START_VS * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_PGM_RESOURCES_VS) == Latte::REGADDR::SQ_PGM_RESOURCES_VS * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_PGM_START_FS) == Latte::REGADDR::SQ_PGM_START_FS * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_PGM_RESOURCES_FS) == Latte::REGADDR::SQ_PGM_RESOURCES_FS * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_PGM_START_ES) == Latte::REGADDR::SQ_PGM_START_ES * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_PGM_RESOURCES_ES) == Latte::REGADDR::SQ_PGM_RESOURCES_ES * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_PGM_START_GS) == Latte::REGADDR::SQ_PGM_START_GS * 4);\nstatic_assert(offsetof(LatteContextRegister, SQ_PGM_RESOURCES_GS) == Latte::REGADDR::SQ_PGM_RESOURCES_GS * 4);\nstatic_assert(offsetof(LatteContextRegister, SPI_VS_OUT_CONFIG) == Latte::REGADDR::SPI_VS_OUT_CONFIG * 4);\nstatic_assert(offsetof(LatteContextRegister, LATTE_SPI_VS_OUT_ID_N) == Latte::REGADDR::SPI_VS_OUT_ID_0 * 4);\n"
  },
  {
    "path": "src/Cafe/HW/Latte/ISA/RegDefines.h",
    "content": "#pragma once\n// todo - this file is superseded by LatteReg.h\n\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n\n#define mmPA_CL_VS_OUT_CNTL                             0xA207\n\n#define mmPA_SU_LINE_CNTL                               0xA282\n#define mmPA_SU_POLY_OFFSET_DB_FMT_CNTL                 0xA37E\n\n#define mmPA_SC_WINDOW_OFFSET                           0xA080\n#define mmPA_SC_AA_CONFIG                               0xA301\n#define mmPA_SC_AA_MASK                                 0xA312\n#define mmPA_SC_AA_SAMPLE_LOCS_MCTX                     0xA307\n#define mmPA_SC_AA_SAMPLE_LOCS_8S_WD1_MCTX              0xA308\n#define mmPA_SC_LINE_STIPPLE                            0xA283\n#define mmPA_SC_LINE_CNTL                               0xA300\n#define mmPA_SC_SCREEN_SCISSOR_TL                       0xA00C\n#define mmPA_SC_SCREEN_SCISSOR_BR                       0xA00D\n#define mmPA_SC_WINDOW_SCISSOR_TL                       0xA081\n#define mmPA_SC_WINDOW_SCISSOR_BR                       0xA082\n#define mmPA_SC_CLIPRECT_RULE                           0xA083\n#define mmPA_SC_CLIPRECT_0_TL                           0xA084\n#define mmPA_SC_CLIPRECT_0_BR                           0xA085\n#define mmPA_SC_CLIPRECT_1_TL                           0xA086\n#define mmPA_SC_CLIPRECT_1_BR                           0xA087\n#define mmPA_SC_CLIPRECT_2_TL                           0xA088\n#define mmPA_SC_CLIPRECT_2_BR                           0xA089\n#define mmPA_SC_CLIPRECT_3_TL                           0xA08A\n#define mmPA_SC_CLIPRECT_3_BR                           0xA08B\n#define mmPA_SC_EDGERULE                                0xA08C\n\n#define mmPA_SC_MODE_CNTL                               0xA293\n#define mmPA_SC_MPASS_PS_CNTL                           0xA292\n\n#define mmVGT_DRAW_INITIATOR                            0xA1FC\n#define mmVGT_EVENT_INITIATOR                           0xA2A4\n#define mmVGT_EVENT_ADDRESS_REG                         0xA1FE\n#define mmVGT_DMA_BASE_HI                               0xA1F9\n#define mmVGT_DMA_BASE                                  0xA1FA\n#define mmVGT_DMA_INDEX_TYPE                            0xA29F\n#define mmVGT_DMA_NUM_INSTANCES                         0xA2A2\n#define mmVGT_DMA_SIZE                                  0xA29D\n\n#define mmVGT_IMMED_DATA                                0xA1FD\n#define mmVGT_INDEX_TYPE                                0x2257\n#define mmVGT_NUM_INDICES                               0x225C\n#define mmVGT_NUM_INSTANCES                             0x225D\n#define mmVGT_PRIMITIVE_TYPE                            0x2256\n#define mmVGT_PRIMITIVEID_EN                            0xA2A1\n#define mmVGT_VTX_CNT_EN                                0xA2AE\n#define mmVGT_REUSE_OFF                                 0xA2AD\n#define mmVGT_MAX_VTX_INDX                              0xA100\n#define mmVGT_MIN_VTX_INDX                              0xA101\n#define mmVGT_INDX_OFFSET                               0xA102\n#define mmVGT_VERTEX_REUSE_BLOCK_CNTL                   0xA316\n#define mmVGT_OUT_DEALLOC_CNTL                          0xA317\n#define mmVGT_MULTI_PRIM_IB_RESET_EN                    0xA2A5\n#define mmVGT_ENHANCE                                   0xA294\n#define mmVGT_OUTPUT_PATH_CNTL                          0xA284\n#define mmVGT_HOS_CNTL                                  0xA285\n#define mmVGT_HOS_MAX_TESS_LEVEL                        0xA286\n#define mmVGT_HOS_MIN_TESS_LEVEL                        0xA287\n#define mmVGT_HOS_REUSE_DEPTH                           0xA288\n#define mmVGT_GROUP_PRIM_TYPE                           0xA289\n#define mmVGT_GROUP_FIRST_DECR                          0xA28A\n#define mmVGT_GROUP_DECR                                0xA28B\n#define mmVGT_GROUP_VECT_0_CNTL                         0xA28C\n#define mmVGT_GROUP_VECT_1_CNTL                         0xA28D\n#define mmVGT_GROUP_VECT_0_FMT_CNTL                     0xA28E\n#define mmVGT_GROUP_VECT_1_FMT_CNTL                     0xA28F\n#define mmVGT_GS_OUT_PRIM_TYPE                          0xA29B\n\n#define mmVGT_STRMOUT_EN                                0xA2AC\n#define mmVGT_STRMOUT_BUFFER_SIZE_0                     0xA2B4\n#define mmVGT_STRMOUT_BUFFER_SIZE_1                     0xA2B8\n#define mmVGT_STRMOUT_BUFFER_SIZE_2                     0xA2BC\n#define mmVGT_STRMOUT_BUFFER_SIZE_3                     0xA2C0\n#define mmVGT_STRMOUT_BUFFER_OFFSET_0                   0xA2B7\n#define mmVGT_STRMOUT_BUFFER_OFFSET_1                   0xA2BB\n#define mmVGT_STRMOUT_BUFFER_OFFSET_2                   0xA2BF\n#define mmVGT_STRMOUT_BUFFER_OFFSET_3                   0xA2C3\n#define mmVGT_STRMOUT_VTX_STRIDE_0                      0xA2B5\n#define mmVGT_STRMOUT_VTX_STRIDE_1                      0xA2B9\n#define mmVGT_STRMOUT_VTX_STRIDE_2                      0xA2BD\n#define mmVGT_STRMOUT_VTX_STRIDE_3                      0xA2C1\n#define mmVGT_STRMOUT_BUFFER_BASE_0                     0xA2B6\n#define mmVGT_STRMOUT_BUFFER_BASE_1                     0xA2BA\n#define mmVGT_STRMOUT_BUFFER_BASE_2                     0xA2BE\n#define mmVGT_STRMOUT_BUFFER_BASE_3                     0xA2C2\n#define mmVGT_STRMOUT_BUFFER_EN                         0xA2C8\n#define mmVGT_STRMOUT_BASE_OFFSET_0                     0xA2C4\n#define mmVGT_STRMOUT_BASE_OFFSET_1                     0xA2C5\n#define mmVGT_STRMOUT_BASE_OFFSET_2                     0xA2C6\n#define mmVGT_STRMOUT_BASE_OFFSET_3                     0xA2C7\n#define mmVGT_STRMOUT_BASE_OFFSET_HI_0                  0xA2D1\n#define mmVGT_STRMOUT_BASE_OFFSET_HI_1                  0xA2D2\n#define mmVGT_STRMOUT_BASE_OFFSET_HI_2                  0xA2D3\n#define mmVGT_STRMOUT_BASE_OFFSET_HI_3                  0xA2D4\n#define mmVGT_STRMOUT_DRAW_OPAQUE_OFFSET                0xA2CA\n#define mmVGT_STRMOUT_DRAW_OPAQUE_BUFFER_FILLED_SIZE    0xA2CB\n#define mmVGT_STRMOUT_DRAW_OPAQUE_VERTEX_STRIDE         0xA2CC\n\n#define mmSQ_PGM_START_PS                               0xA210\n#define mmSQ_PGM_CF_OFFSET_PS                           0xA233\n#define mmSQ_PGM_RESOURCES_PS                           0xA214\n#define mmSQ_PGM_EXPORTS_PS                             0xA215\n#define mmSQ_PGM_START_VS                               0xA216\n#define mmSQ_PGM_CF_OFFSET_VS                           0xA234\n#define mmSQ_PGM_RESOURCES_VS                           0xA21A\n#define mmSQ_PGM_START_GS                               0xA21B\n#define mmSQ_PGM_CF_OFFSET_GS                           0xA235\n#define mmSQ_PGM_RESOURCES_GS                           0xA21F\n#define mmSQ_PGM_START_ES                               0xA220\n#define mmSQ_PGM_CF_OFFSET_ES                           0xA236\n#define mmSQ_PGM_RESOURCES_ES                           0xA224\n#define mmSQ_PGM_START_FS                               0xA225\n#define mmSQ_PGM_CF_OFFSET_FS                           0xA237\n#define mmSQ_PGM_RESOURCES_FS                           0xA229\n#define mmSQ_ESGS_RING_ITEMSIZE                         0xA22A\n#define mmSQ_GSVS_RING_ITEMSIZE                         0xA22B\n#define mmSQ_ESTMP_RING_ITEMSIZE                        0xA22C\n#define mmSQ_GSTMP_RING_ITEMSIZE                        0xA22D\n#define mmSQ_VSTMP_RING_ITEMSIZE                        0xA22E\n#define mmSQ_PSTMP_RING_ITEMSIZE                        0xA22F\n#define mmSQ_FBUF_RING_ITEMSIZE                         0xA230\n#define mmSQ_REDUC_RING_ITEMSIZE                        0xA231\n#define mmSQ_GS_VERT_ITEMSIZE                           0xA232\n#define mmSQ_VTX_SEMANTIC_CLEAR                         0xA238\n\n#define mmSQ_VTX_SEMANTIC_0                             0xA0E0\n#define mmSQ_VTX_SEMANTIC_1                             0xA0E1\n#define mmSQ_VTX_SEMANTIC_2                             0xA0E2\n#define mmSQ_VTX_SEMANTIC_3                             0xA0E3\n#define mmSQ_VTX_SEMANTIC_4                             0xA0E4\n#define mmSQ_VTX_SEMANTIC_5                             0xA0E5\n#define mmSQ_VTX_SEMANTIC_6                             0xA0E6\n#define mmSQ_VTX_SEMANTIC_7                             0xA0E7\n#define mmSQ_VTX_SEMANTIC_8                             0xA0E8\n#define mmSQ_VTX_SEMANTIC_9                             0xA0E9\n#define mmSQ_VTX_SEMANTIC_10                            0xA0EA\n#define mmSQ_VTX_SEMANTIC_11                            0xA0EB\n#define mmSQ_VTX_SEMANTIC_12                            0xA0EC\n#define mmSQ_VTX_SEMANTIC_13                            0xA0ED\n#define mmSQ_VTX_SEMANTIC_14                            0xA0EE\n#define mmSQ_VTX_SEMANTIC_15                            0xA0EF\n#define mmSQ_VTX_SEMANTIC_16                            0xA0F0\n#define mmSQ_VTX_SEMANTIC_17                            0xA0F1\n#define mmSQ_VTX_SEMANTIC_18                            0xA0F2\n#define mmSQ_VTX_SEMANTIC_19                            0xA0F3\n#define mmSQ_VTX_SEMANTIC_20                            0xA0F4\n#define mmSQ_VTX_SEMANTIC_21                            0xA0F5\n#define mmSQ_VTX_SEMANTIC_22                            0xA0F6\n#define mmSQ_VTX_SEMANTIC_23                            0xA0F7\n#define mmSQ_VTX_SEMANTIC_24                            0xA0F8\n#define mmSQ_VTX_SEMANTIC_25                            0xA0F9\n#define mmSQ_VTX_SEMANTIC_26                            0xA0FA\n#define mmSQ_VTX_SEMANTIC_27                            0xA0FB\n#define mmSQ_VTX_SEMANTIC_28                            0xA0FC\n#define mmSQ_VTX_SEMANTIC_29                            0xA0FD\n#define mmSQ_VTX_SEMANTIC_30                            0xA0FE\n#define mmSQ_VTX_SEMANTIC_31                            0xA0FF\n\n#define mmSPI_VS_OUT_ID_0                               0xA185\n#define mmSPI_VS_OUT_ID_1                               0xA186\n#define mmSPI_VS_OUT_ID_2                               0xA187\n#define mmSPI_VS_OUT_ID_3                               0xA188\n#define mmSPI_VS_OUT_ID_4                               0xA189\n#define mmSPI_VS_OUT_ID_5                               0xA18A\n#define mmSPI_VS_OUT_ID_6                               0xA18B\n#define mmSPI_VS_OUT_ID_7                               0xA18C\n#define mmSPI_VS_OUT_ID_8                               0xA18D\n#define mmSPI_VS_OUT_ID_9                               0xA18E\n#define mmSPI_PS_INPUT_CNTL_0                           0xA191\n#define mmSPI_PS_INPUT_CNTL_1                           0xA192\n#define mmSPI_PS_INPUT_CNTL_2                           0xA193\n#define mmSPI_PS_INPUT_CNTL_3                           0xA194\n#define mmSPI_PS_INPUT_CNTL_4                           0xA195\n#define mmSPI_PS_INPUT_CNTL_5                           0xA196\n#define mmSPI_PS_INPUT_CNTL_6                           0xA197\n#define mmSPI_PS_INPUT_CNTL_7                           0xA198\n#define mmSPI_PS_INPUT_CNTL_8                           0xA199\n#define mmSPI_PS_INPUT_CNTL_9                           0xA19A\n#define mmSPI_PS_INPUT_CNTL_10                          0xA19B\n#define mmSPI_PS_INPUT_CNTL_11                          0xA19C\n#define mmSPI_PS_INPUT_CNTL_12                          0xA19D\n#define mmSPI_PS_INPUT_CNTL_13                          0xA19E\n#define mmSPI_PS_INPUT_CNTL_14                          0xA19F\n#define mmSPI_PS_INPUT_CNTL_15                          0xA1A0\n#define mmSPI_PS_INPUT_CNTL_16                          0xA1A1\n#define mmSPI_PS_INPUT_CNTL_17                          0xA1A2\n#define mmSPI_PS_INPUT_CNTL_18                          0xA1A3\n#define mmSPI_PS_INPUT_CNTL_19                          0xA1A4\n#define mmSPI_PS_INPUT_CNTL_20                          0xA1A5\n#define mmSPI_PS_INPUT_CNTL_21                          0xA1A6\n#define mmSPI_PS_INPUT_CNTL_22                          0xA1A7\n#define mmSPI_PS_INPUT_CNTL_23                          0xA1A8\n#define mmSPI_PS_INPUT_CNTL_24                          0xA1A9\n#define mmSPI_PS_INPUT_CNTL_25                          0xA1AA\n#define mmSPI_PS_INPUT_CNTL_26                          0xA1AB\n#define mmSPI_PS_INPUT_CNTL_27                          0xA1AC\n#define mmSPI_PS_INPUT_CNTL_28                          0xA1AD\n#define mmSPI_PS_INPUT_CNTL_29                          0xA1AE\n#define mmSPI_PS_INPUT_CNTL_30                          0xA1AF\n#define mmSPI_PS_INPUT_CNTL_31                          0xA1B0\n#define mmSPI_VS_OUT_CONFIG                             0xA1B1\n#define mmSPI_THREAD_GROUPING                           0xA1B2\n#define mmSPI_PS_IN_CONTROL_0                           0xA1B3\n#define mmSPI_PS_IN_CONTROL_1                           0xA1B4\n#define mmSPI_INTERP_CONTROL_0                          0xA1B5\n#define mmSPI_INPUT_Z                                   0xA1B6\n\n#define mmDB_DEPTH_BASE                                 0xA003\n#define mmDB_DEPTH_INFO                                 0xA004\n#define mmDB_HTILE_DATA_BASE                            0xA005\n#define mmDB_DEPTH_SIZE                                 0xA000\n#define mmDB_DEPTH_VIEW                                 0xA001\n#define mmDB_RENDER_CONTROL                             0xA343\n#define mmDB_RENDER_OVERRIDE                            0xA344\n#define mmDB_SHADER_CONTROL                             0xA203\n#define mmDB_STENCIL_CLEAR                              0xA00A\n#define mmDB_DEPTH_CLEAR                                0xA00B\n#define mmDB_HTILE_SURFACE                              0xA349\n#define mmDB_PRELOAD_CONTROL                            0xA34C\n#define mmDB_PREFETCH_LIMIT                             0xA34D\n#define mmDB_STENCILREFMASK                             0xA10C\n#define mmDB_STENCILREFMASK_BF                          0xA10D\n#define mmDB_SRESULTS_COMPARE_STATE0                    0xA34A\n#define mmDB_SRESULTS_COMPARE_STATE1                    0xA34B\n\n#define mmDB_ALPHA_TO_MASK                              0xA351\n\n#define mmCB_CLRCMP_CONTROL                             0xA30C\n#define mmCB_CLRCMP_SRC                                 0xA30D\n#define mmCB_CLRCMP_DST                                 0xA30E\n#define mmCB_CLRCMP_MSK                                 0xA30F\n#define mmCB_COLOR0_BASE                                0xA010\n#define mmCB_COLOR1_BASE                                0xA011\n#define mmCB_COLOR2_BASE                                0xA012\n#define mmCB_COLOR3_BASE                                0xA013\n#define mmCB_COLOR4_BASE                                0xA014\n#define mmCB_COLOR5_BASE                                0xA015\n#define mmCB_COLOR6_BASE                                0xA016\n#define mmCB_COLOR7_BASE                                0xA017\n#define mmCB_COLOR0_SIZE                                0xA018\n#define mmCB_COLOR1_SIZE                                0xA019\n#define mmCB_COLOR2_SIZE                                0xA01A\n#define mmCB_COLOR3_SIZE                                0xA01B\n#define mmCB_COLOR4_SIZE                                0xA01C\n#define mmCB_COLOR5_SIZE                                0xA01D\n#define mmCB_COLOR6_SIZE                                0xA01E\n#define mmCB_COLOR7_SIZE                                0xA01F\n#define mmCB_COLOR0_VIEW                                0xA020\n#define mmCB_COLOR1_VIEW                                0xA021\n#define mmCB_COLOR2_VIEW                                0xA022\n#define mmCB_COLOR3_VIEW                                0xA023\n#define mmCB_COLOR4_VIEW                                0xA024\n#define mmCB_COLOR5_VIEW                                0xA025\n#define mmCB_COLOR6_VIEW                                0xA026\n#define mmCB_COLOR7_VIEW                                0xA027\n#define mmCB_COLOR0_INFO                                0xA028\n#define mmCB_COLOR1_INFO                                0xA029\n#define mmCB_COLOR2_INFO                                0xA02A\n#define mmCB_COLOR3_INFO                                0xA02B\n#define mmCB_COLOR4_INFO                                0xA02C\n#define mmCB_COLOR5_INFO                                0xA02D\n#define mmCB_COLOR6_INFO                                0xA02E\n#define mmCB_COLOR7_INFO                                0xA02F\n#define mmCB_COLOR0_TILE                                0xA030\n#define mmCB_COLOR1_TILE                                0xA031\n#define mmCB_COLOR2_TILE                                0xA032\n#define mmCB_COLOR3_TILE                                0xA033\n#define mmCB_COLOR4_TILE                                0xA034\n#define mmCB_COLOR5_TILE                                0xA035\n#define mmCB_COLOR6_TILE                                0xA036\n#define mmCB_COLOR7_TILE                                0xA037\n#define mmCB_COLOR0_FRAG                                0xA038\n#define mmCB_COLOR1_FRAG                                0xA039\n#define mmCB_COLOR2_FRAG                                0xA03A\n#define mmCB_COLOR3_FRAG                                0xA03B\n#define mmCB_COLOR4_FRAG                                0xA03C\n#define mmCB_COLOR5_FRAG                                0xA03D\n#define mmCB_COLOR6_FRAG                                0xA03E\n#define mmCB_COLOR7_FRAG                                0xA03F\n#define mmCB_COLOR0_MASK                                0xA040\n#define mmCB_COLOR1_MASK                                0xA041\n#define mmCB_COLOR2_MASK                                0xA042\n#define mmCB_COLOR3_MASK                                0xA043\n#define mmCB_COLOR4_MASK                                0xA044\n#define mmCB_COLOR5_MASK                                0xA045\n#define mmCB_COLOR6_MASK                                0xA046\n#define mmCB_COLOR7_MASK                                0xA047\n#define mmCB_SHADER_MASK                                0xA08F\n#define mmCB_SHADER_CONTROL                             0xA1E8\n\n#define mmSQ_VTX_BASE_VTX_LOC                           0xF3FC // baseVertex\n#define mmSQ_VTX_START_INST_LOC                         0xF3FD // baseInstance\n\n#define mmSQ_CONFIG\t\t\t\t\t\t\t\t\t\t0x2300 // used by GX2SetShaderModeEx\n#define mmSQ_GPR_RESOURCE_MGMT_1\t\t\t\t\t\t0x2301\n#define mmSQ_THREAD_RESOURCE_MGMT\t\t\t\t\t\t0x2303\n#define mmSQ_STACK_RESOURCE_MGMT_1\t\t\t\t\t\t0x2304\n#define mmSQ_STACK_RESOURCE_MGMT_2\t\t\t\t\t\t0x2305\n#define mmSQ_ESGS_RING_BASE\t\t\t\t\t\t\t\t0x2310\n#define mmSQ_ESGS_RING_SIZE\t\t\t\t\t\t\t\t0x2311\n#define mmSQ_GSVS_RING_BASE\t\t\t\t\t\t\t\t0x2312\n#define mmSQ_GSVS_RING_SIZE\t\t\t\t\t\t\t\t0x2313\n#define mmSQ_ESTMP_RING_BASE\t\t\t\t\t\t\t0x2314\n#define mmSQ_ESTMP_RING_SIZE\t\t\t\t\t\t\t0x2315\n#define mmSQ_GSTMP_RING_BASE\t\t\t\t\t\t\t0x2316\n#define mmSQ_GSTMP_RING_SIZE\t\t\t\t\t\t\t0x2317\n\n\n#define mmSQ_TEX_RESOURCE_WORD0\t\t\t\t\t\t\t0xE000\n#define mmSQ_ALU_CONSTANT0_0\t\t\t\t\t\t\t0xC000\n\n#define mmSQ_VTX_ATTRIBUTE_BLOCK_START\t\t\t\t\t(mmSQ_TEX_RESOURCE_WORD0+0x8C0)\n#define mmSQ_VTX_ATTRIBUTE_BLOCK_END\t\t\t\t\t(mmSQ_VTX_ATTRIBUTE_BLOCK_START + 7*16)\n\n#define mmSQ_VTX_UNIFORM_BLOCK_START\t\t\t\t\t(mmSQ_TEX_RESOURCE_WORD0+0x7E0) // 7 dwords for each uniform block\n#define mmSQ_VTX_UNIFORM_BLOCK_END\t\t\t\t\t\t(mmSQ_VTX_UNIFORM_BLOCK_START + 7*16 - 1)\n\n#define mmSQ_PS_UNIFORM_BLOCK_START\t\t\t\t\t\t(mmSQ_TEX_RESOURCE_WORD0+0x250) // 7 dwords for each uniform block\n#define mmSQ_PS_UNIFORM_BLOCK_END\t\t\t\t\t\t(mmSQ_PS_UNIFORM_BLOCK_START + 7*16 - 1)\n\n#define mmSQ_GS_UNIFORM_BLOCK_START\t\t\t\t\t\t(mmSQ_TEX_RESOURCE_WORD0+0xCB0) // 7 dwords for each uniform block\n#define mmSQ_GS_UNIFORM_BLOCK_END\t\t\t\t\t\t(mmSQ_GS_UNIFORM_BLOCK_START + 7*16 - 1)\n\n#define mmSQ_CS_DISPATCH_PARAMS\t\t\t\t\t\t\t(mmSQ_TEX_RESOURCE_WORD0+0x865)"
  },
  {
    "path": "src/Cafe/HW/Latte/LatteAddrLib/AddrLibFastDecode.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n\ntemplate<typename texelBaseType, int texelBaseTypeCount, bool isEncodeDirection, bool isCompressed>\nvoid optimizedDecodeLoop_tm04_numSamples1_8x8(LatteTextureLoaderCtx* textureLoader, uint8* outputData, sint32 texelCountX, sint32 texelCountY)\n{\n\tuint16* tableBase = textureLoader->computeAddrInfo.microTilePixelIndexTable + ((textureLoader->computeAddrInfo.slice & 7) << 6);\n\tfor (sint32 yt = 0; yt < texelCountY; yt += 8)\n\t{\n\t\tfor (sint32 xt = 0; xt < texelCountX; xt += 8)\n\t\t{\n\t\t\tsint32 baseOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMacroTiledCached_tm04_sample1(xt, yt, &textureLoader->computeAddrInfo); // this is only 10-20% of execution time\n\t\t\tfor (sint32 ry = 0; ry < 8; ry++)\n\t\t\t{\n\t\t\t\tsint32 pixelOffset = ((yt + ry)*textureLoader->decodedTexelCountX + (xt)) * (sizeof(texelBaseType)*texelBaseTypeCount);\n\t\t\t\ttexelBaseType* blockOutput = (texelBaseType*)(outputData + pixelOffset);\n\n\t\t\t\tuint16* pixelOffsets = tableBase + (ry << 3);\n\n\t\t\t\tfor (sint32 rx = 0; rx < 8; rx++)\n\t\t\t\t{\n\t\t\t\t\tuint32 pixelIndex = *pixelOffsets;\n\t\t\t\t\tpixelOffsets++;\n\t\t\t\t\tuint32 pixelOffset = pixelIndex * sizeof(texelBaseType)*texelBaseTypeCount;\n\t\t\t\t\tuint32 elemOffset = pixelOffset;\n\t\t\t\t\tif ((sizeof(texelBaseType)*texelBaseTypeCount * 8 * 8) > 256)\n\t\t\t\t\t{\n\t\t\t\t\t\t// separate group bytes, for small formats this step is not necessary since elemOffset is never over 0xFF (maximum is 8*8*bpp)\n\t\t\t\t\t\telemOffset = (elemOffset & 0xFF) | ((elemOffset&~0xFF) << 3);\n\t\t\t\t\t}\n\n\t\t\t\t\tsint32 offset = baseOffset + elemOffset;\n\n\t\t\t\t\tuint8* blockData = textureLoader->inputData + offset;\n\t\t\t\t\t// copy as-is\n\t\t\t\t\tif (texelBaseTypeCount == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t\t\t*(texelBaseType*)blockData = *blockOutput;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t*blockOutput = *(texelBaseType*)blockData;\n\t\t\t\t\t\tblockOutput++;\n\t\t\t\t\t}\n\t\t\t\t\telse if (texelBaseTypeCount == 2)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t((texelBaseType*)blockData)[0] = blockOutput[0];\n\t\t\t\t\t\t\t((texelBaseType*)blockData)[1] = blockOutput[1];\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tblockOutput[0] = ((texelBaseType*)blockData)[0];\n\t\t\t\t\t\t\tblockOutput[1] = ((texelBaseType*)blockData)[1];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tblockOutput += 2;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tassert_dbg();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\ntemplate<typename texelBaseType, int texelBaseTypeCount, bool isEncodeDirection, bool isCompressed>\nvoid optimizedDecodeLoop_tm04_numSamples1_8x8_optimizedRowCopy(LatteTextureLoaderCtx* textureLoader, uint8* outputData, sint32 texelCountX, sint32 texelCountY)\n{\n\tuint16* tableBase = textureLoader->computeAddrInfo.microTilePixelIndexTable + ((textureLoader->computeAddrInfo.slice & 7) << 6);\n\tfor (sint32 yt = 0; yt < texelCountY; yt += 8)\n\t{\n\t\tfor (sint32 xt = 0; xt < texelCountX; xt += 8)\n\t\t{\n\t\t\tsint32 baseOffset = ComputeSurfaceAddrFromCoordMacroTiledCached_tm04_sample1(xt, yt, &textureLoader->computeAddrInfo); // this is only 10-20% of execution time\n\t\t\tfor (sint32 ry = 0; ry < 8; ry++)\n\t\t\t{\n\t\t\t\tsint32 pixelOffset = ((yt + ry)*textureLoader->decodedTexelCountX + (xt)) * (sizeof(texelBaseType)*texelBaseTypeCount);\n\t\t\t\ttexelBaseType* blockOutput = (texelBaseType*)(outputData + pixelOffset);\n\n\t\t\t\tuint16* pixelOffsets = tableBase + (ry << 3);\n\n\t\t\t\tuint32 pixelIndex = *pixelOffsets;\n\t\t\t\tpixelOffsets++;\n\t\t\t\tuint32 elemOffset = pixelIndex * sizeof(texelBaseType)*texelBaseTypeCount;\n\t\t\t\tif ((sizeof(texelBaseType)*texelBaseTypeCount * 8 * 8) > 256)\n\t\t\t\t{\n\t\t\t\t\t// separate group bytes, for small formats this step is not necessary since elemOffset is never over 0xFF (maximum is 8*8*bpp)\n\t\t\t\t\telemOffset = (elemOffset & 0xFF) | ((elemOffset&~0xFF) << 3);\n\t\t\t\t}\n\n\t\t\t\tsint32 offset = baseOffset + elemOffset;\n\n\t\t\t\ttexelBaseType* blockData = (texelBaseType*)(textureLoader->inputData + offset);\n\t\t\t\t// x-to-offset translation table (for bpp = 64)\n\t\t\t\t// 0\t->\t0\n\t\t\t\t// 1\t->\t1\n\t\t\t\t// 2\t->\t4\n\t\t\t\t// 3\t->\t5\n\t\t\t\t// 4\t->\t8\n\t\t\t\t// 5\t->\t9\n\t\t\t\t// 6\t->\t12\n\t\t\t\t// 7\t->\t13\n\n\t\t\t\t// x-to-offset translation table (for bpp = 32)\n\t\t\t\t// 0\t->\t0\n\t\t\t\t// 1\t->\t1\n\t\t\t\t// 2\t->\t2\n\t\t\t\t// 3\t->\t3\n\t\t\t\t// 4\t->\t8\n\t\t\t\t// 5\t->\t9\n\t\t\t\t// 6\t->\t10\n\t\t\t\t// 7\t->\t11\n\n\n\t\t\t\tif ((sizeof(texelBaseType)*texelBaseTypeCount) == 8)\n\t\t\t\t{\n\t\t\t\t\t// bpp = 64\n\t\t\t\t\tif (texelBaseTypeCount == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tblockData[0] = blockOutput[0];\n\t\t\t\t\t\t\tblockData[1] = blockOutput[1];\n\t\t\t\t\t\t\tblockData[4] = blockOutput[2];\n\t\t\t\t\t\t\tblockData[5] = blockOutput[3];\n\t\t\t\t\t\t\tblockData[8] = blockOutput[4];\n\t\t\t\t\t\t\tblockData[9] = blockOutput[5];\n\t\t\t\t\t\t\tblockData[12] = blockOutput[6];\n\t\t\t\t\t\t\tblockData[13] = blockOutput[7];\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tblockOutput[0] = blockData[0];\n\t\t\t\t\t\t\tblockOutput[1] = blockData[1];\n\t\t\t\t\t\t\tblockOutput[2] = blockData[4];\n\t\t\t\t\t\t\tblockOutput[3] = blockData[5];\n\t\t\t\t\t\t\tblockOutput[4] = blockData[8];\n\t\t\t\t\t\t\tblockOutput[5] = blockData[9];\n\t\t\t\t\t\t\tblockOutput[6] = blockData[12];\n\t\t\t\t\t\t\tblockOutput[7] = blockData[13];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tblockOutput += 8;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tassert_dbg();\n\t\t\t\t}\n\t\t\t\telse if ((sizeof(texelBaseType)*texelBaseTypeCount) == 4)\n\t\t\t\t{\n\t\t\t\t\t// bpp = 32\n\t\t\t\t\tif (texelBaseTypeCount == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tuint64* blockOutput64 = (uint64*)blockOutput;\n\t\t\t\t\t\tuint64* blockData64 = (uint64*)blockData;\n\t\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tblockData64[0] = blockOutput64[0];\n\t\t\t\t\t\t\tblockData64[1] = blockOutput64[1];\n\t\t\t\t\t\t\tblockData64[4] = blockOutput64[2];\n\t\t\t\t\t\t\tblockData64[5] = blockOutput64[3];\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tblockOutput64[0] = blockData64[0];\n\t\t\t\t\t\t\tblockOutput64[1] = blockData64[1];\n\t\t\t\t\t\t\tblockOutput64[2] = blockData64[4];\n\t\t\t\t\t\t\tblockOutput64[3] = blockData64[5];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tblockOutput += 8;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t}\n\t\t\t\telse if ((sizeof(texelBaseType)*texelBaseTypeCount) == 1)\n\t\t\t\t{\n\t\t\t\t\t// bpp = 8\n\t\t\t\t\tif (texelBaseTypeCount == 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tuint64* blockOutput64 = (uint64*)blockOutput;\n\t\t\t\t\t\tuint64* blockData64 = (uint64*)blockData;\n\t\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t\t\tblockData64[0] = blockOutput64[0];\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tblockOutput64[0] = blockData64[0];\n\t\t\t\t\t\tblockOutput += 8;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t}\n}\n\ntemplate<typename texelBaseType, int texelBaseTypeCount, bool isEncodeDirection, bool isCompressed>\nvoid optimizedDecodeLoops(LatteTextureLoaderCtx* textureLoader, uint8* outputData)\n{\n\tsint32 texelCountX;\n\tsint32 texelCountY;\n\tif (isCompressed)\n\t{\n\t\ttexelCountX = (textureLoader->width + 3) / 4;\n\t\ttexelCountY = (textureLoader->height + 3) / 4;\n\t}\n\telse\n\t{\n\t\ttexelCountX = textureLoader->width;\n\t\ttexelCountY = textureLoader->height;\n\t}\n\n\tif (textureLoader->tileMode == Latte::E_HWTILEMODE::TM_2D_TILED_THIN1 && textureLoader->computeAddrInfo.numSamples == 1)\n\t{\n\t\tsint32 texelCountOrigX = texelCountX;\n\t\tsint32 texelCountOrigY = texelCountY;\n\t\ttexelCountX &= ~7;\n\t\ttexelCountY &= ~7;\n\t\t// full tiles (assuming tileMode=4 and numSamples=1)\n\t\t// only recalculate tile related offset at the beginning of each block\n\t\t// calculate offsets in loop\n\n\t\t// unsure if this variant is faster:\n\t\tif (textureLoader->computeAddrInfo.microTileType == 0 && (sizeof(texelBaseType)*texelBaseTypeCount) == 8)\n\t\t{\n\t\t\toptimizedDecodeLoop_tm04_numSamples1_8x8_optimizedRowCopy<texelBaseType, texelBaseTypeCount, isEncodeDirection, isCompressed>(textureLoader, outputData, texelCountX, texelCountY);\n\t\t}\n\t\telse if (textureLoader->computeAddrInfo.microTileType == 0 && (sizeof(texelBaseType)*texelBaseTypeCount) == 4)\n\t\t{\n\t\t\toptimizedDecodeLoop_tm04_numSamples1_8x8_optimizedRowCopy<texelBaseType, texelBaseTypeCount, isEncodeDirection, isCompressed>(textureLoader, outputData, texelCountX, texelCountY);\n\t\t}\n\t\telse if (textureLoader->computeAddrInfo.microTileType == 0 && (sizeof(texelBaseType)*texelBaseTypeCount) == 1)\n\t\t{\n\t\t\toptimizedDecodeLoop_tm04_numSamples1_8x8_optimizedRowCopy<texelBaseType, texelBaseTypeCount, isEncodeDirection, isCompressed>(textureLoader, outputData, texelCountX, texelCountY);\n\t\t}\n\t\telse\n\t\t{\n\t\t\toptimizedDecodeLoop_tm04_numSamples1_8x8<texelBaseType, texelBaseTypeCount, isEncodeDirection, isCompressed>(textureLoader, outputData, texelCountX, texelCountY);\n\t\t}\n\t\t// the above code only handles full 8x8 pixel blocks, for uneven sizes we need to process the remaining pixels here\n\t\t// right border\n\t\tfor (sint32 yt = 0; yt < texelCountY; yt++)\n\t\t{\n\t\t\tsint32 pixelOffset = (yt*textureLoader->decodedTexelCountX + texelCountX) * (sizeof(texelBaseType)*texelBaseTypeCount);\n\t\t\ttexelBaseType* blockOutput = (texelBaseType*)(outputData + pixelOffset);\n\t\t\tfor (sint32 xt = texelCountX; xt < texelCountOrigX; xt++)\n\t\t\t{\n\t\t\t\tsint32 offset = ComputeSurfaceAddrFromCoordMacroTiledCached_tm04_sample1(xt, yt, &textureLoader->computeAddrInfo);\n\t\t\t\tuint8* blockData = textureLoader->inputData + offset;\n\t\t\t\t// copy as-is\n\t\t\t\tif (texelBaseTypeCount == 1)\n\t\t\t\t{\n\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t\t*(texelBaseType*)blockData = *blockOutput;\n\t\t\t\t\telse\n\t\t\t\t\t\t*blockOutput = *(texelBaseType*)blockData;\n\t\t\t\t\tblockOutput++;\n\t\t\t\t}\n\t\t\t\telse if (texelBaseTypeCount == 2)\n\t\t\t\t{\n\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t{\n\t\t\t\t\t\t((texelBaseType*)blockData)[0] = blockOutput[0];\n\t\t\t\t\t\t((texelBaseType*)blockData)[1] = blockOutput[1];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tblockOutput[0] = ((texelBaseType*)blockData)[0];\n\t\t\t\t\t\tblockOutput[1] = ((texelBaseType*)blockData)[1];\n\t\t\t\t\t}\n\t\t\t\t\tblockOutput += 2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// bottom border (with bottom right corner)\n\t\tfor (sint32 yt = texelCountY; yt < texelCountOrigY; yt++)\n\t\t{\n\t\t\tsint32 pixelOffset = (yt*textureLoader->decodedTexelCountX) * (sizeof(texelBaseType)*texelBaseTypeCount);\n\t\t\ttexelBaseType* blockOutput = (texelBaseType*)(outputData + pixelOffset);\n\t\t\tfor (sint32 xt = 0; xt < texelCountOrigX; xt++)\n\t\t\t{\n\t\t\t\tsint32 offset = ComputeSurfaceAddrFromCoordMacroTiledCached_tm04_sample1(xt, yt, &textureLoader->computeAddrInfo);\n\t\t\t\tuint8* blockData = textureLoader->inputData + offset;\n\t\t\t\t// copy as-is\n\t\t\t\tif (texelBaseTypeCount == 1)\n\t\t\t\t{\n\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t\t*(texelBaseType*)blockData = *blockOutput;\n\t\t\t\t\telse\n\t\t\t\t\t\t*blockOutput = *(texelBaseType*)blockData;\n\t\t\t\t\tblockOutput++;\n\t\t\t\t}\n\t\t\t\telse if (texelBaseTypeCount == 2)\n\t\t\t\t{\n\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t{\n\t\t\t\t\t\t((texelBaseType*)blockData)[0] = blockOutput[0];\n\t\t\t\t\t\t((texelBaseType*)blockData)[1] = blockOutput[1];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tblockOutput[0] = ((texelBaseType*)blockData)[0];\n\t\t\t\t\t\tblockOutput[1] = ((texelBaseType*)blockData)[1];\n\t\t\t\t\t}\n\t\t\t\t\tblockOutput += 2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse if (textureLoader->tileMode == Latte::E_HWTILEMODE::TM_LINEAR_ALIGNED)\n\t{\n\t\t// optimized handler for linear textures\n\t\tuint32 sliceOffset = textureLoader->sliceIndex * textureLoader->height * textureLoader->pitch;\n\t\tfor (sint32 y = 0; y < texelCountY; y++)\n\t\t{\n\t\t\tsint32 pixelOffset = (y*textureLoader->decodedTexelCountX) * (sizeof(texelBaseType)*texelBaseTypeCount);\n\t\t\ttexelBaseType* blockOutput = (texelBaseType*)(outputData + pixelOffset);\n\t\t\ttexelBaseType* blockData = (texelBaseType*)(textureLoader->inputData + (textureLoader->pitch * y + sliceOffset) * (sizeof(texelBaseType)*texelBaseTypeCount));\n\t\t\tfor (sint32 x = 0; x < texelCountX; x++)\n\t\t\t{\n\t\t\t\t// copy as-is\n\t\t\t\tif (texelBaseTypeCount == 1)\n\t\t\t\t{\n\t\t\t\t\tif(isEncodeDirection)\n\t\t\t\t\t\t*(texelBaseType*)blockData = *blockOutput;\n\t\t\t\t\telse\n\t\t\t\t\t\t*blockOutput = *(texelBaseType*)blockData;\n\t\t\t\t\tblockData++;\n\t\t\t\t\tblockOutput++;\n\t\t\t\t}\n\t\t\t\telse if (texelBaseTypeCount == 2)\n\t\t\t\t{\n\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t{\n\t\t\t\t\t\t((texelBaseType*)blockData)[0] = blockOutput[0];\n\t\t\t\t\t\t((texelBaseType*)blockData)[1] = blockOutput[1];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tblockOutput[0] = ((texelBaseType*)blockData)[0];\n\t\t\t\t\t\tblockOutput[1] = ((texelBaseType*)blockData)[1];\n\t\t\t\t\t}\n\t\t\t\t\tblockData += 2;\n\t\t\t\t\tblockOutput += 2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// generic handler\n\t\tfor (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY)\n\t\t{\n\t\t\tsint32 pixelOffset = ((y / textureLoader->stepY)*textureLoader->decodedTexelCountX) * (sizeof(texelBaseType)*texelBaseTypeCount);\n\t\t\ttexelBaseType* blockOutput = (texelBaseType*)(outputData + pixelOffset);\n\t\t\tfor (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX)\n\t\t\t{\n\t\t\t\tuint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y);\n\t\t\t\t// copy as-is\n\t\t\t\tif (texelBaseTypeCount == 1)\n\t\t\t\t{\n\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t\t*(texelBaseType*)blockData = *blockOutput;\n\t\t\t\t\telse\n\t\t\t\t\t\t*blockOutput = *(texelBaseType*)blockData;\n\t\t\t\t\tblockOutput++;\n\t\t\t\t}\n\t\t\t\telse if (texelBaseTypeCount == 2)\n\t\t\t\t{\n\t\t\t\t\tif (isEncodeDirection)\n\t\t\t\t\t{\n\t\t\t\t\t\t((texelBaseType*)blockData)[0] = blockOutput[0];\n\t\t\t\t\t\t((texelBaseType*)blockData)[1] = blockOutput[1];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tblockOutput[0] = ((texelBaseType*)blockData)[0];\n\t\t\t\t\t\tblockOutput[1] = ((texelBaseType*)blockData)[1];\n\t\t\t\t\t}\n\t\t\t\t\tblockOutput += 2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n#include \"Cafe/OS/libs/gx2/GX2_Surface.h\"\n#include <bit>\n\n/*\n\tInfo:\n\n\t- Extra samples for AA are stored in their own micro-tiles\n\n\tMacro-Tiling:\n\n\t- Contains one micro-tile for every combination of bank/channel select\n\t- Since there are 4 bank and 2 pipe bits this means 4*2 = 8 micro tiles (or 8*4 for thick?). But the arrangement varies per tilemode (aspect ratio)\n\t  Allowed layouts: 1x8, 2x4, 4x2\n\n\t- Address format: .... aaaaabbc aaaaaaaa\t\tA = offset, b = bank, c = channel\n\t- Channel/Bank bits are determined by:\n\t\tchannel0 = x[3] ^ y[3]\n\t\tbank0 = x[3] ^ y[5]\n\t\tbank1 = x[4] ^ y[4]\n\n*/\n\nusing namespace Latte;\n\nnamespace LatteAddrLib\n{\n\t\n\tenum class COMPUTE_SURFACE_RESULT\n\t{\n\t\tRESULT_OK = 0,\n\t\tUNKNOWN_FORMAT = 3,\n\t\tBAD_SIZE_FIELD = 6,\n\t};\n\n\tconst uint32 m_configFlags = (1 << 29);\n\n\tuint32 GetSliceComputingFlags()\n\t{\n\t\treturn (m_configFlags >> 26) & 3;\n\t}\n\n\tuint32 GetFillSizeFieldsFlags()\n\t{\n\t\treturn (m_configFlags >> 25) & 1;\n\t}\n\n\tbool GetFlagUseTileIndex()\n\t{\n\t\treturn ((m_configFlags >> 24) & 1) != 0;\n\t}\n\n\tbool GetFlagNoCubeMipSlicesPad()\n\t{\n\t\treturn ((m_configFlags >> 28) & 1) != 0;\n\t}\n\n\tbool GetFlagNo1DTiledMSAA()\n\t{\n\t\treturn ((m_configFlags >> 29) & 1) != 0;\n\t}\n\n\tbool IsPow2(uint32 dim)\n\t{\n\t\treturn (dim & (dim - 1)) == 0;\n\t}\n\n\tuint32 PowTwoAlign(uint32 x, uint32 align)\n\t{\n\t\treturn (x + align - 1) & ~(align - 1);\n\t}\n\n\tuint32 NextPow2(uint32 dim)\n\t{\n\t\treturn std::bit_ceil<uint32>(dim);\n\t}\n\n\tuint32 GetBitsPerPixel(E_HWSURFFMT format, uint32* pElemMode, uint32* pExpandX, uint32* pExpandY)\n\t{\n\t\tuint32 bpp;\n\t\tuint32 elemMode = 3;\n\t\tswitch (format)\n\t\t{\n\t\tcase E_HWSURFFMT::INVALID_FORMAT:\n\t\t\tbpp = 0;\n\t\t\t*pExpandX = 1;\n\t\t\t*pExpandY = 1;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_8:\n\t\tcase E_HWSURFFMT::HWFMT_4_4:\n\t\tcase E_HWSURFFMT::HWFMT_3_3_2:\n\t\t\tbpp = 8;\n\t\t\t*pExpandX = 1;\n\t\t\t*pExpandY = 1;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_16:\n\t\tcase E_HWSURFFMT::HWFMT_16_FLOAT:\n\t\tcase E_HWSURFFMT::HWFMT_8_8:\n\t\tcase E_HWSURFFMT::HWFMT_5_6_5:\n\t\tcase E_HWSURFFMT::HWFMT_6_5_5:\n\t\tcase E_HWSURFFMT::HWFMT_1_5_5_5:\n\t\tcase E_HWSURFFMT::HWFMT_4_4_4_4:\n\t\t\tbpp = 16;\n\t\t\t*pExpandX = 1;\n\t\t\t*pExpandY = 1;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_5_5_5_1:\n\t\t\tbpp = 16;\n\t\t\t*pExpandX = 1;\n\t\t\t*pExpandY = 1;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_32:\n\t\tcase E_HWSURFFMT::HWFMT_32_FLOAT:\n\t\tcase E_HWSURFFMT::HWFMT_16_16:\n\t\tcase E_HWSURFFMT::HWFMT_16_16_FLOAT:\n\t\tcase E_HWSURFFMT::HWFMT_24_8:\n\t\tcase E_HWSURFFMT::HWFMT_24_8_FLOAT:\n\t\tcase E_HWSURFFMT::HWFMT_10_11_11:\n\t\tcase E_HWSURFFMT::HWFMT_11_11_10:\n\t\tcase E_HWSURFFMT::HWFMT_2_10_10_10:\n\t\tcase E_HWSURFFMT::HWFMT_8_8_8_8:\n\t\tcase E_HWSURFFMT::HWFMT_8_24:\n\t\tcase E_HWSURFFMT::HWFMT_8_24_FLOAT:\n\t\tcase E_HWSURFFMT::HWFMT_10_11_11_FLOAT:\n\t\tcase E_HWSURFFMT::HWFMT_11_11_10_FLOAT:\n\t\tcase E_HWSURFFMT::HWFMT_10_10_10_2:\n\t\t\tbpp = 32;\n\t\t\t*pExpandX = 1;\n\t\t\t*pExpandY = 1;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_32_32:\n\t\tcase E_HWSURFFMT::HWFMT_32_32_FLOAT:\n\t\tcase E_HWSURFFMT::HWFMT_16_16_16_16:\n\t\tcase E_HWSURFFMT::HWFMT_16_16_16_16_FLOAT:\n\t\tcase E_HWSURFFMT::HWFMT_X24_8_32_FLOAT:\n\t\t\tbpp = 64;\n\t\t\t*pExpandX = 1;\n\t\t\t*pExpandY = 1;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_32_32_32_32:\n\t\tcase E_HWSURFFMT::HWFMT_32_32_32_32_FLOAT:\n\t\t\tbpp = 128;\n\t\t\t*pExpandX = 1;\n\t\t\t*pExpandY = 1;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_BC1:\n\t\t\telemMode = 9;\n\t\t\tbpp = 64;\n\t\t\t*pExpandX = 4;\n\t\t\t*pExpandY = 4;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_BC2:\n\t\t\telemMode = 10;\n\t\t\tbpp = 128;\n\t\t\t*pExpandX = 4;\n\t\t\t*pExpandY = 4;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_BC3:\n\t\t\telemMode = 11;\n\t\t\tbpp = 128;\n\t\t\t*pExpandX = 4;\n\t\t\t*pExpandY = 4;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_BC4:\n\t\t\telemMode = 12;\n\t\t\tbpp = 64;\n\t\t\t*pExpandX = 4;\n\t\t\t*pExpandY = 4;\n\t\t\tbreak;\n\t\tcase E_HWSURFFMT::HWFMT_BC5:\n\t\tcase E_HWSURFFMT::U_HWFMT_BC6:\n\t\tcase E_HWSURFFMT::U_HWFMT_BC7:\n\t\t\telemMode = 13;\n\t\t\tbpp = 128;\n\t\t\t*pExpandX = 4;\n\t\t\t*pExpandY = 4;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemu_assert_suspicious();\n\t\t\tbpp = 0;\n\t\t\t*pExpandX = 1;\n\t\t\t*pExpandY = 1;\n\t\t\tbreak;\n\t\t}\n\t\t*pElemMode = elemMode;\n\t\treturn bpp;\n\t}\n\n\tvoid AdjustSurfaceInfo(uint32 elemMode, uint32 expandX, uint32 expandY, uint32* pBpp, uint32* pWidth, uint32* pHeight)\n\t{\n\t\tbool isBCFormat = false;\n\t\tif (pBpp)\n\t\t{\n\t\t\tuint32 bpp = *pBpp;\n\t\t\tuint32 packedBits;\n\t\t\tswitch (elemMode)\n\t\t\t{\n\t\t\tcase 4:\n\t\t\t\tpackedBits = bpp / expandX / expandY;\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\tcase 6:\n\t\t\t\tpackedBits = expandY * expandX * bpp;\n\t\t\t\tbreak;\n\t\t\tcase 7:\n\t\t\tcase 8:\n\t\t\t\tpackedBits = *pBpp;\n\t\t\t\tbreak;\n\t\t\tcase 9:\n\t\t\tcase 12:\n\t\t\t\tpackedBits = 64;\n\t\t\t\tisBCFormat = true;\n\t\t\t\tbreak;\n\t\t\tcase 10:\n\t\t\tcase 11:\n\t\t\tcase 13:\n\t\t\t\tpackedBits = 128;\n\t\t\t\tisBCFormat = true;\n\t\t\t\tbreak;\n\t\t\tcase 0:\n\t\t\tcase 1:\n\t\t\tcase 2:\n\t\t\tcase 3:\n\t\t\t\tpackedBits = *pBpp;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tpackedBits = *pBpp;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t*pBpp = packedBits;\n\t\t}\n\t\tif (pWidth)\n\t\t{\n\t\t\tif (pHeight)\n\t\t\t{\n\t\t\t\tuint32 width = *pWidth;\n\t\t\t\tuint32 height = *pHeight;\n\t\t\t\tif (expandX > 1 || expandY > 1)\n\t\t\t\t{\n\t\t\t\t\tuint32 widthAligned;\n\t\t\t\t\tuint32 heightAligned;\n\t\t\t\t\tif (elemMode == 4)\n\t\t\t\t\t{\n\t\t\t\t\t\twidthAligned = expandX * width;\n\t\t\t\t\t\theightAligned = expandY * height;\n\t\t\t\t\t}\n\t\t\t\t\telse if (isBCFormat)\n\t\t\t\t\t{\n\t\t\t\t\t\twidthAligned = width / expandX;\n\t\t\t\t\t\theightAligned = height / expandY;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\twidthAligned = (width + expandX - 1) / expandX;\n\t\t\t\t\t\theightAligned = (height + expandY - 1) / expandY;\n\t\t\t\t\t}\n\t\t\t\t\t*pWidth = std::max<uint32>(widthAligned, 1);\n\t\t\t\t\t*pHeight = std::max<uint32>(heightAligned, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid ComputeMipLevelDimensions(uint32* pWidth, uint32* pHeight, uint32* pNumSlices, AddrSurfaceFlags flags, Latte::E_HWSURFFMT format, uint32 mipLevel)\n\t{\n\t\tbool isBCn = (uint32)format >= (uint32)Latte::E_HWSURFFMT::HWFMT_BC1 && (uint32)format <= (uint32)Latte::E_HWSURFFMT::U_HWFMT_BC7;\n\t\tif (isBCn && (mipLevel == 0 || flags.inputIsBase))\n\t\t{\n\t\t\t*pWidth = PowTwoAlign(*pWidth, 4);\n\t\t\t*pHeight = PowTwoAlign(*pHeight, 4);\n\t\t}\n\t\tif (isBCn)\n\t\t{\n\t\t\tif (mipLevel != 0)\n\t\t\t{\n\t\t\t\tuint32 width = *pWidth;\n\t\t\t\tuint32 height = *pHeight;\n\t\t\t\tuint32 slices = *pNumSlices;\n\t\t\t\tif (flags.inputIsBase)\n\t\t\t\t{\n\t\t\t\t\tif (!flags.dimCube)\n\t\t\t\t\t\tslices >>= mipLevel;\n\t\t\t\t\twidth = std::max<uint32>(width >> mipLevel, 1);\n\t\t\t\t\theight = std::max<uint32>(height >> mipLevel, 1);\n\t\t\t\t\tslices = std::max<uint32>(slices, 1);\n\t\t\t\t}\n\t\t\t\t*pWidth = NextPow2(width);\n\t\t\t\t*pHeight = NextPow2(height);\n\t\t\t\t*pNumSlices = slices;\n\t\t\t}\n\t\t}\n\t\telse if (mipLevel && flags.inputIsBase)\n\t\t{\n\t\t\tuint32 width = *pWidth;\n\t\t\tuint32 height = *pHeight;\n\t\t\tuint32 slices = *pNumSlices;\n\t\t\twidth >>= mipLevel;\n\t\t\theight >>= mipLevel;\n\t\t\tif (!flags.dimCube) // dim 3D\n\t\t\t\tslices >>= mipLevel;\n\t\t\twidth = std::max<uint32>(1, width);\n\t\t\theight = std::max<uint32>(1, height);\n\t\t\tslices = std::max<uint32>(1, slices);\n\t\t\tif (format != E_HWSURFFMT::U_HWFMT_32_32_32 && format != E_HWSURFFMT::U_HWFMT_32_32_32_FLOAT)\n\t\t\t{\n\t\t\t\twidth = NextPow2(width);\n\t\t\t\theight = NextPow2(height);\n\t\t\t\tslices = NextPow2(slices);\n\t\t\t}\n\t\t\t*pWidth = width;\n\t\t\t*pHeight = height;\n\t\t\t*pNumSlices = slices;\n\t\t}\n\t}\n\n\tE_HWTILEMODE ConvertTileModeToNonBankSwappedMode(E_HWTILEMODE tileMode)\n\t{\n\t\tswitch (tileMode)\n\t\t{\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN1:\n\t\t\treturn E_HWTILEMODE::TM_2D_TILED_THIN1;\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN2:\n\t\t\treturn E_HWTILEMODE::TM_2D_TILED_THIN2;\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN4:\n\t\t\treturn E_HWTILEMODE::TM_2D_TILED_THIN4;\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THICK:\n\t\t\treturn E_HWTILEMODE::TM_2D_TILED_THICK;\n\t\tcase E_HWTILEMODE::TM_3B_TILED_THIN1:\n\t\t\treturn E_HWTILEMODE::TM_3D_TILED_THIN1;\n\t\tcase E_HWTILEMODE::TM_3B_TILED_THICK:\n\t\t\treturn E_HWTILEMODE::TM_3D_TILED_THICK;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\treturn tileMode;\n\t}\n\n\tuint32 _CalculateSurfaceTileSlices(E_HWTILEMODE tileMode, uint32 bpp, uint32 numSamples)\n\t{\n\t\tuint32 bytePerSample = ((bpp << 6) + 7) >> 3;\n\t\tuint32 tileSlices = 1;\n\t\tif (TM_GetThickness(tileMode) > 1)\n\t\t\tnumSamples = 4;\n\t\tif (bytePerSample)\n\t\t{\n\t\t\tuint32 samplePerTile = m_splitSize / bytePerSample;\n\t\t\tif (samplePerTile)\n\t\t\t{\n\t\t\t\ttileSlices = numSamples / samplePerTile;\n\t\t\t\tif (!(numSamples / samplePerTile))\n\t\t\t\t\ttileSlices = 1;\n\t\t\t}\n\t\t}\n\t\treturn tileSlices;\n\t}\n\n\tuint32 ComputeSurfaceRotationFromTileMode(E_HWTILEMODE tileMode)\n\t{\n\t\tswitch (tileMode)\n\t\t{\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN2:\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN4:\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THICK:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN2:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN4:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THICK:\n\t\t\treturn m_pipes * ((m_banks >> 1) - 1);\n\t\tcase E_HWTILEMODE::TM_3D_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_3D_TILED_THICK:\n\t\tcase E_HWTILEMODE::TM_3B_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_3B_TILED_THICK:\n\t\t\tif (m_pipes >= 4)\n\t\t\t\treturn (m_pipes >> 1) - 1;\n\t\t\treturn 1;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tE_HWTILEMODE _ComputeSurfaceMipLevelTileMode(E_HWTILEMODE baseTileMode, uint32 bpp, uint32 level, uint32 width, uint32 height, uint32 numSlices, uint32 numSamples, bool isDepth, bool noRecursive)\n\t{\n\t\tE_HWTILEMODE result;\n\t\tE_HWTILEMODE expTileMode = baseTileMode;\n\t\tuint32 tileSlices = _CalculateSurfaceTileSlices(baseTileMode, bpp, numSamples);\n\t\tswitch (baseTileMode)\n\t\t{\n\t\tcase E_HWTILEMODE::TM_1D_TILED_THIN1:\n\t\t\tif (numSamples > 1 && GetFlagNo1DTiledMSAA())\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2D_TILED_THIN1;\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_1D_TILED_THICK:\n\t\t\tif (numSamples > 1 || isDepth)\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_1D_TILED_THIN1;\n\t\t\tif (numSamples == 2 || numSamples == 4)\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2D_TILED_THICK;\n\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN2:\n\t\t\tif (2 * m_pipeInterleaveBytes > m_splitSize)\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2D_TILED_THIN1;\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN4:\n\t\t\tif (4 * m_pipeInterleaveBytes > m_splitSize)\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2D_TILED_THIN2;\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THICK:\n\t\t\tif (numSamples > 1 || tileSlices > 1 || isDepth)\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2D_TILED_THIN1;\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN2:\n\t\t\tif (2 * m_pipeInterleaveBytes > m_splitSize)\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2B_TILED_THIN1;\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN4:\n\t\t\tif (4 * m_pipeInterleaveBytes > m_splitSize)\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2B_TILED_THIN2;\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THICK:\n\t\t\tif (numSamples > 1 || tileSlices > 1 || isDepth)\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2B_TILED_THIN1;\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_3D_TILED_THICK:\n\t\t\tif (numSamples > 1 || tileSlices > 1 || isDepth)\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_3D_TILED_THIN1;\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_3B_TILED_THICK:\n\t\t\tif (numSamples > 1 || tileSlices > 1 || isDepth)\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_3B_TILED_THIN1;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\texpTileMode = baseTileMode;\n\t\t\tbreak;\n\t\t}\n\t\tuint32 rotation = ComputeSurfaceRotationFromTileMode(expTileMode);\n\t\tif (!(rotation % m_pipes))\n\t\t{\n\t\t\tswitch (expTileMode)\n\t\t\t{\n\t\t\tcase E_HWTILEMODE::TM_3D_TILED_THIN1:\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2D_TILED_THIN1;\n\t\t\t\tbreak;\n\t\t\tcase E_HWTILEMODE::TM_3D_TILED_THICK:\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2D_TILED_THICK;\n\t\t\t\tbreak;\n\t\t\tcase E_HWTILEMODE::TM_3B_TILED_THIN1:\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2B_TILED_THIN1;\n\t\t\t\tbreak;\n\t\t\tcase E_HWTILEMODE::TM_3B_TILED_THICK:\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2B_TILED_THICK;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (noRecursive)\n\t\t{\n\t\t\tresult = expTileMode;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (bpp == 96 || bpp == 48 || bpp == 24)\n\t\t\t\tbpp /= 3u;\n\t\t\tuint32 widthAligned = NextPow2(width);\n\t\t\tuint32 heightAligned = NextPow2(height);\n\t\t\tuint32 numSlicesAligned = NextPow2(numSlices);\n\t\t\tif (level)\n\t\t\t{\n\t\t\t\texpTileMode = ConvertTileModeToNonBankSwappedMode(expTileMode);\n\t\t\t\tuint32 thickness = TM_GetThickness(expTileMode);\n\t\t\t\tuint32 microTileBytes = (numSamples * bpp * (thickness << 6) + 7) >> 3;\n\t\t\t\tuint32 widthAlignFactor;\n\t\t\t\tif (microTileBytes >= m_pipeInterleaveBytes)\n\t\t\t\t\twidthAlignFactor = 1;\n\t\t\t\telse\n\t\t\t\t\twidthAlignFactor = m_pipeInterleaveBytes / microTileBytes;\n\t\t\t\tuint32 macroTileWidth = 8 * m_banks;\n\t\t\t\tuint32 macroTileHeight = 8 * m_pipes;\n\t\t\t\tswitch (expTileMode)\n\t\t\t\t{\n\t\t\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN1:\n\t\t\t\tcase E_HWTILEMODE::TM_3D_TILED_THIN1:\n\t\t\t\t\tif (widthAligned < widthAlignFactor * macroTileWidth || heightAligned < macroTileHeight)\n\t\t\t\t\t\texpTileMode = E_HWTILEMODE::TM_1D_TILED_THIN1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN2:\n\t\t\t\t\tmacroTileWidth >>= 1;\n\t\t\t\t\tmacroTileHeight *= 2;\n\t\t\t\t\tif (widthAligned < widthAlignFactor * macroTileWidth || heightAligned < macroTileHeight)\n\t\t\t\t\t\texpTileMode = E_HWTILEMODE::TM_1D_TILED_THIN1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN4:\n\t\t\t\t\tmacroTileWidth >>= 2;\n\t\t\t\t\tmacroTileHeight *= 4;\n\t\t\t\t\tif (widthAligned < widthAlignFactor * macroTileWidth || heightAligned < macroTileHeight)\n\t\t\t\t\t\texpTileMode = E_HWTILEMODE::TM_1D_TILED_THIN1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase E_HWTILEMODE::TM_2D_TILED_THICK:\n\t\t\t\tcase E_HWTILEMODE::TM_3D_TILED_THICK:\n\t\t\t\t\tif (widthAligned < widthAlignFactor * macroTileWidth || heightAligned < macroTileHeight)\n\t\t\t\t\t\texpTileMode = E_HWTILEMODE::TM_1D_TILED_THICK;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (expTileMode == E_HWTILEMODE::TM_1D_TILED_THICK)\n\t\t\t\t{\n\t\t\t\t\tif (numSlicesAligned < 4)\n\t\t\t\t\t\texpTileMode = E_HWTILEMODE::TM_1D_TILED_THIN1;\n\t\t\t\t}\n\t\t\t\telse if (expTileMode == E_HWTILEMODE::TM_2D_TILED_THICK)\n\t\t\t\t{\n\t\t\t\t\tif (numSlicesAligned < 4)\n\t\t\t\t\t\texpTileMode = E_HWTILEMODE::TM_2D_TILED_THIN1;\n\t\t\t\t}\n\t\t\t\telse if (expTileMode == E_HWTILEMODE::TM_3D_TILED_THICK && numSlicesAligned < 4)\n\t\t\t\t{\n\t\t\t\t\texpTileMode = E_HWTILEMODE::TM_3D_TILED_THIN1;\n\t\t\t\t}\n\t\t\t\tresult = _ComputeSurfaceMipLevelTileMode(expTileMode, bpp, level, widthAligned, heightAligned, numSlicesAligned, numSamples, isDepth, true);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult = expTileMode;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tuint32 _ComputeMacroTileAspectRatio(E_HWTILEMODE tileMode)\n\t{\n\t\tswitch (tileMode)\n\t\t{\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_3D_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_3B_TILED_THIN1:\n\t\t\treturn 1;\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN2:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN2:\n\t\t\treturn 2;\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN4:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN4:\n\t\t\treturn 4;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\treturn 1;\n\t}\n\n\tvoid _AdjustPitchAlignment(AddrSurfaceFlags flags, uint32& pitchAlign)\n\t{\n\t\tif (flags.display)\n\t\t\tpitchAlign = PowTwoAlign(pitchAlign, 32);\n\t}\n\n\tvoid _ComputeSurfaceAlignmentsMacroTiled(E_HWTILEMODE tileMode, uint32 bpp, AddrSurfaceFlags flags, uint32 numSamples, uint32* pBaseAlign, uint32* pPitchAlign, uint32* pHeightAlign, uint32* pMacroWidth, uint32* pMacroHeight)\n\t{\n\t\tuint32 aspectRatio = _ComputeMacroTileAspectRatio(tileMode);\n\t\tuint32 thickness = TM_GetThickness(tileMode);\n\t\tif (bpp == 96 || bpp == 48 || bpp == 24)\n\t\t\tbpp /= 3;\n\t\tif (bpp == 3)\n\t\t\tbpp = 1;\n\t\tuint32 macroTileWidth = (8 * m_banks) / aspectRatio;\n\t\tuint32 macroTileHeight = aspectRatio * 8 * m_pipes;\n\t\tuint32 pitchAlign = std::max(macroTileWidth, macroTileWidth * (m_pipeInterleaveBytes / bpp / (8 * thickness) / numSamples));\n\t\t_AdjustPitchAlignment(flags, *pPitchAlign);\n\t\tuint32 heightAlign = macroTileHeight;\n\t\tuint32 macroTileBytes = numSamples * ((bpp * macroTileHeight * macroTileWidth + 7) >> 3);\n\t\tif (m_chipFamily == 1 && numSamples == 1)\n\t\t\tmacroTileBytes *= 2;\n\t\tuint32 baseAlign;\n\t\tif (thickness == 1)\n\t\t\tbaseAlign = std::max(macroTileBytes, (numSamples * heightAlign * bpp * pitchAlign + 7) >> 3);\n\t\telse\n\t\t\tbaseAlign = std::max(m_pipeInterleaveBytes, (4 * heightAlign * bpp * pitchAlign + 7) >> 3);\n\t\tuint32 microTileBytes = (thickness * numSamples * (bpp << 6) + 7) >> 3;\n\t\tuint32 splits;\n\t\tif (microTileBytes < m_splitSize)\n\t\t\tsplits = 1;\n\t\telse\n\t\t\tsplits = microTileBytes / m_splitSize;\n\t\tbaseAlign /= splits;\n\t\t*pBaseAlign = baseAlign;\n\t\t*pPitchAlign = pitchAlign;\n\t\t*pHeightAlign = heightAlign;\n\t\t*pMacroWidth = macroTileWidth;\n\t\t*pMacroHeight = macroTileHeight;\n\t}\n\n\tuint32 ComputeSurfaceBankSwappedWidth(E_HWTILEMODE tileMode, uint32 bpp, uint32 numSamples, uint32 pitch)\n\t{\n\t\tuint32 bankSwapWidth = 0;\n\t\tuint32 slicesPerTile = 1;\n\t\tuint32 bytesPerSample = 8 * bpp;\n\t\tuint32 samplesPerTile = m_splitSize / bytesPerSample;\n\t\tif (m_splitSize / bytesPerSample)\n\t\t{\n\t\t\tslicesPerTile = numSamples / samplesPerTile;\n\t\t\tif (!(numSamples / samplesPerTile))\n\t\t\t\tslicesPerTile = 1;\n\t\t}\n\t\tif (TM_IsThickAndMacroTiled(tileMode) == 1)\n\t\t\tnumSamples = 4;\n\t\tif (TM_IsBankSwapped(tileMode))\n\t\t{\n\t\t\tuint32 bytesPerTileSlice = numSamples * bytesPerSample / slicesPerTile;\n\t\t\tuint32 aspectRatioFactor = _ComputeMacroTileAspectRatio(tileMode);\n\t\t\tuint32 swapTiles = std::max<uint32>((m_swapSize >> 1) / bpp, 1);\n\t\t\tuint32 swapWidth = swapTiles * 8 * m_banks;\n\t\t\tuint32 heightBytes = numSamples * aspectRatioFactor * m_pipes * bpp / slicesPerTile;\n\t\t\tuint32 swapMax = m_pipes * m_banks * m_rowSize / heightBytes;\n\t\t\tuint32 swapMin = m_pipeInterleaveBytes * 8 * m_banks / bytesPerTileSlice;\n\t\t\tuint32 swapVal;\n\t\t\tif (swapMax >= swapWidth)\n\t\t\t\tswapVal = std::max(swapWidth, swapMin);\n\t\t\telse\n\t\t\t\tswapVal = swapMax;\n\t\t\tfor (bankSwapWidth = swapVal; bankSwapWidth >= 2 * pitch; bankSwapWidth >>= 1);\n\t\t}\n\t\treturn bankSwapWidth;\n\t}\n\n\tvoid PadDimensions(E_HWTILEMODE tileMode, uint32 padDims, int isCube, int cubeAsArray, uint32* pPitch, uint32 pitchAlign, uint32* pHeight, uint32 heightAlign, uint32* pSlices, uint32 sliceAlign)\n\t{\n\t\tuint32 thickness = TM_GetThickness(tileMode);\n\t\tif (!padDims)\n\t\t\tpadDims = 3;\n\t\tif (IsPow2(pitchAlign))\n\t\t{\n\t\t\t*pPitch = PowTwoAlign(*pPitch, pitchAlign);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t*pPitch = pitchAlign + *pPitch - 1;\n\t\t\t*pPitch /= pitchAlign;\n\t\t\t*pPitch *= pitchAlign;\n\t\t}\n\t\tif (padDims > 1)\n\t\t\t*pHeight = PowTwoAlign(*pHeight, heightAlign);\n\t\tif (padDims > 2 || thickness > 1)\n\t\t{\n\t\t\tif (isCube && (!GetFlagNoCubeMipSlicesPad() || cubeAsArray))\n\t\t\t\t*pSlices = NextPow2(*pSlices);\n\t\t\tif (thickness > 1)\n\t\t\t\t*pSlices = PowTwoAlign(*pSlices, sliceAlign);\n\t\t}\n\t}\n\n\tvoid _ComputeSurfaceAlignmentsMicroTiled(E_HWTILEMODE tileMode, uint32 bpp, AddrSurfaceFlags flags, uint32 numSamples, uint32& baseAlignOut, uint32& pitchAlignOut, uint32& heightAlignOut)\n\t{\n\t\tif (bpp == 96 || bpp == 48 || bpp == 24)\n\t\t\tbpp /= 3u;\n\t\tuint32 thickness = TM_GetThickness(tileMode);\n\t\tbaseAlignOut = m_pipeInterleaveBytes;\n\t\tpitchAlignOut = std::max(8u, m_pipeInterleaveBytes / bpp / numSamples / thickness);\n\t\theightAlignOut = 8;\n\t\t_AdjustPitchAlignment(flags, pitchAlignOut);\n\t}\n\n\tvoid _ComputeSurfaceAlignmentsLinear(E_HWTILEMODE tileMode, uint32 bpp, AddrSurfaceFlags flags, uint32* pBaseAlign, uint32* pPitchAlign, uint32* pHeightAlign)\n\t{\n\t\tcemu_assert_debug(tileMode == E_HWTILEMODE::TM_LINEAR_GENERAL || tileMode == E_HWTILEMODE::TM_LINEAR_ALIGNED);\n\t\tif (tileMode == E_HWTILEMODE::TM_LINEAR_ALIGNED)\n\t\t{\n\t\t\tuint32 pixelsPerPipeInterleave = 8 * m_pipeInterleaveBytes / bpp;\n\t\t\t*pBaseAlign = m_pipeInterleaveBytes;\n\t\t\t*pPitchAlign = std::max<uint32>(64, pixelsPerPipeInterleave);\n\t\t\t*pHeightAlign = 1;\n\t\t}\n\t\telse if (tileMode == E_HWTILEMODE::TM_LINEAR_GENERAL)\n\t\t{\n\t\t\t*pBaseAlign = 1;\n\t\t\t*pPitchAlign = 1;\n\t\t\t*pHeightAlign = 1;\n\t\t}\n\t\t_AdjustPitchAlignment(flags, *pPitchAlign);\n\t}\n\n\tvoid _ComputeSurfaceInfoLinear(E_HWTILEMODE tileMode, uint32 bpp, uint32 numSamples, uint32 pitch, uint32 height, uint32 numSlices, uint32 mipLevel, uint32 padDims, AddrSurfaceFlags flags, AddrSurfaceInfo_OUT* pOut)\n\t{\n\t\tuint32 heightAlign;\n\t\tuint32 pitchAlign;\n\t\tuint32 baseAlign;\n\t\tuint32 expPitch = pitch;\n\t\tuint32 expHeight = height;\n\t\tuint32 expNumSlices = numSlices;\n\t\t_ComputeSurfaceAlignmentsLinear(tileMode, bpp, flags, &baseAlign, &pitchAlign, &heightAlign);\n\t\tif (flags.linearWA && mipLevel == 0)\n\t\t{\n\t\t\texpPitch /= 3u;\n\t\t\texpPitch = NextPow2(expPitch);\n\t\t}\n\t\tif (mipLevel)\n\t\t{\n\t\t\texpPitch = NextPow2(expPitch);\n\t\t\texpHeight = NextPow2(expHeight);\n\t\t\tif (flags.dimCube)\n\t\t\t{\n\t\t\t\texpNumSlices = numSlices;\n\t\t\t\tif (numSlices <= 1)\n\t\t\t\t\tpadDims = 2;\n\t\t\t\telse\n\t\t\t\t\tpadDims = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\texpNumSlices = NextPow2(numSlices);\n\t\t\t}\n\t\t}\n\t\tuint32 microTileThickness = TM_GetThickness(tileMode);\n\t\tPadDimensions(tileMode, padDims, flags.dimCube, flags.cubeAsArray, &expPitch, pitchAlign, &expHeight, heightAlign, &expNumSlices, microTileThickness);\n\t\tif (flags.linearWA && mipLevel == 0)\n\t\t\texpPitch *= 3;\n\t\tuint32 slices = expNumSlices * numSamples / microTileThickness;\n\t\tpOut->pitch = expPitch;\n\t\tpOut->height = expHeight;\n\t\tpOut->depth = expNumSlices;\n\t\tpOut->surfSize = (((uint64)expHeight * expPitch * slices * bpp * numSamples + 7) / 8);\n\t\tpOut->baseAlign = baseAlign;\n\t\tpOut->pitchAlign = pitchAlign;\n\t\tpOut->heightAlign = heightAlign;\n\t\tpOut->depthAlign = microTileThickness;\n\t}\n\n\tvoid _ComputeSurfaceInfoMicroTiled(E_HWTILEMODE tileMode, uint32 bpp, uint32 numSamples, uint32 pitch, uint32 height, uint32 numSlices, uint32 mipLevel, uint32 padDims, AddrSurfaceFlags flags, AddrSurfaceInfo_OUT* pOut)\n\t{\n\t\tE_HWTILEMODE expTileMode = tileMode;\n\t\tuint32 expPitch = pitch;\n\t\tuint32 expHeight = height;\n\t\tuint32 expNumSlices = numSlices;\n\t\tuint32 microTileThickness = TM_GetThickness(tileMode);\n\t\tif (mipLevel)\n\t\t{\n\t\t\texpPitch = NextPow2(pitch);\n\t\t\texpHeight = NextPow2(height);\n\t\t\tif (flags.dimCube)\n\t\t\t{\n\t\t\t\texpNumSlices = numSlices;\n\t\t\t\tif (numSlices <= 1)\n\t\t\t\t\tpadDims = 2;\n\t\t\t\telse\n\t\t\t\t\tpadDims = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\texpNumSlices = NextPow2(numSlices);\n\t\t\t}\n\t\t\tif (expTileMode == E_HWTILEMODE::TM_1D_TILED_THICK && expNumSlices < 4)\n\t\t\t{\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_1D_TILED_THIN1;\n\t\t\t\tmicroTileThickness = 1;\n\t\t\t}\n\t\t}\n\t\tuint32 heightAlign;\n\t\tuint32 pitchAlign;\n\t\tuint32 baseAlign;\n\t\t_ComputeSurfaceAlignmentsMicroTiled(expTileMode, bpp, flags, numSamples, /* outputs: */ baseAlign, pitchAlign, heightAlign);\n\t\tPadDimensions(expTileMode, padDims, flags.dimCube, flags.cubeAsArray, &expPitch, pitchAlign, &expHeight, heightAlign, &expNumSlices, microTileThickness);\n\t\tpOut->pitch = expPitch;\n\t\tpOut->height = expHeight;\n\t\tpOut->depth = expNumSlices;\n\t\tpOut->surfSize = (((uint64)expHeight * expPitch * expNumSlices * bpp * numSamples + 7) / 8);\n\t\tpOut->hwTileMode = expTileMode;\n\t\tpOut->baseAlign = baseAlign;\n\t\tpOut->pitchAlign = pitchAlign;\n\t\tpOut->heightAlign = heightAlign;\n\t\tpOut->depthAlign = microTileThickness;\n\t}\n\n\tvoid _ComputeSurfaceInfoMacroTiled(E_HWTILEMODE tileMode, E_HWTILEMODE baseTileMode, uint32 bpp, uint32 numSamples, uint32 pitch, uint32 height, uint32 numSlices, uint32 mipLevel, uint32 padDims, AddrSurfaceFlags flags, AddrSurfaceInfo_OUT* pOut)\n\t{\n\t\tuint32 macroWidth, macroHeight;\n\t\tuint32 baseAlign, heightAlign, pitchAlign;\n\n\t\tuint32 expPitch = pitch;\n\t\tuint32 expHeight = height;\n\t\tuint32 expNumSlices = numSlices;\n\t\tE_HWTILEMODE expTileMode = tileMode;\n\t\tuint32 microTileThickness = TM_GetThickness(tileMode);\n\t\tif (mipLevel)\n\t\t{\n\t\t\texpPitch = NextPow2(pitch);\n\t\t\texpHeight = NextPow2(height);\n\t\t\texpNumSlices = NextPow2(numSlices);\n\t\t\tif (flags.dimCube)\n\t\t\t{\n\t\t\t\t// cubemap\n\t\t\t\texpNumSlices = numSlices;\n\t\t\t\tpadDims = numSlices <= 1 ? 2 : 0;\n\t\t\t}\n\t\t\tif (expTileMode == E_HWTILEMODE::TM_2D_TILED_THICK && expNumSlices < 4)\n\t\t\t{\n\t\t\t\texpTileMode = E_HWTILEMODE::TM_2D_TILED_THIN1;\n\t\t\t\tmicroTileThickness = 1;\n\t\t\t}\n\t\t}\n\t\tuint32 pitchAlignFactor = std::max<uint32>((m_pipeInterleaveBytes >> 3) / bpp, 1);\n\t\tif (tileMode != baseTileMode && mipLevel != 0 && TM_IsThickAndMacroTiled(baseTileMode) && !TM_IsThickAndMacroTiled(tileMode))\n\t\t{\n\t\t\t_ComputeSurfaceAlignmentsMacroTiled(baseTileMode, bpp, flags, numSamples, &baseAlign, &pitchAlign, &heightAlign, &macroWidth, &macroHeight);\n\t\t\tif (expPitch < pitchAlign * pitchAlignFactor || expHeight < heightAlign)\n\t\t\t{\n\t\t\t\t_ComputeSurfaceInfoMicroTiled(E_HWTILEMODE::TM_1D_TILED_THIN1, bpp, numSamples, pitch, height, numSlices, mipLevel, padDims, flags, pOut);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t_ComputeSurfaceAlignmentsMacroTiled(tileMode, bpp, flags, numSamples, &baseAlign, &pitchAlign, &heightAlign, &macroWidth, &macroHeight);\n\t\tuint32 bankSwappedWidth = ComputeSurfaceBankSwappedWidth(tileMode, bpp, numSamples, pitch);\n\t\tif (bankSwappedWidth > pitchAlign)\n\t\t\tpitchAlign = bankSwappedWidth;\n\t\tPadDimensions(tileMode, padDims, flags.dimCube, flags.cubeAsArray, &expPitch, pitchAlign, &expHeight, heightAlign, &expNumSlices, microTileThickness);\n\t\tpOut->pitch = expPitch;\n\t\tpOut->height = expHeight;\n\t\tpOut->depth = expNumSlices;\n\t\tpOut->surfSize = (((uint64)expHeight * expPitch * expNumSlices * bpp * numSamples + 7) / 8);\n\t\tpOut->hwTileMode = expTileMode;\n\t\tpOut->baseAlign = baseAlign;\n\t\tpOut->pitchAlign = pitchAlign;\n\t\tpOut->heightAlign = heightAlign;\n\t\tpOut->depthAlign = microTileThickness;\n\t}\n\n\tCOMPUTE_SURFACE_RESULT ComputeSurfaceInfoEx(const AddrSurfaceInfo_IN* pIn, AddrSurfaceInfo_OUT* pOut)\n\t{\n\t\tLatte::E_HWTILEMODE tileMode = pIn->tileMode;\n\t\tLatte::E_HWTILEMODE baseTileMode = tileMode;\n\t\tuint32 bpp = pIn->bpp;\n\t\tuint32 numSamples = std::max<uint32>(pIn->numSamples, 1);\n\t\tuint32 pitch = pIn->width;\n\t\tuint32 height = pIn->height;\n\t\tuint32 numSlices = pIn->numSlices;\n\t\tuint32 mipLevel = pIn->mipLevel;\n\t\tAddrSurfaceFlags flags = pIn->flags;\n\t\tuint32 padDims = 0;\n\t\tif (flags.dimCube && mipLevel == 0)\n\t\t\tpadDims = 2;\n\t\tif (flags.fmask)\n\t\t\ttileMode = ConvertTileModeToNonBankSwappedMode(tileMode);\n\t\telse\n\t\t\ttileMode = _ComputeSurfaceMipLevelTileMode(tileMode, bpp, mipLevel, pitch, height, numSlices, numSamples, flags.depth, false);\n\t\tswitch (tileMode)\n\t\t{\n\t\tcase E_HWTILEMODE::TM_LINEAR_GENERAL:\n\t\tcase E_HWTILEMODE::TM_LINEAR_ALIGNED:\n\t\t\t_ComputeSurfaceInfoLinear(tileMode, bpp, numSamples, pitch, height, numSlices, mipLevel, padDims, flags, pOut);\n\t\t\tpOut->hwTileMode = tileMode;\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_1D_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_1D_TILED_THICK:\n\t\t\t_ComputeSurfaceInfoMicroTiled(tileMode, bpp, numSamples, pitch, height, numSlices, mipLevel, padDims, flags, pOut);\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN2:\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN4:\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THICK:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN2:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN4:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THICK:\n\t\tcase E_HWTILEMODE::TM_3D_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_3D_TILED_THICK:\n\t\tcase E_HWTILEMODE::TM_3B_TILED_THIN1:\n\t\tcase E_HWTILEMODE::TM_3B_TILED_THICK:\n\t\t\t_ComputeSurfaceInfoMacroTiled(tileMode, baseTileMode, bpp, numSamples, pitch, height, numSlices, mipLevel, padDims, flags, pOut);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn COMPUTE_SURFACE_RESULT::UNKNOWN_FORMAT;\n\t\t}\n\t\treturn COMPUTE_SURFACE_RESULT::RESULT_OK;\n\t}\n\n\tvoid RestoreSurfaceInfo(uint32 elemMode, uint32 expandX, uint32 expandY, uint32*pBpp, uint32 *pWidth, uint32*pHeight)\n\t{\n\t\tif (pBpp)\n\t\t{\n\t\t\tuint32 bpp = *pBpp;\n\t\t\tuint32 originalBits;\n\t\t\tswitch (elemMode)\n\t\t\t{\n\t\t\tcase 4:\n\t\t\t\toriginalBits = expandY * expandX * bpp;\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\tcase 6:\n\t\t\t\toriginalBits = bpp / expandX / expandY;\n\t\t\t\tbreak;\n\t\t\tcase 7:\n\t\t\tcase 8:\n\t\t\t\toriginalBits = *pBpp;\n\t\t\t\tbreak;\n\t\t\tcase 9:\n\t\t\tcase 12:\n\t\t\t\toriginalBits = 64;\n\t\t\t\tbreak;\n\t\t\tcase 10:\n\t\t\tcase 11:\n\t\t\tcase 13:\n\t\t\t\toriginalBits = 128;\n\t\t\t\tbreak;\n\t\t\tcase 0:\n\t\t\tcase 1:\n\t\t\tcase 2:\n\t\t\tcase 3:\n\t\t\t\toriginalBits = *pBpp;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\toriginalBits = *pBpp;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t*pBpp = originalBits;\n\t\t}\n\t\tif (pWidth && pHeight)\n\t\t{\n\t\t\tuint32 width = *pWidth;\n\t\t\tuint32 height = *pHeight;\n\t\t\tif (expandX > 1 || expandY > 1)\n\t\t\t{\n\t\t\t\tif (elemMode == 4)\n\t\t\t\t{\n\t\t\t\t\twidth /= expandX;\n\t\t\t\t\theight /= expandY;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\twidth *= expandX;\n\t\t\t\t\theight *= expandY;\n\t\t\t\t}\n\t\t\t}\n\t\t\t*pWidth = std::max<uint32>(width, 1);\n\t\t\t*pHeight = std::max<uint32>(height, 1);\n\t\t}\n\t}\n\n\tCOMPUTE_SURFACE_RESULT ComputeSurfaceInfo(AddrSurfaceInfo_IN* pIn, AddrSurfaceInfo_OUT* pOut)\n\t{\n\t\tif (GetFillSizeFieldsFlags() == 1 && (pIn->size != sizeof(AddrSurfaceInfo_IN) || pOut->size != sizeof(AddrSurfaceInfo_OUT)))\n\t\t\treturn COMPUTE_SURFACE_RESULT::BAD_SIZE_FIELD;\n\t\tcemu_assert_debug(pIn->bpp <= 128);\n\t\tComputeMipLevelDimensions(&pIn->width, &pIn->height, &pIn->numSlices, pIn->flags, pIn->format, pIn->mipLevel);\n\t\tuint32 width = pIn->width;\n\t\tuint32 height = pIn->height;\n\t\tuint32 bpp = pIn->bpp;\n\t\tuint32 elemMode;\n\t\tuint32 expandX = 1;\n\t\tuint32 expandY = 1;\n\t\tcemu_assert_debug(pIn->tileIndex == 0 && pIn->pTileInfo == nullptr);\n\t\tpOut->pixelBits = pIn->bpp;\n\t\tif (pIn->format != E_HWSURFFMT::INVALID_FORMAT)\n\t\t{\n\t\t\tbpp = GetBitsPerPixel(pIn->format, &elemMode, &expandX, &expandY);\n\t\t\tif (pIn->tileMode == E_HWTILEMODE::TM_LINEAR_ALIGNED && elemMode == 4 && expandX == 3)\n\t\t\t\tpIn->flags.linearWA = true;\n\t\t\tAdjustSurfaceInfo(elemMode, expandX, expandY, &bpp, &width, &height);\n\t\t\tpIn->width = width;\n\t\t\tpIn->height = height;\n\t\t\tpIn->bpp = bpp;\n\t\t}\n\t\telse if (pIn->bpp != 0)\n\t\t{\n\t\t\tpIn->width = std::max<uint32>(pIn->width, 1);\n\t\t\tpIn->height = std::max<uint32>(pIn->height, 1);\n\t\t}\n\t\telse\n\t\t\treturn COMPUTE_SURFACE_RESULT::UNKNOWN_FORMAT;\n\t\tCOMPUTE_SURFACE_RESULT r = ComputeSurfaceInfoEx(pIn, pOut);\n\t\tif (r != COMPUTE_SURFACE_RESULT::RESULT_OK)\n\t\t\treturn r;\n\t\tpOut->bpp = pIn->bpp;\n\t\tpOut->pixelPitch = pOut->pitch;\n\t\tpOut->pixelHeight = pOut->height;\n\t\tif (pIn->format != E_HWSURFFMT::INVALID_FORMAT && (!pIn->flags.linearWA || pIn->mipLevel == 0))\n\t\t{\n\t\t\tRestoreSurfaceInfo(elemMode, expandX, expandY, &bpp, &pOut->pixelPitch, &pOut->pixelHeight);\n\t\t}\n\t\tuint32 sliceFlags = GetSliceComputingFlags();\n\t\tif (sliceFlags)\n\t\t{\n\t\t\tif (sliceFlags == 1)\n\t\t\t\tpOut->sliceSize = (pOut->height * pOut->pitch * pOut->bpp * pIn->numSamples + 7) / 8;\n\t\t}\n\t\telse if (pIn->flags.dim3D)\n\t\t{\n\t\t\tpOut->sliceSize = (uint32)(pOut->surfSize);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(pOut->surfSize == 0 && pOut->depth == 0)\n\t\t\t\tpOut->sliceSize = 0; // edge case for (1D)_ARRAY textures with res 0/0/0\n\t\t\telse\n\t\t\t\tpOut->sliceSize = (uint32)(pOut->surfSize / pOut->depth);\n\t\t\tif (pIn->slice == pIn->numSlices - 1 && pIn->numSlices > 1)\n\t\t\t\tpOut->sliceSize += pOut->sliceSize * (pOut->depth - pIn->numSlices);\n\t\t}\n\t\tpOut->pitchTileMax = (pOut->pitch >> 3) - 1;\n\t\tpOut->heightTileMax = (pOut->height >> 3) - 1;\n\t\tpOut->sliceTileMax = ((pOut->height * pOut->pitch >> 6) - 1);\n\t\treturn COMPUTE_SURFACE_RESULT::RESULT_OK;\n\t}\n\n\tvoid GX2CalculateSurfaceInfo(Latte::E_GX2SURFFMT surfaceFormat, uint32 surfaceWidth, uint32 surfaceHeight, uint32 surfaceDepth, E_DIM surfaceDim, E_GX2TILEMODE surfaceTileMode, uint32 surfaceAA, uint32 level, AddrSurfaceInfo_OUT* pSurfOut, bool optimizeForDepthBuffer, bool optimizeForScanBuffer)\n\t{\n\t\tAddrSurfaceInfo_IN surfInfoIn = { 0 };\n\t\tLatte::E_HWSURFFMT hwFormat = Latte::GetHWFormat(surfaceFormat);\n\t\tmemset(pSurfOut, 0, sizeof(AddrSurfaceInfo_OUT));\n\t\tpSurfOut->size = sizeof(AddrSurfaceInfo_OUT);\n\t\tif (surfaceTileMode == E_GX2TILEMODE::TM_LINEAR_SPECIAL)\n\t\t{\n\t\t\tuint32 numSamples = 1 << surfaceAA;\n\t\t\tuint32 blockSize = IsCompressedFormat(hwFormat) ? 4 : 1;\n\t\t\tuint32 width = ((surfaceWidth >> level) + blockSize - 1) & ~(blockSize - 1);\n\t\t\tpSurfOut->bpp = Latte::GetFormatBits(hwFormat);\n\t\t\tpSurfOut->pitch = width / blockSize;\n\t\t\tpSurfOut->pixelBits = pSurfOut->bpp;\n\t\t\tpSurfOut->baseAlign = 1;\n\t\t\tpSurfOut->pitchAlign = 1;\n\t\t\tpSurfOut->heightAlign = 1;\n\t\t\tpSurfOut->depthAlign = 1;\n\t\t\tswitch (surfaceDim)\n\t\t\t{\n\t\t\tcase E_DIM::DIM_1D:\n\t\t\t\tpSurfOut->height = 1;\n\t\t\t\tpSurfOut->depth = 1;\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_2D:\n\t\t\t\tpSurfOut->height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tpSurfOut->depth = 1;\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_3D:\n\t\t\t\tpSurfOut->height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tpSurfOut->depth = std::max<uint32>(surfaceDepth >> level, 1);\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_CUBEMAP:\n\t\t\t\tpSurfOut->height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tpSurfOut->depth = std::max<uint32>(surfaceDepth, 6);\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_1D_ARRAY:\n\t\t\t\tpSurfOut->height = 1;\n\t\t\t\tpSurfOut->depth = surfaceDepth;\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_2D_ARRAY:\n\t\t\t\tpSurfOut->height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tpSurfOut->depth = surfaceDepth;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpSurfOut->height = (~(blockSize - 1) & (pSurfOut->height + blockSize - 1)) / (uint64)blockSize;\n\t\t\tpSurfOut->pixelPitch = ~(blockSize - 1) & ((surfaceWidth >> level) + blockSize - 1);\n\t\t\tpSurfOut->pixelPitch = std::max<uint32>(pSurfOut->pixelPitch, blockSize);\n\t\t\tpSurfOut->pixelHeight = ~(blockSize - 1) & ((surfaceHeight >> level) + blockSize - 1);\n\t\t\tpSurfOut->pixelHeight = std::max<uint32>(pSurfOut->pixelHeight, blockSize);\n\t\t\tpSurfOut->pitch = std::max<uint32>(pSurfOut->pitch, 1);\n\t\t\tpSurfOut->height = std::max<uint32>(pSurfOut->height, 1);\n\t\t\tpSurfOut->surfSize = pSurfOut->bpp * numSamples * pSurfOut->depth * pSurfOut->height * pSurfOut->pitch >> 3;\n\t\t\tif (surfaceDim == E_DIM::DIM_3D)\n\t\t\t\tpSurfOut->sliceSize = (uint32)pSurfOut->surfSize;\n\t\t\telse\n\t\t\t{\n\t\t\t\tif(pSurfOut->surfSize == 0 && pSurfOut->depth == 0)\n\t\t\t\t\tpSurfOut->sliceSize = 0;\n\t\t\t\telse\n\t\t\t\t\tpSurfOut->sliceSize = (uint32)(pSurfOut->surfSize / pSurfOut->depth);\n\t\t\t}\n\t\t\tpSurfOut->pitchTileMax = (pSurfOut->pitch >> 3) - 1;\n\t\t\tpSurfOut->heightTileMax = (pSurfOut->height >> 3) - 1;\n\t\t\tpSurfOut->sliceTileMax = (pSurfOut->height * pSurfOut->pitch >> 6) - 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmemset(&surfInfoIn, 0, sizeof(AddrSurfaceInfo_IN));\n\t\t\tsurfInfoIn.size = sizeof(AddrSurfaceInfo_IN);\n\t\t\tif (!IsValidHWTileMode((E_HWTILEMODE)surfaceTileMode))\n\t\t\t{\n\t\t\t\t// cemuLog_log(LogType::Force, \"Unexpected TileMode {} in AddrLib\", (uint32)surfaceTileMode);\n\t\t\t\tsurfaceTileMode = (E_GX2TILEMODE)((uint32)surfaceTileMode & 0xF);\n\t\t\t}\n\t\t\tsurfInfoIn.tileMode = MakeHWTileMode(surfaceTileMode);\n\t\t\tsurfInfoIn.format = hwFormat;\n\t\t\tsurfInfoIn.bpp = Latte::GetFormatBits(hwFormat);\n\t\t\tsurfInfoIn.numSamples = 1 << surfaceAA;\n\t\t\tsurfInfoIn.numFrags = surfInfoIn.numSamples;\n\t\t\tsurfInfoIn.width = std::max<uint32>(surfaceWidth >> level, 1);\n\t\t\tswitch (surfaceDim)\n\t\t\t{\n\t\t\tcase E_DIM::DIM_1D:\n\t\t\t\tsurfInfoIn.height = 1;\n\t\t\t\tsurfInfoIn.numSlices = 1;\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_2D:\n\t\t\t\tsurfInfoIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tsurfInfoIn.numSlices = 1;\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_3D:\n\t\t\t\tsurfInfoIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tsurfInfoIn.numSlices = std::max<uint32>(surfaceDepth >> level, 1);\n\t\t\t\tsurfInfoIn.flags.dim3D = true;\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_CUBEMAP:\n\t\t\t\tsurfInfoIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tsurfInfoIn.numSlices = std::max<uint32>(surfaceDepth, 6);\n\t\t\t\tsurfInfoIn.flags.dimCube = true;\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_1D_ARRAY:\n\t\t\t\tsurfInfoIn.height = 1;\n\t\t\t\tsurfInfoIn.numSlices = surfaceDepth;\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_2D_ARRAY:\n\t\t\t\tsurfInfoIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tsurfInfoIn.numSlices = surfaceDepth;\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_2D_MSAA:\n\t\t\t\tsurfInfoIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tsurfInfoIn.numSlices = 1;\n\t\t\t\tbreak;\n\t\t\tcase E_DIM::DIM_2D_ARRAY_MSAA:\n\t\t\t\tsurfInfoIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tsurfInfoIn.numSlices = surfaceDepth;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tsurfInfoIn.slice = 0;\n\t\t\tsurfInfoIn.mipLevel = level;\n\t\t\tsurfInfoIn.flags.inputIsBase = (level == 0);\n\t\t\tsurfInfoIn.flags.depth = optimizeForDepthBuffer;\n\t\t\tsurfInfoIn.flags.display = optimizeForScanBuffer;\n\t\t\tComputeSurfaceInfo(&surfInfoIn, pSurfOut);\n\t\t}\n\t}\n\n\tuint32 CalculateMipOffset(Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, E_DIM dim, E_HWTILEMODE tileMode, uint32 swizzle, uint32 surfaceAA, sint32 mipIndex)\n\t{\n\t\tcemu_assert_debug(IsValidHWTileMode(tileMode));\n\t\tAddrSurfaceInfo_OUT surfaceInfo;\n\t\tuint32 currentMipOffset = 0;\n\t\tE_HWTILEMODE lastTileMode = tileMode;\n\t\tuint32 prevSize = 0;\n\t\tfor (sint32 level = 1; level <= mipIndex; level++)\n\t\t{\n\t\t\tGX2CalculateSurfaceInfo(format, width, height, depth, dim, MakeGX2TileMode(tileMode), surfaceAA, level, &surfaceInfo);\n\t\t\tif (level)\n\t\t\t{\n\t\t\t\tuint32 pad = 0;\n\t\t\t\tif (TM_IsMacroTiled(lastTileMode) && !TM_IsMacroTiled(surfaceInfo.hwTileMode))\n\t\t\t\t{\n\t\t\t\t\tif (level > 1)\n\t\t\t\t\t\tpad = swizzle & 0xFFFF;\n\t\t\t\t}\n\t\t\t\tpad += (surfaceInfo.baseAlign - (currentMipOffset % surfaceInfo.baseAlign)) % surfaceInfo.baseAlign;\n\t\t\t\tcurrentMipOffset = currentMipOffset + pad + prevSize;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcurrentMipOffset = prevSize;\n\t\t\t}\n\t\t\tlastTileMode = surfaceInfo.hwTileMode;\n\t\t\tprevSize = (uint32)surfaceInfo.surfSize;\n\t\t}\n\t\treturn currentMipOffset;\n\t}\n\n\t// Calculate aligned address and size of a given slice and mip level\n\t// For thick-tiled surfaces this returns the area of the whole thick tile (4 slices per thick tile) and the relative slice index within the tile is returned in subSliceIndex\n\tvoid CalculateMipAndSliceAddr(uint32 physAddr, uint32 physMipAddr, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, Latte::E_DIM dim, Latte::E_HWTILEMODE tileMode, uint32 swizzle, uint32 surfaceAA, sint32 mipIndex, sint32 sliceIndex, uint32* outputSliceOffset, uint32* outputSliceSize, sint32* subSliceIndex)\n\t{\n\t\tcemu_assert_debug((uint32)tileMode < 16); // only hardware tilemodes allowed\n\n\t\tAddrSurfaceInfo_OUT surfaceInfo;\n\t\tuint32 currentMipOffset = 0;\n\t\tLatte::E_HWTILEMODE lastTileMode = tileMode;\n\t\tuint32 prevSize = 0;\n\t\tfor (sint32 level = 1; level <= mipIndex; level++)\n\t\t{\n\t\t\tGX2CalculateSurfaceInfo(format, width, height, depth, dim, MakeGX2TileMode(tileMode), surfaceAA, level, &surfaceInfo);\n\t\t\t// extract swizzle from mip-pointer if macro tiled\n\t\t\tif (level == 1 && TM_IsMacroTiled(surfaceInfo.hwTileMode))\n\t\t\t{\n\t\t\t\tswizzle = physMipAddr & 0x700;\n\t\t\t\tphysMipAddr &= ~0x700;\n\t\t\t}\n\t\t\tcemu_assert_debug(IsValidHWTileMode(surfaceInfo.hwTileMode));\n\t\t\tif (level)\n\t\t\t{\n\t\t\t\tuint32 pad = 0;\n\t\t\t\tif (TM_IsMacroTiled(lastTileMode) && !TM_IsMacroTiled(surfaceInfo.hwTileMode))\n\t\t\t\t{\n\t\t\t\t\tif (level > 1)\n\t\t\t\t\t\tpad = swizzle & 0xFFFF;\n\t\t\t\t}\n\t\t\t\tpad += (surfaceInfo.baseAlign - (currentMipOffset % surfaceInfo.baseAlign)) % surfaceInfo.baseAlign;\n\t\t\t\tcurrentMipOffset = currentMipOffset + pad + prevSize;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcurrentMipOffset = prevSize;\n\t\t\t}\n\t\t\tlastTileMode = surfaceInfo.hwTileMode;\n\t\t\tprevSize = (uint32)surfaceInfo.surfSize;\n\t\t}\n\t\t// calculate slice offset\n\t\tif( mipIndex == 0 ) // make sure surfaceInfo is initialized\n\t\t\tGX2CalculateSurfaceInfo(format, width, height, depth, dim, MakeGX2TileMode(tileMode), surfaceAA, 0, &surfaceInfo);\n\t\tuint32 sliceOffset = 0;\n\t\tuint32 sliceSize = 0;\n\n\t\t// surfaceInfo.sliceSize isn't always correct (especially when depth is misaligned with 4 for THICK tile modes?) so we calculate it manually\n\t\t// this formula only works because both pitch and height are aligned to micro/macro blocks by GX2CalculateSurfaceInfo, normally we would have to use the tile dimensions to calculate the size\n\t\tuint32 correctedSliceSize = surfaceInfo.pitch*surfaceInfo.height*surfaceInfo.bpp / 8;\n\t\n\t\tif (TM_IsThick(surfaceInfo.hwTileMode))\n\t\t{\n\t\t\t// 4 slices are interleaved\n\t\t\tsliceOffset = (sliceIndex&~3) * correctedSliceSize;\n\t\t\tsliceSize = correctedSliceSize * 4;\n\t\t\t*subSliceIndex = sliceIndex & 3;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsliceOffset = sliceIndex * correctedSliceSize;\n\t\t\tsliceSize = correctedSliceSize;\n\t\t\t*subSliceIndex = 0;\n\t\t}\n\t\tif (mipIndex)\n\t\t{\n\t\t\tsliceOffset += physMipAddr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsliceOffset += physAddr;\n\t\t}\n\t\t*outputSliceOffset = currentMipOffset + sliceOffset;\n\t\t*outputSliceSize = sliceSize;\n\t}\n\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n\nnamespace LatteAddrLib\n{\n\tstatic const uint32 m_banks = 4;\n\tstatic const uint32 m_banksBitcount = 2;\n\tstatic const uint32 m_pipes = 2;\n\tstatic const uint32 m_pipesBitcount = 1;\n\tstatic const uint32 m_pipeInterleaveBytes = 256;\n\tstatic const uint32 m_pipeInterleaveBytesBitcount = 8;\n\tstatic const uint32 m_rowSize = 2048;\n\tstatic const uint32 m_swapSize = 256;\n\tstatic const uint32 m_splitSize = 2048;\n\tstatic const uint32 m_chipFamily = 2;\n\n\tunion AddrSurfaceFlags\n\t{\n\t\tuint32 rawValue;\n\t\tstruct  \n\t\t{\n\t\t\tbool color : 1;\n\t\t\tbool depth : 1;\n\t\t\tbool stencil : 1;\n\t\t\tbool uknFlag4 : 1;\n\t\t\tbool dimCube : 1;\n\t\t\tbool dim3D : 1;\n\t\t\tbool fmask : 1;\n\t\t\tbool cubeAsArray : 1;\n\t\t\tbool uknFlag8 : 1;\n\t\t\tbool linearWA : 1;\n\t\t\tbool uknFlag10 : 1;\n\t\t\tbool uknFlag11 : 1;\n\t\t\tbool inputIsBase : 1;\n\t\t\tbool display : 1;\n\t\t};\n\t};\n\n\tstruct AddrTileInfo\n\t{\n\t\tuint32 banks;\n\t\tuint32 bankWidth;\n\t\tuint32 bankHeight;\n\t\tuint32 macroAspectRatio;\n\t\tuint32 tileSplitBytes;\n\t\tuint32 pipeConfig;\n\t};\n\n\tstruct AddrSurfaceInfo_IN\n\t{\n\t\tuint32 size;\n\t\tLatte::E_HWTILEMODE tileMode;\n\t\tLatte::E_HWSURFFMT format;\n\t\tuint32 bpp;\n\t\tuint32 numSamples;\n\t\tuint32 width;\n\t\tuint32 height;\n\t\tuint32 numSlices;\n\t\tuint32 slice;\n\t\tuint32 mipLevel;\n\t\tAddrSurfaceFlags flags;\n\t\tuint32 numFrags;\n\t\tAddrTileInfo* pTileInfo;\n\t\tsint32 tileIndex;\n\t};\n\n\tstruct AddrSurfaceInfo_OUT\n\t{\n\t\tuint32 size;\n\t\tuint32 pitch;\n\t\tuint32 height;\n\t\tuint32 depth;\n\t\tuint64 surfSize;\n\t\tLatte::E_HWTILEMODE hwTileMode;\n\t\tuint32 baseAlign;\n\t\tuint32 pitchAlign;\n\t\tuint32 heightAlign;\n\t\tuint32 depthAlign;\n\t\tuint32 bpp;\n\t\tuint32 pixelPitch;\n\t\tuint32 pixelHeight;\n\t\tuint32 pixelBits;\n\t\tuint32 sliceSize;\n\t\tuint32 pitchTileMax;\n\t\tuint32 heightTileMax;\n\t\tuint32 sliceTileMax;\n\t\tAddrTileInfo* pTileInfo;\n\t\tuint32 tileType;\n\t\tsint32 tileIndex;\n\t};\n\n\tinline bool IsHWTileMode(Latte::E_GX2TILEMODE tileMode)\n\t{\n\t\treturn (uint32)tileMode < 16;\n\t}\n\n\tinline bool IsValidHWTileMode(Latte::E_HWTILEMODE tileMode)\n\t{\n\t\treturn (uint32)tileMode < 16;\n\t}\n\n\tinline bool TM_IsThick(Latte::E_HWTILEMODE tileMode)\n\t{\n\t\treturn\n\t\t\ttileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THICK ||\n\t\t\ttileMode == Latte::E_HWTILEMODE::TM_2D_TILED_THICK ||\n\t\t\ttileMode == Latte::E_HWTILEMODE::TM_2B_TILED_THICK ||\n\t\t\ttileMode == Latte::E_HWTILEMODE::TM_3D_TILED_THICK ||\n\t\t\ttileMode == Latte::E_HWTILEMODE::TM_3B_TILED_THICK;\n\t}\n\n\tinline uint32 TM_GetThickness(Latte::E_HWTILEMODE tileMode)\n\t{\n\t\treturn TM_IsThick(tileMode) ? 4 : 1;\n\t}\n\n\tinline bool TM_IsThickAndMacroTiled(Latte::E_HWTILEMODE tileMode)\n\t{\n\t\treturn\n\t\t\ttileMode == Latte::E_HWTILEMODE::TM_2D_TILED_THICK ||\n\t\t\ttileMode == Latte::E_HWTILEMODE::TM_2B_TILED_THICK ||\n\t\t\ttileMode == Latte::E_HWTILEMODE::TM_3D_TILED_THICK ||\n\t\t\ttileMode == Latte::E_HWTILEMODE::TM_3B_TILED_THICK;\n\t}\n\n\tuint32 ComputeSurfaceRotationFromTileMode(Latte::E_HWTILEMODE tileMode);\n\tuint32 ComputeSurfaceBankSwappedWidth(Latte::E_HWTILEMODE tileMode, uint32 bpp, uint32 numSamples, uint32 pitch);\n\t\n\tvoid GX2CalculateSurfaceInfo(Latte::E_GX2SURFFMT surfaceFormat, uint32 surfaceWidth, uint32 surfaceHeight, uint32 surfaceDepth, Latte::E_DIM surfaceDim, Latte::E_GX2TILEMODE surfaceTileMode, uint32 surfaceAA, uint32 level, AddrSurfaceInfo_OUT* pSurfOut, bool optimizeForDepthBuffer = false, bool optimizeForScanBuffer = false);\n\tuint32 CalculateMipOffset(Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, Latte::E_DIM dim, Latte::E_HWTILEMODE tileMode, uint32 swizzle, uint32 surfaceAA, sint32 mipIndex);\n\tvoid CalculateMipAndSliceAddr(uint32 physAddr, uint32 physMipAddr, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, Latte::E_DIM dim, Latte::E_HWTILEMODE tileMode, uint32 swizzle, uint32 surfaceAA, sint32 mipIndex, sint32 sliceIndex, uint32* outputSliceOffset, uint32* outputSliceSize, sint32* subSliceIndex);\n\n\t/* Pixel access */\n\n\tuint32 ComputeSurfaceAddrFromCoordLinear(uint32 x, uint32 y, uint32 slice, uint32 sample, uint32 bpp, uint32 pitch, uint32 height, uint32 numSlices);\n\tuint32 ComputeSurfaceAddrFromCoordMicroTiled(uint32 x, uint32 y, uint32 slice, uint32 bpp, uint32 pitch, uint32 height, Latte::E_HWTILEMODE tileMode, bool isDepth);\n\tuint32 ComputeSurfaceAddrFromCoordMacroTiled(uint32 x, uint32 y, uint32 slice, uint32 sample, uint32 bpp, uint32 pitch, uint32 height, uint32 numSamples, Latte::E_HWTILEMODE tileMode, bool isDepth, uint32 pipeSwizzle, uint32 bankSwizzle);\n\n\tuint32 _ComputePixelIndexWithinMicroTile(uint32 x, uint32 y, uint32 z, uint32 bpp, Latte::E_HWTILEMODE tileMode, uint32 microTileType);\n\n\t// addr lib (optimized access)\n\tstruct CachedSurfaceAddrInfo\n\t{\n\t\tuint32 slice;\n\t\tuint32 sample;\n\t\tuint32 bpp;\n\t\tuint32 pitch;\n\t\tuint32 height;\n\t\tuint32 depth;\n\t\tuint32 numSamples; // for AA\n\t\tLatte::E_HWTILEMODE tileMode;\n\t\tint isDepth;\n\t\tuint32 pipeSwizzle;\n\t\tuint32 bankSwizzle;\n\t\tuint32 pixelOffsetMul;\n\t\tuint32 bytesPerPixel;\n\t\t// calculated data\n\t\tuint32 microTileThickness;\n\t\tuint32 microTileBits;\n\t\tuint32 microTileBytes;\n\t\tuint32 microTileType;\n\t\tuint32 rotation; // bank rotation\n\t\tuint32 macroTilePitch;\n\t\tuint32 macroTileHeight;\n\t\tuint32 macroTilePitchBits;\n\t\tuint32 macroTileHeightBits;\n\t\tuint32 macroTilesPerRow;\n\t\tuint32 macroTileBytes;\n\t\tuint32 bankSwapWidth;\n\t\tuint32 sliceBytes;\n\t\tuint32 sliceIn;\n\t\t// const\n\t\tuint32 c0;\n\t\t// micro tile pixel index table\n\t\tuint16 microTilePixelIndexTable[8 * 8 * 8];\n\t};\n\n\tvoid SetupCachedSurfaceAddrInfo(CachedSurfaceAddrInfo* info, uint32 slice, uint32 sample, uint32 bpp, uint32 pitch, uint32 height, uint32 depth, uint32 numSamples, Latte::E_HWTILEMODE tileMode, int isDepth, uint32 pipeSwizzle, uint32 bankSwizzle);\n\tuint32 ComputeSurfaceAddrFromCoordMacroTiledCached(uint32 x, uint32 y, CachedSurfaceAddrInfo* info);\n\tuint32 ComputeSurfaceAddrFromCoordMacroTiledCached_tm04_sample1(uint32 x, uint32 y, CachedSurfaceAddrInfo* info);\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LatteAddrLib/LatteAddrLib_Coord.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n#include \"Cafe/OS/libs/gx2/GX2_Surface.h\"\n\nusing namespace Latte;\n\nnamespace LatteAddrLib\n{\n\n#if BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_BSD\n\tunsigned char _BitScanReverse(uint32* _Index, uint32 _Mask)\n\t{\n\t\tif (!_Mask)\n\t\t\treturn 0;\n\t\t*_Index = 31 - __builtin_clzl(_Mask);\n\t\treturn 1;\n\t}\n#endif\n\n\tstatic const uint32 bankSwapOrder[] = { 0, 1, 3, 2 };\n\n\tuint32 _GetMicroTileType(bool isDepth)\n\t{\n\t\treturn isDepth ? 1 : 0;\n\t}\n\n\tuint32 _ComputePixelIndexWithinMicroTile(uint32 x, uint32 y, uint32 z, uint32 bpp, E_HWTILEMODE tileMode, uint32 microTileType)\n\t{\n\t\tcemu_assert_debug(microTileType == 0 || microTileType == 1);\n\t\tuint32 pixelBit0, pixelBit1, pixelBit2, pixelBit3, pixelBit4, pixelBit5, pixelBit6, pixelBit7, pixelBit8;\n\t\tpixelBit6 = 0;\n\t\tpixelBit7 = 0;\n\t\tpixelBit8 = 0;\n\t\tuint32 thickness = LatteAddrLib::TM_GetThickness(tileMode);\n\t\tif (microTileType)\n\t\t{\n\t\t\tpixelBit0 = x & 1;\n\t\t\tpixelBit1 = y & 1;\n\t\t\tpixelBit2 = (x & 2) >> 1;\n\t\t\tpixelBit3 = (y & 2) >> 1;\n\t\t\tpixelBit4 = (x & 4) >> 2;\n\t\t\tpixelBit5 = (y & 4) >> 2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tswitch (bpp)\n\t\t\t{\n\t\t\tcase 8:\n\t\t\t\tpixelBit0 = x & 1;\n\t\t\t\tpixelBit1 = (x & 2) >> 1;\n\t\t\t\tpixelBit2 = (x & 4) >> 2;\n\t\t\t\tpixelBit3 = (y & 2) >> 1;\n\t\t\t\tpixelBit4 = y & 1;\n\t\t\t\tpixelBit5 = (y & 4) >> 2;\n\t\t\t\tbreak;\n\t\t\tcase 0x10:\n\t\t\t\tpixelBit0 = x & 1;\n\t\t\t\tpixelBit1 = (x & 2) >> 1;\n\t\t\t\tpixelBit2 = (x & 4) >> 2;\n\t\t\t\tpixelBit3 = y & 1;\n\t\t\t\tpixelBit4 = (y & 2) >> 1;\n\t\t\t\tpixelBit5 = (y & 4) >> 2;\n\t\t\t\tbreak;\n\t\t\tcase 0x20:\n\t\t\tcase 0x60:\n\t\t\t\tpixelBit0 = x & 1;\n\t\t\t\tpixelBit1 = (x & 2) >> 1;\n\t\t\t\tpixelBit2 = y & 1;\n\t\t\t\tpixelBit3 = (x & 4) >> 2;\n\t\t\t\tpixelBit4 = (y & 2) >> 1;\n\t\t\t\tpixelBit5 = (y & 4) >> 2;\n\t\t\t\tbreak;\n\t\t\tcase 0x40:\n\t\t\t\tpixelBit0 = x & 1;\n\t\t\t\tpixelBit1 = y & 1;\n\t\t\t\tpixelBit2 = (x & 2) >> 1;\n\t\t\t\tpixelBit3 = (x & 4) >> 2;\n\t\t\t\tpixelBit4 = (y & 2) >> 1;\n\t\t\t\tpixelBit5 = (y & 4) >> 2;\n\t\t\t\tbreak;\n\t\t\tcase 0x80:\n\t\t\t\tpixelBit0 = y & 1;\n\t\t\t\tpixelBit1 = x & 1;\n\t\t\t\tpixelBit2 = (x & 2) >> 1;\n\t\t\t\tpixelBit3 = (x & 4) >> 2;\n\t\t\t\tpixelBit4 = (y & 2) >> 1;\n\t\t\t\tpixelBit5 = (y & 4) >> 2;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tpixelBit0 = x & 1;\n\t\t\t\tpixelBit1 = (x & 2) >> 1;\n\t\t\t\tpixelBit2 = y & 1;\n\t\t\t\tpixelBit3 = (x & 4) >> 2;\n\t\t\t\tpixelBit4 = (y & 2) >> 1;\n\t\t\t\tpixelBit5 = (y & 4) >> 2;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (thickness > 1)\n\t\t{\n\t\t\tpixelBit6 = z & 1;\n\t\t\tpixelBit7 = (z & 2) >> 1;\n\t\t}\n\t\treturn (pixelBit8 << 8) | (pixelBit7 << 7) | (pixelBit6 << 6) | (pixelBit5 << 5) | (pixelBit4 << 4) | (pixelBit3 << 3) | (pixelBit2 << 2) | (pixelBit1 << 1) | pixelBit0;\n\t}\n\n\tuint32 _ComputePipeFromCoordWoRotation(uint32 x, uint32 y)\n\t{\n\t\t// hardcoded to assume 2 pipes\n\t\tuint32 pipe;\n\t\tpipe = ((y >> 3) ^ (x >> 3)) & 1;\n\t\treturn pipe;\n\t}\n\n\tuint32 _ComputeBankFromCoordWoRotation(uint32 x, uint32 y)\n\t{\n\t\tuint32 bank;\n\t\tif (m_banks == 4)\n\t\t{\n\t\t\tuint32 bankNew = (y >> 4) & 3;\n\t\t\tbankNew = ((bankNew >> 1) | (bankNew << 1)); // swap lowest two bits\n\t\t\tbankNew ^= (x >> 3);\n\t\t\tbankNew &= 3;\n\t\t\tbank = bankNew;\n\t\t}\n\t\telse if (m_banks == 8)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t\tbank = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbank = 0;\n\t\t}\n\t\treturn bank;\n\t}\n\n\tuint32 ComputeSurfaceAddrFromCoordLinear(uint32 x, uint32 y, uint32 slice, uint32 sample, uint32 bpp, uint32 pitch, uint32 height, uint32 numSlices)\n\t{\n\t\tuint32 pixelIndex = x + pitch * y + (slice + numSlices * sample) * height * pitch;\n\t\treturn (pixelIndex * bpp) / 8;\n\t}\n\n\tuint32 ComputeSurfaceAddrFromCoordMicroTiled(uint32 x, uint32 y, uint32 slice, uint32 bpp, uint32 pitch, uint32 height, Latte::E_HWTILEMODE tileMode, bool isDepth)\n\t{\n\t\tuint32 microTileThickness = (tileMode == Latte::E_HWTILEMODE::TM_1D_TILED_THICK) ? 4 : 1;\n\t\tuint32 microTilesPerRow = pitch >> 3;\n\t\tuint32 microTileIndexX = x >> 3;\n\t\tuint32 microTileIndexY = y >> 3;\n\t\tuint32 microTileBytes = microTileThickness * (((bpp << 6) + 7) >> 3); // each tile is 8x8 or 8x8x4\n\t\tuint32 microTileOffset = microTileBytes * (uint64)((x >> 3) + (pitch >> 3) * (y >> 3));\n\t\tuint32 sliceBytes = (height * (uint64)pitch * microTileThickness * bpp + 7) / 8;\n\t\tuint32 sliceOffset = sliceBytes * (slice / microTileThickness);\n\t\tuint32 pixelIndex = _ComputePixelIndexWithinMicroTile(x, y, slice, bpp, tileMode, _GetMicroTileType(isDepth));\n\t\tuint32 pixelOffset = bpp * pixelIndex;\n\t\tpixelOffset >>= 3;\n\t\treturn pixelOffset + microTileOffset + sliceOffset;\n\t}\n\n\tuint32 ComputeSurfaceAddrFromCoordMacroTiled(uint32 x, uint32 y, uint32 slice, uint32 sample, uint32 bpp, uint32 pitch, uint32 height, uint32 numSamples, Latte::E_HWTILEMODE tileMode, bool isDepth, uint32 pipeSwizzle, uint32 bankSwizzle)\n\t{\n\t\tuint32 microTileThickness = LatteAddrLib::TM_GetThickness((E_HWTILEMODE)tileMode);\n\t\tuint32 microTileBits = numSamples * bpp * (microTileThickness * (8 * 8));\n\t\tuint32 microTileBytes = microTileBits >> 3;\n\t\tuint32 pixelIndex = _ComputePixelIndexWithinMicroTile(x, y, slice, bpp, tileMode, _GetMicroTileType(isDepth));\n\t\tuint32 sampleOffset, pixelOffset;\n\t\tif (isDepth)\n\t\t{\n\t\t\tsampleOffset = bpp * sample;\n\t\t\tpixelOffset = numSamples * bpp * pixelIndex;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsampleOffset = sample * (microTileBits / numSamples);\n\t\t\tpixelOffset = bpp * pixelIndex;\n\t\t}\n\t\tuint32 elemOffset = pixelOffset + sampleOffset;\n\t\tuint32 bytesPerSample = microTileBytes / numSamples;\n\t\tuint32 sampleSlice, numSampleSplits;\n\t\tif (numSamples <= 1 || microTileBytes <= m_splitSize)\n\t\t{\n\t\t\tnumSampleSplits = 1;\n\t\t\tsampleSlice = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint32 samplesPerSlice = m_splitSize / bytesPerSample;\n\t\t\tnumSampleSplits = numSamples / samplesPerSlice;\n\t\t\tnumSamples = samplesPerSlice;\n\t\t\tsampleSlice = elemOffset / (microTileBits / numSampleSplits);\n\t\t\telemOffset %= microTileBits / numSampleSplits;\n\t\t}\n\t\telemOffset >>= 3;\n\t\tuint32 pipe = _ComputePipeFromCoordWoRotation(x, y);\n\t\tuint32 bank = _ComputeBankFromCoordWoRotation(x, y);\n\t\tuint32 bankPipe = pipe + m_pipes * bank;\n\t\tuint32 rotation = ComputeSurfaceRotationFromTileMode(tileMode);\n\t\tuint32 swizzle = pipeSwizzle + m_pipes * bankSwizzle;\n\t\tuint32 sliceIn = slice;\n\t\tif (TM_IsThickAndMacroTiled(tileMode))\n\t\t\tsliceIn >>= 2;\n\t\tbankPipe ^= m_pipes * sampleSlice * ((m_banks >> 1) + 1) ^ (swizzle + sliceIn * rotation);\n\t\tbankPipe %= m_pipes * m_banks;\n\t\tpipe = bankPipe % m_pipes;\n\t\tbank = bankPipe / m_pipes;\n\t\tuint64 sliceBytes = (((uint64)height * pitch * microTileThickness * bpp * numSamples + 7) / 8);\n\t\tuint64 sliceOffset = sliceBytes * ((sampleSlice + numSampleSplits * slice) / microTileThickness);\n\t\tuint32 macroTilePitch = 8 * m_banks;\n\t\tuint32 macroTileHeight = 8 * m_pipes;\n\t\tswitch (tileMode)\n\t\t{\n\t\tcase Latte::E_HWTILEMODE::TM_2D_TILED_THIN2:\n\t\tcase Latte::E_HWTILEMODE::TM_2B_TILED_THIN2:\n\t\t\tmacroTilePitch >>= 1;\n\t\t\tmacroTileHeight <<= 1;\n\t\t\tbreak;\n\t\tcase Latte::E_HWTILEMODE::TM_2D_TILED_THIN4:\n\t\tcase Latte::E_HWTILEMODE::TM_2B_TILED_THIN4:\n\t\t\tmacroTilePitch >>= 2;\n\t\t\tmacroTileHeight <<= 2;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\tuint32 macroTilesPerRow = pitch / macroTilePitch;\n\t\tuint32 macroTileBytes = (numSamples * microTileThickness * bpp * macroTileHeight * macroTilePitch + 7) >> 3;\n\t\tuint32 macroTileIndexX = x / macroTilePitch;\n\t\tuint32 macroTileIndexY = y / macroTileHeight;\n\t\tuint32 macroTileOffset = (x / macroTilePitch + pitch / macroTilePitch * (y / macroTileHeight)) * macroTileBytes;\n\t\tif (TM_IsBankSwapped(tileMode))\n\t\t{\n\t\t\tuint32 bankSwapWidth = ComputeSurfaceBankSwappedWidth(tileMode, bpp, numSamples, pitch);\n\t\t\tuint32 swapIndex = macroTilePitch * macroTileIndexX / bankSwapWidth;\n\t\t\tuint32 bankMask = m_banks - 1;\n\t\t\tbank ^= bankSwapOrder[swapIndex & bankMask];\n\t\t}\n\t\tuint32 pipeOffset = (pipe << m_pipeInterleaveBytesBitcount);\n\t\tuint32 bankOffset = (bank << (m_pipesBitcount + m_pipeInterleaveBytesBitcount));\n\t\tuint32 numSwizzleBits = (m_banksBitcount + m_pipesBitcount);\n\t\tuint32 macroSliceOffset = (uint32)((macroTileOffset + sliceOffset) >> numSwizzleBits);\n\t\tmacroSliceOffset += elemOffset;\n\n\t\tuint32 macroSliceOffsetHigh = macroSliceOffset & ~((1 << m_pipeInterleaveBytesBitcount) - 1);\n\t\tuint32 macroSliceOffsetLow = macroSliceOffset & ((1 << m_pipeInterleaveBytesBitcount) - 1);\n\n\t\tuint32 finalMacroTileOffset = (macroSliceOffsetHigh << numSwizzleBits) | macroSliceOffsetLow;\n\t\treturn finalMacroTileOffset | pipeOffset | bankOffset;\n\t}\n\n\tvoid SetupCachedSurfaceAddrInfo(CachedSurfaceAddrInfo* info, uint32 slice, uint32 sample, uint32 bpp, uint32 pitch, uint32 height, uint32 depth, uint32 numSamples, E_HWTILEMODE tileMode, int isDepth, uint32 pipeSwizzle, uint32 bankSwizzle)\n\t{\n\t\tinfo->slice = slice;\n\t\tinfo->sample = sample;\n\t\tinfo->bpp = bpp;\n\t\tinfo->pitch = pitch;\n\t\tinfo->height = height;\n\t\tinfo->depth = depth;\n\t\tinfo->numSamples = numSamples;\n\t\tinfo->tileMode = tileMode;\n\t\tinfo->isDepth = isDepth;\n\t\tinfo->pipeSwizzle = pipeSwizzle;\n\t\tinfo->bankSwizzle = bankSwizzle;\n\t\t// calculate static info\n\t\tinfo->microTileThickness = LatteAddrLib::TM_GetThickness((E_HWTILEMODE)tileMode);\n\t\tinfo->microTileBits = info->numSamples * info->bpp * (info->microTileThickness * (8 * 8));\n\t\tinfo->microTileBytes = info->microTileBits >> 3;\n\t\tinfo->microTileType = (info->isDepth != 0) ? 1 : 0;\n\t\tcemu_assert_debug(sample == 0); // non-zero not supported\n\t\tinfo->rotation = ComputeSurfaceRotationFromTileMode((E_HWTILEMODE)tileMode);\n\t\t// macro tile\n\t\tinfo->macroTilePitch = 8 * m_banks;\n\t\tinfo->macroTileHeight = 8 * m_pipes;\n\t\tswitch (info->tileMode)\n\t\t{\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN2:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN2:\n\t\t\tinfo->macroTilePitch >>= 1;\n\t\t\tinfo->macroTileHeight <<= 1;\n\t\t\tbreak;\n\t\tcase E_HWTILEMODE::TM_2D_TILED_THIN4:\n\t\tcase E_HWTILEMODE::TM_2B_TILED_THIN4:\n\t\t\tinfo->macroTilePitch >>= 2;\n\t\t\tinfo->macroTileHeight <<= 2;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\t_BitScanReverse((DWORD*)&info->macroTilePitchBits, info->macroTilePitch);\n\t\t_BitScanReverse((DWORD*)&info->macroTileHeightBits, info->macroTileHeight);\n\t\tinfo->macroTilesPerRow = info->pitch / info->macroTilePitch;\n\t\tinfo->macroTileBytes = (info->numSamples * info->microTileThickness * info->bpp * info->macroTileHeight * info->macroTilePitch + 7) >> 3;\n\t\t// slice\n\t\tinfo->sliceBytes = (info->height * (uint64)info->pitch * info->microTileThickness * info->bpp * info->numSamples + 7) / 8;\n\t\tinfo->sliceIn = info->slice;\n\t\tif (TM_IsThickAndMacroTiled(tileMode))\n\t\t\tinfo->sliceIn >>= 2;\n\t\t// bank swap\n\t\tif (TM_IsBankSwapped(tileMode))\n\t\t\tinfo->bankSwapWidth = ComputeSurfaceBankSwappedWidth(tileMode, info->bpp, info->numSamples, info->pitch);\n\t\t// pixel offset multiplier\n\t\tif (info->isDepth)\n\t\t{\n\t\t\tinfo->pixelOffsetMul = info->numSamples * info->bpp;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tinfo->pixelOffsetMul = info->bpp;\n\t\t}\n\t\tinfo->bytesPerPixel = info->pixelOffsetMul >> 3;\n\t\t// table for micro tile offset calculation (we could pre-generate these)\n\t\tfor (sint32 z = 0; z < 8; z++)\n\t\t{\n\t\t\tfor (sint32 y = 0; y < 8; y++)\n\t\t\t{\n\t\t\t\tfor (sint32 x = 0; x < 8; x++)\n\t\t\t\t{\n\t\t\t\t\tuint16 v = _ComputePixelIndexWithinMicroTile(x, y, z, info->bpp, info->tileMode, info->microTileType);\n\t\t\t\t\tinfo->microTilePixelIndexTable[x + y * 8 + z * 8 * 8] = v;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// other constant values\n\t\tuint32 swizzle = info->pipeSwizzle + m_pipes * info->bankSwizzle;\n\t\tinfo->c0 = (swizzle + info->sliceIn * info->rotation);\n\t}\n\n\tuint32 ComputeSurfaceAddrFromCoordMacroTiledCached(uint32 x, uint32 y, CachedSurfaceAddrInfo* info)\n\t{\n\t\tuint32 numSamples = info->numSamples;\n\t\tuint32 pixelIndex = (uint32)info->microTilePixelIndexTable[(x & 7) + ((y & 7) << 3) + ((info->slice & 7) << 6)];\n\t\tuint32 pixelOffset = pixelIndex * info->pixelOffsetMul;\n\t\tuint32 bytesPerSample = info->microTileBytes / numSamples;\n\t\tuint32 sampleSlice, numSampleSplits, samplesPerSlice;\n\t\tif (numSamples <= 1 || info->microTileBytes <= m_splitSize)\n\t\t{\n\t\t\tsamplesPerSlice = numSamples;\n\t\t\tnumSampleSplits = 1;\n\t\t\tsampleSlice = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsamplesPerSlice = m_splitSize / bytesPerSample;\n\t\t\tnumSampleSplits = numSamples / samplesPerSlice;\n\t\t\tnumSamples = samplesPerSlice;\n\t\t\tsampleSlice = pixelOffset / (info->microTileBits / numSampleSplits);\n\t\t\tpixelOffset %= info->microTileBits / numSampleSplits;\n\t\t}\n\t\tpixelOffset >>= 3;\n\t\tuint32 pipe = _ComputePipeFromCoordWoRotation(x, y);\n\t\tuint32 bank = _ComputeBankFromCoordWoRotation(x, y);\n\t\tuint32 bankPipe = pipe + m_pipes * bank;\n\t\tbankPipe ^= m_pipes * sampleSlice * ((m_banks >> 1) + 1) ^ info->c0;\n\t\tbankPipe %= m_pipes * m_banks;\n\t\tpipe = bankPipe % m_pipes;\n\t\tbank = bankPipe / m_pipes;\n\t\tuint32 sliceOffset = info->sliceBytes * ((sampleSlice + numSampleSplits * info->slice) / info->microTileThickness);\n\t\tuint32 macroTileIndexX = x >> info->macroTilePitchBits;\n\t\tuint32 macroTileIndexY = y >> info->macroTileHeightBits;\n\t\tuint32 macroTileOffset = (macroTileIndexX + (info->pitch >> info->macroTilePitchBits) * macroTileIndexY) * info->macroTileBytes;\n\t\tif (TM_IsBankSwapped(info->tileMode))\n\t\t{\n\t\t\tuint32 swapIndex = info->macroTilePitch * macroTileIndexX / info->bankSwapWidth;\n\t\t\tbank ^= bankSwapOrder[swapIndex & (m_banks - 1)];\n\t\t}\n\t\tuint32 pipeOffset = (pipe << m_pipeInterleaveBytesBitcount);\n\t\tuint32 bankOffset = (bank << (m_pipesBitcount + m_pipeInterleaveBytesBitcount));\n\t\tuint32 numSwizzleBits = (m_banksBitcount + m_pipesBitcount);\n\t\tuint32 macroSliceOffset = (uint32)((macroTileOffset + sliceOffset) >> numSwizzleBits);\n\t\tmacroSliceOffset += pixelOffset;\n\t\tuint32 macroSliceOffsetHigh = macroSliceOffset & ~((1 << m_pipeInterleaveBytesBitcount) - 1);\n\t\tuint32 macroSliceOffsetLow = macroSliceOffset & ((1 << m_pipeInterleaveBytesBitcount) - 1);\n\t\tuint32 finalMacroTileOffset = (macroSliceOffsetHigh << numSwizzleBits) | macroSliceOffsetLow;\n\t\treturn finalMacroTileOffset | pipeOffset | bankOffset;\n\t}\n\n\t/*\n\t * Optimized routine with following assumptions:\n\t * tileMode is 4\n\t * samples is 1\n\t */\n\tuint32 ComputeSurfaceAddrFromCoordMacroTiledCached_tm04_sample1(uint32 x, uint32 y, CachedSurfaceAddrInfo* info)\n\t{\n\t\tuint32 pixelIndex = (uint32)info->microTilePixelIndexTable[(x & 7) + ((y & 7) << 3) + ((info->slice & 7) << 6)];\n\t\tuint32 pixelOffset = pixelIndex * info->pixelOffsetMul;\n\t\tpixelOffset >>= 3; // bits to bytes\n\t\tuint32 pipe = _ComputePipeFromCoordWoRotation(x, y); // pipe = ((y >> 3) ^ (x >> 3)) & 1;\n\t\tuint32 bank = _ComputeBankFromCoordWoRotation(x, y); // based on (x>>3)&3 and (y>>4)&3\n\t\tpipe ^= (info->c0 >> 0) & 1;\n\t\tbank ^= (info->c0 >> 1) & 3;\n\t\tuint32 sliceOffset = info->sliceBytes * (info->slice / info->microTileThickness);\n\t\tuint32 macroTileIndexX = x >> info->macroTilePitchBits;\n\t\tuint32 macroTileIndexY = y >> info->macroTileHeightBits;\n\t\tuint32 macroTileOffset = (macroTileIndexX + (info->pitch >> info->macroTilePitchBits) * macroTileIndexY) * info->macroTileBytes;\n\t\tuint32 pipeOffset = (pipe << m_pipeInterleaveBytesBitcount);\n\t\tuint32 bankOffset = (bank << (m_pipesBitcount + m_pipeInterleaveBytesBitcount));\n\t\tuint32 numSwizzleBits = (m_banksBitcount + m_pipesBitcount);\n\t\tuint32 macroSliceOffset = (uint32)((macroTileOffset + sliceOffset) >> numSwizzleBits);\n\t\tmacroSliceOffset += pixelOffset;\n\t\tuint32 macroSliceOffsetHigh = macroSliceOffset & ~((1 << m_pipeInterleaveBytesBitcount) - 1);\n\t\tuint32 macroSliceOffsetLow = macroSliceOffset & ((1 << m_pipeInterleaveBytesBitcount) - 1);\n\t\tuint32 finalMacroTileOffset = (macroSliceOffsetHigh << numSwizzleBits) | macroSliceOffsetLow;\n\t\treturn finalMacroTileOffset | pipeOffset | bankOffset;\n\t}\n\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"util/helpers/helpers.h\"\n\n// parse instruction and if valid append it to instructionList\nbool LatteDecompiler_ParseCFInstruction(LatteDecompilerShaderContext* shaderContext, uint32 cfIndex, uint32 cfWord0, uint32 cfWord1, bool* endOfProgram, std::vector<LatteDecompilerCFInstruction>& instructionList)\n{\n\tLatteDecompilerShader* shaderObj = shaderContext->shader;\n\tuint32 cf_inst23_7 = (cfWord1 >> 23) & 0x7F;\n\tif (cf_inst23_7 < 0x40) // starting at 0x40 the bits overlap with the ALU instruction encoding\n\t{\n\t\t*endOfProgram = ((cfWord1 >> 21) & 1) != 0;\n\t\tuint32 addr = cfWord0 & 0xFFFFFFFF;\n\t\tuint32 count = (cfWord1 >> 10) & 7;\n\t\tif (((cfWord1 >> 19) & 1) != 0)\n\t\t\tcount |= 0x8;\n\t\tcount++;\n\t\tif (cf_inst23_7 == GPU7_CF_INST_CALL_FS)\n\t\t{\n\t\t\t// nop\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_NOP)\n\t\t{\n\t\t\t// nop\n\t\t\tif (((cfWord1 >> 0) & 7) != 0)\n\t\t\t\tdebugBreakpoint(); // pop count is not zero\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_EXPORT || cf_inst23_7 == GPU7_CF_INST_EXPORT_DONE)\n\t\t{\n\t\t\t// export\n\t\t\tuint32 edType = (cfWord0 >> 13) & 0x3;\n\t\t\tuint32 edIndexGpr = (cfWord0 >> 23) & 0x7F;\n\t\t\tuint32 edRWRel = (cfWord0 >> 22) & 1;\n\t\t\tif (edRWRel != 0 || edIndexGpr != 0)\n\t\t\t\tdebugBreakpoint();\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\t// set type and address\n\t\t\tcfInstruction.type = cf_inst23_7;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\t// set cond\n\t\t\tcfInstruction.cfCond = (cfWord1 >> 8) & 3;\n\t\t\t// set export component selection\n\t\t\tcfInstruction.exportComponentSel[0] = (cfWord1 >> 0) & 0x7;\n\t\t\tcfInstruction.exportComponentSel[1] = (cfWord1 >> 3) & 0x7;\n\t\t\tcfInstruction.exportComponentSel[2] = (cfWord1 >> 6) & 0x7;\n\t\t\tcfInstruction.exportComponentSel[3] = (cfWord1 >> 9) & 0x7;\n\t\t\t// set export array base, index and burstcount\n\t\t\tcfInstruction.exportArrayBase = (cfWord0 >> 0) & 0x1FFF;\n\t\t\tcfInstruction.exportBurstCount = (cfWord1 >> 17) & 0xF;\n\t\t\t// set export source GPR and type\n\t\t\tcfInstruction.exportSourceGPR = (cfWord0 >> 15) & 0x7F;\n\t\t\tcfInstruction.exportType = edType;\n\t\t\t//cfInstruction->memWriteElemSize = (cfWord0>>29)&3; // unused\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_TEX)\n\t\t{\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\t// set type and address\n\t\t\tcfInstruction.type = cf_inst23_7;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\t// set cond\n\t\t\tcfInstruction.cfCond = (cfWord1 >> 8) & 3;\n\t\t\t// set TEX clause related values\n\t\t\tcfInstruction.addr = addr; // index of first instruction in 64bit words\n\t\t\tcfInstruction.count = count; // number of instructions (each instruction is 128bit)\n\t\t\t// todo: CF_CONST and COND field and maybe other fields?\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_ELSE ||\n\t\t\tcf_inst23_7 == GPU7_CF_INST_POP)\n\t\t{\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\t// set type and address\n\t\t\tcfInstruction.type = cf_inst23_7;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\t// set cond and popCount\n\t\t\tcfInstruction.cfCond = (cfWord1 >> 8) & 3;\n\t\t\tcfInstruction.popCount = (cfWord1 >> 0) & 7;\n\t\t\t// set TEX clause related values\n\t\t\tcfInstruction.addr = addr; // index of first instruction in 64bit words\n\t\t\tcfInstruction.count = count; // number of instructions (each instruction is 128bit)\n\t\t\t// todo: CF_CONST\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_JUMP)\n\t\t{\n\t\t\t// ignored (we use ALU/IF/ELSE/PUSH/POP clauses to determine code flow)\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_LOOP_START_DX10 || cf_inst23_7 == GPU7_CF_INST_LOOP_END ||\n\t\t\t\t cf_inst23_7 == GPU7_CF_INST_LOOP_START_NO_AL)\n\t\t{\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\t// set type and address\n\t\t\tcfInstruction.type = cf_inst23_7;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\t// set cond and popCount\n\t\t\tcfInstruction.cfCond = (cfWord1 >> 8) & 3;\n\t\t\tcfInstruction.popCount = (cfWord1 >> 0) & 7;\n\t\t\t// set TEX clause related values\n\t\t\tcfInstruction.addr = addr; // index of first instruction in 64bit words\n\t\t\tcfInstruction.count = count; // number of instructions (each instruction is 128bit)\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_LOOP_BREAK)\n\t\t{\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\t// set type and address\n\t\t\tcfInstruction.type = cf_inst23_7;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\t// set cond and popCount\n\t\t\tcfInstruction.cfCond = (cfWord1 >> 8) & 3;\n\t\t\tcfInstruction.popCount = (cfWord1 >> 0) & 7;\n\t\t\t// set clause related values\n\t\t\tcfInstruction.addr = addr; // index of first instruction in 64bit words\n\t\t\tcfInstruction.count = count; // number of instructions (each instruction is 128bit)\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_MEM_STREAM0_WRITE ||\n\t\t\tcf_inst23_7 == GPU7_CF_INST_MEM_STREAM1_WRITE)\n\t\t{\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\t// todo: Correctly read all the STREAM0_WRITE specific fields\n\t\t\t// set type and address\n\t\t\tcfInstruction.type = cf_inst23_7;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\t// set export array base\n\t\t\tcfInstruction.exportArrayBase = (cfWord0 >> 0) & 0x1FFF;\n\t\t\tcfInstruction.memWriteArraySize = (cfWord1 >> 0) & 0xFFF;\n\t\t\tcfInstruction.memWriteCompMask = (cfWord1 >> 12) & 0xF;\n\t\t\t// set export source GPR and type\n\t\t\tcfInstruction.exportSourceGPR = (cfWord0 >> 15) & 0x7F;\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_MEM_RING_WRITE)\n\t\t{\n\t\t\t// this CF instruction is only available when the geometry shader stage is active\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\t// set type and address\n\t\t\tcfInstruction.type = cf_inst23_7;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\t// set export array base\n\t\t\tcfInstruction.exportArrayBase = (cfWord0 >> 0) & 0x1FFF;\n\t\t\tcfInstruction.memWriteArraySize = (cfWord1 >> 0) & 0xFFF;\n\t\t\tcfInstruction.memWriteCompMask = (cfWord1 >> 12) & 0xF;\n\t\t\tcfInstruction.memWriteElemSize = ((cfWord0 >> 30) & 0x3);\n\t\t\tcfInstruction.exportBurstCount = (cfWord1 >> 17) & 0xF;\n\t\t\t// set export source GPR and type\n\t\t\tcfInstruction.exportSourceGPR = (cfWord0 >> 15) & 0x7F;\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_EMIT_VERTEX)\n\t\t{\n\t\t\t// this CF instruction is only available when the geometry shader stage is active\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\t// set type and address\n\t\t\tcfInstruction.type = cf_inst23_7;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_CALL)\n\t\t{\n\t\t\t// CALL subroutine\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\tuint32 callCount = (cfWord1 >> 13) & 0x3F;\n\t\t\tcfInstruction.addr = addr; // index of call destination in 64bit words\n\t\t\tcfInstruction.count = callCount; // store callCount in count\n\t\t\tcfInstruction.type = cf_inst23_7;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\t// remember subroutine\n\t\t\tbool subroutineIsKnown = false;\n\t\t\tfor (auto& it : shaderContext->list_subroutines)\n\t\t\t{\n\t\t\t\tif (it.cfAddr == addr)\n\t\t\t\t{\n\t\t\t\t\tsubroutineIsKnown = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (subroutineIsKnown == false)\n\t\t\t{\n\t\t\t\tLatteDecompilerSubroutineInfo subroutineInfo = { 0 };\n\t\t\t\tsubroutineInfo.cfAddr = addr;\n\t\t\t\tshaderContext->list_subroutines.push_back(subroutineInfo);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\telse if (cf_inst23_7 == GPU7_CF_INST_RETURN)\n\t\t{\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\t// set type and address\n\t\t\tcfInstruction.type = cf_inst23_7;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\t// set cond and popCount\n\t\t\tcfInstruction.cfCond = (cfWord1 >> 8) & 3;\n\t\t\tcfInstruction.popCount = (cfWord1 >> 0) & 7;\n\t\t\t// todo - other fields?\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebug_printf(\"Unknown 23_7 clause 0x%x found\\n\", cf_inst23_7);\n\t\t\tshaderObj->hasError = true;\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// ALU instruction\n\t\tuint32 cf_inst26_4 = ((cfWord1 >> 26) & 0xF) | GPU7_CF_INST_ALU_MASK;\n\t\tif (cf_inst26_4 == GPU7_CF_INST_ALU || cf_inst26_4 == GPU7_CF_INST_ALU_PUSH_BEFORE || cf_inst26_4 == GPU7_CF_INST_ALU_POP_AFTER || cf_inst26_4 == GPU7_CF_INST_ALU_POP2_AFTER || cf_inst26_4 == GPU7_CF_INST_ALU_BREAK || cf_inst26_4 == GPU7_CF_INST_ALU_ELSE_AFTER)\n\t\t{\n\t\t\tLatteDecompilerCFInstruction& cfInstruction = instructionList.emplace_back();\n\t\t\t// set type and address\n\t\t\tcfInstruction.type = cf_inst26_4;\n\t\t\tcfInstruction.cfAddr = cfIndex;\n\t\t\t// CF_ALU_* has no cond field\n\t\t\tcfInstruction.cfCond = 0;\n\t\t\t// set ALU clause related values\n\t\t\tcfInstruction.addr = (cfWord0 >> 0) & 0x3FFFFF; // index of first instruction in 64bit words\n\t\t\tcfInstruction.count = ((cfWord1 >> 18) & 0x7F) + 1; // number of instructions (each instruction is 64bit)\n\t\t\t// set constant file/bank values\n\t\t\tcfInstruction.cBank0Index = (cfWord0 >> 22) & 0xF;\n\t\t\tcfInstruction.cBank1Index = (cfWord0 >> 26) & 0xF;\n\t\t\tcfInstruction.cBank0AddrBase = ((cfWord1 >> 2) & 0xFF) * 16;\n\t\t\tcfInstruction.cBank1AddrBase = ((cfWord1 >> 10) & 0xFF) * 16;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebug_printf(\"Unknown 26_4 clause 0x%x found\\n\", cf_inst26_4);\n\t\t\tshaderObj->hasError = true;\n\t\t\treturn false;\n\t\t}\n\t}\n\tcemu_assert_unimplemented(); // should not reach\n\treturn false;\n}\n\nvoid LatteDecompiler_ParseCFSubroutine(LatteDecompilerShaderContext* shaderContext, uint8* programData, uint32 programSize, LatteDecompilerSubroutineInfo* subroutineInfo)\n{\n\tLatteDecompilerShader* shaderObj = shaderContext->shader;\n\t// parse control flow instructions\n\tfor (uint32 i = subroutineInfo->cfAddr; i < programSize / 8; i++)\n\t{\n\t\tuint32 cfWord0 = *(uint32*)(programData + i * 8 + 0);\n\t\tuint32 cfWord1 = *(uint32*)(programData + i * 8 + 4);\n\t\tbool isEndOfProgram = false;\n\t\tif( !LatteDecompiler_ParseCFInstruction(shaderContext, i, cfWord0, cfWord1, &isEndOfProgram, subroutineInfo->instructions) )\n\t\t\tcontinue;\n\t\tcemu_assert_debug(!isEndOfProgram); // should never be encountered in a subroutine?\n\t\tif (shaderObj->hasError)\n\t\t\treturn;\n\t\tauto& cfInstruction = subroutineInfo->instructions.back();\n\t\tif (cfInstruction.type == GPU7_CF_INST_RETURN)\n\t\t\treturn; // todo - should check if this return statement is conditional\n\t}\n\tcemu_assert_debug(false); // should not reach (subroutines have to end with RETURN)\n}\n\nvoid LatteDecompiler_ParseCF(LatteDecompilerShaderContext* shaderContext, uint8* programData, uint32 programSize)\n{\n\tLatteDecompilerShader* shaderObj = shaderContext->shader;\n\t// parse control flow instructions for main entry point\n\tbool endOfProgram = false;\n\tfor (uint32 i = 0; i < programSize / 8; i++)\n\t{\n\t\tuint32 cfWord0 = *(uint32*)(programData + i * 8 + 0);\n\t\tuint32 cfWord1 = *(uint32*)(programData + i * 8 + 4);\n\t\tLatteDecompiler_ParseCFInstruction(shaderContext, i, cfWord0, cfWord1, &endOfProgram, shaderContext->cfInstructions);\n\t\tif (endOfProgram)\n\t\t\tbreak;\n\t}\n\t// parse CF instructions for subroutines\n\tfor (auto& subroutineInfo : shaderContext->list_subroutines)\n\t{\n\t\tLatteDecompiler_ParseCFSubroutine(shaderContext, programData, programSize, &subroutineInfo);\n\t}\n}\n\n// returns true if the given op2/op3 ALU instruction is always executed on the transcendental unit\nbool LatteDecompiler_IsALUTransInstruction(bool isOP3, uint32 opcode)\n{\n\tif( isOP3 == true )\n\t\treturn false; // OP3 has no transcendental instructions?\n\n\tif( opcode == ALU_OP2_INST_COS ||\n\t\topcode == ALU_OP2_INST_SIN ||\n\t\topcode == ALU_OP2_INST_RECIP_FF ||\n\t\topcode == ALU_OP2_INST_RECIP_IEEE ||\n\t\topcode == ALU_OP2_INST_RECIPSQRT_IEEE ||\n\t\topcode == ALU_OP2_INST_RECIPSQRT_CLAMPED ||\n\t\topcode == ALU_OP2_INST_RECIPSQRT_FF ||\n\t\topcode == ALU_OP2_INST_MULLO_INT ||\n\t\topcode == ALU_OP2_INST_MULLO_UINT ||\n\t\topcode == ALU_OP2_INST_FLT_TO_INT ||\n\t\topcode == ALU_OP2_INST_FLT_TO_UINT ||\n\t\topcode == ALU_OP2_INST_INT_TO_FLOAT ||\n\t\topcode == ALU_OP2_INST_UINT_TO_FLOAT ||\n\t\topcode == ALU_OP2_INST_LOG_CLAMPED ||\n\t\topcode == ALU_OP2_INST_LOG_IEEE ||\n\t\topcode == ALU_OP2_INST_EXP_IEEE ||\n\t\topcode == ALU_OP2_INST_UINT_TO_FLOAT ||\n\t\topcode == ALU_OP2_INST_SQRT_IEEE\n\t\t)\n\t{\n\t\t// transcendental\n\t\treturn true;\n\t}\n\telse if( opcode == ALU_OP2_INST_MOV ||\n\t\topcode == ALU_OP2_INST_ADD ||\n\t\topcode == ALU_OP2_INST_NOP ||\n\t\topcode == ALU_OP2_INST_MUL ||\n\t\topcode == ALU_OP2_INST_DOT4 ||\n\t\topcode == ALU_OP2_INST_DOT4_IEEE ||\n\t\topcode == ALU_OP2_INST_MAX || // Not sure if MIN/MAX are non-transcendental?\n\t\topcode == ALU_OP2_INST_MIN ||\n\t\topcode == ALU_OP2_INST_AND_INT ||\n\t\topcode == ALU_OP2_INST_OR_INT ||\n\t\topcode == ALU_OP2_INST_XOR_INT ||\n\t\topcode == ALU_OP2_INST_NOT_INT ||\n\t\topcode == ALU_OP2_INST_ADD_INT ||\n\t\topcode == ALU_OP2_INST_SUB_INT ||\n\t\topcode == ALU_OP2_INST_SETGT ||\n\t\topcode == ALU_OP2_INST_SETGE ||\n\t\topcode == ALU_OP2_INST_SETNE ||\n\t\topcode == ALU_OP2_INST_SETE ||\n\t\topcode == ALU_OP2_INST_SETE_INT ||\n\t\topcode == ALU_OP2_INST_SETNE_INT ||\n\t\topcode == ALU_OP2_INST_SETGT_INT ||\n\t\topcode == ALU_OP2_INST_SETGE_INT ||\n\t\topcode == ALU_OP2_INST_SETGE_UINT ||\n\t\topcode == ALU_OP2_INST_SETGT_UINT ||\n\t\topcode == ALU_OP2_INST_MAX_DX10 ||\n\t\topcode == ALU_OP2_INST_MIN_DX10 ||\n\t\topcode == ALU_OP2_INST_PRED_SETE ||\n\t\topcode == ALU_OP2_INST_PRED_SETNE ||\n\t\topcode == ALU_OP2_INST_PRED_SETGE ||\n\t\topcode == ALU_OP2_INST_PRED_SETGT ||\n\t\topcode == ALU_OP2_INST_PRED_SETE_INT ||\n\t\topcode == ALU_OP2_INST_PRED_SETNE_INT ||\n\t\topcode == ALU_OP2_INST_PRED_SETGT_INT ||\n\t\topcode == ALU_OP2_INST_PRED_SETGE_INT ||\n\t\topcode == ALU_OP2_INST_KILLE_INT ||\n\t\topcode == ALU_OP2_INST_KILLGT_INT ||\n\t\topcode == ALU_OP2_INST_KILLNE_INT ||\n\t\topcode == ALU_OP2_INST_KILLGT ||\n\t\topcode == ALU_OP2_INST_KILLGE ||\n\t\topcode == ALU_OP2_INST_KILLE ||\n\t\topcode == ALU_OP2_INST_MUL_IEEE ||\n\t\topcode == ALU_OP2_INST_FLOOR ||\n\t\topcode == ALU_OP2_INST_FRACT ||\n\t\topcode == ALU_OP2_INST_TRUNC ||\n\t\topcode == ALU_OP2_INST_LSHL_INT ||\n\t\topcode == ALU_OP2_INST_ASHR_INT ||\n\t\topcode == ALU_OP2_INST_LSHR_INT ||\n\t\topcode == ALU_OP2_INST_MAX_INT ||\n\t\topcode == ALU_OP2_INST_MIN_INT ||\n\t\topcode == ALU_OP2_INST_MAX_UINT ||\n\t\topcode == ALU_OP2_INST_MIN_UINT ||\n\t\topcode == ALU_OP2_INST_MOVA_FLOOR ||\n\t\topcode == ALU_OP2_INST_MOVA_INT ||\n\t\topcode == ALU_OP2_INST_SETE_DX10 ||\n\t\topcode == ALU_OP2_INST_SETNE_DX10 ||\n\t\topcode == ALU_OP2_INST_SETGT_DX10 ||\n\t\topcode == ALU_OP2_INST_SETGE_DX10 ||\n\t\topcode == ALU_OP2_INST_RNDNE ||\n\t\topcode == ALU_OP2_INST_CUBE // reduction instruction\n\t\t)\n\t{\n\t\t// not transcendental\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\tdebug_printf(\"_isALUTransInstruction(): Unknown instruction 0x%x (%s)\\n\", opcode, isOP3?\"op3\":\"op2\");\n\t}\n\n\t// ALU.Trans instructions:\n\t// [x] FLT_TO_INT\n\t// [x] FLT_TO_UINT\n\t// [x] INT_TO_FLT\n\t// MULHI_INT\n\t// MULHI_UINT\n\t// [x] MULLO_INT\n\t// [x] MULLO_UINT\n\t// RECIP_INT\n\t// RECIP_UINT\n\t// [x] UINT_TO_FLT\n\t// [x] COS\n\t// [x] EXP_IEEE\n\t// [x] LOG_CLAMPED\n\t// [x] LOG_IEEE\n\t// MUL_LIT\n\t// MUL_LIT_D2\n\t// MUL_LIT_M2\n\t// MUL_LIT_M4\n\t// RECIP_CLAMPED\n\t// [x] RECIP_FF\n\t// [x] RECIP_IEEE\n\t// [x] RECIPSQRT_CLAMPED\n\t// [x] RECIPSQRT_FF\n\t// [x] RECIPSQRT_IEEE\n\t// [x] SIN\n\t// [x] SQRT_IEEE\n\n\treturn false;\n}\n\nvoid LatteDecompiler_ParseALUClause(LatteDecompilerShader* shaderContext, LatteDecompilerCFInstruction* cfInstruction, uint8* programData, uint32 programSize)\n{\n\tsint32 instructionGroupIndex = 0;\n\tsint32 indexInGroup = 0; // index of instruction within instruction group\n\tuint32 elementsWrittenMask = 0; // used to determine ALU/Trans unit for instructions\n\tuint8 literalMask = 0; // mask of used literals for current instruction group\n\tsint32 parserIndex = 0;\n\twhile( parserIndex < cfInstruction->count )\n\t{\n\t\tuint32 aluWord0 = *(uint32*)(programData+(cfInstruction->addr+parserIndex)*8+0);\n\t\tuint32 aluWord1 = *(uint32*)(programData+(cfInstruction->addr+parserIndex)*8+4);\n\t\tparserIndex++;\n\t\tbool isLastInGroup = (aluWord0&0x80000000) != 0;\n\t\tuint32 alu_inst13_5 = (aluWord1>>13)&0x1F;\n\t\t// parameters from ALU word 0 (shared for ALU OP2 and OP3)\n\t\tuint32 src0Sel = (aluWord0>>0)&0x1FF; // source selection\n\t\tuint32 src1Sel = (aluWord0>>13)&0x1FF;\n\t\tuint32 src0Rel = (aluWord0>>9)&0x1; // relative addressing mode\n\t\tuint32 src1Rel = (aluWord0>>22)&0x1;\n\t\tuint32 src0Chan = (aluWord0>>10)&0x3; // component selection x/y/z/w\n\t\tuint32 src1Chan = (aluWord0>>23)&0x3;\n\t\tuint32 src0Neg = (aluWord0>>12)&0x1; // negate input\n\t\tuint32 src1Neg = (aluWord0>>25)&0x1;\n\t\tuint32 indexMode = (aluWord0>>26)&7;\n\t\tuint32 predSel = (aluWord0>>29)&3;\n\t\tif( predSel != 0 )\n\t\t\tdebugBreakpoint();\n\t\tif( alu_inst13_5 >= 0x8 )\n\t\t{\n\t\t\t// op3\n\t\t\t// parameters from ALU word 1\n\t\t\tuint32 src2Sel = (aluWord1>>0)&0x1FF; // source selection\n\t\t\tuint32 src2Rel = (aluWord1>>9)&0x1; // relative addressing mode\n\t\t\tuint32 src2Chan = (aluWord1>>10)&0x3; // component selection x/y/z/w\n\t\t\tuint32 src2Neg = (aluWord1>>12)&0x1; // negate input\n\n\t\t\tuint32 destGpr = (aluWord1>>21)&0x7F;\n\t\t\tuint32 destRel = (aluWord1>>28)&1;\n\t\t\tuint32 destElem = (aluWord1>>29)&3;\n\t\t\tuint32 destClamp = (aluWord1>>31)&1;\n\n\t\t\tLatteDecompilerALUInstruction aluInstruction;\n\t\t\taluInstruction.cfInstruction = cfInstruction;\n\t\t\taluInstruction.isOP3 = true;\n\t\t\taluInstruction.opcode = alu_inst13_5;\n\t\t\taluInstruction.instructionGroupIndex = instructionGroupIndex;\n\t\t\taluInstruction.indexMode = indexMode;\n\t\t\taluInstruction.destGpr = destGpr;\n\t\t\taluInstruction.destRel = destRel;\n\t\t\taluInstruction.destElem = destElem;\n\t\t\taluInstruction.destClamp = destClamp;\n\t\t\taluInstruction.writeMask = 1;\n\t\t\taluInstruction.omod = 0; // op3 has no omod\n\t\t\taluInstruction.sourceOperand[0].sel = src0Sel;\n\t\t\taluInstruction.sourceOperand[0].rel = src0Rel;\n\t\t\taluInstruction.sourceOperand[0].abs = 0;\n\t\t\taluInstruction.sourceOperand[0].neg = src0Neg;\n\t\t\taluInstruction.sourceOperand[0].chan = src0Chan;\n\t\t\taluInstruction.sourceOperand[1].sel = src1Sel;\n\t\t\taluInstruction.sourceOperand[1].rel = src1Rel;\n\t\t\taluInstruction.sourceOperand[1].abs = 0;\n\t\t\taluInstruction.sourceOperand[1].neg = src1Neg;\n\t\t\taluInstruction.sourceOperand[1].chan = src1Chan;\n\t\t\taluInstruction.sourceOperand[2].sel = src2Sel;\n\t\t\taluInstruction.sourceOperand[2].rel = src2Rel;\n\t\t\taluInstruction.sourceOperand[2].abs = 0;\n\t\t\taluInstruction.sourceOperand[2].neg = src2Neg;\n\t\t\taluInstruction.sourceOperand[2].chan = src2Chan;\n\t\t\t// check for literal access\n\t\t\tif( GPU7_ALU_SRC_IS_LITERAL(src0Sel) )\n\t\t\t\tliteralMask |= (1<<src0Chan);\n\t\t\tif( GPU7_ALU_SRC_IS_LITERAL(src1Sel) )\n\t\t\t\tliteralMask |= (1<<src1Chan);\n\t\t\tif( GPU7_ALU_SRC_IS_LITERAL(src2Sel) )\n\t\t\t\tliteralMask |= (1<<src2Chan);\n\t\t\t// determine used ALU unit (x,y,z,w,t)\n\t\t\tuint32 aluUnit = destElem;\n\t\t\tif( aluUnit < 4 && (elementsWrittenMask & (1<<aluUnit)) != 0 )\n\t\t\t{\n\t\t\t\taluUnit = 4; // ALU unit already used, this instruction uses the transcendental unit\n\t\t\t}\n\t\t\telementsWrittenMask |= (1<<aluUnit);\n\t\t\taluInstruction.aluUnit = aluUnit;\n\t\t\taluInstruction.indexInGroup = indexInGroup;\n\t\t\taluInstruction.isLastInstructionOfGroup = isLastInGroup;\n\t\t\t// add instruction to list of sub-instructions\n\t\t\tcfInstruction->instructionsALU.emplace_back(aluInstruction);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint32 alu_inst7_11 = (aluWord1>>7)&0x7FF;\n\n\t\t\tuint32 src0Abs = (aluWord1>>0)&1;\n\t\t\tuint32 src1Abs = (aluWord1>>1)&1;\n\t\t\tuint32 updateExecuteMask = (aluWord1>>2)&1;\n\t\t\tuint32 updatePredicate = (aluWord1>>3)&1;\n\t\t\tuint32 writeMask = (aluWord1>>4)&1;\n\t\t\tuint32 omod = (aluWord1>>5)&3;\n\n\t\t\tuint32 destGpr = (aluWord1>>21)&0x7F;\n\t\t\tuint32 destRel = (aluWord1>>28)&1;\n\t\t\tuint32 destElem = (aluWord1>>29)&3;\n\t\t\tuint32 destClamp = (aluWord1>>31)&1;\n\n\t\t\tLatteDecompilerALUInstruction aluInstruction;\n\t\t\taluInstruction.cfInstruction = cfInstruction;\n\t\t\taluInstruction.isOP3 = false;\n\t\t\taluInstruction.opcode = alu_inst7_11;\n\t\t\taluInstruction.instructionGroupIndex = instructionGroupIndex;\n\t\t\taluInstruction.indexMode = indexMode;\n\t\t\taluInstruction.destGpr = destGpr;\n\t\t\taluInstruction.destRel = destRel;\n\t\t\taluInstruction.destElem = destElem;\n\t\t\taluInstruction.destClamp = destClamp;\n\t\t\taluInstruction.writeMask = writeMask;\n\t\t\taluInstruction.updateExecuteMask = updateExecuteMask;\n\t\t\taluInstruction.updatePredicate = updatePredicate;\n\t\t\taluInstruction.omod = omod;\n\t\t\taluInstruction.sourceOperand[0].sel = src0Sel;\n\t\t\taluInstruction.sourceOperand[0].rel = src0Rel;\n\t\t\taluInstruction.sourceOperand[0].abs = src0Abs;\n\t\t\taluInstruction.sourceOperand[0].neg = src0Neg;\n\t\t\taluInstruction.sourceOperand[0].chan = src0Chan;\n\t\t\taluInstruction.sourceOperand[1].sel = src1Sel;\n\t\t\taluInstruction.sourceOperand[1].rel = src1Rel;\n\t\t\taluInstruction.sourceOperand[1].abs = src1Abs;\n\t\t\taluInstruction.sourceOperand[1].neg = src1Neg;\n\t\t\taluInstruction.sourceOperand[1].chan = src1Chan;\n\t\t\taluInstruction.sourceOperand[2].sel = 0xFFFFFFFF;\n\t\t\t// check for literal access\n\t\t\tif( GPU7_ALU_SRC_IS_LITERAL(src0Sel) )\n\t\t\t\tliteralMask |= (1<<src0Chan);\n\t\t\tif( GPU7_ALU_SRC_IS_LITERAL(src1Sel) )\n\t\t\t\tliteralMask |= (1<<src1Chan);\n\t\t\t// determine ALU unit (x,y,z,w,t)\n\t\t\tuint32 aluUnit = destElem;\n\t\t\t// some instructions always use the transcendental unit\n\t\t\tbool isTranscendentalOperation = LatteDecompiler_IsALUTransInstruction(false, alu_inst7_11);\n\t\t\tif( isTranscendentalOperation )\n\t\t\t\taluUnit = 4;\n\t\t\tif( aluUnit < 4 && (elementsWrittenMask & (1<<aluUnit)) != 0 )\n\t\t\t{\n\t\t\t\taluUnit = 4; // ALU unit already used, this instruction uses the transcendental unit\n\t\t\t}\n\t\t\telementsWrittenMask |= (1<<aluUnit);\n\t\t\taluInstruction.aluUnit = aluUnit;\n\t\t\taluInstruction.indexInGroup = indexInGroup;\n\t\t\taluInstruction.isLastInstructionOfGroup = isLastInGroup;\n\t\t\t// add instruction to list of sub-instructions\n\t\t\tcfInstruction->instructionsALU.emplace_back(aluInstruction);\n\t\t}\n\t\tindexInGroup++;\n\t\tif( isLastInGroup )\n\t\t{\n\t\t\t// load literal data\n\t\t\tif( literalMask )\n\t\t\t{\n\t\t\t\tbool useLiteralDataXY = false;\n\t\t\t\tbool useLiteralDataZW = false;\n\t\t\t\tif( (literalMask&(1|2)) )\n\t\t\t\t{\n\t\t\t\t\tuseLiteralDataXY = true;\n\t\t\t\t}\n\t\t\t\tif( (literalMask&(4|8)) )\n\t\t\t\t{\n\t\t\t\t\tuseLiteralDataXY = true;\n\t\t\t\t\tuseLiteralDataZW = true;\n\t\t\t\t}\n\t\t\t\tuint32 literalWords[4] = {0};\n\t\t\t\tliteralWords[0] = *(uint32*)(programData+(cfInstruction->addr+parserIndex)*8+0);\n\t\t\t\tliteralWords[1] = *(uint32*)(programData+(cfInstruction->addr+parserIndex)*8+4);\n\t\t\t\tif( useLiteralDataZW )\n\t\t\t\t{\n\t\t\t\t\tliteralWords[2] = *(uint32*)(programData+(cfInstruction->addr+parserIndex+1)*8+0);\n\t\t\t\t\tliteralWords[3] = *(uint32*)(programData+(cfInstruction->addr+parserIndex+1)*8+4);\n\t\t\t\t}\n\t\t\t\tif( useLiteralDataZW )\n\t\t\t\t\tparserIndex += 2;\n\t\t\t\telse\n\t\t\t\t\tparserIndex += 1;\n\t\t\t\t// set literal data for all instructions of the current instruction group\n\t\t\t\tfor(auto& aluInstructionItr : reverse_itr(cfInstruction->instructionsALU) )\n\t\t\t\t{\n\t\t\t\t\tif( aluInstructionItr.instructionGroupIndex != instructionGroupIndex )\n\t\t\t\t\t\tbreak;\n\t\t\t\t\taluInstructionItr.literalData.w[0] = literalWords[0];\n\t\t\t\t\taluInstructionItr.literalData.w[1] = literalWords[1];\n\t\t\t\t\taluInstructionItr.literalData.w[2] = literalWords[2];\n\t\t\t\t\taluInstructionItr.literalData.w[3] = literalWords[3];\n\t\t\t\t}\n\t\t\t}\n\t\t\t// reset instruction group related tracking variables\n\t\t\tliteralMask = 0;\n\t\t\telementsWrittenMask = 0;\n\t\t\tindexInGroup = 0;\n\t\t\t// start next group\n\t\t\tinstructionGroupIndex++;\n\t\t}\n\t}\n}\n\n/*\n * Parse TEX clause\n */\nvoid LatteDecompiler_ParseTEXClause(LatteDecompilerShader* shaderContext, LatteDecompilerCFInstruction* cfInstruction, uint8* programData, uint32 programSize)\n{\n\tfor(sint32 i=0; i<cfInstruction->count; i++)\n\t{\n\t\t// each instruction is 128bit\n\t\tuint32 instructionAddr = cfInstruction->addr*2+i*4;\n\t\tuint32 word0 = *(uint32*)(programData+instructionAddr*4+0);\n\t\tuint32 word1 = *(uint32*)(programData+instructionAddr*4+4);\n\t\tuint32 word2 = *(uint32*)(programData+instructionAddr*4+8);\n\t\tuint32 word3 = *(uint32*)(programData+instructionAddr*4+12);\n\t\tuint32 inst0_4 = (word0>>0)&0x1F;\n\t\tif (inst0_4 == GPU7_TEX_INST_SAMPLE || inst0_4 == GPU7_TEX_INST_SAMPLE_L || inst0_4 == GPU7_TEX_INST_SAMPLE_LZ || inst0_4 == GPU7_TEX_INST_SAMPLE_LB || inst0_4 == GPU7_TEX_INST_SAMPLE_C || inst0_4 == GPU7_TEX_INST_SAMPLE_C_L || inst0_4 == GPU7_TEX_INST_SAMPLE_C_LZ || inst0_4 == GPU7_TEX_INST_FETCH4 || inst0_4 == GPU7_TEX_INST_SAMPLE_G || inst0_4 == GPU7_TEX_INST_LD\n\t\t\t|| inst0_4 == GPU7_TEX_INST_GET_TEXTURE_RESINFO || inst0_4 == GPU7_TEX_INST_GET_COMP_TEX_LOD)\n\t\t{\n\t\t\tuint32 fetchType = (word0 >> 5) & 3;\n\t\t\tuint32 bufferId = (word0 >> 8) & 0xFF;\n\t\t\tuint32 samplerId = (word2 >> 15) & 0x1F;\n\t\t\tuint32 srcGpr = (word0 >> 16) & 0x7F;\n\t\t\tuint32 srcRel = (word0 >> 23) & 1;\n\t\t\tif (srcRel != 0)\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 destGpr = (word1 >> 0) & 0x7F;\n\t\t\tuint32 destRel = (word1 >> 7) & 1;\n\t\t\tif (destRel != 0)\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 dstSelX = (word1 >> 9) & 0x7;\n\t\t\tuint32 dstSelY = (word1 >> 12) & 0x7;\n\t\t\tuint32 dstSelZ = (word1 >> 15) & 0x7;\n\t\t\tuint32 dstSelW = (word1 >> 18) & 0x7;\n\n\t\t\tuint32 coordTypeX = (word1 >> 28) & 1;\n\t\t\tuint32 coordTypeY = (word1 >> 29) & 1;\n\t\t\tuint32 coordTypeZ = (word1 >> 30) & 1;\n\t\t\tuint32 coordTypeW = (word1 >> 31) & 1;\n\n\t\t\tuint32 srcSelX = (word2 >> 20) & 0x7;\n\t\t\tuint32 srcSelY = (word2 >> 23) & 0x7;\n\t\t\tuint32 srcSelZ = (word2 >> 26) & 0x7;\n\t\t\tuint32 srcSelW = (word2 >> 29) & 0x7;\n\n\t\t\tuint32 offsetX = (word2 >> 0) & 0x1F;\n\t\t\tuint32 offsetY = (word2 >> 5) & 0x1F;\n\t\t\tuint32 offsetZ = (word2 >> 10) & 0x1F;\n\n\t\t\tsint8 lodBias = (word2 >> 21) & 0x7F;\n\t\t\tif ((lodBias&0x40) != 0)\n\t\t\t\tlodBias |= 0x80;\n\t\t\t// bufferID -> Texture index\n\t\t\t// samplerId -> Sampler index\n\t\t\tsint32 textureIndex = bufferId - 0x00;\n\n\t\t\t// create new tex instruction\n\t\t\tLatteDecompilerTEXInstruction texInstruction;\n\t\t\ttexInstruction.cfInstruction = cfInstruction;\n\t\t\ttexInstruction.opcode = inst0_4;\n\t\t\ttexInstruction.textureFetch.textureIndex = textureIndex;\n\t\t\ttexInstruction.textureFetch.samplerIndex = samplerId;\n\t\t\ttexInstruction.dstSel[0] = dstSelX;\n\t\t\ttexInstruction.dstSel[1] = dstSelY;\n\t\t\ttexInstruction.dstSel[2] = dstSelZ;\n\t\t\ttexInstruction.dstSel[3] = dstSelW;\n\t\t\ttexInstruction.textureFetch.srcSel[0] = srcSelX;\n\t\t\ttexInstruction.textureFetch.srcSel[1] = srcSelY;\n\t\t\ttexInstruction.textureFetch.srcSel[2] = srcSelZ;\n\t\t\ttexInstruction.textureFetch.srcSel[3] = srcSelW;\n\t\t\ttexInstruction.textureFetch.offsetX = (sint8)((offsetX & 0x10) ? (offsetX | 0xE0) : (offsetX));\n\t\t\ttexInstruction.textureFetch.offsetY = (sint8)((offsetY & 0x10) ? (offsetY | 0xE0) : (offsetY));\n\t\t\ttexInstruction.textureFetch.offsetZ = (sint8)((offsetZ & 0x10) ? (offsetZ | 0xE0) : (offsetZ));\n\t\t\ttexInstruction.dstGpr = destGpr;\n\t\t\ttexInstruction.srcGpr = srcGpr;\n\t\t\ttexInstruction.textureFetch.unnormalized[0] = coordTypeX == 0;\n\t\t\ttexInstruction.textureFetch.unnormalized[1] = coordTypeY == 0;\n\t\t\ttexInstruction.textureFetch.unnormalized[2] = coordTypeZ == 0;\n\t\t\ttexInstruction.textureFetch.unnormalized[3] = coordTypeW == 0;\n\t\t\ttexInstruction.textureFetch.lodBias = (sint8)lodBias;\n\t\t\tcfInstruction->instructionsTEX.emplace_back(texInstruction);\n\t\t}\n\t\telse if( inst0_4 == GPU7_TEX_INST_SET_CUBEMAP_INDEX )\n\t\t{\n\t\t\t// todo: check if the encoding of fields matches with that of GPU7_TEX_INST_SAMPLE* (it should, according to AMD doc)\n\t\t\tuint32 fetchType = (word0>>5)&3;\n\t\t\tuint32 bufferId = (word0>>8)&0xFF;\n\t\t\tuint32 samplerId = (word2>>15)&0x1F;\n\t\t\tuint32 srcGpr = (word0>>16)&0x7F;\n\t\t\tuint32 srcRel = (word0>>23)&1;\n\t\t\tif( srcRel != 0 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 destGpr = (word1>>0)&0x7F;\n\t\t\tuint32 destRel = (word1>>7)&1;\n\t\t\tif( destRel != 0 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 dstSelX = (word1>>9)&0x7;\n\t\t\tuint32 dstSelY = (word1>>12)&0x7;\n\t\t\tuint32 dstSelZ = (word1>>15)&0x7;\n\t\t\tuint32 dstSelW = (word1>>18)&0x7;\n\n\t\t\tuint32 srcSelX = (word2>>20)&0x7;\n\t\t\tuint32 srcSelY = (word2>>23)&0x7;\n\t\t\tuint32 srcSelZ = (word2>>26)&0x7;\n\t\t\tuint32 srcSelW = (word2>>29)&0x7;\n\n\t\t\tsint32 textureIndex = bufferId-0x00;\n\n\t\t\t// create new tex instruction\n\t\t\tLatteDecompilerTEXInstruction texInstruction;\n\t\t\ttexInstruction.cfInstruction = cfInstruction;\n\t\t\ttexInstruction.opcode = inst0_4;\n\t\t\ttexInstruction.textureFetch.textureIndex = textureIndex;\n\t\t\ttexInstruction.textureFetch.samplerIndex = samplerId;\n\t\t\ttexInstruction.dstSel[0] = dstSelX;\n\t\t\ttexInstruction.dstSel[1] = dstSelY;\n\t\t\ttexInstruction.dstSel[2] = dstSelZ;\n\t\t\ttexInstruction.dstSel[3] = dstSelW;\n\t\t\ttexInstruction.textureFetch.srcSel[0] = srcSelX;\n\t\t\ttexInstruction.textureFetch.srcSel[1] = srcSelY;\n\t\t\ttexInstruction.textureFetch.srcSel[2] = srcSelZ;\n\t\t\ttexInstruction.textureFetch.srcSel[3] = srcSelW;\n\t\t\ttexInstruction.dstGpr = destGpr;\n\t\t\ttexInstruction.srcGpr = srcGpr;\n\t\t\tcfInstruction->instructionsTEX.emplace_back(texInstruction);\n\t\t}\n\t\telse if (inst0_4 == GPU7_TEX_INST_GET_GRADIENTS_H || inst0_4 == GPU7_TEX_INST_GET_GRADIENTS_V)\n\t\t{\n\t\t\tuint32 fetchType = (word0 >> 5) & 3;\n\t\t\tuint32 bufferId = (word0 >> 8) & 0xFF;\n\t\t\tuint32 samplerId = (word2 >> 15) & 0x1F;\n\t\t\tuint32 srcGpr = (word0 >> 16) & 0x7F;\n\t\t\tuint32 srcRel = (word0 >> 23) & 1;\n\t\t\tif (srcRel != 0)\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 destGpr = (word1 >> 0) & 0x7F;\n\t\t\tuint32 destRel = (word1 >> 7) & 1;\n\t\t\tif (destRel != 0)\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 dstSelX = (word1 >> 9) & 0x7;\n\t\t\tuint32 dstSelY = (word1 >> 12) & 0x7;\n\t\t\tuint32 dstSelZ = (word1 >> 15) & 0x7;\n\t\t\tuint32 dstSelW = (word1 >> 18) & 0x7;\n\n\t\t\tuint32 coordTypeX = (word1 >> 28) & 1;\n\t\t\tuint32 coordTypeY = (word1 >> 29) & 1;\n\t\t\tuint32 coordTypeZ = (word1 >> 30) & 1;\n\t\t\tuint32 coordTypeW = (word1 >> 31) & 1;\n\t\t\tcemu_assert_debug(coordTypeX != GPU7_TEX_UNNORMALIZED);\n\t\t\tcemu_assert_debug(coordTypeY != GPU7_TEX_UNNORMALIZED);\n\t\t\tcemu_assert_debug(coordTypeZ != GPU7_TEX_UNNORMALIZED);\n\t\t\tcemu_assert_debug(coordTypeW != GPU7_TEX_UNNORMALIZED);\n\n\t\t\tuint32 srcSelX = (word2 >> 20) & 0x7;\n\t\t\tuint32 srcSelY = (word2 >> 23) & 0x7;\n\t\t\tuint32 srcSelZ = (word2 >> 26) & 0x7;\n\t\t\tuint32 srcSelW = (word2 >> 29) & 0x7;\n\n\t\t\tuint32 offsetX = (word2 >> 0) & 0x1F;\n\t\t\tuint32 offsetY = (word2 >> 5) & 0x1F;\n\t\t\tuint32 offsetZ = (word2 >> 10) & 0x1F;\n\t\t\tcemu_assert_debug(offsetX == 0);\n\t\t\tcemu_assert_debug(offsetY == 0);\n\t\t\tcemu_assert_debug(offsetZ == 0);\n\n\t\t\t// create new tex instruction\n\t\t\tLatteDecompilerTEXInstruction texInstruction;\n\t\t\ttexInstruction.cfInstruction = cfInstruction;\n\t\t\ttexInstruction.opcode = inst0_4;\n\t\t\ttexInstruction.dstSel[0] = dstSelX;\n\t\t\ttexInstruction.dstSel[1] = dstSelY;\n\t\t\ttexInstruction.dstSel[2] = dstSelZ;\n\t\t\ttexInstruction.dstSel[3] = dstSelW;\n\t\t\ttexInstruction.textureFetch.srcSel[0] = srcSelX;\n\t\t\ttexInstruction.textureFetch.srcSel[1] = srcSelY;\n\t\t\ttexInstruction.textureFetch.srcSel[2] = srcSelZ;\n\t\t\ttexInstruction.textureFetch.srcSel[3] = srcSelW;\n\t\t\ttexInstruction.dstGpr = destGpr;\n\t\t\ttexInstruction.srcGpr = srcGpr;\n\t\t\tcfInstruction->instructionsTEX.emplace_back(texInstruction);\n\t\t}\n\t\telse if (inst0_4 == GPU7_TEX_INST_SET_GRADIENTS_H || inst0_4 == GPU7_TEX_INST_SET_GRADIENTS_V)\n\t\t{\n\t\t\tuint32 bufferId = (word0 >> 8) & 0xFF;\n\t\t\tuint32 samplerId = (word2 >> 15) & 0x1F;\n\t\t\tuint32 srcGpr = (word0 >> 16) & 0x7F;\n\t\t\tuint32 srcRel = (word0 >> 23) & 1;\n\t\t\tif (srcRel != 0)\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 coordTypeX = (word1 >> 28) & 1;\n\t\t\tuint32 coordTypeY = (word1 >> 29) & 1;\n\t\t\tuint32 coordTypeZ = (word1 >> 30) & 1;\n\t\t\tuint32 coordTypeW = (word1 >> 31) & 1;\n\t\t\tcemu_assert_debug(coordTypeX != GPU7_TEX_UNNORMALIZED);\n\t\t\tcemu_assert_debug(coordTypeY != GPU7_TEX_UNNORMALIZED);\n\t\t\tcemu_assert_debug(coordTypeZ != GPU7_TEX_UNNORMALIZED);\n\t\t\tcemu_assert_debug(coordTypeW != GPU7_TEX_UNNORMALIZED);\n\n\t\t\tuint32 srcSelX = (word2 >> 20) & 0x7;\n\t\t\tuint32 srcSelY = (word2 >> 23) & 0x7;\n\t\t\tuint32 srcSelZ = (word2 >> 26) & 0x7;\n\t\t\tuint32 srcSelW = (word2 >> 29) & 0x7;\n\n\t\t\tsint32 textureIndex = bufferId - 0x00;\n\t\t\t// create new tex instruction\n\t\t\tLatteDecompilerTEXInstruction texInstruction;\n\t\t\ttexInstruction.cfInstruction = cfInstruction;\n\t\t\ttexInstruction.opcode = inst0_4;\n\t\t\ttexInstruction.textureFetch.textureIndex = textureIndex;\n\t\t\ttexInstruction.textureFetch.samplerIndex = samplerId;\n\t\t\ttexInstruction.textureFetch.srcSel[0] = srcSelX;\n\t\t\ttexInstruction.textureFetch.srcSel[1] = srcSelY;\n\t\t\ttexInstruction.textureFetch.srcSel[2] = srcSelZ;\n\t\t\ttexInstruction.textureFetch.srcSel[3] = srcSelW;\n\t\t\ttexInstruction.srcGpr = srcGpr;\n\t\t\ttexInstruction.dstGpr = 0xFFFFFFFF;\n\t\t\tcfInstruction->instructionsTEX.emplace_back(texInstruction);\n\t\t}\n\t\telse if( inst0_4 == GPU7_TEX_INST_VFETCH )\n\t\t{\n\t\t\t// this uses the VTX_WORD* encoding\n\t\t\tuint32 fetchType = (word0>>5)&3;\n\t\t\tuint32 bufferId = (word0>>8)&0xFF;\n\t\t\tuint32 offset = (word2>>0)&0xFFFF;\n\t\t\tuint32 endianSwap = (word2>>16)&0x3;\n\t\t\tuint32 constNoStride = (word2>>18)&0x1;\n\t\t\tuint32 srcGpr = (word0>>16)&0x7F;\n\t\t\tuint32 srcRel = (word0>>23)&1;\n\t\t\tif( srcRel != 0 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 destGpr = (word1>>0)&0x7F;\n\t\t\tuint32 destRel = (word1>>7)&1;\n\t\t\tif( destRel != 0 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tuint32 dstSelX = (word1>>9)&0x7;\n\t\t\tuint32 dstSelY = (word1>>12)&0x7;\n\t\t\tuint32 dstSelZ = (word1>>15)&0x7;\n\t\t\tuint32 dstSelW = (word1>>18)&0x7;\n\n\t\t\tuint32 srcSelX = (word0>>24)&0x3;\n\t\t\tuint32 srcSelY = 0;\n\t\t\tuint32 srcSelZ = 0;\n\t\t\tuint32 srcSelW = 0;\n\n\t\t\t// create new tex instruction\n\t\t\tLatteDecompilerTEXInstruction texInstruction;\n\t\t\ttexInstruction.cfInstruction = cfInstruction;\n\t\t\ttexInstruction.opcode = inst0_4;\n\t\t\ttexInstruction.textureFetch.textureIndex = bufferId;\n\t\t\ttexInstruction.textureFetch.samplerIndex = 0;\n\t\t\ttexInstruction.textureFetch.offset = offset;\n\t\t\ttexInstruction.dstSel[0] = dstSelX;\n\t\t\ttexInstruction.dstSel[1] = dstSelY;\n\t\t\ttexInstruction.dstSel[2] = dstSelZ;\n\t\t\ttexInstruction.dstSel[3] = dstSelW;\n\t\t\ttexInstruction.textureFetch.srcSel[0] = srcSelX;\n\t\t\ttexInstruction.textureFetch.srcSel[1] = srcSelY;\n\t\t\ttexInstruction.textureFetch.srcSel[2] = srcSelZ;\n\t\t\ttexInstruction.textureFetch.srcSel[3] = srcSelW;\n\t\t\ttexInstruction.dstGpr = destGpr;\n\t\t\ttexInstruction.srcGpr = srcGpr;\n\t\t\tcfInstruction->instructionsTEX.emplace_back(texInstruction);\n\t\t}\n\t\telse if (inst0_4 == GPU7_TEX_INST_MEM)\n\t\t{\n\t\t\t// memory access\n\t\t\t// MEM_RD_WORD0\n\t\t\tuint32 elementSize = (word0 >> 5) & 3;\n\t\t\tuint32 memOp = (word0 >> 8) & 7;\n\t\t\tuint8 indexed = (word0 >> 12) & 1;\n\t\t\tuint32 srcGPR = (word0 >> 16) & 0x7F;\n\t\t\tuint8 srcREL = (word0 >> 23) & 1;\n\t\t\tuint8 srcSelX = (word0 >> 24) & 3;\n\t\t\t// MEM_RD_WORD1\n\t\t\tuint32 dstGPR = (word1 >> 0) & 0x7F;\n\t\t\tuint8 dstREL = (word1 >> 7) & 1;\n\t\t\tuint8 dstSelX = (word1 >> 9) & 7;\n\t\t\tuint8 dstSelY = (word1 >> 12) & 7;\n\t\t\tuint8 dstSelZ = (word1 >> 15) & 7;\n\t\t\tuint8 dstSelW = (word1 >> 18) & 7;\n\t\t\tuint8 dataFormat = (word1 >> 22) & 0x3F;\n\t\t\tuint8 nfa = (word1 >> 28) & 3;\n\t\t\tuint8 isSigned = (word1 >> 30) & 1;\n\t\t\tuint8 srfMode = (word1 >> 31) & 1;\n\t\t\t// MEM_RD_WORD2\n\t\t\tuint32 arrayBase = (word2 & 0x1FFF);\n\t\t\tuint8 endianSwap = (word2 >> 16) & 3;\n\t\t\tuint32 arraySize = (word2 >> 20) & 0xFFF;\n\t\t\tif (memOp == 2)\n\t\t\t{\n\t\t\t\t// read from scatter buffer (SSBO)\n\t\t\t\tLatteDecompilerTEXInstruction texInstruction;\n\t\t\t\ttexInstruction.cfInstruction = cfInstruction;\n\t\t\t\ttexInstruction.opcode = inst0_4;\n\n\t\t\t\tcemu_assert_debug(srcREL == 0 || dstREL == 0); // unsupported relative access\n\n\t\t\t\ttexInstruction.memRead.arrayBase = arrayBase;\n\t\t\t\ttexInstruction.srcGpr = srcGPR;\n\t\t\t\ttexInstruction.dstGpr = dstGPR;\n\t\t\t\ttexInstruction.memRead.srcSelX = srcSelX;\n\t\t\t\ttexInstruction.dstSel[0] = dstSelX;\n\t\t\t\ttexInstruction.dstSel[1] = dstSelY;\n\t\t\t\ttexInstruction.dstSel[2] = dstSelZ;\n\t\t\t\ttexInstruction.dstSel[3] = dstSelW;\n\n\t\t\t\ttexInstruction.memRead.format = dataFormat;\n\t\t\t\ttexInstruction.memRead.nfa = nfa;\n\t\t\t\ttexInstruction.memRead.isSigned = isSigned;\n\n\t\t\t\tcfInstruction->instructionsTEX.emplace_back(texInstruction);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported tex instruction {}\", inst0_4);\n\t\t\tshaderContext->hasError = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\tcemu_assert_debug(cfInstruction->instructionsALU.empty()); // clause may only contain texture instructions\n}\n\n// iterate all CF instructions and parse clause sub-instructions (if present)\nvoid LatteDecompiler_ParseClauses(LatteDecompilerShaderContext* decompilerContext, uint8* programData, uint32 programSize, std::vector<LatteDecompilerCFInstruction> &list_instructions)\n{\n\tLatteDecompilerShader* shader = decompilerContext->shader;\n\tfor (auto& cfInstruction : list_instructions)\n\t{\n\t\tif (cfInstruction.type == GPU7_CF_INST_ALU || cfInstruction.type == GPU7_CF_INST_ALU_PUSH_BEFORE || cfInstruction.type == GPU7_CF_INST_ALU_POP_AFTER || cfInstruction.type == GPU7_CF_INST_ALU_POP2_AFTER || cfInstruction.type == GPU7_CF_INST_ALU_BREAK || cfInstruction.type == GPU7_CF_INST_ALU_ELSE_AFTER)\n\t\t{\n\t\t\tLatteDecompiler_ParseALUClause(shader, &cfInstruction, programData, programSize);\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_TEX)\n\t\t{\n\t\t\tLatteDecompiler_ParseTEXClause(shader, &cfInstruction, programData, programSize);\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_EXPORT || cfInstruction.type == GPU7_CF_INST_EXPORT_DONE)\n\t\t{\n\t\t\t// no sub-instructions\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_ELSE || cfInstruction.type == GPU7_CF_INST_POP)\n\t\t{\n\t\t\t// no sub-instructions\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END ||\n\t\t\t\t cfInstruction.type == GPU7_CF_INST_LOOP_START_NO_AL)\n\t\t{\n\t\t\t// no sub-instructions\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_LOOP_BREAK)\n\t\t{\n\t\t\t// no sub-instructions\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_MEM_STREAM0_WRITE ||\n\t\t\tcfInstruction.type == GPU7_CF_INST_MEM_STREAM1_WRITE)\n\t\t{\n\t\t\t// no sub-instructions\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_MEM_RING_WRITE)\n\t\t{\n\t\t\t// no sub-instructions\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_CALL)\n\t\t{\n\t\t\t// no sub-instructions\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_RETURN)\n\t\t{\n\t\t\t// no sub-instructions\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_EMIT_VERTEX)\n\t\t{\n\t\t\t// no sub-instructions\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebug_printf(\"_parseClauses(): Unsupported clause 0x%x\\n\", cfInstruction.type);\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n}\n\n// iterate all CF instructions and parse sub-instructions\nvoid LatteDecompiler_ParseClauses(LatteDecompilerShaderContext* shaderContext, uint8* programData, uint32 programSize)\n{\n\tLatteDecompilerShader* shader = shaderContext->shader;\n\tLatteDecompiler_ParseClauses(shaderContext, programData, programSize, shaderContext->cfInstructions);\n\t// parse subroutines\n\tfor (auto& subroutineInfo : shaderContext->list_subroutines)\n\t{\n\t\tLatteDecompiler_ParseClauses(shaderContext, programData, programSize, subroutineInfo.instructions);\n\t}\n}\n\nvoid _LatteDecompiler_GenerateDataForFastAccess(LatteDecompilerShader* shader)\n{\n\tif (shader->hasError)\n\t\treturn;\n\tfor (size_t i = 0; i < shader->list_remappedUniformEntries.size(); i++)\n\t{\n\t\tLatteDecompilerRemappedUniformEntry_t* entry = shader->list_remappedUniformEntries.data() + i;\n\t\tif (entry->isRegister)\n\t\t{\n\t\t\tLatteFastAccessRemappedUniformEntry_register_t entryReg;\n\t\t\tentryReg.indexOffset = entry->index * 16;\n\t\t\tentryReg.mappedIndexOffset = entry->mappedIndex * 16;\n\t\t\tshader->list_remappedUniformEntries_register.push_back(entryReg);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tLatteFastAccessRemappedUniformEntry_buffer_t entryBuf;\n\t\t\tuint32 kcacheBankIdOffset = entry->kcacheBankId* (7 * 4);\n\t\t\tentryBuf.indexOffset = entry->index * 16;\n\t\t\tentryBuf.mappedIndexOffset = entry->mappedIndex * 16;\n\t\t\t// find or create buffer group\n\t\t\tauto bufferGroup = std::find_if(shader->list_remappedUniformEntries_bufferGroups.begin(), shader->list_remappedUniformEntries_bufferGroups.end(), [kcacheBankIdOffset](const LatteDecompilerShader::_RemappedUniformBufferGroup& v) { return v.kcacheBankIdOffset == kcacheBankIdOffset; });\n\t\t\tif (bufferGroup != shader->list_remappedUniformEntries_bufferGroups.end())\n\t\t\t{\n\t\t\t\t(*bufferGroup).entries.emplace_back(entryBuf);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tshader->list_remappedUniformEntries_bufferGroups.emplace_back(kcacheBankIdOffset).entries.emplace_back(entryBuf);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid _LatteDecompiler_Process(LatteDecompilerShaderContext* shaderContext, uint8* programData, uint32 programSize)\n{\n\t// parse control flow instructions\n\tif (shaderContext->shader->hasError == false)\n\t\tLatteDecompiler_ParseCF(shaderContext, programData, programSize);\n\t// parse individual clauses\n\tif (shaderContext->shader->hasError == false)\n\t\tLatteDecompiler_ParseClauses(shaderContext, programData, programSize);\n\t// analyze\n\tif (shaderContext->shader->hasError == false)\n\t\tLatteDecompiler_analyze(shaderContext, shaderContext->shader);\n\tif (shaderContext->shader->hasError == false)\n\t\tLatteDecompiler_analyzeDataTypes(shaderContext);\n\t// emit code\n\tif (shaderContext->shader->hasError == false)\n\t{\n\t    if (g_renderer->GetType() == RendererAPI::OpenGL || g_renderer->GetType() == RendererAPI::Vulkan)\n\t        LatteDecompiler_emitGLSLShader(shaderContext, shaderContext->shader);\n#if ENABLE_METAL\n\t\telse\n\t\t    LatteDecompiler_emitMSLShader(shaderContext, shaderContext->shader);\n#endif\n\t}\n\tLatteDecompiler_cleanup(shaderContext);\n\t// fast access\n\t_LatteDecompiler_GenerateDataForFastAccess(shaderContext->shader);\n}\n\nvoid LatteDecompiler_InitContext(LatteDecompilerShaderContext& dCtx, const LatteDecompilerOptions& options, LatteDecompilerOutput_t* output, LatteConst::ShaderType shaderType, uint64 shaderBaseHash, uint32* contextRegisters)\n{\n\tdCtx.output = output;\n\tdCtx.shaderType = shaderType;\n\tdCtx.options = &options;\n\tdCtx.shaderBaseHash = shaderBaseHash;\n\tdCtx.contextRegisters = contextRegisters;\n\tdCtx.contextRegistersNew = (LatteContextRegister*)contextRegisters;\n\toutput->shaderType = shaderType;\n}\n\nvoid LatteDecompiler_DecompileVertexShader(uint64 shaderBaseHash, uint32* contextRegisters, uint8* programData, uint32 programSize, struct LatteFetchShader* fetchShader, LatteDecompilerOptions& options, LatteDecompilerOutput_t* output)\n{\n\tcemu_assert_debug(fetchShader);\n\tcemu_assert_debug((programSize & 3) == 0);\n\tperformanceMonitor.gpuTime_shaderCreate.beginMeasuring();\n\t// prepare decompiler context\n\tLatteDecompilerShaderContext shaderContext = { 0 };\n\tLatteDecompiler_InitContext(shaderContext, options, output, LatteConst::ShaderType::Vertex, shaderBaseHash, contextRegisters);\n\tshaderContext.fetchShader = fetchShader;\n\t// prepare shader (deprecated)\n\tLatteDecompilerShader* shader = new LatteDecompilerShader(LatteConst::ShaderType::Vertex);\n\tshader->compatibleFetchShader = shaderContext.fetchShader;\n\toutput->shaderType = LatteConst::ShaderType::Vertex;\n\tshaderContext.shader = shader;\n\toutput->shader = shader;\n\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t{\n\t\tshader->textureUnitSamplerAssignment[i] = LATTE_DECOMPILER_SAMPLER_NONE;\n\t\tshader->textureUsesDepthCompare[i] = false;\n\t}\n\t// parse & compile\n\t_LatteDecompiler_Process(&shaderContext, programData, programSize);\n\tperformanceMonitor.gpuTime_shaderCreate.endMeasuring();\n}\n\nvoid LatteDecompiler_DecompileGeometryShader(uint64 shaderBaseHash, uint32* contextRegisters, uint8* programData, uint32 programSize, uint8* gsCopyProgramData, uint32 gsCopyProgramSize, uint32 vsRingParameterCount, LatteDecompilerOptions& options, LatteDecompilerOutput_t* output)\n{\n\tcemu_assert_debug((programSize & 3) == 0);\n\tperformanceMonitor.gpuTime_shaderCreate.beginMeasuring();\n\t// prepare decompiler context\n\tLatteDecompilerShaderContext shaderContext = { 0 };\n\tLatteDecompiler_InitContext(shaderContext, options, output, LatteConst::ShaderType::Geometry, shaderBaseHash, contextRegisters);\n\t// prepare shader\n\tLatteDecompilerShader* shader = new LatteDecompilerShader(LatteConst::ShaderType::Geometry);\n\tshader->ringParameterCountFromPrevStage = vsRingParameterCount;\n\toutput->shaderType = LatteConst::ShaderType::Geometry;\n\tshaderContext.shader = shader;\n\toutput->shader = shader;\n\tif (gsCopyProgramData == NULL)\n\t{\n\t\tshader->hasError = true;\n\t}\n\telse\n\t{\n\t\tshaderContext.parsedGSCopyShader = LatteGSCopyShaderParser_parse(gsCopyProgramData, gsCopyProgramSize);\n\t}\n\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t{\n\t\tshader->textureUnitSamplerAssignment[i] = LATTE_DECOMPILER_SAMPLER_NONE;\n\t\tshader->textureUsesDepthCompare[i] = false;\n\t}\n\t// parse & compile\n\t_LatteDecompiler_Process(&shaderContext, programData, programSize);\n\tperformanceMonitor.gpuTime_shaderCreate.endMeasuring();\n}\n\nvoid LatteDecompiler_DecompilePixelShader(uint64 shaderBaseHash, uint32* contextRegisters, uint8* programData, uint32 programSize, LatteDecompilerOptions& options, LatteDecompilerOutput_t* output)\n{\n\tcemu_assert_debug((programSize & 3) == 0);\n\tperformanceMonitor.gpuTime_shaderCreate.beginMeasuring();\n\t// prepare decompiler context\n\tLatteDecompilerShaderContext shaderContext = { 0 };\n\tLatteDecompiler_InitContext(shaderContext, options, output, LatteConst::ShaderType::Pixel, shaderBaseHash, contextRegisters);\n\tshaderContext.contextRegisters = contextRegisters;\n\t// prepare shader\n\tLatteDecompilerShader* shader = new LatteDecompilerShader(LatteConst::ShaderType::Pixel);\n\toutput->shaderType = LatteConst::ShaderType::Pixel;\n\tshaderContext.shader = shader;\n\toutput->shader = shader;\n\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t{\n\t\tshader->textureUnitSamplerAssignment[i] = LATTE_DECOMPILER_SAMPLER_NONE;\n\t\tshader->textureUsesDepthCompare[i] = false;\n\t}\n\t// parse & compile\n\t_LatteDecompiler_Process(&shaderContext, programData, programSize);\n\tperformanceMonitor.gpuTime_shaderCreate.endMeasuring();\n}\n\nvoid LatteDecompiler_cleanup(LatteDecompilerShaderContext* shaderContext)\n{\n\tshaderContext->cfInstructions.clear();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Renderer/RendererShader.h\"\n#include <boost/container/static_vector.hpp>\n\nnamespace LatteDecompiler\n{\n\tenum class DataType\n\t{\n\t\tUNDEFINED = 0,\n\t\tU32 = 0,\n\t\tS32 = 0,\n\t\tFLOAT = 0\n\t};\n};\n\n// decompiler shader types\n\ntypedef struct\n{\n\tbool\tisRegister; // if true -> Uniform register, if false -> Uniform buffer\n\tuint8\tkcacheBankId; // uniform buffer id (if uniform buffer)\n\tuint32\tindex; // uniform address (in 4-DWORD tuples)\n\tuint32\tmappedIndex; // index in remapped uniform array\n}LatteDecompilerRemappedUniformEntry_t;\n\ntypedef struct\n{\n\tuint32\tindexOffset; // uniform address (in 4-DWORD tuples)\n\tuint32\tmappedIndexOffset; // index in remapped uniform array\n}LatteFastAccessRemappedUniformEntry_register_t;\n\ntypedef struct\n{\n\tuint16\tindexOffset; // uniform address (in 4-DWORD tuples)\n\tuint16\tmappedIndexOffset; // index in remapped uniform array\n}LatteFastAccessRemappedUniformEntry_buffer_t;\n\ntypedef struct\n{\n\tuint32 texUnit;\n\tsint32 uniformLocation;\n\tfloat currentValue[2];\n}LatteUniformTextureScaleEntry_t;\n\nstruct LatteDecompilerShaderResourceMapping\n{\n\tLatteDecompilerShaderResourceMapping()\n\t{\n\t\tstd::fill(textureUnitToBindingPoint, textureUnitToBindingPoint + LATTE_NUM_MAX_TEX_UNITS, -1);\n\t\tstd::fill(uniformBuffersBindingPoint, uniformBuffersBindingPoint + LATTE_NUM_MAX_UNIFORM_BUFFERS, -1);\n\t\tstd::fill(attributeMapping, attributeMapping + LATTE_NUM_MAX_ATTRIBUTE_LOCATIONS, -1);\n\t}\n\tstatic const sint8 UNUSED_BINDING = -1;\n\t// most of this is for Vulkan\n\tsint8 setIndex{};\n\t// texture\n\tsint8 textureUnitToBindingPoint[LATTE_NUM_MAX_TEX_UNITS];\n\t// uniform buffer\n\tsint8 uniformVarsBufferBindingPoint{-1}; // special block for uniform registers/remapped array/custom variables\n\tsint8 uniformBuffersBindingPoint[LATTE_NUM_MAX_UNIFORM_BUFFERS];\n\t// shader storage buffer for transform feedback (if alternative mode is used)\n\tsint8 tfStorageBindingPoint{-1};\n\t// attributes (vertex shader only)\n\tsint8 attributeMapping[LATTE_NUM_MAX_ATTRIBUTE_LOCATIONS];\n\t// Metal exclusive\n\tsint8 verticesPerInstanceBinding{-1};\n\tsint8 indexBufferBinding{-1};\n\tsint8 indexTypeBinding{-1};\n\n\tsint32 getTextureCount()\n\t{\n\t\tsint32 count = 0;\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t\t{\n\t\t\tif (textureUnitToBindingPoint[i] >= 0)\n\t\t\t\tcount++;\n\t\t}\n\t\treturn count;\n\t}\n\n\tsint32 getTextureUnitFromBindingPoint(sint8 bindingPoint)\n\t{\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t\t{\n\t\t\tif (textureUnitToBindingPoint[i] == bindingPoint)\n\t\t\t\treturn i;\n\t\t}\n\n\t\tcemu_assert_debug(false);\n\t\treturn -1;\n\t}\n\n\t// returns -1 if no there is no texture binding point\n\tsint32 getTextureBaseBindingPoint()\n\t{\n\t\tsint32 bindingPoint = 9999;\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t\t{\n\t\t\tif (textureUnitToBindingPoint[i] >= 0)\n\t\t\t\tbindingPoint = std::min(bindingPoint, (sint32)textureUnitToBindingPoint[i]);\n\t\t}\n\t\tif (bindingPoint == 9999)\n\t\t\treturn -1;\n\t\treturn bindingPoint;\n\t}\n\n\tbool getUniformBufferBindingRange(sint32& minBinding, sint32& maxBinding)\n\t{\n\t\tsint32 minBindingPoint = 9999;\n\t\tsint32 maxBindingPoint = -9999;\n\t\tif (uniformVarsBufferBindingPoint >= 0)\n\t\t{\n\t\t\tminBindingPoint = std::min(minBindingPoint, (sint32)uniformVarsBufferBindingPoint);\n\t\t\tmaxBindingPoint = std::max(maxBindingPoint, (sint32)uniformVarsBufferBindingPoint);\n\t\t}\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t\t{\n\t\t\tif (uniformBuffersBindingPoint[i] >= 0)\n\t\t\t{\n\t\t\t\tminBindingPoint = std::min(minBindingPoint, (sint32)uniformBuffersBindingPoint[i]);\n\t\t\t\tmaxBindingPoint = std::max(maxBindingPoint, (sint32)uniformBuffersBindingPoint[i]);\n\t\t\t}\n\t\t}\n\t\tif (minBindingPoint == 9999)\n\t\t\treturn false;\n\t\tminBinding = minBindingPoint;\n\t\tmaxBinding = maxBindingPoint;\n\t\treturn true;\n\t}\n\n\tsint32 getTFStorageBufferBindingPoint()\n\t{\n\t\treturn tfStorageBindingPoint;\n\t}\n\n\tbool hasUniformBuffers()\n\t{\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t\t{\n\t\t\tif (uniformBuffersBindingPoint[i] >= 0)\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tsint32 getAttribHostShaderIndex(uint32 semanticId)\n\t{\n\t\tcemu_assert_debug(semanticId < 0x100);\n\t\treturn attributeMapping[semanticId];\n\t}\n};\n\nstruct LatteDecompilerShader\n{\n\tLatteDecompilerShader(LatteConst::ShaderType shaderType) : shaderType(shaderType) {}\n\n\tLatteDecompilerShader* next{nullptr};\n\tLatteConst::ShaderType shaderType;\n\tuint64 baseHash{0};\n\tuint64 auxHash{0};\n\t// vertex shader\n\tstruct LatteFetchShader* compatibleFetchShader{};\n\t// error tracking\n\tbool hasError{false}; // if set, the shader cannot be used\n\t// compact resource lists for optimized access\n\tstruct QuickBufferEntry\n\t{\n\t\tuint32 index : 8;\n\t\tuint32 size : 24;\n\t};\n\tboost::container::static_vector<QuickBufferEntry, LATTE_NUM_MAX_UNIFORM_BUFFERS> list_quickBufferList;\n\tuint8 textureUnitList[LATTE_NUM_MAX_TEX_UNITS];\n\tuint8 textureUnitListCount{ 0 };\n\t// input\n\tLatte::E_DIM textureUnitDim[LATTE_NUM_MAX_TEX_UNITS]{}; // dimension of texture unit, from the currently set texture\n\tbool textureIsIntegerFormat[LATTE_NUM_MAX_TEX_UNITS]{};\n\t// analyzer stage (uniforms)\n\tuint8 uniformMode{0}; // determines how uniforms are managed within the shader (see LATTE_DECOMPILER_UNIFORM_MODE_* constants)\n\tuint64 uniformDataHash64[2]{0}; // used to avoid redundant calls to glUniform*\n\tstd::vector<LatteDecompilerRemappedUniformEntry_t> list_remappedUniformEntries;\n\t// analyzer stage (textures)\n\tstd::bitset<LATTE_NUM_MAX_TEX_UNITS> textureUnitMask2;\n\tuint16 textureUnitSamplerAssignment[LATTE_NUM_MAX_TEX_UNITS]{ 0 }; // LATTE_DECOMPILER_SAMPLER_NONE means undefined\n\tbool textureUsesDepthCompare[LATTE_NUM_MAX_TEX_UNITS]{};\n\tuint8 textureRenderTargetIndex[LATTE_NUM_MAX_TEX_UNITS];\n\n\t// analyzer stage (pixel outputs)\n\tuint32 pixelColorOutputMask{ 0 }; // from LSB to MSB, 1 bit per written output. 1 if written (indices of color attachments)\n\t// analyzer stage (depth output)\n\tbool depthMask{ false };\n\t// analyzer stage (geometry shader parameters/inputs)\n\tuint32 ringParameterCount{ 0 };\n\tuint32 ringParameterCountFromPrevStage{ 0 }; // used in geometry shader to hold VS ringParameterCount\n\t// analyzer stage (misc)\n\tstd::bitset<LATTE_NUM_STREAMOUT_BUFFER> streamoutBufferWriteMask;\n\tbool hasStreamoutBufferWrite{ false };\n\t// output code\n\tclass StringBuf* strBuf_shaderSource{ nullptr };\n\t// separable shaders\n\tRendererShader* shader{ nullptr };\n\tbool isCustomShader{ false };\n\n\tuint32 outputParameterMask{ 0 };\n\t// resource mapping (binding points)\n\tLatteDecompilerShaderResourceMapping resourceMapping{};\n\t// uniforms\n\tstruct\n\t{\n\t\tsint32 loc_remapped; // uf_remappedVS/uf_remappedGS/uf_remappedPS\n\t\tsint32 loc_uniformRegister; // uf_uniformRegisterVS/uf_uniformRegisterGS/uf_uniformRegisterPS\n\t\tsint32 count_uniformRegister;\n\t\tsint32 loc_windowSpaceToClipSpaceTransform; // uf_windowSpaceToClipSpaceTransform\n\t\tsint32 loc_alphaTestRef; // uf_alphaTestRef\n\t\tsint32 loc_pointSize; // uf_pointSize\n\t\tsint32 loc_fragCoordScale;\n\t\tstd::vector<LatteUniformTextureScaleEntry_t> list_ufTexRescale; // list of mappings for uf_tex*Scale <-> uniform location\n\t\tfloat ufCurrentValueAlphaTestRef;\n\t\tfloat ufCurrentValueFragCoordScale[2];\n\t\tsint32 loc_verticesPerInstance;\n\t\tsint32 loc_streamoutBufferBase[LATTE_NUM_STREAMOUT_BUFFER];\n\t\tuint32 uniformRangeSize; // entire size of uniform variable block\n\t}uniform{ 0 };\n\t// fast access\n\tstruct _RemappedUniformBufferGroup\n\t{\n\t\t_RemappedUniformBufferGroup(uint32 _kcacheBankIdOffset) : kcacheBankIdOffset(_kcacheBankIdOffset) {};\n\n\t\tuint32 kcacheBankIdOffset;\n\t\tstd::vector<LatteFastAccessRemappedUniformEntry_buffer_t> entries;\n\t};\n\tstd::vector<LatteFastAccessRemappedUniformEntry_register_t>\tlist_remappedUniformEntries_register;\n\tstd::vector<_RemappedUniformBufferGroup> list_remappedUniformEntries_bufferGroups;\n};\n\nstruct LatteDecompilerOutputUniformOffsets\n{\n\tsint32 offset_remapped;\n\tsint32 offset_uniformRegister;\n\tsint32 count_uniformRegister; // in vec4\n\tsint32 offset_alphaTestRef;\n\tsint32 offset_pointSize;\n\tsint32 offset_fragCoordScale;\n\tsint32 offset_windowSpaceToClipSpaceTransform;\n\tsint32 offset_texScale[LATTE_NUM_MAX_TEX_UNITS];\n\tsint32 offset_verticesPerInstance{-1};\n\tsint32 offset_streamoutBufferBase[LATTE_NUM_STREAMOUT_BUFFER]{ -1, -1, -1, -1 };\n\tsint32 offset_endOfBlock; // stores size of uniform variable block\n\n\tLatteDecompilerOutputUniformOffsets()\n\t{\n\t\toffset_remapped = -1;\n\t\toffset_uniformRegister = -1;\n\t\tcount_uniformRegister = 0;\n\t\toffset_alphaTestRef = -1;\n\t\toffset_pointSize = -1;\n\t\toffset_fragCoordScale = -1;\n\t\toffset_windowSpaceToClipSpaceTransform = -1;\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t\t\toffset_texScale[i] = -1;\n\t\toffset_endOfBlock = 0;\n\t}\n};\n\nstruct LatteDecompilerOptions\n{\n\tbool usesGeometryShader{ false };\n\t// floating point math\n\tbool strictMul{}; // if true, 0*anything=0 rule is emulated\n\t// Vulkan-specific\n\tbool useTFViaSSBO{ false };\n\tstruct\n\t{\n\t\tbool hasRoundingModeRTEFloat32{ false };\n\t}spirvInstrinsics;\n};\n\nstruct LatteDecompilerOutput_t\n{\n\tLatteDecompilerShader* shader;\n\tLatteConst::ShaderType shaderType;\n\n\t// texture info\n\tstd::bitset<LATTE_NUM_MAX_TEX_UNITS> textureUnitMask;\n\n\t// streamout info\n\tstd::bitset<LATTE_NUM_STREAMOUT_BUFFER> streamoutBufferWriteMask;\n\tuint32 streamoutBufferStride[LATTE_NUM_STREAMOUT_BUFFER]{};\n\n\t// uniform locations\n\tLatteDecompilerOutputUniformOffsets uniformOffsetsGL;\n\tLatteDecompilerOutputUniformOffsets uniformOffsetsVK;\n\t// mapping and binding information\n\tLatteDecompilerShaderResourceMapping resourceMappingGL;\n\tLatteDecompilerShaderResourceMapping resourceMappingVK;\n\tLatteDecompilerShaderResourceMapping resourceMappingMTL;\n};\n\nstruct LatteDecompilerSubroutineInfo;\n\nvoid LatteDecompiler_DecompileVertexShader(uint64 shaderBaseHash, uint32* contextRegisters, uint8* programData, uint32 programSize, struct LatteFetchShader* fetchShader, LatteDecompilerOptions& options, LatteDecompilerOutput_t* output);\nvoid LatteDecompiler_DecompileGeometryShader(uint64 shaderBaseHash, uint32* contextRegisters, uint8* programData, uint32 programSize, uint8* gsCopyProgramData, uint32 gsCopyProgramSize, uint32 vsRingParameterCount, LatteDecompilerOptions& options, LatteDecompilerOutput_t* output);\nvoid LatteDecompiler_DecompilePixelShader(uint64 shaderBaseHash, uint32* contextRegisters, uint8* programData, uint32 programSize, LatteDecompilerOptions& options, LatteDecompilerOutput_t* output);\n\n// specialized shader parsers\n\n#define GPU7_COPY_SHADER_MAX_PARAMS\t(32)\n\nstruct LatteGSCopyShaderStreamWrite_t\n{\n\tuint8 bufferIndex;\n\tuint16 offset; // offset in ring buffer from GS\n\tuint32 exportArrayBase;\n\tuint32 memWriteArraySize;\n\tuint32 memWriteCompMask;\n};\n\nstruct LatteParsedGSCopyShader\n{\n\tstruct\n\t{\n\t\tuint16 offset;\n\t\tuint16 gprIndex;\n\t\tuint8  exportType;\n\t\tuint8  exportParam;\n\t}paramMapping[GPU7_COPY_SHADER_MAX_PARAMS];\n\tsint32 numParam;\n\t// streamout writes\n\tstd::vector<LatteGSCopyShaderStreamWrite_t> list_streamWrites;\n};\n\nLatteParsedGSCopyShader* LatteGSCopyShaderParser_parse(uint8* programData, uint32 programSize);\nbool LatteGSCopyShaderParser_getExportTypeByOffset(LatteParsedGSCopyShader* shaderContext, uint32 offset, uint32* exportType, uint32* exportParam);\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Common/MemPtr.h\"\n#include \"HW/Latte/ISA/LatteReg.h\"\n#if ENABLE_METAL\n#include \"HW/Latte/Renderer/Metal/MetalCommon.h\"\n#endif\n\n// Defined in LatteTextureLegacy.cpp\nLatte::E_GX2SURFFMT LatteTexture_ReconstructGX2Format(const Latte::LATTE_SQ_TEX_RESOURCE_WORD1_N& texUnitWord1, const Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N& texUnitWord4);\n\n/*\n * Return index of used color attachment based on shader pixel export index (0-7)\n */\nsint32 LatteDecompiler_getColorOutputIndexFromExportIndex(LatteDecompilerShaderContext* shaderContext, sint32 exportIndex)\n{\n\tsint32 colorOutputIndex = -1;\n\tsint32 outputCounter = 0;\n\tuint32 cbShaderMask = shaderContext->contextRegisters[mmCB_SHADER_MASK];\n\tuint32 cbShaderControl = shaderContext->contextRegisters[mmCB_SHADER_CONTROL];\n\tfor(sint32 m=0; m<8; m++)\n\t{\n\t\tuint32 outputMask = (cbShaderMask>>(m*4))&0xF;\n\t\tif( outputMask == 0 )\n\t\t\tcontinue;\n\t\tcemu_assert_debug(outputMask == 0xF); // mask is unsupported\n\t\tif( outputCounter == exportIndex )\n\t\t{\n\t\t\tcolorOutputIndex = m;\n\t\t\tbreak;\n\t\t}\n\t\toutputCounter++;\n\t}\n\tcemu_assert_debug(colorOutputIndex != -1); // real outputs and outputs defined via mask do not match up\n\treturn colorOutputIndex;\n}\n\nvoid _remapUniformAccess(LatteDecompilerShaderContext* shaderContext, bool isRegisterUniform, uint32 kcacheBankId, uint32 uniformIndex)\n{\n\tauto& list_uniformMapping = shaderContext->shader->list_remappedUniformEntries;\n\tfor(uint32 i=0; i<list_uniformMapping.size(); i++)\n\t{\n\t\tLatteDecompilerRemappedUniformEntry_t* ufMapping = list_uniformMapping.data()+i;\n\t\tif( isRegisterUniform )\n\t\t{\n\t\t\tif( ufMapping->isRegister == true && ufMapping->index == uniformIndex )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif( ufMapping->isRegister == false && ufMapping->kcacheBankId == kcacheBankId && ufMapping->index == uniformIndex )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\t// add new mapping\n\tLatteDecompilerRemappedUniformEntry_t newMapping = {0};\n\tif( isRegisterUniform )\n\t{\n\t\tnewMapping.isRegister = true;\n\t\tnewMapping.index = uniformIndex;\n\t\tnewMapping.mappedIndex = (uint32)list_uniformMapping.size();\n\t}\n\telse\n\t{\n\t\tnewMapping.isRegister = false;\n\t\tnewMapping.kcacheBankId = kcacheBankId;\n\t\tnewMapping.index = uniformIndex;\n\t\tnewMapping.mappedIndex = (uint32)list_uniformMapping.size();\n\t}\n\tlist_uniformMapping.emplace_back(newMapping);\n}\n\n/*\n * Returns true if the instruction takes integer operands or returns a integer value\n */\nbool _isIntegerInstruction(const LatteDecompilerALUInstruction& aluInstruction)\n{\n\tif (aluInstruction.isOP3 == false)\n\t{\n\t\t// OP2\n\t\tswitch (aluInstruction.opcode)\n\t\t{\n\t\tcase ALU_OP2_INST_ADD:\n\t\tcase ALU_OP2_INST_MUL:\n\t\tcase ALU_OP2_INST_MUL_IEEE:\n\t\tcase ALU_OP2_INST_MAX:\n\t\tcase ALU_OP2_INST_MIN:\n\t\tcase ALU_OP2_INST_FLOOR:\n\t\tcase ALU_OP2_INST_FRACT:\n\t\tcase ALU_OP2_INST_TRUNC:\n\t\tcase ALU_OP2_INST_MOV:\n\t\tcase ALU_OP2_INST_NOP:\n\t\tcase ALU_OP2_INST_DOT4:\n\t\tcase ALU_OP2_INST_DOT4_IEEE:\n\t\tcase ALU_OP2_INST_CUBE:\n\t\tcase ALU_OP2_INST_EXP_IEEE:\n\t\tcase ALU_OP2_INST_LOG_CLAMPED:\n\t\tcase ALU_OP2_INST_LOG_IEEE:\n\t\tcase ALU_OP2_INST_SQRT_IEEE:\n\t\tcase ALU_OP2_INST_SIN:\n\t\tcase ALU_OP2_INST_COS:\n\t\tcase ALU_OP2_INST_RNDNE:\n\t\tcase ALU_OP2_INST_MAX_DX10:\n\t\tcase ALU_OP2_INST_MIN_DX10:\n\t\tcase ALU_OP2_INST_SETGT:\n\t\tcase ALU_OP2_INST_SETGE:\n\t\tcase ALU_OP2_INST_SETNE:\n\t\tcase ALU_OP2_INST_SETE:\n\t\tcase ALU_OP2_INST_PRED_SETE:\n\t\tcase ALU_OP2_INST_PRED_SETGT:\n\t\tcase ALU_OP2_INST_PRED_SETGE:\n\t\tcase ALU_OP2_INST_PRED_SETNE:\n\t\tcase ALU_OP2_INST_KILLE:\n\t\tcase ALU_OP2_INST_KILLGT:\n\t\tcase ALU_OP2_INST_KILLGE:\n\t\tcase ALU_OP2_INST_RECIP_FF:\n\t\tcase ALU_OP2_INST_RECIP_IEEE:\n\t\tcase ALU_OP2_INST_RECIPSQRT_CLAMPED:\n\t\tcase ALU_OP2_INST_RECIPSQRT_FF:\n\t\tcase ALU_OP2_INST_RECIPSQRT_IEEE:\n\t\t\treturn false;\n\t\tcase ALU_OP2_INST_FLT_TO_INT:\n\t\tcase ALU_OP2_INST_INT_TO_FLOAT:\n\t\tcase ALU_OP2_INST_UINT_TO_FLOAT:\n\t\tcase ALU_OP2_INST_ASHR_INT:\n\t\tcase ALU_OP2_INST_LSHR_INT:\n\t\tcase ALU_OP2_INST_LSHL_INT:\n\t\tcase ALU_OP2_INST_MULLO_INT:\n\t\tcase ALU_OP2_INST_MULLO_UINT:\n\t\tcase ALU_OP2_INST_FLT_TO_UINT:\n\t\tcase ALU_OP2_INST_AND_INT:\n\t\tcase ALU_OP2_INST_OR_INT:\n\t\tcase ALU_OP2_INST_XOR_INT:\n\t\tcase ALU_OP2_INST_NOT_INT:\n\t\tcase ALU_OP2_INST_ADD_INT:\n\t\tcase ALU_OP2_INST_SUB_INT:\n\t\tcase ALU_OP2_INST_MAX_INT:\n\t\tcase ALU_OP2_INST_MIN_INT:\n\t\tcase ALU_OP2_INST_MAX_UINT:\n\t\tcase ALU_OP2_INST_MIN_UINT:\n\t\tcase ALU_OP2_INST_SETE_INT:\n\t\tcase ALU_OP2_INST_SETGT_INT:\n\t\tcase ALU_OP2_INST_SETGE_INT:\n\t\tcase ALU_OP2_INST_SETNE_INT:\n\t\tcase ALU_OP2_INST_SETGT_UINT:\n\t\tcase ALU_OP2_INST_SETGE_UINT:\n\t\tcase ALU_OP2_INST_PRED_SETE_INT:\n\t\tcase ALU_OP2_INST_PRED_SETGT_INT:\n\t\tcase ALU_OP2_INST_PRED_SETGE_INT:\n\t\tcase ALU_OP2_INST_PRED_SETNE_INT:\n\t\tcase ALU_OP2_INST_KILLE_INT:\n\t\tcase ALU_OP2_INST_KILLGT_INT:\n\t\tcase ALU_OP2_INST_KILLNE_INT:\n\t\tcase ALU_OP2_INST_MOVA_FLOOR:\n\t\tcase ALU_OP2_INST_MOVA_INT:\n\t\t\treturn true;\n\t\t// these return an integer result but are usually used only for conditionals\n\t\tcase ALU_OP2_INST_SETE_DX10:\n\t\tcase ALU_OP2_INST_SETGT_DX10:\n\t\tcase ALU_OP2_INST_SETGE_DX10:\n\t\tcase ALU_OP2_INST_SETNE_DX10:\n\t\t\treturn true;\n\t\tdefault:\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tdebug_printf(\"_isIntegerInstruction(): OP3=%s opcode=%02x\\n\", aluInstruction.isOP3 ? \"true\" : \"false\", aluInstruction.opcode);\n\t\t\tcemu_assert_debug(false);\n#endif\n\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// OP3\n\t\tswitch (aluInstruction.opcode)\n\t\t{\n\t\tcase ALU_OP3_INST_MULADD:\n\t\tcase ALU_OP3_INST_MULADD_D2:\n\t\tcase ALU_OP3_INST_MULADD_M2:\n\t\tcase ALU_OP3_INST_MULADD_M4:\n\t\tcase ALU_OP3_INST_MULADD_IEEE:\n\t\tcase ALU_OP3_INST_CMOVE:\n\t\tcase ALU_OP3_INST_CMOVGT:\n\t\tcase ALU_OP3_INST_CMOVGE:\n\t\t\treturn false;\n\t\tcase ALU_OP3_INST_CNDE_INT:\n\t\tcase ALU_OP3_INST_CNDGT_INT:\n\t\tcase ALU_OP3_INST_CMOVGE_INT:\n\t\t\treturn true;\n\t\tdefault:\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tdebug_printf(\"_isIntegerInstruction(): OP3=%s opcode=%02x\\n\", aluInstruction.isOP3?\"true\":\"false\", aluInstruction.opcode);\n#endif\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn false;\n}\n\n/*\n * Analyze ALU CF instruction and all instructions within the ALU clause\n */\nvoid LatteDecompiler_analyzeALUClause(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\t// check if this shader has any clause that potentially modifies the pixel execution state\n\tif( cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE || cfInstruction->type == GPU7_CF_INST_ALU_POP_AFTER || cfInstruction->type == GPU7_CF_INST_ALU_POP2_AFTER || cfInstruction->type == GPU7_CF_INST_ALU_BREAK || cfInstruction->type == GPU7_CF_INST_ALU_ELSE_AFTER )\n\t{\n\t\tshaderContext->analyzer.modifiesPixelActiveState = true;\n\t}\n\t// analyze ALU instructions\n\tfor(auto& aluInstruction : cfInstruction->instructionsALU)\n\t{\n\t\t// ignore NOP instruction\n\t\tif( !aluInstruction.isOP3 && aluInstruction.opcode == ALU_OP2_INST_NOP )\n\t\t\tcontinue;\n\t\t// check for CUBE instruction\n\t\tif( !aluInstruction.isOP3 && aluInstruction.opcode == ALU_OP2_INST_CUBE )\n\t\t{\n\t\t\tshaderContext->analyzer.hasRedcCUBE = true;\n\t\t}\n\t\t// check for integer instruction\n\t\tif (_isIntegerInstruction(aluInstruction))\n\t\t\tshaderContext->analyzer.usesIntegerValues = true;\n\t\t// process all available operands (inputs)\n\t\tfor(sint32 f=0; f<3; f++)\n\t\t{\n\t\t\t// check input for uniform access\n\t\t\tif( aluInstruction.sourceOperand[f].sel == 0xFFFFFFFF )\n\t\t\t\tcontinue; // source operand not set/used\n\t\t\t// about uniform register and buffer access tracking:\n\t\t\t// for absolute indices we can determine a maximum size that is accessed\n\t\t\t// relative accesses are tricky because the upper bound of accessed indices is unknown\n\t\t\t// worst case we have to load the full file (256 * 16 byte entries) or for buffers an arbitrary upper bound (64KB in our case)\n\t\t\tif( GPU7_ALU_SRC_IS_CFILE(aluInstruction.sourceOperand[f].sel) )\n\t\t\t{\n\t\t\t\tif (aluInstruction.sourceOperand[f].rel)\n\t\t\t\t{\n\t\t\t\t\tshaderContext->analyzer.uniformRegisterAccessTracker.TrackAccess(GPU7_ALU_SRC_GET_CFILE_INDEX(aluInstruction.sourceOperand[f].sel), true);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_remapUniformAccess(shaderContext, true, 0, GPU7_ALU_SRC_GET_CFILE_INDEX(aluInstruction.sourceOperand[f].sel));\n\t\t\t\t\tshaderContext->analyzer.uniformRegisterAccessTracker.TrackAccess(GPU7_ALU_SRC_GET_CFILE_INDEX(aluInstruction.sourceOperand[f].sel), false);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( GPU7_ALU_SRC_IS_CBANK0(aluInstruction.sourceOperand[f].sel) )\n\t\t\t{\n\t\t\t\t// uniform bank 0 (uniform buffer with index cfInstruction->cBank0Index)\n\t\t\t\tuint32 uniformBufferIndex = cfInstruction->cBank0Index;\n\t\t\t\tcemu_assert(uniformBufferIndex < LATTE_NUM_MAX_UNIFORM_BUFFERS);\n\t\t\t\tuint32 offset = GPU7_ALU_SRC_GET_CBANK0_INDEX(aluInstruction.sourceOperand[f].sel)+cfInstruction->cBank0AddrBase;\n\t\t\t\t_remapUniformAccess(shaderContext, false, uniformBufferIndex, offset);\n\t\t\t\tshaderContext->analyzer.uniformBufferAccessTracker[uniformBufferIndex].TrackAccess(offset, aluInstruction.sourceOperand[f].rel);\n\t\t\t}\n\t\t\telse if( GPU7_ALU_SRC_IS_CBANK1(aluInstruction.sourceOperand[f].sel) )\n\t\t\t{\n\t\t\t\t// uniform bank 1 (uniform buffer with index cfInstruction->cBank1Index)\n\t\t\t\tuint32 uniformBufferIndex = cfInstruction->cBank1Index;\n\t\t\t\tcemu_assert(uniformBufferIndex < LATTE_NUM_MAX_UNIFORM_BUFFERS);\n\t\t\t\tuint32 offset = GPU7_ALU_SRC_GET_CBANK1_INDEX(aluInstruction.sourceOperand[f].sel)+cfInstruction->cBank1AddrBase;\n\t\t\t\t_remapUniformAccess(shaderContext, false, uniformBufferIndex, offset);\n\t\t\t\tshaderContext->analyzer.uniformBufferAccessTracker[uniformBufferIndex].TrackAccess(offset, aluInstruction.sourceOperand[f].rel);\n\t\t\t}\n\t\t\telse if( GPU7_ALU_SRC_IS_GPR(aluInstruction.sourceOperand[f].sel) )\n\t\t\t{\n\t\t\t\tsint32 gprIndex = GPU7_ALU_SRC_GET_GPR_INDEX(aluInstruction.sourceOperand[f].sel);\n\t\t\t\tshaderContext->analyzer.gprUseMask[gprIndex/8] |= (1<<(gprIndex%8));\n\t\t\t\tif( aluInstruction.sourceOperand[f].rel != 0 )\n\t\t\t\t{\n\t\t\t\t\t// if indexed register access is used, all possibly referenced registers are stored to a separate array at the beginning of the group\n\t\t\t\t\tshaderContext->analyzer.usesRelativeGPRRead = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\tif( aluInstruction.destRel != 0 )\n\t\t\tshaderContext->analyzer.usesRelativeGPRWrite = true;\n\t\tshaderContext->analyzer.gprUseMask[aluInstruction.destGpr/8] |= (1<<(aluInstruction.destGpr%8));\n\t}\n}\n\n// analyze TEX CF instruction and all instructions within the TEX clause\nvoid LatteDecompiler_analyzeTEXClause(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tLatteDecompilerShader* shader = shaderContext->shader;\n\tfor(auto& texInstruction : cfInstruction->instructionsTEX)\n\t{\n\t\tif( texInstruction.opcode == GPU7_TEX_INST_SAMPLE ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_SAMPLE_L ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_SAMPLE_LB ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_SAMPLE_LZ ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_SAMPLE_C ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_SAMPLE_C_L ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_SAMPLE_C_LZ ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_FETCH4 ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_SAMPLE_G ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_LD )\n\t\t{\n\t\t\tif (texInstruction.textureFetch.textureIndex < 0 || texInstruction.textureFetch.textureIndex >= LATTE_NUM_MAX_TEX_UNITS)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Shader {:16x} has out of bounds texture access (texture {})\", shaderContext->shader->baseHash, (sint32)texInstruction.textureFetch.textureIndex);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif( texInstruction.textureFetch.samplerIndex < 0 || texInstruction.textureFetch.samplerIndex >= 0x12 )\n\t\t\t\tcemu_assert_debug(false);\n\t\t\tif(shaderContext->output->textureUnitMask[texInstruction.textureFetch.textureIndex] && shader->textureUnitSamplerAssignment[texInstruction.textureFetch.textureIndex] != texInstruction.textureFetch.samplerIndex && shader->textureUnitSamplerAssignment[texInstruction.textureFetch.textureIndex] != LATTE_DECOMPILER_SAMPLER_NONE )\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t\tshaderContext->output->textureUnitMask[texInstruction.textureFetch.textureIndex] = true;\n\t\t\tshader->textureUnitSamplerAssignment[texInstruction.textureFetch.textureIndex] = texInstruction.textureFetch.samplerIndex;\n\t\t\tif( texInstruction.opcode == GPU7_TEX_INST_SAMPLE_C || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_C_L || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_C_LZ)\n\t\t\t\tshader->textureUsesDepthCompare[texInstruction.textureFetch.textureIndex] = true;\n\n\t\t\tbool useTexelCoords = false;\n\t\t\tif (texInstruction.opcode == GPU7_TEX_INST_SAMPLE && (texInstruction.textureFetch.unnormalized[0] && texInstruction.textureFetch.unnormalized[1] && texInstruction.textureFetch.unnormalized[2] && texInstruction.textureFetch.unnormalized[3]))\n\t\t\t\tuseTexelCoords = true;\n\t\t\telse if (texInstruction.opcode == GPU7_TEX_INST_LD)\n\t\t\t\tuseTexelCoords = true;\n\t\t\tif (useTexelCoords)\n\t\t\t{\n\t\t\t\tshaderContext->analyzer.texUnitUsesTexelCoordinates.set(texInstruction.textureFetch.textureIndex);\n\t\t\t}\n\t\t}\n\t\telse if( texInstruction.opcode == GPU7_TEX_INST_GET_COMP_TEX_LOD || texInstruction.opcode == GPU7_TEX_INST_GET_TEXTURE_RESINFO )\n\t\t{\n\t\t\tif( texInstruction.textureFetch.textureIndex < 0 || texInstruction.textureFetch.textureIndex >= LATTE_NUM_MAX_TEX_UNITS )\n\t\t\t\tdebugBreakpoint();\n\t\t\tif( texInstruction.textureFetch.samplerIndex != 0 )\n\t\t\t\tdebugBreakpoint(); // sampler is ignored and should be 0\n\t\t\tshaderContext->output->textureUnitMask[texInstruction.textureFetch.textureIndex] = true;\n\t\t}\n\t\telse if( texInstruction.opcode == GPU7_TEX_INST_SET_CUBEMAP_INDEX )\n\t\t{\n\t\t\t// no analysis required\n\t\t}\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_GET_GRADIENTS_H || texInstruction.opcode == GPU7_TEX_INST_GET_GRADIENTS_V)\n\t\t{\n\t\t\t// no analysis required\n\t\t}\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_SET_GRADIENTS_H || texInstruction.opcode == GPU7_TEX_INST_SET_GRADIENTS_V)\n\t\t{\n\t\t\tshaderContext->analyzer.hasGradientLookup = true;\n\t\t}\n\t\telse if( texInstruction.opcode == GPU7_TEX_INST_VFETCH )\n\t\t{\n\t\t\t// VFETCH is used to access uniform buffers dynamically\n\t\t\tif( texInstruction.textureFetch.textureIndex >= 0x80 && texInstruction.textureFetch.textureIndex <= 0x8F )\n\t\t\t{\n\t\t\t\tuint32 uniformBufferIndex = texInstruction.textureFetch.textureIndex - 0x80;\n\t\t\t\tshaderContext->analyzer.uniformBufferAccessTracker[uniformBufferIndex].TrackAccess(0, true);\n\t\t\t}\n\t\t\telse if( texInstruction.textureFetch.textureIndex == 0x9F && shader->shaderType == LatteConst::ShaderType::Geometry )\n\t\t\t{\n\t\t\t\t// instruction to read geometry shader input from ringbuffer\n\t\t\t}\n\t\t\telse\n\t\t\t\tdebugBreakpoint();\n\t\t}\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_MEM)\n\t\t{\n\t\t\t// SSBO access\n\t\t\tshaderContext->analyzer.hasSSBORead = true;\n\t\t}\n\t\telse\n\t\t\tdebugBreakpoint();\n\t\t// mark read and written registers as used\n\t\tif(texInstruction.dstGpr < LATTE_NUM_GPR)\n\t\t\tshaderContext->analyzer.gprUseMask[texInstruction.dstGpr/8] |= (1<<(texInstruction.dstGpr%8));\n\t\tif(texInstruction.srcGpr < LATTE_NUM_GPR)\n\t\t\tshaderContext->analyzer.gprUseMask[texInstruction.srcGpr/8] |= (1<<(texInstruction.srcGpr%8));\n\t}\n}\n\n/*\n * Analyze export CF instruction\n */\nvoid LatteDecompiler_analyzeExport(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tLatteDecompilerShader* shader = shaderContext->shader;\n\tif( shader->shaderType == LatteConst::ShaderType::Pixel )\n\t{\n\t\tif (cfInstruction->exportType == 0 && cfInstruction->exportArrayBase < 8)\n\t\t{\n\t\t\t// remember color outputs that are written\n\t\t\tfor(uint32 i=0; i<(cfInstruction->exportBurstCount+1); i++)\n\t\t\t{\n\t\t\t\tsint32 colorOutputIndex = LatteDecompiler_getColorOutputIndexFromExportIndex(shaderContext, cfInstruction->exportArrayBase+i);\n\t\t\t\tshader->pixelColorOutputMask |= (1<<colorOutputIndex);\n\t\t\t}\n\t\t}\n\t\telse if (cfInstruction->exportType == 0 && cfInstruction->exportArrayBase == 61)\n\t\t{\n#if ENABLE_METAL\n\t\t\t// Only check for depth buffer mask on Metal, as its not in the PS hash on other backends\n\t\t\tif (g_renderer->GetType() != RendererAPI::Metal || LatteMRT::GetActiveDepthBufferMask(*shaderContext->contextRegistersNew))\n\t\t\t\tshader->depthMask = true;\n#endif\n\t\t}\n\t\telse\n\t\t\tdebugBreakpoint();\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n\t\tif (cfInstruction->exportType == 2 && cfInstruction->exportArrayBase < 32)\n\t\t{\n\t\t\tshaderContext->shader->outputParameterMask |= (1<<cfInstruction->exportArrayBase);\n\t\t}\n\t\telse if (cfInstruction->exportType == 1 && cfInstruction->exportArrayBase == GPU7_DECOMPILER_CF_EXPORT_POINT_SIZE)\n\t\t{\n\t\t\tshaderContext->analyzer.writesPointSize = true;\n\t\t}\n\t}\n\t// mark input GPRs as used\n\tfor(uint32 i=0; i<(cfInstruction->exportBurstCount+1); i++)\n\t{\n\t\tshaderContext->analyzer.gprUseMask[(cfInstruction->exportSourceGPR+i)/8] |= (1<<((cfInstruction->exportSourceGPR+i)%8));\n\t}\n}\n\nvoid LatteDecompiler_analyzeSubroutine(LatteDecompilerShaderContext* shaderContext, uint32 cfAddr)\n{\n\t// analyze CF and clauses up to RET statement\n\n\t// todo - find cfInstruction index from cfAddr\n\tcemu_assert_debug(false);\n\n\tfor(auto& cfInstruction : shaderContext->cfInstructions)\n\t{\n\t\tif (cfInstruction.type == GPU7_CF_INST_ALU || cfInstruction.type == GPU7_CF_INST_ALU_PUSH_BEFORE || cfInstruction.type == GPU7_CF_INST_ALU_POP_AFTER || cfInstruction.type == GPU7_CF_INST_ALU_POP2_AFTER || cfInstruction.type == GPU7_CF_INST_ALU_BREAK || cfInstruction.type == GPU7_CF_INST_ALU_ELSE_AFTER)\n\t\t{\n\t\t\tLatteDecompiler_analyzeALUClause(shaderContext, &cfInstruction);\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_TEX)\n\t\t{\n\t\t\tLatteDecompiler_analyzeTEXClause(shaderContext, &cfInstruction);\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_EXPORT || cfInstruction.type == GPU7_CF_INST_EXPORT_DONE)\n\t\t{\n\t\t\tLatteDecompiler_analyzeExport(shaderContext, &cfInstruction);\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_ELSE || cfInstruction.type == GPU7_CF_INST_POP)\n\t\t{\n\t\t\tshaderContext->analyzer.modifiesPixelActiveState = true;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END ||\n\t\t\t\t cfInstruction.type == GPU7_CF_INST_LOOP_START_NO_AL)\n\t\t{\n\t\t\tshaderContext->analyzer.modifiesPixelActiveState = true;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_LOOP_BREAK)\n\t\t{\n\t\t\tshaderContext->analyzer.modifiesPixelActiveState = true;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_EMIT_VERTEX)\n\t\t{\n\t\t\t// nothing to analyze\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_CALL)\n\t\t{\n\t\t\tcemu_assert_debug(false); // CALLs inside subroutines are still todo\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n}\n\nnamespace LatteDecompiler\n{\n\tvoid _initTextureBindingPointsGL(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\t// for OpenGL we use the relative texture unit index\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t\t{\n\t\t\tif (!decompilerContext->output->textureUnitMask[i])\n\t\t\t\tcontinue;\n\t\t\tsint32 textureBindingPoint;\n\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t\ttextureBindingPoint = i + LATTE_CEMU_VS_TEX_UNIT_BASE;\n\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t\ttextureBindingPoint = i + LATTE_CEMU_GS_TEX_UNIT_BASE;\n\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t\t\ttextureBindingPoint = i + LATTE_CEMU_PS_TEX_UNIT_BASE;\n\n\t\t\tdecompilerContext->output->resourceMappingGL.textureUnitToBindingPoint[i] = textureBindingPoint;\n\t\t}\n\t}\n\n\tvoid _initTextureBindingPointsVK(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\t// for Vulkan we use consecutive indices\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t\t{\n\t\t\tif (!decompilerContext->output->textureUnitMask[i])\n\t\t\t\tcontinue;\n\t\t\tdecompilerContext->output->resourceMappingVK.textureUnitToBindingPoint[i] = decompilerContext->currentBindingPointVK;\n\t\t\tdecompilerContext->currentBindingPointVK++;\n\t\t}\n\t}\n\n#if ENABLE_METAL\n\tvoid _initTextureBindingPointsMTL(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\t// for Vulkan we use consecutive indices\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t\t{\n\t\t\tif (!decompilerContext->output->textureUnitMask[i] || decompilerContext->shader->textureRenderTargetIndex[i] != 255)\n\t\t\t\tcontinue;\n\t\t\tdecompilerContext->output->resourceMappingMTL.textureUnitToBindingPoint[i] = decompilerContext->currentTextureBindingPointMTL;\n\t\t\tdecompilerContext->currentTextureBindingPointMTL++;\n\t\t}\n\t}\n#endif\n\n\tvoid _initHasUniformVarBlock(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\tdecompilerContext->hasUniformVarBlock = false;\n\t\tif (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED)\n\t\t\tdecompilerContext->hasUniformVarBlock = true;\n\t\telse if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE)\n\t\t\tdecompilerContext->hasUniformVarBlock = true;\n\n\t\tbool hasAnyViewportScaleDisabled =\n\t\t\t!decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_X_SCALE_ENA() ||\n\t\t\t!decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Y_SCALE_ENA() ||\n\t\t\t!decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Z_SCALE_ENA();\n\t\t// we currently only support all on/off. Individual component scaling is not supported\n\t\tcemu_assert_debug(decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_X_SCALE_ENA() == !hasAnyViewportScaleDisabled);\n\t\tcemu_assert_debug(decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Y_SCALE_ENA() == !hasAnyViewportScaleDisabled);\n\t\tcemu_assert_debug(decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Z_SCALE_ENA() == !hasAnyViewportScaleDisabled);\n\t\tcemu_assert_debug(decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_X_OFFSET_ENA() == !hasAnyViewportScaleDisabled);\n\t\tcemu_assert_debug(decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Y_OFFSET_ENA() == !hasAnyViewportScaleDisabled);\n\t\tcemu_assert_debug(decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Z_OFFSET_ENA() == !hasAnyViewportScaleDisabled);\n\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && hasAnyViewportScaleDisabled)\n\t\t\tdecompilerContext->hasUniformVarBlock = true; // uf_windowSpaceToClipSpaceTransform\n\t\tbool alphaTestEnable = decompilerContext->contextRegistersNew->SX_ALPHA_TEST_CONTROL.get_ALPHA_TEST_ENABLE();\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Pixel && alphaTestEnable != 0)\n\t\t\tdecompilerContext->hasUniformVarBlock = true; // uf_alphaTestRef\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t\tdecompilerContext->hasUniformVarBlock = true; // uf_fragCoordScale\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && decompilerContext->analyzer.outputPointSize && decompilerContext->analyzer.writesPointSize == false)\n\t\t\tdecompilerContext->hasUniformVarBlock = true; // uf_pointSize\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Geometry && decompilerContext->analyzer.outputPointSize && decompilerContext->analyzer.writesPointSize == false)\n\t\t\tdecompilerContext->hasUniformVarBlock = true; // uf_pointSize\n\t\tif (decompilerContext->analyzer.useSSBOForStreamout &&\n\t\t\t(decompilerContext->shaderType == LatteConst::ShaderType::Vertex && !decompilerContext->options->usesGeometryShader) ||\n\t\t\t(decompilerContext->shaderType == LatteConst::ShaderType::Geometry))\n\t\t{\n\t\t\tdecompilerContext->hasUniformVarBlock = true; // uf_verticesPerInstance and uf_streamoutBufferBase*\n\t\t}\n#if ENABLE_METAL\n\t\tif (g_renderer->GetType() == RendererAPI::Metal)\n\t\t{\n            bool usesGeometryShader = UseGeometryShader(*decompilerContext->contextRegistersNew, decompilerContext->options->usesGeometryShader);\n\n\t\t    if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && usesGeometryShader)\n\t\t\t\tdecompilerContext->hasUniformVarBlock = true; // uf_verticesPerInstance\n\t\t}\n#endif\n\t}\n\n\tvoid _initUniformBindingPoints(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\t// check if uniform vars block has at least one variable\n\t\t_initHasUniformVarBlock(decompilerContext);\n\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t{\n\t\t\tfor (sint32 t = 0; t < LATTE_NUM_MAX_TEX_UNITS; t++)\n\t\t\t{\n\t\t\t\tif (decompilerContext->analyzer.texUnitUsesTexelCoordinates.test(t) == false)\n\t\t\t\t\tcontinue;\n\t\t\t\tdecompilerContext->hasUniformVarBlock = true; // uf_tex%dScale\n\t\t\t}\n\t\t}\n\t\t// assign binding point to uniform var block\n\t\tif (decompilerContext->hasUniformVarBlock)\n\t\t{\n\t\t\tdecompilerContext->output->resourceMappingVK.uniformVarsBufferBindingPoint = decompilerContext->currentBindingPointVK;\n\t\t\tdecompilerContext->currentBindingPointVK++;\n\t\t\tdecompilerContext->output->resourceMappingMTL.uniformVarsBufferBindingPoint = decompilerContext->currentBufferBindingPointMTL;\n\t\t\tdecompilerContext->currentBufferBindingPointMTL++;\n\t\t}\n\t\t// assign binding points to uniform buffers\n\t\tif (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)\n\t\t{\n\t\t\t// for Vulkan we use consecutive indices\n\t\t\tfor (uint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t\t\t{\n\t\t\t\tif (!decompilerContext->analyzer.uniformBufferAccessTracker[i].HasAccess())\n\t\t\t\t\tcontinue;\n\t\t\t\tsint32 uniformBindingPoint = i;\n\t\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t\t\tuniformBindingPoint += 64;\n\t\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t\t\tuniformBindingPoint += 0;\n\t\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t\t\t\tuniformBindingPoint += 32;\n\n\t\t\t\tdecompilerContext->output->resourceMappingVK.uniformBuffersBindingPoint[i] = decompilerContext->currentBindingPointVK;\n\t\t\t\tdecompilerContext->currentBindingPointVK++;\n\t\t\t\tdecompilerContext->output->resourceMappingMTL.uniformBuffersBindingPoint[i] = decompilerContext->currentBufferBindingPointMTL;\n\t\t\t\tdecompilerContext->currentBufferBindingPointMTL++;\n\t\t\t}\n\t\t\t// for OpenGL we use the relative buffer index\n\t\t\tfor (uint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t\t\t{\n\t\t\t\tif (!decompilerContext->analyzer.uniformBufferAccessTracker[i].HasAccess())\n\t\t\t\t\tcontinue;\n\t\t\t\tsint32 uniformBindingPoint = i;\n\t\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t\t\tuniformBindingPoint += 64;\n\t\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t\t\tuniformBindingPoint += 0;\n\t\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t\t\t\tuniformBindingPoint += 32;\n\t\t\t\tdecompilerContext->output->resourceMappingGL.uniformBuffersBindingPoint[i] = uniformBindingPoint;\n\t\t\t}\n\t\t}\n\t\t// shader storage buffer for alternative transform feedback path\n\t\tif (decompilerContext->analyzer.useSSBOForStreamout)\n\t\t{\n\t\t\tdecompilerContext->output->resourceMappingVK.tfStorageBindingPoint = decompilerContext->currentBindingPointVK;\n\t\t\tdecompilerContext->currentBindingPointVK++;\n\t\t\tdecompilerContext->output->resourceMappingMTL.tfStorageBindingPoint = decompilerContext->currentBufferBindingPointMTL;\n\t\t\tdecompilerContext->currentBufferBindingPointMTL++;\n\t\t}\n\t}\n\n\tvoid _initAttributeBindingPoints(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\tif (decompilerContext->shaderType != LatteConst::ShaderType::Vertex)\n\t\t\treturn;\n\t\t// create input attribute binding mapping\n\t\t// OpenGL and Vulkan use consecutive indices starting at 0\n\t\tsint8 bindingIndex = 0;\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_ATTRIBUTE_LOCATIONS; i++)\n\t\t{\n\t\t\tif (decompilerContext->analyzer.inputAttributSemanticMask[i])\n\t\t\t{\n\t\t\t\tdecompilerContext->output->resourceMappingGL.attributeMapping[i] = bindingIndex;\n\t\t\t\tdecompilerContext->output->resourceMappingVK.attributeMapping[i] = bindingIndex;\n\t\t\t\tdecompilerContext->output->resourceMappingMTL.attributeMapping[i] = bindingIndex;\n\t\t\t\tbindingIndex++;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n/*\n * Analyze the shader program\n * This will help to determine:\n * 1) Uniform usage\n * 2) Texture usage\n * 3) Data types\n * 4) CF stack and execution flow\n */\nvoid LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader)\n{\n\t// analyze render state\n\tshaderContext->analyzer.isPointsPrimitive = shaderContext->contextRegistersNew->VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE() == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::POINTS;\n\tshaderContext->analyzer.hasStreamoutEnable = shaderContext->contextRegisters[mmVGT_STRMOUT_EN] != 0; // set if the shader is used for transform feedback operations\n\tif (shaderContext->shaderType == LatteConst::ShaderType::Vertex && !shaderContext->options->usesGeometryShader)\n\t\tshaderContext->analyzer.outputPointSize = shaderContext->analyzer.isPointsPrimitive;\n\telse if (shaderContext->shaderType == LatteConst::ShaderType::Geometry)\n\t{\n\t\tuint32 gsOutPrimType = shaderContext->contextRegisters[mmVGT_GS_OUT_PRIM_TYPE];\n\t\tif (gsOutPrimType == 0) // points\n\t\t\tshaderContext->analyzer.outputPointSize = true;\n\t}\n\t// analyze input attributes for vertex/geometry shader\n\tif (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry)\n\t{\n\t\tif(shaderContext->fetchShader)\n\t\t{\n\t\t\tLatteFetchShader* parsedFetchShader = shaderContext->fetchShader;\n\t\t\tfor(auto& bufferGroup : parsedFetchShader->bufferGroups)\n\t\t\t{\n\t\t\t\tfor (sint32 i = 0; i < bufferGroup.attribCount; i++)\n\t\t\t\t{\n\t\t\t\t\tuint8 semanticId = bufferGroup.attrib[i].semanticId;\n\t\t\t\t\tif (semanticId == 0xFF)\n\t\t\t\t\t{\n\t\t\t\t\t\t// unused attribute? Found in Hot Wheels: World's best driver\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tcemu_assert_debug(semanticId < 0x80);\n\t\t\t\t\tshaderContext->analyzer.inputAttributSemanticMask[semanticId] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// list of subroutines (call destinations)\n\tstd::vector<uint32> list_subroutineAddrs;\n\t// analyze CF and clauses\n\tfor(auto& cfInstruction : shaderContext->cfInstructions)\n\t{\n\t\tif (cfInstruction.type == GPU7_CF_INST_ALU || cfInstruction.type == GPU7_CF_INST_ALU_PUSH_BEFORE || cfInstruction.type == GPU7_CF_INST_ALU_POP_AFTER || cfInstruction.type == GPU7_CF_INST_ALU_POP2_AFTER || cfInstruction.type == GPU7_CF_INST_ALU_BREAK || cfInstruction.type == GPU7_CF_INST_ALU_ELSE_AFTER)\n\t\t{\n\t\t\tLatteDecompiler_analyzeALUClause(shaderContext, &cfInstruction);\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_TEX)\n\t\t{\n\t\t\tLatteDecompiler_analyzeTEXClause(shaderContext, &cfInstruction);\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_EXPORT || cfInstruction.type == GPU7_CF_INST_EXPORT_DONE)\n\t\t{\n\t\t\tLatteDecompiler_analyzeExport(shaderContext, &cfInstruction);\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_ELSE || cfInstruction.type == GPU7_CF_INST_POP)\n\t\t{\n\t\t\tshaderContext->analyzer.modifiesPixelActiveState = true;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END ||\n\t\t\t\t cfInstruction.type == GPU7_CF_INST_LOOP_START_NO_AL)\n\t\t{\n\t\t\tshaderContext->analyzer.modifiesPixelActiveState = true;\n\t\t\tshaderContext->analyzer.hasLoops = true;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_LOOP_BREAK)\n\t\t{\n\t\t\tshaderContext->analyzer.modifiesPixelActiveState = true;\n\t\t\tshaderContext->analyzer.hasLoops = true;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_MEM_STREAM0_WRITE ||\n\t\t\tcfInstruction.type == GPU7_CF_INST_MEM_STREAM1_WRITE)\n\t\t{\n\t\t\tuint32 streamoutBufferIndex;\n\t\t\tif (cfInstruction.type == GPU7_CF_INST_MEM_STREAM0_WRITE)\n\t\t\t\tstreamoutBufferIndex = 0;\n\t\t\telse if (cfInstruction.type == GPU7_CF_INST_MEM_STREAM1_WRITE)\n\t\t\t\tstreamoutBufferIndex = 1;\n\t\t\telse\n\t\t\t\tcemu_assert_debug(false);\n\t\t\tshaderContext->analyzer.hasStreamoutWrite = true;\n\t\t\tcemu_assert(streamoutBufferIndex < shaderContext->output->streamoutBufferWriteMask.size());\n\t\t\tshaderContext->output->streamoutBufferWriteMask[streamoutBufferIndex] = true;\n\t\t\tuint32 vectorWriteSize = 0;\n\t\t\tfor (sint32 f = 0; f < 4; f++)\n\t\t\t{\n\t\t\t\tif ((cfInstruction.memWriteCompMask & (1 << f)) != 0)\n\t\t\t\t\tvectorWriteSize = (f + 1) * 4;\n\t\t\t\tshaderContext->output->streamoutBufferStride[f] = shaderContext->contextRegisters[mmVGT_STRMOUT_VTX_STRIDE_0 + f * 4] << 2;\n\t\t\t}\n\n\t\t\tcemu_assert_debug((cfInstruction.exportArrayBase * 4 + vectorWriteSize) <= shaderContext->output->streamoutBufferStride[streamoutBufferIndex]);\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_MEM_RING_WRITE)\n\t\t{\n\t\t\t// track number of parameters that are output (simplified by just tracking the offset of the last one)\n\t\t\tif (cfInstruction.memWriteElemSize != 3)\n\t\t\t\tdebugBreakpoint();\n\t\t\tif (cfInstruction.exportBurstCount != 0 && cfInstruction.memWriteElemSize != 3)\n\t\t\t{\n\t\t\t\tdebugBreakpoint();\n\t\t\t}\n\t\t\tuint32 dwordWriteCount = (cfInstruction.exportBurstCount + 1) * 4;\n\t\t\tuint32 numRingParameter = (cfInstruction.exportArrayBase + dwordWriteCount) / 4;\n\t\t\tshader->ringParameterCount = std::max(shader->ringParameterCount, numRingParameter);\n\t\t\t// mark input GPRs as used\n\t\t\tfor (uint32 i = 0; i < (cfInstruction.exportBurstCount + 1); i++)\n\t\t\t{\n\t\t\t\tshaderContext->analyzer.gprUseMask[(cfInstruction.exportSourceGPR + i) / 8] |= (1 << ((cfInstruction.exportSourceGPR + i) % 8));\n\t\t\t}\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_EMIT_VERTEX)\n\t\t{\n\t\t\tshaderContext->analyzer.numEmitVertex++;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_CALL)\n\t\t{\n\t\t\t// CALL instruction does not need analyzing\n\t\t\t// and subroutines are analyzed separately\n\t\t}\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\t// analyze subroutines\n\tfor (auto subroutineAddr : list_subroutineAddrs)\n\t{\n\t\tLatteDecompiler_analyzeSubroutine(shaderContext, subroutineAddr);\n\t}\n\t// decide which uniform mode to use\n\tbool hasAnyDynamicBufferAccess = false;\n\tbool hasAnyBufferAccess = false;\n\tfor(auto& it : shaderContext->analyzer.uniformBufferAccessTracker)\n\t{\n\t\tif( it.HasRelativeAccess() )\n\t\t\thasAnyDynamicBufferAccess = true;\n\t\tif( it.HasAccess() )\n\t\t\thasAnyBufferAccess = true;\n\t}\n\tif (hasAnyDynamicBufferAccess)\n\t{\n\t\tshader->uniformMode = LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK;\n\t}\n\telse if(shaderContext->analyzer.uniformRegisterAccessTracker.HasRelativeAccess() )\n\t{\n\t\tshader->uniformMode = LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE;\n\t}\n\telse if(hasAnyBufferAccess || shaderContext->analyzer.uniformRegisterAccessTracker.HasAccess() )\n\t{\n\t\tshader->uniformMode = LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED;\n\t}\n\telse\n\t{\n\t\tshader->uniformMode = LATTE_DECOMPILER_UNIFORM_MODE_NONE;\n\t}\n\t// generate compact list of uniform buffers (for faster access)\n\tcemu_assert_debug(shader->list_quickBufferList.empty());\n\tfor (uint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t{\n\t\tif( !shaderContext->analyzer.uniformBufferAccessTracker[i].HasAccess() )\n\t\t\tcontinue;\n\t\tLatteDecompilerShader::QuickBufferEntry entry;\n\t\tentry.index = i;\n\t\tentry.size = shaderContext->analyzer.uniformBufferAccessTracker[i].DetermineSize(shaderContext->shaderBaseHash, LATTE_GLSL_DYNAMIC_UNIFORM_BLOCK_SIZE) * 16;\n\t\tshader->list_quickBufferList.push_back(entry);\n\t}\n\t// get dimension of each used texture\n\t_LatteRegisterSetTextureUnit* texRegs = nullptr;\n\tif( shader->shaderType == LatteConst::ShaderType::Vertex )\n\t\ttexRegs = shaderContext->contextRegistersNew->SQ_TEX_START_VS;\n\telse if( shader->shaderType == LatteConst::ShaderType::Pixel )\n\t\ttexRegs = shaderContext->contextRegistersNew->SQ_TEX_START_PS;\n\telse if( shader->shaderType == LatteConst::ShaderType::Geometry )\n\t\ttexRegs = shaderContext->contextRegistersNew->SQ_TEX_START_GS;\n\n\tfor(sint32 i=0; i<LATTE_NUM_MAX_TEX_UNITS; i++)\n\t{\n\t\tif (!shaderContext->output->textureUnitMask[i])\n\t\t{\n\t\t\t// texture unit not used\n\t\t\tshader->textureUnitDim[i] = (Latte::E_DIM)0xFF;\n\t\t\tcontinue;\n\t\t}\n\t\tauto& texUnit = texRegs[i];\n\t\tauto dim = texUnit.word0.get_DIM();\n\t\tshader->textureUnitDim[i] = dim;\n\t\tif(dim == Latte::E_DIM::DIM_CUBEMAP)\n\t\t\tshaderContext->analyzer.hasCubeMapTexture = true;\n\t\tshader->textureIsIntegerFormat[i] = texUnit.word4.get_NUM_FORM_ALL() == Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N::E_NUM_FORMAT_ALL::NUM_FORMAT_INT;\n\t}\n\t// generate list of used texture units\n\tshader->textureUnitListCount = 0;\n\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t{\n\t\tif (shaderContext->output->textureUnitMask[i])\n\t\t{\n\t\t\tshader->textureUnitList[shader->textureUnitListCount] = i;\n\t\t\tshader->textureUnitListCount++;\n\t\t}\n\t\tshader->textureRenderTargetIndex[i] = 255;\n\t}\n\t// check if textures are used as render targets\n\tif (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t{\n\t\tstruct {\n\t\t    sint32 index;\n\t\t    MPTR physAddr;\n\t\t\tLatte::E_GX2SURFFMT format;\n\t\t\tLatte::E_HWTILEMODE tileMode;\n\t\t} colorBuffers[LATTE_NUM_COLOR_TARGET]{};\n\n        uint8 colorBufferMask = LatteMRT::GetActiveColorBufferMask(shader, *shaderContext->contextRegistersNew);\n        sint32 colorBufferCount = 0;\n\t\tfor (sint32 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)\n        {\n            auto& colorBuffer = colorBuffers[colorBufferCount];\n            if (((colorBufferMask) & (1 << i)) == 0)\n                continue; // color buffer not enabled\n\n            uint32* colorBufferRegBase = shaderContext->contextRegisters + (mmCB_COLOR0_BASE + i);\n           \tuint32 regColorBufferBase = colorBufferRegBase[mmCB_COLOR0_BASE - mmCB_COLOR0_BASE] & 0xFFFFFF00; // the low 8 bits are ignored? How to Survive seems to rely on this\n\n            uint32 regColorInfo = colorBufferRegBase[mmCB_COLOR0_INFO - mmCB_COLOR0_BASE];\n\n           \tMPTR colorBufferPhysMem = regColorBufferBase;\n            Latte::E_HWTILEMODE colorBufferTileMode = (Latte::E_HWTILEMODE)((regColorInfo >> 8) & 0xF);\n\n            Latte::E_GX2SURFFMT colorBufferFormat = LatteMRT::GetColorBufferFormat(i, *shaderContext->contextRegistersNew);\n\n            colorBuffer = {i, colorBufferPhysMem, colorBufferFormat, colorBufferTileMode};\n            colorBufferCount++;\n        }\n\n\t    for (sint32 i = 0; i < shader->textureUnitListCount; i++)\n        {\n            sint32 textureIndex = shader->textureUnitList[i];\n      \t\tconst auto& texRegister = texRegs[textureIndex];\n\n      \t\t// get physical address of texture data\n      \t\tMPTR physAddr = (texRegister.word2.get_BASE_ADDRESS() << 8);\n      \t\tif (physAddr == MPTR_NULL)\n                continue; // invalid data\n\n            auto tileMode = texRegister.word0.get_TILE_MODE();\n\n            // Check for dimension\n            auto dim = shader->textureUnitDim[textureIndex];\n            // TODO: 2D arrays could be supported as well\n            if (dim != Latte::E_DIM::DIM_2D)\n                continue;\n\n            // Check for mip level\n            auto lastMip = texRegister.word5.get_LAST_LEVEL();\n            // TODO: multiple mip levels could be supported as well\n            if (lastMip != 0)\n                continue;\n\n            Latte::E_GX2SURFFMT format = LatteTexture_ReconstructGX2Format(texRegister.word1, texRegister.word4);\n\n            // Check if the texture is used as render target\n            for (sint32 j = 0; j < colorBufferCount; j++)\n            {\n                const auto& colorBuffer = colorBuffers[j];\n\n                if (physAddr == colorBuffer.physAddr && format == colorBuffer.format && tileMode == colorBuffer.tileMode)\n                {\n                    shader->textureRenderTargetIndex[textureIndex] = colorBuffer.index;\n                    break;\n                }\n            }\n        }\n\t}\n\t// for geometry shaders check the copy shader for stream writes\n\tif (shader->shaderType == LatteConst::ShaderType::Geometry && shaderContext->parsedGSCopyShader->list_streamWrites.empty() == false)\n\t{\n\t\tshaderContext->analyzer.hasStreamoutWrite = true;\n\t\tif (shaderContext->contextRegisters[mmVGT_STRMOUT_EN] != 0)\n\t\t\tshaderContext->analyzer.hasStreamoutEnable = true;\n\t\tfor (auto& it : shaderContext->parsedGSCopyShader->list_streamWrites)\n\t\t{\n\t\t\tshaderContext->output->streamoutBufferWriteMask[it.bufferIndex] = true;\n\t\t\tuint32 vectorWriteSize = 0;\n\t\t\tfor (sint32 f = 0; f < 4; f++)\n\t\t\t{\n\t\t\t\tif ((it.memWriteCompMask&(1 << f)) != 0)\n\t\t\t\t\tvectorWriteSize = (f + 1) * 4;\n\t\t\t}\n\t\t\tshaderContext->output->streamoutBufferStride[it.bufferIndex] = std::max(shaderContext->output->streamoutBufferStride[it.bufferIndex], it.exportArrayBase * 4 + vectorWriteSize);\n\t\t}\n\t}\n\t// analyze input attributes again (if shader has relative GPR read)\n\tif(shaderContext->analyzer.usesRelativeGPRRead && (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry) )\n\t{\n\t\tif(shaderContext->fetchShader)\n\t\t{\n\t\t\tLatteFetchShader* parsedFetchShader = shaderContext->fetchShader;\n\t\t\tfor(auto& bufferGroup : parsedFetchShader->bufferGroups)\n\t\t\t{\n\t\t\t\tfor (sint32 i = 0; i < bufferGroup.attribCount; i++)\n\t\t\t\t{\n\t\t\t\t\tuint32 registerIndex;\n\t\t\t\t\t// get register index based on vtx semantic table\n\t\t\t\t\tuint32 attributeShaderLoc = 0xFFFFFFFF;\n\t\t\t\t\tfor (sint32 f = 0; f < 32; f++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (shaderContext->contextRegisters[mmSQ_VTX_SEMANTIC_0 + f] == bufferGroup.attrib[i].semanticId)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tattributeShaderLoc = f;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (attributeShaderLoc == 0xFFFFFFFF)\n\t\t\t\t\t\tcontinue; // attribute is not mapped to VS input\n\t\t\t\t\tregisterIndex = attributeShaderLoc + 1;\n\t\t\t\t\tshaderContext->analyzer.gprUseMask[registerIndex / 8] |= (1 << (registerIndex % 8));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse if (shaderContext->analyzer.usesRelativeGPRRead && shader->shaderType == LatteConst::ShaderType::Pixel)\n\t{\n\t\t// mark pixel shader inputs as used if there is any relative GPR access\n\t\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\t\tfor (sint32 i = 0; i < psInputTable->count; i++)\n\t\t{\n\t\t\tshaderContext->analyzer.gprUseMask[i / 8] |= (1 << (i % 8));\n\t\t}\n\t}\n\t// analyze CF stack\n\tsint32 cfCurrentStackDepth = 0;\n\tsint32 cfCurrentMaxStackDepth = 0;\n\tfor(auto& cfInstruction : shaderContext->cfInstructions)\n\t{\n\t\tif (cfInstruction.type == GPU7_CF_INST_ALU)\n\t\t{\n\t\t\t// no effect on stack depth\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_ALU_PUSH_BEFORE )\n\t\t{\n\t\t\tcfCurrentStackDepth++;\n\t\t\tcfCurrentMaxStackDepth = std::max(cfCurrentMaxStackDepth, cfCurrentStackDepth);\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_ALU_POP_AFTER)\n\t\t{\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t\tcfCurrentStackDepth--;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_ALU_POP2_AFTER)\n\t\t{\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t\tcfCurrentStackDepth -= 2;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_ALU_BREAK )\n\t\t{\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_ALU_ELSE_AFTER)\n\t\t{\n\t\t\tif (cfInstruction.popCount != 0)\n\t\t\t\tdebugBreakpoint();\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_ELSE )\n\t\t{\n\t\t\t//if (cfInstruction.popCount != 0)\n\t\t\t//\tdebugBreakpoint(); -> Only relevant when ELSE jump is taken\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_POP)\n\t\t{\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t\tcfCurrentStackDepth -= cfInstruction.popCount;\n\t\t\tif (cfCurrentStackDepth < 0)\n\t\t\t\tdebugBreakpoint();\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_LOOP_START_DX10 || cfInstruction.type == GPU7_CF_INST_LOOP_END ||\n\t\t\t\t cfInstruction.type == GPU7_CF_INST_LOOP_START_NO_AL)\n\t\t{\n\t\t\t// no effect on stack depth\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_LOOP_BREAK)\n\t\t{\n\t\t\t// since we assume that the break is not taken (for all pixels), we also don't need to worry about the stack depth adjustment\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_TEX)\n\t\t{\n\t\t\t// no effect on stack depth\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_EXPORT || cfInstruction.type == GPU7_CF_INST_EXPORT_DONE)\n\t\t{\n\t\t\t// no effect on stack depth\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_MEM_STREAM0_WRITE ||\n\t\t\tcfInstruction.type == GPU7_CF_INST_MEM_STREAM1_WRITE)\n\t\t{\n\t\t\t// no effect on stack depth\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_MEM_RING_WRITE)\n\t\t{\n\t\t\t// no effect on stack depth\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_EMIT_VERTEX)\n\t\t{\n\t\t\t// no effect on stack depth\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse if (cfInstruction.type == GPU7_CF_INST_CALL)\n\t\t{\n\t\t\t// no effect on stack depth\n\t\t\tcfInstruction.activeStackDepth = cfCurrentStackDepth;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\tshaderContext->analyzer.activeStackMaxDepth = cfCurrentMaxStackDepth;\n\tif (cfCurrentStackDepth != 0)\n\t{\n\t\tdebug_printf(\"cfCurrentStackDepth is not zero after all CF instructions. depth is %d\\n\", cfCurrentStackDepth);\n\t\tcemu_assert_debug(false);\n\t}\n\tif(list_subroutineAddrs.empty() == false)\n\t\tcemuLog_logDebug(LogType::Force, \"Todo - analyze shader subroutine CF stack\");\n\t// TF mode\n\tif (shaderContext->options->useTFViaSSBO && shaderContext->output->streamoutBufferWriteMask.any())\n\t{\n\t\tshaderContext->analyzer.useSSBOForStreamout = true;\n\t}\n\t// assign binding points\n\tif (shaderContext->shaderType == LatteConst::ShaderType::Vertex)\n\t\tshaderContext->output->resourceMappingVK.setIndex = 0;\n\telse if (shaderContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\tshaderContext->output->resourceMappingVK.setIndex = 1;\n\telse if (shaderContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\tshaderContext->output->resourceMappingVK.setIndex = 2;\n\tLatteDecompiler::_initTextureBindingPointsGL(shaderContext);\n\tLatteDecompiler::_initTextureBindingPointsVK(shaderContext);\n#if ENABLE_METAL\n\tLatteDecompiler::_initTextureBindingPointsMTL(shaderContext);\n#endif\n\tLatteDecompiler::_initUniformBindingPoints(shaderContext);\n\tLatteDecompiler::_initAttributeBindingPoints(shaderContext);\n\tshaderContext->output->resourceMappingMTL.verticesPerInstanceBinding = shaderContext->currentBufferBindingPointMTL++;\n\tshaderContext->output->resourceMappingMTL.indexBufferBinding = shaderContext->currentBufferBindingPointMTL++;\n\tshaderContext->output->resourceMappingMTL.indexTypeBinding = shaderContext->currentBufferBindingPointMTL++;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\" // todo - remove dependency\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/helpers/StringBuf.h\"\n\n#include <bitset>\n#include <boost/container/small_vector.hpp>\n\n#define _CRLF\t\"\\r\\n\"\n\nvoid LatteDecompiler_emitAttributeDecodeGLSL(LatteDecompilerShader* shaderContext, StringBuf* src, LatteParsedFetchShaderAttribute_t* attrib);\n\n/*\n * Variable names:\n * R0-R127 temp\n * Most variables are multi-typed and the respective type is appended to the name\n * Type suffixes are: f (float), i (32bit int), ui (unsigned 32bit int)\n * Examples: R13ui.x, tempf.z\n */\n\n// local prototypes\nvoid _emitTypeConversionPrefix(LatteDecompilerShaderContext* shaderContext, sint32 sourceType, sint32 destinationType);\nvoid _emitTypeConversionSuffix(LatteDecompilerShaderContext* shaderContext, sint32 sourceType, sint32 destinationType);\nvoid LatteDecompiler_emitClauseCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, bool isSubroutine);\n\nconst char* _getShaderUniformBlockInterfaceName(LatteConst::ShaderType mode)\n{\n\tswitch (mode)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t\t\treturn \"uniformBlockVS\";\n\tcase LatteConst::ShaderType::Pixel:\n\t\t\treturn \"uniformBlockPS\";\n\tcase LatteConst::ShaderType::Geometry:\n\t\t\treturn \"uniformBlockGS\";\n\tdefault:\n\t\tbreak;\n\t}\n\tcemu_assert_unimplemented();\n\treturn nullptr;\n}\n\nconst char* _getShaderUniformBlockVariableName(LatteConst::ShaderType mode)\n{\n\tswitch (mode)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t\t\treturn \"uf_blockVS\";\n\tcase LatteConst::ShaderType::Pixel:\n\t\t\treturn \"uf_blockPS\";\n\tcase LatteConst::ShaderType::Geometry:\n\t\t\treturn \"uf_blockGS\";\n\tdefault:\n\t\tbreak;\n\t}\n\tcemu_assert_unimplemented();\n\treturn nullptr;\n}\n\nconst char* _getTextureUnitVariablePrefixName(LatteConst::ShaderType mode)\n{\n\tswitch (mode)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t\t\treturn \"textureUnitVS\";\n\tcase LatteConst::ShaderType::Pixel:\n\t\t\treturn \"textureUnitPS\";\n\tcase LatteConst::ShaderType::Geometry:\n\t\t\treturn \"textureUnitGS\";\n\t}\n\tcemu_assert_unimplemented();\n\treturn nullptr;\n}\n\nconst char* _getElementStrByIndex(uint32 channel)\n{\n\tswitch (channel)\n\t{\n\t\tcase 0:\n\t\t\treturn \"x\";\n\t\tcase 1:\n\t\t\treturn \"y\";\n\t\tcase 2:\n\t\t\treturn \"z\";\n\t\tcase 3:\n\t\t\treturn \"w\";\n\t}\n\treturn \"UNDEFINED\";\n}\n\nchar _tempGenString[64][256];\nuint32 _tempGenStringIndex = 0;\n\nchar* _getTempString()\n{\n\tchar* str = _tempGenString[_tempGenStringIndex];\n\t_tempGenStringIndex = (_tempGenStringIndex+1)%64;\n\treturn str;\n}\n\nstatic char* _getActiveMaskVarName(LatteDecompilerShaderContext* shaderContext, sint32 index)\n{\n\tchar* varName = _getTempString();\n\tif (shaderContext->isSubroutine)\n\t\tsprintf(varName, \"activeMaskStackSub%04x[%d]\", shaderContext->subroutineInfo->cfAddr, index);\n\telse\n\t\tsprintf(varName, \"activeMaskStack[%d]\", index);\n\treturn varName;\n}\n\nstatic char* _getActiveMaskCVarName(LatteDecompilerShaderContext* shaderContext, sint32 index)\n{\n\tchar* varName = _getTempString();\n\tif (shaderContext->isSubroutine)\n\t\tsprintf(varName, \"activeMaskStackCSub%04x[%d]\", shaderContext->subroutineInfo->cfAddr, index);\n\telse\n\t\tsprintf(varName, \"activeMaskStackC[%d]\", index);\n\treturn varName;\n}\n\nstatic char* _getRegisterVarName(LatteDecompilerShaderContext* shaderContext, uint32 index, sint32 destRelIndexMode=-1)\n{\n\tauto type = shaderContext->typeTracker.defaultDataType;\n\tchar* tempStr = _getTempString();\n\tif (shaderContext->typeTracker.useArrayGPRs == false)\n\t{\n\t\tif (type == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\tsprintf(tempStr, \"R%di\", index);\n\t\telse if (type == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\tsprintf(tempStr, \"R%df\", index);\n\t}\n\telse\n\t{\n\t\tchar destRelOffset[32];\n\t\tif (destRelIndexMode >= 0)\n\t\t{\n\t\t\tif (destRelIndexMode == GPU7_INDEX_AR_X)\n\t\t\t\tstrcpy(destRelOffset, \"ARi.x\");\n\t\t\telse if (destRelIndexMode == GPU7_INDEX_AR_Y)\n\t\t\t\tstrcpy(destRelOffset, \"ARi.y\");\n\t\t\telse if (destRelIndexMode == GPU7_INDEX_AR_Z)\n\t\t\t\tstrcpy(destRelOffset, \"ARi.z\");\n\t\t\telse if (destRelIndexMode == GPU7_INDEX_AR_W)\n\t\t\t\tstrcpy(destRelOffset, \"ARi.w\");\n\t\t\telse\n\t\t\t\tdebugBreakpoint();\n\t\t\tif (type == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t{\n\t\t\t\tsprintf(tempStr, \"Ri[%d+%s]\", index, destRelOffset);\n\t\t\t}\n\t\t\telse if (type == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t{\n\t\t\t\tsprintf(tempStr, \"Rf[%d+%s]\", index, destRelOffset);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (type == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t{\n\t\t\t\tsprintf(tempStr, \"Ri[%d]\", index);\n\t\t\t}\n\t\t\telse if (type == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t{\n\t\t\t\tsprintf(tempStr, \"Rf[%d]\", index);\n\t\t\t}\n\t\t}\n\t}\n\treturn tempStr;\n}\n\nstatic void _appendRegisterTypeSuffix(StringBuf* src, sint32 dataType)\n{\n\tif (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\tsrc->add(\"i\");\n\telse if (dataType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT)\n\t\tsrc->add(\"ui\");\n\telse if (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\tsrc->add(\"f\");\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\n// appends x/y/z/w\nstatic void _appendChannel(StringBuf* src, sint32 channelIndex)\n{\n\tcemu_assert_debug(channelIndex >= 0 && channelIndex <= 3);\n\tswitch (channelIndex)\n\t{\n\tcase 0:\n\t\tsrc->add(\"x\");\n\t\treturn;\n\tcase 1:\n\t\tsrc->add(\"y\");\n\t\treturn;\n\tcase 2:\n\t\tsrc->add(\"z\");\n\t\treturn;\n\tcase 3:\n\t\tsrc->add(\"w\");\n\t\treturn;\n\t}\n}\n\n// appends .x/.y/.z/.w\nstatic void _appendChannelAccess(StringBuf* src, sint32 channelIndex)\n{\n\tcemu_assert_debug(channelIndex >= 0 && channelIndex <= 3);\n\tswitch (channelIndex)\n\t{\n\tcase 0:\n\t\tsrc->add(\".x\");\n\t\treturn;\n\tcase 1:\n\t\tsrc->add(\".y\");\n\t\treturn;\n\tcase 2:\n\t\tsrc->add(\".z\");\n\t\treturn;\n\tcase 3:\n\t\tsrc->add(\".w\");\n\t\treturn;\n\t}\n}\n\nstatic void _appendPVPS(LatteDecompilerShaderContext* shaderContext, StringBuf* src, uint32 groupIndex, uint8 aluUnit)\n{\n\tcemu_assert_debug(aluUnit < 5);\n\tif (aluUnit == 4)\n\t{\n\t\tsrc->addFmt(\"PS{}\", (groupIndex & 1));\n\t\t_appendRegisterTypeSuffix(src, shaderContext->typeTracker.defaultDataType);\n\t\treturn;\n\t}\n\tsrc->addFmt(\"PV{}\", (groupIndex & 1));\n\t_appendRegisterTypeSuffix(src, shaderContext->typeTracker.defaultDataType);\n\t_appendChannel(src, aluUnit);\n}\n\nstd::string _FormatFloatAsGLSLConstant(float f)\n{\n\tchar floatAsStr[64];\n\tsize_t floatAsStrLen = fmt::format_to_n(floatAsStr, 64, \"{:#}\", f).size;\n\tsize_t floatAsStrLenOrg = floatAsStrLen;\n\tif(floatAsStrLen > 0 && floatAsStr[floatAsStrLen-1] == '.')\n\t{\n\t\tfloatAsStr[floatAsStrLen] = '0';\n\t\tfloatAsStrLen++;\n\t}\n\tcemu_assert(floatAsStrLen < 50); // constant suspiciously long?\n\tfloatAsStr[floatAsStrLen] = '\\0';\n\tcemu_assert_debug(floatAsStrLen >= 3); // shortest possible form is \"0.0\"\n\treturn floatAsStr;\n}\n\n// tracks PV/PS and register backups\nstruct ALUClauseTemporariesState\n{\n\tstruct PVPSAlias\n\t{\n\t\tenum class LOCATION_TYPE : uint8\n\t\t{\n\t\t\tLOCATION_NONE,\n\t\t\tLOCATION_GPR,\n\t\t\tLOCATION_PVPS,\n\t\t};\n\n\t\tLOCATION_TYPE location{ LOCATION_TYPE::LOCATION_NONE };\n\t\tuint8 index; // GPR index or temporary index\n\t\tuint8 aluUnit; // x,y,z,w (or 5 for PS)\n\n\t\tvoid SetLocationGPR(uint8 gprIndex, uint8 channel)\n\t\t{\n\t\t\tcemu_assert_debug(channel < 4);\n\t\t\tthis->location = LOCATION_TYPE::LOCATION_GPR;\n\t\t\tthis->index = gprIndex;\n\t\t\tthis->aluUnit = channel;\n\t\t}\n\n\t\tvoid SetLocationPSPVTemporary(uint8 aluUnit, uint32 groupIndex)\n\t\t{\n\t\t\tcemu_assert_debug(aluUnit < 5);\n\t\t\tthis->location = LOCATION_TYPE::LOCATION_PVPS;\n\t\t\tthis->index = groupIndex & 1;\n\t\t\tthis->aluUnit = aluUnit;\n\t\t}\n\t};\n\n\tstruct GPRTemporary\n\t{\n\t\tGPRTemporary(uint8 gprIndex, uint8 channel, uint8 backupVarIndex) : gprIndex(gprIndex), channel(channel), backupVarIndex(backupVarIndex) {}\n\n\t\tuint8 gprIndex;\n\t\tuint8 channel;\n\t\tuint8 backupVarIndex;\n\t};\n\n\tvoid TrackGroupOutputPVPS(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstr, size_t numInstr)\n\t{\n\t\t// unset current\n\t\tfor (auto& it : m_pvps)\n\t\t\tit.location = PVPSAlias::LOCATION_TYPE::LOCATION_NONE;\n\t\tfor (size_t i = 0; i < numInstr; i++)\n\t\t{\n\t\t\tLatteDecompilerALUInstruction& inst = aluInstr[i];\n\t\t\tif (!inst.isOP3 && inst.opcode == ALU_OP2_INST_NOP)\n\t\t\t\tcontinue; // skip NOP instruction\n\n\t\t\tif (inst.writeMask == 0)\n\t\t\t{\n\t\t\t\t// map to temporary\n\t\t\t\tm_pvps[inst.aluUnit].SetLocationPSPVTemporary(inst.aluUnit, aluInstr->instructionGroupIndex);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// map to GPR\n\t\t\t\tif(inst.destRel == 0) // is PV/PS set for indexed writes?\n\t\t\t\t\tm_pvps[inst.aluUnit].SetLocationGPR(inst.destGpr, inst.destElem);\n\t\t\t}\n\t\t}\n\t}\n\n\tbool HasPVPS(uint8 aluUnitIndex) const\n\t{\n\t\tcemu_assert_debug(aluUnitIndex < 5);\n\t\treturn m_pvps[aluUnitIndex].location != PVPSAlias::LOCATION_TYPE::LOCATION_NONE;\n\t}\n\n\tvoid EmitPVPSAccess(LatteDecompilerShaderContext* shaderContext, uint8 aluUnitIndex, uint32 currentGroupIndex) const\n\t{\n\t\tswitch (m_pvps[aluUnitIndex].location)\n\t\t{\n\t\tcase PVPSAlias::LOCATION_TYPE::LOCATION_GPR:\n\t\t{\n\t\t\tsint32 temporaryIndex = GetTemporaryForGPR(m_pvps[aluUnitIndex].index, m_pvps[aluUnitIndex].aluUnit);\n\t\t\tif (temporaryIndex < 0)\n\t\t\t{\n\t\t\t\tshaderContext->shaderSource->add(_getRegisterVarName(shaderContext, m_pvps[aluUnitIndex].index, -1));\n\t\t\t\t_appendChannelAccess(shaderContext->shaderSource, m_pvps[aluUnitIndex].aluUnit);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// use temporary instead of GPR\n\t\t\t\tshaderContext->shaderSource->addFmt(\"backupReg{}\", temporaryIndex);\n\t\t\t\t_appendRegisterTypeSuffix(shaderContext->shaderSource, shaderContext->typeTracker.defaultDataType);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase PVPSAlias::LOCATION_TYPE::LOCATION_PVPS:\n\t\t\t_appendPVPS(shaderContext, shaderContext->shaderSource, currentGroupIndex-1, m_pvps[aluUnitIndex].aluUnit);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemuLog_log(LogType::Force, \"Shader {:016x} accesses PV/PS without writing to it\", shaderContext->shaderBaseHash);\n\t\t\tcemu_assert_suspicious();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/*\n\t * Check for GPR channels which are modified before they are read within the same group\n\t * These registers need to be copied to a temporary\n\t */\n\tvoid CreateGPRTemporaries(LatteDecompilerShaderContext* shaderContext, std::span<LatteDecompilerALUInstruction> aluInstructions)\n\t{\n\t\tuint8 registerChannelWriteMask[(LATTE_NUM_GPR * 4 + 7) / 8] = { 0 };\n\n\t\tm_gprTemporaries.clear();\n\t\tfor (auto& aluInstruction : aluInstructions)\n\t\t{\n\t\t\t// ignore NOP instructions\n\t\t\tif (aluInstruction.isOP3 == false && aluInstruction.opcode == ALU_OP2_INST_NOP)\n\t\t\t\tcontinue;\n\t\t\tcemu_assert_debug(aluInstruction.destElem <= 3);\n\t\t\t// check if any previously written register is read\n\t\t\tfor (sint32 f = 0; f < 3; f++)\n\t\t\t{\n\t\t\t\tuint32 readGPRIndex;\n\t\t\t\tuint32 readGPRChannel;\n\t\t\t\tif (GPU7_ALU_SRC_IS_GPR(aluInstruction.sourceOperand[f].sel))\n\t\t\t\t{\n\t\t\t\t\treadGPRIndex = GPU7_ALU_SRC_GET_GPR_INDEX(aluInstruction.sourceOperand[f].sel);\n\t\t\t\t\tcemu_assert_debug(aluInstruction.sourceOperand[f].chan <= 3);\n\t\t\t\t\treadGPRChannel = aluInstruction.sourceOperand[f].chan;\n\t\t\t\t}\n\t\t\t\telse if (GPU7_ALU_SRC_IS_PV(aluInstruction.sourceOperand[f].sel) || GPU7_ALU_SRC_IS_PS(aluInstruction.sourceOperand[f].sel))\n\t\t\t\t{\n\t\t\t\t\tuint8 aluUnitIndex = 0;\n\t\t\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstruction.sourceOperand[f].sel))\n\t\t\t\t\t\taluUnitIndex = aluInstruction.sourceOperand[f].chan;\n\t\t\t\t\telse\n\t\t\t\t\t\taluUnitIndex = 4;\n\t\t\t\t\t// if aliased to a GPR, then consider it a GPR read\n\t\t\t\t\tif(m_pvps[aluUnitIndex].location != PVPSAlias::LOCATION_TYPE::LOCATION_GPR)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\treadGPRIndex = m_pvps[aluUnitIndex].index;\n\t\t\t\t\treadGPRChannel = m_pvps[aluUnitIndex].aluUnit;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tcontinue;\n\t\t\t\t// track GPR read\n\t\t\t\tif ((registerChannelWriteMask[(readGPRIndex * 4 + aluInstruction.sourceOperand[f].chan) / 8] & (1 << ((readGPRIndex * 4 + aluInstruction.sourceOperand[f].chan) % 8))) != 0)\n\t\t\t\t{\n\t\t\t\t\t// register is overwritten by previous instruction, a temporary variable is required\n\t\t\t\t\tif (GetTemporaryForGPR(readGPRIndex, readGPRChannel) < 0)\n\t\t\t\t\t\tm_gprTemporaries.emplace_back(readGPRIndex, readGPRChannel, m_gprTemporaries.size());\n\t\t\t\t}\n\t\t\t}\n\t\t\t// track write\n\t\t\tif (aluInstruction.writeMask != 0)\n\t\t\t\tregisterChannelWriteMask[(aluInstruction.destGpr * 4 + aluInstruction.destElem) / 8] |= (1 << ((aluInstruction.destGpr * 4 + aluInstruction.destElem) % 8));\n\t\t}\n\t\t// output code to move GPRs into temporaries\n\t\tStringBuf* src = shaderContext->shaderSource;\n\t\tfor (auto& it : m_gprTemporaries)\n\t\t{\n\t\t\tsrc->addFmt(\"backupReg{}\", it.backupVarIndex);\n\t\t\t_appendRegisterTypeSuffix(src, shaderContext->typeTracker.defaultDataType);\n\t\t\tsrc->add(\" = \");\n\t\t\tsrc->add(_getRegisterVarName(shaderContext, it.gprIndex));\n\t\t\t_appendChannelAccess(src, it.channel);\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t}\n\n\t// returns -1 if none present\n\tsint32 GetTemporaryForGPR(uint8 gprIndex, uint8 channel) const\n\t{\n\t\tfor (auto& it : m_gprTemporaries)\n\t\t{\n\t\t\tif (it.gprIndex == gprIndex && it.channel == channel)\n\t\t\t\treturn (sint32)it.backupVarIndex;\n\t\t}\n\t\treturn -1;\n\t}\n\nprivate:\n\tPVPSAlias m_pvps[5]{};\n\tboost::container::small_vector<GPRTemporary, 4> m_gprTemporaries;\n};\n\nsint32 _getVertexShaderOutParamSemanticId(uint32* contextRegisters, sint32 index) // deprecated - move to LatteShaderPSInputTable\n{\n\tuint32 vsSemanticId = (contextRegisters[mmSPI_VS_OUT_ID_0 + (index / 4)] >> (8 * (index % 4))) & 0xFF;\n\t// check if export exists since exports are generated based on PS inputs\n\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\tfor (sint32 i = 0; i < psInputTable->count; i++)\n\t{\n\t\tif(psInputTable->import[i].semanticId == vsSemanticId)\n\t\t\treturn vsSemanticId;\n\t}\n\treturn 0xFF;\n}\n\nsint32 _getInputRegisterDataType(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex)\n{\n\treturn shaderContext->typeTracker.defaultDataType;\n}\n\nsint32 _getALUInstructionOutputDataType(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction)\n{\n\treturn shaderContext->typeTracker.defaultDataType;\n}\n\n// returns true if the ALU instruction is a OP2 reduction instruction\nbool _isReductionInstruction(LatteDecompilerALUInstruction* aluInstruction)\n{\n\treturn aluInstruction->isOP3 == false && (aluInstruction->opcode == ALU_OP2_INST_DOT4 || aluInstruction->opcode == ALU_OP2_INST_DOT4_IEEE || aluInstruction->opcode == ALU_OP2_INST_CUBE);\n}\n\n/*\n * Writes the name of the output variable and channel\n * E.g. R5f.x or tempf.x if writeMask is 0\n */\nvoid _emitInstructionOutputVariableName(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction)\n{\n\tauto src = shaderContext->shaderSource;\n\tsint32 outputDataType = _getALUInstructionOutputDataType(shaderContext, aluInstruction);\n\tif( aluInstruction->writeMask == 0 )\n\t{\n\t\t// does not output to GPR\n\t\tif( !_isReductionInstruction(aluInstruction) )\n\t\t{\n\t\t\t// output to PV/PS\n\t\t\t_appendPVPS(shaderContext, src, aluInstruction->instructionGroupIndex, aluInstruction->aluUnit);\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// output to temp\n\t\t\tsrc->add(\"temp\");\n\t\t\t_appendRegisterTypeSuffix(src, outputDataType);\n\t\t}\n\t\t_appendChannelAccess(src, aluInstruction->aluUnit);\n\t}\n\telse\n\t{\n\t\t// output to GPR. Aliasing to PV/PS happens at the end of the group\n\t\tsrc->add(_getRegisterVarName(shaderContext, aluInstruction->destGpr, aluInstruction->destRel==0?-1:aluInstruction->indexMode));\n\t\t_appendChannelAccess(src, aluInstruction->destElem);\n\t}\n}\n\nvoid _emitInstructionPVPSOutputVariableName(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction)\n{\n\t_appendPVPS(shaderContext, shaderContext->shaderSource, aluInstruction->instructionGroupIndex, aluInstruction->aluUnit);\n}\n\nvoid _emitRegisterAccessCode(LatteDecompilerShaderContext* shaderContext, sint32 gprIndex, sint32 channel0, sint32 channel1, sint32 channel2, sint32 channel3, sint32 dataType = -1)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 registerElementDataType = shaderContext->typeTracker.defaultDataType;\n\tcemu_assert_debug(gprIndex >= 0 && gprIndex <= 127);\n\tif (dataType >= 0)\n\t{\n\t\t_emitTypeConversionPrefix(shaderContext, registerElementDataType, dataType);\n\t}\n\tif (shaderContext->typeTracker.useArrayGPRs)\n\t\tsrc->add(\"R\");\n\telse\n\t\tsrc->addFmt(\"R{}\", gprIndex);\n\t_appendRegisterTypeSuffix(src, registerElementDataType);\n\tif (shaderContext->typeTracker.useArrayGPRs)\n\t\tsrc->addFmt(\"[{}]\", gprIndex);\n\n\tsrc->add(\".\");\n\n\tsint32 channelArray[4];\n\tchannelArray[0] = channel0;\n\tchannelArray[1] = channel1;\n\tchannelArray[2] = channel2;\n\tchannelArray[3] = channel3;\n\n\tfor (sint32 i = 0; i < 4; i++)\n\t{\n\t\tif (channelArray[i] >= 0 && channelArray[i] <= 3)\n\t\t\tsrc->add(_getElementStrByIndex(channelArray[i]));\n\t\telse if (channelArray[i] == -1)\n\t\t{\n\t\t\t// channel not used\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\tif (dataType >= 0)\n\t\t_emitTypeConversionSuffix(shaderContext, registerElementDataType, dataType);\n}\n\n// optimized variant of _emitRegisterAccessCode for raw one channel reads\nvoid _emitRegisterChannelAccessCode(LatteDecompilerShaderContext* shaderContext, sint32 gprIndex, sint32 channel, sint32 dataType)\n{\n\tcemu_assert_debug(gprIndex >= 0 && gprIndex <= 127);\n\tcemu_assert_debug(channel >= 0 && channel < 4);\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 registerElementDataType = shaderContext->typeTracker.defaultDataType;\n\t_emitTypeConversionPrefix(shaderContext, registerElementDataType, dataType);\n\tif (shaderContext->typeTracker.useArrayGPRs)\n\t\tsrc->add(\"R\");\n\telse\n\t\tsrc->addFmt(\"R{}\", gprIndex);\n\t_appendRegisterTypeSuffix(src, registerElementDataType);\n\tif (shaderContext->typeTracker.useArrayGPRs)\n\t\tsrc->addFmt(\"[{}]\", gprIndex);\n\tsrc->add(\".\");\n\tsrc->add(_getElementStrByIndex(channel));\n\t_emitTypeConversionSuffix(shaderContext, registerElementDataType, dataType);\n}\n\nvoid _emitALURegisterInputAccessCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 currentRegisterElementType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\tcemu_assert_debug(GPU7_ALU_SRC_IS_GPR(aluInstruction->sourceOperand[operandIndex].sel));\n\tsint32 gprIndex = GPU7_ALU_SRC_GET_GPR_INDEX(aluInstruction->sourceOperand[operandIndex].sel);\t\n\tsint32 temporaryIndex = shaderContext->aluPVPSState->GetTemporaryForGPR(gprIndex, aluInstruction->sourceOperand[operandIndex].chan);\n\tif(temporaryIndex >= 0)\n\t{\n\t\t// access via backup variable\n\t\tsrc->addFmt(\"backupReg{}\", temporaryIndex);\n\t\t_appendRegisterTypeSuffix(src, currentRegisterElementType);\n\t}\n\telse\n\t{\n\t\t// access via register variable\n\t\t_emitRegisterAccessCode(shaderContext, gprIndex, aluInstruction->sourceOperand[operandIndex].chan, -1, -1, -1);\n\t}\n}\n\nvoid _emitPVPSAccessCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex, uint8 aluUnitIndex)\n{\n\tcemu_assert_debug(aluInstruction->instructionGroupIndex > 0); // PV/PS is uninitialized for group 0\n\t// PV/PS vars are currently always using the default type (shaderContext->typeTracker.defaultDataType)\n\tshaderContext->aluPVPSState->EmitPVPSAccess(shaderContext, aluUnitIndex, aluInstruction->instructionGroupIndex);\n}\n\n/*\n * Emits the expression used for calculating the index for uniform access\n * For static access, this is a number\n * For dynamic access, this is AR.* + base\n */\nvoid _emitUniformAccessIndexCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tbool isUniformRegister = GPU7_ALU_SRC_IS_CFILE(aluInstruction->sourceOperand[operandIndex].sel);\n\tsint32 uniformOffset = 0; // index into array, for relative accesses this is the base offset\n\tif( isUniformRegister )\n\t{\n\t\tuniformOffset = GPU7_ALU_SRC_GET_CFILE_INDEX(aluInstruction->sourceOperand[operandIndex].sel);\n\t}\n\telse\n\t{\n\t\tif( GPU7_ALU_SRC_IS_CBANK0(aluInstruction->sourceOperand[operandIndex].sel) )\n\t\t{\n\t\t\tuniformOffset = GPU7_ALU_SRC_GET_CBANK0_INDEX(aluInstruction->sourceOperand[operandIndex].sel) + aluInstruction->cfInstruction->cBank0AddrBase;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuniformOffset = GPU7_ALU_SRC_GET_CBANK1_INDEX(aluInstruction->sourceOperand[operandIndex].sel) + aluInstruction->cfInstruction->cBank1AddrBase;\n\t\t}\n\t}\n\tif( aluInstruction->sourceOperand[operandIndex].rel != 0 )\n\t{\n\t\tif (aluInstruction->indexMode == GPU7_INDEX_AR_X)\n\t\t\tsrc->addFmt(\"ARi.x+{}\", uniformOffset);\n\t\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_Y)\n\t\t\tsrc->addFmt(\"ARi.y+{}\", uniformOffset);\n\t\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_Z)\n\t\t\tsrc->addFmt(\"ARi.z+{}\", uniformOffset);\n\t\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_W)\n\t\t\tsrc->addFmt(\"ARi.w+{}\", uniformOffset);\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse\n\t{\n\t\tsrc->addFmt(\"{}\", uniformOffset);\n\t}\n}\n\nvoid _emitUniformAccessCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex, sint32 requiredType)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif(shaderContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED )\n\t{\n\t\t// uniform registers or buffers are accessed statically with predictable offsets\n\t\t// find entry in remapped uniform\n\t\tif( aluInstruction->sourceOperand[operandIndex].rel != 0 )\n\t\t\tdebugBreakpoint();\n\t\tbool isUniformRegister = GPU7_ALU_SRC_IS_CFILE(aluInstruction->sourceOperand[operandIndex].sel);\n\t\tsint32 uniformOffset = 0; // index into array\n\t\tsint32 uniformBufferIndex = 0;\n\t\tif( isUniformRegister )\n\t\t{\n\t\t\tuniformOffset = GPU7_ALU_SRC_GET_CFILE_INDEX(aluInstruction->sourceOperand[operandIndex].sel);\n\t\t\tuniformBufferIndex = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif( GPU7_ALU_SRC_IS_CBANK0(aluInstruction->sourceOperand[operandIndex].sel) )\n\t\t\t{\n\t\t\t\tuniformOffset = GPU7_ALU_SRC_GET_CBANK0_INDEX(aluInstruction->sourceOperand[operandIndex].sel) + aluInstruction->cfInstruction->cBank0AddrBase;\n\t\t\t\tuniformBufferIndex = aluInstruction->cfInstruction->cBank0Index;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuniformOffset = GPU7_ALU_SRC_GET_CBANK1_INDEX(aluInstruction->sourceOperand[operandIndex].sel) + aluInstruction->cfInstruction->cBank1AddrBase;\n\t\t\t\tuniformBufferIndex = aluInstruction->cfInstruction->cBank1Index;\n\t\t\t}\n\t\t}\n\t\tLatteDecompilerRemappedUniformEntry_t* remappedUniformEntry = NULL;\n\t\tfor(size_t i=0; i< shaderContext->shader->list_remappedUniformEntries.size(); i++)\n\t\t{\n\t\t\tLatteDecompilerRemappedUniformEntry_t* remappedUniformEntryItr = shaderContext->shader->list_remappedUniformEntries.data() + i;\n\t\t\tif( remappedUniformEntryItr->isRegister && isUniformRegister )\n\t\t\t{\n\t\t\t\tif( remappedUniformEntryItr->index == uniformOffset )\n\t\t\t\t{\n\t\t\t\t\tremappedUniformEntry = remappedUniformEntryItr;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif( remappedUniformEntryItr->kcacheBankId == uniformBufferIndex && remappedUniformEntryItr->index == uniformOffset )\n\t\t\t\t{\n\t\t\t\t\tremappedUniformEntry = remappedUniformEntryItr;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcemu_assert_debug(remappedUniformEntry);\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n\t\tif(shaderContext->shader->shaderType == LatteConst::ShaderType::Vertex )\n\t\t\tsrc->addFmt(\"uf_remappedVS[{}]\", remappedUniformEntry->mappedIndex);\n\t\telse if(shaderContext->shader->shaderType == LatteConst::ShaderType::Pixel )\n\t\t\tsrc->addFmt(\"uf_remappedPS[{}]\", remappedUniformEntry->mappedIndex);\n\t\telse if(shaderContext->shader->shaderType == LatteConst::ShaderType::Geometry )\n\t\t\tsrc->addFmt(\"uf_remappedGS[{}]\", remappedUniformEntry->mappedIndex);\n\t\telse\n\t\t\tdebugBreakpoint();\n\t\t_appendChannelAccess(src, aluInstruction->sourceOperand[operandIndex].chan);\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n\t}\n\telse if( shaderContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE )\n\t{\n\t\t// uniform registers are accessed with unpredictable (dynamic) offset\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n\t\tif(shaderContext->shader->shaderType == LatteConst::ShaderType::Vertex )\n\t\t\tsrc->add(\"uf_uniformRegisterVS[\");\n\t\telse if (shaderContext->shader->shaderType == LatteConst::ShaderType::Pixel)\n\t\t\tsrc->add(\"uf_uniformRegisterPS[\");\n\t\telse if(shaderContext->shader->shaderType == LatteConst::ShaderType::Geometry )\n\t\t\tsrc->add(\"uf_uniformRegisterGS[\");\n\t\telse\n\t\t\tdebugBreakpoint();\n\t\t_emitUniformAccessIndexCode(shaderContext, aluInstruction, operandIndex);\n\t\tsrc->add(\"]\");\n\n\t\t_appendChannelAccess(src, aluInstruction->sourceOperand[operandIndex].chan);\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n\t}\n\telse if( shaderContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK )\n\t{\n\t\t// uniform buffers are available as a whole\n\t\tbool isUniformRegister = GPU7_ALU_SRC_IS_CFILE(aluInstruction->sourceOperand[operandIndex].sel);\n\t\tif( isUniformRegister )\n\t\t\tdebugBreakpoint();\n\t\tsint32 uniformBufferIndex = 0;\n\t\tif( GPU7_ALU_SRC_IS_CBANK0(aluInstruction->sourceOperand[operandIndex].sel) )\n\t\t{\n\t\t\tuniformBufferIndex = aluInstruction->cfInstruction->cBank0Index;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuniformBufferIndex = aluInstruction->cfInstruction->cBank1Index;\n\t\t}\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t\tsrc->addFmt(\"{}{}[\", _getShaderUniformBlockVariableName(shaderContext->shader->shaderType), uniformBufferIndex);\n\t\t_emitUniformAccessIndexCode(shaderContext, aluInstruction, operandIndex);\n\t\tsrc->addFmt(\"]\");\n\n\t\t_appendChannelAccess(src, aluInstruction->sourceOperand[operandIndex].chan);\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t}\n\telse\n\t\tdebugBreakpoint();\n}\n\n// Generates (slow) code to read an indexed GPR\nvoid _emitCodeToReadRelativeGPR(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex, sint32 requiredType)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tuint32 gprBaseIndex = GPU7_ALU_SRC_GET_GPR_INDEX(aluInstruction->sourceOperand[operandIndex].sel);\n\tcemu_assert_debug(aluInstruction->sourceOperand[operandIndex].rel != 0);\n\n\tif( shaderContext->typeTracker.useArrayGPRs )\n\t{\n\t\t_emitTypeConversionPrefix(shaderContext, shaderContext->typeTracker.defaultDataType, requiredType);\n\t\tsrc->add(_getRegisterVarName(shaderContext, gprBaseIndex, aluInstruction->indexMode));\n\t\t_appendChannelAccess(src, aluInstruction->sourceOperand[operandIndex].chan);\n\t\t_emitTypeConversionSuffix(shaderContext, shaderContext->typeTracker.defaultDataType, requiredType);\n\t\treturn;\n\t}\n\n\tchar indexAccessCode[64];\n\tif (aluInstruction->indexMode == GPU7_INDEX_AR_X)\n\t\tsprintf(indexAccessCode, \"ARi.x\");\n\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_Y)\n\t\tsprintf(indexAccessCode, \"ARi.y\");\n\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_Z)\n\t\tsprintf(indexAccessCode, \"ARi.z\");\n\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_W)\n\t\tsprintf(indexAccessCode, \"ARi.w\");\n\telse\n\t\tcemu_assert_unimplemented();\n\t\n\tif( LATTE_DECOMPILER_DTYPE_SIGNED_INT != requiredType )\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n\n\t// generated code looks like this:\n\t// result = ((lookupIndex==0)?GPR5:(lookupIndex==1)?GPR6:(lookupIndex==2)?GPR7:...:(lookupIndex==122)?GPR127:0)\n\tsrc->add(\"(\");\n\tfor(sint32 i=gprBaseIndex; i<LATTE_NUM_GPR; i++)\n\t{\n\t\t// only emit access code for registers which are potentially written\n\t\tif((shaderContext->analyzer.gprUseMask[i / 8] & (1 << (i % 8))) == 0 )\n\t\t\tcontinue;\n\t\tsrc->addFmt(\"({}=={})?\", indexAccessCode, i-gprBaseIndex);\n\t\t// code to access gpr\n\t\tuint32 gprIndex = i;\n\t\tsrc->add(_getRegisterVarName(shaderContext, i));\n\t\t_appendChannelAccess(src, aluInstruction->sourceOperand[operandIndex].chan);\n\t\tsrc->add(\":\");\n\t}\n\tsrc->add(\"0)\");\n\tif( LATTE_DECOMPILER_DTYPE_SIGNED_INT != requiredType )\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n}\n\nvoid _emitOperandInputCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex, sint32 requiredType)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif(\toperandIndex < 0 || operandIndex >= 3 )\n\t\tdebugBreakpoint();\n\tsint32 requiredTypeOut = requiredType;\n\tif( requiredType != LATTE_DECOMPILER_DTYPE_FLOAT && (aluInstruction->sourceOperand[operandIndex].abs != 0 || aluInstruction->sourceOperand[operandIndex].neg != 0) )\n\t{\n\t\t// we need to apply float operations on the input but it's not read as a float\n\t\t// force internal required type to float and then cast it back to whatever type is actually required\n\t\trequiredType = LATTE_DECOMPILER_DTYPE_FLOAT;\n\t}\n\n\tif( requiredTypeOut != requiredType )\n\t\t_emitTypeConversionPrefix(shaderContext, requiredType, requiredTypeOut);\n\n\tif( aluInstruction->sourceOperand[operandIndex].neg != 0 )\n\t\tsrc->add(\"-(\");\n\tif( aluInstruction->sourceOperand[operandIndex].abs != 0 )\n\t\tsrc->add(\"abs(\");\n\n\tif( GPU7_ALU_SRC_IS_GPR(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tif( aluInstruction->sourceOperand[operandIndex].rel != 0 )\n\t\t{\n\t\t\t_emitCodeToReadRelativeGPR(shaderContext, aluInstruction, operandIndex, requiredType);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint32 gprIndex = GPU7_ALU_SRC_GET_GPR_INDEX(aluInstruction->sourceOperand[operandIndex].sel);\n\t\t\tif( requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t{\n\t\t\t\t// signed int 32bit\n\t\t\t\tsint32 currentRegisterElementType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\t\t\t\t// write code for register input\n\t\t\t\t_emitTypeConversionPrefix(shaderContext, currentRegisterElementType, requiredType);\n\t\t\t\t_emitALURegisterInputAccessCode(shaderContext, aluInstruction, operandIndex);\n\t\t\t\t_emitTypeConversionSuffix(shaderContext, currentRegisterElementType, requiredType);\n\t\t\t}\n\t\t\telse if( requiredType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT )\n\t\t\t{\n\t\t\t\t// unsigned int 32bit\n\t\t\t\tsint32 currentRegisterElementType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\t\t\t\tif( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t\t{\n\t\t\t\t\t// need to convert from int to uint\n\t\t\t\t\tsrc->add(\"uint(\");\n\t\t\t\t}\n\t\t\t\telse if( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT )\n\t\t\t\t{\n\t\t\t\t\t// no extra work necessary\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tdebugBreakpoint();\n\t\t\t\t// write code for register input\n\t\t\t\t_emitALURegisterInputAccessCode(shaderContext, aluInstruction, operandIndex);\n\t\t\t\tif( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t\t{\n\t\t\t\t\tsrc->add(\")\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( requiredType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\t\t{\n\t\t\t\t// float 32bit\n\t\t\t\tsint32 currentRegisterElementType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\t\t\t\tif( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t\t{\n\t\t\t\t\t// need to convert (not cast) from int bits to float\n\t\t\t\t\tsrc->add(\"intBitsToFloat(\");\n\t\t\t\t}\n\t\t\t\telse if( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\t\t\t{\n\t\t\t\t\t// no extra work necessary\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tdebugBreakpoint();\n\t\t\t\t// write code for register input\n\t\t\t\t_emitALURegisterInputAccessCode(shaderContext, aluInstruction, operandIndex);\n\t\t\t\tif( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t\t{\n\t\t\t\t\tsrc->add(\")\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\telse if( GPU7_ALU_SRC_IS_CONST_0F(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tif(requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT || requiredType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT)\n\t\t\tsrc->add(\"0\");\n\t\telse if( requiredType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\t\tsrc->add(\"0.0\");\n\t}\n\telse if( GPU7_ALU_SRC_IS_CONST_1F(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t\tsrc->add(\"1.0\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t}\n\telse if( GPU7_ALU_SRC_IS_CONST_0_5F(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t\tsrc->add(\"0.5\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t}\n\telse if( GPU7_ALU_SRC_IS_CONST_1I(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tif (requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\tsrc->add(\"int(1)\");\n\t\telse if (requiredType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT)\n\t\t\tsrc->add(\"uint(1)\");\n\t\telse\n\t\t\tcemu_assert_suspicious();\n\t}\n\telse if( GPU7_ALU_SRC_IS_CONST_M1I(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tif( requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\tsrc->add(\"int(-1)\");\n\t\telse\n\t\t\tcemu_assert_suspicious();\n\t}\n\telse if( GPU7_ALU_SRC_IS_LITERAL(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tif( requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\tsrc->addFmt(\"0x{:x}\", aluInstruction->literalData.w[aluInstruction->sourceOperand[operandIndex].chan]);\n\t\telse if( requiredType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT )\n\t\t\tsrc->addFmt(\"uint(0x{:x})\", aluInstruction->literalData.w[aluInstruction->sourceOperand[operandIndex].chan]);\n\t\telse if (requiredType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t{\n\t\t\tuint32 constVal = aluInstruction->literalData.w[aluInstruction->sourceOperand[operandIndex].chan];\n\t\t\tsint32 exponent = (constVal >> 23) & 0xFF;\n\t\t\texponent -= 127;\n\t\t\tif ((constVal & 0xFF) == 0 && exponent >= -10 && exponent <= 10)\n\t\t\t{\n\t\t\t\tsrc->add(_FormatFloatAsGLSLConstant(*(float*)&constVal));\n\t\t\t}\n\t\t\telse\n\t\t\t\tsrc->addFmt(\"intBitsToFloat(0x{:08x})\", constVal);\n\t\t}\n\t}\n\telse if( GPU7_ALU_SRC_IS_CFILE(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\t_emitUniformAccessCode(shaderContext, aluInstruction, operandIndex, requiredType);\n\t}\n\telse if( GPU7_ALU_SRC_IS_CBANK0(aluInstruction->sourceOperand[operandIndex].sel) ||\n\t\tGPU7_ALU_SRC_IS_CBANK1(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\t_emitUniformAccessCode(shaderContext, aluInstruction, operandIndex, requiredType);\n\t}\n\telse if( GPU7_ALU_SRC_IS_PV(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tsint32 currentPVDataType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\t\t_emitTypeConversionPrefix(shaderContext, currentPVDataType, requiredType);\n\t\t_emitPVPSAccessCode(shaderContext, aluInstruction, operandIndex, aluInstruction->sourceOperand[operandIndex].chan);\n\t\t_emitTypeConversionSuffix(shaderContext, currentPVDataType, requiredType);\n\t}\n\telse if( GPU7_ALU_SRC_IS_PS(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tsint32 currentPSDataType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\t\t_emitTypeConversionPrefix(shaderContext, currentPSDataType, requiredType);\n\t\t_emitPVPSAccessCode(shaderContext, aluInstruction, operandIndex, 4);\n\t\t_emitTypeConversionSuffix(shaderContext, currentPSDataType, requiredType);\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"Unsupported shader ALU operand sel {:#x}\\n\", aluInstruction->sourceOperand[operandIndex].sel);\n\t\tdebugBreakpoint();\n\t}\n\n\tif( aluInstruction->sourceOperand[operandIndex].abs != 0 )\n\t\tsrc->add(\")\");\n\tif( aluInstruction->sourceOperand[operandIndex].neg != 0 )\n\t\tsrc->add(\")\");\n\n\tif( requiredTypeOut != requiredType )\n\t\t_emitTypeConversionSuffix(shaderContext, requiredType, requiredTypeOut);\n}\n\nvoid _emitTypeConversionPrefix(LatteDecompilerShaderContext* shaderContext, sint32 sourceType, sint32 destinationType)\n{\n\tif( sourceType == destinationType )\n\t\treturn;\n\tStringBuf* src = shaderContext->shaderSource;\n\tif (sourceType == LATTE_DECOMPILER_DTYPE_FLOAT && destinationType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\tsrc->add(\"floatBitsToInt(\");\n\telse if (sourceType == LATTE_DECOMPILER_DTYPE_FLOAT && destinationType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT)\n\t\tsrc->add(\"floatBitsToUint(\");\n\telse if( sourceType == LATTE_DECOMPILER_DTYPE_SIGNED_INT && destinationType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\tsrc->add(\"intBitsToFloat(\");\n\telse if( sourceType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT && destinationType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\tsrc->add(\"int(\");\n\telse if( sourceType == LATTE_DECOMPILER_DTYPE_SIGNED_INT && destinationType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT )\n\t\tsrc->add(\"uint(\");\n\telse\n\t\tcemu_assert_debug(false);\n}\n\nvoid _emitTypeConversionSuffix(LatteDecompilerShaderContext* shaderContext, sint32 sourceType, sint32 destinationType)\n{\n\tif( sourceType == destinationType )\n\t\treturn;\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->add(\")\");\n}\n\ntemplate<int TDataType>\nvoid _emitALUOperationBinary(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, const char* operandStr)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 outputType = _getALUInstructionOutputDataType(shaderContext, aluInstruction);\n\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\tsrc->add(\" = \");\n\t_emitTypeConversionPrefix(shaderContext, TDataType, outputType);\n\t_emitOperandInputCode(shaderContext, aluInstruction, 0, TDataType);\n\tsrc->add((char*)operandStr);\n\t_emitOperandInputCode(shaderContext, aluInstruction, 1, TDataType);\n\t_emitTypeConversionSuffix(shaderContext, TDataType, outputType);\n\tsrc->add(\";\" _CRLF);\n}\n\nstatic bool _isSameGPROperand(LatteDecompilerALUInstruction* aluInstruction, sint32 opIndexA, sint32 opIndexB)\n{\n\tif (aluInstruction->sourceOperand[opIndexA].sel != aluInstruction->sourceOperand[opIndexB].sel)\n\t\treturn false;\n\tif (!GPU7_ALU_SRC_IS_GPR(aluInstruction->sourceOperand[opIndexA].sel))\n\t\treturn false;\n\tif (aluInstruction->sourceOperand[opIndexA].chan != aluInstruction->sourceOperand[opIndexB].chan)\n\t\treturn false;\n\tif (aluInstruction->sourceOperand[opIndexA].abs != aluInstruction->sourceOperand[opIndexB].abs)\n\t\treturn false;\n\tif (aluInstruction->sourceOperand[opIndexA].neg != aluInstruction->sourceOperand[opIndexB].neg)\n\t\treturn false;\n\tif (aluInstruction->sourceOperand[opIndexA].rel != aluInstruction->sourceOperand[opIndexB].rel)\n\t\treturn false;\n\treturn true;\n}\n\nstatic bool _operandHasModifiers(LatteDecompilerALUInstruction* aluInstruction, sint32 opIndex)\n{\n\treturn aluInstruction->sourceOperand[opIndex].abs != 0 || aluInstruction->sourceOperand[opIndex].neg != 0;\n}\n\nvoid _emitALUOP2InstructionCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, LatteDecompilerALUInstruction* aluInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 outputType = _getALUInstructionOutputDataType(shaderContext, aluInstruction); // data type of output\n\tif( aluInstruction->opcode == ALU_OP2_INST_MOV )\n\t{\n\t\tbool requiresFloatMove = false;\n\t\trequiresFloatMove = aluInstruction->sourceOperand[0].abs != 0 || aluInstruction->sourceOperand[0].neg != 0;\n\t\tif( requiresFloatMove )\n\t\t{\n\t\t\t// abs/neg operations are applied to source operand, do float based move\n\t\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\t\tsrc->add(\" = \");\n\t\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\t\tsrc->add(\" = \");\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, outputType);\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MOVA_FLOOR )\n\t{\n\t\tcemu_assert_debug(aluInstruction->writeMask == 0);\n\t\tcemu_assert_debug(aluInstruction->omod == 0);\n\t\tsrc->add(\"tempResultf = \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\";\" _CRLF);\n\t\tsrc->add(\"tempResultf = floor(tempResultf);\" _CRLF);\n\t\tsrc->add(\"tempResultf = clamp(tempResultf, -256.0, 255.0);\" _CRLF);\n\t\t// set AR\n\t\tif( aluInstruction->destElem == 0 )\n\t\t\tsrc->add(\"ARi.x = int(tempResultf);\" _CRLF);\n\t\telse if( aluInstruction->destElem == 1 )\n\t\t\tsrc->add(\"ARi.y = int(tempResultf);\" _CRLF);\n\t\telse if( aluInstruction->destElem == 2 )\n\t\t\tsrc->add(\"ARi.z = int(tempResultf);\" _CRLF);\n\t\telse \n\t\t\tsrc->add(\"ARi.w = int(tempResultf);\" _CRLF);\n\t\t// set output\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\tif( outputType != LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\tdebugBreakpoint(); // todo\n\t\tsrc->add(\"floatBitsToInt(tempResultf)\");\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MOVA_INT )\n\t{\n\t\tcemu_assert_debug(aluInstruction->writeMask == 0);\n\t\tcemu_assert_debug(aluInstruction->omod == 0);\n\t\tsrc->add(\"tempResulti = \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\";\" _CRLF);\n\t\tsrc->add(\"tempResulti = clamp(tempResulti, -256, 255);\" _CRLF);\n\t\t// set AR\n\t\tif( aluInstruction->destElem == 0 )\n\t\t\tsrc->add(\"ARi.x = tempResulti;\" _CRLF);\n\t\telse if( aluInstruction->destElem == 1 )\n\t\t\tsrc->add(\"ARi.y = tempResulti;\" _CRLF);\n\t\telse if( aluInstruction->destElem == 2 )\n\t\t\tsrc->add(\"ARi.z = tempResulti;\" _CRLF);\n\t\telse \n\t\t\tsrc->add(\"ARi.w = tempResulti;\" _CRLF);\n\t\t// set output\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\tif( outputType != LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\tdebugBreakpoint(); // todo\n\t\tsrc->add(\"tempResulti\");\n\t\tsrc->add(\";\" _CRLF);\n\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_ADD )\n\t{\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_FLOAT>(shaderContext, aluInstruction, \" + \");\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MUL )\n\t{\n\t\t// 0*anything is always 0\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\n\t\t// if any operand is a non-zero literal or constant we can use standard multiplication\n\t\tbool useDefaultMul = false;\n\t\tif (GPU7_ALU_SRC_IS_CONST_0F(aluInstruction->sourceOperand[0].sel) || GPU7_ALU_SRC_IS_CONST_0F(aluInstruction->sourceOperand[1].sel))\n\t\t{\n\t\t\t// result is always zero\n\t\t\tsrc->add(\"0.0\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// multiply\n\t\t\tif (GPU7_ALU_SRC_IS_LITERAL(aluInstruction->sourceOperand[0].sel) || GPU7_ALU_SRC_IS_LITERAL(aluInstruction->sourceOperand[1].sel) ||\n\t\t\t\tGPU7_ALU_SRC_IS_ANY_CONST(aluInstruction->sourceOperand[0].sel) || GPU7_ALU_SRC_IS_ANY_CONST(aluInstruction->sourceOperand[1].sel))\n\t\t\t{\n\t\t\t\tuseDefaultMul = true;\n\t\t\t}\n\t\t\tif (shaderContext->options->strictMul && useDefaultMul == false)\n\t\t\t{\n\t\t\t\tsrc->add(\"mul_nonIEEE(\");\n\t\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t\tsrc->add(\", \");\n\t\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t\tsrc->add(\")\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t\tsrc->add(\" * \");\n\t\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t}\n\t\t}\n\t\t\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MUL_IEEE )\n\t{\n\t\t// 0*anything according to IEEE rules\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_FLOAT>(shaderContext, aluInstruction, \" * \");\n\t}\n\telse if (aluInstruction->opcode == ALU_OP2_INST_RECIP_IEEE)\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"1.0\");\n\t\tsrc->add(\" / \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if (aluInstruction->opcode == ALU_OP2_INST_RECIP_FF)\n\t{\n\t\t// untested (BotW bombs)\n\t\tsrc->add(\"tempResultf = 1.0 / (\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\");\" _CRLF);\n\t\t// INF becomes 0.0\n\t\tsrc->add(\"if( isinf(tempResultf) == true && (floatBitsToInt(tempResultf)&0x80000000) == 0 ) tempResultf = 0.0;\" _CRLF);\n\t\t// -INF becomes -0.0\n\t\tsrc->add(\"else if( isinf(tempResultf) == true && (floatBitsToInt(tempResultf)&0x80000000) != 0 ) tempResultf = -0.0;\" _CRLF);\n\t\t// assign result to output\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"tempResultf\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_RECIPSQRT_IEEE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_RECIPSQRT_CLAMPED ||\n\t\taluInstruction->opcode == ALU_OP2_INST_RECIPSQRT_FF )\n\t{\n\t\t// todo: This should be correct but testing is needed\n\t\tsrc->add(\"tempResultf = 1.0 / sqrt(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\");\" _CRLF);\n\t\tif (aluInstruction->opcode == ALU_OP2_INST_RECIPSQRT_CLAMPED)\n\t\t{\n\t\t\t// note: if( -INF < 0.0 ) does not resolve to true\n\t\t\tsrc->add(\"if( isinf(tempResultf) == true && (floatBitsToInt(tempResultf)&0x80000000) != 0 ) tempResultf = -3.40282347E+38F;\" _CRLF);\n\t\t\tsrc->add(\"else if( isinf(tempResultf) == true && (floatBitsToInt(tempResultf)&0x80000000) == 0 ) tempResultf = 3.40282347E+38F;\" _CRLF);\n\t\t}\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_RECIPSQRT_FF)\n\t\t{\n\t\t\t// untested (BotW bombs)\n\t\t\tsrc->add(\"if( isinf(tempResultf) == true && (floatBitsToInt(tempResultf)&0x80000000) != 0 ) tempResultf = -0.0;\" _CRLF);\n\t\t\tsrc->add(\"else if( isinf(tempResultf) == true && (floatBitsToInt(tempResultf)&0x80000000) == 0 ) tempResultf = 0.0;\" _CRLF);\n\t\t}\n\t\t// assign result to output\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"tempResultf\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MAX ||\n\t\taluInstruction->opcode == ALU_OP2_INST_MIN ||\n\t\taluInstruction->opcode == ALU_OP2_INST_MAX_DX10 ||\n\t\taluInstruction->opcode == ALU_OP2_INST_MIN_DX10 )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_MAX )\n\t\t\tsrc->add(\"max\");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_MIN )\n\t\t\tsrc->add(\"min\");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_MAX_DX10)\n\t\t\tsrc->add(\"max\");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_MIN_DX10)\n\t\t\tsrc->add(\"min\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\", \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_FLOOR ||\n\t\taluInstruction->opcode == ALU_OP2_INST_FRACT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_TRUNC )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_FLOOR )\n\t\t\tsrc->add(\"floor\");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_FRACT )\n\t\t\tsrc->add(\"fract\");\n\t\telse\n\t\t\tsrc->add(\"trunc\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_LOG_CLAMPED ||\n\t\taluInstruction->opcode == ALU_OP2_INST_LOG_IEEE )\n\t{\n\t\tsrc->add(\"tempResultf = max(0.0, \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\");\" _CRLF);\n\n\t\tsrc->add(\"tempResultf = log2(tempResultf);\" _CRLF);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_LOG_CLAMPED )\n\t\t{\n\t\t\tsrc->add(\"if( isinf(tempResultf) == true ) tempResultf = -3.40282347E+38F;\" _CRLF);\n\t\t}\n\t\t// assign result to output\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"tempResultf\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_RNDNE )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"roundEven\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_EXP_IEEE )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"exp2\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SQRT_IEEE )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"sqrt\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SIN ||\n\t\taluInstruction->opcode == ALU_OP2_INST_COS )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_SIN )\n\t\t\tsrc->add(\"sin\");\n\t\telse\n\t\t\tsrc->add(\"cos\");\n\t\tsrc->add(\"((\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")/0.1591549367)\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_FLT_TO_INT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"int\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_FLT_TO_UINT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_UNSIGNED_INT, outputType);\n\t\tsrc->add(\"uint\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_UNSIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_INT_TO_FLOAT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"float(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_UINT_TO_FLOAT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"float(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_UNSIGNED_INT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if (aluInstruction->opcode == ALU_OP2_INST_AND_INT)\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" & \");\n\telse if (aluInstruction->opcode == ALU_OP2_INST_OR_INT)\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" | \");\n\telse if (aluInstruction->opcode == ALU_OP2_INST_XOR_INT)\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" ^ \");\n\telse if( aluInstruction->opcode == ALU_OP2_INST_NOT_INT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"~(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_ADD_INT )\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" + \");\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MAX_INT || aluInstruction->opcode == ALU_OP2_INST_MIN_INT ||\n\t\t\t aluInstruction->opcode == ALU_OP2_INST_MAX_UINT || aluInstruction->opcode == ALU_OP2_INST_MIN_UINT)\n\t{\n\t\t// not verified\n\t\tbool isUnsigned = aluInstruction->opcode == ALU_OP2_INST_MAX_UINT || aluInstruction->opcode == ALU_OP2_INST_MIN_UINT;\n\t\tauto opType = isUnsigned ? LATTE_DECOMPILER_DTYPE_UNSIGNED_INT : LATTE_DECOMPILER_DTYPE_SIGNED_INT;\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, opType, outputType);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_MAX_INT || aluInstruction->opcode == ALU_OP2_INST_MAX_UINT )\n\t\t\tsrc->add(\"max(\");\n\t\telse\n\t\t\tsrc->add(\"min(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, opType);\n\t\tsrc->add(\", \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, opType);\n\t\t_emitTypeConversionSuffix(shaderContext, opType, outputType);\n\t\tsrc->add(\");\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SUB_INT )\n\t{\n\t\t// note: The AMD doc says src1 is on the left side but tests indicate otherwise. It's src0 - src1.\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" - \");\n\t}\n\telse if (aluInstruction->opcode == ALU_OP2_INST_MULLO_INT)\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" * \");\n\telse if (aluInstruction->opcode == ALU_OP2_INST_MULLO_UINT)\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_UNSIGNED_INT>(shaderContext, aluInstruction, \" * \");\n\telse if( aluInstruction->opcode == ALU_OP2_INST_LSHL_INT )\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" << \");\n\telse if( aluInstruction->opcode == ALU_OP2_INST_LSHR_INT )\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" >> \");\n\telse if( aluInstruction->opcode == ALU_OP2_INST_ASHR_INT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\" >> \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETGE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETNE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETE )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_SETGT )\n\t\t\tsrc->add(\" > \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGE )\n\t\t\tsrc->add(\" >= \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_SETNE)\n\t\t\tsrc->add(\" != \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_SETE)\n\t\t\tsrc->add(\" == \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")?1.0:0.0\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGT_DX10 ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETE_DX10 ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETNE_DX10 ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETGE_DX10 )\n\t{\n\t\tif( aluInstruction->omod != 0 )\n\t\t\tdebugBreakpoint();\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"((\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_SETE_DX10 )\n\t\t\tsrc->add(\" == \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETNE_DX10 )\n\t\t\tsrc->add(\" != \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGT_DX10 )\n\t\t\tsrc->add(\" > \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGE_DX10 )\n\t\t\tsrc->add(\" >= \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")?-1:0)\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\");\n\t\tsrc->add(_CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SETE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETNE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETGT_INT || \n\t\taluInstruction->opcode == ALU_OP2_INST_SETGE_INT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_SETE_INT )\n\t\t\tsrc->add(\" == \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETNE_INT )\n\t\t\tsrc->add(\" != \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGT_INT )\n\t\t\tsrc->add(\" > \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGE_INT )\n\t\t\tsrc->add(\" >= \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\")?-1:0\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGE_UINT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETGT_UINT )\n\t{\n\t\t// todo: Unsure if the result is unsigned or signed\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_UNSIGNED_INT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_SETGE_UINT )\n\t\t\tsrc->add(\" >= \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGT_UINT )\n\t\t\tsrc->add(\" > \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_UNSIGNED_INT);\n\t\tsrc->add(\")?int(0xFFFFFFFF):int(0x0)\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_PRED_SETGT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETGE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETNE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETNE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETGE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETGT_INT )\n\t{\n\t\tcemu_assert_debug(aluInstruction->writeMask == 0);\n\t\tbool isIntPred = (aluInstruction->opcode == ALU_OP2_INST_PRED_SETNE_INT) || (aluInstruction->opcode == ALU_OP2_INST_PRED_SETE_INT) || (aluInstruction->opcode == ALU_OP2_INST_PRED_SETGE_INT) || (aluInstruction->opcode == ALU_OP2_INST_PRED_SETGT_INT);\n\n\t\tsrc->add(\"predResult\");\n\t\tsrc->add(\" = (\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, isIntPred?LATTE_DECOMPILER_DTYPE_SIGNED_INT:LATTE_DECOMPILER_DTYPE_FLOAT);\n\n\t\tif (aluInstruction->opcode == ALU_OP2_INST_PRED_SETE || aluInstruction->opcode == ALU_OP2_INST_PRED_SETE_INT)\n\t\t\tsrc->add(\" == \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_PRED_SETGT || aluInstruction->opcode == ALU_OP2_INST_PRED_SETGT_INT)\n\t\t\tsrc->add(\" > \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_PRED_SETGE || aluInstruction->opcode == ALU_OP2_INST_PRED_SETGE_INT)\n\t\t\tsrc->add(\" >= \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_PRED_SETNE || aluInstruction->opcode == ALU_OP2_INST_PRED_SETNE_INT)\n\t\t\tsrc->add(\" != \");\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, isIntPred?LATTE_DECOMPILER_DTYPE_SIGNED_INT:LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\");\" _CRLF);\n\t\t// handle result of predicate instruction based on current ALU clause type\n\t\tif( cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE )\n\t\t{\n\t\t\tsrc->addFmt(\"{} = predResult;\" _CRLF, _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t\tsrc->addFmt(\"{} = predResult == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t}\n\t\telse if( cfInstruction->type == GPU7_CF_INST_ALU_BREAK )\n\t\t{\n\t\t\t// leave current loop\n\t\t\tsrc->add(\"if( predResult == false ) break;\" _CRLF);\n\t\t}\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_KILLE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_KILLNE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_KILLGT_INT)\n\t{\n\t\tsrc->add(\"if( \");\n\t\tsrc->add(\" (\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_KILLE_INT )\n\t\t\tsrc->add(\" == \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_KILLNE_INT)\n\t\t\tsrc->add(\" != \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_KILLGT_INT)\n\t\t\tsrc->add(\" > \");\n\t\telse\n\t\t\tdebugBreakpoint();\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\")\");\n\t\tsrc->add(\") discard;\");\n\t\tsrc->add(_CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_KILLGT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_KILLGE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_KILLE )\n\t{\n\t\tsrc->add(\"if( \");\n\t\tsrc->add(\" (\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_KILLGT )\n\t\t\tsrc->add(\" > \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_KILLGE )\n\t\t\tsrc->add(\" >= \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_KILLE )\n\t\t\tsrc->add(\" == \");\n\t\telse\n\t\t\tdebugBreakpoint();\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\tsrc->add(\") discard;\");\n\t\tsrc->add(_CRLF);\n\t}\n\telse\n\t{\n\t\tsrc->add(\"Unsupported instruction;\" _CRLF);\n\t\tdebug_printf(\"Unsupported ALU op2 instruction 0x%x\\n\", aluInstruction->opcode);\n\t\tshaderContext->shader->hasError = true;\n\t}\n}\n\nvoid _emitALUOP3InstructionCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, LatteDecompilerALUInstruction* aluInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tcemu_assert_debug(aluInstruction->destRel == 0); // todo\n\tsint32 outputType = _getALUInstructionOutputDataType(shaderContext, aluInstruction);\n\n\t/* check for common no-op or mov-like instructions */\n\tif (aluInstruction->opcode == ALU_OP3_INST_CMOVGE || \n\t\taluInstruction->opcode == ALU_OP3_INST_CMOVE || \n\t\taluInstruction->opcode == ALU_OP3_INST_CMOVGT || \n\t\taluInstruction->opcode == ALU_OP3_INST_CNDE_INT || \n\t\taluInstruction->opcode == ALU_OP3_INST_CNDGT_INT || \n\t\taluInstruction->opcode == ALU_OP3_INST_CMOVGE_INT)\n\t{\n\t\tif (_isSameGPROperand(aluInstruction, 1, 2) && !_operandHasModifiers(aluInstruction, 1))\n\t\t{\n\t\t\t// the condition is irrelevant as both operands are the same\n\t\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\t\tsrc->add(\" = \");\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, outputType);\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t\treturn;\n\t\t}\n\t}\n\n\n\t/* generic handlers */\n\tif( aluInstruction->opcode == ALU_OP3_INST_MULADD ||\n\t\taluInstruction->opcode == ALU_OP3_INST_MULADD_D2 ||\n\t\taluInstruction->opcode == ALU_OP3_INST_MULADD_M2 ||\n\t\taluInstruction->opcode == ALU_OP3_INST_MULADD_M4 ||\n\t\taluInstruction->opcode == ALU_OP3_INST_MULADD_IEEE )\n\t{\n\t\t// todo: The difference between MULADD and MULADD IEEE is that the former has 0*anything=0 rule similar to MUL/MUL_IEEE?\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tif (aluInstruction->opcode != ALU_OP3_INST_MULADD) // avoid unnecessary parenthesis to improve code readability slightly\n\t\t\tsrc->add(\"(\");\n\t\t\n\t\tbool useDefaultMul = false;\n\t\tif (GPU7_ALU_SRC_IS_LITERAL(aluInstruction->sourceOperand[0].sel) || GPU7_ALU_SRC_IS_LITERAL(aluInstruction->sourceOperand[1].sel) ||\n\t\t\tGPU7_ALU_SRC_IS_ANY_CONST(aluInstruction->sourceOperand[0].sel) || GPU7_ALU_SRC_IS_ANY_CONST(aluInstruction->sourceOperand[1].sel))\n\t\t{\n\t\t\tuseDefaultMul = true;\n\t\t}\n\t\tif (aluInstruction->opcode == ALU_OP3_INST_MULADD_IEEE)\n\t\t\tuseDefaultMul = true;\n\n\t\tif (shaderContext->options->strictMul && useDefaultMul == false)\n\t\t{\n\t\t\tsrc->add(\"mul_nonIEEE(\");\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\",\");\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\")\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\" * \");\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t}\n\n\t\tsrc->add(\" + \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 2, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tif(aluInstruction->opcode != ALU_OP3_INST_MULADD)\n\t\t\tsrc->add(\")\");\n\t\tif( aluInstruction->opcode == ALU_OP3_INST_MULADD_D2 )\n\t\t\tsrc->add(\"/2.0\");\n\t\telse if( aluInstruction->opcode == ALU_OP3_INST_MULADD_M2 )\n\t\t\tsrc->add(\"*2.0\");\n\t\telse if( aluInstruction->opcode == ALU_OP3_INST_MULADD_M4 )\n\t\t\tsrc->add(\"*4.0\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if(aluInstruction->opcode == ALU_OP3_INST_CNDE_INT || aluInstruction->opcode == ALU_OP3_INST_CNDGT_INT || aluInstruction->opcode == ALU_OP3_INST_CMOVGE_INT)\n\t{\n\t\tbool requiresFloatResult = (aluInstruction->sourceOperand[1].neg != 0) || (aluInstruction->sourceOperand[2].neg != 0);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, requiresFloatResult?LATTE_DECOMPILER_DTYPE_FLOAT:LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"((\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tif (aluInstruction->opcode == ALU_OP3_INST_CNDE_INT)\n\t\t\tsrc->add(\" == \");\n\t\telse if (aluInstruction->opcode == ALU_OP3_INST_CNDGT_INT)\n\t\t\tsrc->add(\" > \");\n\t\telse if (aluInstruction->opcode == ALU_OP3_INST_CMOVGE_INT)\n\t\t\tsrc->add(\" >= \");\n\t\tsrc->add(\"0)?(\");\n\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, requiresFloatResult?LATTE_DECOMPILER_DTYPE_FLOAT:LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\"):(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 2, requiresFloatResult?LATTE_DECOMPILER_DTYPE_FLOAT:LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\"))\");\n\t\t_emitTypeConversionSuffix(shaderContext, requiresFloatResult?LATTE_DECOMPILER_DTYPE_FLOAT:LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP3_INST_CMOVGE ||\n\t\taluInstruction->opcode == ALU_OP3_INST_CMOVE ||\n\t\taluInstruction->opcode == ALU_OP3_INST_CMOVGT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"((\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tif (aluInstruction->opcode == ALU_OP3_INST_CMOVE)\n\t\t\tsrc->add(\" == \");\n\t\telse if (aluInstruction->opcode == ALU_OP3_INST_CMOVGE)\n\t\t\tsrc->add(\" >= \");\n\t\telse if (aluInstruction->opcode == ALU_OP3_INST_CMOVGT)\n\t\t\tsrc->add(\" > \");\n\t\tsrc->add(\"0.0)?(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\"):(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 2, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\"))\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse\n\t{\n\t\tsrc->add(\"Unsupported instruction;\" _CRLF);\n\t\tdebug_printf(\"Unsupported ALU op3 instruction 0x%x\\n\", aluInstruction->opcode);\n\t\tshaderContext->shader->hasError = true;\n\t}\n}\n\nvoid _emitALUReductionInstructionCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluRedcInstruction[4])\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif( aluRedcInstruction[0]->isOP3 == false && (aluRedcInstruction[0]->opcode == ALU_OP2_INST_DOT4 || aluRedcInstruction[0]->opcode == ALU_OP2_INST_DOT4_IEEE) )\n\t{\n\t\t// todo: Figure out and implement the difference between normal DOT4 and DOT4_IEEE\n\t\tsint32 outputType = _getALUInstructionOutputDataType(shaderContext, aluRedcInstruction[0]);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[0]);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\n\t\t// dot(vec4(op0),vec4(op1))\n\t\tsrc->add(\"dot(vec4(\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[0], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[1], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[2], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[3], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\t\n\t\tsrc->add(\"),vec4(\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[0], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[1], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[2], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[3], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\"))\");\n\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluRedcInstruction[0]->isOP3 == false && (aluRedcInstruction[0]->opcode == ALU_OP2_INST_CUBE) )\n\t{\n\t\t/*\n\t\t * How the CUBE instruction works (guessed mostly, based on DirectX/OpenGL spec):\n\t\t   Input: vec4, 3d direction vector (can be unnormalized) + w component (which can be ignored, since it only scales the vector but does not affect the direction)\n\t\n\t\t   First we figure out the major axis (closest axis-aligned vector). There are six possible vectors:\n\t\t   +rx\t0\n\t\t   -rx\t1\n\t\t   +ry\t2\n\t\t   -ry\t3\n\t\t   +rz\t4\n\t\t   -rz\t5\n\t\t   The major axis vector is calculated by looking at the largest (absolute) 3d vector component and then setting the other components to 0.0\n\t\t   The value that remains in the axis vector is referred to as 'MajorAxis' by the AMD documentation.\n\t\t   The S,T coordinates are taken from the other two components.\n\t\t   Example:\t-0.5,0.2,0.4 -> -rx -> -0.5,0.0,0.0 MajorAxis: -0.5, S: 0.2 T: 0.4\n\n\t\t   The CUBE reduction instruction requires a specific mapping for the input vector:\n\t\t   src0 = Rn.zzxy \n\t\t   src1 = Rn.yxzz\n\t\t   It's probably related to the way the instruction works internally?\n\t\t   If we look at the individual components per ALU unit:\n\t\t   z y\t-> Compare y/z\n\t\t   z x  -> Compare x/z\n\t\t   x z  -> Compare x/z\n\t\t   y z  -> Compare y/z\n\t\t*/\n\n\t\tsint32 outputType;\n\n\t\tsrc->add(\"redcCUBE(\");\n\t\tsrc->add(\"vec4(\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[0], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[1], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[2], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[3], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\"),\");\n\t\tsrc->add(\"vec4(\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[0], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[1], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[2], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[3], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\"),\");\n\t\tsrc->add(\"cubeMapSTM,cubeMapFaceId);\" _CRLF);\n\n\t\t// dst.X (S)\n\t\toutputType = _getALUInstructionOutputDataType(shaderContext, aluRedcInstruction[0]);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[0]);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"cubeMapSTM.x\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t\t// dst.Y (T)\n\t\toutputType = _getALUInstructionOutputDataType(shaderContext, aluRedcInstruction[1]);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[1]);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"cubeMapSTM.y\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t\t// dst.Z (MajorAxis)\n\t\toutputType = _getALUInstructionOutputDataType(shaderContext, aluRedcInstruction[2]);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[2]);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"cubeMapSTM.z\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t\t// dst.W (FaceId)\n\t\toutputType = _getALUInstructionOutputDataType(shaderContext, aluRedcInstruction[3]);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[3]);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"cubeMapFaceId\");\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\nvoid _emitALUClauseRegisterBackupCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, sint32 startIndex)\n{\n\tsint32 instructionGroupIndex = cfInstruction->instructionsALU[startIndex].instructionGroupIndex;\n\tsize_t groupSize = 1;\n\twhile ((startIndex + groupSize) < cfInstruction->instructionsALU.size())\n\t{\n\t\tif (instructionGroupIndex != cfInstruction->instructionsALU[startIndex + groupSize].instructionGroupIndex)\n\t\t\tbreak;\n\t\tgroupSize++;\n\t}\n\tshaderContext->aluPVPSState->CreateGPRTemporaries(shaderContext, { cfInstruction->instructionsALU.data() + startIndex, groupSize });\n}\n\n/*\nbool _isPVUsedInNextGroup(LatteDecompilerCFInstruction* cfInstruction, sint32 startIndex, sint32 pvUnit)\n{\n\tsint32 currentGroupIndex = cfInstruction->instructionsALU[startIndex].instructionGroupIndex;\n\tfor (sint32 i = startIndex + 1; i < (sint32)cfInstruction->instructionsALU.size(); i++)\n\t{\n\t\tLatteDecompilerALUInstruction& aluInstructionItr = cfInstruction->instructionsALU[i];\n\t\tif(aluInstructionItr.instructionGroupIndex == currentGroupIndex )\n\t\t\tcontinue;\n\t\tif ((sint32)aluInstructionItr.instructionGroupIndex > currentGroupIndex + 1)\n\t\t\treturn false;\n\t\t// check OP code type\n\t\tif (aluInstructionItr.isOP3)\n\t\t{\n\t\t\t// op0\n\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstructionItr.sourceOperand[0].sel))\n\t\t\t{\n\t\t\t\tuint32 chan = aluInstructionItr.sourceOperand[0].chan;\n\t\t\t\tif (pvUnit == chan)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// op1\n\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstructionItr.sourceOperand[1].sel))\n\t\t\t{\n\t\t\t\tuint32 chan = aluInstructionItr.sourceOperand[1].chan;\n\t\t\t\tif (pvUnit == chan)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// op2\n\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstructionItr.sourceOperand[2].sel))\n\t\t\t{\n\t\t\t\tuint32 chan = aluInstructionItr.sourceOperand[2].chan;\n\t\t\t\tif (pvUnit == chan)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// op0\n\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstructionItr.sourceOperand[0].sel))\n\t\t\t{\n\t\t\t\tuint32 chan = aluInstructionItr.sourceOperand[0].chan;\n\t\t\t\tif (pvUnit == chan)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// op1\n\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstructionItr.sourceOperand[1].sel))\n\t\t\t{\n\t\t\t\tuint32 chan = aluInstructionItr.sourceOperand[1].chan;\n\t\t\t\tif (pvUnit == chan)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// todo: Not all operations use both operands\n\t\t}\n\t}\n\treturn false;\n}\n*/\n\nvoid _emitVec3(LatteDecompilerShaderContext* shaderContext, uint32 dataType, LatteDecompilerALUInstruction* aluInst0, sint32 opIdx0, LatteDecompilerALUInstruction* aluInst1, sint32 opIdx1, LatteDecompilerALUInstruction* aluInst2, sint32 opIdx2)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t{\n\t\tsrc->add(\"vec3(\");\n\t\t_emitOperandInputCode(shaderContext, aluInst0, opIdx0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluInst1, opIdx1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluInst2, opIdx2, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t}\n\telse if (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t{\n\t\tsrc->add(\"ivec3(\");\n\t\t_emitOperandInputCode(shaderContext, aluInst0, opIdx0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluInst1, opIdx1, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluInst2, opIdx2, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\")\");\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\nvoid _emitGPRVectorAssignment(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction** aluInstructions, sint32 count)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\t// output var name (GPR)\n\tsrc->add(_getRegisterVarName(shaderContext, aluInstructions[0]->destGpr, -1));\n\tsrc->add(\".\");\n\tfor (sint32 f = 0; f < count; f++)\n\t{\n\t\tsrc->add(_getElementStrByIndex(aluInstructions[f]->destElem));\n\t}\n\tsrc->add(\" = \");\n}\n\nvoid _emitALUClauseCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tALUClauseTemporariesState pvpsState;\n\tshaderContext->aluPVPSState = &pvpsState;\n\tStringBuf* src = shaderContext->shaderSource;\n\tLatteDecompilerALUInstruction* aluRedcInstruction[4];\n\tsize_t groupStartIndex = 0;\n\tfor(size_t i=0; i<cfInstruction->instructionsALU.size(); i++)\n\t{\n\t\tLatteDecompilerALUInstruction& aluInstruction = cfInstruction->instructionsALU[i];\n\t\tif( aluInstruction.indexInGroup == 0 )\n\t\t{\n\t\t\tsrc->addFmt(\"// {}\" _CRLF, aluInstruction.instructionGroupIndex);\n\t\t\t// apply PV/PS updates for previous group\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\tpvpsState.TrackGroupOutputPVPS(shaderContext, cfInstruction->instructionsALU.data() + groupStartIndex, i - groupStartIndex);\n\t\t\t}\n\t\t\tgroupStartIndex = i;\n\t\t\t// backup registers which are read after being written\n\t\t\t_emitALUClauseRegisterBackupCode(shaderContext, cfInstruction, i);\n\t\t}\n\t\t// detect reduction instructions and use a special handler\n\t\tbool isReductionOperation = _isReductionInstruction(&aluInstruction);\n\t\tif( isReductionOperation )\n\t\t{\n\t\t\tcemu_assert_debug((i + 4) <= cfInstruction->instructionsALU.size());\n\t\t\taluRedcInstruction[0] = &aluInstruction;\n\t\t\taluRedcInstruction[1] = &cfInstruction->instructionsALU[i + 1];\n\t\t\taluRedcInstruction[2] = &cfInstruction->instructionsALU[i + 2];\n\t\t\taluRedcInstruction[3] = &cfInstruction->instructionsALU[i + 3];\n\t\t\tif( aluRedcInstruction[0]->isOP3 != aluRedcInstruction[1]->isOP3 || aluRedcInstruction[1]->isOP3 != aluRedcInstruction[2]->isOP3 || aluRedcInstruction[2]->isOP3 != aluRedcInstruction[3]->isOP3 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tif( aluRedcInstruction[0]->opcode != aluRedcInstruction[1]->opcode || aluRedcInstruction[1]->opcode != aluRedcInstruction[2]->opcode || aluRedcInstruction[2]->opcode != aluRedcInstruction[3]->opcode )\n\t\t\t\tdebugBreakpoint();\n\t\t\tif( aluRedcInstruction[0]->omod != aluRedcInstruction[1]->omod || aluRedcInstruction[1]->omod != aluRedcInstruction[2]->omod || aluRedcInstruction[2]->omod != aluRedcInstruction[3]->omod )\n\t\t\t\tdebugBreakpoint();\n\t\t\tif( aluRedcInstruction[0]->destClamp != aluRedcInstruction[1]->destClamp || aluRedcInstruction[1]->destClamp != aluRedcInstruction[2]->destClamp || aluRedcInstruction[2]->destClamp != aluRedcInstruction[3]->destClamp )\n\t\t\t\tdebugBreakpoint();\n\t\t\t_emitALUReductionInstructionCode(shaderContext, aluRedcInstruction);\n\t\t\ti += 3; // skip the instructions that are part of the reduction operation\n\t\t}\n\t\telse /* not a reduction operation */\n\t\t{\n\t\t\tif( aluInstruction.isOP3 )\n\t\t\t{\n\t\t\t\t// op3\n\t\t\t\t_emitALUOP3InstructionCode(shaderContext, cfInstruction, &aluInstruction);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// op2\n\t\t\t\tif( aluInstruction.opcode == ALU_OP2_INST_NOP )\n\t\t\t\t\tcontinue; // skip NOP instruction\n\t\t\t\t_emitALUOP2InstructionCode(shaderContext, cfInstruction, &aluInstruction);\n\t\t\t}\n\t\t}\n\t\t// handle omod\n\t\tsint32 outputDataType = _getALUInstructionOutputDataType(shaderContext, &aluInstruction);\n\t\tif( aluInstruction.omod != ALU_OMOD_NONE )\n\t\t{\n\t\t\tif( outputDataType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\t\t{\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tif( aluInstruction.omod == ALU_OMOD_MUL2 )\n\t\t\t\t\tsrc->add(\" *= 2.0;\" _CRLF);\n\t\t\t\telse if( aluInstruction.omod == ALU_OMOD_MUL4 )\n\t\t\t\t\tsrc->add(\" *= 4.0;\" _CRLF);\n\t\t\t\telse if( aluInstruction.omod == ALU_OMOD_DIV2 )\n\t\t\t\t\tsrc->add(\" /= 2.0;\" _CRLF);\n\t\t\t}\n\t\t\telse if( outputDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t{\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\" = \");\n\t\t\t\tsrc->add(\"floatBitsToInt(intBitsToFloat(\");\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\")\");\n\t\t\t\tif( aluInstruction.omod == 1 )\n\t\t\t\t\tsrc->add(\" * 2.0\");\n\t\t\t\telse if( aluInstruction.omod == 2 )\n\t\t\t\t\tsrc->add(\" * 4.0\");\n\t\t\t\telse if( aluInstruction.omod == 3 )\n\t\t\t\t\tsrc->add(\" / 2.0\");\n\t\t\t\tsrc->add(\");\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t\t// handle clamp\n\t\tif( aluInstruction.destClamp != 0 )\n\t\t{\n\t\t\tif( outputDataType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\t\t{\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\" = clamp(\");\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\", 0.0, 1.0);\" _CRLF);\n\t\t\t}\n\t\t\telse if( outputDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t{\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\" = clampFI32(\");\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\");\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t\t// handle result broadcasting for reduction instructions\n\t\tif( isReductionOperation )\n\t\t{\n\t\t\t// reduction operations set all four PV components (todo: Needs further research. According to AMD docs, dot4 only sets PV.x? update: Unlike DOT4, CUBE sets all PV elements accordingly to their GPR output?)\n\t\t\tif( aluRedcInstruction[0]->opcode == ALU_OP2_INST_CUBE )\n\t\t\t{\n\t\t\t\t// CUBE\n\t\t\t\tfor (sint32 f = 0; f < 4; f++)\n\t\t\t\t{\n\t\t\t\t\tif (aluRedcInstruction[f]->writeMask != 0)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t_emitInstructionPVPSOutputVariableName(shaderContext, aluRedcInstruction[f]);\n\t\t\t\t\tsrc->add(\" = \");\n\t\t\t\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[0]);\n\t\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// DOT4, DOT4_IEEE, etc.\n\t\t\t\t// reduction operation result is only set for output in redc[0], we also need to update redc[1] to redc[3]\n\t\t\t\tfor(sint32 f=0; f<4; f++)\n\t\t\t\t{\n\t\t\t\t\tif( aluRedcInstruction[f]->writeMask == 0 )\n\t\t\t\t\t\t_emitInstructionPVPSOutputVariableName(shaderContext, aluRedcInstruction[f]);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (f == 0)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[f]);\n\t\t\t\t\t}\n\t\t\t\t\tsrc->add(\" = \");\n\t\t\t\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[0]);\n\t\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tshaderContext->aluPVPSState = nullptr;\n}\n\n/*\n * Emits code to access one component (xyzw) of the texture coordinate input vector\n */\nvoid _emitTEXSampleCoordInputComponent(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction, sint32 componentIndex, sint32 interpretSrcAsType)\n{\n\tcemu_assert(componentIndex >= 0 && componentIndex < 4);\n\tcemu_assert_debug(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_SIGNED_INT || interpretSrcAsType == LATTE_DECOMPILER_DTYPE_FLOAT);\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 elementSel = texInstruction->textureFetch.srcSel[componentIndex];\n\tif (elementSel < 4)\n\t{\n\t\t_emitRegisterChannelAccessCode(shaderContext, texInstruction->srcGpr, elementSel, interpretSrcAsType);\n\t\treturn;\n\t}\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tif(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t{\n\t\tif( elementSel == 4 )\n\t\t\tsrc->add(\"floatBitsToInt(0.0)\");\n\t\telse if( elementSel == 5 )\n\t\t\tsrc->add(\"floatBitsToInt(1.0)\");\n\t}\n\telse if(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t{\n\t\tif( elementSel == 4 )\n\t\t\tsrc->add(\"0.0\");\n\t\telse if( elementSel == 5 )\n\t\t\tsrc->add(\"1.0\");\n\t}\n}\n\nconst char* _texGprAccessElemTable[8] = {\"x\",\"y\",\"z\",\"w\",\"_\",\"_\",\"_\",\"_\"};\n\nchar* _getTexGPRAccess(LatteDecompilerShaderContext* shaderContext, sint32 gprIndex, uint32 dataType, sint8 selX, sint8 selY, sint8 selZ, sint8 selW, char* tempBuffer)\n{\n\t// intBitsToFloat(R{}i.w)\n\t*tempBuffer = '\\0';\n\tuint8 elemCount = (selX > 0 ? 1 : 0) + (selY > 0 ? 1 : 0) + (selZ > 0 ? 1 : 0) + (selW > 0 ? 1 : 0);\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t{\n\t\tif (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t; // no conversion\n\t\telse if (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\tstrcat(tempBuffer, \"intBitsToFloat(\");\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t\tstrcat(tempBuffer, _getRegisterVarName(shaderContext, gprIndex));\n\t\t// _texGprAccessElemTable\n\t\tstrcat(tempBuffer, \".\");\n\t\tif (selX >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selX]);\n\t\tif (selY >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selY]);\n\t\tif (selZ >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selZ]);\n\t\tif (selW >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selW]);\n\t\tif (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t; // no conversion\n\t\telse if (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\tstrcat(tempBuffer, \")\");\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t{\n\t\tif (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\tcemu_assert_unimplemented();\n\t\telse if (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t; // no conversion\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t\tstrcat(tempBuffer, _getRegisterVarName(shaderContext, gprIndex));\n\t\t// _texGprAccessElemTable\n\t\tstrcat(tempBuffer, \".\");\n\t\tif (selX >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selX]);\n\t\tif (selY >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selY]);\n\t\tif (selZ >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selZ]);\n\t\tif (selW >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selW]);\n\t\tif (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\tcemu_assert_unimplemented();\n\t\telse if (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t; // no conversion\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n\treturn tempBuffer;\n}\n\nvoid _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif (texInstruction->textureFetch.textureIndex < 0 || texInstruction->textureFetch.textureIndex >= LATTE_NUM_MAX_TEX_UNITS)\n\t{\n\t\t// skip out of bounds texture unit access\n\t\treturn;\n\t}\n\n\tauto texDim = shaderContext->shader->textureUnitDim[texInstruction->textureFetch.textureIndex];\n\n\tchar tempBuffer0[32];\n\tchar tempBuffer1[32];\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\tsrc->add(\".\");\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tsint32 numWrittenElements = 0;\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\t// texture sampler opcode\n\tuint32 texOpcode = texInstruction->opcode;\n\tif (shaderContext->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n\t\t// vertex shader forces LOD to zero, but certain sampler types don't support textureLod(...) API\n\t\tif (texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ)\n\t\t\ttexOpcode = GPU7_TEX_INST_SAMPLE_C;\n\t}\n\t// check if offset is used\n\tbool hasOffset = false;\n\tif( texInstruction->textureFetch.offsetX != 0 || texInstruction->textureFetch.offsetY != 0 || texInstruction->textureFetch.offsetZ != 0 )\n\t\thasOffset = true;\n\t// emit sample code\n\tif (shaderContext->shader->textureIsIntegerFormat[texInstruction->textureFetch.textureIndex])\n\t{\n\t\t// integer samplers\n\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT) // uint to int\n\t\t{\n\t\t\tif(numWrittenElements == 1)\n\t\t\t\tsrc->add(\" = int(\");\n\t\t\telse\n\t\t\t\tshaderContext->shaderSource->addFmt(\" = ivec{}(\", numWrittenElements);\n\t\t}\n\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\tsrc->add(\" = uintBitsToFloat(\");\n\t}\n\telse\n\t{\n\t\t// float samplers\n\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\tsrc->add(\" = floatBitsToInt(\");\n\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\tsrc->add(\" = (\");\n\t}\n\n\tbool unnormalizationHandled = false;\n\tbool useTexelCoordinates = false;\n\n\t// handle illegal combinations\n\tif (texOpcode == GPU7_TEX_INST_FETCH4 && (texDim == Latte::E_DIM::DIM_1D || texDim == Latte::E_DIM::DIM_1D_ARRAY))\n\t{\n\t\t// fetch4 is not allowed on 1D textures\n\t\t// seen in YWW during boss fight of Level 1-4\n\t\t// todo - investigate what this returns on actual HW\n\t\tif (numWrittenElements == 1)\n\t\t\tshaderContext->shaderSource->add(\"0.0\");\n\t\telse\n\t\t\tshaderContext->shaderSource->addFmt(\"vec{}(0.0)\", numWrittenElements);\n\t\tshaderContext->shaderSource->add(\");\" _CRLF);\n\t\treturn;\n\t}\n\n\n\tif (texOpcode == GPU7_TEX_INST_SAMPLE && (texInstruction->textureFetch.unnormalized[0] && texInstruction->textureFetch.unnormalized[1] && texInstruction->textureFetch.unnormalized[2] && texInstruction->textureFetch.unnormalized[3]) )\n\t{\n\t\t// texture is likely a RECT\n\t\tif (hasOffset)\n\t\t\tcemu_assert_unimplemented();\n\t\tsrc->add(\"texelFetch(\");\n\t\tunnormalizationHandled = true;\n\t\tuseTexelCoordinates = true;\n\t}\n\telse if( texOpcode == GPU7_TEX_INST_FETCH4 )\n\t{\n\t\tif( hasOffset )\n\t\t\tcemu_assert_unimplemented();\n\t\tsrc->add(\"textureGather(\");\n\t}\n\telse if( texOpcode == GPU7_TEX_INST_LD )\n\t{\n\t\tif( hasOffset )\n\t\t\tcemu_assert_unimplemented();\n\t\tsrc->add(\"texelFetch(\");\n\t\tunnormalizationHandled = true;\n\t\tuseTexelCoordinates = true;\n\t}\n\telse if( texOpcode == GPU7_TEX_INST_SAMPLE_L )\n\t{\n\t\t// sample with LOD value set in gpr.w (replaces computed LOD value)\n\t\tif( hasOffset )\n\t\t\tsrc->add(\"textureLodOffset(\");\n\t\telse\n\t\t\tsrc->add(\"textureLod(\");\n\t}\n\telse if (texOpcode == GPU7_TEX_INST_SAMPLE_LZ)\n\t{\n\t\t// sample with LOD set to 0.0 (replaces computed LOD value)\n\t\tif (hasOffset)\n\t\t\tsrc->add(\"textureLodOffset(\");\n\t\telse\n\t\t\tsrc->add(\"textureLod(\");\n\t}\n\telse if (texOpcode == GPU7_TEX_INST_SAMPLE_LB)\n\t{\n\t\t// sample with LOD biased\n\t\t// note: AMD doc says LOD bias is calculated from instruction LOD_BIAS field. But it appears that LOD bias is taken from input register. Might actually be both?\n\t\tif (hasOffset)\n\t\t\tsrc->add(\"textureOffset(\");\n\t\telse\n\t\t\tsrc->add(\"texture(\");\n\t}\n\telse if (texOpcode == GPU7_TEX_INST_SAMPLE)\n\t{\n\t\tif (hasOffset)\n\t\t\tsrc->add(\"textureOffset(\");\n\t\telse\n\t\t\tsrc->add(\"texture(\");\n\t}\n\telse if (texOpcode == GPU7_TEX_INST_SAMPLE_C_L)\n\t{\n\t\t// sample with LOD value set in gpr.w (replaces computed LOD value)\n\t\tif (hasOffset)\n\t\t\tsrc->add(\"textureLodOffset(\");\n\t\telse\n\t\t\tsrc->add(\"textureLod(\");\n\t}\n\telse if (texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ)\n\t{\n\t\t// sample with LOD set to 0.0 (replaces computed LOD value)\n\t\tif (hasOffset)\n\t\t\tsrc->add(\"textureLodOffset(\");\n\t\telse\n\t\t\tsrc->add(\"textureLod(\");\n\t}\n\telse if (texOpcode == GPU7_TEX_INST_SAMPLE_C)\n\t{\n\t\tif (hasOffset)\n\t\t\tsrc->add(\"textureOffset(\");\n\t\telse\n\t\t\tsrc->add(\"texture(\");\n\t}\n\telse if (texOpcode == GPU7_TEX_INST_SAMPLE_G)\n\t{\n\t\tif (hasOffset)\n\t\t\tcemu_assert_unimplemented();\n\t\tsrc->add(\"textureGrad(\");\n\t}\n\telse\n\t{\n\t\tif( hasOffset )\n\t\t\tcemu_assert_unimplemented();\n\t\tcemu_assert_unimplemented();\n\t\tsrc->add(\"texture(\");\n\t}\n\tsrc->addFmt(\"{}{}, \", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex);\n\n\t// for textureGather() add shift (todo: depends on rounding mode set in sampler registers?)\n\tif (texOpcode == GPU7_TEX_INST_FETCH4)\n\t{\n\t\tif (texDim == Latte::E_DIM::DIM_2D)\n\t\t{\n\t\t\t//src->addFmt2(\"(vec2(-0.1) / vec2(textureSize({}{},0).xy)) + \", gpu7Decompiler_getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureIndex);\n\t\t\t\n\t\t\t// vec2(-0.00001) is minimum to break Nvidia\n\t\t\t// vec2(0.0001) is minimum to fix shadows on Intel, also fixes it on AMD (Windows and Linux)\n\n\t\t\t// todo - emulating coordinate rounding mode correctly is tricky\n\t\t\t// GX2 supports two modes: Truncate or rounding according to DX9 rules\n\t\t\t// Vulkan uses truncate mode when point sampling (min and mag is both nearest) otherwise it uses rounding\n\t\t\t\n\t\t\t// adding a small fixed bias is enough to avoid vendor-specific cases where small inaccuracies cause the number to get rounded down due to truncation\n\t\t\tsrc->addFmt(\"vec2(0.0001) + \");\n\t\t}\n\t}\n\n\tconst sint32 texCoordDataType = (texOpcode == GPU7_TEX_INST_LD) ? LATTE_DECOMPILER_DTYPE_SIGNED_INT : LATTE_DECOMPILER_DTYPE_FLOAT;\n\tif(useTexelCoordinates)\n\t{\n\t\t// handle integer coordinates for texelFetch\n\t\tif (texDim == Latte::E_DIM::DIM_2D || texDim == Latte::E_DIM::DIM_2D_MSAA)\n\t\t{\n\t\t\tsrc->add(\"ivec2(\");\n\t\t\tsrc->add(\"vec2(\");\n\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, texCoordDataType);\n\t\t\tsrc->addFmt(\", \");\n\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, texCoordDataType);\n\n\t\t\tsrc->addFmt(\")*uf_tex{}Scale\", texInstruction->textureFetch.textureIndex); // close vec2 and scale\n\n\t\t\tsrc->add(\"), 0\"); // close ivec2 and lod param\n\t\t\t// todo - lod\n\t\t}\n\t\telse if (texDim == Latte::E_DIM::DIM_1D)\n\t\t{\n\t\t\t// VC DS games forget to initialize textures and use texel fetch on an uninitialized texture (a dim of 0 maps to 1D)\n\t\t\tsrc->add(\"int(\");\n\t\t\tsrc->add(\"float(\");\n\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, (texOpcode == GPU7_TEX_INST_LD) ? LATTE_DECOMPILER_DTYPE_SIGNED_INT : LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->addFmt(\")*uf_tex{}Scale.x\", texInstruction->textureFetch.textureIndex);\n\t\t\tsrc->add(\"), 0\");\n\t\t\t// todo - lod\n\t\t}\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\t}\n\telse /* useTexelCoordinates == false */\n\t{\n\t\t// float coordinates\n\t\tif ( (texOpcode == GPU7_TEX_INST_SAMPLE_C || texOpcode == GPU7_TEX_INST_SAMPLE_C_L || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ) )\n\t\t{\n\t\t\t// shadow sampler\n\t\t\tif (texDim == Latte::E_DIM::DIM_2D_ARRAY)\n\t\t\t{\n\t\t\t\t// 3 coords + compare value (as vec4)\n\t\t\t\tsrc->add(\"vec4(\");\n\t\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t\tsrc->add(\",\");\n\t\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t\tsrc->add(\",\");\n\t\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 2, LATTE_DECOMPILER_DTYPE_FLOAT);\n\n\t\t\t\tsrc->addFmt(\",{})\", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[3], -1, -1, -1, tempBuffer0));\n\t\t\t}\n\t\t\telse if (texDim == Latte::E_DIM::DIM_CUBEMAP)\n\t\t\t{\n\t\t\t\t// 2 coords + faceId\n\t\t\t\tif (texInstruction->textureFetch.srcSel[0] >= 4 || texInstruction->textureFetch.srcSel[1] >= 4)\n\t\t\t\t{\n\t\t\t\t\tdebugBreakpoint();\n\t\t\t\t}\n\t\t\t\tsrc->add(\"vec4(\");\n\t\t\t\tsrc->addFmt(\"redcCUBEReverse({},\", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], -1, -1, tempBuffer0));\n\t\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 2, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\t\t\tsrc->addFmt(\")\");\n\t\t\t\tsrc->addFmt(\",cubeMapArrayIndex{})\", texInstruction->textureFetch.textureIndex); // cubemap index\n\t\t\t}\n\t\t\telse if (texDim == Latte::E_DIM::DIM_1D)\n\t\t\t{\n\t\t\t\t// 1 coord + 1 unused coord (per GLSL spec) + compare value\n\t\t\t\tif (texInstruction->textureFetch.srcSel[0] >= 4)\n\t\t\t\t{\n\t\t\t\t\tdebugBreakpoint();\n\t\t\t\t}\n\t\t\t\tsrc->addFmt(\"vec3({},0.0,{})\", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], -1, -1, -1, tempBuffer0), _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[3], -1, -1, -1, tempBuffer1));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// 2 coords + compare value (as vec3)\n\t\t\t\tif (texInstruction->textureFetch.srcSel[0] >= 4 && texInstruction->textureFetch.srcSel[1] >= 4)\n\t\t\t\t{\n\t\t\t\t\tdebugBreakpoint();\n\t\t\t\t}\n\t\t\t\tsrc->addFmt(\"vec3({}, {})\", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], -1, -1, tempBuffer0), _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[3], -1, -1, -1, tempBuffer1));\n\t\t\t}\n\t\t}\n\t\telse if( texDim == Latte::E_DIM::DIM_3D || texDim == Latte::E_DIM::DIM_2D_ARRAY )\n\t\t{\n\t\t\t// 3 coords\n\t\t\tsrc->add(\"vec3(\");\n\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\",\");\n\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\",\");\n\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 2, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\")\");\n\t\t}\n\t\telse if( texDim == Latte::E_DIM::DIM_CUBEMAP )\n\t\t{\n\t\t\t// 2 coords + faceId\n\t\t\tcemu_assert_debug(texInstruction->textureFetch.srcSel[0] < 4);\n\t\t\tcemu_assert_debug(texInstruction->textureFetch.srcSel[1] < 4);\n\t\t\tsrc->add(\"vec4(\");\n\t\t\tsrc->addFmt(\"redcCUBEReverse({},\", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], -1, -1, tempBuffer0));\n\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 2, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\t\tsrc->add(\")\");\n\t\t\tsrc->addFmt(\",cubeMapArrayIndex{})\", texInstruction->textureFetch.textureIndex); // cubemap index\n\t\t}\n\t\telse if( texDim == Latte::E_DIM::DIM_1D )\n\t\t{\n\t\t\t// 1 coord\n\t\t\tsrc->add(_getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], -1, -1, -1, tempBuffer0));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// 2 coords\n\t\t\tsrc->add(\"vec2(\");\n\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\",\");\n\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\")\");\n\t\t\t// avoid truncate to effectively round downwards on texel edges\n\t\t\tif (ActiveSettings::ForceSamplerRoundToPrecision())\n\t\t\t\tsrc->addFmt(\"+ vec2(1.0)/vec2(textureSize({}{}, 0))/512.0\", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex);\n\t\t}\n\t\t// lod or lod bias parameter\n\t\tif( texOpcode == GPU7_TEX_INST_SAMPLE_L || texOpcode == GPU7_TEX_INST_SAMPLE_LB || texOpcode == GPU7_TEX_INST_SAMPLE_C_L)\n\t\t{\n\t\t\tsrc->add(\",\");\n\t\t\tif(texOpcode == GPU7_TEX_INST_SAMPLE_LB)\n\t\t\t\tsrc->add(_FormatFloatAsGLSLConstant((float)texInstruction->textureFetch.lodBias / 16.0f));\n\t\t\telse\n\t\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 3, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t}\n\t\telse if( texOpcode == GPU7_TEX_INST_SAMPLE_LZ || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ )\n\t\t{\n\t\t\tsrc->add(\",0.0\");\n\t\t}\n\t}\n\t// gradient parameters\n\tif (texOpcode == GPU7_TEX_INST_SAMPLE_G)\n\t{\n\t\tif (texDim == Latte::E_DIM::DIM_2D ||\n\t\t\ttexDim == Latte::E_DIM::DIM_1D )\n\t\t{\n\t\t\tsrc->add(\",gradH.xy,gradV.xy\");\n\t\t}\n\t\telse\t\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\t// offset\n\tif( texOpcode == GPU7_TEX_INST_SAMPLE_L || texOpcode == GPU7_TEX_INST_SAMPLE_LZ || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ || texOpcode == GPU7_TEX_INST_SAMPLE || texOpcode == GPU7_TEX_INST_SAMPLE_C )\n\t{\n\t\tif( hasOffset )\n\t\t{\n\t\t\tuint8 offsetComponentCount = 0;\n\t\t\tif( texDim == Latte::E_DIM::DIM_1D )\n\t\t\t\toffsetComponentCount = 1;\n\t\t\telse if( texDim == Latte::E_DIM::DIM_2D )\n\t\t\t\toffsetComponentCount = 2;\n\t\t\telse if( texDim == Latte::E_DIM::DIM_3D )\n\t\t\t\toffsetComponentCount = 3;\n\t\t\telse if( texDim == Latte::E_DIM::DIM_2D_ARRAY )\n\t\t\t\toffsetComponentCount = 2;\n\t\t\telse\n\t\t\t\tcemu_assert_unimplemented();\n\n\t\t\tif( (texInstruction->textureFetch.offsetX&1) )\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\tif( (texInstruction->textureFetch.offsetY&1) )\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\tif ((texInstruction->textureFetch.offsetZ & 1))\n\t\t\t\tcemu_assert_unimplemented();\n\n\t\t\tif( offsetComponentCount == 1 )\n\t\t\t\tsrc->addFmt(\",{}\", texInstruction->textureFetch.offsetX/2);\n\t\t\telse if( offsetComponentCount == 2 )\n\t\t\t\tsrc->addFmt(\",ivec2({},{})\", texInstruction->textureFetch.offsetX/2, texInstruction->textureFetch.offsetY/2, texInstruction->textureFetch.offsetZ/2);\n\t\t\telse if( offsetComponentCount == 3 )\n\t\t\t\tsrc->addFmt(\",ivec3({},{},{})\", texInstruction->textureFetch.offsetX/2, texInstruction->textureFetch.offsetY/2, texInstruction->textureFetch.offsetZ/2);\n\t\t}\n\t}\n\t// lod bias\n\tif( texOpcode == GPU7_TEX_INST_SAMPLE_C || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ )\n\t{\n\t\tsrc->add(\")\");\n\n\t\tif (numWrittenElements > 1)\n\t\t{\n\t\t\t// result is copied into multiple channels\n\t\t\tsrc->add(\".\");\n\t\t\tfor (sint32 f = 0; f < numWrittenElements; f++)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(texInstruction->dstSel[f] == 0); // only x component is defined\n\t\t\t\tsrc->add(\"x\");\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tsrc->add(\").\");\n\t\tfor (sint32 f = 0; f < 4; f++)\n\t\t{\n\t\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t\t{\n\t\t\t\tuint8 elemIndex = texInstruction->dstSel[f];\n\t\t\t\tif (texOpcode == GPU7_TEX_INST_FETCH4)\n\t\t\t\t{\n\t\t\t\t\t// GLSL's textureGather() and GPU7's FETCH4 instruction have a different order of elements\n\t\t\t\t\t// xyzw: top-left, top-right, bottom-right, bottom-left\n\t\t\t\t\t// textureGather\txyzw\n\t\t\t\t\t// fetch4\t\t\tyzxw\n\t\t\t\t\t// translate index from fetch4 to textureGather order\n\t\t\t\t\tstatic uint8 fetchToGather[4] =\n\t\t\t\t\t{\n\t\t\t\t\t\t2, // x -> z\n\t\t\t\t\t\t0, // y -> x\n\t\t\t\t\t\t1, // z -> y\n\t\t\t\t\t\t3, // w -> w\n\t\t\t\t\t};\n\t\t\t\t\telemIndex = fetchToGather[elemIndex];\n\t\t\t\t}\n\t\t\t\tsrc->add(resultElemTable[elemIndex]);\n\t\t\t\tnumWrittenElements++;\n\t\t\t}\n\t\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t\t{\n\t\t\t\t// masked and not written\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t}\n\tsrc->add(\");\");\n\n\t// debug\n#ifdef CEMU_DEBUG_ASSERT\n\tif(texInstruction->opcode == GPU7_TEX_INST_LD )\n\t\tsrc->add(\" // TEX_INST_LD\");\n\telse if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE )\n\t\tsrc->add(\" // TEX_INST_SAMPLE\");\n\telse if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE_L )\n\t\tsrc->add(\" // TEX_INST_SAMPLE_L\");\n\telse if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE_LZ )\n\t\tsrc->add(\" // TEX_INST_SAMPLE_LZ\");\n\telse if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE_C )\n\t\tsrc->add(\" // TEX_INST_SAMPLE_C\");\n\telse if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE_G )\n\t\tsrc->add(\" // TEX_INST_SAMPLE_G\");\n\telse\n\t\tsrc->addFmt(\" // 0x{:02x}\", texInstruction->opcode);\n\tif (texInstruction->opcode != texOpcode)\n\t\tsrc->addFmt(\" (applied as 0x{:02x})\", texOpcode);\n\tsrc->addFmt(\" OffsetXYZ {:02x} {:02x} {:02x}\", (uint8)texInstruction->textureFetch.offsetX&0xFF, (uint8)texInstruction->textureFetch.offsetY&0xFF, (uint8)texInstruction->textureFetch.offsetZ&0xFF);\n#endif\n\tsrc->add(\"\" _CRLF);\n}\n\nvoid _emitTEXGetTextureResInfoCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->addFmt(\"R{}\", texInstruction->dstGpr);\n\tsrc->add(\"i\");\n\tsrc->add(\".\");\n\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tsint32 numWrittenElements = 0;\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\n\t// todo - mip index parameter?\n\n\tauto texDim = shaderContext->shader->textureUnitDim[texInstruction->textureFetch.textureIndex];\n\n\tif (texDim == Latte::E_DIM::DIM_1D)\n\t\tsrc->addFmt(\" = ivec4(textureSize({}{}, 0),1,1,1).\", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex);\n\telse if (texDim == Latte::E_DIM::DIM_1D_ARRAY)\n\t\tsrc->addFmt(\" = ivec4(textureSize({}{}, 0),1,1).\", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex);\n\telse if (texDim == Latte::E_DIM::DIM_2D || texDim == Latte::E_DIM::DIM_2D_MSAA)\n\t\tsrc->addFmt(\" = ivec4(textureSize({}{}, 0),1,1).\", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex);\n\telse if (texDim == Latte::E_DIM::DIM_2D_ARRAY)\n\t\tsrc->addFmt(\" = ivec4(textureSize({}{}, 0),1).\", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex);\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t\tsrc->addFmt(\" = ivec4(textureSize({}{}, 0),1,1).\", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex);\n\t}\n\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[texInstruction->dstSel[f]]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\tsrc->add(\";\" _CRLF);\n}\n\nvoid _emitTEXGetCompTexLodCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\tsrc->add(\".\");\n\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tsint32 numWrittenElements = 0;\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\n\tsrc->add(\" = \");\n\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, shaderContext->typeTracker.defaultDataType);\n\n\tif( shaderContext->shader->textureUnitDim[texInstruction->textureFetch.textureIndex] == Latte::E_DIM::DIM_CUBEMAP )\n\t{\n\t\t// 3 coordinates\n\t\tif(shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\tsrc->addFmt(\"vec4(textureQueryLod({}{}, {}.{}{}{}),0.0,0.0)\", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex, _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]], resultElemTable[texInstruction->textureFetch.srcSel[1]], resultElemTable[texInstruction->textureFetch.srcSel[2]]);\n\t\telse\n\t\t\tsrc->addFmt(\"vec4(textureQueryLod({}{}, intBitsToFloat({}.{}{}{})),0.0,0.0)\", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex, _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]], resultElemTable[texInstruction->textureFetch.srcSel[1]], resultElemTable[texInstruction->textureFetch.srcSel[2]]);\n\t}\n\telse\n\t{\n\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\tsrc->addFmt(\"vec4(textureQueryLod({}{}, {}.{}{}),0.0,0.0)\", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex, _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]], resultElemTable[texInstruction->textureFetch.srcSel[1]]);\n\t\telse\n\t\t\tsrc->addFmt(\"vec4(textureQueryLod({}{}, intBitsToFloat({}.{}{})),0.0,0.0)\", _getTextureUnitVariablePrefixName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex, _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]], resultElemTable[texInstruction->textureFetch.srcSel[1]]);\n\t\tdebugBreakpoint();\n\t}\n\n\n\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, shaderContext->typeTracker.defaultDataType);\n\tsrc->add(\".\");\n\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[texInstruction->dstSel[f]]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\tsrc->add(\";\" _CRLF);\n}\n\nvoid _emitTEXSetCubemapIndexCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->addFmt(\"cubeMapArrayIndex{}\", texInstruction->textureFetch.textureIndex);\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\tsrc->addFmt(\" = intBitsToFloat(R{}i.{});\" _CRLF, texInstruction->srcGpr, resultElemTable[texInstruction->textureFetch.srcSel[0]]);\n\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\tsrc->addFmt(\" = R{}f.{};\" _CRLF, texInstruction->srcGpr, resultElemTable[texInstruction->textureFetch.srcSel[0]]);\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\nvoid _emitTEXGetGradientsHV(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 componentCount = 0;\n\tfor (sint32 i = 0; i < 4; i++)\n\t{\n\t\tif(texInstruction->dstSel[i] == 7)\n\t\t\tcontinue;\n\t\tcomponentCount++;\n\t}\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\tsrc->add(\".\");\n\tconst char* resultElemTable[4] = { \"x\",\"y\",\"z\",\"w\" };\n\tsint32 numWrittenElements = 0;\n\tfor (sint32 f = 0; f < 4; f++)\n\t{\n\t\tif (texInstruction->dstSel[f] < 4)\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if (texInstruction->dstSel[f] == 7)\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\n\tconst char* funcName;\n\tif (texInstruction->opcode == GPU7_TEX_INST_GET_GRADIENTS_H)\n\t\tfuncName = \"dFdx\";\n\telse\n\t\tfuncName = \"dFdy\";\n\n\tsrc->add(\" = \");\n\n\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, shaderContext->typeTracker.defaultDataType);\n\n\tsrc->addFmt(\"{}(\", funcName);\n\t_emitRegisterAccessCode(shaderContext, texInstruction->srcGpr, (componentCount >= 1) ? texInstruction->textureFetch.srcSel[0] : -1, (componentCount >= 2) ? texInstruction->textureFetch.srcSel[1] : -1, (componentCount >= 3) ? texInstruction->textureFetch.srcSel[2] : -1, (componentCount >= 4)?texInstruction->textureFetch.srcSel[3]:-1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\n\tsrc->add(\")\");\n\n\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, shaderContext->typeTracker.defaultDataType);\n\n\tsrc->add(\";\" _CRLF);\n\n}\n\nvoid _emitTEXSetGradientsHV(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif (texInstruction->opcode == GPU7_TEX_INST_SET_GRADIENTS_H)\n\t\tsrc->add(\"gradH = \");\n\telse\n\t\tsrc->add(\"gradV = \");\n\n\t_emitRegisterAccessCode(shaderContext, texInstruction->srcGpr, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], texInstruction->textureFetch.srcSel[2], texInstruction->textureFetch.srcSel[3], LATTE_DECOMPILER_DTYPE_FLOAT);\n\n\tsrc->add(\";\" _CRLF);\n}\n\nvoid _emitGSReadInputVFetchCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\n\tsrc->add(\".\");\n\t\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tsint32 numWrittenElements = 0;\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\n\tsrc->add(\" = \");\n\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, shaderContext->typeTracker.defaultDataType);\n\tsrc->add(\"(v2g[\");\n\tif (texInstruction->textureFetch.srcSel[0] >= 4)\n\t\tcemu_assert_unimplemented();\n\tif (texInstruction->textureFetch.srcSel[1] >= 4)\n\t\tcemu_assert_unimplemented();\n\t// todo: Index type\n\tsrc->add(\"0\");\n\tsrc->addFmt(\"].passV2GParameter{}.\", texInstruction->textureFetch.offset/16);\n\n\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[texInstruction->dstSel[f]]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\tsrc->add(\")\");\n\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, shaderContext->typeTracker.defaultDataType);\n\tsrc->add(\";\" _CRLF);\n}\n\nsint32 _writeDestMaskXYZW(LatteDecompilerShaderContext* shaderContext, sint8* dstSel)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tconst char* resultElemTable[4] = { \"x\",\"y\",\"z\",\"w\" };\n\tsint32 numWrittenElements = 0;\n\tfor (sint32 f = 0; f < 4; f++)\n\t{\n\t\tif (dstSel[f] < 4)\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if (dstSel[f] == 7)\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\treturn numWrittenElements;\n}\n\nvoid _emitTEXVFetchCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\t// handle special case where geometry shader reads input attributes from vertex shader via ringbuffer\n\tStringBuf* src = shaderContext->shaderSource;\n\tif( texInstruction->textureFetch.textureIndex == 0x9F && shaderContext->shaderType == LatteConst::ShaderType::Geometry )\n\t{\n\t\t_emitGSReadInputVFetchCode(shaderContext, texInstruction);\n\t\treturn;\n\t}\n\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\tsrc->add(\".\");\n\n\t_writeDestMaskXYZW(shaderContext, texInstruction->dstSel);\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\n\tsrc->add(\" = \");\n\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\tsrc->add(\"floatBitsToInt(\");\n\telse\n\t\tsrc->add(\"(\");\n\n\tsrc->addFmt(\"{}{}[\", _getShaderUniformBlockVariableName(shaderContext->shader->shaderType), texInstruction->textureFetch.textureIndex - 0x80);\n\n\tif( shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\tsrc->addFmt(\"{}.{}\", _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]]);\n\telse\n\t\tsrc->addFmt(\"floatBitsToInt({}.{})\", _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]]);\n\tsrc->add(\"].\");\n\n\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[texInstruction->dstSel[f]]);\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\tsrc->add(\");\" _CRLF);\n}\n\nvoid _emitTEXReadMemCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\tsrc->add(\".\");\n\tsint32 count = _writeDestMaskXYZW(shaderContext, texInstruction->dstSel);\n\n\tsrc->add(\" = \");\n\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\tsrc->add(\"floatBitsToInt(\");\n\telse\n\t\tsrc->add(\"(\");\n\n\tsint32 readCount;\n\n\tif (texInstruction->memRead.format == FMT_32_FLOAT)\n\t{\n\t\treadCount = 1;\n\t\t// todo\n\t\tsrc->add(\"0.0\");\n\t}\n\telse if (texInstruction->memRead.format == FMT_32_32_FLOAT)\n\t{\n\t\treadCount = 2;\n\t\t// todo\n\t\tsrc->add(\"vec2(0.0,0.0)\");\n\t}\n\telse if (texInstruction->memRead.format == FMT_32_32_32_FLOAT)\n\t{\n\t\treadCount = 3;\n\t\t// todo\n\t\tsrc->add(\"vec3(0.0,0.0,0.0)\");\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\tif (count < readCount)\n\t{\n\t\tif (count == 1)\n\t\t\tsrc->add(\".x\");\n\t\telse if (count == 2)\n\t\t\tsrc->add(\".xy\");\n\t\telse if (count == 3)\n\t\t\tsrc->add(\".xyz\");\n\t}\n\tsrc->add(\");\" _CRLF);\n}\n\nvoid _emitTEXClauseCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tcemu_assert_debug(cfInstruction->instructionsALU.empty());\n\tfor(auto& texInstruction : cfInstruction->instructionsTEX)\n\t{\n\t\tif( texInstruction.opcode == GPU7_TEX_INST_SAMPLE || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_L || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_LB || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_LZ || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_C || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_C_L || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_C_LZ || texInstruction.opcode == GPU7_TEX_INST_FETCH4 || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_G || texInstruction.opcode == GPU7_TEX_INST_LD )\n\t\t\t_emitTEXSampleTextureCode(shaderContext, &texInstruction);\n\t\telse if( texInstruction.opcode == GPU7_TEX_INST_GET_TEXTURE_RESINFO )\n\t\t\t_emitTEXGetTextureResInfoCode(shaderContext, &texInstruction);\n\t\telse if( texInstruction.opcode == GPU7_TEX_INST_GET_COMP_TEX_LOD )\n\t\t\t_emitTEXGetCompTexLodCode(shaderContext, &texInstruction);\n\t\telse if( texInstruction.opcode == GPU7_TEX_INST_SET_CUBEMAP_INDEX )\n\t\t\t_emitTEXSetCubemapIndexCode(shaderContext, &texInstruction);\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_GET_GRADIENTS_H ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_GET_GRADIENTS_V)\n\t\t\t_emitTEXGetGradientsHV(shaderContext, &texInstruction);\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_SET_GRADIENTS_H ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_SET_GRADIENTS_V)\n\t\t\t_emitTEXSetGradientsHV(shaderContext, &texInstruction);\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_VFETCH)\n\t\t\t_emitTEXVFetchCode(shaderContext, &texInstruction);\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_MEM)\n\t\t\t_emitTEXReadMemCode(shaderContext, &texInstruction);\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n}\n\n// generate the code for reading the source input GPR (or constants) for exports\nvoid _emitExportGPRReadCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, sint32 requiredType, uint32 burstIndex)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tuint32 numOutputs = 4;\n\tif( cfInstruction->type == GPU7_CF_INST_MEM_RING_WRITE )\n\t{\n\t\tnumOutputs = (cfInstruction->memWriteCompMask&1)?1:0;\n\t\tnumOutputs += (cfInstruction->memWriteCompMask&2)?1:0;\n\t\tnumOutputs += (cfInstruction->memWriteCompMask&4)?1:0;\n\t\tnumOutputs += (cfInstruction->memWriteCompMask&8)?1:0;\n\t}\n\tif (requiredType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t{\n\t\tif(numOutputs == 1)\n\t\t\tsrc->add(\"float(\");\n\t\telse\n\t\t\tsrc->addFmt(\"vec{}(\", numOutputs);\n\t}\n\telse if (requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t{\n\t\tif (numOutputs == 1)\n\t\t\tsrc->add(\"int(\");\n\t\telse\n\t\t\tsrc->addFmt(\"ivec{}(\", numOutputs);\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n\tsint32 actualOutputs = 0;\n\tfor(sint32 i=0; i<4; i++)\n\t{\n\t\t// todo: Use type of register element based on information from type tracker (currently we assume it's always a signed integer)\n\t\tuint32 exportSel = 0;\n\t\tif( cfInstruction->type == GPU7_CF_INST_MEM_RING_WRITE )\n\t\t{\n\t\t\texportSel = i;\n\t\t\tif( (cfInstruction->memWriteCompMask&(1<<i)) == 0 )\n\t\t\t\tcontinue; // dont output\n\t\t}\n\t\telse\n\t\t{\n\t\t\texportSel = cfInstruction->exportComponentSel[i];\n\t\t}\n\t\tif( actualOutputs > 0 )\n\t\t\tsrc->add(\", \");\n\t\tactualOutputs++;\n\t\tif( exportSel < 4 )\n\t\t{\n\t\t\t_emitRegisterAccessCode(shaderContext, cfInstruction->exportSourceGPR+burstIndex, exportSel, -1, -1, -1, requiredType);\n\t\t}\n\t\telse if (exportSel == 4)\n\t\t{\n\t\t\t// constant zero\n\t\t\tsrc->add(\"0\");\n\t\t}\n\t\telse if (exportSel == 5)\n\t\t{\n\t\t\t// constant one\n\t\t\tsrc->add(\"1.0\");\n\t\t}\n\t\telse if( exportSel == 7 )\n\t\t{\n\t\t\t// element masked (which means 0 is exported?)\n\t\t\tsrc->add(\"0\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tsrc->add(\"0\");\n\t\t}\n\t}\n\tif( requiredType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\tsrc->add(\")\");\n\telse if( requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\tsrc->add(\")\");\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\nvoid _emitExportCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->add(\"// export\" _CRLF);\n\tif(shaderContext->shaderType == LatteConst::ShaderType::Vertex )\n\t{\n\t\tif( cfInstruction->exportBurstCount != 0 )\n\t\t\tdebugBreakpoint();\n\t\tif (cfInstruction->exportType == 1 && cfInstruction->exportArrayBase == GPU7_DECOMPILER_CF_EXPORT_BASE_POSITION)\n\t\t{\n\t\t\t// export position\n\t\t\t// GX2 special state 0 disables rasterizer viewport offset and scaling (probably, exact mechanism is not known). Handle this here\n\t\t\tbool hasAnyViewportScaleDisabled =\n\t\t\t\t!shaderContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_X_SCALE_ENA() ||\n\t\t\t\t!shaderContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Y_SCALE_ENA() ||\n\t\t\t\t!shaderContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Z_SCALE_ENA();\n\n\t\t\tif (hasAnyViewportScaleDisabled)\n\t\t\t{\n\t\t\t\tsrc->add(\"vec4 finalPos = \");\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, 0);\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t\tsrc->add(\"finalPos.xy = finalPos.xy * uf_windowSpaceToClipSpaceTransform - vec2(1.0,1.0);\");\n\t\t\t\tsrc->add(\"SET_POSITION(finalPos);\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->add(\"SET_POSITION(\");\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, 0);\n\t\t\t\tsrc->add(\");\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (cfInstruction->exportType == 1 && cfInstruction->exportArrayBase == GPU7_DECOMPILER_CF_EXPORT_POINT_SIZE )\n\t\t{\n\t\t\t// export gl_PointSize\n\t\t\tif (shaderContext->analyzer.outputPointSize)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(shaderContext->analyzer.writesPointSize);\n\t\t\t\tsrc->add(\"gl_PointSize = (\");\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, 0);\n\t\t\t\tsrc->add(\").x\");\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if( cfInstruction->exportType == 2 && cfInstruction->exportArrayBase < 32 )\n\t\t{\n\t\t\t// export parameter\n\t\t\tsint32 paramIndex = cfInstruction->exportArrayBase;\n\t\t\tuint32 vsSemanticId = _getVertexShaderOutParamSemanticId(shaderContext->contextRegisters, paramIndex);\n\t\t\tif (vsSemanticId != 0xFF)\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"passParameterSem{} = \", vsSemanticId);\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, 0);\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->add(\"// skipped export to semanticId 255\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse if(shaderContext->shaderType == LatteConst::ShaderType::Pixel )\n\t{\n\t\tif( cfInstruction->exportType == 0 && cfInstruction->exportArrayBase < 8 )\n\t\t{\n\t\t\tfor(uint32 i=0; i<(cfInstruction->exportBurstCount+1); i++)\n\t\t\t{\n\t\t\t\tsint32 pixelColorOutputIndex = LatteDecompiler_getColorOutputIndexFromExportIndex(shaderContext, cfInstruction->exportArrayBase+i);\n\t\t\t\t// if color output is for target 0, then also handle alpha test\n\t\t\t\tbool alphaTestEnable = shaderContext->contextRegistersNew->SX_ALPHA_TEST_CONTROL.get_ALPHA_TEST_ENABLE();\n\t\t\t\tauto alphaTestFunc = shaderContext->contextRegistersNew->SX_ALPHA_TEST_CONTROL.get_ALPHA_FUNC();\n\t\t\t\tif( pixelColorOutputIndex == 0 && alphaTestEnable && alphaTestFunc == Latte::E_COMPAREFUNC::NEVER )\n\t\t\t\t{\n\t\t\t\t\t// never pass alpha test\n\t\t\t\t\tsrc->add(\"discard;\" _CRLF);\n\t\t\t\t}\n\t\t\t\telse if( pixelColorOutputIndex == 0 && alphaTestEnable && alphaTestFunc != Latte::E_COMPAREFUNC::ALWAYS)\n\t\t\t\t{\n\t\t\t\t\tsrc->add(\"if( ((\");\n\t\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, i);\n\t\t\t\t\tsrc->add(\").a \");\n\n\t\t\t\t\tswitch( alphaTestFunc )\n\t\t\t\t\t{\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::LESS:\n\t\t\t\t\t\tsrc->add(\"<\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::EQUAL:\n\t\t\t\t\t\tsrc->add(\"==\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::LEQUAL:\n\t\t\t\t\t\tsrc->add(\"<=\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::GREATER:\n\t\t\t\t\t\tsrc->add(\">\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::NOTEQUAL:\n\t\t\t\t\t\tsrc->add(\"!=\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::GEQUAL:\n\t\t\t\t\t\tsrc->add(\">=\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tsrc->add(\" uf_alphaTestRef\");\n\t\t\t\t\tsrc->add(\") == false) discard;\" _CRLF);\n\t\t\t\t}\n\t\t\t\t// pixel color output\n\t\t\t\tsrc->addFmt(\"passPixelColor{} = \", pixelColorOutputIndex);\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, i);\n\t\t\t\tsrc->add(\";\" _CRLF);\n\n\t\t\t\tif( cfInstruction->exportArrayBase+i >= 8 )\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t\telse if( cfInstruction->exportType == 0 && cfInstruction->exportArrayBase == 61 )\n\t\t{\n\t\t\t// pixel depth or gl_FragStencilRefARB\n\t\t\tif( cfInstruction->exportBurstCount > 0 )\n\t\t\t\tcemu_assert_unimplemented();\n\n\t\t\tif (cfInstruction->exportComponentSel[0] == 7)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented(); // gl_FragDepth ?\n\t\t\t}\n\t\t\tif (cfInstruction->exportComponentSel[1] != 7)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented(); // exporting to gl_FragStencilRefARB\n\t\t\t}\n\t\t\tif (cfInstruction->exportComponentSel[2] != 7)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented(); // ukn\n\t\t\t}\n\t\t\tif (cfInstruction->exportComponentSel[3] != 7)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented(); // ukn\n\t\t\t}\n\n\t\t\tsrc->add(\"gl_FragDepth = \");\n\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, 0);\n\t\t\tsrc->add(\".x\");\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n}\n\nvoid _emitXYZWByMask(StringBuf* src, uint32 mask)\n{\n\tif( (mask&(1<<0)) != 0 )\n\t\tsrc->add(\"x\");\n\tif( (mask&(1<<1)) != 0 )\n\t\tsrc->add(\"y\");\n\tif( (mask&(1<<2)) != 0 )\n\t\tsrc->add(\"z\");\n\tif( (mask&(1<<3)) != 0 )\n\t\tsrc->add(\"w\");\n}\n\nvoid _emitCFRingWriteCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\t// calculate parameter output (based on ring buffer output offset relative to GS unit)\n\tuint32 bytesPerVertex = shaderContext->contextRegisters[mmSQ_GS_VERT_ITEMSIZE] * 4;\n\tbytesPerVertex = std::max(bytesPerVertex, (uint32)1); // avoid division by zero\n\tuint32 parameterOffset = ((cfInstruction->exportArrayBase * 4) % bytesPerVertex);\n\t// for geometry shaders with streamout, MEM_RING_WRITE is used to pass the data to the copy shader, which then uses STREAM*_WRITE\n\tif (shaderContext->shaderType == LatteConst::ShaderType::Geometry && shaderContext->analyzer.hasStreamoutEnable)\n\t{\n\t\t// if streamout is enabled, we generate transform feedback output code instead of the normal gs output\n\t\tfor (uint32 burstIndex = 0; burstIndex < (cfInstruction->exportBurstCount + 1); burstIndex++)\n\t\t{\n\t\t\tparameterOffset = ((cfInstruction->exportArrayBase * 4 + burstIndex*0x10) % bytesPerVertex);\n\t\t\t// find matching stream write in copy shader\n\t\t\tLatteGSCopyShaderStreamWrite_t* streamWrite = nullptr;\n\t\t\tfor (auto& it : shaderContext->parsedGSCopyShader->list_streamWrites)\n\t\t\t{\n\t\t\t\tif (it.offset == parameterOffset)\n\t\t\t\t{\n\t\t\t\t\tstreamWrite = &it;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (streamWrite == nullptr)\n\t\t\t{\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (sint32 i = 0; i < 4; i++)\n\t\t\t{\n\t\t\t\tif ((cfInstruction->memWriteCompMask&(1 << i)) == 0)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (shaderContext->options->useTFViaSSBO)\n\t\t\t\t{\n\t\t\t\t\tuint32 u32Offset = streamWrite->exportArrayBase + i;\n\t\t\t\t\tsrc->addFmt(\"sb_buffer[sbBase{} + {}]\", streamWrite->bufferIndex, u32Offset);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tsrc->addFmt(\"sb{}[{}]\", streamWrite->bufferIndex, streamWrite->exportArrayBase + i);\n\t\t\t\t}\n\n\t\t\t\tsrc->add(\" = \");\n\n\t\t\t\t_emitTypeConversionPrefix(shaderContext, shaderContext->typeTracker.defaultDataType, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\n\t\t\t\tsrc->addFmt(\"{}.\", _getRegisterVarName(shaderContext, cfInstruction->exportSourceGPR+burstIndex));\n\t\t\t\tif (i == 0)\n\t\t\t\t\tsrc->add(\"x\");\n\t\t\t\telse if (i == 1)\n\t\t\t\t\tsrc->add(\"y\");\n\t\t\t\telse if (i == 2)\n\t\t\t\t\tsrc->add(\"z\");\n\t\t\t\telse if (i == 3)\n\t\t\t\t\tsrc->add(\"w\");\n\n\t\t\t\t_emitTypeConversionSuffix(shaderContext, shaderContext->typeTracker.defaultDataType, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\n\tif (shaderContext->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n\t\tif (cfInstruction->memWriteElemSize != 3)\n\t\t\tcemu_assert_unimplemented();\n\t\tif ((cfInstruction->exportArrayBase & 3) != 0)\n\t\t\tcemu_assert_unimplemented();\n\t\tfor (sint32 burstIndex = 0; burstIndex < (sint32)(cfInstruction->exportBurstCount + 1); burstIndex++)\n\t\t{\n\t\t\tsrc->addFmt(\"v2g.passV2GParameter{}.\", (cfInstruction->exportArrayBase) / 4 + burstIndex);\n\t\t\t_emitXYZWByMask(src, cfInstruction->memWriteCompMask);\n\t\t\tsrc->addFmt(\" = \");\n\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_SIGNED_INT, burstIndex);\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t}\n\telse if (shaderContext->shaderType == LatteConst::ShaderType::Geometry)\n\t{\n\t\tcemu_assert_debug(cfInstruction->memWriteElemSize == 3);\n\t\t//if (cfInstruction->memWriteElemSize != 3)\n\t\t//\tdebugBreakpoint();\n\t\tcemu_assert_debug((cfInstruction->exportArrayBase & 3) == 0);\n\n\t\tfor (uint32 burstIndex = 0; burstIndex < (cfInstruction->exportBurstCount + 1); burstIndex++)\n\t\t{\n\t\t\tuint32 parameterExportType = 0;\n\t\t\tuint32 parameterExportBase = 0;\n\t\t\tif (LatteGSCopyShaderParser_getExportTypeByOffset(shaderContext->parsedGSCopyShader, parameterOffset + burstIndex * (cfInstruction->memWriteElemSize+1)*4, &parameterExportType, &parameterExportBase) == false)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tshaderContext->hasError = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (parameterExportType == 1 && parameterExportBase == GPU7_DECOMPILER_CF_EXPORT_BASE_POSITION)\n\t\t\t{\n\t\t\t\tsrc->add(\"{\" _CRLF);\n\t\t\t\tsrc->addFmt(\"vec4 pos = vec4(0.0,0.0,0.0,1.0);\" _CRLF);\n\t\t\t\tsrc->addFmt(\"pos.\");\n\t\t\t\t_emitXYZWByMask(src, cfInstruction->memWriteCompMask);\n\t\t\t\tsrc->addFmt(\" = \");\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, burstIndex);\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t\tsrc->add(\"SET_POSITION(pos);\" _CRLF);\n\t\t\t\tsrc->add(\"}\" _CRLF);\n\t\t\t}\n\t\t\telse if (parameterExportType == 2 && parameterExportBase < 16)\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"passG2PParameter{}.\", parameterExportBase);\n\t\t\t\t_emitXYZWByMask(src, cfInstruction->memWriteCompMask);\n\t\t\t\tsrc->addFmt(\" = \");\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, burstIndex);\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\telse\n\t\tdebugBreakpoint(); // todo\n}\n\nvoid _emitStreamWriteCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif (shaderContext->analyzer.hasStreamoutEnable == false)\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tsrc->add(\"// omitted streamout write\" _CRLF);\n#endif\n\t\treturn;\n\t}\n\tuint32 streamoutBufferIndex;\n\tif (cfInstruction->type == GPU7_CF_INST_MEM_STREAM0_WRITE)\n\t\tstreamoutBufferIndex = 0;\n\telse if (cfInstruction->type == GPU7_CF_INST_MEM_STREAM1_WRITE)\n\t\tstreamoutBufferIndex = 1;\n\telse\n\t\tcemu_assert_unimplemented();\n\n\tif (shaderContext->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n\t\tuint32 arraySize = cfInstruction->memWriteArraySize + 1;\n\n\t\tfor (sint32 i = 0; i < (sint32)arraySize; i++)\n\t\t{\n\t\t\tif ((cfInstruction->memWriteCompMask&(1 << i)) == 0)\n\t\t\t\tcontinue;\n\n\t\t\tif (shaderContext->options->useTFViaSSBO)\n\t\t\t{\n\t\t\t\tuint32 u32Offset = cfInstruction->exportArrayBase + i;\n\t\t\t\tsrc->addFmt(\"sb_buffer[sbBase{} + {}]\", streamoutBufferIndex, u32Offset);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"sb{}[{}]\", streamoutBufferIndex, cfInstruction->exportArrayBase + i);\n\t\t\t}\n\n\t\t\tsrc->add(\" = \");\n\n\t\t\t_emitTypeConversionPrefix(shaderContext, shaderContext->typeTracker.defaultDataType, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\n\t\t\tsrc->add(_getRegisterVarName(shaderContext, cfInstruction->exportSourceGPR));\n\t\t\t_appendChannelAccess(src, i);\n\t\t\t_emitTypeConversionSuffix(shaderContext, shaderContext->typeTracker.defaultDataType, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t}\n\telse\n\t\tcemu_assert_debug(false);\n}\n\nvoid _emitCFCall(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tuint32 subroutineAddr = cfInstruction->addr;\n\tLatteDecompilerSubroutineInfo* subroutineInfo = nullptr;\n\t// find subroutine\n\tfor (auto& subroutineItr : shaderContext->list_subroutines)\n\t{\n\t\tif (subroutineItr.cfAddr == subroutineAddr)\n\t\t{\n\t\t\tsubroutineInfo = &subroutineItr;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (subroutineInfo == nullptr)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\t// inline function\n\tif (shaderContext->isSubroutine)\n\t{\n\t\tcemu_assert_debug(false); // inlining with cascaded function calls not supported\n\t\treturn;\n\t}\n\t// init CF stack variables\n\tsrc->addFmt(\"activeMaskStackSub{:04x}[0] = true;\" _CRLF, subroutineInfo->cfAddr);\n\tsrc->addFmt(\"activeMaskStackCSub{:04x}[0] = true;\" _CRLF, subroutineInfo->cfAddr);\n\tsrc->addFmt(\"activeMaskStackCSub{:04x}[1] = true;\" _CRLF, subroutineInfo->cfAddr);\n\n\tshaderContext->isSubroutine = true;\n\tshaderContext->subroutineInfo = subroutineInfo;\n\tfor(auto& cfInstruction : subroutineInfo->instructions)\n\t\tLatteDecompiler_emitClauseCode(shaderContext, &cfInstruction, true);\n\tshaderContext->isSubroutine = false;\n\tshaderContext->subroutineInfo = nullptr;\n}\n\nvoid LatteDecompiler_emitClauseCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, bool isSubroutine)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\n\tif( cfInstruction->type == GPU7_CF_INST_ALU || cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE || cfInstruction->type == GPU7_CF_INST_ALU_POP_AFTER || cfInstruction->type == GPU7_CF_INST_ALU_POP2_AFTER || cfInstruction->type == GPU7_CF_INST_ALU_BREAK || cfInstruction->type == GPU7_CF_INST_ALU_ELSE_AFTER )\n\t{\n\t\t// emit ALU code\n\t\tif (shaderContext->analyzer.modifiesPixelActiveState)\n\t\t{\n\t\t\tif(cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE)\n\t\t\t\tsrc->addFmt(\"if( {} == true ) {{\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1 - 1));\n\t\t\telse\n\t\t\t\tsrc->addFmt(\"if( {} == true ) {{\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1));\n\t\t}\n\t\tif (cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE)\n\t\t{\n\t\t\tsrc->addFmt(\"{} = {};\" _CRLF, _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth-1));\n\t\t\tsrc->addFmt(\"{} = {};\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t}\n\t\t_emitALUClauseCode(shaderContext, cfInstruction);\n\t\tif( shaderContext->analyzer.modifiesPixelActiveState )\n\t\t\tsrc->add(\"}\" _CRLF);\n\t\tcemu_assert_debug(!(shaderContext->analyzer.modifiesPixelActiveState == false && cfInstruction->type != GPU7_CF_INST_ALU));\n\t\t// handle ELSE case of PUSH_BEFORE\n\t\tif( cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE )\n\t\t{\n\t\t\tsrc->add(\"else {\" _CRLF);\n\t\t\tsrc->addFmt(\"{} = false;\" _CRLF, _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t\tsrc->addFmt(\"{} = false;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1));\n\t\t\tsrc->add(\"}\" _CRLF);\n\t\t}\n\t\t// post clause handler\n\t\tif( cfInstruction->type == GPU7_CF_INST_ALU_POP_AFTER )\n\t\t{\n\t\t\tsrc->addFmt(\"{} = {} == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1 - 1), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth - 1), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth - 1));\n\t\t}\n\t\telse if( cfInstruction->type == GPU7_CF_INST_ALU_POP2_AFTER )\n\t\t{\n\t\t\tsrc->addFmt(\"{} = {} == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1 - 2), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth - 2), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth - 2));\n\t\t}\n\t\telse if( cfInstruction->type == GPU7_CF_INST_ALU_ELSE_AFTER )\n\t\t{\n\t\t\t// no condition test\n\t\t\t// pop stack\n\t\t\tif( cfInstruction->popCount != 0 )\n\t\t\t\tdebugBreakpoint();\n\t\t\t// else operation\n\t\t\tsrc->addFmt(\"{} = {} == false;\" _CRLF, _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t\tsrc->addFmt(\"{} = {} == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t}\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_TEX )\n\t{\n\t\t// emit TEX code\n\t\tif (shaderContext->analyzer.modifiesPixelActiveState)\n\t\t{\n\t\t\tsrc->addFmt(\"if( {} == true ) {{\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth+1));\n\t\t}\n\t\t_emitTEXClauseCode(shaderContext, cfInstruction);\n\t\tif (shaderContext->analyzer.modifiesPixelActiveState)\n\t\t{\n\t\t\tsrc->add(\"}\" _CRLF);\n\t\t}\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_EXPORT || cfInstruction->type == GPU7_CF_INST_EXPORT_DONE )\n\t{\n\t\t// emit export code\n\t\t_emitExportCode(shaderContext, cfInstruction);\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_ELSE )\n\t{\n\t\t// todo: Condition test, popCount?\n\t\tsrc->addFmt(\"{} = {} == false;\" _CRLF, _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\tsrc->addFmt(\"{} = {} == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth));\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_POP )\n\t{\n\t\tsrc->addFmt(\"{} = {} == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1 - cfInstruction->popCount), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth - cfInstruction->popCount), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth - cfInstruction->popCount));\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_LOOP_START_DX10 ||\n\t\t\t cfInstruction->type == GPU7_CF_INST_LOOP_START_NO_AL)\n\t{\n\t\t// start of loop\n\t\t// if pixel is disabled, then skip loop\n\t\tif (ActiveSettings::ShaderPreventInfiniteLoopsEnabled())\n\t\t{\n\t\t\t// with iteration limit to prevent infinite loops\n\t\t\tsrc->addFmt(\"int loopCounter{} = 0;\" _CRLF, (sint32)cfInstruction->cfAddr);\n\t\t\tsrc->addFmt(\"while( {} == true && loopCounter{} < 500 )\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1), (sint32)cfInstruction->cfAddr);\n\t\t\tsrc->add(\"{\" _CRLF);\n\t\t\tsrc->addFmt(\"loopCounter{}++;\" _CRLF, (sint32)cfInstruction->cfAddr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsrc->addFmt(\"while( {} == true )\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1));\n\t\t\tsrc->add(\"{\" _CRLF);\n\t\t}\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_LOOP_END )\n\t{\n\t\t// this might not always work\n\t\tif( cfInstruction->popCount != 0 )\n\t\t\tdebugBreakpoint();\n\t\tsrc->add(\"}\" _CRLF);\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_LOOP_BREAK )\n\t{\n\t\tif( cfInstruction->popCount != 0 )\n\t\t\tdebugBreakpoint();\n\t\tif (shaderContext->analyzer.modifiesPixelActiveState)\n\t\t{\n\t\t\tsrc->addFmt(\"if( {} == true ) {{\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1));\n\t\t}\n\t\t// note: active stack level is set to the same level as the loop begin. popCount is ignored\n\t\tsrc->add(\"break;\" _CRLF);\n\n\t\tif (shaderContext->analyzer.modifiesPixelActiveState)\n\t\t\tsrc->add(\"}\" _CRLF);\n\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_MEM_STREAM0_WRITE ||\n\t\tcfInstruction->type == GPU7_CF_INST_MEM_STREAM1_WRITE )\n\t{\n\t\t_emitStreamWriteCode(shaderContext, cfInstruction);\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_MEM_RING_WRITE )\n\t{\n\t\t_emitCFRingWriteCode(shaderContext, cfInstruction);\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_EMIT_VERTEX )\n\t{\n\t\tif( shaderContext->analyzer.modifiesPixelActiveState )\n\t\t\tsrc->addFmt(\"if( {} == true ) {{\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1));\n\t\t// write point size\n\t\tif (shaderContext->analyzer.outputPointSize && shaderContext->analyzer.writesPointSize == false)\n\t\t\tsrc->add(\"gl_PointSize = uf_pointSize;\" _CRLF);\n\t\t// emit vertex\n\t\tsrc->add(\"EmitVertex();\" _CRLF);\n\t\t// increment transform feedback pointer\n\t\tif (shaderContext->analyzer.useSSBOForStreamout)\n\t\t{\n\t\t\tfor (sint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t\t{\n\t\t\t\tif (!shaderContext->output->streamoutBufferWriteMask[i])\n\t\t\t\t\tcontinue;\n\t\t\t\tcemu_assert_debug((shaderContext->output->streamoutBufferStride[i] & 3) == 0);\n\t\t\t\tsrc->addFmt(\"sbBase{} += {};\" _CRLF, i, shaderContext->output->streamoutBufferStride[i] / 4);\n\t\t\t}\n\t\t}\n\n\t\tif( shaderContext->analyzer.modifiesPixelActiveState )\n\t\t\tsrc->add(\"}\" _CRLF);\n\t}\n\telse if (cfInstruction->type == GPU7_CF_INST_CALL)\n\t{\n\t\t_emitCFCall(shaderContext, cfInstruction);\n\t}\n\telse if (cfInstruction->type == GPU7_CF_INST_RETURN)\n\t{\n\t\t// todo (handle properly)\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n}\n\nvoid LatteDecompiler_emitGLSLHelperFunctions(LatteDecompilerShaderContext* shaderContext, StringBuf* fCStr_shaderSource)\n{\n\tif( shaderContext->analyzer.hasRedcCUBE )\n\t{\n\t\tfCStr_shaderSource->add(\"void redcCUBE(vec4 src0, vec4 src1, out vec3 stm, out int faceId)\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"// stm -> x .. s, y .. t, z .. MajorAxis*2.0\\r\\n\"\n\n\t\t\"vec3 inputCoord = normalize(vec3(src1.y, src1.x, src0.x));\\r\\n\"\n\n\t\t\"float rx = inputCoord.x;\\r\\n\"\n\t\t\"float ry = inputCoord.y;\\r\\n\"\n\t\t\"float rz = inputCoord.z;\\r\\n\"\n\t\t\"if( abs(rx) > abs(ry) && abs(rx) > abs(rz) )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"stm.z = rx*2.0;\\r\\n\"\n\t\t\"stm.xy = vec2(ry,rz);\t\\r\\n\"\n\t\t\"if( rx >= 0.0 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 1;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else if( abs(ry) > abs(rx) && abs(ry) > abs(rz) )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"stm.z = ry*2.0;\\r\\n\"\n\t\t\"stm.xy = vec2(rx,rz);\t\\r\\n\"\n\t\t\"if( ry >= 0.0 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 2;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 3;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else //if( abs(rz) > abs(ry) && abs(rz) > abs(rx) )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"stm.z = rz*2.0;\\r\\n\"\n\t\t\"stm.xy = vec2(rx,ry);\t\\r\\n\"\n\t\t\"if( rz >= 0.0 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 4;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 5;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"}\\r\\n\");\n\t}\n\n\tif( shaderContext->analyzer.hasCubeMapTexture )\n\t{\n\t\tfCStr_shaderSource->add(\"vec3 redcCUBEReverse(vec2 st, int faceId)\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"st.yx = st.xy;\\r\\n\"\n\t\t\"vec3 v;\\r\\n\"\n\t\t\"float majorAxis = 1.0;\\r\\n\"\n\t\t\"if( faceId == 0 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.yz = (st-vec2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.x = 1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else if( faceId == 1 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.yz = (st-vec2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.x = -1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else if( faceId == 2 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.xz = (st-vec2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.y = 1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else if( faceId == 3 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.xz = (st-vec2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.y = -1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else if( faceId == 4 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.xy = (st-vec2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.z = 1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.xy = (st-vec2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.z = -1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\n\t\t\"return v;\\r\\n\"\n\t\t\"}\\r\\n\");\n\t}\n\n\t// clamp\n\tfCStr_shaderSource->add(\"\"\n\t\"int clampFI32(int v)\\r\\n\"\n\t\"{\\r\\n\"\n\t\t\"if( v == 0x7FFFFFFF )\\r\\n\"\n\t\t\"\treturn floatBitsToInt(1.0);\\r\\n\"\n\t\t\"else if( v == 0xFFFFFFFF )\\r\\n\"\n\t\t\"\treturn floatBitsToInt(0.0);\\r\\n\"\n\t\t\"return floatBitsToInt(clamp(intBitsToFloat(v), 0.0, 1.0));\\r\\n\"\n\t\"}\\r\\n\");\n\t// mul non-ieee way (0*NaN/INF => 0.0)\n\tif (shaderContext->options->strictMul)\n\t{\n\t\t// things we tried:\n\t\t//fCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){ return mix(a*b,0.0,a==0.0||b==0.0); }\" STR_LINEBREAK);\n\t\t//fCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){ return mix(vec2(a*b,0.0),vec2(0.0,0.0),(equal(vec2(a),vec2(0.0,0.0))||equal(vec2(b),vec2(0.0,0.0)))).x; }\" STR_LINEBREAK);\n\t\t//fCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){ if( a == 0.0 || b == 0.0 ) return 0.0; return a*b; }\" STR_LINEBREAK);\n\t\t//fCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){float r = a*b;r = intBitsToFloat(floatBitsToInt(r)&(((floatBitsToInt(a) != 0) && (floatBitsToInt(b) != 0))?0xFFFFFFFF:0));return r;}\" STR_LINEBREAK); works\n\n\t\t// for \"min\" it used to be: float mul_nonIEEE(float a, float b){ return min(a*b,min(abs(a)*3.40282347E+38F,abs(b)*3.40282347E+38F)); }\n\n\t\tif( LatteGPUState.glVendor == GLVENDOR_NVIDIA && !ActiveSettings::DumpShadersEnabled())\n\t\t\tfCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){return mix(0.0, a*b, (a != 0.0) && (b != 0.0));}\" _CRLF); // compiles faster on Nvidia and also results in lower RAM usage (OpenGL)\n\t\telse\n\t\t\tfCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){ if( a == 0.0 || b == 0.0 ) return 0.0; return a*b; }\" _CRLF);\n\n\t\t// DXKV-like: fCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){ return (b==0.0 ? 0.0 : a) * (a==0.0 ? 0.0 : b); }\" _CRLF);\n\t}\n}\n\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLHeader.hpp\"\n\nvoid LatteDecompiler_emitAttributeImport(LatteDecompilerShaderContext* shaderContext, LatteParsedFetchShaderAttribute_t& attrib)\n{\n\tauto src = shaderContext->shaderSource;\n\n\tstatic const char* dsMappingTableFloat[6] = { \"int(attrDecoder.x)\", \"int(attrDecoder.y)\", \"int(attrDecoder.z)\", \"int(attrDecoder.w)\", /*\"floatBitsToInt(0.0)\"*/ \"0\", /*\"floatBitsToInt(1.0)\"*/ \"0x3f800000\" };\n\tstatic const char* dsMappingTableInt[6] = { \"int(attrDecoder.x)\", \"int(attrDecoder.y)\", \"int(attrDecoder.z)\", \"int(attrDecoder.w)\", \"0\", \"1\" };\n\n\t// get register index based on vtx semantic table\n\tuint32 attributeShaderLoc = 0xFFFFFFFF;\n\tfor (sint32 f = 0; f < 32; f++)\n\t{\n\t\tif (shaderContext->contextRegisters[mmSQ_VTX_SEMANTIC_0 + f] == attrib.semanticId)\n\t\t{\n\t\t\tattributeShaderLoc = f;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (attributeShaderLoc == 0xFFFFFFFF)\n\t\treturn; // attribute is not mapped to VS input\n\tuint32 registerIndex = attributeShaderLoc + 1; // R0 is skipped\n\t// is register used?\n\tif ((shaderContext->analyzer.gprUseMask[registerIndex / 8] & (1 << (registerIndex % 8))) == 0)\n\t{\n\t\tsrc->addFmt(\"// skipped unused attribute for r{}\" _CRLF, registerIndex);\n\t\treturn;\n\t}\n\n\tLatteDecompiler_emitAttributeDecodeGLSL(shaderContext->shader, src, &attrib);\n\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\tsrc->addFmt(\"{} = ivec4(\", _getRegisterVarName(shaderContext, registerIndex));\n\telse\n\t\tsrc->addFmt(\"{} = vec4(\", _getRegisterVarName(shaderContext, registerIndex));\n\tfor (sint32 f = 0; f < 4; f++)\n\t{\n\t\tuint8 ds = attrib.ds[f];\n\t\tif (f > 0)\n\t\t\tsrc->add(\", \");\n\t\t_emitTypeConversionPrefix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, shaderContext->typeTracker.defaultDataType);\n\t\tif (ds >= 6)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t\tds = 4; // read as 0.0\n\t\t}\n\t\tif (attrib.nfa != 1)\n\t\t{\n\t\t\tsrc->add(dsMappingTableFloat[ds]);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsrc->add(dsMappingTableInt[ds]);\n\t\t}\n\t\t_emitTypeConversionSuffix(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, shaderContext->typeTracker.defaultDataType);\n\t}\n\tsrc->add(\");\" _CRLF);\n}\n\nvoid LatteDecompiler_emitGLSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader)\n{\n\tStringBuf* src = new StringBuf(1024*1024*12); // reserve 12MB for generated source (we resize-to-fit at the end)\n\tshaderContext->shaderSource = src;\n\t// GLSL shader header\n\tsrc->add(\"#version 430\" _CRLF); // 430 is required for shader storage (Vulkan alternative TF path)\n\tsrc->add(\"#extension GL_ARB_texture_gather : enable\" _CRLF);\n\tsrc->add(\"#extension GL_ARB_separate_shader_objects : enable\" _CRLF);\n\n\tif (shaderContext->analyzer.hasStreamoutWrite || shaderContext->options->usesGeometryShader )\n\t\tsrc->add(\"#extension GL_ARB_enhanced_layouts : enable\" _CRLF);\n\t\n\t// debug info\n\tsrc->addFmt(\"// shader {:016x}\" _CRLF, shaderContext->shaderBaseHash);\n#ifdef CEMU_DEBUG_ASSERT\n\tsrc->addFmt(\"// usesIntegerValues: {}\" _CRLF, shaderContext->analyzer.usesIntegerValues?\"true\":\"false\");\n\tsrc->addFmt(_CRLF);\n#endif\n\t// header part (definitions for inputs and outputs)\n\tLatteDecompiler::emitHeader(shaderContext);\n\t// helper functions\n\tLatteDecompiler_emitGLSLHelperFunctions(shaderContext, src);\n\t// start of main\n\tsrc->add(\"void main()\" _CRLF);\n\tsrc->add(\"{\" _CRLF);\n\t// variable definition\n\tif (shaderContext->typeTracker.useArrayGPRs == false)\n\t{\n\t\t// each register is a separate variable\n\t\tfor (sint32 i = 0; i < 128; i++)\n\t\t{\n\t\t\tif (shaderContext->analyzer.usesRelativeGPRRead || (shaderContext->analyzer.gprUseMask[i / 8] & (1 << (i & 7))) != 0)\n\t\t\t{\n\t\t\t\tif (shaderContext->typeTracker.genIntReg)\n\t\t\t\t\tsrc->addFmt(\"ivec4 R{}i = ivec4(0);\" _CRLF, i);\n\t\t\t\telse if (shaderContext->typeTracker.genFloatReg)\n\t\t\t\t\tsrc->addFmt(\"vec4 R{}f = vec4(0.0);\" _CRLF, i);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// registers are represented using a single large array\n\t\tif (shaderContext->typeTracker.genIntReg)\n\t\t\tsrc->addFmt(\"ivec4 Ri[128];\" _CRLF);\n\t\telse if (shaderContext->typeTracker.genFloatReg)\n\t\t\tsrc->addFmt(\"vec4 Rf[128];\" _CRLF);\n\t\tfor (sint32 i = 0; i < 128; i++)\n\t\t{\n\t\t\tif (shaderContext->typeTracker.genIntReg)\n\t\t\t\tsrc->addFmt(\"Ri[{}] = ivec4(0);\" _CRLF, i);\n\t\t\telse if (shaderContext->typeTracker.genFloatReg)\n\t\t\t\tsrc->addFmt(\"Rf[{}] = vec4(0.0);\" _CRLF, i);\n\t\t}\n\t}\n\n\tif( shader->shaderType == LatteConst::ShaderType::Vertex )\n\t\tsrc->addFmt(\"uvec4 attrDecoder;\" _CRLF);\n\tif (shaderContext->typeTracker.genIntReg)\n\t\tsrc->addFmt(\"int backupReg0i, backupReg1i, backupReg2i, backupReg3i, backupReg4i;\" _CRLF);\n\tif (shaderContext->typeTracker.genFloatReg)\n\t\tsrc->addFmt(\"float backupReg0f, backupReg1f, backupReg2f, backupReg3f, backupReg4f;\" _CRLF);\n\tif (shaderContext->typeTracker.genIntReg)\n\t{\n\t\tsrc->addFmt(\"int PV0ix = 0, PV0iy = 0, PV0iz = 0, PV0iw = 0, PV1ix = 0, PV1iy = 0, PV1iz = 0, PV1iw = 0;\" _CRLF);\n\t\tsrc->addFmt(\"int PS0i = 0, PS1i = 0;\" _CRLF);\n\t\tsrc->addFmt(\"ivec4 tempi = ivec4(0);\" _CRLF);\n\t}\n\tif (shaderContext->typeTracker.genFloatReg)\n\t{\n\t\tsrc->addFmt(\"float PV0fx = 0.0, PV0fy = 0.0, PV0fz = 0.0, PV0fw = 0.0, PV1fx = 0.0, PV1fy = 0.0, PV1fz = 0.0, PV1fw = 0.0;\" _CRLF);\n\t\tsrc->addFmt(\"float PS0f = 0.0, PS1f = 0.0;\" _CRLF);\n\t\tsrc->addFmt(\"vec4 tempf = vec4(0.0);\" _CRLF);\n\t}\n\tif (shaderContext->analyzer.hasGradientLookup)\n\t{\n\t\tsrc->add(\"vec4 gradH;\" _CRLF);\n\t\tsrc->add(\"vec4 gradV;\" _CRLF);\n\t}\n\tsrc->add(\"float tempResultf;\" _CRLF);\n\tsrc->add(\"int tempResulti;\" _CRLF);\n\tsrc->add(\"ivec4 ARi = ivec4(0);\" _CRLF);\n\tsrc->add(\"bool predResult = true;\" _CRLF);\n\tif(shaderContext->analyzer.modifiesPixelActiveState )\n\t{\n\t\tsrc->addFmt(\"bool activeMaskStack[{}];\" _CRLF, shaderContext->analyzer.activeStackMaxDepth+1);\n\t\tsrc->addFmt(\"bool activeMaskStackC[{}];\" _CRLF, shaderContext->analyzer.activeStackMaxDepth+2);\n\t\tfor (sint32 i = 0; i < shaderContext->analyzer.activeStackMaxDepth; i++)\n\t\t{\n\t\t\tsrc->addFmt(\"activeMaskStack[{}] = false;\" _CRLF, i);\n\t\t}\n\t\tfor (sint32 i = 0; i < shaderContext->analyzer.activeStackMaxDepth+1; i++)\n\t\t{\n\t\t\tsrc->addFmt(\"activeMaskStackC[{}] = false;\" _CRLF, i);\n\t\t}\n\t\tsrc->addFmt(\"activeMaskStack[0] = true;\" _CRLF);\n\t\tsrc->addFmt(\"activeMaskStackC[0] = true;\" _CRLF);\n\t\tsrc->addFmt(\"activeMaskStackC[1] = true;\" _CRLF);\t\n\t\t// generate vars for each subroutine\n\t\tfor (auto& subroutineInfo : shaderContext->list_subroutines)\n\t\t{\n\t\t\tsint32 subroutineMaxStackDepth = 0;\n\t\t\tsrc->addFmt(\"bool activeMaskStackSub{:04x}[{}];\" _CRLF, subroutineInfo.cfAddr, subroutineMaxStackDepth + 1);\n\t\t\tsrc->addFmt(\"bool activeMaskStackCSub{:04x}[{}];\" _CRLF, subroutineInfo.cfAddr, subroutineMaxStackDepth + 2);\n\t\t}\n\t}\n\t// helper variables for cube maps (todo: Only emit when used)\n\tif (shaderContext->analyzer.hasRedcCUBE)\n\t{\n\t\tsrc->add(\"vec3 cubeMapSTM;\" _CRLF);\n\t\tsrc->add(\"int cubeMapFaceId;\" _CRLF);\n\t}\n\tfor(sint32 i=0; i<LATTE_NUM_MAX_TEX_UNITS; i++)\n\t{\n\t\tif(!shaderContext->output->textureUnitMask[i])\n\t\t\tcontinue;\n\t\tif( shader->textureUnitDim[i] != Latte::E_DIM::DIM_CUBEMAP )\n\t\t\tcontinue;\n\t\tsrc->addFmt(\"float cubeMapArrayIndex{} = 0.0;\" _CRLF, i);\n\t}\n\t// init base offset for streamout buffer writes\n\tif (shaderContext->analyzer.useSSBOForStreamout && (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry))\n\t{\n\t\tfor (sint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t{\n\t\t\tif(!shaderContext->output->streamoutBufferWriteMask[i])\n\t\t\t\tcontinue;\n\n\t\t\tcemu_assert_debug((shaderContext->output->streamoutBufferStride[i]&3) == 0);\n\n\t\t\tif (shader->shaderType == LatteConst::ShaderType::Vertex) // vertex shader\n\t\t\t\tsrc->addFmt(\"int sbBase{} = uf_streamoutBufferBase{}/4 + (gl_VertexID + uf_verticesPerInstance * gl_InstanceID)*{};\" _CRLF, i, i, shaderContext->output->streamoutBufferStride[i] / 4);\n\t\t\telse // geometry shader\n\t\t\t{\n\t\t\t\tuint32 gsOutPrimType = shaderContext->contextRegisters[mmVGT_GS_OUT_PRIM_TYPE];\n\t\t\t\tuint32 bytesPerVertex = shaderContext->contextRegisters[mmSQ_GS_VERT_ITEMSIZE] * 4;\n\t\t\t\tuint32 maxVerticesInGS = ((shaderContext->contextRegisters[mmSQ_GSVS_RING_ITEMSIZE] & 0x7FFF) * 4) / bytesPerVertex;\n\t\t\t\t\n\t\t\t\tcemu_assert_debug(gsOutPrimType == 0); // currently we only properly handle GS output primitive points\n\t\t\t\t\n\t\t\t\tsrc->addFmt(\"int sbBase{} = uf_streamoutBufferBase{}/4 + (gl_PrimitiveIDIn * {})*{};\" _CRLF, i, i, maxVerticesInGS, shaderContext->output->streamoutBufferStride[i] / 4);\n\t\t\t}\n\t\t}\n\n\t}\n\t// code to load inputs from previous stage\n\tif( shader->shaderType == LatteConst::ShaderType::Vertex )\n\t{\n\t\tif( (shaderContext->analyzer.gprUseMask[0/8]&(1<<(0%8))) != 0 )\n\t\t{\n\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t\tsrc->addFmt(\"{} = ivec4(gl_VertexID, 0, 0, gl_InstanceID);\" _CRLF, _getRegisterVarName(shaderContext, 0));\n\t\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\tsrc->addFmt(\"{} = floatBitsToInt(ivec4(gl_VertexID, 0, 0, gl_InstanceID));\" _CRLF, _getRegisterVarName(shaderContext, 0));\n\t\t\telse\n\t\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\tLatteFetchShader* parsedFetchShader = shaderContext->fetchShader;\n\t\tfor(auto& bufferGroup : parsedFetchShader->bufferGroups)\n\t\t{\n\t\t\tfor(sint32 i=0; i<bufferGroup.attribCount; i++)\n\t\t\t\tLatteDecompiler_emitAttributeImport(shaderContext, bufferGroup.attrib[i]);\n\t\t}\n\t\tfor (auto& bufferGroup : parsedFetchShader->bufferGroupsInvalid)\n\t\t{\n\t\t\t// these attributes point to non-existent buffers\n\t\t\t// todo - figure out how the hardware actually handles this, currently we assume the input values are zero\n\t\t\tfor (sint32 i = 0; i < bufferGroup.attribCount; i++)\n\t\t\t\tLatteDecompiler_emitAttributeImport(shaderContext, bufferGroup.attrib[i]);\n\t\t}\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t{\n\t\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\n\t\tuint32 psControl0 = shaderContext->contextRegisters[mmSPI_PS_IN_CONTROL_0];\n\t\tuint32 psControl1 = shaderContext->contextRegisters[mmSPI_PS_IN_CONTROL_1];\n\n\t\tuint32 spiInterpControl = shaderContext->contextRegisters[mmSPI_INTERP_CONTROL_0];\n\t\tuint8 spriteEnable = (spiInterpControl >> 1) & 1;\n\t\tcemu_assert_debug(spriteEnable == 0);\n\n\t\tuint8 frontFace_enabled = (psControl1 >> 8) & 1;\n\t\tuint8 frontFace_chan = (psControl1 >> 9) & 3;\n\t\tuint8 frontFace_allBits = (psControl1 >> 11) & 1;\n\t\tuint8 frontFace_regIndex = (psControl1 >> 12) & 0x1F;\n\n\t\t// handle param_gen\n\t\tif (psInputTable->paramGen != 0)\n\t\t{\n\t\t\tcemu_assert_debug((psInputTable->paramGen) == 1); // handle the other bits (the same set of coordinates with different perspective/projection settings?)\n\t\t\tuint32 paramGenGPRIndex = psInputTable->paramGenGPR;\n\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\tsrc->addFmt(\"{} = gl_PointCoord.xyxy;\" _CRLF, _getRegisterVarName(shaderContext, paramGenGPRIndex));\n\t\t\telse\n\t\t\t\tsrc->addFmt(\"{} = floatBitsToInt(gl_PointCoord.xyxy);\" _CRLF, _getRegisterVarName(shaderContext, paramGenGPRIndex));\n\t\t}\n\n\t\tfor (sint32 i = 0; i < psInputTable->count; i++)\n\t\t{\n\t\t\tuint32 psControl0 = shaderContext->contextRegisters[mmSPI_PS_IN_CONTROL_0];\n\t\t\tuint32 spi0_paramGen = (psControl0 >> 15) & 0xF;\n\n\t\t\tsint32 gprIndex = i;// +spi0_paramGen + paramRegOffset;\n\t\t\tif ((shaderContext->analyzer.gprUseMask[gprIndex / 8] & (1 << (gprIndex % 8))) == 0 && shaderContext->analyzer.usesRelativeGPRRead == false)\n\t\t\t\tcontinue;\n\t\t\tuint32 psInputSemanticId = psInputTable->import[i].semanticId;\n\t\t\tif (psInputSemanticId == LATTE_ANALYZER_IMPORT_INDEX_SPIPOSITION)\n\t\t\t{\n\t\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\t\tsrc->addFmt(\"{} = GET_FRAGCOORD();\" _CRLF, _getRegisterVarName(shaderContext, gprIndex));\n\t\t\t\telse\n\t\t\t\t\tsrc->addFmt(\"{} = floatBitsToInt(GET_FRAGCOORD());\" _CRLF, _getRegisterVarName(shaderContext, gprIndex));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (shaderContext->options->usesGeometryShader)\n\t\t\t{\n\t\t\t\t// import from geometry shader\n\t\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t\t\tsrc->addFmt(\"{} = floatBitsToInt(passG2PParameter{});\" _CRLF, _getRegisterVarName(shaderContext, gprIndex), psInputSemanticId & 0x7F);\n\t\t\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\t\tsrc->addFmt(\"{} = passG2PParameter{};\" _CRLF, _getRegisterVarName(shaderContext, gprIndex), psInputSemanticId & 0x7F);\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// import from vertex shader\n\t\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t\t\tsrc->addFmt(\"{} = floatBitsToInt(passParameterSem{});\" _CRLF, _getRegisterVarName(shaderContext, gprIndex), psInputSemanticId);\n\t\t\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\t\tsrc->addFmt(\"{} = passParameterSem{};\" _CRLF, _getRegisterVarName(shaderContext, gprIndex), psInputSemanticId);\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t\t// front facing attribute\n\t\tif (frontFace_enabled)\n\t\t{\n\t\t\tif ((shaderContext->analyzer.gprUseMask[0 / 8] & (1 << (0 % 8))) != 0)\n\t\t\t{\n\t\t\t\tif (frontFace_allBits)\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t\t\tsrc->addFmt(\"{}.{} = floatBitsToInt(gl_FrontFacing?1.0:0.0);\" _CRLF, _getRegisterVarName(shaderContext, frontFace_regIndex), _getElementStrByIndex(frontFace_chan));\n\t\t\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\t\tsrc->addFmt(\"{}.{} = gl_FrontFacing?1.0:0.0;\" _CRLF, _getRegisterVarName(shaderContext, frontFace_regIndex), _getElementStrByIndex(frontFace_chan));\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t}\n\t}\n\tfor(auto& cfInstruction : shaderContext->cfInstructions)\n\t\tLatteDecompiler_emitClauseCode(shaderContext, &cfInstruction, false);\n\tif( shader->shaderType == LatteConst::ShaderType::Geometry )\n\t\tsrc->add(\"EndPrimitive();\" _CRLF);\n\t// vertex shader should write renderstate point size at the end if required but not modified by shader\n\tif (shaderContext->analyzer.outputPointSize && shaderContext->analyzer.writesPointSize == false)\n\t{\n\t\tif (shader->shaderType == LatteConst::ShaderType::Vertex && shaderContext->options->usesGeometryShader == false)\n\t\t\tsrc->add(\"gl_PointSize = uf_pointSize;\" _CRLF);\n\t}\n\t// end of shader main\n\tsrc->add(\"}\" _CRLF);\n\tsrc->shrink_to_fit();\n\tshader->strBuf_shaderSource = src;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLAttrDecoder.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"util/helpers/StringBuf.h\"\n\n#define _CRLF\t\"\\r\\n\"\n\nvoid _readLittleEndianAttributeU32x4(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = attrDataSem{};\" _CRLF, attributeInputIndex);\n}\n\nvoid _readLittleEndianAttributeU32x3(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = uvec4(attrDataSem{}.xyz,0);\" _CRLF, attributeInputIndex);\n}\n\nvoid _readLittleEndianAttributeU32x2(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = uvec4(attrDataSem{}.xy,0,0);\" _CRLF, attributeInputIndex);\n}\n\nvoid _readLittleEndianAttributeU32x1(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = uvec4(attrDataSem{}.x,0,0,0);\" _CRLF, attributeInputIndex);\n}\n\nvoid _readLittleEndianAttributeU16x2(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = uvec4(attrDataSem{}.xy,0,0);\" _CRLF, attributeInputIndex);\n}\n\nvoid _readLittleEndianAttributeU16x4(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = attrDataSem{};\" _CRLF, attributeInputIndex);\n}\n\nvoid _readBigEndianAttributeU32x4(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = attrDataSem{};\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder = (attrDecoder>>24)|((attrDecoder>>8)&0xFF00)|((attrDecoder<<8)&0xFF0000)|((attrDecoder<<24));\" _CRLF);\n}\n\nvoid _readBigEndianAttributeU32x3(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.xyz = attrDataSem{}.xyz;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder.xyz = (attrDecoder.xyz>>24)|((attrDecoder.xyz>>8)&0xFF00)|((attrDecoder.xyz<<8)&0xFF0000)|((attrDecoder.xyz<<24));\" _CRLF);\n\tsrc->add(\"attrDecoder.w = 0;\" _CRLF);\n}\n\nvoid _readBigEndianAttributeU32x2(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.xy = attrDataSem{}.xy;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder.xy = (attrDecoder.xy>>24)|((attrDecoder.xy>>8)&0xFF00)|((attrDecoder.xy<<8)&0xFF0000)|((attrDecoder.xy<<24));\" _CRLF);\n\tsrc->add(\"attrDecoder.z = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.w = 0;\" _CRLF);\n}\n\nvoid _readBigEndianAttributeU32x1(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.x = attrDataSem{}.x;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder.x = (attrDecoder.x>>24)|((attrDecoder.x>>8)&0xFF00)|((attrDecoder.x<<8)&0xFF0000)|((attrDecoder.x<<24));\" _CRLF);\n\tsrc->add(\"attrDecoder.y = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.z = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.w = 0;\" _CRLF);\n}\n\nvoid _readBigEndianAttributeU16x1(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.xy = attrDataSem{}.xy;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder.x = ((attrDecoder.x>>8)&0xFF)|((attrDecoder.x<<8)&0xFF00);\" _CRLF);\n\tsrc->add(\"attrDecoder.y = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.z = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.w = 0;\" _CRLF);\n}\n\nvoid _readBigEndianAttributeU16x2(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.xy = attrDataSem{}.xy;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder.xy = ((attrDecoder.xy>>8)&0xFF)|((attrDecoder.xy<<8)&0xFF00);\" _CRLF);\n\tsrc->add(\"attrDecoder.z = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.w = 0;\" _CRLF);\n}\n\nvoid _readBigEndianAttributeU16x4(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.xyzw = attrDataSem{}.xyzw;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder = ((attrDecoder>>8)&0xFF)|((attrDecoder<<8)&0xFF00);\" _CRLF);\n}\n\nvoid LatteDecompiler_emitAttributeDecodeGLSL(LatteDecompilerShader* shaderContext, StringBuf* src, LatteParsedFetchShaderAttribute_t* attrib)\n{\n\tif (attrib->attributeBufferIndex >= Latte::GPU_LIMITS::NUM_VERTEX_BUFFERS)\n\t{\n\t\tsrc->add(\"attrDecoder = ivec4(0);\" _CRLF);\n\t\treturn;\n\t}\n\n\tuint32 attributeInputIndex = attrib->semanticId;\n\tif( attrib->endianSwap == LatteConst::VertexFetchEndianMode::SWAP_U32 )\n\t{\n\t\tif( attrib->format == FMT_32_32_32_32_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x4(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_32_32_32_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x3(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_32_32_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x2(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_32_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_2_10_10_10 && attrib->nfa == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t\t// Bayonetta 2 uses this format to store normals\n\t\t\tsrc->add(\"attrDecoder.xyzw = uvec4((attrDecoder.x>>0)&0x3FF,(attrDecoder.x>>10)&0x3FF,(attrDecoder.x>>20)&0x3FF,(attrDecoder.x>>30)&0x3);\" _CRLF);\n\t\t\tif (attrib->isSigned != 0)\n\t\t\t{\n\t\t\t\tsrc->add(\"if( (attrDecoder.x&0x200) != 0 ) attrDecoder.x |= 0xFFFFFC00;\" _CRLF);\n\t\t\t\tsrc->add(\"if( (attrDecoder.y&0x200) != 0 ) attrDecoder.y |= 0xFFFFFC00;\" _CRLF);\n\t\t\t\tsrc->add(\"if( (attrDecoder.z&0x200) != 0 ) attrDecoder.z |= 0xFFFFFC00;\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/511.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/511.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.z = floatBitsToUint(max(float(int(attrDecoder.z))/511.0,-1.0));\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/1023.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/1023.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.z = floatBitsToUint(max(float(int(attrDecoder.z))/1023.0,-1.0));\" _CRLF);\n\t\t\t}\n\t\t\tsrc->add(\"attrDecoder.w = floatBitsToUint(float(attrDecoder.w));\" _CRLF); // unsure?\n\n\t\t}\n\t\telse if( attrib->format == FMT_32_32_32_32 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x4(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_32_32_32 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x3(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_32_32 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x2(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_32 && attrib->nfa == 1 && attrib->isSigned == 0)\n\t\t{\n\t\t\t_readBigEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_32 && attrib->nfa == 1 && attrib->isSigned == 1)\n\t\t{\n\t\t\t// we can just read the signed s32 as a u32 since no sign-extension is necessary\n\t\t\t_readBigEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 0 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t// seen in Minecraft Wii U Edition\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = floatBitsToUint(vec4(attrDataSem{}.wzyx)/255.0);\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 0 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t// seen in Minecraft Wii U Edition\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = attrDataSem{}.wzyx;\" _CRLF, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x80) != 0 ) attrDecoder.x |= 0xFFFFFF00;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.y&0x80) != 0 ) attrDecoder.y |= 0xFFFFFF00;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.z&0x80) != 0 ) attrDecoder.z |= 0xFFFFFF00;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.w&0x80) != 0 ) attrDecoder.w |= 0xFFFFFF00;\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/127.0,-1.0));\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/127.0,-1.0));\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.z = floatBitsToUint(max(float(int(attrDecoder.z))/127.0,-1.0));\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.w = floatBitsToUint(max(float(int(attrDecoder.w))/127.0,-1.0));\" _CRLF); \n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t// seen in Minecraft Wii U Edition\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = attrDataSem{}.wzyx;\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_8_8_8_8 && attrib->nfa == 2 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in Ben 10 Omniverse\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = floatBitsToUint(vec4(attrDataSem{}.wzyx));\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"_emitAttributeDecodeGLSL(): Unsupported fmt {:02x} nfa {} signed {} endian {}\\n\", attrib->format, attrib->nfa, attrib->isSigned, attrib->endianSwap);\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\telse if( attrib->endianSwap == LatteConst::VertexFetchEndianMode::SWAP_NONE )\n\t{\n\t\tif( attrib->format == FMT_32_32_32_32_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readLittleEndianAttributeU32x4(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_32_32_32_FLOAT && attrib->nfa == 2)\n\t\t{\n\t\t\t_readLittleEndianAttributeU32x3(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_32_32_FLOAT && attrib->nfa == 2)\n\t\t{\n\t\t\t// seen in Cities of Gold\n\t\t\t_readLittleEndianAttributeU32x2(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_32 && attrib->nfa == 1 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in Nano Assault Neo\n\t\t\t_readLittleEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_2_10_10_10 && attrib->nfa == 0 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in Fast Racing Neo\n\t\t\t_readLittleEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xyzw = uvec4((attrDecoder.x>>0)&0x3FF,(attrDecoder.x>>10)&0x3FF,(attrDecoder.x>>20)&0x3FF,(attrDecoder.x>>30)&0x3);\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/1023.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/1023.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = floatBitsToUint(max(float(int(attrDecoder.z))/1023.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = floatBitsToUint(float(attrDecoder.w));\" _CRLF); // todo - is this correct?\n\t\t}\n\t\telse if (attrib->format == FMT_16_16_16_16 && attrib->nfa == 0 && attrib->isSigned != 0)\n\t\t{\n\t\t\t// seen in CoD ghosts\n\t\t\t_readLittleEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x8000) != 0 ) attrDecoder.z |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x8000) != 0 ) attrDecoder.w |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = floatBitsToUint(max(float(int(attrDecoder.z))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = floatBitsToUint(max(float(int(attrDecoder.w))/32767.0,-1.0));\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16_16_16 && attrib->nfa == 2 && attrib->isSigned == 1 )\n\t\t{\n\t\t\t// seen in Rabbids Land\n\t\t\t_readLittleEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x8000) != 0 ) attrDecoder.z |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x8000) != 0 ) attrDecoder.w |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.xyzw = floatBitsToUint(vec4(ivec4(attrDecoder)));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16_16_16_16_FLOAT && attrib->nfa == 2)\n\t\t{\n\t\t\t// seen in Giana Sisters: Twisted Dreams\n\t\t\t_readLittleEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xyzw = floatBitsToInt(vec4(unpackHalf2x16(attrDecoder.x|(attrDecoder.y<<16)),unpackHalf2x16(attrDecoder.z|(attrDecoder.w<<16))));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16_16 && attrib->nfa == 0 && attrib->isSigned != 0)\n\t\t{\n\t\t\t// seen in Nano Assault Neo\n\t\t\t_readLittleEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/32767.0,-1.0));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16_16_FLOAT && attrib->nfa == 2)\n\t\t{\n\t\t\t// seen in Giana Sisters: Twisted Dreams\n\t\t\t_readLittleEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xy = floatBitsToUint(unpackHalf2x16(attrDecoder.x|(attrDecoder.y<<16)));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 0 && attrib->isSigned == 0 )\n\t\t{\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = floatBitsToUint(vec4(attrDataSem{}.xyzw)/255.0);\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 0 && attrib->isSigned != 0 )\n\t\t{\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = attrDataSem{}.xyzw;\" _CRLF, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x80) != 0 ) attrDecoder.x |= 0xFFFFFF00;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.y&0x80) != 0 ) attrDecoder.y |= 0xFFFFFF00;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.z&0x80) != 0 ) attrDecoder.z |= 0xFFFFFF00;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.w&0x80) != 0 ) attrDecoder.w |= 0xFFFFFF00;\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/127.0,-1.0));\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/127.0,-1.0));\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.z = floatBitsToUint(max(float(int(attrDecoder.z))/127.0,-1.0));\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.w = floatBitsToUint(max(float(int(attrDecoder.w))/127.0,-1.0));\" _CRLF); \n\t\t}\n\t\telse if (attrib->format == FMT_8_8_8_8 && attrib->nfa == 1 && attrib->isSigned == 0)\n\t\t{\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = attrDataSem{}.xyzw;\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_8_8_8_8 && attrib->nfa == 1 && attrib->isSigned != 0)\n\t\t{\n\t\t\t// seen in Sonic Lost World\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = attrDataSem{}.xyzw;\" _CRLF, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x80) != 0 ) attrDecoder.x |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x80) != 0 ) attrDecoder.y |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x80) != 0 ) attrDecoder.z |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x80) != 0 ) attrDecoder.w |= 0xFFFFFF00;\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 2 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t// seen in One Piece\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = floatBitsToInt(vec4(attrDataSem{}.xyzw));\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_8_8 && attrib->nfa == 0 && attrib->isSigned == 0)\n\t\t{\n\t\t\tif( (attrib->offset&3) == 2 && LatteGPUState.glVendor == GLVENDOR_AMD && g_renderer->GetType() == RendererAPI::OpenGL )\n\t\t\t{ \n\t\t\t\t// AMD workaround\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = floatBitsToUint(vec2(attrDataSem{}.zw)/255.0);\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = floatBitsToUint(vec2(attrDataSem{}.xy)/255.0);\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (attrib->format == FMT_8_8 && attrib->nfa == 2 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in BotW\n\t\t\tif ((attrib->offset & 3) == 2 && LatteGPUState.glVendor == GLVENDOR_AMD && g_renderer->GetType() == RendererAPI::OpenGL)\n\t\t\t{\n\t\t\t\t// AMD workaround\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = floatBitsToUint(vec2(attrDataSem{}.zw));\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = floatBitsToUint(vec2(attrDataSem{}.xy));\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (attrib->format == FMT_8_8 && attrib->nfa == 0 && attrib->isSigned != 0)\n\t\t{\n\t\t\tif ((attrib->offset & 3) == 2 && LatteGPUState.glVendor == GLVENDOR_AMD && g_renderer->GetType() == RendererAPI::OpenGL)\n\t\t\t{\n\t\t\t\t// AMD workaround\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = attrDataSem{}.zw;\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"if( (attrDecoder.x&0x80) != 0 ) attrDecoder.x |= 0xFFFFFF00;\" _CRLF);\n\t\t\t\tsrc->add(\"if( (attrDecoder.y&0x80) != 0 ) attrDecoder.y |= 0xFFFFFF00;\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/127.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/127.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = attrDataSem{}.xy;\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"if( (attrDecoder.x&0x80) != 0 ) attrDecoder.x |= 0xFFFFFF00;\" _CRLF);\n\t\t\t\tsrc->add(\"if( (attrDecoder.y&0x80) != 0 ) attrDecoder.y |= 0xFFFFFF00;\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/127.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/127.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (attrib->format == FMT_8_8 && attrib->nfa == 1 && attrib->isSigned == 0)\n\t\t{\n\t\t\tif ((attrib->offset & 3) == 2 && LatteGPUState.glVendor == GLVENDOR_AMD && g_renderer->GetType() == RendererAPI::OpenGL)\n\t\t\t{\n\t\t\t\t// AMD workaround\n\t\t\t\tsrc->addFmt(\"attrDecoder.xyzw = uvec4(attrDataSem{}.zw,0,0);\" _CRLF, attributeInputIndex);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"attrDecoder.xyzw = uvec4(attrDataSem{}.xy,0,0);\" _CRLF, attributeInputIndex);\n\t\t\t}\n\t\t}\n\t\telse if( attrib->format == FMT_8 && attrib->nfa == 0 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t// seen in Pikmin 3\n\t\t\tsrc->addFmt(\"attrDecoder.x = floatBitsToUint(float(attrDataSem{}.x)/255.0);\" _CRLF, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.yzw = uvec3(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_8 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = uvec4(attrDataSem{}.x,0,0,0);\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"_emitAttributeDecodeGLSL(): Unsupported fmt {:02x} nfa {} signed {} endian {}\\n\", attrib->format, attrib->nfa, attrib->isSigned, attrib->endianSwap);\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\telse if( attrib->endianSwap == LatteConst::VertexFetchEndianMode::SWAP_U16 )\n\t{\n\t\tif( attrib->format == FMT_16_16_16_16_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xyzw = floatBitsToInt(vec4(unpackHalf2x16(attrDecoder.x|(attrDecoder.y<<16)),unpackHalf2x16(attrDecoder.z|(attrDecoder.w<<16))));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16_16_16_16 && attrib->nfa == 0 && attrib->isSigned != 0)\n\t\t{\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x8000) != 0 ) attrDecoder.z |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x8000) != 0 ) attrDecoder.w |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = floatBitsToUint(max(float(int(attrDecoder.z))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = floatBitsToUint(max(float(int(attrDecoder.w))/32767.0,-1.0));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16_16_16_16 && attrib->nfa == 0 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in BotW\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(float(int(attrDecoder.x))/65535.0);\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(float(int(attrDecoder.y))/65535.0);\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = floatBitsToUint(float(int(attrDecoder.z))/65535.0);\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = floatBitsToUint(float(int(attrDecoder.w))/65535.0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16_16_16 && attrib->nfa == 2 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t// seen in Minecraft Wii U Edition\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.z&0x8000) != 0 ) attrDecoder.z |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.w&0x8000) != 0 ) attrDecoder.w |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(float(int(attrDecoder.x)));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(float(int(attrDecoder.y)));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = floatBitsToUint(float(int(attrDecoder.z)));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = floatBitsToUint(float(int(attrDecoder.w)));\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16_16_16 && attrib->nfa == 1 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t// seen in Minecraft Wii U Edition\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.z&0x8000) != 0 ) attrDecoder.z |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.w&0x8000) != 0 ) attrDecoder.w |= 0xFFFF0000;\" _CRLF); \n\t\t}\n\t\telse if( attrib->format == FMT_16_16_16_16 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xy = floatBitsToUint(unpackHalf2x16(attrDecoder.x|(attrDecoder.y<<16)));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 0 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xy = floatBitsToUint(vec2(float(attrDecoder.x), float(attrDecoder.y))/65535.0);\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 0 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(max(float(int(attrDecoder.x))/32767.0,-1.0));\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.y = floatBitsToUint(max(float(int(attrDecoder.y))/32767.0,-1.0));\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 1 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 2 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xy = floatBitsToUint(vec2(float(attrDecoder.x), float(attrDecoder.y)));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 2 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF); \n\t\t\tsrc->add(\"attrDecoder.xy = floatBitsToUint(vec2(float(int(attrDecoder.x)), float(int(attrDecoder.y))));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uvec2(0);\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16 && attrib->nfa == 1 && attrib->isSigned == 0)\n\t\t{\n\t\t\t_readBigEndianAttributeU16x1(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_16 && attrib->nfa == 0 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in CoD ghosts\n\t\t\t_readBigEndianAttributeU16x1(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.x = floatBitsToUint(float(int(attrDecoder.x))/65535.0);\" _CRLF);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"_emitAttributeDecodeGLSL(): Unsupported fmt {:02x} nfa {} signed {} endian {}\", attrib->format, attrib->nfa, attrib->isSigned, attrib->endianSwap);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n}\n\n\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLHeader.hpp",
    "content": "#pragma once\n\nnamespace LatteDecompiler\n{\n\tvoid _emitUniformVariables(LatteDecompilerShaderContext* decompilerContext, RendererAPI rendererType, LatteDecompilerOutputUniformOffsets& uniformOffsets)\n\t{\n\t\tLatteDecompilerShaderResourceMapping& resourceMapping = (rendererType == RendererAPI::Vulkan) ? decompilerContext->output->resourceMappingVK : decompilerContext->output->resourceMappingGL;\n\n\t\tif (rendererType == RendererAPI::Vulkan)\n\t\t{\n\t\t\t// for Vulkan uniform vars are in a uniform buffer\n\t\t\tif (decompilerContext->hasUniformVarBlock)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(resourceMapping.uniformVarsBufferBindingPoint >= 0);\n\t\t\t\tdecompilerContext->shaderSource->addFmt(\"layout(set = {}, binding = {}) uniform ufBlock\" _CRLF \"{{\" _CRLF, (sint32)resourceMapping.setIndex, (sint32)resourceMapping.uniformVarsBufferBindingPoint);\n\t\t\t}\n\t\t}\n\n\t\tuint32 uniformCurrentOffset = 0;\n\t\tauto shader = decompilerContext->shader;\n\t\tauto shaderType = decompilerContext->shader->shaderType;\n\t\tauto shaderSrc = decompilerContext->shaderSource;\n\t\tif (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED)\n\t\t{\n\t\t\t// uniform registers or buffers are accessed statically with predictable offsets\n\t\t\t// this allows us to remap the used entries into a more compact array\n\t\t\tif (shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t\tshaderSrc->addFmt(\"uniform ivec4 uf_remappedVS[{}];\" _CRLF, (sint32)shader->list_remappedUniformEntries.size());\n\t\t\telse if (shaderType == LatteConst::ShaderType::Pixel)\n\t\t\t\tshaderSrc->addFmt(\"uniform ivec4 uf_remappedPS[{}];\" _CRLF, (sint32)shader->list_remappedUniformEntries.size());\n\t\t\telse if (shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t\tshaderSrc->addFmt(\"uniform ivec4 uf_remappedGS[{}];\" _CRLF, (sint32)shader->list_remappedUniformEntries.size());\n\t\t\telse\n\t\t\t\tdebugBreakpoint();\n\t\t\tuniformOffsets.offset_remapped = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 16 * shader->list_remappedUniformEntries.size();\n\t\t}\n\t\telse if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE)\n\t\t{\n\t\t\tuint32 cfileSize = decompilerContext->analyzer.uniformRegisterAccessTracker.DetermineSize(decompilerContext->shaderBaseHash, 256);\n\t\t\t// full or partial uniform register file has to be present\n\t\t\tif (shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t\tshaderSrc->addFmt(\"uniform ivec4 uf_uniformRegisterVS[{}];\" _CRLF, cfileSize);\n\t\t\telse if (shaderType == LatteConst::ShaderType::Pixel)\n\t\t\t\tshaderSrc->addFmt(\"uniform ivec4 uf_uniformRegisterPS[{}];\" _CRLF, cfileSize);\n\t\t\telse if (shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t\tshaderSrc->addFmt(\"uniform ivec4 uf_uniformRegisterGS[{}];\" _CRLF, cfileSize);\n\t\t\tuniformOffsets.offset_uniformRegister = uniformCurrentOffset;\n\t\t\tuniformOffsets.count_uniformRegister = cfileSize;\n\t\t\tuniformCurrentOffset += 16 * cfileSize;\n\t\t}\n\t\t// special uniforms\n\t\tbool hasAnyViewportScaleDisabled =\n\t\t\t!decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_X_SCALE_ENA() ||\n\t\t\t!decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Y_SCALE_ENA() ||\n\t\t\t!decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Z_SCALE_ENA();\n\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && hasAnyViewportScaleDisabled)\n\t\t{\n\t\t\t// aka GX2 special state 0\n\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 7)&~7;\n\t\t\tshaderSrc->add(\"uniform vec2 uf_windowSpaceToClipSpaceTransform;\" _CRLF);\n\t\t\tuniformOffsets.offset_windowSpaceToClipSpaceTransform = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 8;\n\t\t}\n\t\tbool alphaTestEnable = decompilerContext->contextRegistersNew->SX_ALPHA_TEST_CONTROL.get_ALPHA_TEST_ENABLE();\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Pixel && alphaTestEnable)\n\t\t{\n\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 3)&~3;\n\t\t\tshaderSrc->add(\"uniform float uf_alphaTestRef;\" _CRLF);\n\t\t\tuniformOffsets.offset_alphaTestRef = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 4;\n\t\t}\n\t\tif (decompilerContext->analyzer.outputPointSize && decompilerContext->analyzer.writesPointSize == false)\n\t\t{\n\t\t\tif ((decompilerContext->shaderType == LatteConst::ShaderType::Vertex && !decompilerContext->options->usesGeometryShader) ||\n\t\t\t\tdecompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t{\n\t\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 3)&~3;\n\t\t\t\tshaderSrc->add(\"uniform float uf_pointSize;\" _CRLF);\n\t\t\t\tuniformOffsets.offset_pointSize = uniformCurrentOffset;\n\t\t\t\tuniformCurrentOffset += 4;\n\t\t\t}\n\t\t}\n\t\t// define uf_fragCoordScale which holds the xy scale for render target resolution vs effective resolution\n\t\tif (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t\t{\n\t\t\tif (rendererType == RendererAPI::OpenGL)\n\t\t\t{\n\t\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 7)&~7;\n\t\t\t\tshaderSrc->add(\"uniform vec2 uf_fragCoordScale;\" _CRLF);\n\t\t\t\tuniformOffsets.offset_fragCoordScale = uniformCurrentOffset;\n\t\t\t\tuniformCurrentOffset += 8;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// in Vulkan uf_fragCoordScale stores the origin in zw\n\t\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 15)&~15;\n\t\t\t\tshaderSrc->add(\"uniform vec4 uf_fragCoordScale;\" _CRLF);\n\t\t\t\tuniformOffsets.offset_fragCoordScale = uniformCurrentOffset;\n\t\t\t\tuniformCurrentOffset += 16;\n\t\t\t}\n\t\t}\n\t\t// provide scale factor for every texture that is accessed via texel coordinates (texelFetch)\n\t\tfor (sint32 t = 0; t < LATTE_NUM_MAX_TEX_UNITS; t++)\n\t\t{\n\t\t\tif (decompilerContext->analyzer.texUnitUsesTexelCoordinates.test(t) == false)\n\t\t\t\tcontinue;\n\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 7) & ~7;\n\t\t\tshaderSrc->addFmt(\"uniform vec2 uf_tex{}Scale;\" _CRLF, t);\n\t\t\tuniformOffsets.offset_texScale[t] = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 8;\n\t\t}\n\t\t// define uf_verticesPerInstance + uf_streamoutBufferBaseX\n\t\tif (decompilerContext->analyzer.useSSBOForStreamout &&\n\t\t\t(shader->shaderType == LatteConst::ShaderType::Vertex && decompilerContext->options->usesGeometryShader == false) ||\n\t\t\t(shader->shaderType == LatteConst::ShaderType::Geometry) )\n\t\t{\n\t\t\tshaderSrc->add(\"uniform int uf_verticesPerInstance;\" _CRLF);\n\t\t\tuniformOffsets.offset_verticesPerInstance = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 4;\n\t\t\tfor (uint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t\t{\n\t\t\t\tif (decompilerContext->output->streamoutBufferWriteMask[i])\n\t\t\t\t{\n\t\t\t\t\tshaderSrc->addFmt(\"uniform int uf_streamoutBufferBase{};\" _CRLF, i);\n\t\t\t\t\tuniformOffsets.offset_streamoutBufferBase[i] = uniformCurrentOffset;\n\t\t\t\t\tuniformCurrentOffset += 4;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tuniformOffsets.offset_endOfBlock = uniformCurrentOffset;\n\t\tif (rendererType == RendererAPI::Vulkan)\n\t\t{\n\t\t\tif (decompilerContext->hasUniformVarBlock)\n\t\t\t\tshaderSrc->add(\"};\" _CRLF); // end of push-constant block\n\t\t}\n\t}\n\n\tvoid _emitUniformBuffers(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\tauto shaderSrc = decompilerContext->shaderSource;\n\t\t// uniform buffer definition\n\t\tif (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)\n\t\t{\n\t\t\tfor (uint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t\t\t{\n\t\t\t\tif (!decompilerContext->analyzer.uniformBufferAccessTracker[i].HasAccess())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tcemu_assert_debug(decompilerContext->output->resourceMappingGL.uniformBuffersBindingPoint[i] >= 0);\n\t\t\t\tcemu_assert_debug(decompilerContext->output->resourceMappingVK.uniformBuffersBindingPoint[i] >= 0);\n\n\t\t\t\tshaderSrc->addFmt(\"UNIFORM_BUFFER_LAYOUT({}, {}, {}) \", (sint32)decompilerContext->output->resourceMappingGL.uniformBuffersBindingPoint[i], (sint32)decompilerContext->output->resourceMappingVK.setIndex, (sint32)decompilerContext->output->resourceMappingVK.uniformBuffersBindingPoint[i]);\n\n\t\t\t\tshaderSrc->addFmt(\"uniform {}{}\" _CRLF, _getShaderUniformBlockInterfaceName(decompilerContext->shaderType), i);\n\t\t\t\tshaderSrc->add(\"{\" _CRLF);\n\t\t\t\tshaderSrc->addFmt(\"vec4 {}{}[{}];\" _CRLF, _getShaderUniformBlockVariableName(decompilerContext->shaderType), i, decompilerContext->analyzer.uniformBufferAccessTracker[i].DetermineSize(decompilerContext->shaderBaseHash, LATTE_GLSL_DYNAMIC_UNIFORM_BLOCK_SIZE));\n\t\t\t\tshaderSrc->add(\"};\" _CRLF _CRLF);\n\t\t\t\tshaderSrc->add(_CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED)\n\t\t{\n\t\t\t// already generated in _emitUniformVariables\n\t\t}\n\t\telse if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE)\n\t\t{\n\t\t\t// already generated in _emitUniformVariables\n\t\t}\n\t\telse if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_NONE)\n\t\t{\n\t\t\t// no uniforms used\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\n\tvoid _emitTextureDefinitions(LatteDecompilerShaderContext* shaderContext)\n\t{\n\t\tauto src = shaderContext->shaderSource;\n\t\t// texture sampler definition\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t\t{\n\t\t\tif (!shaderContext->output->textureUnitMask[i])\n\t\t\t\tcontinue;\n\n\t\t\tsrc->addFmt(\"TEXTURE_LAYOUT({}, {}, {}) \", (sint32)shaderContext->output->resourceMappingGL.textureUnitToBindingPoint[i], (sint32)shaderContext->output->resourceMappingVK.setIndex, (sint32)shaderContext->output->resourceMappingVK.textureUnitToBindingPoint[i]);\n\n\t\t\tsrc->add(\"uniform \");\n\t\t\tif (shaderContext->shader->textureIsIntegerFormat[i])\n\t\t\t{\n\t\t\t\t// integer samplers\n\t\t\t\tif (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_1D)\n\t\t\t\t\tsrc->add(\"usampler1D\");\n\t\t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_2D || shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_2D_MSAA)\n\t\t\t\t\tsrc->add(\"usampler2D\");\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_2D || shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_2D_MSAA)\n\t\t\t\tsrc->add(\"sampler2D\");\n\t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_1D)\n\t\t\t\tsrc->add(\"sampler1D\");\n\t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_2D_ARRAY)\n\t\t\t\tsrc->add(\"sampler2DArray\");\n\t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_CUBEMAP)\n\t\t\t\tsrc->add(\"samplerCubeArray\");\n\t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_3D)\n\t\t\t\tsrc->add(\"sampler3D\");\n\t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_1D)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\tsrc->add(\"sampler2D\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\tif (shaderContext->shader->textureUsesDepthCompare[i])\n\t\t\t\tsrc->add(\"Shadow\"); // shadow sampler\n\n\t\t\tsrc->addFmt(\" {}{};\", _getTextureUnitVariablePrefixName(shaderContext->shaderType), i);\n\t\t\t\n\t\t\tsrc->add(_CRLF);\n\t\t}\n\t}\n\n\tvoid _emitAttributes(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\tauto shaderSrc = decompilerContext->shaderSource;\n\t\tif (decompilerContext->shader->shaderType == LatteConst::ShaderType::Vertex)\n\t\t{\n\t\t\t// attribute inputs\n\t\t\tfor (uint32 i = 0; i < LATTE_NUM_MAX_ATTRIBUTE_LOCATIONS; i++)\n\t\t\t{\n\t\t\t\tif (decompilerContext->analyzer.inputAttributSemanticMask[i])\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(decompilerContext->output->resourceMappingGL.attributeMapping[i] >= 0);\n\t\t\t\t\tcemu_assert_debug(decompilerContext->output->resourceMappingVK.attributeMapping[i] >= 0);\n\t\t\t\t\tcemu_assert_debug(decompilerContext->output->resourceMappingGL.attributeMapping[i] == decompilerContext->output->resourceMappingVK.attributeMapping[i]);\n\n\t\t\t\t\tshaderSrc->addFmt(\"ATTR_LAYOUT({}, {}) in uvec4 attrDataSem{};\" _CRLF, (sint32)decompilerContext->output->resourceMappingVK.setIndex, (sint32)decompilerContext->output->resourceMappingVK.attributeMapping[i], i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid _emitHeaderMacros(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\tauto src = decompilerContext->shaderSource;\n\t\t// OpenGL/Vulkan ifdefs\n\t\tsrc->add(\"#ifdef VULKAN\" _CRLF);\n\t\t// Vulkan defines\n\t\tsrc->add(\"#define ATTR_LAYOUT(__vkSet, __location) layout(set = __vkSet, location = __location)\" _CRLF);\n\t\tsrc->add(\"#define UNIFORM_BUFFER_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(set = __vkSet, binding = __vkLocation, std140)\" _CRLF);\n\t\tsrc->add(\"#define TEXTURE_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(set = __vkSet, binding = __vkLocation)\" _CRLF);\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t{\n\t\t\tsrc->add(\"#define gl_VertexID gl_VertexIndex\" _CRLF);\n\t\t\tsrc->add(\"#define gl_InstanceID gl_InstanceIndex\" _CRLF);\n\t\t\tif (decompilerContext->analyzer.hasStreamoutWrite)\n\t\t\t\tsrc->add(\"#define XFB_BLOCK_LAYOUT(__bufferIndex, __stride, __location) layout(location = __location, xfb_buffer = __bufferIndex, xfb_stride = __stride, xfb_offset = 0)\" _CRLF);\n\n\t\t\tif (decompilerContext->contextRegistersNew->PA_CL_CLIP_CNTL.get_DX_CLIP_SPACE_DEF())\n\t\t\t{\n\t\t\t\tsrc->add(\"#define SET_POSITION(_v) gl_Position = _v\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->add(\"#define SET_POSITION(_v) gl_Position = _v; gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0\" _CRLF);\n\t\t\t}\n\n\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t{\n\t\t\t\tif (decompilerContext->options->usesGeometryShader)\n\t\t\t\t\tsrc->add(\"#define V2G_LAYOUT layout(location = 0)\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t{\n\t\t\tsrc->add(\"#define GET_FRAGCOORD() vec4(gl_FragCoord.xy*uf_fragCoordScale.xy,gl_FragCoord.z, 1.0/gl_FragCoord.w)\" _CRLF);\n\t\t}\n\t\tif (decompilerContext->options->spirvInstrinsics.hasRoundingModeRTEFloat32)\n\t\t{\n\t\t\tsrc->add(\"#extension GL_EXT_spirv_intrinsics: enable\" _CRLF);\n\t\t\tsrc->add(\"spirv_execution_mode(capabilities = [4467], extensions = [\\\"SPV_KHR_float_controls\\\"], 4462, 16);\" _CRLF);\n\t\t\tsrc->add(\"spirv_execution_mode(capabilities = [4467], extensions = [\\\"SPV_KHR_float_controls\\\"], 4462, 32);\" _CRLF);\n\t\t\tsrc->add(\"spirv_execution_mode(capabilities = [4467], extensions = [\\\"SPV_KHR_float_controls\\\"], 4462, 64);\" _CRLF);\n\t\t}\n\t\tsrc->add(\"#else\" _CRLF);\n\t\t// OpenGL defines\n\t\tsrc->add(\"#define ATTR_LAYOUT(__vkSet, __location) layout(location = __location)\" _CRLF);\n\t\tsrc->add(\"#define UNIFORM_BUFFER_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(binding = __glLocation, std140) \" _CRLF);\n\t\tsrc->add(\"#define TEXTURE_LAYOUT(__glLocation, __vkSet, __vkLocation) layout(binding = __glLocation)\" _CRLF);\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t{\n\t\t\tif (decompilerContext->analyzer.hasStreamoutWrite)\n\t\t\t\tsrc->add(\"#define XFB_BLOCK_LAYOUT(__bufferIndex, __stride, __location) layout(xfb_buffer = __bufferIndex, xfb_stride = __stride)\" _CRLF);\n\n\t\t\tsrc->add(\"#define SET_POSITION(_v) gl_Position = _v\\r\\n\");\n\t\t\tif (decompilerContext->options->usesGeometryShader)\n\t\t\t\tsrc->add(\"#define V2G_LAYOUT\" _CRLF);\n\t\t}\n\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t{\n\t\t\tsrc->add(\"#define GET_FRAGCOORD() vec4(gl_FragCoord.xy*uf_fragCoordScale,gl_FragCoord.zw)\" _CRLF);\n\t\t}\n\t\tsrc->add(\"#endif\" _CRLF);\n\n\t\t// geometry shader input/output primitive info\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t{\n\t\t\tauto drawPrimitiveMode = decompilerContext->contextRegistersNew->VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();\n\t\t\tconst char* gsInputPrimitive = \"\";\n\t\t\tif (drawPrimitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::POINTS)\n\t\t\t\tgsInputPrimitive = \"points\";\n\t\t\telse if (drawPrimitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLES)\n\t\t\t\tgsInputPrimitive = \"triangles\";\n\t\t\telse if (drawPrimitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINE_STRIP)\n\t\t\t\tgsInputPrimitive = \"lines_adjacency\";\n\t\t\telse\n\t\t\t{\n\t\t\t\tdebug_printf(\"drawPrimitiveMode %d\\n\", drawPrimitiveMode);\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t\t// note: The input primitive type is not stored with the geometry shader object (and registers). Therefore we have to rely on whatever primitive mode was set for the draw call.\n\t\t\tsrc->addFmt(\"layout({}) in;\" _CRLF, gsInputPrimitive);\n\n\t\t\tuint32 gsOutPrimType = decompilerContext->contextRegisters[mmVGT_GS_OUT_PRIM_TYPE];\n\t\t\tuint32 bytesPerVertex = decompilerContext->contextRegisters[mmSQ_GS_VERT_ITEMSIZE] * 4;\n\t\t\t\n\t\t\tuint32 maxVerticesInGS = ((decompilerContext->contextRegisters[mmSQ_GSVS_RING_ITEMSIZE] & 0x7FFF) * 4) / bytesPerVertex;\n\n\t\t\tif (!decompilerContext->analyzer.hasLoops && decompilerContext->analyzer.numEmitVertex < maxVerticesInGS)\n\t\t\t\tmaxVerticesInGS = decompilerContext->analyzer.numEmitVertex;\n\n\t\t\tsrc->add(\"layout (\");\n\t\t\tif (gsOutPrimType == 0)\n\t\t\t\tsrc->add(\"points\");\n\t\t\telse if (gsOutPrimType == 1)\n\t\t\t\tsrc->add(\"line_strip\");\n\t\t\telse if (gsOutPrimType == 2)\n\t\t\t\tsrc->add(\"triangle_strip\");\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t\tsrc->addFmt(\", max_vertices={}) out;\" _CRLF, (sint32)maxVerticesInGS);\n\t\t}\n\t}\n\n\tvoid _emitVSExports(LatteDecompilerShaderContext* shaderContext)\n\t{\n\t\tauto* src = shaderContext->shaderSource;\n\t\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\t\tauto parameterMask = shaderContext->shader->outputParameterMask;\n\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t{\n\t\t\tif ((parameterMask&(1 << i)) == 0)\n\t\t\t\tcontinue;\n\t\t\tuint32 vsSemanticId = _getVertexShaderOutParamSemanticId(shaderContext->contextRegisters, i);\n\t\t\tif (vsSemanticId > LATTE_ANALYZER_IMPORT_INDEX_PARAM_MAX)\n\t\t\t\tcontinue;\n\t\t\t// get import based on semanticId\n\t\t\tsint32 psInputIndex = -1;\n\t\t\tfor (sint32 f = 0; f < psInputTable->count; f++)\n\t\t\t{\n\t\t\t\tif (psInputTable->import[f].semanticId == vsSemanticId)\n\t\t\t\t{\n\t\t\t\t\tpsInputIndex = f;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (psInputIndex == -1)\n\t\t\t\tcontinue; // no ps input\n\n\t\t\tsrc->addFmt(\"layout(location = {}) \", psInputIndex);\n\t\t\tif (psInputTable->import[psInputIndex].isFlat)\n\t\t\t\tsrc->add(\"flat \");\n\t\t\tif (psInputTable->import[psInputIndex].isNoPerspective)\n\t\t\t\tsrc->add(\"noperspective \");\n\t\t\tsrc->add(\"out\");\n\t\t\tsrc->addFmt(\" vec4 passParameterSem{};\" _CRLF, psInputTable->import[psInputIndex].semanticId);\n\t\t}\n\t}\n\n\tvoid _emitPSImports(LatteDecompilerShaderContext* shaderContext)\n\t{\n\t\tauto* src = shaderContext->shaderSource;\n\t\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\t\tfor (sint32 i = 0; i < psInputTable->count; i++)\n\t\t{\n\t\t\tif (psInputTable->import[i].semanticId > LATTE_ANALYZER_IMPORT_INDEX_PARAM_MAX)\n\t\t\t\tcontinue;\n\t\t\tsrc->addFmt(\"layout(location = {}) \", i);\n\t\t\tif (psInputTable->import[i].isFlat)\n\t\t\t\tsrc->add(\"flat \");\n\t\t\tif (psInputTable->import[i].isNoPerspective)\n\t\t\t\tsrc->add(\"noperspective \");\n\t\t\tsrc->add(\"in\");\n\t\t\tsrc->addFmt(\" vec4 passParameterSem{};\" _CRLF, psInputTable->import[i].semanticId);\n\t\t}\n\t}\n\n\tvoid _emitMisc(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\tauto src = decompilerContext->shaderSource;\n\t\t// per-vertex output (VS or GS)\n\t\tif ((decompilerContext->shaderType == LatteConst::ShaderType::Vertex && !decompilerContext->options->usesGeometryShader) ||\n\t\t\t(decompilerContext->shaderType == LatteConst::ShaderType::Geometry))\n\t\t{\n\t\t\tsrc->add(\"out gl_PerVertex\" _CRLF);\n\t\t\tsrc->add(\"{\" _CRLF);\n\t\t\tsrc->add(\"\tvec4 gl_Position;\" _CRLF);\n\t\t\tif (decompilerContext->analyzer.outputPointSize)\n\t\t\t\tsrc->add(\"\tfloat gl_PointSize;\" _CRLF);\n\t\t\tsrc->add(\"};\" _CRLF);\n\t\t}\n\t\t// varyings (variables passed from vertex to pixel shader, only if geometry stage is disabled\n\t\tif (decompilerContext->options->usesGeometryShader == false)\n\t\t{\n\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t{\n\t\t\t\t_emitVSExports(decompilerContext);\n\t\t\t}\n\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t\t{\n\t\t\t\t_emitPSImports(decompilerContext);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t{\n\t\t\t\t// parameters shared between vertex shader and geometry shader\n\t\t\t\tsrc->add(\"V2G_LAYOUT \");\n\n\t\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t\t\tsrc->add(\"out Vertex\" _CRLF);\n\t\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t\t\tsrc->add(\"in Vertex\" _CRLF);\n\t\t\t\tsrc->add(\"{\" _CRLF);\n\t\t\t\tuint32 ringParameterCountVS2GS = 0;\n\t\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t\t{\n\t\t\t\t\tringParameterCountVS2GS = decompilerContext->shader->ringParameterCount;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tringParameterCountVS2GS = decompilerContext->shader->ringParameterCountFromPrevStage;\n\t\t\t\t}\n\t\t\t\tfor (uint32 f = 0; f < ringParameterCountVS2GS; f++)\n\t\t\t\t\tsrc->addFmt(\" ivec4 passV2GParameter{};\" _CRLF, f);\n\t\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t\t\tsrc->add(\"}v2g;\" _CRLF);\n\t\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t\t\tsrc->add(\"}v2g[];\" _CRLF);\n\t\t\t}\n\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t{\n\t\t\t\t// parameters shared between geometry and pixel shader\n\t\t\t\tuint32 ringItemSize = decompilerContext->contextRegisters[mmSQ_GSVS_RING_ITEMSIZE] & 0x7FFF;\n\t\t\t\tif ((ringItemSize & 0xF) != 0)\n\t\t\t\t\tdebugBreakpoint();\n\t\t\t\tif (((decompilerContext->contextRegisters[mmSQ_GSVS_RING_ITEMSIZE] & 0x7FFF) & 0xF) != 0)\n\t\t\t\t\tdebugBreakpoint();\n\n\t\t\t\tfor (sint32 p = 0; p < decompilerContext->parsedGSCopyShader->numParam; p++)\n\t\t\t\t{\n\t\t\t\t\tif (decompilerContext->parsedGSCopyShader->paramMapping[p].exportType != 2)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tsrc->addFmt(\"layout(location = {}) out vec4 passG2PParameter{};\" _CRLF, decompilerContext->parsedGSCopyShader->paramMapping[p].exportParam & 0x7F, (sint32)decompilerContext->parsedGSCopyShader->paramMapping[p].exportParam);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t\t{\n\t\t\t\t// pixel shader with geometry shader\n\t\t\t\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\t\t\t\tfor (sint32 i = 0; i < psInputTable->count; i++)\n\t\t\t\t{\n\t\t\t\t\tif (psInputTable->import[i].semanticId > LATTE_ANALYZER_IMPORT_INDEX_PARAM_MAX)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tuint32 location = psInputTable->import[i].semanticId & 0x7F; // todo - the range above 128 has special meaning?\n\n\t\t\t\t\tsrc->addFmt(\"layout(location = {}) \", location);\n\t\t\t\t\tif (psInputTable->import[i].isFlat)\n\t\t\t\t\t\tsrc->add(\"flat \");\n\t\t\t\t\tif (psInputTable->import[i].isNoPerspective)\n\t\t\t\t\t\tsrc->add(\"noperspective \");\n\t\t\t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t\t\t\tsrc->add(\"out\");\n\t\t\t\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t\t\t\t\tsrc->add(\"in\");\n\t\t\t\t\telse\n\t\t\t\t\t\tdebugBreakpoint();\n\n\t\t\t\t\tsrc->addFmt(\" vec4 passG2PParameter{};\" _CRLF, (sint32)location);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// output defines\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t{\n\t\t\t// generate pixel outputs for pixel shader\n\t\t\tfor (uint32 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)\n\t\t\t{\n\t\t\t\tif ((decompilerContext->shader->pixelColorOutputMask&(1 << i)) != 0)\n\t\t\t\t{\n\t\t\t\t\tsrc->addFmt(\"layout(location = {}) out vec4 passPixelColor{};\" _CRLF, i, i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// streamout buffer (transform feedback)\n\t\tif ((decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry) && decompilerContext->analyzer.hasStreamoutEnable)\n\t\t{\n\t\t\tif (decompilerContext->options->useTFViaSSBO)\n\t\t\t{\n\t\t\t\tif (decompilerContext->analyzer.useSSBOForStreamout && decompilerContext->analyzer.hasStreamoutWrite)\n\t\t\t\t{\n\t\t\t\t\tsrc->addFmt(\"layout(set = {}, binding = {}) buffer StreamoutBuffer\" _CRLF, decompilerContext->output->resourceMappingVK.setIndex, decompilerContext->output->resourceMappingVK.getTFStorageBufferBindingPoint());\n\t\t\t\t\tsrc->add(\"{\" _CRLF);\n\t\t\t\t\tsrc->add(\"int sb_buffer[];\" _CRLF);\n\t\t\t\t\tsrc->add(\"};\" _CRLF);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsint32 locationOffset = 0; // glslang wants a location for xfb outputs\n\t\t\t\tfor (uint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t\t\t{\n\t\t\t\t\tif (!decompilerContext->output->streamoutBufferWriteMask[i])\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tuint32 bufferStride = decompilerContext->output->streamoutBufferStride[i];\n\t\t\t\t\tsrc->addFmt(\"XFB_BLOCK_LAYOUT({}, {}, {}) out XfbBlock{} \" _CRLF, i, bufferStride, locationOffset, i);\n\t\t\t\t\tsrc->add(\"{\" _CRLF);\n\t\t\t\t\tsrc->addFmt(\"layout(xfb_buffer = {}, xfb_offset = 0) int sb{}[{}];\" _CRLF, i, i, decompilerContext->output->streamoutBufferStride[i] / 4);\n\t\t\t\t\tsrc->add(\"};\" _CRLF);\n\t\t\t\t\tlocationOffset += (decompilerContext->output->streamoutBufferStride[i] / 4);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid emitHeader(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\tconst bool dump_shaders_enabled = ActiveSettings::DumpShadersEnabled();\n\t\tif(dump_shaders_enabled)\n\t\t\tdecompilerContext->shaderSource->add(\"// start of shader inputs/outputs, predetermined by Cemu. Do not touch\" _CRLF);\n\t\t// macros\n\t\t_emitHeaderMacros(decompilerContext);\n\t\t// uniform variables\n\t\tdecompilerContext->shaderSource->add(\"#ifdef VULKAN\" _CRLF);\n\t\t_emitUniformVariables(decompilerContext, RendererAPI::Vulkan, decompilerContext->output->uniformOffsetsVK);\n\t\tdecompilerContext->shaderSource->add(\"#else\" _CRLF);\n\t\t_emitUniformVariables(decompilerContext, RendererAPI::OpenGL, decompilerContext->output->uniformOffsetsGL);\n\t\tdecompilerContext->shaderSource->add(\"#endif\" _CRLF);\n\t\t// uniform buffers\n\t\t_emitUniformBuffers(decompilerContext);\n\t\t// textures\n\t\t_emitTextureDefinitions(decompilerContext);\n\t\t// attributes\n\t\t_emitAttributes(decompilerContext);\n\t\t// misc stuff\n\t\t_emitMisc(decompilerContext);\n\n\t\tif (dump_shaders_enabled)\n\t\t\tdecompilerContext->shaderSource->add(\"// end of shader inputs/outputs\" _CRLF);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSL.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\" // todo - remove dependency\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/helpers/StringBuf.h\"\n\n#include <bitset>\n#include <boost/container/small_vector.hpp>\n\n#define _CRLF\t\"\\r\\n\"\n\nvoid LatteDecompiler_emitAttributeDecodeMSL(LatteDecompilerShader* shaderContext, StringBuf* src, LatteParsedFetchShaderAttribute_t* attrib);\n\n/*\n * Variable names:\n * R0-R127 temp\n * Most variables are multi-typed and the respective type is appended to the name\n * Type suffixes are: f (float), i (32bit int), ui (unsigned 32bit int)\n * Examples: R13ui.x, tempf.z\n */\n\n// local prototypes\nvoid _emitTypeConversionPrefixMSL(LatteDecompilerShaderContext* shaderContext, sint32 sourceType, sint32 destinationType, sint32 componentCount = 1);\nvoid _emitTypeConversionSuffixMSL(LatteDecompilerShaderContext* shaderContext, sint32 sourceType, sint32 destinationType);\nvoid LatteDecompiler_emitClauseCodeMSL(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, bool isSubroutine);\n\nstatic const char* _getElementStrByIndex(uint32 channel)\n{\n\tswitch (channel)\n\t{\n\t\tcase 0:\n\t\t\treturn \"x\";\n\t\tcase 1:\n\t\t\treturn \"y\";\n\t\tcase 2:\n\t\t\treturn \"z\";\n\t\tcase 3:\n\t\t\treturn \"w\";\n\t}\n\treturn \"UNDEFINED\";\n}\n\nstatic char _tempGenString[64][256];\nstatic uint32 _tempGenStringIndex = 0;\n\nstatic char* _getTempString()\n{\n\tchar* str = _tempGenString[_tempGenStringIndex];\n\t_tempGenStringIndex = (_tempGenStringIndex+1)%64;\n\treturn str;\n}\n\nstatic char* _getActiveMaskVarName(LatteDecompilerShaderContext* shaderContext, sint32 index)\n{\n\tchar* varName = _getTempString();\n\tif (shaderContext->isSubroutine)\n\t\tsprintf(varName, \"activeMaskStackSub%04x[%d]\", shaderContext->subroutineInfo->cfAddr, index);\n\telse\n\t\tsprintf(varName, \"activeMaskStack[%d]\", index);\n\treturn varName;\n}\n\nstatic char* _getActiveMaskCVarName(LatteDecompilerShaderContext* shaderContext, sint32 index)\n{\n\tchar* varName = _getTempString();\n\tif (shaderContext->isSubroutine)\n\t\tsprintf(varName, \"activeMaskStackCSub%04x[%d]\", shaderContext->subroutineInfo->cfAddr, index);\n\telse\n\t\tsprintf(varName, \"activeMaskStackC[%d]\", index);\n\treturn varName;\n}\n\nstatic char* _getRegisterVarName(LatteDecompilerShaderContext* shaderContext, uint32 index, sint32 destRelIndexMode=-1)\n{\n\tauto type = shaderContext->typeTracker.defaultDataType;\n\tchar* tempStr = _getTempString();\n\tif (shaderContext->typeTracker.useArrayGPRs == false)\n\t{\n\t\tif (type == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\tsprintf(tempStr, \"R%di\", index);\n\t\telse if (type == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\tsprintf(tempStr, \"R%df\", index);\n\t}\n\telse\n\t{\n\t\tchar destRelOffset[32];\n\t\tif (destRelIndexMode >= 0)\n\t\t{\n\t\t\tif (destRelIndexMode == GPU7_INDEX_AR_X)\n\t\t\t\tstrcpy(destRelOffset, \"ARi.x\");\n\t\t\telse if (destRelIndexMode == GPU7_INDEX_AR_Y)\n\t\t\t\tstrcpy(destRelOffset, \"ARi.y\");\n\t\t\telse if (destRelIndexMode == GPU7_INDEX_AR_Z)\n\t\t\t\tstrcpy(destRelOffset, \"ARi.z\");\n\t\t\telse if (destRelIndexMode == GPU7_INDEX_AR_W)\n\t\t\t\tstrcpy(destRelOffset, \"ARi.w\");\n\t\t\telse\n\t\t\t\tdebugBreakpoint();\n\t\t\tif (type == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t{\n\t\t\t\tsprintf(tempStr, \"Ri[%d+%s]\", index, destRelOffset);\n\t\t\t}\n\t\t\telse if (type == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t{\n\t\t\t\tsprintf(tempStr, \"Rf[%d+%s]\", index, destRelOffset);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (type == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t{\n\t\t\t\tsprintf(tempStr, \"Ri[%d]\", index);\n\t\t\t}\n\t\t\telse if (type == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t{\n\t\t\t\tsprintf(tempStr, \"Rf[%d]\", index);\n\t\t\t}\n\t\t}\n\t}\n\treturn tempStr;\n}\n\nstatic void _appendRegisterTypeSuffix(StringBuf* src, sint32 dataType)\n{\n\tif (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\tsrc->add(\"i\");\n\telse if (dataType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT)\n\t\tsrc->add(\"ui\");\n\telse if (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\tsrc->add(\"f\");\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\n// appends x/y/z/w\nstatic void _appendChannel(StringBuf* src, sint32 channelIndex)\n{\n\tcemu_assert_debug(channelIndex >= 0 && channelIndex <= 3);\n\tswitch (channelIndex)\n\t{\n\tcase 0:\n\t\tsrc->add(\"x\");\n\t\treturn;\n\tcase 1:\n\t\tsrc->add(\"y\");\n\t\treturn;\n\tcase 2:\n\t\tsrc->add(\"z\");\n\t\treturn;\n\tcase 3:\n\t\tsrc->add(\"w\");\n\t\treturn;\n\t}\n}\n\n// appends .x/.y/.z/.w\nstatic void _appendChannelAccess(StringBuf* src, sint32 channelIndex)\n{\n\tcemu_assert_debug(channelIndex >= 0 && channelIndex <= 3);\n\tswitch (channelIndex)\n\t{\n\tcase 0:\n\t\tsrc->add(\".x\");\n\t\treturn;\n\tcase 1:\n\t\tsrc->add(\".y\");\n\t\treturn;\n\tcase 2:\n\t\tsrc->add(\".z\");\n\t\treturn;\n\tcase 3:\n\t\tsrc->add(\".w\");\n\t\treturn;\n\t}\n}\n\nstatic void _appendPVPS(LatteDecompilerShaderContext* shaderContext, StringBuf* src, uint32 groupIndex, uint8 aluUnit)\n{\n\tcemu_assert_debug(aluUnit < 5);\n\tif (aluUnit == 4)\n\t{\n\t\tsrc->addFmt(\"PS{}\", (groupIndex & 1));\n\t\t_appendRegisterTypeSuffix(src, shaderContext->typeTracker.defaultDataType);\n\t\treturn;\n\t}\n\tsrc->addFmt(\"PV{}\", (groupIndex & 1));\n\t_appendRegisterTypeSuffix(src, shaderContext->typeTracker.defaultDataType);\n\t_appendChannel(src, aluUnit);\n}\n\nstd::string _FormatFloatAsConstant(float f)\n{\n\tchar floatAsStr[64];\n\tsize_t floatAsStrLen = fmt::format_to_n(floatAsStr, 64, \"{:#}\", f).size;\n\tsize_t floatAsStrLenOrg = floatAsStrLen;\n\tif(floatAsStrLen > 0 && floatAsStr[floatAsStrLen-1] == '.')\n\t{\n\t\tfloatAsStr[floatAsStrLen] = '0';\n\t\tfloatAsStrLen++;\n\t}\n\tcemu_assert(floatAsStrLen < 50); // constant suspiciously long?\n\tfloatAsStr[floatAsStrLen] = '\\0';\n\tcemu_assert_debug(floatAsStrLen >= 3); // shortest possible form is \"0.0\"\n\treturn floatAsStr;\n}\n\n// tracks PV/PS and register backups\nstruct ALUClauseTemporariesState\n{\n\tstruct PVPSAlias\n\t{\n\t\tenum class LOCATION_TYPE : uint8\n\t\t{\n\t\t\tLOCATION_NONE,\n\t\t\tLOCATION_GPR,\n\t\t\tLOCATION_PVPS,\n\t\t};\n\n\t\tLOCATION_TYPE location{ LOCATION_TYPE::LOCATION_NONE };\n\t\tuint8 index; // GPR index or temporary index\n\t\tuint8 aluUnit; // x,y,z,w (or 5 for PS)\n\n\t\tvoid SetLocationGPR(uint8 gprIndex, uint8 channel)\n\t\t{\n\t\t\tcemu_assert_debug(channel < 4);\n\t\t\tthis->location = LOCATION_TYPE::LOCATION_GPR;\n\t\t\tthis->index = gprIndex;\n\t\t\tthis->aluUnit = channel;\n\t\t}\n\n\t\tvoid SetLocationPSPVTemporary(uint8 aluUnit, uint32 groupIndex)\n\t\t{\n\t\t\tcemu_assert_debug(aluUnit < 5);\n\t\t\tthis->location = LOCATION_TYPE::LOCATION_PVPS;\n\t\t\tthis->index = groupIndex & 1;\n\t\t\tthis->aluUnit = aluUnit;\n\t\t}\n\t};\n\n\tstruct GPRTemporary\n\t{\n\t\tGPRTemporary(uint8 gprIndex, uint8 channel, uint8 backupVarIndex) : gprIndex(gprIndex), channel(channel), backupVarIndex(backupVarIndex) {}\n\n\t\tuint8 gprIndex;\n\t\tuint8 channel;\n\t\tuint8 backupVarIndex;\n\t};\n\n\tvoid TrackGroupOutputPVPS(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstr, size_t numInstr)\n\t{\n\t\t// unset current\n\t\tfor (auto& it : m_pvps)\n\t\t\tit.location = PVPSAlias::LOCATION_TYPE::LOCATION_NONE;\n\t\tfor (size_t i = 0; i < numInstr; i++)\n\t\t{\n\t\t\tLatteDecompilerALUInstruction& inst = aluInstr[i];\n\t\t\tif (!inst.isOP3 && inst.opcode == ALU_OP2_INST_NOP)\n\t\t\t\tcontinue; // skip NOP instruction\n\n\t\t\tif (inst.writeMask == 0)\n\t\t\t{\n\t\t\t\t// map to temporary\n\t\t\t\tm_pvps[inst.aluUnit].SetLocationPSPVTemporary(inst.aluUnit, aluInstr->instructionGroupIndex);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// map to GPR\n\t\t\t\tif(inst.destRel == 0) // is PV/PS set for indexed writes?\n\t\t\t\t\tm_pvps[inst.aluUnit].SetLocationGPR(inst.destGpr, inst.destElem);\n\t\t\t}\n\t\t}\n\t}\n\n\tbool HasPVPS(uint8 aluUnitIndex) const\n\t{\n\t\tcemu_assert_debug(aluUnitIndex < 5);\n\t\treturn m_pvps[aluUnitIndex].location != PVPSAlias::LOCATION_TYPE::LOCATION_NONE;\n\t}\n\n\tvoid EmitPVPSAccess(LatteDecompilerShaderContext* shaderContext, uint8 aluUnitIndex, uint32 currentGroupIndex) const\n\t{\n\t\tswitch (m_pvps[aluUnitIndex].location)\n\t\t{\n\t\tcase PVPSAlias::LOCATION_TYPE::LOCATION_GPR:\n\t\t{\n\t\t\tsint32 temporaryIndex = GetTemporaryForGPR(m_pvps[aluUnitIndex].index, m_pvps[aluUnitIndex].aluUnit);\n\t\t\tif (temporaryIndex < 0)\n\t\t\t{\n\t\t\t\tshaderContext->shaderSource->add(_getRegisterVarName(shaderContext, m_pvps[aluUnitIndex].index, -1));\n\t\t\t\t_appendChannelAccess(shaderContext->shaderSource, m_pvps[aluUnitIndex].aluUnit);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// use temporary instead of GPR\n\t\t\t\tshaderContext->shaderSource->addFmt(\"backupReg{}\", temporaryIndex);\n\t\t\t\t_appendRegisterTypeSuffix(shaderContext->shaderSource, shaderContext->typeTracker.defaultDataType);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase PVPSAlias::LOCATION_TYPE::LOCATION_PVPS:\n\t\t\t_appendPVPS(shaderContext, shaderContext->shaderSource, currentGroupIndex-1, m_pvps[aluUnitIndex].aluUnit);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemuLog_log(LogType::Force, \"Shader {:016x} accesses PV/PS without writing to it\", shaderContext->shaderBaseHash);\n\t\t\tcemu_assert_suspicious();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/*\n\t * Check for GPR channels which are modified before they are read within the same group\n\t * These registers need to be copied to a temporary\n\t */\n\tvoid CreateGPRTemporaries(LatteDecompilerShaderContext* shaderContext, std::span<LatteDecompilerALUInstruction> aluInstructions)\n\t{\n\t\tuint8 registerChannelWriteMask[(LATTE_NUM_GPR * 4 + 7) / 8] = { 0 };\n\n\t\tm_gprTemporaries.clear();\n\t\tfor (auto& aluInstruction : aluInstructions)\n\t\t{\n\t\t\t// ignore NOP instructions\n\t\t\tif (aluInstruction.isOP3 == false && aluInstruction.opcode == ALU_OP2_INST_NOP)\n\t\t\t\tcontinue;\n\t\t\tcemu_assert_debug(aluInstruction.destElem <= 3);\n\t\t\t// check if any previously written register is read\n\t\t\tfor (sint32 f = 0; f < 3; f++)\n\t\t\t{\n\t\t\t\tuint32 readGPRIndex;\n\t\t\t\tuint32 readGPRChannel;\n\t\t\t\tif (GPU7_ALU_SRC_IS_GPR(aluInstruction.sourceOperand[f].sel))\n\t\t\t\t{\n\t\t\t\t\treadGPRIndex = GPU7_ALU_SRC_GET_GPR_INDEX(aluInstruction.sourceOperand[f].sel);\n\t\t\t\t\tcemu_assert_debug(aluInstruction.sourceOperand[f].chan <= 3);\n\t\t\t\t\treadGPRChannel = aluInstruction.sourceOperand[f].chan;\n\t\t\t\t}\n\t\t\t\telse if (GPU7_ALU_SRC_IS_PV(aluInstruction.sourceOperand[f].sel) || GPU7_ALU_SRC_IS_PS(aluInstruction.sourceOperand[f].sel))\n\t\t\t\t{\n\t\t\t\t\tuint8 aluUnitIndex = 0;\n\t\t\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstruction.sourceOperand[f].sel))\n\t\t\t\t\t\taluUnitIndex = aluInstruction.sourceOperand[f].chan;\n\t\t\t\t\telse\n\t\t\t\t\t\taluUnitIndex = 4;\n\t\t\t\t\t// if aliased to a GPR, then consider it a GPR read\n\t\t\t\t\tif(m_pvps[aluUnitIndex].location != PVPSAlias::LOCATION_TYPE::LOCATION_GPR)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\treadGPRIndex = m_pvps[aluUnitIndex].index;\n\t\t\t\t\treadGPRChannel = m_pvps[aluUnitIndex].aluUnit;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tcontinue;\n\t\t\t\t// track GPR read\n\t\t\t\tif ((registerChannelWriteMask[(readGPRIndex * 4 + aluInstruction.sourceOperand[f].chan) / 8] & (1 << ((readGPRIndex * 4 + aluInstruction.sourceOperand[f].chan) % 8))) != 0)\n\t\t\t\t{\n\t\t\t\t\t// register is overwritten by previous instruction, a temporary variable is required\n\t\t\t\t\tif (GetTemporaryForGPR(readGPRIndex, readGPRChannel) < 0)\n\t\t\t\t\t\tm_gprTemporaries.emplace_back(readGPRIndex, readGPRChannel, m_gprTemporaries.size());\n\t\t\t\t}\n\t\t\t}\n\t\t\t// track write\n\t\t\tif (aluInstruction.writeMask != 0)\n\t\t\t\tregisterChannelWriteMask[(aluInstruction.destGpr * 4 + aluInstruction.destElem) / 8] |= (1 << ((aluInstruction.destGpr * 4 + aluInstruction.destElem) % 8));\n\t\t}\n\t\t// output code to move GPRs into temporaries\n\t\tStringBuf* src = shaderContext->shaderSource;\n\t\tfor (auto& it : m_gprTemporaries)\n\t\t{\n\t\t\tsrc->addFmt(\"backupReg{}\", it.backupVarIndex);\n\t\t\t_appendRegisterTypeSuffix(src, shaderContext->typeTracker.defaultDataType);\n\t\t\tsrc->add(\" = \");\n\t\t\tsrc->add(_getRegisterVarName(shaderContext, it.gprIndex));\n\t\t\t_appendChannelAccess(src, it.channel);\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t}\n\n\t// returns -1 if none present\n\tsint32 GetTemporaryForGPR(uint8 gprIndex, uint8 channel) const\n\t{\n\t\tfor (auto& it : m_gprTemporaries)\n\t\t{\n\t\t\tif (it.gprIndex == gprIndex && it.channel == channel)\n\t\t\t\treturn (sint32)it.backupVarIndex;\n\t\t}\n\t\treturn -1;\n\t}\n\nprivate:\n\tPVPSAlias m_pvps[5]{};\n\tboost::container::small_vector<GPRTemporary, 4> m_gprTemporaries;\n};\n\nsint32 _getVertexShaderOutParamSemanticId(uint32* contextRegisters, sint32 index);\nsint32 _getInputRegisterDataType(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex);\nsint32 _getALUInstructionOutputDataType(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction);\nbool _isReductionInstruction(LatteDecompilerALUInstruction* aluInstruction);\n\n/*\n * Writes the name of the output variable and channel\n * E.g. R5f.x or tempf.x if writeMask is 0\n */\nstatic void _emitInstructionOutputVariableName(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction)\n{\n\tauto src = shaderContext->shaderSource;\n\tsint32 outputDataType = _getALUInstructionOutputDataType(shaderContext, aluInstruction);\n\tif( aluInstruction->writeMask == 0 )\n\t{\n\t\t// does not output to GPR\n\t\tif( !_isReductionInstruction(aluInstruction) )\n\t\t{\n\t\t\t// output to PV/PS\n\t\t\t_appendPVPS(shaderContext, src, aluInstruction->instructionGroupIndex, aluInstruction->aluUnit);\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// output to temp\n\t\t\tsrc->add(\"temp\");\n\t\t\t_appendRegisterTypeSuffix(src, outputDataType);\n\t\t}\n\t\t_appendChannelAccess(src, aluInstruction->aluUnit);\n\t}\n\telse\n\t{\n\t\t// output to GPR. Aliasing to PV/PS happens at the end of the group\n\t\tsrc->add(_getRegisterVarName(shaderContext, aluInstruction->destGpr, aluInstruction->destRel==0?-1:aluInstruction->indexMode));\n\t\t_appendChannelAccess(src, aluInstruction->destElem);\n\t}\n}\n\nstatic void _emitInstructionPVPSOutputVariableName(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction)\n{\n\t_appendPVPS(shaderContext, shaderContext->shaderSource, aluInstruction->instructionGroupIndex, aluInstruction->aluUnit);\n}\n\nstatic void _emitRegisterAccessCode(LatteDecompilerShaderContext* shaderContext, sint32 gprIndex, sint32 channel0, sint32 channel1, sint32 channel2, sint32 channel3, sint32 dataType = -1)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 registerElementDataType = shaderContext->typeTracker.defaultDataType;\n\tcemu_assert_debug(gprIndex >= 0 && gprIndex <= 127);\n\n\tsint32 channelArray[4];\n\tchannelArray[0] = channel0;\n\tchannelArray[1] = channel1;\n\tchannelArray[2] = channel2;\n\tchannelArray[3] = channel3;\n\n\tsint32 numComponents = 0;\n\tfor (sint32 i = 0; i < 4; i++)\n\t{\n\t\tif (channelArray[i] >= 0 && channelArray[i] <= 3)\n\t\t    numComponents++;\n\t}\n\n\tif (dataType >= 0)\n\t{\n\t\t_emitTypeConversionPrefixMSL(shaderContext, registerElementDataType, dataType, numComponents);\n\t}\n\tif (shaderContext->typeTracker.useArrayGPRs)\n\t\tsrc->add(\"R\");\n\telse\n\t\tsrc->addFmt(\"R{}\", gprIndex);\n\t_appendRegisterTypeSuffix(src, registerElementDataType);\n\tif (shaderContext->typeTracker.useArrayGPRs)\n\t\tsrc->addFmt(\"[{}]\", gprIndex);\n\n\tsrc->add(\".\");\n\n\tfor (sint32 i = 0; i < 4; i++)\n\t{\n\t\tif (channelArray[i] >= 0 && channelArray[i] <= 3)\n\t\t\tsrc->add(_getElementStrByIndex(channelArray[i]));\n\t\telse if (channelArray[i] == -1)\n\t\t{\n\t\t\t// channel not used\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\tif (dataType >= 0)\n\t\t_emitTypeConversionSuffixMSL(shaderContext, registerElementDataType, dataType);\n}\n\n// optimized variant of _emitRegisterAccessCode for raw one channel reads\nstatic void _emitRegisterChannelAccessCode(LatteDecompilerShaderContext* shaderContext, sint32 gprIndex, sint32 channel, sint32 dataType)\n{\n\tcemu_assert_debug(gprIndex >= 0 && gprIndex <= 127);\n\tcemu_assert_debug(channel >= 0 && channel < 4);\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 registerElementDataType = shaderContext->typeTracker.defaultDataType;\n\t_emitTypeConversionPrefixMSL(shaderContext, registerElementDataType, dataType);\n\tif (shaderContext->typeTracker.useArrayGPRs)\n\t\tsrc->add(\"R\");\n\telse\n\t\tsrc->addFmt(\"R{}\", gprIndex);\n\t_appendRegisterTypeSuffix(src, registerElementDataType);\n\tif (shaderContext->typeTracker.useArrayGPRs)\n\t\tsrc->addFmt(\"[{}]\", gprIndex);\n\tsrc->add(\".\");\n\tsrc->add(_getElementStrByIndex(channel));\n\t_emitTypeConversionSuffixMSL(shaderContext, registerElementDataType, dataType);\n}\n\nstatic void _emitALURegisterInputAccessCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 currentRegisterElementType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\tcemu_assert_debug(GPU7_ALU_SRC_IS_GPR(aluInstruction->sourceOperand[operandIndex].sel));\n\tsint32 gprIndex = GPU7_ALU_SRC_GET_GPR_INDEX(aluInstruction->sourceOperand[operandIndex].sel);\n\tsint32 temporaryIndex = shaderContext->aluPVPSState->GetTemporaryForGPR(gprIndex, aluInstruction->sourceOperand[operandIndex].chan);\n\tif(temporaryIndex >= 0)\n\t{\n\t\t// access via backup variable\n\t\tsrc->addFmt(\"backupReg{}\", temporaryIndex);\n\t\t_appendRegisterTypeSuffix(src, currentRegisterElementType);\n\t}\n\telse\n\t{\n\t\t// access via register variable\n\t\t_emitRegisterAccessCode(shaderContext, gprIndex, aluInstruction->sourceOperand[operandIndex].chan, -1, -1, -1);\n\t}\n}\n\nstatic void _emitPVPSAccessCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex, uint8 aluUnitIndex)\n{\n\tcemu_assert_debug(aluInstruction->instructionGroupIndex > 0); // PV/PS is uninitialized for group 0\n\t// PV/PS vars are currently always using the default type (shaderContext->typeTracker.defaultDataType)\n\tshaderContext->aluPVPSState->EmitPVPSAccess(shaderContext, aluUnitIndex, aluInstruction->instructionGroupIndex);\n}\n\n/*\n * Emits the expression used for calculating the index for uniform access\n * For static access, this is a number\n * For dynamic access, this is AR.* + base\n */\nstatic void _emitUniformAccessIndexCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tbool isUniformRegister = GPU7_ALU_SRC_IS_CFILE(aluInstruction->sourceOperand[operandIndex].sel);\n\tsint32 uniformOffset = 0; // index into array, for relative accesses this is the base offset\n\tif( isUniformRegister )\n\t{\n\t\tuniformOffset = GPU7_ALU_SRC_GET_CFILE_INDEX(aluInstruction->sourceOperand[operandIndex].sel);\n\t}\n\telse\n\t{\n\t\tif( GPU7_ALU_SRC_IS_CBANK0(aluInstruction->sourceOperand[operandIndex].sel) )\n\t\t{\n\t\t\tuniformOffset = GPU7_ALU_SRC_GET_CBANK0_INDEX(aluInstruction->sourceOperand[operandIndex].sel) + aluInstruction->cfInstruction->cBank0AddrBase;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuniformOffset = GPU7_ALU_SRC_GET_CBANK1_INDEX(aluInstruction->sourceOperand[operandIndex].sel) + aluInstruction->cfInstruction->cBank1AddrBase;\n\t\t}\n\t}\n\tif( aluInstruction->sourceOperand[operandIndex].rel != 0 )\n\t{\n\t\tif (aluInstruction->indexMode == GPU7_INDEX_AR_X)\n\t\t\tsrc->addFmt(\"ARi.x+{}\", uniformOffset);\n\t\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_Y)\n\t\t\tsrc->addFmt(\"ARi.y+{}\", uniformOffset);\n\t\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_Z)\n\t\t\tsrc->addFmt(\"ARi.z+{}\", uniformOffset);\n\t\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_W)\n\t\t\tsrc->addFmt(\"ARi.w+{}\", uniformOffset);\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse\n\t{\n\t\tsrc->addFmt(\"{}\", uniformOffset);\n\t}\n}\n\nstatic void _emitUniformAccessCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex, sint32 requiredType)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif(shaderContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED )\n\t{\n\t\t// uniform registers or buffers are accessed statically with predictable offsets\n\t\t// find entry in remapped uniform\n\t\tif( aluInstruction->sourceOperand[operandIndex].rel != 0 )\n\t\t\tdebugBreakpoint();\n\t\tbool isUniformRegister = GPU7_ALU_SRC_IS_CFILE(aluInstruction->sourceOperand[operandIndex].sel);\n\t\tsint32 uniformOffset = 0; // index into array\n\t\tsint32 uniformBufferIndex = 0;\n\t\tif( isUniformRegister )\n\t\t{\n\t\t\tuniformOffset = GPU7_ALU_SRC_GET_CFILE_INDEX(aluInstruction->sourceOperand[operandIndex].sel);\n\t\t\tuniformBufferIndex = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif( GPU7_ALU_SRC_IS_CBANK0(aluInstruction->sourceOperand[operandIndex].sel) )\n\t\t\t{\n\t\t\t\tuniformOffset = GPU7_ALU_SRC_GET_CBANK0_INDEX(aluInstruction->sourceOperand[operandIndex].sel) + aluInstruction->cfInstruction->cBank0AddrBase;\n\t\t\t\tuniformBufferIndex = aluInstruction->cfInstruction->cBank0Index;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuniformOffset = GPU7_ALU_SRC_GET_CBANK1_INDEX(aluInstruction->sourceOperand[operandIndex].sel) + aluInstruction->cfInstruction->cBank1AddrBase;\n\t\t\t\tuniformBufferIndex = aluInstruction->cfInstruction->cBank1Index;\n\t\t\t}\n\t\t}\n\t\tLatteDecompilerRemappedUniformEntry_t* remappedUniformEntry = NULL;\n\t\tfor(size_t i=0; i< shaderContext->shader->list_remappedUniformEntries.size(); i++)\n\t\t{\n\t\t\tLatteDecompilerRemappedUniformEntry_t* remappedUniformEntryItr = shaderContext->shader->list_remappedUniformEntries.data() + i;\n\t\t\tif( remappedUniformEntryItr->isRegister && isUniformRegister )\n\t\t\t{\n\t\t\t\tif( remappedUniformEntryItr->index == uniformOffset )\n\t\t\t\t{\n\t\t\t\t\tremappedUniformEntry = remappedUniformEntryItr;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif( remappedUniformEntryItr->kcacheBankId == uniformBufferIndex && remappedUniformEntryItr->index == uniformOffset )\n\t\t\t\t{\n\t\t\t\t\tremappedUniformEntry = remappedUniformEntryItr;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcemu_assert_debug(remappedUniformEntry);\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n\t\tsrc->addFmt(\"supportBuffer.remapped[{}]\", remappedUniformEntry->mappedIndex);\n\t\t_appendChannelAccess(src, aluInstruction->sourceOperand[operandIndex].chan);\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n\t}\n\telse if( shaderContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE )\n\t{\n\t\t// uniform registers are accessed with unpredictable (dynamic) offset\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n\t\tsrc->add(\"supportBuffer.uniformRegister[\");\n\t\t_emitUniformAccessIndexCode(shaderContext, aluInstruction, operandIndex);\n\t\tsrc->add(\"]\");\n\n\t\t_appendChannelAccess(src, aluInstruction->sourceOperand[operandIndex].chan);\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n\t}\n\telse if( shaderContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK )\n\t{\n\t\t// uniform buffers are available as a whole\n\t\tbool isUniformRegister = GPU7_ALU_SRC_IS_CFILE(aluInstruction->sourceOperand[operandIndex].sel);\n\t\tif( isUniformRegister )\n\t\t\tdebugBreakpoint();\n\t\tsint32 uniformBufferIndex = 0;\n\t\tif( GPU7_ALU_SRC_IS_CBANK0(aluInstruction->sourceOperand[operandIndex].sel) )\n\t\t{\n\t\t\tuniformBufferIndex = aluInstruction->cfInstruction->cBank0Index;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuniformBufferIndex = aluInstruction->cfInstruction->cBank1Index;\n\t\t}\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t\tsrc->addFmt(\"ubuff{}.d[\", uniformBufferIndex);\n\t\t_emitUniformAccessIndexCode(shaderContext, aluInstruction, operandIndex);\n\t\tsrc->addFmt(\"]\");\n\n\t\t_appendChannelAccess(src, aluInstruction->sourceOperand[operandIndex].chan);\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t}\n\telse\n\t\tdebugBreakpoint();\n}\n\n// Generates (slow) code to read an indexed GPR\nstatic void _emitCodeToReadRelativeGPR(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex, sint32 requiredType)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tuint32 gprBaseIndex = GPU7_ALU_SRC_GET_GPR_INDEX(aluInstruction->sourceOperand[operandIndex].sel);\n\tcemu_assert_debug(aluInstruction->sourceOperand[operandIndex].rel != 0);\n\n\tif( shaderContext->typeTracker.useArrayGPRs )\n\t{\n\t\t_emitTypeConversionPrefixMSL(shaderContext, shaderContext->typeTracker.defaultDataType, requiredType);\n\t\tsrc->add(_getRegisterVarName(shaderContext, gprBaseIndex, aluInstruction->indexMode));\n\t\t_appendChannelAccess(src, aluInstruction->sourceOperand[operandIndex].chan);\n\t\t_emitTypeConversionSuffixMSL(shaderContext, shaderContext->typeTracker.defaultDataType, requiredType);\n\t\treturn;\n\t}\n\n\tchar indexAccessCode[64];\n\tif (aluInstruction->indexMode == GPU7_INDEX_AR_X)\n\t\tsprintf(indexAccessCode, \"ARi.x\");\n\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_Y)\n\t\tsprintf(indexAccessCode, \"ARi.y\");\n\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_Z)\n\t\tsprintf(indexAccessCode, \"ARi.z\");\n\telse if (aluInstruction->indexMode == GPU7_INDEX_AR_W)\n\t\tsprintf(indexAccessCode, \"ARi.w\");\n\telse\n\t\tcemu_assert_unimplemented();\n\n\tif( LATTE_DECOMPILER_DTYPE_SIGNED_INT != requiredType )\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n\n\t// generated code looks like this:\n\t// result = ((lookupIndex==0)?GPR5:(lookupIndex==1)?GPR6:(lookupIndex==2)?GPR7:...:(lookupIndex==122)?GPR127:0)\n\tsrc->add(\"(\");\n\tfor(sint32 i=gprBaseIndex; i<LATTE_NUM_GPR; i++)\n\t{\n\t\t// only emit access code for registers which are potentially written\n\t\tif((shaderContext->analyzer.gprUseMask[i / 8] & (1 << (i % 8))) == 0 )\n\t\t\tcontinue;\n\t\tsrc->addFmt(\"({}=={})?\", indexAccessCode, i-gprBaseIndex);\n\t\t// code to access gpr\n\t\tuint32 gprIndex = i;\n\t\tsrc->add(_getRegisterVarName(shaderContext, i));\n\t\t_appendChannelAccess(src, aluInstruction->sourceOperand[operandIndex].chan);\n\t\tsrc->add(\":\");\n\t}\n\tsrc->add(\"0)\");\n\tif( LATTE_DECOMPILER_DTYPE_SIGNED_INT != requiredType )\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, requiredType);\n}\n\nstatic void _emitOperandInputCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, sint32 operandIndex, sint32 requiredType)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif(\toperandIndex < 0 || operandIndex >= 3 )\n\t\tdebugBreakpoint();\n\tsint32 requiredTypeOut = requiredType;\n\tif( requiredType != LATTE_DECOMPILER_DTYPE_FLOAT && (aluInstruction->sourceOperand[operandIndex].abs != 0 || aluInstruction->sourceOperand[operandIndex].neg != 0) )\n\t{\n\t\t// we need to apply float operations on the input but it's not read as a float\n\t\t// force internal required type to float and then cast it back to whatever type is actually required\n\t\trequiredType = LATTE_DECOMPILER_DTYPE_FLOAT;\n\t}\n\n\tif( requiredTypeOut != requiredType )\n\t\t_emitTypeConversionPrefixMSL(shaderContext, requiredType, requiredTypeOut);\n\n\tif( aluInstruction->sourceOperand[operandIndex].neg != 0 )\n\t\tsrc->add(\"-(\");\n\tif( aluInstruction->sourceOperand[operandIndex].abs != 0 )\n\t\tsrc->add(\"abs(\");\n\n\tif( GPU7_ALU_SRC_IS_GPR(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tif( aluInstruction->sourceOperand[operandIndex].rel != 0 )\n\t\t{\n\t\t\t_emitCodeToReadRelativeGPR(shaderContext, aluInstruction, operandIndex, requiredType);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint32 gprIndex = GPU7_ALU_SRC_GET_GPR_INDEX(aluInstruction->sourceOperand[operandIndex].sel);\n\t\t\tif( requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t{\n\t\t\t\t// signed int 32bit\n\t\t\t\tsint32 currentRegisterElementType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\t\t\t\t// write code for register input\n\t\t\t\t_emitTypeConversionPrefixMSL(shaderContext, currentRegisterElementType, requiredType);\n\t\t\t\t_emitALURegisterInputAccessCode(shaderContext, aluInstruction, operandIndex);\n\t\t\t\t_emitTypeConversionSuffixMSL(shaderContext, currentRegisterElementType, requiredType);\n\t\t\t}\n\t\t\telse if( requiredType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT )\n\t\t\t{\n\t\t\t\t// unsigned int 32bit\n\t\t\t\tsint32 currentRegisterElementType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\t\t\t\tif( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t\t{\n\t\t\t\t\t// need to convert from int to uint\n\t\t\t\t\tsrc->add(\"uint(\");\n\t\t\t\t}\n\t\t\t\telse if( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT )\n\t\t\t\t{\n\t\t\t\t\t// no extra work necessary\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tdebugBreakpoint();\n\t\t\t\t// write code for register input\n\t\t\t\t_emitALURegisterInputAccessCode(shaderContext, aluInstruction, operandIndex);\n\t\t\t\tif( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t\t{\n\t\t\t\t\tsrc->add(\")\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if( requiredType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\t\t{\n\t\t\t\t// float 32bit\n\t\t\t\tsint32 currentRegisterElementType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\t\t\t\tif( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t\t{\n\t\t\t\t\t// need to convert (not cast) from int bits to float\n\t\t\t\t\tsrc->add(\"as_type<float>(\"); // TODO: correct?\n\t\t\t\t}\n\t\t\t\telse if( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\t\t\t{\n\t\t\t\t\t// no extra work necessary\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tdebugBreakpoint();\n\t\t\t\t// write code for register input\n\t\t\t\t_emitALURegisterInputAccessCode(shaderContext, aluInstruction, operandIndex);\n\t\t\t\tif( currentRegisterElementType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t\t{\n\t\t\t\t\tsrc->add(\")\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\telse if( GPU7_ALU_SRC_IS_CONST_0F(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tif(requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT || requiredType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT)\n\t\t\tsrc->add(\"0\");\n\t\telse if( requiredType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\t\tsrc->add(\"0.0\");\n\t}\n\telse if( GPU7_ALU_SRC_IS_CONST_1F(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t\tsrc->add(\"1.0\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t}\n\telse if( GPU7_ALU_SRC_IS_CONST_0_5F(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t\tsrc->add(\"0.5\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, requiredType);\n\t}\n\telse if( GPU7_ALU_SRC_IS_CONST_1I(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tif (requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\tsrc->add(\"int(1)\");\n\t\telse if (requiredType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT)\n\t\t\tsrc->add(\"uint(1)\");\n\t\telse\n\t\t\tcemu_assert_suspicious();\n\t}\n\telse if( GPU7_ALU_SRC_IS_CONST_M1I(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tif( requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\tsrc->add(\"int(-1)\");\n\t\telse\n\t\t\tcemu_assert_suspicious();\n\t}\n\telse if( GPU7_ALU_SRC_IS_LITERAL(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tif( requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\tsrc->addFmt(\"int(0x{:x})\", aluInstruction->literalData.w[aluInstruction->sourceOperand[operandIndex].chan]);\n\t\telse if( requiredType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT )\n\t\t\tsrc->addFmt(\"uint(0x{:x})\", aluInstruction->literalData.w[aluInstruction->sourceOperand[operandIndex].chan]);\n\t\telse if (requiredType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t{\n\t\t\tuint32 constVal = aluInstruction->literalData.w[aluInstruction->sourceOperand[operandIndex].chan];\n\t\t\tsint32 exponent = (constVal >> 23) & 0xFF;\n\t\t\texponent -= 127;\n\t\t\tif ((constVal & 0xFF) == 0 && exponent >= -10 && exponent <= 10)\n\t\t\t{\n\t\t\t\tsrc->add(_FormatFloatAsConstant(*(float*)&constVal));\n\t\t\t}\n\t\t\telse\n\t\t\t\tsrc->addFmt(\"as_type<float>(0x{:08x})\", constVal);\n\t\t}\n\t}\n\telse if( GPU7_ALU_SRC_IS_CFILE(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\t_emitUniformAccessCode(shaderContext, aluInstruction, operandIndex, requiredType);\n\t}\n\telse if( GPU7_ALU_SRC_IS_CBANK0(aluInstruction->sourceOperand[operandIndex].sel) ||\n\t\tGPU7_ALU_SRC_IS_CBANK1(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\t_emitUniformAccessCode(shaderContext, aluInstruction, operandIndex, requiredType);\n\t}\n\telse if( GPU7_ALU_SRC_IS_PV(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tsint32 currentPVDataType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\t\t_emitTypeConversionPrefixMSL(shaderContext, currentPVDataType, requiredType);\n\t\t_emitPVPSAccessCode(shaderContext, aluInstruction, operandIndex, aluInstruction->sourceOperand[operandIndex].chan);\n\t\t_emitTypeConversionSuffixMSL(shaderContext, currentPVDataType, requiredType);\n\t}\n\telse if( GPU7_ALU_SRC_IS_PS(aluInstruction->sourceOperand[operandIndex].sel) )\n\t{\n\t\tsint32 currentPSDataType = _getInputRegisterDataType(shaderContext, aluInstruction, operandIndex);\n\t\t_emitTypeConversionPrefixMSL(shaderContext, currentPSDataType, requiredType);\n\t\t_emitPVPSAccessCode(shaderContext, aluInstruction, operandIndex, 4);\n\t\t_emitTypeConversionSuffixMSL(shaderContext, currentPSDataType, requiredType);\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"Unsupported shader ALU operand sel {:#x}\\n\", aluInstruction->sourceOperand[operandIndex].sel);\n\t\tdebugBreakpoint();\n\t}\n\n\tif( aluInstruction->sourceOperand[operandIndex].abs != 0 )\n\t\tsrc->add(\")\");\n\tif( aluInstruction->sourceOperand[operandIndex].neg != 0 )\n\t\tsrc->add(\")\");\n\n\tif( requiredTypeOut != requiredType )\n\t\t_emitTypeConversionSuffixMSL(shaderContext, requiredType, requiredTypeOut);\n}\n\nvoid _emitTypeConversionPrefixMSL(LatteDecompilerShaderContext* shaderContext, sint32 sourceType, sint32 destinationType, sint32 componentCount)\n{\n\tif( sourceType == destinationType )\n\t\treturn;\n\tStringBuf* src = shaderContext->shaderSource;\n\tif (destinationType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t{\n\t    if (componentCount == 1)\n\t\t\tsrc->add(\"as_type<int>(\");\n\t\telse\n            src->addFmt(\"as_type<int{}>(\", componentCount);\n\t}\n\telse if (destinationType == LATTE_DECOMPILER_DTYPE_UNSIGNED_INT)\n\t{\n\t    if (componentCount == 1)\n\t\t\tsrc->add(\"as_type<uint>(\");\n\t\telse\n            src->addFmt(\"as_type<uint{}>(\", componentCount);\n\t}\n\telse if (destinationType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t{\n\t    if (componentCount == 1)\n\t\t\tsrc->add(\"as_type<float>(\");\n\t\telse\n            src->addFmt(\"as_type<float{}>(\", componentCount);\n\t}\n\telse\n\t\tcemu_assert_debug(false);\n}\n\nvoid _emitTypeConversionSuffixMSL(LatteDecompilerShaderContext* shaderContext, sint32 sourceType, sint32 destinationType)\n{\n\tif( sourceType == destinationType )\n\t\treturn;\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->add(\")\");\n}\n\ntemplate<int TDataType>\nstatic void _emitALUOperationBinary(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluInstruction, const char* operandStr)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 outputType = _getALUInstructionOutputDataType(shaderContext, aluInstruction);\n\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\tsrc->add(\" = \");\n\t_emitTypeConversionPrefixMSL(shaderContext, TDataType, outputType);\n\t_emitOperandInputCode(shaderContext, aluInstruction, 0, TDataType);\n\tsrc->add((char*)operandStr);\n\t_emitOperandInputCode(shaderContext, aluInstruction, 1, TDataType);\n\t_emitTypeConversionSuffixMSL(shaderContext, TDataType, outputType);\n\tsrc->add(\";\" _CRLF);\n}\n\nstatic bool _isSameGPROperand(LatteDecompilerALUInstruction* aluInstruction, sint32 opIndexA, sint32 opIndexB)\n{\n\tif (aluInstruction->sourceOperand[opIndexA].sel != aluInstruction->sourceOperand[opIndexB].sel)\n\t\treturn false;\n\tif (!GPU7_ALU_SRC_IS_GPR(aluInstruction->sourceOperand[opIndexA].sel))\n\t\treturn false;\n\tif (aluInstruction->sourceOperand[opIndexA].chan != aluInstruction->sourceOperand[opIndexB].chan)\n\t\treturn false;\n\tif (aluInstruction->sourceOperand[opIndexA].abs != aluInstruction->sourceOperand[opIndexB].abs)\n\t\treturn false;\n\tif (aluInstruction->sourceOperand[opIndexA].neg != aluInstruction->sourceOperand[opIndexB].neg)\n\t\treturn false;\n\tif (aluInstruction->sourceOperand[opIndexA].rel != aluInstruction->sourceOperand[opIndexB].rel)\n\t\treturn false;\n\treturn true;\n}\n\nstatic bool _operandHasModifiers(LatteDecompilerALUInstruction* aluInstruction, sint32 opIndex)\n{\n\treturn aluInstruction->sourceOperand[opIndex].abs != 0 || aluInstruction->sourceOperand[opIndex].neg != 0;\n}\n\nstatic void _emitALUOP2InstructionCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, LatteDecompilerALUInstruction* aluInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 outputType = _getALUInstructionOutputDataType(shaderContext, aluInstruction); // data type of output\n\tif( aluInstruction->opcode == ALU_OP2_INST_MOV )\n\t{\n\t\tbool requiresFloatMove = false;\n\t\trequiresFloatMove = aluInstruction->sourceOperand[0].abs != 0 || aluInstruction->sourceOperand[0].neg != 0;\n\t\tif( requiresFloatMove )\n\t\t{\n\t\t\t// abs/neg operations are applied to source operand, do float based move\n\t\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\t\tsrc->add(\" = \");\n\t\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\t\tsrc->add(\" = \");\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, outputType);\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MOVA_FLOOR )\n\t{\n\t\tcemu_assert_debug(aluInstruction->writeMask == 0);\n\t\tcemu_assert_debug(aluInstruction->omod == 0);\n\t\tsrc->add(\"tempResultf = \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\";\" _CRLF);\n\t\tsrc->add(\"tempResultf = floor(tempResultf);\" _CRLF);\n\t\tsrc->add(\"tempResultf = clamp(tempResultf, -256.0, 255.0);\" _CRLF);\n\t\t// set AR\n\t\tif( aluInstruction->destElem == 0 )\n\t\t\tsrc->add(\"ARi.x = int(tempResultf);\" _CRLF);\n\t\telse if( aluInstruction->destElem == 1 )\n\t\t\tsrc->add(\"ARi.y = int(tempResultf);\" _CRLF);\n\t\telse if( aluInstruction->destElem == 2 )\n\t\t\tsrc->add(\"ARi.z = int(tempResultf);\" _CRLF);\n\t\telse\n\t\t\tsrc->add(\"ARi.w = int(tempResultf);\" _CRLF);\n\t\t// set output\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\tif( outputType != LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\tdebugBreakpoint(); // todo\n\t\tsrc->add(\"as_type<int>(tempResultf)\");\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MOVA_INT )\n\t{\n\t\tcemu_assert_debug(aluInstruction->writeMask == 0);\n\t\tcemu_assert_debug(aluInstruction->omod == 0);\n\t\tsrc->add(\"tempResulti = \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\";\" _CRLF);\n\t\tsrc->add(\"tempResulti = clamp(tempResulti, -256, 255);\" _CRLF);\n\t\t// set AR\n\t\tif( aluInstruction->destElem == 0 )\n\t\t\tsrc->add(\"ARi.x = tempResulti;\" _CRLF);\n\t\telse if( aluInstruction->destElem == 1 )\n\t\t\tsrc->add(\"ARi.y = tempResulti;\" _CRLF);\n\t\telse if( aluInstruction->destElem == 2 )\n\t\t\tsrc->add(\"ARi.z = tempResulti;\" _CRLF);\n\t\telse\n\t\t\tsrc->add(\"ARi.w = tempResulti;\" _CRLF);\n\t\t// set output\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\tif( outputType != LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\tdebugBreakpoint(); // todo\n\t\tsrc->add(\"tempResulti\");\n\t\tsrc->add(\";\" _CRLF);\n\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_ADD )\n\t{\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_FLOAT>(shaderContext, aluInstruction, \" + \");\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MUL )\n\t{\n\t\t// 0*anything is always 0\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\n\t\t// if any operand is a non-zero literal or constant we can use standard multiplication\n\t\tbool useDefaultMul = false;\n\t\tif (GPU7_ALU_SRC_IS_CONST_0F(aluInstruction->sourceOperand[0].sel) || GPU7_ALU_SRC_IS_CONST_0F(aluInstruction->sourceOperand[1].sel))\n\t\t{\n\t\t\t// result is always zero\n\t\t\tsrc->add(\"0.0\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// multiply\n\t\t\tif (GPU7_ALU_SRC_IS_LITERAL(aluInstruction->sourceOperand[0].sel) || GPU7_ALU_SRC_IS_LITERAL(aluInstruction->sourceOperand[1].sel) ||\n\t\t\t\tGPU7_ALU_SRC_IS_ANY_CONST(aluInstruction->sourceOperand[0].sel) || GPU7_ALU_SRC_IS_ANY_CONST(aluInstruction->sourceOperand[1].sel))\n\t\t\t{\n\t\t\t\tuseDefaultMul = true;\n\t\t\t}\n\t\t\tif (shaderContext->options->strictMul && useDefaultMul == false)\n\t\t\t{\n\t\t\t\tsrc->add(\"mul_nonIEEE(\");\n\t\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t\tsrc->add(\", \");\n\t\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t\tsrc->add(\")\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t\tsrc->add(\" * \");\n\t\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\t}\n\t\t}\n\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MUL_IEEE )\n\t{\n\t\t// 0*anything according to IEEE rules\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_FLOAT>(shaderContext, aluInstruction, \" * \");\n\t}\n\telse if (aluInstruction->opcode == ALU_OP2_INST_RECIP_IEEE)\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"1.0\");\n\t\tsrc->add(\" / \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if (aluInstruction->opcode == ALU_OP2_INST_RECIP_FF)\n\t{\n\t\t// untested (BotW bombs)\n\t\tsrc->add(\"tempResultf = 1.0 / (\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\");\" _CRLF);\n\t\t// INF becomes 0.0\n\t\tsrc->add(\"if( isinf(tempResultf) == true && (as_type<int>(tempResultf)&0x80000000) == 0 ) tempResultf = 0.0;\" _CRLF);\n\t\t// -INF becomes -0.0\n\t\tsrc->add(\"else if( isinf(tempResultf) == true && (as_type<int>(tempResultf)&0x80000000) != 0 ) tempResultf = -0.0;\" _CRLF);\n\t\t// assign result to output\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"tempResultf\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_RECIPSQRT_IEEE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_RECIPSQRT_CLAMPED ||\n\t\taluInstruction->opcode == ALU_OP2_INST_RECIPSQRT_FF )\n\t{\n\t\t// todo: This should be correct but testing is needed\n\t\tsrc->add(\"tempResultf = 1.0 / sqrt(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\");\" _CRLF);\n\t\tif (aluInstruction->opcode == ALU_OP2_INST_RECIPSQRT_CLAMPED)\n\t\t{\n\t\t\t// note: if( -INF < 0.0 ) does not resolve to true\n\t\t\tsrc->add(\"if( isinf(tempResultf) == true && (as_type<int>(tempResultf)&0x80000000) != 0 ) tempResultf = -3.40282347E+38F;\" _CRLF);\n\t\t\tsrc->add(\"else if( isinf(tempResultf) == true && (as_type<int>(tempResultf)&0x80000000) == 0 ) tempResultf = 3.40282347E+38F;\" _CRLF);\n\t\t}\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_RECIPSQRT_FF)\n\t\t{\n\t\t\t// untested (BotW bombs)\n\t\t\tsrc->add(\"if( isinf(tempResultf) == true && (as_type<int>(tempResultf)&0x80000000) != 0 ) tempResultf = -0.0;\" _CRLF);\n\t\t\tsrc->add(\"else if( isinf(tempResultf) == true && (as_type<int>(tempResultf)&0x80000000) == 0 ) tempResultf = 0.0;\" _CRLF);\n\t\t}\n\t\t// assign result to output\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"tempResultf\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MAX ||\n\t\taluInstruction->opcode == ALU_OP2_INST_MIN ||\n\t\taluInstruction->opcode == ALU_OP2_INST_MAX_DX10 ||\n\t\taluInstruction->opcode == ALU_OP2_INST_MIN_DX10 )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_MAX )\n\t\t\tsrc->add(\"max\");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_MIN )\n\t\t\tsrc->add(\"min\");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_MAX_DX10)\n\t\t\tsrc->add(\"max\");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_MIN_DX10)\n\t\t\tsrc->add(\"min\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\", \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_FLOOR ||\n\t\taluInstruction->opcode == ALU_OP2_INST_FRACT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_TRUNC )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_FLOOR )\n\t\t\tsrc->add(\"floor\");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_FRACT )\n\t\t\tsrc->add(\"fract\");\n\t\telse\n\t\t\tsrc->add(\"trunc\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_LOG_CLAMPED ||\n\t\taluInstruction->opcode == ALU_OP2_INST_LOG_IEEE )\n\t{\n\t\tsrc->add(\"tempResultf = max(0.0, \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\");\" _CRLF);\n\n\t\tsrc->add(\"tempResultf = log2(tempResultf);\" _CRLF);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_LOG_CLAMPED )\n\t\t{\n\t\t\tsrc->add(\"if( isinf(tempResultf) == true ) tempResultf = -3.40282347E+38F;\" _CRLF);\n\t\t}\n\t\t// assign result to output\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"tempResultf\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_RNDNE )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"rint(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_EXP_IEEE )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"exp2\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SQRT_IEEE )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"sqrt\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SIN ||\n\t\taluInstruction->opcode == ALU_OP2_INST_COS )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_SIN )\n\t\t\tsrc->add(\"sin\");\n\t\telse\n\t\t\tsrc->add(\"cos\");\n\t\tsrc->add(\"((\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")/0.1591549367)\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_FLT_TO_INT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"int\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_FLT_TO_UINT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_UNSIGNED_INT, outputType);\n\t\tsrc->add(\"uint\");\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_UNSIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_INT_TO_FLOAT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"float(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_UINT_TO_FLOAT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"float(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_UNSIGNED_INT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if (aluInstruction->opcode == ALU_OP2_INST_AND_INT)\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" & \");\n\telse if (aluInstruction->opcode == ALU_OP2_INST_OR_INT)\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" | \");\n\telse if (aluInstruction->opcode == ALU_OP2_INST_XOR_INT)\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" ^ \");\n\telse if( aluInstruction->opcode == ALU_OP2_INST_NOT_INT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"~(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\")\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_ADD_INT )\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" + \");\n\telse if( aluInstruction->opcode == ALU_OP2_INST_MAX_INT || aluInstruction->opcode == ALU_OP2_INST_MIN_INT ||\n\t\t\t aluInstruction->opcode == ALU_OP2_INST_MAX_UINT || aluInstruction->opcode == ALU_OP2_INST_MIN_UINT)\n\t{\n\t\t// not verified\n\t\tbool isUnsigned = aluInstruction->opcode == ALU_OP2_INST_MAX_UINT || aluInstruction->opcode == ALU_OP2_INST_MIN_UINT;\n\t\tauto opType = isUnsigned ? LATTE_DECOMPILER_DTYPE_UNSIGNED_INT : LATTE_DECOMPILER_DTYPE_SIGNED_INT;\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, opType, outputType);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_MAX_INT || aluInstruction->opcode == ALU_OP2_INST_MAX_UINT )\n\t\t\tsrc->add(\"max(\");\n\t\telse\n\t\t\tsrc->add(\"min(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, opType);\n\t\tsrc->add(\", \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, opType);\n\t\t_emitTypeConversionSuffixMSL(shaderContext, opType, outputType);\n\t\tsrc->add(\");\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SUB_INT )\n\t{\n\t\t// note: The AMD doc says src1 is on the left side but tests indicate otherwise. It's src0 - src1.\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" - \");\n\t}\n\telse if (aluInstruction->opcode == ALU_OP2_INST_MULLO_INT)\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" * \");\n\telse if (aluInstruction->opcode == ALU_OP2_INST_MULLO_UINT)\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_UNSIGNED_INT>(shaderContext, aluInstruction, \" * \");\n\telse if( aluInstruction->opcode == ALU_OP2_INST_LSHL_INT )\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" << \");\n\telse if( aluInstruction->opcode == ALU_OP2_INST_LSHR_INT )\n\t\t_emitALUOperationBinary<LATTE_DECOMPILER_DTYPE_SIGNED_INT>(shaderContext, aluInstruction, \" >> \");\n\telse if( aluInstruction->opcode == ALU_OP2_INST_ASHR_INT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\" >> \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETGE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETNE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETE )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_SETGT )\n\t\t\tsrc->add(\" > \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGE )\n\t\t\tsrc->add(\" >= \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_SETNE)\n\t\t\tsrc->add(\" != \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_SETE)\n\t\t\tsrc->add(\" == \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")?1.0:0.0\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGT_DX10 ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETE_DX10 ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETNE_DX10 ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETGE_DX10 )\n\t{\n\t\tif( aluInstruction->omod != 0 )\n\t\t\tdebugBreakpoint();\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"((\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_SETE_DX10 )\n\t\t\tsrc->add(\" == \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETNE_DX10 )\n\t\t\tsrc->add(\" != \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGT_DX10 )\n\t\t\tsrc->add(\" > \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGE_DX10 )\n\t\t\tsrc->add(\" >= \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")?-1:0)\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\");\n\t\tsrc->add(_CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SETE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETNE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETGT_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETGE_INT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_SETE_INT )\n\t\t\tsrc->add(\" == \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETNE_INT )\n\t\t\tsrc->add(\" != \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGT_INT )\n\t\t\tsrc->add(\" > \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGE_INT )\n\t\t\tsrc->add(\" >= \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\")?-1:0\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGE_UINT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_SETGT_UINT )\n\t{\n\t\t// todo: Unsure if the result is unsigned or signed\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_UNSIGNED_INT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_SETGE_UINT )\n\t\t\tsrc->add(\" >= \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_SETGT_UINT )\n\t\t\tsrc->add(\" > \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_UNSIGNED_INT);\n\t\tsrc->add(\")?int(0xFFFFFFFF):int(0x0)\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_PRED_SETGT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETGE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETNE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETNE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETGE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_PRED_SETGT_INT )\n\t{\n\t\tcemu_assert_debug(aluInstruction->writeMask == 0);\n\t\tbool isIntPred = (aluInstruction->opcode == ALU_OP2_INST_PRED_SETNE_INT) || (aluInstruction->opcode == ALU_OP2_INST_PRED_SETE_INT) || (aluInstruction->opcode == ALU_OP2_INST_PRED_SETGE_INT) || (aluInstruction->opcode == ALU_OP2_INST_PRED_SETGT_INT);\n\n\t\tsrc->add(\"predResult\");\n\t\tsrc->add(\" = (\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, isIntPred?LATTE_DECOMPILER_DTYPE_SIGNED_INT:LATTE_DECOMPILER_DTYPE_FLOAT);\n\n\t\tif (aluInstruction->opcode == ALU_OP2_INST_PRED_SETE || aluInstruction->opcode == ALU_OP2_INST_PRED_SETE_INT)\n\t\t\tsrc->add(\" == \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_PRED_SETGT || aluInstruction->opcode == ALU_OP2_INST_PRED_SETGT_INT)\n\t\t\tsrc->add(\" > \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_PRED_SETGE || aluInstruction->opcode == ALU_OP2_INST_PRED_SETGE_INT)\n\t\t\tsrc->add(\" >= \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_PRED_SETNE || aluInstruction->opcode == ALU_OP2_INST_PRED_SETNE_INT)\n\t\t\tsrc->add(\" != \");\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, isIntPred?LATTE_DECOMPILER_DTYPE_SIGNED_INT:LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\");\" _CRLF);\n\t\t// handle result of predicate instruction based on current ALU clause type\n\t\tif( cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE )\n\t\t{\n\t\t\tsrc->addFmt(\"{} = predResult;\" _CRLF, _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t\tsrc->addFmt(\"{} = predResult == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t}\n\t\telse if( cfInstruction->type == GPU7_CF_INST_ALU_BREAK )\n\t\t{\n\t\t\t// leave current loop\n\t\t\tsrc->add(\"if( predResult == false ) break;\" _CRLF);\n\t\t}\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_KILLE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_KILLNE_INT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_KILLGT_INT)\n\t{\n\t\tsrc->add(\"if( \");\n\t\tsrc->add(\" (\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_KILLE_INT )\n\t\t\tsrc->add(\" == \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_KILLNE_INT)\n\t\t\tsrc->add(\" != \");\n\t\telse if (aluInstruction->opcode == ALU_OP2_INST_KILLGT_INT)\n\t\t\tsrc->add(\" > \");\n\t\telse\n\t\t\tdebugBreakpoint();\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\")\");\n\t\tsrc->add(\") discard_fragment();\");\n\t\tsrc->add(_CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP2_INST_KILLGT ||\n\t\taluInstruction->opcode == ALU_OP2_INST_KILLGE ||\n\t\taluInstruction->opcode == ALU_OP2_INST_KILLE )\n\t{\n\t\tsrc->add(\"if( \");\n\t\tsrc->add(\" (\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tif( aluInstruction->opcode == ALU_OP2_INST_KILLGT )\n\t\t\tsrc->add(\" > \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_KILLGE )\n\t\t\tsrc->add(\" >= \");\n\t\telse if( aluInstruction->opcode == ALU_OP2_INST_KILLE )\n\t\t\tsrc->add(\" == \");\n\t\telse\n\t\t\tdebugBreakpoint();\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t\tsrc->add(\") discard_fragment();\");\n\t\tsrc->add(_CRLF);\n\t}\n\telse\n\t{\n\t\tsrc->add(\"Unsupported instruction;\" _CRLF);\n\t\tdebug_printf(\"Unsupported ALU op2 instruction 0x%x\\n\", aluInstruction->opcode);\n\t\tshaderContext->shader->hasError = true;\n\t}\n}\n\nstatic void _emitALUOP3InstructionCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, LatteDecompilerALUInstruction* aluInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tcemu_assert_debug(aluInstruction->destRel == 0); // todo\n\tsint32 outputType = _getALUInstructionOutputDataType(shaderContext, aluInstruction);\n\n\t/* check for common no-op or mov-like instructions */\n\tif (aluInstruction->opcode == ALU_OP3_INST_CMOVGE ||\n\t\taluInstruction->opcode == ALU_OP3_INST_CMOVE ||\n\t\taluInstruction->opcode == ALU_OP3_INST_CMOVGT ||\n\t\taluInstruction->opcode == ALU_OP3_INST_CNDE_INT ||\n\t\taluInstruction->opcode == ALU_OP3_INST_CNDGT_INT ||\n\t\taluInstruction->opcode == ALU_OP3_INST_CMOVGE_INT)\n\t{\n\t\tif (_isSameGPROperand(aluInstruction, 1, 2) && !_operandHasModifiers(aluInstruction, 1))\n\t\t{\n\t\t\t// the condition is irrelevant as both operands are the same\n\t\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\t\tsrc->add(\" = \");\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, outputType);\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t\treturn;\n\t\t}\n\t}\n\n\n\t/* generic handlers */\n\tif( aluInstruction->opcode == ALU_OP3_INST_MULADD ||\n\t\taluInstruction->opcode == ALU_OP3_INST_MULADD_D2 ||\n\t\taluInstruction->opcode == ALU_OP3_INST_MULADD_M2 ||\n\t\taluInstruction->opcode == ALU_OP3_INST_MULADD_M4 ||\n\t\taluInstruction->opcode == ALU_OP3_INST_MULADD_IEEE )\n\t{\n\t\t// todo: The difference between MULADD and MULADD IEEE is that the former has 0*anything=0 rule similar to MUL/MUL_IEEE?\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tif (aluInstruction->opcode != ALU_OP3_INST_MULADD) // avoid unnecessary parenthesis to improve code readability slightly\n\t\t\tsrc->add(\"(\");\n\n\t\tbool useDefaultMul = false;\n\t\tif (GPU7_ALU_SRC_IS_LITERAL(aluInstruction->sourceOperand[0].sel) || GPU7_ALU_SRC_IS_LITERAL(aluInstruction->sourceOperand[1].sel) ||\n\t\t\tGPU7_ALU_SRC_IS_ANY_CONST(aluInstruction->sourceOperand[0].sel) || GPU7_ALU_SRC_IS_ANY_CONST(aluInstruction->sourceOperand[1].sel))\n\t\t{\n\t\t\tuseDefaultMul = true;\n\t\t}\n\t\tif (aluInstruction->opcode == ALU_OP3_INST_MULADD_IEEE)\n\t\t\tuseDefaultMul = true;\n\n\t\tif (shaderContext->options->strictMul && useDefaultMul == false)\n\t\t{\n\t\t\tsrc->add(\"mul_nonIEEE(\");\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\",\");\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\")\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t\tsrc->add(\" * \");\n\t\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\t}\n\n\t\tsrc->add(\" + \");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 2, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tif(aluInstruction->opcode != ALU_OP3_INST_MULADD)\n\t\t\tsrc->add(\")\");\n\t\tif( aluInstruction->opcode == ALU_OP3_INST_MULADD_D2 )\n\t\t\tsrc->add(\"/2.0\");\n\t\telse if( aluInstruction->opcode == ALU_OP3_INST_MULADD_M2 )\n\t\t\tsrc->add(\"*2.0\");\n\t\telse if( aluInstruction->opcode == ALU_OP3_INST_MULADD_M4 )\n\t\t\tsrc->add(\"*4.0\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if(aluInstruction->opcode == ALU_OP3_INST_CNDE_INT || aluInstruction->opcode == ALU_OP3_INST_CNDGT_INT || aluInstruction->opcode == ALU_OP3_INST_CMOVGE_INT)\n\t{\n\t\tbool requiresFloatResult = (aluInstruction->sourceOperand[1].neg != 0) || (aluInstruction->sourceOperand[2].neg != 0);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, requiresFloatResult?LATTE_DECOMPILER_DTYPE_FLOAT:LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"((\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tif (aluInstruction->opcode == ALU_OP3_INST_CNDE_INT)\n\t\t\tsrc->add(\" == \");\n\t\telse if (aluInstruction->opcode == ALU_OP3_INST_CNDGT_INT)\n\t\t\tsrc->add(\" > \");\n\t\telse if (aluInstruction->opcode == ALU_OP3_INST_CMOVGE_INT)\n\t\t\tsrc->add(\" >= \");\n\t\tsrc->add(\"0)?(\");\n\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, requiresFloatResult?LATTE_DECOMPILER_DTYPE_FLOAT:LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\"):(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 2, requiresFloatResult?LATTE_DECOMPILER_DTYPE_FLOAT:LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\"))\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, requiresFloatResult?LATTE_DECOMPILER_DTYPE_FLOAT:LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluInstruction->opcode == ALU_OP3_INST_CMOVGE ||\n\t\taluInstruction->opcode == ALU_OP3_INST_CMOVE ||\n\t\taluInstruction->opcode == ALU_OP3_INST_CMOVGT )\n\t{\n\t\t_emitInstructionOutputVariableName(shaderContext, aluInstruction);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"((\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tif (aluInstruction->opcode == ALU_OP3_INST_CMOVE)\n\t\t\tsrc->add(\" == \");\n\t\telse if (aluInstruction->opcode == ALU_OP3_INST_CMOVGE)\n\t\t\tsrc->add(\" >= \");\n\t\telse if (aluInstruction->opcode == ALU_OP3_INST_CMOVGT)\n\t\t\tsrc->add(\" > \");\n\t\tsrc->add(\"0.0)?(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 1, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\"):(\");\n\t\t_emitOperandInputCode(shaderContext, aluInstruction, 2, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\"))\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse\n\t{\n\t\tsrc->add(\"Unsupported instruction;\" _CRLF);\n\t\tdebug_printf(\"Unsupported ALU op3 instruction 0x%x\\n\", aluInstruction->opcode);\n\t\tshaderContext->shader->hasError = true;\n\t}\n}\n\nstatic void _emitALUReductionInstructionCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction* aluRedcInstruction[4])\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif( aluRedcInstruction[0]->isOP3 == false && (aluRedcInstruction[0]->opcode == ALU_OP2_INST_DOT4 || aluRedcInstruction[0]->opcode == ALU_OP2_INST_DOT4_IEEE) )\n\t{\n\t\t// todo: Figure out and implement the difference between normal DOT4 and DOT4_IEEE\n\t\tsint32 outputType = _getALUInstructionOutputDataType(shaderContext, aluRedcInstruction[0]);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[0]);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\n\t\t// dot(float4(op0),float4(op1))\n\t\tsrc->add(\"dot(float4(\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[0], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[1], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[2], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[3], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\"),float4(\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[0], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[1], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[2], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[3], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\"))\");\n\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse if( aluRedcInstruction[0]->isOP3 == false && (aluRedcInstruction[0]->opcode == ALU_OP2_INST_CUBE) )\n\t{\n\t\t/*\n\t\t * How the CUBE instruction works (guessed mostly, based on DirectX/OpenGL spec):\n\t\t   Input: float4, 3d direction vector (can be unnormalized) + w component (which can be ignored, since it only scales the vector but does not affect the direction)\n\n\t\t   First we figure out the major axis (closest axis-aligned vector). There are six possible vectors:\n\t\t   +rx\t0\n\t\t   -rx\t1\n\t\t   +ry\t2\n\t\t   -ry\t3\n\t\t   +rz\t4\n\t\t   -rz\t5\n\t\t   The major axis vector is calculated by looking at the largest (absolute) 3d vector component and then setting the other components to 0.0\n\t\t   The value that remains in the axis vector is referred to as 'MajorAxis' by the AMD documentation.\n\t\t   The S,T coordinates are taken from the other two components.\n\t\t   Example:\t-0.5,0.2,0.4 -> -rx -> -0.5,0.0,0.0 MajorAxis: -0.5, S: 0.2 T: 0.4\n\n\t\t   The CUBE reduction instruction requires a specific mapping for the input vector:\n\t\t   src0 = Rn.zzxy\n\t\t   src1 = Rn.yxzz\n\t\t   It's probably related to the way the instruction works internally?\n\t\t   If we look at the individual components per ALU unit:\n\t\t   z y\t-> Compare y/z\n\t\t   z x  -> Compare x/z\n\t\t   x z  -> Compare x/z\n\t\t   y z  -> Compare y/z\n\t\t*/\n\n\t\tsint32 outputType;\n\n\t\tsrc->add(\"redcCUBE(\");\n\t\tsrc->add(\"float4(\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[0], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[1], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[2], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[3], 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\"),\");\n\t\tsrc->add(\"float4(\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[0], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[1], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[2], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluRedcInstruction[3], 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\"),\");\n\t\tsrc->add(\"cubeMapSTM,cubeMapFaceId);\" _CRLF);\n\n\t\t// dst.X (S)\n\t\toutputType = _getALUInstructionOutputDataType(shaderContext, aluRedcInstruction[0]);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[0]);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"cubeMapSTM.x\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t\t// dst.Y (T)\n\t\toutputType = _getALUInstructionOutputDataType(shaderContext, aluRedcInstruction[1]);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[1]);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"cubeMapSTM.y\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t\t// dst.Z (MajorAxis)\n\t\toutputType = _getALUInstructionOutputDataType(shaderContext, aluRedcInstruction[2]);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[2]);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\"cubeMapSTM.z\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t\t// dst.W (FaceId)\n\t\toutputType = _getALUInstructionOutputDataType(shaderContext, aluRedcInstruction[3]);\n\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[3]);\n\t\tsrc->add(\" = \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\"cubeMapFaceId\");\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, outputType);\n\t\tsrc->add(\";\" _CRLF);\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\nstatic void _emitALUClauseRegisterBackupCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, sint32 startIndex)\n{\n\tsint32 instructionGroupIndex = cfInstruction->instructionsALU[startIndex].instructionGroupIndex;\n\tsize_t groupSize = 1;\n\twhile ((startIndex + groupSize) < cfInstruction->instructionsALU.size())\n\t{\n\t\tif (instructionGroupIndex != cfInstruction->instructionsALU[startIndex + groupSize].instructionGroupIndex)\n\t\t\tbreak;\n\t\tgroupSize++;\n\t}\n\tshaderContext->aluPVPSState->CreateGPRTemporaries(shaderContext, { cfInstruction->instructionsALU.data() + startIndex, groupSize });\n}\n\n/*\nbool _isPVUsedInNextGroup(LatteDecompilerCFInstruction* cfInstruction, sint32 startIndex, sint32 pvUnit)\n{\n\tsint32 currentGroupIndex = cfInstruction->instructionsALU[startIndex].instructionGroupIndex;\n\tfor (sint32 i = startIndex + 1; i < (sint32)cfInstruction->instructionsALU.size(); i++)\n\t{\n\t\tLatteDecompilerALUInstruction& aluInstructionItr = cfInstruction->instructionsALU[i];\n\t\tif(aluInstructionItr.instructionGroupIndex == currentGroupIndex )\n\t\t\tcontinue;\n\t\tif ((sint32)aluInstructionItr.instructionGroupIndex > currentGroupIndex + 1)\n\t\t\treturn false;\n\t\t// check OP code type\n\t\tif (aluInstructionItr.isOP3)\n\t\t{\n\t\t\t// op0\n\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstructionItr.sourceOperand[0].sel))\n\t\t\t{\n\t\t\t\tuint32 chan = aluInstructionItr.sourceOperand[0].chan;\n\t\t\t\tif (pvUnit == chan)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// op1\n\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstructionItr.sourceOperand[1].sel))\n\t\t\t{\n\t\t\t\tuint32 chan = aluInstructionItr.sourceOperand[1].chan;\n\t\t\t\tif (pvUnit == chan)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// op2\n\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstructionItr.sourceOperand[2].sel))\n\t\t\t{\n\t\t\t\tuint32 chan = aluInstructionItr.sourceOperand[2].chan;\n\t\t\t\tif (pvUnit == chan)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// op0\n\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstructionItr.sourceOperand[0].sel))\n\t\t\t{\n\t\t\t\tuint32 chan = aluInstructionItr.sourceOperand[0].chan;\n\t\t\t\tif (pvUnit == chan)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// op1\n\t\t\tif (GPU7_ALU_SRC_IS_PV(aluInstructionItr.sourceOperand[1].sel))\n\t\t\t{\n\t\t\t\tuint32 chan = aluInstructionItr.sourceOperand[1].chan;\n\t\t\t\tif (pvUnit == chan)\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// todo: Not all operations use both operands\n\t\t}\n\t}\n\treturn false;\n}\n*/\n\nstatic void _emitFloat3(LatteDecompilerShaderContext* shaderContext, uint32 dataType, LatteDecompilerALUInstruction* aluInst0, sint32 opIdx0, LatteDecompilerALUInstruction* aluInst1, sint32 opIdx1, LatteDecompilerALUInstruction* aluInst2, sint32 opIdx2)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t{\n\t\tsrc->add(\"float3(\");\n\t\t_emitOperandInputCode(shaderContext, aluInst0, opIdx0, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluInst1, opIdx1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluInst2, opIdx2, LATTE_DECOMPILER_DTYPE_FLOAT);\n\t\tsrc->add(\")\");\n\t}\n\telse if (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t{\n\t\tsrc->add(\"int3(\");\n\t\t_emitOperandInputCode(shaderContext, aluInst0, opIdx0, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluInst1, opIdx1, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\",\");\n\t\t_emitOperandInputCode(shaderContext, aluInst2, opIdx2, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\t\tsrc->add(\")\");\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\nstatic void _emitGPRVectorAssignment(LatteDecompilerShaderContext* shaderContext, LatteDecompilerALUInstruction** aluInstructions, sint32 count)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\t// output var name (GPR)\n\tsrc->add(_getRegisterVarName(shaderContext, aluInstructions[0]->destGpr, -1));\n\tsrc->add(\".\");\n\tfor (sint32 f = 0; f < count; f++)\n\t{\n\t\tsrc->add(_getElementStrByIndex(aluInstructions[f]->destElem));\n\t}\n\tsrc->add(\" = \");\n}\n\nstatic void _emitALUClauseCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tALUClauseTemporariesState pvpsState;\n\tshaderContext->aluPVPSState = &pvpsState;\n\tStringBuf* src = shaderContext->shaderSource;\n\tLatteDecompilerALUInstruction* aluRedcInstruction[4];\n\tsize_t groupStartIndex = 0;\n\tfor(size_t i=0; i<cfInstruction->instructionsALU.size(); i++)\n\t{\n\t\tLatteDecompilerALUInstruction& aluInstruction = cfInstruction->instructionsALU[i];\n\t\tif( aluInstruction.indexInGroup == 0 )\n\t\t{\n\t\t\tsrc->addFmt(\"// {}\" _CRLF, aluInstruction.instructionGroupIndex);\n\t\t\t// apply PV/PS updates for previous group\n\t\t\tif (i > 0)\n\t\t\t{\n\t\t\t\tpvpsState.TrackGroupOutputPVPS(shaderContext, cfInstruction->instructionsALU.data() + groupStartIndex, i - groupStartIndex);\n\t\t\t}\n\t\t\tgroupStartIndex = i;\n\t\t\t// backup registers which are read after being written\n\t\t\t_emitALUClauseRegisterBackupCode(shaderContext, cfInstruction, i);\n\t\t}\n\t\t// detect reduction instructions and use a special handler\n\t\tbool isReductionOperation = _isReductionInstruction(&aluInstruction);\n\t\tif( isReductionOperation )\n\t\t{\n\t\t\tcemu_assert_debug((i + 4) <= cfInstruction->instructionsALU.size());\n\t\t\taluRedcInstruction[0] = &aluInstruction;\n\t\t\taluRedcInstruction[1] = &cfInstruction->instructionsALU[i + 1];\n\t\t\taluRedcInstruction[2] = &cfInstruction->instructionsALU[i + 2];\n\t\t\taluRedcInstruction[3] = &cfInstruction->instructionsALU[i + 3];\n\t\t\tif( aluRedcInstruction[0]->isOP3 != aluRedcInstruction[1]->isOP3 || aluRedcInstruction[1]->isOP3 != aluRedcInstruction[2]->isOP3 || aluRedcInstruction[2]->isOP3 != aluRedcInstruction[3]->isOP3 )\n\t\t\t\tdebugBreakpoint();\n\t\t\tif( aluRedcInstruction[0]->opcode != aluRedcInstruction[1]->opcode || aluRedcInstruction[1]->opcode != aluRedcInstruction[2]->opcode || aluRedcInstruction[2]->opcode != aluRedcInstruction[3]->opcode )\n\t\t\t\tdebugBreakpoint();\n\t\t\tif( aluRedcInstruction[0]->omod != aluRedcInstruction[1]->omod || aluRedcInstruction[1]->omod != aluRedcInstruction[2]->omod || aluRedcInstruction[2]->omod != aluRedcInstruction[3]->omod )\n\t\t\t\tdebugBreakpoint();\n\t\t\tif( aluRedcInstruction[0]->destClamp != aluRedcInstruction[1]->destClamp || aluRedcInstruction[1]->destClamp != aluRedcInstruction[2]->destClamp || aluRedcInstruction[2]->destClamp != aluRedcInstruction[3]->destClamp )\n\t\t\t\tdebugBreakpoint();\n\t\t\t_emitALUReductionInstructionCode(shaderContext, aluRedcInstruction);\n\t\t\ti += 3; // skip the instructions that are part of the reduction operation\n\t\t}\n\t\telse /* not a reduction operation */\n\t\t{\n\t\t\tif( aluInstruction.isOP3 )\n\t\t\t{\n\t\t\t\t// op3\n\t\t\t\t_emitALUOP3InstructionCode(shaderContext, cfInstruction, &aluInstruction);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// op2\n\t\t\t\tif( aluInstruction.opcode == ALU_OP2_INST_NOP )\n\t\t\t\t\tcontinue; // skip NOP instruction\n\t\t\t\t_emitALUOP2InstructionCode(shaderContext, cfInstruction, &aluInstruction);\n\t\t\t}\n\t\t}\n\t\t// handle omod\n\t\tsint32 outputDataType = _getALUInstructionOutputDataType(shaderContext, &aluInstruction);\n\t\tif( aluInstruction.omod != ALU_OMOD_NONE )\n\t\t{\n\t\t\tif( outputDataType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\t\t{\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tif( aluInstruction.omod == ALU_OMOD_MUL2 )\n\t\t\t\t\tsrc->add(\" *= 2.0;\" _CRLF);\n\t\t\t\telse if( aluInstruction.omod == ALU_OMOD_MUL4 )\n\t\t\t\t\tsrc->add(\" *= 4.0;\" _CRLF);\n\t\t\t\telse if( aluInstruction.omod == ALU_OMOD_DIV2 )\n\t\t\t\t\tsrc->add(\" /= 2.0;\" _CRLF);\n\t\t\t}\n\t\t\telse if( outputDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t{\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\" = \");\n\t\t\t\tsrc->add(\"as_type<int>(as_type<float>(\"); // TODO: correct?\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\")\");\n\t\t\t\tif( aluInstruction.omod == 1 )\n\t\t\t\t\tsrc->add(\" * 2.0\");\n\t\t\t\telse if( aluInstruction.omod == 2 )\n\t\t\t\t\tsrc->add(\" * 4.0\");\n\t\t\t\telse if( aluInstruction.omod == 3 )\n\t\t\t\t\tsrc->add(\" / 2.0\");\n\t\t\t\tsrc->add(\");\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t\t// handle clamp\n\t\tif( aluInstruction.destClamp != 0 )\n\t\t{\n\t\t\tif( outputDataType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\t\t{\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\" = clamp(\");\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\", 0.0, 1.0);\" _CRLF);\n\t\t\t}\n\t\t\telse if( outputDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\t\t{\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\" = clampFI32(\");\n\t\t\t\t_emitInstructionOutputVariableName(shaderContext, &aluInstruction);\n\t\t\t\tsrc->add(\");\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t\t// handle result broadcasting for reduction instructions\n\t\tif( isReductionOperation )\n\t\t{\n\t\t\t// reduction operations set all four PV components (todo: Needs further research. According to AMD docs, dot4 only sets PV.x? update: Unlike DOT4, CUBE sets all PV elements accordingly to their GPR output?)\n\t\t\tif( aluRedcInstruction[0]->opcode == ALU_OP2_INST_CUBE )\n\t\t\t{\n\t\t\t\t// CUBE\n\t\t\t\tfor (sint32 f = 0; f < 4; f++)\n\t\t\t\t{\n\t\t\t\t\tif (aluRedcInstruction[f]->writeMask != 0)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t_emitInstructionPVPSOutputVariableName(shaderContext, aluRedcInstruction[f]);\n\t\t\t\t\tsrc->add(\" = \");\n\t\t\t\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[0]);\n\t\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// DOT4, DOT4_IEEE, etc.\n\t\t\t\t// reduction operation result is only set for output in redc[0], we also need to update redc[1] to redc[3]\n\t\t\t\tfor(sint32 f=0; f<4; f++)\n\t\t\t\t{\n\t\t\t\t\tif( aluRedcInstruction[f]->writeMask == 0 )\n\t\t\t\t\t\t_emitInstructionPVPSOutputVariableName(shaderContext, aluRedcInstruction[f]);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (f == 0)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[f]);\n\t\t\t\t\t}\n\t\t\t\t\tsrc->add(\" = \");\n\t\t\t\t\t_emitInstructionOutputVariableName(shaderContext, aluRedcInstruction[0]);\n\t\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tshaderContext->aluPVPSState = nullptr;\n}\n\n/*\n * Emits code to access one component (xyzw) of the texture coordinate input vector\n */\nstatic void _emitTEXSampleCoordInputComponent(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction, sint32 componentIndex, sint32 interpretSrcAsType)\n{\n\tcemu_assert(componentIndex >= 0 && componentIndex < 4);\n\tcemu_assert_debug(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_SIGNED_INT || interpretSrcAsType == LATTE_DECOMPILER_DTYPE_FLOAT);\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 elementSel = texInstruction->textureFetch.srcSel[componentIndex];\n\tif (elementSel < 4)\n\t{\n\t\t_emitRegisterChannelAccessCode(shaderContext, texInstruction->srcGpr, elementSel, interpretSrcAsType);\n\t\treturn;\n\t}\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tif(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t{\n\t\tif( elementSel == 4 )\n\t\t\tsrc->add(\"as_type<int>(0.0)\");\n\t\telse if( elementSel == 5 )\n\t\t\tsrc->add(\"as_type<int>(1.0)\");\n\t}\n\telse if(interpretSrcAsType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t{\n\t\tif( elementSel == 4 )\n\t\t\tsrc->add(\"0.0\");\n\t\telse if( elementSel == 5 )\n\t\t\tsrc->add(\"1.0\");\n\t}\n}\n\nstatic const char* _texGprAccessElemTable[8] = {\"x\",\"y\",\"z\",\"w\",\"_\",\"_\",\"_\",\"_\"};\n\nstatic char* _getTexGPRAccess(LatteDecompilerShaderContext* shaderContext, sint32 gprIndex, uint32 dataType, sint8 selX, sint8 selY, sint8 selZ, sint8 selW, char* tempBuffer)\n{\n\t// as_type<float>(R{}i.w)\n\t*tempBuffer = '\\0';\n\tuint8 elemCount = (selX >= 0 ? 1 : 0) + (selY >= 0 ? 1 : 0) + (selZ >= 0 ? 1 : 0) + (selW >= 0 ? 1 : 0);\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t{\n\t\tif (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t; // no conversion\n\t\telse if (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t{\n\t\t    if (elemCount == 1)\n\t\t\t\tstrcat(tempBuffer, \"as_type<float>(\");\n\t\t\telse\n\t\t\t    strcat(tempBuffer, (\"as_type<float\" + std::to_string(elemCount) + \">(\").c_str());\n\t\t}\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t\tstrcat(tempBuffer, _getRegisterVarName(shaderContext, gprIndex));\n\t\t// _texGprAccessElemTable\n\t\tstrcat(tempBuffer, \".\");\n\t\tif (selX >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selX]);\n\t\tif (selY >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selY]);\n\t\tif (selZ >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selZ]);\n\t\tif (selW >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selW]);\n\t\tif (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t; // no conversion\n\t\telse if (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\tstrcat(tempBuffer, \")\");\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t{\n\t\tif (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\tcemu_assert_unimplemented();\n\t\telse if (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t; // no conversion\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t\tstrcat(tempBuffer, _getRegisterVarName(shaderContext, gprIndex));\n\t\t// _texGprAccessElemTable\n\t\tstrcat(tempBuffer, \".\");\n\t\tif (selX >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selX]);\n\t\tif (selY >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selY]);\n\t\tif (selZ >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selZ]);\n\t\tif (selW >= 0)\n\t\t\tstrcat(tempBuffer, _texGprAccessElemTable[selW]);\n\t\tif (dataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\tcemu_assert_unimplemented();\n\t\telse if (dataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t; // no conversion\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n\treturn tempBuffer;\n}\n\nstatic void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif (texInstruction->textureFetch.textureIndex < 0 || texInstruction->textureFetch.textureIndex >= LATTE_NUM_MAX_TEX_UNITS)\n\t{\n\t\t// skip out of bounds texture unit access\n\t\treturn;\n\t}\n\n\tauto texDim = shaderContext->shader->textureUnitDim[texInstruction->textureFetch.textureIndex];\n\n\tchar tempBuffer0[32];\n\tchar tempBuffer1[32];\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\tsrc->add(\".\");\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tsint32 numWrittenElements = 0;\n\tfor(sint32 f = 0; f < 4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\t// texture sampler opcode\n\tuint32 texOpcode = texInstruction->opcode;\n\t// TODO: is this needed?\n\tif (shaderContext->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n\t\t// vertex shader forces LOD to zero, but certain sampler types don't support textureLod(...) API\n\t\tif (texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ)\n\t\t\ttexOpcode = GPU7_TEX_INST_SAMPLE_C;\n\t}\n\t// check if offset is used\n\tbool hasOffset = false;\n\tif( texInstruction->textureFetch.offsetX != 0 || texInstruction->textureFetch.offsetY != 0 || texInstruction->textureFetch.offsetZ != 0 )\n\t\thasOffset = true;\n\t// emit sample code\n\tif (shaderContext->shader->textureIsIntegerFormat[texInstruction->textureFetch.textureIndex])\n\t{\n\t\t// integer samplers\n\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT) // uint to int\n\t\t{\n\t\t\tif (numWrittenElements == 1)\n\t\t\t\tsrc->add(\" = int(\");\n\t\t\telse\n\t\t\t\tshaderContext->shaderSource->addFmt(\" = int{}(\", numWrittenElements);\n\t\t}\n\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t{\n\t\t\tif (numWrittenElements == 1)\n\t\t\t    src->add(\" = as_type<float>(\");\n\t\t\telse\n\t\t\t\tshaderContext->shaderSource->addFmt(\" = as_type<float{}>(\", numWrittenElements);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// float samplers\n\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t{\n\t\t\tif (numWrittenElements == 1)\n\t\t\t    src->add(\" = as_type<int>(\");\n\t\t\telse\n\t\t\t\tshaderContext->shaderSource->addFmt(\" = as_type<int{}>(\", numWrittenElements);\n\t\t}\n\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\tsrc->add(\" = (\");\n\t}\n\n\tbool isCompare = shaderContext->shader->textureUsesDepthCompare[texInstruction->textureFetch.textureIndex];\n\tbool emulateCompare = (isCompare && !IsValidDepthTextureType(texDim));\n\tbool isGather = (texOpcode == GPU7_TEX_INST_FETCH4);\n\n\tbool unnormalizationHandled = false;\n\tbool useTexelCoordinates = false;\n\tbool isRead = ((texOpcode == GPU7_TEX_INST_SAMPLE && (texInstruction->textureFetch.unnormalized[0] && texInstruction->textureFetch.unnormalized[1] && texInstruction->textureFetch.unnormalized[2] && texInstruction->textureFetch.unnormalized[3])) || texOpcode == GPU7_TEX_INST_LD);\n\n\t// handle illegal combinations\n\tif (texOpcode == GPU7_TEX_INST_FETCH4 && (texDim == Latte::E_DIM::DIM_1D || texDim == Latte::E_DIM::DIM_1D_ARRAY))\n\t{\n\t\t// fetch4 is not allowed on 1D textures\n\t\t// seen in YWW during boss fight of Level 1-4\n\t\t// todo - investigate what this returns on actual HW\n\t\tif (numWrittenElements == 1)\n\t\t\tshaderContext->shaderSource->add(\"0.0\");\n\t\telse\n\t\t\tshaderContext->shaderSource->addFmt(\"float{}(0.0)\", numWrittenElements);\n\t\tshaderContext->shaderSource->add(\");\" _CRLF);\n\t\treturn;\n\t}\n\n\t// Do a framebuffer fetch if possible\n\tuint8 renderTargetIndex = shaderContext->shader->textureRenderTargetIndex[texInstruction->textureFetch.textureIndex];\n\tif (static_cast<MetalRenderer*>(g_renderer.get())->SupportsFramebufferFetch() && renderTargetIndex != 255)\n\t{\n\t    // TODO: support comparison samplers\n\t\t// TODO: support swizzling\n   \t    src->addFmt(\"col{}\", renderTargetIndex);\n\t}\n\telse\n\t{\n\t    // sample_compare returns a float, need to convert to float4\n\t    if (isCompare)\n\t\t\tsrc->addFmt(\"float4(\");\n\n    \tif (emulateCompare)\n    \t{\n            cemu_assert_debug(!isGather);\n\n    \t\tsrc->add(\"sampleCompareEmulate(\");\n    \t}\n\n    \tsrc->addFmt(\"tex{}\", texInstruction->textureFetch.textureIndex);\n    \tif (!emulateCompare)\n    \t{\n    \t    src->add(\".\");\n           \tif (isRead)\n           \t{\n          \t\tif (hasOffset)\n         \t\t\tcemu_assert_unimplemented();\n          \t\tsrc->add(\"read(\");\n          \t\tunnormalizationHandled = true;\n          \t\tuseTexelCoordinates = true;\n           \t}\n           \telse\n           \t{\n           \t    if (isGather)\n         \t\t\tsrc->add(\"gather\");\n          \t\telse\n                    src->add(\"sample\");\n           \t    if (isCompare)\n         \t\t\tsrc->add(\"_compare\");\n          \t\tsrc->addFmt(\"(samplr{}, \", texInstruction->textureFetch.textureIndex);\n           \t}\n    \t}\n    \telse\n    \t{\n    \t    src->addFmt(\", samplr{}, \", texInstruction->textureFetch.textureIndex);\n    \t}\n\n    \t// for textureGather() add shift (todo: depends on rounding mode set in sampler registers?)\n    \tif (texOpcode == GPU7_TEX_INST_FETCH4)\n    \t{\n    \t\tif (texDim == Latte::E_DIM::DIM_2D)\n    \t\t{\n    \t\t\t//src->addFmt2(\"(vec2(-0.1) / vec2(textureSize(tex{},0).xy)) + \", texInstruction->textureIndex);\n\n    \t\t\t// vec2(-0.00001) is minimum to break Nvidia\n    \t\t\t// vec2(0.0001) is minimum to fix shadows on Intel, also fixes it on AMD (Windows and Linux)\n\n    \t\t\t// todo - emulating coordinate rounding mode correctly is tricky\n    \t\t\t// GX2 supports two modes: Truncate or rounding according to DX9 rules\n    \t\t\t// Vulkan uses truncate mode when point sampling (min and mag is both nearest) otherwise it uses rounding\n\n    \t\t\t// adding a small fixed bias is enough to avoid vendor-specific cases where small inaccuracies cause the number to get rounded down due to truncation\n    \t\t\tsrc->addFmt(\"float2(0.0001) + \");\n    \t\t}\n    \t}\n\n    \tconst sint32 texCoordDataType = (texOpcode == GPU7_TEX_INST_LD) ? LATTE_DECOMPILER_DTYPE_SIGNED_INT : LATTE_DECOMPILER_DTYPE_FLOAT;\n    \tif(useTexelCoordinates)\n    \t{\n    \t\t// handle integer coordinates for texelFetch\n    \t\tif (texDim == Latte::E_DIM::DIM_2D || texDim == Latte::E_DIM::DIM_2D_MSAA)\n    \t\t{\n    \t\t\tsrc->add(\"uint2(\");\n    \t\t\tsrc->add(\"float2(\");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, texCoordDataType);\n    \t\t\tsrc->addFmt(\", \");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, texCoordDataType);\n\n    \t\t\tsrc->addFmt(\")*supportBuffer.tex{}Scale\", texInstruction->textureFetch.textureIndex); // close float2 and scale\n\n    \t\t\tsrc->add(\"), 0\"); // close int2 and lod param\n    \t\t\t// todo - lod\n    \t\t}\n    \t\telse if (texDim == Latte::E_DIM::DIM_1D)\n    \t\t{\n    \t\t\t// VC DS games forget to initialize textures and use texel fetch on an uninitialized texture (a dim of 0 maps to 1D)\n    \t\t\tsrc->add(\"uint(\");\n    \t\t\tsrc->add(\"float(\");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, (texOpcode == GPU7_TEX_INST_LD) ? LATTE_DECOMPILER_DTYPE_SIGNED_INT : LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\tsrc->addFmt(\")*supportBuffer.tex{}Scale.x\", texInstruction->textureFetch.textureIndex);\n    \t\t\tsrc->add(\"), 0\");\n    \t\t\t// todo - lod\n    \t\t}\n    \t\telse\n    \t\t\tcemu_assert_debug(false);\n    \t}\n    \telse /* useTexelCoordinates == false */\n    \t{\n    \t\t// float coordinates\n    \t\tif ( (texOpcode == GPU7_TEX_INST_SAMPLE_C || texOpcode == GPU7_TEX_INST_SAMPLE_C_L || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ) )\n    \t\t{\n    \t\t\t// shadow sampler\n    \t\t\tif (texDim == Latte::E_DIM::DIM_2D_ARRAY)\n    \t\t\t{\n    \t\t\t\t// 3 coords + compare value\n    \t\t\t\tsrc->add(\"float2(\");\n    \t\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\t\tsrc->add(\", \");\n    \t\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\t\tsrc->add(\"), uint(rint(\");\n    \t\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 2, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\t\tsrc->add(\"))\");\n\n    \t\t\t\tsrc->addFmt(\", {}\", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[3], -1, -1, -1, tempBuffer0));\n    \t\t\t}\n    \t\t\telse if (texDim == Latte::E_DIM::DIM_CUBEMAP)\n    \t\t\t{\n    \t\t\t\t// 2 coords + faceId\n    \t\t\t\tif (texInstruction->textureFetch.srcSel[0] >= 4 || texInstruction->textureFetch.srcSel[1] >= 4)\n    \t\t\t\t{\n    \t\t\t\t\tdebugBreakpoint();\n    \t\t\t\t}\n    \t\t\t\tsrc->addFmt(\"redcCUBEReverse({},\", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], -1, -1, tempBuffer0));\n    \t\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 2, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n    \t\t\t\tsrc->addFmt(\")\");\n    \t\t\t\tsrc->addFmt(\", uint(cubeMapArrayIndex{})\", texInstruction->textureFetch.textureIndex); // cubemap index\n    \t\t\t}\n    \t\t\telse if (texDim == Latte::E_DIM::DIM_1D)\n    \t\t\t{\n    \t\t\t\t// 1 coord + 1 unused coord (per  spec) + compare value\n    \t\t\t\tif (texInstruction->textureFetch.srcSel[0] >= 4)\n    \t\t\t\t{\n    \t\t\t\t\tdebugBreakpoint();\n    \t\t\t\t}\n    \t\t\t\tsrc->addFmt(\"{}, {}\", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], -1, -1, -1, tempBuffer0), _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[3], -1, -1, -1, tempBuffer1));\n    \t\t\t}\n    \t\t\telse\n    \t\t\t{\n    \t\t\t\t// 2 coords + compare value (as float3)\n    \t\t\t\tif (texInstruction->textureFetch.srcSel[0] >= 4 && texInstruction->textureFetch.srcSel[1] >= 4)\n    \t\t\t\t{\n    \t\t\t\t\tdebugBreakpoint();\n    \t\t\t\t}\n    \t\t\t\tsrc->addFmt(\"float2({}), {}\", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], -1, -1, tempBuffer0), _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[3], -1, -1, -1, tempBuffer1));\n    \t\t\t}\n    \t\t}\n    \t\telse if(texDim == Latte::E_DIM::DIM_2D_ARRAY)\n    \t\t{\n    \t\t\t// 3 coords\n    \t\t\tsrc->add(\"float2(\");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\tsrc->add(\", \");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\tsrc->add(\"), uint(rint(\");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 2, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\tsrc->add(\"))\");\n    \t\t}\n    \t\telse if(texDim == Latte::E_DIM::DIM_3D)\n    \t\t{\n    \t\t\t// 3 coords\n    \t\t\tsrc->add(\"float3(\");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\tsrc->add(\", \");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\tsrc->add(\", \");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 2, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\tsrc->add(\")\");\n    \t\t}\n    \t\telse if( texDim == Latte::E_DIM::DIM_CUBEMAP )\n    \t\t{\n    \t\t\t// 2 coords + faceId\n    \t\t\tcemu_assert_debug(texInstruction->textureFetch.srcSel[0] < 4);\n    \t\t\tcemu_assert_debug(texInstruction->textureFetch.srcSel[1] < 4);\n    \t\t\tsrc->addFmt(\"redcCUBEReverse({},\", _getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], -1, -1, tempBuffer0));\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 2, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n    \t\t\tsrc->add(\")\");\n    \t\t\tsrc->addFmt(\", uint(cubeMapArrayIndex{})\", texInstruction->textureFetch.textureIndex); // cubemap index\n    \t\t}\n    \t\telse if( texDim == Latte::E_DIM::DIM_1D )\n    \t\t{\n    \t\t\t// 1 coord\n    \t\t\tsrc->add(_getTexGPRAccess(shaderContext, texInstruction->srcGpr, LATTE_DECOMPILER_DTYPE_FLOAT, texInstruction->textureFetch.srcSel[0], -1, -1, -1, tempBuffer0));\n    \t\t}\n    \t\telse\n    \t\t{\n    \t\t\t// 2 coords\n    \t\t\tsrc->add(\"float2(\");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 0, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\tsrc->add(\",\");\n    \t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 1, LATTE_DECOMPILER_DTYPE_FLOAT);\n    \t\t\tsrc->add(\")\");\n    \t\t\t// avoid truncate to effectively round downwards on texel edges\n    \t\t\tif (ActiveSettings::ForceSamplerRoundToPrecision())\n    \t\t\t\tsrc->addFmt(\"+ float2(1.0)/float2(tex{}.get_width(), tex{}.get_height())/512.0\", texInstruction->textureFetch.textureIndex, texInstruction->textureFetch.textureIndex);\n    \t\t}\n    \t\t// lod or lod bias parameter\n    \t\t// 1D textures don't support lod\n    \t\tif (texDim != Latte::E_DIM::DIM_1D && texDim != Latte::E_DIM::DIM_1D_ARRAY)\n    \t\t{\n          \t\tif (texOpcode == GPU7_TEX_INST_SAMPLE_L || texOpcode == GPU7_TEX_INST_SAMPLE_LB || texOpcode == GPU7_TEX_INST_SAMPLE_C_L)\n          \t\t{\n          \t\t    src->add(\", \");\n         \t\t\tif (texOpcode == GPU7_TEX_INST_SAMPLE_LB)\n         \t\t\t{\n                        src->addFmt(\"bias({})\", _FormatFloatAsConstant((float)texInstruction->textureFetch.lodBias / 16.0f));\n         \t\t\t}\n         \t\t\telse\n         \t\t\t{\n         \t\t\t    // TODO: is this correct?\n                        src->add(\"level(\");\n        \t\t\t\t_emitTEXSampleCoordInputComponent(shaderContext, texInstruction, 3, LATTE_DECOMPILER_DTYPE_FLOAT);\n        \t\t\t\tsrc->add(\")\");\n         \t\t\t}\n          \t\t}\n          \t\telse if (texOpcode == GPU7_TEX_INST_SAMPLE_LZ || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ)\n          \t\t{\n         \t\t\tsrc->add(\", level(0.0)\");\n          \t\t}\n    \t\t}\n    \t}\n    \t// gradient parameters\n    \tif (texOpcode == GPU7_TEX_INST_SAMPLE_G)\n    \t{\n    \t\tif (texDim == Latte::E_DIM::DIM_2D ||\n    \t\t\ttexDim == Latte::E_DIM::DIM_1D)\n    \t\t{\n    \t\t\tsrc->add(\", gradient2d(gradH.xy, gradV.xy)\");\n    \t\t}\n    \t\telse\n    \t\t{\n    \t\t\tcemu_assert_unimplemented();\n    \t\t}\n    \t}\n\n    \t// offset\n    \tif( texOpcode == GPU7_TEX_INST_SAMPLE_L || texOpcode == GPU7_TEX_INST_SAMPLE_LZ || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ || texOpcode == GPU7_TEX_INST_SAMPLE || texOpcode == GPU7_TEX_INST_SAMPLE_C )\n    \t{\n    \t\tif( hasOffset )\n    \t\t{\n    \t\t\tuint8 offsetComponentCount = 0;\n    \t\t\tif( texDim == Latte::E_DIM::DIM_1D )\n    \t\t\t\toffsetComponentCount = 1;\n    \t\t\telse if( texDim == Latte::E_DIM::DIM_2D )\n    \t\t\t\toffsetComponentCount = 2;\n    \t\t\telse if( texDim == Latte::E_DIM::DIM_3D )\n    \t\t\t\toffsetComponentCount = 3;\n    \t\t\telse if( texDim == Latte::E_DIM::DIM_2D_ARRAY )\n    \t\t\t\toffsetComponentCount = 2;\n    \t\t\telse\n    \t\t\t\tcemu_assert_unimplemented();\n\n    \t\t\tif( (texInstruction->textureFetch.offsetX&1) )\n    \t\t\t\tcemu_assert_unimplemented();\n    \t\t\tif( (texInstruction->textureFetch.offsetY&1) )\n    \t\t\t\tcemu_assert_unimplemented();\n    \t\t\tif ((texInstruction->textureFetch.offsetZ & 1))\n    \t\t\t\tcemu_assert_unimplemented();\n\n    \t\t\tif( offsetComponentCount == 1 )\n    \t\t\t\tsrc->addFmt(\",{}\", texInstruction->textureFetch.offsetX/2);\n    \t\t\telse if( offsetComponentCount == 2 )\n    \t\t\t\tsrc->addFmt(\",int2({},{})\", texInstruction->textureFetch.offsetX/2, texInstruction->textureFetch.offsetY/2, texInstruction->textureFetch.offsetZ/2);\n    \t\t\telse if( offsetComponentCount == 3 )\n    \t\t\t\tsrc->addFmt(\",int3({},{},{})\", texInstruction->textureFetch.offsetX/2, texInstruction->textureFetch.offsetY/2, texInstruction->textureFetch.offsetZ/2);\n    \t\t}\n    \t}\n\n    \t// lod bias (TODO: wht?)\n\n        src->add(\")\");\n    }\n\n    if (isCompare)\n        src->add(\")\");\n\n   \tif (texOpcode == GPU7_TEX_INST_SAMPLE_C || texOpcode == GPU7_TEX_INST_SAMPLE_C_LZ)\n   \t{\n  \t\tsrc->add(\".\");\n\n  \t\tif (numWrittenElements > 1)\n  \t\t{\n \t\t\t// result is copied into multiple channels\n \t\t\tfor (sint32 f = 0; f < numWrittenElements; f++)\n \t\t\t{\n\t\t\t\tcemu_assert_debug(texInstruction->dstSel[f] == 0); // only x component is defined\n\t\t\t\tsrc->add(\"x\");\n \t\t\t}\n  \t\t}\n  \t\telse\n  \t\t{\n  \t\t    src->add(\"x\");\n  \t\t}\n    }\n    else\n    {\n  \t\tsrc->add(\".\");\n  \t\tfor (sint32 f = 0; f < 4; f++)\n  \t\t{\n \t\t\tif (texInstruction->dstSel[f] < 4)\n \t\t\t{\n\t\t\t\tuint8 elemIndex = texInstruction->dstSel[f];\n\t\t\t\tif (isGather)\n\t\t\t\t{\n    \t\t\t\t// 's textureGather() and GPU7's FETCH4 instruction have a different order of elements\n    \t\t\t\t// xyzw: top-left, top-right, bottom-right, bottom-left\n    \t\t\t\t// textureGather\txyzw\n    \t\t\t\t// fetch4\t\t\tyzxw\n    \t\t\t\t// translate index from fetch4 to textureGather order\n    \t\t\t\tstatic uint8 fetchToGather[4] =\n    \t\t\t\t{\n      \t\t\t\t\t\t2, // x -> z\n      \t\t\t\t\t\t0, // y -> x\n      \t\t\t\t\t\t1, // z -> y\n      \t\t\t\t\t\t3, // w -> w\n    \t\t\t\t};\n    \t\t\t\telemIndex = fetchToGather[elemIndex];\n\t\t\t\t}\n\t\t\t\tsrc->add(resultElemTable[elemIndex]);\n \t\t\t}\n \t\t\telse if (texInstruction->dstSel[f] == 7)\n \t\t\t{\n\t\t\t\t// masked and not written\n \t\t\t}\n \t\t\telse\n \t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n \t\t\t}\n  \t\t}\n    }\n\tsrc->add(\");\");\n\n\t// debug\n#ifdef CEMU_DEBUG_ASSERT\n\tif(texInstruction->opcode == GPU7_TEX_INST_LD )\n\t\tsrc->add(\" // TEX_INST_LD\");\n\telse if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE )\n\t\tsrc->add(\" // TEX_INST_SAMPLE\");\n\telse if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE_L )\n\t\tsrc->add(\" // TEX_INST_SAMPLE_L\");\n\telse if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE_LZ )\n\t\tsrc->add(\" // TEX_INST_SAMPLE_LZ\");\n\telse if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE_C )\n\t\tsrc->add(\" // TEX_INST_SAMPLE_C\");\n\telse if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE_G )\n\t\tsrc->add(\" // TEX_INST_SAMPLE_G\");\n\telse\n\t\tsrc->addFmt(\" // 0x{:02x}\", texInstruction->opcode);\n\tif (texInstruction->opcode != texOpcode)\n\t\tsrc->addFmt(\" (applied as 0x{:02x})\", texOpcode);\n\tsrc->addFmt(\" OffsetXYZ {:02x} {:02x} {:02x}\", (uint8)texInstruction->textureFetch.offsetX&0xFF, (uint8)texInstruction->textureFetch.offsetY&0xFF, (uint8)texInstruction->textureFetch.offsetZ&0xFF);\n#endif\n\tsrc->add(\"\" _CRLF);\n}\n\nstatic void _emitTEXGetTextureResInfoCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->addFmt(\"R{}\", texInstruction->dstGpr);\n\tsrc->add(\"i\");\n\tsrc->add(\".\");\n\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tsint32 numWrittenElements = 0;\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\n\t// todo - mip index parameter?\n\n\tif (static_cast<MetalRenderer*>(g_renderer.get())->SupportsFramebufferFetch() && shaderContext->shader->textureRenderTargetIndex[texInstruction->textureFetch.textureIndex] != 255)\n\t{\n\t    // TODO: use the render target size\n\t    src->addFmt(\" = int4(1920, 1080, 1, 1).\");\n\t}\n\telse\n\t{\n    \tauto texDim = shaderContext->shader->textureUnitDim[texInstruction->textureFetch.textureIndex];\n\n    \tif (texDim == Latte::E_DIM::DIM_1D)\n    \t\tsrc->addFmt(\" = int4(tex{}.get_width(), 1, 1, 1).\", texInstruction->textureFetch.textureIndex);\n    \telse if (texDim == Latte::E_DIM::DIM_1D_ARRAY)\n    \t\tsrc->addFmt(\" = int4(tex{}.get_width(), tex{}.get_array_size(), 1, 1).\", texInstruction->textureFetch.textureIndex, texInstruction->textureFetch.textureIndex);\n    \telse if (texDim == Latte::E_DIM::DIM_2D || texDim == Latte::E_DIM::DIM_2D_MSAA)\n    \t\tsrc->addFmt(\" = int4(tex{}.get_width(), tex{}.get_height(), 1, 1).\", texInstruction->textureFetch.textureIndex, texInstruction->textureFetch.textureIndex);\n    \telse if (texDim == Latte::E_DIM::DIM_2D_ARRAY)\n    \t\tsrc->addFmt(\" = int4(tex{}.get_width(), tex{}.get_height(), tex{}.get_array_size(), 1).\", texInstruction->textureFetch.textureIndex, texInstruction->textureFetch.textureIndex, texInstruction->textureFetch.textureIndex);\n    \telse\n    \t{\n    \t\tcemu_assert_debug(false);\n    \t\tsrc->addFmt(\" = int4(tex{}.get_width(), tex{}.get_height(), 1, 1).\", texInstruction->textureFetch.textureIndex, texInstruction->textureFetch.textureIndex);\n    \t}\n\t}\n\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[texInstruction->dstSel[f]]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\tsrc->add(\";\" _CRLF);\n}\n\nstatic void _emitTEXGetCompTexLodCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\tsrc->add(\".\");\n\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tsint32 numWrittenElements = 0;\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\n\tsrc->add(\" = \");\n\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, shaderContext->typeTracker.defaultDataType);\n\n\tif (static_cast<MetalRenderer*>(g_renderer.get())->SupportsFramebufferFetch() && shaderContext->shader->textureRenderTargetIndex[texInstruction->textureFetch.textureIndex] != 255)\n\t{\n\t    // We assume that textures accessed as framebuffer fetch are always sampled at pixel coordinates, therefore the lod would always be 0.0\n\t    src->add(\"float4(0.0, 0.0, 0.0, 0.0)\");\n\t}\n\telse\n\t{\n    \tif (shaderContext->shader->textureUnitDim[texInstruction->textureFetch.textureIndex] == Latte::E_DIM::DIM_CUBEMAP)\n    \t{\n    \t\t// 3 coordinates\n    \t\tif(shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n    \t\t\tsrc->addFmt(\"float4(textureCalculateLod(tex{}, samplr{}, {}.{}{}{}), 0.0, 0.0)\", texInstruction->textureFetch.textureIndex, texInstruction->textureFetch.textureIndex, _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]], resultElemTable[texInstruction->textureFetch.srcSel[1]], resultElemTable[texInstruction->textureFetch.srcSel[2]]);\n    \t\telse\n    \t\t\tsrc->addFmt(\"float4(textureCalculateLod(tex{}, samplr{}, as_type<float3>({}.{}{}{})), 0.0, 0.0)\", texInstruction->textureFetch.textureIndex, texInstruction->textureFetch.textureIndex, _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]], resultElemTable[texInstruction->textureFetch.srcSel[1]], resultElemTable[texInstruction->textureFetch.srcSel[2]]);\n    \t}\n    \telse\n    \t{\n    \t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n    \t\t\tsrc->addFmt(\"float4(textureCalculateLod(tex{}, samplr{}, {}.{}{}), 0.0, 0.0)\", texInstruction->textureFetch.textureIndex, texInstruction->textureFetch.textureIndex, _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]], resultElemTable[texInstruction->textureFetch.srcSel[1]]);\n    \t\telse\n    \t\t\tsrc->addFmt(\"float4(textureCalculateLod(tex{}, samplr{}, as_type<float2>({}.{}{})), 0.0, 0.0)\", texInstruction->textureFetch.textureIndex, texInstruction->textureFetch.textureIndex, _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]], resultElemTable[texInstruction->textureFetch.srcSel[1]]);\n    \t\tdebugBreakpoint();\n    \t}\n\t}\n\n\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, shaderContext->typeTracker.defaultDataType);\n\tsrc->add(\".\");\n\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[texInstruction->dstSel[f]]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\tsrc->add(\";\" _CRLF);\n}\n\nstatic void _emitTEXSetCubemapIndexCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->addFmt(\"cubeMapArrayIndex{}\", texInstruction->textureFetch.textureIndex);\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\tsrc->addFmt(\" = as_type<float>(R{}i.{});\" _CRLF, texInstruction->srcGpr, resultElemTable[texInstruction->textureFetch.srcSel[0]]);\n\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\tsrc->addFmt(\" = R{}f.{};\" _CRLF, texInstruction->srcGpr, resultElemTable[texInstruction->textureFetch.srcSel[0]]);\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\nstatic void _emitTEXGetGradientsHV(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsint32 componentCount = 0;\n\tfor (sint32 i = 0; i < 4; i++)\n\t{\n\t\tif (texInstruction->dstSel[i] == 7)\n\t\t\tcontinue;\n\t\tcomponentCount++;\n\t}\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\tsrc->add(\".\");\n\tconst char* resultElemTable[4] = { \"x\",\"y\",\"z\",\"w\" };\n\tsint32 numWrittenElements = 0;\n\tfor (sint32 f = 0; f < 4; f++)\n\t{\n\t\tif (texInstruction->dstSel[f] < 4)\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if (texInstruction->dstSel[f] == 7)\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\n\tconst char* funcName;\n\tif (texInstruction->opcode == GPU7_TEX_INST_GET_GRADIENTS_H)\n\t\tfuncName = \"dfdx\";\n\telse\n\t\tfuncName = \"dfdy\";\n\n\tsrc->add(\" = \");\n\n\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, shaderContext->typeTracker.defaultDataType, componentCount);\n\n\tsrc->addFmt(\"{}(\", funcName);\n\t_emitRegisterAccessCode(shaderContext, texInstruction->srcGpr, (componentCount >= 1) ? texInstruction->textureFetch.srcSel[0] : -1, (componentCount >= 2) ? texInstruction->textureFetch.srcSel[1] : -1, (componentCount >= 3) ? texInstruction->textureFetch.srcSel[2] : -1, (componentCount >= 4) ? texInstruction->textureFetch.srcSel[3] : -1, LATTE_DECOMPILER_DTYPE_FLOAT);\n\n\tsrc->add(\")\");\n\n\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_FLOAT, shaderContext->typeTracker.defaultDataType);\n\n\tsrc->add(\";\" _CRLF);\n\n}\n\nstatic void _emitTEXSetGradientsHV(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif (texInstruction->opcode == GPU7_TEX_INST_SET_GRADIENTS_H)\n\t\tsrc->add(\"gradH = \");\n\telse\n\t\tsrc->add(\"gradV = \");\n\n\t_emitRegisterAccessCode(shaderContext, texInstruction->srcGpr, texInstruction->textureFetch.srcSel[0], texInstruction->textureFetch.srcSel[1], texInstruction->textureFetch.srcSel[2], texInstruction->textureFetch.srcSel[3], LATTE_DECOMPILER_DTYPE_FLOAT);\n\n\tsrc->add(\";\" _CRLF);\n}\n\nstatic void _emitGSReadInputVFetchCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\n\tsrc->add(\".\");\n\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tsint32 numWrittenElements = 0;\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\n\tsrc->add(\" = \");\n\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, shaderContext->typeTracker.defaultDataType, numWrittenElements);\n\tsrc->add(\"(objectPayload.vertexOut[\");\n\tif (texInstruction->textureFetch.srcSel[0] >= 4)\n\t\tcemu_assert_unimplemented();\n\tif (texInstruction->textureFetch.srcSel[1] >= 4)\n\t\tcemu_assert_unimplemented();\n\tsrc->add(\"vertexIndex\");\n\tsrc->addFmt(\"].passParameterSem{}.\", texInstruction->textureFetch.offset/16);\n\n\n\tfor(sint32 f=0; f<4; f++)\n\t{\n\t\tif( texInstruction->dstSel[f] < 4 )\n\t\t{\n\t\t\tsrc->add(resultElemTable[texInstruction->dstSel[f]]);\n\t\t}\n\t\telse if( texInstruction->dstSel[f] == 7 )\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\tsrc->add(\")\");\n\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, shaderContext->typeTracker.defaultDataType);\n\tsrc->add(\";\" _CRLF);\n}\n\nstatic sint32 _writeDestMaskXYZW(LatteDecompilerShaderContext* shaderContext, sint8* dstSel)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tconst char* resultElemTable[4] = { \"x\",\"y\",\"z\",\"w\" };\n\tsint32 numWrittenElements = 0;\n\tfor (sint32 f = 0; f < 4; f++)\n\t{\n\t\tif (dstSel[f] < 4)\n\t\t{\n\t\t\tsrc->add(resultElemTable[f]);\n\t\t\tnumWrittenElements++;\n\t\t}\n\t\telse if (dstSel[f] == 7)\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\treturn numWrittenElements;\n}\n\nstatic void _emitTEXVFetchCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\t// handle special case where geometry shader reads input attributes from vertex shader via ringbuffer\n\tStringBuf* src = shaderContext->shaderSource;\n\tif( texInstruction->textureFetch.textureIndex == 0x9F && shaderContext->shaderType == LatteConst::ShaderType::Geometry )\n\t{\n\t\t_emitGSReadInputVFetchCode(shaderContext, texInstruction);\n\t\treturn;\n\t}\n\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\tsrc->add(\".\");\n\n\t_writeDestMaskXYZW(shaderContext, texInstruction->dstSel);\n\tconst char* resultElemTable[4] = {\"x\",\"y\",\"z\",\"w\"};\n\tuint32 numWrittenElements = 0;\n\tfor (sint32 f=0; f<4; f++)\n\t{\n\t\tif (texInstruction->dstSel[f] < 4)\n\t\t    numWrittenElements++;\n\t}\n\n\tsrc->add(\" = \");\n\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t{\n\t    if (numWrittenElements == 1)\n\t\t    src->add(\"as_type<int>(\");\n\t\telse\n\t\t    src->addFmt(\"as_type<int{}>(\", numWrittenElements);\n\t}\n\telse\n\t\tsrc->add(\"(\");\n\n\tsrc->addFmt(\"ubuff{}.d[\", texInstruction->textureFetch.textureIndex - 0x80);\n\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\tsrc->addFmt(\"{}.{}\", _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]]);\n\telse\n\t\tsrc->addFmt(\"as_type<int>({}.{})\", _getRegisterVarName(shaderContext, texInstruction->srcGpr), resultElemTable[texInstruction->textureFetch.srcSel[0]]);\n\tsrc->add(\"].\");\n\n\n\tfor (sint32 f=0; f<4; f++)\n\t{\n\t\tif (texInstruction->dstSel[f] < 4)\n\t\t{\n\t\t\tsrc->add(resultElemTable[texInstruction->dstSel[f]]);\n\t\t}\n\t\telse if (texInstruction->dstSel[f] == 7)\n\t\t{\n\t\t\t// masked and not written\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t}\n\tsrc->add(\");\" _CRLF);\n}\n\nstatic void _emitTEXReadMemCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerTEXInstruction* texInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->add(_getRegisterVarName(shaderContext, texInstruction->dstGpr));\n\tsrc->add(\".\");\n\tsint32 count = _writeDestMaskXYZW(shaderContext, texInstruction->dstSel);\n\n\tsrc->add(\" = \");\n\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t{\n\t    if (count == 1)\n\t\t\tsrc->add(\"as_type<int>(\");\n\t\telse\n            src->addFmt(\"as_type<int{}>(\", count);\n\t}\n\telse\n\t\tsrc->add(\"(\");\n\n\tsint32 readCount;\n\n\tif (texInstruction->memRead.format == FMT_32_FLOAT)\n\t{\n\t\treadCount = 1;\n\t\t// todo\n\t\tsrc->add(\"0.0\");\n\t}\n\telse if (texInstruction->memRead.format == FMT_32_32_FLOAT)\n\t{\n\t\treadCount = 2;\n\t\t// todo\n\t\tsrc->add(\"float2(0.0,0.0)\");\n\t}\n\telse if (texInstruction->memRead.format == FMT_32_32_32_FLOAT)\n\t{\n\t\treadCount = 3;\n\t\t// todo\n\t\tsrc->add(\"float3(0.0,0.0,0.0)\");\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tif (count < readCount)\n\t{\n\t\tif (count == 1)\n\t\t\tsrc->add(\".x\");\n\t\telse if (count == 2)\n\t\t\tsrc->add(\".xy\");\n\t\telse if (count == 3)\n\t\t\tsrc->add(\".xyz\");\n\t}\n\tsrc->add(\");\" _CRLF);\n}\n\nstatic void _emitTEXClauseCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tcemu_assert_debug(cfInstruction->instructionsALU.empty());\n\tfor(auto& texInstruction : cfInstruction->instructionsTEX)\n\t{\n\t\tif( texInstruction.opcode == GPU7_TEX_INST_SAMPLE || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_L || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_LB || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_LZ || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_C || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_C_L || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_C_LZ || texInstruction.opcode == GPU7_TEX_INST_FETCH4 || texInstruction.opcode == GPU7_TEX_INST_SAMPLE_G || texInstruction.opcode == GPU7_TEX_INST_LD )\n\t\t\t_emitTEXSampleTextureCode(shaderContext, &texInstruction);\n\t\telse if( texInstruction.opcode == GPU7_TEX_INST_GET_TEXTURE_RESINFO )\n\t\t\t_emitTEXGetTextureResInfoCode(shaderContext, &texInstruction);\n\t\telse if( texInstruction.opcode == GPU7_TEX_INST_GET_COMP_TEX_LOD )\n\t\t\t_emitTEXGetCompTexLodCode(shaderContext, &texInstruction);\n\t\telse if( texInstruction.opcode == GPU7_TEX_INST_SET_CUBEMAP_INDEX )\n\t\t\t_emitTEXSetCubemapIndexCode(shaderContext, &texInstruction);\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_GET_GRADIENTS_H ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_GET_GRADIENTS_V)\n\t\t\t_emitTEXGetGradientsHV(shaderContext, &texInstruction);\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_SET_GRADIENTS_H ||\n\t\t\ttexInstruction.opcode == GPU7_TEX_INST_SET_GRADIENTS_V)\n\t\t\t_emitTEXSetGradientsHV(shaderContext, &texInstruction);\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_VFETCH)\n\t\t\t_emitTEXVFetchCode(shaderContext, &texInstruction);\n\t\telse if (texInstruction.opcode == GPU7_TEX_INST_MEM)\n\t\t\t_emitTEXReadMemCode(shaderContext, &texInstruction);\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n}\n\n// generate the code for reading the source input GPR (or constants) for exports\nstatic void _emitExportGPRReadCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, sint32 requiredType, uint32 burstIndex)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tuint32 numOutputs = 4;\n\tif( cfInstruction->type == GPU7_CF_INST_MEM_RING_WRITE )\n\t{\n\t\tnumOutputs = (cfInstruction->memWriteCompMask&1)?1:0;\n\t\tnumOutputs += (cfInstruction->memWriteCompMask&2)?1:0;\n\t\tnumOutputs += (cfInstruction->memWriteCompMask&4)?1:0;\n\t\tnumOutputs += (cfInstruction->memWriteCompMask&8)?1:0;\n\t}\n\tif (requiredType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t{\n\t\tif(numOutputs == 1)\n\t\t\tsrc->add(\"float(\");\n\t\telse\n\t\t\tsrc->addFmt(\"float{}(\", numOutputs);\n\t}\n\telse if (requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t{\n\t\tif (numOutputs == 1)\n\t\t\tsrc->add(\"int(\");\n\t\telse\n\t\t\tsrc->addFmt(\"int{}(\", numOutputs);\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n\tsint32 actualOutputs = 0;\n\tfor(sint32 i=0; i<4; i++)\n\t{\n\t\t// todo: Use type of register element based on information from type tracker (currently we assume it's always a signed integer)\n\t\tuint32 exportSel = 0;\n\t\tif( cfInstruction->type == GPU7_CF_INST_MEM_RING_WRITE )\n\t\t{\n\t\t\texportSel = i;\n\t\t\tif( (cfInstruction->memWriteCompMask&(1<<i)) == 0 )\n\t\t\t\tcontinue; // dont output\n\t\t}\n\t\telse\n\t\t{\n\t\t\texportSel = cfInstruction->exportComponentSel[i];\n\t\t}\n\t\tif( actualOutputs > 0 )\n\t\t\tsrc->add(\", \");\n\t\tactualOutputs++;\n\t\tif( exportSel < 4 )\n\t\t{\n\t\t\t_emitRegisterAccessCode(shaderContext, cfInstruction->exportSourceGPR+burstIndex, exportSel, -1, -1, -1, requiredType);\n\t\t}\n\t\telse if (exportSel == 4)\n\t\t{\n\t\t\t// constant zero\n\t\t\tsrc->add(\"0\");\n\t\t}\n\t\telse if (exportSel == 5)\n\t\t{\n\t\t\t// constant one\n\t\t\tsrc->add(\"1.0\");\n\t\t}\n\t\telse if( exportSel == 7 )\n\t\t{\n\t\t\t// element masked (which means 0 is exported?)\n\t\t\tsrc->add(\"0\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tsrc->add(\"0\");\n\t\t}\n\t}\n\tif( requiredType == LATTE_DECOMPILER_DTYPE_FLOAT )\n\t\tsrc->add(\")\");\n\telse if( requiredType == LATTE_DECOMPILER_DTYPE_SIGNED_INT )\n\t\tsrc->add(\")\");\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\nstatic void _emitExportCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tsrc->add(\"// export\" _CRLF);\n\tif(shaderContext->shaderType == LatteConst::ShaderType::Vertex )\n\t{\n\t    if (!shaderContext->contextRegistersNew->IsRasterizationEnabled())\n\t\t{\n\t\t\tsrc->add(\"// Rasterization disabled\" _CRLF);\n\t\t\treturn;\n\t\t}\n\n\t\tif( cfInstruction->exportBurstCount != 0 )\n\t\t\tdebugBreakpoint();\n\t\tif (cfInstruction->exportType == 1 && cfInstruction->exportArrayBase == GPU7_DECOMPILER_CF_EXPORT_BASE_POSITION)\n\t\t{\n\t\t\t// export position\n\t\t\t// GX2 special state 0 disables rasterizer viewport offset and scaling (probably, exact mechanism is not known). Handle this here\n\t\t\tbool hasAnyViewportScaleDisabled =\n\t\t\t\t!shaderContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_X_SCALE_ENA() ||\n\t\t\t\t!shaderContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Y_SCALE_ENA() ||\n\t\t\t\t!shaderContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Z_SCALE_ENA();\n\n\t\t\tif (hasAnyViewportScaleDisabled)\n\t\t\t{\n\t\t\t\tsrc->add(\"float4 finalPos = \");\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, 0);\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t\tsrc->add(\"finalPos.xy = finalPos.xy * supportBuffer.windowSpaceToClipSpaceTransform - float2(1.0,1.0);\" _CRLF);\n\t\t\t\tsrc->add(\"SET_POSITION(finalPos);\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->add(\"SET_POSITION(\");\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, 0);\n\t\t\t\tsrc->add(\");\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (cfInstruction->exportType == 1 && cfInstruction->exportArrayBase == GPU7_DECOMPILER_CF_EXPORT_POINT_SIZE )\n\t\t{\n\t\t\t// export gl_PointSize\n\t\t\tif (shaderContext->analyzer.outputPointSize)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(shaderContext->analyzer.writesPointSize);\n\t\t\t\tsrc->add(\"out.pointSize = (\");\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, 0);\n\t\t\t\tsrc->add(\").x\");\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if( cfInstruction->exportType == 2 && cfInstruction->exportArrayBase < 32 )\n\t\t{\n\t\t\t// export parameter\n\t\t\tsint32 paramIndex = cfInstruction->exportArrayBase;\n\t\t\tuint32 vsSemanticId = _getVertexShaderOutParamSemanticId(shaderContext->contextRegisters, paramIndex);\n\t\t\tif (vsSemanticId != 0xFF)\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"out.passParameterSem{} = \", vsSemanticId);\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, 0);\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->add(\"// skipped export to semanticId 255\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n\telse if(shaderContext->shaderType == LatteConst::ShaderType::Pixel )\n\t{\n\t\tif( cfInstruction->exportType == 0 && cfInstruction->exportArrayBase < 8 )\n\t\t{\n\t\t\tfor(uint32 i=0; i<(cfInstruction->exportBurstCount+1); i++)\n\t\t\t{\n\t\t\t\tsint32 pixelColorOutputIndex = LatteDecompiler_getColorOutputIndexFromExportIndex(shaderContext, cfInstruction->exportArrayBase+i);\n\t\t\t\t// if color output is for target 0, then also handle alpha test\n\t\t\t\tbool alphaTestEnable = shaderContext->contextRegistersNew->SX_ALPHA_TEST_CONTROL.get_ALPHA_TEST_ENABLE();\n\t\t\t\tauto alphaTestFunc = shaderContext->contextRegistersNew->SX_ALPHA_TEST_CONTROL.get_ALPHA_FUNC();\n\t\t\t\tif( pixelColorOutputIndex == 0 && alphaTestEnable && alphaTestFunc == Latte::E_COMPAREFUNC::NEVER )\n\t\t\t\t{\n\t\t\t\t\t// never pass alpha test\n\t\t\t\t\tsrc->add(\"discard_fragment();\" _CRLF);\n\t\t\t\t}\n\t\t\t\telse if( pixelColorOutputIndex == 0 && alphaTestEnable && alphaTestFunc != Latte::E_COMPAREFUNC::ALWAYS)\n\t\t\t\t{\n\t\t\t\t\tsrc->add(\"if( ((\");\n\t\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, i);\n\t\t\t\t\tsrc->add(\").a \");\n\n\t\t\t\t\tswitch( alphaTestFunc )\n\t\t\t\t\t{\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::LESS:\n\t\t\t\t\t\tsrc->add(\"<\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::EQUAL:\n\t\t\t\t\t\tsrc->add(\"==\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::LEQUAL:\n\t\t\t\t\t\tsrc->add(\"<=\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::GREATER:\n\t\t\t\t\t\tsrc->add(\">\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::NOTEQUAL:\n\t\t\t\t\t\tsrc->add(\"!=\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Latte::E_COMPAREFUNC::GEQUAL:\n\t\t\t\t\t\tsrc->add(\">=\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tsrc->add(\" supportBuffer.alphaTestRef\");\n\t\t\t\t\tsrc->add(\") == false) discard_fragment();\" _CRLF);\n\t\t\t\t}\n\t\t\t\t// pixel color output\n\t\t\t\tauto dataType = GetColorBufferDataType(pixelColorOutputIndex, *shaderContext->contextRegistersNew);\n\t\t\t\tif (dataType != MetalDataType::NONE)\n\t\t\t\t{\n    \t\t\t\tsrc->addFmt(\"out.passPixelColor{} = as_type<{}>(\", pixelColorOutputIndex, GetDataTypeStr(dataType));\n    \t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, i);\n    \t\t\t\tsrc->add(\");\" _CRLF);\n\t\t\t\t}\n\n\t\t\t\tif( cfInstruction->exportArrayBase+i >= 8 )\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t\telse if( cfInstruction->exportType == 0 && cfInstruction->exportArrayBase == 61 )\n\t\t{\n\t\t\t// pixel depth or gl_FragStencilRefARB\n\t\t\tif( cfInstruction->exportBurstCount > 0 )\n\t\t\t\tcemu_assert_unimplemented();\n\n\t\t\tif (cfInstruction->exportComponentSel[0] == 7)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented(); // gl_FragDepth ?\n\t\t\t}\n\t\t\tif (cfInstruction->exportComponentSel[1] != 7)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented(); // exporting to gl_FragStencilRefARB\n\t\t\t}\n\t\t\tif (cfInstruction->exportComponentSel[2] != 7)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented(); // ukn\n\t\t\t}\n\t\t\tif (cfInstruction->exportComponentSel[3] != 7)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented(); // ukn\n\t\t\t}\n\n\t\t\tif (!shaderContext->shader->depthMask)\n\t\t\t    return;\n\n\t\t\tsrc->add(\"out.passDepth = \");\n\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, 0);\n\t\t\tsrc->add(\".x\");\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t}\n}\n\nstatic void _emitXYZWByMask(StringBuf* src, uint32 mask)\n{\n\tif( (mask&(1<<0)) != 0 )\n\t\tsrc->add(\"x\");\n\tif( (mask&(1<<1)) != 0 )\n\t\tsrc->add(\"y\");\n\tif( (mask&(1<<2)) != 0 )\n\t\tsrc->add(\"z\");\n\tif( (mask&(1<<3)) != 0 )\n\t\tsrc->add(\"w\");\n}\n\nstatic void _emitCFRingWriteCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\t// calculate parameter output (based on ring buffer output offset relative to GS unit)\n\tuint32 bytesPerVertex = shaderContext->contextRegisters[mmSQ_GS_VERT_ITEMSIZE] * 4;\n\tbytesPerVertex = std::max(bytesPerVertex, (uint32)1); // avoid division by zero\n\tuint32 parameterOffset = ((cfInstruction->exportArrayBase * 4) % bytesPerVertex);\n\t// for geometry shaders with streamout, MEM_RING_WRITE is used to pass the data to the copy shader, which then uses STREAM*_WRITE\n\tif (shaderContext->shaderType == LatteConst::ShaderType::Geometry && shaderContext->analyzer.hasStreamoutEnable)\n\t{\n\t\t// if streamout is enabled, we generate transform feedback output code instead of the normal gs output\n\t\tfor (uint32 burstIndex = 0; burstIndex < (cfInstruction->exportBurstCount + 1); burstIndex++)\n\t\t{\n\t\t\tparameterOffset = ((cfInstruction->exportArrayBase * 4 + burstIndex*0x10) % bytesPerVertex);\n\t\t\t// find matching stream write in copy shader\n\t\t\tLatteGSCopyShaderStreamWrite_t* streamWrite = nullptr;\n\t\t\tfor (auto& it : shaderContext->parsedGSCopyShader->list_streamWrites)\n\t\t\t{\n\t\t\t\tif (it.offset == parameterOffset)\n\t\t\t\t{\n\t\t\t\t\tstreamWrite = &it;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (streamWrite == nullptr)\n\t\t\t{\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (sint32 i = 0; i < 4; i++)\n\t\t\t{\n\t\t\t\tif ((cfInstruction->memWriteCompMask&(1 << i)) == 0)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tuint32 u32Offset = streamWrite->exportArrayBase + i;\n\t\t\t\tsrc->addFmt(\"sb[sbBase{} + {}]\", streamWrite->bufferIndex, u32Offset);\n\n\t\t\t\tsrc->add(\" = \");\n\n\t\t\t\t_emitTypeConversionPrefixMSL(shaderContext, shaderContext->typeTracker.defaultDataType, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\n\t\t\t\tsrc->addFmt(\"{}.\", _getRegisterVarName(shaderContext, cfInstruction->exportSourceGPR+burstIndex));\n\t\t\t\tif (i == 0)\n\t\t\t\t\tsrc->add(\"x\");\n\t\t\t\telse if (i == 1)\n\t\t\t\t\tsrc->add(\"y\");\n\t\t\t\telse if (i == 2)\n\t\t\t\t\tsrc->add(\"z\");\n\t\t\t\telse if (i == 3)\n\t\t\t\t\tsrc->add(\"w\");\n\n\t\t\t\t_emitTypeConversionSuffixMSL(shaderContext, shaderContext->typeTracker.defaultDataType, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\n\tif (shaderContext->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n        if (!shaderContext->contextRegistersNew->IsRasterizationEnabled())\n        {\n            src->add(\"// Rasterization disabled\" _CRLF);\n            return;\n        }\n\n\t\tif (cfInstruction->memWriteElemSize != 3)\n\t\t\tcemu_assert_unimplemented();\n\t\tif ((cfInstruction->exportArrayBase & 3) != 0)\n\t\t\tcemu_assert_unimplemented();\n\t\tfor (sint32 burstIndex = 0; burstIndex < (sint32)(cfInstruction->exportBurstCount + 1); burstIndex++)\n\t\t{\n\t\t\tsrc->addFmt(\"out.passParameterSem{}.\", (cfInstruction->exportArrayBase) / 4 + burstIndex);\n\t\t\t_emitXYZWByMask(src, cfInstruction->memWriteCompMask);\n\t\t\tsrc->addFmt(\" = \");\n\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_SIGNED_INT, burstIndex);\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t}\n\telse if (shaderContext->shaderType == LatteConst::ShaderType::Geometry)\n\t{\n\t\tcemu_assert_debug(cfInstruction->memWriteElemSize == 3);\n\t\t//if (cfInstruction->memWriteElemSize != 3)\n\t\t//\tdebugBreakpoint();\n\t\tcemu_assert_debug((cfInstruction->exportArrayBase & 3) == 0);\n\n\t\tfor (uint32 burstIndex = 0; burstIndex < (cfInstruction->exportBurstCount + 1); burstIndex++)\n\t\t{\n\t\t\tuint32 parameterExportType = 0;\n\t\t\tuint32 parameterExportBase = 0;\n\t\t\tif (LatteGSCopyShaderParser_getExportTypeByOffset(shaderContext->parsedGSCopyShader, parameterOffset + burstIndex * (cfInstruction->memWriteElemSize+1)*4, &parameterExportType, &parameterExportBase) == false)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tshaderContext->hasError = true;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (parameterExportType == 1 && parameterExportBase == GPU7_DECOMPILER_CF_EXPORT_BASE_POSITION)\n\t\t\t{\n\t\t\t\tsrc->add(\"{\" _CRLF);\n\t\t\t\tsrc->addFmt(\"float4 pos = float4(0.0,0.0,0.0,1.0);\" _CRLF);\n\t\t\t\tsrc->addFmt(\"pos.\");\n\t\t\t\t_emitXYZWByMask(src, cfInstruction->memWriteCompMask);\n\t\t\t\tsrc->addFmt(\" = \");\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, burstIndex);\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t\tsrc->add(\"SET_POSITION(pos);\" _CRLF);\n\t\t\t\tsrc->add(\"}\" _CRLF);\n\t\t\t}\n\t\t\telse if (parameterExportType == 2 && parameterExportBase < 16)\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"out.passParameterSem{}.\", parameterExportBase);\n\t\t\t\t_emitXYZWByMask(src, cfInstruction->memWriteCompMask);\n\t\t\t\tsrc->addFmt(\" = \");\n\t\t\t\t_emitExportGPRReadCode(shaderContext, cfInstruction, LATTE_DECOMPILER_DTYPE_FLOAT, burstIndex);\n\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\telse\n\t\tdebugBreakpoint(); // todo\n}\n\nstatic void _emitStreamWriteCode(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tif (shaderContext->analyzer.hasStreamoutEnable == false)\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tsrc->add(\"// omitted streamout write\" _CRLF);\n#endif\n\t\treturn;\n\t}\n\tuint32 streamoutBufferIndex;\n\tif (cfInstruction->type == GPU7_CF_INST_MEM_STREAM0_WRITE)\n\t\tstreamoutBufferIndex = 0;\n\telse if (cfInstruction->type == GPU7_CF_INST_MEM_STREAM1_WRITE)\n\t\tstreamoutBufferIndex = 1;\n\telse\n\t\tcemu_assert_unimplemented();\n\n\tif (shaderContext->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n\t\tuint32 arraySize = cfInstruction->memWriteArraySize + 1;\n\n\t\tfor (sint32 i = 0; i < (sint32)arraySize; i++)\n\t\t{\n\t\t\tif ((cfInstruction->memWriteCompMask&(1 << i)) == 0)\n\t\t\t\tcontinue;\n\n\t\t\tuint32 u32Offset = cfInstruction->exportArrayBase + i;\n\t\t\tsrc->addFmt(\"sb[sbBase{} + {}]\", streamoutBufferIndex, u32Offset);\n\n\t\t\tsrc->add(\" = \");\n\n\t\t\t_emitTypeConversionPrefixMSL(shaderContext, shaderContext->typeTracker.defaultDataType, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\n\t\t\tsrc->add(_getRegisterVarName(shaderContext, cfInstruction->exportSourceGPR));\n\t\t\t_appendChannelAccess(src, i);\n\t\t\t_emitTypeConversionSuffixMSL(shaderContext, shaderContext->typeTracker.defaultDataType, LATTE_DECOMPILER_DTYPE_SIGNED_INT);\n\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\t}\n\telse\n\t\tcemu_assert_debug(false);\n}\n\nstatic void _emitCFCall(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\tuint32 subroutineAddr = cfInstruction->addr;\n\tLatteDecompilerSubroutineInfo* subroutineInfo = nullptr;\n\t// find subroutine\n\tfor (auto& subroutineItr : shaderContext->list_subroutines)\n\t{\n\t\tif (subroutineItr.cfAddr == subroutineAddr)\n\t\t{\n\t\t\tsubroutineInfo = &subroutineItr;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (subroutineInfo == nullptr)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\t// inline function\n\tif (shaderContext->isSubroutine)\n\t{\n\t\tcemu_assert_debug(false); // inlining with cascaded function calls not supported\n\t\treturn;\n\t}\n\t// init CF stack variables\n\tsrc->addFmt(\"activeMaskStackSub{:04x}[0] = true;\" _CRLF, subroutineInfo->cfAddr);\n\tsrc->addFmt(\"activeMaskStackCSub{:04x}[0] = true;\" _CRLF, subroutineInfo->cfAddr);\n\tsrc->addFmt(\"activeMaskStackCSub{:04x}[1] = true;\" _CRLF, subroutineInfo->cfAddr);\n\n\tshaderContext->isSubroutine = true;\n\tshaderContext->subroutineInfo = subroutineInfo;\n\tfor(auto& cfInstruction : subroutineInfo->instructions)\n\t\tLatteDecompiler_emitClauseCodeMSL(shaderContext, &cfInstruction, true);\n\tshaderContext->isSubroutine = false;\n\tshaderContext->subroutineInfo = nullptr;\n}\n\nvoid LatteDecompiler_emitClauseCodeMSL(LatteDecompilerShaderContext* shaderContext, LatteDecompilerCFInstruction* cfInstruction, bool isSubroutine)\n{\n\tStringBuf* src = shaderContext->shaderSource;\n\n\tif( cfInstruction->type == GPU7_CF_INST_ALU || cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE || cfInstruction->type == GPU7_CF_INST_ALU_POP_AFTER || cfInstruction->type == GPU7_CF_INST_ALU_POP2_AFTER || cfInstruction->type == GPU7_CF_INST_ALU_BREAK || cfInstruction->type == GPU7_CF_INST_ALU_ELSE_AFTER )\n\t{\n\t\t// emit ALU code\n\t\tif (shaderContext->analyzer.modifiesPixelActiveState)\n\t\t{\n\t\t\tif(cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE)\n\t\t\t\tsrc->addFmt(\"if( {} == true ) {{\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1 - 1));\n\t\t\telse\n\t\t\t\tsrc->addFmt(\"if( {} == true ) {{\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1));\n\t\t}\n\t\tif (cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE)\n\t\t{\n\t\t\tsrc->addFmt(\"{} = {};\" _CRLF, _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth-1));\n\t\t\tsrc->addFmt(\"{} = {};\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t}\n\t\t_emitALUClauseCode(shaderContext, cfInstruction);\n\t\tif( shaderContext->analyzer.modifiesPixelActiveState )\n\t\t\tsrc->add(\"}\" _CRLF);\n\t\tcemu_assert_debug(!(shaderContext->analyzer.modifiesPixelActiveState == false && cfInstruction->type != GPU7_CF_INST_ALU));\n\t\t// handle ELSE case of PUSH_BEFORE\n\t\tif( cfInstruction->type == GPU7_CF_INST_ALU_PUSH_BEFORE )\n\t\t{\n\t\t\tsrc->add(\"else {\" _CRLF);\n\t\t\tsrc->addFmt(\"{} = false;\" _CRLF, _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t\tsrc->addFmt(\"{} = false;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1));\n\t\t\tsrc->add(\"}\" _CRLF);\n\t\t}\n\t\t// post clause handler\n\t\tif( cfInstruction->type == GPU7_CF_INST_ALU_POP_AFTER )\n\t\t{\n\t\t\tsrc->addFmt(\"{} = {} == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1 - 1), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth - 1), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth - 1));\n\t\t}\n\t\telse if( cfInstruction->type == GPU7_CF_INST_ALU_POP2_AFTER )\n\t\t{\n\t\t\tsrc->addFmt(\"{} = {} == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1 - 2), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth - 2), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth - 2));\n\t\t}\n\t\telse if( cfInstruction->type == GPU7_CF_INST_ALU_ELSE_AFTER )\n\t\t{\n\t\t\t// no condition test\n\t\t\t// pop stack\n\t\t\tif( cfInstruction->popCount != 0 )\n\t\t\t\tdebugBreakpoint();\n\t\t\t// else operation\n\t\t\tsrc->addFmt(\"{} = {} == false;\" _CRLF, _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t\tsrc->addFmt(\"{} = {} == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\t}\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_TEX )\n\t{\n\t\t// emit TEX code\n\t\tif (shaderContext->analyzer.modifiesPixelActiveState)\n\t\t{\n\t\t\tsrc->addFmt(\"if( {} == true ) {{\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth+1));\n\t\t}\n\t\t_emitTEXClauseCode(shaderContext, cfInstruction);\n\t\tif (shaderContext->analyzer.modifiesPixelActiveState)\n\t\t{\n\t\t\tsrc->add(\"}\" _CRLF);\n\t\t}\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_EXPORT || cfInstruction->type == GPU7_CF_INST_EXPORT_DONE )\n\t{\n\t\t// emit export code\n\t\t_emitExportCode(shaderContext, cfInstruction);\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_ELSE )\n\t{\n\t\t// todo: Condition test, popCount?\n\t\tsrc->addFmt(\"{} = {} == false;\" _CRLF, _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth));\n\t\tsrc->addFmt(\"{} = {} == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth));\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_POP )\n\t{\n\t\tsrc->addFmt(\"{} = {} == true && {} == true;\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1 - cfInstruction->popCount), _getActiveMaskVarName(shaderContext, cfInstruction->activeStackDepth - cfInstruction->popCount), _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth - cfInstruction->popCount));\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_LOOP_START_DX10 ||\n\t\t\t cfInstruction->type == GPU7_CF_INST_LOOP_START_NO_AL)\n\t{\n\t\t// start of loop\n\t\t// if pixel is disabled, then skip loop\n\t\tif (ActiveSettings::ShaderPreventInfiniteLoopsEnabled())\n\t\t{\n\t\t\t// with iteration limit to prevent infinite loops\n\t\t\tsrc->addFmt(\"int loopCounter{} = 0;\" _CRLF, (sint32)cfInstruction->cfAddr);\n\t\t\tsrc->addFmt(\"while( {} == true && loopCounter{} < 500 )\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1), (sint32)cfInstruction->cfAddr);\n\t\t\tsrc->add(\"{\" _CRLF);\n\t\t\tsrc->addFmt(\"loopCounter{}++;\" _CRLF, (sint32)cfInstruction->cfAddr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsrc->addFmt(\"while( {} == true )\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1));\n\t\t\tsrc->add(\"{\" _CRLF);\n\t\t}\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_LOOP_END )\n\t{\n\t\t// this might not always work\n\t\tif( cfInstruction->popCount != 0 )\n\t\t\tdebugBreakpoint();\n\t\tsrc->add(\"}\" _CRLF);\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_LOOP_BREAK )\n\t{\n\t\tif( cfInstruction->popCount != 0 )\n\t\t\tdebugBreakpoint();\n\t\tif (shaderContext->analyzer.modifiesPixelActiveState)\n\t\t{\n\t\t\tsrc->addFmt(\"if( {} == true ) {{\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1));\n\t\t}\n\t\t// note: active stack level is set to the same level as the loop begin. popCount is ignored\n\t\tsrc->add(\"break;\" _CRLF);\n\n\t\tif (shaderContext->analyzer.modifiesPixelActiveState)\n\t\t\tsrc->add(\"}\" _CRLF);\n\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_MEM_STREAM0_WRITE ||\n\t\tcfInstruction->type == GPU7_CF_INST_MEM_STREAM1_WRITE )\n\t{\n\t\t_emitStreamWriteCode(shaderContext, cfInstruction);\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_MEM_RING_WRITE )\n\t{\n\t\t_emitCFRingWriteCode(shaderContext, cfInstruction);\n\t}\n\telse if( cfInstruction->type == GPU7_CF_INST_EMIT_VERTEX )\n\t{\n\t\tif( shaderContext->analyzer.modifiesPixelActiveState )\n\t\t\tsrc->addFmt(\"if( {} == true ) {{\" _CRLF, _getActiveMaskCVarName(shaderContext, cfInstruction->activeStackDepth + 1));\n\t\t// write point size\n\t\tif (shaderContext->analyzer.outputPointSize && shaderContext->analyzer.writesPointSize == false)\n\t\t\tsrc->add(\"out.pointSize = supportBuffer.pointSize;\" _CRLF);\n\t\tsrc->add(\"mesh.set_vertex(vertexIndex, out);\" _CRLF);\n\t\tsrc->add(\"vertexIndex++;\" _CRLF);\n\t\t// increment transform feedback pointer\n\t\tfor (sint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t{\n\t\t\tif (!shaderContext->output->streamoutBufferWriteMask[i])\n\t\t\t\tcontinue;\n\t\t\tcemu_assert_debug((shaderContext->output->streamoutBufferStride[i] & 3) == 0);\n\t\t\tsrc->addFmt(\"sbBase{} += {};\" _CRLF, i, shaderContext->output->streamoutBufferStride[i] / 4);\n\t\t}\n\n\t\tif( shaderContext->analyzer.modifiesPixelActiveState )\n\t\t\tsrc->add(\"}\" _CRLF);\n\t}\n\telse if (cfInstruction->type == GPU7_CF_INST_CALL)\n\t{\n\t\t_emitCFCall(shaderContext, cfInstruction);\n\t}\n\telse if (cfInstruction->type == GPU7_CF_INST_RETURN)\n\t{\n\t\t// todo (handle properly)\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n}\n\nvoid LatteDecompiler_emitHelperFunctions(LatteDecompilerShaderContext* shaderContext, StringBuf* fCStr_shaderSource)\n{\n\tif( shaderContext->analyzer.hasRedcCUBE )\n\t{\n\t\tfCStr_shaderSource->add(\"void redcCUBE(float4 src0, float4 src1, thread float3& stm, thread int& faceId)\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"// stm -> x .. s, y .. t, z .. MajorAxis*2.0\\r\\n\"\n\n\t\t\"float3 inputCoord = normalize(float3(src1.y, src1.x, src0.x));\\r\\n\"\n\n\t\t\"float rx = inputCoord.x;\\r\\n\"\n\t\t\"float ry = inputCoord.y;\\r\\n\"\n\t\t\"float rz = inputCoord.z;\\r\\n\"\n\t\t\"if( abs(rx) > abs(ry) && abs(rx) > abs(rz) )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"stm.z = rx*2.0;\\r\\n\"\n\t\t\"stm.xy = float2(ry,rz);\t\\r\\n\"\n\t\t\"if( rx >= 0.0 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 1;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else if( abs(ry) > abs(rx) && abs(ry) > abs(rz) )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"stm.z = ry*2.0;\\r\\n\"\n\t\t\"stm.xy = float2(rx,rz);\t\\r\\n\"\n\t\t\"if( ry >= 0.0 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 2;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 3;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else //if( abs(rz) > abs(ry) && abs(rz) > abs(rx) )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"stm.z = rz*2.0;\\r\\n\"\n\t\t\"stm.xy = float2(rx,ry);\t\\r\\n\"\n\t\t\"if( rz >= 0.0 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 4;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"faceId = 5;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"}\\r\\n\");\n\t}\n\n\tif( shaderContext->analyzer.hasCubeMapTexture )\n\t{\n\t\tfCStr_shaderSource->add(\"float3 redcCUBEReverse(float2 st, int faceId)\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"st.yx = st.xy;\\r\\n\"\n\t\t\"float3 v;\\r\\n\"\n\t\t\"float majorAxis = 1.0;\\r\\n\"\n\t\t\"if( faceId == 0 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.yz = (st-float2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.x = 1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else if( faceId == 1 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.yz = (st-float2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.x = -1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else if( faceId == 2 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.xz = (st-float2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.y = 1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else if( faceId == 3 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.xz = (st-float2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.y = -1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else if( faceId == 4 )\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.xy = (st-float2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.z = 1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\t\t\"else\\r\\n\"\n\t\t\"{\\r\\n\"\n\t\t\"v.xy = (st-float2(1.5))*(majorAxis*2.0);\\r\\n\"\n\t\t\"v.z = -1.0;\\r\\n\"\n\t\t\"}\\r\\n\"\n\n\t\t\"return v;\\r\\n\"\n\t\t\"}\\r\\n\");\n\t}\n\n\t// Sample compare emulate\n\t// TODO: only add when needed\n\t// TODO: lod_options overload\n\t// TODO: when the sampler has linear min mag filter, use gather and filter manually\n\t// TODO: offset?\n\tfCStr_shaderSource->add(\"\"\n\t\"template<typename TextureT, typename CoordT>\\r\\n\"\n\t\"float sampleCompareEmulate(TextureT tex, sampler samplr, CoordT coord, float compareValue) {\\r\\n\"\n\t    \"return compareValue < tex.sample(samplr, coord).x ? 1.0 : 0.0;\\r\\n\"\n\t\"}\\r\\n\"\n\t);\n\n\t// Texture calculate lod\n\t// TODO: only add when needed\n\tfCStr_shaderSource->add(\"\"\n\t\"template<typename TextureT, typename CoordT>\\r\\n\"\n\t\"float2 textureCalculateLod(TextureT tex, sampler samplr, CoordT coord) {\\r\\n\"\n        \"float lod = tex.calculate_unclamped_lod(samplr, coord);\\r\\n\"\n        \"return float2(floor(lod), fract(lod));\\r\\n\"\n\t\"}\\r\\n\");\n\n\t// clamp\n\tfCStr_shaderSource->add(\"\"\n\t\"int clampFI32(int v)\\r\\n\"\n\t\"{\\r\\n\"\n\t\t\"if( v == 0x7FFFFFFF )\\r\\n\"\n\t\t\"\treturn as_type<int>(1.0);\\r\\n\"\n\t\t\"else if( v == 0xFFFFFFFF )\\r\\n\"\n\t\t\"\treturn as_type<int>(0.0);\\r\\n\"\n\t\t\"return as_type<int>(clamp(as_type<float>(v), 0.0, 1.0));\\r\\n\"\n\t\"}\\r\\n\");\n\n\t// mul non-ieee way (0*NaN/INF => 0.0)\n\tif (shaderContext->options->strictMul)\n\t{\n\t\t// things we tried:\n\t\t//fCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){ return mix(a*b,0.0,a==0.0||b==0.0); }\" STR_LINEBREAK);\n\t\t//fCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){ return mix(vec2(a*b,0.0),vec2(0.0,0.0),(equal(vec2(a),vec2(0.0,0.0))||equal(vec2(b),vec2(0.0,0.0)))).x; }\" STR_LINEBREAK);\n\t\t//fCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){ if( a == 0.0 || b == 0.0 ) return 0.0; return a*b; }\" STR_LINEBREAK);\n\t\t//fCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){float r = a*b;r = intBitsToFloat(floatBitsToInt(r)&(((floatBitsToInt(a) != 0) && (floatBitsToInt(b) != 0))?0xFFFFFFFF:0));return r;}\" STR_LINEBREAK); works\n\n\t\t// for \"min\" it used to be: float mul_nonIEEE(float a, float b){ return min(a*b,min(abs(a)*3.40282347E+38F,abs(b)*3.40282347E+38F)); }\n\n\t\tif( LatteGPUState.glVendor == GLVENDOR_NVIDIA && !ActiveSettings::DumpShadersEnabled())\n\t\t\tfCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){return mix(0.0, a*b, (a != 0.0) && (b != 0.0));}\" _CRLF); // compiles faster on Nvidia and also results in lower RAM usage (OpenGL)\n\t\telse\n\t\t\tfCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){ if( a == 0.0 || b == 0.0 ) return 0.0; return a*b; }\" _CRLF);\n\n\t\t// DXKV-like: fCStr_shaderSource->add(\"float mul_nonIEEE(float a, float b){ return (b==0.0 ? 0.0 : a) * (a==0.0 ? 0.0 : b); }\" _CRLF);\n\t}\n}\n\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp\"\n\nstatic void LatteDecompiler_emitAttributeImport(LatteDecompilerShaderContext* shaderContext, LatteParsedFetchShaderAttribute_t& attrib)\n{\n\tauto src = shaderContext->shaderSource;\n\n\tstatic const char* dsMappingTableFloat[6] = { \"int(attrDecoder.x)\", \"int(attrDecoder.y)\", \"int(attrDecoder.z)\", \"int(attrDecoder.w)\", /*\"floatBitsToInt(0.0)\"*/ \"0\", /*\"floatBitsToInt(1.0)\"*/ \"0x3f800000\" };\n\tstatic const char* dsMappingTableInt[6] = { \"int(attrDecoder.x)\", \"int(attrDecoder.y)\", \"int(attrDecoder.z)\", \"int(attrDecoder.w)\", \"0\", \"1\" };\n\n\t// get register index based on vtx semantic table\n\tuint32 attributeShaderLoc = 0xFFFFFFFF;\n\tfor (sint32 f = 0; f < 32; f++)\n\t{\n\t\tif (shaderContext->contextRegisters[mmSQ_VTX_SEMANTIC_0 + f] == attrib.semanticId)\n\t\t{\n\t\t\tattributeShaderLoc = f;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (attributeShaderLoc == 0xFFFFFFFF)\n\t\treturn; // attribute is not mapped to VS input\n\tuint32 registerIndex = attributeShaderLoc + 1; // R0 is skipped\n\t// is register used?\n\tif ((shaderContext->analyzer.gprUseMask[registerIndex / 8] & (1 << (registerIndex % 8))) == 0)\n\t{\n\t\tsrc->addFmt(\"// skipped unused attribute for r{}\" _CRLF, registerIndex);\n\t\treturn;\n\t}\n\n\tLatteDecompiler_emitAttributeDecodeMSL(shaderContext->shader, src, &attrib);\n\n\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\tsrc->addFmt(\"{} = int4(\", _getRegisterVarName(shaderContext, registerIndex));\n\telse\n\t\tsrc->addFmt(\"{} = float4(\", _getRegisterVarName(shaderContext, registerIndex));\n\tfor (sint32 f = 0; f < 4; f++)\n\t{\n\t\tuint8 ds = attrib.ds[f];\n\t\tif (f > 0)\n\t\t\tsrc->add(\", \");\n\t\t_emitTypeConversionPrefixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, shaderContext->typeTracker.defaultDataType);\n\t\tif (ds >= 6)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t\tds = 4; // read as 0.0\n\t\t}\n\t\tif (attrib.nfa != 1)\n\t\t{\n\t\t\tsrc->add(dsMappingTableFloat[ds]);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsrc->add(dsMappingTableInt[ds]);\n\t\t}\n\t\t_emitTypeConversionSuffixMSL(shaderContext, LATTE_DECOMPILER_DTYPE_SIGNED_INT, shaderContext->typeTracker.defaultDataType);\n\t}\n\tsrc->add(\");\" _CRLF);\n}\n\nvoid LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader)\n{\n    bool isRectVertexShader = UseRectEmulation(*shaderContext->contextRegistersNew);\n    bool usesGeometryShader = UseGeometryShader(*shaderContext->contextRegistersNew, shaderContext->options->usesGeometryShader);\n    bool fetchVertexManually = (usesGeometryShader || (shaderContext->fetchShader && shaderContext->fetchShader->mtlFetchVertexManually));\n\n\tStringBuf* src = new StringBuf(1024*1024*12); // reserve 12MB for generated source (we resize-to-fit at the end)\n\tshaderContext->shaderSource = src;\n\n\t// debug info\n\tsrc->addFmt(\"// shader {:016x}\" _CRLF, shaderContext->shaderBaseHash);\n#ifdef CEMU_DEBUG_ASSERT\n\tsrc->addFmt(\"// usesIntegerValues: {}\" _CRLF, shaderContext->analyzer.usesIntegerValues ? \"true\" : \"false\");\n\tsrc->addFmt(_CRLF);\n#endif\n    // include metal standard library\n    src->add(\"#include <metal_stdlib>\" _CRLF);\n    src->add(\"using namespace metal;\" _CRLF);\n\t// header part (definitions for inputs and outputs)\n\tLatteDecompiler::emitHeader(shaderContext, isRectVertexShader, usesGeometryShader, fetchVertexManually);\n\t// helper functions\n\tLatteDecompiler_emitHelperFunctions(shaderContext, src);\n\tconst char* functionType = \"\";\n\tconst char* outputTypeName = \"\";\n\tswitch (shader->shaderType)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t    if (fetchVertexManually)\n\t\t{\n\t\t    // TODO: clean this up\n\t\t\t// fetchVertex will modify vid in case of an object shader and an indexed draw\n\n\t\t\t// Vertex buffers\n            std::string vertexBufferDefinitions = \"#define VERTEX_BUFFER_DEFINITIONS \";\n            std::string vertexBuffers = \"#define VERTEX_BUFFERS \";\n            std::string inputFetchDefinition = \"VertexIn fetchVertex(\";\n            if (usesGeometryShader)\n                inputFetchDefinition += \"thread uint&\";\n            else\n                inputFetchDefinition += \"uint\";\n            inputFetchDefinition += \" vid, uint iid\";\n            if (usesGeometryShader)\n                inputFetchDefinition += \", device uint* indexBuffer, uchar indexType\";\n            inputFetchDefinition += \" VERTEX_BUFFER_DEFINITIONS) {\\n\";\n\n\t\t\t// Index buffer\n\t\t\tif (usesGeometryShader)\n\t\t\t{\n                inputFetchDefinition += \"if (indexType == 1) // UShort\\n\";\n                inputFetchDefinition += \"vid = ((device ushort*)indexBuffer)[vid];\\n\";\n                inputFetchDefinition += \"else if (indexType == 2) // UInt\\n\";\n                inputFetchDefinition += \"vid = ((device uint*)indexBuffer)[vid];\\n\";\n\t\t\t}\n\n            inputFetchDefinition += \"VertexIn in;\\n\";\n            for (auto& bufferGroup : shaderContext->fetchShader->bufferGroups)\n\t\t\t{\n                std::optional<LatteConst::VertexFetchType2> fetchType;\n\n\t\t\t\tuint32 bufferIndex = bufferGroup.attributeBufferIndex;\n\t\t\t\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n\t\t\t\tuint32 bufferStride = (shaderContext->contextRegisters[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;\n\n               \tfor (sint32 j = 0; j < bufferGroup.attribCount; ++j)\n               \t{\n              \t\tauto& attr = bufferGroup.attrib[j];\n\n              \t\tuint32 semanticId = shaderContext->output->resourceMappingMTL.attributeMapping[attr.semanticId];\n              \t\tif (semanticId == (uint32)-1)\n             \t\t\tcontinue; // attribute not used?\n\n                    std::string formatName;\n                    uint8 componentCount = 0;\n                    switch (GetMtlVertexFormat(attr.format))\n                    {\n                    case MTL::VertexFormatUChar:\n                        formatName = \"uchar\";\n                        componentCount = 1;\n                        break;\n                    case MTL::VertexFormatUChar2:\n                        formatName = \"uchar2\";\n                        componentCount = 2;\n                        break;\n                    case MTL::VertexFormatUChar3:\n                        formatName = \"uchar3\";\n                        componentCount = 3;\n                        break;\n                    case MTL::VertexFormatUChar4:\n                        formatName = \"uchar4\";\n                        componentCount = 4;\n                        break;\n                    case MTL::VertexFormatUShort:\n                        formatName = \"ushort\";\n                        componentCount = 1;\n                        break;\n                    case MTL::VertexFormatUShort2:\n                        formatName = \"ushort2\";\n                        componentCount = 2;\n                        break;\n                    case MTL::VertexFormatUShort3:\n                        formatName = \"ushort3\";\n                        componentCount = 3;\n                        break;\n                    case MTL::VertexFormatUShort4:\n                        formatName = \"ushort4\";\n                        componentCount = 4;\n                        break;\n                    case MTL::VertexFormatUInt:\n                        formatName = \"uint\";\n                        componentCount = 1;\n                        break;\n                    case MTL::VertexFormatUInt2:\n                        formatName = \"uint2\";\n                        componentCount = 2;\n                        break;\n                    case MTL::VertexFormatUInt3:\n                        formatName = \"uint3\";\n                        componentCount = 3;\n                        break;\n                    case MTL::VertexFormatUInt4:\n                        formatName = \"uint4\";\n                        componentCount = 4;\n                        break;\n                    }\n\n                    // Get the fetch type\n                    std::string fetchTypeStr;\n                    if (attr.fetchType == LatteConst::VertexFetchType2::VERTEX_DATA)\n                        fetchTypeStr = \"vid\";\n                    else if (attr.fetchType == LatteConst::VertexFetchType2::INSTANCE_DATA)\n                        fetchTypeStr = \"iid\";\n                    else if (attr.fetchType == LatteConst::VertexFetchType2::NO_INDEX_OFFSET_DATA)\n                        fetchTypeStr = \"0\"; // TODO: correct?\n\n                    // Fetch the attribute\n                    inputFetchDefinition += fmt::format(\"in.ATTRIBUTE_NAME{} = uint4(uint\", semanticId);\n                    if (componentCount != 1)\n                        inputFetchDefinition += fmt::format(\"{}\", componentCount);\n                    inputFetchDefinition += fmt::format(\"(*(device {}*)\", formatName);\n                    inputFetchDefinition += fmt::format(\"(vertexBuffer{}\", attr.attributeBufferIndex);\n                    inputFetchDefinition += fmt::format(\" + {} * {} + {}))\", fetchTypeStr, bufferStride, attr.offset);\n                    for (uint8 i = 0; i < (4 - componentCount); i++)\n                        inputFetchDefinition += \", 0\";\n                    inputFetchDefinition += \");\\n\";\n\n              \t\tif (fetchType.has_value())\n             \t\t\tcemu_assert_debug(fetchType == attr.fetchType);\n              \t\telse\n             \t\t\tfetchType = attr.fetchType;\n\n              \t\tif (attr.fetchType == LatteConst::INSTANCE_DATA)\n              \t\t{\n             \t\t\tcemu_assert_debug(attr.aluDivisor == 1); // other divisor not yet supported\n              \t\t}\n               \t}\n\n                // TODO: fetch type\n\n\t\t\t\tvertexBufferDefinitions += fmt::format(\", device uchar* vertexBuffer{} [[buffer({})]]\", bufferIndex, GET_MTL_VERTEX_BUFFER_INDEX(bufferIndex));\n\t\t\t\tvertexBuffers += fmt::format(\", vertexBuffer{}\", bufferIndex);\n\t\t\t}\n\n\t\t\tinputFetchDefinition += \"return in;\\n\";\n\t\t\tinputFetchDefinition += \"}\\n\";\n\n\t\t\tsrc->add(vertexBufferDefinitions.c_str());\n\t\t\tsrc->add(\"\\n\");\n\t\t\tsrc->add(vertexBuffers.c_str());\n\t\t\tsrc->add(\"\\n\");\n\t\t\tsrc->add(inputFetchDefinition.c_str());\n\t\t}\n\n\t\tif (usesGeometryShader)\n\t\t{\n\t\t\tfunctionType = \"[[object, max_total_threads_per_threadgroup(VERTICES_PER_VERTEX_PRIMITIVE), max_total_threadgroups_per_mesh_grid(1)]]\";\n\t\t\toutputTypeName = \"void\";\n\t\t}\n\t\telse\n\t\t{\n    \t    functionType = \"vertex\";\n            if (shaderContext->contextRegistersNew->IsRasterizationEnabled())\n       \t        outputTypeName = \"VertexOut\";\n            else\n                outputTypeName = \"void\";\n\t\t}\n\t\tbreak;\n\tcase LatteConst::ShaderType::Geometry:\n        functionType = \"[[mesh, max_total_threads_per_threadgroup(1)]]\";\n        outputTypeName = \"void\";\n        break;\n\tcase LatteConst::ShaderType::Pixel:\n\t    functionType = \"fragment\";\n\t    outputTypeName = \"FragmentOut\";\n\t\tbreak;\n\t}\n\t// start of main\n\tsrc->addFmt(\"{} {} main0(\", functionType, outputTypeName);\n\tLatteDecompiler::emitInputs(shaderContext, isRectVertexShader, usesGeometryShader, fetchVertexManually);\n\tsrc->add(\") {\" _CRLF);\n\tif (fetchVertexManually && (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry))\n\t{\n\t    if (shader->shaderType == LatteConst::ShaderType::Vertex)\n\t\t{\n            if (usesGeometryShader)\n            {\n           \t    // Calculate the imaginary vertex id\n                LattePrimitiveMode vsOutPrimType = shaderContext->contextRegistersNew->VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();\n                if (PrimitiveRequiresConnection(vsOutPrimType))\n           \t        src->add(\"uint vid = tig + tid;\" _CRLF);\n                else\n       \t            src->add(\"uint vid = tig * VERTICES_PER_VERTEX_PRIMITIVE + tid;\" _CRLF);\n          \t\tsrc->add(\"uint iid = vid / supportBuffer.verticesPerInstance;\" _CRLF);\n                src->add(\"vid %= supportBuffer.verticesPerInstance;\" _CRLF);\n\n          \t\t// Fetch the input\n          \t\tsrc->add(\"VertexIn in = fetchVertex(vid, iid, indexBuffer, indexType VERTEX_BUFFERS);\" _CRLF);\n\n          \t\t// Output is defined as object payload\n          \t\tsrc->add(\"object_data VertexOut& out = objectPayload.vertexOut[tid];\" _CRLF);\n            }\n            else\n            {\n          \t\t// Fetch the input\n          \t\tsrc->add(\"VertexIn in = fetchVertex(vid, iid VERTEX_BUFFERS);\" _CRLF);\n            }\n\t\t}\n\t\telse if (shader->shaderType == LatteConst::ShaderType::Geometry)\n\t\t{\n\t\t    src->add(\"GeometryOut out;\" _CRLF);\n\t\t\t// The index of the current vertex that is being emitted\n\t\t\tsrc->add(\"uint vertexIndex = 0;\" _CRLF);\n\t\t}\n\t}\n\n\tif (shader->shaderType == LatteConst::ShaderType::Pixel || (shaderContext->contextRegistersNew->IsRasterizationEnabled() && !usesGeometryShader))\n\t{\n\t    src->addFmt(\"{} out;\" _CRLF, outputTypeName);\n\t}\n\n\t// variable definition\n\tif (shaderContext->typeTracker.useArrayGPRs == false)\n\t{\n\t\t// each register is a separate variable\n\t\tfor (sint32 i = 0; i < 128; i++)\n\t\t{\n\t\t\tif (shaderContext->analyzer.usesRelativeGPRRead || (shaderContext->analyzer.gprUseMask[i / 8] & (1 << (i & 7))) != 0)\n\t\t\t{\n\t\t\t\tif (shaderContext->typeTracker.genIntReg)\n\t\t\t\t\tsrc->addFmt(\"int4 R{}i = int4(0);\" _CRLF, i);\n\t\t\t\telse if (shaderContext->typeTracker.genFloatReg)\n\t\t\t\t\tsrc->addFmt(\"float4 R{}f = float4(0.0);\" _CRLF, i);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// registers are represented using a single large array\n\t\tif (shaderContext->typeTracker.genIntReg)\n\t\t\tsrc->addFmt(\"int4 Ri[128];\" _CRLF);\n\t\telse if (shaderContext->typeTracker.genFloatReg)\n\t\t\tsrc->addFmt(\"float4 Rf[128];\" _CRLF);\n\t\tfor (sint32 i = 0; i < 128; i++)\n\t\t{\n\t\t\tif (shaderContext->typeTracker.genIntReg)\n\t\t\t\tsrc->addFmt(\"Ri[{}] = int4(0);\" _CRLF, i);\n\t\t\telse if (shaderContext->typeTracker.genFloatReg)\n\t\t\t\tsrc->addFmt(\"Rf[{}] = float4(0.0);\" _CRLF, i);\n\t\t}\n\t}\n\n\tif( shader->shaderType == LatteConst::ShaderType::Vertex )\n\t\tsrc->addFmt(\"uint4 attrDecoder;\" _CRLF);\n\tif (shaderContext->typeTracker.genIntReg)\n\t\tsrc->addFmt(\"int backupReg0i, backupReg1i, backupReg2i, backupReg3i, backupReg4i;\" _CRLF);\n\tif (shaderContext->typeTracker.genFloatReg)\n\t\tsrc->addFmt(\"float backupReg0f, backupReg1f, backupReg2f, backupReg3f, backupReg4f;\" _CRLF);\n\tif (shaderContext->typeTracker.genIntReg)\n\t{\n\t\tsrc->addFmt(\"int PV0ix = 0, PV0iy = 0, PV0iz = 0, PV0iw = 0, PV1ix = 0, PV1iy = 0, PV1iz = 0, PV1iw = 0;\" _CRLF);\n\t\tsrc->addFmt(\"int PS0i = 0, PS1i = 0;\" _CRLF);\n\t\tsrc->addFmt(\"int4 tempi = int4(0);\" _CRLF);\n\t}\n\tif (shaderContext->typeTracker.genFloatReg)\n\t{\n\t\tsrc->addFmt(\"float PV0fx = 0.0, PV0fy = 0.0, PV0fz = 0.0, PV0fw = 0.0, PV1fx = 0.0, PV1fy = 0.0, PV1fz = 0.0, PV1fw = 0.0;\" _CRLF);\n\t\tsrc->addFmt(\"float PS0f = 0.0, PS1f = 0.0;\" _CRLF);\n\t\tsrc->addFmt(\"float4 tempf = float4(0.0);\" _CRLF);\n\t}\n\tif (shaderContext->analyzer.hasGradientLookup)\n\t{\n\t\tsrc->add(\"float4 gradH;\" _CRLF);\n\t\tsrc->add(\"float4 gradV;\" _CRLF);\n\t}\n\tsrc->add(\"float tempResultf;\" _CRLF);\n\tsrc->add(\"int tempResulti;\" _CRLF);\n\tsrc->add(\"int4 ARi = int4(0);\" _CRLF);\n\tsrc->add(\"bool predResult = true;\" _CRLF);\n\tif(shaderContext->analyzer.modifiesPixelActiveState )\n\t{\n\t\tsrc->addFmt(\"bool activeMaskStack[{}];\" _CRLF, shaderContext->analyzer.activeStackMaxDepth+1);\n\t\tsrc->addFmt(\"bool activeMaskStackC[{}];\" _CRLF, shaderContext->analyzer.activeStackMaxDepth+2);\n\t\tfor (sint32 i = 0; i < shaderContext->analyzer.activeStackMaxDepth; i++)\n\t\t{\n\t\t\tsrc->addFmt(\"activeMaskStack[{}] = false;\" _CRLF, i);\n\t\t}\n\t\tfor (sint32 i = 0; i < shaderContext->analyzer.activeStackMaxDepth+1; i++)\n\t\t{\n\t\t\tsrc->addFmt(\"activeMaskStackC[{}] = false;\" _CRLF, i);\n\t\t}\n\t\tsrc->addFmt(\"activeMaskStack[0] = true;\" _CRLF);\n\t\tsrc->addFmt(\"activeMaskStackC[0] = true;\" _CRLF);\n\t\tsrc->addFmt(\"activeMaskStackC[1] = true;\" _CRLF);\n\t\t// generate vars for each subroutine\n\t\tfor (auto& subroutineInfo : shaderContext->list_subroutines)\n\t\t{\n\t\t\tsint32 subroutineMaxStackDepth = 0;\n\t\t\tsrc->addFmt(\"bool activeMaskStackSub{:04x}[{}];\" _CRLF, subroutineInfo.cfAddr, subroutineMaxStackDepth + 1);\n\t\t\tsrc->addFmt(\"bool activeMaskStackCSub{:04x}[{}];\" _CRLF, subroutineInfo.cfAddr, subroutineMaxStackDepth + 2);\n\t\t}\n\t}\n\t// helper variables for cube maps (todo: Only emit when used)\n\tif (shaderContext->analyzer.hasRedcCUBE)\n\t{\n\t\tsrc->add(\"float3 cubeMapSTM;\" _CRLF);\n\t\tsrc->add(\"int cubeMapFaceId;\" _CRLF);\n\t}\n\tfor(sint32 i=0; i<LATTE_NUM_MAX_TEX_UNITS; i++)\n\t{\n\t\tif(!shaderContext->output->textureUnitMask[i])\n\t\t\tcontinue;\n\t\tif( shader->textureUnitDim[i] != Latte::E_DIM::DIM_CUBEMAP )\n\t\t\tcontinue;\n\t\tsrc->addFmt(\"float cubeMapArrayIndex{} = 0.0;\" _CRLF, i);\n\t}\n\t// init base offset for streamout buffer writes\n\tif (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry)\n\t{\n\t\tfor (sint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t{\n\t\t\tif(!shaderContext->output->streamoutBufferWriteMask[i])\n\t\t\t\tcontinue;\n\n\t\t\tcemu_assert_debug((shaderContext->output->streamoutBufferStride[i]&3) == 0);\n\n\t\t\tif (shader->shaderType == LatteConst::ShaderType::Vertex) // vertex shader\n\t\t\t\tsrc->addFmt(\"int sbBase{} = supportBuffer.streamoutBufferBase{}/4 + (vid + supportBuffer.verticesPerInstance * iid)*{};\" _CRLF, i, i, shaderContext->output->streamoutBufferStride[i] / 4);\n\t\t\telse // geometry shader\n\t\t\t{\n\t\t\t\tuint32 gsOutPrimType = shaderContext->contextRegisters[mmVGT_GS_OUT_PRIM_TYPE];\n\t\t\t\tuint32 bytesPerVertex = shaderContext->contextRegisters[mmSQ_GS_VERT_ITEMSIZE] * 4;\n\t\t\t\tuint32 maxVerticesInGS = ((shaderContext->contextRegisters[mmSQ_GSVS_RING_ITEMSIZE] & 0x7FFF) * 4) / bytesPerVertex;\n\n\t\t\t\tcemu_assert_debug(gsOutPrimType == 0); // currently we only properly handle GS output primitive points\n\n\t\t\t\tsrc->addFmt(\"int sbBase{} = supportBuffer.streamoutBufferBase{}/4 + (gl_PrimitiveIDIn * {})*{};\" _CRLF, i, i, maxVerticesInGS, shaderContext->output->streamoutBufferStride[i] / 4);\n\t\t\t}\n\t\t}\n\n\t}\n\t// code to load inputs from previous stage\n\tif( shader->shaderType == LatteConst::ShaderType::Vertex )\n\t{\n\t\tif( (shaderContext->analyzer.gprUseMask[0/8]&(1<<(0%8))) != 0 )\n\t\t{\n\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t\tsrc->addFmt(\"{} = int4(vid, 0, 0, iid);\" _CRLF, _getRegisterVarName(shaderContext, 0));\n\t\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\tsrc->addFmt(\"{} = float4(vid, 0, 0, iid);\" _CRLF, _getRegisterVarName(shaderContext, 0)); // TODO: as_type<int4>(float4(vid, 0, 0, iid))?\n\t\t\telse\n\t\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\tLatteFetchShader* parsedFetchShader = shaderContext->fetchShader;\n\t\tfor(auto& bufferGroup : parsedFetchShader->bufferGroups)\n\t\t{\n\t\t\tfor(sint32 i=0; i<bufferGroup.attribCount; i++)\n\t\t\t\tLatteDecompiler_emitAttributeImport(shaderContext, bufferGroup.attrib[i]);\n\t\t}\n\t\tfor (auto& bufferGroup : parsedFetchShader->bufferGroupsInvalid)\n\t\t{\n\t\t\t// these attributes point to non-existent buffers\n\t\t\t// todo - figure out how the hardware actually handles this, currently we assume the input values are zero\n\t\t\tfor (sint32 i = 0; i < bufferGroup.attribCount; i++)\n\t\t\t\tLatteDecompiler_emitAttributeImport(shaderContext, bufferGroup.attrib[i]);\n\t\t}\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t{\n\t\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\n\t\tuint32 psControl0 = shaderContext->contextRegisters[mmSPI_PS_IN_CONTROL_0];\n\t\tuint32 psControl1 = shaderContext->contextRegisters[mmSPI_PS_IN_CONTROL_1];\n\n\t\tuint32 spiInterpControl = shaderContext->contextRegisters[mmSPI_INTERP_CONTROL_0];\n\t\tuint8 spriteEnable = (spiInterpControl >> 1) & 1;\n\t\tcemu_assert_debug(spriteEnable == 0);\n\n\t\tuint8 frontFace_enabled = (psControl1 >> 8) & 1;\n\t\tuint8 frontFace_chan = (psControl1 >> 9) & 3;\n\t\tuint8 frontFace_allBits = (psControl1 >> 11) & 1;\n\t\tuint8 frontFace_regIndex = (psControl1 >> 12) & 0x1F;\n\n\t\t// handle param_gen\n\t\tif (psInputTable->paramGen != 0)\n\t\t{\n\t\t\tcemu_assert_debug((psInputTable->paramGen) == 1); // handle the other bits (the same set of coordinates with different perspective/projection settings?)\n\t\t\tuint32 paramGenGPRIndex = psInputTable->paramGenGPR;\n\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\tsrc->addFmt(\"{} = pointCoord.xyxy;\" _CRLF, _getRegisterVarName(shaderContext, paramGenGPRIndex));\n\t\t\telse\n\t\t\t\tsrc->addFmt(\"{} = as_type<int4>(pointCoord.xyxy);\" _CRLF, _getRegisterVarName(shaderContext, paramGenGPRIndex));\n\t\t}\n\n\t\tfor (sint32 i = 0; i < psInputTable->count; i++)\n\t\t{\n\t\t\tuint32 psControl0 = shaderContext->contextRegisters[mmSPI_PS_IN_CONTROL_0];\n\t\t\tuint32 spi0_paramGen = (psControl0 >> 15) & 0xF;\n\n\t\t\tsint32 gprIndex = i;// +spi0_paramGen + paramRegOffset;\n\t\t\tif ((shaderContext->analyzer.gprUseMask[gprIndex / 8] & (1 << (gprIndex % 8))) == 0 && shaderContext->analyzer.usesRelativeGPRRead == false)\n\t\t\t\tcontinue;\n\t\t\tuint32 psInputSemanticId = psInputTable->import[i].semanticId;\n\t\t\tif (psInputSemanticId == LATTE_ANALYZER_IMPORT_INDEX_SPIPOSITION)\n\t\t\t{\n\t\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\t\tsrc->addFmt(\"{} = GET_FRAGCOORD();\" _CRLF, _getRegisterVarName(shaderContext, gprIndex));\n\t\t\t\telse\n\t\t\t\t\tsrc->addFmt(\"{} = as_type<int4>(GET_FRAGCOORD());\" _CRLF, _getRegisterVarName(shaderContext, gprIndex));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t\tsrc->addFmt(\"{} = as_type<int4>(in.passParameterSem{});\" _CRLF, _getRegisterVarName(shaderContext, gprIndex), psInputSemanticId);\n\t\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\tsrc->addFmt(\"{} = in.passParameterSem{};\" _CRLF, _getRegisterVarName(shaderContext, gprIndex), psInputSemanticId);\n\t\t\telse\n\t\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\t// front facing attribute\n\t\tif (frontFace_enabled)\n\t\t{\n\t\t\tif ((shaderContext->analyzer.gprUseMask[0 / 8] & (1 << (0 % 8))) != 0)\n\t\t\t{\n\t\t\t\tif (frontFace_allBits)\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tif (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_SIGNED_INT)\n\t\t\t\t\tsrc->addFmt(\"{}.{} = as_type<int>(frontFacing ? 1.0 : 0.0);\" _CRLF, _getRegisterVarName(shaderContext, frontFace_regIndex), _getElementStrByIndex(frontFace_chan));\n\t\t\t\telse if (shaderContext->typeTracker.defaultDataType == LATTE_DECOMPILER_DTYPE_FLOAT)\n\t\t\t\t\tsrc->addFmt(\"{}.{} = frontFacing ? 1.0 : 0.0;\" _CRLF, _getRegisterVarName(shaderContext, frontFace_regIndex), _getElementStrByIndex(frontFace_chan));\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t}\n\t}\n\tfor(auto& cfInstruction : shaderContext->cfInstructions)\n\t\tLatteDecompiler_emitClauseCodeMSL(shaderContext, &cfInstruction, false);\n\t//if(shader->shaderType == LatteConst::ShaderType::Geometry)\n\t//\tsrc->add(\"EndPrimitive();\" _CRLF);\n\t// vertex shader should write renderstate point size at the end if required but not modified by shader\n\tif (shaderContext->analyzer.outputPointSize && !shaderContext->analyzer.writesPointSize)\n\t{\n\t\tif (shader->shaderType == LatteConst::ShaderType::Vertex && !shaderContext->options->usesGeometryShader && shaderContext->contextRegistersNew->IsRasterizationEnabled())\n\t\t\tsrc->add(\"out.pointSize = supportBuffer.pointSize;\" _CRLF);\n\t}\n\n\tif (usesGeometryShader && (shader->shaderType == LatteConst::ShaderType::Vertex || shader->shaderType == LatteConst::ShaderType::Geometry))\n\t{\n    \tif (shader->shaderType == LatteConst::ShaderType::Vertex)\n    \t{\n    \t    src->add(\"if (tid == 0) {\" _CRLF);\n            src->add(\"meshGridProperties.set_threadgroups_per_grid(uint3(1, 1, 1));\" _CRLF);\n    \t\tsrc->add(\"}\" _CRLF);\n    \t}\n        else if (shader->shaderType == LatteConst::ShaderType::Geometry)\n        {\n            src->add(\"mesh.set_primitive_count(GET_PRIMITIVE_COUNT(vertexIndex));\" _CRLF);\n\n            // Set indices\n            if (shaderContext->contextRegisters[mmVGT_GS_OUT_PRIM_TYPE] == 1) // Line strip\n            {\n                src->add(\"for (uint8_t i = 0; i < GET_PRIMITIVE_COUNT(vertexIndex) * 2; i++) {\" _CRLF);\n                src->add(\"mesh.set_index(i, (i 2 3) + i % 2);\" _CRLF);\n                src->add(\"}\" _CRLF);\n            }\n            else if (shaderContext->contextRegisters[mmVGT_GS_OUT_PRIM_TYPE] == 2) // Triangle strip\n            {\n                src->add(\"for (uint8_t i = 0; i < GET_PRIMITIVE_COUNT(vertexIndex) * 3; i++) {\" _CRLF);\n                src->add(\"mesh.set_index(i, (i / 3) + i % 3);\" _CRLF);\n                src->add(\"}\" _CRLF);\n            }\n            else\n            {\n                src->add(\"for (uint8_t i = 0; i < vertexIndex; i++) {\" _CRLF);\n                src->add(\"mesh.set_index(i, i);\" _CRLF);\n                src->add(\"}\" _CRLF);\n            }\n        }\n\t}\n\n    if (shader->shaderType == LatteConst::ShaderType::Pixel || (shaderContext->contextRegistersNew->IsRasterizationEnabled() && !usesGeometryShader))\n    {\n    \t// Return\n        src->add(\"return out;\" _CRLF);\n    }\n\n\t// end of shader main\n\tsrc->add(\"}\" _CRLF);\n\tsrc->shrink_to_fit();\n\tshader->strBuf_shaderSource = src;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLAttrDecoder.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"util/helpers/StringBuf.h\"\n\n#define _CRLF\t\"\\r\\n\"\n\nstatic void _readLittleEndianAttributeU32x4(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = in.attrDataSem{};\" _CRLF, attributeInputIndex);\n}\n\nstatic void _readLittleEndianAttributeU32x3(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = uint4(in.attrDataSem{}.xyz,0);\" _CRLF, attributeInputIndex);\n}\n\nstatic void _readLittleEndianAttributeU32x2(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = uint4(in.attrDataSem{}.xy,0,0);\" _CRLF, attributeInputIndex);\n}\n\nstatic void _readLittleEndianAttributeU32x1(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = uint4(in.attrDataSem{}.x,0,0,0);\" _CRLF, attributeInputIndex);\n}\n\nstatic void _readLittleEndianAttributeU16x2(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = uint4(in.attrDataSem{}.xy,0,0);\" _CRLF, attributeInputIndex);\n}\n\nstatic void _readLittleEndianAttributeU16x4(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = in.attrDataSem{};\" _CRLF, attributeInputIndex);\n}\n\nstatic void _readBigEndianAttributeU32x4(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder = in.attrDataSem{};\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder = (attrDecoder>>24)|((attrDecoder>>8)&0xFF00)|((attrDecoder<<8)&0xFF0000)|((attrDecoder<<24));\" _CRLF);\n}\n\nstatic void _readBigEndianAttributeU32x3(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.xyz = in.attrDataSem{}.xyz;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder.xyz = (attrDecoder.xyz>>24)|((attrDecoder.xyz>>8)&0xFF00)|((attrDecoder.xyz<<8)&0xFF0000)|((attrDecoder.xyz<<24));\" _CRLF);\n\tsrc->add(\"attrDecoder.w = 0;\" _CRLF);\n}\n\nstatic void _readBigEndianAttributeU32x2(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.xy = in.attrDataSem{}.xy;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder.xy = (attrDecoder.xy>>24)|((attrDecoder.xy>>8)&0xFF00)|((attrDecoder.xy<<8)&0xFF0000)|((attrDecoder.xy<<24));\" _CRLF);\n\tsrc->add(\"attrDecoder.z = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.w = 0;\" _CRLF);\n}\n\nstatic void _readBigEndianAttributeU32x1(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.x = in.attrDataSem{}.x;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder.x = (attrDecoder.x>>24)|((attrDecoder.x>>8)&0xFF00)|((attrDecoder.x<<8)&0xFF0000)|((attrDecoder.x<<24));\" _CRLF);\n\tsrc->add(\"attrDecoder.y = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.z = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.w = 0;\" _CRLF);\n}\n\nstatic void _readBigEndianAttributeU16x1(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.xy = in.attrDataSem{}.xy;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder.x = ((attrDecoder.x>>8)&0xFF)|((attrDecoder.x<<8)&0xFF00);\" _CRLF);\n\tsrc->add(\"attrDecoder.y = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.z = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.w = 0;\" _CRLF);\n}\n\nstatic void _readBigEndianAttributeU16x2(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.xy = in.attrDataSem{}.xy;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder.xy = ((attrDecoder.xy>>8)&0xFF)|((attrDecoder.xy<<8)&0xFF00);\" _CRLF);\n\tsrc->add(\"attrDecoder.z = 0;\" _CRLF);\n\tsrc->add(\"attrDecoder.w = 0;\" _CRLF);\n}\n\nstatic void _readBigEndianAttributeU16x4(LatteDecompilerShader* shaderContext, StringBuf* src, uint32 attributeInputIndex)\n{\n\tsrc->addFmt(\"attrDecoder.xyzw = in.attrDataSem{}.xyzw;\" _CRLF, attributeInputIndex);\n\tsrc->add(\"attrDecoder = ((attrDecoder>>8)&0xFF)|((attrDecoder<<8)&0xFF00);\" _CRLF);\n}\n\nvoid LatteDecompiler_emitAttributeDecodeMSL(LatteDecompilerShader* shaderContext, StringBuf* src, LatteParsedFetchShaderAttribute_t* attrib)\n{\n\tif (attrib->attributeBufferIndex >= Latte::GPU_LIMITS::NUM_VERTEX_BUFFERS)\n\t{\n\t\tsrc->add(\"attrDecoder = int4(0);\" _CRLF);\n\t\treturn;\n\t}\n\n\tuint32 attributeInputIndex = attrib->semanticId;\n\tif( attrib->endianSwap == LatteConst::VertexFetchEndianMode::SWAP_U32 )\n\t{\n\t\tif( attrib->format == FMT_32_32_32_32_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x4(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_32_32_32_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x3(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_32_32_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x2(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_32_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_2_10_10_10 && attrib->nfa == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t\t// Bayonetta 2 uses this format to store normals\n\t\t\tsrc->add(\"attrDecoder.xyzw = uint4((attrDecoder.x>>0)&0x3FF,(attrDecoder.x>>10)&0x3FF,(attrDecoder.x>>20)&0x3FF,(attrDecoder.x>>30)&0x3);\" _CRLF);\n\t\t\tif (attrib->isSigned != 0)\n\t\t\t{\n\t\t\t\tsrc->add(\"if( (attrDecoder.x&0x200) != 0 ) attrDecoder.x |= 0xFFFFFC00;\" _CRLF);\n\t\t\t\tsrc->add(\"if( (attrDecoder.y&0x200) != 0 ) attrDecoder.y |= 0xFFFFFC00;\" _CRLF);\n\t\t\t\tsrc->add(\"if( (attrDecoder.z&0x200) != 0 ) attrDecoder.z |= 0xFFFFFC00;\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/511.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/511.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.z = as_type<uint>(max(float(int(attrDecoder.z))/511.0,-1.0));\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/1023.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/1023.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.z = as_type<uint>(max(float(int(attrDecoder.z))/1023.0,-1.0));\" _CRLF);\n\t\t\t}\n\t\t\tsrc->add(\"attrDecoder.w = as_type<uint>(float(attrDecoder.w));\" _CRLF); // unsure?\n\n\t\t}\n\t\telse if( attrib->format == FMT_32_32_32_32 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x4(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_32_32_32 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x3(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_32_32 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU32x2(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_32 && attrib->nfa == 1 && attrib->isSigned == 0)\n\t\t{\n\t\t\t_readBigEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_32 && attrib->nfa == 1 && attrib->isSigned == 1)\n\t\t{\n\t\t\t// we can just read the signed s32 as a u32 since no sign-extension is necessary\n\t\t\t_readBigEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 0 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t// seen in Minecraft Wii U Edition\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = as_type<uint4>(float4(in.attrDataSem{}.wzyx)/255.0);\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 0 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t// seen in Minecraft Wii U Edition\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = in.attrDataSem{}.wzyx;\" _CRLF, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x80) != 0 ) attrDecoder.x |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x80) != 0 ) attrDecoder.y |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x80) != 0 ) attrDecoder.z |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x80) != 0 ) attrDecoder.w |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/127.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/127.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = as_type<uint>(max(float(int(attrDecoder.z))/127.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = as_type<uint>(max(float(int(attrDecoder.w))/127.0,-1.0));\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t// seen in Minecraft Wii U Edition\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = in.attrDataSem{}.wzyx;\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_8_8_8_8 && attrib->nfa == 2 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in Ben 10 Omniverse\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = as_type<uint4>(float4(in.attrDataSem{}.wzyx));\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"_emitAttributeDecode(): Unsupported fmt {:02x} nfa {} signed {} endian {}\\n\", attrib->format, attrib->nfa, attrib->isSigned, attrib->endianSwap);\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\telse if( attrib->endianSwap == LatteConst::VertexFetchEndianMode::SWAP_NONE )\n\t{\n\t\tif( attrib->format == FMT_32_32_32_32_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readLittleEndianAttributeU32x4(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_32_32_32_FLOAT && attrib->nfa == 2)\n\t\t{\n\t\t\t_readLittleEndianAttributeU32x3(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_32_32_FLOAT && attrib->nfa == 2)\n\t\t{\n\t\t\t// seen in Cities of Gold\n\t\t\t_readLittleEndianAttributeU32x2(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_32 && attrib->nfa == 1 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in Nano Assault Neo\n\t\t\t_readLittleEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_2_10_10_10 && attrib->nfa == 0 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in Fast Racing Neo\n\t\t\t_readLittleEndianAttributeU32x1(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xyzw = uint4((attrDecoder.x>>0)&0x3FF,(attrDecoder.x>>10)&0x3FF,(attrDecoder.x>>20)&0x3FF,(attrDecoder.x>>30)&0x3);\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/1023.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/1023.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = as_type<uint>(max(float(int(attrDecoder.z))/1023.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = as_type<uint>(float(attrDecoder.w));\" _CRLF); // todo - is this correct?\n\t\t}\n\t\telse if (attrib->format == FMT_16_16_16_16 && attrib->nfa == 0 && attrib->isSigned != 0)\n\t\t{\n\t\t\t// seen in CoD ghosts\n\t\t\t_readLittleEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x8000) != 0 ) attrDecoder.z |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x8000) != 0 ) attrDecoder.w |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = as_type<uint>(max(float(int(attrDecoder.z))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = as_type<uint>(max(float(int(attrDecoder.w))/32767.0,-1.0));\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16_16_16 && attrib->nfa == 2 && attrib->isSigned == 1 )\n\t\t{\n\t\t\t// seen in Rabbids Land\n\t\t\t_readLittleEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x8000) != 0 ) attrDecoder.z |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x8000) != 0 ) attrDecoder.w |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.xyzw = as_type<uint4>(float4(int4(attrDecoder)));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16_16_16_16_FLOAT && attrib->nfa == 2)\n\t\t{\n\t\t\t// seen in Giana Sisters: Twisted Dreams\n\t\t\t_readLittleEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\t// TODO: uint4?\n\t\t\tsrc->add(\"attrDecoder.xyzw = as_type<uint4>(float4(float2(as_type<half2>(attrDecoder.x|(attrDecoder.y<<16))),float2(as_type<half2>(attrDecoder.z|(attrDecoder.w<<16)))));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16_16 && attrib->nfa == 0 && attrib->isSigned != 0)\n\t\t{\n\t\t\t// seen in Nano Assault Neo\n\t\t\t_readLittleEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/32767.0,-1.0));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16_16_FLOAT && attrib->nfa == 2)\n\t\t{\n\t\t\t// seen in Giana Sisters: Twisted Dreams\n\t\t\t_readLittleEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xy = as_type<uint2>(float2(as_type<half2>(attrDecoder.x|(attrDecoder.y<<16))));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 0 && attrib->isSigned == 0 )\n\t\t{\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = as_type<uint4>(float4(in.attrDataSem{}.xyzw)/255.0);\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 0 && attrib->isSigned != 0 )\n\t\t{\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = in.attrDataSem{}.xyzw;\" _CRLF, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x80) != 0 ) attrDecoder.x |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x80) != 0 ) attrDecoder.y |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x80) != 0 ) attrDecoder.z |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x80) != 0 ) attrDecoder.w |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/127.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/127.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = as_type<uint>(max(float(int(attrDecoder.z))/127.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = as_type<uint>(max(float(int(attrDecoder.w))/127.0,-1.0));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_8_8_8_8 && attrib->nfa == 1 && attrib->isSigned == 0)\n\t\t{\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = in.attrDataSem{}.xyzw;\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_8_8_8_8 && attrib->nfa == 1 && attrib->isSigned != 0)\n\t\t{\n\t\t\t// seen in Sonic Lost World\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = in.attrDataSem{}.xyzw;\" _CRLF, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x80) != 0 ) attrDecoder.x |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x80) != 0 ) attrDecoder.y |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x80) != 0 ) attrDecoder.z |= 0xFFFFFF00;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x80) != 0 ) attrDecoder.w |= 0xFFFFFF00;\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_8_8_8_8 && attrib->nfa == 2 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t// seen in One Piece\n\t\t\t// TODO: uint4?\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = as_type<uint4>(float4(in.attrDataSem{}.xyzw));\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_8_8 && attrib->nfa == 0 && attrib->isSigned == 0)\n\t\t{\n\t\t\tif( (attrib->offset&3) == 2 && LatteGPUState.glVendor == GLVENDOR_AMD && g_renderer->GetType() == RendererAPI::OpenGL )\n\t\t\t{\n\t\t\t\t// AMD workaround\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = as_type<uint2>(float2(in.attrDataSem{}.zw)/255.0);\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = as_type<uint2>(float2(in.attrDataSem{}.xy)/255.0);\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (attrib->format == FMT_8_8 && attrib->nfa == 2 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in BotW\n\t\t\tif ((attrib->offset & 3) == 2 && LatteGPUState.glVendor == GLVENDOR_AMD && g_renderer->GetType() == RendererAPI::OpenGL)\n\t\t\t{\n\t\t\t\t// AMD workaround\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = as_type<uint2>(float2(in.attrDataSem{}.zw));\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = as_type<uint2>(float2(in.attrDataSem{}.xy));\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (attrib->format == FMT_8_8 && attrib->nfa == 0 && attrib->isSigned != 0)\n\t\t{\n\t\t\tif ((attrib->offset & 3) == 2 && LatteGPUState.glVendor == GLVENDOR_AMD && g_renderer->GetType() == RendererAPI::OpenGL)\n\t\t\t{\n\t\t\t\t// AMD workaround\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = in.attrDataSem{}.zw;\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"if( (attrDecoder.x&0x80) != 0 ) attrDecoder.x |= 0xFFFFFF00;\" _CRLF);\n\t\t\t\tsrc->add(\"if( (attrDecoder.y&0x80) != 0 ) attrDecoder.y |= 0xFFFFFF00;\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/127.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/127.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"attrDecoder.xy = in.attrDataSem{}.xy;\" _CRLF, attributeInputIndex);\n\t\t\t\tsrc->add(\"if( (attrDecoder.x&0x80) != 0 ) attrDecoder.x |= 0xFFFFFF00;\" _CRLF);\n\t\t\t\tsrc->add(\"if( (attrDecoder.y&0x80) != 0 ) attrDecoder.y |= 0xFFFFFF00;\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/127.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/127.0,-1.0));\" _CRLF);\n\t\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (attrib->format == FMT_8_8 && attrib->nfa == 1 && attrib->isSigned == 0)\n\t\t{\n\t\t\tif ((attrib->offset & 3) == 2 && LatteGPUState.glVendor == GLVENDOR_AMD && g_renderer->GetType() == RendererAPI::OpenGL)\n\t\t\t{\n\t\t\t\t// AMD workaround\n\t\t\t\tsrc->addFmt(\"attrDecoder.xyzw = uint4(in.attrDataSem{}.zw,0,0);\" _CRLF, attributeInputIndex);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsrc->addFmt(\"attrDecoder.xyzw = uint4(in.attrDataSem{}.xy,0,0);\" _CRLF, attributeInputIndex);\n\t\t\t}\n\t\t}\n\t\telse if( attrib->format == FMT_8 && attrib->nfa == 0 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t// seen in Pikmin 3\n\t\t\tsrc->addFmt(\"attrDecoder.x = as_type<uint>(float(in.attrDataSem{}.x)/255.0);\" _CRLF, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.yzw = uint3(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_8 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\tsrc->addFmt(\"attrDecoder.xyzw = uint4(in.attrDataSem{}.x,0,0,0);\" _CRLF, attributeInputIndex);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"_emitAttributeDecode(): Unsupported fmt {:02x} nfa {} signed {} endian {}\\n\", attrib->format, attrib->nfa, attrib->isSigned, attrib->endianSwap);\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\telse if( attrib->endianSwap == LatteConst::VertexFetchEndianMode::SWAP_U16 )\n\t{\n\t\tif( attrib->format == FMT_16_16_16_16_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\t// TODO: uint4?\n\t\t\tsrc->add(\"attrDecoder.xyzw = as_type<uint4>(float4(float2(as_type<half2>(attrDecoder.x|(attrDecoder.y<<16))),float2(as_type<half2>(attrDecoder.z|(attrDecoder.w<<16)))));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16_16_16_16 && attrib->nfa == 0 && attrib->isSigned != 0)\n\t\t{\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x8000) != 0 ) attrDecoder.z |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x8000) != 0 ) attrDecoder.w |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = as_type<uint>(max(float(int(attrDecoder.z))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = as_type<uint>(max(float(int(attrDecoder.w))/32767.0,-1.0));\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16_16_16_16 && attrib->nfa == 0 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in BotW\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(float(int(attrDecoder.x))/65535.0);\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(float(int(attrDecoder.y))/65535.0);\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = as_type<uint>(float(int(attrDecoder.z))/65535.0);\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = as_type<uint>(float(int(attrDecoder.w))/65535.0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16_16_16 && attrib->nfa == 2 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t// seen in Minecraft Wii U Edition\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x8000) != 0 ) attrDecoder.z |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x8000) != 0 ) attrDecoder.w |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(float(int(attrDecoder.x)));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(float(int(attrDecoder.y)));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.z = as_type<uint>(float(int(attrDecoder.z)));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.w = as_type<uint>(float(int(attrDecoder.w)));\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16_16_16 && attrib->nfa == 1 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t// seen in Minecraft Wii U Edition\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.z&0x8000) != 0 ) attrDecoder.z |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.w&0x8000) != 0 ) attrDecoder.w |= 0xFFFF0000;\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16_16_16 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x4(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16_FLOAT && attrib->nfa == 2 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xy = as_type<uint2>(float2(as_type<half2>(attrDecoder.x|(attrDecoder.y<<16))));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 0 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xy = as_type<uint2>(float2(float(attrDecoder.x), float(attrDecoder.y))/65535.0);\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 0 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(max(float(int(attrDecoder.x))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.y = as_type<uint>(max(float(int(attrDecoder.y))/32767.0,-1.0));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 1 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 1 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 2 && attrib->isSigned == 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.xy = as_type<uint2>(float2(float(attrDecoder.x), float(attrDecoder.y)));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t}\n\t\telse if( attrib->format == FMT_16_16 && attrib->nfa == 2 && attrib->isSigned != 0 )\n\t\t{\n\t\t\t_readBigEndianAttributeU16x2(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"if( (attrDecoder.x&0x8000) != 0 ) attrDecoder.x |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"if( (attrDecoder.y&0x8000) != 0 ) attrDecoder.y |= 0xFFFF0000;\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.xy = as_type<uint2>(float2(float(int(attrDecoder.x)), float(int(attrDecoder.y))));\" _CRLF);\n\t\t\tsrc->add(\"attrDecoder.zw = uint2(0);\" _CRLF);\n\t\t}\n\t\telse if (attrib->format == FMT_16 && attrib->nfa == 1 && attrib->isSigned == 0)\n\t\t{\n\t\t\t_readBigEndianAttributeU16x1(shaderContext, src, attributeInputIndex);\n\t\t}\n\t\telse if (attrib->format == FMT_16 && attrib->nfa == 0 && attrib->isSigned == 0)\n\t\t{\n\t\t\t// seen in CoD ghosts\n\t\t\t_readBigEndianAttributeU16x1(shaderContext, src, attributeInputIndex);\n\t\t\tsrc->add(\"attrDecoder.x = as_type<uint>(float(int(attrDecoder.x))/65535.0);\" _CRLF);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"_emitAttributeDecode(): Unsupported fmt {:02x} nfa {} signed {} endian {}\", attrib->format, attrib->nfa, attrib->isSigned, attrib->endianSwap);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitMSLHeader.hpp",
    "content": "#pragma once\n\n#include \"Common/precompiled.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n\nnamespace LatteDecompiler\n{\n\tstatic void _emitUniformVariables(LatteDecompilerShaderContext* decompilerContext, bool usesGeometryShader)\n\t{\n\t    auto src = decompilerContext->shaderSource;\n\n\t\tauto& uniformOffsets = decompilerContext->output->uniformOffsetsVK;\n\n\t\tsrc->add(\"struct SupportBuffer {\" _CRLF);\n\n\t\tuint32 uniformCurrentOffset = 0;\n\t\tauto shader = decompilerContext->shader;\n\t\tauto shaderType = decompilerContext->shader->shaderType;\n\t\tif (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED)\n\t\t{\n\t\t\t// uniform registers or buffers are accessed statically with predictable offsets\n\t\t\t// this allows us to remap the used entries into a more compact array\n\t\t\tsrc->addFmt(\"int4 remapped[{}];\" _CRLF, (sint32)shader->list_remappedUniformEntries.size());\n\t\t\tuniformOffsets.offset_remapped = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 16 * shader->list_remappedUniformEntries.size();\n\t\t}\n\t\telse if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE)\n\t\t{\n\t\t\tuint32 cfileSize = decompilerContext->analyzer.uniformRegisterAccessTracker.DetermineSize(decompilerContext->shaderBaseHash, 256);\n\t\t\t// full or partial uniform register file has to be present\n\t\t\tsrc->addFmt(\"int4 uniformRegister[{}];\" _CRLF, cfileSize);\n\t\t\tuniformOffsets.offset_uniformRegister = uniformCurrentOffset;\n\t\t\tuniformOffsets.count_uniformRegister = cfileSize;\n\t\t\tuniformCurrentOffset += 16 * cfileSize;\n\t\t}\n\t\t// special uniforms\n\t\tbool hasAnyViewportScaleDisabled =\n\t\t\t!decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_X_SCALE_ENA() ||\n\t\t\t!decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Y_SCALE_ENA() ||\n\t\t\t!decompilerContext->contextRegistersNew->PA_CL_VTE_CNTL.get_VPORT_Z_SCALE_ENA();\n\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && hasAnyViewportScaleDisabled)\n\t\t{\n\t\t\t// aka GX2 special state 0\n\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 7)&~7;\n\t\t\tsrc->add(\"float2 windowSpaceToClipSpaceTransform;\" _CRLF);\n\t\t\tuniformOffsets.offset_windowSpaceToClipSpaceTransform = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 8;\n\t\t}\n\t\tbool alphaTestEnable = decompilerContext->contextRegistersNew->SX_ALPHA_TEST_CONTROL.get_ALPHA_TEST_ENABLE();\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Pixel && alphaTestEnable)\n\t\t{\n\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 3)&~3;\n\t\t\tsrc->add(\"float alphaTestRef;\" _CRLF);\n\t\t\tuniformOffsets.offset_alphaTestRef = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 4;\n\t\t}\n\t\tif (decompilerContext->analyzer.outputPointSize && decompilerContext->analyzer.writesPointSize == false)\n\t\t{\n\t\t\tif ((decompilerContext->shaderType == LatteConst::ShaderType::Vertex && !decompilerContext->options->usesGeometryShader) ||\n\t\t\t\tdecompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n\t\t\t{\n\t\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 3)&~3;\n\t\t\t\tsrc->add(\"float pointSize;\" _CRLF);\n\t\t\t\tuniformOffsets.offset_pointSize = uniformCurrentOffset;\n\t\t\t\tuniformCurrentOffset += 4;\n\t\t\t}\n\t\t}\n\t\t// define fragCoordScale which holds the xy scale for render target resolution vs effective resolution\n\t\tif (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t\t{\n\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 7)&~7;\n\t\t\tsrc->add(\"float2 fragCoordScale;\" _CRLF);\n\t\t\tuniformOffsets.offset_fragCoordScale = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 8;\n\t\t}\n\t\t// provide scale factor for every texture that is accessed via texel coordinates (texelFetch)\n\t\tfor (sint32 t = 0; t < LATTE_NUM_MAX_TEX_UNITS; t++)\n\t\t{\n\t\t\tif (decompilerContext->analyzer.texUnitUsesTexelCoordinates.test(t) == false)\n\t\t\t\tcontinue;\n\t\t\tuniformCurrentOffset = (uniformCurrentOffset + 7) & ~7;\n\t\t\tsrc->addFmt(\"float2 tex{}Scale;\" _CRLF, t);\n\t\t\tuniformOffsets.offset_texScale[t] = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 8;\n\t\t}\n\t\t// define verticesPerInstance + streamoutBufferBaseX\n\t\tif ((shader->shaderType == LatteConst::ShaderType::Vertex &&\n\t\t    usesGeometryShader) ||\n\t        (decompilerContext->analyzer.useSSBOForStreamout &&\n\t\t\t(shader->shaderType == LatteConst::ShaderType::Vertex && !decompilerContext->options->usesGeometryShader) ||\n\t\t\t(shader->shaderType == LatteConst::ShaderType::Geometry)))\n\t\t{\n\t\t\tsrc->add(\"int verticesPerInstance;\" _CRLF);\n\t\t\tuniformOffsets.offset_verticesPerInstance = uniformCurrentOffset;\n\t\t\tuniformCurrentOffset += 4;\n\t\t\tfor (uint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t\t{\n\t\t\t\tif (decompilerContext->output->streamoutBufferWriteMask[i])\n\t\t\t\t{\n\t\t\t\t\tsrc->addFmt(\"int streamoutBufferBase{};\" _CRLF, i);\n\t\t\t\t\tuniformOffsets.offset_streamoutBufferBase[i] = uniformCurrentOffset;\n\t\t\t\t\tuniformCurrentOffset += 4;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsrc->add(\"};\" _CRLF _CRLF);\n\n\t\tuniformOffsets.offset_endOfBlock = uniformCurrentOffset;\n\t}\n\n\tstatic void _emitUniformBuffers(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\tauto shaderSrc = decompilerContext->shaderSource;\n\t\t// uniform buffer definition\n\t\tif (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)\n\t\t{\n\t\t\tfor (uint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t\t\t{\n\t\t\t\tif (!decompilerContext->analyzer.uniformBufferAccessTracker[i].HasAccess())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tcemu_assert_debug(decompilerContext->output->resourceMappingMTL.uniformBuffersBindingPoint[i] >= 0);\n\n\t\t\t\tshaderSrc->addFmt(\"struct UBuff{} {{\" _CRLF, i);\n\t\t\t\tshaderSrc->addFmt(\"float4 d[{}];\" _CRLF, decompilerContext->analyzer.uniformBufferAccessTracker[i].DetermineSize(decompilerContext->shaderBaseHash, LATTE_GLSL_DYNAMIC_UNIFORM_BLOCK_SIZE));\n\t\t\t\tshaderSrc->add(\"};\" _CRLF _CRLF);\n\t\t\t}\n\t\t}\n\t\telse if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED)\n\t\t{\n\t\t\t// already generated in _emitUniformVariables\n\t\t}\n\t\telse if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE)\n\t\t{\n\t\t\t// already generated in _emitUniformVariables\n\t\t}\n\t\telse if (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_NONE)\n\t\t{\n\t\t\t// no uniforms used\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\n\tstatic void _emitAttributes(LatteDecompilerShaderContext* decompilerContext, bool fetchVertexManually)\n\t{\n\t\tauto src = decompilerContext->shaderSource;\n\t\tstd::string attributeNames;\n\n\t\tif (decompilerContext->shader->shaderType == LatteConst::ShaderType::Vertex)\n\t\t{\n\t\t    src->add(\"struct VertexIn {\" _CRLF);\n\t\t\t// attribute inputs\n\t\t\tfor (uint32 i = 0; i < LATTE_NUM_MAX_ATTRIBUTE_LOCATIONS; i++)\n\t\t\t{\n\t\t\t\tif (decompilerContext->analyzer.inputAttributSemanticMask[i])\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(decompilerContext->output->resourceMappingMTL.attributeMapping[i] >= 0);\n\n\t\t\t\t\tsrc->addFmt(\"uint4 attrDataSem{}\", i);\n\t\t\t\t\tif (fetchVertexManually)\n\t\t\t\t\t    attributeNames += \"#define ATTRIBUTE_NAME\" + std::to_string((sint32)decompilerContext->output->resourceMappingMTL.attributeMapping[i]) + \" attrDataSem\" + std::to_string(i) + \"\\n\";\n\t\t\t\t\telse\n\t\t\t\t\t    src->addFmt(\" [[attribute({})]]\", (sint32)decompilerContext->output->resourceMappingMTL.attributeMapping[i]);\n\t\t\t\t\tsrc->add(\";\" _CRLF);\n\t\t\t\t}\n\t\t\t}\n\t\t\tsrc->add(\"};\" _CRLF _CRLF);\n\t\t}\n\t\tsrc->addFmt(\"{}\", attributeNames);\n\t}\n\n\tstatic void _emitVSOutputs(LatteDecompilerShaderContext* shaderContext, bool isRectVertexShader)\n\t{\n\t\tauto* src = shaderContext->shaderSource;\n\n\t\tsrc->add(\"struct VertexOut {\" _CRLF);\n\t\tsrc->add(\"float4 position [[position]] [[invariant]];\" _CRLF);\n\t\tif (shaderContext->analyzer.outputPointSize)\n\t\t    src->add(\"float pointSize [[point_size]];\" _CRLF);\n\n\t\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\t\tauto parameterMask = shaderContext->shader->outputParameterMask;\n\t\tbool psInputsWritten[GPU7_PS_MAX_INPUTS] = {false};\n\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t{\n\t\t\tif ((parameterMask&(1 << i)) == 0)\n\t\t\t\tcontinue;\n\t\t\tuint32 vsSemanticId = _getVertexShaderOutParamSemanticId(shaderContext->contextRegisters, i);\n\t\t\tif (vsSemanticId > LATTE_ANALYZER_IMPORT_INDEX_PARAM_MAX)\n\t\t\t\tcontinue;\n\t\t\t// get import based on semanticId\n\t\t\tsint32 psInputIndex = -1;\n\t\t\tfor (sint32 f = 0; f < psInputTable->count; f++)\n\t\t\t{\n\t\t\t\tif (psInputTable->import[f].semanticId == vsSemanticId)\n\t\t\t\t{\n\t\t\t\t\tpsInputIndex = f;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (psInputIndex == -1)\n\t\t\t\tcontinue; // no ps input\n\n\t\t\tpsInputsWritten[psInputIndex] = true;\n\n\t\t\tsrc->addFmt(\"float4 passParameterSem{}\", psInputTable->import[psInputIndex].semanticId);\n\t\t\tif (!isRectVertexShader)\n\t\t\t{\n     \t\t\tsrc->addFmt(\" [[user(locn{})]]\", psInputIndex);\n     \t\t\tif (psInputTable->import[psInputIndex].isFlat)\n    \t\t\t\tsrc->add(\" [[flat]]\");\n     \t\t\tif (psInputTable->import[psInputIndex].isNoPerspective)\n    \t\t\t\tsrc->add(\" [[center_no_perspective]]\");\n\t\t\t}\n\t\t\tsrc->addFmt(\";\" _CRLF);\n\t\t}\n\n\t\t// TODO: handle this in the fragment shader instead?\n\t\t// Declare all PS inputs that are not written by the VS\n\t\tfor (uint32 i = 0; i < psInputTable->count; i++)\n\t\t{\n\t\t    if (psInputsWritten[i])\n\t\t\t\tcontinue;\n\n\t\t\tif (psInputTable->import[i].semanticId > LATTE_ANALYZER_IMPORT_INDEX_PARAM_MAX)\n\t\t\t\tcontinue;\n\n\t\t\tsrc->addFmt(\"float4 unknown{} [[user(locn{})]];\" _CRLF, psInputTable->import[i].semanticId, i);\n\t\t}\n\n\t\tsrc->add(\"};\" _CRLF _CRLF);\n\n\t\tif (isRectVertexShader)\n\t\t{\n\t\t    src->add(\"struct ObjectPayload {\" _CRLF);\n            src->add(\"VertexOut vertexOut[VERTICES_PER_VERTEX_PRIMITIVE];\" _CRLF);\n            src->add(\"};\" _CRLF _CRLF);\n\t\t}\n\t}\n\n\tstatic void _emitPSInputs(LatteDecompilerShaderContext* shaderContext)\n\t{\n\t\tauto* src = shaderContext->shaderSource;\n\n\t\tsrc->add(\"#define GET_FRAGCOORD() float4(in.position.xy * supportBuffer.fragCoordScale.xy, in.position.z, 1.0 / in.position.w)\" _CRLF);\n\n\t\tsrc->add(\"struct FragmentIn {\" _CRLF);\n\t\tsrc->add(\"float4 position [[position]];\" _CRLF);\n\n\t\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\t\tfor (sint32 i = 0; i < psInputTable->count; i++)\n\t\t{\n\t\t\tif (psInputTable->import[i].semanticId > LATTE_ANALYZER_IMPORT_INDEX_PARAM_MAX)\n\t\t\t\tcontinue;\n\t\t\tsrc->addFmt(\"float4 passParameterSem{}\", psInputTable->import[i].semanticId);\n\t\t\tsrc->addFmt(\" [[user(locn{})]]\", i);\n\t\t\tif (psInputTable->import[i].isFlat)\n\t\t\t\tsrc->add(\" [[flat]]\");\n\t\t\tif (psInputTable->import[i].isNoPerspective)\n\t\t\t\tsrc->add(\" [[center_no_perspective]]\");\n\t\t\tsrc->add(\";\" _CRLF);\n\t\t}\n\n\t\tsrc->add(\"};\" _CRLF _CRLF);\n\t}\n\n\tstatic void _emitInputsAndOutputs(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool usesGeometryShader, bool fetchVertexManually)\n\t{\n\t\tauto src = decompilerContext->shaderSource;\n\n\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex)\n\t\t{\n\t\t    _emitAttributes(decompilerContext, fetchVertexManually);\n\t\t}\n\t\telse if (decompilerContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t{\n\t\t    _emitPSInputs(decompilerContext);\n\n\t\t\tsrc->add(\"struct FragmentOut {\" _CRLF);\n\n            // generate pixel outputs for pixel shader\n            for (uint32 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)\n            {\n               \tif ((decompilerContext->shader->pixelColorOutputMask & (1 << i)) != 0)\n               \t{\n                    auto dataType = GetColorBufferDataType(i, *decompilerContext->contextRegistersNew);\n                    if (dataType != MetalDataType::NONE)\n                    {\n              \t\t    src->addFmt(\"{} passPixelColor{} [[color({})]];\" _CRLF, GetDataTypeStr(dataType), i, i);\n                    }\n               \t}\n            }\n\n            // generate depth output for pixel shader\n            if (decompilerContext->shader->depthMask)\n                src->add(\"float passDepth [[depth(any)]];\" _CRLF);\n\n            src->add(\"};\" _CRLF _CRLF);\n\t\t}\n\n\t\tif (!usesGeometryShader || isRectVertexShader)\n\t\t{\n    \t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex && decompilerContext->contextRegistersNew->IsRasterizationEnabled())\n    \t\t\t_emitVSOutputs(decompilerContext, isRectVertexShader);\n\t\t}\n\t\telse\n\t\t{\n            if (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n    \t\t{\n                src->add(\"struct VertexOut {\" _CRLF);\n    \t\t\tuint32 ringParameterCountVS2GS = 0;\n    \t\t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Vertex)\n    \t\t\t{\n    \t\t\t\tringParameterCountVS2GS = decompilerContext->shader->ringParameterCount;\n    \t\t\t}\n    \t\t\telse\n    \t\t\t{\n    \t\t\t\tringParameterCountVS2GS = decompilerContext->shader->ringParameterCountFromPrevStage;\n    \t\t\t}\n    \t\t\tfor (uint32 f = 0; f < ringParameterCountVS2GS; f++)\n    \t\t\t\tsrc->addFmt(\"int4 passParameterSem{};\" _CRLF, f);\n    \t\t\tsrc->add(\"};\" _CRLF _CRLF);\n                src->add(\"struct ObjectPayload {\" _CRLF);\n                src->add(\"VertexOut vertexOut[VERTICES_PER_VERTEX_PRIMITIVE];\" _CRLF);\n                src->add(\"};\" _CRLF _CRLF);\n    \t\t}\n    \t\tif (decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n    \t\t{\n    \t\t\t// parameters shared between geometry and pixel shader\n    \t\t\tuint32 ringItemSize = decompilerContext->contextRegisters[mmSQ_GSVS_RING_ITEMSIZE] & 0x7FFF;\n    \t\t\tif ((ringItemSize & 0xF) != 0)\n    \t\t\t\tdebugBreakpoint();\n    \t\t\tif (((decompilerContext->contextRegisters[mmSQ_GSVS_RING_ITEMSIZE] & 0x7FFF) & 0xF) != 0)\n    \t\t\t\tdebugBreakpoint();\n\n                src->add(\"struct GeometryOut {\" _CRLF);\n                src->add(\"float4 position [[position]];\" _CRLF);\n    \t\t\tfor (sint32 p = 0; p < decompilerContext->parsedGSCopyShader->numParam; p++)\n    \t\t\t{\n    \t\t\t\tif (decompilerContext->parsedGSCopyShader->paramMapping[p].exportType != 2)\n    \t\t\t\t\tcontinue;\n    \t\t\t\tsrc->addFmt(\"float4 passParameterSem{} [[user(locn{})]];\" _CRLF, (sint32)decompilerContext->parsedGSCopyShader->paramMapping[p].exportParam, decompilerContext->parsedGSCopyShader->paramMapping[p].exportParam & 0x7F);\n    \t\t\t}\n                src->add(\"};\" _CRLF _CRLF);\n\n                const uint32 MAX_VERTEX_COUNT = 32;\n\n                // Define the mesh shader output type\n                src->addFmt(\"using MeshType = mesh<GeometryOut, void, {}, GET_PRIMITIVE_COUNT({}), topology::MTL_PRIMITIVE_TYPE>;\" _CRLF, MAX_VERTEX_COUNT, MAX_VERTEX_COUNT);\n    \t\t}\n\t\t}\n\t}\n\n\tstatic void emitHeader(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool usesGeometryShader, bool fetchVertexManually)\n\t{\n\t    auto src = decompilerContext->shaderSource;\n\n        if (usesGeometryShader && (decompilerContext->shaderType == LatteConst::ShaderType::Vertex || decompilerContext->shaderType == LatteConst::ShaderType::Geometry))\n        {\n            LattePrimitiveMode vsOutPrimType = decompilerContext->contextRegistersNew->VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();\n            src->addFmt(\"#define VERTICES_PER_VERTEX_PRIMITIVE {}\" _CRLF, GetVerticesPerPrimitive(vsOutPrimType));\n\n            uint32 gsOutPrimType = decompilerContext->contextRegisters[mmVGT_GS_OUT_PRIM_TYPE];\n            if (decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n            {\n                switch (gsOutPrimType)\n                {\n                case 0: // Point\n                    src->add(\"#define MTL_PRIMITIVE_TYPE point\" _CRLF);\n                   \tsrc->add(\"#define GET_PRIMITIVE_COUNT(vertexCount) (vertexCount / 1)\" _CRLF);\n                    break;\n                case 1: // Line strip\n                    src->add(\"#define MTL_PRIMITIVE_TYPE line\" _CRLF);\n                   \tsrc->add(\"#define GET_PRIMITIVE_COUNT(vertexCount) (vertexCount - 1)\" _CRLF);\n                    break;\n                case 2: // Triangle strip\n                    src->add(\"#define MTL_PRIMITIVE_TYPE triangle\" _CRLF);\n                   \tsrc->add(\"#define GET_PRIMITIVE_COUNT(vertexCount) (vertexCount - 2)\" _CRLF);\n                    break;\n                default:\n                    cemuLog_log(LogType::Force, \"Unknown geometry out primitive type {}\", gsOutPrimType);\n                    break;\n                }\n            }\n        }\n\n        if (decompilerContext->contextRegistersNew->PA_CL_CLIP_CNTL.get_DX_CLIP_SPACE_DEF())\n\t\t\tsrc->add(\"#define SET_POSITION(_v) out.position = _v\" _CRLF);\n\t\telse\n\t\t\tsrc->add(\"#define SET_POSITION(_v) out.position = _v; out.position.z = (out.position.z + out.position.w) / 2.0\" _CRLF);\n\n\t\tconst bool dump_shaders_enabled = ActiveSettings::DumpShadersEnabled();\n\t\tif(dump_shaders_enabled)\n\t\t\tdecompilerContext->shaderSource->add(\"// start of shader inputs/outputs, predetermined by Cemu. Do not touch\" _CRLF);\n\t\t// uniform variables\n\t\t_emitUniformVariables(decompilerContext, usesGeometryShader);\n\t\t// uniform buffers\n\t\t_emitUniformBuffers(decompilerContext);\n\t\t// inputs and outputs\n\t\t_emitInputsAndOutputs(decompilerContext, isRectVertexShader, usesGeometryShader, fetchVertexManually);\n\n\t\tif (dump_shaders_enabled)\n\t\t\tdecompilerContext->shaderSource->add(\"// end of shader inputs/outputs\" _CRLF);\n\t}\n\n\tstatic void _emitUniformBufferDefinitions(LatteDecompilerShaderContext* decompilerContext)\n\t{\n\t\tauto src = decompilerContext->shaderSource;\n\t\t// uniform buffer definition\n\t\tif (decompilerContext->shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)\n\t\t{\n\t\t\tfor (uint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t\t\t{\n\t\t\t\tif (!decompilerContext->analyzer.uniformBufferAccessTracker[i].HasAccess())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tcemu_assert_debug(decompilerContext->output->resourceMappingMTL.uniformBuffersBindingPoint[i] >= 0);\n\n\t\t\t\tsrc->addFmt(\", constant UBuff{}& ubuff{} [[buffer({})]]\", i, i, (sint32)decompilerContext->output->resourceMappingMTL.uniformBuffersBindingPoint[i]);\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic void _emitTextureDefinitions(LatteDecompilerShaderContext* shaderContext)\n\t{\n\t    bool renderTargetIndexUsed[LATTE_NUM_COLOR_TARGET] = {false};\n\n\t\tauto src = shaderContext->shaderSource;\n\t\t// texture sampler definition\n\t\tfor (sint32 i = 0; i < LATTE_NUM_MAX_TEX_UNITS; i++)\n\t\t{\n\t\t\tif (!shaderContext->output->textureUnitMask[i])\n\t\t\t\tcontinue;\n\n\t\t\tuint8 renderTargetIndex = shaderContext->shader->textureRenderTargetIndex[i];\n\t\t\tif (static_cast<MetalRenderer*>(g_renderer.get())->SupportsFramebufferFetch() && renderTargetIndex != 255)\n\t\t\t{\n                if (!renderTargetIndexUsed[renderTargetIndex])\n\t\t\t\t{\n\t\t\t        src->addFmt(\", {} col{} [[color({})]]\", GetDataTypeStr(GetColorBufferDataType(renderTargetIndex, *shaderContext->contextRegistersNew)), renderTargetIndex, renderTargetIndex);\n\t\t\t\t\trenderTargetIndexUsed[renderTargetIndex] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n                src->add(\", \");\n\n    \t\t\t// Only certain texture dimensions can be used with comparison samplers\n    \t\t\tif (shaderContext->shader->textureUsesDepthCompare[i] && IsValidDepthTextureType(shaderContext->shader->textureUnitDim[i]))\n    \t\t\t    src->add(\"depth\");\n    \t\t\telse\n                    src->add(\"texture\");\n\n    \t\t\tif (shaderContext->shader->textureIsIntegerFormat[i])\n    \t\t\t{\n    \t\t\t\t// integer samplers\n    \t\t\t\tif (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_1D)\n    \t\t\t\t\tsrc->add(\"1d<uint>\");\n    \t\t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_2D || shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_2D_MSAA)\n    \t\t\t\t\tsrc->add(\"2d<uint>\");\n    \t\t\t\telse\n    \t\t\t\t\tcemu_assert_unimplemented();\n    \t\t\t}\n    \t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_2D || shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_2D_MSAA)\n    \t\t\t\tsrc->add(\"2d<float>\");\n    \t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_1D)\n    \t\t\t\tsrc->add(\"1d<float>\");\n    \t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_2D_ARRAY)\n    \t\t\t\tsrc->add(\"2d_array<float>\");\n    \t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_CUBEMAP)\n    \t\t\t\tsrc->add(\"cube_array<float>\");\n    \t\t\telse if (shaderContext->shader->textureUnitDim[i] == Latte::E_DIM::DIM_3D)\n    \t\t\t\tsrc->add(\"3d<float>\");\n    \t\t\telse\n    \t\t\t{\n    \t\t\t\tcemu_assert_unimplemented();\n    \t\t\t}\n\n    \t\t\tuint32 binding = shaderContext->output->resourceMappingMTL.textureUnitToBindingPoint[i];\n    \t\t\t//uint32 textureBinding = shaderContext->output->resourceMappingMTL.textureUnitToBindingPoint[i] % 31;\n    \t\t\t//uint32 samplerBinding = textureBinding % 16;\n    \t\t\tsrc->addFmt(\" tex{} [[texture({})]]\", i, binding);\n    \t\t\tsrc->addFmt(\", sampler samplr{} [[sampler({})]]\", i, binding);\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic void emitInputs(LatteDecompilerShaderContext* decompilerContext, bool isRectVertexShader, bool usesGeometryShader, bool fetchVertexManually)\n\t{\n\t    auto src = decompilerContext->shaderSource;\n\n\t\tswitch (decompilerContext->shaderType)\n\t\t{\n\t\tcase LatteConst::ShaderType::Vertex:\n\t\t    if (usesGeometryShader)\n\t\t\t{\n                src->add(\"object_data ObjectPayload& objectPayload [[payload]]\");\n                src->add(\", mesh_grid_properties meshGridProperties\");\n                src->add(\", uint tig [[threadgroup_position_in_grid]]\");\n                src->add(\", uint tid [[thread_index_in_threadgroup]]\");\n                // TODO: only include index buffer if needed\n                src->addFmt(\", device uint* indexBuffer [[buffer({})]]\", decompilerContext->output->resourceMappingMTL.indexBufferBinding);\n                // TODO: put into the support buffer?\n                src->addFmt(\", constant uchar& indexType [[buffer({})]]\", decompilerContext->output->resourceMappingMTL.indexTypeBinding);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t    // TODO: only include these if needed?\n                src->add(\"uint vid [[vertex_id]]\");\n                src->add(\", uint iid [[instance_id]]\");\n\t\t\t}\n\n            if (fetchVertexManually)\n                src->add(\" VERTEX_BUFFER_DEFINITIONS\");\n\t\t\telse\n\t\t\t\tsrc->add(\", VertexIn in [[stage_in]]\");\n\n            break;\n        case LatteConst::ShaderType::Geometry:\n            src->add(\"MeshType mesh\");\n            src->add(\", const object_data ObjectPayload& objectPayload [[payload]]\");\n            break;\n        case LatteConst::ShaderType::Pixel:\n            src->add(\"FragmentIn in [[stage_in]]\");\n            // TODO: only include these if needed?\n            src->add(\", float2 pointCoord [[point_coord]]\");\n            src->add(\", bool frontFacing [[front_facing]]\");\n            break;\n        default:\n            break;\n\t\t}\n\n\t\tif (decompilerContext->output->resourceMappingMTL.uniformVarsBufferBindingPoint >= 0)\n\t\t    src->addFmt(\", constant SupportBuffer& supportBuffer [[buffer({})]]\", decompilerContext->output->resourceMappingMTL.uniformVarsBufferBindingPoint);\n\n        // streamout buffer (transform feedback)\n        if ((decompilerContext->shaderType == LatteConst::ShaderType::Vertex && !decompilerContext->options->usesGeometryShader) || decompilerContext->shaderType == LatteConst::ShaderType::Geometry)\n        {\n            if (decompilerContext->analyzer.hasStreamoutEnable && decompilerContext->analyzer.hasStreamoutWrite)\n                src->addFmt(\", device int* sb [[buffer({})]]\" _CRLF, decompilerContext->output->resourceMappingMTL.tfStorageBindingPoint);\n        }\n\n\t\t// uniform buffers\n\t\t_emitUniformBufferDefinitions(decompilerContext);\n\t\t// textures\n\t\t_emitTextureDefinitions(decompilerContext);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h",
    "content": "// GPU7 instruction set is a hybrid between R600 and R700\n\n// CF instructions\n#define CF_INST_NOP\t\t\t\t\t(0x00)\n#define CF_INST_TEX\t\t\t\t\t(0x01) \n#define CF_INST_LOOP_END\t\t\t(0x05)\n#define CF_INST_LOOP_START_DX10\t\t(0x06)\n#define CF_INST_JUMP\t\t\t\t(0x0A)\n#define CF_INST_ELSE\t\t\t\t(0x0D)\n#define CF_INST_POP\t\t\t\t\t(0x0E)\n#define CF_INST_ELSE_AFTER\t\t\t(0x0F)\n#define CF_INST_CALL_FS\t\t\t\t(0x13)\n#define CF_INST_EXPORT\t\t\t\t(0x27)\n#define CF_INST_EXPORT_DONE\t\t\t(0x28)\n\n#define CF_INST_ALU\t\t\t\t\t(0x08)\n#define CF_INST_ALU_PUSH_BEFORE\t\t(0x09)\n#define CF_INST_ALU_POP_AFTER\t\t(0x0A)\n#define CF_INST_ALU_POP2_AFTER\t\t(0x0B)\n#define CF_INST_ALU_BREAK\t\t\t(0x0E) // leave loop if pred is modified\n\n#define ALU_OMOD_NONE\t\t\t\t(0)\n#define ALU_OMOD_MUL2\t\t\t\t(1)\n#define ALU_OMOD_MUL4\t\t\t\t(2)\n#define ALU_OMOD_DIV2\t\t\t\t(3)\n\n// ALU op2 instructions\n#define ALU_OP2_INST_ADD\t\t\t(0x000)\n#define ALU_OP2_INST_MUL\t\t\t(0x001)\n#define ALU_OP2_INST_MUL_IEEE\t\t(0x002)\n#define ALU_OP2_INST_MAX\t\t\t(0x003)\n#define ALU_OP2_INST_MIN\t\t\t(0x004)\n#define ALU_OP2_INST_MAX_DX10\t\t(0x005)\n#define ALU_OP2_INST_MIN_DX10\t\t(0x006)\n#define ALU_OP2_INST_SETE\t\t\t(0x008)\n#define ALU_OP2_INST_SETGT\t\t\t(0x009)\n#define ALU_OP2_INST_SETGE\t\t\t(0x00A)\n#define ALU_OP2_INST_SETNE\t\t\t(0x00B)\n#define ALU_OP2_INST_SETE_DX10\t\t(0x00C)\n#define ALU_OP2_INST_SETGT_DX10\t\t(0x00D)\n#define ALU_OP2_INST_SETGE_DX10\t\t(0x00E)\n#define ALU_OP2_INST_SETNE_DX10\t\t(0x00F)\n#define ALU_OP2_INST_FLOOR\t\t\t(0x014)\n#define ALU_OP2_INST_FRACT\t\t\t(0x010)\n#define ALU_OP2_INST_TRUNC\t\t\t(0x011)\n#define ALU_OP2_INST_RNDNE\t\t\t(0x013)\n#define ALU_OP2_INST_MOVA_FLOOR\t\t(0x016) // changes address register\n#define ALU_OP2_INST_MOVA_INT\t\t(0x018) // changes address register\n#define ALU_OP2_INST_MOV\t\t\t(0x019)\n#define ALU_OP2_INST_NOP\t\t\t(0x01A)\n#define ALU_OP2_INST_PRED_SETE\t\t(0x020)\n#define ALU_OP2_INST_PRED_SETGT\t\t(0x021)\n#define ALU_OP2_INST_PRED_SETGE\t\t(0x022)\n#define ALU_OP2_INST_PRED_SETNE\t\t(0x023)\n#define ALU_OP2_INST_AND_INT\t\t(0x030) // integer instruction\n#define ALU_OP2_INST_OR_INT\t\t\t(0x031) // integer instruction\n#define ALU_OP2_INST_XOR_INT\t\t(0x032) // integer instruction\n#define ALU_OP2_INST_NOT_INT\t\t(0x033) // integer instruction\n#define ALU_OP2_INST_ADD_INT\t\t(0x034) // integer instruction\n#define ALU_OP2_INST_SUB_INT\t\t(0x035) // integer instruction\n#define ALU_OP2_INST_MAX_INT\t\t(0x036) // integer instruction\n#define ALU_OP2_INST_MIN_INT\t\t(0x037) // integer instruction\n#define ALU_OP2_INST_MAX_UINT\t\t(0x038) // integer instruction\n#define ALU_OP2_INST_MIN_UINT\t\t(0x039) // integer instruction\n#define ALU_OP2_INST_SETE_INT\t\t(0x03A) // integer instruction\n#define ALU_OP2_INST_SETGT_INT\t\t(0x03B) // integer instruction\n#define ALU_OP2_INST_SETGE_INT\t\t(0x03C) // integer instruction\n#define ALU_OP2_INST_SETNE_INT\t\t(0x03D) // integer instruction\n#define ALU_OP2_INST_SETGT_UINT\t\t(0x03E) // integer instruction\n#define ALU_OP2_INST_SETGE_UINT\t\t(0x03F) // integer instruction\n#define ALU_OP2_INST_PRED_SETE_INT\t(0x042) // integer instruction \n#define ALU_OP2_INST_PRED_SETGT_INT\t(0x043) // integer instruction\n#define ALU_OP2_INST_PRED_SETGE_INT\t(0x044) // integer instruction\n#define ALU_OP2_INST_PRED_SETNE_INT\t(0x045) // integer instruction \n#define ALU_OP2_INST_KILLE\t\t\t(0x02C)\n#define ALU_OP2_INST_KILLGT\t\t\t(0x02D)\n#define ALU_OP2_INST_KILLGE\t\t\t(0x02E)\n#define ALU_OP2_INST_KILLE_INT\t\t(0x046)\n#define ALU_OP2_INST_KILLGT_INT\t\t(0x047)\n#define ALU_OP2_INST_KILLNE_INT\t\t(0x049)\n#define ALU_OP2_INST_DOT4\t\t\t(0x050)\n#define ALU_OP2_INST_DOT4_IEEE\t\t(0x051)\n#define ALU_OP2_INST_CUBE\t\t\t(0x052)\n#define ALU_OP2_INST_EXP_IEEE\t\t(0x061)\n#define ALU_OP2_INST_LOG_CLAMPED\t(0x062)\n#define ALU_OP2_INST_LOG_IEEE\t\t(0x063)\n#define ALU_OP2_INST_SQRT_IEEE\t\t(0x06A)\n#define ALU_OP2_INST_SIN\t\t\t(0x06E)\n#define ALU_OP2_INST_COS\t\t\t(0x06F)\n#define ALU_OP2_INST_RECIP_FF\t\t(0x065)\n#define ALU_OP2_INST_RECIP_IEEE\t\t(0x066)\n#define ALU_OP2_INST_RECIPSQRT_CLAMPED (0x067)\n#define ALU_OP2_INST_RECIPSQRT_FF\t(0x068)\n#define ALU_OP2_INST_RECIPSQRT_IEEE\t(0x069)\n#define ALU_OP2_INST_FLT_TO_INT\t\t(0x06B) // conversion instruction\n#define ALU_OP2_INST_INT_TO_FLOAT\t(0x06C) // conversion instruction\n#define ALU_OP2_INST_UINT_TO_FLOAT\t(0x06D) // conversion instruction\n#define ALU_OP2_INST_ASHR_INT\t\t(0x070) // integer instruction\n#define ALU_OP2_INST_LSHR_INT\t\t(0x071) // integer instruction\n#define ALU_OP2_INST_LSHL_INT\t\t(0x072) // integer instruction\n#define ALU_OP2_INST_MULLO_INT\t\t(0x073) // integer instruction\n#define ALU_OP2_INST_MULLO_UINT\t\t(0x075) // integer instruction\n#define ALU_OP2_INST_FLT_TO_UINT\t(0x079) // conversion instruction\n\n// ALU op3 instructions\n#define ALU_OP3_INST_MULADD\t\t\t(0x10)\n#define ALU_OP3_INST_MULADD_M2\t\t(0x11)\n#define ALU_OP3_INST_MULADD_M4\t\t(0x12)\n#define ALU_OP3_INST_MULADD_D2\t\t(0x13)\n#define ALU_OP3_INST_MULADD_IEEE\t(0x14)\n#define ALU_OP3_INST_CMOVE\t\t\t(0x18)\n#define ALU_OP3_INST_CMOVGT\t\t\t(0x19)\n#define ALU_OP3_INST_CMOVGE\t\t\t(0x1A)\n#define ALU_OP3_INST_CNDE_INT\t\t(0x1C) // integer instruction\n#define ALU_OP3_INST_CNDGT_INT\t\t(0x1D) // integer instruction\n#define ALU_OP3_INST_CMOVGE_INT\t\t(0x1E) // integer instruction\n\n// fetch shader\n#define\t\tVTX_INST_SEMANTIC\t(0x01)\n#define\t\tVTX_INST_MEM\t\t(0x02)"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h",
    "content": "#pragma once\n\nstruct LatteDecompilerALUInstruction\n{\n\tstruct LatteDecompilerCFInstruction* cfInstruction{};\n\tbool isOP3{};\n\tuint32 opcode{};\n\tuint32 instructionGroupIndex{};\n\tuint8 indexMode{};\n\tuint8 omod{};\n\t// destination\n\tuint32 destGpr{};\n\tuint8 destRel{};\n\tuint8 destElem{};\n\tuint8 destClamp{};\n\tuint8 writeMask{};\n\t// flags\n\tuint8 updateExecuteMask{};\n\tuint8 updatePredicate{};\n\t// source operands\n\tstruct\n\t{\n\t\tuint32 sel{};\n\t\tuint8 rel{};\n\t\tuint8 abs{};\n\t\tuint8 neg{};\n\t\tuint8 chan{};\n\t}sourceOperand[3];\n\tunion\n\t{\n\t\tuint32 w[4];\n\t\tfloat f[4];\n\t}literalData;\n\t// information from analyzer stage\n\tuint8 aluUnit{}; // 0-3 -> ALU.x/y/u/w (PV), 4 -> Trans unit (PS)\n\tuint8 indexInGroup{}; // index of instruction within instruction group\n\tbool isLastInstructionOfGroup{};\n};\n\nstruct LatteDecompilerTEXInstruction\n{\n\tstruct LatteDecompilerCFInstruction* cfInstruction{};\n\tuint32 opcode{};\n\t// texture or vertex fetch\n\t// shared\n\tsint32 srcGpr;\n\tsint32 dstGpr;\n\tsint8 dstSel[4];\n\t// texture fetch\n\tstruct\n\t{\n\t\tsint32 textureIndex{};\n\t\tsint32 samplerIndex{};\n\t\tuint32 offset{};\n\t\tsint8 srcSel[4]{};\n\t\tsint8 offsetX{};\n\t\tsint8 offsetY{};\n\t\tsint8 offsetZ{};\n\t\tbool unnormalized[4]{}; // set if texture coordinates are in [0,dim] range instead of [0,1]\n\t\tsint8 lodBias{}; // divide by 16 to get actual value\n\t}textureFetch;\n\t// memRead\n\tstruct\n\t{\n\t\tuint32 arrayBase{};\n\t\tsint8 srcSelX{};\n\t\tuint32 format{};\n\t\tuint8 nfa{};\n\t\tuint8 isSigned{};\n\t}memRead;\n};\n\nstruct LatteDecompilerCFInstruction\n{\n\tuint32 type{};\n\tuint32 cfAddr{};\n\t// for clauses with instructions\n\tuint32 addr{};\n\tsint32 count{};\n\t// clause contains either ALU or TEX instructions\n\tstd::vector<LatteDecompilerALUInstruction> instructionsALU;\n\tstd::vector<LatteDecompilerTEXInstruction> instructionsTEX;\n\t// for clauses that access uniform buffers\n\tuint32 cBank0Index{};\n\tuint32 cBank1Index{};\n\tuint32 cBank0AddrBase{};\n\tuint32 cBank1AddrBase{};\n\t// for exports\n\tuint32 exportType{};\n\tuint8  exportComponentSel[4]{};\n\tuint32 exportBurstCount{};\n\t// for mem write\n\tuint32 memWriteArraySize{};\n\tuint8 memWriteCompMask{};\n\tuint8 memWriteElemSize{}; // 0-3\n\t// for exports and mem write\n\tuint32 exportArrayBase{};\n\tuint32 exportSourceGPR{};\n\t// misc\n\tuint32 cfCond{};\n\tuint32 popCount{};\n\t// information from analyzer stage\n\tbool modifiesPredicate{};\n\tbool modifiesActiveMask{};\n\tuint32 numPredInstructions{};\n\tsint32 activeStackDepth{}; // stack depth during the clause/CF instruction\n\n\tLatteDecompilerCFInstruction()\n\t{\n\n\t}\n\n\t~LatteDecompilerCFInstruction()\n\t{\n\t\tcemu_assert_debug(!(instructionsALU.size() != 0 && instructionsTEX.size() != 0)); // make sure we haven't accidentally added the wrong instruction type\n\t}\n\n\tLatteDecompilerCFInstruction(const LatteDecompilerCFInstruction& mE) = default;\n\tLatteDecompilerCFInstruction(LatteDecompilerCFInstruction&& mE) = default;\n\n\tLatteDecompilerCFInstruction& operator=(LatteDecompilerCFInstruction&& mE) = default;\n};\n\nstruct LatteDecompilerSubroutineInfo\n{\n\tuint32 cfAddr;\n\tstd::vector<LatteDecompilerCFInstruction> instructions;\n};\n\n// helper struct to track the highest accessed offset within a buffer\nstruct LatteDecompilerBufferAccessTracker\n{\n\tbool hasStaticIndexAccess{false};\n\tbool hasDynamicIndexAccess{false};\n\tsint32 highestAccessDynamicIndex{0};\n\tsint32 highestAccessStaticIndex{0};\n\n\t// track access, index is the array index and not a byte offset\n\tvoid TrackAccess(sint32 index, bool isDynamicIndex)\n\t{\n\t\tif (isDynamicIndex)\n\t\t{\n\t\t\thasDynamicIndexAccess = true;\n\t\t\tif (index > highestAccessDynamicIndex)\n\t\t\t\thighestAccessDynamicIndex = index;\n\t\t}\n\t\telse\n\t\t{\n\t\t\thasStaticIndexAccess = true;\n\t\t\tif (index > highestAccessStaticIndex)\n\t\t\t\thighestAccessStaticIndex = index;\n\t\t}\n\t}\n\n\tsint32 DetermineSize(uint64 shaderBaseHash, sint32 maximumSize) const\n\t{\n\t\t// here we try to predict the accessed byte range so we dont have to upload the whole buffer\n\t\t// if no bound can be determined then return maximumSize\n\t\t// for some known shaders we use hand-tuned values instead of the maximumSize fallback value that those shaders would normally use\n\t\tif(shaderBaseHash == 0x8ff56afdf1a2f837) // XCX text rendering\n\t\t\treturn 24;\n\t\tif(shaderBaseHash == 0x37b9100c1310d3bb) // BotW UI backdrops 1\n\t\t\treturn 24;\n\t\tif(shaderBaseHash == 0xf7ba548c1fefe24a) // BotW UI backdrops 2\n\t\t\treturn 30;\n\n\t\tsint32 highestAccessIndex = -1;\n\t\tif(hasStaticIndexAccess)\n\t\t\thighestAccessIndex = highestAccessStaticIndex;\n\t\tif(hasDynamicIndexAccess)\n\t\t\treturn maximumSize; // dynamic index exists and no bound can be determined\n\t\tif (highestAccessIndex < 0)\n\t\t\treturn 1; // no access at all? But avoid zero as a size\n\t\treturn highestAccessIndex + 1;\n\t}\n\n\tbool HasAccess() const\n\t{\n\t\treturn hasStaticIndexAccess || hasDynamicIndexAccess;\n\t}\n\n\tbool HasRelativeAccess() const\n\t{\n\t\treturn hasDynamicIndexAccess;\n\t}\n};\n\nstruct LatteDecompilerShaderContext\n{\n\tLatteDecompilerOutput_t* output;\n\tLatteDecompilerShader* shader;\n\tLatteConst::ShaderType shaderType;\n\tconst class LatteDecompilerOptions* options;\n\tuint32* contextRegisters; // deprecated\n\tstruct LatteContextRegister* contextRegistersNew;\n\tuint64 shaderBaseHash;\n\tStringBuf* shaderSource;\n\tstd::vector<LatteDecompilerCFInstruction> cfInstructions;\n\t// fetch shader (required for vertex shader)\n\tLatteFetchShader* fetchShader{};\n\t// geometry copy shader (only present when geometry shader is active)\n\tLatteParsedGSCopyShader* parsedGSCopyShader;\n\t// state\n\tbool hasError;\n\t// type tracker\n\tstruct\n\t{\n\t\t// data type tracker\n\t\tuint8 defaultDataType;\n\t\tbool genFloatReg; // if set, generate R*f register variables\n\t\tbool genIntReg; // if set, generate R*i register variables\n\t\tbool useArrayGPRs; // if set, an array is used to represent GPRs instead of individual variables\n\t}typeTracker;\n\t// analyzer\n\tstruct\n\t{\n\t\t// general\n\t\tbool hasStreamoutEnable{}; // set if streamout is enabled\n\t\tbool hasLoops{}; // loop directives present in shader\n\t\t// vertex shader\n\t\tbool isPointsPrimitive{}; // set if current render primitive is points\n\t\tbool outputPointSize{}; // set if the current shader should output the point size\n\t\tstd::bitset<256> inputAttributSemanticMask; // one set bit for every used semanticId - todo: there are only 128 bit available semantic locations? The MSB has special meaning?\n\t\t// uniforms\n\t\tLatteDecompilerBufferAccessTracker uniformRegisterAccessTracker;\n\t\tLatteDecompilerBufferAccessTracker uniformBufferAccessTracker[LATTE_NUM_MAX_UNIFORM_BUFFERS];\n\t\t// ssbo\n\t\tbool hasSSBORead; // shader has instructions that read from SSBO\n\t\tbool hasSSBOWrite; // shader has instructions that write to SSBO\n\t\t// textures\n\t\tstd::bitset<LATTE_NUM_MAX_TEX_UNITS> texUnitUsesTexelCoordinates;\n\t\tbool hasCubeMapTexture; // set to true if a cubemap texture is used\n\t\tbool hasGradientLookup; // set to true if texture lookup with custom gradients is used\n\t\t// misc\n\t\tbool usesRelativeGPRRead; // set if indexed GPR reads are used\n\t\tbool usesRelativeGPRWrite; // set if indexed GPR writes are used\n\t\tuint8 gprUseMask[(LATTE_NUM_GPR + 7) / 8]; // 1 bit per GPR, set if GPR is read/written anywhere in the program (ignores GPR accesses with relative index)\n\t\tbool hasStreamoutWrite; // stream-out CF instructions are used\n\t\tbool hasRedcCUBE; // has cube reduction instruction\n\t\tbool modifiesPixelActiveState; // set if the active mask is changed anywhere in the shader (If false, we can skip active mask checks)\n\t\tbool usesIntegerValues; // set if the shader uses any kind of integer instruction or integer-based GPR/AR access\n\t\tsint32 activeStackMaxDepth; // maximum depth of pixel state stack\n\t\t// analyzer stage (vs)\n\t\tbool writesPointSize{};\n\t\t// streamout (vs and gs)\n\t\tbool useSSBOForStreamout{};\n\t\t// geometry shader\n\t\tuint32 numEmitVertex{}; // counts how often emit vertex instruction is found\n\t}analyzer;\n\n\t// set while generating code for subroutine\n\tbool isSubroutine;\n\tLatteDecompilerSubroutineInfo* subroutineInfo;\n\n\t// emitter\n\tbool hasUniformVarBlock;\n\tsint32 currentBindingPointVK{};\n\tsint32 currentBufferBindingPointMTL{};\n\tsint32 currentTextureBindingPointMTL{};\n\tstruct ALUClauseTemporariesState* aluPVPSState{nullptr};\n\t\n\t// misc\n\tstd::vector<LatteDecompilerSubroutineInfo> list_subroutines;\n};\n\nvoid LatteDecompiler_analyze(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader);\nvoid LatteDecompiler_analyzeDataTypes(LatteDecompilerShaderContext* shaderContext);\nvoid LatteDecompiler_emitGLSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader);\n#if ENABLE_METAL\nvoid LatteDecompiler_emitMSLShader(LatteDecompilerShaderContext* shaderContext, LatteDecompilerShader* shader);\n#endif\n\nvoid LatteDecompiler_cleanup(LatteDecompilerShaderContext* shaderContext);\n\n// helper functions\n\nsint32 LatteDecompiler_getColorOutputIndexFromExportIndex(LatteDecompilerShaderContext* shaderContext, sint32 exportIndex);\n"
  },
  {
    "path": "src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerRegisterDataTypeTracker.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderAssembly.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h\"\n\nvoid LatteDecompiler_analyzeDataTypes(LatteDecompilerShaderContext* shaderContext)\n{\n\t// determine default type\n\tif (shaderContext->analyzer.usesIntegerValues)\n\t{\n\t\tshaderContext->typeTracker.defaultDataType = LATTE_DECOMPILER_DTYPE_SIGNED_INT;\n\t\tshaderContext->typeTracker.genIntReg = true;\n\t}\n\telse\n\t{\n\t\tshaderContext->typeTracker.defaultDataType = LATTE_DECOMPILER_DTYPE_FLOAT;\n\t\tshaderContext->typeTracker.genFloatReg = true;\n\t}\n\t// determine register representation\n\tif (shaderContext->analyzer.usesRelativeGPRWrite)\n\t{\n\t\tshaderContext->typeTracker.useArrayGPRs = true;\n\t}\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n\nCachedFBOMtl::CachedFBOMtl(class MetalRenderer* metalRenderer, uint64 key) : LatteCachedFBO(key)\n{\n\tm_renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();\n\n\tbool hasAttachment = false;\n\tfor (int i = 0; i < 8; ++i)\n\t{\n\t\tconst auto& buffer = colorBuffer[i];\n\t\tauto textureView = (LatteTextureViewMtl*)buffer.texture;\n\t\tif (!textureView)\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\t\tauto colorAttachment = m_renderPassDescriptor->colorAttachments()->object(i);\n\t\tcolorAttachment->setTexture(textureView->GetRGBAView());\n\t\tcolorAttachment->setLoadAction(MTL::LoadActionLoad);\n\t\tcolorAttachment->setStoreAction(MTL::StoreActionStore);\n\n\t\thasAttachment = true;\n\t}\n\n\t// setup depth attachment\n\tif (depthBuffer.texture)\n\t{\n\t\tauto textureView = static_cast<LatteTextureViewMtl*>(depthBuffer.texture);\n\t\tauto depthAttachment = m_renderPassDescriptor->depthAttachment();\n\t\tdepthAttachment->setTexture(textureView->GetRGBAView());\n\t\tdepthAttachment->setLoadAction(MTL::LoadActionLoad);\n\t\tdepthAttachment->setStoreAction(MTL::StoreActionStore);\n\n\t\t// setup stencil attachment\n\t\tif (depthBuffer.hasStencil && GetMtlPixelFormatInfo(depthBuffer.texture->format, true).hasStencil)\n\t\t{\n\t\t    auto stencilAttachment = m_renderPassDescriptor->stencilAttachment();\n            stencilAttachment->setTexture(textureView->GetRGBAView());\n            stencilAttachment->setLoadAction(MTL::LoadActionLoad);\n            stencilAttachment->setStoreAction(MTL::StoreActionStore);\n\t\t}\n\n\t\thasAttachment = true;\n\t}\n\n\t// HACK: setup a dummy color attachment to prevent Metal from discarding draws for stremout draws in Super Smash Bros. for Wii U (works fine on MoltenVK without this hack though)\n\tif (!hasAttachment)\n\t{\n        auto colorAttachment = m_renderPassDescriptor->colorAttachments()->object(0);\n    \tcolorAttachment->setTexture(metalRenderer->GetNullTexture2D());\n    \tcolorAttachment->setLoadAction(MTL::LoadActionDontCare);\n    \tcolorAttachment->setStoreAction(MTL::StoreActionDontCare);\n\t}\n\n\t// Visibility buffer\n\tm_renderPassDescriptor->setVisibilityResultBuffer(metalRenderer->GetOcclusionQueryResultBuffer());\n}\n\nCachedFBOMtl::~CachedFBOMtl()\n{\n\tm_renderPassDescriptor->release();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h",
    "content": "#pragma once\n\n#include <Metal/Metal.hpp>\n\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/Core/LatteCachedFBO.h\"\n\nclass CachedFBOMtl : public LatteCachedFBO\n{\npublic:\n\tCachedFBOMtl(class MetalRenderer* metalRenderer, uint64 key);\n\n\t~CachedFBOMtl();\n\n\tMTL::RenderPassDescriptor* GetRenderPassDescriptor()\n\t{\n\t    return m_renderPassDescriptor;\n\t}\n\nprivate:\n    MTL::RenderPassDescriptor* m_renderPassDescriptor = nullptr;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n\nLatteTextureMtl::LatteTextureMtl(class MetalRenderer* mtlRenderer, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle,\n\tLatte::E_HWTILEMODE tileMode, bool isDepth)\n\t: LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth), m_mtlr(mtlRenderer)\n{\n    NS_STACK_SCOPED MTL::TextureDescriptor* desc = MTL::TextureDescriptor::alloc()->init();\n    desc->setStorageMode(MTL::StorageModePrivate);\n    //desc->setCpuCacheMode(MTL::CPUCacheModeWriteCombined);\n\n\tsint32 effectiveBaseWidth = width;\n\tsint32 effectiveBaseHeight = height;\n\tsint32 effectiveBaseDepth = depth;\n\tif (overwriteInfo.hasResolutionOverwrite)\n\t{\n\t\teffectiveBaseWidth = overwriteInfo.width;\n\t\teffectiveBaseHeight = overwriteInfo.height;\n\t\teffectiveBaseDepth = overwriteInfo.depth;\n\t}\n\teffectiveBaseWidth = std::max(1, effectiveBaseWidth);\n\teffectiveBaseHeight = std::max(1, effectiveBaseHeight);\n\teffectiveBaseDepth = std::max(1, effectiveBaseDepth);\n\n\tMTL::TextureType textureType;\n\tswitch (dim)\n    {\n    case Latte::E_DIM::DIM_1D:\n        textureType = MTL::TextureType1D;\n        effectiveBaseHeight = 1;\n        break;\n    case Latte::E_DIM::DIM_2D:\n    case Latte::E_DIM::DIM_2D_MSAA:\n        textureType = MTL::TextureType2D;\n        break;\n    case Latte::E_DIM::DIM_2D_ARRAY:\n        textureType = MTL::TextureType2DArray;\n        break;\n    case Latte::E_DIM::DIM_3D:\n        textureType = MTL::TextureType3D;\n        break;\n    case Latte::E_DIM::DIM_CUBEMAP:\n        cemu_assert_debug(effectiveBaseDepth % 6 == 0 && \"cubemaps must have an array length multiple of 6\");\n\n        textureType = MTL::TextureTypeCubeArray;\n        break;\n    default:\n        cemu_assert_unimplemented();\n        textureType = MTL::TextureType2D;\n        break;\n    }\n    desc->setTextureType(textureType);\n\n    // Clamp mip levels\n    mipLevels = std::min(mipLevels, (uint32)maxPossibleMipLevels);\n    mipLevels = std::max(mipLevels, (uint32)1);\n\n\tdesc->setWidth(effectiveBaseWidth);\n\tdesc->setHeight(effectiveBaseHeight);\n\tdesc->setMipmapLevelCount(mipLevels);\n\n\tif (textureType == MTL::TextureType3D)\n\t{\n\t\tdesc->setDepth(effectiveBaseDepth);\n\t}\n\telse if (textureType == MTL::TextureTypeCubeArray)\n\t{\n\t\tdesc->setArrayLength(effectiveBaseDepth / 6);\n\t}\n\telse if (textureType == MTL::TextureType2DArray)\n\t{\n\t\tdesc->setArrayLength(effectiveBaseDepth);\n\t}\n\n\tauto pixelFormat = GetMtlPixelFormat(format, isDepth);\n\tdesc->setPixelFormat(pixelFormat);\n\n\tMTL::TextureUsage usage = MTL::TextureUsageShaderRead | MTL::TextureUsagePixelFormatView;\n\tif (FormatIsRenderable(format))\n\t\tusage |= MTL::TextureUsageRenderTarget;\n\tdesc->setUsage(usage);\n\n\tm_texture = mtlRenderer->GetDevice()->newTexture(desc);\n}\n\nLatteTextureMtl::~LatteTextureMtl()\n{\n\tm_texture->release();\n}\n\nLatteTextureView* LatteTextureMtl::CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)\n{\n\tcemu_assert_debug(mipCount > 0);\n\tcemu_assert_debug(sliceCount > 0);\n\tcemu_assert_debug((firstMip + mipCount) <= this->mipLevels);\n\tcemu_assert_debug((firstSlice + sliceCount) <= this->depth);\n\n\treturn new LatteTextureViewMtl(m_mtlr, this, dim, format, firstMip, mipCount, firstSlice, sliceCount);\n}\n\n// TODO: lazy allocation?\nvoid LatteTextureMtl::AllocateOnHost()\n{\n\t// The texture is already allocated\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h",
    "content": "#pragma once\n\n#include <Metal/Metal.hpp>\n\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"HW/Latte/ISA/LatteReg.h\"\n#include \"util/ChunkedHeap/ChunkedHeap.h\"\n\nclass LatteTextureMtl : public LatteTexture\n{\npublic:\n\tLatteTextureMtl(class MetalRenderer* mtlRenderer, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels,\n\t\tuint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth);\n\t~LatteTextureMtl();\n\n\tMTL::Texture* GetTexture() const {\n\t    return m_texture;\n\t}\n\n\tvoid AllocateOnHost() override;\n\nprotected:\n\tLatteTextureView* CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) override;\n\nprivate:\n\tclass MetalRenderer* m_mtlr;\n\n\tMTL::Texture* m_texture;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n\nLatteTextureReadbackInfoMtl::~LatteTextureReadbackInfoMtl()\n{\n    if (m_commandBuffer)\n        m_commandBuffer->release();\n}\n\nvoid LatteTextureReadbackInfoMtl::StartTransfer()\n{\n\tcemu_assert(m_textureView);\n\n\tauto* baseTexture = (LatteTextureMtl*)m_textureView->baseTexture;\n\n\tcemu_assert_debug(m_textureView->firstSlice == 0);\n\tcemu_assert_debug(m_textureView->firstMip == 0);\n\tcemu_assert_debug(m_textureView->baseTexture->dim != Latte::E_DIM::DIM_3D);\n\n\tsize_t bytesPerRow = GetMtlTextureBytesPerRow(baseTexture->format, baseTexture->isDepth, baseTexture->width);\n\tsize_t bytesPerImage = GetMtlTextureBytesPerImage(baseTexture->format, baseTexture->isDepth, baseTexture->height, bytesPerRow);\n\n\tauto blitCommandEncoder = m_mtlr->GetBlitCommandEncoder();\n\n\tblitCommandEncoder->copyFromTexture(baseTexture->GetTexture(), 0, 0, MTL::Origin{0, 0, 0}, MTL::Size{(uint32)baseTexture->width, (uint32)baseTexture->height, 1}, m_mtlr->GetTextureReadbackBuffer(), m_bufferOffset, bytesPerRow, bytesPerImage);\n\n\tm_commandBuffer = m_mtlr->GetCurrentCommandBuffer()->retain();\n\t// TODO: uncomment?\n\t//m_mtlr->RequestSoonCommit();\n\tm_mtlr->CommitCommandBuffer();\n}\n\nbool LatteTextureReadbackInfoMtl::IsFinished()\n{\n    // Command buffer wasn't even comitted, let's commit immediately\n    //if (m_mtlr->GetCurrentCommandBuffer() == m_commandBuffer)\n    //    m_mtlr->CommitCommandBuffer();\n\n    return CommandBufferCompleted(m_commandBuffer);\n}\n\nvoid LatteTextureReadbackInfoMtl::ForceFinish()\n{\n    m_commandBuffer->waitUntilCompleted();\n}\n\nuint8* LatteTextureReadbackInfoMtl::GetData()\n{\n\treturn (uint8*)m_mtlr->GetTextureReadbackBuffer()->contents() + m_bufferOffset;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalCommon.h\"\n#include \"Cafe/HW/Latte/Core/LatteTextureReadbackInfo.h\"\n\nclass LatteTextureReadbackInfoMtl : public LatteTextureReadbackInfo\n{\npublic:\n\tLatteTextureReadbackInfoMtl(class MetalRenderer* mtlRenderer, LatteTextureView* textureView, uint32 bufferOffset) : LatteTextureReadbackInfo(textureView), m_mtlr{mtlRenderer}, m_bufferOffset{bufferOffset} {}\n\t~LatteTextureReadbackInfoMtl();\n\n\tvoid StartTransfer() override;\n\n\tbool IsFinished() override;\n\tvoid ForceFinish() override;\n\n\tuint8* GetData() override;\n\nprivate:\n\tclass MetalRenderer* m_mtlr;\n\n\tMTL::CommandBuffer* m_commandBuffer = nullptr;\n\n\tuint32 m_bufferOffset = 0;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n#include \"Metal/MTLTexture.hpp\"\n\nuint32 LatteTextureMtl_AdjustTextureCompSel(Latte::E_GX2SURFFMT format, uint32 compSel)\n{\n\tswitch (format)\n\t{\n\tcase Latte::E_GX2SURFFMT::R8_UNORM: // R8 is replicated on all channels (while OpenGL would return 1.0 for BGA instead)\n\tcase Latte::E_GX2SURFFMT::R8_SNORM: // probably the same as _UNORM, but needs testing\n\t\tif (compSel >= 1 && compSel <= 3)\n\t\t\tcompSel = 0;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM: // order of components is reversed (RGBA -> ABGR)\n\t\tif (compSel >= 0 && compSel <= 3)\n\t\t\tcompSel = 3 - compSel;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::BC4_UNORM:\n\tcase Latte::E_GX2SURFFMT::BC4_SNORM:\n\t\tif (compSel >= 1 && compSel <= 3)\n\t\t\tcompSel = 0;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::BC5_UNORM:\n\tcase Latte::E_GX2SURFFMT::BC5_SNORM:\n\t\t// RG maps to RG\n\t\t// B maps to ?\n\t\t// A maps to G (guessed)\n\t\tif (compSel == 3)\n\t\t\tcompSel = 1; // read Alpha as Green\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::A2_B10_G10_R10_UNORM:\n\t\t// reverse components (Wii U: ABGR, OpenGL: RGBA)\n\t\t// used in Resident Evil Revelations\n\t\tif (compSel >= 0 && compSel <= 3)\n\t\t\tcompSel = 3 - compSel;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::X24_G8_UINT:\n\t\t// map everything to alpha?\n\t\tif (compSel >= 0 && compSel <= 3)\n\t\t\tcompSel = 3;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::R4_G4_UNORM:\n\t\t// red and green swapped\n\t\tif (compSel == 0)\n\t\t\tcompSel = 1;\n\t\telse if (compSel == 1)\n\t\t\tcompSel = 0;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\treturn compSel;\n}\n\nLatteTextureViewMtl::LatteTextureViewMtl(MetalRenderer* mtlRenderer, LatteTextureMtl* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)\n\t: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_mtlr(mtlRenderer), m_baseTexture(texture)\n{\n    m_rgbaView = CreateSwizzledView(RGBA_SWIZZLE);\n}\n\nLatteTextureViewMtl::~LatteTextureViewMtl()\n{\n    m_rgbaView->release();\n\tfor (sint32 i = 0; i < std::size(m_viewCache); i++)\n    {\n        if (m_viewCache[i].key != INVALID_SWIZZLE)\n            m_viewCache[i].texture->release();\n    }\n\n    for (auto& [key, texture] : m_fallbackViewCache)\n    {\n        texture->release();\n    }\n}\n\nMTL::Texture* LatteTextureViewMtl::GetSwizzledView(uint32 gpuSamplerSwizzle)\n{\n    // Mask out\n    gpuSamplerSwizzle &= 0x0FFF0000;\n\n    // RGBA swizzle == no swizzle\n    if (gpuSamplerSwizzle == RGBA_SWIZZLE)\n    {\n        return m_rgbaView;\n    }\n\n    // First, try to find a view in the cache\n\n    // Fast cache\n    sint32 freeIndex = -1;\n    for (sint32 i = 0; i < std::size(m_viewCache); i++)\n    {\n        const auto& entry = m_viewCache[i];\n        if (entry.key == gpuSamplerSwizzle)\n        {\n            return entry.texture;\n        }\n        else if (entry.key == INVALID_SWIZZLE && freeIndex == -1)\n        {\n            freeIndex = i;\n        }\n    }\n\n    // Fallback cache\n    auto& fallbackEntry = m_fallbackViewCache[gpuSamplerSwizzle];\n    if (fallbackEntry)\n    {\n        return fallbackEntry;\n    }\n\n    MTL::Texture* texture = CreateSwizzledView(gpuSamplerSwizzle);\n    if (freeIndex != -1)\n        m_viewCache[freeIndex] = {gpuSamplerSwizzle, texture};\n    else\n        fallbackEntry = texture;\n\n    return texture;\n}\n\nMTL::Texture* LatteTextureViewMtl::CreateSwizzledView(uint32 gpuSamplerSwizzle)\n{\n    uint32 compSelR = (gpuSamplerSwizzle >> 16) & 0x7;\n\tuint32 compSelG = (gpuSamplerSwizzle >> 19) & 0x7;\n\tuint32 compSelB = (gpuSamplerSwizzle >> 22) & 0x7;\n\tuint32 compSelA = (gpuSamplerSwizzle >> 25) & 0x7;\n\tcompSelR = LatteTextureMtl_AdjustTextureCompSel(format, compSelR);\n\tcompSelG = LatteTextureMtl_AdjustTextureCompSel(format, compSelG);\n\tcompSelB = LatteTextureMtl_AdjustTextureCompSel(format, compSelB);\n\tcompSelA = LatteTextureMtl_AdjustTextureCompSel(format, compSelA);\n\n\tMTL::TextureType textureType;\n    switch (dim)\n    {\n    case Latte::E_DIM::DIM_1D:\n        textureType = MTL::TextureType1D;\n        break;\n    case Latte::E_DIM::DIM_2D:\n    case Latte::E_DIM::DIM_2D_MSAA:\n        textureType = MTL::TextureType2D;\n        break;\n    case Latte::E_DIM::DIM_2D_ARRAY:\n        textureType = MTL::TextureType2DArray;\n        break;\n    case Latte::E_DIM::DIM_3D:\n        textureType = MTL::TextureType3D;\n        break;\n    case Latte::E_DIM::DIM_CUBEMAP:\n        cemu_assert_debug(this->numSlice % 6 == 0 && \"cubemaps must have an array length multiple of 6\");\n\n        textureType = MTL::TextureTypeCubeArray;\n        break;\n    default:\n        cemu_assert_unimplemented();\n        textureType = MTL::TextureType2D;\n        break;\n    }\n\n    uint32 baseLevel = firstMip;\n    uint32 levelCount = this->numMip;\n    uint32 baseLayer = 0;\n    uint32 layerCount = 1;\n    // TODO: check if base texture is 3D texture as well\n    if (textureType == MTL::TextureType3D)\n    {\n        cemu_assert_debug(firstMip == 0);\n        cemu_assert_debug(this->numSlice == baseTexture->depth);\n    }\n    else\n    {\n        baseLayer = firstSlice;\n        if (textureType == MTL::TextureTypeCubeArray || textureType == MTL::TextureType2DArray)\n            layerCount = this->numSlice;\n    }\n\n    MTL::TextureSwizzleChannels swizzle;\n    swizzle.red = GetMtlTextureSwizzle(compSelR);\n    swizzle.green = GetMtlTextureSwizzle(compSelG);\n    swizzle.blue = GetMtlTextureSwizzle(compSelB);\n    swizzle.alpha = GetMtlTextureSwizzle(compSelA);\n\n    // Clamp mip levels\n    levelCount = std::min(levelCount, m_baseTexture->maxPossibleMipLevels - baseLevel);\n    levelCount = std::max(levelCount, (uint32)1);\n\n    auto pixelFormat = GetMtlPixelFormat(format, m_baseTexture->isDepth);\n    MTL::Texture* texture = m_baseTexture->GetTexture()->newTextureView(pixelFormat, textureType, NS::Range::Make(baseLevel, levelCount), NS::Range::Make(baseLayer, layerCount), swizzle);\n\n    return texture;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h",
    "content": "#pragma once\n\n#include <Metal/Metal.hpp>\n#include <unordered_map>\n\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n\n#define RGBA_SWIZZLE 0x06880000\n#define INVALID_SWIZZLE 0xFFFFFFFF\n\nclass LatteTextureViewMtl : public LatteTextureView\n{\npublic:\n\tLatteTextureViewMtl(class MetalRenderer* mtlRenderer, class LatteTextureMtl* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount);\n\t~LatteTextureViewMtl();\n\n    MTL::Texture* GetSwizzledView(uint32 gpuSamplerSwizzle);\n\n    MTL::Texture* GetRGBAView()\n    {\n        return GetSwizzledView(RGBA_SWIZZLE);\n    }\n\nprivate:\n\tclass MetalRenderer* m_mtlr;\n\n\tclass LatteTextureMtl* m_baseTexture;\n\n\tMTL::Texture* m_rgbaView;\n\tstruct {\n\t    uint32 key;\n\t    MTL::Texture* texture;\n\t} m_viewCache[4] = {{INVALID_SWIZZLE, nullptr}, {INVALID_SWIZZLE, nullptr}, {INVALID_SWIZZLE, nullptr}, {INVALID_SWIZZLE, nullptr}};\n\tstd::unordered_map<uint32, MTL::Texture*> m_fallbackViewCache;\n\n    MTL::Texture* CreateSwizzledView(uint32 gpuSamplerSwizzle);\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n#include \"Cemu/Logging/CemuLogging.h\"\n#include \"HW/Latte/Core/LatteTextureLoader.h\"\n#include \"HW/Latte/Renderer/Metal/MetalCommon.h\"\n\nstd::map<Latte::E_GX2SURFFMT, MetalPixelFormatInfo> MTL_COLOR_FORMAT_TABLE = {\n    {Latte::E_GX2SURFFMT::INVALID_FORMAT, {MTL::PixelFormatInvalid, MetalDataType::NONE, 0}},\n\n\t{Latte::E_GX2SURFFMT::R4_G4_UNORM, {MTL::PixelFormatABGR4Unorm, MetalDataType::FLOAT, 2}},\n\t{Latte::E_GX2SURFFMT::R5_G6_B5_UNORM, {MTL::PixelFormatB5G6R5Unorm, MetalDataType::FLOAT, 2}},\n\t{Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM, {MTL::PixelFormatBGR5A1Unorm, MetalDataType::FLOAT, 2}},\n\t{Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM, {MTL::PixelFormatABGR4Unorm, MetalDataType::FLOAT, 2}},\n\t{Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM, {MTL::PixelFormatA1BGR5Unorm, MetalDataType::FLOAT, 2}},\n\t{Latte::E_GX2SURFFMT::R8_UNORM, {MTL::PixelFormatR8Unorm, MetalDataType::FLOAT, 1}},\n\t{Latte::E_GX2SURFFMT::R8_SNORM, {MTL::PixelFormatR8Snorm, MetalDataType::FLOAT, 1}},\n\t{Latte::E_GX2SURFFMT::R8_UINT, {MTL::PixelFormatR8Uint, MetalDataType::UINT, 1}},\n\t{Latte::E_GX2SURFFMT::R8_SINT, {MTL::PixelFormatR8Sint, MetalDataType::INT, 1}},\n\t{Latte::E_GX2SURFFMT::R8_G8_UNORM, {MTL::PixelFormatRG8Unorm, MetalDataType::FLOAT, 2}},\n\t{Latte::E_GX2SURFFMT::R8_G8_SNORM, {MTL::PixelFormatRG8Snorm, MetalDataType::FLOAT, 2}},\n\t{Latte::E_GX2SURFFMT::R8_G8_UINT, {MTL::PixelFormatRG8Uint, MetalDataType::UINT, 2}},\n\t{Latte::E_GX2SURFFMT::R8_G8_SINT, {MTL::PixelFormatRG8Sint, MetalDataType::INT, 2}},\n\t{Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM, {MTL::PixelFormatRGBA8Unorm, MetalDataType::FLOAT, 4}},\n\t{Latte::E_GX2SURFFMT::R8_G8_B8_A8_SNORM, {MTL::PixelFormatRGBA8Snorm, MetalDataType::FLOAT, 4}},\n\t{Latte::E_GX2SURFFMT::R8_G8_B8_A8_UINT, {MTL::PixelFormatRGBA8Uint, MetalDataType::UINT, 4}},\n\t{Latte::E_GX2SURFFMT::R8_G8_B8_A8_SINT, {MTL::PixelFormatRGBA8Sint, MetalDataType::INT, 4}},\n\t{Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB, {MTL::PixelFormatRGBA8Unorm_sRGB, MetalDataType::FLOAT, 4}},\n\t{Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM, {MTL::PixelFormatRGB10A2Unorm, MetalDataType::FLOAT, 4}},\n\t{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM, {MTL::PixelFormatRGBA16Snorm, MetalDataType::FLOAT, 8}},\n\t{Latte::E_GX2SURFFMT::R10_G10_B10_A2_UINT, {MTL::PixelFormatRGB10A2Uint, MetalDataType::UINT, 4}},\n\t{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SINT, {MTL::PixelFormatRGBA16Sint, MetalDataType::INT, 8}},\n\t{Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB, {MTL::PixelFormatRGB10A2Unorm, MetalDataType::FLOAT, 4}}, // TODO: sRGB?\n\t{Latte::E_GX2SURFFMT::A2_B10_G10_R10_UNORM, {MTL::PixelFormatBGR10A2Unorm, MetalDataType::FLOAT, 4}},\n\t{Latte::E_GX2SURFFMT::A2_B10_G10_R10_UINT, {MTL::PixelFormatRGB10A2Uint, MetalDataType::UINT, 4}},\n\t{Latte::E_GX2SURFFMT::R16_UNORM, {MTL::PixelFormatR16Unorm, MetalDataType::FLOAT, 2}},\n\t{Latte::E_GX2SURFFMT::R16_SNORM, {MTL::PixelFormatR16Snorm, MetalDataType::FLOAT, 2}},\n\t{Latte::E_GX2SURFFMT::R16_UINT, {MTL::PixelFormatR16Uint, MetalDataType::UINT, 2}},\n\t{Latte::E_GX2SURFFMT::R16_SINT, {MTL::PixelFormatR16Sint, MetalDataType::INT, 2}},\n\t{Latte::E_GX2SURFFMT::R16_FLOAT, {MTL::PixelFormatR16Float, MetalDataType::FLOAT, 2}},\n\t{Latte::E_GX2SURFFMT::R16_G16_UNORM, {MTL::PixelFormatRG16Unorm, MetalDataType::FLOAT, 4}},\n\t{Latte::E_GX2SURFFMT::R16_G16_SNORM, {MTL::PixelFormatRG16Snorm, MetalDataType::FLOAT, 4}},\n\t{Latte::E_GX2SURFFMT::R16_G16_UINT, {MTL::PixelFormatRG16Uint, MetalDataType::UINT, 4}},\n\t{Latte::E_GX2SURFFMT::R16_G16_SINT, {MTL::PixelFormatRG16Sint, MetalDataType::INT, 4}},\n\t{Latte::E_GX2SURFFMT::R16_G16_FLOAT, {MTL::PixelFormatRG16Float, MetalDataType::FLOAT, 4}},\n\t{Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM, {MTL::PixelFormatRGBA16Unorm, MetalDataType::FLOAT, 8}},\n\t{Latte::E_GX2SURFFMT::R16_G16_B16_A16_SNORM, {MTL::PixelFormatRGBA16Snorm, MetalDataType::FLOAT, 8}},\n\t{Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT, {MTL::PixelFormatRGBA16Uint, MetalDataType::UINT, 8}},\n\t{Latte::E_GX2SURFFMT::R16_G16_B16_A16_SINT, {MTL::PixelFormatRGBA16Sint, MetalDataType::INT, 8}},\n\t{Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT, {MTL::PixelFormatRGBA16Float, MetalDataType::FLOAT, 8}},\n\t{Latte::E_GX2SURFFMT::R24_X8_UNORM, {MTL::PixelFormatR32Float, MetalDataType::FLOAT, 4}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::R24_X8_FLOAT, {MTL::PixelFormatR32Float, MetalDataType::FLOAT, 4}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::X24_G8_UINT, {MTL::PixelFormatRGBA8Uint, MetalDataType::UINT, 4}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::R32_X8_FLOAT, {MTL::PixelFormatR32Float, MetalDataType::FLOAT, 4}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::X32_G8_UINT_X24, {MTL::PixelFormatRGBA16Uint, MetalDataType::UINT, 8}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT, {MTL::PixelFormatRG11B10Float, MetalDataType::FLOAT, 4}},\n\t{Latte::E_GX2SURFFMT::R32_UINT, {MTL::PixelFormatR32Uint, MetalDataType::UINT, 4}},\n\t{Latte::E_GX2SURFFMT::R32_SINT, {MTL::PixelFormatR32Sint, MetalDataType::INT, 4}},\n\t{Latte::E_GX2SURFFMT::R32_FLOAT, {MTL::PixelFormatR32Float, MetalDataType::FLOAT, 4}},\n\t{Latte::E_GX2SURFFMT::R32_G32_UINT, {MTL::PixelFormatRG32Uint, MetalDataType::UINT, 8}},\n\t{Latte::E_GX2SURFFMT::R32_G32_SINT, {MTL::PixelFormatRG32Sint, MetalDataType::INT, 8}},\n\t{Latte::E_GX2SURFFMT::R32_G32_FLOAT, {MTL::PixelFormatRG32Float, MetalDataType::FLOAT, 8}},\n\t{Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT, {MTL::PixelFormatRGBA32Uint, MetalDataType::UINT, 16}},\n\t{Latte::E_GX2SURFFMT::R32_G32_B32_A32_SINT, {MTL::PixelFormatRGBA32Sint, MetalDataType::INT, 16}},\n\t{Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT, {MTL::PixelFormatRGBA32Float, MetalDataType::FLOAT, 16}},\n\t{Latte::E_GX2SURFFMT::BC1_UNORM, {MTL::PixelFormatBC1_RGBA, MetalDataType::FLOAT, 8, {4, 4}}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::BC1_SRGB, {MTL::PixelFormatBC1_RGBA_sRGB, MetalDataType::FLOAT, 8, {4, 4}}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::BC2_UNORM, {MTL::PixelFormatBC2_RGBA, MetalDataType::FLOAT, 16, {4, 4}}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::BC2_SRGB, {MTL::PixelFormatBC2_RGBA_sRGB, MetalDataType::FLOAT, 16, {4, 4}}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::BC3_UNORM, {MTL::PixelFormatBC3_RGBA, MetalDataType::FLOAT, 16, {4, 4}}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::BC3_SRGB, {MTL::PixelFormatBC3_RGBA_sRGB, MetalDataType::FLOAT, 16, {4, 4}}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::BC4_UNORM, {MTL::PixelFormatBC4_RUnorm, MetalDataType::FLOAT, 8, {4, 4}}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::BC4_SNORM, {MTL::PixelFormatBC4_RSnorm, MetalDataType::FLOAT, 8, {4, 4}}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::BC5_UNORM, {MTL::PixelFormatBC5_RGUnorm, MetalDataType::FLOAT, 16, {4, 4}}}, // TODO: correct?\n\t{Latte::E_GX2SURFFMT::BC5_SNORM, {MTL::PixelFormatBC5_RGSnorm, MetalDataType::FLOAT, 16, {4, 4}}}, // TODO: correct?\n};\n\nstd::map<Latte::E_GX2SURFFMT, MetalPixelFormatInfo> MTL_DEPTH_FORMAT_TABLE = {\n    {Latte::E_GX2SURFFMT::INVALID_FORMAT, {MTL::PixelFormatInvalid, MetalDataType::NONE, 0}},\n\n\t{Latte::E_GX2SURFFMT::D24_S8_UNORM, {MTL::PixelFormatDepth24Unorm_Stencil8, MetalDataType::NONE, 4, {1, 1}, true}},\n\t{Latte::E_GX2SURFFMT::D24_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, MetalDataType::NONE, 4, {1, 1}, true}},\n\t{Latte::E_GX2SURFFMT::D32_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, MetalDataType::NONE, 5, {1, 1}, true}},\n\t{Latte::E_GX2SURFFMT::D16_UNORM, {MTL::PixelFormatDepth16Unorm, MetalDataType::NONE, 2, {1, 1}}},\n\t{Latte::E_GX2SURFFMT::D32_FLOAT, {MTL::PixelFormatDepth32Float, MetalDataType::NONE, 4, {1, 1}}},\n};\n\n// TODO: R10_G10_B10_A2_UINT and R10_G10_B10_A2_SINT\n// TODO: A2_B10_G10_R10_UNORM and A2_B10_G10_R10_UINT\nvoid CheckForPixelFormatSupport(const MetalPixelFormatSupport& support)\n{\n    // Texture decoders\n\n    // Color\n    MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT].textureDecoder =  TextureDecoder_R32_G32_B32_A32_FLOAT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT].textureDecoder = TextureDecoder_R32_G32_B32_A32_UINT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT].textureDecoder = TextureDecoder_R16_G16_B16_A16_FLOAT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT].textureDecoder = TextureDecoder_R16_G16_B16_A16_UINT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM].textureDecoder = TextureDecoder_R16_G16_B16_A16::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R16_G16_B16_A16_SNORM].textureDecoder = TextureDecoder_R16_G16_B16_A16::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM].textureDecoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R8_G8_B8_A8_SNORM].textureDecoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB].textureDecoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R8_G8_B8_A8_UINT].textureDecoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R8_G8_B8_A8_SINT].textureDecoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R32_G32_FLOAT].textureDecoder = TextureDecoder_R32_G32_FLOAT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R32_G32_UINT].textureDecoder = TextureDecoder_R32_G32_UINT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R16_G16_UNORM].textureDecoder = TextureDecoder_R16_G16::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R16_G16_FLOAT].textureDecoder = TextureDecoder_R16_G16_FLOAT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R8_G8_UNORM].textureDecoder = TextureDecoder_R8_G8::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R8_G8_SNORM].textureDecoder = TextureDecoder_R8_G8::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_UNORM].textureDecoder = TextureDecoder_R4_G4_UNORM_To_ABGR4::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R32_FLOAT].textureDecoder = TextureDecoder_R32_FLOAT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R32_UINT].textureDecoder = TextureDecoder_R32_UINT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R16_FLOAT].textureDecoder = TextureDecoder_R16_FLOAT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R16_UNORM].textureDecoder = TextureDecoder_R16_UNORM::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R16_SNORM].textureDecoder = TextureDecoder_R16_SNORM::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R16_UINT].textureDecoder = TextureDecoder_R16_UINT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R8_UNORM].textureDecoder = TextureDecoder_R8::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R8_SNORM].textureDecoder = TextureDecoder_R8::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R8_UINT].textureDecoder = TextureDecoder_R8_UINT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G6_B5_UNORM].textureDecoder = TextureDecoder_R5_G6_B5_swappedRB::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM].textureDecoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM].textureDecoder = TextureDecoder_A1_B5_G5_R5_UNORM::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT].textureDecoder = TextureDecoder_R11_G11_B10_FLOAT::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM].textureDecoder = TextureDecoder_R4_G4_B4_A4_UNORM::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM].textureDecoder = TextureDecoder_R10_G10_B10_A2_UNORM::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM].textureDecoder = TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB].textureDecoder = TextureDecoder_R10_G10_B10_A2_UNORM::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::BC1_SRGB].textureDecoder = TextureDecoder_BC1::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::BC1_UNORM].textureDecoder = TextureDecoder_BC1::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::BC2_UNORM].textureDecoder = TextureDecoder_BC2::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::BC2_SRGB].textureDecoder = TextureDecoder_BC2::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::BC3_UNORM].textureDecoder = TextureDecoder_BC3::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::BC3_SRGB].textureDecoder = TextureDecoder_BC3::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::BC4_UNORM].textureDecoder = TextureDecoder_BC4::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::BC4_SNORM].textureDecoder = TextureDecoder_BC4::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::BC5_UNORM].textureDecoder = TextureDecoder_BC5::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::BC5_SNORM].textureDecoder = TextureDecoder_BC5::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R24_X8_UNORM].textureDecoder = TextureDecoder_R24_X8::getInstance();\n   \tMTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::X24_G8_UINT].textureDecoder = TextureDecoder_X24_G8_UINT::getInstance();\n\n    if (!support.m_supportsPacked16BitFormats)\n    {\n        // B5G6R5Unorm\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G6_B5_UNORM].pixelFormat = MTL::PixelFormatRGBA8Unorm;\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G6_B5_UNORM].bytesPerBlock = 4;\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G6_B5_UNORM].textureDecoder = TextureDecoder_R5G6B5_UNORM_To_RGBA8::getInstance();\n\n        // A1BGR5Unorm\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM].pixelFormat = MTL::PixelFormatRGBA8Unorm;\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM].textureDecoder = TextureDecoder_A1_B5_G5_R5_UNORM_vulkan_To_RGBA8::getInstance();\n\n        // ABGR4Unorm\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_UNORM].pixelFormat = MTL::PixelFormatRG8Unorm;\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_UNORM].bytesPerBlock = 2;\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_UNORM].textureDecoder = TextureDecoder_R4G4_UNORM_To_RG8::getInstance();\n\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM].pixelFormat = MTL::PixelFormatRGBA8Unorm;\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM].bytesPerBlock = 4;\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM].textureDecoder = TextureDecoder_R4G4B4A4_UNORM_To_RGBA8::getInstance();\n\n        // BGR5A1Unorm\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM].pixelFormat = MTL::PixelFormatRGBA8Unorm;\n        MTL_COLOR_FORMAT_TABLE[Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM].textureDecoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB_To_RGBA8::getInstance();\n    }\n\n    // Depth\n   \tMTL_DEPTH_FORMAT_TABLE[Latte::E_GX2SURFFMT::D24_S8_UNORM].textureDecoder = TextureDecoder_D24_S8::getInstance();\n   \tMTL_DEPTH_FORMAT_TABLE[Latte::E_GX2SURFFMT::D24_S8_FLOAT].textureDecoder = TextureDecoder_NullData64::getInstance(); // TODO: why?\n   \tMTL_DEPTH_FORMAT_TABLE[Latte::E_GX2SURFFMT::D32_FLOAT].textureDecoder = TextureDecoder_R32_FLOAT::getInstance();\n   \tMTL_DEPTH_FORMAT_TABLE[Latte::E_GX2SURFFMT::D16_UNORM].textureDecoder = TextureDecoder_R16_UNORM::getInstance();\n   \tMTL_DEPTH_FORMAT_TABLE[Latte::E_GX2SURFFMT::D32_S8_FLOAT].textureDecoder = TextureDecoder_D32_S8_UINT_X24::getInstance();\n\n    if (!support.m_supportsDepth24Unorm_Stencil8)\n    {\n        // Depth24Unorm_Stencil8\n        MTL_DEPTH_FORMAT_TABLE[Latte::E_GX2SURFFMT::D24_S8_UNORM].pixelFormat = MTL::PixelFormatDepth32Float_Stencil8;\n        // TODO: implement the decoder\n        //MTL_DEPTH_FORMAT_TABLE[Latte::E_GX2SURFFMT::D24_S8_UNORM].textureDecoder = TextureDecoder_D24_S8_To_D32_S8::getInstance();\n    }\n}\n\nconst MetalPixelFormatInfo GetMtlPixelFormatInfo(Latte::E_GX2SURFFMT format, bool isDepth)\n{\n    if (isDepth)\n    {\n        auto it = MTL_DEPTH_FORMAT_TABLE.find(format);\n        if (it == MTL_DEPTH_FORMAT_TABLE.end())\n            return {MTL::PixelFormatDepth16Unorm, MetalDataType::NONE, 2}; // Fallback\n        else\n            return it->second;\n    }\n    else\n    {\n        auto it = MTL_COLOR_FORMAT_TABLE.find(format);\n        if (it == MTL_COLOR_FORMAT_TABLE.end())\n            return {MTL::PixelFormatR8Unorm, MetalDataType::FLOAT, 1}; // Fallback\n        else\n            return it->second;\n    }\n}\n\nMTL::PixelFormat GetMtlPixelFormat(Latte::E_GX2SURFFMT format, bool isDepth)\n{\n    auto pixelFormat = GetMtlPixelFormatInfo(format, isDepth).pixelFormat;\n    if (pixelFormat == MTL::PixelFormatInvalid)\n        cemuLog_log(LogType::Force, \"invalid pixel format 0x{:x}, is depth: {}\\n\", format, isDepth);\n\n    return pixelFormat;\n}\n\ninline uint32 CeilDivide(uint32 a, uint32 b) {\n    return (a + b - 1) / b;\n}\n\nsize_t GetMtlTextureBytesPerRow(Latte::E_GX2SURFFMT format, bool isDepth, uint32 width)\n{\n    const auto& formatInfo = GetMtlPixelFormatInfo(format, isDepth);\n\n    return CeilDivide(width, formatInfo.blockTexelSize.x) * formatInfo.bytesPerBlock;\n}\n\nsize_t GetMtlTextureBytesPerImage(Latte::E_GX2SURFFMT format, bool isDepth, uint32 height, size_t bytesPerRow)\n{\n    const auto& formatInfo = GetMtlPixelFormatInfo(format, isDepth);\n\n    return CeilDivide(height, formatInfo.blockTexelSize.y) * bytesPerRow;\n}\n\nMTL::PrimitiveType GetMtlPrimitiveType(LattePrimitiveMode primitiveMode)\n{\n    switch (primitiveMode)\n    {\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::POINTS:\n\t\treturn MTL::PrimitiveTypePoint;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINES:\n\t\treturn MTL::PrimitiveTypeLine;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINE_STRIP:\n\t\treturn MTL::PrimitiveTypeLineStrip;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINE_LOOP:\n\t\treturn MTL::PrimitiveTypeLineStrip; // line loops are emulated as line strips with an extra connecting strip at the end\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINE_STRIP_ADJACENT: // Tropical Freeze level 3-6\n\t    cemuLog_logOnce(LogType::Force, \"Metal doesn't support line strip adjacent primitive, using line strip instead\");\n\t\treturn MTL::PrimitiveTypeLineStrip;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLES:\n\t\treturn MTL::PrimitiveTypeTriangle;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLE_FAN:\n\t\treturn MTL::PrimitiveTypeTriangleStrip;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLE_STRIP:\n\t\treturn MTL::PrimitiveTypeTriangleStrip;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUADS:\n\t\treturn MTL::PrimitiveTypeTriangle; // quads are emulated as 2 triangles\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUAD_STRIP:\n\t\treturn MTL::PrimitiveTypeTriangle; // quad strips are emulated as (count-2)/2 triangles\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS:\n\t\treturn MTL::PrimitiveTypeTriangle; // rects are emulated as 2 triangles\n\tdefault:\n\t\tcemuLog_log(LogType::Force, \"Unsupported primitive mode {}\", primitiveMode);\n\t\tcemu_assert_debug(false);\n\t\treturn MTL::PrimitiveTypeTriangle;\n    }\n}\n\nMTL::VertexFormat GetMtlVertexFormat(uint8 format)\n{\n    switch (format)\n\t{\n\tcase FMT_32_32_32_32_FLOAT:\n\t\treturn MTL::VertexFormatUInt4;\n\tcase FMT_32_32_32_FLOAT:\n\t\treturn MTL::VertexFormatUInt3;\n\tcase FMT_32_32_FLOAT:\n\t\treturn MTL::VertexFormatUInt2;\n\tcase FMT_32_FLOAT:\n\t\treturn MTL::VertexFormatUInt;\n\tcase FMT_8_8_8_8:\n\t\treturn MTL::VertexFormatUChar4;\n\tcase FMT_8_8_8:\n\t\treturn MTL::VertexFormatUChar3;\n\tcase FMT_8_8:\n\t\treturn MTL::VertexFormatUChar2;\n\tcase FMT_8:\n\t\treturn MTL::VertexFormatUChar;\n\tcase FMT_32_32_32_32:\n\t\treturn MTL::VertexFormatUInt4;\n\tcase FMT_32_32_32:\n\t\treturn MTL::VertexFormatUInt3;\n\tcase FMT_32_32:\n\t\treturn MTL::VertexFormatUInt2;\n\tcase FMT_32:\n\t\treturn MTL::VertexFormatUInt;\n\tcase FMT_16_16_16_16:\n\t\treturn MTL::VertexFormatUShort4; // verified to match OpenGL\n\tcase FMT_16_16_16:\n\t\treturn MTL::VertexFormatUShort3;\n\tcase FMT_16_16:\n\t\treturn MTL::VertexFormatUShort2;\n\tcase FMT_16:\n\t\treturn MTL::VertexFormatUShort;\n\tcase FMT_16_16_16_16_FLOAT:\n\t\treturn MTL::VertexFormatUShort4; // verified to match OpenGL\n\tcase FMT_16_16_16_FLOAT:\n\t\treturn MTL::VertexFormatUShort3;\n\tcase FMT_16_16_FLOAT:\n\t\treturn MTL::VertexFormatUShort2;\n\tcase FMT_16_FLOAT:\n\t\treturn MTL::VertexFormatUShort;\n\tcase FMT_2_10_10_10:\n\t\treturn MTL::VertexFormatUInt; // verified to match OpenGL\n\tdefault:\n\t\tcemuLog_log(LogType::Force, \"unsupported vertex format {}\", (uint32)format);\n\t\tassert_dbg();\n\t\treturn MTL::VertexFormatInvalid;\n\t}\n}\n\nuint32 GetMtlVertexFormatSize(uint8 format)\n{\n    switch (format)\n\t{\n\tcase FMT_32_32_32_32_FLOAT:\n\t\treturn 16;\n\tcase FMT_32_32_32_FLOAT:\n\t\treturn 12;\n\tcase FMT_32_32_FLOAT:\n\t\treturn 8;\n\tcase FMT_32_FLOAT:\n\t\treturn 4;\n\tcase FMT_8_8_8_8:\n\t\treturn 4;\n\tcase FMT_8_8_8:\n\t\treturn 3;\n\tcase FMT_8_8:\n\t\treturn 2;\n\tcase FMT_8:\n\t\treturn 1;\n\tcase FMT_32_32_32_32:\n\t\treturn 16;\n\tcase FMT_32_32_32:\n\t\treturn 12;\n\tcase FMT_32_32:\n\t\treturn 8;\n\tcase FMT_32:\n\t\treturn 4;\n\tcase FMT_16_16_16_16:\n\t\treturn 8;\n\tcase FMT_16_16_16:\n\t\treturn 6;\n\tcase FMT_16_16:\n\t\treturn 4;\n\tcase FMT_16:\n\t\treturn 2;\n\tcase FMT_16_16_16_16_FLOAT:\n\t\treturn 8;\n\tcase FMT_16_16_16_FLOAT:\n\t\treturn 6;\n\tcase FMT_16_16_FLOAT:\n\t\treturn 4;\n\tcase FMT_16_FLOAT:\n\t\treturn 2;\n\tcase FMT_2_10_10_10:\n\t\treturn 4;\n\tdefault:\n\t\treturn 0;\n\t}\n}\n\nMTL::IndexType GetMtlIndexType(Renderer::INDEX_TYPE indexType)\n{\n    switch (indexType)\n    {\n    case Renderer::INDEX_TYPE::U16:\n        return MTL::IndexTypeUInt16;\n    case Renderer::INDEX_TYPE::U32:\n        return MTL::IndexTypeUInt32;\n    default:\n        cemu_assert_suspicious();\n        return MTL::IndexTypeUInt32;\n    }\n}\n\nMTL::BlendOperation GetMtlBlendOp(Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC combineFunc)\n{\n    switch (combineFunc)\n\t{\n\tcase Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC::DST_PLUS_SRC:\n\t\treturn MTL::BlendOperationAdd;\n\tcase Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC::SRC_MINUS_DST:\n\t\treturn MTL::BlendOperationSubtract;\n\tcase Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC::MIN_DST_SRC:\n\t\treturn MTL::BlendOperationMin;\n\tcase Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC::MAX_DST_SRC:\n\t\treturn MTL::BlendOperationMax;\n\tcase Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC::DST_MINUS_SRC:\n\t\treturn MTL::BlendOperationReverseSubtract;\n\tdefault:\n\t\tcemu_assert_suspicious();\n\t\treturn MTL::BlendOperationAdd;\n\t}\n}\n\nconst MTL::BlendFactor MTL_BLEND_FACTORS[] =\n{\n    /* 0x00 */ MTL::BlendFactorZero,\n    /* 0x01 */ MTL::BlendFactorOne,\n    /* 0x02 */ MTL::BlendFactorSourceColor,\n    /* 0x03 */ MTL::BlendFactorOneMinusSourceColor,\n    /* 0x04 */ MTL::BlendFactorSourceAlpha,\n    /* 0x05 */ MTL::BlendFactorOneMinusSourceAlpha,\n    /* 0x06 */ MTL::BlendFactorDestinationAlpha,\n    /* 0x07 */ MTL::BlendFactorOneMinusDestinationAlpha,\n    /* 0x08 */ MTL::BlendFactorDestinationColor,\n    /* 0x09 */ MTL::BlendFactorOneMinusDestinationColor,\n    /* 0x0A */ MTL::BlendFactorSourceAlphaSaturated,\n    /* 0x0B */ MTL::BlendFactorZero, // TODO\n    /* 0x0C */ MTL::BlendFactorZero, // TODO\n    /* 0x0D */ MTL::BlendFactorBlendColor,\n    /* 0x0E */ MTL::BlendFactorOneMinusBlendColor,\n    /* 0x0F */ MTL::BlendFactorSource1Color,\n    /* 0x10 */ MTL::BlendFactorOneMinusSource1Color,\n    /* 0x11 */ MTL::BlendFactorSource1Alpha,\n    /* 0x12 */ MTL::BlendFactorOneMinusSource1Alpha,\n    /* 0x13 */ MTL::BlendFactorBlendAlpha,\n    /* 0x14 */ MTL::BlendFactorOneMinusBlendAlpha\n};\n\nMTL::BlendFactor GetMtlBlendFactor(Latte::LATTE_CB_BLENDN_CONTROL::E_BLENDFACTOR factor)\n{\n\tcemu_assert_debug((uint32)factor < std::size(MTL_BLEND_FACTORS));\n\treturn MTL_BLEND_FACTORS[(uint32)factor];\n}\n\nconst MTL::CompareFunction MTL_COMPARE_FUNCTIONS[8] =\n{\n\tMTL::CompareFunctionNever,\n\tMTL::CompareFunctionLess,\n\tMTL::CompareFunctionEqual,\n\tMTL::CompareFunctionLessEqual,\n\tMTL::CompareFunctionGreater,\n\tMTL::CompareFunctionNotEqual,\n\tMTL::CompareFunctionGreaterEqual,\n\tMTL::CompareFunctionAlways\n};\n\nMTL::CompareFunction GetMtlCompareFunc(Latte::E_COMPAREFUNC func)\n{\n    cemu_assert_debug((uint32)func < std::size(MTL_COMPARE_FUNCTIONS));\n    return MTL_COMPARE_FUNCTIONS[(uint32)func];\n}\n\n// TODO: clamp to border color? (should be fine though)\nconst MTL::SamplerAddressMode MTL_SAMPLER_ADDRESS_MODES[] = {\n\tMTL::SamplerAddressModeRepeat, // WRAP\n\tMTL::SamplerAddressModeMirrorRepeat, // MIRROR\n\tMTL::SamplerAddressModeClampToEdge, // CLAMP_LAST_TEXEL\n\tMTL::SamplerAddressModeMirrorClampToEdge, // MIRROR_ONCE_LAST_TEXEL\n\tMTL::SamplerAddressModeClampToEdge, // unsupported HALF_BORDER\n\tMTL::SamplerAddressModeClampToBorderColor, // unsupported MIRROR_ONCE_HALF_BORDER\n\tMTL::SamplerAddressModeClampToBorderColor, // CLAMP_BORDER\n\tMTL::SamplerAddressModeClampToBorderColor // MIRROR_ONCE_BORDER\n};\n\nMTL::SamplerAddressMode GetMtlSamplerAddressMode(Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_CLAMP clamp)\n{\n    cemu_assert_debug((uint32)clamp < std::size(MTL_SAMPLER_ADDRESS_MODES));\n    return MTL_SAMPLER_ADDRESS_MODES[(uint32)clamp];\n}\n\nconst MTL::TextureSwizzle MTL_TEXTURE_SWIZZLES[] = {\n    MTL::TextureSwizzleRed,\n    MTL::TextureSwizzleGreen,\n    MTL::TextureSwizzleBlue,\n    MTL::TextureSwizzleAlpha,\n    MTL::TextureSwizzleZero,\n    MTL::TextureSwizzleOne,\n    MTL::TextureSwizzleZero,\n    MTL::TextureSwizzleZero\n};\n\nMTL::TextureSwizzle GetMtlTextureSwizzle(uint32 swizzle)\n{\n    cemu_assert_debug(swizzle < std::size(MTL_TEXTURE_SWIZZLES));\n    return MTL_TEXTURE_SWIZZLES[swizzle];\n}\n\nconst MTL::StencilOperation MTL_STENCIL_OPERATIONS[8] = {\n\tMTL::StencilOperationKeep,\n\tMTL::StencilOperationZero,\n\tMTL::StencilOperationReplace,\n\tMTL::StencilOperationIncrementClamp,\n\tMTL::StencilOperationDecrementClamp,\n\tMTL::StencilOperationInvert,\n\tMTL::StencilOperationIncrementWrap,\n\tMTL::StencilOperationDecrementWrap\n};\n\nMTL::StencilOperation GetMtlStencilOp(Latte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION action)\n{\n    cemu_assert_debug((uint32)action < std::size(MTL_STENCIL_OPERATIONS));\n    return MTL_STENCIL_OPERATIONS[(uint32)action];\n}\n\nMTL::ColorWriteMask GetMtlColorWriteMask(uint8 mask)\n{\n    MTL::ColorWriteMask mtlMask = MTL::ColorWriteMaskNone;\n    if (mask & 0x1) mtlMask |= MTL::ColorWriteMaskRed;\n    if (mask & 0x2) mtlMask |= MTL::ColorWriteMaskGreen;\n    if (mask & 0x4) mtlMask |= MTL::ColorWriteMaskBlue;\n    if (mask & 0x8) mtlMask |= MTL::ColorWriteMaskAlpha;\n\n    return mtlMask;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalCommon.h\"\n\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n//#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Common/precompiled.h\"\n#include \"HW/Latte/Core/LatteTextureLoader.h\"\n\nstruct Uvec2 {\n    uint32 x;\n    uint32 y;\n};\n\nenum class MetalDataType\n{\n    NONE,\n    INT,\n    UINT,\n    FLOAT,\n};\n\nstruct MetalPixelFormatInfo {\n    MTL::PixelFormat pixelFormat;\n    MetalDataType dataType;\n    size_t bytesPerBlock;\n    Uvec2 blockTexelSize = {1, 1};\n    bool hasStencil = false;\n    TextureDecoder* textureDecoder = nullptr;\n};\n\nvoid CheckForPixelFormatSupport(const MetalPixelFormatSupport& support);\n\nconst MetalPixelFormatInfo GetMtlPixelFormatInfo(Latte::E_GX2SURFFMT format, bool isDepth);\n\nMTL::PixelFormat GetMtlPixelFormat(Latte::E_GX2SURFFMT format, bool isDepth);\n\ninline MetalDataType GetColorBufferDataType(const uint32 index, const LatteContextRegister& lcr)\n{\n    auto format = LatteMRT::GetColorBufferFormat(index, lcr);\n    return GetMtlPixelFormatInfo(format, false).dataType;\n}\n\ninline const char* GetDataTypeStr(MetalDataType dataType)\n{\n\tswitch (dataType)\n\t{\n\tcase MetalDataType::INT:\n\t    return \"int4\";\n\tcase MetalDataType::UINT:\n\t    return \"uint4\";\n\tcase MetalDataType::FLOAT:\n\t    return \"float4\";\n\tdefault:\n\t    cemu_assert_suspicious();\n\t\treturn \"INVALID\";\n\t}\n}\n\nsize_t GetMtlTextureBytesPerRow(Latte::E_GX2SURFFMT format, bool isDepth, uint32 width);\n\nsize_t GetMtlTextureBytesPerImage(Latte::E_GX2SURFFMT format, bool isDepth, uint32 height, size_t bytesPerRow);\n\nMTL::PrimitiveType GetMtlPrimitiveType(LattePrimitiveMode primitiveMode);\n\nMTL::VertexFormat GetMtlVertexFormat(uint8 format);\n\nuint32 GetMtlVertexFormatSize(uint8 format);\n\nMTL::IndexType GetMtlIndexType(Renderer::INDEX_TYPE indexType);\n\nMTL::BlendOperation GetMtlBlendOp(Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC combineFunc);\n\nMTL::BlendFactor GetMtlBlendFactor(Latte::LATTE_CB_BLENDN_CONTROL::E_BLENDFACTOR factor);\n\nMTL::CompareFunction GetMtlCompareFunc(Latte::E_COMPAREFUNC func);\n\nMTL::SamplerAddressMode GetMtlSamplerAddressMode(Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_CLAMP clamp);\n\nMTL::TextureSwizzle GetMtlTextureSwizzle(uint32 swizzle);\n\nMTL::StencilOperation GetMtlStencilOp(Latte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION action);\n\nMTL::ColorWriteMask GetMtlColorWriteMask(uint8 mask);\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n\nMetalAttachmentsInfo::MetalAttachmentsInfo(class CachedFBOMtl* fbo)\n{\n    for (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)\n\t{\n\t    const auto& colorBuffer = fbo->colorBuffer[i];\n\t\tauto texture = static_cast<LatteTextureViewMtl*>(colorBuffer.texture);\n\t\tif (!texture)\n\t\t    continue;\n\n\t\tcolorFormats[i] = texture->format;\n\t}\n\n\t// Depth stencil attachment\n\tif (fbo->depthBuffer.texture)\n\t{\n\t    auto texture = static_cast<LatteTextureViewMtl*>(fbo->depthBuffer.texture);\n        depthFormat = texture->format;\n        hasStencil = fbo->depthBuffer.hasStencil;\n\t}\n}\n\nMetalAttachmentsInfo::MetalAttachmentsInfo(const LatteContextRegister& lcr, const LatteDecompilerShader* pixelShader)\n{\n    uint8 cbMask = LatteMRT::GetActiveColorBufferMask(pixelShader, lcr);\n\tbool dbMask = LatteMRT::GetActiveDepthBufferMask(lcr);\n\n\t// Color attachments\n\tfor (int i = 0; i < 8; ++i)\n\t{\n\t\tif ((cbMask & (1 << i)) == 0)\n\t\t\tcontinue;\n\n\t\tcolorFormats[i] = LatteMRT::GetColorBufferFormat(i, lcr);\n\t}\n\n\t// Depth stencil attachment\n\tif (dbMask)\n\t{\n\t\tLatte::E_GX2SURFFMT format = LatteMRT::GetDepthBufferFormat(lcr);\n\t\tdepthFormat = format;\n\t\thasStencil = GetMtlPixelFormatInfo(format, true).hasStencil;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalCommon.h\"\n\nclass MetalAttachmentsInfo\n{\npublic:\n    MetalAttachmentsInfo() = default;\n    MetalAttachmentsInfo(class CachedFBOMtl* fbo);\n    MetalAttachmentsInfo(const LatteContextRegister& lcr, const class LatteDecompilerShader* pixelShader);\n\n    Latte::E_GX2SURFFMT colorFormats[LATTE_NUM_COLOR_TARGET] = {Latte::E_GX2SURFFMT::INVALID_FORMAT};\n    Latte::E_GX2SURFFMT depthFormat = Latte::E_GX2SURFFMT::INVALID_FORMAT;\n    bool hasStencil = false;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalBufferAllocator.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalBufferAllocator.h\"\n\nMetalBufferChunkedHeap::~MetalBufferChunkedHeap()\n{\n\tfor (auto& chunk : m_chunkBuffers)\n\t\tchunk->release();\n}\n\nuint32 MetalBufferChunkedHeap::allocateNewChunk(uint32 chunkIndex, uint32 minimumAllocationSize)\n{\n\tsize_t allocationSize = std::max<size_t>(m_minimumBufferAllocationSize, minimumAllocationSize);\n\tMTL::Buffer* buffer = m_mtlr->GetDevice()->newBuffer(allocationSize, m_options);\n\tcemu_assert_debug(buffer);\n\tcemu_assert_debug(m_chunkBuffers.size() == chunkIndex);\n\tm_chunkBuffers.emplace_back(buffer);\n\n\treturn allocationSize;\n}\n\nvoid MetalSynchronizedRingAllocator::addUploadBufferSyncPoint(AllocatorBuffer_t& buffer, uint32 offset)\n{\n\tauto commandBuffer = m_mtlr->GetCurrentCommandBuffer();\n\tif (commandBuffer == buffer.lastSyncpointCommandBuffer)\n\t\treturn;\n\tbuffer.lastSyncpointCommandBuffer = commandBuffer;\n\tbuffer.queue_syncPoints.emplace(commandBuffer, offset);\n}\n\nvoid MetalSynchronizedRingAllocator::allocateAdditionalUploadBuffer(uint32 sizeRequiredForAlloc)\n{\n\t// calculate buffer size, should be a multiple of bufferAllocSize that is at least as large as sizeRequiredForAlloc\n\tuint32 bufferAllocSize = m_minimumBufferAllocSize;\n\twhile (bufferAllocSize < sizeRequiredForAlloc)\n\t\tbufferAllocSize += m_minimumBufferAllocSize;\n\n\tAllocatorBuffer_t newBuffer{};\n\tnewBuffer.writeIndex = 0;\n\tnewBuffer.basePtr = nullptr;\n\tnewBuffer.mtlBuffer = m_mtlr->GetDevice()->newBuffer(bufferAllocSize, m_options);\n\tnewBuffer.basePtr = (uint8*)newBuffer.mtlBuffer->contents();\n\tnewBuffer.size = bufferAllocSize;\n\tnewBuffer.index = (uint32)m_buffers.size();\n\tm_buffers.push_back(newBuffer);\n}\n\nMetalSynchronizedRingAllocator::AllocatorReservation_t MetalSynchronizedRingAllocator::AllocateBufferMemory(uint32 size, uint32 alignment)\n{\n\tif (alignment < 128)\n\t\talignment = 128;\n\tsize = (size + 127) & ~127;\n\n\tfor (auto& itr : m_buffers)\n\t{\n\t\t// align pointer\n\t\tuint32 alignmentPadding = (alignment - (itr.writeIndex % alignment)) % alignment;\n\t\tuint32 distanceToSyncPoint;\n\t\tif (!itr.queue_syncPoints.empty())\n\t\t{\n\t\t\tif (itr.queue_syncPoints.front().offset < itr.writeIndex)\n\t\t\t\tdistanceToSyncPoint = 0xFFFFFFFF;\n\t\t\telse\n\t\t\t\tdistanceToSyncPoint = itr.queue_syncPoints.front().offset - itr.writeIndex;\n\t\t}\n\t\telse\n\t\t\tdistanceToSyncPoint = 0xFFFFFFFF;\n\t\tuint32 spaceNeeded = alignmentPadding + size;\n\t\tif (spaceNeeded > distanceToSyncPoint)\n\t\t\tcontinue; // not enough space in current buffer\n\t\tif ((itr.writeIndex + spaceNeeded) > itr.size)\n\t\t{\n\t\t\t// wrap-around\n\t\t\tspaceNeeded = size;\n\t\t\talignmentPadding = 0;\n\t\t\t// check if there is enough space in current buffer after wrap-around\n\t\t\tif (!itr.queue_syncPoints.empty())\n\t\t\t{\n\t\t\t\tdistanceToSyncPoint = itr.queue_syncPoints.front().offset - 0;\n\t\t\t\tif (spaceNeeded > distanceToSyncPoint)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (spaceNeeded > itr.size)\n\t\t\t\tcontinue;\n\t\t\titr.writeIndex = 0;\n\t\t}\n\t\taddUploadBufferSyncPoint(itr, itr.writeIndex);\n\t\titr.writeIndex += alignmentPadding;\n\t\tuint32 offset = itr.writeIndex;\n\t\titr.writeIndex += size;\n\t\titr.cleanupCounter = 0;\n\t\tMetalSynchronizedRingAllocator::AllocatorReservation_t res;\n\t\tres.mtlBuffer = itr.mtlBuffer;\n\t\tres.memPtr = itr.basePtr + offset;\n\t\tres.bufferOffset = offset;\n\t\tres.size = size;\n\t\tres.bufferIndex = itr.index;\n\n\t\treturn res;\n\t}\n\n\t// allocate new buffer\n\tallocateAdditionalUploadBuffer(size);\n\n\treturn AllocateBufferMemory(size, alignment);\n}\n\nvoid MetalSynchronizedRingAllocator::FlushReservation(AllocatorReservation_t& uploadReservation)\n{\n    if (RequiresFlush())\n    {\n        uploadReservation.mtlBuffer->didModifyRange(NS::Range(uploadReservation.bufferOffset, uploadReservation.size));\n    }\n}\n\nvoid MetalSynchronizedRingAllocator::CleanupBuffer(MTL::CommandBuffer* latestFinishedCommandBuffer)\n{\n\tfor (auto& itr : m_buffers)\n\t{\n\t\twhile (!itr.queue_syncPoints.empty() && latestFinishedCommandBuffer == itr.queue_syncPoints.front().commandBuffer)\n\t\t{\n\t\t\titr.queue_syncPoints.pop();\n\t\t}\n\t\tif (itr.queue_syncPoints.empty())\n\t\t\titr.cleanupCounter++;\n\t}\n\n\t// check if last buffer is available for deletion\n\tif (m_buffers.size() >= 2)\n\t{\n\t\tauto& lastBuffer = m_buffers.back();\n\t\tif (lastBuffer.cleanupCounter >= 1000)\n\t\t{\n\t\t\t// release buffer\n\t\t\tlastBuffer.mtlBuffer->release();\n\t\t\tm_buffers.pop_back();\n\t\t}\n\t}\n}\n\nMTL::Buffer* MetalSynchronizedRingAllocator::GetBufferByIndex(uint32 index) const\n{\n\treturn m_buffers[index].mtlBuffer;\n}\n\nvoid MetalSynchronizedRingAllocator::GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const\n{\n\tnumBuffers = (uint32)m_buffers.size();\n\ttotalBufferSize = 0;\n\tfreeBufferSize = 0;\n\tfor (auto& itr : m_buffers)\n\t{\n\t\ttotalBufferSize += itr.size;\n\t\t// calculate free space in buffer\n\t\tuint32 distanceToSyncPoint;\n\t\tif (!itr.queue_syncPoints.empty())\n\t\t{\n\t\t\tif (itr.queue_syncPoints.front().offset < itr.writeIndex)\n\t\t\t\tdistanceToSyncPoint = (itr.size - itr.writeIndex) + itr.queue_syncPoints.front().offset; // size with wrap-around\n\t\t\telse\n\t\t\t\tdistanceToSyncPoint = itr.queue_syncPoints.front().offset - itr.writeIndex;\n\t\t}\n\t\telse\n\t\t\tdistanceToSyncPoint = itr.size;\n\t\tfreeBufferSize += distanceToSyncPoint;\n\t}\n}\n\n/* MetalSynchronizedHeapAllocator */\n\nMetalSynchronizedHeapAllocator::AllocatorReservation* MetalSynchronizedHeapAllocator::AllocateBufferMemory(uint32 size, uint32 alignment)\n{\n\tCHAddr addr = m_chunkedHeap.alloc(size, alignment);\n\tm_activeAllocations.emplace_back(addr);\n\tAllocatorReservation* res = m_poolAllocatorReservation.allocObj();\n\tres->bufferIndex = addr.chunkIndex;\n\tres->bufferOffset = addr.offset;\n\tres->size = size;\n\tres->mtlBuffer = m_chunkedHeap.GetBufferByIndex(addr.chunkIndex);\n\tres->memPtr = m_chunkedHeap.GetChunkPtr(addr.chunkIndex) + addr.offset;\n\n\treturn res;\n}\n\nvoid MetalSynchronizedHeapAllocator::FreeReservation(AllocatorReservation* uploadReservation)\n{\n\t// put the allocation on a delayed release queue for the current command buffer\n\tMTL::CommandBuffer* currentCommandBuffer = m_mtlr->GetCurrentCommandBuffer();\n\tauto it = std::find_if(m_activeAllocations.begin(), m_activeAllocations.end(), [&uploadReservation](const TrackedAllocation& allocation) { return allocation.allocation.chunkIndex == uploadReservation->bufferIndex && allocation.allocation.offset == uploadReservation->bufferOffset; });\n\tcemu_assert_debug(it != m_activeAllocations.end());\n\tm_releaseQueue[currentCommandBuffer].emplace_back(it->allocation);\n\tm_activeAllocations.erase(it);\n\tm_poolAllocatorReservation.freeObj(uploadReservation);\n}\n\nvoid MetalSynchronizedHeapAllocator::FlushReservation(AllocatorReservation* uploadReservation)\n{\n\tif (m_chunkedHeap.RequiresFlush())\n\t{\n\t    uploadReservation->mtlBuffer->didModifyRange(NS::Range(uploadReservation->bufferOffset, uploadReservation->size));\n\t}\n}\n\nvoid MetalSynchronizedHeapAllocator::CleanupBuffer(MTL::CommandBuffer* latestFinishedCommandBuffer)\n{\n    auto it = m_releaseQueue.find(latestFinishedCommandBuffer);\n    if (it == m_releaseQueue.end())\n        return;\n\n    // release allocations\n\tfor (auto& addr : it->second)\n\t\tm_chunkedHeap.free(addr);\n\tm_releaseQueue.erase(it);\n}\n\nvoid MetalSynchronizedHeapAllocator::GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const\n{\n\tm_chunkedHeap.GetStats(numBuffers, totalBufferSize, freeBufferSize);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalBufferAllocator.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Metal/MTLResource.hpp\"\n#include \"util/ChunkedHeap/ChunkedHeap.h\"\n#include \"util/helpers/MemoryPool.h\"\n\n#include <utility>\n\ninline MTL::ResourceOptions GetResourceOptions(MTL::ResourceOptions options)\n{\n    if (options & MTL::ResourceStorageModeShared || options & MTL::ResourceStorageModeManaged)\n        options |= MTL::ResourceCPUCacheModeWriteCombined;\n\n    return options;\n}\n\nclass MetalBufferChunkedHeap : private ChunkedHeap<>\n{\n  public:\n\tMetalBufferChunkedHeap(const class MetalRenderer* mtlRenderer, MTL::ResourceOptions options, size_t minimumBufferAllocationSize) : m_mtlr(mtlRenderer), m_options(GetResourceOptions(options)), m_minimumBufferAllocationSize(minimumBufferAllocationSize) { };\n\t~MetalBufferChunkedHeap();\n\n\tusing ChunkedHeap::alloc;\n\tusing ChunkedHeap::free;\n\n\tuint8* GetChunkPtr(uint32 index) const\n\t{\n\t\tif (index >= m_chunkBuffers.size())\n\t\t\treturn nullptr;\n\n\t\treturn (uint8*)m_chunkBuffers[index]->contents();\n\t}\n\n\tMTL::Buffer* GetBufferByIndex(uint32 index) const\n    {\n        cemu_assert_debug(index < m_chunkBuffers.size());\n\n        return m_chunkBuffers[index];\n    }\n\n    bool RequiresFlush() const\n    {\n        return m_options & MTL::ResourceStorageModeManaged;\n    }\n\n\tvoid GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const\n\t{\n\t\tnumBuffers = m_chunkBuffers.size();\n\t\ttotalBufferSize = m_numHeapBytes;\n\t\tfreeBufferSize = m_numHeapBytes - m_numAllocatedBytes;\n\t}\n\n  private:\n\tuint32 allocateNewChunk(uint32 chunkIndex, uint32 minimumAllocationSize) override;\n\n\tconst class MetalRenderer* m_mtlr;\n\n\tMTL::ResourceOptions m_options;\n\tsize_t m_minimumBufferAllocationSize;\n\n\tstd::vector<MTL::Buffer*> m_chunkBuffers;\n};\n\n// a circular ring-buffer which tracks and releases memory per command-buffer\nclass MetalSynchronizedRingAllocator\n{\npublic:\n\tMetalSynchronizedRingAllocator(class MetalRenderer* mtlRenderer, MTL::ResourceOptions options, uint32 minimumBufferAllocSize) : m_mtlr(mtlRenderer), m_options(GetResourceOptions(options)), m_minimumBufferAllocSize(minimumBufferAllocSize) {};\n\tMetalSynchronizedRingAllocator(const MetalSynchronizedRingAllocator&) = delete; // disallow copy\n\n\tstruct BufferSyncPoint_t\n\t{\n\t\t// todo - modularize sync point\n\t\tMTL::CommandBuffer* commandBuffer;\n\t\tuint32 offset;\n\n\t\tBufferSyncPoint_t(MTL::CommandBuffer* _commandBuffer, uint32 _offset) : commandBuffer(_commandBuffer), offset(_offset) {};\n\t};\n\n\tstruct AllocatorBuffer_t\n\t{\n\t\tMTL::Buffer* mtlBuffer;\n\t\tuint8* basePtr;\n\t\tuint32 size;\n\t\tuint32 writeIndex;\n\t\tstd::queue<BufferSyncPoint_t> queue_syncPoints;\n\t\tMTL::CommandBuffer* lastSyncpointCommandBuffer{ nullptr };\n\t\tuint32 index;\n\t\tuint32 cleanupCounter{ 0 }; // increased by one every time CleanupBuffer() is called if there is no sync point. If it reaches 300 then the buffer is released\n\t};\n\n\tstruct AllocatorReservation_t\n\t{\n\t\tMTL::Buffer* mtlBuffer;\n\t\tuint8* memPtr;\n\t\tuint32 bufferOffset;\n\t\tuint32 size;\n\t\tuint32 bufferIndex;\n\t};\n\n\tAllocatorReservation_t AllocateBufferMemory(uint32 size, uint32 alignment);\n\tvoid FlushReservation(AllocatorReservation_t& uploadReservation);\n\tvoid CleanupBuffer(MTL::CommandBuffer* latestFinishedCommandBuffer);\n\tMTL::Buffer* GetBufferByIndex(uint32 index) const;\n\n    bool RequiresFlush() const\n    {\n        return m_options & MTL::ResourceStorageModeManaged;\n    }\n\n\tvoid GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const;\n\nprivate:\n\tvoid allocateAdditionalUploadBuffer(uint32 sizeRequiredForAlloc);\n\tvoid addUploadBufferSyncPoint(AllocatorBuffer_t& buffer, uint32 offset);\n\n\tconst class MetalRenderer* m_mtlr;\n\n\tMTL::ResourceOptions m_options;\n\tconst uint32 m_minimumBufferAllocSize;\n\n\tstd::vector<AllocatorBuffer_t> m_buffers;\n};\n\n// heap style allocator with released memory being freed after the current command buffer finishes\nclass MetalSynchronizedHeapAllocator\n{\n\tstruct TrackedAllocation\n\t{\n\t\tTrackedAllocation(CHAddr allocation) : allocation(allocation) {};\n\t\tCHAddr allocation;\n\t};\n\n  public:\n\tMetalSynchronizedHeapAllocator(class MetalRenderer* mtlRenderer, MTL::ResourceOptions options, size_t minimumBufferAllocSize) : m_mtlr(mtlRenderer), m_chunkedHeap(m_mtlr, options, minimumBufferAllocSize) {}\n\tMetalSynchronizedHeapAllocator(const MetalSynchronizedHeapAllocator&) = delete; // disallow copy\n\n\tstruct AllocatorReservation\n\t{\n\t\tMTL::Buffer* mtlBuffer;\n\t\tuint8* memPtr;\n\t\tuint32 bufferOffset;\n\t\tuint32 size;\n\t\tuint32 bufferIndex;\n\t};\n\n\tAllocatorReservation* AllocateBufferMemory(uint32 size, uint32 alignment);\n\tvoid FreeReservation(AllocatorReservation* uploadReservation);\n\tvoid FlushReservation(AllocatorReservation* uploadReservation);\n\n\tvoid CleanupBuffer(MTL::CommandBuffer* latestFinishedCommandBuffer);\n\n\tvoid GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const;\n  private:\n\tconst class MetalRenderer* m_mtlr;\n\tMetalBufferChunkedHeap m_chunkedHeap;\n\t// allocations\n\tstd::vector<TrackedAllocation> m_activeAllocations;\n\tMemoryPool<AllocatorReservation> m_poolAllocatorReservation{32};\n\t// release queue\n\tstd::unordered_map<MTL::CommandBuffer*, std::vector<CHAddr>> m_releaseQueue;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalCommon.h",
    "content": "#pragma once\n\n#include <Foundation/Foundation.hpp>\n#include <Metal/Metal.hpp>\n\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n\nstruct MetalPixelFormatSupport\n{\n\tbool m_supportsR8Unorm_sRGB;\n\tbool m_supportsRG8Unorm_sRGB;\n\tbool m_supportsPacked16BitFormats;\n\tbool m_supportsDepth24Unorm_Stencil8;\n\n\tMetalPixelFormatSupport() = default;\n\tMetalPixelFormatSupport(MTL::Device* device)\n\t{\n        m_supportsR8Unorm_sRGB = device->supportsFamily(MTL::GPUFamilyApple1);\n        m_supportsRG8Unorm_sRGB = device->supportsFamily(MTL::GPUFamilyApple1);\n        m_supportsPacked16BitFormats = device->supportsFamily(MTL::GPUFamilyApple1);\n        m_supportsDepth24Unorm_Stencil8 = device->depth24Stencil8PixelFormatSupported();\n\t}\n};\n\n// TODO: don't define a new struct for this\nstruct MetalQueryRange\n{\n    uint32 begin;\n\tuint32 end;\n};\n\n#define MAX_MTL_BUFFERS 31\n// Buffer indices 28-30 are reserved for the helper shaders\n#define MTL_RESERVED_BUFFERS 3\n#define MAX_MTL_VERTEX_BUFFERS (MAX_MTL_BUFFERS - MTL_RESERVED_BUFFERS)\n#define GET_MTL_VERTEX_BUFFER_INDEX(index) (MAX_MTL_VERTEX_BUFFERS - index - 1)\n\n#define MAX_MTL_TEXTURES 31\n#define MAX_MTL_SAMPLERS 16\n\n#define GET_HELPER_BUFFER_BINDING(index) (28 + index)\n#define GET_HELPER_TEXTURE_BINDING(index) (29 + index)\n#define GET_HELPER_SAMPLER_BINDING(index) (14 + index)\n\nconstexpr uint32 INVALID_UINT32 = std::numeric_limits<uint32>::max();\nconstexpr size_t INVALID_OFFSET = std::numeric_limits<size_t>::max();\n\ninline size_t Align(size_t size, size_t alignment)\n{\n    return (size + alignment - 1) & ~(alignment - 1);\n}\n\n__attribute__((unused)) static inline void StackAutoRelease(void* object)\n{\n    (*(NS::Object**)object)->release();\n}\n\n#define NS_STACK_SCOPED __attribute__((cleanup(StackAutoRelease))) __attribute__((unused))\n\n// Cast from const char* to NS::String*\ninline NS::String* ToNSString(const char* str)\n{\n    return NS::String::string(str, NS::ASCIIStringEncoding);\n}\n\n// Cast from std::string to NS::String*\ninline NS::String* ToNSString(const std::string& str)\n{\n    return ToNSString(str.c_str());\n}\n\n// Cast from const char* to NS::URL*\ninline NS::URL* ToNSURL(const char* str)\n{\n    return NS::URL::fileURLWithPath(ToNSString(str));\n}\n\n// Cast from std::string to NS::URL*\ninline NS::URL* ToNSURL(const std::string& str)\n{\n    return ToNSURL(str.c_str());\n}\n\ninline NS::String* GetLabel(const std::string& label, const void* identifier)\n{\n    return ToNSString(label + \" (\" + std::to_string(reinterpret_cast<uintptr_t>(identifier)) + \")\");\n}\n\nconstexpr MTL::RenderStages ALL_MTL_RENDER_STAGES = MTL::RenderStageVertex | MTL::RenderStageObject | MTL::RenderStageMesh | MTL::RenderStageFragment;\n\ninline bool IsValidDepthTextureType(Latte::E_DIM dim)\n{\n    return (dim == Latte::E_DIM::DIM_2D || dim == Latte::E_DIM::DIM_2D_MSAA || dim == Latte::E_DIM::DIM_2D_ARRAY || dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA || dim == Latte::E_DIM::DIM_CUBEMAP);\n}\n\ninline bool CommandBufferCompleted(MTL::CommandBuffer* commandBuffer)\n{\n    auto status = commandBuffer->status();\n    return (status == MTL::CommandBufferStatusCompleted || status == MTL::CommandBufferStatusError);\n}\n\ninline bool FormatIsRenderable(Latte::E_GX2SURFFMT format)\n{\n    return !Latte::IsCompressedFormat(format);\n}\n\ntemplate <typename... T>\ninline bool executeCommand(fmt::format_string<T...> fmt, T&&... args) {\n    std::string command = fmt::format(fmt, std::forward<T>(args)...);\n    int res = system(command.c_str());\n    if (res != 0)\n    {\n        cemuLog_log(LogType::Force, \"command \\\"{}\\\" failed with exit code {}\", command, res);\n        return false;\n    }\n\n    return true;\n}\n\n/*\nclass MemoryMappedFile\n{\npublic:\n    MemoryMappedFile(const std::string& filePath)\n    {\n        // Open the file\n        m_fd = open(filePath.c_str(), O_RDONLY);\n        if (m_fd == -1) {\n            cemuLog_log(LogType::Force, \"failed to open file: {}\", filePath);\n            return;\n        }\n\n        // Get the file size\n        // Use a loop to handle the case where the file size is 0 (more of a safety net)\n        struct stat fileStat;\n        while (true)\n        {\n            if (fstat(m_fd, &fileStat) == -1)\n            {\n                close(m_fd);\n                cemuLog_log(LogType::Force, \"failed to get file size: {}\", filePath);\n                return;\n            }\n            m_fileSize = fileStat.st_size;\n\n            if (m_fileSize == 0)\n            {\n                cemuLog_logOnce(LogType::Force, \"file size is 0: {}\", filePath);\n                std::this_thread::sleep_for(std::chrono::milliseconds(10));\n                continue;\n            }\n\n            break;\n        }\n\n        // Memory map the file\n        m_data = mmap(nullptr, m_fileSize, PROT_READ, MAP_PRIVATE, m_fd, 0);\n        if (m_data == MAP_FAILED)\n        {\n            close(m_fd);\n            cemuLog_log(LogType::Force, \"failed to memory map file: {}\", filePath);\n            return;\n        }\n    }\n\n    ~MemoryMappedFile()\n    {\n        if (m_data && m_data != MAP_FAILED)\n            munmap(m_data, m_fileSize);\n\n        if (m_fd != -1)\n            close(m_fd);\n    }\n\n    uint8* data() const { return static_cast<uint8*>(m_data); }\n    size_t size() const { return m_fileSize; }\n\nprivate:\n    int m_fd = -1;\n    void* m_data = nullptr;\n    size_t m_fileSize = 0;\n};\n*/\n\ninline uint32 GetVerticesPerPrimitive(LattePrimitiveMode primitiveMode)\n{\n    switch (primitiveMode)\n    {\n    case LattePrimitiveMode::POINTS:\n        return 1;\n    case LattePrimitiveMode::LINES:\n        return 2;\n    case LattePrimitiveMode::LINE_STRIP:\n        // Same as line, but requires connection\n        return 2;\n    case LattePrimitiveMode::TRIANGLES:\n        return 3;\n    case LattePrimitiveMode::RECTS:\n        return 3;\n    default:\n        cemuLog_log(LogType::Force, \"Unimplemented primitive type {}\", primitiveMode);\n        return 0;\n    }\n}\n\ninline bool PrimitiveRequiresConnection(LattePrimitiveMode primitiveMode)\n{\n    if (primitiveMode == LattePrimitiveMode::LINE_STRIP)\n        return true;\n    else\n        return false;\n}\n\ninline bool UseRectEmulation(const LatteContextRegister& lcr) {\n    const LattePrimitiveMode primitiveMode = lcr.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();\n    return (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS);\n}\n\ninline bool UseGeometryShader(const LatteContextRegister& lcr, bool hasGeometryShader) {\n    return hasGeometryShader || UseRectEmulation(lcr);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalCppImpl.cpp",
    "content": "#define NS_PRIVATE_IMPLEMENTATION\n#define CA_PRIVATE_IMPLEMENTATION\n#define MTL_PRIVATE_IMPLEMENTATION\n#include <Foundation/Foundation.hpp>\n#include <QuartzCore/QuartzCore.hpp>\n#include <Metal/Metal.hpp>\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalDepthStencilCache.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalDepthStencilCache.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"HW/Latte/ISA/RegDefines.h\"\n#include \"HW/Latte/Renderer/Metal/LatteToMtl.h\"\n#include \"Metal/MTLDepthStencil.hpp\"\n\nMetalDepthStencilCache::~MetalDepthStencilCache()\n{\n    for (auto& pair : m_depthStencilCache)\n    {\n        pair.second->release();\n    }\n    m_depthStencilCache.clear();\n}\n\nMTL::DepthStencilState* MetalDepthStencilCache::GetDepthStencilState(const LatteContextRegister& lcr)\n{\n    uint64 stateHash = CalculateDepthStencilHash(lcr);\n    auto& depthStencilState = m_depthStencilCache[stateHash];\n    if (depthStencilState)\n        return depthStencilState;\n\n\t// Depth stencil state\n\tbool depthEnable = lcr.DB_DEPTH_CONTROL.get_Z_ENABLE();\n\tauto depthFunc = lcr.DB_DEPTH_CONTROL.get_Z_FUNC();\n\tbool depthWriteEnable = lcr.DB_DEPTH_CONTROL.get_Z_WRITE_ENABLE();\n\n\tNS_STACK_SCOPED MTL::DepthStencilDescriptor* desc = MTL::DepthStencilDescriptor::alloc()->init();\n\tif (depthEnable)\n\t{\n\t    desc->setDepthWriteEnabled(depthWriteEnable);\n\t    desc->setDepthCompareFunction(GetMtlCompareFunc(depthFunc));\n\t}\n\n\t// Stencil state\n\tbool stencilEnable = lcr.DB_DEPTH_CONTROL.get_STENCIL_ENABLE();\n\tif (stencilEnable)\n\t{\n\t    // get stencil control parameters\n    \tbool backStencilEnable = lcr.DB_DEPTH_CONTROL.get_BACK_STENCIL_ENABLE();\n    \tauto frontStencilFunc = lcr.DB_DEPTH_CONTROL.get_STENCIL_FUNC_F();\n    \tauto frontStencilZPass = lcr.DB_DEPTH_CONTROL.get_STENCIL_ZPASS_F();\n    \tauto frontStencilZFail = lcr.DB_DEPTH_CONTROL.get_STENCIL_ZFAIL_F();\n    \tauto frontStencilFail = lcr.DB_DEPTH_CONTROL.get_STENCIL_FAIL_F();\n    \tauto backStencilFunc = lcr.DB_DEPTH_CONTROL.get_STENCIL_FUNC_B();\n    \tauto backStencilZPass = lcr.DB_DEPTH_CONTROL.get_STENCIL_ZPASS_B();\n    \tauto backStencilZFail = lcr.DB_DEPTH_CONTROL.get_STENCIL_ZFAIL_B();\n    \tauto backStencilFail = lcr.DB_DEPTH_CONTROL.get_STENCIL_FAIL_B();\n    \t// get stencil control parameters\n    \tuint32 stencilCompareMaskFront = lcr.DB_STENCILREFMASK.get_STENCILMASK_F();\n    \tuint32 stencilWriteMaskFront = lcr.DB_STENCILREFMASK.get_STENCILWRITEMASK_F();\n    \tuint32 stencilCompareMaskBack = lcr.DB_STENCILREFMASK_BF.get_STENCILMASK_B();\n    \tuint32 stencilWriteMaskBack = lcr.DB_STENCILREFMASK_BF.get_STENCILWRITEMASK_B();\n\n    \tNS_STACK_SCOPED MTL::StencilDescriptor* frontStencil = MTL::StencilDescriptor::alloc()->init();\n    \tfrontStencil->setReadMask(stencilCompareMaskFront);\n    \tfrontStencil->setWriteMask(stencilWriteMaskFront);\n    \tfrontStencil->setStencilCompareFunction(GetMtlCompareFunc(frontStencilFunc));\n    \tfrontStencil->setDepthFailureOperation(GetMtlStencilOp(frontStencilZFail));\n    \tfrontStencil->setStencilFailureOperation(GetMtlStencilOp(frontStencilFail));\n    \tfrontStencil->setDepthStencilPassOperation(GetMtlStencilOp(frontStencilZPass));\n    \tdesc->setFrontFaceStencil(frontStencil);\n\n    \tNS_STACK_SCOPED MTL::StencilDescriptor* backStencil = MTL::StencilDescriptor::alloc()->init();\n    \tif (backStencilEnable)\n    \t{\n           \tbackStencil->setReadMask(stencilCompareMaskBack);\n           \tbackStencil->setWriteMask(stencilWriteMaskBack);\n           \tbackStencil->setStencilCompareFunction(GetMtlCompareFunc(backStencilFunc));\n           \tbackStencil->setDepthFailureOperation(GetMtlStencilOp(backStencilZFail));\n           \tbackStencil->setStencilFailureOperation(GetMtlStencilOp(backStencilFail));\n           \tbackStencil->setDepthStencilPassOperation(GetMtlStencilOp(backStencilZPass));\n    \t}\n    \telse\n    \t{\n           \tbackStencil->setReadMask(stencilCompareMaskFront);\n           \tbackStencil->setWriteMask(stencilWriteMaskFront);\n           \tbackStencil->setStencilCompareFunction(GetMtlCompareFunc(frontStencilFunc));\n           \tbackStencil->setDepthFailureOperation(GetMtlStencilOp(frontStencilZFail));\n           \tbackStencil->setStencilFailureOperation(GetMtlStencilOp(frontStencilFail));\n           \tbackStencil->setDepthStencilPassOperation(GetMtlStencilOp(frontStencilZPass));\n    \t}\n    \tdesc->setBackFaceStencil(backStencil);\n\t}\n\n\tdepthStencilState = m_mtlr->GetDevice()->newDepthStencilState(desc);\n\n\treturn depthStencilState;\n}\n\nuint64 MetalDepthStencilCache::CalculateDepthStencilHash(const LatteContextRegister& lcr)\n{\n    uint32* ctxRegister = lcr.GetRawView();\n\n    // Hash\n    uint64 stateHash = 0;\n    uint32 depthControl = ctxRegister[Latte::REGADDR::DB_DEPTH_CONTROL];\n\tbool stencilTestEnable = depthControl & 1;\n\tif (stencilTestEnable)\n\t{\n\t\tstateHash += ctxRegister[mmDB_STENCILREFMASK];\n\t\tstateHash = std::rotl<uint64>(stateHash, 17);\n\t\tif(depthControl & (1<<7)) // back stencil enable\n\t\t{\n\t\t\tstateHash += ctxRegister[mmDB_STENCILREFMASK_BF];\n\t\t\tstateHash = std::rotl<uint64>(stateHash, 13);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// zero out stencil related bits (8-31)\n\t\tdepthControl &= 0xFF;\n\t}\n\n\tstateHash = std::rotl<uint64>(stateHash, 17);\n\tstateHash += depthControl;\n\n\treturn stateHash;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalDepthStencilCache.h",
    "content": "#pragma once\n\n#include <Metal/Metal.hpp>\n\n#include \"HW/Latte/ISA/LatteReg.h\"\n\nclass MetalDepthStencilCache\n{\npublic:\n    MetalDepthStencilCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {}\n    ~MetalDepthStencilCache();\n\n    MTL::DepthStencilState* GetDepthStencilState(const LatteContextRegister& lcr);\n\nprivate:\n    class MetalRenderer* m_mtlr;\n\n    std::map<uint64, MTL::DepthStencilState*> m_depthStencilCache;\n\n    uint64 CalculateDepthStencilHash(const LatteContextRegister& lcr);\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalLayer.h",
    "content": "#pragma once\n\nvoid* CreateMetalLayer(void* handle, float& scaleX, float& scaleY);\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalLayer.mm",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalLayer.h\"\n\n#include \"Cafe/HW/Latte/Renderer/MetalView.h\"\n\nvoid* CreateMetalLayer(void* handle, float& scaleX, float& scaleY)\n{\n\tNSView* view = (NSView*)handle;\n\n\tMetalView* childView = [[MetalView alloc] initWithFrame:view.bounds];\n\tchildView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;\n\tchildView.wantsLayer = YES;\n\n\t[view addSubview:childView];\n\n\tconst NSRect points = [childView frame];\n    const NSRect pixels = [childView convertRectToBacking:points];\n\n\tscaleX = (float)(pixels.size.width / points.size.width);\n    scaleY = (float)(pixels.size.height / points.size.height);\n\n\treturn childView.layer;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalLayerHandle.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalLayerHandle.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalLayer.h\"\n\n#include \"gui/interface/WindowSystem.h\"\n\nMetalLayerHandle::MetalLayerHandle(MTL::Device* device, const Vector2i& size, bool mainWindow)\n{\n    const auto& windowInfo = (mainWindow ? WindowSystem::GetWindowInfo().window_main : WindowSystem::GetWindowInfo().window_pad);\n\n    m_layer = (CA::MetalLayer*)CreateMetalLayer(windowInfo.surface, m_layerScaleX, m_layerScaleY);\n    m_layer->setDevice(device);\n    m_layer->setDrawableSize(CGSize{(float)size.x * m_layerScaleX, (float)size.y * m_layerScaleY});\n    m_layer->setFramebufferOnly(true);\n}\n\nMetalLayerHandle::~MetalLayerHandle()\n{\n    if (m_layer)\n        m_layer->release();\n}\n\nvoid MetalLayerHandle::Resize(const Vector2i& size)\n{\n    m_layer->setDrawableSize(CGSize{(float)size.x * m_layerScaleX, (float)size.y * m_layerScaleY});\n}\n\nbool MetalLayerHandle::AcquireDrawable()\n{\n    if (m_drawable)\n        return true;\n\n    m_drawable = m_layer->nextDrawable();\n    if (!m_drawable)\n    {\n        cemuLog_log(LogType::Force, \"layer {} failed to acquire next drawable\", (void*)this);\n        return false;\n    }\n\n    return true;\n}\n\nvoid MetalLayerHandle::PresentDrawable(MTL::CommandBuffer* commandBuffer)\n{\n    commandBuffer->presentDrawable(m_drawable);\n    m_drawable = nullptr;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalLayerHandle.h",
    "content": "#pragma once\n\n#include <QuartzCore/QuartzCore.hpp>\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalCommon.h\"\n#include \"util/math/vector2.h\"\n\nclass MetalLayerHandle\n{\npublic:\n    MetalLayerHandle() = default;\n    MetalLayerHandle(MTL::Device* device, const Vector2i& size, bool mainWindow);\n\n    ~MetalLayerHandle();\n\n    void Resize(const Vector2i& size);\n\n    bool AcquireDrawable();\n\n    void PresentDrawable(MTL::CommandBuffer* commandBuffer);\n\n    CA::MetalLayer* GetLayer() const { return m_layer; }\n\n    CA::MetalDrawable* GetDrawable() const { return m_drawable; }\n\nprivate:\n    CA::MetalLayer* m_layer = nullptr;\n    float m_layerScaleX, m_layerScaleY;\n\n    CA::MetalDrawable* m_drawable = nullptr;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalCommon.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalVoidVertexPipeline.h\"\n\n#include \"CafeSystem.h\"\n#include \"Cemu/Logging/CemuLogging.h\"\n#include \"Common/precompiled.h\"\n#include \"HW/MMU/MMU.h\"\n#include \"config/CemuConfig.h\"\n\nMetalMemoryManager::~MetalMemoryManager()\n{\n    if (m_bufferCache)\n    {\n        m_bufferCache->release();\n    }\n}\n\nvoid* MetalMemoryManager::AcquireTextureUploadBuffer(size_t size)\n{\n    if (m_textureUploadBuffer.size() < size)\n    {\n        m_textureUploadBuffer.resize(size);\n    }\n\n    return m_textureUploadBuffer.data();\n}\n\nvoid MetalMemoryManager::ReleaseTextureUploadBuffer(uint8* mem)\n{\n    cemu_assert_debug(m_textureUploadBuffer.data() == mem);\n\tm_textureUploadBuffer.clear();\n}\n\nvoid MetalMemoryManager::InitBufferCache(size_t size)\n{\n    cemu_assert_debug(!m_bufferCache);\n\n    m_metalBufferCacheMode = g_current_game_profile->GetBufferCacheMode();\n\n    if (m_metalBufferCacheMode == MetalBufferCacheMode::Auto)\n    {\n        // TODO: do this for all unified memory systems?\n        if (m_mtlr->IsAppleGPU())\n        {\n            switch (CafeSystem::GetForegroundTitleId())\n            {\n            // The Legend of Zelda: Wind Waker HD\n            case 0x0005000010143600: // EUR\n            case 0x0005000010143500: // USA\n            case 0x0005000010143400: // JPN\n                // TODO: use host instead?\n                m_metalBufferCacheMode = MetalBufferCacheMode::DeviceShared;\n                break;\n            default:\n                m_metalBufferCacheMode = MetalBufferCacheMode::DevicePrivate;\n                break;\n            }\n        }\n        else\n        {\n            m_metalBufferCacheMode = MetalBufferCacheMode::DevicePrivate;\n        }\n    }\n\n    // First, try to import the host memory as a buffer\n    if (m_metalBufferCacheMode == MetalBufferCacheMode::Host)\n    {\n        if (m_mtlr->HasUnifiedMemory())\n        {\n            m_importedMemBaseAddress = mmuRange_MEM2.getBase();\n           \tm_hostAllocationSize = mmuRange_MEM2.getSize();\n            m_bufferCache = m_mtlr->GetDevice()->newBuffer(memory_getPointerFromVirtualOffset(m_importedMemBaseAddress), m_hostAllocationSize, MTL::ResourceStorageModeShared, nullptr);\n            if (!m_bufferCache)\n            {\n                cemuLog_log(LogType::Force, \"Failed to import host memory as a buffer, using device shared mode instead\");\n                m_metalBufferCacheMode = MetalBufferCacheMode::DeviceShared;\n            }\n        }\n        else\n        {\n            cemuLog_log(LogType::Force, \"Host buffer cache mode is only available on unified memory systems, using device shared mode instead\");\n            m_metalBufferCacheMode = MetalBufferCacheMode::DeviceShared;\n        }\n    }\n\n    if (!m_bufferCache)\n        m_bufferCache = m_mtlr->GetDevice()->newBuffer(size, (m_metalBufferCacheMode == MetalBufferCacheMode::DevicePrivate ? MTL::ResourceStorageModePrivate : MTL::ResourceStorageModeShared));\n\n#ifdef CEMU_DEBUG_ASSERT\n    m_bufferCache->setLabel(GetLabel(\"Buffer cache\", m_bufferCache));\n#endif\n}\n\nvoid MetalMemoryManager::UploadToBufferCache(const void* data, size_t offset, size_t size)\n{\n    cemu_assert_debug(m_metalBufferCacheMode != MetalBufferCacheMode::Host);\n    cemu_assert_debug(m_bufferCache);\n    cemu_assert_debug((offset + size) <= m_bufferCache->length());\n\n    if (m_metalBufferCacheMode == MetalBufferCacheMode::DevicePrivate)\n    {\n        auto blitCommandEncoder = m_mtlr->GetBlitCommandEncoder();\n\n        auto allocation = m_stagingAllocator.AllocateBufferMemory(size, 1);\n        memcpy(allocation.memPtr, data, size);\n        m_stagingAllocator.FlushReservation(allocation);\n\n        blitCommandEncoder->copyFromBuffer(allocation.mtlBuffer, allocation.bufferOffset, m_bufferCache, offset, size);\n\n        //m_mtlr->CopyBufferToBuffer(allocation.mtlBuffer, allocation.bufferOffset, m_bufferCache, offset, size, ALL_MTL_RENDER_STAGES, ALL_MTL_RENDER_STAGES);\n    }\n    else\n    {\n        memcpy((uint8*)m_bufferCache->contents() + offset, data, size);\n    }\n}\n\nvoid MetalMemoryManager::CopyBufferCache(size_t srcOffset, size_t dstOffset, size_t size)\n{\n    cemu_assert_debug(m_metalBufferCacheMode != MetalBufferCacheMode::Host);\n    cemu_assert_debug(m_bufferCache);\n\n    if (m_metalBufferCacheMode == MetalBufferCacheMode::DevicePrivate)\n        m_mtlr->CopyBufferToBuffer(m_bufferCache, srcOffset, m_bufferCache, dstOffset, size, ALL_MTL_RENDER_STAGES, ALL_MTL_RENDER_STAGES);\n    else\n        memcpy((uint8*)m_bufferCache->contents() + dstOffset, (uint8*)m_bufferCache->contents() + srcOffset, size);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalBufferAllocator.h\"\n\n#include \"GameProfile/GameProfile.h\"\n\nclass MetalMemoryManager\n{\npublic:\n    MetalMemoryManager(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer}, m_stagingAllocator(m_mtlr, m_mtlr->GetOptimalBufferStorageMode(), 32u * 1024 * 1024), m_indexAllocator(m_mtlr, m_mtlr->GetOptimalBufferStorageMode(), 4u * 1024 * 1024) {}\n    ~MetalMemoryManager();\n\n    MetalSynchronizedRingAllocator& GetStagingAllocator()\n    {\n        return m_stagingAllocator;\n    }\n\n    MetalSynchronizedHeapAllocator& GetIndexAllocator()\n    {\n        return m_indexAllocator;\n    }\n\n    MTL::Buffer* GetBufferCache()\n    {\n        return m_bufferCache;\n    }\n\n    void CleanupBuffers(MTL::CommandBuffer* latestFinishedCommandBuffer)\n    {\n        m_stagingAllocator.CleanupBuffer(latestFinishedCommandBuffer);\n        m_indexAllocator.CleanupBuffer(latestFinishedCommandBuffer);\n    }\n\n    // Texture upload buffer\n    void* AcquireTextureUploadBuffer(size_t size);\n    void ReleaseTextureUploadBuffer(uint8* mem);\n\n    // Buffer cache\n    void InitBufferCache(size_t size);\n    void UploadToBufferCache(const void* data, size_t offset, size_t size);\n    void CopyBufferCache(size_t srcOffset, size_t dstOffset, size_t size);\n\n    // Getters\n    bool UseHostMemoryForCache() const\n    {\n        return (m_metalBufferCacheMode == MetalBufferCacheMode::Host);\n    }\n\n    bool NeedsReducedLatency() const\n    {\n        return (m_metalBufferCacheMode == MetalBufferCacheMode::DeviceShared || m_metalBufferCacheMode == MetalBufferCacheMode::Host);\n    }\n\n    MPTR GetImportedMemBaseAddress() const\n    {\n        return m_importedMemBaseAddress;\n    }\n\n    size_t GetHostAllocationSize() const\n    {\n        return m_hostAllocationSize;\n    }\n\nprivate:\n    class MetalRenderer* m_mtlr;\n\n    std::vector<uint8> m_textureUploadBuffer;\n\n    MetalSynchronizedRingAllocator m_stagingAllocator;\n    MetalSynchronizedHeapAllocator m_indexAllocator;\n\n    MTL::Buffer* m_bufferCache = nullptr;\n    MetalBufferCacheMode m_metalBufferCacheMode;\n    MPTR m_importedMemBaseAddress;\n    size_t m_hostAllocationSize = 0;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h\"\n\nMetalOutputShaderCache::~MetalOutputShaderCache()\n{\n    for (uint8 i = 0; i < METAL_OUTPUT_SHADER_CACHE_SIZE; i++)\n    {\n        if (m_cache[i])\n            m_cache[i]->release();\n    }\n}\n\nMTL::RenderPipelineState* MetalOutputShaderCache::GetPipeline(RendererOutputShader* shader, uint8 shaderIndex, bool usesSRGB)\n{\n    uint8 cacheIndex = (usesSRGB ? METAL_SHADER_TYPE_COUNT : 0) + shaderIndex;\n    auto& renderPipelineState = m_cache[cacheIndex];\n    if (renderPipelineState)\n        return renderPipelineState;\n\n    // Create a new render pipeline state\n    auto vertexShaderMtl = static_cast<RendererShaderMtl*>(shader->GetVertexShader())->GetFunction();\n    auto fragmentShaderMtl = static_cast<RendererShaderMtl*>(shader->GetFragmentShader())->GetFunction();\n\n    NS_STACK_SCOPED auto renderPipelineDescriptor = MTL::RenderPipelineDescriptor::alloc()->init();\n    renderPipelineDescriptor->setVertexFunction(vertexShaderMtl);\n    renderPipelineDescriptor->setFragmentFunction(fragmentShaderMtl);\n    renderPipelineDescriptor->colorAttachments()->object(0)->setPixelFormat(usesSRGB ? MTL::PixelFormatBGRA8Unorm_sRGB : MTL::PixelFormatBGRA8Unorm);\n\n    NS::Error* error = nullptr;\n    renderPipelineState = m_mtlr->GetDevice()->newRenderPipelineState(renderPipelineDescriptor, &error);\n    if (error)\n    {\n        cemuLog_log(LogType::Force, \"error creating output render pipeline state: {}\", error->localizedDescription()->utf8String());\n    }\n\n    return renderPipelineState;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n\nconstexpr uint8 METAL_SHADER_TYPE_COUNT = 6;\nconstexpr uint8 METAL_OUTPUT_SHADER_CACHE_SIZE = 2 * METAL_SHADER_TYPE_COUNT;\n\nclass MetalOutputShaderCache\n{\npublic:\n    MetalOutputShaderCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {}\n    ~MetalOutputShaderCache();\n\n    MTL::RenderPipelineState* GetPipeline(RendererOutputShader* shader, uint8 shaderIndex, bool usesSRGB);\n\nprivate:\n    class MetalRenderer* m_mtlr;\n\n    MTL::RenderPipelineState* m_cache[METAL_OUTPUT_SHADER_CACHE_SIZE] = {nullptr};\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h",
    "content": "#pragma once\n\nclass MetalPerformanceMonitor\n{\npublic:\n    // Per frame data\n    uint32 m_commandBuffers = 0;\n    uint32 m_renderPasses = 0;\n    uint32 m_clears = 0;\n    uint32 m_manualVertexFetchDraws = 0;\n    uint32 m_meshDraws = 0;\n    uint32 m_triangleFans = 0;\n\n    MetalPerformanceMonitor() = default;\n    ~MetalPerformanceMonitor() = default;\n\n    void ResetPerFrameData()\n    {\n        m_commandBuffers = 0;\n        m_renderPasses = 0;\n        m_clears = 0;\n        m_manualVertexFetchDraws = 0;\n        m_meshDraws = 0;\n        m_triangleFans = 0;\n    }\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h\"\n\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Common/RegisterSerializer.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderCache.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cemu/FileCache/FileCache.h\"\n#include \"Common/precompiled.h\"\n#include \"util/helpers/helpers.h\"\n#include \"config/ActiveSettings.h\"\n\n#include <openssl/sha.h>\n\nstatic bool g_compilePipelineThreadInit{false};\nstatic std::mutex g_compilePipelineMutex;\nstatic std::condition_variable g_compilePipelineCondVar;\nstatic std::queue<MetalPipelineCompiler*> g_compilePipelineRequests;\n\nstatic void compileThreadFunc(sint32 threadIndex)\n{\n\tSetThreadName(\"compilePl\");\n\n\t// one thread runs at normal priority while the others run at lower priority\n\tif (threadIndex != 0)\n\t\t; // TODO: set thread priority\n\n\twhile (true)\n\t{\n\t\tstd::unique_lock lock(g_compilePipelineMutex);\n\t\twhile (g_compilePipelineRequests.empty())\n\t\t\tg_compilePipelineCondVar.wait(lock);\n\n\t\tMetalPipelineCompiler* request = g_compilePipelineRequests.front();\n\n\t\tg_compilePipelineRequests.pop();\n\n\t\tlock.unlock();\n\n\t\trequest->Compile(true, false, true);\n\t\tdelete request;\n\t}\n}\n\nstatic void initCompileThread()\n{\n\tuint32 numCompileThreads;\n\n\tuint32 cpuCoreCount = GetPhysicalCoreCount();\n\tif (cpuCoreCount <= 2)\n\t\tnumCompileThreads = 1;\n\telse\n\t\tnumCompileThreads = 2 + (cpuCoreCount - 3); // 2 plus one additionally for every extra core above 3\n\n\tnumCompileThreads = std::min(numCompileThreads, 8u); // cap at 8\n\n\tfor (uint32 i = 0; i < numCompileThreads; i++)\n\t{\n\t\tstd::thread compileThread(compileThreadFunc, i);\n\t\tcompileThread.detach();\n\t}\n}\n\nstatic void queuePipeline(MetalPipelineCompiler* v)\n{\n\tstd::unique_lock lock(g_compilePipelineMutex);\n\tg_compilePipelineRequests.push(std::move(v));\n\tlock.unlock();\n\tg_compilePipelineCondVar.notify_one();\n}\n\n// make a guess if a pipeline is not essential\n// non-essential means that skipping these drawcalls shouldn't lead to permanently corrupted graphics\nbool IsAsyncPipelineAllowed(const MetalAttachmentsInfo& attachmentsInfo, Vector2i extend, uint32 indexCount)\n{\n\tif (extend.x == 1600 && extend.y == 1600)\n\t\treturn false; // Splatoon ink mechanics use 1600x1600 R8 and R8G8 framebuffers, this resolution is rare enough that we can just blacklist it globally\n\n\tif (attachmentsInfo.depthFormat != Latte::E_GX2SURFFMT::INVALID_FORMAT)\n\t\treturn true; // aggressive filter but seems to work well so far\n\n\t// small index count (3,4,5,6) is often associated with full-viewport quads (which are considered essential due to often being used to generate persistent textures)\n\tif (indexCount <= 6)\n\t\treturn false;\n\n\treturn true;\n}\n\nMetalPipelineCache* g_mtlPipelineCache = nullptr;\n\nMetalPipelineCache& MetalPipelineCache::GetInstance()\n{\n    return *g_mtlPipelineCache;\n}\n\nMetalPipelineCache::MetalPipelineCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer}\n{\n    g_mtlPipelineCache = this;\n}\n\nMetalPipelineCache::~MetalPipelineCache()\n{\n    for (auto& [key, pipelineObj] : m_pipelineCache)\n    {\n        pipelineObj->m_pipeline->release();\n        delete pipelineObj;\n    }\n}\n\nPipelineObject* MetalPipelineCache::GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, Vector2i extend, uint32 indexCount, const LatteContextRegister& lcr)\n{\n    uint64 hash = CalculatePipelineHash(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedAttachmentsInfo, activeAttachmentsInfo, lcr);\n    PipelineObject*& pipelineObj = m_pipelineCache[hash];\n    if (pipelineObj)\n        return pipelineObj;\n\n    pipelineObj = new PipelineObject();\n\n    MetalPipelineCompiler* compiler = new MetalPipelineCompiler(m_mtlr, *pipelineObj);\n    compiler->InitFromState(fetchShader, vertexShader, geometryShader, pixelShader, lastUsedAttachmentsInfo, activeAttachmentsInfo, lcr);\n\n    bool allowAsyncCompile = false;\n    if (GetConfig().async_compile)\n\t\tallowAsyncCompile = IsAsyncPipelineAllowed(activeAttachmentsInfo, extend, indexCount);\n\n\tif (allowAsyncCompile)\n\t{\n\t    if (!g_compilePipelineThreadInit)\n\t\t{\n\t\t\tinitCompileThread();\n\t\t\tg_compilePipelineThreadInit = true;\n\t\t}\n\n\t\tqueuePipeline(compiler);\n\t}\n\telse\n\t{\n\t    // Also force compile to ensure that the pipeline is ready\n        cemu_assert_debug(compiler->Compile(true, true, true));\n        delete compiler;\n\t}\n\n\t// Save to cache\n    AddCurrentStateToCache(hash, lastUsedAttachmentsInfo);\n\n    return pipelineObj;\n}\n\nuint64 MetalPipelineCache::CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr)\n{\n    // Hash\n    uint64 stateHash = 0;\n    for (int i = 0; i < Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS; ++i)\n\t{\n\t    Latte::E_GX2SURFFMT format = lastUsedAttachmentsInfo.colorFormats[i];\n\t\tif (format == Latte::E_GX2SURFFMT::INVALID_FORMAT)\n            continue;\n\n\t\tstateHash += GetMtlPixelFormat(format, false) + i * 31;\n\t\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\t\tif (activeAttachmentsInfo.colorFormats[i] == Latte::E_GX2SURFFMT::INVALID_FORMAT)\n\t\t{\n            stateHash += 1;\n\t\t    stateHash = std::rotl<uint64>(stateHash, 1);\n\t\t}\n\t}\n\n\tif (lastUsedAttachmentsInfo.depthFormat != Latte::E_GX2SURFFMT::INVALID_FORMAT)\n\t{\n\t\tstateHash += GetMtlPixelFormat(lastUsedAttachmentsInfo.depthFormat, true);\n\t\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\t\tif (activeAttachmentsInfo.depthFormat == Latte::E_GX2SURFFMT::INVALID_FORMAT)\n\t\t{\n            stateHash += 1;\n\t\t    stateHash = std::rotl<uint64>(stateHash, 1);\n\t\t}\n\t}\n\n\tfor (auto& group : fetchShader->bufferGroups)\n\t{\n\t\tuint32 bufferStride = group.getCurrentBufferStride(lcr.GetRawView());\n\t\tstateHash = std::rotl<uint64>(stateHash, 7);\n\t\tstateHash += bufferStride * 3;\n\t}\n\n\tstateHash += fetchShader->getVkPipelineHashFragment();\n\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\tstateHash += lcr.GetRawView()[mmVGT_STRMOUT_EN];\n\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\tif(lcr.PA_CL_CLIP_CNTL.get_DX_RASTERIZATION_KILL())\n\t\tstateHash += 0x333333;\n\n\tstateHash = (stateHash >> 8) + (stateHash * 0x370531ull) % 0x7F980D3BF9B4639Dull;\n\n\tuint32* ctxRegister = lcr.GetRawView();\n\n\tif (vertexShader)\n\t\tstateHash += vertexShader->baseHash;\n\n\tstateHash = std::rotl<uint64>(stateHash, 13);\n\n\tif (pixelShader)\n\t\tstateHash += pixelShader->baseHash + pixelShader->auxHash;\n\n\tstateHash = std::rotl<uint64>(stateHash, 13);\n\n\tuint32 polygonCtrl = lcr.PA_SU_SC_MODE_CNTL.getRawValue();\n\tstateHash += polygonCtrl;\n\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\tstateHash += ctxRegister[Latte::REGADDR::PA_CL_CLIP_CNTL];\n\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\tconst auto colorControlReg = ctxRegister[Latte::REGADDR::CB_COLOR_CONTROL];\n\tstateHash += colorControlReg;\n\n\tstateHash += ctxRegister[Latte::REGADDR::CB_TARGET_MASK];\n\n\tconst uint32 blendEnableMask = (colorControlReg >> 8) & 0xFF;\n\tif (blendEnableMask)\n\t{\n\t\tfor (auto i = 0; i < 8; ++i)\n\t\t{\n\t\t\tif (((blendEnableMask & (1 << i))) == 0)\n\t\t\t\tcontinue;\n\t\t\tstateHash = std::rotl<uint64>(stateHash, 7);\n\t\t\tstateHash += ctxRegister[Latte::REGADDR::CB_BLEND0_CONTROL + i];\n\t\t}\n\t}\n\n\t// Mesh pipeline\n\tconst LattePrimitiveMode primitiveMode = static_cast<LattePrimitiveMode>(LatteGPUState.contextRegister[mmVGT_PRIMITIVE_TYPE]);\n    bool isPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS);\n\n    bool usesGeometryShader = (geometryShader != nullptr || isPrimitiveRect);\n\n    if (usesGeometryShader)\n    {\n        stateHash += lcr.GetRawView()[mmVGT_PRIMITIVE_TYPE];\n        stateHash = std::rotl<uint64>(stateHash, 7);\n    }\n\n\treturn stateHash;\n}\n\nstruct\n{\n\tuint32 pipelineLoadIndex;\n\tuint32 pipelineMaxFileIndex;\n\n\tstd::atomic_uint32_t pipelinesQueued;\n\tstd::atomic_uint32_t pipelinesLoaded;\n} g_mtlCacheState;\n\nuint32 MetalPipelineCache::BeginLoading(uint64 cacheTitleId)\n{\n\tstd::error_code ec;\n\tfs::create_directories(ActiveSettings::GetCachePath(\"shaderCache/transferable\"), ec);\n\tconst auto pathCacheFile = ActiveSettings::GetCachePath(\"shaderCache/transferable/{:016x}_mtlpipeline.bin\", cacheTitleId);\n\n\t// init cache loader state\n\tg_mtlCacheState.pipelineLoadIndex = 0;\n\tg_mtlCacheState.pipelineMaxFileIndex = 0;\n\tg_mtlCacheState.pipelinesLoaded = 0;\n\tg_mtlCacheState.pipelinesQueued = 0;\n\n\t// start async compilation threads\n\tm_compilationCount.store(0);\n\tm_compilationQueue.clear();\n\n\t// get core count\n\tuint32 cpuCoreCount = GetPhysicalCoreCount();\n\tm_numCompilationThreads = std::clamp(cpuCoreCount, 1u, 8u);\n\t// TODO: uncomment?\n\t//if (VulkanRenderer::GetInstance()->GetDisableMultithreadedCompilation())\n\t//\tm_numCompilationThreads = 1;\n\n\tfor (uint32 i = 0; i < m_numCompilationThreads; i++)\n\t{\n\t\tstd::thread compileThread(&MetalPipelineCache::CompilerThread, this);\n\t\tcompileThread.detach();\n\t}\n\n\t// open cache file or create it\n\tcemu_assert_debug(s_cache == nullptr);\n\ts_cache = FileCache::Open(pathCacheFile, true, LatteShaderCache_getPipelineCacheExtraVersion(cacheTitleId));\n\tif (!s_cache)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to open or create Metal pipeline cache file: {}\", _pathToUtf8(pathCacheFile));\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\ts_cache->UseCompression(false);\n\t\tg_mtlCacheState.pipelineMaxFileIndex = s_cache->GetMaximumFileIndex();\n\t}\n\treturn s_cache->GetFileCount();\n}\n\nbool MetalPipelineCache::UpdateLoading(uint32& pipelinesLoadedTotal, uint32& pipelinesMissingShaders)\n{\n\tpipelinesLoadedTotal = g_mtlCacheState.pipelinesLoaded;\n\tpipelinesMissingShaders = 0;\n\twhile (g_mtlCacheState.pipelineLoadIndex <= g_mtlCacheState.pipelineMaxFileIndex)\n\t{\n\t\tif (m_compilationQueue.size() >= 50)\n\t\t{\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t\treturn true; // queue up to 50 entries at a time\n\t\t}\n\n\t\tuint64 fileNameA, fileNameB;\n\t\tstd::vector<uint8> fileData;\n\t\tif (s_cache->GetFileByIndex(g_mtlCacheState.pipelineLoadIndex, &fileNameA, &fileNameB, fileData))\n\t\t{\n\t\t\t// queue for async compilation\n\t\t\tg_mtlCacheState.pipelinesQueued++;\n\t\t\tm_compilationQueue.push(std::move(fileData));\n\t\t\tg_mtlCacheState.pipelineLoadIndex++;\n\t\t\treturn true;\n\t\t}\n\t\tg_mtlCacheState.pipelineLoadIndex++;\n\t}\n\tif (g_mtlCacheState.pipelinesLoaded != g_mtlCacheState.pipelinesQueued)\n\t{\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\treturn true; // pipelines still compiling\n\t}\n\treturn false; // done\n}\n\nvoid MetalPipelineCache::EndLoading()\n{\n\t// shut down compilation threads\n\tuint32 threadCount = m_numCompilationThreads;\n\tm_numCompilationThreads = 0; // signal thread shutdown\n\tfor (uint32 i = 0; i < threadCount; i++)\n\t{\n\t\tm_compilationQueue.push({}); // push empty workload for every thread. Threads then will shutdown after checking for m_numCompilationThreads == 0\n\t}\n\t// keep cache file open for writing of new pipelines\n}\n\nvoid MetalPipelineCache::Close()\n{\n    if(s_cache)\n    {\n        delete s_cache;\n        s_cache = nullptr;\n    }\n}\n\nstruct CachedPipeline\n{\n\tstruct ShaderHash\n\t{\n\t\tuint64 baseHash;\n\t\tuint64 auxHash;\n\t\tbool isPresent{};\n\n\t\tvoid set(uint64 baseHash, uint64 auxHash)\n\t\t{\n\t\t\tthis->baseHash = baseHash;\n\t\t\tthis->auxHash = auxHash;\n\t\t\tthis->isPresent = true;\n\t\t}\n\t};\n\n\tShaderHash vsHash; // includes fetch shader\n\tShaderHash gsHash;\n\tShaderHash psHash;\n\n\tMetalAttachmentsInfo lastUsedAttachmentsInfo;\n\n\tLatte::GPUCompactedRegisterState gpuState;\n};\n\nvoid MetalPipelineCache::LoadPipelineFromCache(std::span<uint8> fileData)\n{\n\tstatic FSpinlock s_spinlockSharedInternal;\n\n\t// deserialize file\n\tLatteContextRegister* lcr = new LatteContextRegister();\n\ts_spinlockSharedInternal.lock();\n\tCachedPipeline* cachedPipeline = new CachedPipeline();\n\ts_spinlockSharedInternal.unlock();\n\n\tMemStreamReader streamReader(fileData.data(), fileData.size());\n\tif (!DeserializePipeline(streamReader, *cachedPipeline))\n\t{\n\t\t// failed to deserialize\n\t\ts_spinlockSharedInternal.lock();\n\t\tdelete lcr;\n\t\tdelete cachedPipeline;\n\t\ts_spinlockSharedInternal.unlock();\n\t\treturn;\n\t}\n\t// restored register view from compacted state\n\tLatte::LoadGPURegisterState(*lcr, cachedPipeline->gpuState);\n\n\tLatteDecompilerShader* vertexShader = nullptr;\n\tLatteDecompilerShader* geometryShader = nullptr;\n\tLatteDecompilerShader* pixelShader = nullptr;\n\t// find vertex shader\n\tif (cachedPipeline->vsHash.isPresent)\n\t{\n\t\tvertexShader = LatteSHRC_FindVertexShader(cachedPipeline->vsHash.baseHash, cachedPipeline->vsHash.auxHash);\n\t\tif (!vertexShader)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Vertex shader not found in cache\");\n\t\t\treturn;\n\t\t}\n\t}\n\t// find geometry shader\n\tif (cachedPipeline->gsHash.isPresent)\n\t{\n\t\tgeometryShader = LatteSHRC_FindGeometryShader(cachedPipeline->gsHash.baseHash, cachedPipeline->gsHash.auxHash);\n\t\tif (!geometryShader)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Geometry shader not found in cache\");\n\t\t\treturn;\n\t\t}\n\t}\n\t// find pixel shader\n\tif (cachedPipeline->psHash.isPresent)\n\t{\n\t\tpixelShader = LatteSHRC_FindPixelShader(cachedPipeline->psHash.baseHash, cachedPipeline->psHash.auxHash);\n\t\tif (!pixelShader)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Pixel shader not found in cache\");\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (!pixelShader)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\n\tMetalAttachmentsInfo attachmentsInfo(*lcr, pixelShader);\n\n\tPipelineObject* pipelineObject = new PipelineObject();\n\n\t// compile\n\t{\n\t\tMetalPipelineCompiler pp(m_mtlr, *pipelineObject);\n\t\tpp.InitFromState(vertexShader->compatibleFetchShader, vertexShader, geometryShader, pixelShader, cachedPipeline->lastUsedAttachmentsInfo, attachmentsInfo, *lcr);\n\t\tpp.Compile(true, true, false);\n\t\t// destroy pp early\n\t}\n\n\t// Cache the pipeline\n   \tuint64 pipelineStateHash = CalculatePipelineHash(vertexShader->compatibleFetchShader, vertexShader, geometryShader, pixelShader, cachedPipeline->lastUsedAttachmentsInfo, attachmentsInfo, *lcr);\n   \tm_pipelineCacheLock.lock();\n   \tm_pipelineCache[pipelineStateHash] = pipelineObject;\n   \tm_pipelineCacheLock.unlock();\n\n\t// clean up\n\ts_spinlockSharedInternal.lock();\n\tdelete lcr;\n\tdelete cachedPipeline;\n\ts_spinlockSharedInternal.unlock();\n}\n\nConcurrentQueue<CachedPipeline*> g_mtlPipelineCachingQueue;\n\nvoid MetalPipelineCache::AddCurrentStateToCache(uint64 pipelineStateHash, const MetalAttachmentsInfo& lastUsedAttachmentsInfo)\n{\n\tif (!m_pipelineCacheStoreThread)\n\t{\n\t\tm_pipelineCacheStoreThread = new std::thread(&MetalPipelineCache::WorkerThread, this);\n\t\tm_pipelineCacheStoreThread->detach();\n\t}\n\t// fill job structure with cached GPU state\n\t// for each cached pipeline we store:\n\t// - Active shaders (referenced by hash)\n\t// - An almost-complete register state of the GPU (minus some ALU uniform constants which aren't relevant)\n\tCachedPipeline* job = new CachedPipeline();\n\tauto vs = LatteSHRC_GetActiveVertexShader();\n\tauto gs = LatteSHRC_GetActiveGeometryShader();\n\tauto ps = LatteSHRC_GetActivePixelShader();\n\tif (vs)\n\t\tjob->vsHash.set(vs->baseHash, vs->auxHash);\n\tif (gs)\n\t\tjob->gsHash.set(gs->baseHash, gs->auxHash);\n\tif (ps)\n\t\tjob->psHash.set(ps->baseHash, ps->auxHash);\n\tjob->lastUsedAttachmentsInfo = lastUsedAttachmentsInfo;\n\tLatte::StoreGPURegisterState(LatteGPUState.contextNew, job->gpuState);\n\t// queue job\n\tg_mtlPipelineCachingQueue.push(job);\n}\n\nbool MetalPipelineCache::SerializePipeline(MemStreamWriter& memWriter, CachedPipeline& cachedPipeline)\n{\n\tmemWriter.writeBE<uint8>(0x01); // version\n\tuint8 presentMask = 0;\n\tif (cachedPipeline.vsHash.isPresent)\n\t\tpresentMask |= 1;\n\tif (cachedPipeline.gsHash.isPresent)\n\t\tpresentMask |= 2;\n\tif (cachedPipeline.psHash.isPresent)\n\t\tpresentMask |= 4;\n\tmemWriter.writeBE<uint8>(presentMask);\n\tif (cachedPipeline.vsHash.isPresent)\n\t{\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.vsHash.baseHash);\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.vsHash.auxHash);\n\t}\n\tif (cachedPipeline.gsHash.isPresent)\n\t{\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.gsHash.baseHash);\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.gsHash.auxHash);\n\t}\n\tif (cachedPipeline.psHash.isPresent)\n\t{\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.psHash.baseHash);\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.psHash.auxHash);\n\t}\n\n\tfor (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)\n\t    memWriter.writeBE<uint16>((uint16)cachedPipeline.lastUsedAttachmentsInfo.colorFormats[i]);\n\tmemWriter.writeBE<uint16>((uint16)cachedPipeline.lastUsedAttachmentsInfo.depthFormat);\n\n\tLatte::SerializeRegisterState(cachedPipeline.gpuState, memWriter);\n\n\treturn true;\n}\n\nbool MetalPipelineCache::DeserializePipeline(MemStreamReader& memReader, CachedPipeline& cachedPipeline)\n{\n\t// version\n\tif (memReader.readBE<uint8>() != 1)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Cached Metal pipeline corrupted or has unknown version\");\n\t\treturn false;\n\t}\n\t// shader hashes\n\tuint8 presentMask = memReader.readBE<uint8>();\n\tif (presentMask & 1)\n\t{\n\t\tuint64 baseHash = memReader.readBE<uint64>();\n\t\tuint64 auxHash = memReader.readBE<uint64>();\n\t\tcachedPipeline.vsHash.set(baseHash, auxHash);\n\t}\n\tif (presentMask & 2)\n\t{\n\t\tuint64 baseHash = memReader.readBE<uint64>();\n\t\tuint64 auxHash = memReader.readBE<uint64>();\n\t\tcachedPipeline.gsHash.set(baseHash, auxHash);\n\t}\n\tif (presentMask & 4)\n\t{\n\t\tuint64 baseHash = memReader.readBE<uint64>();\n\t\tuint64 auxHash = memReader.readBE<uint64>();\n\t\tcachedPipeline.psHash.set(baseHash, auxHash);\n\t}\n\n\tfor (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)\n\t    cachedPipeline.lastUsedAttachmentsInfo.colorFormats[i] = (Latte::E_GX2SURFFMT)memReader.readBE<uint16>();\n\tcachedPipeline.lastUsedAttachmentsInfo.depthFormat = (Latte::E_GX2SURFFMT)memReader.readBE<uint16>();\n\n\t// deserialize GPU state\n\tif (!Latte::DeserializeRegisterState(cachedPipeline.gpuState, memReader))\n\t{\n\t\treturn false;\n\t}\n\tcemu_assert_debug(!memReader.hasError());\n\n\treturn true;\n}\n\nint MetalPipelineCache::CompilerThread()\n{\n\tSetThreadName(\"plCacheCompiler\");\n\twhile (m_numCompilationThreads != 0)\n\t{\n\t\tstd::vector<uint8> pipelineData = m_compilationQueue.pop();\n\t\tif(pipelineData.empty())\n\t\t\tcontinue;\n\t\tLoadPipelineFromCache(pipelineData);\n\t\t++g_mtlCacheState.pipelinesLoaded;\n\t}\n\treturn 0;\n}\n\nvoid MetalPipelineCache::WorkerThread()\n{\n\tSetThreadName(\"plCacheWriter\");\n\twhile (true)\n\t{\n\t\tCachedPipeline* job;\n\t\tg_mtlPipelineCachingQueue.pop(job);\n\t\tif (!s_cache)\n\t\t{\n\t\t\tdelete job;\n\t\t\tcontinue;\n\t\t}\n\t\t// serialize\n\t\tMemStreamWriter memWriter(1024 * 4);\n\t\tSerializePipeline(memWriter, *job);\n\t\tauto blob = memWriter.getResult();\n\t\t// file name is derived from data hash\n\t\tuint8 hash[SHA256_DIGEST_LENGTH];\n\t\tSHA256(blob.data(), blob.size(), hash);\n\t\tuint64 nameA = *(uint64be*)(hash + 0);\n\t\tuint64 nameB = *(uint64be*)(hash + 8);\n\t\ts_cache->AddFileAsync({ nameA, nameB }, blob.data(), blob.size());\n\t\tdelete job;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h\"\n#include \"util/helpers/ConcurrentQueue.h\"\n#include \"util/helpers/fspinlock.h\"\n#include \"util/math/vector2.h\"\n\nclass MetalPipelineCache\n{\npublic:\n\tstatic MetalPipelineCache& GetInstance();\n\n    MetalPipelineCache(class MetalRenderer* metalRenderer);\n    ~MetalPipelineCache();\n\n    PipelineObject* GetRenderPipelineState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, Vector2i extend, uint32 indexCount, const LatteContextRegister& lcr);\n\n    // Cache loading\n\tuint32 BeginLoading(uint64 cacheTitleId); // returns count of pipelines stored in cache\n\tbool UpdateLoading(uint32& pipelinesLoadedTotal, uint32& pipelinesMissingShaders);\n\tvoid EndLoading();\n\tvoid LoadPipelineFromCache(std::span<uint8> fileData);\n       void Close(); // called on title exit\n\n    // Debug\n    size_t GetPipelineCacheSize() const { return m_pipelineCache.size(); }\n\nprivate:\n    class MetalRenderer* m_mtlr;\n\n    std::map<uint64, PipelineObject*> m_pipelineCache;\n    FSpinlock m_pipelineCacheLock;\n\n\tstd::thread* m_pipelineCacheStoreThread;\n\n\tclass FileCache* s_cache;\n\n\tstd::atomic_uint32_t m_numCompilationThreads{ 0 };\n\tConcurrentQueue<std::vector<uint8>> m_compilationQueue;\n\tstd::atomic_uint32_t m_compilationCount;\n\n    static uint64 CalculatePipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr);\n\n    void AddCurrentStateToCache(uint64 pipelineStateHash, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo);\n\n\t// pipeline serialization for file\n\tbool SerializePipeline(class MemStreamWriter& memWriter, struct CachedPipeline& cachedPipeline);\n\tbool DeserializePipeline(class MemStreamReader& memReader, struct CachedPipeline& cachedPipeline);\n\n    int CompilerThread();\n\tvoid WorkerThread();\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalCommon.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h\"\n\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n\n#include <chrono>\n\nextern std::atomic_int g_compiling_pipelines;\nextern std::atomic_int g_compiling_pipelines_async;\nextern std::atomic_uint64_t g_compiling_pipelines_syncTimeSum;\n\nstatic void rectsEmulationGS_outputSingleVertex(std::string& gsSrc, const LatteDecompilerShader* vertexShader, LatteShaderPSInputTable& psInputTable, sint32 vIdx, const LatteContextRegister& latteRegister)\n{\n\tauto parameterMask = vertexShader->outputParameterMask;\n\tfor (uint32 i = 0; i < 32; i++)\n\t{\n\t\tif ((parameterMask & (1 << i)) == 0)\n\t\t\tcontinue;\n\t\tsint32 vsSemanticId = psInputTable.getVertexShaderOutParamSemanticId(latteRegister.GetRawView(), i);\n\t\tif (vsSemanticId < 0)\n\t\t\tcontinue;\n\t\t// make sure PS has matching input\n\t\tif (!psInputTable.hasPSImportForSemanticId(vsSemanticId))\n\t\t\tcontinue;\n\t\tgsSrc.append(fmt::format(\"out.passParameterSem{} = objectPayload.vertexOut[{}].passParameterSem{};\\r\\n\", vsSemanticId, vIdx, vsSemanticId));\n\t}\n\tgsSrc.append(fmt::format(\"out.position = objectPayload.vertexOut[{}].position;\\r\\n\", vIdx));\n\tgsSrc.append(fmt::format(\"mesh.set_vertex({}, out);\\r\\n\", vIdx));\n}\n\nstatic void rectsEmulationGS_outputGeneratedVertex(std::string& gsSrc, const LatteDecompilerShader* vertexShader, LatteShaderPSInputTable& psInputTable, const char* variant, const LatteContextRegister& latteRegister)\n{\n\tauto parameterMask = vertexShader->outputParameterMask;\n\tfor (uint32 i = 0; i < 32; i++)\n\t{\n\t\tif ((parameterMask & (1 << i)) == 0)\n\t\t\tcontinue;\n\t\tsint32 vsSemanticId = psInputTable.getVertexShaderOutParamSemanticId(latteRegister.GetRawView(), i);\n\t\tif (vsSemanticId < 0)\n\t\t\tcontinue;\n\t\t// make sure PS has matching input\n\t\tif (!psInputTable.hasPSImportForSemanticId(vsSemanticId))\n\t\t\tcontinue;\n\t\tgsSrc.append(fmt::format(\"out.passParameterSem{} = gen4thVertex{}(objectPayload.vertexOut[0].passParameterSem{}, objectPayload.vertexOut[1].passParameterSem{}, objectPayload.vertexOut[2].passParameterSem{});\\r\\n\", vsSemanticId, variant, vsSemanticId, vsSemanticId, vsSemanticId));\n\t}\n\tgsSrc.append(fmt::format(\"out.position = gen4thVertex{}(objectPayload.vertexOut[0].position, objectPayload.vertexOut[1].position, objectPayload.vertexOut[2].position);\\r\\n\", variant));\n\tgsSrc.append(fmt::format(\"mesh.set_vertex(3, out);\\r\\n\"));\n}\n\nstatic void rectsEmulationGS_outputVerticesCode(std::string& gsSrc, const LatteDecompilerShader* vertexShader, LatteShaderPSInputTable& psInputTable, sint32 p0, sint32 p1, sint32 p2, sint32 p3, const char* variant, const LatteContextRegister& latteRegister)\n{\n\tsint32 pList[4] = { p0, p1, p2, p3 };\n\tfor (sint32 i = 0; i < 4; i++)\n\t{\n\t\tif (pList[i] == 3)\n\t\t\trectsEmulationGS_outputGeneratedVertex(gsSrc, vertexShader, psInputTable, variant, latteRegister);\n\t\telse\n\t\t\trectsEmulationGS_outputSingleVertex(gsSrc, vertexShader, psInputTable, pList[i], latteRegister);\n\t}\n\tgsSrc.append(fmt::format(\"mesh.set_index(0, {});\\r\\n\", pList[0]));\n\tgsSrc.append(fmt::format(\"mesh.set_index(1, {});\\r\\n\", pList[1]));\n\tgsSrc.append(fmt::format(\"mesh.set_index(2, {});\\r\\n\", pList[2]));\n\tgsSrc.append(fmt::format(\"mesh.set_index(3, {});\\r\\n\", pList[1]));\n\tgsSrc.append(fmt::format(\"mesh.set_index(4, {});\\r\\n\", pList[2]));\n\tgsSrc.append(fmt::format(\"mesh.set_index(5, {});\\r\\n\", pList[3]));\n}\n\nstatic RendererShaderMtl* rectsEmulationGS_generate(MetalRenderer* metalRenderer, const LatteDecompilerShader* vertexShader, const LatteContextRegister& latteRegister)\n{\n\tstd::string gsSrc;\n\tgsSrc.append(\"#include <metal_stdlib>\\r\\n\");\n\tgsSrc.append(\"using namespace metal;\\r\\n\");\n\n\tLatteShaderPSInputTable psInputTable;\n\tLatteShader_CreatePSInputTable(&psInputTable, latteRegister.GetRawView());\n\n\t// inputs & outputs\n\tstd::string vertexOutDefinition = \"struct VertexOut {\\r\\n\";\n\tvertexOutDefinition += \"float4 position;\\r\\n\";\n\tstd::string geometryOutDefinition = \"struct GeometryOut {\\r\\n\";\n\tgeometryOutDefinition += \"float4 position [[position]];\\r\\n\";\n\tauto parameterMask = vertexShader->outputParameterMask;\n\tfor (uint32 i = 0; i < 32; i++)\n\t{\n\t\tif ((parameterMask & (1 << i)) == 0)\n\t\t\tcontinue;\n\t\tsint32 vsSemanticId = psInputTable.getVertexShaderOutParamSemanticId(latteRegister.GetRawView(), i);\n\t\tif (vsSemanticId < 0)\n\t\t\tcontinue;\n\t\tauto psImport = psInputTable.getPSImportBySemanticId(vsSemanticId);\n\t\tif (psImport == nullptr)\n\t\t\tcontinue;\n\n\t\t// VertexOut\n\t\tvertexOutDefinition += fmt::format(\"float4 passParameterSem{};\\r\\n\", vsSemanticId);\n\n\t\t// GeometryOut\n\t\tgeometryOutDefinition += fmt::format(\"float4 passParameterSem{}\", vsSemanticId);\n\n        geometryOutDefinition += fmt::format(\" [[user(locn{})]]\", psInputTable.getPSImportLocationBySemanticId(vsSemanticId));\n        if (psImport->isFlat)\n            geometryOutDefinition += \" [[flat]]\";\n        if (psImport->isNoPerspective)\n\t\t\tgeometryOutDefinition += \" [[center_no_perspective]]\";\n        geometryOutDefinition += \";\\r\\n\";\n\t}\n\tvertexOutDefinition += \"};\\r\\n\";\n\tgeometryOutDefinition += \"};\\r\\n\";\n\n\tgsSrc.append(vertexOutDefinition);\n\tgsSrc.append(geometryOutDefinition);\n\n\tgsSrc.append(\"struct ObjectPayload {\\r\\n\");\n\tgsSrc.append(\"VertexOut vertexOut[3];\\r\\n\");\n\tgsSrc.append(\"};\\r\\n\");\n\n\t// gen function\n\tgsSrc.append(\"float4 gen4thVertexA(float4 a, float4 b, float4 c)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\tgsSrc.append(\"return b - (c - a);\\r\\n\");\n\tgsSrc.append(\"}\\r\\n\");\n\n\tgsSrc.append(\"float4 gen4thVertexB(float4 a, float4 b, float4 c)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\tgsSrc.append(\"return c - (b - a);\\r\\n\");\n\tgsSrc.append(\"}\\r\\n\");\n\n\tgsSrc.append(\"float4 gen4thVertexC(float4 a, float4 b, float4 c)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\tgsSrc.append(\"return c + (b - a);\\r\\n\");\n\tgsSrc.append(\"}\\r\\n\");\n\n\t// main\n\tgsSrc.append(\"using MeshType = mesh<GeometryOut, void, 4, 2, topology::triangle>;\\r\\n\");\n\tgsSrc.append(\"[[mesh, max_total_threads_per_threadgroup(1)]]\\r\\n\");\n\tgsSrc.append(\"void main0(MeshType mesh, const object_data ObjectPayload& objectPayload [[payload]])\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\tgsSrc.append(\"GeometryOut out;\\r\\n\");\n\n\t// there are two possible winding orders that need different triangle generation:\n\t// 0 1\n\t// 2 3\n\t// and\n\t// 0 1\n\t// 3 2\n\t// all others are just symmetries of these cases\n\n\t// we can determine the case by comparing the distance 0<->1 and 0<->2\n\n\tgsSrc.append(\"float dist0_1 = length(objectPayload.vertexOut[1].position.xy - objectPayload.vertexOut[0].position.xy);\\r\\n\");\n\tgsSrc.append(\"float dist0_2 = length(objectPayload.vertexOut[2].position.xy - objectPayload.vertexOut[0].position.xy);\\r\\n\");\n\tgsSrc.append(\"float dist1_2 = length(objectPayload.vertexOut[2].position.xy - objectPayload.vertexOut[1].position.xy);\\r\\n\");\n\n\t// emit vertices\n\tgsSrc.append(\"if(dist0_1 > dist0_2 && dist0_1 > dist1_2)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\t// p0 to p1 is diagonal\n\trectsEmulationGS_outputVerticesCode(gsSrc, vertexShader, psInputTable, 2, 1, 0, 3, \"A\", latteRegister);\n\tgsSrc.append(\"} else if ( dist0_2 > dist0_1 && dist0_2 > dist1_2 ) {\\r\\n\");\n\t// p0 to p2 is diagonal\n\trectsEmulationGS_outputVerticesCode(gsSrc, vertexShader, psInputTable, 1, 2, 0, 3, \"B\", latteRegister);\n\tgsSrc.append(\"} else {\\r\\n\");\n\t// p1 to p2 is diagonal\n\trectsEmulationGS_outputVerticesCode(gsSrc, vertexShader, psInputTable, 0, 1, 2, 3, \"C\", latteRegister);\n\tgsSrc.append(\"}\\r\\n\");\n\n\tgsSrc.append(\"mesh.set_primitive_count(2);\\r\\n\");\n\n\tgsSrc.append(\"}\\r\\n\");\n\n\tauto mtlShader = new RendererShaderMtl(metalRenderer, RendererShader::ShaderType::kGeometry, 0, 0, false, false, gsSrc);\n\tmtlShader->PreponeCompilation(true);\n\n\treturn mtlShader;\n}\n\n#define INVALID_TITLE_ID 0xFFFFFFFFFFFFFFFF\n\nuint64 s_cacheTitleId = INVALID_TITLE_ID;\n\nextern std::atomic_int g_compiled_shaders_total;\nextern std::atomic_int g_compiled_shaders_async;\n\ntemplate<typename T>\nvoid SetFragmentState(T* desc, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, bool rasterizationEnabled, const LatteContextRegister& lcr)\n{\n\t// TODO: check if the pixel shader is valid as well?\n\tif (!rasterizationEnabled/* || !pixelShaderMtl*/)\n\t{\n\t    desc->setRasterizationEnabled(false);\n\t\treturn;\n\t}\n\n    // Color attachments\n\tconst Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = lcr.CB_COLOR_CONTROL;\n\tuint32 blendEnableMask = colorControlReg.get_BLEND_MASK();\n\tuint32 renderTargetMask = lcr.CB_TARGET_MASK.get_MASK();\n\tfor (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)\n\t{\n\t    Latte::E_GX2SURFFMT format = lastUsedAttachmentsInfo.colorFormats[i];\n\t\tif (format == Latte::E_GX2SURFFMT::INVALID_FORMAT)\n\t\t    continue;\n\n\t\tMTL::PixelFormat pixelFormat = GetMtlPixelFormat(format, false);\n\t\tauto colorAttachment = desc->colorAttachments()->object(i);\n\t\tcolorAttachment->setPixelFormat(pixelFormat);\n\n\t\t// Disable writes if not in the active FBO\n\t\tif (activeAttachmentsInfo.colorFormats[i] == Latte::E_GX2SURFFMT::INVALID_FORMAT)\n        {\n            colorAttachment->setWriteMask(MTL::ColorWriteMaskNone);\n            continue;\n        }\n\n\t\tcolorAttachment->setWriteMask(GetMtlColorWriteMask((renderTargetMask >> (i * 4)) & 0xF));\n\n\t\t// Blending\n\t\tbool blendEnabled = ((blendEnableMask & (1 << i))) != 0;\n\t\t// Only float data type is blendable\n\t\tif (blendEnabled && GetMtlPixelFormatInfo(format, false).dataType == MetalDataType::FLOAT)\n\t\t{\n       \t\tcolorAttachment->setBlendingEnabled(true);\n\n       \t\tconst auto& blendControlReg = lcr.CB_BLENDN_CONTROL[i];\n\n       \t\tauto rgbBlendOp = GetMtlBlendOp(blendControlReg.get_COLOR_COMB_FCN());\n       \t\tauto srcRgbBlendFactor = GetMtlBlendFactor(blendControlReg.get_COLOR_SRCBLEND());\n       \t\tauto dstRgbBlendFactor = GetMtlBlendFactor(blendControlReg.get_COLOR_DSTBLEND());\n\n       \t\tcolorAttachment->setRgbBlendOperation(rgbBlendOp);\n       \t\tcolorAttachment->setSourceRGBBlendFactor(srcRgbBlendFactor);\n       \t\tcolorAttachment->setDestinationRGBBlendFactor(dstRgbBlendFactor);\n       \t\tif (blendControlReg.get_SEPARATE_ALPHA_BLEND())\n       \t\t{\n       \t\t\tcolorAttachment->setAlphaBlendOperation(GetMtlBlendOp(blendControlReg.get_ALPHA_COMB_FCN()));\n      \t\t    colorAttachment->setSourceAlphaBlendFactor(GetMtlBlendFactor(blendControlReg.get_ALPHA_SRCBLEND()));\n      \t\t    colorAttachment->setDestinationAlphaBlendFactor(GetMtlBlendFactor(blendControlReg.get_ALPHA_DSTBLEND()));\n       \t\t}\n       \t\telse\n       \t\t{\n           \t\tcolorAttachment->setAlphaBlendOperation(rgbBlendOp);\n           \t\tcolorAttachment->setSourceAlphaBlendFactor(srcRgbBlendFactor);\n           \t\tcolorAttachment->setDestinationAlphaBlendFactor(dstRgbBlendFactor);\n       \t\t}\n\t\t}\n\t}\n\n\t// Depth stencil attachment\n\tif (lastUsedAttachmentsInfo.depthFormat != Latte::E_GX2SURFFMT::INVALID_FORMAT)\n\t{\n\t    MTL::PixelFormat pixelFormat = GetMtlPixelFormat(lastUsedAttachmentsInfo.depthFormat, true);\n        desc->setDepthAttachmentPixelFormat(pixelFormat);\n        if (lastUsedAttachmentsInfo.hasStencil)\n            desc->setStencilAttachmentPixelFormat(pixelFormat);\n\t}\n}\n\nMetalPipelineCompiler::~MetalPipelineCompiler()\n{\n    /*\n    for (auto& pair : m_pipelineCache)\n    {\n        pair.second->release();\n    }\n    m_pipelineCache.clear();\n\n    NS::Error* error = nullptr;\n    m_binaryArchive->serializeToURL(m_binaryArchiveURL, &error);\n    if (error)\n    {\n        cemuLog_log(LogType::Force, \"error serializing binary archive: {}\", error->localizedDescription()->utf8String());\n        error->release();\n    }\n    m_binaryArchive->release();\n\n    m_binaryArchiveURL->release();\n    */\n    if (m_pipelineDescriptor)\n        m_pipelineDescriptor->release();\n}\n\nvoid MetalPipelineCompiler::InitFromState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr)\n{\n    m_usesGeometryShader = UseGeometryShader(lcr, geometryShader != nullptr);\n    if (m_usesGeometryShader && !m_mtlr->SupportsMeshShaders())\n        return;\n\n    // Rasterization\n\tm_rasterizationEnabled = lcr.IsRasterizationEnabled();\n\n    // Shaders\n    m_vertexShaderMtl = static_cast<RendererShaderMtl*>(vertexShader->shader);\n    if (geometryShader)\n        m_geometryShaderMtl = static_cast<RendererShaderMtl*>(geometryShader->shader);\n    else if (UseRectEmulation(lcr))\n        m_geometryShaderMtl = rectsEmulationGS_generate(m_mtlr, vertexShader, lcr);\n    else\n        m_geometryShaderMtl = nullptr;\n    m_pixelShaderMtl = static_cast<RendererShaderMtl*>(pixelShader->shader);\n\n    if (m_usesGeometryShader)\n        InitFromStateMesh(fetchShader, lastUsedAttachmentsInfo, activeAttachmentsInfo, lcr);\n    else\n        InitFromStateRender(fetchShader, vertexShader, lastUsedAttachmentsInfo, activeAttachmentsInfo, lcr);\n}\n\nbool MetalPipelineCompiler::Compile(bool forceCompile, bool isRenderThread, bool showInOverlay)\n{\n    if (m_usesGeometryShader && !m_mtlr->SupportsMeshShaders())\n        return false;\n\n    if (forceCompile)\n\t{\n\t\t// if some shader stages are not compiled yet, compile them now\n\t\tif (m_vertexShaderMtl && !m_vertexShaderMtl->IsCompiled())\n\t\t\tm_vertexShaderMtl->PreponeCompilation(isRenderThread);\n\t\tif (m_geometryShaderMtl && !m_geometryShaderMtl->IsCompiled())\n\t\t\tm_geometryShaderMtl->PreponeCompilation(isRenderThread);\n\t\tif (m_pixelShaderMtl && !m_pixelShaderMtl->IsCompiled())\n\t\t\tm_pixelShaderMtl->PreponeCompilation(isRenderThread);\n\t}\n\telse\n\t{\n\t    // fail early if some shader stages are not compiled\n\t\tif (m_vertexShaderMtl && !m_vertexShaderMtl->IsCompiled())\n\t\t\treturn false;\n\t\tif (m_geometryShaderMtl && !m_geometryShaderMtl->IsCompiled())\n\t\t\treturn false;\n\t\tif (m_pixelShaderMtl && !m_pixelShaderMtl->IsCompiled())\n\t\t\treturn false;\n\t}\n\n\t// Compile\n    MTL::RenderPipelineState* pipeline = nullptr;\n    NS::Error* error = nullptr;\n\n    auto start = std::chrono::high_resolution_clock::now();\n    if (m_usesGeometryShader)\n    {\n        auto desc = static_cast<MTL::MeshRenderPipelineDescriptor*>(m_pipelineDescriptor);\n\n        // Shaders\n        desc->setObjectFunction(m_vertexShaderMtl->GetFunction());\n        desc->setMeshFunction(m_geometryShaderMtl->GetFunction());\n        if (m_rasterizationEnabled)\n            desc->setFragmentFunction(m_pixelShaderMtl->GetFunction());\n\n#ifdef CEMU_DEBUG_ASSERT\n        desc->setLabel(GetLabel(\"Mesh render pipeline state\", desc));\n#endif\n       \tpipeline = m_mtlr->GetDevice()->newRenderPipelineState(desc, MTL::PipelineOptionNone, nullptr, &error);\n    }\n    else\n    {\n        auto desc = static_cast<MTL::RenderPipelineDescriptor*>(m_pipelineDescriptor);\n\n        // Shaders\n        desc->setVertexFunction(m_vertexShaderMtl->GetFunction());\n        if (m_rasterizationEnabled)\n            desc->setFragmentFunction(m_pixelShaderMtl->GetFunction());\n\n#ifdef CEMU_DEBUG_ASSERT\n        desc->setLabel(GetLabel(\"Render pipeline state\", desc));\n#endif\n       \tpipeline = m_mtlr->GetDevice()->newRenderPipelineState(desc, MTL::PipelineOptionNone, nullptr, &error);\n    }\n    auto end = std::chrono::high_resolution_clock::now();\n\n    auto creationDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();\n\n   \tif (error)\n   \t{\n       \tcemuLog_log(LogType::Force, \"error creating render pipeline state: {}\", error->localizedDescription()->utf8String());\n   \t}\n\n    if (showInOverlay)\n\t{\n\t\tif (isRenderThread)\n\t\t\tg_compiling_pipelines_syncTimeSum += creationDuration;\n\t\telse\n\t\t\tg_compiling_pipelines_async++;\n\t\tg_compiling_pipelines++;\n\t}\n\n\tm_pipelineObj.m_pipeline = pipeline;\n\n\treturn true;\n}\n\nvoid MetalPipelineCompiler::InitFromStateRender(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr)\n{\n\t// Render pipeline state\n\tMTL::RenderPipelineDescriptor* desc = MTL::RenderPipelineDescriptor::alloc()->init();\n\n    // Vertex descriptor\n    if (!fetchShader->mtlFetchVertexManually)\n    {\n    \tNS_STACK_SCOPED MTL::VertexDescriptor* vertexDescriptor = MTL::VertexDescriptor::alloc()->init();\n    \tfor (auto& bufferGroup : fetchShader->bufferGroups)\n    \t{\n    \t\tstd::optional<LatteConst::VertexFetchType2> fetchType;\n\n    \t\tuint32 minBufferStride = 0;\n    \t\tfor (sint32 j = 0; j < bufferGroup.attribCount; ++j)\n    \t\t{\n    \t\t\tauto& attr = bufferGroup.attrib[j];\n\n    \t\t\tuint32 semanticId = vertexShader->resourceMapping.attributeMapping[attr.semanticId];\n    \t\t\tif (semanticId == (uint32)-1)\n    \t\t\t\tcontinue; // attribute not used?\n\n    \t\t\tauto attribute = vertexDescriptor->attributes()->object(semanticId);\n    \t\t\tattribute->setOffset(attr.offset);\n    \t\t\tattribute->setBufferIndex(GET_MTL_VERTEX_BUFFER_INDEX(attr.attributeBufferIndex));\n    \t\t\tattribute->setFormat(GetMtlVertexFormat(attr.format));\n\n    \t\t\tminBufferStride = std::max(minBufferStride, attr.offset + GetMtlVertexFormatSize(attr.format));\n\n    \t\t\tif (fetchType.has_value())\n    \t\t\t\tcemu_assert_debug(fetchType == attr.fetchType);\n    \t\t\telse\n    \t\t\t\tfetchType = attr.fetchType;\n\n    \t\t\tif (attr.fetchType == LatteConst::INSTANCE_DATA)\n    \t\t\t{\n    \t\t\t\tcemu_assert_debug(attr.aluDivisor == 1); // other divisor not yet supported\n    \t\t\t}\n    \t\t}\n\n    \t\tuint32 bufferIndex = bufferGroup.attributeBufferIndex;\n    \t\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n    \t\tuint32 bufferStride = (lcr.GetRawView()[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;\n\n    \t\tauto layout = vertexDescriptor->layouts()->object(GET_MTL_VERTEX_BUFFER_INDEX(bufferIndex));\n    \t\tif (bufferStride == 0)\n    \t\t{\n    \t\t    // Buffer stride cannot be zero, let's use the minimum stride\n    \t\t\tbufferStride = minBufferStride;\n\n    \t\t\t// Additionally, constant vertex function must be used\n    \t\t\tlayout->setStepFunction(MTL::VertexStepFunctionConstant);\n    \t\t\tlayout->setStepRate(0);\n    \t\t}\n    \t\telse\n    \t\t{\n      \t\tif (!fetchType.has_value() || fetchType == LatteConst::VertexFetchType2::VERTEX_DATA)\n     \t\t\tlayout->setStepFunction(MTL::VertexStepFunctionPerVertex);\n      \t\telse if (fetchType == LatteConst::VertexFetchType2::INSTANCE_DATA)\n     \t\t\tlayout->setStepFunction(MTL::VertexStepFunctionPerInstance);\n      \t\telse\n      \t\t{\n      \t\t    cemuLog_log(LogType::Force, \"unimplemented vertex fetch type {}\", (uint32)fetchType.value());\n     \t\t\tcemu_assert(false);\n      \t\t}\n    \t\t}\n    \t\tbufferStride = Align(bufferStride, 4);\n    \t\tlayout->setStride(bufferStride);\n    \t}\n\n    \tdesc->setVertexDescriptor(vertexDescriptor);\n    }\n\n\tSetFragmentState(desc, lastUsedAttachmentsInfo, activeAttachmentsInfo, m_rasterizationEnabled, lcr);\n\n\tm_pipelineDescriptor = desc;\n}\n\nvoid MetalPipelineCompiler::InitFromStateMesh(const LatteFetchShader* fetchShader, const MetalAttachmentsInfo& lastUsedAttachmentsInfo, const MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr)\n{\n\t// Render pipeline state\n\tMTL::MeshRenderPipelineDescriptor* desc = MTL::MeshRenderPipelineDescriptor::alloc()->init();\n\n\tSetFragmentState(desc, lastUsedAttachmentsInfo, activeAttachmentsInfo, m_rasterizationEnabled, lcr);\n\n\tm_pipelineDescriptor = desc;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCompiler.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h\"\n\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n\nstruct PipelineObject\n{\n    MTL::RenderPipelineState* m_pipeline = nullptr;\n};\n\nclass MetalPipelineCompiler\n{\npublic:\n    MetalPipelineCompiler(class MetalRenderer* metalRenderer, PipelineObject& pipelineObj) : m_mtlr{metalRenderer}, m_pipelineObj{pipelineObj} {}\n    ~MetalPipelineCompiler();\n\n    void InitFromState(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr);\n\n    bool Compile(bool forceCompile, bool isRenderThread, bool showInOverlay);\n\nprivate:\n    class MetalRenderer* m_mtlr;\n    PipelineObject& m_pipelineObj;\n\n    class RendererShaderMtl* m_vertexShaderMtl;\n    class RendererShaderMtl* m_geometryShaderMtl;\n    class RendererShaderMtl* m_pixelShaderMtl;\n    bool m_usesGeometryShader;\n    bool m_rasterizationEnabled;\n\n    NS::Object* m_pipelineDescriptor = nullptr;\n\n    void InitFromStateRender(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr);\n\n    void InitFromStateMesh(const LatteFetchShader* fetchShader, const class MetalAttachmentsInfo& lastUsedAttachmentsInfo, const class MetalAttachmentsInfo& activeAttachmentsInfo, const LatteContextRegister& lcr);\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalQuery.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n\nbool LatteQueryObjectMtl::getResult(uint64& numSamplesPassed)\n{\n    if (m_commandBuffer && !CommandBufferCompleted(m_commandBuffer))\n        return false;\n\n    uint64* resultPtr = m_mtlr->GetOcclusionQueryResultsPtr();\n\n    numSamplesPassed = 0;\n    for (uint32 i = m_range.begin; i != m_range.end; i = (i + 1) % MetalRenderer::OCCLUSION_QUERY_POOL_SIZE)\n        numSamplesPassed += resultPtr[i];\n\n    return true;\n}\n\nLatteQueryObjectMtl::~LatteQueryObjectMtl()\n{\n    if (m_commandBuffer)\n        m_commandBuffer->release();\n}\n\nvoid LatteQueryObjectMtl::begin()\n{\n    m_range.begin = m_mtlr->GetOcclusionQueryIndex();\n    m_mtlr->BeginOcclusionQuery();\n}\n\nvoid LatteQueryObjectMtl::end()\n{\n    m_range.end = m_mtlr->GetOcclusionQueryIndex();\n    m_mtlr->EndOcclusionQuery();\n\n    m_commandBuffer = m_mtlr->GetAndRetainCurrentCommandBufferIfNotCompleted();\n    if (m_commandBuffer)\n        m_mtlr->RequestSoonCommit();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalQuery.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Core/LatteQueryObject.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalCommon.h\"\n\nclass LatteQueryObjectMtl : public LatteQueryObject\n{\npublic:\n\tLatteQueryObjectMtl(class MetalRenderer* mtlRenderer) : m_mtlr{mtlRenderer} {}\n\t~LatteQueryObjectMtl();\n\n\tbool getResult(uint64& numSamplesPassed) override;\n\tvoid begin() override;\n\tvoid end() override;\n\n\tvoid GrowRange()\n\t{\n\t    m_range.end++;\n\t}\n\nprivate:\n\tclass MetalRenderer* m_mtlr;\n\n\tMetalQueryRange m_range = {INVALID_UINT32, INVALID_UINT32};\n\t// TODO: make this a list of command buffers?\n\tMTL::CommandBuffer* m_commandBuffer = nullptr;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalMemoryManager.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalDepthStencilCache.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteTextureReadbackMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalVoidVertexPipeline.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalQuery.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/UtilityShaderSource.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteIndices.h\"\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n#include \"CafeSystem.h\"\n#include \"Cemu/Logging/CemuLogging.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"config/CemuConfig.h\"\n\n#define IMGUI_IMPL_METAL_CPP\n#include \"imgui/imgui_extension.h\"\n#include \"imgui/imgui_impl_metal.h\"\n\n#define EVENT_VALUE_WRAP 4096\n\nextern bool hasValidFramebufferAttached;\n\nfloat supportBufferData[512 * 4];\n\n// Defined in the OpenGL renderer\nvoid LatteDraw_handleSpecialState8_clearAsDepth();\n\nstd::vector<MetalRenderer::DeviceInfo> MetalRenderer::GetDevices()\n{\n    NS_STACK_SCOPED auto devices = MTL::CopyAllDevices();\n    std::vector<MetalRenderer::DeviceInfo> result;\n    result.reserve(devices->count());\n    for (uint32 i = 0; i < devices->count(); i++)\n    {\n        MTL::Device* device = static_cast<MTL::Device*>(devices->object(i));\n        result.push_back({std::string(device->name()->utf8String()), device->registryID()});\n    }\n\n    return result;\n}\n\nMetalRenderer::MetalRenderer()\n{\n    // Options\n\n    // Position invariance\n    switch (g_current_game_profile->GetPositionInvariance())\n    {\n    case PositionInvariance::Auto:\n        switch (CafeSystem::GetForegroundTitleId())\n        {\n        // Bayonetta\n        case 0x0005000010157F00: // EUR\n        case 0x0005000010157E00: // USA\n        case 0x000500001014DB00: // JPN\n        // Bayonetta 2\n        case 0x0005000010172700: // EUR\n        case 0x0005000010172600: // USA\n        // Disney Planes\n        case 0x0005000010136900: // EUR\n        case 0x0005000010136A00: // EUR (TODO: check)\n        case 0x0005000010136B00: // EUR (TODO: check)\n        case 0x000500001011C500: // USA (TODO: check)\n        // LEGO STAR WARS: The Force Awakens\n        case 0x00050000101DAA00: // EUR\n        case 0x00050000101DAB00: // USA\n        // Mario Kart 8\n        case 0x000500001010ED00: // EUR\n        case 0x000500001010EC00: // USA\n        case 0x000500001010EB00: // JPN\n        case 0x0005000010183A00: // JPN (TODO: check)\n        // Minecraft: Story Mode\n        case 0x000500001020A300: // EUR\n        case 0x00050000101E0100: // USA\n        //case 0x000500001020a200: // USA\n        // Ninja Gaiden 3: Razor's Edge\n        case 0x0005000010110B00: // EUR\n        case 0x0005000010139B00: // EUR (TODO: check)\n        case 0x0005000010110A00: // USA\n        case 0x0005000010110900: // JPN\n        // Resident Evil: Revelations\n        case 0x000500001012B400: // EUR\n        case 0x000500001012CF00: // USA\n        // Star Fox Zero\n        case 0x00050000101B0500: // EUR\n        case 0x0005000010201C00: // EUR (TODO: check)\n        case 0x00050000101B0400: // USA\n        case 0x0005000010201B00: // USA (TODO: check)\n        // The Legend of Zelda: Breath of the Wild\n        case 0x00050000101C9500: // EUR\n        case 0x00050000101C9400: // USA\n        case 0x00050000101C9300: // JPN\n        // Wonderful 101\n        case 0x0005000010135300: // EUR\n        case 0x000500001012DC00: // USA\n        case 0x0005000010116300: // JPN\n        case 0x0005000010185600: // JPN (TODO: check)\n            m_positionInvariance = true;\n            break;\n        default:\n            m_positionInvariance = false;\n            break;\n        }\n        break;\n    case PositionInvariance::False:\n        m_positionInvariance = false;\n        break;\n    case PositionInvariance::True:\n        m_positionInvariance = true;\n        break;\n    }\n\n    // Pick a device\n    auto& config = GetConfig();\n    const bool hasDeviceSet = config.mtl_graphic_device_uuid != 0;\n\n    // If a device is set, try to find it\n    if (hasDeviceSet)\n    {\n        NS_STACK_SCOPED auto devices = MTL::CopyAllDevices();\n        for (uint32 i = 0; i < devices->count(); i++)\n        {\n            MTL::Device* device = static_cast<MTL::Device*>(devices->object(i));\n            if (device->registryID() == config.mtl_graphic_device_uuid)\n            {\n                m_device = device;\n                break;\n            }\n        }\n    }\n\n    if (!m_device)\n    {\n        if (hasDeviceSet)\n        {\n            cemuLog_log(LogType::Force, \"The selected GPU ({}) could not be found. Using the system default device.\", config.mtl_graphic_device_uuid);\n            config.mtl_graphic_device_uuid = 0;\n        }\n        // Use the system default device\n        m_device = MTL::CreateSystemDefaultDevice();\n    }\n\n    // Vendor\n    const char* deviceName = m_device->name()->utf8String();\n    if (memcmp(deviceName, \"Apple\", 5) == 0)\n        m_vendor = GfxVendor::Apple;\n    else if (memcmp(deviceName, \"AMD\", 3) == 0)\n        m_vendor = GfxVendor::AMD;\n    else if (memcmp(deviceName, \"Intel\", 5) == 0)\n        m_vendor = GfxVendor::Intel;\n    else if (memcmp(deviceName, \"NVIDIA\", 6) == 0)\n        m_vendor = GfxVendor::Nvidia;\n    else\n        m_vendor = GfxVendor::Generic;\n\n    // Feature support\n    m_isAppleGPU = m_device->supportsFamily(MTL::GPUFamilyApple1);\n    m_supportsFramebufferFetch = GetConfig().framebuffer_fetch.GetValue() ? m_device->supportsFamily(MTL::GPUFamilyApple2) : false;\n    m_hasUnifiedMemory = m_device->hasUnifiedMemory();\n    m_supportsMetal3 = m_device->supportsFamily(MTL::GPUFamilyMetal3);\n    m_supportsMeshShaders = (m_supportsMetal3 && (m_vendor != GfxVendor::Intel || GetConfig().force_mesh_shaders.GetValue())); // Intel GPUs have issues with mesh shaders\n    m_recommendedMaxVRAMUsage = m_device->recommendedMaxWorkingSetSize();\n    m_pixelFormatSupport = MetalPixelFormatSupport(m_device);\n\n    CheckForPixelFormatSupport(m_pixelFormatSupport);\n\n    // Command queue\n    m_commandQueue = m_device->newCommandQueue();\n\n    // Synchronization resources\n    m_event = m_device->newEvent();\n\n    // Resources\n    NS_STACK_SCOPED MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init();\n#ifdef CEMU_DEBUG_ASSERT\n    samplerDescriptor->setLabel(GetLabel(\"Nearest sampler state\", samplerDescriptor));\n#endif\n    m_nearestSampler = m_device->newSamplerState(samplerDescriptor);\n\n    samplerDescriptor->setMinFilter(MTL::SamplerMinMagFilterLinear);\n    samplerDescriptor->setMagFilter(MTL::SamplerMinMagFilterLinear);\n#ifdef CEMU_DEBUG_ASSERT\n    samplerDescriptor->setLabel(GetLabel(\"Linear sampler state\", samplerDescriptor));\n#endif\n    m_linearSampler = m_device->newSamplerState(samplerDescriptor);\n\n    // Null resources\n    NS_STACK_SCOPED MTL::TextureDescriptor* textureDescriptor = MTL::TextureDescriptor::alloc()->init();\n    textureDescriptor->setTextureType(MTL::TextureType1D);\n    textureDescriptor->setWidth(1);\n    textureDescriptor->setUsage(MTL::TextureUsageShaderRead);\n    m_nullTexture1D = m_device->newTexture(textureDescriptor);\n#ifdef CEMU_DEBUG_ASSERT\n    m_nullTexture1D->setLabel(GetLabel(\"Null texture 1D\", m_nullTexture1D));\n#endif\n\n    textureDescriptor->setTextureType(MTL::TextureType2D);\n    textureDescriptor->setHeight(1);\n    textureDescriptor->setUsage(MTL::TextureUsageShaderRead | MTL::TextureUsageRenderTarget);\n    m_nullTexture2D = m_device->newTexture(textureDescriptor);\n#ifdef CEMU_DEBUG_ASSERT\n    m_nullTexture2D->setLabel(GetLabel(\"Null texture 2D\", m_nullTexture2D));\n#endif\n\n    m_memoryManager = new MetalMemoryManager(this);\n    m_outputShaderCache = new MetalOutputShaderCache(this);\n    m_pipelineCache = new MetalPipelineCache(this);\n    m_depthStencilCache = new MetalDepthStencilCache(this);\n    m_samplerCache = new MetalSamplerCache(this);\n\n    // Lower the commit treshold when buffer cache needs reduced latency\n    if (m_memoryManager->NeedsReducedLatency())\n        m_defaultCommitTreshlod = 64;\n    else\n        m_defaultCommitTreshlod = 196;\n\n    // Occlusion queries\n    m_occlusionQuery.m_resultBuffer = m_device->newBuffer(OCCLUSION_QUERY_POOL_SIZE * sizeof(uint64), MTL::ResourceStorageModeShared);\n#ifdef CEMU_DEBUG_ASSERT\n    m_occlusionQuery.m_resultBuffer->setLabel(GetLabel(\"Occlusion query result buffer\", m_occlusionQuery.m_resultBuffer));\n#endif\n    m_occlusionQuery.m_resultsPtr = (uint64*)m_occlusionQuery.m_resultBuffer->contents();\n\n    // Reset vertex and uniform buffers\n   \tfor (uint32 i = 0; i < MAX_MTL_VERTEX_BUFFERS; i++)\n        m_state.m_vertexBufferOffsets[i] = INVALID_OFFSET;\n\n   \tfor (uint32 i = 0; i < METAL_SHADER_TYPE_TOTAL; i++)\n    {\n        for (uint32 j = 0; j < MAX_MTL_BUFFERS; j++)\n            m_state.m_uniformBufferOffsets[i][j] = INVALID_OFFSET;\n    }\n\n    // Utility shader library\n\n    // Create the library\n    NS::Error* error = nullptr;\n\tNS_STACK_SCOPED MTL::Library* utilityLibrary = m_device->newLibrary(ToNSString(utilityShaderSource), nullptr, &error);\n\tif (error)\n    {\n        cemuLog_log(LogType::Force, \"failed to create utility library (error: {})\", error->localizedDescription()->utf8String());\n    }\n\n    // Pipelines\n    NS_STACK_SCOPED MTL::Function* vertexFullscreenFunction = utilityLibrary->newFunction(ToNSString(\"vertexFullscreen\"));\n    NS_STACK_SCOPED MTL::Function* fragmentCopyDepthToColorFunction = utilityLibrary->newFunction(ToNSString(\"fragmentCopyDepthToColor\"));\n\n    m_copyDepthToColorDesc = MTL::RenderPipelineDescriptor::alloc()->init();\n    m_copyDepthToColorDesc->setVertexFunction(vertexFullscreenFunction);\n    m_copyDepthToColorDesc->setFragmentFunction(fragmentCopyDepthToColorFunction);\n\n    // Void vertex pipelines\n    if (m_isAppleGPU)\n        m_copyBufferToBufferPipeline = new MetalVoidVertexPipeline(this, utilityLibrary, \"vertexCopyBufferToBuffer\");\n\n    // HACK: for some reason, this variable ends up being initialized to some garbage data, even though its declared as bool m_captureFrame = false;\n    m_occlusionQuery.m_lastCommandBuffer = nullptr;\n    m_captureFrame = false;\n}\n\nMetalRenderer::~MetalRenderer()\n{\n    if (m_isAppleGPU)\n        delete m_copyBufferToBufferPipeline;\n    //delete m_copyTextureToTexturePipeline;\n    //delete m_restrideBufferPipeline;\n\n    m_copyDepthToColorDesc->release();\n    for (const auto [pixelFormat, pipeline] : m_copyDepthToColorPipelines)\n        pipeline->release();\n\n    delete m_outputShaderCache;\n    delete m_pipelineCache;\n    delete m_depthStencilCache;\n    delete m_samplerCache;\n    delete m_memoryManager;\n\n    m_nullTexture1D->release();\n    m_nullTexture2D->release();\n\n    m_nearestSampler->release();\n    m_linearSampler->release();\n\n    if (m_readbackBuffer)\n        m_readbackBuffer->release();\n\n    if (m_xfbRingBuffer)\n        m_xfbRingBuffer->release();\n\n    m_occlusionQuery.m_resultBuffer->release();\n\n    m_event->release();\n\n    m_commandQueue->release();\n    m_device->release();\n}\n\nvoid MetalRenderer::InitializeLayer(const Vector2i& size, bool mainWindow)\n{\n    auto& layer = GetLayer(mainWindow);\n    layer = MetalLayerHandle(m_device, size, mainWindow);\n    layer.GetLayer()->setPixelFormat(MTL::PixelFormatBGRA8Unorm);\n}\n\nvoid MetalRenderer::ShutdownLayer(bool mainWindow)\n{\n    GetLayer(mainWindow) = MetalLayerHandle();\n}\n\nvoid MetalRenderer::ResizeLayer(const Vector2i& size, bool mainWindow)\n{\n    GetLayer(mainWindow).Resize(size);\n}\n\nvoid MetalRenderer::Initialize()\n{\n    Renderer::Initialize();\n    RendererShaderMtl::Initialize();\n}\n\nvoid MetalRenderer::Shutdown()\n{\n    // TODO: should shutdown both layers\n    ImGui_ImplMetal_Shutdown();\n    CommitCommandBuffer();\n    Renderer::Shutdown();\n    RendererShaderMtl::Shutdown();\n}\n\nbool MetalRenderer::IsPadWindowActive()\n{\n    return (GetLayer(false).GetLayer() != nullptr);\n}\n\nbool MetalRenderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const\n{\n    // Subtract host memory from total VRAM, since it's shared with the CPU\n    usageInMB = (m_device->currentAllocatedSize() - m_memoryManager->GetHostAllocationSize()) / 1024 / 1024;\n    totalInMB = m_recommendedMaxVRAMUsage / 1024 / 1024;\n\n    return true;\n}\n\nvoid MetalRenderer::ClearColorbuffer(bool padView)\n{\n    if (!AcquireDrawable(!padView))\n        return;\n\n    ClearColorTextureInternal(GetLayer(!padView).GetDrawable()->texture(), 0, 0, 0.0f, 0.0f, 0.0f, 0.0f);\n}\n\nvoid MetalRenderer::DrawEmptyFrame(bool mainWindow)\n{\n    if (!BeginFrame(mainWindow))\n\t\treturn;\n\tSwapBuffers(mainWindow, !mainWindow);\n}\n\nvoid MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC)\n{\n    if (swapTV)\n        SwapBuffer(true);\n    if (swapDRC)\n        SwapBuffer(false);\n\n    // Reset the command buffers (they are released by TemporaryBufferAllocator)\n    CommitCommandBuffer();\n\n    // Debug\n    m_performanceMonitor.ResetPerFrameData();\n\n    // GPU capture\n    if (m_capturing)\n    {\n        EndCapture();\n    }\n    else if (m_captureFrame)\n    {\n        StartCapture();\n        m_captureFrame = false;\n    }\n}\n\nvoid MetalRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool padView) {\n\tif (!m_screenshot_requested && m_screenshot_state == ScreenshotState::None)\n\t\treturn;\n\n\tif (m_mainLayer.GetDrawable())\n\t{\n\t\t// we already took a pad view screenshow and want a main window screenshot\n\t\tif (m_screenshot_state == ScreenshotState::Main && padView)\n\t\t\treturn;\n\n\t\tif (m_screenshot_state == ScreenshotState::Pad && !padView)\n\t\t\treturn;\n\n\t\t// remember which screenshot is left to take\n\t\tif (m_screenshot_state == ScreenshotState::None)\n\t\t\tm_screenshot_state = padView ? ScreenshotState::Main : ScreenshotState::Pad;\n\t\telse\n\t\t\tm_screenshot_state = ScreenshotState::None;\n\t}\n\telse\n\t\tm_screenshot_state = ScreenshotState::None;\n\n\tauto texMtl = static_cast<LatteTextureMtl*>(texView->baseTexture);\n\n\tint width, height;\n\ttexMtl->GetEffectiveSize(width, height, 0);\n\n\tuint32 bytesPerRow = GetMtlTextureBytesPerRow(texMtl->format, texMtl->isDepth, width);\n\tuint32 size = GetMtlTextureBytesPerImage(texMtl->format, texMtl->isDepth, height, bytesPerRow);\n\n\tauto blitCommandEncoder = GetBlitCommandEncoder();\n\n\tauto& bufferAllocator = m_memoryManager->GetStagingAllocator();\n\tauto buffer = bufferAllocator.AllocateBufferMemory(size, 1);\n\n\tblitCommandEncoder->copyFromTexture(texMtl->GetTexture(), 0, 0, MTL::Origin(0, 0, 0), MTL::Size(width, height, 1), buffer.mtlBuffer, buffer.bufferOffset, bytesPerRow, 0);\n\n\tbool formatValid = true;\n\tstd::vector<uint8> rgb_data;\n\trgb_data.reserve(3 * width * height);\n\n\tauto pixelFormat = texMtl->GetTexture()->pixelFormat();\n\t// TODO: implement more formats\n\tswitch (pixelFormat)\n\t{\n\tcase MTL::PixelFormatRGBA8Unorm:\n\t\tfor (auto ptr = buffer.memPtr; ptr < buffer.memPtr + size; ptr += 4)\n\t\t{\n\t\t\trgb_data.emplace_back(*ptr);\n\t\t\trgb_data.emplace_back(*(ptr + 1));\n\t\t\trgb_data.emplace_back(*(ptr + 2));\n\t\t}\n\t\tbreak;\n\tcase MTL::PixelFormatRGBA8Unorm_sRGB:\n\t\tfor (auto ptr = buffer.memPtr; ptr < buffer.memPtr + size; ptr += 4)\n\t\t{\n\t\t\trgb_data.emplace_back(SRGBComponentToRGB(*ptr));\n\t\t\trgb_data.emplace_back(SRGBComponentToRGB(*(ptr + 1)));\n\t\t\trgb_data.emplace_back(SRGBComponentToRGB(*(ptr + 2)));\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tcemuLog_log(LogType::Force, \"Unsupported screenshot texture pixel format {}\", pixelFormat);\n\t\tformatValid = false;\n\t\tbreak;\n\t}\n\n\tif (formatValid)\n\t\tSaveScreenshot(rgb_data, width, height, !padView);\n}\n\nvoid MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,\n\t\t\t\t\t\t\t\tsint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,\n\t\t\t\t\t\t\t\tbool padView, bool clearBackground)\n{\n    if (!AcquireDrawable(!padView))\n        return;\n\n    MTL::Texture* presentTexture = static_cast<LatteTextureViewMtl*>(texView)->GetRGBAView();\n\n    // Create render pass\n    auto& layer = GetLayer(!padView);\n\n    NS_STACK_SCOPED MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();\n    auto colorAttachment = renderPassDescriptor->colorAttachments()->object(0);\n    colorAttachment->setTexture(layer.GetDrawable()->texture());\n    colorAttachment->setLoadAction(clearBackground ? MTL::LoadActionClear : MTL::LoadActionLoad);\n    colorAttachment->setStoreAction(MTL::StoreActionStore);\n\n    auto renderCommandEncoder = GetTemporaryRenderCommandEncoder(renderPassDescriptor);\n\n    // Get a render pipeline\n\n    // Find out which shader we are using\n    uint8 shaderIndex = 255;\n    if (shader == RendererOutputShader::s_copy_shader) shaderIndex = 0;\n    else if (shader == RendererOutputShader::s_bicubic_shader) shaderIndex = 1;\n    else if (shader == RendererOutputShader::s_hermit_shader) shaderIndex = 2;\n    else if (shader == RendererOutputShader::s_copy_shader_ud) shaderIndex = 3;\n    else if (shader == RendererOutputShader::s_bicubic_shader_ud) shaderIndex = 4;\n    else if (shader == RendererOutputShader::s_hermit_shader_ud) shaderIndex = 5;\n\n    uint8 shaderType = shaderIndex % 3;\n\n    // Get the render pipeline state\n    auto renderPipelineState = m_outputShaderCache->GetPipeline(shader, shaderIndex, m_state.m_usesSRGB);\n\n    // Draw to Metal layer\n    renderCommandEncoder->setRenderPipelineState(renderPipelineState);\n    renderCommandEncoder->setFragmentTexture(presentTexture, 0);\n    renderCommandEncoder->setFragmentSamplerState((useLinearTexFilter ? m_linearSampler : m_nearestSampler), 0);\n\n    // Set uniforms\n    float outputSize[2] = {(float)imageWidth, (float)imageHeight};\n    switch (shaderType)\n    {\n    case 2:\n        renderCommandEncoder->setFragmentBytes(outputSize, sizeof(outputSize), 0);\n        break;\n    default:\n        break;\n    }\n\n    renderCommandEncoder->setViewport(MTL::Viewport{(double)imageX, (double)imageY, (double)imageWidth, (double)imageHeight, 0.0, 1.0});\n    renderCommandEncoder->setScissorRect(MTL::ScissorRect{(uint32)imageX, (uint32)imageY, (uint32)imageWidth, (uint32)imageHeight});\n\n    renderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangle, NS::UInteger(0), NS::UInteger(3));\n\n    EndEncoding();\n}\n\nbool MetalRenderer::BeginFrame(bool mainWindow)\n{\n    return AcquireDrawable(mainWindow);\n}\n\nvoid MetalRenderer::Flush(bool waitIdle)\n{\n    if (m_recordedDrawcalls > 0 || waitIdle)\n        CommitCommandBuffer();\n\n    if (waitIdle && m_executingCommandBuffers.size() != 0)\n        m_executingCommandBuffers.back()->waitUntilCompleted();\n}\n\nvoid MetalRenderer::NotifyLatteCommandProcessorIdle()\n{\n    //if (m_commitOnIdle)\n    //    CommitCommandBuffer();\n}\n\nbool MetalRenderer::ImguiBegin(bool mainWindow)\n{\n    if (!Renderer::ImguiBegin(mainWindow))\n\t\treturn false;\n\n\tif (!AcquireDrawable(mainWindow))\n\t\treturn false;\n\n\tEnsureImGuiBackend();\n\n\t// Check if the font texture needs to be built\n\tImGuiIO& io = ImGui::GetIO();\n    if (!io.Fonts->IsBuilt())\n        ImGui_ImplMetal_CreateFontsTexture(m_device);\n\n\tauto& layer = GetLayer(mainWindow);\n\n\t// Render pass descriptor\n\tNS_STACK_SCOPED MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();\n    auto colorAttachment = renderPassDescriptor->colorAttachments()->object(0);\n    colorAttachment->setTexture(layer.GetDrawable()->texture());\n    colorAttachment->setLoadAction(MTL::LoadActionLoad);\n    colorAttachment->setStoreAction(MTL::StoreActionStore);\n\n    // New frame\n\tImGui_ImplMetal_NewFrame(renderPassDescriptor);\n\tImGui_UpdateWindowInformation(mainWindow);\n\tImGui::NewFrame();\n\n\tif (m_encoderType != MetalEncoderType::Render)\n\t    GetTemporaryRenderCommandEncoder(renderPassDescriptor);\n\n\treturn true;\n}\n\nvoid MetalRenderer::ImguiEnd()\n{\n    EnsureImGuiBackend();\n\n    if (m_encoderType != MetalEncoderType::Render)\n    {\n        cemuLog_logOnce(LogType::Force, \"no render command encoder, cannot draw ImGui\");\n        return;\n    }\n\n    ImGui::Render();\n\tImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), GetCurrentCommandBuffer(), (MTL::RenderCommandEncoder*)m_commandEncoder);\n\t//ImGui::EndFrame();\n\n\tEndEncoding();\n}\n\nImTextureID MetalRenderer::GenerateTexture(const std::vector<uint8>& data, const Vector2i& size)\n{\n    try\n\t{\n\t\tstd::vector <uint8> tmp(size.x * size.y * 4);\n\t\tfor (size_t i = 0; i < data.size() / 3; ++i)\n\t\t{\n\t\t\ttmp[(i * 4) + 0] = data[(i * 3) + 0];\n\t\t\ttmp[(i * 4) + 1] = data[(i * 3) + 1];\n\t\t\ttmp[(i * 4) + 2] = data[(i * 3) + 2];\n\t\t\ttmp[(i * 4) + 3] = 0xFF;\n\t\t}\n\n\t\tNS_STACK_SCOPED MTL::TextureDescriptor* desc = MTL::TextureDescriptor::alloc()->init();\n\t\tdesc->setTextureType(MTL::TextureType2D);\n\t\tdesc->setPixelFormat(MTL::PixelFormatRGBA8Unorm);\n\t\tdesc->setWidth(size.x);\n\t\tdesc->setHeight(size.y);\n\t\tdesc->setStorageMode(m_isAppleGPU ? MTL::StorageModeShared : MTL::StorageModeManaged);\n\t\tdesc->setUsage(MTL::TextureUsageShaderRead);\n\n\t\tMTL::Texture* texture = m_device->newTexture(desc);\n\n\t\t// TODO: do a GPU copy?\n\t\ttexture->replaceRegion(MTL::Region(0, 0, size.x, size.y), 0, 0, tmp.data(), size.x * 4, 0);\n\n\t\treturn (ImTextureID)texture;\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"can't generate imgui texture: {}\", ex.what());\n\t\treturn nullptr;\n\t}\n}\n\nvoid MetalRenderer::DeleteTexture(ImTextureID id)\n{\n    EnsureImGuiBackend();\n\n    ((MTL::Texture*)id)->release();\n}\n\nvoid MetalRenderer::DeleteFontTextures()\n{\n    EnsureImGuiBackend();\n\n    ImGui_ImplMetal_DestroyFontsTexture();\n}\n\nvoid MetalRenderer::AppendOverlayDebugInfo()\n{\n    ImGui::Text(\"--- GPU info ---\");\n    ImGui::Text(\"GPU                        %s\", m_device->name()->utf8String());\n    ImGui::Text(\"Is Apple GPU               %s\", (m_isAppleGPU ? \"yes\" : \"no\"));\n    ImGui::Text(\"Supports framebuffer fetch %s\", (m_supportsFramebufferFetch ? \"yes\" : \"no\"));\n    ImGui::Text(\"Has unified memory         %s\", (m_hasUnifiedMemory ? \"yes\" : \"no\"));\n    ImGui::Text(\"Supports Metal3            %s\", (m_supportsMetal3 ? \"yes\" : \"no\"));\n\n    ImGui::Text(\"--- Metal info ---\");\n    ImGui::Text(\"Render pipeline states     %zu\", m_pipelineCache->GetPipelineCacheSize());\n\n    ImGui::Text(\"--- Metal info (per frame) ---\");\n    ImGui::Text(\"Command buffers            %u\", m_performanceMonitor.m_commandBuffers);\n    ImGui::Text(\"Render passes              %u\", m_performanceMonitor.m_renderPasses);\n    ImGui::Text(\"Clears                     %u\", m_performanceMonitor.m_clears);\n    ImGui::Text(\"Manual vertex fetch draws  %u (mesh draws: %u)\", m_performanceMonitor.m_manualVertexFetchDraws, m_performanceMonitor.m_meshDraws);\n    ImGui::Text(\"Triangle fans              %u\", m_performanceMonitor.m_triangleFans);\n\n    ImGui::Text(\"--- Cache debug info ---\");\n\n\tuint32 bufferCacheHeapSize = 0;\n\tuint32 bufferCacheAllocationSize = 0;\n\tuint32 bufferCacheNumAllocations = 0;\n\n\tLatteBufferCache_getStats(bufferCacheHeapSize, bufferCacheAllocationSize, bufferCacheNumAllocations);\n\n\tImGui::Text(\"Buffer\");\n\tImGui::SameLine(60.0f);\n\tImGui::Text(\"%06uKB / %06uKB Allocs: %u\", (uint32)(bufferCacheAllocationSize + 1023) / 1024, ((uint32)bufferCacheHeapSize + 1023) / 1024, (uint32)bufferCacheNumAllocations);\n\n\tuint32 numBuffers;\n\tsize_t totalSize, freeSize;\n\n\tm_memoryManager->GetStagingAllocator().GetStats(numBuffers, totalSize, freeSize);\n\tImGui::Text(\"Staging\");\n\tImGui::SameLine(60.0f);\n\tImGui::Text(\"%06uKB / %06uKB Buffers: %u\", ((uint32)(totalSize - freeSize) + 1023) / 1024, ((uint32)totalSize + 1023) / 1024, (uint32)numBuffers);\n\n\tm_memoryManager->GetIndexAllocator().GetStats(numBuffers, totalSize, freeSize);\n\tImGui::Text(\"Index\");\n\tImGui::SameLine(60.0f);\n\tImGui::Text(\"%06uKB / %06uKB Buffers: %u\", ((uint32)(totalSize - freeSize) + 1023) / 1024, ((uint32)totalSize + 1023) / 1024, (uint32)numBuffers);\n}\n\nvoid MetalRenderer::renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ)\n{\n    // halfZ is handled in the shader\n\n    m_state.m_viewport = MTL::Viewport{x, y, width, height, nearZ, farZ};\n}\n\nvoid MetalRenderer::renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight)\n{\n    m_state.m_scissor = MTL::ScissorRect{(uint32)scissorX, (uint32)scissorY, (uint32)scissorWidth, (uint32)scissorHeight};\n}\n\nLatteCachedFBO* MetalRenderer::rendertarget_createCachedFBO(uint64 key)\n{\n\treturn new CachedFBOMtl(this, key);\n}\n\nvoid MetalRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* cfbo)\n{\n\tif (cfbo == (LatteCachedFBO*)m_state.m_activeFBO.m_fbo)\n\t    m_state.m_activeFBO = {nullptr};\n}\n\nvoid MetalRenderer::rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo)\n{\n\tm_state.m_activeFBO = {(CachedFBOMtl*)cfbo, MetalAttachmentsInfo((CachedFBOMtl*)cfbo)};\n\tm_state.m_fboChanged = true;\n}\n\nvoid* MetalRenderer::texture_acquireTextureUploadBuffer(uint32 size)\n{\n    return m_memoryManager->AcquireTextureUploadBuffer(size);\n}\n\nvoid MetalRenderer::texture_releaseTextureUploadBuffer(uint8* mem)\n{\n    m_memoryManager->ReleaseTextureUploadBuffer(mem);\n}\n\nTextureDecoder* MetalRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height)\n{\n    return GetMtlPixelFormatInfo(format, isDepth).textureDecoder;\n}\n\nvoid MetalRenderer::texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex)\n{\n    if (hostTexture->isDepth)\n    {\n        texture_clearDepthSlice(hostTexture, sliceIndex, mipIndex, true, hostTexture->hasStencil, 0.0f, 0);\n    }\n    else\n    {\n        texture_clearColorSlice(hostTexture, sliceIndex, mipIndex, 0.0f, 0.0f, 0.0f, 0.0f);\n    }\n}\n\n// TODO: do a cpu copy on Apple Silicon?\nvoid MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize)\n{\n    auto textureMtl = (LatteTextureMtl*)hostTexture;\n\n    uint32 offsetZ = 0;\n    if (textureMtl->Is3DTexture())\n    {\n        offsetZ = sliceIndex;\n        sliceIndex = 0;\n    }\n\n    size_t bytesPerRow = GetMtlTextureBytesPerRow(textureMtl->format, textureMtl->isDepth, width);\n    // No need to set bytesPerImage for 3D textures, since we always load just one slice\n    //size_t bytesPerImage = GetMtlTextureBytesPerImage(textureMtl->GetFormat(), textureMtl->isDepth, height, bytesPerRow);\n    //if (m_isAppleGPU)\n    //{\n    //    textureMtl->GetTexture()->replaceRegion(MTL::Region(0, 0, offsetZ, width, height, 1), mipIndex, sliceIndex, pixelData, bytesPerRow, 0);\n    //}\n    //else\n    //{\n    auto blitCommandEncoder = GetBlitCommandEncoder();\n\n    // Allocate a temporary buffer\n    auto& bufferAllocator = m_memoryManager->GetStagingAllocator();\n    auto allocation = bufferAllocator.AllocateBufferMemory(compressedImageSize, 1);\n    memcpy(allocation.memPtr, pixelData, compressedImageSize);\n    bufferAllocator.FlushReservation(allocation);\n\n    // TODO: specify blit options when copying to a depth stencil texture?\n    // Copy the data from the temporary buffer to the texture\n    blitCommandEncoder->copyFromBuffer(allocation.mtlBuffer, allocation.bufferOffset, bytesPerRow, 0, MTL::Size(width, height, 1), textureMtl->GetTexture(), sliceIndex, mipIndex, MTL::Origin(0, 0, offsetZ));\n    //}\n}\n\nvoid MetalRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a)\n{\n    if (!FormatIsRenderable(hostTexture->format))\n    {\n        cemuLog_logOnce(LogType::Force, \"cannot clear color texture with format {}, because it's not renderable\", hostTexture->format);\n        return;\n    }\n\n    auto mtlTexture = static_cast<LatteTextureMtl*>(hostTexture)->GetTexture();\n\n    ClearColorTextureInternal(mtlTexture, sliceIndex, mipIndex, r, g, b, a);\n}\n\nvoid MetalRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue)\n{\n    clearStencil = (clearStencil && GetMtlPixelFormatInfo(hostTexture->format, true).hasStencil);\n    if (!clearDepth && !clearStencil)\n    {\n        cemuLog_logOnce(LogType::Force, \"skipping depth/stencil clear\");\n        return;\n    }\n\n    auto mtlTexture = static_cast<LatteTextureMtl*>(hostTexture)->GetTexture();\n\n    NS_STACK_SCOPED MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();\n    if (clearDepth)\n    {\n        auto depthAttachment = renderPassDescriptor->depthAttachment();\n        depthAttachment->setTexture(mtlTexture);\n        depthAttachment->setClearDepth(depthValue);\n        depthAttachment->setLoadAction(MTL::LoadActionClear);\n        depthAttachment->setStoreAction(MTL::StoreActionStore);\n        depthAttachment->setSlice(sliceIndex);\n        depthAttachment->setLevel(mipIndex);\n    }\n    if (clearStencil)\n    {\n        auto stencilAttachment = renderPassDescriptor->stencilAttachment();\n        stencilAttachment->setTexture(mtlTexture);\n        stencilAttachment->setClearStencil(stencilValue);\n        stencilAttachment->setLoadAction(MTL::LoadActionClear);\n        stencilAttachment->setStoreAction(MTL::StoreActionStore);\n        stencilAttachment->setSlice(sliceIndex);\n        stencilAttachment->setLevel(mipIndex);\n    }\n\n    GetTemporaryRenderCommandEncoder(renderPassDescriptor);\n    EndEncoding();\n\n    // Debug\n    m_performanceMonitor.m_clears++;\n}\n\nLatteTexture* MetalRenderer::texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth)\n{\n    return new LatteTextureMtl(this, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth);\n}\n\nvoid MetalRenderer::texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit)\n{\n    m_state.m_textures[textureUnit] = static_cast<LatteTextureViewMtl*>(textureView);\n}\n\nvoid MetalRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth_)\n{\n    // Source size seems to apply to the destination texture as well, therefore we need to adjust it when block size doesn't match\n    Uvec2 srcBlockTexelSize = GetMtlPixelFormatInfo(src->format, src->isDepth).blockTexelSize;\n    Uvec2 dstBlockTexelSize = GetMtlPixelFormatInfo(dst->format, dst->isDepth).blockTexelSize;\n    if (srcBlockTexelSize.x != dstBlockTexelSize.x || srcBlockTexelSize.y != dstBlockTexelSize.y)\n    {\n        uint32 multX = (srcBlockTexelSize.x > dstBlockTexelSize.x ? srcBlockTexelSize.x / dstBlockTexelSize.x : dstBlockTexelSize.x / srcBlockTexelSize.x);\n        effectiveCopyWidth *= multX;\n\n        uint32 multY = (srcBlockTexelSize.y > dstBlockTexelSize.y ? srcBlockTexelSize.y / dstBlockTexelSize.y : dstBlockTexelSize.y / srcBlockTexelSize.y);\n        effectiveCopyHeight *= multY;\n    }\n\n    auto blitCommandEncoder = GetBlitCommandEncoder();\n\n    auto mtlSrc = static_cast<LatteTextureMtl*>(src)->GetTexture();\n    auto mtlDst = static_cast<LatteTextureMtl*>(dst)->GetTexture();\n\n    uint32 srcBaseLayer = 0;\n    uint32 dstBaseLayer = 0;\n    uint32 srcOffsetZ = 0;\n    uint32 dstOffsetZ = 0;\n    uint32 srcLayerCount = 1;\n    uint32 dstLayerCount = 1;\n    uint32 srcDepth = 1;\n    uint32 dstDepth = 1;\n\n\tif (src->Is3DTexture())\n\t{\n\t\tsrcOffsetZ = srcSlice;\n\t\tsrcDepth = srcDepth_;\n\t}\n\telse\n\t{\n\t\tsrcBaseLayer = srcSlice;\n\t\tsrcLayerCount = srcDepth_;\n\t}\n\n\tif (dst->Is3DTexture())\n\t{\n\t\tdstOffsetZ = dstSlice;\n\t\tdstDepth = srcDepth_;\n\t}\n\telse\n\t{\n\t\tdstBaseLayer = dstSlice;\n\t\tdstLayerCount = srcDepth_;\n\t}\n\n\t// If copying whole textures, we can do a more efficient copy\n    if (effectiveSrcX == 0 && effectiveSrcY == 0 && effectiveDstX == 0 && effectiveDstY == 0 &&\n        srcOffsetZ == 0 && dstOffsetZ == 0 &&\n        effectiveCopyWidth == src->GetMipWidth(srcMip) && effectiveCopyHeight == src->GetMipHeight(srcMip) && srcDepth == src->GetMipDepth(srcMip) &&\n        effectiveCopyWidth == dst->GetMipWidth(dstMip) && effectiveCopyHeight == dst->GetMipHeight(dstMip) && dstDepth == dst->GetMipDepth(dstMip) &&\n        srcLayerCount == dstLayerCount)\n    {\n        blitCommandEncoder->copyFromTexture(mtlSrc, srcBaseLayer, srcMip, mtlDst, dstBaseLayer, dstMip, srcLayerCount, 1);\n    }\n    else\n    {\n        if (srcLayerCount == dstLayerCount)\n        {\n            for (uint32 i = 0; i < srcLayerCount; i++)\n            {\n                blitCommandEncoder->copyFromTexture(mtlSrc, srcBaseLayer + i, srcMip, MTL::Origin(effectiveSrcX, effectiveSrcY, srcOffsetZ), MTL::Size(effectiveCopyWidth, effectiveCopyHeight, srcDepth), mtlDst, dstBaseLayer + i, dstMip, MTL::Origin(effectiveDstX, effectiveDstY, dstOffsetZ));\n            }\n        }\n        else\n        {\n            for (uint32 i = 0; i < std::max(srcLayerCount, dstLayerCount); i++)\n            {\n                if (srcLayerCount == 1)\n                    srcOffsetZ++;\n                else\n                    srcSlice++;\n\n                if (dstLayerCount == 1)\n                    dstOffsetZ++;\n                else\n                    dstSlice++;\n\n                blitCommandEncoder->copyFromTexture(mtlSrc, srcBaseLayer, srcMip, MTL::Origin(effectiveSrcX, effectiveSrcY, srcOffsetZ), MTL::Size(effectiveCopyWidth, effectiveCopyHeight, 1), mtlDst, dstBaseLayer, dstMip, MTL::Origin(effectiveDstX, effectiveDstY, dstOffsetZ));\n            }\n        }\n    }\n}\n\nLatteTextureReadbackInfo* MetalRenderer::texture_createReadback(LatteTextureView* textureView)\n{\n    size_t uploadSize = static_cast<LatteTextureMtl*>(textureView->baseTexture)->GetTexture()->allocatedSize();\n\n    if ((m_readbackBufferWriteOffset + uploadSize) > TEXTURE_READBACK_SIZE)\n\t{\n\t\tm_readbackBufferWriteOffset = 0;\n\t}\n\n    auto* result = new LatteTextureReadbackInfoMtl(this, textureView, m_readbackBufferWriteOffset);\n    m_readbackBufferWriteOffset += uploadSize;\n\n\treturn result;\n}\n\nvoid MetalRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height)\n{\n    // scale copy size to effective size\n\tsint32 effectiveCopyWidth = width;\n\tsint32 effectiveCopyHeight = height;\n\tLatteTexture_scaleToEffectiveSize(sourceTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0);\n\t//sint32 sourceEffectiveWidth, sourceEffectiveHeight;\n\t//sourceTexture->GetEffectiveSize(sourceEffectiveWidth, sourceEffectiveHeight, srcMip);\n\n    texture_copyImageSubData(sourceTexture, srcMip, 0, 0, srcSlice, destinationTexture, dstMip, 0, 0, dstSlice, effectiveCopyWidth, effectiveCopyHeight, 1);\n}\n\nvoid MetalRenderer::bufferCache_init(const sint32 bufferSize)\n{\n    m_memoryManager->InitBufferCache(bufferSize);\n}\n\nvoid MetalRenderer::bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset)\n{\n    m_memoryManager->UploadToBufferCache(buffer, bufferOffset, size);\n}\n\nvoid MetalRenderer::bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size)\n{\n    m_memoryManager->CopyBufferCache(srcOffset, dstOffset, size);\n}\n\nvoid MetalRenderer::bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size)\n{\n    if (m_memoryManager->UseHostMemoryForCache())\n        dstOffset -= m_memoryManager->GetImportedMemBaseAddress();\n\n    CopyBufferToBuffer(GetXfbRingBuffer(), srcOffset, m_memoryManager->GetBufferCache(), dstOffset, size, MTL::RenderStageVertex | MTL::RenderStageMesh, ALL_MTL_RENDER_STAGES);\n}\n\nvoid MetalRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size)\n{\n    cemu_assert_debug(!m_memoryManager->UseHostMemoryForCache());\n    cemu_assert_debug(bufferIndex < LATTE_MAX_VERTEX_BUFFERS);\n\n    m_state.m_vertexBufferOffsets[bufferIndex] = offset;\n}\n\nvoid MetalRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size)\n{\n    cemu_assert_debug(!m_memoryManager->UseHostMemoryForCache());\n\n    m_state.m_uniformBufferOffsets[GetMtlGeneralShaderType(shaderType)][bufferIndex] = offset;\n}\n\nRendererShader* MetalRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader)\n{\n    return new RendererShaderMtl(this, type, baseHash, auxHash, isGameShader, isGfxPackShader, source);\n}\n\nvoid MetalRenderer::streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize)\n{\n    m_state.m_streamoutState.buffers[bufferIndex].enabled = true;\n\tm_state.m_streamoutState.buffers[bufferIndex].ringBufferOffset = ringBufferOffset;\n}\n\nvoid MetalRenderer::streamout_begin()\n{\n    // Do nothing\n}\n\nvoid MetalRenderer::streamout_rendererFinishDrawcall()\n{\n    // Do nothing\n}\n\nvoid MetalRenderer::draw_beginSequence()\n{\n    m_state.m_skipDrawSequence = false;\n\n    bool streamoutEnable = LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] != 0;\n\n    // update shader state\n\tLatteSHRC_UpdateActiveShaders();\n\tif (LatteGPUState.activeShaderHasError)\n\t{\n\t\tcemuLog_logOnce(LogType::Force, \"Skipping drawcalls due to shader error\\n\");\n\t\tm_state.m_skipDrawSequence = true;\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\n\t// update render target and texture state\n\tLatteGPUState.requiresTextureBarrier = false;\n\twhile (true)\n\t{\n\t\tLatteGPUState.repeatTextureInitialization = false;\n\t\tif (!LatteMRT::UpdateCurrentFBO())\n\t\t{\n\t\t\tcemuLog_logOnce(LogType::Force, \"Rendertarget invalid\\n\");\n\t\t\tm_state.m_skipDrawSequence = true;\n\t\t\treturn; // no render target\n\t\t}\n\n\t\tif (!hasValidFramebufferAttached && !streamoutEnable)\n\t\t{\n\t\t\tcemuLog_logOnce(LogType::Force, \"Drawcall with no color buffer or depth buffer attached\\n\");\n\t\t\tm_state.m_skipDrawSequence = true;\n\t\t\treturn; // no render target\n\t\t}\n\t\tLatteTexture_updateTextures();\n\t\tif (!LatteGPUState.repeatTextureInitialization)\n\t\t\tbreak;\n\t}\n\n\t// apply render target\n\tLatteMRT::ApplyCurrentState();\n\n\t// viewport and scissor box\n\tLatteRenderTarget_updateViewport();\n\tLatteRenderTarget_updateScissorBox();\n\n\tif (!LatteGPUState.contextNew.IsRasterizationEnabled() && !streamoutEnable)\n\t\tm_state.m_skipDrawSequence = true;\n}\n\nvoid MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst)\n{\n    if (m_state.m_skipDrawSequence)\n\t{\n\t    LatteGPUState.drawCallCounter++;\n\t\treturn;\n\t}\n\n\t// fast clear color as depth\n\tif (LatteGPUState.contextNew.GetSpecialStateValues()[8] != 0)\n\t{\n\t\tLatteDraw_handleSpecialState8_clearAsDepth();\n\t\tLatteGPUState.drawCallCounter++;\n\t\treturn;\n\t}\n\telse if (LatteGPUState.contextNew.GetSpecialStateValues()[5] != 0)\n\t{\n\t\tdraw_handleSpecialState5();\n\t\tLatteGPUState.drawCallCounter++;\n\t\treturn;\n\t}\n\n\tauto& encoderState = m_state.m_encoderState;\n\n    // Shaders\n    LatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();\n    LatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader();\n    LatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();\n    const auto fetchShader = LatteSHRC_GetActiveFetchShader();\n\n    /*\n    bool neverSkipAccurateBarrier = false;\n\n    // \"Accurate barriers\" is usually enabled globally but since the CPU cost is substantial we allow users to disable it (debug -> 'Accurate barriers' option)\n\t// We always force accurate barriers for known problematic shaders\n\tif (pixelShader)\n\t{\n\t\tif (pixelShader->baseHash == 0x6f6f6e7b9aae57af && pixelShader->auxHash == 0x00078787f9249249) // BotW lava\n\t\t\tneverSkipAccurateBarrier = true;\n\t\tif (pixelShader->baseHash == 0x4c0bd596e3aef4a6 && pixelShader->auxHash == 0x003c3c3fc9269249) // BotW foam layer for water on the bottom of waterfalls\n\t\t\tneverSkipAccurateBarrier = true;\n\t}\n\n\t// Check if we need to end the render pass\n\tif (!m_state.m_isFirstDrawInRenderPass && (GetConfig().vk_accurate_barriers || neverSkipAccurateBarrier))\n\t{\n    \t// Fragment shader is most likely to require a render pass flush, so check for it first\n    \tbool endRenderPass = CheckIfRenderPassNeedsFlush(pixelShader);\n    \tif (!endRenderPass)\n    \t    endRenderPass = CheckIfRenderPassNeedsFlush(vertexShader);\n    \tif (!endRenderPass && geometryShader)\n    \t    endRenderPass = CheckIfRenderPassNeedsFlush(geometryShader);\n\n    \tif (endRenderPass)\n        {\n    \t    EndEncoding();\n            // TODO: only log in debug?\n            cemuLog_logOnce(LogType::Force, \"Ending render pass due to render target self-dependency\\n\");\n        }\n\t}\n\t*/\n\n    // Primitive type\n    const LattePrimitiveMode primitiveMode = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();\n    auto mtlPrimitiveType = GetMtlPrimitiveType(primitiveMode);\n\n    bool usesGeometryShader = UseGeometryShader(LatteGPUState.contextNew, geometryShader != nullptr);\n    if (usesGeometryShader && !m_supportsMeshShaders)\n        return;\n\n    bool fetchVertexManually = (usesGeometryShader || fetchShader->mtlFetchVertexManually);\n\n\t// Index buffer\n\tRenderer::INDEX_TYPE hostIndexType;\n\tuint32 hostIndexCount;\n\tuint32 indexMin = 0;\n\tuint32 indexMax = 0;\n\tRenderer::IndexAllocation indexAllocation;\n\tLatteIndices_decode(memory_getPointerFromVirtualOffset(indexDataMPTR), indexType, count, primitiveMode, indexMin, indexMax, hostIndexType, hostIndexCount, indexAllocation);\n\tauto indexAllocationMtl = static_cast<MetalSynchronizedHeapAllocator::AllocatorReservation*>(indexAllocation.rendererInternal);\n\n\t// Buffer cache\n\tif (m_memoryManager->UseHostMemoryForCache())\n\t{\n\t\t// direct memory access (Wii U memory space imported as a buffer), update buffer bindings\n\t\tdraw_updateVertexBuffersDirectAccess();\n\t\tif (vertexShader)\n\t\t\tdraw_updateUniformBuffersDirectAccess(vertexShader, mmSQ_VTX_UNIFORM_BLOCK_START);\n\t\tif (geometryShader)\n\t\t\tdraw_updateUniformBuffersDirectAccess(geometryShader, mmSQ_GS_UNIFORM_BLOCK_START);\n\t\tif (pixelShader)\n\t\t\tdraw_updateUniformBuffersDirectAccess(pixelShader, mmSQ_PS_UNIFORM_BLOCK_START);\n\t}\n\telse\n\t{\n    \t// synchronize vertex and uniform cache and update buffer bindings\n    \t// We need to call this before getting the render command encoder, since it can cause buffer copies\n    \tLatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount);\n\t}\n\n\t// Render pass\n\tauto renderCommandEncoder = GetRenderCommandEncoder();\n\n    // Render pipeline state\n    PipelineObject* pipelineObj = m_pipelineCache->GetRenderPipelineState(fetchShader, vertexShader, geometryShader, pixelShader, m_state.m_lastUsedFBO.m_attachmentsInfo, m_state.m_activeFBO.m_attachmentsInfo, m_state.m_activeFBO.m_fbo->m_size, count, LatteGPUState.contextNew);\n    if (!pipelineObj->m_pipeline)\n        return;\n\n    if (pipelineObj->m_pipeline != encoderState.m_renderPipelineState)\n   \t{\n        renderCommandEncoder->setRenderPipelineState(pipelineObj->m_pipeline);\n  \t\tencoderState.m_renderPipelineState = pipelineObj->m_pipeline;\n   \t}\n\n\t// Depth stencil state\n\n\t// Disable depth write when there is no depth attachment\n\tauto& depthControl = LatteGPUState.contextNew.DB_DEPTH_CONTROL;\n\tbool depthWriteEnable = depthControl.get_Z_WRITE_ENABLE();\n\tif (!m_state.m_activeFBO.m_fbo->depthBuffer.texture)\n\t    depthControl.set_Z_WRITE_ENABLE(false);\n\n\tMTL::DepthStencilState* depthStencilState = m_depthStencilCache->GetDepthStencilState(LatteGPUState.contextNew);\n\tif (depthStencilState != encoderState.m_depthStencilState)\n\t{\n\t    renderCommandEncoder->setDepthStencilState(depthStencilState);\n\t\tencoderState.m_depthStencilState = depthStencilState;\n\t}\n\n\t// Restore the original depth write state\n\tdepthControl.set_Z_WRITE_ENABLE(depthWriteEnable);\n\n\t// Stencil reference\n\tbool stencilEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ENABLE();\n\tif (stencilEnable)\n\t{\n\t    bool backStencilEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_BACK_STENCIL_ENABLE();\n\t\tuint32 stencilRefFront = LatteGPUState.contextNew.DB_STENCILREFMASK.get_STENCILREF_F();\n    \tuint32 stencilRefBack;\n        if (backStencilEnable)\n            stencilRefBack = LatteGPUState.contextNew.DB_STENCILREFMASK_BF.get_STENCILREF_B();\n        else\n            stencilRefBack = stencilRefFront;\n\n\t    if (stencilRefFront != encoderState.m_stencilRefFront || stencilRefBack != encoderState.m_stencilRefBack)\n\t\t{\n\t\t    renderCommandEncoder->setStencilReferenceValues(stencilRefFront, stencilRefBack);\n\n\t\t\tencoderState.m_stencilRefFront = stencilRefFront;\n\t\t\tencoderState.m_stencilRefBack = stencilRefBack;\n\t\t}\n\t}\n\n\t// Blend color\n\tuint32* blendColorConstantU32 = LatteGPUState.contextRegister + Latte::REGADDR::CB_BLEND_RED;\n\n\tif (blendColorConstantU32[0] != encoderState.m_blendColor[0] || blendColorConstantU32[1] != encoderState.m_blendColor[1] || blendColorConstantU32[2] != encoderState.m_blendColor[2] || blendColorConstantU32[3] != encoderState.m_blendColor[3])\n\t{\n    \tfloat* blendColorConstant = (float*)LatteGPUState.contextRegister + Latte::REGADDR::CB_BLEND_RED;\n    \trenderCommandEncoder->setBlendColor(blendColorConstant[0], blendColorConstant[1], blendColorConstant[2], blendColorConstant[3]);\n\n        encoderState.m_blendColor[0] = blendColorConstantU32[0];\n        encoderState.m_blendColor[1] = blendColorConstantU32[1];\n        encoderState.m_blendColor[2] = blendColorConstantU32[2];\n        encoderState.m_blendColor[3] = blendColorConstantU32[3];\n\t}\n\n\t// polygon control\n\tconst auto& polygonControlReg = LatteGPUState.contextNew.PA_SU_SC_MODE_CNTL;\n\tconst auto frontFace = polygonControlReg.get_FRONT_FACE();\n\tuint32 cullFront = polygonControlReg.get_CULL_FRONT();\n\tuint32 cullBack = polygonControlReg.get_CULL_BACK();\n\tuint32 polyOffsetFrontEnable = polygonControlReg.get_OFFSET_FRONT_ENABLED();\n\n\tif (polyOffsetFrontEnable)\n\t{\n    \tuint32 frontScaleU32 = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_SCALE.getRawValue();\n    \tuint32 frontOffsetU32 = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_OFFSET.getRawValue();\n    \tuint32 offsetClampU32 = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_CLAMP.getRawValue();\n\n        if (frontOffsetU32 != encoderState.m_depthBias || frontScaleU32 != encoderState.m_depthSlope || offsetClampU32 != encoderState.m_depthClamp)\n        {\n           \tfloat frontScale = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_SCALE.get_SCALE();\n           \tfloat frontOffset = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_OFFSET.get_OFFSET();\n           \tfloat offsetClamp = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_CLAMP.get_CLAMP();\n\n           \tfrontScale /= 16.0f;\n\n            renderCommandEncoder->setDepthBias(frontOffset, frontScale, offsetClamp);\n\n            encoderState.m_depthBias = frontOffsetU32;\n            encoderState.m_depthSlope = frontScaleU32;\n            encoderState.m_depthClamp = offsetClampU32;\n        }\n\t}\n\telse\n\t{\n\t    if (0 != encoderState.m_depthBias || 0 != encoderState.m_depthSlope || 0 != encoderState.m_depthClamp)\n\t\t{\n\t        renderCommandEncoder->setDepthBias(0.0f, 0.0f, 0.0f);\n\n\t\t\tencoderState.m_depthBias = 0;\n\t\t\tencoderState.m_depthSlope = 0;\n\t\t\tencoderState.m_depthClamp = 0;\n\t\t}\n\t}\n\n\t// Depth clip mode\n\tcemu_assert_debug(LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_NEAR_DISABLE() == LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_FAR_DISABLE()); // near or far clipping can be disabled individually\n\tbool zClipEnable = LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_FAR_DISABLE() == false;\n\n\tif (zClipEnable != encoderState.m_depthClipEnable)\n\t{\n\t    renderCommandEncoder->setDepthClipMode(zClipEnable ? MTL::DepthClipModeClip : MTL::DepthClipModeClamp);\n        encoderState.m_depthClipEnable = zClipEnable;\n\t}\n\n\t// Visibility result mode\n\tif (m_occlusionQuery.m_active)\n\t{\n\t    auto mode = (m_occlusionQuery.m_currentIndex == INVALID_UINT32 ? MTL::VisibilityResultModeDisabled : MTL::VisibilityResultModeCounting);\n\t    renderCommandEncoder->setVisibilityResultMode(mode, m_occlusionQuery.m_currentIndex * sizeof(uint64));\n\t}\n\n\t// todo - how does culling behave with rects?\n\t// right now we just assume that their winding is always CW\n\tif (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS)\n\t{\n\t\tif (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CW)\n\t\t\tcullFront = cullBack;\n\t\telse\n\t\t\tcullBack = cullFront;\n\t}\n\n\t// Cull mode\n\n\t// Cull front and back is handled by disabling rasterization\n\tif (!(cullFront && cullBack))\n\t{\n        MTL::CullMode cullMode;\n       \tif (cullFront)\n      \t\tcullMode = MTL::CullModeFront;\n       \telse if (cullBack)\n      \t\tcullMode = MTL::CullModeBack;\n       \telse\n      \t\tcullMode = MTL::CullModeNone;\n\n        if (cullMode != encoderState.m_cullMode)\n       \t{\n       \t    renderCommandEncoder->setCullMode(cullMode);\n      \t\tencoderState.m_cullMode = cullMode;\n       \t}\n\t}\n\n\t// Front face\n\tMTL::Winding frontFaceWinding;\n\tif (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CCW)\n\t\tfrontFaceWinding = MTL::WindingCounterClockwise;\n\telse\n\t\tfrontFaceWinding = MTL::WindingClockwise;\n\n    if (frontFaceWinding != encoderState.m_frontFaceWinding)\n   \t{\n   \t    renderCommandEncoder->setFrontFacingWinding(frontFaceWinding);\n  \t\tencoderState.m_frontFaceWinding = frontFaceWinding;\n   \t}\n\n    // Viewport\n    if (m_state.m_viewport.originX != encoderState.m_viewport.originX ||\n        m_state.m_viewport.originY != encoderState.m_viewport.originY ||\n        m_state.m_viewport.width != encoderState.m_viewport.width ||\n        m_state.m_viewport.height != encoderState.m_viewport.height ||\n        m_state.m_viewport.znear != encoderState.m_viewport.znear ||\n        m_state.m_viewport.zfar != encoderState.m_viewport.zfar)\n    {\n        renderCommandEncoder->setViewport(m_state.m_viewport);\n\n        encoderState.m_viewport = m_state.m_viewport;\n    }\n\n    // Scissor\n    if (m_state.m_scissor.x != encoderState.m_scissor.x ||\n        m_state.m_scissor.y != encoderState.m_scissor.y ||\n        m_state.m_scissor.width != encoderState.m_scissor.width ||\n        m_state.m_scissor.height != encoderState.m_scissor.height)\n    {\n        encoderState.m_scissor = m_state.m_scissor;\n\n        // TODO: clamp scissor to render target dimensions?\n        //scissor.width = ;\n        //scissor.height = ;\n        renderCommandEncoder->setScissorRect(encoderState.m_scissor);\n    }\n\n\t// Resources\n\n\t// Vertex buffers\n    for (uint8 i = 0; i < MAX_MTL_VERTEX_BUFFERS; i++)\n    {\n        size_t offset = m_state.m_vertexBufferOffsets[i];\n        if (offset != INVALID_OFFSET)\n        {\n            // Bind\n            SetBuffer(renderCommandEncoder, GetMtlShaderType(vertexShader->shaderType, usesGeometryShader), m_memoryManager->GetBufferCache(), offset, GET_MTL_VERTEX_BUFFER_INDEX(i));\n        }\n    }\n\n\t// Prepare streamout\n\tm_state.m_streamoutState.verticesPerInstance = count;\n\tLatteStreamout_PrepareDrawcall(count, instanceCount);\n\n\t// Uniform buffers, textures and samplers\n\tBindStageResources(renderCommandEncoder, vertexShader, usesGeometryShader);\n\tif (usesGeometryShader && geometryShader)\n\t    BindStageResources(renderCommandEncoder, geometryShader, usesGeometryShader);\n\tBindStageResources(renderCommandEncoder, pixelShader, usesGeometryShader);\n\n\t// Draw\n\tif (usesGeometryShader)\n\t{\n\t    if (hostIndexType != INDEX_TYPE::NONE)\n\t\t    SetBuffer(renderCommandEncoder, METAL_SHADER_TYPE_OBJECT, indexAllocationMtl->mtlBuffer, indexAllocationMtl->bufferOffset, vertexShader->resourceMapping.indexBufferBinding);\n\n\t\tuint8 hostIndexTypeU8 = (uint8)hostIndexType;\n\t\trenderCommandEncoder->setObjectBytes(&hostIndexTypeU8, sizeof(hostIndexTypeU8), vertexShader->resourceMapping.indexTypeBinding);\n        encoderState.m_buffers[METAL_SHADER_TYPE_OBJECT][vertexShader->resourceMapping.indexTypeBinding] = {nullptr};\n\n\t\tuint32 verticesPerPrimitive = GetVerticesPerPrimitive(primitiveMode);\n\t\tuint32 threadgroupCount = count * instanceCount;\n\t\tif (PrimitiveRequiresConnection(primitiveMode))\n\t\t    threadgroupCount -= verticesPerPrimitive - 1;\n\t\telse\n\t\t    threadgroupCount /= verticesPerPrimitive;\n\n\t\trenderCommandEncoder->drawMeshThreadgroups(MTL::Size(threadgroupCount, 1, 1), MTL::Size(verticesPerPrimitive, 1, 1), MTL::Size(1, 1, 1));\n\t}\n\telse\n\t{\n        if (hostIndexType != INDEX_TYPE::NONE)\n       \t{\n       \t    auto mtlIndexType = GetMtlIndexType(hostIndexType);\n      \t\trenderCommandEncoder->drawIndexedPrimitives(mtlPrimitiveType, hostIndexCount, mtlIndexType, indexAllocationMtl->mtlBuffer, indexAllocationMtl->bufferOffset, instanceCount, baseVertex, baseInstance);\n       \t}\n       \telse\n       \t{\n      \t\trenderCommandEncoder->drawPrimitives(mtlPrimitiveType, baseVertex, count, instanceCount, baseInstance);\n       \t}\n\t}\n\n\tm_state.m_isFirstDrawInRenderPass = false;\n\n\t// Occlusion queries\n\tif (m_occlusionQuery.m_active)\n\t    m_occlusionQuery.m_currentIndex = (m_occlusionQuery.m_currentIndex + 1) % OCCLUSION_QUERY_POOL_SIZE;\n\n\t// Streamout\n\tLatteStreamout_FinishDrawcall(m_memoryManager->UseHostMemoryForCache());\n\n\t// Debug\n\tif (fetchVertexManually)\n\t    m_performanceMonitor.m_manualVertexFetchDraws++;\n\tif (usesGeometryShader)\n\t    m_performanceMonitor.m_meshDraws++;\n\tif (primitiveMode == LattePrimitiveMode::TRIANGLE_FAN)\n\t    m_performanceMonitor.m_triangleFans++;\n\n\tLatteGPUState.drawCallCounter++;\n}\n\nvoid MetalRenderer::draw_endSequence()\n{\n    LatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();\n\t// post-drawcall logic\n\tif (pixelShader)\n\t\tLatteRenderTarget_trackUpdates();\n\tbool hasReadback = LatteTextureReadback_Update();\n\tm_recordedDrawcalls++;\n\t// The number of draw calls needs to twice as big, since we are interrupting the render pass\n\t// TODO: ucomment?\n\tif (m_recordedDrawcalls >= m_commitTreshold * 2/* || hasReadback*/)\n\t{\n\t\tCommitCommandBuffer();\n\n        // TODO: where should this be called?\n        LatteTextureReadback_UpdateFinishedTransfers(false);\n\t}\n}\n\nvoid MetalRenderer::draw_updateVertexBuffersDirectAccess()\n{\n\tLatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader();\n\tif (!parsedFetchShader)\n\t\treturn;\n\n\tfor (auto& bufferGroup : parsedFetchShader->bufferGroups)\n\t{\n\t\tuint32 bufferIndex = bufferGroup.attributeBufferIndex;\n\t\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n\t\tMPTR bufferAddress = LatteGPUState.contextRegister[bufferBaseRegisterIndex + 0];\n\n\t\tif (bufferAddress == MPTR_NULL) [[unlikely]]\n\t\t\tbufferAddress = m_memoryManager->GetImportedMemBaseAddress();\n\n\t\tm_state.m_vertexBufferOffsets[bufferIndex] = bufferAddress - m_memoryManager->GetImportedMemBaseAddress();\n\t}\n}\n\nvoid MetalRenderer::draw_updateUniformBuffersDirectAccess(LatteDecompilerShader* shader, const uint32 uniformBufferRegOffset)\n{\n\tif (shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)\n\t{\n\t\tfor (const auto& buf : shader->list_quickBufferList)\n\t\t{\n\t\t\tsint32 i = buf.index;\n\t\t\tMPTR physicalAddr = LatteGPUState.contextRegister[uniformBufferRegOffset + i * 7 + 0];\n\t\t\tuint32 uniformSize = LatteGPUState.contextRegister[uniformBufferRegOffset + i * 7 + 1] + 1;\n\n\t\t\tif (physicalAddr == MPTR_NULL) [[unlikely]]\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tuniformSize = std::min<uint32>(uniformSize, buf.size);\n\n\t\t\tcemu_assert_debug(physicalAddr < 0x50000000);\n\n\t\t\tuint32 bufferIndex = i;\n\t\t\tcemu_assert_debug(bufferIndex < 16);\n\n\t\t\tm_state.m_uniformBufferOffsets[GetMtlGeneralShaderType(shader->shaderType)][bufferIndex] = physicalAddr - m_memoryManager->GetImportedMemBaseAddress();\n\t\t}\n\t}\n}\n\nvoid MetalRenderer::draw_handleSpecialState5()\n{\n    LatteMRT::UpdateCurrentFBO();\n\tLatteRenderTarget_updateViewport();\n\n\tLatteTextureView* colorBuffer = LatteMRT::GetColorAttachment(0);\n\tLatteTextureView* depthBuffer = LatteMRT::GetDepthAttachment();\n\tauto colorTextureMtl = static_cast<LatteTextureViewMtl*>(colorBuffer);\n\tauto depthTextureMtl = static_cast<LatteTextureViewMtl*>(depthBuffer);\n\n\tsint32 vpWidth, vpHeight;\n\tLatteMRT::GetVirtualViewportDimensions(vpWidth, vpHeight);\n\n\t// Get the pipeline\n\tMTL::PixelFormat colorPixelFormat = colorTextureMtl->GetRGBAView()->pixelFormat();\n\tauto& pipeline = m_copyDepthToColorPipelines[colorPixelFormat];\n\tif (!pipeline)\n\t{\n\t    m_copyDepthToColorDesc->colorAttachments()->object(0)->setPixelFormat(colorPixelFormat);\n\n        NS::Error* error = nullptr;\n        pipeline = m_device->newRenderPipelineState(m_copyDepthToColorDesc, &error);\n        if (error)\n        {\n            cemuLog_log(LogType::Force, \"failed to create copy depth to color pipeline (error: {})\", error->localizedDescription()->utf8String());\n        }\n\t}\n\n\t// Sadly, we need to end encoding to ensure that the depth data is up-to-date\n\tEndEncoding();\n\n\t// Copy depth to color\n\tauto renderCommandEncoder = GetRenderCommandEncoder();\n\n\tauto& encoderState = m_state.m_encoderState;\n\n\trenderCommandEncoder->setRenderPipelineState(pipeline);\n\t// TODO: make a helper function for this\n\tencoderState.m_renderPipelineState = pipeline;\n\tSetTexture(renderCommandEncoder, METAL_SHADER_TYPE_FRAGMENT, depthTextureMtl->GetRGBAView(), GET_HELPER_TEXTURE_BINDING(0));\n\t// TODO: make a helper function for this\n\trenderCommandEncoder->setFragmentBytes(&vpWidth, sizeof(sint32), GET_HELPER_BUFFER_BINDING(0));\n\tencoderState.m_buffers[METAL_SHADER_TYPE_FRAGMENT][GET_HELPER_BUFFER_BINDING(0)] = {nullptr};\n\n\trenderCommandEncoder->drawPrimitives(MTL::PrimitiveTypeTriangle,  NS::UInteger(0),  NS::UInteger(3));\n}\n\nRenderer::IndexAllocation MetalRenderer::indexData_reserveIndexMemory(uint32 size)\n{\n    auto allocation = m_memoryManager->GetIndexAllocator().AllocateBufferMemory(size, 128);\n\n    return {allocation->memPtr, allocation};\n}\n\nvoid MetalRenderer::indexData_releaseIndexMemory(IndexAllocation& allocation)\n{\n    m_memoryManager->GetIndexAllocator().FreeReservation(static_cast<MetalSynchronizedHeapAllocator::AllocatorReservation*>(allocation.rendererInternal));\n}\n\nvoid MetalRenderer::indexData_uploadIndexMemory(IndexAllocation& allocation)\n{\n    m_memoryManager->GetIndexAllocator().FlushReservation(static_cast<MetalSynchronizedHeapAllocator::AllocatorReservation*>(allocation.rendererInternal));\n}\n\nLatteQueryObject* MetalRenderer::occlusionQuery_create() {\n\treturn new LatteQueryObjectMtl(this);\n}\n\nvoid MetalRenderer::occlusionQuery_destroy(LatteQueryObject* queryObj) {\n    auto queryObjMtl = static_cast<LatteQueryObjectMtl*>(queryObj);\n    delete queryObjMtl;\n}\n\nvoid MetalRenderer::occlusionQuery_flush() {\n    if (m_occlusionQuery.m_lastCommandBuffer)\n        m_occlusionQuery.m_lastCommandBuffer->waitUntilCompleted();\n}\n\nvoid MetalRenderer::occlusionQuery_updateState() {\n    ProcessFinishedCommandBuffers();\n}\n\nvoid MetalRenderer::SetBuffer(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::Buffer* buffer, size_t offset, uint32 index)\n{\n    auto& boundBuffer = m_state.m_encoderState.m_buffers[shaderType][index];\n    if (buffer == boundBuffer.m_buffer && offset == boundBuffer.m_offset)\n        return;\n\n    if (buffer == boundBuffer.m_buffer)\n    {\n        // Update just the offset\n        boundBuffer.m_offset = offset;\n\n        switch (shaderType)\n        {\n        case METAL_SHADER_TYPE_VERTEX:\n            renderCommandEncoder->setVertexBufferOffset(offset, index);\n            break;\n        case METAL_SHADER_TYPE_OBJECT:\n            renderCommandEncoder->setObjectBufferOffset(offset, index);\n            break;\n        case METAL_SHADER_TYPE_MESH:\n            renderCommandEncoder->setMeshBufferOffset(offset, index);\n            break;\n        case METAL_SHADER_TYPE_FRAGMENT:\n            renderCommandEncoder->setFragmentBufferOffset(offset, index);\n            break;\n        }\n\n        return;\n    }\n\n    boundBuffer = {buffer, offset};\n\n    switch (shaderType)\n    {\n    case METAL_SHADER_TYPE_VERTEX:\n        renderCommandEncoder->setVertexBuffer(buffer, offset, index);\n        break;\n    case METAL_SHADER_TYPE_OBJECT:\n        renderCommandEncoder->setObjectBuffer(buffer, offset, index);\n        break;\n    case METAL_SHADER_TYPE_MESH:\n        renderCommandEncoder->setMeshBuffer(buffer, offset, index);\n        break;\n    case METAL_SHADER_TYPE_FRAGMENT:\n        renderCommandEncoder->setFragmentBuffer(buffer, offset, index);\n        break;\n    }\n}\n\nvoid MetalRenderer::SetTexture(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::Texture* texture, uint32 index)\n{\n    auto& boundTexture = m_state.m_encoderState.m_textures[shaderType][index];\n    if (texture == boundTexture)\n        return;\n\n    boundTexture = texture;\n\n    switch (shaderType)\n    {\n    case METAL_SHADER_TYPE_VERTEX:\n        renderCommandEncoder->setVertexTexture(texture, index);\n        break;\n    case METAL_SHADER_TYPE_OBJECT:\n        renderCommandEncoder->setObjectTexture(texture, index);\n        break;\n    case METAL_SHADER_TYPE_MESH:\n        renderCommandEncoder->setMeshTexture(texture, index);\n        break;\n    case METAL_SHADER_TYPE_FRAGMENT:\n        renderCommandEncoder->setFragmentTexture(texture, index);\n        break;\n    }\n}\n\nvoid MetalRenderer::SetSamplerState(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::SamplerState* samplerState, uint32 index)\n{\n    auto& boundSamplerState = m_state.m_encoderState.m_samplers[shaderType][index];\n    if (samplerState == boundSamplerState)\n        return;\n\n    boundSamplerState = samplerState;\n\n    switch (shaderType)\n    {\n    case METAL_SHADER_TYPE_VERTEX:\n        renderCommandEncoder->setVertexSamplerState(samplerState, index);\n        break;\n    case METAL_SHADER_TYPE_OBJECT:\n        renderCommandEncoder->setObjectSamplerState(samplerState, index);\n        break;\n    case METAL_SHADER_TYPE_MESH:\n        renderCommandEncoder->setMeshSamplerState(samplerState, index);\n        break;\n    case METAL_SHADER_TYPE_FRAGMENT:\n        renderCommandEncoder->setFragmentSamplerState(samplerState, index);\n        break;\n    }\n}\n\nMTL::CommandBuffer* MetalRenderer::GetCommandBuffer()\n{\n    bool needsNewCommandBuffer = (!m_currentCommandBuffer.m_commandBuffer || m_currentCommandBuffer.m_commited);\n    if (needsNewCommandBuffer)\n\t{\n        // Debug\n        //m_commandQueue->insertDebugCaptureBoundary();\n\n        auto pool = NS::AutoreleasePool::alloc()->init();\n\t    MTL::CommandBuffer* mtlCommandBuffer = m_commandQueue->commandBuffer()->retain();\n\t\tpool->release();\n\t\tm_currentCommandBuffer = {mtlCommandBuffer};\n\n\t\t// Wait for the previous command buffer\n\t\tif (m_eventValue != -1)\n\t\t    mtlCommandBuffer->encodeWait(m_event, m_eventValue);\n\n\t\tm_recordedDrawcalls = 0;\n\t\tm_commitTreshold = m_defaultCommitTreshlod;\n\n        // Debug\n        m_performanceMonitor.m_commandBuffers++;\n\n\t\treturn mtlCommandBuffer;\n\t}\n\telse\n\t{\n\t    return m_currentCommandBuffer.m_commandBuffer;\n\t}\n}\n\nMTL::RenderCommandEncoder* MetalRenderer::GetTemporaryRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor)\n{\n    EndEncoding();\n\n    auto commandBuffer = GetCommandBuffer();\n\n    auto pool = NS::AutoreleasePool::alloc()->init();\n    auto renderCommandEncoder = commandBuffer->renderCommandEncoder(renderPassDescriptor)->retain();\n    pool->release();\n#ifdef CEMU_DEBUG_ASSERT\n    renderCommandEncoder->setLabel(GetLabel(\"Temporary render command encoder\", renderCommandEncoder));\n#endif\n    m_commandEncoder = renderCommandEncoder;\n    m_encoderType = MetalEncoderType::Render;\n\n    // Debug\n    m_performanceMonitor.m_renderPasses++;\n\n    return renderCommandEncoder;\n}\n\n// Some render passes clear the attachments, forceRecreate is supposed to be used in those cases\nMTL::RenderCommandEncoder* MetalRenderer::GetRenderCommandEncoder(bool forceRecreate)\n{\n    bool fboChanged = m_state.m_fboChanged;\n    m_state.m_fboChanged = false;\n\n    // Check if we need to begin a new render pass\n    if (m_commandEncoder)\n    {\n        if (!forceRecreate)\n        {\n            if (m_encoderType == MetalEncoderType::Render)\n            {\n                bool needsNewRenderPass = false;\n                if (fboChanged)\n                {\n                    needsNewRenderPass = (m_state.m_lastUsedFBO.m_fbo == nullptr);\n                    if (!needsNewRenderPass)\n                    {\n                        for (uint8 i = 0; i < 8; i++)\n                        {\n                            if (m_state.m_activeFBO.m_fbo->colorBuffer[i].texture && m_state.m_activeFBO.m_fbo->colorBuffer[i].texture != m_state.m_lastUsedFBO.m_fbo->colorBuffer[i].texture)\n                            {\n                                needsNewRenderPass = true;\n                                break;\n                            }\n                        }\n                    }\n\n                    if (!needsNewRenderPass)\n                    {\n                        if (m_state.m_activeFBO.m_fbo->depthBuffer.texture && (m_state.m_activeFBO.m_fbo->depthBuffer.texture != m_state.m_lastUsedFBO.m_fbo->depthBuffer.texture || ( m_state.m_activeFBO.m_fbo->depthBuffer.hasStencil && !m_state.m_lastUsedFBO.m_fbo->depthBuffer.hasStencil)))\n                        {\n                            needsNewRenderPass = true;\n                        }\n                    }\n                }\n\n                if (!needsNewRenderPass)\n                {\n                    return (MTL::RenderCommandEncoder*)m_commandEncoder;\n                }\n            }\n        }\n\n        EndEncoding();\n    }\n\n    auto commandBuffer = GetCommandBuffer();\n\n    auto pool = NS::AutoreleasePool::alloc()->init();\n    auto renderCommandEncoder = commandBuffer->renderCommandEncoder(m_state.m_activeFBO.m_fbo->GetRenderPassDescriptor())->retain();\n    pool->release();\n#ifdef CEMU_DEBUG_ASSERT\n    renderCommandEncoder->setLabel(GetLabel(\"Render command encoder\", renderCommandEncoder));\n#endif\n    m_commandEncoder = renderCommandEncoder;\n    m_encoderType = MetalEncoderType::Render;\n\n    // Update state\n    m_state.m_lastUsedFBO = m_state.m_activeFBO;\n    m_state.m_isFirstDrawInRenderPass = true;\n\n    ResetEncoderState();\n\n    // Debug\n    m_performanceMonitor.m_renderPasses++;\n\n    return renderCommandEncoder;\n}\n\nMTL::ComputeCommandEncoder* MetalRenderer::GetComputeCommandEncoder()\n{\n    if (m_commandEncoder)\n    {\n        if (m_encoderType == MetalEncoderType::Compute)\n        {\n            return (MTL::ComputeCommandEncoder*)m_commandEncoder;\n        }\n\n        EndEncoding();\n    }\n\n    auto commandBuffer = GetCommandBuffer();\n\n    auto pool = NS::AutoreleasePool::alloc()->init();\n    auto computeCommandEncoder = commandBuffer->computeCommandEncoder()->retain();\n    pool->release();\n    m_commandEncoder = computeCommandEncoder;\n    m_encoderType = MetalEncoderType::Compute;\n\n    ResetEncoderState();\n\n    return computeCommandEncoder;\n}\n\nMTL::BlitCommandEncoder* MetalRenderer::GetBlitCommandEncoder()\n{\n    if (m_commandEncoder)\n    {\n        if (m_encoderType == MetalEncoderType::Blit)\n        {\n            return (MTL::BlitCommandEncoder*)m_commandEncoder;\n        }\n\n        EndEncoding();\n    }\n\n    auto commandBuffer = GetCommandBuffer();\n\n    auto pool = NS::AutoreleasePool::alloc()->init();\n    auto blitCommandEncoder = commandBuffer->blitCommandEncoder()->retain();\n    pool->release();\n    m_commandEncoder = blitCommandEncoder;\n    m_encoderType = MetalEncoderType::Blit;\n\n    ResetEncoderState();\n\n    return blitCommandEncoder;\n}\n\nvoid MetalRenderer::EndEncoding()\n{\n    if (m_commandEncoder)\n    {\n        m_commandEncoder->endEncoding();\n        m_commandEncoder->release();\n        m_commandEncoder = nullptr;\n        m_encoderType = MetalEncoderType::None;\n\n        // Commit the command buffer if enough draw calls have been recorded\n        if (m_recordedDrawcalls >= m_commitTreshold)\n            CommitCommandBuffer();\n    }\n}\n\nvoid MetalRenderer::CommitCommandBuffer()\n{\n    if (!m_currentCommandBuffer.m_commandBuffer)\n        return;\n\n    EndEncoding();\n\n    ProcessFinishedCommandBuffers();\n\n    // Commit the command buffer\n    if (!m_currentCommandBuffer.m_commited)\n    {\n        // Handled differently, since it seems like Metal doesn't always call the completion handler\n        //commandBuffer.m_commandBuffer->addCompletedHandler(^(MTL::CommandBuffer*) {\n        //    m_memoryManager->GetTemporaryBufferAllocator().CommandBufferFinished(commandBuffer.m_commandBuffer);\n        //});\n\n        // Signal event\n        m_eventValue = (m_eventValue + 1) % EVENT_VALUE_WRAP;\n        auto mtlCommandBuffer = m_currentCommandBuffer.m_commandBuffer;\n        mtlCommandBuffer->encodeSignalEvent(m_event, m_eventValue);\n\n        mtlCommandBuffer->commit();\n        m_currentCommandBuffer.m_commited = true;\n\n        m_executingCommandBuffers.push_back(mtlCommandBuffer);\n\n        // Debug\n        //m_commandQueue->insertDebugCaptureBoundary();\n    }\n}\n\nvoid MetalRenderer::ProcessFinishedCommandBuffers()\n{\n    // Check for finished command buffers\n    for (auto it = m_executingCommandBuffers.begin(); it != m_executingCommandBuffers.end();)\n    {\n        auto commandBuffer = *it;\n        if (CommandBufferCompleted(commandBuffer))\n        {\n            m_memoryManager->CleanupBuffers(commandBuffer);\n            commandBuffer->release();\n            it = m_executingCommandBuffers.erase(it);\n        }\n        else\n        {\n            ++it;\n        }\n    }\n}\n\nbool MetalRenderer::AcquireDrawable(bool mainWindow)\n{\n    auto& layer = GetLayer(mainWindow);\n    if (!layer.GetLayer())\n        return false;\n\n    const bool latteBufferUsesSRGB = mainWindow ? LatteGPUState.tvBufferUsesSRGB : LatteGPUState.drcBufferUsesSRGB;\n    if (latteBufferUsesSRGB != m_state.m_usesSRGB)\n    {\n        layer.GetLayer()->setPixelFormat(latteBufferUsesSRGB ? MTL::PixelFormatBGRA8Unorm_sRGB : MTL::PixelFormatBGRA8Unorm);\n        m_state.m_usesSRGB = latteBufferUsesSRGB;\n    }\n\n    return layer.AcquireDrawable();\n}\n\n/*\nbool MetalRenderer::CheckIfRenderPassNeedsFlush(LatteDecompilerShader* shader)\n{\n    sint32 textureCount = shader->resourceMapping.getTextureCount();\n\tfor (int i = 0; i < textureCount; ++i)\n\t{\n\t\tconst auto relative_textureUnit = shader->resourceMapping.getTextureUnitFromBindingPoint(i);\n\t\tauto hostTextureUnit = relative_textureUnit;\n\t\tauto textureDim = shader->textureUnitDim[relative_textureUnit];\n\n\t\t// Texture is accessed as a framebuffer fetch, therefore there is no need to flush it\n\t\tif (shader->textureRenderTargetIndex[relative_textureUnit] != 255)\n\t\t    continue;\n\n\t\tauto texUnitRegIndex = hostTextureUnit * 7;\n\t\tswitch (shader->shaderType)\n\t\t{\n\t\tcase LatteConst::ShaderType::Vertex:\n\t\t\thostTextureUnit += LATTE_CEMU_VS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS;\n\t\t\tbreak;\n\t\tcase LatteConst::ShaderType::Pixel:\n\t\t\thostTextureUnit += LATTE_CEMU_PS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS;\n\t\t\tbreak;\n\t\tcase LatteConst::ShaderType::Geometry:\n\t\t\thostTextureUnit += LATTE_CEMU_GS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tUNREACHABLE;\n\t\t}\n\n\t\tauto textureView = m_state.m_textures[hostTextureUnit];\n\t\tif (!textureView)\n            continue;\n\n\t\tLatteTexture* baseTexture = textureView->baseTexture;\n\n\t    // If the texture is also used in the current render pass, we need to end the render pass to \"flush\" the texture\n\t\tfor (uint8 i = 0; i < LATTE_NUM_COLOR_TARGET; i++)\n\t\t{\n\t\t    auto colorTarget = m_state.m_activeFBO.m_fbo->colorBuffer[i].texture;\n\t\t\tif (colorTarget && colorTarget->baseTexture == baseTexture)\n\t\t\t    return true;\n\t\t}\n\t}\n\n\treturn false;\n}\n*/\n\nvoid MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader, bool usesGeometryShader)\n{\n    auto mtlShaderType = GetMtlShaderType(shader->shaderType, usesGeometryShader);\n\n    sint32 textureCount = shader->resourceMapping.getTextureCount();\n\tfor (int i = 0; i < textureCount; ++i)\n\t{\n\t\tconst auto relative_textureUnit = shader->resourceMapping.getTextureUnitFromBindingPoint(i);\n\t\tauto hostTextureUnit = relative_textureUnit;\n\n\t\t// Don't bind textures that are accessed with a framebuffer fetch\n\t\tif (m_supportsFramebufferFetch && shader->textureRenderTargetIndex[relative_textureUnit] != 255)\n            continue;\n\n\t\tauto textureDim = shader->textureUnitDim[relative_textureUnit];\n\t\tauto texUnitRegIndex = hostTextureUnit * 7;\n\t\tswitch (shader->shaderType)\n\t\t{\n\t\tcase LatteConst::ShaderType::Vertex:\n\t\t\thostTextureUnit += LATTE_CEMU_VS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS;\n\t\t\tbreak;\n\t\tcase LatteConst::ShaderType::Pixel:\n\t\t\thostTextureUnit += LATTE_CEMU_PS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS;\n\t\t\tbreak;\n\t\tcase LatteConst::ShaderType::Geometry:\n\t\t\thostTextureUnit += LATTE_CEMU_GS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tUNREACHABLE;\n\t\t}\n\n\t\t// TODO: correct?\n\t\tuint32 binding = shader->resourceMapping.getTextureBaseBindingPoint() + i;\n\t\tif (binding >= MAX_MTL_TEXTURES)\n\t\t{\n\t\t    cemuLog_logOnce(LogType::Force, \"invalid texture binding {}\", binding);\n            continue;\n\t\t}\n\n\t\tauto textureView = m_state.m_textures[hostTextureUnit];\n\t\tif (!textureView)\n\t\t{\n            if (textureDim == Latte::E_DIM::DIM_1D)\n                SetTexture(renderCommandEncoder, mtlShaderType, m_nullTexture1D, binding);\n           \telse\n                SetTexture(renderCommandEncoder, mtlShaderType, m_nullTexture2D, binding);\n            SetSamplerState(renderCommandEncoder, mtlShaderType, m_nearestSampler, binding);\n            continue;\n\t\t}\n\n\t\tif (textureDim == Latte::E_DIM::DIM_1D && (textureView->dim != Latte::E_DIM::DIM_1D))\n\t\t{\n\t\t    SetTexture(renderCommandEncoder, mtlShaderType, m_nullTexture1D, binding);\n\t\t\tcontinue;\n\t\t}\n\t\telse if (textureDim == Latte::E_DIM::DIM_2D && (textureView->dim != Latte::E_DIM::DIM_2D && textureView->dim != Latte::E_DIM::DIM_2D_MSAA))\n\t\t{\n\t\t    SetTexture(renderCommandEncoder, mtlShaderType, m_nullTexture2D, binding);\n\t\t\tcontinue;\n\t\t}\n\n\t\tLatteTexture* baseTexture = textureView->baseTexture;\n\n\t\tuint32 stageSamplerIndex = shader->textureUnitSamplerAssignment[relative_textureUnit];\n\t\tMTL::SamplerState* sampler;\n\t\tif (stageSamplerIndex != LATTE_DECOMPILER_SAMPLER_NONE)\n\t\t{\n\t\t    uint32 samplerIndex = stageSamplerIndex + LatteDecompiler_getTextureSamplerBaseIndex(shader->shaderType);\n\t\t\t_LatteRegisterSetSampler* samplerWords = LatteGPUState.contextNew.SQ_TEX_SAMPLER + samplerIndex;\n\n\t\t\t// Overwriting\n\n            // Lod bias\n            //if (baseTexture->overwriteInfo.hasLodBias)\n            //    samplerWords->WORD1.set_LOD_BIAS(baseTexture->overwriteInfo.lodBias);\n            //else if (baseTexture->overwriteInfo.hasRelativeLodBias)\n            //    samplerWords->WORD1.set_LOD_BIAS(samplerWords->WORD1.get_LOD_BIAS() + baseTexture->overwriteInfo.relativeLodBias);\n\n            // Max anisotropy\n            if (baseTexture->overwriteInfo.anisotropicLevel >= 0)\n                samplerWords->WORD0.set_MAX_ANISO_RATIO(baseTexture->overwriteInfo.anisotropicLevel);\n\n    \t\tsampler = m_samplerCache->GetSamplerState(LatteGPUState.contextNew, shader->shaderType, stageSamplerIndex, samplerWords);\n\t\t}\n\t\telse\n\t\t{\n\t\t    sampler = m_nearestSampler;\n\t\t}\n        SetSamplerState(renderCommandEncoder, mtlShaderType, sampler, binding);\n\n\t\t// get texture register word 0\n\t\tuint32 word4 = LatteGPUState.contextRegister[texUnitRegIndex + 4];\n\t\tauto& boundTexture = m_state.m_encoderState.m_textures[mtlShaderType][binding];\n\t\tMTL::Texture* mtlTexture = textureView->GetSwizzledView(word4);\n\t\tSetTexture(renderCommandEncoder, mtlShaderType, mtlTexture, binding);\n\t}\n\n\t// Support buffer\n\tauto GET_UNIFORM_DATA_PTR = [&](size_t index) { return supportBufferData + (index / 4); };\n\n\tsint32 shaderAluConst;\n\tsint32 shaderUniformRegisterOffset;\n\n\tswitch (shader->shaderType)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t\tshaderAluConst = 0x400;\n\t\tshaderUniformRegisterOffset = mmSQ_VTX_UNIFORM_BLOCK_START;\n\t\tbreak;\n\tcase LatteConst::ShaderType::Pixel:\n\t\tshaderAluConst = 0;\n\t\tshaderUniformRegisterOffset = mmSQ_PS_UNIFORM_BLOCK_START;\n\t\tbreak;\n\tcase LatteConst::ShaderType::Geometry:\n\t\tshaderAluConst = 0; // geometry shader has no ALU const\n\t\tshaderUniformRegisterOffset = mmSQ_GS_UNIFORM_BLOCK_START;\n\t\tbreak;\n\tdefault:\n\t\tUNREACHABLE;\n\t}\n\n\tif (shader->resourceMapping.uniformVarsBufferBindingPoint >= 0)\n\t{\n\t\tif (shader->uniform.list_ufTexRescale.empty() == false)\n\t\t{\n\t\t\tfor (auto& entry : shader->uniform.list_ufTexRescale)\n\t\t\t{\n\t\t\t\tfloat* xyScale = LatteTexture_getEffectiveTextureScale(shader->shaderType, entry.texUnit);\n\t\t\t\tmemcpy(entry.currentValue, xyScale, sizeof(float) * 2);\n\t\t\t\tmemcpy(GET_UNIFORM_DATA_PTR(entry.uniformLocation), xyScale, sizeof(float) * 2);\n\t\t\t}\n\t\t}\n\t\tif (shader->uniform.loc_alphaTestRef >= 0)\n\t\t{\n\t\t\t*GET_UNIFORM_DATA_PTR(shader->uniform.loc_alphaTestRef) = LatteGPUState.contextNew.SX_ALPHA_REF.get_ALPHA_TEST_REF();\n\t\t}\n\t\tif (shader->uniform.loc_pointSize >= 0)\n\t\t{\n\t\t\tconst auto& pointSizeReg = LatteGPUState.contextNew.PA_SU_POINT_SIZE;\n\t\t\tfloat pointWidth = (float)pointSizeReg.get_WIDTH() / 8.0f;\n\t\t\tif (pointWidth == 0.0f)\n\t\t\t\tpointWidth = 1.0f / 8.0f; // minimum size\n\t\t\t*GET_UNIFORM_DATA_PTR(shader->uniform.loc_pointSize) = pointWidth;\n\t\t}\n\t\tif (shader->uniform.loc_remapped >= 0)\n\t\t{\n\t\t\tLatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped));\n\t\t}\n\t\tif (shader->uniform.loc_uniformRegister >= 0)\n\t\t{\n\t\t\tuint32* uniformRegData = (uint32*)(LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst);\n\t\t\tmemcpy(GET_UNIFORM_DATA_PTR(shader->uniform.loc_uniformRegister), uniformRegData, shader->uniform.count_uniformRegister * 16);\n\t\t}\n\t\tif (shader->uniform.loc_windowSpaceToClipSpaceTransform >= 0)\n\t\t{\n\t\t\tsint32 viewportWidth;\n\t\t\tsint32 viewportHeight;\n\t\t\tLatteRenderTarget_GetCurrentVirtualViewportSize(&viewportWidth, &viewportHeight); // always call after _updateViewport()\n\t\t\tfloat* v = GET_UNIFORM_DATA_PTR(shader->uniform.loc_windowSpaceToClipSpaceTransform);\n\t\t\tv[0] = 2.0f / (float)viewportWidth;\n\t\t\tv[1] = 2.0f / (float)viewportHeight;\n\t\t}\n\t\tif (shader->uniform.loc_fragCoordScale >= 0)\n\t\t{\n\t\t\tLatteMRT::GetCurrentFragCoordScale(GET_UNIFORM_DATA_PTR(shader->uniform.loc_fragCoordScale));\n\t\t}\n\t\tif (shader->uniform.loc_verticesPerInstance >= 0)\n\t\t{\n\t\t\t*(int*)(supportBufferData + ((size_t)shader->uniform.loc_verticesPerInstance / 4)) = m_state.m_streamoutState.verticesPerInstance;\n\t\t\tfor (sint32 b = 0; b < LATTE_NUM_STREAMOUT_BUFFER; b++)\n\t\t\t{\n\t\t\t\tif (shader->uniform.loc_streamoutBufferBase[b] >= 0)\n\t\t\t\t{\n\t\t\t\t\t*(uint32*)GET_UNIFORM_DATA_PTR(shader->uniform.loc_streamoutBufferBase[b]) = m_state.m_streamoutState.buffers[b].ringBufferOffset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tsize_t size = shader->uniform.uniformRangeSize;\n\t\tauto& bufferAllocator = m_memoryManager->GetStagingAllocator();\n\t\tauto allocation = bufferAllocator.AllocateBufferMemory(size, 1);\n\t\tmemcpy(allocation.memPtr, supportBufferData, size);\n\t\tbufferAllocator.FlushReservation(allocation);\n\n\t\tSetBuffer(renderCommandEncoder, mtlShaderType, allocation.mtlBuffer, allocation.bufferOffset, shader->resourceMapping.uniformVarsBufferBindingPoint);\n\t}\n\n\t// Uniform buffers\n\tfor (sint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t{\n\t\tif (shader->resourceMapping.uniformBuffersBindingPoint[i] >= 0)\n\t\t{\n    \t\tuint32 binding = shader->resourceMapping.uniformBuffersBindingPoint[i];\n    \t\tif (binding >= MAX_MTL_BUFFERS)\n    \t\t{\n    \t\t    cemuLog_logOnce(LogType::Force, \"invalid buffer binding {}\", binding);\n    \t\t\tcontinue;\n    \t\t}\n\n    \t\tsize_t offset = m_state.m_uniformBufferOffsets[GetMtlGeneralShaderType(shader->shaderType)][i];\n    \t\tif (offset == INVALID_OFFSET)\n                continue;\n\n            SetBuffer(renderCommandEncoder, mtlShaderType, m_memoryManager->GetBufferCache(), offset, binding);\n\t\t}\n\t}\n\n\t// Storage buffer\n\tif (shader->resourceMapping.tfStorageBindingPoint >= 0)\n\t{\n        SetBuffer(renderCommandEncoder, mtlShaderType, m_xfbRingBuffer, 0, shader->resourceMapping.tfStorageBindingPoint);\n\t}\n}\n\nvoid MetalRenderer::ClearColorTextureInternal(MTL::Texture* mtlTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a)\n{\n    NS_STACK_SCOPED MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();\n    auto colorAttachment = renderPassDescriptor->colorAttachments()->object(0);\n    colorAttachment->setTexture(mtlTexture);\n    colorAttachment->setClearColor(MTL::ClearColor(r, g, b, a));\n    colorAttachment->setLoadAction(MTL::LoadActionClear);\n    colorAttachment->setStoreAction(MTL::StoreActionStore);\n    colorAttachment->setSlice(sliceIndex);\n    colorAttachment->setLevel(mipIndex);\n\n    GetTemporaryRenderCommandEncoder(renderPassDescriptor);\n    EndEncoding();\n\n    // Debug\n    m_performanceMonitor.m_clears++;\n}\n\nvoid MetalRenderer::CopyBufferToBuffer(MTL::Buffer* src, uint32 srcOffset, MTL::Buffer* dst, uint32 dstOffset, uint32 size, MTL::RenderStages after, MTL::RenderStages before)\n{\n    // TODO: uncomment and fix performance issues\n    // Do the copy in a vertex shader on Apple GPUs\n    /*\n    if (m_isAppleGPU && m_encoderType == MetalEncoderType::Render)\n    {\n        auto renderCommandEncoder = static_cast<MTL::RenderCommandEncoder*>(m_commandEncoder);\n\n        MTL::Resource* barrierBuffers[] = {src};\n        renderCommandEncoder->memoryBarrier(barrierBuffers, 1, after, after | MTL::RenderStageVertex);\n\n\t\trenderCommandEncoder->setRenderPipelineState(m_copyBufferToBufferPipeline->GetRenderPipelineState());\n\t\tm_state.m_encoderState.m_renderPipelineState = m_copyBufferToBufferPipeline->GetRenderPipelineState();\n\n\t\tSetBuffer(renderCommandEncoder, METAL_SHADER_TYPE_VERTEX, src, srcOffset, GET_HELPER_BUFFER_BINDING(0));\n\t\tSetBuffer(renderCommandEncoder, METAL_SHADER_TYPE_VERTEX, dst, dstOffset, GET_HELPER_BUFFER_BINDING(1));\n\n\t\trenderCommandEncoder->drawPrimitives(MTL::PrimitiveTypePoint, NS::UInteger(0), NS::UInteger(size));\n\n\t\tbarrierBuffers[0] = dst;\n        renderCommandEncoder->memoryBarrier(barrierBuffers, 1, before | MTL::RenderStageVertex, before);\n    }\n    else\n    {\n    */\n        auto blitCommandEncoder = GetBlitCommandEncoder();\n\n        blitCommandEncoder->copyFromBuffer(src, srcOffset, dst, dstOffset, size);\n    //}\n}\n\nvoid MetalRenderer::SwapBuffer(bool mainWindow)\n{\n    if (!AcquireDrawable(mainWindow))\n        return;\n\n    auto commandBuffer = GetCommandBuffer();\n    GetLayer(mainWindow).PresentDrawable(commandBuffer);\n}\n\nvoid MetalRenderer::EnsureImGuiBackend()\n{\n    if (!ImGui::GetIO().BackendRendererUserData)\n    {\n        ImGui_ImplMetal_Init(m_device);\n        //ImGui_ImplMetal_CreateFontsTexture(m_device);\n    }\n}\n\nvoid MetalRenderer::StartCapture()\n{\n    auto captureManager = MTL::CaptureManager::sharedCaptureManager();\n    auto desc = MTL::CaptureDescriptor::alloc()->init();\n    desc->setCaptureObject(m_device);\n\n    // Check if a debugger with support for GPU capture is attached\n    if (captureManager->supportsDestination(MTL::CaptureDestinationDeveloperTools))\n    {\n        desc->setDestination(MTL::CaptureDestinationDeveloperTools);\n    }\n    else\n    {\n        if (GetConfig().gpu_capture_dir.GetValue().empty())\n        {\n            cemuLog_log(LogType::Force, \"No GPU capture directory specified, cannot do a GPU capture\");\n            return;\n        }\n\n        // Check if the GPU trace document destination is available\n        if (!captureManager->supportsDestination(MTL::CaptureDestinationGPUTraceDocument))\n        {\n            cemuLog_log(LogType::Force, \"GPU trace document destination is not available, cannot do a GPU capture\");\n            return;\n        }\n\n        // Get current date and time as a string\n        auto now = std::chrono::system_clock::now();\n        std::time_t now_time = std::chrono::system_clock::to_time_t(now);\n        std::ostringstream oss;\n        oss << std::put_time(std::localtime(&now_time), \"%Y-%m-%d_%H-%M-%S\");\n        std::string now_str = oss.str();\n\n        std::string capturePath = fmt::format(\"{}/cemu_{}.gputrace\", GetConfig().gpu_capture_dir.GetValue(), now_str);\n        desc->setDestination(MTL::CaptureDestinationGPUTraceDocument);\n        desc->setOutputURL(ToNSURL(capturePath));\n    }\n\n    NS::Error* error = nullptr;\n    captureManager->startCapture(desc, &error);\n    if (error)\n    {\n        cemuLog_log(LogType::Force, \"Failed to start GPU capture: {}\", error->localizedDescription()->utf8String());\n    }\n\n    m_capturing = true;\n}\n\nvoid MetalRenderer::EndCapture()\n{\n    auto captureManager = MTL::CaptureManager::sharedCaptureManager();\n    captureManager->stopCapture();\n\n    m_capturing = false;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalLayerHandle.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalPerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalOutputShaderCache.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalAttachmentsInfo.h\"\n\nenum MetalGeneralShaderType\n{\n    METAL_GENERAL_SHADER_TYPE_VERTEX,\n    METAL_GENERAL_SHADER_TYPE_GEOMETRY,\n    METAL_GENERAL_SHADER_TYPE_FRAGMENT,\n\n    METAL_GENERAL_SHADER_TYPE_TOTAL\n};\n\ninline MetalGeneralShaderType GetMtlGeneralShaderType(LatteConst::ShaderType shaderType)\n{\n    switch (shaderType)\n    {\n    case LatteConst::ShaderType::Vertex:\n        return METAL_GENERAL_SHADER_TYPE_VERTEX;\n    case LatteConst::ShaderType::Geometry:\n        return METAL_GENERAL_SHADER_TYPE_GEOMETRY;\n    case LatteConst::ShaderType::Pixel:\n        return METAL_GENERAL_SHADER_TYPE_FRAGMENT;\n    default:\n        return METAL_GENERAL_SHADER_TYPE_TOTAL;\n    }\n}\n\nenum MetalShaderType\n{\n    METAL_SHADER_TYPE_VERTEX,\n    METAL_SHADER_TYPE_OBJECT,\n    METAL_SHADER_TYPE_MESH,\n    METAL_SHADER_TYPE_FRAGMENT,\n\n    METAL_SHADER_TYPE_TOTAL\n};\n\ninline MetalShaderType GetMtlShaderType(LatteConst::ShaderType shaderType, bool usesGeometryShader)\n{\n    switch (shaderType)\n    {\n    case LatteConst::ShaderType::Vertex:\n        if (usesGeometryShader)\n            return METAL_SHADER_TYPE_OBJECT;\n        else\n            return METAL_SHADER_TYPE_VERTEX;\n    case LatteConst::ShaderType::Geometry:\n        return METAL_SHADER_TYPE_MESH;\n    case LatteConst::ShaderType::Pixel:\n        return METAL_SHADER_TYPE_FRAGMENT;\n    default:\n        return METAL_SHADER_TYPE_TOTAL;\n    }\n}\n\nstruct MetalEncoderState\n{\n    MTL::RenderPipelineState* m_renderPipelineState = nullptr;\n    MTL::DepthStencilState* m_depthStencilState = nullptr;\n    MTL::CullMode m_cullMode = MTL::CullModeNone;\n    MTL::Winding m_frontFaceWinding = MTL::WindingClockwise;\n    MTL::Viewport m_viewport;\n    MTL::ScissorRect m_scissor;\n    uint32 m_stencilRefFront = 0;\n    uint32 m_stencilRefBack = 0;\n    uint32 m_blendColor[4] = {0};\n    uint32 m_depthBias = 0;\n   \tuint32 m_depthSlope = 0;\n   \tuint32 m_depthClamp = 0;\n    bool m_depthClipEnable = true;\n    struct {\n        MTL::Buffer* m_buffer;\n        size_t m_offset;\n    } m_buffers[METAL_SHADER_TYPE_TOTAL][MAX_MTL_BUFFERS];\n    MTL::Texture* m_textures[METAL_SHADER_TYPE_TOTAL][MAX_MTL_TEXTURES];\n    MTL::SamplerState* m_samplers[METAL_SHADER_TYPE_TOTAL][MAX_MTL_SAMPLERS];\n};\n\nstruct MetalStreamoutState\n{\n\tstruct\n\t{\n\t\tbool enabled;\n\t\tuint32 ringBufferOffset;\n\t} buffers[LATTE_NUM_STREAMOUT_BUFFER];\n\tsint32 verticesPerInstance;\n};\n\nstruct MetalActiveFBOState\n{\n    class CachedFBOMtl* m_fbo = nullptr;\n    MetalAttachmentsInfo m_attachmentsInfo;\n};\n\nstruct MetalState\n{\n    MetalEncoderState m_encoderState{};\n\n    bool m_usesSRGB = false;\n\n    bool m_skipDrawSequence = false;\n    bool m_isFirstDrawInRenderPass = true;\n\n    MetalActiveFBOState m_activeFBO;\n    // If the FBO changes, but it's the same FBO as the last one with some omitted attachments, this FBO doesn't change\n    MetalActiveFBOState m_lastUsedFBO;\n    bool m_fboChanged = false;\n\n    size_t m_vertexBufferOffsets[MAX_MTL_VERTEX_BUFFERS];\n    class LatteTextureViewMtl* m_textures[LATTE_NUM_MAX_TEX_UNITS * 3] = {nullptr};\n    size_t m_uniformBufferOffsets[METAL_GENERAL_SHADER_TYPE_TOTAL][MAX_MTL_BUFFERS];\n\n    MTL::Viewport m_viewport;\n    MTL::ScissorRect m_scissor;\n\n    MetalStreamoutState m_streamoutState;\n};\n\nstruct MetalCommandBuffer\n{\n    MTL::CommandBuffer* m_commandBuffer = nullptr;\n    bool m_commited = false;\n};\n\nenum class MetalEncoderType\n{\n    None,\n    Render,\n    Compute,\n    Blit,\n};\n\nclass MetalRenderer : public Renderer\n{\npublic:\n    static constexpr uint32 OCCLUSION_QUERY_POOL_SIZE = 1024;\n    static constexpr uint32 TEXTURE_READBACK_SIZE = 32 * 1024 * 1024; // 32 MB\n\n    struct DeviceInfo\n    {\n        std::string name;\n        uint64 uuid;\n    };\n\n    static std::vector<DeviceInfo> GetDevices();\n\n    MetalRenderer();\n\t~MetalRenderer() override;\n\n\tRendererAPI GetType() override\n\t{\n\t    return RendererAPI::Metal;\n\t}\n\n\tstatic MetalRenderer* GetInstance() {\n\t    return static_cast<MetalRenderer*>(g_renderer.get());\n\t}\n\n\t// Helper functions\n\tMTL::Device* GetDevice() const {\n        return m_device;\n    }\n\n\tvoid InitializeLayer(const Vector2i& size, bool mainWindow);\n\tvoid ShutdownLayer(bool mainWindow);\n\tvoid ResizeLayer(const Vector2i& size, bool mainWindow);\n\n\tvoid Initialize() override;\n\tvoid Shutdown() override;\n\tbool IsPadWindowActive() override;\n\n\tbool GetVRAMInfo(int& usageInMB, int& totalInMB) const override;\n\n\tvoid ClearColorbuffer(bool padView) override;\n\tvoid DrawEmptyFrame(bool mainWindow) override;\n\tvoid SwapBuffers(bool swapTV, bool swapDRC) override;\n\n\tvoid HandleScreenshotRequest(LatteTextureView* texView, bool padView) override;\n\n\tvoid DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,\n\t\t\t\t\t\t\t\t\tsint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,\n\t\t\t\t\t\t\t\t\tbool padView, bool clearBackground) override;\n\tbool BeginFrame(bool mainWindow) override;\n\n\t// flush control\n\tvoid Flush(bool waitIdle = false) override;\t\t// called when explicit flush is required (e.g. by imgui)\n\tvoid NotifyLatteCommandProcessorIdle() override; // called when command processor has no more commands available or when stalled\n\n\t// imgui\n\tbool ImguiBegin(bool mainWindow) override;\n\tvoid ImguiEnd() override;\n\tImTextureID GenerateTexture(const std::vector<uint8>& data, const Vector2i& size) override;\n\tvoid DeleteTexture(ImTextureID id) override;\n\tvoid DeleteFontTextures() override;\n\n\tbool UseTFViaSSBO() const override { return true; }\n\tvoid AppendOverlayDebugInfo() override;\n\n\t// rendertarget\n\tvoid renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ = false) override;\n\tvoid renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight) override;\n\n\tLatteCachedFBO* rendertarget_createCachedFBO(uint64 key) override;\n\tvoid rendertarget_deleteCachedFBO(LatteCachedFBO* fbo) override;\n\tvoid rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) override;\n\n\t// texture functions\n\tvoid* texture_acquireTextureUploadBuffer(uint32 size) override;\n\tvoid texture_releaseTextureUploadBuffer(uint8* mem) override;\n\n\tTextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) override;\n\n\tvoid texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) override;\n\tvoid texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) override;\n\tvoid texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) override;\n\tvoid texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) override;\n\n\tLatteTexture* texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) override;\n\n\tvoid texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) override;\n\tvoid texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) override;\n\n\tLatteTextureReadbackInfo* texture_createReadback(LatteTextureView* textureView) override;\n\n\t// surface copy\n\tvoid surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height) override;\n\n\t// buffer cache\n\tvoid bufferCache_init(const sint32 bufferSize) override;\n\tvoid bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) override;\n\tvoid bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) override;\n\tvoid bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) override;\n\n\tvoid buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) override;\n\tvoid buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override;\n\n\t// shader\n\tRendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool compileAsync, bool isGfxPackSource) override;\n\n\t// streamout\n\tvoid streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;\n\tvoid streamout_begin() override;\n\tvoid streamout_rendererFinishDrawcall() override;\n\n\t// core drawing logic\n\tvoid draw_beginSequence() override;\n\tvoid draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) override;\n\tvoid draw_endSequence() override;\n\n\tvoid draw_updateVertexBuffersDirectAccess();\n\tvoid draw_updateUniformBuffersDirectAccess(LatteDecompilerShader* shader, const uint32 uniformBufferRegOffset);\n\n\tvoid draw_handleSpecialState5();\n\n\t// index\n\tIndexAllocation indexData_reserveIndexMemory(uint32 size) override;\n\tvoid indexData_releaseIndexMemory(IndexAllocation& allocation) override;\n\tvoid indexData_uploadIndexMemory(IndexAllocation& allocation) override;\n\n\t// occlusion queries\n\tLatteQueryObject* occlusionQuery_create() override;\n\tvoid occlusionQuery_destroy(LatteQueryObject* queryObj) override;\n\tvoid occlusionQuery_flush() override;\n\tvoid occlusionQuery_updateState() override;\n\n\t// Helpers\n\tMetalPerformanceMonitor& GetPerformanceMonitor() { return m_performanceMonitor; }\n\n\tvoid SetShouldMaximizeConcurrentCompilation(bool shouldMaximizeConcurrentCompilation)\n\t{\n\t    if (m_supportsMetal3)\n\t        m_device->setShouldMaximizeConcurrentCompilation(shouldMaximizeConcurrentCompilation);\n\t}\n\n\tbool IsCommandBufferActive() const\n\t{\n        return (m_currentCommandBuffer.m_commandBuffer && !m_currentCommandBuffer.m_commited);\n    }\n\n\tMTL::CommandBuffer* GetCurrentCommandBuffer() const\n    {\n        cemu_assert_debug(m_currentCommandBuffer.m_commandBuffer);\n\n        return m_currentCommandBuffer.m_commandBuffer;\n    }\n\n    MTL::CommandBuffer* GetAndRetainCurrentCommandBufferIfNotCompleted() const\n    {\n        // The command buffer has been commited and has finished execution\n        if (m_currentCommandBuffer.m_commited && m_executingCommandBuffers.size() == 0)\n            return nullptr;\n\n        return GetCurrentCommandBuffer()->retain();\n    }\n\n    void RequestSoonCommit()\n    {\n        m_commitTreshold = m_recordedDrawcalls + 8;\n    }\n\n    MTL::CommandEncoder* GetCommandEncoder()\n    {\n        return m_commandEncoder;\n    }\n\n    MetalEncoderType GetEncoderType()\n    {\n        return m_encoderType;\n    }\n\n    void ResetEncoderState()\n    {\n        m_state.m_encoderState = {};\n\n        // TODO: set viewport and scissor to render target dimensions if render commands\n\n        for (uint32 i = 0; i < METAL_SHADER_TYPE_TOTAL; i++)\n        {\n            for (uint32 j = 0; j < MAX_MTL_BUFFERS; j++)\n                m_state.m_encoderState.m_buffers[i][j] = {nullptr};\n            for (uint32 j = 0; j < MAX_MTL_TEXTURES; j++)\n                m_state.m_encoderState.m_textures[i][j] = nullptr;\n            for (uint32 j = 0; j < MAX_MTL_SAMPLERS; j++)\n                m_state.m_encoderState.m_samplers[i][j] = nullptr;\n        }\n    }\n\n    MetalEncoderState& GetEncoderState()\n    {\n        return m_state.m_encoderState;\n    }\n\n    void SetBuffer(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::Buffer* buffer, size_t offset, uint32 index);\n    void SetTexture(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::Texture* texture, uint32 index);\n    void SetSamplerState(MTL::RenderCommandEncoder* renderCommandEncoder, MetalShaderType shaderType, MTL::SamplerState* samplerState, uint32 index);\n\n\tMTL::CommandBuffer* GetCommandBuffer();\n\tMTL::RenderCommandEncoder* GetTemporaryRenderCommandEncoder(MTL::RenderPassDescriptor* renderPassDescriptor);\n\tMTL::RenderCommandEncoder* GetRenderCommandEncoder(bool forceRecreate = false);\n    MTL::ComputeCommandEncoder* GetComputeCommandEncoder();\n    MTL::BlitCommandEncoder* GetBlitCommandEncoder();\n    void EndEncoding();\n    void CommitCommandBuffer();\n    void ProcessFinishedCommandBuffers();\n\n    bool AcquireDrawable(bool mainWindow);\n\n    //bool CheckIfRenderPassNeedsFlush(LatteDecompilerShader* shader);\n    void BindStageResources(MTL::RenderCommandEncoder* renderCommandEncoder, LatteDecompilerShader* shader, bool usesGeometryShader);\n\n    void ClearColorTextureInternal(MTL::Texture* mtlTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a);\n\n    void CopyBufferToBuffer(MTL::Buffer* src, uint32 srcOffset, MTL::Buffer* dst, uint32 dstOffset, uint32 size, MTL::RenderStages after, MTL::RenderStages before);\n\n    // Getters\n    bool GetPositionInvariance() const\n    {\n        return m_positionInvariance;\n    }\n\n    bool IsAppleGPU() const\n    {\n        return m_isAppleGPU;\n    }\n\n    bool SupportsFramebufferFetch() const\n    {\n        return m_supportsFramebufferFetch;\n    }\n\n    bool HasUnifiedMemory() const\n    {\n        return m_hasUnifiedMemory;\n    }\n\n    bool SupportsMetal3() const\n    {\n        return m_supportsMetal3;\n    }\n\n    bool SupportsMeshShaders() const\n    {\n        return m_supportsMeshShaders;\n    }\n\n    //MTL::StorageMode GetOptimalTextureStorageMode() const\n    //{\n    //    return (m_isAppleGPU ? MTL::StorageModeShared : MTL::StorageModePrivate);\n    //}\n\n    MTL::ResourceOptions GetOptimalBufferStorageMode() const\n    {\n        return (m_hasUnifiedMemory ? MTL::ResourceStorageModeShared : MTL::ResourceStorageModeManaged);\n    }\n\n    MTL::Texture* GetNullTexture2D() const\n    {\n        return m_nullTexture2D;\n    }\n\n    MTL::Buffer* GetTextureReadbackBuffer()\n    {\n        if (!m_readbackBuffer)\n        {\n            m_readbackBuffer = m_device->newBuffer(TEXTURE_READBACK_SIZE, MTL::ResourceStorageModeShared);\n#ifdef CEMU_DEBUG_ASSERT\n            m_readbackBuffer->setLabel(GetLabel(\"Texture readback buffer\", m_readbackBuffer));\n#endif\n        }\n\n        return m_readbackBuffer;\n    }\n\n    MTL::Buffer* GetXfbRingBuffer()\n    {\n        if (!m_xfbRingBuffer)\n        {\n            // HACK: using just LatteStreamout_GetRingBufferSize will cause page faults\n            m_xfbRingBuffer = m_device->newBuffer(LatteStreamout_GetRingBufferSize() * 4, MTL::ResourceStorageModePrivate);\n#ifdef CEMU_DEBUG_ASSERT\n            m_xfbRingBuffer->setLabel(GetLabel(\"Transform feedback buffer\", m_xfbRingBuffer));\n#endif\n        }\n\n        return m_xfbRingBuffer;\n    }\n\n    MTL::Buffer* GetOcclusionQueryResultBuffer() const\n    {\n        return m_occlusionQuery.m_resultBuffer;\n    }\n\n    uint64* GetOcclusionQueryResultsPtr()\n    {\n        return m_occlusionQuery.m_resultsPtr;\n    }\n\n    uint32 GetOcclusionQueryIndex()\n    {\n        return m_occlusionQuery.m_currentIndex;\n    }\n\n    void BeginOcclusionQuery()\n    {\n        m_occlusionQuery.m_active = true;\n    }\n\n    void EndOcclusionQuery()\n    {\n        m_occlusionQuery.m_active = false;\n\n        // Release the old command buffer\n        if (m_occlusionQuery.m_lastCommandBuffer)\n            m_occlusionQuery.m_lastCommandBuffer->release();\n\n        // Get and retain the current command buffer\n        m_occlusionQuery.m_lastCommandBuffer = GetAndRetainCurrentCommandBufferIfNotCompleted();\n    }\n\n    // GPU capture\n    void CaptureFrame()\n    {\n        m_captureFrame = true;\n    }\n\nprivate:\n\tMetalLayerHandle m_mainLayer;\n\tMetalLayerHandle m_padLayer;\n\n\tMetalPerformanceMonitor m_performanceMonitor;\n\n\t// Options\n\tbool m_positionInvariance;\n\n\t// Metal objects\n\tMTL::Device* m_device = nullptr;\n\tMTL::CommandQueue* m_commandQueue;\n\n\t// Feature support\n\tbool m_isAppleGPU;\n\tbool m_supportsFramebufferFetch;\n\tbool m_hasUnifiedMemory;\n\tbool m_supportsMetal3;\n\tbool m_supportsMeshShaders;\n\tuint32 m_recommendedMaxVRAMUsage;\n\tMetalPixelFormatSupport m_pixelFormatSupport;\n\n\t// Managers and caches\n\tclass MetalMemoryManager* m_memoryManager;\n\tclass MetalOutputShaderCache* m_outputShaderCache;\n\tclass MetalPipelineCache* m_pipelineCache;\n\tclass MetalDepthStencilCache* m_depthStencilCache;\n\tclass MetalSamplerCache* m_samplerCache;\n\n\t// Pipelines\n\tMTL::RenderPipelineDescriptor* m_copyDepthToColorDesc;\n\tstd::map<MTL::PixelFormat, MTL::RenderPipelineState*> m_copyDepthToColorPipelines;\n\n\t// Void vertex pipelines\n\tclass MetalVoidVertexPipeline* m_copyBufferToBufferPipeline;\n\n\t// Synchronization resources\n\tMTL::Event* m_event;\n\tint32_t m_eventValue = -1;\n\n\t// Resources\n\tMTL::SamplerState* m_nearestSampler;\n\tMTL::SamplerState* m_linearSampler;\n\n\t// Null resources\n\tMTL::Texture* m_nullTexture1D;\n\tMTL::Texture* m_nullTexture2D;\n\n\t// Texture readback\n\tMTL::Buffer* m_readbackBuffer = nullptr;\n\tuint32 m_readbackBufferWriteOffset = 0;\n\n\t// Transform feedback\n\tMTL::Buffer* m_xfbRingBuffer = nullptr;\n\n\t// Occlusion queries\n\tstruct\n\t{\n    \tMTL::Buffer* m_resultBuffer;\n    \tuint64* m_resultsPtr;\n    \tuint32 m_currentIndex = 0;\n        bool m_active = false;\n        MTL::CommandBuffer* m_lastCommandBuffer = nullptr;\n\t} m_occlusionQuery;\n\n\t// Active objects\n\tMetalCommandBuffer m_currentCommandBuffer{};\n\tstd::vector<MTL::CommandBuffer*> m_executingCommandBuffers;\n\tMetalEncoderType m_encoderType = MetalEncoderType::None;\n\tMTL::CommandEncoder* m_commandEncoder = nullptr;\n\n    uint32 m_recordedDrawcalls;\n    uint32 m_defaultCommitTreshlod;\n    uint32 m_commitTreshold;\n\n\t// State\n\tMetalState m_state;\n\n\t// GPU capture\n\tbool m_captureFrame = false;\n\tbool m_capturing = false;\n\n\t// Helpers\n\tMetalLayerHandle& GetLayer(bool mainWindow)\n\t{\n\t    return (mainWindow ? m_mainLayer : m_padLayer);\n\t}\n\n\tvoid SwapBuffer(bool mainWindow);\n\n\tvoid EnsureImGuiBackend();\n\n\t// GPU capture\n\tvoid StartCapture();\n\tvoid EndCapture();\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h\"\n\nMTL::SamplerBorderColor GetBorderColor(LatteConst::ShaderType shaderType, uint32 stageSamplerIndex, const _LatteRegisterSetSampler* samplerWords, bool logWorkaround = false)\n{\n    auto borderType = samplerWords->WORD0.get_BORDER_COLOR_TYPE();\n\n    MTL::SamplerBorderColor borderColor;\n    if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::TRANSPARENT_BLACK)\n        borderColor = MTL::SamplerBorderColorTransparentBlack;\n    else if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::OPAQUE_BLACK)\n        borderColor = MTL::SamplerBorderColorOpaqueBlack;\n    else if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::OPAQUE_WHITE)\n        borderColor = MTL::SamplerBorderColorOpaqueWhite;\n    else [[unlikely]]\n    {\n        _LatteRegisterSetSamplerBorderColor* borderColorReg;\n\t\tif (shaderType == LatteConst::ShaderType::Vertex)\n\t\t\tborderColorReg = LatteGPUState.contextNew.TD_VS_SAMPLER_BORDER_COLOR + stageSamplerIndex;\n\t\telse if (shaderType == LatteConst::ShaderType::Pixel)\n\t\t\tborderColorReg = LatteGPUState.contextNew.TD_PS_SAMPLER_BORDER_COLOR + stageSamplerIndex;\n\t\telse // geometry\n\t\t\tborderColorReg = LatteGPUState.contextNew.TD_GS_SAMPLER_BORDER_COLOR + stageSamplerIndex;\n\t\tfloat r = borderColorReg->red.get_channelValue();\n\t\tfloat g = borderColorReg->green.get_channelValue();\n\t\tfloat b = borderColorReg->blue.get_channelValue();\n\t\tfloat a = borderColorReg->alpha.get_channelValue();\n\n\t\t// Metal doesn't support custom border color\n\t\t// Let's find the best match\n\t\tbool opaque = (a == 1.0f);\n\t\tbool white = (r == 1.0f);\n\t\tif (opaque)\n\t\t{\n\t\t    if (white)\n                borderColor = MTL::SamplerBorderColorOpaqueWhite;\n            else\n                borderColor = MTL::SamplerBorderColorOpaqueBlack;\n\t\t}\n\t\telse\n\t\t{\n\t\t    borderColor = MTL::SamplerBorderColorTransparentBlack;\n\t\t}\n\n\t\tif (logWorkaround)\n\t\t{\n\t\t    float newR, newG, newB, newA;\n\t\t\tswitch (borderColor)\n\t\t\t{\n\t\t\tcase MTL::SamplerBorderColorTransparentBlack:\n                newR = 0.0f;\n                newG = 0.0f;\n                newB = 0.0f;\n                newA = 0.0f;\n                break;\n            case MTL::SamplerBorderColorOpaqueBlack:\n                newR = 0.0f;\n                newG = 0.0f;\n                newB = 0.0f;\n                newA = 1.0f;\n                break;\n            case MTL::SamplerBorderColorOpaqueWhite:\n                newR = 1.0f;\n                newG = 1.0f;\n                newB = 1.0f;\n                newA = 1.0f;\n                break;\n            }\n\n            if (r != newR || g != newG || b != newB || a != newA)\n                cemuLog_log(LogType::Force, \"Custom border color ({}, {}, {}, {}) is not supported on Metal, using ({}, {}, {}, {}) instead\", r, g, b, a, newR, newG, newB, newA);\n\t\t}\n    }\n\n    return borderColor;\n}\n\nMetalSamplerCache::~MetalSamplerCache()\n{\n    for (auto& pair : m_samplerCache)\n    {\n        pair.second->release();\n    }\n    m_samplerCache.clear();\n}\n\nMTL::SamplerState* MetalSamplerCache::GetSamplerState(const LatteContextRegister& lcr, LatteConst::ShaderType shaderType, uint32 stageSamplerIndex, const _LatteRegisterSetSampler* samplerWords)\n{\n    uint64 stateHash = CalculateSamplerHash(lcr, shaderType, stageSamplerIndex, samplerWords);\n    auto& samplerState = m_samplerCache[stateHash];\n    if (samplerState)\n        return samplerState;\n\n\t// Sampler state\n\n\n    NS_STACK_SCOPED MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init();\n\n    // lod\n    uint32 iMinLOD = samplerWords->WORD1.get_MIN_LOD();\n    uint32 iMaxLOD = samplerWords->WORD1.get_MAX_LOD();\n    //sint32 iLodBias = samplerWords->WORD1.get_LOD_BIAS();\n\n    auto filterMip = samplerWords->WORD0.get_MIP_FILTER();\n    if (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::NONE)\n    {\n        samplerDescriptor->setMipFilter(MTL::SamplerMipFilterNearest);\n        samplerDescriptor->setLodMinClamp(0.0f);\n        samplerDescriptor->setLodMaxClamp(0.25f);\n    }\n    else if (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::POINT)\n    {\n        samplerDescriptor->setMipFilter(MTL::SamplerMipFilterNearest);\n        samplerDescriptor->setLodMinClamp((float)iMinLOD / 64.0f);\n        samplerDescriptor->setLodMaxClamp((float)iMaxLOD / 64.0f);\n    }\n    else if (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::LINEAR)\n    {\n        samplerDescriptor->setMipFilter(MTL::SamplerMipFilterLinear);\n        samplerDescriptor->setLodMinClamp((float)iMinLOD / 64.0f);\n        samplerDescriptor->setLodMaxClamp((float)iMaxLOD / 64.0f);\n    }\n    else\n    {\n        // fallback for invalid constants\n        samplerDescriptor->setMipFilter(MTL::SamplerMipFilterLinear);\n        samplerDescriptor->setLodMinClamp((float)iMinLOD / 64.0f);\n        samplerDescriptor->setLodMaxClamp((float)iMaxLOD / 64.0f);\n    }\n\n    auto filterMin = samplerWords->WORD0.get_XY_MIN_FILTER();\n    cemu_assert_debug(filterMin != Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::BICUBIC); // todo\n    samplerDescriptor->setMinFilter((filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::POINT || filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::ANISO_POINT) ? MTL::SamplerMinMagFilterNearest : MTL::SamplerMinMagFilterLinear);\n\n    auto filterMag = samplerWords->WORD0.get_XY_MAG_FILTER();\n    samplerDescriptor->setMagFilter((filterMag == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::POINT || filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::ANISO_POINT) ? MTL::SamplerMinMagFilterNearest : MTL::SamplerMinMagFilterLinear);\n\n    auto filterZ = samplerWords->WORD0.get_Z_FILTER();\n    // todo: z-filter for texture array samplers is customizable for GPU7 but OpenGL/Vulkan doesn't expose this functionality?\n\n    auto clampX = samplerWords->WORD0.get_CLAMP_X();\n    auto clampY = samplerWords->WORD0.get_CLAMP_Y();\n    auto clampZ = samplerWords->WORD0.get_CLAMP_Z();\n\n    samplerDescriptor->setSAddressMode(GetMtlSamplerAddressMode(clampX));\n    samplerDescriptor->setTAddressMode(GetMtlSamplerAddressMode(clampY));\n    samplerDescriptor->setRAddressMode(GetMtlSamplerAddressMode(clampZ));\n\n    auto maxAniso = samplerWords->WORD0.get_MAX_ANISO_RATIO();\n\n    if (maxAniso > 0)\n        samplerDescriptor->setMaxAnisotropy(1 << maxAniso);\n\n    // TODO: set lod bias\n    //samplerInfo.mipLodBias = (float)iLodBias / 64.0f;\n\n    // depth compare\n    //uint8 depthCompareMode = shader->textureUsesDepthCompare[relative_textureUnit] ? 1 : 0;\n    // TODO: is it okay to just cast?\n    samplerDescriptor->setCompareFunction(GetMtlCompareFunc((Latte::E_COMPAREFUNC)samplerWords->WORD0.get_DEPTH_COMPARE_FUNCTION()));\n\n    // Border color\n    auto borderColor = GetBorderColor(shaderType, stageSamplerIndex, samplerWords, true);\n    samplerDescriptor->setBorderColor(borderColor);\n\n    samplerState = m_mtlr->GetDevice()->newSamplerState(samplerDescriptor);\n\n    return samplerState;\n}\n\nuint64 MetalSamplerCache::CalculateSamplerHash(const LatteContextRegister& lcr, LatteConst::ShaderType shaderType, uint32 stageSamplerIndex, const _LatteRegisterSetSampler* samplerWords)\n{\n    uint64 hash = 0;\n    hash = std::rotl<uint64>(hash, 17);\n    hash += (uint64)samplerWords->WORD0.getRawValue();\n    hash = std::rotl<uint64>(hash, 17);\n    hash += (uint64)samplerWords->WORD1.getRawValue();\n    hash = std::rotl<uint64>(hash, 17);\n    hash += (uint64)samplerWords->WORD2.getRawValue();\n\n    auto borderColor = GetBorderColor(shaderType, stageSamplerIndex, samplerWords);\n\n    hash = std::rotl<uint64>(hash, 5);\n    hash += (uint64)borderColor;\n\n    // TODO: check this\n\treturn hash;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.h",
    "content": "#pragma once\n\n#include <Metal/Metal.hpp>\n\n#include \"HW/Latte/Core/LatteConst.h\"\n#include \"HW/Latte/ISA/LatteReg.h\"\n\nclass MetalSamplerCache\n{\npublic:\n    MetalSamplerCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {}\n    ~MetalSamplerCache();\n\n    MTL::SamplerState* GetSamplerState(const LatteContextRegister& lcr, LatteConst::ShaderType shaderType, uint32 stageSamplerIndex, const _LatteRegisterSetSampler* samplerWords);\n\nprivate:\n    class MetalRenderer* m_mtlr;\n\n    std::map<uint64, MTL::SamplerState*> m_samplerCache;\n\n    uint64 CalculateSamplerHash(const LatteContextRegister& lcr, LatteConst::ShaderType shaderType, uint32 stageSamplerIndex, const _LatteRegisterSetSampler* samplerWords);\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalVoidVertexPipeline.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalVoidVertexPipeline.h\"\n\nMetalVoidVertexPipeline::MetalVoidVertexPipeline(class MetalRenderer* mtlRenderer, MTL::Library* library, const std::string& vertexFunctionName)\n{\n    // Render pipeline state\n    NS_STACK_SCOPED MTL::Function* vertexFunction = library->newFunction(ToNSString(vertexFunctionName));\n\n    NS_STACK_SCOPED MTL::RenderPipelineDescriptor* renderPipelineDescriptor = MTL::RenderPipelineDescriptor::alloc()->init();\n    renderPipelineDescriptor->setVertexFunction(vertexFunction);\n    renderPipelineDescriptor->setRasterizationEnabled(false);\n\n    NS::Error* error = nullptr;\n    m_renderPipelineState = mtlRenderer->GetDevice()->newRenderPipelineState(renderPipelineDescriptor, &error);\n    if (error)\n    {\n        cemuLog_log(LogType::Force, \"error creating hybrid render pipeline state: {}\", error->localizedDescription()->utf8String());\n    }\n}\n\nMetalVoidVertexPipeline::~MetalVoidVertexPipeline()\n{\n    m_renderPipelineState->release();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/MetalVoidVertexPipeline.h",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/MetalCommon.h\"\n#include \"HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Metal/MTLLibrary.hpp\"\n#include \"Metal/MTLRenderPipeline.hpp\"\n\nclass MetalVoidVertexPipeline\n{\npublic:\n    MetalVoidVertexPipeline(class MetalRenderer* mtlRenderer, MTL::Library* library, const std::string& vertexFunctionName);\n    ~MetalVoidVertexPipeline();\n\n    MTL::RenderPipelineState* GetRenderPipelineState() const { return m_renderPipelineState; }\n\nprivate:\n    MTL::RenderPipelineState* m_renderPipelineState;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalCommon.h\"\n\n//#include \"Cemu/FileCache/FileCache.h\"\n//#include \"config/ActiveSettings.h\"\n#include \"Cemu/Logging/CemuLogging.h\"\n#include \"Common/precompiled.h\"\n#include \"GameProfile/GameProfile.h\"\n#include \"util/helpers/helpers.h\"\n\n#define METAL_AIR_CACHE_NAME \"Cemu_AIR_cache\"\n#define METAL_AIR_CACHE_PATH \"/Volumes/\" METAL_AIR_CACHE_NAME\n#define METAL_AIR_CACHE_SIZE (16 * 1024 * 1024)\n#define METAL_AIR_CACHE_BLOCK_COUNT (METAL_AIR_CACHE_SIZE / 512)\n\nstatic bool s_isLoadingShadersMtl{false};\n//static bool s_hasRAMFilesystem{false};\n//class FileCache* s_airCache{nullptr};\n\nextern std::atomic_int g_compiled_shaders_total;\nextern std::atomic_int g_compiled_shaders_async;\n\nclass ShaderMtlThreadPool\n{\npublic:\n\tvoid StartThreads()\n\t{\n\t\tif (m_threadsActive.exchange(true))\n\t\t\treturn;\n\n\t\t// Create thread pool\n\t\tconst uint32 threadCount = 2;\n\t\tfor (uint32 i = 0; i < threadCount; ++i)\n\t\t\ts_threads.emplace_back(&ShaderMtlThreadPool::CompilerThreadFunc, this);\n\n\t\t// Create AIR cache thread\n\t\t/*\n\t    s_airCacheThread = new std::thread(&ShaderMtlThreadPool::AIRCacheThreadFunc, this);\n\n\t\t// Set priority\n\t\tsched_param schedParam;\n        schedParam.sched_priority = 20;\n        if (pthread_setschedparam(s_airCacheThread->native_handle(), SCHED_FIFO, &schedParam) != 0) {\n            cemuLog_log(LogType::Force, \"failed to set FIFO thread priority\");\n        }\n\n        if (pthread_setschedparam(s_airCacheThread->native_handle(), SCHED_RR, &schedParam) != 0) {\n            cemuLog_log(LogType::Force, \"failed to set RR thread priority\");\n        }\n        */\n\t}\n\n\tvoid StopThreads()\n\t{\n\t\tif (!m_threadsActive.exchange(false))\n\t\t\treturn;\n\t\tfor (uint32 i = 0; i < s_threads.size(); ++i)\n\t\t\ts_compilationQueueCount.increment();\n\t\tfor (auto& it : s_threads)\n\t\t\tit.join();\n\t\ts_threads.clear();\n\n\t\t/*\n\t\tif (s_airCacheThread)\n\t\t{\n            s_airCacheQueueCount.increment();\n    \t\ts_airCacheThread->join();\n    \t\tdelete s_airCacheThread;\n\t\t}\n\t\t*/\n\t}\n\n\t~ShaderMtlThreadPool()\n\t{\n\t\tStopThreads();\n\t}\n\n\tvoid CompilerThreadFunc()\n\t{\n\t\tSetThreadName(\"mtlShaderComp\");\n\t\twhile (m_threadsActive.load(std::memory_order::relaxed))\n\t\t{\n\t\t\ts_compilationQueueCount.decrementWithWait();\n\t\t\ts_compilationQueueMutex.lock();\n\t\t\tif (s_compilationQueue.empty())\n\t\t\t{\n\t\t\t\t// queue empty again, shaders compiled synchronously via PreponeCompilation()\n\t\t\t\ts_compilationQueueMutex.unlock();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tRendererShaderMtl* job = s_compilationQueue.front();\n\t\t\ts_compilationQueue.pop_front();\n\t\t\t// set compilation state\n\t\t\tcemu_assert_debug(job->m_compilationState.getValue() == RendererShaderMtl::COMPILATION_STATE::QUEUED);\n\t\t\tjob->m_compilationState.setValue(RendererShaderMtl::COMPILATION_STATE::COMPILING);\n\t\t\ts_compilationQueueMutex.unlock();\n\t\t\t// compile\n\t\t\tjob->CompileInternal();\n\t\t\tif (job->ShouldCountCompilation())\n\t\t\t    ++g_compiled_shaders_async;\n\t\t\t// mark as compiled\n\t\t\tcemu_assert_debug(job->m_compilationState.getValue() == RendererShaderMtl::COMPILATION_STATE::COMPILING);\n\t\t\tjob->m_compilationState.setValue(RendererShaderMtl::COMPILATION_STATE::DONE);\n\t\t}\n\t}\n\n\t/*\n\tvoid AIRCacheThreadFunc()\n    {\n        SetThreadName(\"mtlAIRCache\");\n        while (m_threadsActive.load(std::memory_order::relaxed))\n        {\n            s_airCacheQueueCount.decrementWithWait();\n            s_airCacheQueueMutex.lock();\n            if (s_airCacheQueue.empty())\n            {\n                s_airCacheQueueMutex.unlock();\n                continue;\n            }\n\n            // Create RAM filesystem\n            if (!s_hasRAMFilesystem)\n            {\n                executeCommand(\"diskutil erasevolume HFS+ {} $(hdiutil attach -nomount ram://{})\", METAL_AIR_CACHE_NAME, METAL_AIR_CACHE_BLOCK_COUNT);\n                s_hasRAMFilesystem = true;\n            }\n\n            RendererShaderMtl* job = s_airCacheQueue.front();\n            s_airCacheQueue.pop_front();\n            s_airCacheQueueMutex.unlock();\n            // compile\n            job->CompileToAIR();\n        }\n    }\n    */\n\n\tbool HasThreadsRunning() const { return m_threadsActive; }\n\npublic:\n\tstd::vector<std::thread> s_threads;\n\t//std::thread* s_airCacheThread{nullptr};\n\n\tstd::deque<RendererShaderMtl*> s_compilationQueue;\n\tCounterSemaphore s_compilationQueueCount;\n\tstd::mutex s_compilationQueueMutex;\n\n\t/*\n\tstd::deque<RendererShaderMtl*> s_airCacheQueue;\n\tCounterSemaphore s_airCacheQueueCount;\n\tstd::mutex s_airCacheQueueMutex;\n\t*/\n\nprivate:\n\tstd::atomic<bool> m_threadsActive;\n} shaderMtlThreadPool;\n\n// TODO: find out if it would be possible to cache compiled Metal shaders\nvoid RendererShaderMtl::ShaderCacheLoading_begin(uint64 cacheTitleId)\n{\n    s_isLoadingShadersMtl = true;\n\n    // Open AIR cache\n    /*\n    if (s_airCache)\n\t{\n\t\tdelete s_airCache;\n\t\ts_airCache = nullptr;\n\t}\n\tuint32 airCacheMagic = GeneratePrecompiledCacheId();\n\tconst std::string cacheFilename = fmt::format(\"{:016x}_air.bin\", cacheTitleId);\n\tconst fs::path cachePath = ActiveSettings::GetCachePath(\"shaderCache/precompiled/{}\", cacheFilename);\n\ts_airCache = FileCache::Open(cachePath, true, airCacheMagic);\n\tif (!s_airCache)\n\t\tcemuLog_log(LogType::Force, \"Unable to open AIR cache {}\", cacheFilename);\n\t*/\n\n    // Maximize shader compilation speed\n    static_cast<MetalRenderer*>(g_renderer.get())->SetShouldMaximizeConcurrentCompilation(true);\n}\n\nvoid RendererShaderMtl::ShaderCacheLoading_end()\n{\n    s_isLoadingShadersMtl = false;\n\n    // Reset shader compilation speed\n    static_cast<MetalRenderer*>(g_renderer.get())->SetShouldMaximizeConcurrentCompilation(false);\n}\n\nvoid RendererShaderMtl::ShaderCacheLoading_Close()\n{\n    // Close the AIR cache\n    /*\n    if (s_airCache)\n    {\n        delete s_airCache;\n        s_airCache = nullptr;\n    }\n\n    // Close RAM filesystem\n    if (s_hasRAMFilesystem)\n        executeCommand(\"diskutil eject {}\", METAL_AIR_CACHE_PATH);\n    */\n}\n\nvoid RendererShaderMtl::Initialize()\n{\n    shaderMtlThreadPool.StartThreads();\n}\n\nvoid RendererShaderMtl::Shutdown()\n{\n    shaderMtlThreadPool.StopThreads();\n}\n\nRendererShaderMtl::RendererShaderMtl(MetalRenderer* mtlRenderer, ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& mslCode)\n\t: RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_mtlr{mtlRenderer}, m_mslCode{mslCode}\n{\n\t// start async compilation\n\tshaderMtlThreadPool.s_compilationQueueMutex.lock();\n\tm_compilationState.setValue(COMPILATION_STATE::QUEUED);\n\tshaderMtlThreadPool.s_compilationQueue.push_back(this);\n\tshaderMtlThreadPool.s_compilationQueueCount.increment();\n\tshaderMtlThreadPool.s_compilationQueueMutex.unlock();\n\tcemu_assert_debug(shaderMtlThreadPool.HasThreadsRunning()); // make sure .StartThreads() was called\n}\n\nRendererShaderMtl::~RendererShaderMtl()\n{\n    if (m_function)\n        m_function->release();\n}\n\nvoid RendererShaderMtl::PreponeCompilation(bool isRenderThread)\n{\n\tshaderMtlThreadPool.s_compilationQueueMutex.lock();\n\tbool isStillQueued = m_compilationState.hasState(COMPILATION_STATE::QUEUED);\n\tif (isStillQueued)\n\t{\n\t\t// remove from queue\n\t\tshaderMtlThreadPool.s_compilationQueue.erase(std::remove(shaderMtlThreadPool.s_compilationQueue.begin(), shaderMtlThreadPool.s_compilationQueue.end(), this), shaderMtlThreadPool.s_compilationQueue.end());\n\t\tm_compilationState.setValue(COMPILATION_STATE::COMPILING);\n\t}\n\tshaderMtlThreadPool.s_compilationQueueMutex.unlock();\n\tif (!isStillQueued)\n\t{\n\t\tm_compilationState.waitUntilValue(COMPILATION_STATE::DONE);\n\t\tif (ShouldCountCompilation())\n\t\t    --g_compiled_shaders_async; // compilation caused a stall so we don't consider this one async\n\t\treturn;\n\t}\n\telse\n\t{\n\t\t// compile synchronously\n\t\tCompileInternal();\n\t\tm_compilationState.setValue(COMPILATION_STATE::DONE);\n\t}\n}\n\nbool RendererShaderMtl::IsCompiled()\n{\n\treturn m_compilationState.hasState(COMPILATION_STATE::DONE);\n};\n\nbool RendererShaderMtl::WaitForCompiled()\n{\n\tm_compilationState.waitUntilValue(COMPILATION_STATE::DONE);\n\treturn true;\n}\n\nbool RendererShaderMtl::ShouldCountCompilation() const\n{\n    return !s_isLoadingShadersMtl && m_isGameShader;\n}\n\nMTL::Library* RendererShaderMtl::LibraryFromSource()\n{\n    // Compile from source\n    NS_STACK_SCOPED MTL::CompileOptions* options = MTL::CompileOptions::alloc()->init();\n    if (g_current_game_profile->GetShaderFastMath())\n        options->setFastMathEnabled(true);\n\n    if (m_mtlr->GetPositionInvariance())\n    {\n        // TODO: filter out based on GPU state\n        options->setPreserveInvariance(true);\n    }\n\n    NS::Error* error = nullptr;\n\tMTL::Library* library = m_mtlr->GetDevice()->newLibrary(ToNSString(m_mslCode), options, &error);\n\tif (error)\n    {\n        cemuLog_log(LogType::Force, \"failed to create library from source: {} -> {}\", error->localizedDescription()->utf8String(), m_mslCode.c_str());\n        return nullptr;\n    }\n\n    return library;\n}\n\n/*\nMTL::Library* RendererShaderMtl::LibraryFromAIR(std::span<uint8> data)\n{\n    dispatch_data_t dispatchData = dispatch_data_create(data.data(), data.size(), nullptr, DISPATCH_DATA_DESTRUCTOR_DEFAULT);\n\n    NS::Error* error = nullptr;\n\tMTL::Library* library = m_mtlr->GetDevice()->newLibrary(dispatchData, &error);\n\tif (error)\n    {\n        cemuLog_log(LogType::Force, \"failed to create library from AIR: {}\", error->localizedDescription()->utf8String());\n        return nullptr;\n    }\n\n    return library;\n}\n*/\n\nvoid RendererShaderMtl::CompileInternal()\n{\n    MTL::Library* library = nullptr;\n\n    // First, try to retrieve the compiled shader from the AIR cache\n    /*\n    if (s_isLoadingShadersMtl && (m_isGameShader && !m_isGfxPackShader) && s_airCache)\n    {\n        cemu_assert_debug(m_baseHash != 0);\n\t\tuint64 h1, h2;\n\t\tGenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);\n\t\tstd::vector<uint8> cacheFileData;\n\t\tif (s_airCache->GetFile({ h1, h2 }, cacheFileData))\n\t\t{\n\t\t\tlibrary = LibraryFromAIR(std::span<uint8>(cacheFileData.data(), cacheFileData.size()));\n\t\t\tFinishCompilation();\n\t\t}\n    }\n    */\n\n    // Not in the cache, compile from source\n    if (!library)\n    {\n        // Compile from source\n        library = LibraryFromSource();\n        FinishCompilation();\n        if (!library)\n            return;\n\n        // Store in the AIR cache\n        /*\n        shaderMtlThreadPool.s_airCacheQueueMutex.lock();\n        shaderMtlThreadPool.s_airCacheQueue.push_back(this);\n        shaderMtlThreadPool.s_airCacheQueueCount.increment();\n        shaderMtlThreadPool.s_airCacheQueueMutex.unlock();\n        */\n    }\n\n    m_function = library->newFunction(ToNSString(\"main0\"));\n    library->release();\n\n\t// Count shader compilation\n\tif (ShouldCountCompilation())\n\t    g_compiled_shaders_total++;\n}\n\n/*\nvoid RendererShaderMtl::CompileToAIR()\n{\n    uint64 h1, h2;\n\tGenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);\n\n    // The shader is not in the cache, compile it\n\tstd::string baseFilename = fmt::format(\"{}/{}_{}\", METAL_AIR_CACHE_PATH, h1, h2);\n\n\t// Source\n\tstd::ofstream mslFile;\n    mslFile.open(fmt::format(\"{}.metal\", baseFilename));\n    mslFile << m_mslCode;\n    mslFile.close();\n\n    // Compile\n\tif (!executeCommand(\"xcrun -sdk macosx metal -o {}.ir -c {}.metal -w\", baseFilename, baseFilename))\n\t    return;\n\tif (!executeCommand(\"xcrun -sdk macosx metallib -o {}.metallib {}.ir\", baseFilename, baseFilename))\n        return;\n\n\t// Clean up\n\texecuteCommand(\"rm {}.metal\", baseFilename);\n\texecuteCommand(\"rm {}.ir\", baseFilename);\n\n\t// Load from the newly generated AIR\n\tMemoryMappedFile airFile(fmt::format(\"{}.metallib\", baseFilename));\n\tstd::span<uint8> airData = std::span<uint8>(airFile.data(), airFile.size());\n\t//library = LibraryFromAIR(std::span<uint8>(airData.data(), airData.size()));\n\n\t// Store in the cache\n\ts_airCache->AddFile({ h1, h2 }, airData.data(), airData.size());\n\n\t// Clean up\n\texecuteCommand(\"rm {}.metallib\", baseFilename);\n\n\tFinishCompilation();\n}\n*/\n\nvoid RendererShaderMtl::FinishCompilation()\n{\n    m_mslCode.clear();\n    m_mslCode.shrink_to_fit();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/RendererShaderMtl.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/RendererShader.h\"\n#include \"HW/Latte/Renderer/Metal/CachedFBOMtl.h\"\n#include \"HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#include \"util/helpers/ConcurrentQueue.h\"\n#include \"util/helpers/Semaphore.h\"\n\n#include <Metal/Metal.hpp>\n\nclass RendererShaderMtl : public RendererShader\n{\n    friend class ShaderMtlThreadPool;\n\n\tenum class COMPILATION_STATE : uint32\n\t{\n\t\tNONE,\n\t\tQUEUED,\n\t\tCOMPILING,\n\t\tDONE\n\t};\n\npublic:\n    static void ShaderCacheLoading_begin(uint64 cacheTitleId);\n    static void ShaderCacheLoading_end();\n    static void ShaderCacheLoading_Close();\n\n    static void Initialize();\n\tstatic void Shutdown();\n\n\tRendererShaderMtl(class MetalRenderer* mtlRenderer, ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& mslCode);\n\tvirtual ~RendererShaderMtl();\n\n\tMTL::Function* GetFunction() const\n\t{\n\t    return m_function;\n\t}\n\n\tvoid PreponeCompilation(bool isRenderThread) override;\n\tbool IsCompiled() override;\n\tbool WaitForCompiled() override;\n\nprivate:\n    class MetalRenderer* m_mtlr;\n\n\tMTL::Function* m_function = nullptr;\n\n\tStateSemaphore<COMPILATION_STATE> m_compilationState{ COMPILATION_STATE::NONE };\n\n\tstd::string m_mslCode;\n\n\tbool ShouldCountCompilation() const;\n\n\tMTL::Library* LibraryFromSource();\n\n\t//MTL::Library* LibraryFromAIR(std::span<uint8> data);\n\n\tvoid CompileInternal();\n\n\t//void CompileToAIR();\n\n\tvoid FinishCompilation();\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Metal/UtilityShaderSource.h",
    "content": "#pragma once\n\n#define __STRINGIFY(x) #x\n#define _STRINGIFY(x) __STRINGIFY(x)\n\nconstexpr const char* utilityShaderSource = R\"(#include <metal_stdlib>\nusing namespace metal;\n\n#define GET_BUFFER_BINDING(index) (28 + index)\n#define GET_TEXTURE_BINDING(index) (29 + index)\n#define GET_SAMPLER_BINDING(index) (14 + index)\n\nconstant float2 positions[] = {float2(-1.0, -3.0), float2(-1.0, 1.0), float2(3.0, 1.0)};\n\nstruct VertexOut {\n    float4 position [[position]];\n    float2 texCoord;\n};\n\nvertex VertexOut vertexFullscreen(ushort vid [[vertex_id]]) {\n    VertexOut out;\n    out.position = float4(positions[vid], 0.0, 1.0);\n    out.texCoord = positions[vid] * 0.5 + 0.5;\n    out.texCoord.y = 1.0 - out.texCoord.y;\n\n    return out;\n}\n\n//fragment float4 fragmentPresent(VertexOut in [[stage_in]], texture2d<float> tex [[texture(0)]], //sampler samplr [[sampler(0)]]) {\n//    return tex.sample(samplr, in.texCoord);\n//}\n\nvertex void vertexCopyBufferToBuffer(uint vid [[vertex_id]], device uint8_t* src [[buffer(GET_BUFFER_BINDING(0))]], device uint8_t* dst [[buffer(GET_BUFFER_BINDING(1))]]) {\n    dst[vid] = src[vid];\n}\n\nfragment float4 fragmentCopyDepthToColor(VertexOut in [[stage_in]], texture2d<float, access::read> src [[texture(GET_TEXTURE_BINDING(0))]]) {\n    return float4(src.read(uint2(in.position.xy)).r, 0.0, 0.0, 0.0);\n}\n\n//struct RestrideParams {\n//    uint oldStride;\n//    uint newStride;\n//};\n\n//vertex void vertexRestrideBuffer(uint vid [[vertex_id]], device uint8_t* src [[buffer//(GET_BUFFER_BINDING(0))]], device uint8_t* dst [[buffer(GET_BUFFER_BINDING(1))]], constant //RestrideParams& params [[buffer(GET_BUFFER_BINDING(2))]]) {\n//    for (uint32_t i = 0; i < params.oldStride; i++) {\n//        dst[vid * params.newStride + i] = src[vid * params.oldStride + i];\n//    }\n//}\n)\";\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/MetalView.h",
    "content": "#pragma once\n\n#import <Cocoa/Cocoa.h>\n#import <QuartzCore/CAMetalLayer.h>\n\n@interface MetalView : NSView\n@end\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/MetalView.mm",
    "content": "#include \"Cafe/HW/Latte/Renderer/MetalView.h\"\n\n@implementation MetalView\n\n-(BOOL) wantsUpdateLayer { return YES; }\n\n+(Class) layerClass { return [CAMetalLayer class]; }\n\n// copied from https://github.com/KhronosGroup/MoltenVK/blob/master/Demos/Cube/macOS/DemoViewController.m\n\n-(CALayer*) makeBackingLayer\n{\n\tCALayer* layer = [self.class.layerClass layer];\n\tCGSize viewScale = [self convertSizeToBacking: CGSizeMake(1.0, 1.0)];\n\tlayer.contentsScale = MIN(viewScale.width, viewScale.height);\n\treturn layer;\n}\n\n-(BOOL) layer: (CALayer *)layer shouldInheritContentsScale: (CGFloat)newScale fromWindow: (NSWindow *)window\n{\n\tif (newScale == layer.contentsScale) { return NO; }\n\n\tlayer.contentsScale = newScale;\n\treturn YES;\n}\n@end\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/CachedFBOGL.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h\"\n#include \"Cafe/HW/Latte/Core/LatteCachedFBO.h\"\n#include \"Common/GLInclude/GLInclude.h\"\n\nclass CachedFBOGL : public LatteCachedFBO\n{\npublic:\n\tCachedFBOGL(uint64 key)\n\t\t: LatteCachedFBO(key)\n\t{\n\t\t// generate framebuffer\n\t\tif (glCreateFramebuffers && false)\n\t\t\tglCreateFramebuffers(1, &glId_fbo);\n\t\telse\n\t\t\tglGenFramebuffers(1, &glId_fbo);\n\t\t// bind framebuffer\n\t\t((OpenGLRenderer*)g_renderer.get())->rendertarget_bindFramebufferObject(this);\n\t\t// setup framebuffer\n\t\tfor (sint32 i = 0; i < 8; i++)\n\t\t{\n\t\t\tLatteTextureViewGL* colorTexViewGL = (LatteTextureViewGL*)colorBuffer[i].texture;\n\t\t\tif (!colorTexViewGL)\n\t\t\t\tglFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL_TEXTURE_2D, 0, 0);\n\t\t\telse if (colorTexViewGL->dim == Latte::E_DIM::DIM_2D)\n\t\t\t\tglFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL_TEXTURE_2D, colorTexViewGL->glTexId, 0);\n\t\t\telse if (colorTexViewGL->dim == Latte::E_DIM::DIM_3D)\n\t\t\t\tglFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT + i, colorTexViewGL->glTexId, 0, 0);\n\t\t\telse if (colorTexViewGL->dim == Latte::E_DIM::DIM_2D_ARRAY)\n\t\t\t\tglFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT + i, colorTexViewGL->glTexId, 0, 0);\n\t\t\telse if (colorTexViewGL->dim == Latte::E_DIM::DIM_CUBEMAP)\n\t\t\t\tglFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT + i, colorTexViewGL->glTexId, 0, 0);\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t}\n\t\t}\n\n\t\tif (depthBuffer.texture)\n\t\t{\n\t\t\tLatteTextureViewGL* depthTexViewGL = (LatteTextureViewGL*)depthBuffer.texture;\n\t\t\tif (depthTexViewGL->dim == Latte::E_DIM::DIM_2D)\n\t\t\t\tglFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexViewGL->glTexId, 0);\n\t\t\telse if (depthTexViewGL->dim == Latte::E_DIM::DIM_2D_ARRAY)\n\t\t\t\tglFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexViewGL->glTexId, 0, 0);\n\t\t\telse\n\t\t\t\tcemu_assert_suspicious();\n\t\t\tif (depthBuffer.hasStencil)\n\t\t\t{\n\t\t\t\tif (depthTexViewGL->dim == Latte::E_DIM::DIM_2D)\n\t\t\t\t\tglFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthTexViewGL->glTexId, 0);\n\t\t\t\telse if (depthTexViewGL->dim == Latte::E_DIM::DIM_2D_ARRAY)\n\t\t\t\t\tglFramebufferTextureLayer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthTexViewGL->glTexId, 0, 0);\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tglFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tglFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);\n\t\t\tglFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);\n\t\t}\n\t\tSetDrawBuffers();\n\t}\n\nprivate:\n\tvoid SetDrawBuffers()\n\t{\n\t\tGLenum buffers[8];\n\t\tuint32 bufferCount = 0;\n\t\tfor (uint32 i = 0; i < 8; i++)\n\t\t{\n\t\t\tif (colorBuffer[i].texture)\n\t\t\t{\n\t\t\t\tbuffers[bufferCount] = GL_COLOR_ATTACHMENT0_EXT + i;\n\t\t\t\tbufferCount++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// pad with GL_NONE entries to make sure that draw buffer indices match up with color attachment indices\n\t\t\t\tbuffers[bufferCount] = GL_NONE;\n\t\t\t\tbufferCount++;\n\t\t\t}\n\t\t}\n\t\t// trim trailing GL_NONE\n\t\twhile (bufferCount > 0 && buffers[bufferCount - 1] == GL_NONE)\n\t\t\tbufferCount--;\n\n\t\tif (bufferCount == 0)\n\t\t\tglDrawBuffer(GL_NONE);\n\t\telse\n\t\t\tglDrawBuffers(bufferCount, buffers);\n\t}\n\npublic:\n\tGLuint glId_fbo{};\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n\n#include \"config/LaunchSettings.h\"\n\nLatteTextureGL::LatteTextureGL(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle,\n\tLatte::E_HWTILEMODE tileMode, bool isDepth)\n\t: LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth)\n{\n\tGenerateEmptyTextureFromGX2Dim(dim, this->glId_texture, this->glTexTarget, true);\n\t// set format info\n\tFormatInfoGL glFormatInfo;\n\tGetOpenGLFormatInfo(isDepth, overwriteInfo.hasFormatOverwrite ? (Latte::E_GX2SURFFMT)overwriteInfo.format : format, dim, &glFormatInfo);\n\tthis->glInternalFormat = glFormatInfo.glInternalFormat;\n\tthis->isAlternativeFormat = glFormatInfo.isUsingAlternativeFormat;\n\t// set debug name\n\tbool useGLDebugNames = false;\n#ifdef CEMU_DEBUG_ASSERT\n\tuseGLDebugNames = true;\n#endif\n\tif (LaunchSettings::NSightModeEnabled())\n\t\tuseGLDebugNames = true;\n\tif (useGLDebugNames)\n\t{\n\t\tchar textureDebugLabel[512];\n\t\tsprintf(textureDebugLabel, \"%08x_f%04x%s_p%04x_%dx%d\", physAddress, (uint32)format, this->isDepth ? \"_d\" : \"\", pitch, width, height);\n\t\tglObjectLabel(GL_TEXTURE, this->glId_texture, -1, textureDebugLabel);\n\t}\n}\n\nLatteTextureGL::~LatteTextureGL()\n{\n\tglDeleteTextures(1, &glId_texture);\n\tcatchOpenGLError();\n}\n\nvoid LatteTextureGL::GenerateEmptyTextureFromGX2Dim(Latte::E_DIM dim, GLuint& texId, GLint& texTarget, bool createForTargetType)\n{\n\tif (dim == Latte::E_DIM::DIM_2D)\n\t\ttexTarget = GL_TEXTURE_2D;\n\telse if (dim == Latte::E_DIM::DIM_1D)\n\t\ttexTarget = GL_TEXTURE_1D;\n\telse if (dim == Latte::E_DIM::DIM_3D)\n\t\ttexTarget = GL_TEXTURE_3D;\n\telse if (dim == Latte::E_DIM::DIM_2D_ARRAY)\n\t\ttexTarget = GL_TEXTURE_2D_ARRAY;\n\telse if (dim == Latte::E_DIM::DIM_CUBEMAP)\n\t\ttexTarget = GL_TEXTURE_CUBE_MAP_ARRAY;\n\telse if (dim == Latte::E_DIM::DIM_2D_MSAA)\n\t\ttexTarget = GL_TEXTURE_2D; // todo, GL_TEXTURE_2D_MULTISAMPLE ?\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\tif(createForTargetType)\n\t\ttexId = glCreateTextureWrapper(texTarget); // initializes the texture to texTarget (equivalent to calling glGenTextures + glBindTexture)\n\telse\n\t\tglGenTextures(1, &texId);\n}\n\nLatteTextureView* LatteTextureGL::CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)\n{\n\treturn new LatteTextureViewGL(this, dim, format, firstMip, mipCount, firstSlice, sliceCount);\n}\n\nvoid LatteTextureGL::GetOpenGLFormatInfo(bool isDepth, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, FormatInfoGL* formatInfoOut)\n{\n\tformatInfoOut->isUsingAlternativeFormat = false;\n\n\tif (isDepth)\n\t{\n\t\tif (format == Latte::E_GX2SURFFMT::D24_S8_UNORM)\n\t\t{\n\t\t\tformatInfoOut->setFormat(GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);\n\t\t\treturn;\n\t\t}\n\t\telse if (format == Latte::E_GX2SURFFMT::D24_S8_FLOAT)\n\t\t{\n\t\t\tformatInfoOut->setFormat(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);\n\t\t\tformatInfoOut->markAsAlternativeFormat();\n\t\t\treturn;\n\t\t}\n\t\telse if (format == Latte::E_GX2SURFFMT::D32_S8_FLOAT)\n\t\t{\n\t\t\tformatInfoOut->setFormat(GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);\n\t\t\treturn;\n\t\t}\n\t\telse if (format == Latte::E_GX2SURFFMT::D32_FLOAT)\n\t\t{\n\t\t\tformatInfoOut->setFormat(GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT);\n\t\t\treturn;\n\t\t}\n\t\telse if (format == Latte::E_GX2SURFFMT::D16_UNORM)\n\t\t{\n\t\t\tformatInfoOut->setFormat(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT);\n\t\t\treturn;\n\t\t}\n\t\t// unsupported depth format\n\t\tcemuLog_log(LogType::Force, \"OpenGL: Unsupported texture depth format 0x{:04x}\", (uint32)format);\n\t\t// use placeholder format\n\t\tformatInfoOut->setFormat(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT);\n\t\tformatInfoOut->markAsAlternativeFormat();\n\t\treturn;\n\t}\n\n\tbool glIsCompressed = false;\n\tbool isUsingAlternativeFormat = false; // set to true if there is no bit-perfect matching OpenGL format\n\tsint32 glInternalFormat;\n\tsint32 glSuppliedFormat;\n\tsint32 glSuppliedFormatType;\n\t// get format information\n\tif (format == Latte::E_GX2SURFFMT::R4_G4_UNORM)\n\t{\n\t\tformatInfoOut->setFormat(GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4);\n\t\tformatInfoOut->markAsAlternativeFormat();\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM)\n\t{\n\t\tformatInfoOut->setFormat(GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT)\n\t{\n\t\tformatInfoOut->setFormat(GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_FLOAT)\n\t{\n\t\tformatInfoOut->setFormat(GL_RG16F, GL_RG, GL_HALF_FLOAT);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R16_SNORM)\n\t{\n\t\tformatInfoOut->setFormat(GL_R16_SNORM, GL_RED, GL_SHORT);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R16_FLOAT)\n\t{\n\t\tformatInfoOut->setFormat(GL_R16F, GL_RED, GL_HALF_FLOAT);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::BC1_UNORM ||\n\t\tformat == Latte::E_GX2SURFFMT::BC1_SRGB)\n\t{\n\t\tif (format == Latte::E_GX2SURFFMT::BC1_SRGB)\n\t\t\tformatInfoOut->setCompressed(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, -1, -1);\n\t\telse\n\t\t\tformatInfoOut->setCompressed(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, -1, -1);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::BC2_UNORM || format == Latte::E_GX2SURFFMT::BC2_SRGB)\n\t{\n\t\t// todo - use OpenGL BC2 format if available\n\t\tformatInfoOut->setFormat(GL_RGBA16F, GL_RGBA, GL_FLOAT);\n\t\tformatInfoOut->markAsAlternativeFormat();\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::BC3_UNORM || format == Latte::E_GX2SURFFMT::BC3_SRGB)\n\t{\n\t\tif (format == Latte::E_GX2SURFFMT::BC3_SRGB)\n\t\t\tformatInfoOut->setCompressed(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, -1, -1);\n\t\telse\n\t\t\tformatInfoOut->setCompressed(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, -1, -1);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::BC4_UNORM || format == Latte::E_GX2SURFFMT::BC4_SNORM)\n\t{\n\t\tbool allowCompressed = true;\n\t\tif (dim != Latte::E_DIM::DIM_2D && dim != Latte::E_DIM::DIM_2D_ARRAY)\n\t\t\tallowCompressed = false; // RGTC1 does not support non-2D textures\n\t\tif (allowCompressed)\n\t\t{\n\t\t\tif (format == Latte::E_GX2SURFFMT::BC4_UNORM)\n\t\t\t\tformatInfoOut->setCompressed(GL_COMPRESSED_RED_RGTC1, -1, -1);\n\t\t\telse\n\t\t\t\tformatInfoOut->setCompressed(GL_COMPRESSED_SIGNED_RED_RGTC1, -1, -1);\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tformatInfoOut->setFormat(GL_RG16F, GL_RG, GL_FLOAT);\n\t\t\tformatInfoOut->markAsAlternativeFormat();\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::BC5_UNORM || format == Latte::E_GX2SURFFMT::BC5_SNORM)\n\t{\n\t\tif (format == Latte::E_GX2SURFFMT::BC5_SNORM)\n\t\t\tformatInfoOut->setCompressed(GL_COMPRESSED_SIGNED_RG_RGTC2, -1, -1);\n\t\telse\n\t\t\tformatInfoOut->setCompressed(GL_COMPRESSED_RG_RGTC2, -1, -1);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R32_FLOAT)\n\t{\n\t\tformatInfoOut->setFormat(GL_R32F, GL_RED, GL_FLOAT);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R32_G32_FLOAT)\n\t{\n\t\tformatInfoOut->setFormat(GL_RG32F, GL_RG, GL_FLOAT);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R32_G32_UINT)\n\t{\n\t\tformatInfoOut->setFormat(GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R32_UINT)\n\t{\n\t\tformatInfoOut->setFormat(GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R16_UINT)\n\t{\n\t\t// used by VC DS (New Super Mario Bros)\n\t\tformatInfoOut->setFormat(GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R8_UINT)\n\t{\n\t\t// used by VC DS (New Super Mario Bros)\n\t\tformatInfoOut->setFormat(GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT)\n\t{\n\t\tformatInfoOut->setFormat(GL_RGBA32F, GL_RGBA, GL_FLOAT);\n\t\treturn;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM || format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB)\n\t{\n\t\tif (format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB)\n\t\t\tglInternalFormat = GL_SRGB8_ALPHA8;\n\t\telse\n\t\t\tglInternalFormat = GL_RGBA8;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_UNSIGNED_BYTE;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SNORM)\n\t{\n\t\tglInternalFormat = GL_RGBA8_SNORM;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_BYTE;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R8_UNORM)\n\t{\n\t\tglInternalFormat = GL_R8;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RED;\n\t\tglSuppliedFormatType = GL_UNSIGNED_BYTE;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R8_SNORM)\n\t{\n\t\tglInternalFormat = GL_R8_SNORM;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RED;\n\t\tglSuppliedFormatType = GL_BYTE;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_UNORM)\n\t{\n\t\tglInternalFormat = GL_RG8;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RG;\n\t\tglSuppliedFormatType = GL_UNSIGNED_BYTE;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_SNORM)\n\t{\n\t\tglInternalFormat = GL_RG8_SNORM;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RG;\n\t\tglSuppliedFormatType = GL_BYTE;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R16_UNORM)\n\t{\n\t\tglInternalFormat = GL_R16;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RED;\n\t\tglSuppliedFormatType = GL_UNSIGNED_SHORT;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM)\n\t{\n\t\tglInternalFormat = GL_RGBA16;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_UNSIGNED_SHORT;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_SNORM)\n\t{\n\t\tglInternalFormat = GL_RGBA16_SNORM;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_SHORT;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_UNORM)\n\t{\n\t\tglInternalFormat = GL_RG16;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RG;\n\t\tglSuppliedFormatType = GL_UNSIGNED_SHORT;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R5_G6_B5_UNORM)\n\t{\n\t\tglInternalFormat = GL_RGB565;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGB;\n\t\tglSuppliedFormatType = GL_UNSIGNED_SHORT_5_6_5_REV;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM)\n\t{\n\t\tglInternalFormat = GL_RGB5_A1;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_UNSIGNED_SHORT_5_5_5_1;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM)\n\t{\n\t\tglInternalFormat = GL_RGB5_A1;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_UNSIGNED_SHORT_5_5_5_1;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM)\n\t{\n\t\tglInternalFormat = GL_RGB10_A2;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_UNSIGNED_INT_2_10_10_10_REV;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB) // used by Super Mario Maker\n\t{\n\t\tglInternalFormat = GL_RGB10_A2; // todo - how to handle SRGB for this format?\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_UNSIGNED_INT_2_10_10_10_REV;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::A2_B10_G10_R10_UNORM)\n\t{\n\t\tglInternalFormat = GL_RGB10_A2;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_UNSIGNED_INT_10_10_10_2;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM)\n\t{\n\t\tglInternalFormat = GL_RGBA16_SNORM; // OpenGL has no signed version of GL_RGB10_A2\n\t\tisUsingAlternativeFormat = true;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_SHORT;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT)\n\t{\n\t\tglInternalFormat = GL_R11F_G11F_B10F;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGB;\n\t\tglSuppliedFormatType = GL_UNSIGNED_INT_10F_11F_11F_REV;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT)\n\t{\n\t\tglInternalFormat = GL_RGBA32UI;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA_INTEGER;\n\t\tglSuppliedFormatType = GL_UNSIGNED_INT;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT)\n\t{\n\t\tglInternalFormat = GL_RGBA16UI;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA_INTEGER;\n\t\tglSuppliedFormatType = GL_UNSIGNED_SHORT;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UINT)\n\t{\n\t\tglInternalFormat = GL_RGBA8UI;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA_INTEGER;\n\t\tglSuppliedFormatType = GL_UNSIGNED_BYTE;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R24_X8_UNORM)\n\t{\n\t\t// OpenGL has no color version of GL_DEPTH24_STENCIL8, therefore we use a 32-bit floating-point format instead\n\t\tglInternalFormat = GL_R32F;\n\t\tisUsingAlternativeFormat = true;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RED;\n\t\tglSuppliedFormatType = GL_FLOAT;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::X24_G8_UINT)\n\t{\n\t\t// OpenGL has no X24_G8 format, we use RGBA8UI instead and manually swizzle the channels\n\t\t// this format is used in Resident Evil Revelations when scanning with the Genesis. It's also used in Cars 3: Driven to Win?\n\n\t\tglInternalFormat = GL_RGBA8UI;\n\t\tisUsingAlternativeFormat = true;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_RGBA;\n\t\tglSuppliedFormatType = GL_FLOAT;\n\t\tglIsCompressed = false;\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::R32_X8_FLOAT)\n\t{\n\t\t// only available as depth format in OpenGL\n\t\t// used by Cars 3: Driven to Win\n\t\t// find a way to emulate this using a color format\n\t\tglInternalFormat = GL_DEPTH32F_STENCIL8;\n\t\tisUsingAlternativeFormat = false;\n\t\t// supplied format\n\t\tglSuppliedFormat = GL_DEPTH_STENCIL;\n\t\tglSuppliedFormatType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;\n\t\tglIsCompressed = false;\n\t\tcemu_assert_debug(false);\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"OpenGL: Unsupported texture format 0x{:04x}\", (uint32)format);\n\t\tcemu_assert_unimplemented();\n\t}\n\tformatInfoOut->glInternalFormat = glInternalFormat;\n\tformatInfoOut->glSuppliedFormat = glSuppliedFormat;\n\tformatInfoOut->glSuppliedFormatType = glSuppliedFormatType;\n\tformatInfoOut->glIsCompressed = glIsCompressed;\n\tformatInfoOut->isUsingAlternativeFormat = isUsingAlternativeFormat;\n}\n\nvoid LatteTextureGL::AllocateOnHost()\n{\n\tauto hostTexture = this;\n\tcemu_assert_debug(hostTexture->isDataDefined == false);\n\tsint32 effectiveBaseWidth = hostTexture->width;\n\tsint32 effectiveBaseHeight = hostTexture->height;\n\tsint32 effectiveBaseDepth = hostTexture->depth;\n\tif (hostTexture->overwriteInfo.hasResolutionOverwrite)\n\t{\n\t\teffectiveBaseWidth = hostTexture->overwriteInfo.width;\n\t\teffectiveBaseHeight = hostTexture->overwriteInfo.height;\n\t\teffectiveBaseDepth = hostTexture->overwriteInfo.depth;\n\t}\n\t// calculate mip count\n\tsint32 mipLevels = std::min(hostTexture->mipLevels, hostTexture->maxPossibleMipLevels);\n\tmipLevels = std::max(mipLevels, 1);\n\t// create immutable storage\n\tif (hostTexture->dim == Latte::E_DIM::DIM_2D || hostTexture->dim == Latte::E_DIM::DIM_2D_MSAA)\n\t{\n\t\tcemu_assert_debug(effectiveBaseDepth == 1);\n\t\tglTextureStorage2DWrapper(GL_TEXTURE_2D, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight);\n\t}\n\telse if (hostTexture->dim == Latte::E_DIM::DIM_1D)\n\t{\n\t\tcemu_assert_debug(effectiveBaseHeight == 1);\n\t\tcemu_assert_debug(effectiveBaseDepth == 1);\n\t\tglTextureStorage1DWrapper(GL_TEXTURE_1D, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth);\n\t}\n\telse if (hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY || hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA)\n\t{\n\t\tglTextureStorage3DWrapper(GL_TEXTURE_2D_ARRAY, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth));\n\t}\n\telse if (hostTexture->dim == Latte::E_DIM::DIM_3D)\n\t{\n\t\tglTextureStorage3DWrapper(GL_TEXTURE_3D, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, std::max(1, effectiveBaseDepth));\n\t}\n\telse if (hostTexture->dim == Latte::E_DIM::DIM_CUBEMAP)\n\t{\n\t\tglTextureStorage3DWrapper(GL_TEXTURE_CUBE_MAP_ARRAY, hostTexture->glId_texture, mipLevels, hostTexture->glInternalFormat, effectiveBaseWidth, effectiveBaseHeight, effectiveBaseDepth);\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"Common/GLInclude/GLInclude.h\"\n\nclass LatteTextureGL : public LatteTexture\n{\npublic:\n\tLatteTextureGL(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels,\n\t\tuint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth);\n\n\t~LatteTextureGL();\n\n\tvoid AllocateOnHost() override;\n\n\tstatic void GenerateEmptyTextureFromGX2Dim(Latte::E_DIM dim, GLuint& texId, GLint& texTarget, bool createForTargetType);\n\nprotected:\n\tLatteTextureView* CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) override;\n\npublic:\n\tstruct FormatInfoGL\n\t{\n\t\tsint32 glInternalFormat;\n\t\tsint32 glSuppliedFormat;\n\t\tsint32 glSuppliedFormatType;\n\t\tbool glIsCompressed;\n\t\tbool isUsingAlternativeFormat{};\n\n\t\tvoid setFormat(sint32 glInternalFormat, sint32 glSuppliedFormat, sint32 glSuppliedFormatType)\n\t\t{\n\t\t\tthis->glInternalFormat = glInternalFormat;\n\t\t\tthis->glSuppliedFormat = glSuppliedFormat;\n\t\t\tthis->glSuppliedFormatType = glSuppliedFormatType;\n\t\t\tthis->glIsCompressed = false;\n\t\t}\n\n\t\tvoid setCompressed(sint32 glInternalFormat, sint32 glSuppliedFormat, sint32 glSuppliedFormatType)\n\t\t{\n\t\t\tsetFormat(glInternalFormat, glSuppliedFormat, glSuppliedFormatType);\n\t\t\tthis->glIsCompressed = true;\n\t\t}\n\n\t\tvoid markAsAlternativeFormat()\n\t\t{\n\t\t\tthis->isUsingAlternativeFormat = true;\n\t\t}\n\t};\n\n\tstatic void GetOpenGLFormatInfo(bool isDepth, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, FormatInfoGL* formatInfoOut);\n\n\t// OpenGL stuff\n\tGLuint glId_texture;\n\tGLint glTexTarget; // GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_2D_ARRAY etc.\n\tGLint glInternalFormat = 0; // internal format of OpenGL texture (0 if not initialized)\n\tbool isAlternativeFormat{}; // if set to true, the OpenGL format is not a bit-perfect match for the GX2 format\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"config/LaunchSettings.h\"\n\nLatteTextureViewGL::LatteTextureViewGL(LatteTextureGL* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount, bool registerView, bool forceCreateNewTexId)\n\t: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format, registerView)\n{\n\tif (dim != texture->dim || format != texture->format ||\n\t\tfirstSlice != 0 || firstMip != 0 || mipCount != texture->mipLevels || sliceCount != texture->depth ||\t\n\t\tforceCreateNewTexId)\n\t{\n\t\tLatteTextureGL::GenerateEmptyTextureFromGX2Dim(dim, glTexId, glTexTarget, false);\n\t\tthis->glInternalFormat = 0;\n\t\tInitAliasView();\n\t}\n\telse\n\t{\n\t\tglTexId = texture->glId_texture;\n\t\tglTexTarget = texture->glTexTarget;\n\t\tglInternalFormat = texture->glInternalFormat;\n\t}\n\t// mark all sampler properties as undefined\n\tsamplerState.maxAniso = 0xFF;\n\tsamplerState.filterMin = 0xFFFFFFFF;\n\tsamplerState.filterMag = 0xFFFFFFFF;\n\tsamplerState.maxMipLevels = 0xFF;\n\tsamplerState.borderType = 0xFF;\n\tsamplerState.borderColor[0] = 9999.0f;\n\tsamplerState.borderColor[1] = 9999.0f;\n\tsamplerState.borderColor[2] = 9999.0f;\n\tsamplerState.borderColor[3] = 9999.0f;\n\tsamplerState.clampS = 0xFF;\n\tsamplerState.clampT = 0xFF;\n\tsamplerState.clampR = 0xFF;\n\tsamplerState.minLod = 0xFFFF;\n\tsamplerState.maxLod = 0xFFFF;\n\tsamplerState.lodBias = 0x7FFF;\n\tsamplerState.depthCompareMode = 0xFF;\n\tsamplerState.depthCompareFunc = 0xFF;\n\tswizzleR = 0xFF;\n\tswizzleG = 0xFF;\n\tswizzleB = 0xFF;\n\tswizzleA = 0xFF;\n}\n\nLatteTextureViewGL::~LatteTextureViewGL()\n{\n\tdelete m_alternativeView;\n\t((OpenGLRenderer*)g_renderer.get())->texture_notifyDelete(this);\n\tglDeleteTextures(1, &glTexId);\n}\n\nvoid LatteTextureViewGL::InitAliasView()\n{\n\tconst auto texture = (LatteTextureGL*)baseTexture;\n\t// compute internal format\n\tif(texture->overwriteInfo.hasFormatOverwrite)\n\t{\n\t\tcemu_assert_debug(format == texture->format);\n\t\tglInternalFormat = texture->glInternalFormat; // for format overwrite no aliasing is allowed and thus we always inherit the internal format of the base texture\n\t}\n\telse if (baseTexture->isDepth)\n\t{\n\t\t// depth is handled differently\n\t\tcemu_assert(format == texture->format); // is depth alias with different format intended?\n\t\tglInternalFormat = texture->glInternalFormat;\n\t}\n\telse\n\t{\n\t\tLatteTextureGL::FormatInfoGL glFormatInfo;\n\t\tLatteTextureGL::GetOpenGLFormatInfo(baseTexture->isDepth, format, dim, &glFormatInfo);\n\t\tglInternalFormat = glFormatInfo.glInternalFormat;\n\t}\n\n\tcatchOpenGLError();\n\tif (firstMip >= texture->maxPossibleMipLevels)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"InitAliasView(): Out of bounds mip level requested\");\n\t\tglTextureView(glTexId, glTexTarget, texture->glId_texture, glInternalFormat, texture->maxPossibleMipLevels - 1, numMip, firstSlice, this->numSlice);\n\t}\n\telse\n\t\tglTextureView(glTexId, glTexTarget, texture->glId_texture, glInternalFormat, firstMip, numMip, firstSlice, numSlice);\n\n\tcatchOpenGLError();\n\n\tif (glTextureParameteri)\n\t{\n\t\tglTextureParameteri(glTexId, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\t\tglTextureParameteri(glTexId, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\t\tglTextureParameteri(glTexId, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n\t\tglTextureParameteri(glTexId, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\t\tglTextureParameteri(glTexId, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);\n\t\tglTextureParameteri(glTexId, GL_TEXTURE_COMPARE_MODE, GL_NONE);\n\t}\n\telse\n\t{\n\t\t// todo - fallback for when DSA isn't supported\n\t}\n\n\t// set debug name\n\tbool useGLDebugNames = false;\n#ifdef CEMU_DEBUG_ASSERT\n\tuseGLDebugNames = true;\n#endif\n\tif (LaunchSettings::NSightModeEnabled())\n\t\tuseGLDebugNames = true;\n\tif (useGLDebugNames)\n\t{\n\t\tchar textureDebugLabel[512];\n\t\tsprintf(textureDebugLabel, \"%08x_f%04x_p%04x_viewFMT%04x%s_org%d\", baseTexture->physAddress, (uint32)baseTexture->format, baseTexture->pitch, (uint32)this->format, baseTexture->isDepth?\"_d\":\"\", texture->glId_texture);\n\t\tglObjectLabel(GL_TEXTURE, glTexId, -1, textureDebugLabel);\n\t}\n}\n\nLatteTextureViewGL* LatteTextureViewGL::GetAlternativeView()\n{\n\tif (!m_alternativeView)\n\t\tm_alternativeView = new LatteTextureViewGL((LatteTextureGL*)baseTexture, dim, format, firstMip, numMip, firstSlice, numSlice, false, true);\n\treturn m_alternativeView;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"Common/GLInclude/GLInclude.h\"\n\nclass LatteTextureViewGL : public LatteTextureView\n{\npublic:\n\tLatteTextureViewGL(class LatteTextureGL* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount, bool registerView = true, bool forceCreateNewTexId = false);\n\t~LatteTextureViewGL();\n\n\tLatteTextureViewGL* GetAlternativeView();\n\n\t// GL specific states\n\tLatteSamplerState samplerState{};\n\tuint8 swizzleR;\n\tuint8 swizzleG;\n\tuint8 swizzleB;\n\tuint8 swizzleA;\n\n\tGLuint glTexId;\n\tGLint glTexTarget;\n\tsint32 glInternalFormat;\n\n\tLatteTextureViewGL* m_alternativeView{ nullptr };\nprivate:\n\tvoid InitAliasView();\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLQuery.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"Common/GLInclude/GLInclude.h\"\n\nclass LatteQueryObjectGL : public LatteQueryObject\n{\n\tfriend class OpenGLRenderer;\n\n\tbool getResult(uint64& numSamplesPassed) override;\n\tvoid begin() override;\n\tvoid end() override;\n\nprivate:\n\tGLuint m_queryId{};\n\tGLenum m_glTarget{};\n};\n\nLatteQueryObject* OpenGLRenderer::occlusionQuery_create()\n{\n\tif (!list_queryCacheOcclusion.empty())\n\t{\n\t\tLatteQueryObjectGL* queryObject = list_queryCacheOcclusion.front();\n\t\tlist_queryCacheOcclusion.erase(list_queryCacheOcclusion.begin() + 0);\n\t\tqueryObject->m_glTarget = GL_SAMPLES_PASSED;\n\t\tqueryObject->queryEnded = false;\n\t\tqueryObject->queryEventStart = 0;\n\t\tqueryObject->queryEventEnd = 0;\n\t\treturn queryObject;\n\t}\n\t// no query object available in cache, create new query\n\tLatteQueryObjectGL* queryObject = new LatteQueryObjectGL();\n\tglGenQueries(1, &queryObject->m_queryId);\n\tqueryObject->m_glTarget = GL_SAMPLES_PASSED;\n\tqueryObject->queryEnded = false;\n\tqueryObject->index = 0;\n\tqueryObject->queryEventStart = 0;\n\tqueryObject->queryEventEnd = 0;\n\tcatchOpenGLError();\n\treturn queryObject;\n}\n\nvoid OpenGLRenderer::occlusionQuery_destroy(LatteQueryObject* queryObj)\n{\n\tlist_queryCacheOcclusion.emplace_back(static_cast<LatteQueryObjectGL*>(queryObj));\n}\n\nvoid OpenGLRenderer::occlusionQuery_flush()\n{\n\tglFlush();\n}\n\nbool LatteQueryObjectGL::getResult(uint64& numSamplesPassed)\n{\n\tGLint resultAvailable = 0;\n\tcatchOpenGLError();\n\tglGetQueryObjectiv(this->m_queryId, GL_QUERY_RESULT_AVAILABLE, &resultAvailable);\n\tif (resultAvailable == 0)\n\t\treturn false;\n\tcatchOpenGLError();\n\tGLint64 queryResult = 0;\n\tglGetQueryObjecti64v(this->m_queryId, GL_QUERY_RESULT, &queryResult);\n\tnumSamplesPassed = queryResult;\n\treturn true;\n}\n\nvoid LatteQueryObjectGL::begin()\n{\n\tcatchOpenGLError();\n\tglBeginQueryIndexed(this->m_glTarget, this->index, this->m_queryId);\n\tcatchOpenGLError();\n}\n\nvoid LatteQueryObjectGL::end()\n{\n\tglEndQueryIndexed(this->m_glTarget, this->index);\n\tcatchOpenGLError();\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"WindowSystem.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteRingBuffer.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteOverlay.h\"\n\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/CachedFBOGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLTextureReadback.h\"\n\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n\n#include \"imgui/imgui_impl_opengl3.h\"\n#include \"imgui/imgui_extension.h\"\n\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n\nclass DefaultOpenGLCanvasCallbacks : public OpenGLCanvasCallbacks\n{\n} g_defaultOpenGLCanvasCallbacks;\n\nOpenGLCanvasCallbacks* g_openGLCanvasCallbacks = &g_defaultOpenGLCanvasCallbacks;\n\nvoid SetOpenGLCanvasCallbacks(OpenGLCanvasCallbacks* callbacks)\n{\n\tcemu_assert_debug(g_openGLCanvasCallbacks == &g_defaultOpenGLCanvasCallbacks);\n\tg_openGLCanvasCallbacks = callbacks;\n}\n\nvoid ClearOpenGLCanvasCallbacks()\n{\n\tcemu_assert_debug(g_openGLCanvasCallbacks != &g_defaultOpenGLCanvasCallbacks);\n\tg_openGLCanvasCallbacks = &g_defaultOpenGLCanvasCallbacks;\n}\n\nbool GLCanvas_HasPadViewOpen()\n{\n\treturn g_openGLCanvasCallbacks->HasPadViewOpen();\n}\n\nbool GLCanvas_MakeCurrent(bool padView)\n{\n\treturn g_openGLCanvasCallbacks->MakeCurrent(padView);\n}\n\nvoid GLCanvas_SwapBuffers(bool swapTV, bool swapDRC)\n{\n\tg_openGLCanvasCallbacks->SwapBuffers(swapTV, swapDRC);\n}\n\n#define STRINGIFY2(X) #X\n#define STRINGIFY(X) STRINGIFY2(X)\n\nnamespace CemuGL\n{\n#define GLFUNC(__type, __name)\t__type __name;\n#define EGLFUNC(__type, __name)\t__type __name;\n#include \"Common/GLInclude/glFunctions.h\"\n#undef GLFUNC\n#undef EGLFUNC\n}\n\n#include \"config/ActiveSettings.h\"\n#include \"config/LaunchSettings.h\"\n\nstatic const int TEXBUFFER_SIZE = 1024 * 1024 * 32; // 32MB\n\nstruct\n{\n\t// options\n\tbool useTextureUploadBuffer;\n\t// texture upload\n\tGLuint uploadBuffer;\n\tsint32 uploadIndex;\n\tvoid* uploadBufferPtr;\n\tLatteRingBuffer_t* uploadRingBuffer;\n\t// current texture work buffer (subrange of uploadRingBuffer)\n\tuint8* texWorkBuffer;\n\tsint32 texWorkBufferSize;\n\t// texture upload buffer (when not using persistent buffer)\n\tstd::vector<uint8> texUploadBuffer;\n\t// FBO for fast clearing (on Nvidia or if glClearTexSubImage is not supported)\n\tGLuint clearFBO;\n}glRendererState;\n\nstatic const GLenum glDepthFuncTable[] =\n{\n\tGL_NEVER,\n\tGL_LESS,\n\tGL_EQUAL,\n\tGL_LEQUAL,\n\tGL_GREATER,\n\tGL_NOTEQUAL,\n\tGL_GEQUAL,\n\tGL_ALWAYS\n};\n\nstatic const GLenum glAlphaTestFunc[] =\n{\n\tGL_NEVER,\n\tGL_LESS,\n\tGL_EQUAL,\n\tGL_LEQUAL,\n\tGL_GREATER,\n\tGL_NOTEQUAL,\n\tGL_GEQUAL,\n\tGL_ALWAYS\n};\n\nOpenGLRenderer::OpenGLRenderer()\n{\n\tglRendererState.useTextureUploadBuffer = false;\n\tif (glRendererState.useTextureUploadBuffer)\n\t{\n\t\tglCreateBuffers(1, &glRendererState.uploadBuffer);\n\t\tglNamedBufferStorage(glRendererState.uploadBuffer, TEXBUFFER_SIZE, nullptr, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);\n\t\tvoid* buffer = glMapNamedBufferRange(glRendererState.uploadBuffer, 0, TEXBUFFER_SIZE, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);\n\t\tif (buffer == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to allocate GL texture upload buffer. Using traditional API instead\");\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\tglRendererState.uploadBufferPtr = buffer;\n\t\tglRendererState.uploadRingBuffer = LatteRingBuffer_create((uint8*)buffer, TEXBUFFER_SIZE);\n\t\tglRendererState.uploadIndex = 0;\n\t}\n\n#if BOOST_OS_WINDOWS\n\ttry\n\t{\n\t\tm_dxgi_wrapper = std::make_unique<DXGIWrapper>();\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Unable to create dxgi wrapper: {} (VRAM overlay stat won't be available)\", ex.what());\n\t}\n#endif\n}\n\nOpenGLRenderer::~OpenGLRenderer()\n{\n\tif(m_pipeline != 0)\n\t\tglDeleteProgramPipelines(1, &m_pipeline);\n\n\tglDeleteBuffers(1, &m_backbufferBlit_uniformBuffer);\n}\n\nOpenGLRenderer* OpenGLRenderer::GetInstance()\n{\n\tcemu_assert_debug(g_renderer && dynamic_cast<OpenGLRenderer*>(g_renderer.get()));\n\treturn (OpenGLRenderer*)g_renderer.get();\n}\n\nbool OpenGLRenderer::ImguiBegin(bool mainWindow)\n{\n\tif (!mainWindow)\n\t{\n\t\tGLCanvas_MakeCurrent(true);\n\t\tm_isPadViewContext = true;\n\t}\n\n\tif(!Renderer::ImguiBegin(mainWindow))\n\t\treturn false;\n\t\n\trenderstate_resetColorControl();\n\trenderstate_resetDepthControl();\n\trenderstate_resetStencilMask();\n\n\tif (glClipControl)\n\t\tglClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);\n\n\tImGui_ImplOpenGL3_NewFrame();\n\tImGui_UpdateWindowInformation(mainWindow);\n\tImGui::NewFrame();\n\treturn true;\n}\n\nvoid OpenGLRenderer::ImguiEnd()\n{\n\tImGui::Render();\n\tImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());\n\n\tif (m_isPadViewContext)\n\t{\n\t\tGLCanvas_MakeCurrent(false);\n\t\tm_isPadViewContext = false;\n\t}\n\n\tif (glClipControl)\n\t\tglClipControl(GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE);\n}\n\nImTextureID OpenGLRenderer::GenerateTexture(const std::vector<uint8>& data, const Vector2i& size)\n{\n\tGLuint textureId;\n\tglGenTextures(1, &textureId);\n\n\tglBindTexture(GL_TEXTURE_2D, textureId);\n\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);\n\n\tglActiveTexture(GL_TEXTURE0);\n\tglTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB, size.x, size.y, 0, GL_RGB, GL_UNSIGNED_BYTE, data.data());\n\treturn (ImTextureID)(uintptr_t)textureId;\n}\n\nvoid OpenGLRenderer::DeleteTexture(ImTextureID id)\n{\n\tif (id)\n\t{\n\t\tGLuint textureId = (GLuint)(uintptr_t)id;\n\t\tglDeleteTextures(1, &textureId);\n\t}\n}\n\nvoid OpenGLRenderer::DeleteFontTextures()\n{\n\tImGui_ImplOpenGL3_DestroyFontsTexture();\n}\n\ntypedef void(*GL_IMPORT)();\n\n#if BOOST_OS_WINDOWS\nGL_IMPORT _GetOpenGLFunction(HMODULE hLib, const char* name)\n{\n\tGL_IMPORT r = (GL_IMPORT)wglGetProcAddress(name);\n\tif (r == nullptr)\n\t\tr = (GL_IMPORT)GetProcAddress(hLib, name);\n\treturn r;\n}\n\nvoid LoadOpenGLImports()\n{\n\tHMODULE hLib = LoadLibraryA(\"opengl32.dll\");\n#define GLFUNC(__type, __name)\t__name = (__type)_GetOpenGLFunction(hLib, STRINGIFY(__name));\n#include \"Common/GLInclude/glFunctions.h\"\n#undef GLFUNC\n}\n#elif BOOST_OS_LINUX || BOOST_OS_BSD\nGL_IMPORT _GetOpenGLFunction(void* hLib, PFNGLXGETPROCADDRESSPROC func, const char* name)\n{\n\tGL_IMPORT r = (GL_IMPORT)func((const GLubyte*)name);\n\treturn r;\n}\n\n#include <dlfcn.h>\n// #define RTLD_NOW        \t0x00002\n// #define RTLD_GLOBAL        \t0x00100\n\nvoid LoadOpenGLImports()\n{\n\tPFNGLXGETPROCADDRESSPROC _glXGetProcAddress = nullptr;\n\tvoid* libGL = dlopen(\"libGL.so.1\", RTLD_NOW | RTLD_GLOBAL);\n\t_glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)dlsym(libGL, \"glXGetProcAddressARB\");\n\tif(!_glXGetProcAddress)\n\t{\n\t\tlibGL = dlopen(\"libGL.so\", RTLD_NOW | RTLD_GLOBAL);\n\t\t_glXGetProcAddress = (PFNGLXGETPROCADDRESSPROC)dlsym(libGL, \"glXGetProcAddressARB\");\n\t}\n\n\tvoid* libEGL = dlopen(\"libEGL.so.1\", RTLD_NOW | RTLD_GLOBAL);\n\tif(!libEGL)\n\t{\n\t\tlibGL = dlopen(\"libEGL.so\", RTLD_NOW | RTLD_GLOBAL);\n\t}\n\n#define GLFUNC(__type, __name)\t__name = (__type)_GetOpenGLFunction(libGL, _glXGetProcAddress, STRINGIFY(__name));\n#define EGLFUNC(__type, __name)\t__name = (__type)dlsym(libEGL, STRINGIFY(__name));\n#include \"Common/GLInclude/glFunctions.h\"\n#undef GLFUNC\n#undef EGLFUNC\n}\n\n#if BOOST_OS_LINUX || BOOST_OS_BSD\n// dummy function for all code that is statically linked with cemu and attempts to use eglSwapInterval\n// used to suppress wxWidgets calls to eglSwapInterval\nextern \"C\"\nEGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval)\n{\n\treturn EGL_TRUE;\n}\n#endif\n\n#elif BOOST_OS_MACOS\nvoid LoadOpenGLImports()\n{\n\tcemu_assert_unimplemented();\n}\n#endif\n\nvoid OpenGLRenderer::Initialize()\n{\n\tRenderer::Initialize();\n\tauto lock = cemuLog_acquire();\n\tcemuLog_log(LogType::Force, \"------- Init OpenGL graphics backend -------\");\n\n\tGLCanvas_MakeCurrent(false);\n\tLoadOpenGLImports();\n\tGetVendorInformation();\t\n\n#if BOOST_OS_WINDOWS\n\tif (wglSwapIntervalEXT)\n\t\twglSwapIntervalEXT(0); // disable V-Sync per default\n#endif\n\n\tif (glMaxShaderCompilerThreadsARB)\n\t\tglMaxShaderCompilerThreadsARB(0xFFFFFFFF);\n\n\tcemuLog_log(LogType::Force, \"OpenGL extensions:\");\n\tcemuLog_log(LogType::Force, \"ARB_clip_control: {}\", glClipControl ? \"available\" : \"not supported\");\n\tcemuLog_log(LogType::Force, \"ARB_get_program_binary: {}\", (glGetProgramBinary != NULL && glProgramBinary != NULL) ? \"available\" : \"not supported\");\n\tcemuLog_log(LogType::Force, \"ARB_clear_texture: {}\", (glClearTexImage != NULL) ? \"available\" : \"not supported\");\n\tcemuLog_log(LogType::Force, \"ARB_copy_image: {}\", (glCopyImageSubData != NULL) ? \"available\" : \"not supported\");\n\tcemuLog_log(LogType::Force, \"NV_depth_buffer_float: {}\", (glDepthRangedNV != NULL) ? \"available\" : \"not supported\");\n\n\t// enable framebuffer SRGB support\n\tglEnable(GL_FRAMEBUFFER_SRGB);\n\n\tif (this->m_vendor != GfxVendor::AMD)\n\t{\n\t\t// don't enable this for AMD because GL_PROGRAM_POINT_SIZE breaks shader binaries for some reason\n\t\t// it also seems like AMD ignores GL_POINT_SPRITE and gl_PointCoord is always 0.0/0.0\n\n\t\t// point size is always defined via shader\n\t\tglEnable(GL_PROGRAM_POINT_SIZE);\n\n\t\t// since we are using compatibility profile point sprites are disabled by default (e.g. gl_PointCoord wont work)\n\t\tglEnable(GL_POINT_SPRITE);\n\t}\n\n\t// check if clip control is available\n\tif (glClipControl)\n\t{\n\t\tglClipControl(GL_UPPER_LEFT, GL_NEGATIVE_ONE_TO_ONE);\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"ARB_CLIP_CONTROL not supported by graphics driver. This will lead to crashes or graphical artifacts.\");\n\t}\n\n\t// set pixel unpack alignment to 1 byte\n\tglPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n\n\t// on NVIDIA rendering to SNORM textures is clamped to [0.0,1.0] range for non-core profiles\n\t// we can still disable the clamping using an older function (note that AMD and Intel don't need this, which is technically incorrect according to the compatibility profile spec)\n\tif (m_vendor == GfxVendor::Nvidia)\n\t\tglClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);\n\n\n\tglEnable(GL_PRIMITIVE_RESTART);\n\tglPrimitiveRestartIndex(0xFFFFFFFF);\n\n\tglGenProgramPipelines(1, &m_pipeline);\n\tglBindProgramPipeline(m_pipeline);\n\n\tlock.unlock();\n\n\t// create framebuffer for fast clearing (avoid glClearTexSubImage on Nvidia)\n\tif (glCreateFramebuffers)\n\t\tglCreateFramebuffers(1, &glRendererState.clearFBO);\n\telse\n\t{\n\t\tglGenFramebuffers(1, &glRendererState.clearFBO);\n\t\t// bind to initialize\n\t\tglBindFramebuffer(GL_FRAMEBUFFER_EXT, glRendererState.clearFBO);\n\t\tglBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);\n\t}\n\n\t// create uniform buffers for backbufferblit\n\tglCreateBuffers(1, &m_backbufferBlit_uniformBuffer);\n\tglNamedBufferStorage(m_backbufferBlit_uniformBuffer, sizeof(RendererOutputShader::OutputUniformVariables), nullptr, GL_DYNAMIC_STORAGE_BIT);\n\n\tdraw_init();\n\n\tcatchOpenGLError();\n\n\tglGenBuffers(1, &glStreamoutCacheRingBuffer);\n\tglBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, glStreamoutCacheRingBuffer);\n\tglBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, LatteStreamout_GetRingBufferSize(), NULL, GL_DYNAMIC_DRAW);\n\tglBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);\n\n\tcatchOpenGLError();\n\n\t// imgui\n\tImGui_ImplOpenGL3_Init(\"#version 130\");\n}\n\nbool OpenGLRenderer::IsPadWindowActive()\n{\n\treturn GLCanvas_HasPadViewOpen();\n}\n\nvoid OpenGLRenderer::Flush(bool waitIdle)\n{\n\tglFlush();\n\tif (waitIdle)\n\t\tglFinish();\n}\n\nvoid OpenGLRenderer::NotifyLatteCommandProcessorIdle()\n{\n\tglFlush();\n}\n\nvoid OpenGLRenderer::GetVendorInformation()\n{\n\t// example vendor strings:\n\t// ATI Technologies Inc.\n\t// NVIDIA Corporation \n\t// Intel\n\tchar* glVendorString = (char*)glGetString(GL_VENDOR);\n\tchar* glRendererString = (char*)glGetString(GL_RENDERER);\n\tchar* glVersionString = (char*)glGetString(GL_VERSION);\n\n\tcemuLog_log(LogType::Force, \"GL_VENDOR: {}\", glVendorString ? glVendorString : \"unknown\");\n\tcemuLog_log(LogType::Force, \"GL_RENDERER: {}\", glRendererString ? glRendererString : \"unknown\");\n\tcemuLog_log(LogType::Force, \"GL_VERSION: {}\", glVersionString ? glVersionString : \"unknown\");\n\n\tif(glVersionString && boost::icontains(glVersionString, \"Mesa\"))\n\t{\n\t\tm_vendor = GfxVendor::Mesa;\n\t\treturn;\n\t}\n\n\tif (glVendorString)\n\t{\n\t\tif ((toupper(glVendorString[0]) == 'A' && toupper(glVendorString[1]) == 'T' && toupper(glVendorString[2]) == 'I') ||\n\t\t\t(toupper(glVendorString[0]) == 'A' && toupper(glVendorString[1]) == 'M' && toupper(glVendorString[2]) == 'D'))\n\t\t{\n\t\t\tm_vendor = GfxVendor::AMD;\n\t\t\treturn;\n\t\t}\n\t\telse if (memcmp(glVendorString, \"NVIDIA\", 6) == 0)\n\t\t{\n\t\t\tm_vendor = GfxVendor::Nvidia;\n\t\t\treturn;\n\t\t}\n\t\telse if (memcmp(glVendorString, \"Intel\", 5) == 0)\n\t\t{\n\t\t\tm_vendor = GfxVendor::Intel;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tm_vendor = GfxVendor::Generic;\n}\n\nvoid _glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam)\n{\n\tif (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, \"Buffer\"))\n\t\treturn;\n\tif (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, \"performance warning\"))\n\t\treturn;\n\tif (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, \"Dithering is enabled\"))\n\t\treturn;\n\tif (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, \"Blending is enabled, but is not supported for integer framebuffers\"))\n\t\treturn;\n\tif (LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, \"does not have a defined base level\"))\n\t\treturn;\n\tif(LatteGPUState.glVendor == GLVENDOR_NVIDIA && strstr(message, \"has depth comparisons disabled, with a texture object\"))\n\t\treturn;\n\n\tcemuLog_log(LogType::Force, \"GLDEBUG: {}\", message);\n\n\tcemu_assert_debug(false);\n}\n\nvoid OpenGLRenderer::EnableDebugMode()\n{\n\tglEnable(GL_DEBUG_OUTPUT);\n\tglEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);\n\tglDebugMessageCallback(_glDebugCallback, NULL);\n\tglDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, true);\n}\n\nvoid OpenGLRenderer::SwapBuffers(bool swapTV, bool swapDRC)\n{\n\tGLCanvas_SwapBuffers(swapTV, swapDRC);\n\n\tif (swapTV)\n\t\tcleanupAfterFrame();\n}\n\nbool OpenGLRenderer::BeginFrame(bool mainWindow)\n{\n\tif (!mainWindow && !IsPadWindowActive())\n\t\treturn false;\n\n\tGLCanvas_MakeCurrent(!mainWindow);\n\n\tClearColorbuffer(!mainWindow);\n\treturn true;\n}\n\nvoid OpenGLRenderer::DrawEmptyFrame(bool mainWindow)\n{\n\tif (!BeginFrame(mainWindow))\n\t\treturn;\n\t\n\tSwapBuffers(mainWindow, !mainWindow);\n}\n\nvoid OpenGLRenderer::ClearColorbuffer(bool padView)\n{\n\tglClearColor(0.0f, 0.0f, 0.0f, 0.0f);\n\tglClear(GL_COLOR_BUFFER_BIT);\n}\n\n\nvoid OpenGLRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool padView)\n{\n\tif(!m_screenshot_requested && m_screenshot_state == ScreenshotState::None)\n\t\treturn;\n\n\tif (IsPadWindowActive())\n\t{\n\t\t// we already took a pad view screenshow and want a main window screenshot\n\t\tif (m_screenshot_state == ScreenshotState::Main && padView)\n\t\t\treturn;\n\n\t\tif (m_screenshot_state == ScreenshotState::Pad && !padView)\n\t\t\treturn;\n\n\t\t// remember which screenshot is left to take\n\t\tif (m_screenshot_state == ScreenshotState::None)\n\t\t\tm_screenshot_state = padView ? ScreenshotState::Main : ScreenshotState::Pad;\n\t\telse\n\t\t\tm_screenshot_state = ScreenshotState::None;\n\t}\n\telse\n\t\tm_screenshot_state = ScreenshotState::None;\n\n\tint screenshotWidth, screenshotHeight;\n\tglBindBuffer(GL_PIXEL_PACK_BUFFER, 0);\n\ttexture_bindAndActivate(texView, 0);\n\tglGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &screenshotWidth);\n\tglGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &screenshotHeight);\n\tglPixelStorei(GL_PACK_ALIGNMENT, 1); // set alignment to 1\n\n\tconst sint32 pixelDataSize = screenshotWidth * screenshotHeight * 3;\n\tstd::vector<uint8> rgb_data(pixelDataSize);\n\n\tglGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, rgb_data.data());\n\ttexture_bindAndActivate(nullptr, 0);\n\t\n\tconst bool srcUsesSRGB = HAS_FLAG(texView->format, Latte::E_GX2SURFFMT::FMT_BIT_SRGB);\n\tconst bool dstUsesSRGB = (!padView && LatteGPUState.tvBufferUsesSRGB) || (padView && LatteGPUState.drcBufferUsesSRGB);\n\tif((srcUsesSRGB && !dstUsesSRGB) || (!srcUsesSRGB && dstUsesSRGB))\n\t{\n\t\tfor (sint32 iy = 0; iy < screenshotHeight; ++iy)\n\t\t{\n\t\t\tfor (sint32 ix = 0; ix < screenshotWidth; ++ix)\n\t\t\t{\n\t\t\t\tuint8* pData = rgb_data.data() + (ix + iy * screenshotWidth) * 3;\n\t\t\t\tif (srcUsesSRGB && !dstUsesSRGB)\n\t\t\t\t{\n\t\t\t\t\t// SRGB -> RGB\n\t\t\t\t\tpData[0] = SRGBComponentToRGB(pData[0]);\n\t\t\t\t\tpData[1] = SRGBComponentToRGB(pData[1]);\n\t\t\t\t\tpData[2] = SRGBComponentToRGB(pData[2]);\n\t\t\t\t}\n\t\t\t\telse if (!srcUsesSRGB && dstUsesSRGB)\n\t\t\t\t{\n\t\t\t\t\t// RGB -> SRGB\n\t\t\t\t\tpData[0] = RGBComponentToSRGB(pData[0]);\n\t\t\t\t\tpData[1] = RGBComponentToSRGB(pData[1]);\n\t\t\t\t\tpData[2] = RGBComponentToSRGB(pData[2]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tSaveScreenshot(rgb_data, screenshotWidth, screenshotHeight, !padView);\n}\n\nvoid OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight, bool padView, bool clearBackground)\n{\n\tif (padView && !IsPadWindowActive())\n\t\treturn;\n\n\tcatchOpenGLError();\n\tGLCanvas_MakeCurrent(padView);\n\n\trenderstate_resetColorControl();\n\trenderstate_resetDepthControl();\n\tattributeStream_reset();\n\n\t// bind back buffer\n\trendertarget_bindFramebufferObject(nullptr);\n\n\tif (clearBackground)\n\t{\n\t\tint windowWidth, windowHeight;\n\t\tif (padView)\n\t\t\tWindowSystem::GetPadWindowPhysSize(windowWidth, windowHeight);\n\t\telse\n\t\t\tWindowSystem::GetWindowPhysSize(windowWidth, windowHeight);\n\t\tg_renderer->renderTarget_setViewport(0, 0, windowWidth, windowHeight, 0.0f, 1.0f);\n\t\tg_renderer->ClearColorbuffer(padView);\n\t}\n\n\tshader_unbind(RendererShader::ShaderType::kGeometry);\n\tshader_bind(shader->GetVertexShader());\n\tshader_bind(shader->GetFragmentShader());\n\n\t// update and bind uniform buffer\n\tauto uniformBuffer = shader->FillUniformBlockBuffer(*texView, {imageWidth, imageHeight}, padView);\n\tglNamedBufferSubData(m_backbufferBlit_uniformBuffer, 0, sizeof(uniformBuffer), &uniformBuffer);\n\n\tglBindBufferBase(GL_UNIFORM_BUFFER, 0, m_backbufferBlit_uniformBuffer);\n\n\t// set viewport\n\tglViewportIndexedf(0, imageX, imageY, imageWidth, imageHeight);\n\n\tLatteTextureViewGL* texViewGL = (LatteTextureViewGL*)texView;\n\ttexture_bindAndActivate(texView, 0);\n\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n\ttexViewGL->samplerState.clampS = texViewGL->samplerState.clampT = 0xFF;\n\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, useLinearTexFilter ? GL_LINEAR : GL_NEAREST);\n\ttexViewGL->samplerState.filterMin = 0xFFFFFFFF;\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, useLinearTexFilter ? GL_LINEAR : GL_NEAREST);\n\ttexViewGL->samplerState.filterMag = 0xFFFFFFFF;\n\n\tglDisable(GL_FRAMEBUFFER_SRGB);\n\n\tuint16 indexData[6] = { 0,1,2,3,4,5 };\n\tglDrawRangeElements(GL_TRIANGLES, 0, 5, 6, GL_UNSIGNED_SHORT, indexData);\n\n\tglEnable(GL_FRAMEBUFFER_SRGB);\n\n\t// unbind texture\n\ttexture_bindAndActivate(nullptr, 0);\n\n\tcatchOpenGLError();\n\n\t// restore viewport\n\tglViewportIndexedf(0, prevViewportX, prevViewportY, prevViewportWidth, prevViewportHeight);\n\n\t// switch back to TV context\n\tif (padView)\n\t\tGLCanvas_MakeCurrent(false);\n}\n\nvoid OpenGLRenderer::renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ /*= false*/)\n{\n\tif (prevNearZ != nearZ || prevFarZ != farZ || _prevHalfZ != halfZ)\n\t{\n\t\tif (*(uint32*)&farZ == 0x3f7fffff)\n\t\t\t*(uint32*)&farZ = 0x3f800000;\n\t\tif (glDepthRangedNV)\n\t\t\tglDepthRangedNV(nearZ, farZ);\n\t\telse\n\t\t\tglDepthRange(nearZ, farZ);\n\t\tprevNearZ = nearZ;\n\t\tprevFarZ = farZ;\n\t}\n\n\tbool invertY = false;\n\tif (height < 0.0)\n\t{\n\t\tinvertY = true;\n\t\ty += height;\n\t\theight = -height;\n\t}\n\n\tif (glClipControl && (_prevInvertY != invertY || _prevHalfZ != halfZ))\n\t{\n\t\tGLenum clipDepth = halfZ ? GL_ZERO_TO_ONE : GL_NEGATIVE_ONE_TO_ONE;\n\t\tif (invertY)\n\t\t\tglClipControl(GL_LOWER_LEFT, clipDepth); // OpenGL style\n\t\telse\n\t\t\tglClipControl(GL_UPPER_LEFT, clipDepth); // DX style (default for GX2)\n\t\t_prevInvertY = invertY;\n\t\t_prevHalfZ = halfZ;\n\t}\n\n\tif (prevViewportX == x && prevViewportY == y && prevViewportWidth == width && prevViewportHeight == height)\n\t\treturn; // viewport did not change\n\tglViewportIndexedf(0, x, y, width, height);\n\tprevViewportX = x;\n\tprevViewportY = y;\n\tprevViewportWidth = width;\n\tprevViewportHeight = height;\n}\n\nvoid OpenGLRenderer::renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight)\n{\n\tif (prevScissorEnable != true)\n\t{\n\t\t// enable scissor box\n\t\tglEnable(GL_SCISSOR_TEST);\n\t\tprevScissorEnable = true;\n\t}\n\tglScissor(scissorX, scissorY, scissorWidth, scissorHeight);\n}\n\nLatteCachedFBO* OpenGLRenderer::rendertarget_createCachedFBO(uint64 key)\n{\n\treturn new CachedFBOGL(key);\n}\n\nvoid OpenGLRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* cfbo)\n{\n\tauto cfboGL = (CachedFBOGL*)cfbo;\n\tif (prevBoundFBO == cfboGL->glId_fbo)\n\t{\n\t\tglBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);\n\t\tprevBoundFBO = 0;\n\t}\n\tglDeleteFramebuffers(1, &cfboGL->glId_fbo);\n}\n\n// set active FBO\nvoid OpenGLRenderer::rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo)\n{\n\tGLuint fboid;\n\tif (cfbo)\n\t{\n\t\tconst auto cfboGL = (CachedFBOGL*)cfbo;\n\t\tfboid = cfboGL->glId_fbo;\n\t}\n\telse\n\t\tfboid = 0;\n\n\tif (prevBoundFBO != fboid)\n\t{\n\t\tglBindFramebuffer(GL_FRAMEBUFFER_EXT, fboid);\n\t\tprevBoundFBO = fboid;\n\t}\n}\n\nvoid OpenGLRenderer::renderstate_setChannelTargetMask(uint32 renderTargetMask)\n{\n\tif (renderTargetMask != prevTargetColorMask)\n\t{\n\t\tfor (sint32 i = 0; i < 8; i++)\n\t\t{\n\t\t\tuint32 targetRGBAMask = ((renderTargetMask >> (i * 4)) & 0xF);\n\t\t\tif (targetRGBAMask != ((prevTargetColorMask >> (i * 4)) & 0xF))\n\t\t\t{\n\t\t\t\t// update color mask\n\t\t\t\tglColorMaski(i, (targetRGBAMask & 1) ? GL_TRUE : GL_FALSE, (targetRGBAMask & 2) ? GL_TRUE : GL_FALSE, (targetRGBAMask & 4) ? GL_TRUE : GL_FALSE, (targetRGBAMask & 8) ? GL_TRUE : GL_FALSE);\n\t\t\t}\n\t\t}\n\t\tprevTargetColorMask = renderTargetMask;\n\t}\n}\n\nvoid OpenGLRenderer::renderstate_setAlwaysWriteDepth()\n{\n\tif (prevDepthEnable == 0)\n\t{\n\t\tglEnable(GL_DEPTH_TEST);\n\t\tprevDepthEnable = 1;\n\t}\n\tglDepthFunc(GL_ALWAYS);\n\tprevDepthFunc = Latte::LATTE_DB_DEPTH_CONTROL::E_ZFUNC::ALWAYS;\n}\n\nstatic const GLuint table_glBlendSrcDst[] =\n{\n\t/* 0x00 */ GL_ZERO,\n\t/* 0x01 */ GL_ONE,\n\t/* 0x02 */ GL_SRC_COLOR,\n\t/* 0x03 */ GL_ONE_MINUS_SRC_COLOR,\n\t/* 0x04 */ GL_SRC_ALPHA,\n\t/* 0x05 */ GL_ONE_MINUS_SRC_ALPHA,\n\t/* 0x06 */ GL_DST_ALPHA,\n\t/* 0x07 */ GL_ONE_MINUS_DST_ALPHA,\n\t/* 0x08 */ GL_DST_COLOR,\n\t/* 0x09 */ GL_ONE_MINUS_DST_COLOR,\n\t/* 0x0A */ GL_SRC_ALPHA_SATURATE,\n\t/* 0x0B */ 0xFFFFFFFF,\n\t/* 0x0C */ 0xFFFFFFFF,\n\t/* 0x0D */ GL_CONSTANT_COLOR,\n\t/* 0x0E */ GL_ONE_MINUS_CONSTANT_COLOR,\n\t/* 0x0F */ GL_SRC1_COLOR,\n\t/* 0x10 */ GL_ONE_MINUS_SRC1_COLOR,\n\t/* 0x11 */ GL_SRC1_ALPHA,\n\t/* 0x12 */ GL_ONE_MINUS_SRC1_ALPHA,\n\t/* 0x13 */ GL_CONSTANT_ALPHA,\n\t/* 0x14 */ GL_ONE_MINUS_CONSTANT_ALPHA\n};\n\nstatic GLuint GetGLBlendFactor(Latte::LATTE_CB_BLENDN_CONTROL::E_BLENDFACTOR blendFactor)\n{\n\tuint32 blendFactorU = (uint32)blendFactor;\n\tif (blendFactorU >= 0xF && blendFactorU <= 0x12)\n\t{\n\t\tdebug_printf(\"Unsupported dual-source blending used\\n\");\n\t\tcemu_assert_debug(false); // dual-source blending\n\t\treturn GL_ZERO;\n\t}\n\tif (blendFactorU >= (sizeof(table_glBlendSrcDst) / sizeof(table_glBlendSrcDst[0])))\n\t{\n\t\tdebug_printf(\"GetGLBlendFactor: Constant 0x%x out of range\\n\", blendFactor);\n\t\treturn GL_ZERO;\n\t}\n\tif (table_glBlendSrcDst[blendFactorU] == -1)\n\t{\n\t\tdebug_printf(\"GetGLBlendFactor: Constant 0x%x is invalid\\n\", blendFactor);\n\t\tcemu_assert_debug(false);\n\t\treturn GL_ZERO;\n\t}\n\treturn table_glBlendSrcDst[blendFactorU];\n}\n\nstatic const GLuint table_glBlendCombine[] =\n{\n\tGL_FUNC_ADD,\n\tGL_FUNC_SUBTRACT,\n\tGL_MIN,\n\tGL_MAX,\n\tGL_FUNC_REVERSE_SUBTRACT\n};\n\nGLuint GetGLBlendCombineFunc(Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC combineFunc)\n{\n\tuint32 combineFuncU = (uint32)combineFunc;\n\tif (combineFuncU >= (sizeof(table_glBlendCombine) / sizeof(table_glBlendCombine[0])))\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn GL_FUNC_ADD;\n\t}\n\treturn table_glBlendCombine[combineFuncU];\n}\n\n\nvoid* OpenGLRenderer::texture_acquireTextureUploadBuffer(uint32 size)\n{\n\tif (glRendererState.useTextureUploadBuffer)\n\t{\n\t\tglRendererState.texWorkBuffer = LatteRingBuffer_allocate(glRendererState.uploadRingBuffer, size, 1024);\n\t\tglRendererState.texWorkBufferSize = size;\n\t\treturn glRendererState.texWorkBuffer;\n\t}\n\t// static memory buffer\n\tif (glRendererState.texUploadBuffer.size() < size)\n\t{\n\t\tglRendererState.texUploadBuffer.resize(size);\n\t}\n\treturn glRendererState.texUploadBuffer.data();\n}\n\nvoid OpenGLRenderer::texture_releaseTextureUploadBuffer(uint8* mem)\n{\n\t// do nothing\n}\n\nTextureDecoder* OpenGLRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height)\n{\n\tTextureDecoder* texDecoder = nullptr;\n\tif (isDepth)\n\t{\n\t\tif (format == Latte::E_GX2SURFFMT::R32_FLOAT)\n\t\t{\n\t\t\treturn TextureDecoder_R32_FLOAT::getInstance();\n\t\t}\n\t\tif (format == Latte::E_GX2SURFFMT::D24_S8_UNORM)\n\t\t{\n\t\t\treturn TextureDecoder_D24_S8::getInstance();\n\t\t}\n\t\telse if (format == Latte::E_GX2SURFFMT::D24_S8_FLOAT)\n\t\t{\n\t\t\treturn TextureDecoder_NullData64::getInstance();\n\t\t}\n\t\telse if (format == Latte::E_GX2SURFFMT::D32_S8_FLOAT)\n\t\t{\n\t\t\treturn TextureDecoder_D32_S8_UINT_X24::getInstance();\n\t\t}\n\t\telse if (format == Latte::E_GX2SURFFMT::R32_FLOAT)\n\t\t{\n\t\t\treturn TextureDecoder_R32_FLOAT::getInstance();\n\t\t}\n\t\telse if (format == Latte::E_GX2SURFFMT::R16_UNORM)\n\t\t{\n\t\t\treturn TextureDecoder_R16_FLOAT::getInstance();\n\t\t}\n\t\treturn nullptr;\n\t}\n\tif (format == Latte::E_GX2SURFFMT::R4_G4_UNORM)\n\t\ttexDecoder = TextureDecoder_R4_G4_UNORM_To_RGBA4::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM)\n\t\ttexDecoder = TextureDecoder_R4_G4_B4_A4_UNORM::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT)\n\t\ttexDecoder = TextureDecoder_R16_G16_B16_A16_FLOAT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_FLOAT)\n\t\ttexDecoder = TextureDecoder_R16_G16_FLOAT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R16_SNORM)\n\t\ttexDecoder = TextureDecoder_R16_SNORM::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R16_FLOAT)\n\t\ttexDecoder = TextureDecoder_R16_FLOAT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R32_FLOAT)\n\t\ttexDecoder = TextureDecoder_R32_FLOAT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::BC1_UNORM)\n\t\ttexDecoder = TextureDecoder_BC1::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::BC1_SRGB)\n\t\ttexDecoder = TextureDecoder_BC1::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::BC2_UNORM)\n\t\ttexDecoder = TextureDecoder_BC2_UNORM_uncompress::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::BC2_SRGB)\n\t\ttexDecoder = TextureDecoder_BC2_SRGB_uncompress::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::BC3_UNORM)\n\t\ttexDecoder = TextureDecoder_BC3::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::BC3_SRGB)\n\t\ttexDecoder = TextureDecoder_BC3::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::BC4_UNORM)\n\t{\n\t\tif (dim != Latte::E_DIM::DIM_2D && dim != Latte::E_DIM::DIM_2D_ARRAY)\n\t\t\ttexDecoder = TextureDecoder_BC4_UNORM_uncompress::getInstance();\n\t\telse\n\t\t\ttexDecoder = TextureDecoder_BC4::getInstance();\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::BC4_SNORM)\n\t{\n\t\tif (dim != Latte::E_DIM::DIM_2D && dim != Latte::E_DIM::DIM_2D_ARRAY)\n\t\t\ttexDecoder = TextureDecoder_BC4::getInstance();\n\t\telse\n\t\t\ttexDecoder = TextureDecoder_BC4_UNORM_uncompress::getInstance();\n\t}\n\telse if (format == Latte::E_GX2SURFFMT::BC5_UNORM)\n\t\ttexDecoder = TextureDecoder_BC5::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::BC5_SNORM)\n\t\ttexDecoder = TextureDecoder_BC5::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM)\n\t\ttexDecoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SNORM)\n\t\ttexDecoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB)\n\t\ttexDecoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R8_UNORM)\n\t\ttexDecoder = TextureDecoder_R8::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R8_SNORM)\n\t\ttexDecoder = TextureDecoder_R8::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_UNORM)\n\t\ttexDecoder = TextureDecoder_R8_G8::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_SNORM)\n\t\ttexDecoder = TextureDecoder_R8_G8::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R16_UNORM)\n\t\ttexDecoder = TextureDecoder_R16_UNORM::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM)\n\t\ttexDecoder = TextureDecoder_R16_G16_B16_A16::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_SNORM)\n\t\ttexDecoder = TextureDecoder_R16_G16_B16_A16::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_UNORM)\n\t\ttexDecoder = TextureDecoder_R16_G16::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R5_G6_B5_UNORM)\n\t\ttexDecoder = TextureDecoder_R5_G6_B5::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM)\n\t\ttexDecoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedOpenGL::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM)\n\t\ttexDecoder = TextureDecoder_A1_B5_G5_R5_UNORM::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R32_G32_FLOAT)\n\t\ttexDecoder = TextureDecoder_R32_G32_FLOAT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R32_G32_UINT)\n\t\ttexDecoder = TextureDecoder_R32_G32_UINT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R32_UINT)\n\t\ttexDecoder = TextureDecoder_R32_UINT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R16_UINT)\n\t\ttexDecoder = TextureDecoder_R16_UINT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R8_UINT)\n\t\ttexDecoder = TextureDecoder_R8_UINT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT)\n\t\ttexDecoder = TextureDecoder_R32_G32_B32_A32_FLOAT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM)\n\t\ttexDecoder = TextureDecoder_R10_G10_B10_A2_UNORM::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::A2_B10_G10_R10_UNORM)\n\t\ttexDecoder = TextureDecoder_A2_B10_G10_R10_UNORM_To_RGBA16::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM)\n\t\ttexDecoder = TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB)\n\t\ttexDecoder = TextureDecoder_R10_G10_B10_A2_UNORM::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT)\n\t\ttexDecoder = TextureDecoder_R11_G11_B10_FLOAT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT)\n\t\ttexDecoder = TextureDecoder_R32_G32_B32_A32_UINT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT)\n\t\ttexDecoder = TextureDecoder_R16_G16_B16_A16_UINT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UINT)\n\t\ttexDecoder = TextureDecoder_R8_G8_B8_A8_UINT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::R24_X8_UNORM)\n\t\ttexDecoder = TextureDecoder_R24_X8::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::X24_G8_UINT)\n\t\ttexDecoder = TextureDecoder_X24_G8_UINT::getInstance();\n\telse if (format == Latte::E_GX2SURFFMT::D32_S8_FLOAT)\n\t\ttexDecoder = TextureDecoder_D32_S8_UINT_X24::getInstance();\n\telse\n\t\tcemu_assert_debug(false);\n\n\tcemu_assert_debug(!isDepth);\n\n\treturn texDecoder;\n}\n\n// use standard API to upload texture data\nvoid OpenGLRenderer_texture_loadSlice_normal(LatteTexture* hostTextureGeneric, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 imageSize)\n{\n\tauto hostTexture = (LatteTextureGL*)hostTextureGeneric;\n\tsint32 effectiveWidth = width;\n\tsint32 effectiveHeight = height;\n\tsint32 effectiveDepth = depth;\n\tcemu_assert_debug(hostTexture->overwriteInfo.hasResolutionOverwrite == false); // not supported in _loadSlice\n\tcemu_assert_debug(hostTexture->overwriteInfo.hasFormatOverwrite == false); // not supported in _loadSlice\n\t// get format info\n\tLatteTextureGL::FormatInfoGL glFormatInfo;\n\tLatteTextureGL::GetOpenGLFormatInfo(hostTexture->isDepth, hostTexture->overwriteInfo.hasFormatOverwrite ? (Latte::E_GX2SURFFMT)hostTexture->overwriteInfo.format : hostTexture->format, hostTexture->dim, &glFormatInfo);\n\t// upload slice\n\tcatchOpenGLError();\n\tif (mipIndex >= hostTexture->maxPossibleMipLevels)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"2D texture mip level allocated out of range\");\n\t\treturn;\n\t}\n\tif (hostTexture->dim == Latte::E_DIM::DIM_2D || hostTexture->dim == Latte::E_DIM::DIM_2D_MSAA)\n\t{\n\t\tif (glFormatInfo.glIsCompressed)\n\t\t\tglCompressedTextureSubImage2DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, 0, effectiveWidth, effectiveHeight, glFormatInfo.glInternalFormat, imageSize, pixelData);\n\t\telse\n\t\t\tglTextureSubImage2DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, 0, effectiveWidth, effectiveHeight, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData);\n\t}\n\telse if (hostTexture->dim == Latte::E_DIM::DIM_1D)\n\t{\n\t\tif (glFormatInfo.glIsCompressed)\n\t\t\tglCompressedTextureSubImage1DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, width, glFormatInfo.glInternalFormat, imageSize, pixelData);\n\t\telse\n\t\t\tglTextureSubImage1DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, width, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData);\n\t}\n\telse if (hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY || hostTexture->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA ||\n\t\t\t hostTexture->dim == Latte::E_DIM::DIM_3D ||\n\t\t\t hostTexture->dim == Latte::E_DIM::DIM_CUBEMAP)\n\t{\n\t\tif (glFormatInfo.glIsCompressed)\n\t\t\tglCompressedTextureSubImage3DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, glFormatInfo.glInternalFormat, imageSize, pixelData);\n\t\telse\n\t\t\tglTextureSubImage3DWrapper(hostTexture->glTexTarget, hostTexture->glId_texture, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, glFormatInfo.glSuppliedFormat, glFormatInfo.glSuppliedFormatType, pixelData);\n\t}\n\tcatchOpenGLError();\n}\n\n// use persistent buffers to upload data\nvoid OpenGLRenderer_texture_loadSlice_viaBuffers(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 imageSize)\n{\n\t// bind buffer\n\tglBindBuffer(GL_PIXEL_UNPACK_BUFFER, glRendererState.uploadBuffer);\n\tcatchOpenGLError();\n\t// upload data to buffer\n\tcemu_assert(imageSize <= TEXBUFFER_SIZE);\n\n\tcemu_assert_debug(glRendererState.texWorkBufferSize == imageSize);\n\tglFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, (GLintptr)(glRendererState.texWorkBuffer - (uint8*)glRendererState.uploadBufferPtr), imageSize);\n\tcatchOpenGLError();\n\tOpenGLRenderer_texture_loadSlice_normal(hostTexture, width, height, depth, (void*)(glRendererState.texWorkBuffer - (uint8*)glRendererState.uploadBufferPtr), sliceIndex, mipIndex, imageSize);\n\t// unbind buffer and sync\n\tglBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);\n\tcatchOpenGLError();\n}\n\nvoid OpenGLRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 imageSize)\n{\n\tif (glRendererState.useTextureUploadBuffer)\n\t\tOpenGLRenderer_texture_loadSlice_viaBuffers(hostTexture, width, height, depth, pixelData, sliceIndex, mipIndex, imageSize);\n\telse\n\t\tOpenGLRenderer_texture_loadSlice_normal(hostTexture, width, height, depth, pixelData, sliceIndex, mipIndex, imageSize);\n}\n\nvoid OpenGLRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a)\n{\n\tLatteTextureGL* texGL = (LatteTextureGL*)hostTexture;\n\tcemu_assert_debug(!texGL->isDepth);\n\n\tsint32 eWidth, eHeight;\n\thostTexture->GetEffectiveSize(eWidth, eHeight, mipIndex);\n\trenderstate_resetColorControl();\n\trenderTarget_setViewport(0, 0, eWidth, eHeight, 0.0f, 1.0f);\n\tLatteMRT::BindColorBufferOnly(hostTexture->GetOrCreateView(mipIndex, 1, sliceIndex, 1));\n\tglClearColor(r, g, b, a);\n\tglClear(GL_COLOR_BUFFER_BIT);\n}\n\nvoid OpenGLRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue)\n{\n\tLatteTextureGL* texGL = (LatteTextureGL*)hostTexture;\n\tcemu_assert_debug(texGL->isDepth);\n\n\tsint32 eWidth, eHeight;\n\thostTexture->GetEffectiveSize(eWidth, eHeight, mipIndex);\n\trenderstate_resetColorControl();\n\trenderstate_resetDepthControl();\n\trenderTarget_setViewport(0, 0, eWidth, eHeight, 0.0f, 1.0f);\n\tLatteMRT::BindDepthBufferOnly(hostTexture->GetOrCreateView(mipIndex, 1, sliceIndex, 1));\n\n\tif (!hostTexture->hasStencil)\n\t\tclearStencil = false;\n\n\tif (clearDepth)\n\t\tglClearDepth(clearDepth);\n\tif (clearStencil)\n\t{\n\t\trenderstate_resetStencilMask();\n\t\tglClearStencil((GLint)stencilValue);\n\t}\n\tglClear((clearDepth ? GL_DEPTH_BUFFER_BIT : 0) | (clearStencil ? GL_STENCIL_BUFFER_BIT : 0));\n\tcatchOpenGLError();\n}\n\n\nvoid OpenGLRenderer::texture_clearSlice(LatteTexture* hostTextureGeneric, sint32 sliceIndex, sint32 mipIndex)\n{\n\tauto hostTexture = (LatteTextureGL*)hostTextureGeneric;\n\t// get OpenGL format info\n\tLatteTextureGL::FormatInfoGL formatInfoGL;\n\tLatteTextureGL::GetOpenGLFormatInfo(hostTexture->isDepth, hostTexture->format, hostTexture->dim, &formatInfoGL);\n\t// get effective size of mip\n\tsint32 effectiveWidth, effectiveHeight;\n\thostTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, mipIndex);\n\n\t// on Nvidia glClearTexImage and glClearTexSubImage has bad performance (clearing a 4K texture takes up to 50ms)\n\t// clearing with glTextureSubImage2D from a CPU RAM buffer is only slightly slower\n\t// clearing with glTextureSubImage2D from a OpenGL buffer is 10-20% faster than glClearTexImage\n\t// clearing with FBO and glClear is orders of magnitude faster than the other methods\n\t// (these are results from 2018, may be different now)\n\n\tif (this->m_vendor == GfxVendor::Nvidia || glClearTexSubImage == nullptr)\n\t{\n\t\tif (formatInfoGL.glIsCompressed)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported clear for compressed texture\");\n\t\t\treturn; // todo - create integer texture view to clear compressed textures\n\t\t}\n\t\tif (hostTextureGeneric->isDepth)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported clear for depth texture\");\n\t\t\treturn; // todo - use depth clear\n\t\t}\n\n\t\tglBindFramebuffer(GL_FRAMEBUFFER_EXT, glRendererState.clearFBO);\n\t\t// set attachment\n\t\tif (hostTexture->dim == Latte::E_DIM::DIM_2D)\n\t\t\tglFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hostTexture->glId_texture, mipIndex);\n\t\telse\n\t\t\tglFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, hostTexture->glId_texture, mipIndex, sliceIndex);\n\n\t\tglClearColor(0.0f, 0.0f, 0.0f, 0.0f);\n\t\tglClear(GL_COLOR_BUFFER_BIT);\n\t\tglBindFramebuffer(GL_FRAMEBUFFER_EXT, prevBoundFBO);\n\t\treturn;\n\t}\n\tif (glClearTexSubImage == nullptr)\n\t\treturn;\n\tglClearTexSubImage(hostTexture->glId_texture, mipIndex, 0, 0, sliceIndex, effectiveWidth, effectiveHeight, 1, formatInfoGL.glSuppliedFormat, formatInfoGL.glSuppliedFormatType, NULL);\n}\n\nLatteTexture* OpenGLRenderer::texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels,\n\tuint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth)\n{\n\treturn new LatteTextureGL(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth);\n}\n\nvoid OpenGLRenderer::texture_setActiveTextureUnit(sint32 index)\n{\n\tif (activeTextureUnit != index)\n\t{\n\t\tglActiveTexture(GL_TEXTURE0 + index);\n\t\tactiveTextureUnit = index;\n\t}\n}\n\nvoid OpenGLRenderer::texture_bindAndActivate(LatteTextureView* textureView, uint32 textureUnit)\n{\n\tconst auto textureViewGL = (LatteTextureViewGL*)textureView;\n\t// don't call glBindTexture if the texture is already bound\n\tif (m_latteBoundTextures[textureUnit] == textureViewGL)\n\t{\n\t\ttexture_setActiveTextureUnit(textureUnit);\n\t\treturn; // already bound\n\t}\n\t// bind\n\tm_latteBoundTextures[textureUnit] = textureViewGL;\n\ttexture_setActiveTextureUnit(textureUnit);\n\tif (textureViewGL)\n\t{\n\t\tglBindTexture(textureViewGL->glTexTarget, textureViewGL->glTexId);\n\t}\n}\n\nvoid OpenGLRenderer::texture_notifyDelete(LatteTextureView* textureView)\n{\n\tfor (uint32 i = 0; i < Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3; i++)\n\t{\n\t\tif (m_latteBoundTextures[i] == textureView)\n\t\t\tm_latteBoundTextures[i] = nullptr;\n\t}\n}\n\n// set Latte texture, on the OpenGL renderer this behaves like _bindAndActivate() but doesn't call _setActiveTextureUnit() if the texture is already bound\nvoid OpenGLRenderer::texture_setLatteTexture(LatteTextureView* textureView1, uint32 textureUnit)\n{\n\tauto textureView = ((LatteTextureViewGL*)textureView1);\n\n\tcemu_assert_debug(textureUnit < Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3);\n\tif (m_latteBoundTextures[textureUnit] == textureView)\n\t\treturn;\n\tif (textureView == nullptr)\n\t\treturn;\n\t// bind\n\tif (glBindTextureUnit)\n\t{\n\t\tglBindTextureUnit(textureUnit, textureView->glTexId);\n\t\tm_latteBoundTextures[textureUnit] = textureView;\n\t\tactiveTextureUnit = -1;\n\t}\n\telse\n\t{\n\t\ttexture_setActiveTextureUnit(textureUnit);\n\t\tglBindTexture(textureView->glTexTarget, textureView->glTexId);\n\t\tm_latteBoundTextures[textureUnit] = textureView;\n\t}\n}\n\nvoid OpenGLRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY,\n\tsint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth)\n{\n\tauto srcGL = (LatteTextureGL*)src;\n\tauto dstGL = (LatteTextureGL*)dst;\n\tif ((srcGL->isAlternativeFormat || dstGL->isAlternativeFormat) && (srcGL->glInternalFormat != dstGL->glInternalFormat))\n\t{\n\t\tif (srcGL->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT && dstGL->format == Latte::E_GX2SURFFMT::BC4_UNORM)\n\t\t{\n\t\t\tcemu_assert_debug(dstGL->dim != Latte::E_DIM::DIM_2D);\n\t\t\t// special case where BC4 format is replaced with R16F for array/3d-textures (since OpenGL's BC4 compression only supports 2D textures)\n\t\t\ttexture_syncSliceSpecialBC4(srcGL, srcSlice, srcMip, dstGL, dstSlice, dstMip);\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"_syncSlice() called with unhandled alternative format\");\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (srcGL->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT && dstGL->format == Latte::E_GX2SURFFMT::BC3_UNORM)\n\t{\n\t\tif ((dstGL->width >> dstMip) < 4 ||\t(dstGL->height >> dstMip) < 4)\n\t\t{\n\t\t\ttexture_syncSliceSpecialIntegerToBC3(srcGL, srcSlice, srcMip, dstGL, dstSlice, dstMip);\n\t\t\treturn;\n\n\t\t}\n\t}\n\tcatchOpenGLError();\n\tglCopyImageSubData(srcGL->glId_texture, srcGL->glTexTarget, srcMip, effectiveSrcX, effectiveSrcY, srcSlice, dstGL->glId_texture, dstGL->glTexTarget, dstMip, effectiveDstX, effectiveDstY, dstSlice, effectiveCopyWidth, effectiveCopyHeight, srcDepth);\n\tcatchOpenGLError();\n}\n\nLatteTextureReadbackInfo* OpenGLRenderer::texture_createReadback(LatteTextureView* textureView)\n{\n\treturn new LatteTextureReadbackInfoGL(textureView);\n}\n\nvoid LatteDraw_resetAttributePointerCache();\n\nvoid OpenGLRenderer::attributeStream_reset()\n{\n\t// reset attribute state\n\tattributeStream_unbindVertexBuffer();\n\t// setup vertices\n\tSetArrayElementBuffer(0);\n\tLatteDraw_resetAttributePointerCache();\n\tSetAttributeArrayState(0, true, -1);\n\tSetAttributeArrayState(1, true, -1);\n\tfor (uint32 i = 0; i < GPU_GL_MAX_NUM_ATTRIBUTE; i++)\n\t\tSetAttributeArrayState(i, false, -1);\n}\n\nvoid OpenGLRenderer::bufferCache_init(const sint32 bufferSize)\n{\n\tglGenBuffers(1, &glAttributeCacheAB);\n\tglBindBuffer(GL_ARRAY_BUFFER, glAttributeCacheAB);\n\tglBufferData(GL_ARRAY_BUFFER, bufferSize, NULL, GL_STREAM_DRAW);\n\tglBindBuffer(GL_ARRAY_BUFFER, 0);\n}\n\nvoid OpenGLRenderer::attributeStream_bindVertexCacheBuffer()\n{\n\tif (_boundArrayBuffer == glAttributeCacheAB)\n\t\treturn;\n\t_boundArrayBuffer = glAttributeCacheAB;\n\tglBindBuffer(GL_ARRAY_BUFFER, glAttributeCacheAB);\n}\n\nvoid OpenGLRenderer::attributeStream_unbindVertexBuffer()\n{\n\tif (_boundArrayBuffer == 0)\n\t\treturn;\n\t_boundArrayBuffer = 0;\n\tglBindBuffer(GL_ARRAY_BUFFER, 0);\n}\n\nRendererShader* OpenGLRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader)\n{\n\treturn new RendererShaderGL(type, baseHash, auxHash, isGameShader, isGfxPackShader, source);\n}\n\nvoid OpenGLRenderer::shader_bind(RendererShader* shader)\n{\n\tauto shaderGL = (RendererShaderGL*)shader;\n\tGLbitfield shaderBit;\n\tconst auto program = shaderGL->GetProgram();\n\tswitch(shader->GetType())\n\t{\n\tcase RendererShader::ShaderType::kVertex:\n\t\tif (program == prevVertexShaderProgram)\n\t\t\treturn;\n\t\tshaderBit = GL_VERTEX_SHADER_BIT;\n\t\tprevVertexShaderProgram = program;\n\t\tbreak;\n\tcase RendererShader::ShaderType::kFragment:\n\t\tif (program == prevPixelShaderProgram)\n\t\t\treturn;\n\t\tshaderBit = GL_FRAGMENT_SHADER_BIT;\n\t\tprevPixelShaderProgram = program;\n\t\tbreak;\n\tcase RendererShader::ShaderType::kGeometry:\n\t\tif (program == prevGeometryShaderProgram)\n\t\t\treturn;\n\t\tshaderBit = GL_GEOMETRY_SHADER_BIT;\n\t\tprevGeometryShaderProgram = program;\n\t\tbreak;\n\tdefault:\n\t\tUNREACHABLE;\n\t}\n\n\tcatchOpenGLError();\n\tglUseProgramStages(m_pipeline, shaderBit, program);\n\tcatchOpenGLError();\n}\n\nvoid OpenGLRenderer::shader_unbind(RendererShader::ShaderType shaderType)\n{\n\tswitch (shaderType) { \n\t\tcase RendererShader::ShaderType::kVertex:\n\t\tglUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, 0);\n\t\tprevVertexShaderProgram = -1;\n\t\tbreak;\n\tcase RendererShader::ShaderType::kFragment: \n\t\tglUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, 0);\n\t\tprevPixelShaderProgram = -1;\n\t\tbreak;\n\tcase RendererShader::ShaderType::kGeometry: \n\t\tglUseProgramStages(m_pipeline, GL_GEOMETRY_SHADER_BIT, 0);\n\t\tprevGeometryShaderProgram = -1;\n\t\tbreak;\n\tdefault: \n\t\tUNREACHABLE;\n\t}\n}\n\nvoid decodeBC4Block_UNORM(uint8* blockStorage, float* rOutput);\n\nvoid OpenGLRenderer::texture_syncSliceSpecialBC4(LatteTexture* srcTexture, sint32 srcSliceIndex, sint32 srcMipIndex, LatteTexture* dstTexture, sint32 dstSliceIndex, sint32 dstMipIndex)\n{\n\tauto srcTextureGL = (LatteTextureGL*)srcTexture;\n\tauto dstTextureGL = (LatteTextureGL*)dstTexture;\n\n\tsint32 sourceTexWidth = std::max(srcTexture->width >> srcMipIndex, 1);\n\tsint32 sourceTexHeight = std::max(srcTexture->height >> srcMipIndex, 1);\n\tsint32 destTexWidth = std::max(dstTexture->width >> dstMipIndex, 1);\n\tsint32 destTexHeight = std::max(dstTexture->height >> dstMipIndex, 1);\n\n\tsint32 compressedCopyWidth = std::min(sourceTexWidth, std::max(1, destTexWidth / 4));\n\tsint32 compressedCopyHeight = std::min(sourceTexHeight, std::max(1, destTexHeight / 4));\n\n\tuint8* texelData = (uint8*)malloc(compressedCopyWidth*compressedCopyHeight * 8);\n\tfloat* pixelRGBA16fData = (float*)malloc(destTexWidth*destTexHeight * sizeof(float) * 2);\n\tglBindBuffer(GL_PIXEL_PACK_BUFFER, 0);\n\tif (glGetTextureSubImage)\n\t\tglGetTextureSubImage(srcTextureGL->glId_texture, 0, 0, 0, srcSliceIndex, compressedCopyWidth, compressedCopyHeight, 1, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, compressedCopyWidth * compressedCopyHeight * 8, texelData);\n\tfor (sint32 bx = 0; bx < compressedCopyWidth; bx++)\n\t{\n\t\tfor (sint32 by = 0; by < compressedCopyHeight; by++)\n\t\t{\n\t\t\tfloat rBlock[4 * 4];\n\t\t\tdecodeBC4Block_UNORM(texelData + (bx + by * compressedCopyWidth) * 8, rBlock);\n\t\t\tfor (sint32 sy = 0; sy < std::min(4, destTexHeight - by * 4); sy++)\n\t\t\t{\n\t\t\t\tfor (sint32 sx = 0; sx < std::min(4, destTexWidth - bx * 4); sx++)\n\t\t\t\t{\n\t\t\t\t\tsint32 pixelIndex = (bx * 4 + sx) + (by * 4 + sy)*destTexWidth;\n\t\t\t\t\tpixelRGBA16fData[pixelIndex * 2] = rBlock[sx + sy * 4];\n\t\t\t\t\tpixelRGBA16fData[pixelIndex * 2 + 1] = rBlock[sx + sy * 4];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// upload mip\n\tif (glGetTextureSubImage && glTextureSubImage3D)\n\t\tglTextureSubImage3D(dstTextureGL->glId_texture, dstMipIndex, 0, 0, dstSliceIndex, destTexWidth, destTexHeight, 1, GL_RG, GL_FLOAT, pixelRGBA16fData);\n\tfree(pixelRGBA16fData);\n\tfree(texelData);\n\tcatchOpenGLError();\n}\n\nvoid OpenGLRenderer::texture_syncSliceSpecialIntegerToBC3(LatteTexture* srcTexture, sint32 srcSliceIndex, sint32 srcMipIndex, LatteTexture* dstTexture, sint32 dstSliceIndex, sint32 dstMipIndex)\n{\n\tauto srcTextureGL = (LatteTextureGL*)srcTexture;\n\tauto dstTextureGL = (LatteTextureGL*)dstTexture;\n\n\tsint32 sourceTexWidth = std::max(srcTexture->width >> srcMipIndex, 1);\n\tsint32 sourceTexHeight = std::max(srcTexture->height >> srcMipIndex, 1);\n\tsint32 destTexWidth = std::max(dstTexture->width >> dstMipIndex, 1);\n\tsint32 destTexHeight = std::max(dstTexture->height >> dstMipIndex, 1);\n\n\tsint32 compressedCopyWidth = std::min(sourceTexWidth, std::max(1, destTexWidth / 4));\n\tsint32 compressedCopyHeight = std::min(sourceTexHeight, std::max(1, destTexHeight / 4));\n\n\tuint8* texelData = (uint8*)malloc(compressedCopyWidth*compressedCopyHeight * 16);\n\n\tcatchOpenGLError();\n\tglBindBuffer(GL_PIXEL_PACK_BUFFER, 0);\n\tcatchOpenGLError();\n\tif (glGetTextureSubImage)\n\t\tglGetTextureSubImage(srcTextureGL->glId_texture, 0, 0, 0, srcSliceIndex, compressedCopyWidth, compressedCopyHeight, 1, GL_RGBA_INTEGER, GL_UNSIGNED_INT, compressedCopyWidth * compressedCopyHeight * 16, texelData);\n\t//float* pixelRGBA16fData = (float*)malloc(destTexWidth*destTexHeight * sizeof(float) * 2);\n\t//for (sint32 bx = 0; bx < compressedCopyWidth; bx++)\n\t//{\n\t//\tfor (sint32 by = 0; by < compressedCopyHeight; by++)\n\t//\t{\n\t//\t\tfloat rBlock[4 * 4];\n\t//\t\tdecodeBC4Block_UNORM(texelData + (bx + by * compressedCopyWidth) * 8, rBlock);\n\t//\t\tfor (sint32 sy = 0; sy < min(4, destTexHeight - by * 4); sy++)\n\t//\t\t{\n\t//\t\t\tfor (sint32 sx = 0; sx < min(4, destTexWidth - bx * 4); sx++)\n\t//\t\t\t{\n\t//\t\t\t\tsint32 pixelIndex = (bx * 4 + sx) + (by * 4 + sy)*destTexWidth;\n\t//\t\t\t\tpixelRGBA16fData[pixelIndex * 2] = rBlock[sx + sy * 4];\n\t//\t\t\t\tpixelRGBA16fData[pixelIndex * 2 + 1] = rBlock[sx + sy * 4];\n\t//\t\t\t}\n\t//\t\t}\n\t//\t}\n\t//}\n\t// upload mip\n\tcatchOpenGLError();\n\tif (glGetTextureSubImage && glCompressedTextureSubImage3D)\n\t\tglCompressedTextureSubImage3D(dstTextureGL->glId_texture, dstMipIndex, 0, 0, dstSliceIndex, destTexWidth, destTexHeight, 1, dstTextureGL->glInternalFormat, compressedCopyWidth * compressedCopyHeight * 16, texelData);\n\tfree(texelData);\n\tcatchOpenGLError();\n}\n\nvoid OpenGLRenderer::renderstate_updateBlendingAndColorControl()\n{\n\tcatchOpenGLError();\n\tconst auto& colorControlReg = LatteGPUState.contextNew.CB_COLOR_CONTROL;\n\n\tconst auto specialOp = colorControlReg.get_SPECIAL_OP();\n\tconst uint32 blendEnableMask = colorControlReg.get_BLEND_MASK();\n\tconst auto logicOp = colorControlReg.get_ROP();\n\n\tcemu_assert_debug(!colorControlReg.get_MULTIWRITE_ENABLE()); // not supported\n\n\tuint32 renderTargetMask = LatteGPUState.contextNew.CB_TARGET_MASK.get_MASK();\n\tif (specialOp == Latte::LATTE_CB_COLOR_CONTROL::E_SPECIALOP::DISABLE)\n\t{\n\t\trenderTargetMask = 0;\n\t}\n\tOpenGLRenderer::renderstate_setChannelTargetMask(renderTargetMask);\n\tcatchOpenGLError();\n\n\t// handle depth and stencil control\n\t// get depth control parameters\n\tbool depthEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_Z_ENABLE();\n\tauto depthFunc = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_Z_FUNC();\n\tbool depthWriteEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_Z_WRITE_ENABLE();\n\n\t// get stencil control parameters\n\tbool stencilEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ENABLE();\n\tbool backStencilEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_BACK_STENCIL_ENABLE();\n\tauto frontStencilFunc = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FUNC_F();\n\tauto frontStencilZPass = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZPASS_F();\n\tauto frontStencilZFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZFAIL_F();\n\tauto frontStencilFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FAIL_F();\n\tauto backStencilFunc = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FUNC_B();\n\tauto backStencilZPass = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZPASS_B();\n\tauto backStencilZFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZFAIL_B();\n\tauto backStencilFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FAIL_B();\n\n\t// get stencil control parameters\n\tuint32 stencilCompareMaskFront = LatteGPUState.contextNew.DB_STENCILREFMASK.get_STENCILMASK_F();\n\tuint32 stencilWriteMaskFront = LatteGPUState.contextNew.DB_STENCILREFMASK.get_STENCILWRITEMASK_F();\n\tuint32 stencilRefFront = LatteGPUState.contextNew.DB_STENCILREFMASK.get_STENCILREF_F();\n\tuint32 stencilCompareMaskBack = LatteGPUState.contextNew.DB_STENCILREFMASK_BF.get_STENCILMASK_B();\n\tuint32 stencilWriteMaskBack = LatteGPUState.contextNew.DB_STENCILREFMASK_BF.get_STENCILWRITEMASK_B();\n\tuint32 stencilRefBack = LatteGPUState.contextNew.DB_STENCILREFMASK_BF.get_STENCILREF_B();\n\n\tconst static GLenum stencilActionGX2ToGL[] =\n\t{\n\t\tGL_KEEP,\n\t\tGL_ZERO,\n\t\tGL_REPLACE,\n\t\tGL_INCR,\n\t\tGL_DECR,\n\t\tGL_INVERT,\n\t\tGL_INCR_WRAP,\n\t\tGL_DECR_WRAP\n\t};\n\n\tif (prevStencilEnable != stencilEnable)\n\t{\n\t\tif (stencilEnable)\n\t\t\tglEnable(GL_STENCIL_TEST);\n\t\telse\n\t\t\tglDisable(GL_STENCIL_TEST);\n\t\tprevStencilEnable = stencilEnable;\n\t}\n\n\t// update stencil parameters only if stencil is enabled\n\tif (stencilEnable)\n\t{\n\t\tif (!backStencilEnable)\n\t\t{\n\t\t\t// if back face stencil is disabled then use front parameters\n\t\t\tbackStencilFunc = frontStencilFunc;\n\t\t\tbackStencilZPass = frontStencilZPass;\n\t\t\tbackStencilZFail = frontStencilZFail;\n\t\t\tbackStencilFail = frontStencilFail;\n\t\t\tstencilRefBack = stencilRefFront;\n\t\t\tstencilCompareMaskBack = stencilCompareMaskFront;\n\t\t\tstencilWriteMaskBack = stencilWriteMaskFront;\n\t\t}\n\t\t// update stencil configuration for front side\n\t\tif (prevFrontStencilFail != frontStencilFail || prevFrontStencilZFail != frontStencilZFail || prevFrontStencilZPass != frontStencilZPass)\n\t\t{\n\t\t\tglStencilOpSeparate(GL_FRONT, stencilActionGX2ToGL[(size_t)frontStencilFail], stencilActionGX2ToGL[(size_t)frontStencilZFail], stencilActionGX2ToGL[(size_t)frontStencilZPass]);\n\t\t\tprevFrontStencilFail = frontStencilFail;\n\t\t\tprevFrontStencilZFail = frontStencilZFail;\n\t\t\tprevFrontStencilZPass = frontStencilZPass;\n\t\t}\n\t\tif (prevFrontStencilFunc != frontStencilFunc || prevStencilRefFront != stencilRefFront || prevStencilCompareMaskFront != stencilCompareMaskFront)\n\t\t{\n\t\t\tglStencilFuncSeparate(GL_FRONT, glDepthFuncTable[(size_t)frontStencilFunc], stencilRefFront, stencilCompareMaskFront);\n\t\t\tprevFrontStencilFunc = frontStencilFunc;\n\t\t\tprevStencilRefFront = stencilRefFront;\n\t\t\tprevStencilCompareMaskFront = stencilCompareMaskFront;\n\t\t}\n\t\tif (prevStencilWriteMaskFront != stencilWriteMaskFront)\n\t\t{\n\t\t\tglStencilMaskSeparate(GL_FRONT, stencilWriteMaskFront);\n\t\t\tprevStencilWriteMaskFront = stencilWriteMaskFront;\n\t\t}\n\t\t// update stencil configuration for back side\n\t\tif (prevBackStencilFail != backStencilFail || prevBackStencilZFail != backStencilZFail || prevBackStencilZPass != backStencilZPass)\n\t\t{\n\t\t\tglStencilOpSeparate(GL_BACK, stencilActionGX2ToGL[(size_t)backStencilFail], stencilActionGX2ToGL[(size_t)backStencilZFail], stencilActionGX2ToGL[(size_t)backStencilZPass]);\n\t\t\tprevBackStencilFail = backStencilFail;\n\t\t\tprevBackStencilZFail = backStencilZFail;\n\t\t\tprevBackStencilZPass = backStencilZPass;\n\t\t}\n\t\tif (prevBackStencilFunc != backStencilFunc || prevStencilRefBack != stencilRefBack || prevStencilCompareMaskBack != stencilCompareMaskBack)\n\t\t{\n\t\t\tglStencilFuncSeparate(GL_BACK, glDepthFuncTable[(size_t)backStencilFunc], stencilRefBack, stencilCompareMaskBack);\n\t\t\tprevBackStencilFunc = backStencilFunc;\n\t\t\tprevStencilRefBack = stencilRefBack;\n\t\t\tprevStencilCompareMaskBack = stencilCompareMaskBack;\n\t\t}\n\t\tif (prevStencilWriteMaskBack != stencilWriteMaskBack)\n\t\t{\n\t\t\tglStencilMaskSeparate(GL_BACK, stencilWriteMaskBack);\n\t\t\tprevStencilWriteMaskBack = stencilWriteMaskBack;\n\t\t}\n\t}\n\n\tif (depthEnable != prevDepthEnable)\n\t{\n\t\tif (depthEnable)\n\t\t\tglEnable(GL_DEPTH_TEST);\n\t\telse\n\t\t\tglDisable(GL_DEPTH_TEST);\n\t\tprevDepthEnable = depthEnable;\n\t}\n\tif (depthWriteEnable != prevDepthWriteEnable)\n\t{\n\t\tif (depthWriteEnable)\n\t\t\tglDepthMask(GL_TRUE);\n\t\telse\n\t\t\tglDepthMask(GL_FALSE);\n\t\tprevDepthWriteEnable = depthWriteEnable;\n\t}\n\tif (depthFunc != prevDepthFunc)\n\t{\n\t\tglDepthFunc(glDepthFuncTable[(size_t)depthFunc]);\n\t\tprevDepthFunc = depthFunc;\n\t}\n\n\tcatchOpenGLError();\n\tuint32 blendChangeMask = blendEnableMask ^ prevBlendMask;\n\tif (blendChangeMask)\n\t{\n\t\tfor (uint32 i = 0; i < 8; i++)\n\t\t{\n\t\t\tif ((blendChangeMask & (1 << i)) != 0)\n\t\t\t{\n\t\t\t\t// bit changed -> blend mode was toggled\n\t\t\t\tif ((blendEnableMask & (1 << i)) != 0)\n\t\t\t\t\tglEnablei(GL_BLEND, i);\n\t\t\t\telse\n\t\t\t\t\tglDisablei(GL_BLEND, i);\n\t\t\t}\n\t\t}\n\t\tprevBlendMask = blendEnableMask;\n\t}\n\tcatchOpenGLError();\n\n\tuint32* blendColorConstant = LatteGPUState.contextRegister + Latte::REGADDR::CB_BLEND_RED;\n\tif (blendColorConstant[0] != prevBlendColorConstant[0] ||\n\t\tblendColorConstant[1] != prevBlendColorConstant[1] ||\n\t\tblendColorConstant[2] != prevBlendColorConstant[2] ||\n\t\tblendColorConstant[3] != prevBlendColorConstant[3])\n\t{\n\t\tglBlendColor(*(float*)(blendColorConstant + 0), *(float*)(blendColorConstant + 1), *(float*)(blendColorConstant + 2), *(float*)(blendColorConstant + 3));\n\t\tprevBlendColorConstant[0] = blendColorConstant[0];\n\t\tprevBlendColorConstant[1] = blendColorConstant[1];\n\t\tprevBlendColorConstant[2] = blendColorConstant[2];\n\t\tprevBlendColorConstant[3] = blendColorConstant[3];\n\t}\n\n\tfor (uint32 i = 0; i < 8; i++)\n\t{\n\t\tconst auto& blendControlReg = LatteGPUState.contextNew.CB_BLENDN_CONTROL[i];\n\t\tif (blendControlReg.getRawValue() != prevBlendControlReg[i])\n\t\t{\n\t\t\tif (blendControlReg.get_SEPARATE_ALPHA_BLEND())\n\t\t\t{\n\t\t\t\tglBlendFuncSeparatei(i, GetGLBlendFactor(blendControlReg.get_COLOR_SRCBLEND()), GetGLBlendFactor(blendControlReg.get_COLOR_DSTBLEND()), GetGLBlendFactor(blendControlReg.get_ALPHA_SRCBLEND()), GetGLBlendFactor(blendControlReg.get_ALPHA_DSTBLEND()));\n\t\t\t\tglBlendEquationSeparatei(i, GetGLBlendCombineFunc(blendControlReg.get_COLOR_COMB_FCN()), GetGLBlendCombineFunc(blendControlReg.get_ALPHA_COMB_FCN()));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tauto colorSrc = GetGLBlendFactor(blendControlReg.get_COLOR_SRCBLEND());\n\t\t\t\tauto colorDst = GetGLBlendFactor(blendControlReg.get_COLOR_DSTBLEND());\n\t\t\t\tglBlendFuncSeparatei(i, colorSrc, colorDst, colorSrc, colorDst);\n\t\t\t\tauto combineFunc = GetGLBlendCombineFunc(blendControlReg.get_COLOR_COMB_FCN());\n\t\t\t\tglBlendEquationSeparatei(i, combineFunc, combineFunc);\n\t\t\t}\n\t\t\tprevBlendControlReg[i] = blendControlReg.getRawValue();\n\t\t}\n\t}\n\t// set logic op\n\tuint32 logicOpGL = GL_COPY;\n\tif (logicOp == Latte::LATTE_CB_COLOR_CONTROL::E_LOGICOP::COPY)\n\t\tlogicOpGL = GL_COPY;\n\telse if (logicOp == Latte::LATTE_CB_COLOR_CONTROL::E_LOGICOP::SET)\n\t\tlogicOpGL = GL_SET;\n\telse if (logicOp == Latte::LATTE_CB_COLOR_CONTROL::E_LOGICOP::CLEAR)\n\t\tlogicOpGL = GL_CLEAR;\n\telse if (logicOp == Latte::LATTE_CB_COLOR_CONTROL::E_LOGICOP::OR)\n\t\tlogicOpGL = GL_OR;\n\telse\n\t\tcemu_assert_unimplemented();\n\tif (prevLogicOp != logicOpGL)\n\t{\n\t\tif (logicOpGL != GL_COPY)\n\t\t\tglEnable(GL_COLOR_LOGIC_OP);\n\t\telse\n\t\t\tglDisable(GL_COLOR_LOGIC_OP);\n\t\tglLogicOp(logicOpGL);\n\t\tprevLogicOp = logicOpGL;\n\t}\n\n\t// polygon control\n\tconst auto& polygonControlReg = LatteGPUState.contextNew.PA_SU_SC_MODE_CNTL;\n\tconst auto frontFace = polygonControlReg.get_FRONT_FACE();\n\tuint32 cullFront = polygonControlReg.get_CULL_FRONT();\n\tuint32 cullBack = polygonControlReg.get_CULL_BACK();\n\t// todo - polygon modes\n\tuint32 lineAndPointOffsetEnabled = polygonControlReg.get_OFFSET_PARA_ENABLED();\n\tuint32 polyOffsetFrontEnabled = polygonControlReg.get_OFFSET_FRONT_ENABLED();\n\tuint32 polyOffsetBackEnabled = polygonControlReg.get_OFFSET_BACK_ENABLED();\n\n\tuint32 cullEnable = (cullFront || cullBack) ? 1 : 0;\n\tif (prevCullEnable != cullEnable)\n\t{\n\t\tif (cullEnable)\n\t\t\tglEnable(GL_CULL_FACE);\n\t\telse\n\t\t\tglDisable(GL_CULL_FACE);\n\t\tprevCullEnable = cullEnable;\n\t}\n\tif (prevCullFrontFace != frontFace)\n\t{\n\t\tif (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CCW)\n\t\t\tglFrontFace(GL_CCW);\n\t\telse if (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CW)\n\t\t\tglFrontFace(GL_CW);\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t\tprevCullFrontFace = frontFace;\n\t}\n\tif (prevCullFront != cullFront || prevCullBack != cullBack)\n\t{\n\t\tif (cullFront && cullBack)\n\t\t\tglCullFace(GL_FRONT_AND_BACK);\n\t\telse if (cullFront == 0 && cullBack)\n\t\t\tglCullFace(GL_BACK);\n\t\telse if (cullFront && cullBack == 0)\n\t\t\tglCullFace(GL_FRONT);\n\t\telse\n\t\t\t; // front and back disabled, do nothing here since we force disable culling via glDisable(GL_CULL_FACE) above\n\t\tprevCullFront = cullFront;\n\t\tprevCullBack = cullBack;\n\t}\n\n\tif (polyOffsetFrontEnabled != prevPolygonOffsetFrontEnabled)\n\t{\n\t\tif (polyOffsetFrontEnabled)\n\t\t\tglEnable(GL_POLYGON_OFFSET_FILL);\n\t\telse\n\t\t\tglDisable(GL_POLYGON_OFFSET_FILL);\n\t\tprevPolygonOffsetFrontEnabled = polyOffsetFrontEnabled;\n\n\t}\n\n\tif (polyOffsetFrontEnabled)\n\t{\n\t\t// if polygon offset is enabled check if offset/scale register changed\n\t\tif (LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_OFFSET.getRawValue() != prevPolygonFrontOffsetU32 || LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_SCALE.getRawValue() != prevPolygonFrontScaleU32 || LatteGPUState.contextNew.PA_SU_POLY_OFFSET_CLAMP.getRawValue() != prevPolygonClampU32)\n\t\t{\n\t\t\tfloat frontScale = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_SCALE.get_SCALE();\n\t\t\tfloat frontOffset = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_OFFSET.get_OFFSET();\n\t\t\tfloat offsetClamp = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_CLAMP.get_CLAMP();\n\n\t\t\tfrontScale /= 16.0f;\n\n\t\t\t//if( glPolygonOffsetClampEXT )\n\t\t\t//\tglPolygonOffsetClampEXT(frontOffset, frontScale, offsetClamp);\t\t\n\t\t\t//else\n\t\t\tglPolygonOffset(frontScale, frontOffset);\n\n\t\t\tprevPolygonFrontOffsetU32 = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_SCALE.getRawValue();\n\t\t\tprevPolygonFrontScaleU32 = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_SCALE.getRawValue();\n\t\t\tprevPolygonClampU32 = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_CLAMP.getRawValue();\n\t\t}\n\t}\n\t// clip control\n\tcatchOpenGLError();\n\tcemu_assert_debug(LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_NEAR_DISABLE() == LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_FAR_DISABLE()); // near/far clipping disabled individually\n\tuint32 zClipEnable = LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_NEAR_DISABLE() == false;\n\t// todo: Mass Effect 3 uses precompiled display lists which seem to write values to PA_CL_CLIP_CNTL which aren't available via the traditional GX2 API\n\tif (prevZClipEnable != zClipEnable)\n\t{\n\t\tif (zClipEnable)\n\t\t{\n\t\t\t// disable depth clamping and enable clipping\n\t\t\tglDisable(GL_DEPTH_CLAMP);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// enable depth clamping and disable clipping\n\t\t\tglEnable(GL_DEPTH_CLAMP);\n\t\t}\n\t\tprevZClipEnable = zClipEnable;\n\t}\n\tcatchOpenGLError();\n\t// point size\n\tconst auto& pointSizeReg = LatteGPUState.contextNew.PA_SU_POINT_SIZE;\n\tif (pointSizeReg.getRawValue() != prevPointSizeReg)\n\t{\n\t\tfloat pointWidth = (float)pointSizeReg.get_WIDTH() / 8.0f;\n\t\tfloat pointHeight = (float)pointSizeReg.get_HEIGHT() / 8.0f;\n\t\tif (pointWidth == 0.0f)\n\t\t\tglPointSize(1.0f / 8.0f); // minimum size\n\t\telse\n\t\t\tglPointSize(pointWidth);\n\t\tprevPointSizeReg = pointSizeReg.getRawValue();\n\t\tcatchOpenGLError();\n\t}\n\t// primitive restart index\n\tuint32 primitiveRestartIndex = LatteGPUState.contextNew.VGT_MULTI_PRIM_IB_RESET_INDX.get_RESTART_INDEX();\n\tif (prevPrimitiveRestartIndex != primitiveRestartIndex)\n\t{\n\t\tglPrimitiveRestartIndex(primitiveRestartIndex);\n\t\tprevPrimitiveRestartIndex = primitiveRestartIndex;\n\t}\n}\n\nvoid OpenGLRenderer::renderstate_resetColorControl()\n{\n\trenderstate_setChannelTargetMask(0xF);\n\t// disable blending\n\tuint32 blendEnableMask = 0;\n\tfor (uint32 i = 0; i < 8; i++)\n\t{\n\t\tif (((blendEnableMask^prevBlendMask)&(1 << i)) != 0)\n\t\t{\n\t\t\t// bit changed -> blend mode was toggled\n\t\t\tif ((blendEnableMask&(1 << i)) != 0)\n\t\t\t\tglEnablei(GL_BLEND, i);\n\t\t\telse\n\t\t\t\tglDisablei(GL_BLEND, i);\n\t\t}\n\t}\n\tprevBlendMask = blendEnableMask;\n\t// \"forget\" blend states\n\tfor (uint32 i = 0; i < 8; i++)\n\t{\n\t\tprevBlendControlReg[i] = 0xFFFFFFFF;\n\t}\n\t// disable alpha test\n\tif (prevAlphaTestEnable != 0)\n\t{\n\t\tglDisable(GL_ALPHA_TEST);\n\t\tprevAlphaTestEnable = 0;\n\t}\n\tif (prevLogicOp != GL_COPY)\n\t{\n\t\tglDisable(GL_COLOR_LOGIC_OP);\n\t\tglLogicOp(GL_COPY);\n\t\tprevLogicOp = GL_COPY;\n\t}\n\t// disable culling\n\tuint32 cullEnable = 0;\n\tif (prevCullEnable != cullEnable)\n\t{\n\t\tglDisable(GL_CULL_FACE);\n\t\tprevCullEnable = 0;\n\t}\n\t// disable polygon offset\n\tif (prevPolygonOffsetFrontEnabled != 0)\n\t{\n\t\tglDisable(GL_POLYGON_OFFSET_FILL);\n\t\tprevPolygonOffsetFrontEnabled = 0;\n\t}\n\t// disable scissor box\n\tif (prevScissorEnable != false)\n\t{\n\t\tglDisable(GL_SCISSOR_TEST);\n\t\tprevScissorEnable = false;\n\t}\n}\n\nvoid OpenGLRenderer::renderstate_resetDepthControl()\n{\n\tif (prevDepthEnable)\n\t{\n\t\tglDisable(GL_DEPTH_TEST);\n\t\tprevDepthEnable = false;\n\t}\n\tif (!prevDepthWriteEnable)\n\t{\n\t\tglDepthMask(GL_TRUE);\n\t\tprevDepthWriteEnable = true;\n\t}\n\tif (prevStencilEnable)\n\t{\n\t\tglDisable(GL_STENCIL_TEST);\n\t\tprevStencilEnable = false;\n\t}\n\t//if (prevZClipEnable == 0)\n\t//{\n\t//\tglDisable(GL_DEPTH_CLAMP);\n\t//\tprevZClipEnable = 1;\n\t//}\n\n\tglDisable(GL_DEPTH_CLAMP);\n\tprevZClipEnable = 1;\n\n\tif (prevPrimitiveRestartIndex != 0xFFFFFFFF)\n\t{\n\t\tglPrimitiveRestartIndex(0xFFFFFFFF);\n\t\tprevPrimitiveRestartIndex = 0xFFFFFFFF;\n\t}\n}\n\nvoid OpenGLRenderer::renderstate_resetStencilMask()\n{\n\tuint32 stencilWriteMaskFront = 0xFFFFFFFF; // enable front mask\n\tuint32 stencilWriteMaskBack = 0xFFFFFFFF; // enable back mask\n\tif (prevStencilWriteMaskFront != stencilWriteMaskFront)\n\t{\n\t\tglStencilMaskSeparate(GL_FRONT, stencilWriteMaskFront);\n\t\tprevStencilWriteMaskFront = stencilWriteMaskFront;\n\t}\n\tif (prevStencilWriteMaskBack != stencilWriteMaskBack)\n\t{\n\t\tglStencilMaskSeparate(GL_BACK, stencilWriteMaskBack);\n\t\tprevStencilWriteMaskBack = stencilWriteMaskBack;\n\t}\n}\n\nvoid OpenGLRenderer::cleanupAfterFrame()\n{\n\tReleaseBufferCacheEntries();\n}\n\nvoid OpenGLRenderer::ReleaseBufferCacheEntries()\n{\n\tfor (auto& itr : m_destructionQueues.bufferCacheEntries)\n\t\titr.free();\n\tm_destructionQueues.bufferCacheEntries.clear();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h",
    "content": "#pragma once\n#include \"Common/GLInclude/GLInclude.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Renderer/RendererOuputShader.h\"\n\n#define GPU_GL_MAX_NUM_ATTRIBUTE\t\t(16) // Wii U GPU supports more than 16 but not all desktop GPUs do. Have to keep this at 16 until we find a better solution\n\nclass OpenGLCanvasCallbacks\n{\n  public:\n\tvirtual bool HasPadViewOpen() const\n\t{\n\t\treturn false;\n\t}\n\tvirtual bool MakeCurrent(bool padView)\n\t{\n\t\treturn false;\n\t}\n\tvirtual void SwapBuffers(bool swapTV, bool swapDRC) {}\n\tvirtual ~OpenGLCanvasCallbacks() = default;\n};\n\nvoid SetOpenGLCanvasCallbacks(OpenGLCanvasCallbacks* callbacks);\nvoid ClearOpenGLCanvasCallbacks();\n\nbool GLCanvas_HasPadViewOpen();\nbool GLCanvas_MakeCurrent(bool padView);\nvoid GLCanvas_SwapBuffers(bool swapTV, bool swapDRC);\n\nclass OpenGLRenderer : public Renderer\n{\n\tfriend class OpenGLCanvas;\npublic:\n\tOpenGLRenderer();\n\t~OpenGLRenderer();\n\n\tRendererAPI GetType() override { return RendererAPI::OpenGL; }\n\n\tstatic OpenGLRenderer* GetInstance();\n\n\t// imgui\n\tbool ImguiBegin(bool mainWindow) override;\n\tvoid ImguiEnd() override;\n\tImTextureID GenerateTexture(const std::vector<uint8>& data, const Vector2i& size) override;\n\tvoid DeleteTexture(ImTextureID id) override;\n\tvoid DeleteFontTextures() override;\n\n\tvoid Initialize() override;\n\tbool IsPadWindowActive() override;\n\n\tvoid Flush(bool waitIdle = false) override;\n\tvoid NotifyLatteCommandProcessorIdle() override;\n\n\tvoid EnableDebugMode() override;\n\tvoid SwapBuffers(bool swapTV = true, bool swapDRC = true) override;\n\n\tbool BeginFrame(bool mainWindow) override;\n\tvoid DrawEmptyFrame(bool mainWindow) override;\n\tvoid ClearColorbuffer(bool padView) override;\n\tvoid HandleScreenshotRequest(LatteTextureView* texView, bool padView) override;\n\n\tvoid DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight, bool padView, bool clearBackground) override;\n\n\tvoid AppendOverlayDebugInfo() override\n\t{\n\t\t// does nothing currently\n\t}\n\n\t// rendertarget\n\tvoid renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ = false) override;\n\tvoid renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight) override;\n\n\tLatteCachedFBO* rendertarget_createCachedFBO(uint64 key) override;\n\tvoid rendertarget_deleteCachedFBO(LatteCachedFBO* cfbo) override;\n\tvoid rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) override;\n\n\t// renderstate functions\n\tvoid renderstate_setChannelTargetMask(uint32 renderTargetMask);\n\tvoid renderstate_setAlwaysWriteDepth();\n\tvoid renderstate_updateBlendingAndColorControl();\n\tvoid renderstate_resetColorControl();\n\tvoid renderstate_resetDepthControl();\n\tvoid renderstate_resetStencilMask();\n\n\tvoid renderstate_updateTextureSettingsGL(LatteDecompilerShader* shaderContext, LatteTextureView* _hostTextureView, uint32 hostTextureUnit, const Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N texUnitWord4, uint32 texUnitIndex, bool isDepthSampler);\n\n\t// texture functions\n\tvoid* texture_acquireTextureUploadBuffer(uint32 size) override;\n\tvoid texture_releaseTextureUploadBuffer(uint8* mem) override;\n\n\tTextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) override;\n\n\tvoid texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) override;\n\tvoid texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) override;\n\tvoid texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) override;\n\tvoid texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) override;\n\n\tLatteTexture* texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) override;\n\n\tvoid texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) override;\n\tvoid texture_bindAndActivate(LatteTextureView* textureView, uint32 textureUnit);\n\tvoid texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) override;\n\n\tvoid texture_notifyDelete(LatteTextureView* textureView);\n\n\tLatteTextureReadbackInfo* texture_createReadback(LatteTextureView* textureView) override;\n\n\tvoid surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height) override;\n\n\tvoid attributeStream_reset();\n\tvoid bufferCache_init(const sint32 bufferSize) override;\n\tvoid bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) override;\n\tvoid bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) override;\n\n\tvoid buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) override;\n\tvoid buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override;\n\n\tvoid _setupVertexAttributes();\n\n\tvoid attributeStream_bindVertexCacheBuffer();\n\tvoid attributeStream_unbindVertexBuffer();\n\n\tstatic void SetAttributeArrayState(uint32 index, bool isEnabled, sint32 aluDivisor);\n\tstatic void SetArrayElementBuffer(GLuint arrayElementBuffer);\n\n\t// index (not used by OpenGL renderer yet)\n\tIndexAllocation indexData_reserveIndexMemory(uint32 size) override\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn {};\n\t}\n\n\tvoid indexData_releaseIndexMemory(IndexAllocation& allocation) override\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tvoid indexData_uploadIndexMemory(IndexAllocation& allocation) override\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\t// uniform\n\tvoid uniformData_update();\n\n\t// shader\n\tRendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader) override;\n\tvoid shader_bind(RendererShader* shader);\n\tvoid shader_unbind(RendererShader::ShaderType shaderType);\n\n\t// streamout\n\tvoid streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;\n\tvoid streamout_begin() override;\n\tvoid bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) override;\n\tvoid streamout_rendererFinishDrawcall() override;\n\n\t// draw\n\tvoid draw_init();\n\n\tvoid draw_beginSequence() override;\n\tvoid draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) override;\n\tvoid draw_endSequence() override;\n\n\ttemplate<bool TIsMinimal, bool THasProfiling>\n\tvoid draw_genericDrawHandler(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType);\n\n\t// resource garbage collection\n\tvoid cleanupAfterFrame();\n\tvoid ReleaseBufferCacheEntries();\n\n\t// occlusion queries\n\tLatteQueryObject* occlusionQuery_create() override;\n\tvoid occlusionQuery_destroy(LatteQueryObject* queryObj) override;\n\tvoid occlusionQuery_flush() override;\n\tvoid occlusionQuery_updateState() override {};\n\nprivate:\n\tvoid GetVendorInformation() override;\n\n\tvoid texture_setActiveTextureUnit(sint32 index);\n\n\tvoid texture_syncSliceSpecialBC4(LatteTexture* srcTexture, sint32 srcSliceIndex, sint32 srcMipIndex, LatteTexture* dstTexture, sint32 dstSliceIndex, sint32 dstMipIndex);\n\tvoid texture_syncSliceSpecialIntegerToBC3(LatteTexture* srcTexture, sint32 srcSliceIndex, sint32 srcMipIndex, LatteTexture* dstTexture, sint32 dstSliceIndex, sint32 dstMipIndex);\n\n\tGLuint m_pipeline = 0;\n\n\tbool m_isPadViewContext{};\n\n\t// rendertarget viewport\n\tfloat prevViewportX = 0;\n\tfloat prevViewportY = 0;\n\tfloat prevViewportWidth = 0;\n\tfloat prevViewportHeight = 0;\n\n\tfloat prevNearZ = -999999.0f;\n\tfloat prevFarZ = -9999999.0f;\n\tbool _prevInvertY = false;\n\tbool _prevHalfZ = false;\n\n\tuint32 prevScissorX = 0;\n\tuint32 prevScissorY = 0;\n\tuint32 prevScissorWidth = 0;\n\tuint32 prevScissorHeight = 0;\n\tbool prevScissorEnable = false;\n\n\tbool m_isXfbActive = false;\n\n\tsint32 activeTextureUnit = 0;\n\tvoid* m_latteBoundTextures[Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE * 3]{};\n\n\t// backbuffer blit\n\tGLuint m_backbufferBlit_uniformBuffer;\n\n\t// attribute stream\n\tGLuint glAttributeCacheAB{};\n\tGLuint _boundArrayBuffer{};\n\n\t// streamout\n\tGLuint glStreamoutCacheRingBuffer;\n\n\t// cfbo\n\tGLuint prevBoundFBO = 0;\n\tGLuint glId_fbo = 0;\n\n\t// renderstate\n\tuint32 prevBlendControlReg[8] = { 0 };\n\tuint32 prevBlendMask = 0;\n\tuint32 prevLogicOp = 0;\n\tuint32 prevBlendColorConstant[4] = { 0 };\n\tuint8 prevAlphaTestEnable = 0;\n\tbool prevDepthEnable = 0;\n\tbool prevDepthWriteEnable = 0;\n\tLatte::LATTE_DB_DEPTH_CONTROL::E_ZFUNC prevDepthFunc = (Latte::LATTE_DB_DEPTH_CONTROL::E_ZFUNC)-1;\n\tbool prevStencilEnable = false;\n\tLatte::LATTE_DB_DEPTH_CONTROL::E_STENCILFUNC prevFrontStencilFunc = (Latte::LATTE_DB_DEPTH_CONTROL::E_STENCILFUNC)-1;\n\tLatte::LATTE_DB_DEPTH_CONTROL::E_STENCILFUNC prevBackStencilFunc = (Latte::LATTE_DB_DEPTH_CONTROL::E_STENCILFUNC)-1;\n\tLatte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION prevFrontStencilZPass = (Latte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION)-1;\n\tLatte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION prevFrontStencilZFail = (Latte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION)-1;\n\tLatte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION prevFrontStencilFail = (Latte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION)-1;\n\tLatte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION prevBackStencilZPass = (Latte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION)-1;\n\tLatte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION prevBackStencilZFail = (Latte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION)-1;\n\tLatte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION prevBackStencilFail = (Latte::LATTE_DB_DEPTH_CONTROL::E_STENCILACTION)-1;\n\tuint32 prevStencilRefFront = -1;\n\tuint32 prevStencilCompareMaskFront = -1;\n\tuint32 prevStencilWriteMaskFront = -1;\n\tuint32 prevStencilRefBack = -1;\n\tuint32 prevStencilCompareMaskBack = -1;\n\tuint32 prevStencilWriteMaskBack = -1;\n\n\tuint32 prevTargetColorMask = 0; // RGBA color mask for each render target (4 bit per target, starting from LSB)\n\tuint32 prevCullEnable = 0;\n\tuint32 prevCullFront = 0;\n\tuint32 prevCullBack = 0;\n\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE prevCullFrontFace = Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CCW;\n\n\tuint32 prevPolygonFrontScaleU32 = 0;\n\tuint32 prevPolygonFrontOffsetU32 = 0;\n\tuint32 prevPolygonClampU32 = 0;\n\tuint32 prevPolygonOffsetFrontEnabled = 0;\n\tuint32 prevPolygonOffsetBackEnabled = 0;\n\n\tuint32 prevZClipEnable = 0;\n\n\tuint32 prevPointSizeReg = 0xFFFFFFFF;\n\n\tuint32 prevPrimitiveRestartIndex = 0xFFFFFFFF;\n\n\tGLuint prevVertexShaderProgram = -1;\n\tGLuint prevGeometryShaderProgram = -1;\n\tGLuint prevPixelShaderProgram = -1;\n\n\t// occlusion queries\n\tstd::vector<class LatteQueryObjectGL*> list_queryCacheOcclusion; // cache for unused queries\n\n\t// resource garbage collection\n\tstruct BufferCacheReleaseQueueEntry\n\t{\n\t\tBufferCacheReleaseQueueEntry(VirtualBufferHeap_t* heap, VirtualBufferHeapEntry_t* entry) : m_heap(heap), m_entry(entry) {};\n\n\t\tvoid free()\n\t\t{\n\t\t\tvirtualBufferHeap_free(m_heap, m_entry);\n\t\t}\n\n\t\tVirtualBufferHeap_t* m_heap{};\n\t\tVirtualBufferHeapEntry_t* m_entry{};\n\t};\n\n\tstruct\n\t{\n\t\tsint32 index;\n\t\tstd::vector<BufferCacheReleaseQueueEntry> bufferCacheEntries;\n\t}m_destructionQueues;\n\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp",
    "content": "#include \"Common/GLInclude/GLInclude.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteRingBuffer.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteSoftware.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/CachedFBOGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h\"\n\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"config/ActiveSettings.h\"\n\n\nusing _INDEX_TYPE = Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE;\n\nGLenum sGLActiveDrawMode = 0;\n\nextern bool hasValidFramebufferAttached;\n\n#define INDEX_CACHE_ENTRIES\t\t(8)\n\ntypedef struct\n{\n\tMPTR prevIndexDataMPTR;\n\tsint32 prevIndexType;\n\tsint32 prevCount;\n\t// index data\n\tuint8* indexData;\n\tuint8* indexData2;\n\tuint32 indexBufferOffset;\n\tsint32 indexDataSize; // current size\n\tsint32 indexDataLimit; // maximum size\n\t// info\n\tuint32 maxIndex;\n\tuint32 minIndex;\n}indexDataCacheEntry_t;\n\nstruct\n{\n\tindexDataCacheEntry_t indexCacheEntry[INDEX_CACHE_ENTRIES];\n\tsint32 nextCacheEntryIndex;\n\t// info about currently used index data\n\tuint32 maxIndex;\n\tuint32 minIndex;\n\tuint8* indexData;\n\t// buffer \n\tGLuint glIndexCacheBuffer;\n\tVirtualBufferHeap_t* indexBufferVirtualHeap;\n\tuint8* mappedIndexBuffer;\n\tLatteRingBuffer_t* indexRingBuffer;\n\tuint8* tempIndexStorage;\n\t// misc\n\tbool initialized;\n\tGLuint glActiveElementArrayBuffer;\n}indexState = { 0 };\n\nstruct\n{\n\tuint8* vboOutput;\n\tuint32 vboStride;\n\tuint8 dataFormat;\n\tuint8 nfa;\n\tbool isSigned;\n}activeAttributePointer[LATTE_VS_ATTRIBUTE_LIMIT] = { 0 };\n\nvoid LatteDraw_resetAttributePointerCache()\n{\n\tfor (sint32 i = 0; i < LATTE_VS_ATTRIBUTE_LIMIT; i++)\n\t{\n\t\tactiveAttributePointer[i].vboOutput = (uint8*)-1;\n\t\tactiveAttributePointer[i].vboStride = (uint32)-1;\n\t}\n}\n\nvoid _setAttributeBufferPointerRaw(uint32 attributeShaderLoc, uint8* buffer, uint32 bufferSize, uint32 stride, LatteParsedFetchShaderAttribute_t* attrib, uint8* vboOutput, uint32 vboStride)\n{\n\tuint32 dataFormat = attrib->format;\n\tbool isSigned = attrib->isSigned != 0;\n\tuint8 nfa = attrib->nfa;\n\t// don't call glVertexAttribIPointer if parameters have not changed\n\tif (activeAttributePointer[attributeShaderLoc].vboOutput == vboOutput && activeAttributePointer[attributeShaderLoc].vboStride == vboStride && activeAttributePointer[attributeShaderLoc].dataFormat == dataFormat && activeAttributePointer[attributeShaderLoc].nfa == nfa && activeAttributePointer[attributeShaderLoc].isSigned == isSigned)\n\t{\n\t\treturn;\n\t}\n\tactiveAttributePointer[attributeShaderLoc].vboOutput = vboOutput;\n\tactiveAttributePointer[attributeShaderLoc].vboStride = vboStride;\n\tactiveAttributePointer[attributeShaderLoc].dataFormat = dataFormat;\n\tactiveAttributePointer[attributeShaderLoc].nfa = nfa;\n\tactiveAttributePointer[attributeShaderLoc].isSigned = isSigned;\n\t// setup attribute pointer\n\tif (dataFormat == FMT_32_32_32_32_FLOAT || dataFormat == FMT_32_32_32_32)\n\t{\n\t\tglVertexAttribIPointer(attributeShaderLoc, 4, GL_UNSIGNED_INT, vboStride, vboOutput);\n\t}\n\telse if (dataFormat == FMT_32_32_32_FLOAT || dataFormat == FMT_32_32_32)\n\t{\n\t\tglVertexAttribIPointer(attributeShaderLoc, 3, GL_UNSIGNED_INT, vboStride, vboOutput);\n\t}\n\telse if (dataFormat == FMT_32_32_FLOAT || dataFormat == FMT_32_32)\n\t{\n\t\tglVertexAttribIPointer(attributeShaderLoc, 2, GL_UNSIGNED_INT, vboStride, vboOutput);\n\t}\n\telse if (dataFormat == FMT_32_FLOAT || dataFormat == FMT_32)\n\t{\n\t\tglVertexAttribIPointer(attributeShaderLoc, 1, GL_UNSIGNED_INT, vboStride, vboOutput);\n\t}\n\telse if (dataFormat == FMT_8_8_8_8)\n\t{\n\t\tglVertexAttribIPointer(attributeShaderLoc, 4, GL_UNSIGNED_BYTE, vboStride, vboOutput);\n\t}\n\telse if (dataFormat == FMT_8_8)\n\t{\n\t\t// workaround for AMD (alignment must be 4 for 2xbyte)\n\t\tif (((uint32)(size_t)vboOutput & 0x3) == 2 && LatteGPUState.glVendor == GLVENDOR_AMD)\n\t\t{\n\t\t\tglVertexAttribIPointer(attributeShaderLoc, 4, GL_UNSIGNED_BYTE, vboStride, vboOutput - 2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tglVertexAttribIPointer(attributeShaderLoc, 2, GL_UNSIGNED_BYTE, vboStride, vboOutput);\n\t\t}\n\t}\n\telse if (dataFormat == FMT_8)\n\t{\n\t\tglVertexAttribIPointer(attributeShaderLoc, 1, GL_UNSIGNED_BYTE, vboStride, vboOutput);\n\t}\n\telse if (dataFormat == FMT_16_16_16_16_FLOAT || dataFormat == FMT_16_16_16_16)\n\t{\n\t\tglVertexAttribIPointer(attributeShaderLoc, 4, GL_UNSIGNED_SHORT, vboStride, vboOutput);\n\t}\n\telse if (dataFormat == FMT_16_16_FLOAT || dataFormat == FMT_16_16)\n\t{\n\t\tglVertexAttribIPointer(attributeShaderLoc, 2, GL_UNSIGNED_SHORT, vboStride, vboOutput);\n\t}\n\telse if (dataFormat == FMT_16_FLOAT || dataFormat == FMT_16)\n\t{\n\t\tglVertexAttribIPointer(attributeShaderLoc, 1, GL_UNSIGNED_SHORT, vboStride, vboOutput);\n\t}\n\telse if (dataFormat == FMT_2_10_10_10)\n\t{\n\t\tglVertexAttribIPointer(attributeShaderLoc, 1, GL_UNSIGNED_INT, vboStride, vboOutput);\n\t}\n\telse\n\t{\n\t\tdebug_printf(\"_setAttributeBufferPointerRaw(): Unsupported format %d\\n\", dataFormat);\n\t\tcemu_assert_unimplemented();\n\t}\n}\n\nbool glAttributeArrayIsEnabled[GPU_GL_MAX_NUM_ATTRIBUTE] = { 0 };\nsint32 glAttributeArrayAluDivisor[GPU_GL_MAX_NUM_ATTRIBUTE] = { 0 };\n\nvoid OpenGLRenderer::SetAttributeArrayState(uint32 index, bool isEnabled, sint32 aluDivisor)\n{\n\tcemu_assert_debug(index < GPU_GL_MAX_NUM_ATTRIBUTE);\n\tcatchOpenGLError();\n\tif (glAttributeArrayIsEnabled[index] != isEnabled)\n\t{\n\t\tif (isEnabled)\n\t\t{\n\t\t\t// enable\n\t\t\tglEnableVertexAttribArray(index);\n\t\t\tglAttributeArrayIsEnabled[index] = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// disable\n\t\t\tglDisableVertexAttribArray(index);\n\t\t\tglAttributeArrayIsEnabled[index] = false;\n\t\t}\n\t\tcatchOpenGLError();\n\t}\n\t// set divisor state\n\tif (glAttributeArrayAluDivisor[index] != aluDivisor)\n\t{\n\t\tif (aluDivisor <= 0)\n\t\t\tglVertexAttribDivisor(index, 0);\n\t\telse\n\t\t\tglVertexAttribDivisor(index, aluDivisor);\n\t\tglAttributeArrayAluDivisor[index] = aluDivisor;\n\t\tcatchOpenGLError();\n\t}\n}\n\n// Sets the currently active element array buffer and binds it\nvoid OpenGLRenderer::SetArrayElementBuffer(GLuint arrayElementBuffer)\n{\n\tif (arrayElementBuffer == indexState.glActiveElementArrayBuffer)\n\t\treturn;\n\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrayElementBuffer);\n\tindexState.glActiveElementArrayBuffer = arrayElementBuffer;\n}\n\ntypedef struct\n{\n\tMPTR physAddr;\n\tsint32 count;\n\tuint32 primitiveRestartIndex;\n\tuint32 primitiveMode;\n}indexDataCacheKey_t;\n\ntypedef struct _indexDataCacheEntry_t\n{\n\tindexDataCacheKey_t key;\n\t_indexDataCacheEntry_t* nextInBucket; // points to next element in same bucket\n\tuint32 physSize;\n\tuint32 hash;\n\t_INDEX_TYPE indexType;\n\t//sint32 indexType;\n\tuint32 minIndex;\n\tuint32 maxIndex;\n\tuint32 lastAccessFrameCount;\n\tVirtualBufferHeapEntry_t* heapEntry;\n\t_indexDataCacheEntry_t* nextInMostRecentUsage; // points to element which was used more recently\n\t_indexDataCacheEntry_t* prevInMostRecentUsage; // points to element which was used less recently\n}indexDataCacheEntry2_t;\n\n#define INDEX_DATA_CACHE_BUCKETS\t\t(1783)\n\nindexDataCacheEntry2_t* indexDataCacheBucket[INDEX_DATA_CACHE_BUCKETS] = { 0 };\nindexDataCacheEntry2_t* indexDataCacheFirst = nullptr; // points to least recently used item\nindexDataCacheEntry2_t* indexDataCacheLast = nullptr; // points to most recently used item\nsint32 indexDataCacheEntryCount = 0;\n\nvoid _appendToUsageLinkedList(indexDataCacheEntry2_t* entry)\n{\n\tif (indexDataCacheLast == nullptr)\n\t{\n\t\tindexDataCacheLast = entry;\n\t\tindexDataCacheFirst = entry;\n\t\tentry->nextInMostRecentUsage = nullptr;\n\t\tentry->prevInMostRecentUsage = nullptr;\n\t}\n\telse\n\t{\n\t\tindexDataCacheLast->nextInMostRecentUsage = entry;\n\t\tentry->prevInMostRecentUsage = indexDataCacheLast;\n\t\tentry->nextInMostRecentUsage = nullptr;\n\t\tindexDataCacheLast = entry;\n\t}\n}\n\nvoid _removeFromUsageLinkedList(indexDataCacheEntry2_t* entry)\n{\n\tif (entry->prevInMostRecentUsage)\n\t{\n\t\tentry->prevInMostRecentUsage->nextInMostRecentUsage = entry->nextInMostRecentUsage;\n\t}\n\telse\n\t\tindexDataCacheFirst = entry->nextInMostRecentUsage;\n\tif (entry->nextInMostRecentUsage)\n\t{\n\t\tentry->nextInMostRecentUsage->prevInMostRecentUsage = entry->prevInMostRecentUsage;\n\t}\n\telse\n\t\tindexDataCacheLast = entry->prevInMostRecentUsage;\n\tentry->prevInMostRecentUsage = nullptr;\n\tentry->nextInMostRecentUsage = nullptr;\n}\n\nvoid _removeFromBucket(indexDataCacheEntry2_t* entry)\n{\n\tuint32 indexDataBucketIdx = (uint32)((entry->key.physAddr + entry->key.count) ^ (entry->key.physAddr >> 16)) % INDEX_DATA_CACHE_BUCKETS;\n\tif (indexDataCacheBucket[indexDataBucketIdx] == entry)\n\t{\n\t\tindexDataCacheBucket[indexDataBucketIdx] = entry->nextInBucket;\n\t\tentry->nextInBucket = nullptr;\n\t\treturn;\n\t}\n\tindexDataCacheEntry2_t* cacheEntryItr = indexDataCacheBucket[indexDataBucketIdx];\n\twhile (cacheEntryItr)\n\t{\n\t\tif (cacheEntryItr->nextInBucket == entry)\n\t\t{\n\t\t\tcacheEntryItr->nextInBucket = entry->nextInBucket;\n\t\t\tentry->nextInBucket = nullptr;\n\t\t\treturn;\n\t\t}\n\t\t// next\n\t\tcacheEntryItr = cacheEntryItr->nextInBucket;\n\t}\n}\n\nvoid _decodeAndUploadIndexData(indexDataCacheEntry2_t* cacheEntry)\n{\n\tuint32 count = cacheEntry->key.count;\n\tuint32 primitiveRestartIndex = cacheEntry->key.primitiveRestartIndex;\n\tif (cacheEntry->indexType == _INDEX_TYPE::U16_BE)\n\t{\n\t\t// 16bit indices\n\t\tuint16* indexInputU16 = (uint16*)memory_getPointerFromPhysicalOffset(cacheEntry->key.physAddr);\n\t\tuint16* indexOutputU16 = (uint16*)indexState.tempIndexStorage;\n\t\tcemu_assert_debug(count != 0);\n\t\tuint16 indexMinU16 = 0xFFFF;\n\t\tuint16 indexMaxU16 = 0;\n\t\tif (primitiveRestartIndex < 0x10000)\n\t\t{\n\t\t\t// with primitive restart index\n\t\t\tuint16 primitiveRestartIndexU16 = (uint16)primitiveRestartIndex;\n\t\t\tfor (uint32 i = 0; i < count; i++)\n\t\t\t{\n\t\t\t\tuint16 idxU16 = _swapEndianU16(*indexInputU16);\n\t\t\t\tindexInputU16++;\n\t\t\t\tif (primitiveRestartIndexU16 != idxU16)\n\t\t\t\t{\n\t\t\t\t\tindexMinU16 = std::min(indexMinU16, idxU16);\n\t\t\t\t\tindexMaxU16 = std::max(indexMaxU16, idxU16);\n\t\t\t\t}\n\t\t\t\t*indexOutputU16 = idxU16;\n\t\t\t\tindexOutputU16++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// without primitive restart index\n\t\t\tfor (uint32 i = 0; i < count; i++)\n\t\t\t{\n\t\t\t\tuint16 idxU16 = _swapEndianU16(*indexInputU16);\n\t\t\t\tindexInputU16++;\n\t\t\t\tindexMinU16 = std::min(indexMinU16, idxU16);\n\t\t\t\tindexMaxU16 = std::max(indexMaxU16, idxU16);\n\t\t\t\t*indexOutputU16 = idxU16;\n\t\t\t\tindexOutputU16++;\n\t\t\t}\n\t\t}\n\t\tcacheEntry->minIndex = indexMinU16;\n\t\tcacheEntry->maxIndex = indexMaxU16;\n\t\tglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, cacheEntry->heapEntry->startOffset, count * sizeof(uint16), indexState.tempIndexStorage);\n\t\tperformanceMonitor.cycle[performanceMonitor.cycleIndex].indexDataUploaded += (count * sizeof(uint16));\n\t}\n\telse if(cacheEntry->indexType == _INDEX_TYPE::U32_BE)\n\t{\n\t\t// 32bit indices\n\t\tuint32* indexInputU32 = (uint32*)memory_getPointerFromPhysicalOffset(cacheEntry->key.physAddr);\n\t\tuint32* indexOutputU32 = (uint32*)indexState.tempIndexStorage;\n\t\tcemu_assert_debug(count != 0);\n\t\tuint32 indexMinU32 = _swapEndianU32(*indexInputU32);\n\t\tuint32 indexMaxU32 = _swapEndianU32(*indexInputU32);\n\t\tfor (uint32 i = 0; i < count; i++)\n\t\t{\n\t\t\tuint32 idxU32 = _swapEndianU32(*indexInputU32);\n\t\t\tindexInputU32++;\n\t\t\tif (idxU32 != primitiveRestartIndex)\n\t\t\t{\n\t\t\t\tindexMinU32 = std::min(indexMinU32, idxU32);\n\t\t\t\tindexMaxU32 = std::max(indexMaxU32, idxU32);\n\t\t\t}\n\t\t\t*indexOutputU32 = idxU32;\n\t\t\tindexOutputU32++;\n\t\t}\n\t\tcacheEntry->minIndex = indexMinU32;\n\t\tcacheEntry->maxIndex = indexMaxU32;\n\t\tglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, cacheEntry->heapEntry->startOffset, count * sizeof(uint32), indexState.tempIndexStorage);\n\t\tperformanceMonitor.cycle[performanceMonitor.cycleIndex].indexDataUploaded += (count * sizeof(uint32));\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n}\n\n\nvoid LatteDraw_cleanupAfterFrame()\n{\n\t// drop everything from cache that is older than 30 frames\n\tuint32 frameCounter = LatteGPUState.frameCounter;\n\twhile (indexDataCacheFirst)\n\t{\n\t\tindexDataCacheEntry2_t* entry = indexDataCacheFirst;\n\t\tif ((frameCounter - entry->lastAccessFrameCount) < 30)\n\t\t\tbreak;\n\t\t// remove entry\n\t\tvirtualBufferHeap_free(indexState.indexBufferVirtualHeap, entry->heapEntry);\n\t\t_removeFromUsageLinkedList(entry);\n\t\t_removeFromBucket(entry);\n\t\tfree(entry);\n\t}\n}\n\nvoid LatteDrawGL_removeLeastRecentlyUsedIndexCacheEntries(sint32 count)\n{\n\twhile (indexDataCacheFirst && count > 0)\n\t{\n\t\tindexDataCacheEntry2_t* entry = indexDataCacheFirst;\n\t\t// remove entry\n\t\tvirtualBufferHeap_free(indexState.indexBufferVirtualHeap, entry->heapEntry);\n\t\t_removeFromUsageLinkedList(entry);\n\t\t_removeFromBucket(entry);\n\t\tfree(entry);\n\t\tcount--;\n\t}\n}\n\nuint32 LatteDrawGL_calculateIndexDataHash(uint8* data, uint32 size)\n{\n\tuint32 h = 0;\n\tif (size < 16)\n\t{\n\t\t// hash the bytes individually\n\t\twhile (size != 0)\n\t\t{\n\t\t\th += (uint32)*data;\n\t\t\tdata++;\n\t\t\tsize--;\n\t\t}\n\t\treturn h;\n\t}\n\t// first 16 bytes\n\th += *(uint32*)(data + 0);\n\th += *(uint32*)(data + 4);\n\th += *(uint32*)(data + 8);\n\th += *(uint32*)(data + 12);\n\t// last 16 bytes\n\tdata = data + ((size - 16)&~3);\n\th += *(uint32*)(data + 0);\n\th += *(uint32*)(data + 4);\n\th += *(uint32*)(data + 8);\n\th += *(uint32*)(data + 12);\n\treturn h;\n}\n\n// index handling with cache\n// todo - Outdated cache implementation. Update OpenGL renderer to use the generic implementation that is also used by the Vulkan renderer\nvoid LatteDrawGL_prepareIndicesWithGPUCache(MPTR indexDataMPTR, _INDEX_TYPE indexType, sint32 count, sint32 primitiveMode)\n{\n\tif (indexType == _INDEX_TYPE::AUTO)\n\t{\n\t\tindexState.minIndex = 0;\n\t\tindexState.maxIndex = count - 1;\n\t\t// since no indices are used we don't need to unbind the element array buffer\n\t\treturn; // automatic indices\n\t}\n\n\tOpenGLRenderer::SetArrayElementBuffer(indexState.glIndexCacheBuffer);\n\tuint32 indexDataBucketIdx = (uint32)((indexDataMPTR + count) ^ (indexDataMPTR >> 16)) % INDEX_DATA_CACHE_BUCKETS;\n\t// find matching entry\n\tuint32 primitiveRestartIndex = LatteGPUState.contextNew.VGT_MULTI_PRIM_IB_RESET_INDX.get_RESTART_INDEX();\n\tindexDataCacheEntry2_t* cacheEntryItr = indexDataCacheBucket[indexDataBucketIdx];\n\tindexDataCacheKey_t compareKey;\n\tcompareKey.physAddr = indexDataMPTR;\n\tcompareKey.count = count;\n\tcompareKey.primitiveMode = primitiveMode;\n\tcompareKey.primitiveRestartIndex = primitiveRestartIndex;\n\twhile (cacheEntryItr)\n\t{\n\t\tif (memcmp(&(cacheEntryItr->key), &compareKey, sizeof(compareKey)) != 0)\n\t\t{\n\t\t\t// next\n\t\t\tcacheEntryItr = cacheEntryItr->nextInBucket;\n\t\t\tcontinue;\n\t\t}\n\t\t// entry found\n\t\tindexState.minIndex = cacheEntryItr->minIndex;\n\t\tindexState.maxIndex = cacheEntryItr->maxIndex;\n\t\tindexState.indexData = (uint8*)(size_t)cacheEntryItr->heapEntry->startOffset;\n\t\tcacheEntryItr->lastAccessFrameCount = LatteGPUState.frameCounter;\n\t\t// check if the data changed\n\t\tuint32 h = LatteDrawGL_calculateIndexDataHash(memory_getPointerFromPhysicalOffset(indexDataMPTR), cacheEntryItr->physSize);\n\t\tif (cacheEntryItr->hash != h)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"IndexData hash changed\");\n\t\t\t_decodeAndUploadIndexData(cacheEntryItr);\n\t\t\tcacheEntryItr->hash = h;\n\t\t}\n\t\t// move entry to the front\n\t\t_removeFromUsageLinkedList(cacheEntryItr);\n\t\t_appendToUsageLinkedList(cacheEntryItr);\n\t\treturn;\n\t}\n\t// calculate size of index data in cache\n\tsint32 cacheIndexDataSize = 0;\n\tif (indexType == _INDEX_TYPE::U16_BE || indexType == _INDEX_TYPE::U16_LE)\n\t\tcacheIndexDataSize = count * sizeof(uint16);\n\telse\n\t\tcacheIndexDataSize = count * sizeof(uint32);\n\t// no matching entry, create new one\n\tVirtualBufferHeapEntry_t* heapEntry = virtualBufferHeap_allocate(indexState.indexBufferVirtualHeap, cacheIndexDataSize);\n\tif (heapEntry == nullptr)\n\t{\n\t\twhile (true)\n\t\t{\n\t\t\tLatteDrawGL_removeLeastRecentlyUsedIndexCacheEntries(10);\n\t\t\theapEntry = virtualBufferHeap_allocate(indexState.indexBufferVirtualHeap, cacheIndexDataSize);\n\t\t\tif (heapEntry != nullptr)\n\t\t\t\tbreak;\n\t\t\tif (indexDataCacheFirst == nullptr)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Unable to allocate entry in index cache\");\n\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t}\n\t}\n\tindexDataCacheEntry2_t* cacheEntry = (indexDataCacheEntry2_t*)malloc(sizeof(indexDataCacheEntry2_t));\n\tmemset(cacheEntry, 0, sizeof(indexDataCacheEntry2_t));\n\tcacheEntry->key.physAddr = indexDataMPTR;\n\tcacheEntry->physSize = (indexType == _INDEX_TYPE::U16_BE || indexType == _INDEX_TYPE::U16_LE) ? (count * sizeof(uint16)) : (count * sizeof(uint32));\n\tcacheEntry->hash = LatteDrawGL_calculateIndexDataHash(memory_getPointerFromPhysicalOffset(indexDataMPTR), cacheEntry->physSize);\n\tcacheEntry->key.count = count;\n\tcacheEntry->key.primitiveRestartIndex = primitiveRestartIndex;\n\tcacheEntry->indexType = indexType;\n\tcacheEntry->key.primitiveMode = primitiveMode;\n\tcacheEntry->heapEntry = heapEntry;\n\tcacheEntry->lastAccessFrameCount = LatteGPUState.frameCounter;\n\t// append entry in bucket list\n\tcacheEntry->nextInBucket = indexDataCacheBucket[indexDataBucketIdx];\n\tindexDataCacheBucket[indexDataBucketIdx] = cacheEntry;\n\t// append as most recently used entry\n\t_appendToUsageLinkedList(cacheEntry);\n\t// decode and upload the data\n\t_decodeAndUploadIndexData(cacheEntry);\n\n\tindexDataCacheEntryCount++;\n\tindexState.minIndex = cacheEntry->minIndex;\n\tindexState.maxIndex = cacheEntry->maxIndex;\n\tindexState.indexData = (uint8*)(size_t)cacheEntry->heapEntry->startOffset;\n}\n\nvoid LatteDraw_handleSpecialState8_clearAsDepth()\n{\n\tif (LatteGPUState.contextNew.GetSpecialStateValues()[0] == 0)\n\t\tcemuLog_logDebug(LogType::Force, \"Special state 8 requires special state 0 but it is not set?\");\n\t// get depth buffer information\n\tuint32 regDepthBuffer = LatteGPUState.contextRegister[mmDB_HTILE_DATA_BASE];\n\tuint32 regDepthSize = LatteGPUState.contextRegister[mmDB_DEPTH_SIZE];\n\tuint32 regDepthBufferInfo = LatteGPUState.contextRegister[mmDB_DEPTH_INFO];\n\t// get format and tileMode from info reg\n\tuint32 depthBufferTileMode = (regDepthBufferInfo >> 15) & 0xF;\n\n\tMPTR depthBufferPhysMem = regDepthBuffer << 8;\n\tuint32 depthBufferPitch = (((regDepthSize >> 0) & 0x3FF) + 1);\n\tuint32 depthBufferHeight = ((((regDepthSize >> 10) & 0xFFFFF) + 1) / depthBufferPitch);\n\tdepthBufferPitch <<= 3;\n\tdepthBufferHeight <<= 3;\n\tuint32 depthBufferWidth = depthBufferPitch;\n\n\tsint32 sliceIndex = 0; // todo\n\tsint32 mipIndex = 0;\n\n\t// clear all color buffers that match the format of the depth buffer\n\tsint32 searchIndex = 0;\n\tbool targetFound = false;\n\twhile (true)\n\t{\n\t\tLatteTextureView* view = LatteTC_LookupTextureByData(depthBufferPhysMem, depthBufferWidth, depthBufferHeight, depthBufferPitch, 0, 1, sliceIndex, 1, &searchIndex);\n\t\tif (!view)\n\t\t{\n\t\t\t// should we clear in RAM instead?\n\t\t\tbreak;\n\t\t}\n\t\tsint32 effectiveClearWidth = view->baseTexture->width;\n\t\tsint32 effectiveClearHeight = view->baseTexture->height;\n\t\tLatteTexture_scaleToEffectiveSize(view->baseTexture, &effectiveClearWidth, &effectiveClearHeight, 0);\n\n\t\t// hacky way to get clear color\n\t\tfloat* regClearColor = (float*)(LatteGPUState.contextRegister + 0xC000 + 0); // REG_BASE_ALU_CONST\n\n\t\tuint8 clearColor[4] = { 0 };\n\t\tclearColor[0] = (uint8)(regClearColor[0] * 255.0f);\n\t\tclearColor[1] = (uint8)(regClearColor[1] * 255.0f);\n\t\tclearColor[2] = (uint8)(regClearColor[2] * 255.0f);\n\t\tclearColor[3] = (uint8)(regClearColor[3] * 255.0f);\n\n\t\t// todo - use fragment shader software emulation (evoke for one pixel) to determine clear color\n\t\t// todo - dont clear entire slice, use effectiveClearWidth, effectiveClearHeight\n\n\t\tif (g_renderer->GetType() == RendererAPI::OpenGL)\n\t\t{\n\t\t\t//cemu_assert_debug(false); // implement g_renderer->texture_clearColorSlice properly for OpenGL renderer\n\t\t\tif (glClearTexSubImage)\n\t\t\t\tglClearTexSubImage(((LatteTextureViewGL*)view)->glTexId, mipIndex, 0, 0, 0, effectiveClearWidth, effectiveClearHeight, 1, GL_RGBA, GL_UNSIGNED_BYTE, clearColor);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (view->baseTexture->isDepth)\n\t\t\t\tg_renderer->texture_clearDepthSlice(view->baseTexture, sliceIndex + view->firstSlice, mipIndex + view->firstMip, true, view->baseTexture->hasStencil, 0.0f, 0);\n\t\t\telse\n\t\t\t\tg_renderer->texture_clearColorSlice(view->baseTexture, sliceIndex + view->firstSlice, mipIndex + view->firstMip, clearColor[0], clearColor[1], clearColor[2], clearColor[3]);\n\t\t}\n\t}\n}\n\nvoid LatteDrawGL_doDraw(_INDEX_TYPE indexType, uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count)\n{\n\tif (indexType == _INDEX_TYPE::U16_BE)\n\t{\n\t\t// 16bit index, big endian\n\t\tif (instanceCount > 1 || baseInstance != 0)\n\t\t{\n\t\t\tglDrawElementsInstancedBaseVertexBaseInstance(sGLActiveDrawMode, count, GL_UNSIGNED_SHORT, indexState.indexData, instanceCount, baseVertex, baseInstance);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (baseVertex != 0)\n\t\t\t\tglDrawRangeElementsBaseVertex(sGLActiveDrawMode, indexState.minIndex, indexState.maxIndex, count, GL_UNSIGNED_SHORT, indexState.indexData, baseVertex);\n\t\t\telse\n\t\t\t\tglDrawRangeElements(sGLActiveDrawMode, indexState.minIndex, indexState.maxIndex, count, GL_UNSIGNED_SHORT, indexState.indexData);\n\t\t}\n\t}\n\telse if (indexType == _INDEX_TYPE::U32_BE)\n\t{\n\t\t// 32bit index, big endian\n\t\tif (instanceCount > 1 || baseInstance != 0)\n\t\t{\n\t\t\t//debug_printf(\"Render instanced\\n\");\n\t\t\tglDrawElementsInstancedBaseVertexBaseInstance(sGLActiveDrawMode, count, GL_UNSIGNED_INT, indexState.indexData, instanceCount, baseVertex, baseInstance);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tglDrawRangeElementsBaseVertex(sGLActiveDrawMode, indexState.minIndex, indexState.maxIndex, count, GL_UNSIGNED_INT, indexState.indexData, baseVertex);\n\t\t}\n\t}\n\telse if (indexType == _INDEX_TYPE::AUTO)\n\t{\n\t\t// render without index (automatic index generation)\n\t\tcemu_assert_debug(baseInstance == 0);\n\t\tif (instanceCount > 1)\n\t\t\tglDrawArraysInstanced(sGLActiveDrawMode, baseVertex, count, instanceCount);\n\t\telse\n\t\t{\n\t\t\tglDrawArrays(sGLActiveDrawMode, baseVertex, count);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n}\n\nuint32 _glVertexBufferOffset[32] = { 0 };\n\nvoid OpenGLRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size)\n{\n\t_glVertexBufferOffset[bufferIndex] = offset;\n}\n\nvoid OpenGLRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size)\n{\n\tswitch (shaderType)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t\tbufferIndex += 0;\n\t\tbreak;\n\tcase LatteConst::ShaderType::Pixel:\n\t\tbufferIndex += 32;\n\t\tbreak;\n\tcase LatteConst::ShaderType::Geometry:\n\t\tbufferIndex += 64;\n\t\tbreak;\n\t}\n\n\tif (offset == 0 && size == 0)\n\t{\n\t\t// when binding NULL we just bind some arbitrary undefined data so the OpenGL driver is happy since a size of 0 is not allowed (should we bind a buffer filled with zeroes instead?)\n\t\tglBindBufferRange(GL_UNIFORM_BUFFER, bufferIndex, glAttributeCacheAB, 0, 32);\n\t\treturn;\n\t}\n\tglBindBufferRange(GL_UNIFORM_BUFFER, bufferIndex, glAttributeCacheAB, offset, size);\n}\n\nvoid LatteDraw_resetAttributePointerCache();\n\nvoid _resetAttributes(LatteParsedFetchShaderBufferGroup_t* attribGroup, bool* attributeArrayUsed)\n{\n\tfor (sint32 i = 0; i < attribGroup->attribCount; i++)\n\t{\n\t\tLatteParsedFetchShaderAttribute_t* attrib = attribGroup->attrib + i;\n\t\tsint32 attributeShaderLocation = attrib->semanticId; // we now bind to the semanticId instead\n\t\tattributeArrayUsed[attributeShaderLocation] = false;\n\t}\n}\n\nvoid OpenGLRenderer::_setupVertexAttributes()\n{\n\tLatteFetchShader* fetchShader = LatteSHRC_GetActiveFetchShader();\n\tLatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();\n\n\tcatchOpenGLError();\n\n\t// bind buffer\n\tattributeStream_bindVertexCacheBuffer();\n\n\tcatchOpenGLError();\n\tLatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader();\n\tbool attributeArrayUsed[32] = { 0 }; // used to keep track of enabled vertex attributes for this shader\n\tsint32 attributeDataIndex = 0;\n\tuint32 vboDataOffset = 0;\n\n\tbool tfBufferIsBound = false;\n\tsint32 maxReallocAttemptLimit = 1;\n\n\tfor(auto& bufferGroup : parsedFetchShader->bufferGroups)\n\t{\n\t\tuint32 bufferIndex = bufferGroup.attributeBufferIndex;\n\t\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n\t\tMPTR bufferAddress = LatteGPUState.contextRegister[bufferBaseRegisterIndex + 0];\n\t\tuint32 bufferSize = LatteGPUState.contextRegister[bufferBaseRegisterIndex + 1] + 1;\n\t\tuint32 bufferStride = (LatteGPUState.contextRegister[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;\n\n\t\tif (bufferAddress == MPTR_NULL)\n\t\t{\n\t\t\t_resetAttributes(&bufferGroup, attributeArrayUsed);\n\t\t\tcontinue;\n\t\t}\n\n\t\tvboDataOffset = _glVertexBufferOffset[bufferIndex];\n\n\t\tfor (sint32 i = 0; i < bufferGroup.attribCount; i++)\n\t\t{\n\t\t\tLatteParsedFetchShaderAttribute_t* attrib = bufferGroup.attrib + i;\n\t\t\tsint32 attributeShaderLocation = attrib->semanticId; // we now bind to the semanticId instead\n\n\t\t\tattributeShaderLocation = vertexShader->resourceMapping.getAttribHostShaderIndex(attrib->semanticId);\n\t\t\tif (attributeShaderLocation == -1)\n\t\t\t\tcontinue; // attribute not used\n\t\t\tif (attributeShaderLocation >= GPU_GL_MAX_NUM_ATTRIBUTE)\n\t\t\t\tcontinue;\n\t\t\tif (attributeArrayUsed[attributeShaderLocation] == true)\n\t\t\t{\n\t\t\t\tdebug_printf(\"Fetch shader attribute is bound multiple times\\n\");\n\t\t\t}\n\n\t\t\t// get buffer\n\t\t\tuint32 bufferIndex = attrib->attributeBufferIndex;\n\t\t\tcemu_assert_debug(bufferIndex < 0x10);\n\n\t\t\tcemu_assert_debug(attrib->fetchType == LatteConst::VERTEX_DATA || attrib->fetchType == LatteConst::INSTANCE_DATA); // unsupported fetch type\n\n\t\t\tSetAttributeArrayState(attributeShaderLocation, true, (bufferStride == 0) ? 99999999 : attrib->aluDivisor);\n\n\t\t\tuint8* bufferInput = memory_getPointerFromPhysicalOffset(bufferAddress) + attrib->offset;\n\t\t\tuint32 bufferSizeInput = bufferSize - attrib->offset;\n\n\t\t\tuint8* vboGLPtr;\n\t\t\tvboGLPtr = (uint8*)(size_t)(vboDataOffset + attrib->offset);\n\t\t\t_setAttributeBufferPointerRaw(attributeShaderLocation, NULL, 0, bufferStride, attrib, vboGLPtr, bufferStride);\n\n\t\t\tattributeArrayUsed[attributeShaderLocation] = true;\n\t\t\tattributeDataIndex++;\n\t\t\tcatchOpenGLError();\n\t\t}\n\t}\n\tfor (uint32 i = 0; i < GPU_GL_MAX_NUM_ATTRIBUTE; i++)\n\t{\n\t\tif (attributeArrayUsed[i] == false && glAttributeArrayIsEnabled[i] == true)\n\t\t\tSetAttributeArrayState(i, false, -1);\n\t}\n}\n\nvoid rectsEmulationGS_outputSingleVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 vIdx);\nvoid rectsEmulationGS_outputGeneratedVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, const char* variant);\nvoid rectsEmulationGS_outputVerticesCode(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 p0, sint32 p1, sint32 p2, sint32 p3, const char* variant, const LatteContextRegister& latteRegister);\n\nstd::map<uint64, RendererShaderGL*> g_mapGLRectEmulationGS;\n\nRendererShaderGL* rectsEmulationGS_generateShaderGL(LatteDecompilerShader* vertexShader)\n{\n\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\n\tstd::string gsSrc;\n\tgsSrc.append(\"#version 450\\r\\n\");\n\n\t// layout\n\tgsSrc.append(\"layout(triangles) in;\\r\\n\");\n\tgsSrc.append(\"layout(triangle_strip) out;\\r\\n\");\n\tgsSrc.append(\"layout(max_vertices = 4) out;\\r\\n\");\n\n\t// gl_PerVertex input\n\n\tgsSrc.append(\"in gl_PerVertex {\\r\\n\");\n\tgsSrc.append(\"vec4 gl_Position;\\r\\n\");\n\tgsSrc.append(\"} gl_in[];\\r\\n\");\n\n\t// gl_PerVertex output\n\n\tgsSrc.append(\"out gl_PerVertex {\\r\\n\");\n\tgsSrc.append(\"vec4 gl_Position;\\r\\n\");\n\tgsSrc.append(\"};\\r\\n\");\n\n\t// inputs & outputs\n\tauto parameterMask = vertexShader->outputParameterMask;\n\tfor (sint32 f = 0; f < 2; f++)\n\t{\n\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t{\n\t\t\tif ((parameterMask & (1 << i)) == 0)\n\t\t\t\tcontinue;\n\t\t\tsint32 vsSemanticId = psInputTable->getVertexShaderOutParamSemanticId(LatteGPUState.contextRegister, i);\n\t\t\tif (vsSemanticId < 0)\n\t\t\t\tcontinue;\n\t\t\tauto psImport = psInputTable->getPSImportBySemanticId(vsSemanticId);\n\t\t\tif (psImport == nullptr)\n\t\t\t\tcontinue;\n\n\t\t\tgsSrc.append(fmt::format(\"layout(location = {}) \", psInputTable->getPSImportLocationBySemanticId(vsSemanticId)));\n\t\t\tif (psImport->isFlat)\n\t\t\t\tgsSrc.append(\"flat \");\n\t\t\tif (psImport->isNoPerspective)\n\t\t\t\tgsSrc.append(\"noperspective \");\n\n\t\t\tif (f == 0)\n\t\t\t\tgsSrc.append(\"in\");\n\t\t\telse\n\t\t\t\tgsSrc.append(\"out\");\n\n\t\t\tif (f == 0)\n\t\t\t\tgsSrc.append(fmt::format(\" vec4 passParameterSem{}In[];\\r\\n\", vsSemanticId));\n\t\t\telse\n\t\t\t\tgsSrc.append(fmt::format(\" vec4 passParameterSem{}Out;\\r\\n\", vsSemanticId));\n\t\t}\n\t}\n\n\t// gen function\n\tgsSrc.append(\"vec4 gen4thVertexA(vec4 a, vec4 b, vec4 c)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\tgsSrc.append(\"return b - (c - a);\\r\\n\");\n\tgsSrc.append(\"}\\r\\n\");\n\n\tgsSrc.append(\"vec4 gen4thVertexB(vec4 a, vec4 b, vec4 c)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\tgsSrc.append(\"return c - (b - a);\\r\\n\");\n\tgsSrc.append(\"}\\r\\n\");\n\n\tgsSrc.append(\"vec4 gen4thVertexC(vec4 a, vec4 b, vec4 c)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\tgsSrc.append(\"return c + (b - a);\\r\\n\");\n\tgsSrc.append(\"}\\r\\n\");\n\n\t// main\n\tgsSrc.append(\"void main()\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\n\t// there are two possible winding orders that need different triangle generation:\n\t// 0 1\n\t// 2 3\n\t// and\n\t// 0 1\n\t// 3 2\n\t// all others are just symmetries of these cases\n\n\t// we can determine the case by comparing the distance 0<->1 and 0<->2\n\n\tgsSrc.append(\"float dist0_1 = length(gl_in[1].gl_Position.xy - gl_in[0].gl_Position.xy);\\r\\n\");\n\tgsSrc.append(\"float dist0_2 = length(gl_in[2].gl_Position.xy - gl_in[0].gl_Position.xy);\\r\\n\");\n\tgsSrc.append(\"float dist1_2 = length(gl_in[2].gl_Position.xy - gl_in[1].gl_Position.xy);\\r\\n\");\n\n\t// emit vertices\n\tgsSrc.append(\"if(dist0_1 > dist0_2 && dist0_1 > dist1_2)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\t// p0 to p1 is diagonal\n\trectsEmulationGS_outputVerticesCode(gsSrc, vertexShader, psInputTable, 2, 1, 0, 3, \"A\", LatteGPUState.contextNew);\n\tgsSrc.append(\"} else if ( dist0_2 > dist0_1 && dist0_2 > dist1_2 ) {\\r\\n\");\n\t// p0 to p2 is diagonal\n\trectsEmulationGS_outputVerticesCode(gsSrc, vertexShader, psInputTable, 1, 2, 0, 3, \"B\", LatteGPUState.contextNew);\n\tgsSrc.append(\"} else {\\r\\n\");\n\t// p1 to p2 is diagonal\n\trectsEmulationGS_outputVerticesCode(gsSrc, vertexShader, psInputTable, 0, 1, 2, 3, \"C\", LatteGPUState.contextNew);\n\tgsSrc.append(\"}\\r\\n\");\n\n\tgsSrc.append(\"}\\r\\n\");\n\n\tauto glShader = new RendererShaderGL(RendererShader::ShaderType::kGeometry, 0, 0, false, false, gsSrc);\n\tglShader->PreponeCompilation(true);\n\n\treturn glShader;\n}\n\nRendererShaderGL* rectsEmulationGS_getShaderGL(LatteDecompilerShader* vertexShader)\n{\n\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\n\tuint64 h = vertexShader->baseHash + psInputTable->key;\n\n\tauto itr = g_mapGLRectEmulationGS.find(h);\n\tif (itr != g_mapGLRectEmulationGS.end())\n\t\treturn (*itr).second;\n\n\tauto glShader = rectsEmulationGS_generateShaderGL(vertexShader);\n\n\tg_mapGLRectEmulationGS.emplace(h, glShader);\n\treturn glShader;\n}\n\nuint32 sPrevTextureReadbackDrawcallUpdate = 0;\n\ntemplate<bool TIsMinimal, bool THasProfiling>\nvoid OpenGLRenderer::draw_genericDrawHandler(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType)\n{\n\tReleaseBufferCacheEntries();\n\n\tcatchOpenGLError();\n\tvoid* indexData = indexDataMPTR != MPTR_NULL ? memory_getPointerFromPhysicalOffset(indexDataMPTR) : NULL;\n\tauto primitiveMode = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();\n\t// handle special state 8 (clear as depth)\n\tif (LatteGPUState.contextNew.GetSpecialStateValues()[8] != 0)\n\t{\n\t\tLatteDraw_handleSpecialState8_clearAsDepth();\n\t\tLatteGPUState.drawCallCounter++;\n\t\treturn;\n\t}\n\n\t// update shaders and uniforms\n\tif constexpr (!TIsMinimal)\n\t{\n\t\tbeginPerfMonProfiling(performanceMonitor.gpuTime_dcStageShaderAndUniformMgr);\n\t\tLatteSHRC_UpdateActiveShaders();\n\t\tLatteDecompilerShader* vs = (LatteDecompilerShader*)LatteSHRC_GetActiveVertexShader();\n\t\tLatteDecompilerShader* gs = (LatteDecompilerShader*)LatteSHRC_GetActiveGeometryShader();\n\t\tLatteDecompilerShader* ps = (LatteDecompilerShader*)LatteSHRC_GetActivePixelShader();\n\t\tif (vs)\n\t\t\tshader_bind(vs->shader);\n\t\telse\n\t\t\tshader_unbind(RendererShader::ShaderType::kVertex);\n\t\tif (ps && LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] == 0)\n\t\t\tshader_bind(ps->shader);\n\t\telse\n\t\t\tshader_unbind(RendererShader::ShaderType::kFragment);\n\t\tif (gs)\n\t\t\tshader_bind(gs->shader);\n\t\telse\n\t\t\tshader_unbind(RendererShader::ShaderType::kGeometry);\n\t\tendPerfMonProfiling(performanceMonitor.gpuTime_dcStageShaderAndUniformMgr);\n\t}\n\tif (LatteGPUState.activeShaderHasError)\n\t{\n\t\tdebug_printf(\"Skipped drawcall due to shader error\\n\");\n\t\treturn;\n\t}\n\t// check for blacklisted shaders\n\tuint64 vsShaderHash = 0;\n\tif (LatteSHRC_GetActiveVertexShader())\n\t\tvsShaderHash = LatteSHRC_GetActiveVertexShader()->baseHash;\n\tuint64 psShaderHash = 0;\n\tif (LatteSHRC_GetActivePixelShader())\n\t\tpsShaderHash = LatteSHRC_GetActivePixelShader()->baseHash;\n\n\t// setup streamout (if enabled)\n\tbool rasterizerEnable = LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_DX_RASTERIZATION_KILL() == false;\n\tif (!LatteGPUState.contextNew.PA_CL_VTE_CNTL.get_VPORT_X_OFFSET_ENA())\n\t\trasterizerEnable = true;\n\n\tbool streamoutEnable = LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] != 0;\n\tif (streamoutEnable)\n\t{\n\t\tif (glBeginTransformFeedback == nullptr)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn; // transform feedback not supported\n\t\t}\n\t}\n\t// skip draw if output is not used\n\tif (rasterizerEnable == false && streamoutEnable == false)\n\t{\n\t\t// rasterizer and streamout disabled\n\t\tLatteGPUState.drawCallCounter++;\n\t\treturn;\n\t}\n\t// get primitive\n\tif (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLES)\n\t\tsGLActiveDrawMode = GL_TRIANGLES;\n\telse if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLE_STRIP)\n\t\tsGLActiveDrawMode = GL_TRIANGLE_STRIP;\n\telse if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUADS)\n\t\tsGLActiveDrawMode = GL_QUADS;\n\telse if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLE_FAN)\n\t\tsGLActiveDrawMode = GL_TRIANGLE_FAN;\n\telse if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS)\n\t\tsGLActiveDrawMode = GL_TRIANGLES;\n\telse if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::POINTS)\n\t\tsGLActiveDrawMode = GL_POINTS;\n\telse if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINES)\n\t\tsGLActiveDrawMode = GL_LINES;\n\telse if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINE_STRIP)\n\t\tsGLActiveDrawMode = GL_LINE_STRIP;\n\telse if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINE_LOOP)\n\t\tsGLActiveDrawMode = GL_LINE_LOOP;\n\telse if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUAD_STRIP)\n\t\tsGLActiveDrawMode = GL_QUAD_STRIP;\n\telse\n\t{\n\t\tcemu_assert_debug(false); // unsupported primitive type\n\t\tLatteGPUState.drawCallCounter++;\n\t\treturn;\n\t}\n\n\tif constexpr (!TIsMinimal)\n\t{\n\t\t// update render targets and textures\n\t\tLatteGPUState.requiresTextureBarrier = false;\n\t\tbeginPerfMonProfiling(performanceMonitor.gpuTime_dcStageTextures);\n\t\twhile (true)\n\t\t{\n\t\t\tLatteGPUState.repeatTextureInitialization = false;\n\t\t\tif (streamoutEnable == false)\n\t\t\t{\n\t\t\t\t// only handle rendertargets if streamout is inactive\n\t\t\t\tif (LatteMRT::UpdateCurrentFBO() == false)\n\t\t\t\t\treturn; // no render target\n\t\t\t\tif (hasValidFramebufferAttached == false)\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t\tLatteTexture_updateTextures(); // caution: Do not call any functions that potentially modify texture bindings after this line\n\t\t\tif (LatteGPUState.repeatTextureInitialization == false)\n\t\t\t\tbreak;\n\t\t\tcatchOpenGLError();\n\t\t}\n\t\tendPerfMonProfiling(performanceMonitor.gpuTime_dcStageTextures);\n\n\t\tbeginPerfMonProfiling(performanceMonitor.gpuTime_dcStageMRT);\n\t\tLatteMRT::ApplyCurrentState();\n\t\tendPerfMonProfiling(performanceMonitor.gpuTime_dcStageMRT);\n\n\t\t// texture barrier for write-read patterns\n\t\tif (LatteGPUState.requiresTextureBarrier && glTextureBarrier)\n\t\t{\n\t\t\tglTextureBarrier();\n\t\t}\n\n\t}\n\n\tcatchOpenGLError();\n\t// handle RECT primitive\n\tif (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS)\n\t{\n\t\tRendererShaderGL* rectsEmulationShader = rectsEmulationGS_getShaderGL(LatteSHRC_GetActiveVertexShader());\n\t\tshader_bind(rectsEmulationShader);\n\t}\n\n\t// prepare index cache\n\tbeginPerfMonProfiling(performanceMonitor.gpuTime_dcStageIndexMgr);\n\tLatteDrawGL_prepareIndicesWithGPUCache(indexDataMPTR, indexType, count, (sint32)primitiveMode);\n\tendPerfMonProfiling(performanceMonitor.gpuTime_dcStageIndexMgr);\n\n\t// synchronize vertex and uniform buffers\n\tLatteBufferCache_Sync(indexState.minIndex + baseVertex, indexState.maxIndex + baseVertex, baseInstance, instanceCount);\n\n\t_setupVertexAttributes();\n\n\t// update renderstate\n\tLatteRenderTarget_updateViewport();\n\tLatteRenderTarget_updateScissorBox();\n\trenderstate_updateBlendingAndColorControl();\n\tcatchOpenGLError();\n\t// handle special state 5 (convert depth to color)\n\tif (LatteGPUState.contextNew.GetSpecialStateValues()[5] != 0)\n\t{\n\t\tdebug_printf(\"GPU7 special state 5 used\\n\");\n\t\tLatteTextureView* rt_color = LatteMRT::GetColorAttachment(0);\n\t\tLatteTextureView* rt_depth = LatteMRT::GetDepthAttachment();\n\t\tif (!rt_depth || !rt_color)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"GPU7 special state 5 used but render target not setup correctly\");\n\t\t\treturn;\n\t\t}\n\t\tsurfaceCopy_copySurfaceWithFormatConversion(rt_depth->baseTexture, rt_depth->firstMip, rt_depth->firstSlice, rt_color->baseTexture, rt_color->firstMip, rt_color->firstSlice, rt_depth->baseTexture->width, rt_depth->baseTexture->height);\n\t\tLatteGPUState.drawCallCounter++;\n\t\treturn;\n\t}\n\n\tbeginPerfMonProfiling(performanceMonitor.gpuTime_dcStageShaderAndUniformMgr);\n\t// update uniform values\n\tuniformData_update();\n\tendPerfMonProfiling(performanceMonitor.gpuTime_dcStageShaderAndUniformMgr);\n\tcatchOpenGLError();\n\t// upload special uniforms\n\tLatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();\n\tLatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();\n\tLatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader();\n\tif (vertexShader)\n\t{\n\t\tauto vertexShaderGL = (RendererShaderGL*)vertexShader->shader;\n\t\tif (vertexShader->uniform.loc_windowSpaceToClipSpaceTransform >= 0)\n\t\t{\n\t\t\tsint32 viewportWidth;\n\t\t\tsint32 viewportHeight;\n\t\t\tLatteRenderTarget_GetCurrentVirtualViewportSize(&viewportWidth, &viewportHeight); // always call after _updateViewport()\n\t\t\tfloat t[2];\n\t\t\tt[0] = 2.0f / (float)viewportWidth;\n\t\t\tt[1] = 2.0f / (float)viewportHeight;\n\t\t\tglProgramUniform2fv(vertexShaderGL->GetProgram(), vertexShader->uniform.loc_windowSpaceToClipSpaceTransform, 1, t);\n\t\t}\n\t\t// update uf_texRescaleFactors\n\t\tfor (auto& entry : vertexShader->uniform.list_ufTexRescale)\n\t\t{\n\t\t\tfloat* xyScale = LatteTexture_getEffectiveTextureScale(LatteConst::ShaderType::Vertex, entry.texUnit);\n\t\t\tif (memcmp(entry.currentValue, xyScale, sizeof(float) * 2) == 0)\n\t\t\t\tcontinue; // value unchanged\n\t\t\tmemcpy(entry.currentValue, xyScale, sizeof(float) * 2);\n\t\t\tglProgramUniform2fv(vertexShaderGL->GetProgram(), entry.uniformLocation, 1, xyScale);\n\t\t}\n\t\t// update uf_pointSize\n\t\tif (vertexShader->uniform.loc_pointSize >= 0)\n\t\t{\n\t\t\tfloat t[1];\n\t\t\tfloat pointWidth = (float)LatteGPUState.contextNew.PA_SU_POINT_SIZE.get_WIDTH() / 8.0f;\n\t\t\tif (pointWidth == 0.0f)\n\t\t\t\tpointWidth = 1.0f / 8.0f; // minimum size\n\t\t\tt[0] = pointWidth;\n\t\t\tglProgramUniform1fv(vertexShaderGL->GetProgram(), vertexShader->uniform.loc_pointSize, 1, t);\n\t\t}\n\t}\n\tif (geometryShader)\n\t{\n\t\tauto geometryShaderGL = (RendererShaderGL*)geometryShader->shader;\n\t\t// update uf_texRescaleFactors\n\t\tfor (auto& entry : geometryShader->uniform.list_ufTexRescale)\n\t\t{\n\t\t\tfloat* xyScale = LatteTexture_getEffectiveTextureScale(LatteConst::ShaderType::Geometry, entry.texUnit);\n\t\t\tif (memcmp(entry.currentValue, xyScale, sizeof(float) * 2) == 0)\n\t\t\t\tcontinue; // value unchanged\n\t\t\tmemcpy(entry.currentValue, xyScale, sizeof(float) * 2);\n\t\t\tglProgramUniform2fv(geometryShaderGL->GetProgram(), entry.uniformLocation, 1, xyScale);\n\t\t}\n\t\t// update uf_pointSize\n\t\tif (geometryShader->uniform.loc_pointSize >= 0)\n\t\t{\n\t\t\tfloat t[1];\n\t\t\tfloat pointWidth = (float)LatteGPUState.contextNew.PA_SU_POINT_SIZE.get_WIDTH() / 8.0f;\n\t\t\tif (pointWidth == 0.0f)\n\t\t\t\tpointWidth = 1.0f / 8.0f; // minimum size\n\t\t\tt[0] = pointWidth;\n\t\t\tglProgramUniform1fv(geometryShaderGL->GetProgram(), geometryShader->uniform.loc_pointSize, 1, t);\n\t\t}\n\t}\n\tif (pixelShader)\n\t{\n\t\tauto pixelShaderGL = (RendererShaderGL*)pixelShader->shader;\n\t\tif (pixelShader->uniform.loc_alphaTestRef >= 0)\n\t\t{\n\t\t\tfloat t[1];\n\t\t\tt[0] = LatteGPUState.contextNew.SX_ALPHA_REF.get_ALPHA_TEST_REF();\n\t\t\tif (pixelShader->uniform.ufCurrentValueAlphaTestRef != t[0])\n\t\t\t{\n\t\t\t\tglProgramUniform1fv(pixelShaderGL->GetProgram(), pixelShader->uniform.loc_alphaTestRef, 1, t);\n\t\t\t\tpixelShader->uniform.ufCurrentValueAlphaTestRef = t[0];\n\t\t\t}\n\t\t}\n\t\t// update uf_fragCoordScale\n\t\tif (pixelShader->uniform.loc_fragCoordScale >= 0)\n\t\t{\n\t\t\tfloat coordScale[4];\n\t\t\tLatteMRT::GetCurrentFragCoordScale(coordScale);\n\t\t\tif (pixelShader->uniform.ufCurrentValueFragCoordScale[0] != coordScale[0] || pixelShader->uniform.ufCurrentValueFragCoordScale[1] != coordScale[1])\n\t\t\t{\n\t\t\t\tglProgramUniform2fv(pixelShaderGL->GetProgram(), pixelShader->uniform.loc_fragCoordScale, 1, coordScale);\n\t\t\t\tpixelShader->uniform.ufCurrentValueFragCoordScale[0] = coordScale[0];\n\t\t\t\tpixelShader->uniform.ufCurrentValueFragCoordScale[1] = coordScale[1];\n\t\t\t}\n\t\t}\n\t\t// update uf_texRescaleFactors\n\t\tfor (auto& entry : pixelShader->uniform.list_ufTexRescale)\n\t\t{\n\t\t\tfloat* xyScale = LatteTexture_getEffectiveTextureScale(LatteConst::ShaderType::Pixel, entry.texUnit);\n\t\t\tif (memcmp(entry.currentValue, xyScale, sizeof(float) * 2) == 0)\n\t\t\t\tcontinue; // value unchanged\n\t\t\tmemcpy(entry.currentValue, xyScale, sizeof(float) * 2);\n\t\t\tglProgramUniform2fv(pixelShaderGL->GetProgram(), entry.uniformLocation, 1, xyScale);\n\t\t}\n\t}\n\tcatchOpenGLError();\n\t// prepare streamout\n\tLatteStreamout_PrepareDrawcall(count, instanceCount);\n\n\tif (streamoutEnable && rasterizerEnable)\n\t{\n\t\tif (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUADS)\n\t\t\tsGLActiveDrawMode = GL_POINTS;\n\t}\n\tcatchOpenGLError();\n\t// render\n\tbeginPerfMonProfiling(performanceMonitor.gpuTime_dcStageDrawcallAPI);\n\tLatteDrawGL_doDraw(indexType, baseVertex, baseInstance, instanceCount, count);\n\tendPerfMonProfiling(performanceMonitor.gpuTime_dcStageDrawcallAPI);\n\t// post-drawcall logic\n\tif(pixelShader)\n\t\tLatteRenderTarget_trackUpdates();\n\tLatteStreamout_FinishDrawcall(false);\n\tcatchOpenGLError();\n\n\tif (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS)\n\t\tshader_unbind(RendererShader::ShaderType::kGeometry);\n\n\tLatteGPUState.drawCallCounter++;\n\tif (streamoutEnable && rasterizerEnable)\n\t{\n\t\t// streamout and rasterizer enabled, repeat drawcall with streamout disabled\n\t\tuint32 strmOutEnOrg = LatteGPUState.contextRegister[mmVGT_STRMOUT_EN];\n\t\tLatteGPUState.contextRegister[mmVGT_STRMOUT_EN] = 0;\n\t\tdraw_genericDrawHandler<false, THasProfiling>(baseVertex, baseInstance, instanceCount, count, indexDataMPTR, indexType);\n\t\tLatteGPUState.contextRegister[mmVGT_STRMOUT_EN] = strmOutEnOrg;\n\t\treturn;\n\t}\n\tLatteTextureReadback_Update();\n\tuint32 dcSinceLastReadbackCheck = LatteGPUState.drawCallCounter - sPrevTextureReadbackDrawcallUpdate;\n\tif (dcSinceLastReadbackCheck >= 150)\n\t{\n\t\tLatteTextureReadback_UpdateFinishedTransfers(false);\n\t\tsPrevTextureReadbackDrawcallUpdate = LatteGPUState.drawCallCounter;\n\t}\t\n\tcatchOpenGLError();\n}\n\nvoid OpenGLRenderer::draw_beginSequence()\n{\n\t// no-op\n}\n\nvoid OpenGLRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst)\n{\n\tbool isMinimal = !isFirst;\n    if (isMinimal)\n        draw_genericDrawHandler<true, false>(baseVertex, baseInstance, instanceCount, count, indexDataMPTR, indexType);\n    else\n        draw_genericDrawHandler<false, false>(baseVertex, baseInstance, instanceCount, count, indexDataMPTR, indexType);\n}\n\nvoid OpenGLRenderer::draw_endSequence()\n{\n\t// no-op\n}\n\n#define GPU7_INDEX_BUFFER_CACHE_SIZE_DEPR\t\t(18*1024*1024) // 18MB\n\nvoid OpenGLRenderer::draw_init()\n{\n\tif (indexState.initialized)\n\t\treturn;\n\tindexState.initialized = true;\n\t// create index buffer\n\tglGenBuffers(1, &indexState.glIndexCacheBuffer);\n\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexState.glIndexCacheBuffer);\n\tglBufferData(GL_ELEMENT_ARRAY_BUFFER, GPU7_INDEX_BUFFER_CACHE_SIZE_DEPR, NULL, GL_DYNAMIC_DRAW);\n#if BOOST_OS_WINDOWS\n\tindexState.mappedIndexBuffer = (uint8*)_aligned_malloc(GPU7_INDEX_BUFFER_CACHE_SIZE_DEPR, 256);\n#else\n\tindexState.mappedIndexBuffer = (uint8*)aligned_alloc(256, GPU7_INDEX_BUFFER_CACHE_SIZE_DEPR);\n#endif\n\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\tindexState.indexRingBuffer = LatteRingBuffer_create(indexState.mappedIndexBuffer, GPU7_INDEX_BUFFER_CACHE_SIZE_DEPR);\n\tindexState.tempIndexStorage = (uint8*)malloc(1024 * 1024 * 8);\n\t// create virtual heap for index buffer\n\tindexState.indexBufferVirtualHeap = virtualBufferHeap_create(GPU7_INDEX_BUFFER_CACHE_SIZE_DEPR);\n}\n\nvoid OpenGLRenderer::bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset)\n{\n\tattributeStream_bindVertexCacheBuffer();\n\tglBufferSubData(GL_ARRAY_BUFFER, bufferOffset, size, buffer);\n}\n\nvoid OpenGLRenderer::bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size)\n{\n\tattributeStream_bindVertexCacheBuffer();\n\tglCopyBufferSubData(GL_ARRAY_BUFFER, GL_ARRAY_BUFFER, srcOffset, dstOffset, size);\n}\n\n\nGLint glClampTable[] =\n{\n\tGL_REPEAT,\n\tGL_MIRRORED_REPEAT,\n\tGL_CLAMP_TO_EDGE,\n\tGL_MIRROR_CLAMP_TO_EDGE,\n\tGL_CLAMP_TO_EDGE,\n\tGL_MIRROR_CLAMP_TO_BORDER_EXT,\n\tGL_CLAMP_TO_BORDER,\n\tGL_MIRROR_CLAMP_TO_BORDER_EXT\n};\n\nGLint glCompSelTable[8] =\n{\n\tGL_RED,\n\tGL_GREEN,\n\tGL_BLUE,\n\tGL_ALPHA,\n\tGL_ZERO,\n\tGL_ONE,\n\t0,\n\t0\n};\n\nGLint glDepthCompareTable[8] = {\n\tGL_NEVER,\n\tGL_LESS,\n\tGL_EQUAL,\n\tGL_LEQUAL,\n\tGL_GREATER,\n\tGL_NOTEQUAL,\n\tGL_GEQUAL,\n\tGL_ALWAYS\n};\n\n// Remaps component selection if the underlying OpenGL texture format would behave differently than it's GPU7 counterpart\nuint32 _correctTextureCompSelGL(Latte::E_GX2SURFFMT format, uint32 compSel)\n{\n\tswitch (format)\n\t{\n\tcase Latte::E_GX2SURFFMT::R8_UNORM: // R8 is replicated on all channels (while OpenGL would return 1.0 for BGA instead)\n\tcase Latte::E_GX2SURFFMT::R8_SNORM: // probably the same as _UNORM, but needs testing\n\t\tif (compSel >= 1 && compSel <= 3)\n\t\t\tcompSel = 0;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM: // order of components is reversed (RGBA -> ABGR)\n\t\tif (compSel >= 0 && compSel <= 3)\n\t\t\tcompSel = 3 - compSel;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::BC4_UNORM:\n\tcase Latte::E_GX2SURFFMT::BC4_SNORM:\n\t\tif (compSel >= 1 && compSel <= 3)\n\t\t\tcompSel = 0;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::BC5_UNORM:\n\tcase Latte::E_GX2SURFFMT::BC5_SNORM:\n\t\t// RG maps to RG\n\t\t// B maps to ?\n\t\t// A maps to G (guessed)\n\t\tif (compSel == 3)\n\t\t\tcompSel = 1; // read Alpha as Green\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::A2_B10_G10_R10_UNORM:\n\t\t// reverse components (Wii U: ABGR, OpenGL: RGBA)\n\t\t// used in Resident Evil Revelations\n\t\tif (compSel >= 0 && compSel <= 3)\n\t\t\tcompSel = 3 - compSel;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::X24_G8_UINT:\n\t\t// map everything to alpha?\n\t\tif (compSel >= 0 && compSel <= 3)\n\t\t\tcompSel = 3;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\treturn compSel;\n}\n\n#define quickBindTexture() \t\tif( textureIsActive == false ) { texture_bindAndActivate(hostTextureView, hostTextureUnit); textureIsActive = true; }\n\nuint32 _getGLMinFilter(Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER filterMin, Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER filterMip)\n{\n\tbool isMinPointFilter = (filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::POINT) || (filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::ANISO_POINT);\n\n\tif (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::NONE)\n\t{\n\t\t// no mip\n\t\treturn isMinPointFilter ? GL_NEAREST : GL_LINEAR;\n\t}\n\telse if (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::POINT)\n\t{\n\t\t// nearest neighbor\n\t\treturn isMinPointFilter ? GL_NEAREST_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_NEAREST;\n\t}\n\t// else -> filterMip == LINEAR\n\treturn isMinPointFilter ? GL_NEAREST_MIPMAP_LINEAR : GL_LINEAR_MIPMAP_LINEAR;\n}\n\n/*\n* Update channel swizzling and other texture settings for a texture unit\n* hostTextureView is the texture unit view used on the host side\n*/\nvoid OpenGLRenderer::renderstate_updateTextureSettingsGL(LatteDecompilerShader* shaderContext, LatteTextureView* _hostTextureView, uint32 hostTextureUnit, const Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N texUnitWord4, uint32 texUnitIndex, bool isDepthSampler)\n{\n\tauto hostTextureView = (LatteTextureViewGL*)_hostTextureView;\n\n\tLatteTexture* baseTexture = hostTextureView->baseTexture;\n\t// get texture register word 0\n\tcatchOpenGLError();\n\tbool textureIsActive = false;\n\n\tuint32 compSelR = (uint32)texUnitWord4.get_DST_SEL_X();\n\tuint32 compSelG = (uint32)texUnitWord4.get_DST_SEL_Y();\n\tuint32 compSelB = (uint32)texUnitWord4.get_DST_SEL_Z();\n\tuint32 compSelA = (uint32)texUnitWord4.get_DST_SEL_W();\n\t// on OpenGL some channels might be mapped differently\n\tcompSelR = _correctTextureCompSelGL(hostTextureView->format, compSelR);\n\tcompSelG = _correctTextureCompSelGL(hostTextureView->format, compSelG);\n\tcompSelB = _correctTextureCompSelGL(hostTextureView->format, compSelB);\n\tcompSelA = _correctTextureCompSelGL(hostTextureView->format, compSelA);\n\t// update swizzle parameters\n\tif (hostTextureView->swizzleR != compSelR)\n\t{\n\t\tquickBindTexture();\n\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_SWIZZLE_R, glCompSelTable[compSelR]);\n\t\thostTextureView->swizzleR = compSelR;\n\t}\n\tif (hostTextureView->swizzleG != compSelG)\n\t{\n\t\tquickBindTexture();\n\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_SWIZZLE_G, glCompSelTable[compSelG]);\n\t\thostTextureView->swizzleG = compSelG;\n\t}\n\tif (hostTextureView->swizzleB != compSelB)\n\t{\n\t\tquickBindTexture();\n\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_SWIZZLE_B, glCompSelTable[compSelB]);\n\t\thostTextureView->swizzleB = compSelB;\n\t}\n\tif (hostTextureView->swizzleA != compSelA)\n\t{\n\t\tquickBindTexture();\n\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_SWIZZLE_A, glCompSelTable[compSelA]);\n\t\thostTextureView->swizzleA = compSelA;\n\t}\n\tcatchOpenGLError();\n\n\tuint32 stageSamplerIndex = shaderContext->textureUnitSamplerAssignment[texUnitIndex];\n\tif (stageSamplerIndex != LATTE_DECOMPILER_SAMPLER_NONE)\n\t{\n\t\tuint32 samplerIndex = stageSamplerIndex;\n\t\tsamplerIndex += LatteDecompiler_getTextureSamplerBaseIndex(shaderContext->shaderType);\n\n\t\tconst _LatteRegisterSetSampler* samplerWords = LatteGPUState.contextNew.SQ_TEX_SAMPLER + samplerIndex;\n\n\t\tauto filterMag = samplerWords->WORD0.get_XY_MAG_FILTER();\n\t\tauto filterMin = samplerWords->WORD0.get_XY_MAG_FILTER();\n\t\t//auto filterZ = samplerWords->WORD0.get_Z_FILTER();\n\t\tauto filterMip = samplerWords->WORD0.get_MIP_FILTER();\n\n\t\t// get OpenGL constant for min filter\n\t\tuint32 filterMinGL = _getGLMinFilter(filterMin, filterMip);\n\t\tuint32 filterMagGL = (filterMag == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::POINT || filterMag == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::ANISO_POINT) ? GL_NEAREST : GL_LINEAR;\n\n\t\t// todo: z-filter is customizable for GPU7 but OpenGL doesn't offer the same functionality?\n\n\t\tLatteSamplerState* samplerState = &hostTextureView->samplerState;\n\n\t\tcatchOpenGLError();\n\n\t\tuint32 clampX = (uint32)samplerWords->WORD0.get_CLAMP_X();\n\t\tuint32 clampY = (uint32)samplerWords->WORD0.get_CLAMP_Y();\n\t\tuint32 clampZ = (uint32)samplerWords->WORD0.get_CLAMP_Z();\n\t\tif (samplerState->clampS != clampX)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_WRAP_S, glClampTable[clampX]);\n\t\t\tsamplerState->clampS = clampX;\n\t\t}\n\t\tif (samplerState->clampT != clampY)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_WRAP_T, glClampTable[clampY]);\n\t\t\tsamplerState->clampT = clampY;\n\t\t}\n\t\tif (samplerState->clampR != clampZ)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_WRAP_R, glClampTable[clampZ]);\n\t\t\tsamplerState->clampR = clampZ;\n\t\t}\n\t\tcatchOpenGLError();\n\n\t\tuint32 maxAniso = (uint32)samplerWords->WORD0.get_MAX_ANISO_RATIO();\n\n\t\tif (baseTexture->overwriteInfo.anisotropicLevel >= 0)\n\t\t\tmaxAniso = baseTexture->overwriteInfo.anisotropicLevel;\n\n\t\tif (samplerState->maxAniso != maxAniso)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameterf(hostTextureView->glTexTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)(1 << maxAniso));\n\t\t\tsamplerState->maxAniso = maxAniso;\n\t\t\tcatchOpenGLError();\n\t\t}\n\t\tif (samplerState->filterMin != filterMinGL)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_MIN_FILTER, filterMinGL);\n\t\t\tsamplerState->filterMin = filterMinGL;\n\t\t\tcatchOpenGLError();\n\t\t}\n\n\t\tif (samplerState->filterMag != filterMagGL)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_MAG_FILTER, filterMagGL);\n\t\t\tsamplerState->filterMag = filterMagGL;\n\t\t\tcatchOpenGLError();\n\t\t}\n\t\tif (samplerState->maxMipLevels != hostTextureView->numMip)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_MAX_LEVEL, std::max(hostTextureView->numMip, 1) - 1);\n\t\t\tsamplerState->maxMipLevels = hostTextureView->numMip;\n\t\t\tcatchOpenGLError();\n\t\t}\n\t\t// lod\n\t\tuint32 iMinLOD = samplerWords->WORD1.get_MIN_LOD();\n\t\tuint32 iMaxLOD = samplerWords->WORD1.get_MAX_LOD();\n\t\tsint32 iLodBias = samplerWords->WORD1.get_LOD_BIAS();\n\n\t\t// apply relative lod bias from graphic pack\n\t\tif (baseTexture->overwriteInfo.hasRelativeLodBias)\n\t\t{\n\t\t\tiLodBias += baseTexture->overwriteInfo.relativeLodBias;\n\t\t}\n\t\t// apply absolute lod bias from graphic pack\n\t\tif (baseTexture->overwriteInfo.hasLodBias)\n\t\t{\n\t\t\tiLodBias = baseTexture->overwriteInfo.lodBias;\n\t\t}\n\n\t\tif (samplerState->minLod != iMinLOD)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameterf(hostTextureView->glTexTarget, GL_TEXTURE_MIN_LOD, (float)iMinLOD / 64.0f);\n\t\t\tsamplerState->minLod = iMinLOD;\n\t\t}\n\t\tif (samplerState->maxLod != iMaxLOD)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameterf(hostTextureView->glTexTarget, GL_TEXTURE_MAX_LOD, (float)iMaxLOD / 64.0f);\n\t\t\tsamplerState->maxLod = iMaxLOD;\n\t\t}\n\t\tif (samplerState->lodBias != iLodBias)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameterf(hostTextureView->glTexTarget, GL_TEXTURE_LOD_BIAS, (float)iLodBias / 64.0f);\n\t\t\tsamplerState->lodBias = iLodBias;\n\t\t}\n\t\t// depth compare\n\t\tuint32 samplerDepthCompare = (uint32)samplerWords->WORD0.get_DEPTH_COMPARE_FUNCTION();\n\t\tuint8 depthCompareMode = isDepthSampler ? 1 : 0;\n\n\t\tif (samplerDepthCompare != samplerState->depthCompareFunc)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_COMPARE_FUNC, glDepthCompareTable[samplerDepthCompare]);\n\t\t\tsamplerState->depthCompareFunc = samplerDepthCompare;\n\t\t}\n\n\t\tif (depthCompareMode != samplerState->depthCompareMode)\n\t\t{\n\t\t\tquickBindTexture();\n\t\t\tif (depthCompareMode != 0)\n\t\t\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);\n\t\t\telse\n\t\t\t\tglTexParameteri(hostTextureView->glTexTarget, GL_TEXTURE_COMPARE_MODE, GL_NONE);\n\t\t\tsamplerState->depthCompareMode = depthCompareMode;\n\t\t}\n\n\t\tcatchOpenGLError();\n\t\t// border\n\t\tauto borderType = samplerWords->WORD0.get_BORDER_COLOR_TYPE();\n\t\tif (samplerState->borderType != (uint8)borderType || borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::REGISTER)\n\t\t{\n\t\t\t// todo: Should we use integer border color (glTexParameteriv) for integer texture formats?\n\t\t\tGLfloat borderColor[4];\n\t\t\tif (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::TRANSPARENT_BLACK)\n\t\t\t{\n\t\t\t\tborderColor[0] = 0.0f;\n\t\t\t\tborderColor[1] = 0.0f;\n\t\t\t\tborderColor[2] = 0.0f;\n\t\t\t\tborderColor[3] = 0.0f;\n\t\t\t}\n\t\t\telse if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::OPAQUE_BLACK)\n\t\t\t{\n\t\t\t\tborderColor[0] = 0.0f;\n\t\t\t\tborderColor[1] = 0.0f;\n\t\t\t\tborderColor[2] = 0.0f;\n\t\t\t\tborderColor[3] = 1.0f;\n\t\t\t}\n\t\t\telse if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::OPAQUE_WHITE)\n\t\t\t{\n\t\t\t\tborderColor[0] = 1.0f;\n\t\t\t\tborderColor[1] = 1.0f;\n\t\t\t\tborderColor[2] = 1.0f;\n\t\t\t\tborderColor[3] = 1.0f;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// border color from register\n\t\t\t\t_LatteRegisterSetSamplerBorderColor* borderColorReg;\n\t\t\t\tif (shaderContext->shaderType == LatteConst::ShaderType::Vertex || shaderContext->shaderType == LatteConst::ShaderType::Compute)\n\t\t\t\t\tborderColorReg = LatteGPUState.contextNew.TD_VS_SAMPLER_BORDER_COLOR + stageSamplerIndex;\n\t\t\t\telse if (shaderContext->shaderType == LatteConst::ShaderType::Pixel)\n\t\t\t\t\tborderColorReg = LatteGPUState.contextNew.TD_PS_SAMPLER_BORDER_COLOR + stageSamplerIndex;\n\t\t\t\telse // geometry\n\t\t\t\t\tborderColorReg = LatteGPUState.contextNew.TD_GS_SAMPLER_BORDER_COLOR + stageSamplerIndex;\n\n\t\t\t\tborderColor[0] = borderColorReg->red.get_channelValue();\n\t\t\t\tborderColor[1] = borderColorReg->green.get_channelValue();\n\t\t\t\tborderColor[2] = borderColorReg->blue.get_channelValue();\n\t\t\t\tborderColor[3] = borderColorReg->alpha.get_channelValue();\n\t\t\t}\n\n\t\t\tif (samplerState->borderColor[0] != borderColor[0] || samplerState->borderColor[1] != borderColor[1] || samplerState->borderColor[2] != borderColor[2] || samplerState->borderColor[3] != borderColor[3])\n\t\t\t{\n\t\t\t\tquickBindTexture();\n\t\t\t\tglTexParameterfv(hostTextureView->glTexTarget, GL_TEXTURE_BORDER_COLOR, borderColor);\n\t\t\t\tsamplerState->borderColor[0] = borderColor[0];\n\t\t\t\tsamplerState->borderColor[1] = borderColor[1];\n\t\t\t\tsamplerState->borderColor[2] = borderColor[2];\n\t\t\t\tsamplerState->borderColor[3] = borderColor[3];\n\t\t\t}\n\t\t\tsamplerState->borderType = (uint8)borderType;\n\t\t}\n\t\tcatchOpenGLError();\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererStreamout.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n\n#include \"Cafe/OS/libs/gx2/GX2.h\" // todo - remove dependency\n\nvoid OpenGLRenderer::streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize)\n{\n\tcatchOpenGLError();\n\tglBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, bufferIndex, glStreamoutCacheRingBuffer, ringBufferOffset, rangeSize);\n\tcatchOpenGLError();\n}\n\nvoid OpenGLRenderer::streamout_begin()\n{\n\t// get primitive mode\n\tGLenum glTransformFeedbackPrimitiveMode;\n\tauto primitiveMode = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();\n\tif (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::POINTS)\n\t\tglTransformFeedbackPrimitiveMode = GL_POINTS;\n\telse if(primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLES)\n\t\tglTransformFeedbackPrimitiveMode = GL_POINTS;\n\telse if (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUADS)\n\t\tglTransformFeedbackPrimitiveMode = GL_POINTS;\n\telse\n\t{\n\t\tdebug_printf(\"Unsupported streamout primitive mode 0x%02x\\n\", primitiveMode);\n\t\tcemu_assert_debug(false);\n\t}\n\tcemu_assert_debug(m_isXfbActive == false);\n\tglEnable(GL_RASTERIZER_DISCARD_EXT);\n\tglBeginTransformFeedback(glTransformFeedbackPrimitiveMode);\n\tcatchOpenGLError();\n\tm_isXfbActive = true;\n}\n\nvoid OpenGLRenderer::bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size)\n{\n\tif (glCopyNamedBufferSubData)\n\t\tglCopyNamedBufferSubData(glStreamoutCacheRingBuffer, glAttributeCacheAB, srcOffset, dstOffset, size);\n\telse\n\t\tcemuLog_log(LogType::Force, \"glCopyNamedBufferSubData() not supported\");\n}\n\nvoid OpenGLRenderer::streamout_rendererFinishDrawcall()\n{\n\tif (m_isXfbActive)\n\t{\n\t\tglEndTransformFeedback();\n\t\tglBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);\n\t\tglDisable(GL_RASTERIZER_DISCARD_EXT);\n\n\t\tm_isXfbActive = false;\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererUniformData.cpp",
    "content": "#include \"RendererShaderGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n\nGLint _gl_remappedUniformData[4 * 256];\n\nvoid OpenGLRenderer::uniformData_update()\n{\n\t// update uniforms\n\tLatteDecompilerShader* shaderArray[3];\n\tshaderArray[0] = LatteSHRC_GetActiveVertexShader();\n\tshaderArray[1] = LatteSHRC_GetActivePixelShader();\n\tshaderArray[2] = LatteSHRC_GetActiveGeometryShader();;\n\n\tuint32 shaderBlockUniformRegisterOffset[3];\n\tshaderBlockUniformRegisterOffset[0] = mmSQ_VTX_UNIFORM_BLOCK_START;\n\tshaderBlockUniformRegisterOffset[1] = mmSQ_PS_UNIFORM_BLOCK_START;\n\tshaderBlockUniformRegisterOffset[2] = mmSQ_GS_UNIFORM_BLOCK_START;\n\n\tuint32 shaderALUConstOffset[3];\n\tshaderALUConstOffset[0] = 0x400;\n\tshaderALUConstOffset[1] = 0;\n\tshaderALUConstOffset[2] = 0xFFFFFFFF; // GS has no uniform registers\n\n\tfor (sint32 s = 0; s < 3; s++)\n\t{\n\t\t// update block uniforms\n\t\tLatteDecompilerShader* shader = shaderArray[s];\n\t\tif (!shader)\n\t\t\tcontinue;\n\n\t\tauto hostShader = (RendererShaderGL*)shader->shader;\n\n\t\tif (shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED)\n\t\t{\n\t\t\tauto& list_uniformMapping = shader->list_remappedUniformEntries;\n\t\t\tcemu_assert_debug(list_uniformMapping.size() <= 256);\n\t\t\tsint32 remappedArraySize = (sint32)list_uniformMapping.size();\n\t\t\tLatteBufferCache_LoadRemappedUniforms(shader, (float*)(_gl_remappedUniformData));\n\t\t\t// update values only when the hash changed\n\t\t\tif (remappedArraySize > 0)\n\t\t\t{\n\t\t\t\tuint64 uniformDataHash[2] = { 0 };\n\t\t\t\tuint64* remappedUniformData64 = (uint64*)_gl_remappedUniformData;\n\t\t\t\tfor (sint32 f = 0; f < remappedArraySize; f++)\n\t\t\t\t{\n\t\t\t\t\tuniformDataHash[0] ^= remappedUniformData64[0];\n\t\t\t\t\tuniformDataHash[0] = std::rotl<uint64>(uniformDataHash[0], 11);\n\t\t\t\t\tuniformDataHash[1] ^= remappedUniformData64[1];\n\t\t\t\t\tuniformDataHash[1] = std::rotl<uint64>(uniformDataHash[1], 11);\n\t\t\t\t\tremappedUniformData64 += 2;\n\t\t\t\t}\n\t\t\t\tif (shader->uniformDataHash64[0] != uniformDataHash[0] || shader->uniformDataHash64[1] != uniformDataHash[1])\n\t\t\t\t{\n\t\t\t\t\tshader->uniformDataHash64[0] = uniformDataHash[0];\n\t\t\t\t\tshader->uniformDataHash64[1] = uniformDataHash[1];\n\t\t\t\t\thostShader->SetUniform4iv(shader->uniform.loc_remapped, _gl_remappedUniformData, remappedArraySize);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE)\n\t\t{\n\t\t\tif (shaderALUConstOffset[s] == 0xFFFFFFFF)\n\t\t\t\tassert_dbg();\n\t\t\tGLint* uniformRegData = (GLint*)(LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderALUConstOffset[s]);\n\t\t\thostShader->SetUniform4iv(shader->uniform.loc_uniformRegister, uniformRegData, shader->uniform.count_uniformRegister);\n\t\t}\n\t\telse if (shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)\n\t\t{\n\t\t\t// handled by _syncGPUUniformBuffers()\n\t\t}\n\t\telse if (shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_NONE)\n\t\t{\n\t\t\t// no uniforms used\n\t\t}\n\t}\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLSurfaceCopy.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/CachedFBOGL.h\"\n\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteDefaultShaders.h\"\n\nvoid LatteDraw_resetAttributePointerCache();\n\nvoid _setDepthCompareMode(LatteTextureViewGL* textureView, uint8 depthCompareMode)\n{\n\tif (depthCompareMode != textureView->samplerState.depthCompareMode)\n\t{\n\t\tif (depthCompareMode != 0)\n\t\t\tglTexParameteri(textureView->glTexTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);\n\t\telse\n\t\t\tglTexParameteri(textureView->glTexTarget, GL_TEXTURE_COMPARE_MODE, GL_NONE);\n\t\ttextureView->samplerState.depthCompareMode = depthCompareMode;\n\t}\n}\n\nvoid OpenGLRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height)\n{\n\t// scale copy size to effective size\n\tsint32 effectiveCopyWidth = width;\n\tsint32 effectiveCopyHeight = height;\n\tLatteTexture_scaleToEffectiveSize(sourceTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0);\n\tsint32 sourceEffectiveWidth, sourceEffectiveHeight;\n\tsourceTexture->GetEffectiveSize(sourceEffectiveWidth, sourceEffectiveHeight, srcMip);\n\t// reset everything\n\trenderstate_resetColorControl();\n\trenderstate_resetDepthControl();\n\tattributeStream_unbindVertexBuffer();\n\n\tSetArrayElementBuffer(0);\n\tLatteDraw_resetAttributePointerCache();\n\tSetAttributeArrayState(0, true, -1);\n\tSetAttributeArrayState(1, true, -1);\n\tfor (uint32 i = 2; i < GPU_GL_MAX_NUM_ATTRIBUTE; i++)\n\t\tSetAttributeArrayState(i, false, -1);\n\tcatchOpenGLError();\n\t// set viewport\n\tg_renderer->renderTarget_setViewport(0, 0, (float)effectiveCopyWidth, (float)effectiveCopyHeight, 0.0f, 1.0f);\n\tcatchOpenGLError();\n\t// get a view of the copied slice/mip in the source and destination texture\n\tLatteTextureView* sourceView = sourceTexture->GetOrCreateView(srcMip, 1, srcSlice, 1);\n\tLatteTextureView* destinationView = destinationTexture->GetOrCreateView(dstMip, 1, dstSlice, 1);\n\n\ttexture_bindAndActivate(sourceView, 0);\n\tcatchOpenGLError();\n\t// setup texture attributes\n\t_setDepthCompareMode((LatteTextureViewGL*)sourceView, 0);\n\tcatchOpenGLError();\n\t// bind framebuffer\n\tif (destinationTexture->isDepth)\n\t\tLatteMRT::BindDepthBufferOnly(destinationView);\n\telse\n\t\tLatteMRT::BindColorBufferOnly(destinationView);\n\tcatchOpenGLError();\n\t// enable depth writes if the destination is a depth texture\n\tif (destinationTexture->isDepth)\n\t\trenderstate_setAlwaysWriteDepth();\n\t// bind format specific copy shader\n\tLatteDefaultShader_t* copyShader = LatteDefaultShader_getPixelCopyShader_depthToColor();\n\tif (destinationTexture->isDepth)\n\t\tcopyShader = LatteDefaultShader_getPixelCopyShader_colorToDepth();\n\tglUseProgram(copyShader->glProgamId);\n\tcatchOpenGLError();\n\t// setup uniforms\n\tglUniform1i(copyShader->copyShaderUniforms.uniformLoc_textureSrc, 0);\n\tcatchOpenGLError();\n\n\tfloat vertexOffsets[4 * 4];\n\tfloat srcCopyWidth = (float)width / (float)sourceTexture->width;\n\tfloat srcCopyHeight = (float)height / (float)sourceTexture->height;\n\t// q0 vertex\n\tvertexOffsets[0] = -1.0f;\n\tvertexOffsets[1] = 1.0f;\n\t// q0 uv\n\tvertexOffsets[2] = 0.0f;\n\tvertexOffsets[3] = 0.0f;\n\t// q1\n\tvertexOffsets[4] = 1.0f;\n\tvertexOffsets[5] = 1.0f;\n\t// q1 uv\n\tvertexOffsets[6] = srcCopyWidth;\n\tvertexOffsets[7] = 0.0f;\n\t// q2\n\tvertexOffsets[8] = -1.0f;\n\tvertexOffsets[9] = -1.0f;\n\t// q2 uv\n\tvertexOffsets[10] = 0.0f;\n\tvertexOffsets[11] = srcCopyHeight;\n\t// q3\n\tvertexOffsets[12] = 1.0f;\n\tvertexOffsets[13] = -1.0f;\n\t// q3 uv\n\tvertexOffsets[14] = srcCopyWidth;\n\tvertexOffsets[15] = srcCopyHeight;\n\n\tglUniform4fv(copyShader->copyShaderUniforms.uniformLoc_vertexOffsets, 4, vertexOffsets);\n\tcatchOpenGLError();\n\n\t// draw\n\tuint16 indexData[6] = { 0,1,3,0,2,3 };\n\tglDrawRangeElements(GL_TRIANGLES, 0, 5, 6, GL_UNSIGNED_SHORT, indexData);\n\tcatchOpenGLError();\n\n\tLatteGPUState.repeatTextureInitialization = true;\n\tglUseProgram(0);\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLTextureReadback.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Core/LatteTextureReadbackInfo.h\"\n#include \"Common/GLInclude/GLInclude.h\"\n\nclass LatteTextureReadbackInfoGL : public LatteTextureReadbackInfo\n{\npublic:\n\tLatteTextureReadbackInfoGL(LatteTextureView* textureView);\n\n\t~LatteTextureReadbackInfoGL();\n\n\tvoid StartTransfer() override;\n\tbool IsFinished() override;\n\n\tuint8* GetData() override;\n\tvoid ReleaseData() override;\n\nprivate:\n\tGLuint m_texFormatGL;\n\tGLuint m_texDataTypeGL;\n\n\t// buffer\n\tGLuint texImageBufferGL = 0;\n\t// sync\n\tGLsync imageCopyFinSync = nullptr;\n};\n\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h\"\n\n#include \"Cemu/FileCache/FileCache.h\"\n\n#include \"config/ActiveSettings.h\"\n#include \"config/LaunchSettings.h\"\n\nextern std::atomic_int g_compiled_shaders_total;\nextern std::atomic_int g_compiled_shaders_async;\n\nbool s_isLoadingShaders{false};\n\nbool RendererShaderGL::loadBinary()\n{\n\tif (!s_programBinaryCache)\n\t\treturn false;\n\tif (m_isGameShader == false || m_isGfxPackShader)\n\t\treturn false; // only non-custom \n\tif (!glProgramBinary)\n\t\treturn false; // OpenGL program binaries not supported\n\n\tcemu_assert_debug(m_baseHash != 0);\n\tuint64 h1, h2;\n\tGenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);\n\tstd::vector<uint8> cacheFileData;\n\tif (!s_programBinaryCache->GetFile({h1, h2 }, cacheFileData))\n\t\treturn false;\n\tif (cacheFileData.size() <= sizeof(uint32))\n\t\treturn false;\n\n\tuint32 shaderBinFormat = *(uint32*)(cacheFileData.data());\n\n\tm_program = glCreateProgram();\n\tglProgramBinary(m_program, shaderBinFormat, cacheFileData.data()+4, cacheFileData.size()-4);\n\n\tint status = -1;\n\tglGetProgramiv(m_program, GL_LINK_STATUS, &status);\n\tif (status != GL_TRUE)\n\t{\n\t\tglDeleteProgram(m_program);\n\t\tm_program = 0;\n\t\treturn false;\n\t}\n\tm_isCompiled = true;\n\treturn true;\n}\n\nvoid RendererShaderGL::storeBinary()\n{\n\tif (!s_programBinaryCache)\n\t\treturn;\n\tif (!glGetProgramBinary)\n\t\treturn;\n\tif (m_program == 0)\n\t\treturn;\n\tif (!m_isGameShader || m_isGfxPackShader)\n\t\treturn;\n\n\tGLint binaryLength = 0;\n\tglGetProgramiv(m_program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);\n\tif (binaryLength > 0)\n\t{\n\t\tuint64 h1, h2;\n\t\tGenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);\n\t\t// build stored shader data (4 byte format + binary data)\n\t\tstd::vector<uint8> storedBinary(binaryLength+sizeof(uint32), 0);\n\t\tGLenum binaryFormat = 0;\n\t\tglGetProgramBinary(m_program, binaryLength, NULL, &binaryFormat, storedBinary.data()+sizeof(uint32));\t\t\n\t\t*(uint32*)(storedBinary.data() + 0) = binaryFormat;\n\t\t// store\n\t\ts_programBinaryCache->AddFileAsync({h1, h2 }, storedBinary.data(), storedBinary.size());\n\t}\n}\n\nRendererShaderGL::RendererShaderGL(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslSource)\n\t: RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_glslSource(glslSource)\n{\n\tGLenum glShaderType;\n\tswitch (type)\n\t{\n\tcase ShaderType::kVertex:\n\t\tglShaderType = GL_VERTEX_SHADER;\n\t\tbreak;\n\tcase ShaderType::kFragment:\n\t\tglShaderType = GL_FRAGMENT_SHADER;\n\t\tbreak;\n\tcase ShaderType::kGeometry:\n\t\tglShaderType = GL_GEOMETRY_SHADER;\n\t\tbreak;\n\tdefault:\n\t\tcemu_assert_debug(false);\n\t}\n\n\tif (s_isLoadingShaders)\n\t{\n\t\tif (loadBinary())\n\t\t{\n\t\t\tm_glslSource.clear();\n\t\t\tm_glslSource.shrink_to_fit();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tm_shader_object = glCreateShader(glShaderType);\n\n\tconst char *c_str = m_glslSource.c_str();\n\tconst GLint size = (GLint)m_glslSource.size();\n\tglShaderSource(m_shader_object, 1, &c_str, &size);\n\tglCompileShader(m_shader_object);\n\n\tGLint log_length;\n\tglGetShaderiv(m_shader_object, GL_INFO_LOG_LENGTH, &log_length);\n\tif (log_length > 0)\n\t{\n\t\tchar log[2048]{};\n\t\tGLsizei log_size;\n\t\tglGetShaderInfoLog(m_shader_object, std::min<uint32>(log_length, sizeof(log) - 1), &log_size, log);\n\t\tcemuLog_log(LogType::Force, \"Error/Warning in shader:\");\n\t\tcemuLog_log(LogType::Force, log);\n\t}\n\n\t// set debug name\n\tif (LaunchSettings::NSightModeEnabled()) \n\t{\n\t\tauto objNameStr = fmt::format(\"shader_{:016x}_{:016x}\", m_baseHash, m_auxHash);\n\t\tglObjectLabel(GL_SHADER, m_shader_object, objNameStr.size(), objNameStr.c_str());\n\t}\n\n\tm_program = glCreateProgram();\n\tglProgramParameteri(m_program, GL_PROGRAM_SEPARABLE, GL_TRUE);\n\tglProgramParameteri(m_program, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);\n\tglAttachShader(m_program, m_shader_object);\n\tm_shader_attached = true;\n\tglLinkProgram(m_program);\n\n\tstoreBinary();\n\n\t// count shader compilation\n\tif (!s_isLoadingShaders)\n\t\t++g_compiled_shaders_total;\n\n\t// we can throw away the GLSL code to conserve RAM\n\tm_glslSource.clear();\n\tm_glslSource.shrink_to_fit();\n}\n\nRendererShaderGL::~RendererShaderGL()\n{\n\tif (m_shader_object != 0 && m_shader_attached)\n\t\tglDetachShader(m_program, m_shader_object);\n\n\tif (m_shader_object != 0)\n\t\tglDeleteShader(m_shader_object);\n\n\tif (m_program != 0)\n\t\tglDeleteProgram(m_program);\n}\n\nvoid RendererShaderGL::PreponeCompilation(bool isRenderThread)\n{\n\t// the logic for initiating compilation is currently in the constructor\n\t// here we only guarantee that it is finished before we return\n\tif (m_isCompiled)\n\t\treturn;\n\tWaitForCompiled();\n}\n\nbool RendererShaderGL::IsCompiled()\n{\n\tcemu_assert_debug(false);\n\treturn true;\n}\n\nbool RendererShaderGL::WaitForCompiled()\n{\n\tchar infoLog[8 * 1024];\n\tif (m_isCompiled)\n\t\treturn true;\n\t// check if compilation was successful\n\tGLint compileStatus = GL_FALSE;\n\tglGetShaderiv(m_shader_object, GL_COMPILE_STATUS, &compileStatus);\n\tif (compileStatus == 0)\n\t{\n\t\tuint32 infoLogLength, tempLength;\n\t\tglGetShaderiv(m_shader_object, GL_INFO_LOG_LENGTH, (GLint *)&infoLogLength);\n\t\tif (infoLogLength != 0)\n\t\t{\n\t\t\ttempLength = sizeof(infoLog) - 1;\n\t\t\tglGetShaderInfoLog(m_shader_object, std::min(infoLogLength, tempLength), (GLsizei*)&tempLength, (GLcharARB*)infoLog);\n\t\t\tinfoLog[tempLength] = '\\0';\n\t\t\tcemuLog_log(LogType::Force, \"Compile error in shader. Log:\");\n\t\t\tcemuLog_log(LogType::Force, infoLog);\n\t\t}\n\t\tif (m_shader_object != 0)\n\t\t\tglDeleteShader(m_shader_object);\n\t\tm_isCompiled = true;\n\t\treturn false;\n\t}\n\t// get shader binary\n\tGLint linkStatus = GL_FALSE;\n\tglGetProgramiv(m_program, GL_LINK_STATUS, &linkStatus);\n\tif (linkStatus == 0)\n\t{\n\t\tuint32 infoLogLength, tempLength;\n\t\tglGetProgramiv(m_program, GL_INFO_LOG_LENGTH, (GLint *)&infoLogLength);\n\t\tif (infoLogLength != 0)\n\t\t{\n\t\t\ttempLength = sizeof(infoLog) - 1;\n\t\t\tglGetProgramInfoLog(m_program, std::min(infoLogLength, tempLength), (GLsizei*)&tempLength, (GLcharARB*)infoLog);\n\t\t\tinfoLog[tempLength] = '\\0';\n\t\t\tcemuLog_log(LogType::Force, \"Link error in shader. Log:\");\n\t\t\tcemuLog_log(LogType::Force, infoLog);\n\t\t}\n\t\tm_isCompiled = true;\n\t\treturn false;\n\t}\n\n\t/*glDetachShader(m_program, m_shader_object);\n\tm_shader_attached = false;*/\n\tm_isCompiled = true;\n\treturn true;\n}\n\nsint32 RendererShaderGL::GetUniformLocation(const char* name)\n{\n\treturn glGetUniformLocation(m_program, name);\n}\n\nvoid RendererShaderGL::SetUniform1i(sint32 location, sint32 value)\n{\n\tglProgramUniform1i(m_program, location, value);\n}\n\nvoid RendererShaderGL::SetUniform1f(sint32 location, float value)\n{\n\tglProgramUniform1f(m_program, location, value);\n}\n\nvoid RendererShaderGL::SetUniform2fv(sint32 location, void* data, sint32 count)\n{\n\tglProgramUniform2fv(m_program, location, count, (const GLfloat*)data);\n}\n\nvoid RendererShaderGL::SetUniform4iv(sint32 location, void* data, sint32 count)\n{\n\tglProgramUniform4iv(m_program, location, count, (const GLint*)data);\n}\n\nvoid RendererShaderGL::ShaderCacheLoading_begin(uint64 cacheTitleId)\n{\n    cemu_assert_debug(!s_programBinaryCache); // should not be set, ShaderCacheLoading_Close() not called?\n\t// determine if cache is enabled\n\tbool usePrecompiled = false;\n\tswitch (ActiveSettings::GetPrecompiledShadersOption())\n\t{\n\tcase PrecompiledShaderOption::Auto:\n\t\tif (g_renderer->GetVendor() == GfxVendor::Nvidia)\n\t\t\tusePrecompiled = false;\n\t\telse\n\t\t\tusePrecompiled = true;\n\t\tbreak;\n\tcase PrecompiledShaderOption::Enable:\n\t\tusePrecompiled = true;\n\t\tbreak;\n\tcase PrecompiledShaderOption::Disable:\n\t\tusePrecompiled = false;\n\t\tbreak;\n\tdefault:\n\t\tUNREACHABLE;\n\t}\n\n\tcemuLog_log(LogType::Force, \"Using precompiled shaders: {}\", usePrecompiled ? \"true\" : \"false\");\n\n\tif (usePrecompiled)\n\t{\n\t\tconst uint32 cacheMagic = GeneratePrecompiledCacheId();\n\t\tconst std::string cacheFilename = fmt::format(\"{:016x}_gl.bin\", cacheTitleId);\n        s_programBinaryCache = FileCache::Open(ActiveSettings::GetCachePath(\"shaderCache/precompiled/{}\", cacheFilename), true, cacheMagic);\n\t\tif (s_programBinaryCache == nullptr)\n\t\t\tcemuLog_log(LogType::Force, \"Unable to open OpenGL precompiled cache {}\", cacheFilename);\n\t}\n\ts_isLoadingShaders = true;\n}\n\nvoid RendererShaderGL::ShaderCacheLoading_end()\n{\n\ts_isLoadingShaders = false;\n}\n\nvoid RendererShaderGL::ShaderCacheLoading_Close()\n{\n    if(s_programBinaryCache)\n    {\n        delete s_programBinaryCache;\n        s_programBinaryCache = nullptr;\n    }\n    g_compiled_shaders_total = 0;\n    g_compiled_shaders_async = 0;\n}\n\nFileCache* RendererShaderGL::s_programBinaryCache{};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/RendererShader.h\"\n#include \"Common/GLInclude/GLInclude.h\"\n\nclass RendererShaderGL : public RendererShader\n{\npublic:\n\tRendererShaderGL(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslSource);\n\n\tvirtual ~RendererShaderGL();\n\n\tvoid PreponeCompilation(bool isRenderThread) override;\n\tbool IsCompiled() override;\n\tbool WaitForCompiled() override;\n\n\tGLuint GetProgram() const { cemu_assert_debug(m_isCompiled); return m_program; }\n\tGLuint GetShaderObject() const { cemu_assert_debug(m_isCompiled); return m_shader_object; }\n\n\tsint32 GetUniformLocation(const char* name);\n\n\tvoid SetUniform1i(sint32 location, sint32 value);\n\tvoid SetUniform1f(sint32 location, float value);\n\tvoid SetUniform2fv(sint32 location, void* data, sint32 count);\n\tvoid SetUniform4iv(sint32 location, void* data, sint32 count);\n\n\tstatic void ShaderCacheLoading_begin(uint64 cacheTitleId);\n\tstatic void ShaderCacheLoading_end();\n    static void ShaderCacheLoading_Close();\n\nprivate:\n\tGLuint m_program;\n\tGLuint m_shader_object;\n\n\tbool loadBinary();\n\tvoid storeBinary();\n\n\tstd::string m_glslSource;\n\n\tbool m_shader_attached{ false };\n\tbool m_isCompiled{ false };\n\n\tstatic class FileCache* s_programBinaryCache;\n};\n\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/OpenGL/TextureReadbackGL.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLTextureReadback.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h\"\n\nLatteTextureReadbackInfoGL::LatteTextureReadbackInfoGL(LatteTextureView* textureView)\n\t: LatteTextureReadbackInfo(textureView)\n{\n\tLatteTexture* baseTexture = textureView->baseTexture;\n\t// handle format\n\tif (textureView->format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM)\n\t{\n\t\tm_image_size = baseTexture->width*baseTexture->height * 4;\n\t\tm_texFormatGL = GL_RGBA;\n\t\tm_texDataTypeGL = GL_UNSIGNED_BYTE;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB)\n\t{\n\t\tm_image_size = baseTexture->width*baseTexture->height * 4;\n\t\tm_texFormatGL = GL_RGBA;\n\t\tm_texDataTypeGL = GL_UNSIGNED_BYTE;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT)\n\t{\n\t\tm_image_size = baseTexture->width*baseTexture->height * 16;\n\t\tm_texFormatGL = GL_RGBA;\n\t\tm_texDataTypeGL = GL_FLOAT;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R32_FLOAT)\n\t{\n\t\tif (baseTexture->isDepth)\n\t\t{\n\t\t\tm_image_size = baseTexture->width*baseTexture->height * 4;\n\t\t\tm_texFormatGL = GL_DEPTH_COMPONENT;\n\t\t\tm_texDataTypeGL = GL_FLOAT;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_image_size = baseTexture->width*baseTexture->height * 4;\n\t\t\tm_texFormatGL = GL_RED;\n\t\t\tm_texDataTypeGL = GL_FLOAT;\n\t\t}\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R16_UNORM)\n\t{\n\t\tif (baseTexture->isDepth)\n\t\t{\n\t\t\tm_image_size = baseTexture->width*baseTexture->height * 2;\n\t\t\tm_texFormatGL = GL_DEPTH_COMPONENT;\n\t\t\tm_texDataTypeGL = GL_UNSIGNED_SHORT;\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_image_size = baseTexture->width*baseTexture->height * 2;\n\t\t\tm_texFormatGL = GL_RED;\n\t\t\tm_texDataTypeGL = GL_UNSIGNED_SHORT;\n\t\t}\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT)\n\t{\n\t\tm_image_size = baseTexture->width*baseTexture->height * 8;\n\t\tm_texFormatGL = GL_RGBA;\n\t\tm_texDataTypeGL = GL_HALF_FLOAT;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R8_G8_UNORM)\n\t{\n\t\tm_image_size = baseTexture->width*baseTexture->height * 2;\n\t\tm_texFormatGL = GL_RG;\n\t\tm_texDataTypeGL = GL_UNSIGNED_BYTE;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM)\n\t{\n\t\tm_image_size = baseTexture->width*baseTexture->height * 8;\n\t\tm_texFormatGL = GL_RGBA;\n\t\tm_texDataTypeGL = GL_UNSIGNED_SHORT;\n\t}\n\telse\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Unsupported texture readback format {:04x}\", (uint32)textureView->format);\n\t\treturn;\n\t}\n}\n\nLatteTextureReadbackInfoGL::~LatteTextureReadbackInfoGL()\n{\n\tif(imageCopyFinSync != 0)\n\t\tglDeleteSync(imageCopyFinSync);\n\n\tif(texImageBufferGL)\n\t\tglDeleteBuffers(1, &texImageBufferGL);\n}\n\nvoid LatteTextureReadbackInfoGL::StartTransfer()\n{\n\tcemu_assert(m_textureView);\n\t((OpenGLRenderer*)g_renderer.get())->texture_bindAndActivate(m_textureView, 0);\n\t// create unsynchronized buffer\n\tglGenBuffers(1, &texImageBufferGL);\n\tglBindBuffer(GL_PIXEL_PACK_BUFFER, texImageBufferGL);\n\tglBufferData(GL_PIXEL_PACK_BUFFER, m_image_size, NULL, GL_DYNAMIC_READ);\n\t// request texture read into buffer\n\tglGetTexImage(((LatteTextureViewGL*)m_textureView)->glTexTarget, 0, m_texFormatGL, m_texDataTypeGL, NULL);\n\tglFlush();\n\t// create fence sync (so we can check if the image copy operation finished)\n\timageCopyFinSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);\n\tm_textureView = nullptr;\n}\n\nbool LatteTextureReadbackInfoGL::IsFinished()\n{\n\tGLenum status = glClientWaitSync(imageCopyFinSync, 0, 0);\n\t\tif (status == GL_TIMEOUT_EXPIRED)\n\t\t\treturn false;\n\t\telse if (status == GL_ALREADY_SIGNALED || status == GL_SIGNALED)\n\t\t\treturn true;\n\t\telse\n\t\t\tthrow std::runtime_error(\"_updateFinishedTransfers(): Error during readback sync check\\n\");\n}\n\nuint8* LatteTextureReadbackInfoGL::GetData()\n{\n\t\tglBindBuffer(GL_PIXEL_PACK_BUFFER, texImageBufferGL);\n\t\treturn (uint8*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);\n}\n\n\nvoid LatteTextureReadbackInfoGL::ReleaseData()\n{\n\tglUnmapBuffer(GL_PIXEL_PACK_BUFFER);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Renderer.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"WindowSystem.h\"\n\n#include \"config/CemuConfig.h\"\n#include \"Cafe/HW/Latte/Core/LatteOverlay.h\"\n\n#include <imgui.h>\n#include \"imgui/imgui_extension.h\"\n#include <png.h>\n\n#include \"config/ActiveSettings.h\"\n\nstd::unique_ptr<Renderer> g_renderer;\n\nbool Renderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const\n{\n\tusageInMB = totalInMB = -1;\n\t\n#if BOOST_OS_WINDOWS\n\tif (m_dxgi_wrapper)\n\t{\n\t\tDXGI_QUERY_VIDEO_MEMORY_INFO info{};\n\t\tif (m_dxgi_wrapper->QueryVideoMemoryInfo(info))\n\t\t{\n\t\t\ttotalInMB = (info.Budget / 1000) / 1000;\n\t\t\tusageInMB = (info.CurrentUsage / 1000) / 1000;\n\t\t\treturn true;\n\t\t}\n\t}\n#endif\n\n\treturn false;\n}\n\n\nvoid Renderer::Initialize()\n{\n\t// imgui\n\timguiFontAtlas = new ImFontAtlas();\n\timguiFontAtlas->AddFontDefault();\n\n\tauto setupContext = [](ImGuiContext* context){\n\t\tImGui::SetCurrentContext(context);\n\t\tImGuiIO& io = ImGui::GetIO();\n\t\tio.WantSaveIniSettings = false;\n\t\tio.IniFilename = nullptr;\n\t};\n\n\timguiTVContext = ImGui::CreateContext(imguiFontAtlas);\n\timguiPadContext = ImGui::CreateContext(imguiFontAtlas);\n\tsetupContext(imguiTVContext);\n\tsetupContext(imguiPadContext);\n}\n\nvoid Renderer::Shutdown()\n{\n\t// imgui\n\tImGui::DestroyContext(imguiTVContext);\n\tImGui::DestroyContext(imguiPadContext);\n    ImGui_ClearFonts();\n\tdelete imguiFontAtlas;\n}\n\nbool Renderer::ImguiBegin(bool mainWindow)\n{\n\tsint32 w = 0, h = 0;\n\tif (mainWindow)\n\t\tWindowSystem::GetWindowPhysSize(w, h);\n\telse if (WindowSystem::IsPadWindowOpen())\n\t\tWindowSystem::GetPadWindowPhysSize(w, h);\n\telse\n\t\treturn false;\n\t\t\n\tif (w == 0 || h == 0)\n\t\treturn false;\n\n\t// select the right context\n\tImGui::SetCurrentContext(mainWindow ? imguiTVContext : imguiPadContext);\n\n\tconst Vector2f window_size{(float)w, (float)h};\n\tauto& io = ImGui::GetIO();\n\tio.DisplaySize = {window_size.x, window_size.y}; // should be only updated in the renderer and only when needed\n\n\tImGui_PrecacheFonts();\n\treturn true;\n}\n\nuint8 Renderer::SRGBComponentToRGB(uint8 ci)\n{\n\tconst float cs = (float)ci / 255.0f;\n\tfloat cl;\n\tif (cs <= 0.04045)\n\t\tcl = cs / 12.92f;\n\telse\n\t\tcl = std::pow((cs + 0.055f) / 1.055f, 2.4f);\n\tcl = std::min(cl, 1.0f);\n\treturn (uint8)(cl * 255.0f);\n}\n\nuint8 Renderer::RGBComponentToSRGB(uint8 cli)\n{\n\tconst float cl = (float)cli / 255.0f;\n\tfloat cs;\n\tif (cl < 0.0031308)\n\t\tcs = 12.92f * cl;\n\telse\n\t\tcs = 1.055f * std::pow(cl, 0.41666f) - 0.055f;\n\tcs = std::max(std::min(cs, 1.0f), 0.0f);\n\treturn (uint8)(cs * 255.0f);\n}\n\nvoid Renderer::RequestScreenshot(ScreenshotSaveFunction onSaveScreenshot)\n{\n\tm_screenshot_requested = true;\n\tm_on_save_screenshot = onSaveScreenshot;\n}\n\nvoid Renderer::CancelScreenshotRequest()\n{\n\tm_screenshot_requested = false;\n\tm_on_save_screenshot = {};\n}\n\n\nvoid Renderer::SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int height, bool mainWindow)\n{\n\tstd::thread(\n\t\t[=, screenshotRequested = std::exchange(m_screenshot_requested, false), onSaveScreenshot = std::exchange(m_on_save_screenshot, {})]() {\n\t\t\tif (screenshotRequested && onSaveScreenshot)\n\t\t\t{\n\t\t\t\tauto notificationMessage = onSaveScreenshot(rgb_data, width, height, mainWindow);\n\t\t\t\tif (notificationMessage.has_value())\n\t\t\t\t\tLatteOverlay_pushNotification(notificationMessage.value(), 2500);\n\t\t\t}\n\t\t})\n\t\t.detach();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Renderer.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteCachedFBO.h\"\n#include \"Cafe/HW/Latte/Renderer/RendererShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteTextureLoader.h\"\n#include \"Cafe/HW/Latte/Core/LatteTextureReadbackInfo.h\"\n#include \"Cafe/HW/Latte/Core/LatteQueryObject.h\"\n#include \"Cafe/HW/Latte/Renderer/RendererOuputShader.h\"\n\n#if BOOST_OS_WINDOWS\n#include \"util/DXGIWrapper/DXGIWrapper.h\"\n#endif\n\n// imgui forward declarations\nstruct ImFontAtlas;\nstruct ImGuiContext;\n\nenum class GfxVendor\n{\n\tGeneric,\n\n\tAMD,\n\tIntel,\n\tNvidia,\n\tApple,\n\tMesa,\n\n\tMAX\n};\n\nenum class RendererAPI\n{\n\tOpenGL,\n\tVulkan,\n\tMetal,\n\n\tMAX\n};\n\nusing ImTextureID = void*;\n\nclass Renderer\n{\npublic:\n\tenum class INDEX_TYPE\n\t{\n\t\tNONE,\n\t\tU16,\n\t\tU32\n\t};\n\n\tvirtual ~Renderer() = default;\n\n\tvirtual RendererAPI GetType() = 0;\n\n\tvirtual void Initialize();\n\tvirtual void Shutdown();\n\tvirtual bool IsPadWindowActive() = 0;\n\n\tvirtual bool GetVRAMInfo(int& usageInMB, int& totalInMB) const;\n\n\tvirtual void EnableDebugMode() {}\n\n\tvirtual void ClearColorbuffer(bool padView) = 0;\n\tvirtual void DrawEmptyFrame(bool mainWindow) = 0;\n\tvirtual void SwapBuffers(bool swapTV, bool swapDRC) = 0;\n\n\tusing ScreenshotSaveFunction = std::function<std::optional<std::string>(const std::vector<uint8>&, int, int, bool)>;\n\tvoid RequestScreenshot(ScreenshotSaveFunction onSaveScreenshot);\n\tvoid CancelScreenshotRequest();\n\n\tvirtual void HandleScreenshotRequest(LatteTextureView* texView, bool padView){}\n\n\tvirtual void DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,\n\t\t\t\t\t\t\t\t\t\t\t\tsint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight,\n\t\t\t\t\t\t\t\t\t\t\t\tbool padView, bool clearBackground) = 0;\n\tvirtual bool BeginFrame(bool mainWindow) = 0;\n\n\t// flush control\n\tvirtual void Flush(bool waitIdle = false) = 0; // called when explicit flush is required (e.g. by imgui)\n\tvirtual void NotifyLatteCommandProcessorIdle() = 0; // called when command processor has no more commands available or when stalled\n\n\t// imgui\n\tvirtual bool ImguiBegin(bool mainWindow);\n\tvirtual void ImguiEnd() = 0;\n\tvirtual ImTextureID GenerateTexture(const std::vector<uint8>& data, const Vector2i& size) = 0;\n\tvirtual void DeleteTexture(ImTextureID id) = 0;\n\tvirtual void DeleteFontTextures() = 0;\n\n\tGfxVendor GetVendor() const { return m_vendor; }\n\tvirtual bool UseTFViaSSBO() const { return false; }\n\tvirtual void AppendOverlayDebugInfo() = 0;\n\n\t// rendertarget\n\tvirtual void renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ = false) = 0;\n\tvirtual void renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight) = 0;\n\n\tvirtual LatteCachedFBO* rendertarget_createCachedFBO(uint64 key) = 0;\n\tvirtual void rendertarget_deleteCachedFBO(LatteCachedFBO* fbo) = 0;\n\tvirtual void rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) = 0;\n\n\t// texture functions\n\tvirtual void* texture_acquireTextureUploadBuffer(uint32 size) = 0;\n\tvirtual void texture_releaseTextureUploadBuffer(uint8* mem) = 0;\n\n\tvirtual TextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) = 0;\n\n\tvirtual void texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) = 0;\n\tvirtual void texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) = 0;\n\tvirtual void texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) = 0;\n\tvirtual void texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) = 0;\n\n\tvirtual LatteTexture* texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) = 0;\n\n\tvirtual void texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) = 0;\n\tvirtual void texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) = 0;\n\n\tvirtual LatteTextureReadbackInfo* texture_createReadback(LatteTextureView* textureView) = 0;\n\n\t// surface copy\n\tvirtual void surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height) = 0;\n\n\t// buffer cache\n\tvirtual void bufferCache_init(const sint32 bufferSize) = 0;\n\tvirtual void bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) = 0;\n\tvirtual void bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) = 0;\n\tvirtual void bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) = 0;\n\n\tvirtual void buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) = 0;\n\tvirtual void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) = 0;\n\n\t// shader\n\tvirtual RendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool compileAsync, bool isGfxPackSource) = 0;\n\n\t// streamout\n\tvirtual void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) = 0;\n\tvirtual void streamout_begin() = 0;\n\tvirtual void streamout_rendererFinishDrawcall() = 0;\n\n\t// core drawing logic\n\tvirtual void draw_beginSequence() = 0;\n\tvirtual void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) = 0;\n\tvirtual void draw_endSequence() = 0;\n\n\t// index\n\tstruct IndexAllocation\n\t{\n\t\tvoid* mem; // pointer to index data inside buffer\n\t\tvoid* rendererInternal; // for renderer use\n\t};\n\n\tvirtual IndexAllocation indexData_reserveIndexMemory(uint32 size) = 0;\n\tvirtual void indexData_releaseIndexMemory(IndexAllocation& allocation) = 0;\n\tvirtual void indexData_uploadIndexMemory(IndexAllocation& allocation) = 0;\n\n\t// occlusion queries\n\tvirtual LatteQueryObject* occlusionQuery_create() = 0;\n\tvirtual void occlusionQuery_destroy(LatteQueryObject* queryObj) = 0;\n\tvirtual void occlusionQuery_flush() = 0;\n\tvirtual void occlusionQuery_updateState() = 0;\n\nprotected:\n\tvirtual void GetVendorInformation() { }\n\tGfxVendor m_vendor = GfxVendor::Generic;\n\n\tstatic uint8 SRGBComponentToRGB(uint8 ci);\n\tstatic uint8 RGBComponentToSRGB(uint8 cli);\n\n\tenum class ScreenshotState\n\t{\n\t\tNone,\n\t\tMain,\n\t\tPad,\n\t};\n\tScreenshotState m_screenshot_state = ScreenshotState::None;\n\tbool m_screenshot_requested = false;\n\tScreenshotSaveFunction m_on_save_screenshot;\n\n\tvoid SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int height, bool mainWindow);\n\n\n\tImFontAtlas* imguiFontAtlas{};\n\tImGuiContext* imguiTVContext{};\n\tImGuiContext* imguiPadContext{};\n\n#if BOOST_OS_WINDOWS\n\tstd::unique_ptr<DXGIWrapper> m_dxgi_wrapper{};\n#endif\n};\n\nextern std::unique_ptr<Renderer> g_renderer;\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/RendererOuputShader.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/RendererOuputShader.h\"\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n#include \"config/ActiveSettings.h\"\n\nconst std::string RendererOutputShader::s_copy_shader_source =\nR\"(\nvoid outputShader()\n{\n\tcolorOut0 = vec4(texture(textureSrc, passUV).rgb,1.0);\n}\n)\";\n\nconst std::string RendererOutputShader::s_copy_shader_source_mtl =\nR\"(#include <metal_stdlib>\nusing namespace metal;\n\nstruct VertexOut {\n    float2 uv;\n};\n\nfragment float4 main0(VertexOut in [[stage_in]], texture2d<float> textureSrc [[texture(0)]], sampler samplr [[sampler(0)]]) {\n\treturn float4(textureSrc.sample(samplr, in.uv).rgb, 1.0);\n}\n)\";\n\nconst std::string RendererOutputShader::s_bicubic_shader_source =\nR\"(\nvec4 cubic(float x)\n{\n\tfloat x2 = x * x;\n\tfloat x3 = x2 * x;\n\tvec4 w;\n\tw.x = -x3 + 3 * x2 - 3 * x + 1;\n\tw.y = 3 * x3 - 6 * x2 + 4;\n\tw.z = -3 * x3 + 3 * x2 + 3 * x + 1;\n\tw.w = x3;\n\treturn w / 6.0;\n}\n\nvec4 bcFilter(vec2 uv, vec4 texelSize)\n{\n\tvec2 pixel = uv*texelSize.zw - 0.5;\n\tvec2 pixelFrac = fract(pixel);\n\tvec2 pixelInt = pixel - pixelFrac;\n\n\tvec4 xcubic = cubic(pixelFrac.x);\n\tvec4 ycubic = cubic(pixelFrac.y);\n\n\tvec4 c = vec4(pixelInt.x - 0.5, pixelInt.x + 1.5, pixelInt.y - 0.5, pixelInt.y + 1.5);\n\tvec4 s = vec4(xcubic.x + xcubic.y, xcubic.z + xcubic.w, ycubic.x + ycubic.y, ycubic.z + ycubic.w);\n\tvec4 offset = c + vec4(xcubic.y, xcubic.w, ycubic.y, ycubic.w) / s;\n\n\tvec4 sample0 = texture(textureSrc, vec2(offset.x, offset.z) * texelSize.xy);\n\tvec4 sample1 = texture(textureSrc, vec2(offset.y, offset.z) * texelSize.xy);\n\tvec4 sample2 = texture(textureSrc, vec2(offset.x, offset.w) * texelSize.xy);\n\tvec4 sample3 = texture(textureSrc, vec2(offset.y, offset.w) * texelSize.xy);\n\n\tfloat sx = s.x / (s.x + s.y);\n\tfloat sy = s.z / (s.z + s.w);\n\n\treturn mix(\n\t\tmix(sample3, sample2, sx),\n\t\tmix(sample1, sample0, sx), sy);\n}\n\nvoid outputShader(){\n\tvec4 texelSize = vec4( 1.0 / textureSrcResolution.xy, textureSrcResolution.xy);\n\tcolorOut0 = vec4(bcFilter(passUV, texelSize).rgb,1.0);\n}\n)\";\n\nconst std::string RendererOutputShader::s_bicubic_shader_source_mtl =\nR\"(#include <metal_stdlib>\nusing namespace metal;\n\nfloat4 cubic(float x) {\n\tfloat x2 = x * x;\n\tfloat x3 = x2 * x;\n\tfloat4 w;\n\tw.x = -x3 + 3 * x2 - 3 * x + 1;\n\tw.y = 3 * x3 - 6 * x2 + 4;\n\tw.z = -3 * x3 + 3 * x2 + 3 * x + 1;\n\tw.w = x3;\n\treturn w / 6.0;\n}\n\nfloat4 bcFilter(texture2d<float> textureSrc, sampler samplr, float2 texcoord, float2 texscale) {\n\tfloat fx = fract(texcoord.x);\n\tfloat fy = fract(texcoord.y);\n\ttexcoord.x -= fx;\n\ttexcoord.y -= fy;\n\n\tfloat4 xcubic = cubic(fx);\n\tfloat4 ycubic = cubic(fy);\n\n\tfloat4 c = float4(texcoord.x - 0.5, texcoord.x + 1.5, texcoord.y - 0.5, texcoord.y + 1.5);\n\tfloat4 s = float4(xcubic.x + xcubic.y, xcubic.z + xcubic.w, ycubic.x + ycubic.y, ycubic.z + ycubic.w);\n\tfloat4 offset = c + float4(xcubic.y, xcubic.w, ycubic.y, ycubic.w) / s;\n\n\tfloat4 sample0 = textureSrc.sample(samplr, float2(offset.x, offset.z) * texscale);\n\tfloat4 sample1 = textureSrc.sample(samplr, float2(offset.y, offset.z) * texscale);\n\tfloat4 sample2 = textureSrc.sample(samplr, float2(offset.x, offset.w) * texscale);\n\tfloat4 sample3 = textureSrc.sample(samplr, float2(offset.y, offset.w) * texscale);\n\n\tfloat sx = s.x / (s.x + s.y);\n\tfloat sy = s.z / (s.z + s.w);\n\n\treturn mix(\n\t\tmix(sample3, sample2, sx),\n\t\tmix(sample1, sample0, sx), sy);\n}\n\nstruct VertexOut {\n    float2 uv;\n};\n\nfragment float4 main0(VertexOut in [[stage_in]], texture2d<float> textureSrc [[texture(0)]], sampler samplr [[sampler(0)]]) {\n    float2 textureSrcResolution = float2(textureSrc.get_width(), textureSrc.get_height());\n\treturn float4(bcFilter(textureSrc, samplr, in.uv * textureSrcResolution, float2(1.0, 1.0) / textureSrcResolution).rgb, 1.0);\n}\n)\";\n\nconst std::string RendererOutputShader::s_hermite_shader_source =\nR\"(\n// https://www.shadertoy.com/view/MllSzX\n\nvec3 CubicHermite (vec3 A, vec3 B, vec3 C, vec3 D, float t)\n{\n\tfloat t2 = t*t;\n    float t3 = t*t*t;\n    vec3 a = -A/2.0 + (3.0*B)/2.0 - (3.0*C)/2.0 + D/2.0;\n    vec3 b = A - (5.0*B)/2.0 + 2.0*C - D / 2.0;\n    vec3 c = -A/2.0 + C/2.0;\n   \tvec3 d = B;\n\n    return a*t3 + b*t2 + c*t + d;\n}\n\n\nvec3 BicubicHermiteTexture(vec2 uv, vec4 texelSize)\n{\n\tvec2 pixel = uv*texelSize.zw + 0.5;\n\tvec2 frac = fract(pixel);\n    pixel = floor(pixel) / texelSize.zw - vec2(texelSize.xy/2.0);\n\n\tvec4 doubleSize = texelSize*2.0;\n\n\tvec3 C00 = texture(textureSrc, pixel + vec2(-texelSize.x ,-texelSize.y)).rgb;\n    vec3 C10 = texture(textureSrc, pixel + vec2( 0.0        ,-texelSize.y)).rgb;\n    vec3 C20 = texture(textureSrc, pixel + vec2( texelSize.x ,-texelSize.y)).rgb;\n    vec3 C30 = texture(textureSrc, pixel + vec2( doubleSize.x,-texelSize.y)).rgb;\n\n    vec3 C01 = texture(textureSrc, pixel + vec2(-texelSize.x , 0.0)).rgb;\n    vec3 C11 = texture(textureSrc, pixel + vec2( 0.0        , 0.0)).rgb;\n    vec3 C21 = texture(textureSrc, pixel + vec2( texelSize.x , 0.0)).rgb;\n    vec3 C31 = texture(textureSrc, pixel + vec2( doubleSize.x, 0.0)).rgb;\n\n    vec3 C02 = texture(textureSrc, pixel + vec2(-texelSize.x , texelSize.y)).rgb;\n    vec3 C12 = texture(textureSrc, pixel + vec2( 0.0        , texelSize.y)).rgb;\n    vec3 C22 = texture(textureSrc, pixel + vec2( texelSize.x , texelSize.y)).rgb;\n    vec3 C32 = texture(textureSrc, pixel + vec2( doubleSize.x, texelSize.y)).rgb;\n\n    vec3 C03 = texture(textureSrc, pixel + vec2(-texelSize.x , doubleSize.y)).rgb;\n    vec3 C13 = texture(textureSrc, pixel + vec2( 0.0        , doubleSize.y)).rgb;\n    vec3 C23 = texture(textureSrc, pixel + vec2( texelSize.x , doubleSize.y)).rgb;\n    vec3 C33 = texture(textureSrc, pixel + vec2( doubleSize.x, doubleSize.y)).rgb;\n\n    vec3 CP0X = CubicHermite(C00, C10, C20, C30, frac.x);\n    vec3 CP1X = CubicHermite(C01, C11, C21, C31, frac.x);\n    vec3 CP2X = CubicHermite(C02, C12, C22, C32, frac.x);\n    vec3 CP3X = CubicHermite(C03, C13, C23, C33, frac.x);\n\n    return CubicHermite(CP0X, CP1X, CP2X, CP3X, frac.y);\n}\n\nvoid outputShader(){\n\tvec4 texelSize = vec4( 1.0 / textureSrcResolution.xy, textureSrcResolution.xy);\n\tcolorOut0 = vec4(BicubicHermiteTexture(passUV, texelSize), 1.0);\n}\n)\";\n\nconst std::string RendererOutputShader::s_hermite_shader_source_mtl =\nR\"(#include <metal_stdlib>\nusing namespace metal;\n\n// https://www.shadertoy.com/view/MllSzX\n\nfloat3 CubicHermite(float3 A, float3 B, float3 C, float3 D, float t) {\n\tfloat t2 = t*t;\n    float t3 = t*t*t;\n    float3 a = -A/2.0 + (3.0*B)/2.0 - (3.0*C)/2.0 + D/2.0;\n    float3 b = A - (5.0*B)/2.0 + 2.0*C - D / 2.0;\n    float3 c = -A/2.0 + C/2.0;\n   \tfloat3 d = B;\n\n    return a*t3 + b*t2 + c*t + d;\n}\n\n\nfloat3 BicubicHermiteTexture(texture2d<float> textureSrc, sampler samplr, float2 uv, float4 texelSize) {\n\tfloat2 pixel = uv*texelSize.zw + 0.5;\n\tfloat2 frac = fract(pixel);\n    pixel = floor(pixel) / texelSize.zw - float2(texelSize.xy/2.0);\n\n\tfloat4 doubleSize = texelSize*texelSize;\n\n\tfloat3 C00 = textureSrc.sample(samplr, pixel + float2(-texelSize.x ,-texelSize.y)).rgb;\n    float3 C10 = textureSrc.sample(samplr, pixel + float2( 0.0        ,-texelSize.y)).rgb;\n    float3 C20 = textureSrc.sample(samplr, pixel + float2( texelSize.x ,-texelSize.y)).rgb;\n    float3 C30 = textureSrc.sample(samplr, pixel + float2( doubleSize.x,-texelSize.y)).rgb;\n\n    float3 C01 = textureSrc.sample(samplr, pixel + float2(-texelSize.x , 0.0)).rgb;\n    float3 C11 = textureSrc.sample(samplr, pixel + float2( 0.0        , 0.0)).rgb;\n    float3 C21 = textureSrc.sample(samplr, pixel + float2( texelSize.x , 0.0)).rgb;\n    float3 C31 = textureSrc.sample(samplr, pixel + float2( doubleSize.x, 0.0)).rgb;\n\n    float3 C02 = textureSrc.sample(samplr, pixel + float2(-texelSize.x , texelSize.y)).rgb;\n    float3 C12 = textureSrc.sample(samplr, pixel + float2( 0.0        , texelSize.y)).rgb;\n    float3 C22 = textureSrc.sample(samplr, pixel + float2( texelSize.x , texelSize.y)).rgb;\n    float3 C32 = textureSrc.sample(samplr, pixel + float2( doubleSize.x, texelSize.y)).rgb;\n\n    float3 C03 = textureSrc.sample(samplr, pixel + float2(-texelSize.x , doubleSize.y)).rgb;\n    float3 C13 = textureSrc.sample(samplr, pixel + float2( 0.0        , doubleSize.y)).rgb;\n    float3 C23 = textureSrc.sample(samplr, pixel + float2( texelSize.x , doubleSize.y)).rgb;\n    float3 C33 = textureSrc.sample(samplr, pixel + float2( doubleSize.x, doubleSize.y)).rgb;\n\n    float3 CP0X = CubicHermite(C00, C10, C20, C30, frac.x);\n    float3 CP1X = CubicHermite(C01, C11, C21, C31, frac.x);\n    float3 CP2X = CubicHermite(C02, C12, C22, C32, frac.x);\n    float3 CP3X = CubicHermite(C03, C13, C23, C33, frac.x);\n\n    return CubicHermite(CP0X, CP1X, CP2X, CP3X, frac.y);\n}\n\nstruct VertexOut {\n    float4 position [[position]];\n    float2 uv;\n};\n\nfragment float4 main0(VertexOut in [[stage_in]], texture2d<float> textureSrc [[texture(0)]], sampler samplr [[sampler(0)]], constant float2& outputResolution [[buffer(0)]]) {\n\tfloat4 texelSize = float4(1.0 / outputResolution.xy, outputResolution.xy);\n\treturn float4(BicubicHermiteTexture(textureSrc, samplr, in.uv, texelSize), 1.0);\n}\n)\";\n\nRendererOutputShader::RendererOutputShader(const std::string& vertex_source, const std::string& fragment_source)\n{\n    std::string finalFragmentSrc;\n    if (g_renderer->GetType() == RendererAPI::Metal)\n        finalFragmentSrc = fragment_source;\n    else\n        finalFragmentSrc = PrependFragmentPreamble(fragment_source);\n\n\tm_vertex_shader.reset(g_renderer->shader_create(RendererShader::ShaderType::kVertex, 0, 0, vertex_source, false, false));\n\tm_fragment_shader.reset(g_renderer->shader_create(RendererShader::ShaderType::kFragment, 0, 0, finalFragmentSrc, false, false));\n\n\tm_vertex_shader->PreponeCompilation(true);\n\tm_fragment_shader->PreponeCompilation(true);\n\n\tif (!m_vertex_shader->WaitForCompiled())\n\t\tthrow std::exception();\n\n\tif(!m_fragment_shader->WaitForCompiled())\n\t\tthrow std::exception();\n\n}\n\nRendererOutputShader::OutputUniformVariables RendererOutputShader::FillUniformBlockBuffer(const LatteTextureView& texture_view, const Vector2i& output_res, const bool padView) const\n{\n\tOutputUniformVariables vars;\n\n\tsint32 effectiveWidth, effectiveHeight;\n\ttexture_view.baseTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, 0);\n\tvars.textureSrcResolution = {(float)effectiveWidth, (float)effectiveHeight};\n\n\tvars.nativeResolution = {(float)texture_view.baseTexture->width, (float)texture_view.baseTexture->height};\n\tvars.outputResolution = output_res;\n\n\tvars.applySRGBEncoding = padView ? LatteGPUState.drcBufferUsesSRGB : LatteGPUState.tvBufferUsesSRGB;\n\tvars.targetGamma = padView ? ActiveSettings::GetDRCGamma() : ActiveSettings::GetTVGamma();\n\tvars.displayGamma = GetConfig().userDisplayGamma;\n\n\treturn vars;\n}\n\nRendererOutputShader* RendererOutputShader::s_copy_shader;\nRendererOutputShader* RendererOutputShader::s_copy_shader_ud;\n\nRendererOutputShader* RendererOutputShader::s_bicubic_shader;\nRendererOutputShader* RendererOutputShader::s_bicubic_shader_ud;\n\nRendererOutputShader* RendererOutputShader::s_hermit_shader;\nRendererOutputShader* RendererOutputShader::s_hermit_shader_ud;\n\nstd::string RendererOutputShader::GetOpenGlVertexSource(bool render_upside_down)\n{\n\t// vertex shader\n\tstd::ostringstream vertex_source;\n\t\tvertex_source <<\n\t\t\tR\"(#version 420\nlayout(location = 0) smooth out vec2 passUV;\n\nout gl_PerVertex\n{\n   vec4 gl_Position;\n};\n\nvoid main(){\n\tvec2 vPos;\n\tvec2 vUV;\n\tint vID = gl_VertexID;\n)\";\n\n\t\tif (render_upside_down)\n\t\t{\n\t\t\tvertex_source <<\n\t\t\t\tR\"(\tif( vID == 0 ) { vPos = vec2(1.0,1.0); vUV = vec2(1.0,0.0); }\n\telse if( vID == 1 ) { vPos = vec2(-1.0,1.0); vUV = vec2(0.0,0.0); }\n\telse if( vID == 2 ) { vPos = vec2(-1.0,-1.0); vUV = vec2(0.0,1.0); }\n\telse if( vID == 3 ) { vPos = vec2(-1.0,-1.0); vUV = vec2(0.0,1.0); }\n\telse if( vID == 4 ) { vPos = vec2(1.0,-1.0); vUV = vec2(1.0,1.0); }\n\telse if( vID == 5 ) { vPos = vec2(1.0,1.0); vUV = vec2(1.0,0.0); }\n\t)\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvertex_source <<\n\t\t\t\tR\"(\tif( vID == 0 ) { vPos = vec2(1.0,1.0); vUV = vec2(1.0,1.0); }\n\telse if( vID == 1 ) { vPos = vec2(-1.0,1.0); vUV = vec2(0.0,1.0); }\n\telse if( vID == 2 ) { vPos = vec2(-1.0,-1.0); vUV = vec2(0.0,0.0); }\n\telse if( vID == 3 ) { vPos = vec2(-1.0,-1.0); vUV = vec2(0.0,0.0); }\n\telse if( vID == 4 ) { vPos = vec2(1.0,-1.0); vUV = vec2(1.0,0.0); }\n\telse if( vID == 5 ) { vPos = vec2(1.0,1.0); vUV = vec2(1.0,1.0); }\n\t)\";\n\t\t}\n\n\t\tvertex_source <<\n\t\t\tR\"(\tpassUV = vUV;\n\tgl_Position = vec4(vPos, 0.0, 1.0);\n}\n)\";\n\t\treturn vertex_source.str();\n}\n\nstd::string RendererOutputShader::GetVulkanVertexSource(bool render_upside_down)\n{\n\t// vertex shader\n\tstd::ostringstream vertex_source;\n\t\tvertex_source <<\n\t\t\tR\"(#version 450\nlayout(location = 0) out vec2 passUV;\n\nout gl_PerVertex\n{\n   vec4 gl_Position;\n};\n\nvoid main(){\n\tvec2 vPos;\n\tvec2 vUV;\n\tint vID = gl_VertexIndex;\n)\";\n\n\t\tif (render_upside_down)\n\t\t{\n\t\t\tvertex_source <<\n\t\t\t\tR\"(\tif( vID == 0 ) { vPos = vec2(1.0,1.0); vUV = vec2(1.0,0.0); }\n\telse if( vID == 1 ) { vPos = vec2(-1.0,1.0); vUV = vec2(0.0,0.0); }\n\telse if( vID == 2 ) { vPos = vec2(-1.0,-1.0); vUV = vec2(0.0,1.0); }\n\telse if( vID == 3 ) { vPos = vec2(-1.0,-1.0); vUV = vec2(0.0,1.0); }\n\telse if( vID == 4 ) { vPos = vec2(1.0,-1.0); vUV = vec2(1.0,1.0); }\n\telse if( vID == 5 ) { vPos = vec2(1.0,1.0); vUV = vec2(1.0,0.0); }\n\t)\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvertex_source <<\n\t\t\t\tR\"(\tif( vID == 0 ) { vPos = vec2(1.0,1.0); vUV = vec2(1.0,1.0); }\n\telse if( vID == 1 ) { vPos = vec2(-1.0,1.0); vUV = vec2(0.0,1.0); }\n\telse if( vID == 2 ) { vPos = vec2(-1.0,-1.0); vUV = vec2(0.0,0.0); }\n\telse if( vID == 3 ) { vPos = vec2(-1.0,-1.0); vUV = vec2(0.0,0.0); }\n\telse if( vID == 4 ) { vPos = vec2(1.0,-1.0); vUV = vec2(1.0,0.0); }\n\telse if( vID == 5 ) { vPos = vec2(1.0,1.0); vUV = vec2(1.0,1.0); }\n\t)\";\n\t\t}\n\n\t\tvertex_source <<\n\t\t\tR\"(\tpassUV = vUV;\n\tgl_Position = vec4(vPos, 0.0, 1.0);\n}\n)\";\n\t\treturn vertex_source.str();\n}\n\nstd::string RendererOutputShader::GetMetalVertexSource(bool render_upside_down)\n{\n\t// vertex shader\n\tstd::ostringstream vertex_source;\n\t\tvertex_source <<\n\t\t\tR\"(#include <metal_stdlib>\nusing namespace metal;\n\nstruct VertexOut {\n    float4 position [[position]];\n    float2 uv;\n};\n\nvertex VertexOut main0(ushort vid [[vertex_id]]) {\n\tVertexOut out;\n\tfloat2 pos;\n\tif (vid == 0) pos = float2(-1.0, -3.0);\n\telse if (vid == 1) pos = float2(-1.0, 1.0);\n\telse if (vid == 2) pos = float2(3.0, 1.0);\n\tout.uv = pos * 0.5 + 0.5;\n\tout.uv.y = 1.0 - out.uv.y;\n)\";\n\n\t\tif (render_upside_down)\n\t\t{\n\t\t\tvertex_source <<\n\t\t\t\tR\"(\tpos.y = -pos.y;\n\t)\";\n\t\t}\n\n\t\tvertex_source <<\n\t\t\tR\"(\tout.position = float4(pos, 0.0, 1.0);\n\treturn out;\n}\n)\";\n\t\treturn vertex_source.str();\n}\n\nstd::string RendererOutputShader::PrependFragmentPreamble(const std::string& shaderSrc)\n{\n\treturn R\"(#version 430\nlayout(location = 0) smooth in vec2 passUV;\nlayout(binding = 0) uniform sampler2D textureSrc;\nlayout(location = 0) out vec4 colorOut0;\n\n#ifdef VULKAN\nlayout (binding = 1, std140)\n#else\nlayout (binding = 0, std140)\n#endif\nuniform parameters {\nuniform vec2 textureSrcResolution;\nuniform vec2 nativeResolution;\nuniform vec2 outputResolution;\nuniform bool applySRGBEncoding;\nuniform float targetGamma;\nuniform float displayGamma;\n};\n\nfloat sRGBEncode(float linear)\n{\n\tif(linear <= 0.0031308)\n\t\treturn 12.92f * linear;\n\telse\n\t\treturn 1.055f * pow(linear, 1.0f / 2.4f) - 0.055f;\n\n}\n\nvec3 sRGBEncode(vec3 linear)\n{\n\treturn vec3(sRGBEncode(linear.r), sRGBEncode(linear.g), sRGBEncode(linear.b));\n}\n\n// fwd. declaration\nvoid outputShader();\nvoid main()\n{\n\toutputShader(); // sets colorOut0\n\tif(applySRGBEncoding)\n\t\tcolorOut0 = vec4(sRGBEncode(colorOut0.rgb), 1.0f);\n\n\tif (displayGamma > 0.0f)\n\t\tcolorOut0 = pow(colorOut0, vec4(targetGamma / displayGamma) );\n\telse\n\t\tcolorOut0 = vec4( sRGBEncode( pow(colorOut0.rgb, vec3(targetGamma)) ), 1.0f);\n\n}\n\n)\" + shaderSrc;\n}\nvoid RendererOutputShader::InitializeStatic()\n{\n    if (g_renderer->GetType() == RendererAPI::Metal)\n    {\n        std::string vertex_source = GetMetalVertexSource(false);\n        std::string vertex_source_ud = GetMetalVertexSource(true);\n\n       \ts_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source_mtl);\n       \ts_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source_mtl);\n\n       \ts_bicubic_shader = new RendererOutputShader(vertex_source, s_bicubic_shader_source_mtl);\n       \ts_bicubic_shader_ud = new RendererOutputShader(vertex_source_ud, s_bicubic_shader_source_mtl);\n\n       \ts_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source_mtl);\n       \ts_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source_mtl);\n    }\n    else\n    {\n    \tstd::string vertex_source, vertex_source_ud;\n    \t// vertex shader\n    \tif (g_renderer->GetType() == RendererAPI::OpenGL)\n    \t{\n    \t\tvertex_source = GetOpenGlVertexSource(false);\n    \t\tvertex_source_ud = GetOpenGlVertexSource(true);\n    \t}\n    \telse if (g_renderer->GetType() == RendererAPI::Vulkan)\n    \t{\n    \t\tvertex_source = GetVulkanVertexSource(false);\n    \t\tvertex_source_ud = GetVulkanVertexSource(true);\n    \t}\n    \ts_copy_shader = new RendererOutputShader(vertex_source, s_copy_shader_source);\n    \ts_copy_shader_ud = new RendererOutputShader(vertex_source_ud, s_copy_shader_source);\n\n    \ts_bicubic_shader = new RendererOutputShader(vertex_source, s_bicubic_shader_source);\n    \ts_bicubic_shader_ud = new RendererOutputShader(vertex_source_ud, s_bicubic_shader_source);\n\n    \ts_hermit_shader = new RendererOutputShader(vertex_source, s_hermite_shader_source);\n    \ts_hermit_shader_ud = new RendererOutputShader(vertex_source_ud, s_hermite_shader_source);\n    }\n}\n\nvoid RendererOutputShader::ShutdownStatic()\n{\n\tdelete s_copy_shader;\n\tdelete s_copy_shader_ud;\n\n\tdelete s_bicubic_shader;\n\tdelete s_bicubic_shader_ud;\n\n\tdelete s_hermit_shader;\n\tdelete s_hermit_shader_ud;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/RendererOuputShader.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/RendererShader.h\"\n#include \"util/math/vector2.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n\nclass RendererOutputShader\n{\npublic:\n\tstruct OutputUniformVariables\n\t{\n\t\tVector2f textureSrcResolution;\n\t\tVector2f nativeResolution;\n\t\tVector2f outputResolution;\n\t\tuint32 applySRGBEncoding;\n\t\tfloat targetGamma;\n\t\tfloat displayGamma;\n\t};\n\tenum Shader\n\t{\n\t\tkCopy,\n\t\tkBicubic,\n\t\tkHermit,\n\t};\n\tRendererOutputShader(const std::string& vertex_source, const std::string& fragment_source);\n\tvirtual ~RendererOutputShader() = default;\n\n\tOutputUniformVariables FillUniformBlockBuffer(const LatteTextureView& texture_view, const Vector2i& output_res, const bool padView) const;\n\n\tRendererShader* GetVertexShader() const\n\t{\n\t\treturn m_vertex_shader.get();\n\t}\n\n\tRendererShader* GetFragmentShader() const\n\t{\n\t\treturn m_fragment_shader.get();\n\t}\n\n\tstatic void InitializeStatic();\n\tstatic void ShutdownStatic();\n\n\tstatic RendererOutputShader* s_copy_shader;\n\tstatic RendererOutputShader* s_copy_shader_ud;\n\n\tstatic RendererOutputShader* s_bicubic_shader;\n\tstatic RendererOutputShader* s_bicubic_shader_ud;\n\n\tstatic RendererOutputShader* s_hermit_shader;\n\tstatic RendererOutputShader* s_hermit_shader_ud;\n\n\tstatic std::string GetOpenGlVertexSource(bool render_upside_down);\n\tstatic std::string GetVulkanVertexSource(bool render_upside_down);\n\tstatic std::string GetMetalVertexSource(bool render_upside_down);\n\n\tstatic std::string PrependFragmentPreamble(const std::string& shaderSrc);\n\nprotected:\n\tstd::unique_ptr<RendererShader> m_vertex_shader;\n\tstd::unique_ptr<RendererShader> m_fragment_shader;\n\n\nprivate:\n\tstatic const std::string s_copy_shader_source;\n\tstatic const std::string s_bicubic_shader_source;\n\tstatic const std::string s_hermite_shader_source;\n\n\tstatic const std::string s_bicubic_shader_source_vk;\n\tstatic const std::string s_hermite_shader_source_vk;\n\n\tstatic const std::string s_copy_shader_source_mtl;\n\tstatic const std::string s_bicubic_shader_source_mtl;\n\tstatic const std::string s_hermite_shader_source_mtl;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/RendererShader.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/RendererShader.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n\n// generate a Cemu version and setting dependent id\nuint32 RendererShader::GeneratePrecompiledCacheId()\n{\n\tuint32 v = 0;\n\tconst char* s = EMULATOR_VERSION_SUFFIX;\n\twhile (*s)\n\t{\n\t\tv = std::rotl<uint32>(v, 7);\n\t\tv += (uint32)(*s);\n\t\ts++;\n\t}\n\tv += (EMULATOR_VERSION_MAJOR * 1000000u);\n\tv += (EMULATOR_VERSION_MINOR * 10000u);\n\tv += (EMULATOR_VERSION_PATCH * 100u);\n\n\t// settings that can influence shaders\n\tv += (uint32)g_current_game_profile->GetAccurateShaderMul() * 133;\n\n\treturn v;\n}\n\nvoid RendererShader::GenerateShaderPrecompiledCacheFilename(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, uint64& h1, uint64& h2)\n{\n\th1 = baseHash;\n\th2 = auxHash;\n\n\tif (type == RendererShader::ShaderType::kVertex)\n\t\th2 += 0xA16374cull;\n\telse if (type == RendererShader::ShaderType::kFragment)\n\t\th2 += 0x8752deull;\n\telse if (type == RendererShader::ShaderType::kGeometry)\n\t\th2 += 0x65a035ull;\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/RendererShader.h",
    "content": "#pragma once\n\nclass RendererShader\n{\npublic:\n\tenum class ShaderType\n\t{\n\t\tkVertex,\n\t\tkFragment,\n\t\tkGeometry\n\t};\n\n\tvirtual ~RendererShader() = default;\n\n\tShaderType GetType() const { return m_type; }\n\t\n\tvirtual void PreponeCompilation(bool isRenderThread) = 0; // if shader not yet compiled, compile it synchronously (if possible) or alternatively wait for compilation. After this function IsCompiled() is guaranteed to be true\n\tvirtual bool IsCompiled() = 0;\n\tvirtual bool WaitForCompiled() = 0;\n\n\nprotected:\n\t// if isGameShader is true, then baseHash and auxHash are valid\n\tRendererShader(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader)\n\t\t: m_type(type), m_baseHash(baseHash), m_auxHash(auxHash), m_isGameShader(isGameShader), m_isGfxPackShader(isGfxPackShader) {}\n\n\tstatic uint32 GeneratePrecompiledCacheId();\n\tstatic void GenerateShaderPrecompiledCacheFilename(ShaderType type, uint64 baseHash, uint64 auxHash, uint64& h1, uint64& h2);\n\nprotected:\n\tShaderType m_type;\n\tuint64 m_baseHash;\t\n\tuint64 m_auxHash;\n\tbool m_isGameShader;\n\tbool m_isGfxPackShader;\n};\n\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h\"\n\nvoid CachedFBOVk::CreateRenderPass()\n{\n\tVKRObjectRenderPass::AttachmentInfo_t attachmentInfo;\n\n\tfor (int i = 0; i < 8; ++i)\n\t{\n\t\tauto& buffer = colorBuffer[i];\n\t\tauto textureViewVk = (LatteTextureViewVk*)buffer.texture;\n\t\tif (!textureViewVk)\n\t\t{\n\t\t\tattachmentInfo.colorAttachment[i].viewObj = nullptr;\n\t\t\tcontinue;\n\t\t}\n\t\t// setup color attachment\n\t\tauto viewObj = textureViewVk->GetViewRGBA();\n\t\tattachmentInfo.colorAttachment[i].viewObj = viewObj;\n\t\tattachmentInfo.colorAttachment[i].format = textureViewVk->GetFormat();\n\t}\n\n\t// setup depth attachment\n\tif (depthBuffer.texture)\n\t{\n\t\tLatteTextureViewVk* depthTexVk = static_cast<LatteTextureViewVk*>(depthBuffer.texture);\n\t\tauto depthBufferViewObj = depthTexVk->GetViewRGBA();\n\t\tattachmentInfo.depthAttachment.viewObj = depthBufferViewObj;\n\t\tattachmentInfo.depthAttachment.format = depthTexVk->GetFormat();\n\t\tattachmentInfo.depthAttachment.hasStencil = depthTexVk->baseTexture->hasStencil;\n\t}\n\telse\n\t{\n\t\t// no depth attachment\n\t\tattachmentInfo.depthAttachment.viewObj = nullptr;\n\t}\n\n\tm_vkrObjRenderPass = new VKRObjectRenderPass(attachmentInfo);\n}\n\nCachedFBOVk::~CachedFBOVk()\n{\n\twhile (!m_usedByPipelines.empty())\n\t\tdelete m_usedByPipelines[0];\n\tauto vkr = VulkanRenderer::GetInstance();\n\tvkr->ReleaseDestructibleObject(m_vkrObjFramebuffer);\n\tm_vkrObjFramebuffer = nullptr;\n\tvkr->ReleaseDestructibleObject(m_vkrObjRenderPass);\n\tm_vkrObjRenderPass = nullptr;\n}\n\nVKRObjectTextureView* CachedFBOVk::GetColorBufferImageView(uint32 index)\n{\n\tcemu_assert(index < 8);\n\tauto& cb = colorBuffer[index];\n\tauto textureViewVk = (LatteTextureViewVk*)cb.texture;\n\tif (!textureViewVk)\n\t\treturn nullptr;\n\tauto viewDim = textureViewVk->dim;\n\tif (viewDim == Latte::E_DIM::DIM_3D)\n\t\tviewDim = Latte::E_DIM::DIM_2D; // bind 3D texture slices as 2D images\n\treturn textureViewVk->GetViewRGBA();\n}\n\nVKRObjectTextureView* CachedFBOVk::GetDepthStencilBufferImageView(bool& hasStencil)\n{\n\thasStencil = false;\n\tauto textureViewVk = (LatteTextureViewVk*)depthBuffer.texture;\n\tif (!textureViewVk)\n\t\treturn nullptr;\n\tcemu_assert_debug(textureViewVk->numMip == 1);\n\thasStencil = textureViewVk->baseTexture->hasStencil;\n\treturn textureViewVk->GetViewRGBA();\n}\n\nvoid CachedFBOVk::CreateFramebuffer()\n{\n\tstd::array<VKRObjectTextureView*, 9> imageViews{};\n\tint imageViewIndex = 0;\n\tfor (uint32 i = 0; i < 8; ++i)\n\t{\n\t\tVKRObjectTextureView* cbView = GetColorBufferImageView(i);\n\t\tif (!cbView)\n\t\t\tcontinue;\n\t\timageViews[imageViewIndex++] = cbView;\n\t}\n\n\tbool hasStencil = false;\n\tVKRObjectTextureView* depthStencilView = GetDepthStencilBufferImageView(hasStencil);\n\tif (depthStencilView)\n\t\timageViews[imageViewIndex++] = depthStencilView;\n\n\tcemu_assert_debug(imageViewIndex < 9);\n\n\tm_vkrObjFramebuffer = new VKRObjectFramebuffer(m_vkrObjRenderPass, std::span<VKRObjectTextureView*>(imageViews.data(), imageViewIndex), m_size);\n\n\tm_extend = { (uint32)m_size.x, (uint32)m_size.y };\n}\n\n\nvoid CachedFBOVk::InitDynamicRenderingData()\n{\n\t// init struct for KHR_dynamic_rendering\n\tfor (int i = 0; i < 8; ++i)\n\t{\n\t\tm_vkColorAttachments[i].sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;\n\t\tm_vkColorAttachments[i].pNext = nullptr;\n\t\tm_vkColorAttachments[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\n\t\tm_vkColorAttachments[i].resolveMode = VK_RESOLVE_MODE_NONE;\n\t\tm_vkColorAttachments[i].resolveImageView = VK_NULL_HANDLE;\n\t\tm_vkColorAttachments[i].resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\n\t\tm_vkColorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;\n\t\tm_vkColorAttachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n\n\t\t// ignore clearValue\n\n\t\tVKRObjectTextureView* cbView = GetColorBufferImageView(i);\n\n\t\tauto& buffer = colorBuffer[i];\n\t\tif (!cbView)\n\t\t{\n\t\t\tm_vkColorAttachments[i].imageView = VK_NULL_HANDLE;\n\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t\tm_vkColorAttachments[i].imageView = cbView->m_textureImageView;\n\t}\n\n\tm_vkRenderingInfo.pColorAttachments = m_vkColorAttachments;\n\tm_vkRenderingInfo.colorAttachmentCount = 8;\n\t// trim the color attachment list if tail entries are not set\n\twhile (m_vkRenderingInfo.colorAttachmentCount > 0)\n\t{\n\t\tif (m_vkColorAttachments[m_vkRenderingInfo.colorAttachmentCount - 1].imageView)\n\t\t\tbreak;\n\t\tm_vkRenderingInfo.colorAttachmentCount--;\n\t}\n\n\t// initially set both stencil and depth attachment to an empty default\n\tm_vkDepthAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;\n\tm_vkDepthAttachment.pNext = nullptr;\n\tm_vkDepthAttachment.imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\tm_vkDepthAttachment.resolveMode = VK_RESOLVE_MODE_NONE;\n\tm_vkDepthAttachment.resolveImageView = VK_NULL_HANDLE;\n\tm_vkDepthAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\tm_vkDepthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n\tm_vkDepthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n\n\tm_vkStencilAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;\n\tm_vkStencilAttachment.pNext = nullptr;\n\tm_vkStencilAttachment.imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\tm_vkStencilAttachment.resolveMode = VK_RESOLVE_MODE_NONE;\n\tm_vkStencilAttachment.resolveImageView = VK_NULL_HANDLE;\n\tm_vkStencilAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\tm_vkStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n\tm_vkStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n\n\tm_vkRenderingInfo.pDepthAttachment = nullptr;\n\tm_vkRenderingInfo.pStencilAttachment = nullptr;\n\n\tbool hasStencil = false;\n\tVKRObjectTextureView* depthStencilView = GetDepthStencilBufferImageView(hasStencil);\n\n\t// setup depth and stencil attachment\n\tif (depthStencilView)\n\t{\n\t\tm_vkDepthAttachment.imageView = depthStencilView->m_textureImageView;\n\t\tm_vkDepthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;\n\t\tm_vkDepthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n\t\tm_vkRenderingInfo.pDepthAttachment = &m_vkDepthAttachment;\n\t\tif (hasStencil)\n\t\t{\n\t\t\tm_vkStencilAttachment.imageView = depthStencilView->m_textureImageView;\n\t\t\tm_vkStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;\n\t\t\tm_vkStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n\t\t\tm_vkRenderingInfo.pStencilAttachment = &m_vkStencilAttachment;\n\t\t}\n\t}\n\n\tm_vkRenderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR;\n\tm_vkRenderingInfo.pNext = nullptr;\n\tm_vkRenderingInfo.flags = 0;\n\tm_vkRenderingInfo.renderArea.offset = { 0, 0 };\n\tm_vkRenderingInfo.renderArea.extent = m_extend;\n\tm_vkRenderingInfo.viewMask = 0; // multiview disabled\n\tm_vkRenderingInfo.layerCount = 1;\n}\n\n\nuint32 s_currentCollisionCheckIndex = 1;\n\nbool CachedFBOVk::CheckForCollision(VkDescriptorSetInfo* vsDS, VkDescriptorSetInfo* gsDS, VkDescriptorSetInfo* psDS) const\n{\n\ts_currentCollisionCheckIndex++;\n\tconst uint32 curColIndex = s_currentCollisionCheckIndex;\n\tfor (auto& itr : m_referencedTextures)\n\t{\n\t\tLatteTextureVk* vkTex = (LatteTextureVk*)itr;\n\t\tvkTex->m_collisionCheckIndex = curColIndex;\n\t}\n\tif (vsDS)\n\t{\n\t\tfor (auto& itr : vsDS->list_fboCandidates)\n\t\t{\n\t\t\tif (itr->m_collisionCheckIndex == curColIndex)\n\t\t\t\treturn true;\n\t\t}\n\t}\n\tif (gsDS)\n\t{\n\t\tfor (auto& itr : gsDS->list_fboCandidates)\n\t\t{\n\t\t\tif (itr->m_collisionCheckIndex == curColIndex)\n\t\t\t\treturn true;\n\t\t}\n\t}\n\tif (psDS)\n\t{\n\t\tfor (auto& itr : psDS->list_fboCandidates)\n\t\t{\n\t\t\tif (itr->m_collisionCheckIndex == curColIndex)\n\t\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Core/LatteCachedFBO.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h\"\n\nclass CachedFBOVk : public LatteCachedFBO\n{\npublic:\n\tCachedFBOVk(uint64 key, VkDevice device)\n\t\t: LatteCachedFBO(key), m_device(device)\n\t{\n\t\tCreateRenderPass();\n\t\tCreateFramebuffer();\n\t\tInitDynamicRenderingData();\n\t}\n\n\t~CachedFBOVk();\n\n\tstatic inline FSpinlock s_spinlockDependency;\n\n\tVKRObjectFramebuffer* GetFramebufferObj() const\n\t{\n\t\treturn m_vkrObjFramebuffer;\n\t}\n\n\tVKRObjectRenderPass* GetRenderPassObj() const\n\t{\n\t\treturn m_vkrObjRenderPass;\n\t}\n\n\t// for KHR_dynamic_rendering\n\tVkRenderingInfoKHR* GetRenderingInfo()\n\t{\n\t\treturn &m_vkRenderingInfo;\n\t}\n\n\n\tvoid TrackDependency(class PipelineInfo* pipelineInfo)\n\t{\n\t\ts_spinlockDependency.lock();\n\t\tm_usedByPipelines.emplace_back(pipelineInfo);\n\t\ts_spinlockDependency.unlock();\n\t}\n\n\tvoid RemoveDependency(class PipelineInfo* pipelineInfo)\n\t{\n\t\ts_spinlockDependency.lock();\n\t\tvectorRemoveByValue(m_usedByPipelines, pipelineInfo);\n\t\ts_spinlockDependency.unlock();\n\t}\n\n\t[[nodiscard]] const VkExtent2D& GetExtend() const { return m_extend;}\n\n\t// checks if any of the sampled textures are output by the FBO\n\tbool CheckForCollision(VkDescriptorSetInfo* vsDS, VkDescriptorSetInfo* gsDS, VkDescriptorSetInfo* psDS) const;\n\nprivate:\n\n\tvoid CreateRenderPass();\n\tvoid CreateFramebuffer();\n\n\tvoid InitDynamicRenderingData();\n\n\tVKRObjectTextureView* GetColorBufferImageView(uint32 index);\n\tVKRObjectTextureView* GetDepthStencilBufferImageView(bool& hasStencil);\n\n\tVkDevice m_device;\n\tVKRObjectRenderPass* m_vkrObjRenderPass{};\n\tVKRObjectFramebuffer* m_vkrObjFramebuffer{};\n\n\tVkExtent2D m_extend;\n\n\t// for KHR_dynamic_rendering\n\tVkRenderingInfoKHR m_vkRenderingInfo;\n\tVkRenderingAttachmentInfoKHR m_vkColorAttachments[8];\n\tVkRenderingAttachmentInfoKHR m_vkDepthAttachment;\n\tVkRenderingAttachmentInfoKHR m_vkStencilAttachment;\n\n\tstd::vector<class PipelineInfo*> m_usedByPipelines; // PipelineInfo objects which use this renderpass/framebuffer\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.h",
    "content": "#pragma once\n\n#if BOOST_OS_MACOS\n\n#include <vulkan/vulkan.h>\n\nVkSurfaceKHR CreateCocoaSurface(VkInstance instance, void* handle);\n\n#endif\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n\n#include \"Cafe/HW/Latte/Renderer/MetalView.h\"\n\nVkSurfaceKHR CreateCocoaSurface(VkInstance instance, void* handle)\n{\n\tNSView* view = (NSView*)handle;\n\n\tMetalView* childView = [[MetalView alloc] initWithFrame:view.bounds];\n\tchildView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;\n\tchildView.wantsLayer = YES;\n\n\t[view addSubview:childView];\n\n\tVkMetalSurfaceCreateInfoEXT surface;\n\tsurface.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;\n\tsurface.pNext = NULL;\n\tsurface.flags = 0;\n\tsurface.pLayer = (CAMetalLayer*)childView.layer;\n\n\tVkSurfaceKHR result;\n\tVkResult err;\n\tif ((err = vkCreateMetalSurfaceEXT(instance, &surface, nullptr, &result)) != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Cannot create a Metal Vulkan surface: {}\", (sint32)err);\n\t\tthrow std::runtime_error(fmt::format(\"Cannot create a Metal Vulkan surface: {}\", err));\n\t}\n\n\treturn result;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n\nuint32 LatteTextureVk_AdjustTextureCompSel(Latte::E_GX2SURFFMT format, uint32 compSel)\n{\n\tswitch (format)\n\t{\n\tcase Latte::E_GX2SURFFMT::R8_UNORM: // R8 is replicated on all channels (while OpenGL would return 1.0 for BGA instead)\n\tcase Latte::E_GX2SURFFMT::R8_SNORM: // probably the same as _UNORM, but needs testing\n\t\tif (compSel >= 1 && compSel <= 3)\n\t\t\tcompSel = 0;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM: // order of components is reversed (RGBA -> ABGR)\n\t\tif (compSel >= 0 && compSel <= 3)\n\t\t\tcompSel = 3 - compSel;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::BC4_UNORM:\n\tcase Latte::E_GX2SURFFMT::BC4_SNORM:\n\t\tif (compSel >= 1 && compSel <= 3)\n\t\t\tcompSel = 0;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::BC5_UNORM:\n\tcase Latte::E_GX2SURFFMT::BC5_SNORM:\n\t\t// RG maps to RG\n\t\t// B maps to ?\n\t\t// A maps to G (guessed)\n\t\tif (compSel == 3)\n\t\t\tcompSel = 1; // read Alpha as Green\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::A2_B10_G10_R10_UNORM:\n\t\t// reverse components (Wii U: ABGR, OpenGL: RGBA)\n\t\t// used in Resident Evil Revelations\n\t\tif (compSel >= 0 && compSel <= 3)\n\t\t\tcompSel = 3 - compSel;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::X24_G8_UINT:\n\t\t// map everything to alpha?\n\t\tif (compSel >= 0 && compSel <= 3)\n\t\t\tcompSel = 3;\n\t\tbreak;\n\tcase Latte::E_GX2SURFFMT::R4_G4_UNORM:\n\t\t// red and green swapped\n\t\tif (compSel == 0)\n\t\t\tcompSel = 1;\n\t\telse if (compSel == 1)\n\t\t\tcompSel = 0;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\treturn compSel;\n}\n\nLatteTextureViewVk::LatteTextureViewVk(VkDevice device, LatteTextureVk* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)\n\t: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_device(device)\n{\n\tif(texture->overwriteInfo.hasFormatOverwrite)\n\t{\n\t\tcemu_assert_debug(format == texture->format); // if format overwrite is used, the texture is no longer taking part in aliasing and the format of any view has to match\n\t\tm_format = texture->GetFormat();\n\t}\n\telse if (dim != texture->dim || format != texture->format)\n\t{\n\t\tVulkanRenderer::FormatInfoVK texFormatInfo;\n\t\tVulkanRenderer::GetInstance()->GetTextureFormatInfoVK(format, texture->isDepth, dim, 0, 0, &texFormatInfo);\n\t\tm_format = texFormatInfo.vkImageFormat;\n\t}\n\telse\n\t\tm_format = texture->GetFormat();\n\tm_uniqueId = VulkanRenderer::GetInstance()->GenUniqueId();\n}\n\nLatteTextureViewVk::~LatteTextureViewVk()\n{\n\twhile (!list_descriptorSets.empty())\n\t\tdelete list_descriptorSets[0];\n\n\tif (m_smallCacheView0)\n\t\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(m_smallCacheView0);\n\tif (m_smallCacheView1)\n\t\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(m_smallCacheView1);\n\n\tif (m_fallbackCache)\n\t{\n\t\tfor (auto& itr : *m_fallbackCache)\n\t\t\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(itr.second);\n\t\tdelete m_fallbackCache;\n\t\tm_fallbackCache = nullptr;\n\t}\n}\n\nVKRObjectTextureView* LatteTextureViewVk::CreateView(uint32 gpuSamplerSwizzle)\n{\n\tuint32 compSelR = (gpuSamplerSwizzle >> 16) & 0x7;\n\tuint32 compSelG = (gpuSamplerSwizzle >> 19) & 0x7;\n\tuint32 compSelB = (gpuSamplerSwizzle >> 22) & 0x7;\n\tuint32 compSelA = (gpuSamplerSwizzle >> 25) & 0x7;\n\tcompSelR = LatteTextureVk_AdjustTextureCompSel(format, compSelR);\n\tcompSelG = LatteTextureVk_AdjustTextureCompSel(format, compSelG);\n\tcompSelB = LatteTextureVk_AdjustTextureCompSel(format, compSelB);\n\tcompSelA = LatteTextureVk_AdjustTextureCompSel(format, compSelA);\n\n\tVkImageViewCreateInfo viewInfo{};\n\tviewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n\tviewInfo.image = GetBaseImage()->GetImageObj()->m_image;\n\tviewInfo.viewType = GetImageViewTypeFromGX2Dim(dim);\n\tviewInfo.format = m_format;\n\tviewInfo.subresourceRange.aspectMask = GetBaseImage()->GetImageAspect();\n\tif (viewInfo.subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)\n\t\tviewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; // make sure stencil is never set, we only support sampling depth for now\n\tviewInfo.subresourceRange.baseMipLevel = firstMip;\n\tviewInfo.subresourceRange.levelCount = this->numMip;\n\tif (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_3D && baseTexture->Is3DTexture())\n\t{\n\t\tcemu_assert_debug(firstMip == 0);\n\t\tcemu_assert_debug(this->numSlice == baseTexture->depth);\n\t\tviewInfo.subresourceRange.baseArrayLayer = 0;\n\t\tviewInfo.subresourceRange.layerCount = 1;\n\t}\n\telse\n\t{\n\t\tviewInfo.subresourceRange.baseArrayLayer = firstSlice;\n\t\tviewInfo.subresourceRange.layerCount = this->numSlice;\n\t}\n\n\tstatic const VkComponentSwizzle swizzle[] =\n\t{\n\t\tVK_COMPONENT_SWIZZLE_R,\n\t\tVK_COMPONENT_SWIZZLE_G,\n\t\tVK_COMPONENT_SWIZZLE_B,\n\t\tVK_COMPONENT_SWIZZLE_A,\n\t\tVK_COMPONENT_SWIZZLE_ZERO,\n\t\tVK_COMPONENT_SWIZZLE_ONE,\n\t\tVK_COMPONENT_SWIZZLE_ZERO,\n\t\tVK_COMPONENT_SWIZZLE_ZERO\n\t};\n\n\tviewInfo.components.r = swizzle[compSelR];\n\tviewInfo.components.g = swizzle[compSelG];\n\tviewInfo.components.b = swizzle[compSelB];\n\tviewInfo.components.a = swizzle[compSelA];\n\n\tVkImageView view;\n\tif (vkCreateImageView(m_device, &viewInfo, nullptr, &view) != VK_SUCCESS)\n\t\tthrow std::runtime_error(\"failed to create texture image view!\");\n\n\treturn new VKRObjectTextureView(GetBaseImage()->GetImageObj(), view);\n}\n\nVKRObjectTextureView* LatteTextureViewVk::GetViewRGBA()\n{ \n\treturn GetSamplerView(0x06880000); // RGBA swizzle\n}\n\nVKRObjectTextureView* LatteTextureViewVk::GetSamplerView(uint32 gpuSamplerSwizzle)\n{\n\tgpuSamplerSwizzle &= 0x0FFF0000;\n\t// look up view in cache\n\t// intentionally using unrolled code here instead of a loop for a small performance gain\n\tif (m_smallCacheSwizzle0 == gpuSamplerSwizzle)\n\t\treturn m_smallCacheView0;\n\tif (m_smallCacheSwizzle1 == gpuSamplerSwizzle)\n\t\treturn m_smallCacheView1;\n\tauto fallbackCache = m_fallbackCache;\n\tif (m_fallbackCache)\n\t{\n\t\tconst auto it = fallbackCache->find(gpuSamplerSwizzle);\n\t\tif (it != fallbackCache->cend())\n\t\t\treturn it->second;\n\t}\n\t// not cached, create new view and store in cache\n\tauto viewObj = CreateView(gpuSamplerSwizzle);\n\tif (m_smallCacheSwizzle0 == CACHE_EMPTY_ENTRY)\n\t{\n\t\tm_smallCacheSwizzle0 = gpuSamplerSwizzle;\n\t\tm_smallCacheView0 = viewObj;\n\t}\n\telse if (m_smallCacheSwizzle1 == CACHE_EMPTY_ENTRY)\n\t{\n\t\tm_smallCacheSwizzle1 = gpuSamplerSwizzle;\n\t\tm_smallCacheView1 = viewObj;\n\t}\n\telse\n\t{\n\t\tif (!m_fallbackCache)\n\t\t\tm_fallbackCache = new std::unordered_map<uint32, VKRObjectTextureView*>();\n\t\tm_fallbackCache->insert_or_assign(gpuSamplerSwizzle, viewObj);\n\t}\n\treturn viewObj;\n}\n\nVkSampler LatteTextureViewVk::GetDefaultTextureSampler(bool useLinearTexFilter)\n{\n\tVkSampler& sampler = GetViewRGBA()->m_textureDefaultSampler[useLinearTexFilter ? 1 : 0];\n\n\tif (sampler != VK_NULL_HANDLE)\n\t\treturn sampler;\n\n\tVkSamplerCreateInfo samplerInfo{};\n\tsamplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n\n\t// emulate OpenGL minFilters\n\t// see note under: https://docs.vulkan.org/spec/latest/chapters/samplers.html#VkSamplerCreateInfo\n\t// if maxLod = 0 then magnification is always performed\n\tsamplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;\n\tsamplerInfo.minLod = 0.0f;\n\tsamplerInfo.maxLod = 0.25f;\n\n\tif (useLinearTexFilter)\n\t{\n\t\tsamplerInfo.magFilter = VK_FILTER_LINEAR;\n\t\tsamplerInfo.minFilter = VK_FILTER_LINEAR;\n\t}\n\telse\n\t{\n\t\tsamplerInfo.magFilter = VK_FILTER_NEAREST;\n\t\tsamplerInfo.minFilter = VK_FILTER_NEAREST;\n\t}\n\tsamplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;\n\tsamplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;\n\tsamplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;\n\n\tif (vkCreateSampler(m_device, &samplerInfo, nullptr, &sampler) != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to create default sampler\");\n\t\tthrow std::runtime_error(\"failed to create texture sampler!\");\n\t}\n\n\treturn sampler;\n}\n\nVkImageViewType LatteTextureViewVk::GetImageViewTypeFromGX2Dim(Latte::E_DIM dim)\n{\n\tswitch (dim)\n\t{\n\tcase Latte::E_DIM::DIM_1D:\n\t\treturn VK_IMAGE_VIEW_TYPE_1D;\n\tcase Latte::E_DIM::DIM_2D:\n\tcase Latte::E_DIM::DIM_2D_MSAA:\n\t\treturn VK_IMAGE_VIEW_TYPE_2D;\n\tcase Latte::E_DIM::DIM_2D_ARRAY:\n\t\treturn VK_IMAGE_VIEW_TYPE_2D_ARRAY;\n\tcase Latte::E_DIM::DIM_3D:\n\t\treturn VK_IMAGE_VIEW_TYPE_3D;\n\tcase Latte::E_DIM::DIM_CUBEMAP:\n\t\treturn VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;\n\tdefault:\n\t\tcemu_assert_unimplemented();\n\t}\n\treturn VK_IMAGE_VIEW_TYPE_2D;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h\"\n\nclass LatteTextureViewVk : public LatteTextureView\n{\npublic:\n\tLatteTextureViewVk(VkDevice device, class LatteTextureVk* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount);\n\t~LatteTextureViewVk();\n\n\tuint64 GetUniqueId() const { return m_uniqueId; };\n\tVKRObjectTextureView* GetViewRGBA();\n\tVKRObjectTextureView* GetSamplerView(uint32 gpuSamplerSwizzle);\n\tVkSampler GetDefaultTextureSampler(bool useLinearTexFilter);\n\tVkFormat GetFormat() const { return m_format; }\n\n\tLatteTextureVk* GetBaseImage() const { return (LatteTextureVk*)baseTexture; }\n\t\n\tvoid AddDescriptorSetReference(struct VkDescriptorSetInfo* dsInfo) { if (std::find(list_descriptorSets.begin(), list_descriptorSets.end(), dsInfo) == list_descriptorSets.end()) list_descriptorSets.emplace_back(dsInfo); };\n\tvoid RemoveDescriptorSetReference(struct VkDescriptorSetInfo* dsInfo) { list_descriptorSets.erase(std::remove(list_descriptorSets.begin(), list_descriptorSets.end(), dsInfo), list_descriptorSets.end()); };\n\nprivate:\n\tVkImageViewType GetImageViewTypeFromGX2Dim(Latte::E_DIM dim);\n\tVKRObjectTextureView* CreateView(uint32 gpuSamplerSwizzle);\n\n\t// each texture view holds one Vulkan image view per swizzle mask. Image views are only instantiated when requested via GetViewRGBA/GetSamplerView\n\t// since a large majority of texture views will only have 1 or 2 instantiated image views, we use a small fixed-size cache\n\t// and only allocate the larger map (m_fallbackCache) if necessary\n\tinline static const uint32 CACHE_EMPTY_ENTRY = 0xFFFFFFFF;\n\n\tuint32 m_smallCacheSwizzle0 = { CACHE_EMPTY_ENTRY };\n\tuint32 m_smallCacheSwizzle1 = { CACHE_EMPTY_ENTRY };\n\tVKRObjectTextureView* m_smallCacheView0 = {};\n\tVKRObjectTextureView* m_smallCacheView1 = {};\n\tstd::unordered_map<uint32, VKRObjectTextureView*>* m_fallbackCache{};\n\t\n\tVkDevice m_device;\n\tVkFormat m_format;\n\tstd::vector<struct VkDescriptorSetInfo*> list_descriptorSets; // list of descriptors sets referencing this view\n\n\tuint64 m_uniqueId;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n\nLatteTextureVk::LatteTextureVk(class VulkanRenderer* vkRenderer, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle,\n\tLatte::E_HWTILEMODE tileMode, bool isDepth)\n\t: LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth), m_vkr(vkRenderer)\n{\n\tvkObjTex = new VKRObjectTexture();\n\n\tVkImageCreateInfo imageInfo{};\n\timageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n\t\n\tsint32 effectiveBaseWidth = width;\n\tsint32 effectiveBaseHeight = height;\n\tsint32 effectiveBaseDepth = depth;\n\tif (overwriteInfo.hasResolutionOverwrite)\n\t{\n\t\teffectiveBaseWidth = overwriteInfo.width;\n\t\teffectiveBaseHeight = overwriteInfo.height;\n\t\teffectiveBaseDepth = overwriteInfo.depth;\n\t}\n\teffectiveBaseDepth = std::max(1, effectiveBaseDepth);\n\n\timageInfo.extent.width = effectiveBaseWidth;\n\timageInfo.extent.height = effectiveBaseHeight;\n\timageInfo.mipLevels = mipLevels;\n\timageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;\n\timageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\timageInfo.samples = VK_SAMPLE_COUNT_1_BIT;\n\n\tif (dim == Latte::E_DIM::DIM_3D)\n\t{\n\t\timageInfo.extent.depth = effectiveBaseDepth;\n\t\timageInfo.arrayLayers = 1;\n\t\timageInfo.flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;\n\t}\n\telse\n\t{\n\t\timageInfo.extent.depth = 1;\n\t\timageInfo.arrayLayers = effectiveBaseDepth;\n\t\tif (dim != Latte::E_DIM::DIM_1D && (effectiveBaseDepth % 6) == 0 && effectiveBaseWidth == effectiveBaseHeight)\n\t\t\timageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;\n\t}\n\t\n\tVulkanRenderer::FormatInfoVK texFormatInfo;\n\tvkRenderer->GetTextureFormatInfoVK(format, isDepth, dim, effectiveBaseWidth, effectiveBaseHeight, &texFormatInfo);\n\tcemu_assert_debug(hasStencil == ((texFormatInfo.vkImageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0));\n\timageInfo.format = texFormatInfo.vkImageFormat;\n\tvkObjTex->m_imageAspect = texFormatInfo.vkImageAspect;\n\t\n\tif (isDepth == false && texFormatInfo.isCompressed)\n\t{\n\t\timageInfo.flags |= VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;\n\t}\n\tif (isDepth == false)\n\t\timageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;\n\n\tif (isDepth)\n\t{\n\t\timageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;\n\t}\n\telse\n\t{\n\t\tif(Latte::IsCompressedFormat(format) == false && texFormatInfo.vkImageFormat != VK_FORMAT_R4G4_UNORM_PACK8) // Vulkan's R4G4 cant be used as a color attachment\n\t\t\timageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;\n\t}\n\n\tif (dim == Latte::E_DIM::DIM_2D)\n\t\timageInfo.imageType = VK_IMAGE_TYPE_2D;\n\telse if (dim == Latte::E_DIM::DIM_1D)\n\t\timageInfo.imageType = VK_IMAGE_TYPE_1D;\n\telse if (dim == Latte::E_DIM::DIM_3D)\n\t\timageInfo.imageType = VK_IMAGE_TYPE_3D;\n\telse if (dim == Latte::E_DIM::DIM_2D_ARRAY)\n\t\timageInfo.imageType = VK_IMAGE_TYPE_2D;\n\telse if (dim == Latte::E_DIM::DIM_CUBEMAP)\n\t\timageInfo.imageType = VK_IMAGE_TYPE_2D;\n\telse if (dim == Latte::E_DIM::DIM_2D_MSAA)\n\t\timageInfo.imageType = VK_IMAGE_TYPE_2D;\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tif (vkCreateImage(m_vkr->GetLogicalDevice(), &imageInfo, nullptr, &vkObjTex->m_image) != VK_SUCCESS)\n\t\tm_vkr->UnrecoverableError(\"Failed to create texture image\");\n\t\n\tif (m_vkr->IsDebugMarkersEnabled())\n\t{\n\t\tVkDebugUtilsObjectNameInfoEXT objName{};\n\t\tobjName.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;\n\t\tobjName.objectType = VK_OBJECT_TYPE_IMAGE;\n\t\tobjName.pNext = nullptr;\n\t\tobjName.objectHandle = (uint64_t)vkObjTex->m_image;\n\t\tauto objNameStr = fmt::format(\"tex_{:08x}_fmt{:04x}\", physAddress, (uint32)format);\n\t\tobjName.pObjectName = objNameStr.c_str();\n\t\tvkSetDebugUtilsObjectNameEXT(m_vkr->GetLogicalDevice(), &objName);\n\t}\n\n\tvkObjTex->m_flags = imageInfo.flags;\n\tvkObjTex->m_format = imageInfo.format;\n\n\t// init layout array\n\tm_layoutsMips = std::max(mipLevels, 1u); // todo - use effective mip count\n\tm_layoutsDepth = std::max(depth, 1u);\n\tif (Is3DTexture())\n\t\tm_layouts.resize(m_layoutsMips, VK_IMAGE_LAYOUT_UNDEFINED); // one per mip\n\telse\n\t\tm_layouts.resize(m_layoutsMips * m_layoutsDepth, VK_IMAGE_LAYOUT_UNDEFINED); // one per layer per mip\n}\n\nLatteTextureVk::~LatteTextureVk()\n{\n\tcemu_assert_debug(views.empty());\n\n\tm_vkr->surfaceCopy_notifyTextureRelease(this);\n\n\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(vkObjTex);\n\tvkObjTex = nullptr;\n}\n\nLatteTextureView* LatteTextureVk::CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)\n{\n\tcemu_assert_debug(mipCount > 0);\n\tcemu_assert_debug(sliceCount > 0);\n\tcemu_assert_debug((firstMip + mipCount) <= this->mipLevels);\n\tcemu_assert_debug((firstSlice + sliceCount) <= this->depth);\n\treturn new LatteTextureViewVk(m_vkr->GetLogicalDevice(), this, dim, format, firstMip, mipCount, firstSlice, sliceCount);\n}\n\nvoid LatteTextureVk::AllocateOnHost()\n{\n\tauto allocationInfo = VulkanRenderer::GetInstance()->GetMemoryManager()->imageMemoryAllocate(GetImageObj()->m_image);\n\tvkObjTex->m_allocation = allocationInfo;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"util/ChunkedHeap/ChunkedHeap.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h\"\n\nclass LatteTextureVk : public LatteTexture\n{\npublic:\n\tLatteTextureVk(class VulkanRenderer* vkRenderer, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels,\n\t\tuint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth);\n\n\t~LatteTextureVk();\n\n\tvoid AllocateOnHost() override;\n\n\tVKRObjectTexture* GetImageObj() const { return vkObjTex; };\n\t\n\tVkFormat GetFormat() const { return vkObjTex->m_format; }\n\tVkImageAspectFlags GetImageAspect() const { return vkObjTex->m_imageAspect; }\n\n\tVkImageLayout GetImageLayout(VkImageSubresource& subresource)\n\t{\n\t\tcemu_assert_debug(subresource.mipLevel < m_layoutsMips);\n\t\tcemu_assert_debug(subresource.arrayLayer < m_layoutsDepth);\n\t\tif (Is3DTexture())\n\t\t\treturn m_layouts[subresource.mipLevel];\n\t\treturn m_layouts[subresource.mipLevel * m_layoutsDepth + subresource.arrayLayer];\n\t}\n\n\tVkImageLayout GetImageLayout(VkImageSubresourceRange& subresource)\n\t{\n\t\tcemu_assert_debug(subresource.baseMipLevel < m_layoutsMips);\n\t\tcemu_assert_debug(subresource.baseArrayLayer < m_layoutsDepth);\n\t\tcemu_assert_debug(subresource.levelCount == 1);\n\t\tif (Is3DTexture())\n\t\t\treturn m_layouts[subresource.baseMipLevel];\n\t\tcemu_assert_debug(subresource.layerCount > 0);\n\t\tif (subresource.layerCount > 1)\n\t\t{\n\t\t\tVkImageLayout imgLayout = m_layouts[subresource.baseMipLevel * m_layoutsDepth + subresource.baseArrayLayer];\n\t\t\tfor (uint32 i = 1; i < subresource.layerCount; i++)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(m_layouts[subresource.baseMipLevel * m_layoutsDepth + subresource.baseArrayLayer + i] == imgLayout);\n\t\t\t}\n\t\t\treturn imgLayout;\n\t\t}\n\t\treturn m_layouts[subresource.baseMipLevel * m_layoutsDepth + subresource.baseArrayLayer];\n\t}\n\n\tvoid SetImageLayout(VkImageSubresource& subresource, VkImageLayout newLayout)\n\t{\n\t\tcemu_assert_debug(subresource.mipLevel < m_layoutsMips);\n\t\tcemu_assert_debug(subresource.arrayLayer < m_layoutsDepth);\n\t\tif (Is3DTexture())\n\t\t\tm_layouts[subresource.mipLevel] = newLayout;\n\t\telse\n\t\t\tm_layouts[subresource.mipLevel * m_layoutsDepth + subresource.arrayLayer] = newLayout;\n\t}\n\n\tvoid SetImageLayout(VkImageSubresourceRange& subresource, VkImageLayout newLayout)\n\t{\n\t\tcemu_assert_debug(subresource.baseMipLevel < m_layoutsMips);\n\t\tcemu_assert_debug(subresource.baseArrayLayer < m_layoutsDepth);\n\t\tcemu_assert_debug(subresource.levelCount == 1);\n\t\tif (Is3DTexture())\n\t\t\tm_layouts[subresource.baseMipLevel] = newLayout;\n\t\telse\n\t\t{\n\t\t\tfor(uint32 i=0; i<subresource.layerCount; i++)\n\t\t\t\tm_layouts[subresource.baseMipLevel * m_layoutsDepth + subresource.baseArrayLayer + i] = newLayout;\n\t\t}\n\t}\n\nprotected:\n\tLatteTextureView* CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount) override;\n\npublic:\n\tuint64 m_vkFlushIndex{}; // used to track read-write dependencies within the same renderpass\n\n\tuint64 m_vkFlushIndex_read{};\n\tuint64 m_vkFlushIndex_write{};\n\n\tuint32 m_collisionCheckIndex{}; // used to track if texture is being both sampled and output to during drawcall\n\nprivate:\n\tclass VulkanRenderer* m_vkr;\n\n\tVKRObjectTexture* vkObjTex{};\n\tstd::vector<VkImageLayout> m_layouts;\n\tuint32 m_layoutsMips;\n\tuint32 m_layoutsDepth;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/CemuConfig.h\"\n#include \"util/helpers/ConcurrentQueue.h\"\n#include \"Cemu/FileCache/FileCache.h\"\n\n#include <glslang/Public/ShaderLang.h>\n#include <glslang/SPIRV/GlslangToSpv.h>\n#include \"util/helpers/helpers.h\"\n\nbool s_isLoadingShadersVk{ false };\nclass FileCache* s_spirvCache{nullptr};\n\nextern std::atomic_int g_compiled_shaders_total;\nextern std::atomic_int g_compiled_shaders_async;\n\nconsteval TBuiltInResource GetDefaultBuiltInResource()\n{\n\tTBuiltInResource defaultResource = {};\n\tdefaultResource.maxLights = 32;\n\tdefaultResource.maxClipPlanes = 6;\n\tdefaultResource.maxTextureUnits = 32;\n\tdefaultResource.maxTextureCoords = 32;\n\tdefaultResource.maxVertexAttribs = 64;\n\tdefaultResource.maxVertexUniformComponents = 4096;\n\tdefaultResource.maxVaryingFloats = 64;\n\tdefaultResource.maxVertexTextureImageUnits = 32;\n\tdefaultResource.maxCombinedTextureImageUnits = 80;\n\tdefaultResource.maxTextureImageUnits = 32;\n\tdefaultResource.maxFragmentUniformComponents = 4096;\n\tdefaultResource.maxDrawBuffers = 32;\n\tdefaultResource.maxVertexUniformVectors = 128;\n\tdefaultResource.maxVaryingVectors = 8;\n\tdefaultResource.maxFragmentUniformVectors = 16;\n\tdefaultResource.maxVertexOutputVectors = 16;\n\tdefaultResource.maxFragmentInputVectors = 15;\n\tdefaultResource.minProgramTexelOffset = -8;\n\tdefaultResource.maxProgramTexelOffset = 7;\n\tdefaultResource.maxClipDistances = 8;\n\tdefaultResource.maxComputeWorkGroupCountX = 65535;\n\tdefaultResource.maxComputeWorkGroupCountY = 65535;\n\tdefaultResource.maxComputeWorkGroupCountZ = 65535;\n\tdefaultResource.maxComputeWorkGroupSizeX = 1024;\n\tdefaultResource.maxComputeWorkGroupSizeY = 1024;\n\tdefaultResource.maxComputeWorkGroupSizeZ = 64;\n\tdefaultResource.maxComputeUniformComponents = 1024;\n\tdefaultResource.maxComputeTextureImageUnits = 16;\n\tdefaultResource.maxComputeImageUniforms = 8;\n\tdefaultResource.maxComputeAtomicCounters = 8;\n\tdefaultResource.maxComputeAtomicCounterBuffers = 1;\n\tdefaultResource.maxVaryingComponents = 60;\n\tdefaultResource.maxVertexOutputComponents = 64;\n\tdefaultResource.maxGeometryInputComponents = 64;\n\tdefaultResource.maxGeometryOutputComponents = 128;\n\tdefaultResource.maxFragmentInputComponents = 128;\n\tdefaultResource.maxImageUnits = 8;\n\tdefaultResource.maxCombinedImageUnitsAndFragmentOutputs = 8;\n\tdefaultResource.maxCombinedShaderOutputResources = 8;\n\tdefaultResource.maxImageSamples = 0;\n\tdefaultResource.maxVertexImageUniforms = 0;\n\tdefaultResource.maxTessControlImageUniforms = 0;\n\tdefaultResource.maxTessEvaluationImageUniforms = 0;\n\tdefaultResource.maxGeometryImageUniforms = 0;\n\tdefaultResource.maxFragmentImageUniforms = 8;\n\tdefaultResource.maxCombinedImageUniforms = 8;\n\tdefaultResource.maxGeometryTextureImageUnits = 16;\n\tdefaultResource.maxGeometryOutputVertices = 256;\n\tdefaultResource.maxGeometryTotalOutputComponents = 1024;\n\tdefaultResource.maxGeometryUniformComponents = 1024;\n\tdefaultResource.maxGeometryVaryingComponents = 64;\n\tdefaultResource.maxTessControlInputComponents = 128;\n\tdefaultResource.maxTessControlOutputComponents = 128;\n\tdefaultResource.maxTessControlTextureImageUnits = 16;\n\tdefaultResource.maxTessControlUniformComponents = 1024;\n\tdefaultResource.maxTessControlTotalOutputComponents = 4096;\n\tdefaultResource.maxTessEvaluationInputComponents = 128;\n\tdefaultResource.maxTessEvaluationOutputComponents = 128;\n\tdefaultResource.maxTessEvaluationTextureImageUnits = 16;\n\tdefaultResource.maxTessEvaluationUniformComponents = 1024;\n\tdefaultResource.maxTessPatchComponents = 120;\n\tdefaultResource.maxPatchVertices = 32;\n\tdefaultResource.maxTessGenLevel = 64;\n\tdefaultResource.maxViewports = 16;\n\tdefaultResource.maxVertexAtomicCounters = 0;\n\tdefaultResource.maxTessControlAtomicCounters = 0;\n\tdefaultResource.maxTessEvaluationAtomicCounters = 0;\n\tdefaultResource.maxGeometryAtomicCounters = 0;\n\tdefaultResource.maxFragmentAtomicCounters = 8;\n\tdefaultResource.maxCombinedAtomicCounters = 8;\n\tdefaultResource.maxAtomicCounterBindings = 1;\n\tdefaultResource.maxVertexAtomicCounterBuffers = 0;\n\tdefaultResource.maxTessControlAtomicCounterBuffers = 0;\n\tdefaultResource.maxTessEvaluationAtomicCounterBuffers = 0;\n\tdefaultResource.maxGeometryAtomicCounterBuffers = 0;\n\tdefaultResource.maxFragmentAtomicCounterBuffers = 1;\n\tdefaultResource.maxCombinedAtomicCounterBuffers = 1;\n\tdefaultResource.maxAtomicCounterBufferSize = 16384;\n\tdefaultResource.maxTransformFeedbackBuffers = 4;\n\tdefaultResource.maxTransformFeedbackInterleavedComponents = 64;\n\tdefaultResource.maxCullDistances = 8;\n\tdefaultResource.maxCombinedClipAndCullDistances = 8;\n\tdefaultResource.maxSamples = 4;\n\tdefaultResource.maxMeshOutputVerticesNV = 256;\n\tdefaultResource.maxMeshOutputPrimitivesNV = 512;\n\tdefaultResource.maxMeshWorkGroupSizeX_NV = 32;\n\tdefaultResource.maxMeshWorkGroupSizeY_NV = 1;\n\tdefaultResource.maxMeshWorkGroupSizeZ_NV = 1;\n\tdefaultResource.maxTaskWorkGroupSizeX_NV = 32;\n\tdefaultResource.maxTaskWorkGroupSizeY_NV = 1;\n\tdefaultResource.maxTaskWorkGroupSizeZ_NV = 1;\n\tdefaultResource.maxMeshViewCountNV = 4;\n\n\tdefaultResource.limits = {};\n\tdefaultResource.limits.nonInductiveForLoops = true;\n\tdefaultResource.limits.whileLoops = true;\n\tdefaultResource.limits.doWhileLoops = true;\n\tdefaultResource.limits.generalUniformIndexing = true;\n\tdefaultResource.limits.generalAttributeMatrixVectorIndexing = true;\n\tdefaultResource.limits.generalVaryingIndexing = true;\n\tdefaultResource.limits.generalSamplerIndexing = true;\n\tdefaultResource.limits.generalVariableIndexing = true;\n\tdefaultResource.limits.generalConstantMatrixVectorIndexing = true;\n\treturn defaultResource;\n};\n\nclass _ShaderVkThreadPool\n{\npublic:\n\tvoid StartThreads()\n\t{\n\t\tif (m_threadsActive.exchange(true))\n\t\t\treturn;\n\t\t// create thread pool\n\t\tconst uint32 threadCount = 2;\n\t\tfor (uint32 i = 0; i < threadCount; ++i)\n\t\t\ts_threads.emplace_back(&_ShaderVkThreadPool::CompilerThreadFunc, this);\n\t}\n\n\tvoid StopThreads()\n\t{\n\t\tif (!m_threadsActive.exchange(false))\n\t\t\treturn;\n\t\tfor (uint32 i = 0; i < s_threads.size(); ++i)\n\t\t\ts_compilationQueueCount.increment();\n\t\tfor (auto& it : s_threads)\n\t\t\tit.join();\n\t\ts_threads.clear();\n\t}\n\n\t~_ShaderVkThreadPool()\n\t{\n\t\tStopThreads();\n\t}\n\n\tvoid CompilerThreadFunc()\n\t{\n\t\tSetThreadName(\"vkShaderComp\");\n\t\twhile (m_threadsActive.load(std::memory_order::relaxed))\n\t\t{\n\t\t\ts_compilationQueueCount.decrementWithWait();\n\t\t\ts_compilationQueueMutex.lock();\n\t\t\tif (s_compilationQueue.empty())\n\t\t\t{\n\t\t\t\t// queue empty again, shaders compiled synchronously via PreponeCompilation()\n\t\t\t\ts_compilationQueueMutex.unlock();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tRendererShaderVk* job = s_compilationQueue.front();\n\t\t\ts_compilationQueue.pop_front();\n\t\t\t// set compilation state\n\t\t\tcemu_assert_debug(job->m_compilationState.getValue() == RendererShaderVk::COMPILATION_STATE::QUEUED);\n\t\t\tjob->m_compilationState.setValue(RendererShaderVk::COMPILATION_STATE::COMPILING);\n\t\t\ts_compilationQueueMutex.unlock();\n\t\t\t// compile\n\t\t\tjob->CompileInternal(false);\n\t\t\t++g_compiled_shaders_async;\n\t\t\t// mark as compiled\n\t\t\tcemu_assert_debug(job->m_compilationState.getValue() == RendererShaderVk::COMPILATION_STATE::COMPILING);\n\t\t\tjob->m_compilationState.setValue(RendererShaderVk::COMPILATION_STATE::DONE);\n\t\t}\n\t}\n\n\tbool HasThreadsRunning() const { return m_threadsActive; }\n\npublic:\n\tstd::vector<std::thread> s_threads;\n\n\tstd::deque<RendererShaderVk*> s_compilationQueue;\n\tCounterSemaphore s_compilationQueueCount;\n\tstd::mutex s_compilationQueueMutex;\n\nprivate:\n\tstd::atomic<bool> m_threadsActive;\n}ShaderVkThreadPool;\n\nRendererShaderVk::RendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslCode)\n\t: RendererShader(type, baseHash, auxHash, isGameShader, isGfxPackShader), m_glslCode(glslCode)\n{\n\t// start async compilation\n\tShaderVkThreadPool.s_compilationQueueMutex.lock();\n\tm_compilationState.setValue(COMPILATION_STATE::QUEUED);\n\tShaderVkThreadPool.s_compilationQueue.push_back(this);\n\tShaderVkThreadPool.s_compilationQueueCount.increment();\n\tShaderVkThreadPool.s_compilationQueueMutex.unlock();\n\tcemu_assert_debug(ShaderVkThreadPool.HasThreadsRunning()); // make sure .StartThreads() was called\n}\n\nRendererShaderVk::~RendererShaderVk()\n{\n\twhile (!list_pipelineInfo.empty())\n\t\tdelete list_pipelineInfo[0];\n\n\tVkDevice vkDev = VulkanRenderer::GetInstance()->GetLogicalDevice();\n\tvkDestroyShaderModule(vkDev, m_shader_module, nullptr);\n}\n\nvoid RendererShaderVk::Init()\n{\n\tShaderVkThreadPool.StartThreads();\n}\n\nvoid RendererShaderVk::Shutdown()\n{\n\tShaderVkThreadPool.StopThreads();\n}\n\nvoid RendererShaderVk::CreateVkShaderModule(std::span<uint32> spirvBuffer)\n{\n\tVkShaderModuleCreateInfo createInfo{};\n\tcreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n\tcreateInfo.codeSize = spirvBuffer.size_bytes();\n\tcreateInfo.pCode = spirvBuffer.data();\n\n\tVulkanRenderer* vkr = (VulkanRenderer*)g_renderer.get();\n\n\tVkDevice m_device = vkr->GetLogicalDevice();\n\n\tVkResult result = vkCreateShaderModule(m_device, &createInfo, nullptr, &m_shader_module);\n\tif (result != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Vulkan: Shader error\");\n\t\tthrow std::runtime_error(fmt::format(\"Failed to create shader module: {}\", result));\n\t}\n\n\t// set debug name\n\tif (vkr->IsDebugMarkersEnabled())\n\t{\n\t\tVkDebugUtilsObjectNameInfoEXT objName{};\n\t\tobjName.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;\n\t\tobjName.objectType = VK_OBJECT_TYPE_SHADER_MODULE;\n\t\tobjName.pNext = nullptr;\n\t\tobjName.objectHandle = (uint64_t)m_shader_module;\n\t\tauto objNameStr = fmt::format(\"shader_{:016x}_{:016x}\", m_baseHash, m_auxHash);\n\t\tobjName.pObjectName = objNameStr.c_str();\n\t\tvkSetDebugUtilsObjectNameEXT(vkr->GetLogicalDevice(), &objName);\n\t}\n}\n\nvoid RendererShaderVk::FinishCompilation()\n{\n\tm_glslCode.clear();\n\tm_glslCode.shrink_to_fit();\n}\n\nvoid RendererShaderVk::CompileInternal(bool isRenderThread)\n{\n\tconst bool compileWithDebugInfo = ((VulkanRenderer*)g_renderer.get())->IsTracingToolEnabled();\n\n\t// try to retrieve SPIR-V module from cache\n\tif (s_isLoadingShadersVk && (m_isGameShader && !m_isGfxPackShader) && s_spirvCache && !compileWithDebugInfo)\n\t{\n\t\tcemu_assert_debug(m_baseHash != 0);\n\t\tuint64 h1, h2;\n\t\tGenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);\n\t\tstd::vector<uint8> cacheFileData;\n\t\tif (s_spirvCache->GetFile({ h1, h2 }, cacheFileData))\n\t\t{\n\t\t\t// generate shader from cached SPIR-V buffer\n\t\t\tCreateVkShaderModule(std::span<uint32>((uint32*)cacheFileData.data(), cacheFileData.size() / sizeof(uint32)));\n\t\t\tFinishCompilation();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tEShLanguage state;\n\tswitch (GetType())\n\t{\n\tcase ShaderType::kVertex:\n\t\tstate = EShLangVertex;\n\t\tbreak;\n\tcase ShaderType::kFragment:\n\t\tstate = EShLangFragment;\n\t\tbreak;\n\tcase ShaderType::kGeometry:\n\t\tstate = EShLangGeometry;\n\t\tbreak;\n\tdefault:\n\t\tcemu_assert_debug(false);\n\t}\n\n\tglslang::TShader Shader(state);\n\tconst char* cstr = m_glslCode.c_str();\n\tShader.setStrings(&cstr, 1);\n\tShader.setEnvInput(glslang::EShSourceGlsl, state, glslang::EShClientVulkan, 100);\n\tShader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetClientVersion::EShTargetVulkan_1_1);\n\tShader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetLanguageVersion::EShTargetSpv_1_3);\n\n\tstd::string PreprocessedGLSL;\n\tglslang::TShader::ForbidIncluder Includer;\n\tTBuiltInResource Resources = GetDefaultBuiltInResource();\n\tEShMessages messagesPreprocess = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);\n\tif (!Shader.preprocess(&Resources, 450, ENoProfile, false, false, messagesPreprocess, &PreprocessedGLSL, Includer))\n\t{\n\t\tcemuLog_log(LogType::Force, fmt::format(\"GLSL Preprocessing Failed For {:016x}_{:016x}: \\\"{}\\\"\", m_baseHash, m_auxHash, Shader.getInfoLog()));\n\t\tFinishCompilation();\n\t\treturn;\n\t}\n\n\tconst char* PreprocessedCStr = PreprocessedGLSL.c_str();\n\tShader.setStrings(&PreprocessedCStr, 1);\n\tEShMessages messagesParseLink = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);\n\tif (!Shader.parse(&Resources, 100, false, messagesParseLink))\n\t{\n\t\tcemuLog_log(LogType::Force, fmt::format(\"GLSL parsing failed for {:016x}_{:016x}: \\\"{}\\\"\", m_baseHash, m_auxHash, Shader.getInfoLog()));\n\t\tcemuLog_logDebug(LogType::Force, \"GLSL source:\\n{}\", m_glslCode);\n\t\tcemu_assert_debug(false);\n\t\tFinishCompilation();\n\t\treturn;\n\t}\n\n\tglslang::TProgram Program;\n\tProgram.addShader(&Shader);\n\n\tif (!Program.link(messagesParseLink))\n\t{\n\t\tcemuLog_log(LogType::Force, fmt::format(\"GLSL linking failed for {:016x}_{:016x}: \\\"{}\\\"\", m_baseHash, m_auxHash, Program.getInfoLog()));\n\t\tcemu_assert_debug(false);\n\t\tFinishCompilation();\n\t\treturn;\n\t}\n\n\tif (!Program.mapIO())\n\t{\n\t\tcemuLog_log(LogType::Force, fmt::format(\"GLSL linking failed for {:016x}_{:016x}: \\\"{}\\\"\", m_baseHash, m_auxHash, Program.getInfoLog()));\n\t\tFinishCompilation();\n\t\treturn;\n\t}\n\n\t// temp storage for SPIR-V after translation\n\tstd::vector<uint32> spirvBuffer;\n\tspv::SpvBuildLogger logger;\n\n\tglslang::SpvOptions spvOptions;\n\tspvOptions.disableOptimizer = false;\n\tspvOptions.validate = false;\n\tspvOptions.optimizeSize = true;\n\tif (compileWithDebugInfo)\n\t{\n\t\tspvOptions.generateDebugInfo = true;\n\t\tspvOptions.emitNonSemanticShaderDebugInfo = true;\n\t\tspvOptions.emitNonSemanticShaderDebugSource = true;\n\n\t\tShader.addSourceText(m_glslCode.c_str(), (uint32)m_glslCode.size());\n\t\tShader.setSourceFile(fmt::format(\"shader_{:016x}_{:016x}.glsl\", m_baseHash, m_auxHash).c_str());\n\t}\n\n\t//auto beginTime = benchmarkTimer_start();\n\n\tGlslangToSpv(*Program.getIntermediate(state), spirvBuffer, &logger, &spvOptions);\n\n\t//double timeDur = benchmarkTimer_stop(beginTime);\n\t//forceLogRemoveMe_printf(\"Shader GLSL-to-SPIRV compilation took %lfms Size %08x\", timeDur, spirvBuffer.size()*4);\n\n\t// store in cache, unless it got compiled with debug info or is a modified shader from a gfx pack\n\tif (s_spirvCache && m_isGameShader && m_isGfxPackShader == false && !compileWithDebugInfo)\n\t{\n\t\tuint64 h1, h2;\n\t\tGenerateShaderPrecompiledCacheFilename(m_type, m_baseHash, m_auxHash, h1, h2);\n\t\ts_spirvCache->AddFile({ h1, h2 }, (const uint8*)spirvBuffer.data(), spirvBuffer.size() * sizeof(uint32));\n\t}\n\n\tCreateVkShaderModule(spirvBuffer);\n\n\t// count compiled shader\n\tif (!s_isLoadingShadersVk)\n\t{\n\t\tif( m_isGameShader )\n\t\t\t++g_compiled_shaders_total;\n\t}\n\n\tFinishCompilation();\n}\n\nvoid RendererShaderVk::PreponeCompilation(bool isRenderThread)\n{\n\tShaderVkThreadPool.s_compilationQueueMutex.lock();\n\tbool isStillQueued = m_compilationState.hasState(COMPILATION_STATE::QUEUED);\n\tif (isStillQueued)\n\t{\n\t\t// remove from queue\n\t\tShaderVkThreadPool.s_compilationQueue.erase(std::remove(ShaderVkThreadPool.s_compilationQueue.begin(), ShaderVkThreadPool.s_compilationQueue.end(), this), ShaderVkThreadPool.s_compilationQueue.end());\n\t\tm_compilationState.setValue(COMPILATION_STATE::COMPILING);\n\t}\n\tShaderVkThreadPool.s_compilationQueueMutex.unlock();\n\tif (!isStillQueued)\n\t{\n\t\tm_compilationState.waitUntilValue(COMPILATION_STATE::DONE);\n\t\t--g_compiled_shaders_async; // compilation caused a stall so we don't consider this one async\n\t\treturn;\n\t}\n\telse\n\t{\n\t\t// compile synchronously\n\t\tCompileInternal(isRenderThread);\n\t\tm_compilationState.setValue(COMPILATION_STATE::DONE);\n\t}\n}\n\nbool RendererShaderVk::IsCompiled()\n{\n\treturn m_compilationState.hasState(COMPILATION_STATE::DONE);\n};\n\nbool RendererShaderVk::WaitForCompiled()\n{\n\tm_compilationState.waitUntilValue(COMPILATION_STATE::DONE);\n\treturn true;\n}\n\nvoid RendererShaderVk::ShaderCacheLoading_begin(uint64 cacheTitleId)\n{\n\tif (s_spirvCache)\n\t{\n\t\tdelete s_spirvCache;\n\t\ts_spirvCache = nullptr;\n\t}\n\tuint32 spirvCacheMagic = GeneratePrecompiledCacheId();\n\tconst std::string cacheFilename = fmt::format(\"{:016x}_spirv.bin\", cacheTitleId);\n\tconst fs::path cachePath = ActiveSettings::GetCachePath(\"shaderCache/precompiled/{}\", cacheFilename);\n\ts_spirvCache = FileCache::Open(cachePath, true, spirvCacheMagic);\n\tif (s_spirvCache == nullptr)\n\t\tcemuLog_log(LogType::Force, \"Unable to open SPIR-V cache {}\", cacheFilename);\n\ts_isLoadingShadersVk = true;\n}\n\nvoid RendererShaderVk::ShaderCacheLoading_end()\n{\n\t// keep g_spirvCache open since we will write to it while the game is running\n\ts_isLoadingShadersVk = false;\n}\n\nvoid RendererShaderVk::ShaderCacheLoading_Close()\n{\n    delete s_spirvCache;\n    s_spirvCache = nullptr;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/RendererShader.h\"\n#include \"util/helpers/ConcurrentQueue.h\"\n\n#include <vulkan/vulkan_core.h>\n#include \"util/helpers/Semaphore.h\"\n#include \"util/helpers/fspinlock.h\"\n\nclass RendererShaderVk : public RendererShader\n{\n\tfriend class VulkanRenderer;\n\tfriend class _ShaderVkThreadPool;\n\n\tenum class COMPILATION_STATE : uint32\n\t{\n\t\tNONE,\n\t\tQUEUED,\n\t\tCOMPILING,\n\t\tDONE\n\t};\n\npublic:\n\tstatic void ShaderCacheLoading_begin(uint64 cacheTitleId);\n    static void ShaderCacheLoading_end();\n    static void ShaderCacheLoading_Close();\n\n\tRendererShaderVk(ShaderType type, uint64 baseHash, uint64 auxHash, bool isGameShader, bool isGfxPackShader, const std::string& glslCode);\n\tvirtual ~RendererShaderVk();\n\n\tstatic void Init();\n\tstatic void Shutdown();\n\n\tVkShaderModule& GetShaderModule() { return m_shader_module; }\n\n\tstatic inline FSpinlock s_dependencyLock;\n\n\tvoid TrackDependency(class PipelineInfo* p)\n\t{\n\t\ts_dependencyLock.lock();\n\t\tlist_pipelineInfo.emplace_back(p);\n\t\ts_dependencyLock.unlock();\n\t}\n\n\tvoid RemoveDependency(class PipelineInfo* p)\n\t{\n\t\ts_dependencyLock.lock();\n\t\tvectorRemoveByValue(list_pipelineInfo, p);\n\t\ts_dependencyLock.unlock();\n\t}\n\n\tvoid PreponeCompilation(bool isRenderThread) override;\n\tbool IsCompiled() override;\n\tbool WaitForCompiled() override;\n\nprivate:\n\tvoid CompileInternal(bool isRenderThread);\n\n\tvoid FinishCompilation();\n\n\tVkShaderModule m_shader_module = nullptr;\n\n\tStateSemaphore<COMPILATION_STATE> m_compilationState{ COMPILATION_STATE::NONE };\n\n\tstd::string m_glslCode;\n\n\tvoid CreateVkShaderModule(std::span<uint32> spirvBuffer);\n\n\t// pipeline infos\n\tstd::vector<class PipelineInfo*> list_pipelineInfo;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp",
    "content": "#include \"SwapchainInfoVk.h\"\n\n#include \"config/CemuConfig.h\"\n#include \"WindowSystem.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteTiming.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n\nSwapchainInfoVk::SwapchainInfoVk(bool mainWindow, Vector2i size) : mainWindow(mainWindow), m_desiredExtent(size)\n{\n\tauto& windowHandleInfo = mainWindow ? WindowSystem::GetWindowInfo().canvas_main : WindowSystem::GetWindowInfo().canvas_pad;\n\tauto renderer = VulkanRenderer::GetInstance();\n\tm_instance = renderer->GetVkInstance();\n\tm_logicalDevice = renderer->GetLogicalDevice();\n\tm_physicalDevice = renderer->GetPhysicalDevice();\n\n\tm_surface = renderer->CreateFramebufferSurface(m_instance, windowHandleInfo);\n}\n\n\nSwapchainInfoVk::~SwapchainInfoVk()\n{\n\tCleanup();\n\tif(m_surface != VK_NULL_HANDLE)\n\t\tvkDestroySurfaceKHR(m_instance, m_surface, nullptr);\n}\n\nvoid SwapchainInfoVk::Create()\n{\n\tconst auto details = QuerySwapchainSupport(m_surface, m_physicalDevice);\n\tm_surfaceFormat = ChooseSurfaceFormat(details.formats);\n\tm_actualExtent = ChooseSwapExtent(details.capabilities);\n\n\t// use at least two swapchain images. fewer than that causes problems on some drivers\n\tuint32_t image_count = std::max(2u, details.capabilities.minImageCount);\n\tif(details.capabilities.maxImageCount > 0)\n\t\timage_count = std::min(image_count, details.capabilities.maxImageCount);\n\tif(image_count < 2)\n\t\tcemuLog_log(LogType::Force, \"Vulkan: Swapchain image count less than 2 may cause problems\");\n\n\tVkSwapchainCreateInfoKHR create_info = CreateSwapchainCreateInfo(m_surface, details, m_surfaceFormat, image_count, m_actualExtent);\n\tcreate_info.oldSwapchain = nullptr;\n\tcreate_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;\n\n\tVkResult result = vkCreateSwapchainKHR(m_logicalDevice, &create_info, nullptr, &m_swapchain);\n\tif (result != VK_SUCCESS)\n\t\tUnrecoverableError(\"Error attempting to create a swapchain\");\n\n\tresult = vkGetSwapchainImagesKHR(m_logicalDevice, m_swapchain, &image_count, nullptr);\n\tif (result != VK_SUCCESS)\n\t\tUnrecoverableError(\"Error attempting to retrieve the count of swapchain images\");\n\n\n\tm_swapchainImages.resize(image_count);\n\tresult = vkGetSwapchainImagesKHR(m_logicalDevice, m_swapchain, &image_count, m_swapchainImages.data());\n\tif (result != VK_SUCCESS)\n\t\tUnrecoverableError(\"Error attempting to retrieve swapchain images\");\n\t// create default renderpass\n\tVkAttachmentDescription colorAttachment = {};\n\tcolorAttachment.format = m_surfaceFormat.format;\n\tcolorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;\n\tcolorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n\tcolorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n\tcolorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n\tcolorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n\tcolorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\tcolorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;\n\n\tVkAttachmentReference colorAttachmentRef = {};\n\tcolorAttachmentRef.attachment = 0;\n\tcolorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n\tVkSubpassDescription subpass = {};\n\tsubpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n\tsubpass.colorAttachmentCount = 1;\n\tsubpass.pColorAttachments = &colorAttachmentRef;\n\n\tVkRenderPassCreateInfo renderPassInfo = {};\n\trenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n\trenderPassInfo.attachmentCount = 1;\n\trenderPassInfo.pAttachments = &colorAttachment;\n\trenderPassInfo.subpassCount = 1;\n\trenderPassInfo.pSubpasses = &subpass;\n\tresult = vkCreateRenderPass(m_logicalDevice, &renderPassInfo, nullptr, &m_swapchainRenderPass);\n\tif (result != VK_SUCCESS)\n\t\tUnrecoverableError(\"Failed to create renderpass for swapchain\");\n\n\t// create swapchain image views\n\tm_swapchainImageViews.resize(m_swapchainImages.size());\n\tfor (sint32 i = 0; i < m_swapchainImages.size(); i++)\n\t{\n\t\tVkImageViewCreateInfo createInfo = {};\n\t\tcreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n\t\tcreateInfo.image = m_swapchainImages[i];\n\t\tcreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;\n\t\tcreateInfo.format = m_surfaceFormat.format;\n\t\tcreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\tcreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\tcreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\tcreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n\t\tcreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\tcreateInfo.subresourceRange.baseMipLevel = 0;\n\t\tcreateInfo.subresourceRange.levelCount = 1;\n\t\tcreateInfo.subresourceRange.baseArrayLayer = 0;\n\t\tcreateInfo.subresourceRange.layerCount = 1;\n\t\tresult = vkCreateImageView(m_logicalDevice, &createInfo, nullptr, &m_swapchainImageViews[i]);\n\t\tif (result != VK_SUCCESS)\n\t\t\tUnrecoverableError(\"Failed to create imageviews for swapchain\");\n\t}\n\n\t// create swapchain framebuffers\n\tm_swapchainFramebuffers.resize(m_swapchainImages.size());\n\tfor (size_t i = 0; i < m_swapchainImages.size(); i++)\n\t{\n\t\tVkImageView attachments[1];\n\t\tattachments[0] = m_swapchainImageViews[i];\n\t\t// create framebuffer\n\t\tVkFramebufferCreateInfo framebufferInfo = {};\n\t\tframebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;\n\t\tframebufferInfo.renderPass = m_swapchainRenderPass;\n\t\tframebufferInfo.attachmentCount = 1;\n\t\tframebufferInfo.pAttachments = attachments;\n\t\tframebufferInfo.width = m_actualExtent.width;\n\t\tframebufferInfo.height = m_actualExtent.height;\n\t\tframebufferInfo.layers = 1;\n\t\tresult = vkCreateFramebuffer(m_logicalDevice, &framebufferInfo, nullptr, &m_swapchainFramebuffers[i]);\n\t\tif (result != VK_SUCCESS)\n\t\t\tUnrecoverableError(\"Failed to create framebuffer for swapchain\");\n\t}\n\n\tm_presentSemaphores.resize(m_swapchainImages.size());\n\t// create present semaphores\n\tVkSemaphoreCreateInfo info = {};\n\tinfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n\tfor (auto& semaphore : m_presentSemaphores){\n\t\tif (vkCreateSemaphore(m_logicalDevice, &info, nullptr, &semaphore) != VK_SUCCESS)\n\t\t\tUnrecoverableError(\"Failed to create semaphore for swapchain present\");\n\t}\n\n\tm_acquireSemaphores.resize(m_swapchainImages.size());\n\t// create acquire semaphores\n\tinfo = {};\n\tinfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n\tfor (auto& semaphore : m_acquireSemaphores){\n\t\tif (vkCreateSemaphore(m_logicalDevice, &info, nullptr, &semaphore) != VK_SUCCESS)\n\t\t\tUnrecoverableError(\"Failed to create semaphore for swapchain acquire\");\n\t}\n\n\tVkFenceCreateInfo fenceInfo = {};\n\tfenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n\tfenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;\n\tresult = vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &m_imageAvailableFence);\n\tif (result != VK_SUCCESS)\n\t\tUnrecoverableError(\"Failed to create fence for swapchain\");\n\n\tm_acquireIndex = 0;\n\thasDefinedSwapchainImage = false;\n\n\tm_queueDepth = 0;\n}\n\nvoid SwapchainInfoVk::Cleanup()\n{\n\tm_swapchainImages.clear();\n\n\tfor (auto& sem: m_acquireSemaphores)\n\t\tvkDestroySemaphore(m_logicalDevice, sem, nullptr);\n\tm_acquireSemaphores.clear();\n\n\tfor (auto& sem: m_presentSemaphores)\n\t\tvkDestroySemaphore(m_logicalDevice, sem, nullptr);\n\tm_presentSemaphores.clear();\n\n\tif (m_swapchainRenderPass)\n\t{\n\t\tvkDestroyRenderPass(m_logicalDevice, m_swapchainRenderPass, nullptr);\n\t\tm_swapchainRenderPass = nullptr;\n\t}\n\n\tfor (auto& imageView : m_swapchainImageViews)\n\t\tvkDestroyImageView(m_logicalDevice, imageView, nullptr);\n\tm_swapchainImageViews.clear();\n\n\tfor (auto& framebuffer : m_swapchainFramebuffers)\n\t\tvkDestroyFramebuffer(m_logicalDevice, framebuffer, nullptr);\n\tm_swapchainFramebuffers.clear();\n\n\n\tif (m_imageAvailableFence)\n\t{\n\t\tWaitAvailableFence();\n\t\tvkDestroyFence(m_logicalDevice, m_imageAvailableFence, nullptr);\n\t\tm_imageAvailableFence = nullptr;\n\t}\n\tif (m_swapchain)\n\t{\n\t\tvkDestroySwapchainKHR(m_logicalDevice, m_swapchain, nullptr);\n\t\tm_swapchain = VK_NULL_HANDLE;\n\t}\n}\n\nbool SwapchainInfoVk::IsValid() const\n{\n\treturn m_swapchain && !m_acquireSemaphores.empty();\n}\n\nvoid SwapchainInfoVk::WaitAvailableFence()\n{\n\tif(m_awaitableFence != VK_NULL_HANDLE)\n\t\tvkWaitForFences(m_logicalDevice, 1, &m_awaitableFence, VK_TRUE, UINT64_MAX);\n\tm_awaitableFence = VK_NULL_HANDLE;\n}\n\nvoid SwapchainInfoVk::ResetAvailableFence() const\n{\n\tvkResetFences(m_logicalDevice, 1, &m_imageAvailableFence);\n}\n\nVkSemaphore SwapchainInfoVk::ConsumeAcquireSemaphore()\n{\n\tVkSemaphore ret = m_currentSemaphore;\n\tm_currentSemaphore = VK_NULL_HANDLE;\n\treturn ret;\n}\n\nbool SwapchainInfoVk::AcquireImage()\n{\n\tResetAvailableFence();\n\n\tVkSemaphore acquireSemaphore = m_acquireSemaphores[m_acquireIndex];\n\tVkResult result = vkAcquireNextImageKHR(m_logicalDevice, m_swapchain, 1'000'000'000, acquireSemaphore, m_imageAvailableFence, &swapchainImageIndex);\n\tif (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)\n\t\tm_shouldRecreate = true;\n\tif (result == VK_TIMEOUT)\n\t{\n\t\tswapchainImageIndex = -1;\n\t\treturn false;\n\t}\n\n\tif (result < 0)\n\t{\n\t\tswapchainImageIndex = -1;\n\t\tif (result != VK_ERROR_OUT_OF_DATE_KHR)\n\t\t\tthrow std::runtime_error(fmt::format(\"Failed to acquire next image: {}\", result));\n\t\treturn false;\n\t}\n\tm_currentSemaphore = acquireSemaphore;\n\tm_awaitableFence = m_imageAvailableFence;\n\tm_acquireIndex = (m_acquireIndex + 1) % m_swapchainImages.size();\n\n\treturn true;\n}\n\nvoid SwapchainInfoVk::UnrecoverableError(const char* errMsg)\n{\n\tcemuLog_log(LogType::Force, \"Unrecoverable error in Vulkan swapchain\");\n\tcemuLog_log(LogType::Force, \"Msg: {}\", errMsg);\n\tthrow std::runtime_error(errMsg);\n}\n\n\nSwapchainInfoVk::SwapchainSupportDetails SwapchainInfoVk::QuerySwapchainSupport(VkSurfaceKHR surface, const VkPhysicalDevice& device)\n{\n\tSwapchainSupportDetails details;\n\n\tVkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);\n\tif (result != VK_SUCCESS)\n\t{\n\t\tif (result != VK_ERROR_SURFACE_LOST_KHR)\n\t\t\tcemuLog_log(LogType::Force, \"vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed. Error {}\", (sint32)result);\n\t\tthrow std::runtime_error(fmt::format(\"Unable to retrieve physical device surface capabilities: {}\", result));\n\t}\n\n\tuint32_t formatCount = 0;\n\tresult = vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);\n\tif (result != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"vkGetPhysicalDeviceSurfaceFormatsKHR failed. Error {}\", (sint32)result);\n\t\tthrow std::runtime_error(fmt::format(\"Unable to retrieve the number of formats for a surface on a physical device: {}\", result));\n\t}\n\n\tif (formatCount != 0)\n\t{\n\t\tdetails.formats.resize(formatCount);\n\t\tresult = vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());\n\t\tif (result != VK_SUCCESS)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"vkGetPhysicalDeviceSurfaceFormatsKHR failed. Error {}\", (sint32)result);\n\t\t\tthrow std::runtime_error(fmt::format(\"Unable to retrieve the formats for a surface on a physical device: {}\", result));\n\t\t}\n\t}\n\n\tuint32_t presentModeCount = 0;\n\tresult = vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);\n\tif (result != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"vkGetPhysicalDeviceSurfacePresentModesKHR failed. Error {}\", (sint32)result);\n\t\tthrow std::runtime_error(fmt::format(\"Unable to retrieve the count of present modes for a surface on a physical device: {}\", result));\n\t}\n\n\tif (presentModeCount != 0)\n\t{\n\t\tdetails.presentModes.resize(presentModeCount);\n\t\tresult = vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());\n\t\tif (result != VK_SUCCESS)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"vkGetPhysicalDeviceSurfacePresentModesKHR failed. Error {}\", (sint32)result);\n\t\t\tthrow std::runtime_error(fmt::format(\"Unable to retrieve the present modes for a surface on a physical device: {}\", result));\n\t\t}\n\t}\n\n\treturn details;\n}\n\nVkSurfaceFormatKHR SwapchainInfoVk::ChooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats) const\n{\n\tif (formats.size() == 1 && formats[0].format == VK_FORMAT_UNDEFINED)\n\t\treturn{ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };\n\n\tfor (const auto& format : formats)\n\t{\n\t\tif (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)\n\t\t\treturn format;\n\t}\n\n\treturn formats[0];\n}\n\nVkExtent2D SwapchainInfoVk::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) const\n{\n\tif (capabilities.currentExtent.width != std::numeric_limits<uint32>::max())\n\t\treturn capabilities.currentExtent;\n\n\tVkExtent2D actualExtent = { (uint32)m_desiredExtent.x, (uint32)m_desiredExtent.y };\n\tactualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));\n\tactualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));\n\treturn actualExtent;\n}\n\nVkPresentModeKHR SwapchainInfoVk::ChoosePresentMode(const std::vector<VkPresentModeKHR>& modes)\n{\n\tm_maxQueued = 0;\n\tconst auto vsyncState = (VSync)GetConfig().vsync.GetValue();\n\tif (vsyncState == VSync::MAILBOX)\n\t{\n\t\tif (std::find(modes.cbegin(), modes.cend(), VK_PRESENT_MODE_MAILBOX_KHR) != modes.cend())\n\t\t\treturn VK_PRESENT_MODE_MAILBOX_KHR;\n\n\t\tcemuLog_log(LogType::Force, \"Vulkan: Can't find mailbox present mode\");\n\t}\n\telse if (vsyncState == VSync::Immediate)\n\t{\n\t\tif (std::find(modes.cbegin(), modes.cend(), VK_PRESENT_MODE_IMMEDIATE_KHR) != modes.cend())\n\t\t\treturn VK_PRESENT_MODE_IMMEDIATE_KHR;\n\n\t\tcemuLog_log(LogType::Force, \"Vulkan: Can't find immediate present mode\");\n\t}\n\telse if (vsyncState == VSync::SYNC_AND_LIMIT)\n\t{\n\t\tLatteTiming_EnableHostDrivenVSync();\n\t\t// use immediate mode if available, other wise fall back to\n\t\t//if (std::find(modes.cbegin(), modes.cend(), VK_PRESENT_MODE_IMMEDIATE_KHR) != modes.cend())\n\t\t//\treturn VK_PRESENT_MODE_IMMEDIATE_KHR;\n\t\t//else\n\t\t//\tcemuLog_log(LogType::Force, \"Vulkan: Present mode 'immediate' not available. Vsync might not behave as intended\");\n\t\treturn VK_PRESENT_MODE_FIFO_KHR;\n\t}\n\n\tm_maxQueued = 1;\n\treturn VK_PRESENT_MODE_FIFO_KHR;\n}\n\nVkSwapchainCreateInfoKHR SwapchainInfoVk::CreateSwapchainCreateInfo(VkSurfaceKHR surface, const SwapchainSupportDetails& swapchainSupport, const VkSurfaceFormatKHR& surfaceFormat, uint32 imageCount, const VkExtent2D& extent)\n{\n\tVkSwapchainCreateInfoKHR createInfo{};\n\tcreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;\n\tcreateInfo.surface = surface;\n\tcreateInfo.minImageCount = imageCount;\n\tcreateInfo.imageFormat = surfaceFormat.format;\n\tcreateInfo.imageExtent = extent;\n\tcreateInfo.imageArrayLayers = 1;\n\tcreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;\n\n\tconst VulkanRenderer::QueueFamilyIndices indices = VulkanRenderer::GetInstance()->FindQueueFamilies(surface, m_physicalDevice);\n\tm_swapchainQueueFamilyIndices = { (uint32)indices.graphicsFamily, (uint32)indices.presentFamily };\n\tif (indices.graphicsFamily != indices.presentFamily)\n\t{\n\t\tcreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;\n\t\tcreateInfo.queueFamilyIndexCount = m_swapchainQueueFamilyIndices.size();\n\t\tcreateInfo.pQueueFamilyIndices = m_swapchainQueueFamilyIndices.data();\n\t}\n\telse\n\t\tcreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n\tcreateInfo.preTransform = swapchainSupport.capabilities.currentTransform;\n\tcreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;\n\tcreateInfo.presentMode = ChoosePresentMode(swapchainSupport.presentModes);\n\tcreateInfo.clipped = VK_TRUE;\n\n\tcemuLog_logDebug(LogType::Force, \"vulkan presentation mode: {}\", createInfo.presentMode);\n\treturn createInfo;\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h",
    "content": "#pragma once\n\n#include \"util/math/vector2.h\"\n#include <vulkan/vulkan_core.h>\n\nstruct SwapchainInfoVk\n{\n\tenum class VSync\n\t{\n\t\t// values here must match GeneralSettings2::m_vsync\n\t\tImmediate = 0,\n\t\tFIFO = 1,\n\t\tMAILBOX = 2,\n\t\tSYNC_AND_LIMIT = 3, // synchronize emulated vsync events to monitor vsync. But skip events if rate higher than virtual vsync period\n\t};\n\n\tstruct SwapchainSupportDetails\n\t{\n\t\tVkSurfaceCapabilitiesKHR capabilities;\n\t\tstd::vector<VkSurfaceFormatKHR> formats;\n\t\tstd::vector<VkPresentModeKHR> presentModes;\n\t};\n\n\tvoid Cleanup();\n\tvoid Create();\n\n\tbool IsValid() const;\n\n\tvoid WaitAvailableFence();\n\tvoid ResetAvailableFence() const;\n\n\tbool AcquireImage();\n\t// retrieve semaphore of last acquire for submitting a wait operation\n\t// only one wait operation must be submitted per acquire (which submits a single signal operation)\n\t// therefore subsequent calls will return a NULL handle\n\tVkSemaphore ConsumeAcquireSemaphore();\n\n\tstatic void UnrecoverableError(const char* errMsg);\n\n\tstatic SwapchainSupportDetails QuerySwapchainSupport(VkSurfaceKHR surface, const VkPhysicalDevice& device);\n\n\tVkPresentModeKHR ChoosePresentMode(const std::vector<VkPresentModeKHR>& modes);\n\tVkSurfaceFormatKHR ChooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats) const;\n\tVkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) const;\n\n\tVkSwapchainCreateInfoKHR CreateSwapchainCreateInfo(VkSurfaceKHR surface, const SwapchainSupportDetails& swapchainSupport, const VkSurfaceFormatKHR& surfaceFormat, uint32 imageCount, const VkExtent2D& extent);\n\n\n\tVkExtent2D getExtent() const\n\t{\n\t\treturn m_actualExtent;\n\t}\n\n\tSwapchainInfoVk(bool mainWindow, Vector2i size);\n\tSwapchainInfoVk(const SwapchainInfoVk&) = delete;\n\tSwapchainInfoVk(SwapchainInfoVk&&) noexcept = default;\n\t~SwapchainInfoVk();\n\n\tbool mainWindow{};\n\n\tbool m_shouldRecreate = false;\n\tVSync m_vsyncState = VSync::Immediate;\n\tbool hasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state\n\n\tVkInstance m_instance{};\n\tVkPhysicalDevice m_physicalDevice{};\n\tVkDevice m_logicalDevice{};\n\tVkSurfaceKHR m_surface{};\n\tVkSurfaceFormatKHR m_surfaceFormat{};\n\tVkSwapchainKHR m_swapchain{};\n\tVector2i m_desiredExtent{};\n\tVkExtent2D m_actualExtent{};\n\tuint32 swapchainImageIndex = (uint32)-1;\n\tuint64 m_presentId = 1;\n\tuint64 m_queueDepth = 0; // number of frames with pending presentation requests\n\tuint64 m_maxQueued = 0; // the maximum number of frames with presentation requests.\n\n\n\t// swapchain image ringbuffer (indexed by swapchainImageIndex)\n\tstd::vector<VkImage> m_swapchainImages;\n\tstd::vector<VkImageView> m_swapchainImageViews;\n\tstd::vector<VkFramebuffer> m_swapchainFramebuffers;\n\tstd::vector<VkSemaphore> m_presentSemaphores; // indexed by swapchainImageIndex\n\n\tVkRenderPass m_swapchainRenderPass = nullptr;\n\nprivate:\n\tuint32 m_acquireIndex = 0;\n\tstd::vector<VkSemaphore> m_acquireSemaphores; // indexed by m_acquireIndex\n\tVkFence m_imageAvailableFence{};\n\tVkFence m_awaitableFence = VK_NULL_HANDLE;\n\tVkSemaphore m_currentSemaphore = VK_NULL_HANDLE;\n\n\tstd::array<uint32, 2> m_swapchainQueueFamilyIndices;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/TextureReadbackVk.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanTextureReadback.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h\"\n\nLatteTextureReadbackInfoVk::LatteTextureReadbackInfoVk(VkDevice device, LatteTextureView* textureView)\n\t: LatteTextureReadbackInfo(textureView), m_device(device)\n{\n\tm_image_size = GetImageSize(textureView);\n}\n\nLatteTextureReadbackInfoVk::~LatteTextureReadbackInfoVk()\n{\n}\n\nuint32 LatteTextureReadbackInfoVk::GetImageSize(LatteTextureView* textureView)\n{\n\tconst auto* baseTexture = (LatteTextureVk*)textureView->baseTexture;\n\t// handle format\n\tconst auto textureFormat = baseTexture->GetFormat();\n\tif (textureView->format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM)\n\t{\n\t\tcemu_assert(textureFormat == VK_FORMAT_R8G8B8A8_UNORM);\n\t\treturn baseTexture->width * baseTexture->height * 4;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R8_UNORM )\n\t{\n\t\tcemu_assert(textureFormat == VK_FORMAT_R8_UNORM);\n\t\treturn baseTexture->width * baseTexture->height * 1;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB)\n\t{\n\t\tcemu_assert(textureFormat == VK_FORMAT_R8G8B8A8_SRGB);\n\t\treturn baseTexture->width * baseTexture->height * 4;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT)\n\t{\n\t\tcemu_assert(textureFormat == VK_FORMAT_R32G32B32A32_SFLOAT);\n\t\treturn baseTexture->width * baseTexture->height * 16;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R32_FLOAT)\n\t{\n\t\tcemu_assert(textureFormat == VK_FORMAT_R32_SFLOAT || textureFormat == VK_FORMAT_D32_SFLOAT);\n\t\tif (baseTexture->isDepth)\n\t\t\treturn baseTexture->width * baseTexture->height * 4;\n\t\telse\n\t\t\treturn baseTexture->width * baseTexture->height * 4;\t\t\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R16_UNORM)\n\t{\n\t\tcemu_assert(textureFormat == VK_FORMAT_R16_UNORM);\n\t\tif (baseTexture->isDepth)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn baseTexture->width * baseTexture->height * 2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn baseTexture->width * baseTexture->height * 2;\n\t\t}\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT)\n\t{\n\t\tcemu_assert(textureFormat == VK_FORMAT_R16G16B16A16_SFLOAT);\n\t\treturn baseTexture->width * baseTexture->height * 8;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R8_G8_UNORM)\n\t{\n\t\tcemu_assert(textureFormat == VK_FORMAT_R8G8_UNORM);\n\t\treturn baseTexture->width * baseTexture->height * 2;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM)\n\t{\n\t\tcemu_assert(textureFormat == VK_FORMAT_R16G16B16A16_UNORM);\n\t\treturn baseTexture->width * baseTexture->height * 8;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::D24_S8_UNORM)\n\t{\n\t\tcemu_assert(textureFormat == VK_FORMAT_D24_UNORM_S8_UINT);\n\t\t// todo - if driver does not support VK_FORMAT_D24_UNORM_S8_UINT this is represented as VK_FORMAT_D32_SFLOAT_S8_UINT which is 8 bytes\n\t\treturn baseTexture->width * baseTexture->height * 4;\n\t}\n\telse if (textureView->format == Latte::E_GX2SURFFMT::R5_G6_B5_UNORM )\n\t{\n\t\tif(textureFormat == VK_FORMAT_R5G6B5_UNORM_PACK16){\n\t\t\treturn baseTexture->width * baseTexture->height * 2;\n\t\t}\t\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"Unsupported texture readback format {:04x}\", (uint32)textureView->format);\n\t\tcemu_assert_debug(false);\n\t\treturn 0;\n\t}\n}\n\n\nvoid LatteTextureReadbackInfoVk::StartTransfer()\n{\n\tcemu_assert(m_textureView);\n\n\tauto* baseTexture = (LatteTextureVk*)m_textureView->baseTexture;\n\tbaseTexture->GetImageObj()->flagForCurrentCommandBuffer();\n\n\tcemu_assert_debug(m_textureView->firstSlice == 0);\n\tcemu_assert_debug(m_textureView->firstMip == 0);\n\tcemu_assert_debug(m_textureView->baseTexture->dim != Latte::E_DIM::DIM_3D);\n\n\tVkBufferImageCopy region{};\n\tregion.bufferOffset = m_buffer_offset;\n\tregion.bufferRowLength = baseTexture->width;\n\tregion.bufferImageHeight = baseTexture->height;\n\n\tregion.imageSubresource.aspectMask = baseTexture->GetImageAspect();\n\tregion.imageSubresource.baseArrayLayer = 0;\n\tregion.imageSubresource.layerCount = 1;\n\tregion.imageSubresource.mipLevel = 0;\n\n\tregion.imageOffset = {0,0,0};\n\tregion.imageExtent = {(uint32)baseTexture->width,(uint32)baseTexture->height,1};\n\n\tconst auto renderer = VulkanRenderer::GetInstance();\n\trenderer->draw_endRenderPass();\n\n\trenderer->barrier_image<VulkanRenderer::ANY_TRANSFER | VulkanRenderer::IMAGE_WRITE, VulkanRenderer::TRANSFER_READ>(baseTexture, region.imageSubresource, VK_IMAGE_LAYOUT_GENERAL);\n\n\trenderer->barrier_sequentializeTransfer();\n\n\tvkCmdCopyImageToBuffer(renderer->getCurrentCommandBuffer(), baseTexture->GetImageObj()->m_image, VK_IMAGE_LAYOUT_GENERAL, m_buffer, 1, &region);\n\n\trenderer->barrier_sequentializeTransfer();\n\n\trenderer->barrier_image<VulkanRenderer::TRANSFER_READ, VulkanRenderer::ANY_TRANSFER | VulkanRenderer::IMAGE_WRITE>(baseTexture, region.imageSubresource, VK_IMAGE_LAYOUT_GENERAL); // make sure transfer is finished before image is modified\n\trenderer->barrier_bufferRange<VulkanRenderer::TRANSFER_WRITE, VulkanRenderer::HOST_READ>(m_buffer, m_buffer_offset, m_image_size); // make sure transfer is finished before result is read\n\n\tm_associatedCommandBufferId = renderer->GetCurrentCommandBufferId();\n\tm_textureView = nullptr;\n\n\t// to decrease latency of readbacks make sure that the current command buffer is submitted soon\n\trenderer->RequestSubmitSoon();\n\trenderer->RequestSubmitOnIdle();\n}\n\nbool LatteTextureReadbackInfoVk::IsFinished()\n{\n\tconst auto renderer = VulkanRenderer::GetInstance();\n\treturn renderer->HasCommandBufferFinished(m_associatedCommandBufferId);\n}\n\nvoid LatteTextureReadbackInfoVk::ForceFinish()\n{\n\tconst auto renderer = VulkanRenderer::GetInstance();\n\trenderer->WaitCommandBufferFinished(m_associatedCommandBufferId);\n}\n\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"util/math/vector2.h\"\n\nclass VKRMoveableRefCounterRef\n{\npublic:\n\tclass VKRMoveableRefCounter* ref;\n};\n\nclass VKRMoveableRefCounter\n{\npublic:\n\tVKRMoveableRefCounter()\n\t{\n\t\tselfRef = new VKRMoveableRefCounterRef();\n\t\tselfRef->ref = this;\n\t}\n\n\tvirtual ~VKRMoveableRefCounter()\n\t{\n\t\tcemu_assert_debug(m_refCount == 0);\n\n\t\t// remove references\n#ifdef CEMU_DEBUG_ASSERT\n\t\tfor (auto itr : refs)\n\t\t{\n\t\t\tauto& rev = itr->ref->reverseRefs;\n\t\t\trev.erase(std::remove(rev.begin(), rev.end(), this->selfRef), rev.end());\n\t\t}\n#endif\n\t\tfor (auto itr : refs)\n\t\t{\n\t\t\titr->ref->m_refCount--;\n\t\t\tif (itr->ref->m_refCount == 0)\n\t\t\t\titr->ref->RefCountReachedZero();\n\t\t}\n\t\trefs.clear();\n\t\tdelete selfRef;\n\t\tselfRef = nullptr;\n\t}\n\n\tVKRMoveableRefCounter(const VKRMoveableRefCounter&) = delete;\n\tVKRMoveableRefCounter& operator=(const VKRMoveableRefCounter&) = delete;\n\tVKRMoveableRefCounter(VKRMoveableRefCounter&& rhs) noexcept\n\t{\n\t\tthis->refs = std::move(rhs.refs);\n\t\tthis->m_refCount.store(rhs.m_refCount);\n\t\trhs.m_refCount = 0;\n\t\tthis->selfRef = rhs.selfRef;\n\t\trhs.selfRef = nullptr;\n\t\tthis->selfRef->ref = this;\n\t}\n\n\tVKRMoveableRefCounter& operator=(VKRMoveableRefCounter&& rhs) noexcept\n\t{\n\t\tcemu_assert(false);\n\t\treturn *this;\n\t}\n\n\tvoid addRef(VKRMoveableRefCounter* refTarget)\n\t{\n\t\tthis->refs.emplace_back(refTarget->selfRef);\n\t\trefTarget->m_refCount++;\n\n#ifdef CEMU_DEBUG_ASSERT\n\t\t// add reverse ref\n\t\trefTarget->reverseRefs.emplace_back(this->selfRef);\n#endif\n\t}\n\n\t// methods to directly increment/decrement ref counter (for situations where no external object is available)\n\tvoid incRef()\n\t{\n\t\tm_refCount++;\n\t}\n\n\tvoid decRef()\n\t{\n\t\tm_refCount--;\n\t\tif (m_refCount == 0)\n\t\t\tRefCountReachedZero();\n\t}\n\nprotected:\n  \tvirtual void RefCountReachedZero()\n\t{\n\t\t// does nothing by default\n\t}\n\n\tstd::atomic_int_least32_t m_refCount{};\nprivate:\n\tVKRMoveableRefCounterRef* selfRef;\n\tstd::vector<VKRMoveableRefCounterRef*> refs;\n#ifdef CEMU_DEBUG_ASSERT\n\tstd::vector<VKRMoveableRefCounterRef*> reverseRefs;\n#endif\n};\n\nclass VKRDestructibleObject : public VKRMoveableRefCounter\n{\npublic:\n\tvoid flagForCurrentCommandBuffer();\n\tbool canDestroy();\n\n\tvirtual ~VKRDestructibleObject() {};\nprivate:\n\tuint64 m_lastCmdBufferId{};\n};\n\n/* Vulkan objects */\n\nclass VKRObjectTexture : public VKRDestructibleObject\n{\npublic:\n\tVKRObjectTexture();\n\t~VKRObjectTexture() override;\n\n\tVkImage m_image{ VK_NULL_HANDLE };\n\tVkFormat m_format = VK_FORMAT_UNDEFINED;\n\tVkImageCreateFlags m_flags;\n\tVkImageAspectFlags m_imageAspect;\n\tstruct VkImageMemAllocation* m_allocation{};\n\n};\n\nclass VKRObjectTextureView : public VKRDestructibleObject\n{\npublic:\n\tVKRObjectTextureView(VKRObjectTexture* tex, VkImageView view);\n\t~VKRObjectTextureView() override;\n\n\tVkImageView m_textureImageView{ VK_NULL_HANDLE };\n\tVkSampler m_textureDefaultSampler[2] = { VK_NULL_HANDLE, VK_NULL_HANDLE }; // relict from LatteTextureViewVk, get rid of it eventually\n};\n\n\nclass VKRObjectSampler : public VKRDestructibleObject\n{\n  public:\n\tVKRObjectSampler(VkSamplerCreateInfo* samplerInfo);\n\t~VKRObjectSampler() override;\n\n\tstatic VKRObjectSampler* GetOrCreateSampler(VkSamplerCreateInfo* samplerInfo);\n\tstatic void DestroyCache();\n\n\tvoid RefCountReachedZero() override; // sampler objects are destroyed when not referenced anymore\n\n\tVkSampler GetSampler() const { return m_sampler; }\n  private:\n\tstatic std::unordered_map<uint64, VKRObjectSampler*> s_samplerCache;\n\tVkSampler m_sampler{ VK_NULL_HANDLE };\n\tuint64 m_hash;\n};\n\nclass VKRObjectRenderPass : public VKRDestructibleObject\n{\npublic:\n\tstruct AttachmentEntryColor_t\n\t{\n\t\tVKRObjectTextureView* viewObj{};\n\t\tbool isPresent{};\n\t\tVkFormat format; // todo - we dont need to track isPresent or viewObj, we can just compare this with VK_FORMAT_UNDEFINED\n\t};\n\n\tstruct AttachmentEntryDepth_t\n\t{\n\t\tVKRObjectTextureView* viewObj{};\n\t\tbool isPresent{};\n\t\tVkFormat format; // todo - we dont need to track isPresent or viewObj, we can just compare this with VK_FORMAT_UNDEFINED\n\t\tbool hasStencil;\n\t};\n\n\tstruct AttachmentInfo_t\n\t{\n\t\tAttachmentEntryColor_t colorAttachment[Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS];\n\t\tAttachmentEntryDepth_t depthAttachment;\n\t};\n\n\tVkFormat GetColorFormat(size_t index)\n\t{\n\t\tif (index >= Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS)\n\t\t\treturn VK_FORMAT_UNDEFINED;\n\t\treturn m_colorAttachmentFormat[index];\n\t}\n\n\tVkFormat GetDepthFormat()\n\t{\n\t\treturn m_depthAttachmentFormat;\n\t}\n\npublic:\n\tVKRObjectRenderPass(AttachmentInfo_t& attachmentInfo, sint32 colorAttachmentCount = Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS);\n\t~VKRObjectRenderPass() override;\n\tVkRenderPass m_renderPass{ VK_NULL_HANDLE };\n\tVkFormat m_colorAttachmentFormat[Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS];\n\tVkFormat m_depthAttachmentFormat;\n\tuint64 m_hashForPipeline; // helper var. Holds hash of all the renderpass creation parameters (mainly the formats) that affect the pipeline state\n};\n\nclass VKRObjectFramebuffer : public VKRDestructibleObject\n{\npublic:\n\tVKRObjectFramebuffer(VKRObjectRenderPass* renderPass, std::span<VKRObjectTextureView*> attachments, Vector2i size);\n\t~VKRObjectFramebuffer() override;\n\n\tVkFramebuffer m_frameBuffer{ VK_NULL_HANDLE };\n};\n\nclass VKRObjectPipeline : public VKRDestructibleObject\n{\npublic:\n\tVKRObjectPipeline();\n\t~VKRObjectPipeline() override;\n\n\tvoid SetPipeline(VkPipeline newPipeline);\n\tVkPipeline GetPipeline() const { return m_pipeline; }\n\n\tVkDescriptorSetLayout m_vertexDSL = VK_NULL_HANDLE, m_pixelDSL = VK_NULL_HANDLE, m_geometryDSL = VK_NULL_HANDLE;\n\tVkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;\n\nprivate:\n\tVkPipeline m_pipeline = VK_NULL_HANDLE;\n};\n\nclass VKRObjectDescriptorSet : public VKRDestructibleObject\n{\npublic:\n\tVKRObjectDescriptorSet();\n\t~VKRObjectDescriptorSet() override;\n\n\tVkDescriptorSet descriptorSet{ VK_NULL_HANDLE };\n};"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VKRMemoryManager.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VKRMemoryManager.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include <imgui.h>\n\n/* VKRSynchronizedMemoryBuffer */\n\nVKRSynchronizedRingAllocator::~VKRSynchronizedRingAllocator()\n{\n\tfor(auto& buf : m_buffers)\n\t{\n\t\tm_vkrMemMgr->DeleteBuffer(buf.vk_buffer, buf.vk_mem);\n\t}\n}\n\nvoid VKRSynchronizedRingAllocator::addUploadBufferSyncPoint(AllocatorBuffer_t& buffer, uint32 offset)\n{\n\tauto cmdBufferId = m_vkr->GetCurrentCommandBufferId();\n\tif (cmdBufferId == buffer.lastSyncpointCmdBufferId)\n\t\treturn;\n\tbuffer.lastSyncpointCmdBufferId = cmdBufferId;\n\tbuffer.queue_syncPoints.emplace(cmdBufferId, offset);\n}\n\nvoid VKRSynchronizedRingAllocator::allocateAdditionalUploadBuffer(uint32 sizeRequiredForAlloc)\n{\n\t// calculate buffer size, should be a multiple of bufferAllocSize that is at least as large as sizeRequiredForAlloc\n\tuint32 bufferAllocSize = m_minimumBufferAllocSize;\n\twhile (bufferAllocSize < sizeRequiredForAlloc)\n\t\tbufferAllocSize += m_minimumBufferAllocSize;\n\n\tAllocatorBuffer_t newBuffer{};\n\tnewBuffer.writeIndex = 0;\n\tnewBuffer.basePtr = nullptr;\n\tif (m_bufferType == VKR_BUFFER_TYPE::STAGING)\n\t\tm_vkrMemMgr->CreateBuffer(bufferAllocSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, newBuffer.vk_buffer, newBuffer.vk_mem);\n\telse if (m_bufferType == VKR_BUFFER_TYPE::INDEX)\n\t\tm_vkrMemMgr->CreateBuffer(bufferAllocSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, newBuffer.vk_buffer, newBuffer.vk_mem);\n\telse if (m_bufferType == VKR_BUFFER_TYPE::STRIDE)\n\t\tm_vkrMemMgr->CreateBuffer(bufferAllocSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, newBuffer.vk_buffer, newBuffer.vk_mem);\n\telse\n\t\tcemu_assert_debug(false);\n\n\tvoid* bufferPtr = nullptr;\n\tvkMapMemory(m_vkr->GetLogicalDevice(), newBuffer.vk_mem, 0, VK_WHOLE_SIZE, 0, &bufferPtr);\n\tnewBuffer.basePtr = (uint8*)bufferPtr;\n\tnewBuffer.size = bufferAllocSize;\n\tnewBuffer.index = (uint32)m_buffers.size();\n\tm_buffers.push_back(newBuffer);\n}\n\nVKRSynchronizedRingAllocator::AllocatorReservation_t VKRSynchronizedRingAllocator::AllocateBufferMemory(uint32 size, uint32 alignment)\n{\n\tif (alignment < 128)\n\t\talignment = 128;\n\tsize = (size + 127) & ~127;\n\n\tfor (auto& itr : m_buffers)\n\t{\n\t\t// align pointer\n\t\tuint32 alignmentPadding = (alignment - (itr.writeIndex % alignment)) % alignment;\n\t\tuint32 distanceToSyncPoint;\n\t\tif (!itr.queue_syncPoints.empty())\n\t\t{\n\t\t\tif (itr.queue_syncPoints.front().offset < itr.writeIndex)\n\t\t\t\tdistanceToSyncPoint = 0xFFFFFFFF;\n\t\t\telse\n\t\t\t\tdistanceToSyncPoint = itr.queue_syncPoints.front().offset - itr.writeIndex;\n\t\t}\n\t\telse\n\t\t\tdistanceToSyncPoint = 0xFFFFFFFF;\n\t\tuint32 spaceNeeded = alignmentPadding + size;\n\t\tif (spaceNeeded > distanceToSyncPoint)\n\t\t\tcontinue; // not enough space in current buffer\n\t\tif ((itr.writeIndex + spaceNeeded) > itr.size)\n\t\t{\n\t\t\t// wrap-around\n\t\t\tspaceNeeded = size;\n\t\t\talignmentPadding = 0;\n\t\t\t// check if there is enough space in current buffer after wrap-around\n\t\t\tif (!itr.queue_syncPoints.empty())\n\t\t\t{\n\t\t\t\tdistanceToSyncPoint = itr.queue_syncPoints.front().offset - 0;\n\t\t\t\tif (spaceNeeded > distanceToSyncPoint)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (spaceNeeded > itr.size)\n\t\t\t\tcontinue;\n\t\t\titr.writeIndex = 0;\n\t\t}\n\t\taddUploadBufferSyncPoint(itr, itr.writeIndex);\n\t\titr.writeIndex += alignmentPadding;\n\t\tuint32 offset = itr.writeIndex;\n\t\titr.writeIndex += size;\n\t\titr.cleanupCounter = 0;\n\t\tVKRSynchronizedRingAllocator::AllocatorReservation_t res;\n\t\tres.vkBuffer = itr.vk_buffer;\n\t\tres.vkMem = itr.vk_mem;\n\t\tres.memPtr = itr.basePtr + offset;\n\t\tres.bufferOffset = offset;\n\t\tres.size = size;\n\t\tres.bufferIndex = itr.index;\n\t\treturn res;\n\t}\n\t// allocate new buffer\n\tallocateAdditionalUploadBuffer(size);\n\treturn AllocateBufferMemory(size, alignment);\n}\n\nvoid VKRSynchronizedRingAllocator::FlushReservation(AllocatorReservation_t& uploadReservation)\n{\n\tcemu_assert_debug(m_bufferType == VKR_BUFFER_TYPE::STAGING); // only the staging buffer isn't coherent\n\t// todo - use nonCoherentAtomSize for flush size (instead of hardcoded constant)\n\tVkMappedMemoryRange flushedRange{};\n\tflushedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;\n\tflushedRange.memory = uploadReservation.vkMem;\n\tflushedRange.offset = uploadReservation.bufferOffset;\n\tflushedRange.size = uploadReservation.size;\n\tvkFlushMappedMemoryRanges(m_vkr->GetLogicalDevice(), 1, &flushedRange);\n}\n\nvoid VKRSynchronizedRingAllocator::CleanupBuffer(uint64 latestFinishedCommandBufferId)\n{\n\tif (latestFinishedCommandBufferId > 1)\n\t\tlatestFinishedCommandBufferId -= 1;\n\n\tfor (auto& itr : m_buffers)\n\t{\n\t\twhile (!itr.queue_syncPoints.empty() && latestFinishedCommandBufferId > itr.queue_syncPoints.front().commandBufferId)\n\t\t{\n\t\t\titr.queue_syncPoints.pop();\n\t\t}\n\t\tif (itr.queue_syncPoints.empty())\n\t\t\titr.cleanupCounter++;\n\t}\n\n\t// check if last buffer is available for deletion\n\tif (m_buffers.size() >= 2)\n\t{\n\t\tauto& lastBuffer = m_buffers.back();\n\t\tif (lastBuffer.cleanupCounter >= 1000)\n\t\t{\n\t\t\t// release buffer\n\t\t\tvkUnmapMemory(m_vkr->GetLogicalDevice(), lastBuffer.vk_mem);\n\t\t\tm_vkrMemMgr->DeleteBuffer(lastBuffer.vk_buffer, lastBuffer.vk_mem);\n\t\t\tm_buffers.pop_back();\n\t\t}\n\t}\n}\n\nVkBuffer VKRSynchronizedRingAllocator::GetBufferByIndex(uint32 index) const\n{\n\treturn m_buffers[index].vk_buffer;\n}\n\nvoid VKRSynchronizedRingAllocator::GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const\n{\n\tnumBuffers = (uint32)m_buffers.size();\n\ttotalBufferSize = 0;\n\tfreeBufferSize = 0;\n\tfor (auto& itr : m_buffers)\n\t{\n\t\ttotalBufferSize += itr.size;\n\t\t// calculate free space in buffer\n\t\tuint32 distanceToSyncPoint;\n\t\tif (!itr.queue_syncPoints.empty())\n\t\t{\n\t\t\tif (itr.queue_syncPoints.front().offset < itr.writeIndex)\n\t\t\t\tdistanceToSyncPoint = (itr.size - itr.writeIndex) + itr.queue_syncPoints.front().offset; // size with wrap-around\n\t\t\telse\n\t\t\t\tdistanceToSyncPoint = itr.queue_syncPoints.front().offset - itr.writeIndex;\n\t\t}\n\t\telse\n\t\t\tdistanceToSyncPoint = itr.size;\n\t\tfreeBufferSize += distanceToSyncPoint;\n\t}\n}\n\n/* VKRSynchronizedHeapAllocator */\n\nVKRSynchronizedHeapAllocator::VKRSynchronizedHeapAllocator(class VKRMemoryManager* vkMemoryManager, VKR_BUFFER_TYPE bufferType, size_t minimumBufferAllocSize)\n\t: m_vkrMemMgr(vkMemoryManager), m_chunkedHeap(bufferType, minimumBufferAllocSize) {};\n\nVKRSynchronizedHeapAllocator::AllocatorReservation* VKRSynchronizedHeapAllocator::AllocateBufferMemory(uint32 size, uint32 alignment)\n{\n\tCHAddr addr = m_chunkedHeap.alloc(size, alignment);\n\tm_activeAllocations.emplace_back(addr);\n\tAllocatorReservation* res = m_poolAllocatorReservation.allocObj();\n\tres->bufferIndex = addr.chunkIndex;\n\tres->bufferOffset = addr.offset;\n\tres->size = size;\n\tres->memPtr = m_chunkedHeap.GetChunkPtr(addr.chunkIndex) + addr.offset;\n\tm_chunkedHeap.GetChunkVkMemInfo(addr.chunkIndex, res->vkBuffer, res->vkMem);\n\treturn res;\n}\n\nvoid VKRSynchronizedHeapAllocator::FreeReservation(AllocatorReservation* uploadReservation)\n{\n\t// put the allocation on a delayed release queue for the current command buffer\n\tuint64 currentCommandBufferId = VulkanRenderer::GetInstance()->GetCurrentCommandBufferId();\n\tauto it = std::find_if(m_activeAllocations.begin(), m_activeAllocations.end(), [&uploadReservation](const TrackedAllocation& allocation) { return allocation.allocation.chunkIndex == uploadReservation->bufferIndex && allocation.allocation.offset == uploadReservation->bufferOffset; });\n\tcemu_assert_debug(it != m_activeAllocations.end());\n\tm_releaseQueue[currentCommandBufferId].emplace_back(it->allocation);\n\tm_activeAllocations.erase(it);\n\tm_poolAllocatorReservation.freeObj(uploadReservation);\n}\n\nvoid VKRSynchronizedHeapAllocator::FlushReservation(AllocatorReservation* uploadReservation)\n{\n\tif (m_chunkedHeap.RequiresFlush(uploadReservation->bufferIndex))\n\t{\n\t\tVkMappedMemoryRange flushedRange{};\n\t\tflushedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;\n\t\tflushedRange.memory = uploadReservation->vkMem;\n\t\tflushedRange.offset = uploadReservation->bufferOffset;\n\t\tflushedRange.size = uploadReservation->size;\n\t\tvkFlushMappedMemoryRanges(VulkanRenderer::GetInstance()->GetLogicalDevice(), 1, &flushedRange);\n\t}\n}\n\nvoid VKRSynchronizedHeapAllocator::CleanupBuffer(uint64 latestFinishedCommandBufferId)\n{\n\tauto it = m_releaseQueue.begin();\n\twhile (it != m_releaseQueue.end())\n\t{\n\t\tif (it->first <= latestFinishedCommandBufferId)\n\t\t{\n\t\t\t// release allocations\n\t\t\tfor(auto& addr : it->second)\n\t\t\t\tm_chunkedHeap.free(addr);\n\t\t\tit = m_releaseQueue.erase(it);\n\t\t\tcontinue;\n\t\t}\n\t\tit++;\n\t}\n}\n\nvoid VKRSynchronizedHeapAllocator::GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const\n{\n\tm_chunkedHeap.GetStats(numBuffers, totalBufferSize, freeBufferSize);\n}\n\n/* VkTextureChunkedHeap */\n\nVkTextureChunkedHeap::~VkTextureChunkedHeap()\n{\n\tVkDevice device = VulkanRenderer::GetInstance()->GetLogicalDevice();\n\tfor (auto& i : m_list_chunkInfo)\n\t{\n\t\tvkFreeMemory(device, i.mem, nullptr);\n\t}\n}\n\nuint32 VkTextureChunkedHeap::allocateNewChunk(uint32 chunkIndex, uint32 minimumAllocationSize)\n{\n\tcemu_assert_debug(m_list_chunkInfo.size() == chunkIndex);\n\tm_list_chunkInfo.resize(m_list_chunkInfo.size() + 1);\n\n\t// pad minimumAllocationSize to 32KB alignment\n\tminimumAllocationSize = (minimumAllocationSize + (32 * 1024 - 1)) & ~(32 * 1024 - 1);\n\n\tuint32 allocationSize = 1024 * 1024 * 128;\n\tif (chunkIndex == 0)\n\t{\n\t\t// make the first allocation smaller, this decreases wasted memory when there are textures that require specific flags (and thus separate heaps)\n\t\tallocationSize = 1024 * 1024 * 16;\n\t}\n\tif (allocationSize < minimumAllocationSize)\n\t\tallocationSize = minimumAllocationSize;\n\t// get available memory types/heaps\n\tstd::vector<uint32> deviceLocalMemoryTypeIndices = m_vkrMemoryManager->FindMemoryTypes(m_typeFilter, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);\n\tstd::vector<uint32> hostLocalMemoryTypeIndices = m_vkrMemoryManager->FindMemoryTypes(m_typeFilter, 0);\n\t// remove device local memory types from host local vector\n\tauto pred = [&deviceLocalMemoryTypeIndices](const uint32& v) -> bool {\n\t\treturn std::find(deviceLocalMemoryTypeIndices.begin(), deviceLocalMemoryTypeIndices.end(), v) != deviceLocalMemoryTypeIndices.end();\n\t};\n\thostLocalMemoryTypeIndices.erase(std::remove_if(hostLocalMemoryTypeIndices.begin(), hostLocalMemoryTypeIndices.end(), pred), hostLocalMemoryTypeIndices.end());\n\t// allocate chunk memory\n\tfor (sint32 t = 0; t < 3; t++)\n\t{\n\t\t// attempt to allocate from device local memory first\n\t\tfor (auto memType : deviceLocalMemoryTypeIndices)\n\t\t{\n\t\t\tVkMemoryAllocateInfo allocInfo{};\n\t\t\tallocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n\t\t\tallocInfo.allocationSize = allocationSize;\n\t\t\tallocInfo.memoryTypeIndex = memType;\n\n\t\t\tVkDeviceMemory imageMemory;\n\t\t\tVkResult r = vkAllocateMemory(VulkanRenderer::GetInstance()->GetLogicalDevice(), &allocInfo, nullptr, &imageMemory);\n\t\t\tif (r != VK_SUCCESS)\n\t\t\t\tcontinue;\n\t\t\tm_list_chunkInfo[chunkIndex].mem = imageMemory;\n\t\t\treturn allocationSize;\n\t\t}\n\t\t// attempt to allocate from host-local memory\n\t\tfor (auto memType : hostLocalMemoryTypeIndices)\n\t\t{\n\t\t\tVkMemoryAllocateInfo allocInfo{};\n\t\t\tallocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n\t\t\tallocInfo.allocationSize = allocationSize;\n\t\t\tallocInfo.memoryTypeIndex = memType;\n\n\t\t\tVkDeviceMemory imageMemory;\n\t\t\tVkResult r = vkAllocateMemory(VulkanRenderer::GetInstance()->GetLogicalDevice(), &allocInfo, nullptr, &imageMemory);\n\t\t\tif (r != VK_SUCCESS)\n\t\t\t\tcontinue;\n\t\t\tm_list_chunkInfo[chunkIndex].mem = imageMemory;\n\t\t\treturn allocationSize;\n\t\t}\n\t\t// retry with smaller size if possible\n\t\tallocationSize /= 2;\n\t\tif (allocationSize < minimumAllocationSize)\n\t\t\tbreak;\n\t\tcemuLog_log(LogType::Force, \"Failed to allocate texture memory chunk with size {}MB. Trying again with smaller allocation size\", allocationSize / 1024 / 1024);\n\t}\n\tcemuLog_log(LogType::Force, \"Unable to allocate image memory chunk ({} heaps)\", deviceLocalMemoryTypeIndices.size());\n\tthrow std::runtime_error(\"failed to allocate image memory!\");\n\treturn 0;\n}\n\n/* VkBufferChunkedHeap */\n\nVKRBuffer* VKRBuffer::Create(VKR_BUFFER_TYPE bufferType, size_t bufferSize, VkMemoryPropertyFlags properties)\n{\n\tauto* memMgr = VulkanRenderer::GetInstance()->GetMemoryManager();\n\tVkBuffer buffer;\n\tVkDeviceMemory bufferMemory;\n\tbool allocSuccess;\n\tif (bufferType == VKR_BUFFER_TYPE::STAGING)\n\t\tallocSuccess = memMgr->CreateBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, properties, buffer, bufferMemory);\n\telse if (bufferType == VKR_BUFFER_TYPE::INDEX)\n\t\tallocSuccess = memMgr->CreateBuffer(bufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, properties, buffer, bufferMemory);\n\telse if (bufferType == VKR_BUFFER_TYPE::STRIDE)\n\t\tallocSuccess = memMgr->CreateBuffer(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, properties, buffer, bufferMemory);\n\telse\n\t\tcemu_assert_debug(false);\n\tif (!allocSuccess)\n\t\treturn nullptr;\n\n\tVKRBuffer* bufferObj = new VKRBuffer(buffer, bufferMemory);\n\t// if host visible, then map buffer\n\tvoid* data = nullptr;\n\tif (properties & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)\n\t{\n\t\tvkMapMemory(VulkanRenderer::GetInstance()->GetLogicalDevice(), bufferMemory, 0, bufferSize, 0, &data);\n\t\tbufferObj->m_requiresFlush = !HAS_FLAG(properties, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\t}\n\tbufferObj->m_mappedMemory = (uint8*)data;\n\treturn bufferObj;\n}\n\nVKRBuffer::~VKRBuffer()\n{\n\tif (m_mappedMemory)\n\t\tvkUnmapMemory(VulkanRenderer::GetInstance()->GetLogicalDevice(), m_bufferMemory);\n\tif (m_bufferMemory != VK_NULL_HANDLE)\n\t\tvkFreeMemory(VulkanRenderer::GetInstance()->GetLogicalDevice(), m_bufferMemory, nullptr);\n\tif (m_buffer != VK_NULL_HANDLE)\n\t\tvkDestroyBuffer(VulkanRenderer::GetInstance()->GetLogicalDevice(), m_buffer, nullptr);\n}\n\nVkBufferChunkedHeap::~VkBufferChunkedHeap()\n{\n\tfor (auto& chunk : m_chunkBuffers)\n\t\tdelete chunk;\n}\n\nuint32 VkBufferChunkedHeap::allocateNewChunk(uint32 chunkIndex, uint32 minimumAllocationSize)\n{\n\tsize_t allocationSize = std::max<size_t>(m_minimumBufferAllocationSize, minimumAllocationSize);\n\tVKRBuffer* buffer = VKRBuffer::Create(m_bufferType, allocationSize, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\tif(!buffer)\n\t\tbuffer = VKRBuffer::Create(m_bufferType, allocationSize, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);\n\tif(!buffer)\n\t\tVulkanRenderer::GetInstance()->UnrecoverableError(\"Failed to allocate buffer memory for VkBufferChunkedHeap\");\n\tcemu_assert_debug(buffer);\n\tcemu_assert_debug(m_chunkBuffers.size() == chunkIndex);\n\tm_chunkBuffers.emplace_back(buffer);\n\t// todo - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT might be worth it?\n\treturn allocationSize;\n}\n\nbool VKRMemoryManager::FindMemoryType(uint32 typeFilter, VkMemoryPropertyFlags properties, uint32& memoryIndex) const\n{\n\tVkPhysicalDeviceMemoryProperties memProperties;\n\tvkGetPhysicalDeviceMemoryProperties(m_vkr->GetPhysicalDevice(), &memProperties);\n\n\tfor (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)\n\t{\n\t\tif (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)\n\t\t{\n\t\t\tmemoryIndex = i;\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nstd::vector<uint32> VKRMemoryManager::FindMemoryTypes(uint32_t typeFilter, VkMemoryPropertyFlags properties) const\n{\n\tstd::vector<uint32> memoryTypes;\n\tmemoryTypes.clear();\n\tVkPhysicalDeviceMemoryProperties memProperties;\n\tvkGetPhysicalDeviceMemoryProperties(m_vkr->GetPhysicalDevice(), &memProperties);\n\n\tfor (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)\n\t{\n\t\tif (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)\n\t\t\tmemoryTypes.emplace_back(i);\n\t}\n\n\tif (memoryTypes.empty())\n\t\tm_vkr->UnrecoverableError(fmt::format(\"Failed to find suitable memory type ({0:#08x} {1:#08x})\", typeFilter, properties).c_str());\n\n\treturn memoryTypes;\n}\n\nsize_t VKRMemoryManager::GetTotalMemoryForBufferType(VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, size_t minimumBufferSize)\n{\n\tVkDevice logicalDevice = m_vkr->GetLogicalDevice();\n\t// create temporary buffer object to get memory type\n\tVkBuffer temporaryBuffer;\n\tVkBufferCreateInfo bufferInfo{};\n\tbufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n\tbufferInfo.usage = usage;\n\tbufferInfo.size = minimumBufferSize; // the buffer size can theoretically influence the memory type, is there a better way to handle this?\n\tbufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\tif (vkCreateBuffer(logicalDevice, &bufferInfo, nullptr, &temporaryBuffer) != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Vulkan: GetTotalMemoryForBufferType() failed to create temporary buffer\");\n\t\treturn 0;\n\t}\n\n\t// get memory requirements for buffer\n\tVkMemoryRequirements memRequirements;\n\tvkGetBufferMemoryRequirements(logicalDevice, temporaryBuffer, &memRequirements);\n\tuint32 typeFilter = memRequirements.memoryTypeBits;\n\t// destroy temporary buffer\n\tvkDestroyBuffer(logicalDevice, temporaryBuffer, nullptr);\n\t// get list of all suitable heaps\n\tstd::unordered_set<uint32> list_heapIndices;\n\tVkPhysicalDeviceMemoryProperties memProperties{};\n\tvkGetPhysicalDeviceMemoryProperties(m_vkr->GetPhysicalDevice(), &memProperties);\n\tfor (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)\n\t{\n\t\tif (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)\n\t\t\tlist_heapIndices.emplace(memProperties.memoryTypes[i].heapIndex);\n\t}\n\t// sum up size of heaps\n\tsize_t total = 0;\n\tfor (auto heapIndex : list_heapIndices)\n\t{\n\t\tif (heapIndex > memProperties.memoryHeapCount)\n\t\t\tcontinue;\n\t\ttotal += memProperties.memoryHeaps[heapIndex].size;\n\t}\n\n\treturn total;\n}\n\nbool VKRMemoryManager::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) const\n{\n\tVkBufferCreateInfo bufferInfo{};\n\tbufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n\tbufferInfo.usage = usage;\n\tbufferInfo.size = size;\n\tbufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\tif (vkCreateBuffer(m_vkr->GetLogicalDevice(), &bufferInfo, nullptr, &buffer) != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to create buffer (CreateBuffer)\");\n\t\treturn false;\n\t}\n\n\tVkMemoryRequirements memRequirements;\n\tvkGetBufferMemoryRequirements(m_vkr->GetLogicalDevice(), buffer, &memRequirements);\n\n\tVkMemoryAllocateInfo allocInfo{};\n\tallocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n\tallocInfo.allocationSize = memRequirements.size;\n\tif (!FindMemoryType(memRequirements.memoryTypeBits, properties, allocInfo.memoryTypeIndex))\n\t{\n\t\tvkDestroyBuffer(m_vkr->GetLogicalDevice(), buffer, nullptr);\n\t\treturn false;\n\t}\n\tif (vkAllocateMemory(m_vkr->GetLogicalDevice(), &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS)\n\t{\n\t\tvkDestroyBuffer(m_vkr->GetLogicalDevice(), buffer, nullptr);\n\t\treturn false;\n\t}\n\tif (vkBindBufferMemory(m_vkr->GetLogicalDevice(), buffer, bufferMemory, 0) != VK_SUCCESS)\n\t{\n\t\tvkDestroyBuffer(m_vkr->GetLogicalDevice(), buffer, nullptr);\n\t\tcemuLog_log(LogType::Force, \"Failed to bind buffer (CreateBuffer)\");\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool VKRMemoryManager::CreateBufferFromHostMemory(void* hostPointer, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) const\n{\n\tVkBufferCreateInfo bufferInfo{};\n\tbufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n\tbufferInfo.usage = usage;\n\tbufferInfo.size = size;\n\tbufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n\tVkExternalMemoryBufferCreateInfo emb{};\n\temb.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;\n\temb.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;\n\n\tbufferInfo.pNext = &emb;\n\n\tif (vkCreateBuffer(m_vkr->GetLogicalDevice(), &bufferInfo, nullptr, &buffer) != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to create buffer (CreateBuffer)\");\n\t\treturn false;\n\t}\n\n\tVkMemoryRequirements memRequirements;\n\tvkGetBufferMemoryRequirements(m_vkr->GetLogicalDevice(), buffer, &memRequirements);\n\n\tVkMemoryAllocateInfo allocInfo{};\n\tallocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n\tallocInfo.allocationSize = memRequirements.size;\n\n\tVkImportMemoryHostPointerInfoEXT importHostMem{};\n\timportHostMem.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT;\n\timportHostMem.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT;\n\timportHostMem.pHostPointer = hostPointer;\n\t// VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT or\n\t// VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT\n\t// whats the difference ?\n\n\tallocInfo.pNext = &importHostMem;\n\n\tif (!FindMemoryType(memRequirements.memoryTypeBits, properties, allocInfo.memoryTypeIndex))\n\t{\n\t\tvkDestroyBuffer(m_vkr->GetLogicalDevice(), buffer, nullptr);\n\t\treturn false;\n\t}\n\tif (vkAllocateMemory(m_vkr->GetLogicalDevice(), &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS)\n\t{\n\t\tvkDestroyBuffer(m_vkr->GetLogicalDevice(), buffer, nullptr);\n\t\treturn false;\n\t}\n\tif (vkBindBufferMemory(m_vkr->GetLogicalDevice(), buffer, bufferMemory, 0) != VK_SUCCESS)\n\t{\n\t\tvkDestroyBuffer(m_vkr->GetLogicalDevice(), buffer, nullptr);\n\t\tcemuLog_log(LogType::Force, \"Failed to bind buffer (CreateBufferFromHostMemory)\");\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nvoid VKRMemoryManager::DeleteBuffer(VkBuffer& buffer, VkDeviceMemory& deviceMem) const\n{\n\tif (buffer != VK_NULL_HANDLE)\n\t\tvkDestroyBuffer(m_vkr->GetLogicalDevice(), buffer, nullptr);\n\tif (deviceMem != VK_NULL_HANDLE)\n\t\tvkFreeMemory(m_vkr->GetLogicalDevice(), deviceMem, nullptr);\n\tbuffer = VK_NULL_HANDLE;\n\tdeviceMem = VK_NULL_HANDLE;\n}\n\nVkImageMemAllocation* VKRMemoryManager::imageMemoryAllocate(VkImage image)\n{\n\tVkMemoryRequirements memRequirements;\n\tvkGetImageMemoryRequirements(m_vkr->GetLogicalDevice(), image, &memRequirements);\n\tuint32 typeFilter = memRequirements.memoryTypeBits;\n\n\t// get or create heap for this type filter\n\tVkTextureChunkedHeap* texHeap;\n\tauto it = map_textureHeap.find(typeFilter);\n\tif (it == map_textureHeap.end())\n\t{\n\t\ttexHeap = new VkTextureChunkedHeap(this, typeFilter);\n\t\tmap_textureHeap.emplace(typeFilter, texHeap);\n\t}\n\telse\n\t\ttexHeap = it->second.get();\n\n\t// alloc mem from heap\n\tuint32 allocationSize = (uint32)memRequirements.size;\n\n\tCHAddr mem = texHeap->allocMem(allocationSize, (uint32)memRequirements.alignment);\n\tif (!mem.isValid())\n\t{\n\t\t// allocation failed, try to make space by deleting textures\n\t\t// todo - improve this algorithm\n\t\tstd::vector<LatteTexture*> deleteableTextures = LatteTC_GetDeleteableTextures();\n\t\t// delete up to 20 textures from the deletable textures list, then retry allocation\n\t\twhile (!deleteableTextures.empty())\n\t\t{\n\t\t\tsize_t numDelete = deleteableTextures.size();\n\t\t\tif (numDelete > 20)\n\t\t\t\tnumDelete = 20;\n\t\t\tfor (size_t i = 0; i < numDelete; i++)\n\t\t\t\tLatteTexture_Delete(deleteableTextures[i]);\n\t\t\tdeleteableTextures.erase(deleteableTextures.begin(), deleteableTextures.begin() + numDelete);\n\t\t\tmem = texHeap->allocMem(allocationSize, (uint32)memRequirements.alignment);\n\t\t\tif (mem.isValid())\n\t\t\t\tbreak;\n\t\t}\n\t\tif (!mem.isValid())\n\t\t{\n\t\t\tm_vkr->UnrecoverableError(\"Ran out of VRAM for textures\");\n\t\t}\n\t}\n\n\tvkBindImageMemory(m_vkr->GetLogicalDevice(), image, texHeap->getChunkMem(mem.chunkIndex), mem.offset);\n\n\treturn new VkImageMemAllocation(typeFilter, mem, allocationSize);\n}\n\nvoid VKRMemoryManager::imageMemoryFree(VkImageMemAllocation* imageMemAllocation)\n{\n\tauto heapItr = map_textureHeap.find(imageMemAllocation->typeFilter);\n\tif (heapItr == map_textureHeap.end())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Internal texture heap error\");\n\t\treturn;\n\t}\n\theapItr->second->freeMem(imageMemAllocation->mem);\n\tdelete imageMemAllocation;\n}\n\nvoid VKRMemoryManager::appendOverlayHeapDebugInfo()\n{\n\tfor (auto& itr : map_textureHeap)\n\t{\n\t\tuint32 heapSize;\n\t\tuint32 allocatedBytes;\n\t\titr.second->getStatistics(heapSize, allocatedBytes);\n\n\t\tuint32 heapSizeMB = (heapSize / 1024 / 1024);\n\t\tuint32 allocatedBytesMB = (allocatedBytes / 1024 / 1024);\n\n\t\tImGui::Text(\"%s\", fmt::format(\"{0:#08x} Size: {1}MB/{2}MB\", itr.first, allocatedBytesMB, heapSizeMB).c_str());\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VKRMemoryManager.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"util/ChunkedHeap/ChunkedHeap.h\"\n#include \"util/helpers/MemoryPool.h\"\n\nenum class VKR_BUFFER_TYPE\n{\n\tSTAGING, // staging upload buffer\n\tINDEX, // buffer for index data\n\tSTRIDE, // buffer for stride-adjusted vertex data\n};\n\nclass VKRBuffer\n{\n  public:\n\tstatic VKRBuffer* Create(VKR_BUFFER_TYPE bufferType, size_t bufferSize, VkMemoryPropertyFlags properties);\n\t~VKRBuffer();\n\n\tVkBuffer GetVkBuffer() const { return m_buffer; }\n\tVkDeviceMemory GetVkBufferMemory() const { return m_bufferMemory; }\n\n\tuint8* GetPtr() const { return m_mappedMemory; }\n\n\tbool RequiresFlush() const { return m_requiresFlush; }\n\n  private:\n\tVKRBuffer(VkBuffer buffer, VkDeviceMemory bufferMem) : m_buffer(buffer), m_bufferMemory(bufferMem) { };\n\n\tVkBuffer m_buffer;\n\tVkDeviceMemory m_bufferMemory;\n\tuint8* m_mappedMemory;\n\tbool m_requiresFlush{false};\n};\n\nstruct VkImageMemAllocation\n{\n\tVkImageMemAllocation(uint32 _typeFilter, CHAddr _mem, uint32 _allocationSize) : typeFilter(_typeFilter), mem(_mem), allocationSize(_allocationSize) { };\n\n\tuint32 typeFilter;\n\tCHAddr mem;\n\tuint32 allocationSize;\n\n\tuint32 getAllocationSize() { return allocationSize; }\n};\n\nclass VkTextureChunkedHeap : private ChunkedHeap<>\n{\npublic:\n\tVkTextureChunkedHeap(class VKRMemoryManager* memoryManager, uint32 typeFilter) : m_vkrMemoryManager(memoryManager), m_typeFilter(typeFilter) { };\n\t~VkTextureChunkedHeap();\n\n\tstruct ChunkInfo\n\t{\n\t\tVkDeviceMemory mem;\n\t};\n\n\tCHAddr allocMem(uint32 size, uint32 alignment)\n\t{\n\t\tif (alignment < 4)\n\t\t\talignment = 4;\n\t\tif ((alignment & (alignment - 1)) != 0)\n\t\t{\n\t\t\t// not a power of two\n\t\t\tcemuLog_log(LogType::Force, \"VkTextureChunkedHeap: Invalid alignment {}\", alignment);\n\t\t}\n\t\treturn this->alloc(size, alignment);\n\t}\n\n\tvoid freeMem(CHAddr addr)\n\t{\n\t\tthis->free(addr);\n\t}\n\n\tVkDeviceMemory getChunkMem(uint32 index)\n\t{\n\t\tif (index >= m_list_chunkInfo.size())\n\t\t\treturn VK_NULL_HANDLE;\n\t\treturn m_list_chunkInfo[index].mem;\n\t}\n\n\tvoid getStatistics(uint32& totalHeapSize, uint32& allocatedBytes) const\n\t{\n\t\ttotalHeapSize = m_numHeapBytes;\n\t\tallocatedBytes = m_numAllocatedBytes;\n\t}\n\n  private:\n\tuint32 allocateNewChunk(uint32 chunkIndex, uint32 minimumAllocationSize) override;\n\n\tuint32 m_typeFilter{ 0xFFFFFFFF };\n\tclass VKRMemoryManager* m_vkrMemoryManager;\n\tstd::vector<ChunkInfo> m_list_chunkInfo;\n};\n\nclass VkBufferChunkedHeap : private ChunkedHeap<>\n{\n  public:\n\tVkBufferChunkedHeap(VKR_BUFFER_TYPE bufferType, size_t minimumBufferAllocationSize) : m_bufferType(bufferType), m_minimumBufferAllocationSize(minimumBufferAllocationSize) { };\n\t~VkBufferChunkedHeap();\n\n\tusing ChunkedHeap::alloc;\n\tusing ChunkedHeap::free;\n\n\tuint8* GetChunkPtr(uint32 index) const\n\t{\n\t\tif (index >= m_chunkBuffers.size())\n\t\t\treturn nullptr;\n\t\treturn m_chunkBuffers[index]->GetPtr();\n\t}\n\n\tvoid GetChunkVkMemInfo(uint32 index, VkBuffer& buffer, VkDeviceMemory& mem)\n\t{\n\t\tif (index >= m_chunkBuffers.size())\n\t\t{\n\t\t\tbuffer = VK_NULL_HANDLE;\n\t\t\tmem = VK_NULL_HANDLE;\n\t\t\treturn;\n\t\t}\n\t\tbuffer = m_chunkBuffers[index]->GetVkBuffer();\n\t\tmem = m_chunkBuffers[index]->GetVkBufferMemory();\n\t}\n\n\tvoid GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const\n\t{\n\t\tnumBuffers = m_chunkBuffers.size();\n\t\ttotalBufferSize = m_numHeapBytes;\n\t\tfreeBufferSize = m_numHeapBytes - m_numAllocatedBytes;\n\t}\n\n\tbool RequiresFlush(uint32 index) const\n\t{\n\t\tif (index >= m_chunkBuffers.size())\n\t\t\treturn false;\n\t\treturn m_chunkBuffers[index]->RequiresFlush();\n\t}\n\n  private:\n\tuint32 allocateNewChunk(uint32 chunkIndex, uint32 minimumAllocationSize) override;\n\n\tVKR_BUFFER_TYPE m_bufferType;\n\tstd::vector<VKRBuffer*> m_chunkBuffers;\n\tsize_t m_minimumBufferAllocationSize;\n};\n\n// a circular ring-buffer which tracks and releases memory per command-buffer\nclass VKRSynchronizedRingAllocator\n{\npublic:\n\tVKRSynchronizedRingAllocator(class VulkanRenderer* vkRenderer, class VKRMemoryManager* vkMemoryManager, VKR_BUFFER_TYPE bufferType, uint32 minimumBufferAllocSize) : m_vkr(vkRenderer), m_vkrMemMgr(vkMemoryManager), m_bufferType(bufferType), m_minimumBufferAllocSize(minimumBufferAllocSize) {};\n\tVKRSynchronizedRingAllocator(const VKRSynchronizedRingAllocator&) = delete; // disallow copy\n\t~VKRSynchronizedRingAllocator();\n\n\tstruct BufferSyncPoint_t\n\t{\n\t\t// todo - modularize sync point\n\t\tuint64 commandBufferId;\n\t\tuint32 offset;\n\n\t\tBufferSyncPoint_t(uint64 _commandBufferId, uint32 _offset) : commandBufferId(_commandBufferId), offset(_offset) {};\n\t};\n\n\tstruct AllocatorBuffer_t\n\t{\n\t\tVkBuffer vk_buffer;\n\t\tVkDeviceMemory vk_mem;\n\t\tuint8* basePtr;\n\t\tuint32 size;\n\t\tuint32 writeIndex;\n\t\tstd::queue<BufferSyncPoint_t> queue_syncPoints;\n\t\tuint64 lastSyncpointCmdBufferId{ 0xFFFFFFFFFFFFFFFFull };\n\t\tuint32 index;\n\t\tuint32 cleanupCounter{ 0 }; // increased by one every time CleanupBuffer() is called if there is no sync point. If it reaches 300 then the buffer is released\n\t};\n\n\tstruct AllocatorReservation_t\n\t{\n\t\tVkBuffer vkBuffer;\n\t\tVkDeviceMemory vkMem;\n\t\tuint8* memPtr;\n\t\tuint32 bufferOffset;\n\t\tuint32 size;\n\t\tuint32 bufferIndex;\n\t};\n\n\tAllocatorReservation_t AllocateBufferMemory(uint32 size, uint32 alignment);\n\tvoid FlushReservation(AllocatorReservation_t& uploadReservation);\n\tvoid CleanupBuffer(uint64 latestFinishedCommandBufferId);\n\tVkBuffer GetBufferByIndex(uint32 index) const;\n\n\tvoid GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const;\n\nprivate:\n\tvoid allocateAdditionalUploadBuffer(uint32 sizeRequiredForAlloc);\n\tvoid addUploadBufferSyncPoint(AllocatorBuffer_t& buffer, uint32 offset);\n\n\tconst class VulkanRenderer* m_vkr;\n\tconst class VKRMemoryManager* m_vkrMemMgr;\n\tconst VKR_BUFFER_TYPE m_bufferType;\n\tconst uint32 m_minimumBufferAllocSize;\n\n\tstd::vector<AllocatorBuffer_t> m_buffers;\n\n};\n\n// heap style allocator with released memory being freed after the current command buffer finishes\nclass VKRSynchronizedHeapAllocator\n{\n\tstruct TrackedAllocation\n\t{\n\t\tTrackedAllocation(CHAddr allocation) : allocation(allocation) {};\n\t\tCHAddr allocation;\n\t};\n\n  public:\n\tVKRSynchronizedHeapAllocator(class VKRMemoryManager* vkMemoryManager, VKR_BUFFER_TYPE bufferType, size_t minimumBufferAllocSize);\n\tVKRSynchronizedHeapAllocator(const VKRSynchronizedHeapAllocator&) = delete; // disallow copy\n\n\tstruct AllocatorReservation\n\t{\n\t\tVkBuffer vkBuffer;\n\t\tVkDeviceMemory vkMem;\n\t\tuint8* memPtr;\n\t\tuint32 bufferOffset;\n\t\tuint32 size;\n\t\tuint32 bufferIndex;\n\t};\n\n\tAllocatorReservation* AllocateBufferMemory(uint32 size, uint32 alignment);\n\tvoid FreeReservation(AllocatorReservation* uploadReservation);\n\tvoid FlushReservation(AllocatorReservation* uploadReservation);\n\n\tvoid CleanupBuffer(uint64 latestFinishedCommandBufferId);\n\n\tvoid GetStats(uint32& numBuffers, size_t& totalBufferSize, size_t& freeBufferSize) const;\n  private:\n\tconst class VKRMemoryManager* m_vkrMemMgr;\n\tVkBufferChunkedHeap m_chunkedHeap;\n\t// allocations\n\tstd::vector<TrackedAllocation> m_activeAllocations;\n\tMemoryPool<AllocatorReservation> m_poolAllocatorReservation{32};\n\t// release queue\n\tstd::unordered_map<uint64, std::vector<CHAddr>> m_releaseQueue;\n};\n\nvoid LatteIndices_invalidateAll();\n\nclass VKRMemoryManager\n{\n\tfriend class VKRSynchronizedRingAllocator;\npublic:\n\tVKRMemoryManager(class VulkanRenderer* renderer) :\n\t\t\tm_stagingBuffer(renderer, this, VKR_BUFFER_TYPE::STAGING, 32u * 1024 * 1024),\n\t\t\tm_indexBuffer(this, VKR_BUFFER_TYPE::INDEX, 4u * 1024 * 1024),\n\t\t\tm_vertexStrideMetalBuffer(renderer, this, VKR_BUFFER_TYPE::STRIDE, 4u * 1024 * 1024)\n\t{\n\t\tm_vkr = renderer;\n\t}\n\n\t// texture memory management\n\tstd::unordered_map<uint32, std::unique_ptr<VkTextureChunkedHeap>> map_textureHeap; // one heap per memory type\n\tstd::vector<uint8> m_textureUploadBuffer;\n\n\t// texture upload buffer\n\tvoid* TextureUploadBufferAcquire(uint32 size)\n\t{\n\t\tif (m_textureUploadBuffer.size() < size)\n\t\t\tm_textureUploadBuffer.resize(size);\n\n\t\treturn m_textureUploadBuffer.data();\n\t}\n\n\tvoid TextureUploadBufferRelease(uint8* mem)\n\t{\n\t\tcemu_assert_debug(m_textureUploadBuffer.data() == mem);\n\t\tm_textureUploadBuffer.clear();\n\t}\n\n\tVKRSynchronizedRingAllocator& getStagingAllocator() { return m_stagingBuffer; }; // allocator for texture/attribute/uniform uploads\n\tVKRSynchronizedHeapAllocator& GetIndexAllocator() { return m_indexBuffer; }; // allocator for index data\n\tVKRSynchronizedRingAllocator& getMetalStrideWorkaroundAllocator() { return m_vertexStrideMetalBuffer; }; // allocator for stride-adjusted vertex data\n\n\tvoid cleanupBuffers(uint64 latestFinishedCommandBufferId)\n\t{\n\t\tLatteIndices_invalidateAll();\n\t\tm_stagingBuffer.CleanupBuffer(latestFinishedCommandBufferId);\n\t\tm_indexBuffer.CleanupBuffer(latestFinishedCommandBufferId);\n\t\tm_vertexStrideMetalBuffer.CleanupBuffer(latestFinishedCommandBufferId);\n\t}\n\n\tbool FindMemoryType(uint32 typeFilter, VkMemoryPropertyFlags properties, uint32& memoryIndex) const; // searches for exact properties. Can gracefully fail without throwing exception (returns false)\n\tstd::vector<uint32> FindMemoryTypes(uint32_t typeFilter, VkMemoryPropertyFlags properties) const;\n\n\t// image memory allocation\n\tvoid imageMemoryFree(VkImageMemAllocation* imageMemAllocation);\n\tVkImageMemAllocation* imageMemoryAllocate(VkImage image);\n\n\t// buffer management\n\tsize_t GetTotalMemoryForBufferType(VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, size_t minimumBufferSize = 16 * 1024 * 1024);\n\n\tbool CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) const; // same as CreateBuffer but doesn't throw exception on failure\n\tbool CreateBufferFromHostMemory(void* hostPointer, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) const;\n\n\tvoid DeleteBuffer(VkBuffer& buffer, VkDeviceMemory& deviceMem) const;\n\n\t// overlay info\n\tvoid appendOverlayHeapDebugInfo();\n\n\tprivate:\n\t\tclass VulkanRenderer* m_vkr;\n\t\tVKRSynchronizedRingAllocator m_stagingBuffer;\n\t\tVKRSynchronizedHeapAllocator m_indexBuffer;\n\t\tVKRSynchronizedRingAllocator m_vertexStrideMetalBuffer;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VKRPipelineInfo.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h\"\n\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n\n#include \"imgui/imgui_impl_vulkan.h\"\n#include \"imgui/imgui_extension.h\"\n#include \"config/CemuConfig.h\"\n\nPipelineInfo::PipelineInfo(uint64 minimalStateHash, uint64 pipelineHash, LatteFetchShader* fetchShader, LatteDecompilerShader* vertexShader, LatteDecompilerShader* pixelShader, LatteDecompilerShader* geometryShader)\n{\n\tthis->minimalStateHash = minimalStateHash;\n\tthis->stateHash = pipelineHash;\n\n\tthis->fetchShader = fetchShader;\n\tthis->vertexShader = vertexShader;\n\tthis->geometryShader = geometryShader;\n\tthis->pixelShader = pixelShader;\n\n\tthis->vertexShaderVk = vertexShader ? (RendererShaderVk*)vertexShader->shader : nullptr;\n\tthis->geometryShaderVk = geometryShader ? (RendererShaderVk*)geometryShader->shader : nullptr;\n\tthis->pixelShaderVk = pixelShader ? (RendererShaderVk*)pixelShader->shader : nullptr;\n\n\t// init VKRObjPipeline\n\tm_vkrObjPipeline = new VKRObjectPipeline();\n\n\t// track dependency with shaders\n\tif (vertexShaderVk)\n\t\tvertexShaderVk->TrackDependency(this);\n\tif (geometryShaderVk)\n\t\tgeometryShaderVk->TrackDependency(this);\n\tif (pixelShaderVk)\n\t\tpixelShaderVk->TrackDependency(this);\n\n\t// \"Accurate barriers\" is usually enabled globally but since the CPU cost is substantial we allow users to disable it (debug -> 'Accurate barriers' option)\n\t// We always force accurate barriers for known problematic shaders\n\tif (pixelShader)\n\t{\n\t\tif (pixelShader->baseHash == 0x6f6f6e7b9aae57af && pixelShader->auxHash == 0x00078787f9249249) // BotW lava\n\t\t\tneverSkipAccurateBarrier = true;\n\t\tif (pixelShader->baseHash == 0x4c0bd596e3aef4a6 && pixelShader->auxHash == 0x003c3c3fc9269249) // BotW foam layer for water on the bottom of waterfalls\n\t\t\tneverSkipAccurateBarrier = true;\n\t\tif (pixelShader->baseHash == 0x3a7e6b48dae31305 && pixelShader->auxHash == 0x003c3c3fc9269249) // BotW Gerudo Town water\n\t\t\tneverSkipAccurateBarrier = true;\n\t}\n}\n\n\nPipelineInfo::~PipelineInfo()\n{\n\tif (rectEmulationGS)\n\t{\n\t\tdelete rectEmulationGS;\n\t\trectEmulationGS = nullptr;\n\t}\n\n\t// delete descriptor sets\n\twhile (!pixel_ds_cache.empty())\n\t{\n\t\tVkDescriptorSetInfo* dsInfo = pixel_ds_cache.begin()->second;\n\t\tdelete dsInfo;\n\t}\n\twhile (!geometry_ds_cache.empty())\n\t{\n\t\tVkDescriptorSetInfo* dsInfo = geometry_ds_cache.begin()->second;\n\t\tdelete dsInfo;\n\t}\n\twhile (!vertex_ds_cache.empty())\n\t{\n\t\tVkDescriptorSetInfo* dsInfo = vertex_ds_cache.begin()->second;\n\t\tdelete dsInfo;\n\t}\n\n\t// disassociate from shaders\n\tif (vertexShaderVk)\n\t\tvertexShaderVk->RemoveDependency(this);\n\tif (geometryShaderVk)\n\t\tgeometryShaderVk->RemoveDependency(this);\n\tif (pixelShaderVk)\n\t\tpixelShaderVk->RemoveDependency(this);\n\n\t// queue pipeline for destruction\n\tif (m_vkrObjPipeline)\n\t{\n\t\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(m_vkrObjPipeline);\n\t\tm_vkrObjPipeline = nullptr;\n\t}\n\n\t// remove from cache\n\tVulkanRenderer::GetInstance()->unregisterGraphicsPipeline(this);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.cpp",
    "content": "#if BOOST_OS_WINDOWS\n\n#include <Windows.h>\n\n#include \"WindowSystem.h\"\n\ntypedef LONG NTSTATUS;\n\ntypedef UINT32 D3DKMT_HANDLE;\ntypedef UINT D3DDDI_VIDEO_PRESENT_SOURCE_ID;\n\ntypedef struct _D3DKMT_OPENADAPTERFROMHDC\n{\n\tHDC                            hDc;\n\tD3DKMT_HANDLE                  hAdapter;\n\tLUID                           AdapterLuid;\n\tD3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;\n}D3DKMT_OPENADAPTERFROMHDC;\n\ntypedef struct _D3DKMT_WAITFORVERTICALBLANKEVENT {\n\tD3DKMT_HANDLE                  hAdapter;\n\tD3DKMT_HANDLE                  hDevice;\n\tD3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId;\n} D3DKMT_WAITFORVERTICALBLANKEVENT;\n\nclass DeviceVsyncHandler\n{\npublic:\n\tDeviceVsyncHandler(void(*cbVSync)()) : m_vsyncDriverVSyncCb(cbVSync)\n\t{\n\t\tm_shutdownThread = false;\n\t\tif (!pfnD3DKMTOpenAdapterFromHdc)\n\t\t{\n\t\t\tHMODULE hModuleGDI = LoadLibraryA(\"gdi32.dll\");\n\t\t\t*(void**)&pfnD3DKMTOpenAdapterFromHdc = GetProcAddress(hModuleGDI, \"D3DKMTOpenAdapterFromHdc\");\n\t\t\t*(void**)&pfnD3DKMTWaitForVerticalBlankEvent = GetProcAddress(hModuleGDI, \"D3DKMTWaitForVerticalBlankEvent\");\n\t\t}\n\t\tm_thd = std::thread(&DeviceVsyncHandler::vsyncThread, this);\n\t}\n\n\t~DeviceVsyncHandler()\n\t{\n\t\tm_shutdownThread = true;\n\t\tcemu_assert_debug(m_thd.joinable());\n\t\tm_thd.join();\n\t}\n\n\tvoid notifyWindowPosChanged()\n\t{\n\t\tm_checkMonitorChange = true;\n\t}\n\nprivate:\n\tbool HasMonitorChanged()\n\t{\n\t\tHWND hWnd = (HWND)WindowSystem::GetWindowInfo().canvas_main.surface;\n\t\tif (hWnd == 0)\n\t\t\treturn true;\n\t\tHMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);\n\n\t\tMONITORINFOEXW monitorInfo{};\n\t\tmonitorInfo.cbSize = sizeof(monitorInfo);\n\t\tif (GetMonitorInfoW(hMonitor, &monitorInfo) == 0)\n\t\t\treturn true;\n\n\t\tif (wcscmp(monitorInfo.szDevice, m_activeMonitorDevice) == 0)\n\t\t\treturn false;\n\t\t\n\t\treturn true;\n\t}\n\n\tHRESULT GetAdapterHandleFromHwnd(D3DKMT_HANDLE* phAdapter, UINT* pOutput)\n\t{\n\t\tHWND hWnd = (HWND)WindowSystem::GetWindowInfo().canvas_main.surface;\n\t\tif (hWnd == 0)\n\t\t\treturn E_FAIL;\n\n\t\twcsncpy(m_activeMonitorDevice, L\"\", 32); // reset remembered monitor device\n\t\tm_checkMonitorChange = false;\n\n\t\tD3DKMT_OPENADAPTERFROMHDC OpenAdapterData;\n\n\t\t*phAdapter = 0;\n\t\t*pOutput = 0;\n\n\t\tHMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);\n\n\t\tMONITORINFOEXW monitorInfo{};\n\t\tmonitorInfo.cbSize = sizeof(monitorInfo);\n\t\tif (GetMonitorInfoW(hMonitor, &monitorInfo) == 0)\n\t\t\treturn E_FAIL;\n\n\n\t\tHDC hdc = CreateDCW(NULL, monitorInfo.szDevice, NULL, NULL);\n\t\tif (hdc == NULL) {\n\t\t\treturn E_FAIL;\n\t\t}\n\n\t\tOpenAdapterData.hDc = hdc;\n\t\tif (pfnD3DKMTOpenAdapterFromHdc(&OpenAdapterData) == 0)\n\t\t{\n\t\t\tDeleteDC(hdc);\n\t\t\t*phAdapter = OpenAdapterData.hAdapter;\n\t\t\t*pOutput = OpenAdapterData.VidPnSourceId;\n\t\t\t// remember monitor device\n\t\t\twcsncpy(m_activeMonitorDevice, monitorInfo.szDevice, 32);\n\t\t\treturn S_OK;\n\t\t}\n\t\tDeleteDC(hdc);\n\n\t\treturn E_FAIL;\n\t}\n\n\tvoid vsyncThread()\n\t{\n\t\tD3DKMT_HANDLE hAdapter;\n\t\tUINT hOutput;\n\t\tGetAdapterHandleFromHwnd(&hAdapter, &hOutput);\n\n\t\tint failCount = 0;\n\t\twhile (!m_shutdownThread)\n\t\t{\n\t\t\tD3DKMT_WAITFORVERTICALBLANKEVENT arg;\n\t\t\targ.hDevice = 0;\n\t\t\targ.hAdapter = hAdapter;\n\t\t\targ.VidPnSourceId = hOutput;\n\t\t\tNTSTATUS r = pfnD3DKMTWaitForVerticalBlankEvent(&arg);\n\t\t\tif (r != 0)\n\t\t\t{\n\t\t\t\t//cemuLog_log(LogType::Force, \"Wait for VerticalBlank failed\");\n\t\t\t\tSleep(1000 / 60);\n\t\t\t\tfailCount++;\n\t\t\t\tif (failCount >= 10)\n\t\t\t\t{\n\t\t\t\t\twhile (GetAdapterHandleFromHwnd(&hAdapter, &hOutput) != S_OK)\n\t\t\t\t\t{\n\t\t\t\t\t\tSleep(1000 / 60);\n\t\t\t\t\t\tif (m_shutdownThread)\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tfailCount = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tsignalVsync();\n\t\t\tif (m_checkMonitorChange)\n\t\t\t{\n\t\t\t\tm_checkMonitorChange = false;\n\t\t\t\tif (HasMonitorChanged())\n\t\t\t\t{\n\t\t\t\t\twhile (GetAdapterHandleFromHwnd(&hAdapter, &hOutput) != S_OK)\n\t\t\t\t\t{\n\t\t\t\t\t\tSleep(1000 / 60);\n\t\t\t\t\t\tif (m_shutdownThread)\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid signalVsync()\n\t{\n\t\tif(m_vsyncDriverVSyncCb)\n\t\t\tm_vsyncDriverVSyncCb();\n\t}\n\n\tvoid setCallback(void(*cbVSync)())\n\t{\n\t\tm_vsyncDriverVSyncCb = cbVSync;\n\t}\n\nprivate:\n\tNTSTATUS(__stdcall* pfnD3DKMTOpenAdapterFromHdc)(D3DKMT_OPENADAPTERFROMHDC* Arg1) = nullptr;\n\tNTSTATUS(__stdcall* pfnD3DKMTWaitForVerticalBlankEvent)(const D3DKMT_WAITFORVERTICALBLANKEVENT* Arg1) = nullptr;\n\n\tstd::thread m_thd;\n\tbool m_shutdownThread;\n\tbool m_checkMonitorChange{};\n\tWCHAR m_activeMonitorDevice[32];\n\n\tvoid (*m_vsyncDriverVSyncCb)() = nullptr;\n};\n\nDeviceVsyncHandler* s_vsyncDriver = nullptr;\n\nstd::mutex s_driverAccess;\n\nvoid VsyncDriver_startThread(void(*cbVSync)())\n{\n\tstd::unique_lock<std::mutex> ul(s_driverAccess);\n\tif (!s_vsyncDriver)\n\t\ts_vsyncDriver = new DeviceVsyncHandler(cbVSync);\n}\n\nvoid VsyncDriver_notifyWindowPosChanged()\n{\n\tstd::unique_lock<std::mutex> ul(s_driverAccess);\n\tif (s_vsyncDriver)\n\t\ts_vsyncDriver->notifyWindowPosChanged();\n}\n\n#else\n\nvoid VsyncDriver_startThread(void(*cbVSync)())\n{\n\tcemu_assert_unimplemented();\n}\n\nvoid VsyncDriver_notifyWindowPosChanged()\n{\n\n}\n\n#endif\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.h",
    "content": "#pragma once\n\nvoid VsyncDriver_startThread(void(*cbVSync)());\nvoid VsyncDriver_notifyWindowPosChanged();"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#define VKFUNC_DEFINE\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include <numeric> // for std::iota\n\n#if BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_BSD\n#include <dlfcn.h>\n#endif\n\n#define VULKAN_API_CPU_BENCHMARK 0\t// if 1, Cemu will log the CPU time spent per Vulkan API function\n\nbool g_vulkan_available = false;\n\n#if VULKAN_API_CPU_BENCHMARK != 0\nuint64 s_vulkanBenchmarkLastResultsTime = 0;\n\nstruct VulkanBenchmarkFuncInfo\n{\n\tstd::string funcName;\n\tuint64 cycles;\n\tuint32 numCalls;\n};\n\nstd::vector<VulkanBenchmarkFuncInfo*> s_vulkanBenchmarkFuncs;\n\ntemplate<typename TRet, typename... Args>\nauto VkWrapperFuncGenTest(TRet (*func)(Args...), const char* name)\n{\n\tstatic VulkanBenchmarkFuncInfo _FuncInfo;\n\tstatic auto _FuncPtrCopy = func;\n\tTRet (*newFunc)(Args...);\n\tif constexpr(std::is_void_v<TRet>)\n\t{\n\t\tnewFunc = +[](Args... args) { uint64 t = __rdtsc(); _mm_mfence(); _FuncPtrCopy(args...); _mm_mfence(); _FuncInfo.cycles += (__rdtsc() - t); _FuncInfo.numCalls++; };\n\t}\n\telse\n\t\tnewFunc = +[](Args... args) -> TRet { uint64 t = __rdtsc(); _mm_mfence(); TRet r = _FuncPtrCopy(args...); _mm_mfence(); _FuncInfo.cycles += (__rdtsc() - t); _FuncInfo.numCalls++; return r; };\n\tif(func && func != newFunc)\n\t\t_FuncPtrCopy = func;\n\tif(_FuncInfo.funcName.empty())\n\t{\n\t\t_FuncInfo = {.funcName = name, .cycles = 0, .numCalls = 0};\n\t\ts_vulkanBenchmarkFuncs.emplace_back(&_FuncInfo);\n\t}\n\treturn newFunc;\n};\n#endif\n\n// called when a TV SwapBuffers is called\nvoid VulkanBenchmarkPrintResults()\n{\n#if VULKAN_API_CPU_BENCHMARK != 0\n\t// note: This could be done by hooking vk present functions\n\tuint64 currentCycle = __rdtsc();\n\tuint64 elapsedCycles = currentCycle - s_vulkanBenchmarkLastResultsTime;\n\ts_vulkanBenchmarkLastResultsTime = currentCycle;\n\tdouble elapsedCyclesDbl = (double)elapsedCycles;\n\tcemuLog_log(LogType::Force, \"--- Vulkan API CPU benchmark ---\");\n\tcemuLog_log(LogType::Force, \"Elapsed cycles this frame: {:} | Current cycle {:} | NumFunc {:}\", elapsedCycles, currentCycle, s_vulkanBenchmarkFuncs.size());\n\n\tstd::vector<sint32> sortedIndices(s_vulkanBenchmarkFuncs.size());\n\tstd::iota(sortedIndices.begin(), sortedIndices.end(), 0);\n\tstd::sort(sortedIndices.begin(), sortedIndices.end(),\n\t\t\t  [](int32_t a, int32_t b) {\n\t\t\t\t  return s_vulkanBenchmarkFuncs[a]->cycles > s_vulkanBenchmarkFuncs[b]->cycles;\n\t\t\t  });\n\tfor (sint32 idx : sortedIndices)\n\t{\n\t\tauto& func = s_vulkanBenchmarkFuncs[idx];\n\t\tif(func->cycles == 0)\n\t\t\treturn;\n\t\tcemuLog_log(LogType::Force, \"{}: {} cycles ({:.4}%) {} calls\", func->funcName.c_str(), func->cycles, ((double)func->cycles / elapsedCyclesDbl) * 100.0, func->numCalls);\n\t\tfunc->cycles = 0;\n\t\tfunc->numCalls = 0;\n\t}\n#endif\n}\n\n#if BOOST_OS_WINDOWS\n\nbool InitializeGlobalVulkan()\n{\n\tconst auto hmodule = LoadLibraryA(\"vulkan-1.dll\");\n\n\tif(g_vulkan_available)\n\t\treturn true;\n\n\tif (hmodule == nullptr)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Vulkan loader not available. Outdated graphics driver or Vulkan runtime not installed?\");\n\t\treturn false;\n\t}\n\n\t#define VKFUNC_INIT\n\t#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n\n\tif(!vkEnumerateInstanceVersion)\n\t{\n\t\tcemuLog_log(LogType::Force, \"vkEnumerateInstanceVersion not available. Outdated graphics driver or Vulkan runtime?\");\n\t\tFreeLibrary(hmodule);\n\t\treturn false;\n\t}\n\t\n\tg_vulkan_available = true;\n\treturn true;\n}\n\nbool InitializeInstanceVulkan(VkInstance instance)\n{\n\tconst auto hmodule = GetModuleHandleA(\"vulkan-1.dll\");\n\tif (hmodule == nullptr)\n\t\treturn false;\n\n\t#define VKFUNC_INSTANCE_INIT\n\t#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n\t\n\treturn true;\n}\n\nbool InitializeDeviceVulkan(VkDevice device)\n{\n\tconst auto hmodule = GetModuleHandleA(\"vulkan-1.dll\");\n\tif (hmodule == nullptr)\n\t\treturn false;\n\n\t#define VKFUNC_DEVICE_INIT\n\t#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n\n#if VULKAN_API_CPU_BENCHMARK != 0\n\t#define VKFUNC_DEFINE_CUSTOM(__func) __func = VkWrapperFuncGenTest(__func, #__func)\n\t#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#endif\n\n\treturn true;\n}\n\n#else\n\nvoid* dlopen_vulkan_loader()\n{\n#if BOOST_OS_LINUX || BOOST_OS_BSD\n\tvoid* vulkan_so = dlopen(\"libvulkan.so\", RTLD_NOW);\n\tif(!vulkan_so)\n\t\tvulkan_so = dlopen(\"libvulkan.so.1\", RTLD_NOW);\n#elif BOOST_OS_MACOS\n\tvoid* vulkan_so = dlopen(\"libMoltenVK.dylib\", RTLD_NOW);\n#endif\n\treturn vulkan_so;\n}\n\nbool InitializeGlobalVulkan()\n{\n\tvoid* vulkan_so = dlopen_vulkan_loader();\n\n\tif(g_vulkan_available)\n\t\treturn true;\n\n\tif (!vulkan_so)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Vulkan loader not available.\");\n\t\treturn false;\n\t}\n\n\t#define VKFUNC_INIT\n\t#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n\n\tif(!vkEnumerateInstanceVersion)\n\t{\n\t\tcemuLog_log(LogType::Force, \"vkEnumerateInstanceVersion not available. Outdated graphics driver or Vulkan runtime?\");\n\t\treturn false;\n\t}\n\t\n\tg_vulkan_available = true;\n\treturn true;\n}\n\nbool InitializeInstanceVulkan(VkInstance instance)\n{\n\tvoid* vulkan_so = dlopen_vulkan_loader();\n\tif (!vulkan_so)\n\t\treturn false;\n\n\t#define VKFUNC_INSTANCE_INIT\n\t#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n\t\n\treturn true;\n}\n\nbool InitializeDeviceVulkan(VkDevice device)\n{\n\tvoid* vulkan_so = dlopen_vulkan_loader();\n\tif (!vulkan_so)\n\t\treturn false;\n\n\t#define VKFUNC_DEVICE_INIT\n\t#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n\n#if VULKAN_API_CPU_BENCHMARK != 0\n\t#define VKFUNC_DEFINE_CUSTOM(__func) __func = VkWrapperFuncGenTest(__func, #__func)\n\t#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#endif\n\n\treturn true;\n}\n\n#endif\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h",
    "content": "#ifndef _VULKAN_API_\n#define _VULKAN_API_\n\n#if BOOST_OS_WINDOWS\n#define VK_USE_PLATFORM_WIN32_KHR // todo - define in CMakeLists.txt\n#endif\n\n#include <vulkan/vulkan.h>\n\nbool InitializeGlobalVulkan();\nbool InitializeInstanceVulkan(VkInstance instance);\nbool InitializeDeviceVulkan(VkDevice device);\nextern bool g_vulkan_available;\n\n#endif\n\n#ifdef VKFUNC_DEFINE_CUSTOM\n\t#define VKFUNC(__FUNC__) VKFUNC_DEFINE_CUSTOM(__FUNC__)\n\t#define VKFUNC_INSTANCE(__FUNC__) VKFUNC_DEFINE_CUSTOM(__FUNC__)\n\t#define VKFUNC_DEVICE(__FUNC__) VKFUNC_DEFINE_CUSTOM(__FUNC__)\n#elif defined(VKFUNC_DEFINE)\n\t#define VKFUNC(__FUNC__) NOEXPORT PFN_##__FUNC__ __FUNC__ = nullptr\n\t#define VKFUNC_INSTANCE(__FUNC__) NOEXPORT PFN_##__FUNC__ __FUNC__ = nullptr\n\t#define VKFUNC_DEVICE(__FUNC__) NOEXPORT PFN_##__FUNC__ __FUNC__ = nullptr\n#else\n\t#if defined(VKFUNC_INIT)\n\t\t#if BOOST_OS_WINDOWS\n\t\t#define VKFUNC(__FUNC__) __FUNC__ = (PFN_##__FUNC__)GetProcAddress(hmodule, #__FUNC__)\n\t\t#else\n\t\t#define VKFUNC(__FUNC__) __FUNC__ = (PFN_##__FUNC__)dlsym(vulkan_so, #__FUNC__)\n\t\t#endif\n\t\t#define VKFUNC_INSTANCE(__FUNC__)\n\t\t#define VKFUNC_DEVICE(__FUNC__)\n\t#elif defined(VKFUNC_INSTANCE_INIT)\n\t\t#define VKFUNC(__FUNC__) \n\t\t#define VKFUNC_INSTANCE(__FUNC__) __FUNC__ = (PFN_##__FUNC__)vkGetInstanceProcAddr(instance, #__FUNC__)\n\t\t#define VKFUNC_DEVICE(__FUNC__)\n\t#elif defined(VKFUNC_DEVICE_INIT)\n\t\t#define VKFUNC(__FUNC__) \n\t\t#define VKFUNC_INSTANCE(__FUNC__)\n\t\t#define VKFUNC_DEVICE(__FUNC__) __FUNC__ = (PFN_##__FUNC__)vkGetDeviceProcAddr(device, #__FUNC__)\n\t#else\n\t\t#define VKFUNC(__FUNC__) extern PFN_##__FUNC__ __FUNC__\n\t\t#define VKFUNC_INSTANCE(__FUNC__) extern PFN_##__FUNC__ __FUNC__\n\t\t#define VKFUNC_DEVICE(__FUNC__) extern PFN_##__FUNC__ __FUNC__\n\t#endif\n#endif\n\n\n\n// global functions\nVKFUNC(vkGetInstanceProcAddr);\nVKFUNC(vkCreateInstance);\nVKFUNC(vkGetDeviceProcAddr);\nVKFUNC(vkEnumerateInstanceExtensionProperties);\nVKFUNC(vkEnumerateDeviceExtensionProperties);\nVKFUNC(vkEnumerateInstanceVersion);\n\n// instance functions\nVKFUNC_INSTANCE(vkDestroyInstance);\nVKFUNC_INSTANCE(vkEnumeratePhysicalDevices);\nVKFUNC_INSTANCE(vkCreateDevice);\nVKFUNC_INSTANCE(vkDestroyDevice);\nVKFUNC_INSTANCE(vkDeviceWaitIdle);\n\n// device debug functions\n\n// instance debug functions\nVKFUNC_INSTANCE(vkCreateDebugReportCallbackEXT);\n\nVKFUNC_INSTANCE(vkGetPhysicalDeviceToolPropertiesEXT);\nVKFUNC_INSTANCE(vkSetDebugUtilsObjectNameEXT);\n\n//VKFUNC_INSTANCE(vkCreateDebugReportCallbackEXT);\n\n// getters\nVKFUNC_DEVICE(vkGetDeviceQueue);\nVKFUNC_INSTANCE(vkGetPhysicalDeviceQueueFamilyProperties);\nVKFUNC_INSTANCE(vkGetPhysicalDeviceSurfaceSupportKHR);\nVKFUNC_INSTANCE(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);\nVKFUNC_INSTANCE(vkGetPhysicalDeviceSurfaceFormatsKHR);\nVKFUNC_INSTANCE(vkGetPhysicalDeviceSurfacePresentModesKHR);\nVKFUNC_INSTANCE(vkGetPhysicalDeviceMemoryProperties);\nVKFUNC_INSTANCE(vkGetPhysicalDeviceProperties);\nVKFUNC_INSTANCE(vkGetPhysicalDeviceProperties2);\nVKFUNC_INSTANCE(vkGetPhysicalDeviceFeatures2);\nVKFUNC_INSTANCE(vkGetPhysicalDeviceFormatProperties);\n\n// semaphore\nVKFUNC_DEVICE(vkCreateSemaphore);\nVKFUNC_DEVICE(vkDestroySemaphore);\n\n// imageview\nVKFUNC_DEVICE(vkCreateImageView);\nVKFUNC_DEVICE(vkDestroyImageView);\n\n// shader\nVKFUNC_DEVICE(vkCreateShaderModule);\nVKFUNC_DEVICE(vkDestroyShaderModule);\n\n// framebuffer\nVKFUNC_DEVICE(vkCreateFramebuffer);\nVKFUNC_DEVICE(vkDestroyFramebuffer);\n\n// renderpass\nVKFUNC_DEVICE(vkCreateRenderPass);\nVKFUNC_DEVICE(vkDestroyRenderPass);\nVKFUNC_DEVICE(vkCmdBeginRenderPass);\nVKFUNC_DEVICE(vkCmdEndRenderPass);\n\n// command buffers\nVKFUNC_DEVICE(vkCreateCommandPool);\nVKFUNC_DEVICE(vkDestroyCommandPool);\nVKFUNC_DEVICE(vkAllocateCommandBuffers);\nVKFUNC_DEVICE(vkFreeCommandBuffers);\nVKFUNC_DEVICE(vkBeginCommandBuffer);\nVKFUNC_DEVICE(vkResetCommandBuffer);\nVKFUNC_DEVICE(vkEndCommandBuffer);\nVKFUNC_DEVICE(vkQueueSubmit);\n\n// pipeline\nVKFUNC_DEVICE(vkCreatePipelineCache);\nVKFUNC_DEVICE(vkMergePipelineCaches);\nVKFUNC_DEVICE(vkGetPipelineCacheData);\nVKFUNC_DEVICE(vkDestroyPipelineCache);\nVKFUNC_DEVICE(vkCreatePipelineLayout);\nVKFUNC_DEVICE(vkDestroyPipelineLayout);\nVKFUNC_DEVICE(vkCreateGraphicsPipelines);\nVKFUNC_DEVICE(vkDestroyPipeline);\nVKFUNC_DEVICE(vkCmdBindPipeline);\n\n// swapchain\n#if BOOST_OS_LINUX || BOOST_OS_BSD\nVKFUNC_INSTANCE(vkCreateXlibSurfaceKHR);\nVKFUNC_INSTANCE(vkCreateXcbSurfaceKHR);\n#ifdef HAS_WAYLAND\nVKFUNC_INSTANCE(vkCreateWaylandSurfaceKHR);\n#endif\n#endif\n\n#if BOOST_OS_WINDOWS\nVKFUNC_INSTANCE(vkCreateWin32SurfaceKHR);\n#endif\n\n#if BOOST_OS_MACOS\nVKFUNC_INSTANCE(vkCreateMetalSurfaceEXT);\n#endif\n\nVKFUNC_INSTANCE(vkDestroySurfaceKHR);\nVKFUNC_DEVICE(vkCreateSwapchainKHR);\nVKFUNC_DEVICE(vkDestroySwapchainKHR);\nVKFUNC_DEVICE(vkGetSwapchainImagesKHR);\nVKFUNC_DEVICE(vkAcquireNextImageKHR);\nVKFUNC_INSTANCE(vkQueuePresentKHR);\n\n// fences\nVKFUNC_DEVICE(vkCreateFence);\nVKFUNC_DEVICE(vkWaitForFences);\nVKFUNC_DEVICE(vkGetFenceStatus);\nVKFUNC_DEVICE(vkResetFences);\nVKFUNC_DEVICE(vkDestroyFence);\n\n// cmd\nVKFUNC_DEVICE(vkCmdDraw);\nVKFUNC_DEVICE(vkCmdCopyBufferToImage);\nVKFUNC_DEVICE(vkCmdCopyImageToBuffer);\nVKFUNC_DEVICE(vkCmdClearColorImage);\nVKFUNC_DEVICE(vkCmdClearAttachments);\nVKFUNC_DEVICE(vkCmdBindIndexBuffer);\nVKFUNC_DEVICE(vkCmdBindVertexBuffers);\nVKFUNC_DEVICE(vkCmdDrawIndexed);\nVKFUNC_DEVICE(vkCmdSetViewport);\nVKFUNC_DEVICE(vkCmdSetScissor);\nVKFUNC_DEVICE(vkCmdBindDescriptorSets);\nVKFUNC_DEVICE(vkCmdPipelineBarrier);\nVKFUNC_DEVICE(vkCmdClearDepthStencilImage);\nVKFUNC_DEVICE(vkCmdCopyBuffer);\nVKFUNC_DEVICE(vkCmdCopyImage);\nVKFUNC_DEVICE(vkCmdBlitImage);\nVKFUNC_DEVICE(vkCmdPushConstants);\nVKFUNC_DEVICE(vkCmdSetBlendConstants);\nVKFUNC_DEVICE(vkCmdSetDepthBias);\n\n// synchronization2\n\nVKFUNC_DEVICE(vkCmdPipelineBarrier2KHR);\n\n// khr_dynamic_rendering\nVKFUNC_DEVICE(vkCmdBeginRenderingKHR);\nVKFUNC_DEVICE(vkCmdEndRenderingKHR);\n\n// khr_present_wait\nVKFUNC_DEVICE(vkWaitForPresentKHR);\n\n// transform feedback extension\nVKFUNC_DEVICE(vkCmdBindTransformFeedbackBuffersEXT);\nVKFUNC_DEVICE(vkCmdBeginTransformFeedbackEXT);\nVKFUNC_DEVICE(vkCmdEndTransformFeedbackEXT);\n\n// query\nVKFUNC_DEVICE(vkCreateQueryPool);\nVKFUNC_DEVICE(vkDestroyQueryPool);\nVKFUNC_DEVICE(vkCmdResetQueryPool);\nVKFUNC_DEVICE(vkCmdBeginQuery);\nVKFUNC_DEVICE(vkCmdEndQuery);\nVKFUNC_DEVICE(vkCmdCopyQueryPoolResults);\n\n// event\nVKFUNC_DEVICE(vkCreateEvent);\nVKFUNC_DEVICE(vkCmdSetEvent);\nVKFUNC_DEVICE(vkCmdWaitEvents);\nVKFUNC_DEVICE(vkGetEventStatus);\nVKFUNC_DEVICE(vkDestroyEvent);\n\n// memory\nVKFUNC_DEVICE(vkAllocateMemory);\nVKFUNC_DEVICE(vkFreeMemory);\nVKFUNC_DEVICE(vkCreateBuffer);\nVKFUNC_DEVICE(vkDestroyBuffer);\nVKFUNC_DEVICE(vkBindBufferMemory);\nVKFUNC_DEVICE(vkMapMemory);\nVKFUNC_DEVICE(vkUnmapMemory);\nVKFUNC_DEVICE(vkGetBufferMemoryRequirements);\nVKFUNC_DEVICE(vkFlushMappedMemoryRanges);\nVKFUNC_DEVICE(vkInvalidateMappedMemoryRanges);\n\n// image\nVKFUNC_DEVICE(vkCreateImage);\nVKFUNC_DEVICE(vkDestroyImage);\nVKFUNC_DEVICE(vkGetImageMemoryRequirements);\nVKFUNC_DEVICE(vkBindImageMemory);\n\nVKFUNC_DEVICE(vkCreateSampler);\nVKFUNC_DEVICE(vkDestroySampler);\n\nVKFUNC_DEVICE(vkCreateDescriptorSetLayout);\nVKFUNC_DEVICE(vkAllocateDescriptorSets);\nVKFUNC_DEVICE(vkFreeDescriptorSets);\nVKFUNC_DEVICE(vkUpdateDescriptorSets);\nVKFUNC_DEVICE(vkCreateDescriptorPool);\nVKFUNC_DEVICE(vkDestroyDescriptorPool);\nVKFUNC_DEVICE(vkDestroyDescriptorSetLayout);\n\n#undef VKFUNC_INIT\n#undef VKFUNC_INSTANCE_INIT\n#undef VKFUNC_DEVICE_INIT\n#undef VKFUNC_DEFINE\n\n#undef VKFUNC\n#undef VKFUNC_INSTANCE\n#undef VKFUNC_DEVICE\n#undef VKFUNC_DEFINE_CUSTOM\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/helpers/helpers.h\"\n#include \"util/helpers/Serializer.h\"\n#include \"Cafe/HW/Latte/Common/RegisterSerializer.h\"\n\n/* rects emulation */\n\nvoid rectsEmulationGS_outputSingleVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 vIdx, const LatteContextRegister& latteRegister)\n{\n\tauto parameterMask = vertexShader->outputParameterMask;\n\tfor (uint32 i = 0; i < 32; i++)\n\t{\n\t\tif ((parameterMask & (1 << i)) == 0)\n\t\t\tcontinue;\n\t\tsint32 vsSemanticId = psInputTable->getVertexShaderOutParamSemanticId(latteRegister.GetRawView(), i);\n\t\tif (vsSemanticId < 0)\n\t\t\tcontinue;\n\t\t// make sure PS has matching input\n\t\tif (!psInputTable->hasPSImportForSemanticId(vsSemanticId))\n\t\t\tcontinue;\n\t\tgsSrc.append(fmt::format(\"passParameterSem{}Out = passParameterSem{}In[{}];\\r\\n\", vsSemanticId, vsSemanticId, vIdx));\n\t}\n\tgsSrc.append(fmt::format(\"gl_Position = gl_in[{}].gl_Position;\\r\\n\", vIdx));\n\tgsSrc.append(\"EmitVertex();\\r\\n\");\n}\n\nvoid rectsEmulationGS_outputGeneratedVertex(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, const char* variant, const LatteContextRegister& latteRegister)\n{\n\tauto parameterMask = vertexShader->outputParameterMask;\n\tfor (uint32 i = 0; i < 32; i++)\n\t{\n\t\tif ((parameterMask & (1 << i)) == 0)\n\t\t\tcontinue;\n\t\tsint32 vsSemanticId = psInputTable->getVertexShaderOutParamSemanticId(latteRegister.GetRawView(), i);\n\t\tif (vsSemanticId < 0)\n\t\t\tcontinue;\n\t\t// make sure PS has matching input\n\t\tif (!psInputTable->hasPSImportForSemanticId(vsSemanticId))\n\t\t\tcontinue;\n\t\tgsSrc.append(fmt::format(\"passParameterSem{}Out = gen4thVertex{}(passParameterSem{}In[0], passParameterSem{}In[1], passParameterSem{}In[2]);\\r\\n\", vsSemanticId, variant, vsSemanticId, vsSemanticId, vsSemanticId));\n\t}\n\tgsSrc.append(fmt::format(\"gl_Position = gen4thVertex{}(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_in[2].gl_Position);\\r\\n\", variant));\n\tgsSrc.append(\"EmitVertex();\\r\\n\");\n}\n\nvoid rectsEmulationGS_outputVerticesCode(std::string& gsSrc, LatteDecompilerShader* vertexShader, LatteShaderPSInputTable* psInputTable, sint32 p0, sint32 p1, sint32 p2, sint32 p3, const char* variant, const LatteContextRegister& latteRegister)\n{\n\tsint32 pList[4] = { p0, p1, p2, p3 };\n\tfor (sint32 i = 0; i < 4; i++)\n\t{\n\t\tif (pList[i] == 3)\n\t\t\trectsEmulationGS_outputGeneratedVertex(gsSrc, vertexShader, psInputTable, variant, latteRegister);\n\t\telse\n\t\t\trectsEmulationGS_outputSingleVertex(gsSrc, vertexShader, psInputTable, pList[i], latteRegister);\n\t}\n}\n\nRendererShaderVk* rectsEmulationGS_generate(LatteDecompilerShader* vertexShader, const LatteContextRegister& latteRegister)\n{\n\tstd::string gsSrc;\n\n\tgsSrc.append(\"#version 450\\r\\n\");\n\n\tLatteShaderPSInputTable* psInputTable = LatteSHRC_GetPSInputTable();\n\n\t// layout\n\tgsSrc.append(\"layout(triangles) in;\\r\\n\");\n\tgsSrc.append(\"layout(triangle_strip) out;\\r\\n\");\n\tgsSrc.append(\"layout(max_vertices = 4) out;\\r\\n\");\n\n\t// inputs & outputs\n\tauto parameterMask = vertexShader->outputParameterMask;\n\tfor (sint32 f = 0; f < 2; f++)\n\t{\n\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t{\n\t\t\tif ((parameterMask & (1 << i)) == 0)\n\t\t\t\tcontinue;\n\t\t\tsint32 vsSemanticId = psInputTable->getVertexShaderOutParamSemanticId(latteRegister.GetRawView(), i);\n\t\t\tif (vsSemanticId < 0)\n\t\t\t\tcontinue;\n\t\t\tauto psImport = psInputTable->getPSImportBySemanticId(vsSemanticId);\n\t\t\tif (psImport == nullptr)\n\t\t\t\tcontinue;\n\n\t\t\tgsSrc.append(fmt::format(\"layout(location = {}) \", psInputTable->getPSImportLocationBySemanticId(vsSemanticId)));\n\t\t\tif (psImport->isFlat)\n\t\t\t\tgsSrc.append(\"flat \");\n\t\t\tif (psImport->isNoPerspective)\n\t\t\t\tgsSrc.append(\"noperspective \");\n\n\t\t\tif (f == 0)\n\t\t\t\tgsSrc.append(\"in\");\n\t\t\telse\n\t\t\t\tgsSrc.append(\"out\");\n\n\t\t\tif (f == 0)\n\t\t\t\tgsSrc.append(fmt::format(\" vec4 passParameterSem{}In[];\\r\\n\", vsSemanticId));\n\t\t\telse\n\t\t\t\tgsSrc.append(fmt::format(\" vec4 passParameterSem{}Out;\\r\\n\", vsSemanticId));\n\t\t}\n\t}\n\n\t// gen function\n\tgsSrc.append(\"vec4 gen4thVertexA(vec4 a, vec4 b, vec4 c)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\tgsSrc.append(\"return b - (c - a);\\r\\n\");\n\tgsSrc.append(\"}\\r\\n\");\n\n\tgsSrc.append(\"vec4 gen4thVertexB(vec4 a, vec4 b, vec4 c)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\tgsSrc.append(\"return c - (b - a);\\r\\n\");\n\tgsSrc.append(\"}\\r\\n\");\n\n\tgsSrc.append(\"vec4 gen4thVertexC(vec4 a, vec4 b, vec4 c)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\tgsSrc.append(\"return c + (b - a);\\r\\n\");\n\tgsSrc.append(\"}\\r\\n\");\n\n\t// main\n\tgsSrc.append(\"void main()\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\n\t// there are two possible winding orders that need different triangle generation:\n\t// 0 1\n\t// 2 3\n\t// and\n\t// 0 1\n\t// 3 2\n\t// all others are just symmetries of these cases\n\n\t// we can determine the case by comparing the distance 0<->1 and 0<->2\n\n\tgsSrc.append(\"float dist0_1 = length(gl_in[1].gl_Position.xy - gl_in[0].gl_Position.xy);\\r\\n\");\n\tgsSrc.append(\"float dist0_2 = length(gl_in[2].gl_Position.xy - gl_in[0].gl_Position.xy);\\r\\n\");\n\tgsSrc.append(\"float dist1_2 = length(gl_in[2].gl_Position.xy - gl_in[1].gl_Position.xy);\\r\\n\");\n\n\t// emit vertices\n\tgsSrc.append(\"if(dist0_1 > dist0_2 && dist0_1 > dist1_2)\\r\\n\");\n\tgsSrc.append(\"{\\r\\n\");\n\t// p0 to p1 is diagonal\n\trectsEmulationGS_outputVerticesCode(gsSrc, vertexShader, psInputTable, 2, 1, 0, 3, \"A\", latteRegister);\n\tgsSrc.append(\"} else if ( dist0_2 > dist0_1 && dist0_2 > dist1_2 ) {\\r\\n\");\n\t// p0 to p2 is diagonal\n\trectsEmulationGS_outputVerticesCode(gsSrc, vertexShader, psInputTable, 1, 2, 0, 3, \"B\", latteRegister);\n\tgsSrc.append(\"} else {\\r\\n\");\n\t// p1 to p2 is diagonal\n\trectsEmulationGS_outputVerticesCode(gsSrc, vertexShader, psInputTable, 0, 1, 2, 3, \"C\", latteRegister);\n\tgsSrc.append(\"}\\r\\n\");\n\n\tgsSrc.append(\"}\\r\\n\");\n\n\tauto vkShader = new RendererShaderVk(RendererShader::ShaderType::kGeometry, 0, 0, false, false, gsSrc);\n\tvkShader->PreponeCompilation(true);\n\treturn vkShader;\n}\n\n/* pipeline compiler and cache helper */\n\nextern std::atomic_int g_compiling_pipelines;\nextern std::atomic_int g_compiling_pipelines_async;\nextern std::atomic_uint64_t g_compiling_pipelines_syncTimeSum;\n\nPipelineCompiler::PipelineCompiler() {};\nPipelineCompiler::~PipelineCompiler()\n{\n\tif (m_vkrObjPipeline)\n\t\tm_vkrObjPipeline->decRef();\n\tif (m_renderPassObj)\n\t\tm_renderPassObj->decRef();\n};\n\nVkFormat PipelineCompiler::GetVertexFormat(uint8 format)\n{\n\tswitch (format)\n\t{\n\tcase FMT_32_32_32_32_FLOAT:\n\t\treturn VK_FORMAT_R32G32B32A32_UINT;\n\tcase FMT_32_32_32_FLOAT:\n\t\treturn VK_FORMAT_R32G32B32_UINT;\n\tcase FMT_32_32_FLOAT:\n\t\treturn VK_FORMAT_R32G32_UINT;\n\tcase FMT_32_FLOAT:\n\t\treturn VK_FORMAT_R32_UINT;\n\tcase FMT_8_8_8_8:\n\t\treturn VK_FORMAT_R8G8B8A8_UINT;\n\tcase FMT_8_8_8:\n\t\treturn VK_FORMAT_R8G8B8_UINT;\n\tcase FMT_8_8:\n\t\treturn VK_FORMAT_R8G8_UINT;\n\tcase FMT_8:\n\t\treturn VK_FORMAT_R8_UINT;\n\tcase FMT_32_32_32_32:\n\t\treturn VK_FORMAT_R32G32B32A32_UINT;\n\tcase FMT_32_32_32:\n\t\treturn VK_FORMAT_R32G32B32_UINT;\n\tcase FMT_32_32:\n\t\treturn VK_FORMAT_R32G32_UINT;\n\tcase FMT_32:\n\t\treturn VK_FORMAT_R32_UINT;\n\tcase FMT_16_16_16_16:\n\t\treturn VK_FORMAT_R16G16B16A16_UINT; // verified to match OpenGL\n\tcase FMT_16_16_16:\n\t\treturn VK_FORMAT_R16G16B16_UINT;\n\tcase FMT_16_16:\n\t\treturn VK_FORMAT_R16G16_UINT;\n\tcase FMT_16:\n\t\treturn VK_FORMAT_R16_UINT;\n\tcase FMT_16_16_16_16_FLOAT:\n\t\treturn VK_FORMAT_R16G16B16A16_UINT; // verified to match OpenGL\n\tcase FMT_16_16_16_FLOAT:\n\t\treturn VK_FORMAT_R16G16B16_UINT;\n\tcase FMT_16_16_FLOAT:\n\t\treturn VK_FORMAT_R16G16_UINT;\n\tcase FMT_16_FLOAT:\n\t\treturn VK_FORMAT_R16_UINT;\n\tcase FMT_2_10_10_10:\n\t\treturn VK_FORMAT_R32_UINT; // verified to match OpenGL\n\tdefault:\n\t\tcemuLog_log(LogType::Force, \"Unsupported vertex format: {:02x}\", format);\n\t\tassert_dbg();\n\t\treturn VK_FORMAT_UNDEFINED;\n\t}\n}\n\nstatic VkBlendOp GetVkBlendOp(Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC combineFunc)\n{\n\tswitch (combineFunc)\n\t{\n\tcase Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC::DST_PLUS_SRC:\n\t\treturn VK_BLEND_OP_ADD;\n\tcase Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC::SRC_MINUS_DST:\n\t\treturn VK_BLEND_OP_SUBTRACT;\n\tcase Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC::MIN_DST_SRC:\n\t\treturn VK_BLEND_OP_MIN;\n\tcase Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC::MAX_DST_SRC:\n\t\treturn VK_BLEND_OP_MAX;\n\tcase Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC::DST_MINUS_SRC:\n\t\treturn VK_BLEND_OP_REVERSE_SUBTRACT;\n\tdefault:\n\t\tcemu_assert_suspicious();\n\t\treturn VK_BLEND_OP_ADD;\n\t}\n}\n\nstatic VkBlendFactor GetVkBlendFactor(Latte::LATTE_CB_BLENDN_CONTROL::E_BLENDFACTOR factor)\n{\n\tconst VkBlendFactor factors[] =\n\t{\n\t\t/* 0x00 */ VK_BLEND_FACTOR_ZERO,\n\t\t/* 0x01 */ VK_BLEND_FACTOR_ONE,\n\t\t/* 0x02 */ VK_BLEND_FACTOR_SRC_COLOR,\n\t\t/* 0x03 */ VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,\n\t\t/* 0x04 */ VK_BLEND_FACTOR_SRC_ALPHA,\n\t\t/* 0x05 */ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,\n\t\t/* 0x06 */ VK_BLEND_FACTOR_DST_ALPHA,\n\t\t/* 0x07 */ VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,\n\t\t/* 0x08 */ VK_BLEND_FACTOR_DST_COLOR,\n\t\t/* 0x09 */ VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,\n\t\t/* 0x0A */ VK_BLEND_FACTOR_SRC_ALPHA_SATURATE,\n\t\t/* 0x0B */ VK_BLEND_FACTOR_MAX_ENUM, // todo\n\t\t/* 0x0C */ VK_BLEND_FACTOR_MAX_ENUM, // todo\n\t\t/* 0x0D */ VK_BLEND_FACTOR_CONSTANT_COLOR,\n\t\t/* 0x0E */ VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,\n\t\t/* 0x0F */ VK_BLEND_FACTOR_SRC1_COLOR,\n\t\t/* 0x10 */ VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,\n\t\t/* 0x11 */ VK_BLEND_FACTOR_SRC1_ALPHA,\n\t\t/* 0x12 */ VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,\n\t\t/* 0x13 */ VK_BLEND_FACTOR_CONSTANT_ALPHA,\n\t\t/* 0x14 */ VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA\n\t};\n\tcemu_assert_debug((uint32)factor < std::size(factors));\n\treturn factors[(uint32)factor];\n}\n\nbool PipelineCompiler::ConsumesBlendConstants(VkBlendFactor blendFactor)\n{\n\tif (blendFactor == VK_BLEND_FACTOR_CONSTANT_COLOR ||\n\t\tblendFactor == VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR ||\n\t\tblendFactor == VK_BLEND_FACTOR_CONSTANT_ALPHA ||\n\t\tblendFactor == VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA)\n\t\treturn true;\n\treturn false;\n}\n\nvoid PipelineCompiler::CreateDescriptorSetLayout(VulkanRenderer* vkRenderer, LatteDecompilerShader* shader, VkDescriptorSetLayout& layout, PipelineInfo* vkrPipelineInfo)\n{\n\t// create vertex shader descriptor set\n\tstd::vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;\n\n\tVkShaderStageFlags stageFlags = 0;\n\tuint32 stageIndex = 0;\n\tif (shader->shaderType == LatteConst::ShaderType::Vertex)\n\t{\n\t\tstageFlags = VK_SHADER_STAGE_VERTEX_BIT;\n\t\tstageIndex = VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX;\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t{\n\t\tstageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\t\tstageIndex = VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT;\n\t}\n\telse if (shader->shaderType == LatteConst::ShaderType::Geometry)\n\t{\n\t\tstageFlags = VK_SHADER_STAGE_GEOMETRY_BIT;\n\t\tstageIndex = VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY;\n\t}\n\t// attributes\n\t// -> not part of descriptor\n\n\t// textures\n\tsint32 textureBindingBase = shader->resourceMapping.getTextureBaseBindingPoint();\n\tif (textureBindingBase >= 0)\n\t{\n\t\tsint32 textureCount = shader->resourceMapping.getTextureCount();\n\t\tfor (sint32 i = 0; i < textureCount; i++)\n\t\t{\n\t\t\tVkDescriptorSetLayoutBinding entry{};\n\t\t\tentry.binding = (uint32)textureBindingBase + i;\n\t\t\tentry.descriptorCount = 1;\n\t\t\tentry.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\t\t\tentry.pImmutableSamplers = nullptr;\n\t\t\tentry.stageFlags = stageFlags;\n\t\t\tdescriptorSetLayoutBindings.emplace_back(entry);\n\t\t}\n\t}\n\n\t// uniform buffers\n\tif (shader->resourceMapping.uniformVarsBufferBindingPoint >= 0)\n\t{\n\t\tVkDescriptorSetLayoutBinding entry{};\n\t\tentry.binding = shader->resourceMapping.uniformVarsBufferBindingPoint;\n\t\tentry.descriptorCount = 1;\n\t\tentry.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;\n\t\tentry.pImmutableSamplers = nullptr;\n\t\tentry.stageFlags = stageFlags;\n\t\tdescriptorSetLayoutBindings.emplace_back(entry);\n\t}\n\n\tfor (sint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t{\n\t\tif (shader->resourceMapping.uniformBuffersBindingPoint[i] >= 0)\n\t\t{\n\t\t\tVkDescriptorSetLayoutBinding entry{};\n\t\t\tentry.binding = shader->resourceMapping.uniformBuffersBindingPoint[i];\n\t\t\tentry.descriptorCount = 1;\n\t\t\tentry.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;\n\t\t\tentry.pImmutableSamplers = nullptr;\n\t\t\tentry.stageFlags = stageFlags;\n\t\t\tdescriptorSetLayoutBindings.emplace_back(entry);\n\n\t\t\tvkrPipelineInfo->dynamicOffsetInfo.list_uniformBuffers[stageIndex].emplace_back((uint8)i);\n\t\t}\n\t}\n\n\t// storage buffer for TF\n\tif (shader->resourceMapping.tfStorageBindingPoint >= 0)\n\t{\n\t\tVkDescriptorSetLayoutBinding entry{};\n\t\tentry.binding = shader->resourceMapping.tfStorageBindingPoint;\n\t\tentry.descriptorCount = 1;\n\t\tentry.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;\n\t\tentry.pImmutableSamplers = nullptr;\n\t\tentry.stageFlags = stageFlags;\n\t\tdescriptorSetLayoutBindings.emplace_back(entry);\n\t}\n\n\tif (shader->resourceMapping.uniformVarsBufferBindingPoint >= 0)\n\t\tvkrPipelineInfo->dynamicOffsetInfo.hasUniformVar[stageIndex] = true;\n\tif (shader->resourceMapping.hasUniformBuffers())\n\t\tvkrPipelineInfo->dynamicOffsetInfo.hasUniformBuffers[stageIndex] = true;\n\n\tVkDescriptorSetLayoutCreateInfo layoutInfo = {};\n\tlayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n\tlayoutInfo.bindingCount = descriptorSetLayoutBindings.size();\n\tlayoutInfo.pBindings = descriptorSetLayoutBindings.data();\n\n\tif (vkCreateDescriptorSetLayout(vkRenderer->m_logicalDevice, &layoutInfo, nullptr, &layout) != VK_SUCCESS)\n\t\tvkRenderer->UnrecoverableError(fmt::format(\"Failed to create descriptor set layout for shader {0:#x}\", shader->baseHash).c_str());\n}\n\nbool PipelineCompiler::InitShaderStages(VulkanRenderer* vkRenderer, RendererShaderVk* vkVertexShader, RendererShaderVk* vkPixelShader, RendererShaderVk* vkGeometryShader)\n{\n\t// prepare shader stages\n\tcemu_assert_debug(vkVertexShader == nullptr || vkVertexShader->IsCompiled());\n\tcemu_assert_debug(vkPixelShader == nullptr || vkPixelShader->IsCompiled());\n\tcemu_assert_debug(vkGeometryShader == nullptr || vkGeometryShader->IsCompiled());\n\n\tif ((vkVertexShader && vkVertexShader->GetShaderModule() == VK_NULL_HANDLE) ||\n\t\t(vkGeometryShader && vkGeometryShader->GetShaderModule() == VK_NULL_HANDLE) ||\n\t\t(vkPixelShader && vkPixelShader->GetShaderModule() == VK_NULL_HANDLE))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Vulkan-Info: Pipeline creation failed due to invalid shader(s)\");\n\t\treturn false;\n\t}\n\n\tif (vkVertexShader)\n\t\tshaderStages.emplace_back(vkRenderer->CreatePipelineShaderStageCreateInfo(VK_SHADER_STAGE_VERTEX_BIT, vkVertexShader->GetShaderModule(), \"main\"));\n\n\tif (vkGeometryShader)\n\t\tshaderStages.emplace_back(vkRenderer->CreatePipelineShaderStageCreateInfo(VK_SHADER_STAGE_GEOMETRY_BIT, vkGeometryShader->GetShaderModule(), \"main\"));\n\telse if (m_rectEmulationGS)\n\t\tshaderStages.emplace_back(vkRenderer->CreatePipelineShaderStageCreateInfo(VK_SHADER_STAGE_GEOMETRY_BIT, m_rectEmulationGS->GetShaderModule(), \"main\"));\n\n\tif (vkPixelShader)\n\t\tshaderStages.emplace_back(vkRenderer->CreatePipelineShaderStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, vkPixelShader->GetShaderModule(), \"main\"));\n\n\treturn true;\n}\n\nvoid PipelineCompiler::InitVertexInputState(const LatteContextRegister& latteRegister, LatteDecompilerShader* vertexShader, LatteFetchShader* fetchShader)\n{\n\tvertexInputAttributeDescription.reserve(16);\n\tvertexInputBindingDescription.reserve(fetchShader->bufferGroups.size());\n\n\tfor (auto& bufferGroup : fetchShader->bufferGroups)\n\t{\n\t\tstd::optional<LatteConst::VertexFetchType2> fetchType;\n\n\t\tfor (sint32 j = 0; j < bufferGroup.attribCount; ++j)\n\t\t{\n\t\t\tauto& attr = bufferGroup.attrib[j];\n\n\t\t\tuint32 semanticId = vertexShader->resourceMapping.attributeMapping[attr.semanticId];\n\t\t\tif (semanticId == (uint32)-1)\n\t\t\t\tcontinue; // attribute not used?\n\n\t\t\tVkVertexInputAttributeDescription entry{};\n\t\t\tentry.location = semanticId;\n\t\t\tentry.offset = attr.offset;\n\t\t\tentry.binding = attr.attributeBufferIndex;\n\t\t\tentry.format = GetVertexFormat(attr.format);\n\t\t\tvertexInputAttributeDescription.emplace_back(entry);\n\n\t\t\tif (fetchType.has_value())\n\t\t\t\tcemu_assert_debug(fetchType == attr.fetchType);\n\t\t\telse\n\t\t\t\tfetchType = attr.fetchType;\n\n\t\t\tif (attr.fetchType == LatteConst::INSTANCE_DATA)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(attr.aluDivisor == 1); // other divisor not yet supported\n\t\t\t\t// use VK_EXT_vertex_attribute_divisor\n\t\t\t}\n\t\t}\n\n\t\tuint32 bufferIndex = bufferGroup.attributeBufferIndex;\n\t\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n\t\tuint32 bufferStride = (latteRegister.GetRawView()[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;\n\n\t\tVkVertexInputBindingDescription entry{};\n#if BOOST_OS_MACOS\n\t\tif (bufferStride % 4 != 0) {\n\t\t\tbufferStride = bufferStride + (4-(bufferStride % 4));\n\t\t}\n#endif\n\t\tentry.stride = bufferStride;\n\t\tif (!fetchType.has_value() || fetchType == LatteConst::VertexFetchType2::VERTEX_DATA)\n\t\t\tentry.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;\n\t\telse if (fetchType == LatteConst::VertexFetchType2::INSTANCE_DATA)\n\t\t\tentry.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;\n\t\telse\n\t\t{\n\t\t\tcemu_assert(false);\n\t\t}\n\t\tentry.binding = bufferIndex;\n\t\tvertexInputBindingDescription.emplace_back(entry);\n\t}\n\n\tvertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;\n\tvertexInputInfo.vertexBindingDescriptionCount = vertexInputBindingDescription.size();\n\tvertexInputInfo.pVertexBindingDescriptions = vertexInputBindingDescription.data();\n\tvertexInputInfo.vertexAttributeDescriptionCount = vertexInputAttributeDescription.size();\n\tvertexInputInfo.pVertexAttributeDescriptions = vertexInputAttributeDescription.data();\n}\n\nvoid PipelineCompiler::InitInputAssemblyState(const Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE primitiveMode)\n{\n\tinputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;\n\tinputAssembly.primitiveRestartEnable = VK_TRUE;\n\tswitch (primitiveMode)\n\t{\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::POINTS:\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;\n\t\tinputAssembly.primitiveRestartEnable = false;\n\t\tbreak;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINES:\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST;\n\t\tinputAssembly.primitiveRestartEnable = false;\n\t\tbreak;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINE_STRIP:\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;\n\t\tbreak;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINE_LOOP:\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; // line loops are emulated as line strips with an extra connecting strip at the end\n\t\tbreak;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::LINE_STRIP_ADJACENT: // Tropical Freeze level 3-6\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY;\n\t\tbreak;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLES:\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n\t\tinputAssembly.primitiveRestartEnable = false;\n\t\tbreak;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLE_FAN:\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;\n\t\tbreak;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::TRIANGLE_STRIP:\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;\n\t\tbreak;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUADS:\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // quads are emulated as 2 triangles\n\t\tinputAssembly.primitiveRestartEnable = false;\n\t\tbreak;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::QUAD_STRIP:\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // quad strips are emulated as (count-2)/2 triangles\n\t\tinputAssembly.primitiveRestartEnable = false;\n\t\tbreak;\n\tcase Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS:\n\t\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // rects are emulated as 2 triangles\n\t\tinputAssembly.primitiveRestartEnable = false;\n\t\tbreak;\n\tdefault:\n\t\tcemuLog_logDebug(LogType::Force, \"Vulkan-Unsupported: Graphics pipeline with primitive mode {} created\", primitiveMode);\n\t\tcemu_assert_debug(false);\n\t}\n}\n\nvoid PipelineCompiler::InitViewportState()\n{\n\tviewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;\n\tviewportState.viewportCount = 1;\n\tviewportState.scissorCount = 1;\n}\n\nvoid PipelineCompiler::InitRasterizerState(const LatteContextRegister& latteRegister, VulkanRenderer* vkRenderer, bool isPrimitiveRect, bool& usesDepthBias)\n{\n\t// polygon control\n\tconst auto& polygonControlReg = latteRegister.PA_SU_SC_MODE_CNTL;\n\tconst auto frontFace = polygonControlReg.get_FRONT_FACE();\n\tuint32 cullFront = polygonControlReg.get_CULL_FRONT();\n\tuint32 cullBack = polygonControlReg.get_CULL_BACK();\n\tuint32 polyOffsetFrontEnable = polygonControlReg.get_OFFSET_FRONT_ENABLED();\n\n\tcemu_assert_debug(LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_NEAR_DISABLE() == LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_FAR_DISABLE()); // near or far clipping can be disabled individually\n\tbool zClipEnable = LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_ZCLIP_FAR_DISABLE() == false;\n\n\t// z-clipping\n\trasterizerExt.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT;\n\trasterizerExt.depthClipEnable = zClipEnable;\n\trasterizerExt.flags = 0;\n\n\trasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;\n\trasterizer.rasterizerDiscardEnable = LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_DX_RASTERIZATION_KILL();\n\trasterizer.pNext = VulkanRenderer::GetInstance()->m_featureControl.deviceExtensions.depth_clip_enable ? &rasterizerExt : nullptr;\n\t// GX2SetSpecialState(0, true) workaround\n\tif (!LatteGPUState.contextNew.PA_CL_VTE_CNTL.get_VPORT_X_OFFSET_ENA())\n\t\trasterizer.rasterizerDiscardEnable = false;\n\n\trasterizer.polygonMode = VK_POLYGON_MODE_FILL;\n\tif (vkRenderer->m_featureControl.deviceExtensions.nv_fill_rectangle && isPrimitiveRect)\n\t\trasterizer.polygonMode = VK_POLYGON_MODE_FILL_RECTANGLE_NV;\n\n\trasterizer.depthClampEnable = VK_TRUE; // depth clamping is always enabled\n\n\trasterizer.lineWidth = 1.0f; // TODO -> mmPA_SU_LINE_CNTL\n\n\tusesDepthBias = polyOffsetFrontEnable;\n\tif (polyOffsetFrontEnable)\n\t{\n\t\trasterizer.depthBiasEnable = VK_TRUE;\n\t\t// initialize to zero, set dynamically via vkCmdSetDepthBias\n\t\trasterizer.depthBiasConstantFactor = 0.0f;\n\t\trasterizer.depthBiasSlopeFactor = 0.0f;\n\t\trasterizer.depthBiasClamp = 0.0f;\n\t}\n\telse\n\t\trasterizer.depthBiasEnable = VK_FALSE;\n\n\t// todo - how does culling behave with rects?\n\t// right now we just assume that their winding is always CW\n\tif (isPrimitiveRect)\n\t{\n\t\tif (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CW)\n\t\t\tcullFront = cullBack;\n\t\telse\n\t\t\tcullBack = cullFront;\n\t}\n\n\tif (cullFront && cullBack)\n\t\trasterizer.cullMode = VK_CULL_MODE_FRONT_AND_BACK;\n\telse if (cullFront)\n\t\trasterizer.cullMode = VK_CULL_MODE_FRONT_BIT;\n\telse if (cullBack)\n\t\trasterizer.cullMode = VK_CULL_MODE_BACK_BIT;\n\telse\n\t\trasterizer.cullMode = VK_CULL_MODE_NONE;\n\n\tif (frontFace == Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CCW)\n\t\trasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;\n\telse\n\t\trasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;\n\n\t// multisampling\n\tmultisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;\n\tmultisampling.sampleShadingEnable = VK_FALSE;\n\tmultisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n}\n\nbool _IsVkIntegerFormat(VkFormat fmt)\n{\n\treturn\n\t\t// 8bit integer formats\n\t\tfmt == VK_FORMAT_R8_UINT || fmt == VK_FORMAT_R8_SINT ||\n\t\tfmt == VK_FORMAT_R8G8_UINT || fmt == VK_FORMAT_R8G8_SINT ||\n\t\tfmt == VK_FORMAT_R8G8B8_UINT || fmt == VK_FORMAT_R8G8B8_SINT ||\n\t\tfmt == VK_FORMAT_R8G8B8A8_UINT || fmt == VK_FORMAT_R8G8B8A8_SINT ||\n\t\tfmt == VK_FORMAT_B8G8R8A8_UINT || fmt == VK_FORMAT_B8G8R8A8_SINT ||\n\t\t// 16bit integer formats\n\t\tfmt == VK_FORMAT_R16_UINT || fmt == VK_FORMAT_R16_SINT ||\n\t\tfmt == VK_FORMAT_R16G16_UINT || fmt == VK_FORMAT_R16G16_SINT ||\n\t\tfmt == VK_FORMAT_R16G16B16_UINT || fmt == VK_FORMAT_R16G16B16_SINT ||\n\t\tfmt == VK_FORMAT_R16G16B16A16_UINT || fmt == VK_FORMAT_R16G16B16A16_SINT ||\n\t\t// 32bit integer formats\n\t\tfmt == VK_FORMAT_R32_UINT || fmt == VK_FORMAT_R32_SINT ||\n\t\tfmt == VK_FORMAT_R32G32_UINT || fmt == VK_FORMAT_R32G32_SINT ||\n\t\tfmt == VK_FORMAT_R32G32B32_UINT || fmt == VK_FORMAT_R32G32B32_SINT ||\n\t\tfmt == VK_FORMAT_R32G32B32A32_UINT || fmt == VK_FORMAT_R32G32B32A32_SINT;\n}\n\n\nvoid PipelineCompiler::InitBlendState(const LatteContextRegister& latteRegister, PipelineInfo* pipelineInfo, bool& usesBlendConstants, VKRObjectRenderPass* renderPassObj)\n{\n\tconst Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = latteRegister.CB_COLOR_CONTROL;\n\tuint32 blendEnableMask = colorControlReg.get_BLEND_MASK();\n\tuint32 renderTargetMask = latteRegister.CB_TARGET_MASK.get_MASK();\n\n\tusesBlendConstants = false;\n\n\tfor (size_t i = 0; i < colorBlendAttachments.size(); i++)\n\t{\n\t\tauto& entry = colorBlendAttachments[i];\n\t\tif (((blendEnableMask & (1 << i))) != 0)\n\t\t\tentry.blendEnable = VK_TRUE;\n\t\telse\n\t\t\tentry.blendEnable = VK_FALSE;\n\n\t\tif (entry.blendEnable != VK_FALSE && _IsVkIntegerFormat(renderPassObj->GetColorFormat(i)))\n\t\t{\n\t\t\t// force-disable blending for integer formats\n\t\t\tentry.blendEnable = VK_FALSE;\n\t\t}\n\t\t\n\t\tconst auto& blendControlReg = latteRegister.CB_BLENDN_CONTROL[i];\n\n\t\tentry.colorWriteMask = (renderTargetMask >> (i * 4)) & 0xF;\n\t\tentry.colorBlendOp = GetVkBlendOp(blendControlReg.get_COLOR_COMB_FCN());\n\t\tentry.srcColorBlendFactor = GetVkBlendFactor(blendControlReg.get_COLOR_SRCBLEND());\n\t\tentry.dstColorBlendFactor = GetVkBlendFactor(blendControlReg.get_COLOR_DSTBLEND());\n\t\tif (blendControlReg.get_SEPARATE_ALPHA_BLEND())\n\t\t{\n\t\t\tentry.alphaBlendOp = GetVkBlendOp(blendControlReg.get_ALPHA_COMB_FCN());\n\t\t\tentry.srcAlphaBlendFactor = GetVkBlendFactor(blendControlReg.get_ALPHA_SRCBLEND());\n\t\t\tentry.dstAlphaBlendFactor = GetVkBlendFactor(blendControlReg.get_ALPHA_DSTBLEND());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tentry.alphaBlendOp = entry.colorBlendOp;\n\t\t\tentry.srcAlphaBlendFactor = entry.srcColorBlendFactor;\n\t\t\tentry.dstAlphaBlendFactor = entry.dstColorBlendFactor;\n\t\t}\n\n\t\tusesBlendConstants |= ConsumesBlendConstants(entry.srcColorBlendFactor);\n\t\tusesBlendConstants |= ConsumesBlendConstants(entry.dstColorBlendFactor);\n\t\tusesBlendConstants |= ConsumesBlendConstants(entry.srcAlphaBlendFactor);\n\t\tusesBlendConstants |= ConsumesBlendConstants(entry.dstAlphaBlendFactor);\n\t}\n\n\t// setup VkPipelineColorBlendStateCreateInfo\n\tcolorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;\n\n\tconst auto logicOp = colorControlReg.get_ROP();\n\tif (logicOp == Latte::LATTE_CB_COLOR_CONTROL::E_LOGICOP::COPY)\n\t{\n\t\tcolorBlending.logicOpEnable = VK_FALSE;\n\t\tcolorBlending.logicOp = VK_LOGIC_OP_COPY;\n\t}\n\telse\n\t{\n\t\tcolorBlending.logicOpEnable = VK_TRUE;\n\t\tswitch (logicOp)\n\t\t{\n\t\tcase Latte::LATTE_CB_COLOR_CONTROL::E_LOGICOP::SET:\n\t\t\tcolorBlending.logicOp = VK_LOGIC_OP_SET;\n\t\t\tbreak;\n\t\tcase Latte::LATTE_CB_COLOR_CONTROL::E_LOGICOP::CLEAR:\n\t\t\tcolorBlending.logicOp = VK_LOGIC_OP_CLEAR;\n\t\t\tbreak;\n\t\tcase Latte::LATTE_CB_COLOR_CONTROL::E_LOGICOP::OR:\n\t\t\tcolorBlending.logicOp = VK_LOGIC_OP_OR;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcolorBlending.logicOp = VK_LOGIC_OP_COPY;\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\n\tcolorBlending.attachmentCount = colorBlendAttachments.size();\n\tcolorBlending.pAttachments = colorBlendAttachments.data();\n\n\t// we use VK_DYNAMIC_STATE_BLEND_CONSTANTS, the blend constants here don't matter\n\tcolorBlending.blendConstants[0] = 0;\n\tcolorBlending.blendConstants[1] = 0;\n\tcolorBlending.blendConstants[2] = 0;\n\tcolorBlending.blendConstants[3] = 0;\n}\n\nvoid PipelineCompiler::InitDescriptorSetLayouts(VulkanRenderer* vkRenderer, PipelineInfo* vkrPipelineInfo, LatteDecompilerShader* vertexShader, LatteDecompilerShader* pixelShader, LatteDecompilerShader* geometryShader)\n{\n\tauto vkObjPipeline = vkrPipelineInfo->m_vkrObjPipeline;\n\n\tif (vertexShader)\n\t{\n\t\tcemu_assert_debug(descriptorSetLayoutCount == 0);\n\t\tCreateDescriptorSetLayout(vkRenderer, vertexShader, descriptorSetLayout[descriptorSetLayoutCount], vkrPipelineInfo);\n\t\tvkObjPipeline->m_vertexDSL = descriptorSetLayout[descriptorSetLayoutCount];\n\t\tdescriptorSetLayoutCount++;\n\t}\n\n\tif (pixelShader)\n\t{\n\t\tcemu_assert_debug(descriptorSetLayoutCount == 1);\n\t\tCreateDescriptorSetLayout(vkRenderer, pixelShader, descriptorSetLayout[descriptorSetLayoutCount], vkrPipelineInfo);\n\t\tvkObjPipeline->m_pixelDSL = descriptorSetLayout[descriptorSetLayoutCount];\n\t\tdescriptorSetLayoutCount++;\n\t}\n\telse if (geometryShader)\n\t{\n\t\t// if no pixel shader is present, create empty placeholder descriptor set layout (geometry shader set must be at index 2)\n\t\tVkDescriptorSetLayoutCreateInfo layoutInfo = {};\n\t\tlayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n\t\tlayoutInfo.bindingCount = 0;\n\t\tlayoutInfo.pBindings = nullptr;\n\t\tif (vkCreateDescriptorSetLayout(vkRenderer->m_logicalDevice, &layoutInfo, nullptr, &descriptorSetLayout[descriptorSetLayoutCount]) != VK_SUCCESS)\n\t\t\tvkRenderer->UnrecoverableError(fmt::format(\"Failed to create placeholder descriptor set layout for shader {0:#x}\", geometryShader->baseHash).c_str());\n\t\tdescriptorSetLayoutCount++;\n\t}\n\n\tif (geometryShader)\n\t{\n\t\tcemu_assert_debug(descriptorSetLayoutCount == 2);\n\t\tCreateDescriptorSetLayout(vkRenderer, geometryShader, descriptorSetLayout[descriptorSetLayoutCount], vkrPipelineInfo);\n\t\tvkObjPipeline->m_geometryDSL = descriptorSetLayout[descriptorSetLayoutCount];\n\t\tdescriptorSetLayoutCount++;\n\t}\n}\n\nvoid PipelineCompiler::InitDepthStencilState()\n{\n\t// get depth control parameters\n\tbool depthEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_Z_ENABLE();\n\tauto depthFunc = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_Z_FUNC();\n\tbool depthWriteEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_Z_WRITE_ENABLE();\n\n\t// setup VkPipelineDepthStencilStateCreateInfo\n\tdepthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;\n\tdepthStencilState.depthTestEnable = depthEnable ? VK_TRUE : VK_FALSE;\n\tdepthStencilState.depthWriteEnable = depthWriteEnable ? VK_TRUE : VK_FALSE;\n\n\tstatic const VkCompareOp vkDepthCompareTable[8] =\n\t{\n\t\tVK_COMPARE_OP_NEVER,\n\t\tVK_COMPARE_OP_LESS,\n\t\tVK_COMPARE_OP_EQUAL,\n\t\tVK_COMPARE_OP_LESS_OR_EQUAL,\n\t\tVK_COMPARE_OP_GREATER,\n\t\tVK_COMPARE_OP_NOT_EQUAL,\n\t\tVK_COMPARE_OP_GREATER_OR_EQUAL,\n\t\tVK_COMPARE_OP_ALWAYS\n\t};\n\n\tdepthStencilState.depthCompareOp = vkDepthCompareTable[(size_t)depthFunc];\n\n\tdepthStencilState.depthBoundsTestEnable = false; // todo\n\tdepthStencilState.minDepthBounds = 0.0f;\n\tdepthStencilState.maxDepthBounds = 1.0f;\n\n\t// get stencil control parameters\n\tbool stencilEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ENABLE();\n\tbool backStencilEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_BACK_STENCIL_ENABLE();\n\tauto frontStencilFunc = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FUNC_F();\n\tauto frontStencilZPass = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZPASS_F();\n\tauto frontStencilZFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZFAIL_F();\n\tauto frontStencilFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FAIL_F();\n\tauto backStencilFunc = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FUNC_B();\n\tauto backStencilZPass = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZPASS_B();\n\tauto backStencilZFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZFAIL_B();\n\tauto backStencilFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FAIL_B();\n\t// get stencil control parameters\n\tuint32 stencilCompareMaskFront = LatteGPUState.contextNew.DB_STENCILREFMASK.get_STENCILMASK_F();\n\tuint32 stencilWriteMaskFront = LatteGPUState.contextNew.DB_STENCILREFMASK.get_STENCILWRITEMASK_F();\n\tuint32 stencilRefFront = LatteGPUState.contextNew.DB_STENCILREFMASK.get_STENCILREF_F();\n\tuint32 stencilCompareMaskBack = LatteGPUState.contextNew.DB_STENCILREFMASK_BF.get_STENCILMASK_B();\n\tuint32 stencilWriteMaskBack = LatteGPUState.contextNew.DB_STENCILREFMASK_BF.get_STENCILWRITEMASK_B();\n\tuint32 stencilRefBack = LatteGPUState.contextNew.DB_STENCILREFMASK_BF.get_STENCILREF_B();\n\n\tstatic const VkStencilOp stencilOpTable[8] = {\n\t\tVK_STENCIL_OP_KEEP,\n\t\tVK_STENCIL_OP_ZERO,\n\t\tVK_STENCIL_OP_REPLACE,\n\t\tVK_STENCIL_OP_INCREMENT_AND_CLAMP,\n\t\tVK_STENCIL_OP_DECREMENT_AND_CLAMP,\n\t\tVK_STENCIL_OP_INVERT,\n\t\tVK_STENCIL_OP_INCREMENT_AND_WRAP,\n\t\tVK_STENCIL_OP_DECREMENT_AND_WRAP\n\t};\n\n\tdepthStencilState.stencilTestEnable = stencilEnable ? VK_TRUE : VK_FALSE;\n\n\tdepthStencilState.front.reference = stencilRefFront;\n\tdepthStencilState.front.compareMask = stencilCompareMaskFront;\n\tdepthStencilState.front.writeMask = stencilWriteMaskFront;\n\tdepthStencilState.front.compareOp = vkDepthCompareTable[(size_t)frontStencilFunc];\n\tdepthStencilState.front.depthFailOp = stencilOpTable[(size_t)frontStencilZFail];\n\tdepthStencilState.front.failOp = stencilOpTable[(size_t)frontStencilFail];\n\tdepthStencilState.front.passOp = stencilOpTable[(size_t)frontStencilZPass];\n\n\tif (backStencilEnable)\n\t{\n\t\tdepthStencilState.back.reference = stencilRefBack;\n\t\tdepthStencilState.back.compareMask = stencilCompareMaskBack;\n\t\tdepthStencilState.back.writeMask = stencilWriteMaskBack;\n\t\tdepthStencilState.back.compareOp = vkDepthCompareTable[(size_t)backStencilFunc];\n\t\tdepthStencilState.back.depthFailOp = stencilOpTable[(size_t)backStencilZFail];\n\t\tdepthStencilState.back.failOp = stencilOpTable[(size_t)backStencilFail];\n\t\tdepthStencilState.back.passOp = stencilOpTable[(size_t)backStencilZPass];\n\t}\n\telse\n\t{\n\t\tdepthStencilState.back.reference = stencilRefFront;\n\t\tdepthStencilState.back.compareMask = stencilCompareMaskFront;\n\t\tdepthStencilState.back.writeMask = stencilWriteMaskFront;\n\t\tdepthStencilState.back.compareOp = vkDepthCompareTable[(size_t)frontStencilFunc];\n\t\tdepthStencilState.back.depthFailOp = stencilOpTable[(size_t)frontStencilZFail];\n\t\tdepthStencilState.back.failOp = stencilOpTable[(size_t)frontStencilFail];\n\t\tdepthStencilState.back.passOp = stencilOpTable[(size_t)frontStencilZPass];\n\t}\n}\n\nvoid PipelineCompiler::InitDynamicState(PipelineInfo* pipelineInfo, bool usesBlendConstants, bool usesDepthBias)\n{\n\n\tif (usesBlendConstants)\n\t{\n\t\tdynamicStates.emplace_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS);\n\t\tpipelineInfo->usesBlendConstants = true;\n\t}\n\tif (usesDepthBias)\n\t{\n\t\tdynamicStates.emplace_back(VK_DYNAMIC_STATE_DEPTH_BIAS);\n\t\tpipelineInfo->usesDepthBias = true;\n\t}\n\n\tdynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;\n\tdynamicState.dynamicStateCount = dynamicStates.size();\n\tdynamicState.pDynamicStates = dynamicStates.data();\n}\n\nbool PipelineCompiler::InitFromCurrentGPUState(PipelineInfo* pipelineInfo, const LatteContextRegister& latteRegister, VKRObjectRenderPass* renderPassObj, bool requireRobustBufferAccess)\n{\n\tVulkanRenderer* vkRenderer = VulkanRenderer::GetInstance();\n\n\t// ##########################################################################################################################################\n\tbool isPrimitiveRect = false;\n\tconst auto primitiveMode = latteRegister.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();\n\tisPrimitiveRect = (primitiveMode == Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE::RECTS);\n\n\tm_fetchShader = pipelineInfo->fetchShader;\n\tm_vkVertexShader = pipelineInfo->vertexShaderVk;\n\tm_vkPixelShader = pipelineInfo->pixelShaderVk;\n\tm_vkGeometryShader = pipelineInfo->geometryShaderVk;\n\tm_vkrObjPipeline = pipelineInfo->m_vkrObjPipeline;\n\tm_renderPassObj = renderPassObj;\n\tm_requestRobustBufferAccess = requireRobustBufferAccess;\n\n\t// if required generate RECT emulation geometry shader\n\tif (!vkRenderer->m_featureControl.deviceExtensions.nv_fill_rectangle && isPrimitiveRect)\n\t{\n\t\tcemu_assert(m_vkGeometryShader == nullptr); // todo - handle cases where the game already provides a GS\n\t\tm_rectEmulationGS = rectsEmulationGS_generate(pipelineInfo->vertexShader, latteRegister);\n\t\tpipelineInfo->rectEmulationGS = m_rectEmulationGS;\n\t}\n\n\t// ##########################################################################################################################################\n\n\tpipelineInfo->primitiveMode = primitiveMode;\n\tInitVertexInputState(latteRegister, pipelineInfo->vertexShader, pipelineInfo->fetchShader);\n\tInitInputAssemblyState(primitiveMode);\n\tInitViewportState();\n\tbool usesDepthBias = false;\n\tInitRasterizerState(latteRegister, vkRenderer, isPrimitiveRect, usesDepthBias);\n\tbool usesBlendConstants = false;\n\tInitBlendState(latteRegister, pipelineInfo, usesBlendConstants, renderPassObj);\n\tInitDescriptorSetLayouts(vkRenderer, pipelineInfo, pipelineInfo->vertexShader, pipelineInfo->pixelShader, pipelineInfo->geometryShader);\n\n\t// ##########################################################################################################################################\n\n\tVkPipelineLayoutCreateInfo pipelineLayoutInfo{};\n\tpipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n\tpipelineLayoutInfo.setLayoutCount = descriptorSetLayoutCount;\n\tpipelineLayoutInfo.pSetLayouts = descriptorSetLayout;\n\tpipelineLayoutInfo.pPushConstantRanges = nullptr;\n\tpipelineLayoutInfo.pushConstantRangeCount = 0;\n\n\tVkResult result = vkCreatePipelineLayout(vkRenderer->m_logicalDevice, &pipelineLayoutInfo, nullptr, &m_pipelineLayout);\n\tif (result != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to create pipeline layout: {}\", result);\n\t\treturn false;\n\t}\n\n\t// ###################################################\n\n\tInitDepthStencilState();\n\n\t// ##########################################################################################################################################\n\n\tInitDynamicState(pipelineInfo, usesBlendConstants, usesDepthBias);\n\n\t// ##########################################################################################################################################\n\n\tpipelineInfo->m_vkrObjPipeline->m_pipelineLayout = m_pipelineLayout;\n\n\t// increment ref counter for vkrObjPipeline and renderpass object to make sure they dont get released while we are using them\n\tm_vkrObjPipeline->incRef();\n\tm_renderPassObj->incRef();\n\treturn true;\n}\n\nbool PipelineCompiler::Compile(bool forceCompile, bool isRenderThread, bool showInOverlay)\n{\n\tVulkanRenderer* vkRenderer = VulkanRenderer::GetInstance();\n\n\tif (!vkRenderer->m_featureControl.deviceExtensions.pipeline_creation_cache_control)\n\t\tforceCompile = true; // if VK_EXT_pipeline_creation_cache_control is not supported we always force synchronous compilation\n\n\tif (!forceCompile)\n\t{\n\t\t// fail early if some shader stages are not compiled\n\t\tif (m_vkVertexShader && m_vkVertexShader->IsCompiled() == false)\n\t\t\treturn false;\n\t\tif (m_vkPixelShader && m_vkPixelShader->IsCompiled() == false)\n\t\t\treturn false;\n\t\tif (m_vkGeometryShader && m_vkGeometryShader->IsCompiled() == false)\n\t\t\treturn false;\n\t}\n\telse\n\t{\n\t\t// if some shader stages are not compiled yet, compile them now\n\t\tif (m_vkVertexShader && m_vkVertexShader->IsCompiled() == false)\n\t\t\tm_vkVertexShader->PreponeCompilation(isRenderThread);\n\t\tif (m_vkPixelShader && m_vkPixelShader->IsCompiled() == false)\n\t\t\tm_vkPixelShader->PreponeCompilation(isRenderThread);\n\t\tif (m_vkGeometryShader && m_vkGeometryShader->IsCompiled() == false)\n\t\t\tm_vkGeometryShader->PreponeCompilation(isRenderThread);\n\t}\n\n\tif (shaderStages.empty())\n\t{\n\t\tif (!InitShaderStages(vkRenderer, m_vkVertexShader, m_vkPixelShader, m_vkGeometryShader))\n\t\t\treturn true; // invalid shaders, cannot compile\n\t}\n\n\tVkGraphicsPipelineCreateInfo pipelineInfo{};\n\tpipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;\n\tpipelineInfo.stageCount = shaderStages.size();\n\tpipelineInfo.pStages = shaderStages.data();\n\tpipelineInfo.pVertexInputState = &vertexInputInfo;\n\tpipelineInfo.pInputAssemblyState = &inputAssembly;\n\tpipelineInfo.pViewportState = &viewportState;\n\tpipelineInfo.pDynamicState = &dynamicState;\n\tpipelineInfo.pRasterizationState = &rasterizer;\n\tpipelineInfo.pMultisampleState = &multisampling;\n\tpipelineInfo.pColorBlendState = &colorBlending;\n\tpipelineInfo.layout = m_pipelineLayout;\n\tpipelineInfo.renderPass = m_renderPassObj->m_renderPass;\n\tpipelineInfo.pDepthStencilState = &depthStencilState;\n\tpipelineInfo.subpass = 0;\n\tpipelineInfo.basePipelineHandle = nullptr;\n\tpipelineInfo.flags = 0;\n\tif (!forceCompile)\n\t\tpipelineInfo.flags |= VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT;\n\n\tvoid* prevStruct = nullptr;\n\n\tVkPipelineCreationFeedbackCreateInfoEXT creationFeedbackInfo;\n\tVkPipelineCreationFeedbackEXT creationFeedback;\n\tboost::container::static_vector<VkPipelineCreationFeedbackEXT, 3> creationStageFeedback;\n\tif (vkRenderer->m_featureControl.deviceExtensions.pipeline_feedback)\n\t{\n\t\tcreationFeedback = {};\n\t\tcreationFeedback.flags = VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT;\n\n\t\tfor (uint32_t i = 0; i < pipelineInfo.stageCount; ++i)\n\t\t\tcreationStageFeedback.push_back({VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT, 0});\n\n\t\tcreationFeedbackInfo = {};\n\t\tcreationFeedbackInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT;\n\t\tcreationFeedbackInfo.pPipelineCreationFeedback = &creationFeedback;\n\t\tcreationFeedbackInfo.pPipelineStageCreationFeedbacks = creationStageFeedback.data();\n\t\tcreationFeedbackInfo.pipelineStageCreationFeedbackCount = pipelineInfo.stageCount;\n\t\tcreationFeedbackInfo.pNext = prevStruct;\n\t\tprevStruct = &creationFeedbackInfo;\n\t}\n\n\tVkPipelineRobustnessCreateInfoEXT pipelineRobustnessCreateInfo{};\n\tif (vkRenderer->m_featureControl.deviceExtensions.pipeline_robustness && m_requestRobustBufferAccess)\n\t{\n\t\t// per-pipeline handling of robust buffer access, if the extension is not available then we fall back to device feature robustBufferAccess\n\t\tpipelineRobustnessCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT;\n\t\tpipelineRobustnessCreateInfo.pNext = prevStruct;\n\t\tprevStruct = &pipelineRobustnessCreateInfo;\n\t\tpipelineRobustnessCreateInfo.storageBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;\n\t\tpipelineRobustnessCreateInfo.uniformBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;\n\t\tpipelineRobustnessCreateInfo.vertexInputs = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT;\n\t\tpipelineRobustnessCreateInfo.images = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT;\n\t}\n\n\tpipelineInfo.pNext = prevStruct;\n\n\tVkPipeline pipeline = VK_NULL_HANDLE;\n\tVkResult result;\n\tuint8 retryCount = 0;\n\twhile (retryCount < 3)\n\t{\n\t\tstd::shared_lock lock(vkRenderer->m_pipeline_cache_save_mutex);\n\t\tresult = vkCreateGraphicsPipelines(vkRenderer->m_logicalDevice, vkRenderer->m_pipeline_cache, 1, &pipelineInfo, nullptr, &pipeline);\n\t\tlock.unlock();\n\t\tif (result != VK_ERROR_OUT_OF_DEVICE_MEMORY)\n\t\t\tbreak;\n\t\tretryCount++;\n\t}\n\n\tif (result == VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT)\n\t{\n\t\treturn false;\n\t}\n\telse if (result == VK_SUCCESS)\n\t{\n\t\tm_vkrObjPipeline->SetPipeline(pipeline);\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to create graphics pipeline. Error {}\", (sint32)result);\n\t\tcemu_assert_debug(false);\n\t\treturn true; // true indicates that caller should no longer attempt to compile this pipeline again\n\t}\n\tvkRenderer->m_pipeline_cache_semaphore.notify();\n\n\tif (vkRenderer->m_featureControl.deviceExtensions.pipeline_feedback)\n\t{\n\t\tif (HAS_FLAG(creationFeedback.flags, VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT))\n\t\t{\n\t\t\tbool hasCacheHit = HAS_FLAG(creationFeedback.flags, VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT);\n\t\t\tif (!hasCacheHit)\n\t\t\t{\n\t\t\t\tif (showInOverlay)\n\t\t\t\t{\n\t\t\t\t\tif (isRenderThread)\n\t\t\t\t\t\tg_compiling_pipelines_syncTimeSum += creationFeedback.duration;\n\t\t\t\t\telse\n\t\t\t\t\t\tg_compiling_pipelines_async++;\n\t\t\t\t\tg_compiling_pipelines++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\nvoid PipelineCompiler::TrackAsCached(uint64 baseHash, uint64 pipelineStateHash)\n{\n\tauto& pipelineCache = VulkanPipelineStableCache::GetInstance();\n\tif (pipelineCache.HasPipelineCached(baseHash, pipelineStateHash))\n\t\treturn;\n\tpipelineCache.AddCurrentStateToCache(baseHash, pipelineStateHash);\n}\n\n// calculate whether the pipeline requires robust buffer access\n// if there is a potential risk for a shader to do out-of-bounds reads or writes we need to enable robust buffer access\n// this can happen when:\n// - Streamout is used with too small of a buffer (probably? Could also be some issue with how the streamout array index is calculated -> We can maybe fix this in the future)\n// - The shader uses dynamic indices for uniform access. This will trigger the uniform mode to be FULL_CBANK\nbool PipelineCompiler::CalcRobustBufferAccessRequirement(LatteDecompilerShader* vertexShader, LatteDecompilerShader* pixelShader, LatteDecompilerShader* geometryShader)\n{\n\tbool requiresRobustBufferAcces = false;\n\tif (vertexShader)\n\t{\n\t\tcemu_assert_debug(vertexShader->shaderType == LatteConst::ShaderType::Vertex);\n\t\trequiresRobustBufferAcces |= vertexShader->hasStreamoutBufferWrite;\n\t\trequiresRobustBufferAcces |= vertexShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK;\n\t}\n\tif (geometryShader)\n\t{\n\t\tcemu_assert_debug(geometryShader->shaderType == LatteConst::ShaderType::Geometry);\n\t\trequiresRobustBufferAcces |= geometryShader->hasStreamoutBufferWrite;\n\t\trequiresRobustBufferAcces |= geometryShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK;\n\t}\n\tif (pixelShader)\n\t{\n\t\tcemu_assert_debug(pixelShader->shaderType == LatteConst::ShaderType::Pixel);\n\t\trequiresRobustBufferAcces |= pixelShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK;\n\t}\n\treturn requiresRobustBufferAcces;\n}\n\nstatic std::vector<std::thread> s_compileThreads;\nstatic std::atomic_bool s_compileThreadsShutdownSignal{};\nstatic ConcurrentQueue<PipelineCompiler*> s_pipelineCompileRequests;\n\nstatic void compilePipeline_thread(sint32 threadIndex)\n{\n\tSetThreadName(\"compilePl\");\n#ifdef _WIN32\n\t// to avoid starving the main cpu and render threads the pipeline compile threads run at lower priority\n\t// except for one thread which we always run at normal priority to prevent the opposite scenario where all compile threads are starved\n\tif(threadIndex != 0)\n\t\tSetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);\n#endif\n\twhile (!s_compileThreadsShutdownSignal)\n\t{\n\t\tPipelineCompiler* request = s_pipelineCompileRequests.pop();\n\t\tif (!request)\n\t\t\tcontinue;\n\t\trequest->Compile(true, false, true);\n\t\tdelete request;\n\t}\n}\n\nvoid PipelineCompiler::CompileThreadPool_Start()\n{\n\tcemu_assert_debug(s_compileThreads.empty());\n\ts_compileThreadsShutdownSignal = false;\n\tuint32 numCompileThreads;\n\n\tuint32 cpuCoreCount = GetPhysicalCoreCount();\n\tif (cpuCoreCount <= 2)\n\t\tnumCompileThreads = 1;\n\telse\n\t\tnumCompileThreads = 2 + (cpuCoreCount - 3); // 2 plus one additionally for every extra core above 3\n\n\tnumCompileThreads = std::min(numCompileThreads, 8u); // cap at 8\n\n\tfor (uint32_t i = 0; i < numCompileThreads; i++)\n\t{\n\t\ts_compileThreads.emplace_back(compilePipeline_thread, i);\n\t}\n}\n\nvoid PipelineCompiler::CompileThreadPool_Stop()\n{\n\ts_compileThreadsShutdownSignal = true;\n\t{\n\t\t// push one empty workload for each thread\n\t\t// this way we can make sure that each waiting thread is woken up to see the shutdown signal\n\t\tfor (auto& thread : s_compileThreads)\n\t\t\ts_pipelineCompileRequests.push(nullptr);\n\t}\n\tfor (auto& thread : s_compileThreads)\n\t\tthread.join();\n\twhile (!s_pipelineCompileRequests.empty())\n\t{\n\t\tPipelineCompiler* pipelineCompiler = s_pipelineCompileRequests.pop();\n\t\tif (pipelineCompiler)\n\t\t\tdelete pipelineCompiler;\n\t}\n\ts_compileThreads.clear();\n}\n\nvoid PipelineCompiler::CompileThreadPool_QueueCompilation(PipelineCompiler* v)\n{\n\ts_pipelineCompileRequests.push(v);\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"VKRBase.h\"\n\nclass PipelineCompiler : public VKRMoveableRefCounter\n{\nprivate:\n\t// helper functions\n\tVkFormat GetVertexFormat(uint8 format);\n\tbool ConsumesBlendConstants(VkBlendFactor blendFactor);\n\n\tvoid CreateDescriptorSetLayout(VulkanRenderer* vkRenderer, LatteDecompilerShader* shader, VkDescriptorSetLayout& layout, PipelineInfo* vkrPipelineInfo);\n\nprivate:\n\n\t/* shader stages (requires compiled shader) */\n\n\tRendererShaderVk* m_rectEmulationGS{};\n\n\tbool InitShaderStages(VulkanRenderer* vkRenderer, RendererShaderVk* vkVertexShader, RendererShaderVk* vkPixelShader, RendererShaderVk* vkGeometryShader);\n\n\t/* vertex input state */\n\n\tvoid InitVertexInputState(const LatteContextRegister& latteRegister, LatteDecompilerShader* vertexShader, LatteFetchShader* fetchShader);\n\tvoid InitInputAssemblyState(const Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE primitiveMode);\n\tvoid InitViewportState();\n\tvoid InitRasterizerState(const LatteContextRegister& latteRegister, VulkanRenderer* vkRenderer, bool isPrimitiveRect, bool& usesDepthBias);\n\tvoid InitBlendState(const LatteContextRegister& latteRegister, PipelineInfo* pipelineInfo, bool& usesBlendConstants, VKRObjectRenderPass* renderPassObj);\n\tvoid InitDescriptorSetLayouts(VulkanRenderer* vkRenderer, PipelineInfo* vkrPipelineInfo, LatteDecompilerShader* vertexShader, LatteDecompilerShader* pixelShader, LatteDecompilerShader* geometryShader);\n\tvoid InitDepthStencilState();\n\tvoid InitDynamicState(PipelineInfo* pipelineInfo, bool usesBlendConstants, bool usesDepthBias);\n\npublic:\n\tPipelineCompiler();\n\t~PipelineCompiler();\n\n\tVKRObjectPipeline* m_vkrObjPipeline{};\n\tLatteFetchShader* m_fetchShader{};\n\tRendererShaderVk* m_vkVertexShader{};\n\tRendererShaderVk* m_vkPixelShader{};\n\tRendererShaderVk* m_vkGeometryShader{};\n\n\tbool InitFromCurrentGPUState(PipelineInfo* pipelineInfo, const LatteContextRegister& latteRegister, VKRObjectRenderPass* renderPassObj, bool requireRobustBufferAccess);\n\tvoid TrackAsCached(uint64 baseHash, uint64 pipelineStateHash); // stores pipeline to permanent cache if not yet cached. Must be called synchronously from render thread due to dependency on GPU state\n\n\tstatic bool CalcRobustBufferAccessRequirement(LatteDecompilerShader* vertexShader, LatteDecompilerShader* pixelShader, LatteDecompilerShader* geometryShader);\n\n\t// API for thread pool\n\tstatic void CompileThreadPool_Start();\n\tstatic void CompileThreadPool_Stop();\n\tstatic void CompileThreadPool_QueueCompilation(PipelineCompiler* v);\n\n\tVkPipelineLayout m_pipelineLayout;\n\tVKRObjectRenderPass* m_renderPassObj{};\n\tbool m_requestRobustBufferAccess{false};\n\n\t/* shader stages */\n\tstd::vector<VkPipelineShaderStageCreateInfo> shaderStages;\n\n\t/* vertex attribute description */\n\tstd::vector<VkVertexInputAttributeDescription> vertexInputAttributeDescription;\n\tstd::vector<VkVertexInputBindingDescription> vertexInputBindingDescription;\n\tVkPipelineVertexInputStateCreateInfo vertexInputInfo{};\n\n\t/* input assembly state */\n\tVkPipelineInputAssemblyStateCreateInfo inputAssembly{};\n\n\t/* viewport state */\n\tVkPipelineViewportStateCreateInfo viewportState{};\n\n\t/* rasterizer state */\n\tVkPipelineRasterizationStateCreateInfo rasterizer{};\n\tVkPipelineRasterizationDepthClipStateCreateInfoEXT rasterizerExt{};\n\tVkPipelineMultisampleStateCreateInfo multisampling{};\n\n\t/* blend state */\n\tstd::array<VkPipelineColorBlendAttachmentState, 8> colorBlendAttachments{};\n\tVkPipelineColorBlendStateCreateInfo colorBlending{};\n\n\t/* descriptor set layouts */\n\tVkDescriptorSetLayout descriptorSetLayout[3];\n\tsint32 descriptorSetLayoutCount = 0;\n\n\t/* depth stencil state */\n\tVkPipelineDepthStencilStateCreateInfo depthStencilState{};\n\n\t/* dynamic state */\n\tstd::vector<VkDynamicState> dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };\n\tVkPipelineDynamicStateCreateInfo dynamicState = {};\n\n\t// returns true if the shader was compiled (even if errors occurred)\n\tbool Compile(bool forceCompile, bool isRenderThread, bool showInOverlay);\n\n};"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Core/LatteCachedFBO.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/helpers/Serializer.h\"\n#include \"Cafe/HW/Latte/Common/RegisterSerializer.h\"\n#include \"Cemu/FileCache/FileCache.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderCache.h\"\n#include \"util/helpers/helpers.h\"\n#include <openssl/sha.h>\n\nstruct\n{\n\tuint32 pipelineLoadIndex;\n\tuint32 pipelineMaxFileIndex;\n\t\n\tstd::atomic_uint32_t pipelinesQueued;\n\tstd::atomic_uint32_t pipelinesLoaded;\n}g_vkCacheState;\n\nVulkanPipelineStableCache g_vkPipelineStableCacheInstance;\n\nVulkanPipelineStableCache& VulkanPipelineStableCache::GetInstance()\n{\n\treturn g_vkPipelineStableCacheInstance;\n}\n\nuint32 VulkanPipelineStableCache::BeginLoading(uint64 cacheTitleId)\n{\n\tstd::error_code ec;\n\tfs::create_directories(ActiveSettings::GetCachePath(\"shaderCache/transferable\"), ec);\n\tconst auto pathCacheFile = ActiveSettings::GetCachePath(\"shaderCache/transferable/{:016x}_vkpipeline.bin\", cacheTitleId);\n\t\n\t// init cache loader state\n\tg_vkCacheState.pipelineLoadIndex = 0;\n\tg_vkCacheState.pipelineMaxFileIndex = 0;\n\tg_vkCacheState.pipelinesLoaded = 0;\n\tg_vkCacheState.pipelinesQueued = 0;\n\t\n\t// start async compilation threads\n\tm_compilationCount.store(0);\t\n\tm_compilationQueue.clear();\n\n\t// get core count\n\tuint32 cpuCoreCount = GetPhysicalCoreCount();\n\tm_numCompilationThreads = std::clamp(cpuCoreCount, 1u, 8u);\n\tif (VulkanRenderer::GetInstance()->GetDisableMultithreadedCompilation())\n\t\tm_numCompilationThreads = 1;\n\n\tfor (uint32 i = 0; i < m_numCompilationThreads; i++)\n\t{\n\t\tstd::thread compileThread(&VulkanPipelineStableCache::CompilerThread, this);\n\t\tcompileThread.detach();\n\t}\n\n\t// open cache file or create it\n\tcemu_assert_debug(s_cache == nullptr);\n\ts_cache = FileCache::Open(pathCacheFile, true, LatteShaderCache_getPipelineCacheExtraVersion(cacheTitleId));\n\tif (!s_cache)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to open or create Vulkan pipeline cache file: {}\", _pathToUtf8(pathCacheFile));\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\ts_cache->UseCompression(false);\n\t\tg_vkCacheState.pipelineMaxFileIndex = s_cache->GetMaximumFileIndex();\n\t}\n\treturn s_cache->GetFileCount();\n}\n\nbool VulkanPipelineStableCache::UpdateLoading(uint32& pipelinesLoadedTotal, uint32& pipelinesMissingShaders)\n{\n\tpipelinesLoadedTotal = g_vkCacheState.pipelinesLoaded;\n\tpipelinesMissingShaders = 0;\n\twhile (g_vkCacheState.pipelineLoadIndex <= g_vkCacheState.pipelineMaxFileIndex)\n\t{\n\t\tif (m_compilationQueue.size() >= 50)\n\t\t{\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t\treturn true; // queue up to 50 entries at a time\n\t\t}\n\n\t\tuint64 fileNameA, fileNameB;\n\t\tstd::vector<uint8> fileData;\n\t\tif (s_cache->GetFileByIndex(g_vkCacheState.pipelineLoadIndex, &fileNameA, &fileNameB, fileData))\n\t\t{\n\t\t\t// queue for async compilation\n\t\t\tg_vkCacheState.pipelinesQueued++;\n\t\t\tm_compilationQueue.push(std::move(fileData));\n\t\t\tg_vkCacheState.pipelineLoadIndex++;\n\t\t\treturn true;\n\t\t}\n\t\tg_vkCacheState.pipelineLoadIndex++;\n\t}\n\tif (g_vkCacheState.pipelinesLoaded != g_vkCacheState.pipelinesQueued)\n\t{\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\treturn true; // pipelines still compiling\n\t}\n\treturn false; // done\n}\n\nvoid VulkanPipelineStableCache::EndLoading()\n{\n\t// shut down compilation threads\n\tuint32 threadCount = m_numCompilationThreads;\n\tm_numCompilationThreads = 0; // signal thread shutdown\n\tfor (uint32 i = 0; i < threadCount; i++)\n\t{\n\t\tm_compilationQueue.push({}); // push empty workload for every thread. Threads then will shutdown after checking for m_numCompilationThreads == 0\n\t}\n\t// keep cache file open for writing of new pipelines\n}\n\nvoid VulkanPipelineStableCache::Close()\n{\n    if(s_cache)\n    {\n        delete s_cache;\n        s_cache = nullptr;\n    }\n}\n\nstruct CachedPipeline\n{\n\tstruct ShaderHash\n\t{\n\t\tuint64 baseHash;\n\t\tuint64 auxHash;\n\t\tbool isPresent{};\n\n\t\tvoid set(uint64 baseHash, uint64 auxHash)\n\t\t{\n\t\t\tthis->baseHash = baseHash;\n\t\t\tthis->auxHash = auxHash;\n\t\t\tthis->isPresent = true;\n\t\t}\n\t};\n\n\tShaderHash vsHash; // includes fetch shader\n\tShaderHash gsHash;\n\tShaderHash psHash;\n\n\tLatte::GPUCompactedRegisterState gpuState;\n};\n\nVkFormat __getColorBufferVkFormat(const uint32 index, const LatteContextRegister& lcr)\n{\n\tLatte::E_GX2SURFFMT colorBufferFormat = LatteMRT::GetColorBufferFormat(index, lcr);\n\tVulkanRenderer::FormatInfoVK texFormatInfo;\n\tVulkanRenderer::GetInstance()->GetTextureFormatInfoVK(colorBufferFormat, false, Latte::E_DIM::DIM_2D, 1280, 720, &texFormatInfo);\n\treturn texFormatInfo.vkImageFormat;\n}\n\nvoid __getDepthBufferVkFormat(const LatteContextRegister& lcr, VkFormat& dbFormat, bool& hasStencil)\n{\n\tLatte::E_GX2SURFFMT format = LatteMRT::GetDepthBufferFormat(lcr);\n\tVulkanRenderer::FormatInfoVK texFormatInfo;\n\tVulkanRenderer::GetInstance()->GetTextureFormatInfoVK(format, true, Latte::E_DIM::DIM_2D, 1280, 720, &texFormatInfo);\n\tdbFormat = texFormatInfo.vkImageFormat;\n\thasStencil = (texFormatInfo.vkImageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;\n}\n\n// create placeholder renderpass for cached pipeline\nVKRObjectRenderPass* __CreateTemporaryRenderPass(const LatteDecompilerShader* pixelShader, const LatteContextRegister& lcr)\n{\n\tVKRObjectRenderPass::AttachmentInfo_t attachmentInfo;\n\n\tuint8 cbMask = LatteMRT::GetActiveColorBufferMask(pixelShader, lcr);\n\tbool dbMask = LatteMRT::GetActiveDepthBufferMask(lcr);\n\n\tfor (int i = 0; i < 8; ++i)\n\t{\n\t\tif ((cbMask & (1 << i)) == 0)\n\t\t{\n\t\t\tattachmentInfo.colorAttachment[i].viewObj = nullptr;\n\t\t\tcontinue;\n\t\t}\n\t\t// setup color attachment\n\t\tattachmentInfo.colorAttachment[i].viewObj = nullptr;\n\t\tattachmentInfo.colorAttachment[i].isPresent = true;\n\t\tattachmentInfo.colorAttachment[i].format = __getColorBufferVkFormat(i, lcr);\n\t}\n\n\t// setup depth attachment\n\tif (dbMask)\n\t{\n\t\tattachmentInfo.depthAttachment.viewObj = nullptr;\n\t\tattachmentInfo.depthAttachment.isPresent = true;\n\t\tVkFormat dbFormat;\n\t\tbool hasStencil;\n\t\t__getDepthBufferVkFormat(lcr, dbFormat, hasStencil);\n\t\tattachmentInfo.depthAttachment.format = dbFormat;\n\t\tattachmentInfo.depthAttachment.hasStencil = hasStencil;\n\t}\n\telse\n\t{\n\t\t// no depth attachment\n\t\tattachmentInfo.depthAttachment.viewObj = nullptr;\n\t\tattachmentInfo.depthAttachment.isPresent = false;\n\t}\n\n\treturn new VKRObjectRenderPass(attachmentInfo);\n}\n\nvoid VulkanPipelineStableCache::LoadPipelineFromCache(std::span<uint8> fileData)\n{\n\tstatic FSpinlock s_spinlockSharedInternal;\n\n\t// deserialize file\n\tLatteContextRegister* lcr = new LatteContextRegister();\n\ts_spinlockSharedInternal.lock();\n\tCachedPipeline* cachedPipeline = new CachedPipeline();\n\ts_spinlockSharedInternal.unlock();\n\n\tMemStreamReader streamReader(fileData.data(), fileData.size());\n\tif (!DeserializePipeline(streamReader, *cachedPipeline))\n\t{\n\t\t// failed to deserialize\n\t\ts_spinlockSharedInternal.lock();\n\t\tdelete lcr;\n\t\tdelete cachedPipeline;\n\t\ts_spinlockSharedInternal.unlock();\n\t\treturn;\n\t}\n\t// restored register view from compacted state\n\tLatte::LoadGPURegisterState(*lcr, cachedPipeline->gpuState);\n\n\tLatteDecompilerShader* vertexShader = nullptr;\n\tLatteDecompilerShader* geometryShader = nullptr;\n\tLatteDecompilerShader* pixelShader = nullptr;\n\t// find vertex shader\n\tif (cachedPipeline->vsHash.isPresent)\n\t{\n\t\tvertexShader = LatteSHRC_FindVertexShader(cachedPipeline->vsHash.baseHash, cachedPipeline->vsHash.auxHash);\n\t\tif (!vertexShader)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Vertex shader not found in cache\");\n\t\t\treturn;\n\t\t}\n\t}\n\t// find geometry shader\n\tif (cachedPipeline->gsHash.isPresent)\n\t{\n\t\tgeometryShader = LatteSHRC_FindGeometryShader(cachedPipeline->gsHash.baseHash, cachedPipeline->gsHash.auxHash);\n\t\tif (!geometryShader)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Geometry shader not found in cache\");\n\t\t\treturn;\n\t\t}\n\t}\n\t// find pixel shader\n\tif (cachedPipeline->psHash.isPresent)\n\t{\n\t\tpixelShader = LatteSHRC_FindPixelShader(cachedPipeline->psHash.baseHash, cachedPipeline->psHash.auxHash);\n\t\tif (!pixelShader)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Pixel shader not found in cache\");\n\t\t\treturn;\n\t\t}\n\t}\n\t// create temporary renderpass\n\tif (!pixelShader)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\tauto renderPass = __CreateTemporaryRenderPass(pixelShader, *lcr);\n\t// create pipeline info\n\tm_pipelineIsCachedLock.lock();\n\tPipelineInfo* pipelineInfo = new PipelineInfo(0, 0, vertexShader->compatibleFetchShader, vertexShader, pixelShader, geometryShader);\n\tm_pipelineIsCachedLock.unlock();\n\t// compile\n\t{\n\t\tPipelineCompiler pipelineCompiler;\n\t\tbool requiresRobustBufferAccess = PipelineCompiler::CalcRobustBufferAccessRequirement(vertexShader, pixelShader, geometryShader);\n\t\tif (!pipelineCompiler.InitFromCurrentGPUState(pipelineInfo, *lcr, renderPass, requiresRobustBufferAccess))\n\t\t{\n\t\t\ts_spinlockSharedInternal.lock();\n\t\t\tdelete lcr;\n\t\t\tdelete cachedPipeline;\n\t\t\ts_spinlockSharedInternal.unlock();\n\t\t\treturn;\n\t\t}\n\t\tpipelineCompiler.Compile(true, true, false);\n\t}\n\t// on success, calculate pipeline hash and flag as present in cache\n\tuint64 pipelineBaseHash = vertexShader->baseHash;\n\tuint64 pipelineStateHash = VulkanRenderer::draw_calculateGraphicsPipelineHash(vertexShader->compatibleFetchShader, vertexShader, geometryShader, pixelShader, renderPass, *lcr);\n\tm_pipelineIsCachedLock.lock();\n\tm_pipelineIsCached.emplace(pipelineBaseHash, pipelineStateHash);\n\tm_pipelineIsCachedLock.unlock();\n\t// clean up\n\ts_spinlockSharedInternal.lock();\n\tdelete pipelineInfo;\n\tdelete lcr;\n\tdelete cachedPipeline;\n\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(renderPass);\n\ts_spinlockSharedInternal.unlock();\n}\n\nbool VulkanPipelineStableCache::HasPipelineCached(uint64 baseHash, uint64 pipelineStateHash)\n{\n\tPipelineHash ph(baseHash, pipelineStateHash);\n\treturn m_pipelineIsCached.find(ph) != m_pipelineIsCached.end();\n}\n\nConcurrentQueue<CachedPipeline*> g_pipelineCachingQueue;\n\nvoid VulkanPipelineStableCache::AddCurrentStateToCache(uint64 baseHash, uint64 pipelineStateHash)\n{\n\tm_pipelineIsCached.emplace(baseHash, pipelineStateHash);\n\tif (!m_pipelineCacheStoreThread)\n\t{\n\t\tm_pipelineCacheStoreThread = new std::thread(&VulkanPipelineStableCache::WorkerThread, this);\n\t\tm_pipelineCacheStoreThread->detach();\n\t}\n\t// fill job structure with cached GPU state\n\t// for each cached pipeline we store:\n\t// - Active shaders (referenced by hash)\n\t// - An almost-complete register state of the GPU (minus some ALU uniform constants which aren't relevant)\n\tCachedPipeline* job = new CachedPipeline();\n\tauto vs = LatteSHRC_GetActiveVertexShader();\n\tauto gs = LatteSHRC_GetActiveGeometryShader();\n\tauto ps = LatteSHRC_GetActivePixelShader();\n\tif (vs)\n\t\tjob->vsHash.set(vs->baseHash, vs->auxHash);\n\tif (gs)\n\t\tjob->gsHash.set(gs->baseHash, gs->auxHash);\n\tif (ps)\n\t\tjob->psHash.set(ps->baseHash, ps->auxHash);\n\tLatte::StoreGPURegisterState(LatteGPUState.contextNew, job->gpuState);\n\t// queue job\n\tg_pipelineCachingQueue.push(job);\n}\n\nbool VulkanPipelineStableCache::SerializePipeline(MemStreamWriter& memWriter, CachedPipeline& cachedPipeline)\n{\n\tmemWriter.writeBE<uint8>(0x01); // version\n\tuint8 presentMask = 0;\n\tif (cachedPipeline.vsHash.isPresent)\n\t\tpresentMask |= 1;\n\tif (cachedPipeline.gsHash.isPresent)\n\t\tpresentMask |= 2;\n\tif (cachedPipeline.psHash.isPresent)\n\t\tpresentMask |= 4;\n\tmemWriter.writeBE<uint8>(presentMask);\n\tif (cachedPipeline.vsHash.isPresent)\n\t{\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.vsHash.baseHash);\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.vsHash.auxHash);\n\t}\n\tif (cachedPipeline.gsHash.isPresent)\n\t{\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.gsHash.baseHash);\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.gsHash.auxHash);\n\t}\n\tif (cachedPipeline.psHash.isPresent)\n\t{\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.psHash.baseHash);\n\t\tmemWriter.writeBE<uint64>(cachedPipeline.psHash.auxHash);\n\t}\n\tLatte::SerializeRegisterState(cachedPipeline.gpuState, memWriter);\n\treturn true;\n}\n\nbool VulkanPipelineStableCache::DeserializePipeline(MemStreamReader& memReader, CachedPipeline& cachedPipeline)\n{\n\t// version\n\tif (memReader.readBE<uint8>() != 1)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Cached Vulkan pipeline corrupted or has unknown version\");\n\t\treturn false;\n\t}\n\t// shader hashes\n\tuint8 presentMask = memReader.readBE<uint8>();\n\tif (presentMask & 1)\n\t{\n\t\tuint64 baseHash = memReader.readBE<uint64>();\n\t\tuint64 auxHash = memReader.readBE<uint64>();\n\t\tcachedPipeline.vsHash.set(baseHash, auxHash);\n\t}\n\tif (presentMask & 2)\n\t{\n\t\tuint64 baseHash = memReader.readBE<uint64>();\n\t\tuint64 auxHash = memReader.readBE<uint64>();\n\t\tcachedPipeline.gsHash.set(baseHash, auxHash);\n\t}\n\tif (presentMask & 4)\n\t{\n\t\tuint64 baseHash = memReader.readBE<uint64>();\n\t\tuint64 auxHash = memReader.readBE<uint64>();\n\t\tcachedPipeline.psHash.set(baseHash, auxHash);\n\t}\n\t// deserialize GPU state\n\tif (!Latte::DeserializeRegisterState(cachedPipeline.gpuState, memReader))\n\t{\n\t\treturn false;\n\t}\n\tcemu_assert_debug(!memReader.hasError());\n\treturn true;\n}\n\nint VulkanPipelineStableCache::CompilerThread()\n{\n\tSetThreadName(\"plCacheCompiler\");\n\twhile (m_numCompilationThreads != 0)\n\t{\n\t\tstd::vector<uint8> pipelineData = m_compilationQueue.pop();\n\t\tif(pipelineData.empty())\n\t\t\tcontinue;\n\t\tLoadPipelineFromCache(pipelineData);\n\t\t++g_vkCacheState.pipelinesLoaded;\n\t}\n\treturn 0;\n}\n\nvoid VulkanPipelineStableCache::WorkerThread()\n{\n\tSetThreadName(\"plCacheWriter\");\n\twhile (true)\n\t{\n\t\tCachedPipeline* job;\n\t\tg_pipelineCachingQueue.pop(job);\n\t\tif (!s_cache)\n\t\t{\n\t\t\tdelete job;\n\t\t\tcontinue;\n\t\t}\n\t\t// serialize\n\t\tMemStreamWriter memWriter(1024 * 4);\n\t\tSerializePipeline(memWriter, *job);\n\t\tauto blob = memWriter.getResult();\n\t\t// file name is derived from data hash\n\t\tuint8 hash[SHA256_DIGEST_LENGTH];\n\t\tSHA256(blob.data(), blob.size(), hash);\n\t\tuint64 nameA = *(uint64be*)(hash + 0);\n\t\tuint64 nameB = *(uint64be*)(hash + 8);\n\t\ts_cache->AddFileAsync({ nameA, nameB }, blob.data(), blob.size());\n\t\tdelete job;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h",
    "content": "#pragma once\n#include \"util/helpers/fspinlock.h\"\n\nstruct VulkanPipelineHash\n{\n\tVulkanPipelineHash() = default;\n\tVulkanPipelineHash(uint64 h0, uint64 h1) : h0(h0), h1(h1) {};\n\n\tuint64 h0;\n\tuint64 h1;\n};\n\nclass VulkanPipelineStableCache\n{\n\tstruct PipelineHash \n\t{\n\t\tPipelineHash(uint64 h0, uint64 h1) : h0(h0), h1(h1) {};\n\n\t\tuint64 h0;\n\t\tuint64 h1;\n\n\t\tbool operator==(const PipelineHash& r) const\n\t\t{\n\t\t\treturn h0 == r.h0 && h1 == r.h1;\n\t\t}\n\n\t\tstruct HashFunc \n\t\t{\n\t\t\tsize_t operator()(const PipelineHash& v) const\n\t\t\t{\n\t\t\t\tstatic_assert(sizeof(uint64) == sizeof(size_t));\n\t\t\t\treturn v.h0 ^ v.h1;\n\t\t\t}\n\t\t};\n\t};\n\npublic:\n\tstatic VulkanPipelineStableCache& GetInstance();\n\n\tuint32 BeginLoading(uint64 cacheTitleId); // returns count of pipelines stored in cache\n\tbool UpdateLoading(uint32& pipelinesLoadedTotal, uint32& pipelinesMissingShaders);\n\tvoid EndLoading();\n\tvoid LoadPipelineFromCache(std::span<uint8> fileData);\n    void Close(); // called on title exit\n\n\tbool HasPipelineCached(uint64 baseHash, uint64 pipelineStateHash);\n\tvoid AddCurrentStateToCache(uint64 baseHash, uint64 pipelineStateHash);\n\n\t// pipeline serialization for file\n\tbool SerializePipeline(class MemStreamWriter& memWriter, struct CachedPipeline& cachedPipeline);\n\tbool DeserializePipeline(class MemStreamReader& memReader, struct CachedPipeline& cachedPipeline);\n\nprivate:\n\tint CompilerThread();\n\tvoid WorkerThread();\n\n\tstd::thread* m_pipelineCacheStoreThread;\n\n\tstd::unordered_set<PipelineHash, PipelineHash::HashFunc> m_pipelineIsCached;\n\tFSpinlock m_pipelineIsCachedLock;\n\tclass FileCache* s_cache;\n\n\tstd::atomic_uint32_t m_numCompilationThreads{ 0 };\n\tConcurrentQueue<std::vector<uint8>> m_compilationQueue;\n\tstd::atomic_uint32_t m_compilationCount;\n};"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanQuery.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n\nclass LatteQueryObjectVk : public LatteQueryObject\n{\n\tfriend class VulkanRenderer;\n\n\tLatteQueryObjectVk(VulkanRenderer* rendererVk) : m_rendererVk(rendererVk) \n\t{\n\n\t};\n\n\tbool getResult(uint64& numSamplesPassed) override;\n\tvoid begin() override;\n\tvoid end() override;\n\tvoid beginFragment();\n\tvoid endFragment();\n\tvoid handleFinishedFragments();\n\n\tuint32 acquireQueryIndex();\n\tvoid releaseQueryIndex(uint32 queryIndex);\n\nprivate:\n\tstruct queryFragment \n\t{\n\t\tuint32 queryIndex;\n\t\tuint64 m_finishCommandBuffer;\n\t\tbool isFinished;\n\t};\n\n\tVulkanRenderer* m_rendererVk;\n\t//sint32 m_queryIndex;\n\tstd::vector<queryFragment> list_queryFragments;\n\tbool m_vkQueryEnded{};\n\tbool m_hasActiveQuery{};\n\tbool m_hasActiveFragment{};\n\tuint64 m_finishCommandBuffer;\n\tuint64 m_acccumulatedSum;\n};\n\nbool LatteQueryObjectVk::getResult(uint64& numSamplesPassed)\n{\n\tif (!m_vkQueryEnded)\n\t\treturn false;\n\tif (!m_rendererVk->HasCommandBufferFinished(m_finishCommandBuffer))\n\t\treturn false;\n\thandleFinishedFragments();\n\tcemu_assert_debug(list_queryFragments.empty());\n\tnumSamplesPassed = m_acccumulatedSum;\n\t//numSamplesPassed = m_rendererVk->m_occlusionQueries.ptrQueryResults[m_queryIndex];\n\treturn true;\n}\n\nvoid LatteQueryObjectVk::beginFragment()\n{\n\tm_rendererVk->draw_endRenderPass();\n\n\thandleFinishedFragments();\n\tuint32 newQueryIndex = acquireQueryIndex();\n\n\tqueryFragment qf{};\n\tqf.queryIndex = newQueryIndex;\n\tqf.isFinished = false;\n\tqf.m_finishCommandBuffer = 0;\n\tlist_queryFragments.emplace_back(qf);\n\n\n\tvkCmdResetQueryPool(m_rendererVk->m_state.currentCommandBuffer, m_rendererVk->m_occlusionQueries.queryPool, newQueryIndex, 1);\n\tvkCmdBeginQuery(m_rendererVk->m_state.currentCommandBuffer, m_rendererVk->m_occlusionQueries.queryPool, newQueryIndex, VK_QUERY_CONTROL_PRECISE_BIT);\n\t// todo - we already synchronize with command buffers, should we also set wait bits?\n\n\tm_hasActiveFragment = true;\n}\n\nvoid LatteQueryObjectVk::begin()\n{\n\tm_vkQueryEnded = false;\n\tm_hasActiveQuery = true;\n\tbeginFragment();\n}\n\nvoid LatteQueryObjectVk::endFragment()\n{\n\tm_rendererVk->draw_endRenderPass();\n\n\tcemu_assert_debug(m_hasActiveFragment);\n\tuint32 queryIndex = list_queryFragments.back().queryIndex;\n\tvkCmdEndQuery(m_rendererVk->m_state.currentCommandBuffer, m_rendererVk->m_occlusionQueries.queryPool, queryIndex);\n\n\tvkCmdCopyQueryPoolResults(m_rendererVk->m_state.currentCommandBuffer, m_rendererVk->m_occlusionQueries.queryPool, queryIndex, 1, m_rendererVk->m_occlusionQueries.bufferQueryResults, queryIndex * sizeof(uint64), 8, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);\n\tlist_queryFragments.back().m_finishCommandBuffer = m_rendererVk->GetCurrentCommandBufferId();\n\tlist_queryFragments.back().isFinished = true;\n\tm_hasActiveFragment = false;\n}\n\nvoid LatteQueryObjectVk::handleFinishedFragments()\n{\n\t// remove finished fragments and add to m_acccumulatedSum\n\twhile (!list_queryFragments.empty())\n\t{\n\t\tauto& it = list_queryFragments.front();\n\t\tif (!it.isFinished)\n\t\t\tbreak;\n\t\tif (!m_rendererVk->HasCommandBufferFinished(it.m_finishCommandBuffer))\n\t\t\tbreak;\n\t\tm_acccumulatedSum += m_rendererVk->m_occlusionQueries.ptrQueryResults[it.queryIndex];\n\t\treleaseQueryIndex(it.queryIndex);\n\t\tlist_queryFragments.erase(list_queryFragments.begin());\n\t}\n}\n\nuint32 LatteQueryObjectVk::acquireQueryIndex()\n{\n\tif (m_rendererVk->m_occlusionQueries.list_availableQueryIndices.empty())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Vulkan-Error: Exhausted query pool\");\n\t\tassert_dbg();\n\t}\n\tuint32 queryIndex = m_rendererVk->m_occlusionQueries.list_availableQueryIndices.back();\n\tm_rendererVk->m_occlusionQueries.list_availableQueryIndices.pop_back();\n\treturn queryIndex;\n}\n\nvoid LatteQueryObjectVk::releaseQueryIndex(uint32 queryIndex)\n{\n\tm_rendererVk->m_occlusionQueries.list_availableQueryIndices.emplace_back(queryIndex);\n}\n\nvoid LatteQueryObjectVk::end()\n{\n\tcemu_assert_debug(!list_queryFragments.empty());\n\tif(m_hasActiveFragment)\n\t\tendFragment();\n\tm_vkQueryEnded = true;\n\tm_hasActiveQuery = false;\n\tm_finishCommandBuffer = m_rendererVk->GetCurrentCommandBufferId();\n\tm_rendererVk->m_occlusionQueries.m_lastCommandBuffer = m_finishCommandBuffer;\n\tm_rendererVk->RequestSubmitSoon(); // make sure the current command buffer gets submitted soon\n\tm_rendererVk->RequestSubmitOnIdle();\n}\n\nLatteQueryObject* VulkanRenderer::occlusionQuery_create()\n{\n\t// create query pool if it doesn't already exist\n\tif(m_occlusionQueries.queryPool == VK_NULL_HANDLE)\n\t{ \n\t\tVkQueryPoolCreateInfo queryPoolCreateInfo{};\n\t\tqueryPoolCreateInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;\n\t\tqueryPoolCreateInfo.flags = 0;\n\t\tqueryPoolCreateInfo.queryType = VK_QUERY_TYPE_OCCLUSION;\n\t\tqueryPoolCreateInfo.queryCount = OCCLUSION_QUERY_POOL_SIZE;\n\t\tqueryPoolCreateInfo.pipelineStatistics = 0;\n\t\tauto r = vkCreateQueryPool(m_logicalDevice, &queryPoolCreateInfo, nullptr, &m_occlusionQueries.queryPool);\n\t\tif (r != VK_SUCCESS)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Vulkan-Error: Failed to create query pool with error {}\", (sint32)r);\n\t\t\treturn nullptr;\n\t\t}\n\t}\n\tLatteQueryObjectVk* queryObjVk = nullptr;\n\tif (m_occlusionQueries.list_cachedQueries.empty())\n\t{\n\t\tqueryObjVk = new LatteQueryObjectVk(this);\n\t}\n\telse\n\t{\n\t\tqueryObjVk = m_occlusionQueries.list_cachedQueries.front();\n\t\tm_occlusionQueries.list_cachedQueries.erase(m_occlusionQueries.list_cachedQueries.begin()+0);\n\t}\n\tqueryObjVk->queryEnded = false;\n\tqueryObjVk->queryEventStart = 0;\n\tqueryObjVk->queryEventEnd = 0;\n\tqueryObjVk->m_vkQueryEnded = false;\n\tqueryObjVk->m_acccumulatedSum = 0;\n\tcemu_assert_debug(queryObjVk->list_queryFragments.empty()); // query fragment list should always be cleared in _destroy()\n\tm_occlusionQueries.list_currentlyActiveQueries.emplace_back(queryObjVk);\n\treturn queryObjVk;\n}\n\nvoid VulkanRenderer::occlusionQuery_destroy(LatteQueryObject* queryObj)\n{\n\tLatteQueryObjectVk* queryObjVk = static_cast<LatteQueryObjectVk*>(queryObj);\n\tm_occlusionQueries.list_currentlyActiveQueries.erase(std::remove(m_occlusionQueries.list_currentlyActiveQueries.begin(), m_occlusionQueries.list_currentlyActiveQueries.end(), queryObj), m_occlusionQueries.list_currentlyActiveQueries.end());\n\tm_occlusionQueries.list_cachedQueries.emplace_back(queryObjVk);\n\tfor (auto& it : queryObjVk->list_queryFragments)\n\t\tqueryObjVk->releaseQueryIndex(it.queryIndex);\n\tqueryObjVk->list_queryFragments.clear();\n}\n\nvoid VulkanRenderer::occlusionQuery_flush()\n{\n\tWaitCommandBufferFinished(m_occlusionQueries.m_lastCommandBuffer);\n}\n\nvoid VulkanRenderer::occlusionQuery_updateState()\n{\n\t// check for finished command buffers here since query states are tied to buffers\n\tProcessFinishedCommandBuffers();\n}\n\nvoid VulkanRenderer::occlusionQuery_notifyEndCommandBuffer()\n{\n\tfor (auto& it : m_occlusionQueries.list_currentlyActiveQueries)\n\t\tif(it->m_hasActiveQuery)\n\t\t\tit->endFragment();\n}\n\nvoid VulkanRenderer::occlusionQuery_notifyBeginCommandBuffer()\n{\n\tfor (auto& it : m_occlusionQueries.list_currentlyActiveQueries)\n\t\tif (it->m_hasActiveQuery)\n\t\t\tit->beginFragment();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanTextureReadback.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Core/LatteOverlay.h\"\n\n#include \"Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h\"\n\n#include \"Cafe/CafeSystem.h\"\n\n#include \"util/helpers/helpers.h\"\n#include \"util/helpers/StringHelpers.h\"\n\n#include \"config/ActiveSettings.h\"\n#include \"config/CemuConfig.h\"\n#include \"WindowSystem.h\"\n\n#include \"imgui/imgui_extension.h\"\n#include \"imgui/imgui_impl_vulkan.h\"\n\n#include \"Cafe/TitleList/GameInfo.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteTiming.h\" // vsync control\n\n#include <cstdint>\n#include <glslang/Public/ShaderLang.h>\n\n#ifndef VK_API_VERSION_MAJOR\n#define VK_API_VERSION_MAJOR(version) (((uint32_t)(version) >> 22) & 0x7FU)\n#define VK_API_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3FFU)\n#endif\n\nextern std::atomic_int g_compiling_pipelines;\n\nconst  std::vector<const char*> kOptionalDeviceExtensions =\n{\n\tVK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME,\n\tVK_NV_FILL_RECTANGLE_EXTENSION_NAME,\n\tVK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME,\n\tVK_EXT_FILTER_CUBIC_EXTENSION_NAME, // not supported by any device yet\n\tVK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME,\n\tVK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,\n\tVK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME,\n\tVK_KHR_PRESENT_WAIT_EXTENSION_NAME,\n\tVK_KHR_PRESENT_ID_EXTENSION_NAME,\n\tVK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME,\n\tVK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME\n};\n\nconst std::vector<const char*> kRequiredDeviceExtensions =\n{\n\tVK_KHR_SWAPCHAIN_EXTENSION_NAME,\n\tVK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME\n}; // Intel doesnt support VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME\n\nVKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData)\n{\n#ifdef CEMU_DEBUG_ASSERT\n\n\tif (strstr(pCallbackData->pMessage, \"consumes input location\"))\n\t\treturn VK_FALSE; // false means we dont care\n\tif (strstr(pCallbackData->pMessage, \"blend\"))\n\t\treturn VK_FALSE; //\n\n\t// note: Check if previously used location in VK_EXT_debug_report callback is the same as messageIdNumber under the new extension\n\t// validation errors which are difficult to fix\n\tif (pCallbackData->messageIdNumber == 0x6c3b517c || pCallbackData->messageIdNumber == 0xffffffffa6b17cdf || pCallbackData->messageIdNumber == 0xffffffffc406fcb7)\n\t\treturn VK_FALSE; // its illegal to render to and sample from same texture\n\tif (pCallbackData->messageIdNumber == 0x6e633069)\n\t\treturn VK_FALSE; // framebuffer attachments should have identity swizzle\n\tif (pCallbackData->messageIdNumber == 0xffffffffb408bc0b)\n\t\treturn VK_FALSE; // too many samplers\n\n\tif (pCallbackData->messageIdNumber == 0x6bbb14)\n\t\treturn VK_FALSE; // SPIR-V inconsistency\n\n\tif (strstr(pCallbackData->pMessage, \"Number of currently valid sampler objects is not less than the maximum allowed\"))\n\t\treturn VK_FALSE;\n\n#endif\n\n\tcemuLog_log(LogType::Force, (char*)pCallbackData->pMessage);\n\n\treturn VK_FALSE;\n}\n\nstd::vector<VulkanRenderer::DeviceInfo> VulkanRenderer::GetDevices()\n{\n    if(!vkEnumerateInstanceVersion)\n    {\n        cemuLog_log(LogType::Force, \"Vulkan cant list devices because Vulkan loader failed\");\n        return {};\n    }\n\tuint32 apiVersion = VK_API_VERSION_1_1;\n\tif (vkEnumerateInstanceVersion(&apiVersion) != VK_SUCCESS)\n\t{\n\t\tif (VK_API_VERSION_MAJOR(apiVersion) < 1 || VK_API_VERSION_MINOR(apiVersion) < 2)\n\t\t\tapiVersion = VK_API_VERSION_1_1;\n\t}\n\n\tstd::vector<DeviceInfo> result;\n\n\tstd::vector<const char*> requiredExtensions;\n\trequiredExtensions.clear();\n\trequiredExtensions.emplace_back(VK_KHR_SURFACE_EXTENSION_NAME);\n\t#if BOOST_OS_WINDOWS\n\trequiredExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);\n\t#elif BOOST_OS_LINUX || BOOST_OS_BSD\n\tauto backend = WindowSystem::GetWindowInfo().window_main.backend;\n\tif(backend == WindowSystem::WindowHandleInfo::Backend::X11)\n\t\trequiredExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);\n\t#ifdef HAS_WAYLAND\n\telse if (backend == WindowSystem::WindowHandleInfo::Backend::Wayland)\n\t\trequiredExtensions.emplace_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);\n\t#endif\n\t#elif BOOST_OS_MACOS\n\trequiredExtensions.emplace_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);\n\t#endif\n\n\tVkApplicationInfo app_info{};\n\tapp_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;\n\tapp_info.pApplicationName = EMULATOR_NAME;\n\tapp_info.applicationVersion = VK_MAKE_VERSION(EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH);\n\tapp_info.pEngineName = EMULATOR_NAME;\n\tapp_info.engineVersion = app_info.applicationVersion;\n\tapp_info.apiVersion = apiVersion;\n\n\tVkInstanceCreateInfo create_info{};\n\tcreate_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;\n\tcreate_info.pApplicationInfo = &app_info;\n\tcreate_info.ppEnabledExtensionNames = requiredExtensions.data();\n\tcreate_info.enabledExtensionCount = requiredExtensions.size();\n\tcreate_info.ppEnabledLayerNames = nullptr;\n\tcreate_info.enabledLayerCount = 0;\n\n\tVkInstance instance = nullptr;\n\ttry\n\t{\n\t\tVkResult err;\n\t\tif ((err = vkCreateInstance(&create_info, nullptr, &instance)) != VK_SUCCESS)\n\t\t\tthrow std::runtime_error(fmt::format(\"Unable to create a Vulkan instance: {}\", err));\n\n\t\tif (!InitializeInstanceVulkan(instance))\n\t\t\tthrow std::runtime_error(\"can't initialize instanced vulkan functions\");\n\n\t\tuint32_t device_count = 0;\n\t\tvkEnumeratePhysicalDevices(instance, &device_count, nullptr);\n\t\tif (device_count == 0)\n\t\t\tthrow std::runtime_error(\"Failed to find a GPU with Vulkan support.\");\n\n\t\t// create tmp surface to create a logical device\n\t\tauto surface = CreateFramebufferSurface(instance, WindowSystem::GetWindowInfo().window_main);\n\t\tstd::vector<VkPhysicalDevice> devices(device_count);\n\t\tvkEnumeratePhysicalDevices(instance, &device_count, devices.data());\n\t\tfor (const auto& device : devices)\n\t\t{\n\t\t\tif (IsDeviceSuitable(surface, device))\n\t\t\t{\n\t\t\t\tVkPhysicalDeviceIDProperties physDeviceIDProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES };\n\t\t\t\tVkPhysicalDeviceProperties2 physDeviceProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };\n\t\t\t\tphysDeviceProps.pNext = &physDeviceIDProps;\n\t\t\t\tvkGetPhysicalDeviceProperties2(device, &physDeviceProps);\n\n\t\t\t\tresult.emplace_back(physDeviceProps.properties.deviceName, physDeviceIDProps.deviceUUID);\n\t\t\t}\n\t\t}\n\t\tvkDestroySurfaceKHR(instance, surface, nullptr);\n\t}\n\tcatch (...)\n\t{\n\t}\n\n\tif (instance)\n\t\tvkDestroyInstance(instance, nullptr);\n\n\treturn result;\n\n}\n\nvoid VulkanRenderer::DetermineVendor()\n{\n\tVkPhysicalDeviceProperties2 properties{};\n\tVkPhysicalDeviceDriverProperties driverProperties{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES };\n\tproperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;\n\tif (m_featureControl.deviceExtensions.driver_properties)\n\t\tproperties.pNext = &driverProperties;\n\n\tvkGetPhysicalDeviceProperties2(m_physicalDevice, &properties);\n\tswitch (properties.properties.vendorID)\n\t{\n\tcase 0x10DE:\n\t\tm_vendor = GfxVendor::Nvidia;\n\t\tbreak;\n\tcase 0x8086: // iGPU\n\t\tm_vendor = GfxVendor::Intel;\n\t\tbreak;\n\tcase 0x1002:\n\t\tm_vendor = GfxVendor::AMD;\n\t\tbreak;\n\tcase 0x106B:\n\t\tm_vendor = GfxVendor::Apple;\n\t\tbreak;\n\t}\n\n\tVkDriverId driverId = driverProperties.driverID;\n\n\tif(driverId == VK_DRIVER_ID_MESA_RADV || driverId == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA)\n\t\tm_vendor = GfxVendor::Mesa;\n\n\tcemuLog_log(LogType::Force, \"Using GPU: {}\", properties.properties.deviceName);\n\n\tif (m_featureControl.deviceExtensions.driver_properties)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Driver version: {}\", driverProperties.driverInfo);\n\n\t\tif(m_vendor == GfxVendor::Nvidia)\n\t\t{\n\t\t\t// multithreaded pipelines on nvidia (requires 515 or higher)\n\t\t\tm_featureControl.disableMultithreadedCompilation = (StringHelpers::ToInt(std::string(driverProperties.driverInfo)) < 515);\n\t\t}\n\t}\n\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"Driver version (as stored in device info): {:08}\", properties.properties.driverVersion);\n\n\t\tif(m_vendor == GfxVendor::Nvidia)\n\t\t{\n\t\t\t// if the driver does not support the extension,\n\t\t\t// it is assumed the driver is under version 515\n\t\t\tm_featureControl.disableMultithreadedCompilation = true;\n\t\t}\n\t}\n}\n\nvoid VulkanRenderer::GetDeviceFeatures()\n{\n\t/* Get Vulkan features via GetPhysicalDeviceFeatures2 */\n\tvoid* prevStruct = nullptr;\n\tVkPhysicalDeviceCustomBorderColorFeaturesEXT bcf{};\n\tbcf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;\n\tbcf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;\n\tprevStruct = &bcf;\n\n\tVkPhysicalDevicePipelineCreationCacheControlFeaturesEXT pcc{};\n\tpcc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT;\n\tpcc.pNext = prevStruct;\n\tprevStruct = &pcc;\n\n\tVkPhysicalDevicePresentIdFeaturesKHR pidf{};\n\tpidf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR;\n\tpidf.pNext = prevStruct;\n\tprevStruct = &pidf;\n\n\tVkPhysicalDevicePresentWaitFeaturesKHR pwf{};\n\tpwf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR;\n\tpwf.pNext = prevStruct;\n\tprevStruct = &pwf;\n\n\tVkPhysicalDevicePipelineRobustnessFeaturesEXT pprf{};\n\tif (m_featureControl.deviceExtensions.pipeline_robustness)\n\t{\n\t\tpprf.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT;\n\t\tpprf.pNext = prevStruct;\n\t\tprevStruct = &pprf;\n\t}\n\n\tVkPhysicalDeviceFeatures2 physicalDeviceFeatures2{};\n\tphysicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;\n\tphysicalDeviceFeatures2.pNext = prevStruct;\n\n\tvkGetPhysicalDeviceFeatures2(m_physicalDevice, &physicalDeviceFeatures2);\n\n\tcemuLog_log(LogType::Force, \"Vulkan: present_wait extension: {}\", (pwf.presentWait && pidf.presentId) ? \"supported\" : \"unsupported\");\n\n\t/* Get Vulkan device properties and limits */\n\tVkPhysicalDeviceFloatControlsPropertiesKHR pfcp{};\n\tprevStruct = nullptr;\n\tif (m_featureControl.deviceExtensions.shader_float_controls)\n\t{\n\t\tpfcp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR;\n\t\tpfcp.pNext = prevStruct;\n\t\tprevStruct = &pfcp;\n\t}\n\n\tVkPhysicalDeviceProperties2 prop2{};\n\tprop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;\n\tprop2.pNext = prevStruct;\n\n\tvkGetPhysicalDeviceProperties2(m_physicalDevice, &prop2);\n\n\t/* Determine which subfeatures we can use */\n\n\tm_featureControl.deviceExtensions.pipeline_creation_cache_control = pcc.pipelineCreationCacheControl;\n\tm_featureControl.deviceExtensions.custom_border_color_without_format = m_featureControl.deviceExtensions.custom_border_color && bcf.customBorderColorWithoutFormat;\n\tm_featureControl.shaderFloatControls.shaderRoundingModeRTEFloat32 = m_featureControl.deviceExtensions.shader_float_controls && pfcp.shaderRoundingModeRTEFloat32;\n\tif(!m_featureControl.shaderFloatControls.shaderRoundingModeRTEFloat32)\n\t\tcemuLog_log(LogType::Force, \"Shader round mode control not available on this device or driver. Some rendering issues might occur.\");\n\n\tif (!m_featureControl.deviceExtensions.pipeline_creation_cache_control)\n\t{\n\t\tcemuLog_log(LogType::Force, \"VK_EXT_pipeline_creation_cache_control not supported. Cannot use asynchronous shader and pipeline compilation\");\n\t\t// if async shader compilation is enabled show warning message\n\t\tif (GetConfig().async_compile)\n\t\t\tLatteOverlay_pushNotification(_tr(\"Async shader compile is enabled but not supported by the graphics driver\\nCemu will use synchronous compilation which can cause additional stutter\"), 10000);\n\t}\n\tif (!m_featureControl.deviceExtensions.custom_border_color_without_format)\n\t{\n\t\tif (m_featureControl.deviceExtensions.custom_border_color)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"VK_EXT_custom_border_color is present but only with limited support. Cannot emulate arbitrary border color\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"VK_EXT_custom_border_color not supported. Cannot emulate arbitrary border color\");\n\t\t}\n\t}\n\tif (!m_featureControl.deviceExtensions.depth_clip_enable)\n\t{\n\t\tcemuLog_log(LogType::Force, \"VK_EXT_depth_clip_enable not supported\");\n\t}\n\tif (m_featureControl.deviceExtensions.pipeline_robustness)\n\t{\n\t\tif ( pprf.pipelineRobustness != VK_TRUE )\n\t\t\tm_featureControl.deviceExtensions.pipeline_robustness = false;\n\t}\n\t// get limits\n\tm_featureControl.limits.minUniformBufferOffsetAlignment = std::max(prop2.properties.limits.minUniformBufferOffsetAlignment, (VkDeviceSize)4);\n\tm_featureControl.limits.nonCoherentAtomSize = std::max(prop2.properties.limits.nonCoherentAtomSize, (VkDeviceSize)4);\n\tcemuLog_log(LogType::Force, fmt::format(\"VulkanLimits: UBAlignment {0} nonCoherentAtomSize {1}\", prop2.properties.limits.minUniformBufferOffsetAlignment, prop2.properties.limits.nonCoherentAtomSize));\n}\n\nVulkanRenderer::VulkanRenderer()\n{\n\tglslang::InitializeProcess();\n\n\tcemuLog_log(LogType::Force, \"------- Init Vulkan graphics backend -------\");\n\n\tconst bool useValidationLayer = cemuLog_isLoggingEnabled(LogType::VulkanValidation);\n\tif (useValidationLayer)\n\t\tcemuLog_log(LogType::Force, \"Validation layer is enabled\");\n\n\tVkResult err;\n\n\t// build list of layers\n\tm_layerNames.clear();\n\tif (useValidationLayer)\n\t\tm_layerNames.emplace_back(\"VK_LAYER_KHRONOS_validation\");\n\n\t// check available instance extensions\n\tstd::vector<const char*> enabledInstanceExtensions = CheckInstanceExtensionSupport(m_featureControl);\n\n\tuint32 apiVersion = VK_API_VERSION_1_1;\n\tif (vkEnumerateInstanceVersion(&apiVersion) != VK_SUCCESS)\n\t{\n\t\tif (VK_API_VERSION_MAJOR(apiVersion) < 1 || VK_API_VERSION_MINOR(apiVersion) < 2)\n\t\t\tapiVersion = VK_API_VERSION_1_1;\n\t}\n\n\tcemuLog_log(LogType::Force, fmt::format(\"Vulkan instance version: {}.{}\", VK_API_VERSION_MAJOR(apiVersion), VK_API_VERSION_MINOR(apiVersion)));\n\n\tVkApplicationInfo app_info{};\n\tapp_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;\n\tapp_info.pApplicationName = EMULATOR_NAME;\n\tapp_info.applicationVersion = VK_MAKE_VERSION(EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH);\n\tapp_info.pEngineName = EMULATOR_NAME;\n\tapp_info.engineVersion = app_info.applicationVersion;\n\tapp_info.apiVersion = apiVersion;\n\n\tVkInstanceCreateInfo create_info{};\n\tcreate_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;\n\tcreate_info.pApplicationInfo = &app_info;\n\tcreate_info.ppEnabledExtensionNames = enabledInstanceExtensions.data();\n\tcreate_info.enabledExtensionCount = enabledInstanceExtensions.size();\n\tcreate_info.ppEnabledLayerNames = m_layerNames.data();\n\tcreate_info.enabledLayerCount = m_layerNames.size();\n\n\terr = vkCreateInstance(&create_info, nullptr, &m_instance);\n\n\tif (err == VK_ERROR_LAYER_NOT_PRESENT) {\n\t\tcemuLog_log(LogType::Force, \"Failed to enable vulkan validation (VK_LAYER_KHRONOS_validation)\");\n\t\tcreate_info.enabledLayerCount = 0;\n\t\terr = vkCreateInstance(&create_info, nullptr, &m_instance);\n\t}\n\n\tif (err != VK_SUCCESS)\n\t\tthrow std::runtime_error(fmt::format(\"Unable to create a Vulkan instance: {}\", err));\n\n\tif (!InitializeInstanceVulkan(m_instance))\n\t\tthrow std::runtime_error(\"Unable to load instanced Vulkan functions\");\n\n\tuint32_t device_count = 0;\n\tvkEnumeratePhysicalDevices(m_instance, &device_count, nullptr);\n\tif (device_count == 0)\n\t\tthrow std::runtime_error(\"Failed to find a GPU with Vulkan support.\");\n\n\t// create tmp surface to create a logical device\n\tauto surface = CreateFramebufferSurface(m_instance, WindowSystem::GetWindowInfo().window_main);\n\n\tauto& config = GetConfig();\n\tdecltype(config.vk_graphic_device_uuid) zero{};\n\tconst bool has_device_set = config.vk_graphic_device_uuid != zero;\n\n\tVkPhysicalDevice fallbackDevice = VK_NULL_HANDLE;\n\n\tstd::vector<VkPhysicalDevice> devices(device_count);\n\tvkEnumeratePhysicalDevices(m_instance, &device_count, devices.data());\n\tfor (const auto& device : devices)\n\t{\n\t\tif (IsDeviceSuitable(surface, device))\n\t\t{\n\t\t\tif (fallbackDevice == VK_NULL_HANDLE)\n\t\t\t\tfallbackDevice = device;\n\n\t\t\tif (has_device_set)\n\t\t\t{\n\t\t\t\tVkPhysicalDeviceIDProperties physDeviceIDProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES };\n\t\t\t\tVkPhysicalDeviceProperties2 physDeviceProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };\n\t\t\t\tphysDeviceProps.pNext = &physDeviceIDProps;\n\t\t\t\tvkGetPhysicalDeviceProperties2(device, &physDeviceProps);\n\n\t\t\t\tif (memcmp(config.vk_graphic_device_uuid.data(), physDeviceIDProps.deviceUUID, VK_UUID_SIZE) != 0)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tm_physicalDevice = device;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (m_physicalDevice == VK_NULL_HANDLE && fallbackDevice != VK_NULL_HANDLE)\n\t{\n\t\tcemuLog_log(LogType::Force, \"The selected GPU could not be found or is not suitable. Falling back to first available device instead\");\n\t\tm_physicalDevice = fallbackDevice;\n\t\tconfig.vk_graphic_device_uuid = {}; // resetting device selection\n\t}\n\telse if (m_physicalDevice == VK_NULL_HANDLE)\n\t{\n\t\tcemuLog_log(LogType::Force, \"No physical GPU could be found with the required extensions and swap chain support.\");\n\t\tthrow std::runtime_error(\"No physical GPU could be found with the required extensions and swap chain support.\");\n\t}\n\n\tCheckDeviceExtensionSupport(m_physicalDevice, m_featureControl); // todo - merge this with GetDeviceFeatures and separate from IsDeviceSuitable?\n\n\tDetermineVendor();\n\tGetDeviceFeatures();\n\n\t// init memory manager\n\tmemoryManager.reset(new VKRMemoryManager(this));\n\n\ttry\n\t{\n\t\tVkPhysicalDeviceIDProperties physDeviceIDProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES };\n\t\tVkPhysicalDeviceProperties2 physDeviceProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };\n\t\tphysDeviceProps.pNext = &physDeviceIDProps;\n\t\tvkGetPhysicalDeviceProperties2(m_physicalDevice, &physDeviceProps);\n\n\t\t#if BOOST_OS_WINDOWS\n\t\tm_dxgi_wrapper = std::make_unique<DXGIWrapper>(physDeviceIDProps.deviceLUID);\n\t\t#endif\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"can't create dxgi wrapper: {}\", ex.what());\n\t}\n\n\t// create logical device\n\tm_indices = FindQueueFamilies(surface, m_physicalDevice);\n\tstd::set<int> uniqueQueueFamilies = { m_indices.graphicsFamily, m_indices.presentFamily };\n\tstd::vector<VkDeviceQueueCreateInfo> queueCreateInfos = CreateQueueCreateInfos(uniqueQueueFamilies);\n\tVkPhysicalDeviceFeatures deviceFeatures = {};\n\n\tdeviceFeatures.independentBlend = VK_TRUE;\n\tdeviceFeatures.samplerAnisotropy = VK_TRUE;\n\tdeviceFeatures.imageCubeArray = VK_TRUE;\n\t//moltenVK supports logicOp via private api\n\tdeviceFeatures.logicOp = VK_TRUE;\n#if !BOOST_OS_MACOS\n\tdeviceFeatures.geometryShader = VK_TRUE;\n#endif\n\tdeviceFeatures.occlusionQueryPrecise = VK_TRUE;\n\tdeviceFeatures.depthClamp = VK_TRUE;\n\tdeviceFeatures.depthBiasClamp = VK_TRUE;\n\n\tif (m_featureControl.deviceExtensions.pipeline_robustness)\n\t{\n\t\tdeviceFeatures.robustBufferAccess = VK_FALSE;\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"VK_EXT_pipeline_robustness not supported. Falling back to robustBufferAccess\");\n\t\tdeviceFeatures.robustBufferAccess = VK_TRUE;\n\t}\n\n\tif (m_featureControl.mode.useTFEmulationViaSSBO)\n\t{\n\t\tdeviceFeatures.vertexPipelineStoresAndAtomics = true;\n\t}\n\n\tvoid* deviceExtensionFeatures = nullptr;\n\n\t// enable VK_EXT_pipeline_creation_cache_control\n\tVkPhysicalDevicePipelineCreationCacheControlFeaturesEXT cacheControlFeature{};\n\tif (m_featureControl.deviceExtensions.pipeline_creation_cache_control)\n\t{\n\t\tcacheControlFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT;\n\t\tcacheControlFeature.pNext = deviceExtensionFeatures;\n\t\tdeviceExtensionFeatures = &cacheControlFeature;\n\t\tcacheControlFeature.pipelineCreationCacheControl = VK_TRUE;\n\t}\n\t// enable VK_EXT_custom_border_color\n\tVkPhysicalDeviceCustomBorderColorFeaturesEXT customBorderColorFeature{};\n\tif (m_featureControl.deviceExtensions.custom_border_color_without_format)\n\t{\n\t\tcustomBorderColorFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;\n\t\tcustomBorderColorFeature.pNext = deviceExtensionFeatures;\n\t\tdeviceExtensionFeatures = &customBorderColorFeature;\n\t\tcustomBorderColorFeature.customBorderColors = VK_TRUE;\n\t\tcustomBorderColorFeature.customBorderColorWithoutFormat = VK_TRUE;\n\t}\n\t// enable VK_KHR_present_id\n\tVkPhysicalDevicePresentIdFeaturesKHR presentIdFeature{};\n\tif(m_featureControl.deviceExtensions.present_wait)\n\t{\n\t\tpresentIdFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR;\n\t\tpresentIdFeature.pNext = deviceExtensionFeatures;\n\t\tdeviceExtensionFeatures = &presentIdFeature;\n\t\tpresentIdFeature.presentId = VK_TRUE;\n\t}\n\t// enable VK_KHR_present_wait\n\tVkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeature{};\n\tif(m_featureControl.deviceExtensions.present_wait)\n\t{\n\t\tpresentWaitFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR;\n\t\tpresentWaitFeature.pNext = deviceExtensionFeatures;\n\t\tdeviceExtensionFeatures = &presentWaitFeature;\n\t\tpresentWaitFeature.presentWait = VK_TRUE;\n\t}\n\t// enable VK_EXT_pipeline_robustness\n\tVkPhysicalDevicePipelineRobustnessFeaturesEXT pipelineRobustnessFeature{};\n\tif (m_featureControl.deviceExtensions.pipeline_robustness)\n\t{\n\t\tpipelineRobustnessFeature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT;\n\t\tpipelineRobustnessFeature.pNext = deviceExtensionFeatures;\n\t\tdeviceExtensionFeatures = &pipelineRobustnessFeature;\n\t\tpipelineRobustnessFeature.pipelineRobustness = VK_TRUE;\n\t}\n\n\tstd::vector<const char*> used_extensions;\n\tVkDeviceCreateInfo createInfo = CreateDeviceCreateInfo(queueCreateInfos, deviceFeatures, deviceExtensionFeatures, used_extensions);\n\n\tVkResult result = vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_logicalDevice);\n\tif (result != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Vulkan: Unable to create a logical device. Error {}\", (sint32)result);\n\t\tthrow std::runtime_error(fmt::format(\"Unable to create a logical device: {}\", result));\n\t}\n\n\tInitializeDeviceVulkan(m_logicalDevice);\n\n\tvkGetDeviceQueue(m_logicalDevice, m_indices.graphicsFamily, 0, &m_graphicsQueue);\n\tvkGetDeviceQueue(m_logicalDevice, m_indices.graphicsFamily, 0, &m_presentQueue);\n\n\tvkDestroySurfaceKHR(m_instance, surface, nullptr);\n\n\tif (useValidationLayer && m_featureControl.instanceExtensions.debug_utils)\n\t{\n\t\tPFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(m_instance, \"vkCreateDebugUtilsMessengerEXT\"));\n\n\t\tVkDebugUtilsMessengerCreateInfoEXT debugCallback{};\n\t\tdebugCallback.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;\n\t\tdebugCallback.pNext = nullptr;\n\t\tdebugCallback.flags = 0;\n\t\tdebugCallback.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;\n\t\tdebugCallback.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;\n\t\tdebugCallback.pfnUserCallback = &DebugUtilsCallback;\n\n\t\tvkCreateDebugUtilsMessengerEXT(m_instance, &debugCallback, nullptr, &m_debugCallback);\n\n\t\tcemuLog_log(LogType::Force, \"Debug: Vulkan validation layer enabled, vkCreateDebugUtilsMessengerEXT will be used to log validation errors\");\n\t}\n\n\tif (this->IsTracingToolEnabled())\n\t\tcemuLog_log(LogType::Force, \"Debug: Tracing tool detected, will recompile all shaders with debug info enabled. This disables the SPIR-V cache.\");\n\tif (this->IsDebugMarkersEnabled())\n\t\tcemuLog_log(LogType::Force, \"Debug: Detected tool capable of using debug markers, will use vkDebugMarkerSetObjectNameEXT to identify Vulkan objects\");\n\n\t// set initial viewport and scissor box size\n\tm_state.currentViewport.width = 4;\n\tm_state.currentViewport.height = 4;\n\tm_state.currentScissorRect.extent.width = 4;\n\tm_state.currentScissorRect.extent.height = 4;\n\n\tQueryMemoryInfo();\n\tQueryAvailableFormats();\n\tCreateCommandPool();\n\tCreateCommandBuffers();\n\tCreateDescriptorPool();\n\tswapchain_createDescriptorSetLayout();\n\n\t// extension info\n\t// cemuLog_log(LogType::Force, \"VK_KHR_dynamic_rendering: {}\", m_featureControl.deviceExtensions.dynamic_rendering?\"supported\":\"not supported\");\n\n\tvoid* bufferPtr;\n\t// init ringbuffer for uniform vars\n\tm_uniformVarBufferMemoryIsCoherent = false;\n\tif (memoryManager->CreateBuffer(UNIFORMVAR_RINGBUFFER_SIZE, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_uniformVarBuffer, m_uniformVarBufferMemory))\n\t\tm_uniformVarBufferMemoryIsCoherent = true;\n\telse if (memoryManager->CreateBuffer(UNIFORMVAR_RINGBUFFER_SIZE, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_uniformVarBuffer, m_uniformVarBufferMemory))\n\t\tm_uniformVarBufferMemoryIsCoherent = true; // unified memory\n\telse if (memoryManager->CreateBuffer(UNIFORMVAR_RINGBUFFER_SIZE, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, m_uniformVarBuffer, m_uniformVarBufferMemory))\n\t\tm_uniformVarBufferMemoryIsCoherent = true;\n\telse if (memoryManager->CreateBuffer(UNIFORMVAR_RINGBUFFER_SIZE, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, m_uniformVarBuffer, m_uniformVarBufferMemory))\n\t\tm_uniformVarBufferMemoryIsCoherent = true;\n\telse\n\t{\n\t\tmemoryManager->CreateBuffer(UNIFORMVAR_RINGBUFFER_SIZE, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, m_uniformVarBuffer, m_uniformVarBufferMemory);\n\t}\n\n\tif (!m_uniformVarBufferMemoryIsCoherent)\n\t\tcemuLog_log(LogType::Force, \"[Vulkan-Info] Using non-coherent memory for uniform data\");\n\tbufferPtr = nullptr;\n\tvkMapMemory(m_logicalDevice, m_uniformVarBufferMemory, 0, VK_WHOLE_SIZE, 0, &bufferPtr);\n\tm_uniformVarBufferPtr = (uint8*)bufferPtr;\n\n\t// texture readback buffer\n\tif (!memoryManager->CreateBuffer(TEXTURE_READBACK_SIZE, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_textureReadbackBuffer, m_textureReadbackBufferMemory))\n\t{\n\t\tmemoryManager->CreateBuffer(TEXTURE_READBACK_SIZE, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_textureReadbackBuffer, m_textureReadbackBufferMemory);\n\t}\n\tbufferPtr = nullptr;\n\tvkMapMemory(m_logicalDevice, m_textureReadbackBufferMemory, 0, VK_WHOLE_SIZE, 0, &bufferPtr);\n\tm_textureReadbackBufferPtr = (uint8*)bufferPtr;\n\n\t// transform feedback ringbuffer\n\tmemoryManager->CreateBuffer(LatteStreamout_GetRingBufferSize(), VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | (m_featureControl.mode.useTFEmulationViaSSBO ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : 0), 0, m_xfbRingBuffer, m_xfbRingBufferMemory);\n\n\t// occlusion query result buffer\n\tif (!memoryManager->CreateBuffer(OCCLUSION_QUERY_POOL_SIZE * sizeof(uint64), VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_occlusionQueries.bufferQueryResults, m_occlusionQueries.memoryQueryResults))\n\t{\n\t\tmemoryManager->CreateBuffer(OCCLUSION_QUERY_POOL_SIZE * sizeof(uint64), VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, m_occlusionQueries.bufferQueryResults, m_occlusionQueries.memoryQueryResults);\n\t}\n\tbufferPtr = nullptr;\n\tvkMapMemory(m_logicalDevice, m_occlusionQueries.memoryQueryResults, 0, VK_WHOLE_SIZE, 0, &bufferPtr);\n\tm_occlusionQueries.ptrQueryResults = (uint64*)bufferPtr;\n\n\tfor (sint32 i = 0; i < OCCLUSION_QUERY_POOL_SIZE; i++)\n\t\tm_occlusionQueries.list_availableQueryIndices.emplace_back(i);\n\n\t// start compilation threads\n\tRendererShaderVk::Init(); // shaders\n\tPipelineCompiler::CompileThreadPool_Start(); // pipelines\n}\n\nVulkanRenderer::~VulkanRenderer()\n{\n\tSubmitCommandBuffer();\n\tWaitDeviceIdle();\n\tWaitCommandBufferFinished(GetCurrentCommandBufferId());\n\t// shut down pipeline save thread\n\tm_destructionRequested = true;\n\tm_pipeline_cache_semaphore.notify();\n\tm_pipeline_cache_save_thread.join();\n\n\tvkDestroyPipelineCache(m_logicalDevice, m_pipeline_cache, nullptr);\n\n\tif(!m_backbufferBlitDescriptorSetCache.empty())\n\t{\n\t\tstd::vector<VkDescriptorSet> freeVector;\n\t\tfreeVector.reserve(m_backbufferBlitDescriptorSetCache.size());\n\t\tstd::transform(m_backbufferBlitDescriptorSetCache.begin(), m_backbufferBlitDescriptorSetCache.end(), std::back_inserter(freeVector), [](auto& i) {\n\t\t  return i.second;\n\t\t});\n\t\tvkFreeDescriptorSets(m_logicalDevice, m_descriptorPool, freeVector.size(), freeVector.data());\n\t}\n\n\tvkDestroyDescriptorPool(m_logicalDevice, m_descriptorPool, nullptr);\n\n\tfor(auto& i : m_backbufferBlitPipelineCache)\n\t{\n\t\tvkDestroyPipeline(m_logicalDevice, i.second, nullptr);\n\t}\n\tm_backbufferBlitPipelineCache = {};\n\n\tif(m_occlusionQueries.queryPool != VK_NULL_HANDLE)\n\t\tvkDestroyQueryPool(m_logicalDevice, m_occlusionQueries.queryPool, nullptr);\n\n\tvkDestroyDescriptorSetLayout(m_logicalDevice, m_swapchainDescriptorSetLayout, nullptr);\n\n\t// shut down imgui\n\tImGui_ImplVulkan_Shutdown();\n\n\t// delete null objects\n\tDeleteNullObjects();\n\n\t// delete buffers\n\tmemoryManager->DeleteBuffer(m_uniformVarBuffer, m_uniformVarBufferMemory);\n\tmemoryManager->DeleteBuffer(m_textureReadbackBuffer, m_textureReadbackBufferMemory);\n\tmemoryManager->DeleteBuffer(m_xfbRingBuffer, m_xfbRingBufferMemory);\n\tmemoryManager->DeleteBuffer(m_occlusionQueries.bufferQueryResults, m_occlusionQueries.memoryQueryResults);\n\tmemoryManager->DeleteBuffer(m_bufferCache, m_bufferCacheMemory);\n\n\tm_padSwapchainInfo = nullptr;\n\tm_mainSwapchainInfo = nullptr;\n\n\t// clean up resources used for surface copy\n\tsurfaceCopy_cleanup();\n\n\t// clean up default shaders\n\tdelete defaultShaders.copySurface_vs;\n\tdefaultShaders.copySurface_vs = nullptr;\n\tdelete defaultShaders.copySurface_psColor2Depth;\n\tdefaultShaders.copySurface_psColor2Depth = nullptr;\n\tdelete defaultShaders.copySurface_psDepth2Color;\n\tdefaultShaders.copySurface_psDepth2Color = nullptr;\n\n\t// destroy misc\n\tfor (auto& it : m_cmd_buffer_fences)\n\t{\n\t\tvkDestroyFence(m_logicalDevice, it, nullptr);\n\t\tit = VK_NULL_HANDLE;\n\t}\n\n\tfor(auto& sem : m_commandBufferSemaphores)\n\t{\n\t\tvkDestroySemaphore(m_logicalDevice, sem, nullptr);\n\t\tsem = VK_NULL_HANDLE;\n\t}\n\n\tif (m_pipelineLayout != VK_NULL_HANDLE)\n\t\tvkDestroyPipelineLayout(m_logicalDevice, m_pipelineLayout, nullptr);\n\n\tif (m_commandPool != VK_NULL_HANDLE)\n\t\tvkDestroyCommandPool(m_logicalDevice, m_commandPool, nullptr);\n\n\tVKRObjectSampler::DestroyCache();\n\n\t// destroy debug callback\n\tif (m_debugCallback)\n\t{\n\t\tPFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(m_instance, \"vkDestroyDebugUtilsMessengerEXT\"));\n\t\tvkDestroyDebugUtilsMessengerEXT(m_instance, m_debugCallback, nullptr);\n\t}\n\n\twhile(!m_destructionQueue.empty())\n\t\tProcessDestructionQueue();\n\n\t// destroy memory manager\n\tmemoryManager.reset();\n\n\t// destroy instance, devices\n\tif (m_instance != VK_NULL_HANDLE)\n\t{\n\t\tif (m_logicalDevice != VK_NULL_HANDLE)\n\t\t{\n\t\t\tvkDestroyDevice(m_logicalDevice, nullptr);\n\t\t}\n\n\t\tvkDestroyInstance(m_instance, nullptr);\n\t}\n\n\t// crashes?\n\t//glslang::FinalizeProcess();\n}\n\nVulkanRenderer* VulkanRenderer::GetInstance()\n{\n#ifdef CEMU_DEBUG_ASSERT\n\tcemu_assert_debug(g_renderer && dynamic_cast<VulkanRenderer*>(g_renderer.get()));\n\t// Use #if here because dynamic_casts dont get optimized away even if the result is not stored as with cemu_assert_debug\n#endif\n\treturn (VulkanRenderer*)g_renderer.get();\n}\n\nvoid VulkanRenderer::InitializeSurface(const Vector2i& size, bool mainWindow)\n{\n\tif (mainWindow)\n\t{\n\t\tm_mainSwapchainInfo = std::make_unique<SwapchainInfoVk>(mainWindow, size);\n\t\tm_mainSwapchainInfo->Create();\n\t}\n\telse\n\t{\n\t\tm_padSwapchainInfo = std::make_unique<SwapchainInfoVk>(mainWindow, size);\n\t\t// todo: figure out a way to exclusively create swapchain on main LatteThread\n\t\tm_padSwapchainInfo->Create();\n\t}\n}\n\nconst std::unique_ptr<SwapchainInfoVk>& VulkanRenderer::GetChainInfoPtr(bool mainWindow) const\n{\n\treturn mainWindow ? m_mainSwapchainInfo : m_padSwapchainInfo;\n}\n\nSwapchainInfoVk& VulkanRenderer::GetChainInfo(bool mainWindow) const\n{\n\treturn *GetChainInfoPtr(mainWindow);\n}\n\nvoid VulkanRenderer::StopUsingPadAndWait()\n{\n\tm_destroyPadSwapchainNextAcquire.test_and_set();\n\tm_destroyPadSwapchainNextAcquire.wait(true);\n}\n\nbool VulkanRenderer::IsPadWindowActive()\n{\n\treturn IsSwapchainInfoValid(false);\n}\n\nvoid VulkanRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool padView)\n{\n\tif (!m_screenshot_requested && m_screenshot_state == ScreenshotState::None)\n\t\treturn;\n\n\tif (IsSwapchainInfoValid(false))\n\t{\n\t\t// we already took a pad view screenshow and want a main window screenshot\n\t\tif (m_screenshot_state == ScreenshotState::Main && padView)\n\t\t\treturn;\n\n\t\tif (m_screenshot_state == ScreenshotState::Pad && !padView)\n\t\t\treturn;\n\n\t\t// remember which screenshot is left to take\n\t\tif (m_screenshot_state == ScreenshotState::None)\n\t\t\tm_screenshot_state = padView ? ScreenshotState::Main : ScreenshotState::Pad;\n\t\telse\n\t\t\tm_screenshot_state = ScreenshotState::None;\n\t}\n\telse\n\t\tm_screenshot_state = ScreenshotState::None;\n\n\tauto texViewVk = (LatteTextureViewVk*)texView;\n\tauto baseImageTex = texViewVk->GetBaseImage();\n\n\tauto textureVk = baseImageTex->GetImageObj();\n\ttextureVk->flagForCurrentCommandBuffer();\n\n\tauto dumpImage = textureVk->m_image;\n\tauto baseImage = dumpImage;\n\n\tint width, height;\n\tbaseImageTex->GetEffectiveSize(width, height, 0);\n\n\tVkImage image = nullptr;\n\tVkDeviceMemory imageMemory = nullptr;\n\n\tif (texViewVk->firstMip != 0)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to capture screenshot: capturing non-zero mip is not supported\");\n\t\treturn;\n\t}\n\n\tauto format = baseImageTex->GetFormat();\n\tif (format != VK_FORMAT_R8G8B8A8_UNORM && format != VK_FORMAT_R8G8B8A8_SRGB && format != VK_FORMAT_R8G8B8_UNORM && format != VK_FORMAT_R8G8B8_SNORM)\n\t{\n\t\tVkFormatProperties formatProps;\n\t\tvkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, &formatProps);\n\t\tbool supportsBlit = (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) != 0;\n\n\t\tconst bool dstUsesSRGB = (!padView && LatteGPUState.tvBufferUsesSRGB) || (padView && LatteGPUState.drcBufferUsesSRGB);\n\t\tconst auto blitFormat = dstUsesSRGB ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;\n\n\t\tvkGetPhysicalDeviceFormatProperties(m_physicalDevice, blitFormat, &formatProps);\n\t\tsupportsBlit &= (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) != 0;\n\n\t\tif (!supportsBlit)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Screenshot failed: Framebuffer is not in RGB8 format and blitting is unsupported\");\n\t\t\treturn;\n\t\t}\n\n\t\t// convert texture using blitting\n\t\tVkImageCreateInfo imageInfo{};\n\t\timageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n\t\timageInfo.format = blitFormat;\n\t\timageInfo.extent = {(uint32)width, (uint32)height, 1};\n\t\timageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\t\timageInfo.samples = VK_SAMPLE_COUNT_1_BIT;\n\t\timageInfo.arrayLayers = 1;\n\t\timageInfo.mipLevels = 1;\n\t\timageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;\n\t\timageInfo.imageType = VK_IMAGE_TYPE_2D;\n\t\timageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\t\timageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;\n\n\t\tif (vkCreateImage(m_logicalDevice, &imageInfo, nullptr, &image) != VK_SUCCESS)\n\t\t\treturn;\n\n\t\tVkMemoryRequirements memRequirements;\n\t\tvkGetImageMemoryRequirements(m_logicalDevice, image, &memRequirements);\n\n\t\tVkMemoryAllocateInfo allocInfo{};\n\t\tallocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n\t\tallocInfo.allocationSize = memRequirements.size;\n\t\tuint32 memIndex;\n\t\tbool foundMemory = memoryManager->FindMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, memIndex);\n\t\tif (!foundMemory)\n\t\t{\n\t\t\tvkDestroyImage(m_logicalDevice, image, nullptr);\n\t\t\tcemuLog_log(LogType::Force, \"Screenshot request failed due to incompatible vulkan memory types.\");\n\t\t\treturn;\n\t\t}\n\t\tallocInfo.memoryTypeIndex = memIndex;\n\n\t\tif (vkAllocateMemory(m_logicalDevice, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS)\n\t\t{\n\t\t\tvkDestroyImage(m_logicalDevice, image, nullptr);\n\t\t\tcemuLog_log(LogType::Force, \"Screenshot request failed due to failed memory allocation.\");\n\t\t\treturn;\n\t\t}\n\n\t\tvkBindImageMemory(m_logicalDevice, image, imageMemory, 0);\n\n\t\t// prepare dst image for blitting\n\t\t{\n\t\t\tVkImageSubresourceRange range;\n\t\t\trange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\t\trange.baseMipLevel = 0;\n\t\t\trange.levelCount = 1;\n\t\t\trange.baseArrayLayer = 0;\n\t\t\trange.layerCount = 1;\n\t\t\t// TRANSFER_READ is here only to silence validation as srcStageMask = 0 is only supported when using synchronization2\n\t\t\tbarrier_image<TRANSFER_READ, TRANSFER_WRITE>(image, range, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);\n\t\t}\n\t\t// prepare src image for blitting\n\t\t{\n\t\t\tVkImageSubresourceLayers range;\n\t\t\trange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\t\trange.mipLevel = 0;\n\t\t\trange.baseArrayLayer = texViewVk->firstSlice;\n\t\t\trange.layerCount = 1;\n\t\t\tbarrier_image<IMAGE_WRITE | TRANSFER_WRITE, SYNC_OP::TRANSFER_READ>(baseImageTex, range, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);\n\t\t}\n\n\t\tVkOffset3D blitSize{width, height, 1};\n\t\tVkImageBlit imageBlitRegion{};\n\t\timageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\timageBlitRegion.srcSubresource.mipLevel = 0;\n\t\timageBlitRegion.srcSubresource.baseArrayLayer = texViewVk->firstSlice;\n\t\timageBlitRegion.srcSubresource.layerCount = 1;\n\t\timageBlitRegion.srcOffsets[1] = blitSize;\n\n\t\timageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\timageBlitRegion.dstSubresource.mipLevel = 0;\n\t\timageBlitRegion.dstSubresource.baseArrayLayer = 0;\n\t\timageBlitRegion.dstSubresource.layerCount = 1;\n\t\timageBlitRegion.dstOffsets[1] = blitSize;\n\n\t\t// Issue the blit command\n\t\tvkCmdBlitImage(m_state.currentCommandBuffer, dumpImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageBlitRegion, VK_FILTER_NEAREST);\n\n\t\t// dest image to general layout\n\t\t{\n\t\t\tVkImageSubresourceRange range;\n\t\t\trange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\t\trange.baseMipLevel = 0;\n\t\t\trange.levelCount = 1;\n\t\t\trange.baseArrayLayer = 0;\n\t\t\trange.layerCount = 1;\n\t\t\tbarrier_image<TRANSFER_WRITE, TRANSFER_READ>(image, range, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL);\n\t\t}\n\t\t// transition image back\n\t\t{\n\t\t\tVkImageSubresourceLayers range;\n\t\t\trange.aspectMask = baseImageTex->GetImageAspect();\n\t\t\trange.mipLevel = 0;\n\t\t\trange.baseArrayLayer = texViewVk->firstSlice;\n\t\t\trange.layerCount = 1;\n\t\t\tbarrier_image<TRANSFER_READ, TRANSFER_WRITE | IMAGE_WRITE>(baseImageTex, range, VK_IMAGE_LAYOUT_GENERAL);\n\t\t}\n\n\t\tformat = VK_FORMAT_R8G8B8A8_UNORM;\n\t\tdumpImage = image;\n\t}\n\n\tuint32 size;\n\tswitch (format)\n\t{\n\tcase VK_FORMAT_R8G8B8A8_UNORM:\n\tcase VK_FORMAT_R8G8B8A8_SRGB:\n\t\tsize = 4 * width * height;\n\t\tbreak;\n\tcase VK_FORMAT_R8G8B8_UNORM:\n\tcase VK_FORMAT_R8G8B8_SRGB:\n\t\tsize = 3 * width * height;\n\t\tbreak;\n\tdefault:\n\t\tsize = 0;\n\t}\n\n\tif (size == 0)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\n\tVkBufferImageCopy region{};\n\tregion.bufferOffset = 0;\n\tregion.bufferRowLength = width;\n\tregion.bufferImageHeight = height;\n\n\tregion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\tregion.imageSubresource.baseArrayLayer = 0;\n\tregion.imageSubresource.layerCount = 1;\n\tregion.imageSubresource.mipLevel = 0;\n\n\tregion.imageOffset = { 0,0,0 };\n\tregion.imageExtent = { (uint32)width,(uint32)height,1 };\n\n\tvoid* bufferPtr = nullptr;\n\n\tVkBuffer buffer = nullptr;\n\tVkDeviceMemory bufferMemory = nullptr;\n\tmemoryManager->CreateBuffer(size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, buffer, bufferMemory);\n\tvkMapMemory(m_logicalDevice, bufferMemory, 0, VK_WHOLE_SIZE, 0, &bufferPtr);\n\n\t// if no blit was necessary a barrier still needs to be inserted and slice may not be zero\n\tif (dumpImage == baseImage)\n\t{\n\t\tregion.imageSubresource.baseArrayLayer = texViewVk->firstSlice;\n\t\tbarrier_image<IMAGE_WRITE | TRANSFER_WRITE, TRANSFER_READ>(baseImageTex, region.imageSubresource, VK_IMAGE_LAYOUT_GENERAL);\n\t}\n\n\tvkCmdCopyImageToBuffer(m_state.currentCommandBuffer, dumpImage, VK_IMAGE_LAYOUT_GENERAL, buffer, 1, &region);\n\n\tSubmitCommandBuffer();\n\tWaitCommandBufferFinished(GetCurrentCommandBufferId());\n\n\tbool formatValid = true;\n\n\tstd::vector<uint8> rgb_data;\n\trgb_data.reserve(3 * width * height);\n\n\tswitch (format)\n\t{\n\tcase VK_FORMAT_R8G8B8A8_UNORM:\n\t\tfor (auto ptr = (uint8*)bufferPtr; ptr < (uint8*)bufferPtr + size; ptr += 4)\n\t\t{\n\t\t\trgb_data.emplace_back(*ptr);\n\t\t\trgb_data.emplace_back(*(ptr + 1));\n\t\t\trgb_data.emplace_back(*(ptr + 2));\n\t\t}\n\t\tbreak;\n\tcase VK_FORMAT_R8G8B8A8_SRGB:\n\t\tfor (auto ptr = (uint8*)bufferPtr; ptr < (uint8*)bufferPtr + size; ptr += 4)\n\t\t{\n\t\t\trgb_data.emplace_back(SRGBComponentToRGB(*ptr));\n\t\t\trgb_data.emplace_back(SRGBComponentToRGB(*(ptr + 1)));\n\t\t\trgb_data.emplace_back(SRGBComponentToRGB(*(ptr + 2)));\n\t\t}\n\t\tbreak;\n\tcase VK_FORMAT_R8G8B8_UNORM:\n\t\tstd::copy((uint8*)bufferPtr, (uint8*)bufferPtr + size, rgb_data.begin());\n\t\tbreak;\n\tcase VK_FORMAT_R8G8B8_SRGB:\n\t\tstd::transform((uint8*)bufferPtr, (uint8*)bufferPtr + size, rgb_data.begin(), SRGBComponentToRGB);\n\t\tbreak;\n\tdefault:\n\t\tformatValid = false;\n\t\tcemu_assert_debug(false);\n\t}\n\n\tvkUnmapMemory(m_logicalDevice, bufferMemory);\n\tvkFreeMemory(m_logicalDevice, bufferMemory, nullptr);\n\tvkDestroyBuffer(m_logicalDevice, buffer, nullptr);\n\n\tif (image)\n\t\tvkDestroyImage(m_logicalDevice, image, nullptr);\n\tif (imageMemory)\n\t\tvkFreeMemory(m_logicalDevice, imageMemory, nullptr);\n\n\tif (formatValid)\n\t\tSaveScreenshot(rgb_data, width, height, !padView);\n}\n\nstatic const float kQueuePriority = 1.0f;\n\nstd::vector<VkDeviceQueueCreateInfo> VulkanRenderer::CreateQueueCreateInfos(const std::set<sint32>& uniqueQueueFamilies) const\n{\n\tstd::vector<VkDeviceQueueCreateInfo> queueCreateInfos;\n\n\tfor (int queueFamily : uniqueQueueFamilies)\n\t{\n\t\tVkDeviceQueueCreateInfo queueCreateInfo{};\n\t\tqueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;\n\t\tqueueCreateInfo.queueFamilyIndex = queueFamily;\n\t\tqueueCreateInfo.queueCount = 1;\n\t\tqueueCreateInfo.pQueuePriorities = &kQueuePriority;\n\t\tqueueCreateInfos.emplace_back(queueCreateInfo);\n\t}\n\n\treturn queueCreateInfos;\n}\n\nVkDeviceCreateInfo VulkanRenderer::CreateDeviceCreateInfo(const std::vector<VkDeviceQueueCreateInfo>& queueCreateInfos, const VkPhysicalDeviceFeatures& deviceFeatures, const void* deviceExtensionStructs, std::vector<const char*>& used_extensions) const\n{\n\tused_extensions = kRequiredDeviceExtensions;\n\tif (m_featureControl.deviceExtensions.tooling_info)\n\t\tused_extensions.emplace_back(VK_EXT_TOOLING_INFO_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.depth_range_unrestricted)\n\t\tused_extensions.emplace_back(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.nv_fill_rectangle)\n\t\tused_extensions.emplace_back(VK_NV_FILL_RECTANGLE_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.pipeline_feedback)\n\t\tused_extensions.emplace_back(VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.cubic_filter)\n\t\tused_extensions.emplace_back(VK_EXT_FILTER_CUBIC_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.custom_border_color)\n\t\tused_extensions.emplace_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.driver_properties)\n\t\tused_extensions.emplace_back(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.external_memory_host)\n\t\tused_extensions.emplace_back(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.synchronization2)\n\t\tused_extensions.emplace_back(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.dynamic_rendering)\n\t\tused_extensions.emplace_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.shader_float_controls)\n\t\tused_extensions.emplace_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.depth_clip_enable)\n\t\tused_extensions.emplace_back(VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME);\n\tif (m_featureControl.deviceExtensions.present_wait)\n\t{\n\t\tused_extensions.emplace_back(VK_KHR_PRESENT_ID_EXTENSION_NAME);\n\t\tused_extensions.emplace_back(VK_KHR_PRESENT_WAIT_EXTENSION_NAME);\n\t}\n\tif (m_featureControl.deviceExtensions.pipeline_robustness)\n\t\tused_extensions.emplace_back(VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME);\n\n\tVkDeviceCreateInfo createInfo{};\n\tcreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;\n\tcreateInfo.pQueueCreateInfos = queueCreateInfos.data();\n\tcreateInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size();\n\tcreateInfo.pEnabledFeatures = &deviceFeatures;\n\tcreateInfo.enabledExtensionCount = used_extensions.size();\n\tcreateInfo.ppEnabledExtensionNames = used_extensions.data();\n\n\tcreateInfo.pNext = deviceExtensionStructs;\n\n\tif (!m_layerNames.empty())\n\t{\n\t\tcreateInfo.enabledLayerCount = m_layerNames.size();\n\t\tcreateInfo.ppEnabledLayerNames = m_layerNames.data();\n\t}\n\n\treturn createInfo;\n}\n\nRendererShader* VulkanRenderer::shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader)\n{\n\treturn new RendererShaderVk(type, baseHash, auxHash, isGameShader, isGfxPackShader, source);\n}\n\nVulkanRenderer::QueueFamilyIndices VulkanRenderer::FindQueueFamilies(VkSurfaceKHR surface, VkPhysicalDevice device)\n{\n\tuint32_t queueFamilyCount = 0;\n\tvkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);\n\n\tstd::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);\n\tvkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());\n\n\tQueueFamilyIndices indices;\n\tfor (int i = 0; i < (int)queueFamilies.size(); ++i)\n\t{\n\t\tconst auto& queueFamily = queueFamilies[i];\n\t\tif (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)\n\t\t\tindices.graphicsFamily = i;\n\n\t\tVkBool32 presentSupport = false;\n\t\tconst VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);\n\t\tif (result != VK_SUCCESS)\n\t\t\tthrow std::runtime_error(fmt::format(\"Error while attempting to check if a surface supports presentation: {}\", result));\n\n\t\tif (queueFamily.queueCount > 0 && presentSupport)\n\t\t\tindices.presentFamily = i;\n\n\t\tif (indices.IsComplete())\n\t\t\tbreak;\n\t}\n\n\treturn indices;\n}\n\nbool VulkanRenderer::CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info)\n{\n\tstd::vector<VkExtensionProperties> availableDeviceExtensions;\n\n\tauto isExtensionAvailable = [&availableDeviceExtensions](const char* extensionName) -> bool\n\t{\n\t\treturn std::find_if(availableDeviceExtensions.begin(), availableDeviceExtensions.end(),\n\t\t\t[&extensionName](const VkExtensionProperties& prop) -> bool\n\t\t{\n\t\t\treturn strcmp(prop.extensionName, extensionName) == 0;\n\t\t}) != availableDeviceExtensions.cend();\n\t};\n\n\tuint32_t extensionCount;\n\tVkResult result = vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);\n\tif (result != VK_SUCCESS)\n\t\tthrow std::runtime_error(fmt::format(\"Cannot retrieve count of properties for a physical device: {}\", result));\n\n\tavailableDeviceExtensions.resize(extensionCount);\n\tresult = vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableDeviceExtensions.data());\n\tif (result != VK_SUCCESS)\n\t\tthrow std::runtime_error(fmt::format(\"Cannot retrieve properties for a physical device: {}\", result));\n\n\tstd::set<std::string> requiredExtensions(kRequiredDeviceExtensions.begin(), kRequiredDeviceExtensions.end());\n\tfor (const auto& extension : availableDeviceExtensions)\n\t{\n\t\trequiredExtensions.erase(extension.extensionName);\n\t}\n\n\tinfo.deviceExtensions.tooling_info = isExtensionAvailable(VK_EXT_TOOLING_INFO_EXTENSION_NAME);\n\tinfo.deviceExtensions.transform_feedback = isExtensionAvailable(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME);\n\tinfo.deviceExtensions.depth_range_unrestricted = isExtensionAvailable(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);\n\tinfo.deviceExtensions.nv_fill_rectangle = isExtensionAvailable(VK_NV_FILL_RECTANGLE_EXTENSION_NAME);\n\tinfo.deviceExtensions.pipeline_feedback = isExtensionAvailable(VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME);\n\tinfo.deviceExtensions.cubic_filter = isExtensionAvailable(VK_EXT_FILTER_CUBIC_EXTENSION_NAME);\n\tinfo.deviceExtensions.custom_border_color = isExtensionAvailable(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);\n\tinfo.deviceExtensions.driver_properties = isExtensionAvailable(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME);\n\tinfo.deviceExtensions.external_memory_host = isExtensionAvailable(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME);\n\tinfo.deviceExtensions.synchronization2 = isExtensionAvailable(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);\n\tinfo.deviceExtensions.shader_float_controls = isExtensionAvailable(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);\n\tinfo.deviceExtensions.dynamic_rendering = false; // isExtensionAvailable(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);\n\tinfo.deviceExtensions.depth_clip_enable = isExtensionAvailable(VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME);\n\tinfo.deviceExtensions.pipeline_robustness = isExtensionAvailable(VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME);\n\t// dynamic rendering doesn't provide any benefits for us right now. Driver implementations are very unoptimized as of Feb 2022\n\tinfo.deviceExtensions.present_wait = isExtensionAvailable(VK_KHR_PRESENT_WAIT_EXTENSION_NAME) && isExtensionAvailable(VK_KHR_PRESENT_ID_EXTENSION_NAME);\n\n\t// check for validation layers and frame debuggers\n\tinfo.usingDebugMarkerTool = false;\n\tinfo.usingTracingTool = false;\n\tif (info.deviceExtensions.tooling_info && vkGetPhysicalDeviceToolPropertiesEXT)\n\t{\n\t\tuint32_t toolCount = 0;\n\t\tif (vkGetPhysicalDeviceToolPropertiesEXT(device, &toolCount, nullptr) == VK_SUCCESS)\n\t\t{\n\t\t\tstd::vector<VkPhysicalDeviceToolPropertiesEXT> toolProperties(toolCount);\n\t\t\tif (toolCount > 0 && vkGetPhysicalDeviceToolPropertiesEXT(device, &toolCount, toolProperties.data()) == VK_SUCCESS)\n\t\t\t{\n\t\t\t\tfor (auto& itr : toolProperties)\n\t\t\t\t{\n\t\t\t\t\tif ((itr.purposes & VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT) != 0 && info.instanceExtensions.debug_utils && vkSetDebugUtilsObjectNameEXT)\n\t\t\t\t\t\tinfo.usingDebugMarkerTool = true;\n\t\t\t\t\tif ((itr.purposes & VK_TOOL_PURPOSE_TRACING_BIT) != 0)\n\t\t\t\t\t\tinfo.usingTracingTool = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn requiredExtensions.empty();\n}\n\nstd::vector<const char*> VulkanRenderer::CheckInstanceExtensionSupport(FeatureControl& info)\n{\n\tstd::vector<VkExtensionProperties> availableInstanceExtensions;\n\tstd::vector<const char*> enabledInstanceExtensions;\n\tVkResult err;\n\n\tauto isExtensionAvailable = [&availableInstanceExtensions](const char* extensionName) -> bool\n\t{\n\t\treturn std::find_if(availableInstanceExtensions.begin(), availableInstanceExtensions.end(),\n\t\t\t[&extensionName](const VkExtensionProperties& prop) -> bool\n\t\t{\n\t\t\treturn strcmp(prop.extensionName, extensionName) == 0;\n\t\t}) != availableInstanceExtensions.cend();\n\t};\n\n\t// get list of available instance extensions\n\tuint32_t count;\n\tif ((err = vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr)) != VK_SUCCESS)\n\t\tthrow std::runtime_error(fmt::format(\"Failed to retrieve the instance extension properties : {}\", err));\n\n\tavailableInstanceExtensions.resize(count);\n\tif ((err = vkEnumerateInstanceExtensionProperties(nullptr, &count, availableInstanceExtensions.data())) != VK_SUCCESS)\n\t\tthrow std::runtime_error(fmt::format(\"Failed to retrieve the instance extension properties: {}\", err));\n\n\t// build list of required extensions\n\tstd::vector<const char*> requiredInstanceExtensions;\n\trequiredInstanceExtensions.emplace_back(VK_KHR_SURFACE_EXTENSION_NAME);\n\t#if BOOST_OS_WINDOWS\n\trequiredInstanceExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);\n\t#elif BOOST_OS_LINUX || BOOST_OS_BSD\n\tauto backend = WindowSystem::GetWindowInfo().window_main.backend;\n\tif(backend == WindowSystem::WindowHandleInfo::Backend::X11)\n\t\trequiredInstanceExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);\n\t#if HAS_WAYLAND\n\telse if (backend == WindowSystem::WindowHandleInfo::Backend::Wayland)\n\t\trequiredInstanceExtensions.emplace_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);\n\t#endif\n\t#elif BOOST_OS_MACOS\n\trequiredInstanceExtensions.emplace_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);\n\t#endif\n\tif (cemuLog_isLoggingEnabled(LogType::VulkanValidation))\n\t\trequiredInstanceExtensions.emplace_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);\n\n\t// make sure all required extensions are supported\n\tfor (const auto& extension : availableInstanceExtensions)\n\t{\n\t\tfor (auto it = requiredInstanceExtensions.begin(); it < requiredInstanceExtensions.end(); ++it)\n\t\t{\n\t\t\tif (strcmp(*it, extension.extensionName) == 0)\n\t\t\t{\n\t\t\t\tenabledInstanceExtensions.emplace_back(*it);\n\t\t\t\trequiredInstanceExtensions.erase(it);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tif (!requiredInstanceExtensions.empty())\n\t{\n\t\tcemuLog_log(LogType::Force, \"The following required Vulkan instance extensions are not supported:\");\n\n\t\tstd::stringstream ss;\n\t\tfor (const auto& extension : requiredInstanceExtensions)\n\t\t\tcemuLog_log(LogType::Force, \"{}\", extension);\n\t\tcemuLog_waitForFlush();\n\t\tthrow std::runtime_error(ss.str());\n\t}\n\n\t// check for optional extensions\n\tinfo.instanceExtensions.debug_utils = isExtensionAvailable(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);\n\tif (info.instanceExtensions.debug_utils)\n\t\tenabledInstanceExtensions.emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);\n\treturn enabledInstanceExtensions;\n}\n\nbool VulkanRenderer::IsDeviceSuitable(VkSurfaceKHR surface, const VkPhysicalDevice& device)\n{\n\tif (!FindQueueFamilies(surface, device).IsComplete())\n\t\treturn false;\n\n\t// check API version (using Vulkan 1.0 way of querying properties)\n\tVkPhysicalDeviceProperties properties{};\n\tvkGetPhysicalDeviceProperties(device, &properties);\n\tuint32 vkVersionMajor = VK_API_VERSION_MAJOR(properties.apiVersion);\n\tuint32 vkVersionMinor = VK_API_VERSION_MINOR(properties.apiVersion);\n\tif (vkVersionMajor < 1 || (vkVersionMajor == 1 && vkVersionMinor < 1))\n\t\treturn false; // minimum required version is Vulkan 1.1\n\n\tFeatureControl info;\n\tif (!CheckDeviceExtensionSupport(device, info))\n\t\treturn false;\n\n\tconst auto swapchainSupport = SwapchainInfoVk::QuerySwapchainSupport(surface, device);\n\n\treturn !swapchainSupport.formats.empty() && !swapchainSupport.presentModes.empty();\n}\n\n#if BOOST_OS_WINDOWS\nVkSurfaceKHR VulkanRenderer::CreateWinSurface(VkInstance instance, HWND hwindow)\n{\n\tVkWin32SurfaceCreateInfoKHR sci{};\n\tsci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;\n\tsci.hwnd = hwindow;\n\tsci.hinstance = GetModuleHandle(nullptr);\n\n\tVkSurfaceKHR result;\n\tVkResult err;\n\tif ((err = vkCreateWin32SurfaceKHR(instance, &sci, nullptr, &result)) != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Cannot create a Win32 Vulkan surface: {}\", (sint32)err);\n\t\tthrow std::runtime_error(fmt::format(\"Cannot create a Win32 Vulkan surface: {}\", err));\n\t}\n\n\treturn result;\n}\n#endif\n\n#if BOOST_OS_LINUX || BOOST_OS_BSD\nVkSurfaceKHR VulkanRenderer::CreateXlibSurface(VkInstance instance, Display* dpy, Window window)\n{\n    VkXlibSurfaceCreateInfoKHR sci{};\n    sci.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;\n    sci.flags = 0;\n\tsci.dpy = dpy;\n    sci.window = window;\n\n    VkSurfaceKHR result;\n    VkResult err;\n    if ((err = vkCreateXlibSurfaceKHR(instance, &sci, nullptr, &result)) != VK_SUCCESS)\n    {\n\t\tcemuLog_log(LogType::Force, \"Cannot create a X11 Vulkan surface: {}\", (sint32)err);\n        throw std::runtime_error(fmt::format(\"Cannot create a X11 Vulkan surface: {}\", err));\n    }\n\n    return result;\n}\n\nVkSurfaceKHR VulkanRenderer::CreateXcbSurface(VkInstance instance, xcb_connection_t* connection, xcb_window_t window)\n{\n    VkXcbSurfaceCreateInfoKHR sci{};\n    sci.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;\n    sci.flags = 0;\n    sci.connection = connection;\n    sci.window = window;\n\n    VkSurfaceKHR result;\n    VkResult err;\n    if ((err = vkCreateXcbSurfaceKHR(instance, &sci, nullptr, &result)) != VK_SUCCESS)\n    {\n        cemuLog_log(LogType::Force, \"Cannot create a XCB Vulkan surface: {}\", (sint32)err);\n        throw std::runtime_error(fmt::format(\"Cannot create a XCB Vulkan surface: {}\", err));\n    }\n\n    return result;\n}\n#ifdef HAS_WAYLAND\nVkSurfaceKHR VulkanRenderer::CreateWaylandSurface(VkInstance instance, wl_display* display, wl_surface* surface)\n{\n    VkWaylandSurfaceCreateInfoKHR sci{};\n    sci.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;\n    sci.flags = 0;\n\tsci.display = display;\n\tsci.surface = surface;\n\n    VkSurfaceKHR result;\n    VkResult err;\n    if ((err = vkCreateWaylandSurfaceKHR(instance, &sci, nullptr, &result)) != VK_SUCCESS)\n    {\n        cemuLog_log(LogType::Force, \"Cannot create a Wayland Vulkan surface: {}\", (sint32)err);\n        throw std::runtime_error(fmt::format(\"Cannot create a Wayland Vulkan surface: {}\", err));\n    }\n\n    return result;\n}\n#endif // HAS_WAYLAND\n#endif // BOOST_OS_LINUX\n\nVkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, WindowSystem::WindowHandleInfo& windowInfo)\n{\n#if BOOST_OS_WINDOWS\n\treturn CreateWinSurface(instance, static_cast<HWND>(windowInfo.surface));\n#elif BOOST_OS_LINUX || BOOST_OS_BSD\n\tif(windowInfo.backend == WindowSystem::WindowHandleInfo::Backend::X11)\n\t\treturn CreateXlibSurface(instance, static_cast<Display*>(windowInfo.display), reinterpret_cast<Window>(windowInfo.surface));\n\t#ifdef HAS_WAYLAND\n\tif(windowInfo.backend == WindowSystem::WindowHandleInfo::Backend::Wayland)\n\t\treturn CreateWaylandSurface(instance, static_cast<wl_display*>(windowInfo.display), static_cast<wl_surface*>(windowInfo.surface));\n\t#endif\n\treturn {};\n#elif BOOST_OS_MACOS\n\treturn CreateCocoaSurface(instance, windowInfo.surface);\n#endif\n}\n\nvoid VulkanRenderer::CreateCommandPool()\n{\n\tVkCommandPoolCreateInfo poolInfo{};\n\tpoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;\n\tpoolInfo.queueFamilyIndex = m_indices.graphicsFamily;\n\tpoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;\n\n\tVkResult result = vkCreateCommandPool(m_logicalDevice, &poolInfo, nullptr, &m_commandPool);\n\tif (result != VK_SUCCESS)\n\t\tthrow std::runtime_error(fmt::format(\"Failed to create command pool: {}\", result));\n}\n\nvoid VulkanRenderer::CreateCommandBuffers()\n{\n\tauto it = m_cmd_buffer_fences.begin();\n\tVkFenceCreateInfo fenceInfo{};\n\tfenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n\tvkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &*it);\n\n\t++it;\n\tfenceInfo.flags = 0;\n\tfor (; it != m_cmd_buffer_fences.end(); ++it)\n\t{\n\t\tvkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &*it);\n\t}\n\n\tVkCommandBufferAllocateInfo allocInfo = {};\n\tallocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;\n\tallocInfo.commandPool = m_commandPool;\n\tallocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n\tallocInfo.commandBufferCount = (uint32_t)m_commandBuffers.size();\n\n\tconst VkResult result = vkAllocateCommandBuffers(m_logicalDevice, &allocInfo, m_commandBuffers.data());\n\tif (result != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to allocate command buffers: {}\", result);\n\t\tthrow std::runtime_error(fmt::format(\"Failed to allocate command buffers: {}\", result));\n\t}\n\n\tfor (auto& semItr : m_commandBufferSemaphores)\n\t{\n\t\tVkSemaphoreCreateInfo info = {};\n\t\tinfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n\t\tif (vkCreateSemaphore(m_logicalDevice, &info, nullptr, &semItr) != VK_SUCCESS)\n\t\t\tUnrecoverableError(\"Failed to create semaphore for command buffer\");\n\t}\n}\n\nbool VulkanRenderer::IsSwapchainInfoValid(bool mainWindow) const\n{\n\tauto& chainInfo = GetChainInfoPtr(mainWindow);\n\treturn chainInfo && chainInfo->IsValid();\n}\n\n\nvoid VulkanRenderer::CreateNullTexture(NullTexture& nullTex, VkImageType imageType)\n{\n\t// these are used when the game requests NULL ptr textures\n\tVkImageCreateInfo imageInfo{};\n\timageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n\tif (imageType == VK_IMAGE_TYPE_1D)\n\t{\n\t\timageInfo.extent.width = 4;\n\t\timageInfo.extent.height = 1;\n\t}\n\telse if (imageType == VK_IMAGE_TYPE_2D)\n\t{\n\t\timageInfo.extent.width = 4;\n\t\timageInfo.extent.height = 1;\n\t}\n\telse\n\t{\n\t\tcemu_assert(false);\n\t}\n\timageInfo.mipLevels = 1;\n\timageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;\n\timageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\timageInfo.samples = VK_SAMPLE_COUNT_1_BIT;\n\timageInfo.extent.depth = 1;\n\timageInfo.arrayLayers = 1;\n\timageInfo.imageType = imageType;\n\timageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;\n\tif (vkCreateImage(m_logicalDevice, &imageInfo, nullptr, &nullTex.image) != VK_SUCCESS)\n\t\tUnrecoverableError(\"Failed to create nullTex image\");\n\tnullTex.allocation = memoryManager->imageMemoryAllocate(nullTex.image);\n\n\tVkClearColorValue clrColor{};\n\tClearColorImageRaw(nullTex.image, 0, 0, clrColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);\n\t// texture view\n\tVkImageViewCreateInfo viewInfo{};\n\tviewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n\tviewInfo.image = nullTex.image;\n\tif (imageType == VK_IMAGE_TYPE_1D)\n\t\tviewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;\n\telse if (imageType == VK_IMAGE_TYPE_2D)\n\t\tviewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;\n\telse\n\t{\n\t\tcemu_assert(false);\n\t}\n\tviewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;\n\tviewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\tviewInfo.subresourceRange.baseMipLevel = 0;\n\tviewInfo.subresourceRange.levelCount = 1;\n\tviewInfo.subresourceRange.baseArrayLayer = 0;\n\tviewInfo.subresourceRange.layerCount = 1;\n\tif (vkCreateImageView(m_logicalDevice, &viewInfo, nullptr, &nullTex.view) != VK_SUCCESS)\n\t\tUnrecoverableError(\"Failed to create nullTex image view\");\n\t// sampler\n\tVkSamplerCreateInfo samplerInfo{};\n\tsamplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n\tsamplerInfo.magFilter = VK_FILTER_LINEAR;\n\tsamplerInfo.minFilter = VK_FILTER_LINEAR;\n\tsamplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n\tsamplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n\tsamplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n\tsamplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n\tsamplerInfo.mipLodBias = 0.0f;\n\tsamplerInfo.compareOp = VK_COMPARE_OP_NEVER;\n\tsamplerInfo.minLod = 0.0f;\n\tsamplerInfo.maxLod = 0.0f;\n\tsamplerInfo.maxAnisotropy = 1.0;\n\tsamplerInfo.anisotropyEnable = VK_FALSE;\n\tsamplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;\n\tvkCreateSampler(m_logicalDevice, &samplerInfo, nullptr, &nullTex.sampler);\n}\n\nvoid VulkanRenderer::CreateNullObjects()\n{\n\tCreateNullTexture(nullTexture1D, VK_IMAGE_TYPE_1D);\n\tCreateNullTexture(nullTexture2D, VK_IMAGE_TYPE_2D);\n}\n\nvoid VulkanRenderer::DeleteNullTexture(NullTexture& nullTex)\n{\n\tvkDestroySampler(m_logicalDevice, nullTex.sampler, nullptr);\n\tnullTex.sampler = VK_NULL_HANDLE;\n\tvkDestroyImageView(m_logicalDevice, nullTex.view, nullptr);\n\tnullTex.view = VK_NULL_HANDLE;\n\tvkDestroyImage(m_logicalDevice, nullTex.image, nullptr);\n\tnullTex.image = VK_NULL_HANDLE;\n\tmemoryManager->imageMemoryFree(nullTex.allocation);\n\tnullTex.allocation = nullptr;\n}\n\nvoid VulkanRenderer::DeleteNullObjects()\n{\n\tDeleteNullTexture(nullTexture1D);\n\tDeleteNullTexture(nullTexture2D);\n}\n\nvoid VulkanRenderer::ImguiInit()\n{\n\tVkRenderPass prevRenderPass = m_imguiRenderPass;\n\n\tVkAttachmentDescription colorAttachment = {};\n\tcolorAttachment.format = m_mainSwapchainInfo->m_surfaceFormat.format;\n\tcolorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;\n\tcolorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;\n\tcolorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n\tcolorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n\tcolorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n\tcolorAttachment.initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;\n\tcolorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;\n\n\tVkAttachmentReference colorAttachmentRef = {};\n\tcolorAttachmentRef.attachment = 0;\n\tcolorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n\tVkSubpassDescription subpass = {};\n\tsubpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n\tsubpass.colorAttachmentCount = 1;\n\tsubpass.pColorAttachments = &colorAttachmentRef;\n\n\tVkRenderPassCreateInfo renderPassInfo = {};\n\trenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n\trenderPassInfo.attachmentCount = 1;\n\trenderPassInfo.pAttachments = &colorAttachment;\n\trenderPassInfo.subpassCount = 1;\n\trenderPassInfo.pSubpasses = &subpass;\n\tconst auto result = vkCreateRenderPass(m_logicalDevice, &renderPassInfo, nullptr, &m_imguiRenderPass);\n\tif (result != VK_SUCCESS)\n\t\tthrow VkException(result, \"can't create imgui renderpass\");\n\n\tImGui_ImplVulkan_InitInfo info{};\n\tinfo.Instance = m_instance;\n\tinfo.PhysicalDevice = m_physicalDevice;\n\tinfo.Device = m_logicalDevice;\n\tinfo.QueueFamily = m_indices.presentFamily;\n\tinfo.Queue = m_presentQueue;\n\tinfo.PipelineCache = m_pipeline_cache;\n\tinfo.DescriptorPool = m_descriptorPool;\n\tinfo.MinImageCount = m_mainSwapchainInfo->m_swapchainImages.size();\n\tinfo.ImageCount = info.MinImageCount;\n\n\tImGui_ImplVulkan_Init(&info, m_imguiRenderPass);\n\n\tif (prevRenderPass != VK_NULL_HANDLE)\n\t\tvkDestroyRenderPass(GetLogicalDevice(), prevRenderPass, nullptr);\n}\n\nvoid VulkanRenderer::Initialize()\n{\n\tRenderer::Initialize();\n\tInitFirstCommandBuffer();\n\tCreatePipelineCache();\n\tImguiInit();\n\tCreateNullObjects();\n}\n\nvoid VulkanRenderer::Shutdown()\n{\n\tSubmitCommandBuffer();\n\tWaitDeviceIdle();\n\t// stop compilation threads\n\tRendererShaderVk::Shutdown();\n\tPipelineCompiler::CompileThreadPool_Stop();\n\n\tDeleteFontTextures();\n\tRenderer::Shutdown();\n\tif (m_imguiRenderPass != VK_NULL_HANDLE)\n\t{\n\t\tvkDestroyRenderPass(m_logicalDevice, m_imguiRenderPass, nullptr);\n\t\tm_imguiRenderPass = VK_NULL_HANDLE;\n\t}\n\tRendererShaderVk::Shutdown();\n}\n\nvoid VulkanRenderer::UnrecoverableError(const char* errMsg) const\n{\n\tcemuLog_log(LogType::Force, \"Unrecoverable error in Vulkan renderer\");\n\tcemuLog_log(LogType::Force, \"Msg: {}\", errMsg);\n\tthrow std::runtime_error(errMsg);\n}\n\nstruct VulkanRequestedFormat_t\n{\n\tVkFormat fmt;\n\tconst char* name;\n\tbool isDepth;\n\tbool mustSupportAttachment;\n\tbool mustSupportBlending;\n};\n\n#define reqColorFormat(__name, __reqAttachment, __reqBlend) {__name, \"\"#__name, false, __reqAttachment, __reqBlend}\n#define reqDepthFormat(__name) {__name, \"\"#__name, true, true, false}\n\nVulkanRequestedFormat_t requestedFormatList[] =\n{\n\treqDepthFormat(VK_FORMAT_D32_SFLOAT_S8_UINT),\n\treqDepthFormat(VK_FORMAT_D24_UNORM_S8_UINT),\n\treqDepthFormat(VK_FORMAT_D32_SFLOAT),\n\treqDepthFormat(VK_FORMAT_D16_UNORM),\n\treqColorFormat(VK_FORMAT_R32G32B32A32_SFLOAT, true, true),\n\treqColorFormat(VK_FORMAT_R32G32B32A32_UINT, true, false),\n\treqColorFormat(VK_FORMAT_R16G16B16A16_SFLOAT, true, true),\n\treqColorFormat(VK_FORMAT_R16G16B16A16_UINT, true, false),\n\treqColorFormat(VK_FORMAT_R16G16B16A16_UNORM, true, true),\n\treqColorFormat(VK_FORMAT_R16G16B16A16_SNORM, true, true),\n\treqColorFormat(VK_FORMAT_R8G8B8A8_UNORM, true, true),\n\treqColorFormat(VK_FORMAT_R8G8B8A8_SNORM, true, true),\n\treqColorFormat(VK_FORMAT_R8G8B8A8_SRGB, true, true),\n\treqColorFormat(VK_FORMAT_R8G8B8A8_UINT, true, false),\n\treqColorFormat(VK_FORMAT_R8G8B8A8_SINT, true, false),\n\treqColorFormat(VK_FORMAT_R4G4B4A4_UNORM_PACK16, true, true),\n\treqColorFormat(VK_FORMAT_R32G32_SFLOAT, true, true),\n\treqColorFormat(VK_FORMAT_R32G32_UINT, true, false),\n\treqColorFormat(VK_FORMAT_R16G16_UNORM, true, true),\n\treqColorFormat(VK_FORMAT_R16G16_SFLOAT, true, true),\n\treqColorFormat(VK_FORMAT_R8G8_UNORM, true, true),\n\treqColorFormat(VK_FORMAT_R8G8_SNORM, true, true),\n\treqColorFormat(VK_FORMAT_R4G4_UNORM_PACK8, true, true),\n\treqColorFormat(VK_FORMAT_R32_SFLOAT, true, true),\n\treqColorFormat(VK_FORMAT_R32_UINT, true, false),\n\treqColorFormat(VK_FORMAT_R16_SFLOAT, true, true),\n\treqColorFormat(VK_FORMAT_R16_UNORM, true, true),\n\treqColorFormat(VK_FORMAT_R16_SNORM, true, true),\n\treqColorFormat(VK_FORMAT_R8_UNORM, true, true),\n\treqColorFormat(VK_FORMAT_R8_SNORM, true, true),\n\treqColorFormat(VK_FORMAT_R5G6B5_UNORM_PACK16, true, true),\n\treqColorFormat(VK_FORMAT_R5G5B5A1_UNORM_PACK16, true, true),\n\treqColorFormat(VK_FORMAT_B10G11R11_UFLOAT_PACK32, true, true),\n\treqColorFormat(VK_FORMAT_R16G16B16A16_SNORM, true, true),\n\treqColorFormat(VK_FORMAT_BC1_RGBA_SRGB_BLOCK, false, false),\n\treqColorFormat(VK_FORMAT_BC1_RGBA_UNORM_BLOCK, false, false),\n\treqColorFormat(VK_FORMAT_BC2_UNORM_BLOCK, false, false),\n\treqColorFormat(VK_FORMAT_BC2_SRGB_BLOCK, false, false),\n\treqColorFormat(VK_FORMAT_BC3_UNORM_BLOCK, false, false),\n\treqColorFormat(VK_FORMAT_BC3_SRGB_BLOCK, false, false),\n\treqColorFormat(VK_FORMAT_BC4_UNORM_BLOCK, false, false),\n\treqColorFormat(VK_FORMAT_BC4_SNORM_BLOCK, false, false),\n\treqColorFormat(VK_FORMAT_BC5_UNORM_BLOCK, false, false),\n\treqColorFormat(VK_FORMAT_BC5_SNORM_BLOCK, false, false),\n\treqColorFormat(VK_FORMAT_A2B10G10R10_UNORM_PACK32, true, true),\n\treqColorFormat(VK_FORMAT_R32_SFLOAT, true, true)\n};\n\nvoid VulkanRenderer::QueryMemoryInfo()\n{\n\tVkPhysicalDeviceMemoryProperties memProperties;\n\tvkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memProperties);\n\tcemuLog_log(LogType::Force, \"Vulkan device memory info:\");\n\tfor (uint32 i = 0; i < memProperties.memoryHeapCount; i++)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Heap {} - Size {}MB Flags 0x{:08x}\", i, (sint32)(memProperties.memoryHeaps[i].size / 1024ll / 1024ll), (uint32)memProperties.memoryHeaps[i].flags);\n\t}\n\tfor (uint32 i = 0; i < memProperties.memoryTypeCount; i++)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Memory {} - HeapIndex {} Flags 0x{:08x}\", i, (sint32)memProperties.memoryTypes[i].heapIndex, (uint32)memProperties.memoryTypes[i].propertyFlags);\n\t}\n}\n\nvoid VulkanRenderer::QueryAvailableFormats()\n{\n\tVkFormatProperties fmtProp{};\n\tvkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_D24_UNORM_S8_UINT, &fmtProp);\n\t// D24S8\n\tif (fmtProp.optimalTilingFeatures != 0) // todo - more restrictive check\n\t{\n\t\tm_supportedFormatInfo.fmt_d24_unorm_s8_uint = true;\n\t}\n\t// R4G4\n\tfmtProp = {};\n\tvkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_R4G4_UNORM_PACK8, &fmtProp);\n\tif (fmtProp.optimalTilingFeatures != 0)\n\t{\n\t\tm_supportedFormatInfo.fmt_r4g4_unorm_pack = true;\n\t}\n\t// R5G6B5\n\tfmtProp = {};\n\tvkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_R5G6B5_UNORM_PACK16, &fmtProp);\n\tif (fmtProp.optimalTilingFeatures != 0)\n\t{\n\t\tm_supportedFormatInfo.fmt_r5g6b5_unorm_pack = true;\n\t}\n\t// R4G4B4A4\n\tfmtProp = {};\n\tvkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_R4G4B4A4_UNORM_PACK16, &fmtProp);\n\tif (fmtProp.optimalTilingFeatures != 0)\n\t{\n\t\tm_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack = true;\n\t}\n\t// A1R5G5B5\n\tfmtProp = {};\n\tvkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_A1R5G5B5_UNORM_PACK16, &fmtProp);\n\tif (fmtProp.optimalTilingFeatures != 0)\n\t{\n\t\tm_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack = true;\n\t}\n\t// print info about unsupported formats to log\n\tfor (auto& it : requestedFormatList)\n\t{\n\t\tfmtProp = {};\n\t\tvkGetPhysicalDeviceFormatProperties(m_physicalDevice, it.fmt, &fmtProp);\n\t\tVkFormatFeatureFlags requestedBits = 0;\n\t\tif (it.mustSupportAttachment)\n\t\t{\n\t\t\tif (it.isDepth)\n\t\t\t\trequestedBits |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;\n\t\t\telse\n\t\t\t\trequestedBits |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;\n\t\t\tif (!it.isDepth && it.mustSupportBlending)\n\t\t\t\trequestedBits |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;\n\t\t}\n\t\trequestedBits |= VK_FORMAT_FEATURE_TRANSFER_DST_BIT;\n\t\trequestedBits |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;\n\n\t\tif (fmtProp.optimalTilingFeatures == 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"{} not supported\", it.name);\n\t\t}\n\t\telse if ((fmtProp.optimalTilingFeatures & requestedBits) != requestedBits)\n\t\t{\n\t\t\t//std::string missingStr;\n\t\t\t//missingStr.assign(fmt::format(\"{} missing features:\", it.name));\n\t\t\t//if (!(fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) && !it.isDepth && it.mustSupportAttachment)\n\t\t\t//\tmissingStr.append(\" COLOR_ATTACHMENT\");\n\t\t\t//if (!(fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT) && !it.isDepth && it.mustSupportBlending)\n\t\t\t//\tmissingStr.append(\" COLOR_ATTACHMENT_BLEND\");\n\t\t\t//if (!(fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) && it.isDepth && it.mustSupportAttachment)\n\t\t\t//\tmissingStr.append(\" DEPTH_ATTACHMENT\");\n\t\t\t//if (!(fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_TRANSFER_DST_BIT))\n\t\t\t//\tmissingStr.append(\" TRANSFER_DST\");\n\t\t\t//if (!(fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))\n\t\t\t//\tmissingStr.append(\" SAMPLED_IMAGE\");\n\t\t\t//cemuLog_log(LogType::Force, \"{}\", missingStr.c_str());\n\t\t}\n\t}\n}\n\nbool VulkanRenderer::ImguiBegin(bool mainWindow)\n{\n\tif (!Renderer::ImguiBegin(mainWindow))\n\t\treturn false;\n\n\tauto& chainInfo = GetChainInfo(mainWindow);\n\n\tif (!AcquireNextSwapchainImage(mainWindow))\n\t\treturn false;\n\n\tdraw_endRenderPass();\n\tm_state.currentPipeline = VK_NULL_HANDLE;\n\n\tImGui_ImplVulkan_CreateFontsTexture(m_state.currentCommandBuffer);\n\tImGui_ImplVulkan_NewFrame(m_state.currentCommandBuffer, chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex], chainInfo.getExtent());\n\tImGui_UpdateWindowInformation(mainWindow);\n\tImGui::NewFrame();\n\treturn true;\n}\n\nvoid VulkanRenderer::ImguiEnd()\n{\n\tImGui::Render();\n\tImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), m_state.currentCommandBuffer);\n\tvkCmdEndRenderPass(m_state.currentCommandBuffer);\n}\n\nImTextureID VulkanRenderer::GenerateTexture(const std::vector<uint8>& data, const Vector2i& size)\n{\n\ttry\n\t{\n\t\tstd::vector <uint8> tmp(size.x * size.y * 4);\n\t\tfor (size_t i = 0; i < data.size() / 3; ++i)\n\t\t{\n\t\t\ttmp[(i * 4) + 0] = data[(i * 3) + 0];\n\t\t\ttmp[(i * 4) + 1] = data[(i * 3) + 1];\n\t\t\ttmp[(i * 4) + 2] = data[(i * 3) + 2];\n\t\t\ttmp[(i * 4) + 3] = 0xFF;\n\t\t}\n\t\treturn (ImTextureID)ImGui_ImplVulkan_GenerateTexture(m_state.currentCommandBuffer, tmp, size);\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"can't generate imgui texture: {}\", ex.what());\n\t\treturn nullptr;\n\t}\n}\n\nvoid VulkanRenderer::DeleteTexture(ImTextureID id)\n{\n\tWaitDeviceIdle();\n\tImGui_ImplVulkan_DeleteTexture(id);\n}\n\nvoid VulkanRenderer::DeleteFontTextures()\n{\n\tWaitDeviceIdle();\n\tImGui_ImplVulkan_DestroyFontsTexture();\n}\n\n\nbool VulkanRenderer::BeginFrame(bool mainWindow)\n{\n\tif (!AcquireNextSwapchainImage(mainWindow))\n\t\treturn false;\n\n\tauto& chainInfo = GetChainInfo(mainWindow);\n\n\tVkClearColorValue clearColor{ 0, 0, 0, 0 };\n\tClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);\n\n\t// mark current swapchain image as well defined\n\tchainInfo.hasDefinedSwapchainImage = true;\n\n\treturn true;\n}\n\nvoid VulkanRenderer::DrawEmptyFrame(bool mainWindow)\n{\n\tif (!BeginFrame(mainWindow))\n\t\treturn;\n\tSwapBuffers(mainWindow, !mainWindow);\n}\n\nvoid VulkanRenderer::InitFirstCommandBuffer()\n{\n\tcemu_assert_debug(m_state.currentCommandBuffer == nullptr);\n\t// m_commandBufferIndex always points to the currently used command buffer, so we set it to 0\n\tm_commandBufferIndex = 0;\n\tm_commandBufferSyncIndex = 0;\n\n\tm_state.currentCommandBuffer = m_commandBuffers[m_commandBufferIndex];\n\tvkResetFences(m_logicalDevice, 1, &m_cmd_buffer_fences[m_commandBufferIndex]);\n\tVkCommandBufferBeginInfo beginInfo{};\n\tbeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\tbeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;\n\tvkBeginCommandBuffer(m_state.currentCommandBuffer, &beginInfo);\n\n\tvkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &m_state.currentViewport);\n\tvkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &m_state.currentScissorRect);\n\n\tm_state.resetCommandBufferState();\n}\n\nvoid VulkanRenderer::ProcessFinishedCommandBuffers()\n{\n\tbool finishedCmdBuffers = false;\n\twhile (m_commandBufferSyncIndex != m_commandBufferIndex)\n\t{\n\t\tVkResult fenceStatus = vkGetFenceStatus(m_logicalDevice, m_cmd_buffer_fences[m_commandBufferSyncIndex]);\n\t\tif (fenceStatus == VK_SUCCESS)\n\t\t{\n\t\t\tProcessDestructionQueue();\n\t\t\tm_uniformVarBufferReadIndex = m_cmdBufferUniformRingbufIndices[m_commandBufferSyncIndex];\n\t\t\tm_commandBufferSyncIndex = (m_commandBufferSyncIndex + 1) % m_commandBuffers.size();\n\t\t\tmemoryManager->cleanupBuffers(m_countCommandBufferFinished);\n\t\t\tm_countCommandBufferFinished++;\n\t\t\tfinishedCmdBuffers = true;\n\t\t\tcontinue;\n\t\t}\n\t\telse if (fenceStatus == VK_NOT_READY)\n\t\t{\n\t\t\t// not signaled\n\t\t\tbreak;\n\t\t}\n\t\tcemuLog_log(LogType::Force, \"vkGetFenceStatus returned unexpected error {}\", (sint32)fenceStatus);\n\t\tcemu_assert_debug(false);\n\t}\n\tif (finishedCmdBuffers)\n\t{\n\t\tLatteTextureReadback_UpdateFinishedTransfers(false);\n\t}\n}\n\nvoid VulkanRenderer::WaitForNextFinishedCommandBuffer()\n{\n\tcemu_assert_debug(m_commandBufferSyncIndex != m_commandBufferIndex);\n\t// wait on least recently submitted command buffer\n\tVkResult result = vkWaitForFences(m_logicalDevice, 1, &m_cmd_buffer_fences[m_commandBufferSyncIndex], true, UINT64_MAX);\n\tif (result == VK_TIMEOUT)\n\t{\n\t\tcemuLog_log(LogType::Force, \"vkWaitForFences: Returned VK_TIMEOUT on infinite fence\");\n\t}\n\telse if (result != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"vkWaitForFences: Returned unhandled error {}\", (sint32)result);\n\t}\n\t// process\n\tProcessFinishedCommandBuffers();\n}\n\nvoid VulkanRenderer::SubmitCommandBuffer(VkSemaphore signalSemaphore, VkSemaphore waitSemaphore)\n{\n\tdraw_endRenderPass();\n\n\tocclusionQuery_notifyEndCommandBuffer();\n\n\tvkEndCommandBuffer(m_state.currentCommandBuffer);\n\n\tVkSubmitInfo submitInfo = {};\n\tsubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n\tsubmitInfo.commandBufferCount = 1;\n\tsubmitInfo.pCommandBuffers = &m_state.currentCommandBuffer;\n\n\t// signal current command buffer semaphore\n\tVkSemaphore signalSemArray[2];\n\tif (signalSemaphore != VK_NULL_HANDLE)\n\t{\n\t\tsubmitInfo.signalSemaphoreCount = 2;\n\t\tsignalSemArray[0] = m_commandBufferSemaphores[m_commandBufferIndex]; // signal current\n\t\tsignalSemArray[1] = signalSemaphore; // signal current\n\t\tsubmitInfo.pSignalSemaphores = signalSemArray;\n\t}\n\telse\n\t{\n\t\tsubmitInfo.signalSemaphoreCount = 1;\n\t\tsubmitInfo.pSignalSemaphores = &m_commandBufferSemaphores[m_commandBufferIndex]; // signal current\n\t}\n\n\t// wait for previous command buffer semaphore\n\tVkSemaphore prevSem = GetLastSubmittedCmdBufferSemaphore();\n\tconst VkPipelineStageFlags semWaitStageMask[2] = { VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT };\n\tVkSemaphore waitSemArray[2];\n\tsubmitInfo.waitSemaphoreCount = 0;\n\tif (m_numSubmittedCmdBuffers > 0)\n\t\twaitSemArray[submitInfo.waitSemaphoreCount++] = prevSem; // wait on semaphore from previous submit\n\tif (waitSemaphore != VK_NULL_HANDLE)\n\t\twaitSemArray[submitInfo.waitSemaphoreCount++] = waitSemaphore;\n\tsubmitInfo.pWaitDstStageMask = semWaitStageMask;\n\tsubmitInfo.pWaitSemaphores = waitSemArray;\n\n\tconst VkResult result = vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_cmd_buffer_fences[m_commandBufferIndex]);\n\tif (result != VK_SUCCESS)\n\t\tUnrecoverableError(fmt::format(\"failed to submit command buffer. Error {}\", result).c_str());\n\tm_numSubmittedCmdBuffers++;\n\n\t// check if any previously submitted command buffers have finished execution\n\tProcessFinishedCommandBuffers();\n\n\t// acquire next command buffer\n\tauto nextCmdBufferIndex = (m_commandBufferIndex + 1) % m_commandBuffers.size();\n\tif (nextCmdBufferIndex == m_commandBufferSyncIndex)\n\t{\n\t\t// force wait for the next command buffer\n\t\tcemuLog_logDebug(LogType::Force, \"Vulkan: Waiting for available command buffer...\");\n\t\tWaitForNextFinishedCommandBuffer();\n\t}\n\tm_cmdBufferUniformRingbufIndices[nextCmdBufferIndex] = m_cmdBufferUniformRingbufIndices[m_commandBufferIndex];\n\tm_commandBufferIndex = nextCmdBufferIndex;\n\n\n\tm_state.currentCommandBuffer = m_commandBuffers[m_commandBufferIndex];\n\tvkResetFences(m_logicalDevice, 1, &m_cmd_buffer_fences[m_commandBufferIndex]);\n\tvkResetCommandBuffer(m_state.currentCommandBuffer, 0);\n\n\tVkCommandBufferBeginInfo beginInfo{};\n\tbeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\tbeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;\n\tvkBeginCommandBuffer(m_state.currentCommandBuffer, &beginInfo);\n\n\t// make sure some states are set for this command buffer\n\tvkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &m_state.currentViewport);\n\tvkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &m_state.currentScissorRect);\n\n\t// DEBUG\n\t//debug_genericBarrier();\n\n\t// reset states which are bound to a command buffer\n\tm_state.resetCommandBufferState();\n\n\tocclusionQuery_notifyBeginCommandBuffer();\n\n\tm_recordedDrawcalls = 0;\n\tm_submitThreshold = 300;\n\tm_submitOnIdle = false;\n}\n\n// submit within next 10 drawcalls\nvoid VulkanRenderer::RequestSubmitSoon()\n{\n\tm_submitThreshold = std::min(m_submitThreshold, m_recordedDrawcalls + 10);\n}\n\n// command buffer will be submitted when GPU has no more commands to process or when threshold is reached\nvoid VulkanRenderer::RequestSubmitOnIdle()\n{\n\tm_submitOnIdle = true;\n}\n\nuint64 VulkanRenderer::GetCurrentCommandBufferId() const\n{\n\treturn m_numSubmittedCmdBuffers;\n}\n\nbool VulkanRenderer::HasCommandBufferFinished(uint64 commandBufferId) const\n{\n\treturn m_countCommandBufferFinished > commandBufferId;\n}\n\nvoid VulkanRenderer::WaitCommandBufferFinished(uint64 commandBufferId)\n{\n\tif (commandBufferId == m_numSubmittedCmdBuffers)\n\t\tSubmitCommandBuffer();\n\twhile (HasCommandBufferFinished(commandBufferId) == false)\n\t\tWaitForNextFinishedCommandBuffer();\n}\n\nvoid VulkanRenderer::PipelineCacheSaveThread(size_t cache_size)\n{\n\tSetThreadName(\"vkDriverPlCache\");\n\tconst auto dir = ActiveSettings::GetCachePath(\"shaderCache/driver/vk\");\n\tif (!fs::exists(dir))\n\t{\n\t\ttry\n\t\t{\n\t\t\tfs::create_directories(dir);\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"can't create vulkan pipeline cache directory \\\"{}\\\": {}\", _pathToUtf8(dir), ex.what());\n\t\t\treturn;\n\t\t}\n\t}\n\n\tconst auto filename = dir / fmt::format(L\"{:016x}.bin\", CafeSystem::GetForegroundTitleId());\n\n\twhile (true)\n\t{\n\t\tif (m_destructionRequested)\n\t\t\treturn;\n\t\tm_pipeline_cache_semaphore.wait();\n\t\tif (m_destructionRequested)\n\t\t\treturn;\n\t\tfor (sint32 i = 0; i < 15 * 4; i++)\n\t\t{\n\t\t\tif (m_destructionRequested)\n\t\t\t\treturn;\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(250));\n\t\t}\n\n\t\t// always prioritize the compiler threads over this thread\n\t\t// avoid calling stalling lock() since it will block other threads from entering even when the lock is currently held in shared mode\n\t\twhile (!m_pipeline_cache_save_mutex.try_lock())\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(250));\n\n\t\tsize_t size = 0;\n\t\tVkResult res = vkGetPipelineCacheData(m_logicalDevice, m_pipeline_cache, &size, nullptr);\n\t\tif (res == VK_SUCCESS && size > 0 && size != cache_size)\n\t\t{\n\t\t\tstd::vector<uint8_t> cacheData(size);\n\t\t\tres = vkGetPipelineCacheData(m_logicalDevice, m_pipeline_cache, &size, cacheData.data());\n\t\t\tm_pipeline_cache_semaphore.reset();\n\t\t\tm_pipeline_cache_save_mutex.unlock();\n\n\t\t\tif (res == VK_SUCCESS)\n\t\t\t{\n\n\t\t\t\tauto file = std::ofstream(filename, std::ios::out | std::ios::binary);\n\t\t\t\tif (file.is_open())\n\t\t\t\t{\n\t\t\t\t\tfile.write((char*)cacheData.data(), cacheData.size());\n\t\t\t\t\tfile.close();\n\n\t\t\t\t\tcache_size = size;\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"pipeline cache saved\");\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"can't write pipeline cache to disk\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"can't retrieve pipeline cache data: 0x{:x}\", res);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_pipeline_cache_semaphore.reset();\n\t\t\tm_pipeline_cache_save_mutex.unlock();\n\t\t}\n\t}\n}\n\nvoid VulkanRenderer::CreatePipelineCache()\n{\n\tstd::vector<uint8_t> cacheData;\n\tconst auto dir = ActiveSettings::GetCachePath(\"shaderCache/driver/vk\");\n\tif (fs::exists(dir))\n\t{\n\t\tconst auto filename = dir / fmt::format(\"{:016x}.bin\", CafeSystem::GetForegroundTitleId());\n\t\tauto file = std::ifstream(filename, std::ios::in | std::ios::binary | std::ios::ate);\n\t\tif (file.is_open())\n\t\t{\n\t\t\tconst size_t fileSize = file.tellg();\n\t\t\tfile.seekg(0, std::ifstream::beg);\n\t\t\tcacheData.resize(fileSize);\n\t\t\tfile.read((char*)cacheData.data(), cacheData.size());\n\t\t\tfile.close();\n\t\t}\n\t}\n\n\tVkPipelineCacheCreateInfo createInfo{};\n\tcreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;\n\tcreateInfo.initialDataSize = cacheData.size();\n\tcreateInfo.pInitialData = cacheData.data();\n\tVkResult result = vkCreatePipelineCache(m_logicalDevice, &createInfo, nullptr, &m_pipeline_cache);\n\tif (result != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to open Vulkan pipeline cache: {}\", result);\n\t\t// unable to load the existing cache, start with an empty cache instead\n\t\tcreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;\n\t\tcreateInfo.initialDataSize = 0;\n\t\tcreateInfo.pInitialData = nullptr;\n\t\tresult = vkCreatePipelineCache(m_logicalDevice, &createInfo, nullptr, &m_pipeline_cache);\n\t\tif (result != VK_SUCCESS)\n\t\t\tUnrecoverableError(fmt::format(\"Failed to create new Vulkan pipeline cache: {}\", result).c_str());\n\t}\n\n\tsize_t cache_size = 0;\n\tvkGetPipelineCacheData(m_logicalDevice, m_pipeline_cache, &cache_size, nullptr);\n\n\tm_pipeline_cache_save_thread = std::thread(&VulkanRenderer::PipelineCacheSaveThread, this, cache_size);\n}\n\nvoid VulkanRenderer::swapchain_createDescriptorSetLayout()\n{\n\tVkDescriptorSetLayoutBinding bindings[2]{};\n\tVkDescriptorSetLayoutBinding& samplerLayoutBinding = bindings[0];\n\tsamplerLayoutBinding.binding = 0;\n\tsamplerLayoutBinding.descriptorCount = 1;\n\tsamplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\tsamplerLayoutBinding.pImmutableSamplers = nullptr;\n\tsamplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\n\tVkDescriptorSetLayoutBinding& uniformBufferBinding = bindings[1];\n\tuniformBufferBinding.binding = 1;\n\tuniformBufferBinding.descriptorCount = 1;\n\tuniformBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;\n\tuniformBufferBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\n\tVkDescriptorSetLayoutCreateInfo layoutInfo = {};\n\tlayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n\tlayoutInfo.bindingCount = std::size(bindings);\n\tlayoutInfo.pBindings = bindings;\n\n\tif (vkCreateDescriptorSetLayout(m_logicalDevice, &layoutInfo, nullptr, &m_swapchainDescriptorSetLayout) != VK_SUCCESS)\n\t\tUnrecoverableError(\"failed to create descriptor set layout for swapchain\");\n}\n\nvoid VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, sint32 width, sint32 height, FormatInfoVK* formatInfoOut)\n{\n\tformatInfoOut->texelCountX = width;\n\tformatInfoOut->texelCountY = height;\n\tformatInfoOut->isCompressed = false;\n\tif (isDepth)\n\t{\n\t\tswitch (format)\n\t\t{\n\t\tcase Latte::E_GX2SURFFMT::D24_S8_UNORM:\n\t\t\tif (m_supportedFormatInfo.fmt_d24_unorm_s8_uint == false)\n\t\t\t{\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_D32_SFLOAT_S8_UINT;\n\t\t\t\tformatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;\n\t\t\t\tformatInfoOut->decoder = TextureDecoder_NullData64::getInstance();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_D24_UNORM_S8_UINT;\n\t\t\t\tformatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;\n\t\t\t\tformatInfoOut->decoder = TextureDecoder_D24_S8::getInstance();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::D24_S8_FLOAT:\n\t\t\t// alternative format\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_D32_SFLOAT_S8_UINT;\n\t\t\tformatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_NullData64::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::D32_FLOAT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_D32_SFLOAT;\n\t\t\tformatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_DEPTH_BIT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R32_FLOAT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::D16_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_D16_UNORM;\n\t\t\tformatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_DEPTH_BIT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_UNORM::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::D32_S8_FLOAT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_D32_SFLOAT_S8_UINT;\n\t\t\tformatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_D32_S8_UINT_X24::getInstance();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemuLog_log(LogType::Force, \"Unsupported depth texture format {:04x}\", (uint32)format);\n\t\t\t// default to placeholder format\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_D16_UNORM;\n\t\t\tformatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_DEPTH_BIT;\n\t\t\tformatInfoOut->decoder = nullptr;\n\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t{\n\t\tformatInfoOut->vkImageAspect = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\tif(format == (Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT | Latte::E_GX2SURFFMT::FMT_BIT_SRGB)) // Seen in Sonic Transformed level Starry Speedway. SRGB should just be ignored for native float formats?\n\t\t\tformat = Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT;\n\t\tswitch (format)\n\t\t{\n\t\t\t// RGBA formats\n\t\tcase Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R32G32B32A32_SFLOAT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R32_G32_B32_A32_FLOAT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R32G32B32A32_UINT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R32_G32_B32_A32_UINT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16G16B16A16_SFLOAT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_G16_B16_A16_FLOAT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16G16B16A16_UINT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_G16_B16_A16_UINT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16G16B16A16_UNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_G16_B16_A16::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R16_G16_B16_A16_SNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16G16B16A16_SNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_G16_B16_A16::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R8_G8_B8_A8_SNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_SNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_SRGB;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R8_G8_B8_A8_UINT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UINT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R8_G8_B8_A8_SINT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_SINT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R8_G8_B8_A8::getInstance();\n\t\t\tbreak;\n\t\t\t// RG formats\n\t\tcase Latte::E_GX2SURFFMT::R32_G32_FLOAT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R32G32_SFLOAT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R32_G32_FLOAT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R32_G32_UINT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R32G32_UINT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R32_G32_UINT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R16_G16_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16G16_UNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_G16::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R16_G16_FLOAT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16G16_SFLOAT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_G16_FLOAT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R8_G8_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8_UNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R8_G8::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R8_G8_SNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8_SNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R8_G8::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R4_G4_UNORM:\n\t\t\tif (m_supportedFormatInfo.fmt_r4g4_unorm_pack == false)\n\t\t\t{\n\t\t\t\tif (m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack == false) {\n\t\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;\n\t\t\t\t\tformatInfoOut->decoder = TextureDecoder_R4G4_UNORM_To_RGBA8::getInstance();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16;\n\t\t\t\t\tformatInfoOut->decoder = TextureDecoder_R4_G4_UNORM_To_ABGR4::getInstance();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R4G4_UNORM_PACK8;\n\t\t\t\tformatInfoOut->decoder = TextureDecoder_R4_G4::getInstance();\n\t\t\t}\n\t\t\tbreak;\n\t\t\t// R formats\n\t\tcase Latte::E_GX2SURFFMT::R32_FLOAT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R32_SFLOAT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R32_FLOAT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R32_UINT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R32_UINT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R32_UINT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R16_FLOAT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16_SFLOAT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_FLOAT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R16_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16_UNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_UNORM::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R16_SNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16_SNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_SNORM::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R16_UINT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16_UINT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R16_UINT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R8_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8_UNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R8::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R8_SNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8_SNORM;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R8::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R8_UINT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8_UINT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R8_UINT::getInstance();\n\t\t\tbreak;\n\t\t\t// special formats\n\t\tcase Latte::E_GX2SURFFMT::R5_G6_B5_UNORM:\n\t\t\tif (m_supportedFormatInfo.fmt_r5g6b5_unorm_pack == false) {\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;\n\t\t\t\tformatInfoOut->decoder = TextureDecoder_R5G6B5_UNORM_To_RGBA8::getInstance();\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Vulkan has R in MSB, GPU7 has it in LSB\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;\n\t\t\t\tformatInfoOut->decoder = TextureDecoder_R5_G6_B5_swappedRB::getInstance();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM:\n\t\t\tif (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false) {\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;\n\t\t\t\tformatInfoOut->decoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB_To_RGBA8::getInstance();\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// used in Super Mario 3D World for the hidden Luigi sprites\n\t\t\t\t// since order of channels is reversed in Vulkan compared to GX2 the format we need is A1B5G5R5\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_A1R5G5B5_UNORM_PACK16;\n\t\t\t\tformatInfoOut->decoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB::getInstance();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM:\n\t\t\tif (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false) {\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;\n\t\t\t\tformatInfoOut->decoder = TextureDecoder_A1_B5_G5_R5_UNORM_vulkan_To_RGBA8::getInstance();\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// used by VC64 (e.g. Ocarina of Time)\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_A1R5G5B5_UNORM_PACK16; // A 15 R 10..14, G 5..9 B 0..4\n\t\t\t\tformatInfoOut->decoder = TextureDecoder_A1_B5_G5_R5_UNORM_vulkan::getInstance();\n\t\t\t}\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_B10G11R11_UFLOAT_PACK32; // verify if order of channels is still the same as GX2\n\t\t\tformatInfoOut->decoder = TextureDecoder_R11_G11_B10_FLOAT::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM:\n\t\t\tif (m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack == false) {\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM;\n\t\t\t\tformatInfoOut->decoder = TextureDecoder_R4G4B4A4_UNORM_To_RGBA8::getInstance();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16;\n \t\t\t\tformatInfoOut->decoder = TextureDecoder_R4_G4_B4_A4_UNORM::getInstance();\n\t\t\t}\n\t\t\tbreak;\n\t\t\t// special formats - R10G10B10_A2\n\t\tcase Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32; // todo - verify\n\t\t\tformatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_UNORM::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R16G16B16A16_SNORM; // Vulkan has VK_FORMAT_A2R10G10B10_SNORM_PACK32 but it doesnt work?\n\t\t\tformatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB:\n\t\t\t//formatInfoOut->vkImageFormat = VK_FORMAT_R16G16B16A16_SNORM; // Vulkan has no uncompressed SRGB format with more than 8 bits per channel\n\t\t\t//formatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16::getInstance();\n\t\t\t//break;\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32; // todo - verify\n\t\t\tformatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_UNORM::getInstance();\n\t\t\tbreak;\n\t\t\t// compressed formats\n\t\tcase Latte::E_GX2SURFFMT::BC1_SRGB:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; // todo - verify\n\t\t\tformatInfoOut->decoder = TextureDecoder_BC1::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::BC1_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; // todo - verify\n\t\t\tformatInfoOut->decoder = TextureDecoder_BC1::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::BC2_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_BC2_UNORM_BLOCK; // todo - verify\n\t\t\tformatInfoOut->decoder = TextureDecoder_BC2::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::BC2_SRGB:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_BC2_SRGB_BLOCK; // todo - verify\n\t\t\tformatInfoOut->decoder = TextureDecoder_BC2::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::BC3_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_BC3_UNORM_BLOCK;\n\t\t\tformatInfoOut->decoder = TextureDecoder_BC3::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::BC3_SRGB:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_BC3_SRGB_BLOCK;\n\t\t\tformatInfoOut->decoder = TextureDecoder_BC3::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::BC4_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_BC4_UNORM_BLOCK;\n\t\t\tformatInfoOut->decoder = TextureDecoder_BC4::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::BC4_SNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_BC4_SNORM_BLOCK;\n\t\t\tformatInfoOut->decoder = TextureDecoder_BC4::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::BC5_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_BC5_UNORM_BLOCK;\n\t\t\tformatInfoOut->decoder = TextureDecoder_BC5::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::BC5_SNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_BC5_SNORM_BLOCK;\n\t\t\tformatInfoOut->decoder = TextureDecoder_BC5::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::R24_X8_UNORM:\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R32_SFLOAT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_R24_X8::getInstance();\n\t\t\tbreak;\n\t\tcase Latte::E_GX2SURFFMT::X24_G8_UINT:\n\t\t\t// used by Color Splash and Resident Evil\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UINT; // todo - should we use ABGR format?\n\t\t\tformatInfoOut->decoder = TextureDecoder_X24_G8_UINT::getInstance(); // todo - verify\n\t\tcase Latte::E_GX2SURFFMT::R32_X8_FLOAT:\n\t\t\t// seen in Disney Infinity 3.0\n\t\t\tformatInfoOut->vkImageFormat = VK_FORMAT_R32_SFLOAT;\n\t\t\tformatInfoOut->decoder = TextureDecoder_NullData64::getInstance();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemuLog_log(LogType::Force, \"Unsupported color texture format {:04x}\", (uint32)format);\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n}\n\nVkPipelineShaderStageCreateInfo VulkanRenderer::CreatePipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule& module, const char* entryName) const\n{\n\tVkPipelineShaderStageCreateInfo shaderStageInfo{};\n\tshaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n\tshaderStageInfo.stage = stage;\n\tshaderStageInfo.module = module;\n\tshaderStageInfo.pName = entryName;\n\treturn shaderStageInfo;\n}\n\nVkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSetLayout descriptorLayout, bool padView, RendererOutputShader* shader)\n{\n\tauto& chainInfo = GetChainInfo(!padView);\n\n\tRendererShaderVk* vertexRendererShader = static_cast<RendererShaderVk*>(shader->GetVertexShader());\n\tRendererShaderVk* fragmentRendererShader = static_cast<RendererShaderVk*>(shader->GetFragmentShader());\n\n\tuint64 hash = 0;\n\thash += (uint64)vertexRendererShader;\n\thash += (uint64)fragmentRendererShader;\n\thash += ((uint64)padView) << 1;\n\n\tconst auto it = m_backbufferBlitPipelineCache.find(hash);\n\tif (it != m_backbufferBlitPipelineCache.cend())\n\t\treturn it->second;\n\n\tstd::vector<VkPipelineShaderStageCreateInfo> shaderStages;\n\tif (vertexRendererShader)\n\t\tshaderStages.emplace_back(CreatePipelineShaderStageCreateInfo(VK_SHADER_STAGE_VERTEX_BIT, vertexRendererShader->GetShaderModule(), \"main\"));\n\n\tif (fragmentRendererShader)\n\t\tshaderStages.emplace_back(CreatePipelineShaderStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, fragmentRendererShader->GetShaderModule(), \"main\"));\n\n\tVkPipelineVertexInputStateCreateInfo vertexInputInfo{};\n\tvertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;\n\tvertexInputInfo.vertexBindingDescriptionCount = 0;\n\tvertexInputInfo.vertexAttributeDescriptionCount = 0;\n\n\tVkPipelineInputAssemblyStateCreateInfo inputAssembly{};\n\tinputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;\n\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n\tinputAssembly.primitiveRestartEnable = VK_FALSE;\n\n\tVkPipelineViewportStateCreateInfo viewportState{};\n\tviewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;\n\tviewportState.viewportCount = 1;\n\tviewportState.scissorCount = 1;\n\n\tVkDynamicState dynamicStates[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };\n\n\tVkPipelineDynamicStateCreateInfo dynamicState = {};\n\tdynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;\n\tdynamicState.dynamicStateCount = std::size(dynamicStates);\n\tdynamicState.pDynamicStates = dynamicStates;\n\n\tVkPipelineRasterizationStateCreateInfo rasterizer{};\n\trasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;\n\trasterizer.depthClampEnable = VK_FALSE;\n\trasterizer.rasterizerDiscardEnable = VK_FALSE;\n\trasterizer.polygonMode = VK_POLYGON_MODE_FILL;\n\trasterizer.lineWidth = 1.0f;\n\trasterizer.cullMode = VK_CULL_MODE_BACK_BIT;\n\trasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;\n\trasterizer.depthBiasEnable = VK_FALSE;\n\n\tVkPipelineMultisampleStateCreateInfo multisampling{};\n\tmultisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;\n\tmultisampling.sampleShadingEnable = VK_FALSE;\n\tmultisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n\n\tVkPipelineColorBlendAttachmentState colorBlendAttachment{};\n\tcolorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;\n\tcolorBlendAttachment.blendEnable = VK_FALSE;\n\n\tVkPipelineColorBlendStateCreateInfo colorBlending{};\n\tcolorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;\n\tcolorBlending.logicOpEnable = VK_FALSE;\n\tcolorBlending.logicOp = VK_LOGIC_OP_COPY;\n\tcolorBlending.attachmentCount = 1;\n\tcolorBlending.pAttachments = &colorBlendAttachment;\n\tcolorBlending.blendConstants[0] = 0.0f;\n\tcolorBlending.blendConstants[1] = 0.0f;\n\tcolorBlending.blendConstants[2] = 0.0f;\n\tcolorBlending.blendConstants[3] = 0.0f;\n\n\tVkPipelineLayoutCreateInfo pipelineLayoutInfo{};\n\tpipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n\tpipelineLayoutInfo.setLayoutCount = 1;\n\tpipelineLayoutInfo.pSetLayouts = &descriptorLayout;\n\n\tVkResult result;\n\tif (m_pipelineLayout == VK_NULL_HANDLE)\n\t{\n\t\tresult = vkCreatePipelineLayout(m_logicalDevice, &pipelineLayoutInfo, nullptr, &m_pipelineLayout);\n\t\tif (result != VK_SUCCESS)\n\t\t\tthrow std::runtime_error(fmt::format(\"Failed to create pipeline layout: {}\", result));\n\t}\n\n\tVkGraphicsPipelineCreateInfo pipelineInfo = {};\n\tpipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;\n\tpipelineInfo.stageCount = shaderStages.size();\n\tpipelineInfo.pStages = shaderStages.data();\n\tpipelineInfo.pVertexInputState = &vertexInputInfo;\n\tpipelineInfo.pInputAssemblyState = &inputAssembly;\n\tpipelineInfo.pViewportState = &viewportState;\n\tpipelineInfo.pDynamicState = &dynamicState;\n\tpipelineInfo.pRasterizationState = &rasterizer;\n\tpipelineInfo.pMultisampleState = &multisampling;\n\tpipelineInfo.pColorBlendState = &colorBlending;\n\tpipelineInfo.layout = m_pipelineLayout;\n\tpipelineInfo.renderPass = chainInfo.m_swapchainRenderPass;\n\tpipelineInfo.subpass = 0;\n\tpipelineInfo.basePipelineHandle = VK_NULL_HANDLE;\n\n\tVkPipeline pipeline = nullptr;\n\tstd::shared_lock lock(m_pipeline_cache_save_mutex);\n\tresult = vkCreateGraphicsPipelines(m_logicalDevice, m_pipeline_cache, 1, &pipelineInfo, nullptr, &pipeline);\n\tif (result != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to create graphics pipeline. Error {}\", result);\n\t\tthrow std::runtime_error(fmt::format(\"Failed to create graphics pipeline: {}\", result));\n\t}\n\n\tm_backbufferBlitPipelineCache[hash] = pipeline;\n\tm_pipeline_cache_semaphore.notify();\n\n\treturn pipeline;\n}\n\nbool VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow)\n{\n\tif(!IsSwapchainInfoValid(mainWindow))\n\t\treturn false;\n\n\tif(!mainWindow && m_destroyPadSwapchainNextAcquire.test())\n\t{\n\t\tRecreateSwapchain(mainWindow, true);\n\t\tm_destroyPadSwapchainNextAcquire.clear();\n\t\tm_destroyPadSwapchainNextAcquire.notify_all();\n\t\treturn false;\n\t}\n\n\tauto& chainInfo = GetChainInfo(mainWindow);\n\n\tif (chainInfo.swapchainImageIndex != -1)\n\t\treturn true; // image already reserved\n\n\tif (!UpdateSwapchainProperties(mainWindow))\n\t\treturn false;\n\n\tbool result = chainInfo.AcquireImage();\n\tif (!result)\n\t\treturn false;\n\n\tSubmitCommandBuffer(VK_NULL_HANDLE, chainInfo.ConsumeAcquireSemaphore());\n\treturn true;\n}\n\nvoid VulkanRenderer::RecreateSwapchain(bool mainWindow, bool skipCreate)\n{\n\tSubmitCommandBuffer();\n\tWaitDeviceIdle();\n\tauto& chainInfo = GetChainInfo(mainWindow);\n\n\tVector2i size;\n\tif (mainWindow)\n\t{\n\t\tImGui_ImplVulkan_Shutdown();\n\t\tWindowSystem::GetWindowPhysSize(size.x, size.y);\n\t}\n\telse\n\t{\n\t\tWindowSystem::GetPadWindowPhysSize(size.x, size.y);\n\t}\n\n\tchainInfo.swapchainImageIndex = -1;\n\tchainInfo.Cleanup();\n\tchainInfo.m_desiredExtent = size;\n\tif(!skipCreate)\n\t{\n\t\tchainInfo.Create();\n\t}\n\n\tif (mainWindow)\n\t\tImguiInit();\n}\n\nbool VulkanRenderer::UpdateSwapchainProperties(bool mainWindow)\n{\n\tauto& chainInfo = GetChainInfo(mainWindow);\n\tbool stateChanged = chainInfo.m_shouldRecreate;\n\n\tconst auto configValue =  (VSync)GetConfig().vsync.GetValue();\n\tif(chainInfo.m_vsyncState != configValue)\n\t\tstateChanged = true;\n\n\tint width, height;\n\tif (mainWindow)\n\t\tWindowSystem::GetWindowPhysSize(width, height);\n\telse\n\t\tWindowSystem::GetPadWindowPhysSize(width, height);\n\tauto extent = chainInfo.getExtent();\n\tif (width != extent.width || height != extent.height)\n\t\tstateChanged = true;\n\n\tif(stateChanged)\n\t{\n\t\ttry\n\t\t{\n\t\t\tRecreateSwapchain(mainWindow);\n\t\t}\n\t\tcatch (std::exception&)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tchainInfo.m_shouldRecreate = false;\n\tchainInfo.m_vsyncState = configValue;\n\treturn true;\n}\n\nvoid VulkanRenderer::SwapBuffer(bool mainWindow)\n{\n\tif(!AcquireNextSwapchainImage(mainWindow))\n\t\treturn;\n\n\tauto& chainInfo = GetChainInfo(mainWindow);\n\n\tif (!chainInfo.hasDefinedSwapchainImage)\n\t{\n\t\t// set the swapchain image to a defined state\n\t\tVkClearColorValue clearColor{ 0, 0, 0, 0 };\n\t\tClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);\n\t}\n\n\tconst size_t currentFrameCmdBufferID = GetCurrentCommandBufferId();\n\n\tVkSemaphore presentSemaphore = chainInfo.m_presentSemaphores[chainInfo.swapchainImageIndex];\n\tSubmitCommandBuffer(presentSemaphore); // submit all command and signal semaphore\n\n\tcemu_assert_debug(m_numSubmittedCmdBuffers > 0);\n\n\t// wait for the previous frame to finish rendering\n\tWaitCommandBufferFinished(m_commandBufferIDOfPrevFrame);\n\tm_commandBufferIDOfPrevFrame = currentFrameCmdBufferID;\n\n\tchainInfo.WaitAvailableFence();\n\n\tVkPresentIdKHR presentId = {};\n\n\tVkPresentInfoKHR presentInfo = {};\n\tpresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;\n\tpresentInfo.swapchainCount = 1;\n\tpresentInfo.pSwapchains = &chainInfo.m_swapchain;\n\tpresentInfo.pImageIndices = &chainInfo.swapchainImageIndex;\n\t// wait on command buffer semaphore\n\tpresentInfo.waitSemaphoreCount = 1;\n\tpresentInfo.pWaitSemaphores = &presentSemaphore;\n\n\t// if present_wait is available and enabled, add frame markers to present requests\n\t// and limit the number of queued present operations\n\tif (m_featureControl.deviceExtensions.present_wait && chainInfo.m_maxQueued > 0)\n\t{\n\t\tpresentId.sType = VK_STRUCTURE_TYPE_PRESENT_ID_KHR;\n\t\tpresentId.swapchainCount = 1;\n\t\tpresentId.pPresentIds = &chainInfo.m_presentId;\n\n\t\tpresentInfo.pNext = &presentId;\n\n\t\tif(chainInfo.m_queueDepth >= chainInfo.m_maxQueued)\n\t\t{\n\t\t\tuint64 waitFrameId = chainInfo.m_presentId - chainInfo.m_queueDepth;\n\t\t\tvkWaitForPresentKHR(m_logicalDevice, chainInfo.m_swapchain, waitFrameId, 40'000'000);\n\t\t\tchainInfo.m_queueDepth--;\n\t\t}\n\t}\n\n\tVkResult result = vkQueuePresentKHR(m_presentQueue, &presentInfo);\n\tif (result < 0 && result != VK_ERROR_OUT_OF_DATE_KHR)\n\t{\n\t\tthrow std::runtime_error(fmt::format(\"Failed to present image: {}\", result));\n\t}\n\tif(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)\n\t\tchainInfo.m_shouldRecreate = true;\n\n\tif(result >= 0)\n\t{\n\t\tchainInfo.m_queueDepth++;\n\t\tchainInfo.m_presentId++;\n\t}\n\n\tchainInfo.hasDefinedSwapchainImage = false;\n\n\tchainInfo.swapchainImageIndex = -1;\n}\n\nvoid VulkanRenderer::Flush(bool waitIdle)\n{\n\tif (m_recordedDrawcalls > 0 || m_submitOnIdle)\n\t\tSubmitCommandBuffer();\n\tif (waitIdle)\n\t\tWaitCommandBufferFinished(GetCurrentCommandBufferId());\n}\n\nvoid VulkanRenderer::NotifyLatteCommandProcessorIdle()\n{\n\tif (m_submitOnIdle)\n\t\tSubmitCommandBuffer();\n}\n\nvoid VulkanBenchmarkPrintResults();\n\nvoid VulkanRenderer::SwapBuffers(bool swapTV, bool swapDRC)\n{\n\tSubmitCommandBuffer();\n\n\tif (swapTV && IsSwapchainInfoValid(true))\n\t\tSwapBuffer(true);\n\n\tif (swapDRC && IsSwapchainInfoValid(false))\n\t\tSwapBuffer(false);\n\n\tif(swapTV)\n\t\tVulkanBenchmarkPrintResults();\n}\n\nvoid VulkanRenderer::ClearColorbuffer(bool padView)\n{\n\tif (!IsSwapchainInfoValid(!padView))\n\t\treturn;\n\n\tauto& chainInfo = GetChainInfo(!padView);\n\tif (chainInfo.swapchainImageIndex == -1)\n\t\treturn;\n\n\tVkClearColorValue clearColor{ 0, 0, 0, 0 };\n\tClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);\n}\n\nvoid VulkanRenderer::ClearColorImageRaw(VkImage image, uint32 sliceIndex, uint32 mipIndex, const VkClearColorValue& color, VkImageLayout inputLayout, VkImageLayout outputLayout)\n{\n\tdraw_endRenderPass();\n\n\tVkImageSubresourceRange subresourceRange{};\n\tsubresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\tsubresourceRange.baseMipLevel = mipIndex;\n\tsubresourceRange.levelCount = 1;\n\tsubresourceRange.baseArrayLayer = sliceIndex;\n\tsubresourceRange.layerCount = 1;\n\n\tbarrier_image<SYNC_OP::ANY_TRANSFER | SYNC_OP::IMAGE_READ | SYNC_OP::IMAGE_WRITE, SYNC_OP::ANY_TRANSFER>(image, subresourceRange, inputLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);\n\n\tvkCmdClearColorImage(m_state.currentCommandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &color, 1, &subresourceRange);\n\n    barrier_image<ANY_TRANSFER, SYNC_OP::ANY_TRANSFER | SYNC_OP::IMAGE_READ | SYNC_OP::IMAGE_WRITE>(image, subresourceRange, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, outputLayout);\n}\n\nvoid VulkanRenderer::ClearColorImage(LatteTextureVk* vkTexture, uint32 sliceIndex, uint32 mipIndex, const VkClearColorValue& color, VkImageLayout outputLayout)\n{\n\tif(vkTexture->isDepth)\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn;\n\t}\n\tif (vkTexture->IsCompressedFormat())\n\t{\n\t\t// vkCmdClearColorImage cannot be called on compressed formats\n\t\t// for now we ignore affected clears but still transition the image to the correct layout\n\t\tauto imageObj = vkTexture->GetImageObj();\n\t\timageObj->flagForCurrentCommandBuffer();\n\t\tVkImageSubresourceLayers subresourceRange{};\n\t\tsubresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\tsubresourceRange.mipLevel = mipIndex;\n\t\tsubresourceRange.baseArrayLayer = sliceIndex;\n\t\tsubresourceRange.layerCount = 1;\n\t\tbarrier_image<ANY_TRANSFER | IMAGE_READ, ANY_TRANSFER | IMAGE_READ | IMAGE_WRITE>(vkTexture, subresourceRange, outputLayout);\n\t\tif(color.float32[0] == 0.0f && color.float32[1] == 0.0f && color.float32[2] == 0.0f && color.float32[3] == 0.0f)\n\t\t{\n\t\t\tstatic bool dbgMsgPrinted = false;\n\t\t\tif(!dbgMsgPrinted)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported compressed texture clear to zero\");\n\t\t\t\tdbgMsgPrinted = true;\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\n\tVkImageSubresourceRange subresourceRange;\n\n\tsubresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\tsubresourceRange.baseMipLevel = mipIndex;\n\tsubresourceRange.levelCount = 1;\n\tsubresourceRange.baseArrayLayer = sliceIndex;\n\tsubresourceRange.layerCount = 1;\n\n\tauto imageObj = vkTexture->GetImageObj();\n\timageObj->flagForCurrentCommandBuffer();\n\n\tVkImageLayout inputLayout = vkTexture->GetImageLayout(subresourceRange);\n\tClearColorImageRaw(imageObj->m_image, sliceIndex, mipIndex, color, inputLayout, outputLayout);\n\tvkTexture->SetImageLayout(subresourceRange, outputLayout);\n}\n\nvoid VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight, bool padView, bool clearBackground)\n{\n\tif(!AcquireNextSwapchainImage(!padView))\n\t\treturn;\n\n\tauto& chainInfo = GetChainInfo(!padView);\n\tLatteTextureViewVk* texViewVk = (LatteTextureViewVk*)texView;\n\tdraw_endRenderPass();\n\n\t// barrier for input texture\n\tVkMemoryBarrier memoryBarrier{};\n\tmemoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;\n\tVkPipelineStageFlags srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;\n\tVkPipelineStageFlags dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;\n\tmemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;\n\tmemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT;\n\tvkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStage, dstStage, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);\n\n\tauto pipeline = backbufferBlit_createGraphicsPipeline(m_swapchainDescriptorSetLayout, padView, shader);\n\n\tVkRenderPassBeginInfo renderPassInfo = {};\n\trenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n\trenderPassInfo.renderPass = chainInfo.m_swapchainRenderPass;\n\trenderPassInfo.framebuffer = chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex];\n\trenderPassInfo.renderArea.offset = { 0, 0 };\n\trenderPassInfo.renderArea.extent = chainInfo.getExtent();\n\trenderPassInfo.clearValueCount = 0;\n\n\tVkViewport viewport{};\n\tviewport.x = imageX;\n\tviewport.y = imageY;\n\tviewport.width = imageWidth;\n\tviewport.height = imageHeight;\n\tviewport.minDepth = 0.0f;\n\tviewport.maxDepth = 1.0f;\n\tvkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &viewport);\n\n\tVkRect2D scissor{};\n\tscissor.extent = chainInfo.getExtent();\n\tvkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &scissor);\n\n\tauto descriptSet = backbufferBlit_createDescriptorSet(m_swapchainDescriptorSetLayout, texViewVk, useLinearTexFilter);\n\n\tvkCmdBeginRenderPass(m_state.currentCommandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);\n\n\tif (clearBackground)\n\t{\n\t\tVkClearAttachment clearAttachment{};\n\t\tclearAttachment.clearValue = {0,0,0,0};\n\t\tclearAttachment.colorAttachment = 0;\n\t\tclearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\t\tVkClearRect clearExtent = {{{0,0},chainInfo.m_actualExtent}, 0, 1};\n\t\tvkCmdClearAttachments(m_state.currentCommandBuffer, 1, &clearAttachment, 1, &clearExtent);\n\t}\n\n\tvkCmdBindPipeline(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);\n\tm_state.currentPipeline = pipeline;\n\n\tauto outputUniforms = shader->FillUniformBlockBuffer(*texView, {imageWidth, imageHeight}, padView);\n\n\tauto outputUniformOffset = uniformData_uploadUniformDataBufferGetOffset({(uint8*)&outputUniforms, sizeof(decltype(outputUniforms))});\n\n\tvkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &descriptSet,\n\t\t1, &outputUniformOffset);\n\n\tvkCmdDraw(m_state.currentCommandBuffer, 6, 1, 0, 0);\n\n\tvkCmdEndRenderPass(m_state.currentCommandBuffer);\n\n\t// restore viewport\n\tvkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &m_state.currentViewport);\n\n\t// mark current swapchain image as well defined\n\tchainInfo.hasDefinedSwapchainImage = true;\n}\n\nvoid VulkanRenderer::CreateDescriptorPool()\n{\n\tstd::array<VkDescriptorPoolSize, 4> poolSizes = {};\n\tpoolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\tpoolSizes[0].descriptorCount = 1024 * 128;\n\tpoolSizes[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n\tpoolSizes[1].descriptorCount = 1024 * 1;\n\tpoolSizes[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;\n\tpoolSizes[2].descriptorCount = 1024 * 128;\n\tpoolSizes[3].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;\n\tpoolSizes[3].descriptorCount = 1024 * 4;\n\n\tVkDescriptorPoolCreateInfo poolInfo = {};\n\tpoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;\n\tpoolInfo.poolSizeCount = poolSizes.size();\n\tpoolInfo.pPoolSizes = poolSizes.data();\n\tpoolInfo.maxSets = 1024 * 256;\n\tpoolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;\n\n\tif (vkCreateDescriptorPool(m_logicalDevice, &poolInfo, nullptr, &m_descriptorPool) != VK_SUCCESS)\n\t\tUnrecoverableError(\"Failed to create descriptor pool!\");\n}\n\nVkDescriptorSet VulkanRenderer::backbufferBlit_createDescriptorSet(VkDescriptorSetLayout descriptor_set_layout, LatteTextureViewVk* texViewVk, bool useLinearTexFilter)\n{\n\tuint64 hash = 0;\n\thash += (uint64)texViewVk->GetViewRGBA();\n\thash += (uint64)texViewVk->GetDefaultTextureSampler(useLinearTexFilter);\n\n\tconst auto it = m_backbufferBlitDescriptorSetCache.find(hash);\n\tif (it != m_backbufferBlitDescriptorSetCache.cend())\n\t\treturn it->second;\n\n\tVkDescriptorSetAllocateInfo allocInfo = {};\n\tallocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n\tallocInfo.descriptorPool = m_descriptorPool;\n\tallocInfo.descriptorSetCount = 1;\n\tallocInfo.pSetLayouts = &descriptor_set_layout;\n\n\tVkDescriptorSet result;\n\tif (vkAllocateDescriptorSets(m_logicalDevice, &allocInfo, &result) != VK_SUCCESS)\n\t\tUnrecoverableError(\"Failed to allocate descriptor sets for backbuffer blit\");\n\tperformanceMonitor.vk.numDescriptorSets.increment();\n\n\tVkDescriptorImageInfo imageInfo = {};\n\timageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\timageInfo.imageView = texViewVk->GetViewRGBA()->m_textureImageView;\n\timageInfo.sampler = texViewVk->GetDefaultTextureSampler(useLinearTexFilter);\n\n\tVkWriteDescriptorSet descriptorWrites[2]{};\n\n\tVkWriteDescriptorSet& samplerWrite = descriptorWrites[0];\n\tsamplerWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n\tsamplerWrite.dstSet = result;\n\tsamplerWrite.dstBinding = 0;\n\tsamplerWrite.dstArrayElement = 0;\n\tsamplerWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\tsamplerWrite.descriptorCount = 1;\n\tsamplerWrite.pImageInfo = &imageInfo;\n\n\tVkWriteDescriptorSet& uniformBufferWrite = descriptorWrites[1];\n\tuniformBufferWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n\tuniformBufferWrite.dstSet = result;\n\tuniformBufferWrite.dstBinding = 1;\n\tuniformBufferWrite.descriptorCount = 1;\n\tuniformBufferWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;\n\n\tVkDescriptorBufferInfo uniformBufferInfo{};\n\tuniformBufferInfo.buffer = m_uniformVarBuffer;\n\tuniformBufferInfo.offset = 0;\n\tuniformBufferInfo.range = sizeof(RendererOutputShader::OutputUniformVariables);\n\tuniformBufferWrite.pBufferInfo = &uniformBufferInfo;\n\n\n\tvkUpdateDescriptorSets(m_logicalDevice, std::size(descriptorWrites), descriptorWrites, 0, nullptr);\n\tperformanceMonitor.vk.numDescriptorSamplerTextures.increment();\n\n\tm_backbufferBlitDescriptorSetCache[hash] = result;\n\treturn result;\n}\n\nvoid VulkanRenderer::renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ)\n{\n\t// the Vulkan renderer handles halfZ in the vertex shader\n\n\tfloat vpNewX = x;\n\tfloat vpNewY = y + height;\n\tfloat vpNewWidth = width;\n\tfloat vpNewHeight = -height;\n\n\tif (m_state.currentViewport.x == vpNewX && m_state.currentViewport.y == vpNewY && m_state.currentViewport.width == vpNewWidth && m_state.currentViewport.height == vpNewHeight && m_state.currentViewport.minDepth == nearZ && m_state.currentViewport.maxDepth == farZ)\n\t\treturn; // viewport did not change\n\n\tm_state.currentViewport.x = vpNewX;\n\tm_state.currentViewport.y = vpNewY;\n\tm_state.currentViewport.width = vpNewWidth;\n\tm_state.currentViewport.height = vpNewHeight;\n\n\tm_state.currentViewport.minDepth = nearZ;\n\tm_state.currentViewport.maxDepth = farZ;\n\n\tvkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &m_state.currentViewport);\n}\n\n\nvoid VulkanRenderer::renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight)\n{\n\tm_state.currentScissorRect.offset.x = scissorX;\n\tm_state.currentScissorRect.offset.y = scissorY;\n\tm_state.currentScissorRect.extent.width = scissorWidth;\n\tm_state.currentScissorRect.extent.height = scissorHeight;\n\tvkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &m_state.currentScissorRect);\n}\n\nLatteCachedFBO* VulkanRenderer::rendertarget_createCachedFBO(uint64 key)\n{\n\treturn new CachedFBOVk(key, m_logicalDevice);\n}\n\nvoid VulkanRenderer::rendertarget_deleteCachedFBO(LatteCachedFBO* cfbo)\n{\n\tif (cfbo == m_state.activeFBO)\n\t\tm_state.activeFBO = nullptr;\n}\n\nvoid VulkanRenderer::rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo)\n{\n\tm_state.activeFBO = (CachedFBOVk*)cfbo;\n}\n\nvoid* VulkanRenderer::texture_acquireTextureUploadBuffer(uint32 size)\n{\n\treturn memoryManager->TextureUploadBufferAcquire(size);\n}\n\nvoid VulkanRenderer::texture_releaseTextureUploadBuffer(uint8* mem)\n{\n\tmemoryManager->TextureUploadBufferRelease(mem);\n}\n\nTextureDecoder* VulkanRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height)\n{\n\tFormatInfoVK texFormatInfo{};\n\tGetTextureFormatInfoVK(format, isDepth, dim, width, height, &texFormatInfo);\n\treturn texFormatInfo.decoder;\n}\n\nvoid VulkanRenderer::ReleaseDestructibleObject(VKRDestructibleObject* destructibleObject)\n{\n\t// destroy immediately if possible\n\tif (destructibleObject->canDestroy())\n\t{\n\t\tdelete destructibleObject;\n\t\treturn;\n\t}\n\t// otherwise put on queue\n\tm_spinlockDestructionQueue.lock();\n\tm_destructionQueue.emplace_back(destructibleObject);\n\tm_spinlockDestructionQueue.unlock();\n}\n\nvoid VulkanRenderer::ProcessDestructionQueue()\n{\n\tm_spinlockDestructionQueue.lock();\n\tfor (auto it = m_destructionQueue.begin(); it != m_destructionQueue.end();)\n\t{\n\t\tif ((*it)->canDestroy())\n\t\t{\n\t\t\tdelete (*it);\n\t\t\tit = m_destructionQueue.erase(it);\n\t\t\tcontinue;\n\t\t}\n\t\t++it;\n\t}\n\tm_spinlockDestructionQueue.unlock();\n}\n\nVkDescriptorSetInfo::~VkDescriptorSetInfo()\n{\n\tfor (auto& it : list_referencedViews)\n\t\tit->RemoveDescriptorSetReference(this);\n\t// unregister\n\tswitch (shaderType)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t{\n\t\tauto r = pipeline_info->vertex_ds_cache.erase(stateHash);\n\t\tcemu_assert_debug(r == 1);\n\t\tbreak;\n\t}\n\tcase LatteConst::ShaderType::Pixel:\n\t{\n\t\tauto r = pipeline_info->pixel_ds_cache.erase(stateHash);\n\t\tcemu_assert_debug(r == 1);\n\t\tbreak;\n\t}\n\tcase LatteConst::ShaderType::Geometry:\n\t{\n\t\tauto r = pipeline_info->geometry_ds_cache.erase(stateHash);\n\t\tcemu_assert_debug(r == 1);\n\t\tbreak;\n\t}\n\tdefault:\n\t\tUNREACHABLE;\n\t}\n\t// update global stats\n\tperformanceMonitor.vk.numDescriptorSamplerTextures.decrement(statsNumSamplerTextures);\n\tperformanceMonitor.vk.numDescriptorDynUniformBuffers.decrement(statsNumDynUniformBuffers);\n\tperformanceMonitor.vk.numDescriptorStorageBuffers.decrement(statsNumStorageBuffers);\n\n\tauto renderer = VulkanRenderer::GetInstance();\n\trenderer->ReleaseDestructibleObject(m_vkObjDescriptorSet);\n\tm_vkObjDescriptorSet = nullptr;\n}\n\nvoid VulkanRenderer::texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex)\n{\n\tdraw_endRenderPass();\n\tauto vkTexture = (LatteTextureVk*)hostTexture;\n\tif (vkTexture->isDepth)\n\t\ttexture_clearDepthSlice(hostTexture, sliceIndex, mipIndex, true, vkTexture->hasStencil, 0.0f, 0);\n\telse\n\t{\n\t\tcemu_assert_debug(vkTexture->dim != Latte::E_DIM::DIM_3D);\n\t\tClearColorImage(vkTexture, sliceIndex, mipIndex, { 0,0,0,0 }, VK_IMAGE_LAYOUT_GENERAL);\n\t}\n}\n\nvoid VulkanRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a)\n{\n\tauto vkTexture = (LatteTextureVk*)hostTexture;\n\tif(vkTexture->dim == Latte::E_DIM::DIM_3D)\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\tClearColorImage(vkTexture, sliceIndex, mipIndex, {r, g, b, a}, VK_IMAGE_LAYOUT_GENERAL);\n}\n\nvoid VulkanRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue)\n{\n\tdraw_endRenderPass(); // vkCmdClearDepthStencilImage must not be inside renderpass\n\n\tauto vkTexture = (LatteTextureVk*)hostTexture;\n\n\tVkImageAspectFlags imageAspect = vkTexture->GetImageAspect();\n\n\tVkImageAspectFlags aspectMask = 0;\n\tif (clearDepth && (imageAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)\n\t\taspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;\n\tif (clearStencil && (imageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)\n\t\taspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;\n\n\tauto imageObj = vkTexture->GetImageObj();\n\timageObj->flagForCurrentCommandBuffer();\n\n\tVkImageSubresourceLayers subresourceRange{};\n\tsubresourceRange.aspectMask = vkTexture->GetImageAspect();\n\tsubresourceRange.mipLevel = mipIndex;\n\tsubresourceRange.baseArrayLayer = sliceIndex;\n\tsubresourceRange.layerCount = 1;\n\tbarrier_image<ANY_TRANSFER | IMAGE_READ | IMAGE_WRITE, ANY_TRANSFER>(vkTexture, subresourceRange, VK_IMAGE_LAYOUT_GENERAL);\n\n\tVkClearDepthStencilValue depthStencilValue{};\n\tdepthStencilValue.depth = depthValue;\n\tdepthStencilValue.stencil = stencilValue;\n\n\tVkImageSubresourceRange range{};\n\trange.baseMipLevel = mipIndex;\n\trange.levelCount = 1;\n\trange.baseArrayLayer = sliceIndex;\n\trange.layerCount = 1;\n\n\trange.aspectMask = aspectMask;\n\n\tvkCmdClearDepthStencilImage(m_state.currentCommandBuffer, imageObj->m_image, VK_IMAGE_LAYOUT_GENERAL, &depthStencilValue, 1, &range);\n\n\tbarrier_image<ANY_TRANSFER, ANY_TRANSFER | IMAGE_READ | IMAGE_WRITE>(vkTexture, subresourceRange, VK_IMAGE_LAYOUT_GENERAL);\n}\n\nvoid VulkanRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize)\n{\n\tauto vkTexture = (LatteTextureVk*)hostTexture;\n\tauto vkImageObj = vkTexture->GetImageObj();\n\tvkImageObj->flagForCurrentCommandBuffer();\n\n\tdraw_endRenderPass();\n\n\tVkMemoryRequirements memRequirements;\n\tvkGetImageMemoryRequirements(m_logicalDevice, vkImageObj->m_image, &memRequirements);\n\n\tuint32 uploadSize = compressedImageSize;// memRequirements.size;\n\tuint32 uploadAlignment = memRequirements.alignment;\n\n\tVKRSynchronizedRingAllocator& vkMemAllocator = memoryManager->getStagingAllocator();\n\n\tauto uploadResv = vkMemAllocator.AllocateBufferMemory(uploadSize, uploadAlignment);\n\tmemcpy(uploadResv.memPtr, pixelData, compressedImageSize);\n\tvkMemAllocator.FlushReservation(uploadResv);\n\n\tFormatInfoVK texFormatInfo;\n\tGetTextureFormatInfoVK(hostTexture->format, hostTexture->isDepth, hostTexture->dim, 0, 0, &texFormatInfo);\n\n\tbool is3DTexture = hostTexture->Is3DTexture();\n\n\tVkImageSubresourceLayers barrierSubresourceRange{};\n\tbarrierSubresourceRange.aspectMask = texFormatInfo.vkImageAspect;\n\tbarrierSubresourceRange.mipLevel = mipIndex;\n\tbarrierSubresourceRange.baseArrayLayer = is3DTexture ? 0 : sliceIndex;\n\tbarrierSubresourceRange.layerCount = 1;\n\tbarrier_image<ANY_TRANSFER | IMAGE_READ | IMAGE_WRITE | HOST_WRITE, ANY_TRANSFER>(vkTexture, barrierSubresourceRange, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);\n\n\tVkBufferImageCopy imageRegion[2]{};\n\tsint32 imageRegionCount = 0;\n\tif (texFormatInfo.vkImageAspect == VK_IMAGE_ASPECT_COLOR_BIT || texFormatInfo.vkImageAspect == VK_IMAGE_ASPECT_DEPTH_BIT)\n\t{\n\t\timageRegion[0].bufferOffset = uploadResv.bufferOffset;\n\t\timageRegion[0].imageExtent.width = width;\n\t\timageRegion[0].imageExtent.height = height;\n\t\timageRegion[0].imageExtent.depth = 1;\n\t\timageRegion[0].imageOffset.z = is3DTexture ? sliceIndex : 0;\n\n\t\timageRegion[0].imageSubresource.mipLevel = mipIndex;\n\t\timageRegion[0].imageSubresource.aspectMask = texFormatInfo.vkImageAspect;\n\t\timageRegion[0].imageSubresource.baseArrayLayer = is3DTexture ? 0 : sliceIndex;\n\t\timageRegion[0].imageSubresource.layerCount = 1;\n\t\timageRegionCount = 1;\n\t}\n\telse if (texFormatInfo.vkImageAspect == VK_IMAGE_ASPECT_DEPTH_BIT)\n\t{\n\t\tif (is3DTexture)\n\t\t\tcemu_assert_debug(false);\n\n\t\t// depth only copy\n\t\timageRegion[0].bufferOffset = uploadResv.bufferOffset;\n\t\timageRegion[0].imageExtent.width = width;\n\t\timageRegion[0].imageExtent.height = height;\n\t\timageRegion[0].imageExtent.depth = 1;\n\n\t\timageRegion[0].imageSubresource.mipLevel = mipIndex;\n\t\timageRegion[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;\n\t\timageRegion[0].imageSubresource.baseArrayLayer = sliceIndex;\n\t\timageRegion[0].imageSubresource.layerCount = 1;\n\n\t\timageRegionCount = 1;\n\t}\n\telse if (texFormatInfo.vkImageAspect == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))\n\t{\n\t\tif (is3DTexture)\n\t\t\tcemu_assert_debug(false);\n\n\t\t// depth copy\n\t\timageRegion[0].bufferOffset = uploadResv.bufferOffset;\n\t\timageRegion[0].imageExtent.width = width;\n\t\timageRegion[0].imageExtent.height = height;\n\t\timageRegion[0].imageExtent.depth = 1;\n\n\t\timageRegion[0].imageSubresource.mipLevel = mipIndex;\n\t\timageRegion[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;\n\t\timageRegion[0].imageSubresource.baseArrayLayer = sliceIndex;\n\t\timageRegion[0].imageSubresource.layerCount = 1;\n\n\t\t// stencil copy\n\t\timageRegion[1].bufferOffset = uploadResv.bufferOffset;\n\t\timageRegion[1].imageExtent.width = width;\n\t\timageRegion[1].imageExtent.height = height;\n\t\timageRegion[1].imageExtent.depth = 1;\n\n\t\timageRegion[1].imageSubresource.mipLevel = mipIndex;\n\t\timageRegion[1].imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;\n\t\timageRegion[1].imageSubresource.baseArrayLayer = sliceIndex;\n\t\timageRegion[1].imageSubresource.layerCount = 1;\n\n\t\timageRegionCount = 2;\n\t}\n\telse\n\t\tcemu_assert_debug(false);\n\n\tvkCmdCopyBufferToImage(m_state.currentCommandBuffer, uploadResv.vkBuffer, vkImageObj->m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageRegionCount, imageRegion);\n\n\tbarrier_image<ANY_TRANSFER, ANY_TRANSFER | IMAGE_READ | IMAGE_WRITE>(vkTexture, barrierSubresourceRange, VK_IMAGE_LAYOUT_GENERAL);\n}\n\nLatteTexture* VulkanRenderer::texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels,\n\tuint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth)\n{\n\treturn new LatteTextureVk(this, dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth);\n}\n\nvoid VulkanRenderer::texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit)\n{\n\tm_state.boundTexture[textureUnit] = static_cast<LatteTextureViewVk*>(textureView);\n}\n\nvoid VulkanRenderer::texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth)\n{\n\tLatteTextureVk* srcVk = static_cast<LatteTextureVk*>(src);\n\tLatteTextureVk* dstVk = static_cast<LatteTextureVk*>(dst);\n\n\tdraw_endRenderPass(); // vkCmdCopyImage must be called outside of a renderpass\n\n\tVKRObjectTexture* srcVkObj = srcVk->GetImageObj();\n\tVKRObjectTexture* dstVkObj = dstVk->GetImageObj();\n\tsrcVkObj->flagForCurrentCommandBuffer();\n\tdstVkObj->flagForCurrentCommandBuffer();\n\n\tVkImageCopy region{};\n\tregion.srcOffset.x = effectiveSrcX;\n\tregion.srcOffset.y = effectiveSrcY;\n\tregion.dstOffset.x = effectiveDstX;\n\tregion.dstOffset.y = effectiveDstY;\n\tregion.extent.width = effectiveCopyWidth;\n\tregion.extent.height = effectiveCopyHeight;\n\tregion.extent.depth = 1;\n\n\tif (src->Is3DTexture())\n\t{\n\t\tregion.srcOffset.z = srcSlice;\n\t\tregion.extent.depth = srcDepth;\n\t\tregion.srcSubresource.baseArrayLayer = 0;\n\t\tregion.srcSubresource.layerCount = 1;\n\t}\n\telse\n\t{\n\t\tregion.srcOffset.z = 0;\n\t\tregion.extent.depth = 1;\n\t\tregion.srcSubresource.baseArrayLayer = srcSlice;\n\t\tregion.srcSubresource.layerCount = srcDepth;\n\t}\n\n\tif (dst->Is3DTexture())\n\t{\n\t\tregion.dstOffset.z = dstSlice;\n\t\tregion.dstSubresource.baseArrayLayer = 0;\n\t\tregion.dstSubresource.layerCount = 1;\n\t}\n\telse\n\t{\n\t\tregion.dstOffset.z = 0;\n\t\tregion.dstSubresource.baseArrayLayer = dstSlice;\n\t\tregion.dstSubresource.layerCount = srcDepth;\n\t}\n\n\tregion.srcSubresource.mipLevel = srcMip;\n\tregion.srcSubresource.aspectMask = srcVk->GetImageAspect();\n\n\tregion.dstSubresource.mipLevel = dstMip;\n\tregion.dstSubresource.aspectMask = dstVk->GetImageAspect();\n\n\tbool srcIsCompressed = Latte::IsCompressedFormat(srcVk->format);\n\tbool dstIsCompressed = Latte::IsCompressedFormat(dstVk->format);\n\n\tif (!srcIsCompressed && dstIsCompressed)\n\t{\n\t\t// handle the special case where the destination is compressed and not a multiple of the texel size (4)\n\t\tsint32 mipWidth = std::max(dst->width >> dstMip, 1);\n\t\tsint32 mipHeight = std::max(dst->height >> dstMip, 1);\n\n\n\t\tif (mipWidth < 4 || mipHeight < 4)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"vkCmdCopyImage - blocked copy for unsupported uncompressed->compressed copy with dst smaller than 4x4\");\n\t\t\treturn;\n\t\t}\n\n\t}\n\n\t// make sure all write operations to the src image have finished\n\tbarrier_image<SYNC_OP::IMAGE_WRITE | SYNC_OP::ANY_TRANSFER, SYNC_OP::ANY_TRANSFER>(srcVk, region.srcSubresource, VK_IMAGE_LAYOUT_GENERAL);\n\t// make sure all read and write operations to the dst image have finished\n\tbarrier_image<SYNC_OP::IMAGE_READ | SYNC_OP::IMAGE_WRITE | SYNC_OP::ANY_TRANSFER, SYNC_OP::ANY_TRANSFER>(dstVk, region.dstSubresource, VK_IMAGE_LAYOUT_GENERAL);\n\n\tvkCmdCopyImage(m_state.currentCommandBuffer, srcVkObj->m_image, VK_IMAGE_LAYOUT_GENERAL, dstVkObj->m_image, VK_IMAGE_LAYOUT_GENERAL, 1, &region);\n\n\t// make sure the transfer is finished before the image is read or written\n\tbarrier_image<SYNC_OP::ANY_TRANSFER, SYNC_OP::IMAGE_READ | SYNC_OP::IMAGE_WRITE | SYNC_OP::ANY_TRANSFER>(dstVk, region.dstSubresource, VK_IMAGE_LAYOUT_GENERAL);\n}\n\nLatteTextureReadbackInfo* VulkanRenderer::texture_createReadback(LatteTextureView* textureView)\n{\n\tauto* result = new LatteTextureReadbackInfoVk(m_logicalDevice, textureView);\n\n\tLatteTextureVk* vkTex = (LatteTextureVk*)textureView->baseTexture;\n\n\tVkMemoryRequirements memRequirements;\n\tvkGetImageMemoryRequirements(m_logicalDevice, vkTex->GetImageObj()->m_image, &memRequirements);\n\n\tconst uint32 linearImageSize = result->GetImageSize();\n\tconst uint32 uploadSize = (linearImageSize == 0) ? memRequirements.size : linearImageSize;\n\tconst uint32 uploadAlignment = 256; // todo - use Vk optimalBufferCopyOffsetAlignment\n\tm_textureReadbackBufferWriteIndex = (m_textureReadbackBufferWriteIndex + uploadAlignment - 1) & ~(uploadAlignment - 1);\n\n\tif ((m_textureReadbackBufferWriteIndex + uploadSize + 256) > TEXTURE_READBACK_SIZE)\n\t{\n\t\tm_textureReadbackBufferWriteIndex = 0;\n\t}\n\n\tconst uint32 uploadBufferOffset = m_textureReadbackBufferWriteIndex;\n\tm_textureReadbackBufferWriteIndex += uploadSize;\n\n\tresult->SetBuffer(m_textureReadbackBuffer, m_textureReadbackBufferPtr, uploadBufferOffset);\n\n\treturn result;\n}\n\nuint32 s_vkCurrentUniqueId = 0;\n\nuint64 VulkanRenderer::GenUniqueId()\n{\n\ts_vkCurrentUniqueId++;\n\treturn s_vkCurrentUniqueId;\n}\n\nvoid VulkanRenderer::streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize)\n{\n\tVkDeviceSize tfBufferOffset = ringBufferOffset;\n\tm_streamoutState.buffer[bufferIndex].enabled = true;\n\tm_streamoutState.buffer[bufferIndex].ringBufferOffset = ringBufferOffset;\n}\n\nvoid VulkanRenderer::streamout_begin()\n{\n\tif (m_featureControl.mode.useTFEmulationViaSSBO)\n\t\treturn;\n\tif (m_state.hasActiveXfb == false)\n\t\tm_state.hasActiveXfb = true;\n}\n\nvoid VulkanRenderer::streamout_applyTransformFeedbackState()\n{\n\tif (m_featureControl.mode.useTFEmulationViaSSBO)\n\t\treturn;\n\tcemu_assert_debug(m_state.hasActiveXfb == false);\n\tif (m_state.hasActiveXfb)\n\t{\n\t\t// set buffers\n\t\tfor (sint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++)\n\t\t{\n\t\t\tif (m_streamoutState.buffer[i].enabled)\n\t\t\t{\n\t\t\t\tVkBuffer tfBuffer = m_xfbRingBuffer;\n\t\t\t\tVkDeviceSize tfBufferOffset = m_streamoutState.buffer[i].ringBufferOffset;\n\t\t\t\tVkDeviceSize tfBufferSize = VK_WHOLE_SIZE;\n\t\t\t\tvkCmdBindTransformFeedbackBuffersEXT(m_state.currentCommandBuffer, i, 1, &tfBuffer, &tfBufferOffset, &tfBufferSize);\n\t\t\t}\n\t\t}\n\t\t// begin transform feedback\n\t\tvkCmdBeginTransformFeedbackEXT(m_state.currentCommandBuffer, 0, 0, nullptr, nullptr);\n\t}\n}\n\nvoid VulkanRenderer::streamout_rendererFinishDrawcall()\n{\n\tif (m_state.hasActiveXfb)\n\t{\n\t\tvkCmdEndTransformFeedbackEXT(m_state.currentCommandBuffer, 0, 0, nullptr, nullptr);\n\t\tm_streamoutState.buffer[0].enabled = false;\n\t\tm_streamoutState.buffer[1].enabled = false;\n\t\tm_streamoutState.buffer[2].enabled = false;\n\t\tm_streamoutState.buffer[3].enabled = false;\n\t\tm_state.hasActiveXfb = false;\n\t}\n}\n\n\nvoid VulkanRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size)\n{\n\tcemu_assert_debug(!m_useHostMemoryForCache);\n\tif (m_state.currentVertexBinding[bufferIndex].offset == offset)\n\t\treturn;\n\tcemu_assert_debug(bufferIndex < LATTE_MAX_VERTEX_BUFFERS);\n\tm_state.currentVertexBinding[bufferIndex].offset = offset;\n\tVkBuffer attrBuffer = m_bufferCache;\n\tVkDeviceSize attrOffset = offset;\n\tvkCmdBindVertexBuffers(m_state.currentCommandBuffer, bufferIndex, 1, &attrBuffer, &attrOffset);\n}\n\nvoid VulkanRenderer::buffer_bindVertexStrideWorkaroundBuffer(VkBuffer fixedBuffer, uint32 offset, uint32 bufferIndex, uint32 size)\n{\n\tcemu_assert_debug(bufferIndex < LATTE_MAX_VERTEX_BUFFERS);\n\tm_state.currentVertexBinding[bufferIndex].offset = 0xFFFFFFFF;\n\tVkBuffer attrBuffer = fixedBuffer;\n\tVkDeviceSize attrOffset = offset;\n\tvkCmdBindVertexBuffers(m_state.currentCommandBuffer, bufferIndex, 1, &attrBuffer, &attrOffset);\n}\n\nstd::pair<VkBuffer, uint32> VulkanRenderer::buffer_genStrideWorkaroundVertexBuffer(MPTR buffer, uint32 size, uint32 oldStride)\n{\n\tcemu_assert_debug(oldStride % 4 != 0);\n\n\tstd::span<uint8> old_buffer{memory_getPointerFromPhysicalOffset(buffer), size};\n\n\t//new stride is the nearest multiple of 4\n\tuint32 newStride = oldStride + (4-(oldStride % 4));\n\tuint32 newSize = size / oldStride * newStride;\n\n\tauto new_buffer_alloc = memoryManager->getMetalStrideWorkaroundAllocator().AllocateBufferMemory(newSize, 128);\n\n\tstd::span<uint8> new_buffer{new_buffer_alloc.memPtr, new_buffer_alloc.size};\n\n\tfor(size_t elem = 0; elem < size / oldStride; elem++)\n\t{\n\t\tmemcpy(&new_buffer[elem * newStride], &old_buffer[elem * oldStride], oldStride);\n\t}\n\treturn {new_buffer_alloc.vkBuffer, new_buffer_alloc.bufferOffset};\n}\n\nvoid VulkanRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size)\n{\n\tcemu_assert_debug(!m_useHostMemoryForCache);\n\tcemu_assert_debug(bufferIndex < 16);\n\tswitch (shaderType)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t\tdynamicOffsetInfo.shaderUB[VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX].uniformBufferOffset[bufferIndex] = offset;\n\t\tbreak;\n\tcase LatteConst::ShaderType::Geometry:\n\t\tdynamicOffsetInfo.shaderUB[VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY].uniformBufferOffset[bufferIndex] = offset;\n\t\tbreak;\n\tcase LatteConst::ShaderType::Pixel:\n\t\tdynamicOffsetInfo.shaderUB[VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT].uniformBufferOffset[bufferIndex] = offset;\n\t\tbreak;\n\tdefault:\n\t\tcemu_assert_debug(false);\n\t}\n}\n\nvoid VulkanRenderer::bufferCache_init(const sint32 bufferSize)\n{\n\tm_importedMemBaseAddress = 0x10000000;\n\tsize_t hostAllocationSize = 0x40000000ull;\n\t// todo - get size of allocation\n\tbool configUseHostMemory = false; // todo - replace this with a config option\n\tm_useHostMemoryForCache = false;\n\tif (m_featureControl.deviceExtensions.external_memory_host && configUseHostMemory)\n\t{\n\t\tm_useHostMemoryForCache = memoryManager->CreateBufferFromHostMemory(memory_getPointerFromVirtualOffset(m_importedMemBaseAddress), hostAllocationSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 0, m_importedMem, m_importedMemMemory);\n\t\tif (!m_useHostMemoryForCache)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Unable to import host memory to Vulkan buffer. Use default cache system instead\");\n\t\t}\n\t}\n\tif(!m_useHostMemoryForCache)\n\t\tmemoryManager->CreateBuffer(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 0, m_bufferCache, m_bufferCacheMemory);\n}\n\nvoid VulkanRenderer::bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset)\n{\n\tdraw_endRenderPass();\n\n\tVKRSynchronizedRingAllocator& vkMemAllocator = memoryManager->getStagingAllocator();\n\n\tauto uploadResv = vkMemAllocator.AllocateBufferMemory(size, 256);\n\tmemcpy(uploadResv.memPtr, buffer, size);\n\n\tvkMemAllocator.FlushReservation(uploadResv);\n\n\tbarrier_bufferRange<ANY_TRANSFER | HOST_WRITE, ANY_TRANSFER,\n\t\tBUFFER_SHADER_READ, TRANSFER_WRITE>(\n\t\t\tuploadResv.vkBuffer, uploadResv.bufferOffset, uploadResv.size, // make sure any in-flight transfers are completed\n\t\t\tm_bufferCache, bufferOffset, size); // make sure all reads are completed before we overwrite the data\n\n\tVkBufferCopy region;\n\tregion.srcOffset = uploadResv.bufferOffset;\n\tregion.dstOffset = bufferOffset;\n\tregion.size = size;\n\tvkCmdCopyBuffer(m_state.currentCommandBuffer, uploadResv.vkBuffer, m_bufferCache, 1, &region);\n\n\tbarrier_sequentializeTransfer();\n}\n\nvoid VulkanRenderer::bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size)\n{\n\tcemu_assert_debug(!m_useHostMemoryForCache);\n\tdraw_endRenderPass();\n\n\tbarrier_sequentializeTransfer();\n\n\tbool isOverlapping = (srcOffset + size) > dstOffset && (srcOffset) < (dstOffset + size);\n\tcemu_assert_debug(!isOverlapping);\n\n\tVkBufferCopy bufferCopy{};\n\tbufferCopy.srcOffset = srcOffset;\n\tbufferCopy.dstOffset = dstOffset;\n\tbufferCopy.size = size;\n\tvkCmdCopyBuffer(m_state.currentCommandBuffer, m_bufferCache, m_bufferCache, 1, &bufferCopy);\n\n\tbarrier_sequentializeTransfer();\n}\n\nvoid VulkanRenderer::bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size)\n{\n\tdraw_endRenderPass();\n\n\tVkBuffer dstBuffer;\n\tif (m_useHostMemoryForCache)\n\t{\n\t\t// in host memory mode, dstOffset is physical address instead of cache address\n\t\tdstBuffer = m_importedMem;\n\t\tdstOffset -= m_importedMemBaseAddress;\n\t}\n\telse\n\t\tdstBuffer = m_bufferCache;\n\n\tbarrier_bufferRange<BUFFER_SHADER_WRITE, TRANSFER_READ,\n\t\tANY_TRANSFER | BUFFER_SHADER_READ, TRANSFER_WRITE>(\n\t\t\tm_xfbRingBuffer, srcOffset, size, // wait for all writes to finish\n\t\t\tdstBuffer, dstOffset, size); // wait for all reads to finish\n\n\tbarrier_sequentializeTransfer();\n\n\tVkBufferCopy bufferCopy{};\n\tbufferCopy.srcOffset = srcOffset;\n\tbufferCopy.dstOffset = dstOffset;\n\tbufferCopy.size = size;\n\tvkCmdCopyBuffer(m_state.currentCommandBuffer, m_xfbRingBuffer, dstBuffer, 1, &bufferCopy);\n\n\tbarrier_sequentializeTransfer();\n}\n\nvoid VulkanRenderer::AppendOverlayDebugInfo()\n{\n\tImGui::Text(\"--- Vulkan debug info ---\");\n\tImGui::Text(\"GfxPipelines   %u\", performanceMonitor.vk.numGraphicPipelines.get());\n\tImGui::Text(\"DescriptorSets %u\", performanceMonitor.vk.numDescriptorSets.get());\n\tImGui::Text(\"DS ImgSamplers %u\", performanceMonitor.vk.numDescriptorSamplerTextures.get());\n\tImGui::Text(\"DS DynUniform  %u\", performanceMonitor.vk.numDescriptorDynUniformBuffers.get());\n\tImGui::Text(\"DS StorageBuf  %u\", performanceMonitor.vk.numDescriptorStorageBuffers.get());\n\tImGui::Text(\"Images         %u\", performanceMonitor.vk.numImages.get());\n\tImGui::Text(\"ImageView      %u\", performanceMonitor.vk.numImageViews.get());\n\tImGui::Text(\"ImageSampler   %u\", performanceMonitor.vk.numSamplers.get());\n\tImGui::Text(\"RenderPass     %u\", performanceMonitor.vk.numRenderPass.get());\n\tImGui::Text(\"Framebuffer    %u\", performanceMonitor.vk.numFramebuffer.get());\n\tm_spinlockDestructionQueue.lock();\n\tImGui::Text(\"DestructionQ   %u\", (unsigned int)m_destructionQueue.size());\n\tm_spinlockDestructionQueue.unlock();\n\n\n\tImGui::Text(\"BeginRP/f      %u\", performanceMonitor.vk.numBeginRenderpassPerFrame.get());\n\tImGui::Text(\"Barriers/f     %u\", performanceMonitor.vk.numDrawBarriersPerFrame.get());\n\tImGui::Text(\"--- Cache debug info ---\");\n\n\tuint32 bufferCacheHeapSize = 0;\n\tuint32 bufferCacheAllocationSize = 0;\n\tuint32 bufferCacheNumAllocations = 0;\n\n\tLatteBufferCache_getStats(bufferCacheHeapSize, bufferCacheAllocationSize, bufferCacheNumAllocations);\n\n\tImGui::Text(\"Buffer\");\n\tImGui::SameLine(60.0f);\n\tImGui::Text(\"%06uKB / %06uKB Allocs: %u\", (uint32)(bufferCacheAllocationSize + 1023) / 1024, ((uint32)bufferCacheHeapSize + 1023) / 1024, (uint32)bufferCacheNumAllocations);\n\n\tuint32 numBuffers;\n\tsize_t totalSize, freeSize;\n\n\tmemoryManager->getStagingAllocator().GetStats(numBuffers, totalSize, freeSize);\n\tImGui::Text(\"Staging\");\n\tImGui::SameLine(60.0f);\n\tImGui::Text(\"%06uKB / %06uKB Buffers: %u\", ((uint32)(totalSize - freeSize) + 1023) / 1024, ((uint32)totalSize + 1023) / 1024, (uint32)numBuffers);\n\n\tmemoryManager->GetIndexAllocator().GetStats(numBuffers, totalSize, freeSize);\n\tImGui::Text(\"Index\");\n\tImGui::SameLine(60.0f);\n\tImGui::Text(\"%06uKB / %06uKB Buffers: %u\", ((uint32)(totalSize - freeSize) + 1023) / 1024, ((uint32)totalSize + 1023) / 1024, (uint32)numBuffers);\n\n\tImGui::Text(\"--- Tex heaps ---\");\n\tmemoryManager->appendOverlayHeapDebugInfo();\n}\n\nvoid VKRDestructibleObject::flagForCurrentCommandBuffer()\n{\n\tm_lastCmdBufferId = VulkanRenderer::GetInstance()->GetCurrentCommandBufferId();\n}\n\nbool VKRDestructibleObject::canDestroy()\n{\n\tif (m_refCount > 0)\n\t\treturn false;\n\treturn VulkanRenderer::GetInstance()->HasCommandBufferFinished(m_lastCmdBufferId);\n}\n\nVKRObjectTexture::VKRObjectTexture()\n{\n\tperformanceMonitor.vk.numImages.increment();\n}\n\nVKRObjectTexture::~VKRObjectTexture()\n{\n\tauto vkr = VulkanRenderer::GetInstance();\n\tif (m_allocation)\n\t{\n\t\tvkr->GetMemoryManager()->imageMemoryFree(m_allocation);\n\t\tm_allocation = nullptr;\n\t}\n\tif (m_image)\n\t\tvkDestroyImage(vkr->GetLogicalDevice(), m_image, nullptr);\n\tperformanceMonitor.vk.numImages.decrement();\n}\n\nVKRObjectTextureView::VKRObjectTextureView(VKRObjectTexture* tex, VkImageView view)\n{\n\tm_textureImageView = view;\n\tthis->addRef(tex);\n\tperformanceMonitor.vk.numImageViews.increment();\n}\n\nVKRObjectTextureView::~VKRObjectTextureView()\n{\n\tauto logicalDevice = VulkanRenderer::GetInstance()->GetLogicalDevice();\n\tif (m_textureDefaultSampler[0] != VK_NULL_HANDLE)\n\t\tvkDestroySampler(logicalDevice, m_textureDefaultSampler[0], nullptr);\n\tif (m_textureDefaultSampler[1] != VK_NULL_HANDLE)\n\t\tvkDestroySampler(logicalDevice, m_textureDefaultSampler[1], nullptr);\n\tvkDestroyImageView(logicalDevice, m_textureImageView, nullptr);\n\tperformanceMonitor.vk.numImageViews.decrement();\n}\n\nstatic uint64 CalcHashSamplerCreateInfo(const VkSamplerCreateInfo& info)\n{\n\tuint64 h = 0xcbf29ce484222325ULL;\n\tauto fnvHashCombine = [](uint64_t &h, auto val) {\n\t\tusing T = decltype(val);\n\t\tstatic_assert(sizeof(T) <= 8);\n\t\tuint64_t val64 = 0;\n\t\tstd::memcpy(&val64, &val, sizeof(val));\n\t\th ^= val64;\n\t\th *= 0x100000001b3ULL;\n\t};\n\tcemu_assert_debug(info.sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);\n\tfnvHashCombine(h, info.flags);\n\tfnvHashCombine(h, info.magFilter);\n\tfnvHashCombine(h, info.minFilter);\n\tfnvHashCombine(h, info.mipmapMode);\n\tfnvHashCombine(h, info.addressModeU);\n\tfnvHashCombine(h, info.addressModeV);\n\tfnvHashCombine(h, info.addressModeW);\n\tfnvHashCombine(h, info.mipLodBias);\n\tfnvHashCombine(h, info.anisotropyEnable);\n\tif(info.anisotropyEnable == VK_TRUE)\n\t\tfnvHashCombine(h, info.maxAnisotropy);\n\tfnvHashCombine(h, info.compareEnable);\n\tif(info.compareEnable == VK_TRUE)\n\t\tfnvHashCombine(h, info.compareOp);\n\tfnvHashCombine(h, info.minLod);\n\tfnvHashCombine(h, info.maxLod);\n\tfnvHashCombine(h, info.borderColor);\n\tfnvHashCombine(h, info.unnormalizedCoordinates);\n\t// handle custom border color\n\tVkBaseOutStructure* ext = (VkBaseOutStructure*)info.pNext;\n\twhile(ext)\n\t{\n\t\tif(ext->sType == VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT)\n\t\t{\n\t\t\tauto* extInfo = (VkSamplerCustomBorderColorCreateInfoEXT*)ext;\n\t\t\tfnvHashCombine(h, extInfo->customBorderColor.uint32[0]);\n\t\t\tfnvHashCombine(h, extInfo->customBorderColor.uint32[1]);\n\t\t\tfnvHashCombine(h, extInfo->customBorderColor.uint32[2]);\n\t\t\tfnvHashCombine(h, extInfo->customBorderColor.uint32[3]);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\text = ext->pNext;\n\t}\n\treturn h;\n}\n\nstd::unordered_map<uint64, VKRObjectSampler*> VKRObjectSampler::s_samplerCache;\n\nVKRObjectSampler::VKRObjectSampler(VkSamplerCreateInfo* samplerInfo)\n{\n\tauto* vulkanRenderer = VulkanRenderer::GetInstance();\n\tif (vkCreateSampler(vulkanRenderer->GetLogicalDevice(), samplerInfo, nullptr, &m_sampler) != VK_SUCCESS)\n\t\tvulkanRenderer->UnrecoverableError(\"Failed to create texture sampler\");\n\tperformanceMonitor.vk.numSamplers.increment();\n\tm_hash = CalcHashSamplerCreateInfo(*samplerInfo);\n}\n\nVKRObjectSampler::~VKRObjectSampler()\n{\n\tvkDestroySampler(VulkanRenderer::GetInstance()->GetLogicalDevice(), m_sampler, nullptr);\n\tperformanceMonitor.vk.numSamplers.decrement();\n\t// remove from cache\n\tauto it = s_samplerCache.find(m_hash);\n\tif(it != s_samplerCache.end())\n\t\ts_samplerCache.erase(it);\n}\n\nvoid VKRObjectSampler::RefCountReachedZero()\n{\n\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(this);\n}\n\nVKRObjectSampler* VKRObjectSampler::GetOrCreateSampler(VkSamplerCreateInfo* samplerInfo)\n{\n\tauto* vulkanRenderer = VulkanRenderer::GetInstance();\n\tuint64 hash = CalcHashSamplerCreateInfo(*samplerInfo);\n\tauto it = s_samplerCache.find(hash);\n\tif (it != s_samplerCache.end())\n\t{\n\t\tauto* sampler = it->second;\n\t\treturn sampler;\n\t}\n\tauto* sampler = new VKRObjectSampler(samplerInfo);\n\ts_samplerCache[hash] = sampler;\n\treturn sampler;\n}\n\nvoid VKRObjectSampler::DestroyCache()\n{\n\t// assuming all other objects which depend on vkSampler are destroyed, this cache should also have been emptied already\n\t// but just to be sure lets still clear the cache\n\tcemu_assert_debug(s_samplerCache.empty());\n\tfor(auto& sampler : s_samplerCache)\n\t{\n\t\tcemu_assert_debug(sampler.second->m_refCount == 0);\n\t\tdelete sampler.second;\n\t}\n\ts_samplerCache.clear();\n}\n\nVKRObjectRenderPass::VKRObjectRenderPass(AttachmentInfo_t& attachmentInfo, sint32 colorAttachmentCount)\n{\n\t// generate helper hash for pipeline state\n\tuint64 stateHash = 0;\n\tfor (int i = 0; i < Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS; ++i)\n\t{\n\t\tif (attachmentInfo.colorAttachment[i].isPresent || attachmentInfo.colorAttachment[i].viewObj)\n\t\t{\n\t\t\tstateHash += attachmentInfo.colorAttachment[i].format + i * 31;\n\t\t\tstateHash = std::rotl<uint64>(stateHash, 7);\n\t\t}\n\t}\n\tif (attachmentInfo.depthAttachment.isPresent || attachmentInfo.depthAttachment.viewObj)\n\t{\n\t\tstateHash += attachmentInfo.depthAttachment.format;\n\t\tstateHash = std::rotl<uint64>(stateHash, 7);\n\t}\n\tm_hashForPipeline = stateHash;\n\n\t// setup Vulkan renderpass\n\tstd::vector<VkAttachmentDescription> attachments_descriptions;\n\tstd::array<VkAttachmentReference, Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS> color_attachments_references{};\n\tcemu_assert(colorAttachmentCount <= color_attachments_references.size());\n\tsint32 numColorAttachments = 0;\n\tfor (int i = 0; i < 8; ++i)\n\t{\n\t\tif (attachmentInfo.colorAttachment[i].viewObj == nullptr && attachmentInfo.colorAttachment[i].isPresent == false)\n\t\t{\n\t\t\tcolor_attachments_references[i].attachment = VK_ATTACHMENT_UNUSED;\n\t\t\tm_colorAttachmentFormat[i] = VK_FORMAT_UNDEFINED;\n\t\t\tcontinue;\n\t\t}\n\t\tm_colorAttachmentFormat[i] = attachmentInfo.colorAttachment[i].format;\n\n\t\tcolor_attachments_references[i].attachment = (uint32)attachments_descriptions.size();\n\t\tcolor_attachments_references[i].layout = VK_IMAGE_LAYOUT_GENERAL;\n\n\t\tVkAttachmentDescription entry{};\n\t\tentry.format = attachmentInfo.colorAttachment[i].format;\n\t\tentry.samples = VK_SAMPLE_COUNT_1_BIT;\n\t\tentry.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;\n\t\tentry.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n\t\tentry.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n\t\tentry.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n\t\tentry.initialLayout = VK_IMAGE_LAYOUT_GENERAL;\n\t\tentry.finalLayout = VK_IMAGE_LAYOUT_GENERAL;\n\t\tattachments_descriptions.emplace_back(entry);\n\n\t\tnumColorAttachments = i + 1;\n\t}\n\n\tVkAttachmentReference depth_stencil_attachments_references{};\n\tbool hasDepthStencilAttachment = false;\n\tif (attachmentInfo.depthAttachment.viewObj == nullptr && attachmentInfo.depthAttachment.isPresent == false)\n\t{\n\t\tdepth_stencil_attachments_references.attachment = VK_ATTACHMENT_UNUSED;\n\t\tm_depthAttachmentFormat = VK_FORMAT_UNDEFINED;\n\t}\n\telse\n\t{\n\t\thasDepthStencilAttachment = true;\n\t\tdepth_stencil_attachments_references.attachment = (uint32)attachments_descriptions.size();\n\t\tdepth_stencil_attachments_references.layout = VK_IMAGE_LAYOUT_GENERAL;\n\t\tm_depthAttachmentFormat = attachmentInfo.depthAttachment.format;\n\n\t\tVkAttachmentDescription entry{};\n\t\tentry.format = attachmentInfo.depthAttachment.format;\n\t\tentry.samples = VK_SAMPLE_COUNT_1_BIT;\n\t\tentry.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;\n\t\tentry.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n\t\tif (attachmentInfo.depthAttachment.hasStencil)\n\t\t{\n\t\t\tentry.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;\n\t\t\tentry.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tentry.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n\t\t\tentry.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n\t\t}\n\t\tentry.initialLayout = VK_IMAGE_LAYOUT_GENERAL;\n\t\tentry.finalLayout = VK_IMAGE_LAYOUT_GENERAL;\n\t\tattachments_descriptions.emplace_back(entry);\n\t}\n\n\t// todo - use numColorAttachments instead of .size() or colorAttachmentCount (needs adjusting in many places)\n\n\tVkSubpassDescription subpass{};\n\tsubpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n\tsubpass.colorAttachmentCount = colorAttachmentCount;\n\tsubpass.pColorAttachments = color_attachments_references.data();\n\tsubpass.inputAttachmentCount = 0;\n\tsubpass.pInputAttachments = nullptr;\n\tsubpass.pDepthStencilAttachment = &depth_stencil_attachments_references;\n\n\tVkRenderPassCreateInfo renderPassInfo{};\n\trenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n\trenderPassInfo.attachmentCount = (uint32)attachments_descriptions.size();\n\trenderPassInfo.pAttachments = attachments_descriptions.data();\n\trenderPassInfo.subpassCount = 1;\n\trenderPassInfo.pSubpasses = &subpass;\n\n\trenderPassInfo.pDependencies = nullptr;\n\trenderPassInfo.dependencyCount = 0;\n\t// before Cemu 1.25.5 we used zero here, which means implicit synchronization. For 1.25.5 it was changed to 2 (using the subpass dependencies above)\n\t// Reverted this again to zero for Cemu 1.25.5b as the performance cost is just too high. Manual synchronization is preferred\n\n\tif (vkCreateRenderPass(VulkanRenderer::GetInstance()->GetLogicalDevice(), &renderPassInfo, nullptr, &m_renderPass) != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Vulkan-Error: Failed to create render pass\");\n\t\tthrow std::runtime_error(\"failed to create render pass!\");\n\t}\n\n\t// track references\n\tfor (int i = 0; i < 8; ++i)\n\t{\n\t\tif (attachmentInfo.colorAttachment[i].viewObj)\n\t\t\taddRef(attachmentInfo.colorAttachment[i].viewObj);\n\t}\n\tif (attachmentInfo.depthAttachment.viewObj)\n\t\taddRef(attachmentInfo.depthAttachment.viewObj);\n\tperformanceMonitor.vk.numRenderPass.increment();\n}\n\nVKRObjectRenderPass::~VKRObjectRenderPass()\n{\n\tif (m_renderPass != VK_NULL_HANDLE)\n\t\tvkDestroyRenderPass(VulkanRenderer::GetInstance()->GetLogicalDevice(), m_renderPass, nullptr);\n\tperformanceMonitor.vk.numRenderPass.decrement();\n}\n\nVKRObjectFramebuffer::VKRObjectFramebuffer(VKRObjectRenderPass* renderPass, std::span<VKRObjectTextureView*> attachments, Vector2i size)\n{\n\t// convert VKRObjectTextureView* array to vkImageView array\n\tstd::array<VkImageView, 16> attachmentViews;\n\tcemu_assert(attachments.size() < attachmentViews.size());\n\tfor (size_t i = 0; i < attachments.size(); i++)\n\t\tattachmentViews[i] = attachments[i]->m_textureImageView;\n\n\tVkFramebufferCreateInfo createInfo{};\n\tcreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;\n\tcreateInfo.pAttachments = attachmentViews.data();\n\tcreateInfo.attachmentCount = attachments.size();\n\tcreateInfo.renderPass = renderPass->m_renderPass;\n\tcreateInfo.layers = 1;\n\tcreateInfo.width = size.x;\n\tcreateInfo.height = size.y;\n\tif (vkCreateFramebuffer(VulkanRenderer::GetInstance()->GetLogicalDevice(), &createInfo, nullptr, &m_frameBuffer) != VK_SUCCESS)\n\t\tthrow std::runtime_error(\"failed to create framebuffer!\");\n\n\t// track refs\n\tthis->addRef(renderPass);\n\tfor (auto& itr : attachments)\n\t\tthis->addRef(itr);\n\n\tperformanceMonitor.vk.numFramebuffer.increment();\n}\n\nVKRObjectFramebuffer::~VKRObjectFramebuffer()\n{\n\tif (m_frameBuffer != VK_NULL_HANDLE)\n\t\tvkDestroyFramebuffer(VulkanRenderer::GetInstance()->GetLogicalDevice(), m_frameBuffer, nullptr);\n\tperformanceMonitor.vk.numFramebuffer.decrement();\n}\n\nVKRObjectPipeline::VKRObjectPipeline()\n{\n}\n\nvoid VKRObjectPipeline::SetPipeline(VkPipeline newPipeline)\n{\n\tif (m_pipeline == newPipeline)\n\t\treturn;\n\tcemu_assert_debug(m_pipeline == VK_NULL_HANDLE); // replacing an already assigned pipeline is not intended\n\tif(m_pipeline == VK_NULL_HANDLE && newPipeline != VK_NULL_HANDLE)\n\t\tperformanceMonitor.vk.numGraphicPipelines.increment();\n\telse if(m_pipeline != VK_NULL_HANDLE && newPipeline == VK_NULL_HANDLE)\n\t\tperformanceMonitor.vk.numGraphicPipelines.decrement();\n\tm_pipeline = newPipeline;\n}\n\nVKRObjectPipeline::~VKRObjectPipeline()\n{\n\tauto vkr = VulkanRenderer::GetInstance();\n\tif (m_pipeline != VK_NULL_HANDLE)\n\t{\n\t\tvkDestroyPipeline(vkr->GetLogicalDevice(), m_pipeline, nullptr);\n\t\tperformanceMonitor.vk.numGraphicPipelines.decrement();\n\t}\n\tif (m_vertexDSL != VK_NULL_HANDLE)\n\t\tvkDestroyDescriptorSetLayout(vkr->GetLogicalDevice(), m_vertexDSL, nullptr);\n\tif (m_pixelDSL != VK_NULL_HANDLE)\n\t\tvkDestroyDescriptorSetLayout(vkr->GetLogicalDevice(), m_pixelDSL, nullptr);\n\tif (m_geometryDSL != VK_NULL_HANDLE)\n\t\tvkDestroyDescriptorSetLayout(vkr->GetLogicalDevice(), m_geometryDSL, nullptr);\n\tif (m_pipelineLayout != VK_NULL_HANDLE)\n\t\tvkDestroyPipelineLayout(vkr->GetLogicalDevice(), m_pipelineLayout, nullptr);\n}\n\nVKRObjectDescriptorSet::VKRObjectDescriptorSet()\n{\n\tperformanceMonitor.vk.numDescriptorSets.increment();\n}\n\nVKRObjectDescriptorSet::~VKRObjectDescriptorSet()\n{\n\tauto vkr = VulkanRenderer::GetInstance();\n\tvkFreeDescriptorSets(vkr->GetLogicalDevice(), vkr->GetDescriptorPool(), 1, &descriptorSet);\n\tperformanceMonitor.vk.numDescriptorSets.decrement();\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h",
    "content": "#pragma once\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VKRMemoryManager.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h\"\n#include \"util/math/vector2.h\"\n#include \"util/helpers/Semaphore.h\"\n#include \"util/containers/flat_hash_map.hpp\"\n#include \"util/containers/robin_hood.h\"\n\nstruct VkSupportedFormatInfo_t\n{\n\tbool fmt_d24_unorm_s8_uint{};\n\tbool fmt_r4g4_unorm_pack{};\n\tbool fmt_r5g6b5_unorm_pack{};\n\tbool fmt_r4g4b4a4_unorm_pack{};\n\tbool fmt_a1r5g5b5_unorm_pack{};\n};\n\nstruct VkDescriptorSetInfo\n{\n\tVKRObjectDescriptorSet* m_vkObjDescriptorSet{};\n\n\t~VkDescriptorSetInfo();\n\n\tstd::vector<LatteTextureViewVk*> list_referencedViews;\n\tstd::vector<LatteTextureVk*> list_fboCandidates; // prefiltered list of textures which may need a barrier\n\tLatteConst::ShaderType shaderType{};\n\tuint64 stateHash{};\n\tclass PipelineInfo* pipeline_info{};\n\n\t// tracking for allocated descriptors\n\tuint8 statsNumSamplerTextures{ 0 };\n\tuint8 statsNumDynUniformBuffers{ 0 };\n\tuint8 statsNumStorageBuffers{ 0 };\n};\n\nclass VkException : public std::runtime_error\n{\npublic:\n\tVkException(VkResult result, const std::string& message)\n\t\t: runtime_error(message), m_result(result)\n\t{}\n\n\tVkResult GetResult() const { return m_result; }\n\nprivate:\n\tVkResult m_result;\n};\n\nnamespace VulkanRendererConst\n{\n\tstatic const inline int SHADER_STAGE_INDEX_VERTEX = 0;\n\tstatic const inline int SHADER_STAGE_INDEX_FRAGMENT = 1;\n\tstatic const inline int SHADER_STAGE_INDEX_GEOMETRY = 2;\n\tstatic const inline int SHADER_STAGE_INDEX_COUNT = 3;\n};\n\nclass PipelineInfo\n{\npublic:\n\tPipelineInfo(uint64 minimalStateHash, uint64 pipelineHash, struct LatteFetchShader* fetchShader, LatteDecompilerShader* vertexShader, LatteDecompilerShader* pixelShader, LatteDecompilerShader* geometryShader);\n\tPipelineInfo(const PipelineInfo& info) = delete;\n\t~PipelineInfo();\n\n\tbool operator==(const PipelineInfo& pipeline_info) const\n\t{\n\t\treturn true;\n\t}\n\n\n\ttemplate<typename T>\n\tstruct direct_hash\n\t{\n\t\tsize_t operator()(const uint64& k) const noexcept\n\t\t{\n\t\t\treturn k;\n\t\t}\n\t};\n\n\t// std::unordered_map<uint64, VkDescriptorSetInfo*> 3.16% (total CPU time)\n\t// robin_hood::unordered_flat_map<uint64, VkDescriptorSetInfo*> vertex_ds_cache, pixel_ds_cache, geometry_ds_cache; ~1.80%\n\t// ska::bytell_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>> vertex_ds_cache, pixel_ds_cache, geometry_ds_cache; -> 1.91%\n\tska::flat_hash_map<uint64, VkDescriptorSetInfo*, direct_hash<uint64>> vertex_ds_cache, pixel_ds_cache, geometry_ds_cache; // 1.71%\n\n\tVKRObjectPipeline* m_vkrObjPipeline;\n\n\tLatteDecompilerShader* vertexShader = nullptr;\n\tLatteDecompilerShader* geometryShader = nullptr;\n\tLatteDecompilerShader* pixelShader = nullptr;\n\tLatteFetchShader* fetchShader = nullptr;\n\tLatte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE primitiveMode{};\n\n\tRendererShaderVk* vertexShaderVk = nullptr;\n\tRendererShaderVk* geometryShaderVk = nullptr;\n\tRendererShaderVk* pixelShaderVk = nullptr;\n\n\tuint64 minimalStateHash;\n\tuint64 stateHash;\n\n\tbool usesBlendConstants{ false };\n\tbool usesDepthBias{ false };\n\n\tstruct\n\t{\n\t\tbool hasUniformVar[VulkanRendererConst::SHADER_STAGE_INDEX_COUNT];\n\t\tbool hasUniformBuffers[VulkanRendererConst::SHADER_STAGE_INDEX_COUNT];\n\t\tstd::vector<uint8> list_uniformBuffers[VulkanRendererConst::SHADER_STAGE_INDEX_COUNT];\n\t}dynamicOffsetInfo{};\n\n\t// primitive rects emulation\n\tRendererShaderVk* rectEmulationGS = nullptr;\n\n\t// hack - accurate barrier needed for this pipeline\n\tbool neverSkipAccurateBarrier{false};\n};\n\nnamespace WindowSystem\n{\n\tstruct WindowHandleInfo;\n};\n\nclass VulkanRenderer : public Renderer\n{\n\tfriend class LatteQueryObjectVk;\n\tfriend class LatteTextureReadbackInfoVk;\n\tfriend class PipelineCompiler;\n\n\tusing VSync = SwapchainInfoVk::VSync;\n\n\tstatic const inline int UNIFORMVAR_RINGBUFFER_SIZE = 1024 * 1024 * 16; // 16MB\n\n\tstatic const inline int TEXTURE_READBACK_SIZE = 32 * 1024 * 1024; // 32 MB\n\n\tstatic const inline int OCCLUSION_QUERY_POOL_SIZE = 1024;\n\npublic:\n\n\t// memory management\n\tstd::unique_ptr<VKRMemoryManager> memoryManager;\n\tVKRMemoryManager* GetMemoryManager() const { return memoryManager.get(); };\n\n\tVkSupportedFormatInfo_t m_supportedFormatInfo;\n\n\ttypedef struct\n\t{\n\t\t// Vulkan image info\n\t\tVkFormat vkImageFormat;\n\t\tVkImageAspectFlags vkImageAspect;\n\t\tbool isCompressed;\n\n\t\t// texture decoder info\n\t\tTextureDecoder* decoder;\n\n\t\tsint32 texelCountX;\n\t\tsint32 texelCountY;\n\t}FormatInfoVK;\n\n\tstruct DeviceInfo\n\t{\n\t\tDeviceInfo(const std::string name, uint8* uuid)\n\t\t\t: name(name)\n\t\t{\n\t\t\tstd::copy(uuid, uuid + VK_UUID_SIZE, this->uuid.data());\n\t\t}\n\n\t\tstd::string name;\n\t\tstd::array<uint8, VK_UUID_SIZE> uuid;\n\t};\n\n\tstatic std::vector<DeviceInfo> GetDevices();\n\tVulkanRenderer();\n\tvirtual ~VulkanRenderer();\n\n\tRendererAPI GetType() override { return RendererAPI::Vulkan; }\n\n\tstatic VulkanRenderer* GetInstance();\n\n\tvoid UnrecoverableError(const char* errMsg) const;\n\n\tvoid GetDeviceFeatures();\n\tvoid DetermineVendor();\n\tvoid InitializeSurface(const Vector2i& size, bool mainWindow);\n\n\tconst std::unique_ptr<SwapchainInfoVk>& GetChainInfoPtr(bool mainWindow) const;\n\tSwapchainInfoVk& GetChainInfo(bool mainWindow) const;\n\n\tvoid StopUsingPadAndWait();\n\tbool IsPadWindowActive() override;\n\n\tvoid HandleScreenshotRequest(LatteTextureView* texView, bool padView) override;\n\n\tvoid QueryMemoryInfo();\n\tvoid QueryAvailableFormats();\n\n#if BOOST_OS_WINDOWS\n\tstatic VkSurfaceKHR CreateWinSurface(VkInstance instance, HWND hwindow);\n#endif\n#if BOOST_OS_LINUX || BOOST_OS_BSD\n\tstatic VkSurfaceKHR CreateXlibSurface(VkInstance instance, Display* dpy, Window window);\n    static VkSurfaceKHR CreateXcbSurface(VkInstance instance, xcb_connection_t* connection, xcb_window_t window);\n\t#ifdef HAS_WAYLAND\n\tstatic VkSurfaceKHR CreateWaylandSurface(VkInstance instance, wl_display* display, wl_surface* surface);\n\t#endif\n#endif\n\n\tstatic VkSurfaceKHR CreateFramebufferSurface(VkInstance instance, struct WindowSystem::WindowHandleInfo& windowInfo);\n\n\tvoid AppendOverlayDebugInfo() override;\n\n\tvoid ImguiInit();\n\tVkInstance GetVkInstance() const { return m_instance; }\n\tVkDevice GetLogicalDevice() const { return m_logicalDevice; }\n\tVkPhysicalDevice GetPhysicalDevice() const { return m_physicalDevice; }\n\n\tVkDescriptorPool GetDescriptorPool() const { return m_descriptorPool; }\n\n\tvoid WaitDeviceIdle() const { vkDeviceWaitIdle(m_logicalDevice); }\n\n\tvoid Initialize() override;\n\tvoid Shutdown() override;\n\n\tvoid SwapBuffers(bool swapTV = true, bool swapDRC = true) override;\n\n\tvoid Flush(bool waitIdle = false) override;\n\tvoid NotifyLatteCommandProcessorIdle() override;\n\n\tuint64 GenUniqueId(); // return unique id (uses incrementing counter)\n\n\tvoid DrawEmptyFrame(bool mainWindow) override;\n\n\tvoid InitFirstCommandBuffer();\n\tvoid ProcessFinishedCommandBuffers();\n\tvoid WaitForNextFinishedCommandBuffer();\n\tvoid SubmitCommandBuffer(VkSemaphore signalSemaphore = VK_NULL_HANDLE, VkSemaphore waitSemaphore = VK_NULL_HANDLE);\n\tvoid RequestSubmitSoon();\n\tvoid RequestSubmitOnIdle();\n\n\t// command buffer synchronization\n\tuint64 GetCurrentCommandBufferId() const;\n\tbool HasCommandBufferFinished(uint64 commandBufferId) const;\n\tvoid WaitCommandBufferFinished(uint64 commandBufferId);\n\n\t// resource destruction queue\n\tvoid ReleaseDestructibleObject(VKRDestructibleObject* destructibleObject);\n\tvoid ProcessDestructionQueue();\n\n\tFSpinlock m_spinlockDestructionQueue;\n\tstd::vector<VKRDestructibleObject*> m_destructionQueue;\n\n\tvoid PipelineCacheSaveThread(size_t cache_size);\n\n\tvoid ClearColorbuffer(bool padView) override;\n\tvoid ClearColorImageRaw(VkImage image, uint32 sliceIndex, uint32 mipIndex, const VkClearColorValue& color, VkImageLayout inputLayout, VkImageLayout outputLayout);\n\tvoid ClearColorImage(LatteTextureVk* vkTexture, uint32 sliceIndex, uint32 mipIndex, const VkClearColorValue& color, VkImageLayout outputLayout);\n\n\tvoid DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, sint32 imageX, sint32 imageY, sint32 imageWidth, sint32 imageHeight, bool padView, bool clearBackground) override;\n\tvoid CreateDescriptorPool();\n\tVkDescriptorSet backbufferBlit_createDescriptorSet(VkDescriptorSetLayout descriptor_set_layout, LatteTextureViewVk* texViewVk, bool useLinearTexFilter);\n\n\trobin_hood::unordered_flat_map<uint64, robin_hood::unordered_flat_map<uint64, PipelineInfo*> > m_pipeline_info_cache; // using robin_hood::unordered_flat_map is twice as fast (1-2% overall CPU time reduction)\n\tvoid draw_debugPipelineHashState();\n\tPipelineInfo* draw_getCachedPipeline();\n\n\t// pipeline state hash\n\tstatic uint64 draw_calculateMinimalGraphicsPipelineHash(const LatteFetchShader* fetchShader, const LatteContextRegister& lcr);\n\tstatic uint64 draw_calculateGraphicsPipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const VKRObjectRenderPass* renderPassObj, const LatteContextRegister& lcr);\n\n\t// rendertarget\n\tvoid renderTarget_setViewport(float x, float y, float width, float height, float nearZ, float farZ, bool halfZ = false) override;\n\tvoid renderTarget_setScissor(sint32 scissorX, sint32 scissorY, sint32 scissorWidth, sint32 scissorHeight) override;\n\n\tLatteCachedFBO* rendertarget_createCachedFBO(uint64 key) override;\n\tvoid rendertarget_deleteCachedFBO(LatteCachedFBO* cfbo) override;\n\tvoid rendertarget_bindFramebufferObject(LatteCachedFBO* cfbo) override;\n\n\t// texture functions\n\tvoid* texture_acquireTextureUploadBuffer(uint32 size) override;\n\tvoid texture_releaseTextureUploadBuffer(uint8* mem) override;\n\n\tTextureDecoder* texture_chooseDecodedFormat(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, uint32 width, uint32 height) override;\n\n\tvoid texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex) override;\n\tvoid texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) override;\n\tvoid texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) override;\n\n\tvoid texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) override;\n\n\tLatteTexture* texture_createTextureEx(Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle, Latte::E_HWTILEMODE tileMode, bool isDepth) override;\n\n\tvoid texture_setLatteTexture(LatteTextureView* textureView, uint32 textureUnit) override;\n\n\tvoid texture_copyImageSubData(LatteTexture* src, sint32 srcMip, sint32 effectiveSrcX, sint32 effectiveSrcY, sint32 srcSlice, LatteTexture* dst, sint32 dstMip, sint32 effectiveDstX, sint32 effectiveDstY, sint32 dstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight, sint32 srcDepth) override;\n\tLatteTextureReadbackInfo* texture_createReadback(LatteTextureView* textureView) override;\n\n\t// surface copy\n\tvoid surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height) override;\n\tvoid surfaceCopy_notifyTextureRelease(LatteTextureVk* hostTexture);\n\n\tprivate:\n\tvoid surfaceCopy_viaDrawcall(LatteTextureVk* srcTextureVk, sint32 texSrcMip, sint32 texSrcSlice, LatteTextureVk* dstTextureVk, sint32 texDstMip, sint32 texDstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight);\n\n\tvoid surfaceCopy_cleanup();\n\nprivate:\n\tuint64 copySurface_getPipelineStateHash(struct VkCopySurfaceState_t& state);\n\tstruct CopySurfacePipelineInfo* copySurface_getCachedPipeline(struct VkCopySurfaceState_t& state);\n\tstruct CopySurfacePipelineInfo* copySurface_getOrCreateGraphicsPipeline(struct VkCopySurfaceState_t& state);\n\tVKRObjectTextureView* surfaceCopy_createImageView(LatteTextureVk* textureVk, uint32 sliceIndex, uint32 mipIndex);\n\tVKRObjectFramebuffer* surfaceCopy_getOrCreateFramebuffer(struct VkCopySurfaceState_t& state, struct CopySurfacePipelineInfo* pipelineInfo);\n\tVKRObjectDescriptorSet* surfaceCopy_getOrCreateDescriptorSet(struct VkCopySurfaceState_t& state, struct CopySurfacePipelineInfo* pipelineInfo);\n\n\tVKRObjectRenderPass* copySurface_createRenderpass(struct VkCopySurfaceState_t& state);\n\n\tstd::unordered_map<uint64, struct CopySurfacePipelineInfo*> m_copySurfacePipelineCache;\n\npublic:\n\t// renderer interface\n\tvoid bufferCache_init(const sint32 bufferSize) override;\n\tvoid bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) override;\n\tvoid bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) override;\n\n\tvoid buffer_bindVertexBuffer(uint32 bufferIndex, uint32 buffer, uint32 size) override;\n\tvoid buffer_bindVertexStrideWorkaroundBuffer(VkBuffer fixedBuffer, uint32 offset, uint32 bufferIndex, uint32 size);\n\tstd::pair<VkBuffer, uint32> buffer_genStrideWorkaroundVertexBuffer(MPTR buffer, uint32 size, uint32 oldStride);\n\tvoid buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override;\n\n\tRendererShader* shader_create(RendererShader::ShaderType type, uint64 baseHash, uint64 auxHash, const std::string& source, bool isGameShader, bool isGfxPackShader) override;\n\n\tIndexAllocation indexData_reserveIndexMemory(uint32 size) override;\n\tvoid indexData_releaseIndexMemory(IndexAllocation& allocation) override;\n\tvoid indexData_uploadIndexMemory(IndexAllocation& allocation) override;\n\n\t// externally callable\n\tvoid GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isDepth, Latte::E_DIM dim, sint32 width, sint32 height, FormatInfoVK* formatInfoOut);\n\tvoid unregisterGraphicsPipeline(PipelineInfo* pipelineInfo);\n\nprivate:\n\tstruct VkRendererState\n\t{\n\t\tVkRendererState() = default;\n\t\tVkRendererState(const VkRendererState&) = delete;\n\t\tVkRendererState(VkRendererState&&) noexcept = delete;\n\n\t\t// textures\n\t\tLatteTextureViewVk* boundTexture[128]{};\n\n\t\t// rendertarget\n\t\tCachedFBOVk* activeFBO{}; // the FBO active for the emulated GPU\n\n\t\t// command buffer\n\t\tVkCommandBuffer currentCommandBuffer{};\n\n\t\t// pipeline\n\t\tVkPipeline currentPipeline{ VK_NULL_HANDLE };\n\n\t\t// renderpass\n\t\tCachedFBOVk* activeRenderpassFBO{}; // the FBO of the currently active Vulkan renderpass\n\n\t\t// drawcall state\n\t\tPipelineInfo* activePipelineInfo{ nullptr };\n\t\tVkDescriptorSetInfo* activeVertexDS{ nullptr };\n\t\tVkDescriptorSetInfo* activePixelDS{ nullptr };\n\t\tVkDescriptorSetInfo* activeGeometryDS{ nullptr };\n\t\tbool descriptorSetsChanged{ false };\n\t\tbool hasRenderSelfDependency{ false }; // set if current drawcall samples textures which are also output as a rendertarget\n\n\t\t// viewport and scissor box\n\t\tVkViewport currentViewport{};\n\t\tVkRect2D currentScissorRect{};\n\n\t\t// vertex bindings\n\t\tstruct\n\t\t{\n\t\t\tuint32 offset;\n\t\t}currentVertexBinding[LATTE_MAX_VERTEX_BUFFERS]{};\n\n\t\t// transform feedback\n\t\tbool hasActiveXfb{};\n\n\t\t// index buffer\n\t\tRenderer::INDEX_TYPE activeIndexType{};\n\t\tuint32 activeIndexBufferIndex{};\n\t\tuint32 activeIndexBufferOffset{};\n\n\t\t// polygon offset\n\t\tuint32 prevPolygonFrontOffsetU32{ 0xFFFFFFFF };\n\t\tuint32 prevPolygonFrontScaleU32{ 0xFFFFFFFF };\n\t\tuint32 prevPolygonFrontClampU32{ 0xFFFFFFFF };\n\n\t\tvoid resetCommandBufferState()\n\t\t{\n\t\t\tprevPolygonFrontOffsetU32 = 0xFFFFFFFF;\n\t\t\tprevPolygonFrontScaleU32 = 0xFFFFFFFF;\n\t\t\tprevPolygonFrontClampU32 = 0xFFFFFFFF;\n\t\t\tcurrentPipeline = VK_NULL_HANDLE;\n\t\t\tfor (auto& itr : currentVertexBinding)\n\t\t\t{\n\t\t\t\titr.offset = 0xFFFFFFFF;\n\t\t\t}\n\t\t\tactiveIndexType = Renderer::INDEX_TYPE::NONE;\n\t\t\tactiveIndexBufferIndex = std::numeric_limits<uint32>::max();\n\t\t\tactiveIndexBufferOffset = std::numeric_limits<uint32>::max();\n\t\t}\n\n\t\t// invalidation / flushing\n\t\tuint64 currentFlushIndex{0};\n\t\tbool requestFlush{ false }; // flush after every draw operation. The renderpass dependencies dont handle dependencies across multiple drawcalls inside a single renderpass\n\n\t\t// draw sequence\n\t\tbool drawSequenceSkip; // if true, skip draw_execute()\n\t}m_state;\n\n\tstd::unique_ptr<SwapchainInfoVk> m_mainSwapchainInfo{}, m_padSwapchainInfo{};\n\tstd::atomic_flag m_destroyPadSwapchainNextAcquire{};\n\tbool IsSwapchainInfoValid(bool mainWindow) const;\n\n\tVkRenderPass m_imguiRenderPass = VK_NULL_HANDLE;\n\n\tVkDescriptorPool m_descriptorPool;\n\n  public:\n\tstruct QueueFamilyIndices\n\t{\n\t\tint32_t graphicsFamily = -1;\n\t\tint32_t presentFamily = -1;\n\n\t\tbool IsComplete() const\t{ return graphicsFamily >= 0 && presentFamily >= 0;\t}\n\t};\n\tstatic QueueFamilyIndices FindQueueFamilies(VkSurfaceKHR surface, VkPhysicalDevice device);\n\n  private:\n\n\tstruct FeatureControl\n\t{\n\t\tstruct\n\t\t{\n\t\t\t// if using new optional extensions add to CheckDeviceExtensionSupport and CreateDeviceCreateInfo\n\t\t\tbool tooling_info = false; // VK_EXT_tooling_info\n\t\t\tbool transform_feedback = false;\n\t\t\tbool depth_range_unrestricted = false;\n\t\t\tbool nv_fill_rectangle = false; // NV_fill_rectangle\n\t\t\tbool pipeline_feedback = false;\n\t\t\tbool pipeline_creation_cache_control = false; // VK_EXT_pipeline_creation_cache_control\n\t\t\tbool custom_border_color = false; // VK_EXT_custom_border_color\n\t\t\tbool custom_border_color_without_format = false; // VK_EXT_custom_border_color (specifically customBorderColorWithoutFormat)\n\t\t\tbool cubic_filter = false; // VK_EXT_FILTER_CUBIC_EXTENSION_NAME\n\t\t\tbool driver_properties = false; // VK_KHR_driver_properties\n\t\t\tbool external_memory_host = false; // VK_EXT_external_memory_host\n\t\t\tbool synchronization2 = false; // VK_KHR_synchronization2\n\t\t\tbool dynamic_rendering = false; // VK_KHR_dynamic_rendering\n\t\t\tbool shader_float_controls = false; // VK_KHR_shader_float_controls\n\t\t\tbool present_wait = false; // VK_KHR_present_wait\n\t\t\tbool depth_clip_enable = false; // VK_EXT_depth_clip_enable\n\t\t\tbool pipeline_robustness = false; // VK_EXT_pipeline_robustness\n\t\t}deviceExtensions;\n\n\t\tstruct\n\t\t{\n\t\t\tbool shaderRoundingModeRTEFloat32{ false };\n\t\t}shaderFloatControls; // from VK_KHR_shader_float_controls\n\n\t\tstruct\n\t\t{\n\t\t\tbool debug_utils = false; // VK_EXT_DEBUG_UTILS\n\t\t}instanceExtensions;\n\n\t\tstruct\n\t\t{\n\t\t\tbool useTFEmulationViaSSBO = true; // emulate transform feedback via shader writes to a storage buffer\n\t\t}mode;\n\n\t\tstruct\n\t\t{\n\t\t\tuint32 minUniformBufferOffsetAlignment = 256;\n\t\t\tuint32 nonCoherentAtomSize = 256;\n\t\t}limits;\n\n\t\tbool usingDebugMarkerTool{ false }; // validation layer or other tool capable of handling debug markers is used\n\t\tbool usingTracingTool{ false }; // frame debugger or other API replaying tool is used\n\t\tbool disableMultithreadedCompilation{ false }; // for old nvidia drivers\n\n\t}m_featureControl{};\n\tstatic bool CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info);\n\tstatic std::vector<const char*> CheckInstanceExtensionSupport(FeatureControl& info);\n\n\tbool UpdateSwapchainProperties(bool mainWindow);\n\tvoid SwapBuffer(bool mainWindow);\n\n\tVkDescriptorSetLayout m_swapchainDescriptorSetLayout;\n\n\tVkQueue m_graphicsQueue, m_presentQueue;\n\n\t// swapchain\n\n\tstd::vector<VkDeviceQueueCreateInfo> CreateQueueCreateInfos(const std::set<int>& uniqueQueueFamilies) const;\n\tVkDeviceCreateInfo CreateDeviceCreateInfo(const std::vector<VkDeviceQueueCreateInfo>& queueCreateInfos, const VkPhysicalDeviceFeatures& deviceFeatures, const void* deviceExtensionStructs, std::vector<const char*>& used_extensions) const;\n\tstatic bool IsDeviceSuitable(VkSurfaceKHR surface, const VkPhysicalDevice& device);\n\n\tvoid CreateCommandPool();\n\tvoid CreateCommandBuffers();\n\n\tvoid swapchain_createDescriptorSetLayout();\n\n\t// shader\n\n\tbool IsAsyncPipelineAllowed(uint32 numIndices);\n\n\tuint64 GetDescriptorSetStateHash(LatteDecompilerShader* shader);\n\n\t// imgui\n\tbool ImguiBegin(bool mainWindow) override;\n\tvoid ImguiEnd() override;\n\tImTextureID GenerateTexture(const std::vector<uint8>& data, const Vector2i& size) override;\n\tvoid DeleteTexture(ImTextureID id) override;\n\tvoid DeleteFontTextures() override;\n\tbool BeginFrame(bool mainWindow) override;\n\n\tbool UseTFViaSSBO() const override { return m_featureControl.mode.useTFEmulationViaSSBO; }\n\n\t// drawcall emulation\n\tPipelineInfo* draw_createGraphicsPipeline(uint32 indexCount);\n\tPipelineInfo* draw_getOrCreateGraphicsPipeline(uint32 indexCount);\n\n\tvoid draw_updateVkBlendConstants();\n\tvoid draw_updateDepthBias(bool forceUpdate);\n\n\tvoid draw_setRenderPass();\n\tvoid draw_endRenderPass();\n\n\tvoid draw_beginSequence() override;\n\tvoid draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) override;\n\tvoid draw_endSequence() override;\n\n\tvoid draw_updateVertexBuffersDirectAccess();\n\tvoid draw_updateUniformBuffersDirectAccess(LatteDecompilerShader* shader, const uint32 uniformBufferRegOffset, LatteConst::ShaderType shaderType);\n\n\tvoid draw_prepareDynamicOffsetsForDescriptorSet(uint32 shaderStageIndex, uint32* dynamicOffsets, sint32& numDynOffsets, const PipelineInfo* pipeline_info);\n\tVkDescriptorSetInfo* draw_getOrCreateDescriptorSet(PipelineInfo* pipeline_info, LatteDecompilerShader* shader);\n\tvoid draw_prepareDescriptorSets(PipelineInfo* pipeline_info, VkDescriptorSetInfo*& vertexDS, VkDescriptorSetInfo*& pixelDS, VkDescriptorSetInfo*& geometryDS);\n\tvoid draw_handleSpecialState5();\n\n\t// draw synchronization helper\n\tvoid sync_inputTexturesChanged();\n\tvoid sync_RenderPassLoadTextures(CachedFBOVk* fboVk);\n\tvoid sync_RenderPassStoreTextures(CachedFBOVk* fboVk);\n\n\t// command buffer\n\tVkCommandBuffer getCurrentCommandBuffer() const { return m_state.currentCommandBuffer; }\n\n\t// uniform\n\tuint32 uniformData_uploadUniformDataBufferGetOffset(std::span<uint8, std::dynamic_extent> data);\n\tvoid uniformData_updateUniformVars(uint32 shaderStageIndex, LatteDecompilerShader* shader);\n\n\t// misc\n\tvoid CreatePipelineCache();\n\tVkPipelineShaderStageCreateInfo CreatePipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule& module, const char* entryName) const;\n\tVkPipeline backbufferBlit_createGraphicsPipeline(VkDescriptorSetLayout descriptorLayout, bool padView, RendererOutputShader* shader);\n\tbool AcquireNextSwapchainImage(bool mainWindow);\n\tvoid RecreateSwapchain(bool mainWindow, bool skipCreate = false);\n\n\t// streamout\n\tvoid streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;\n\tvoid streamout_begin() override;\n\tvoid streamout_applyTransformFeedbackState();\n\tvoid bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) override;\n\tvoid streamout_rendererFinishDrawcall() override;\n\n\t// occlusion queries\n\tLatteQueryObject* occlusionQuery_create() override;\n\tvoid occlusionQuery_destroy(LatteQueryObject* queryObj) override;\n\tvoid occlusionQuery_flush() override;\n\tvoid occlusionQuery_updateState() override;\n\tvoid occlusionQuery_notifyEndCommandBuffer();\n\tvoid occlusionQuery_notifyBeginCommandBuffer();\n\nprivate:\n\tstd::vector<const char*> m_layerNames;\n\tVkInstance m_instance = VK_NULL_HANDLE;\n\tVkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;\n\tVkDevice  m_logicalDevice = VK_NULL_HANDLE;\n\tVkDebugUtilsMessengerEXT m_debugCallback = nullptr;\n\tvolatile bool m_destructionRequested = false;\n\n\tQueueFamilyIndices m_indices{};\n\n\tSemaphore m_pipeline_cache_semaphore;\n\tstd::shared_mutex m_pipeline_cache_save_mutex;\n\tstd::thread m_pipeline_cache_save_thread;\n\tVkPipelineCache m_pipeline_cache{ nullptr };\n\tstd::unordered_map<uint64, VkPipeline> m_backbufferBlitPipelineCache;\n\tstd::unordered_map<uint64, VkDescriptorSet> m_backbufferBlitDescriptorSetCache;\n\tVkPipelineLayout m_pipelineLayout{nullptr};\n\tVkCommandPool m_commandPool{ nullptr };\n\n\t// buffer to cache uniform vars\n\tVkBuffer m_uniformVarBuffer = VK_NULL_HANDLE;\n\tVkDeviceMemory m_uniformVarBufferMemory = VK_NULL_HANDLE;\n\tbool m_uniformVarBufferMemoryIsCoherent{false};\n\tuint8* m_uniformVarBufferPtr = nullptr;\n\tuint32 m_uniformVarBufferWriteIndex = 0;\n\tuint32 m_uniformVarBufferReadIndex = 0;\n\n\t// transform feedback ringbuffer\n\tVkBuffer m_xfbRingBuffer = VK_NULL_HANDLE;\n\tVkDeviceMemory m_xfbRingBufferMemory = VK_NULL_HANDLE;\n\n\t// buffer cache (attributes, uniforms and streamout)\n\tVkBuffer m_bufferCache = VK_NULL_HANDLE;\n\tVkDeviceMemory m_bufferCacheMemory = VK_NULL_HANDLE;\n\n\t// texture readback\n\tVkBuffer m_textureReadbackBuffer = VK_NULL_HANDLE;\n\tVkDeviceMemory m_textureReadbackBufferMemory = VK_NULL_HANDLE;\n\tuint8* m_textureReadbackBufferPtr = nullptr;\n\tuint32 m_textureReadbackBufferWriteIndex = 0;\n\n\t// placeholder objects to simulate NULL buffers and textures\n\tstruct NullTexture\n\t{\n\t\tVkImage image;\n\t\tVkImageView view;\n\t\tVkSampler sampler;\n\t\tVkImageMemAllocation* allocation;\n\t};\n\n\tNullTexture nullTexture1D{};\n\tNullTexture nullTexture2D{};\n\n\tvoid CreateNullTexture(NullTexture& nullTex, VkImageType imageType);\n\tvoid CreateNullObjects();\n\tvoid DeleteNullTexture(NullTexture& nullTex);\n\tvoid DeleteNullObjects();\n\n\t// if VK_EXT_external_memory_host is supported we can (optionally) import all of the Wii U memory into a Vulkan memory object\n\t// this allows us to skip any vertex/uniform caching logic and let the GPU directly read the memory from main RAM\n\t// Wii U memory imported into a buffer\n\tbool m_useHostMemoryForCache{ false };\n\tVkBuffer m_importedMem = VK_NULL_HANDLE;\n\tVkDeviceMemory m_importedMemMemory = VK_NULL_HANDLE;\n\tMPTR m_importedMemBaseAddress = 0;\n\n\t// command buffer, garbage collection, synchronization\n\tstatic constexpr uint32 kCommandBufferPoolSize = 128;\n\n\tsize_t m_commandBufferIndex = 0; // current buffer being filled\n\tsize_t m_commandBufferSyncIndex = 0; // latest buffer that finished execution (updated on submit)\n\tsize_t m_commandBufferIDOfPrevFrame = 0;\n\tstd::array<size_t, kCommandBufferPoolSize> m_cmdBufferUniformRingbufIndices {}; // index in the uniform ringbuffer\n\tstd::array<VkFence, kCommandBufferPoolSize> m_cmd_buffer_fences;\n\tstd::array<VkCommandBuffer, kCommandBufferPoolSize> m_commandBuffers;\n\tstd::array<VkSemaphore, kCommandBufferPoolSize> m_commandBufferSemaphores;\n\n\tVkSemaphore GetLastSubmittedCmdBufferSemaphore()\n\t{\n\t\treturn m_commandBufferSemaphores[(m_commandBufferIndex + m_commandBufferSemaphores.size() - 1) % m_commandBufferSemaphores.size()];\n\t}\n\n\tuint64 m_numSubmittedCmdBuffers{};\n\tuint64 m_countCommandBufferFinished{};\n\n\tuint32 m_recordedDrawcalls{}; // number of drawcalls recorded into current command buffer\n\tuint32 m_submitThreshold{}; // submit current buffer if recordedDrawcalls exceeds this number\n\tbool m_submitOnIdle{}; // submit current buffer if Latte command processor goes into idle state (no more commands or waiting for externally signaled condition)\n\n\t// tracking for dynamic offsets\n\tstruct\n\t{\n\t\tuint32 uniformVarBufferOffset[VulkanRendererConst::SHADER_STAGE_INDEX_COUNT];\n\t\tstruct\n\t\t{\n\t\t\tuint32 uniformBufferOffset[LATTE_NUM_MAX_UNIFORM_BUFFERS];\n\t\t}shaderUB[VulkanRendererConst::SHADER_STAGE_INDEX_COUNT];\n\t}dynamicOffsetInfo{};\n\n\t// streamout\n\tstruct\n\t{\n\t\tstruct\n\t\t{\n\t\t\tbool enabled;\n\t\t\tuint32 ringBufferOffset;\n\t\t}buffer[LATTE_NUM_STREAMOUT_BUFFER];\n\t\tsint32 verticesPerInstance;\n\t}m_streamoutState{};\n\n\tstruct\n\t{\n\t\tVkQueryPool queryPool{VK_NULL_HANDLE};\n\t\tsint32 currentQueryIndex{};\n\t\tstd::vector<class LatteQueryObjectVk*> list_cachedQueries;\n\t\tstd::vector<class LatteQueryObjectVk*> list_currentlyActiveQueries;\n\t\tuint64 m_lastCommandBuffer{};\n\t\t// query result buffer\n\t\tVkBuffer bufferQueryResults;\n\t\tVkDeviceMemory memoryQueryResults;\n\t\tuint64* ptrQueryResults;\n\t\tstd::vector<uint16> list_availableQueryIndices;\n\t}m_occlusionQueries;\n\n\t// barrier\n\n\tenum SYNC_OP : uint32\n\t{\n\t\t/* name */\t\t\t\t\t\t/* operations */\n\t\tHOST_WRITE\t\t\t= 0x01,\n\t\tHOST_READ\t\t\t= 0x02,\n\n\t\t// BUFFER_INDEX_READ (should be separated?)\n\t\tBUFFER_SHADER_READ\t= 0x04,\t\t// any form of shader read access\n\t\tBUFFER_SHADER_WRITE\t= 0x08,\t\t// any form of shader write access\n\t\tANY_TRANSFER\t\t= 0x10,\t\t// previous transfer to/from buffer or image\n\t\tTRANSFER_READ\t\t= 0x80,\t\t// transfer from image/buffer\n\t\tTRANSFER_WRITE\t\t= 0x100,\t// transfer to image/buffer\n\n\n\t\tIMAGE_READ\t\t\t= 0x20,\n\t\tIMAGE_WRITE\t\t\t= 0x40,\n\n\t};\n\n\ttemplate<uint32 TSyncOp>\n\tvoid barrier_calcStageAndMask(VkPipelineStageFlags& stages, VkAccessFlags& accessFlags)\n\t{\n\t\tstages = 0;\n\t\taccessFlags = 0;\n\t\tif constexpr ((TSyncOp & BUFFER_SHADER_READ) != 0)\n\t\t{\n\t\t\t// in theory: VK_ACCESS_INDEX_READ_BIT should be set here too but indices are currently separated\n\t\t\tstages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;\n\t\t\taccessFlags |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT;\n\t\t}\n\n\t\tif constexpr ((TSyncOp & BUFFER_SHADER_WRITE) != 0)\n\t\t{\n\t\t\tstages |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;\n\t\t\taccessFlags |= VK_ACCESS_SHADER_WRITE_BIT;\n\t\t}\n\n\t\tif constexpr ((TSyncOp & ANY_TRANSFER) != 0)\n\t\t{\n\t\t\t//stages |= VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_HOST_BIT;\n\t\t\t//accessFlags |= VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT;\n\t\t\tstages |= VK_PIPELINE_STAGE_TRANSFER_BIT;\n\t\t\taccessFlags |= VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;\n\n\t\t\t//accessFlags |= VK_ACCESS_MEMORY_READ_BIT;\n\t\t\t//accessFlags |= VK_ACCESS_MEMORY_WRITE_BIT;\n\t\t}\n\n\t\tif constexpr ((TSyncOp & TRANSFER_READ) != 0)\n\t\t{\n\t\t\tstages |= VK_PIPELINE_STAGE_TRANSFER_BIT;\n\t\t\taccessFlags |= VK_ACCESS_TRANSFER_READ_BIT;\n\n\t\t\t//accessFlags |= VK_ACCESS_MEMORY_READ_BIT;\n\t\t}\n\n\t\tif constexpr ((TSyncOp & TRANSFER_WRITE) != 0)\n\t\t{\n\t\t\tstages |= VK_PIPELINE_STAGE_TRANSFER_BIT;\n\t\t\taccessFlags |= VK_ACCESS_TRANSFER_WRITE_BIT;\n\n\t\t\t//accessFlags |= VK_ACCESS_MEMORY_WRITE_BIT;\n\t\t}\n\n\t\tif constexpr ((TSyncOp & HOST_WRITE) != 0)\n\t\t{\n\t\t\tstages |= VK_PIPELINE_STAGE_HOST_BIT;\n\t\t\taccessFlags |= VK_ACCESS_HOST_WRITE_BIT;\n\t\t}\n\n\t\tif constexpr ((TSyncOp & HOST_READ) != 0)\n\t\t{\n\t\t\tstages |= VK_PIPELINE_STAGE_HOST_BIT;\n\t\t\taccessFlags |= VK_ACCESS_HOST_READ_BIT;\n\t\t}\n\n\t\tif constexpr ((TSyncOp & IMAGE_READ) != 0)\n\t\t{\n\t\t\tstages |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;\n\t\t\taccessFlags |= VK_ACCESS_SHADER_READ_BIT;\n\n\t\t\tstages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n\t\t\taccessFlags |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;\n\n\t\t\tstages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;\n\t\t\taccessFlags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;\n\t\t}\n\n\t\tif constexpr ((TSyncOp & IMAGE_WRITE) != 0)\n\t\t{\n\t\t\tstages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n\t\t\taccessFlags |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n\n\t\t\tstages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;\n\t\t\taccessFlags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;\n\t\t}\n\t}\n\n\ttemplate<uint32 TSrcSyncOp, uint32 TDstSyncOp>\n\tvoid barrier_bufferRange(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size)\n\t{\n\t\tVkBufferMemoryBarrier bufMemBarrier{};\n\t\tbufMemBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;\n\t\tbufMemBarrier.pNext = nullptr;\n\t\tbufMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n\t\tbufMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n\n\t\tVkPipelineStageFlags srcStages = 0;\n\t\tVkPipelineStageFlags dstStages = 0;\n\n\t\tbufMemBarrier.srcAccessMask = 0;\n\t\tbufMemBarrier.dstAccessMask = 0;\n\n\t\tbarrier_calcStageAndMask<TSrcSyncOp>(srcStages, bufMemBarrier.srcAccessMask);\n\t\tbarrier_calcStageAndMask<TDstSyncOp>(dstStages, bufMemBarrier.dstAccessMask);\n\n\t\tbufMemBarrier.buffer = buffer;\n\t\tbufMemBarrier.offset = offset;\n\t\tbufMemBarrier.size = size;\n\t\tvkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStages, dstStages, 0, 0, nullptr, 1, &bufMemBarrier, 0, nullptr);\n\t}\n\n\ttemplate<uint32 TSrcSyncOpA, uint32 TDstSyncOpA, uint32 TSrcSyncOpB, uint32 TDstSyncOpB>\n\tvoid barrier_bufferRange(VkBuffer bufferA, VkDeviceSize offsetA, VkDeviceSize sizeA,\n\t\t\t\t\t\t\t VkBuffer bufferB, VkDeviceSize offsetB, VkDeviceSize sizeB)\n\t{\n\t\tVkPipelineStageFlags srcStagesA = 0;\n\t\tVkPipelineStageFlags dstStagesA = 0;\n\t\tVkPipelineStageFlags srcStagesB = 0;\n\t\tVkPipelineStageFlags dstStagesB = 0;\n\n\t\tVkBufferMemoryBarrier bufMemBarrier[2];\n\n\t\tbufMemBarrier[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;\n\t\tbufMemBarrier[0].pNext = nullptr;\n\t\tbufMemBarrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n\t\tbufMemBarrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n\t\tbufMemBarrier[0].srcAccessMask = 0;\n\t\tbufMemBarrier[0].dstAccessMask = 0;\n\t\tbarrier_calcStageAndMask<TSrcSyncOpA>(srcStagesA, bufMemBarrier[0].srcAccessMask);\n\t\tbarrier_calcStageAndMask<TDstSyncOpA>(dstStagesA, bufMemBarrier[0].dstAccessMask);\n\t\tbufMemBarrier[0].buffer = bufferA;\n\t\tbufMemBarrier[0].offset = offsetA;\n\t\tbufMemBarrier[0].size = sizeA;\n\n\t\tbufMemBarrier[1].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;\n\t\tbufMemBarrier[1].pNext = nullptr;\n\t\tbufMemBarrier[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n\t\tbufMemBarrier[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n\t\tbufMemBarrier[1].srcAccessMask = 0;\n\t\tbufMemBarrier[1].dstAccessMask = 0;\n\t\tbarrier_calcStageAndMask<TSrcSyncOpB>(srcStagesB, bufMemBarrier[1].srcAccessMask);\n\t\tbarrier_calcStageAndMask<TDstSyncOpB>(dstStagesB, bufMemBarrier[1].dstAccessMask);\n\t\tbufMemBarrier[1].buffer = bufferB;\n\t\tbufMemBarrier[1].offset = offsetB;\n\t\tbufMemBarrier[1].size = sizeB;\n\n\t\tvkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStagesA|srcStagesB, dstStagesA|dstStagesB, 0, 0, nullptr, 2, bufMemBarrier, 0, nullptr);\n\t}\n\n\tvoid barrier_sequentializeTransfer()\n\t{\n\t\tVkMemoryBarrier memBarrier{};\n\t\tmemBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;\n\t\tmemBarrier.pNext = nullptr;\n\n\t\tVkPipelineStageFlags srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT;\n\t\tVkPipelineStageFlags dstStages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;\n\n\t\tmemBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;\n\t\tmemBarrier.dstAccessMask = 0;\n\n\t\tmemBarrier.srcAccessMask |= (VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT);\n\t\tmemBarrier.dstAccessMask |= (VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT);\n\n\t\tvkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStages, dstStages, 0, 1, &memBarrier, 0, nullptr, 0, nullptr);\n\t}\n\n\tvoid barrier_sequentializeCommand()\n\t{\n\t\tVkPipelineStageFlags srcStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;\n\t\tVkPipelineStageFlags dstStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;\n\n\t\tvkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStages, dstStages, 0, 0, nullptr, 0, nullptr, 0, nullptr);\n\t}\n\n\ttemplate<uint32 TSrcSyncOp, uint32 TDstSyncOp>\n\tvoid barrier_image(VkImage imageVk, VkImageSubresourceRange& subresourceRange, VkImageLayout oldLayout, VkImageLayout newLayout)\n\t{\n\t\tVkPipelineStageFlags srcStages = 0;\n\t\tVkPipelineStageFlags dstStages = 0;\n\n\t\tVkImageMemoryBarrier imageMemBarrier{};\n\t\timageMemBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n\t\timageMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n\t\timageMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n\t\timageMemBarrier.srcAccessMask = 0;\n\t\timageMemBarrier.dstAccessMask = 0;\n\t\tbarrier_calcStageAndMask<TSrcSyncOp>(srcStages, imageMemBarrier.srcAccessMask);\n\t\tbarrier_calcStageAndMask<TDstSyncOp>(dstStages, imageMemBarrier.dstAccessMask);\n\t\timageMemBarrier.image = imageVk;\n\t\timageMemBarrier.subresourceRange = subresourceRange;\n\t\timageMemBarrier.oldLayout = oldLayout;\n\t\timageMemBarrier.newLayout = newLayout;\n\n\t\tvkCmdPipelineBarrier(m_state.currentCommandBuffer,\n\t\t\t\t\t\t\t srcStages, dstStages,\n\t\t\t\t\t\t\t 0,\n\t\t\t\t\t\t\t 0, NULL,\n\t\t\t\t\t\t\t 0, NULL,\n\t\t\t\t\t\t\t 1, &imageMemBarrier);\n\t}\n\n\ttemplate<uint32 TSrcSyncOp, uint32 TDstSyncOp>\n\tvoid barrier_image(LatteTextureVk* vkTexture, VkImageSubresourceLayers& subresourceLayers, VkImageLayout newLayout)\n\t{\n\t\tVkImage imageVk = vkTexture->GetImageObj()->m_image;\n\n\t\tVkImageSubresourceRange subresourceRange;\n\t\tsubresourceRange.aspectMask = subresourceLayers.aspectMask;\n\t\tsubresourceRange.baseArrayLayer = subresourceLayers.baseArrayLayer;\n\t\tsubresourceRange.layerCount = subresourceLayers.layerCount;\n\t\tsubresourceRange.baseMipLevel = subresourceLayers.mipLevel;\n\t\tsubresourceRange.levelCount = 1;\n\n\t\tbarrier_image<TSrcSyncOp, TDstSyncOp>(imageVk, subresourceRange, vkTexture->GetImageLayout(subresourceRange), newLayout);\n\n\t\tvkTexture->SetImageLayout(subresourceRange, newLayout);\n\t}\n\n\npublic:\n\tbool GetDisableMultithreadedCompilation() const { return m_featureControl.disableMultithreadedCompilation; }\n\tbool HasSPRIVRoundingModeRTE32() const { return m_featureControl.shaderFloatControls.shaderRoundingModeRTEFloat32; }\n\tbool IsDebugMarkersEnabled() const { return m_featureControl.usingDebugMarkerTool; }\n\tbool IsTracingToolEnabled() const { return m_featureControl.usingTracingTool; }\n\nprivate:\n\n\t// debug\n\tvoid debug_genericBarrier();\n\n\t// shaders\n\tstruct\n\t{\n\t\tRendererShaderVk* copySurface_vs{};\n\t\tRendererShaderVk* copySurface_psDepth2Color{};\n\t\tRendererShaderVk* copySurface_psColor2Depth{};\n\t}defaultShaders;\n\n\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h\"\n\n#include \"Cafe/HW/Latte/Core/LattePerformanceMonitor.h\"\n#include \"Cafe/HW/Latte/Core/LatteShader.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteIndices.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"imgui/imgui_impl_vulkan.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"util/helpers/helpers.h\"\n\nextern bool hasValidFramebufferAttached;\n\n// includes only states that may change during minimal drawcalls\nuint64 VulkanRenderer::draw_calculateMinimalGraphicsPipelineHash(const LatteFetchShader* fetchShader, const LatteContextRegister& lcr)\n{\n\tuint64 stateHash = 0;\n\n\t// fetch shader\n\tfor (auto& group : fetchShader->bufferGroups)\n\t{\n\t\tuint32 bufferStride = group.getCurrentBufferStride(lcr.GetRawView());\n\t\tstateHash = std::rotl<uint64>(stateHash, 7);\n\t\tstateHash += bufferStride * 3;\n\t}\n\n\tstateHash += fetchShader->getVkPipelineHashFragment();\n\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\tstateHash += lcr.GetRawView()[mmVGT_PRIMITIVE_TYPE];\n\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\tstateHash += lcr.GetRawView()[mmVGT_STRMOUT_EN];\n\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\tif(lcr.PA_CL_CLIP_CNTL.get_DX_RASTERIZATION_KILL())\n\t\tstateHash += 0x333333;\n\n\treturn stateHash;\n}\n\nuint64 VulkanRenderer::draw_calculateGraphicsPipelineHash(const LatteFetchShader* fetchShader, const LatteDecompilerShader* vertexShader, const LatteDecompilerShader* geometryShader, const LatteDecompilerShader* pixelShader, const VKRObjectRenderPass* renderPassObj, const LatteContextRegister& lcr)\n{\n\t// note: vertexShader references a fetchShader (vertexShader->fetchShader) but it's not necessarily the one that is currently active\n\t// this is because we try to separate dynamic state (mainly attribute offsets) from the actual attribute data layout and mapping (types and slots)\n\t// on Vulkan this causes issues because we bake the attribute offsets, which may not match vertexShader->compatibleFetchShader, into the pipeline\n\t// To avoid issues always use the active fetch shader. Not the one associated with the vertexShader object\n\t// note 2:\n\t// there is a secondary issue where we dont store all fetch shaders into the pipeline cache (only a single fetch shader is tied to each stored vertex shader)\n\t// but we can probably trust drivers to not require pipeline recompilation if only the offsets differ\n\t// An alternative would be to use VK_EXT_vertex_input_dynamic_state but it comes with minor overhead\n\t// Regardless, the extension is not well supported as of writing this (July 2021, only 10% of GPUs support it on Windows. Nvidia only)\n\n\tcemu_assert_debug(vertexShader->compatibleFetchShader->key == fetchShader->key); // fetch shaders must be layout compatible, but may have different offsets\n\n\tuint64 stateHash;\n\tstateHash = draw_calculateMinimalGraphicsPipelineHash(fetchShader, lcr);\n\tstateHash = (stateHash >> 8) + (stateHash * 0x370531ull) % 0x7F980D3BF9B4639Dull;\n\n\tuint32* ctxRegister = lcr.GetRawView();\n\n\tif (vertexShader)\n\t\tstateHash += vertexShader->baseHash;\n\n\tstateHash = std::rotl<uint64>(stateHash, 13);\n\n\tif (geometryShader)\n\t\tstateHash += geometryShader->baseHash;\n\n\tstateHash = std::rotl<uint64>(stateHash, 13);\n\n\tif (pixelShader)\n\t\tstateHash += pixelShader->baseHash + pixelShader->auxHash;\n\n\tstateHash = std::rotl<uint64>(stateHash, 13);\n\n\tuint32 polygonCtrl = lcr.PA_SU_SC_MODE_CNTL.getRawValue();\n\tstateHash += polygonCtrl;\n\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\tstateHash += ctxRegister[Latte::REGADDR::PA_CL_CLIP_CNTL];\n\tstateHash = std::rotl<uint64>(stateHash, 7);\n\n\tconst auto colorControlReg = ctxRegister[Latte::REGADDR::CB_COLOR_CONTROL];\n\tstateHash += colorControlReg;\n\n\tstateHash += ctxRegister[Latte::REGADDR::CB_TARGET_MASK];\n\n\tconst uint32 blendEnableMask = (colorControlReg >> 8) & 0xFF;\n\tif (blendEnableMask)\n\t{\n\t\tfor (auto i = 0; i < 8; ++i)\n\t\t{\n\t\t\tif (((blendEnableMask & (1 << i))) == 0)\n\t\t\t\tcontinue;\n\t\t\tstateHash = std::rotl<uint64>(stateHash, 7);\n\t\t\tstateHash += ctxRegister[Latte::REGADDR::CB_BLEND0_CONTROL + i];\n\t\t}\n\t}\n\n\tstateHash += renderPassObj->m_hashForPipeline;\n\n\tuint32 depthControl = ctxRegister[Latte::REGADDR::DB_DEPTH_CONTROL];\n\tbool stencilTestEnable = depthControl & 1;\n\tif (stencilTestEnable)\n\t{\n\t\tstateHash += ctxRegister[mmDB_STENCILREFMASK];\n\t\tstateHash = std::rotl<uint64>(stateHash, 17);\n\t\tif(depthControl & (1<<7)) // back stencil enable\n\t\t{\n\t\t\tstateHash += ctxRegister[mmDB_STENCILREFMASK_BF];\n\t\t\tstateHash = std::rotl<uint64>(stateHash, 13);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// zero out stencil related bits (8-31)\n\t\tdepthControl &= 0xFF;\n\t}\n\n\tstateHash = std::rotl<uint64>(stateHash, 17);\n\tstateHash += depthControl;\n\n\t// polygon offset\n\tif (polygonCtrl & (1 << 11))\n\t{\n\t\t// front offset enabled\n\t\tstateHash += 0x1111;\n\t}\n\n\treturn stateHash;\n}\n\nvoid VulkanRenderer::draw_debugPipelineHashState()\n{\n\tcemu_assert_debug(false);\n}\n\nPipelineInfo* VulkanRenderer::draw_getCachedPipeline()\n{\n\t// todo - optimize m_pipeline_info_cache away and store directly in vk vertex shader\n\tconst auto fetchShader = LatteSHRC_GetActiveFetchShader();\n\tconst auto vertexShader = LatteSHRC_GetActiveVertexShader();\n\tconst auto it = m_pipeline_info_cache.find(vertexShader->baseHash);\n\tif (it == m_pipeline_info_cache.cend())\n\t\treturn nullptr;\n\n\tconst auto geometryShader = LatteSHRC_GetActiveGeometryShader();\n\tconst auto pixelShader = LatteSHRC_GetActivePixelShader();\n\tauto cachedFboVk = (CachedFBOVk*)m_state.activeFBO;\n\n\tconst uint64 stateHash = draw_calculateGraphicsPipelineHash(fetchShader, vertexShader, geometryShader, pixelShader, cachedFboVk->GetRenderPassObj(), LatteGPUState.contextNew);\n\n\tconst auto innerit = it->second.find(stateHash);\n\tif (innerit == it->second.cend())\n\t\treturn nullptr;\n\n\treturn innerit->second;\n}\n\nvoid VulkanRenderer::unregisterGraphicsPipeline(PipelineInfo* pipelineInfo)\n{\n\tbool removedFromCache = false;\n\tfor (auto& topMapItr : m_pipeline_info_cache)\n\t{\n\t\tauto& subMap = topMapItr.second;\n\t\tfor (auto it = subMap.cbegin(); it != subMap.cend();)\n\t\t{\n\t\t\tif (it->second == pipelineInfo)\n\t\t\t{\n\t\t\t\tsubMap.erase(it);\n\t\t\t\tremovedFromCache = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t++it;\n\t\t}\n\t\tif (removedFromCache)\n\t\t\tbreak;\n\t}\n}\n\n// make a guess if a pipeline is not essential\n// non-essential means that skipping these drawcalls shouldn't lead to permanently corrupted graphics\nbool VulkanRenderer::IsAsyncPipelineAllowed(uint32 numIndices)\n{\n\t// frame debuggers dont handle async well (as of 2020)\n\tif (IsTracingToolEnabled())\n\t\treturn false;\n\n\tCachedFBOVk* currentFBO = m_state.activeFBO;\n\tauto fboExtend = currentFBO->GetExtend();\n\n\tif (fboExtend.width == 1600 && fboExtend.height == 1600)\n\t\treturn false; // Splatoon ink mechanics use 1600x1600 R8 and R8G8 framebuffers, this resolution is rare enough that we can just blacklist it globally\n\n\tif (currentFBO->hasDepthBuffer())\n\t\treturn true; // aggressive filter but seems to work well so far\n\n\t// small index count (3,4,5,6) is often associated with full-viewport quads (which are considered essential due to often being used to generate persistent textures)\n\tif (numIndices <= 6)\n\t{\n\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// create graphics pipeline for current state\nPipelineInfo* VulkanRenderer::draw_createGraphicsPipeline(uint32 indexCount)\n{\n\tconst auto fetchShader = LatteSHRC_GetActiveFetchShader();\n\tconst auto vertexShader = LatteSHRC_GetActiveVertexShader();\n\tconst auto geometryShader = LatteSHRC_GetActiveGeometryShader();\n\tconst auto pixelShader = LatteSHRC_GetActivePixelShader();\n\tauto cachedFboVk = (CachedFBOVk*)m_state.activeFBO;\n\n\tuint64 minimalStateHash = draw_calculateMinimalGraphicsPipelineHash(fetchShader, LatteGPUState.contextNew);\n\tuint64 pipelineHash = draw_calculateGraphicsPipelineHash(fetchShader, vertexShader, geometryShader, pixelShader, cachedFboVk->GetRenderPassObj(), LatteGPUState.contextNew);\n\n\t// create PipelineInfo\n\tauto vkFBO = (CachedFBOVk*)(VulkanRenderer::GetInstance()->m_state.activeFBO);\n\tPipelineInfo* pipelineInfo = new PipelineInfo(minimalStateHash, pipelineHash, fetchShader, vertexShader, pixelShader, geometryShader);\n\n\t// register pipeline\n\tuint64 vsBaseHash = vertexShader->baseHash;\n\tauto it = m_pipeline_info_cache.emplace(vsBaseHash, robin_hood::unordered_flat_map<uint64, PipelineInfo*>());\n\tauto& cache_map = it.first->second;\n\tcache_map.emplace(pipelineHash, pipelineInfo);\n\n\t// init pipeline compiler\n\tPipelineCompiler* pipelineCompiler = new PipelineCompiler();\n\n\tbool requiresRobustBufferAccess = PipelineCompiler::CalcRobustBufferAccessRequirement(vertexShader, pixelShader, geometryShader);\n\tpipelineCompiler->InitFromCurrentGPUState(pipelineInfo, LatteGPUState.contextNew, vkFBO->GetRenderPassObj(), requiresRobustBufferAccess);\n\tpipelineCompiler->TrackAsCached(vsBaseHash, pipelineHash);\n\n\t// use heuristics based on parameter patterns to determine if the current drawcall is essential (non-skipable)\n\tbool allowAsyncCompile = false;\n\tif (GetConfig().async_compile)\n\t\tallowAsyncCompile = IsAsyncPipelineAllowed(indexCount);\n\n\tif (allowAsyncCompile)\n\t{\n\t\t// even when async is allowed, attempt synchronous creation first (which will immediately fail if the pipeline is not cached)\n\t\tif (pipelineCompiler->Compile(false, true, true) == false)\n\t\t{\n\t\t\t// shaders or pipeline not cached -> asynchronous compilation\n\t\t\tPipelineCompiler::CompileThreadPool_QueueCompilation(pipelineCompiler);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdelete pipelineCompiler;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// synchronous compilation\n\t\tpipelineCompiler->Compile(true, true, true);\n\t\tdelete pipelineCompiler;\n\t}\n\n\treturn pipelineInfo;\n}\n\nPipelineInfo* VulkanRenderer::draw_getOrCreateGraphicsPipeline(uint32 indexCount)\n{\n\tauto cache_object = draw_getCachedPipeline();\n\tif (cache_object != nullptr)\n\t{\n\n#ifdef CEMU_DEBUG_ASSERT\n\t\tcemu_assert_debug(cache_object->vertexShader == LatteSHRC_GetActiveVertexShader());\n\t\tcemu_assert_debug(cache_object->geometryShader == LatteSHRC_GetActiveGeometryShader());\n\t\tcemu_assert_debug(cache_object->pixelShader == LatteSHRC_GetActivePixelShader());\n\t\tif (cache_object->fetchShader->key != LatteSHRC_GetActiveFetchShader()->key ||\n\t\t\tcache_object->fetchShader->vkPipelineHashFragment != LatteSHRC_GetActiveFetchShader()->vkPipelineHashFragment)\n\t\t{\n\t\t\tdebug_printf(\"Incompatible fetch shader %p %p\\n\", cache_object->fetchShader, LatteSHRC_GetActiveFetchShader());\n\t\t\tassert_dbg();\n\t\t}\n\t\tuint64 calcMinimalHash = draw_calculateMinimalGraphicsPipelineHash(LatteSHRC_GetActiveFetchShader(), LatteGPUState.contextNew);\n\t\tauto currentPrimitiveMode = LatteGPUState.contextNew.VGT_PRIMITIVE_TYPE.get_PRIMITIVE_MODE();\n\t\tcemu_assert_debug(cache_object->primitiveMode == currentPrimitiveMode);\n\t\tcemu_assert_debug(cache_object->minimalStateHash == calcMinimalHash);\n#endif\n\t\treturn cache_object;\n\t}\n\t//draw_debugPipelineHashState();\n\n\treturn draw_createGraphicsPipeline(indexCount);\n}\n\nRenderer::IndexAllocation VulkanRenderer::indexData_reserveIndexMemory(uint32 size)\n{\n\tVKRSynchronizedHeapAllocator::AllocatorReservation* resv = memoryManager->GetIndexAllocator().AllocateBufferMemory(size, 32);\n\treturn { resv->memPtr, resv };\n}\n\nvoid VulkanRenderer::indexData_releaseIndexMemory(IndexAllocation& allocation)\n{\n\tmemoryManager->GetIndexAllocator().FreeReservation((VKRSynchronizedHeapAllocator::AllocatorReservation*)allocation.rendererInternal);\n}\n\nvoid VulkanRenderer::indexData_uploadIndexMemory(IndexAllocation& allocation)\n{\n\tmemoryManager->GetIndexAllocator().FlushReservation((VKRSynchronizedHeapAllocator::AllocatorReservation*)allocation.rendererInternal);\n}\n\nfloat s_vkUniformData[512 * 4];\n\nuint32 VulkanRenderer::uniformData_uploadUniformDataBufferGetOffset(std::span<uint8> data)\n{\n\tconst uint32 bufferAlignmentM1 = std::max(m_featureControl.limits.minUniformBufferOffsetAlignment, m_featureControl.limits.nonCoherentAtomSize) - 1;\n\tconst uint32 uniformSize = ((uint32)data.size() + bufferAlignmentM1) & ~bufferAlignmentM1;\n\n\tauto waitWhileCondition = [&](std::function<bool()> condition) {\n\t\twhile (condition())\n\t\t{\n\t\t\tif (m_commandBufferSyncIndex == m_commandBufferIndex)\n\t\t\t{\n\t\t\t\tif (m_cmdBufferUniformRingbufIndices[m_commandBufferIndex] != m_uniformVarBufferReadIndex)\n\t\t\t\t{\n\t\t\t\t\tdraw_endRenderPass();\n\t\t\t\t\tSubmitCommandBuffer();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// submitting work would not change readIndex, so there's no way for conditions based on it to change\n\t\t\t\t\tcemuLog_log(LogType::Force, \"draw call overflowed and corrupted uniform ringbuffer. expect visual corruption\");\n\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tWaitForNextFinishedCommandBuffer();\n\t\t}\n\t};\n\n\t// wrap around if it doesnt fit consecutively\n\tif (m_uniformVarBufferWriteIndex + uniformSize > UNIFORMVAR_RINGBUFFER_SIZE)\n\t{\n\t\twaitWhileCondition([&]() {\n\t\t\treturn m_uniformVarBufferReadIndex > m_uniformVarBufferWriteIndex || m_uniformVarBufferReadIndex == 0;\n\t\t});\n\t\tm_uniformVarBufferWriteIndex = 0;\n\t}\n\n\tauto ringBufRemaining = [&]() {\n\t\tssize_t ringBufferUsedBytes = (ssize_t)m_uniformVarBufferWriteIndex - m_uniformVarBufferReadIndex;\n\t\tif (ringBufferUsedBytes < 0)\n\t\t\tringBufferUsedBytes += UNIFORMVAR_RINGBUFFER_SIZE;\n\t\treturn UNIFORMVAR_RINGBUFFER_SIZE - 1 - ringBufferUsedBytes;\n\t};\n\twaitWhileCondition([&]() {\n\t\treturn ringBufRemaining() < uniformSize;\n\t});\n\n\tconst uint32 uniformOffset = m_uniformVarBufferWriteIndex;\n\tmemcpy(m_uniformVarBufferPtr + uniformOffset, data.data(), data.size());\n\tm_uniformVarBufferWriteIndex += uniformSize;\n\t// flush if not coherent\n\tif (!m_uniformVarBufferMemoryIsCoherent)\n\t{\n\t\tVkMappedMemoryRange flushedRange{};\n\t\tflushedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;\n\t\tflushedRange.memory = m_uniformVarBufferMemory;\n\t\tflushedRange.offset = uniformOffset;\n\t\tflushedRange.size = uniformSize;\n\t\tvkFlushMappedMemoryRanges(m_logicalDevice, 1, &flushedRange);\n\t}\n\treturn uniformOffset;\n}\n\nvoid VulkanRenderer::uniformData_updateUniformVars(uint32 shaderStageIndex, LatteDecompilerShader* shader)\n{\n\tauto GET_UNIFORM_DATA_PTR = [](size_t index) { return s_vkUniformData + (index / 4); };\n\n\tsint32 shaderAluConst;\n\n\tswitch (shader->shaderType)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t\tshaderAluConst = 0x400;\n\t\tbreak;\n\tcase LatteConst::ShaderType::Pixel:\n\t\tshaderAluConst = 0;\n\t\tbreak;\n\tcase LatteConst::ShaderType::Geometry:\n\t\tshaderAluConst = 0; // geometry shader has no ALU const\n\t\tbreak;\n\tdefault:\n\t\tUNREACHABLE;\n\t}\n\n\tif (shader->resourceMapping.uniformVarsBufferBindingPoint >= 0)\n\t{\n\t\tif (shader->uniform.list_ufTexRescale.empty() == false)\n\t\t{\n\t\t\tfor (auto& entry : shader->uniform.list_ufTexRescale)\n\t\t\t{\n\t\t\t\tfloat* xyScale = LatteTexture_getEffectiveTextureScale(shader->shaderType, entry.texUnit);\n\t\t\t\tmemcpy(entry.currentValue, xyScale, sizeof(float) * 2);\n\t\t\t\tmemcpy(GET_UNIFORM_DATA_PTR(entry.uniformLocation), xyScale, sizeof(float) * 2);\n\t\t\t}\n\t\t}\n\t\tif (shader->uniform.loc_alphaTestRef >= 0)\n\t\t{\n\t\t\t*GET_UNIFORM_DATA_PTR(shader->uniform.loc_alphaTestRef) = LatteGPUState.contextNew.SX_ALPHA_REF.get_ALPHA_TEST_REF();\n\t\t}\n\t\tif (shader->uniform.loc_pointSize >= 0)\n\t\t{\n\t\t\tconst auto& pointSizeReg = LatteGPUState.contextNew.PA_SU_POINT_SIZE;\n\t\t\tfloat pointWidth = (float)pointSizeReg.get_WIDTH() / 8.0f;\n\t\t\tif (pointWidth == 0.0f)\n\t\t\t\tpointWidth = 1.0f / 8.0f; // minimum size\n\t\t\t*GET_UNIFORM_DATA_PTR(shader->uniform.loc_pointSize) = pointWidth;\n\t\t}\n\t\tif (shader->uniform.loc_remapped >= 0)\n\t\t{\n\t\t\tLatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped));\n\t\t}\n\t\tif (shader->uniform.loc_uniformRegister >= 0)\n\t\t{\n\t\t\tuint32* uniformRegData = (uint32*)(LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst);\n\t\t\tmemcpy(GET_UNIFORM_DATA_PTR(shader->uniform.loc_uniformRegister), uniformRegData, shader->uniform.count_uniformRegister * 16);\n\t\t}\n\t\tif (shader->uniform.loc_windowSpaceToClipSpaceTransform >= 0)\n\t\t{\n\t\t\tsint32 viewportWidth;\n\t\t\tsint32 viewportHeight;\n\t\t\tLatteRenderTarget_GetCurrentVirtualViewportSize(&viewportWidth, &viewportHeight); // always call after _updateViewport()\n\t\t\tfloat* v = GET_UNIFORM_DATA_PTR(shader->uniform.loc_windowSpaceToClipSpaceTransform);\n\t\t\tv[0] = 2.0f / (float)viewportWidth;\n\t\t\tv[1] = 2.0f / (float)viewportHeight;\n\t\t}\n\t\tif (shader->uniform.loc_fragCoordScale >= 0)\n\t\t{\n\t\t\tLatteMRT::GetCurrentFragCoordScale(GET_UNIFORM_DATA_PTR(shader->uniform.loc_fragCoordScale));\n\t\t}\n\t\tif (shader->uniform.loc_verticesPerInstance >= 0)\n\t\t{\n\t\t\t*(int*)GET_UNIFORM_DATA_PTR(shader->uniform.loc_verticesPerInstance) = m_streamoutState.verticesPerInstance;\n\t\t\tfor (sint32 b = 0; b < LATTE_NUM_STREAMOUT_BUFFER; b++)\n\t\t\t{\n\t\t\t\tif (shader->uniform.loc_streamoutBufferBase[b] >= 0)\n\t\t\t\t{\n\t\t\t\t\t*(uint32*)GET_UNIFORM_DATA_PTR(shader->uniform.loc_streamoutBufferBase[b]) = m_streamoutState.buffer[b].ringBufferOffset;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdynamicOffsetInfo.uniformVarBufferOffset[shaderStageIndex] = uniformData_uploadUniformDataBufferGetOffset({(uint8*)s_vkUniformData, shader->uniform.uniformRangeSize});\n\t}\n}\n\nvoid VulkanRenderer::draw_prepareDynamicOffsetsForDescriptorSet(uint32 shaderStageIndex, uint32* dynamicOffsets,\n\tsint32& numDynOffsets,\n\tconst PipelineInfo* pipeline_info)\n{\n\tnumDynOffsets = 0;\n\tif (pipeline_info->dynamicOffsetInfo.hasUniformVar[shaderStageIndex])\n\t{\n\t\tdynamicOffsets[0] = dynamicOffsetInfo.uniformVarBufferOffset[shaderStageIndex];\n\t\tnumDynOffsets++;\n\t}\n\tif (pipeline_info->dynamicOffsetInfo.hasUniformBuffers[shaderStageIndex])\n\t{\n\t\tfor (auto& itr : pipeline_info->dynamicOffsetInfo.list_uniformBuffers[shaderStageIndex])\n\t\t{\n\t\t\tdynamicOffsets[numDynOffsets] = dynamicOffsetInfo.shaderUB[shaderStageIndex].uniformBufferOffset[itr];\n\t\t\tnumDynOffsets++;\n\t\t}\n\t}\n}\n\nuint64 VulkanRenderer::GetDescriptorSetStateHash(LatteDecompilerShader* shader)\n{\n\tuint64 hash = 0;\n\n\tconst sint32 textureCount = shader->resourceMapping.getTextureCount();\n\tfor (int i = 0; i < textureCount; ++i)\n\t{\n\t\tconst auto relative_textureUnit = shader->resourceMapping.getTextureUnitFromBindingPoint(i);\n\t\tauto hostTextureUnit = relative_textureUnit;\n\t\tauto textureDim = shader->textureUnitDim[relative_textureUnit];\n\t\tauto texUnitRegIndex = hostTextureUnit * 7;\n\t\tswitch (shader->shaderType)\n\t\t{\n\t\tcase LatteConst::ShaderType::Vertex:\n\t\t\thostTextureUnit += LATTE_CEMU_VS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS;\n\t\t\tbreak;\n\t\tcase LatteConst::ShaderType::Pixel:\n\t\t\thostTextureUnit += LATTE_CEMU_PS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS;\n\t\t\tbreak;\n\t\tcase LatteConst::ShaderType::Geometry:\n\t\t\thostTextureUnit += LATTE_CEMU_GS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tUNREACHABLE;\n\t\t}\n\n\t\tauto texture = m_state.boundTexture[hostTextureUnit];\n\t\tif (!texture)\n\t\t\tcontinue;\n\n\t\tconst uint32 word4 = LatteGPUState.contextRegister[texUnitRegIndex + 4];\n\n\t\tuint32 samplerIndex = shader->textureUnitSamplerAssignment[relative_textureUnit];\n\t\tif (samplerIndex != LATTE_DECOMPILER_SAMPLER_NONE)\n\t\t{\n\t\t\tsamplerIndex += LatteDecompiler_getTextureSamplerBaseIndex(shader->shaderType);\n\t\t\thash += LatteGPUState.contextRegister[Latte::REGADDR::SQ_TEX_SAMPLER_WORD0_0 + samplerIndex * 3 + 0];\n\t\t\thash = std::rotl<uint64>(hash, 7);\n\t\t\thash += LatteGPUState.contextRegister[Latte::REGADDR::SQ_TEX_SAMPLER_WORD0_0 + samplerIndex * 3 + 1];\n\t\t\thash = std::rotl<uint64>(hash, 7);\n\t\t\thash += LatteGPUState.contextRegister[Latte::REGADDR::SQ_TEX_SAMPLER_WORD0_0 + samplerIndex * 3 + 2];\n\t\t\thash = std::rotl<uint64>(hash, 7);\n\t\t}\n\t\thash = std::rotl<uint64>(hash, 7);\n\t\t// hash view id + swizzle mask\n\t\thash += (uint64)texture->GetUniqueId();\n\t\thash = std::rotr<uint64>(hash, 21);\n\t\thash += (uint64)(word4 & 0x0FFF0000);\n\t}\n\n\treturn hash;\n}\n\nVkDescriptorSetInfo* VulkanRenderer::draw_getOrCreateDescriptorSet(PipelineInfo* pipeline_info, LatteDecompilerShader* shader)\n{\n\tconst uint64 stateHash = GetDescriptorSetStateHash(shader);\n\n\tVkDescriptorSetLayout descriptor_set_layout;\n\tswitch (shader->shaderType)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t{\n\t\tconst auto it = pipeline_info->vertex_ds_cache.find(stateHash);\n\t\tif (it != pipeline_info->vertex_ds_cache.cend())\n\t\t\treturn it->second;\n\t\tdescriptor_set_layout = pipeline_info->m_vkrObjPipeline->m_vertexDSL;\n\t\tbreak;\n\t}\n\tcase LatteConst::ShaderType::Pixel:\n\t{\n\t\tconst auto it = pipeline_info->pixel_ds_cache.find(stateHash);\n\t\tif (it != pipeline_info->pixel_ds_cache.cend())\n\t\t\treturn it->second;\n\t\tdescriptor_set_layout = pipeline_info->m_vkrObjPipeline->m_pixelDSL;\n\t\tbreak;\n\t}\n\tcase LatteConst::ShaderType::Geometry:\n\t{\n\t\tconst auto it = pipeline_info->geometry_ds_cache.find(stateHash);\n\t\tif (it != pipeline_info->geometry_ds_cache.cend())\n\t\t\treturn it->second;\n\t\tdescriptor_set_layout = pipeline_info->m_vkrObjPipeline->m_geometryDSL;\n\t\tbreak;\n\t}\n\tdefault:\n\t\tUNREACHABLE;\n\t}\n\n\t// create new descriptor set\n\tVkDescriptorSetInfo* dsInfo = new VkDescriptorSetInfo();\n\tdsInfo->stateHash = stateHash;\n\tdsInfo->shaderType = shader->shaderType;\n\tdsInfo->pipeline_info = pipeline_info;\n\n\tdsInfo->m_vkObjDescriptorSet = new VKRObjectDescriptorSet();\n\tauto vkObjDS = dsInfo->m_vkObjDescriptorSet;\n\n\tVkDescriptorSetAllocateInfo allocInfo = {};\n\tallocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n\tallocInfo.descriptorPool = m_descriptorPool;\n\tallocInfo.descriptorSetCount = 1;\n\tallocInfo.pSetLayouts = &descriptor_set_layout;\n\n\tVkDescriptorSet result;\n\tif (vkAllocateDescriptorSets(m_logicalDevice, &allocInfo, &result) != VK_SUCCESS)\n\t{\n\t\tUnrecoverableError(fmt::format(\"Failed to allocate descriptor sets. Currently allocated: Descriptors={} TextureSamplers={} DynUniformBuffers={} StorageBuffers={}\",\n\t\t\tperformanceMonitor.vk.numDescriptorSets.get(),\n\t\t\tperformanceMonitor.vk.numDescriptorSamplerTextures.get(),\n\t\t\tperformanceMonitor.vk.numDescriptorDynUniformBuffers.get(),\n\t\t\tperformanceMonitor.vk.numDescriptorStorageBuffers.get()\n\t\t).c_str());\n\t}\n\tvkObjDS->descriptorSet = result;\n\n\tsint32 textureCount = shader->resourceMapping.getTextureCount();\n\n\tstd::vector<VkWriteDescriptorSet> descriptorWrites;\n\tstd::vector<VkDescriptorImageInfo> textureArray;\n\tfor (int i = 0; i < textureCount; ++i)\n\t{\n\t\tVkDescriptorImageInfo info{};\n\t\tconst auto relative_textureUnit = shader->resourceMapping.getTextureUnitFromBindingPoint(i);\n\t\tauto hostTextureUnit = relative_textureUnit;\n\t\tauto textureDim = shader->textureUnitDim[relative_textureUnit];\n\t\tauto texUnitRegIndex = hostTextureUnit * 7;\n\t\tswitch (shader->shaderType)\n\t\t{\n\t\tcase LatteConst::ShaderType::Vertex:\n\t\t\thostTextureUnit += LATTE_CEMU_VS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS;\n\t\t\tbreak;\n\t\tcase LatteConst::ShaderType::Pixel:\n\t\t\thostTextureUnit += LATTE_CEMU_PS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS;\n\t\t\tbreak;\n\t\tcase LatteConst::ShaderType::Geometry:\n\t\t\thostTextureUnit += LATTE_CEMU_GS_TEX_UNIT_BASE;\n\t\t\ttexUnitRegIndex += Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tUNREACHABLE;\n\t\t}\n\n\t\tauto textureView = m_state.boundTexture[hostTextureUnit];\n\t\tif (!textureView)\n\t\t{\n\t\t\tif (textureDim == Latte::E_DIM::DIM_1D)\n\t\t\t{\n\t\t\t\tinfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\t\t\t\tinfo.imageView = nullTexture1D.view;\n\t\t\t\tinfo.sampler = nullTexture1D.sampler;\n\t\t\t\ttextureArray.emplace_back(info);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tinfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\t\t\t\tinfo.imageView = nullTexture2D.view;\n\t\t\t\tinfo.sampler = nullTexture2D.sampler;\n\t\t\t\ttextureArray.emplace_back(info);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\t// safeguard to avoid using mismatching texture dimensions\n\t\t// if we properly support aux hash for vs/gs this should never trigger\n\t\tif (textureDim == Latte::E_DIM::DIM_1D && (textureView->dim != Latte::E_DIM::DIM_1D))\n\t\t{\n\t\t\t// should be 1D\n\t\t\tinfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\t\t\tinfo.imageView = nullTexture1D.view;\n\t\t\tinfo.sampler = nullTexture1D.sampler;\n\t\t\ttextureArray.emplace_back(info);\n\t\t\t// cemuLog_log(LogType::Force, \"Vulkan-Info: Shader 0x{:016x} uses 1D texture but bound texture has mismatching type (dim: 0x{:02x})\", shader->baseHash, textureView->gx2Dim);\n\t\t\tcontinue;\n\t\t}\n\t\telse if (textureDim == Latte::E_DIM::DIM_2D && (textureView->dim != Latte::E_DIM::DIM_2D && textureView->dim != Latte::E_DIM::DIM_2D_MSAA))\n\t\t{\n\t\t\t// should be 2D\n\t\t\t// is GPU7 fine with 2D access to a 2D_ARRAY texture?\n\t\t\tinfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\t\t\tinfo.imageView = nullTexture2D.view;\n\t\t\tinfo.sampler = nullTexture2D.sampler;\n\t\t\ttextureArray.emplace_back(info);\n\t\t\t// cemuLog_log(LogType::Force, \"Vulkan-Info: Shader 0x{:016x} uses 2D texture but bound texture has mismatching type (dim: 0x{:02x})\", shader->baseHash, textureView->gx2Dim);\n\t\t\tcontinue;\n\t\t}\n\n\t\tinfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\n\t\tVkSamplerCustomBorderColorCreateInfoEXT samplerCustomBorderColor{};\n\n\t\tVkSamplerCreateInfo samplerInfo{};\n\t\tsamplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n\n\t\tLatteTexture* baseTexture = textureView->baseTexture;\n\t\t// get texture register word 0\n\t\tuint32 word4 = LatteGPUState.contextRegister[texUnitRegIndex + 4];\n\n\t\tauto imageViewObj = textureView->GetSamplerView(word4);\n\t\tinfo.imageView = imageViewObj->m_textureImageView;\n\t\tvkObjDS->addRef(imageViewObj);\n\n\t\t// track relation between view and descriptor set\n\t\tvectorAppendUnique(dsInfo->list_referencedViews, textureView);\n\t\ttextureView->AddDescriptorSetReference(dsInfo);\n\n\t\tif (!baseTexture->IsCompressedFormat())\n\t\t\tvectorAppendUnique(dsInfo->list_fboCandidates, (LatteTextureVk*)baseTexture);\n\n\t\tuint32 stageSamplerIndex = shader->textureUnitSamplerAssignment[relative_textureUnit];\n\t\tif (stageSamplerIndex != LATTE_DECOMPILER_SAMPLER_NONE)\n\t\t{\n\t\t\tuint32 samplerIndex = stageSamplerIndex + LatteDecompiler_getTextureSamplerBaseIndex(shader->shaderType);\n\t\t\tconst _LatteRegisterSetSampler* samplerWords = LatteGPUState.contextNew.SQ_TEX_SAMPLER + samplerIndex;\n\n\t\t\t// lod\n\t\t\tuint32 iMinLOD = samplerWords->WORD1.get_MIN_LOD();\n\t\t\tuint32 iMaxLOD = samplerWords->WORD1.get_MAX_LOD();\n\t\t\tsint32 iLodBias = samplerWords->WORD1.get_LOD_BIAS();\n\n\t\t\t// apply relative lod bias from graphic pack\n\t\t\tif (baseTexture->overwriteInfo.hasRelativeLodBias)\n\t\t\t\tiLodBias += baseTexture->overwriteInfo.relativeLodBias;\n\t\t\t// apply absolute lod bias from graphic pack\n\t\t\tif (baseTexture->overwriteInfo.hasLodBias)\n\t\t\t\tiLodBias = baseTexture->overwriteInfo.lodBias;\n\n\t\t\tauto filterMip = samplerWords->WORD0.get_MIP_FILTER();\n\t\t\tif (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::NONE)\n\t\t\t{\n\t\t\t\tsamplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;\n\t\t\t\tsamplerInfo.minLod = 0;\n\t\t\t\tsamplerInfo.maxLod = 0.25f;\n\t\t\t}\n\t\t\telse if (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::POINT)\n\t\t\t{\n\t\t\t\tsamplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;\n\t\t\t\tsamplerInfo.minLod = (float)iMinLOD / 64.0f;\n\t\t\t\tsamplerInfo.maxLod = (float)iMaxLOD / 64.0f;\n\t\t\t}\n\t\t\telse if (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::LINEAR)\n\t\t\t{\n\t\t\t\tsamplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n\t\t\t\tsamplerInfo.minLod = (float)iMinLOD / 64.0f;\n\t\t\t\tsamplerInfo.maxLod = (float)iMaxLOD / 64.0f;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// fallback for invalid constants\n\t\t\t\tsamplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n\t\t\t\tsamplerInfo.minLod = (float)iMinLOD / 64.0f;\n\t\t\t\tsamplerInfo.maxLod = (float)iMaxLOD / 64.0f;\n\t\t\t}\n\n\t\t\tauto filterMin = samplerWords->WORD0.get_XY_MIN_FILTER();\n\t\t\tcemu_assert_debug(filterMin != Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::BICUBIC); // todo\n\t\t\tsamplerInfo.minFilter = (filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::POINT || filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::ANISO_POINT) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;\n\n\t\t\tauto filterMag = samplerWords->WORD0.get_XY_MAG_FILTER();\n\t\t\tsamplerInfo.magFilter = (filterMag == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::POINT || filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::ANISO_POINT) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;\n\n\t\t\tauto filterZ = samplerWords->WORD0.get_Z_FILTER();\n\t\t\t// todo: z-filter for texture array samplers is customizable for GPU7 but OpenGL/Vulkan doesn't expose this functionality?\n\n\t\t\tstatic const VkSamplerAddressMode s_vkClampTable[] = {\n\t\t\t\tVK_SAMPLER_ADDRESS_MODE_REPEAT, // WRAP\n\t\t\t\tVK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, // MIRROR\n\t\t\t\tVK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // CLAMP_LAST_TEXEL\n\t\t\t\tVK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE, // MIRROR_ONCE_LAST_TEXEL\n\t\t\t\tVK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // unsupported HALF_BORDER\n\t\t\t\tVK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, // unsupported MIRROR_ONCE_HALF_BORDER\n\t\t\t\tVK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER, // CLAMP_BORDER\n\t\t\t\tVK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER // MIRROR_ONCE_BORDER\n\t\t\t};\n\n\t\t\tauto clampX = samplerWords->WORD0.get_CLAMP_X();\n\t\t\tauto clampY = samplerWords->WORD0.get_CLAMP_Y();\n\t\t\tauto clampZ = samplerWords->WORD0.get_CLAMP_Z();\n\n\t\t\tsamplerInfo.addressModeU = s_vkClampTable[(size_t)clampX];\n\t\t\tsamplerInfo.addressModeV = s_vkClampTable[(size_t)clampY];\n\t\t\tsamplerInfo.addressModeW = s_vkClampTable[(size_t)clampZ];\n\n\t\t\tauto maxAniso = samplerWords->WORD0.get_MAX_ANISO_RATIO();\n\n\t\t\tif (baseTexture->overwriteInfo.anisotropicLevel >= 0)\n\t\t\t\tmaxAniso = baseTexture->overwriteInfo.anisotropicLevel;\n\n\t\t\tif (maxAniso > 0)\n\t\t\t{\n\t\t\t\tsamplerInfo.anisotropyEnable = VK_TRUE;\n\t\t\t\tsamplerInfo.maxAnisotropy = (float)(1 << maxAniso);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsamplerInfo.anisotropyEnable = VK_FALSE;\n\t\t\t\tsamplerInfo.maxAnisotropy = 1.0f;\n\t\t\t}\n\n\t\t\tsamplerInfo.mipLodBias = (float)iLodBias / 64.0f;\n\n\t\t\t// depth compare\n\t\t\tuint8 depthCompareMode = shader->textureUsesDepthCompare[relative_textureUnit] ? 1 : 0;\n\t\t\tstatic const VkCompareOp s_vkCompareOps[]\n\t\t\t{\n\t\t\t\tVK_COMPARE_OP_NEVER,\n\t\t\t\tVK_COMPARE_OP_LESS,\n\t\t\t\tVK_COMPARE_OP_EQUAL,\n\t\t\t\tVK_COMPARE_OP_LESS_OR_EQUAL,\n\t\t\t\tVK_COMPARE_OP_GREATER,\n\t\t\t\tVK_COMPARE_OP_NOT_EQUAL,\n\t\t\t\tVK_COMPARE_OP_GREATER_OR_EQUAL,\n\t\t\t\tVK_COMPARE_OP_ALWAYS,\n\t\t\t};\n\t\t\tif (depthCompareMode == 1)\n\t\t\t{\n\t\t\t\tsamplerInfo.compareEnable = VK_TRUE;\n\t\t\t\tsamplerInfo.compareOp = s_vkCompareOps[(size_t)samplerWords->WORD0.get_DEPTH_COMPARE_FUNCTION()];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsamplerInfo.compareEnable = VK_FALSE;\n\t\t\t}\n\n\t\t\t// border\n\t\t\tauto borderType = samplerWords->WORD0.get_BORDER_COLOR_TYPE();\n\n\t\t\tif (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::TRANSPARENT_BLACK)\n\t\t\t\tsamplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;\n\t\t\telse if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::OPAQUE_BLACK)\n\t\t\t\tsamplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;\n\t\t\telse if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::OPAQUE_WHITE)\n\t\t\t\tsamplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (this->m_featureControl.deviceExtensions.custom_border_color_without_format)\n\t\t\t\t{\n\t\t\t\t\tsamplerCustomBorderColor.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT;\n\t\t\t\t\tsamplerCustomBorderColor.format = VK_FORMAT_UNDEFINED;\n\n\t\t\t\t\t_LatteRegisterSetSamplerBorderColor* borderColorReg;\n\t\t\t\t\tif (shader->shaderType == LatteConst::ShaderType::Vertex)\n\t\t\t\t\t\tborderColorReg = LatteGPUState.contextNew.TD_VS_SAMPLER_BORDER_COLOR + stageSamplerIndex;\n\t\t\t\t\telse if (shader->shaderType == LatteConst::ShaderType::Pixel)\n\t\t\t\t\t\tborderColorReg = LatteGPUState.contextNew.TD_PS_SAMPLER_BORDER_COLOR + stageSamplerIndex;\n\t\t\t\t\telse // geometry\n\t\t\t\t\t\tborderColorReg = LatteGPUState.contextNew.TD_GS_SAMPLER_BORDER_COLOR + stageSamplerIndex;\n\t\t\t\t\tsamplerCustomBorderColor.customBorderColor.float32[0] = borderColorReg->red.get_channelValue();\n\t\t\t\t\tsamplerCustomBorderColor.customBorderColor.float32[1] = borderColorReg->green.get_channelValue();\n\t\t\t\t\tsamplerCustomBorderColor.customBorderColor.float32[2] = borderColorReg->blue.get_channelValue();\n\t\t\t\t\tsamplerCustomBorderColor.customBorderColor.float32[3] = borderColorReg->alpha.get_channelValue();\n\n\t\t\t\t\tsamplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT;\n\t\t\t\t\tsamplerInfo.pNext = &samplerCustomBorderColor;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// default to transparent black if custom border color is not supported\n\t\t\t\t\tsamplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tVKRObjectSampler* samplerObj = VKRObjectSampler::GetOrCreateSampler(&samplerInfo);\n\t\tvkObjDS->addRef(samplerObj);\n\t\tinfo.sampler = samplerObj->GetSampler();\n\t\ttextureArray.emplace_back(info);\n\t}\n\n\tif (textureCount > 0)\n\t{\n\t\tfor (sint32 i = 0; i < textureCount; i++)\n\t\t{\n\t\t\tVkWriteDescriptorSet write_descriptor{};\n\t\t\twrite_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n\t\t\twrite_descriptor.dstSet = result;\n\t\t\twrite_descriptor.dstBinding = shader->resourceMapping.getTextureBaseBindingPoint() + i;\n\t\t\twrite_descriptor.dstArrayElement = 0;\n\t\t\twrite_descriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\t\t\twrite_descriptor.descriptorCount = 1;\n\t\t\twrite_descriptor.pImageInfo = textureArray.data() + i;\n\t\t\tdescriptorWrites.emplace_back(write_descriptor);\n\t\t\tperformanceMonitor.vk.numDescriptorSamplerTextures.increment();\n\t\t\tdsInfo->statsNumSamplerTextures++;\n\t\t}\n\t}\n\n\t// descriptor for uniform vars (as buffer)\n\n\tVkDescriptorBufferInfo uniformVarsBufferInfo{};\n\n\tif (shader->resourceMapping.uniformVarsBufferBindingPoint >= 0)\n\t{\n\t\tuniformVarsBufferInfo.buffer = m_uniformVarBuffer;\n\t\tuniformVarsBufferInfo.offset = 0; // fixed offset is always zero since we only use dynamic offsets\n\t\tuniformVarsBufferInfo.range = shader->uniform.uniformRangeSize;\n\n\t\tVkWriteDescriptorSet write_descriptor{};\n\t\twrite_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n\t\twrite_descriptor.dstSet = result;\n\t\twrite_descriptor.dstBinding = shader->resourceMapping.uniformVarsBufferBindingPoint;\n\t\twrite_descriptor.dstArrayElement = 0;\n\t\twrite_descriptor.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;\n\t\twrite_descriptor.descriptorCount = 1;\n\t\twrite_descriptor.pBufferInfo = &uniformVarsBufferInfo;\n\t\tdescriptorWrites.emplace_back(write_descriptor);\n\t\tperformanceMonitor.vk.numDescriptorDynUniformBuffers.increment();\n\t\tdsInfo->statsNumDynUniformBuffers++;\n\t}\n\n\t// descriptor for uniform buffers\n\n\tVkDescriptorBufferInfo uniformBufferInfo{};\n\tuniformBufferInfo.buffer = m_useHostMemoryForCache ? m_importedMem : m_bufferCache;\n\tuniformBufferInfo.offset = 0; // fixed offset is always zero since we only use dynamic offsets\n\n\tif (m_vendor == GfxVendor::AMD)\n\t{\n\t\t// on AMD we enable robust buffer access and map the remaining range of the buffer\n\t\tuniformBufferInfo.range = VK_WHOLE_SIZE;\n\t}\n\telse\n\t{\n\t\t// on other vendors (which may not allow large range values) we disable robust buffer access and use a fixed size\n\t\t// update: starting with their Vulkan 1.2 drivers Nvidia now also prevents out-of-bounds access. Unlike on AMD, we can't use VK_WHOLE_SIZE due to 64KB size limit of uniforms\n\t\t// as a workaround we set the size to the allowed maximum. A proper solution would be to use SSBOs for large uniforms / uniforms with unknown size?\n\t\tuniformBufferInfo.range = 1024 * 16 * 4; // XCX\n\t}\n\n\tfor (sint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)\n\t{\n\t\tif (shader->resourceMapping.uniformBuffersBindingPoint[i] >= 0)\n\t\t{\n\t\t\tVkWriteDescriptorSet write_descriptor{};\n\t\t\twrite_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n\t\t\twrite_descriptor.dstSet = result;\n\t\t\twrite_descriptor.dstBinding = shader->resourceMapping.uniformBuffersBindingPoint[i];\n\t\t\twrite_descriptor.dstArrayElement = 0;\n\t\t\twrite_descriptor.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;\n\t\t\twrite_descriptor.descriptorCount = 1;\n\t\t\twrite_descriptor.pBufferInfo = &uniformBufferInfo;\n\t\t\tdescriptorWrites.emplace_back(write_descriptor);\n\t\t\tperformanceMonitor.vk.numDescriptorDynUniformBuffers.increment();\n\t\t\tdsInfo->statsNumDynUniformBuffers++;\n\t\t}\n\t}\n\n\n\tVkDescriptorBufferInfo tfStorageBufferInfo{};\n\n\tif (shader->resourceMapping.tfStorageBindingPoint >= 0)\n\t{\n\t\ttfStorageBufferInfo.buffer = m_xfbRingBuffer;\n\t\ttfStorageBufferInfo.offset = 0; // offset is calculated in shader\n\t\ttfStorageBufferInfo.range = VK_WHOLE_SIZE;\n\n\t\tVkWriteDescriptorSet write_descriptor{};\n\t\twrite_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n\t\twrite_descriptor.dstSet = result;\n\t\twrite_descriptor.dstBinding = shader->resourceMapping.tfStorageBindingPoint;\n\t\twrite_descriptor.dstArrayElement = 0;\n\t\twrite_descriptor.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;\n\t\twrite_descriptor.descriptorCount = 1;\n\t\twrite_descriptor.pBufferInfo = &tfStorageBufferInfo;\n\t\tdescriptorWrites.emplace_back(write_descriptor);\n\t\tperformanceMonitor.vk.numDescriptorStorageBuffers.increment();\n\t\tdsInfo->statsNumStorageBuffers++;\n\t}\n\n\tif (!descriptorWrites.empty())\n\t\tvkUpdateDescriptorSets(m_logicalDevice, (uint32)descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);\n\n\tswitch (shader->shaderType)\n\t{\n\tcase LatteConst::ShaderType::Vertex:\n\t{\n\t\tpipeline_info->vertex_ds_cache[stateHash] = dsInfo;\n\t\tbreak;\n\t}\n\tcase LatteConst::ShaderType::Pixel:\n\t{\n\t\tpipeline_info->pixel_ds_cache[stateHash] = dsInfo;\n\t\tbreak;\n\t}\n\tcase LatteConst::ShaderType::Geometry:\n\t{\n\t\tpipeline_info->geometry_ds_cache[stateHash] = dsInfo;\n\t\tbreak;\n\t}\n\tdefault:\n\t\tUNREACHABLE;\n\t}\n\n\treturn dsInfo;\n}\n\nvoid VulkanRenderer::sync_inputTexturesChanged()\n{\n\tbool writeFlushRequired = false;\n\n\tif (m_state.activeVertexDS)\n\t{\n\t\tfor (auto& tex : m_state.activeVertexDS->list_fboCandidates)\n\t\t{\n\t\t\ttex->m_vkFlushIndex_read = m_state.currentFlushIndex;\n\t\t\tif (tex->m_vkFlushIndex_write == m_state.currentFlushIndex)\n\t\t\t\twriteFlushRequired = true;\n\t\t}\n\t}\n\tif (m_state.activeGeometryDS)\n\t{\n\t\tfor (auto& tex : m_state.activeGeometryDS->list_fboCandidates)\n\t\t{\n\t\t\ttex->m_vkFlushIndex_read = m_state.currentFlushIndex;\n\t\t\tif (tex->m_vkFlushIndex_write == m_state.currentFlushIndex)\n\t\t\t\twriteFlushRequired = true;\n\t\t}\n\t}\n\tif (m_state.activePixelDS)\n\t{\n\t\tfor (auto& tex : m_state.activePixelDS->list_fboCandidates)\n\t\t{\n\t\t\ttex->m_vkFlushIndex_read = m_state.currentFlushIndex;\n\t\t\tif (tex->m_vkFlushIndex_write == m_state.currentFlushIndex)\n\t\t\t\twriteFlushRequired = true;\n\t\t}\n\t}\n\t// barrier here\n\tif (writeFlushRequired)\n\t{\n\t\tVkMemoryBarrier memoryBarrier{};\n\t\tmemoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;\n\t\tmemoryBarrier.srcAccessMask = 0;\n\t\tmemoryBarrier.dstAccessMask = 0;\n\n\t\tVkPipelineStageFlags srcStage = 0;\n\t\tVkPipelineStageFlags dstStage = 0;\n\n\t\t// src\n\t\tsrcStage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n\t\tmemoryBarrier.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n\n\t\tsrcStage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;\n\t\tmemoryBarrier.srcAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;\n\n\t\t// dst\n\t\tdstStage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;\n\t\tmemoryBarrier.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;\n\n\t\tdstStage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;\n\t\tmemoryBarrier.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;\n\n\t\tvkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStage, dstStage, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);\n\n\t\tperformanceMonitor.vk.numDrawBarriersPerFrame.increment();\n\n\t\tm_state.currentFlushIndex++;\n\t}\n}\n\nvoid VulkanRenderer::sync_RenderPassLoadTextures(CachedFBOVk* fboVk)\n{\n\tbool readFlushRequired = false;\n\t// always called after draw_inputTexturesChanged()\n\tfor (auto& tex : fboVk->GetTextures())\n\t{\n\t\tLatteTextureVk* texVk = (LatteTextureVk*)tex;\n\t\t// write-before-write\n\t\tif (texVk->m_vkFlushIndex_write == m_state.currentFlushIndex)\n\t\t\treadFlushRequired = true;\n\n\n\t\ttexVk->m_vkFlushIndex_write = m_state.currentFlushIndex;\n\t\t// todo - also check for write-before-write ?\n\t\tif (texVk->m_vkFlushIndex_read == m_state.currentFlushIndex)\n\t\t\treadFlushRequired = true;\n\t}\n\t// barrier here\n\tif (readFlushRequired)\n\t{\n\t\tVkMemoryBarrier memoryBarrier{};\n\t\tmemoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;\n\t\tmemoryBarrier.srcAccessMask = 0;\n\t\tmemoryBarrier.dstAccessMask = 0;\n\n\t\tVkPipelineStageFlags srcStage = 0;\n\t\tVkPipelineStageFlags dstStage = 0;\n\n\t\t// src\n\t\tsrcStage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n\t\tmemoryBarrier.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n\n\t\tsrcStage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;\n\t\tmemoryBarrier.srcAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;\n\n\t\t// dst\n\t\tdstStage |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;\n\t\tmemoryBarrier.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;\n\n\t\tdstStage |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;\n\t\tmemoryBarrier.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;\n\n\t\tvkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStage, dstStage, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);\n\n\t\tperformanceMonitor.vk.numDrawBarriersPerFrame.increment();\n\n\t\tm_state.currentFlushIndex++;\n\t}\n}\n\nvoid VulkanRenderer::sync_RenderPassStoreTextures(CachedFBOVk* fboVk)\n{\n\tuint32 flushIndex = m_state.currentFlushIndex;\n\tfor (auto& tex : fboVk->GetTextures())\n\t{\n\t\tLatteTextureVk* texVk = (LatteTextureVk*)tex;\n\t\ttexVk->m_vkFlushIndex_write = flushIndex;\n\t}\n}\n\nvoid VulkanRenderer::draw_prepareDescriptorSets(PipelineInfo* pipeline_info, VkDescriptorSetInfo*& vertexDS, VkDescriptorSetInfo*& pixelDS, VkDescriptorSetInfo*& geometryDS)\n{\n\tconst auto vertexShader = LatteSHRC_GetActiveVertexShader();\n\tconst auto geometryShader = LatteSHRC_GetActiveGeometryShader();\n\tconst auto pixelShader = LatteSHRC_GetActivePixelShader();\n\n\tauto prepareShaderDescriptors = [this, &pipeline_info](LatteDecompilerShader* shader) -> VkDescriptorSetInfo* {\n\t\tif (!shader)\n\t\t\treturn nullptr;\n\t\tauto descriptorSetInfo = draw_getOrCreateDescriptorSet(pipeline_info, shader);\n\t\tdescriptorSetInfo->m_vkObjDescriptorSet->flagForCurrentCommandBuffer();\n\t\treturn descriptorSetInfo;\n\t};\n\n\tvertexDS = prepareShaderDescriptors(vertexShader);\n\tpixelDS = prepareShaderDescriptors(pixelShader);\n\tgeometryDS = prepareShaderDescriptors(geometryShader);\n}\n\nvoid VulkanRenderer::draw_updateVkBlendConstants()\n{\n\tuint32* blendColorConstant = LatteGPUState.contextRegister + Latte::REGADDR::CB_BLEND_RED;\n\tvkCmdSetBlendConstants(m_state.currentCommandBuffer, (const float*)blendColorConstant);\n}\n\nvoid VulkanRenderer::draw_updateDepthBias(bool forceUpdate)\n{\n\tuint32 frontScaleU32 = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_SCALE.getRawValue();\n\tuint32 frontOffsetU32 = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_OFFSET.getRawValue();\n\tuint32 offsetClampU32 = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_CLAMP.getRawValue();\n\n\tif (forceUpdate == false &&\n\t\tm_state.prevPolygonFrontScaleU32 == frontScaleU32 &&\n\t\tm_state.prevPolygonFrontOffsetU32 == frontOffsetU32 &&\n\t\tm_state.prevPolygonFrontClampU32 == offsetClampU32)\n\t\treturn;\n\n\tm_state.prevPolygonFrontScaleU32 = frontScaleU32;\n\tm_state.prevPolygonFrontOffsetU32 = frontOffsetU32;\n\tm_state.prevPolygonFrontClampU32 = offsetClampU32;\n\n\tfloat frontScale = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_SCALE.get_SCALE();\n\tfloat frontOffset = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_FRONT_OFFSET.get_OFFSET();\n\tfloat offsetClamp = LatteGPUState.contextNew.PA_SU_POLY_OFFSET_CLAMP.get_CLAMP();\n\n\tfrontScale /= 16.0f;\n\n\tvkCmdSetDepthBias(m_state.currentCommandBuffer, frontOffset, offsetClamp, frontScale);\n}\n\nbool s_syncOnNextDraw = false;\n\nvoid VulkanRenderer::draw_setRenderPass()\n{\n\tCachedFBOVk* fboVk = m_state.activeFBO;\n\n\t// update self-dependency flag\n\tif (m_state.descriptorSetsChanged || m_state.activeRenderpassFBO != fboVk)\n\t{\n\t\tm_state.hasRenderSelfDependency = fboVk->CheckForCollision(m_state.activeVertexDS, m_state.activeGeometryDS, m_state.activePixelDS);\n\t}\n\n\tauto vkObjRenderPass = fboVk->GetRenderPassObj();\n\tauto vkObjFramebuffer = fboVk->GetFramebufferObj();\n\n\tbool overridePassReuse = m_state.hasRenderSelfDependency && (GetConfig().vk_accurate_barriers || m_state.activePipelineInfo->neverSkipAccurateBarrier);\n\n\tif (!overridePassReuse && m_state.activeRenderpassFBO == fboVk)\n\t{\n\t\tif (m_state.descriptorSetsChanged)\n\t\t\tsync_inputTexturesChanged();\n\t\treturn;\n\t}\n\tdraw_endRenderPass();\n\tif (m_state.descriptorSetsChanged)\n\t\tsync_inputTexturesChanged();\n\n\t// assume that FBO changed, update self-dependency state\n\tm_state.hasRenderSelfDependency = fboVk->CheckForCollision(m_state.activeVertexDS, m_state.activeGeometryDS, m_state.activePixelDS);\n\n\tsync_RenderPassLoadTextures(fboVk);\n\n\tif (m_featureControl.deviceExtensions.dynamic_rendering)\n\t{\n\t\tvkCmdBeginRenderingKHR(m_state.currentCommandBuffer, fboVk->GetRenderingInfo());\n\t}\n\telse\n\t{\n\t\tVkRenderPass renderPass = vkObjRenderPass->m_renderPass;\n\t\tVkFramebuffer framebuffer = vkObjFramebuffer->m_frameBuffer;\n\t\tVkExtent2D extend = fboVk->GetExtend();\n\n\t\tVkRenderPassBeginInfo renderPassInfo{};\n\t\trenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n\t\trenderPassInfo.renderPass = renderPass;\n\t\trenderPassInfo.framebuffer = framebuffer;\n\t\trenderPassInfo.renderArea.offset = { 0, 0 };\n\t\trenderPassInfo.renderArea.extent = extend;\n\t\trenderPassInfo.clearValueCount = 0;\n\t\tvkCmdBeginRenderPass(m_state.currentCommandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);\n\t}\n\n\tm_state.activeRenderpassFBO = fboVk;\n\n\tvkObjRenderPass->flagForCurrentCommandBuffer();\n\tvkObjFramebuffer->flagForCurrentCommandBuffer();\n\n\tperformanceMonitor.vk.numBeginRenderpassPerFrame.increment();\n}\n\nvoid VulkanRenderer::draw_endRenderPass()\n{\n\tif (!m_state.activeRenderpassFBO)\n\t\treturn;\n\tif (m_featureControl.deviceExtensions.dynamic_rendering)\n\t\tvkCmdEndRenderingKHR(m_state.currentCommandBuffer);\n\telse\n\t\tvkCmdEndRenderPass(m_state.currentCommandBuffer);\n\tsync_RenderPassStoreTextures(m_state.activeRenderpassFBO);\n\tm_state.activeRenderpassFBO = nullptr;\n}\n\nvoid LatteDraw_handleSpecialState8_clearAsDepth();\n\n// transfer depth buffer data to color buffer\nvoid VulkanRenderer::draw_handleSpecialState5()\n{\n\tLatteMRT::UpdateCurrentFBO();\n\tLatteRenderTarget_updateViewport();\n\n\tLatteTextureView* colorBuffer = LatteMRT::GetColorAttachment(0);\n\tLatteTextureView* depthBuffer = LatteMRT::GetDepthAttachment();\n\n\tsint32 vpWidth, vpHeight;\n\tLatteMRT::GetVirtualViewportDimensions(vpWidth, vpHeight);\n\n\tsurfaceCopy_copySurfaceWithFormatConversion(\n\t\tdepthBuffer->baseTexture, depthBuffer->firstMip, depthBuffer->firstSlice,\n\t\tcolorBuffer->baseTexture, colorBuffer->firstMip, colorBuffer->firstSlice,\n\t\tvpWidth, vpHeight);\n}\n\nvoid VulkanRenderer::draw_beginSequence()\n{\n\tm_state.drawSequenceSkip = false;\n\n\tbool streamoutEnable = LatteGPUState.contextRegister[mmVGT_STRMOUT_EN] != 0;\n\n\t// update shader state\n\tLatteSHRC_UpdateActiveShaders();\n\tif (LatteGPUState.activeShaderHasError)\n\t{\n\t\tcemuLog_logDebugOnce(LogType::Force, \"Skipping drawcalls due to shader error\");\n\t\tm_state.drawSequenceSkip = true;\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\n\t// update render target and texture state\n\tLatteGPUState.requiresTextureBarrier = false;\n\twhile (true)\n\t{\n\t\tLatteGPUState.repeatTextureInitialization = false;\n\t\tif (!LatteMRT::UpdateCurrentFBO())\n\t\t{\n\t\t\tdebug_printf(\"Rendertarget invalid\\n\");\n\t\t\tm_state.drawSequenceSkip = true;\n\t\t\treturn; // no render target\n\t\t}\n\n\t\tif (!hasValidFramebufferAttached && !streamoutEnable)\n\t\t{\n\t\t\tdebug_printf(\"Drawcall with no color buffer or depth buffer attached\\n\");\n\t\t\tm_state.drawSequenceSkip = true;\n\t\t\treturn; // no render target\n\t\t}\n\t\tLatteTexture_updateTextures();\n\t\tif (!LatteGPUState.repeatTextureInitialization)\n\t\t\tbreak;\n\t}\n\n\t// apply render target\n\tLatteMRT::ApplyCurrentState();\n\n\t// viewport and scissor box\n\tLatteRenderTarget_updateViewport();\n\tLatteRenderTarget_updateScissorBox();\n\n\t// check for conditions which would turn the drawcalls into no-ops\n\tbool rasterizerEnable = LatteGPUState.contextNew.PA_CL_CLIP_CNTL.get_DX_RASTERIZATION_KILL() == false;\n\n\t// GX2SetSpecialState(0, true) enables DX_RASTERIZATION_KILL, but still expects depth writes to happen? -> Research which stages are disabled by DX_RASTERIZATION_KILL exactly\n\t// for now we use a workaround:\n\tif (!LatteGPUState.contextNew.PA_CL_VTE_CNTL.get_VPORT_X_OFFSET_ENA())\n\t\trasterizerEnable = true;\n\n\tif (rasterizerEnable == false && streamoutEnable == false)\n\t\tm_state.drawSequenceSkip = true;\n}\n\nvoid VulkanRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst)\n{\n\tif (m_state.drawSequenceSkip)\n\t{\n\t\tLatteGPUState.drawCallCounter++;\n\t\treturn;\n\t}\n\n\t// fast clear color as depth\n\tif (LatteGPUState.contextNew.GetSpecialStateValues()[8] != 0)\n\t{\n\t\tLatteDraw_handleSpecialState8_clearAsDepth();\n\t\tLatteGPUState.drawCallCounter++;\n\t\treturn;\n\t}\n\telse if (LatteGPUState.contextNew.GetSpecialStateValues()[5] != 0)\n\t{\n\t\tdraw_handleSpecialState5();\n\t\tLatteGPUState.drawCallCounter++;\n\t\treturn;\n\t}\n\n\t// prepare streamout\n\tm_streamoutState.verticesPerInstance = count;\n\tLatteStreamout_PrepareDrawcall(count, instanceCount);\n\n\t// update uniform vars\n\tLatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();\n\tLatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();\n\tLatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader();\n\n\tif (vertexShader)\n\t\tuniformData_updateUniformVars(VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX, vertexShader);\n\tif (pixelShader)\n\t\tuniformData_updateUniformVars(VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT, pixelShader);\n\tif (geometryShader)\n\t\tuniformData_updateUniformVars(VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY, geometryShader);\n\t// store where the read pointer should go after command buffer execution\n\tm_cmdBufferUniformRingbufIndices[m_commandBufferIndex] = m_uniformVarBufferWriteIndex;\n\n\t// process index data\n\tconst LattePrimitiveMode primitiveMode = static_cast<LattePrimitiveMode>(LatteGPUState.contextRegister[mmVGT_PRIMITIVE_TYPE]);\n\n\tRenderer::INDEX_TYPE hostIndexType;\n\tuint32 hostIndexCount;\n\tuint32 indexMin = 0;\n\tuint32 indexMax = 0;\n\tRenderer::IndexAllocation indexAllocation;\n\tLatteIndices_decode(memory_getPointerFromVirtualOffset(indexDataMPTR), indexType, count, primitiveMode, indexMin, indexMax, hostIndexType, hostIndexCount, indexAllocation);\n\tVKRSynchronizedHeapAllocator::AllocatorReservation* indexReservation = (VKRSynchronizedHeapAllocator::AllocatorReservation*)indexAllocation.rendererInternal;\n\t// update index binding\n\tbool isPrevIndexData = false;\n\tif (hostIndexType != INDEX_TYPE::NONE)\n\t{\n\t\tuint32 indexBufferIndex = indexReservation->bufferIndex;\n\t\tuint32 indexBufferOffset = indexReservation->bufferOffset;\n\t\tif (m_state.activeIndexBufferOffset != indexBufferOffset || m_state.activeIndexBufferIndex != indexBufferIndex || m_state.activeIndexType != hostIndexType)\n\t\t{\n\t\t\tm_state.activeIndexType = hostIndexType;\n\t\t\tm_state.activeIndexBufferOffset = indexBufferOffset;\n\t\t\tm_state.activeIndexBufferIndex = indexBufferIndex;\n\t\t\tVkIndexType vkType;\n\t\t\tif (hostIndexType == INDEX_TYPE::U16)\n\t\t\t\tvkType = VK_INDEX_TYPE_UINT16;\n\t\t\telse if (hostIndexType == INDEX_TYPE::U32)\n\t\t\t\tvkType = VK_INDEX_TYPE_UINT32;\n\t\t\telse\n\t\t\t\tcemu_assert(false);\n\t\t\tvkCmdBindIndexBuffer(m_state.currentCommandBuffer, indexReservation->vkBuffer, indexBufferOffset, vkType);\n\t\t}\n\t\telse\n\t\t\tisPrevIndexData = true;\n\t}\n\n\tif (m_useHostMemoryForCache)\n\t{\n\t\t// direct memory access (Wii U memory space imported as a Vulkan buffer), update buffer bindings\n\t\tdraw_updateVertexBuffersDirectAccess();\n\t\tLatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();\n\t\tif (vertexShader)\n\t\t\tdraw_updateUniformBuffersDirectAccess(vertexShader, mmSQ_VTX_UNIFORM_BLOCK_START, LatteConst::ShaderType::Vertex);\n\t\tLatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader();\n\t\tif (geometryShader)\n\t\t\tdraw_updateUniformBuffersDirectAccess(geometryShader, mmSQ_GS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Geometry);\n\t\tLatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();\n\t\tif (pixelShader)\n\t\t\tdraw_updateUniformBuffersDirectAccess(pixelShader, mmSQ_PS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Pixel);\n\t}\n\telse\n\t{\n\t\t// synchronize vertex and uniform cache and update buffer bindings\n\t\tLatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount);\n\t}\n\n\tPipelineInfo* pipeline_info;\n\n\tif (!isFirst)\n\t{\n\t\tif (m_state.activePipelineInfo->minimalStateHash != draw_calculateMinimalGraphicsPipelineHash(vertexShader->compatibleFetchShader, LatteGPUState.contextNew))\n\t\t{\n\t\t\t// pipeline changed\n\t\t\tpipeline_info = draw_getOrCreateGraphicsPipeline(count);\n\t\t\tm_state.activePipelineInfo = pipeline_info;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpipeline_info = m_state.activePipelineInfo;\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tauto pipeline_info2 = draw_getOrCreateGraphicsPipeline(count);\n\t\t\tif (pipeline_info != pipeline_info2)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n#endif\n\t\t}\n\t}\n\telse\n\t{\n\t\tpipeline_info = draw_getOrCreateGraphicsPipeline(count);\n\t\tm_state.activePipelineInfo = pipeline_info;\n\t}\n\n\tauto vkObjPipeline = pipeline_info->m_vkrObjPipeline;\n\tif (vkObjPipeline->GetPipeline() == VK_NULL_HANDLE)\n\t{\n\t\t// invalid/uninitialized pipeline\n\t\tm_state.activeVertexDS = nullptr;\n\t\treturn;\n\t}\n\n\n\tVkDescriptorSetInfo *vertexDS = nullptr, *pixelDS = nullptr, *geometryDS = nullptr;\n\tif (!isFirst && m_state.activeVertexDS)\n\t{\n\t\tvertexDS = m_state.activeVertexDS;\n\t\tpixelDS = m_state.activePixelDS;\n\t\tgeometryDS = m_state.activeGeometryDS;\n\t\tm_state.descriptorSetsChanged = false;\n\t}\n\telse\n\t{\n\t\tdraw_prepareDescriptorSets(pipeline_info, vertexDS, pixelDS, geometryDS);\n\t\tm_state.activeVertexDS = vertexDS;\n\t\tm_state.activePixelDS = pixelDS;\n\t\tm_state.activeGeometryDS = geometryDS;\n\t\tm_state.descriptorSetsChanged = true;\n\t}\n\n\tdraw_setRenderPass();\n\n\tif (m_state.currentPipeline != vkObjPipeline->GetPipeline())\n\t{\n\t\tvkCmdBindPipeline(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkObjPipeline->GetPipeline());\n\t\tvkObjPipeline->flagForCurrentCommandBuffer();\n\t\tm_state.currentPipeline = vkObjPipeline->GetPipeline();\n\t\t// depth bias\n\t\tif (pipeline_info->usesDepthBias)\n\t\t\tdraw_updateDepthBias(true);\n\t}\n\telse\n\t{\n\t\tif (pipeline_info->usesDepthBias)\n\t\t\tdraw_updateDepthBias(false);\n\t}\n\n\t// update blend constants\n\tif (pipeline_info->usesBlendConstants)\n\t\tdraw_updateVkBlendConstants();\n\n\t// update descriptor sets\n\tuint32_t dynamicOffsets[17 * 2];\n\tif (vertexDS && pixelDS)\n\t{\n\t\t// update vertex and pixel descriptor set in a single call to vkCmdBindDescriptorSets\n\t\tsint32 numDynOffsetsVS;\n\t\tsint32 numDynOffsetsPS;\n\t\tdraw_prepareDynamicOffsetsForDescriptorSet(VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX, dynamicOffsets, numDynOffsetsVS,\n\t\t\tpipeline_info);\n\t\tdraw_prepareDynamicOffsetsForDescriptorSet(VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT, dynamicOffsets + numDynOffsetsVS, numDynOffsetsPS,\n\t\t\tpipeline_info);\n\n\t\tVkDescriptorSet dsArray[2];\n\t\tdsArray[0] = vertexDS->m_vkObjDescriptorSet->descriptorSet;\n\t\tdsArray[1] = pixelDS->m_vkObjDescriptorSet->descriptorSet;\n\n\t\tvkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n\t\t\tvkObjPipeline->m_pipelineLayout, 0, 2, dsArray, numDynOffsetsVS + numDynOffsetsPS,\n\t\t\tdynamicOffsets);\n\t}\n\telse if (vertexDS)\n\t{\n\t\tsint32 numDynOffsets;\n\t\tdraw_prepareDynamicOffsetsForDescriptorSet(VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX, dynamicOffsets, numDynOffsets,\n\t\t\tpipeline_info);\n\t\tvkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n\t\t\tvkObjPipeline->m_pipelineLayout, 0, 1, &vertexDS->m_vkObjDescriptorSet->descriptorSet, numDynOffsets,\n\t\t\tdynamicOffsets);\n\t}\n\telse if (pixelDS)\n\t{\n\t\tsint32 numDynOffsets;\n\t\tdraw_prepareDynamicOffsetsForDescriptorSet(VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT, dynamicOffsets, numDynOffsets,\n\t\t\tpipeline_info);\n\t\tvkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n\t\t\tvkObjPipeline->m_pipelineLayout, 1, 1, &pixelDS->m_vkObjDescriptorSet->descriptorSet, numDynOffsets,\n\t\t\tdynamicOffsets);\n\t}\n\tif (geometryDS)\n\t{\n\t\tsint32 numDynOffsets;\n\t\tdraw_prepareDynamicOffsetsForDescriptorSet(VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY, dynamicOffsets, numDynOffsets,\n\t\t\tpipeline_info);\n\t\tvkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n\t\t\tvkObjPipeline->m_pipelineLayout, 2, 1, &geometryDS->m_vkObjDescriptorSet->descriptorSet, numDynOffsets,\n\t\t\tdynamicOffsets);\n\t}\n\n\t// draw\n\tif (hostIndexType != INDEX_TYPE::NONE)\n\t\tvkCmdDrawIndexed(m_state.currentCommandBuffer, hostIndexCount, instanceCount, 0, baseVertex, baseInstance);\n\telse\n\t\tvkCmdDraw(m_state.currentCommandBuffer, count, instanceCount, baseVertex, baseInstance);\n\n\tLatteStreamout_FinishDrawcall(m_useHostMemoryForCache);\n\n\tLatteGPUState.drawCallCounter++;\n}\n\n// used in place of vertex/uniform caching when direct memory access is possible\nvoid VulkanRenderer::draw_updateVertexBuffersDirectAccess()\n{\n\tLatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader();\n\tif (!parsedFetchShader)\n\t\treturn;\n\tfor (auto& bufferGroup : parsedFetchShader->bufferGroups)\n\t{\n\t\tuint32 bufferIndex = bufferGroup.attributeBufferIndex;\n\t\tuint32 bufferBaseRegisterIndex = mmSQ_VTX_ATTRIBUTE_BLOCK_START + bufferIndex * 7;\n\t\tMPTR bufferAddress = LatteGPUState.contextRegister[bufferBaseRegisterIndex + 0];\n\t\tuint32 bufferSize = LatteGPUState.contextRegister[bufferBaseRegisterIndex + 1] + 1;\n\t\tuint32 bufferStride = (LatteGPUState.contextRegister[bufferBaseRegisterIndex + 2] >> 11) & 0xFFFF;\n\n\t\tif (bufferAddress == MPTR_NULL) [[unlikely]]\n\t\t{\n\t\t\tbufferAddress = 0x10000000;\n\t\t}\n\t\tif (m_state.currentVertexBinding[bufferIndex].offset == bufferAddress)\n\t\t\tcontinue;\n\t\tcemu_assert_debug(bufferAddress < 0x50000000);\n\t\tVkBuffer attrBuffer = m_importedMem;\n\t\tVkDeviceSize attrOffset = bufferAddress - m_importedMemBaseAddress;\n\t\tvkCmdBindVertexBuffers(m_state.currentCommandBuffer, bufferIndex, 1, &attrBuffer, &attrOffset);\n\t}\n}\n\nvoid VulkanRenderer::draw_updateUniformBuffersDirectAccess(LatteDecompilerShader* shader, const uint32 uniformBufferRegOffset, LatteConst::ShaderType shaderType)\n{\n\tif (shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK)\n\t{\n\t\tfor(const auto& buf : shader->list_quickBufferList)\n\t\t{\n\t\t\tsint32 i = buf.index;\n\t\t\tMPTR physicalAddr = LatteGPUState.contextRegister[uniformBufferRegOffset + i * 7 + 0];\n\t\t\tuint32 uniformSize = LatteGPUState.contextRegister[uniformBufferRegOffset + i * 7 + 1] + 1;\n\n\t\t\tif (physicalAddr == MPTR_NULL) [[unlikely]]\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tuniformSize = std::min<uint32>(uniformSize, buf.size);\n\n\t\t\tcemu_assert_debug(physicalAddr < 0x50000000);\n\n\t\t\tuint32 bufferIndex = i;\n\t\t\tcemu_assert_debug(bufferIndex < 16);\n\n\t\t\tswitch (shaderType)\n\t\t\t{\n\t\t\tcase LatteConst::ShaderType::Vertex:\n\t\t\t\tdynamicOffsetInfo.shaderUB[VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX].uniformBufferOffset[bufferIndex] = physicalAddr - m_importedMemBaseAddress;\n\t\t\t\tbreak;\n\t\t\tcase LatteConst::ShaderType::Geometry:\n\t\t\t\tdynamicOffsetInfo.shaderUB[VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY].uniformBufferOffset[bufferIndex] = physicalAddr - m_importedMemBaseAddress;\n\t\t\t\tbreak;\n\t\t\tcase LatteConst::ShaderType::Pixel:\n\t\t\t\tdynamicOffsetInfo.shaderUB[VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT].uniformBufferOffset[bufferIndex] = physicalAddr - m_importedMemBaseAddress;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tUNREACHABLE;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid VulkanRenderer::draw_endSequence()\n{\n\tLatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader();\n\t// post-drawcall logic\n\tif (pixelShader)\n\t\tLatteRenderTarget_trackUpdates();\n\tbool hasReadback = LatteTextureReadback_Update();\n\tm_recordedDrawcalls++;\n\tif (m_recordedDrawcalls >= m_submitThreshold || hasReadback)\n\t{\n\t\tSubmitCommandBuffer();\n\t}\n}\n\nvoid VulkanRenderer::debug_genericBarrier()\n{\n\tdraw_endRenderPass();\n\n\tVkMemoryBarrier memoryBarrier{};\n\tmemoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;\n\tmemoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT |\n\t\tVK_ACCESS_INDEX_READ_BIT |\n\t\tVK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |\n\t\tVK_ACCESS_UNIFORM_READ_BIT |\n\t\tVK_ACCESS_INPUT_ATTACHMENT_READ_BIT |\n\t\tVK_ACCESS_SHADER_READ_BIT |\n\t\tVK_ACCESS_SHADER_WRITE_BIT |\n\t\tVK_ACCESS_COLOR_ATTACHMENT_READ_BIT |\n\t\tVK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |\n\t\tVK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |\n\t\tVK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |\n\t\tVK_ACCESS_TRANSFER_READ_BIT |\n\t\tVK_ACCESS_TRANSFER_WRITE_BIT |\n\t\tVK_ACCESS_HOST_READ_BIT |\n\t\tVK_ACCESS_HOST_WRITE_BIT |\n\t\tVK_ACCESS_MEMORY_READ_BIT |\n\t\tVK_ACCESS_MEMORY_WRITE_BIT;\n\n\tmemoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT |\n\t\tVK_ACCESS_INDEX_READ_BIT |\n\t\tVK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |\n\t\tVK_ACCESS_UNIFORM_READ_BIT |\n\t\tVK_ACCESS_INPUT_ATTACHMENT_READ_BIT |\n\t\tVK_ACCESS_SHADER_READ_BIT |\n\t\tVK_ACCESS_SHADER_WRITE_BIT |\n\t\tVK_ACCESS_COLOR_ATTACHMENT_READ_BIT |\n\t\tVK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |\n\t\tVK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |\n\t\tVK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |\n\t\tVK_ACCESS_TRANSFER_READ_BIT |\n\t\tVK_ACCESS_TRANSFER_WRITE_BIT |\n\t\tVK_ACCESS_HOST_READ_BIT |\n\t\tVK_ACCESS_HOST_WRITE_BIT |\n\t\tVK_ACCESS_MEMORY_READ_BIT |\n\t\tVK_ACCESS_MEMORY_WRITE_BIT;\n\n\tvkCmdPipelineBarrier(m_state.currentCommandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n\nstruct CopyShaderPushConstantData_t\n{\n\tfloat vertexOffsets[4 * 2];\n\tsint32 srcTexelOffset[2];\n};\n\nstruct CopySurfacePipelineInfo\n{\n\ttemplate<typename T>\n\tstruct TexSliceMipMapping\n\t{\n\t\tTexSliceMipMapping(LatteTextureVk* texture) : m_texture(texture) {};\n\t\t~TexSliceMipMapping()\n\t\t{\n\t\t\t//delete vkObjPipeline;\n\t\t\t//delete vkObjRenderPass;\n\t\t\tfor (auto itr : m_array)\n\t\t\t{\n\t\t\t\tif (itr != nullptr)\n\t\t\t\t\tdelete itr;\n\t\t\t}\n\t\t}\n\n\t\tT* create(sint32 sliceIndex, sint32 mipIndex)\n\t\t{\n\t\t\tsint32 idx = m_texture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tif (idx >= m_array.size())\n\t\t\t\tm_array.resize(idx + 1);\n\t\t\tT* v = new T();\n\t\t\tm_array[idx] = v;\n\t\t\treturn v;\n\t\t}\n\n\t\tT* get(sint32 sliceIndex, sint32 mipIndex) const\n\t\t{\n\t\t\tsint32 idx = m_texture->GetSliceMipArrayIndex(sliceIndex, mipIndex);\n\t\t\tif (idx >= m_array.size())\n\t\t\t\treturn nullptr;\n\t\t\treturn m_array[idx];\n\t\t}\n\n\t\tTexSliceMipMapping(const TexSliceMipMapping&) = delete;\n\t\tTexSliceMipMapping& operator=(const TexSliceMipMapping&) = delete;\n\t\tTexSliceMipMapping(TexSliceMipMapping&& rhs)\n\t\t{\n\t\t\tm_texture = rhs.m_texture;\n\t\t\tm_array = std::move(rhs.m_array);\n\t\t}\n\n\t\tTexSliceMipMapping& operator=(TexSliceMipMapping&& rhs)\n\t\t{\n\t\t\tm_texture = rhs.m_texture;\n\t\t\tm_array = std::move(rhs.m_array);\n\t\t}\n\n\t\tLatteTextureVk* m_texture;\n\t\tstd::vector<T*> m_array;\n\t};\n\n\tstruct FramebufferValue\n\t{\n\t\tVKRObjectFramebuffer* vkObjFramebuffer;\n\t\tVKRObjectTextureView* vkObjImageView;\n\t};\n\n\tstruct DescriptorValue\n\t{\n\t\tVKRObjectDescriptorSet* vkObjDescriptorSet;\n\t\tVKRObjectTextureView* vkObjImageView;\n\t\t//VKRObjectSampler* vkObjSampler;\n\t};\n\n\tCopySurfacePipelineInfo() = default;\n\tCopySurfacePipelineInfo(VkDevice device) : m_device(device) {}\n\tCopySurfacePipelineInfo(const CopySurfacePipelineInfo& info) = delete;\n\t~CopySurfacePipelineInfo()\n\t{\n\t\tauto renderer = VulkanRenderer::GetInstance();\n\t\trenderer->ReleaseDestructibleObject(vkObjRenderPass);\n\t\trenderer->ReleaseDestructibleObject(vkObjPipeline);\n\n\t\tfor(auto& i : map_framebuffers)\n\t\t{\n\t\t\tfor(auto& fb : i.second.m_array)\n\t\t\t{\n\t\t\t\trenderer->ReleaseDestructibleObject(fb->vkObjFramebuffer);\n\t\t\t\trenderer->ReleaseDestructibleObject(fb->vkObjImageView);\n\t\t\t}\n\t\t}\n\n\t\tfor(auto& i : map_descriptors)\n\t\t{\n\t\t\tfor(auto& descriptor : i.second.m_array)\n\t\t\t{\n\t\t\t\trenderer->ReleaseDestructibleObject(descriptor->vkObjImageView);\n\t\t\t\trenderer->ReleaseDestructibleObject(descriptor->vkObjDescriptorSet);\n\t\t\t}\n\t\t}\n\t}\n\n\tVkDevice m_device = nullptr;\n\n\tVKRObjectPipeline* vkObjPipeline{};\n\tVKRObjectRenderPass* vkObjRenderPass{};\n\n\t// map of framebuffers used with this pipeline\n\tstd::unordered_map<LatteTextureVk*, TexSliceMipMapping<FramebufferValue>> map_framebuffers;\n\n\t// map of descriptor sets used with this pipeline\n\tstd::unordered_map<LatteTextureVk*, TexSliceMipMapping<DescriptorValue>> map_descriptors;\n};\n\nstruct VkCopySurfaceState_t\n{\n\tLatteTextureVk* sourceTexture;\n\tsint32 srcMip;\n\tsint32 srcSlice;\n\tLatteTextureVk* destinationTexture;\n\tsint32 dstMip;\n\tsint32 dstSlice;\n\tsint32 width;\n\tsint32 height;\n};\n\nextern std::atomic_int g_compiling_pipelines;\n\nuint64 VulkanRenderer::copySurface_getPipelineStateHash(VkCopySurfaceState_t& state)\n{\n\tuint64 h = 0;\n\n\th += (uintptr_t)state.destinationTexture->GetFormat();\n\th = std::rotr<uint64>(h, 7);\n\n\th += state.sourceTexture->isDepth ? 0x1111ull : 0;\n\th = std::rotr<uint64>(h, 7);\n\th += state.destinationTexture->isDepth ? 0x1112ull : 0;\n\th = std::rotr<uint64>(h, 7);\n\n\treturn h;\n}\n\nCopySurfacePipelineInfo* VulkanRenderer::copySurface_getCachedPipeline(VkCopySurfaceState_t& state)\n{\n\tconst uint64 stateHash = copySurface_getPipelineStateHash(state);\n\n\tconst auto it = m_copySurfacePipelineCache.find(stateHash);\n\tif (it == m_copySurfacePipelineCache.cend())\n\t\treturn nullptr;\n\treturn it->second;\n}\n\nRendererShaderVk* _vkGenSurfaceCopyShader_vs()\n{\n\tconst char* vsShaderSrc = \n\t\t\"#version 450\\r\\n\"\n\t\t\"layout(location = 0) out ivec2 passSrcTexelOffset;\\r\\n\"\n\t\t\"layout(push_constant) uniform pushConstants {\\r\\n\"\n\t\t\"vec2 vertexOffsets[4];\\r\\n\"\n\t\t\"ivec2 srcTexelOffset;\\r\\n\"\n\t\t\"}uf_pushConstants;\\r\\n\"\n\t\t\"\\r\\n\"\n\t\t\"void main(){\\r\\n\"\n\t\t//\"ivec2 tUV;\\r\\n\"\n\t\t\"vec2 tPOS;\\r\\n\"\n\t\t\"switch(gl_VertexIndex)\"\n\t\t\"{\\r\\n\"\n\t\t// AMD driver has issues with indexed push constant access, therefore use this workaround\n\t\t\"case 0: tPOS = uf_pushConstants.vertexOffsets[0].xy; break;\\r\\n\"\n\t\t\"case 1: tPOS = uf_pushConstants.vertexOffsets[1].xy; break;\\r\\n\"\n\t\t\"case 2: tPOS = uf_pushConstants.vertexOffsets[3].xy; break;\\r\\n\"\n\t\t\"case 3: tPOS = uf_pushConstants.vertexOffsets[0].xy; break;\\r\\n\"\n\t\t\"case 4: tPOS = uf_pushConstants.vertexOffsets[2].xy; break;\\r\\n\"\n\t\t\"case 5: tPOS = uf_pushConstants.vertexOffsets[3].xy; break;\\r\\n\"\n\t\t\"}\"\n\t\t\"passSrcTexelOffset = uf_pushConstants.srcTexelOffset;\\r\\n\"\n\t\t\"gl_Position = vec4(tPOS, 0, 1.0);\\r\\n\"\n\t\t\"}\\r\\n\";\n\n\tstd::string shaderStr(vsShaderSrc);\n\tauto vkShader = new RendererShaderVk(RendererShader::ShaderType::kVertex, 0, 0, false, false, shaderStr);\n\tvkShader->PreponeCompilation(true);\n\treturn vkShader;\n}\n\nRendererShaderVk* _vkGenSurfaceCopyShader_ps_colorToDepth()\n{\n\tconst char* psShaderSrc = \"\"\n\t\t\"#version 450\\r\\n\"\n\t\t\"layout(location = 0) in flat ivec2 passSrcTexelOffset;\\r\\n\"\n\t\t\"layout(binding = 0) uniform sampler2D textureSrc;\\r\\n\"\n\t\t\"in vec4 gl_FragCoord;\\r\\n\"\n\t\t\"\\r\\n\"\n\t\t\"void main(){\\r\\n\"\n\t\t\"gl_FragDepth = texelFetch(textureSrc, passSrcTexelOffset + ivec2(gl_FragCoord.xy), 0).r;\\r\\n\"\n\t\t\"}\\r\\n\";\n\n\tstd::string shaderStr(psShaderSrc);\n\tauto vkShader = new RendererShaderVk(RendererShader::ShaderType::kFragment, 0, 0, false, false, shaderStr);\n\tvkShader->PreponeCompilation(true);\n\treturn vkShader;\n}\n\nRendererShaderVk* _vkGenSurfaceCopyShader_ps_depthToColor()\n{\n\tconst char* psShaderSrc = \"\"\n\t\t\"#version 450\\r\\n\"\n\t\t\"layout(location = 0) in flat ivec2 passSrcTexelOffset;\\r\\n\"\n\t\t\"layout(binding = 0) uniform sampler2D textureSrc;\\r\\n\"\n\t\t\"layout(location = 0) out vec4 colorOut0;\\r\\n\"\n\t\t\"in vec4 gl_FragCoord;\\r\\n\"\n\t\t\"\\r\\n\"\n\t\t\"void main(){\\r\\n\"\n\t\t\"colorOut0.r = texelFetch(textureSrc, passSrcTexelOffset + ivec2(gl_FragCoord.xy), 0).r;\\r\\n\"\n\t\t\"}\\r\\n\";\n\n\tstd::string shaderStr(psShaderSrc);\n\tauto vkShader = new RendererShaderVk(RendererShader::ShaderType::kFragment, 0, 0, false, false, shaderStr);\n\tvkShader->PreponeCompilation(true);\n\treturn vkShader;\n}\n\nVKRObjectRenderPass* VulkanRenderer::copySurface_createRenderpass(VkCopySurfaceState_t& state)\n{\n\tVKRObjectRenderPass::AttachmentInfo_t attachmentInfo{};\n\n\tif (state.destinationTexture->isDepth)\n\t{\n\t\tattachmentInfo.depthAttachment.viewObj = ((LatteTextureViewVk*)state.destinationTexture->baseView)->GetViewRGBA();\n\t\tattachmentInfo.depthAttachment.format = state.destinationTexture->GetFormat();\n\t\tattachmentInfo.depthAttachment.hasStencil = state.destinationTexture->hasStencil;\n\t}\n\telse\n\t{\n\t\tattachmentInfo.colorAttachment[0].viewObj = ((LatteTextureViewVk*)state.destinationTexture->baseView)->GetViewRGBA();\n\t\tattachmentInfo.colorAttachment[0].format = state.destinationTexture->GetFormat();\n\t}\n\n\tVKRObjectRenderPass* vkObjRenderPass = new VKRObjectRenderPass(attachmentInfo, 1);\n\n\treturn vkObjRenderPass;\n}\n\nCopySurfacePipelineInfo* VulkanRenderer::copySurface_getOrCreateGraphicsPipeline(VkCopySurfaceState_t& state)\n{\n\tauto cache_object = copySurface_getCachedPipeline(state);\n\tif (cache_object != nullptr)\n\t\treturn cache_object;\n\n\tif (defaultShaders.copySurface_vs == nullptr)\n\t{\n\t\t// on first call generate shaders\n\t\tdefaultShaders.copySurface_vs = _vkGenSurfaceCopyShader_vs();\n\t\tdefaultShaders.copySurface_psColor2Depth = _vkGenSurfaceCopyShader_ps_colorToDepth(); \n\t\tdefaultShaders.copySurface_psDepth2Color = _vkGenSurfaceCopyShader_ps_depthToColor();\n\t}\n\n\tRendererShaderVk* vertexShader = defaultShaders.copySurface_vs;\n\tRendererShaderVk* pixelShader = nullptr;\n\tif (state.sourceTexture->isDepth && !state.destinationTexture->isDepth)\n\t\tpixelShader = defaultShaders.copySurface_psDepth2Color;\n\telse if (!state.sourceTexture->isDepth && state.destinationTexture->isDepth)\n\t\tpixelShader = defaultShaders.copySurface_psColor2Depth;\n\telse\n\t{\n\t\tcemu_assert(false);\n\t}\n\n\tstd::vector<VkPipelineShaderStageCreateInfo> shaderStages;\n\n\tshaderStages.emplace_back(CreatePipelineShaderStageCreateInfo(VK_SHADER_STAGE_VERTEX_BIT, vertexShader->GetShaderModule(), \"main\"));\n\tshaderStages.emplace_back(CreatePipelineShaderStageCreateInfo(VK_SHADER_STAGE_FRAGMENT_BIT, pixelShader->GetShaderModule(), \"main\"));\n\n\t// ##########################################################################################################################################\n\n\tconst uint64 stateHash = copySurface_getPipelineStateHash(state);\n\n\tCopySurfacePipelineInfo* copyPipeline = new CopySurfacePipelineInfo();\n\n\tm_copySurfacePipelineCache.try_emplace(stateHash, copyPipeline);\n\n\tVKRObjectPipeline* vkObjPipeline = new VKRObjectPipeline();\n\n\t// ##########################################################################################################################################\n\n\tVkPipelineVertexInputStateCreateInfo vertexInputInfo{};\n\tvertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;\n\tvertexInputInfo.vertexBindingDescriptionCount = 0;\n\tvertexInputInfo.pVertexBindingDescriptions = nullptr;\n\tvertexInputInfo.vertexAttributeDescriptionCount = 0;\n\tvertexInputInfo.pVertexAttributeDescriptions = nullptr;\n\n\t// ##########################################################################################################################################\n\n\tVkPipelineInputAssemblyStateCreateInfo inputAssembly{};\n\tinputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;\n\tinputAssembly.primitiveRestartEnable = VK_FALSE;\n\tinputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n\n\t// ##########################################################################################################################################\n\n\tVkPipelineViewportStateCreateInfo viewportState{};\n\tviewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;\n\tviewportState.viewportCount = 1;\n\tviewportState.scissorCount = 1;\n\n\t// ##########################################################################################################################################\n\n\tVkPipelineRasterizationStateCreateInfo rasterizer{};\n\trasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;\n\trasterizer.depthClampEnable = VK_FALSE;\n\trasterizer.rasterizerDiscardEnable = VK_FALSE;\n\trasterizer.polygonMode = VK_POLYGON_MODE_FILL;\n\trasterizer.lineWidth = 1.0f;\n\trasterizer.cullMode = VK_CULL_MODE_NONE;\n\trasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;\n\n\t// ##########################################################################################################################################\n\n\tVkPipelineMultisampleStateCreateInfo multisampling{};\n\tmultisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;\n\tmultisampling.sampleShadingEnable = VK_FALSE;\n\tmultisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n\n\t// ##########################################################################################################################################\n\n\tVkPipelineColorBlendStateCreateInfo colorBlending{};\n\tVkPipelineColorBlendAttachmentState blendAttachment{};\n\n\tif (!state.destinationTexture->isDepth)\n\t{\n\t\tblendAttachment.blendEnable = VK_FALSE;\n\t\tblendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT;\n\t\tcolorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;\n\t\tcolorBlending.attachmentCount = 1;\n\t\tcolorBlending.pAttachments = &blendAttachment;\n\t\tcolorBlending.logicOpEnable = VK_FALSE;\n\t}\n\n\n\t// ##########################################################################################################################################\n\n\tstd::vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;\n\n\tVkDescriptorSetLayoutBinding entry{};\n\tentry.binding = 0;\n\tentry.descriptorCount = 1;\n\tentry.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\tentry.pImmutableSamplers = nullptr;\n\tentry.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\tdescriptorSetLayoutBindings.emplace_back(entry);\n\n\tVkDescriptorSetLayoutCreateInfo layoutInfo = {};\n\tlayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n\tlayoutInfo.bindingCount = (uint32_t)descriptorSetLayoutBindings.size();\n\tlayoutInfo.pBindings = descriptorSetLayoutBindings.data();\n\n\tif (vkCreateDescriptorSetLayout(m_logicalDevice, &layoutInfo, nullptr, &vkObjPipeline->m_pixelDSL) != VK_SUCCESS)\n\t\tUnrecoverableError(fmt::format(\"Failed to create descriptor set layout for surface copy shader\").c_str());\n\n\t// ##########################################################################################################################################\n\n\tVkPushConstantRange pushConstantRange{};\n\tpushConstantRange.offset = 0;\n\tpushConstantRange.size = sizeof(CopyShaderPushConstantData_t);\n\tpushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;\n\n\tVkPipelineLayoutCreateInfo pipelineLayoutInfo{};\n\tpipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n\tpipelineLayoutInfo.setLayoutCount = 1;\n\tpipelineLayoutInfo.pSetLayouts = &vkObjPipeline->m_pixelDSL;\n\tpipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;\n\tpipelineLayoutInfo.pushConstantRangeCount = 1;\n\n\tVkResult result = vkCreatePipelineLayout(m_logicalDevice, &pipelineLayoutInfo, nullptr, &vkObjPipeline->m_pipelineLayout);\n\tif (result != VK_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to create pipeline layout: {}\", result);\n\t\tvkObjPipeline->SetPipeline(VK_NULL_HANDLE);\n\t\treturn copyPipeline;\n\t}\n\n\t// ###################################################\n\n\tbool writeDepth = state.destinationTexture->isDepth;\n\n\tVkPipelineDepthStencilStateCreateInfo depthStencilState{};\n\tdepthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;\n\tdepthStencilState.depthTestEnable = writeDepth ? VK_TRUE : VK_FALSE;\n\tdepthStencilState.depthWriteEnable = writeDepth ? VK_TRUE : VK_FALSE;\n\tdepthStencilState.depthCompareOp = VK_COMPARE_OP_ALWAYS;\n\n\tdepthStencilState.depthBoundsTestEnable = false;\n\tdepthStencilState.minDepthBounds = 0.0f;\n\tdepthStencilState.maxDepthBounds = 1.0f;\n\n\tdepthStencilState.stencilTestEnable = VK_FALSE;\n\n\t// ##########################################################################################################################################\n\n\tstd::vector<VkDynamicState> dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };\n\n\tVkPipelineDynamicStateCreateInfo dynamicState = {};\n\tdynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;\n\tdynamicState.dynamicStateCount = (uint32_t)dynamicStates.size();\n\tdynamicState.pDynamicStates = dynamicStates.data();\n\n\t// ##########################################################################################################################################\n\n\tcopyPipeline->vkObjRenderPass = copySurface_createRenderpass(state);\n\tvkObjPipeline->addRef(copyPipeline->vkObjRenderPass);\n\n\t// ###########################################################\n\n\tVkGraphicsPipelineCreateInfo pipelineInfo{};\n\tpipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;\n\tpipelineInfo.stageCount = (uint32_t)shaderStages.size();\n\tpipelineInfo.pStages = shaderStages.data();\n\tpipelineInfo.pVertexInputState = &vertexInputInfo;\n\tpipelineInfo.pInputAssemblyState = &inputAssembly;\n\tpipelineInfo.pViewportState = &viewportState;\n\tpipelineInfo.pDynamicState = &dynamicState;\n\tpipelineInfo.pRasterizationState = &rasterizer;\n\tpipelineInfo.pMultisampleState = &multisampling;\n\tpipelineInfo.pColorBlendState = state.destinationTexture->isDepth?nullptr:&colorBlending;\n\tpipelineInfo.layout = vkObjPipeline->m_pipelineLayout;\n\tpipelineInfo.renderPass = copyPipeline->vkObjRenderPass->m_renderPass;\n\tpipelineInfo.pDepthStencilState = &depthStencilState;\n\tpipelineInfo.subpass = 0;\n\tpipelineInfo.basePipelineHandle = nullptr;\n\tpipelineInfo.flags = 0;\n\n\tcopyPipeline->vkObjPipeline = vkObjPipeline;\n\n\tVkPipeline pipeline = VK_NULL_HANDLE;\n\tresult = vkCreateGraphicsPipelines(m_logicalDevice, m_pipeline_cache, 1, &pipelineInfo, nullptr, &pipeline);\n\tif (result != VK_SUCCESS)\n\t{\n\t\tcopyPipeline->vkObjPipeline->SetPipeline(nullptr);\n\t\tcemuLog_log(LogType::Force, \"Failed to create graphics pipeline for surface copy. Error {} Info:\", (sint32)result);\n\t\tcemu_assert_suspicious();\n\t}\n\telse\n\t\tcopyPipeline->vkObjPipeline->SetPipeline(pipeline);\n\treturn copyPipeline;\n}\n\nVKRObjectTextureView* VulkanRenderer::surfaceCopy_createImageView(LatteTextureVk* textureVk, uint32 sliceIndex, uint32 mipIndex)\n{\n\n\tVkImageViewCreateInfo viewCreateInfo = {};\n\tviewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n\tviewCreateInfo.image = textureVk->GetImageObj()->m_image;\n\tviewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;\n\tviewCreateInfo.format = textureVk->GetFormat();\n\tviewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n\tviewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n\tviewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n\tviewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n\tif (textureVk->isDepth)\n\t\tviewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;\n\telse\n\t\tviewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n\tviewCreateInfo.subresourceRange.baseMipLevel = mipIndex;\n\tviewCreateInfo.subresourceRange.levelCount = 1;\n\tviewCreateInfo.subresourceRange.baseArrayLayer = sliceIndex;\n\tviewCreateInfo.subresourceRange.layerCount = 1;\n\tVkImageView imageView;\n\tif (vkCreateImageView(m_logicalDevice, &viewCreateInfo, nullptr, &imageView) != VK_SUCCESS)\n\t\tUnrecoverableError(\"Failed to create framebuffer image view for copy surface operation\");\n\treturn new VKRObjectTextureView(textureVk->GetImageObj(), imageView);\n}\n\nVKRObjectFramebuffer* VulkanRenderer::surfaceCopy_getOrCreateFramebuffer(VkCopySurfaceState_t& state, CopySurfacePipelineInfo* pipelineInfo)\n{\n\tauto itr = pipelineInfo->map_framebuffers.find(state.destinationTexture);\n\tif (itr != pipelineInfo->map_framebuffers.end())\n\t{\n\t\tauto p = itr->second.get(state.dstSlice, state.dstMip);\n\t\tif (p != nullptr)\n\t\t\treturn p->vkObjFramebuffer;\n\t}\n\n\t// create view\n\tVKRObjectTextureView* vkObjTextureView = surfaceCopy_createImageView(state.destinationTexture, state.dstSlice, state.dstMip);\n\n\t// create new framebuffer\n\tsint32 effectiveWidth, effectiveHeight;\n\tstate.destinationTexture->GetEffectiveSize(effectiveWidth, effectiveHeight, state.dstMip);\n\n\tstd::array<VKRObjectTextureView*, 1> fbAttachments;\n\tfbAttachments[0] = vkObjTextureView;\n\n\tVKRObjectFramebuffer* vkObjFramebuffer = new VKRObjectFramebuffer(pipelineInfo->vkObjRenderPass, fbAttachments, Vector2i(effectiveWidth, effectiveHeight));\n\n\t// register\n\tauto insertResult = pipelineInfo->map_framebuffers.try_emplace(state.destinationTexture, state.destinationTexture);\n\tCopySurfacePipelineInfo::FramebufferValue* framebufferVal = insertResult.first->second.create(state.dstSlice, state.dstMip);\n\tframebufferVal->vkObjFramebuffer = vkObjFramebuffer;\n\tframebufferVal->vkObjImageView = vkObjTextureView;\n\t\n\treturn vkObjFramebuffer;\n}\n\nVKRObjectDescriptorSet* VulkanRenderer::surfaceCopy_getOrCreateDescriptorSet(VkCopySurfaceState_t& state, CopySurfacePipelineInfo* pipelineInfo)\n{\n\tauto itr = pipelineInfo->map_descriptors.find(state.sourceTexture);\n\tif (itr != pipelineInfo->map_descriptors.end())\n\t{\n\t\tauto p = itr->second.get(state.srcSlice, state.srcMip);\n\t\tif (p != nullptr)\n\t\t\treturn p->vkObjDescriptorSet;\n\t}\n\n\tVKRObjectDescriptorSet* vkObjDescriptorSet = new VKRObjectDescriptorSet();\n\n\t// allocate new descriptor set\n\tVkDescriptorSetAllocateInfo allocInfo = {};\n\tallocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n\tallocInfo.descriptorPool = m_descriptorPool;\n\tallocInfo.descriptorSetCount = 1;\n\tallocInfo.pSetLayouts = &pipelineInfo->vkObjPipeline->m_pixelDSL;\n\n\tif (vkAllocateDescriptorSets(m_logicalDevice, &allocInfo, &vkObjDescriptorSet->descriptorSet) != VK_SUCCESS)\n\t{\n\t\tUnrecoverableError(\"failed to allocate descriptor set for surface copy operation\");\n\t}\n\n\t// create view\n\tVKRObjectTextureView* vkObjImageView = surfaceCopy_createImageView(state.sourceTexture, state.srcSlice, state.srcMip);\n\tvkObjDescriptorSet->addRef(vkObjImageView);\n\n\t// create sampler\n\tVkSamplerCreateInfo samplerInfo{};\n\tsamplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n\tsamplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;\n\tsamplerInfo.minLod = 0;\n\tsamplerInfo.maxLod = 0;\n\tsamplerInfo.minFilter = VK_FILTER_NEAREST;\n\tsamplerInfo.magFilter = VK_FILTER_NEAREST;\n\tsamplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;\n\tsamplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;\n\tsamplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;\n\tsamplerInfo.anisotropyEnable = VK_FALSE;\n\tsamplerInfo.maxAnisotropy = 1.0f;\n\tsamplerInfo.mipLodBias = 0;\n\tsamplerInfo.compareEnable = VK_FALSE;\n\tsamplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;\n\n\tif (vkCreateSampler(m_logicalDevice, &samplerInfo, nullptr, &vkObjImageView->m_textureDefaultSampler[0]) != VK_SUCCESS)\n\t\tUnrecoverableError(\"Failed to create texture sampler for surface copy operation\");\n\n\t// create descriptor image info\n\tVkDescriptorImageInfo descriptorImageInfo{};\n\n\tdescriptorImageInfo.sampler = vkObjImageView->m_textureDefaultSampler[0];\n\tdescriptorImageInfo.imageView = vkObjImageView->m_textureImageView;\n\tdescriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;\n\n\tVkWriteDescriptorSet write_descriptor{};\n\twrite_descriptor.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n\twrite_descriptor.dstSet = vkObjDescriptorSet->descriptorSet;\n\twrite_descriptor.dstBinding = 0;\n\twrite_descriptor.dstArrayElement = 0;\n\twrite_descriptor.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n\twrite_descriptor.descriptorCount = 1;\n\twrite_descriptor.pImageInfo = &descriptorImageInfo;\n\n\tvkUpdateDescriptorSets(m_logicalDevice, 1, &write_descriptor, 0, nullptr);\n\n\t// register\n\tauto insertResult = pipelineInfo->map_descriptors.try_emplace(state.sourceTexture, state.sourceTexture);\n\tCopySurfacePipelineInfo::DescriptorValue* descriptorValue = insertResult.first->second.create(state.srcSlice, state.srcMip);\n\tdescriptorValue->vkObjDescriptorSet = vkObjDescriptorSet;\n\tdescriptorValue->vkObjImageView = vkObjImageView;\n\t\n\treturn vkObjDescriptorSet;\n}\n\nvoid VulkanRenderer::surfaceCopy_viaDrawcall(LatteTextureVk* srcTextureVk, sint32 texSrcMip, sint32 texSrcSlice, LatteTextureVk* dstTextureVk, sint32 texDstMip, sint32 texDstSlice, sint32 effectiveCopyWidth, sint32 effectiveCopyHeight)\n{\n\tdraw_endRenderPass();\n\n\t//debug_printf(\"surfaceCopy_viaDrawcall Src %04d %04d Dst %04d %04d CopySize %04d %04d\\n\", srcTextureVk->width, srcTextureVk->height, dstTextureVk->width, dstTextureVk->height, effectiveCopyWidth, effectiveCopyHeight);\n\n\n\tVkImageSubresourceLayers srcImageSubresource;\n\tsrcImageSubresource.aspectMask = srcTextureVk->GetImageAspect();\n\tsrcImageSubresource.baseArrayLayer = texSrcSlice;\n\tsrcImageSubresource.mipLevel = texSrcMip;\n\tsrcImageSubresource.layerCount = 1;\n\n\tVkImageSubresourceLayers dstImageSubresource;\n\tdstImageSubresource.aspectMask = dstTextureVk->GetImageAspect();\n\tdstImageSubresource.baseArrayLayer = texDstSlice;\n\tdstImageSubresource.mipLevel = texDstMip;\n\tdstImageSubresource.layerCount = 1;\n\n\tVkCopySurfaceState_t copySurfaceState;\n\tcopySurfaceState.sourceTexture = srcTextureVk;\n\tcopySurfaceState.srcSlice = texSrcSlice;\n\tcopySurfaceState.srcMip = texSrcMip;\n\tcopySurfaceState.destinationTexture = dstTextureVk;\n\tcopySurfaceState.dstSlice = texDstSlice;\n\tcopySurfaceState.dstMip = texDstMip;\n\tcopySurfaceState.width = effectiveCopyWidth;\n\tcopySurfaceState.height = effectiveCopyHeight;\n\n\tCopySurfacePipelineInfo* copySurfacePipelineInfo = copySurface_getOrCreateGraphicsPipeline(copySurfaceState);\n\n\t// get framebuffer\n\tVKRObjectFramebuffer* vkObjFramebuffer = surfaceCopy_getOrCreateFramebuffer(copySurfaceState, copySurfacePipelineInfo);\n\tvkObjFramebuffer->flagForCurrentCommandBuffer();\n\n\t// get descriptor set\n\tVKRObjectDescriptorSet* vkObjDescriptorSet = surfaceCopy_getOrCreateDescriptorSet(copySurfaceState, copySurfacePipelineInfo);\n\t\n\tsint32 dstEffectiveWidth, dstEffectiveHeight;\n\tdstTextureVk->GetEffectiveSize(dstEffectiveWidth, dstEffectiveHeight, texDstMip);\n\n\tsint32 srcEffectiveWidth, srcEffectiveHeight;\n\tsrcTextureVk->GetEffectiveSize(srcEffectiveWidth, srcEffectiveHeight, texSrcMip);\n\n\tCopyShaderPushConstantData_t pushConstantData;\n\n\tfloat srcCopyWidth = (float)1.0f;\n\tfloat srcCopyHeight = (float)1.0f;\n\t// q0 vertex\n\tpushConstantData.vertexOffsets[0] = -1.0f;\n\tpushConstantData.vertexOffsets[1] = 1.0f;\n\t// q1\n\tpushConstantData.vertexOffsets[2] = 1.0f;\n\tpushConstantData.vertexOffsets[3] = 1.0f;\n\t// q2\n\tpushConstantData.vertexOffsets[4] = -1.0f;\n\tpushConstantData.vertexOffsets[5] = -1.0f;\n\t// q3\n\tpushConstantData.vertexOffsets[6] = 1.0f;\n\tpushConstantData.vertexOffsets[7] = -1.0f;\n\n\tpushConstantData.srcTexelOffset[0] = 0;\n\tpushConstantData.srcTexelOffset[1] = 0;\n\n\tvkCmdPushConstants(m_state.currentCommandBuffer, copySurfacePipelineInfo->vkObjPipeline->m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(pushConstantData), &pushConstantData);\n\n\t// draw\n\tVkRenderPassBeginInfo renderPassInfo{};\n\trenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n\trenderPassInfo.renderPass = copySurfacePipelineInfo->vkObjRenderPass->m_renderPass;\n\trenderPassInfo.framebuffer = vkObjFramebuffer->m_frameBuffer;\n\trenderPassInfo.renderArea.offset = { 0, 0 };\n\trenderPassInfo.renderArea.extent = { (uint32_t)effectiveCopyWidth, (uint32_t)effectiveCopyHeight };\n\trenderPassInfo.clearValueCount = 0;\n\n\tVkViewport viewport{};\n\tviewport.x = 0;\n\tviewport.y = (float)effectiveCopyHeight;\n\tviewport.width = (float)effectiveCopyWidth;\n\tviewport.height = (float)-effectiveCopyHeight;\n\tviewport.minDepth = 0.0f;\n\tviewport.maxDepth = 1.0f;\n\n\tVkRect2D scissor;\n\tscissor.offset.x = 0;\n\tscissor.offset.y = 0;\n\tscissor.extent.width = effectiveCopyWidth;\n\tscissor.extent.height = effectiveCopyHeight;\n\n\tvkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &viewport);\n\tvkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &scissor);\n\n\tcemu_assert_debug(srcTextureVk->GetImageObj()->m_image != dstTextureVk->GetImageObj()->m_image);\n\n\tbarrier_image<SYNC_OP::IMAGE_WRITE | SYNC_OP::ANY_TRANSFER, SYNC_OP::IMAGE_READ>(srcTextureVk, srcImageSubresource, VK_IMAGE_LAYOUT_GENERAL); // wait for any modifying operations on source image to complete\n\tbarrier_image<SYNC_OP::IMAGE_READ | SYNC_OP::IMAGE_WRITE | SYNC_OP::ANY_TRANSFER, SYNC_OP::IMAGE_WRITE>(dstTextureVk, dstImageSubresource, VK_IMAGE_LAYOUT_GENERAL); // wait for any operations on destination image to complete\n\n\t\n\tvkCmdBeginRenderPass(m_state.currentCommandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);\n\n\tvkCmdBindPipeline(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, copySurfacePipelineInfo->vkObjPipeline->GetPipeline());\n\tcopySurfacePipelineInfo->vkObjPipeline->flagForCurrentCommandBuffer();\n\n\tm_state.currentPipeline = copySurfacePipelineInfo->vkObjPipeline->GetPipeline();\n\n\tvkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n\t\tcopySurfacePipelineInfo->vkObjPipeline->m_pipelineLayout, 0, 1, &vkObjDescriptorSet->descriptorSet, 0, nullptr);\n\tvkObjDescriptorSet->flagForCurrentCommandBuffer();\n\n\tvkCmdDraw(m_state.currentCommandBuffer, 6, 1, 0, 0);\n\n\tvkCmdEndRenderPass(m_state.currentCommandBuffer);\n\n\tbarrier_image<SYNC_OP::IMAGE_READ, SYNC_OP::IMAGE_READ | SYNC_OP::IMAGE_WRITE | SYNC_OP::ANY_TRANSFER>(srcTextureVk, srcImageSubresource, VK_IMAGE_LAYOUT_GENERAL); // wait for drawcall to complete before any other operations on the source image\n\tbarrier_image<SYNC_OP::IMAGE_WRITE, SYNC_OP::IMAGE_READ | SYNC_OP::IMAGE_WRITE | SYNC_OP::ANY_TRANSFER>(dstTextureVk, dstImageSubresource, VK_IMAGE_LAYOUT_GENERAL); // wait for drawcall to complete before any other operations on the destination image\n\n\t// restore viewport and scissor box\n\tvkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &m_state.currentViewport);\n\tvkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &m_state.currentScissorRect);\n\n\tLatteTexture_TrackTextureGPUWrite(dstTextureVk, texDstSlice, texDstMip, LatteTexture_getNextUpdateEventCounter());\n}\n\nstruct vkComponentDesc_t\n{\n\tenum class TYPE : uint8\n\t{\n\t\tNONE,\n\t\tUNORM,\n\t\tSNORM,\n\t\tFLOAT\n\t};\n\tuint8 bits;\n\tTYPE type;\n\n\tvkComponentDesc_t(uint8 b, TYPE t) : bits(b), type(t) {};\n\tfriend bool operator==(const vkComponentDesc_t& lhs, const vkComponentDesc_t& rhs)\n\t{\n\t\treturn lhs.bits == rhs.bits && lhs.type == rhs.type;\n\t}\n};\n\nbool vkIsDepthFormat(VkFormat imageFormat)\n{\n\tswitch (imageFormat)\n\t{\n\tcase VK_FORMAT_D32_SFLOAT_S8_UINT:\n\tcase VK_FORMAT_D24_UNORM_S8_UINT:\n\tcase VK_FORMAT_D32_SFLOAT:\n\tcase VK_FORMAT_D16_UNORM:\n\t\treturn true;\n\tdefault:\n\t\tbreak;\n\t}\n\treturn false;\n}\n\nvkComponentDesc_t vkGetFormatDepthBits(VkFormat imageFormat)\n{\n\tswitch (imageFormat)\n\t{\n\tcase VK_FORMAT_D32_SFLOAT_S8_UINT:\n\t\treturn vkComponentDesc_t(32, vkComponentDesc_t::TYPE::FLOAT);\n\tcase VK_FORMAT_D24_UNORM_S8_UINT:\n\t\treturn vkComponentDesc_t(24, vkComponentDesc_t::TYPE::UNORM);\n\tcase VK_FORMAT_D32_SFLOAT:\n\t\treturn vkComponentDesc_t(32, vkComponentDesc_t::TYPE::FLOAT);\n\tcase VK_FORMAT_D16_UNORM:\n\t\treturn vkComponentDesc_t(16, vkComponentDesc_t::TYPE::UNORM);\n\tdefault:\n\t\tbreak;\n\t}\n\treturn vkComponentDesc_t(0, vkComponentDesc_t::TYPE::NONE);\n}\n\nbool vkIsBitCompatibleColorDepthFormat(VkFormat format1, VkFormat format2)\n{\n\tcemu_assert_debug(vkIsDepthFormat(format1) != vkIsDepthFormat(format2));\n\n\tVkFormat depthFormat, colorFormat;\n\tif (vkIsDepthFormat(format1))\n\t{\n\t\tdepthFormat = format1;\n\t\tcolorFormat = format2;\n\t}\n\telse\n\t{\n\t\tdepthFormat = format2;\n\t\tcolorFormat = format1;\n\t}\n\n\tswitch (depthFormat)\n\t{\n\tcase VK_FORMAT_D32_SFLOAT_S8_UINT:\n\t\treturn colorFormat == VK_FORMAT_R32_SFLOAT;\n\tcase VK_FORMAT_D24_UNORM_S8_UINT:\n\t\treturn false; // there is no 24-bit color format\n\tcase VK_FORMAT_D32_SFLOAT:\n\t\treturn colorFormat == VK_FORMAT_R32_SFLOAT;\n\tcase VK_FORMAT_D16_UNORM:\n\t\treturn colorFormat == VK_FORMAT_R16_UNORM;\n\tdefault:\n\t\tbreak;\n\t}\n\treturn false;\n}\n\nvoid VulkanRenderer::surfaceCopy_copySurfaceWithFormatConversion(LatteTexture* sourceTexture, sint32 srcMip, sint32 srcSlice, LatteTexture* destinationTexture, sint32 dstMip, sint32 dstSlice, sint32 width, sint32 height)\n{\n\t// scale copy size to effective size\n\tsint32 effectiveCopyWidth = width;\n\tsint32 effectiveCopyHeight = height;\n\tLatteTexture_scaleToEffectiveSize(sourceTexture, &effectiveCopyWidth, &effectiveCopyHeight, 0);\n\tsint32 sourceEffectiveWidth, sourceEffectiveHeight;\n\tsourceTexture->GetEffectiveSize(sourceEffectiveWidth, sourceEffectiveHeight, srcMip);\n\n\tsint32 texSrcMip = srcMip;\n\tsint32 texSrcSlice = srcSlice;\n\tsint32 texDstMip = dstMip;\n\tsint32 texDstSlice = dstSlice;\n\n\tLatteTextureVk* srcTextureVk = (LatteTextureVk*)sourceTexture;\n\tLatteTextureVk* dstTextureVk = (LatteTextureVk*)destinationTexture;\n\n\t// check if texture rescale ratios match\n\t// todo - if not, we have to use drawcall based copying\n\tif (!LatteTexture_doesEffectiveRescaleRatioMatch(srcTextureVk, texSrcMip, dstTextureVk, texDstMip))\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"surfaceCopy_copySurfaceViaDrawcall(): Mismatching dimensions\");\n\t\treturn;\n\t}\n\n\t// check if bpp size matches\n\tif (srcTextureVk->GetBPP() != dstTextureVk->GetBPP())\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"surfaceCopy_copySurfaceViaDrawcall(): Mismatching BPP\");\n\t\treturn;\n\t}\n\n\tsurfaceCopy_viaDrawcall(srcTextureVk, texSrcMip, texSrcSlice, dstTextureVk, texDstMip, texDstSlice, effectiveCopyWidth, effectiveCopyHeight);\n}\n\n// called whenever a texture is destroyed\n// it is guaranteed that the texture is not in use and all associated resources (descriptor sets, framebuffers) can be destroyed safely\nvoid VulkanRenderer::surfaceCopy_notifyTextureRelease(LatteTextureVk* hostTexture)\n{\n\tfor (auto& itr : m_copySurfacePipelineCache)\n\t{\n\t\tauto& pipelineInfo = itr.second;\n\t\t\n\t\tauto itrDescriptors = pipelineInfo->map_descriptors.find(hostTexture);\n\t\tif (itrDescriptors != pipelineInfo->map_descriptors.end())\n\t\t{\n\t\t\tfor (auto p : itrDescriptors->second.m_array)\n\t\t\t{\n\t\t\t\tif (p)\n\t\t\t\t{\n\t\t\t\t\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(p->vkObjDescriptorSet);\n\t\t\t\t\tp->vkObjDescriptorSet = nullptr;\n\t\t\t\t\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(p->vkObjImageView);\n\t\t\t\t\tp->vkObjImageView = nullptr;\n\t\t\t\t}\n\t\t\t}\n\t\t\tpipelineInfo->map_descriptors.erase(itrDescriptors);\n\t\t}\n\n\t\tauto itrFramebuffers = pipelineInfo->map_framebuffers.find(hostTexture);\n\t\tif (itrFramebuffers != pipelineInfo->map_framebuffers.end())\n\t\t{\n\t\t\tfor (auto p : itrFramebuffers->second.m_array)\n\t\t\t{\n\t\t\t\tif (p)\n\t\t\t\t{\n\t\t\t\t\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(p->vkObjFramebuffer);\n\t\t\t\t\tp->vkObjFramebuffer = nullptr;\n\t\t\t\t\tVulkanRenderer::GetInstance()->ReleaseDestructibleObject(p->vkObjImageView);\n\t\t\t\t\tp->vkObjImageView = nullptr;\n\t\t\t\t}\n\t\t\t}\n\t\t\tpipelineInfo->map_framebuffers.erase(itrFramebuffers);\n\t\t}\n\t}\n}\n\nvoid VulkanRenderer::surfaceCopy_cleanup()\n{\n\tfor(auto& i : m_copySurfacePipelineCache)\n\t{\n\t\tdelete i.second;\n\t}\n\tm_copySurfacePipelineCache = {};\n}\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Renderer/Vulkan/VulkanTextureReadback.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Core/LatteTextureReadbackInfo.h\"\n\nclass LatteTextureReadbackInfoVk : public LatteTextureReadbackInfo\n{\npublic:\n\tLatteTextureReadbackInfoVk(VkDevice device, LatteTextureView* textureView);\n\t~LatteTextureReadbackInfoVk();\n\n\tstatic uint32 GetImageSize(LatteTextureView* textureView);\n\n\tvoid StartTransfer() override;\n\n\tbool IsFinished() override;\n\tvoid ForceFinish() override;\n\n\tuint8* GetData() override\n\t{\n\t\treturn m_buffer_ptr + m_buffer_offset;\n\t}\n\n\tuint32 GetImageSize() const\n\t{\n\t\treturn m_image_size;\n\t}\n\n\tvoid SetBuffer(VkBuffer buffer, uint8* buffer_ptr, const uint32 buffer_offset)\n\t{\n\t\tm_buffer = buffer;\n\t\tm_buffer_ptr = buffer_ptr;\n\t\tm_buffer_offset = buffer_offset;\n\t}\n\nprivate:\n\tVkDevice m_device = nullptr;\n\n\tVkBuffer m_buffer = nullptr;\n\tuint8* m_buffer_ptr = nullptr;\n\tuint32 m_buffer_offset = 0;\n\tuint64 m_associatedCommandBufferId = 0;\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/ShaderInfo/ShaderDescription.cpp",
    "content": "#include \"Cafe/HW/Latte/ShaderInfo/ShaderInfo.h\"\n#include \"Cafe/HW/Latte/ISA/LatteInstructions.h\"\n\nnamespace Latte\n{\n\tbool ShaderDescription::analyzeShaderCode(void* shaderProgram, size_t sizeInBytes, LatteConst::ShaderType shaderType)\n\t{\n\t\tassert_dbg();\n\n\n\t\t// parse CF flow\n\t\t// we need to parse:\n\t\t// - Export clauses to gather info about exported attributes and written render targets\n\t\t// - ALU clauses to gather info about accessed uniforms (and the remapped uniform)\n\n\t\tconst LatteCFInstruction* cfCode = (const LatteCFInstruction*)shaderProgram;\n\t\tconst size_t cfMaxCount = sizeInBytes / 8;\n\n\t\tsize_t cfIndex = 0;\n\t\twhile (cfIndex < cfMaxCount)\n\t\t{\n\t\t\tconst LatteCFInstruction* baseInstr = cfCode + cfIndex;\n\t\t\tcfIndex++;\n\t\t\tbool isALU = false;\n\t\t\tif (const auto cfInstr = baseInstr->getParserIfOpcodeMatch<LatteCFInstruction_DEFAULT>())\n\t\t\t{\n\t\t\t\tcemu_assert_debug(cfInstr->getField_WHOLE_QUAD_MODE() == 0);\n\n\t\t\t\tcemu_assert_debug(cfInstr->getField_CALL_COUNT() == 0); // todo\n\t\t\t\tcemu_assert_debug(cfInstr->getField_POP_COUNT() == 0); // todo\n\n\t\t\t\tauto cond = cfInstr->getField_COND();\n\n\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t\telse if (const auto cfInstr = baseInstr->getParserIfOpcodeMatch<LatteCFInstruction_ALU>())\n\t\t\t{\n\t\t\t\tassert_dbg();\n\t\t\t\tisALU = true;\n\t\t\t}\n\t\t\telse if (const auto cfInstr = baseInstr->getParserIfOpcodeMatch<LatteCFInstruction_EXPORT_IMPORT>())\n\t\t\t{\n\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"ShaderDescription::analyzeShaderCode(): Missing implementation for CF opcode 0x%02x\\n\", baseInstr->getField_Opcode());\n\t\t\t\tcemu_assert_debug(false); // todo\n\t\t\t}\n\t\t\tif (!isALU && baseInstr->getField_END_OF_PROGRAM())\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn true;\n\t}\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/ShaderInfo/ShaderInfo.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"util/containers/SmallBitset.h\"\n\nnamespace Latte\n{\n\tclass ShaderDescription\n\t{\n\tpublic:\n\t\tbool analyzeShaderCode(void* shaderProgram, size_t sizeInBytes, LatteConst::ShaderType shaderType);\n\n\t\t// public data\n\n\t\t// pixel shader only\n\t\tSmallBitset<8> renderTargetWriteMask; // true if render target is written\n\n\t};\n};"
  },
  {
    "path": "src/Cafe/HW/Latte/ShaderInfo/ShaderInstanceInfo.cpp",
    "content": ""
  },
  {
    "path": "src/Cafe/HW/Latte/Transcompiler/LatteTC.cpp",
    "content": "#include \"Cafe/HW/Latte/Transcompiler/LatteTC.h\"\n#include \"Cafe/HW/Latte/ISA/LatteInstructions.h\"\n\n#include \"util/Zir/Core/IR.h\"\n#include \"util/Zir/Core/ZpIRBuilder.h\"\n#include \"util/Zir/Core/ZpIRDebug.h\"\n\nclass CFBlockNode\n{\npublic:\n\tCFBlockNode(uint32 cfAddress, const LatteCFInstruction& cfInstruction) : cfAddress(cfAddress), cfNext(cfAddress + sizeof(LatteCFInstruction))\n\t{\n\t\tm_cfInstructions.emplace_back(cfInstruction);\n\t\tirBasicBlock = new ZpIR::ZpIRBasicBlock();\n\t};\n\n\tvoid addInstruction(const LatteCFInstruction& cfInstruction)\n\t{\n\t\tm_cfInstructions.emplace_back(cfInstruction);\n\t}\n\n\t// next CF address after this block of CF instructions (assuming no branches)\n\tvoid setNextAddress(uint32 addr)\n\t{\n\t\tcfNext = addr;\n\t}\n\n\tuint32 cfAddress; // offset of the first cf instruction\n\tuint32 cfNext{ 0 }; // offset of the next cf instruction if no branch happens\n\n\tZpIR::ZpIRBasicBlock* irBasicBlock{};\n\n\tstd::vector<LatteCFInstruction> m_cfInstructions;\n\nprivate:\n};\n\n// emit IR code for all clauses in a DAG node\nvoid LatteTCGenIR::genIRForNode(CFBlockNode& node)\n{\n\tm_irGenContext.reset();\n\tm_irGenContext.irBuilder = new ZpIR::BasicBlockBuilder(node.irBasicBlock);\n\tm_irGenContext.isEntryBasicBlock = (&node == m_ctx.mainFunctionDAG.GetEntryNode());\n\n\t// for vertex shaders add initialization code to main()\n\tif (&node == m_ctx.mainFunctionDAG.GetEntryNode() && m_ctx.shaderType == SHADER_TYPE::VERTEX)\n\t{\n\t\tfor (uint32 channel = 0; channel < 4; channel++)\n\t\t{\n\t\t\tZpIR::IRReg irReg = m_irGenContext.irBuilder->createReg(ZpIR::DataType::U32);\n\t\t\tm_irGenContext.irBuilder->emit_RR(ZpIR::IR::OpCode::MOV, irReg, m_irGenContext.irBuilder->createConstU32(0));\n\t\t\tthis->m_irGenContext.activeVars.set(0, channel, irReg);\n\t\t}\n\t\t// todo - correctly init R0 based on currently set context register state\n\t}\n\n\n\tfor (auto& itr : node.m_cfInstructions)\n\t{\n\t\tconst auto opcode = itr.getField_Opcode();\n\t\tif (const auto cfInstr = itr.getParserIfOpcodeMatch<LatteCFInstruction_DEFAULT>())\n\t\t{\n\t\t\tif(opcode == LatteCFInstruction::OPCODE::INST_CALL_FS)\n\t\t\t\tprocessCF_CALL_FS(*cfInstr);\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t}\n\t\telse if (const auto cfInstr = itr.getParserIfOpcodeMatch<LatteCFInstruction_ALU>())\n\t\t{\n\t\t\tif (opcode == LatteCFInstruction::OPCODE::INST_ALU)\n\t\t\t\tprocessCF_ALU(*cfInstr);\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t}\n\t\telse if (const auto cfInstr = itr.getParserIfOpcodeMatch<LatteCFInstruction_EXPORT_IMPORT>())\n\t\t{\n\t\t\tif (opcode == LatteCFInstruction::OPCODE::INST_EXPORT || \n\t\t\t\topcode == LatteCFInstruction::OPCODE::INST_EXPORT_DONE)\n\t\t\t\tprocessCF_EXPORT(*cfInstr);\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebug_printf(\"Missing implementation for CF opcode 0x%02x\\n\", itr.getField_Opcode());\n\t\t\tassert_dbg(); // todo\n\t\t}\n\t}\n}\n\n// parse CF program and create unlinked DAG\nvoid LatteTCGenIR::parseCF_createNodes(NodeDAG& nodeDAG)\n{\n\tconst LatteCFInstruction* cfCode = (const LatteCFInstruction*)m_ctx.programData;\n\tconst size_t cfMaxCount = m_ctx.programSize / 8;\n\n\t// quick prepass to gather a list of jump destinations used by the next pass\n\t// todo\n\n\t// linear pass where we turn uninterrupted sequences of CF instructions (no branch to or from) into CFBlockNode\n\t// algorithm description:\n\t// 1) Create CFBlockNode from first CF instruction. Make it the currently active node\n\t// 2) For each remaining (1 .. n) CF instruction of program\n\t// 2.1) If CF instruction can be merged into active node (no branch destination, no conditionals or other control flow branches) then add it to the currently active node\n\t// 2.2) Otherwise finalize active node, add it to node list. Then create new CFBlockNode node from CF instruction and make it active node\n\t// 3) Finalize active node and add to node list\n\n\tcemu_assert_debug(cfMaxCount != 0); // zero not allowed\n\n\tCFBlockNode* activeNode = new CFBlockNode(0, cfCode[0]); // first instruction becomes the initial node\n\tsize_t cfIndex = 1;\n\t//m_nodes.emplace_back(activeNode);\n\twhile (cfIndex < cfMaxCount)\n\t{\n\t\tconst LatteCFInstruction* baseInstr = cfCode + cfIndex;\n\t\tcfIndex++;\n\t\tbool canMerge;\n\t\tbool isALU = false;\n\t\tif (const auto cfInstr = baseInstr->getParserIfOpcodeMatch<LatteCFInstruction_DEFAULT>())\n\t\t{\n\t\t\tcemu_assert_debug(cfInstr->getField_WHOLE_QUAD_MODE() == 0);\n\n\t\t\tcemu_assert_debug(cfInstr->getField_CALL_COUNT() == 0); // todo\n\t\t\tcemu_assert_debug(cfInstr->getField_POP_COUNT() == 0); // todo\n\n\t\t\tauto cond = cfInstr->getField_COND();\n\n\t\t\tassert_dbg();\n\t\t\t//cfInstr->getField_COND() == LatteCFInstruction::CF_COND::CF_COND_ACTIVE;\n\t\t}\n\t\telse if (const auto cfInstr = baseInstr->getParserIfOpcodeMatch<LatteCFInstruction_ALU>())\n\t\t{\n\t\t\t// always merge ALU clauses since they dont have their own condition modes?\n\t\t\t// todo - except if they are a jump target\n\t\t\tcanMerge = true;\n\t\t\tisALU = true;\n\t\t}\n\t\telse if (const auto cfInstr = baseInstr->getParserIfOpcodeMatch<LatteCFInstruction_EXPORT_IMPORT>())\n\t\t{\n\t\t\t// no extra conditions, always merge\n\t\t\tcanMerge = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebug_printf(\"Missing implementation for CF opcode 0x%02x\\n\", baseInstr->getField_Opcode());\n\t\t\tassert_dbg(); // todo\n\t\t}\n\n\t\tif (canMerge)\n\t\t{\n\t\t\tactiveNode->addInstruction(*baseInstr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tactiveNode->setNextAddress((uint32)cfIndex - 1);\n\t\t\tnodeDAG.m_nodes.emplace_back(activeNode);\n\t\t\t// start new active node\n\t\t\tactiveNode = new CFBlockNode((uint32)cfIndex - 1, *baseInstr);\n\t\t}\n\n\t\tif (!isALU && baseInstr->getField_END_OF_PROGRAM())\n\t\t\tbreak;\n\t}\n\t// finalize last node\n\tcemu_assert_debug(!activeNode->m_cfInstructions.empty());\n\tnodeDAG.m_nodes.emplace_back(activeNode);\n}\n\nvoid LatteTCGenIR::parseCFToDAG()\n{\n\t// parse CF and create preliminary node DAG\n\tparseCF_createNodes(m_ctx.mainFunctionDAG);\n\t// link up the nodes\n\tcemu_assert_debug(m_ctx.mainFunctionDAG.m_nodes.size() == 1);\n\t// assign to ir object\n\tfor (auto& itr : m_ctx.mainFunctionDAG.m_nodes)\n\t\tm_ctx.irObject->m_basicBlocks.emplace_back(itr->irBasicBlock);\n\tm_ctx.irObject->m_entryBlocks.emplace_back(m_ctx.mainFunctionDAG.m_nodes[0]->irBasicBlock);\n}\n\nvoid LatteTCGenIR::emitIR()\n{\n\tcemu_assert_debug(m_ctx.mainFunctionDAG.m_nodes.size() == 1);\n\n\tfor (auto& itr : m_ctx.mainFunctionDAG.m_nodes)\n\t{\n\t\tgenIRForNode(*itr);\n\t}\n\n}\n\nvoid LatteTCGenIR::cleanup()\n{\n\t// clean up\n\t//for (auto itr : m_ctx.list_irNodesCtx)\n\t//\tdelete itr;\n\t//m_ctx.list_irNodesCtx.clear();\n}\n\nvoid LatteTCGenIR::setVertexShaderContext(const LatteFetchShader* parsedFetchShader, const uint32* vtxSemanticTable)\n{\n\tm_vertexShaderCtx.parsedFetchShader = parsedFetchShader;\n\tm_vertexShaderCtx.vtxSemanticTable = vtxSemanticTable;\n}\n\n\nZpIR::ZpIRFunction* LatteTCGenIR::transcompileLatteToIR(const void* programData, uint32 programSize, SHADER_TYPE shaderType)\n{\n\t//return nullptr;\n\tZpIR::ZpIRFunction* irObject = new ZpIR::ZpIRFunction();\n\n\t// init context\n\tm_ctx = {};\n\tm_ctx.programData = (const uint32*)programData;\n\tm_ctx.programSize = programSize;\n\tm_ctx.irObject = irObject;\n\tm_ctx.shaderType = shaderType;\n\n\t// parse control flow instructions and convert it to list of CFBlockNode\n\t// each node is a single IR basic block, consisting of one or multiple CF instructions\n\tparseCFToDAG();\n\t// process clauses and emit IR nodes\n\temitIR();\n\t// cleanup\n\tcleanup();\n\treturn irObject;\n}"
  },
  {
    "path": "src/Cafe/HW/Latte/Transcompiler/LatteTC.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/ISA/LatteInstructions.h\"\n#include \"Cafe/HW/Latte/Core/FetchShader.h\"\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"util/Zir/Core/IR.h\"\n\n#include <boost/container/static_vector.hpp>\n\nnamespace ZpIR\n{\n\tclass BasicBlockBuilder;\n}\n\n// transforms GPU7/Latte shader binaries into an SSA IR (ZpIR) representation\nclass LatteTCGenIR\n{\n\t//friend class CFNodeInfo;\n\tfriend struct CFNodeInfo_CALL_FS;\nprivate:\n\tstruct NodeDAG // one per function (shaders usually have main only)\n\t{\n\t\tstd::vector<class CFBlockNode*> m_nodes;\n\t\t// class CFBlockNode* entrypoint;\n\n\t\tclass CFBlockNode* GetEntryNode()\n\t\t{\n\t\t\treturn m_nodes[0];\n\t\t}\n\t};\n\t\npublic:\n\ttypedef unsigned short GPRElementIndex; // grpIndex*4+channel\n\n\tenum SHADER_TYPE\n\t{\n\t\tVERTEX,\n\t\tGEOMETRY,\n\t\tPIXEL,\n\t};\n\n\tvoid setVertexShaderContext(const LatteFetchShader* parsedFetchShader, const uint32* vtxSemanticTable);\n\n\tZpIR::ZpIRFunction* transcompileLatteToIR(const void* programData, uint32 programSize, SHADER_TYPE shaderType);\n\nprivate:\n\tZpIR::IRReg getIRRegFromGPRElement(uint32 gprIndex, uint32 channel, ZpIR::DataType typeHint);\n\tZpIR::IRReg getTypedIRRegFromGPRElement(uint32 gprIndex, uint32 channel, ZpIR::DataType type);\n\n\tZpIR::IRReg loadALUOperand(LatteALUSrcSel srcSel, uint8 srcChan, bool isNeg, bool isAbs, bool isRel, uint8 indexMode, const uint32* literalData, ZpIR::DataType typeHint, bool convertOnTypeMismatch);\n\tvoid emitALUGroup(const class LatteClauseInstruction_ALU* aluUnit[5], const uint32* literalData);\n\t\n\tvoid genIRForNode(class CFBlockNode& node);\n\n\tvoid parseCFToDAG();\n\tvoid parseCF_createNodes(NodeDAG& nodeDAG);\n\tvoid emitIR();\n\tvoid cleanup();\n\n\t// IR emitter\n\tvoid processCF_CALL_FS(const LatteCFInstruction_DEFAULT& cfInstruction);\n\tvoid processCF_ALU(const LatteCFInstruction_ALU& cfInstruction);\n\tvoid processCF_EXPORT(const LatteCFInstruction_EXPORT_IMPORT& cfInstruction);\n\n\t// helpers\n\tvoid CF_CALL_FS_emitFetchAttribute(LatteParsedFetchShaderAttribute_t& attribute, Latte::GPRType dstGPR);\n\nprivate:\n\t// tracks mapping GPR<->IR variable for current basic block\n\tstruct IREmitterActiveVars\n\t{\n\t\tbool get(uint32 gprIndex, uint32 channelIndex, ZpIR::IRReg& reg)\n\t\t{\n\t\t\tsize_t index = gprIndex * 4 + channelIndex;\n\t\t\tif (!m_present.test(index))\n\t\t\t\treturn false;\n\t\t\treg = m_irReg[index];\n\t\t\treturn true;\n\t\t}\n\n\t\tvoid set(uint32 gprIndex, uint32 channelIndex, ZpIR::IRReg reg)\n\t\t{\n\t\t\tsize_t index = gprIndex * 4 + channelIndex;\n\t\t\tm_present.set(index);\n\t\t\tm_irReg[index] = reg;\n\t\t}\n\n\t\t// set register after current group\n\t\tstruct DelayedAssignment\n\t\t{\n\t\t\tuint16 index;\n\t\t\tZpIR::IRReg reg;\n\t\t\tbool isSet{false};\n\t\t};\n\n\t\tstruct DelayedAssignmentPVPS\n\t\t{\n\t\t\tZpIR::IRReg reg;\n\t\t\tbool isSet{ false };\n\t\t};\n\n\t\tvoid setAfterGroup(uint8 aluUnit, uint32 gprIndex, uint32 channelIndex, ZpIR::IRReg reg)\n\t\t{\n\t\t\tcemu_assert_debug(aluUnit < 5);\n\t\t\tcemu_assert_debug(!m_delayedAssignments[aluUnit].isSet);\n\t\t\tm_delayedAssignments[aluUnit].reg = reg;\n\t\t\tm_delayedAssignments[aluUnit].index = gprIndex * 4 + channelIndex;\n\t\t\tm_delayedAssignments[aluUnit].isSet = true;\n\t\t}\n\n\t\tvoid setAfterGroupPVPS(uint8 aluUnit, ZpIR::IRReg reg)\n\t\t{\n\t\t\tcemu_assert_debug(aluUnit < 5);\n\t\t\tcemu_assert_debug(!m_delayedAssignmentsPSPV[aluUnit].isSet);\n\t\t\tm_delayedAssignmentsPSPV[aluUnit].reg = reg;\n\t\t\tm_delayedAssignmentsPSPV[aluUnit].isSet = true;\n\t\t}\n\n\t\tvoid applyDelayedAfterGroup()\n\t\t{\n\t\t\t// GPRs\n\t\t\tfor (size_t i = 0; i < 5; i++)\n\t\t\t{\n\t\t\t\tauto& assignment = m_delayedAssignments[i];\n\t\t\t\tif(!assignment.isSet)\n\t\t\t\t\tcontinue;\n\t\t\t\tsetGPR(assignment.index, assignment.reg);\n\t\t\t\tassignment.isSet = false;\n\t\t\t}\n\t\t\t// PV/PS\n\t\t\tfor (size_t i = 0; i < 5; i++)\n\t\t\t{\n\t\t\t\tauto& assignment = m_delayedAssignmentsPSPV[i];\n\t\t\t\tif (!assignment.isSet)\n\t\t\t\t\tcontinue;\n\t\t\t\tsetPVPS((uint32)i, assignment.reg);\n\t\t\t\tassignment.isSet = false;\n\t\t\t}\n\t\t}\n\n\t\tvoid reset()\n\t\t{\n\t\t\tm_present.reset();\n\t\t}\n\n\tprivate:\n\t\tvoid setGPR(uint32 gprChannelindex, ZpIR::IRReg reg)\n\t\t{\n\t\t\tm_present.set(gprChannelindex);\n\t\t\tm_irReg[gprChannelindex] = reg;\n\t\t}\n\n\t\tvoid setPVPS(uint32 unitIndex, ZpIR::IRReg reg)\n\t\t{\n\t\t\tm_presentPVPS.set(unitIndex);\n\t\t\tm_irRegPVPS[unitIndex] = reg;\n\t\t}\n\n\t\tZpIR::IRReg m_irReg[128 * 4]{};\n\t\tZpIR::IRReg m_irRegPVPS[5]{};\n\t\tstd::bitset<128 * 4> m_present;\n\t\tstd::bitset<5> m_presentPVPS;\n\t\tDelayedAssignment m_delayedAssignments[5]{};\n\t\tDelayedAssignmentPVPS m_delayedAssignmentsPSPV[5]{};\n\t};\n\n\tstruct\n\t{\n\t\tIREmitterActiveVars activeVars;\n\t\tZpIR::BasicBlockBuilder* irBuilder;\n\t\tbool isEntryBasicBlock{};\n\n\t\tvoid reset()\n\t\t{\n\t\t\tactiveVars.reset();\n\t\t}\n\t}m_irGenContext;\n\n\tstruct  \n\t{\n\t\tconst uint32* programData;\n\t\tuint32 programSize;\n\t\t//std::vector<struct CFNodeInfo*> list_irNodesCtx;\n\t\t// first node in flow of main() function\n\t\t//struct CFNodeInfo* mainEntry;\n\t\t\n\t\tSHADER_TYPE shaderType;\n\n\t\tNodeDAG mainFunctionDAG;\n\t\t// current IR object\n\t\tstruct ZpIR::ZpIRFunction* irObject;\n\t}m_ctx;\n\n\n\t// vertex shader info\n\tstruct\n\t{\n\t\tconst LatteFetchShader* parsedFetchShader{};\n\t\tconst uint32* vtxSemanticTable{};\n\t}m_vertexShaderCtx{};\n};\n"
  },
  {
    "path": "src/Cafe/HW/Latte/Transcompiler/LatteTCGenIR.cpp",
    "content": "#include \"Cafe/HW/Latte/Transcompiler/LatteTC.h\"\n#include \"Cafe/HW/Latte/ISA/LatteInstructions.h\"\n#include \"util/Zir/Core/ZpIRBuilder.h\"\n\nvoid LatteTCGenIR::CF_CALL_FS_emitFetchAttribute(LatteParsedFetchShaderAttribute_t& attribute, Latte::GPRType dstGPR)\n{\n\tauto irBuilder = m_irGenContext.irBuilder;\n\n\t// extract each channel\n\tfor (sint32 t = 0; t < 4; t++)\n\t{\n\t\tuint32 gprElementIndex = (uint32)dstGPR * 4 + t;\n\t\tLatteConst::VertexFetchDstSel ds = (LatteConst::VertexFetchDstSel)attribute.ds[t];\n\n\t\tswitch (ds)\n\t\t{\n\t\tcase LatteConst::VertexFetchDstSel::X:\n\t\tcase LatteConst::VertexFetchDstSel::Y:\n\t\tcase LatteConst::VertexFetchDstSel::Z:\n\t\tcase LatteConst::VertexFetchDstSel::W:\n\t\t{\n\t\t\tuint8 channelIndex = (uint8)((uint32)ds - (uint32)LatteConst::VertexFetchDstSel::X);\n\n\t\t\tZpIR::IRReg resultHolder = m_irGenContext.irBuilder->createReg(ZpIR::DataType::U32);\n\t\t\tZpIR::LocationSymbolName importSource = ZpIR::ShaderSubset::ShaderImportLocation().SetVertexAttribute(attribute.semanticId, channelIndex);\n\t\t\tm_irGenContext.irBuilder->emit_IMPORT(importSource, resultHolder);\n\n\t\t\t// swap endianness\n\t\t\tif (attribute.endianSwap == LatteConst::VertexFetchEndianMode::SWAP_U32)\n\t\t\t{\n\t\t\t\t// todo - this may be more complex depending on type\n\t\t\t\tZpIR::IRReg elementResult;\n\t\t\t\tirBuilder->emit_RR(ZpIR::IR::OpCode::SWAP_ENDIAN, irBuilder->createReg(elementResult, ZpIR::DataType::U32), resultHolder);\n\t\t\t\tresultHolder = elementResult;\n\t\t\t}\n\n\t\t\tbool isSigned = attribute.isSigned;\n\n\t\t\t// transform\n\t\t\tLatteConst::VertexFetchFormat fmt = (LatteConst::VertexFetchFormat)attribute.format;\n\t\t\tLatteClauseInstruction_VTX::NUM_FORMAT_ALL nfa = (LatteClauseInstruction_VTX::NUM_FORMAT_ALL)attribute.nfa;\n\n\t\t\tif (fmt == LatteConst::VertexFetchFormat::VTX_FMT_32_32_32_FLOAT ||\n\t\t\t\tfmt == LatteConst::VertexFetchFormat::VTX_FMT_32_32_FLOAT)\n\t\t\t{\n\t\t\t\tuint32 numComp;\n\t\t\t\tif (fmt == LatteConst::VertexFetchFormat::VTX_FMT_32_32_32_FLOAT)\n\t\t\t\t\tnumComp = 3;\n\t\t\t\telse if (fmt == LatteConst::VertexFetchFormat::VTX_FMT_32_32_FLOAT)\n\t\t\t\t\tnumComp = 2;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t}\n\n\t\t\t\tcemu_assert_debug(attribute.endianSwap == LatteConst::VertexFetchEndianMode::SWAP_U32);\n\t\t\t\tcemu_assert_debug(nfa == LatteClauseInstruction_VTX::NUM_FORMAT_ALL::NUM_FORMAT_SCALED);\n\t\t\t\tcemu_assert_debug(channelIndex < numComp);\n\n\t\t\t\tZpIR::IRReg elementResult;\n\t\t\t\tirBuilder->emit_RR(ZpIR::IR::OpCode::BITCAST, irBuilder->createReg(elementResult, ZpIR::DataType::F32), resultHolder);\n\t\t\t\tresultHolder = elementResult;\n\t\t\t}\n\t\t\telse if (fmt == LatteConst::VertexFetchFormat::VTX_FMT_8_8_8_8)\n\t\t\t{\n\t\t\t\tuint32 numComp;\n\t\t\t\tswitch (fmt)\n\t\t\t\t{\n\t\t\t\tcase LatteConst::VertexFetchFormat::VTX_FMT_8_8_8_8:\n\t\t\t\t\tnumComp = 4;\n\t\t\t\t\tbreak;\n\t\t\t\tcase LatteConst::VertexFetchFormat::VTX_FMT_8_8_8:\n\t\t\t\t\tnumComp = 3;\n\t\t\t\t\tbreak;\n\t\t\t\tcase LatteConst::VertexFetchFormat::VTX_FMT_8_8:\n\t\t\t\t\tnumComp = 2;\n\t\t\t\t\tbreak;\n\t\t\t\tcase LatteConst::VertexFetchFormat::VTX_FMT_8:\n\t\t\t\t\tnumComp = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcemu_assert_debug(attribute.endianSwap == LatteConst::VertexFetchEndianMode::SWAP_NONE);\n\t\t\t\tcemu_assert_debug(channelIndex < numComp);\n\n\t\t\t\tif (nfa == LatteClauseInstruction_VTX::NUM_FORMAT_ALL::NUM_FORMAT_NORM)\n\t\t\t\t{\n\t\t\t\t\t// scaled\n\t\t\t\t\tif (isSigned)\n\t\t\t\t\t{\n\t\t\t\t\t\tassert_dbg();\n\t\t\t\t\t\t// we can fake sign extend by subtracting 128? Would be faster than the AND + Conditional OR\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tresultHolder = irBuilder->emit_RR(ZpIR::IR::OpCode::CONVERT_INT_TO_FLOAT, ZpIR::DataType::F32, resultHolder);\n\t\t\t\t\t\tresultHolder = irBuilder->emit_RRR(ZpIR::IR::OpCode::DIV, ZpIR::DataType::F32, resultHolder, irBuilder->createConstF32(255.0f));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tassert_dbg();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tassert_dbg();\n\t\t\t}\n\n\t\t\t// todo - we need a sign-extend instruction for this which should take arbitrary bit count\n\n\n\t\t\tthis->m_irGenContext.activeVars.set(dstGPR, t, resultHolder); // set GPR.channel to the result\n\t\t\tbreak;\n\t\t}\n\t\tcase LatteConst::VertexFetchDstSel::CONST_0F:\n\t\t{\n\t\t\t// todo - this could also be an integer zero. Use attribute format / other channel info to determine if this type is integer/float\n\t\t\tZpIR::IRReg resultHolder;\n\t\t\tirBuilder->emit_RR(ZpIR::IR::OpCode::MOV, irBuilder->createReg(resultHolder, ZpIR::DataType::F32), irBuilder->createConstF32(0.0f));\n\t\t\tthis->m_irGenContext.activeVars.set(dstGPR, t, resultHolder);\n\t\t\tbreak;\n\t\t}\n\t\tcase LatteConst::VertexFetchDstSel::CONST_1F:\n\t\t{\n\t\t\tZpIR::IRReg resultHolder;\n\t\t\tirBuilder->emit_RR(ZpIR::IR::OpCode::MOV, irBuilder->createReg(resultHolder, ZpIR::DataType::F32), irBuilder->createConstF32(1.0f));\n\t\t\tthis->m_irGenContext.activeVars.set(dstGPR, t, resultHolder);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tassert_dbg();\n\t\t}\n\t}\n}\n\nvoid LatteTCGenIR::processCF_CALL_FS(const LatteCFInstruction_DEFAULT& cfInstruction)\n{\n\tauto fetchShader = m_vertexShaderCtx.parsedFetchShader;\n\tauto semanticTable = m_vertexShaderCtx.vtxSemanticTable;\n\n\t// generate IR to decode vertex attributes\n\tcemu_assert_debug(fetchShader->bufferGroupsInvalid.size() == 0); // todo\n\tfor(auto& bufferGroup : fetchShader->bufferGroups)\n\t{\n\t\tfor (sint32 i = 0; i < bufferGroup.attribCount; i++)\n\t\t{\n\t\t\tauto& attribute = bufferGroup.attrib[i];\n\n\t\t\tuint32 dstGPR = 0;\n\t\t\t// get register index based on vtx semantic table\n\t\t\tuint32 attributeShaderLoc = 0xFFFFFFFF;\n\t\t\tfor (sint32 f = 0; f < 32; f++)\n\t\t\t{\n\t\t\t\tif (semanticTable[f] == attribute.semanticId)\n\t\t\t\t{\n\t\t\t\t\tattributeShaderLoc = f;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (attributeShaderLoc == 0xFFFFFFFF)\n\t\t\t\tcontinue; // attribute is not mapped to VS input\n\t\t\tdstGPR = attributeShaderLoc + 1; // R0 is skipped\n\n\t\t\t// emit IR code for attribute import (decode into GPR)\n\t\t\tCF_CALL_FS_emitFetchAttribute(attribute, dstGPR);\n\t\t}\n\t}\n}\n\n// get IRReg for Latte GPR (single channel) typeHint is used when register has to be imported\n// if convertOnTypeMismatch is set then we bitcast the register on type mismatch\nZpIR::IRReg LatteTCGenIR::getIRRegFromGPRElement(uint32 gprIndex, uint32 channel, ZpIR::DataType typeHint)\n{\n\t// get IR register for <GPR>.<channel> from currently active context\n\tZpIR::IRReg r;\n\tif (m_irGenContext.activeVars.get(gprIndex, channel, r))\n\t\treturn r;\n\n\t// if GPR.channel is not known\n\t// in the entry basic block we can assume a value of zero because there is nowhere to import from\n\tif (m_irGenContext.isEntryBasicBlock)\n\t{\n\t\tif (typeHint == ZpIR::DataType::F32)\n\t\t\treturn m_irGenContext.irBuilder->createConstF32(0.0f);\n\t\telse if (typeHint == ZpIR::DataType::U32)\n\t\t\treturn m_irGenContext.irBuilder->createConstU32(0);\n\t\telse if (typeHint == ZpIR::DataType::S32)\n\t\t\treturn m_irGenContext.irBuilder->createConstS32(0);\n\t\tcemu_assert_debug(false);\n\t}\n\n\t// otherwise create import and resolve later during register allocation\n\tr = m_irGenContext.irBuilder->createReg(typeHint);\n\tm_irGenContext.irBuilder->addImport(r, gprIndex*4 + channel);\n\n\treturn r;\n}\n\n// similar to getIRRegFromGPRElement() but will bitcast the type if it mismatches\nZpIR::IRReg LatteTCGenIR::getTypedIRRegFromGPRElement(uint32 gprIndex, uint32 channel, ZpIR::DataType type)\n{\n\tauto irReg = getIRRegFromGPRElement(gprIndex, channel, type);\n\tif (m_irGenContext.irBuilder->getRegType(irReg) == type)\n\t\treturn irReg;\n\t// type does not match, bitcast into new reg\n\tauto newReg = m_irGenContext.irBuilder->createReg(type);\n\tm_irGenContext.irBuilder->emit_RR(ZpIR::IR::OpCode::BITCAST, newReg, irReg);\n\t// remember converted register since its likely that it is accessed with the same type again\n\t// todo - ideally, we would keep track of all the types. But it has to be efficient\n\tm_irGenContext.activeVars.set(gprIndex, channel, newReg);\n\treturn newReg;\n}\n\n// try to determine the type of the constant from the raw u32 value\nZpIR::DataType _guessTypeFromConstantValue(uint32 bits)\n{\n\tif (bits == 0x3F800000) // float 1.0\n\t\treturn ZpIR::DataType::F32;\n\treturn ZpIR::DataType::S32;\n}\n\n// maybe pass a type hint parameter\nZpIR::IRReg LatteTCGenIR::loadALUOperand(LatteALUSrcSel srcSel, uint8 srcChan, bool isNeg, bool isAbs, bool isRel, uint8 indexMode, const uint32* literalData, ZpIR::DataType typeHint, bool convertOnTypeMismatch)\n{\n\tif (srcSel.isGPR())\n\t{\n\t\t//LatteTCGenIR::GPRElement gprElement = srcSel.getGPR() * 4 + srcChan;\n\t\tif (isRel)\n\t\t\tassert_dbg();\n\n\t\tZpIR::IRReg reg;\n\t\t\n\t\tif(convertOnTypeMismatch)\n\t\t\treg = getTypedIRRegFromGPRElement(srcSel.getGPR(), srcChan, typeHint);\n\t\telse\n\t\t\treg = getIRRegFromGPRElement(srcSel.getGPR(), srcChan, typeHint);\n\n\t\t// if additional transformations are applied then we create a temporary IRReg here\n\t\t// todo - is caching&recycling the transformed registers worth it?\n\t\tif (isAbs || isNeg)\n\t\t{\n\t\t\t// create new var and apply transformation\n\t\t\tassert_dbg();\n\t\t}\n\n\t\treturn reg;\n\t}\n\telse if (srcSel.isAnyConst())\n\t{\n\t\tif (srcSel.isConst_0F())\n\t\t{\n\t\t\treturn m_irGenContext.irBuilder->createConstF32(0.0f); // todo - could also be integer type constant? Try to find a way to predict the type correctly\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n\telse if (srcSel.isLiteral())\n\t{\n\t\t// literal constant\n\t\t// we guess the type\n\t\treturn m_irGenContext.irBuilder->createTypedConst(literalData[srcChan], _guessTypeFromConstantValue(literalData[srcChan]));\n\t}\n\telse if (srcSel.isCFile())\n\t{\n\t\t// constant registers / uniform registers\n\t\tuint32 cfileIndex = srcSel.getCFile();\n\t\tauto newReg = m_irGenContext.irBuilder->createReg(typeHint);\n\t\tZpIR::LocationSymbolName importSource = ZpIR::ShaderSubset::ShaderImportLocation().SetUniformRegister(cfileIndex*4 + srcChan);\n\t\tm_irGenContext.irBuilder->emit_IMPORT(importSource, newReg);\n\t\treturn newReg;\n\t}\n\telse\n\t\tassert_dbg();\n\n\treturn 0;\n}\n\nvoid LatteTCGenIR::emitALUGroup(const LatteClauseInstruction_ALU* aluUnit[5], const uint32* literalData)\n{\n\t//struct\n\t//{\n\t//\tuint32 gprElementIndex;\n\t//\tZpIR::IRReg irReg;\n\t//\tbool isSet;\n\t//}groupOutput[5] = {};\n\n\tZpIR::BasicBlockBuilder* irBuilder = m_irGenContext.irBuilder;\n\n\t// used by MOV instruction which can be used with any 32bit type (float, int, uint)\n\tauto getMOVSourceType = [&](const LatteClauseInstruction_ALU_OP2* instrOP2) -> ZpIR::DataType\n\t{\n\t\tauto sel = instrOP2->getSrc0Sel();\n\t\tif (sel.isGPR())\n\t\t{\n\t\t\tZpIR::IRReg r;\n\t\t\tif (!m_irGenContext.activeVars.get(sel.getGPR(), instrOP2->getSrc0Chan(), r))\n\t\t\t{\n\t\t\t\t// import, do we have an alternative way to guess the type?\n\t\t\t\t// for now lets assume float because it will be correct more often than not\n\t\t\t\t// getting the type wrong means a temporary register and two bit cast instructions will be spawned\n\t\t\t\treturn ZpIR::DataType::F32;\n\t\t\t}\n\t\t\treturn m_irGenContext.irBuilder->getRegType(r);\n\t\t}\n\t\telse if (sel.isLiteral())\n\t\t{\n\t\t\treturn _guessTypeFromConstantValue(literalData[instrOP2->getSrc0Chan()]);\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t\treturn ZpIR::DataType::S32;\n\t};\n\n\tauto getOp0Reg = [&](const LatteClauseInstruction_ALU_OP2* instrOP2, ZpIR::DataType type) -> ZpIR::IRReg\n\t{\n\t\t// todo - pass type hint, so internally correct type is used if register needs to be created\n\t\tZpIR::IRReg r = loadALUOperand(instrOP2->getSrc0Sel(), instrOP2->getSrc0Chan(), instrOP2->isSrc0Neg(), false, instrOP2->isSrc0Rel(), instrOP2->getIndexMode(), literalData, type, true);\n\t\t// make sure type matches with 'type' (loadALUOperand should convert)\n\t\tcemu_assert_debug(irBuilder->getRegType(r) == type);\n\t\treturn r;\n\t};\n\n\tauto getOp1Reg = [&](const LatteClauseInstruction_ALU_OP2* instrOP2, ZpIR::DataType type) -> ZpIR::IRReg\n\t{\n\t\t// todo - pass type hint, so internally correct type is used if register needs to be created\n\t\tZpIR::IRReg r = loadALUOperand(instrOP2->getSrc1Sel(), instrOP2->getSrc1Chan(), instrOP2->isSrc1Neg(), false, instrOP2->isSrc1Rel(), instrOP2->getIndexMode(), literalData, type, true);\n\t\t// make sure type matches with 'type' (loadALUOperand should convert)\n\t\tcemu_assert_debug(irBuilder->getRegType(r) == type);\n\t\treturn r;\n\t};\n\n\tauto getResultReg = [&](uint8 aluUnit, const LatteClauseInstruction_ALU_OP2* instrOP2, ZpIR::DataType type) -> ZpIR::IRReg\n\t{\n\t\t// create output register\n\t\tZpIR::IRReg r = m_irGenContext.irBuilder->createReg(type);\n\n\t\tcemu_assert_debug(instrOP2->getDestClamp() == 0); // todo\n\t\tcemu_assert_debug(instrOP2->getDestRel() == 0); // todo\n\t\tcemu_assert_debug(instrOP2->getOMod() == 0); // todo\n\n\t\tif (instrOP2->getWriteMask())\n\t\t{\n\t\t\t// output to GPR\n\t\t\tm_irGenContext.activeVars.setAfterGroup(aluUnit, instrOP2->getDestGpr(), instrOP2->getDestElem(), r);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// output only to PV/PS\n\t\t\tassert_dbg();\n\t\t}\n\t\t// output to PV/PS\n\t\t// todo\n\n\t\t// check for disabled destination GPR?\n\n\t\t// also assign PV/PS\n\t\t// todo\n\n\t\t//ZpIR::IRReg r;\n\t\t//if (m_irGenContext.activeVars.get(gprIndex, channel, r))\n\t\t//\treturn r;\n\n\t\t//// if GPR not present then create import for it\n\t\t//r = m_irGenContext.irBuilder->createReg(typeHint);\n\t\t//m_irGenContext.irBuilder->addImport(r, 0x12345678);\n\n\t\treturn r;\n\t};\n\n\tfor (sint32 aluUnitIndex = 0; aluUnitIndex < 5; aluUnitIndex++)\n\t{\n\t\tconst LatteClauseInstruction_ALU* instr = aluUnit[aluUnitIndex];\n\t\tif (instr == nullptr)\n\t\t\tcontinue;\n\t\tif (instr->isOP3())\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto opcode2 = instr->getOP2Code();\n\t\t\tauto instrOP2 = instr->getOP2Instruction();\n\n\t\t\t// prepare operands, load them into IRVars if they aren't already\n\t\t\tuint8 indexMode = instrOP2->getIndexMode();\n\n\t\t\tswitch (opcode2)\n\t\t\t{\n\t\t\tcase LatteClauseInstruction_ALU::OPCODE_OP2::MUL:\n\t\t\tcase LatteClauseInstruction_ALU::OPCODE_OP2::MUL_IEEE:\n\t\t\t{\n\t\t\t\t// how to implement this with least amount of copy paste and still having very good performance?\n\t\t\t\t// maybe use lambdas? Or functions?\n\t\t\t\tirBuilder->emit_RRR(ZpIR::IR::OpCode::MUL, getResultReg(aluUnitIndex, instrOP2, ZpIR::DataType::F32), getOp0Reg(instrOP2, ZpIR::DataType::F32), getOp1Reg(instrOP2, ZpIR::DataType::F32));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase LatteClauseInstruction_ALU::OPCODE_OP2::MOV:\n\t\t\t{\n\t\t\t\t// MOV is type-agnostic, but some flags might make it apply float operations\n\t\t\t\tZpIR::DataType guessedType = getMOVSourceType(instrOP2);\n\n\t\t\t\tirBuilder->emit_RR(ZpIR::IR::OpCode::MOV, getResultReg(aluUnitIndex, instrOP2, guessedType), getOp0Reg(instrOP2, guessedType));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase LatteClauseInstruction_ALU::OPCODE_OP2::DOT4:\n\t\t\t{\n\t\t\t\t// reduction opcode\n\t\t\t\t// must be mirrored to .xyzw units\n\t\t\t\tcemu_assert_debug(aluUnitIndex == 0);\n\t\t\t\tcemu_assert_debug(aluUnit[0]->getOP2Code() == aluUnit[1]->getOP2Code());\n\t\t\t\tcemu_assert_debug(aluUnit[1]->getOP2Code() == aluUnit[2]->getOP2Code());\n\t\t\t\tcemu_assert_debug(aluUnit[2]->getOP2Code() == aluUnit[3]->getOP2Code());\n\n\t\t\t\tauto unit_x = instrOP2;\n\t\t\t\tauto unit_y = aluUnit[1]->getOP2Instruction();\n\t\t\t\tauto unit_z = aluUnit[2]->getOP2Instruction();\n\t\t\t\tauto unit_w = aluUnit[3]->getOP2Instruction();\n\n\t\t\t\tcemu_assert_debug(unit_x->getDestClamp() == false);\n\t\t\t\tcemu_assert_debug(unit_x->getOMod() == 0);\n\t\t\t\tcemu_assert_debug(unit_x->getDestRel() == false);\n\n\t\t\t\tZpIR::IRReg productX = irBuilder->emit_RRR(ZpIR::IR::OpCode::MUL, ZpIR::DataType::F32, getOp0Reg(unit_x, ZpIR::DataType::F32), getOp1Reg(unit_x, ZpIR::DataType::F32));\n\t\t\t\tZpIR::IRReg productY = irBuilder->emit_RRR(ZpIR::IR::OpCode::MUL, ZpIR::DataType::F32, getOp0Reg(unit_y, ZpIR::DataType::F32), getOp1Reg(unit_y, ZpIR::DataType::F32));\n\t\t\t\tZpIR::IRReg productZ = irBuilder->emit_RRR(ZpIR::IR::OpCode::MUL, ZpIR::DataType::F32, getOp0Reg(unit_z, ZpIR::DataType::F32), getOp1Reg(unit_z, ZpIR::DataType::F32));\n\t\t\t\tZpIR::IRReg productW = irBuilder->emit_RRR(ZpIR::IR::OpCode::MUL, ZpIR::DataType::F32, getOp0Reg(unit_w, ZpIR::DataType::F32), getOp1Reg(unit_w, ZpIR::DataType::F32));\n\n\t\t\t\tZpIR::IRReg sum = irBuilder->emit_RRR(ZpIR::IR::OpCode::ADD, ZpIR::DataType::F32, productX, productY);\n\t\t\t\tsum = irBuilder->emit_RRR(ZpIR::IR::OpCode::ADD, ZpIR::DataType::F32, sum, productZ);\n\t\t\t\tsum = irBuilder->emit_RRR(ZpIR::IR::OpCode::ADD, ZpIR::DataType::F32, sum, productW);\n\n\t\t\t\t// assign result\n\t\t\t\tif (unit_x->getWriteMask())\n\t\t\t\t\tm_irGenContext.activeVars.setAfterGroup(0, unit_x->getDestGpr(), unit_x->getDestElem(), sum);\n\t\t\t\tif (unit_y->getWriteMask())\n\t\t\t\t\tm_irGenContext.activeVars.setAfterGroup(1, unit_y->getDestGpr(), unit_y->getDestElem(), sum);\n\t\t\t\tif (unit_z->getWriteMask())\n\t\t\t\t\tm_irGenContext.activeVars.setAfterGroup(2, unit_z->getDestGpr(), unit_z->getDestElem(), sum);\n\t\t\t\tif (unit_w->getWriteMask())\n\t\t\t\t\tm_irGenContext.activeVars.setAfterGroup(3, unit_w->getDestGpr(), unit_w->getDestElem(), sum);\n\n\t\t\t\t// also set result in PV.x\n\t\t\t\tm_irGenContext.activeVars.setAfterGroupPVPS(0, sum);\n\t\t\t\t// todo - do we need to update the other units?\n\n\t\t\t\taluUnitIndex += 3;\n\t\t\t\tcontinue;;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tassert_dbg();\n\t\t\t}\n\n\t\t\t// handle dest clamp\n\t\t\tif (instrOP2->getDestClamp())\n\t\t\t{\n\t\t\t\tassert_dbg();\n\t\t\t}\n\n\t\t\t//uint32 src0Sel = (aluWord0 >> 0) & 0x1FF; // source selection\n\t\t\t//uint32 src1Sel = (aluWord0 >> 13) & 0x1FF;\n\t\t\t//uint32 src0Rel = (aluWord0 >> 9) & 0x1; // relative addressing mode\n\t\t\t//uint32 src1Rel = (aluWord0 >> 22) & 0x1;\n\t\t\t//uint32 src0Chan = (aluWord0 >> 10) & 0x3; // component selection x/y/z/w\n\t\t\t//uint32 src1Chan = (aluWord0 >> 23) & 0x3;\n\t\t\t//uint32 src0Neg = (aluWord0 >> 12) & 0x1; // negate input\n\t\t\t//uint32 src1Neg = (aluWord0 >> 25) & 0x1;\n\t\t\t//uint32 indexMode = (aluWord0 >> 26) & 7;\n\t\t\t//uint32 predSel = (aluWord0 >> 29) & 3;\n\n\t\t\t//uint32 src0Abs = (aluWord1 >> 0) & 1;\n\t\t\t//uint32 src1Abs = (aluWord1 >> 1) & 1;\n\t\t\t//uint32 updateExecuteMask = (aluWord1 >> 2) & 1;\n\t\t\t//uint32 updatePredicate = (aluWord1 >> 3) & 1;\n\t\t\t//uint32 writeMask = (aluWord1 >> 4) & 1;\n\t\t\t//uint32 omod = (aluWord1 >> 5) & 3;\n\n\t\t\t//uint32 destGpr = (aluWord1 >> 21) & 0x7F;\n\t\t\t//uint32 destRel = (aluWord1 >> 28) & 1;\n\t\t\t//uint32 destElem = (aluWord1 >> 29) & 3;\n\t\t\t//uint32 destClamp = (aluWord1 >> 31) & 1;\n\n\t\t}\n\t}\n\t// update IR vars with outputs from group\n\tm_irGenContext.activeVars.applyDelayedAfterGroup();\n}\n\nvoid LatteTCGenIR::processCF_ALU(const LatteCFInstruction_ALU& cfInstruction)\n{\n\tuint32 aluAddr = cfInstruction.getField_ADDR();\n\tuint32 aluCount = cfInstruction.getField_COUNT();\n\n\tconst uint32* clauseCode = m_ctx.programData + aluAddr * 2;\n\tuint32 clauseLength = aluCount;\n\t\n\tconst LatteClauseInstruction_ALU* aluCode = (const LatteClauseInstruction_ALU*)clauseCode;\n\t\n\tconst LatteClauseInstruction_ALU* aluUnit[5] = {};\n\t\n\tconst LatteClauseInstruction_ALU* instr = aluCode;\n\tconst LatteClauseInstruction_ALU* instrLast = aluCode + clauseLength;\n\t\n\t// process instructions in groups\n\tuint8 literalMask = 0;\n\twhile (instr < instrLast)\n\t{\n\t\tif (instr->isOP3())\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tLatteClauseInstruction_ALU::OPCODE_OP2 opcode2 = instr->getOP2Code();\n\t\t\tconst LatteClauseInstruction_ALU_OP2* op = instr->getOP2Instruction();\n\t\t\tuint32 unitIndex = 0;\n\t\t\tif (op->isTranscedentalUnit())\n\t\t\t\tunitIndex = 4;\n\t\t\telse\n\t\t\t{\n\t\t\t\tunitIndex = op->getDestElem();\n\t\t\t\tif (aluUnit[unitIndex]) // unit already occupied, use transcendental unit instead\n\t\t\t\t\tunitIndex = 4;\n\t\t\t}\n\t\t\tcemu_assert_debug(!aluUnit[unitIndex]); // unit already used\n\t\t\taluUnit[unitIndex] = op;\n\t\n\t\t\t// check for literal access\n\t\t\tif (op->getSrc0Sel().isLiteral())\n\t\t\t\tliteralMask |= (op->getSrc0Chan() >= 2 ? 2 : 1);\n\t\t\tif (op->getSrc1Sel().isLiteral())\n\t\t\t\tliteralMask |= (op->getSrc1Chan() >= 2 ? 2 : 1);\n\t\t}\n\t\n\t\tif (instr->isLastInGroup())\n\t\t{\n\t\t\t// emit code for group\n\t\t\t// extract literal constants\n\t\t\tconst uint32* literalData = nullptr;\n\t\t\tif (literalMask)\n\t\t\t{\n\t\t\t\tliteralData = (const uint32*)(instr + 1);\n\t\t\t\tif (literalMask & 2)\n\t\t\t\t\tinstr += 2;\n\t\t\t\telse\n\t\t\t\t\tinstr += 1;\n\t\t\t\tif ((instr + 1) > instrLast)\n\t\t\t\t\tassert_dbg(); // out of bounds\n\t\t\t}\n\t\t\t// generate code for group\n\t\t\temitALUGroup(aluUnit, literalData);\n\t\t\t// reset group\n\t\t\tstd::fill(aluUnit, aluUnit + 5, nullptr);\n\t\t\tliteralMask = 0;\n\t\t}\n\t\tinstr++;\n\t}\n\tif (aluUnit[0] || aluUnit[1] || aluUnit[2] || aluUnit[3] || aluUnit[4])\n\t\tassert_dbg();\n}\n\nvoid LatteTCGenIR::processCF_EXPORT(const LatteCFInstruction_EXPORT_IMPORT& cfInstruction)\n{\n\tauto exportType = cfInstruction.getField_TYPE();\n\n\tcemu_assert_debug(cfInstruction.getField_BURST_COUNT() == 1); // todo\n\n\tuint32 arrayBase = cfInstruction.getField_ARRAY_BASE();\n\n\tcemu_assert_debug(cfInstruction.isEncodingBUF() == false); // todo\n\n\tLatteCFInstruction_EXPORT_IMPORT::COMPSEL sel[4];\n\tsel[0] = cfInstruction.getSwizField_SEL_X();\n\tsel[1] = cfInstruction.getSwizField_SEL_Y();\n\tsel[2] = cfInstruction.getSwizField_SEL_Z();\n\tsel[3] = cfInstruction.getSwizField_SEL_W();\n\n\tuint32 sourceGPR = cfInstruction.getField_RW_GPR();\n\n\tZpIR::DataType typeHint;\n\tif (exportType == LatteCFInstruction_EXPORT_IMPORT::EXPORT_TYPE::POSITION)\n\t\ttypeHint = ZpIR::DataType::F32;\n\telse if (exportType == LatteCFInstruction_EXPORT_IMPORT::EXPORT_TYPE::PARAMETER)\n\t{\n\t\t// todo - determine correct type for parameter\n\t\ttypeHint = ZpIR::DataType::F32;\n\t}\n\telse\n\t\tassert_dbg();\n\n\t// get xyzw registers\n\tZpIR::IRReg regArray[4];\n\tsize_t regExportCount = 0; // number of exported registers/channels, number of valid regArray entries\n\tfor (size_t i = 0; i < 4; i++)\n\t{\n\t\tswitch (sel[i])\n\t\t{\n\t\tcase LatteCFInstruction_EXPORT_IMPORT::COMPSEL::X:\n\t\tcase LatteCFInstruction_EXPORT_IMPORT::COMPSEL::Y:\n\t\tcase LatteCFInstruction_EXPORT_IMPORT::COMPSEL::Z:\n\t\tcase LatteCFInstruction_EXPORT_IMPORT::COMPSEL::W:\n\t\t{\n\t\t\tuint32 channelIndex = (uint32)sel[i];\n\t\t\tregArray[regExportCount] = getTypedIRRegFromGPRElement(sourceGPR, channelIndex, typeHint);\n\t\t\tregExportCount++;\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tassert_dbg();\n\t\t\tbreak;\n\t\t}\n\t\t}\n\t\t//ZpIR::IRReg r;\n\t\t//if (m_irGenContext.activeVars.get(gprIndex, channel, r))\n\t\t//\treturn r;\n\t}\n\n\t//ZpIR::LocationSymbolName exportSymbolName;\n\tZpIR::ShaderSubset::ShaderExportLocation loc;\n\n\tif (exportType == LatteCFInstruction_EXPORT_IMPORT::EXPORT_TYPE::POSITION)\n\t{\n\t\tloc.SetPosition();\n\t}\n\telse if (exportType == LatteCFInstruction_EXPORT_IMPORT::EXPORT_TYPE::PARAMETER)\n\t{\n\t\tloc.SetOutputAttribute(arrayBase);\n\t\t//exportSymbolName = 0x20000 + arrayBase;\n\t}\n\telse\n\t{\n\t\t// todo\n\t\tassert_dbg();\n\t}\n\n\tcemu_assert_debug(regExportCount == 4); // todo - encode channel mask (e.g. xyz, xw, w, etc.) into export symbol name\n\n\tm_irGenContext.irBuilder->emit_EXPORT(loc, std::span(regArray, regArray + regExportCount));\n\n}\n"
  },
  {
    "path": "src/Cafe/HW/MMU/MMU.cpp",
    "content": "#include \"Cafe/HW/MMU/MMU.h\"\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"Cemu/Logging/CemuLogging.h\"\n#include \"WindowSystem.h\"\n#include \"util/MemMapper/MemMapper.h\"\n#include \"config/ActiveSettings.h\"\n\nuint8* memory_base = NULL; // base address of the reserved 4GB space\nuint8* memory_elfCodeArena = NULL;\n\nvoid checkMemAlloc(void* result)\n{\n\tif (result == nullptr)\n\t\tassert_dbg();\n}\n\nvoid memory_initPhysicalLayout()\n{\n\tassert_dbg();\n\t// todo - rewrite this using new MemMapper and MMU tables\n\t//memory_base = (uint8*)VirtualAlloc(NULL, 0x100000000ULL, MEM_RESERVE, PAGE_READWRITE);\n\t//VirtualFree(memory_base, 0, MEM_RELEASE);\n\n\t//// todo - figure out all the ranges and allocate them properly\n\n\t//// allocate memory for the kernel\n\t////checkMemAlloc(VirtualAlloc(memory_base + 0x08000000, 1024*1024*2, MEM_COMMIT, PAGE_READWRITE));\n\t//// allocate memory for bootrom\n\t//checkMemAlloc(VirtualAlloc(memory_base + 0x00000000, 1024*16, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE));\n\n\n\t//// allocate memory at 0x016FFFFC (is this some sort of register interface or maybe just temporary storage?)\n\t//checkMemAlloc(VirtualAlloc(memory_base + 0x016FF000, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));\n\n\t//// temporary storage for bootrom copy\n\t//checkMemAlloc(VirtualAlloc(memory_base + 0x016c0000, 0x4000 + 0x4000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));\n\t//// 0x016c0000\n\n\t//// L2\n\t//checkMemAlloc(VirtualAlloc(memory_base + 0xE0000000, 1024 * 16, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));\n\n\t//// kernel memory\n\t//// currently it is unknown if this is it's own physical memory region or if this is mapped somehow\n\t//// considering the ancast is never copied here and no memory mapping is setup it seems like a hardwired mirror to 0x08000000? \n\t////checkMemAlloc(VirtualAlloc(memory_base + 0xFFE00000, 0x180000, MEM_COMMIT, PAGE_READWRITE));\n\t//HANDLE hKernelMem = CreateFileMappingA(\n\t//\tINVALID_HANDLE_VALUE,    // use paging file\n\t//\tNULL,                    // default security\n\t//\tPAGE_READWRITE,          // read/write access\n\t//\t0,                       // maximum object size (high-order DWORD)\n\t//\t1024 * 1024 * 2,         // maximum object size (low-order DWORD)\n\t//\t\"kernelMem08000000\");    // name of mapping object\n\t//\n\t//checkMemAlloc(MapViewOfFileEx(hKernelMem, FILE_MAP_ALL_ACCESS, 0, 0, 1024 * 1024 * 2, memory_base + 0x08000000));\n\t//checkMemAlloc(MapViewOfFileEx(hKernelMem, FILE_MAP_ALL_ACCESS, 0, 0, 1024 * 1024 * 2, memory_base + 0xFFE00000));\n\n\t//// IOSU->PPC bootParamBlock\n\t//checkMemAlloc(VirtualAlloc(memory_base + 0x01FFF000, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));\n\n\t//// used as dynamic kernel memory?\n\t//checkMemAlloc(VirtualAlloc(memory_base + 0x1C000000, 0x01000000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));\n\n\t//// mapped by kernel to FF200000 (loader.elf?)\n\t//checkMemAlloc(VirtualAlloc(memory_base + 0x1B800000, 0x00800000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));\n}\n\nstd::vector<struct MMURange*> g_mmuRanges;\n\nstd::vector<MMURange*> memory_getMMURanges()\n{\n\treturn g_mmuRanges;\n}\n\nMMURange* memory_getMMURangeByAddress(MPTR address)\n{\n\tfor (auto& itr : g_mmuRanges)\n\t{\n\t\tif (address >= itr->getBase() && address < itr->getEnd())\n\t\t\treturn itr;\n\t}\n\treturn nullptr;\n}\n\nMMURange::MMURange(const uint32 baseAddress, const uint32 size, MMU_MEM_AREA_ID areaId, const std::string_view name, MFLAG flags) : baseAddress(baseAddress), size(size), initSize(size), areaId(areaId), name(name), flags(flags)\n{\n\tg_mmuRanges.emplace_back(this);\n}\n\nvoid MMURange::mapMem()\n{\n\tcemu_assert_debug(!m_isMapped);\n\tif (MemMapper::AllocateMemory(memory_base + baseAddress, size, MemMapper::PAGE_PERMISSION::P_RW, true) == nullptr)\n\t{\n\t\tstd::string errorMsg = _tr(\"Unable to allocate {} memory\", name);\n\t\tWindowSystem::ShowErrorDialog(errorMsg, _tr(\"Error\"));\n\t\t#if BOOST_OS_WINDOWS\n\t\tExitProcess(-1);\n\t\t#else\n\t\texit(-1);\n\t\t#endif\n\t}\n\tm_isMapped = true;\n}\n\nvoid MMURange::unmapMem()\n{\n    MemMapper::FreeMemory(memory_base + baseAddress, size, true);\n\tm_isMapped = false;\n}\n\nMMURange mmuRange_LOW0\t\t\t\t\t{ 0x00010000, 0x000F0000, MMU_MEM_AREA_ID::CODE_LOW0, \"CODE_LOW0\" }; // code cave (Cemuhook)\nMMURange mmuRange_TRAMPOLINE_AREA\t\t{ 0x00E00000, 0x00200000, MMU_MEM_AREA_ID::CODE_TRAMPOLINE, \"TRAMPOLINE_AREA\" }; // code area for trampolines and imports\nMMURange mmuRange_CODECAVE\t\t\t\t{ 0x01800000, 0x00400000, MMU_MEM_AREA_ID::CODE_CAVE, \"CODECAVE\" }; // code cave area (4MiB)\nMMURange mmuRange_TEXT_AREA\t\t\t\t{ 0x02000000, 0x0C000000, MMU_MEM_AREA_ID::CODE_MAIN, \"TEXT_AREA\" }; // module text sections go here (0x02000000 to 0x10000000, 224MiB)\nMMURange mmuRange_CEMU_AREA\t\t\t\t{ 0x0E000000, 0x02000000, MMU_MEM_AREA_ID::CEMU_PRIVATE, \"CEMU_AREA\", MMURange::MFLAG::FLAG_MAP_EARLY }; // Cemu-only, 32MiB. Should be allocated early for SysAllocator\nMMURange mmuRange_MEM2\t\t\t\t\t{ 0x10000000, 0x40000000, MMU_MEM_AREA_ID::MEM2_DATA, \"MEM2\" }; // main memory area (1GB)\nMMURange mmuRange_OVERLAY_AREA\t\t\t{ 0xA0000000, 0x1C000000, MMU_MEM_AREA_ID::OVERLAY, \"OVERLAY_AREA\", MMURange::MFLAG::FLAG_OPTIONAL }; // has to be requested, 448MiB\nMMURange mmuRange_FGBUCKET\t\t\t\t{ 0xE0000000, 0x04000000, MMU_MEM_AREA_ID::FGBUCKET, \"FGBUCKET\" }; // foreground bucket (64MiB)\nMMURange mmuRange_TILINGAPERTURE\t\t{ 0xE8000000, 0x02000000, MMU_MEM_AREA_ID::TILING_APERATURE, \"TILINGAPERTURE\" }; // tiling aperture\nMMURange mmuRange_MEM1\t\t\t\t\t{ 0xF4000000, 0x02000000, MMU_MEM_AREA_ID::MEM1, \"MEM1\" }; // 32MiB\nMMURange mmuRange_RPLLOADER\t\t\t\t{ 0xF6000000, 0x02000000, MMU_MEM_AREA_ID::RPLLOADER, \"RPLLOADER_AREA\" }; // shared with RPLLoader\nMMURange mmuRange_SHARED_AREA\t\t\t{ 0xF8000000, 0x02000000, MMU_MEM_AREA_ID::SHAREDDATA, \"SHARED_AREA\", MMURange::MFLAG::FLAG_MAP_EARLY }; // 32MiB, Cemuhook accesses this memory region at boot\nMMURange mmuRange_CORE0_LC\t\t\t\t{ 0xFFC00000, 0x00005000, MMU_MEM_AREA_ID::CPU_LC0, \"CORE0_LC\" }; // locked L2 cache of core 0\nMMURange mmuRange_CORE1_LC\t\t\t\t{ 0xFFC40000, 0x00005000, MMU_MEM_AREA_ID::CPU_LC1, \"CORE1_LC\" }; // locked L2 cache of core 1\nMMURange mmuRange_CORE2_LC\t\t\t\t{ 0xFFC80000, 0x00005000, MMU_MEM_AREA_ID::CPU_LC2, \"CORE2_LC\" }; // locked L2 cache of core 2\nMMURange mmuRange_HIGHMEM\t\t\t\t{ 0xFFFFF000, 0x00001000, MMU_MEM_AREA_ID::CPU_PER_CORE, \"PER-CORE\" }; // per-core memory? Used by coreinit and PPC kernel to store core context specific data (like current thread ptr). We dont use it but Project Zero has a bug where it writes a byte at 0xfffffffe thus this memory range needs to be writable\n\nvoid memory_init()\n{\n\t// reserve a continous range of 4GB\n\tif(!memory_base)\n\t\tmemory_base = (uint8*)MemMapper::ReserveMemory(nullptr, (size_t)0x100000000, MemMapper::PAGE_PERMISSION::P_RW);\n\tif( !memory_base )\n\t{\n\t\tdebug_printf(\"memory_init(): Unable to reserve 4GB of memory\\n\");\n\t\tdebugBreakpoint();\n\t\tWindowSystem::ShowErrorDialog(_tr(\"Unable to reserve 4GB of memory\"), _tr(\"Error\"));\n\t\texit(-1);\n\t}\n\tfor (auto& itr : g_mmuRanges)\n\t{\n\t\tif (itr->isMappedEarly())\n\t\t\titr->mapMem();\n\t}\n}\n\nvoid memory_mapForCurrentTitle()\n{\n\tfor (auto& itr : g_mmuRanges)\n\t\tif(!itr->isMapped())\n\t\t\titr->resetConfig();\n\t// expand ranges\n\tauto gfxPackMappings = GraphicPack2::GetActiveRAMMappings();\n\tfor (auto& mapping : gfxPackMappings)\n\t{\n\t\tMMURange* mmuRange = nullptr;\n\t\tfor (auto& itr : g_mmuRanges)\n\t\t{\n\t\t\tif (itr->getBase() == mapping.first)\n\t\t\t{\n\t\t\t\tmmuRange = itr;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!mmuRange)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Graphic pack error: Unable to apply modified RAM mapping {:08x}-{:08x}. Start address must match one of the existing MMU ranges:\", mapping.first, mapping.second));\n\t\t\tfor (auto& itr : g_mmuRanges)\n\t\t\t{\n\t\t\t\tif(itr->isMapped())\n\t\t\t\t\tcontinue;\n\t\t\t\tcemuLog_log(LogType::Force, fmt::format(\"{:08x}-{:08x} ({:})\", itr->getBase(), itr->getEnd(), itr->getName()));\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\t// make sure the new range isn't overlapping with anything\n\t\tbool isOverlapping = false;\n\t\tfor (auto& itr : g_mmuRanges)\n\t\t{\n\t\t\tif(itr == mmuRange)\n\t\t\t\tcontinue;\n\t\t\tif (mapping.first < itr->getEnd() && mapping.second > itr->getBase())\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Graphic pack error: Unable to apply modified memory range {:08x}-{:08x} since it is overlapping with {:08x}-{:08x} ({:})\", mapping.first, mapping.second, itr->getBase(), itr->getEnd(), itr->getName()));\n\t\t\t\tisOverlapping = true;\n\t\t\t}\n\t\t}\n\t\tif(isOverlapping)\n\t\t\tcontinue;\n\t\tmmuRange->setEnd(mapping.second);\n\t}\n\n\tfor (auto& itr : g_mmuRanges)\n\t{\n\t\tif (!itr->isOptional() && !itr->isMappedEarly())\n\t\t\titr->mapMem();\n\t}\n}\n\nvoid memory_unmapForCurrentTitle()\n{\n    for (auto& itr : g_mmuRanges)\n    {\n        if (itr->isMapped() && !itr->isMappedEarly())\n            itr->unmapMem();\n    }\n}\n\nvoid memory_logModifiedMemoryRanges()\n{\n\tauto gfxPackMappings = GraphicPack2::GetActiveRAMMappings();\n\tfor (auto& mapping : gfxPackMappings)\n\t{\n\t\tMMURange* mmuRange = nullptr;\n\t\tfor (auto& itr : g_mmuRanges)\n\t\t{\n\t\t\tif (itr->getBase() == mapping.first)\n\t\t\t{\n\t\t\t\tmmuRange = itr;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!mmuRange)\n\t\t\tcontinue;\n\t\tsint32 extraMem = (sint32)mapping.second - (sint32)(mmuRange->getBase() + mmuRange->getInitSize());\n\t\textraMem = (extraMem + 1023) / 1024;\n\t\tstd::string memAmountStr;\n\t\tif (extraMem >= 8 * 1024 * 1024)\n\t\t\tmemAmountStr = fmt::format(\"{:+}MiB\", (extraMem + 1023) / 1024);\n\t\telse\n\t\t\tmemAmountStr = fmt::format(\"{:+}KiB\", extraMem);\n\t\tcemuLog_log(LogType::Force, fmt::format(\"Graphic pack: Using modified RAM mapping {:08x}-{:08x} ({})\", mapping.first, mapping.second, memAmountStr));\n\t}\n}\n\nvoid memory_enableOverlayArena()\n{\n\tif (mmuRange_OVERLAY_AREA.isMapped())\n\t\treturn;\n\tmmuRange_OVERLAY_AREA.mapMem();\n}\n\nvoid memory_enableHBLELFCodeArea()\n{\n\tif (memory_elfCodeArena != NULL)\n\t\treturn;\n\tmemory_elfCodeArena = (uint8*)MemMapper::AllocateMemory(memory_base + 0x00800000, 0x00800000, MemMapper::PAGE_PERMISSION::P_RW, true);\n\tif (memory_elfCodeArena == NULL)\n\t{\n\t\tdebug_printf(\"memory_enableHBLELFCodeArea(): Unable to allocate memory for ELF arena\\n\");\n\t\tdebugBreakpoint();\n\t}\n}\n\nbool memory_isAddressRangeAccessible(MPTR virtualAddress, uint32 size)\n{\n\tfor (auto& itr : g_mmuRanges)\n\t{\n\t\tif(!itr->isMapped())\n\t\t\tcontinue;\n\t\tif (virtualAddress >= itr->getBase() && virtualAddress < itr->getEnd())\n\t\t{\n\t\t\tuint32 remainingSize = itr->getEnd() - virtualAddress;\n\t\t\treturn size <= remainingSize && itr->isMapped();\n\t\t}\n\t}\n\treturn false;\n}\n\nuint32 memory_virtualToPhysical(uint32 virtualOffset)\n{\n\t// currently we map virtual to physical space 1:1\n\treturn virtualOffset;\n}\n\nuint32 memory_physicalToVirtual(uint32 physicalOffset)\n{\n\t// currently we map virtual to physical space 1:1\n\treturn physicalOffset;\n}\n\nuint8* memory_getPointerFromPhysicalOffset(uint32 physicalOffset)\n{\n\treturn memory_base + physicalOffset;\n}\n\nuint32 memory_getVirtualOffsetFromPointer(void* ptr)\n{\n\tif( !ptr )\n\t\treturn MPTR_NULL;\n\treturn (uint32)((uint8*)ptr - (uint8*)memory_base);\n}\n\nuint8* memory_getPointerFromVirtualOffset(uint32 virtualOffset)\n{\t\n\treturn memory_base + virtualOffset;\n}\n\nuint8* memory_getPointerFromVirtualOffsetAllowNull(uint32 virtualOffset)\n{\t\n\tif( virtualOffset == MPTR_NULL )\n\t\treturn nullptr;\n\treturn memory_getPointerFromVirtualOffset(virtualOffset);\n}\n\n// write access\nvoid memory_writeDouble(uint32 address, double vf)\n{\n\tuint64 v = *(uint64*)&vf;\n\tuint32 v1 = v&0xFFFFFFFF;\n\tuint32 v2 = v>>32;\n\tuint8* ptr = memory_getPointerFromVirtualOffset(address);\n\t*(uint32*)(ptr+4) = CPU_swapEndianU32(v1);\n\t*(uint32*)(ptr+0) = CPU_swapEndianU32(v2);\n}\n\nvoid memory_writeFloat(uint32 address, float vf)\n{\n\tuint32 v = *(uint32*)&vf;\n\t*(uint32*)(memory_getPointerFromVirtualOffset(address)) = CPU_swapEndianU32(v);\n}\n\nvoid memory_writeU32(uint32 address, uint32 v)\n{\n\t*(uint32*)(memory_getPointerFromVirtualOffset(address)) = CPU_swapEndianU32(v);\n}\n\nvoid memory_writeU64(uint32 address, uint64 v)\n{\n\t*(uint64*)(memory_getPointerFromVirtualOffset(address)) = CPU_swapEndianU64(v);\n}\n\nvoid memory_writeU16(uint32 address, uint16 v)\n{\n\t*(uint16*)(memory_getPointerFromVirtualOffset(address)) = CPU_swapEndianU16(v);\n}\n\nvoid memory_writeU8(uint32 address, uint8 v)\n{\n\t*(uint8*)(memory_getPointerFromVirtualOffset(address)) = v;\n}\n\n// read access\n\ndouble memory_readDouble(uint32 address)\n{\n\tuint32 v[2];\n\tv[1] = *(uint32*)(memory_getPointerFromVirtualOffset(address));\n\tv[0] = *(uint32*)(memory_getPointerFromVirtualOffset(address)+4);\n\tv[0] = CPU_swapEndianU32(v[0]);\n\tv[1] = CPU_swapEndianU32(v[1]);\n\treturn *(double*)v;\n}\n\nfloat memory_readFloat(uint32 address)\n{\n\tuint32 v = *(uint32*)(memory_getPointerFromVirtualOffset(address));\n\tv = CPU_swapEndianU32(v);\n\treturn *(float*)&v;\n}\n\nuint64 memory_readU64(uint32 address)\n{\n\tuint64 v = *(uint64*)(memory_getPointerFromVirtualOffset(address));\n\treturn CPU_swapEndianU64(v);\n}\n\nuint32 memory_readU32(uint32 address)\n{\n\tuint32 v = *(uint32*)(memory_getPointerFromVirtualOffset(address));\n\treturn CPU_swapEndianU32(v);\n}\n\nuint16 memory_readU16(uint32 address)\n{\n\tuint16 v = *(uint16*)(memory_getPointerFromVirtualOffset(address));\n\treturn CPU_swapEndianU16(v);\n}\n\nuint8 memory_readU8(uint32 address)\n{\n\treturn *(uint8*)(memory_getPointerFromVirtualOffset(address));\n}\n\nextern \"C\" DLLEXPORT void* memory_getBase()\n{\n\treturn memory_base;\n}\n\nvoid memory_writeDumpFile(uint32 startAddr, uint32 size, const fs::path& path)\n{\n\tfs::path filePath = path;\n\tfilePath /= fmt::format(\"{:08x}.bin\", startAddr);\n\tFileStream* fs = FileStream::createFile2(filePath);\n\tif (fs)\n\t{\n\t\tfs->writeData(memory_base + startAddr, size);\n\t\tdelete fs;\n\t}\n}\n\nvoid memory_createDump()\n{\n\tconst uint32 pageSize = MemMapper::GetPageSize();\n\tfs::path path = ActiveSettings::GetUserDataPath(\"dump/ramDump{:}\", (uint32)time(nullptr));\n\tfs::create_directories(path);\n\n\tfor (auto& itr : g_mmuRanges)\n\t{\n\t\tif(!itr->isMapped())\n\t\t\tcontinue;\n\t\tmemory_writeDumpFile(itr->getBase(), itr->getSize(), path);\n\t}\n}\n\nnamespace MMU\n{\n\t// MMIO access handler\n\t// located in address region 0x0C000000 - 0x0E000000\n\t// there seem to be multiple subregions + special meanings for some address bits maybe?\n\t// Try to figure this out. We know these regions (in Wii U mode):\n\t// 0x0C000000 (the old GC register interface?)\n\t// 0x0D000000 (new Wii U stuff?)\n\n\tstd::unordered_map<PAddr, MMIOFuncWrite32>* g_mmioHandlerW32{};\n\tstd::unordered_map<PAddr, MMIOFuncWrite16>* g_mmioHandlerW16{};\n\tstd::unordered_map<PAddr, MMIOFuncRead32>* g_mmioHandlerR32{};\n\tstd::unordered_map<PAddr, MMIOFuncRead16>* g_mmioHandlerR16{};\n\n\tvoid _initHandlers()\n\t{\n\t\tif (g_mmioHandlerW32)\n\t\t\treturn;\n\t\tg_mmioHandlerW32 = new std::unordered_map<PAddr, MMIOFuncWrite32>();\n\t\tg_mmioHandlerW16 = new std::unordered_map<PAddr, MMIOFuncWrite16>();\n\t\tg_mmioHandlerR32 = new std::unordered_map<PAddr, MMIOFuncRead32>();\n\t\tg_mmioHandlerR16 = new std::unordered_map<PAddr, MMIOFuncRead16>();\n\t}\n\n\tPAddr _MakeMMIOAddress(MMIOInterface interfaceLocation, uint32 relativeAddress)\n\t{\n\t\tPAddr addr = 0;\n\t\tif (interfaceLocation == MMIOInterface::INTERFACE_0C000000)\n\t\t\taddr = 0x0C000000;\n\t\telse if (interfaceLocation == MMIOInterface::INTERFACE_0D000000)\n\t\t\taddr = 0x0D000000;\n\t\telse\n\t\t\tassert_dbg();\n\t\treturn addr + relativeAddress;\n\t}\n\n\tvoid RegisterMMIO_W32(MMIOInterface interfaceLocation, uint32 relativeAddress, MMIOFuncWrite32 ptr)\n\t{\n\t\t_initHandlers();\n\t\tg_mmioHandlerW32->emplace(_MakeMMIOAddress(interfaceLocation, relativeAddress), ptr);\n\t}\n\n\tvoid RegisterMMIO_W16(MMIOInterface interfaceLocation, uint32 relativeAddress, MMIOFuncWrite16 ptr)\n\t{\n\t\t_initHandlers();\n\t\tg_mmioHandlerW16->emplace(_MakeMMIOAddress(interfaceLocation, relativeAddress), ptr);\n\t}\n\n\tvoid RegisterMMIO_R32(MMIOInterface interfaceLocation, uint32 relativeAddress, MMIOFuncRead32 ptr)\n\t{\n\t\t_initHandlers();\n\t\tPAddr addr = _MakeMMIOAddress(interfaceLocation, relativeAddress);\n\t\tg_mmioHandlerR32->emplace(addr, ptr);\n\t}\n\n\tvoid RegisterMMIO_R16(MMIOInterface interfaceLocation, uint32 relativeAddress, MMIOFuncRead16 ptr)\n\t{\n\t\t_initHandlers();\n\t\tg_mmioHandlerR16->emplace(_MakeMMIOAddress(interfaceLocation, relativeAddress), ptr);\n\t}\n\n\tvoid WriteMMIO_32(PAddr address, uint32 value)\n\t{\n\t\tcemu_assert_debug((address & 0x3) == 0);\n\t\tauto itr = g_mmioHandlerW32->find(address);\n\t\tif (itr == g_mmioHandlerW32->end())\n\t\t{\n\t\t\t//cemuLog_logDebug(LogType::Force, \"[MMU] MMIO write u32 0x{:08x} from unhandled address 0x{:08x}\", value, address);\n\t\t\treturn;\n\t\t}\n\t\treturn itr->second(address, value);\n\t}\n\n\tvoid WriteMMIO_16(PAddr address, uint16 value)\n\t{\n\t\tcemu_assert_debug((address & 0x1) == 0);\n\t\tauto itr = g_mmioHandlerW16->find(address);\n\t\tif (itr == g_mmioHandlerW16->end())\n\t\t{\n\t\t\t//cemuLog_logDebug(LogType::Force, \"[MMU] MMIO write u16 0x{:04x} from unhandled address 0x{:08x}\", (uint32)value, address);\n\t\t\treturn;\n\t\t}\n\t\treturn itr->second(address, value);\n\t}\n\n\n\t// todo - instead of passing the physical address to Read/WriteMMIO we should pass an interface id and a relative address? This would allow remapping the hardware address (tho we can just unregister + register at different addresses)\n\n\tuint32 ReadMMIO_32(PAddr address)\n\t{\n\t\tcemu_assert_debug((address & 0x3) == 0);\n\t\tauto itr = g_mmioHandlerR32->find(address);\n\t\tif(itr == g_mmioHandlerR32->end())\n\t\t{\n\t\t\t//cemuLog_logDebug(LogType::Force, \"[MMU] MMIO read u32 from unhandled address 0x{:08x}\", address);\n\t\t\treturn 0;\n\t\t}\n\t\treturn itr->second(address);\n\t}\n\n\tuint16 ReadMMIO_16(PAddr address)\n\t{\n\t\tcemu_assert_debug((address & 0x1) == 0);\n\t\tauto itr = g_mmioHandlerR16->find(address);\n\t\tif (itr == g_mmioHandlerR16->end())\n\t\t{\n\t\t\t//cemuLog_logDebug(LogType::Force, \"[MMU] MMIO read u16 from unhandled address 0x{:08x}\", address);\n\t\t\treturn 0;\n\t\t}\n\t\treturn itr->second(address);\n\t}\n\n\n}\n"
  },
  {
    "path": "src/Cafe/HW/MMU/MMU.h",
    "content": "#pragma once\n\nvoid memory_init();\nvoid memory_mapForCurrentTitle();\nvoid memory_unmapForCurrentTitle();\nvoid memory_logModifiedMemoryRanges();\n\nvoid memory_enableOverlayArena();\nvoid memory_enableHBLELFCodeArea();\nuint32 memory_getVirtualOffsetFromPointer(void* ptr);\nuint8* memory_getPointerFromVirtualOffset(uint32 virtualOffset);\nuint8* memory_getPointerFromVirtualOffsetAllowNull(uint32 virtualOffset);\n\nuint8* memory_getPointerFromPhysicalOffset(uint32 physicalOffset);\n\nuint32 memory_virtualToPhysical(uint32 virtualOffset);\nuint32 memory_physicalToVirtual(uint32 physicalOffset);\n\nextern uint8* memory_base; // points to base of PowerPC address space\n\nenum class MMU_MEM_AREA_ID\n{\n\tCODE_LOW0,\n\tCODE_TRAMPOLINE,\n\tCODE_CAVE,\n\tCODE_MAIN,\n\tMEM2_DATA,\n\tFGBUCKET,\n\tTILING_APERATURE,\n\tOVERLAY,\n\tMAPABLE_SPACE,\n\tMEM1,\n\tRPLLOADER,\n\tSHAREDDATA,\n\n\tCPU_LC0,\n\tCPU_LC1,\n\tCPU_LC2,\n\tCPU_PER_CORE,\n\n\tCEMU_PRIVATE,\n};\n\nstruct MMURange\n{\n\tenum MFLAG\n\t{\n\t\tFLAG_OPTIONAL = (1 << 0), // allocate only on explicit request\n\t\tFLAG_MAP_EARLY = (1 << 1), // map at Cemu launch, normally memory is mapped when a game is loaded\n\t};\n\n\tMMURange(const uint32 baseAddress, const uint32 size, MMU_MEM_AREA_ID areaId, const std::string_view name, MFLAG flags = (MFLAG)0);\n\n\tvoid mapMem();\n\tvoid unmapMem();\n\n\tuint8* getPtr() const\n\t{\n\t\tcemu_assert_debug(m_isMapped);\n\t\treturn memory_base + baseAddress;\n\t}\n\n\tuint32 getBase() const\n\t{\n\t\treturn baseAddress;\n\t}\n\n\t// reset to initial parameters\n\tvoid resetConfig()\n\t{\n\t\tsize = initSize;\n\t}\n\n\tvoid setEnd(uint32 endAddress)\n\t{\n\t\tcemu_assert_debug(!m_isMapped);\n\t\tcemu_assert_debug((endAddress & 0xFFF) == 0);\n\t\tsize = endAddress - baseAddress;\n\t}\n\n\t// returns offset of last byte + 1 (base + size)\n\tuint32 getEnd() const\n\t{\n\t\treturn baseAddress + size;\n\t}\n\n\tuint32 getSize() const\n\t{\n\t\treturn size;\n\t}\n\n\tuint32 getInitSize() const\n\t{\n\t\treturn initSize;\n\t}\n\n\tstd::string_view getName() const\n\t{\n\t\treturn name;\n\t}\n\n\tbool containsAddress(uint32 addr) const\n\t{\n\t\treturn addr >= getBase() && addr < getEnd();\n\t}\n\n\tbool isMapped() const { return m_isMapped; };\n\tbool isOptional() const { return (flags & MFLAG::FLAG_OPTIONAL) != 0; };\n\tbool isMappedEarly() const { return (flags & MFLAG::FLAG_MAP_EARLY) != 0; };\n\n\tconst uint32 baseAddress;\n\tconst uint32 initSize; // initial size\n\tconst std::string name;\n\tconst MFLAG flags;\n\tconst MMU_MEM_AREA_ID areaId;\n\t// runtime parameters\n\tuint32 size;\n\tbool m_isMapped{};\n};\n\n\nextern MMURange mmuRange_LOW0;\nextern MMURange mmuRange_TRAMPOLINE_AREA;\nextern MMURange mmuRange_CODECAVE;\nextern MMURange mmuRange_TEXT_AREA;\nextern MMURange mmuRange_MEM2;\nextern MMURange mmuRange_CEMU_AREA;\nextern MMURange mmuRange_OVERLAY_AREA;\nextern MMURange mmuRange_FGBUCKET;\nextern MMURange mmuRange_TILINGAPERTURE;\nextern MMURange mmuRange_MEM1;\nextern MMURange mmuRange_RPLLOADER;\nextern MMURange mmuRange_SHARED_AREA;\nextern MMURange mmuRange_CORE0_LC;\nextern MMURange mmuRange_CORE1_LC;\nextern MMURange mmuRange_CORE2_LC;\nstd::vector<MMURange*> memory_getMMURanges();\nMMURange* memory_getMMURangeByAddress(MPTR address);\n\nbool memory_isAddressRangeAccessible(MPTR virtualAddress, uint32 size);\n\n#define MEMORY_CODELOW0_ADDR\t\t\t\t(0x00010000)\n#define MEMORY_CODELOW0_SIZE\t\t\t\t(0x000F0000) // ~1MB\n\n#define MEMORY_CODE_TRAMPOLINE_AREA_ADDR\t(0x00E00000) // code area for trampolines and imports\n#define MEMORY_CODE_TRAMPOLINE_AREA_SIZE\t(0x00200000) // 2MB\n\n#define MEMORY_CODECAVEAREA_ADDR\t\t\t(0x01800000)\n#define MEMORY_CODECAVEAREA_SIZE\t\t\t(0x00400000) // 4MB\n\n#define MEMORY_CODEAREA_ADDR\t\t\t\t(0x02000000)\n#define MEMORY_CODEAREA_SIZE\t\t\t\t(0x0E000000) // 224MB\n\n#define MEMORY_DATA_AREA_ADDR\t\t\t\t(0x10000000)\n#define MEMORY_DATA_AREA_SIZE\t\t\t\t(0x40000000)\n\n#define MEMORY_FGBUCKET_AREA_ADDR\t\t\t(0xE0000000) // actual offset is 0xE0000000 according to PPC kernel\n#define MEMORY_FGBUCKET_AREA_SIZE\t\t\t(0x04000000) // 64MB split up into multiple subareas, size is verified with value from PPC kernel\n\n#define MEMORY_TILINGAPERTURE_AREA_ADDR\t\t(0xE8000000)\n#define MEMORY_TILINGAPERTURE_AREA_SIZE\t\t(0x02000000) // 32MB\n\n#define MEMORY_OVERLAY_AREA_OFFSET\t\t\t(0xA0000000)\n#define MEMORY_OVERLAY_AREA_SIZE\t\t\t(448*1024*1024) // 448MB (recycled background app memory)\n\n#define MEMORY_MEM1_AREA_ADDR\t\t\t\t(0xF4000000)\n#define MEMORY_MEM1_AREA_SIZE\t\t\t\t(0x02000000) // 32MB\n\n#define MEMORY_RPLLOADER_AREA_ADDR\t\t\t(0xF6000000) // workarea for RPLLoader (normally this is kernel workspace)\n#define MEMORY_RPLLOADER_AREA_SIZE\t\t\t(0x02000000) // 32MB\n\n#define MEMORY_SHAREDDATA_AREA_ADDR\t\t\t(0xF8000000)\n#define MEMORY_SHAREDDATA_AREA_SIZE\t\t\t(0x02000000) // 32MB\n\n#if BOOST_OS_WINDOWS\n#define CPU_swapEndianU64(_v) _byteswap_uint64((uint64)(_v))\n#define CPU_swapEndianU32(_v) _byteswap_ulong((uint32)(_v))\n#define CPU_swapEndianU16(_v) _byteswap_ushort((uint16)(_v))\n#elif BOOST_OS_LINUX\n#define CPU_swapEndianU64(_v) bswap_64((uint64)(_v))\n#define CPU_swapEndianU32(_v) bswap_32((uint32)(_v))\n#define CPU_swapEndianU16(_v) bswap_16((uint16)(_v))\n#elif BOOST_OS_MACOS\n#define CPU_swapEndianU64(_v) OSSwapInt64((uint64)(_v))\n#define CPU_swapEndianU32(_v) OSSwapInt32((uint32)(_v))\n#define CPU_swapEndianU16(_v) OSSwapInt16((uint16)(_v))\n#elif BOOST_OS_BSD\n#ifdef __OpenBSD__\n#define CPU_swapEndianU64(_v) swap64((uint64)(_v))\n#define CPU_swapEndianU32(_v) swap32((uint32)(_v))\n#define CPU_swapEndianU16(_v) swap16((uint16)(_v))\n#else // FreeBSD and NetBSD\n#define CPU_swapEndianU64(_v) bswap64((uint64)(_v))\n#define CPU_swapEndianU32(_v) bswap32((uint32)(_v))\n#define CPU_swapEndianU16(_v) bswap16((uint16)(_v))\n#endif\n#endif\n\n// C-style memory access, deprecated. Use memory_read<> and memory_write<> templates instead\nvoid memory_writeDouble(uint32 address, double vf);\nvoid memory_writeFloat(uint32 address, float vf);\nvoid memory_writeU32(uint32 address, uint32 v);\nvoid memory_writeU16(uint32 address, uint16 v);\nvoid memory_writeU8(uint32 address, uint8 v);\nvoid memory_writeU64(uint32 address, uint64 v);\n\ndouble memory_readDouble(uint32 address);\nfloat memory_readFloat(uint32 address);\nuint64 memory_readU64(uint32 address);\nuint32 memory_readU32(uint32 address);\nuint16 memory_readU16(uint32 address);\nuint8 memory_readU8(uint32 address);\n\nvoid memory_createDump();\n\ntemplate<size_t count>\nvoid memory_readBytes(VAddr address, std::array<uint8, count>& buffer)\n{\n\tmemcpy(buffer.data(), memory_getPointerFromVirtualOffset(address), count);\n}\n\ntemplate <typename T> inline T memory_read(VAddr address)\n{\n\treturn *(betype<T>*)(memory_base + address);\n}\n\ntemplate <typename T> inline void memory_write(VAddr address, T value)\n{\n\t*(betype<T>*)(memory_base + address) = value;\n}\n\n// LLE implementation\nvoid memory_initPhysicalLayout();\n\nnamespace MMU\n{\n\tusing MMIOFuncWrite32 = void (*)(PAddr addr, uint32 value);\n\tusing MMIOFuncWrite16 = void (*)(PAddr addr, uint16 value);\n\n\tusing MMIOFuncRead32 = uint32(*)(PAddr addr);\n\tusing MMIOFuncRead16 = uint16(*)(PAddr addr);\n\n\tenum class MMIOInterface\n\t{\n\t\tINTERFACE_0C000000,\n\t\tINTERFACE_0D000000,\n\t\t//INTERFACE_0D000000,\n\t};\n\n\tvoid RegisterMMIO_W16(MMIOInterface interfaceLocation, uint32 relativeAddress, MMIOFuncWrite16 ptr);\n\tvoid RegisterMMIO_W32(MMIOInterface interfaceLocation, uint32 relativeAddress, MMIOFuncWrite32 ptr);\n\tvoid RegisterMMIO_R32(MMIOInterface interfaceLocation, uint32 relativeAddress, MMIOFuncRead32 ptr);\n\tvoid RegisterMMIO_R16(MMIOInterface interfaceLocation, uint32 relativeAddress, MMIOFuncRead16 ptr);\n\n\ttemplate<typename TRegType, auto TReadFunc, auto TWriteFunc>\n\tvoid RegisterMMIO_32(MMIOInterface interfaceLocation, uint32 relativeAddress)\n\t{\n\t\tRegisterMMIO_W32(interfaceLocation, relativeAddress,\n\t\t\t[](PAddr addr, uint32 value) -> void\n\t\t{\n\t\t\tTRegType temp;\n\t\t\ttemp.setFromRaw(value);\n\t\t\tTWriteFunc(addr, temp);\n\t\t});\n\t\tRegisterMMIO_R32(interfaceLocation, relativeAddress,\n\t\t\t[](PAddr addr) -> uint32\n\t\t{\n\t\t\treturn TReadFunc(addr).getRawValue();\n\t\t});\n\t}\n\n\tvoid WriteMMIO_32(PAddr address, uint32 value);\n\tvoid WriteMMIO_16(PAddr address, uint16 value);\n\tuint32 ReadMMIO_32(PAddr address);\n\tuint16 ReadMMIO_16(PAddr address);\n\n}\n\n#define MMU_IsInPPCMemorySpace(__ptr) ((const uint8*)(__ptr) >= memory_base && (const uint8*)(__ptr) < (memory_base + 0x100000000))\n"
  },
  {
    "path": "src/Cafe/HW/SI/SI.cpp",
    "content": "#include \"Cafe/HW/MMU/MMU.h\"\n#include \"Cafe/HW/Common/HwReg.h\"\n#include \"si.h\"\n\nnamespace HW_SI\n{\n\n\tstruct  \n\t{\n\t\tstruct  \n\t\t{\n\t\t\tHWREG::SICOMCSR sicomcsr{};\n\t\t\tHWREG::SIPOLL sipoll{};\n\t\t\tHWREG::SICOUTBUF outBuf[4]{};\n\t\t}registerState;\n\t\tstruct\n\t\t{\n\t\t\tuint8 cmd{};\n\t\t\tuint8 buf[2]{};\n\t\t}outputBufferState[4];\n\t\tstruct  \n\t\t{\n\t\t\tbool hasErrorNoResponse{};\n\t\t}channelStatus[4];\n\t}g_si;\n\n\t// normally we should call this periodically according to the parameters set in SIPOLL\n\t// but for now we just call it whenever status registers are read\n\tvoid handlePollUpdate()\n\t{\n\t\tfor (uint32 i = 0; i < 4; i++)\n\t\t{\n\t\t\t// note: Order of EN and VBCPY is from MSB to LSB\n\t\t\tbool isEnabled = ((g_si.registerState.sipoll.get_EN() >> (3 - i))&1) != 0;\n\t\t\tif (isEnabled)\n\t\t\t{\n\t\t\t\tg_si.channelStatus[i].hasErrorNoResponse = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid handleQueuedTransfers()\n\t{\n\t\t\n\t}\n\n\tvoid flushAllOutputBuffers()\n\t{\n\t\tfor (uint32 i = 0; i < 4; i++)\n\t\t{\n\t\t\tg_si.outputBufferState[i].cmd = g_si.registerState.outBuf[i].get_CMD();\n\t\t\tg_si.outputBufferState[i].buf[0] = g_si.registerState.outBuf[i].get_OUTPUT0();\n\t\t\tg_si.outputBufferState[i].buf[1] = g_si.registerState.outBuf[i].get_OUTPUT1();\n\t\t}\n\t}\n\n\t/* +0x6400/0x640C/0x6418/0x6424 | SI0COUTBUF - SI3COUTBUF */\n\n\tHWREG::SICOUTBUF SI_COUTBUF_R32(PAddr addr)\n\t{\n\t\tuint32 joyChannelIndex = (addr & 0xFF) / 0xC;\n\n\t\tcemu_assert_debug(false);\n\t\treturn HWREG::SICOUTBUF();\n\t}\n\n\tvoid SI_COUTBUF_W32(PAddr addr, HWREG::SICOUTBUF newValue)\n\t{\n\t\tuint32 joyChannelIndex = (addr & 0xFF) / 0xC;\n\t\tg_si.registerState.outBuf[joyChannelIndex] = newValue;\n\t}\n\n\t/* +0x6430 | SIPOLL */\n\n\tHWREG::SIPOLL SI_POLL_R32(PAddr addr)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn g_si.registerState.sipoll;\n\t}\n\n\tvoid SI_POLL_W32(PAddr addr, HWREG::SIPOLL newValue)\n\t{\n\t\tg_si.registerState.sipoll = newValue;\n\t}\n\n\t/* +0x6434 | SICOMCSR */\n\n\tHWREG::SICOMCSR SI_COMCSR_R32(PAddr addr)\n\t{\n\t\treturn g_si.registerState.sicomcsr;\n\t}\n\n\tvoid SI_COMCSR_W32(PAddr addr, HWREG::SICOMCSR newValue)\n\t{\n\t\tuint32 unhandledBits = g_si.registerState.sicomcsr.getRawValue() & ~(0x80000000);\n\t\tcemu_assert_debug(unhandledBits == 0);\n\t\t// clear transfer complete interrupt\n\t\tif (newValue.get_TCINT())\n\t\t{\n\t\t\tg_si.registerState.sicomcsr.set_TCINT(0);\n\t\t}\n\n\t\tif (newValue.get_TRANSFER_START())\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\thandleQueuedTransfers();\n\t\t}\n\t}\n\n\t/* +0x6438 | SISR */\n\n\tHWREG::SISR SI_SR_R32(PAddr addr)\n\t{\n\t\thandlePollUpdate();\n\t\tHWREG::SISR reg;\n\t\t// no response error\n\t\tif (g_si.channelStatus[0].hasErrorNoResponse)\n\t\t\treg.set_NOREP0(1);\n\t\tif (g_si.channelStatus[1].hasErrorNoResponse)\n\t\t\treg.set_NOREP1(1);\n\t\tif (g_si.channelStatus[2].hasErrorNoResponse)\n\t\t\treg.set_NOREP2(1);\n\t\tif (g_si.channelStatus[3].hasErrorNoResponse)\n\t\t\treg.set_NOREP3(1);\n\n\t\t// todo - other status fields\n\n\t\treturn reg;\n\t}\n\n\tvoid SI_SR_W32(PAddr addr, HWREG::SISR newValue)\n\t{\n\t\tif (newValue.get_NOREP0())\n\t\t\tg_si.channelStatus[0].hasErrorNoResponse = false;\n\t\tif (newValue.get_NOREP1())\n\t\t\tg_si.channelStatus[1].hasErrorNoResponse = false;\n\t\tif (newValue.get_NOREP2())\n\t\t\tg_si.channelStatus[2].hasErrorNoResponse = false;\n\t\tif (newValue.get_NOREP3())\n\t\t\tg_si.channelStatus[3].hasErrorNoResponse = false;\n\n\n\t\tif (newValue.get_WR())\n\t\t{\n\t\t\t// copies contents of SICOUTBUF to the internal shadow buffers\n\t\t\tflushAllOutputBuffers();\n\t\t}\n\t}\n\n\tvoid Initialize()\n\t{\n\t\tMMU::RegisterMMIO_32<HWREG::SICOUTBUF, SI_COUTBUF_R32, SI_COUTBUF_W32>(MMU::MMIOInterface::INTERFACE_0D000000, 0x6400);\n\t\tMMU::RegisterMMIO_32<HWREG::SICOUTBUF, SI_COUTBUF_R32, SI_COUTBUF_W32>(MMU::MMIOInterface::INTERFACE_0D000000, 0x640C);\n\t\tMMU::RegisterMMIO_32<HWREG::SICOUTBUF, SI_COUTBUF_R32, SI_COUTBUF_W32>(MMU::MMIOInterface::INTERFACE_0D000000, 0x6418);\n\t\tMMU::RegisterMMIO_32<HWREG::SICOUTBUF, SI_COUTBUF_R32, SI_COUTBUF_W32>(MMU::MMIOInterface::INTERFACE_0D000000, 0x6424);\n\n\t\tMMU::RegisterMMIO_32<HWREG::SIPOLL, SI_POLL_R32, SI_POLL_W32>(MMU::MMIOInterface::INTERFACE_0D000000, 0x6430);\n\t\tMMU::RegisterMMIO_32<HWREG::SICOMCSR, SI_COMCSR_R32, SI_COMCSR_W32>(MMU::MMIOInterface::INTERFACE_0D000000, 0x6434);\n\t\tMMU::RegisterMMIO_32<HWREG::SISR, SI_SR_R32, SI_SR_W32>(MMU::MMIOInterface::INTERFACE_0D000000, 0x6438);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/HW/SI/si.h",
    "content": "\nnamespace HW_SI\n{\n\tvoid Initialize();\n};"
  },
  {
    "path": "src/Cafe/HW/VI/VI.cpp",
    "content": "#include \"Cafe/HW/MMU/MMU.h\"\n\n\nnamespace HW_VI\n{\n\n\tRunAtCemuBoot _initVI([]()\n\t{\n\t\t//MMU::RegisterMMIO_R16(MMU::MMIOInterface::INTERFACE_0C000000, 0x1e0002, VI_UKN1E0002_R16);\n\t});\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/ODM/iosu_odm.cpp",
    "content": "#include <util/helpers/helpers.h>\n#include \"iosu_odm.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Common/FileStream.h\"\n#include \"util/helpers/Semaphore.h\"\n#include \"../kernel/iosu_kernel.h\"\n\nnamespace iosu\n{\n\tnamespace odm\n\t{\n\t\tusing namespace iosu::kernel;\n\n\t\tstd::string s_devicePath = \"/dev/odm\";\n\t\tstd::thread s_serviceThread;\n\t\tstd::atomic_bool s_requestStop{false};\n\t\tstd::atomic_bool s_isRunning{false};\n\t\tstd::atomic_bool s_threadInitialized{ false };\n\n\t\tIOSMsgQueueId s_msgQueueId;\n\t\tSysAllocator<iosu::kernel::IOSMessage, 128> _s_msgBuffer;\n\n\t\tenum class ODM_CMD_OPERATION_TYPE\n\t\t{\n\t\t\tCHECK_STATE = 4,\n\t\t\tUKN_5 = 5,\n\t\t};\n\n\t\tenum class ODM_STATE\n\t\t{\n\t\t\tNONE = 0,\n\t\t\tINITIAL = 1,\n\t\t\tAUTHENTICATION = 2,\n\t\t\tWAIT_FOR_DISC_READY = 3,\n\t\t\tCAFE_DISC = 4,\n\t\t\tRVL_DISC = 5,\n\t\t\tCLEANING_DISC = 6,\n\t\t\tINVALID_DISC = 8,\n\t\t\tDIRTY_DISC = 9,\n\t\t\tNO_DISC = 10,\n\t\t\tINVALID_DRIVE = 11,\n\t\t\tFATAL = 12,\n\t\t\tHARD_FATAL = 13,\n\t\t\tSHUTDOWN = 14,\n\t\t};\n\n\t\tvoid ODMHandleCommandIoctl(uint32 clientHandle, IPCCommandBody* cmd, ODM_CMD_OPERATION_TYPE operationId, void* ptrIn, uint32 sizeIn, void* ptrOut, uint32 sizeOut)\n\t\t{\n\t\t\tswitch(operationId)\n\t\t\t{\n\t\t\t\tcase ODM_CMD_OPERATION_TYPE::CHECK_STATE:\n\t\t\t\t{\n\t\t\t\t\t*(uint32be*)ptrOut = (uint32)ODM_STATE::NO_DISC;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase ODM_CMD_OPERATION_TYPE::UKN_5:\n\t\t\t\t{\n\t\t\t\t\t// does this return anything?\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"ODMHandleCommandIoctl: Unknown operationId %d\\n\", (uint32)operationId);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_OK);\n\t\t}\n\n\t\tuint32 CreateClientHandle()\n\t\t{\n\t\t\treturn 1; // we dont care about handles for now\n\t\t}\n\n\t\tvoid CloseClientHandle(uint32 handle)\n\t\t{\n\n\t\t}\n\n\t\tvoid ODMServiceThread()\n\t\t{\n\t\t\tSetThreadName(\"ODMService\");\n\t\t\ts_msgQueueId = IOS_CreateMessageQueue(_s_msgBuffer.GetPtr(), _s_msgBuffer.GetCount());\n\t\t\tcemu_assert(!IOS_ResultIsError((IOS_ERROR)s_msgQueueId));\n\t\t\tIOS_ERROR r = IOS_RegisterResourceManager(s_devicePath.c_str(), s_msgQueueId);\n\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t\ts_threadInitialized = true;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tIOSMessage msg;\n\t\t\t\tIOS_ERROR r = IOS_ReceiveMessage(s_msgQueueId, &msg, 0);\n\t\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t\t\tif (msg == 0)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(s_requestStop);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tIPCCommandBody* cmd = MEMPTR<IPCCommandBody>(msg).GetPtr();\n\t\t\t\tuint32 clientHandle = (uint32)cmd->devHandle;\n\t\t\t\tif (cmd->cmdId == IPCCommandId::IOS_OPEN)\n\t\t\t\t{\n\t\t\t\t\tIOS_ResourceReply(cmd, (IOS_ERROR)CreateClientHandle());\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_CLOSE)\n\t\t\t\t{\n\t\t\t\t\tCloseClientHandle((IOSDevHandle)(uint32)cmd->devHandle);\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_OK);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_IOCTLV)\n\t\t\t\t{\n\t\t\t\t\tuint32 requestId = cmd->args[0];\n\t\t\t\t\tuint32 numIn = cmd->args[1];\n\t\t\t\t\tuint32 numOut = cmd->args[2];\n\t\t\t\t\tIPCIoctlVector* vec = MEMPTR<IPCIoctlVector>{ cmd->args[3] }.GetPtr();\n\t\t\t\t\tIPCIoctlVector* vecIn = vec + numIn;\n\t\t\t\t\tIPCIoctlVector* vecOut = vec + 0;\n\t\t\t\t\tcemuLog_log(LogType::Force, \"{}: Received unsupported Ioctlv cmd\", s_devicePath);\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_INVALID);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_IOCTL)\n\t\t\t\t{\n\t\t\t\t\tODMHandleCommandIoctl(clientHandle, cmd, (ODM_CMD_OPERATION_TYPE)cmd->args[0].value(), MEMPTR<void>(cmd->args[1]), cmd->args[2], MEMPTR<void>(cmd->args[3]), cmd->args[4]);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"{}: Unsupported cmdId\", s_devicePath);\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_INVALID);\n\t\t\t\t}\n\t\t\t}\n\t\t\ts_threadInitialized = false;\n\t\t}\n\n\t\tvoid Initialize()\n\t\t{\n\t\t\tif (s_isRunning.exchange(true))\n\t\t\t\treturn;\n\t\t\ts_threadInitialized = false;\n\t\t\ts_requestStop = false;\n\t\t\ts_serviceThread = std::thread(&ODMServiceThread);\n\t\t\twhile (!s_threadInitialized) std::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t}\n\n\t\tvoid Shutdown()\n\t\t{\n\t\t\tif (!s_isRunning.exchange(false))\n\t\t\t\treturn;\n\t\t\ts_requestStop = true;\n\t\t\tIOS_SendMessage(s_msgQueueId, 0, 0);\n\t\t\ts_serviceThread.join();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/ODM/iosu_odm.h",
    "content": "#pragma once\n\nnamespace iosu\n{\n\tnamespace odm\n\t{\n\t\tvoid Initialize();\n\t\tvoid Shutdown();\n\t}\n}"
  },
  {
    "path": "src/Cafe/IOSU/PDM/iosu_pdm.cpp",
    "content": "#include <util/helpers/helpers.h>\n#include \"iosu_pdm.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Common/FileStream.h\"\n#include \"util/helpers/Semaphore.h\"\n\n#if BOOST_OS_LINUX\n// using chrono::year_month_date and other features require a relatively recent stdlibc++\n// to avoid upping the required version we use the STL reference implementation for now\n#include \"Common/unix/date.h\"\nnamespace chrono_d = date;\n#else\nnamespace chrono_d = std::chrono;\n#endif\n\n\nnamespace iosu\n{\n\tnamespace pdm\n\t{\n\t\tstd::recursive_mutex sPlaystatsLock;\n\t\tstd::recursive_mutex sDiaryLock;\n\n\t\tfs::path GetPDFile(const char* filename)\n\t\t{\n\t\t\t// todo - support for per-account tracking\n\t\t\treturn ActiveSettings::GetMlcPath(fmt::format(\"usr/save/system/pdm/80000001/{}\", filename));\n\t\t}\n\n\t\tvoid MakeDirectory()\n\t\t{\n\t\t\tfs::path path = GetPDFile(\".\");\n\t\t\tstd::error_code ec;\n\t\t\tfs::create_directories(path, ec);\n\t\t}\n\n\t\tchrono_d::year_month_day GetDateFromDayIndex(uint16 dayIndex)\n\t\t{\n\t\t\tchrono_d::sys_days startDateDay(chrono_d::year(2000) / chrono_d::January / chrono_d::day(1));\n\t\t\tchrono_d::sys_days lastPlayedDay = startDateDay + chrono_d::days(dayIndex);\n\t\t\treturn chrono_d::year_month_day(lastPlayedDay);\n\t\t}\n\n\t\tuint16 GetTodaysDayIndex()\n\t\t{\n\t\t\tchrono_d::sys_days startDateDay(chrono_d::year(2000) / chrono_d::January / chrono_d::day(1));\n\t\t\tchrono_d::sys_days currentDateDay = chrono_d::floor<chrono_d::days>(std::chrono::system_clock::now());\n\t\t\treturn (uint16)(currentDateDay - startDateDay).count();\n\t\t}\n\n\t\tstruct PlayStatsEntry \n\t\t{\n\t\t\tuint32be titleIdHigh;\n\t\t\tuint32be titleIdLow;\n\t\t\tuint32be totalMinutesPlayed;\n\t\t\tuint16be numTimesLaunched;\n\t\t\tuint16be firstLaunchDayIndex; // first time this title was launched\n\t\t\tuint16be mostRecentDayIndex; // last time this title was played\n\t\t\tuint16be ukn12; // maybe just padding?\n\t\t};\n\n\t\tstatic_assert(sizeof(PlayStatsEntry) == 0x14);\n\n\t\tstruct\n\t\t{\n\t\t\tFileStream* fs{};\n\t\t\tuint32be numEntries;\n\t\t\tPlayStatsEntry entry[NUM_PLAY_STATS_ENTRIES];\n\t\t}PlayStats;\n\n\t\tvoid CreatePlaystats()\n\t\t{\n\t\t\tPlayStats.fs = FileStream::createFile2(GetPDFile(\"PlayStats.dat\"));\n\t\t\tif (!PlayStats.fs)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Unable to open or create PlayStats.dat\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tuint32be entryCount = 0;\n\t\t\tPlayStats.fs->writeData(&entryCount, sizeof(uint32be));\n\t\t\tPlayStats.fs->writeData(PlayStats.entry, NUM_PLAY_STATS_ENTRIES * sizeof(PlayStatsEntry));\n\t\t\tstatic_assert((NUM_PLAY_STATS_ENTRIES * sizeof(PlayStatsEntry)) == 0x1400);\n\t\t}\n\n\t\tvoid OpenPlaystats()\n\t\t{\n\t\t\tstd::unique_lock _l(sPlaystatsLock);\n\t\t\tPlayStats.numEntries = 0;\n\t\t\tfor (size_t i = 0; i < NUM_PLAY_STATS_ENTRIES; i++)\n\t\t\t{\n\t\t\t\tauto& e = PlayStats.entry[i];\n\t\t\t\tmemset(&e, 0, sizeof(PlayStatsEntry));\n\t\t\t}\n\t\t\tcemu_assert_debug(!PlayStats.fs);\n\t\t\tPlayStats.fs = FileStream::openFile2(GetPDFile(\"PlayStats.dat\"), true);\n\t\t\tif (!PlayStats.fs)\n\t\t\t{\n\t\t\t\tCreatePlaystats();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (PlayStats.fs->GetSize() != (NUM_PLAY_STATS_ENTRIES * 20 + 4))\n\t\t\t{\n\t\t\t\tdelete PlayStats.fs;\n\t\t\t\tPlayStats.fs = nullptr;\n\t\t\t\tcemuLog_log(LogType::Force, \"PlayStats.dat malformed. Time tracking wont be used\");\n\t\t\t\t// dont delete the existing file in case it could still be salvaged (todo) and instead just dont track play time\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tPlayStats.numEntries = 0;\n\t\t\tPlayStats.fs->readData(&PlayStats.numEntries, sizeof(uint32be));\n\t\t\tif (PlayStats.numEntries > NUM_PLAY_STATS_ENTRIES)\n\t\t\t\tPlayStats.numEntries = NUM_PLAY_STATS_ENTRIES;\n\t\t\tPlayStats.fs->readData(PlayStats.entry, NUM_PLAY_STATS_ENTRIES * 20);\n\t\t}\n\n\t\tvoid ClosePlaystats()\n\t\t{\n\t\t\tstd::unique_lock _l(sPlaystatsLock);\n\t\t\tif (PlayStats.fs)\n\t\t\t{\n\t\t\t\tdelete PlayStats.fs;\n\t\t\t\tPlayStats.fs = nullptr;\n\t\t\t}\n\t\t}\n\n\t\tvoid UnloadPlaystats()\n\t\t{\n\t\t\tstd::unique_lock _l(sPlaystatsLock);\n\t\t\tcemu_assert_debug(!PlayStats.fs); // unloading expects that file is closed\n\t\t\tPlayStats.numEntries = 0;\n\t\t\tfor(auto& it : PlayStats.entry)\n\t\t\t\tit = PlayStatsEntry{};\n\t\t}\n\n\t\tPlayStatsEntry* PlayStats_GetEntry(uint64 titleId)\n\t\t{\n\t\t\tstd::unique_lock _l(sPlaystatsLock);\n\t\t\tuint32be titleIdHigh = (uint32)(titleId>>32);\n\t\t\tuint32be titleIdLow = (uint32)(titleId & 0xFFFFFFFF);\n\t\t\tsize_t numEntries = PlayStats.numEntries;\n\t\t\tfor (size_t i = 0; i < numEntries; i++)\n\t\t\t{\n\t\t\t\tif (PlayStats.entry[i].titleIdHigh == titleIdHigh && PlayStats.entry[i].titleIdLow == titleIdLow)\n\t\t\t\t\treturn &PlayStats.entry[i];\n\t\t\t}\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tvoid PlayStats_WriteEntryNoLock(PlayStatsEntry* entry, bool writeEntryCount = false)\n\t\t{\n\t\t\tif (!PlayStats.fs)\n\t\t\t\treturn;\n\t\t\tsize_t entryIndex = entry - PlayStats.entry;\n\t\t\tcemu_assert(entryIndex < NUM_PLAY_STATS_ENTRIES);\n\t\t\tPlayStats.fs->SetPosition(4 + entryIndex * sizeof(PlayStatsEntry));\n\t\t\tif (PlayStats.fs->writeData(entry, sizeof(PlayStatsEntry)) != sizeof(PlayStatsEntry))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to write to PlayStats.dat\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (writeEntryCount)\n\t\t\t{\n\t\t\t\tuint32be numEntries = PlayStats.numEntries;\n\t\t\t\tPlayStats.fs->SetPosition(0);\n\t\t\t\tPlayStats.fs->writeData(&numEntries, sizeof(uint32be));\n\t\t\t}\n\t\t}\n\n\t\tvoid PlayStats_WriteEntry(PlayStatsEntry* entry, bool writeEntryCount = false)\n\t\t{\n\t\t\tstd::unique_lock _l(sPlaystatsLock);\n\t\t\tPlayStats_WriteEntryNoLock(entry, writeEntryCount);\n\t\t}\n\n\t\tPlayStatsEntry* PlayStats_CreateEntry(uint64 titleId)\n\t\t{\n\t\t\tstd::unique_lock _l(sPlaystatsLock);\n\t\t\tbool entryCountChanged = false;\n\t\t\tPlayStatsEntry* newEntry;\n\t\t\tif(PlayStats.numEntries < NUM_PLAY_STATS_ENTRIES)\n\t\t\t{\n\t\t\t\tnewEntry = PlayStats.entry + PlayStats.numEntries;\n\t\t\t\tPlayStats.numEntries += 1;\n\t\t\t\tentryCountChanged = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// list is full - find existing entry with least amount of minutes and replace it\n\t\t\t\tnewEntry = PlayStats.entry + 0;\n\t\t\t\tfor (uint32 i = 1; i < NUM_PLAY_STATS_ENTRIES; i++)\n\t\t\t\t{\n\t\t\t\t\tif(PlayStats.entry[i].totalMinutesPlayed < newEntry->totalMinutesPlayed)\n\t\t\t\t\t\tnewEntry = PlayStats.entry + i;\n\t\t\t\t}\n\t\t\t}\n\t\t\tnewEntry->titleIdHigh = (uint32)(titleId >> 32);\n\t\t\tnewEntry->titleIdLow = (uint32)(titleId & 0xFFFFFFFF);\n\t\t\tnewEntry->firstLaunchDayIndex = GetTodaysDayIndex();\n\t\t\tnewEntry->mostRecentDayIndex = newEntry->firstLaunchDayIndex;\n\t\t\tnewEntry->numTimesLaunched = 1;\n\t\t\tnewEntry->totalMinutesPlayed = 0;\n\t\t\tnewEntry->ukn12 = 0;\n\t\t\tPlayStats_WriteEntryNoLock(newEntry, entryCountChanged);\n\t\t\treturn newEntry;\n\t\t}\n\n\t\t// sets last played if entry already exists\n\t\t// if it does not exist it creates a new entry with first and last played set to today\n\t\tPlayStatsEntry* PlayStats_BeginNewTracking(uint64 titleId)\n\t\t{\n\t\t\tstd::unique_lock _l(sPlaystatsLock);\n\t\t\tPlayStatsEntry* entry = PlayStats_GetEntry(titleId);\n\t\t\tif (entry)\n\t\t\t{\n\t\t\t\tentry->mostRecentDayIndex = GetTodaysDayIndex();\n\t\t\t\tentry->numTimesLaunched += 1;\n\t\t\t\tPlayStats_WriteEntry(entry);\n\t\t\t\treturn entry;\n\t\t\t}\n\t\t\treturn PlayStats_CreateEntry(titleId);\n\t\t}\n\n\t\tvoid PlayStats_CountAdditionalMinutes(PlayStatsEntry* entry, uint32 additionalMinutes)\n\t\t{\n\t\t\tstd::unique_lock _l(sPlaystatsLock);\n\t\t\tif (additionalMinutes == 0)\n\t\t\t\treturn;\n\t\t\tentry->totalMinutesPlayed += additionalMinutes;\n\t\t\tentry->mostRecentDayIndex = GetTodaysDayIndex();\n\t\t\tPlayStats_WriteEntryNoLock(entry);\n\t\t}\n\n\t\tstruct PlayDiaryHeader\n\t\t{\n\t\t\t// the play diary is a rolling log\n\t\t\t// initially only writeIndex increases\n\t\t\t// after the log is filled, writeIndex wraps over and readIndex will increase as well\n\t\t\tuint32be readIndex;\n\t\t\tuint32be writeIndex;\n\t\t};\n\n\t\tstatic_assert(sizeof(PlayDiaryEntry) == 0x10);\n\t\tstatic_assert(sizeof(PlayDiaryHeader) == 0x8);\n\n\t\tstruct\n\t\t{\n\t\t\tFileStream* fs{};\n\t\t\tPlayDiaryHeader header;\n\t\t\tPlayDiaryEntry entry[NUM_PLAY_DIARY_ENTRIES_MAX];\n\t\t}PlayDiaryData;\n\n\t\tvoid CreatePlayDiary()\n\t\t{\n\t\t\tMakeDirectory();\n\t\t\tcemu_assert_debug(!PlayDiaryData.fs);\n\t\t\tPlayDiaryData.fs = FileStream::createFile2(GetPDFile(\"PlayDiary.dat\"));\n\t\t\tif (!PlayDiaryData.fs)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to read or write PlayDiary.dat, playtime tracking will not be possible\");\n\t\t\t}\n\t\t\t// write header\n\t\t\tPlayDiaryData.header.readIndex = 0;\n\t\t\tPlayDiaryData.header.writeIndex = 0;\n\t\t\tif (PlayDiaryData.fs)\n\t\t\t\tPlayDiaryData.fs->writeData(&PlayDiaryData.header, sizeof(PlayDiaryHeader));\n\t\t}\n\n\t\tvoid OpenPlayDiary()\n\t\t{\n\t\t\tstd::unique_lock _lock(sDiaryLock);\n\t\t\tcemu_assert_debug(!PlayDiaryData.fs);\n\t\t\tPlayDiaryData.fs = FileStream::openFile2(GetPDFile(\"PlayDiary.dat\"), true);\n\t\t\tif (!PlayDiaryData.fs)\n\t\t\t{\n\t\t\t\tCreatePlayDiary();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// read header\n\t\t\tif (PlayDiaryData.fs->readData(&PlayDiaryData.header, sizeof(PlayDiaryHeader)) != sizeof(PlayDiaryHeader))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to read valid PlayDiary header\");\n\t\t\t\tdelete PlayDiaryData.fs;\n\t\t\t\tPlayDiaryData.fs = nullptr;\n\t\t\t\tCreatePlayDiary();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (PlayDiaryData.header.readIndex > NUM_PLAY_DIARY_ENTRIES_MAX || PlayDiaryData.header.writeIndex > NUM_PLAY_DIARY_ENTRIES_MAX)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Bad value in play diary header (read={} write={})\", (uint32)PlayDiaryData.header.readIndex, (uint32)PlayDiaryData.header.writeIndex);\n\t\t\t\tPlayDiaryData.header.readIndex = PlayDiaryData.header.readIndex % NUM_PLAY_DIARY_ENTRIES_MAX;\n\t\t\t\tPlayDiaryData.header.writeIndex = PlayDiaryData.header.writeIndex % NUM_PLAY_DIARY_ENTRIES_MAX;\n\t\t\t}\n\t\t\t// read entries and set any not-yet-written entries to zero\n\t\t\tuint32 readBytes = PlayDiaryData.fs->readData(PlayDiaryData.entry, NUM_PLAY_DIARY_ENTRIES_MAX * sizeof(PlayDiaryEntry));\n\t\t\tuint32 readEntries = readBytes / sizeof(PlayDiaryEntry);\n\t\t\twhile (readEntries < NUM_PLAY_DIARY_ENTRIES_MAX)\n\t\t\t{\n\t\t\t\tPlayDiaryData.entry[readEntries].titleId = 0;\n\t\t\t\tPlayDiaryData.entry[readEntries].ukn08 = 0;\n\t\t\t\tPlayDiaryData.entry[readEntries].dayIndex = 0;\n\t\t\t\tPlayDiaryData.entry[readEntries].ukn0E = 0;\n\t\t\t\treadEntries++;\n\t\t\t}\n\t\t}\n\n\t\tvoid ClosePlayDiary()\n\t\t{\n\t\t\tstd::unique_lock _lock(sDiaryLock);\n\t\t\tif (PlayDiaryData.fs)\n\t\t\t{\n\t\t\t\tdelete PlayDiaryData.fs;\n\t\t\t\tPlayDiaryData.fs = nullptr;\n\t\t\t}\n\t\t}\n\n\t\tvoid UnloadDiaryData()\n\t\t{\n\t\t\tstd::unique_lock _lock(sDiaryLock);\n\t\t\tcemu_assert_debug(!PlayDiaryData.fs); // unloading expects that file is closed\n\t\t\tPlayDiaryData.header.readIndex = 0;\n\t\t\tPlayDiaryData.header.writeIndex = 0;\n\t\t\tfor (auto& it : PlayDiaryData.entry)\n\t\t\t\tit = PlayDiaryEntry{};\n\t\t}\n\n\t\tuint32 GetDiaryEntries(uint8 accountSlot, PlayDiaryEntry* diaryEntries, uint32 maxEntries)\n\t\t{\n\t\t\tstd::unique_lock _lock(sDiaryLock);\n\t\t\tuint32 numReadEntries = 0;\n\t\t\tuint32 currentEntryIndex = PlayDiaryData.header.readIndex;\n\t\t\twhile (currentEntryIndex != PlayDiaryData.header.writeIndex && numReadEntries < maxEntries)\n\t\t\t{\n\t\t\t\t*diaryEntries = PlayDiaryData.entry[currentEntryIndex];\n\t\t\t\tnumReadEntries++;\n\t\t\t\tdiaryEntries++;\n\t\t\t\tcurrentEntryIndex = (currentEntryIndex+1) % NUM_PLAY_DIARY_ENTRIES_MAX;\n\t\t\t}\n\t\t\treturn numReadEntries;\n\t\t}\n\n\t\tbool GetStatForGamelist(uint64 titleId, GameListStat& stat)\n\t\t{\n\t\t\tstat.last_played.year = 0;\n\t\t\tstat.last_played.month = 0;\n\t\t\tstat.last_played.day = 0;\n\t\t\tstat.numMinutesPlayed = 0;\n\t\t\tstd::unique_lock _lock(sDiaryLock);\n\t\t\t// the play stats give us last time played and the total minutes\n\t\t\tPlayStatsEntry* playStats = PlayStats_GetEntry(titleId);\n\t\t\tif (playStats)\n\t\t\t{\n\t\t\t\tstat.numMinutesPlayed = playStats->totalMinutesPlayed;\n\t\t\t\tchrono_d::year_month_day ymd = GetDateFromDayIndex(playStats->mostRecentDayIndex);\n\t\t\t\tstat.last_played.year = (int)ymd.year();\n\t\t\t\tstat.last_played.month = (unsigned int)ymd.month() - 1;\n\t\t\t\tstat.last_played.day = (unsigned int)ymd.day();\n\t\t\t}\n\t\t\t_lock.unlock();\n\t\t\t// check legacy time tracking for game entries in settings.xml\n\t\t\tstd::unique_lock _lockGC(GetConfig().game_cache_entries_mutex);\n\t\t\tfor (auto& gameEntry : GetConfig().game_cache_entries)\n\t\t\t{\n\t\t\t\tif(gameEntry.title_id != titleId)\n\t\t\t\t\tcontinue;\n\t\t\t\tstat.numMinutesPlayed += (gameEntry.legacy_time_played / 60);\t\t\t\t\n\t\t\t\tif (gameEntry.legacy_last_played != 0)\n\t\t\t\t{\n\t\t\t\t\ttime_t td = gameEntry.legacy_last_played;\n\t\t\t\t\ttm* date = localtime(&td);\n\t\t\t\t\tuint32 legacyYear = (uint32)date->tm_year + 1900;\n\t\t\t\t\tuint32 legacyMonth = (uint32)date->tm_mon;\n\t\t\t\t\tuint32 legacyDay = (uint32)date->tm_mday;\n\t\t\t\t\tif (stat.last_played.year == 0 || std::tie(legacyYear, legacyMonth, legacyDay) > std::tie(stat.last_played.year, stat.last_played.month, stat.last_played.day))\n\t\t\t\t\t{\n\t\t\t\t\t\tstat.last_played.year = legacyYear;\n\t\t\t\t\t\tstat.last_played.month = legacyMonth;\n\t\t\t\t\t\tstat.last_played.day = legacyDay;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tstd::thread sPDMTimeTrackingThread;\n\t\tCounterSemaphore sPDMSem;\n\t\tstd::atomic_bool sPDMRequestExitThread{ false };\n\n\t\tvoid TimeTrackingThread(uint64 titleId)\n\t\t{\n\t\t\tSetThreadName(\"PlayDiaryThread\");\n\t\t\tPlayStatsEntry* playStatsEntry = PlayStats_BeginNewTracking(titleId);\n\n\t\t\tauto startTime = std::chrono::steady_clock::now();\n\t\t\tuint32 prevMinuteCounter = 0;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tsPDMSem.decrementWithWaitAndTimeout(15000);\n\t\t\t\tif (sPDMRequestExitThread.load(std::memory_order::relaxed))\n\t\t\t\t\tbreak;\n\t\t\t\tauto currentTime = std::chrono::steady_clock::now();\n\t\t\t\tuint32 elapsedMinutes = std::chrono::duration_cast<std::chrono::minutes>(currentTime - startTime).count();\n\t\t\t\tif (elapsedMinutes > prevMinuteCounter)\n\t\t\t\t{\n\t\t\t\t\tPlayStats_CountAdditionalMinutes(playStatsEntry, (elapsedMinutes - prevMinuteCounter));\n\t\t\t\t\t// todo - also update PlayDiary (and other files)\n\t\t\t\t\tprevMinuteCounter = elapsedMinutes;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tclass : public ::IOSUModule\n\t\t{\n\t\t\tvoid PDMLoadAll()\n\t\t\t{\n\t\t\t\tOpenPlaystats();\n\t\t\t\tOpenPlayDiary();\n\t\t\t}\n\n\t\t\tvoid PDMUnloadAll()\n\t\t\t{\n\t\t\t\tUnloadPlaystats();\n\t\t\t\tUnloadDiaryData();\n\t\t\t}\n\n\t\t\tvoid PDMCloseAll()\n\t\t\t{\n\t\t\t\tClosePlaystats();\n\t\t\t\tClosePlayDiary();\n\t\t\t}\n\n\t\t\tvoid SystemLaunch() override\n\t\t\t{\n\t\t\t\t// todo - add support for per-account handling\n\t\t\t\tPDMLoadAll();\n\t\t\t\tPDMCloseAll(); // close the files again, user may mess with MLC files or change MLC path while no game is running\n\t\t\t}\n\t\t\tvoid SystemExit() override\n\t\t\t{\n\t\t\t\tPDMCloseAll();\n\t\t\t\tPDMUnloadAll();\n\t\t\t}\n\t\t\tvoid TitleStart() override\n\t\t\t{\n\t\t\t\t// reload data and keep files open\n\t\t\t\tPDMUnloadAll();\n\t\t\t\tPDMLoadAll();\n\t\t\t\tauto titleId = CafeSystem::GetForegroundTitleId();\n\t\t\t\tsPDMRequestExitThread = false;\n\t\t\t\tsPDMTimeTrackingThread = std::thread(TimeTrackingThread, titleId);\n\t\t\t}\n\t\t\tvoid TitleStop() override\n\t\t\t{\n\t\t\t\tsPDMRequestExitThread.store(true);\n\t\t\t\tsPDMSem.increment();\n\t\t\t\tif(sPDMTimeTrackingThread.joinable())\n\t\t\t\t\tsPDMTimeTrackingThread.join();\n\t\t\t\tPDMCloseAll();\n\t\t\t}\n\t\t}sIOSUModuleNNPDM;\n\n\t\tIOSUModule* GetModule()\n\t\t{\n\t\t\treturn static_cast<IOSUModule*>(&sIOSUModuleNNPDM);\n\t\t}\n\n\n\t\tbool GameListStat::LastPlayDate::operator<(const LastPlayDate& b) const\n\t\t{\n\t\t\tconst auto& a = *this;\n\n\t\t\tif(a.year < b.year)\n\t\t\t\treturn true;\n\t\t\tif(a.year > b.year)\n\t\t\t\treturn false;\n\n\t\t\t// same year\n\t\t\tif(a.month < b.month)\n\t\t\t\treturn true;\n\t\t\tif(a.month > b.month)\n\t\t\t\treturn false;\n\n\t\t\t// same year and month\n\t\t\treturn a.day < b.day;\n\t\t}\n\n\t\tbool GameListStat::LastPlayDate::operator==(const LastPlayDate& b) const\n\t\t{\n\t\t\tconst auto& a = *this;\n\t\t\treturn a.year == b.year &&\n\t\t\t\t   a.month == b.month &&\n\t\t\t\t   a.day == b.day;\n\t\t}\n\t\tstd::weak_ordering GameListStat::LastPlayDate::operator<=>(const LastPlayDate& b) const = default;\n\n\t};\n};\n"
  },
  {
    "path": "src/Cafe/IOSU/PDM/iosu_pdm.h",
    "content": "#pragma once\n#include \"Cafe/IOSU/iosu_types_common.h\"\n\nnamespace iosu\n{\n\tnamespace pdm\n\t{\n\t\tinline constexpr size_t NUM_PLAY_STATS_ENTRIES = 256;\n\t\tinline constexpr size_t NUM_PLAY_DIARY_ENTRIES_MAX = 18250; // 0x474A\n\n\t\tstruct PlayDiaryEntry\n\t\t{\n\t\t\tuint64be titleId;\n\t\t\tuint32be ukn08; // probably minutes\n\t\t\tuint16be dayIndex;\n\t\t\tuint16be ukn0E;\n\t\t};\n\n\t\tuint32 GetDiaryEntries(uint8 accountSlot, PlayDiaryEntry* diaryEntries, uint32 maxEntries);\n\n\t\t/* Helper for UI game list */\n\t\tstruct GameListStat\n\t\t{\n\t\t\tstruct LastPlayDate\n\t\t\t{\n\t\t\t\tuint32 year; // if 0 -> never played\n\t\t\t\tuint32 month;\n\t\t\t\tuint32 day;\n\n\t\t\t\tbool operator<(const LastPlayDate& b) const;\n\t\t\t\tbool operator==(const LastPlayDate& b) const;\n\t\t\t\tstd::weak_ordering operator<=>(const LastPlayDate& b) const;\n\t\t\t}last_played;\n\t\t\tuint32 numMinutesPlayed;\n\t\t};\n\n\t\tbool GetStatForGamelist(uint64 titleId, GameListStat& stat);\n\n\t\tIOSUModule* GetModule();\n\t};\n};"
  },
  {
    "path": "src/Cafe/IOSU/ccr_nfc/iosu_ccr_nfc.cpp",
    "content": "#include \"iosu_ccr_nfc.h\"\n#include \"Cafe/IOSU/kernel/iosu_kernel.h\"\n#include \"util/crypto/aes128.h\"\n#include <openssl/evp.h>\n#include <openssl/hmac.h>\n\nnamespace iosu\n{\n\tnamespace ccr_nfc\n\t{\n\t\tIOSMsgQueueId sCCRNFCMsgQueue;\n\t\tSysAllocator<iosu::kernel::IOSMessage, 0x20> sCCRNFCMsgQueueMsgBuffer;\n\t\tstd::thread sCCRNFCThread;\n\n\t\tconstexpr uint8 sNfcKey[] = { 0xC1, 0x2B, 0x07, 0x10, 0xD7, 0x2C, 0xEB, 0x5D, 0x43, 0x49, 0xB7, 0x43, 0xE3, 0xCA, 0xD2, 0x24 };\n\t\tconstexpr uint8 sNfcKeyIV[] = { 0x4F, 0xD3, 0x9A, 0x6E, 0x79, 0xFC, 0xEA, 0xAD, 0x99, 0x90, 0x4D, 0xB8, 0xEE, 0x38, 0xE9, 0xDB };\n\n\t\tconstexpr uint8 sUnfixedInfosMagicBytes[] = { 0x00, 0x00, 0xDB, 0x4B, 0x9E, 0x3F, 0x45, 0x27, 0x8F, 0x39, 0x7E, 0xFF, 0x9B, 0x4F, 0xB9, 0x93 };\n\t\tconstexpr uint8 sLockedSecretMagicBytes[] = { 0xFD, 0xC8, 0xA0, 0x76, 0x94, 0xB8, 0x9E, 0x4C, 0x47, 0xD3, 0x7D, 0xE8, 0xCE, 0x5C, 0x74, 0xC1 };\n\t\tconstexpr uint8 sUnfixedInfosString[] = { 0x75, 0x6E, 0x66, 0x69, 0x78, 0x65, 0x64, 0x20, 0x69, 0x6E, 0x66, 0x6F, 0x73, 0x00, 0x00, 0x00 };\n\t\tconstexpr uint8 sLockedSecretString[] = { 0x6C, 0x6F, 0x63, 0x6B, 0x65, 0x64, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x00, 0x00, 0x00 };\n\n\t\tconstexpr uint8 sLockedSecretHmacKey[] = { 0x7F, 0x75, 0x2D, 0x28, 0x73, 0xA2, 0x00, 0x17, 0xFE, 0xF8, 0x5C, 0x05, 0x75, 0x90, 0x4B, 0x6D };\n\t\tconstexpr uint8 sUnfixedInfosHmacKey[] = { 0x1D, 0x16, 0x4B, 0x37, 0x5B, 0x72, 0xA5, 0x57, 0x28, 0xB9, 0x1D, 0x64, 0xB6, 0xA3, 0xC2, 0x05 };\n\n\t\tuint8 sLockedSecretInternalKey[0x10];\n\t\tuint8 sLockedSecretInternalNonce[0x10];\n\t\tuint8 sLockedSecretInternalHmacKey[0x10];\n\n\t\tuint8 sUnfixedInfosInternalKey[0x10];\n\t\tuint8 sUnfixedInfosInternalNonce[0x10];\n\t\tuint8 sUnfixedInfosInternalHmacKey[0x10];\n\n\t\tsint32 __CCRNFCValidateCryptData(CCRNFCCryptData* data, uint32 size, bool validateOffsets)\n\t\t{\n\t\t\tif (!data)\n\t\t\t{\n\t\t\t\treturn CCR_NFC_ERROR;\n\t\t\t}\n\n\t\t\tif (size != sizeof(CCRNFCCryptData))\n\t\t\t{\n\t\t\t\treturn CCR_NFC_ERROR;\n\t\t\t}\n\n\t\t\tif (!validateOffsets)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\t// Make sure all offsets are within bounds\n\t\t\tif (data->version == 0)\n\t\t\t{\n\t\t\t\tif (data->unfixedInfosHmacOffset < 0x1C9 && data->unfixedInfosOffset < 0x1C9 &&\n\t\t\t\t\tdata->lockedSecretHmacOffset < 0x1C9 && data->lockedSecretOffset < 0x1C9 &&\n\t\t\t\t\tdata->lockedSecretSize < 0x1C9 && data->unfixedInfosSize < 0x1C9)\n\t\t\t\t{\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (data->version == 2)\n\t\t\t{\n\t\t\t\tif (data->unfixedInfosHmacOffset < 0x21D && data->unfixedInfosOffset < 0x21D &&\n\t\t\t\t\tdata->lockedSecretHmacOffset < 0x21D && data->lockedSecretOffset < 0x21D &&\n\t\t\t\t\tdata->lockedSecretSize < 0x21D && data->unfixedInfosSize < 0x21D)\n\t\t\t\t{\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn CCR_NFC_ERROR;\n\t\t}\n\n\t\tsint32 CCRNFCAESCTRCrypt(const uint8* key, const void* ivNonce, const void* inData, uint32 inSize, void* outData, uint32 outSize)\n\t\t{\n\t\t\tuint8 tmpIv[0x10];\n\t\t\tmemcpy(tmpIv, ivNonce, sizeof(tmpIv));\n\n\t\t\tmemcpy(outData, inData, inSize);\n\t\t\tAES128CTR_transform((uint8*)outData, outSize, (uint8*)key, tmpIv);\n\t\t\treturn 0;\n\t\t}\n\n\t\tsint32 __CCRNFCGenerateKey(const uint8* hmacKey, uint32 hmacKeySize, const uint8* name, uint32 nameSize, const uint8* inData, uint32 inSize, uint8* outData, uint32 outSize)\n\t\t{\n\t\t\tif (nameSize != 0xe || outSize != 0x40)\n\t\t\t{\n\t\t\t\treturn CCR_NFC_ERROR;\n\t\t\t}\n\n   \t\t\t// Create a buffer containing 2 counter bytes, the key name, and the key data\n\t\t\tuint8 buffer[0x50];\n\t\t\tbuffer[0] = 0;\n\t\t\tbuffer[1] = 0;\n\t\t\tmemcpy(buffer + 2, name, nameSize);\n\t\t\tmemcpy(buffer + nameSize + 2, inData, inSize);\n\n\t\t\tuint16 counter = 0;\n\t\t\twhile (outSize > 0)\n\t\t\t{\n        \t\t// Set counter bytes and increment counter\n\t\t\t\tbuffer[0] = (counter >> 8) & 0xFF;\n\t\t\t\tbuffer[1] = counter & 0xFF;\n\t\t\t\tcounter++;\n\n\t\t\t\tuint32 dataSize = outSize;\n\t\t\t\tif (!HMAC(EVP_sha256(), hmacKey, hmacKeySize, buffer, sizeof(buffer), outData, &dataSize))\n\t\t\t\t{\n\t\t\t\t\treturn CCR_NFC_ERROR;\n\t\t\t\t}\n\n\t\t\t\toutSize -= 0x20;\n\t\t\t\toutData += 0x20;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\tsint32 __CCRNFCGenerateInternalKeys(const CCRNFCCryptData* in, const uint8* keyGenSalt)\n\t\t{\n\t\t\tuint8 lockedSecretBuffer[0x40] = { 0 };\n\t\t\tuint8 unfixedInfosBuffer[0x40] = { 0 };\n\t\t\tuint8 outBuffer[0x40] = { 0 };\n\n\t\t\t// Fill the locked secret buffer\n\t\t\tmemcpy(lockedSecretBuffer, sLockedSecretMagicBytes, sizeof(sLockedSecretMagicBytes));\n\t\t\tif (in->version == 0)\n\t\t\t{\n\t\t\t\t// For Version 0 this is the 16-byte Format Info\n\t\t\t\tmemcpy(lockedSecretBuffer + 0x10, in->data + in->uuidOffset, 0x10);\n\t\t\t}\n\t\t\telse if (in->version == 2)\n\t\t\t{\n\t\t\t\t// For Version 2 this is 2 times the 7-byte UID + 1 check byte\n\t\t\t\tmemcpy(lockedSecretBuffer + 0x10, in->data + in->uuidOffset, 8);\n\t\t\t\tmemcpy(lockedSecretBuffer + 0x18, in->data + in->uuidOffset, 8);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn CCR_NFC_ERROR;\n\t\t\t}\n\t\t\t// Append key generation salt\n\t\t\tmemcpy(lockedSecretBuffer + 0x20, keyGenSalt, 0x20);\n\n\t\t\t// Generate the key output\n\t\t\tsint32 res = __CCRNFCGenerateKey(sLockedSecretHmacKey, sizeof(sLockedSecretHmacKey), sLockedSecretString, 0xe, lockedSecretBuffer, sizeof(lockedSecretBuffer), outBuffer, sizeof(outBuffer));\n\t\t\tif (res != 0)\n\t\t\t{\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\t// Unpack the key buffer\n\t\t\tmemcpy(sLockedSecretInternalKey, outBuffer, 0x10);\n\t\t\tmemcpy(sLockedSecretInternalNonce, outBuffer + 0x10, 0x10);\n\t\t\tmemcpy(sLockedSecretInternalHmacKey, outBuffer + 0x20, 0x10);\n\n\t\t\t// Fill the unfixed infos buffer\n\t\t\tmemcpy(unfixedInfosBuffer, in->data + in->seedOffset, 2);\n\t\t\tmemcpy(unfixedInfosBuffer + 2, sUnfixedInfosMagicBytes + 2, 0xe);\n\t\t\tif (in->version == 0)\n\t\t\t{\n\t\t\t\t// For Version 0 this is the 16-byte Format Info\n\t\t\t\tmemcpy(unfixedInfosBuffer + 0x10, in->data + in->uuidOffset, 0x10);\n\t\t\t}\n\t\t\telse if (in->version == 2)\n\t\t\t{\n\t\t\t\t// For Version 2 this is 2 times the 7-byte UID + 1 check byte\n\t\t\t\tmemcpy(unfixedInfosBuffer + 0x10, in->data + in->uuidOffset, 8);\n\t\t\t\tmemcpy(unfixedInfosBuffer + 0x18, in->data + in->uuidOffset, 8);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn CCR_NFC_ERROR;\n\t\t\t}\n\t\t\t// Append key generation salt\n\t\t\tmemcpy(unfixedInfosBuffer + 0x20, keyGenSalt, 0x20);\n\n\t\t\t// Generate the key output\n\t\t\tres = __CCRNFCGenerateKey(sUnfixedInfosHmacKey, sizeof(sUnfixedInfosHmacKey), sUnfixedInfosString, 0xe, unfixedInfosBuffer, sizeof(unfixedInfosBuffer), outBuffer, sizeof(outBuffer));\n\t\t\tif (res != 0)\n\t\t\t{\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\t// Unpack the key buffer\n\t\t\tmemcpy(sUnfixedInfosInternalKey, outBuffer, 0x10);\n\t\t\tmemcpy(sUnfixedInfosInternalNonce, outBuffer + 0x10, 0x10);\n\t\t\tmemcpy(sUnfixedInfosInternalHmacKey, outBuffer + 0x20, 0x10);\n\n\t\t\treturn 0;\n\t\t}\n\n\t\tsint32 __CCRNFCCryptData(const CCRNFCCryptData* in, CCRNFCCryptData* out, bool decrypt)\n\t\t{\n\t\t\t// Decrypt key generation salt\n\t\t\tuint8 keyGenSalt[0x20];\n\t\t\tsint32 res = CCRNFCAESCTRCrypt(sNfcKey, sNfcKeyIV, in->data + in->keyGenSaltOffset, 0x20, keyGenSalt, sizeof(keyGenSalt));\n\t\t\tif (res != 0)\n\t\t\t{\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\t// Prepare internal keys\n\t\t\tres = __CCRNFCGenerateInternalKeys(in, keyGenSalt);\n\t\t\tif (res != 0)\n\t\t\t{\n\t\t\t\treturn res;\n\t\t\t}\n\n\t\t\tif (decrypt)\n\t\t\t{\n\t\t\t\t// Only version 0 tags have an encrypted locked secret area\n\t\t\t\tif (in->version == 0)\n\t\t\t\t{\n\t\t\t\t\tres = CCRNFCAESCTRCrypt(sLockedSecretInternalKey, sLockedSecretInternalNonce, in->data + in->lockedSecretOffset, in->lockedSecretSize, out->data + in->lockedSecretOffset, in->lockedSecretSize);\n\t\t\t\t\tif (res != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn res;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Decrypt unfxied infos\n\t\t\t\tres = CCRNFCAESCTRCrypt(sUnfixedInfosInternalKey, sUnfixedInfosInternalNonce, in->data + in->unfixedInfosOffset, in->unfixedInfosSize, out->data + in->unfixedInfosOffset, in->unfixedInfosSize);\n\t\t\t\tif (res != 0)\n\t\t\t\t{\n\t\t\t\t\treturn res;\n\t\t\t\t}\n\n\t\t\t\t// Verify HMACs\n\t\t\t\tuint8 hmacBuffer[0x20];\n\t\t\t\tuint32 hmacLen = sizeof(hmacBuffer);\n\n\t\t\t\tif (!HMAC(EVP_sha256(), sLockedSecretInternalHmacKey, sizeof(sLockedSecretInternalHmacKey), out->data + in->lockedSecretHmacOffset + 0x20, (in->dataSize - in->lockedSecretHmacOffset) - 0x20, hmacBuffer, &hmacLen))\n\t\t\t\t{\n\t\t\t\t\treturn CCR_NFC_ERROR;\n\t\t\t\t}\n\n\t\t\t\tif (memcmp(in->data + in->lockedSecretHmacOffset, hmacBuffer, 0x20) != 0)\n\t\t\t\t{\n\t\t\t\t\treturn CCR_NFC_INVALID_LOCKED_SECRET;\n\t\t\t\t}\n\n\t\t\t\tif (in->version == 0)\n\t\t\t\t{\n\t\t\t\t\thmacLen = sizeof(hmacBuffer);\n\t\t\t\t\tres = HMAC(EVP_sha256(), sUnfixedInfosInternalHmacKey, sizeof(sUnfixedInfosInternalHmacKey), out->data + in->unfixedInfosHmacOffset + 0x20, (in->dataSize - in->unfixedInfosHmacOffset) - 0x20, hmacBuffer, &hmacLen) ? 0 : CCR_NFC_ERROR;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\thmacLen = sizeof(hmacBuffer);\n\t\t\t\t\tres = HMAC(EVP_sha256(), sUnfixedInfosInternalHmacKey, sizeof(sUnfixedInfosInternalHmacKey), out->data + in->unfixedInfosHmacOffset + 0x21, (in->dataSize - in->unfixedInfosHmacOffset) - 0x21, hmacBuffer, &hmacLen) ? 0 : CCR_NFC_ERROR;\n\t\t\t\t}\n\n\t\t\t\tif (memcmp(in->data + in->unfixedInfosHmacOffset, hmacBuffer, 0x20) != 0)\n\t\t\t\t{\n\t\t\t\t\treturn CCR_NFC_INVALID_UNFIXED_INFOS;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint8 hmacBuffer[0x20];\n\t\t\t\tuint32 hmacLen = sizeof(hmacBuffer);\n\n\t\t\t\tif (!HMAC(EVP_sha256(), sLockedSecretInternalHmacKey, sizeof(sLockedSecretInternalHmacKey), out->data + in->lockedSecretHmacOffset + 0x20, (in->dataSize - in->lockedSecretHmacOffset) - 0x20, hmacBuffer, &hmacLen))\n\t\t\t\t{\n\t\t\t\t\treturn CCR_NFC_ERROR;\n\t\t\t\t}\n\n\t\t\t\tif (memcmp(in->data + in->lockedSecretHmacOffset, hmacBuffer, 0x20) != 0)\n\t\t\t\t{\n\t\t\t\t\treturn CCR_NFC_INVALID_LOCKED_SECRET;\n\t\t\t\t}\n\n\t\t\t\t// Only version 0 tags have an encrypted locked secret area\n\t\t\t\tif (in->version == 0)\n\t\t\t\t{\n\t\t\t\t\tuint32 hmacLen = 0x20;\n\t\t\t\t\tif (!HMAC(EVP_sha256(), sUnfixedInfosInternalHmacKey, sizeof(sUnfixedInfosInternalHmacKey), out->data + in->unfixedInfosHmacOffset + 0x20, (in->dataSize - in->unfixedInfosHmacOffset) - 0x20, out->data + in->unfixedInfosHmacOffset, &hmacLen))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn CCR_NFC_ERROR;\n\t\t\t\t\t}\n\n\t\t\t\t\tres = CCRNFCAESCTRCrypt(sLockedSecretInternalKey, sLockedSecretInternalNonce, in->data + in->lockedSecretOffset, in->lockedSecretSize, out->data + in->lockedSecretOffset, in->lockedSecretSize);\n\t\t\t\t\tif (res != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn res;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tuint32 hmacLen = 0x20;\n\t\t\t\t\tif (!HMAC(EVP_sha256(), sUnfixedInfosInternalHmacKey, sizeof(sUnfixedInfosInternalHmacKey), out->data + in->unfixedInfosHmacOffset + 0x21, (in->dataSize - in->unfixedInfosHmacOffset) - 0x21, out->data + in->unfixedInfosHmacOffset, &hmacLen))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn CCR_NFC_ERROR;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tres = CCRNFCAESCTRCrypt(sUnfixedInfosInternalKey, sUnfixedInfosInternalNonce, in->data + in->unfixedInfosOffset, in->unfixedInfosSize, out->data + in->unfixedInfosOffset, in->unfixedInfosSize);\n\t\t\t\tif (res != 0)\n\t\t\t\t{\n\t\t\t\t\treturn res;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn res;\n\t\t}\n\n\t\tvoid CCRNFCThread()\n\t\t{\n\t\t\tiosu::kernel::IOSMessage msg;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tIOS_ERROR error = iosu::kernel::IOS_ReceiveMessage(sCCRNFCMsgQueue, &msg, 0);\n\t\t\t\tcemu_assert(!IOS_ResultIsError(error));\n\n\t\t\t\t// Check for system exit\n\t\t\t\tif (msg == 0xf00dd00d)\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tIPCCommandBody* cmd = MEMPTR<IPCCommandBody>(msg).GetPtr();\n\t\t\t\tif (cmd->cmdId == IPCCommandId::IOS_OPEN)\n\t\t\t\t{\n\t\t\t\t\tiosu::kernel::IOS_ResourceReply(cmd, IOS_ERROR_OK);\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_CLOSE)\n\t\t\t\t{\n\t\t\t\t\tiosu::kernel::IOS_ResourceReply(cmd, IOS_ERROR_OK);\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_IOCTL)\n\t\t\t\t{\n\t\t\t\t\tsint32 result;\n\t\t\t\t\tuint32 requestId = cmd->args[0];\n\t\t\t\t\tvoid* ptrIn = MEMPTR<void>(cmd->args[1]);\n\t\t\t\t\tuint32 sizeIn = cmd->args[2];\n\t\t\t\t\tvoid* ptrOut = MEMPTR<void>(cmd->args[3]);\n\t\t\t\t\tuint32 sizeOut = cmd->args[4];\n\n\t\t\t\t\tif ((result = __CCRNFCValidateCryptData(static_cast<CCRNFCCryptData*>(ptrIn), sizeIn, true)) == 0 && \n\t\t\t\t\t\t(result = __CCRNFCValidateCryptData(static_cast<CCRNFCCryptData*>(ptrOut), sizeOut, false)) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Initialize outData with inData\n\t\t\t\t\t\tmemcpy(ptrOut, ptrIn, sizeIn);\n\n\t\t\t\t\t\tswitch (requestId)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase 1: // encrypt\n\t\t\t\t\t\t\tresult = __CCRNFCCryptData(static_cast<CCRNFCCryptData*>(ptrIn), static_cast<CCRNFCCryptData*>(ptrOut), false);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 2: // decrypt\n\t\t\t\t\t\t\tresult = __CCRNFCCryptData(static_cast<CCRNFCCryptData*>(ptrIn), static_cast<CCRNFCCryptData*>(ptrOut), true);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"/dev/ccr_nfc: Unsupported IOCTL requestId\");\n\t\t\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\t\t\t\tresult = IOS_ERROR_INVALID;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tiosu::kernel::IOS_ResourceReply(cmd, static_cast<IOS_ERROR>(result));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"/dev/ccr_nfc: Unsupported IPC cmdId\");\n\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\t\tiosu::kernel::IOS_ResourceReply(cmd, IOS_ERROR_INVALID);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tclass : public ::IOSUModule\n\t\t{\n\t\t\tvoid SystemLaunch() override\n\t\t\t{\n\t\t\t\tsCCRNFCMsgQueue = iosu::kernel::IOS_CreateMessageQueue(sCCRNFCMsgQueueMsgBuffer.GetPtr(), sCCRNFCMsgQueueMsgBuffer.GetCount());\n\t\t\t\tcemu_assert(!IOS_ResultIsError(static_cast<IOS_ERROR>(sCCRNFCMsgQueue)));\n\n\t\t\t\tIOS_ERROR error = iosu::kernel::IOS_RegisterResourceManager(\"/dev/ccr_nfc\", sCCRNFCMsgQueue);\n\t\t\t\tcemu_assert(!IOS_ResultIsError(error));\n\n\t\t\t\tsCCRNFCThread = std::thread(CCRNFCThread);\n\t\t\t}\n\n\t\t\tvoid SystemExit() override\n\t\t\t{\n\t\t\t\tif (sCCRNFCMsgQueue < 0)\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tiosu::kernel::IOS_SendMessage(sCCRNFCMsgQueue, 0xf00dd00d, 0);\n\t\t\t\tsCCRNFCThread.join();\n\n\t\t\t\tiosu::kernel::IOS_DestroyMessageQueue(sCCRNFCMsgQueue);\n\t\t\t\tsCCRNFCMsgQueue = -1;\n\t\t\t}\n\t\t} sIOSUModuleCCRNFC;\n\n\t\tIOSUModule* GetModule()\n\t\t{\n\t\t\treturn &sIOSUModuleCCRNFC;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/ccr_nfc/iosu_ccr_nfc.h",
    "content": "#pragma once\n#include \"Cafe/IOSU/iosu_types_common.h\"\n\n#define CCR_NFC_ERROR \t\t\t\t\t(-0x2F001E)\n#define CCR_NFC_INVALID_LOCKED_SECRET\t(-0x2F0029)\n#define CCR_NFC_INVALID_UNFIXED_INFOS\t(-0x2F002A)\n\nnamespace iosu\n{\n\tnamespace ccr_nfc\n\t{\n\t\tstruct CCRNFCCryptData\n\t\t{\n\t\t\tuint32 version;\n\t\t\tuint32 dataSize;\n\t\t\tuint32 seedOffset;\n\t\t\tuint32 keyGenSaltOffset;\n\t\t\tuint32 uuidOffset;\n\t\t\tuint32 unfixedInfosOffset;\n\t\t\tuint32 unfixedInfosSize;\n\t\t\tuint32 lockedSecretOffset;\n\t\t\tuint32 lockedSecretSize;\n\t\t\tuint32 unfixedInfosHmacOffset;\n\t\t\tuint32 lockedSecretHmacOffset;\n\t\t\tuint8 data[540];\n\t\t};\n\t\tstatic_assert(sizeof(CCRNFCCryptData) == 0x248);\n\n\t\tIOSUModule* GetModule();\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/fsa/fsa_types.h",
    "content": "#pragma once\n\nenum class FS_RESULT : sint32 // aka FSStatus\n{\n\tSUCCESS = 0,\n\tEND_ITERATION = -2, // used by FSGetMountSource / FSGetMountSourceNext to indicate when last element was reached\n\tMAX_HANDLES = -3,\n\tALREADY_EXISTS = -5,\n\tNOT_FOUND = -6,\n\tNOT_FILE = -7,\n\tNOT_DIR = -8,\n\tPERMISSION_ERROR = -10,\n\n\tFATAL_ERROR = -0x400,\n\tERR_PLACEHOLDER = -9999, // used when exact error code has yet to be determined\n};\n\nenum class FSA_RESULT : sint32 // aka FSError/FSAStatus\n{\n\tOK = 0,\n\tNOT_INIT = -0x30000 - 0x01,\n\tEND_OF_DIRECTORY = -0x30000 - 0x04,\n\tEND_OF_FILE = -0x30000 - 0x05,\n\tMAX_CLIENTS = -0x30000 - 0x12,\n\tMAX_FILES = -0x30000 - 0x13,\n\tMAX_DIRS = -0x30000 - 0x14,\n\tALREADY_EXISTS = -0x30000 - 0x16,\n\tNOT_FOUND = -0x30000 - 0x17,\n\tPERMISSION_ERROR = -0x30000 - 0x1A,\n\tINVALID_PARAM = -0x30000 - 0x21,\n\tINVALID_PATH = -0x30000 - 0x22,\n\tINVALID_BUFFER = -0x30000 - 0x23,\n\tINVALID_ALIGNMENT = -0x30000 - 0x24,\n\tINVALID_CLIENT_HANDLE = -0x30000 - 0x25,\n\tINVALID_FILE_HANDLE = -0x30000 - 0x26,\n\tINVALID_DIR_HANDLE = -0x30000 - 0x27,\n\tNOT_FILE = -0x30000 - 0x28,\n\tNOT_DIR = -0x30000 - 0x29,\n\tOUT_OF_RESOURCES = -0x30000 - 0x2C,\n\tFATAL_ERROR = -0x30000 - 0x400,\n};\n\nenum class FSA_CMD_OPERATION_TYPE : uint32\n{\n\tCHANGEDIR = 0x5,\n\tGETCWD = 0x6,\n\tMAKEDIR = 0x7,\n\tREMOVE = 0x8,\n\tRENAME = 0x9,\n\tOPENDIR = 0xA,\n\tREADDIR = 0xB,\n\tREWINDDIR = 0xC,\n\tCLOSEDIR = 0xD,\n\tOPENFILE = 0xE,\n\tREAD = 0xF,\n\tWRITE = 0x10,\n\tGETPOS = 0x11,\n\tSETPOS = 0x12,\n\tISEOF = 0x13,\n\tGETSTATFILE = 0x14,\n\tCLOSEFILE = 0x15,\n\tFLUSHFILE = 0x17,\n\tQUERYINFO = 0x18,\n\tAPPENDFILE = 0x19,\n\tTRUNCATEFILE = 0x1A,\n\tFLUSHQUOTA = 0x1E,\n};\n\nusing FSResHandle = sint32;\nusing FSFileHandle2 = FSResHandle;\nusing FSDirHandle2 = FSResHandle;\n#define FS_INVALID_HANDLE_VALUE -1\n\n#define FSA_FILENAME_SIZE_MAX 128\n#define FSA_PATH_SIZE_MAX (512 + FSA_FILENAME_SIZE_MAX)\n#define FSA_CMD_PATH_MAX_LENGTH FSA_PATH_SIZE_MAX\n#define FSA_MAX_CLIENTS 32\n\ntypedef sint32 FSStatus;\t  // DEPR - replaced by FS_RESULT\ntypedef uint32 FS_ERROR_MASK; // replace with enum bitmask\ntypedef uint32 FSFileSize;\ntypedef uint64 FSLargeSize;\ntypedef uint64 FSTime;\n\nenum class FSFlag : uint32\n{\n\tNONE = 0,\n\tIS_DIR = 0x80000000,\n\tIS_FILE = 0x01000000,\n};\nDEFINE_ENUM_FLAG_OPERATORS(FSFlag);\n\n#pragma pack(1)\n\nstruct FSStat_t\n{\n\t/* +0x000 */ betype<FSFlag> flag;\n\t/* +0x004 */ uint32be permissions;\n\t/* +0x008 */ uint32be ownerId;\n\t/* +0x00C */ uint32be groupId;\n\t/* +0x010 */ betype<FSFileSize> size;\n\t/* +0x014 */ betype<FSFileSize> allocatedSize;\n\t/* +0x018 */ betype<FSLargeSize> quotaSize;\n\t/* +0x020 */ uint32be entryId;\n\t/* +0x024 */ betype<FSTime> createdTime;\n\t/* +0x02C */ betype<FSTime> modifiedTime;\n\t/* +0x034 */ uint8 attributes[0x30];\n};\n\nstatic_assert(sizeof(FSStat_t) == 0x64);\n\nstruct FSDirEntry_t\n{\n\t/* +0x00 */ FSStat_t stat;\n\t/* +0x64 */ char name[FSA_FILENAME_SIZE_MAX];\n};\n\nstatic_assert(sizeof(FSDirEntry_t) == 0xE4);\n\nstruct FSADeviceInfo_t\n{\n\tuint8 ukn0[0x8];\n\tuint64be deviceSizeInSectors;\n\tuint32be deviceSectorSize;\n\tuint8 ukn014[0x14];\n};\nstatic_assert(sizeof(FSADeviceInfo_t) == 0x28);\n\n#pragma pack()\n\n// query types for QueryInfo\n#define FSA_QUERY_TYPE_FREESPACE 0\n#define FSA_QUERY_TYPE_DEVICE_INFO 4\n#define FSA_QUERY_TYPE_STAT 5\n"
  },
  {
    "path": "src/Cafe/IOSU/fsa/iosu_fsa.cpp",
    "content": "#include \"fsa_types.h\"\n#include \"iosu_fsa.h\"\n#include \"Cafe/IOSU/kernel/iosu_kernel.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n#include \"util/helpers/helpers.h\"\n\n#include \"Cafe/OS/libs/coreinit/coreinit_FS.h\"\t // get rid of this dependency, requires reworking some of the IPC stuff. See locations where we use coreinit::FSCmdBlockBody_t\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\" // also remove this dependency\n\n#include \"Cafe/HW/MMU/MMU.h\"\n\nusing namespace iosu::kernel;\n\nnamespace iosu\n{\n\tnamespace fsa\n\t{\n\t\tIOSMsgQueueId sFSAIoMsgQueue;\n\t\tSysAllocator<iosu::kernel::IOSMessage, 352> _m_sFSAIoMsgQueueMsgBuffer;\n\t\tstd::thread sFSAIoThread;\n\n\t\tstruct FSAClient // IOSU's counterpart to the coreinit FSClient struct\n\t\t{\n\t\t\tstd::string workingDirectory;\n\t\t\tbool isAllocated{false};\n\n\t\t\tvoid AllocateAndInitialize()\n\t\t\t{\n\t\t\t\tisAllocated = true;\n\t\t\t\tworkingDirectory = std::string(\"/\");\n\t\t\t}\n\n\t\t\tvoid ReleaseAndCleanup()\n\t\t\t{\n\t\t\t\tisAllocated = false;\n\t\t\t}\n\t\t};\n\n\t\tstd::array<FSAClient, 624> sFSAClientArray;\n\n\t\tIOS_ERROR FSAAllocateClient(sint32& indexOut)\n\t\t{\n\t\t\tfor (size_t i = 0; i < sFSAClientArray.size(); i++)\n\t\t\t{\n\t\t\t\tif (sFSAClientArray[i].isAllocated)\n\t\t\t\t\tcontinue;\n\t\t\t\tsFSAClientArray[i].AllocateAndInitialize();\n\t\t\t\tindexOut = (sint32)i;\n\t\t\t\treturn IOS_ERROR_OK;\n\t\t\t}\n\t\t\treturn (IOS_ERROR)0xFFFCFFEE;\n\t\t}\n\n\t\tFSA_RESULT FSA_convertFSCtoFSAStatus(sint32 fscError)\n\t\t{\n\t\t\tif (fscError == FSC_STATUS_OK)\n\t\t\t\treturn FSA_RESULT::OK;\n\t\t\telse if (fscError == FSC_STATUS_FILE_NOT_FOUND)\n\t\t\t\treturn FSA_RESULT::NOT_FOUND;\n\t\t\telse if (fscError == FSC_STATUS_ALREADY_EXISTS)\n\t\t\t\treturn FSA_RESULT::ALREADY_EXISTS;\n\t\t\tcemu_assert_unimplemented();\n\t\t\treturn FSA_RESULT::FATAL_ERROR;\n\t\t}\n\n\t\tstd::string __FSATranslatePath(FSAClient* fsaClient, std::string_view input, bool endWithSlash = false)\n\t\t{\n\t\t\tstd::string tmp;\n\t\t\tif (input.empty())\n\t\t\t{\n\t\t\t\ttmp.assign(fsaClient->workingDirectory);\n\t\t\t\tif (endWithSlash)\n\t\t\t\t\ttmp.push_back('/');\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\tchar c = input.front();\n\t\t\tcemu_assert_debug(c != '\\\\'); // how to handle backward slashes?\n\n\t\t\tif (c == '/')\n\t\t\t{\n\t\t\t\t// absolute path\n\t\t\t\ttmp.assign(\"/\"); // keep the leading slash\n\t\t\t}\n\t\t\telse if (c == '~')\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tinput.remove_prefix(1);\n\t\t\t\ttmp.assign(\"/\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// in all other cases the path is relative to the working directory\n\t\t\t\ttmp.assign(fsaClient->workingDirectory);\n\t\t\t}\n\t\t\t// parse path\n\t\t\tsize_t idx = 0;\n\t\t\twhile (idx < input.size())\n\t\t\t{\n\t\t\t\tc = input[idx];\n\t\t\t\tif (c == '/')\n\t\t\t\t{\n\t\t\t\t\tidx++;\n\t\t\t\t\tcontinue; // filter leading and repeated slashes\n\t\t\t\t}\n\n\t\t\t\tif (c == '.')\n\t\t\t\t{\n\t\t\t\t\tif ((input.size() - idx) >= 3 && input[idx + 1] == '.' && input[idx + 2] == '/')\n\t\t\t\t\t{\n\t\t\t\t\t\t// \"../\"\n                        while(!tmp.empty())\n                        {\n                            if(tmp.back() == '/')\n                            {\n                                tmp.pop_back();\n                                break;\n                            }\n                            tmp.pop_back();\n                        }\n\t\t\t\t\t\tidx += 3;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse if ((input.size() - idx) == 2 && input[idx + 1] == '.')\n\t\t\t\t\t{\n\t\t\t\t\t\t// \"..\" at the end\n                        while(!tmp.empty())\n                        {\n                            if(tmp.back() == '/')\n                            {\n                                tmp.pop_back();\n                                break;\n                            }\n                            tmp.pop_back();\n                        }\n\t\t\t\t\t\tidx += 2;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse if ((input.size() - idx) >= 2 && input[idx + 1] == '/')\n\t\t\t\t\t{\n\t\t\t\t\t\t// \"./\"\n\t\t\t\t\t\tidx += 2;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!tmp.empty() && tmp.back() != '/')\n\t\t\t\t\ttmp.push_back('/');\n\n\t\t\t\twhile (idx < input.size())\n\t\t\t\t{\n\t\t\t\t\tc = input[idx];\n\t\t\t\t\tif (c == '/')\n\t\t\t\t\t\tbreak;\n\t\t\t\t\ttmp.push_back(c);\n\t\t\t\t\tidx++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (endWithSlash)\n\t\t\t{\n\t\t\t\tif (tmp.empty() || tmp.back() != '/')\n\t\t\t\t\ttmp.push_back('/');\n\t\t\t}\n\t\t\treturn tmp;\n\t\t}\n\n\t\tFSCVirtualFile* __FSAOpenNode(FSAClient* client, std::string_view path, FSC_ACCESS_FLAG accessFlags, sint32& fscStatus)\n\t\t{\n\t\t\tstd::string translatedPath = __FSATranslatePath(client, path);\n\t\t\treturn fsc_open(translatedPath.c_str(), accessFlags, &fscStatus);\n\t\t}\n\n\t\tclass _FSAHandleTable {\n\t\t\tstruct _FSAHandleResource\n\t\t\t{\n\t\t\t\tbool isAllocated{false};\n\t\t\t\tFSCVirtualFile* fscFile;\n\t\t\t\tuint16 handleCheckValue;\n\t\t\t};\n\n\t\tpublic:\n\t\t\tFSA_RESULT AllocateHandle(FSResHandle& handleOut, FSCVirtualFile* fscFile)\n\t\t\t{\n\t\t\t\tfor (size_t i = 0; i < m_handleTable.size(); i++)\n\t\t\t\t{\n\t\t\t\t\tauto& it = m_handleTable.at(i);\n\t\t\t\t\tif (it.isAllocated)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tuint16 checkValue = (uint16)m_currentCounter;\n\t\t\t\t\tm_currentCounter++;\n\t\t\t\t\tit.handleCheckValue = checkValue;\n\t\t\t\t\tit.fscFile = fscFile;\n\t\t\t\t\tit.isAllocated = true;\n\t\t\t\t\tuint32 handleVal = ((uint32)i << 16) | (uint32)checkValue;\n\t\t\t\t\thandleOut = (FSResHandle)handleVal;\n\t\t\t\t\treturn FSA_RESULT::OK;\n\t\t\t\t}\n\t\t\t\tcemuLog_log(LogType::Force, \"FSA: Ran out of file handles\");\n\t\t\t\treturn FSA_RESULT::FATAL_ERROR;\n\t\t\t}\n\n\t\t\tFSA_RESULT ReleaseHandle(FSResHandle handle)\n\t\t\t{\n\t\t\t\tuint16 index = (uint16)((uint32)handle >> 16);\n\t\t\t\tuint16 checkValue = (uint16)(handle & 0xFFFF);\n\t\t\t\tif (index >= m_handleTable.size())\n\t\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n\t\t\t\tauto& it = m_handleTable.at(index);\n\t\t\t\tif (!it.isAllocated)\n\t\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n\t\t\t\tif (it.handleCheckValue != checkValue)\n\t\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n\t\t\t\tit.fscFile = nullptr;\n\t\t\t\tit.isAllocated = false;\n\t\t\t\treturn FSA_RESULT::OK;\n\t\t\t}\n\n\t\t\tFSCVirtualFile* GetByHandle(FSResHandle handle)\n\t\t\t{\n\t\t\t\tuint16 index = (uint16)((uint32)handle >> 16);\n\t\t\t\tuint16 checkValue = (uint16)(handle & 0xFFFF);\n\t\t\t\tif (index >= m_handleTable.size())\n\t\t\t\t\treturn nullptr;\n\t\t\t\tauto& it = m_handleTable.at(index);\n\t\t\t\tif (!it.isAllocated)\n\t\t\t\t\treturn nullptr;\n\t\t\t\tif (it.handleCheckValue != checkValue)\n\t\t\t\t\treturn nullptr;\n\t\t\t\treturn it.fscFile;\n\t\t\t}\n\n\t\tprivate:\n\t\t\tuint32 m_currentCounter = 1;\n\t\t\tstd::array<_FSAHandleResource, 0x3C0> m_handleTable;\n\t\t};\n\n\t\t_FSAHandleTable sFileHandleTable;\n\t\t_FSAHandleTable sDirHandleTable;\n\n\t\tFSA_RESULT __FSAOpenFile(FSAClient* client, const char* path, const char* accessModifierStr, sint32* fileHandle)\n\t\t{\n\t\t\t*fileHandle = FS_INVALID_HANDLE_VALUE;\n\t\t\tFSC_ACCESS_FLAG accessModifier = FSC_ACCESS_FLAG::NONE;\n\t\t\tbool truncateFile = false; // todo: Support for this\n\t\t\tbool isAppend = false;\t   // todo: proper support for this (all write operations should move cursor to the end of the file?)\n\t\t\tif (strcmp(accessModifierStr, \"r\") == 0 || strcmp(accessModifierStr, \"rb\") == 0)\n\t\t\t\taccessModifier = FSC_ACCESS_FLAG::READ_PERMISSION;\n\t\t\telse if (strcmp(accessModifierStr, \"r+\") == 0)\n\t\t\t{\n\t\t\t\t// the cursor will be set to the beginning of the file\n\t\t\t\t// allows read and write access\n\t\t\t\taccessModifier = FSC_ACCESS_FLAG::READ_PERMISSION | FSC_ACCESS_FLAG::WRITE_PERMISSION; // read, write\n\t\t\t}\n\t\t\telse if (strcmp(accessModifierStr, \"w\") == 0)\n\t\t\t{\n\t\t\t\taccessModifier = FSC_ACCESS_FLAG::READ_PERMISSION | FSC_ACCESS_FLAG::WRITE_PERMISSION | FSC_ACCESS_FLAG::FILE_ALWAYS_CREATE; // create new file & write\n\t\t\t\ttruncateFile = true;\n\t\t\t}\n\t\t\telse if (strcmp(accessModifierStr, \"w+\") == 0)\n\t\t\t{\n\t\t\t\taccessModifier = FSC_ACCESS_FLAG::READ_PERMISSION | FSC_ACCESS_FLAG::WRITE_PERMISSION | FSC_ACCESS_FLAG::FILE_ALWAYS_CREATE; // create new file & read & write\n\t\t\t\ttruncateFile = true;\n\t\t\t}\n\t\t\telse if (strcmp(accessModifierStr, \"wb\") == 0) // used in Super Meat Boy\n\t\t\t{\n\t\t\t\t// b flag is allowed has no effect\n\t\t\t\taccessModifier = FSC_ACCESS_FLAG::READ_PERMISSION | FSC_ACCESS_FLAG::WRITE_PERMISSION | FSC_ACCESS_FLAG::FILE_ALWAYS_CREATE; // create new file & write\n\t\t\t\ttruncateFile = true;\n\t\t\t}\n\t\t\telse if (strcmp(accessModifierStr, \"a+\") == 0)\n\t\t\t{\n\t\t\t\taccessModifier = FSC_ACCESS_FLAG::READ_PERMISSION | FSC_ACCESS_FLAG::WRITE_PERMISSION | FSC_ACCESS_FLAG::FILE_ALLOW_CREATE | FSC_ACCESS_FLAG::IS_APPEND;\n\t\t\t\tisAppend = true;\n\t\t\t}\n\t\t\telse if (strcmp(accessModifierStr, \"a\") == 0)\n\t\t\t{\n\t\t\t\taccessModifier = FSC_ACCESS_FLAG::WRITE_PERMISSION | FSC_ACCESS_FLAG::FILE_ALLOW_CREATE | FSC_ACCESS_FLAG::IS_APPEND;\n\t\t\t\tisAppend = true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tcemu_assert_debug(false);\n\n\t\t\taccessModifier |= FSC_ACCESS_FLAG::OPEN_DIR | FSC_ACCESS_FLAG::OPEN_FILE;\n\t\t\tsint32 fscStatus;\n\t\t\tFSCVirtualFile* fscFile = __FSAOpenNode(client, path, accessModifier, fscStatus);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::NOT_FOUND;\n\t\t\tif (fscFile->fscGetType() != FSC_TYPE_FILE)\n\t\t\t{\n\t\t\t\tdelete fscFile;\n\t\t\t\treturn FSA_RESULT::NOT_FILE;\n\t\t\t}\n\t\t\tif (isAppend)\n\t\t\t\tfsc_setFileSeek(fscFile, fsc_getFileSize(fscFile));\n\t\t\tFSResHandle fsFileHandle;\n\t\t\tFSA_RESULT r = sFileHandleTable.AllocateHandle(fsFileHandle, fscFile);\n\t\t\tif (r != FSA_RESULT::OK)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Exceeded maximum number of FSA file handles\");\n\t\t\t\tdelete fscFile;\n\t\t\t\treturn FSA_RESULT::MAX_FILES;\n\t\t\t}\n\t\t\t*fileHandle = fsFileHandle;\n\t\t\tcemuLog_log(LogType::CoreinitFile, \"Open file {} (access: {} result: ok handle: 0x{})\", path, accessModifierStr, (uint32)*fileHandle);\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT __FSAOpenDirectory(FSAClient* client, std::string_view path, sint32* dirHandle)\n\t\t{\n\t\t\t*dirHandle = FS_INVALID_HANDLE_VALUE;\n\t\t\tsint32 fscStatus;\n\t\t\tFSCVirtualFile* fscFile = __FSAOpenNode(client, path, FSC_ACCESS_FLAG::OPEN_DIR | FSC_ACCESS_FLAG::OPEN_FILE, fscStatus);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::NOT_FOUND;\n\t\t\tif (fscFile->fscGetType() != FSC_TYPE_DIRECTORY)\n\t\t\t{\n\t\t\t\tdelete fscFile;\n\t\t\t\treturn FSA_RESULT::NOT_DIR;\n\t\t\t}\n\t\t\tFSResHandle fsDirHandle;\n\t\t\tFSA_RESULT r = sDirHandleTable.AllocateHandle(fsDirHandle, fscFile);\n\t\t\tif (r != FSA_RESULT::OK)\n\t\t\t{\n\t\t\t\tdelete fscFile;\n\t\t\t\treturn FSA_RESULT::MAX_DIRS;\n\t\t\t}\n\t\t\t*dirHandle = fsDirHandle;\n\t\t\tcemuLog_log(LogType::CoreinitFile, \"Open directory {} (result: ok handle: 0x{})\", path, (uint32)*dirHandle);\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT __FSACloseFile(uint32 fileHandle)\n\t\t{\n\t\t\tuint8 handleType = 0;\n\t\t\tFSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle);\n\t\t\tif (!fscFile)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"__FSACloseFile(): Invalid handle (0x{:08x})\", fileHandle);\n\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n\t\t\t}\n\t\t\t// unregister file\n\t\t\tsFileHandleTable.ReleaseHandle(fileHandle); // todo - use the error code of this\n\t\t\tfsc_close(fscFile);\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_remove(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tstd::string path = __FSATranslatePath(client, (char*)shimBuffer->request.cmdRemove.path);\n\t\t\tsint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\tfsc_remove(path.c_str(), &fscStatus);\n\t\t\treturn FSA_convertFSCtoFSAStatus(fscStatus);\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_makeDir(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tstd::string path = __FSATranslatePath(client, (char*)shimBuffer->request.cmdMakeDir.path);\n\t\t\tsint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\tfsc_createDir(path.c_str(), &fscStatus);\n\t\t\treturn FSA_convertFSCtoFSAStatus(fscStatus);\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_rename(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tstd::string srcPath = __FSATranslatePath(client, (char*)shimBuffer->request.cmdRename.srcPath);\n\t\t\tstd::string dstPath = __FSATranslatePath(client, (char*)shimBuffer->request.cmdRename.dstPath);\n\t\t\tsint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\tfsc_rename(srcPath.c_str(), dstPath.c_str(), &fscStatus);\n\t\t\treturn FSA_convertFSCtoFSAStatus(fscStatus);\n\t\t}\n\n\t\tbool __FSA_GetStatFromFSCFile(FSCVirtualFile* fscFile, FSStat_t* fsStatOut)\n\t\t{\n\t\t\tmemset(fsStatOut, 0x00, sizeof(FSStat_t));\n\t\t\tFSFlag statFlag = FSFlag::NONE;\n\t\t\tif (fsc_isDirectory(fscFile))\n\t\t\t{\n\t\t\t\t// note: Only quota (save) directories have the size field set. For other directories it's zero.\n\t\t\t\t// Hyrule Warriors relies on the size field being zero for /vol/content/data/. Otherwise it will try to read it like a file and get stuck in an endless loop.\n\t\t\t\t// Art Academy reads the size for save directories\n\t\t\t\tstatFlag |= FSFlag::IS_DIR;\n\t\t\t\tfsStatOut->size = 0;\n\t\t\t}\n\t\t\telse if (fsc_isFile(fscFile))\n\t\t\t{\n\t\t\t\tfsStatOut->size = fsc_getFileSize(fscFile);\n                statFlag |= FSFlag::IS_FILE;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t}\n\t\t\tfsStatOut->permissions = 0x777; // format matches unix (fstat) permissions?\n\t\t\tfsStatOut->flag = statFlag;\n\t\t\treturn true;\n\t\t}\n\n\t\tFSA_RESULT __FSA_GetFileStat(FSAClient* client, const char* path, FSStat_t* fsStatOut)\n\t\t{\n\t\t\tsint32 fscStatus;\n\t\t\tFSCVirtualFile* fscFile = __FSAOpenNode(client, path, FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::OPEN_DIR, fscStatus);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_convertFSCtoFSAStatus(fscStatus);\n\t\t\t__FSA_GetStatFromFSCFile(fscFile, fsStatOut);\n\t\t\tdelete fscFile;\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_queryInfo(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tchar* path = (char*)shimBuffer->request.cmdQueryInfo.query;\n\t\t\tuint32 queryType = shimBuffer->request.cmdQueryInfo.queryType;\n\t\t\t// handle query\n\t\t\tsint32 fscStatus = FSC_STATUS_OK;\n\t\t\tif (queryType == FSA_QUERY_TYPE_STAT)\n\t\t\t{\n\t\t\t\tFSStat_t* fsStat = &shimBuffer->response.cmdQueryInfo.queryStat.stat;\n\t\t\t\tFSA_RESULT fsaStatus = __FSA_GetFileStat(client, path, fsStat);\n\t\t\t\treturn fsaStatus;\n\t\t\t}\n\t\t\telse if (queryType == FSA_QUERY_TYPE_FREESPACE)\n\t\t\t{\n\t\t\t\tsint32 fscStatus;\n\t\t\t\tFSCVirtualFile* fscFile = __FSAOpenNode(client, path, FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::OPEN_DIR, fscStatus);\n\t\t\t\tif (!fscFile)\n\t\t\t\t\treturn FSA_convertFSCtoFSAStatus(fscStatus);\n\t\t\t\tbetype<uint64>* fsStatSize = &shimBuffer->response.cmdQueryInfo.queryFreeSpace.freespace;\n\t\t\t\t*fsStatSize = 30ull * 1024 * 1024 * 1024; // placeholder value. How is this determined?\n\t\t\t\tdelete fscFile;\n\t\t\t\treturn FSA_RESULT::OK;\n\t\t\t}\n\t\t\telse if (queryType == FSA_QUERY_TYPE_DEVICE_INFO)\n\t\t\t{\n\t\t\t\tFSADeviceInfo_t* deviceInfo = &shimBuffer->response.cmdQueryInfo.queryDeviceInfo.info;\n\t\t\t\t// always report hardcoded values for now.\n\t\t\t\tdeviceInfo->deviceSectorSize = 512;\n\t\t\t\tdeviceInfo->deviceSizeInSectors = (32ull * 1024 * 1024 * 1024) / deviceInfo->deviceSectorSize;\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t\treturn FSA_RESULT::OK;\n\t\t\t}\n\t\t\telse\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\treturn FSA_convertFSCtoFSAStatus(fscStatus);\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_getStatFile(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tFSFileHandle2 fileHandle = shimBuffer->request.cmdGetStatFile.fileHandle;\n\t\t\tFSStat_t* statOut = &shimBuffer->response.cmdStatFile.statOut;\n\t\t\tFSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::NOT_FOUND;\n\t\t\tcemu_assert_debug(fsc_isFile(fscFile));\n\t\t\t__FSA_GetStatFromFSCFile(fscFile, statOut);\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_read(FSAClient* client, FSAShimBuffer* shimBuffer, MEMPTR<void> destPtr, uint32be transferSize)\n\t\t{\n\t\t\tuint32 transferElementSize = shimBuffer->request.cmdReadFile.size;\n\t\t\tuint32 filePos = shimBuffer->request.cmdReadFile.filePos;\n\t\t\tuint32 fileHandle = shimBuffer->request.cmdReadFile.fileHandle;\n\t\t\tuint32 flags = shimBuffer->request.cmdReadFile.flag;\n\n\t\t\tFSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n\n\t\t\tuint32 bytesToRead = transferSize;\n\t\t\t// update file position if flag is set\n\t\t\tif ((flags & FSA_CMD_FLAG_SET_POS) != 0)\n\t\t\t\tfsc_setFileSeek(fscFile, filePos);\n\t\t\t// todo: File permissions\n\t\t\tuint32 bytesSuccessfullyRead = fsc_readFile(fscFile, destPtr, bytesToRead);\n\t\t\tif (transferElementSize == 0)\n\t\t\t\treturn FSA_RESULT::OK;\n\n\t\t\tLatteBufferCache_notifyDCFlush(destPtr.GetMPTR(), bytesToRead);\n\n\t\t\treturn (FSA_RESULT)(bytesSuccessfullyRead / transferElementSize); // return number of elements read\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_write(FSAClient* client, FSAShimBuffer* shimBuffer, MEMPTR<void> destPtr, uint32be transferSize)\n\t\t{\n\t\t\tuint32 transferElementSize = shimBuffer->request.cmdWriteFile.size;\n\t\t\tuint32 filePos = shimBuffer->request.cmdWriteFile.filePos;\n\t\t\tuint32 fileHandle = shimBuffer->request.cmdWriteFile.fileHandle;\n\t\t\tuint32 flags = shimBuffer->request.cmdWriteFile.flag;\n\n\t\t\tFSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n\t\t\tcemu_assert_debug((transferSize % transferElementSize) == 0);\n\t\t\tuint32 bytesToWrite = transferSize;\n\t\t\t// check for write permission (should this happen before or after setting file position?)\n\t\t\tif (!fsc_isWritable(fscFile))\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\treturn FSA_RESULT::PERMISSION_ERROR;\n\t\t\t}\n\t\t\t// update file position if flag is set\n\t\t\tif ((flags & FSA_CMD_FLAG_SET_POS) != 0)\n\t\t\t\tfsc_setFileSeek(fscFile, filePos);\n\t\t\tuint32 bytesSuccessfullyWritten = fsc_writeFile(fscFile, destPtr, bytesToWrite);\n\t\t\tdebug_printf(\"FSAProcessCmd_write(): Writing 0x%08x bytes (bytes actually written: 0x%08x)\\n\", bytesToWrite, bytesSuccessfullyWritten);\n\t\t\treturn (FSA_RESULT)(bytesSuccessfullyWritten / transferElementSize); // return number of elements read\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_setPos(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tuint32 fileHandle = shimBuffer->request.cmdSetPosFile.fileHandle;\n\t\t\tuint32 filePos = shimBuffer->request.cmdSetPosFile.filePos;\n\t\t\tFSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n\t\t\tfsc_setFileSeek(fscFile, filePos);\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_getPos(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tuint32 fileHandle = shimBuffer->request.cmdGetPosFile.fileHandle;\n\t\t\tFSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n\t\t\tuint32 filePos = fsc_getFileSeek(fscFile);\n\t\t\tshimBuffer->response.cmdGetPosFile.filePos = filePos;\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_openFile(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tsint32 fileHandle = 0;\n\t\t\tFSA_RESULT fsaResult = __FSAOpenFile(client, (char*)shimBuffer->request.cmdOpenFile.path, (char*)shimBuffer->request.cmdOpenFile.mode, &fileHandle);\n\t\t\tshimBuffer->response.cmdOpenFile.fileHandleOutput = fileHandle;\n\t\t\treturn fsaResult;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_closeFile(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\treturn __FSACloseFile(shimBuffer->request.cmdCloseFile.fileHandle);\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_openDir(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tsint32 dirHandle = 0;\n\t\t\tFSA_RESULT fsaResult = __FSAOpenDirectory(client, (const char*)shimBuffer->request.cmdOpenFile.path, &dirHandle);\n\t\t\tshimBuffer->response.cmdOpenDir.dirHandleOutput = dirHandle;\n\t\t\treturn fsaResult;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_readDir(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tFSCVirtualFile* fscFile = sDirHandleTable.GetByHandle((sint32)shimBuffer->request.cmdReadDir.dirHandle);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::INVALID_DIR_HANDLE;\n\t\t\tFSDirEntry_t* dirEntryOut = &shimBuffer->response.cmdReadDir.dirEntry;\n\t\t\tFSCDirEntry fscDirEntry;\n\t\t\tif (fsc_nextDir(fscFile, &fscDirEntry) == false)\n\t\t\t\treturn FSA_RESULT::END_OF_DIRECTORY;\n\t\t\tstrcpy(dirEntryOut->name, fscDirEntry.path);\n\t\t\tFSFlag statFlag = FSFlag::NONE;\n\t\t\tdirEntryOut->stat.size = 0;\n\t\t\tif (fscDirEntry.isDirectory)\n\t\t\t{\n\t\t\t\tstatFlag |= FSFlag::IS_DIR;\n\t\t\t}\n\t\t\telse if (fscDirEntry.isFile)\n\t\t\t{\n\t\t\t\tstatFlag |= FSFlag::IS_FILE;\n\t\t\t\tdirEntryOut->stat.size = fscDirEntry.fileSize;\n\t\t\t}\n\t\t\tdirEntryOut->stat.flag = statFlag;\n\t\t\tdirEntryOut->stat.permissions = 0x777;\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_closeDir(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tFSCVirtualFile* fscFile = sDirHandleTable.GetByHandle((sint32)shimBuffer->request.cmdReadDir.dirHandle);\n\t\t\tif (!fscFile)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"CloseDir: Invalid handle (0x{:08x})\", (sint32)shimBuffer->request.cmdReadDir.dirHandle);\n\t\t\t\treturn FSA_RESULT::INVALID_DIR_HANDLE;\n\t\t\t}\n\t\t\tsDirHandleTable.ReleaseHandle(shimBuffer->request.cmdReadDir.dirHandle);\n\t\t\tfsc_close(fscFile);\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_flushQuota(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_rewindDir(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tFSCVirtualFile* fscFile = sDirHandleTable.GetByHandle((sint32)shimBuffer->request.cmdRewindDir.dirHandle);\n\t\t\tif (!fscFile)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"RewindDir: Invalid handle (0x{:08x})\", (sint32)shimBuffer->request.cmdRewindDir.dirHandle);\n\t\t\t\treturn FSA_RESULT::INVALID_DIR_HANDLE;\n\t\t\t}\n\t\t\tif (!fscFile->fscRewindDir())\n\t\t\t\treturn FSA_RESULT::FATAL_ERROR;\n\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_flushFile(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_appendFile(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tFSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(shimBuffer->request.cmdAppendFile.fileHandle);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tcemuLog_log(LogType::Force, \"FSAProcessCmd_appendFile(): size 0x{:08x} count 0x{:08x} (todo)\\n\", shimBuffer->request.cmdAppendFile.size, shimBuffer->request.cmdAppendFile.count);\n#endif\n\t\t\treturn (FSA_RESULT)(shimBuffer->request.cmdAppendFile.count.value());\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_truncateFile(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tFSFileHandle2 fileHandle = shimBuffer->request.cmdTruncateFile.fileHandle;\n\t\t\tFSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n\t\t\tfsc_setFileLength(fscFile, fsc_getFileSeek(fscFile));\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_isEof(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tuint32 fileHandle = shimBuffer->request.cmdIsEof.fileHandle;\n\t\t\tFSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle);\n\t\t\tif (!fscFile)\n\t\t\t\treturn FSA_RESULT::INVALID_FILE_HANDLE;\n\t\t\tuint32 filePos = fsc_getFileSeek(fscFile);\n\t\t\tuint32 fileSize = fsc_getFileSize(fscFile);\n\t\t\tif (filePos >= fileSize)\n\t\t\t\treturn FSA_RESULT::END_OF_FILE;\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_getCwd(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tchar* pathOutput = shimBuffer->response.cmdGetCWD.path;\n\t\t\tsint32 pathOutputMaxLen = sizeof(shimBuffer->response.cmdGetCWD.path);\n\t\t\tcemu_assert(pathOutputMaxLen > 0);\n\t\t\tsint32 fscStatus = FSC_STATUS_OK;\n\t\t\tstrncpy(pathOutput, client->workingDirectory.data(), std::min(client->workingDirectory.size() + 1, (size_t)pathOutputMaxLen));\n\t\t\tpathOutput[pathOutputMaxLen - 1] = '\\0';\n\t\t\treturn FSA_convertFSCtoFSAStatus(fscStatus);\n\t\t}\n\n\t\tFSA_RESULT FSAProcessCmd_changeDir(FSAClient* client, FSAShimBuffer* shimBuffer)\n\t\t{\n\t\t\tconst char* path = (const char*)shimBuffer->request.cmdChangeDir.path;\n\t\t\tshimBuffer->request.cmdChangeDir.path[sizeof(shimBuffer->request.cmdChangeDir.path) - 1] = '\\0';\n\t\t\tsint32 fscStatus = FSC_STATUS_OK;\n\t\t\tclient->workingDirectory.assign(__FSATranslatePath(client, path, true));\n\t\t\treturn FSA_convertFSCtoFSAStatus(fscStatus);\n\t\t}\n\n\t\tvoid FSAHandleCommandIoctlv(FSAClient* client, IPCCommandBody* cmd, FSA_CMD_OPERATION_TYPE operationId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec)\n\t\t{\n\t\t\tFSA_RESULT fsaResult = FSA_RESULT::FATAL_ERROR;\n\n\t\t\tswitch (operationId)\n\t\t\t{\n\t\t\tcase FSA_CMD_OPERATION_TYPE::READ:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_read(client, (FSAShimBuffer*)vec[0].basePhys.GetPtr(), vec[1].basePhys, vec[1].size);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::WRITE:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_write(client, (FSAShimBuffer*)vec[0].basePhys.GetPtr(), vec[1].basePhys, vec[1].size);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::CHANGEDIR:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::GETCWD:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::MAKEDIR:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::RENAME:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::OPENDIR:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::READDIR:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::CLOSEDIR:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::OPENFILE:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::REMOVE:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::GETPOS:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::SETPOS:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::ISEOF:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::GETSTATFILE:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::CLOSEFILE:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::QUERYINFO:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::APPENDFILE:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::TRUNCATEFILE:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::FLUSHQUOTA:\n\t\t\t{\n\t\t\t\t// These are IOCTL and no IOCTLV\n\t\t\t\tcemu_assert_error();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t}\n\n\t\t\tIOS_ResourceReply(cmd, (IOS_ERROR)fsaResult);\n\t\t}\n\n\t\tvoid FSAHandleCommandIoctl(FSAClient* client, IPCCommandBody* cmd, FSA_CMD_OPERATION_TYPE operationId, void* ptrIn, void* ptrOut)\n\t\t{\n\t\t\tFSAShimBuffer* shimBuffer = (FSAShimBuffer*)ptrIn;\n\t\t\tFSA_RESULT fsaResult = FSA_RESULT::FATAL_ERROR;\n\n\t\t\tswitch (operationId)\n\t\t\t{\n\t\t\tcase FSA_CMD_OPERATION_TYPE::REMOVE:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_remove(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::CHANGEDIR:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_changeDir(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::GETCWD:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_getCwd(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::MAKEDIR:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_makeDir(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::RENAME:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_rename(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::OPENDIR:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_openDir(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::READDIR:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_readDir(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::CLOSEDIR:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_closeDir(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::OPENFILE:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_openFile(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::GETPOS:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_getPos(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::SETPOS:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_setPos(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::ISEOF:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_isEof(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::GETSTATFILE:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_getStatFile(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::CLOSEFILE:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_closeFile(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::QUERYINFO:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_queryInfo(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::APPENDFILE:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_appendFile(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::TRUNCATEFILE:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_truncateFile(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::FLUSHQUOTA:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_flushQuota(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::REWINDDIR:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_rewindDir(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::FLUSHFILE:\n\t\t\t{\n\t\t\t\tfsaResult = FSAProcessCmd_flushFile(client, shimBuffer);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase FSA_CMD_OPERATION_TYPE::READ:\n\t\t\tcase FSA_CMD_OPERATION_TYPE::WRITE:\n\t\t\t{\n\t\t\t\t// These commands are IOCTLVs not IOCTL\n\t\t\t\tcemu_assert_error();\n\t\t\t}\n\t\t\t}\n\t\t\tIOS_ResourceReply(cmd, (IOS_ERROR)fsaResult);\n\t\t}\n\n\t\tvoid FSAIoThread()\n\t\t{\n\t\t\tSetThreadName(\"IOSU-FSA\");\n\t\t\tIOSMessage msg;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tIOS_ERROR r = IOS_ReceiveMessage(sFSAIoMsgQueue, &msg, 0);\n\t\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t\t\tif (msg == 0)\n\t\t\t\t\treturn; // shutdown signaled\n\t\t\t\tIPCCommandBody* cmd = MEMPTR<IPCCommandBody>(msg).GetPtr();\n\t\t\t\tuint32 clientHandle = (uint32)cmd->devHandle;\n\t\t\t\tif (cmd->cmdId == IPCCommandId::IOS_OPEN)\n\t\t\t\t{\n\t\t\t\t\tsint32 clientIndex = 0;\n\t\t\t\t\tr = FSAAllocateClient(clientIndex);\n\t\t\t\t\tif (r != IOS_ERROR_OK)\n\t\t\t\t\t{\n\t\t\t\t\t\tIOS_ResourceReply(cmd, r);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tIOS_ResourceReply(cmd, (IOS_ERROR)clientIndex);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_CLOSE)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert(clientHandle < sFSAClientArray.size());\n\t\t\t\t\tsFSAClientArray[clientHandle].ReleaseAndCleanup();\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_OK);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_IOCTL)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert(clientHandle < sFSAClientArray.size());\n\t\t\t\t\tcemu_assert(sFSAClientArray[clientHandle].isAllocated);\n\t\t\t\t\tFSAHandleCommandIoctl(sFSAClientArray.data() + clientHandle, cmd, (FSA_CMD_OPERATION_TYPE)cmd->args[0].value(), MEMPTR<void>(cmd->args[1]), MEMPTR<void>(cmd->args[3]));\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_IOCTLV)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert(clientHandle < sFSAClientArray.size());\n\t\t\t\t\tcemu_assert(sFSAClientArray[clientHandle].isAllocated);\n\t\t\t\t\tFSA_CMD_OPERATION_TYPE requestId = (FSA_CMD_OPERATION_TYPE)cmd->args[0].value();\n\t\t\t\t\tuint32 numIn = cmd->args[1];\n\t\t\t\t\tuint32 numOut = cmd->args[2];\n\t\t\t\t\tIPCIoctlVector* vec = MEMPTR<IPCIoctlVector>{cmd->args[3]}.GetPtr();\n\t\t\t\t\tFSAHandleCommandIoctlv(sFSAClientArray.data() + clientHandle, cmd, requestId, numIn, numOut, vec);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"/dev/fsa: Unsupported IPC cmdId\");\n\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_INVALID);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid Initialize()\n\t\t{\n\t\t\tfor (auto& it : sFSAClientArray)\n\t\t\t\tit.ReleaseAndCleanup();\n\t\t\tsFSAIoMsgQueue = (IOSMsgQueueId)IOS_CreateMessageQueue(_m_sFSAIoMsgQueueMsgBuffer.GetPtr(), _m_sFSAIoMsgQueueMsgBuffer.GetCount());\n\t\t\tIOS_ERROR r = IOS_RegisterResourceManager(\"/dev/fsa\", sFSAIoMsgQueue);\n\t\t\tIOS_DeviceAssociateId(\"/dev/fsa\", 11);\n\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t\tsFSAIoThread = std::thread(FSAIoThread);\n\t\t}\n\n\t\tvoid Shutdown()\n\t\t{\n\t\t\tIOS_SendMessage(sFSAIoMsgQueue, 0, 0);\n\t\t\tsFSAIoThread.join();\n\t\t}\n\t} // namespace fsa\n} // namespace iosu\n"
  },
  {
    "path": "src/Cafe/IOSU/fsa/iosu_fsa.h",
    "content": "#pragma once\n#include <IOSU/iosu_ipc_common.h>\n#include \"fsa_types.h\"\n\nnamespace iosu\n{\n\tnamespace fsa\n\t{\n\n\t\tstruct FSARequest\n\t\t{\n\t\t\tuint32be ukn0;\n\t\t\tunion\n\t\t\t{\n\t\t\t\tuint8 ukn04[0x51C];\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tMEMPTR<void> dest;\n\t\t\t\t\tuint32be size;\n\t\t\t\t\tuint32be count;\n\t\t\t\t\tuint32be filePos;\n\t\t\t\t\tuint32be fileHandle;\n\t\t\t\t\tuint32be flag;\n\t\t\t\t} cmdReadFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tMEMPTR<void> dest;\n\t\t\t\t\tuint32be size;\n\t\t\t\t\tuint32be count;\n\t\t\t\t\tuint32be filePos;\n\t\t\t\t\tuint32be fileHandle;\n\t\t\t\t\tuint32be flag;\n\t\t\t\t} cmdWriteFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint8 path[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t\tuint8 mode[12];\t\t   // +0x284 note: code seems to access this value like it has a size of 0x10 but the actual struct element is only 12 bytes? Maybe a typo (10 instead of 0x10 in the struct def)\n\t\t\t\t\tuint32be createMode;   // +0x290\n\t\t\t\t\tuint32be openFlags;\t   // +0x294\n\t\t\t\t\tuint32be preallocSize; // +0x298\n\t\t\t\t} cmdOpenFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be fileHandle;\n\t\t\t\t} cmdCloseFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint8 path[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t} cmdRemove;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint8 path[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t\tuint8 ukn0284[12]; // +0x284\n\t\t\t\t} cmdOpenDir;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tbetype<uint32> dirHandle;\n\t\t\t\t} cmdReadDir;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tbetype<uint32> dirHandle;\n\t\t\t\t} cmdCloseDir;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint8 path[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t\tuint32be uknParam;\n\t\t\t\t} cmdMakeDir;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint8 path[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t} cmdChangeDir;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint8 query[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t\tuint32be queryType;\n\t\t\t\t} cmdQueryInfo;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint8 srcPath[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t\tuint8 dstPath[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t} cmdRename;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be size;\n\t\t\t\t\tuint32be count;\n\t\t\t\t\tuint32be fileHandle;\n\t\t\t\t\tuint32be uknParam;\n\t\t\t\t} cmdAppendFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be fileHandle;\n\t\t\t\t} cmdTruncateFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be fileHandle;\n\t\t\t\t} cmdGetStatFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint8 path[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t} cmdFlushQuota;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be fileHandle;\n\t\t\t\t\tuint32be filePos;\n\t\t\t\t} cmdSetPosFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be fileHandle;\n\t\t\t\t} cmdGetPosFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be fileHandle;\n\t\t\t\t} cmdIsEof;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be dirHandle;\n\t\t\t\t} cmdRewindDir;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be fileHandle;\n\t\t\t\t} cmdFlushFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint8 path[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t\tuint32be mode1;\n\t\t\t\t\tuint32be mode2;\n\t\t\t\t} cmdChangeMode;\n\t\t\t};\n\t\t};\n\t\tstatic_assert(sizeof(FSARequest) == 0x520);\n\n#pragma pack(1)\n\t\tstruct FSAResponse\n\t\t{\n\t\t\tuint32be ukn0;\n\t\t\tunion\n\t\t\t{\n\t\t\t\tuint8 ukn04[0x28F];\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be fileHandleOutput; // +0x584 used to return file handle on success\n\t\t\t\t} cmdOpenFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be dirHandleOutput; // +0x584 used to return dir handle on success\n\t\t\t\t} cmdOpenDir;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32be filePos;\n\t\t\t\t} cmdGetPosFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tFSStat_t statOut;\n\t\t\t\t} cmdStatFile;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tFSDirEntry_t dirEntry;\n\t\t\t\t} cmdReadDir;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tchar path[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t} cmdGetCWD;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tunion\n\t\t\t\t\t{\n\t\t\t\t\t\tuint8 ukn04[0x64];\n\t\t\t\t\t\tstruct\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuint64be freespace;\n\t\t\t\t\t\t} queryFreeSpace;\n\t\t\t\t\t\tstruct\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFSStat_t stat;\n\t\t\t\t\t\t} queryStat;\n\t\t\t\t\t\tstruct\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tFSADeviceInfo_t info;\n\t\t\t\t\t\t} queryDeviceInfo;\n\t\t\t\t\t};\n\t\t\t\t} cmdQueryInfo;\n\t\t\t};\n\t\t};\n\t\tstatic_assert(sizeof(FSAResponse) == 0x293);\n#pragma pack()\n\n\t\tstruct FSAShimBuffer\n\t\t{\n\t\t\tFSARequest request;\n\t\t\tuint8 ukn0520[0x60];\n\t\t\tFSAResponse response;\n\t\t\tuint8 ukn0813[0x6D];\n\t\t\tIPCIoctlVector ioctlvVec[3];\n\t\t\tuint8 ukn08A4[0x5C];\n\t\t\t/* +0x0900 */ uint32be operationType;\n\t\t\tbetype<IOSDevHandle> fsaDevHandle;\n\t\t\t/* +0x0908 */ uint16be ipcReqType; // 0 -> IoctlAsync, 1 -> IoctlvAsync\n\t\t\tuint8 ioctlvVecIn;\n\t\t\tuint8 ioctlvVecOut;\n\t\t\tuint32 ukn090C;\n\t\t\tuint32 ukn0910;\n\t\t\tuint32 ukn0914;\n\t\t\tuint32 ukn0918;\n\t\t\tuint32 ukn091C;\n\t\t\tuint32 ukn0920;\n\t\t\tuint32 ukn0924;\n\t\t\tuint32 ukn0928;\n\t\t\tuint32 ukn092C;\n\t\t\tuint32 ukn0930;\n\t\t\tuint32 ukn0934;\n\t\t};\n\t\tstatic_assert(sizeof(FSAShimBuffer) == 0x938); // exact size of this is not known\n\n\t\tvoid Initialize();\n\t\tvoid Shutdown();\n\t} // namespace fsa\n} // namespace iosu\n"
  },
  {
    "path": "src/Cafe/IOSU/iosu_ipc_common.h",
    "content": "#pragma once\n\nusing IOSDevHandle = uint32;\n\nenum class IPCDriverState : uint32\n{\n\tCLOSED = 1,\n\tINITIALIZED = 2,\n\tREADY = 3,\n\tSUBMITTING = 4\n};\n\nenum class IPCCommandId : uint32\n{\n\tIOS_OPEN = 1,\n\tIOS_CLOSE = 2,\n\n\tIOS_IOCTL = 6,\n\tIOS_IOCTLV = 7,\n};\n\nstruct IPCIoctlVector\n{\n\tMEMPTR<void> baseVirt;\n\tuint32be size;\n\tMEMPTR<void> basePhys;\n};\n\nstatic_assert(sizeof(IPCIoctlVector) == 0xC);\n\nstruct IPCCommandBody\n{\n\t/* +0x00 */ betype<IPCCommandId> cmdId;\n\t/* +0x04 */ uint32be result; // set by IOSU\n\t/* +0x08 */ betype<IOSDevHandle> devHandle;\n\t/* +0x0C */ uint32be ukn0C;\n\t/* +0x10 */ uint32be ukn10;\n\t/* +0x14 */ uint32be ukn14;\n\t/* +0x18 */ uint32be ukn18;\n\t/* +0x1C */ uint32be ukn1C;\n\t/* +0x20 */ uint32be ukn20;\n\t/* +0x24 */ uint32be args[5];\n\t// anything below may only be present on the PPC side?\n\t/* +0x38 */ betype<IPCCommandId> prev_cmdId;\n\t/* +0x3C */ betype<IOSDevHandle> prev_devHandle;\n\t/* +0x40 */ MEMPTR<void> ppcVirt0;\n\t/* +0x44 */ MEMPTR<void> ppcVirt1;\n\n\t/*\n\t\tIOS_Open:\n\t\targs[0] = const char* path\n\t\targs[1] = pathLen + 1\n\t\targs[2] = flags\n\n\t\tIOS_Close:\n\t\tOnly devHandle is set\n\n\t\tIOS_Ioctl:\n\t\targs[0] = requestId\n\t\targs[1] = ptrIn\n\t\targs[2] = sizeIn\n\t\targs[3] = ptrOut\n\t\targs[4] = sizeOut\n\n\t\tIOS_Ioctlv:\n\t\targs[0] = requestId\n\t\targs[1] = numIn\n\t\targs[2] = numOut\n\t\targs[3] = IPCIoctlVector*\n\n\n\t*/\n};\n"
  },
  {
    "path": "src/Cafe/IOSU/iosu_types_common.h",
    "content": "#pragma once\n\nusing IOSMsgQueueId = uint32;\nusing IOSTimerId = uint32;\n\nstatic constexpr IOSTimerId IOSInvalidTimerId = 0xFFFFFFFF;\n\n// returned for syscalls\n// maybe also shared with IPC?\nenum IOS_ERROR : sint32\n{\n\tIOS_ERROR_OK = 0,\n\tIOS_ERROR_INVALID = -4,\n\tIOS_ERROR_MAXIMUM_REACHED = -5,\n\n\tIOS_ERROR_NONE_AVAILABLE = -7, // returned by non-blocking IOS_ReceiveMessage on empty message\n\tIOS_ERROR_WOULD_BLOCK = -8,\n\n\tIOS_ERROR_INVALID_ARG = -29,\n};\n\ninline bool IOS_ResultIsError(const IOS_ERROR err)\n{\n\treturn (err & 0x80000000) != 0;\n}\n\nclass IOSUModule\n{\n  public:\n\tvirtual void SystemLaunch() {}; // CafeSystem is initialized\n\tvirtual void SystemExit() {}; // CafeSystem is shutdown\n\tvirtual void TitleStart() {}; // foreground title is launched\n\tvirtual void TitleStop() {}; // foreground title is closed\n};\n"
  },
  {
    "path": "src/Cafe/IOSU/kernel/iosu_kernel.cpp",
    "content": "#include \"iosu_kernel.h\"\n#include \"util/helpers/fspinlock.h\"\n#include \"util/helpers/helpers.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IPC.h\"\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n\nnamespace iosu\n{\n\tnamespace kernel\n\t{\n\t\tstd::mutex sInternalMutex;\n\n\t\tvoid IOS_DestroyResourceManagerForQueueId(IOSMsgQueueId msgQueueId);\n\t\tvoid _IPCDestroyAllHandlesForMsgQueue(IOSMsgQueueId msgQueueId);\n\n\t\tstatic void _assume_lock()\n\t\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tcemu_assert_debug(!sInternalMutex.try_lock());\n#endif\n\t\t}\n\n\t\t/* message queue */\n\n\t\tstruct IOSMessageQueue \n\t\t{\n\t\t\t// placeholder\n\t\t\t/* +0x00 */ uint32be ukn00;\n\t\t\t/* +0x04 */ uint32be ukn04;\n\t\t\t/* +0x08 */ uint32be numQueuedMessages;\n\t\t\t/* +0x0C */ uint32be readIndex;\n\t\t\t/* +0x10 */ uint32be msgArraySize; // 0 if queue is not allocated\n\t\t\t/* +0x14 */ MEMPTR<betype<IOSMessage>> msgArray;\n\t\t\t/* +0x18 */ IOSMsgQueueId queueHandle;\n\t\t\t/* +0x1C */ uint32be ukn1C;\n\n\t\t\tuint32 GetWriteIndex()\n\t\t\t{\n\t\t\t\tuint32 idx = readIndex + numQueuedMessages;\n\t\t\t\tif (idx >= msgArraySize)\n\t\t\t\t\tidx -= msgArraySize;\n\t\t\t\treturn idx;\n\t\t\t}\n\n\t\t\t/* HLE extension */\n\t\t\tstd::condition_variable cv_send;\n\t\t\tstd::condition_variable cv_recv;\n\t\t};\n\n\t\tstd::array<IOSMessageQueue, 750> sMsgQueuePool;\n\n\t\tIOS_ERROR _IOS_GetMessageQueue(IOSMsgQueueId queueHandle, IOSMessageQueue*& queueOut)\n\t\t{\n\t\t\t_assume_lock();\n\t\t\tuint32 index = (queueHandle & 0xFFF);\n\t\t\tif (index >= sMsgQueuePool.size())\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\tIOSMessageQueue& q = sMsgQueuePool.at(index);\n\t\t\tif(q.queueHandle != queueHandle)\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\tqueueOut = &q;\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\tIOSMsgQueueId IOS_CreateMessageQueue(IOSMessage* messageArray, uint32 messageCount)\n\t\t{\n\t\t\tstd::unique_lock _l(sInternalMutex);\n\t\t\tcemu_assert(messageCount != 0);\n\t\t\tauto it = std::find_if(sMsgQueuePool.begin(), sMsgQueuePool.end(), [](const IOSMessageQueue& q) { return q.msgArraySize == 0; });\n\t\t\tif (it == sMsgQueuePool.end())\n\t\t\t{\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t\treturn IOS_ERROR_MAXIMUM_REACHED;\n\t\t\t}\n\t\t\tsize_t index = std::distance(sMsgQueuePool.begin(), it);\n\t\t\tIOSMessageQueue& msgQueue = sMsgQueuePool.at(index);\n\t\t\t// create queue handle\n\t\t\tstatic uint32 sQueueHandleCounter = 0;\n\t\t\tuint32 queueHandle = (uint32)index | ((sQueueHandleCounter<<12)&0x7FFFFFFF);\n\t\t\tsQueueHandleCounter++;\n\n\t\t\tmsgQueue.queueHandle = queueHandle;\n\t\t\tmsgQueue.msgArraySize = messageCount;\n\t\t\tmsgQueue.msgArray = (betype<IOSMessage>*)messageArray;\n\n\t\t\tmsgQueue.numQueuedMessages = 0;\n\t\t\tmsgQueue.readIndex = 0;\n\n\t\t\treturn queueHandle;\n\t\t}\n\n\t\tIOS_ERROR IOS_DestroyMessageQueue(IOSMsgQueueId msgQueueId)\n\t\t{\n\t\t\tstd::unique_lock _l(sInternalMutex);\n\t\t\tIOSMessageQueue* msgQueue = nullptr;\n\t\t\tIOS_ERROR r = _IOS_GetMessageQueue(msgQueueId, msgQueue);\n\t\t\tif (r != IOS_ERROR_OK)\n\t\t\t\treturn r;\n\t\t\tmsgQueue->msgArraySize = 0;\n\t\t\tmsgQueue->queueHandle = 0;\n\t\t\tIOS_DestroyResourceManagerForQueueId(msgQueueId);\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\tIOS_ERROR IOS_SendMessage(IOSMsgQueueId msgQueueId, IOSMessage message, uint32 flags)\n\t\t{\n\t\t\tstd::unique_lock _l(sInternalMutex);\n\t\t\tcemu_assert_debug(flags == 0 || flags == 1);\n\t\t\tbool dontBlock = (flags & 1) != 0;\n\t\t\tIOSMessageQueue* msgQueue = nullptr;\n\t\t\tIOS_ERROR r = _IOS_GetMessageQueue(msgQueueId, msgQueue);\n\t\t\tif (r != IOS_ERROR_OK)\n\t\t\t\treturn r;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tif (msgQueue->numQueuedMessages == msgQueue->msgArraySize)\n\t\t\t\t{\n\t\t\t\t\tif (dontBlock)\n\t\t\t\t\t\treturn IOS_ERROR_WOULD_BLOCK;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\t\t\t\tmsgQueue->cv_send.wait(_l);\n\t\t\t\t// after returning from wait, make sure the queue handle is unchanged\n\t\t\t\tif (msgQueue->queueHandle != msgQueueId)\n\t\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\t}\n\t\t\tuint32 writeIndex = msgQueue->GetWriteIndex();\n\t\t\tmsgQueue->msgArray[writeIndex] = message;\n\t\t\tmsgQueue->numQueuedMessages += 1;\n\t\t\tmsgQueue->cv_recv.notify_one();\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\tIOS_ERROR IOS_ReceiveMessage(IOSMsgQueueId msgQueueId, IOSMessage* messageOut, uint32 flags)\n\t\t{\n\t\t\tstd::unique_lock _l(sInternalMutex);\n\t\t\tcemu_assert_debug(flags == 0 || flags == 1);\n\t\t\tbool dontBlock = (flags & 1) != 0;\n\t\t\tIOSMessageQueue* msgQueue = nullptr;\n\t\t\tIOS_ERROR r = _IOS_GetMessageQueue(msgQueueId, msgQueue);\n\t\t\tif (r != IOS_ERROR_OK)\n\t\t\t\treturn r;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tif (msgQueue->numQueuedMessages == 0)\n\t\t\t\t{\n\t\t\t\t\tif (dontBlock)\n\t\t\t\t\t\treturn IOS_ERROR_NONE_AVAILABLE;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\t\t\t\tmsgQueue->cv_recv.wait(_l);\n\t\t\t\t// after returning from wait, make sure the queue handle is unchanged\n\t\t\t\tif (msgQueue->queueHandle != msgQueueId)\n\t\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\t}\n\t\t\t*messageOut = msgQueue->msgArray[(uint32)msgQueue->readIndex];\n\t\t\tmsgQueue->readIndex = msgQueue->readIndex + 1;\n\t\t\tif (msgQueue->readIndex >= msgQueue->msgArraySize)\n\t\t\t\tmsgQueue->readIndex -= msgQueue->msgArraySize;\n\t\t\tmsgQueue->numQueuedMessages -= 1;\n\t\t\tmsgQueue->cv_send.notify_one();\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\t/* timer */\n\n\t\tstd::mutex sTimerMutex;\n\t\tstd::condition_variable sTimerCV;\n\t\tstd::atomic_bool sTimerThreadStop;\n\n\t\tstruct IOSTimer\n\t\t{\n\t\t\tIOSMsgQueueId queueId;\n\t\t\tuint32 message;\n\t\t\tHRTick nextFire;\n\t\t\tHRTick repeat;\n\t\t\tbool isValid;\n\t\t};\n\n\t\tstd::vector<IOSTimer> sTimers;\n\t\tstd::vector<IOSTimerId> sTimersFreeHandles;\n\n\t\tauto sTimerSortComparator = [](const IOSTimerId& idA, const IOSTimerId& idB)\n\t\t{\n\t\t\t// order by nextFire, then by timerId to avoid duplicate keys\n\t\t\tIOSTimer& timerA = sTimers[idA];\n\t\t\tIOSTimer& timerB = sTimers[idB];\n\t\t\tif (timerA.nextFire != timerB.nextFire)\n\t\t\t\treturn timerA.nextFire < timerB.nextFire;\n\t\t\treturn idA < idB;\n\t\t};\n\t\tstd::set<IOSTimerId, decltype(sTimerSortComparator)> sTimerByFireTime;\n\n\t\tIOSTimer& IOS_GetFreeTimer()\n\t\t{\n\t\t\tcemu_assert_debug(!sTimerMutex.try_lock()); // lock must be held by current thread\n\t\t\tif (sTimersFreeHandles.empty())\n\t\t\t\treturn sTimers.emplace_back();\n\t\t\tIOSTimerId timerId = sTimersFreeHandles.back();\n\t\t\tsTimersFreeHandles.pop_back();\n\t\t\treturn sTimers[timerId];\n\t\t}\n\n\t\tvoid IOS_TimerSetNextFireTime(IOSTimer& timer, HRTick nextFire)\n\t\t{\n\t\t\tcemu_assert_debug(!sTimerMutex.try_lock()); // lock must be held by current thread\n\t\t\tIOSTimerId timerId = &timer - sTimers.data();\n\t\t\tauto it = sTimerByFireTime.find(timerId);\n\t\t\tif(it != sTimerByFireTime.end())\n\t\t\t\tsTimerByFireTime.erase(it);\n\t\t\ttimer.nextFire = nextFire;\n\t\t\tif(nextFire != 0)\n\t\t\t\tsTimerByFireTime.insert(timerId);\n\t\t}\n\n\t\tvoid IOS_StopTimerInternal(IOSTimerId timerId)\n\t\t{\n\t\t\tcemu_assert_debug(!sTimerMutex.try_lock());\n\t\t\tIOS_TimerSetNextFireTime(sTimers[timerId], 0);\n\t\t}\n\n\t\tIOS_ERROR IOS_CreateTimer(uint32 startMicroseconds, uint32 repeatMicroseconds, uint32 queueId, uint32 message)\n\t\t{\n\t\t\tstd::unique_lock _l(sTimerMutex);\n\t\t\tIOSTimer& timer = IOS_GetFreeTimer();\n\t\t\ttimer.queueId = queueId;\n\t\t\ttimer.message = message;\n\t\t\tHRTick nextFire = HighResolutionTimer::now().getTick() + HighResolutionTimer::microsecondsToTicks(startMicroseconds);\n\t\t\ttimer.repeat = HighResolutionTimer::microsecondsToTicks(repeatMicroseconds);\n\t\t\tIOS_TimerSetNextFireTime(timer, nextFire);\n\t\t\ttimer.isValid = true;\n\t\t\tsTimerCV.notify_one();\n\t\t\treturn (IOS_ERROR)(&timer - sTimers.data());\n\t\t}\n\n\t\tIOS_ERROR IOS_StopTimer(IOSTimerId timerId)\n\t\t{\n\t\t\tstd::unique_lock _l(sTimerMutex);\n\t\t\tif (timerId >= sTimers.size() || !sTimers[timerId].isValid)\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\tIOS_StopTimerInternal(timerId);\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\tIOS_ERROR IOS_DestroyTimer(IOSTimerId timerId)\n\t\t{\n\t\t\tstd::unique_lock _l(sTimerMutex);\n\t\t\tif (timerId >= sTimers.size() || !sTimers[timerId].isValid)\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\tIOS_StopTimerInternal(timerId);\n\t\t\tsTimers[timerId].isValid = false;\n\t\t\tsTimersFreeHandles.push_back(timerId);\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\tvoid IOSTimerThread()\n\t\t{\n\t\t\tSetThreadName(\"IOS-Timer\");\n\t\t\tstd::unique_lock _l(sTimerMutex);\n\t\t\twhile (!sTimerThreadStop)\n\t\t\t{\n\t\t\t\tif (sTimerByFireTime.empty())\n\t\t\t\t{\n\t\t\t\t\tsTimerCV.wait_for(_l, std::chrono::milliseconds(10000));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tIOSTimerId timerId = *sTimerByFireTime.begin();\n\t\t\t\tIOSTimer& timer = sTimers[timerId];\n\t\t\t\tHRTick now = HighResolutionTimer::now().getTick();\n\t\t\t\tif (now >= timer.nextFire)\n\t\t\t\t{\n\t\t\t\t\tif(timer.repeat == 0)\n\t\t\t\t\t\tIOS_TimerSetNextFireTime(timer, 0);\n\t\t\t\t\telse\n\t\t\t\t\t\tIOS_TimerSetNextFireTime(timer, timer.nextFire + timer.repeat);\n\t\t\t\t\tIOSMsgQueueId queueId = timer.queueId;\n\t\t\t\t\tuint32 message = timer.message;\n\t\t\t\t\t// fire timer\n\t\t\t\t\t_l.unlock();\n\t\t\t\t\tIOSMessage msg;\n\t\t\t\t\tIOS_SendMessage(queueId, message, 1);\n\t\t\t\t\t_l.lock();\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tsTimerCV.wait_for(_l, std::chrono::microseconds(HighResolutionTimer::ticksToMicroseconds(timer.nextFire - now)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/* devices and IPC */\n\n\t\tstruct IOSResourceManager\n\t\t{\n\t\t\tbool isSet{false};\n\t\t\tstd::string path;\n\t\t\tIOSMsgQueueId msgQueueId;\n\t\t};\n\n\t\tstd::array<IOSResourceManager, 512> sDeviceResources;\n\t\t\n\t\tIOSResourceManager* _IOS_FindResourceManager(const char* devicePath)\n\t\t{\n\t\t\t_assume_lock();\n\t\t\tstd::string_view devicePathSV{ devicePath };\n\t\t\tfor (auto& it : sDeviceResources)\n\t\t\t{\n\t\t\t\tif (it.isSet && it.path == devicePathSV)\n\t\t\t\t\treturn &it;\n\t\t\t}\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tIOSResourceManager* _IOS_CreateNewResourceManager(const char* devicePath, IOSMsgQueueId msgQueueId)\n\t\t{\n\t\t\t_assume_lock();\n\t\t\tstd::string_view devicePathSV{ devicePath };\n\t\t\tfor (auto& it : sDeviceResources)\n\t\t\t{\n\t\t\t\tif (!it.isSet)\n\t\t\t\t{\n\t\t\t\t\tit.isSet = true;\n\t\t\t\t\tit.path = devicePath;\n\t\t\t\t\tit.msgQueueId = msgQueueId;\n\t\t\t\t\treturn &it;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tIOS_ERROR IOS_RegisterResourceManager(const char* devicePath, IOSMsgQueueId msgQueueId)\n\t\t{\n\t\t\tstd::unique_lock _lock(sInternalMutex);\n\t\t\tif (_IOS_FindResourceManager(devicePath))\n\t\t\t{\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t\treturn IOS_ERROR_INVALID; // correct error code?\n\t\t\t}\n\n\t\t\t// verify if queue is valid\n\t\t\tIOSMessageQueue* msgQueue;\n\t\t\tIOS_ERROR r = _IOS_GetMessageQueue(msgQueueId, msgQueue);\n\t\t\tif (r != IOS_ERROR_OK)\n\t\t\t\treturn r;\n\n\t\t\t// create resource manager\n\t\t\tIOSResourceManager* resourceMgr = _IOS_CreateNewResourceManager(devicePath, msgQueueId);\n\t\t\tif (!resourceMgr)\n\t\t\t\treturn IOS_ERROR_MAXIMUM_REACHED;\n\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\tvoid IOS_DestroyResourceManagerForQueueId(IOSMsgQueueId msgQueueId)\n\t\t{\n\t\t\t_assume_lock();\n\t\t\t// destroy all IPC handles associated with this queue\n\t\t\t_IPCDestroyAllHandlesForMsgQueue(msgQueueId);\n\t\t\t// destroy device resource manager\n\t\t\tfor (auto& it : sDeviceResources)\n\t\t\t{\n\t\t\t\tif (it.isSet && it.msgQueueId == msgQueueId)\n\t\t\t\t{\n\t\t\t\t\tit.isSet = false;\n\t\t\t\t\tit.path.clear();\n\t\t\t\t\tit.msgQueueId = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tIOS_ERROR IOS_DeviceAssociateId(const char* devicePath, uint32 id)\n\t\t{\n\t\t\t// not yet implemented\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\t/* IPC */\n\t\t\n\t\tstruct IOSDispatchableCommand\n\t\t{\n\t\t\t// stores a copy of incoming IPC requests with some extra information required for replies\n\t\t\tIPCCommandBody body; // our dispatchable copy\n\t\t\tIPCIoctlVector vecCopy[8]; // our copy of the Ioctlv vector array\n\t\t\tIPCCommandBody* originalBody; // the original command that was sent to us\n\t\t\tuint32 ppcCoreIndex;\n\t\t\tIOSDevHandle replyHandle; // handle for outgoing replies\n\t\t\tbool isAllocated{false};\n\t\t};\n\n\t\tSysAllocator<IOSDispatchableCommand, 96> sIPCDispatchableCommandPool;\n\t\tstd::queue<IOSDispatchableCommand*> sIPCFreeDispatchableCommands;\n\t\tFSpinlock sIPCDispatchableCommandPoolLock;\n\n\t\tvoid _IPCInitDispatchablePool()\n\t\t{\n\t\t\tsIPCDispatchableCommandPoolLock.lock();\n\t\t\twhile (!sIPCFreeDispatchableCommands.empty())\n\t\t\t\tsIPCFreeDispatchableCommands.pop();\n\t\t\tfor (size_t i = 0; i < sIPCDispatchableCommandPool.GetCount(); i++)\n\t\t\t\tsIPCFreeDispatchableCommands.push(sIPCDispatchableCommandPool.GetPtr()+i);\n\t\t\tsIPCDispatchableCommandPoolLock.unlock();\n\t\t}\n\n\t\tIOSDispatchableCommand* _IPCAllocateDispatchableCommand()\n\t\t{\n\t\t\tsIPCDispatchableCommandPoolLock.lock();\n\t\t\tif (sIPCFreeDispatchableCommands.empty())\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"IOS: Exhausted pool of dispatchable commands\");\n\t\t\t\tsIPCDispatchableCommandPoolLock.unlock();\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\tIOSDispatchableCommand* cmd = sIPCFreeDispatchableCommands.front();\n\t\t\tsIPCFreeDispatchableCommands.pop();\n\t\t\tcemu_assert_debug(!cmd->isAllocated);\n\t\t\tcmd->isAllocated = true;\n\t\t\tsIPCDispatchableCommandPoolLock.unlock();\n\t\t\treturn cmd;\n\t\t}\n\n\t\tvoid _IPCReleaseDispatchableCommand(IOSDispatchableCommand* cmd)\n\t\t{\n\t\t\tsIPCDispatchableCommandPoolLock.lock();\n\t\t\tcemu_assert_debug(cmd->isAllocated);\n\t\t\tcmd->isAllocated = false;\n\t\t\tsIPCFreeDispatchableCommands.push(cmd);\n\t\t\tsIPCDispatchableCommandPoolLock.unlock();\n\t\t}\n\n\t\tstatic constexpr size_t MAX_NUM_ACTIVE_DEV_HANDLES = 96; // per process\n\n\t\tstruct IPCActiveDeviceHandle\n\t\t{\n\t\t\tbool isSet{false};\n\t\t\tuint32 handleCheckValue{0};\n\t\t\tstd::string path;\n\t\t\tIOSMsgQueueId msgQueueId;\n\t\t\t// dispatch target handle (retrieved via IOS_OPEN command to dispatch target)\n\t\t\tbool hasDispatchTargetHandle{false};\n\t\t\tIOSDevHandle dispatchTargetHandle;\n\t\t};\n\n\t\tIPCActiveDeviceHandle sActiveDeviceHandles[MAX_NUM_ACTIVE_DEV_HANDLES];\n\n\t\tIOS_ERROR _IPCCreateResourceHandle(const char* devicePath, IOSDevHandle& handleOut)\n\t\t{\n\t\t\tstd::unique_lock _lock(sInternalMutex);\n\t\t\tstatic uint32 sHandleCreationCounter = 1;\n\t\t\t// find resource manager for device\n\t\t\tIOSResourceManager* resMgr = _IOS_FindResourceManager(devicePath);\n\t\t\tif (!resMgr)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"IOSU-Kernel: IOS_Open() could not open {}\", devicePath);\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\t}\n\t\t\tIOSMsgQueueId msgQueueId = resMgr->msgQueueId;\n\t\t\t_lock.unlock();\n\t\t\t// create new handle\n\t\t\tsint32 deviceHandleIndex = -1;\n\t\t\tfor (size_t i = 0; i < MAX_NUM_ACTIVE_DEV_HANDLES; i++)\n\t\t\t{\n\t\t\t\tif (!sActiveDeviceHandles[i].isSet)\n\t\t\t\t{\n\t\t\t\t\tdeviceHandleIndex = (sint32)i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcemu_assert_debug(deviceHandleIndex >= 0);\n\t\t\tif (deviceHandleIndex < 0)\n\t\t\t\treturn IOS_ERROR_MAXIMUM_REACHED;\n\t\t\t// calc handle\n\t\t\tuint32 devHandle = deviceHandleIndex | ((sHandleCreationCounter << 12) & 0x7FFFFFFF);\n\t\t\tsHandleCreationCounter++;\n\t\t\t// init handle instance\n\t\t\tsActiveDeviceHandles[deviceHandleIndex].isSet = true;\n\t\t\tsActiveDeviceHandles[deviceHandleIndex].handleCheckValue = devHandle;\n\t\t\tsActiveDeviceHandles[deviceHandleIndex].path = devicePath;\n\t\t\tsActiveDeviceHandles[deviceHandleIndex].msgQueueId = msgQueueId;\n\t\t\tsActiveDeviceHandles[deviceHandleIndex].hasDispatchTargetHandle = false;\t\t\t\n\t\t\thandleOut = devHandle;\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\tIOS_ERROR _IPCDestroyResourceHandle(IOSDevHandle devHandle)\n\t\t{\n\t\t\tstd::unique_lock _lock(sInternalMutex);\n\t\t\tuint32 index = devHandle & 0xFFF;\n\t\t\tcemu_assert(index < MAX_NUM_ACTIVE_DEV_HANDLES);\n\t\t\tif (!sActiveDeviceHandles[index].isSet)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"_IPCDispatchToResourceManager(): Resource manager destroyed before all IPC commands were processed\");\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\t}\n\t\t\tif (devHandle != sActiveDeviceHandles[index].handleCheckValue)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"_IPCDispatchToResourceManager(): Mismatching handle\");\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\t}\n\t\t\tsActiveDeviceHandles[index].isSet = false;\n\t\t\tsActiveDeviceHandles[index].handleCheckValue = 0;\n\t\t\tsActiveDeviceHandles[index].hasDispatchTargetHandle = false;\n\t\t\t_lock.unlock();\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\tvoid _IPCDestroyAllHandlesForMsgQueue(IOSMsgQueueId msgQueueId)\n\t\t{\n\t\t\t_assume_lock();\n\t\t\tfor (auto& it : sActiveDeviceHandles)\n\t\t\t{\n\t\t\t\tif (it.isSet && it.msgQueueId == msgQueueId)\n\t\t\t\t{\n\t\t\t\t\tit.isSet = false;\n\t\t\t\t\tit.path.clear();\n\t\t\t\t\tit.handleCheckValue = 0;\n\t\t\t\t\tit.hasDispatchTargetHandle = false;\n\t\t\t\t\tit.msgQueueId = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tIOS_ERROR _IPCAssignDispatchTargetHandle(IOSDevHandle devHandle, IOSDevHandle internalHandle)\n\t\t{\n\t\t\tstd::unique_lock _lock(sInternalMutex);\n\t\t\tuint32 index = devHandle & 0xFFF;\n\t\t\tcemu_assert(index < MAX_NUM_ACTIVE_DEV_HANDLES);\n\t\t\tif (!sActiveDeviceHandles[index].isSet)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"_IPCDispatchToResourceManager(): Resource manager destroyed before all IPC commands were processed\");\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\t}\n\t\t\tif (devHandle != sActiveDeviceHandles[index].handleCheckValue)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"_IPCDispatchToResourceManager(): Mismatching handle\");\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\t}\n\t\t\tcemu_assert_debug(!sActiveDeviceHandles[index].hasDispatchTargetHandle);\n\t\t\tsActiveDeviceHandles[index].hasDispatchTargetHandle = true;\n\t\t\tsActiveDeviceHandles[index].dispatchTargetHandle = internalHandle;\n\t\t\t_lock.unlock();\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\tIOS_ERROR _IPCDispatchToResourceManager(IOSDevHandle devHandle, IOSDispatchableCommand* dispatchCmd)\n\t\t{\n\t\t\tstd::unique_lock _lock(sInternalMutex);\n\t\t\tuint32 index = devHandle & 0xFFF;\n\t\t\tcemu_assert(index < MAX_NUM_ACTIVE_DEV_HANDLES);\n\t\t\tif (!sActiveDeviceHandles[index].isSet)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"_IPCDispatchToResourceManager(): Resource manager destroyed before all IPC commands were processed\");\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\t}\n\t\t\tif (devHandle != sActiveDeviceHandles[index].handleCheckValue)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"_IPCDispatchToResourceManager(): Mismatching handle\");\n\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\t}\n\t\t\tIOSMsgQueueId msgQueueId = sActiveDeviceHandles[index].msgQueueId;\n\t\t\tif (dispatchCmd->body.cmdId == IPCCommandId::IOS_OPEN)\n\t\t\t{\n\t\t\t\tcemu_assert(!sActiveDeviceHandles[index].hasDispatchTargetHandle);\n\t\t\t\tdispatchCmd->body.devHandle = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert(sActiveDeviceHandles[index].hasDispatchTargetHandle);\n\t\t\t\tdispatchCmd->body.devHandle = sActiveDeviceHandles[index].dispatchTargetHandle;\n\t\t\t}\n\t\t\t_lock.unlock();\n\t\t\tMEMPTR<IOSDispatchableCommand> msgVal{ dispatchCmd };\n\t\t\tIOS_ERROR r = IOS_SendMessage(msgQueueId, msgVal.GetMPTR(), 1);\n\t\t\tif(r != IOS_ERROR_OK)\n\t\t\t\tcemuLog_log(LogType::Force, \"_IPCDispatchToResourceManager(): SendMessage returned {}\", (sint32)r);\n\t\t\treturn r;\n\t\t}\n\n\t\tstd::mutex sMtxReply[3];\n\n\t\tvoid _IPCReplyAndRelease(IOSDispatchableCommand* dispatchCmd, uint32 result)\n\t\t{\n\t\t\tcemu_assert(dispatchCmd->ppcCoreIndex < 3);\n\t\t\tstd::unique_lock _l(sMtxReply[(uint32)dispatchCmd->ppcCoreIndex]);\n\t\t\tcemu_assert(dispatchCmd >= sIPCDispatchableCommandPool.GetPtr() && dispatchCmd < sIPCDispatchableCommandPool.GetPtr() + sIPCDispatchableCommandPool.GetCount());\t\n\t\t\tdispatchCmd->originalBody->result = result;\n\t\t\t// submit to COS\n\t\t\tIPCCommandBody* responseArray[1];\n\t\t\tresponseArray[0] = dispatchCmd->originalBody;\n\t\t\tcoreinit::IPCDriver_NotifyResponses(dispatchCmd->ppcCoreIndex, responseArray, 1);\n\t\t\t_IPCReleaseDispatchableCommand(dispatchCmd);\n\t\t}\n\n\t\tIOS_ERROR _IPCHandlerIn_IOS_Open(IOSDispatchableCommand* dispatchCmd)\n\t\t{\n\t\t\tIPCCommandBody& cmd = dispatchCmd->body;\n\t\t\tconst char* name = MEMPTR<const char>(cmd.args[0]).GetPtr();\n\t\t\tuint32 nameLenPlusOne = cmd.args[1];\n\t\t\tcemu_assert(nameLenPlusOne > 0);\n\t\t\tuint32 flags = cmd.args[2];\n\t\t\tcemu_assert_debug(flags == 0);\n\n\t\t\tstd::string devicePath{ name, nameLenPlusOne - 1 };\n\n\t\t\tIOSDevHandle handle;\n\t\t\tIOS_ERROR r = _IPCCreateResourceHandle(devicePath.c_str(), handle);\n\t\t\tif (r != IOS_ERROR_OK)\n\t\t\t\treturn r;\n\t\t\tdispatchCmd->replyHandle = handle;\n\t\t\tdispatchCmd->body.devHandle = 0;\n\t\t\tr = _IPCDispatchToResourceManager(handle, dispatchCmd);\n\t\t\treturn r;\n\t\t}\n\n\t\tIOS_ERROR _IPCHandlerIn_IOS_Close(IOSDispatchableCommand* dispatchCmd)\n\t\t{\n\t\t\tIPCCommandBody& cmd = dispatchCmd->body;\n\t\t\tIOS_ERROR r = _IPCDispatchToResourceManager(dispatchCmd->body.devHandle, dispatchCmd);\n\t\t\treturn r;\n\t\t}\n\n\t\tIOS_ERROR _IPCHandlerIn_IOS_Ioctl(IOSDispatchableCommand* dispatchCmd)\n\t\t{\n\t\t\tIPCCommandBody& cmd = dispatchCmd->body;\n\t\t\tIOS_ERROR r = _IPCDispatchToResourceManager(dispatchCmd->body.devHandle, dispatchCmd);\n\t\t\treturn r;\n\t\t}\n\n\t\tIOS_ERROR _IPCHandlerIn_IOS_Ioctlv(IOSDispatchableCommand* dispatchCmd)\n\t\t{\n\t\t\tIPCCommandBody& cmd = dispatchCmd->body;\n\t\t\tuint32 requestId = dispatchCmd->body.args[0];\n\t\t\tuint32 numIn = dispatchCmd->body.args[1];\n\t\t\tuint32 numOut = dispatchCmd->body.args[2];\n\t\t\tIPCIoctlVector* vec = MEMPTR<IPCIoctlVector>(cmd.args[3]).GetPtr();\n\t\t\t// copy the vector array\n\t\t\tuint32 numVec = numIn + numOut;\n\t\t\tif (numVec <= 8)\n\t\t\t{\n\t\t\t\tstd::copy(vec, vec + numVec, dispatchCmd->vecCopy);\n\t\t\t\tdispatchCmd->body.args[3] = MEMPTR<IPCIoctlVector>(vec).GetMPTR();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// reuse the original vector pointer\n\t\t\t\tcemuLog_log(LogType::Force, \"Info: Ioctlv command with more than 8 vectors\");\n\t\t\t}\n\t\t\treturn _IPCDispatchToResourceManager(dispatchCmd->body.devHandle, dispatchCmd);\n\t\t}\n\n\t\t// normally COS kernel handles this, but currently we skip the IPC getting proxied through it\n\t\tIOS_ERROR _IPCHandlerIn_TranslateVectorAddresses(IOSDispatchableCommand* dispatchCmd)\n\t\t{\n\t\t\tuint32 numIn = dispatchCmd->body.args[1];\n\t\t\tuint32 numOut = dispatchCmd->body.args[2];\n\t\t\tIPCIoctlVector* vec = MEMPTR<IPCIoctlVector>(dispatchCmd->body.args[3]).GetPtr();\n\t\t\tfor (uint32 i = 0; i < numIn + numOut; i++)\n\t\t\t{\n\t\t\t\tif (vec[i].baseVirt == nullptr && vec[i].size != 0)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"IPC Ioctlv failed because baseVirt is null but size is not 0\");\n\t\t\t\t\treturn IOS_ERROR_INVALID;\n\t\t\t\t}\n\t\t\t\t// todo - check for valid pointer range\n\t\t\t\tvec[i].basePhys = vec[i].baseVirt;\n\t\t\t}\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\t// called by COS directly\n\t\tvoid IPCSubmitFromCOS(uint32 ppcCoreIndex, IPCCommandBody* cmd)\n\t\t{\n\t\t\t// create a copy of the cmd\n\t\t\tIOSDispatchableCommand* dispatchCmd = _IPCAllocateDispatchableCommand();\n\t\t\tdispatchCmd->body = *cmd;\n\t\t\tdispatchCmd->originalBody = cmd;\n\t\t\tdispatchCmd->ppcCoreIndex = ppcCoreIndex;\n\t\t\tdispatchCmd->replyHandle = cmd->devHandle;\n\t\t\t// forward command to device\n\t\t\tIOS_ERROR r = IOS_ERROR_INVALID;\n\t\t\tswitch ((IPCCommandId)cmd->cmdId)\n\t\t\t{\n\t\t\tcase IPCCommandId::IOS_OPEN:\n\t\t\t\tdispatchCmd->replyHandle = 0;\n\t\t\t\tr = _IPCHandlerIn_IOS_Open(dispatchCmd);\n\t\t\t\tbreak;\n\t\t\tcase IPCCommandId::IOS_CLOSE:\n\t\t\t\tr = _IPCHandlerIn_IOS_Close(dispatchCmd);\n\t\t\t\tbreak;\n\t\t\tcase IPCCommandId::IOS_IOCTL:\n\t\t\t\tr = _IPCHandlerIn_IOS_Ioctl(dispatchCmd);\n\t\t\t\tbreak;\n\t\t\tcase IPCCommandId::IOS_IOCTLV:\n\t\t\t\tr = _IPCHandlerIn_TranslateVectorAddresses(dispatchCmd);\n\t\t\t\tif(r < 0)\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Ioctlv error\");\n\t\t\t\telse\n\t\t\t\t\tr = _IPCHandlerIn_IOS_Ioctlv(dispatchCmd);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemuLog_log(LogType::Force, \"Invalid IPC command {}\", (uint32)(IPCCommandId)cmd->cmdId);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (r < 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Error occurred while trying to dispatch IPC\");\t\t\t\n\t\t\t\t_IPCReplyAndRelease(dispatchCmd, r);\n\t\t\t\t// in non-error case the device handler will send the result asynchronously via IOS_ResourceReply\n\t\t\t}\n\t\t}\n\n\t\tIOS_ERROR IOS_ResourceReply(IPCCommandBody* cmd, IOS_ERROR result)\n\t\t{\n\t\t\tIOSDispatchableCommand* dispatchCmd = (IOSDispatchableCommand*)cmd;\n\t\t\tcemu_assert(dispatchCmd >= sIPCDispatchableCommandPool.GetPtr() && dispatchCmd < sIPCDispatchableCommandPool.GetPtr() + sIPCDispatchableCommandPool.GetCount());\n\t\t\tcemu_assert_debug(dispatchCmd->isAllocated);\n\t\t\tdispatchCmd->originalBody->result = result;\n\t\t\tif (dispatchCmd->originalBody->cmdId == IPCCommandId::IOS_OPEN)\n\t\t\t{\n\t\t\t\tIOSDevHandle devHandle = dispatchCmd->replyHandle;\n\t\t\t\tif (IOS_ResultIsError(result))\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"IOS_ResourceReply(): Target device triggered an error on IOS_OPEN\");\n\t\t\t\t\t// dispatch target returned error, destroy our device handle again\n\t\t\t\t\tIOS_ERROR r = _IPCDestroyResourceHandle(devHandle);\n\t\t\t\t\tcemu_assert(r == IOS_ERROR_OK);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemu_assert(_IPCAssignDispatchTargetHandle(devHandle, (IOSDevHandle)result) == IOS_ERROR_OK);\n\t\t\t\t\tresult = (IOS_ERROR)(uint32)devHandle;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (dispatchCmd->originalBody->cmdId == IPCCommandId::IOS_CLOSE)\n\t\t\t{\n\t\t\t\tif (IOS_ResultIsError(result))\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"IOS_ResourceReply(): Target device triggered an error on IOS_CLOSE\");\n\t\t\t\t}\n\t\t\t\t// reply, then destroy handle\n\t\t\t\tIOSDevHandle devHandle = dispatchCmd->replyHandle;\n\t\t\t\t_IPCReplyAndRelease(dispatchCmd, result);\n\t\t\t\tIOS_ERROR r = _IPCDestroyResourceHandle(devHandle);\n\t\t\t\tcemu_assert_debug(r == IOS_ERROR::IOS_ERROR_OK);\n\t\t\t\treturn IOS_ERROR_OK;\n\t\t\t}\n\t\t\t_IPCReplyAndRelease(dispatchCmd, result);\n\t\t\treturn IOS_ERROR_OK;\n\t\t}\n\n\t\tclass : public ::IOSUModule\n\t\t{\n\t\t\tvoid SystemLaunch() override\n\t\t\t{\n\t\t\t\t_IPCInitDispatchablePool();\n\t\t\t\t// start timer thread\n\t\t\t\tsTimerThreadStop = false;\n\t\t\t\tm_timerThread = std::thread(IOSTimerThread);\n\t\t\t}\n\n\t\t\tvoid SystemExit() override\n\t\t\t{\n\t\t\t\t// stop timer thread\n\t\t\t\tsTimerThreadStop = true;\n\t\t\t\tsTimerCV.notify_one();\n\t\t\t\tm_timerThread.join();\n\t\t\t\t// reset resources\n\t\t\t\t// todo\n\t\t\t}\n\n\t\t\tstd::thread m_timerThread;\n\t\t}sIOSUModuleKernel;\n\n\t\tIOSUModule* GetModule()\n\t\t{\n\t\t\treturn static_cast<IOSUModule*>(&sIOSUModuleKernel);\n\t\t}\n\n\n\t}\n}"
  },
  {
    "path": "src/Cafe/IOSU/kernel/iosu_kernel.h",
    "content": "#pragma once\n#include \"Cafe/IOSU/iosu_ipc_common.h\"\n#include \"Cafe/IOSU/iosu_types_common.h\"\n\nnamespace iosu\n{\n\tnamespace kernel\n\t{\n\t\tusing IOSMessage = uint32;\n\n\t\tIOSMsgQueueId IOS_CreateMessageQueue(IOSMessage* messageArray, uint32 messageCount);\n\t\tIOS_ERROR IOS_DestroyMessageQueue(IOSMsgQueueId msgQueueId);\n\t\tIOS_ERROR IOS_SendMessage(IOSMsgQueueId msgQueueId, IOSMessage message, uint32 flags);\n\t\tIOS_ERROR IOS_ReceiveMessage(IOSMsgQueueId msgQueueId, IOSMessage* messageOut, uint32 flags);\n\n\t\tIOS_ERROR IOS_CreateTimer(uint32 startMicroseconds, uint32 repeatMicroseconds, uint32 queueId, uint32 message);\n\t\tIOS_ERROR IOS_StopTimer(IOSTimerId timerId);\n\t\tIOS_ERROR IOS_DestroyTimer(IOSTimerId timerId);\n\n\t\tIOS_ERROR IOS_RegisterResourceManager(const char* devicePath, IOSMsgQueueId msgQueueId);\n\t\tIOS_ERROR IOS_DeviceAssociateId(const char* devicePath, uint32 id);\n\t\tIOS_ERROR IOS_ResourceReply(IPCCommandBody* cmd, IOS_ERROR result);\n\n\t\tvoid IPCSubmitFromCOS(uint32 ppcCoreIndex, IPCCommandBody* cmd);\n\n\t\tIOSUModule* GetModule();\n\t}\n}"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_acp.cpp",
    "content": "#include \"iosu_ioctl.h\"\n#include \"iosu_acp.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"util/tinyxml2/tinyxml2.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/nn_save/nn_save.h\"\n#include \"util/helpers/helpers.h\"\n#include \"Cafe/OS/libs/nn_acp/nn_acp.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_FS.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n//#include \"Cafe/HW/Espresso/PPCState.h\"\n\n#include \"Cafe/IOSU/iosu_types_common.h\"\n#include \"Cafe/IOSU/nn/iosu_nn_service.h\"\n\n#include \"Cafe/IOSU/legacy/iosu_act.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"config/ActiveSettings.h\"\n\n#include <inttypes.h>\n\nusing ACPDeviceType = iosu::acp::ACPDeviceType;\n\nstatic_assert(sizeof(acpMetaXml_t) == 0x3440);\nstatic_assert(offsetof(acpMetaXml_t, title_id) == 0x0000);\nstatic_assert(offsetof(acpMetaXml_t, boss_id) == 0x0008);\nstatic_assert(offsetof(acpMetaXml_t, os_version) == 0x0010);\nstatic_assert(offsetof(acpMetaXml_t, app_size) == 0x0018);\nstatic_assert(offsetof(acpMetaXml_t, common_save_size) == 0x0020);\n\nstatic_assert(offsetof(acpMetaXml_t, version) == 0x0048);\nstatic_assert(offsetof(acpMetaXml_t, product_code) == 0x004C);\nstatic_assert(offsetof(acpMetaXml_t, logo_type) == 0x00B4);\nstatic_assert(offsetof(acpMetaXml_t, pc_cero) == 0x0100);\n\nstatic_assert(offsetof(acpMetaXml_t, longname_ja) == 0x038C);\nstatic_assert(offsetof(acpMetaXml_t, shortname_ja) == 0x1B8C);\nstatic_assert(offsetof(acpMetaXml_t, publisher_ja) == 0x278C);\n\nstatic_assert(sizeof(acpMetaData_t) == 0x1AB00);\nstatic_assert(offsetof(acpMetaData_t, bootMovie) == 0);\nstatic_assert(offsetof(acpMetaData_t, bootLogoTex) == 0x13B38);\n\nnamespace iosu\n{\n\n\tstruct\n\t{\n\t\tbool isInitialized;\n\t}iosuAcp = { 0 };\n\n\tvoid _xml_parseU32(tinyxml2::XMLElement* xmlElement, const char* name, uint32be* v)\n\t{\n\t\ttinyxml2::XMLElement* subElement = xmlElement->FirstChildElement(name);\n\t\t*v = 0;\n\t\tif (subElement == nullptr)\n\t\t\treturn;\n\t\tconst char* text = subElement->GetText();\n\t\tuint32 value;\n\t\tif (sscanf(text, \"%u\", &value) == 0)\n\t\t\treturn;\n\t\t*v = value;\n\t}\n\n\tvoid _xml_parseHex16(tinyxml2::XMLElement* xmlElement, const char* name, uint16be* v)\n\t{\n\t\ttinyxml2::XMLElement* subElement = xmlElement->FirstChildElement(name);\n\t\t*v = 0;\n\t\tif (subElement == nullptr)\n\t\t\treturn;\n\t\tconst char* text = subElement->GetText();\n\t\tuint32 value;\n\t\tif (sscanf(text, \"%x\", &value) == 0)\n\t\t\treturn;\n\t\t*v = value;\n\t}\n\n\tvoid _xml_parseHex32(tinyxml2::XMLElement* xmlElement, const char* name, uint32be* v)\n\t{\n\t\ttinyxml2::XMLElement* subElement = xmlElement->FirstChildElement(name);\n\t\t*v = 0;\n\t\tif (subElement == nullptr)\n\t\t\treturn;\n\t\tconst char* text = subElement->GetText();\n\t\tuint32 value;\n\t\tif (sscanf(text, \"%x\", &value) == 0)\n\t\t\treturn;\n\t\t*v = value;\n\t}\n\n\tvoid _xml_parseHex64(tinyxml2::XMLElement* xmlElement, const char* name, uint64* v)\n\t{\n\t\ttinyxml2::XMLElement* subElement = xmlElement->FirstChildElement(name);\n\t\t*v = 0;\n\t\tif (subElement == nullptr)\n\t\t\treturn;\n\t\tconst char* text = subElement->GetText();\n\t\tuint64 value;\n\t\tif (sscanf(text, \"%\" SCNx64, &value) == 0)\n\t\t\treturn;\n\t\t*v = _swapEndianU64(value);\n\t}\n\n\tvoid _xml_parseString_(tinyxml2::XMLElement* xmlElement, const char* name, char* output, sint32 maxLength)\n\t{\n\t\ttinyxml2::XMLElement* subElement = xmlElement->FirstChildElement(name);\n\t\toutput[0] = '\\0';\n\t\tif (subElement == nullptr)\n\t\t\treturn;\n\t\tconst char* text = subElement->GetText();\n\t\tif (text == nullptr)\n\t\t{\n\t\t\toutput[0] = '\\0';\n\t\t\treturn;\n\t\t}\n\t\tstrncpy(output, text, maxLength - 1);\n\t\toutput[maxLength - 1] = '\\0';\n\t}\n\n#define _metaXml_parseString(__xmlElement, __name, __output) _xml_parseString_(__xmlElement, __name, __output, sizeof(__output));\n\n\tvoid parseSaveMetaXml(uint8* metaXmlData, sint32 metaXmlLength, acpMetaXml_t* metaXml)\n\t{\n\t\tmemset(metaXml, 0, sizeof(acpMetaXml_t));\n\t\ttinyxml2::XMLDocument appXml;\n\t\tappXml.Parse((const char*)metaXmlData, metaXmlLength);\n\t\tuint32 titleVersion = 0xFFFFFFFF;\n\t\ttinyxml2::XMLElement* menuElement = appXml.FirstChildElement(\"menu\");\n\t\tif (menuElement)\n\t\t{\n\t\t\t_xml_parseHex64(menuElement, \"title_id\", &metaXml->title_id);\n\t\t\t_xml_parseHex64(menuElement, \"boss_id\", &metaXml->boss_id);\n\t\t\t_xml_parseHex64(menuElement, \"os_version\", &metaXml->os_version);\n\t\t\t_xml_parseHex64(menuElement, \"app_size\", &metaXml->app_size);\n\t\t\t_xml_parseHex64(menuElement, \"common_save_size\", &metaXml->common_save_size);\n\t\t\t_xml_parseHex64(menuElement, \"account_save_size\", &metaXml->account_save_size);\n\t\t\t_xml_parseHex64(menuElement, \"common_boss_size\", &metaXml->common_boss_size);\n\t\t\t_xml_parseHex64(menuElement, \"account_boss_size\", &metaXml->account_boss_size);\n\t\t\t_xml_parseHex64(menuElement, \"join_game_mode_mask\", &metaXml->join_game_mode_mask);\n\t\t\t_xml_parseU32(menuElement, \"version\", &metaXml->version);\n\t\t\t_metaXml_parseString(menuElement, \"product_code\", metaXml->product_code);\n\t\t\t_metaXml_parseString(menuElement, \"content_platform\", metaXml->content_platform);\n\t\t\t_metaXml_parseString(menuElement, \"company_code\", metaXml->company_code);\n\t\t\t_metaXml_parseString(menuElement, \"mastering_date\", metaXml->mastering_date);\n\t\t\t_xml_parseU32(menuElement, \"logo_type\", &metaXml->logo_type);\n\n\t\t\t_xml_parseU32(menuElement, \"app_launch_type\", &metaXml->app_launch_type);\n\t\t\t_xml_parseU32(menuElement, \"invisible_flag\", &metaXml->invisible_flag);\n\t\t\t_xml_parseU32(menuElement, \"no_managed_flag\", &metaXml->no_managed_flag);\n\t\t\t_xml_parseU32(menuElement, \"no_event_log\", &metaXml->no_event_log);\n\t\t\t_xml_parseU32(menuElement, \"no_icon_database\", &metaXml->no_icon_database);\n\t\t\t_xml_parseU32(menuElement, \"launching_flag\", &metaXml->launching_flag);\n\t\t\t_xml_parseU32(menuElement, \"install_flag\", &metaXml->install_flag);\n\t\t\t_xml_parseU32(menuElement, \"closing_msg\", &metaXml->closing_msg);\n\t\t\t_xml_parseU32(menuElement, \"title_version\", &metaXml->title_version);\n\t\t\t_xml_parseHex32(menuElement, \"group_id\", &metaXml->group_id);\n\t\t\t_xml_parseU32(menuElement, \"save_no_rollback\", &metaXml->save_no_rollback);\n\t\t\t_xml_parseU32(menuElement, \"bg_daemon_enable\", &metaXml->bg_daemon_enable);\n\t\t\t_xml_parseHex32(menuElement, \"join_game_id\", &metaXml->join_game_id);\n\n\t\t\t_xml_parseU32(menuElement, \"olv_accesskey\", &metaXml->olv_accesskey);\n\t\t\t_xml_parseU32(menuElement, \"wood_tin\", &metaXml->wood_tin);\n\t\t\t_xml_parseU32(menuElement, \"e_manual\", &metaXml->e_manual);\n\t\t\t_xml_parseU32(menuElement, \"e_manual_version\", &metaXml->e_manual_version);\n\t\t\t_xml_parseHex32(menuElement, \"region\", &metaXml->region);\n\n\t\t\t_xml_parseU32(menuElement, \"pc_cero\", &metaXml->pc_cero);\n\t\t\t_xml_parseU32(menuElement, \"pc_esrb\", &metaXml->pc_esrb);\n\t\t\t_xml_parseU32(menuElement, \"pc_bbfc\", &metaXml->pc_bbfc);\n\t\t\t_xml_parseU32(menuElement, \"pc_usk\", &metaXml->pc_usk);\n\t\t\t_xml_parseU32(menuElement, \"pc_pegi_gen\", &metaXml->pc_pegi_gen);\n\t\t\t_xml_parseU32(menuElement, \"pc_pegi_fin\", &metaXml->pc_pegi_fin);\n\t\t\t_xml_parseU32(menuElement, \"pc_pegi_prt\", &metaXml->pc_pegi_prt);\n\t\t\t_xml_parseU32(menuElement, \"pc_pegi_bbfc\", &metaXml->pc_pegi_bbfc);\n\n\t\t\t_xml_parseU32(menuElement, \"pc_cob\", &metaXml->pc_cob);\n\t\t\t_xml_parseU32(menuElement, \"pc_grb\", &metaXml->pc_grb);\n\t\t\t_xml_parseU32(menuElement, \"pc_cgsrr\", &metaXml->pc_cgsrr);\n\t\t\t_xml_parseU32(menuElement, \"pc_oflc\", &metaXml->pc_oflc);\n\n\t\t\t_xml_parseU32(menuElement, \"pc_reserved0\", &metaXml->pc_reserved0);\n\t\t\t_xml_parseU32(menuElement, \"pc_reserved1\", &metaXml->pc_reserved1);\n\t\t\t_xml_parseU32(menuElement, \"pc_reserved2\", &metaXml->pc_reserved2);\n\t\t\t_xml_parseU32(menuElement, \"pc_reserved3\", &metaXml->pc_reserved3);\n\n\t\t\t_xml_parseU32(menuElement, \"ext_dev_nunchaku\", &metaXml->ext_dev_nunchaku);\n\t\t\t_xml_parseU32(menuElement, \"ext_dev_classic\", &metaXml->ext_dev_classic);\n\t\t\t_xml_parseU32(menuElement, \"ext_dev_urcc\", &metaXml->ext_dev_urcc);\n\t\t\t_xml_parseU32(menuElement, \"ext_dev_board\", &metaXml->ext_dev_board);\n\t\t\t_xml_parseU32(menuElement, \"ext_dev_usb_keyboard\", &metaXml->ext_dev_usb_keyboard);\n\t\t\t_xml_parseU32(menuElement, \"ext_dev_etc\", &metaXml->ext_dev_etc);\n\n\t\t\t_metaXml_parseString(menuElement, \"ext_dev_etc_name\", metaXml->ext_dev_etc_name);\n\n\t\t\t_xml_parseU32(menuElement, \"eula_version\", &metaXml->eula_version);\n\t\t\t_xml_parseU32(menuElement, \"drc_use\", &metaXml->drc_use);\n\t\t\t_xml_parseU32(menuElement, \"network_use\", &metaXml->network_use);\n\t\t\t_xml_parseU32(menuElement, \"online_account_use\", &metaXml->online_account_use);\n\t\t\t_xml_parseU32(menuElement, \"direct_boot\", &metaXml->direct_boot);\n\t\t\t_xml_parseU32(menuElement, \"reserved_flag0\", &(metaXml->reserved_flag[0]));\n\t\t\t_xml_parseU32(menuElement, \"reserved_flag1\", &(metaXml->reserved_flag[1]));\n\t\t\t_xml_parseU32(menuElement, \"reserved_flag2\", &(metaXml->reserved_flag[2]));\n\t\t\t_xml_parseU32(menuElement, \"reserved_flag3\", &(metaXml->reserved_flag[3]));\n\t\t\t_xml_parseU32(menuElement, \"reserved_flag4\", &(metaXml->reserved_flag[4]));\n\t\t\t_xml_parseU32(menuElement, \"reserved_flag5\", &(metaXml->reserved_flag[5]));\n\t\t\t_xml_parseU32(menuElement, \"reserved_flag6\", &(metaXml->reserved_flag[6]));\n\t\t\t_xml_parseU32(menuElement, \"reserved_flag7\", &(metaXml->reserved_flag[7]));\n\n\t\t\t_metaXml_parseString(menuElement, \"longname_ja\", metaXml->longname_ja);\n\t\t\t_metaXml_parseString(menuElement, \"longname_en\", metaXml->longname_en);\n\t\t\t_metaXml_parseString(menuElement, \"longname_fr\", metaXml->longname_fr);\n\t\t\t_metaXml_parseString(menuElement, \"longname_de\", metaXml->longname_de);\n\t\t\t_metaXml_parseString(menuElement, \"longname_it\", metaXml->longname_it);\n\t\t\t_metaXml_parseString(menuElement, \"longname_es\", metaXml->longname_es);\n\t\t\t_metaXml_parseString(menuElement, \"longname_zhs\", metaXml->longname_zhs);\n\t\t\t_metaXml_parseString(menuElement, \"longname_ko\", metaXml->longname_ko);\n\t\t\t_metaXml_parseString(menuElement, \"longname_nl\", metaXml->longname_nl);\n\t\t\t_metaXml_parseString(menuElement, \"longname_pt\", metaXml->longname_pt);\n\t\t\t_metaXml_parseString(menuElement, \"longname_ru\", metaXml->longname_ru);\n\t\t\t_metaXml_parseString(menuElement, \"longname_zht\", metaXml->longname_zht);\n\n\t\t\t_metaXml_parseString(menuElement, \"shortname_ja\", metaXml->shortname_ja);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_en\", metaXml->shortname_en);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_fr\", metaXml->shortname_fr);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_de\", metaXml->shortname_de);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_it\", metaXml->shortname_it);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_es\", metaXml->shortname_es);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_zhs\", metaXml->shortname_zhs);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_ko\", metaXml->shortname_ko);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_nl\", metaXml->shortname_nl);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_pt\", metaXml->shortname_pt);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_ru\", metaXml->shortname_ru);\n\t\t\t_metaXml_parseString(menuElement, \"shortname_zht\", metaXml->shortname_zht);\n\n\t\t\t_metaXml_parseString(menuElement, \"publisher_ja\", metaXml->publisher_ja);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_en\", metaXml->publisher_en);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_fr\", metaXml->publisher_fr);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_de\", metaXml->publisher_de);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_it\", metaXml->publisher_it);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_es\", metaXml->publisher_es);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_zhs\", metaXml->publisher_zhs);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_ko\", metaXml->publisher_ko);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_nl\", metaXml->publisher_nl);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_pt\", metaXml->publisher_pt);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_ru\", metaXml->publisher_ru);\n\t\t\t_metaXml_parseString(menuElement, \"publisher_zht\", metaXml->publisher_zht);\n\n\t\t\tfor (sint32 i = 0; i < 32; i++)\n\t\t\t{\n\t\t\t\tchar tempStr[256];\n\t\t\t\tsprintf(tempStr, \"add_on_unique_id%d\", i);\n\t\t\t\t_xml_parseU32(menuElement, tempStr, &(metaXml->add_on_unique_id[i]));\n\t\t\t}\n\t\t}\n\t}\n\n\tbool _is8DigitHex(const char* str)\n\t{\n\t\tif (strlen(str) != 8)\n\t\t\treturn false;\n\t\tfor (sint32 f = 0; f < 8; f++)\n\t\t{\n\t\t\tif (str[f] >= '0' && str[f] <= '9')\n\t\t\t\tcontinue;\n\t\t\tif (str[f] >= 'a' && str[f] <= 'f')\n\t\t\t\tcontinue;\n\t\t\tif (str[f] >= 'A' && str[f] <= 'F')\n\t\t\t\tcontinue;\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tsint32 ACPGetSaveDataTitleIdList(uint32 storageDeviceGuessed, acpTitleId_t* titleIdList, sint32 maxCount, uint32be* countOut)\n\t{\n\t\tsint32 count = 0;\n\n\t\tconst char* devicePath = \"/vol/storage_mlc01/\";\n\t\tif (storageDeviceGuessed != 3)\n\t\t\tcemu_assert_unimplemented();\n\t\tchar searchPath[FSA_CMD_PATH_MAX_LENGTH];\n\t\tsprintf(searchPath, \"%susr/save/\", devicePath);\n\t\tsint32 fscStatus = 0;\n\t\tFSCVirtualFile* fscDirIteratorTitleIdHigh = fsc_openDirIterator(searchPath, &fscStatus);\n\t\tFSCDirEntry dirEntryTitleIdHigh;\n\t\tFSCDirEntry dirEntryTitleIdLow;\n\t\tif(fscDirIteratorTitleIdHigh)\n\t\t{ \n\t\t\twhile (fsc_nextDir(fscDirIteratorTitleIdHigh, &dirEntryTitleIdHigh))\n\t\t\t{\n\t\t\t\t// is 8-digit hex?\n\t\t\t\tif(_is8DigitHex(dirEntryTitleIdHigh.path) == false)\n\t\t\t\t\tcontinue;\n\t\t\t\tuint32 titleIdHigh;\n\t\t\t\tsscanf(dirEntryTitleIdHigh.path, \"%x\", &titleIdHigh);\n\t\t\t\tsprintf(searchPath, \"%susr/save/%08x/\", devicePath, titleIdHigh);\n\t\t\t\tFSCVirtualFile* fscDirIteratorTitleIdLow = fsc_openDirIterator(searchPath, &fscStatus);\n\t\t\t\tif (fscDirIteratorTitleIdLow)\n\t\t\t\t{\n\t\t\t\t\twhile (fsc_nextDir(fscDirIteratorTitleIdLow, &dirEntryTitleIdLow))\n\t\t\t\t\t{\n\t\t\t\t\t\t// is 8-digit hex?\n\t\t\t\t\t\tif (_is8DigitHex(dirEntryTitleIdLow.path) == false)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tuint32 titleIdLow;\n\t\t\t\t\t\tsscanf(dirEntryTitleIdLow.path, \"%x\", &titleIdLow);\n\t\t\t\t\t\t// check if /meta/meta.xml exists\n\t\t\t\t\t\tchar tempPath[FSA_CMD_PATH_MAX_LENGTH];\n\t\t\t\t\t\tsprintf(tempPath, \"%susr/save/%08x/%08x/meta/meta.xml\", devicePath, titleIdHigh, titleIdLow);\n\t\t\t\t\t\tif (fsc_doesFileExist(tempPath))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (count < maxCount)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttitleIdList[count].titleIdHigh = titleIdHigh;\n\t\t\t\t\t\t\t\ttitleIdList[count].titleIdLow = titleIdLow;\n\t\t\t\t\t\t\t\tcount++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"ACPGetSaveDataTitleIdList(): Missing meta.xml for save {:08x}-{:08x}\", titleIdHigh, titleIdLow);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tfsc_close(fscDirIteratorTitleIdLow);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfsc_close(fscDirIteratorTitleIdHigh);\n\t\t}\n\t\t*countOut = count;\n\t\treturn 0;\n\t}\n\n\tsint32 ACPGetTitleSaveMetaXml(uint64 titleId, acpMetaXml_t* acpMetaXml, sint32 uknType)\n\t{\n\t\t// uknType is probably the storage device?\n\t\tif (uknType != 3) // mlc01 ?\n\t\t\tassert_dbg();\n\n\t\tchar xmlPath[FSA_CMD_PATH_MAX_LENGTH];\n\t\tsprintf(xmlPath, \"%susr/save/%08x/%08x/meta/meta.xml\", \"/vol/storage_mlc01/\", (uint32)(titleId>>32), (uint32)(titleId&0xFFFFFFFF));\n\n\t\tuint32 saveMetaXmlSize = 0;\n\t\tuint8* saveMetaXmlData = fsc_extractFile(xmlPath, &saveMetaXmlSize);\n\t\tif (saveMetaXmlData)\n\t\t{\n\t\t\tparseSaveMetaXml(saveMetaXmlData, saveMetaXmlSize, acpMetaXml);\n\t\t\tfree(saveMetaXmlData);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"ACPGetTitleSaveMetaXml(): Meta file \\\"{}\\\" does not exist\", xmlPath);\n\t\t\tmemset(acpMetaXml, 0, sizeof(acpMetaXml_t));\n\t\t}\n\t\treturn 0;\n\t}\n\n\tsint32 ACPGetTitleMetaData(uint64 titleId, acpMetaData_t* acpMetaData)\n\t{\n\t\tmemset(acpMetaData, 0, sizeof(acpMetaData_t));\n\n\t\tchar titlePath[1024];\n\n\t\tif (((titleId >> 32) & 0x10) != 0)\n\t\t{\n\t\t\tsprintf(titlePath, \"/vol/storage_mlc01/sys/title/%08x/%08x/\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsprintf(titlePath, \"/vol/storage_mlc01/usr/title/%08x/%08x/\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\t}\n\n\n\t\tchar filePath[FSA_CMD_PATH_MAX_LENGTH];\n\t\tsprintf(filePath, \"%smeta/bootMovie.h264\", titlePath);\n\n\t\t// bootMovie.h264\n\t\tuint32 metaBootMovieSize = 0;\n\t\tuint8* metaBootMovieData = fsc_extractFile(filePath, &metaBootMovieSize);\n\t\tif (metaBootMovieData)\n\t\t{\n\t\t\tmemcpy(acpMetaData->bootMovie, metaBootMovieData, std::min<uint32>(metaBootMovieSize, sizeof(acpMetaData->bootMovie)));\n\t\t\tfree(metaBootMovieData);\n\t\t}\n\t\telse\n\t\t\tcemuLog_log(LogType::Force, \"ACPGetTitleMetaData(): Unable to load \\\"{}\\\"\", filePath);\n\t\t// bootLogoTex.tga\n\t\tsprintf(filePath, \"%smeta/bootLogoTex.tga\", titlePath);\n\t\tuint32 metaBootLogoSize = 0;\n\t\tuint8* metaBootLogoData = fsc_extractFile(filePath, &metaBootLogoSize);\n\t\tif (metaBootLogoData)\n\t\t{\n\t\t\tmemcpy(acpMetaData->bootLogoTex, metaBootLogoData, std::min<uint32>(metaBootLogoSize, sizeof(acpMetaData->bootLogoTex)));\n\t\t\tfree(metaBootLogoData);\n\t\t}\n\t\telse\n\t\t\tcemuLog_log(LogType::Force, \"ACPGetTitleMetaData(): Unable to load \\\"{}\\\"\", filePath);\n\n\n\t\treturn 0;\n\t}\n\n\tsint32 ACPGetTitleMetaXml(uint64 titleId, acpMetaXml_t* acpMetaXml)\n\t{\n\t\tmemset(acpMetaXml, 0, sizeof(acpMetaXml_t));\n\n\t\tchar titlePath[1024];\n\n\t\tif (((titleId >> 32) & 0x10) != 0)\n\t\t{\n\t\t\tsprintf(titlePath, \"/vol/storage_mlc01/sys/title/%08x/%08x/\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsprintf(titlePath, \"/vol/storage_mlc01/usr/title/%08x/%08x/\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\t}\n\n\n\t\tchar filePath[FSA_CMD_PATH_MAX_LENGTH];\n\t\tsprintf(filePath, \"%smeta/meta.xml\", titlePath);\n\n\t\tuint32 metaXmlSize = 0;\n\t\tuint8* metaXmlData = fsc_extractFile(filePath, &metaXmlSize);\n\t\tif (metaXmlData)\n\t\t{\n\t\t\tparseSaveMetaXml(metaXmlData, metaXmlSize, acpMetaXml);\n\t\t\tfree(metaXmlData);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"ACPGetTitleMetaXml(): Meta file \\\"{}\\\" does not exist\", filePath);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tsint32 ACPGetTitleSaveDirEx(uint64 titleId, uint32 storageDeviceGuessed, acpSaveDirInfo_t* saveDirInfo, sint32 maxCount, uint32be* countOut)\n\t{\n\t\tsint32 count = 0;\n\n\t\tconst char* devicePath = \"/vol/storage_mlc01/\";\n\t\tif (storageDeviceGuessed != 3)\n\t\t\tcemu_assert_unimplemented();\n\n\t\tchar searchPath[FSA_CMD_PATH_MAX_LENGTH];\n\t\tchar tempPath[FSA_CMD_PATH_MAX_LENGTH];\n\n\t\tsint32 fscStatus = 0;\n\t\t// add common dir\n\t\tsprintf(searchPath, \"%susr/save/%08x/%08x/user/common/\", devicePath, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\tif (fsc_doesDirectoryExist(searchPath))\n\t\t{\n\t\t\tacpSaveDirInfo_t* entry = saveDirInfo + count;\n\t\t\tif (count < maxCount)\n\t\t\t{\n\t\t\t\t// get dir size\n\t\t\t\tsprintf(tempPath, \"%susr/save/%08x/%08x/user/common/\", devicePath, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\t\t\tFSCVirtualFile* fscDir = fsc_open(tempPath, FSC_ACCESS_FLAG::OPEN_DIR, &fscStatus);\n\t\t\t\tuint64 dirSize = 0;\n\t\t\t\tif (fscDir)\n\t\t\t\t{\n\t\t\t\t\tdirSize = fsc_getFileSize(fscDir);\n\t\t\t\t\tfsc_close(fscDir);\n\t\t\t\t}\n\n\t\t\t\tmemset(entry, 0, sizeof(acpSaveDirInfo_t));\n\t\t\t\tentry->ukn00 = (uint32)(titleId>>32);\n\t\t\t\tentry->ukn04 = (uint32)(titleId&0xFFFFFFFF);\n\t\t\t\tentry->persistentId = 0; // 0 -> common save\n\t\t\t\tentry->ukn0C = 0;\n\t\t\t\tentry->sizeA = _swapEndianU64(0); // ukn\n\t\t\t\tentry->sizeB = _swapEndianU64(dirSize);\n\t\t\t\tentry->time = _swapEndianU64((coreinit::OSGetTime() / ESPRESSO_TIMER_CLOCK));\n\t\t\t\tsprintf(entry->path, \"%susr/save/%08x/%08x/meta/\", devicePath, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\t// add user directories\n\t\tsprintf(searchPath, \"%susr/save/%08x/%08x/user/\", devicePath, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\tFSCVirtualFile* fscDirIterator = fsc_openDirIterator(searchPath, &fscStatus);\n\t\tif (fscDirIterator == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"ACPGetTitleSaveDirEx(): Failed to iterate directories in \\\"{}\\\"\", searchPath);\n\t\t\t*countOut = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tFSCDirEntry dirEntry;\n\t\t\twhile( fsc_nextDir(fscDirIterator, &dirEntry) )\n\t\t\t{\n\t\t\t\tif(dirEntry.isDirectory == false)\n\t\t\t\t\tcontinue;\n\t\t\t\t// is 8-digit hex name? (persistent id)\n\t\t\t\tif(_is8DigitHex(dirEntry.path) == false )\n\t\t\t\t\tcontinue;\n\t\t\t\tuint32 persistentId = 0;\n\t\t\t\tsscanf(dirEntry.path, \"%x\", &persistentId);\n\t\t\t\tacpSaveDirInfo_t* entry = saveDirInfo + count;\n\t\t\t\tif (count < maxCount)\n\t\t\t\t{\n\t\t\t\t\tmemset(entry, 0, sizeof(acpSaveDirInfo_t));\n\t\t\t\t\tentry->ukn00 = (uint32)(titleId >> 32); // titleId?\n\t\t\t\t\tentry->ukn04 = (uint32)(titleId & 0xFFFFFFFF); // titleId?\n\t\t\t\t\tentry->persistentId = persistentId; // 0 -> common save\n\t\t\t\t\tentry->ukn0C = 0;\n\t\t\t\t\tentry->sizeA = _swapEndianU64(0);\n\t\t\t\t\tentry->sizeB = _swapEndianU64(0);\n\t\t\t\t\tentry->time = _swapEndianU64((coreinit::OSGetTime() / ESPRESSO_TIMER_CLOCK));\n\t\t\t\t\tsprintf(entry->path, \"%susr/save/%08x/%08x/meta/\", devicePath, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfsc_close(fscDirIterator);\n\t\t}\n\t\t*countOut = count;\n\t\treturn 0;\n\t}\n\n\tint iosuAcp_thread()\n\t{\n\t\tSetThreadName(\"iosuAcp_thread\");\n\t\twhile (true)\n\t\t{\n\t\t\tuint32 returnValue = 0; // Ioctl return value\n\t\t\tioQueueEntry_t* ioQueueEntry = iosuIoctl_getNextWithWait(IOS_DEVICE_ACP_MAIN);\n\t\t\tif (ioQueueEntry->request == IOSU_ACP_REQUEST_CEMU)\n\t\t\t{\n\t\t\t\tiosuAcpCemuRequest_t* acpCemuRequest = (iosuAcpCemuRequest_t*)ioQueueEntry->bufferVectors[0].buffer.GetPtr();\n\t\t\t\tif (acpCemuRequest->requestCode == IOSU_ACP_GET_SAVE_DATA_TITLE_ID_LIST)\n\t\t\t\t{\n\t\t\t\t\tuint32be count = 0;\n\t\t\t\t\tacpCemuRequest->returnCode = ACPGetSaveDataTitleIdList(acpCemuRequest->type, (acpTitleId_t*)acpCemuRequest->ptr.GetPtr(), acpCemuRequest->maxCount, &count);\n\t\t\t\t\tacpCemuRequest->resultU32.u32 = count;\n\t\t\t\t}\n\t\t\t\telse if (acpCemuRequest->requestCode == IOSU_ACP_GET_TITLE_SAVE_META_XML)\n\t\t\t\t{\n\t\t\t\t\tacpCemuRequest->returnCode = ACPGetTitleSaveMetaXml(acpCemuRequest->titleId, (acpMetaXml_t*)acpCemuRequest->ptr.GetPtr(), acpCemuRequest->type);\n\t\t\t\t}\n\t\t\t\telse if (acpCemuRequest->requestCode == IOSU_ACP_GET_TITLE_SAVE_DIR)\n\t\t\t\t{\n\t\t\t\t\tuint32be count = 0;\n\t\t\t\t\tacpCemuRequest->returnCode = ACPGetTitleSaveDirEx(acpCemuRequest->titleId, acpCemuRequest->type, (acpSaveDirInfo_t*)acpCemuRequest->ptr.GetPtr(), acpCemuRequest->maxCount, &count);\n\t\t\t\t\tacpCemuRequest->resultU32.u32 = count;\n\t\t\t\t}\n\t\t\t\telse if (acpCemuRequest->requestCode == IOSU_ACP_GET_TITLE_META_DATA)\n\t\t\t\t{\n\t\t\t\t\tacpCemuRequest->returnCode = ACPGetTitleMetaData(acpCemuRequest->titleId, (acpMetaData_t*)acpCemuRequest->ptr.GetPtr());\n\t\t\t\t}\n\t\t\t\telse if (acpCemuRequest->requestCode == IOSU_ACP_GET_TITLE_META_XML)\n\t\t\t\t{\n\t\t\t\t\tacpCemuRequest->returnCode = ACPGetTitleMetaXml(acpCemuRequest->titleId, (acpMetaXml_t*)acpCemuRequest->ptr.GetPtr());\n\t\t\t\t}\n\t\t\t\telse if (acpCemuRequest->requestCode == IOSU_ACP_CREATE_SAVE_DIR_EX)\n\t\t\t\t{\n\t\t\t\t\tacpCemuRequest->returnCode = acp::ACPCreateSaveDirEx(acpCemuRequest->accountSlot, acpCemuRequest->titleId);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\tiosuIoctl_completeRequest(ioQueueEntry, returnValue);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tvoid iosuAcp_init()\n\t{\n\t\tif (iosuAcp.isInitialized)\n\t\t\treturn;\n\t\tstd::thread t(iosuAcp_thread);\n\t\tt.detach();\n\t\tiosuAcp.isInitialized = true;\n\t}\n\n\tbool iosuAcp_isInitialized()\n\t{\n\t\treturn iosuAcp.isInitialized;\n\t}\n\n\t/* Above is the legacy implementation. Below is the new style implementation which also matches the official IPC protocol and works with the real nn_acp.rpl */\n\n\tnamespace acp\n\t{\n\n\t\tuint64 _ACPGetTimestamp()\n\t\t{\n\t\t\treturn coreinit::OSGetTime() / ESPRESSO_TIMER_CLOCK;\n\t\t}\n\n\t\tnnResult ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType)\n\t\t{\n\t\t\tif (deviceType == ACPDeviceType::UnknownType)\n\t\t\t{\n\t\t\t\treturn (nnResult)0xA030FB80;\n\t\t\t}\n\n\t\t\t// create or modify the saveinfo\n\t\t\tconst auto saveinfoPath = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/meta/saveinfo.xml\", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));\n\t\t\tauto saveinfoData = FileStream::LoadIntoMemory(saveinfoPath);\n\t\t\tif (saveinfoData && !saveinfoData->empty())\n\t\t\t{\n\t\t\t\tnamespace xml = tinyxml2;\n\t\t\t\txml::XMLDocument doc;\n\t\t\t\ttinyxml2::XMLError xmlError = doc.Parse((const char*)saveinfoData->data(), saveinfoData->size());\n\t\t\t\tif (xmlError == xml::XML_SUCCESS || xmlError == xml::XML_ERROR_EMPTY_DOCUMENT)\n\t\t\t\t{\n\t\t\t\t\txml::XMLNode* child = doc.FirstChild();\n\t\t\t\t\t// check for declaration -> <?xml version=\"1.0\" encoding=\"utf-8\"?>\n\t\t\t\t\tif (!child || !child->ToDeclaration())\n\t\t\t\t\t{\n\t\t\t\t\t\txml::XMLDeclaration* decl = doc.NewDeclaration();\n\t\t\t\t\t\tdoc.InsertFirstChild(decl);\n\t\t\t\t\t}\n\n\t\t\t\t\txml::XMLElement* info = doc.FirstChildElement(\"info\");\n\t\t\t\t\tif (!info)\n\t\t\t\t\t{\n\t\t\t\t\t\tinfo = doc.NewElement(\"info\");\n\t\t\t\t\t\tdoc.InsertEndChild(info);\n\t\t\t\t\t}\n\n\t\t\t\t\t// find node with persistentId\n\t\t\t\t\tchar tmp[64];\n\t\t\t\t\tsprintf(tmp, \"%08x\", persistentId);\n\t\t\t\t\tbool foundNode = false;\n\t\t\t\t\tfor (xml::XMLElement* account = info->FirstChildElement(\"account\"); account; account = account->NextSiblingElement(\"account\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (account->Attribute(\"persistentId\", tmp))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// found the entry! -> update timestamp\n\t\t\t\t\t\t\txml::XMLElement* timestamp = account->FirstChildElement(\"timestamp\");\n\t\t\t\t\t\t\tsprintf(tmp, \"%\" PRIx64, _ACPGetTimestamp());\n\t\t\t\t\t\t\tif (timestamp)\n\t\t\t\t\t\t\t\ttimestamp->SetText(tmp);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttimestamp = doc.NewElement(\"timestamp\");\n\t\t\t\t\t\t\t\taccount->InsertFirstChild(timestamp);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tfoundNode = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!foundNode)\n\t\t\t\t\t{\n\t\t\t\t\t\ttinyxml2::XMLElement* account = doc.NewElement(\"account\");\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsprintf(tmp, \"%08x\", persistentId);\n\t\t\t\t\t\t\taccount->SetAttribute(\"persistentId\", tmp);\n\n\t\t\t\t\t\t\ttinyxml2::XMLElement* timestamp = doc.NewElement(\"timestamp\");\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsprintf(tmp, \"%\" PRIx64, _ACPGetTimestamp());\n\t\t\t\t\t\t\t\ttimestamp->SetText(tmp);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\taccount->InsertFirstChild(timestamp);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tinfo->InsertFirstChild(account);\n\t\t\t\t\t}\n\n\t\t\t\t\t// update file\n\t\t\t\t\ttinyxml2::XMLPrinter printer;\n\t\t\t\t\tdoc.Print(&printer);\n\t\t\t\t\tFileStream* fs = FileStream::createFile2(saveinfoPath);\n\t\t\t\t\tif (fs)\n\t\t\t\t\t{\n\t\t\t\t\t\tfs->writeString(printer.CStr());\n\t\t\t\t\t\tdelete fs;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn NN_RESULT_SUCCESS;\n\t\t}\n\n\t\tvoid CreateSaveMetaFiles(uint32 persistentId, uint64 titleId)\n\t\t{\n\t\t\tstd::string titlePath = CafeSystem::GetMlcStoragePath(CafeSystem::GetForegroundTitleId());\n\n\t\t\tsint32 fscStatus;\n\t\t\tFSCVirtualFile* fscFile = fsc_open((titlePath + \"/meta/meta.xml\").c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);\n\t\t\tif (fscFile)\n\t\t\t{\n\t\t\t\tsint32 fileSize = fsc_getFileSize(fscFile);\n\n\t\t\t\tstd::unique_ptr<uint8[]> fileContent = std::make_unique<uint8[]>(fileSize);\n\t\t\t\tfsc_readFile(fscFile, fileContent.get(), fileSize);\n\t\t\t\tfsc_close(fscFile);\n\n\t\t\t\tconst auto outPath = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/meta/meta.xml\", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));\n\n\t\t\t\tstd::ofstream myFile(outPath, std::ios::out | std::ios::binary);\n\t\t\t\tmyFile.write((char*)fileContent.get(), fileSize);\n\t\t\t\tmyFile.close();\n\t\t\t}\n\n\t\t\tfscFile = fsc_open((titlePath + \"/meta/iconTex.tga\").c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);\n\t\t\tif (fscFile)\n\t\t\t{\n\t\t\t\tsint32 fileSize = fsc_getFileSize(fscFile);\n\n\t\t\t\tstd::unique_ptr<uint8[]> fileContent = std::make_unique<uint8[]>(fileSize);\n\t\t\t\tfsc_readFile(fscFile, fileContent.get(), fileSize);\n\t\t\t\tfsc_close(fscFile);\n\n\t\t\t\tconst auto outPath = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/meta/iconTex.tga\", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));\n\n\t\t\t\tstd::ofstream myFile(outPath, std::ios::out | std::ios::binary);\n\t\t\t\tmyFile.write((char*)fileContent.get(), fileSize);\n\t\t\t\tmyFile.close();\n\t\t\t}\n\n\t\t\tACPUpdateSaveTimeStamp(persistentId, titleId, iosu::acp::ACPDeviceType::InternalDeviceType);\n\t\t}\n\n\n\t\tsint32 _ACPCreateSaveDir(uint32 persistentId, uint64 titleId, ACPDeviceType type)\n\t\t{\n\t\t\tuint32 high = GetTitleIdHigh(titleId) & (~0xC);\n\t\t\tuint32 low = GetTitleIdLow(titleId);\n\n\t\t\tsint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\tchar path[256];\n\n\t\t\tsprintf(path, \"%susr/boss/\", \"/vol/storage_mlc01/\");\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/boss/%08x/\", \"/vol/storage_mlc01/\", high);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/boss/%08x/%08x/\", \"/vol/storage_mlc01/\", high, low);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/boss/%08x/%08x/user/\", \"/vol/storage_mlc01/\", high, low);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/boss/%08x/%08x/user/common\", \"/vol/storage_mlc01/\", high, low);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/boss/%08x/%08x/user/%08x/\", \"/vol/storage_mlc01/\", high, low, persistentId == 0 ? 0x80000001 : persistentId);\n\t\t\tfsc_createDir(path, &fscStatus);\n\n\t\t\tsprintf(path, \"%susr/save/%08x/\", \"/vol/storage_mlc01/\", high);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/save/%08x/%08x/\", \"/vol/storage_mlc01/\", high, low);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/save/%08x/%08x/meta/\", \"/vol/storage_mlc01/\", high, low);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/save/%08x/%08x/user/\", \"/vol/storage_mlc01/\", high, low);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/save/%08x/%08x/user/common\", \"/vol/storage_mlc01/\", high, low);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/save/%08x/%08x/user/%08x\", \"/vol/storage_mlc01/\", high, low, persistentId == 0 ? 0x80000001 : persistentId);\n\t\t\tfsc_createDir(path, &fscStatus);\n\n\t\t\t// copy xml meta files\n\t\t\tCreateSaveMetaFiles(persistentId, titleId);\n\t\t\treturn 0;\n\t\t}\n\n\t\tnnResult ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type)\n\t\t{\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\treturn _ACPCreateSaveDir(persistentId, titleId, type);\n\t\t}\n\n\t\tsint32 ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId)\n\t\t{\n\t\t\tuint32 persistentId = 0;\n\t\t\tcemu_assert_debug(accountSlot >= 1 && accountSlot <= 13); // outside valid slot range?\n\t\t\tbool r = iosu::act::GetPersistentId(accountSlot, &persistentId);\n\t\t\tcemu_assert_debug(r);\n\t\t\treturn _ACPCreateSaveDir(persistentId, titleId, ACPDeviceType::InternalDeviceType);\n\t\t}\n\n\t\tnnResult ACPGetOlvAccesskey(uint32be* accessKey)\n\t\t{\n\t\t\t*accessKey = CafeSystem::GetForegroundTitleOlvAccesskey();\n\t\t\treturn 0;\n\t\t}\n\n\t\tclass AcpMainService : public iosu::nn::IPCService\n\t\t{\n\t\t  public:\n\t\t\tAcpMainService() : iosu::nn::IPCService(\"/dev/acp_main\") {}\n\n\t\t\tnnResult ServiceCall(IPCServiceCall& serviceCall) override\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Unsupported service call to /dev/acp_main\");\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACP, 0);\n\t\t\t}\n\t\t};\n\n\t\tAcpMainService gACPMainService;\n\n\t\tclass : public ::IOSUModule\n\t\t{\n\t\t\tvoid TitleStart() override\n\t\t\t{\n\t\t\t\tgACPMainService.Start();\n\t\t\t\t// gACPMainService.SetTimerUpdate(1000); // call TimerUpdate() once a second\n\t\t\t}\n\t\t\tvoid TitleStop() override\n\t\t\t{\n\t\t\t\tgACPMainService.Stop();\n\t\t\t}\n\t\t}sIOSUModuleNNACP;\n\n\t\tIOSUModule* GetModule()\n\t\t{\n\t\t\treturn static_cast<IOSUModule*>(&sIOSUModuleNNACP);\n\t\t}\n\t} // namespace acp\n} // namespace iosu\n"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_acp.h",
    "content": "#pragma once\n\n#include \"Cafe/IOSU/iosu_types_common.h\"\n#include \"Cafe/OS/libs/nn_common.h\" // for nnResult\n\ntypedef struct\n{\n\t/* +0x0000 */ uint64 title_id; // parsed via GetHex64\n\t/* +0x0008 */ uint64 boss_id; // parsed via GetHex64\n\t/* +0x0010 */ uint64 os_version; // parsed via GetHex64\n\t/* +0x0018 */ uint64 app_size; // parsed via GetHex64\n\t/* +0x0020 */ uint64 common_save_size; // parsed via GetHex64\n\t/* +0x0028 */ uint64 account_save_size; // parsed via GetHex64\n\t/* +0x0030 */ uint64 common_boss_size; // parsed via GetHex64\n\t/* +0x0038 */ uint64 account_boss_size; // parsed via GetHex64\n\t/* +0x0040 */ uint64 join_game_mode_mask; // parsed via GetHex64\n\t/* +0x0048 */ uint32be version;\n\t/* +0x004C */ char product_code[0x20];\n\t/* +0x006C */ char content_platform[0x20];\n\t/* +0x008C */ char company_code[8];\n\t/* +0x0094 */ char mastering_date[0x20];\n\t/* +0x00B4 */ uint32be logo_type;\n\t/* +0x00B8 */ uint32be app_launch_type;\n\t/* +0x00BC */ uint32be invisible_flag;\n\t/* +0x00C0 */ uint32be no_managed_flag;\n\t/* +0x00C4 */ uint32be no_event_log;\n\t/* +0x00C8 */ uint32be no_icon_database;\n\t/* +0x00CC */ uint32be launching_flag;\n\t/* +0x00D0 */ uint32be install_flag;\n\t/* +0x00D4 */ uint32be closing_msg;\n\t/* +0x00D8 */ uint32be title_version;\n\t/* +0x00DC */ uint32be group_id; // Hex32\n\t/* +0x00E0 */ uint32be save_no_rollback;\n\t/* +0x00E4 */ uint32be bg_daemon_enable;\n\t/* +0x00E8 */ uint32be join_game_id; // Hex32\n\t/* +0x00EC */ uint32be olv_accesskey;\n\t/* +0x00F0 */ uint32be wood_tin;\n\t/* +0x00F4 */ uint32be e_manual;\n\t/* +0x00F8 */ uint32be e_manual_version;\n\t/* +0x00FC */ uint32be region; // Hex32\n\t/* +0x0100 */ uint32be pc_cero;\n\t/* +0x0104 */ uint32be pc_esrb;\n\t/* +0x0108 */ uint32be pc_bbfc;\n\t/* +0x010C */ uint32be pc_usk;\n\t/* +0x0110 */ uint32be pc_pegi_gen;\n\t/* +0x0114 */ uint32be pc_pegi_fin;\n\t/* +0x0118 */ uint32be pc_pegi_prt;\n\t/* +0x011C */ uint32be pc_pegi_bbfc;\n\t/* +0x0120 */ uint32be pc_cob;\n\t/* +0x0124 */ uint32be pc_grb;\n\t/* +0x0128 */ uint32be pc_cgsrr;\n\t/* +0x012C */ uint32be pc_oflc;\n\t/* +0x0130 */ uint32be pc_reserved0;\n\t/* +0x0134 */ uint32be pc_reserved1;\n\t/* +0x0138 */ uint32be pc_reserved2;\n\t/* +0x013C */ uint32be pc_reserved3;\n\t/* +0x0140 */ uint32be ext_dev_nunchaku;\n\t/* +0x0144 */ uint32be ext_dev_classic;\n\t/* +0x0148 */ uint32be ext_dev_urcc;\n\t/* +0x014C */ uint32be ext_dev_board;\n\t/* +0x0150 */ uint32be ext_dev_usb_keyboard;\n\t/* +0x0154 */ uint32be ext_dev_etc;\n\t/* +0x0158 */ char ext_dev_etc_name[0x200];\n\t/* +0x0358 */ uint32be eula_version;\n\t/* +0x035C */ uint32be drc_use;\n\t/* +0x0360 */ uint32be network_use;\n\t/* +0x0364 */ uint32be online_account_use;\n\t/* +0x0368 */ uint32be direct_boot;\n\t/* +0x036C */ uint32be reserved_flag[8]; // array of U32, reserved_flag%d\n\t/* +0x038C */ char     longname_ja[0x200];\n\t/* +0x058C */ char     longname_en[0x200];\n\t/* +0x078C */ char     longname_fr[0x200];\n\t/* +0x098C */ char     longname_de[0x200];\n\t/* +0x0B8C */ char     longname_it[0x200];\n\t/* +0x0D8C */ char     longname_es[0x200];\n\t/* +0x0F8C */ char     longname_zhs[0x200];\n\t/* +0x118C */ char     longname_ko[0x200];\n\t/* +0x138C */ char     longname_nl[0x200];\n\t/* +0x158C */ char     longname_pt[0x200];\n\t/* +0x178C */ char     longname_ru[0x200];\n\t/* +0x198C */ char     longname_zht[0x200];\n\t/* +0x1B8C */ char     shortname_ja[0x100];\n\t/* +0x1C8C */ char     shortname_en[0x100];\n\t/* +0x1D8C */ char     shortname_fr[0x100];\n\t/* +0x1E8C */ char     shortname_de[0x100];\n\t/* +0x1F8C */ char     shortname_it[0x100];\n\t/* +0x208C */ char     shortname_es[0x100];\n\t/* +0x218C */ char     shortname_zhs[0x100];\n\t/* +0x228C */ char     shortname_ko[0x100];\n\t/* +0x238C */ char     shortname_nl[0x100];\n\t/* +0x248C */ char     shortname_pt[0x100];\n\t/* +0x258C */ char     shortname_ru[0x100];\n\t/* +0x268C */ char     shortname_zht[0x100];\n\t/* +0x278C */ char     publisher_ja[0x100];\n\t/* +0x288C */ char     publisher_en[0x100];\n\t/* +0x298C */ char     publisher_fr[0x100];\n\t/* +0x2A8C */ char     publisher_de[0x100];\n\t/* +0x2B8C */ char     publisher_it[0x100];\n\t/* +0x2C8C */ char     publisher_es[0x100];\n\t/* +0x2D8C */ char     publisher_zhs[0x100];\n\t/* +0x2E8C */ char     publisher_ko[0x100];\n\t/* +0x2F8C */ char     publisher_nl[0x100];\n\t/* +0x308C */ char     publisher_pt[0x100];\n\t/* +0x318C */ char     publisher_ru[0x100];\n\t/* +0x328C */ char     publisher_zht[0x100];\n\t/* +0x338C */ uint32be add_on_unique_id[0x20]; // Hex32, add_on_unique_id%d\n\t/* +0x340C */ uint8    padding[0x3440 - 0x340C]; // guessed\n\t\t\t\t\t\t\t\t\t\t\t\t\t // struct size is 0x3440\n}acpMetaXml_t;\n\ntypedef struct\n{\n\t/* +0x06BDC | +0x00000 */ uint8 bootMovie[0x13B38];\n\t/* +0x1A714 | +0x13B38 */ uint8 bootLogoTex[0x6FBC];\n\t/* +0x216D0 | +0x1AAF4 */ uint8 ukn1AAF4[4];\n\t/* +0x216D4 | +0x1AAF8 */ uint8 ukn1AAF8[4];\n\t/* +0x216D8 | +0x1AAFC */ uint8 ukn1AAFC[4];\n}acpMetaData_t;\n\ntypedef struct\n{\n\tuint32be titleIdHigh;\n\tuint32be titleIdLow;\n}acpTitleId_t;\n\ntypedef struct\n{\n\t// for ACPGetTitleSaveDirEx\n\n\tuint32be ukn00;\n\tuint32be ukn04;\n\tuint32be persistentId;\n\tuint32be ukn0C;\n\t//uint32be ukn10; // ukn10/ukn14 are part of size\n\t//uint32be ukn14;\n\t//uint32be ukn18; // ukn18/ukn1C are part of size\n\t//uint32be ukn1C;\n\tuint64 sizeA;\n\tuint64 sizeB;\n\t// path starts at 0x20, length unknown?\n\tchar path[0x40]; // %susr/save/%08x/%08x/meta/\t\t\t// /vol/storage_mlc01/\n\t/* +0x60 */ uint64 time;\n\t/* +0x68 */ uint8 padding[0x80 - 0x68];\n\t// size is 0x80, but actual content size is only 0x60 and padded to 0x80?\n}acpSaveDirInfo_t;\n\n\n// custom dev/acp_main protocol (Cemu only)\n#define IOSU_ACP_REQUEST_CEMU\t\t(0xEE)\n\ntypedef struct\n{\n\tuint32 requestCode;\n\t// input\n\tuint8 accountSlot;\n\t//uint32 unique;\n\t//uint64 titleId;\n\t//uint32 titleVersion;\n\t//uint32 serverId;\n\tuint64 titleId;\n\tsint32 type;\n\tMEMPTR<void> ptr;\n\tsint32 maxCount;\n\t// output\n\tuint32 returnCode; // ACP return value\n\tunion\n\t{\n\t\t//struct\n\t\t//{\n\t\t//\tuint64 u64;\n\t\t//}resultU64;\n\t\tstruct\n\t\t{\n\t\t\tuint32 u32;\n\t\t}resultU32;\n\t\t//struct\n\t\t//{\n\t\t//\tchar strBuffer[1024];\n\t\t//}resultString;\n\t\t//struct\n\t\t//{\n\t\t//\tuint8 binBuffer[1024];\n\t\t//}resultBinary;\n\t};\n}iosuAcpCemuRequest_t;\n\n// ACP request Cemu subcodes\n#define IOSU_ACP_GET_SAVE_DATA_TITLE_ID_LIST\t\t\t\t0x01\n#define IOSU_ACP_GET_TITLE_SAVE_META_XML\t\t\t\t\t0x02\n#define IOSU_ACP_GET_TITLE_SAVE_DIR\t\t\t\t\t\t\t0x03\n#define IOSU_ACP_GET_TITLE_META_DATA\t\t\t\t\t\t0x04\n#define IOSU_ACP_GET_TITLE_META_XML\t\t\t\t\t\t\t0x05\n#define IOSU_ACP_CREATE_SAVE_DIR_EX\t\t\t\t\t\t\t0x06\n\nnamespace iosu\n{\n\tvoid iosuAcp_init();\n\n\tnamespace acp\n\t{\n\t\tenum ACPDeviceType\n\t\t{\n\t\t\tUnknownType = 0,\n\t\t\tInternalDeviceType = 1,\n\t\t\tUSBDeviceType = 3,\n\t\t};\n\n\t\tclass IOSUModule* GetModule();\n\n\t\tvoid CreateSaveMetaFiles(uint32 persistentId, uint64 titleId);\n\t\tnnResult ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType);\n\n\t\tnnResult ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type);\n\t\tsint32 ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId);\n\t\tnnResult ACPGetOlvAccesskey(uint32be* accessKey);\n\t}\n\n}"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_act.cpp",
    "content": "#include \"iosu_act.h\"\n#include \"iosu_ioctl.h\"\n\n#include \"Cafe/OS/libs/nn_common.h\"\n\n#include <algorithm>\n#include <mutex>\n\n#include \"openssl/evp.h\" /* EVP_Digest */\n#include \"openssl/sha.h\" /* SHA256_DIGEST_LENGTH */\n#include \"Cafe/Account/Account.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/helpers/helpers.h\"\n\n#include \"Cemu/napi/napi.h\"\n#include \"Cemu/ncrypto/ncrypto.h\"\n\n#include \"Cafe/IOSU/kernel/iosu_kernel.h\"\n#include \"Cafe/IOSU/nn/iosu_nn_service.h\"\n\nusing namespace iosu::kernel;\n\nusing NexToken = NAPI::ACTNexToken;\nstatic_assert(sizeof(NexToken) == 0x25C);\n\nstruct  \n{\n\tbool isInitialized;\n\tstd::mutex actMutex;\n}iosuAct = { };\n\n// account manager\n\nstruct actAccountData_t\n{\n\tbool isValid;\n\t// options\n\tbool isNetworkAccount;\n\tbool hasParseError; // set if any occurs while parsing account.dat\n\t// IDs\n\tuint8 uuid[16];\n\tuint32 persistentId;\n\tuint64 transferableIdBase;\n\tuint32 simpleAddressId;\n\tuint32 principalId;\n\t// NNID\n\tchar accountId[64];\n\tuint8 accountPasswordCache[32];\n\t// country & language\n\tuint32 countryIndex;\n\tchar country[8];\n\tchar timeZoneId[16];\n\tsint64 utcOffset;\n\t// Mii\n\tFFLData_t miiData;\n\tuint16le miiNickname[ACT_NICKNAME_LENGTH];\n\n\tbool IsNetworkAccount() const\n\t{\n\t\treturn isNetworkAccount; // todo - IOSU only checks if accountId is not empty?\n\t}\n};\n\n#define IOSU_ACT_ACCOUNT_MAX_COUNT (0xC)\n\nactAccountData_t _actAccountData[IOSU_ACT_ACCOUNT_MAX_COUNT] = {};\nbool _actAccountDataInitialized = false;\n\nvoid FillAccountData(const Account& account, const bool online_enabled, int index)\n{\n\tcemu_assert_debug(index < IOSU_ACT_ACCOUNT_MAX_COUNT);\n\tauto& data = _actAccountData[index];\n\tdata.isValid = true;\n\t// options\n\tdata.isNetworkAccount = account.IsValidOnlineAccount();\n\tdata.hasParseError = false;\n\t// IDs\n\tstd::copy(account.GetUuid().cbegin(), account.GetUuid().cend(), data.uuid);\n\tdata.persistentId = account.GetPersistentId();\n\tdata.transferableIdBase = account.GetTransferableIdBase();\n\tdata.simpleAddressId = account.GetSimpleAddressId();\n\tdata.principalId = account.GetPrincipalId();\n\t// NNID\n\tstd::copy(account.GetAccountId().begin(), account.GetAccountId().end(), data.accountId);\n\tstd::copy(account.GetAccountPasswordCache().begin(), account.GetAccountPasswordCache().end(), data.accountPasswordCache);\n\t// country & language\n\tdata.countryIndex = account.GetCountry();\n\tstrcpy(data.country, NCrypto::GetCountryAsString(data.countryIndex));\n\tstd::copy(account.GetTimeZoneId().cbegin(), account.GetTimeZoneId().cend(), data.timeZoneId);\n\tdata.utcOffset = account.GetUtcOffset() / 1'000'000;\n\t// Mii\n\tstd::copy(account.GetMiiData().begin(), account.GetMiiData().end(), (uint8*)&data.miiData);\n\tstd::copy(account.GetMiiName().begin(), account.GetMiiName().end(), data.miiNickname);\n\t\t\n\t// if online mode is disabled, make all accounts offline\n\tif(!online_enabled)\n\t{\n\t\tdata.isNetworkAccount = false;\n\t\tdata.principalId = 0;\n\t\tdata.simpleAddressId = 0;\n\t\tmemset(data.accountId, 0x00, sizeof(data.accountId));\n\t}\n}\n\nvoid iosuAct_loadAccounts()\n{\n\tif (_actAccountDataInitialized)\n\t\treturn;\n\n\tconst bool online_enabled = ActiveSettings::IsOnlineEnabled();\n\tconst auto persistent_id = ActiveSettings::GetPersistentId();\n\n\t// first account is always our selected one\n\tint counter = 0;\n\tconst auto& first_acc = Account::GetAccount(persistent_id);\n\tFillAccountData(first_acc, online_enabled, counter);\n\t++counter;\n\t// enable multiple accounts for cafe functions (badly tested)\n\t//for (const auto& account : Account::GetAccounts())\n\t//{\n\t//\tif (first_acc.GetPersistentId() != account.GetPersistentId())\n\t//\t{\n\t//\t\tFillAccountData(account, online_enabled, counter);\n\t//\t\t++counter;\n\t//\t}\n\t//}\n\n\tcemuLog_log(LogType::Force, \"IOSU_ACT: using account {} in first slot\", boost::nowide::narrow(first_acc.GetMiiName()));\n\t\n\t_actAccountDataInitialized = true;\n}\n\nbool iosuAct_isAccountDataLoaded()\n{\n\treturn _actAccountDataInitialized;\n}\n\nuint32 iosuAct_acquirePrincipalIdByAccountId(const char* nnid, uint32* pid)\n{\n\tNAPI::AuthInfo authInfo;\n\tNAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);\n\tNAPI::ACTConvertNnidToPrincipalIdResult result = NAPI::ACT_ACTConvertNnidToPrincipalId(authInfo, nnid);\n\tif (result.isValid() && result.isFound)\n\t{\n\t\t*pid = result.principalId;\n\t}\n\telse\n\t{\n\t\t*pid = 0;\n\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_ACT, 0); // what error should we return? The friend list app expects nn_act.AcquirePrincipalIdByAccountId to never return an error\n\t}\n\treturn 0;\n}\n\nsint32 iosuAct_getAccountIndexBySlot(uint8 slot)\n{\n\tif (slot == iosu::act::ACT_SLOT_CURRENT)\n\t\treturn 0;\n\tif (slot == 0xFF)\n\t\treturn 0; // ?\n\tcemu_assert_debug(slot != 0);\n\tcemu_assert_debug(slot <= IOSU_ACT_ACCOUNT_MAX_COUNT);\n\treturn slot - 1;\n}\n\nuint32 iosuAct_getAccountIdOfCurrentAccount()\n{\n\tcemu_assert_debug(_actAccountData[0].isValid);\n\treturn _actAccountData[0].persistentId;\n}\n\n// IOSU act API interface\n\nstatic const auto ACTResult_Ok = 0;\nstatic const auto ACTResult_InvalidValue = BUILD_NN_RESULT(NN_RESULT_LEVEL_LVL6, NN_RESULT_MODULE_NN_ACT, 0x12F00); // 0xC0712F00\nstatic const auto ACTResult_OutOfRange = BUILD_NN_RESULT(NN_RESULT_LEVEL_LVL6, NN_RESULT_MODULE_NN_ACT, 0x12D80); // 0xC0712D80\nstatic const auto ACTResult_AccountDoesNotExist = BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_ACT, NN_ACT_RESULT_ACCOUNT_DOES_NOT_EXIST); // 0xA071F480\nstatic const auto ACTResult_NotANetworkAccount = BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_ACT, 0x1FE80); // 0xA071FE80\n\nnnResult ServerActErrorCodeToNNResult(NAPI::ACT_ERROR_CODE ec)\n{\n\tswitch (ec)\n\t{\n\tcase (NAPI::ACT_ERROR_CODE)1:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2401);\n\tcase (NAPI::ACT_ERROR_CODE)2:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2402);\n\tcase (NAPI::ACT_ERROR_CODE)3:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2403);\n\tcase (NAPI::ACT_ERROR_CODE)4:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2458);\n\tcase (NAPI::ACT_ERROR_CODE)5:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2642);\n\tcase (NAPI::ACT_ERROR_CODE)6:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2641);\n\tcase (NAPI::ACT_ERROR_CODE)7:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2522);\n\tcase (NAPI::ACT_ERROR_CODE)8:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2534);\n\tcase (NAPI::ACT_ERROR_CODE)9:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2404);\n\tcase (NAPI::ACT_ERROR_CODE)10:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2451);\n\tcase (NAPI::ACT_ERROR_CODE)11:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2511);\n\tcase (NAPI::ACT_ERROR_CODE)12:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2812);\n\tcase (NAPI::ACT_ERROR_CODE)100:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2571);\n\tcase (NAPI::ACT_ERROR_CODE)101:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2572);\n\tcase (NAPI::ACT_ERROR_CODE)103:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2575);\n\tcase (NAPI::ACT_ERROR_CODE)104:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2452);\n\tcase (NAPI::ACT_ERROR_CODE)105:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2592);\n\tcase (NAPI::ACT_ERROR_CODE)106:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2611);\n\tcase (NAPI::ACT_ERROR_CODE)107:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2502);\n\tcase (NAPI::ACT_ERROR_CODE)108:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2802);\n\tcase (NAPI::ACT_ERROR_CODE)109:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2503);\n\tcase (NAPI::ACT_ERROR_CODE)110:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2501);\n\tcase (NAPI::ACT_ERROR_CODE)111:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2632);\n\tcase (NAPI::ACT_ERROR_CODE)112:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2631);\n\tcase (NAPI::ACT_ERROR_CODE)113:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2452);\n\tcase (NAPI::ACT_ERROR_CODE)114:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2593);\n\tcase (NAPI::ACT_ERROR_CODE)115:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2591);\n\tcase (NAPI::ACT_ERROR_CODE)116:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2614);\n\tcase (NAPI::ACT_ERROR_CODE)117:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2651);\n\tcase (NAPI::ACT_ERROR_CODE)118:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2484);\n\tcase (NAPI::ACT_ERROR_CODE)119:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2803);\n\tcase (NAPI::ACT_ERROR_CODE)120:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2813);\n\tcase (NAPI::ACT_ERROR_CODE)121:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2804);\n\tcase (NAPI::ACT_ERROR_CODE)122:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2814);\n\tcase (NAPI::ACT_ERROR_CODE)123:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2882);\n\tcase (NAPI::ACT_ERROR_CODE)124:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2512);\n\tcase (NAPI::ACT_ERROR_CODE)125:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2485);\n\tcase (NAPI::ACT_ERROR_CODE)126:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2805);\n\tcase (NAPI::ACT_ERROR_CODE)127:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2815);\n\tcase (NAPI::ACT_ERROR_CODE)128:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2661);\n\tcase (NAPI::ACT_ERROR_CODE)129:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2615);\n\tcase (NAPI::ACT_ERROR_CODE)130:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2531);\n\tcase (NAPI::ACT_ERROR_CODE)131:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2616);\n\tcase (NAPI::ACT_ERROR_CODE)132:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2822);\n\tcase (NAPI::ACT_ERROR_CODE)133:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2832);\n\tcase (NAPI::ACT_ERROR_CODE)134:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2823);\n\tcase (NAPI::ACT_ERROR_CODE)135:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2833);\n\tcase (NAPI::ACT_ERROR_CODE)136:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2824);\n\tcase (NAPI::ACT_ERROR_CODE)137:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2834);\n\tcase (NAPI::ACT_ERROR_CODE)138:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2825);\n\tcase (NAPI::ACT_ERROR_CODE)139:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2835);\n\tcase (NAPI::ACT_ERROR_CODE)142:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2635);\n\tcase (NAPI::ACT_ERROR_CODE)143:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2634);\n\tcase (NAPI::ACT_ERROR_CODE)1004:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2503);\n\tcase (NAPI::ACT_ERROR_CODE)1006:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2471);\n\tcase (NAPI::ACT_ERROR_CODE)1016:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2532);\n\tcase (NAPI::ACT_ERROR_CODE)1017:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2483);\n\tcase (NAPI::ACT_ERROR_CODE)1018:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2533);\n\tcase (NAPI::ACT_ERROR_CODE)1019:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2481);\n\tcase (NAPI::ACT_ERROR_CODE)1020:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2473);\n\tcase NAPI::ACT_ERROR_CODE::ACT_GAME_SERVER_NOT_FOUND:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2482);\n\tcase (NAPI::ACT_ERROR_CODE)1022:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2472);\n\tcase (NAPI::ACT_ERROR_CODE)1023:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2612);\n\tcase (NAPI::ACT_ERROR_CODE)1024:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2535);\n\tcase (NAPI::ACT_ERROR_CODE)1025:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2536);\n\tcase (NAPI::ACT_ERROR_CODE)1031:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2537);\n\tcase (NAPI::ACT_ERROR_CODE)1032:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2636);\n\tcase (NAPI::ACT_ERROR_CODE)1033:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2662);\n\tcase (NAPI::ACT_ERROR_CODE)1035:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2671);\n\tcase (NAPI::ACT_ERROR_CODE)1036:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2679);\n\tcase (NAPI::ACT_ERROR_CODE)1037:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2672);\n\tcase (NAPI::ACT_ERROR_CODE)1038:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2674);\n\tcase (NAPI::ACT_ERROR_CODE)1039:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2680);\n\tcase (NAPI::ACT_ERROR_CODE)1040:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2675);\n\tcase (NAPI::ACT_ERROR_CODE)1041:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2673);\n\tcase (NAPI::ACT_ERROR_CODE)1042:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2676);\n\tcase (NAPI::ACT_ERROR_CODE)1043:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2681);\n\tcase (NAPI::ACT_ERROR_CODE)1044:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2678);\n\tcase (NAPI::ACT_ERROR_CODE)1045:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2677);\n\tcase (NAPI::ACT_ERROR_CODE)1046:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2596);\n\tcase (NAPI::ACT_ERROR_CODE)1100:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2541);\n\tcase (NAPI::ACT_ERROR_CODE)1101:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2542);\n\tcase (NAPI::ACT_ERROR_CODE)1103:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2594);\n\tcase (NAPI::ACT_ERROR_CODE)1104:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2576);\n\tcase (NAPI::ACT_ERROR_CODE)1105:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2613);\n\tcase (NAPI::ACT_ERROR_CODE)1106:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2633);\n\tcase (NAPI::ACT_ERROR_CODE)1107:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2577);\n\tcase (NAPI::ACT_ERROR_CODE)1111:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2538);\n\tcase (NAPI::ACT_ERROR_CODE)1115:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2597);\n\tcase (NAPI::ACT_ERROR_CODE)1125:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2585);\n\tcase (NAPI::ACT_ERROR_CODE)1126:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2586);\n\tcase (NAPI::ACT_ERROR_CODE)1134:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2587);\n\tcase (NAPI::ACT_ERROR_CODE)1200:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2884);\n\tcase (NAPI::ACT_ERROR_CODE)2001:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2931);\n\tcase (NAPI::ACT_ERROR_CODE)2002:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2881);\n\tcase (NAPI::ACT_ERROR_CODE)2999:\n\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, (NN_ERROR_CODE)2883);\n\tdefault:\n\t\tbreak;\n\t}\n\tcemuLog_log(LogType::Force, \"Received unknown ACT error code {}\", (uint32)ec);\n\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, NN_ERROR_CODE::ACT_UNKNOWN_SERVER_ERROR);\n}\n\nnamespace iosu\n{\n\tnamespace act\n\t{\n\t\tuint8 getCurrentAccountSlot()\n\t\t{\n\t\t\treturn 1;\n\t\t}\n\n\t\tactAccountData_t* GetAccountBySlotNo(uint8 slotNo)\n\t\t{\n\t\t\t// only call this while holding actMutex\n\t\t\tuint8 accIndex;\n\t\t\tif(slotNo == iosu::act::ACT_SLOT_CURRENT)\n\t\t\t{\n\t\t\t\taccIndex = getCurrentAccountSlot() - 1;\n\t\t\t\tcemu_assert_debug(accIndex >= 0 && accIndex < IOSU_ACT_ACCOUNT_MAX_COUNT);\n\t\t\t}\n\t\t\telse if(slotNo > 0 && slotNo <= IOSU_ACT_ACCOUNT_MAX_COUNT)\n\t\t\t\taccIndex = slotNo - 1;\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t\tif(!_actAccountData[accIndex].isValid)\n\t\t\t\treturn nullptr;\n\t\t\treturn &_actAccountData[accIndex];\n\t\t}\n\n\t\t// has ownership of account data\n\t\t// while any thread has a LockedAccount in non-null state no other thread can access the account data\n\t\tclass LockedAccount\n\t\t{\n\t\t  public:\n\t\t\tLockedAccount(uint8 slotNo)\n\t\t\t{\n\t\t\t\tiosuAct.actMutex.lock();\n\t\t\t\tm_account = GetAccountBySlotNo(slotNo);\n\t\t\t\tif(!m_account)\n\t\t\t\t\tiosuAct.actMutex.unlock();\n\t\t\t}\n\n\t\t\t~LockedAccount()\n\t\t\t{\n\t\t\t\tif(m_account)\n\t\t\t\t\tiosuAct.actMutex.unlock();\n\t\t\t}\n\n\t\t\tvoid Release()\n\t\t\t{\n\t\t\t\tif(m_account)\n\t\t\t\t\tiosuAct.actMutex.unlock();\n\t\t\t\tm_account = nullptr;\n\t\t\t}\n\n\t\t\tactAccountData_t* operator->()\n\t\t\t{\n\t\t\t\treturn m_account;\n\t\t\t}\n\n\t\t\tactAccountData_t& operator*()\n\t\t\t{\n\t\t\t\treturn *m_account;\n\t\t\t}\n\n\t\t\tLockedAccount(const LockedAccount&) = delete;\n\t\t\tLockedAccount& operator=(const LockedAccount&) = delete;\n\n\t\t\toperator bool() const { return m_account != nullptr; }\n\n\t\t  private:\n\t\t\tactAccountData_t* m_account{nullptr};\n\t\t};\n\n\t\tbool getPrincipalId(uint8 slot, uint32* principalId)\n\t\t{\n\t\t\tsint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);\n\t\t\tif (_actAccountData[accountIndex].isValid == false)\n\t\t\t{\n\t\t\t\t*principalId = 0;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t*principalId = _actAccountData[accountIndex].principalId;\n\t\t\treturn true;\n\t\t}\n\n\t\tbool getAccountId(uint8 slot, char* accountId)\n\t\t{\n\t\t\tsint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);\n\t\t\tif (_actAccountData[accountIndex].isValid == false)\n\t\t\t{\n\t\t\t\t*accountId = '\\0';\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tstrcpy(accountId, _actAccountData[accountIndex].accountId);\n\t\t\treturn true;\n\t\t}\n\n\t\t// returns empty string if invalid\n\t\tstd::string getAccountId2(uint8 slot)\n\t\t{\n\t\t\tsint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);\n\t\t\tif (_actAccountData[accountIndex].isValid == false)\n\t\t\t\treturn {};\n\t\t\treturn {_actAccountData[accountIndex].accountId};\n\t\t}\n\n\t\tbool getMii(uint8 slot, FFLData_t* fflData)\n\t\t{\n\t\t\tsint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);\n\t\t\tif (_actAccountData[accountIndex].isValid == false)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tmemcpy(fflData, &_actAccountData[accountIndex].miiData, sizeof(FFLData_t));\n\t\t\treturn true;\n\t\t}\n\n\t\t// return screenname in little-endian wide characters\n\t\tbool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH])\n\t\t{\n\t\t\tsint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);\n\t\t\tif (_actAccountData[accountIndex].isValid == false)\n\t\t\t{\n\t\t\t\tscreenname[0] = '\\0';\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor (sint32 i = 0; i < ACT_NICKNAME_LENGTH; i++)\n\t\t\t{\n\t\t\t\tscreenname[i] = (uint16)_actAccountData[accountIndex].miiNickname[i];\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tbool getCountryIndex(uint8 slot, uint32* countryIndex)\n\t\t{\n\t\t\tsint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);\n\t\t\tif (_actAccountData[accountIndex].isValid == false)\n\t\t\t{\n\t\t\t\t*countryIndex = 0;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t*countryIndex = _actAccountData[accountIndex].countryIndex;\n\t\t\treturn true;\n\t\t}\n\n\t\tbool GetPersistentId(uint8 slot, uint32* persistentId)\n\t\t{\n\t\t\tsint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);\n\t\t\tif(!_actAccountData[accountIndex].isValid)\n\t\t\t{\n\t\t\t\t*persistentId = 0;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t*persistentId = _actAccountData[accountIndex].persistentId;\n\t\t\treturn true;\n\t\t}\n\n\t\tnnResult AcquireNexToken(uint8 accountSlot, uint64 titleId, uint16 titleVersion, uint32 serverId, uint8* tokenOut, uint32 tokenLen)\n\t\t{\n\t\t\tif (accountSlot != ACT_SLOT_CURRENT)\n\t\t\t\treturn ACTResult_InvalidValue;\n\t\t\tLockedAccount account(accountSlot);\n\t\t\tif (!account)\n\t\t\t\treturn ACTResult_AccountDoesNotExist;\n\t\t\tif (!account->IsNetworkAccount())\n\t\t\t\treturn ACTResult_NotANetworkAccount;\n\t\t\tcemu_assert_debug(ActiveSettings::IsOnlineEnabled());\n\t\t\tif (tokenLen != sizeof(NexToken))\n\t\t\t\treturn ACTResult_OutOfRange;\n\n\t\t\tNAPI::AuthInfo authInfo;\n\t\t\tNAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);\n\t\t\tNAPI::ACTGetNexTokenResult nexTokenResult = NAPI::ACT_GetNexToken_WithCache(authInfo, titleId, titleVersion, serverId);\n\t\t\tif (nexTokenResult.isValid())\n\t\t\t{\n\t\t\t\tmemcpy(tokenOut, &nexTokenResult.nexToken, sizeof(NexToken));\n\t\t\t\treturn ACTResult_Ok;\n\t\t\t}\n\t\t\telse if (nexTokenResult.apiError == NAPI_RESULT::SERVICE_ERROR)\n\t\t\t{\n\t\t\t\tnnResult returnCode = ServerActErrorCodeToNNResult(nexTokenResult.serviceError);\n\t\t\t\tcemu_assert_debug((returnCode&0x80000000) != 0);\n\t\t\t\treturn returnCode;\n\t\t\t}\n\t\t\treturn nnResultStatus(NN_RESULT_MODULE_NN_ACT, NN_ERROR_CODE::ACT_UNKNOWN_SERVER_ERROR);\n\t\t}\n\n\t\tnnResult AcquireIndependentServiceToken(uint8 accountSlot, uint64 titleId, uint16 titleVersion, std::string_view clientId, uint8* tokenOut, uint32 tokenLen)\n\t\t{\n\t\t\tstatic constexpr size_t IndependentTokenMaxLength = 512+1; // 512 bytes + null terminator\n\t\t\tif(accountSlot != ACT_SLOT_CURRENT)\n\t\t\t\treturn ACTResult_InvalidValue;\n\t\t\tLockedAccount account(accountSlot);\n\t\t\tif (!account)\n\t\t\t\treturn ACTResult_AccountDoesNotExist;\n\t\t\tif (!account->IsNetworkAccount())\n\t\t\t\treturn ACTResult_NotANetworkAccount;\n\t\t\tcemu_assert_debug(ActiveSettings::IsOnlineEnabled());\n\t\t\tif (tokenLen < IndependentTokenMaxLength)\n\t\t\t\treturn ACTResult_OutOfRange;\n\t\t\tNAPI::AuthInfo authInfo;\n\t\t\tNAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);\n\t\t\taccount.Release();\n\t\t\tNAPI::ACTGetIndependentTokenResult tokenResult = NAPI::ACT_GetIndependentToken_WithCache(authInfo, titleId, titleVersion, clientId);\n\t\t\tuint32 returnCode = 0;\n\t\t\tif (tokenResult.isValid())\n\t\t\t{\n\t\t\t\tfor (size_t i = 0; i < std::min(tokenResult.token.size(), (size_t)IndependentTokenMaxLength); i++)\n\t\t\t\t{\n\t\t\t\t\ttokenOut[i] = tokenResult.token[i];\n\t\t\t\t\ttokenOut[i + 1] = '\\0';\n\t\t\t\t}\n\t\t\t\treturnCode = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturnCode = 0x80000000; // todo - proper error codes\n\t\t\t}\n\t\t\treturn returnCode;\n\t\t}\n\n\t\tclass ActService : public iosu::nn::IPCService\n\t\t{\n\t\tpublic:\n\t\t\tActService() : iosu::nn::IPCService(\"/dev/act\") {}\n\n\t\t\tnnResult ServiceCall(IPCServiceCall& serviceCall) override\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Unsupported service call to /dev/act\");\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACT, 0);\n\t\t\t}\n\t\t};\n\n\t\tActService gActService;\n\n\t\tvoid Initialize()\n\t\t{\n\t\t\tgActService.Start();\n\t\t}\n\n\t\tvoid Stop()\n\t\t{\n\t\t\tgActService.Stop();\n\t\t}\n\t}\n}\n\n\n// IOSU act IO\n\ntypedef struct  \n{\n\t/* +0x00 */ uint32be ukn00;\n\t/* +0x04 */ uint32be ukn04;\n\t/* +0x08 */ uint32be ukn08;\n\t/* +0x0C */ uint32be subcommandCode;\n\t/* +0x10 */ uint8 ukn10;\n\t/* +0x11 */ uint8 ukn11;\n\t/* +0x12 */ uint8 ukn12;\n\t/* +0x13 */ uint8 accountSlot;\n\t/* +0x14 */ uint32be unique; // is this command specific?\n}cmdActRequest00_t;\n\ntypedef struct  \n{\n\tuint32be returnCode;\n\tuint8 transferableIdBase[8];\n}cmdActGetTransferableIDResult_t;\n\n#define ACT_SUBCMD_GET_TRANSFERABLE_ID\t\t4\n#define ACT_SUBCMD_INITIALIZE\t\t\t\t0x14\n\n#define _cancelIfAccountDoesNotExist() \\\nif (_actAccountData[accountIndex].isValid == false) \\\n{ \\\n\t/* account does not exist*/  \\\n\tioctlReturnValue = 0; \\\n\tactCemuRequest->setACTReturnCode(BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_ACT, NN_ACT_RESULT_ACCOUNT_DOES_NOT_EXIST)); /* 0xA071F480 */ \\\n\tactCemuRequest->resultU64.u64 = 0; \\\n\tiosuIoctl_completeRequest(ioQueueEntry, ioctlReturnValue); \\\n\tcontinue; \\\n}\n\nint iosuAct_thread()\n{\n\tSetThreadName(\"iosuAct_thread\");\n\twhile (true)\n\t{\n\t\tuint32 ioctlReturnValue = 0;\n\t\tioQueueEntry_t* ioQueueEntry = iosuIoctl_getNextWithWait(IOS_DEVICE_ACT);\n\t\tif (ioQueueEntry->request == 0)\n\t\t{\n\t\t\tif (ioQueueEntry->countIn != 1 || ioQueueEntry->countOut != 1)\n\t\t\t{\n\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t\tioBufferVector_t* vectorsDebug = ioQueueEntry->bufferVectors.GetPtr();\n\n\t\t\tvoid* outputBuffer = ioQueueEntry->bufferVectors[0].buffer.GetPtr();\n\t\t\tcmdActRequest00_t* requestCmd = (cmdActRequest00_t*)ioQueueEntry->bufferVectors[0].unknownBuffer.GetPtr();\n\t\t\tif (requestCmd->subcommandCode == ACT_SUBCMD_INITIALIZE)\n\t\t\t{\n\t\t\t\t// do nothing for now (there is no result?)\n\t\t\t}\n\t\t\telse if (requestCmd->subcommandCode == ACT_SUBCMD_GET_TRANSFERABLE_ID)\n\t\t\t{\n\t\t\t\tcmdActGetTransferableIDResult_t* cmdResult = (cmdActGetTransferableIDResult_t*)outputBuffer;\n\t\t\t\tcmdResult->returnCode = 0;\n\t\t\t\t*(uint64*)cmdResult->transferableIdBase = _swapEndianU64(0x1122334455667788);\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t}\n\t\telse if (ioQueueEntry->request == IOSU_ACT_REQUEST_CEMU)\n\t\t{\n\t\t\tiosuActCemuRequest_t* actCemuRequest = (iosuActCemuRequest_t*)ioQueueEntry->bufferVectors[0].buffer.GetPtr();\n\t\t\tsint32 accountIndex;\n\t\t\tioctlReturnValue = 0;\n\t\t\tif (actCemuRequest->requestCode == IOSU_ARC_ACCOUNT_ID)\n\t\t\t{\n\t\t\t\taccountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);\n\t\t\t\t_cancelIfAccountDoesNotExist();\n\t\t\t\tstrcpy(actCemuRequest->resultString.strBuffer, _actAccountData[accountIndex].accountId);\n\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_UUID)\n\t\t\t{\n\t\t\t\taccountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);\n\t\t\t\tif (actCemuRequest->accountSlot == 0xFF)\n\t\t\t\t{\n\t\t\t\t\t// common uuid (placeholder algorithm)\n\t\t\t\t\tfor (uint32 i = 0; i < 16; i++)\n\t\t\t\t\t\tactCemuRequest->resultBinary.binBuffer[i] = i * 0x74 + i + ~i + i * 133;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_cancelIfAccountDoesNotExist();\n\t\t\t\t\tmemcpy(actCemuRequest->resultBinary.binBuffer, _actAccountData[accountIndex].uuid, 16);\n\t\t\t\t}\n\n\t\t\t\tcemu_assert_debug(actCemuRequest->uuidName != -1); // todo\n\t\t\t\tif (actCemuRequest->uuidName != -1 && actCemuRequest->uuidName != -2)\n\t\t\t\t{\n\t\t\t\t\t// generate name based UUID\n\t\t\t\t\t// format:\n\t\t\t\t\t// first 10 bytes of UUID + 6 bytes of a hash\n\t\t\t\t\t// hash algorithm:\n\t\t\t\t\t// sha256 of\n\t\t\t\t\t//   4 bytes uuidName (big-endian)\n\t\t\t\t\t//   4 bytes 0x3A275E09 (big-endian)\n\t\t\t\t\t//   6 bytes from the end of UUID\n\t\t\t\t\t// bytes 10-15 are used from the hash and replace the last 6 bytes of the UUID\n\n\t\t\t\t\tEVP_MD_CTX *ctx_sha256 = EVP_MD_CTX_new();\n\t\t\t\t\tEVP_DigestInit(ctx_sha256, EVP_sha256());\n\n\t\t\t\t\tuint32 name = (uint32)actCemuRequest->uuidName;\n\t\t\t\t\tuint8 tempArray[] = {\n\t\t\t\t\t\tstatic_cast<uint8>((name >> 24) & 0xFF),\n\t\t\t\t\t\tstatic_cast<uint8>((name >> 16) & 0xFF),\n\t\t\t\t\t\tstatic_cast<uint8>((name >> 8) & 0xFF),\n\t\t\t\t\t\tstatic_cast<uint8>((name >> 0) & 0xFF),\n\t\t\t\t\t\t0x3A,\n\t\t\t\t\t\t0x27,\n\t\t\t\t\t\t0x5E,\n\t\t\t\t\t\t0x09,\n\t\t\t\t\t};\n\t\t\t\t\tEVP_DigestUpdate(ctx_sha256, tempArray, sizeof(tempArray));\n\t\t\t\t\tEVP_DigestUpdate(ctx_sha256, actCemuRequest->resultBinary.binBuffer+10, 6);\n\t\t\t\t\tuint8 h[SHA256_DIGEST_LENGTH];\n\t\t\t\t\tEVP_DigestFinal_ex(ctx_sha256, h, NULL);\n\t\t\t\t\tEVP_MD_CTX_free(ctx_sha256);\n\n\t\t\t\t\tmemcpy(actCemuRequest->resultBinary.binBuffer + 0xA, h + 0xA, 6);\n\t\t\t\t}\n\t\t\t\telse if (actCemuRequest->uuidName == -2)\n\t\t\t\t{\n\t\t\t\t\t// return account uuid\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"Gen UUID unknown mode {}\", actCemuRequest->uuidName);\n\t\t\t\t}\n\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_SIMPLEADDRESS)\n\t\t\t{\n\t\t\t\taccountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);\n\t\t\t\t_cancelIfAccountDoesNotExist();\n\t\t\t\tactCemuRequest->resultU32.u32 = _actAccountData[accountIndex].simpleAddressId;\n\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_PRINCIPALID)\n\t\t\t{\n\t\t\t\taccountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);\n\t\t\t\t_cancelIfAccountDoesNotExist();\n\t\t\t\tactCemuRequest->resultU32.u32 = _actAccountData[accountIndex].principalId;\n\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_TRANSFERABLEID)\n\t\t\t{\n\t\t\t\taccountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);\n\t\t\t\t_cancelIfAccountDoesNotExist();\n\t\t\t\tactCemuRequest->resultU64.u64 = _actAccountData[accountIndex].transferableIdBase;\n\t\t\t\t// todo - transferable also contains a unique id\n\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_PERSISTENTID)\n\t\t\t{\n\t\t\t\tif(actCemuRequest->accountSlot != 0)\n\t\t\t\t{\n\t\t\t\t\taccountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);\n\t\t\t\t\t_cancelIfAccountDoesNotExist();\n\t\t\t\t\tactCemuRequest->resultU32.u32 = _actAccountData[accountIndex].persistentId;\n\t\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// F1 Race Stars calls IsSlotOccupied and indirectly GetPersistentId on slot 0 which is not valid\n\t\t\t\t\tactCemuRequest->resultU32.u32 = 0;\n\t\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_COUNTRY)\n\t\t\t{\n\t\t\t\taccountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);\n\t\t\t\t_cancelIfAccountDoesNotExist();\n\t\t\t\tstrcpy(actCemuRequest->resultString.strBuffer, _actAccountData[accountIndex].country);\n\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_TIMEZONEID)\n\t\t\t{\n\t\t\t\taccountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);\n\t\t\t\t_cancelIfAccountDoesNotExist();\n\t\t\t\tstrcpy(actCemuRequest->resultString.strBuffer, _actAccountData[accountIndex].timeZoneId);\n\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_ISNETWORKACCOUNT)\n\t\t\t{\n\t\t\t\taccountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);\n\t\t\t\t_cancelIfAccountDoesNotExist();\n\t\t\t\tactCemuRequest->resultU32.u32 = _actAccountData[accountIndex].isNetworkAccount;\n\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_ACQUIRENEXTOKEN)\n\t\t\t{\n\t\t\t\tnnResult r = iosu::act::AcquireNexToken(actCemuRequest->accountSlot, actCemuRequest->titleId, actCemuRequest->titleVersion, actCemuRequest->serverId, actCemuRequest->resultBinary.binBuffer, sizeof(NexToken));\n\t\t\t\tactCemuRequest->setACTReturnCode(r);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_ACQUIREINDEPENDENTTOKEN)\n\t\t\t{\n\t\t\t\tnnResult r = iosu::act::AcquireIndependentServiceToken(actCemuRequest->accountSlot, actCemuRequest->titleId, actCemuRequest->titleVersion, actCemuRequest->clientId, actCemuRequest->resultBinary.binBuffer, sizeof(actCemuRequest->resultBinary.binBuffer));\n\t\t\t\tactCemuRequest->setACTReturnCode(r);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_ACQUIREPIDBYNNID)\n\t\t\t{\t\t\t\t\n\t\t\t\tuint32 returnCode = iosuAct_acquirePrincipalIdByAccountId(actCemuRequest->clientId, &actCemuRequest->resultU32.u32);\n\t\t\t\tactCemuRequest->setACTReturnCode(returnCode);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_MIIDATA)\n\t\t\t{\n\n\t\t\t\taccountIndex = iosuAct_getAccountIndexBySlot(actCemuRequest->accountSlot);\n\t\t\t\t_cancelIfAccountDoesNotExist();\n\t\t\t\tmemcpy(actCemuRequest->resultBinary.binBuffer, &_actAccountData[accountIndex].miiData, sizeof(FFLData_t));\n\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t}\n\t\t\telse if (actCemuRequest->requestCode == IOSU_ARC_INIT)\n\t\t\t{\n\t\t\t\tiosuAct_loadAccounts();\n\t\t\t\tactCemuRequest->setACTReturnCode(0);\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t\tiosuIoctl_completeRequest(ioQueueEntry, ioctlReturnValue);\n\t}\n\treturn 0;\n}\n\nvoid iosuAct_init_depr()\n{\n\tif (iosuAct.isInitialized)\n\t\treturn;\n\tstd::thread t(iosuAct_thread);\n\tt.detach();\n\tiosuAct.isInitialized = true;\n}\n\nbool iosuAct_isInitialized()\n{\n\treturn iosuAct.isInitialized;\n}\n\nuint16 FFLCalculateCRC16(uint8* input, sint32 length)\n{\n\tuint16 crc = 0;\n\tfor (sint32 c = 0; c < length; c++)\n\t{\n\t\tfor (sint32 f = 0; f < 8; f++)\n\t\t{\n\t\t\tif ((crc & 0x8000) != 0)\n\t\t\t{\n\t\t\t\tuint16 t = crc << 1;\n\t\t\t\tcrc = t ^ 0x1021;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcrc <<= 1;\n\t\t\t}\n\t\t}\n\t\tcrc ^= (uint16)input[c];\n\t}\n\treturn crc;\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_act.h",
    "content": "#pragma once\n\nvoid iosuAct_init_depr();\nbool iosuAct_isInitialized();\n\n#define ACT_ACCOUNTID_LENGTH \t(17) // includes '\\0'\n\n// Mii\n\n#define MII_FFL_STORAGE_SIZE\t(96)\n\n#define MII_FFL_NAME_LENGTH\t\t(10) // counted in wchar_t elements (16-bit unicode)\n\n#define ACT_NICKNAME_LENGTH\t(10) // aka Mii nickname\n#define ACT_NICKNAME_SIZE\t(11)\n\ntypedef struct  \n{\n\tuint32be high;\n\tuint32be low;\n}FFLDataID_t;\n\ntypedef struct  \n{\n\t/* +0x00 */ uint32\t\tuknFlags;\n\t/* +0x04 */ FFLDataID_t miiId; // bytes 8 and 9 are part of the CRC? (miiId is based on account transferable id?)\n\t/* +0x0C */ uint8\t\tukn0C[0xA];\n\t/* +0x16 */ uint8\t\tukn16[2];\n\t/* +0x18 */ uint16\t\tukn18;\n\t/* +0x1A */ uint16le\tmiiName[MII_FFL_NAME_LENGTH];\n\t/* +0x2E */ uint16\t\tukn2E;\n\t/* +0x30 */ uint8\t\tukn30[MII_FFL_STORAGE_SIZE-0x30];\n}FFLData_t;\n\nstatic_assert(sizeof(FFLData_t) == MII_FFL_STORAGE_SIZE, \"FFLData_t size invalid\");\nstatic_assert(offsetof(FFLData_t, miiId) == 0x04, \"FFLData->miiId offset invalid\");\nstatic_assert(offsetof(FFLData_t, miiName) == 0x1A, \"FFLData->miiName offset invalid\");\nstatic_assert(offsetof(FFLData_t, ukn2E) == 0x2E, \"FFLData->ukn2E offset invalid\");\n\nstatic uint16 FFLCalculateCRC16(uint8* input, sint32 length);\n\nnamespace iosu\n{\n\tnamespace act\n\t{\n\t\tuint8 getCurrentAccountSlot();\n\t\tbool getPrincipalId(uint8 slot, uint32* principalId);\n\t\tbool getAccountId(uint8 slot, char* accountId);\n\t\tbool getMii(uint8 slot, FFLData_t* fflData);\n\t\tbool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH]);\n\t\tbool getCountryIndex(uint8 slot, uint32* countryIndex);\n\t\tbool GetPersistentId(uint8 slot, uint32* persistentId);\n\n\t\tstd::string getAccountId2(uint8 slot);\n\n\t\tstatic constexpr uint8 ACT_SLOT_CURRENT = 0xFE;\n\n\t\tvoid Initialize();\n\t\tvoid Stop();\n\t}\n}\n\n// custom dev/act/ protocol (Cemu only)\n#define IOSU_ACT_REQUEST_CEMU (0xEE)\n\nstruct iosuActCemuRequest_t\n{\n\tuint32 requestCode;\n\t// input\n\tuint8 accountSlot;\n\tuint32 unique;\n\tsint32 uuidName;\n\tuint64 titleId;\n\tuint32 titleVersion;\n\tuint32 serverId;\n\tchar clientId[64];\n\tuint32 expiresIn;\n\t// output\n\tuint32 returnCode;\n\tunion\n\t{\n\t\tstruct\n\t\t{\n\t\t\tuint64 u64;\n\t\t}resultU64;\n\t\tstruct\n\t\t{\n\t\t\tuint32 u32;\n\t\t}resultU32;\n\t\tstruct\n\t\t{\n\t\t\tchar strBuffer[1024];\n\t\t}resultString;\n\t\tstruct  \n\t\t{\n\t\t\tuint8 binBuffer[1024];\n\t\t}resultBinary;\n\t};\n\n\tvoid setACTReturnCode(uint32 code)\n\t{\n\t\treturnCode = code;\n\t}\n};\n\n// Act Request Cemu subcodes\n#define IOSU_ARC_INIT\t\t\t\t\t0x00\n#define IOSU_ARC_ACCOUNT_ID\t\t\t\t0x01\n#define IOSU_ARC_TRANSFERABLEID\t\t\t0x02\n#define IOSU_ARC_PERSISTENTID\t\t\t0x03\n#define IOSU_ARC_UUID\t\t\t\t\t0x04\n#define IOSU_ARC_SIMPLEADDRESS\t\t\t0x05\n#define IOSU_ARC_PRINCIPALID\t\t\t0x06\n#define IOSU_ARC_COUNTRY\t\t\t\t0x07\n#define IOSU_ARC_ISNETWORKACCOUNT\t\t0x08\n#define IOSU_ARC_ACQUIRENEXTOKEN\t\t0x09\n#define IOSU_ARC_MIIDATA\t\t\t\t0x0A\n#define IOSU_ARC_ACQUIREINDEPENDENTTOKEN 0x0B\n#define IOSU_ARC_ACQUIREPIDBYNNID\t\t0x0C\n#define IOSU_ARC_TIMEZONEID\t\t\t\t0x0D\n\nuint32 iosuAct_getAccountIdOfCurrentAccount();\n\nbool iosuAct_isAccountDataLoaded();"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_crypto.cpp",
    "content": "#include \"iosu_crypto.h\"\n\n#include \"config/ActiveSettings.h\"\n#include \"openssl/bn.h\"\n#include \"openssl/obj_mac.h\"\n#include \"openssl/ec.h\"\n#include \"openssl/x509.h\"\n#include \"openssl/ssl.h\"\n#include \"openssl/ecdsa.h\"\n\n#include \"util/crypto/aes128.h\"\n#include \"Common/FileStream.h\"\n\nuint8 otpMem[1024];\nbool hasOtpMem = false;\n\nuint8 seepromMem[512];\nbool hasSeepromMem = false;\n\nstruct  \n{\n\tbool hasCertificates;\n\tstruct  \n\t{\n\t\tbool isValid;\n\t\tsint32 id;\n\t\tX509* cert;\n\t\tstd::vector<uint8> certData;\n\t\tRSA* pkey;\n\t\tstd::vector<uint8> pkeyDERData;\n\t}certList[256];\n\tsint32 certListCount;\n}iosuCryptoCertificates = { 0 };\n\nCertECC_t g_wiiuDeviceCert;\n\nvoid iosuCrypto_readOtpData(void* output, sint32 wordIndex, sint32 size)\n{\n\tmemcpy(output, otpMem + wordIndex * 4, size);\n}\n\nvoid iosuCrypto_readOtpData(uint32be& output, sint32 wordIndex)\n{\n\tmemcpy(&output, otpMem + wordIndex * 4, sizeof(uint32be));\n}\n\nvoid iosuCrypto_readSeepromData(void* output, sint32 wordIndex, sint32 size)\n{\n\tmemcpy(output, seepromMem + wordIndex * 2, size);\n}\n\nbool iosuCrypto_getDeviceId(uint32* deviceId)\n{\n\tuint32be deviceIdBE;\n\t*deviceId = 0;\n\tif (!hasOtpMem)\n\t\treturn false;\n\tiosuCrypto_readOtpData(&deviceIdBE, 0x87, sizeof(uint32));\n\t*deviceId = (uint32)deviceIdBE;\n\treturn true;\n}\n\nvoid iosuCrypto_getDeviceSerialString(char* serialString)\n{\n\tchar serialStringPart0[32]; // code\n\tchar serialStringPart1[32]; // serial\n\tif (hasSeepromMem == false)\n\t{\n\t\tstrcpy(serialString, \"FEH000000000\");\n\t\treturn;\n\t}\n\tmemset(serialStringPart0, 0, sizeof(serialStringPart0));\n\tmemset(serialStringPart1, 0, sizeof(serialStringPart1));\n\tiosuCrypto_readSeepromData(serialStringPart0, 0xAC, 8);\n\tiosuCrypto_readSeepromData(serialStringPart1, 0xB0, 0x10);\n\tsprintf(serialString, \"%s%s\", serialStringPart0, serialStringPart1);\n}\n\nstatic const char* base64_charset =\n\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\"abcdefghijklmnopqrstuvwxyz\"\n\"0123456789+/\";\n\nint iosuCrypto_base64Encode(unsigned char const* bytes_to_encode, unsigned int inputLen, char* output)\n{\n\tint i = 0;\n\tint j = 0;\n\tunsigned char charArray_3[3];\n\tunsigned char charArray_4[4];\n\tsint32 outputLength = 0;\n\twhile (inputLen--)\n\t{\n\t\tcharArray_3[i++] = *(bytes_to_encode++);\n\t\tif (i == 3)\n\t\t{\n\t\t\tcharArray_4[0] = (charArray_3[0] & 0xfc) >> 2;\n\t\t\tcharArray_4[1] = ((charArray_3[0] & 0x03) << 4) + ((charArray_3[1] & 0xf0) >> 4);\n\t\t\tcharArray_4[2] = ((charArray_3[1] & 0x0f) << 2) + ((charArray_3[2] & 0xc0) >> 6);\n\t\t\tcharArray_4[3] = charArray_3[2] & 0x3f;\n\t\t\tfor (i = 0; (i < 4); i++)\n\t\t\t{\n\t\t\t\toutput[outputLength] = base64_charset[charArray_4[i]];\n\t\t\t\toutputLength++;\n\t\t\t}\n\t\t\ti = 0;\n\t\t}\n\t}\n\tif (i)\n\t{\n\t\tfor (j = i; j < 3; j++)\n\t\t\tcharArray_3[j] = '\\0';\n\n\t\tcharArray_4[0] = (charArray_3[0] & 0xfc) >> 2;\n\t\tcharArray_4[1] = ((charArray_3[0] & 0x03) << 4) + ((charArray_3[1] & 0xf0) >> 4);\n\t\tcharArray_4[2] = ((charArray_3[1] & 0x0f) << 2) + ((charArray_3[2] & 0xc0) >> 6);\n\t\tcharArray_4[3] = charArray_3[2] & 0x3f;\n\n\t\tfor (j = 0; j < (i + 1); j++)\n\t\t{\n\t\t\toutput[outputLength] = base64_charset[charArray_4[j]];\n\t\t\toutputLength++;\n\t\t}\n\t\twhile (i++ < 3)\n\t\t{\n\t\t\toutput[outputLength] = '=';\n\t\t\toutputLength++;\n\t\t}\n\t}\n\treturn outputLength;\n}\n\nstd::string iosuCrypto_base64Encode(unsigned char const* bytes_to_encode, unsigned int inputLen)\n{\n\tint encodedLen = inputLen / 3 * 4 + 16;\n\tstd::string strB64;\n\tstrB64.resize(encodedLen);\n\tint outputLen = iosuCrypto_base64Encode(bytes_to_encode, inputLen, strB64.data());\n\tcemu_assert_debug(outputLen < strB64.size());\n\tstrB64.resize(outputLen);\n\treturn strB64;\n}\nstatic_assert(sizeof(CertECC_t) == sizeof(CertECC_t));\n\nEC_KEY* ECCPubKey_getPublicKey(ECCPubKey& pubKey) // verified and works\n{\n\tBIGNUM* bn_r = BN_new();\n\tBIGNUM* bn_s = BN_new();\n\tBN_bin2bn(pubKey.keyData + 0, 30, bn_r);\n\tBN_bin2bn(pubKey.keyData + 30, 30, bn_s);\n\n\tEC_KEY* ec_pubKey = EC_KEY_new_by_curve_name(NID_sect233r1);\n\tint r = EC_KEY_set_public_key_affine_coordinates(ec_pubKey, bn_r, bn_s);\n\n\tBN_free(bn_r);\n\tBN_free(bn_s);\n\n\treturn ec_pubKey;\n}\n\nECDSA_SIG* ECCPubKey_getSignature(CertECC_t& cert)\n{\n\tBIGNUM* bn_r = BN_new();\n\tBIGNUM* bn_s = BN_new();\n\tBN_bin2bn(cert.signature + 0, 30, bn_r);\n\tBN_bin2bn(cert.signature + 30, 30, bn_s);\n\n\t//EC_KEY* ec_pubKey = EC_KEY_new_by_curve_name(NID_sect233r1);\n\t//int r = EC_KEY_set_public_key_affine_coordinates(ec_pubKey, bn_r, bn_s);\n\tECDSA_SIG* ec_sig = ECDSA_SIG_new();\n\t//ECDSA_do_sign_ex\n#if OPENSSL_VERSION_NUMBER >= 0x10100000L\n\tECDSA_SIG_set0(ec_sig, bn_r, bn_s);\n#else\n\tBN_copy(ec_sig->r, bn_r);\n\tBN_copy(ec_sig->s, bn_s);\n#endif\n\n\tBN_free(bn_r);\n\tBN_free(bn_s);\n\n\treturn ec_sig;\n}\n\nvoid ECCPubKey_setSignature(CertECC_t& cert, ECDSA_SIG* sig)\n{\n#if OPENSSL_VERSION_NUMBER >= 0x10100000L\n\tconst BIGNUM* sig_r = nullptr, * sig_s = nullptr;\n\tECDSA_SIG_get0(sig, &sig_r, &sig_s);\n\n\tsint32 lenR = BN_num_bytes(sig_r);\n\tsint32 lenS = BN_num_bytes(sig_s);\n\n\tcemu_assert_debug(lenR <= 30);\n\tcemu_assert_debug(lenS <= 30);\n\n\tmemset(cert.signature, 0, sizeof(cert.signature));\n\tBN_bn2bin(sig_r, cert.signature + (30 - lenR));\n\tBN_bn2bin(sig_s, cert.signature + 60 / 2 + (30 - lenS));\n#else\n\tsint32 lenR = BN_num_bytes(sig->r);\n\tsint32 lenS = BN_num_bytes(sig->s);\n\n\tcemu_assert_debug(lenR <= 30);\n\tcemu_assert_debug(lenS <= 30);\n\n\tmemset(cert.signature, 0, sizeof(cert.signature));\n\tBN_bn2bin(sig->r, cert.signature + (30 - lenR));\n\tBN_bn2bin(sig->s, cert.signature + 60 / 2 + (30 - lenS));\n#endif\n}\n\nECCPrivKey g_consoleCertPrivKey{};\n\nvoid iosuCrypto_getDeviceCertPrivateKey(void* privKeyOut, sint32 len)\n{\n\tcemu_assert(len == 30);\n\tmemcpy(privKeyOut, g_consoleCertPrivKey.keyData, 30);\n}\n\nvoid iosuCrypto_getDeviceCertificate(void* certOut, sint32 len)\n{\n\tcemu_assert(len == 0x180);\n\tmemcpy(certOut, &g_wiiuDeviceCert, 0x180);\n}\n\nvoid iosuCrypto_generateDeviceCertificate()\n{\n\tstatic_assert(sizeof(g_wiiuDeviceCert) == 0x180);\n\tmemset(&g_wiiuDeviceCert, 0, sizeof(g_wiiuDeviceCert));\n\tif (!hasOtpMem)\n\t\treturn; // cant generate certificate without OPT\n\n\t// set header based on otp security mode\n\tg_wiiuDeviceCert.sigType = CertECC_t::SIGTYPE::ECC_SHA256;\n\n\tg_wiiuDeviceCert.ukn0C0[0] = 0x00;\n\tg_wiiuDeviceCert.ukn0C0[1] = 0x00;\n\tg_wiiuDeviceCert.ukn0C0[2] = 0x00;\n\tg_wiiuDeviceCert.ukn0C0[3] = 0x02;\n\n\n\tiosuCrypto_readOtpData(g_wiiuDeviceCert.signature, 0xA3, 0x3C);\n\n\tuint32be caValue;\n\tiosuCrypto_readOtpData(caValue, 0xA1);\n\tuint32be msValue;\n\tiosuCrypto_readOtpData(msValue, 0xA0);\n\n\tsprintf(g_wiiuDeviceCert.certificateSubject, \"Root-CA%08x-MS%08x\", (uint32)caValue, (uint32)msValue);\n\n\tuint32be ngNameValue;\n\tiosuCrypto_readOtpData(ngNameValue, 0x87);\n\tsprintf(g_wiiuDeviceCert.ngName, \"NG%08x\", (uint32)ngNameValue);\n\n\tiosuCrypto_readOtpData(&g_wiiuDeviceCert.ngKeyId, 0xA2, sizeof(uint32));\n\n\n\tuint8 privateKey[0x20];\n\tmemset(privateKey, 0, sizeof(privateKey));\n\tiosuCrypto_readOtpData(privateKey, 0x88, 0x1E);\n\tmemcpy(g_consoleCertPrivKey.keyData, privateKey, 30);\n\n\tauto context = BN_CTX_new();\n\tBN_CTX_start(context);\n\tBIGNUM* bn_privKey = BN_CTX_get(context);\n\tBN_bin2bn(privateKey, 0x1E, bn_privKey);\n\n\tEC_GROUP *group = EC_GROUP_new_by_curve_name(NID_sect233r1);\n\tEC_POINT *pubkey = EC_POINT_new(group);\n\n\tEC_POINT_mul(group, pubkey, bn_privKey, NULL, NULL, NULL);\n\n\tBIGNUM* bn_x = BN_CTX_get(context);\n\tBIGNUM* bn_y = BN_CTX_get(context);\t\n\n\tEC_POINT_get_affine_coordinates(group, pubkey, bn_x, bn_y, NULL);\n\n\tuint8 publicKeyOutput[0x3C];\n\tmemset(publicKeyOutput, 0, sizeof(publicKeyOutput));\n\n\tsint32 lenX = BN_num_bytes(bn_x);\n\tsint32 lenY = BN_num_bytes(bn_y);\n\n\tBN_bn2bin(bn_x, publicKeyOutput + (0x1E - lenX)); // todo - verify if the bias is correct\n\tBN_bn2bin(bn_y, publicKeyOutput + 0x3C / 2 + (0x1E - lenY));\n\n\tmemcpy(g_wiiuDeviceCert.publicKey, publicKeyOutput, 0x3C);\n\n\t// clean up\n\tEC_POINT_free(pubkey);\n\tBN_CTX_end(context); // clears all BN variables\n\tBN_CTX_free(context);\n}\n\nsint32 iosuCrypto_getDeviceCertificateBase64Encoded(char* output)\n{\n\tiosuCrypto_base64Encode((uint8*)&g_wiiuDeviceCert, sizeof(g_wiiuDeviceCert), output);\n\tsint32 len = sizeof(g_wiiuDeviceCert) / 3 * 4;\n\toutput[len] = '\\0';\n\treturn len;\n}\n\nbool iosuCrypto_loadCertificate(uint32 id, std::wstring_view mlcSubpath, std::wstring_view pkeyMlcSubpath)\n{\n\tX509* cert = nullptr;\n\t// load cert data\n\tconst auto certPath = ActiveSettings::GetMlcPath(mlcSubpath);\n\tauto certData = FileStream::LoadIntoMemory(certPath);\n\tif (!certData)\n\t\treturn false; // file missing\n\t// get optional aes encrypted private key data\n\tstd::optional<std::vector<uint8>> pkeyData;\n\tif (!pkeyMlcSubpath.empty())\n\t{\n\t\tconst auto pkeyPath = ActiveSettings::GetMlcPath(pkeyMlcSubpath);\n\t\tpkeyData = FileStream::LoadIntoMemory(pkeyPath);\n\t\tif (!pkeyData || pkeyData->empty())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Unable to load private key file {}\", pkeyPath.generic_string());\n\t\t\treturn false;\n\t\t}\n\t\telse if ((pkeyData->size() % 16) != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Private key file has invalid length. Possibly corrupted? File: {}\", pkeyPath.generic_string());\n\t\t\treturn false;\n\t\t}\n\t}\n\t// load certificate\n\tunsigned char* tempPtr = (unsigned char*)certData->data();\n\tcert = d2i_X509(nullptr, (const unsigned char**)&tempPtr, certData->size());\n\tif (cert == nullptr)\n\t{\n\t\tcemuLog_log(LogType::Force, \"IOSU_CRYPTO: Unable to load certificate \\\"{}\\\"\", boost::nowide::narrow(std::wstring(mlcSubpath)));\n\t\treturn false;\n\t}\n\t// load optional rsa key\n\tRSA* pkeyRSA = nullptr;\n\tif (pkeyData)\n\t{\n\t\tcemu_assert((pkeyData->size() & 15) == 0);\n\t\tuint8 aesKey[16];\n\t\tuint8 iv[16] = { 0 };\n\t\tuint8 pkeyDecryptedData[4096];\n\t\t// decrypt pkey\n\t\tiosuCrypto_readOtpData(aesKey, 0x120 / 4, 16);\n\t\tAES128_CBC_decrypt(pkeyDecryptedData, pkeyData->data(), pkeyData->size(), aesKey, iv);\n\t\t// convert to OpenSSL RSA pkey\n\t\tunsigned char* pkeyTempPtr = pkeyDecryptedData;\n\t\tpkeyRSA = d2i_RSAPrivateKey(nullptr, (const unsigned char **)&pkeyTempPtr, pkeyData->size());\n\t\tif (pkeyRSA == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IOSU_CRYPTO: Unable to decrypt private key \\\"{}\\\"\", boost::nowide::narrow(std::wstring(pkeyMlcSubpath)));\n\t\t\treturn false;\n\t\t}\n\t\t// encode private key as DER\n\t\tEVP_PKEY *evpPkey = EVP_PKEY_new();\n\t\tEVP_PKEY_assign_RSA(evpPkey, pkeyRSA);\n\t\tstd::vector<uint8> derPKeyData(1024 * 32);\n\t\tunsigned char* derPkeyTemp = derPKeyData.data();\n\t\tsint32 derPkeySize = i2d_PrivateKey(evpPkey, &derPkeyTemp);\n\t\tderPKeyData.resize(derPkeySize);\n\t\tderPKeyData.shrink_to_fit();\n\t\tiosuCryptoCertificates.certList[iosuCryptoCertificates.certListCount].pkeyDERData = derPKeyData;\n\t}\n\n\t// register certificate and optional pkey\n\tiosuCryptoCertificates.certList[iosuCryptoCertificates.certListCount].cert = cert;\n\tiosuCryptoCertificates.certList[iosuCryptoCertificates.certListCount].certData = *certData;\n\tiosuCryptoCertificates.certList[iosuCryptoCertificates.certListCount].pkey = pkeyRSA;\n\tiosuCryptoCertificates.certList[iosuCryptoCertificates.certListCount].id = id;\n\tiosuCryptoCertificates.certList[iosuCryptoCertificates.certListCount].isValid = true;\n\tiosuCryptoCertificates.certListCount++;\n\treturn true;\n}\n\nbool iosuCrypto_addClientCertificate(void* sslctx, sint32 certificateId)\n{\n\tSSL_CTX* ctx = (SSL_CTX*)sslctx;\n\t// find entry\n\tfor (sint32 i = 0; i < iosuCryptoCertificates.certListCount; i++)\n\t{\n\t\tif (iosuCryptoCertificates.certList[i].isValid && iosuCryptoCertificates.certList[i].id == certificateId)\n\t\t{\n\t\t\tif (SSL_CTX_use_certificate(ctx, iosuCryptoCertificates.certList[i].cert) != 1)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Unable to setup certificate {}\", certificateId);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (SSL_CTX_use_RSAPrivateKey(ctx, iosuCryptoCertificates.certList[i].pkey) != 1)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Unable to setup certificate {} RSA private key\", certificateId);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (SSL_CTX_check_private_key(ctx) == false)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Certificate private key could not be validated (verify required files for online mode or disable online mode)\");\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t}\n\tcemuLog_log(LogType::Force, \"Certificate not found (verify required files for online mode or disable online mode)\");\n\treturn false;\n}\n\nbool iosuCrypto_addCACertificate(void* sslctx, sint32 certificateId)\n{\n\tSSL_CTX* ctx = (SSL_CTX*)sslctx;\n\t// find entry\n\tfor (sint32 i = 0; i < iosuCryptoCertificates.certListCount; i++)\n\t{\n\t\tif (iosuCryptoCertificates.certList[i].isValid && iosuCryptoCertificates.certList[i].id == certificateId)\n\t\t{\n\t\t\tX509_STORE* store = SSL_CTX_get_cert_store((SSL_CTX*)sslctx);\n\t\t\tX509_STORE_add_cert(store, iosuCryptoCertificates.certList[i].cert);\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nbool iosuCrypto_addCustomCACertificate(void* sslctx, uint8* certData, sint32 certLength)\n{\n\tSSL_CTX* ctx = (SSL_CTX*)sslctx;\n\tX509_STORE* store = SSL_CTX_get_cert_store((SSL_CTX*)sslctx);\n\tunsigned char* tempPtr = (unsigned char*)certData;\n\tX509* cert = d2i_X509(NULL, (const unsigned char**)&tempPtr, certLength);\n\tif (cert == nullptr)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Invalid custom server PKI certificate\");\n\t\treturn false;\n\t}\n\tX509_STORE_add_cert(store, cert);\n\treturn true;\n}\n\nuint8* iosuCrypto_getCertificateDataById(sint32 certificateId, sint32* certificateSize)\n{\n\tfor (sint32 i = 0; i < iosuCryptoCertificates.certListCount; i++)\n\t{\n\t\tif (iosuCryptoCertificates.certList[i].isValid && iosuCryptoCertificates.certList[i].id == certificateId)\n\t\t{\n\t\t\t*certificateSize = iosuCryptoCertificates.certList[i].certData.size();\n\t\t\treturn iosuCryptoCertificates.certList[i].certData.data();\n\t\t}\n\t}\n\treturn nullptr;\n}\n\nuint8* iosuCrypto_getCertificatePrivateKeyById(sint32 certificateId, sint32* certificateSize)\n{\n\tfor (sint32 i = 0; i < iosuCryptoCertificates.certListCount; i++)\n\t{\n\t\tif (iosuCryptoCertificates.certList[i].isValid && iosuCryptoCertificates.certList[i].id == certificateId)\n\t\t{\n\t\t\t*certificateSize = iosuCryptoCertificates.certList[i].pkeyDERData.size();\n\t\t\treturn iosuCryptoCertificates.certList[i].pkeyDERData.data();\n\t\t}\n\t}\n\treturn nullptr;\n}\n\nstruct\n{\n\tconst int id;\n\tconst wchar_t name[256];\n\tconst wchar_t key[256];\n} const g_certificates[] = {\n\t// NINTENDO CLIENT CERTS\n\t{ 1, L\"ccerts/WIIU_COMMON_1_CERT.der\", L\"ccerts/WIIU_COMMON_1_RSA_KEY.aes\" },\n\t{ 3, L\"ccerts/WIIU_ACCOUNT_1_CERT.der\", L\"ccerts/WIIU_ACCOUNT_1_RSA_KEY.aes\" },\n\t{ 4, L\"ccerts/WIIU_OLIVE_1_CERT.der\", L\"ccerts/WIIU_OLIVE_1_RSA_KEY.aes\" },\n\t{ 5, L\"ccerts/WIIU_VINO_1_CERT.der\", L\"ccerts/WIIU_VINO_1_RSA_KEY.aes\" },\n\t{ 6, L\"ccerts/WIIU_WOOD_1_CERT.der\", L\"ccerts/WIIU_WOOD_1_RSA_KEY.aes\" },\n\t{ 7, L\"ccerts/WIIU_OLIVE_1_CERT.der\", L\"ccerts/WIIU_OLIVE_1_RSA_KEY.aes\" },\n\t{ 8, L\"ccerts/WIIU_WOOD_1_CERT.der\", L\"ccerts/WIIU_WOOD_1_RSA_KEY.aes\" },\n\n\t// NINTENDO CA CERTS\n\t{ 100, L\"scerts/CACERT_NINTENDO_CA.der\", L\"\" },\n\t{ 101, L\"scerts/CACERT_NINTENDO_CA_G2.der\", L\"\" },\n\t{ 102, L\"scerts/CACERT_NINTENDO_CA_G3.der\", L\"\" },\n\t{ 103, L\"scerts/CACERT_NINTENDO_CLASS2_CA.der\", L\"\" },\n\t{ 104, L\"scerts/CACERT_NINTENDO_CLASS2_CA_G2.der\", L\"\" },\n\t{ 105, L\"scerts/CACERT_NINTENDO_CLASS2_CA_G3.der\", L\"\" },\n\n\t// COMMERCIAL CA CERTS\n\t{ 1001, L\"scerts/BALTIMORE_CYBERTRUST_ROOT_CA.der\", L\"\" },\n\t{ 1002, L\"scerts/CYBERTRUST_GLOBAL_ROOT_CA.der\", L\"\" },\n\t{ 1003, L\"scerts/VERIZON_GLOBAL_ROOT_CA.der\", L\"\" },\n\t{ 1004, L\"scerts/GLOBALSIGN_ROOT_CA.der\", L\"\" },\n\t{ 1005, L\"scerts/GLOBALSIGN_ROOT_CA_R2.der\", L\"\" },\n\t{ 1006, L\"scerts/GLOBALSIGN_ROOT_CA_R3.der\", L\"\" },\n\t{ 1007, L\"scerts/VERISIGN_CLASS3_PUBLIC_PRIMARY_CA_G3.der\", L\"\" },\n\t{ 1008, L\"scerts/VERISIGN_UNIVERSAL_ROOT_CA.der\", L\"\" },\n\t{ 1009, L\"scerts/VERISIGN_CLASS3_PUBLIC_PRIMARY_CA_G5.der\", L\"\" },\n\t{ 1010, L\"scerts/THAWTE_PRIMARY_ROOT_CA_G3.der\", L\"\" },\n\t{ 1011, L\"scerts/THAWTE_PRIMARY_ROOT_CA.der\", L\"\" },\n\t{ 1012, L\"scerts/GEOTRUST_GLOBAL_CA.der\", L\"\" },\n\t{ 1013, L\"scerts/GEOTRUST_GLOBAL_CA2.der\", L\"\" },\n\t{ 1014, L\"scerts/GEOTRUST_PRIMARY_CA.der\", L\"\" },\n\t{ 1015, L\"scerts/GEOTRUST_PRIMARY_CA_G3.der\", L\"\" },\n\t{ 1016, L\"scerts/ADDTRUST_EXT_CA_ROOT.der\", L\"\" },\n\t{ 1017, L\"scerts/COMODO_CA.der\", L\"\" },\n\t{ 1018, L\"scerts/UTN_DATACORP_SGC_CA.der\", L\"\" },\n\t{ 1019, L\"scerts/UTN_USERFIRST_HARDWARE_CA.der\" , L\"\" },\n\t{ 1020, L\"scerts/DIGICERT_HIGH_ASSURANCE_EV_ROOT_CA.der\", L\"\" },\n\t{ 1021, L\"scerts/DIGICERT_ASSURED_ID_ROOT_CA.der\", L\"\" },\n\t{ 1022, L\"scerts/DIGICERT_GLOBAL_ROOT_CA.der\", L\"\" },\n\t{ 1023, L\"scerts/GTE_CYBERTRUST_GLOBAL_ROOT.der\", L\"\" },\n\t{ 1024, L\"scerts/VERISIGN_CLASS3_PUBLIC_PRIMARY_CA.der\", L\"\" },\n\t{ 1025, L\"scerts/THAWTE_PREMIUM_SERVER_CA.der\", L\"\" },\n\t{ 1026, L\"scerts/EQUIFAX_SECURE_CA.der\", L\"\" },\n\t{ 1027, L\"scerts/ENTRUST_SECURE_SERVER_CA.der\", L\"\" },\n\t{ 1028, L\"scerts/VERISIGN_CLASS3_PUBLIC_PRIMARY_CA_G2.der\", L\"\" },\n\t{ 1029, L\"scerts/ENTRUST_CA_2048.der\", L\"\" },\n\t{ 1030, L\"scerts/ENTRUST_ROOT_CA.der\", L\"\" },\n\t{ 1031, L\"scerts/ENTRUST_ROOT_CA_G2.der\", L\"\" },\n\t{ 1032, L\"scerts/DIGICERT_ASSURED_ID_ROOT_CA_G2.der\", L\"\" },\n\t{ 1033, L\"scerts/DIGICERT_GLOBAL_ROOT_CA_G2.der\", L\"\" },\n};\n\nvoid iosuCrypto_loadSSLCertificates()\n{\n\tif (iosuCryptoCertificates.hasCertificates)\n\t\treturn;\n\n\tif (!hasOtpMem)\n\t\treturn; // cant load certificates without OTP keys\n\n\t// load CA certificate\n\tbool hasAllCertificates = true;\n\tfor( const auto& c : g_certificates )\n\t{\n\t\tstd::wstring certDir = L\"sys/title/0005001b/10054000/content/\";\n\t\tstd::wstring certFilePath = certDir + c.name;\n\t\tstd::wstring keyFilePath;\t\t\n\n\t\tif( *c.key )\n\t\t\tkeyFilePath = certDir + c.key;\n\t\telse\n\t\t\tkeyFilePath.clear();\n\n\t\tif (iosuCrypto_loadCertificate(c.id, certFilePath, keyFilePath) == false)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Unable to load certificate \\\"{}\\\"\", boost::nowide::narrow(certFilePath));\n\t\t\thasAllCertificates = false;\n\t\t}\n\t}\n\tiosuCryptoCertificates.hasCertificates = hasAllCertificates; // true\n}\n\nvoid iosuCrypto_init()\n{\n\t// load OTP dump\n\tif (std::ifstream otp_file(ActiveSettings::GetUserDataPath(\"otp.bin\"), std::ifstream::in | std::ios::binary); otp_file.is_open())\n\t{\n\t\totp_file.seekg(0, std::ifstream::end);\n\t\tconst auto length = otp_file.tellg();\n\t\totp_file.seekg(0, std::ifstream::beg);\n\t\t// verify if OTP is ok\n\t\tif (length != 1024) // todo - should also check some fixed values to verify integrity of otp dump\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IOSU_CRYPTO: otp.bin has wrong size (must be 1024 bytes)\");\n\t\t\thasOtpMem = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\totp_file.read((char*)otpMem, 1024);\n\t\t\thasOtpMem = (bool)otp_file;\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"IOSU_CRYPTO: No otp.bin found. Online mode cannot be used\");\n\t\thasOtpMem = false;\n\t}\n\n\tif (std::ifstream seeprom_file(ActiveSettings::GetUserDataPath(\"seeprom.bin\"), std::ifstream::in | std::ios::binary); seeprom_file.is_open())\n\t{\n\t\tseeprom_file.seekg(0, std::ifstream::end);\n\t\tconst auto length = seeprom_file.tellg();\n\t\tseeprom_file.seekg(0, std::ifstream::beg);\n\t\t// verify if seeprom is ok\n\t\tif (length != 512) // todo - maybe check some known values to verify integrity of seeprom\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IOSU_CRYPTO: seeprom.bin has wrong size (must be 512 bytes)\");\n\t\t\thasSeepromMem = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tseeprom_file.read((char*)seepromMem, 512);\n\t\t\thasSeepromMem = (bool)seeprom_file;\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"IOSU_CRYPTO: No Seeprom.bin found. Online mode cannot be used\");\n\t\thasSeepromMem = false;\n\t}\n\t\n\t// generate device certificate\n\tiosuCrypto_generateDeviceCertificate();\n\t// load SSL certificates\n\tiosuCrypto_loadSSLCertificates();\n}\n\nbool iosuCrypto_checkRequirementMLCFile(std::string_view mlcSubpath, std::string& additionalErrorInfo_filePath)\n{\n\tconst auto path = ActiveSettings::GetMlcPath(mlcSubpath);\n\tadditionalErrorInfo_filePath = _pathToUtf8(path);\n\tsint32 fileDataSize = 0;\n\tauto fileData = FileStream::LoadIntoMemory(path);\n\tif (!fileData)\n\t\treturn false;\n\treturn true;\n}\n\nsint32 iosuCrypt_checkRequirementsForOnlineMode(std::string& additionalErrorInfo)\n{\n\tstd::error_code ec;\n\t// check if otp.bin is present\n\tconst auto otp_file = ActiveSettings::GetUserDataPath(\"otp.bin\");\n\tif(!fs::exists(otp_file, ec))\n\t\treturn IOS_CRYPTO_ONLINE_REQ_OTP_MISSING;\n\tif(fs::file_size(otp_file, ec) != 1024)\n\t\treturn IOS_CRYPTO_ONLINE_REQ_OTP_CORRUPTED;\n\t// check if seeprom.bin is present\n\tconst auto seeprom_file = ActiveSettings::GetUserDataPath(\"seeprom.bin\");\n\tif (!fs::exists(seeprom_file, ec))\n\t\treturn IOS_CRYPTO_ONLINE_REQ_SEEPROM_MISSING;\n\tif (fs::file_size(seeprom_file, ec) != 512)\n\t\treturn IOS_CRYPTO_ONLINE_REQ_SEEPROM_CORRUPTED;\n\t\n\tfor (const auto& c : g_certificates)\n\t{\n\t\tstd::string subPath = fmt::format(\"sys/title/0005001b/10054000/content/{}\", boost::nowide::narrow(c.name));\n\t\tif (iosuCrypto_checkRequirementMLCFile(subPath, additionalErrorInfo) == false)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Missing dumped file for online mode: {}\", subPath);\n\t\t\treturn IOS_CRYPTO_ONLINE_REQ_MISSING_FILE;\n\t\t}\n\n\t\tif (*c.key)\n\t\t{\n\t\t\tstd::string subPath = fmt::format(\"sys/title/0005001b/10054000/content/{}\", boost::nowide::narrow(c.key));\n\t\t\tif (iosuCrypto_checkRequirementMLCFile(subPath, additionalErrorInfo) == false)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Missing dumped file for online mode: {}\", subPath);\n\t\t\t\treturn IOS_CRYPTO_ONLINE_REQ_MISSING_FILE;\n\t\t\t}\n\t\t}\n\t}\n\treturn IOS_CRYPTO_ONLINE_REQ_OK;\n}\n\nstd::vector<const wchar_t*> iosuCrypt_getCertificateKeys()\n{\n\tstd::vector<const wchar_t*> result;\n\tresult.reserve(std::size(g_certificates));\n\tfor (const auto& c : g_certificates)\n\t{\n\t\tif (c.key[0] == '\\0')\n\t\t\tcontinue;\n\t\t\n\t\tresult.emplace_back(c.key);\n\t}\n\treturn result;\n}\n\nstd::vector<const wchar_t*> iosuCrypt_getCertificateNames()\n{\n\tstd::vector<const wchar_t*> result;\n\tresult.reserve(std::size(g_certificates));\n\tfor (const auto& c : g_certificates)\n\t{\n\t\tresult.emplace_back(c.name);\n\t}\n\treturn result;\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_crypto.h",
    "content": "#pragma once\n\nvoid iosuCrypto_init();\n\nbool iosuCrypto_getDeviceId(uint32* deviceId);\nvoid iosuCrypto_getDeviceSerialString(char* serialString);\n\n// certificate API\n\nstruct ECCPrivKey\n{\n\tuint8 keyData[30];\n};\n\nstruct ECCPubKey\n{\n\tuint8 keyData[60];\n};\n\nstruct ECCSig\n{\n\tuint8 keyData[60]; // check size?\n};\n\nstruct CHash256\n{\n\tuint8 b[32];\n};\n\nstruct CertECC_t\n{\n\tenum class SIGTYPE : uint32\n\t{\n\t\tECC_SHA256 = 0x00010005\n\t};\n\n\t/* +0x000 */ betype<SIGTYPE>\tsigType; // 01 00 02 00\n\t/* +0x004 */ uint8\t\t\t\tsignature[0x3C]; // from OTP 0xA3*4\n\t/* +0x040 */ uint8\t\t\t\tukn040[0x40]; // seems to be just padding\n\t/* +0x080 */ char\t\t\t\tcertificateSubject[0x40]; // \"Root - CA%08x - MS%08x\" \n\t/* +0x0C0 */ char\t\t\t\tukn0C0[0x4]; // ??? 00 00 00 02 ?\n\t/* +0x0C4 */ char\t\t\t\tngName[0x40]; // \"NG%08X\"\n\t/* +0x104 */ uint32\t\t\t\tngKeyId; // big endian? (from OTP 0xA2*4)\n\t/* +0x108 */ uint8\t\t\t\tpublicKey[0x3C];\n\t/* +0x144 */ uint8\t\t\t\tpadding[0x180 - 0x144];\n\n\t\n};\n\nstatic_assert(sizeof(CertECC_t) == 0x180);\n\nsint32 iosuCrypto_getDeviceCertificateBase64Encoded(char* output);\nbool iosuCrypto_verifyCert(CertECC_t& cert);\n\nstd::string iosuCrypto_base64Encode(unsigned char const* bytes_to_encode, unsigned int inputLen);\n\n// certificate store\nbool iosuCrypto_addClientCertificate(void* sslctx, sint32 certificateId);\nbool iosuCrypto_addCACertificate(void* sslctx, sint32 certificateId);\nbool iosuCrypto_addCustomCACertificate(void* sslctx, uint8* certData, sint32 certLength);\n\nuint8* iosuCrypto_getCertificateDataById(sint32 certificateId, sint32* certificateSize);\nuint8* iosuCrypto_getCertificatePrivateKeyById(sint32 certificateId, sint32* certificateSize);\n\n// helper for online functionality\nenum\n{\n\tIOS_CRYPTO_ONLINE_REQ_OK,\n\tIOS_CRYPTO_ONLINE_REQ_OTP_MISSING,\n\tIOS_CRYPTO_ONLINE_REQ_OTP_CORRUPTED,\n\tIOS_CRYPTO_ONLINE_REQ_SEEPROM_MISSING,\n\tIOS_CRYPTO_ONLINE_REQ_SEEPROM_CORRUPTED,\n\tIOS_CRYPTO_ONLINE_REQ_MISSING_FILE\n};\n\nsint32 iosuCrypt_checkRequirementsForOnlineMode(std::string& additionalErrorInfo);\nvoid iosuCrypto_readOtpData(void* output, sint32 wordIndex, sint32 size);\n\nstd::vector<const wchar_t*> iosuCrypt_getCertificateKeys();\nstd::vector<const wchar_t*> iosuCrypt_getCertificateNames();"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_fpd.cpp",
    "content": "#include \"iosu_act.h\"\n#include \"iosu_fpd.h\"\n#include \"Cemu/nex/nex.h\"\n#include \"Cemu/nex/nexFriends.h\"\n#include \"util/helpers/helpers.h\"\n#include \"config/CemuConfig.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cemu/napi/napi.h\"\n#include \"util/helpers/StringHelpers.h\"\n#include \"Cafe/IOSU/iosu_types_common.h\"\n#include \"Cafe/IOSU/nn/iosu_nn_service.h\"\n\n#include \"Common/CafeString.h\"\n\nstd::mutex g_friend_notification_mutex;\nstd::vector< std::pair<std::string, int> > g_friend_notifications;\n\nnamespace iosu\n{\n\tnamespace fpd\n\t{\n\t\tusing NotificationRunningId = uint64;\n\n\t\tstruct NotificationEntry\n\t\t{\n\t\t\tNotificationEntry(uint64 index, NexFriends::NOTIFICATION_TYPE type, uint32 pid) : timestamp(std::chrono::steady_clock::now()), runningId(index), type(type), pid(pid) {}\n\t\t\tstd::chrono::steady_clock::time_point timestamp;\n\t\t\tNotificationRunningId runningId;\n\t\t\tNexFriends::NOTIFICATION_TYPE type;\n\t\t\tuint32 pid;\n\t\t};\n\n\t\tclass\n\t\t{\n\t\t  public:\n\t\t\tvoid TrackNotification(NexFriends::NOTIFICATION_TYPE type, uint32 pid)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(m_mtxNotificationQueue);\n\t\t\t\tm_notificationQueue.emplace_back(m_notificationQueueIndex++, type, pid);\n\t\t\t}\n\n\t\t\tvoid RemoveExpired()\n\t\t\t{\n\t\t\t\t// remove entries older than 10 seconds\n\t\t\t\tstd::chrono::steady_clock::time_point expireTime = std::chrono::steady_clock::now() - std::chrono::seconds(10);\n\t\t\t\tstd::erase_if(m_notificationQueue, [expireTime](const auto& notification) {\n\t\t\t\t\treturn notification.timestamp < expireTime;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tstd::optional<NotificationEntry> GetNextNotification(NotificationRunningId& previousRunningId)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(m_mtxNotificationQueue);\n\t\t\t\tauto it = std::lower_bound(m_notificationQueue.begin(), m_notificationQueue.end(), previousRunningId, [](const auto& notification, const auto& runningId) {\n\t\t\t\t\treturn notification.runningId <= runningId;\n\t\t\t\t});\n\t\t\t\tsize_t itIndex = it - m_notificationQueue.begin();\n\t\t\t\tif(it == m_notificationQueue.end())\n\t\t\t\t\treturn std::nullopt;\n\t\t\t\tpreviousRunningId = it->runningId;\n\t\t\t\treturn *it;\n\t\t\t}\n\n\t\t  private:\n\t\t\tstd::vector<NotificationEntry> m_notificationQueue;\n\t\t\tstd::mutex m_mtxNotificationQueue;\n\t\t\tstd::atomic_uint64_t m_notificationQueueIndex{1};\n\t\t}g_NotificationQueue;\n\n\t\tstruct  \n\t\t{\n\t\t\tbool isThreadStarted;\n\t\t\tbool isInitialized2;\n\t\t\tNexFriends* nexFriendSession;\n\t\t\tstd::mutex mtxFriendSession;\n\t\t\t// session state\n\t\t\tstd::atomic_bool sessionStarted{false};\n\t\t\t// current state\n\t\t\tnexPresenceV2 myPresence;\n\t\t}g_fpd = {};\n\n\t\tvoid OverlayNotificationHandler(NexFriends::NOTIFICATION_TYPE type, uint32 pid)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Friends::Notification {:02x} pid {:08x}\", type, pid);\n\t\t\tif(!GetConfig().notification.friends)\n\t\t\t\treturn;\n\t\t\tstd::unique_lock lock(g_friend_notification_mutex);\n\t\t\tstd::string message;\n\t\t\tif(type == NexFriends::NOTIFICATION_TYPE::NOTIFICATION_TYPE_ONLINE)\n\t\t\t{\n\t\t\t\tg_friend_notifications.emplace_back(\"Connected to friend service\", 5000);\n\t\t\t\tif(g_fpd.nexFriendSession && g_fpd.nexFriendSession->getPendingFriendRequestCount() > 0)\n\t\t\t\t\tg_friend_notifications.emplace_back(fmt::format(\"You have {} pending friend request(s)\", g_fpd.nexFriendSession->getPendingFriendRequestCount()), 5000);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::string msg_format;\n\t\t\t\tswitch(type)\n\t\t\t\t{\n\t\t\t\tcase NexFriends::NOTIFICATION_TYPE_ONLINE: break;\n\t\t\t\tcase NexFriends::NOTIFICATION_TYPE_FRIEND_LOGIN: msg_format = \"{} is now online\"; break;\n\t\t\t\tcase NexFriends::NOTIFICATION_TYPE_FRIEND_LOGOFF: msg_format = \"{} is now offline\"; break;\n\t\t\t\tcase NexFriends::NOTIFICATION_TYPE_FRIEND_PRESENCE_CHANGE: break;\n\t\t\t\tcase NexFriends::NOTIFICATION_TYPE_ADDED_FRIEND: msg_format = \"{} has been added to your friend list\"; break;\n\t\t\t\tcase NexFriends::NOTIFICATION_TYPE_REMOVED_FRIEND: msg_format = \"{} has been removed from your friend list\"; break;\n\t\t\t\tcase NexFriends::NOTIFICATION_TYPE_ADDED_OUTGOING_REQUEST: break;\n\t\t\t\tcase NexFriends::NOTIFICATION_TYPE_REMOVED_OUTGOING_REQUEST: break;\n\t\t\t\tcase NexFriends::NOTIFICATION_TYPE_ADDED_INCOMING_REQUEST: msg_format = \"{} wants to add you to his friend list\"; break;\n\t\t\t\tcase NexFriends::NOTIFICATION_TYPE_REMOVED_INCOMING_REQUEST: break;\n\t\t\t\tdefault: ;\n\t\t\t\t}\n\t\t\t\tif (!msg_format.empty())\n\t\t\t\t{\n\t\t\t\t\tstd::string name = fmt::format(\"{:#x}\", pid);\n\t\t\t\t\tif (g_fpd.nexFriendSession)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst std::string tmp = g_fpd.nexFriendSession->getAccountNameByPid(pid);\n\t\t\t\t\t\tif (!tmp.empty())\n\t\t\t\t\t\t\tname = tmp;\n\t\t\t\t\t}\n\t\t\t\t\tg_friend_notifications.emplace_back(fmt::format(fmt::runtime(msg_format), name), 5000);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid NotificationHandler(NexFriends::NOTIFICATION_TYPE type, uint32 pid)\n\t\t{\n\t\t\tOverlayNotificationHandler(type, pid);\n\t\t\tg_NotificationQueue.TrackNotification(type, pid);\n\t\t}\n\n\t\tvoid convertMultiByteStringToBigEndianWidechar(const char* input, uint16be* output, sint32 maxOutputLength)\n\t\t{\n\t\t\tstd::vector<uint16be> beStr = StringHelpers::FromUtf8(input);\n\t\t\tif (beStr.size() >= maxOutputLength - 1)\n\t\t\t\tbeStr.resize(maxOutputLength-1);\n\t\t\tfor (size_t i = 0; i < beStr.size(); i++)\n\t\t\t\toutput[i] = beStr[i];\n\t\t\toutput[beStr.size()] = '\\0';\n\t\t}\n\n\t\tvoid convertFPDTimestampToDate(uint64 timestamp, FPDDate* fpdDate)\n\t\t{\n\t\t\t// if the timestamp is zero then still return a valid date\n\t\t\tif (timestamp == 0)\n\t\t\t{\n\t\t\t\tfpdDate->second = 0;\n\t\t\t\tfpdDate->minute = 0;\n\t\t\t\tfpdDate->hour = 0;\n\t\t\t\tfpdDate->day = 1;\n\t\t\t\tfpdDate->month = 1;\n\t\t\t\tfpdDate->year = 1970;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfpdDate->second = (uint8)((timestamp) & 0x3F);\n\t\t\tfpdDate->minute = (uint8)((timestamp >> 6) & 0x3F);\n\t\t\tfpdDate->hour = (uint8)((timestamp >> 12) & 0x1F);\n\t\t\tfpdDate->day = (uint8)((timestamp >> 17) & 0x1F);\n\t\t\tfpdDate->month = (uint8)((timestamp >> 22) & 0xF);\n\t\t\tfpdDate->year = (uint16)((timestamp >> 26));\n\t\t}\n\n\t\tuint64 convertDateToFPDTimestamp(FPDDate* fpdDate)\n\t\t{\n\t\t\tuint64 t = 0;\n\t\t\tt |= (uint64)fpdDate->second;\n\t\t\tt |= ((uint64)fpdDate->minute<<6);\n\t\t\tt |= ((uint64)fpdDate->hour<<12);\n\t\t\tt |= ((uint64)fpdDate->day<<17);\n\t\t\tt |= ((uint64)fpdDate->month<<22);\n\t\t\tt |= ((uint64)(uint16)fpdDate->year<<26);\n\t\t\treturn t;\n\t\t}\n\n\t\tvoid NexPresenceToGameMode(const nexPresenceV2* presence, GameMode* gameMode)\n\t\t{\n\t\t\tmemset(gameMode, 0, sizeof(GameMode));\n\t\t\tgameMode->joinFlagMask = presence->joinFlagMask;\n\t\t\tgameMode->matchmakeType = presence->joinAvailability;\n\t\t\tgameMode->joinGameId = presence->gameId;\n\t\t\tgameMode->joinGameMode = presence->gameMode;\n\t\t\tgameMode->hostPid = presence->hostPid;\n\t\t\tgameMode->groupId = presence->groupId;\n\t\t\tmemcpy(gameMode->appSpecificData, presence->appSpecificData, 0x14);\n\t\t}\n\n\t\tvoid GameModeToNexPresence(const GameMode* gameMode, nexPresenceV2* presence)\n\t\t{\n\t\t\t*presence = {};\n\t\t\tpresence->joinFlagMask = gameMode->joinFlagMask;\n\t\t\tpresence->joinAvailability = (uint8)(uint32)gameMode->matchmakeType;\n\t\t\tpresence->gameId = gameMode->joinGameId;\n\t\t\tpresence->gameMode = gameMode->joinGameMode;\n\t\t\tpresence->hostPid = gameMode->hostPid;\n\t\t\tpresence->groupId = gameMode->groupId;\n\t\t\tmemcpy(presence->appSpecificData, gameMode->appSpecificData, 0x14);\n\t\t}\n\n\t\tvoid NexFriendToFPDFriendData(const nexFriend* frd, FriendData* friendData)\n\t\t{\n\t\t\tmemset(friendData, 0, sizeof(FriendData));\n\t\t\t// setup friend data\n\t\t\tfriendData->type = 1; // friend\n\t\t\tfriendData->pid = frd->nnaInfo.principalInfo.principalId;\n\t\t\tmemcpy(friendData->mii, frd->nnaInfo.principalInfo.mii.miiData, FFL_SIZE);\n\t\t\tstrcpy((char*)friendData->nnid, frd->nnaInfo.principalInfo.nnid);\n\t\t\t// screenname\n\t\t\tconvertMultiByteStringToBigEndianWidechar(frd->nnaInfo.principalInfo.mii.miiNickname, friendData->screenname, sizeof(friendData->screenname) / sizeof(uint16be));\n\n\t\t\tfriendData->friendExtraData.isOnline = frd->presence.isOnline != 0 ? 1 : 0;\n\n\t\t\tfriendData->friendExtraData.gameKey.titleId = frd->presence.gameKey.titleId;\n\t\t\tfriendData->friendExtraData.gameKey.ukn08 = frd->presence.gameKey.ukn;\n\t\t\tNexPresenceToGameMode(&frd->presence, &friendData->friendExtraData.gameMode);\n\n\t\t\tauto fixed_presence_msg = '\\0' + frd->presence.msg; // avoid first character of comment from being cut off\n\t\t\tfriendData->friendExtraData.gameModeDescription.assignFromUTF8(fixed_presence_msg);\n\t\t\t\n\t\t\tauto fixed_comment = '\\0' + frd->comment.commentString; // avoid first character of comment from being cut off\n\t\t\tfriendData->friendExtraData.comment.assignFromUTF8(fixed_comment);\n\t\t\t\n\t\t\t// set valid dates\n\t\t\tfriendData->uknDate.year = 2018;\n\t\t\tfriendData->uknDate.day = 1;\n\t\t\tfriendData->uknDate.month = 1;\n\t\t\tfriendData->uknDate.hour = 1;\n\t\t\tfriendData->uknDate.minute = 1;\n\t\t\tfriendData->uknDate.second = 1;\n\n\t\t\tfriendData->friendExtraData.approvalTime.year = 2018;\n\t\t\tfriendData->friendExtraData.approvalTime.day = 1;\n\t\t\tfriendData->friendExtraData.approvalTime.month = 1;\n\t\t\tfriendData->friendExtraData.approvalTime.hour = 1;\n\t\t\tfriendData->friendExtraData.approvalTime.minute = 1;\n\t\t\tfriendData->friendExtraData.approvalTime.second = 1;\n\n\t\t\tconvertFPDTimestampToDate(frd->lastOnlineTimestamp, &friendData->friendExtraData.lastOnline);\n\t\t}\n\n\t\tvoid NexFriendRequestToFPDFriendData(const nexFriendRequest* frdReq, bool isIncoming, FriendData* friendData)\n\t\t{\n\t\t\tmemset(friendData, 0, sizeof(FriendData));\n\t\t\t// setup friend data\n\t\t\tfriendData->type = 0; // friend request\n\t\t\tfriendData->pid = frdReq->principalInfo.principalId;\n\t\t\tmemcpy(friendData->mii, frdReq->principalInfo.mii.miiData, FFL_SIZE);\n\t\t\tstrcpy((char*)friendData->nnid, frdReq->principalInfo.nnid);\n\t\t\t// screenname\n\t\t\tconvertMultiByteStringToBigEndianWidechar(frdReq->principalInfo.mii.miiNickname, friendData->screenname, sizeof(friendData->screenname) / sizeof(uint16be));\n\n\t\t\tconvertMultiByteStringToBigEndianWidechar(frdReq->message.commentStr.c_str(), friendData->requestExtraData.comment, sizeof(friendData->requestExtraData.comment) / sizeof(uint16be));\n\n\t\t\tFPDDate expireDate;\n\t\t\tconvertFPDTimestampToDate(frdReq->message.expireTimestamp, &expireDate);\n\n\t\t\tbool isProvisional = frdReq->message.expireTimestamp == 0;\n\n\t\t\t//friendData->requestExtraData.ukn0A8 = 0; // no change?\n\t\t\t//friendData->requestExtraData.ukn0A0 = 0; // if not set -> provisional friend request\n\t\t\t//friendData->requestExtraData.ukn0A4 = isProvisional ? 0 : 123; // no change?\n\n\t\t\tfriendData->requestExtraData.messageId = frdReq->message.messageId;\n\n\t\t\t///* +0x0A8 */ uint8 ukn0A8;\n\t\t\t///* +0x0A9 */ uint8 ukn0A9; // comment language? (guessed)\n\t\t\t///* +0x0AA */ uint16be comment[0x40];\n\t\t\t///* +0x12A */ uint8 ukn12A; // ingame name language? (guessed)\n\t\t\t///* +0x12B */ uint8 _padding12B;\n\n\t\t\t// set valid dates\n\n\t\t\tfriendData->uknDate.year = 2018;\n\t\t\tfriendData->uknDate.day = 20;\n\t\t\tfriendData->uknDate.month = 4;\n\t\t\tfriendData->uknDate.hour = 12;\n\t\t\tfriendData->uknDate.minute = 1;\n\t\t\tfriendData->uknDate.second = 1;\n\n\t\t\tfriendData->requestExtraData.uknData0.year = 2018;\n\t\t\tfriendData->requestExtraData.uknData0.day = 24;\n\t\t\tfriendData->requestExtraData.uknData0.month = 4;\n\t\t\tfriendData->requestExtraData.uknData0.hour = 1;\n\t\t\tfriendData->requestExtraData.uknData0.minute = 1;\n\t\t\tfriendData->requestExtraData.uknData0.second = 1;\n\n\t\t\t// this is the date used for 'Expires in'\n\t\t\tconvertFPDTimestampToDate(frdReq->message.expireTimestamp, &friendData->requestExtraData.uknData1);\n\t\t}\n\n\t\tvoid NexFriendRequestToFPDFriendRequest(const nexFriendRequest* frdReq, bool isIncoming, FriendRequest* friendRequest)\n\t\t{\n\t\t\tmemset(friendRequest, 0, sizeof(FriendRequest));\n\n\t\t\tfriendRequest->pid = frdReq->principalInfo.principalId;\n\t\t\t\n\t\t\tstrncpy((char*)friendRequest->nnid, frdReq->principalInfo.nnid, sizeof(friendRequest->nnid));\n\t\t\tfriendRequest->nnid[sizeof(friendRequest->nnid) - 1] = '\\0';\n\n\t\t\tmemcpy(friendRequest->miiData, frdReq->principalInfo.mii.miiData, sizeof(friendRequest->miiData));\n\n\t\t\tconvertMultiByteStringToBigEndianWidechar(frdReq->message.commentStr.c_str(), friendRequest->message, sizeof(friendRequest->message) / sizeof(friendRequest->message[0]));\n\t\t\tconvertMultiByteStringToBigEndianWidechar(frdReq->principalInfo.mii.miiNickname, friendRequest->screenname, sizeof(friendRequest->screenname) / sizeof(friendRequest->screenname[0]));\n\n\t\t\tfriendRequest->isMarkedAsReceived = 1;\n\n\t\t\tfriendRequest->ukn98 = _swapEndianU64(frdReq->message.messageId);\n\n\t\t\tconvertFPDTimestampToDate(0, &friendRequest->uknDate);\n\t\t\tconvertFPDTimestampToDate(0, &friendRequest->uknDate2);\n\t\t\tconvertFPDTimestampToDate(frdReq->message.expireTimestamp, &friendRequest->expireDate);\n\t\t}\n\n\t\tstruct FPProfile\n\t\t{\n\t\t\tuint8be country;\n\t\t\tuint8be area;\n\t\t\tuint16be unused;\n\t\t};\n\t\tstatic_assert(sizeof(FPProfile) == 4);\n\n\t\tstruct SelfPresence\n\t\t{\n\t\t\tuint8be ukn[0x130]; // todo\n\t\t};\n\t\tstatic_assert(sizeof(SelfPresence) == 0x130);\n\n\t\tstruct SelfPlayingGame\n\t\t{\n\t\t\tuint8be ukn0[0x10];\n\t\t};\n\t\tstatic_assert(sizeof(SelfPlayingGame) == 0x10);\n\n\t\tstatic const auto FPResult_Ok = 0;\n\t\tstatic const auto FPResult_InvalidIPCParam = BUILD_NN_RESULT(NN_RESULT_LEVEL_LVL6, NN_RESULT_MODULE_NN_FP, 0x680);\n\t\tstatic const auto FPResult_RequestFailed = BUILD_NN_RESULT(NN_RESULT_LEVEL_FATAL, NN_RESULT_MODULE_NN_FP, 0); // figure out proper error code\n\t\tstatic const auto FPResult_Aborted = BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_FP, 0x3480);\n\n\t\tclass FPDService : public iosu::nn::IPCSimpleService\n\t\t{\n\n\t\t\tstruct NotificationAsyncRequest\n\t\t\t{\n\t\t\t\tNotificationAsyncRequest(IPCCommandBody* cmd, uint32 maxNumEntries, FPDNotification* notificationsOut, uint32be* countOut)\n\t\t\t\t\t: cmd(cmd), maxNumEntries(maxNumEntries), notificationsOut(notificationsOut), countOut(countOut)\n\t\t\t\t{\n\t\t\t\t}\n\n\t\t\t\tIPCCommandBody* cmd;\n\t\t\t\tuint32 maxNumEntries;\n\t\t\t\tFPDNotification* notificationsOut;\n\t\t\t\tuint32be* countOut;\n\t\t\t};\n\n\t\t\tstruct FPDClient\n\t\t\t{\n\t\t\t\tbool hasLoggedIn{false};\n\t\t\t\tuint32 notificationMask{0};\n\t\t\t\tNotificationRunningId prevRunningId{0};\n\t\t\t\tstd::vector<NotificationAsyncRequest> notificationRequests;\n\t\t\t};\n\n\t\t\t// storage for async IPC requests\n\t\t\tstd::vector<IPCCommandBody*> m_asyncLoginRequests;\n\t\t\tstd::vector<FPDClient*> m_clients;\n\n\t\t  public:\n\t\t\tFPDService() : iosu::nn::IPCSimpleService(\"/dev/fpd\") {}\n\n\t\t\tstd::string GetThreadName() override\n\t\t\t{\n\t\t\t\treturn \"IOSUModule::FPD\";\n\t\t\t}\n\n\t\t\tvoid StartService() override\n\t\t\t{\n\t\t\t\tcemu_assert_debug(m_asyncLoginRequests.empty());\n\t\t\t}\n\n\t\t\tvoid StopService() override\n\t\t\t{\n\t\t\t\tm_asyncLoginRequests.clear();\n\t\t\t\tfor(auto& it : m_clients)\n\t\t\t\t\tdelete it;\n\t\t\t\tm_clients.clear();\n\t\t\t}\n\n\t\t\tvoid* CreateClientObject() override\n\t\t\t{\n\t\t\t\tFPDClient* client = new FPDClient();\n\t\t\t\tm_clients.push_back(client);\n\t\t\t\treturn client;\n\t\t\t}\n\n\t\t\tvoid DestroyClientObject(void* clientObject) override\n\t\t\t{\n\t\t\t\tFPDClient* client = (FPDClient*)clientObject;\n\t\t\t\tstd::erase(m_clients, client);\n\t\t\t\tdelete client;\n\t\t\t}\n\n\t\t\tvoid SendQueuedNotifications(FPDClient* client)\n\t\t\t{\n\t\t\t\tif (client->notificationRequests.empty())\n\t\t\t\t\treturn;\n\t\t\t\tif (client->notificationRequests.size() > 1)\n\t\t\t\t\tcemuLog_log(LogType::Force, \"FPD: More than one simultanous notification query not supported\");\n\t\t\t\tNotificationAsyncRequest& request = client->notificationRequests[0];\n\t\t\t\tuint32 numNotifications = 0;\n\t\t\t\twhile(numNotifications < request.maxNumEntries)\n\t\t\t\t{\n\t\t\t\t\tauto notification = g_NotificationQueue.GetNextNotification(client->prevRunningId);\n\t\t\t\t\tif (!notification)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tuint32 flag = 1 << static_cast<uint32>(notification->type);\n\t\t\t\t\tif((client->notificationMask & flag) == 0)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\trequest.notificationsOut[numNotifications].type = static_cast<uint32>(notification->type);\n\t\t\t\t\trequest.notificationsOut[numNotifications].pid = notification->pid;\n\t\t\t\t\tnumNotifications++;\n\t\t\t\t}\n\t\t\t\tif (numNotifications == 0)\n\t\t\t\t\treturn;\n\t\t\t\t*request.countOut = numNotifications;\n\t\t\t\tServiceCallAsyncRespond(request.cmd, FPResult_Ok);\n\t\t\t\tclient->notificationRequests.erase(client->notificationRequests.begin());\n\t\t\t}\n\n\t\t\tvoid TimerUpdate() override\n\t\t\t{\n\t\t\t\t// called once a second while service is running\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn;\n\t\t\t\tg_fpd.nexFriendSession->update();\n\t\t\t\twhile(!m_asyncLoginRequests.empty())\n\t\t\t\t{\n\t\t\t\t\tif(g_fpd.nexFriendSession->isOnline())\n\t\t\t\t\t{\n\t\t\t\t\t\tServiceCallAsyncRespond(m_asyncLoginRequests.front(), FPResult_Ok);\n\t\t\t\t\t\tm_asyncLoginRequests.erase(m_asyncLoginRequests.begin());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// handle notification responses\n\t\t\t\tg_NotificationQueue.RemoveExpired();\n\t\t\t\tfor(auto& client : m_clients)\n\t\t\t\t\tSendQueuedNotifications(client);\n\t\t\t}\n\n\t\t\tuint32 ServiceCall(void* clientObject, uint32 requestId, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut) override\n\t\t\t{\n\t\t\t\t// for /dev/fpd input and output vectors are swapped\n\t\t\t\tstd::swap(vecIn, vecOut);\n\t\t\t\tstd::swap(numVecIn, numVecOut);\n\n\t\t\t\tFPDClient* fpdClient = (FPDClient*)clientObject;\n\t\t\t\tswitch(static_cast<FPD_REQUEST_ID>(requestId))\n\t\t\t\t{\n\t\t\t\tcase FPD_REQUEST_ID::SetNotificationMask:\n\t\t\t\t\treturn CallHandler_SetNotificationMask(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetNotificationAsync:\n\t\t\t\t\treturn CallHandler_GetNotificationAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::SetLedEventMask:\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"[/dev/fpd] SetLedEventMask is todo\");\n\t\t\t\t\treturn FPResult_Ok;\n\t\t\t\tcase FPD_REQUEST_ID::LoginAsync:\n\t\t\t\t\treturn CallHandler_LoginAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::HasLoggedIn:\n\t\t\t\t\treturn CallHandler_HasLoggedIn(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::IsOnline:\n\t\t\t\t\treturn CallHandler_IsOnline(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetMyPrincipalId:\n\t\t\t\t\treturn CallHandler_GetMyPrincipalId(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetMyAccountId:\n\t\t\t\t\treturn CallHandler_GetMyAccountId(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetMyScreenName:\n\t\t\t\t\treturn CallHandler_GetMyScreenName(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetMyMii:\n\t\t\t\t\treturn CallHandler_GetMyMii(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetMyProfile:\n\t\t\t\t\treturn CallHandler_GetMyProfile(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetMyPresence:\n\t\t\t\t\treturn CallHandler_GetMyPresence(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetMyComment:\n\t\t\t\t\treturn CallHandler_GetMyComment(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetMyPreference:\n\t\t\t\t\treturn CallHandler_GetMyPreference(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetMyPlayingGame:\n\t\t\t\t\treturn CallHandler_GetMyPlayingGame(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetFriendAccountId:\n\t\t\t\t\treturn CallHandler_GetFriendAccountId(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetFriendScreenName:\n\t\t\t\t\treturn CallHandler_GetFriendScreenName(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetFriendMii:\n\t\t\t\t\treturn CallHandler_GetFriendMii(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetFriendPresence:\n\t\t\t\t\treturn CallHandler_GetFriendPresence(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetFriendRelationship:\n\t\t\t\t\treturn CallHandler_GetFriendRelationship(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetFriendList:\n\t\t\t\t\treturn CallHandler_GetFriendList_GetFriendListAll(fpdClient, vecIn, numVecIn, vecOut, numVecOut, false);\n\t\t\t\tcase FPD_REQUEST_ID::GetFriendListAll:\n\t\t\t\t\treturn CallHandler_GetFriendList_GetFriendListAll(fpdClient, vecIn, numVecIn, vecOut, numVecOut, true);\n\t\t\t\tcase FPD_REQUEST_ID::GetFriendRequestList:\n\t\t\t\t\treturn CallHandler_GetFriendRequestList(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetFriendRequestListEx:\n\t\t\t\t\treturn CallHandler_GetFriendRequestListEx(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetBlackList:\n\t\t\t\t\treturn CallHandler_GetBlackList(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetFriendListEx:\n\t\t\t\t\treturn CallHandler_GetFriendListEx(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::UpdateCommentAsync:\n\t\t\t\t\treturn CallHandler_UpdateCommentAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::UpdatePreferenceAsync:\n\t\t\t\t\treturn CallHandler_UpdatePreferenceAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::AddFriendRequestByPlayRecordAsync:\n\t\t\t\t\treturn CallHandler_AddFriendRequestAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::AcceptFriendRequestAsync:\n\t\t\t\t\treturn CallHandler_AcceptFriendRequestAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::DeleteFriendRequestAsync:\n\t\t\t\t\treturn CallHandler_DeleteFriendRequestAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::CancelFriendRequestAsync:\n\t\t\t\t\treturn CallHandler_CancelFriendRequestAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::MarkFriendRequestsAsReceivedAsync:\n\t\t\t\t\treturn CallHandler_MarkFriendRequestsAsReceivedAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::RemoveFriendAsync:\n\t\t\t\t\treturn CallHandler_RemoveFriendAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::DeleteFriendFlagsAsync:\n\t\t\t\t\treturn CallHandler_DeleteFriendFlagsAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetBasicInfoAsync:\n\t\t\t\t\treturn CallHandler_GetBasicInfoAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::CheckSettingStatusAsync:\n\t\t\t\t\treturn CallHandler_CheckSettingStatusAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::IsPreferenceValid:\n\t\t\t\t\treturn CallHandler_IsPreferenceValid(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::GetRequestBlockSettingAsync:\n\t\t\t\t\treturn CallHandler_GetRequestBlockSettingAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::AddFriendAsyncByPid:\n\t\t\t\t\treturn CallHandler_AddFriendAsyncByPid(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tcase FPD_REQUEST_ID::UpdateGameModeVariation1:\n\t\t\t\tcase FPD_REQUEST_ID::UpdateGameModeVariation2:\n\t\t\t\t\treturn CallHandler_UpdateGameMode(fpdClient, vecIn, numVecIn, vecOut, numVecOut);\n\t\t\t\tdefault:\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Unsupported service call {} to /dev/fpd\", requestId);\n\t\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_FATAL, NN_RESULT_MODULE_NN_FP, 0);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t#define DeclareInputPtr(__Name, __T, __count, __vecIndex) if(sizeof(__T)*(__count) != vecIn[__vecIndex].size) { cemuLog_log(LogType::Force, \"FPD: IPC buffer has incorrect size\"); return FPResult_InvalidIPCParam;};  __T* __Name = ((__T*)vecIn[__vecIndex].basePhys.GetPtr())\n\t\t\t#define DeclareInput(__Name, __T, __vecIndex) if(sizeof(__T) != vecIn[__vecIndex].size) { cemuLog_log(LogType::Force, \"FPD: IPC buffer has incorrect size\"); return FPResult_InvalidIPCParam;}; __T __Name = *((__T*)vecIn[__vecIndex].basePhys.GetPtr())\n\t\t\t#define DeclareOutputPtr(__Name, __T, __count, __vecIndex) if(sizeof(__T)*(__count) != vecOut[__vecIndex].size) { cemuLog_log(LogType::Force, \"FPD: IPC buffer has incorrect size\"); return FPResult_InvalidIPCParam;}; __T* __Name = ((__T*)vecOut[__vecIndex].basePhys.GetPtr())\n\n\t\t\ttemplate<typename T>\n\t\t\tstatic nnResult WriteValueOutput(IPCIoctlVector* vec, const T& value)\n\t\t\t{\n\t\t\t\tif(vec->size != sizeof(T))\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t*(T*)vec->basePhys.GetPtr() = value;\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_SetNotificationMask(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 1 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tDeclareInput(notificationMask, uint32be, 0);\n\t\t\t\tfpdClient->notificationMask = notificationMask;\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetNotificationAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 2)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif((vecOut[0].size % sizeof(FPDNotification)) != 0 || vecOut[0].size < sizeof(FPDNotification))\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"FPD GetNotificationAsync: Unexpected output size\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\t\t\t\tDeclareOutputPtr(countOut, uint32be, 1, 1);\n\t\t\t\tuint32 maxCount = vecOut[0].size / sizeof(FPDNotification);\n\t\t\t\tDeclareOutputPtr(notificationList, FPDNotification, maxCount, 0);\n\t\t\t\tfpdClient->notificationRequests.emplace_back(cmd, maxCount, notificationList, countOut);\n\t\t\t\tSendQueuedNotifications(fpdClient); // if any notifications are queued, send them immediately\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_LoginAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!ActiveSettings::IsOnlineEnabled())\n\t\t\t\t{\n\t\t\t\t\t// not online, fail immediately\n\t\t\t\t\treturn FPResult_Ok; // Splatoon expects this to always return success otherwise it will softlock. This should be FPResult_Aborted?\n\t\t\t\t}\n\t\t\t\tStartFriendSession();\n\t\t\t\tfpdClient->hasLoggedIn = true;\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\t\t\t\tm_asyncLoginRequests.emplace_back(cmd);\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_HasLoggedIn(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\treturn WriteValueOutput<uint32be>(vecOut, fpdClient->hasLoggedIn ? 1 : 0);\n\t\t\t}\n\n\t\t\tnnResult CallHandler_IsOnline(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tbool isOnline = g_fpd.nexFriendSession ? g_fpd.nexFriendSession->isOnline() : false;\n\t\t\t\treturn WriteValueOutput<uint32be>(vecOut, isOnline?1:0);\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetMyPrincipalId(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tuint8 slot = iosu::act::getCurrentAccountSlot();\n\t\t\t\tuint32 pid = 0;\n\t\t\t\tiosu::act::getPrincipalId(slot, &pid);\n\t\t\t\treturn WriteValueOutput<uint32be>(vecOut, pid);\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetMyAccountId(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tuint8 slot = iosu::act::getCurrentAccountSlot();\n\t\t\t\tstd::string accountId = iosu::act::getAccountId2(slot);\n\t\t\t\tif(vecOut->size != ACT_ACCOUNTID_LENGTH)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetMyAccountId: Unexpected output size\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tif(accountId.length() > ACT_ACCOUNTID_LENGTH-1)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetMyAccountId: AccountID is too long\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tif(accountId.empty())\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetMyAccountId: AccountID is empty\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam; // should return 0xC0C00800 ?\n\t\t\t\t}\n\t\t\t\tchar* outputStr = (char*)vecOut->basePhys.GetPtr();\n\t\t\t\tmemset(outputStr, 0, ACT_ACCOUNTID_LENGTH);\n\t\t\t\tmemcpy(outputStr, accountId.data(), accountId.length());\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetMyScreenName(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tuint8 slot = iosu::act::getCurrentAccountSlot();\n\t\t\t\tif(vecOut->size != ACT_NICKNAME_SIZE*sizeof(uint16be))\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetMyScreenName: Unexpected output size\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tuint16 screenname[ACT_NICKNAME_SIZE]{0};\n\t\t\t\tbool r = iosu::act::getScreenname(slot, screenname);\n\t\t\t\tif (!r)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetMyScreenName: Screenname is empty\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam; // should return 0xC0C00800 ?\n\t\t\t\t}\n\t\t\t\tuint16be* outputStr = (uint16be*)vecOut->basePhys.GetPtr();\n\t\t\t\tfor(sint32 i = 0; i < ACT_NICKNAME_SIZE; i++)\n\t\t\t\t\toutputStr[i] = screenname[i];\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetMyMii(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tuint8 slot = iosu::act::getCurrentAccountSlot();\n\t\t\t\tif(vecOut->size != FFL_SIZE)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetMyMii: Unexpected output size\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tbool r = iosu::act::getMii(slot, (FFLData_t*)vecOut->basePhys.GetPtr());\n\t\t\t\tif (!r)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetMyMii: Mii is empty\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam; // should return 0xC0C00800 ?\n\t\t\t\t}\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetMyProfile(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tuint8 slot = iosu::act::getCurrentAccountSlot();\n\t\t\t\tFPProfile profile{0};\n\t\t\t\t// todo\n\t\t\t\tcemuLog_log(LogType::Force, \"GetMyProfile is todo\");\n\t\t\t\treturn WriteValueOutput<FPProfile>(vecOut, profile);\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetMyPresence(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tuint8 slot = iosu::act::getCurrentAccountSlot();\n\t\t\t\tSelfPresence selfPresence{0};\n\t\t\t\tcemuLog_log(LogType::Force, \"GetMyPresence is todo\");\n\t\t\t\treturn WriteValueOutput<SelfPresence>(vecOut, selfPresence);\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetMyComment(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tstd::vector<uint16be> myComment;\n\t\t\t\tif(g_fpd.nexFriendSession)\n\t\t\t\t{\n\t\t\t\t\tif(vecOut->size != MY_COMMENT_LENGTH * sizeof(uint16be))\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"GetMyComment: Unexpected output size\");\n\t\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t\t}\n\t\t\t\t\tnexComment myNexComment;\n\t\t\t\t\tg_fpd.nexFriendSession->getMyComment(myNexComment);\n\t\t\t\t\tmyComment = StringHelpers::FromUtf8(myNexComment.commentString);\n\t\t\t\t}\n\t\t\t\tmyComment.insert(myComment.begin(), '\\0');\n\t\t\t\tmemcpy(vecOut->basePhys.GetPtr(), myComment.data(), MY_COMMENT_LENGTH * sizeof(uint16be));\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetMyPreference(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tFPDPreference selfPreference{0};\n\t\t\t\tif(g_fpd.nexFriendSession)\n\t\t\t\t{\n\t\t\t\t\tnexPrincipalPreference nexPreference;\n\t\t\t\t\tg_fpd.nexFriendSession->getMyPreference(nexPreference);\n\t\t\t\t\tselfPreference.showOnline = nexPreference.showOnline;\n\t\t\t\t\tselfPreference.showGame = nexPreference.showGame;\n\t\t\t\t\tselfPreference.blockFriendRequests = nexPreference.blockFriendRequests;\n\t\t\t\t\tselfPreference.ukn = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tmemset(&selfPreference, 0, sizeof(FPDPreference));\n\t\t\t\treturn WriteValueOutput<FPDPreference>(vecOut, selfPreference);\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetMyPlayingGame(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tGameKey selfPlayingGame\n\t\t\t\t{\n\t\t\t\t\tCafeSystem::GetForegroundTitleId(),\n\t\t\t\t\tCafeSystem::GetForegroundTitleVersion(),\n\t\t\t\t\t{0,0,0,0,0,0}\n\t\t\t\t};\n\t\t\t\tif (GetTitleIdHigh(CafeSystem::GetForegroundTitleId()) != 0x00050000)\n\t\t\t\t{\n\t\t\t\t\tselfPlayingGame.titleId = 0;\n\t\t\t\t\tselfPlayingGame.ukn08 = 0;\n\t\t\t\t}\n\t\t\t\treturn WriteValueOutput<GameKey>(vecOut, selfPlayingGame);\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetFriendAccountId(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 2 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t// todo - online check\n\t\t\t\tDeclareInput(count, uint32be, 1);\n\t\t\t\tDeclareInputPtr(pidList, uint32be, count, 0);\n\t\t\t\tDeclareOutputPtr(accountId, CafeString<ACT_ACCOUNTID_LENGTH>, count, 0);\n\t\t\t\tmemset(accountId, 0, ACT_ACCOUNTID_LENGTH * count);\n\t\t\t\tif (g_fpd.nexFriendSession)\n\t\t\t\t{\n\t\t\t\t\tfor (uint32 i = 0; i < count; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst uint32 pid = pidList[i];\n\t\t\t\t\t\tauto& nnidOutput = accountId[i];\n\t\t\t\t\t\tnexFriend frd;\n\t\t\t\t\t\tnexFriendRequest frdReq;\n\t\t\t\t\t\tif (g_fpd.nexFriendSession->getFriendByPID(frd, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnnidOutput.assign(frd.nnaInfo.principalInfo.nnid);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbool incoming = false;\n\t\t\t\t\t\tif (g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnnidOutput.assign(frdReq.principalInfo.nnid);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"GetFriendAccountId: PID {} not found\", pid);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetFriendScreenName(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstatic_assert(sizeof(CafeWideString<ACT_NICKNAME_SIZE>) == 11*2);\n\t\t\t\tif(numVecIn != 3 || numVecOut != 2)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tDeclareInput(count, uint32be, 1);\n\t\t\t\tDeclareInputPtr(pidList, uint32be, count, 0);\n\t\t\t\tDeclareInput(replaceNonAscii, uint8be, 2);\n\t\t\t\tDeclareOutputPtr(nameList, CafeWideString<ACT_NICKNAME_SIZE>, count, 0);\n\t\t\t\tuint8be* languageList = nullptr;\n\t\t\t\tif(vecOut[1].size > 0) // languageList is optional\n\t\t\t\t{\n\t\t\t\t\tDeclareOutputPtr(_languageList, uint8be, count, 1);\n\t\t\t\t\tlanguageList = _languageList;\n\t\t\t\t}\n\t\t\t\tmemset(nameList, 0, ACT_NICKNAME_SIZE * sizeof(CafeWideString<ACT_NICKNAME_SIZE>));\n\t\t\t\tif (g_fpd.nexFriendSession)\n\t\t\t\t{\n\t\t\t\t\tfor (uint32 i = 0; i < count; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst uint32 pid = pidList[i];\n\t\t\t\t\t\tCafeWideString<ACT_NICKNAME_SIZE>& screennameOutput = nameList[i];\n\t\t\t\t\t\tif (languageList)\n\t\t\t\t\t\t\tlanguageList[i] = 0; // unknown\n\t\t\t\t\t\tnexFriend frd;\n\t\t\t\t\t\tnexFriendRequest frdReq;\n\t\t\t\t\t\tif (g_fpd.nexFriendSession->getFriendByPID(frd, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tscreennameOutput.assignFromUTF8(frd.nnaInfo.principalInfo.mii.miiNickname);\n\t\t\t\t\t\t\tif (languageList)\n\t\t\t\t\t\t\t\tlanguageList[i] = frd.nnaInfo.principalInfo.regionGuessed;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbool incoming = false;\n\t\t\t\t\t\tif (g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tscreennameOutput.assignFromUTF8(frdReq.principalInfo.mii.miiNickname);\n\t\t\t\t\t\t\tif (languageList)\n\t\t\t\t\t\t\t\tlanguageList[i] = frdReq.principalInfo.regionGuessed;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"GetFriendScreenName: PID {} not found\", pid);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetFriendMii(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 2 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tDeclareInput(count, uint32be, 1);\n\t\t\t\tDeclareInputPtr(pidList, uint32be, count, 0);\n\t\t\t\tDeclareOutputPtr(miiList, FFLData_t, count, 0);\n\t\t\t\tmemset(miiList, 0, sizeof(FFLData_t) * count);\n\t\t\t\tif (g_fpd.nexFriendSession)\n\t\t\t\t{\n\t\t\t\t\tfor (uint32 i = 0; i < count; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst uint32 pid = pidList[i];\n\t\t\t\t\t\tFFLData_t& miiOutput = miiList[i];\n\t\t\t\t\t\tnexFriend frd;\n\t\t\t\t\t\tnexFriendRequest frdReq;\n\t\t\t\t\t\tif (g_fpd.nexFriendSession->getFriendByPID(frd, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmemcpy(&miiOutput, frd.nnaInfo.principalInfo.mii.miiData, FFL_SIZE);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbool incoming = false;\n\t\t\t\t\t\tif (g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmemcpy(&miiOutput, frdReq.principalInfo.mii.miiData, FFL_SIZE);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetFriendPresence(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 2 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tDeclareInput(count, uint32be, 1);\n\t\t\t\tDeclareInputPtr(pidList, uint32be, count, 0);\n\t\t\t\tDeclareOutputPtr(presenceList, FriendPresence, count, 0);\n\t\t\t\tmemset(presenceList, 0, sizeof(FriendPresence) * count);\n\t\t\t\tif (g_fpd.nexFriendSession)\n\t\t\t\t{\n\t\t\t\t\tfor (uint32 i = 0; i < count; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tFriendPresence& presenceOutput = presenceList[i];\n\t\t\t\t\t\tconst uint32 pid = pidList[i];\n\t\t\t\t\t\tnexFriend frd;\n\t\t\t\t\t\tif (g_fpd.nexFriendSession->getFriendByPID(frd, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpresenceOutput.isOnline = frd.presence.isOnline ? 1 : 0;\n\t\t\t\t\t\t\tpresenceOutput.isValid = 1;\n\t\t\t\t\t\t\t// todo - region and subregion\n\t\t\t\t\t\t\tpresenceOutput.gameMode.joinFlagMask = frd.presence.joinFlagMask;\n\t\t\t\t\t\t\tpresenceOutput.gameMode.matchmakeType = frd.presence.joinAvailability;\n\t\t\t\t\t\t\tpresenceOutput.gameMode.joinGameId = frd.presence.gameId;\n\t\t\t\t\t\t\tpresenceOutput.gameMode.joinGameMode = frd.presence.gameMode;\n\t\t\t\t\t\t\tpresenceOutput.gameMode.hostPid = frd.presence.hostPid;\n\t\t\t\t\t\t\tpresenceOutput.gameMode.groupId = frd.presence.groupId;\n\n\t\t\t\t\t\t\tmemcpy(presenceOutput.gameMode.appSpecificData, frd.presence.appSpecificData, 0x14);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"GetFriendPresence: PID {} not found\", pid);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetFriendRelationship(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif(numVecIn != 2 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t// todo - check for valid session (same for all GetFriend* functions)\n\t\t\t\tDeclareInput(count, uint32be, 1);\n\t\t\t\tDeclareInputPtr(pidList, uint32be, count, 0);\n\t\t\t\tDeclareOutputPtr(relationshipList, uint8be, count, 0); // correct?\n\t\t\t\tfor(uint32 i=0; i<count; i++)\n\t\t\t\t\trelationshipList[i] = RELATIONSHIP_INVALID;\n\t\t\t\tif (g_fpd.nexFriendSession)\n\t\t\t\t{\n\t\t\t\t\tfor (uint32 i = 0; i < count; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst uint32 pid = pidList[i];\n\t\t\t\t\t\tuint8be& relationshipOutput = relationshipList[i];\n\t\t\t\t\t\tnexFriend frd;\n\t\t\t\t\t\tnexFriendRequest frdReq;\n\t\t\t\t\t\tbool incoming;\n\t\t\t\t\t\tif (g_fpd.nexFriendSession->getFriendByPID(frd, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\trelationshipOutput = RELATIONSHIP_FRIEND;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (incoming)\n\t\t\t\t\t\t\t\trelationshipOutput = RELATIONSHIP_FRIENDREQUEST_IN;\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\trelationshipOutput = RELATIONSHIP_FRIENDREQUEST_OUT;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetFriendList_GetFriendListAll(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut, bool isAll)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif(numVecIn != 2 || numVecOut != 2)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tDeclareInput(startIndex, uint32be, 0);\n\t\t\t\tDeclareInput(maxCount, uint32be, 1);\n\t\t\t\tif (maxCount * sizeof(FriendPID) != vecOut[0].size || vecOut[0].basePhys.IsNull())\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetFriendListAll: pid list buffer size is incorrect\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn WriteValueOutput<uint32be>(vecOut+1, 0);\n\t\t\t\tbetype<FriendPID>* pidList = (betype<FriendPID>*)vecOut[0].basePhys.GetPtr();\n\t\t\t\tstd::vector<FriendPID> temporaryPidList;\n\t\t\t\ttemporaryPidList.resize(std::min<size_t>(maxCount, 500));\n\t\t\t\tuint32 pidCount = 0;\n\t\t\t\tg_fpd.nexFriendSession->getFriendPIDs(temporaryPidList.data(), &pidCount, startIndex, temporaryPidList.size(), isAll);\n\t\t\t\tstd::copy(temporaryPidList.begin(), temporaryPidList.begin() + pidCount, pidList);\n\t\t\t\treturn WriteValueOutput<uint32be>(vecOut+1, pidCount);\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetFriendRequestList(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif(numVecIn != 2 || numVecOut != 2)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tDeclareInput(startIndex, uint32be, 0);\n\t\t\t\tDeclareInput(maxCount, uint32be, 1);\n\t\t\t\tif(maxCount * sizeof(FriendPID) != vecOut[0].size || vecOut[0].basePhys.IsNull())\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetFriendRequestList: pid list buffer size is incorrect\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn WriteValueOutput<uint32be>(vecOut+1, 0);\n\t\t\t\tbetype<FriendPID>* pidList = (betype<FriendPID>*)vecOut[0].basePhys.GetPtr();\n\t\t\t\tstd::vector<FriendPID> temporaryPidList;\n\t\t\t\ttemporaryPidList.resize(std::min<size_t>(maxCount, 500));\n\t\t\t\tuint32 pidCount = 0;\n\t\t\t\tg_fpd.nexFriendSession->getFriendRequestPIDs(temporaryPidList.data(), &pidCount, startIndex, temporaryPidList.size(), true, false);\n\t\t\t\tstd::copy(temporaryPidList.begin(), temporaryPidList.begin() + pidCount, pidList);\n\t\t\t\treturn WriteValueOutput<uint32be>(vecOut+1, pidCount);\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetFriendRequestListEx(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif(numVecIn != 2 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tDeclareInput(count, uint32be, 1);\n\t\t\t\tDeclareInputPtr(pidList, uint32be, count, 0);\n\t\t\t\tDeclareOutputPtr(friendRequests, FriendRequest, count, 0);\n\t\t\t\tmemset(friendRequests, 0, sizeof(FriendRequest) * count);\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_Ok;\n\t\t\t\tfor(uint32 i=0; i<count; i++)\n\t\t\t\t{\n\t\t\t\t\tnexFriendRequest frdReq;\n\t\t\t\t\tbool incoming = false;\n\t\t\t\t\tif (!g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pidList[i]))\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"GetFriendRequestListEx: Failed to get friend request\");\n\t\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\t\t}\n\t\t\t\t\tNexFriendRequestToFPDFriendRequest(&frdReq, incoming, friendRequests + i);\n\t\t\t\t}\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetBlackList(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif(numVecIn != 2 || numVecOut != 2)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tDeclareInput(startIndex, uint32be, 0);\n\t\t\t\tDeclareInput(maxCount, uint32be, 1);\n\t\t\t\tif(maxCount * sizeof(FriendPID) != vecOut[0].size)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetBlackList: pid list buffer size is incorrect\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn WriteValueOutput<uint32be>(vecOut+1, 0);\n\t\t\t\tbetype<FriendPID>* pidList = (betype<FriendPID>*)vecOut[0].basePhys.GetPtr();\n\t\t\t\t// todo!\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"GetBlackList is todo\");\n\t\t\t\tuint32 countOut = 0;\n\n\t\t\t\treturn WriteValueOutput<uint32be>(vecOut+1, countOut);\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetFriendListEx(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif(numVecIn != 2 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tDeclareInput(count, uint32be, 1);\n\t\t\t\tDeclareInputPtr(pidList, betype<FriendPID>, count, 0);\n\t\t\t\tif(count * sizeof(FriendPID) != vecIn[0].size)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetFriendListEx: pid input list buffer size is incorrect\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tif(count * sizeof(FriendData) != vecOut[0].size)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GetFriendListEx: Friend output list buffer size is incorrect\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tFriendData* friendOutput = (FriendData*)vecOut[0].basePhys.GetPtr();\n\t\t\t\tmemset(friendOutput, 0, sizeof(FriendData) * count);\n\t\t\t\tif (g_fpd.nexFriendSession)\n\t\t\t\t{\n\t\t\t\t\tfor (uint32 i = 0; i < count; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tuint32 pid = pidList[i];\n\t\t\t\t\t\tFriendData* friendData = friendOutput + i;\n\t\t\t\t\t\tnexFriend frd;\n\t\t\t\t\t\tnexFriendRequest frdReq;\n\t\t\t\t\t\tif (g_fpd.nexFriendSession->getFriendByPID(frd, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tNexFriendToFPDFriendData(&frd, friendData);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbool incoming = false;\n\t\t\t\t\t\tif (g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tNexFriendRequestToFPDFriendData(&frdReq, incoming, friendData);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"GetFriendListEx: Failed to find friend or request with pid {}\", pid);\n\t\t\t\t\t\tmemset(friendData, 0, sizeof(FriendData));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tstatic void NexBasicInfoToBasicInfo(const nexPrincipalBasicInfo& nexBasicInfo, FriendBasicInfo& basicInfo)\n\t\t\t{\n\t\t\t\tmemset(&basicInfo, 0, sizeof(FriendBasicInfo));\n\t\t\t\tbasicInfo.pid = nexBasicInfo.principalId;\n\t\t\t\tstrcpy(basicInfo.nnid, nexBasicInfo.nnid);\n\n\t\t\t\tconvertMultiByteStringToBigEndianWidechar(nexBasicInfo.mii.miiNickname, basicInfo.screenname, sizeof(basicInfo.screenname) / sizeof(uint16be));\n\t\t\t\tmemcpy(basicInfo.miiData, nexBasicInfo.mii.miiData, FFL_SIZE);\n\n\t\t\t\tbasicInfo.uknDate90.day = 1;\n\t\t\t\tbasicInfo.uknDate90.month = 1;\n\t\t\t\tbasicInfo.uknDate90.hour = 1;\n\t\t\t\tbasicInfo.uknDate90.minute = 1;\n\t\t\t\tbasicInfo.uknDate90.second = 1;\n\n\t\t\t\t// unknown values not set:\n\t\t\t\t// ukn15\n\t\t\t\t// ukn2E\n\t\t\t\t// ukn2F\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetBasicInfoAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (numVecIn != 2 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tDeclareInput(count, uint32be, 1);\n\t\t\t\tDeclareInputPtr(pidListBE, betype<FriendPID>, count, 0);\n\t\t\t\tDeclareOutputPtr(basicInfoList, FriendBasicInfo, count, 0);\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t{\n\t\t\t\t\tmemset(basicInfoList, 0, sizeof(FriendBasicInfo) * sizeof(count));\n\t\t\t\t\treturn FPResult_Ok;\n\t\t\t\t}\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\t\t\t\tstd::vector<uint32> pidList;\n\t\t\t\tstd::copy(pidListBE, pidListBE + count, std::back_inserter(pidList));\n\t\t\t\tg_fpd.nexFriendSession->requestPrincipleBaseInfoByPID(pidList.data(), count, [cmd, basicInfoList, count](NexFriends::RpcErrorCode result, std::span<nexPrincipalBasicInfo> basicInfo) -> void {\n\t\t\t\t\tif (result != NexFriends::ERR_NONE)\n\t\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_RequestFailed);\n\t\t\t\t\tcemu_assert_debug(basicInfo.size() == count);\n\t\t\t\t\tfor(uint32 i = 0; i < count; i++)\n\t\t\t\t\t\tNexBasicInfoToBasicInfo(basicInfo[i], basicInfoList[i]);\n\t\t\t\t\tServiceCallAsyncRespond(cmd, FPResult_Ok);\n\t\t\t\t});\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_UpdateCommentAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (numVecIn != 1 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tuint32 messageLength = vecIn[0].size / sizeof(uint16be);\n\t\t\t\tDeclareInputPtr(newComment, uint16be, messageLength, 0);\n\t\t\t\tif (messageLength == 0 || newComment[messageLength-1] != 0)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"UpdateCommentAsync: Message must contain at least a null-termination character\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\n\t\t\t\tauto utf8_comment = StringHelpers::ToUtf8(newComment, messageLength);\n\t\t\t\tnexComment temporaryComment;\n\t\t\t\ttemporaryComment.ukn0 = 0;\n\t\t\t\ttemporaryComment.commentString = utf8_comment;\n\t\t\t\ttemporaryComment.ukn1 = 0;\n\n\t\t\t\tg_fpd.nexFriendSession->updateCommentAsync(temporaryComment, [cmd](NexFriends::RpcErrorCode result) {\n\t\t\t\t\tif (result != NexFriends::ERR_NONE)\n\t\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_RequestFailed);\n\t\t\t\t\tServiceCallAsyncRespond(cmd, FPResult_Ok);\n\t\t\t\t});\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_UpdatePreferenceAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (numVecIn != 1 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInputPtr(newPreference, FPDPreference, 1, 0);\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\t\t\t\tg_fpd.nexFriendSession->updatePreferencesAsync(nexPrincipalPreference(newPreference->showOnline != 0 ? 1 : 0, newPreference->showGame != 0 ? 1 : 0, newPreference->blockFriendRequests != 0 ? 1 : 0), [cmd](NexFriends::RpcErrorCode result){\n\t\t\t\t\tif (result != NexFriends::ERR_NONE)\n\t\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_RequestFailed);\n\t\t\t\t\tServiceCallAsyncRespond(cmd, FPResult_Ok);\n\t\t\t\t});\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_AddFriendRequestAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (numVecIn != 2 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInputPtr(playRecord, RecentPlayRecordEx, 1, 0);\n\t\t\t\tuint32 msgLength = vecIn[1].size/sizeof(uint16be);\n\t\t\t\tDeclareInputPtr(msgBE, uint16be, msgLength, 1);\n\t\t\t\tif(msgLength == 0 || msgBE[msgLength-1] != 0)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"AddFriendRequestAsync: Message must contain at least a null-termination character and end with one\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tstd::string msg = StringHelpers::ToUtf8({ msgBE, msgLength-1 });\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\t\t\t\tg_fpd.nexFriendSession->addFriendRequest(playRecord->pid, msg.data(), [cmd](NexFriends::RpcErrorCode result){\n\t\t\t\t\tif (result != NexFriends::ERR_NONE)\n\t\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_RequestFailed);\n\t\t\t\t\tServiceCallAsyncRespond(cmd, FPResult_Ok);\n\t\t\t\t});\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_AcceptFriendRequestAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (numVecIn != 1 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInput(requestId, uint64be, 0);\n\t\t\t\tnexFriendRequest frq;\n\t\t\t\tbool isIncoming;\n\t\t\t\tif (!g_fpd.nexFriendSession->getFriendRequestByMessageId(frq, &isIncoming, requestId))\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tif(!isIncoming)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"AcceptFriendRequestAsync: Trying to accept outgoing friend request\");\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\t}\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\t\t\t\tg_fpd.nexFriendSession->acceptFriendRequest(requestId, [cmd](NexFriends::RpcErrorCode result){\n\t\t\t\t\tif (result != NexFriends::ERR_NONE)\n\t\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_RequestFailed);\n\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_Ok);\n\t\t\t\t});\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_DeleteFriendRequestAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\t// reject incoming friend request\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (numVecIn != 1 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInput(requestId, uint64be, 0);\n\t\t\t\tnexFriendRequest frq;\n\t\t\t\tbool isIncoming;\n\t\t\t\tif (!g_fpd.nexFriendSession->getFriendRequestByMessageId(frq, &isIncoming, requestId))\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tif(!isIncoming)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"CancelFriendRequestAsync: Trying to block outgoing friend request\");\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\t}\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\t\t\t\tg_fpd.nexFriendSession->deleteFriendRequest(requestId, [cmd](NexFriends::RpcErrorCode result){\n\t\t\t\t\tif (result != NexFriends::ERR_NONE)\n\t\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_RequestFailed);\n\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_Ok);\n\t\t\t\t});\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_CancelFriendRequestAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\t// retract outgoing friend request\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (numVecIn != 1 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInput(requestId, uint64be, 0);\n\t\t\t\tnexFriendRequest frq;\n\t\t\t\tbool isIncoming;\n\t\t\t\tif (!g_fpd.nexFriendSession->getFriendRequestByMessageId(frq, &isIncoming, requestId))\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tif(isIncoming)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"CancelFriendRequestAsync: Trying to cancel incoming friend request\");\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\t}\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\t\t\t\tg_fpd.nexFriendSession->removeFriend(frq.principalInfo.principalId, [cmd](NexFriends::RpcErrorCode result){\n\t\t\t\t\tif (result != NexFriends::ERR_NONE)\n\t\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_RequestFailed);\n\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_Ok);\n\t\t\t\t});\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_MarkFriendRequestsAsReceivedAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (numVecIn != 2 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInput(count, uint32be, 1);\n\t\t\t\tDeclareInputPtr(requestIdsBE, uint64be, count, 0);\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\t\t\t\t// endian convert\n\t\t\t\tstd::vector<uint64> requestIds;\n\t\t\t\tstd::copy(requestIdsBE, requestIdsBE + count, std::back_inserter(requestIds));\n\t\t\t\tg_fpd.nexFriendSession->markFriendRequestsAsReceived(requestIds.data(), requestIds.size(), [cmd](NexFriends::RpcErrorCode result){\n\t\t\t\t\tif (result != NexFriends::ERR_NONE)\n\t\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_RequestFailed);\n\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_Ok);\n\t\t\t\t});\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_RemoveFriendAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (numVecIn != 1 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInput(pid, uint32be, 0);\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\t\t\t\tg_fpd.nexFriendSession->removeFriend(pid, [cmd](NexFriends::RpcErrorCode result){\n\t\t\t\t\tif (result != NexFriends::ERR_NONE)\n\t\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_RequestFailed);\n\t\t\t\t\treturn ServiceCallAsyncRespond(cmd, FPResult_Ok);\n\t\t\t\t});\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_DeleteFriendFlagsAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tif (numVecIn != 3 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInput(pid, uint32be, 0);\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"DeleteFriendFlagsAsync is todo\");\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_CheckSettingStatusAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif (numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (vecOut[0].size != sizeof(uint8be))\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tIPCCommandBody* cmd = ServiceCallDelayCurrentResponse();\n\n\t\t\t\t// for now we respond immediately\n\t\t\t\tuint8 settingsStatus = 1; // todo - figure out what this status means\n\t\t\t\tauto r = WriteValueOutput<uint8be>(vecOut, settingsStatus);\n\t\t\t\tServiceCallAsyncRespond(cmd, r);\n\t\t\t\tcemuLog_log(LogType::Force, \"CheckSettingStatusAsync is todo\");\n\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_IsPreferenceValid(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif (numVecIn != 0 || numVecOut != 1)\n\t\t\t\t\treturn 0;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn 0;\n\t\t\t\t// we currently automatically put the preferences into a valid state on session creation if they are not set yet\n\t\t\t\treturn WriteValueOutput<uint32be>(vecOut, 1); // if we return 0, the friend app will show the first time setup screen\n\t\t\t}\n\n\t\t\tnnResult CallHandler_GetRequestBlockSettingAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut) // todo\n\t\t\t{\n\t\t\t\tif (numVecIn != 2 || numVecOut != 1)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInput(count, uint32be, 1);\n\t\t\t\tDeclareInputPtr(pidList, betype<FriendPID>, count, 0);\n\t\t\t\tDeclareOutputPtr(settingList, uint8be, count, 0);\n\t\t\t\tcemuLog_log(LogType::Force, \"GetRequestBlockSettingAsync is todo\");\n\n\t\t\t\tfor (uint32 i = 0; i < count; i++)\n\t\t\t\t\tsettingList[i] = 0;\n\t\t\t\t// implementation is todo. Used by friend list app when adding a friend\n\t\t\t\t// 0 means not blocked. Friend app will continue with GetBasicInformation()\n\t\t\t\t// 1 means blocked. Friend app will continue with AddFriendAsync to add the user as a provisional friend\n\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_AddFriendAsyncByPid(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif (numVecIn != 1 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInput(pid, uint32be, 0);\n\t\t\t\tcemuLog_log(LogType::Force, \"AddFriendAsyncByPid is todo\");\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tnnResult CallHandler_UpdateGameMode(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)\n\t\t\t{\n\t\t\t\tif (numVecIn != 2 || numVecOut != 0)\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\tif (!g_fpd.nexFriendSession)\n\t\t\t\t\treturn FPResult_RequestFailed;\n\t\t\t\tDeclareInputPtr(gameMode, iosu::fpd::GameMode, 1, 0);\n\t\t\t\tuint32 messageLength = vecIn[1].size / sizeof(uint16be);\n\t\t\t\tif(messageLength == 0 || (vecIn[1].size%sizeof(uint16be)) != 0)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"UpdateGameMode: Message must contain at least a null-termination character\");\n\t\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t\t}\n\t\t\t\tDeclareInputPtr(gameModeMessage, uint16be, messageLength, 1);\n\t\t\t\tmessageLength--;\n\t\t\t\tGameModeToNexPresence(gameMode, &g_fpd.myPresence);\n\t\t\t\tg_fpd.nexFriendSession->updateMyPresence(g_fpd.myPresence);\n\t\t\t\t// todo - message\n\t\t\t\treturn FPResult_Ok;\n\t\t\t}\n\n\t\t\tvoid StartFriendSession()\n\t\t\t{\n\t\t\t\tbool expected = false;\n\t\t\t\tif (!g_fpd.sessionStarted.compare_exchange_strong(expected, true))\n\t\t\t\t\treturn;\n\t\t\t\tcemu_assert(!g_fpd.nexFriendSession);\n\t\t\t\tNAPI::AuthInfo authInfo;\n\t\t\t\tNAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);\n\t\t\t\tNAPI::ACTGetNexTokenResult nexTokenResult = NAPI::ACT_GetNexToken_WithCache(authInfo, 0x0005001010001C00, 0x0000, 0x00003200);\n\t\t\t\tif (!nexTokenResult.isValid())\n\t\t\t\t{\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"IOSU_FPD: Failed to acquire nex token for friend server\");\n\t\t\t\t\tg_fpd.myPresence.isOnline = 0;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// get values needed for friend session\n\t\t\t\tuint32 myPid;\n\t\t\t\tuint8 currentSlot = iosu::act::getCurrentAccountSlot();\n\t\t\t\tiosu::act::getPrincipalId(currentSlot, &myPid);\n\t\t\t\tchar accountId[256] = { 0 };\n\t\t\t\tiosu::act::getAccountId(currentSlot, accountId);\n\t\t\t\tFFLData_t miiData;\n\t\t\t\tact::getMii(currentSlot, &miiData);\n\t\t\t\tuint16 screenName[ACT_NICKNAME_LENGTH + 1] = { 0 };\n\t\t\t\tact::getScreenname(currentSlot, screenName);\n\t\t\t\tuint32 countryCode = 0;\n\t\t\t\tact::getCountryIndex(currentSlot, &countryCode);\n\t\t\t\t// init presence\n\t\t\t\tg_fpd.myPresence.isOnline = 1;\n\t\t\t\tif (GetTitleIdHigh(CafeSystem::GetForegroundTitleId()) == 0x00050000)\n\t\t\t\t{\n\t\t\t\t\tg_fpd.myPresence.gameKey.titleId = CafeSystem::GetForegroundTitleId();\n\t\t\t\t\tg_fpd.myPresence.gameKey.ukn = CafeSystem::GetForegroundTitleVersion();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tg_fpd.myPresence.gameKey.titleId = 0; // icon will not be ??? or invalid to others\n\t\t\t\t\tg_fpd.myPresence.gameKey.ukn = 0;\n\t\t\t\t}\n\t\t\t\t// resolve potential domain to IP address\n\t\t\t\tstruct addrinfo hints = {0}, *addrs;\n\t\t\t\thints.ai_family = AF_INET;\n\t\t\t\tconst int status = getaddrinfo(nexTokenResult.nexToken.host, NULL, &hints, &addrs);\n\t\t\t\tif (status != 0)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"IOSU_FPD: Failed to resolve hostname {}\", nexTokenResult.nexToken.host);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tchar addrstr[NI_MAXHOST];\n\t\t\t\tgetnameinfo(addrs->ai_addr, addrs->ai_addrlen, addrstr, sizeof addrstr, NULL, 0, NI_NUMERICHOST);\n\t\t\t\tcemuLog_log(LogType::Force, \"IOSU_FPD: Resolved IP for hostname {}, {}\", nexTokenResult.nexToken.host, addrstr);\n\t\t\t\t// start session\n\t\t\t\tconst uint32_t hostIp = ((struct sockaddr_in*)addrs->ai_addr)->sin_addr.s_addr;\n\t\t\t\tfreeaddrinfo(addrs);\n\t\t\t\tg_fpd.mtxFriendSession.lock();\n\t\t\t\tg_fpd.nexFriendSession = new NexFriends(hostIp, nexTokenResult.nexToken.port, \"ridfebb9\", myPid, nexTokenResult.nexToken.nexPassword, nexTokenResult.nexToken.token, accountId, (uint8*)&miiData, (wchar_t*)screenName, (uint8)countryCode, g_fpd.myPresence);\n\t\t\t\tg_fpd.nexFriendSession->setNotificationHandler(NotificationHandler);\n\t\t\t\tg_fpd.mtxFriendSession.unlock();\n\t\t\t\tcemuLog_log(LogType::Force, \"IOSU_FPD: Created friend server session\");\n\t\t\t}\n\n\t\t\tvoid StopFriendSession()\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(g_fpd.mtxFriendSession);\n\t\t\t\tbool expected = true;\n\t\t\t\tif (!g_fpd.sessionStarted.compare_exchange_strong(expected, false) )\n\t\t\t\t\treturn;\n\t\t\t\tdelete g_fpd.nexFriendSession;\n\t\t\t\tg_fpd.nexFriendSession = nullptr;\n\t\t\t}\n\n\t\t  private:\n\n\n\t\t};\n\n\t\tFPDService gFPDService;\n\n\t\tclass : public ::IOSUModule\n\t\t{\n\t\t\tvoid TitleStart() override\n\t\t\t{\n\t\t\t\tgFPDService.Start();\n\t\t\t\tgFPDService.SetTimerUpdate(1000); // call TimerUpdate() once a second\n\t\t\t}\n\t\t\tvoid TitleStop() override\n\t\t\t{\n\t\t\t\tgFPDService.StopFriendSession();\n\t\t\t\tgFPDService.Stop();\n\t\t\t}\n\t\t}sIOSUModuleNNFPD;\n\n\t\tIOSUModule* GetModule()\n\t\t{\n\t\t\treturn static_cast<IOSUModule*>(&sIOSUModuleNNFPD);\n\t\t}\n\n\t}\n}\n\n"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_fpd.h",
    "content": "#pragma once\n#include \"Cafe/IOSU/iosu_types_common.h\"\n#include \"Common/CafeString.h\"\n\nnamespace iosu\n{\n\tnamespace fpd\n\t{\n\t\tstruct FPDDate\n\t\t{\n\t\t\t/* +0x0 */ uint16be year;\n\t\t\t/* +0x2 */ uint8 month;\n\t\t\t/* +0x3 */ uint8 day;\n\t\t\t/* +0x4 */ uint8 hour;\n\t\t\t/* +0x5 */ uint8 minute;\n\t\t\t/* +0x6 */ uint8 second;\n\t\t\t/* +0x7 */ uint8 padding;\n\t\t};\n\n\t\tstatic_assert(sizeof(FPDDate) == 8);\n\n\t\tstruct RecentPlayRecordEx\n\t\t{\n\t\t\t/* +0x00 */ uint32be pid;\n\t\t\t/* +0x04 */ uint8 ukn04;\n\t\t\t/* +0x05 */ uint8 ukn05;\n\t\t\t/* +0x06 */ uint8 ukn06[0x22];\n\t\t\t/* +0x28 */ uint8 ukn28[0x22];\n\t\t\t/* +0x4A */ uint8 _uknOrPadding4A[6];\n\t\t\t/* +0x50 */ uint32be ukn50;\n\t\t\t/* +0x54 */ uint32be ukn54;\n\t\t\t/* +0x58 */ uint16be ukn58;\n\t\t\t/* +0x5C */ uint8 _padding5C[4];\n\t\t\t/* +0x60 */ iosu::fpd::FPDDate date;\n\t\t};\n\n\t\tstatic_assert(sizeof(RecentPlayRecordEx) == 0x68, \"\");\n\t\tstatic_assert(offsetof(RecentPlayRecordEx, ukn06) == 0x06, \"\");\n\t\tstatic_assert(offsetof(RecentPlayRecordEx, ukn50) == 0x50, \"\");\n\n\t\tstruct GameKey\n\t\t{\n\t\t\t/* +0x00 */ uint64be titleId;\n\t\t\t/* +0x08 */ uint16be ukn08;\n\t\t\t/* +0x0A */ uint8 _padding0A[6];\n\t\t};\n\t\tstatic_assert(sizeof(GameKey) == 0x10);\n\n\t\tstruct Profile\n\t\t{\n\t\t\tuint8be region;\n\t\t\tuint8be regionSubcode;\n\t\t\tuint8be platform;\n\t\t\tuint8be ukn3;\n\t\t};\n\t\tstatic_assert(sizeof(Profile) == 0x4);\n\n\t\tstruct GameMode\n\t\t{\n\t\t\t/* +0x00 */ uint32be joinFlagMask;\n\t\t\t/* +0x04 */ uint32be matchmakeType;\n\t\t\t/* +0x08 */ uint32be joinGameId;\n\t\t\t/* +0x0C */ uint32be joinGameMode;\n\t\t\t/* +0x10 */ uint32be hostPid;\n\t\t\t/* +0x14 */ uint32be groupId;\n\t\t\t/* +0x18 */ uint8    appSpecificData[0x14];\n\t\t};\n\t\tstatic_assert(sizeof(GameMode) == 0x2C);\n\n\t\tstruct FriendData\n\t\t{\n\t\t\t/* +0x000 */ uint8 type; // type (Non-Zero -> Friend, 0 -> Friend request ? )\n\t\t\t/* +0x001 */ uint8 _padding1[7];\n\t\t\t/* +0x008 */ uint32be pid;\n\t\t\t/* +0x00C */ char nnid[0x10 + 1];\n\t\t\t/* +0x01D */ uint8 ukn01D;\n\t\t\t/* +0x01E */ uint8 _padding1E[2];\n\t\t\t/* +0x020 */ uint16be screenname[10 + 1];\n\t\t\t/* +0x036 */ uint8 ukn036;\n\t\t\t/* +0x037 */ uint8 _padding037;\n\t\t\t/* +0x038 */ uint8 mii[0x60];\n\t\t\t/* +0x098 */ FPDDate uknDate;\n\t\t\t// sub struct (the part above seems to be shared with friend requests)\n\t\t\tunion\n\t\t\t{\n\t\t\t\tstruct \n\t\t\t\t{\n\t\t\t\t\t/* +0x0A0 */ Profile profile; // this is returned for nn_fp.GetFriendProfile\n\t\t\t\t\t/* +0x0A4 */ uint32be ukn0A4;\n\t\t\t\t\t/* +0x0A8 */ GameKey gameKey;\n\t\t\t\t\t/* +0x0B8 */ GameMode gameMode;\n\t\t\t\t\t/* +0x0E4 */ CafeWideString<0x82> gameModeDescription;\n\t\t\t\t\t/* +0x1E8 */ Profile profile1E8; // how does it differ from the one at 0xA0? Returned by GetFriendPresence\n\t\t\t\t\t/* +0x1EC */ uint8 isOnline;\n\t\t\t\t\t/* +0x1ED */ uint8 _padding1ED[3];\n\t\t\t\t\t// some other sub struct?\n\t\t\t\t\t/* +0x1F0 */ CafeWideString<0x12> comment; // pops up every few seconds in friend list\n\t\t\t\t\t/* +0x214 */ uint32be _padding214;\n\t\t\t\t\t/* +0x218 */ FPDDate approvalTime;\n\t\t\t\t\t/* +0x220 */ FPDDate lastOnline;\n\t\t\t\t}friendExtraData;\n\t\t\t\tstruct \n\t\t\t\t{\n\t\t\t\t\t/* +0x0A0 */ uint64be messageId; // guessed. If 0, then relationship is FRIENDSHIP_REQUEST_OUT, otherwise FRIENDSHIP_REQUEST_IN\n\t\t\t\t\t/* +0x0A8 */ uint8 ukn0A8;\n\t\t\t\t\t/* +0x0A9 */ uint8 ukn0A9; // comment language? (guessed)\n\t\t\t\t\t/* +0x0AA */ uint16be comment[0x40];\n\t\t\t\t\t/* +0x12A */ uint8 ukn12A; // ingame name language? (guessed)\n\t\t\t\t\t/* +0x12B */ uint8 _padding12B;\n\t\t\t\t\t/* +0x12C */ uint16be uknMessage[18]; // exact length unknown, could be shorter (ingame screen name?)\n\t\t\t\t\t/* +0x150 */ uint64 gameKeyTitleId;\n\t\t\t\t\t/* +0x158 */ uint16be gameKeyUkn;\n\t\t\t\t\t/* +0x15A */ uint8 _padding[6];\n\t\t\t\t\t/* +0x160 */ FPDDate uknData0;\n\t\t\t\t\t/* +0x168 */ FPDDate uknData1;\n\t\t\t\t}requestExtraData;\n\t\t\t};\n\t\t};\n\t\tstatic_assert(sizeof(FriendData) == 0x228);\n\t\tstatic_assert(offsetof(FriendData, friendExtraData.gameKey) == 0x0A8);\n\t\tstatic_assert(offsetof(FriendData, friendExtraData.gameModeDescription) == 0x0E4);\n\t\tstatic_assert(offsetof(FriendData, friendExtraData.comment) == 0x1F0);\n\t\t\n\t\tstatic_assert(offsetof(FriendData, requestExtraData.messageId) == 0x0A0);\n\t\tstatic_assert(offsetof(FriendData, requestExtraData.comment) == 0x0AA);\n\t\tstatic_assert(offsetof(FriendData, requestExtraData.uknMessage) == 0x12C);\n\t\tstatic_assert(offsetof(FriendData, requestExtraData.gameKeyTitleId) == 0x150);\n\t\tstatic_assert(offsetof(FriendData, requestExtraData.uknData1) == 0x168);\n\n\t\tstruct FriendBasicInfo\n\t\t{\n\t\t\t/* +0x00 */ uint32be pid;\n\t\t\t/* +0x04 */ char nnid[0x11];\n\t\t\t/* +0x15 */ uint8 ukn15;\n\t\t\t/* +0x16 */ uint8 uknOrPadding[2];\n\t\t\t/* +0x18 */ uint16be screenname[11];\n\t\t\t/* +0x2E */ uint8 ukn2E; // bool option\n\t\t\t/* +0x2F */ uint8 ukn2F;\n\t\t\t/* +0x30 */ uint8 miiData[0x60];\n\t\t\t/* +0x90 */ FPDDate uknDate90;\n\t\t};\n\n\t\tstatic_assert(sizeof(FriendBasicInfo) == 0x98);\n\t\tstatic_assert(offsetof(FriendBasicInfo, nnid) == 0x04);\n\t\tstatic_assert(offsetof(FriendBasicInfo, ukn15) == 0x15);\n\t\tstatic_assert(offsetof(FriendBasicInfo, screenname) == 0x18);\n\t\tstatic_assert(offsetof(FriendBasicInfo, ukn2E) == 0x2E);\n\t\tstatic_assert(offsetof(FriendBasicInfo, miiData) == 0x30);\n\n\t\tstruct FriendRequest\n\t\t{\n\t\t\t/* +0x000 */ uint32be pid;\n\t\t\t/* +0x004 */ uint8 nnid[17]; // guessed type\n\t\t\t/* +0x015 */ uint8 _uknOrPadding15;\n\t\t\t/* +0x016 */ uint8 _uknOrPadding16;\n\t\t\t/* +0x017 */ uint8 _uknOrPadding17;\n\t\t\t/* +0x018 */ uint16be screenname[11];\n\t\t\t/* +0x02E */ uint8 ukn2E; // bool option\n\t\t\t/* +0x02F */ uint8 ukn2F;  // ukn\n\t\t\t/* +0x030 */ uint8 miiData[0x60];\n\t\t\t/* +0x090 */ FPDDate uknDate;\n\t\t\t/* +0x098 */ uint64 ukn98;\n\t\t\t/* +0x0A0 */ uint8 isMarkedAsReceived;\n\t\t\t/* +0x0A1 */ uint8 uknA1;\n\t\t\t/* +0x0A2 */ uint16be message[0x40];\n\t\t\t/* +0x122 */ uint8 ukn122;\n\t\t\t/* +0x123 */ uint8 _padding123;\n\t\t\t/* +0x124 */ uint16be uknString2[18];\n\t\t\t/* +0x148 */ uint64 gameKeyTitleId;\n\t\t\t/* +0x150 */ uint16be gameKeyUkn;\n\t\t\t/* +0x152 */ uint8 _padding152[6];\n\t\t\t/* +0x158 */ FPDDate uknDate2;\n\t\t\t/* +0x160 */ FPDDate expireDate;\n\t\t};\n\n\t\tstatic_assert(sizeof(FriendRequest) == 0x168);\n\t\tstatic_assert(offsetof(FriendRequest, uknDate) == 0x090);\n\t\tstatic_assert(offsetof(FriendRequest, message) == 0x0A2);\n\t\tstatic_assert(offsetof(FriendRequest, uknString2) == 0x124);\n\t\tstatic_assert(offsetof(FriendRequest, gameKeyTitleId) == 0x148);\n\n\t\tstruct FriendPresence\n\t\t{\n\t\t\tGameMode gameMode;\n\t\t\t/* +0x2C */ Profile  profile;\n\t\t\t/* +0x30 */ uint8\t isOnline;\n\t\t\t/* +0x31 */ uint8    isValid;\n\t\t\t/* +0x32 */ uint8\t padding[2]; // guessed\n\t\t};\n\t\tstatic_assert(sizeof(FriendPresence) == 0x34);\n\t\tstatic_assert(offsetof(FriendPresence, isOnline) == 0x30);\n\n\t\tstruct FPDNotification\n\t\t{\n\t\t\tbetype<uint32> type;\n\t\t\tbetype<uint32> pid;\n\t\t};\n\t\tstatic_assert(sizeof(FPDNotification) == 8);\n\n\t\tstruct FPDPreference\n\t\t{\n\t\t\tuint8be showOnline; // show online status to others\n\t\t\tuint8be showGame; // show played game to others\n\t\t\tuint8be blockFriendRequests; // block friend requests\n\t\t\tuint8be ukn; // probably padding?\n\t\t};\n\t\tstatic_assert(sizeof(FPDPreference) == 4);\n\n\t\tstatic const int RELATIONSHIP_INVALID = 0;\n\t\tstatic const int RELATIONSHIP_FRIENDREQUEST_OUT = 1;\n\t\tstatic const int RELATIONSHIP_FRIENDREQUEST_IN = 2;\n\t\tstatic const int RELATIONSHIP_FRIEND = 3;\n\n\t\tstatic const int GAMEMODE_MAX_MESSAGE_LENGTH = 0x80; // limit includes null-terminator character, so only 0x7F actual characters can be used\n\t\tstatic const int MY_COMMENT_LENGTH = 0x12;\n\n\t\tenum class FPD_REQUEST_ID\n\t\t{\n\t\t\tLoginAsync = 0x2775,\n\t\t\tHasLoggedIn = 0x2777,\n\t\t\tIsOnline = 0x2778,\n\t\t\tGetMyPrincipalId = 0x27D9,\n\t\t\tGetMyAccountId = 0x27DA,\n\t\t\tGetMyScreenName = 0x27DB,\n\t\t\tGetMyMii = 0x27DC,\n\t\t\tGetMyProfile = 0x27DD,\n\t\t\tGetMyPreference = 0x27DE,\n\t\t\tGetMyPresence = 0x27DF,\n\t\t\tIsPreferenceValid = 0x27E0,\n\t\t\tGetFriendList = 0x283D,\n\t\t\tGetFriendListAll = 0x283E,\n\t\t\tGetFriendAccountId = 0x283F,\n\t\t\tGetFriendScreenName = 0x2840,\n\t\t\tGetFriendPresence = 0x2845,\n\t\t\tGetFriendRelationship = 0x2846,\n\t\t\tGetFriendMii = 0x2841,\n\t\t\tGetBlackList = 0x28A1,\n\t\t\tGetFriendRequestList = 0x2905,\n\t\t\tUpdateGameModeVariation1 = 0x2969, // there seem to be two different requestIds for the 2-param and 3-param version of UpdateGameMode,\n\t\t\tUpdateGameModeVariation2 = 0x296A, // but the third parameter is never used and the same handler is used for both\n\t\t\tAddFriendAsyncByPid = 0x29CD,\n\t\t\tAddFriendAsyncByXXX = 0x29CE, // probably by name?\n\t\t\tGetRequestBlockSettingAsync = 0x2B5D,\n\t\t\tGetMyComment = 0x4EE9,\n\t\t\tGetMyPlayingGame = 0x4EEA,\n\t\t\tCheckSettingStatusAsync = 0x7596,\n\t\t\tGetFriendListEx = 0x75F9,\n\t\t\tGetFriendRequestListEx = 0x76C1,\n\t\t\tUpdateCommentAsync = 0x7726,\n\t\t\tUpdatePreferenceAsync = 0x7727,\n\t\t\tRemoveFriendAsync = 0x7789,\n\t\t\tDeleteFriendFlagsAsync = 0x778A,\n\t\t\tAddFriendRequestByPlayRecordAsync = 0x778B,\n\t\t\tCancelFriendRequestAsync = 0x778C,\n\t\t\tAcceptFriendRequestAsync = 0x7851,\n\t\t\tDeleteFriendRequestAsync = 0x7852,\n\t\t\tMarkFriendRequestsAsReceivedAsync = 0x7854,\n\t\t\tGetBasicInfoAsync = 0x7919,\n\t\t\tSetLedEventMask = 0x9D0B,\n\t\t\tSetNotificationMask = 0x15ff5,\n\t\t\tGetNotificationAsync = 0x15FF6,\n\t\t};\n\n\t\tusing FriendPID = uint32;\n\n\t\tIOSUModule* GetModule();\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_ioctl.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"iosu_ioctl.h\"\n#include \"util/helpers/ringbuffer.h\"\n\n#include \"util/helpers/Semaphore.h\"\n\n// deprecated IOCTL handling code\n\nRingBuffer<ioQueueEntry_t*, 256> _ioctlRingbuffer[IOS_DEVICE_COUNT];\nCounterSemaphore _ioctlRingbufferSemaphore[IOS_DEVICE_COUNT];\n\nstd::mutex ioctlMutex;\n\nsint32 iosuIoctl_pushAndWait(uint32 ioctlHandle, ioQueueEntry_t* ioQueueEntry)\n{\n\tif (ioctlHandle != IOS_DEVICE_ACT && ioctlHandle != IOS_DEVICE_ACP_MAIN && ioctlHandle != IOS_DEVICE_MCP && ioctlHandle != IOS_DEVICE_BOSS && ioctlHandle != IOS_DEVICE_NIM && ioctlHandle != IOS_DEVICE_FPD)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Unsupported IOSU device {}\", ioctlHandle);\n\t\tcemu_assert_debug(false);\n\t\treturn 0;\n\t}\n\t__OSLockScheduler();\n\tioctlMutex.lock();\n\tioQueueEntry->ppcThread = coreinit::OSGetCurrentThread();\n\t\n\t_ioctlRingbuffer[ioctlHandle].Push(ioQueueEntry);\n\tioctlMutex.unlock();\n\t_ioctlRingbufferSemaphore[ioctlHandle].increment();\n\tcoreinit::__OSSuspendThreadInternal(coreinit::OSGetCurrentThread());\n\tif (ioQueueEntry->isCompleted == false)\n\t\tassert_dbg();\n\t__OSUnlockScheduler();\n\treturn ioQueueEntry->returnValue;\n}\n\nioQueueEntry_t* iosuIoctl_getNextWithWait(uint32 deviceIndex)\n{\n\t_ioctlRingbufferSemaphore[deviceIndex].decrementWithWait();\n\tif (_ioctlRingbuffer[deviceIndex].HasData() == false)\n\t\tassert_dbg();\n\treturn _ioctlRingbuffer[deviceIndex].Pop();\n}\n\nioQueueEntry_t* iosuIoctl_getNextWithTimeout(uint32 deviceIndex, sint32 ms)\n{\n\tif (!_ioctlRingbufferSemaphore[deviceIndex].decrementWithWaitAndTimeout(ms))\n\t\treturn nullptr; // timeout or spurious wake up\n\tif (_ioctlRingbuffer[deviceIndex].HasData() == false)\n\t\treturn nullptr;\n\treturn _ioctlRingbuffer[deviceIndex].Pop();\n}\n\nvoid iosuIoctl_completeRequest(ioQueueEntry_t* ioQueueEntry, uint32 returnValue)\n{\n\tioQueueEntry->returnValue = returnValue;\n\tioQueueEntry->isCompleted = true;\n\tcoreinit::OSResumeThread(ioQueueEntry->ppcThread);\n}\n\nvoid iosuIoctl_init()\n{\n\tfor (sint32 i = 0; i < IOS_DEVICE_COUNT; i++)\n\t{\n\t\t_ioctlRingbuffer[i].Clear();\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_ioctl.h",
    "content": "#pragma once\n\nstruct OSThread_t;\n\ntypedef struct _ioBufferVector_t\n{\n\t// the meaning of these values might be arbitrary? (up to the /dev/* handler to process them)\n\t//uint32 ukn00;\n\tMEMPTR<uint8> buffer;\n\tuint32be bufferSize;\n\tuint32 ukn08;\n\t//uint32 ukn0C;\n\tMEMPTR<uint8> unknownBuffer;\n}ioBufferVector_t;\n\ntypedef struct\n{\n\tbool isIoctlv; // false -> ioctl, true -> ioctlv\n\tbool isAsync;\n\tuint32 request;\n\tuint32 countIn;\n\tuint32 countOut;\n\tMEMPTR<ioBufferVector_t> bufferVectors;\n\t// info about submitter\n\tOSThread_t* ppcThread;\n\t//MPTR ppcThread;\n\t// result\n\tbool isCompleted;\n\tuint32 returnValue;\n}ioQueueEntry_t;\n\n\n#define IOS_PATH_SOCKET\t\t\"/dev/socket\"\n#define IOS_PATH_ODM\t\t\"/dev/odm\"\n#define IOS_PATH_ACT\t\t\"/dev/act\"\n#define IOS_PATH_FPD\t\t\"/dev/fpd\"\n#define IOS_PATH_ACP_MAIN\t\"/dev/acp_main\"\n#define IOS_PATH_MCP\t\t\"/dev/mcp\"\n#define IOS_PATH_BOSS\t\t\"/dev/boss\"\n#define IOS_PATH_NIM\t\t\"/dev/nim\"\n#define IOS_PATH_IOSUHAX\t\"/dev/iosuhax\"\n\n#define IOS_DEVICE_UKN\t\t(0x1)\n#define IOS_DEVICE_ODM\t\t(0x2)\n#define IOS_DEVICE_SOCKET\t(0x3)\n#define IOS_DEVICE_ACT\t\t(0x4)\n#define IOS_DEVICE_FPD\t\t(0x5)\n#define IOS_DEVICE_ACP_MAIN\t(0x6)\n#define IOS_DEVICE_MCP\t\t(0x7)\n#define IOS_DEVICE_BOSS\t\t(0x8)\n#define IOS_DEVICE_NIM\t\t(0x9)\n\n#define IOS_DEVICE_COUNT\t10\n\nvoid iosuIoctl_init();\n\n\n// for use by IOSU\nioQueueEntry_t* iosuIoctl_getNextWithWait(uint32 deviceIndex);\nioQueueEntry_t* iosuIoctl_getNextWithTimeout(uint32 deviceIndex, sint32 ms);\nvoid iosuIoctl_completeRequest(ioQueueEntry_t* ioQueueEntry, uint32 returnValue);\n\n// for use by PPC\nsint32 iosuIoctl_pushAndWait(uint32 ioctlHandle, ioQueueEntry_t* ioQueueEntry);\n"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_mcp.cpp",
    "content": "#include \"iosu_ioctl.h\"\n#include \"iosu_mcp.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"util/tinyxml2/tinyxml2.h\"\n\n#include \"config/CemuConfig.h\"\n#include \"Cafe/TitleList/GameInfo.h\"\n#include \"util/helpers/helpers.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/IOSU/iosu_ipc_common.h\"\n#include \"Cafe/IOSU/kernel/iosu_kernel.h\"\n\nusing namespace iosu::kernel;\n\nnamespace iosu\n{\n\tstruct\n\t{\n\t\tbool isInitialized;\n\t}iosuMcp = { 0 };\n\n\tstd::recursive_mutex sTitleInfoMutex;\n\n\tbool sHasAllTitlesMounted = false;\n\n\tuint32 mcpBuildTitleList(MCPTitleInfo* titleList, uint32 maxTitlesToCopy, std::function<bool(const TitleInfo&)> filterFunc)\n\t{\n\t\tCafeTitleList::WaitForMandatoryScan();\n\t\tstd::set<TitleId> titleIdsVisited;\n\t\tauto cafeTitleList = CafeTitleList::AcquireInternalList();\n\n\t\tuint32 numTitlesCopied = 0;\n\t\tfor (auto& it : cafeTitleList)\n\t\t{\n\t\t\tif (numTitlesCopied == maxTitlesToCopy)\n\t\t\t\tbreak;\n\t\t\tuint64 titleId = it->GetAppTitleId();\n\t\t\tif (titleIdsVisited.find(titleId) != titleIdsVisited.end())\n\t\t\t\tcontinue;\n\t\t\tif (!filterFunc(*it))\n\t\t\t\tcontinue;\n\t\t\ttitleIdsVisited.emplace(titleId);\n\t\t\tif (titleList)\n\t\t\t{\n\t\t\t\tauto& titleOut = titleList[numTitlesCopied];\n\t\t\t\ttitleOut.titleIdHigh = (uint32)(titleId >> 32);\n\t\t\t\ttitleOut.titleIdLow = (uint32)(titleId & 0xFFFFFFFF);\n\t\t\t\ttitleOut.titleVersion = it->GetAppTitleVersion();\n\t\t\t\ttitleOut.appGroup = it->GetAppGroup();\n\t\t\t\ttitleOut.appType = it->GetAppType();\n\n\t\t\t\tstd::string titlePath = CafeSystem::GetMlcStoragePath(titleId);\n\t\t\t\tstrcpy(titleOut.appPath, titlePath.c_str());\n\n\t\t\t\tstrcpy((char*)titleOut.deviceName, \"mlc\");\n\n\t\t\t\ttitleOut.osVersion = 0; // todo\n\t\t\t\ttitleOut.sdkVersion = it->GetAppSDKVersion();\n\t\t\t}\n\n\t\t\tnumTitlesCopied++;\n\t\t}\n\t\tCafeTitleList::ReleaseInternalList();\n\n\t\tif (!sHasAllTitlesMounted)\n\t\t{\n\t\t\tCafeSystem::MlcStorageMountAllTitles();\n\t\t\tsHasAllTitlesMounted = true;\n\t\t}\n\n\t\treturn numTitlesCopied;\n\t}\n\n\tsint32 mcpGetTitleList(MCPTitleInfo* titleList, uint32 titleListBufferSize, uint32be* titleCount)\n\t{\n\t\tstd::unique_lock _lock(sTitleInfoMutex);\n\t\tuint32 maxEntryCount = titleListBufferSize / sizeof(MCPTitleInfo);\n\t\t*titleCount = mcpBuildTitleList(titleList, maxEntryCount, [](const TitleInfo& titleInfo) -> bool { return true; });\n\t\treturn 0;\n\t}\n\n\tsint32 mcpGetTitleCount()\n\t{\n\t\tstd::unique_lock _lock(sTitleInfoMutex);\n\t\treturn mcpBuildTitleList(nullptr, 0xFFFFFFFF, [](const TitleInfo& titleInfo) -> bool { return true; });\n\t}\n\n\tsint32 mcpGetTitleListByAppType(MCPTitleInfo* titleList, uint32 titleListBufferSize, uint32be* titleCount, uint32 appType)\n\t{\n\t\tstd::unique_lock _lock(sTitleInfoMutex);\n\t\tuint32 maxEntryCount = titleListBufferSize / sizeof(MCPTitleInfo);\n\t\t*titleCount = mcpBuildTitleList(titleList, maxEntryCount, [appType](const TitleInfo& titleInfo) -> bool { return titleInfo.GetAppType() == appType; });\n\t\treturn 0;\n\t}\n\n\tsint32 mcpGetTitleListByTitleId(MCPTitleInfo* titleList, uint32 titleListBufferSize, uint32be* titleCount, uint64 titleId)\n\t{\n\t\tstd::unique_lock _lock(sTitleInfoMutex);\n\t\tuint32 maxEntryCount = titleListBufferSize / sizeof(MCPTitleInfo);\n\t\t*titleCount = mcpBuildTitleList(titleList, maxEntryCount, [titleId](const TitleInfo& titleInfo) -> bool { return titleInfo.GetAppTitleId() == titleId; });\n\t\treturn 0;\n\t}\n\n\tint iosuMcp_thread()\n\t{\n\t\tSetThreadName(\"iosuMcp_thread\");\n\t\twhile (true)\n\t\t{\n\t\t\tuint32 returnValue = 0; // Ioctl return value\n\t\t\tioQueueEntry_t* ioQueueEntry = iosuIoctl_getNextWithWait(IOS_DEVICE_MCP);\n\t\t\tif (ioQueueEntry->request == IOSU_MCP_REQUEST_CEMU)\n\t\t\t{\n\t\t\t\tiosuMcpCemuRequest_t* mcpCemuRequest = (iosuMcpCemuRequest_t*)ioQueueEntry->bufferVectors[0].buffer.GetPtr();\n\t\t\t\tif (mcpCemuRequest->requestCode == IOSU_MCP_GET_TITLE_LIST)\n\t\t\t\t{\n\t\t\t\t\tuint32be titleCount = mcpCemuRequest->titleListRequest.titleCount;\n\t\t\t\t\tmcpCemuRequest->returnCode = mcpGetTitleList(mcpCemuRequest->titleListRequest.titleList.GetPtr(), mcpCemuRequest->titleListRequest.titleListBufferSize, &titleCount);\n\t\t\t\t\tmcpCemuRequest->titleListRequest.titleCount = titleCount;\n\t\t\t\t}\n\t\t\t\telse if (mcpCemuRequest->requestCode == IOSU_MCP_GET_TITLE_LIST_BY_APP_TYPE)\n\t\t\t\t{\n\t\t\t\t\tuint32be titleCount = mcpCemuRequest->titleListRequest.titleCount;\n\t\t\t\t\tmcpCemuRequest->returnCode = mcpGetTitleListByAppType(mcpCemuRequest->titleListRequest.titleList.GetPtr(), mcpCemuRequest->titleListRequest.titleListBufferSize, &titleCount, mcpCemuRequest->titleListRequest.appType);\n\t\t\t\t\tmcpCemuRequest->titleListRequest.titleCount = titleCount;\n\t\t\t\t}\n\t\t\t\telse if (mcpCemuRequest->requestCode == IOSU_MCP_GET_TITLE_INFO)\n\t\t\t\t{\n\t\t\t\t\tuint32be titleCount = mcpCemuRequest->titleListRequest.titleCount;\n\t\t\t\t\tmcpCemuRequest->returnCode = mcpGetTitleListByTitleId(mcpCemuRequest->titleListRequest.titleList.GetPtr(), mcpCemuRequest->titleListRequest.titleListBufferSize, &titleCount, mcpCemuRequest->titleListRequest.titleId);\n\t\t\t\t\tmcpCemuRequest->titleListRequest.titleCount = titleCount;\n\t\t\t\t}\n\t\t\t\telse if (mcpCemuRequest->requestCode == IOSU_MCP_GET_TITLE_COUNT)\n\t\t\t\t{\n\t\t\t\t\tuint32be titleCount = mcpGetTitleCount();\n\t\t\t\t\tmcpCemuRequest->returnCode = titleCount;\n\t\t\t\t\tmcpCemuRequest->titleListRequest.titleCount = titleCount;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t\tiosuIoctl_completeRequest(ioQueueEntry, returnValue);\n\t\t}\n\t\treturn 0;\n\t}\n\n    // deprecated\n\tvoid iosuMcp_init()\n\t{\n\t\tif (iosuMcp.isInitialized)\n\t\t\treturn;\n\t\tstd::thread t(iosuMcp_thread);\n\t\tt.detach();\n\t\tiosuMcp.isInitialized = true;\n\t}\n\n\tnamespace mcp\n\t{\n\t\tIOSMsgQueueId sMCPIoMsgQueue;\n\t\tSysAllocator<iosu::kernel::IOSMessage, 352> _m_sMCPIoMsgQueueMsgBuffer;\n\t\tstd::thread sMCPIoThread;\n\n\t\tstruct MCPClient\n\t\t{\n\t\t\tstd::string workingDirectory;\n\t\t\tbool isAllocated{ false };\n\n\t\t\tvoid AllocateAndInitialize()\n\t\t\t{\n\t\t\t\tisAllocated = true;\n\t\t\t\tworkingDirectory = std::string(\"/\");\n\t\t\t}\n\n\t\t\tvoid ReleaseAndCleanup()\n\t\t\t{\n\t\t\t\tisAllocated = false;\n\t\t\t}\n\t\t};\n\n\t\tstd::array<MCPClient, 256> sMCPClientArray;\n\n\t\tIOS_ERROR MCPAllocateClient(sint32& indexOut)\n\t\t{\n\t\t\tfor (size_t i = 0; i < sMCPClientArray.size(); i++)\n\t\t\t{\n\t\t\t\tif (sMCPClientArray[i].isAllocated)\n\t\t\t\t\tcontinue;\n\t\t\t\tsMCPClientArray[i].AllocateAndInitialize();\n\t\t\t\tindexOut = (sint32)i;\n\t\t\t\treturn IOS_ERROR_OK;\n\t\t\t}\n\t\t\treturn IOS_ERROR::IOS_ERROR_MAXIMUM_REACHED;\n\t\t}\n\n\t\tvoid MCPIoThread()\n\t\t{\n\t\t\tSetThreadName(\"IOSU-MCP\");\n\t\t\tIOSMessage msg;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tIOS_ERROR r = IOS_ReceiveMessage(sMCPIoMsgQueue, &msg, 0);\n\t\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t\t\tif (msg == 0)\n\t\t\t\t\treturn; // shutdown signaled\n\t\t\t\tIPCCommandBody* cmd = MEMPTR<IPCCommandBody>(msg).GetPtr();\n\t\t\t\tuint32 clientHandle = (uint32)cmd->devHandle;\n\t\t\t\tif (cmd->cmdId == IPCCommandId::IOS_OPEN)\n\t\t\t\t{\n\t\t\t\t\tsint32 clientIndex = 0;\n\t\t\t\t\tr = MCPAllocateClient(clientIndex);\n\t\t\t\t\tif (r != IOS_ERROR_OK)\n\t\t\t\t\t{\n\t\t\t\t\t\tIOS_ResourceReply(cmd, r);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tIOS_ResourceReply(cmd, (IOS_ERROR)clientIndex);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_CLOSE)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert(clientHandle < sMCPClientArray.size());\n\t\t\t\t\tsMCPClientArray[clientHandle].ReleaseAndCleanup();\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_OK);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_IOCTL)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert(clientHandle < sMCPClientArray.size());\n\t\t\t\t\tcemu_assert(sMCPClientArray[clientHandle].isAllocated);\n\t\t\t\t\tIOS_ResourceReply(cmd, (IOS_ERROR)0x80000000);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_IOCTLV)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t\t//uint32 requestId = cmd->args[0];\n\t\t\t\t\t//uint32 numIn = cmd->args[1];\n\t\t\t\t\t//uint32 numOut = cmd->args[2];\n\t\t\t\t\t//IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>{ cmd->args[3] }.GetPtr();\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_INVALID);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"/dev/mcp: Unsupported IPC cmdId\");\n\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_INVALID);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid Init()\n\t\t{\n\t\t\tfor (auto& it : sMCPClientArray)\n\t\t\t\tit.ReleaseAndCleanup();\n\t\t\tsMCPIoMsgQueue = (IOSMsgQueueId)IOS_CreateMessageQueue(_m_sMCPIoMsgQueueMsgBuffer.GetPtr(), _m_sMCPIoMsgQueueMsgBuffer.GetCount());\n\t\t\tIOS_ERROR r = IOS_RegisterResourceManager(\"/dev/mcp\", sMCPIoMsgQueue);\n\t\t\tIOS_DeviceAssociateId(\"/dev/mcp\", 11);\n\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t\tsMCPIoThread = std::thread(MCPIoThread);\n\t\t}\n\n\t\tvoid Shutdown()\n\t\t{\n\t\t\tIOS_SendMessage(sMCPIoMsgQueue, 0, 0);\n\t\t\tsMCPIoThread.join();\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_mcp.h",
    "content": "\n#pragma pack(1)\n\nstruct MCPTitleInfo\n{\n\n\t/* +0x00 */ uint32be titleIdHigh; // app.xml\n\t/* +0x04 */ uint32be titleIdLow;\n\t/* +0x08 */ uint32be appGroup;\n\t/* +0x0C */ char appPath[0x38]; // size guessed\n\t/* +0x44 */ uint32be appType; // app.xml\n\t/* +0x48 */ uint16be titleVersion; // app.xml\n\t// everything below is uncertain\n\t/* +0x4A */ uint64be osVersion; // app.xml\n\t/* +0x52 */ uint32be sdkVersion; // app.xml\n\t/* +0x56 */ uint8 deviceName[10];\n\t/* +0x60 */ uint8 uknPadding; // possibly the index of the device?\n\t//move this and the stuff below\n};\n\nstatic_assert(sizeof(MCPTitleInfo) == 0x61);\n\n#pragma pack()\n\n// custom dev/mcp protocol (Cemu only)\n#define IOSU_MCP_REQUEST_CEMU (0xEE)\n\ntypedef struct\n{\n\tuint32 requestCode;\n\tstruct  \n\t{\n\t\tMEMPTR<MCPTitleInfo> titleList;\n\t\tuint32be titleCount;\n\t\tuint32be titleListBufferSize;\n\t\tuint64 titleId;\n\t\t// filters\n\t\tuint32be appType;\n\t}titleListRequest;\n\n\t// output\n\tuint32 returnCode; // ACP return value\n\tunion\n\t{\n\t\t//struct\n\t\t//{\n\t\t//\tuint64 u64;\n\t\t//}resultU64;\n\t\tstruct\n\t\t{\n\t\t\tuint32 u32;\n\t\t}resultU32;\n\t\t//struct\n\t\t//{\n\t\t//\tchar strBuffer[1024];\n\t\t//}resultString;\n\t\t//struct\n\t\t//{\n\t\t//\tuint8 binBuffer[1024];\n\t\t//}resultBinary;\n\t};\n}iosuMcpCemuRequest_t;\n\n// MCP request Cemu subcodes\n#define IOSU_MCP_GET_TITLE_LIST\t\t\t\t\t\t\t\t0x01\n#define IOSU_MCP_GET_TITLE_LIST_BY_APP_TYPE\t\t\t\t\t0x02\n#define IOSU_MCP_GET_TITLE_INFO\t\t\t\t\t\t\t\t0x03\t// get title list by titleId\n#define IOSU_MCP_GET_TITLE_COUNT\t\t\t\t\t\t\t0x04\n\nnamespace iosu\n{\n\tsint32 mcpGetTitleCount();\n\tsint32 mcpGetTitleList(MCPTitleInfo* titleList, uint32 titleListBufferSize, uint32be* titleCount);\n\n\tvoid iosuMcp_init();\n\n\tnamespace mcp\n\t{\n\t\tvoid Init();\n\t\tvoid Shutdown();\n\t};\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_nim.cpp",
    "content": "#include \"iosu_nim.h\"\n#include \"iosu_ioctl.h\"\n#include \"iosu_act.h\"\n#include \"iosu_mcp.h\"\n#include \"util/crypto/aes128.h\"\n#include \"curl/curl.h\"\n#include \"openssl/bn.h\"\n#include \"openssl/x509.h\"\n#include \"openssl/ssl.h\"\n#include \"util/helpers/helpers.h\"\n#include \"Cemu/napi/napi.h\"\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"Cafe/CafeSystem.h\"\n\nnamespace iosu\n{\n\tnamespace nim\n\t{\n\t\tstruct NIMTitleLatestVersion\n\t\t{\n\t\t\tuint64 titleId;\n\t\t\tuint32 version;\n\t\t};\n\n#define PACKAGE_TYPE_UPDATE\t\t(1)\n\n\t\tstruct NIMPackage\n\t\t{\n\t\t\tuint64 titleId;\n\t\t\tuint16 version;\n\t\t\tuint8 type;\n\t\t};\n\n\t\tstruct\n\t\t{\n\t\t\tbool isInitialized;\n\t\t\t// version list\n\t\t\tsint32 latestVersion;\n\t\t\tchar fqdn[256];\n\t\t\tstd::vector<NIMTitleLatestVersion> titlesLatestVersion;\n\t\t\t// nim packages\n\t\t\t// note: Seems like scope.rpx expects the number of packages to never change after the initial GetNum call?\n\t\t\tstd::vector<NIMPackage> packages;\n\t\t\tbool packageListReady;\n\t\t\tbool backgroundThreadStarted;\n\t\t} g_nim = {};\n\n\t\tbool nim_CheckDownloadsDisabled()\n\t\t{\n\t\t\t// currently for the Wii U menu we disable NIM to speed up boot times\n\t\t\tuint64 tid = CafeSystem::GetForegroundTitleId();\n\t\t\treturn tid == 0x0005001010040000 || tid == 0x0005001010040100 || tid == 0x0005001010040200;\n\t\t}\n\n\t\tbool nim_getLatestVersion()\n\t\t{\n\t\t\tg_nim.latestVersion = -1;\n\t\t\tNAPI::AuthInfo authInfo;\n\t\t\tauthInfo.country = NCrypto::GetCountryAsString(Account::GetCurrentAccount().GetCountry());\n\t\t\tauthInfo.region = NCrypto::SEEPROM_GetRegion();\n\t\t\tauto versionListVersionResult = NAPI::TAG_GetVersionListVersion(authInfo);\n\t\t\tif (!versionListVersionResult.isValid)\n\t\t\t\treturn false;\n\t\t\tif (versionListVersionResult.fqdnURL.size() >= 256)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"NIM: fqdn URL too long\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tg_nim.latestVersion = (sint32)versionListVersionResult.version;\n\t\t\tstrcpy(g_nim.fqdn, versionListVersionResult.fqdnURL.c_str());\n\t\t\treturn true;\n\t\t}\n\n\t\tbool nim_getVersionList()\n\t\t{\n\t\t\tg_nim.titlesLatestVersion.clear();\n\n\t\t\tNAPI::AuthInfo authInfo;\n\t\t\tauthInfo.country = NCrypto::GetCountryAsString(Account::GetCurrentAccount().GetCountry());\n\t\t\tauthInfo.region = NCrypto::SEEPROM_GetRegion();\n\t\t\tauto versionListVersionResult = NAPI::TAG_GetVersionListVersion(authInfo);\n\t\t\tif (!versionListVersionResult.isValid)\n\t\t\t\treturn false;\n\t\t\tauto versionListResult = TAG_GetVersionList(authInfo, versionListVersionResult.fqdnURL, versionListVersionResult.version);\n\t\t\tif (!versionListResult.isValid)\n\t\t\t\treturn false;\n\t\t\tfor (auto& itr : versionListResult.titleVersionList)\n\t\t\t{\n\t\t\t\tNIMTitleLatestVersion titleLatestVersion;\n\t\t\t\ttitleLatestVersion.titleId = itr.first;\n\t\t\t\ttitleLatestVersion.version = itr.second;\n\t\t\t\tg_nim.titlesLatestVersion.push_back(titleLatestVersion);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tNIMTitleLatestVersion* nim_findTitleLatestVersion(uint64 titleId)\n\t\t{\n\t\t\tfor (auto& titleLatestVersion : g_nim.titlesLatestVersion)\n\t\t\t{\n\t\t\t\tif (titleLatestVersion.titleId == titleId)\n\t\t\t\t\treturn &titleLatestVersion;\n\t\t\t}\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tvoid nim_buildDownloadList()\n\t\t{\n\t\t\tif(nim_CheckDownloadsDisabled())\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"nim_buildDownloadList: Downloads are disabled for this title\");\n\t\t\t\tg_nim.packages.clear();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsint32 titleCount = mcpGetTitleCount();\n\t\t\tMCPTitleInfo* titleList = (MCPTitleInfo*)malloc(titleCount * sizeof(MCPTitleInfo));\n\t\t\tmemset(titleList, 0, titleCount * sizeof(MCPTitleInfo));\n\n\t\t\tuint32be titleCountBE = titleCount;\n\t\t\tif (mcpGetTitleList(titleList, titleCount * sizeof(MCPTitleInfo), &titleCountBE) != 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"IOSU: nim failed to acquire title list\");\n\t\t\t\tfree(titleList);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttitleCount = titleCountBE;\n\t\t\t// check for game updates\n\t\t\tfor (sint32 i = 0; i < titleCount; i++)\n\t\t\t{\n\t\t\t\tif( titleList[i].titleIdHigh != 0x00050000 )\n\t\t\t\t\tcontinue;\n\t\t\t\t// find update title in title version list\n\t\t\t\tuint64 titleId = (0x0005000EULL << 32) | ((uint64)(uint32)titleList[i].titleIdLow);\n\t\t\t\tNIMTitleLatestVersion* latestVersionInfo = nim_findTitleLatestVersion(titleId);\n\t\t\t\tif(latestVersionInfo == nullptr)\n\t\t\t\t\tcontinue;\n\t\t\t\t// compare version\n\t\t\t\tif(latestVersionInfo->version <= (uint32)titleList[i].titleVersion )\n\t\t\t\t\tcontinue; // already on latest version\n\t\t\t\t// add to packages\n\t\t\t\tNIMPackage nimPackage{};\n\t\t\t\tnimPackage.titleId = titleId;\n\t\t\t\tnimPackage.type = PACKAGE_TYPE_UPDATE;\n\t\t\t\tg_nim.packages.emplace_back(std::move(nimPackage));\n\t\t\t}\n\t\t\t// check for AOC/titles to download\n\t\t\t// todo\n\t\t\tfree(titleList);\n\t\t}\n\n\t\tvoid nim_getPackagesInfo(uint64* titleIdList, sint32 count, titlePackageInfo_t* packageInfoList)\n\t\t{\n\t\t\tmemset(packageInfoList, 0, sizeof(titlePackageInfo_t)*count);\n\t\t\tif(nim_CheckDownloadsDisabled())\n\t\t\t\treturn;\n\t\t\tfor (sint32 i = 0; i < count; i++)\n\t\t\t{\n\t\t\t\tuint64 titleId = _swapEndianU64(titleIdList[i]);\n\t\t\t\ttitlePackageInfo_t* packageInfo = packageInfoList + i;\n\n\t\t\t\tpackageInfo->titleId = _swapEndianU64(titleIdList[0]);\n\n\t\t\t\tpackageInfo->ukn0C = 1; // update\n\n\t\t\t\t// pending\n\t\t\t\tpackageInfo->ukn48 = 0; // with 0 there is no progress bar, with 3 there is a progress bar\n\t\t\t\tpackageInfo->ukn40 = (5 << 20) | (0 << 27) | (1<<31) | (0x30000<<0);\n\n\t\t\t\tpackageInfo->ukn0F = 1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tstruct idbeIconCacheEntry_t\n\t\t{\n\t\t\tvoid setIconData(NAPI::IDBEIconDataV0& newIconData)\n\t\t\t{\n\t\t\t\ticonData = newIconData;\n\t\t\t\thasIconData = true;\n\t\t\t}\n\n\t\t\tvoid setNoIcon()\n\t\t\t{\n\t\t\t\thasIconData = false;\n\t\t\t\ticonData = {};\n\t\t\t}\n\n\t\t\tuint64 titleId;\n\t\t\tuint32 lastRequestTime;\n\t\t\tbool hasIconData{ false };\n\t\t\tNAPI::IDBEIconDataV0 iconData{};\n\t\t};\n\n\t\tstd::vector<idbeIconCacheEntry_t> idbeIconCache;\n\n\t\tvoid idbe_addIconToCache(uint64 titleId, NAPI::IDBEIconDataV0* iconData)\n\t\t{\n\t\t\tidbeIconCacheEntry_t newCacheEntry;\n\t\t\tnewCacheEntry.titleId = titleId;\n\t\t\tnewCacheEntry.lastRequestTime = GetTickCount();\n\t\t\tif (iconData)\n\t\t\t\tnewCacheEntry.setIconData(*iconData);\n\t\t\telse\n\t\t\t\tnewCacheEntry.setNoIcon();\n\t\t\tidbeIconCache.push_back(newCacheEntry);\n\t\t}\n\n\t\tsint32 nim_getIconDatabaseEntry(uint64 titleId, void* idbeIconOutput)\n\t\t{\n\t\t\t// if titleId is an update, replace it with gameId instead\n\t\t\tif ((uint32)(titleId >> 32) == 0x0005000EULL)\n\t\t\t{\n\t\t\t\ttitleId &= ~0xF00000000ULL;\n\t\t\t}\n\n\t\t\tfor (auto& entry : idbeIconCache)\n\t\t\t{\n\t\t\t\tif (entry.titleId == titleId)\n\t\t\t\t{\n\t\t\t\t\tif( entry.hasIconData )\n\t\t\t\t\t\tmemcpy(idbeIconOutput, &entry.iconData, sizeof(NAPI::IDBEIconDataV0));\n\t\t\t\t\telse\n\t\t\t\t\t\tmemset(idbeIconOutput, 0, sizeof(NAPI::IDBEIconDataV0));\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tauto result = NAPI::IDBE_Request(ActiveSettings::GetNetworkService(), titleId);\n\t\t\tif (!result)\n\t\t\t{\n\t\t\t\tmemset(idbeIconOutput, 0, sizeof(NAPI::IDBEIconDataV0));\n\t\t\t\tcemuLog_log(LogType::Force, \"NIM: Unable to download IDBE icon\");\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t// add new cache entry\n\t\t\tidbe_addIconToCache(titleId, &*result);\n\t\t\t// return result\n\t\t\tmemcpy(idbeIconOutput, &*result, sizeof(NAPI::IDBEIconDataV0));\n\t\t\treturn 0;\n\t\t}\n\n\t\tvoid nim_backgroundThread()\n\t\t{\n\t\t\twhile (iosuAct_isAccountDataLoaded() == false)\n\t\t\t{\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(500));\n\t\t\t}\n\n\t\t\tif (nim_getLatestVersion())\n\t\t\t{\n\t\t\t\tif (nim_getVersionList())\n\t\t\t\t{\n\t\t\t\t\tnim_buildDownloadList();\n\t\t\t\t}\n\t\t\t}\n\t\t\tg_nim.packageListReady = true;\n\t\t}\n\n\t\tvoid iosuNim_waitUntilPackageListReady()\n\t\t{\n\t\t\tif (g_nim.backgroundThreadStarted == false)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"IOSU: Starting nim background thread\");\n\t\t\t\tstd::thread t(nim_backgroundThread);\n\t\t\t\tt.detach();\n\t\t\t\tg_nim.backgroundThreadStarted = true;\n\t\t\t}\n\t\t\twhile (g_nim.packageListReady == false)\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(200));\n\t\t}\n\n\n\t\tvoid iosuNim_thread()\n\t\t{\n\t\t\tSetThreadName(\"iosuNim_thread\");\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tuint32 returnValue = 0; // Ioctl return value\n\t\t\t\tioQueueEntry_t* ioQueueEntry = iosuIoctl_getNextWithWait(IOS_DEVICE_NIM);\n\t\t\t\tif (ioQueueEntry->request == IOSU_NIM_REQUEST_CEMU)\n\t\t\t\t{\n\t\t\t\t\tiosuNimCemuRequest_t* nimCemuRequest = (iosuNimCemuRequest_t*)ioQueueEntry->bufferVectors[0].buffer.GetPtr();\n\t\t\t\t\tif (nimCemuRequest->requestCode == IOSU_NIM_GET_ICON_DATABASE_ENTRY)\n\t\t\t\t\t{\n\t\t\t\t\t\tnimCemuRequest->returnCode = nim_getIconDatabaseEntry(nimCemuRequest->titleId, nimCemuRequest->ptr.GetPtr());\n\t\t\t\t\t}\n\t\t\t\t\telse if (nimCemuRequest->requestCode == IOSU_NIM_GET_PACKAGE_COUNT)\n\t\t\t\t\t{\n\t\t\t\t\t\tiosuNim_waitUntilPackageListReady();\n\t\t\t\t\t\tnimCemuRequest->resultU32.u32 = (uint32)g_nim.packages.size();\n\t\t\t\t\t\tnimCemuRequest->returnCode = 0;\n\t\t\t\t\t}\n\t\t\t\t\telse if (nimCemuRequest->requestCode == IOSU_NIM_GET_PACKAGES_TITLEID)\n\t\t\t\t\t{\n\t\t\t\t\t\tiosuNim_waitUntilPackageListReady();\n\t\t\t\t\t\tuint32 maxCount = nimCemuRequest->maxCount;\n\t\t\t\t\t\tuint64* titleIdList = (uint64*)nimCemuRequest->ptr.GetPtr();\n\t\t\t\t\t\tuint32 count = 0;\n\t\t\t\t\t\tmemset(titleIdList, 0, sizeof(uint64) * maxCount);\n\t\t\t\t\t\tfor (auto& package : g_nim.packages)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttitleIdList[count] = _swapEndianU64(package.titleId);\n\t\t\t\t\t\t\tcount++;\n\t\t\t\t\t\t\tif (count >= maxCount)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnimCemuRequest->returnCode = 0;\n\t\t\t\t\t}\n\t\t\t\t\telse if (nimCemuRequest->requestCode == IOSU_NIM_GET_PACKAGES_INFO)\n\t\t\t\t\t{\n\t\t\t\t\t\tiosuNim_waitUntilPackageListReady();\n\t\t\t\t\t\tuint32 maxCount = nimCemuRequest->maxCount;\n\t\t\t\t\t\tuint64* titleIdList = (uint64*)nimCemuRequest->ptr.GetPtr();\n\t\t\t\t\t\ttitlePackageInfo_t* packageInfo = (titlePackageInfo_t*)nimCemuRequest->ptr2.GetPtr();\n\t\t\t\t\t\tnim_getPackagesInfo(titleIdList, maxCount, packageInfo);\n\t\t\t\t\t\tnimCemuRequest->returnCode = 0;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\tiosuIoctl_completeRequest(ioQueueEntry, returnValue);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tvoid Initialize()\n\t\t{\n\t\t\tif (g_nim.isInitialized)\n\t\t\t\treturn;\n\t\t\tstd::vector<idbeIconCacheEntry_t> idbeIconCache = std::vector<idbeIconCacheEntry_t>();\n\t\t\tg_nim.titlesLatestVersion = std::vector<NIMTitleLatestVersion>();\n\t\t\tg_nim.packages.clear();\n\t\t\tg_nim.packageListReady = false;\n\t\t\tg_nim.backgroundThreadStarted = false;\n\t\t\tstd::thread t2(iosuNim_thread);\n\t\t\tt2.detach();\n\t\t\tg_nim.isInitialized = true;\n\t\t}\n\n\t}\n}\n\n"
  },
  {
    "path": "src/Cafe/IOSU/legacy/iosu_nim.h",
    "content": "#pragma once\n\nnamespace iosu\n{\n\tnamespace nim\n\t{\n\t\tstruct titlePackageInfo_t\n\t\t{\n\t\t\tuint64 titleId;\n\t\t\tuint32be ukn08;\n\t\t\tuint8 ukn0C;\n\t\t\tuint8 ukn0D;\n\t\t\tuint8 ukn0E;\n\t\t\tuint8 ukn0F;\n\t\t\tuint8 ukn10;\n\t\t\tuint8 ukn11;\n\t\t\tuint8 ukn12;\n\t\t\tuint8 ukn13;\n\t\t\tuint8 ukn14[0xC];\n\t\t\tuint32be ukn20;\n\t\t\tuint32be ukn24;\n\t\t\t// ukn sint64 value (uknDA)\n\t\t\t//uint32be ukn28_h;\n\t\t\t//uint32be ukn2C_l;\n\t\t\tuint64 ukn28DLProgressRelatedMax_u64be;\n\t\t\t// ukn sint64 value (uknDB)\n\t\t\t//uint32be ukn30_h;\n\t\t\t//uint32be ukn34_l;\n\t\t\tuint64 ukn30DLProgressRelatedCur_u64be;\n\t\t\t// ukn sint64 value (uknDC)\n\t\t\tuint32be ukn38DLProgressRelatedMax;\n\t\t\tuint32be ukn3CDLProgressRelatedCur;\n\t\t\tuint32be ukn40;\n\t\t\tuint32be ukn44;\n\t\t\tuint8 ukn48; // 0-7 are allowed values\n\t\t\tuint8 ukn49;\n\t\t\tuint8 ukn4A;\n\t\t\tuint8 ukn4B;\n\t\t\tuint32be ukn4C;\n\t\t};\n\n\t\tstatic_assert(sizeof(titlePackageInfo_t) == 0x50);\n\n\t\tstruct iosuNimCemuRequest_t\n\t\t{\n\t\t\tuint32 requestCode;\n\t\t\t// input\n\t\t\tuint64 titleId;\n\t\t\tMEMPTR<void> ptr;\n\t\t\tMEMPTR<void> ptr2;\n\t\t\tsint32 maxCount;\n\n\t\t\t// output\n\t\t\tuint32 returnCode; // NIM return value\n\t\t\tunion\n\t\t\t{\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint32 u32;\n\t\t\t\t}resultU32;\n\t\t\t};\n\t\t};\n\n\t\t// custom dev/nim protocol (Cemu only)\n\t\t#define IOSU_NIM_REQUEST_CEMU\t\t\t\t\t\t\t\t\t(0xEE)\n\n\t\t// NIM request Cemu subcodes\n\t\t#define IOSU_NIM_GET_ICON_DATABASE_ENTRY\t\t\t\t\t\t0x01\n\t\t#define IOSU_NIM_GET_PACKAGE_COUNT\t\t\t\t\t\t\t\t0x02\n\t\t#define IOSU_NIM_GET_PACKAGES_INFO\t\t\t\t\t\t\t\t0x03\n\t\t#define IOSU_NIM_GET_PACKAGES_TITLEID\t\t\t\t\t\t\t0x04\n\n\t\tvoid Initialize();\n\t}\n}"
  },
  {
    "path": "src/Cafe/IOSU/nn/boss/boss_common.cpp",
    "content": ""
  },
  {
    "path": "src/Cafe/IOSU/nn/boss/boss_common.h",
    "content": "#pragma once\n#include \"Common/CafeString.h\"\n\nnamespace nn::boss\n{\n\ttypedef uint32 BossResult;\n\n\tstruct VTableEntry\n\t{\n\t\tuint16be offsetA{0};\n\t\tuint16be offsetB{0};\n\t\tMEMPTR<void> ptr;\n\t};\n\tstatic_assert(sizeof(VTableEntry) == 8);\n\n\tstruct TitleId\n\t{\n\t\tuint64be u64{};\n\n\t\tstatic bool IsValid(TitleId* _thisptr);\n\t\tstatic TitleId* ctorDefault(TitleId* _thisptr);\n\t\tstatic TitleId* ctorFromTitleId(TitleId* _thisptr, uint64 titleId); // __ct__Q3_2nn4boss7TitleIDFUL\n\t\tstatic TitleId* ctorCopy(TitleId* _thisptr, TitleId* titleId); // __ct__Q3_2nn4boss7TitleIDFRCQ3_2nn4boss7TitleID\n\t\tstatic bool operator_ne(TitleId* _thisptr, TitleId* titleId);\n\n\t};\n\tstatic_assert(sizeof(TitleId) == 8);\n\n\tstruct TaskId\n\t{\n\t\tCafeString<8> id;\n\n\t\tTaskId() = default;\n\t\tTaskId(const char* taskId) { id.assign(taskId); }\n\n\t\tstatic TaskId* ctorDefault(TaskId* _thisptr);\n\t\tstatic TaskId* ctorFromString(TaskId* _thisptr, const char* taskId);\n\n\t\t//auto operator<=>(const TaskId& other) const = default;\n\t\tstd::strong_ordering operator<=>(const TaskId& other) const noexcept {\n\t\t\treturn id <=> other.id; // Delegate to CafeString's operator<=>\n\t\t}\n\t};\n\tstatic_assert(sizeof(TaskId) == 8);\n\n\tstruct Title\n\t{\n\t\tuint32be accountId{}; // 0x00\n\t\tTitleId titleId{}; // 0x8\n\t\tMEMPTR<void> vTablePtr{}; // 0x10\n\n\t\tstruct VTable\n\t\t{\n\t\t\tVTableEntry rtti;\n\t\t\tVTableEntry dtor;\n\t\t};\n\t\tstatic inline SysAllocator<VTable> s_titleVTable;\n\n\t\tstatic Title* ctor(Title* _this);\n\t\tstatic void dtor(Title* _this, uint32 options);\n\t\tstatic void InitVTable();\n\t};\n\tstatic_assert(sizeof(Title) == 0x18);\n\n\tstruct DirectoryName\n\t{\n\t\tCafeString<8> name2;\n\n\t\tstatic DirectoryName* ctor(DirectoryName* _thisptr);\n\t\tstatic const char* operator_const_char(DirectoryName* _thisptr);\n\t};\n\tstatic_assert(sizeof(DirectoryName) == 8);\n\n\tstruct BossAccount // the actual class name is \"Account\" and while the boss namespace helps us separate this from Account(.h) we use an alternative name to avoid confusion\n\t{\n\t\tstruct VTable\n\t\t{\n\t\t\tVTableEntry rtti;\n\t\t\tVTableEntry dtor;\n\t\t};\n\t\tstatic inline SysAllocator<VTable> s_VTable;\n\n\t\tuint32be accountId;\n\t\tMEMPTR<void> vTablePtr;\n\n\t\tstatic BossAccount* ctor(BossAccount* _this, uint32 accountId);\n\t\tstatic void dtor(BossAccount* _this, uint32 options);\n\t\tstatic void InitVTable();\n\n\t};\n\tstatic_assert(sizeof(BossAccount) == 8);\n\n\tenum class TaskWaitState : uint32 // for Task::Wait()\n\t{\n\t\tDone = 1,\n\t};\n\n\tenum class TaskTurnState : uint32\n\t{\n\t\tUkn = 0,\n\t\tStopped = 1,\n\t\tReady = 4,\n\t\tRunning = 6,\n\t\tDone = 7, // how does this differ from DoneSuccess?\n\t\tDoneSuccess = 16,\n\t\tDoneError = 17\n\t};\n\n\tenum class TaskState : uint8\n\t{\n\t\tInitial = 0,\n\t\tStopped = 1,\n\t\tReady = 4, // waiting for turn to run\n\t\tRunning = 6,\n\t\tDone = 7,\n\t};\n\n\tenum class TaskType : uint16\n\t{\n\t\tNbdlTaskSetting = 2,\n\t\tRawDlTaskSetting_1 = 1,\n\t\tRawDlTaskSetting_3 = 3,\n\t\tRawDlTaskSetting_9 = 9,\n\t\tRawUlTaskSetting = 4,\n\t\tPlayLogUploadTaskSetting = 5,\n\t\tPlayReportSetting = 6,\n\t\tDataStoreDownloadSetting = 8,\n\t\tNbdlDataListTaskSetting = 10\n\t};\n\n\tstruct TaskSettingCore // the setting struct as used by IOSU\n\t{\n\t\tstruct LifeTime\n\t\t{\n\t\t\tuint32be high;\n\t\t\tuint32be low;\n\t\t};\n\n\t\tuint32be persistentId;\n\t\tuint32be ukn04;\n\t\tuint32be ukn08;\n\t\tuint32be ukn0C;\n\t\tuint32be ukn10;\n\t\tuint32be ukn14;\n\t\tuint32be ukn18;\n\t\tuint32be ukn1C;\n\t\tTaskId taskId; // +0x20\n\t\tbetype<TaskType> taskType; // +0x28\n\t\tuint8be priority; // +0x2A\n\t\tuint8be mode; // +0x2B\n\t\tuint8be permission; // +0x2C\n\t\tuint16be intervalA; // +0x2E\n\t\tuint32be intervalB; // +0x30\n\t\tuint32be unk34; // +0x34 - could be padding\n\t\tLifeTime lifeTime; // +0x38 - this is a 64bit value, but the whole struct has a size of 0x1004 and doesnt preserve the alignment in an array. Its probably handled as two 32bit values?\n\t\tuint8be httpProtocol; // +0x40\n\t\tuint8be internalClientCert; // +0x41\n\t\tuint16be httpOption; // +0x42\n\t\tuint8 ukn44[0x48 - 0x44]; // padding?\n\t\tCafeString<256> url; // +0x48\n\t\tCafeString<64> lastModifiedTime; // +0x148\n\t\tuint8be internalCaCert[3]; // +0x188\n\t\tuint8 ukn18B; // +0x18B - padding?\n\t\tuint32be httpTimeout; // +0x18C\n\t\tCafeString<128> caCert[3]; // +0x190 - 3 entries, each 0x80 bytes\n\t\tCafeString<128> clientCertName; // +0x310\n\t\tCafeString<128> clientCertKey; // +0x390\n\t\tstruct HttpHeader\n\t\t{\n\t\t\tCafeString<32> name; // +0x00\n\t\t\tCafeString<64> value; // +0x20\n\t\t};\n\t\tHttpHeader httpHeaders[3]; // +0x410\n\t\tCafeString<96> httpQueryString; // +0x530\n\t\tCafeString<512> serviceToken; // +0x590\n\n\t\tuint8 ukn790[0x7C0 - 0x790];\n\t\t// after 0x7C0 the task-specific fields seem to start?\n\n\t\tunion\n\t\t{\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tuint32be optionValue; // +0x7C0\n\t\t\t\tCafeString<32> largeHttpHeaderKey; // +0x7C4\n\t\t\t\tCafeString<512> largeHttpHeaderValue; // +0x7E4\n\t\t\t}rawUl; // RawUlTaskSetting\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tuint32be optionValue; // +0x7C0\n\t\t\t\tCafeString<32> largeHttpHeaderKey; // +0x7C4\n\t\t\t\tCafeString<512> largeHttpHeaderValue; // +0x7E4\n\t\t\t\t// inherits the above values from RawUlTaskSetting\n\t\t\t\t// the play report fields are too large to fit into the available space, so instead they are passed via their own system call that attaches it to the task. See PlayReportSetting::RegisterPreprocess\n\t\t\t}playReportSetting;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tuint8be newArrival; // +0x7C0\n\t\t\t\tuint8be led; // +0x7C1\n\t\t\t\tuint8be ukn7C2[6]; // +0x7C2 - padding?\n\t\t\t\tCafeString<8> bossDirectory; // +0x7C8\n\t\t\t\tCafeString<32> fileName; // +0x7D0 Not 100% sure this is fileName\n\t\t\t}rawDl; // RawDlTaskSetting\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tCafeString<32> bossCode; // +0x7C0\n\t\t\t\tCafeString<8> bossDirectory; // +0x7E0\n\t\t\t\tuint32be ukn7E8;\n\t\t\t\tuint32be ukn7EC;\n\t\t\t\tuint32be directorySizeLimitHigh; // +0x7F0\n\t\t\t\tuint32be directorySizeLimitLow; // +0x7F4\n\t\t\t\tCafeString<32> fileName; // +0x7F8\n\t\t\t\t// more fields here...\n\t\t\t}nbdl;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tuint8 finalPadding[0xC00 - 0x7C0];\n\t\t\t}paddedBlock;\n\t\t};\n\t};\n\tstatic_assert(sizeof(TaskSettingCore) == 0xC00);\n\n\tstruct TaskSetting : public TaskSettingCore\n\t{\n\t\tuint8 paddingC00[0x1000 - 0xC00];\n\t\tMEMPTR<void> vTablePtr; // +0x1000\n\n\t\tstruct VTableTaskSetting\n\t\t{\n\t\t\tVTableEntry rtti;\n\t\t\tVTableEntry dtor;\n\t\t\tVTableEntry RegisterPreprocess; // todo - double check the offset\n\t\t\tVTableEntry unk1;\n\t\t};\n\t\tstatic inline SysAllocator<VTableTaskSetting> s_VTable;\n\n\t\tstatic TaskSetting* ctor(TaskSetting* _thisptr);\n\t\tstatic void dtor(TaskSetting* _this, uint32 options);\n\t\tstatic bool IsPrivileged(TaskSetting* _thisptr);\n\t\tstatic void InitializeSetting(TaskSetting* _thisptr);\n\t\tstatic void InitVTable();\n\t};\n\tstatic_assert(offsetof(TaskSetting, priority) == 0x2A);\n\tstatic_assert(offsetof(TaskSetting, mode) == 0x2B);\n\tstatic_assert(offsetof(TaskSetting, permission) == 0x2C);\n\tstatic_assert(offsetof(TaskSetting, intervalA) == 0x2E);\n\tstatic_assert(offsetof(TaskSetting, intervalB) == 0x30);\n\tstatic_assert(offsetof(TaskSetting, lifeTime) == 0x38);\n\tstatic_assert(offsetof(TaskSetting, httpProtocol) == 0x40);\n\tstatic_assert(offsetof(TaskSetting, internalClientCert) == 0x41);\n\tstatic_assert(offsetof(TaskSetting, httpOption) == 0x42);\n\tstatic_assert(offsetof(TaskSetting, url) == 0x48);\n\tstatic_assert(offsetof(TaskSetting, lastModifiedTime) == 0x148);\n\tstatic_assert(offsetof(TaskSetting, internalCaCert) == 0x188);\n\tstatic_assert(offsetof(TaskSetting, httpTimeout) == 0x18C);\n\tstatic_assert(offsetof(TaskSetting, caCert) == 0x190);\n\tstatic_assert(offsetof(TaskSetting, clientCertName) == 0x310);\n\tstatic_assert(offsetof(TaskSetting, clientCertKey) == 0x390);\n\tstatic_assert(offsetof(TaskSetting, httpHeaders) == 0x410);\n\tstatic_assert(offsetof(TaskSetting, httpQueryString) == 0x530);\n\tstatic_assert(offsetof(TaskSetting, serviceToken) == 0x590);\n\t// rawUl\n\tstatic_assert(offsetof(TaskSetting, rawUl.optionValue) == 0x7C0);\n\tstatic_assert(offsetof(TaskSetting, rawUl.largeHttpHeaderKey) == 0x7C4);\n\tstatic_assert(offsetof(TaskSetting, rawUl.largeHttpHeaderValue) == 0x7E4);\n\t// rawDl\n\tstatic_assert(offsetof(TaskSetting, rawDl.newArrival) == 0x7C0);\n\tstatic_assert(offsetof(TaskSetting, rawDl.bossDirectory) == 0x7C8);\n\tstatic_assert(offsetof(TaskSetting, rawDl.fileName) == 0x7D0);\n\t// nbdl\n\tstatic_assert(offsetof(TaskSetting, nbdl.bossCode) == 0x7C0);\n\tstatic_assert(offsetof(TaskSetting, nbdl.bossDirectory) == 0x7E0);\n\n\tstatic_assert(offsetof(TaskSetting, vTablePtr) == 0x1000);\n\tstatic_assert(sizeof(TaskSetting) == 0x1004);\n\n\t/* NetTaskSetting */\n\n\tstruct NetTaskSetting : TaskSetting\n\t{\n\t\tstruct VTableNetTaskSetting : public VTableTaskSetting\n\t\t{ };\n\t\tstatic inline SysAllocator<VTableNetTaskSetting> s_VTable;\n\n\t\tstatic NetTaskSetting* ctor(NetTaskSetting* _thisptr);\n\t\tstatic BossResult AddCaCert(NetTaskSetting* _thisptr, const char* name);\n\t\tstatic BossResult SetServiceToken(NetTaskSetting* _thisptr, const uint8* serviceToken);\n\t\tstatic BossResult AddInternalCaCert(NetTaskSetting* _thisptr, char certId);\n\t\tstatic void SetInternalClientCert(NetTaskSetting* _thisptr, char certId);\n\t\tstatic void InitVTable();\n\t};\n\tstatic_assert(sizeof(NetTaskSetting) == 0x1004);\n\n\t/* NbdlTaskSetting */\n\n\tstruct NbdlTaskSetting : NetTaskSetting\n\t{\n\t\tstruct VTableNbdlTaskSetting : public VTableNetTaskSetting\n\t\t{\n\t\t\tVTableEntry rttiNetTaskSetting; // unknown\n\t\t};\n\t\tstatic_assert(sizeof(VTableNbdlTaskSetting) == 8*5);\n\t\tstatic inline SysAllocator<VTableNbdlTaskSetting> s_VTable;\n\n\t\tstatic NbdlTaskSetting* ctor(NbdlTaskSetting* _thisptr);\n\t\tstatic BossResult Initialize(NbdlTaskSetting* _thisptr, const char* bossCode, uint64 directorySizeLimit, const char* bossDirectory);\n\t\tstatic BossResult SetFileName(NbdlTaskSetting* _thisptr, const char* fileName);\n\t\tstatic void InitVTable();\n\t};\n\tstatic_assert(sizeof(NbdlTaskSetting) == 0x1004);\n\n\t/* RawUlTaskSetting */\n\n\tstruct RawUlTaskSetting : NetTaskSetting\n\t{\n\t\tuint32be ukRaw1; // 0x1004\n\t\tuint32be ukRaw2; // 0x1008\n\t\tuint32be ukRaw3; // 0x100C\n\t\tuint8 rawSpace[0x200]; // 0x1010\n\n\t\tstruct VTableRawUlTaskSetting : public VTableNetTaskSetting\n\t\t{\n\t\t\tVTableEntry rttiNetTaskSetting; // unknown\n\t\t};\n\t\tstatic_assert(sizeof(VTableRawUlTaskSetting) == 8*5);\n\t\tstatic inline SysAllocator<VTableRawUlTaskSetting> s_VTable;\n\n\t\tstatic RawUlTaskSetting* ctor(RawUlTaskSetting* _thisptr);\n\t\tstatic void dtor(RawUlTaskSetting* _this, uint32 options);\n\t\tstatic void InitVTable();\n\t};\n\tstatic_assert(sizeof(RawUlTaskSetting) == 0x1210);\n\n\t/* RawDlTaskSetting */\n\tstruct RawDlTaskSetting : NetTaskSetting\n\t{\n\t\tstruct VTableRawDlTaskSetting : public VTableNetTaskSetting\n\t\t{\n\t\t\tVTableEntry rttiNetTaskSetting; // unknown\n\t\t};\n\t\tstatic_assert(sizeof(VTableRawDlTaskSetting) == 8*5);\n\t\tstatic inline SysAllocator<VTableRawDlTaskSetting> s_VTable;\n\n\t\tstatic RawDlTaskSetting* ctor(RawDlTaskSetting* _thisptr);\n\t\tstatic BossResult Initialize(RawDlTaskSetting* _thisptr, const char* url, bool newArrival, bool led, const char* fileName, const char* bossDirectory);\n\n\t\tstatic void InitVTable();\n\t};\n\tstatic_assert(sizeof(RawDlTaskSetting) == 0x1004);\n\n\t/* PlayReportSetting */\n\n\tstruct PlayReportSetting : RawUlTaskSetting\n\t{\n\t\tMEMPTR<uint8> ukn1210_ptr; // 0x1210\n\t\tuint32be ukn1214_size; // 0x1214\n\t\tuint32be ukPlay3; // 0x1218\n\t\tuint32be ukPlay4; // 0x121C\n\n\t\tstruct VTablePlayReportSetting : public VTableRawUlTaskSetting\n\t\t{};\n\t\tstatic_assert(sizeof(VTablePlayReportSetting) == 8*5);\n\t\tstatic inline SysAllocator<VTablePlayReportSetting> s_VTable;\n\n\t\tstatic PlayReportSetting* ctor(PlayReportSetting* _this);\n\t\tstatic void dtor(PlayReportSetting* _this, uint32 options);\n\t\tstatic void Initialize(PlayReportSetting* _this, uint8* ptr, uint32 size);\n\t\tstatic bool Set(PlayReportSetting* _this, const char* keyname, uint32 value);\n\t\tstatic void InitVTable();\n\t};\n\tstatic_assert(sizeof(PlayReportSetting) == 0x1220);\n\n\t/* Storage */\n\tenum class StorageKind : uint32\n\t{\n\t\tStorageNbdl = 0,\n\t\tStorageRawDl = 1,\n\t};\n\n\tstruct DataName\n\t{\n\t\tCafeString<32> name;\n\n\t\tstatic DataName* ctor(DataName* _this); // __ct__Q3_2nn4boss8DataNameFv\n\t\tstatic const char* operator_const_char(DataName* _this); // __opPCc__Q3_2nn4boss8DataNameCFv\n\n\t\tconst char* c_str() const\n\t\t{\n\t\t\treturn name.c_str();\n\t\t}\n\t};\n\tstatic_assert(sizeof(DataName) == 32);\n\n\t/* IPC commands for /dev/boss */\n\tenum class BossCommandId : uint32\n\t{\n\t\t// task operations\n\t\tTaskIsRegistered = 0x69,\n\t\tTaskRegisterA = 0x6A,\n\t\tTaskRegisterForImmediateRunA = 0x6B,\n\t\tTaskUnregister = 0x6D,\n\t\tTaskRun = 0x78,\n\t\tTaskStartScheduling = 0x77,\n\t\tTaskStopScheduling = 0x79,\n\t\tTaskWaitA = 0x7A,\n\t\tTaskGetHttpStatusCodeA = 0x7C,\n\t\tTaskGetTurnState = 0x7E,\n\t\tTaskGetContentLength = 0x82,\n\t\tTaskGetProcessedLength = 0x83,\n\t\t// storage operations\n\t\tStorageExist = 0x87,\n\t\tStorageGetDataList = 0xB0,\n\t\t// NsData operations\n\t\tNsDataExist = 0x90,\n\t\tNsDataRead = 0x93,\n\t\tNsDataGetSize = 0x96,\n\t\tNsDataDeleteFile = 0xA7,\n\t\tNsDataDeleteFileWithHistory = 0xA8,\n\t\tNsFinalize = 0xB3,\n\t\t// Title operations\n\t\tTitleSetNewArrivalFlag = 0x9E,\n\n\t\t// most (if not all?) opcodes seem to have a secondary form with an additional titleId parameter in the high range around 0x150 and serviceId 1\n\n\t\t// unknown commands\n\t\tUknA7 = 0xA5,\n\t\tDeleteDataRelated = 0xA6,\n\t};\n\n\n}"
  },
  {
    "path": "src/Cafe/IOSU/nn/boss/boss_service.cpp",
    "content": "#include \"Cafe/OS/libs/nn_common.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"util/helpers/helpers.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n\n#include \"Cafe/IOSU/iosu_types_common.h\"\n#include \"Cafe/IOSU/nn/iosu_nn_service.h\"\n\n#include \"Cafe/IOSU/legacy/iosu_act.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"config/ActiveSettings.h\"\n\n#include \"boss_service.h\"\n#include \"boss_common.h\"\n\n#include <pugixml.hpp>\n#include <curl/curl.h>\n#include <openssl/x509.h>\n#include <openssl/evp.h>\n#include <openssl/hmac.h>\n\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"Cemu/napi/napi_helper.h\"\n#include \"IOSU/legacy/iosu_crypto.h\"\n#include \"util/crypto/aes128.h\"\n\nnamespace iosu::boss\n{\n\tusing namespace ::nn::boss;\n\n\tstatic constexpr nnResult RESULT_SUCCESS = 0x200080;\n\tstatic constexpr nnResult RESULT_C0203880 = 0xC0203880;\n\tstatic constexpr nnResult RESULT_NOTEXIST = 0xA021F900;\n\n\tstatic constexpr nnResult RESULT_STORAGE_NOTEXIST = 0xA025AA00;\n\tstatic constexpr nnResult RESULT_FADENTRY_NOTEXIST = 0xA021FB00;\n\n\ttemplate <typename ... TArgs>\n\tvoid AppendHeaderParam(CurlRequestHelper& request, const char* fieldName, const char* format, TArgs&& ... args)\n\t{\n\t\trequest.addHeaderField(fieldName, fmt::format(fmt::runtime(format), std::forward<TArgs>(args)...).c_str());\n\t}\n\n\tclass StorageDatabase // FAD\n\t{\n\t\tstatic constexpr uint32 FAD_ENTRY_MAX_COUNT = 512; // max entries in a single FAD file\n\n\tpublic:\n\t\tstruct BossStorageFadEntry\n\t\t{\n\t\t\tCafeString<32> fileName; // 0x00\n\t\t\tuint32be fileId; // 0x20\n\t\t\tuint32 ukn24; // 0x24\n\t\t\tuint32 flags; // 0x28\n\t\t\tuint32 memo_2C; // 0x2C\n\t\t\tuint64be entryCreationTimestamp;\n\t\t\t// flags:\n\t\t\t// 0x80000000\t\tReadFlag\n\t\t\t// 0x40000000\t\tDeleteProtectionFlag\n\t\t\t// 0x20000000\t\tNew arrival flag?\n\t\t};\n\t\tstatic_assert(sizeof(BossStorageFadEntry) == 0x38);\n\n\t\tstruct BossStorageFadFile\n\t\t{\n\t\t\tuint8 _00[0x08];\n\t\t\tBossStorageFadEntry entries[FAD_ENTRY_MAX_COUNT];\n\t\t};\n\t\tstatic_assert(sizeof(BossStorageFadFile) == 28680);\n\n\t\tstatic bool CheckIfStorageExists(const DirectoryName& bossDirectory, uint64 titleId, uint32 persistentId)\n\t\t{\n\t\t\tfs::path fadPath = ActiveSettings::GetMlcPath(\"usr/boss/{:08x}/{:08x}/user/common/{:08x}/{}\", GetTitleIdHigh(titleId), GetTitleIdLow(titleId), persistentId, bossDirectory.name2.c_str());\n\t\t\tstd::error_code ec;\n\t\t\treturn fs::exists(fadPath, ec);\n\t\t}\n\n\t\tnnResult Load(TaskId& taskId, uint64 titleId, uint32 persistentId)\n\t\t{\n\t\t\t// todo - if same FAD db already loaded then skip this\n\t\t\tm_hasValidFadData = false;\n\t\t\tmemset(&m_fadData, 0, sizeof(m_fadData));\n\t\t\tfs::path fadPath = ActiveSettings::GetMlcPath(\"usr/boss/{:08x}/{:08x}/user/common/{:08x}/{}\", GetTitleIdHigh(titleId), GetTitleIdLow(titleId), persistentId, taskId.id.c_str());\n\t\t\tstd::error_code ec;\n\t\t\tif (!fs::exists(fadPath, ec))\n\t\t\t\tfs::create_directories(fadPath, ec);\n\t\t\tfadPath /= \"fad.db\";\n\t\t\tm_fadFilePath = fadPath;\n\t\t\tFileStream* fs = FileStream::openFile2(fadPath);\n\t\t\tif (!fs)\n\t\t\t\treturn RESULT_STORAGE_NOTEXIST;\n\t\t\tfs->readData(&m_fadData, sizeof(m_fadData));\n\t\t\tdelete fs;\n\t\t\tm_hasValidFadData = true; // the file may not exist yet, so consider it valid even if we cant open it\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult CreateNewStorage(TaskId& taskId, uint64 titleId, uint32 persistentId)\n\t\t{\n\t\t\tmemset(&m_fadData, 0, sizeof(m_fadData));\n\t\t\tfs::path fadPath = ActiveSettings::GetMlcPath(\"usr/boss/{:08x}/{:08x}/user/common/{:08x}/{}\", GetTitleIdHigh(titleId), GetTitleIdLow(titleId), persistentId, taskId.id.c_str());\n\t\t\tstd::error_code ec;\n\t\t\tif (!fs::exists(fadPath, ec))\n\t\t\t\tfs::create_directories(fadPath, ec);\n\t\t\tm_fadFilePath = fadPath / \"fad.db\";\n\t\t\tFileStream* fs = FileStream::createFile2(m_fadFilePath);\n\t\t\tif (fs)\n\t\t\t{\n\t\t\t\tfs->writeData(&m_fadData, sizeof(m_fadData));\n\t\t\t\tdelete fs;\n\t\t\t\tm_hasValidFadData = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to create FAD data file at {}\", _pathToUtf8(m_fadFilePath));\n\t\t\t\treturn NN_RESULT_PLACEHOLDER_ERROR;\n\t\t\t}\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tvoid Store()\n\t\t{\n\t\t\tif (!m_hasValidFadData)\n\t\t\t\treturn;\n\t\t\tFileStream* fs = FileStream::createFile2(m_fadFilePath);\n\t\t\tif (fs)\n\t\t\t{\n\t\t\t\tfs->writeData(&m_fadData, sizeof(m_fadData));\n\t\t\t\tdelete fs;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to store FAD data to {}\", m_fadFilePath.string());\n\t\t\t}\n\t\t}\n\n\t\tvoid Clear()\n\t\t{\n\t\t\tm_hasValidFadData = false;\n\t\t\tmemset(&m_fadData, 0, sizeof(m_fadData));\n\t\t}\n\n\t\tvoid DeleteEntryByFileName(CafeString<32> fileName)\n\t\t{\n\t\t\tcemu_assert_debug(m_hasValidFadData);\n\t\t\tfor (sint32 i = 0; i < FAD_ENTRY_MAX_COUNT; i++)\n\t\t\t{\n\t\t\t\tif (m_fadData.entries[i].fileName == fileName)\n\t\t\t\t{\n\t\t\t\t\t// shift remaining entries\n\t\t\t\t\tmemmove(m_fadData.entries + i, m_fadData.entries + i + 1, (FAD_ENTRY_MAX_COUNT - i - 1) * sizeof(BossStorageFadEntry));\n\t\t\t\t\t// reset last entry\n\t\t\t\t\tmemset(m_fadData.entries + FAD_ENTRY_MAX_COUNT - 1, 0, sizeof(BossStorageFadEntry));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tnnResult AddEntry(CafeString<32> fileName, uint32 fileId)\n\t\t{\n\t\t\tif (!fileId)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Cannot add BOSS file with fileId 0\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (fileName.empty())\n\t\t\t\treturn false;\n\t\t\tDeleteEntryByFileName(fileName);\n\t\t\tcemu_assert_debug(m_hasValidFadData);\n\t\t\tfor (sint32 i=0; i<FAD_ENTRY_MAX_COUNT; i++)\n\t\t\t{\n\t\t\t\tif (m_fadData.entries[i].fileId == 0)\n\t\t\t\t{\n\t\t\t\t\tm_fadData.entries[i].fileName = fileName;\n\t\t\t\t\tm_fadData.entries[i].fileId = fileId;\n\t\t\t\t\tm_fadData.entries[i].memo_2C = 0;\n\t\t\t\t\tm_fadData.entries[i].entryCreationTimestamp = 0;\n\t\t\t\t\tm_fadData.entries[i].ukn24 = 0;\n\t\t\t\t\tm_fadData.entries[i].flags = 0;\n\t\t\t\t\treturn 0x200080;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcemuLog_log(LogType::Force, \"FAD file {} is full\", _pathToUtf8(m_fadFilePath));\n\t\t\treturn 0xA021FB00;\n\t\t}\n\n\t\tvoid GetDataList(std::vector<DataName>& dataList)\n\t\t{\n\t\t\tcemu_assert_debug(m_hasValidFadData);\n\t\t\tdataList.clear();\n\t\t\tfor (sint32 i = 0; i < FAD_ENTRY_MAX_COUNT; i++)\n\t\t\t{\n\t\t\t\tif (m_fadData.entries[i].fileId == 0)\n\t\t\t\t\tbreak; // end of list\n\t\t\t\tDataName dataName;\n\t\t\t\tdataName.name = m_fadData.entries[i].fileName;\n\t\t\t\tdataList.push_back(dataName);\n\t\t\t}\n\t\t}\n\n\t\tbool GetEntryByFilename(const DataName& fileName, BossStorageFadEntry& outEntry)\n\t\t{\n\t\t\tif (fileName.name.empty())\n\t\t\t\treturn false;\n\t\t\tcemu_assert_debug(m_hasValidFadData);\n\t\t\tfor (sint32 i = 0; i < FAD_ENTRY_MAX_COUNT; i++)\n\t\t\t{\n\t\t\t\tif (m_fadData.entries[i].fileName == fileName.name)\n\t\t\t\t{\n\t\t\t\t\toutEntry = m_fadData.entries[i];\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (m_fadData.entries[i].fileId == 0)\n\t\t\t\t\tbreak; // end of list\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\tprivate:\n\t\tBossStorageFadFile m_fadData;\n\t\tbool m_hasValidFadData = false;\n\t\tfs::path m_fadFilePath;\n\t};\n\tStorageDatabase m_fadDb;\n\n\tclass NsDataAccessor\n\t{\n\tpublic:\n\t\tnnResult Open(const DirectoryName& bossDirectory, uint64 titleId, uint32 persistentId, DataName& fileName)\n\t\t{\n\t\t\tm_isValid = false;\n\t\t\tm_nsDataPath.clear();\n\t\t\tTaskId taskId(bossDirectory.name2.c_str());\n\t\t\tnnResult r = m_fadDb.Load(taskId, titleId, persistentId);\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn r;\n\t\t\tif (!m_fadDb.GetEntryByFilename(fileName, m_fadEntry))\n\t\t\t\treturn RESULT_FADENTRY_NOTEXIST;\n\t\t\tm_nsDataPath = BuildNsDataPath(bossDirectory, titleId, persistentId, m_fadEntry.fileId);\n\t\t\tm_isValid = true;\n\t\t\tm_bossDirectory = bossDirectory;\n\t\t\tm_titleId = titleId;\n\t\t\tm_persistentId = persistentId;\n\t\t\tm_fileName = fileName;\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tvoid Close()\n\t\t{\n\t\t\tm_isValid = false;\n\t\t}\n\n\t\tnnResult Delete()\n\t\t{\n\t\t\tcemu_assert_debug(m_isValid); // only call this after successful Open()\n\t\t\tstd::error_code ec;\n\t\t\tif (!fs::remove(m_nsDataPath, ec) )\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to delete BOSS file {}\", _pathToUtf8(m_nsDataPath));\n\t\t\t// remove from FAD\n\t\t\tTaskId taskId(m_bossDirectory.name2.c_str());\n\t\t\tnnResult r = m_fadDb.Load(taskId, m_titleId, m_persistentId);\n\t\t\tif (NN_RESULT_IS_SUCCESS(r))\n\t\t\t\tm_fadDb.DeleteEntryByFileName(m_fileName.name);\n\t\t\tm_isValid = false;\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tbool Exists() const\n\t\t{\n\t\t\tif (!m_isValid)\n\t\t\t\treturn false;\n\t\t\t// check if the file actually exists on the host filesystem\n\t\t\tstd::error_code ec;\n\t\t\tif (m_nsDataPath.empty())\n\t\t\t\treturn false;\n\t\t\tbool r = fs::exists(m_nsDataPath, ec);\n\t\t\tif (!r)\n\t\t\t\tcemuLog_log(LogType::Force, \"BOSS: File exists in FAD cache but not on disk {}. To fix this reset the SpotPass cache. In the menu under debug select \\\"Clear SpotPass cache\\\"\", _pathToUtf8(m_nsDataPath));\n\t\t\treturn r;\n\t\t}\n\n\t\tnnResult GetSize(uint32& fileSize) const\n\t\t{\n\t\t\tcemu_assert_debug(m_isValid); // only call this after successful Open()\n\t\t\tif (!m_isValid)\n\t\t\t\treturn NN_RESULT_PLACEHOLDER_ERROR;\n\t\t\tstd::unique_ptr<FileStream> fs(FileStream::openFile2(m_nsDataPath));\n\t\t\tif (!fs)\n\t\t\t\treturn NN_RESULT_PLACEHOLDER_ERROR;\n\t\t\tfileSize = (uint32)fs->GetSize();\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tbool Read(void* buffer, uint32 size, uint32 offset, uint32& bytesRead)\n\t\t{\n\t\t\tif (!m_isValid)\n\t\t\t\treturn false;\n\t\t\tstd::unique_ptr<FileStream> fs(FileStream::openFile2(m_nsDataPath));\n\t\t\tif (!fs)\n\t\t\t\treturn false;\n\t\t\tfs->SetPosition(offset);\n\t\t\tbytesRead = (uint32)fs->readData(buffer, size);\n\t\t\treturn true;\n\t\t}\n\n\tprivate:\n\t\tfs::path BuildNsDataPath(const DirectoryName& bossDirectory, uint64 titleId, uint32 persistentId, uint32 dataId)\n\t\t{\n\t\t\treturn ActiveSettings::GetMlcPath(\"usr/boss/{:08x}/{:08x}/user/common/data/{}/{:08x}\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF), bossDirectory.name2.c_str(), dataId);\n\t\t}\n\n\t\tbool m_isValid{false};\n\t\tStorageDatabase::BossStorageFadEntry m_fadEntry;\n\t\tfs::path m_nsDataPath;\n\t\t// if m_isValid is true, these hold the current file information:\n\t\tDirectoryName m_bossDirectory;\n\t\tuint64 m_titleId{};\n\t\tuint32 m_persistentId{};\n\t\tDataName m_fileName;\n\t};\n\n\tNsDataAccessor m_nsDataAccessor;\n\n\tclass RegisteredTask\n\t{\n\tpublic:\n\t\tRegisteredTask(const TaskId& taskId, const TaskSettingCore& taskSettings)\n\t\t\t: m_taskId(taskId), m_taskSettings(taskSettings)\n\t\t{\n\t\t\tm_persistentId = iosuAct_getAccountIdOfCurrentAccount();\n\t\t}\n\n\t\tnnResult Run()\n\t\t{\n\t\t\tstd::unique_lock _l(m_mutex);\n\t\t\tcemu_assert_debug(m_taskState == TaskState::Initial || m_taskState == TaskState::Done);\n\t\t\tm_taskTurnState = TaskTurnState::Ready;\n\t\t\tm_taskState = TaskState::Ready;\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tTaskState GetState()\n\t\t{\n\t\t\tstd::unique_lock _l(m_mutex);\n\t\t\treturn m_taskState;\n\t\t}\n\n\t\tTaskTurnState GetTurnState()\n\t\t{\n\t\t\tstd::unique_lock _l(m_mutex);\n\t\t\treturn m_taskTurnState;\n\t\t}\n\n\t\tsint32 GetHttpStatusCode() const\n\t\t{\n\t\t\treturn m_httpStatusCode;\n\t\t}\n\n\t\tuint32 GetContentLength() const\n\t\t{\n\t\t\treturn m_contentLength;\n\t\t}\n\n\t\tuint32 GetProcessedLength() const\n\t\t{\n\t\t\treturn m_contentLength; // todo - unlike content length, this value is getting updated as the download happens. But for now we just return the content length\n\t\t}\n\n\t\tnnResult TaskDoRequest(CURL* curl)\n\t\t{\n\t\t\tstd::unique_lock _l(m_mutex);\n\t\t\tif (m_taskState != TaskState::Ready)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Task {} is not ready to run, current state: {}\", m_taskId.id.c_str(), static_cast<uint32>(m_taskState));\n\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_FATAL, NN_RESULT_MODULE_NN_BOSS, 0);\n\t\t\t}\n\t\t\tm_taskState = TaskState::Running;\n\t\t\tm_taskTurnState = TaskTurnState::Running;\n\t\t\tm_contentLength = 0;\n\t\t\t_l.unlock();\n\t\t\tif (!ActiveSettings::IsOnlineEnabled())\n\t\t\t{\n\t\t\t\tm_taskState = TaskState::Done;\n\t\t\t\tm_taskTurnState = TaskTurnState::DoneError;\n\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_BOSS, 0);\n\t\t\t}\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\t// construct request URL\n\t\t\tstd::string requestUrl;\n\t\t\tif (!m_taskSettings.url.empty())\n\t\t\t\trequestUrl.assign(m_taskSettings.url.c_str()); // custom url\n\t\t\telse\n\t\t\t{\n\t\t\t\tswitch (ActiveSettings::GetNetworkService())\n\t\t\t\t{\n\t\t\t\tcase NetworkService::Pretendo:\n\t\t\t\t\trequestUrl = PretendoURLs::BOSSURL;\n\t\t\t\t\tbreak;\n\t\t\t\tcase NetworkService::Custom:\n\t\t\t\t\trequestUrl = GetNetworkConfig().urls.BOSS.GetValue();\n\t\t\t\t\tbreak;\n\t\t\t\tcase NetworkService::Nintendo:\n\t\t\t\tdefault:\n\t\t\t\t\trequestUrl = NintendoURLs::BOSSURL;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tchar languageCode[8];\n\t\t\tswitch (GetConfig().console_language)\n\t\t\t{\n\t\t\tcase CafeConsoleLanguage::JA:\n\t\t\t\tstrcpy(languageCode, \"ja\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::EN:\n\t\t\t\tstrcpy(languageCode, \"en\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::FR:\n\t\t\t\tstrcpy(languageCode, \"fr\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::DE:\n\t\t\t\tstrcpy(languageCode, \"de\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::IT:\n\t\t\t\tstrcpy(languageCode, \"it\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::ES:\n\t\t\t\tstrcpy(languageCode, \"es\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::ZH:\n\t\t\t\tstrcpy(languageCode, \"zh\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::KO:\n\t\t\t\tstrcpy(languageCode, \"ko\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::NL:\n\t\t\t\tstrcpy(languageCode, \"nl\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::PT:\n\t\t\t\tstrcpy(languageCode, \"pt\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::RU:\n\t\t\t\tstrcpy(languageCode, \"ru\");\n\t\t\t\tbreak;\n\t\t\tcase CafeConsoleLanguage::TW:\n\t\t\t\tstrcpy(languageCode, \"tw\"); // usually zh-tw?\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tstrcpy(languageCode, \"en\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst char* countryCode = NCrypto::GetCountryAsString(Account::GetCurrentAccount().GetCountry());\n\t\t\tif (m_taskSettings.taskType == TaskType::NbdlDataListTaskSetting)\n\t\t\t{\n\t\t\t\t// use bossCode (and fileName?) as part of the URL\n\t\t\t\trequestUrl.append(fmt::format(fmt::runtime(\"/{}/{}/{}?c={}&l={}\"), \"1\", m_taskSettings.nbdl.bossCode.c_str(), m_taskId.id.c_str(), countryCode, languageCode));\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"IOSU-BOSS: Unsupported task type: {}\", static_cast<uint32>(m_taskSettings.taskType.value()));\n\t\t\t\t_l.lock();\n\t\t\t\tm_taskState = TaskState::Done;\n\t\t\t\tm_taskTurnState = TaskTurnState::DoneError;\n\t\t\t\tm_contentLength = 0;\n\t\t\t\tm_httpStatusCode = 0;\n\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_BOSS, 0);\n\t\t\t}\n\t\t\telse if (m_taskSettings.taskType == TaskType::NbdlTaskSetting)\n\t\t\t{\n\t\t\t\t// todo - language and country code come from the task settings\n\t\t\t\tcemu_assert_debug(m_taskSettings.nbdl.fileName.empty()); // todo - changes the url\n\t\t\t\tconst char* apiVersion = \"1\";\n\t\t\t\trequestUrl.append(fmt::format(fmt::runtime(\"/{}/{}/{}?c={}&l={}\"), apiVersion, m_taskSettings.nbdl.bossCode.c_str(), m_taskId.id.c_str(), countryCode, languageCode));\n\t\t\t}\n\t\t\telse if (m_taskSettings.taskType == TaskType::PlayReportSetting)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"IOSU-BOSS: PlayReport tasks are not implemented yet\");\n\t\t\t\t_l.lock();\n\t\t\t\tm_taskState = TaskState::Done;\n\t\t\t\tm_taskTurnState = TaskTurnState::DoneError;\n\t\t\t\tm_contentLength = 0;\n\t\t\t\tm_httpStatusCode = 200;\n\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_BOSS, 0);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"IOSU-BOSS: Unknown task type: {}\", static_cast<uint32>(m_taskSettings.taskType.value()));\n\t\t\t\t_l.lock();\n\t\t\t\tm_taskState = TaskState::Done;\n\t\t\t\tm_taskTurnState = TaskTurnState::DoneError;\n\t\t\t\tm_contentLength = 0;\n\t\t\t\tm_httpStatusCode = 0;\n\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_BOSS, 0);\n\t\t\t}\n\n\t\t\tCurlRequestHelper request;\n\t\t\trequest.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::CUSTOM);\n\t\t\t// add certs\n\t\t\tSetupSSL(request);\n\t\t\t// parameters\n\t\t\tAppendHeaderParam(request, \"X-BOSS-Digest:\", \"\"); // todo - implement this\n\t\t\tAppendHeaderParam(request, \"X-Boss-UniqueId\", \"{:05x}\", ((titleId >> 8) & 0xFFFFF));\n\t\t\tAppendHeaderParam(request, \"X-BOSS-TitleId\", \"{:016x}\", titleId);\n\t\t\tif (!m_taskSettings.serviceToken.empty())\n\t\t\t\tAppendHeaderParam(request, \"X-Nintendo-ServiceToken\", \"{}\", m_taskSettings.serviceToken.c_str());\n\n\t\t\tif (!request.submitRequest(false))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed BOSS request\"));\n\t\t\t\t_l.lock();\n\t\t\t\tm_taskState = TaskState::Done;\n\t\t\t\tm_taskTurnState = TaskTurnState::DoneError;\n\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_FATAL, NN_RESULT_MODULE_NN_BOSS, 0);\n\t\t\t}\n\t\t\tsint32 httpStatusCode = request.GetHTTPStatusCode();\n\t\t\tm_httpStatusCode = httpStatusCode;\n\t\t\tm_contentLength = request.getReceivedData().size(); // note - for Nbdl tasks which length is returned?\n\n\t\t\t{\n\t\t\t\tif (httpStatusCode != 200)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"BOSS task_run: Received unexpected HTTP response code {}\", httpStatusCode);\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"URL: {}\", requestUrl);\n\t\t\t\t}\n\t\t\t\tif (httpStatusCode == 404)\n\t\t\t\t{\n\t\t\t\t\t_l.lock();\n\t\t\t\t\tm_taskState = TaskState::Done;\n\t\t\t\t\tm_taskTurnState = TaskTurnState::DoneError;\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"BOSS task_run: Received 404 Not Found for URL: {}\", requestUrl);\n\t\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_FATAL, NN_RESULT_MODULE_NN_BOSS, 0);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// for Nbdl tasks get the list of files to download\n\t\t\tif (m_taskSettings.taskType == TaskType::NbdlTaskSetting)\n\t\t\t{\n\t\t\t\tstd::vector<NbdlQueuedFile> queuedFiles = ParseNbdlTasksheet(request.getReceivedData());\n\t\t\t\tcemuLog_log(LogType::Force, \"SpotPass - NbdlTask has {} files to download:\", queuedFiles.size());\n\t\t\t\tfor (const auto& file : queuedFiles)\n\t\t\t\t{\n\t\t\t\t\tDownloadNbdlFile(file);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (m_taskSettings.taskType == TaskType::RawDlTaskSetting_1 || m_taskSettings.taskType == TaskType::RawDlTaskSetting_3 || m_taskSettings.taskType == TaskType::RawDlTaskSetting_9)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\t{\n\t\t\t\t_l.lock();\n\t\t\t\tm_taskState = TaskState::Done;\n\t\t\t\tm_taskTurnState = TaskTurnState::DoneSuccess;\n\t\t\t}\n\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_BOSS, 0);\n\t\t}\n\n\t\tstd::recursive_mutex& GetMutex() { return m_mutex; }\n\tprivate:\n\t\tstruct NbdlQueuedFile\n\t\t{\n\t\t\tNbdlQueuedFile(std::string_view url, std::string_view fileName, uint32 dataId, uint32 fileType, uint32 size)\n\t\t\t\t: url(url), fileName(fileName), dataId(dataId), fileType(fileType), size(size)\n\t\t\t{}\n\n\t\t\tstd::string url;\n\t\t\tstd::string fileName;\n\t\t\tuint32 dataId;\n\t\t\tuint32 fileType; // 0 = AppData, 1 = Message, 2 = Unknown\n\t\t\tuint32 size;\n\t\t};\n\n\t\tstd::vector<NbdlQueuedFile> ParseNbdlTasksheet(std::span<uint8> xmlContent)\n\t\t{\n\t\t\tpugi::xml_document doc;\n\t\t\tpugi::xml_parse_result result = doc.load_buffer(xmlContent.data(), xmlContent.size());\n\t\t\tif (!result)\n\t\t\t\treturn {};\n\t\t\tstd::vector<NbdlQueuedFile> fileList;\n\t\t\tfor (pugi::xml_node sheet = doc.child(\"TaskSheet\"); sheet; sheet = sheet.next_sibling(\"TaskSheet\"))\n\t\t\t{\n\t\t\t\tpugi::xml_node serviceStatus = sheet.child(\"ServiceStatus\");\n\t\t\t\tif (strcmp(serviceStatus.child_value(), \"close\") == 0)\n\t\t\t\t{\n\t\t\t\t\t// service is closed, skip all files\n\t\t\t\t\tcemuLog_log(LogType::Force, \"BossNbdl: Service is closed, skipping all files in tasksheet\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (strcmp(serviceStatus.child_value(), \"open\") != 0)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"BossNbdl: Unknown ServiceStatus value: {}\", serviceStatus.child_value());\n\t\t\t\t}\n\t\t\t\t// read and verify titleId\n\t\t\t\tpugi::xml_node nodeTitleId = sheet.child(\"TitleId\");\n\t\t\t\tif (nodeTitleId)\n\t\t\t\t{\n\t\t\t\t\tuint64 titleId;\n\t\t\t\t\tTitleIdParser::ParseFromStr(nodeTitleId.child_value(), titleId);\n\t\t\t\t\tif (titleId != CafeSystem::GetForegroundTitleId())\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"BossNbdl: TitleId in tasksheet ({:016x}) does not match foreground titleId ({:016x})\", titleId, CafeSystem::GetForegroundTitleId());\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"BossNbdl: Missing TitleId field in tasksheet\");\n\t\t\t\t}\n\t\t\t\t// read and verify taskId\n\t\t\t\tpugi::xml_node nodeTaskId = sheet.child(\"TaskId\");\n\t\t\t\tif (nodeTaskId)\n\t\t\t\t{\n\t\t\t\t\tif (strcmp(nodeTaskId.child_value(), m_taskId.id.c_str()) != 0)\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"BossNbdl: TaskId in tasksheet ({}) does not match current taskId ({})\", nodeTaskId.child_value(), m_taskId.id.c_str());\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"BossNbdl: Missing TaskId field in tasksheet\");\n\t\t\t\t}\n\n\t\t\t\t// read files list\n\t\t\t\tpugi::xml_node files = sheet.child(\"Files\");\n\t\t\t\tif (!files)\n\t\t\t\t\tcontinue;\n\t\t\t\tfor (pugi::xml_node file = files.child(\"File\"); file; file = file.next_sibling(\"File\"))\n\t\t\t\t{\n\t\t\t\t\tpugi::xml_node fileName = file.child(\"Filename\");\n\t\t\t\t\tif (!fileName)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tpugi::xml_node dataId = file.child(\"DataId\");\n\t\t\t\t\tif (!dataId)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tpugi::xml_node url = file.child(\"Url\");\n\t\t\t\t\tif (!url)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tpugi::xml_node size = file.child(\"Size\");\n\t\t\t\t\tif (!size)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tpugi::xml_node type = file.child(\"Type\");\n\t\t\t\t\tif (!type)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tuint32 fileType;\n\t\t\t\t\tif (strcmp(type.child_value(), \"AppData\") == 0)\n\t\t\t\t\t\tfileType = 0;\n\t\t\t\t\telse if (strcmp(type.child_value(), \"Message\") == 0)\n\t\t\t\t\t\tfileType = 1;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"BossNbdl: Unknown file Type value: {}\", type.child_value());\n\t\t\t\t\t\tfileType = 0;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!file.child(\"AutoDelete\").empty())\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"BossNbdl: Field AutoDelete is set but not supported. Value: {}\", file.child_value(\"AutoDelete\"));\n\n\t\t\t\t\t// fields and categories which we dont handle yet:\n\t\t\t\t\t// Attributes, Attribute1, Attribute2, Attribute3\n\t\t\t\t\t// Notify, Conditions, SecInterval, LED, Played\n\n\t\t\t\t\tfileList.emplace_back(\n\t\t\t\t\t\turl.child_value(),\n\t\t\t\t\t\tfileName.child_value(),\n\t\t\t\t\t\tdataId.text().as_int(),\n\t\t\t\t\t\tfileType,\n\t\t\t\t\t\tsize.text().as_int()\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn fileList;\n\t\t}\n\n\t\tvoid SetupSSL(CurlRequestHelper& request)\n\t\t{\n\t\t\trequest.ClearCaCertIds();\n\t\t\trequest.ClearClientCertIds();\n\t\t\tfor (sint32 i=0; i<3; i++)\n\t\t\t{\n\t\t\t\tif (m_taskSettings.internalCaCert[i] != 0)\n\t\t\t\t\trequest.AddCaCertId(m_taskSettings.internalCaCert[i]);\n\t\t\t}\n\t\t\trequest.AddCaCertId(105);\n\t\t\tif (m_taskSettings.internalClientCert != 0)\n\t\t\t\trequest.AddCaCertId(m_taskSettings.internalClientCert);\n\t\t\telse\n\t\t\t\trequest.AddCaCertId(3); // whats the default for each task type?\n\t\t\tcemu_assert_debug(m_taskSettings.caCert[0].empty());\n\t\t\tcemu_assert_debug(m_taskSettings.caCert[1].empty());\n\t\t\tcemu_assert_debug(m_taskSettings.caCert[2].empty());\n\t\t\tcemu_assert_debug(m_taskSettings.clientCertName.empty());\n\t\t}\n\n\t\tvoid DownloadNbdlFile(const NbdlQueuedFile& nbdlFile)\n\t\t{\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId(); // todo - use titleId from task settings?\n\t\t\tfs::path dataFilePath = ActiveSettings::GetMlcPath(\"usr/boss/{:08x}/{:08x}/user/common/data/{}/{:08x}\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF), m_taskId.id.c_str(), nbdlFile.dataId);\n\n\t\t\t// if the file already exists locally, skip download\n\t\t\t// but still add the entry to the FAD db\n\t\t\tstd::error_code ec;\n\t\t\tif (fs::exists(dataFilePath))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"\\t- {} (DataId:{:08x} {}KB) (Skipping, already downloaded)\", nbdlFile.fileName, nbdlFile.dataId, (nbdlFile.size+1023)/1024);\n\t\t\t\tTrackDownloadedNbdlFile(nbdlFile);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcemuLog_log(LogType::Force, \"\\t- {} (DataId:{:08x} {}KB)\", nbdlFile.fileName, nbdlFile.dataId, (nbdlFile.size+1023)/1024);\n\n\t\t\tCurlRequestHelper request;\n\t\t\trequest.initate(ActiveSettings::GetNetworkService(), nbdlFile.url, CurlRequestHelper::SERVER_SSL_CONTEXT::CUSTOM);\n\t\t\tSetupSSL(request);\n\n\t\t\tbool r = request.submitRequest();\n\t\t\tif (!r)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to download SpotPass nbdl file: {}\", nbdlFile.fileName);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// decrypt and store file\n\t\t\tstd::vector<uint8> receivedData = request.getReceivedData();\n\t\t\tstruct BossNbdlHeader\n\t\t\t{\n\t\t\t\t/* +0x00 */ uint32be magic;\n\t\t\t\t/* +0x04 */\tuint32be version; // guessed\n\t\t\t\t/* +0x08 */\tuint16be ukn08; // must always be 1\n\t\t\t\t/* +0x0A */\tuint16be ukn0A; // must always be 2\n\t\t\t\t/* +0x0C */\tuint8 nonce[0xC];\n\t\t\t\t/* +0x18 */\tuint32 padding18; // unused\n\t\t\t\t/* +0x1C */\tuint32 padding1C; // unused\n\t\t\t\t/* +0x20 */\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tuint8 uknHashData[0x20];\n\t\t\t\t} encryptedHeader;\n\t\t\t};\n\t\t\tif (receivedData.size() < sizeof(BossNbdlHeader))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Received SpotPass nbdl file is too small: {} bytes\", receivedData.size());\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tBossNbdlHeader nbdlHeader;\n\t\t\tmemcpy(&nbdlHeader, receivedData.data(), sizeof(BossNbdlHeader));\n\t\t\tif (nbdlHeader.magic != 'boss' || nbdlHeader.version != 0x20001 || nbdlHeader.ukn08 != 1 || nbdlHeader.ukn0A != 2)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Received SpotPass nbdl file has incorrect header\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// file must be padded to 16 byte alignment for AES decryption (padding is cut off after decryption)\n\t\t\tsize_t originalFileSize = receivedData.size();\n\t\t\tconst uint32 paddedFileSize = (originalFileSize + 0xF) & (~0xF);\n\t\t\treceivedData.resize(paddedFileSize);\n\t\t\t// extra validation\n\t\t\tif (originalFileSize != nbdlFile.size)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"SpotPass nbdl file size mismatch, expected {} bytes but got {} bytes\", nbdlFile.size, originalFileSize);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (nbdlFile.fileName.find(\"..\") != std::string::npos)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"SpotPass nbdl filename contains suspicious characters\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// prepare nonce for AES128-CTR\n\t\t\tuint8 aesNonce[0x10];\n\t\t\tmemset(aesNonce, 0, sizeof(aesNonce));\n\t\t\tmemcpy(aesNonce, nbdlHeader.nonce, 0xC);\n\t\t\taesNonce[0xF] = 1;\n\t\t\t// decrypt\n\t\t\tuint8 bossAesKey[16] = { 0x39,0x70,0x57,0x35,0x58,0x70,0x34,0x58,0x37,0x41,0x7a,0x30,0x71,0x5a,0x70,0x74 };\n\t\t\tmemset(aesNonce, 0, sizeof(aesNonce));\n\t\t\tmemcpy(aesNonce, nbdlHeader.nonce, 0xC);\n\t\t\taesNonce[0xF] = 1;\n\t\t\tAES128CTR_transform(receivedData.data() + offsetof(BossNbdlHeader, encryptedHeader), receivedData.size() - sizeof(BossNbdlHeader::encryptedHeader), bossAesKey, aesNonce);\n\t\t\t// get HMAC from header\n\t\t\tuint8 fileHMAC[32];\n\t\t\tmemcpy(fileHMAC, &((BossNbdlHeader*)receivedData.data())->encryptedHeader.uknHashData, 32);\n\t\t\t// write decrypted data to filesystem using a temporary path\n\t\t\tfs::path tmpDataPath = ActiveSettings::GetMlcPath(\"usr/boss/{:08x}/{:08x}/user/common/data/{}/.{:08x}\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF), m_taskId.id.c_str(), nbdlFile.dataId);\n\t\t\tif (!fs::exists(tmpDataPath.parent_path()))\n\t\t\t\tfs::create_directories(tmpDataPath.parent_path(), ec);\n\t\t\tFileStream* fs = FileStream::createFile2(tmpDataPath);\n\t\t\tif (fs)\n\t\t\t{\n\t\t\t\tfs->writeData(receivedData.data() + sizeof(BossNbdlHeader), originalFileSize - sizeof(BossNbdlHeader));\n\t\t\t\tdelete fs;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to create temporary SpotPass nbdl file: {}\", _pathToUtf8(tmpDataPath));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// to make sure that the file actually stored correctly to disk we read it back and verify the hash\n\t\t\tauto readbackFileData = FileStream::LoadIntoMemory(tmpDataPath);\n\t\t\tuint8 hmacHash[32];\n\t\t\tunsigned int hmacHashLen = 32;\n\t\t\tHMAC(EVP_sha256(), \"uyr5I8pu4ycq2pOT3D53Bp0n7jK8eyjLO5U20ocUNdN5muwUcC4By881UXECeM08\", 64, readbackFileData->data(), originalFileSize - sizeof(BossNbdlHeader), hmacHash, &hmacHashLen);\n\t\t\tif (memcmp(hmacHash, fileHMAC, 32) != 0)\n\t\t\t{\n\t\t\t\t// failed to verify hash\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to verify hash for SpotPass nbdl file: {}\", _pathToUtf8(tmpDataPath));\n\t\t\t\tfs::remove(tmpDataPath, ec);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// rename temporary file to final path\n\t\t\tfs::rename(tmpDataPath, dataFilePath, ec);\n\t\t\t// update FAD entry\n\t\t\tTrackDownloadedNbdlFile(nbdlFile);\n\t\t}\n\n\t\tvoid TrackDownloadedNbdlFile(const NbdlQueuedFile& nbdlFile)\n\t\t{\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\tnnResult storageResult = m_fadDb.Load(m_taskId, titleId, m_persistentId);\n\t\t\tif (storageResult == RESULT_STORAGE_NOTEXIST)\n\t\t\t\tstorageResult = m_fadDb.CreateNewStorage(m_taskId, titleId, m_persistentId);\n\t\t\tif (NN_RESULT_IS_FAILURE(storageResult))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to create FAD database for task {}: {:08x}\", m_taskId.id.c_str(), storageResult);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tCafeString<32> filenameStr;\n\t\t\tfilenameStr.assign(nbdlFile.fileName);\n\t\t\tm_fadDb.AddEntry(filenameStr, nbdlFile.dataId);\n\t\t\tm_fadDb.Store();\n\t\t\t// todo - DIDX and ref database\n\t\t}\n\n\t\tTaskId m_taskId;\n\t\tuint32 m_persistentId;\n\t\tTaskSettingCore m_taskSettings;\n\t\tstd::recursive_mutex m_mutex;\n\t\tTaskState m_taskState{ TaskState::Initial };\n\t\tTaskTurnState m_taskTurnState{ TaskTurnState::Ukn };\n\t\tsint32 m_httpStatusCode{ 0 };\n\t\tuint32 m_contentLength{ 0 }; // content length of the last request\n\t};\n\n\tclass BossDaemon\n\t{\n\tpublic:\n\t\tvoid Start()\n\t\t{\n\t\t\tif (m_threadRunning.exchange(true))\n\t\t\t\treturn;\n\t\t\tm_bossDaemonThread = std::thread(&BossDaemon::BossDaemonThread, this);\n\t\t}\n\n\t\tvoid Stop()\n\t\t{\n\t\t\tif (!m_threadRunning.exchange(false))\n\t\t\t\treturn;\n\t\t\tm_bossDaemonThread.join();\n\t\t}\n\n\t\tvoid RegisterTask(const TaskSettingCore& taskSetting)\n\t\t{\n\t\t\tstd::unique_lock _l(m_taskMtx);\n\t\t\tif (m_registeredTasks.find(taskSetting.taskId) != m_registeredTasks.end())\n\t\t\t{\n\t\t\t\t// task already registered. Return error?\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"IOSU-Boss: Task {} is already registered\", taskSetting.taskId.id.c_str());\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tm_registeredTasks.try_emplace(taskSetting.taskId, std::make_shared<RegisteredTask>(taskSetting.taskId, taskSetting));\n\t\t}\n\n\t\tvoid UnregisterTask(uint32 persistentId, const TaskId& taskId)\n\t\t{\n\t\t\tstd::unique_lock _l(m_taskMtx);\n\t\t\tauto it = m_registeredTasks.find(taskId);\n\t\t\tif (it != m_registeredTasks.end())\n\t\t\t{\n\t\t\t\tm_registeredTasks.erase(it);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// todo - return error\n\t\t\t}\n\t\t}\n\n\t\tbool TaskIsRegistered(uint32 persistentId, const TaskId& taskId)\n\t\t{\n\t\t\tstd::unique_lock _l(m_taskMtx);\n\t\t\treturn m_registeredTasks.find(taskId) != m_registeredTasks.end();\n\t\t}\n\n\t\tvoid TaskRun(uint32 persistentId, const TaskId& taskId)\n\t\t{\n\t\t\t// todo - there is an extra parameter for controlling background/foreground running?\n\t\t\tstd::shared_ptr<RegisteredTask> registeredTask = GetRegisteredTask2(persistentId, taskId);\n\t\t\tif (registeredTask)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"IOSU-Boss: Running task {}\", taskId.id.c_str());\n\t\t\t\tregisteredTask->Run();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"IOSU-Boss: Trying to run task {} which has not been registered\", taskId.id.c_str());\n\t\t\t\t// todo - return error -> 0xA021F900\n\t\t\t}\n\t\t}\n\n\t\tvoid StartScheduleTask(uint32 persistentId, const TaskId& taskId, bool runImmediately)\n\t\t{\n\t\t\tif (runImmediately)\n\t\t\t{\n\t\t\t\t// proper implementation is still todo\n\t\t\t\t// handling automatic scheduling and task state transitions is quite complex\n\t\t\t\t// for now we only run the task once\n\t\t\t\tstd::shared_ptr<RegisteredTask> registeredTask = GetRegisteredTask2(persistentId, taskId);\n\t\t\t\tif(!registeredTask)\n\t\t\t\t\treturn;\n\t\t\t\tTaskState state = registeredTask->GetState();\n\t\t\t\tif (state == TaskState::Stopped || state == TaskState::Initial)\n\t\t\t\t{\n\t\t\t\t\tregisteredTask->Run();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"StartScheduleTask(): No support for scheduling tasks that aren't in stopped state\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"IOSU-Boss: Unsupported StartScheduling called for task {}\", taskId.id.c_str());\n\t\t\t}\n\t\t}\n\n\t\tvoid StopScheduleTask(uint32 persistentId, const TaskId& taskId)\n\t\t{\n\t\t\t// todo\n\t\t\t// task scheduling is not yet implemented so this does nothing for now\n\t\t}\n\n\t\tstd::shared_ptr<RegisteredTask> GetRegisteredTask2(const uint32 persistentId, const TaskId& taskId)\n\t\t{\n\t\t\tstd::unique_lock _l(m_taskMtx);\n\t\t\tauto it = m_registeredTasks.find(taskId); // todo - check persistentId as well (make it part of the key?)\n\t\t\tif (it != m_registeredTasks.end())\n\t\t\t\treturn it->second;\n\t\t\treturn nullptr;\n\t\t}\n\n\tprivate:\n\t\tvoid BossDaemonThread()\n\t\t{\n\t\t\tCURL* curl = curl_easy_init();\n\t\t\twhile ( m_threadRunning )\n\t\t\t{\n\t\t\t\t// check for tasks to run\n\t\t\t\t{\n\t\t\t\t\tstd::shared_ptr<RegisteredTask> task = GetNextRunableTask();\n\t\t\t\t\tif (task)\n\t\t\t\t\t{\n\t\t\t\t\t\ttask->TaskDoRequest(curl);\n\t\t\t\t\t\tcemu_assert_debug(task->GetState() != TaskState::Ready);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t\t\t}\n\t\t\tcurl_easy_cleanup(curl);\n\t\t}\n\n\t\tstd::shared_ptr<RegisteredTask> GetNextRunableTask()\n\t\t{\n\t\t\tstd::unique_lock _l(m_taskMtx);\n\t\t\tfor (auto& task : m_registeredTasks)\n\t\t\t{\n\t\t\t\tif (task.second->GetState() == TaskState::Ready)\n\t\t\t\t\treturn task.second;\n\t\t\t}\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tstd::thread m_bossDaemonThread;\n\t\tstd::atomic_bool m_threadRunning{ false };\n\t\t// task list\n\t\tstd::mutex m_taskMtx;\n\t\tstd::map<TaskId, std::shared_ptr<RegisteredTask>> m_registeredTasks;\n\t}s_bossDaemon;\n\n\tclass BossMainService : public iosu::nn::IPCService\n\t{\n\tpublic:\n\t\tBossMainService() : iosu::nn::IPCService(\"/dev/boss\") {}\n\n\t\tnnResult ServiceCall(IPCServiceCall& serviceCall) override\n\t\t{\n\t\t\tif (serviceCall.GetServiceId() == 0)\n\t\t\t{\n\t\t\t\tswitch (static_cast<BossCommandId>(serviceCall.GetCommandId()))\n\t\t\t\t{\n\t\t\t\tcase BossCommandId::TaskIsRegistered:\n\t\t\t\t\treturn HandleTaskIsRegistered(serviceCall);\n\t\t\t\tcase BossCommandId::TaskRegisterA:\n\t\t\t\t\treturn HandleTaskRegister(serviceCall, false);\n\t\t\t\tcase BossCommandId::TaskRegisterForImmediateRunA:\n\t\t\t\t\treturn HandleTaskRegister(serviceCall, true);\n\t\t\t\tcase BossCommandId::TaskUnregister:\n\t\t\t\t\treturn HandleTaskUnregister(serviceCall);\n\t\t\t\tcase BossCommandId::TaskRun:\n\t\t\t\t\treturn HandleTaskRun(serviceCall);\n\t\t\t\tcase BossCommandId::TaskStartScheduling:\n\t\t\t\t\treturn HandleTaskStartScheduling(serviceCall);\n\t\t\t\tcase BossCommandId::TaskStopScheduling:\n\t\t\t\t\treturn HandleTaskStopScheduling(serviceCall);\n\t\t\t\tcase BossCommandId::TaskWaitA:\n\t\t\t\t\treturn HandleTaskWait(serviceCall);\n\t\t\t\tcase BossCommandId::TaskGetTurnState:\n\t\t\t\t\treturn HandleTaskGetTurnState(serviceCall);\n\t\t\t\tcase BossCommandId::TaskGetHttpStatusCodeA:\n\t\t\t\t\treturn HandleTaskGetHttpStatusCodeA(serviceCall);\n\t\t\t\tcase BossCommandId::TaskGetContentLength:\n\t\t\t\t\treturn HandleTaskGetContentLength(serviceCall);\n\t\t\t\tcase BossCommandId::TaskGetProcessedLength:\n\t\t\t\t\treturn HandleTaskGetProcessedLength(serviceCall);\n\t\t\t\tcase BossCommandId::UknA7:\n\t\t\t\t\treturn HandleUknA7(serviceCall);\n\t\t\t\tcase BossCommandId::DeleteDataRelated:\n\t\t\t\t\treturn HandleDeleteDataRelated(serviceCall);\n\t\t\t\tcase BossCommandId::StorageExist:\n\t\t\t\t\treturn HandleStorageExist(serviceCall);\n\t\t\t\tcase BossCommandId::StorageGetDataList:\n\t\t\t\t\treturn HandleStorageGetDataList(serviceCall);\n\t\t\t\tcase BossCommandId::NsDataExist:\n\t\t\t\t\treturn HandleNsDataExist(serviceCall);\n\t\t\t\tcase BossCommandId::NsDataRead:\n\t\t\t\t\treturn HandleNsDataRead(serviceCall);\n\t\t\t\tcase BossCommandId::NsDataGetSize:\n\t\t\t\t\treturn HandleNsDataGetSize(serviceCall);\n\t\t\t\tcase BossCommandId::NsDataDeleteFile:\n\t\t\t\t\treturn HandleNsDataDeleteFile(serviceCall, false);\n\t\t\t\tcase BossCommandId::NsDataDeleteFileWithHistory:\n\t\t\t\t\treturn HandleNsDataDeleteFile(serviceCall, true);\n\t\t\t\tcase BossCommandId::NsFinalize:\n\t\t\t\t\treturn HandleNsFinalize(serviceCall);\n\t\t\t\tcase BossCommandId::TitleSetNewArrivalFlag:\n\t\t\t\t\treturn HandleTitleSetNewArrivalFlag(serviceCall);\n\t\t\t\tdefault:\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Unsupported service call to /dev/boss\");\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t}\n\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_BOSS, 0);\n\t\t}\n\n\t\t// helper function to get proper persistentId\n\t\tuint32 BossGetPersistentId(uint32 persistentId)\n\t\t{\n\t\t\tif (persistentId != 0)\n\t\t\t\treturn persistentId;\n\t\t\tuint32 currentPersistentId;\n\t\t\tbool r = iosu::act::GetPersistentId(iosu::act::ACT_SLOT_CURRENT, &currentPersistentId);;\n\t\t\tif (!r)\n\t\t\t\treturn 0;\n\t\t\treturn currentPersistentId;\n\t\t}\n\n\t\tnnResult HandleTaskIsRegistered(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\tbool isRegistered = s_bossDaemon.TaskIsRegistered(persistentId, taskId);\n\t\t\t// write response\n\t\t\tserviceCall.WriteResponse<uint8be>(isRegistered ? 1 : 0);\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleTaskRegister(IPCServiceCall& serviceCall, bool forImmediateRun)\n\t\t{\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\tIPCServiceCall::UnalignedBuffer taskSettingsBuffer = serviceCall.ReadUnalignedInputBufferInfo();\n\t\t\tTaskSettingCore taskSetting = taskSettingsBuffer.ReadType<TaskSettingCore>(); // bugged.. (but on the submission side)\n\t\t\tif (taskSetting.persistentId == 0)\n\t\t\t\ttaskSetting.persistentId = persistentId;\n\t\t\ttaskSetting.taskId = taskId;\n\t\t\ts_bossDaemon.RegisterTask(taskSetting);\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleTaskUnregister(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\ts_bossDaemon.UnregisterTask(persistentId, taskId);\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleTaskRun(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\tbool isForegroundRun = serviceCall.ReadParameter<uint8be>() != 0; // todo - handle this\n\t\t\ts_bossDaemon.TaskRun(persistentId, taskId);\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleTaskStartScheduling(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\tuint8 startImmediately = serviceCall.ReadParameter<uint8be>();\n\t\t\ts_bossDaemon.StartScheduleTask(persistentId, taskId, startImmediately != 0);\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleTaskStopScheduling(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\ts_bossDaemon.StopScheduleTask(persistentId, taskId);\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleTaskWait(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tstatic_assert(sizeof(betype<TaskWaitState>) == 4);\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\tTaskWaitState waitState = serviceCall.ReadParameter<betype<TaskWaitState>>();\n\t\t\tuint32 timeout = serviceCall.ReadParameter<uint32be>();\n\t\t\tstd::chrono::steady_clock::time_point endTime;\n\t\t\tif (timeout != 0)\n\t\t\t\tendTime = std::chrono::steady_clock::now() + std::chrono::seconds(timeout);\n\t\t\tstd::shared_ptr<RegisteredTask> registeredTask = s_bossDaemon.GetRegisteredTask2(persistentId, taskId);\n\t\t\tcemu_assert_debug(registeredTask != nullptr);\n\t\t\tif (!registeredTask)\n\t\t\t\treturn RESULT_NOTEXIST;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\t// todo - make async\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t\t\t\tTaskState currentState = registeredTask->GetState();\n\t\t\t\t// does the state match the wait state?\n\t\t\t\tif (waitState == TaskWaitState::Done)\n\t\t\t\t{\n\t\t\t\t\tif (currentState == TaskState::Done)\n\t\t\t\t\t{\n\t\t\t\t\t\tserviceCall.WriteResponse<uint8be>(1); // 0 -> timeout, 1 -> no timeout\n\t\t\t\t\t\treturn RESULT_SUCCESS;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"IOSU-Boss: Unknown task wait state {}\", static_cast<uint32>(waitState));\n\t\t\t\t\tserviceCall.WriteResponse<uint8be>(0);\n\t\t\t\t\treturn RESULT_SUCCESS;\n\t\t\t\t}\n\t\t\t\t// check for timeout\n\t\t\t\tif (timeout != 0 && std::chrono::steady_clock::now() >= endTime)\n\t\t\t\t{\n\t\t\t\t\tserviceCall.WriteResponse<uint8be>(0);\n\t\t\t\t\treturn RESULT_SUCCESS; // which error to return here?\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tnnResult HandleTaskGetTurnState(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tstatic_assert(sizeof(betype<TaskTurnState>) == 4);\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\tstd::shared_ptr<RegisteredTask> registeredTask = s_bossDaemon.GetRegisteredTask2(persistentId, taskId);\n\t\t\tTaskTurnState turnState = registeredTask ? registeredTask->GetTurnState() : TaskTurnState::Ukn;\n\t\t\tserviceCall.WriteResponse<uint32be>(1); // execution counter - todo\n\t\t\tserviceCall.WriteResponse<betype<TaskTurnState>>(turnState);\n\t\t\tif (!registeredTask)\n\t\t\t\treturn RESULT_NOTEXIST;\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleTaskGetHttpStatusCodeA(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\tstd::shared_ptr<RegisteredTask> registeredTask = s_bossDaemon.GetRegisteredTask2(persistentId, taskId);\n\t\t\tsint32 httpStatusCode = registeredTask ? registeredTask->GetHttpStatusCode() : 0;\n\t\t\tserviceCall.WriteResponse<sint32be>(1); // execution counter - todo\n\t\t\tserviceCall.WriteResponse<sint32be>(httpStatusCode);\n\t\t\tif (!registeredTask)\n\t\t\t\treturn RESULT_NOTEXIST;\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleTaskGetContentLength(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\tstd::shared_ptr<RegisteredTask> registeredTask = s_bossDaemon.GetRegisteredTask2(persistentId, taskId);\n\t\t\tuint32 contentLength = registeredTask ? registeredTask->GetContentLength() : 0;\n\t\t\tserviceCall.WriteResponse<uint32be>(1); // execution counter - todo\n\t\t\tserviceCall.WriteResponse<uint64be>(contentLength);\n\t\t\tif (!registeredTask)\n\t\t\t\treturn RESULT_NOTEXIST;\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleTaskGetProcessedLength(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tuint32 persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tTaskId taskId = serviceCall.ReadParameter<TaskId>();\n\t\t\tstd::shared_ptr<RegisteredTask> registeredTask = s_bossDaemon.GetRegisteredTask2(persistentId, taskId);\n\t\t\tuint32 processedLength = registeredTask ? registeredTask->GetProcessedLength() : 0;\n\t\t\tserviceCall.WriteResponse<uint32be>(1); // execution counter - todo\n\t\t\tserviceCall.WriteResponse<uint64be>(processedLength); // this the actual length?\n\t\t\tif (!registeredTask)\n\t\t\t\treturn RESULT_NOTEXIST;\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\t/* Storage */\n\n\t\tnnResult HandleStorageExist(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tstatic_assert(sizeof(DirectoryName) == 8);\n\t\t\tstatic_assert(sizeof(betype<StorageKind>) == 4);\n\t\t\tauto persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tDirectoryName directoryName = serviceCall.ReadParameter<DirectoryName>();\n\t\t\tStorageKind storageKind = serviceCall.ReadParameter<betype<StorageKind>>();\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\t// todo - investigate how IOSU handles this\n\t\t\tbool storageExists = true;\n\t\t\tif (storageKind == StorageKind::StorageNbdl)\n\t\t\t{\n\t\t\t\t// but for now we only check if the fad.db file exists for nbdl\n\t\t\t\tstorageExists = m_fadDb.CheckIfStorageExists(directoryName, titleId, persistentId);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"IOSU-Boss: Unhandled storage kind {}\", static_cast<uint32>(storageKind));\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\tserviceCall.WriteResponse<uint8be>(storageExists ? 1 : 0);\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleStorageGetDataList(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tauto persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tDirectoryName directoryName = serviceCall.ReadParameter<DirectoryName>();\n\t\t\tuint32 ukn = serviceCall.ReadParameter<uint32be>();\n\t\t\tcemu_assert_debug(ukn == 0);\n\t\t\tIPCServiceCall::UnalignedBuffer dataListOutputBuffer = serviceCall.ReadUnalignedOutputBufferInfo();\n\t\t\tuint32 startOffset = serviceCall.ReadParameter<uint32be>(); // guessed\n\t\t\tcemu_assert_debug(startOffset == 0); // todo - implement offset\n\t\t\tsize_t dataListSize = dataListOutputBuffer.GetSize() / sizeof(DataName);\n\t\t\tstd::vector<DataName> dataListTmp;\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\t// open FAD database\n\t\t\tTaskId taskId(directoryName.name2.c_str());\n\t\t\tnnResult r = m_fadDb.Load(taskId, titleId, persistentId);\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn r;\n\t\t\tm_fadDb.GetDataList(dataListTmp);\n\t\t\tif (dataListTmp.size() > dataListSize)\n\t\t\t\tdataListTmp.resize(dataListSize);\n\t\t\t// write to output\n\t\t\tdataListOutputBuffer.WriteData(dataListTmp.data(), dataListTmp.size() * sizeof(DataName));\n\t\t\tserviceCall.WriteResponse<uint32be>((uint32)dataListTmp.size());\n\t\t\tserviceCall.WriteResponse<uint8be>(1); // extra byte to indicate success or failure\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\t/* NsData */\n\n\t\tnnResult HandleNsDataExist(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tauto persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tDirectoryName directoryName = serviceCall.ReadParameter<DirectoryName>();\n\t\t\tuint32 ukn = serviceCall.ReadParameter<uint32be>(); // storage kind?\n\t\t\tDataName fileName = serviceCall.ReadParameter<DataName>();\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\tnnResult r = m_nsDataAccessor.Open(directoryName, titleId, persistentId, fileName);\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn r;\n\t\t\tbool nsDataExists = m_nsDataAccessor.Exists();\n\t\t\tserviceCall.WriteResponse<uint8be>(nsDataExists);\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleNsDataRead(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tauto persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tDirectoryName directoryName = serviceCall.ReadParameter<DirectoryName>();\n\t\t\tuint32 ukn = serviceCall.ReadParameter<uint32be>(); // storage kind?\n\t\t\tDataName fileName = serviceCall.ReadParameter<DataName>();\n\t\t\tIPCServiceCall::UnalignedBuffer dataOutputBuffer = serviceCall.ReadUnalignedOutputBufferInfo();\n\t\t\tuint64 readOffset = serviceCall.ReadParameter<uint64be>();\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\tnnResult r = m_nsDataAccessor.Open(directoryName, titleId, persistentId, fileName);\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t{\n\t\t\t\tserviceCall.WriteResponse<uint64be>(0); // should we still write the bytes read in case of failure?\n\t\t\t\treturn r;\n\t\t\t}\n\t\t\tuint32 bytesRead = 0;\n\t\t\tstd::vector<uint8> tmpBuffer;\n\t\t\ttmpBuffer.resize(dataOutputBuffer.GetSize());\n\t\t\tbool rRead = m_nsDataAccessor.Read(tmpBuffer.data(), tmpBuffer.size(), readOffset, bytesRead);\n\t\t\tdataOutputBuffer.WriteData(tmpBuffer.data(), tmpBuffer.size());\n\t\t\tserviceCall.WriteResponse<uint64be>(bytesRead);\n\t\t\t// todo - handle rRead\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleNsDataGetSize(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tauto persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tDirectoryName directoryName = serviceCall.ReadParameter<DirectoryName>();\n\t\t\tuint32 ukn = serviceCall.ReadParameter<uint32be>(); // storage kind?\n\t\t\tDataName fileName = serviceCall.ReadParameter<DataName>();\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\tnnResult r = m_nsDataAccessor.Open(directoryName, titleId, persistentId, fileName);\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn r;\n\t\t\tuint32 fileSize = 0;\n\t\t\tr = m_nsDataAccessor.GetSize(fileSize);\n\t\t\tserviceCall.WriteResponse<uint64be>(fileSize);\n\t\t\treturn r;\n\t\t}\n\n\t\tnnResult HandleNsDataDeleteFile(IPCServiceCall& serviceCall, bool withHistory)\n\t\t{\n\t\t\tauto persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tDirectoryName directoryName = serviceCall.ReadParameter<DirectoryName>();\n\t\t\tuint32 ukn = serviceCall.ReadParameter<uint32be>(); // storage kind?\n\t\t\tDataName fileName = serviceCall.ReadParameter<DataName>();\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\tnnResult r = m_nsDataAccessor.Open(directoryName, titleId, persistentId, fileName);\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn r;\n\t\t\t// todo - handle withHistory\n\t\t\treturn m_nsDataAccessor.Delete();\n\t\t}\n\n\t\tnnResult HandleNsFinalize(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tauto persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tDirectoryName directoryName = serviceCall.ReadParameter<DirectoryName>();\n\t\t\tuint32 ukn = serviceCall.ReadParameter<uint32be>(); // storage kind?\n\t\t\tDataName fileName = serviceCall.ReadParameter<DataName>();\n\t\t\tm_nsDataAccessor.Close();\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\t/* Title */\n\n\t\tnnResult HandleTitleSetNewArrivalFlag(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tauto persistentId = BossGetPersistentId(serviceCall.ReadParameter<uint32be>());\n\t\t\tif (!persistentId)\n\t\t\t\treturn RESULT_C0203880;\n\t\t\tuint8 flagValue = serviceCall.ReadParameter<uint8be>();\n\t\t\tcemuLog_logDebug(LogType::Force, \"IOSU-Boss: Unhandled command TitleSetNewArrivalFlag\");\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\t/* stubbed opcodes */\n\t\tnnResult HandleUknA7(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"IOSU-Boss: Unhandled command A7\");\n\t\t\t// no response data\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult HandleDeleteDataRelated(IPCServiceCall& serviceCall)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"IOSU-Boss: Unhandled delete command\");\n\t\t\t// no response data\n\t\t\treturn RESULT_SUCCESS;\n\t\t}\n\n\n\t};\n\n\tBossMainService s_bossService;\n\n\tclass : public ::IOSUModule\n\t{\n\t\tvoid TitleStart() override\n\t\t{\n\t\t\ts_bossService.Start();\n\t\t\ts_bossDaemon.Start();\n\t\t}\n\t\tvoid TitleStop() override\n\t\t{\n\t\t\ts_bossService.Stop();\n\t\t\tm_fadDb.Clear();\n\t\t\tm_nsDataAccessor.Close();\n\t\t}\n\t}sIOSUModuleNNBOSS;\n\n\tIOSUModule* GetModule()\n\t{\n\t\treturn static_cast<IOSUModule*>(&sIOSUModuleNNBOSS);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/IOSU/nn/boss/boss_service.h",
    "content": "#pragma once\n#include \"Cafe/IOSU/iosu_types_common.h\"\n\nnamespace iosu::boss\n{\n\tIOSUModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/IOSU/nn/iosu_nn_service.cpp",
    "content": "#include \"iosu_nn_service.h\"\n#include \"../kernel/iosu_kernel.h\"\n#include \"util/helpers/helpers.h\"\n\nusing namespace iosu::kernel;\n\nnamespace iosu\n{\n\tnamespace nn\n\t{\n\t\t/* IPCSimpleService */\n\t\tvoid IPCSimpleService::Start()\n\t\t{\n\t\t\tif (m_isRunning.exchange(true))\n\t\t\t\treturn;\n\t\t\tm_threadInitialized = false;\n\t\t\tm_requestStop = false;\n\t\t\tm_serviceThread = std::thread(&IPCSimpleService::ServiceThread, this);\n\t\t\twhile (!m_threadInitialized) std::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t\tStartService();\n\t\t}\n\n\t\tvoid IPCSimpleService::Stop()\n\t\t{\n\t\t\tif (!m_isRunning.exchange(false))\n\t\t\t\treturn;\n\t\t\tm_requestStop = true;\n\t\t\tStopService();\n\t\t\tif(m_timerId != IOSInvalidTimerId)\n\t\t\t\tIOS_DestroyTimer(m_timerId);\n\t\t\tm_timerId = IOSInvalidTimerId;\n\t\t\tIOS_SendMessage(m_msgQueueId, 0, 0); // wake up thread\n\t\t\tm_serviceThread.join();\n\t\t}\n\n\t\tvoid IPCSimpleService::ServiceThread()\n\t\t{\n\t\t\tif(!GetThreadName().empty())\n\t\t\t\tSetThreadName(GetThreadName().c_str());\n\t\t\tm_msgQueueId = IOS_CreateMessageQueue(_m_msgBuffer.GetPtr(), _m_msgBuffer.GetCount());\n\t\t\tcemu_assert(!IOS_ResultIsError((IOS_ERROR)m_msgQueueId));\n\t\t\tIOS_ERROR r = IOS_RegisterResourceManager(m_devicePath.c_str(), m_msgQueueId);\n\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t\tm_threadInitialized = true;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tIOSMessage msg;\n\t\t\t\tr = IOS_ReceiveMessage(m_msgQueueId, &msg, 0);\n\t\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t\t\tif (msg == 0)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(m_requestStop);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if(msg == 1)\n\t\t\t\t{\n\t\t\t\t\tTimerUpdate();\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tIPCCommandBody* cmd = MEMPTR<IPCCommandBody>(msg).GetPtr();\n\t\t\t\tif (cmd->cmdId == IPCCommandId::IOS_OPEN)\n\t\t\t\t{\n\t\t\t\t\tvoid* clientObject = CreateClientObject();\n\t\t\t\t\tif(clientObject == nullptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"IPCSimpleService[{}]: Maximum handle count reached or handle rejected\", m_devicePath);\n\t\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_MAXIMUM_REACHED);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tIOSDevHandle newHandle = GetFreeHandle();\n\t\t\t\t\tm_clientObjects[newHandle] = clientObject;\n\t\t\t\t\tIOS_ResourceReply(cmd, (IOS_ERROR)newHandle);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_CLOSE)\n\t\t\t\t{\n\t\t\t\t\tvoid* clientObject = GetClientObjectByHandle(cmd->devHandle);\n\t\t\t\t\tif (clientObject)\n\t\t\t\t\t\tDestroyClientObject(clientObject);\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_OK);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_IOCTLV)\n\t\t\t\t{\n\t\t\t\t\tvoid* clientObject = GetClientObjectByHandle(cmd->devHandle);\n\t\t\t\t\tif (!clientObject)\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"IPCSimpleService[{}]: Invalid IPC handle\", m_devicePath);\n\t\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_INVALID);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tuint32 requestId = cmd->args[0];\n\t\t\t\t\tuint32 numIn = cmd->args[1];\n\t\t\t\t\tuint32 numOut = cmd->args[2];\n\t\t\t\t\tIPCIoctlVector* vec = MEMPTR<IPCIoctlVector>{ cmd->args[3] }.GetPtr();\n\t\t\t\t\tIPCIoctlVector* vecIn = vec + 0; // the ordering of vecIn/vecOut differs from IPCService\n\t\t\t\t\tIPCIoctlVector* vecOut = vec + numIn;\n\t\t\t\t\tm_delayResponse = false;\n\t\t\t\t\tm_activeCmd = cmd;\n\t\t\t\t\tuint32 result = ServiceCall(clientObject, requestId, vecIn, numIn, vecOut, numOut);\n\t\t\t\t\tif (!m_delayResponse)\n\t\t\t\t\t\tIOS_ResourceReply(cmd, (IOS_ERROR)result);\n\t\t\t\t\tm_activeCmd = nullptr;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"IPCSimpleService[{}]: Unsupported IPC cmdId {}\", m_devicePath, (uint32)cmd->cmdId.value());\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_INVALID);\n\t\t\t\t}\n\t\t\t}\n\t\t\tIOS_DestroyMessageQueue(m_msgQueueId);\n\t\t\tm_threadInitialized = false;\n\t\t}\n\n\t\tvoid IPCSimpleService::SetTimerUpdate(uint32 milliseconds)\n\t\t{\n\t\t\tif(m_timerId != IOSInvalidTimerId)\n\t\t\t\tIOS_DestroyTimer(m_timerId);\n\t\t\tm_timerId = IOS_CreateTimer(milliseconds * 1000, milliseconds * 1000, m_msgQueueId, 1);\n\t\t}\n\n\t\tIPCCommandBody* IPCSimpleService::ServiceCallDelayCurrentResponse()\n\t\t{\n\t\t\tcemu_assert_debug(m_activeCmd);\n\t\t\tm_delayResponse = true;\n\t\t\treturn m_activeCmd;\n\t\t}\n\n\t\tvoid IPCSimpleService::ServiceCallAsyncRespond(IPCCommandBody* response, uint32 r)\n\t\t{\n\t\t\tIOS_ResourceReply(response, (IOS_ERROR)r);\n\t\t}\n\n\t\t/* IPCService */\n\t\tvoid IPCService::Start()\n\t\t{\n\t\t\tif (m_isRunning.exchange(true))\n\t\t\t\treturn;\n\t\t\tm_threadInitialized = false;\n\t\t\tm_requestStop = false;\n\t\t\tm_serviceThread = std::thread(&IPCService::ServiceThread, this);\n\t\t\twhile (!m_threadInitialized) std::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t}\n\n\t\tvoid IPCService::Stop()\n\t\t{\n\t\t\tif (!m_isRunning.exchange(false))\n\t\t\t\treturn;\n\t\t\tm_requestStop = true;\n\t\t\tIOS_SendMessage(m_msgQueueId, 0, 0); // wake up thread\n\t\t\tm_serviceThread.join();\n\t\t}\n\n\t\tvoid IPCService::ServiceThread()\n\t\t{\n\t\t\tstd::string serviceName = m_devicePath.substr(m_devicePath.find_last_of('/') == std::string::npos ? 0 : m_devicePath.find_last_of('/') + 1);\n\t\t\tserviceName.insert(0, \"NNsvc_\");\n\t\t\tSetThreadName(serviceName.c_str());\n\t\t\tm_msgQueueId = IOS_CreateMessageQueue(_m_msgBuffer.GetPtr(), _m_msgBuffer.GetCount());\n\t\t\tcemu_assert(!IOS_ResultIsError((IOS_ERROR)m_msgQueueId));\n\t\t\tIOS_ERROR r = IOS_RegisterResourceManager(m_devicePath.c_str(), m_msgQueueId);\n\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t\tm_threadInitialized = true;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tIOSMessage msg;\n\t\t\t\tIOS_ERROR r = IOS_ReceiveMessage(m_msgQueueId, &msg, 0);\n\t\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t\t\tif (msg == 0)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(m_requestStop);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tIPCCommandBody* cmd = MEMPTR<IPCCommandBody>(msg).GetPtr();\n\t\t\t\tif (cmd->cmdId == IPCCommandId::IOS_OPEN)\n\t\t\t\t{\n\t\t\t\t\tIOS_ResourceReply(cmd, (IOS_ERROR)CreateClientHandle());\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_CLOSE)\n\t\t\t\t{\n\t\t\t\t\tCloseClientHandle((IOSDevHandle)(uint32)cmd->devHandle);\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_OK);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (cmd->cmdId == IPCCommandId::IOS_IOCTLV)\n\t\t\t\t{\n\t\t\t\t\tuint32 requestId = cmd->args[0];\n\t\t\t\t\tuint32 numOut = cmd->args[1];\n\t\t\t\t\tuint32 numIn = cmd->args[2];\n\t\t\t\t\tIPCIoctlVector* vec = MEMPTR<IPCIoctlVector>{ cmd->args[3] }.GetPtr();\n\t\t\t\t\tIPCIoctlVector* vecOut = vec + 0; // out buffers come first\n\t\t\t\t\tIPCIoctlVector* vecIn = vec + numOut;\n\n\t\t\t\t\tcemu_assert(numIn > 0 && numOut > 0);\n\t\t\t\t\tcemu_assert(vecIn->size >= 80 && !vecIn->basePhys.IsNull());\n\n\t\t\t\t\tIPCServiceRequestHeader* serviceRequest = MEMPTR<IPCServiceRequestHeader>(vecIn->basePhys).GetPtr();\n\t\t\t\t\tIPCServiceResponseHeader* serviceResponse = MEMPTR<IPCServiceResponseHeader>(vecOut->basePhys).GetPtr();\n\n\t\t\t\t\tIOSDevHandle clientHandle = 0; // todo\n\t\t\t\t\tIPCServiceCall serviceCall(clientHandle, serviceRequest->serviceId, serviceRequest->commandId);\n\n#if 0\n\t\t\t\t\t// log all buffers\n\t\t\t\t\tcemuLog_log(LogType::Force, \"IPC ServiceCall. In: {}, Out: {}, ServiceId: {}, CommandId: {} (0x{:x})\", numIn, numOut, serviceRequest->serviceId, serviceRequest->commandId, serviceRequest->commandId);\n\t\t\t\t\tfor (size_t i = 0; i <numOut+numIn; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"\");\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"Buffer {} - BasePhys: {}, Size: {}\", i, vec[i].basePhys, vec[i].size);\n\t\t\t\t\t\tcemuLog_logHexDump(LogType::Force, MEMPTR<uint8>(vec[i].basePhys).GetPtr(), vec[i].size, 16);\n\t\t\t\t\t}\n#endif\n\n\t\t\t\t\t// parameter and response data is appended directly after the headers, so we add the streams without the headers\n\t\t\t\t\tserviceCall.AddInputStream(MEMPTR<uint8>(vecIn[0].basePhys).GetPtr() + sizeof(IPCServiceRequestHeader), vecIn[0].size - sizeof(IPCServiceRequestHeader));\n\t\t\t\t\tserviceCall.AddOutputStream(MEMPTR<uint8>(vecOut[0].basePhys).GetPtr() + sizeof(IPCServiceResponseHeader), vecOut[0].size - sizeof(IPCServiceResponseHeader));\n\t\t\t\t\t// add remaining input/output buffers\n\t\t\t\t\tfor (size_t i = 1; i < numIn; i++)\n\t\t\t\t\t\tserviceCall.AddInputStream(MEMPTR<uint8>(vecIn[i].basePhys).GetPtr(), vecIn[i].size);\n\t\t\t\t\tfor (size_t i = 1; i < numOut; i++)\n\t\t\t\t\t\tserviceCall.AddOutputStream(MEMPTR<uint8>(vecOut[i].basePhys).GetPtr(), vecOut[i].size);\n\n\t\t\t\t\tserviceResponse->nnResultCode = (uint32)ServiceCall(serviceCall);\n\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_OK);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"{}: Unsupported cmdId\", m_devicePath);\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t\tIOS_ResourceReply(cmd, IOS_ERROR_INVALID);\n\t\t\t\t}\n\t\t\t}\n\t\t\tIOS_DestroyMessageQueue(m_msgQueueId);\n\t\t\tm_threadInitialized = false;\n\t\t}\n\t};\n};\n"
  },
  {
    "path": "src/Cafe/IOSU/nn/iosu_nn_service.h",
    "content": "#pragma once\n#include \"Cafe/IOSU/kernel/iosu_kernel.h\"\n#include \"Cafe/IOSU/iosu_ipc_common.h\"\n#include \"Cafe/IOSU/iosu_types_common.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n\nnamespace iosu\n{\n\tnamespace nn\n\t{\n\t\t// a simple service interface which wraps handle management and Ioctlv/IoctlvAsync (used by /dev/fpd and others are still to be determined)\n\t\tclass IPCSimpleService\n\t\t{\n\t\t  public:\n\t\t\tIPCSimpleService(std::string_view devicePath) : m_devicePath(devicePath) {};\n\t\t\tvirtual ~IPCSimpleService() {};\n\n\t\t\tvirtual void StartService() {};\n\t\t\tvirtual void StopService() {};\n\n\t\t\tvirtual std::string GetThreadName() = 0;\n\n\t\t\tvirtual void* CreateClientObject() = 0;\n\t\t\tvirtual void DestroyClientObject(void* clientObject) = 0;\n\t\t\tvirtual uint32 ServiceCall(void* clientObject, uint32 requestId, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut) = 0;\n\t\t\tvirtual void TimerUpdate() {};\n\n\t\t\tIPCCommandBody* ServiceCallDelayCurrentResponse();\n\t\t\tstatic void ServiceCallAsyncRespond(IPCCommandBody* response, uint32 r);\n\n\t\t\tvoid Start();\n\t\t\tvoid Stop();\n\n\t\t\tvoid SetTimerUpdate(uint32 milliseconds);\n\n\t\t  private:\n\t\t\tvoid ServiceThread();\n\n\t\t\tIOSDevHandle GetFreeHandle()\n\t\t\t{\n\t\t\t\twhile(m_clientObjects.find(m_nextHandle) != m_clientObjects.end() || m_nextHandle == 0)\n\t\t\t\t{\n\t\t\t\t\tm_nextHandle++;\n\t\t\t\t\tm_nextHandle &= 0x7FFFFFFF;\n\t\t\t\t}\n\t\t\t\tIOSDevHandle newHandle = m_nextHandle;\n\t\t\t\tm_nextHandle++;\n\t\t\t\tm_nextHandle &= 0x7FFFFFFF;\n\t\t\t\treturn newHandle;\n\t\t\t}\n\n\t\t\tvoid* GetClientObjectByHandle(IOSDevHandle handle) const\n\t\t\t{\n\t\t\t\tauto it = m_clientObjects.find(handle);\n\t\t\t\tif(it == m_clientObjects.end())\n\t\t\t\t\treturn nullptr;\n\t\t\t\treturn it->second;\n\t\t\t}\n\n\t\t\tstd::string m_devicePath;\n\t\t\tstd::thread m_serviceThread;\n\t\t\tstd::atomic_bool m_requestStop{false};\n\t\t\tstd::atomic_bool m_isRunning{false};\n\t\t\tstd::atomic_bool m_threadInitialized{ false };\n\t\t\tstd::unordered_map<IOSDevHandle, void*> m_clientObjects;\n\t\t\tIOSDevHandle m_nextHandle{1};\n\t\t\tIOSTimerId m_timerId{IOSInvalidTimerId};\n\n\t\t\tIPCCommandBody* m_activeCmd{nullptr};\n\t\t\tbool m_delayResponse{false};\n\n\t\t\tIOSMsgQueueId m_msgQueueId;\n\t\t\tSysAllocator<iosu::kernel::IOSMessage, 128> _m_msgBuffer;\n\t\t};\n\n\t\t// a complex service interface which wraps Ioctlv and adds an additional service channel, used by /dev/act, /dev/acp_main, /dev/boss and most nn services\n\t\tclass IPCService\n\t\t{\n\t\t\tstruct IPCServiceRequestHeader\n\t\t\t{\n\t\t\t\tuint32be ukn00;\n\t\t\t\tuint32be serviceId;\n\t\t\t\tuint32be ukn08;\n\t\t\t\tuint32be commandId;\n\t\t\t};\n\n\t\t\tstatic_assert(sizeof(IPCServiceRequestHeader) == 0x10);\n\n\t\t\tstruct IPCServiceResponseHeader\n\t\t\t{\n\t\t\t\tuint32be nnResultCode;\n\t\t\t};\n\t\tpublic:\n\t\t\tclass IPCParameterStream // input stream for parameters\n\t\t\t{\n\t\t\tpublic:\n\t\t\t\tIPCParameterStream() = default;\n\t\t\t\tIPCParameterStream(void* data, uint32 size) : m_data((uint8_t*)data), m_size(size) {}\n\n\t\t\t\ttemplate<typename T>\n\t\t\t\tT ReadParameter(bool& hasError)\n\t\t\t\t{\n\t\t\t\t\thasError = false;\n\t\t\t\t\tif (m_readIndex + sizeof(T) > m_size)\n\t\t\t\t\t{\n\t\t\t\t\t\thasError = true;\n\t\t\t\t\t\treturn T{};\n\t\t\t\t\t}\n\t\t\t\t\tT value;\n\t\t\t\t\tmemcpy(&value, &m_data[m_readIndex], sizeof(T));\n\t\t\t\t\tm_readIndex += sizeof(T);\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\n\t\t\t\tuint8* GetData() { return m_data; }\n\t\t\t\tuint32 GetSize() const { return m_size; }\n\n\t\t\tprivate:\n\t\t\t\tuint8* m_data{nullptr};\n\t\t\t\tuint32 m_size{0};\n\t\t\t\tuint32 m_readIndex{0};\n\t\t\t};\n\n\t\t\tclass IPCResponseStream // output stream for response data\n\t\t\t{\n\t\t\tpublic:\n\t\t\t\tIPCResponseStream() = default;\n\t\t\t\tIPCResponseStream(void* data, uint32 size) : m_data((uint8*)data), m_size(size) {}\n\n\t\t\t\ttemplate<typename T>\n\t\t\t\tvoid Write(const T& value)\n\t\t\t\t{\n\t\t\t\t\tif (m_writtenSize + sizeof(T) > m_size)\n\t\t\t\t\t{\n\t\t\t\t\t\tm_hasError = true;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tmemcpy(&m_data[m_writtenSize], &value, sizeof(T));\n\t\t\t\t\tm_writtenSize += sizeof(T);\n\t\t\t\t}\n\n\t\t\t\tuint8* GetData() { return m_data; }\n\t\t\t\tuint32 GetSize() const { return m_size; }\n\n\t\t\tprivate:\n\t\t\t\tuint8* m_data{nullptr};\n\t\t\t\tuint32 m_writtenSize{0};\n\t\t\t\tuint32 m_size{0};\n\t\t\t\tbool m_hasError{false};\n\t\t\t};\n\n\t\t\tclass IPCServiceCall\n\t\t\t{\n\t\t\t\tstruct LargeBufferHeader\n\t\t\t\t{\n\t\t\t\t\tuint32be alignedSize; // size of the aligned (middle) part of the buffer\n\t\t\t\t\tuint8be ukn4;\n\t\t\t\t\tuint8be ukn5;\n\t\t\t\t\tuint8be headSize;\n\t\t\t\t\tuint8be tailSize;\n\t\t\t\t};\n\t\t\t\tstatic_assert(sizeof(LargeBufferHeader) == 8);\n\t\t\tpublic:\n\t\t\t\tstruct UnalignedBuffer\n\t\t\t\t{\n\t\t\t\t\tUnalignedBuffer(bool isOutput, std::span<uint8> head, std::span<uint8> middle, std::span<uint8> tail) : m_isOutput(isOutput)\n\t\t\t\t\t{\n\t\t\t\t\t\theadPtr = head.data();\n\t\t\t\t\t\theadSize = (uint32)head.size();\n\t\t\t\t\t\tmiddlePtr = middle.data();\n\t\t\t\t\t\tmiddleSize = (uint32)middle.size();\n\t\t\t\t\t\ttailPtr = tail.data();\n\t\t\t\t\t\ttailSize = (uint32)tail.size();\n\t\t\t\t\t};\n\n\t\t\t\t\ttemplate<typename T>\n\t\t\t\t\tT ReadType()\n\t\t\t\t\t{\n\t\t\t\t\t\tcemu_assert(!m_isOutput);\n\t\t\t\t\t\tT v;\n\t\t\t\t\t\tmemcpy((uint8_t*)&v, headPtr, headSize);\n\t\t\t\t\t\tmemcpy((uint8_t*)&v + headSize, middlePtr, middleSize);\n\t\t\t\t\t\tmemcpy((uint8_t*)&v + headSize + middleSize, tailPtr, tailSize);\n\t\t\t\t\t\treturn v;\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid WriteData(void* data, size_t size)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (size == 0)\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\tcemu_assert(m_isOutput);\n\t\t\t\t\t\tcemu_assert((headSize + middleSize + tailSize) >= size);\n\t\t\t\t\t\tsize_t bytesToCopy = std::min<size_t>(size, headSize);\n\t\t\t\t\t\tmemcpy(headPtr, data, bytesToCopy);\n\t\t\t\t\t\tsize -= bytesToCopy;\n\t\t\t\t\t\tif (size > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbytesToCopy = std::min<size_t>(size, middleSize);\n\t\t\t\t\t\t\tmemcpy(middlePtr, (uint8_t*)data + headSize, bytesToCopy);\n\t\t\t\t\t\t\tsize -= bytesToCopy;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (size > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbytesToCopy = std::min<size_t>(size, tailSize);\n\t\t\t\t\t\t\tmemcpy(tailPtr, (uint8_t*)data + headSize + middleSize, bytesToCopy);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tsize_t GetSize() const\n\t\t\t\t\t{\n\t\t\t\t\t\treturn headSize + middleSize + tailSize;\n\t\t\t\t\t}\n\n\t\t\t\tprivate:\n\t\t\t\t\tvoid* headPtr;\n\t\t\t\t\tuint32 headSize;\n\t\t\t\t\tvoid* middlePtr; // aligned\n\t\t\t\t\tuint32 middleSize;\n\t\t\t\t\tvoid* tailPtr;\n\t\t\t\t\tuint32 tailSize;\n\t\t\t\t\tbool m_isOutput;\n\t\t\t\t};\n\n\t\t\t\tIPCServiceCall(IOSDevHandle clientHandle, uint32 serviceId, uint32 commandId) : m_clientHandle(clientHandle), m_serviceId(serviceId), m_commandId(commandId)\n\t\t\t\t{\n\t\t\t\t}\n\n\t\t\t\tvoid AddInputStream(void* data, uint32 size)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert(m_paramStreamArraySize < 4);\n\t\t\t\t\tm_paramStreamArray[m_paramStreamArraySize++] = IPCParameterStream(data, size);\n\t\t\t\t}\n\n\t\t\t\tvoid AddOutputStream(void* data, uint32 size)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert(m_responseStreamArraySize < 4);\n\t\t\t\t\tm_responseStreamArray[m_responseStreamArraySize++] = IPCResponseStream(data, size);\n\t\t\t\t}\n\n\t\t\t\tuint32 GetServiceId() const\n\t\t\t\t{\n\t\t\t\t\treturn m_serviceId;\n\t\t\t\t}\n\n\t\t\t\tuint32 GetCommandId() const\n\t\t\t\t{\n\t\t\t\t\treturn m_commandId;\n\t\t\t\t}\n\n\t\t\t\ttemplate<typename T>\n\t\t\t\tT ReadParameter()\n\t\t\t\t{\n\t\t\t\t\t// read only from stream 0 for now\n\t\t\t\t\treturn m_paramStreamArray[0].ReadParameter<T>(m_hasError);\n\t\t\t\t}\n\n\t\t\t\tUnalignedBuffer ReadUnalignedInputBufferInfo()\n\t\t\t\t{\n\t\t\t\t\t// how large/unaligned buffers work:\n\t\t\t\t\t// Instead of appending the data into the parameter stream, there are two separate buffers created:\n\t\t\t\t\t// 1. A ioctl vector that points directly to the aligned part of the original buffer. Both the pointer and the size are aligned\n\t\t\t\t\t// 2. A ioctl vector with an allocated up-to-128byte buffer that holds any unaligned head or tail data (e.g. anything that isn't occupying the full 64 byte alignment)\n\t\t\t\t\t// The buffer layout is then also serialized into the parameter stream\n\t\t\t\t\tLargeBufferHeader header = ReadParameter<LargeBufferHeader>();\n\t\t\t\t\t// get aligned buffer part\n\t\t\t\t\tvoid* alignedBuffer = m_paramStreamArray[m_inputBufferIndex+0].GetData();\n\t\t\t\t\tcemu_assert(m_paramStreamArray[m_inputBufferIndex+0].GetSize() == header.alignedSize);\n\t\t\t\t\t// get head and tail buffer parts\n\t\t\t\t\tuint8* unalignedDataBuffer = m_paramStreamArray[m_inputBufferIndex+1].GetData();\n\t\t\t\t\tcemu_assert((header.headSize + header.tailSize) <= m_paramStreamArray[m_inputBufferIndex+1].GetSize());\n\t\t\t\t\tUnalignedBuffer largeBuffer(false, {(uint8*)unalignedDataBuffer, header.headSize}, {(uint8*)alignedBuffer, header.alignedSize}, {(uint8*)unalignedDataBuffer + header.headSize, header.tailSize});\n\t\t\t\t\tm_inputBufferIndex += 2; // if there is no unaligned data then are both buffers still present?\n\t\t\t\t\treturn largeBuffer;\n\t\t\t\t}\n\n\t\t\t\tUnalignedBuffer ReadUnalignedOutputBufferInfo()\n\t\t\t\t{\n\t\t\t\t\tLargeBufferHeader header = ReadParameter<LargeBufferHeader>();\n\t\t\t\t\t// get aligned buffer part\n\t\t\t\t\tvoid* alignedBuffer = m_responseStreamArray[m_outputBufferIndex+0].GetData();\n\t\t\t\t\tcemu_assert(m_responseStreamArray[m_outputBufferIndex+0].GetSize() == header.alignedSize);\n\t\t\t\t\t// get head and tail buffer parts\n\t\t\t\t\tuint8* unalignedDataBuffer = m_responseStreamArray[m_outputBufferIndex+1].GetData();\n\t\t\t\t\tcemu_assert((header.headSize + header.tailSize) <= m_responseStreamArray[m_outputBufferIndex+1].GetSize());\n\t\t\t\t\tUnalignedBuffer largeBuffer(true, {(uint8*)unalignedDataBuffer, header.headSize}, {(uint8*)alignedBuffer, header.alignedSize}, {(uint8*)unalignedDataBuffer + header.headSize, header.tailSize});\n\t\t\t\t\tm_outputBufferIndex += 2; // if there is no unaligned data then are both buffers still present?\n\t\t\t\t\treturn largeBuffer;\n\t\t\t\t}\n\n\t\t\t\ttemplate<typename T>\n\t\t\t\tvoid WriteResponse(const T& value)\n\t\t\t\t{\n\t\t\t\t\tm_responseStreamArray[0].Write<T>(value);\n\t\t\t\t}\n\n\t\t\tprivate:\n\t\t\t\tIOSDevHandle m_clientHandle;\n\t\t\t\tuint32 m_serviceId;\n\t\t\t\tuint32 m_commandId;\n\t\t\t\tIPCParameterStream m_paramStreamArray[4]{};\n\t\t\t\tsize_t m_paramStreamArraySize{0};\n\t\t\t\tIPCResponseStream m_responseStreamArray[4]{};\n\t\t\t\tsize_t m_responseStreamArraySize{0};\n\t\t\t\tbool m_hasError{false};\n\t\t\t\tsint8 m_inputBufferIndex{1};\n\t\t\t\tsint8 m_outputBufferIndex{1};\n\t\t\t};\n\n\t\t\tIPCService(std::string_view devicePath) : m_devicePath(devicePath) {};\n\t\t\tvirtual ~IPCService() {};\n\n\t\t\tvirtual IOSDevHandle CreateClientHandle()\n\t\t\t{\n\t\t\t\treturn (IOSDevHandle)0;\n\t\t\t}\n\n\t\t\tvirtual void CloseClientHandle(IOSDevHandle handle)\n\t\t\t{\n\t\t\t\t\n\t\t\t}\n\n\t\t\tvirtual nnResult ServiceCall(IPCServiceCall& serviceCall)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tvoid Start();\n\t\t\tvoid Stop();\n\n\t\tprivate:\n\t\t\tvoid ServiceThread();\n\n\t\t\tstd::string m_devicePath;\n\t\t\tstd::thread m_serviceThread;\n\t\t\tstd::atomic_bool m_requestStop{false};\n\t\t\tstd::atomic_bool m_isRunning{false};\n\t\t\tstd::atomic_bool m_threadInitialized{ false };\n\n\t\t\tIOSMsgQueueId m_msgQueueId;\n\t\t\tSysAllocator<iosu::kernel::IOSMessage, 128> _m_msgBuffer;\n\t\t};\n\n\t};\n};"
  },
  {
    "path": "src/Cafe/OS/RPL/COSModule.cpp",
    "content": "#include \"COSModule.h\"\n\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n#include \"Cafe/OS/libs/zlib125/zlib125.h\"\n#include \"OS/libs/gx2/GX2.h\"\n#include \"OS/libs/dmae/dmae.h\"\n#include \"OS/libs/padscore/padscore.h\"\n#include \"OS/libs/vpad/vpad.h\"\n#include \"OS/libs/snd_core/ax.h\"\n#include \"OS/libs/snd_user/snd_user.h\"\n#include \"OS/libs/mic/mic.h\"\n#include \"OS/libs/erreula/erreula.h\"\n#include \"OS/libs/nlibnss/nlibnss.h\"\n#include \"OS/libs/nn_acp/nn_acp.h\"\n#include \"OS/libs/nn_act/nn_act.h\"\n#include \"OS/libs/nn_acp/nn_acp.h\"\n#include \"OS/libs/nn_ac/nn_ac.h\"\n#include \"OS/libs/nn_boss/nn_boss.h\"\n#include \"OS/libs/nn_ec/nn_ec.h\"\n#include \"OS/libs/nn_boss/nn_boss.h\"\n#include \"OS/libs/nn_nfp/nn_nfp.h\"\n#include \"OS/libs/nn_uds/nn_uds.h\"\n#include \"OS/libs/nn_nim/nn_nim.h\"\n#include \"OS/libs/nn_ndm/nn_ndm.h\"\n#include \"OS/libs/nn_spm/nn_spm.h\"\n#include \"OS/libs/nn_save/nn_save.h\"\n#include \"OS/libs/nsysnet/nsysnet.h\"\n#include \"OS/libs/nn_fp/nn_fp.h\"\n#include \"OS/libs/nn_idbe/nn_idbe.h\"\n#include \"OS/libs/nn_olv/nn_olv.h\"\n#include \"OS/libs/nn_idbe/nn_idbe.h\"\n#include \"OS/libs/nlibnss/nlibnss.h\"\n#include \"OS/libs/nlibcurl/nlibcurl.h\"\n#include \"OS/libs/sysapp/sysapp.h\"\n#include \"OS/libs/nsyshid/nsyshid.h\"\n#include \"OS/libs/nsyskbd/nsyskbd.h\"\n#include \"OS/libs/swkbd/swkbd.h\"\n#include \"OS/libs/camera/camera.h\"\n#include \"OS/libs/proc_ui/proc_ui.h\"\n#include \"OS/libs/avm/avm.h\"\n#include \"OS/libs/drmapp/drmapp.h\"\n#include \"OS/libs/TCL/TCL.h\"\n#include \"OS/libs/nn_cmpt/nn_cmpt.h\"\n#include \"OS/libs/nn_ccr/nn_ccr.h\"\n#include \"OS/libs/nn_temp/nn_temp.h\"\n#include \"OS/libs/nn_aoc/nn_aoc.h\"\n#include \"OS/libs/nn_pdm/nn_pdm.h\"\n#include \"OS/libs/h264_avc/h264dec.h\"\n#include \"OS/libs/ntag/ntag.h\"\n#include \"OS/libs/nfc/nfc.h\"\n\nstd::span<COSModule*> GetCOSModules()\n{\n\tstatic std::vector<COSModule*> s_cosModules =\n\t{\n\t\tcoreinit::GetModule(),\n\t\tzlib::GetModule(),\n\t\tGX2::GetModule(),\n\t\tdmae::GetModule(),\n\t\tpadscore::GetModule(),\n\t\tvpad::GetModule(),\n\t\tsnd_core::GetModuleSndCore1(),\n\t\tsnd_core::GetModuleSndCore2(),\n\t\tsnd_user::GetModuleSndUser1(),\n\t\tsnd_user::GetModuleSndUser2(),\n\t\tmic::GetModule(),\n\t\tnn::erreula::GetModule(),\n\t\tnn::act::GetModule(),\n\t\tnn::acp::GetModule(),\n\t\tnn::ac::GetModule(),\n\t\tnn::ec::GetModule(),\n\t\tnn::boss::GetModule(),\n\t\tnn::nfp::GetModule(),\n\t\tnn::uds::GetModule(),\n\t\tnn::nim::GetModule(),\n\t\tnn::ndm::GetModule(),\n\t\tnn::spm::GetModule(),\n\t\tnn::save::GetModule(),\n\t\tnsysnet::GetModule(),\n\t\tnn::fp::GetModule(),\n\t\tnn::olv::GetModule(),\n\t\tnn::idbe::GetModule(),\n\t\tnlibnss::GetModule(),\n\t\tnlibcurl::GetModule(),\n\t\tsysapp::GetModule(),\n\t\tnsyshid::GetModule(),\n\t\tnsyskbd::GetModule(),\n\t\tswkbd::GetModule(),\n\t\tcamera::GetModule(),\n\t\tproc_ui::GetModule(),\n\t\tavm::GetModule(),\n\t\tdrmapp::GetModule(),\n\t\tTCL::GetModule(),\n\t\tnn::cmpt::GetModule(),\n\t\tnn::ccr::GetModule(),\n\t\tnn::temp::GetModule(),\n\t\tnn::aoc::GetModule(),\n\t\tnn::pdm::GetModule(),\n\t\tH264::GetModule(),\n\t\tntag::GetModule(),\n\t\tnfc::GetModule(),\n\t};\n\treturn s_cosModules;\n}\n"
  },
  {
    "path": "src/Cafe/OS/RPL/COSModule.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tenum class RplEntryReason;\n};\n\n// base class for HLE RPL implementations\nclass COSModule\n{\npublic:\n\tvirtual std::string_view GetName() = 0;\n\n\tvirtual std::vector<std::string_view> GetDependencies() { return {}; };\n\n\tvirtual void RPLMapped() {}; // RPL mapped into process\n\tvirtual void RPLUnmapped() {}; // RPL unmapped\n\n\tvirtual void rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) {};\n\t// note: to simplify cleanup, both RPLUnmapped() and rpl_entry(unload) are always called even if the process is shutdown via \"Close game\"\n};\n\nstd::span<COSModule*> GetCOSModules();\n"
  },
  {
    "path": "src/Cafe/OS/RPL/elf.cpp",
    "content": "#include <zlib.h>\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n#include \"util/VirtualHeap/VirtualHeap.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n\ntypedef struct  \n{\n\t/* +0x00 */ uint32be magic;\n\t/* +0x04 */ uint8 eiClass;\n\t/* +0x05 */ uint8 eiData;\n\t/* +0x06 */ uint8 eiVersion;\n\t/* +0x07 */ uint8 eiOSABI;\n\t/* +0x08 */ uint8 eiOSABIVersion;\n\t/* +0x09 */ uint8 eiPadding[7];\n\t/* +0x10 */ uint16be eType;\n\t/* +0x12 */ uint16be eMachine;\n\t/* +0x14 */ uint32be eVersion;\n\t/* +0x18 */ uint32be entrypoint;\n\t/* +0x1C */ uint32be phOffset;\n\t/* +0x20 */ uint32be shOffset;\n\n\t/* +0x24 */ uint32be eFlags;\n\t/* +0x28 */ uint16be eHeaderSize;\n\t/* +0x2A */ uint16be ePHEntrySize;\n\t/* +0x2C */ uint16be ePHNum;\n\t/* +0x2E */ uint16be eSHEntrySize;\n\t/* +0x30 */ uint16be eSHNum;\n\t/* +0x32 */ uint16be eShStrIndex;\n}elfHeader_t;\n\nstatic_assert(sizeof(elfHeader_t) == 0x34, \"\");\n\ntypedef struct\n{\n\t/* +0x00 */ uint32be nameOffset;\n\t/* +0x04 */ uint32be shType;\n\t/* +0x08 */ uint32be shFlags;\n\t/* +0x0C */ uint32be shAddr;\n\t/* +0x10 */ uint32be shOffset;\n\t/* +0x14 */ uint32be shSize;\n\n\t/* +0x18 */ uint32be shLink;\n\t/* +0x1C */ uint32be shInfo;\n\n\t/* +0x20 */ uint32be shAddrAlign;\n\t/* +0x24 */ uint32be shEntSize;\n}elfSectionEntry_t;\n\nstatic_assert(sizeof(elfSectionEntry_t) == 0x28, \"\");\n\n#define PF_X\t\t(1 << 0)\t/* Segment is executable */\n#define PF_W\t\t(1 << 1)\t/* Segment is writable */\n#define PF_R\t\t(1 << 2)\t/* Segment is readable */\n\n// Map elf into memory\nuint32 ELF_LoadFromMemory(uint8* elfData, sint32 size, const char* name)\n{\n\telfHeader_t* header = (elfHeader_t*)elfData;\n\n\tuint32 sectionCount = header->eSHNum;\n\tuint32 sectionTableOffset = header->shOffset;\n\tuint32 sectionTableEntrySize = header->eSHEntrySize;\n\n\telfSectionEntry_t* sectionTable = (elfSectionEntry_t*)(elfData + (uint32)header->shOffset);\n\tmemory_enableHBLELFCodeArea();\n\tfor (uint32 i = 0; i < sectionCount; i++)\n\t{\n\t\tdebug_printf(\"%02d Addr %08x Size %08x Offs %08x Flags %08x Type %08x EntSize %08x\\n\", i, (uint32)sectionTable[i].shAddr, (uint32)sectionTable[i].shSize, (uint32)sectionTable[i].shOffset, (uint32)sectionTable[i].shFlags, (uint32)sectionTable[i].shType, (uint32)sectionTable[i].shEntSize);\n\t\tuint32 shAddr = (uint32)sectionTable[i].shAddr;\n\t\tuint32 shSize = (uint32)sectionTable[i].shSize;\n\t\tuint32 shOffset = (uint32)sectionTable[i].shOffset;\n\t\tuint32 shType = (uint32)sectionTable[i].shType;\n\t\tuint32 shFlags = (uint32)sectionTable[i].shFlags;\n\n\t\tif (shOffset > (uint32)size)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"ELF section {} out of bounds\", i);\n\t\t\tcontinue;\n\t\t}\n\t\tuint32 copySize = std::min(shSize, size - shOffset);\n\n\t\t// 0x00802000\n\t\tif (shAddr != 0)\n\t\t{\n\t\t\tif (shType == SHT_NOBITS)\n\t\t\t{\n\t\t\t\tmemset(memory_getPointerFromVirtualOffset(shAddr), 0, shSize);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tmemcpy(memory_getPointerFromVirtualOffset(shAddr), elfData + shOffset, copySize);\n\t\t\t}\n\t\t\t//  \tSHT_NOBITS\n\t\t}\n\t\tif((shFlags & PF_X) > 0)\n\t\t\tPPCRecompiler_allocateRange(shAddr, shSize);\n\t}\n\treturn header->entrypoint;\n}\n\n// From Homebrew Launcher:\n//#define MEM_BASE                    (0x00800000)\n//#define ELF_DATA_ADDR               (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x00))\n//#define ELF_DATA_SIZE               (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x04))\n//#define HBL_CHANNEL                 (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x08))\n//#define RPX_MAX_SIZE                (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x0C))\n//#define RPX_MAX_CODE_SIZE           (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x10))\n//#define MAIN_ENTRY_ADDR             (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x00))\n//#define OS_FIRMWARE                 (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x04))\n//\n//#define OS_SPECIFICS                ((OsSpecifics*)(MEM_BASE + 0x1500))\n//\n//#define MEM_AREA_TABLE              ((s_mem_area*)(MEM_BASE + 0x1600))\n\n//typedef struct _OsSpecifics\n//{\n//\tunsigned int addr_OSDynLoad_Acquire;\n//\tunsigned int addr_OSDynLoad_FindExport;\n//\tunsigned int addr_OSTitle_main_entry;\n//\n//\tunsigned int addr_KernSyscallTbl1;\n//\tunsigned int addr_KernSyscallTbl2;\n//\tunsigned int addr_KernSyscallTbl3;\n//\tunsigned int addr_KernSyscallTbl4;\n//\tunsigned int addr_KernSyscallTbl5;\n//\n//\tint(*LiWaitIopComplete)(int, int *);\n//\tint(*LiWaitIopCompleteWithInterrupts)(int, int *);\n//\tunsigned int addr_LiWaitOneChunk;\n//\tunsigned int addr_PrepareTitle_hook;\n//\tunsigned int addr_sgIsLoadingBuffer;\n//\tunsigned int addr_gDynloadInitialized;\n//\tunsigned int orig_LiWaitOneChunkInstr;\n//} OsSpecifics;\n"
  },
  {
    "path": "src/Cafe/OS/RPL/rpl.cpp",
    "content": "#include <zlib.h>\n\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n#include \"Cafe/OS/RPL/rpl_symbol_storage.h\"\n#include \"util/VirtualHeap/VirtualHeap.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"util/ChunkedHeap/ChunkedHeap.h\"\n\n#include \"util/crypto/crc32.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_DynLoad.h\"\n#include \"COSModule.h\"\n\nclass PPCCodeHeap : public VHeap\n{\npublic:\n\tPPCCodeHeap(void* heapBase, uint32 heapSize) : VHeap(heapBase, heapSize) { };\n\n\tvoid* alloc(uint32 size, uint32 alignment = 4) override\n\t{\n\t\treturn VHeap::alloc(size, alignment);\n\t}\n\n\tvoid free(void* addr) override\n\t{\n\t\tuint32 allocSize = getAllocationSizeFromAddr(addr);\n\t\tMPTR ppcAddr = memory_getVirtualOffsetFromPointer(addr);\n\t\tPPCRecompiler_invalidateRange(ppcAddr, ppcAddr + allocSize);\n\t\tVHeap::free(addr);\n\t}\n};\n\nVHeap rplLoaderHeap_workarea(nullptr, MEMORY_RPLLOADER_AREA_SIZE);\nPPCCodeHeap rplLoaderHeap_lowerAreaCodeMem2(nullptr, MEMORY_CODE_TRAMPOLINE_AREA_SIZE);\nPPCCodeHeap rplLoaderHeap_codeArea2(nullptr, MEMORY_CODEAREA_SIZE);\n\nChunkedFlatAllocator<64 * 1024> g_heapTrampolineArea;\n\nstd::vector<RPLDependency*> rplDependencyList;\n\nRPLModule* rplModuleList[256];\nsint32 rplModuleCount = 0;\n\nbool rplLoader_applicationHasMemoryControl = false;\nuint32 rplLoader_maxCodeAddress = 0; // highest used code address\nuint32 rplLoader_currentTLSModuleIndex = 1; // value 0 is reserved\nuint32 rplLoader_currentHandleCounter = 0x00001000;\nsint16 rplLoader_currentTlsModuleIndex = 0x0001;\nRPLModule* rplLoader_mainModule = nullptr;\nuint32 rplLoader_sdataAddr = MPTR_NULL; // r13\nuint32 rplLoader_sdata2Addr = MPTR_NULL; // r2\nuint32 rplLoader_currentDataAllocatorAddr = 0x10000000;\n\nstd::map<void(*)(PPCInterpreter_t* hCPU), uint32> g_map_callableExports;\n\nstruct RPLMappingRegion\n{\n\tMPTR baseAddress;\n\tuint32 endAddress;\n\tuint32 calcEndAddress; // used to verify endAddress\n};\n\nstruct RPLRegionMappingTable\n{\n\tRPLMappingRegion region[4];\n};\n\n#define RPL_MAPPING_REGION_DATA\t\t\t0\n#define RPL_MAPPING_REGION_LOADERINFO\t1\n#define RPL_MAPPING_REGION_TEXT\t\t\t2\n#define RPL_MAPPING_REGION_TEMP\t\t\t3\n\nvoid RPLLoader_UnloadModule(RPLDependency* rplDependency, bool skipPPCCalls);\nvoid RPLLoader_RemoveDependency(std::string_view name);\n\nuint8* RPLLoader_AllocateTrampolineCodeSpace(RPLModule* rplLoaderContext, sint32 size)\n{\t\n\tif (rplLoaderContext)\n\t{\n\t\t// allocation owned by rpl\n\t\treturn (uint8*)rplLoaderContext->heapTrampolineArea.alloc(size, 4);\n\t}\n\t// allocation owned by global context\n\tauto result = (uint8*)g_heapTrampolineArea.alloc(size, 4);\n\trplLoader_maxCodeAddress = std::max(rplLoader_maxCodeAddress, memory_getVirtualOffsetFromPointer(g_heapTrampolineArea.getCurrentBlockPtr()) + g_heapTrampolineArea.getCurrentBlockOffset());\n\treturn result;\n}\n\nuint8* RPLLoader_AllocateTrampolineCodeSpace(sint32 size)\n{\n\treturn RPLLoader_AllocateTrampolineCodeSpace(nullptr, size);\n}\n\nMPTR RPLLoader_AllocateCodeSpace(uint32 size, uint32 alignment)\n{\n\tcemu_assert_debug((alignment & (alignment - 1)) == 0); // alignment must be a power of 2\n\tMPTR codeAddr = memory_getVirtualOffsetFromPointer(rplLoaderHeap_codeArea2.alloc(size, alignment));\n\trplLoader_maxCodeAddress = std::max(rplLoader_maxCodeAddress, codeAddr + size);\n\tPPCRecompiler_allocateRange(codeAddr, size);\n\treturn codeAddr;\n}\n\nuint32 RPLLoader_AllocateDataSpace(RPLModule* rpl, uint32 size, uint32 alignment)\n{\n\tif (rplLoader_applicationHasMemoryControl)\n\t{\n\t\tStackAllocator<uint32be> memPtr;\n\t\t*(memPtr.GetPointer()) = 0;\n\t\tPPCCoreCallback(rpl->funcAlloc.value(), size, alignment, memPtr.GetPointer());\n\t\treturn (uint32)*(memPtr.GetPointer());\n\t}\n\trplLoader_currentDataAllocatorAddr = (rplLoader_currentDataAllocatorAddr + alignment - 1) & ~(alignment - 1);\n\tuint32 mem = rplLoader_currentDataAllocatorAddr;\n\trplLoader_currentDataAllocatorAddr += size;\n\treturn mem;\n}\n\nvoid RPLLoader_FreeData(RPLModule* rpl, void* ptr)\n{\n\tPPCCoreCallback(rpl->funcFree.value(), ptr);\n}\n\nuint32 RPLLoader_GetDataAllocatorAddr()\n{\n\treturn (rplLoader_currentDataAllocatorAddr + 0xFFF) & (~0xFFF);\n}\n\nuint32 RPLLoader_GetMaxCodeOffset()\n{\n\treturn rplLoader_maxCodeAddress;\n}\n\n#define PPCASM_OPC_R_TEMPL_SIMM(_rD, _rA, _IMM) (((_rD)<<21)|((_rA)<<16)|((_IMM)&0xFFFF))\n\n// generates 32-bit jump. Modifies R11 and CTR\nMPTR _generateTrampolineFarJump(RPLModule* rplLoaderContext, MPTR destAddr)\n{\n\tauto itr = rplLoaderContext->trampolineMap.find(destAddr);\n\tif (itr != rplLoaderContext->trampolineMap.end())\n\t\treturn itr->second;\n\n\tMPTR trampolineAddr = memory_getVirtualOffsetFromPointer(RPLLoader_AllocateTrampolineCodeSpace(rplLoaderContext, 4*4));\n\tuint32 destAddrU32 = (uint32)destAddr;\n\tuint32 ppcOpcode = 0;\n\t// ADDI R11, R0, ...\n\tppcOpcode = PPCASM_OPC_R_TEMPL_SIMM(11, 0, destAddrU32 & 0xFFFF);\n\tppcOpcode |= (14 << 26);\n\tmemory_writeU32(trampolineAddr + 0x0, ppcOpcode);\n\t// ADDIS R11, R11, ...<<16\n\tppcOpcode = PPCASM_OPC_R_TEMPL_SIMM(11, 11, ((destAddrU32 >> 16) + ((destAddrU32 >> 15) & 1)) & 0xFFFF);\n\tppcOpcode |= (15 << 26);\n\tmemory_writeU32(trampolineAddr + 0x4, ppcOpcode);\n\t// MTCTR r11\n\tmemory_writeU32(trampolineAddr + 0x8, 0x7D6903A6);\n\t// BCTR\n\tmemory_writeU32(trampolineAddr + 0xC, 0x4E800420);\n\t// if the destination is a known symbol, create a proxy (duplicate) symbol at the jump\n\trplSymbolStorage_createJumpProxySymbol(trampolineAddr, destAddr);\n\trplLoaderContext->trampolineMap.emplace(destAddr, trampolineAddr);\n\treturn trampolineAddr;\n}\n\nvoid* RPLLoader_AllocWorkarea(uint32 size, uint32 alignment, uint32* allocSize)\n{\n\tsize = (size + 31)&~31;\n\t*allocSize = size;\n\tvoid* allocAddr = rplLoaderHeap_workarea.alloc(size, alignment);\n\tcemu_assert(allocAddr != nullptr);\n\tmemset(allocAddr, 0, size);\n\treturn allocAddr;\n}\n\nvoid RPLLoader_FreeWorkarea(void* allocAddr)\n{\n\trplLoaderHeap_workarea.free(allocAddr);\n}\n\nbool RPLLoader_CheckBounds(RPLModule* rplLoaderContext, uint32 offset, uint32 size)\n{\n\tif ((offset + size) > rplLoaderContext->RPLRawData.size_bytes())\n\t\treturn false;\n\treturn true;\n}\n\nbool RPLLoader_ProcessHeaders(std::string_view moduleName, uint8* rplData, uint32 rplSize, RPLModule** rplLoaderContextOut)\n{\n\trplHeaderNew_t* rplHeader = (rplHeaderNew_t*)rplData;\n\t*rplLoaderContextOut = nullptr;\n\tif (rplHeader->version04 != 0x01)\n\t\treturn false;\n\tif (rplHeader->ukn05 != 0x02)\n\t\treturn false;\n\tif (rplHeader->magic2_0 != 0xCA)\n\t\treturn false;\n\tif (rplHeader->magic2_1 != 0xFE)\n\t\treturn false;\n\tif (rplHeader->ukn06 > 1)\n\t\treturn false;\n\tif (rplHeader->ukn12 != 0x14)\n\t\treturn false;\n\tif (rplHeader->ukn14 != 0x01)\n\t\treturn false;\n\tif (rplHeader->sectionTableEntryCount < 2)\n\t\treturn false; // RPL must end with two sections: CRCS + FILEINFO\n\t// setup RPL info struct\n\tRPLModule* rplLoaderContext = new RPLModule();\n\trplLoaderContext->RPLRawData = std::span<uint8>(rplData, rplSize);\n\trplLoaderContext->heapTrampolineArea.setBaseAllocator(&rplLoaderHeap_lowerAreaCodeMem2);\n\t// load section table\n\tif ((uint32)rplHeader->sectionTableEntrySize != sizeof(rplSectionEntryNew_t))\n\t\tassert_dbg();\n\tsint32 sectionCount = (sint32)rplHeader->sectionTableEntryCount;\n\tsint32 sectionTableSize = (sint32)rplHeader->sectionTableEntrySize * sectionCount;\n\trplLoaderContext->sectionTablePtr = (rplSectionEntryNew_t*)malloc(sectionTableSize);\n\tmemcpy(rplLoaderContext->sectionTablePtr, rplData + (uint32)(rplHeader->sectionTableOffset), sectionTableSize);\n\t// copy rpl header\n\tmemcpy(&rplLoaderContext->rplHeader, rplHeader, sizeof(rplHeaderNew_t));\n\t// verify that section n-1 is FILEINFO\n\trplSectionEntryNew_t* fileinfoSection = rplLoaderContext->sectionTablePtr + ((uint32)rplLoaderContext->rplHeader.sectionTableEntryCount - 1);\n\tif (fileinfoSection->fileOffset == 0 || (uint32)fileinfoSection->fileOffset >= rplSize || (uint32)fileinfoSection->type != SHT_RPL_FILEINFO)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"RPLLoader: Last section not FILEINFO\");\n\t}\n\t// verify that section n-2 is CRCs\n\trplSectionEntryNew_t* crcSection = rplLoaderContext->sectionTablePtr + ((uint32)rplLoaderContext->rplHeader.sectionTableEntryCount - 2);\n\tif (crcSection->fileOffset == 0 || (uint32)crcSection->fileOffset >= rplSize || (uint32)crcSection->type != SHT_RPL_CRCS)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"RPLLoader: The section before FILEINFO must be CRCs\");\n\t}\n\t// load FILEINFO section\n\tif (fileinfoSection->sectionSize < sizeof(RPLFileInfoData))\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: FILEINFO section size is below expected size\");\n\t\tdelete rplLoaderContext;\n\t\treturn false;\n\t}\n\n\t// read RPL mapping info\n\tuint8* fileInfoRawPtr = (uint8*)(rplData + fileinfoSection->fileOffset);\n\tif (((uint64)fileinfoSection->fileOffset+fileinfoSection->sectionSize) > (uint64)rplSize)\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: FILEINFO section outside of RPL file bounds\");\n\t\treturn false;\n\t}\n\trplLoaderContext->sectionData_fileInfo.resize(fileinfoSection->sectionSize);\n\tmemcpy(rplLoaderContext->sectionData_fileInfo.data(), fileInfoRawPtr, rplLoaderContext->sectionData_fileInfo.size());\n\n\tRPLFileInfoData* fileInfoPtr = (RPLFileInfoData*)rplLoaderContext->sectionData_fileInfo.data();\n\tif (fileInfoPtr->fileInfoMagic != 0xCAFE0402)\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: Invalid FILEINFO magic\");\n\t\treturn false;\n\t}\n\n\t// process FILEINFO\n\trplLoaderContext->fileInfo.textRegionSize = fileInfoPtr->textRegionSize;\n\trplLoaderContext->fileInfo.dataRegionSize = fileInfoPtr->dataRegionSize;\n\trplLoaderContext->fileInfo.baseAlign = fileInfoPtr->baseAlign;\n\trplLoaderContext->fileInfo.ukn14 = fileInfoPtr->ukn14;\n\trplLoaderContext->fileInfo.trampolineAdjustment = fileInfoPtr->trampolineAdjustment;\n\trplLoaderContext->fileInfo.ukn4C = fileInfoPtr->ukn4C;\n\trplLoaderContext->fileInfo.tlsModuleIndex = fileInfoPtr->tlsModuleIndex;\n\trplLoaderContext->fileInfo.sdataBase1 = fileInfoPtr->sdataBase1;\n\trplLoaderContext->fileInfo.sdataBase2 = fileInfoPtr->sdataBase2;\n\trplLoaderContext->fileInfo.flags = fileInfoPtr->flags;\n\n\t// init section address table\n\trplLoaderContext->sectionAddressTable2.resize(sectionCount);\n\t// init modulename\n\trplLoaderContext->moduleName2.assign(moduleName);\n\t// convert modulename to lower-case\n\tfor(auto& c : rplLoaderContext->moduleName2)\n\t\tc = _ansiToLower(c);\n\n\t// load CRC section\n\tuint32 crcTableExpectedSize = sectionCount * sizeof(uint32be);\n\tif (!RPLLoader_CheckBounds(rplLoaderContext, crcSection->fileOffset, crcTableExpectedSize))\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: CRC section outside of RPL file bounds\");\n\t\tcrcSection->sectionSize = 0;\n\t}\n\telse if (crcSection->sectionSize < crcTableExpectedSize)\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: CRC section size (0x{:x}) less than required (0x{:x})\", (uint32)crcSection->sectionSize, crcTableExpectedSize);\n\t}\n\telse if (crcSection->sectionSize != crcTableExpectedSize)\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: CRC section size (0x{:x}) does not match expected size (0x{:x})\", (uint32)crcSection->sectionSize, crcTableExpectedSize);\n\t}\n\n\tuint32 crcActualSectionCount = crcSection->sectionSize / sizeof(uint32); // how many CRCs are actually stored\n\n\trplLoaderContext->crcTable.resize(sectionCount);\n\tif (crcActualSectionCount > 0)\n\t{\n\t\tuint32be* crcTableData = (uint32be*)(rplData + crcSection->fileOffset);\n\t\tfor (uint32 i = 0; i < crcActualSectionCount; i++)\n\t\t\trplLoaderContext->crcTable[i] = crcTableData[i];\n\t}\n\n\t// verify CRC of FILEINFO section\n\tuint32 crcCalcFileinfo = crc32_calc(0, rplLoaderContext->sectionData_fileInfo.data(), rplLoaderContext->sectionData_fileInfo.size());\n\tuint32 crcFileinfo = rplLoaderContext->GetSectionCRC(sectionCount - 1);\n\tif (crcCalcFileinfo != crcFileinfo)\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: FILEINFO section has CRC mismatch - Calculated: {:08x} Actual: {:08x}\", crcCalcFileinfo, crcFileinfo);\n\t}\n\n\trplLoaderContext->sectionAddressTable2[sectionCount - 1].ptr = rplLoaderContext->sectionData_fileInfo.data();\n\trplLoaderContext->sectionAddressTable2[sectionCount - 2].ptr = nullptr;// rplLoaderContext->crcTablePtr;\n\n\t// set output\n\t*rplLoaderContextOut = rplLoaderContext;\n\treturn true;\n}\n\nclass RPLUncompressedSection\n{\npublic:\n\tstd::vector<uint8> sectionData;\n};\n\nrplSectionEntryNew_t* RPLLoader_GetSection(RPLModule* rplLoaderContext, sint32 sectionIndex)\n{\n\tsint32 sectionCount = rplLoaderContext->rplHeader.sectionTableEntryCount;\n\tif (sectionIndex < 0 || sectionIndex >= sectionCount)\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: Section index out of bounds\");\n\t\trplLoaderContext->hasError = true;\n\t\treturn nullptr;\n\t}\n\trplSectionEntryNew_t* section = rplLoaderContext->sectionTablePtr + sectionIndex;\n\treturn section;\n}\n\nRPLUncompressedSection* RPLLoader_LoadUncompressedSection(RPLModule* rplLoaderContext, sint32 sectionIndex)\n{\n\tconst rplSectionEntryNew_t* section = RPLLoader_GetSection(rplLoaderContext, sectionIndex);\n\tif (section == nullptr)\n\t\treturn nullptr;\n\n\tRPLUncompressedSection* uSection = new RPLUncompressedSection();\n\n\tif ((uint32)section->type == 0x8)\n\t{\n\t\tuSection->sectionData.resize(section->sectionSize);\n\t\tstd::fill(uSection->sectionData.begin(), uSection->sectionData.end(), 0);\n\t\treturn uSection;\n\t}\n\n\t// check if raw size does not exceed bounds of rpl\n\tif (!RPLLoader_CheckBounds(rplLoaderContext, section->fileOffset, section->sectionSize))\n\t{\n\t\t// BSS\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: Raw data for section {} exceeds bounds of RPL file\", sectionIndex);\n\t\trplLoaderContext->hasError = true;\n\t\tdelete uSection;\n\t\treturn nullptr;\n\t}\n\n\tuint32 sectionFlags = section->flags;\n\tif ((sectionFlags & SHF_RPL_COMPRESSED) != 0)\n\t{\n\t\t// decompress\n\t\tif (!RPLLoader_CheckBounds(rplLoaderContext, section->fileOffset, sizeof(uint32be)) )\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"RPLLoader: Uncompressed data of section {} is too large\", sectionIndex);\n\t\t\trplLoaderContext->hasError = true;\n\t\t\tdelete uSection;\n\t\t\treturn nullptr;\n\t\t}\n\t\tuint32 uncompressedSize = *(uint32be*)(rplLoaderContext->RPLRawData.data() + (uint32)section->fileOffset);\n\t\tif (uncompressedSize >= 1*1024*1024*1024) // sections bigger than 1GB not allowed\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"RPLLoader: Uncompressed data of section {} is too large\", sectionIndex);\n\t\t\trplLoaderContext->hasError = true;\n\t\t\tdelete uSection;\n\t\t\treturn nullptr;\n\t\t}\n\t\tint ret;\n\t\tz_stream strm;\n\t\tstrm.zalloc = Z_NULL;\n\t\tstrm.zfree = Z_NULL;\n\t\tstrm.opaque = Z_NULL;\n\t\tret = inflateInit(&strm);\n\t\tif (ret == Z_OK)\n\t\t{\n\t\t\tstrm.avail_in = (uint32)section->sectionSize - 4;\n\t\t\tstrm.next_in = rplLoaderContext->RPLRawData.data() + (uint32)section->fileOffset + 4;\n\t\t\tstrm.avail_out = uncompressedSize;\n\t\t\tuSection->sectionData.resize(uncompressedSize);\n\t\t\tstrm.next_out = uSection->sectionData.data();\n\t\t\tret = inflate(&strm, Z_FULL_FLUSH);\n\t\t\tinflateEnd(&strm);\n\t\t\tif ((ret != Z_OK && ret != Z_STREAM_END) || strm.avail_in != 0 || strm.avail_out != 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"RPLLoader: Error while inflating data for section {}\", sectionIndex);\n\t\t\t\trplLoaderContext->hasError = true;\n\t\t\t\tdelete uSection;\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// no decompression\n\t\tuSection->sectionData.resize(section->sectionSize);\n\t\tconst uint8* sectionDataBegin = rplLoaderContext->RPLRawData.data() + (uint32)section->fileOffset;\n\t\tstd::copy(sectionDataBegin, sectionDataBegin + section->sectionSize, uSection->sectionData.data());\n\t}\n\treturn uSection;\n}\n\nbool RPLLoader_LoadSingleSection(RPLModule* rplLoaderContext, sint32 sectionIndex, RPLMappingRegion* regionMappingInfo, MPTR mappedAddress)\n{\n\trplSectionEntryNew_t* section = RPLLoader_GetSection(rplLoaderContext, sectionIndex);\n\tif (section == nullptr)\n\t\treturn false;\n\n\tuint32 mappingOffset = (uint32)section->virtualAddress - (uint32)regionMappingInfo->baseAddress;\n\tif (mappingOffset >= 0x10000000)\n\t\tcemuLog_logDebug(LogType::Force, \"Suspicious section mapping offset: 0x{:08x}\", mappingOffset);\n\tuint32 sectionAddress = mappedAddress + mappingOffset;\n\n\trplLoaderContext->sectionAddressTable2[sectionIndex].ptr = memory_getPointerFromVirtualOffset(sectionAddress);\n\n\tcemu_assert(rplLoaderContext->debugSectionLoadMask[sectionIndex] == false);\n\trplLoaderContext->debugSectionLoadMask[sectionIndex] = true;\n\n\t// extract section\n\tRPLUncompressedSection* uncompressedSection = RPLLoader_LoadUncompressedSection(rplLoaderContext, sectionIndex);\n\tif (uncompressedSection == nullptr)\n\t{\n\t\trplLoaderContext->hasError = true;\n\t\treturn false;\n\t}\n\n\t// copy to mapped address\n\tif(section->virtualAddress < regionMappingInfo->baseAddress || (section->virtualAddress + uncompressedSection->sectionData.size()) > regionMappingInfo->endAddress)\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: Section {} (0x{:08x} to 0x{:08x}) is not fully contained in it's bounding region (0x{:08x} to 0x{:08x})\", sectionIndex, section->virtualAddress, section->virtualAddress + uncompressedSection->sectionData.size(), regionMappingInfo->baseAddress, regionMappingInfo->endAddress);\n\tuint8* sectionAddressPtr = memory_getPointerFromVirtualOffset(sectionAddress);\n\tstd::copy(uncompressedSection->sectionData.begin(), uncompressedSection->sectionData.end(), sectionAddressPtr);\n\n\t// update size in section (todo - use separate field)\n\tif (uncompressedSection->sectionData.size() < section->sectionSize)\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: Section {} uncompresses to {} bytes but sectionSize is {}\", sectionIndex, uncompressedSection->sectionData.size(), (uint32)section->sectionSize);\n\n\tsection->sectionSize = uncompressedSection->sectionData.size();\n\n\tdelete uncompressedSection;\n\treturn true;\n}\n\nbool RPLLoader_LoadSections(sint32 aProcId, RPLModule* rplLoaderContext)\n{\n\tRPLRegionMappingTable regionMappingTable;\n\tmemset(&regionMappingTable, 0, sizeof(RPLRegionMappingTable));\n\tregionMappingTable.region[0].baseAddress = 0xFFFFFFFF;\n\tregionMappingTable.region[1].baseAddress = 0xFFFFFFFF;\n\tregionMappingTable.region[2].baseAddress = 0xFFFFFFFF;\n\tregionMappingTable.region[3].baseAddress = 0xFFFFFFFF;\n\tfor (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\trplSectionEntryNew_t* section = rplLoaderContext->sectionTablePtr + i;\n\t\tuint32 sectionType = section->type;\n\t\tuint32 sectionFlags = section->flags;\n\t\tuint32 sectionVirtualAddr = section->virtualAddress;\n\t\tuint32 sectionFileOffset = section->fileOffset;\n\t\tuint32 sectionSize = section->sectionSize;\n\t\tif(sectionSize == 0)\n\t\t\tcontinue;\n\t\tif (sectionType == SHT_RPL_CRCS)\n\t\t\tcontinue;\n\t\tif (sectionType == SHT_RPL_FILEINFO)\n\t\t\tcontinue;\n\t\t//if (sectionType == SHT_RPL_IMPORTS) -> The official loader seems to skip these, leading to incorrect boundary calculations\n\t\t//\tcontinue;\n\t\tif ((sectionFlags & 2) == 0)\n\t\t{\n\t\t\tuint32 endFileOffset = sectionFileOffset + sectionSize;\n\t\t\tregionMappingTable.region[RPL_MAPPING_REGION_TEMP].baseAddress = std::min(regionMappingTable.region[RPL_MAPPING_REGION_TEMP].baseAddress, sectionFileOffset);\n\t\t\tregionMappingTable.region[RPL_MAPPING_REGION_TEMP].endAddress = std::max(regionMappingTable.region[RPL_MAPPING_REGION_TEMP].endAddress, endFileOffset);\n\t\t\tcontinue;\n\t\t}\n\t\tif ((sectionFlags & 4) != 0 && sectionType != SHT_RPL_EXPORTS && sectionType != SHT_RPL_IMPORTS)\n\t\t{\n\t\t\tregionMappingTable.region[RPL_MAPPING_REGION_TEXT].baseAddress = std::min(regionMappingTable.region[RPL_MAPPING_REGION_TEXT].baseAddress, sectionVirtualAddr);\n\t\t\tcontinue;\n\t\t}\n\t\tif ((sectionFlags & 1) != 0)\n\t\t{\n\t\t\tregionMappingTable.region[RPL_MAPPING_REGION_DATA].baseAddress = std::min(regionMappingTable.region[RPL_MAPPING_REGION_DATA].baseAddress, sectionVirtualAddr);\n\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{ \n\t\t\tregionMappingTable.region[RPL_MAPPING_REGION_LOADERINFO].baseAddress = std::min(regionMappingTable.region[RPL_MAPPING_REGION_LOADERINFO].baseAddress, sectionVirtualAddr);\n\t\t\tcontinue;\n\n\t\t}\n\t}\n\tfor (sint32 i = 0; i < 4; i++)\n\t{\n\t\tif (regionMappingTable.region[i].baseAddress == 0xFFFFFFFF)\n\t\t\tregionMappingTable.region[i].baseAddress = 0;\n\t}\n\tregionMappingTable.region[RPL_MAPPING_REGION_TEXT].endAddress = (regionMappingTable.region[RPL_MAPPING_REGION_TEXT].baseAddress + rplLoaderContext->fileInfo.textRegionSize) - rplLoaderContext->fileInfo.trampolineAdjustment;\n\tregionMappingTable.region[RPL_MAPPING_REGION_DATA].endAddress = regionMappingTable.region[RPL_MAPPING_REGION_DATA].baseAddress + rplLoaderContext->fileInfo.dataRegionSize;\n\tregionMappingTable.region[RPL_MAPPING_REGION_LOADERINFO].endAddress = (regionMappingTable.region[RPL_MAPPING_REGION_LOADERINFO].baseAddress + rplLoaderContext->fileInfo.ukn14) - rplLoaderContext->fileInfo.ukn4C;\n\n\t// calculate region size\n\tuint32 regionDataSize = regionMappingTable.region[RPL_MAPPING_REGION_DATA].endAddress - regionMappingTable.region[RPL_MAPPING_REGION_DATA].baseAddress;\n\tuint32 regionLoaderinfoSize = regionMappingTable.region[RPL_MAPPING_REGION_LOADERINFO].endAddress - regionMappingTable.region[RPL_MAPPING_REGION_LOADERINFO].baseAddress;\n\tuint32 regionTextSize = regionMappingTable.region[RPL_MAPPING_REGION_TEXT].endAddress - regionMappingTable.region[RPL_MAPPING_REGION_TEXT].baseAddress;\n\n\trplLoaderContext->regionMappingBase_data = RPLLoader_AllocateDataSpace(rplLoaderContext, regionDataSize, 0x1000);\n\trplLoaderContext->regionMappingBase_loaderInfo = RPLLoader_AllocateDataSpace(rplLoaderContext, regionLoaderinfoSize, 0x1000);\n\trplLoaderContext->regionMappingBase_text = rplLoaderHeap_codeArea2.alloc(regionTextSize + 0x1000, 0x1000);\n\trplLoader_maxCodeAddress = std::max(rplLoader_maxCodeAddress, rplLoaderContext->regionMappingBase_text.GetMPTR() + regionTextSize + 0x1000);\n\tPPCRecompiler_allocateRange(rplLoaderContext->regionMappingBase_text.GetMPTR(), regionTextSize + 0x1000);\n\n\t// workaround for DKC Tropical Freeze\n\tif (boost::iequals(rplLoaderContext->moduleName2, \"rs10_production\"))\n\t{\n\t\t// allocate additional 12MB of unused data to get below a size of 0x3E200000 for the main ExpHeap\n\t\t// otherwise the game will assume it's running on a Devkit unit with 2GB of RAM and subtract 1GB from available space\n\t\tRPLLoader_AllocateDataSpace(rplLoaderContext, 12*1024*1024, 0x1000);\n\t}\n\t// set region sizes\n\trplLoaderContext->regionSize_data = regionDataSize;\n\trplLoaderContext->regionSize_loaderInfo = regionLoaderinfoSize;\n\trplLoaderContext->regionSize_text = regionTextSize;\n\n\t// load data sections\n\tfor (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\trplSectionEntryNew_t* section = rplLoaderContext->sectionTablePtr + i;\n\t\tuint32 sectionType = section->type;\n\t\tuint32 sectionFlags = section->flags;\n\t\tif (section->sectionSize == 0)\n\t\t\tcontinue;\n\t\tif( rplLoaderContext->sectionAddressTable2[i].ptr != nullptr )\n\t\t\tcontinue;\n\t\tif ((sectionFlags & 2) == 0)\n\t\t\tcontinue;\n\t\tif ((sectionFlags & 1) == 0)\n\t\t\tcontinue;\n\n\t\tRPLLoader_LoadSingleSection(rplLoaderContext, i, regionMappingTable.region + RPL_MAPPING_REGION_DATA, rplLoaderContext->regionMappingBase_data);\n\t}\n\t// load loaderinfo sections\n\tfor (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\trplSectionEntryNew_t* section = rplLoaderContext->sectionTablePtr + i;\n\t\tuint32 sectionType = section->type;\n\t\tuint32 sectionFlags = section->flags;\n\t\tif (section->sectionSize == 0)\n\t\t\tcontinue;\n\t\tif (rplLoaderContext->sectionAddressTable2[i].ptr != nullptr)\n\t\t\tcontinue;\n\t\tif ((sectionFlags & 2) == 0)\n\t\t\tcontinue;\n\t\tif(sectionType != SHT_RPL_EXPORTS && sectionType != SHT_RPL_IMPORTS && (sectionFlags&5) != 0 )\n\t\t\tcontinue;\n\t\tbool readRaw = false;\n\n\t\tRPLLoader_LoadSingleSection(rplLoaderContext, i, regionMappingTable.region + RPL_MAPPING_REGION_LOADERINFO, rplLoaderContext->regionMappingBase_loaderInfo);\n\n\t\tif (sectionType == SHT_RPL_EXPORTS)\n\t\t{\n\t\t\tuint8* sectionAddress = (uint8*)rplLoaderContext->sectionAddressTable2[i].ptr;\n\t\t\tif ((sectionFlags & 4) != 0)\n\t\t\t{\n\t\t\t\trplLoaderContext->exportFCount = *(uint32be*)(sectionAddress + 0);\n\t\t\t\trplLoaderContext->exportFDataPtr = (rplExportTableEntry_t*)(sectionAddress + 8);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\trplLoaderContext->exportDCount = *(uint32be*)(sectionAddress + 0);\n\t\t\t\trplLoaderContext->exportDDataPtr = (rplExportTableEntry_t*)(sectionAddress + 8);\n\t\t\t}\n\t\t}\n\t}\n\t// load text sections\n\tuint32 textSectionMappedBase = rplLoaderContext->regionMappingBase_text.GetMPTR() + (uint32)rplLoaderContext->fileInfo.trampolineAdjustment; // leave some space for trampolines before the code section begins\n\tfor (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\trplSectionEntryNew_t* section = rplLoaderContext->sectionTablePtr + i;\n\t\tuint32 sectionType = section->type;\n\t\tuint32 sectionFlags = section->flags;\n\t\tif( section->sectionSize == 0 )\n\t\t\tcontinue;\n\t\tif (rplLoaderContext->sectionAddressTable2[i].ptr != nullptr)\n\t\t\tcontinue;\n\t\tif ((sectionFlags & 2) == 0)\n\t\t\tcontinue;\n\t\tif ((sectionFlags & 4) == 0)\n\t\t\tcontinue;\n\t\tif( sectionType == SHT_RPL_EXPORTS)\n\t\t\tcontinue;\n\n\t\tif (section->type == 0x8)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"RPLLoader: Unsupported text section type 0x8\");\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\n\t\tRPLLoader_LoadSingleSection(rplLoaderContext, i, regionMappingTable.region + RPL_MAPPING_REGION_TEXT, textSectionMappedBase);\n\t}\n\t// load temp region sections\n\tuint32 tempRegionSize = regionMappingTable.region[RPL_MAPPING_REGION_TEMP].endAddress - regionMappingTable.region[RPL_MAPPING_REGION_TEMP].baseAddress;\n\tuint8* tempRegionPtr;\n\tuint32 tempRegionAllocSize = 0;\n\ttempRegionPtr = (uint8*)RPLLoader_AllocWorkarea(tempRegionSize, 0x20, &tempRegionAllocSize);\n\trplLoaderContext->tempRegionPtr = tempRegionPtr;\n\trplLoaderContext->tempRegionAllocSize = tempRegionAllocSize;\n\tmemcpy(tempRegionPtr, rplLoaderContext->RPLRawData.data()+regionMappingTable.region[RPL_MAPPING_REGION_TEMP].baseAddress, tempRegionSize);\n\t// load temp region sections\n\tfor (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\trplSectionEntryNew_t* section = rplLoaderContext->sectionTablePtr + i;\n\t\tuint32 sectionType = section->type;\n\t\tuint32 sectionFlags = section->flags;\n\t\tif (section->sectionSize == 0)\n\t\t\tcontinue;\n\t\tif (rplLoaderContext->sectionAddressTable2[i].ptr != nullptr)\n\t\t\tcontinue;\n\t\tif (sectionType == SHT_RPL_FILEINFO || sectionType == SHT_RPL_CRCS)\n\t\t\tcontinue;\n\t\t// calculate offset within temp section\n\t\tuint32 sectionFileOffset = section->fileOffset;\n\t\tuint32 sectionSize = section->sectionSize;\n\t\tcemu_assert_debug(sectionFileOffset >= regionMappingTable.region[RPL_MAPPING_REGION_TEMP].baseAddress);\n\t\tcemu_assert_debug((sectionFileOffset + sectionSize) <= regionMappingTable.region[RPL_MAPPING_REGION_TEMP].endAddress);\n\t\trplLoaderContext->sectionAddressTable2[i].ptr = (tempRegionPtr + (sectionFileOffset - regionMappingTable.region[RPL_MAPPING_REGION_TEMP].baseAddress));\n\n\t\tuint32 sectionEndAddress = sectionFileOffset + sectionSize;\n\t\tregionMappingTable.region[RPL_MAPPING_REGION_TEMP].calcEndAddress = std::max(regionMappingTable.region[RPL_MAPPING_REGION_TEMP].calcEndAddress, sectionEndAddress);\n\t}\n\t// todo: Verify calcEndAddress<=endAddress for each region\n\n\t// dump loaded sections\n\t/*\n\tfor (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\trplSectionEntryNew_t* section = rplLoaderContext->sectionTablePtr + i;\n\t\tuint32 sectionType = section->type;\n\t\tuint32 sectionFlags = section->flags;\n\t\tif (section->sectionSize == 0)\n\t\t\tcontinue;\n\t\tif (rplLoaderContext->sectionAddressTable2[i].ptr == nullptr)\n\t\t\tcontinue;\n\t\tFileStream* fs = FileStream::createFile2(fmt::format(\"dump/rpl_sections/{}_{:08x}_type{:08x}.bin\", i, (uint32)section->virtualAddress, (uint32)sectionType));\n\t\tfs->writeData(rplLoaderContext->sectionAddressTable2[i].ptr, section->sectionSize);\n\t\tdelete fs;\n\t}\n\t*/\n\treturn true;\n}\n\nstruct RPLFileSymtabEntry\n{\n\t/* +0x0 */ uint32be ukn00;\n\t/* +0x4 */ uint32be symbolAddress;\n\t/* +0x8 */ uint32be ukn08;\n\t/* +0xC */ uint8    info;\n\t/* +0xD */ uint8    ukn0D;\n\t/* +0xE */ uint16be sectionIndex;\n};\n\nstruct RPLSharedImportTracking\n{\n\tRPLModule* rplLoaderContext; // rpl loader context of module with exports\n\trplSectionEntryNew_t* exportSection; // export section\n\tchar modulename[RPL_MODULE_NAME_LENGTH];\n};\n\nstatic_assert(sizeof(RPLFileSymtabEntry) == 0x10, \"rplSymtabEntry_t has invalid size\");\n\ntypedef struct\n{\n\tuint64 hash1;\n\tuint64 hash2;\n\tuint32 address;\n}mappedFunctionImport_t;\n\nstd::vector<mappedFunctionImport_t> list_mappedFunctionImports = std::vector<mappedFunctionImport_t>();\n\nvoid _calculateMappedImportNameHash(const char* rplName, const char* funcName, uint64* h1Out, uint64* h2Out)\n{\n\tuint64 h1 = 0;\n\tuint64 h2 = 0;\n\t// rplName\n\twhile (*rplName)\n\t{\n\t\tuint64 v = (uint64)*rplName;\n\t\th1 += v;\n\t\th2 ^= v;\n\t\th1 = std::rotl<uint64>(h1, 3);\n\t\th2 = std::rotl<uint64>(h2, 7);\n\t\trplName++;\n\t}\n\t// funcName\n\twhile (*funcName)\n\t{\n\t\tuint64 v = (uint64)*funcName;\n\t\th1 += v;\n\t\th2 ^= v;\n\t\th1 = std::rotl<uint64>(h1, 3);\n\t\th2 = std::rotl<uint64>(h2, 7);\n\t\tfuncName++;\n\t}\n\t*h1Out = h1;\n\t*h2Out = h2;\n}\n\nuint32 RPLLoader_MakePPCCallable(void(*ppcCallableExport)(PPCInterpreter_t* hCPU))\n{\n\tauto it = g_map_callableExports.find(ppcCallableExport);\n\tif (it != g_map_callableExports.end())\n\t\treturn it->second;\n\t// get HLE function index\n\tsint32 functionIndex = PPCInterpreter_registerHLECall(ppcCallableExport, fmt::format(\"PPCCallback{:x}\", (uintptr_t)ppcCallableExport));\n\tMPTR codeAddr = memory_getVirtualOffsetFromPointer(RPLLoader_AllocateTrampolineCodeSpace(4));\n\tuint32 opcode = (1 << 26) | functionIndex;\n\tmemory_write<uint32>(codeAddr, opcode);\n\tg_map_callableExports[ppcCallableExport] = codeAddr;\n\treturn codeAddr;\n}\n\nuint32 rpl_mapHLEImport(RPLModule* rplLoaderContext, const char* rplName, const char* funcName, bool functionMustExist)\n{\n\t// calculate import name hash\n\tuint64 mappedImportHash1;\n\tuint64 mappedImportHash2;\n\t_calculateMappedImportNameHash(rplName, funcName, &mappedImportHash1, &mappedImportHash2);\n\t// find already mapped name\n\tfor (auto& importItr : list_mappedFunctionImports)\n\t{\n\t\tif (importItr.hash1 == mappedImportHash1 && importItr.hash2 == mappedImportHash2)\n\t\t{\n\t\t\treturn importItr.address;\n\t\t}\n\t}\n\t// copy lib file name and cut off .rpl from libName if present\n\tchar libName[512];\n\tstrcpy_s(libName, rplName);\n\tfor (sint32 i = 0; i < sizeof(libName); i++)\n\t{\n\t\tif (libName[i] == '\\0')\n\t\t\tbreak;\n\t\tif (libName[i] == '.')\n\t\t{\n\t\t\tlibName[i] = '\\0';\n\t\t\tbreak;\n\t\t}\n\t}\n\t// find import in list of known exports\n\tsint32 functionIndex = osLib_getFunctionIndex(libName, funcName);\n\tif (functionIndex >= 0)\n\t{\n\t\tMPTR codeAddr = memory_getVirtualOffsetFromPointer(RPLLoader_AllocateTrampolineCodeSpace(4));\n\t\tuint32 opcode = (1 << 26) | functionIndex;\n\t\tmemory_write<uint32>(codeAddr, opcode);\n\t\t// register mapped import\n\t\tmappedFunctionImport_t newImport;\n\t\tnewImport.hash1 = mappedImportHash1;\n\t\tnewImport.hash2 = mappedImportHash2;\n\t\tnewImport.address = codeAddr;\n\t\tlist_mappedFunctionImports.push_back(newImport);\n\t\t// remember in symbol storage for debugger\n\t\trplSymbolStorage_store(libName, funcName, codeAddr);\n\t\treturn codeAddr;\n\t}\n\telse\n\t{\n\t\tif (functionMustExist == false)\n\t\t\treturn MPTR_NULL;\n\t}\n\t// create code for unsupported import\n\tuint32 codeStart = memory_getVirtualOffsetFromPointer(RPLLoader_AllocateTrampolineCodeSpace(256));\n\tuint32 currentAddress = codeStart;\n\tuint32 opcode = (1 << 26) | (0xFFD0); // opcode for HLE: Unsupported import\n\tmemory_write<uint32>(codeStart + 0, opcode);\n\tmemory_write<uint32>(codeStart + 4, 0x4E800020);\n\tcurrentAddress += 8;\n\t// write name of lib/function\n\tsint32 libNameLength = std::min(128, (sint32)strlen(libName));\n\tsint32 funcNameLength = std::min(128, (sint32)strlen(funcName));\n\tmemcpy(memory_getPointerFromVirtualOffset(currentAddress), libName, libNameLength);\n\tcurrentAddress += libNameLength;\n\tmemory_writeU8(currentAddress, '.');\n\tcurrentAddress++;\n\tmemcpy(memory_getPointerFromVirtualOffset(currentAddress), funcName, funcNameLength);\n\tcurrentAddress += funcNameLength;\n\tmemory_writeU8(currentAddress, '\\0');\n\tcurrentAddress++;\n\t// align address to 4 byte boundary\n\tcurrentAddress = (currentAddress + 3)&~3;\n\t// register mapped import\n\tmappedFunctionImport_t newImport;\n\tnewImport.hash1 = mappedImportHash1;\n\tnewImport.hash2 = mappedImportHash2;\n\tnewImport.address = codeStart;\n\tlist_mappedFunctionImports.push_back(newImport);\n\t// remember in symbol storage for debugger\n\trplSymbolStorage_store(libName, funcName, codeStart);\n\t// return address of code start\n\treturn codeStart;\n}\n\nMPTR RPLLoader_FindRPLExport(RPLModule* rplLoaderContext, const char* symbolName, bool isData)\n{\n\tif (isData)\n\t{\n\t\tcemu_assert_debug(false);\n\t\t// todo - look in DDataPtr\n\t}\n\tif (rplLoaderContext->exportFDataPtr)\n\t{\n\t\tchar* exportNameData = (char*)((uint8*)rplLoaderContext->exportFDataPtr - 8);\n\t\tfor (uint32 f = 0; f < rplLoaderContext->exportFCount; f++)\n\t\t{\n\t\t\tchar* name = exportNameData + (uint32)rplLoaderContext->exportFDataPtr[f].nameOffset;\n\t\t\tif (strcmp(name, symbolName) == 0)\n\t\t\t{\n\t\t\t\treturn (uint32)rplLoaderContext->exportFDataPtr[f].virtualOffset;\n\t\t\t}\n\t\t}\n\t}\n\treturn MPTR_NULL;\n}\n\nMPTR _findHLEExport(RPLModule* rplLoaderContext, RPLSharedImportTracking* sharedImportTrackingEntry, char* libname, char* symbolName, bool isData)\n{\n\tif (isData)\n\t{\n\t\t// data export\n\t\tMPTR weakExportAddr = osLib_getPointer(libname, symbolName);\n\t\tif (weakExportAddr != 0xFFFFFFFF)\n\t\t\treturn weakExportAddr;\n\t\tcemuLog_logDebug(LogType::Force, \"Unsupported data export ({}): {}.{}\", rplLoaderContext->moduleName2, libname, symbolName);\n\t\treturn MPTR_NULL;\n\t}\n\telse\n\t{\n\t\t// try to find HLE/placeholder export\n\t\tMPTR mappedFunctionAddr = rpl_mapHLEImport(rplLoaderContext, libname, symbolName, true);\n\t\tif (mappedFunctionAddr == MPTR_NULL)\n\t\t\tcemu_assert_debug(false);\n\t\treturn mappedFunctionAddr;\n\t}\n}\n\nuint32 RPLLoader_FindModuleExport(RPLModule* rplLoaderContext, bool isData, const char* exportName)\n{\n\tif (isData == false)\n\t{\n\t\t// find function export\n\t\tchar* exportNameData = (char*)((uint8*)rplLoaderContext->exportFDataPtr - 8);\n\t\tfor (uint32 f = 0; f < rplLoaderContext->exportFCount; f++)\n\t\t{\n\t\t\tchar* name = exportNameData + (uint32)rplLoaderContext->exportFDataPtr[f].nameOffset;\n\t\t\tif (strcmp(name, exportName) == 0)\n\t\t\t{\n\t\t\t\tuint32 exportAddress = rplLoaderContext->exportFDataPtr[f].virtualOffset;\n\t\t\t\treturn exportAddress;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// find data export\n\t\tchar* exportNameData = (char*)((uint8*)rplLoaderContext->exportDDataPtr - 8);\n\t\tfor (uint32 f = 0; f < rplLoaderContext->exportDCount; f++)\n\t\t{\n\t\t\tchar* name = exportNameData + (uint32)rplLoaderContext->exportDDataPtr[f].nameOffset;\n\t\t\tif (strcmp(name, exportName) == 0)\n\t\t\t{\n\t\t\t\tuint32 exportAddress = rplLoaderContext->exportDDataPtr[f].virtualOffset;\n\t\t\t\treturn exportAddress;\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\nbool RPLLoader_FixImportSymbols(RPLModule* rplLoaderContext, sint32 symtabSectionIndex, rplSectionEntryNew_t* symTabSection, std::span<RPLSharedImportTracking> sharedImportTracking, uint32 linkMode)\n{\n\tuint32 sectionSize = symTabSection->sectionSize;\n\tuint32 symbolEntrySize = symTabSection->ukn24;\n\tif (symbolEntrySize == 0)\n\t\tsymbolEntrySize = 0x10;\n\tcemu_assert(symbolEntrySize == 0x10);\n\tcemu_assert((sectionSize % symbolEntrySize) == 0);\n\tuint32 symbolCount = sectionSize / symbolEntrySize;\n\tcemu_assert(symbolCount >= 2);\n\n\tuint16 sectionCount = rplLoaderContext->rplHeader.sectionTableEntryCount;\n\tuint8* symtabData = (uint8*)rplLoaderContext->sectionAddressTable2[symtabSectionIndex].ptr;\n\n\tuint32 strtabSectionIndex = symTabSection->symtabSectionIndex;\n\tuint8* strtabData = (uint8*)rplLoaderContext->sectionAddressTable2[strtabSectionIndex].ptr;\n\tuint32 strtabSize = rplLoaderContext->sectionTablePtr[strtabSectionIndex].sectionSize;\n\n\tfor (uint32 i = 0; i < symbolCount; i++)\n\t{\n\t\tRPLFileSymtabEntry* sym = (RPLFileSymtabEntry*)(symtabData + i*symbolEntrySize);\n\t\tuint16 symSectionIndex = sym->sectionIndex;\n\t\tif (symSectionIndex == 0 || symSectionIndex >= sectionCount)\n\t\t\tcontinue;\n\t\tvoid* symbolSectionAddress = rplLoaderContext->sectionAddressTable2[symSectionIndex].ptr;\n\t\tif (symbolSectionAddress == nullptr)\n\t\t{\n\t\t\tsym->symbolAddress = 0xCD000000 | i;\n\t\t\tcontinue;\n\t\t}\n\t\trplSectionEntryNew_t* symbolSection = rplLoaderContext->sectionTablePtr + symSectionIndex;\n\t\tuint32 symbolOffset = sym->symbolAddress - symbolSection->virtualAddress;\n\t\t\n\t\tif (symSectionIndex >= sharedImportTracking.size())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"RPL-Loader: Symbol {} references invalid section\", i);\n\t\t}\n\t\telse if (sharedImportTracking[symSectionIndex].rplLoaderContext != nullptr)\n\t\t{\n\t\t\tif (linkMode == 0)\n\t\t\t{\n\t\t\t\tcontinue; // ?\n\t\t\t}\n\t\t\tif (symbolOffset < 8)\n\t\t\t{\n\t\t\t\tcemu_assert(symbolSectionAddress >= memory_base && symbolSectionAddress <= (memory_base + 0x100000000ULL));\n\t\t\t\tuint32 symbolSectionMPTR = memory_getVirtualOffsetFromPointer(symbolSectionAddress);\n\t\t\t\tuint32 symbolRelativeAddress = (uint32)sym->symbolAddress - (uint32)symbolSection->virtualAddress;\n\n\t\t\t\tsym->symbolAddress = (symbolSectionMPTR + symbolRelativeAddress);\n\t\t\t\tcontinue; // ?\n\t\t\t}\n\n\t\t\tif (sharedImportTracking[symSectionIndex].rplLoaderContext == HLE_MODULE_PTR)\n\t\t\t{\n\t\t\t\t// get address\n\t\t\t\tuint32 nameOffset = sym->ukn00;\n\t\t\t\tchar* symbolName = (char*)strtabData + nameOffset;\n\t\t\t\tif (nameOffset >= strtabSize)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"RPLLoader: Symbol {} in section {} has out-of-bounds name offset\", i, symSectionIndex);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tuint32 exportAddress;\n\t\t\t\tif (nameOffset == 0)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(symbolName[0] == '\\0');\n\t\t\t\t\texportAddress = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tbool isDataExport = (rplLoaderContext->sectionTablePtr[symSectionIndex].flags & 0x4) == 0;\n\t\t\t\t\texportAddress = _findHLEExport(rplLoaderContext, sharedImportTracking.data() + symSectionIndex, sharedImportTracking[symSectionIndex].modulename, symbolName, isDataExport);\n\t\t\t\t}\n\n\t\t\t\tsym->symbolAddress = exportAddress;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tRPLModule* ctxExportModule = sharedImportTracking[symSectionIndex].rplLoaderContext;\n\t\t\t\tuint32 nameOffset = sym->ukn00;\n\t\t\t\tchar* symbolName = (char*)strtabData + nameOffset;\n\n\t\t\t\tbool foundExport = false;\n\t\t\t\tif ((rplLoaderContext->sectionTablePtr[symSectionIndex].flags & 0x4) != 0)\n\t\t\t\t{\n\t\t\t\t\t// find function export\n\t\t\t\t\tchar* exportNameData = (char*)((uint8*)ctxExportModule->exportFDataPtr - 8);\n\t\t\t\t\tfor (uint32 f = 0; f < ctxExportModule->exportFCount; f++)\n\t\t\t\t\t{\n\t\t\t\t\t\tchar* name = exportNameData + (uint32)ctxExportModule->exportFDataPtr[f].nameOffset;\n\t\t\t\t\t\tif (strcmp(name, symbolName) == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuint32 exportAddress = ctxExportModule->exportFDataPtr[f].virtualOffset;\n\t\t\t\t\t\t\tsym->symbolAddress = exportAddress;\n\t\t\t\t\t\t\tfoundExport = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// find data export\n\t\t\t\t\tchar* exportNameData = (char*)((uint8*)ctxExportModule->exportDDataPtr - 8);\n\t\t\t\t\tfor (uint32 f = 0; f < ctxExportModule->exportDCount; f++)\n\t\t\t\t\t{\n\t\t\t\t\t\tchar* name = exportNameData + (uint32)ctxExportModule->exportDDataPtr[f].nameOffset;\n\t\t\t\t\t\tif (strcmp(name, symbolName) == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuint32 exportAddress = ctxExportModule->exportDDataPtr[f].virtualOffset;\n\t\t\t\t\t\t\tsym->symbolAddress = exportAddress;\n\t\t\t\t\t\t\tfoundExport = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (foundExport == false)\n\t\t\t\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\t\t\tif (nameOffset > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"export not found - force lookup in function exports\");\n\t\t\t\t\t\t// workaround - force look up export in function exports\n\t\t\t\t\t\tchar* exportNameData = (char*)((uint8*)ctxExportModule->exportFDataPtr - 8);\n\t\t\t\t\t\tfor (uint32 f = 0; f < ctxExportModule->exportFCount; f++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tchar* name = exportNameData + (uint32)ctxExportModule->exportFDataPtr[f].nameOffset;\n\t\t\t\t\t\t\tif (strcmp(name, symbolName) == 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuint32 exportAddress = ctxExportModule->exportFDataPtr[f].virtualOffset;\n\t\t\t\t\t\t\t\tsym->symbolAddress = exportAddress;\n\t\t\t\t\t\t\t\tfoundExport = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n#endif\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint32 symbolType = sym->info & 0xF;\n\t\t\tif (symbolType == 6)\n\t\t\t\tcontinue;\n\t\t\tif (((uint32)symbolSection->type != SHT_RPL_IMPORTS && linkMode != 2) ||\n\t\t\t\t((uint32)symbolSection->type == SHT_RPL_IMPORTS && linkMode != 1 && linkMode != 2)\n\t\t\t\t)\n\t\t\t{\n\t\t\t\t// update virtual address to match actual mapped address\n\t\t\t\tcemu_assert(symbolSectionAddress >= memory_base && symbolSectionAddress <= (memory_base + 0x100000000ULL));\n\t\t\t\tuint32 symbolSectionMPTR = memory_getVirtualOffsetFromPointer(symbolSectionAddress);\n\t\t\t\tuint32 symbolRelativeAddress = (uint32)sym->symbolAddress - (uint32)symbolSection->virtualAddress;\n\t\t\t\tsym->symbolAddress = (symbolSectionMPTR + symbolRelativeAddress);\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\nbool RPLLoader_ApplySingleReloc(RPLModule* rplLoaderContext, uint32 uknR3, uint8* relocTargetSectionAddress, uint32 relocType, bool isSymbolBinding2, uint32 relocOffset, uint32 relocAddend, uint32 symbolAddress, sint16 tlsModuleIndex)\n{\n\tMPTR relocTargetSectionMPTR = memory_getVirtualOffsetFromPointer(relocTargetSectionAddress);\n\tMPTR relocAddrMPTR = relocTargetSectionMPTR + relocOffset;\n\tuint8* relocAddr = memory_getPointerFromVirtualOffset(relocAddrMPTR);\n\n\tif (relocType == RPL_RELOC_HA16)\n\t{\n\t\tuint32 relocDestAddr = symbolAddress + relocAddend;\n\t\tuint32 p = (relocDestAddr >> 16);\n\t\tp += (relocDestAddr >> 15) & 1;\n\t\t*(uint16be*)(relocAddr) = (uint16)p;\n\t}\n\telse if (relocType == RPL_RELOC_LO16)\n\t{\n\t\tuint32 relocDestAddr = symbolAddress + relocAddend;\n\t\tuint32 p = relocDestAddr;\n\t\t*(uint16be*)(relocAddr) = (uint16)p;\n\t}\n\telse if (relocType == RPL_RELOC_HI16)\n\t{\n\t\tuint32 relocDestAddr = symbolAddress + relocAddend;\n\t\tuint32 p = relocDestAddr>>16;\n\t\t*(uint16be*)(relocAddr) = (uint16)p;\n\t}\n\telse if (relocType == RPL_RELOC_REL24)\n\t{\n\t\t// todo - effect of isSymbolBinding2?\n\t\tuint32 opc = *(uint32be*)relocAddr;\n\t\tuint32 relocDestAddr = symbolAddress + relocAddend;\n\t\tuint32 jumpDistance = relocDestAddr - memory_getVirtualOffsetFromPointer(relocAddr);\n\t\tif ((jumpDistance>>25) != 0 && (jumpDistance >> 25) != 0x7F)\n\t\t{\n\t\t\t// can't reach with 24bit jump, use trampoline + absolute branch\n\t\t\tMPTR trampolineAddr = _generateTrampolineFarJump(rplLoaderContext, relocDestAddr);\n\t\t\t// make absolute branch\n\t\t\tcemu_assert_debug((opc >> 26) == 18); // should be B/BL instruction\n\t\t\topc &= ~0x03fffffc;\n\t\t\topc |= (trampolineAddr & 0x3FFFFFC);\n\t\t\topc |= (1 << 1); // absolute jump\n\t\t\t*(uint32be*)relocAddr = opc;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// within range, update jump opcode\n\t\t\tif ((jumpDistance & 3) != 0)\n\t\t\t\tcemuLog_log(LogType::Force, \"RPL-Loader: Encountered unaligned RPL_RELOC_REL24\");\n\t\t\topc &= ~0x03fffffc;\n\t\t\topc |= (jumpDistance &0x03fffffc);\n\t\t\t*(uint32be*)relocAddr = opc;\n\t\t}\n\t}\n\telse if (relocType == RPL_RELOC_REL14)\n\t{\n\t\t// seen in Your Shape: Fitness Evolved\n\t\t// todo - effect of isSymbolBinding2?\n\t\tuint32 opc = *(uint32be*)relocAddr;\n\t\tuint32 relocDestAddr = symbolAddress + relocAddend;\n\t\tuint32 jumpDistance = relocDestAddr - memory_getVirtualOffsetFromPointer(relocAddr);\n\t\tif ((jumpDistance & ~0x7fff) != 0xFFFF8000 && (jumpDistance & ~0x7fff) != 0x00000000)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// within range, update jump opcode\n\t\t\tif ((jumpDistance & 3) != 0)\n\t\t\t\tcemuLog_log(LogType::Force, \"RPL-Loader: Encountered unaligned RPL_RELOC_REL14\");\n\t\t\topc &= ~0xfffc;\n\t\t\topc |= (jumpDistance & 0xfffc);\n\t\t\t*(uint32be*)relocAddr = opc;\n\t\t}\n\t}\n\telse if (relocType == RPL_RELOC_ADDR32)\n\t{\n\t\tuint32 relocDestAddr = symbolAddress + relocAddend;\n\t\tuint32 p = relocDestAddr;\n\t\t*(uint32be*)(relocAddr) = (uint32)p;\n\t}\n\telse if (relocType == R_PPC_DTPMOD32)\n\t{\n\t\t// patch tls_index.moduleIndex\n\t\t*(uint32be*)(relocAddr) = (uint32)(sint32)tlsModuleIndex;\n\t}\n\telse if (relocType == R_PPC_DTPREL32)\n\t{\n\t\t// patch tls_index.size\n\t\t*(uint32be*)(relocAddr) = (uint32)(sint32)(symbolAddress + relocAddend);\n\t}\n\telse if (relocType == R_PPC_REL16_HA)\n\t{\n\t\t// used by WUT\n\t\tuint32 relAddr = (symbolAddress + relocAddend) - relocAddrMPTR;\n\t\tuint32 p = (relAddr >> 16);\n\t\tp += (relAddr >> 15) & 1;\n\t\t*(uint16be*)(relocAddr) = (uint16)p;\n\t}\n\telse if (relocType == R_PPC_REL16_HI)\n\t{\n\t\t// used by WUT\n\t\tuint32 relAddr = (symbolAddress + relocAddend) - relocAddrMPTR;\n\t\tuint32 p = (relAddr >> 16);\n\t\t*(uint16be*)(relocAddr) = (uint16)p;\n\t}\n\telse if (relocType == R_PPC_REL16_LO)\n\t{\n\t\t// used by WUT\n\t\tuint32 relAddr = (symbolAddress + relocAddend) - relocAddrMPTR;\n\t\tuint32 p = (relAddr & 0xFFFF);\n\t\t*(uint16be*)(relocAddr) = (uint16)p;\n\t}\n\telse if (relocType == 0x6D) // SDATA reloc\n\t{\n\t\tuint32 opc = *(uint32be*)relocAddr;\n\n\t\tuint32 registerIndex = (opc >> 16) & 0x1F;\n\t\tuint32 destination = (symbolAddress + relocAddend);;\n\n\t\tif (registerIndex == 2)\n\t\t{\n\t\t\tuint32 offset = destination - rplLoader_sdata2Addr;\n\t\t\tuint32 newOpc = (opc & 0xffe00000) | (offset & 0xffff) | (registerIndex << 16);\n\t\t\t*(uint32be*)relocAddr = newOpc;\n\t\t}\n\t\telse if (registerIndex == 13)\n\t\t{\n\t\t\tuint32 offset = destination - rplLoader_sdataAddr;\n\t\t\tuint32 newOpc = (opc & 0xffe00000) | (offset & 0xffff) | (registerIndex << 16);\n\t\t\t*(uint32be*)relocAddr = newOpc;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"RPLLoader: sdata reloc uses register other than r2/r13\");\n\t\t\tcemu_assert(false);\n\t\t}\n\t}\n\telse if (relocType == 0xFB)\n\t{\n\t\t// relative offset - high\n\t\tuint32 relocDestAddr = symbolAddress + relocAddend;\n\t\tuint32 relativeOffset = relocDestAddr - relocAddrMPTR;\n\t\tuint16 prevValue = *(uint16be*)relocAddr;\n\t\tuint32 newImm = ((relativeOffset >> 16) + ((relativeOffset >> 15) & 0x1));\n\t\tnewImm &= 0xFFFF;\n\t\t*(uint16be*)relocAddr = newImm;\n\t\tif (symbolAddress != 0)\n\t\t{\n\t\t\tcemu_assert_debug((uint32)prevValue == newImm);\n\t\t}\n\t}\n\telse if (relocType == 0xFD)\n\t{\n\t\t// relative offset - low\n\t\tuint32 relocDestAddr = symbolAddress + relocAddend;\n\t\tuint32 relativeOffset = relocDestAddr - relocAddrMPTR;\n\t\tuint16 prevValue = *(uint16be*)relocAddr;\n\t\tuint32 newImm = relativeOffset;\n\t\tnewImm &= 0xFFFF;\n\t\t*(uint16be*)relocAddr = newImm;\n\t\tif (symbolAddress != 0)\n\t\t{\n\t\t\tcemu_assert_debug((uint32)prevValue == newImm);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: Unsupported reloc type 0x{:02x}\", relocType);\n\t\tcemu_assert_debug(false); // unknown reloc type\n\t}\n\treturn true;\n}\n\nbool RPLLoader_ApplyRelocs(RPLModule* rplLoaderContext, sint32 relaSectionIndex, rplSectionEntryNew_t* section, uint32 linkMode)\n{\n\tuint32 relocTargetSectionIndex = section->relocTargetSectionIndex;\n\tif (relocTargetSectionIndex >= (uint32)rplLoaderContext->rplHeader.sectionTableEntryCount)\n\t\tassert_dbg();\n\tuint32 symtabSectionIndex = section->symtabSectionIndex;\n\tuint8* relocTargetSectionAddress = (uint8*)(rplLoaderContext->sectionAddressTable2[relocTargetSectionIndex].ptr);\n\tcemu_assert(relocTargetSectionAddress);\n\t// get symtab info\n\trplSectionEntryNew_t* symtabSection = rplLoaderContext->sectionTablePtr + symtabSectionIndex;\n\tuint32 symtabSectionSize = symtabSection->sectionSize;\n\tuint32 symbolEntrySize = symtabSection->ukn24;\n\tif (symbolEntrySize == 0)\n\t\tsymbolEntrySize = 0x10;\n\tcemu_assert(symbolEntrySize == 0x10);\n\tcemu_assert((symtabSectionSize % symbolEntrySize) == 0);\n\tuint32 symbolCount = symtabSectionSize / symbolEntrySize;\n\tcemu_assert(symbolCount >= 2);\n\tuint8* symtabData = (uint8*)rplLoaderContext->sectionAddressTable2[symtabSectionIndex].ptr;\n\t// decompress reloc section if needed\n\tuint8* relocData;\n\tuint32 relocSize;\n\tif ((uint32)(section->flags) & SHF_RPL_COMPRESSED)\n\t{\n\t\tuint8* relocRawData = (uint8*)rplLoaderContext->sectionAddressTable2[relaSectionIndex].ptr;\n\t\tuint32 relocUncompressedSize = *(uint32be*)relocRawData;\n\t\trelocData = (uint8*)malloc(relocUncompressedSize);\n\t\trelocSize = relocUncompressedSize;\n\t\t// decompress\n\t\tint ret;\n\t\tz_stream strm;\n\t\tstrm.zalloc = Z_NULL;\n\t\tstrm.zfree = Z_NULL;\n\t\tstrm.opaque = Z_NULL;\n\t\tret = inflateInit(&strm);\n\t\tif (ret == Z_OK)\n\t\t{\n\t\t\tstrm.avail_in = (uint32)section->sectionSize - 4;\n\t\t\tstrm.next_in = relocRawData + 4;\n\t\t\tstrm.avail_out = relocUncompressedSize;\n\t\t\tstrm.next_out = relocData;\n\t\t\tret = inflate(&strm, Z_FULL_FLUSH);\n\t\t\tcemu_assert_debug(ret == Z_OK || ret == Z_STREAM_END);\n\t\t\tcemu_assert_debug(strm.avail_in == 0 && strm.avail_out == 0);\n\t\t\tinflateEnd(&strm);\n\t\t}\n\t}\n\telse\n\t{\n\t\trelocData = (uint8*)rplLoaderContext->sectionAddressTable2[relaSectionIndex].ptr;\n\t\trelocSize = section->sectionSize;\n\t}\n\t// check CRC\n\tuint32 calcCRC = crc32_calc(0, relocData, relocSize);\n\tuint32 crc = rplLoaderContext->GetSectionCRC(relaSectionIndex);\n\tif (calcCRC != crc)\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader {} - Relocation section {} has CRC mismatch - Calc: {:08x} Actual: {:08x}\", rplLoaderContext->moduleName2.c_str(), relaSectionIndex, calcCRC, crc);\n\t}\n\t// process relocations\n\tsint32 relocCount = relocSize / sizeof(rplRelocNew_t);\n\trplRelocNew_t* reloc = (rplRelocNew_t*)relocData;\n\tfor (sint32 i = 0; i < relocCount; i++)\n\t{\n\t\tuint32 relocType = (uint32)reloc->symbolIndexAndType & 0xFF;\n\t\tuint32 relocSymbolIndex = (uint32)reloc->symbolIndexAndType >> 8;\n\t\tif (relocType == 0)\n\t\t{\n\t\t\t// next\n\t\t\treloc++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (relocSymbolIndex >= symbolCount)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"reloc with symbol index out of range 0x{:04x}\", (uint32)relocSymbolIndex);\n\t\t\treloc++;\n\t\t\tcontinue;\n\t\t}\n\t\t// get symbol\n\t\tRPLFileSymtabEntry* sym = (RPLFileSymtabEntry*)(symtabData + symbolEntrySize*relocSymbolIndex);\n\n\t\tif ((uint32)sym->sectionIndex >= (uint32)rplLoaderContext->rplHeader.sectionTableEntryCount)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"reloc with sectionIndex out of range 0x{:04x}\", (uint32)sym->sectionIndex);\n\t\t\treloc++;\n\t\t\tcontinue;\n\t\t}\n\t\t// exclude symbols that arent ready yet\n\t\tif (linkMode == 0)\n\t\t{\n\t\t\tif ((uint32)rplLoaderContext->sectionTablePtr[(uint32)sym->sectionIndex].type == SHT_RPL_IMPORTS)\n\t\t\t{\n\t\t\t\treloc++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tuint32 symbolAddress = sym->symbolAddress;\n\t\tuint8 symbolType = (sym->info >> 0) & 0xF;\n\t\tuint8 symbolBinding = (sym->info >> 4) & 0xF;\n\t\tif ((symbolAddress&0xFF000000) == 0xCD000000)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t\t// next\n\t\t\treloc++;\n\t\t\tcontinue;\n\t\t}\n\t\tsint16 tlsModuleIndex = -1;\n\t\tif (relocType == R_PPC_DTPMOD32 || relocType == R_PPC_DTPREL32)\n\t\t{\n\t\t\t// TLS-relocation\n\t\t\tif (symbolType != 6)\n\t\t\t\tassert_dbg(); // not a TLS symbol\n\t\t\tif (rplLoaderContext->fileInfo.tlsModuleIndex == -1)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"RPLLoader: TLS relocs applied to non-TLS module\");\n\t\t\t\tcemu_assert_debug(false); // module not a TLS-module\n\t\t\t}\n\t\t\ttlsModuleIndex = rplLoaderContext->fileInfo.tlsModuleIndex;\n\t\t}\n\t\tuint32 relocOffset = (uint32)reloc->relocOffset - (uint32)rplLoaderContext->sectionTablePtr[relocTargetSectionIndex].virtualAddress;\n\t\tRPLLoader_ApplySingleReloc(rplLoaderContext, 0, relocTargetSectionAddress, relocType, symbolBinding == 2, relocOffset, reloc->relocAddend, symbolAddress, tlsModuleIndex);\n\n\t\t// next reloc\n\t\treloc++;\n\t}\n\n\tif ((uint32)(section->flags) & SHF_RPL_COMPRESSED)\n\t\tfree(relocData);\n\treturn true;\n}\n\nbool RPLLoader_HandleRelocs(RPLModule* rplLoaderContext, std::span<RPLSharedImportTracking> sharedImportTracking, uint32 linkMode)\n{\n\t// resolve relocs\n\tfor (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\trplSectionEntryNew_t* section = rplLoaderContext->sectionTablePtr + i;\n\t\tuint32 sectionType = section->type;\n\t\tif( sectionType != SHT_SYMTAB )\n\t\t\tcontinue;\n\t\tRPLLoader_FixImportSymbols(rplLoaderContext, i, section, sharedImportTracking, linkMode);\n\t}\n\n\t// apply relocs again after we have fixed the import section\n\tfor (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\trplSectionEntryNew_t* section = rplLoaderContext->sectionTablePtr + i;\n\t\tuint32 sectionType = section->type;\n\t\tif (sectionType != SHT_RELA)\n\t\t\tcontinue;\n\t\tRPLLoader_ApplyRelocs(rplLoaderContext, i, section, linkMode);\n\t}\n\treturn true;\n}\n\nvoid _RPLLoader_ExtractModuleNameFromPath(char* output, std::string_view input)\n{\n\t// scan to last '/'\n\tcemu_assert(!input.empty());\n\tsize_t startIndex = input.size() - 1;\n\twhile (startIndex > 0)\n\t{\n\t\tif (input[startIndex] == '/')\n\t\t{\n\t\t\tstartIndex++;\n\t\t\tbreak;\n\t\t}\n\t\tstartIndex--;\n\t}\n\t// cut off after '.'\n\tsize_t endIndex = startIndex;\n\twhile (endIndex < input.size())\n\t{\n\t\tif (input[endIndex] == '.')\n\t\t\tbreak;\n\t\tendIndex++;\n\t}\n\tsize_t nameLen = endIndex - startIndex;\n\tcemu_assert(nameLen != 0);\n\tnameLen = std::min<size_t>(nameLen, RPL_MODULE_NAME_LENGTH-1);\n\tmemcpy(output, input.data() + startIndex, nameLen);\n\toutput[nameLen] = '\\0';\n\t// convert to lower case\n\tstd::for_each(output, output + nameLen, [](char& c) {c = _ansiToLower(c);});\n}\n\nvoid RPLLoader_InitState()\n{\n\tcemu_assert_debug(!rplLoaderHeap_lowerAreaCodeMem2.hasAllocations());\n\tcemu_assert_debug(!rplLoaderHeap_codeArea2.hasAllocations());\n\tcemu_assert_debug(!rplLoaderHeap_workarea.hasAllocations());\n\trplLoaderHeap_lowerAreaCodeMem2.setHeapBase(memory_getPointerFromVirtualOffset(MEMORY_CODE_TRAMPOLINE_AREA_ADDR));\n\trplLoaderHeap_codeArea2.setHeapBase(memory_getPointerFromVirtualOffset(MEMORY_CODEAREA_ADDR));\n\trplLoaderHeap_workarea.setHeapBase(memory_getPointerFromVirtualOffset(MEMORY_RPLLOADER_AREA_ADDR));\n\tg_heapTrampolineArea.setBaseAllocator(&rplLoaderHeap_lowerAreaCodeMem2);\n    RPLLoader_UnloadAll();\n}\n\nvoid RPLLoader_BeginCemuhookCRC(RPLModule* rpl)\n{\n\t// calculate some values required for CRC\n\tsint32 sectionSymTableIndex = -1;\n\tsint32 sectionStrTableIndex = -1;\n\tfor (sint32 i = 0; i < rpl->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\tif (rpl->sectionTablePtr[i].type == SHT_SYMTAB)\n\t\t\tsectionSymTableIndex = i;\n\t\tif (rpl->sectionTablePtr[i].type == SHT_STRTAB && i != rpl->rplHeader.nameSectionIndex && sectionStrTableIndex == -1)\n\t\t\tsectionStrTableIndex = i;\n\t}\n\t// init patches CRC\n\trpl->patchCRC = 0;\n\tstatic const uint8 rplMagic[4] = { 0x7F, 'R', 'P', 'X' };\n\trpl->patchCRC = crc32_calc(rpl->patchCRC, rplMagic, sizeof(rplMagic));\n\tsint32 sectionCount = rpl->rplHeader.sectionTableEntryCount;\n\trpl->patchCRC = crc32_calc(rpl->patchCRC, &sectionCount, sizeof(sectionCount));\n\trpl->patchCRC = crc32_calc(rpl->patchCRC, &sectionSymTableIndex, sizeof(sectionSymTableIndex));\n\trpl->patchCRC = crc32_calc(rpl->patchCRC, &sectionStrTableIndex, sizeof(sectionStrTableIndex));\n\tsint32 sectionSectNameTableIndex = rpl->rplHeader.nameSectionIndex;\n\trpl->patchCRC = crc32_calc(rpl->patchCRC, &sectionSectNameTableIndex, sizeof(sectionSectNameTableIndex));\n\n\t// sections\n\tfor (sint32 i = 0; i < rpl->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\tauto sect = rpl->sectionTablePtr + i;\n\t\tuint32 nameOffset = sect->nameOffset;\n\t\tuint32 shType = sect->type;\n\t\tuint32 flags = sect->flags;\n\t\tuint32 virtualAddress = sect->virtualAddress;\n\t\tuint32 alignment = sect->alignment;\n\t\tuint32 sectionFileOffset = sect->fileOffset;\n\t\tuint32 sectionCompressedSize = sect->sectionSize;\n\t\tuint32 rawSize = 0;\n\t\tbool memoryAllocated = false;\n\t\tvoid* rawData = nullptr;\n\t\tif (shType == SHT_NOBITS)\n\t\t{\n\t\t\trawData = NULL;\n\t\t\trawSize = sectionCompressedSize;\n\t\t}\n\t\telse if ((flags&SHF_RPL_COMPRESSED) != 0)\n\t\t{\n\t\t\tuint32 decompressedSize = _swapEndianU32(*(uint32*)(rpl->RPLRawData.data() + sectionFileOffset));\n\t\t\trawSize = decompressedSize;\n\t\t\tif (rawSize >= 1024*1024*1024)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"RPLLoader-CRC: Cannot load section {} which is too large ({} bytes)\", i, decompressedSize);\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trawData = (uint8*)malloc(decompressedSize);\n\t\t\tif (rawData == nullptr)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"RPLLoader-CRC: Failed to allocate memory for uncompressed section {} ({} bytes)\", i, decompressedSize);\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmemoryAllocated = true;\n\t\t\t// decompress\n\t\t\tz_stream strm;\n\t\t\tstrm.zalloc = Z_NULL;\n\t\t\tstrm.zfree = Z_NULL;\n\t\t\tstrm.opaque = Z_NULL;\n\t\t\tinflateInit(&strm);\n\t\t\tstrm.avail_in = sectionCompressedSize - 4;\n\t\t\tstrm.next_in = rpl->RPLRawData.data() + (uint32)sectionFileOffset + 4;\n\t\t\tstrm.avail_out = decompressedSize;\n\t\t\tstrm.next_out = (Bytef*)rawData;\n\t\t\tauto ret = inflate(&strm, Z_FULL_FLUSH);\n\t\t\tif (ret != Z_OK && ret != Z_STREAM_END || strm.avail_in != 0 || strm.avail_out != 0)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"RPLLoader-CRC: Unable to decompress section {}\", i);\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"zRet {} availIn {} availOut {}\", ret, (sint32)strm.avail_in, (sint32)strm.avail_out);\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tfree(rawData);\n\t\t\t\tinflateEnd(&strm);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tinflateEnd(&strm);\n\t\t}\n\t\telse\n\t\t{\n\t\t\trawSize = sectionCompressedSize;\n\t\t\trawData = rpl->RPLRawData.data() + sectionFileOffset;\n\t\t}\n\n\t\trpl->patchCRC = crc32_calc(rpl->patchCRC, &nameOffset, sizeof(nameOffset));\n\t\trpl->patchCRC = crc32_calc(rpl->patchCRC, &shType, sizeof(shType));\n\t\trpl->patchCRC = crc32_calc(rpl->patchCRC, &flags, sizeof(flags));\n\t\trpl->patchCRC = crc32_calc(rpl->patchCRC, &virtualAddress, sizeof(virtualAddress));\n\t\trpl->patchCRC = crc32_calc(rpl->patchCRC, &rawSize, sizeof(rawSize));\n\t\trpl->patchCRC = crc32_calc(rpl->patchCRC, &alignment, sizeof(alignment));\n\n\t\tif (rawData != nullptr && rawSize > 0)\n\t\t{\n\t\t\trpl->patchCRC = crc32_calc(rpl->patchCRC, rawData, rawSize);\n\t\t}\n\t\tif (memoryAllocated && rawData)\n\t\t\tfree(rawData);\n\t}\n}\n\nvoid RPLLoader_incrementModuleDependencyRefs(RPLModule* rpl)\n{\n\tfor (uint32 i = 0; i < (uint32)rpl->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\tif (rpl->sectionTablePtr[i].type != (uint32be)SHT_RPL_IMPORTS)\n\t\t\tcontinue;\n\t\tchar* libName = (char*)((uint8*)rpl->sectionAddressTable2[i].ptr + 8);\n\t\tRPLLoader_AddDependency(libName);\n\t}\n}\n\nvoid RPLLoader_decrementModuleDependencyRefs(RPLModule* rpl)\n{\n\tfor (uint32 i = 0; i < (uint32)rpl->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\tif (rpl->sectionTablePtr[i].type != (uint32be)SHT_RPL_IMPORTS)\n\t\t\tcontinue;\n\t\tchar* libName = (char*)((uint8*)rpl->sectionAddressTable2[i].ptr + 8);\n\t\tRPLLoader_RemoveDependency(libName);\n\t}\n}\n\nvoid RPLLoader_UpdateEntrypoint(RPLModule* rpl)\n{\n\tuint32 virtualEntrypoint = rpl->rplHeader.entrypoint;\n\tuint32 entrypoint = 0xFFFFFFFF;\n\tfor (sint32 i = 0; i < (sint32)rpl->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\trplSectionEntryNew_t* section = rpl->sectionTablePtr + i;\n\t\tuint32 sectionStartAddr = (uint32)section->virtualAddress;\n\t\tuint32 sectionEndAddr = (uint32)section->virtualAddress + (uint32)section->sectionSize;\n\t\tif (virtualEntrypoint >= sectionStartAddr && virtualEntrypoint < sectionEndAddr)\n\t\t{\n\t\t\tcemu_assert_debug(entrypoint == 0xFFFFFFFF);\n\t\t\tentrypoint = (virtualEntrypoint - sectionStartAddr + memory_getVirtualOffsetFromPointer(rpl->sectionAddressTable2[i].ptr));\n\t\t}\n\t}\n\tcemu_assert(entrypoint != 0xFFFFFFFF);\n\trpl->entrypoint = entrypoint;\n}\n\nvoid RPLLoader_InitModuleAllocator(RPLModule* rpl)\n{\n\tif (!rplLoader_applicationHasMemoryControl)\n\t{\n\t\trpl->funcAlloc = 0;\n\t\trpl->funcFree = 0;\n\t\treturn;\n\t}\n\tcoreinit::OSDynLoad_GetAllocator(&rpl->funcAlloc, &rpl->funcFree);\n}\n\n// map rpl into memory, but do not resolve relocs and imports yet\nRPLModule* RPLLoader_LoadFromMemory(uint8* rplData, sint32 size, std::string_view name)\n{\n\tchar moduleName[RPL_MODULE_NAME_LENGTH];\n\t_RPLLoader_ExtractModuleNameFromPath(moduleName, name);\n\tRPLModule* rpl = nullptr;\n\tif (RPLLoader_ProcessHeaders({ moduleName }, rplData, size, &rpl) == false)\n\t{\n\t\tdelete rpl;\n\t\treturn nullptr;\n\t}\n\tRPLLoader_InitModuleAllocator(rpl);\n\tRPLLoader_BeginCemuhookCRC(rpl);\n\tif (RPLLoader_LoadSections(0, rpl) == false)\n\t{\n\t\tdelete rpl;\n\t\treturn nullptr;\n\t}\n\n\tcemuLog_logDebug(LogType::Force, \"Load {} Code-Offset: -0x{:x}\", name, rpl->regionMappingBase_text.GetMPTR() - 0x02000000);\n\n\t// sdata (r2/r13)\n\tuint32 sdataBaseAddress = rpl->fileInfo.sdataBase1; // base + 0x8000\n\tuint32 sdataBaseAddress2 = rpl->fileInfo.sdataBase2; // base + 0x8000\n\tfor (uint32 i = 0; i < (uint32)rpl->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\tif(rpl->sectionTablePtr[i].sectionSize == 0)\n\t\t\tcontinue;\n\t\tuint32 sectionFlags = rpl->sectionTablePtr[i].flags;\n\t\tuint32 sectionVirtualAddress = rpl->sectionTablePtr[i].virtualAddress;\n\t\tuint32 sectionSize = rpl->sectionTablePtr[i].sectionSize;\n\t\tif( (sectionFlags&4) != 0 )\n\t\t\tcontinue;\n\t\tif(sdataBaseAddress == 0x00008000 && sdataBaseAddress2 == 0x00008000)\n\t\t\tcontinue; // sdata not used (this workaround is needed for Wii U Party to boot)\n\t\t// sdata 1\n\t\tif ((sdataBaseAddress - 0x8000) >= (sectionVirtualAddress) &&\n\t\t\t(sdataBaseAddress - 0x8000) <= (sectionVirtualAddress + sectionSize))\n\t\t{\n\t\t\tuint32 rplLoader_sdataAddrNew = memory_getVirtualOffsetFromPointer(rpl->sectionAddressTable2[i].ptr) + (sdataBaseAddress - sectionVirtualAddress);\n\t\t\trplLoader_sdataAddr = rplLoader_sdataAddrNew;\n\t\t}\n\t\t// sdata 2\n\t\tif ((sdataBaseAddress2 - 0x8000) >= (sectionVirtualAddress) &&\n\t\t\t(sdataBaseAddress2 - 0x8000) <= (sectionVirtualAddress + sectionSize))\n\t\t{\n\t\t\trplLoader_sdata2Addr = memory_getVirtualOffsetFromPointer(rpl->sectionAddressTable2[i].ptr) + (sdataBaseAddress2 - sectionVirtualAddress);\n\t\t}\n\n\t}\n\t// cancel if error\n\tif (rpl->hasError)\n\t{\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: Unable to load RPL due to errors\");\n\t\tdelete rpl;\n\t\treturn nullptr;\n\t}\n\t// find TLS section\n\tuint32 tlsStartAddress = 0xFFFFFFFF;\n\tuint32 tlsEndAddress = 0;\n\tfor (uint32 i = 0; i < (uint32)rpl->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\tif ( ((uint32)rpl->sectionTablePtr[i].flags & SHF_TLS) == 0 )\n\t\t\tcontinue;\n\t\tuint32 sectionVirtualAddress = rpl->sectionTablePtr[i].virtualAddress;\n\t\tuint32 sectionSize = rpl->sectionTablePtr[i].sectionSize;\n\t\ttlsStartAddress = std::min(tlsStartAddress, sectionVirtualAddress);\n\t\ttlsEndAddress = std::max(tlsEndAddress, sectionVirtualAddress+sectionSize);\n\t}\n\tif (tlsStartAddress == 0xFFFFFFFF)\n\t{\n\t\ttlsStartAddress = 0;\n\t\ttlsEndAddress = 0;\n\t}\n\trpl->tlsStartAddress = tlsStartAddress;\n\trpl->tlsEndAddress = tlsEndAddress;\n\n\t// add to module list\n\tcemu_assert(rplModuleCount < 256);\n\trplModuleList[rplModuleCount] = rpl;\n\trplModuleCount++;\n\n\t// track dependencies\n\tRPLLoader_incrementModuleDependencyRefs(rpl);\n\n\t// update entrypoint\n\tRPLLoader_UpdateEntrypoint(rpl);\n\treturn rpl;\n}\n\nvoid RPLLoader_FlushMemory(RPLModule* rpl)\n{\n\t// invalidate recompiler cache\n\tPPCRecompiler_invalidateRange(rpl->regionMappingBase_text.GetMPTR(), rpl->regionMappingBase_text.GetMPTR() + rpl->regionSize_text);\n\trpl->heapTrampolineArea.forEachBlock([](void* mem, uint32 size)\n\t{\n\t\tMEMPTR<void> memVirtual = mem;\n\t\tPPCRecompiler_invalidateRange(memVirtual.GetMPTR(), memVirtual.GetMPTR() + size);\n\t});\n}\n\n// resolve relocs and imports of all modules. Or resolve exports\nvoid RPLLoader_LinkSingleModule(RPLModule* rplLoaderContext, bool resolveOnlyExports)\n{\n\t// setup shared import tracking\n\tstd::vector<RPLSharedImportTracking> sharedImportTracking;\n\n\tsharedImportTracking.resize(rplLoaderContext->rplHeader.sectionTableEntryCount - 2);\n\n\tmemset(sharedImportTracking.data(), 0, sizeof(RPLSharedImportTracking) * sharedImportTracking.size());\n\n\tfor (uint32 i = 0; i < (uint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\tif( rplLoaderContext->sectionTablePtr[i].type != (uint32be)SHT_RPL_IMPORTS )\n\t\t\tcontinue;\n\t\tchar* libName = (char*)((uint8*)rplLoaderContext->sectionAddressTable2[i].ptr + 8);\n\t\t// make module name\n\t\tchar _importModuleName[RPL_MODULE_NAME_LENGTH];\n\t\t_RPLLoader_ExtractModuleNameFromPath(_importModuleName, libName);\n\t\t// find in loaded module list\n\t\tstd::string importModuleName{_importModuleName};\n\t\tbool foundModule = false;\n\t\tfor (sint32 f = 0; f < rplModuleCount; f++)\n\t\t{\n\t\t\tif (boost::iequals(rplModuleList[f]->moduleName2, importModuleName))\n\t\t\t{\n\t\t\t\tsharedImportTracking[i].rplLoaderContext = rplModuleList[f];\n\t\t\t\tmemset(sharedImportTracking[i].modulename, 0, sizeof(sharedImportTracking[i].modulename));\n\t\t\t\tstrcpy_s(sharedImportTracking[i].modulename, importModuleName.c_str());\n\t\t\t\tfoundModule = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif( foundModule )\n\t\t\tcontinue;\n\t\t// if not found, we assume it's a HLE lib\n\t\tsharedImportTracking[i].rplLoaderContext = HLE_MODULE_PTR;\n\t\tsharedImportTracking[i].exportSection = nullptr;\n\t\tstrcpy_s(sharedImportTracking[i].modulename, libName);\n\t}\n\n\tif (resolveOnlyExports)\n\t\tRPLLoader_HandleRelocs(rplLoaderContext, sharedImportTracking, 2);\n\telse\n\t\tRPLLoader_HandleRelocs(rplLoaderContext, sharedImportTracking, 0);\n\n\tRPLLoader_FlushMemory(rplLoaderContext);\n}\n\nvoid RPLLoader_LoadSectionDebugSymbols(RPLModule* rplLoaderContext, rplSectionEntryNew_t* section, int symtabSectionIndex)\n{\n\tuint32 sectionSize = section->sectionSize;\n\tuint32 symbolEntrySize = section->ukn24;\n\tif (symbolEntrySize == 0)\n\t\tsymbolEntrySize = 0x10;\n\tcemu_assert(symbolEntrySize == 0x10);\n\tcemu_assert((sectionSize % symbolEntrySize) == 0);\n\tuint32 symbolCount = sectionSize / symbolEntrySize;\n\tcemu_assert(symbolCount >= 2);\n\n\tuint16 sectionCount = rplLoaderContext->rplHeader.sectionTableEntryCount;\n\tuint8* symtabData = (uint8*)rplLoaderContext->sectionAddressTable2[symtabSectionIndex].ptr;\n\n\tuint32 strtabSectionIndex = section->symtabSectionIndex;\n\tuint8* strtabData = (uint8*)rplLoaderContext->sectionAddressTable2[strtabSectionIndex].ptr;\n\n\tfor (uint32 i = 0; i < symbolCount; i++)\n\t{\n\t\tRPLFileSymtabEntry* sym = (RPLFileSymtabEntry*)(symtabData + i * symbolEntrySize);\n\n\t\tuint16 symSectionIndex = sym->sectionIndex;\n\t\tif (symSectionIndex == 0 || symSectionIndex >= sectionCount)\n\t\t\tcontinue;\n\t\tvoid* symbolSectionAddress = rplLoaderContext->sectionAddressTable2[symSectionIndex].ptr;\n\t\tif (symbolSectionAddress == nullptr)\n\t\t\tcontinue;\n\t\trplSectionEntryNew_t* symbolSection = rplLoaderContext->sectionTablePtr + symSectionIndex;\n\t\tif(symbolSection->type == SHT_RPL_EXPORTS || symbolSection->type == SHT_RPL_IMPORTS)\n\t\t\tcontinue; // exports and imports are handled separately\n\n\t\tuint32 symbolOffset = sym->symbolAddress - symbolSection->virtualAddress;\n\n\t\tuint32 nameOffset = sym->ukn00;\n\t\tif (nameOffset > 0)\n\t\t{\n\t\t\tchar* symbolName = (char*)strtabData + nameOffset;\n\t\t\tif (sym->info == 0x12)\n\t\t\t{\n\t\t\t\trplSymbolStorage_store(rplLoaderContext->moduleName2.c_str(), symbolName, sym->symbolAddress);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid RPLLoader_LoadDebugSymbols(RPLModule* rplLoaderContext)\n{\n\tfor (sint32 i = 0; i < (sint32)rplLoaderContext->rplHeader.sectionTableEntryCount; i++)\n\t{\n\t\trplSectionEntryNew_t* section = rplLoaderContext->sectionTablePtr + i;\n\t\tuint32 sectionType = section->type;\n\t\tif (sectionType != SHT_SYMTAB)\n\t\t\tcontinue;\n\t\tRPLLoader_LoadSectionDebugSymbols(rplLoaderContext, section, i);\n\t}\n}\n\nvoid RPLLoader_UnloadModule(RPLDependency* rplDependency, bool skipPPCCalls)\n{\n\t/*\n\t  A note:\n\t  Mario Party 10's mg0408.rpl (minigame Spike Ball Scramble) has a bug where it keeps running code (function 0x02086BCC for example) after RPL unload\n\t  It seems to rely on the RPL loader not zeroing released memory\n\t*/\n\n\tif (rplDependency->rplHLEModule)\n\t{\n\t\tcemu_assert_debug(!rplDependency->rplLoaderContext);\n\t\t// HLE module unload logic is handled by parent functions for now\n\t\treturn;\n\t}\n\tRPLModule* rpl = rplDependency->rplLoaderContext;\n\t// decrease reference counters of all dependencies\n\tRPLLoader_decrementModuleDependencyRefs(rpl);\n\t// save module config for this module in the debugger\n\tg_debuggerDispatcher.NotifyModuleUnloaded(rpl);\n\t// call rpl_entry with reason unload\n\tif (!skipPPCCalls)\n\t{\n\t\tcemu_assert_debug(PPCInterpreter_getCurrentInstance()); // must be running on a CPU emulation thread\n\t\tif (rpl->entrypoint)\n\t\t{\n\t\t\tPPCCoreCallback(rpl->entrypoint, rplDependency->coreinitHandle, 2); // 2 -> unload\n\t\t}\n\t}\n\t// release memory\n\trplLoaderHeap_codeArea2.free(rpl->regionMappingBase_text.GetPtr());\n\trpl->regionMappingBase_text = nullptr;\n\n\t// for some reason freeing the data allocations causes a crash in MP10 on boot\n\tif (!skipPPCCalls)\n\t{\n\t\tRPLLoader_FreeData(rpl, MEMPTR<void>(rpl->regionMappingBase_data).GetPtr());\n\t\trpl->regionMappingBase_data = 0;\n\t\tRPLLoader_FreeData(rpl, MEMPTR<void>(rpl->regionMappingBase_loaderInfo).GetPtr());\n\t\trpl->regionMappingBase_loaderInfo = 0;\n\t}\n\trpl->heapTrampolineArea.releaseAll();\n\n\t// todo - remove from rplSymbolStorage_store\n\n\tif (rpl->sectionTablePtr)\n\t{\n\t\tfree(rpl->sectionTablePtr);\n\t\trpl->sectionTablePtr = nullptr;\n\t}\n\n\t// unload temp region\n\tif (rpl->tempRegionPtr)\n\t{\n\t\tRPLLoader_FreeWorkarea(rpl->tempRegionPtr);\n\t\trpl->tempRegionPtr = nullptr;\n\t}\n\n\t// remove from rpl module list\n\tfor (sint32 i = 0; i < rplModuleCount; i++)\n\t{\n\t\tif (rplModuleList[i] == rpl)\n\t\t{\n\t\t\trplModuleList[i] = rplModuleList[rplModuleCount-1];\n\t\t\trplModuleCount--;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tdelete rpl;\n}\n\nvoid RPLLoader_FixModuleTLSIndex(RPLModule* rplLoaderContext)\n{\n\tsint16 tlsModuleIndex = -1;\n\tfor (auto& dep : rplDependencyList)\n\t{\n\t\tif (boost::iequals(rplLoaderContext->moduleName2, dep->modulename))\n\t\t{\n\t\t\ttlsModuleIndex = dep->tlsModuleIndex;\n\t\t\tbreak;\n\t\t}\n\t}\n\tcemu_assert(tlsModuleIndex != -1);\n\trplLoaderContext->fileInfo.tlsModuleIndex = tlsModuleIndex;\n}\n\nvoid RPLLoader_Link()\n{\n\t// calculate TLS index\n\tfor (sint32 i = 0; i < rplModuleCount; i++)\n\t{\n\t\tif (rplModuleList[i]->isLinked)\n\t\t\tcontinue;\n\t\tRPLLoader_FixModuleTLSIndex(rplModuleList[i]);\n\t}\n\t// resolve relocs\n\tfor (sint32 i = 0; i < rplModuleCount; i++)\n\t{\n\t\tif(rplModuleList[i]->isLinked)\n\t\t\tcontinue;\n\t\tRPLLoader_LinkSingleModule(rplModuleList[i], false);\n\t}\n\t// resolve imports and load debug symbols\n\tfor (sint32 i = 0; i < rplModuleCount; i++)\n\t{\n\t\tif (rplModuleList[i]->isLinked)\n\t\t\tcontinue;\n\t\tRPLLoader_LinkSingleModule(rplModuleList[i], true);\n\t\tRPLLoader_LoadDebugSymbols(rplModuleList[i]);\n\t\trplModuleList[i]->isLinked = true; // mark as linked\n\t\tGraphicPack2::NotifyModuleLoaded(rplModuleList[i]);\n\t\tg_debuggerDispatcher.NotifyModuleLoaded(rplModuleList[i]);\n\t}\n}\n\nuint32 RPLLoader_GetModuleEntrypoint(RPLModule* rplLoaderContext)\n{\n\treturn rplLoaderContext->entrypoint;\n}\n\n// takes a module name without extension, returns true if the RPL module is a known Cafe OS module\nbool RPLLoader_IsKnownCafeOSModule(std::string_view name)\n{\n\tstatic std::unordered_set<std::string> s_systemModules556 = {\n\t\t\t\"avm\",\"camera\",\"coreinit\",\"dc\",\"dmae\",\"drmapp\",\"erreula\",\n\t\t\t\"gx2\",\"h264\",\"lzma920\",\"mic\",\"nfc\",\"nio_prof\",\"nlibcurl\",\n\t\t\t\"nlibnss\",\"nlibnss2\",\"nn_ac\",\"nn_acp\",\"nn_act\",\"nn_aoc\",\"nn_boss\",\n\t\t\t\"nn_ccr\",\"nn_cmpt\",\"nn_dlp\",\"nn_ec\",\"nn_fp\",\"nn_hai\",\"nn_hpad\",\n\t\t\t\"nn_idbe\",\"nn_ndm\",\"nn_nets2\",\"nn_nfp\",\"nn_nim\",\"nn_olv\",\"nn_pdm\",\n\t\t\t\"nn_save\",\"nn_sl\",\"nn_spm\",\"nn_temp\",\"nn_uds\",\"nn_vctl\",\"nsysccr\",\n\t\t\t\"nsyshid\",\"nsyskbd\",\"nsysnet\",\"nsysuhs\",\"nsysuvd\",\"ntag\",\"padscore\",\n\t\t\t\"proc_ui\",\"sndcore2\",\"snduser2\",\"snd_core\",\"snd_user\",\"swkbd\",\"sysapp\",\n\t\t\t\"tcl\",\"tve\",\"uac\",\"uac_rpl\",\"usb_mic\",\"uvc\",\"uvd\",\"vpad\",\"vpadbase\",\n\t\t\t\"zlib125\"};\n\tstd::string nameLower{name};\n\tstd::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), _ansiToLower);\n\treturn s_systemModules556.contains(nameLower);\n}\n\nCOSModule* RPLLoader_GetHLECafeOSModule(std::string_view moduleName)\n{\n\tstd::span<COSModule*> cosModules = GetCOSModules();\n\tfor (auto& module : cosModules)\n\t{\n\t\tif (boost::iequals(module->GetName(), moduleName))\n\t\t\treturn module;\n\t}\n\treturn nullptr;\n}\n\n// increment reference counter for module\nvoid RPLLoader_AddDependency(std::string_view name)\n{\n\tcemu_assert(!name.empty());\n\t// get module name from path\n\tchar moduleName[RPL_MODULE_NAME_LENGTH];\n\t_RPLLoader_ExtractModuleNameFromPath(moduleName, name);\n\t// check if dependency already exists\n\tfor (auto& dep : rplDependencyList)\n\t{\n\t\tif (strcmp(moduleName, dep->modulename) == 0)\n\t\t{\n\t\t\tdep->referenceCount++;\n\t\t\treturn;\n\t\t}\n\t}\n\t// add new entry\n\tRPLDependency* newDependency = new RPLDependency();\n\tstrcpy(newDependency->modulename, moduleName);\n\tnewDependency->referenceCount = 1;\n\tnewDependency->coreinitHandle = rplLoader_currentHandleCounter;\n\tnewDependency->tlsModuleIndex = rplLoader_currentTlsModuleIndex;\n\tnewDependency->isCafeOSModule = RPLLoader_IsKnownCafeOSModule(moduleName);\n\trplLoader_currentTlsModuleIndex++; // todo - delay handle and tls allocation until the module is actually loaded. It may not exist\n\trplLoader_currentHandleCounter++;\n\tif (rplLoader_currentTlsModuleIndex == 0x7FFF)\n\t\tcemuLog_log(LogType::Force, \"RPLLoader: Exhausted TLS module indices pool\");\n\t// convert name to path/filename if it isn't already one\n\tif (name.find_first_of('.') != std::string_view::npos)\n\t{\n\t\tnewDependency->filepath = name;\n\t}\n\telse\n\t{\n\t\tnewDependency->filepath = name;\n\t\tnewDependency->filepath.append(\".rpl\");\n\t}\n\tif (newDependency->filepath.size() >= RPL_MODULE_PATH_LENGTH)\n\t\tcemuLog_log(LogType::Force, \"RPLLoader_AddDependency(): RPL path too long \\\"{}\\\"\", newDependency->filepath);\n\t// if no CafeLibs RPL is present then try to load as a HLE module\n\t// we dont check for isCafeOSModule == true here because the user might want to replace application RPLs in some cases\n\tconst auto cafeLibsFilePath = ActiveSettings::GetUserDataPath(\"cafeLibs/{}\", newDependency->filepath);\n\tstd::error_code ec;\n\tif (!fs::exists(cafeLibsFilePath, ec))\n\t\tnewDependency->rplHLEModule = RPLLoader_GetHLECafeOSModule(moduleName);\n\trplDependencyList.push_back(newDependency);\n}\n\n// decrement reference counter for dependency by module path\nvoid RPLLoader_RemoveDependency(std::string_view name)\n{\n\tcemu_assert(!name.empty());\n\t// get module name from path\n\tchar moduleName[RPL_MODULE_NAME_LENGTH];\n\t_RPLLoader_ExtractModuleNameFromPath(moduleName, name);\n\t// find dependency and decrement ref count\n\tfor (auto& dep : rplDependencyList)\n\t{\n\t\tif (strcmp(moduleName, dep->modulename) == 0)\n\t\t{\n\t\t\tdep->referenceCount--;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nbool RPLLoader_HasDependency(std::string_view name)\n{\n\tchar moduleName[RPL_MODULE_NAME_LENGTH];\n\t_RPLLoader_ExtractModuleNameFromPath(moduleName, name);\n\tfor (const auto& dep : rplDependencyList)\n\t{\n\t\tif (strcmp(moduleName, dep->modulename) == 0)\n\t\t\treturn true;\n\t}\n\treturn false;\n}\n\n// decrement reference counter for dependency by module handle\nvoid RPLLoader_RemoveDependency(uint32 handle)\n{\n\tfor (auto& dep : rplDependencyList)\n\t{\n\t\tif (dep->coreinitHandle == handle)\n\t\t{\n\t\t\tcemu_assert_debug(dep->referenceCount != 0);\n\t\t\tif(dep->referenceCount > 0)\n\t\t\t\tdep->referenceCount--;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nRPLDependency* RPLLoader_GetDependencyByRPLModule(RPLModule* rpl)\n{\n\tcemu_assert_debug(rpl);\n\tfor (auto& dep : rplDependencyList)\n\t{\n\t\tif (dep->rplLoaderContext == rpl)\n\t\t\treturn dep;\n\t}\n\tcemu_assert_suspicious(); // should never happen. Modules get loaded via dependency tracking so a dependency entry needs to exist\n\treturn nullptr;\n}\n\nuint32 RPLLoader_GetHandleByModuleName(const char* name)\n{\n\t// get module name from path\n\tchar moduleName[RPL_MODULE_NAME_LENGTH];\n\t_RPLLoader_ExtractModuleNameFromPath(moduleName, name);\n\t// search for existing dependency\n\tfor (auto& dep : rplDependencyList)\n\t{\n\t\tif (strcmp(moduleName, dep->modulename) == 0)\n\t\t{\n\t\t\tcemu_assert_debug(dep->loadAttempted);\n\t\t\tif (!dep->isCafeOSModule && !dep->rplLoaderContext)\n\t\t\t\treturn RPL_INVALID_HANDLE; // module not found\n\t\t\treturn dep->coreinitHandle;\n\t\t}\n\t}\n\treturn RPL_INVALID_HANDLE;\n}\n\nuint32 RPLLoader_GetMaxTLSModuleIndex()\n{\n\treturn rplLoader_currentTlsModuleIndex - 1;\n}\n\nbool RPLLoader_GetTLSDataByTLSIndex(sint16 tlsModuleIndex, uint8** tlsData, sint32* tlsSize)\n{\n\tRPLModule* rplLoaderContext = nullptr;\n\tfor (auto& dep : rplDependencyList)\n\t{\n\t\tif (dep->tlsModuleIndex == tlsModuleIndex)\n\t\t{\n\t\t\trplLoaderContext = dep->rplLoaderContext;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (rplLoaderContext == nullptr)\n\t\treturn false;\n\tcemu_assert(rplLoaderContext->tlsStartAddress != 0);\n\tuint32 tlsDataSize = rplLoaderContext->tlsEndAddress - rplLoaderContext->tlsStartAddress;\n\tcemu_assert_debug(tlsDataSize < 0x10000); // check for suspiciously large TLS area\n\t*tlsData = (uint8*)memory_getPointerFromVirtualOffset(rplLoaderContext->tlsStartAddress);\n\t*tlsSize = tlsDataSize;\n\treturn true;\n}\n\nbool RPLLoader_LoadFromVirtualPath(RPLDependency* dependency, std::string_view filePath)\n{\n\tuint32 rplSize = 0;\n\tuint8* rplData = fsc_extractFile(std::string(filePath).c_str(), &rplSize);\n\tif (rplData)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Loading: {}\", filePath);\n\t\tdependency->rplLoaderContext = RPLLoader_LoadFromMemory(rplData, rplSize, filePath);\n\t\tfree(rplData);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nstd::span<COSModule*> GetCOSModules();\n\nvoid RPLLoader_LoadDependency(RPLDependency* dependency)\n{\n\t// if its a HLE module then notify that it has been mapped\n\tif (dependency->rplHLEModule)\n\t{\n\t\tdependency->rplHLEModule->RPLMapped();\n\t\t// load chained dependencies\n\t\t// this is necessary for something like GX2.rpl which uses TCL.rpl functions\n\t\tauto depList = dependency->rplHLEModule->GetDependencies();\n\t\tfor (const auto& dep : depList)\n\t\t\tRPLLoader_AddDependency(dep);\n\t\treturn;\n\t}\n\t// check if module is already loaded\n\tfor (sint32 i = 0; i < rplModuleCount; i++)\n\t{\n\t\tif(!boost::iequals(rplModuleList[i]->moduleName2, dependency->modulename))\n\t\t\tcontinue;\n\t\tdependency->rplLoaderContext = rplModuleList[i];\n\t\treturn;\n\t}\n\t//char filePath[RPL_MODULE_PATH_LENGTH];\n\tstd::string rplPath;\n\t// check if path is absolute\n\tif (!dependency->filepath.empty() && dependency->filepath.front() == '/')\n\t{\n\t\trplPath = dependency->filepath;\n\t\tRPLLoader_LoadFromVirtualPath(dependency, rplPath);\n\t\treturn;\n\t}\n\t// attempt to load rpl from code directory of current title\n\trplPath =  \"/internal/current_title/code/\";\n\trplPath.append(dependency->filepath);\n\t// except if it is blacklisted\n\tbool isBlacklisted = false;\n\tif (boost::iequals(dependency->filepath, \"erreula.rpl\"))\n\t{\n\t\tif (fsc_doesFileExist(rplPath.c_str()))\n\t\t\tisBlacklisted = true;\n\t}\n\tif (isBlacklisted)\n\t\tcemuLog_log(LogType::Force, fmt::format(\"Game tried to load \\\"{}\\\" but it is blacklisted (using Cemu's implementation instead)\", rplPath));\n\telse if (RPLLoader_LoadFromVirtualPath(dependency, rplPath))\n\t\treturn;\n\t// attempt to load rpl from Cemu's /cafeLibs/ directory\n\tif (ActiveSettings::LoadSharedLibrariesEnabled())\n\t{\n\t\tconst auto cafeLibsFilePath = ActiveSettings::GetUserDataPath(\"cafeLibs/{}\", dependency->filepath);\n\t\tauto fileData = FileStream::LoadIntoMemory(cafeLibsFilePath);\n\t\tif (fileData)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Loading RPL: /cafeLibs/{}\", dependency->filepath);\n\t\t\tdependency->rplLoaderContext = RPLLoader_LoadFromMemory(fileData->data(), fileData->size(), dependency->filepath);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n// loads and unloads modules based on the current dependency list\nvoid RPLLoader_UpdateDependencies()\n{\n\tbool repeat = true;\n\twhile (repeat)\n\t{\n\t\trepeat = false;\n\t\tfor(auto idx = 0; idx<rplDependencyList.size(); )\n\t\t{\n\t\t\tauto dependency = rplDependencyList[idx];\n\t\t\t// debug_printf(\"DEP 0x%02x %s\\n\", dependency->referenceCount, dependency->modulename);\n\t\t\tif(dependency->referenceCount == 0)\n\t\t\t{\n\t\t\t\t// unload RPLs\n\t\t\t\t// todo - should we let HLE modules know if they are being unloaded?\n\t\t\t\tif (dependency->rplLoaderContext)\n\t\t\t\t{\n\t\t\t\t\tRPLLoader_UnloadModule(dependency, false);\n\t\t\t\t\tdependency->rplLoaderContext = nullptr;\n\t\t\t\t}\n\t\t\t\telse if (dependency->rplHLEModule)\n\t\t\t\t{\n\t\t\t\t\tdependency->rplHLEModule->rpl_entry(dependency->coreinitHandle, coreinit::RplEntryReason::Unloaded);\n\t\t\t\t\tdependency->rplHLEModule->RPLUnmapped();\n\t\t\t\t\t// untrack chained dependencies\n\t\t\t\t\tauto depList = dependency->rplHLEModule->GetDependencies();\n\t\t\t\t\tfor (const auto& dep : depList)\n\t\t\t\t\t\tRPLLoader_RemoveDependency(dep);\n\t\t\t\t}\n\t\t\t\t// remove from dependency list\n\t\t\t\trplDependencyList.erase(rplDependencyList.begin()+idx);\n\t\t\t\tidx--;\n\t\t\t\trepeat = true; // unload can effect reference count of other dependencies\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (!dependency->loadAttempted)\n\t\t\t{\n\t\t\t\t// load\n\t\t\t\tdependency->loadAttempted = true;\n\t\t\t\tRPLLoader_LoadDependency(dependency);\n\t\t\t\trepeat = true;\n\t\t\t\tidx++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tidx++;\n\t\t}\n\t}\n\tRPLLoader_Link();\n}\n\nvoid RPLLoader_LoadCoreinit()\n{\n\tRPLLoader_AddDependency(\"coreinit\");\n\tfor (auto& dep : rplDependencyList)\n\t{\n\t\tif (strcmp(dep->modulename, \"coreinit\") == 0)\n\t\t{\n\t\t\tdep->loadAttempted = true;\n\t\t\tRPLLoader_LoadDependency(dep);\n\t\t\treturn;\n\t\t}\n\t}\n\tcemu_assert_suspicious();\n}\n\nvoid RPLLoader_SetMainModule(RPLModule* rplLoaderContext)\n{\n\trplLoaderContext->entrypointCalled = true;\n\trplLoader_mainModule = rplLoaderContext;\n}\n\nuint32 RPLLoader_GetMainModuleHandle()\n{\n\tfor (auto& dep : rplDependencyList)\n\t{\n\t\tif (dep->rplLoaderContext == rplLoader_mainModule)\n\t\t{\n\t\t\treturn dep->coreinitHandle;\n\t\t}\n\t}\n\tcemu_assert(false);\n\treturn 0;\n}\n\nRPLModule* RPLLoader_FindModuleByCodeAddr(uint32 addr)\n{\n\tfor (sint32 i = 0; i < rplModuleCount; i++)\n\t{\n\t\tuint32 startAddr = rplModuleList[i]->regionMappingBase_text.GetMPTR();\n\t\tuint32 endAddr = rplModuleList[i]->regionMappingBase_text.GetMPTR() + rplModuleList[i]->regionSize_text;\n\t\tif (addr >= startAddr && addr < endAddr)\n\t\t\treturn rplModuleList[i];\n\t}\n\treturn nullptr;\n}\n\nRPLModule* RPLLoader_FindModuleByDataAddr(uint32 addr)\n{\n\tfor (sint32 i = 0; i < rplModuleCount; i++)\n\t{\n\t\t// data\n\t\tuint32 startAddr = rplModuleList[i]->regionMappingBase_data;\n\t\tuint32 endAddr = rplModuleList[i]->regionMappingBase_data + rplModuleList[i]->regionSize_data;\n\t\tif (addr >= startAddr && addr < endAddr)\n\t\t\treturn rplModuleList[i];\n\t\t// loaderinfo\n\t\tstartAddr = rplModuleList[i]->regionMappingBase_loaderInfo;\n\t\tendAddr = rplModuleList[i]->regionMappingBase_loaderInfo + rplModuleList[i]->regionSize_loaderInfo;\n\t\tif (addr >= startAddr && addr < endAddr)\n\t\t\treturn rplModuleList[i];\n\t}\n\treturn nullptr;\n}\n\nRPLModule* RPLLoader_FindModuleByName(std::string module)\n{\n\tfor (sint32 i = 0; i < rplModuleCount; i++)\n\t{\n\t\tif (rplModuleList[i]->moduleName2 == module) return rplModuleList[i];\n\t}\n\treturn nullptr;\n}\n\nvoid RPLLoader_CallEntrypoints()\n{\n\t// for HLE modules we need to check the dependency list\n\tfor (auto& dependency : rplDependencyList)\n\t{\n\t\tif (!dependency->rplHLEModule)\n\t\t\tcontinue;\n\t\tif (dependency->hleEntrypointCalled)\n\t\t\tcontinue;\n\t\tdependency->rplHLEModule->rpl_entry(dependency->coreinitHandle, coreinit::RplEntryReason::Loaded);\n\t\tdependency->hleEntrypointCalled = true;\n\t}\n\t// iterate loaded RPL modules\n\tfor (sint32 i = 0; i < rplModuleCount; i++)\n\t{\n\t\tif (rplModuleList[i]->entrypointCalled)\n\t\t\tcontinue;\n\t\tuint32 moduleHandle = RPLLoader_GetHandleByModuleName(rplModuleList[i]->moduleName2.c_str());\n\t\tMPTR entryPoint = RPLLoader_GetModuleEntrypoint(rplModuleList[i]);\n\t\tPPCCoreCallback(entryPoint, moduleHandle, 1); // 1 -> load, 2 -> unload\n\t\trplModuleList[i]->entrypointCalled = true;\n\t}\n}\n\n// calls the entrypoint of coreinit and marks it as called so that RPLLoader_CallEntrypoints() wont call it again later\nvoid RPLLoader_CallCoreinitEntrypoint()\n{\n\t// for HLE modules we need to check the dependency list\n\tfor (auto& dependency : rplDependencyList)\n\t{\n\t\tif (strcmp(dependency->modulename, \"coreinit\") != 0)\n\t\t\tcontinue;\n\t\tif (!dependency->rplHLEModule)\n\t\t\tcontinue;\n\t\tif (dependency->hleEntrypointCalled)\n\t\t\tcontinue;\n\t\tdependency->rplHLEModule->rpl_entry(dependency->coreinitHandle, coreinit::RplEntryReason::Loaded);\n\t\tdependency->hleEntrypointCalled = true;\n\t\treturn;\n\t}\n\tcemu_assert_unimplemented(); // coreinit.rpl present in cafelibs? We currently do not support native coreinit and no thread context exists yet to do a PPC call\n}\n\nvoid RPLLoader_NotifyControlPassedToApplication()\n{\n\trplLoader_applicationHasMemoryControl = true;\n}\n\nuint32 RPLLoader_FindModuleOrHLEExport(uint32 moduleHandle, bool isData, const char* exportName)\n{\n\t// find dependency from handle\n\tRPLModule* rplLoaderContext = nullptr;\n\tRPLDependency* dependency = nullptr;\n\tfor (auto& dep : rplDependencyList)\n\t{\n\t\tif (dep->coreinitHandle == moduleHandle)\n\t\t{\n\t\t\trplLoaderContext = dep->rplLoaderContext;\n\t\t\tdependency = dep;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tuint32 exportResult = 0;\n\tif (rplLoaderContext)\n\t{\n\t\texportResult = RPLLoader_FindModuleExport(rplLoaderContext, isData, exportName);\n\t}\n\telse\n\t{\n\t\t// attempt to find HLE export\n\t\tif (isData)\n\t\t{\n\t\t\tMPTR weakExportAddr = osLib_getPointer(dependency->modulename, exportName);\n\t\t\tcemu_assert_debug(weakExportAddr != 0xFFFFFFFF);\n\t\t\texportResult = weakExportAddr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\texportResult = rpl_mapHLEImport(rplLoaderContext, dependency->modulename, exportName, true);\n\t\t}\n\t}\n\n\treturn exportResult;\n}\n\nuint32 RPLLoader_GetSDA1Base()\n{\n\tcemu_assert_debug(rplModuleCount > 0); // this should not be called before the main executable was loaded\n\treturn rplLoader_sdataAddr;\n}\n\nuint32 RPLLoader_GetSDA2Base()\n{\n\tcemu_assert_debug(rplModuleCount > 0);\n\treturn rplLoader_sdata2Addr;\n}\n\nRPLModule** RPLLoader_GetModuleList()\n{\n\treturn rplModuleList;\n}\n\nsint32 RPLLoader_GetModuleCount()\n{\n\treturn rplModuleCount;\n}\n\ntemplate<typename TAddr, typename TSize>\nclass SimpleHeap\n{\n\tstruct allocEntry_t\n\t{\n\t\tTAddr start;\n\t\tTAddr end;\n\t\tallocEntry_t(TAddr start, TAddr end) : start(start), end(end) {};\n\t};\n\npublic:\n\tSimpleHeap(TAddr baseAddress, TSize size) : m_base(baseAddress), m_size(size)\n\t{\n\n\t}\n\n\tTAddr alloc(TSize size, TSize alignment)\n\t{\n\t\tcemu_assert_debug(alignment != 0);\n\t\tTAddr allocBase = m_base;\n\t\tallocBase = (allocBase + alignment - 1)&~(alignment-1);\n\t\twhile (true)\n\t\t{\n\t\t\tbool hasCollision = false;\n\t\t\tfor (auto& itr : list_allocatedEntries)\n\t\t\t{\n\t\t\t\tif (allocBase < itr.end && (allocBase + size) >= itr.start)\n\t\t\t\t{\n\t\t\t\t\tallocBase = itr.end;\n\t\t\t\t\tallocBase = (allocBase + alignment - 1)&~(alignment - 1);\n\t\t\t\t\thasCollision = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(hasCollision == false)\n\t\t\t\tbreak;\n\t\t}\n\t\tif ((allocBase + size) > (m_base + m_size))\n\t\t\treturn 0;\n\t\tlist_allocatedEntries.emplace_back(allocBase, allocBase + size);\n\t\treturn allocBase;\n\t}\n\n\tvoid free(TAddr addr)\n\t{\n\t\tfor (sint32 i = 0; i < list_allocatedEntries.size(); i++)\n\t\t{\n\t\t\tif (list_allocatedEntries[i].start == addr)\n\t\t\t{\n\t\t\t\tlist_allocatedEntries.erase(list_allocatedEntries.begin() + i);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tcemu_assert(false);\n\t\treturn;\n\t}\n\nprivate:\n\tTAddr  m_base;\n\tTSize  m_size;\n\tstd::vector<allocEntry_t> list_allocatedEntries;\n};\n\nSimpleHeap<uint32, uint32> heapCodeCaveArea(MEMORY_CODECAVEAREA_ADDR, MEMORY_CODECAVEAREA_SIZE);\n\nMEMPTR<void> RPLLoader_AllocateCodeCaveMem(uint32 alignment, uint32 size)\n{\n\tuint32 addr = heapCodeCaveArea.alloc(size, 256);\n\treturn MEMPTR<void>{addr};\n}\n\nvoid RPLLoader_ReleaseCodeCaveMem(MEMPTR<void> addr)\n{\n\theapCodeCaveArea.free(addr.GetMPTR());\n}\n\nvoid RPLLoader_UnloadAll()\n{\n\t// unload all RPL modules\n\twhile (rplModuleCount > 0)\n\t{\n\t\tRPLDependency* dep = RPLLoader_GetDependencyByRPLModule(rplModuleList[0]);\n\t\tRPLLoader_UnloadModule(dep, true);\n\t}\n\t// notify every remaining HLE module its unloaded and unmapped\n\t// and do it in reverse order so that coreinit comes last\n\tRPLLoader_RemoveDependency(\"coreinit\"); // undo manual ref count from RPLLoader_LoadCoreinit()\n\tfor (sint32 i = (sint32)rplDependencyList.size()-1; i>=0; i--)\n\t{\n\t\tRPLDependency* dependency = rplDependencyList[i];\n\t\tcemu_assert_debug(dependency->referenceCount >= 0); // sanity check for ref count\n\t\tif (!dependency->rplHLEModule)\n\t\t\tcontinue;\n\t\tif (dependency->referenceCount <= 0)\n\t\t\tcontinue;\n\t\tcemu_assert_debug(dependency->hleEntrypointCalled); // entrypoint should have been called\n\t\tdependency->rplHLEModule->rpl_entry(dependency->coreinitHandle, coreinit::RplEntryReason::Unloaded);\n\t\tdependency->rplHLEModule->RPLUnmapped();\n\t}\n\trplDependencyList.clear();\n\t// unload all remaining symbols\n\trplSymbolStorage_unloadAll();\n\t// free all code imports\n\tg_heapTrampolineArea.releaseAll();\n\tlist_mappedFunctionImports.clear();\n\tg_map_callableExports.clear();\n\trplLoader_applicationHasMemoryControl = false;\n\trplLoader_maxCodeAddress = 0;\n\trplLoader_currentDataAllocatorAddr = 0x10000000;\n\trplLoader_currentTLSModuleIndex = 1;\n\trplLoader_sdataAddr = MPTR_NULL;\n\trplLoader_sdata2Addr = MPTR_NULL;\n\trplLoader_mainModule = nullptr;\n}\n"
  },
  {
    "path": "src/Cafe/OS/RPL/rpl.h",
    "content": "#pragma once\n\nstruct RPLModule;\n\n#define RPL_INVALID_HANDLE\t\t0xFFFFFFFF\n\nvoid RPLLoader_InitState();\nvoid RPLLoader_UnloadAll();\n\nuint8* RPLLoader_AllocateTrampolineCodeSpace(sint32 size);\n\nMPTR RPLLoader_AllocateCodeSpace(uint32 size, uint32 alignment);\n\nuint32 RPLLoader_GetMaxCodeOffset();\nuint32 RPLLoader_GetDataAllocatorAddr();\n\nRPLModule* RPLLoader_LoadFromMemory(uint8* rplData, sint32 size, std::string_view name);\nuint32 rpl_mapHLEImport(RPLModule* rplLoaderContext, const char* rplName, const char* funcName, bool functionMustExist);\nvoid RPLLoader_Link();\n\nMPTR RPLLoader_FindRPLExport(RPLModule* rplLoaderContext, const char* symbolName, bool isData);\nuint32 RPLLoader_GetModuleEntrypoint(RPLModule* rplLoaderContext);\n\nvoid RPLLoader_SetMainModule(RPLModule* rplLoaderContext);\nuint32 RPLLoader_GetMainModuleHandle();\n\nvoid RPLLoader_CallEntrypoints();\nvoid RPLLoader_CallCoreinitEntrypoint();\nvoid RPLLoader_NotifyControlPassedToApplication();\n\nvoid RPLLoader_AddDependency(std::string_view name);\nvoid RPLLoader_RemoveDependency(uint32 handle);\nbool RPLLoader_HasDependency(std::string_view name);\nvoid RPLLoader_UpdateDependencies();\n\nvoid RPLLoader_LoadCoreinit();\n\nuint32 RPLLoader_GetHandleByModuleName(const char* name);\nuint32 RPLLoader_GetMaxTLSModuleIndex();\nbool RPLLoader_GetTLSDataByTLSIndex(sint16 tlsModuleIndex, uint8** tlsData, sint32* tlsSize);\n\nuint32 RPLLoader_FindModuleOrHLEExport(uint32 moduleHandle, bool isData, const char* exportName);\n\nuint32 RPLLoader_GetSDA1Base();\nuint32 RPLLoader_GetSDA2Base();\n\nsint32 RPLLoader_GetModuleCount();\nRPLModule** RPLLoader_GetModuleList();\n\nMEMPTR<void> RPLLoader_AllocateCodeCaveMem(uint32 alignment, uint32 size);\nvoid RPLLoader_ReleaseCodeCaveMem(MEMPTR<void> addr);\n\n// exports\n\nuint32 RPLLoader_MakePPCCallable(void(*ppcCallableExport)(struct PPCInterpreter_t* hCPU));\n\n// elf loader\n\nuint32 ELF_LoadFromMemory(uint8* elfData, sint32 size, const char* name);"
  },
  {
    "path": "src/Cafe/OS/RPL/rpl_debug_symbols.cpp",
    "content": "#include \"Cafe/OS/RPL/rpl_debug_symbols.h\"\n\nstd::map<MPTR, rplDebugSymbolBase*> map_DebugSymbols;\n\nvoid rplDebugSymbol_createComment(MPTR address, const wchar_t* comment)\n{\n\tauto new_comment = new rplDebugSymbolComment();\n\tnew_comment->type = RplDebugSymbolComment;\n\tnew_comment->comment = comment;\n\tmap_DebugSymbols[address] = new_comment;\n}\n\nrplDebugSymbolBase* rplDebugSymbol_getForAddress(MPTR address)\n{\n\treturn map_DebugSymbols[address];\n}\n\nconst std::map<MPTR, rplDebugSymbolBase*>& rplDebugSymbol_getSymbols()\n{\n\treturn map_DebugSymbols;\n}"
  },
  {
    "path": "src/Cafe/OS/RPL/rpl_debug_symbols.h",
    "content": "#pragma once\n#include <map>\n\nenum RplDebugSymbolType : uint8\n{\n\tRplDebugSymbolComment = 0,\n};\n\nstruct rplDebugSymbolBase\n{\n\tRplDebugSymbolType type;\n\trplDebugSymbolBase* next;\n};\n\nstruct rplDebugSymbolComment : rplDebugSymbolBase\n{\n\tstd::wstring comment;\n};\n\n\nvoid rplDebugSymbol_createComment(MPTR address, const wchar_t* comment);\nrplDebugSymbolBase* rplDebugSymbol_getForAddress(MPTR address);\nconst std::map<MPTR, rplDebugSymbolBase*>&  rplDebugSymbol_getSymbols();"
  },
  {
    "path": "src/Cafe/OS/RPL/rpl_structs.h",
    "content": "#pragma once\n\n#include \"util/ChunkedHeap/ChunkedHeap.h\"\n\n#define RPL_MODULE_NAME_LENGTH\t64\n#define RPL_MODULE_PATH_LENGTH\t256\n\n// types\n#define SHT_RPL_EXPORTS\t\t\t(0x80000001)\n#define SHT_RPL_IMPORTS\t\t\t(0x80000002)\n#define SHT_RPL_CRCS\t\t\t(0x80000003)\n#define SHT_RPL_FILEINFO\t\t(0x80000004)\n\n#define SHT_PROGBITS\t\t\t(0x00000001)\n#define SHT_SYMTAB\t\t\t\t(0x00000002)\n#define SHT_STRTAB\t\t\t\t(0x00000003)\n#define SHT_RELA\t\t\t\t(0x00000004)\n#define SHT_HASH\t\t\t\t(0x00000005)\n#define SHT_DYNAMIC\t\t\t\t(0x00000006)\n#define SHT_NOTE\t\t\t\t(0x00000007)\n#define SHT_NOBITS\t\t\t\t(0x00000008) // this section contains no data\n#define SHT_REL\t\t\t\t\t(0x00000009) \n#define SHT_SHLIB\t\t\t\t(0x0000000A) \n#define SHT_DYNSYM\t\t\t\t(0x0000000B)\n\n// flags\n#define SHF_EXECUTE\t\t\t\t0x00000004\n#define SHF_RPL_COMPRESSED\t\t0x08000000\n#define SHF_TLS\t\t\t\t\t0x04000000\n\n// relocs\n#define RPL_RELOC_ADDR32\t1\n#define RPL_RELOC_LO16\t\t4\n#define RPL_RELOC_HI16\t\t5\n#define RPL_RELOC_HA16\t\t6\n#define RPL_RELOC_REL24\t\t10 \n#define RPL_RELOC_REL14\t\t11\n\n#define R_PPC_DTPMOD32\t\t68\n#define R_PPC_DTPREL32\t\t78\n\n#define R_PPC_REL16_HA\t\t251\n#define R_PPC_REL16_HI\t\t252\n#define R_PPC_REL16_LO\t\t253\n\n#define HLE_MODULE_PTR\t\t((RPLModule*)-1)\n\ntypedef struct\n{\n\t/* +0x00 */ uint32be relocOffset;\n\t/* +0x04 */ uint32be symbolIndexAndType;\n\t/* +0x08 */ uint32be relocAddend;\n}rplRelocNew_t;\n\ntypedef struct\n{\n\t/* +0x00 */ uint32be nameOffset;\n\t/* +0x04 */ uint32be type;\n\t/* +0x08 */ uint32be flags;\n\t/* +0x0C */ uint32be virtualAddress;\n\t/* +0x10 */ uint32be fileOffset;\n\t/* +0x14 */ uint32be sectionSize;\n\t/* +0x18 */ uint32be symtabSectionIndex;\n\t/* +0x1C */ uint32be relocTargetSectionIndex;\n\t/* +0x20 */ uint32be alignment;\n\t/* +0x24 */ uint32be ukn24; // for symtab: Size of each symbol entry\n}rplSectionEntryNew_t;\n\ntypedef struct\n{\n\t/* +0x00 */ uint32be magic1;\n\t/* +0x04 */ uint8    version04; // probably version?\n\t/* +0x05 */ uint8    ukn05; // probably version?\n\t/* +0x06 */ uint8    ukn06; // probably version?\n\t/* +0x07 */ uint8    magic2_0; // part of second magic\n\t/* +0x08 */ uint8    magic2_1; // part of second magic\n\t/* +0x09 */ uint8    ukn09;\n\t/* +0x0A */ uint8    ukn0A;\n\t/* +0x0B */ uint8    ukn0B;\n\t/* +0x0C */ uint32be dataRegionSize;\n\t/* +0x10 */ uint8    ukn10;\n\t/* +0x11 */ uint8    ukn11;\n\t/* +0x12 */ uint16be ukn12;\n\t/* +0x14 */ uint32be ukn14;\n\t/* +0x18 */ uint32be entrypoint;\n\t/* +0x1C */ uint32be ukn1C;\n\t/* +0x20 */ uint32be sectionTableOffset;\n\t/* +0x24 */ uint32be ukn24;\n\t/* +0x28 */ uint16be ukn28;\n\t/* +0x2A */ uint16be programHeaderTableEntrySize;\n\t/* +0x2C */ uint16be programHeaderTableEntryCount;\n\t/* +0x2E */ uint16be sectionTableEntrySize;\n\t/* +0x30 */ uint16be sectionTableEntryCount;\n\t/* +0x32 */ uint16be nameSectionIndex;\n}rplHeaderNew_t;\n\nstatic_assert(offsetof(rplHeaderNew_t, dataRegionSize) == 0xC);\nstatic_assert(offsetof(rplHeaderNew_t, programHeaderTableEntrySize) == 0x2A);\n\n\ntypedef struct\n{\n\t/* +0x00 */ uint32be fileInfoMagic; // always 0xCAFE0402\n\t/* +0x04 */ uint32be textRegionSize; // text region size\n\t/* +0x08 */ uint32be ukn08; // base align text\n\t/* +0x0C */ uint32be dataRegionSize; // size of data sections\n\t/* +0x10 */ uint32be baseAlign; // base align data?\n\t/* +0x14 */ uint32be ukn14;\n\t/* +0x18 */ uint32be ukn18;\n\t/* +0x1C */ uint32be ukn1C;\n\t/* +0x20 */ uint32be trampolineAdjustment;\n\t/* +0x24 */ uint32be sdataBase1;\n\t/* +0x28 */ uint32be sdataBase2;\n\t/* +0x2C */ uint32be ukn2C;\n\t/* +0x30 */ uint32be ukn30;\n\t/* +0x34 */ uint32be flags;\n\t/* +0x38 */ uint32be ukn38;\n\t/* +0x3C */ uint32be ukn3C;\n\t/* +0x40 */ uint32be minimumToolkitVersion;\n\t/* +0x44 */ uint32be ukn44;\n\t/* +0x48 */ uint32be ukn48;\n\t/* +0x4C */ uint32be ukn4C;\n\t/* +0x50 */ uint32be ukn50;\n\t/* +0x54 */ uint32be ukn54;\n\t/* +0x58 */ sint16be tlsModuleIndex;\n}RPLFileInfoData;\n\nstatic_assert(offsetof(RPLFileInfoData, tlsModuleIndex) == 0x58);\n\n\ntypedef struct\n{\n\t//uint32 address;\n\tvoid* ptr;\n}rplSectionAddressEntry_t;\n\ntypedef struct\n{\n\tuint32be virtualOffset;\n\tuint32be nameOffset;\n}rplExportTableEntry_t;\n\nstruct RPLModule\n{\n\tuint32 ukn00; // pointer to shared memory region? (0xEFE01000)\n\tuint32 ukn04; // related to text region size?\n\tuint32 padding14;\n\tuint32 padding18;\n\trplHeaderNew_t rplHeader;\n\trplSectionEntryNew_t* sectionTablePtr; // copy of section table\n\n\tuint32 entrypoint;\n\n\tMPTR textRegionTemp; // temporary memory for text section?\n\n\tMEMPTR<void> regionMappingBase_text; // base destination address for text region\n\tMPTR regionMappingBase_data; // base destination address for data region\n\tMPTR regionMappingBase_loaderInfo; // base destination address for loaderInfo region\n\tuint8* tempRegionPtr;\n\tuint32 tempRegionAllocSize;\n\n\tuint32 exportDCount;\n\trplExportTableEntry_t* exportDDataPtr;\n\tuint32 exportFCount;\n\trplExportTableEntry_t* exportFDataPtr;\n\n\tstd::string moduleName2;\n\t\n\tstd::vector<rplSectionAddressEntry_t> sectionAddressTable2;\n\n\tuint32 tlsStartAddress;\n\tuint32 tlsEndAddress;\n\tuint32 regionSize_text;\n\tuint32 regionSize_data;\n\tuint32 regionSize_loaderInfo;\n\n\tuint32 patchCRC; // Cemuhook style module crc for patches.txt\n\n\t// trampoline management\n\tChunkedFlatAllocator<16 * 1024> heapTrampolineArea;\n\tstd::unordered_map<MPTR, MPTR> trampolineMap;\n\n\t// section data\n\tstd::vector<uint8> sectionData_fileInfo;\n\tstd::vector<uint8> sectionData_crc;\n\n\t// parsed FILEINFO\n\tstruct \n\t{\n\t\tuint32 textRegionSize; // size of region containing all text sections\n\t\t//uint32 ukn08; // base align text?\n\t\tuint32 dataRegionSize; // size of region containing all data sections\n\t\tuint32 baseAlign;\n\t\tuint32 ukn14;\n\t\tuint32 trampolineAdjustment;\n\t\tuint32 ukn4C;\n\t\tsint16 tlsModuleIndex;\n\n\t\tuint32 sdataBase1;\n\t\tuint32 sdataBase2;\n\t\t\n\t\tuint32 flags;\n\t}fileInfo;\n\t// parsed CRC\n\tstd::vector<uint32> crcTable;\n\n\tuint32 GetSectionCRC(size_t sectionIndex) const\n\t{\n\t\tif (sectionIndex >= crcTable.size())\n\t\t\treturn 0;\n\t\treturn crcTable[sectionIndex];\n\t}\n\t\n\tbool IsRPX() const\n\t{\n\t    return fileInfo.flags & 2;\n\t}\n\n\t// state\n\tbool isLinked; // set to true if _linkModule was called on this module\n\tbool entrypointCalled; // set if entrypoint was called\n\n\t// allocator\t\n\tbetype<MPTR> funcAlloc;\n\tbetype<MPTR> funcFree;\n\n\t// replaces rplData ptr\n\tstd::span<uint8> RPLRawData;\n\n\tbool debugSectionLoadMask[128] = { false };\n\tbool hasError{ false };\n\n};\n\nstruct RPLDependency\n{\n\tchar modulename[RPL_MODULE_NAME_LENGTH];\n\tstd::string filepath;\n\tbool loadAttempted;\n\tbool hleEntrypointCalled{false};\n\tbool isCafeOSModule; // name is a known Cafe OS system RPL\n\tRPLModule* rplLoaderContext{}; // context of loaded module, can be nullptr for HLE COS modules\n\tclass COSModule* rplHLEModule{}; // set if this is a HLE module\n\tsint32 referenceCount;\n\tuint32 coreinitHandle; // fake handle for coreinit\n\tsint16 tlsModuleIndex; // tls module index assigned to this dependency\n};\n\nRPLModule* RPLLoader_FindModuleByCodeAddr(uint32 addr);\nRPLModule* RPLLoader_FindModuleByDataAddr(uint32 addr);\nRPLModule* RPLLoader_FindModuleByName(std::string module);\n"
  },
  {
    "path": "src/Cafe/OS/RPL/rpl_symbol_storage.cpp",
    "content": "#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/RPL/rpl_symbol_storage.h\"\n\nstruct rplSymbolLib_t\n{\n\tchar* libName;\n\trplSymbolLib_t* next;\n};\n\nstruct  \n{\n\trplSymbolLib_t* libs;\n\tstd::mutex m_symbolStorageMutex;\n\tstd::unordered_map<uint32, RPLStoredSymbol*> map_symbolByAddress;\n\t// allocator for strings\n\tchar* strAllocatorBlock;\n\tsint32 strAllocatorOffset;\n\tstd::vector<void*> list_strAllocatedBlocks;\n}rplSymbolStorage = { 0 };\n\n#define STR_ALLOC_BLOCK_SIZE\t(128*1024) // allocate 128KB blocks at once\n\nchar* rplSymbolStorage_allocDupString(const char* str)\n{\n\tsint32 len = (sint32)strlen(str);\n\tif (rplSymbolStorage.strAllocatorBlock == nullptr || (rplSymbolStorage.strAllocatorOffset + len + 1) >= STR_ALLOC_BLOCK_SIZE)\n\t{\n\t\t// allocate new block\n\t\trplSymbolStorage.strAllocatorBlock = (char*)malloc(STR_ALLOC_BLOCK_SIZE);\n\t\trplSymbolStorage.strAllocatorOffset = 0;\n\t\trplSymbolStorage.list_strAllocatedBlocks.emplace_back(rplSymbolStorage.strAllocatorBlock);\n\t}\n\tcemu_assert_debug((rplSymbolStorage.strAllocatorOffset + len + 1) <= STR_ALLOC_BLOCK_SIZE);\n\tchar* allocatedStr = rplSymbolStorage.strAllocatorBlock + rplSymbolStorage.strAllocatorOffset;\n\trplSymbolStorage.strAllocatorOffset += len + 1;\n\tstrcpy(allocatedStr, str);\n\treturn allocatedStr;\n}\n\nchar* rplSymbolStorage_storeLibname(const char* libName)\n{\n\tif (rplSymbolStorage.libs == NULL)\n\t{\n\t\trplSymbolLib_t* libEntry = new rplSymbolLib_t();\n\t\tlibEntry->libName = rplSymbolStorage_allocDupString(libName);\n\t\tlibEntry->next = NULL;\n\t\trplSymbolStorage.libs = libEntry;\n\t\treturn libEntry->libName;\n\t}\n\trplSymbolLib_t* libItr = rplSymbolStorage.libs;\n\twhile (libItr)\n\t{\n\t\tif (boost::iequals(libItr->libName, libName))\n\t\t\treturn libItr->libName;\n\t\t// next\n\t\tlibItr = libItr->next;\n\t}\n\t// create new entry\n\trplSymbolLib_t* libEntry = new rplSymbolLib_t();\n\tlibEntry->libName = rplSymbolStorage_allocDupString(libName);\n\tlibEntry->next = rplSymbolStorage.libs;\n\trplSymbolStorage.libs = libEntry;\n\treturn libEntry->libName;\n}\n\nRPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address)\n{\n\tstd::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);\n\tchar* libNameStorage = rplSymbolStorage_storeLibname(libName);\n\tchar* symbolNameStorage = rplSymbolStorage_allocDupString(symbolName);\n\tRPLStoredSymbol* storedSymbol = new RPLStoredSymbol();\n\tstoredSymbol->address = address;\n\tstoredSymbol->libName = libNameStorage;\n\tstoredSymbol->symbolName = symbolNameStorage;\n\tstoredSymbol->flags = 0;\n\trplSymbolStorage.map_symbolByAddress[address] = storedSymbol;\n\treturn storedSymbol;\n}\n\nRPLStoredSymbol* rplSymbolStorage_getByAddress(MPTR address)\n{\n\tstd::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);\n\treturn rplSymbolStorage.map_symbolByAddress[address];\n}\n\nRPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address)\n{\n    // highly inefficient but doesn't matter for now\n    std::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);\n    for(uint32 i=0; i<4096; i++)\n    {\n        RPLStoredSymbol* symbol = rplSymbolStorage.map_symbolByAddress[address];\n        if(symbol)\n            return symbol;\n        address -= 4;\n    }\n    return nullptr;\n}\n\nvoid rplSymbolStorage_remove(RPLStoredSymbol* storedSymbol)\n{\n\tstd::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);\n\tif (rplSymbolStorage.map_symbolByAddress[storedSymbol->address] == storedSymbol)\n\t\trplSymbolStorage.map_symbolByAddress[storedSymbol->address] = nullptr;\n\tdelete storedSymbol;\n}\n\nvoid rplSymbolStorage_removeRange(MPTR address, sint32 length)\n{\n\twhile (length > 0)\n\t{\n\t\tRPLStoredSymbol* symbol = rplSymbolStorage_getByAddress(address);\n\t\tif (symbol)\n\t\t\trplSymbolStorage_remove(symbol);\n\t\taddress += 4;\n\t\tlength -= 4;\n\t}\n}\n\nvoid rplSymbolStorage_createJumpProxySymbol(MPTR jumpAddress, MPTR destAddress)\n{\n\tRPLStoredSymbol* destSymbol = rplSymbolStorage_getByAddress(destAddress);\n\tif (destSymbol)\n\t\trplSymbolStorage_store((char*)destSymbol->libName, (char*)destSymbol->symbolName, jumpAddress);\n}\n\nstd::unordered_map<uint32, RPLStoredSymbol*>& rplSymbolStorage_lockSymbolMap()\n{\n\trplSymbolStorage.m_symbolStorageMutex.lock();\n\treturn rplSymbolStorage.map_symbolByAddress;\n}\n\nvoid rplSymbolStorage_unlockSymbolMap()\n{\n\trplSymbolStorage.m_symbolStorageMutex.unlock();\n}\n\nvoid rplSymbolStorage_init()\n{\n\tcemu_assert_debug(rplSymbolStorage.map_symbolByAddress.empty());\n\tcemu_assert_debug(rplSymbolStorage.strAllocatorBlock == nullptr);\n}\n\nvoid rplSymbolStorage_unloadAll()\n{\n\t// free symbols\n\tfor (auto& it : rplSymbolStorage.map_symbolByAddress)\n\t\tdelete it.second;\n\trplSymbolStorage.map_symbolByAddress.clear();\n\t// free libs\n\trplSymbolLib_t* lib = rplSymbolStorage.libs;\n\twhile (lib)\n\t{\n\t\trplSymbolLib_t* next = lib->next;\n\t\tdelete lib;\n\t\tlib = next;\n\t}\n\trplSymbolStorage.libs = nullptr;\n\t// free strings\n\tfor (auto it : rplSymbolStorage.list_strAllocatedBlocks)\n\t\tfree(it);\n    rplSymbolStorage.list_strAllocatedBlocks.clear();\n\trplSymbolStorage.strAllocatorBlock = nullptr;\n\trplSymbolStorage.strAllocatorOffset = 0;\n}\n"
  },
  {
    "path": "src/Cafe/OS/RPL/rpl_symbol_storage.h",
    "content": "struct RPLStoredSymbol\n{\n\tMPTR address;\n\tvoid* libName;\n\tvoid* symbolName;\n\tuint32 flags;\n};\n\nvoid rplSymbolStorage_init();\nvoid rplSymbolStorage_unloadAll();\nRPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolName, MPTR address);\nvoid rplSymbolStorage_remove(RPLStoredSymbol* storedSymbol);\nvoid rplSymbolStorage_removeRange(MPTR address, sint32 length);\nRPLStoredSymbol* rplSymbolStorage_getByAddress(MPTR address);\nRPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address);\nvoid rplSymbolStorage_createJumpProxySymbol(MPTR jumpAddress, MPTR destAddress);\n\nstd::unordered_map<uint32, RPLStoredSymbol*>& rplSymbolStorage_lockSymbolMap();\nvoid rplSymbolStorage_unlockSymbolMap();"
  },
  {
    "path": "src/Cafe/OS/common/OSCommon.cpp",
    "content": "#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/OS/libs/proc_ui/proc_ui.h\"\n#include \"Cafe/OS/libs/nsysnet/nsysnet.h\"\n#include \"Cafe/OS/libs/nlibnss/nlibnss.h\"\n#include \"Cafe/OS/libs/nlibcurl/nlibcurl.h\"\n#include \"Cafe/OS/libs/nn_nfp/nn_nfp.h\"\n#include \"Cafe/OS/libs/nn_act/nn_act.h\"\n#include \"Cafe/OS/libs/nn_acp/nn_acp.h\"\n#include \"Cafe/OS/libs/nn_ac/nn_ac.h\"\n#include \"Cafe/OS/libs/nn_uds/nn_uds.h\"\n#include \"Cafe/OS/libs/nn_nim/nn_nim.h\"\n#include \"Cafe/OS/libs/nn_ndm/nn_ndm.h\"\n#include \"Cafe/OS/libs/nn_spm/nn_spm.h\"\n#include \"Cafe/OS/libs/nn_ec/nn_ec.h\"\n#include \"Cafe/OS/libs/nn_boss/nn_boss.h\"\n#include \"Cafe/OS/libs/nn_sl/nn_sl.h\"\n#include \"Cafe/OS/libs/nn_fp/nn_fp.h\"\n#include \"Cafe/OS/libs/nn_olv/nn_olv.h\"\n#include \"Cafe/OS/libs/nn_idbe/nn_idbe.h\"\n#include \"Cafe/OS/libs/nn_save/nn_save.h\"\n#include \"Cafe/OS/libs/erreula/erreula.h\"\n#include \"Cafe/OS/libs/sysapp/sysapp.h\"\n#include \"Cafe/OS/libs/dmae/dmae.h\"\n#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"Cafe/OS/libs/vpad/vpad.h\"\n#include \"Cafe/OS/libs/nsyskbd/nsyskbd.h\"\n#include \"Cafe/OS/libs/nsyshid/nsyshid.h\"\n#include \"Cafe/OS/libs/snd_user/snd_user.h\"\n#include \"Cafe/OS/libs/zlib125/zlib125.h\"\n#include \"Cafe/OS/libs/padscore/padscore.h\"\n#include \"Cafe/OS/libs/camera/camera.h\"\n#include \"../libs/swkbd/swkbd.h\"\n\nstruct osFunctionEntry_t\n{\n\tuint32 libHashA;\n\tuint32 libHashB;\n\tuint32 funcHashA;\n\tuint32 funcHashB;\n\tstd::string name;\n\tHLEIDX hleFunc;\n\n\tosFunctionEntry_t(uint32 libHashA, uint32 libHashB, uint32 funcHashA, uint32 funcHashB, std::string_view name, HLEIDX hleFunc) :\n\t\tlibHashA(libHashA), libHashB(libHashB), funcHashA(funcHashA), funcHashB(funcHashB), name(name), hleFunc(hleFunc) {};\n};\n\ntypedef struct\n{\n\tuint32 libHashA;\n\tuint32 libHashB;\n\tuint32 funcHashA;\n\tuint32 funcHashB;\n\tuint32 vPtr;\n}osPointerEntry_t;\n\nstd::vector<osFunctionEntry_t>* s_osFunctionTable;\nstd::vector<osPointerEntry_t> osDataTable;\n\nvoid osLib_generateHashFromName(const char* name, uint32* hashA, uint32* hashB)\n{\n\tuint32 h1 = 0x688BA2BA;\n\tuint32 h2 = 0xF64A71D5;\n\twhile( *name )\n\t{\n\t\tuint32 c = (uint32)*name;\n\t\th1 += c;\n\t\th1 = (h1<<3)|((h1>>29));\n\t\th2 ^= c;\n\t\th2 = (h2<<7)|((h2>>25));\n\t\th1 += h2;\n\t\th2 += c;\n\t\th2 = (h2<<3)|((h2>>29));\n\t\tname++;\n\t}\n\t*hashA = h1;\n\t*hashB = h2;\n}\n\nvoid osLib_addFunctionInternal(const char* libraryName, const char* functionName, void(*osFunction)(PPCInterpreter_t* hCPU))\n{\n\tif (!s_osFunctionTable)\n\t\ts_osFunctionTable = new std::vector<osFunctionEntry_t>(); // replace with static allocation + constinit once we have C++20 available\n\t// calculate hash\n\tuint32 libHashA, libHashB;\n\tuint32 funcHashA, funcHashB;\n\tosLib_generateHashFromName(libraryName, &libHashA, &libHashB);\n\tosLib_generateHashFromName(functionName, &funcHashA, &funcHashB);\n\tstd::string hleName = fmt::format(\"{}.{}\", libraryName, functionName);\n\t// if entry already exists, update it\n\tfor (auto& it : *s_osFunctionTable)\n\t{\n\t\tif (it.libHashA == libHashA &&\n\t\t\tit.libHashB == libHashB &&\n\t\t\tit.funcHashA == funcHashA &&\n\t\t\tit.funcHashB == funcHashB)\n\t\t{\n\t\t\tit.hleFunc = PPCInterpreter_registerHLECall(osFunction, hleName);\n\t\t\treturn;\n\t\t}\n\t}\n\ts_osFunctionTable->emplace_back(libHashA, libHashB, funcHashA, funcHashB, hleName, PPCInterpreter_registerHLECall(osFunction, hleName));\n}\n\nextern \"C\" DLLEXPORT void osLib_registerHLEFunction(const char* libraryName, const char* functionName, void(*osFunction)(PPCInterpreter_t * hCPU))\n{\n\tosLib_addFunctionInternal(libraryName, functionName, osFunction);\n}\n\nsint32 osLib_getFunctionIndex(const char* libraryName, const char* functionName)\n{\n\tuint32 libHashA, libHashB;\n\tuint32 funcHashA, funcHashB;\n\tosLib_generateHashFromName(libraryName, &libHashA, &libHashB);\n\tosLib_generateHashFromName(functionName, &funcHashA, &funcHashB);\n\tfor (auto& it : *s_osFunctionTable)\n\t{\n\t\tif (it.libHashA == libHashA &&\n\t\t\tit.libHashB == libHashB &&\n\t\t\tit.funcHashA == funcHashA &&\n\t\t\tit.funcHashB == funcHashB)\n\t\t{\n\t\t\treturn it.hleFunc;\n\t\t}\n\t}\n\treturn -1;\n}\n\nvoid osLib_addVirtualPointer(const char* libraryName, const char* functionName, uint32 vPtr)\n{\n\t// calculate hash\n\tuint32 libHashA, libHashB;\n\tuint32 funcHashA, funcHashB;\n\tosLib_generateHashFromName(libraryName, &libHashA, &libHashB);\n\tosLib_generateHashFromName(functionName, &funcHashA, &funcHashB);\n\t// if entry already exists, update it\n\tfor (auto& it : osDataTable)\n\t{\n\t\tif (it.libHashA == libHashA &&\n\t\t\tit.libHashB == libHashB &&\n\t\t\tit.funcHashA == funcHashA &&\n\t\t\tit.funcHashB == funcHashB)\n\t\t{\n\t\t\tit.vPtr = vPtr;\n\t\t\treturn;\n\t\t}\n\t}\n\t// add entry\n\tauto writeIndex = osDataTable.size();\n\tosDataTable.resize(osDataTable.size() + 1);\n\tosDataTable[writeIndex].libHashA = libHashA;\n\tosDataTable[writeIndex].libHashB = libHashB;\n\tosDataTable[writeIndex].funcHashA = funcHashA;\n\tosDataTable[writeIndex].funcHashB = funcHashB;\n\tosDataTable[writeIndex].vPtr = vPtr;\n}\n\nuint32 osLib_getPointer(const char* libraryName, const char* functionName)\n{\n\tuint32 libHashA, libHashB;\n\tuint32 funcHashA, funcHashB;\n\tosLib_generateHashFromName(libraryName, &libHashA, &libHashB);\n\tosLib_generateHashFromName(functionName, &funcHashA, &funcHashB);\n\tfor (auto& it : osDataTable)\n\t{\n\t\tif (it.libHashA == libHashA &&\n\t\t\tit.libHashB == libHashB &&\n\t\t\tit.funcHashA == funcHashA &&\n\t\t\tit.funcHashB == funcHashB)\n\t\t{\n\t\t\treturn it.vPtr;\n\t\t}\n\t}\n\treturn 0xFFFFFFFF;\n}\n\nvoid osLib_returnFromFunction(PPCInterpreter_t* hCPU, uint32 returnValue)\n{\n\thCPU->gpr[3] = returnValue;\n\thCPU->instructionPointer = hCPU->spr.LR;\n}\n\nvoid osLib_returnFromFunction64(PPCInterpreter_t* hCPU, uint64 returnValue64)\n{\n\thCPU->gpr[3] = (returnValue64>>32)&0xFFFFFFFF;\n\thCPU->gpr[4] = (returnValue64>>0)&0xFFFFFFFF;\n\thCPU->instructionPointer = hCPU->spr.LR;\n}\n"
  },
  {
    "path": "src/Cafe/OS/common/OSCommon.h",
    "content": "#pragma once\n\nstruct PPCInterpreter_t;\n\n#define OSLIB_FUNCTIONTABLE_TYPE_FUNCTION\t(1)\n#define OSLIB_FUNCTIONTABLE_TYPE_POINTER\t(2)\n\nvoid osLib_generateHashFromName(const char* name, uint32* hashA, uint32* hashB);\nsint32 osLib_getFunctionIndex(const char* libraryName, const char* functionName);\nuint32 osLib_getPointer(const char* libraryName, const char* functionName);\n\nvoid osLib_addFunctionInternal(const char* libraryName, const char* functionName, void(*osFunction)(PPCInterpreter_t* hCPU));\n#define osLib_addFunction(__p1, __p2, __p3) osLib_addFunctionInternal((const char*)__p1, __p2, __p3)\nvoid osLib_addVirtualPointer(const char* libraryName, const char* functionName, uint32 vPtr);\n\nvoid osLib_returnFromFunction(PPCInterpreter_t* hCPU, uint32 returnValue);\nvoid osLib_returnFromFunction64(PPCInterpreter_t* hCPU, uint64 returnValue64);\n\n// libs\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n\n// from coreinit but more convenient to have this in the common header\nnamespace coreinit\n{\n\tenum class RplEntryReason\n\t{\n\t\tLoaded = 1,\n\t\tUnloaded = 2,\n\t};\n}\n\n// utility functions\n#include \"Cafe/OS/common/OSUtil.h\"\n\n// va_list\nstruct ppc_va_list\n{\n\tuint8be gprIndex;\n\tuint8be fprIndex;\n\tuint8be _padding2[2];\n\tMEMPTR<uint8be> overflow_arg_area;\n\tMEMPTR<uint8be> reg_save_area;\n};\nstatic_assert(sizeof(ppc_va_list) == 0xC);\n\nstruct ppc_va_list_reg_storage\n{\n\tuint32be gpr_save_area[8]; // 32 bytes, r3 to r10\n\tfloat64be fpr_save_area[8]; // 64 bytes, f1 to f8\n\tppc_va_list vargs;\n\tuint32be padding;\n};\nstatic_assert(sizeof(ppc_va_list_reg_storage) == 0x70);\n\n// Equivalent of va_start for PPC HLE functions. Must be called before any StackAllocator<> definitions\n#define ppc_define_va_list(__gprIndex, __fprIndex) \\\n\tMPTR vaOriginalR1 = PPCInterpreter_getCurrentInstance()->gpr[1]; \\\n\tStackAllocator<ppc_va_list_reg_storage> va_list_storage; \\\n\tfor(int i=3; i<=10; i++) va_list_storage->gpr_save_area[i-3] = PPCInterpreter_getCurrentInstance()->gpr[i]; \\\n\tfor(int i=1; i<=8; i++) va_list_storage->fpr_save_area[i-1] = PPCInterpreter_getCurrentInstance()->fpr[i].fp0; \\\n\tva_list_storage->vargs.gprIndex = __gprIndex; \\\n\tva_list_storage->vargs.fprIndex = __fprIndex; \\\n\tva_list_storage->vargs.reg_save_area = (uint8be*)&va_list_storage; \\\n\tva_list_storage->vargs.overflow_arg_area = {vaOriginalR1 + 8}; \\\n\tppc_va_list& vargs = va_list_storage->vargs;\n\nenum class ppc_va_type\n{\n\tINT32 = 1,\n\tINT64 = 2,\n\tFLOAT_OR_DOUBLE = 3,\n};\n\nstatic void* _ppc_va_arg(ppc_va_list* vargs, ppc_va_type argType)\n{\n\tvoid* r;\n\tswitch ( argType )\n\t{\n\tdefault:\n\t\tcemu_assert_suspicious();\n\tcase ppc_va_type::INT32:\n\t\tif ( vargs[0].gprIndex < 8u )\n\t\t{\n\t\t\tr = &vargs->reg_save_area[4 * vargs->gprIndex];\n\t\t\tvargs->gprIndex++;\n\t\t\treturn r;\n\t\t}\n\t\tr = vargs->overflow_arg_area;\n\t\tvargs->overflow_arg_area += 4;\n\t\treturn r;\n\tcase ppc_va_type::INT64:\n\t\tif ( (vargs->gprIndex & 1) != 0 )\n\t\t\tvargs->gprIndex++;\n\t\tif ( vargs->gprIndex < 8 )\n\t\t{\n\t\t\tr = &vargs->reg_save_area[4 * vargs->gprIndex];\n\t\t\tvargs->gprIndex += 2;\n\t\t\treturn r;\n\t\t}\n\t\tvargs->overflow_arg_area = {(vargs->overflow_arg_area.GetMPTR()+7) & 0xFFFFFFF8};\n\t\tr = vargs->overflow_arg_area;\n\t\tvargs->overflow_arg_area += 8;\n\t\treturn r;\n\tcase ppc_va_type::FLOAT_OR_DOUBLE:\n\t\tif ( vargs->fprIndex < 8 )\n\t\t{\n\t\t\tr = &vargs->reg_save_area[0x20 + 8 * vargs->fprIndex];\n\t\t\tvargs->fprIndex++;\n\t\t\treturn r;\n\t\t}\n\t\tvargs->overflow_arg_area = {(vargs->overflow_arg_area.GetMPTR()+7) & 0xFFFFFFF8};\n\t\tr = vargs->overflow_arg_area;\n\t\tvargs->overflow_arg_area += 8;\n\t\treturn r;\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/common/OSUtil.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/HW/MMU/MMU.h\"\n\n#include <fmt/ostream.h>\n#include <fmt/compile.h>\n#include <fmt/ranges.h>\n\nclass cafeExportParamWrapper\n{\npublic:\n\ttemplate <typename T>\n\tstatic void getParamWrapper(PPCInterpreter_t* hCPU, int& gprIndex, int& fprIndex, T& v)\n\t{\n\t\tif constexpr (std::is_pointer_v<T>)\n\t\t{\n\t\t\tuint32be addr;\n\t\t\tif (gprIndex >= 8)\n\t\t\t\taddr = memory_readU32(hCPU->gpr[1] + 8 + (gprIndex - 8) * 4);\n\t\t\telse\n\t\t\t\taddr = hCPU->gpr[3 + gprIndex];\n\n\t\t\tusing TPtr = std::remove_pointer_t<T>;\n\t\t\tv = MEMPTR<TPtr>(addr).GetPtr();\n\t\t\tgprIndex++;\n\t\t}\n\t\telse if constexpr (std::is_base_of_v<MEMPTRBase, T>)\n\t\t{\n\t\t\tuint32be addr;\n\t\t\tif (gprIndex >= 8)\n\t\t\t\taddr = memory_readU32(hCPU->gpr[1] + 8 + (gprIndex - 8) * 4);\n\t\t\telse\n\t\t\t\taddr = hCPU->gpr[3 + gprIndex];\n\n\t\t\tv = addr.value();\n\t\t\tgprIndex++;\n\t\t}\n\t\telse if constexpr (std::is_enum_v<T>)\n\t\t{\n\t\t\tusing TEnum = std::underlying_type_t<T>;\n\t\t\tgetParamWrapper<TEnum>(hCPU, gprIndex, fprIndex, (TEnum&)v);\n\t\t}\n\t\telse if constexpr (std::is_integral_v<T>)\n\t\t{\n\t\t\tif constexpr (sizeof(T) == sizeof(uint64))\n\t\t\t{\n\t\t\t\tgprIndex = (gprIndex + 1)&~1;\n\t\t\t\tif (gprIndex >= 8)\n\t\t\t\t\tv = (T)memory_readU64(hCPU->gpr[1] + 8 + (gprIndex - 8) * 4);\n\t\t\t\telse\n\t\t\t\t\tv = (T)(((uint64)hCPU->gpr[3 + gprIndex]) << 32) | ((uint64)hCPU->gpr[3 + gprIndex + 1]);\n\n\t\t\t\tgprIndex += 2;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (gprIndex >= 8)\n\t\t\t\t\tv = (T)memory_readU32(hCPU->gpr[1] + 8 + (gprIndex - 8) * 4);\n\t\t\t\telse\n\t\t\t\t\tv = (T)hCPU->gpr[3 + gprIndex];\n\n\t\t\t\tgprIndex++;\n\t\t\t}\n\t\t}\n\t\telse if constexpr (std::is_floating_point_v<T>)\n\t\t{\n\t\t\tv = (T)hCPU->fpr[1 + fprIndex].fpr;\n\t\t\tfprIndex++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t}\n\n\ttemplate<typename T>\n\tstatic void setReturnResult(PPCInterpreter_t* hCPU, T r)\n\t{\n\t\tif constexpr (std::is_pointer_v<T>)\n\t\t{\n\t\t\thCPU->gpr[3] = MEMPTR(r).GetMPTR();\n\t\t}\n\t\telse if constexpr (std::is_reference_v<T>)\n\t\t{\n\t\t\thCPU->gpr[3] = MEMPTR(&r).GetMPTR();\n\t\t}\n\t\telse if constexpr (std::is_enum_v<T>)\n\t\t{\n\t\t\tusing TEnum = std::underlying_type_t<T>;\n\t\t\tsetReturnResult<TEnum>(hCPU, (TEnum)r);\n\t\t}\n\t\telse if constexpr (std::is_integral_v<T>)\n\t\t{\n\t\t\tif constexpr(sizeof(T) == 8)\n\t\t\t{\n\t\t\t\tconst auto t = static_cast<uint64>(r);\n\t\t\t\thCPU->gpr[3] = (uint32)(t >> 32); // high\n\t\t\t\thCPU->gpr[4] = (uint32)(t); // low\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\thCPU->gpr[3] = (uint32)r;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t\t//static_assert(false);\n\t\t}\n\t}\n\n\ttemplate<typename T>\n\tstatic auto getFormatResult(T r)\n\t{\n\t\tif constexpr (std::is_pointer_v<T>)\n\t\t\treturn MEMPTR(r).GetMPTR();\n\t\telse if constexpr (std::is_enum_v<T>)\n\t\t\treturn static_cast<std::underlying_type_t<T>>(r);\n\t\telse if constexpr(!std::is_fundamental_v<T>)\n\t\t\treturn MEMPTR(&r).GetMPTR();\n\t\telse \n\t\t\treturn r;\n\t}\n};\n\ntemplate<typename T>\nT cafeExportGetParamWrapper(PPCInterpreter_t* hCPU, int& gprIndex, int& fprIndex)\n{\n\tT v;\n\tcafeExportParamWrapper::getParamWrapper(hCPU, gprIndex, fprIndex, v);\n\treturn v;\n}\n\ntemplate <typename R, typename ... Args>\nstatic std::tuple<Args...> cafeExportBuildArgTuple(PPCInterpreter_t* hCPU, R(fn)(Args...))\n{\n\tint gprIndex = 0;\n\tint fprIndex = 0;\n\treturn std::tuple<Args...>{ cafeExportGetParamWrapper<Args>(hCPU, gprIndex, fprIndex)... };\n}\n\ntemplate<typename T>\nT cafeExportGetFormatParamWrapper(PPCInterpreter_t* hCPU, int& gprIndex, int& fprIndex)\n{\n\tT v;\n\tcafeExportParamWrapper::getParamWrapper(hCPU, gprIndex, fprIndex, v);\n\t// if T is char* or const char*, return \"null\" instead of nullptr since newer fmtlib would throw otherwise\n\tif constexpr (std::is_same_v<T, char*> || std::is_same_v<T, const char*>)\n\t\treturn v ? v : (T)\"null\";\n\treturn v;\n}\n\ntemplate<typename T>\nusing _CAFE_FORMAT_ARG = std::conditional_t<std::is_pointer_v<T>,\n\tstd::conditional_t<std::is_same_v<T, char*> || std::is_same_v<T, const char*>, T, MEMPTR<T>>, T>;\n\ntemplate <typename R, typename... Args>\nstatic auto cafeExportBuildFormatTuple(PPCInterpreter_t* hCPU, R(fn)(Args...))\n{\n\tint gprIndex = 0;\n\tint fprIndex = 0;\n\treturn std::tuple<_CAFE_FORMAT_ARG<Args>...>{\n\t\tcafeExportGetFormatParamWrapper<_CAFE_FORMAT_ARG<Args>>(hCPU, gprIndex, fprIndex)...\n\t};\n}\n\ntemplate<auto fn, typename TNames, LogType TLogType>\nvoid cafeExportCallWrapper(PPCInterpreter_t* hCPU)\n{\n\tauto tup = cafeExportBuildArgTuple(hCPU, fn);\n\tbool shouldLog = false;\n\tif (cemuLog_isLoggingEnabled(TLogType))\n\t{\n\t\tconst auto format_tup = cafeExportBuildFormatTuple(hCPU, fn);\n\t\tif(cemuLog_advancedPPCLoggingEnabled())\n\t\t{\n\t\t\tMPTR threadMPTR = memory_getVirtualOffsetFromPointer(coreinit::OSGetCurrentThread());\n\t\t\tif constexpr (std::tuple_size_v<decltype(format_tup)> > 0)\n\t\t\t\tshouldLog = cemuLog_log(TLogType, \"{}.{}{} # LR: {:#x} | Thread: {:#x}\", TNames::GetLib(), TNames::GetFunc(), format_tup, hCPU->spr.LR, threadMPTR);\n\t\t\telse\n\t\t\t\tshouldLog = cemuLog_log(TLogType, \"{}.{}() # LR: {:#x} | Thread: {:#x}\", TNames::GetLib(), TNames::GetFunc(), hCPU->spr.LR, threadMPTR);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif constexpr (std::tuple_size_v<decltype(format_tup)> > 0)\n\t\t\t{\n\t\t\t\tshouldLog = cemuLog_log(TLogType, \"{}.{}{}\", TNames::GetLib(), TNames::GetFunc(), format_tup);\n\t\t\t}\n\t\t\telse\n\t\t\t\tshouldLog = cemuLog_log(TLogType, \"{}.{}()\", TNames::GetLib(), TNames::GetFunc());\n\t\t}\n\t}\n\n\tif constexpr (!std::is_void_v<decltype(std::apply(fn, tup))>)\n\t{\n\t\t// has non-void return type\n\t\tdecltype(auto) result = std::apply(fn, tup);\n\t\tcafeExportParamWrapper::setReturnResult<decltype(std::apply(fn, tup))>(hCPU, result);\n\t\tif(shouldLog)\n\t\t\tcemuLog_log(TLogType, \"\\t\\t{}.{} -> {}\", TNames::GetLib(), TNames::GetFunc(), cafeExportParamWrapper::getFormatResult(result));\n\t}\n\telse\n\t{\n\t\t// return type is void\n\t\tstd::apply(fn, tup);\n\t}\n\t// return from func\n\thCPU->instructionPointer = hCPU->spr.LR;\n}\n\nvoid osLib_addFunctionInternal(const char* libraryName, const char* functionName, void(*osFunction)(PPCInterpreter_t* hCPU));\n\ntemplate<auto fn, typename TNames, LogType TLogType>\nvoid cafeExportMakeWrapper(const char* libname, const char* funcname)\n{\n\tosLib_addFunctionInternal(libname, funcname, &cafeExportCallWrapper<fn, TNames, TLogType>);\n}\n\n#define cafeExportRegister(__libname, __func, __logtype) \\\n\t { \\\n\t\tstruct StringWrapper { \\\n\t\t\tstatic const char* GetLib() { return __libname; }; \\\n\t\t\tstatic const char* GetFunc() { return #__func; }; \\\n\t\t}; \\\n\t\tcafeExportMakeWrapper<__func, StringWrapper, __logtype>(__libname, # __func);\\\n\t}\n\n#define cafeExportRegisterFunc(__func, __libname, __funcname, __logtype) \\\n\t {\\\n\t\tstruct StringWrapper { \\\n\t\t\tstatic const char* GetLib() { return __libname; }; \\\n\t\t\tstatic const char* GetFunc() { return __funcname; }; \\\n\t\t}; \\\n\t\tcafeExportMakeWrapper<__func, StringWrapper, __logtype>(__libname, __funcname);\\\n\t}\n\ntemplate<auto fn>\nMPTR makeCallableExport()\n{\n\treturn PPCInterpreter_makeCallableExportDepr(&cafeExportCallWrapper<fn, \"CALLABLE_EXPORT\">);\n}\n\nvoid osLib_addVirtualPointer(const char* libraryName, const char* functionName, uint32 vPtr);\n"
  },
  {
    "path": "src/Cafe/OS/common/PPCConcurrentQueue.h",
    "content": "#pragma once\n\n#include <mutex>\n#include <condition_variable>\n#include <queue>\n\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n\ntemplate <typename T>\nclass PPCConcurrentQueue\n{\npublic:\n\tPPCConcurrentQueue() = default;\n\tPPCConcurrentQueue(const PPCConcurrentQueue&) = delete;\n\tPPCConcurrentQueue& operator=(const PPCConcurrentQueue&) = delete;\n\n\tvoid push(const T& item, OSThread_t* thread)\n\t{\n\t\t//if(thread == nullptr)\n\t\t//\tthread = coreinitThread_getCurrentThread(ppcInterpreterCurrentInstance);\n\t\t//OSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\t\t//cemu_assert_debug(thread == nullptr || currentThread == thread);\n\n\t\t// cemuLog_logDebug(LogType::Force, \"push suspend count: {}\", _swapEndianU32(thread->suspend) - m_suspendCount);\n\n\t\t//__OSLockScheduler();\n\n\t\t__OSLockScheduler();\n\t\tm_queue.push(item);\n\t\tcoreinit::__OSResumeThreadInternal(thread, 1);\n\t\t__OSUnlockScheduler();\n\n\t\t//__OSUnlockScheduler();\n\n\t\t//m_prevSuspendCount = _swapEndianU32(thread->suspend) - m_suspendCount;\n\t\t//coreinit_resumeThread(thread, _swapEndianU32(thread->suspend));\n\t}\n\n\tT pop(OSThread_t* thread = nullptr)\n\t{\n\t\t//if (thread == nullptr)\n\t\t//\tthread = coreinitThread_getCurrentThread(ppcInterpreterCurrentInstance);\n\n\t\tOSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\t\tcemu_assert_debug(thread == nullptr || currentThread == thread);\n\n\t\t//thread = coreinitThread_getCurrentThread(ppcInterpreterCurrentInstance);\n\n\t\t// cemuLog_logDebug(LogType::Force, \"pop suspend count: {}\", _swapEndianU32(thread->suspend) + m_suspendCount);\n\n\t\t__OSLockScheduler();\n\t\tif (m_queue.empty())\n\t\t\tcoreinit::__OSSuspendThreadInternal(thread);\n\t\tauto val = m_queue.front();\n\t\tm_queue.pop();\n\t\t__OSUnlockScheduler();\n\n\t\t//coreinit_suspendThread(thread, m_suspendCount + m_prevSuspendCount);\n\t\t//m_prevSuspendCount = 0;\n\t\t//PPCCore_switchToScheduler();\n\n\t\treturn val;\n\t}\nprivate:\n\t//const int m_suspendCount = 8000;\n\tstd::queue<T> m_queue;\n\t//std::atomic<uint32> m_prevSuspendCount;\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/TCL/TCL.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/TCL/TCL.h\"\n\n#include \"HW/Latte/Core/LattePM4.h\"\n\nnamespace TCL\n{\n\tSysAllocator<coreinit::OSEvent> s_updateRetirementEvent;\n\tuint64 s_currentRetireMarker = 0;\n\n\tstruct TCLStatePPC // mapped into PPC space\n\t{\n\t\tuint64be gpuRetireMarker; // written by GPU\n\t};\n\n\tSysAllocator<TCLStatePPC> s_tclStatePPC;\n\n\t// called from GPU for timestamp EOP event\n\tvoid TCLGPUNotifyNewRetirementTimestamp()\n\t{\n\t\t// gpuRetireMarker is updated via event eop command\n\t\t__OSLockScheduler();\n\t\tcoreinit::OSSignalEventAllInternal(s_updateRetirementEvent.GetPtr());\n\t\t__OSUnlockScheduler();\n\t}\n\n\tint TCLTimestamp(TCLTimestampId id, uint64be* timestampOut)\n\t{\n\t\tif (id == TCLTimestampId::TIMESTAMP_LAST_BUFFER_RETIRED)\n\t\t{\n\t\t\tMEMPTR<uint32> b;\n\t\t\t// this is the timestamp of the last buffer that was retired by the GPU\n\t\t\tstdx::atomic_ref<uint64be> retireTimestamp(s_tclStatePPC->gpuRetireMarker);\n\t\t\t*timestampOut = retireTimestamp.load();\n\t\t\treturn 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"TCLTimestamp(): Unsupported timestamp ID {}\", (uint32)id);\n\t\t\t*timestampOut = 0;\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tint TCLWaitTimestamp(TCLTimestampId id, uint64 waitTs, uint64 timeout)\n\t{\n\t\tif (id == TCLTimestampId::TIMESTAMP_LAST_BUFFER_RETIRED)\n\t\t{\n\t\t\twhile ( true )\n\t\t\t{\n\t\t\t\tstdx::atomic_ref<uint64be> retireTimestamp(s_tclStatePPC->gpuRetireMarker);\n\t\t\t\tuint64 currentTimestamp = retireTimestamp.load();\n\t\t\t\tif (currentTimestamp >= waitTs)\n\t\t\t\t\treturn 0;\n\t\t\t\tcoreinit::OSWaitEvent(s_updateRetirementEvent.GetPtr());\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"TCLWaitTimestamp(): Unsupported timestamp ID {}\", (uint32)id);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tstatic constexpr uint32 TCL_RING_BUFFER_SIZE = 4096; // in U32s\n\n\tstd::atomic<uint32> tclRingBufferA[TCL_RING_BUFFER_SIZE];\n\tstd::atomic<uint32> tclRingBufferA_readIndex{0};\n\tstd::atomic<uint32> tclRingBufferA_writeIndex{0};\n\n\t// GPU code calls this to grab the next command word\n\tbool TCLGPUReadRBWord(uint32& cmdWord)\n\t{\n\t\tuint32 readIndex = tclRingBufferA_readIndex.load(std::memory_order::relaxed);\n\t\tuint32 writeIndex = tclRingBufferA_writeIndex.load(std::memory_order::acquire);\n\t\tif (readIndex == writeIndex)\n\t\t\treturn false;\n\t\tcmdWord = tclRingBufferA[readIndex].load(std::memory_order::relaxed);\n\t\ttclRingBufferA_readIndex.store((readIndex + 1) % TCL_RING_BUFFER_SIZE, std::memory_order::release);\n\t\treturn true;\n\t}\n\n\tvoid TCLWaitForRBSpace(uint32be numU32s)\n\t{\n\t\tuint32 writeIndex = tclRingBufferA_writeIndex.load(std::memory_order::relaxed);\n\t\twhile (true)\n\t\t{\n\t\t\tuint32 readIndex = tclRingBufferA_readIndex.load(std::memory_order::acquire);\n\t\t\tuint32 distance = (readIndex + TCL_RING_BUFFER_SIZE - writeIndex) & (TCL_RING_BUFFER_SIZE - 1);\n\t\t\tif (writeIndex == readIndex) // buffer completely empty\n\t\t\t\tdistance = TCL_RING_BUFFER_SIZE;\n\t\t\tif (distance >= numU32s + 1) // assume distance minus one, because we are never allowed to completely wrap around\n\t\t\t\tbreak;\n\t\t\t_mm_pause();\n\t\t}\n\t}\n\n\t// this function assumes that TCLWaitForRBSpace was called and that there is enough space\n\tvoid TCLWriteCmd(uint32be* cmd, uint32 cmdLen)\n\t{\n\t\tuint32 writeIndex = tclRingBufferA_writeIndex.load(std::memory_order::relaxed);\n\n\t\twhile (cmdLen > 0)\n\t\t{\n\t\t\ttclRingBufferA[writeIndex].store(*cmd, std::memory_order::relaxed);\n\t\t\twriteIndex++;\n\t\t\twriteIndex &= (TCL_RING_BUFFER_SIZE - 1);\n\t\t\tcmd++;\n\t\t\tcmdLen--;\n\t\t}\n\n\t\ttclRingBufferA_writeIndex.store(writeIndex, std::memory_order::release);\n\t}\n\n\t#define EVENT_TYPE_TS\t\t5\n\n\tvoid TCLSubmitRetireMarker(bool triggerEventInterrupt)\n\t{\n\t\ts_currentRetireMarker++;\n\t\tuint32be cmd[6];\n\t\tcmd[0] = pm4HeaderType3(IT_EVENT_WRITE_EOP, 5);\n\t\tcmd[1] = (4 | (EVENT_TYPE_TS << 8)); // event type (bits 8-15) and event index (bits 0-7).\n\t\tcmd[2] = MEMPTR<void>(&s_tclStatePPC->gpuRetireMarker).GetMPTR(); // address lower 32bits + data sel bits\n\t\tcmd[3] = 0x40000000; // select 64bit write, lower 16 bits are the upper bits of the address\n\t\tif (triggerEventInterrupt)\n\t\t\tcmd[3] |= 0x2000000; // trigger interrupt after value has been written\n\t\tcmd[4] = (uint32)s_currentRetireMarker; // data lower 32 bits\n\t\tcmd[5] = (uint32)(s_currentRetireMarker>>32); // data higher 32 bits\n\t\tTCLWriteCmd(cmd, 6);\n\t}\n\n\tint TCLSubmitToRing(uint32be* cmd, uint32 cmdLen, betype<TCLSubmissionFlag>* controlFlags, uint64be* timestampValueOut)\n\t{\n\t\tTCLSubmissionFlag flags = *controlFlags;\n\t\tcemu_assert_debug(timestampValueOut); // handle case where this is null\n\n\t\t// make sure there is enough space to submit all commands at one\n\t\tuint32 totalCommandLength = cmdLen;\n\t\ttotalCommandLength += 6; // space needed for TCLSubmitRetireMarker\n\n\t\tTCLWaitForRBSpace(totalCommandLength);\n\n\t\t// submit command buffer\n\t\tTCLWriteCmd(cmd, cmdLen);\n\n\t\t// create new marker timestamp and tell GPU to write it to our variable after its done processing the command\n\t\tif ((HAS_FLAG(flags, TCLSubmissionFlag::USE_RETIRED_MARKER)))\n\t\t{\n\t\t\tTCLSubmitRetireMarker(!HAS_FLAG(flags, TCLSubmissionFlag::NO_MARKER_INTERRUPT));\n\t\t\t*timestampValueOut = s_currentRetireMarker; // incremented before each submit\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\treturn 0;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"tcl\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"TCL\", TCLSubmitToRing, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"TCL\", TCLTimestamp, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"TCL\", TCLWaitTimestamp, LogType::Placeholder);\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\ts_currentRetireMarker = 0;\n\t\t\t\ts_tclStatePPC->gpuRetireMarker = 0;\n\t\t\t\tcoreinit::OSInitEvent(s_updateRetirementEvent.GetPtr(), coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t\ts_currentRetireMarker = 0;\n\t\t\t\ts_tclStatePPC->gpuRetireMarker = 0;\n\t\t\t}\n\t\t}\n\t}s_COStclModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COStclModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/TCL/TCL.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace TCL\n{\n\tenum class TCLTimestampId\n\t{\n\t\tTIMESTAMP_LAST_BUFFER_RETIRED = 1,\n\t};\n\n\tenum class TCLSubmissionFlag : uint32\n\t{\n\t\tSURFACE_SYNC = 0x400000, // submit surface sync packet before cmd\n\t\tNO_MARKER_INTERRUPT = 0x200000,\n\t\tUSE_RETIRED_MARKER = 0x20000000, // Controls whether the timer is updated before or after (retired) the cmd. Also controls which timestamp is returned for the submission. Before and after using separate counters\n\t};\n\n\tint TCLTimestamp(TCLTimestampId id, uint64be* timestampOut);\n\tint TCLWaitTimestamp(TCLTimestampId id, uint64 waitTs, uint64 timeout);\n\tint TCLSubmitToRing(uint32be* cmd, uint32 cmdLen, betype<TCLSubmissionFlag>* controlFlags, uint64be* timestampValueOut);\n\n\t// called from Latte code\n\tbool TCLGPUReadRBWord(uint32& cmdWord);\n\tvoid TCLGPUNotifyNewRetirementTimestamp();\n\n\tCOSModule* GetModule();\n}\nENABLE_BITMASK_OPERATORS(TCL::TCLSubmissionFlag);\n"
  },
  {
    "path": "src/Cafe/OS/libs/avm/avm.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"avm.h\"\n\nnamespace avm\n{\n\tbool AVMIsHDCPAvailable()\n\t{\n\t\treturn true;\n\t}\n\n\tbool AVMIsHDCPOn()\n\t{\n\t\treturn true;\n\t}\n\n\tbool AVMGetAnalogContentsProtectionEnable(uint32be* isEnable)\n\t{\n\t\t*isEnable = 1;\n\t\treturn false;\n\t}\n\n\tbool AVMIsAnalogContentsProtectionOn()\n\t{\n\t\treturn true;\n\t}\n\n\tbool AVMSetAnalogContentsProtectionEnable(sint32 newState)\n\t{\n\t\treturn true;  // returns 1 (true) if new state was applied successfully?\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"avm\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"avm\", AVMIsHDCPAvailable, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"avm\", AVMIsHDCPOn, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"avm\", AVMGetAnalogContentsProtectionEnable, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"avm\", AVMIsAnalogContentsProtectionOn, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"avm\", AVMSetAnalogContentsProtectionEnable, LogType::Placeholder);\n\t\t};\n\t}s_COSavmModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSavmModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/avm/avm.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace avm\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/camera/camera.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"camera.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n\nnamespace camera\n{\n\n\tstruct CAMInitInfo_t\n\t{\n\t\t/* +0x00 */ uint32be ukn00;\n\t\t/* +0x04 */ uint32be width;\n\t\t/* +0x08 */ uint32be height;\n\t\t\n\t\t/* +0x0C */ uint32be workMemorySize;\n\t\t/* +0x10 */ MEMPTR<void> workMemory;\n\n\t\t/* +0x14 */ uint32be handlerFuncPtr;\n\n\t\t/* +0x18 */ uint32be ukn18;\n\t\t/* +0x1C */ uint32be fps;\n\n\t\t/* +0x20 */ uint32be ukn20;\n\t};\n\n\tstruct CAMTargetSurface \n\t{\n\t\t/* +0x00 */ uint32be surfaceSize;\n\t\t/* +0x04 */ MEMPTR<void> surfacePtr;\n\t\t/* +0x08 */ uint32be ukn08;\n\t\t/* +0x0C */ uint32be ukn0C;\n\t\t/* +0x10 */ uint32be ukn10;\n\t\t/* +0x14 */ uint32be ukn14;\n\t\t/* +0x18 */ uint32be ukn18;\n\t\t/* +0x1C */ uint32be ukn1C;\n\t};\n\n\tstruct CAMCallbackParam \n\t{\n\t\t// type 0 - frame decoded | field1 - imagePtr, field2 - imageSize, field3 - ukn (0)\n\t\t// type 1 - ???\n\n\n\t\t/* +0x0 */ uint32be type; // 0 -> Frame decoded\n\t\t/* +0x4 */ uint32be field1;\n\t\t/* +0x8 */ uint32be field2;\n\t\t/* +0xC */ uint32be field3;\n\t};\n\n\n\t#define CAM_ERROR_SUCCESS\t\t\t0\n\t#define CAM_ERROR_INVALID_HANDLE\t\t-8\n\n\tstd::vector<struct CameraInstance*> g_table_cameraHandles;\n\tstd::vector<struct CameraInstance*> g_activeCameraInstances;\n\tstd::recursive_mutex g_mutex_camera;\n\tstd::atomic_int g_cameraCounter{ 0 };\n\tSysAllocator<coreinit::OSAlarm_t, 1> g_alarm_camera;\n\tSysAllocator<CAMCallbackParam, 1> g_cameraHandlerParam;\n\n\tCameraInstance* GetCameraInstanceByHandle(sint32 camHandle)\n\t{\n\t\tstd::unique_lock<std::recursive_mutex> _lock(g_mutex_camera);\n\t\tif (camHandle <= 0)\n\t\t\treturn nullptr;\n\t\tcamHandle -= 1;\n\t\tif (camHandle >= g_table_cameraHandles.size())\n\t\t\treturn nullptr;\n\t\treturn g_table_cameraHandles[camHandle];\n\t}\n\n\tstruct CameraInstance \n\t{\n\t\tCameraInstance(uint32 frameWidth, uint32 frameHeight, MPTR handlerFunc) : width(frameWidth), height(frameHeight), handlerFunc(handlerFunc) { AcquireHandle(); };\n\t\t~CameraInstance() { if (isOpen) { CloseCam(); } ReleaseHandle(); };\n\n\t\tsint32 handle{ 0 };\n\t\tuint32 width;\n\t\tuint32 height;\n\t\tbool isOpen{false};\n\t\tstd::queue<CAMTargetSurface> queue_targetSurfaces;\n\t\tMPTR handlerFunc;\n\n\t\tbool OpenCam()\n\t\t{\n\t\t\tif (isOpen)\n\t\t\t\treturn false;\n\t\t\tisOpen = true;\n\t\t\tg_activeCameraInstances.push_back(this);\n\t\t\treturn true;\n\t\t}\n\n\t\tbool CloseCam()\n\t\t{\n\t\t\tif (!isOpen)\n\t\t\t\treturn false;\n\t\t\tisOpen = false;\n\t\t\tvectorRemoveByValue(g_activeCameraInstances, this);\n\t\t\treturn true;\n\t\t}\n\n\t\tvoid QueueTargetSurface(CAMTargetSurface* targetSurface)\n\t\t{\n\t\t\tstd::unique_lock<std::recursive_mutex> _lock(g_mutex_camera);\n\t\t\tcemu_assert_debug(queue_targetSurfaces.size() < 100); // check for sane queue length\n\t\t\tqueue_targetSurfaces.push(*targetSurface);\n\t\t}\n\n\tprivate:\n\t\tvoid AcquireHandle()\n\t\t{\n\t\t\tstd::unique_lock<std::recursive_mutex> _lock(g_mutex_camera);\n\t\t\tfor (uint32 i = 0; i < g_table_cameraHandles.size(); i++)\n\t\t\t{\n\t\t\t\tif (g_table_cameraHandles[i] == nullptr)\n\t\t\t\t{\n\t\t\t\t\tg_table_cameraHandles[i] = this;\n\t\t\t\t\tthis->handle = i + 1;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis->handle = (sint32)(g_table_cameraHandles.size() + 1);\n\t\t\tg_table_cameraHandles.push_back(this);\n\t\t}\n\n\t\tvoid ReleaseHandle()\n\t\t{\n\t\t\tfor (uint32 i = 0; i < g_table_cameraHandles.size(); i++)\n\t\t\t{\n\t\t\t\tif (g_table_cameraHandles[i] == this)\n\t\t\t\t{\n\t\t\t\t\tg_table_cameraHandles[i] = nullptr;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t};\n\n\tsint32 CAMGetMemReq(void* ukn)\n\t{\n\t\treturn 1 * 1024; // always return 1KB\n\t}\n\n\tsint32 CAMCheckMemSegmentation(void* base, uint32 size)\n\t{\n\t\treturn CAM_ERROR_SUCCESS; // always return success\n\t}\n\n\tvoid ppcCAMUpdate60(PPCInterpreter_t* hCPU)\n\t{\n\t\t// update all open camera instances\n\t\tsize_t numCamInstances = g_activeCameraInstances.size();\n\t\t//for (auto& itr : g_activeCameraInstances)\n\t\tfor(size_t i=0; i<numCamInstances; i++)\n\t\t{\n\t\t\tstd::unique_lock<std::recursive_mutex> _lock(g_mutex_camera);\n\t\t\tif (i >= g_activeCameraInstances.size())\n\t\t\t\tbreak;\n\t\t\tCameraInstance* camInstance = g_activeCameraInstances[i];\n\t\t\t// todo - handle 30 / 60 FPS\n\t\t\tif (camInstance->queue_targetSurfaces.empty())\n\t\t\t\tcontinue;\n\t\t\tauto& targetSurface = camInstance->queue_targetSurfaces.front();\n\t\t\tg_cameraHandlerParam->type = 0;\n\t\t\tg_cameraHandlerParam->field1 = targetSurface.surfacePtr.GetMPTR();\n\t\t\tg_cameraHandlerParam->field2 = targetSurface.surfaceSize;\n\t\t\tg_cameraHandlerParam->field3 = 0;\n\t\t\tcemu_assert_debug(camInstance->handlerFunc != MPTR_NULL);\n\t\t\tcamInstance->queue_targetSurfaces.pop();\n\t\t\t_lock.unlock();\n\t\t\tPPCCoreCallback(camInstance->handlerFunc, g_cameraHandlerParam.GetPtr());\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\n\tsint32 CAMInit(uint32 cameraId, CAMInitInfo_t* camInitInfo, uint32be* error)\n\t{\n\t\tCameraInstance* camInstance = new CameraInstance(camInitInfo->width, camInitInfo->height, camInitInfo->handlerFuncPtr);\n\t\t*error = 0; // Hunter's Trophy 2 will fail to boot if we don't set this\n\t\tstd::unique_lock<std::recursive_mutex> _lock(g_mutex_camera);\n\t\tif (g_cameraCounter == 0)\n\t\t{\n\t\t\tcoreinit::OSCreateAlarm(g_alarm_camera.GetPtr());\n\t\t\tcoreinit::OSSetPeriodicAlarm(g_alarm_camera.GetPtr(), coreinit::OSGetTime(), (uint64)ESPRESSO_TIMER_CLOCK / 60ull, RPLLoader_MakePPCCallable(ppcCAMUpdate60));\n\t\t}\n\t\tg_cameraCounter++;\n\n\t\treturn camInstance->handle;\n\t}\n\n\tsint32 CAMExit(sint32 camHandle)\n\t{\n\t\tCameraInstance* camInstance = GetCameraInstanceByHandle(camHandle);\n\t\tif (!camInstance)\n\t\t\treturn CAM_ERROR_INVALID_HANDLE;\n\t\tCAMClose(camHandle);\n\t\tdelete camInstance;\n\n\t\tstd::unique_lock<std::recursive_mutex> _lock(g_mutex_camera);\n\t\tg_cameraCounter--;\n\t\tif (g_cameraCounter == 0)\n\t\t\tcoreinit::OSCancelAlarm(g_alarm_camera.GetPtr());\n\t\treturn CAM_ERROR_SUCCESS;\n\t}\n\n\tsint32 CAMOpen(sint32 camHandle)\n\t{\n\t\tCameraInstance* camInstance = GetCameraInstanceByHandle(camHandle);\n\t\tif (!camInstance)\n\t\t\treturn CAM_ERROR_INVALID_HANDLE;\n\t\tcamInstance->OpenCam();\n\t\treturn CAM_ERROR_SUCCESS;\n\t}\n\n\tsint32 CAMClose(sint32 camHandle)\n\t{\n\t\tCameraInstance* camInstance = GetCameraInstanceByHandle(camHandle);\n\t\tif (!camInstance)\n\t\t\treturn CAM_ERROR_INVALID_HANDLE;\n\t\tcamInstance->CloseCam();\n\t\treturn CAM_ERROR_SUCCESS;\n\t}\n\n\tsint32 CAMSubmitTargetSurface(sint32 camHandle, CAMTargetSurface* targetSurface)\n\t{\n\t\tCameraInstance* camInstance = GetCameraInstanceByHandle(camHandle);\n\t\tif (!camInstance)\n\t\t\treturn CAM_ERROR_INVALID_HANDLE;\n\t\t\n\t\tcamInstance->QueueTargetSurface(targetSurface);\n\n\t\treturn CAM_ERROR_SUCCESS;\n\t}\n\n\tvoid reset()\n\t{\n\t\tg_cameraCounter = 0;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"camera\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"camera\", CAMGetMemReq, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"camera\", CAMCheckMemSegmentation, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"camera\", CAMInit, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"camera\", CAMExit, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"camera\", CAMOpen, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"camera\", CAMClose, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"camera\", CAMSubmitTargetSurface, LogType::Placeholder);\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\treset();\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t\t// todo\n\t\t\t}\n\t\t}\n\t}s_COScameraModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COScameraModule;\n\t}\n}\n\n"
  },
  {
    "path": "src/Cafe/OS/libs/camera/camera.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace camera\n{\n\tsint32 CAMOpen(sint32 camHandle);\n\tsint32 CAMClose(sint32 camHandle);\n\n\tCOSModule* GetModule();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Common/SysAllocator.h\"\n#include \"Cafe/OS/RPL/rpl_symbol_storage.h\"\n\n#include \"Cafe/OS/libs/coreinit/coreinit_Misc.h\"\n\n// includes for Initialize coreinit submodules\n#include \"Cafe/OS/libs/coreinit/coreinit_BSP.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Scheduler.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Atomic.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_OverlayArena.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_DynLoad.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_GHS.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_HWInterface.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Memory.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IM.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_LockedCache.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MemoryMapping.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IPC.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IPCBuf.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Coroutine.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_OSScreen.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_FG.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_SystemInfo.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_SysHeap.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MCP.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_CodeGen.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MPQueue.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_FS.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_UnitHeap.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_FrmHeap.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_BlockHeap.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.h\"\n\nCoreinitSharedData* gCoreinitData = nullptr;\n\nsint32 ScoreStackTrace(OSThread_t* thread, MPTR sp)\n{\n\tuint32 stackMinAddr = thread->stackEnd.GetMPTR();\n\tuint32 stackMaxAddr = thread->stackBase.GetMPTR();\n\n\tsint32 score = 0;\n\tuint32 currentStackPtr = sp;\n\tfor (sint32 i = 0; i < 50; i++)\n\t{\n\t\tuint32 nextStackPtr = memory_readU32(currentStackPtr);\n\t\tif (nextStackPtr < currentStackPtr)\n\t\t\tbreak;\n\t\tif (nextStackPtr < stackMinAddr || nextStackPtr > stackMaxAddr)\n\t\t\tbreak;\n\t\tif ((nextStackPtr & 3) != 0)\n\t\t\tbreak;\n\t\tscore += 10;\n\n\t\tuint32 returnAddress = 0;\n\t\treturnAddress = memory_readU32(nextStackPtr + 4);\n\t\t//cemuLog_log(LogType::Force, fmt::format(\"SP {0:08x} ReturnAddress {1:08x}\", nextStackPtr, returnAddress));\n\t\tif (returnAddress > 0 && returnAddress < 0x10000000 && (returnAddress&3) == 0)\n\t\t\tscore += 5; // within code region\n\t\telse\n\t\t\tscore -= 5;\n\n\t\tcurrentStackPtr = nextStackPtr;\n\n\t}\n\treturn score;\n}\n\nvoid DebugLogStackTrace(OSThread_t* thread, MPTR sp, bool printSymbols)\n{\n\t// sp might not point to a valid stackframe\n\t// scan stack and evaluate which sp is most likely the beginning of the stackframe\n\n\t// scan 0x400 bytes\n\tsint32 highestScore = -1;\n\tuint32 highestScoreSP = sp;\n\tfor (sint32 i = 0; i < 0x100; i++)\n\t{\n\t\tuint32 sampleSP = sp + i * 4;\n\t\tsint32 score = ScoreStackTrace(thread, sampleSP);\n\t\tif (score > highestScore)\n\t\t{\n\t\t\thighestScore = score;\n\t\t\thighestScoreSP = sampleSP;\n\t\t}\n\t}\n\n\tif (highestScoreSP != sp)\n\t\tcemuLog_log(LogType::Force, fmt::format(\"Trace starting at SP {0:08x} r1 = {1:08x}\", highestScoreSP, sp));\n\telse\n\t\tcemuLog_log(LogType::Force, fmt::format(\"Trace starting at SP/r1 {0:08x}\", highestScoreSP));\n\n\t// print stack trace\n\tuint32 currentStackPtr = highestScoreSP;\n\tuint32 stackMinAddr = thread->stackEnd.GetMPTR();\n\tuint32 stackMaxAddr = thread->stackBase.GetMPTR();\n\tfor (sint32 i = 0; i < 20; i++)\n\t{\n\t\tuint32 nextStackPtr = memory_readU32(currentStackPtr);\n\t\tif (nextStackPtr < currentStackPtr)\n\t\t\tbreak;\n\t\tif (nextStackPtr < stackMinAddr || nextStackPtr > stackMaxAddr)\n\t\t\tbreak;\n\n\t\tuint32 returnAddress = 0;\n\t\treturnAddress = memory_readU32(nextStackPtr + 4);\n\n\t\tRPLStoredSymbol* symbol = nullptr;\n\t\tif(printSymbols)\n\t\t\tsymbol = rplSymbolStorage_getByClosestAddress(returnAddress);\n\n\t\tif(symbol)\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"SP {:08x} ReturnAddr {:08x}   ({}.{}+0x{:x})\", nextStackPtr, returnAddress, (const char*)symbol->libName, (const char*)symbol->symbolName, returnAddress - symbol->address));\n\t\telse\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"SP {:08x} ReturnAddr {:08x}\", nextStackPtr, returnAddress));\n\n\t\tcurrentStackPtr = nextStackPtr;\n\t}\n}\n\ntypedef struct\n{\n\t/* +0x00 */ uint32be name;\n\t/* +0x04 */ uint32be fileType; // 2 = font\n\t/* +0x08 */ uint32be kernelFilenamePtr;\n\t/* +0x0C */ MEMPTR<void> data;\n\t/* +0x10 */ uint32be size;\n\t/* +0x14 */ uint32be ukn14;\n\t/* +0x18 */ uint32be ukn18;\n}coreinitShareddataEntry_t;\n\nstatic_assert(sizeof(coreinitShareddataEntry_t) == 0x1C, \"\");\n\nuint8* extractCafeDefaultFont(sint32* size);\n\nMPTR placeholderFont = MPTR_NULL;\nsint32 placeholderFontSize = 0;\n\nvoid coreinitExport_OSGetSharedData(PPCInterpreter_t* hCPU)\n{\n\t// parameters:\n\t// r3\t\tsharedAreaId\n\t// r4\t\tflags\n\t// r5\t\tareaPtrPtr\n\t// r6\t\tareaSizePtr\n\n\t// on real Wii U hw/sw there is a list of shared area entries starting at offset +0xF8000000\n\t// properly formated (each entry is 0x1C bytes) it looks like this:\n\t// FF CA FE 01 00 00 00 02 FF E8 47 AC F8 00 00 70 00 C8 0D 4C 00 00 00 00 FF FF FF FC\n\t// FF CA FE 02 00 00 00 02 FF E8 47 B7 F8 C8 0D C0 00 22 7E B4 00 00 00 00 00 00 11 D5\n\t// FF CA FE 03 00 00 00 02 FF E8 47 A0 F8 EA 8C 80 00 25 44 E0 00 00 00 00 FF A0 00 00\n\t// FF CA FE 04 00 00 00 02 FF E8 47 C2 F9 0F D1 60 00 7D 93 5C 00 00 00 00 FF FF FF FC\n\n\tuint32 sharedAreaId = hCPU->gpr[3];\n\n\tcoreinitShareddataEntry_t* shareddataTable = (coreinitShareddataEntry_t*)memory_getPointerFromVirtualOffset(MEMORY_SHAREDDATA_AREA_ADDR);\n\n\tuint32 name = 0xFFCAFE01 + sharedAreaId;\n\tfor (sint32 i = 0; i < 4; i++)\n\t{\n\t\tif ((uint32)shareddataTable[i].name == name)\n\t\t{\n\t\t\tmemory_writeU32(hCPU->gpr[5], shareddataTable[i].data.GetMPTR());\n\t\t\tmemory_writeU32(hCPU->gpr[6], (uint32)shareddataTable[i].size);\n\t\t\tosLib_returnFromFunction(hCPU, 1);\n\t\t\treturn;\n\t\t}\n\t}\n\t// some games require a valid result or they will crash, return a pointer to our placeholder font\n\tcemuLog_log(LogType::Force, \"OSGetSharedData() called by game but no shareddata fonts loaded. Use placeholder font\");\n\tif (placeholderFont == MPTR_NULL)\n\t{\n\t\t// load and then return placeholder font\n\t\tuint8* placeholderFontPtr = extractCafeDefaultFont(&placeholderFontSize);\n\t\tplaceholderFont = coreinit_allocFromSysArea(placeholderFontSize, 256);\n\t\tif (placeholderFont == MPTR_NULL)\n\t\t\tcemuLog_log(LogType::Force, \"Failed to alloc placeholder font sys memory\");\n\t\tmemcpy(memory_getPointerFromVirtualOffset(placeholderFont), placeholderFontPtr, placeholderFontSize);\n\t\tfree(placeholderFontPtr);\n\t}\n\t// return placeholder font\n\tmemory_writeU32(hCPU->gpr[5], placeholderFont);\n\tmemory_writeU32(hCPU->gpr[6], placeholderFontSize);\n\tosLib_returnFromFunction(hCPU, 1);\n}\n\nnamespace coreinit\n{\n\tsint32 OSGetCoreId()\n\t{\n\t\treturn PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance());\n\t}\n\n\tuint32 OSGetCoreCount()\n\t{\n\t\treturn Espresso::CORE_COUNT;\n\t}\n\n\tuint32 OSIsDebuggerInitialized()\n\t{\n\t\treturn 0;\n\t}\n\n\tuint32 OSIsDebuggerPresent()\n\t{\n\t\treturn 0;\n\t}\n\n\tuint32 OSGetConsoleType()\n\t{\n\t\treturn 0x03000050;\n\t}\n\n\tuint32 OSGetMainCoreId()\n\t{\n\t\treturn 1;\n\t}\n\n\tbool OSIsMainCore()\n\t{\n\t\treturn OSGetCoreId() == OSGetMainCoreId();\n\t}\n\n\tuint32 OSGetStackPointer()\n\t{\n\t\treturn PPCInterpreter_getCurrentInstance()->gpr[1];\n\t}\n\n\tvoid coreinitExport_ENVGetEnvironmentVariable(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"ENVGetEnvironmentVariable(\\\"{}\\\",0x08x,0x{:x})\", (char*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]), hCPU->gpr[4], hCPU->gpr[5]);\n\t\tchar* envKeyStr = (char*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\tchar* outputString = (char*)memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\t\tsint32 outputStringMaxLen = (sint32)hCPU->gpr[5];\n\t\t// also return the string \"\" just in case\n\t\tif (outputStringMaxLen > 0)\n\t\t{\n\t\t\toutputString[0] = '\\0';\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, 1);\n\t}\n\n\tvoid coreinit_exit(uint32 r)\n\t{\n\t\tcemuLog_log(LogType::Force, \"The title terminated the process by calling coreinit.exit({})\", (sint32)r);\n        DebugLogStackTrace(coreinit::OSGetCurrentThread(), coreinit::OSGetStackPointer());\n\t\tcemu_assert_debug(false);\n\t\t// never return\n\t\twhile (true) std::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t}\n\n\tbool OSIsOffBoot()\n\t{\n\t\treturn true;\n\t}\n\n\tuint32 OSGetBootPMFlags()\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"OSGetBootPMFlags() - placeholder\");\n\t\treturn 0;\n\t}\n\n\tuint32 OSGetSystemMode()\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"OSGetSystemMode() - placeholder\");\n\t\t// if this returns 2, barista softlocks shortly after boot\n\t\treturn 0;\n\t}\n\n\tvoid OSPanic(const char* file, sint32 lineNumber, const char* msg)\n\t{\n\t\tcemuLog_log(LogType::Force, \"OSPanic!\");\n\t\tcemuLog_log(LogType::Force, \"File: {}:{}\", file, lineNumber);\n\t\tcemuLog_log(LogType::Force, \"Msg: {}\", msg);\n\t\tDebugLogStackTrace(coreinit::OSGetCurrentThread(), coreinit::OSGetStackPointer());\n#ifdef CEMU_DEBUG_ASSERT\n\t\twhile (true) std::this_thread::sleep_for(std::chrono::milliseconds(100));\n#endif\n\t}\n\n\tvoid InitializeCore()\n\t{\n\t\tcafeExportRegister(\"coreinit\", OSGetCoreId, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetCoreCount, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSIsDebuggerInitialized, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSIsDebuggerPresent, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetConsoleType, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetMainCoreId, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSIsMainCore, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetStackPointer, LogType::CoreinitThread);\n\n\t\tosLib_addFunction(\"coreinit\", \"ENVGetEnvironmentVariable\", coreinitExport_ENVGetEnvironmentVariable);\n\n\t\tcafeExportRegisterFunc(coreinit_exit, \"coreinit\", \"exit\", LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSIsOffBoot, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetBootPMFlags, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetSystemMode, LogType::CoreinitThread);\n\n\t\tcafeExportRegister(\"coreinit\", OSPanic, LogType::Placeholder);\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"coreinit\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcoreinit::InitializeCore();\n\t\t\tcoreinit::InitializeSchedulerLock();\n\t\t\tcoreinit::InitializeSysHeap();\n\n\t\t\t// allocate coreinit global data\n\t\t\tgCoreinitData = (CoreinitSharedData*)memory_getPointerFromVirtualOffset(coreinit_allocFromSysArea(sizeof(CoreinitSharedData), 32));\n\t\t\tmemset(gCoreinitData, 0x00, sizeof(CoreinitSharedData));\n\n\t\t\t// coreinit weak links\n\t\t\tosLib_addVirtualPointer(\"coreinit\", \"MEMAllocFromDefaultHeap\", memory_getVirtualOffsetFromPointer(&gCoreinitData->MEMAllocFromDefaultHeap));\n\t\t\tosLib_addVirtualPointer(\"coreinit\", \"MEMAllocFromDefaultHeapEx\", memory_getVirtualOffsetFromPointer(&gCoreinitData->MEMAllocFromDefaultHeapEx));\n\t\t\tosLib_addVirtualPointer(\"coreinit\", \"MEMFreeToDefaultHeap\", memory_getVirtualOffsetFromPointer(&gCoreinitData->MEMFreeToDefaultHeap));\n\t\t\tosLib_addVirtualPointer(\"coreinit\", \"__atexit_cleanup\", memory_getVirtualOffsetFromPointer(&gCoreinitData->__atexit_cleanup));\n\t\t\tosLib_addVirtualPointer(\"coreinit\", \"__stdio_cleanup\", memory_getVirtualOffsetFromPointer(&gCoreinitData->__stdio_cleanup));\n\t\t\tosLib_addVirtualPointer(\"coreinit\", \"__cpp_exception_cleanup_ptr\", memory_getVirtualOffsetFromPointer(&gCoreinitData->__cpp_exception_cleanup_ptr));\n\t\t\tosLib_addVirtualPointer(\"coreinit\", \"__cpp_exception_init_ptr\", memory_getVirtualOffsetFromPointer(&gCoreinitData->__cpp_exception_init_ptr));\n\n\t\t\t// init GHS and threads\n\t\t\tcoreinit::PrepareGHSRuntime();\n\t\t\tcoreinit::MapThreadExports();\n\n\t\t\t// reset threads\n\t\t\tactiveThreadCount = 0;\n\t\t\t// init submodules\n\t\t\tcoreinit::InitializeMEM();\n\t\t\tcoreinit::InitializeMEMFrmHeap();\n\t\t\tcoreinit::InitializeMEMUnitHeap();\n\t\t\tcoreinit::InitializeMEMBlockHeap();\n\t\t\tcoreinit::InitializeFG();\n\t\t\tcoreinit::InitializeBSP();\n\t\t\tcoreinit::InitializeMCP();\n\t\t\tcoreinit::InitializeOverlayArena();\n\t\t\tcoreinit::InitializeDynLoad();\n\t\t\tcoreinit::InitializeGHS();\n\t\t\tcoreinit::InitializeHWInterface();\n\t\t\tcoreinit::InitializeAtomic();\n\t\t\tcoreinit::InitializeMemory();\n\t\t\tcoreinit::InitializeIM();\n\t\t\tcoreinit::InitializeLC();\n\t\t\tcoreinit::InitializeMP();\n\t\t\tcoreinit::InitializeTimeAndCalendar();\n\t\t\tcoreinit::MapAlarmExports();\n\t\t\tcoreinit::InitializeFS();\n\t\t\tcoreinit::InitializeSystemInfo();\n\t\t\tcoreinit::InitializeConcurrency();\n\t\t\tcoreinit::InitializeSpinlock();\n\t\t\tcoreinit::InitializeMessageQueue();\n\t\t\tcoreinit::MapIPCExports();\n\t\t\tcoreinit::InitializeIPCBuf();\n\t\t\tcoreinit::InitializeMemoryMapping();\n\t\t\tcoreinit::InitializeCodeGen();\n\t\t\tcoreinit::InitializeCoroutine();\n\t\t\tcoreinit::InitializeOSScreen();\n\n\t\t\t// legacy mem stuff\n\t\t\tcoreinit::expheap_load();\n\n\t\t\t// misc exports\n\t\t\tcoreinit::miscInit();\n\t\t\tosLib_addFunction(\"coreinit\", \"OSGetSharedData\", coreinitExport_OSGetSharedData);\n\t\t\tosLib_addFunction(\"coreinit\", \"UCReadSysConfig\", coreinitExport_UCReadSysConfig);\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\tcoreinit::InitializeThread();\n\t\t\t\tcoreinit::InitializeAlarm();\n\t\t\t\tcoreinit::InitializeIPC();\n\t\t\t\tInitializeAsyncCallback();\n\t\t\t\t// remaining coreinit initialization happens in coreinit_start and requires a valid PPC context\n\t\t\t\tOSThread_t* initialThread = coreinit::OSGetDefaultThread(1);\n\t\t\t\tcoreinit::OSSetThreadPriority(initialThread, 16);\n\t\t\t\tcoreinit::OSRunThread(initialThread, PPCInterpreter_makeCallableExportDepr(coreinit_start), 0, nullptr);\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t\t// todo\n\t\t\t}\n\t\t}\n\t}s_COSCoreinitModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSCoreinitModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit.h",
    "content": "#pragma once\n#include \"Cafe/HW/Espresso/Const.h\"\n#include \"Cafe/OS/RPL/COSModule.h\"\n\n#define PPC_CORE_COUNT     (Espresso::CORE_COUNT)\n\n#include \"Cafe/OS/libs/coreinit/coreinit_MessageQueue.h\"\n\n// async callback helper\n\nvoid InitializeAsyncCallback();\nvoid coreinitAsyncCallback_add(MPTR functionMPTR, uint32 numParameters, uint32 r3 = 0, uint32 r4 = 0, uint32 r5 = 0, uint32 r6 = 0, uint32 r7 = 0, uint32 r8 = 0, uint32 r9 = 0, uint32 r10 = 0);\nvoid coreinitAsyncCallback_addWithLock(MPTR functionMPTR, uint32 numParameters, uint32 r3 = 0, uint32 r4 = 0, uint32 r5 = 0, uint32 r6 = 0, uint32 r7 = 0, uint32 r8 = 0, uint32 r9 = 0, uint32 r10 = 0);\n\n// coreinit shared memory\nstruct CoreinitSharedData\n{\n\tMEMPTR<void> MEMAllocFromDefaultHeap;\n\tMEMPTR<void> MEMAllocFromDefaultHeapEx;\n\tMEMPTR<void> MEMFreeToDefaultHeap;\n\tMPTR __atexit_cleanup;\n\tMPTR __cpp_exception_init_ptr;\n\tMPTR __cpp_exception_cleanup_ptr;\n\tMPTR __stdio_cleanup;\n};\n\nextern CoreinitSharedData* gCoreinitData;\n\n// coreinit init\nvoid coreinit_start(PPCInterpreter_t* hCPU);\n\nMPTR OSAllocFromSystem(uint32 size, uint32 alignment);\nvoid OSFreeToSystem(MPTR mem);\n\n// above is all the legacy stuff. New code uses namespaces\n\nnamespace coreinit\n{\n\tsint32 OSGetCoreId();\n\tuint32 OSGetCoreCount();\n\tuint32 OSGetStackPointer();\n\n\tCOSModule* GetModule();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n\n// #define ALARM_LOGGING\n\nnamespace coreinit\n{\n\tSysAllocator<OSEvent> g_alarmEvent;\n\n\tSysAllocator<OSThread_t> g_alarmThread;\n\tSysAllocator<uint8, 1024 * 128> _g_alarmThreadStack;\n\tSysAllocator<char, 32> _g_alarmThreadName;\n\n\n\tclass OSHostAlarm \n\t{\n\tpublic:\n\t\tOSHostAlarm(uint64 nextFire, uint64 period, void(*callbackFunc)(uint64 currentTick, void* context), void* context) : m_nextFire(nextFire), m_period(period), m_callbackFunc(callbackFunc), m_context(context)\n\t\t{\n\t\t\tcemu_assert_debug(__OSHasSchedulerLock()); // must hold lock\n\t\t\tauto r = g_activeAlarmList.emplace(this);\n\t\t\tcemu_assert_debug(r.second); // check if insertion was successful\n\t\t\tm_isActive = true;\n\t\t\tupdateEarliestAlarmAtomic();\n\t\t}\n\n\t\t~OSHostAlarm()\n\t\t{\n\t\t\tcemu_assert_debug(__OSHasSchedulerLock()); // must hold lock\n\t\t\tif (m_isActive)\n\t\t\t{\n\t\t\t\tg_activeAlarmList.erase(g_activeAlarmList.find(this));\n\t\t\t\tupdateEarliestAlarmAtomic();\n\t\t\t}\n\t\t}\n\n\t\tuint64 getFireTick() const\n\t\t{\n\t\t\treturn m_nextFire;\n\t\t}\n\n\t\tvoid triggerAlarm(uint64 currentTick)\n\t\t{\n\t\t\tm_callbackFunc(currentTick, m_context);\n\t\t}\n\n\t\tstatic void updateEarliestAlarmAtomic()\n\t\t{\n\t\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\t\tif (!g_activeAlarmList.empty())\n\t\t\t{\n\t\t\t\tauto firstAlarm = g_activeAlarmList.begin();\n\t\t\t\tg_soonestAlarm = (*firstAlarm)->m_nextFire;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tg_soonestAlarm = std::numeric_limits<uint64>::max();\n\t\t\t}\n\t\t}\n\n\t\tstatic void updateAlarms(uint64 currentTick)\n\t\t{\n\t\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\t\tif (g_activeAlarmList.empty())\n\t\t\t\treturn;\n\n\t\t\t// debug begin\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tuint64 prevTick = 0;\n\t\t\tauto itr = g_activeAlarmList.begin();\n\t\t\twhile (itr != g_activeAlarmList.end())\n\t\t\t{\n\t\t\t\tuint64 t = (*itr)->m_nextFire;\n\t\t\t\tif (t < prevTick)\n\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\tprevTick = t;\n\t\t\t\t++itr;\n\t\t\t}\n#endif\n\t\t\t// debug end\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tauto firstAlarm = g_activeAlarmList.begin();\n\t\t\t\tif (currentTick >= (*firstAlarm)->m_nextFire)\n\t\t\t\t{\n\t\t\t\t\tOSHostAlarm* alarm = *firstAlarm;\n\t\t\t\t\tg_activeAlarmList.erase(firstAlarm);\n\t\t\t\t\talarm->triggerAlarm(currentTick);\n\t\t\t\t\t// if periodic alarm then requeue\n\t\t\t\t\tif (alarm->m_period > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\talarm->m_nextFire += alarm->m_period;\n\t\t\t\t\t\tg_activeAlarmList.emplace(alarm);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\talarm->m_isActive = false;\n\t\t\t\t\tupdateEarliestAlarmAtomic();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\t\t\t}\t\n\t\t}\n\n\t\tuint64 getNextFire() const \n\t\t{\n\t\t\treturn m_nextFire;\n\t\t}\n\n\t\tstatic bool quickCheckForAlarm(uint64 currentTick)\n\t\t{\n\t\t\t// fast way to check if any alarm was triggered without requiring scheduler lock\n\t\t\treturn currentTick >= g_soonestAlarm;\n\t\t}\n\n        static void Reset()\n        {\n            g_activeAlarmList.clear();\n            g_soonestAlarm = 0;\n        }\n\n\tpublic:\n\t\tstruct ComparatorFireTime\n\t\t{\n\t\t\tbool operator ()(OSHostAlarm* const & p1, OSHostAlarm* const & p2) const\n\t\t\t{\n\t\t\t\tauto p1Fire = p1->getNextFire();\n\t\t\t\tauto p2Fire = p2->getNextFire();\n\t\t\t\tif (p1Fire == p2Fire)\n\t\t\t\t\treturn (uintptr_t)p1 < (uintptr_t)p2; // if time is equal, differ by pointer (to allow storing multiple alarms with same firing time)\n\t\t\t\treturn p1Fire < p2Fire;\n\t\t\t}\n\t\t};\n\n\tprivate:\t\n\t\tuint64 m_nextFire;\n\t\tuint64 m_period; // if zero then repeat is disabled \n\t\tbool m_isActive{ false };\n\n\t\tvoid (*m_callbackFunc)(uint64 currentTick, void* context);\n\t\tvoid* m_context;\n\n\t\tstatic std::set<class OSHostAlarm*, ComparatorFireTime> g_activeAlarmList;\n\t\tstatic std::atomic_uint64_t g_soonestAlarm;\n\t};\n\n\n\tstd::set<class OSHostAlarm*, OSHostAlarm::ComparatorFireTime> OSHostAlarm::g_activeAlarmList;\n\tstd::atomic_uint64_t OSHostAlarm::g_soonestAlarm{};\n\n\tOSHostAlarm* OSHostAlarmCreate(uint64 nextFire, uint64 period, void(*callbackFunc)(uint64 currentTick, void* context), void* context)\n\t{\n\t\tOSHostAlarm* hostAlarm = new OSHostAlarm(nextFire, period, callbackFunc, context);\n\t\treturn hostAlarm;\n\t}\n\n\tvoid OSHostAlarmDestroy(OSHostAlarm* hostAlarm)\n\t{\n\t\tdelete hostAlarm;\n\t}\n\n\tvoid alarm_update()\n\t{\t\n\t\tcemu_assert_debug(!__OSHasSchedulerLock());\n\t\tuint64 currentTick = coreinit::OSGetTime();\n\t\tif (!OSHostAlarm::quickCheckForAlarm(currentTick))\n\t\t\treturn;\n\t\t__OSLockScheduler();\n\t\tOSHostAlarm::updateAlarms(currentTick);\n\t\t__OSUnlockScheduler();\n\t}\n\n\t/* alarm API */\n\n\tvoid OSCreateAlarm(OSAlarm_t* alarm)\n\t{\n\t\tmemset(alarm, 0, sizeof(OSAlarm_t));\n\t\talarm->setMagic();\n\t}\n\n\tvoid OSCreateAlarmEx(OSAlarm_t* alarm, const char* alarmName)\n\t{\n\t\tmemset(alarm, 0, sizeof(OSAlarm_t));\n\t\talarm->setMagic();\n\t\talarm->name = alarmName;\n\t}\n\n\tstd::unordered_map<OSAlarm_t*, OSHostAlarm*> g_activeAlarms;\n\n\tbool OSCancelAlarm(OSAlarm_t* alarm)\n\t{\n\t\t__OSLockScheduler();\n\t\tbool alarmWasActive = false;\n\t\tauto itr = g_activeAlarms.find(alarm);\n\t\tif (itr != g_activeAlarms.end())\n\t\t{\n\t\t\tOSHostAlarmDestroy(itr->second);\n\t\t\tg_activeAlarms.erase(itr);\n\t\t\talarmWasActive = true;\n\t\t}\n\n\t\t__OSUnlockScheduler();\n\t\treturn alarmWasActive;\n\t}\n\n\tvoid __OSHostAlarmTriggered(uint64 currentTick, void* context)\n\t{\n#ifdef ALARM_LOGGING\n\t\tcemuLog_log(LogType::Force, \"[Alarm] Alarm ready and alarm thread signalled. Current tick: {}\", currentTick);\n#endif\n\t\tOSSignalEventInternal(g_alarmEvent.GetPtr());\n\t}\n\n\tvoid __OSInitiateAlarm(OSAlarm_t* alarm, uint64 startTime, uint64 period, MPTR handlerFunc, bool isPeriodic)\n\t{\n        cemu_assert_debug(MMU_IsInPPCMemorySpace(alarm));\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\n\t\tuint64 nextTime = startTime;\n\n#ifdef ALARM_LOGGING\n\t\tdouble periodInMS = (double)period * 1000.0 / (double)EspressoTime::GetTimerClock();\n\t\tcemuLog_log(LogType::Force, \"[Alarm] Start alarm 0x{:08x}. Func 0x{:08x}. Period: {}ms\", MEMPTR(alarm).GetMPTR(), handlerFunc, periodInMS);\n#endif\n\n\t\tif (isPeriodic)\n\t\t{\n\t\t\tcemu_assert_debug(period != 0);\n\t\t\tif (period == 0)\n\t\t\t\treturn;\n\n\t\t\tuint64 currentTime = OSGetTime();\n\n\t\t\tuint64 ticksSinceStart = currentTime - startTime;\n\t\t\tuint64 numPeriods = ticksSinceStart / period;\n\n\t\t\tnextTime = startTime + (numPeriods + 1ull) * period;\n\n\t\t\talarm->startTime = _swapEndianU64(startTime);\n\t\t\talarm->nextTime = _swapEndianU64(nextTime);\n\t\t\talarm->period = _swapEndianU64(period);\n\t\t\talarm->handler = _swapEndianU32(handlerFunc);\n\t\t}\n\t\telse\n\t\t{\n\t\t\talarm->nextTime = _swapEndianU64(startTime);\n\t\t\talarm->period = 0;\n\t\t\talarm->handler = _swapEndianU32(handlerFunc);\n\t\t}\n\n\t\tauto existingAlarmItr = g_activeAlarms.find(alarm);\n\t\tif (existingAlarmItr != g_activeAlarms.end())\n\t\t{\n\t\t\t// delete existing alarm\n\t\t\tcemuLog_logDebug(LogType::Force, \"__OSInitiateAlarm() called on alarm which was already active\");\n\t\t\tOSHostAlarmDestroy(existingAlarmItr->second);\n\t\t\tg_activeAlarms.erase(existingAlarmItr);\n\t\t}\n\n\t\tg_activeAlarms[alarm] = OSHostAlarmCreate(nextTime, period, __OSHostAlarmTriggered, nullptr);\n\t}\n\n\tvoid OSSetAlarm(OSAlarm_t* alarm, uint64 delayInTicks, MPTR handlerFunc)\n\t{\n\t\t__OSLockScheduler();\n\t\t__OSInitiateAlarm(alarm, OSGetTime() + delayInTicks, 0, handlerFunc, false);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid OSSetPeriodicAlarm(OSAlarm_t* alarm, uint64 nextFire, uint64 period, MPTR handlerFunc)\n\t{\n\t\t__OSLockScheduler();\n\t\t__OSInitiateAlarm(alarm, nextFire, period, handlerFunc, true);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid OSSetAlarmUserData(OSAlarm_t* alarm, uint32 userData)\n\t{\n\t\talarm->userData = userData;\n\t}\n\n\tuint32 OSGetAlarmUserData(OSAlarm_t* alarm)\n\t{\n\t\treturn alarm->userData;\n\t}\n\n\tvoid OSAlarm_Shutdown()\n\t{\n        __OSLockScheduler();\n        if(g_activeAlarms.empty())\n        {\n            __OSUnlockScheduler();\n            return;\n        }\n        for(auto& itr : g_activeAlarms)\n        {\n            OSHostAlarmDestroy(itr.second);\n        }\n        g_activeAlarms.clear();\n        OSHostAlarm::Reset();\n        __OSUnlockScheduler();\n\t}\n\n\tvoid _OSAlarmThread(PPCInterpreter_t* hCPU)\n\t{\n\t\twhile( true )\n\t\t{\n\t\t\tOSWaitEvent(g_alarmEvent.GetPtr());\n\t\t\tuint64 currentTick = OSGetTime();\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\t// get alarm to fire\n\t\t\t\tOSAlarm_t* alarm = nullptr;\n\t\t\t\t__OSLockScheduler();\n\t\t\t\tauto itr = g_activeAlarms.begin();\n\t\t\t\twhile(itr != g_activeAlarms.end())\n\t\t\t\t{\n\t\t\t\t\tif (currentTick >= _swapEndianU64(itr->first->nextTime))\n\t\t\t\t\t{\n\t\t\t\t\t\talarm = itr->first;\n\t\t\t\t\t\tif (alarm->period == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// end alarm\n\t\t\t\t\t\t\tg_activeAlarms.erase(itr);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\talarm->nextTime = _swapEndianU64(_swapEndianU64(alarm->nextTime) + _swapEndianU64(alarm->period));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t++itr;\n\t\t\t\t}\n\t\t\t\t__OSUnlockScheduler();\n\t\t\t\tif (!alarm)\n\t\t\t\t\tbreak;\n\t\t\t\t// do callback for alarm\n#ifdef ALARM_LOGGING\n\t\t\t\tdouble periodInMS = (double)_swapEndianU64(alarm->period) * 1000.0 / (double)EspressoTime::GetTimerClock();\n\t\t\t\tcemuLog_log(LogType::Force, \"[Alarm] Callback 0x{:08x} for alarm 0x{:08x}. Current tick: {}. Period: {}ms\", _swapEndianU32(alarm->handler), MEMPTR(alarm).GetMPTR(), currentTick, periodInMS);\n#endif\n\t\t\t\tPPCCoreCallback(_swapEndianU32(alarm->handler), alarm, &(g_alarmThread.GetPtr()->context));\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid MapAlarmExports()\n\t{\n\t\tcafeExportRegister(\"coreinit\", OSCreateAlarm, LogType::CoreinitAlarm);\n\t\tcafeExportRegister(\"coreinit\", OSCreateAlarmEx, LogType::CoreinitAlarm);\n\t\tcafeExportRegister(\"coreinit\", OSCancelAlarm, LogType::CoreinitAlarm);\n\t\tcafeExportRegister(\"coreinit\", OSSetAlarm, LogType::CoreinitAlarm);\n\t\tcafeExportRegister(\"coreinit\", OSSetPeriodicAlarm, LogType::CoreinitAlarm);\n\t\tcafeExportRegister(\"coreinit\", OSSetAlarmUserData, LogType::CoreinitAlarm);\n\t\tcafeExportRegister(\"coreinit\", OSGetAlarmUserData, LogType::CoreinitAlarm);\n\t}\n\n\tvoid InitializeAlarm()\n\t{\n\t\t// init event\n\t\tOSInitEvent(g_alarmEvent.GetPtr(), OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_AUTO);\n\n\t\t// create alarm callback handler thread\n\t\tcoreinit::OSCreateThreadType(g_alarmThread.GetPtr(), RPLLoader_MakePPCCallable(_OSAlarmThread), 0, nullptr, _g_alarmThreadStack.GetPtr() + _g_alarmThreadStack.GetByteSize(), (sint32)_g_alarmThreadStack.GetByteSize(), 0, 0x7, OSThread_t::THREAD_TYPE::TYPE_IO);\n\t\tOSResumeThread(g_alarmThread.GetPtr());\n\t\tstrcpy(_g_alarmThreadName.GetPtr(), \"Alarm Thread\");\n\t\tcoreinit::OSSetThreadName(g_alarmThread.GetPtr(), _g_alarmThreadName.GetPtr());\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Alarm.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n\nnamespace coreinit\n{\n\tclass OSHostAlarm;\n\tOSHostAlarm* OSHostAlarmCreate(uint64 nextFire, uint64 period, void(*callbackFunc)(uint64 currentTick, void* context), void* context);\n\tvoid OSHostAlarmDestroy(OSHostAlarm* hostAlarm);\n\n\tstruct OSAlarm_t\n\t{\n\t\t/* +0x00 */ betype<uint32>  magic;\n\t\t/* +0x04 */ MEMPTR<const char> name;\n\t\t/* +0x08 */ uint32\t        ukn08;\n\t\t/* +0x0C */ MPTR\t\t\thandler;\n\t\t/* +0x10 */ uint32          ukn10;\n\t\t/* +0x14 */ uint32\t\t\tpadding14;\n\t\t/* +0x18 */ uint64\t        nextTime; // next fire time\n\t\t/* +0x20 */ MPTR\t\t\tprev; // pointer to OSAlarm\n\t\t/* +0x24 */ MPTR\t\t\tnext; // pointer to OSAlarm\n\t\t/* +0x28 */ uint64          period; // period (zero for non-periodic timer)\n\t\t/* +0x30 */ uint64          startTime; // period start\n\t\t/* +0x38 */ uint32be        userData;\n\t\t/* +0x3C */ uint32\t\t    ukn3C;\n\t\t/* +0x40 */ OSThreadQueue   uknThreadQueue;\n\t\t/* +0x50 */ MPTR\t\t\talarmQueue;\n\t\t/* +0x54 */ MPTR\t\t\tukn54;\n\n\t\tvoid setMagic()\n\t\t{\n\t\t\tmagic = (uint32)'aLrM';\n\t\t}\n\n\t\tbool checkMagic()\n\t\t{\n\t\t\treturn magic == (uint32)'aLrM';\n\t\t}\n\t};\n\n\tstatic_assert(sizeof(OSAlarm_t) == 0x58);\n\n\tvoid OSCreateAlarm(OSAlarm_t* alarm);\n\tbool OSCancelAlarm(OSAlarm_t* alarm);\n\tvoid OSSetAlarm(OSAlarm_t* alarm, uint64 time, MPTR handlerFunc);\n\tvoid OSSetAlarmUserData(OSAlarm_t* alarm, uint32 userData);\n\tvoid OSSetPeriodicAlarm(OSAlarm_t* OSAlarm, uint64 startTick, uint64 periodTick, MPTR OSAlarmHandler);\n\n\tvoid OSAlarm_Shutdown();\n\n\tvoid alarm_update();\n\n\tvoid MapAlarmExports();\n\tvoid InitializeAlarm();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Atomic.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include <atomic>\n#include \"coreinit_Atomic.h\"\n\nnamespace coreinit\n{\n\t/* 32bit atomic operations */\n\n\tuint32 OSSwapAtomic(std::atomic<uint32be>* mem, uint32 newValue)\n\t{\n\t\tuint32be _newValue = newValue;\n\t\tuint32be previousValue = mem->exchange(_newValue);\n\t\treturn previousValue;\n\t}\n\n\tbool OSCompareAndSwapAtomic(std::atomic<uint32be>* mem, uint32 compareValue, uint32 swapValue)\n\t{\n\t\t// seen in GTA3 homebrew port\n\t\tuint32be _compareValue = compareValue;\n\t\tuint32be _swapValue = swapValue;\n\t\treturn mem->compare_exchange_strong(_compareValue, _swapValue);\n\t}\n\n\tbool OSCompareAndSwapAtomicEx(std::atomic<uint32be>* mem, uint32 compareValue, uint32 swapValue, uint32be* previousValue)\n\t{\n\t\t// seen in GTA3 homebrew port\n\t\tuint32be _compareValue = compareValue;\n\t\tuint32be _swapValue = swapValue;\n\t\tbool r = mem->compare_exchange_strong(_compareValue, _swapValue);\n\t\t*previousValue = _compareValue;\n\t\treturn r;\n\t}\n\n\tuint32 OSAddAtomic(std::atomic<uint32be>* mem, uint32 adder)\n\t{\n        // used by SDL Wii U port\n\t\tuint32be knownValue;\n\t\twhile (true)\n\t\t{\n\t\t\tknownValue = mem->load();\n\t\t\tuint32be newValue = knownValue + adder;\n\t\t\tif (mem->compare_exchange_strong(knownValue, newValue))\n\t\t\t\tbreak;\n\t\t}\n\t\treturn knownValue;\n\t}\n\n\t/* 64bit atomic operations */\n\n\tuint64 OSSwapAtomic64(std::atomic<uint64be>* mem, uint64 newValue)\n\t{\n\t\tuint64be _newValue = newValue;\n\t\tuint64be previousValue = mem->exchange(_newValue);\n\t\treturn previousValue;\n\t}\n\n\tuint64 OSSetAtomic64(std::atomic<uint64be>* mem, uint64 newValue)\n\t{\n\t\treturn OSSwapAtomic64(mem, newValue);\n\t}\n\n\tuint64 OSGetAtomic64(std::atomic<uint64be>* mem)\n\t{\n\t\treturn mem->load();\n\t}\n\n\tuint64 OSAddAtomic64(std::atomic<uint64be>* mem, uint64 adder)\n\t{\n\t\tuint64be knownValue;\n\t\twhile (true)\n\t\t{\n\t\t\tknownValue = mem->load();\n\t\t\tuint64be newValue = knownValue + adder;\n\t\t\tif (mem->compare_exchange_strong(knownValue, newValue))\n\t\t\t\tbreak;\n\t\t}\n\t\treturn knownValue;\n\t}\n\n\tuint64 OSAndAtomic64(std::atomic<uint64be>* mem, uint64 val)\n\t{\n\t\tuint64be knownValue;\n\t\twhile (true)\n\t\t{\n\t\t\tknownValue = mem->load();\n\t\t\tuint64be newValue = knownValue & val;\n\t\t\tif (mem->compare_exchange_strong(knownValue, newValue))\n\t\t\t\tbreak;\n\t\t}\n\t\treturn knownValue;\n\t}\n\n\tuint64 OSOrAtomic64(std::atomic<uint64be>* mem, uint64 val)\n\t{\n\t\tuint64be knownValue;\n\t\twhile (true)\n\t\t{\n\t\t\tknownValue = mem->load();\n\t\t\tuint64be newValue = knownValue | val;\n\t\t\tif (mem->compare_exchange_strong(knownValue, newValue))\n\t\t\t\tbreak;\n\t\t}\n\t\treturn knownValue;\n\t}\n\n\tbool OSCompareAndSwapAtomic64(std::atomic<uint64be>* mem, uint64 compareValue, uint64 swapValue)\n\t{\n\t\tuint64be _compareValue = compareValue;\n\t\tuint64be _swapValue = swapValue;\n\t\treturn mem->compare_exchange_strong(_compareValue, _swapValue);\n\t}\n\n\tbool OSCompareAndSwapAtomicEx64(std::atomic<uint64be>* mem, uint64 compareValue, uint64 swapValue, uint64be* previousValue)\n\t{\n\t\tuint64be _compareValue = compareValue;\n\t\tuint64be _swapValue = swapValue;\n\t\tbool r = mem->compare_exchange_strong(_compareValue, _swapValue);\n\t\t*previousValue = _compareValue;\n\t\treturn r;\n\t}\n\n\tvoid InitializeAtomic()\n\t{\n\t\t// 32bit atomic operations\n\t\tcafeExportRegister(\"coreinit\", OSSwapAtomic, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSCompareAndSwapAtomic, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSCompareAndSwapAtomicEx, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSAddAtomic, LogType::Placeholder);\n\t\t\n\t\t// 64bit atomic operations\n\t\tcafeExportRegister(\"coreinit\", OSSetAtomic64, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSGetAtomic64, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSSwapAtomic64, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSAddAtomic64, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSAndAtomic64, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSOrAtomic64, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSCompareAndSwapAtomic64, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSCompareAndSwapAtomicEx64, LogType::Placeholder);\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Atomic.h",
    "content": "#pragma once\n#include <atomic>\n\nnamespace coreinit\n{\n\tuint32 OSSwapAtomic(std::atomic<uint32be>* mem, uint32 newValue);\n\tbool OSCompareAndSwapAtomic(std::atomic<uint32be>* mem, uint32 compareValue, uint32 swapValue);\n\tbool OSCompareAndSwapAtomicEx(std::atomic<uint32be>* mem, uint32 compareValue, uint32 swapValue, uint32be* previousValue);\n\tuint32 OSAddAtomic(std::atomic<uint32be>* mem, uint32 adder);\n\t\n\tuint64 OSSwapAtomic64(std::atomic<uint64be>* mem, uint64 newValue);\n\tuint64 OSSetAtomic64(std::atomic<uint64be>* mem, uint64 newValue);\n\tuint64 OSGetAtomic64(std::atomic<uint64be>* mem);\n\tuint64 OSAddAtomic64(std::atomic<uint64be>* mem, uint64 adder);\n\tuint64 OSAndAtomic64(std::atomic<uint64be>* mem, uint64 val);\n\tuint64 OSOrAtomic64(std::atomic<uint64be>* mem, uint64 val);\n\tbool OSCompareAndSwapAtomic64(std::atomic<uint64be>* mem, uint64 compareValue, uint64 swapValue);\n\tbool OSCompareAndSwapAtomicEx64(std::atomic<uint64be>* mem, uint64 compareValue, uint64 swapValue, uint64be* previousValue);\n\n\tvoid InitializeAtomic();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_BSP.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"coreinit_BSP.h\"\n\nnamespace coreinit\n{\n\tbool bspGetHardwareVersion(uint32be* version)\n\t{\n\t\tuint8 highVersion = 0x11; // anything below 0x11 will be considered as Hollywood\n\t\t// todo: Check version returned on console\n\t\tuint32 tempVers = highVersion << 24;\n\t\t*version = tempVers;\n\t\treturn true;\n\t}\n\n\tvoid InitializeBSP()\n\t{\n\t\tcafeExportRegister(\"coreinit\", bspGetHardwareVersion, LogType::Placeholder);\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_BSP.h",
    "content": "namespace coreinit\n{\n\tvoid InitializeBSP();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Callbacks.cpp",
    "content": "#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"util/helpers/fspinlock.h\"\n\nstruct CoreinitAsyncCallback\n{\n\tCoreinitAsyncCallback(MPTR functionMPTR, uint32 numParameters, uint32 r3, uint32 r4, uint32 r5, uint32 r6, uint32 r7, uint32 r8, uint32 r9, uint32 r10) :\n\t\tm_functionMPTR(functionMPTR), m_numParameters(numParameters), m_gprParam{ r3, r4, r5, r6, r7, r8, r9, r10 } {};\n\n\tstatic void queue(MPTR functionMPTR, uint32 numParameters, uint32 r3, uint32 r4, uint32 r5, uint32 r6, uint32 r7, uint32 r8, uint32 r9, uint32 r10)\n\t{\n\t\ts_asyncCallbackSpinlock.lock();\n\t\ts_asyncCallbackQueue.emplace_back(allocateAndInitFromPool(functionMPTR, numParameters, r3, r4, r5, r6, r7, r8, r9, r10));\n\t\ts_asyncCallbackSpinlock.unlock();\n\t}\n\n\tstatic void callNextFromQueue()\n\t{\n\t\ts_asyncCallbackSpinlock.lock();\n\t\tif (s_asyncCallbackQueue.empty())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"AsyncCallbackQueue is empty. Unexpected behavior\");\n\t\t\ts_asyncCallbackSpinlock.unlock();\n\t\t\treturn;\n\t\t}\n\t\tCoreinitAsyncCallback* cb = s_asyncCallbackQueue[0];\n\t\ts_asyncCallbackQueue.erase(s_asyncCallbackQueue.begin());\n\t\ts_asyncCallbackSpinlock.unlock();\n\t\tcb->doCall();\n\t\ts_asyncCallbackSpinlock.lock();\n\t\treleaseToPool(cb);\n\t\ts_asyncCallbackSpinlock.unlock();\n\t}\n\nprivate:\n\tvoid doCall()\n\t{\n\t\tPPCCoreCallback(m_functionMPTR, m_gprParam[0], m_gprParam[1], m_gprParam[2], m_gprParam[3], m_gprParam[4], m_gprParam[5], m_gprParam[6], m_gprParam[7]);\n\t}\n\t\n\tstatic CoreinitAsyncCallback* allocateAndInitFromPool(MPTR functionMPTR, uint32 numParameters, uint32 r3, uint32 r4, uint32 r5, uint32 r6, uint32 r7, uint32 r8, uint32 r9, uint32 r10)\n\t{\n\t\tcemu_assert_debug(s_asyncCallbackSpinlock.is_locked());\n\t\tif (s_asyncCallbackPool.empty())\n\t\t{\n\t\t\tCoreinitAsyncCallback* cb = new CoreinitAsyncCallback(functionMPTR, numParameters, r3, r4, r5, r6, r7, r8, r9, r10);\n\t\t\treturn cb;\n\t\t}\n\t\tCoreinitAsyncCallback* cb = s_asyncCallbackPool[0];\n\t\ts_asyncCallbackPool.erase(s_asyncCallbackPool.begin());\n\n\t\t*cb = CoreinitAsyncCallback(functionMPTR, numParameters, r3, r4, r5, r6, r7, r8, r9, r10);\n\t\treturn cb;\n\t}\n\n\tstatic void releaseToPool(CoreinitAsyncCallback* cb)\n\t{\n\t\tcemu_assert_debug(s_asyncCallbackSpinlock.is_locked());\n\t\ts_asyncCallbackPool.emplace_back(cb);\n\t}\n\n\tstatic std::vector<struct CoreinitAsyncCallback*> s_asyncCallbackPool;\n\tstatic std::vector<struct CoreinitAsyncCallback*> s_asyncCallbackQueue;\n\tstatic FSpinlock s_asyncCallbackSpinlock;\n\n\tsint32\tm_numParameters;\n\tuint32\tm_gprParam[9];\n\tMPTR\tm_functionMPTR;\n};\n\nstd::vector<struct CoreinitAsyncCallback*> CoreinitAsyncCallback::s_asyncCallbackPool;\nstd::vector<struct CoreinitAsyncCallback*> CoreinitAsyncCallback::s_asyncCallbackQueue;\nFSpinlock CoreinitAsyncCallback::s_asyncCallbackSpinlock;\n\nSysAllocator<OSThread_t> g_coreinitCallbackThread;\nSysAllocator<uint8, 1024*64> _g_coreinitCallbackThreadStack;\nSysAllocator<coreinit::OSSemaphore> g_asyncCallbackAsync;\nSysAllocator<char, 32> _g_coreinitCBThreadName;\n\nvoid _coreinitCallbackThread(PPCInterpreter_t* hCPU)\n{\n\twhile (coreinit::OSWaitSemaphore(g_asyncCallbackAsync.GetPtr()))\n\t{\n\t\tCoreinitAsyncCallback::callNextFromQueue();\n\t}\n}\n\nvoid coreinitAsyncCallback_addWithLock(MPTR functionMPTR, uint32 numParameters, uint32 r3, uint32 r4, uint32 r5, uint32 r6, uint32 r7, uint32 r8, uint32 r9, uint32 r10)\n{\n\tcemu_assert_debug(numParameters <= 8);\n\tif (functionMPTR >= 0x10000000)\n\t{\n\t\tcemuLog_log(LogType::Force, fmt::format(\"Suspicious callback address {0:08x} params: {1:08x} {2:08x} {3:08x} {4:08x}\", functionMPTR, r3, r4, r5, r6));\n\t\tcemuLog_waitForFlush();\n\t}\n\tCoreinitAsyncCallback::queue(functionMPTR, numParameters, r3, r4, r5, r6, r7, r8, r9, r10);\n\t__OSLockScheduler();\n\tcoreinit::OSSignalSemaphoreInternal(g_asyncCallbackAsync.GetPtr(), false);\n\t__OSUnlockScheduler();\n}\n\nvoid coreinitAsyncCallback_add(MPTR functionMPTR, uint32 numParameters, uint32 r3, uint32 r4, uint32 r5, uint32 r6, uint32 r7, uint32 r8, uint32 r9, uint32 r10)\n{\n\tcemu_assert_debug(__OSHasSchedulerLock() == false); // do not call when holding scheduler lock\n\tcoreinitAsyncCallback_addWithLock(functionMPTR, numParameters, r3, r4, r5, r6, r7, r8, r9, r10);\n}\n\nvoid InitializeAsyncCallback()\n{\n\tcoreinit::OSInitSemaphore(g_asyncCallbackAsync.GetPtr(), 0);\n\n\tcoreinit::OSCreateThreadType(g_coreinitCallbackThread.GetPtr(), PPCInterpreter_makeCallableExportDepr(_coreinitCallbackThread), 0, nullptr, _g_coreinitCallbackThreadStack.GetPtr() + _g_coreinitCallbackThreadStack.GetByteSize(), (sint32)_g_coreinitCallbackThreadStack.GetByteSize(), 0, 7, OSThread_t::THREAD_TYPE::TYPE_IO);\n\tcoreinit::OSResumeThread(g_coreinitCallbackThread.GetPtr());\n\n\tstrcpy(_g_coreinitCBThreadName.GetPtr(), \"Callback Thread\");\n\tcoreinit::OSSetThreadName(g_coreinitCallbackThread.GetPtr(), _g_coreinitCBThreadName.GetPtr());\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_CodeGen.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_CodeGen.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n#include \"Common/ExceptionHandler/ExceptionHandler.h\"\n\nnamespace coreinit\n{\n\tstruct\n\t{\n\t\tbool rangeIsAllocated;\n\t\tMPTR rangeStart;\n\t\tuint32 rangeSize;\n\t\tuint8* cacheStateCopy; // holds a copy of the entire range, simulates icache state (updated via ICBI)\n\t}coreinitCodeGen = {0};\n\n\tvoid codeGenArea_memoryWriteCallback(void* pageStart, size_t size)\n\t{\n\t\tuint32 ea = memory_getVirtualOffsetFromPointer(pageStart);\n\t\tuint32 eaEnd = ea + (uint32)size;\n\t\twhile (ea <= eaEnd)\n\t\t{\n\t\t\tcodeGenHandleICBI(ea);\n\t\t\tea += 0x20;\n\t\t}\n\t}\n\n\tvoid OSGetCodegenVirtAddrRange(betype<uint32>* rangeStart, betype<uint32>* rangeSize)\n\t{\n\t\tuint32 codegenSize = 0x01000000; // todo: Read from cos.xml\n\t\t//debug_printf(\"OSGetCodegenVirtAddrRange(0x%08x,0x%08x)\\n\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\t// on first call, allocate range\n\t\tif( coreinitCodeGen.rangeIsAllocated == false )\n\t\t{\n\t\t\tcoreinitCodeGen.rangeStart = RPLLoader_AllocateCodeSpace(codegenSize, 0x1000);\n\t\t\tcoreinitCodeGen.rangeSize = codegenSize;\n\t\t\tcoreinitCodeGen.cacheStateCopy = new uint8[codegenSize];\n\t\t\tmemset(coreinitCodeGen.cacheStateCopy, 0, codegenSize);\n\t\t\tcoreinitCodeGen.rangeIsAllocated = true;\n\t\t}\n\t\t*rangeStart = coreinitCodeGen.rangeStart;\n\t\t*rangeSize = coreinitCodeGen.rangeSize;\n\t}\n\n\tvoid OSGetCodegenVirtAddrRangeInternal(uint32& rangeStart, uint32& rangeSize)\n\t{\n\t\tif (coreinitCodeGen.rangeIsAllocated == 0)\n\t\t{\n\t\t\trangeStart = 0;\n\t\t\trangeSize = 0;\n\t\t\treturn;\n\t\t}\n\t\trangeStart = coreinitCodeGen.rangeStart;\n\t\trangeSize = coreinitCodeGen.rangeSize;\n\t}\n\n\tvoid ICInvalidateRange(uint32 startAddress, uint32 size)\n\t{\n\t\tuint32 ea = startAddress & ~0x1F;\n\t\tuint32 eaEnd = (startAddress + size + 0x1F)&~0x1F;\n\t\twhile (ea <= eaEnd)\n\t\t{\n\t\t\tcodeGenHandleICBI(ea);\n\t\t\tea += 0x20;\n\t\t}\n\n\t}\n\n\tvoid coreinitExport_OSCodegenCopy(PPCInterpreter_t* hCPU)\n\t{\n\t\tif( coreinitCodeGen.rangeIsAllocated == false )\n\t\t\tassert_dbg();\n\n\t\tuint32 codeAddrDest = hCPU->gpr[3];\n\t\tuint32 memAddrSrc = hCPU->gpr[4];\n\t\tuint32 size = hCPU->gpr[5];\n\n\t\tif( codeAddrDest < coreinitCodeGen.rangeStart || codeAddrDest >= (coreinitCodeGen.rangeStart+coreinitCodeGen.rangeSize) )\n\t\t\tassert_dbg();\n\t\tif( (codeAddrDest+size) < coreinitCodeGen.rangeStart || (codeAddrDest+size) > (coreinitCodeGen.rangeStart+coreinitCodeGen.rangeSize) )\n\t\t\tassert_dbg();\n\n\t\tmemcpy(memory_getPointerFromVirtualOffset(codeAddrDest), memory_getPointerFromVirtualOffset(memAddrSrc), size);\n\n\t\t// invalidate recompiler range\n\t\tuint32 ea = codeAddrDest & ~0x1F;\n\t\tuint32 eaEnd = (codeAddrDest + size + 0x1F)&~0x1F;\n\t\twhile (ea <= eaEnd)\n\t\t{\n\t\t\tcodeGenHandleICBI(ea);\n\t\t\tea += 0x20;\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid codeGenHandleICBI(uint32 ea)\n\t{\n\t\tcemu_assert_debug((ea & 0x1F) == 0);\n\t\tif (coreinitCodeGen.rangeIsAllocated == false)\n\t\t\treturn;\n\t\tcemu_assert_debug((coreinitCodeGen.rangeStart & 0x1F) == 0);\n\t\tcemu_assert_debug((coreinitCodeGen.rangeSize & 0x1F) == 0);\n\t\tif (ea >= coreinitCodeGen.rangeStart && ea < (coreinitCodeGen.rangeStart + coreinitCodeGen.rangeSize))\n\t\t{\n\t\t\tuint8* cacheCopy = coreinitCodeGen.cacheStateCopy + (ea - coreinitCodeGen.rangeStart);\n\t\t\tuint8* currentState = memory_getPointerFromVirtualOffset(ea);\n\t\t\tif (memcmp(currentState, cacheCopy, 32) != 0)\n\t\t\t{\n\t\t\t\t// instructions changed\n\t\t\t\t// flush cache\n\t\t\t\tPPCRecompiler_invalidateRange(ea, ea+0x20);\n\t\t\t\t// update icache copy\n\t\t\t\tmemcpy(cacheCopy, currentState, 32);\n\t\t\t}\n\t\t}\n\t}\n\n\tbool _avoidCodeGenJIT = false;\n\n\t// currently we dont handle code invalidation well for direct write access\n\t// therefore if we detect attempts to write we will disable JITing the area\n\tbool codeGenShouldAvoid()\n\t{\n\t\treturn _avoidCodeGenJIT;\n\t}\n\n\tbool OSSwitchSecCodeGenMode(bool isRXOnly)\n\t{\n\t\tif (!_avoidCodeGenJIT)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Disable JIT on dynamic code area\");\n\t\t}\n\t\t_avoidCodeGenJIT = true; // this function getting called is usually a sign that \n\t\t// does this have a return value?\n\t\treturn true;\n\t}\n\n\tvoid InitializeCodeGen()\n\t{\n\t\tcafeExportRegister(\"coreinit\", OSGetCodegenVirtAddrRange, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", ICInvalidateRange, LogType::Placeholder);\n\n\t\tosLib_addFunction(\"coreinit\", \"OSCodegenCopy\", coreinitExport_OSCodegenCopy);\n\n\t\tcafeExportRegister(\"coreinit\", OSSwitchSecCodeGenMode, LogType::Placeholder);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_CodeGen.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tvoid OSGetCodegenVirtAddrRangeInternal(uint32& rangeStart, uint32& rangeSize);\n\tvoid codeGenHandleICBI(uint32 ea);\n\tbool codeGenShouldAvoid();\n\n\tvoid InitializeCodeGen();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Coroutine.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Coroutine.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"Cafe/HW/MMU/MMU.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n\nnamespace coreinit\n{\n\tstatic_assert(sizeof(OSCoroutine) == 0x180);\n\n\tstatic uint32 s_PPCAddrOSSwitchCoroutineAfterOSLoadCoroutine = 0;\n\n\tvoid coreinitExport_OSInitCoroutine(PPCInterpreter_t* hCPU)\n\t{\n\t\tOSCoroutine* coroutine = (OSCoroutine*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\tcoroutine->lr = _swapEndianU32(hCPU->gpr[4]);\n\t\tcoroutine->r1 = _swapEndianU32(hCPU->gpr[5]);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid coreinitCoroutine_OSSaveCoroutine(OSCoroutine* coroutine, PPCInterpreter_t* hCPU)\n\t{\n\t\tcoroutine->lr = _swapEndianU32(hCPU->spr.LR);\n\t\tcoroutine->cr = _swapEndianU32(ppc_getCR(hCPU));\n\t\tcoroutine->gqr1 = _swapEndianU32(hCPU->spr.UGQR[1]);\n\t\tcoroutine->r1 = _swapEndianU32(hCPU->gpr[1]);\n\t\tcoroutine->r2 = _swapEndianU32(hCPU->gpr[2]);\n\t\tcoroutine->r13 = _swapEndianU32(hCPU->gpr[13]);\n\t\tfor (sint32 i = 14; i < 32; i++)\n\t\t\tcoroutine->gpr[i - 14] = _swapEndianU32(hCPU->gpr[i]);\n\t\tfor (sint32 i = 14; i < 32; i++)\n\t\t{\n\t\t\tcoroutine->fpr[i - 14] = _swapEndianU64(hCPU->fpr[i].fp0int);\n\t\t}\n\t\tfor (sint32 i = 14; i < 32; i++)\n\t\t{\n\t\t\tcoroutine->psr[i - 14] = _swapEndianU64(hCPU->fpr[i].fp1int);\n\t\t}\n\t}\n\n\tvoid coreinitCoroutine_OSLoadCoroutine(OSCoroutine* coroutine, PPCInterpreter_t* hCPU)\n\t{\n\t\thCPU->spr.LR = _swapEndianU32(coroutine->lr);\n\t\tppc_setCR(hCPU, _swapEndianU32(coroutine->cr));\n\t\thCPU->spr.UGQR[1] = _swapEndianU32(coroutine->gqr1);\n\t\thCPU->gpr[1] = _swapEndianU32(coroutine->r1);\n\t\thCPU->gpr[2] = _swapEndianU32(coroutine->r2);\n\t\thCPU->gpr[13] = _swapEndianU32(coroutine->r13);\n\t\tfor (sint32 i = 14; i < 32; i++)\n\t\t\thCPU->gpr[i] = _swapEndianU32(coroutine->gpr[i - 14]);\n\t\tfor (sint32 i = 14; i < 32; i++)\n\t\t{\n\t\t\thCPU->fpr[i].fp0int = _swapEndianU64(coroutine->fpr[i - 14]);\n\t\t}\n\t\tfor (sint32 i = 14; i < 32; i++)\n\t\t{\n\t\t\thCPU->fpr[i].fp1int = _swapEndianU64(coroutine->psr[i - 14]);\n\t\t}\n\t}\n\n\tvoid coreinitExport_OSSwitchCoroutine(PPCInterpreter_t* hCPU)\n\t{\n\t\t// OSSwitchCoroutine is a wrapper for OSSaveCoroutine + OSLoadCoroutine but it has side effects that we need to care about:\n\t\t// r31 is saved and restored via the stack in OSSwitchCoroutine\n\t\t// r4 is stored in the r31 field of coroutineCurrent. Injustice: Gods Among Us reads the r31 field and expects it to match coroutineCurrent (0x027183D4 @ EU v16)\n\t\tOSCoroutine* coroutineCurrent = MEMPTR<OSCoroutine>(hCPU->gpr[3]);\n\t\tOSCoroutine* coroutineNext = MEMPTR<OSCoroutine>(hCPU->gpr[4]);\n\t\thCPU->gpr[1] -= 0x10;\n\t\tmemory_writeU32(hCPU->gpr[1]+0xC, hCPU->gpr[31]);\n\t\tmemory_writeU32(hCPU->gpr[1]+0x14, hCPU->spr.LR);\n\t\thCPU->spr.LR = s_PPCAddrOSSwitchCoroutineAfterOSLoadCoroutine;\n\t\thCPU->gpr[31] = hCPU->gpr[4];\n\t\tcoreinitCoroutine_OSSaveCoroutine(coroutineCurrent, hCPU);\n\t\thCPU->gpr[3] = hCPU->gpr[31];\n\t\thCPU->gpr[4] = 1;\n\t\tcoreinitCoroutine_OSLoadCoroutine(coroutineNext, hCPU);\n\t\thCPU->instructionPointer = hCPU->spr.LR;\n\t}\n\n\tvoid coreinitExport_OSSwitchCoroutineAfterOSLoadCoroutine(PPCInterpreter_t* hCPU)\n\t{\n\t\t// resuming after OSSaveCoroutine\n\t\thCPU->gpr[31] = memory_readU32(hCPU->gpr[1]+0xC);\n\t\thCPU->spr.LR = memory_readU32(hCPU->gpr[1]+0x14);\n\t\thCPU->gpr[1] += 0x10;\n\t\thCPU->instructionPointer = hCPU->spr.LR;\n\t}\n\n\tvoid coreinitExport_OSSwitchFiberEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(param0, 0);\n\t\tppcDefineParamU32(param1, 1);\n\t\tppcDefineParamU32(param2, 2);\n\t\tppcDefineParamU32(param3, 3);\n\t\tppcDefineParamMPTR(newInstructionPointer, 4);\n\t\tppcDefineParamMPTR(newStackPointer, 5);\n\n\t\tMPTR prevStackpointer = hCPU->gpr[1];\n\t\thCPU->gpr[1] = newStackPointer;\n\t\thCPU->gpr[3] = param0;\n\t\thCPU->gpr[4] = param1;\n\t\thCPU->gpr[5] = param2;\n\t\thCPU->gpr[6] = param3;\n\n\t\tPPCCore_executeCallbackInternal(newInstructionPointer);\n\t\tuint32 returnValue = hCPU->gpr[3];\n\n\t\thCPU->gpr[1] = prevStackpointer;\n\n\t\tosLib_returnFromFunction(hCPU, returnValue);\n\t}\n\n\tvoid InitializeCoroutine()\n\t{\n\t\tosLib_addFunction(\"coreinit\", \"OSInitCoroutine\", coreinitExport_OSInitCoroutine);\n\t\tosLib_addFunction(\"coreinit\", \"OSSwitchCoroutine\", coreinitExport_OSSwitchCoroutine);\n\t\tosLib_addFunction(\"coreinit\", \"OSSwitchFiberEx\", coreinitExport_OSSwitchFiberEx);\n\n\t\ts_PPCAddrOSSwitchCoroutineAfterOSLoadCoroutine = RPLLoader_MakePPCCallable(coreinitExport_OSSwitchCoroutineAfterOSLoadCoroutine);\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Coroutine.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tstruct OSCoroutine\n\t{\n\t\t/* +0x00 */ uint32 lr;\n\t\t/* +0x04 */ uint32 cr;\n\t\t/* +0x08 */ uint32 gqr1;\n\t\t/* +0x0C */ uint32 r1;  // stack pointer\n\t\t/* +0x10 */ uint32 r2;\n\t\t/* +0x14 */ uint32 r13;\n\t\t/* +0x18 */ uint32 gpr[18];\n\t\tuint64 fpr[18];\n\t\tuint64 psr[18];\n\t};\n\n\tstatic_assert(sizeof(OSCoroutine) == 0x180);\n\n\tvoid InitializeCoroutine();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_DynLoad.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n\nnamespace coreinit\n{\n\tMPTR _osDynLoadFuncAlloc = MPTR_NULL;\n\tMPTR _osDynLoadFuncFree = MPTR_NULL;\n\tMPTR _osDynLoadTLSFuncAlloc = MPTR_NULL;\n\tMPTR _osDynLoadTLSFuncFree = MPTR_NULL;\n\n\tuint32 OSDynLoad_SetAllocator(MPTR allocFunc, MPTR freeFunc)\n\t{\n\t\t_osDynLoadFuncAlloc = allocFunc;\n\t\t_osDynLoadFuncFree = freeFunc;\n\t\treturn 0;\n\t}\n\n\tvoid OSDynLoad_SetTLSAllocator(MPTR allocFunc, MPTR freeFunc)\n\t{\n\t\t_osDynLoadTLSFuncAlloc = allocFunc;\n\t\t_osDynLoadTLSFuncFree = freeFunc;\n\t}\n\n\tuint32 OSDynLoad_GetAllocator(betype<MPTR>* funcAlloc, betype<MPTR>* funcFree)\n\t{\n\t\t*funcAlloc = _osDynLoadFuncAlloc;\n\t\t*funcFree = _osDynLoadFuncFree;\n\t\treturn 0;\n\t}\n\n\tvoid OSDynLoad_GetTLSAllocator(betype<MPTR>* funcAlloc, betype<MPTR>* funcFree)\n\t{\n\t\t*funcAlloc = _osDynLoadTLSFuncAlloc;\n\t\t*funcFree = _osDynLoadTLSFuncFree;\n\t}\n\n\tvoid* OSDynLoad_AllocatorAlloc(sint32 size, sint32 alignment)\n\t{\n\t\tif (_osDynLoadFuncAlloc == MPTR_NULL)\n\t\t\treturn MPTR_NULL;\n\t\tStackAllocator<MEMPTR<void>> _ptrStorage;\n\t\tint r = PPCCoreCallback(_osDynLoadFuncAlloc, size, alignment, _ptrStorage.GetMPTR());\n\t\tif (r != 0)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn MPTR_NULL;\n\t\t}\n\t\treturn _ptrStorage->GetPtr();\n\t}\n\n\tvoid OSDynLoad_AllocatorFree(void* mem)\n\t{\n\t\tif (_osDynLoadFuncFree == MPTR_NULL)\n\t\t\treturn;\n\t\tMEMPTR<void> _mem = mem;\n\t\tPPCCoreCallback(_osDynLoadFuncFree, _mem);\n\t}\n\n\tuint32 OSDynLoad_Acquire(const char* libName, uint32be* moduleHandleOut)\n\t{\n\t\t// truncate path\n\t\tsint32 fileNameStartIndex = 0;\n\t\tsint32 tempLen = (sint32)strlen(libName);\n\t\tfor (sint32 i = tempLen - 1; i >= 0; i--)\n\t\t{\n\t\t\tif (libName[i] == '/')\n\t\t\t{\n\t\t\t\tfileNameStartIndex = i + 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// truncate file extension \n\t\tchar tempLibName[512];\n\t\tstrcpy(tempLibName, libName + fileNameStartIndex);\n\t\ttempLen = (sint32)strlen(tempLibName);\n\t\tfor (sint32 i = tempLen - 1; i >= 0; i--)\n\t\t{\n\t\t\tif (tempLibName[i] == '.')\n\t\t\t{\n\t\t\t\ttempLibName[i] = '\\0';\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// search for loaded modules with matching name\n\t\tuint32 rplHandle = RPLLoader_GetHandleByModuleName(libName);\n\t\tif (rplHandle == RPL_INVALID_HANDLE && !RPLLoader_HasDependency(libName))\n\t\t{\n\t\t\tRPLLoader_AddDependency(libName);\n\t\t\tRPLLoader_UpdateDependencies();\n\t\t\tRPLLoader_Link();\n\t\t\tRPLLoader_CallEntrypoints();\n\t\t\trplHandle = RPLLoader_GetHandleByModuleName(libName);\n\t\t}\n\t\tif (rplHandle == RPL_INVALID_HANDLE)\n\t\t\t*moduleHandleOut = 0;\n\t\telse\n\t\t\t*moduleHandleOut = rplHandle;\n\t\tif (rplHandle == RPL_INVALID_HANDLE)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"OSDynLoad_Acquire() failed to load module '{}'\", libName);\n\t\t\treturn 0xFFFCFFE9; // module not found\n\t\t}\n\t\treturn 0;\n\t}\n\n\tvoid OSDynLoad_Release(uint32 moduleHandle)\n\t{\n\t\tif (moduleHandle == RPL_INVALID_HANDLE)\n\t\t\treturn;\n\t\tRPLLoader_RemoveDependency(moduleHandle);\n\t\tRPLLoader_UpdateDependencies();\n\t}\n\n\tuint32 OSDynLoad_FindExport(uint32 moduleHandle, uint32 isData, const char* exportName, betype<MPTR>* addrOut)\n\t{\n\t\tif (moduleHandle == 0xFFFFFFFF)\n\t\t{\n\t\t\t// main module\n\t\t\t// Assassins Creed 4 has this handle hardcoded\n\t\t\tmoduleHandle = RPLLoader_GetMainModuleHandle();\n\t\t}\n\n\t\tMPTR exportResult = RPLLoader_FindModuleOrHLEExport(moduleHandle, isData, exportName);\n\t\t*addrOut = exportResult;\n\n\t\tif (exportResult == MPTR_NULL)\n\t\t\treturn 0xFFFFFFFF;\n\t\treturn 0;\n\t}\n\n\tvoid InitializeDynLoad()\n\t{\n\t\tcafeExportRegister(\"coreinit\", OSDynLoad_SetAllocator, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSDynLoad_SetTLSAllocator, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSDynLoad_GetAllocator, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSDynLoad_GetTLSAllocator, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", OSDynLoad_Acquire, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSDynLoad_Release, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSDynLoad_FindExport, LogType::Placeholder);\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tuint32 OSDynLoad_SetAllocator(MPTR allocFunc, MPTR freeFunc);\n\tvoid OSDynLoad_SetTLSAllocator(MPTR allocFunc, MPTR freeFunc);\n\tuint32 OSDynLoad_GetAllocator(betype<MPTR>* funcAlloc, betype<MPTR>* funcFree);\n\tvoid OSDynLoad_GetTLSAllocator(betype<MPTR>* funcAlloc, betype<MPTR>* funcFree);\n\n\tvoid* OSDynLoad_AllocatorAlloc(sint32 size, sint32 alignment);\n\tvoid OSDynLoad_AllocatorFree(void* mem);\n\n\tuint32 OSDynLoad_Acquire(const char* libName, uint32be* moduleHandleOut);\n\tvoid OSDynLoad_Release(uint32 moduleHandle);\n\tuint32 OSDynLoad_FindExport(uint32 moduleHandle, uint32 isData, const char* exportName, betype<MPTR>* addrOut);\n\n\tvoid InitializeDynLoad();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_FG.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include <memory>\n\n#define FG_BUCKET_AREA_FREE\t\t\t\t\t0\t// free area available game\n#define FG_BUCKET_AREA_AUDIO_TRANSITION\t\t1\t// transition audio buffer\n#define FG_BUCKET_AREA2\t\t\t\t\t\t2\t// frame storage?\tTV?\n#define FG_BUCKET_AREA3\t\t\t\t\t\t3\t// frame storage?\tDRC?\n#define FG_BUCKET_AREA4\t\t\t\t\t\t4\t// frame storage?\tTV?\n#define FG_BUCKET_AREA5\t\t\t\t\t\t5\t// frame storage?\tDRC?\n#define FG_BUCKET_AREA_SAVE\t\t\t\t\t6\n#define FG_BUCKET_AREA_COPY\t\t\t\t\t7\t// for OS copy data (clipboard and title switch parameters)\n\n#define FG_BUCKET_AREA_FREE_SIZE\t\t\t0x2800000\n#define FG_BUCKET_AREA_SAVE_SIZE\t\t\t0x1000\n#define FG_BUCKET_AREA_COPY_SIZE\t\t\t0x400000\n\n#define FG_BUCKET_AREA_COUNT\t8\n\nnamespace coreinit\n{\n\tMEMPTR<void> fgAddr = nullptr; // NULL if not in foreground\n\tMEMPTR<uint8> fgSaveAreaAddr = nullptr;\n\n\tstruct\n\t{\n\t\tuint32 id;\n\t\tuint32 startOffset;\n\t\tuint32 size;\n\t}fgAreaEntries[FG_BUCKET_AREA_COUNT] =\n\t{\n\t\t{ 0, 0, 0x2800000 },\n\t\t{ 7, 0x2800000, 0x400000 },\n\t\t{ 1, 0x2C00000, 0x900000 },\n\t\t{ 2, 0x3500000, 0x3C0000 },\n\t\t{ 3, 0x38C0000, 0x1C0000 },\n\t\t{ 4, 0x3A80000, 0x3C0000 },\n\t\t{ 5, 0x3E40000, 0x1BF000 },\n\t\t{ 6, 0x3FFF000, 0x1000 }\n\t};\n\n\tMEMPTR<uint8> GetFGMemByArea(uint32 areaId)\n\t{\n\t\tif (fgAddr == nullptr)\n\t\t\treturn nullptr;\n\t\tfor (sint32 i = 0; i < FG_BUCKET_AREA_COUNT; i++)\n\t\t{\n\t\t\tif (fgAreaEntries[i].id == areaId)\n\t\t\t\treturn MEMPTR<uint8>(fgAddr.GetPtr<uint8>() + fgAreaEntries[i].startOffset);\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\n\tbool OSGetForegroundBucket(MEMPTR<void>* offset, uint32be* size)\n\t{\n\t\t// return full size of foreground bucket area\n\t\tif (offset)\n\t\t\t*offset = { (MPTR)MEMORY_FGBUCKET_AREA_ADDR };\n\t\tif (size)\n\t\t\t*size = MEMORY_FGBUCKET_AREA_SIZE;\n\t\t// return true if in foreground\n\t\treturn true;\n\t}\n\n\tbool OSGetForegroundBucketFreeArea(MEMPTR<void>* offset, uint32be* size)\n\t{\n\t\tuint8* freeAreaAddr = GetFGMemByArea(FG_BUCKET_AREA_FREE).GetPtr();\n\t\t*offset = freeAreaAddr;\n\t\t*size = FG_BUCKET_AREA_FREE_SIZE;\n\t\t// return true if in foreground\n\t\treturn (fgAddr != nullptr);\n\t}\n\n\tvoid coreinitExport_OSGetForegroundBucket(PPCInterpreter_t* hCPU)\n\t{\n\t\t//debug_printf(\"OSGetForegroundBucket(0x%x,0x%x)\\n\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\t// returns the whole FG bucket area (if the current process is in the foreground)\n\t\tppcDefineParamMPTR(areaOutput, 0);\n\t\tppcDefineParamMPTR(areaSize, 1);\n\t\tbool r = OSGetForegroundBucket((MEMPTR<void>*)memory_getPointerFromVirtualOffsetAllowNull(areaOutput), (uint32be*)memory_getPointerFromVirtualOffsetAllowNull(areaSize));\n\t\tosLib_returnFromFunction(hCPU, r ? 1 : 0);\n\t}\n\n\tvoid InitForegroundBucket()\n\t{\n\t\tuint32be fgSize;\n\t\tOSGetForegroundBucket(&fgAddr, &fgSize);\n\t\tuint8* freeAreaPtr = GetFGMemByArea(FG_BUCKET_AREA_FREE).GetPtr();\n\t\tmemset(freeAreaPtr, 0, FG_BUCKET_AREA_FREE_SIZE);\n\t\tuint8* saveAreaPtr = GetFGMemByArea(FG_BUCKET_AREA_SAVE).GetPtr();\n\t\tfgSaveAreaAddr = saveAreaPtr;\n\t\tif (*(uint32be*)saveAreaPtr != (uint32be)'Save')\n\t\t{\n\t\t\t// clear save area\n\t\t\tmemset(saveAreaPtr, 0, FG_BUCKET_AREA_SAVE_SIZE);\n\t\t\t// clear copy area\n\t\t\tmemset(GetFGMemByArea(FG_BUCKET_AREA_COPY).GetPtr(), 0, FG_BUCKET_AREA_COPY_SIZE);\n\t\t\t// init save area\n\t\t\t*(uint32be*)(saveAreaPtr + 0x00) = 'Save';\n\t\t\t*(uint32be*)(saveAreaPtr + 0x08) |= 0x300;\n\t\t}\n\t}\n\n\tvoid __OSClearCopyData()\n\t{\n\t\tuint8* fgCopyArea = GetFGMemByArea(FG_BUCKET_AREA_COPY).GetPtr();\n\t\tif (fgCopyArea)\n\t\t{\n\t\t\t*(uint32be*)(fgCopyArea + 0x00) = 0;\n\t\t}\n\t}\n\n\tuint32 __OSGetCopyDataSize()\n\t{\n\t\tuint8* fgCopyArea = GetFGMemByArea(FG_BUCKET_AREA_COPY).GetPtr();\n\t\tif (fgCopyArea)\n\t\t{\n\t\t\treturn *(uint32be*)(fgCopyArea + 0x00);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tuint8* __OSGetCopyDataPtr()\n\t{\n\t\tuint8* fgCopyArea = GetFGMemByArea(FG_BUCKET_AREA_COPY).GetPtr();\n\t\tif (fgCopyArea)\n\t\t\treturn fgCopyArea + 4;\n\t\treturn nullptr;\n\t}\n\n\tbool __OSAppendCopyData(uint8* data, sint32 length)\n\t{\n\t\tuint8* fgCopyArea = GetFGMemByArea(FG_BUCKET_AREA_COPY).GetPtr();\n\t\tif (fgCopyArea == nullptr)\n\t\t\treturn false;\n\t\tuint32 currentOffset = *(uint32be*)(fgCopyArea + 0x00);\n\t\tif ((currentOffset + length) > FG_BUCKET_AREA_COPY_SIZE - 4)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\tmemcpy(fgCopyArea + currentOffset + 4, data, length);\n\t\t*(uint32be*)(fgCopyArea + 0x00) += length;\n\t\treturn true;\n\t}\n\n\tbool __OSResizeCopyData(sint32 length)\n\t{\n\t\tuint8* fgCopyArea = GetFGMemByArea(FG_BUCKET_AREA_COPY).GetPtr();\n\t\tif (fgCopyArea == nullptr)\n\t\t\treturn false;\n\t\tsint32 currentOffset = (sint32) * (uint32be*)(fgCopyArea + 0x00);\n\t\tif (length < currentOffset)\n\t\t{\n\t\t\t// can only make copy data smaller\n\t\t\t*(uint32be*)(fgCopyArea + 0x00) = length;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool OSCopyFromClipboard(void* data, uint32be* size)\n\t{\n\t\tuint32 cSize = *size;\n\t\tif (cSize == 0 && data == nullptr)\n\t\t\treturn false;\n\t\tif (OSGetForegroundBucket(nullptr, nullptr) == false)\n\t\t\treturn false;\n\n\t\t// todo\n\n\t\t*size = 0;\n\t\treturn true;\n\t}\n\n\tvoid coreinitExport_OSCopyFromClipboard(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"OSCopyFromClipboard(0x{:x},0x{:x})\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\tppcDefineParamMEMPTR(buffer, void, 0);\n\t\tppcDefineParamMEMPTR(size, uint32be, 1);\n\t\tbool r = OSCopyFromClipboard(buffer.GetPtr(), size.GetPtr());\n\t\tosLib_returnFromFunction(hCPU, r ? 1 : 0);\n\t}\n\n\tvoid InitializeFG()\n\t{\n\t\tosLib_addFunction(\"coreinit\", \"OSGetForegroundBucket\", coreinitExport_OSGetForegroundBucket);\n\t\tcafeExportRegister(\"coreinit\", OSGetForegroundBucket, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", OSGetForegroundBucketFreeArea, LogType::CoreinitMem);\n\t\tosLib_addFunction(\"coreinit\", \"OSCopyFromClipboard\", coreinitExport_OSCopyFromClipboard);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_FG.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tvoid __OSClearCopyData();\n\tuint32 __OSGetCopyDataSize();\n\tuint8* __OSGetCopyDataPtr();\n\tbool __OSAppendCopyData(uint8* data, sint32 length);\n\tbool __OSResizeCopyData(sint32 length);\n\n\tbool OSGetForegroundBucket(MEMPTR<void>* offset, uint32be* size);\n\tbool OSGetForegroundBucketFreeArea(MEMPTR<void>* offset, uint32be* size);\n\n\tvoid InitForegroundBucket();\n\n\tvoid InitializeFG();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_FS.cpp",
    "content": "#include <OS/RPL/rpl.h>\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_SystemInfo.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_FS.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MessageQueue.h\"\n#include \"util/helpers/Semaphore.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/IOSU/iosu_ipc_common.h\"\n#include \"coreinit_IPC.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n#include \"coreinit_IPCBuf.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/TitleList/TitleInfo.h\"\n\n#define FS_CB_PLACEHOLDER_FINISHCMD (MPTR)(0xF122330E)\n\n// return false if src+'\\0' does not fit into dst\ntemplate<std::size_t Size>\nbool strcpy_whole(char (&dst)[Size], const char* src)\n{\n\tsize_t inputLength = strlen(src);\n\tif ((inputLength + 1) > Size)\n\t{\n\t\tdst[0] = '\\0';\n\t\treturn false;\n\t}\n\tstrcpy(dst, src);\n\treturn true;\n}\n\nbool strcpy_whole(char* dst, size_t dstLength, const char* src)\n{\n\tsize_t inputLength = strlen(src);\n\tif ((inputLength + 1) > dstLength)\n\t{\n\t\tdst[0] = '\\0';\n\t\treturn false;\n\t}\n\tstrcpy(dst, src);\n\treturn true;\n}\n\nnamespace coreinit\n{\n\tSysAllocator<OSMutex> s_fsGlobalMutex;\n\n\tinline void FSLockMutex()\n\t{\n\t\tOSLockMutex(&s_fsGlobalMutex);\n\t}\n\n\tinline void FSUnlockMutex()\n\t{\n\t\tOSUnlockMutex(&s_fsGlobalMutex);\n\t}\n\n\tvoid _debugVerifyCommand(const char* stage, FSCmdBlockBody* fsCmdBlockBody);\n\n\tbool sFSInitialized = true; // this should be false but it seems like some games rely on FSInit being called before main()? Twilight Princess for example reads files before it calls FSInit\n\tbool sFSShutdown = false;\n\n\tenum class MOUNT_TYPE : uint32\n\t{\n\t\tSD = 0,\n\t\t// 1 = usb?\n\t};\n\n\tstruct FS_MOUNT_SOURCE\n\t{\n\t\tuint32be sourceType; // ukn values\n\t\tchar path[128];\t\t // todo - determine correct length\n\t};\n\n\tFS_RESULT FSGetMountSourceNext(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, MOUNT_TYPE mountSourceType, FS_MOUNT_SOURCE* mountSourceInfo, FS_ERROR_MASK errMask)\n\t{\n\t\tif (mountSourceType == MOUNT_TYPE::SD)\n\t\t{\n\t\t\t// This function is supposed to be called after an initial FSGetMountSource call => always returns FS_RESULT::END_ITERATION because we only have one SD Card\n\t\t\t// It *might* causes issues if this function is called for getting the first MountSource (instead of \"FSGetMountSource\")\n\t\t\tcemu_assert_suspicious();\n\t\t\treturn FS_RESULT::END_ITERATION;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\treturn FS_RESULT::END_ITERATION;\n\t}\n\n\tFS_RESULT FSGetMountSource(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, MOUNT_TYPE mountSourceType, FS_MOUNT_SOURCE* mountSourceInfo, FS_ERROR_MASK errMask)\n\t{\n\t\t// This implementation is simplified A LOT compared to what the Wii U is actually doing. On Cemu we expect to only have one mountable source (SD Card) anyway,\n\t\t// so we can just hard code it. Other mount types are not (yet) supported.\n\t\tif (mountSourceType == MOUNT_TYPE::SD)\n\t\t{\n\t\t\t// check for SD card permissions (from cos.xml)\n\t\t\t// One Piece relies on failing here, otherwise it will call FSGetMountSource in an infinite loop\n\t\t\tCosCapabilityBitsFS perms = static_cast<CosCapabilityBitsFS>(CafeSystem::GetForegroundTitleCosCapabilities(CosCapabilityGroup::FS));\n\t\t\tif(!HAS_FLAG(perms, CosCapabilityBitsFS::SDCARD_MOUNT))\n\t\t\t{\n\t\t\t\tcemuLog_logOnce(LogType::Force, \"Title is trying to access SD card mount info without having SD card permissions. This may not be a bug\");\n\t\t\t\treturn FS_RESULT::END_ITERATION;\n\t\t\t}\n\t\t\tmountSourceInfo->sourceType = 0;\n\t\t\tstrcpy(mountSourceInfo->path, \"/sd\");\n\t\t\treturn FS_RESULT::SUCCESS;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\treturn FS_RESULT::END_ITERATION;\n\t}\n\n\tbool _sdCard01Mounted = false;\n\tbool _mlc01Mounted = false;\n\n\tvoid mountSDCard()\n\t{\n\t\tif (_sdCard01Mounted)\n\t\t\treturn;\n\n\t\tstd::error_code ec;\n\t\tconst auto path = ActiveSettings::GetUserDataPath(\"sdcard/\");\n\t\tfs::create_directories(path, ec);\n\t\tFSCDeviceHostFS_Mount(\"/vol/external01\", _pathToUtf8(path), FSC_PRIORITY_BASE);\n\n\t\t_sdCard01Mounted = true;\n\t}\n\n\tFS_RESULT FSMount(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FS_MOUNT_SOURCE* mountSourceInfo, char* mountPathOut, sint32 mountPathMaxLength, FS_ERROR_MASK errMask)\n\t{\n\t\tif (mountSourceInfo->sourceType != 0)\n\t\t{\n\t\t\treturn FS_RESULT::ERR_PLACEHOLDER;\n\t\t}\n\n\t\tif (!strcmp(mountSourceInfo->path, \"/sd\"))\n\t\t{\n\t\t\tconst char* sdMountPath = \"/vol/external01\";\n\t\t\t// note: mount path should not end with a slash\n\t\t\tif (!strcpy_whole(mountPathOut, mountPathMaxLength, sdMountPath))\n\t\t\t\treturn FS_RESULT::ERR_PLACEHOLDER; // string does not fit\n\t\t\tmountSDCard();\n\t\t}\n\n\t\treturn FS_RESULT::SUCCESS;\n\t}\n\n\tFS_RESULT FSBindMount(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* mountPathSrc, char* mountPathOut, FS_ERROR_MASK errMask)\n\t{\n\t\tif (strcmp(mountPathSrc, \"/dev/sdcard01\") == 0)\n\t\t{\n\t\t\tif (_sdCard01Mounted)\n\t\t\t\treturn FS_RESULT::ERR_PLACEHOLDER;\n\n\t\t\tstd::error_code ec;\n\t\t\tconst auto path = ActiveSettings::GetUserDataPath(\"sdcard/\");\n\t\t\tfs::create_directories(path, ec);\n\t\t\tif (!FSCDeviceHostFS_Mount(mountPathOut, _pathToUtf8(path), FSC_PRIORITY_BASE))\n\t\t\t\treturn FS_RESULT::ERR_PLACEHOLDER;\n\t\t\t_sdCard01Mounted = true;\n\t\t}\n\t\telse if (strcmp(mountPathSrc, \"/dev/mlc01\") == 0)\n\t\t{\n\t\t\tif (_mlc01Mounted)\n\t\t\t\treturn FS_RESULT::ERR_PLACEHOLDER;\n\n\t\t\tif (!FSCDeviceHostFS_Mount(mountPathOut, _pathToUtf8(ActiveSettings::GetMlcPath()), FSC_PRIORITY_BASE))\n\t\t\t\treturn FS_RESULT::ERR_PLACEHOLDER;\n\t\t\t_mlc01Mounted = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn FS_RESULT::ERR_PLACEHOLDER;\n\t\t}\n\n\t\treturn FS_RESULT::SUCCESS;\n\t}\n\n\t// return the aligned FSClientBody struct inside a FSClient struct\n\tFSClientBody_t* __FSGetClientBody(FSClient_t* fsClient)\n\t{\n\t\t// align pointer to 64 bytes\n\t\tif (fsClient == nullptr)\n\t\t\treturn nullptr;\n\t\tFSClientBody_t* fsClientBody = (FSClientBody_t*)(((uintptr_t)fsClient + 0x3F) & ~0x3F);\n\t\tfsClientBody->selfClient = fsClient;\n\t\treturn fsClientBody;\n\t}\n\n\t// return the aligned FSClientBody struct inside a FSClient struct\n\tFSCmdBlockBody* __FSGetCmdBlockBody(FSCmdBlock_t* fsCmdBlock)\n\t{\n\t\t// align pointer to 64 bytes\n\t\tif (fsCmdBlock == nullptr)\n\t\t\treturn nullptr;\n\t\tFSCmdBlockBody* fsCmdBlockBody = (FSCmdBlockBody*)(((uintptr_t)fsCmdBlock + 0x3F) & ~0x3F);\n\t\tfsCmdBlockBody->selfCmdBlock = fsCmdBlock;\n\t\treturn fsCmdBlockBody;\n\t}\n\n\tvoid __FSErrorAndBlock(std::string_view msg)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Critical error in FS: {}\", msg);\n\t\twhile (true)\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1000));\n\t}\n\n\t/* FS client management */\n\tFSClientBody_t* g_fsRegisteredClientBodies = nullptr;\n\n\tsint32 FSGetClientNum()\n\t{\n\t\tsint32 clientNum = 0;\n\t\tFSClientBody_t* fsBodyItr = g_fsRegisteredClientBodies;\n\t\twhile (fsBodyItr)\n\t\t{\n\t\t\tclientNum++;\n\t\t\tfsBodyItr = fsBodyItr->fsClientBodyNext.GetPtr();\n\t\t}\n\t\treturn clientNum;\n\t}\n\n\tbool __FSIsClientRegistered(FSClientBody_t* fsClientBody)\n\t{\n\t\tFSLockMutex();\n\t\tFSClientBody_t* fsClientBodyFirst = g_fsRegisteredClientBodies;\n\t\tFSClientBody_t* fsClientBodyItr = fsClientBodyFirst;\n\t\tif (fsClientBodyItr == NULL)\n\t\t{\n\t\t\tFSUnlockMutex();\n\t\t\treturn false;\n\t\t}\n\t\twhile (true)\n\t\t{\n\t\t\tif (fsClientBody == fsClientBodyItr)\n\t\t\t{\n\t\t\t\tFSUnlockMutex();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// next\n\t\t\tfsClientBodyItr = fsClientBodyItr->fsClientBodyNext.GetPtr();\n\t\t\tif (fsClientBodyItr == MPTR_NULL)\n\t\t\t\tbreak;\n\t\t\tif (fsClientBodyItr == fsClientBodyFirst)\n\t\t\t\tbreak;\n\t\t}\n\t\tFSUnlockMutex();\n\t\treturn false;\n\t}\n\n\tvoid __FSInitCmdQueue(FSCmdQueue* fsCmdQueueBE, MPTR dequeueHandlerFuncMPTR, uint32 numMaxCommandsInFlight)\n\t{\n\t\tcemu_assert(numMaxCommandsInFlight > 0);\n\t\tfsCmdQueueBE->dequeueHandlerFuncMPTR = _swapEndianU32(dequeueHandlerFuncMPTR);\n\t\tfsCmdQueueBE->numCommandsInFlight = 0;\n\t\tfsCmdQueueBE->numMaxCommandsInFlight = numMaxCommandsInFlight;\n\t\tcoreinit::OSFastMutex_Init(&fsCmdQueueBE->fastMutex, nullptr);\n\t\tfsCmdQueueBE->first = nullptr;\n\t\tfsCmdQueueBE->last = nullptr;\n\t}\n\n\tvoid FSInit()\n\t{\n\t\tsFSInitialized = true;\n\t}\n\n\tvoid FSShutdown()\n\t{\n\t\tcemuLog_log(LogType::Force, \"FSShutdown called\");\n\t}\n\n\tFS_RESULT FSAddClientEx(FSClient_t* fsClient, uint32 uknR4, uint32 errHandling)\n\t{\n\t\tif (!sFSInitialized || sFSShutdown || !fsClient)\n\t\t{\n\t\t\t__FSErrorAndBlock(\"Called FSAddClient(Ex) with invalid parameters or while FS is not initialized\");\n\t\t\treturn FS_RESULT::FATAL_ERROR;\n\t\t}\n\t\tFSLockMutex();\n\t\tif (uknR4 != 0)\n\t\t{\n\t\t\tuint32 uknValue = memory_readU32(uknR4 + 0x00);\n\t\t\tif (uknValue == 0)\n\t\t\t{\n\t\t\t\tFSUnlockMutex();\n\t\t\t\t__FSErrorAndBlock(\"FSAddClientEx - unknown error\");\n\t\t\t\treturn FS_RESULT::FATAL_ERROR;\n\t\t\t}\n\t\t}\n\t\tif (__FSIsClientRegistered(__FSGetClientBody(fsClient)))\n\t\t{\n\t\t\tFSUnlockMutex();\n\t\t\t__FSErrorAndBlock(\"Called FSAddClient(Ex) on client that was already added\");\n\t\t\treturn FS_RESULT::FATAL_ERROR;\n\t\t}\n\t\tFSClientBody_t* fsClientBody = __FSGetClientBody(fsClient);\n\t\t__FSInitCmdQueue(&fsClientBody->fsCmdQueue, MPTR_NULL, 1);\n\n\t\tIOSDevHandle devHandle = IOS_Open(\"/dev/fsa\", 0);\n\t\tif (IOS_ResultIsError((IOS_ERROR)devHandle))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"FSAddClientEx(): Exhausted device handles\");\n\t\t\tcemu_assert(IOS_ResultIsError((IOS_ERROR)devHandle));\n\t\t\tFSUnlockMutex();\n\t\t\treturn FS_RESULT::FATAL_ERROR;\n\t\t}\n\t\tfsClientBody->iosuFSAHandle = devHandle;\n\n\t\t// add to list of registered clients\n\t\tif (g_fsRegisteredClientBodies != MPTR_NULL)\n\t\t{\n\t\t\tfsClientBody->fsClientBodyNext = g_fsRegisteredClientBodies;\n\t\t\tg_fsRegisteredClientBodies = fsClientBody;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tg_fsRegisteredClientBodies = fsClientBody;\n\t\t\tfsClientBody->fsClientBodyNext = nullptr;\n\t\t}\n\t\tFSUnlockMutex();\n\t\treturn FS_RESULT::SUCCESS;\n\t}\n\n\tFS_RESULT FSAddClient(FSClient_t* fsClient, uint32 errHandling)\n\t{\n\t\treturn FSAddClientEx(fsClient, 0, errHandling);\n\t}\n\n\tFS_RESULT FSDelClient(FSClient_t* fsClient, uint32 errHandling)\n\t{\n\t\tif (sFSInitialized == false || sFSShutdown == true || !fsClient)\n\t\t{\n\t\t\t__FSErrorAndBlock(\"Called FSDelClient with invalid parameters or while FS is not initialized\");\n\t\t\treturn FS_RESULT::FATAL_ERROR;\n\t\t}\n\t\tFSClientBody_t* fsClientBody = __FSGetClientBody(fsClient);\n\t\tFSLockMutex();\n\t\tIOS_Close(fsClientBody->iosuFSAHandle);\n\t\t// todo: wait till in-flight transactions are done\n\t\t// remove from list\n\t\tif (g_fsRegisteredClientBodies == fsClientBody)\n\t\t{\n\t\t\t// first entry in list\n\t\t\tg_fsRegisteredClientBodies = fsClientBody->fsClientBodyNext.GetPtr();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// scan for entry in list\n\t\t\tFSClientBody_t* fsBodyItr = g_fsRegisteredClientBodies;\n\t\t\tFSClientBody_t* fsBodyPrev = g_fsRegisteredClientBodies;\n\t\t\tbool entryFound = false;\n\t\t\twhile (fsBodyItr)\n\t\t\t{\n\t\t\t\tif (fsBodyItr == fsClientBody)\n\t\t\t\t{\n\t\t\t\t\tfsBodyPrev->fsClientBodyNext = fsClientBody->fsClientBodyNext;\n\t\t\t\t\tentryFound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// next\n\t\t\t\tfsBodyPrev = fsBodyItr;\n\t\t\t\tfsBodyItr = fsBodyItr->fsClientBodyNext.GetPtr();\n\t\t\t}\n\t\t\tif (entryFound == false)\n\t\t\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\t\tassert_dbg();\n#endif\n\t\t\t}\n\t\t}\n\t\tFSUnlockMutex();\n\t\treturn FS_RESULT::SUCCESS;\n\t}\n\n\t/* FS command queue */\n\n\tSemaphore g_semaphoreQueuedCmds;\n\n\tvoid __FSQueueCmdByPriority(FSCmdQueue* fsCmdQueueBE, FSCmdBlockBody* fsCmdBlockBody, bool stopAtEqualPriority)\n\t{\n\t\tif (!fsCmdQueueBE->first)\n\t\t{\n\t\t\t// queue is currently empty\n\t\t\tcemu_assert(!fsCmdQueueBE->last);\n\t\t\tfsCmdQueueBE->first = fsCmdBlockBody;\n\t\t\tfsCmdQueueBE->last = fsCmdBlockBody;\n\t\t\tfsCmdBlockBody->next = nullptr;\n\t\t\tfsCmdBlockBody->previous = nullptr;\n\t\t\treturn;\n\t\t}\n\t\t// iterate from last to first element as long as iterated priority is lower\n\t\tFSCmdBlockBody* fsCmdBlockBodyItrPrev = nullptr;\n\t\tFSCmdBlockBody* fsCmdBlockBodyItr = fsCmdQueueBE->last;\n\t\twhile (true)\n\t\t{\n\t\t\tif (!fsCmdBlockBodyItr)\n\t\t\t{\n\t\t\t\t// insert at the head of the list\n\t\t\t\tfsCmdQueueBE->first = fsCmdBlockBody;\n\t\t\t\tfsCmdBlockBody->next = fsCmdBlockBodyItrPrev;\n\t\t\t\tfsCmdBlockBody->previous = nullptr;\n\t\t\t\tfsCmdBlockBodyItrPrev->previous = fsCmdBlockBody;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// compare priority\n\t\t\tif ((stopAtEqualPriority && fsCmdBlockBodyItr->priority >= fsCmdBlockBody->priority) || (stopAtEqualPriority == false && fsCmdBlockBodyItr->priority > fsCmdBlockBody->priority))\n\t\t\t{\n\t\t\t\t// insert cmd here\n\t\t\t\tif (fsCmdBlockBodyItrPrev)\n\t\t\t\t{\n\t\t\t\t\tfsCmdBlockBody->next = fsCmdBlockBodyItrPrev;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfsCmdBlockBody->next = nullptr;\n\t\t\t\t\tfsCmdQueueBE->last = fsCmdBlockBody;\n\t\t\t\t}\n\t\t\t\tfsCmdBlockBody->previous = fsCmdBlockBodyItr;\n\t\t\t\tif (fsCmdBlockBodyItrPrev)\n\t\t\t\t\tfsCmdBlockBodyItrPrev->previous = fsCmdBlockBody;\n\t\t\t\tfsCmdBlockBodyItr->next = fsCmdBlockBody;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// next\n\t\t\tfsCmdBlockBodyItrPrev = fsCmdBlockBodyItr;\n\t\t\tfsCmdBlockBodyItr = fsCmdBlockBodyItr->previous;\n\t\t}\n\t}\n\n\tFSCmdBlockBody* __FSTakeCommandFromQueue(FSCmdQueue* cmdQueue)\n\t{\n\t\tif (!cmdQueue->first)\n\t\t\treturn nullptr;\n\t\t// dequeue cmd\n\t\tFSCmdBlockBody* dequeuedCmd = cmdQueue->first;\n\t\tif (cmdQueue->first == cmdQueue->last)\n\t\t\tcmdQueue->last = nullptr;\n\t\tcmdQueue->first = dequeuedCmd->next;\n\t\tdequeuedCmd->next = nullptr;\n\t\tif (dequeuedCmd->next)\n\t\t{\n\t\t\tFSCmdBlockBody* fsCmdBodyNext = dequeuedCmd->next;\n\t\t\tfsCmdBodyNext->previous = nullptr;\n\t\t}\n\t\treturn dequeuedCmd;\n\t}\n\n\tvoid __FSAIoctlResponseCallback(PPCInterpreter_t* hCPU);\n\n\tvoid __FSAIPCSubmitCommandAsync(iosu::fsa::FSAShimBuffer* shimBuffer, const MEMPTR<void>& callback, void* context)\n\t{\n\t\tif (shimBuffer->ipcReqType == 0)\n\t\t{\n\t\t\tIOS_ERROR r = IOS_IoctlAsync(shimBuffer->fsaDevHandle, shimBuffer->operationType, &shimBuffer->request, sizeof(shimBuffer->request), &shimBuffer->response, sizeof(shimBuffer->response), callback, context);\n\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t}\n\t\telse if (shimBuffer->ipcReqType == 1)\n\t\t{\n\t\t\tIOS_ERROR r = IOS_IoctlvAsync(shimBuffer->fsaDevHandle, shimBuffer->operationType, shimBuffer->ioctlvVecIn, shimBuffer->ioctlvVecOut, shimBuffer->ioctlvVec, callback, context);\n\t\t\tcemu_assert(!IOS_ResultIsError(r));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_error();\n\t\t}\n\t}\n\n\tFSA_RESULT __FSADecodeIOSErrorToFSA(IOS_ERROR result)\n\t{\n\t\treturn (FSA_RESULT)result;\n\t}\n\n\tFSA_RESULT __FSAIPCSubmitCommand(iosu::fsa::FSAShimBuffer* shimBuffer)\n\t{\n\t\tif (shimBuffer->ipcReqType == 0)\n\t\t{\n\t\t\tIOS_ERROR result = IOS_Ioctl(shimBuffer->fsaDevHandle, shimBuffer->operationType, &shimBuffer->request, sizeof(shimBuffer->request), &shimBuffer->response, sizeof(shimBuffer->response));\n\t\t\treturn __FSADecodeIOSErrorToFSA(result);\n\t\t}\n\t\telse if (shimBuffer->ipcReqType == 1)\n\t\t{\n\t\t\tIOS_ERROR result = IOS_Ioctlv(shimBuffer->fsaDevHandle, shimBuffer->operationType, shimBuffer->ioctlvVecIn, shimBuffer->ioctlvVecOut, shimBuffer->ioctlvVec);\n\t\t\treturn __FSADecodeIOSErrorToFSA(result);\n\t\t}\n\t\treturn FSA_RESULT::FATAL_ERROR;\n\t}\n\n\tvoid __FSUpdateQueue(FSCmdQueue* cmdQueue)\n\t{\n\t\tFSLockMutex();\n\t\tif (cmdQueue->numCommandsInFlight < cmdQueue->numMaxCommandsInFlight)\n\t\t{\n\t\t\tFSCmdBlockBody* dequeuedCommand = __FSTakeCommandFromQueue(cmdQueue);\n\t\t\tif (dequeuedCommand)\n\t\t\t{\n\t\t\t\tcmdQueue->numCommandsInFlight += 1;\n\t\t\t\tif (cmdQueue->numCommandsInFlight >= cmdQueue->numMaxCommandsInFlight)\n\t\t\t\t\tcmdQueue->queueFlags = cmdQueue->queueFlags | FSCmdQueue::QUEUE_FLAG::IS_FULL;\n\t\t\t\tcemu_assert_debug(cmdQueue->dequeueHandlerFuncMPTR == 0); // not supported. We HLE call the handler here\n\t\t\t\t__FSAIPCSubmitCommandAsync(&dequeuedCommand->fsaShimBuffer, MEMPTR<void>(PPCInterpreter_makeCallableExportDepr(__FSAIoctlResponseCallback)), &dequeuedCommand->fsaShimBuffer);\n\t\t\t}\n\t\t}\n\t\tFSUnlockMutex();\n\t}\n\n\tvoid __FSQueueDefaultFinishFunc(FSCmdBlockBody* fsCmdBlockBody, FS_RESULT result)\n\t{\n\t\tswitch ((FSA_CMD_OPERATION_TYPE)fsCmdBlockBody->fsaShimBuffer.operationType.value())\n\t\t{\n\t\tcase FSA_CMD_OPERATION_TYPE::OPENFILE:\n\t\t{\n\t\t\t*fsCmdBlockBody->returnValues.cmdOpenFile.handlePtr = fsCmdBlockBody->fsaShimBuffer.response.cmdOpenFile.fileHandleOutput;\n\t\t\tbreak;\n\t\t}\n\n\t\tcase FSA_CMD_OPERATION_TYPE::GETCWD:\n\t\t{\n\t\t\tauto transferSize = fsCmdBlockBody->returnValues.cmdGetCwd.transferSize;\n\t\t\tif (transferSize < 0 && transferSize > sizeof(fsCmdBlockBody->fsaShimBuffer.response.cmdGetCWD.path))\n\t\t\t{\n\t\t\t\tcemu_assert_error();\n\t\t\t}\n\t\t\tmemcpy(fsCmdBlockBody->returnValues.cmdGetCwd.pathPtr, fsCmdBlockBody->fsaShimBuffer.response.cmdGetCWD.path, transferSize);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase FSA_CMD_OPERATION_TYPE::OPENDIR:\n\t\t{\n\t\t\t*fsCmdBlockBody->returnValues.cmdOpenDir.handlePtr = fsCmdBlockBody->fsaShimBuffer.response.cmdOpenDir.dirHandleOutput;\n\t\t\tbreak;\n\t\t}\n\t\tcase FSA_CMD_OPERATION_TYPE::READDIR:\n\t\t{\n\t\t\t*fsCmdBlockBody->returnValues.cmdReadDir.dirEntryPtr = fsCmdBlockBody->fsaShimBuffer.response.cmdReadDir.dirEntry;\n\t\t\tbreak;\n\t\t}\n\t\tcase FSA_CMD_OPERATION_TYPE::GETPOS:\n\t\t{\n\t\t\t*fsCmdBlockBody->returnValues.cmdGetPosFile.filePosPtr = fsCmdBlockBody->fsaShimBuffer.response.cmdGetPosFile.filePos;\n\t\t\tbreak;\n\t\t}\n\t\tcase FSA_CMD_OPERATION_TYPE::GETSTATFILE:\n\t\t{\n\t\t\t*((FSStat_t*)fsCmdBlockBody->returnValues.cmdStatFile.resultPtr.GetPtr()) = fsCmdBlockBody->fsaShimBuffer.response.cmdStatFile.statOut;\n\t\t\tbreak;\n\t\t}\n\t\tcase FSA_CMD_OPERATION_TYPE::QUERYINFO:\n\t\t{\n\t\t\tif (fsCmdBlockBody->fsaShimBuffer.request.cmdQueryInfo.queryType == FSA_QUERY_TYPE_FREESPACE)\n\t\t\t{\n\t\t\t\t*((uint64be*)fsCmdBlockBody->returnValues.cmdQueryInfo.queryResultPtr.GetPtr()) = fsCmdBlockBody->fsaShimBuffer.response.cmdQueryInfo.queryFreeSpace.freespace;\n\t\t\t}\n\t\t\telse if (fsCmdBlockBody->fsaShimBuffer.request.cmdQueryInfo.queryType == FSA_QUERY_TYPE_STAT)\n\t\t\t{\n\t\t\t\t*((FSStat_t*)fsCmdBlockBody->returnValues.cmdQueryInfo.queryResultPtr.GetPtr()) = fsCmdBlockBody->fsaShimBuffer.response.cmdQueryInfo.queryStat.stat;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase FSA_CMD_OPERATION_TYPE::CHANGEDIR:\n\t\tcase FSA_CMD_OPERATION_TYPE::MAKEDIR:\n\t\tcase FSA_CMD_OPERATION_TYPE::REMOVE:\n\t\tcase FSA_CMD_OPERATION_TYPE::RENAME:\n\t\tcase FSA_CMD_OPERATION_TYPE::CLOSEDIR:\n\t\tcase FSA_CMD_OPERATION_TYPE::READ:\n\t\tcase FSA_CMD_OPERATION_TYPE::WRITE:\n\t\tcase FSA_CMD_OPERATION_TYPE::SETPOS:\n\t\tcase FSA_CMD_OPERATION_TYPE::ISEOF:\n\t\tcase FSA_CMD_OPERATION_TYPE::CLOSEFILE:\n\t\tcase FSA_CMD_OPERATION_TYPE::APPENDFILE:\n\t\tcase FSA_CMD_OPERATION_TYPE::TRUNCATEFILE:\n\t\tcase FSA_CMD_OPERATION_TYPE::FLUSHQUOTA:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\t}\n\t}\n\n\tvoid export___FSQueueDefaultFinishFunc(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamPtr(cmd, FSCmdBlockBody, 0);\n\t\tFS_RESULT result = (FS_RESULT)PPCInterpreter_getCallParamU32(hCPU, 1);\n\t\t__FSQueueDefaultFinishFunc(cmd, static_cast<FS_RESULT>(result));\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid __FSQueueCmd(FSCmdQueue* cmdQueue, FSCmdBlockBody* fsCmdBlockBody, MPTR finishCmdFunc)\n\t{\n\t\tfsCmdBlockBody->cmdFinishFuncMPTR = finishCmdFunc;\n\t\tFSLockMutex();\n\t\tfsCmdBlockBody->statusCode = _swapEndianU32(FSA_CMD_STATUS_CODE_D900A22);\n\t\t__FSQueueCmdByPriority(cmdQueue, fsCmdBlockBody, true);\n\t\tFSUnlockMutex();\n\t\t__FSUpdateQueue(cmdQueue);\n\t}\n\n\tFSA_RESULT _FSIosErrorToFSAStatus(IOS_ERROR iosError)\n\t{\n\t\treturn (FSA_RESULT)iosError;\n\t}\n\n\tFS_RESULT _FSAStatusToFSStatus(FSA_RESULT err)\n\t{\n\t\tif ((int)err > 0)\n\t\t{\n\t\t\treturn (FS_RESULT)err;\n\t\t}\n\t\tswitch (err)\n\t\t{\n\t\tcase FSA_RESULT::OK:\n\t\t{\n\t\t\treturn FS_RESULT::SUCCESS;\n\t\t}\n\t\tcase FSA_RESULT::END_OF_DIRECTORY:\n\t\tcase FSA_RESULT::END_OF_FILE:\n\t\t{\n\t\t\treturn FS_RESULT::END_ITERATION;\n\t\t}\n\t\tcase FSA_RESULT::ALREADY_EXISTS:\n\t\t{\n\t\t\treturn FS_RESULT::ALREADY_EXISTS;\n\t\t}\n\t\tcase FSA_RESULT::NOT_FOUND:\n\t\t{\n\t\t\treturn FS_RESULT::NOT_FOUND;\n\t\t}\n\t\tcase FSA_RESULT::PERMISSION_ERROR:\n\t\t{\n\t\t\treturn FS_RESULT::PERMISSION_ERROR;\n\t\t}\n\t\tcase FSA_RESULT::NOT_FILE:\n\t\t{\n\t\t\treturn FS_RESULT::NOT_FILE;\n\t\t}\n\t\tcase FSA_RESULT::NOT_DIR:\n\t\t{\n\t\t\treturn FS_RESULT::NOT_DIR;\n\t\t}\n\t\tcase FSA_RESULT::MAX_FILES:\n\t\tcase FSA_RESULT::MAX_DIRS:\n\t\t{\n\t\t\treturn FS_RESULT::MAX_HANDLES;\n\t\t}\n\t\tcase FSA_RESULT::INVALID_CLIENT_HANDLE:\n\t\tcase FSA_RESULT::INVALID_FILE_HANDLE:\n\t\tcase FSA_RESULT::INVALID_DIR_HANDLE:\n\t\tcase FSA_RESULT::INVALID_PARAM:\n\t\tcase FSA_RESULT::INVALID_PATH:\n\t\tcase FSA_RESULT::INVALID_BUFFER:\n\t\tcase FSA_RESULT::INVALID_ALIGNMENT:\n\t\tcase FSA_RESULT::NOT_INIT:\n\t\tcase FSA_RESULT::MAX_CLIENTS:\n\t\tcase FSA_RESULT::OUT_OF_RESOURCES:\n\t\tcase FSA_RESULT::FATAL_ERROR:\n\t\t{\n\t\t\treturn FS_RESULT::FATAL_ERROR;\n\t\t}\n\t\t}\n\t\tcemu_assert_unimplemented();\n\t\treturn FS_RESULT::FATAL_ERROR;\n\t}\n\n\tvoid __FSCmdSubmitResult(FSCmdBlockBody* fsCmdBlockBody, FS_RESULT result)\n\t{\n\t\t_debugVerifyCommand(\"FSCmdSubmitResult\", fsCmdBlockBody);\n\n\t\tFSClientBody_t* fsClientBody = fsCmdBlockBody->fsClientBody.GetPtr();\n\t\tOSFastMutex_Lock(&fsClientBody->fsCmdQueue.fastMutex);\n\t\tfsCmdBlockBody->cancelState &= ~(1 << 0); // clear cancel bit\n\t\tif (fsClientBody->currentCmdBlockBody.GetPtr() == fsCmdBlockBody)\n\t\t\tfsClientBody->currentCmdBlockBody = nullptr;\n\t\tfsCmdBlockBody->statusCode = _swapEndianU32(FSA_CMD_STATUS_CODE_D900A24);\n\t\tOSFastMutex_Unlock(&fsClientBody->fsCmdQueue.fastMutex);\n\t\t// send result via msg queue or callback\n\t\tcemu_assert_debug(!fsCmdBlockBody->asyncResult.fsAsyncParamsNew.ioMsgQueue != !fsCmdBlockBody->asyncResult.fsAsyncParamsNew.userCallback); // either must be set\n\t\tfsCmdBlockBody->ukn09EA = 0;\n\t\tfsCmdBlockBody->ukn9F4_lastErrorRelated = 0;\n\t\tif (fsCmdBlockBody->asyncResult.fsAsyncParamsNew.ioMsgQueue)\n\t\t{\n\t\t\t// msg queue\n\t\t\t_debugVerifyCommand(\"SubmitResultQueue\", fsCmdBlockBody);\n\t\t\tcoreinit::OSMessageQueue* ioMsgQueue = fsCmdBlockBody->asyncResult.fsAsyncParamsNew.ioMsgQueue.GetPtr();\n\t\t\tfsCmdBlockBody->asyncResult.fsCmdBlock = fsCmdBlockBody->selfCmdBlock;\n\t\t\tfsCmdBlockBody->asyncResult.fsStatusNew = (uint32)result;\n\t\t\twhile (OSSendMessage(ioMsgQueue, &fsCmdBlockBody->asyncResult.msgUnion.osMsg, 0) == 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"FS driver: Failed to add message to result queue. Retrying...\");\n\t\t\t\tif (PPCInterpreter_getCurrentInstance())\n\t\t\t\t\tPPCCore_switchToScheduler();\n\t\t\t\telse\n\t\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// callback\n\t\t\t_debugVerifyCommand(\"SubmitResultCallback\", fsCmdBlockBody);\n\t\t\tFSClient_t* fsClient = fsCmdBlockBody->asyncResult.fsClient.GetPtr();\n\t\t\tFSCmdBlock_t* fsCmdBlock = fsCmdBlockBody->asyncResult.fsCmdBlock.GetPtr();\n\t\t\tPPCCoreCallback(fsCmdBlockBody->asyncResult.fsAsyncParamsNew.userCallback, fsClient, fsCmdBlock, (sint32)result, fsCmdBlockBody->asyncResult.fsAsyncParamsNew.userContext);\n\t\t}\n\t}\n\n\tvoid __FSAIoctlResponseCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(iosResult, 0);\n\t\tppcDefineParamPtr(cmd, FSCmdBlockBody, 1);\n\n\t\tFSA_RESULT fsaStatus = _FSIosErrorToFSAStatus((IOS_ERROR)iosResult);\n\n\t\tcmd->statusCode = _swapEndianU32(FSA_CMD_STATUS_CODE_D900A26);\n\t\tcmd->lastFSAStatus = fsaStatus;\n\n\t\t// translate error code to FSStatus\n\t\tFS_RESULT fsStatus = _FSAStatusToFSStatus(fsaStatus);\n\n\t\t// On actual hardware this delegates the processing to the AppIO threads, but for now we just run it directly from the IPC thread\n\t\tFSClientBody_t* client = cmd->fsClientBody;\n\t\tFSCmdQueue& cmdQueue = client->fsCmdQueue;\n\t\tFSLockMutex();\n\t\tcmdQueue.numCommandsInFlight -= 1;\n\t\tcmdQueue.queueFlags = cmdQueue.queueFlags & ~FSCmdQueue::QUEUE_FLAG::IS_FULL;\n\t\tFSUnlockMutex();\n\n\t\tif (cmd->cmdFinishFuncMPTR)\n\t\t{\n\t\t\tif (cmd->cmdFinishFuncMPTR != FS_CB_PLACEHOLDER_FINISHCMD)\n\t\t\t\tPPCCoreCallback(MEMPTR<void>(cmd->cmdFinishFuncMPTR), cmd, fsStatus);\n\t\t}\n\n\t\t__FSCmdSubmitResult(cmd, fsStatus);\n\t\t// dont read from cmd after this point, since the game could already have modified it\n\t\t__FSUpdateQueue(&client->fsCmdQueue);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\t/* FS commands */\n\n\tvoid FSInitCmdBlock(FSCmdBlock_t* fsCmdBlock)\n\t{\n\t\tmemset(fsCmdBlock, 0x00, sizeof(FSCmdBlock_t));\n\t\tFSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);\n\t\tfsCmdBlockBody->statusCode = _swapEndianU32(FSA_CMD_STATUS_CODE_D900A21);\n\t\tfsCmdBlockBody->priority = 0x10;\n\t}\n\n\tvoid __FSAsyncToSyncInit(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSAsyncParams* asyncParams)\n\t{\n\t\tif (fsClient == nullptr || fsCmdBlock == nullptr || asyncParams == nullptr)\n\t\t\tassert_dbg();\n\t\tFSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);\n\t\tcoreinit::OSInitMessageQueue(&fsCmdBlockBody->syncTaskMsgQueue, fsCmdBlockBody->_syncTaskMsg, 1);\n\t\tasyncParams->userCallback = nullptr;\n\t\tasyncParams->userContext = nullptr;\n\t\tasyncParams->ioMsgQueue = &fsCmdBlockBody->syncTaskMsgQueue;\n\t}\n\n\tvoid __FSPrepareCmdAsyncResult(FSClientBody_t* fsClientBody, FSCmdBlockBody* fsCmdBlockBody, FSAsyncResult* fsCmdBlockAsyncResult, FSAsyncParams* fsAsyncParams)\n\t{\n\t\tmemcpy(&fsCmdBlockAsyncResult->fsAsyncParamsNew, fsAsyncParams, sizeof(FSAsyncParams));\n\n\t\tfsCmdBlockAsyncResult->fsClient = fsClientBody->selfClient;\n\t\tfsCmdBlockAsyncResult->fsCmdBlock = fsCmdBlockBody->selfCmdBlock;\n\n\t\tfsCmdBlockAsyncResult->msgUnion.fsMsg.fsAsyncResult = fsCmdBlockAsyncResult;\n\t\tfsCmdBlockAsyncResult->msgUnion.fsMsg.commandType = _swapEndianU32(8);\n\t}\n\n\tsint32 __FSPrepareCmd(FSClientBody_t* fsClientBody, FSCmdBlockBody* fsCmdBlockBody, uint32 errHandling, FSAsyncParams* fsAsyncParams)\n\t{\n\t\tif (sFSInitialized == false || sFSShutdown == true)\n\t\t\treturn -0x400;\n\t\tif (!fsClientBody || !fsCmdBlockBody)\n\t\t{\n\t\t\tcemu_assert(false);\n\t\t\treturn -0x400;\n\t\t}\n\t\tif (_swapEndianU32(fsCmdBlockBody->statusCode) != FSA_CMD_STATUS_CODE_D900A21 && _swapEndianU32(fsCmdBlockBody->statusCode) != FSA_CMD_STATUS_CODE_D900A24)\n\t\t{\n\t\t\tcemu_assert(false);\n\t\t\treturn -0x400;\n\t\t}\n\t\tif ((fsAsyncParams->userCallback == nullptr && fsAsyncParams->ioMsgQueue == nullptr) ||\n\t\t\t(fsAsyncParams->userCallback != nullptr && fsAsyncParams->ioMsgQueue != nullptr))\n\t\t{\n\t\t\t// userCallback and ioMsgQueue both set or none set\n\t\t\tcemu_assert(false);\n\t\t\treturn -0x400;\n\t\t}\n\t\tfsCmdBlockBody->fsClientBody = fsClientBody;\n\t\tfsCmdBlockBody->errHandling = _swapEndianU32(errHandling);\n\t\tfsCmdBlockBody->uknStatusGuessed09E9 = 0;\n\t\tfsCmdBlockBody->cancelState &= ~(1 << 0); // clear cancel bit\n\t\tfsCmdBlockBody->fsaShimBuffer.fsaDevHandle = fsClientBody->iosuFSAHandle;\n\t\t__FSPrepareCmdAsyncResult(fsClientBody, fsCmdBlockBody, &fsCmdBlockBody->asyncResult, fsAsyncParams);\n\t\treturn 0;\n\t}\n\n#define _FSCmdIntro()                                                                        \\\n\tFSClientBody_t* fsClientBody = __FSGetClientBody(fsClient);                              \\\n\tFSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);                      \\\n\tsint32 fsError = __FSPrepareCmd(fsClientBody, fsCmdBlockBody, errorMask, fsAsyncParams); \\\n\tif (fsError != 0)                                                                        \\\n\t\treturn fsError;\n\n\tvoid _debugVerifyCommand(const char* stage, FSCmdBlockBody* fsCmdBlockBody)\n\t{\n\t\tif (fsCmdBlockBody->asyncResult.msgUnion.fsMsg.commandType != _swapEndianU32(8))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Corrupted FS command detected in stage {}\", stage);\n\t\t\tcemuLog_log(LogType::Force, \"Printing CMD block: \");\n\t\t\tfor (uint32 i = 0; i < (sizeof(FSCmdBlockBody) + 31) / 32; i++)\n\t\t\t{\n\t\t\t\tuint8* p = ((uint8*)fsCmdBlockBody) + i * 32;\n\t\t\t\tcemuLog_log(LogType::Force, \"{:04x}: {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} | {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x}\",\n\t\t\t\t\t\t\ti * 32,\n\t\t\t\t\t\t\tp[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15],\n\t\t\t\t\t\t\tp[16], p[17], p[18], p[19], p[20], p[21], p[22], p[23], p[24], p[25], p[26], p[27], p[28], p[29], p[30], p[31]);\n\t\t\t}\n\t\t}\n\t}\n\n\tFSAsyncResult* FSGetAsyncResult(OSMessage* msg)\n\t{\n\t\treturn (FSAsyncResult*)memory_getPointerFromVirtualOffset(msg->message);\n\t}\n\n\tsint32 __FSProcessAsyncResult(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, sint32 fsStatus, uint32 errHandling)\n\t{\n\t\t// a positive result (or zero) means success. Most operations return zero in case of success. Read and write operations return the number of transferred units\n\t\tif (fsStatus >= 0)\n\t\t{\n\t\t\tFSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);\n\t\t\tOSMessage msg;\n\t\t\tOSReceiveMessage(&fsCmdBlockBody->syncTaskMsgQueue, &msg, OS_MESSAGE_BLOCK);\n\t\t\t_debugVerifyCommand(\"handleAsyncResult\", fsCmdBlockBody);\n\t\t\tFSAsyncResult* asyncResult = FSGetAsyncResult(&msg);\n\t\t\treturn asyncResult->fsStatusNew;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// todo - error handling\n\t\t\tcemuLog_log(LogType::Force, \"FS handleAsyncResult(): unexpected error {:08x}\", errHandling);\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_OpenFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, char* path, char* mode, uint32 createMode, uint32 openFlags, uint32 preallocSize)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tif (path == NULL)\n\t\t\treturn FSA_RESULT::INVALID_PATH;\n\t\tif (mode == NULL)\n\t\t\treturn FSA_RESULT::INVALID_PARAM;\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::OPENFILE;\n\t\t// path\n\t\tsize_t pathLen = strlen((char*)path);\n\t\tif (pathLen >= FSA_CMD_PATH_MAX_LENGTH)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tpathLen = FSA_CMD_PATH_MAX_LENGTH - 1;\n\t\t}\n\t\tfor (sint32 i = 0; i < pathLen; i++)\n\t\t\tfsaShimBuffer->request.cmdOpenFile.path[i] = path[i];\n\t\tfor (size_t i = pathLen; i < FSA_CMD_PATH_MAX_LENGTH; i++)\n\t\t\tfsaShimBuffer->request.cmdOpenFile.path[i] = '\\0';\n\t\t// mode\n\t\tsize_t modeLen = strlen((char*)mode);\n\t\tif (modeLen >= 12)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tmodeLen = 12 - 1;\n\t\t}\n\t\tfor (sint32 i = 0; i < modeLen; i++)\n\t\t\tfsaShimBuffer->request.cmdOpenFile.mode[i] = mode[i];\n\t\tfor (size_t i = modeLen; i < 12; i++)\n\t\t\tfsaShimBuffer->request.cmdOpenFile.mode[i] = '\\0';\n\t\t// createMode\n\t\tfsaShimBuffer->request.cmdOpenFile.createMode = createMode;\n\t\t// openFlags\n\t\tfsaShimBuffer->request.cmdOpenFile.openFlags = openFlags;\n\t\t// preallocSize\n\t\tfsaShimBuffer->request.cmdOpenFile.preallocSize = preallocSize;\n\n\t\tfsaShimBuffer->response.cmdOpenFile.fileHandleOutput = 0xFFFFFFFF;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSOpenFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandlePtr outFileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tif (outFileHandle == nullptr || path == nullptr || mode == nullptr)\n\t\t\treturn -0x400;\n\t\tfsCmdBlockBody->returnValues.cmdOpenFile.handlePtr = outFileHandle;\n\t\tfsError = (FSStatus)__FSPrepareCmd_OpenFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, path, mode, 0x660, 0, 0);\n\t\tif (fsError != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn fsError;\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSOpenFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandlePtr outFileHandle, uint32 errHandling)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSOpenFileAsync(fsClient, fsCmdBlock, path, mode, outFileHandle, errHandling, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);\n\t}\n\n\tsint32 FSOpenFileExAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandlePtr outFileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\tif (openFlag != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"FSOpenFileEx called with unsupported flags!\");\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\n\t\t_FSCmdIntro();\n\t\tif (outFileHandle == nullptr || path == nullptr || mode == nullptr)\n\t\t\treturn -0x400;\n\t\tfsCmdBlockBody->returnValues.cmdOpenFile.handlePtr = outFileHandle;\n\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_OpenFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, path, mode, createMode, openFlag, preallocSize);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSOpenFileEx(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandlePtr outFileHandle, uint32 errHandling)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSOpenFileExAsync(fsClient, fsCmdBlock, path, mode, createMode, openFlag, preallocSize, outFileHandle, errHandling, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_CloseFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, uint32 fileHandle)\n\t{\n\t\tif (fsaShimBuffer == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::CLOSEFILE;\n\n\t\tfsaShimBuffer->request.cmdCloseFile.fileHandle = fileHandle;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSCloseFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_CloseFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSCloseFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errHandling)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSCloseFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_FlushFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, uint32 fileHandle)\n\t{\n\t\tif (fsaShimBuffer == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::FLUSHFILE;\n\n\t\tfsaShimBuffer->request.cmdFlushFile.fileHandle = fileHandle;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSFlushFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_FlushFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSFlushFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errHandling)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSFlushFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_ReadFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, void* dest, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag)\n\t{\n\t\tif (fsaShimBuffer == NULL || dest == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tMPTR destMPTR = memory_getVirtualOffsetFromPointer(dest);\n\t\tif ((destMPTR & 0x3F) != 0)\n\t\t\treturn FSA_RESULT::INVALID_ALIGNMENT;\n\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 1;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::READ;\n\n\t\tfsaShimBuffer->ioctlvVecIn = 1;\n\t\tfsaShimBuffer->ioctlvVecOut = 2;\n\n\t\tfsaShimBuffer->ioctlvVec[0].baseVirt = fsaShimBuffer;\n\t\tfsaShimBuffer->ioctlvVec[0].size = sizeof(iosu::fsa::FSARequest);\n\n\t\tfsaShimBuffer->ioctlvVec[1].baseVirt = destMPTR;\n\t\tfsaShimBuffer->ioctlvVec[1].size = size * count;\n\n\t\tfsaShimBuffer->ioctlvVec[2].baseVirt = &fsaShimBuffer->response;\n\t\tfsaShimBuffer->ioctlvVec[2].size = sizeof(iosu::fsa::FSAResponse);\n\n\t\tfsaShimBuffer->request.cmdReadFile.dest = dest;\n\t\tfsaShimBuffer->request.cmdReadFile.size = size;\n\t\tfsaShimBuffer->request.cmdReadFile.count = count;\n\t\tfsaShimBuffer->request.cmdReadFile.filePos = filePos;\n\t\tfsaShimBuffer->request.cmdReadFile.fileHandle = fileHandle;\n\t\tfsaShimBuffer->request.cmdReadFile.flag = flag;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tSysAllocator<uint8, 128, 64> _tempFSSpace;\n\n\tsint32 __FSReadFileAsyncEx(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dest, uint32 size, uint32 count, bool usePos, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tif (size == 0 || count == 0 || dest == NULL)\n\t\t\tdest = _tempFSSpace.GetPtr();\n\t\tsint64 transferSizeS64 = (sint64)size * (sint64)count;\n\t\tif (transferSizeS64 < 0 || (transferSizeS64 >= 2LL * 1024LL * 1024LL * 1024LL))\n\t\t{\n\t\t\t// size below 0 or over 2GB\n\t\t\tcemu_assert(false);\n\t\t\treturn -0x400;\n\t\t}\n\n\t\t// coreinit.rpl splits up each read into smaller chunks (probably to support canceling big writes). This is handled by a specific\n\t\t// callback for the __FSQueueCmd functions. Whenever a chunk is read, it's getting re-queued until the reading has been completed.\n\t\t// For this it writes values into the fsCmdBlockBody->returnValues struct. At the moment we go the lazy route of just reading everything\n\t\t// at once, so we can skip the initialization of these values.\n\n\t\tif (usePos)\n\t\t\tflag |= FSA_CMD_FLAG_SET_POS;\n\t\telse\n\t\t\tflag &= ~FSA_CMD_FLAG_SET_POS;\n\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_ReadFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dest, size, count, filePos, fileHandle, flag);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSReadFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\tcemu_assert_debug(flag == 0); // todo\n\t\treturn __FSReadFileAsyncEx(fsClient, fsCmdBlock, dst, size, count, false, 0, fileHandle, flag, errorMask, fsAsyncParams);\n\t}\n\n\tsint32 FSReadFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSReadFileAsync(fsClient, fsCmdBlock, dst, size, count, fileHandle, flag, errorMask, asyncParams.GetPointer());\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tsint32 FSReadFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\tcemu_assert_debug(flag == 0); // todo\n\t\tsint32 fsStatus = __FSReadFileAsyncEx(fsClient, fsCmdBlock, dst, size, count, true, filePos, fileHandle, flag, errorMask, fsAsyncParams);\n\t\treturn fsStatus;\n\t}\n\n\tsint32 FSReadFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSReadFileWithPosAsync(fsClient, fsCmdBlock, dst, size, count, filePos, fileHandle, flag, errorMask, asyncParams.GetPointer());\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_WriteFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, void* dest, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag)\n\t{\n\t\tif (fsaShimBuffer == NULL || dest == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tMPTR destMPTR = memory_getVirtualOffsetFromPointer(dest);\n\t\tif ((destMPTR & 0x3F) != 0)\n\t\t\treturn FSA_RESULT::INVALID_ALIGNMENT;\n\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 1;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::WRITE;\n\n\t\tfsaShimBuffer->ioctlvVecIn = 2;\n\t\tfsaShimBuffer->ioctlvVecOut = 1;\n\n\t\tfsaShimBuffer->ioctlvVec[0].baseVirt = fsaShimBuffer;\n\t\tfsaShimBuffer->ioctlvVec[0].size = sizeof(iosu::fsa::FSARequest);\n\n\t\tfsaShimBuffer->ioctlvVec[1].baseVirt = destMPTR;\n\t\tfsaShimBuffer->ioctlvVec[1].size = size * count;\n\n\t\tfsaShimBuffer->ioctlvVec[2].baseVirt = &fsaShimBuffer->response;\n\t\tfsaShimBuffer->ioctlvVec[2].size = sizeof(iosu::fsa::FSAResponse);\n\n\t\tfsaShimBuffer->request.cmdWriteFile.dest = dest;\n\t\tfsaShimBuffer->request.cmdWriteFile.size = size;\n\t\tfsaShimBuffer->request.cmdWriteFile.count = count;\n\t\tfsaShimBuffer->request.cmdWriteFile.filePos = filePos;\n\t\tfsaShimBuffer->request.cmdWriteFile.fileHandle = fileHandle;\n\t\tfsaShimBuffer->request.cmdWriteFile.flag = flag;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 __FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dest, uint32 size, uint32 count, bool useFilePos, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tif (size == 0 || count == 0 || dest == nullptr)\n\t\t\tdest = _tempFSSpace.GetPtr();\n\t\tsint64 transferSizeS64 = (sint64)size * (sint64)count;\n\t\tif (transferSizeS64 < 0 || (transferSizeS64 >= 2LL * 1024LL * 1024LL * 1024LL))\n\t\t{\n\t\t\t// size below 0 or over 2GB\n\t\t\tcemu_assert(false);\n\t\t\treturn -0x400;\n\t\t}\n\n\t\t// coreinit.rpl splits up each write into smaller chunks (probably to support canceling big writes). This is handled by a specific\n\t\t// callback for the __FSQueueCmd functions. Whenever a chunk is written, it's getting re-queued until the writing has been completed.\n\t\t// For this it writes values into the fsCmdBlockBody->returnValues struct. At the moment we go the lazy route of just writing everything\n\t\t// at once, so we can skip the initialization of these values.\n\n\t\tif (useFilePos)\n\t\t\tflag |= FSA_CMD_FLAG_SET_POS;\n\t\telse\n\t\t\tflag &= ~FSA_CMD_FLAG_SET_POS;\n\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_WriteFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dest, size, count, filePos, fileHandle, flag);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSWriteFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\treturn __FSWriteFileWithPosAsync(fsClient, fsCmdBlock, src, size, count, false, 0, fileHandle, flag, errorMask, fsAsyncParams);\n\t}\n\n\tsint32 FSWriteFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSWriteFileAsync(fsClient, fsCmdBlock, src, size, count, fileHandle, flag, errorMask, asyncParams.GetPointer());\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tsint32 FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\treturn __FSWriteFileWithPosAsync(fsClient, fsCmdBlock, src, size, count, true, filePos, fileHandle, flag, errorMask, fsAsyncParams);\n\t}\n\n\tsint32 FSWriteFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSWriteFileWithPosAsync(fsClient, fsCmdBlock, src, size, count, filePos, fileHandle, flag, errorMask, asyncParams.GetPointer());\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_SetPosFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, uint32 fileHandle, uint32 filePos)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->request.cmdSetPosFile.fileHandle = fileHandle;\n\t\tfsaShimBuffer->request.cmdSetPosFile.filePos = filePos;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::SETPOS;\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSSetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_SetPosFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle, filePos);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSSetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask)\n\t{\n\t\t// used by games: Mario Kart 8\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSSetPosFileAsync(fsClient, fsCmdBlock, fileHandle, filePos, errorMask, asyncParams.GetPointer());\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_GetPosFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, uint32 fileHandle)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->request.cmdGetPosFile.fileHandle = fileHandle;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::GETPOS;\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSGetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t// games using this: Darksiders Warmastered Edition\n\t\t_FSCmdIntro();\n\t\tfsCmdBlockBody->returnValues.cmdGetPosFile.filePosPtr = returnedFilePos;\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_GetPosFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSGetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSGetPosFileAsync(fsClient, fsCmdBlock, fileHandle, returnedFilePos, errorMask, asyncParams.GetPointer());\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_OpenDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, char* path)\n\t{\n\t\tif (fsaShimBuffer == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tif (path == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_PATH;\n\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::OPENDIR;\n\n\t\t// path\n\t\tsint32 pathLen = (sint32)strlen((char*)path);\n\t\tif (pathLen >= FSA_CMD_PATH_MAX_LENGTH)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tpathLen = FSA_CMD_PATH_MAX_LENGTH - 1;\n\t\t}\n\t\tfor (sint32 i = 0; i < pathLen; i++)\n\t\t\tfsaShimBuffer->request.cmdOpenDir.path[i] = path[i];\n\t\tfor (sint32 i = pathLen; i < FSA_CMD_PATH_MAX_LENGTH; i++)\n\t\t\tfsaShimBuffer->request.cmdOpenDir.path[i] = '\\0';\n\n\t\tfsaShimBuffer->response.cmdOpenDir.dirHandleOutput = -1;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSOpenDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tcemu_assert(dirHandleOut && path);\n\t\tfsCmdBlockBody->returnValues.cmdOpenDir.handlePtr = dirHandleOut.GetMPTR();\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_OpenDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, path);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSOpenDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSOpenDirAsync(fsClient, fsCmdBlock, path, dirHandleOut, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_ReadDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, FSDirHandle2 dirHandle)\n\t{\n\t\tif (fsaShimBuffer == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::READDIR;\n\t\tfsaShimBuffer->request.cmdReadDir.dirHandle = dirHandle;\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSReadDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_ReadDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dirHandle);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\t\tfsCmdBlockBody->returnValues.cmdReadDir.dirEntryPtr = dirEntryOut;\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSReadDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSReadDirAsync(fsClient, fsCmdBlock, dirHandle, dirEntryOut, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_CloseDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, FSDirHandle2 dirHandle)\n\t{\n\t\tif (fsaShimBuffer == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::CLOSEDIR;\n\t\tfsaShimBuffer->request.cmdCloseDir.dirHandle = dirHandle;\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSCloseDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_CloseDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dirHandle);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSCloseDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSCloseDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_RewindDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, FSDirHandle2 dirHandle)\n\t{\n\t\tif (fsaShimBuffer == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::REWINDDIR;\n\n\t\tfsaShimBuffer->request.cmdRewindDir.dirHandle = dirHandle;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSRewindDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_RewindDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dirHandle);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSRewindDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSRewindDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_AppendFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, uint32 size, uint32 count, uint32 fileHandle, uint32 uknParam)\n\t{\n\t\tif (fsaShimBuffer == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::APPENDFILE;\n\n\t\tfsaShimBuffer->request.cmdAppendFile.fileHandle = fileHandle;\n\t\tfsaShimBuffer->request.cmdAppendFile.count = count;\n\t\tfsaShimBuffer->request.cmdAppendFile.size = size;\n\t\tfsaShimBuffer->request.cmdAppendFile.uknParam = uknParam;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSAppendFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 size, uint32 count, uint32 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_AppendFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, size, count, fileHandle, 0);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSAppendFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 size, uint32 count, uint32 fileHandle, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSAppendFileAsync(fsClient, fsCmdBlock, size, count, fileHandle, errorMask, asyncParams.GetPointer());\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_TruncateFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, FSFileHandle2 fileHandle)\n\t{\n\t\tif (fsaShimBuffer == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::TRUNCATEFILE;\n\n\t\tfsaShimBuffer->request.cmdTruncateFile.fileHandle = fileHandle;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSTruncateFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_TruncateFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSTruncateFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSTruncateFileAsync(fsClient, fsCmdBlock, fileHandle, errorMask, asyncParams.GetPointer());\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_Rename(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, char* srcPath, char* dstPath)\n\t{\n\t\tif (fsaShimBuffer == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tif (srcPath == NULL || dstPath == NULL)\n\t\t\treturn FSA_RESULT::INVALID_PATH;\n\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::RENAME;\n\n\t\t// source path\n\t\tsize_t stringLen = strlen((char*)srcPath);\n\t\tif (stringLen >= FSA_CMD_PATH_MAX_LENGTH)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tstringLen = FSA_CMD_PATH_MAX_LENGTH - 1;\n\t\t}\n\t\tfor (sint32 i = 0; i < stringLen; i++)\n\t\t{\n\t\t\tfsaShimBuffer->request.cmdRename.srcPath[i] = srcPath[i];\n\t\t}\n\t\tfsaShimBuffer->request.cmdRename.srcPath[stringLen] = '\\0';\n\t\t// destination path\n\t\tstringLen = strlen((char*)dstPath);\n\t\tif (stringLen >= FSA_CMD_PATH_MAX_LENGTH)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tstringLen = FSA_CMD_PATH_MAX_LENGTH - 1;\n\t\t}\n\t\tfor (sint32 i = 0; i < stringLen; i++)\n\t\t{\n\t\t\tfsaShimBuffer->request.cmdRename.dstPath[i] = dstPath[i];\n\t\t}\n\t\tfsaShimBuffer->request.cmdRename.dstPath[stringLen] = '\\0';\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSRenameAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t// used by titles: XCX (via SAVERenameAsync)\n\t\t_FSCmdIntro();\n\t\tif (srcPath == NULL || dstPath == NULL)\n\t\t{\n\t\t\tcemu_assert_debug(false); // path must not be NULL\n\t\t\treturn -0x400;\n\t\t}\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_Rename(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, srcPath, dstPath);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSRename(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSRenameAsync(fsClient, fsCmdBlock, srcPath, dstPath, errorMask, asyncParams.GetPointer());\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_Remove(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, uint8* path)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tif (path == NULL)\n\t\t\treturn FSA_RESULT::INVALID_PATH;\n\n\t\tfsaShimBuffer->fsaDevHandle = devHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::REMOVE;\n\n\t\tsize_t pathLen = strlen((char*)path);\n\t\tif (pathLen >= FSA_CMD_PATH_MAX_LENGTH)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tpathLen = FSA_CMD_PATH_MAX_LENGTH - 1;\n\t\t}\n\t\tfor (sint32 i = 0; i < pathLen; i++)\n\t\t{\n\t\t\tfsaShimBuffer->request.cmdRemove.path[i] = path[i];\n\t\t}\n\t\tfsaShimBuffer->request.cmdRemove.path[pathLen] = '\\0';\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSRemoveAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t// used by titles: XCX (via SAVERemoveAsync)\n\t\t_FSCmdIntro();\n\t\tif (filePath == NULL)\n\t\t{\n\t\t\tcemu_assert_debug(false); // path must not be NULL\n\t\t\treturn -0x400;\n\t\t}\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_Remove(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, filePath);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSRemove(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSRemoveAsync(fsClient, fsCmdBlock, filePath, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_MakeDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, const char* path, uint32 uknVal660)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tif (path == NULL)\n\t\t\treturn FSA_RESULT::INVALID_PATH;\n\n\t\tfsaShimBuffer->fsaDevHandle = devHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::MAKEDIR;\n\n\t\tsize_t pathLen = strlen((char*)path);\n\t\tif (pathLen >= FSA_CMD_PATH_MAX_LENGTH)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tpathLen = FSA_CMD_PATH_MAX_LENGTH - 1;\n\t\t}\n\t\tfor (sint32 i = 0; i < pathLen; i++)\n\t\t{\n\t\t\tfsaShimBuffer->request.cmdMakeDir.path[i] = path[i];\n\t\t}\n\t\tfsaShimBuffer->request.cmdMakeDir.path[pathLen] = '\\0';\n\t\tfsaShimBuffer->request.cmdMakeDir.uknParam = uknVal660;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSMakeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* dirPath, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t// used by titles: XCX (via SAVEMakeDirAsync)\n\t\t_FSCmdIntro();\n\t\tif (dirPath == NULL)\n\t\t{\n\t\t\tcemu_assert_debug(false); // path must not be NULL\n\t\t\treturn -0x400;\n\t\t}\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_MakeDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dirPath, 0x660);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSMakeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSMakeDirAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_ChangeDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, uint8* path)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tif (path == NULL)\n\t\t\treturn FSA_RESULT::INVALID_PATH;\n\n\t\tfsaShimBuffer->fsaDevHandle = devHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::CHANGEDIR;\n\n\t\tsize_t pathLen = strlen((char*)path);\n\t\tif (pathLen >= FSA_CMD_PATH_MAX_LENGTH)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tpathLen = FSA_CMD_PATH_MAX_LENGTH - 1;\n\t\t}\n\t\tfor (sint32 i = 0; i < pathLen; i++)\n\t\t\tfsaShimBuffer->request.cmdChangeDir.path[i] = path[i];\n\n\t\tfsaShimBuffer->request.cmdChangeDir.path[pathLen] = '\\0';\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSChangeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tif (path == NULL)\n\t\t{\n\t\t\tcemu_assert_debug(false); // path must not be NULL\n\t\t\treturn -0x400;\n\t\t}\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_ChangeDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, (uint8*)path);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSChangeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSChangeDirAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_GetCwd(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tfsaShimBuffer->fsaDevHandle = devHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::GETCWD;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSGetCwdAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t// used by titles: Super Mario Maker\n\t\t_FSCmdIntro();\n\t\tfsCmdBlockBody->returnValues.cmdGetCwd.pathPtr = dirPathOut;\n\t\tfsCmdBlockBody->returnValues.cmdGetCwd.transferSize = dirPathMaxLen;\n\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_GetCwd(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSGetCwd(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSGetCwdAsync(fsClient, fsCmdBlock, dirPathOut, dirPathMaxLen, errorMask, &asyncParams);\n\t\tauto r = __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t\treturn r;\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_FlushQuota(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, char* path)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tif (path == NULL)\n\t\t\treturn FSA_RESULT::INVALID_PATH;\n\n\t\tfsaShimBuffer->fsaDevHandle = devHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::FLUSHQUOTA;\n\n\t\tsize_t pathLen = strlen((char*)path);\n\t\tif (pathLen >= FSA_CMD_PATH_MAX_LENGTH)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tpathLen = FSA_CMD_PATH_MAX_LENGTH - 1;\n\t\t}\n\t\tfor (sint32 i = 0; i < pathLen; i++)\n\t\t\tfsaShimBuffer->request.cmdFlushQuota.path[i] = path[i];\n\t\tfsaShimBuffer->request.cmdFlushQuota.path[pathLen] = '\\0';\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSFlushQuotaAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_FlushQuota(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, path);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSFlushQuota(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSFlushQuotaAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_QueryInfo(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, uint8* queryString, uint32 queryType)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tif (queryString == NULL)\n\t\t\treturn FSA_RESULT::INVALID_PATH;\n\t\tif (queryType > 8)\n\t\t\treturn FSA_RESULT::INVALID_PARAM;\n\n\t\tfsaShimBuffer->fsaDevHandle = devHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::QUERYINFO;\n\n\t\tsize_t stringLen = strlen((char*)queryString);\n\t\tif (stringLen >= FSA_CMD_PATH_MAX_LENGTH)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tstringLen = FSA_CMD_PATH_MAX_LENGTH - 1;\n\t\t}\n\t\tfor (sint32 i = 0; i < stringLen; i++)\n\t\t{\n\t\t\tfsaShimBuffer->request.cmdQueryInfo.query[i] = queryString[i];\n\t\t}\n\n\t\tfsaShimBuffer->request.cmdQueryInfo.query[stringLen] = '\\0';\n\t\tfsaShimBuffer->request.cmdQueryInfo.queryType = queryType;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 __FSQueryInfoAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* queryString, uint32 queryType, void* queryResult, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tcemu_assert(queryString && queryResult); // query string and result must not be null\n\t\tfsCmdBlockBody->returnValues.cmdQueryInfo.queryResultPtr = queryResult;\n\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_QueryInfo(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, queryString, queryType);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSGetStatAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSStat_t* statOut, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\tsint32 fsStatus = __FSQueryInfoAsync(fsClient, fsCmdBlock, (uint8*)path, FSA_QUERY_TYPE_STAT, statOut, errorMask, fsAsyncParams);\n\t\treturn fsStatus;\n\t}\n\n\tsint32 FSGetStat(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSStat_t* statOut, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSGetStatAsync(fsClient, fsCmdBlock, path, statOut, errorMask, &asyncParams);\n\t\tsint32 ret = __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t\treturn ret;\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_GetStatFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, FSFileHandle2 fileHandle)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tfsaShimBuffer->fsaDevHandle = devHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::GETSTATFILE;\n\n\t\tfsaShimBuffer->request.cmdGetStatFile.fileHandle = fileHandle;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSGetStatFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, FSStat_t* statOut, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t_FSCmdIntro();\n\t\tcemu_assert(statOut); // statOut must not be null\n\t\tfsCmdBlockBody->returnValues.cmdStatFile.resultPtr = statOut;\n\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_GetStatFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSGetStatFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, FSStat_t* statOut, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSGetStatFileAsync(fsClient, fsCmdBlock, fileHandle, statOut, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tsint32 FSGetFreeSpaceSizeAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t// used by: Wii U system settings app, Art Academy, Unity (e.g. Snoopy's Grand Adventure), Super Smash Bros\n\t\tsint32 fsStatus = __FSQueryInfoAsync(fsClient, fsCmdBlock, (uint8*)path, FSA_QUERY_TYPE_FREESPACE, returnedFreeSize, errorMask, fsAsyncParams);\n\t\treturn fsStatus;\n\t}\n\n\tsint32 FSGetFreeSpaceSize(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSGetFreeSpaceSizeAsync(fsClient, fsCmdBlock, path, returnedFreeSize, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_IsEof(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, uint32 fileHandle)\n\t{\n\t\tif (fsaShimBuffer == NULL)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tfsaShimBuffer->fsaDevHandle = devHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::ISEOF;\n\n\t\tfsaShimBuffer->request.cmdIsEof.fileHandle = fileHandle;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tsint32 FSIsEofAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams)\n\t{\n\t\t// used by Paper Monsters Recut\n\t\t_FSCmdIntro();\n\n\t\tFSA_RESULT prepareResult = __FSPrepareCmd_IsEof(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle);\n\t\tif (prepareResult != FSA_RESULT::OK)\n\t\t\treturn (FSStatus)_FSAStatusToFSStatus(prepareResult);\n\n\t\t__FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc));\n\t\treturn (FSStatus)FS_RESULT::SUCCESS;\n\t}\n\n\tsint32 FSIsEof(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask)\n\t{\n\t\tStackAllocator<FSAsyncParams, 1> asyncParams;\n\t\t__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);\n\t\tsint32 fsAsyncRet = FSIsEofAsync(fsClient, fsCmdBlock, fileHandle, errorMask, &asyncParams);\n\t\treturn __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);\n\t}\n\n\tvoid FSSetUserData(FSCmdBlock_t* fsCmdBlock, void* userData)\n\t{\n\t\tFSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);\n\t\tif (fsCmdBlockBody)\n\t\t\tfsCmdBlockBody->userData = userData;\n\t}\n\n\tvoid* FSGetUserData(FSCmdBlock_t* fsCmdBlock)\n\t{\n\t\tFSCmdBlockBody* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock);\n\t\tvoid* userData = nullptr;\n\t\tif (fsCmdBlockBody)\n\t\t\tuserData = fsCmdBlockBody->userData.GetPtr();\n\t\treturn userData;\n\t}\n\n\tFS_VOLSTATE FSGetVolumeState(FSClient_t* fsClient)\n\t{\n\t\t// todo\n\t\treturn FS_VOLSTATE_READY;\n\t}\n\n\tsint32 FSGetErrorCodeForViewer(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock)\n\t{\n\t\t// todo\n\t\treturn 0; // no error\n\t}\n\n\tFSCmdBlock_t* FSGetCurrentCmdBlock(FSClient_t* fsClient)\n\t{\n\t\tFSClientBody_t* fsClientBody = __FSGetClientBody(fsClient);\n\t\tif (!fsClientBody)\n\t\t\treturn nullptr;\n\t\tFSCmdBlockBody* cmdBlockBody = fsClientBody->currentCmdBlockBody;\n\t\tif (!cmdBlockBody)\n\t\t\treturn nullptr;\n\t\treturn cmdBlockBody->selfCmdBlock;\n\t}\n\n\tsint32 FSGetLastErrorCodeForViewer(FSClient_t* fsClient)\n\t{\n\t\tFSCmdBlock_t* cmdBlock = FSGetCurrentCmdBlock(fsClient);\n\t\tif (cmdBlock)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\treturn 0; // no error\n\t}\n\n\tstd::vector<FSAClientHandle> s_fsa_activeClients;\n\tstd::mutex s_fsa_activeClientsMutex;\n\n\tFSAClientHandle FSAAddClientEx(void* data)\n\t{\n\t\tif (data != NULL)\n\t\t{\n\t\t\t// TODO\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\tIOSDevHandle handle = IOS_Open(\"/dev/fsa\", 0);\n\t\tif (handle < IOS_ERROR::IOS_ERROR_OK)\n\t\t{\n\t\t\treturn (FSAClientHandle)FSA_RESULT::PERMISSION_ERROR;\n\t\t}\n\n\t\ts_fsa_activeClientsMutex.lock();\n\t\ts_fsa_activeClients.push_back((FSAClientHandle)handle);\n\t\ts_fsa_activeClientsMutex.unlock();\n\n\t\treturn (FSAClientHandle)handle;\n\t}\n\n\tFSAClientHandle FSAAddClient(void* data)\n\t{\n\t\treturn FSAAddClientEx(data);\n\t}\n\n\tFSA_RESULT FSADelClient(FSAClientHandle clientHandle)\n\t{\n\t\tif (clientHandle == 0)\n\t\t{\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\t\t}\n\t\ts_fsa_activeClientsMutex.lock();\n\n\t\tauto it = std::find(s_fsa_activeClients.begin(), s_fsa_activeClients.end(), clientHandle);\n\t\tif (it != s_fsa_activeClients.end())\n\t\t{\n\t\t\tIOS_Close(clientHandle);\n\t\t\ts_fsa_activeClients.erase(it);\n\t\t}\n\n\t\ts_fsa_activeClientsMutex.unlock();\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tSysAllocator<coreinit::IPCBufPool_t*> s_fsaIpcPool;\n\tSysAllocator<uint8, 0x37500> s_fsaIpcPoolBuffer;\n\tSysAllocator<uint32be> s_fsaIpcPoolBufferNumItems;\n\n\tstd::mutex sFSAIPCBufferLock;\n\tbool s_fsaInitDone = false;\n\n\tvoid FSAInit()\n\t{\n\t\tif (!s_fsaInitDone)\n\t\t{\n\t\t\ts_fsaIpcPool = IPCBufPoolCreate(s_fsaIpcPoolBuffer.GetPtr(), s_fsaIpcPoolBuffer.GetByteSize(), sizeof(iosu::fsa::FSAShimBuffer), &s_fsaIpcPoolBufferNumItems, 0);\n\t\t\ts_fsaInitDone = true;\n\t\t}\n\t}\n\n\tbool FSAShimCheckClientHandle(FSAClientHandle clientHandle)\n\t{\n\t\tstd::scoped_lock lock(s_fsa_activeClientsMutex);\n\t\tif (std::find(s_fsa_activeClients.begin(), s_fsa_activeClients.end(), clientHandle) != s_fsa_activeClients.end())\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tFSA_RESULT FSAShimAllocateBuffer(MEMPTR<MEMPTR<iosu::fsa::FSAShimBuffer>> outBuffer)\n\t{\n\t\tif (!s_fsaInitDone)\n\t\t\treturn FSA_RESULT::NOT_INIT;\n\n\t\tsFSAIPCBufferLock.lock();\n\t\tauto ptr = IPCBufPoolAllocate(s_fsaIpcPool, sizeof(iosu::fsa::FSAShimBuffer));\n\t\tsFSAIPCBufferLock.unlock();\n\n\t\tif (!ptr)\n\t\t\treturn FSA_RESULT::OUT_OF_RESOURCES;\n\n\t\tstd::memset(ptr, 0, sizeof(iosu::fsa::FSAShimBuffer));\n\t\toutBuffer[0] = reinterpret_cast<iosu::fsa::FSAShimBuffer*>(ptr);\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tFSA_RESULT FSAShimFreeBuffer(iosu::fsa::FSAShimBuffer* buffer)\n\t{\n\t\tsFSAIPCBufferLock.lock();\n\t\tIPCBufPoolFree(s_fsaIpcPool, (uint8_t*)buffer);\n\t\tsFSAIPCBufferLock.unlock();\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tFSA_RESULT FSACloseFile(FSAClientHandle client, uint32 fileHandle)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_CloseFile(shimBuffer->GetPtr(), client, fileHandle);\n\t\tif (result == FSA_RESULT::OK)\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAFlushFile(FSAClientHandle client, uint32_t fileHandle)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_FlushFile(shimBuffer->GetPtr(), client, fileHandle);\n\t\tif (result == FSA_RESULT::OK)\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAMakeDir(FSAClientHandle client, const char* path, uint32 uknVal660)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_MakeDir(shimBuffer->GetPtr(), client, path, uknVal660);\n\t\tif (result == FSA_RESULT::OK)\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSARename(FSAClientHandle client, char* oldPath, char* newPath)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_Rename(shimBuffer->GetPtr(), client, oldPath, newPath);\n\t\tif (result == FSA_RESULT::OK)\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAChangeDir(FSAClientHandle client, char* path)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_ChangeDir(shimBuffer->GetPtr(), client, (uint8_t*)path);\n\t\tif (result == FSA_RESULT::OK)\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAReadDir(FSAClientHandle client, FSDirHandle2 dirHandle, MEMPTR<FSDirEntry_t> directoryEntry)\n\t{\n\t\tif (directoryEntry.IsNull())\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_ReadDir(shimBuffer->GetPtr(), client, dirHandle);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t\tif (result == FSA_RESULT::OK)\n\t\t\t{\n\t\t\t\t*directoryEntry = shimBuffer->GetPtr()->response.cmdReadDir.dirEntry;\n\t\t\t}\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAOpenDir(FSAClientHandle client, char* path, MEMPTR<uint32be> dirHandle)\n\t{\n\t\tif (dirHandle.IsNull())\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_OpenDir(shimBuffer->GetPtr(), client, path);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t\tif (result == FSA_RESULT::OK)\n\t\t\t{\n\t\t\t\t*dirHandle = shimBuffer->GetPtr()->response.cmdOpenDir.dirHandleOutput;\n\t\t\t}\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSACloseDir(FSAClientHandle client, FSDirHandle2 dirHandle)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_CloseDir(shimBuffer->GetPtr(), client, dirHandle);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSARewindDir(FSAClientHandle client, FSDirHandle2 dirHandle)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_RewindDir(shimBuffer->GetPtr(), client, dirHandle);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAOpenFileEx(FSAClientHandle client, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32_t preallocSize, MEMPTR<uint32be> outFileHandle)\n\t{\n\t\tif (outFileHandle.IsNull())\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_OpenFile(shimBuffer->GetPtr(), client, path, mode, createMode, openFlag, preallocSize);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t\tif (result == FSA_RESULT::OK)\n\t\t\t{\n\t\t\t\t*outFileHandle = shimBuffer->GetPtr()->response.cmdOpenFile.fileHandleOutput;\n\t\t\t}\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAGetStatFile(FSAClientHandle client, FSFileHandle2 fileHandle, MEMPTR<FSStat_t> outStat)\n\t{\n\t\tif (outStat.IsNull())\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_GetStatFile(shimBuffer->GetPtr(), client, fileHandle);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t\tif (result == FSA_RESULT::OK)\n\t\t\t{\n\t\t\t\t*outStat = shimBuffer->GetPtr()->response.cmdStatFile.statOut;\n\t\t\t}\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSASetPosFile(FSAClientHandle client, FSFileHandle2 fileHandle, uint32_t pos)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_SetPosFile(shimBuffer->GetPtr(), client, fileHandle, pos);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSATruncateFile(FSAClientHandle client, FSFileHandle2 fileHandle)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_TruncateFile(shimBuffer->GetPtr(), client, fileHandle);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSARemove(FSAClientHandle client, char* path)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_Remove(shimBuffer->GetPtr(), client, (uint8_t*)path);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT __FSPrepareCmd_ChangeMode(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, uint8_t* path, uint32 permission, uint32 permissionMask)\n\t{\n\t\tif (fsaShimBuffer == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\t\tif (path == nullptr)\n\t\t\treturn FSA_RESULT::INVALID_PATH;\n\n\t\tfsaShimBuffer->fsaDevHandle = fsaHandle;\n\t\tfsaShimBuffer->ipcReqType = 0;\n\t\tfsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::REWINDDIR;\n\n\t\tsize_t pathLen = strlen((char*)path);\n\n\t\tfor (sint32 i = 0; i < pathLen; i++)\n\t\t\tfsaShimBuffer->request.cmdChangeMode.path[i] = path[i];\n\t\tfor (size_t i = pathLen; i < FSA_CMD_PATH_MAX_LENGTH; i++)\n\t\t\tfsaShimBuffer->request.cmdChangeMode.path[i] = '\\0';\n\n\t\tfsaShimBuffer->request.cmdChangeMode.mode1 = permission;\n\t\tfsaShimBuffer->request.cmdChangeMode.mode2 = permissionMask;\n\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tFSA_RESULT FSAChangeMode(FSAClientHandle client, const char* path, uint32 permission)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_ChangeMode(shimBuffer->GetPtr(), client, (uint8_t*)path, permission, 0x666);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAReadFile(FSAClientHandle client, void* buffer, uint32_t size, uint32_t count, FSFileHandle2 handle, uint32_t flags)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_ReadFile(shimBuffer->GetPtr(), client, buffer, size, count, 0, handle, flags & ~0x2);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAWriteFile(FSAClientHandle client, void* buffer, uint32_t size, uint32_t count, FSFileHandle2 handle, uint32_t flags)\n\t{\n\t\tif (!FSAShimCheckClientHandle(client))\n\t\t\treturn FSA_RESULT::INVALID_CLIENT_HANDLE;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_WriteFile(shimBuffer->GetPtr(), client, buffer, size, count, 0, handle, flags & ~0x2);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAGetInfoByQuery(FSAClientHandle client, char* path, uint32_t queryType, MEMPTR<void> outData)\n\t{\n\t\tif (outData.IsNull())\n\t\t\treturn FSA_RESULT::INVALID_BUFFER;\n\n\t\tStackAllocator<MEMPTR<iosu::fsa::FSAShimBuffer>, 1> shimBuffer;\n\t\tFSA_RESULT result = FSAShimAllocateBuffer(shimBuffer.GetPointer());\n\t\tif (result != FSA_RESULT::OK)\n\t\t\treturn result;\n\n\t\tresult = __FSPrepareCmd_QueryInfo(shimBuffer->GetPtr(), client, (uint8_t*)path, queryType);\n\t\tif (result == FSA_RESULT::OK)\n\t\t{\n\t\t\tresult = __FSAIPCSubmitCommand(shimBuffer->GetPtr());\n\t\t\tif (result == FSA_RESULT::OK)\n\t\t\t{\n\t\t\t\tif (queryType == FSA_QUERY_TYPE_FREESPACE)\n\t\t\t\t{\n\t\t\t\t\t*MEMPTR<uint64be>(outData.GetMPTR()) = shimBuffer->GetPtr()->response.cmdQueryInfo.queryFreeSpace.freespace;\n\t\t\t\t}\n\t\t\t\telse if (queryType == FSA_QUERY_TYPE_DEVICE_INFO)\n\t\t\t\t{\n\t\t\t\t\t*MEMPTR<FSADeviceInfo_t>(outData.GetMPTR()) = shimBuffer->GetPtr()->response.cmdQueryInfo.queryDeviceInfo.info;\n\t\t\t\t}\n\t\t\t\telse if (queryType == FSA_QUERY_TYPE_STAT)\n\t\t\t\t{\n\t\t\t\t\t*MEMPTR<FSStat_t>(outData.GetMPTR()) = shimBuffer->GetPtr()->response.cmdQueryInfo.queryStat.stat;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// TODO: implement other query types\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t\tresult = FSA_RESULT::FATAL_ERROR;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tFSAShimFreeBuffer(shimBuffer->GetPtr());\n\t\treturn result;\n\t}\n\n\tFSA_RESULT FSAGetStat(FSAClientHandle client, char* path, FSStat_t* outStat)\n\t{\n\t\treturn FSAGetInfoByQuery(client, path, FSA_QUERY_TYPE_STAT, outStat);\n\t}\n\n\tFSA_RESULT FSAGetFreeSpaceSize(FSAClientHandle client, char* path, uint64* outSize)\n\t{\n\t\treturn FSAGetInfoByQuery(client, path, FSA_QUERY_TYPE_DEVICE_INFO, outSize);\n\t}\n\n\tFSA_RESULT FSAGetDeviceInfo(FSAClientHandle client, char* path, void* outSize)\n\t{\n\t\treturn FSAGetInfoByQuery(client, path, FSA_QUERY_TYPE_FREESPACE, outSize);\n\t}\n\n\tSysAllocator s_fsaStr_OK(\"FSA_STATUS_OK\");\n\tSysAllocator s_fsaStr_NOT_INIT(\"FSA_STATUS_NOT_INIT\");\n\tSysAllocator s_fsaStr_END_OF_DIRECTORY(\"FSA_STATUS_END_OF_DIRECTORY\");\n\tSysAllocator s_fsaStr_END_OF_FILE(\"FSA_STATUS_END_OF_FILE\");\n\tSysAllocator s_fsaStr_MAX_CLIENTS(\"FSA_STATUS_MAX_CLIENTS\");\n\tSysAllocator s_fsaStr_MAX_FILES(\"FSA_STATUS_MAX_FILES\");\n\tSysAllocator s_fsaStr_MAX_DIRS(\"FSA_STATUS_MAX_DIRS\");\n\tSysAllocator s_fsaStr_ALREADY_EXISTS(\"FSA_STATUS_ALREADY_EXISTS\");\n\tSysAllocator s_fsaStr_NOT_FOUND(\"FSA_STATUS_NOT_FOUND\");\n\tSysAllocator s_fsaStr_PERMISSION_ERROR(\"FSA_STATUS_PERMISSION_ERROR\");\n\tSysAllocator s_fsaStr_INVALID_PARAM(\"FSA_STATUS_INVALID_PARAM\");\n\tSysAllocator s_fsaStr_INVALID_PATH(\"FSA_STATUS_INVALID_PATH\");\n\tSysAllocator s_fsaStr_INVALID_BUFFER(\"FSA_STATUS_INVALID_BUFFER\");\n\tSysAllocator s_fsaStr_INVALID_ALIGNMENT(\"FSA_STATUS_INVALID_ALIGNMENT\");\n\tSysAllocator s_fsaStr_INVALID_CLIENT_HANDLE(\"FSA_STATUS_INVALID_CLIENT_HANDLE\");\n\tSysAllocator s_fsaStr_INVALID_FILE_HANDLE(\"FSA_STATUS_INVALID_FILE_HANDLE\");\n\tSysAllocator s_fsaStr_INVALID_DIR_HANDLE(\"FSA_STATUS_INVALID_DIR_HANDLE\");\n\tSysAllocator s_fsaStr_NOT_FILE(\"FSA_STATUS_NOT_FILE\");\n\tSysAllocator s_fsaStr_NOT_DIR(\"FSA_STATUS_NOT_DIR\");\n\tSysAllocator s_fsaStr_OUT_OF_RESOURCES(\"FSA_STATUS_OUT_OF_RESOURCES\");\n\tSysAllocator s_fsaStr_UNKNOWN(\"FSA_STATUS_???\");\n\n\tconst char* FSAGetStatusStr(FSA_RESULT status)\n\t{\n\t\tswitch (status)\n\t\t{\n\t\tcase FSA_RESULT::OK:\n\t\t{\n\t\t\treturn s_fsaStr_OK.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::NOT_INIT:\n\t\t{\n\t\t\treturn s_fsaStr_NOT_INIT.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::END_OF_DIRECTORY:\n\t\t{\n\t\t\treturn s_fsaStr_END_OF_DIRECTORY.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::END_OF_FILE:\n\t\t{\n\t\t\treturn s_fsaStr_END_OF_FILE.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::MAX_CLIENTS:\n\t\t{\n\t\t\treturn s_fsaStr_MAX_CLIENTS.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::MAX_FILES:\n\t\t{\n\t\t\treturn s_fsaStr_MAX_FILES.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::MAX_DIRS:\n\t\t{\n\t\t\treturn s_fsaStr_MAX_DIRS.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::ALREADY_EXISTS:\n\t\t{\n\t\t\treturn s_fsaStr_ALREADY_EXISTS.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::NOT_FOUND:\n\t\t{\n\t\t\treturn s_fsaStr_NOT_FOUND.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::PERMISSION_ERROR:\n\t\t{\n\t\t\treturn s_fsaStr_PERMISSION_ERROR.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::INVALID_PARAM:\n\t\t{\n\t\t\treturn s_fsaStr_INVALID_PARAM.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::INVALID_PATH:\n\t\t{\n\t\t\treturn s_fsaStr_INVALID_PATH.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::INVALID_BUFFER:\n\t\t{\n\t\t\treturn s_fsaStr_INVALID_BUFFER.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::INVALID_ALIGNMENT:\n\t\t{\n\t\t\treturn s_fsaStr_INVALID_ALIGNMENT.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::INVALID_CLIENT_HANDLE:\n\t\t{\n\t\t\treturn s_fsaStr_INVALID_CLIENT_HANDLE.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::INVALID_FILE_HANDLE:\n\t\t{\n\t\t\treturn s_fsaStr_INVALID_FILE_HANDLE.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::INVALID_DIR_HANDLE:\n\t\t{\n\t\t\treturn s_fsaStr_INVALID_DIR_HANDLE.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::NOT_FILE:\n\t\t{\n\t\t\treturn s_fsaStr_NOT_FILE.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::NOT_DIR:\n\t\t{\n\t\t\treturn s_fsaStr_NOT_DIR.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::OUT_OF_RESOURCES:\n\t\t{\n\t\t\treturn s_fsaStr_OUT_OF_RESOURCES.GetPtr();\n\t\t}\n\t\tcase FSA_RESULT::FATAL_ERROR:\n\t\t{\n\t\t\treturn s_fsaStr_UNKNOWN.GetPtr();\n\t\t}\n\t\t}\n\t\tcemu_assert_unimplemented();\n\t\treturn s_fsaStr_UNKNOWN.GetPtr();\n\t}\n\n\tFSA_RESULT FSAMount(FSAClientHandle client, const char* source, const char* target, uint32 flags, void* arg_buf, uint32_t arg_len)\n\t{\n\t\tif (\"/dev/sdcard01\" == std::string_view(source) && \"/vol/external01\" == std::string_view(target) && flags == 0 && arg_buf == nullptr && arg_len == 0)\n\t\t{\n\t\t\tmountSDCard();\n\t\t\treturn FSA_RESULT::OK;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\treturn FSA_RESULT::FATAL_ERROR;\n\t}\n\n\tFSA_RESULT FSAUnmount(FSAClientHandle client,\n\t\t\t\t\t\t  const char* mountedTarget,\n\t\t\t\t\t\t  uint32 flags)\n\t{\n\t\treturn FSA_RESULT::OK;\n\t}\n\n\tvoid InitializeFS()\n\t{\n\t\tOSInitMutex(&s_fsGlobalMutex);\n\n\t\tcafeExportRegister(\"coreinit\", FSInit, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSShutdown, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSGetMountSource, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetMountSourceNext, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSMount, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSBindMount, LogType::CoreinitFile);\n\n\t\t// client management\n\t\tcafeExportRegister(\"coreinit\", FSAddClientEx, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSAddClient, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSDelClient, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetClientNum, LogType::CoreinitFile);\n\n\t\t// cmd\n\t\tcafeExportRegister(\"coreinit\", FSInitCmdBlock, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetAsyncResult, LogType::CoreinitFile);\n\n\t\t// file operations\n\t\tcafeExportRegister(\"coreinit\", FSOpenFileAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSOpenFile, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSOpenFileExAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSOpenFileEx, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSCloseFileAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSCloseFile, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSReadFileAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSReadFile, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSReadFileWithPosAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSReadFileWithPos, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSWriteFileAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSWriteFile, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSWriteFileWithPosAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSWriteFileWithPos, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSSetPosFileAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSSetPosFile, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetPosFileAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetPosFile, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSAppendFileAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSAppendFile, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSTruncateFileAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSTruncateFile, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSRenameAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSRename, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSRemoveAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSRemove, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSMakeDirAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSMakeDir, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSChangeDirAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSChangeDir, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetCwdAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetCwd, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSIsEofAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSIsEof, LogType::CoreinitFile);\n\n\t\t// directory operations\n\t\tcafeExportRegister(\"coreinit\", FSOpenDirAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSOpenDir, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSReadDirAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSReadDir, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSCloseDirAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSCloseDir, LogType::CoreinitFile);\n\n\t\t// stat\n\t\tcafeExportRegister(\"coreinit\", FSGetFreeSpaceSizeAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetFreeSpaceSize, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSGetStatAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetStat, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSGetStatFileAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetStatFile, LogType::CoreinitFile);\n\n\t\t// misc\n\t\tcafeExportRegister(\"coreinit\", FSFlushQuotaAsync, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSFlushQuota, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSSetUserData, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetUserData, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSGetCurrentCmdBlock, LogType::CoreinitFile);\n\n\t\tcafeExportRegister(\"coreinit\", FSGetVolumeState, LogType::CoreinitFile);\n\t\tcafeExportRegister(\"coreinit\", FSGetErrorCodeForViewer, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSGetLastErrorCodeForViewer, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", FSAMakeDir, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAInit, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAAddClient, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSADelClient, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSARewindDir, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAGetDeviceInfo, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSARename, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", FSAChangeDir, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", FSAMount, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAUnmount, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", FSAChangeMode, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAReadDir, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAOpenDir, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSACloseDir, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSACloseFile, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAFlushFile, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAOpenFileEx, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAGetStatFile, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAGetFreeSpaceSize, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSASetPosFile, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSATruncateFile, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSARemove, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAReadFile, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAWriteFile, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAGetStat, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", FSAGetStatusStr, LogType::Placeholder);\n\n\t\tg_fsRegisteredClientBodies = nullptr;\n\t}\n} // namespace coreinit\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_FS.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/IOSU/iosu_ipc_common.h\"\n#include \"Cafe/IOSU/fsa/fsa_types.h\"\n#include \"Cafe/IOSU/fsa/iosu_fsa.h\"\n#include \"coreinit_MessageQueue.h\"\n\ntypedef MEMPTR<betype<FSFileHandle2>> FSFileHandlePtr;\ntypedef MEMPTR<betype<FSDirHandle2>> FSDirHandlePtr;\n\ntypedef uint32 FSAClientHandle;\n\nstruct FSAsyncParams\n{\n\tMEMPTR<void> userCallback;\n\tMEMPTR<void> userContext;\n\tMEMPTR<coreinit::OSMessageQueue> ioMsgQueue;\n};\nstatic_assert(sizeof(FSAsyncParams) == 0xC);\n\nnamespace coreinit\n{\n\tstruct FSCmdBlockBody;\n\n\tstruct FSCmdQueue\n\t{\n\t\tenum class QUEUE_FLAG : uint32\n\t\t{\n\t\t\tIS_FULL = (1 << 0), // waiting for Ioctl(v) result\n\t\t\tCANCEL_ALL = (1 << 4),\n\t\t};\n\n\t\t/* +0x00 */ MEMPTR<FSCmdBlockBody> first;\n\t\t/* +0x04 */ MEMPTR<FSCmdBlockBody> last;\n\t\t/* +0x08 */ OSFastMutex fastMutex;\n\t\t/* +0x34 */ MPTR dequeueHandlerFuncMPTR;\n\t\t/* +0x38 */ uint32be numCommandsInFlight;\n\t\t/* +0x3C */ uint32 numMaxCommandsInFlight;\n\t\t/* +0x40 */ betype<QUEUE_FLAG> queueFlags;\n\t};\n\tDEFINE_ENUM_FLAG_OPERATORS(FSCmdQueue::QUEUE_FLAG);\n\n\tstatic_assert(sizeof(FSCmdQueue) == 0x44);\n\n#define FS_CLIENT_BUFFER_SIZE (5888)\n#define FS_CMD_BLOCK_SIZE (2688)\n\n\tstruct FSClient_t\n\t{\n\t\tuint8 buffer[FS_CLIENT_BUFFER_SIZE];\n\t};\n\n\tstruct FSCmdBlock_t\n\t{\n\t\tunion\n\t\t{\n\t\t\tuint8 buffer[FS_CMD_BLOCK_SIZE];\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tuint32 mount_it;\n\t\t\t} data;\n\t\t};\n\t};\n\n\tstatic_assert(sizeof(FSCmdBlock_t) == FS_CMD_BLOCK_SIZE);\n\n\tstruct FSClientBody_t\n\t{\n\t\tuint8 ukn0000[0x100];\n\t\tuint8 ukn0100[0x100];\n\t\tuint8 ukn0200[0x100];\n\t\tuint8 ukn0300[0x100];\n\t\tuint8 ukn0400[0x100];\n\t\tuint8 ukn0500[0x100];\n\t\tuint8 ukn0600[0x100];\n\t\tuint8 ukn0700[0x100];\n\t\tuint8 ukn0800[0x100];\n\t\tuint8 ukn0900[0x100];\n\t\tuint8 ukn0A00[0x100];\n\t\tuint8 ukn0B00[0x100];\n\t\tuint8 ukn0C00[0x100];\n\t\tuint8 ukn0D00[0x100];\n\t\tuint8 ukn0E00[0x100];\n\t\tuint8 ukn0F00[0x100];\n\t\tuint8 ukn1000[0x100];\n\t\tuint8 ukn1100[0x100];\n\t\tuint8 ukn1200[0x100];\n\t\tuint8 ukn1300[0x100];\n\t\tuint8 ukn1400[0x10];\n\t\tuint8 ukn1410[0x10];\n\t\tuint8 ukn1420[0x10];\n\t\tuint8 ukn1430[0x10];\n\t\tuint32 ukn1440;\n\t\tbetype<IOSDevHandle> iosuFSAHandle;\n\t\tuint32 ukn1448;\n\t\tuint32 ukn144C;\n\t\tuint8 ukn1450[0x10];\n\t\tuint8 ukn1460[0x10];\n\t\tuint8 ukn1470[0x10];\n\t\tFSCmdQueue fsCmdQueue;\n\t\t/* +0x14C4 */ MEMPTR<struct FSCmdBlockBody> currentCmdBlockBody; // set to currently active cmd\n\t\tuint32 ukn14C8;\n\t\tuint32 ukn14CC;\n\t\tuint8 ukn14D0[0x10];\n\t\tuint8 ukn14E0[0x10];\n\t\tuint8 ukn14F0[0x10];\n\t\tuint8 ukn1500[0x100];\n\t\tuint32 ukn1600;\n\t\tuint32 ukn1604;\n\t\tuint32 ukn1608;\n\t\tuint32 ukn160C;\n\t\tuint32 ukn1610;\n\t\tMEMPTR<FSClientBody_t> fsClientBodyNext;\t // next FSClientBody_t* in list of registered clients (list is circular, the last element points to the first element)\n\t\tuint32 ukn1618;\n\t\t/* +0x161C */ MEMPTR<FSClient_t> selfClient; // pointer to FSClient struct which holds this FSClientBody\n\t\tuint32 ukn1620;\n\t};\n\n\tstruct FSAsyncResult\n\t{\n\t\t/* +0x00 */ FSAsyncParams fsAsyncParamsNew;\n\n\t\t// fs message storage\n\t\tstruct FSMessage\n\t\t{\n\t\t\t/* +0x0C / 0x0978 */ MEMPTR<FSAsyncResult> fsAsyncResult;\n\t\t\t/* +0x10 */ MPTR fsClientMPTR2;\t // 0x097C\n\t\t\t/* +0x14 */ MPTR fsCmdBlockMPTR; // 0x0980\n\t\t\t/* +0x18 */ MPTR commandType;\t // 0x0984\n\t\t};\n\n\t\tunion\n\t\t{\n\t\t\tOSMessage osMsg;\n\t\t\tFSMessage fsMsg;\n\t\t} msgUnion;\n\n\t\t/* +0x1C */ MEMPTR<FSClient_t> fsClient;\t // 0x0988\n\t\t/* +0x20 */ MEMPTR<FSCmdBlock_t> fsCmdBlock; // 0x98C\n\t\t/* +0x24 */ uint32be fsStatusNew;\t\t\t // 0x990\n\t};\n\n\tstatic_assert(sizeof(FSAsyncResult) == 0x28);\n\n\tstruct FSCmdBlockReturnValues_t\n\t{\n\t\tunion\n\t\t{\n\t\t\tuint8 ukn0[0x14];\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tMEMPTR<betype<FSResHandle>> handlePtr;\n\t\t\t} cmdOpenFile;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tMEMPTR<uint32be> filePosPtr;\n\t\t\t} cmdGetPosFile;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tuint32be transferSize;\n\t\t\t\tuint32be uknVal094C;\n\t\t\t\tuint32be transferElemSize;\n\t\t\t\tuint32be uknVal0954;\n\t\t\t} cmdReadFile;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tuint32be transferSize;\n\t\t\t\tuint32be uknVal094C;\n\t\t\t\tuint32be transferElemSize;\n\t\t\t\tuint32be uknVal0954;\n\t\t\t} cmdWriteFile;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tMEMPTR<uint32be> handlePtr;\n\t\t\t} cmdOpenDir;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tMEMPTR<FSDirEntry_t> dirEntryPtr;\n\t\t\t} cmdReadDir;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tMEMPTR<char> pathPtr;\n\t\t\t\tuint32be transferSize;\n\t\t\t} cmdGetCwd;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tMEMPTR<void> queryResultPtr;\n\t\t\t} cmdQueryInfo;\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tMEMPTR<void> resultPtr;\n\t\t\t} cmdStatFile;\n\t\t};\n\t};\n\n\tstatic_assert(sizeof(FSCmdBlockReturnValues_t) == 0x14);\n\n\tstruct FSCmdBlockBody\n\t{\n\t\tiosu::fsa::FSAShimBuffer fsaShimBuffer;\n\t\t/* +0x0938 */ MEMPTR<FSClientBody_t> fsClientBody;\n\t\t/* +0x093C */ uint32 statusCode;\t// not a status code but rather the state? Uses weird values for some reason\n\t\t/* +0x0940 */ uint32be cancelState; // bitmask. Bit 0 -> If set command has been canceled\n\t\tFSCmdBlockReturnValues_t returnValues;\n\t\t// link for cmd queue\n\t\tMEMPTR<FSCmdBlockBody> next;\n\t\tMEMPTR<FSCmdBlockBody> previous;\n\t\t/* +0x960 */ betype<FSA_RESULT> lastFSAStatus;\n\t\tuint32 ukn0964;\n\t\t/* +0x0968 */ uint8 errHandling; // return error flag mask\n\t\t/* +0x096C */ FSAsyncResult asyncResult;\n\t\t/* +0x0994 */ MEMPTR<void> userData;\n\t\t/* +0x0998 */ OSMessageQueue syncTaskMsgQueue; // this message queue is used when mapping asynchronous tasks to synchronous API\n\t\t/* +0x09D4 */ OSMessage _syncTaskMsg[1];\n\t\t/* +0x09E4 */ MPTR cmdFinishFuncMPTR;\n\t\t/* +0x09E8 */ uint8 priority;\n\t\tuint8 uknStatusGuessed09E9;\n\t\tuint8 ukn09EA;\n\t\tuint8 ukn09EB;\n\t\tuint32 ukn09EC;\n\t\tuint32 ukn9F0;\n\t\tuint32be ukn9F4_lastErrorRelated;\n\t\t/* +0x9F8 */ MEMPTR<FSCmdBlock_t> selfCmdBlock;\n\t\tuint32 ukn9FC;\n\t};\n\n\tstatic_assert(sizeof(FSCmdBlock_t) == 0xA80);\n\n#define FSA_CMD_FLAG_SET_POS (1 << 0)\n\n#define FSA_CMD_STATUS_CODE_D900A21 0xD900A21 // cmd block is initialized\n#define FSA_CMD_STATUS_CODE_D900A22 0xD900A22 // cmd block is queued\n#define FSA_CMD_STATUS_CODE_D900A24 0xD900A24 // cmd block was processed and is available again\n#define FSA_CMD_STATUS_CODE_D900A26 0xD900A26 // cmd block result is being processed\n\n\tenum FS_VOLSTATE : sint32\n\t{\n\t\tFS_VOLSTATE_READY = 1,\n\t};\n\n\t// internal interface\n\tsint32 __FSQueryInfoAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* queryString, uint32 queryType, void* queryResult, uint32 errHandling, FSAsyncParams* fsAsyncParams);\n\n\t// coreinit exports\n\tFS_RESULT FSAddClientEx(FSClient_t* fsClient, uint32 uknR4, uint32 errHandling);\n\tFS_RESULT FSAddClient(FSClient_t* fsClient, uint32 errHandling);\n\tFS_RESULT FSDelClient(FSClient_t* fsClient, uint32 errHandling);\n\n\tvoid FSInitCmdBlock(FSCmdBlock_t* fsCmdBlock);\n\n\tsint32 FSOpenFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandlePtr outFileHandle, uint32 errHandling, FSAsyncParams* asyncParams);\n\tsint32 FSOpenFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandlePtr outFileHandle, uint32 errHandling);\n\n\tsint32 FSReadFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSReadFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask);\n\tsint32 FSReadFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSReadFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask);\n\n\tsint32 FSWriteFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSWriteFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask);\n\tsint32 FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSWriteFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask);\n\n\tsint32 FSSetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSSetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask);\n\tsint32 FSGetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSGetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask);\n\n\tsint32 FSAppendFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 size, uint32 count, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSAppendFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 size, uint32 count, uint32 errorMask);\n\n\tsint32 FSIsEofAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSIsEof(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask);\n\n\tsint32 FSRenameAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSRename(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask);\n\tsint32 FSRemoveAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSRemove(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask);\n\tsint32 FSMakeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* dirPath, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSMakeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, uint32 errorMask);\n\tsint32 FSChangeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSChangeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask);\n\tsint32 FSGetCwdAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSGetCwd(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask);\n\n\tsint32 FSGetFreeSpaceSizeAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSGetFreeSpaceSize(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask);\n\n\tsint32 FSOpenDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSOpenDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask);\n\tsint32 FSReadDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSReadDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSCloseDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSCloseDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask);\n\n\tsint32 FSFlushQuotaAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParams* fsAsyncParams);\n\tsint32 FSFlushQuota(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask);\n\n\tFS_VOLSTATE FSGetVolumeState(FSClient_t* fsClient);\n\n\tvoid InitializeFS();\n}; // namespace coreinit\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_GHS.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_GHS.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n\nnamespace coreinit\n{\n\tstruct iobbuf\n\t{\n\t\tuint32be ukn00; // lock index?\n\t\tuint32be ukn04; // ?\n\t\tuint32be ukn08; // ?\n\t\tuint32be flags; // permissions and channel\n\t};\n\n\t#define GHS_FOPEN_MAX\t100\n\n\tstruct GHSAccessibleData\n\t{\n\t\tiobbuf _iob[GHS_FOPEN_MAX];\n\t\tMPTR _iob_lock[GHS_FOPEN_MAX];\n\t\tuint16be __gh_FOPEN_MAX;\n\t\tMEMPTR<void> ghs_environ;\n\t\tuint32 ghs_Errno; // exposed as 'errno' data export\n\t};\n\n\tSysAllocator<GHSAccessibleData> g_ghs_data;\n\n\tstruct ghs_flock\n\t{\n\t\tuint32be mutexIndex;\n\t};\n\n\tvoid __ghs_flock_create(ghs_flock* flock);\n\tghs_flock* __ghs_flock_ptr(iobbuf* iob);\n\n\tstd::recursive_mutex g_ghsLock;\n\tstd::recursive_mutex g_ghsLockFlock;\n\n\tSysAllocator<coreinit::OSMutex, GHS_FOPEN_MAX> _flockMutexArray;\n\tbool _flockMutexMask[GHS_FOPEN_MAX]; // if set, mutex in _flockMutexArray is reserved\n\n\t#define IOB_FLAG_IN\t\t\t\t(0x1)\n\t#define IOB_FLAG_OUT\t\t\t(0x2)\n\n\t#define IOB_FLAG_CHANNEL(__x)\t((__x)<<18)\n\n\tvoid PrepareGHSRuntime()\n\t{\n\t\tg_ghs_data->ghs_environ = nullptr;\n\t\tg_ghs_data->__gh_FOPEN_MAX = GHS_FOPEN_MAX;\n\t\tg_ghs_data->ghs_Errno = 0;\n\n\t\tfor (sint32 i = 0; i < GHS_FOPEN_MAX; i++)\n\t\t\t_flockMutexMask[i] = false;\n\t\t// init stdin/stdout/stderr\n\t\tg_ghs_data->_iob[0].flags = IOB_FLAG_IN;\n\t\tg_ghs_data->_iob[1].flags = IOB_FLAG_OUT;\n\t\tg_ghs_data->_iob[1].flags = IOB_FLAG_OUT;\n\t\tg_ghs_data->_iob[0].flags |= IOB_FLAG_CHANNEL(0);\n\t\tg_ghs_data->_iob[1].flags |= IOB_FLAG_CHANNEL(1);\n\t\tg_ghs_data->_iob[2].flags |= IOB_FLAG_CHANNEL(2);\n\t\t__ghs_flock_create(__ghs_flock_ptr(g_ghs_data->_iob + 0));\n\t\t__ghs_flock_create(__ghs_flock_ptr(g_ghs_data->_iob + 1));\n\t\t__ghs_flock_create(__ghs_flock_ptr(g_ghs_data->_iob + 2));\n\n\t\tosLib_addVirtualPointer(\"coreinit\", \"__gh_FOPEN_MAX\", memory_getVirtualOffsetFromPointer(&g_ghs_data->__gh_FOPEN_MAX));\n\t\tosLib_addVirtualPointer(\"coreinit\", \"_iob\", memory_getVirtualOffsetFromPointer(g_ghs_data->_iob));\n\t\tosLib_addVirtualPointer(\"coreinit\", \"environ\", memory_getVirtualOffsetFromPointer(&g_ghs_data->ghs_environ));\n\t\tosLib_addVirtualPointer(\"coreinit\", \"errno\", memory_getVirtualOffsetFromPointer(&g_ghs_data->ghs_Errno));\n\t}\n\n\tvoid __ghs_flock_create(ghs_flock* flock)\n\t{\n\t\tg_ghsLockFlock.lock();\n\t\t// find available mutex\n\t\tsint32 mutexIndex = -1;\n\t\tfor (sint32 i = 0; i < GHS_FOPEN_MAX; i++)\n\t\t{\n\t\t\tif (!_flockMutexMask[i])\n\t\t\t{\n\t\t\t\tmutexIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (mutexIndex == -1)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"__ghs_flock_create(): No flock available\");\n\t\t\tcemu_assert(false); // no available mutex\n\t\t}\n\t\t// mark mutex as reserved\n\t\t_flockMutexMask[mutexIndex] = true;\n\t\t// init mutex\n\t\tcoreinit::OSInitMutexEx(_flockMutexArray.GetPtr() + mutexIndex, NULL);\n\t\t// update flock to point to the reserved mutex\n\t\tflock->mutexIndex = mutexIndex;\n\t\tg_ghsLockFlock.unlock();\n\t}\n\n\tvoid __ghs_flock_destroy(uint32 index)\n\t{\n\t\tg_ghsLockFlock.lock();\n\t\tcemu_assert_debug(index > 2); // stdin/stdout/stderr should never be released?\n\t\tcemu_assert(index < GHS_FOPEN_MAX);\n\t\tcemu_assert_debug(_flockMutexMask[index]);\n\t\t_flockMutexMask[index] = false;\n\t\tg_ghsLockFlock.unlock();\n\t}\n\n\tghs_flock* __ghs_flock_ptr(iobbuf* iob)\n\t{\n\t\tsize_t streamIndex = iob - g_ghs_data->_iob;\n\t\treturn (ghs_flock*)&(g_ghs_data->_iob_lock[streamIndex]);\n\t}\n\n\tvoid __ghs_flock_file(uint32 index)\n\t{\n\t\tcemu_assert(index < GHS_FOPEN_MAX);\n\t\tOSLockMutex(_flockMutexArray.GetPtr() + index);\n\t}\n\n\tvoid __ghs_funlock_file(uint32 index)\n\t{\n\t\tcemu_assert(index < GHS_FOPEN_MAX);\n\t\tOSUnlockMutex(_flockMutexArray.GetPtr() + index);\n\t}\n\n\tvoid __ghsLock()\n\t{\n\t\twhile (!g_ghsLock.try_lock())\n\t\t{\n\t\t\tPPCCore_switchToScheduler();\n\t\t}\n\t}\n\n\tvoid __ghsUnlock()\n\t{\n\t\tg_ghsLock.unlock();\n\t}\n\n\tvoid* __get_eh_init_block()\n\t{\n\t\treturn nullptr;\n\t}\n\n\tvoid* __get_eh_globals()\n\t{\n\t\tOSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\t\treturn currentThread->crt.eh_globals.GetPtr();\n\t}\n\n\tvoid* __get_eh_mem_manage()\n\t{\n\t\tOSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\t\treturn &currentThread->crt.eh_mem_manage;\n\t}\n\n\tsint32be* __gh_errno_ptr()\n\t{\n\t\tOSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\t\treturn &currentThread->context.ghs_errno;\n\t}\n\n\tvoid __gh_set_errno(sint32 errNo)\n\t{\n\t\t*__gh_errno_ptr() = errNo;\n\t}\n\n\tsint32 __gh_get_errno()\n\t{\n\t\treturn *__gh_errno_ptr();\n\t}\n\n\tvoid* __get_eh_store_globals()\n\t{\n\t\tOSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\t\treturn &currentThread->crt.eh_store_globals;\n\t}\n\n\tvoid* __get_eh_store_globals_tdeh()\n\t{\n\t\tOSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\t\treturn &currentThread->crt.eh_store_globals_tdeh;\n\t}\n\n\tstruct ghs_mtx_t\n\t{\n\t\tMEMPTR<coreinit::OSMutex> mutexPtr;\n\t};\n\n\tvoid __ghs_mtx_init(ghs_mtx_t* mtx)\n\t{\n\t\tmtx->mutexPtr = (coreinit::OSMutex*)coreinit::_weak_MEMAllocFromDefaultHeapEx(ppcsizeof<coreinit::OSMutex>(), 8);\n\t\tcoreinit::OSInitMutex(mtx->mutexPtr.GetPtr());\n\t}\n\n\tvoid __ghs_mtx_dst(ghs_mtx_t* mtx)\n\t{\n\t\tcoreinit::_weak_MEMFreeToDefaultHeap(mtx->mutexPtr.GetPtr());\n\t\tmtx->mutexPtr = nullptr;\n\t}\n\n\tvoid __ghs_mtx_lock(ghs_mtx_t* mtx)\n\t{\n\t\tcoreinit::OSLockMutex(mtx->mutexPtr.GetPtr());\n\t}\n\n\tvoid __ghs_mtx_unlock(ghs_mtx_t* mtx)\n\t{\n\t\tcoreinit::OSUnlockMutex(mtx->mutexPtr.GetPtr());\n\t}\n\n\tstruct OSTLSBlock\n\t{\n\t\tMPTR addr;\n\t\tuint32 ukn04;\n\t};\n\n\tstatic_assert(sizeof(OSTLSBlock) == 8);\n\n\tstruct TLS_Index\n\t{\n\t\tuint16 ukn00;\n\t\tuint16 tlsModuleIndex;\n\t\tMPTR   ukn04;\n\t};\n\n\tvoid* __tls_get_addr(TLS_Index* tlsIndex)\n\t{\n\t\tOSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\n\t\tif (_swapEndianU16(tlsIndex->tlsModuleIndex) == 0)\n\t\t\tassert_dbg();\n\n\t\t// check if we need to allocate additional TLS blocks for this thread\n\t\tif (_swapEndianU16(tlsIndex->tlsModuleIndex) >= _swapEndianU32(currentThread->numAllocatedTLSBlocks))\n\t\t{\n\t\t\tuint32 allocSize = (RPLLoader_GetMaxTLSModuleIndex() + 1) * sizeof(OSTLSBlock); // __OSDynLoad_gTLSHeader.ukn00 * 8;\n\t\t\tMPTR allocMem = coreinit_allocFromSysArea(allocSize, 4);\n\t\t\tmemset(memory_getPointerFromVirtualOffset(allocMem), 0, allocSize);\n\t\t\tif (_swapEndianU32(currentThread->numAllocatedTLSBlocks) != 0)\n\t\t\t{\n\t\t\t\t// keep previously allocated blocks\n\t\t\t\tmemcpy(memory_getPointerFromVirtualOffset(allocMem), memory_getPointerFromVirtualOffset(_swapEndianU32(currentThread->tlsBlocksMPTR)), _swapEndianU32(currentThread->numAllocatedTLSBlocks) * 8);\n\t\t\t}\n\t\t\tcurrentThread->tlsBlocksMPTR = _swapEndianU32(allocMem);\n\t\t\tcurrentThread->numAllocatedTLSBlocks = _swapEndianU16(RPLLoader_GetMaxTLSModuleIndex() + 1);\n\t\t}\n\t\t// look up TLS address based on moduleIndex\n\t\tOSTLSBlock* tlsBlock = (OSTLSBlock*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(currentThread->tlsBlocksMPTR) + sizeof(OSTLSBlock) * (uint32)_swapEndianU16(tlsIndex->tlsModuleIndex));\n\t\tif (tlsBlock->addr != _swapEndianU32(MPTR_NULL))\n\t\t{\n\t\t\t//osLib_returnFromFunction(hCPU, _swapEndianU32(tlsBlock->addr)+_swapEndianU32(tlsIndex->ukn04));\n\t\t\treturn memory_getPointerFromVirtualOffset(_swapEndianU32(tlsBlock->addr) + _swapEndianU32(tlsIndex->ukn04));\n\t\t}\n\t\t// alloc data for TLS block\n\t\tuint8* tlsSectionData = nullptr;\n\t\tsint32 tlsSize = 0;\n\n\t\tbool r = RPLLoader_GetTLSDataByTLSIndex((sint16)_swapEndianU16(tlsIndex->tlsModuleIndex), &tlsSectionData, &tlsSize);\n\t\tcemu_assert(r);\n\t\tcemu_assert(tlsSize != 0);\n\n\t\tMPTR tlsData = coreinit_allocFromSysArea(tlsSize, 32);\n\t\tmemcpy(memory_getPointerFromVirtualOffset(tlsData), tlsSectionData, tlsSize);\n\t\ttlsBlock->addr = _swapEndianU32(tlsData);\n\t\treturn memory_getPointerFromVirtualOffset(_swapEndianU32(tlsBlock->addr) + _swapEndianU32(tlsIndex->ukn04));\n\t}\n\n\tvoid InitializeGHS()\n\t{\n\t\tcafeExportRegister(\"coreinit\", __ghs_flock_create, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __ghs_flock_destroy, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __ghs_flock_ptr, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __ghs_flock_file, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __ghs_funlock_file, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __ghsLock, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __ghsUnlock, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", __get_eh_init_block, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __get_eh_globals, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __get_eh_mem_manage, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __gh_errno_ptr, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __gh_set_errno, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __gh_get_errno, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __get_eh_store_globals, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __get_eh_store_globals_tdeh, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", __ghs_mtx_init, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __ghs_mtx_dst, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __ghs_mtx_lock, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __ghs_mtx_unlock, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", __tls_get_addr, LogType::Placeholder);\n\t}\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_GHS.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tvoid PrepareGHSRuntime();\n\n\tsint32be* __gh_errno_ptr();\n\tvoid __gh_set_errno(sint32 errNo);\n\tsint32 __gh_get_errno();\n\n\tvoid InitializeGHS();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_HWInterface.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"coreinit_HWInterface.h\"\n\nnamespace coreinit\n{\n\tenum class RegisterInterfaceId : uint32 // for __OSRead/__OSWrite API (register access in userspace)\n\t{\n\t\tINTERFACE_VI_UKN = 0, // 0x0C1E0000\n\n\t\tINTERFACE_VI2_UKN = 3, // might also be some other interface?\n\n\n\t};\n\n\tenum class SysRegisterInterfaceId : uint32 // for __OSRead/__OSWriteRegister (register access via kernel systemcall)\n\t{\n\t\tINTERFACE_UKN = 0,\n\n\t\tINTERFACE_3_ACR_VI = 3, // 0x0D00021C\n\n\t\tINTERFACE_6_SI = 6, // 0x0D006400\n\t\tINTERFACE_7_AI_PROBABLY = 7, // 0x0D046C00 // AI or some secondary AI interface?\n\n\t};\n\n\tPAddr _GetRegisterPhysicalAddress(RegisterInterfaceId interfaceId, uint32 offset)\n\t{\n\t\tPAddr base = 0;\n\t\tswitch (interfaceId)\n\t\t{\n\t\tcase RegisterInterfaceId::INTERFACE_VI_UKN:\n\t\t\tbase = 0x0C1E0000;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemu_assert_debug(false); // todo\n\t\t\treturn 0;\n\t\t}\n\t\treturn base + offset;\n\t}\n\n\n\tPAddr _GetSysRegisterPhysicalAddress(SysRegisterInterfaceId interfaceId, uint32 offset)\n\t{\n\t\tPAddr base = 0;\n\t\tswitch (interfaceId)\n\t\t{\n\t\tcase SysRegisterInterfaceId::INTERFACE_3_ACR_VI:\n\t\t\tbase = 0x0D00021C;\n\t\t\tbreak;\n\t\tcase SysRegisterInterfaceId::INTERFACE_6_SI:\n\t\t\tbase = 0x0D006400;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemu_assert_debug(false); // todo\n\t\t\treturn 0;\n\t\t}\n\t\treturn base + offset;\n\t}\n\n\t/* Userspace register interface */\n\n\tuint32 OSReadRegister32(RegisterInterfaceId interfaceId, uint32 offset)\n\t{\n\t\tPAddr regAddr = _GetRegisterPhysicalAddress(interfaceId, offset);\n\t\tcemu_assert_debug(regAddr);\n\t\treturn MMU::ReadMMIO_32(regAddr);\n\t}\n\n\tuint16 OSReadRegister16(RegisterInterfaceId interfaceId, uint32 offset)\n\t{\n\t\tPAddr regAddr = _GetRegisterPhysicalAddress(interfaceId, offset);\n\t\tcemu_assert_debug(regAddr);\n\t\treturn MMU::ReadMMIO_16(regAddr);\n\t}\n\n\tvoid OSWriteRegister16(uint16 newValue, RegisterInterfaceId interfaceId, uint32 offset)\n\t{\n\t\tstatic bool s_dbg = false;\n\t\tif (!s_dbg)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\ts_dbg = true;\n\t\t}\n\t}\n\n\tvoid OSWriteRegister32(uint16 newValue, RegisterInterfaceId interfaceId, uint32 offset)\n\t{\n\t\tstatic bool s_dbg = false;\n\t\tif (!s_dbg)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\ts_dbg = true;\n\t\t}\n\t}\n\n\tvoid OSModifyRegister16(RegisterInterfaceId interfaceId, uint32 uknR4, uint32 uknR5, uint32 uknR6)\n\t{\n\t\tstatic bool s_dbg = false;\n\t\tif (!s_dbg)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\ts_dbg = true;\n\t\t}\n\t}\n\n\t/* Kernel register interface */\n\n\tuint32 __OSReadRegister32Ex(SysRegisterInterfaceId interfaceId, uint32 registerId)\n\t{\n\t\tuint32 offset = registerId * 4;\n\t\tcemu_assert_debug(offset < 0x40);\n\t\tPAddr regAddr = _GetSysRegisterPhysicalAddress(interfaceId, offset);\n\t\tcemu_assert_debug(regAddr);\n\t\treturn MMU::ReadMMIO_32(regAddr);\n\t}\n\n\tvoid __OSWriteRegister32Ex(SysRegisterInterfaceId interfaceId, uint32 registerId, uint32 newValue)\n\t{\n\t\tuint32 offset = registerId * 4;\n\t\tcemu_assert_debug(offset < 0x40);\n\t\tPAddr regAddr = _GetSysRegisterPhysicalAddress(interfaceId, offset);\n\t\tcemu_assert_debug(regAddr);\n\t\tMMU::WriteMMIO_32(regAddr, newValue);\n\t}\n\n\tvoid InitializeHWInterface()\n\t{\n\t\tcafeExportRegister(\"coreinit\", OSReadRegister32, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSReadRegister16, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSWriteRegister16, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSWriteRegister32, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSModifyRegister16, LogType::Placeholder);\n\n\n\t\tcafeExportRegister(\"coreinit\", __OSReadRegister32Ex, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __OSWriteRegister32Ex, LogType::Placeholder);\n\t};\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_HWInterface.h",
    "content": "namespace coreinit\n{\n\tvoid InitializeHWInterface();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_IM.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n\n// APD = Automatic Power Down\n\nnamespace coreinit\n{\n\t#define IM_ERROR_NONE 0\n\n\tvoid coreinitExport_IMIsAPDEnabledBySysSettings(PPCInterpreter_t* hCPU)\n\t{\n\t\tdebug_printf(\"IMIsAPDEnabledBySysSettings(0x%08x)\\n\", hCPU->gpr[3]);\n\t\tppcDefineParamTypePtr(isAPDEnabled, uint32be, 0);\n\t\t*isAPDEnabled = 0;\n\t\tosLib_returnFromFunction(hCPU, IM_ERROR_NONE);\n\t}\n\n\tvoid coreinitExport_IMGetTimeBeforeAPD(PPCInterpreter_t* hCPU)\n\t{\n\t\t// parameters:\n\t\t// r3\tuint32*\t\treturns the remaining number of seconds until auto-shutdown\n\t\tmemory_writeU32(hCPU->gpr[3], 60 * 30); // 30 minutes\n\t\tosLib_returnFromFunction(hCPU, IM_ERROR_NONE);\n\t}\n\n\tvoid coreinitExport_IMGetTimeBeforeDimming(PPCInterpreter_t* hCPU)\n\t{\n\t\t// parameters:\n\t\t// r3\tuint32*\t\treturns the remaining number of seconds until dimming\n\t\tmemory_writeU32(hCPU->gpr[3], 60 * 30); // 30 minutes\n\t\tosLib_returnFromFunction(hCPU, IM_ERROR_NONE);\n\t}\n\n\tbool imDimIsEnabled = true;\n\n\tvoid coreinitExport_IMEnableDim(PPCInterpreter_t* hCPU)\n\t{\n\t\timDimIsEnabled = true;\n\t\tosLib_returnFromFunction(hCPU, IM_ERROR_NONE);\n\t}\n\n\tvoid coreinitExport_IMIsDimEnabled(PPCInterpreter_t* hCPU)\n\t{\n\t\t// parameters:\n\t\t// r3\tuint32*\t\treturns the remaining number of seconds until auto-shutdown\n\t\tmemory_writeU32(hCPU->gpr[3], imDimIsEnabled ? 1 : 0); // enabled\n\t\tosLib_returnFromFunction(hCPU, IM_ERROR_NONE);\n\t}\n\n\tvoid coreinitExport_IMGetAPDPeriod(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"IMGetAPDPeriod(0x{:08x})\", hCPU->gpr[3]);\n\t\t// parameters:\n\t\t// r3\tuint32*\t\treturns the number of seconds until auto-shutdown occurs\n\t\tmemory_writeU32(hCPU->gpr[3], 600);\n\t\tosLib_returnFromFunction(hCPU, IM_ERROR_NONE);\n\t}\n\n\tvoid coreinitExport_IM_GetParameter(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"IM_GetParameter()\");\n\n\t\tppcDefineParamS32(imHandle, 0); // handle from IM_Open()\n\t\tppcDefineParamS32(uknR4, 1);\n\t\tppcDefineParamS32(parameterId, 2);\n\t\tppcDefineParamStructPtr(output, void, 3);\n\t\tppcDefineParamS32(uknR7, 4);\n\t\tppcDefineParamS32(uknR8, 5);\n\n\t\tif (parameterId == 0)\n\t\t{\n\t\t\t// inactive seconds\n\t\t\t*(uint32be*)output = 600;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, IM_ERROR_NONE);\n\t}\n\n\tvoid coreinitExport_IM_GetRuntimeParameter(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"IM_GetRuntimeParameter()\");\n\n\t\tppcDefineParamS32(parameterId, 0);\n\t\tppcDefineParamStructPtr(output, void, 1);\n\n\t\tif (parameterId == 8)\n\t\t{\n\t\t\t// indicates if last session was ended due to auto-power-down\n\t\t\t*(uint32be*)output = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, IM_ERROR_NONE);\n\t}\n\n\tvoid coreinitExport_IM_GetHomeButtonParams(PPCInterpreter_t* hCPU)\n\t{\n\t\tdebug_printf(\"IM_GetHomeButtonParams(...)\\n\");\n\t\tppcDefineParamS32(imObj, 0);\n\t\tppcDefineParamMPTR(ipcBuf, 1);\n\t\tppcDefineParamMPTR(paramOut, 2);\n\t\tppcDefineParamS32(uknR6, 3);\n\t\tppcDefineParamS32(uknR7, 4);\n\n\t\t// todo\n\t\t// note: No idea what these values mean. But they were chosen so that the Browser (surf.rpx) does not OSPanic()\n\t\tmemory_writeU32(paramOut + 0x0, 0);\n\t\tmemory_writeU32(paramOut + 0x4, 0);\n\n\t\t// for scope.rpx (Download Manager)\n\t\t//memory_writeU32(paramOut + 0x0, 1);\n\t\t//memory_writeU32(paramOut + 0x4, 2); // some sort of index (starting at 1?)\n\n\n\t\tosLib_returnFromFunction(hCPU, IM_ERROR_NONE);\n\t}\n\n\tvoid InitializeIM()\n\t{\n\t\tosLib_addFunction(\"coreinit\", \"IMIsAPDEnabledBySysSettings\", coreinitExport_IMIsAPDEnabledBySysSettings);\n\t\tosLib_addFunction(\"coreinit\", \"IMGetTimeBeforeAPD\", coreinitExport_IMGetTimeBeforeAPD);\n\t\tosLib_addFunction(\"coreinit\", \"IMGetTimeBeforeDimming\", coreinitExport_IMGetTimeBeforeDimming);\n\t\tosLib_addFunction(\"coreinit\", \"IMEnableDim\", coreinitExport_IMEnableDim);\n\t\tosLib_addFunction(\"coreinit\", \"IMIsDimEnabled\", coreinitExport_IMIsDimEnabled);\n\t\tosLib_addFunction(\"coreinit\", \"IMGetAPDPeriod\", coreinitExport_IMGetAPDPeriod);\n\t\tosLib_addFunction(\"coreinit\", \"IM_GetHomeButtonParams\", coreinitExport_IM_GetHomeButtonParams);\n\t\tosLib_addFunction(\"coreinit\", \"IM_GetParameter\", coreinitExport_IM_GetParameter);\n\t\tosLib_addFunction(\"coreinit\", \"IM_GetRuntimeParameter\", coreinitExport_IM_GetRuntimeParameter);\n\t}\n\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_IM.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tvoid InitializeIM();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_IOS.cpp",
    "content": "#include \"Cafe/OS/libs/coreinit/coreinit_IOS.h\"\n#include \"Cafe/IOSU/legacy/iosu_ioctl.h\"\n\n// superseded by coreinit_IPC.cpp/h\n\nsint32 __depr__IOS_Open(char* path, uint32 mode)\n{\n\tsint32 iosDevice = 0;\n\tif (path == nullptr)\n\t{\n\t\tiosDevice = 0;\n\t}\n\telse\n\t{\n\t\tif (strcmp(path, IOS_PATH_ODM) == 0)\n\t\t\tiosDevice = IOS_DEVICE_ODM;\n\t\telse if (strcmp(path, IOS_PATH_SOCKET) == 0)\n\t\t\tiosDevice = IOS_DEVICE_SOCKET;\n\t\telse if (strcmp(path, IOS_PATH_ACT) == 0)\n\t\t\tiosDevice = IOS_DEVICE_ACT;\n\t\telse if (strcmp(path, IOS_PATH_FPD) == 0)\n\t\t\tiosDevice = IOS_DEVICE_FPD;\n\t\telse if (strcmp(path, IOS_PATH_ACP_MAIN) == 0)\n\t\t\tiosDevice = IOS_DEVICE_ACP_MAIN;\n\t\telse if (strcmp(path, IOS_PATH_MCP) == 0)\n\t\t\tiosDevice = IOS_DEVICE_MCP;\n\t\telse if (strcmp(path, IOS_PATH_BOSS) == 0)\n\t\t\tiosDevice = IOS_DEVICE_BOSS;\n\t\telse if (strcmp(path, IOS_PATH_NIM) == 0)\n\t\t\tiosDevice = IOS_DEVICE_NIM;\n\t\telse if (strcmp(path, IOS_PATH_IOSUHAX) == 0)\n\t\t\treturn -1;\n\t\telse\n\t\t\tiosDevice = IOS_DEVICE_UKN;\n\t}\n\treturn iosDevice;\n}\n\nsint32 __depr__IOS_Ioctl(uint32 fd, uint32 request, void* inBuffer, uint32 inSize, void* outBuffer, uint32 outSize)\n{\n\tswitch (fd)\n\t{\n\t\tcase IOS_DEVICE_ODM:\n\t\t{\n\t\t\t// Home Menu uses ioctl cmd 5 on startup and then repeats cmd 4 every frame\n\t\t\tif (request == 4)\n\t\t\t{\n\t\t\t\t// check drive state\n\t\t\t\tdebug_printf(\"checkDriveState()\\n\");\n\t\t\t\t*(uint32be*)outBuffer = 0xA;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdebug_printf(\"odm unsupported ioctl %d\\n\", request);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\t// todo\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported Ioctl command\");\n\t\t}\n\t}\n\treturn 0;\n}\n\nsint32 __depr__IOS_Ioctlv(uint32 fd, uint32 request, uint32 countIn, uint32 countOut, ioBufferVector_t* ioBufferVectors)\n{\n\tStackAllocator<ioQueueEntry_t> _queueEntryBuf;\n\tioQueueEntry_t* queueEntry = _queueEntryBuf.GetPointer();\n\n\tqueueEntry->isIoctlv = true;\n\tqueueEntry->isAsync = false;\n\tqueueEntry->request = request;\n\tqueueEntry->countIn = countIn;\n\tqueueEntry->countOut = countOut;\n\tqueueEntry->bufferVectors = ioBufferVectors;\n\n\tqueueEntry->ppcThread = nullptr;\n\tqueueEntry->returnValue = 0;\n\tqueueEntry->isCompleted = false;\n\n\tsint32 r = iosuIoctl_pushAndWait(fd, queueEntry);\n\n\treturn r;\n}\n\nsint32 __depr__IOS_Close(uint32 fd)\n{\n\treturn 0;\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_IOS.h",
    "content": "// IOS\ntypedef struct _ioBufferVector_t ioBufferVector_t;\n\nsint32 __depr__IOS_Open(char* path, uint32 mode);\nsint32 __depr__IOS_Ioctl(uint32 fd, uint32 request, void* inBuffer, uint32 inSize, void* outBuffer, uint32 outSize);\nsint32 __depr__IOS_Ioctlv(uint32 fd, uint32 request, uint32 countIn, uint32 countOut, ioBufferVector_t* ioBufferVectors);\nsint32 __depr__IOS_Close(uint32 fd);\n\n// superseded by coreinit_IPC.h"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_IPC.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/IOSU/kernel/iosu_kernel.h\"\n#include \"Cafe/HW/Espresso/Const.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"coreinit_MessageQueue.h\"\n#include \"coreinit_IPC.h\"\n\nnamespace coreinit\n{\n\tstatic constexpr inline size_t IPC_NUM_RESOURCE_BUFFERS = 0x30;\n\t\n\tstruct IPCResourceBuffer\n\t{\n\t\tIPCCommandBody commandBody;\n\t\tuint8 bufferData[0x80 - 0x48];\n\t};\n\t\n\tstatic_assert(sizeof(IPCCommandBody) == 0x48);\n\tstatic_assert(sizeof(IPCResourceBuffer) == 0x80);\n\n\tstruct IPCResourceBufferDescriptor\n\t{\n\t\t/* +0x00 */ uint32be IsAllocated;\n\t\t/* +0x04 */ MEMPTR<OSMessageQueue> asyncMsgQueue; // optional, if set a message will be sent to this queue...\n\t\t/* +0x08 */ MEMPTR<void> asyncResultFunc; // ...otherwise this is checked and delegated to the IPC threads. If false, only eventSynchronousIPC will be signaled. If true, a message will be sent to the per-core ipc queue\n\t\t/* +0x0C */ MEMPTR<void> asyncResultUserParam;\n\t\t/* +0x10 */ uint32 ukn10;\n\t\t/* +0x14 */ MEMPTR<IPCResourceBuffer> resourcePtr;\n\t\t/* +0x18 */ OSEvent eventSynchronousIPC;\n\t};\n\n\tstatic_assert(sizeof(IPCResourceBufferDescriptor) == 0x3C);\n\n\tstruct IPCBufferFIFO\n\t{\n\t\tsint32be writeIndex;\n\t\tsint32be readIndex;\n\t\tsint32be numQueuedEntries;\n\t\tsint32be mostQueuedEntries;\n\t\tMEMPTR<IPCResourceBufferDescriptor> ringbufferArray[IPC_NUM_RESOURCE_BUFFERS];\n\n\t\tvoid Init()\n\t\t{\n\t\t\twriteIndex = 0;\n\t\t\treadIndex = -1;\n\t\t\tnumQueuedEntries = 0;\n\t\t\tmostQueuedEntries = 0;\n\t\t\tfor (size_t i = 0; i < IPC_NUM_RESOURCE_BUFFERS; i++)\n\t\t\t\tringbufferArray[i] = nullptr;\n\t\t}\n\n\t\tvoid Push(IPCResourceBufferDescriptor* descriptor)\n\t\t{\n\t\t\tcemu_assert(readIndex != writeIndex); // if equal, fifo is full (should not happen as there not more buffers than ringbuffer entries)\n\t\t\tringbufferArray[writeIndex] = descriptor;\n\t\t\tif (readIndex < 0)\n\t\t\t\treadIndex = writeIndex;\n\t\t\twriteIndex = (writeIndex + 1) % IPC_NUM_RESOURCE_BUFFERS;\n\t\t\t++numQueuedEntries;\n\t\t\tif (numQueuedEntries > mostQueuedEntries)\n\t\t\t\tmostQueuedEntries = numQueuedEntries;\n\t\t}\n\n\t\tIPCResourceBufferDescriptor* Pop()\n\t\t{\n\t\t\tif (numQueuedEntries == 0)\n\t\t\t\treturn nullptr;\n\t\t\tIPCResourceBufferDescriptor* r = ringbufferArray[readIndex].GetPtr();\n\t\t\t--numQueuedEntries;\n\t\t\tif (numQueuedEntries == 0)\n\t\t\t\treadIndex = -1;\n\t\t\telse\n\t\t\t\treadIndex = (readIndex + 1) % IPC_NUM_RESOURCE_BUFFERS;\n\t\t\treturn r;\n\t\t}\n\t};\n\n\tstruct IPCDriverCOSKernelCommunicationArea\n\t{\n\t\tuint32be numAvailableResponses;\n\t\tMEMPTR<IPCCommandBody> responseArray[11];\n\t};\n\n\tstatic_assert(sizeof(IPCDriverCOSKernelCommunicationArea) == 0x30);\n\n\tstruct alignas(64) IPCDriver\n\t{\n\t\tbetype<IPCDriverState> state;\n\t\tuint32 ukn04;\n\t\tuint32 coreIndex;\n\t\tuint32 writeIndexCmd020;\n\t\tMEMPTR<IPCResourceBuffer> resourceBuffers;\n\n\t\t/* 0x16C */ IPCBufferFIFO fifoFreeBuffers;\n\t\t/* 0x23C */ IPCBufferFIFO fifoBuffersInFlight;\n\n\t\t/* 0x334 */ uint32 resourceBuffersInitialized;\n\t\t/* 0x338 */ IPCDriverCOSKernelCommunicationArea kernelSharedArea; // this is passed to system call 0x1E00 (IPCOpen)\n\n\t\t/* 0x3FC */ IPCResourceBufferDescriptor resBufferDescriptor[IPC_NUM_RESOURCE_BUFFERS];\n\t};\n\n\t//static_assert(sizeof(IPCDriverInstance) == 0x1740);\n\n\tSysAllocator<IPCResourceBuffer, IPC_NUM_RESOURCE_BUFFERS * Espresso::CORE_COUNT, 0x40> s_ipcResourceBuffers;\n\tSysAllocator<IPCDriver, Espresso::CORE_COUNT, 0x40> s_ipcDriver;\n\n\tIPCDriver& IPCDriver_GetByCore(uint32 coreIndex)\n\t{\n\t\tcemu_assert_debug(coreIndex >= 0 && coreIndex < (uint32)Espresso::CORE_COUNT);\n\t\treturn s_ipcDriver[coreIndex];\n\t}\n\n\tvoid IPCDriver_InitForCore(uint32 coreIndex)\n\t{\n\t\tIPCDriver& ipcDriver = IPCDriver_GetByCore(coreIndex);\n\t\tipcDriver.coreIndex = coreIndex;\n\t\tipcDriver.state = IPCDriverState::INITIALIZED;\n\t\tipcDriver.resourceBuffers = s_ipcResourceBuffers.GetPtr() + IPC_NUM_RESOURCE_BUFFERS * coreIndex;\n\t\tipcDriver.resourceBuffersInitialized = 0;\n\t\t// setup resource descriptors\n\t\tfor (size_t i = 0; i < IPC_NUM_RESOURCE_BUFFERS; i++)\n\t\t{\n\t\t\tipcDriver.resBufferDescriptor[i].resourcePtr = ipcDriver.resourceBuffers.GetPtr() + i;\n\t\t\tipcDriver.resBufferDescriptor[i].asyncResultFunc = nullptr;\n\t\t\tipcDriver.resBufferDescriptor[i].asyncResultUserParam = nullptr;\n\t\t}\n\t\tipcDriver.resourceBuffersInitialized = 1;\n\t\t// setup resource buffer FIFOs\n\t\tipcDriver.fifoFreeBuffers.Init();\n\t\tipcDriver.fifoBuffersInFlight.Init();\n\t\tfor (size_t i = 0; i < IPC_NUM_RESOURCE_BUFFERS; i++)\n\t\t\tipcDriver.fifoFreeBuffers.Push(ipcDriver.resBufferDescriptor + i);\n\t}\n\n\tIPCResourceBufferDescriptor* IPCDriver_AllocateResource(IPCDriver* ipcDriver, IOSDevHandle devHandle, IPCCommandId cmdId, OSMessageQueue* asyncMessageQueue, MEMPTR<void> asyncResultFunc, MEMPTR<void> asyncResultUserParam)\n\t{\n\t\tcemu_assert_debug(ipcDriver->coreIndex == OSGetCoreId());\n\t\tIPCResourceBufferDescriptor* descriptor = nullptr;\n\t\twhile (true) \n\t\t{\n\t\t\tdescriptor = ipcDriver->fifoFreeBuffers.Pop();\n\t\t\tif (!descriptor)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"IPCDriver: Exceeded free resources\");\n\t\t\t\tOSYieldThread();\n\t\t\t\tcemu_assert_unimplemented(); // we should wait for an event instead of busylooping\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\tcemu_assert_debug(descriptor >= ipcDriver->resBufferDescriptor && descriptor < ipcDriver->resBufferDescriptor + IPC_NUM_RESOURCE_BUFFERS);\n\t\tcemu_assert_debug(descriptor->resourcePtr.GetPtr() >= ipcDriver->resourceBuffers.GetPtr() && descriptor->resourcePtr.GetPtr() < (ipcDriver->resourceBuffers.GetPtr() + IPC_NUM_RESOURCE_BUFFERS));\n\t\tIPCResourceBuffer* res = descriptor->resourcePtr;\n\t\tIPCCommandBody& cmdBody = res->commandBody;\n\n\t\tdescriptor->IsAllocated = 1;\n\t\tdescriptor->asyncMsgQueue = asyncMessageQueue;\n\t\tdescriptor->asyncResultFunc = asyncResultFunc;\n\t\tdescriptor->asyncResultUserParam = asyncResultUserParam;\n\n\t\tcmdBody.cmdId = cmdId;\n\t\tcmdBody.ukn0C = 0;\n\t\tcmdBody.ukn14 = 0;\n\t\tcmdBody.result = 0;\n\t\tcmdBody.devHandle = devHandle;\n\n\t\treturn descriptor;\n\t}\n\n\tvoid IPCDriver_ReleaseResource(IPCDriver* ipcDriver, IPCResourceBufferDescriptor* requestDescriptor)\n\t{\n\t\trequestDescriptor->IsAllocated = 0;\n\t\tipcDriver->fifoFreeBuffers.Push(requestDescriptor);\n\t}\n\n\t/* IPC threads */\n\n\tSysAllocator<OSThread_t, Espresso::CORE_COUNT> gIPCThread;\n\tSysAllocator<uint8, 0x4000 * Espresso::CORE_COUNT> _gIPCThreadStack;\n\tSysAllocator<uint8, 0x18 * Espresso::CORE_COUNT> _gIPCThreadNameStorage;\n\tSysAllocator<OSMessageQueue, Espresso::CORE_COUNT> gIPCThreadMsgQueue;\n\tSysAllocator<OSMessage, Espresso::CORE_COUNT * IPC_NUM_RESOURCE_BUFFERS> _gIPCThreadSemaphoreStorage;\n\n\t// handler thread for asynchronous callbacks for IPC responses\n\tvoid __IPCDriverThreadFunc(PPCInterpreter_t* hCPU)\n\t{\n\t\tuint32 coreIndex = OSGetCoreId();\n\t\twhile (true)\n\t\t{\n\t\t\tOSMessage msg;\n\t\t\tOSReceiveMessage(gIPCThreadMsgQueue.GetPtr() + coreIndex, &msg, OS_MESSAGE_BLOCK);\n\t\t\tcemu_assert(msg.data2 == 1); // type must be callback\n\t\t\tMEMPTR<void> cbFunc{ msg.message };\n\t\t\tcemu_assert(cbFunc != nullptr);\n\t\t\tPPCCoreCallback(cbFunc.GetPtr(), (uint32)msg.data0, (uint32)msg.data1);\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid IPCDriver_InitIPCThread(uint32 coreIndex)\n\t{\n\t\t// create a thread with 0x4000 stack space\n\t\t// and a message queue large enough to hold the maximum number of commands (IPC_NUM_RESOURCE_BUFFERS)\n\t\tOSInitMessageQueue(gIPCThreadMsgQueue.GetPtr() + coreIndex, _gIPCThreadSemaphoreStorage.GetPtr() + coreIndex * IPC_NUM_RESOURCE_BUFFERS, IPC_NUM_RESOURCE_BUFFERS);\n\t\tOSThread_t* ipcThread = gIPCThread.GetPtr() + coreIndex;\n\t\t__OSCreateThreadType(ipcThread, PPCInterpreter_makeCallableExportDepr(__IPCDriverThreadFunc), 0, nullptr, _gIPCThreadStack.GetPtr() + 0x4000 * coreIndex + 0x4000, 0x4000, 15, (1 << coreIndex), OSThread_t::THREAD_TYPE::TYPE_DRIVER);\n\t\tsprintf((char*)_gIPCThreadNameStorage.GetPtr()+coreIndex*0x18, \"{SYS IPC Core %d}\", coreIndex);\n\t\tOSSetThreadName(ipcThread, (char*)_gIPCThreadNameStorage.GetPtr() + coreIndex * 0x18);\n\t\tOSResumeThread(ipcThread);\n\t}\n\n\t/* coreinit IOS_* API */\n\n\tvoid _IPCDriver_SubmitCmdAllQueued(IPCDriver& ipcDriver)\n\t{\n\t\t// on COS, submitted commands first go to the COS kernel via syscall 0x2000, where they are processed, copied and queued again\n\t\t// we skip all of this and just pass our IPC commands directly to the IOSU kernel handler HLE function\n\t\t// important: IOSU needs to know which PPC core sent the command, so that it can also notify the same core about the result\n\t\tipcDriver.state = IPCDriverState::SUBMITTING;\n\t\twhile (true)\n\t\t{\n\t\t\tIPCResourceBufferDescriptor* res = ipcDriver.fifoBuffersInFlight.Pop();\n\t\t\tif (!res)\n\t\t\t\tbreak;\n\t\t\t// resolve pointers\n\t\t\tswitch (res->resourcePtr->commandBody.cmdId)\n\t\t\t{\n\t\t\tcase IPCCommandId::IOS_OPEN:\n\t\t\t\tres->resourcePtr->commandBody.args[0] = res->resourcePtr->commandBody.ppcVirt0.GetMPTR();\n\t\t\t\tbreak;\n\t\t\tcase IPCCommandId::IOS_CLOSE:\n\t\t\t\tbreak;\n\t\t\tcase IPCCommandId::IOS_IOCTL:\n\t\t\t\tres->resourcePtr->commandBody.args[1] = res->resourcePtr->commandBody.ppcVirt0.GetMPTR();\n\t\t\t\tres->resourcePtr->commandBody.args[3] = res->resourcePtr->commandBody.ppcVirt1.GetMPTR();\n\t\t\t\tbreak;\n\t\t\tcase IPCCommandId::IOS_IOCTLV:\n\t\t\t\tres->resourcePtr->commandBody.args[3] = res->resourcePtr->commandBody.ppcVirt0.GetMPTR();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tiosu::kernel::IPCSubmitFromCOS(ipcDriver.coreIndex, &res->resourcePtr->commandBody);\n\t\t}\n\t\tipcDriver.state = IPCDriverState::READY;\n\t}\n\n\tvoid _IPCDriver_SubmitCmd(IPCDriver& ipcDriver, IPCResourceBufferDescriptor* requestDescriptor)\n\t{\n\t\tif (requestDescriptor->asyncResultFunc == nullptr)\n\t\t\tOSInitEvent(&requestDescriptor->eventSynchronousIPC, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_AUTO);\n\t\tipcDriver.fifoBuffersInFlight.Push(requestDescriptor);\n\t\tcemu_assert_debug(ipcDriver.state == IPCDriverState::READY || ipcDriver.state == IPCDriverState::INITIALIZED);\n\t\t_IPCDriver_SubmitCmdAllQueued(ipcDriver);\n\t}\n\n\tuint32 _IPCDriver_WaitForResultAndRelease(IPCDriver& ipcDriver, IPCResourceBufferDescriptor* requestDescriptor)\n\t{\n\t\tOSWaitEvent(&requestDescriptor->eventSynchronousIPC);\n\t\tuint32 r = requestDescriptor->resourcePtr->commandBody.result;\n\t\tIPCDriver_ReleaseResource(&ipcDriver, requestDescriptor);\n\t\treturn r;\n\t}\n\n\tvoid IPCDriver_HandleResponse(IPCDriver& ipcDriver, IPCCommandBody* res, uint32 ppcCoreIndex)\n\t{\n\t\tsize_t index = (IPCResourceBuffer*)res - ipcDriver.resourceBuffers.GetPtr();\n\t\tcemu_assert(index < IPC_NUM_RESOURCE_BUFFERS);\n\t\tIPCResourceBufferDescriptor* descriptor = ipcDriver.resBufferDescriptor + index;\n\t\tcemu_assert(descriptor->IsAllocated != 0);\n\t\tif (descriptor->asyncMsgQueue != nullptr)\n\t\t{\n\t\t\tOSMessage msg;\n\t\t\tmsg.message = 0;\n\t\t\tmsg.data0 = res->result;\n\t\t\tmsg.data1 = descriptor->asyncResultUserParam.GetMPTR();\n\t\t\tmsg.data2 = 0;\n\t\t\tsint32 r = OSSendMessage(descriptor->asyncMsgQueue.GetPtr(), &msg, 0);\n\t\t\tcemu_assert(r != 0);\n\t\t\tIPCDriver_ReleaseResource(&ipcDriver, descriptor);\n\t\t\treturn;\n\t\t}\n\t\tif (descriptor->asyncResultFunc != nullptr)\n\t\t{\n\t\t\tOSMessage msg;\n\t\t\tmsg.message = descriptor->asyncResultFunc.GetMPTR();\n\t\t\tmsg.data0 = res->result;\n\t\t\tmsg.data1 = descriptor->asyncResultUserParam.GetMPTR();\n\t\t\tmsg.data2 = 1;\n\t\t\tsint32 r = OSSendMessage(gIPCThreadMsgQueue.GetPtr() + ppcCoreIndex, &msg, 0);\n\t\t\tcemu_assert(r != 0);\n\t\t\tIPCDriver_ReleaseResource(&ipcDriver, descriptor);\n\t\t\treturn;\n\t\t}\n\t\t// signal event for synchronous IPC\n\t\tOSSignalEvent(&descriptor->eventSynchronousIPC);\n\t}\n\n\t// handles responses queued in shared region\n\tvoid IPCDriver_KernelCallback(IPCDriver& ipcDriver)\n\t{\n\t\tcemu_assert_debug(ipcDriver.kernelSharedArea.numAvailableResponses != 0);\n\t\tfor (uint32 i = 0; i < ipcDriver.kernelSharedArea.numAvailableResponses; i++)\n\t\t\tIPCDriver_HandleResponse(ipcDriver, ipcDriver.kernelSharedArea.responseArray[i], ipcDriver.coreIndex);\n\t\tipcDriver.kernelSharedArea.numAvailableResponses = 0;\n\t}\n\n\t// called by our HLE'd IOSU directly\n\tvoid IPCDriver_NotifyResponses(uint32 ppcCoreIndex, IPCCommandBody** responseArray, uint32 numResponses)\n\t{\n\t\tcemu_assert(numResponses < 11);\n\t\tIPCDriver& ipcDriver = IPCDriver_GetByCore(ppcCoreIndex);\n\t\tipcDriver.kernelSharedArea.numAvailableResponses = numResponses;\n\t\tfor (uint32 i = 0; i < numResponses; i++)\n\t\t\tipcDriver.kernelSharedArea.responseArray[i] = responseArray[i];\n\t\tIPCDriver_KernelCallback(ipcDriver);\n\t}\n\n\tvoid _IPCDriver_SetupCmd_IOSOpen(IPCDriver& ipcDriver, IPCResourceBufferDescriptor* requestDescriptor, const char* devicePath, uint32 flags)\n\t{\n\t\t// store the path in the buffer after the command body\n\t\tIPCResourceBuffer* resBuffer = requestDescriptor->resourcePtr;\n\t\tIPCCommandBody& cmdBody = resBuffer->commandBody;\n\n\t\tuint8* buffer = resBuffer->bufferData;\n\t\tsize_t pathLen = strlen(devicePath);\n\t\tif (pathLen > 31)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IOS_Open(): Device path must not exceed 31 characters\");\n\t\t\tcemu_assert_error();\n\t\t}\n\t\tmemcpy(buffer, devicePath, pathLen + 1);\n\n\t\tcmdBody.ppcVirt0 = MEMPTR<void>(buffer).GetMPTR();\n\t\tcmdBody.args[0] = 0;\n\t\tcmdBody.args[1] = (uint32)(pathLen + 1);\n\t\tcmdBody.args[2] = flags;\n\t}\n\n\tIOS_ERROR _IPCDriver_SetupCmd_IOSIoctl(IPCDriver& ipcDriver, IPCResourceBufferDescriptor* requestDescriptor, uint32 requestId, void* ptrIn, uint32 sizeIn, void* ptrOut, uint32 sizeOut)\n\t{\n\t\tIPCCommandBody& cmdBody = requestDescriptor->resourcePtr->commandBody;\n\t\tcmdBody.args[0] = requestId;\n\t\tcmdBody.args[1] = MPTR_NULL; // set to ppcVirt0 later\n\t\tcmdBody.args[2] = sizeIn;\n\t\tcmdBody.args[3] = MPTR_NULL; // set to ppcVirt1 later\n\t\tcmdBody.args[4] = sizeOut;\n\t\tcmdBody.ppcVirt0 = MEMPTR<void>(ptrIn).GetMPTR();\n\t\tcmdBody.ppcVirt1 = MEMPTR<void>(ptrOut).GetMPTR();\n\t\treturn IOS_ERROR_OK;\n\t}\n\n\tIOS_ERROR _IPCDriver_SetupCmd_IOSIoctlv(IPCDriver& ipcDriver, IPCResourceBufferDescriptor* requestDescriptor, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec)\n\t{\n\t\tIPCCommandBody& cmdBody = requestDescriptor->resourcePtr->commandBody;\n\t\t// set args\n\t\tcmdBody.ppcVirt0 = MEMPTR<void>(vec).GetMPTR();\n\t\tcmdBody.args[0] = requestId;\n\t\tcmdBody.args[1] = numIn;\n\t\tcmdBody.args[2] = numOut;\n\t\tcmdBody.args[3] = 0; // set to ppcVirt0 later\n\t\treturn IOS_ERROR_OK;\n\t}\n\n\tIOSDevHandle IOS_Open(const char* devicePath, uint32 flags)\n\t{\n\t\tIPCDriver& ipcDriver = IPCDriver_GetByCore(OSGetCoreId());\n\t\tIPCResourceBufferDescriptor* ipcDescriptor = IPCDriver_AllocateResource(&ipcDriver, 0, IPCCommandId::IOS_OPEN, nullptr, nullptr, nullptr);\n\t\t_IPCDriver_SetupCmd_IOSOpen(ipcDriver, ipcDescriptor, devicePath, flags);\n\t\t_IPCDriver_SubmitCmd(ipcDriver, ipcDescriptor);\n\t\tuint32 r = _IPCDriver_WaitForResultAndRelease(ipcDriver, ipcDescriptor);\n\t\treturn r;\n\t}\n\n\tIOS_ERROR IOS_Close(IOSDevHandle devHandle)\n\t{\n\t\tIPCDriver& ipcDriver = IPCDriver_GetByCore(OSGetCoreId());\n\t\tIPCResourceBufferDescriptor* ipcDescriptor = IPCDriver_AllocateResource(&ipcDriver, devHandle, IPCCommandId::IOS_CLOSE, nullptr, nullptr, nullptr);\n\t\t_IPCDriver_SubmitCmd(ipcDriver, ipcDescriptor);\n\t\tIOS_ERROR r = (IOS_ERROR)_IPCDriver_WaitForResultAndRelease(ipcDriver, ipcDescriptor);\n\t\treturn r;\n\t}\n\n\tIOS_ERROR IOS_Ioctl(IOSDevHandle devHandle, uint32 requestId, void* ptrIn, uint32 sizeIn, void* ptrOut, uint32 sizeOut)\n\t{\n\t\tIPCDriver& ipcDriver = IPCDriver_GetByCore(OSGetCoreId());\n\t\tIPCResourceBufferDescriptor* ipcDescriptor = IPCDriver_AllocateResource(&ipcDriver, devHandle, IPCCommandId::IOS_IOCTL, nullptr, nullptr, nullptr);\n\t\tIOS_ERROR r = _IPCDriver_SetupCmd_IOSIoctl(ipcDriver, ipcDescriptor, requestId, ptrIn, sizeIn, ptrOut, sizeOut);\n\t\tif (r != IOS_ERROR_OK)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IOS_Ioctl failed due to bad parameters\");\n\t\t\tIPCDriver_ReleaseResource(&ipcDriver, ipcDescriptor);\n\t\t\treturn r;\n\t\t}\n\t\t_IPCDriver_SubmitCmd(ipcDriver, ipcDescriptor);\n\t\tr = (IOS_ERROR)_IPCDriver_WaitForResultAndRelease(ipcDriver, ipcDescriptor);\n\t\treturn r;\n\t}\n\n\tIOS_ERROR IOS_IoctlAsync(IOSDevHandle devHandle, uint32 requestId, void* ptrIn, uint32 sizeIn, void* ptrOut, uint32 sizeOut, MEMPTR<void> asyncResultFunc, MEMPTR<void> asyncResultUserParam)\n\t{\n\t\tIPCDriver& ipcDriver = IPCDriver_GetByCore(OSGetCoreId());\n\t\tIPCResourceBufferDescriptor* ipcDescriptor = IPCDriver_AllocateResource(&ipcDriver, devHandle, IPCCommandId::IOS_IOCTL, nullptr, asyncResultFunc, asyncResultUserParam);\n\t\tIOS_ERROR r = _IPCDriver_SetupCmd_IOSIoctl(ipcDriver, ipcDescriptor, requestId, ptrIn, sizeIn, ptrOut, sizeOut);\n\t\tif (r != IOS_ERROR_OK)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IOS_Ioctl failed due to bad parameters\");\n\t\t\tIPCDriver_ReleaseResource(&ipcDriver, ipcDescriptor);\n\t\t\treturn r;\n\t\t}\n\t\t_IPCDriver_SubmitCmd(ipcDriver, ipcDescriptor);\n\t\treturn r;\n\t}\n\n\tIOS_ERROR IOS_Ioctlv(IOSDevHandle devHandle, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec)\n\t{\n\t\tIPCDriver& ipcDriver = IPCDriver_GetByCore(OSGetCoreId());\n\t\tIPCResourceBufferDescriptor* ipcDescriptor = IPCDriver_AllocateResource(&ipcDriver, devHandle, IPCCommandId::IOS_IOCTLV, nullptr, nullptr, nullptr);\n\t\tIOS_ERROR r = _IPCDriver_SetupCmd_IOSIoctlv(ipcDriver, ipcDescriptor, requestId, numIn, numOut, vec);\n\t\tif (r != IOS_ERROR_OK)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IOS_Ioctlv failed due to bad parameters\");\n\t\t\tIPCDriver_ReleaseResource(&ipcDriver, ipcDescriptor);\n\t\t\treturn r;\n\t\t}\n\t\t_IPCDriver_SubmitCmd(ipcDriver, ipcDescriptor);\n\t\tr = (IOS_ERROR)_IPCDriver_WaitForResultAndRelease(ipcDriver, ipcDescriptor);\n\t\treturn r;\n\t}\n\n\tIOS_ERROR IOS_IoctlvAsync(IOSDevHandle devHandle, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec, MEMPTR<void> asyncResultFunc, MEMPTR<void> asyncResultUserParam)\n\t{\n\t\tIPCDriver& ipcDriver = IPCDriver_GetByCore(OSGetCoreId());\n\t\tIPCResourceBufferDescriptor* ipcDescriptor = IPCDriver_AllocateResource(&ipcDriver, devHandle, IPCCommandId::IOS_IOCTLV, nullptr, asyncResultFunc, asyncResultUserParam);\n\t\tIOS_ERROR r = _IPCDriver_SetupCmd_IOSIoctlv(ipcDriver, ipcDescriptor, requestId, numIn, numOut, vec);\n\t\tif (r != IOS_ERROR_OK)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IOS_Ioctlv failed due to bad parameters\");\n\t\t\tIPCDriver_ReleaseResource(&ipcDriver, ipcDescriptor);\n\t\t\treturn r;\n\t\t}\n\t\t_IPCDriver_SubmitCmd(ipcDriver, ipcDescriptor);\n\t\treturn r;\n\t}\n\n\tvoid MapIPCExports()\n\t{\n\t\tcafeExportRegister(\"coreinit\", IOS_Open, LogType::PPC_IPC);\n\t\tcafeExportRegister(\"coreinit\", IOS_Close, LogType::PPC_IPC);\n\t\tcafeExportRegister(\"coreinit\", IOS_Ioctl, LogType::PPC_IPC);\n\t\tcafeExportRegister(\"coreinit\", IOS_IoctlAsync, LogType::PPC_IPC);\n\t\tcafeExportRegister(\"coreinit\", IOS_Ioctlv, LogType::PPC_IPC);\n\t\tcafeExportRegister(\"coreinit\", IOS_IoctlvAsync, LogType::PPC_IPC);\n\t}\n\n\tvoid InitializeIPC()\n\t{\n\t\tfor (uint32 i = 0; i < Espresso::CORE_COUNT; i++)\n\t\t{\n\t\t\tIPCDriver_InitForCore(i);\n\t\t\tIPCDriver_InitIPCThread(i);\n\t\t}\n\t}\n\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_IPC.h",
    "content": "#include \"Cafe/IOSU/iosu_ipc_common.h\"\n#include \"Cafe/IOSU/iosu_types_common.h\"\n\nnamespace coreinit\n{\n\tvoid IPCDriver_NotifyResponses(uint32 ppcCoreIndex, IPCCommandBody** responseArray, uint32 numResponses);\n\n\tIOSDevHandle IOS_Open(const char* devicePath, uint32 flags);\n\tIOS_ERROR IOS_Close(IOSDevHandle devHandle);\n\tIOS_ERROR IOS_Ioctl(IOSDevHandle devHandle, uint32 requestId, void* ptrIn, uint32 sizeIn, void* ptrOut, uint32 sizeOut);\n\tIOS_ERROR IOS_IoctlAsync(IOSDevHandle devHandle, uint32 requestId, void* ptrIn, uint32 sizeIn, void* ptrOut, uint32 sizeOut, MEMPTR<void> asyncResultFunc, MEMPTR<void> asyncResultUserParam);\n\tIOS_ERROR IOS_Ioctlv(IOSDevHandle devHandle, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec);\n\tIOS_ERROR IOS_IoctlvAsync(IOSDevHandle devHandle, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec, MEMPTR<void> asyncResultFunc, MEMPTR<void> asyncResultUserParam);\n\n\tvoid MapIPCExports();\n\tvoid InitializeIPC();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_IPCBuf.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"coreinit_IPCBuf.h\"\n\nnamespace coreinit\n{\n\tvoid FIFOInit(IPCFifo_t* fifo, uint32 entryCount, void* entryArray)\n\t{\n\t\tfifo->entryCount = entryCount;\n\t\tfifo->entryArray = (FIFOEntry_t*)entryArray;\n\t\tfifo->writeIndex = 0;\n\t\tfifo->readIndex = -1;\n\t\tfifo->availableEntries = 0;\n\t}\n\n\tsint32 FIFOPush(IPCFifo_t* fifo, void* entry)\n\t{\n\t\tif (fifo->readIndex == fifo->writeIndex)\n\t\t{\n\t\t\tassert_dbg();\n\t\t\treturn -8;\n\t\t}\n\t\tfifo->entryArray[(uint32)fifo->writeIndex].p = (uint8*)entry;\n\t\tif ((sint32)fifo->readIndex < 0)\n\t\t{\n\t\t\t// set readIndex to valid value when fifo was empty\n\t\t\tfifo->readIndex = fifo->writeIndex;\n\t\t}\n\t\tfifo->availableEntries = (uint32)fifo->availableEntries + 1;\n\t\tfifo->writeIndex = ((uint32)fifo->writeIndex + 1) % (uint32)fifo->entryCount;\n\t\treturn 0;\n\t}\n\n\tsint32 FIFOPop(IPCFifo_t* fifo, uint8** entry)\n\t{\n\t\t*entry = nullptr;\n\t\tif ((sint32)fifo->readIndex < 0)\n\t\t\treturn -7;\n\t\tfifo->availableEntries = (uint32)fifo->availableEntries - 1;\n\t\t*entry = fifo->entryArray[(uint32)fifo->readIndex].p.GetPtr();\n\t\tfifo->readIndex = ((uint32)fifo->readIndex + 1) % (uint32)fifo->entryCount;\n\n\t\tif (fifo->availableEntries == (uint32be)0)\n\t\t{\n\t\t\tfifo->readIndex = -1;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tvoid* getUpwardsAlignedAddr(void* addr, uint32 alignment)\n\t{\n\t\tuint64 v = ((uint64)addr + alignment - 1) & ~(uint64)(alignment - 1);\n\t\treturn (uint8*)v;\n\t}\n\n\tvoid* getDownwardsAlignedAddr(void* addr, uint32 alignment)\n\t{\n\t\tuint64 v = ((uint64)addr) & ~(uint64)(alignment - 1);\n\t\treturn (uint8*)v;\n\t}\n\n\tIPCBufPool_t* IPCBufPoolCreate(uint8* bufferArea, uint32 bufferSize, uint32 entrySize, uint32be* entryCountOutput, uint32 uknR7)\n\t{\n\t\tmemset(bufferArea, 0, bufferSize);\n\t\tIPCBufPool_t* ipcBufPool = (IPCBufPool_t*)getUpwardsAlignedAddr(bufferArea, 4);\n\t\tuint8* alignedEnd = (uint8*)getDownwardsAlignedAddr(bufferArea + bufferSize, 4);\n\t\tuint8* dataStart = (uint8*)getUpwardsAlignedAddr(ipcBufPool + 1, 0x4);\n\n\t\t*entryCountOutput = 0;\n\t\t// todo: Validate parameters\n\n\t\tOSInitMutexEx(&ipcBufPool->mutex, NULL);\n\n\t\tipcBufPool->fullBufferPtr = bufferArea;\n\t\tipcBufPool->fullBufferSize = bufferSize;\n\t\tipcBufPool->uknFromParamR7 = uknR7;\n\n\t\tuint32 paddedEntrySize = (entrySize + 0x3F) & ~0x3F;\n\n\t\tipcBufPool->ukn10 = 0;\n\t\tipcBufPool->magic = 0xBADF00D;\n\n\t\tipcBufPool->entrySize1 = paddedEntrySize;\n\t\tipcBufPool->entrySize2 = paddedEntrySize;\n\n\t\tuint32 remainingSize = (uint32)((bufferArea + bufferSize) - dataStart);\n\t\tuint32 entryCount = remainingSize / paddedEntrySize;\n\t\tif (entryCount <= 1)\n\t\t\tassert_dbg();\n\n\t\tipcBufPool->entryCountMul4 = entryCount * 4;\n\t\tif ((uint32)ipcBufPool->entryCountMul4 >= paddedEntrySize)\n\t\t{\n\t\t\t// special handling required (need to adjust entry count?)\n\t\t\tassert_dbg();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tentryCount--; // remove one entry to make room for entry pointer array\n\t\t\tipcBufPool->entryCount = entryCount;\n\t\t\t*entryCountOutput = entryCount;\n\t\t\tipcBufPool->entryStartPtr = (dataStart + (uint32)ipcBufPool->entryCountMul4);\n\t\t\tFIFOInit(&ipcBufPool->fifo, (uint32)ipcBufPool->entryCount, dataStart);\n\t\t}\n\t\t// add all entries to the fifo\n\t\tfor (sint32 i = 0; i < (sint32)ipcBufPool->entryCount; i++)\n\t\t{\n\t\t\tuint8* entry = ipcBufPool->entryStartPtr.GetPtr() + i * (uint32)ipcBufPool->entrySize2;\n\t\t\tif (FIFOPush(&ipcBufPool->fifo, entry) != 0)\n\t\t\t\treturn nullptr;\n\t\t}\n\t\treturn ipcBufPool;\n\t}\n\n\tuint8* IPCBufPoolAllocate(IPCBufPool_t* ipcBufPool, uint32 size)\n\t{\n\t\tuint8* entry = nullptr;\n\t\tOSLockMutex(&ipcBufPool->mutex);\n\t\tif (ipcBufPool->magic == (uint32be)0xBADF00D && size <= (uint32)ipcBufPool->entrySize1)\n\t\t{\n\t\t\tFIFOPop(&ipcBufPool->fifo, &entry);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t\tOSUnlockMutex(&ipcBufPool->mutex);\n\t\treturn entry;\n\t}\n\n\tsint32 IPCBufPoolFree(IPCBufPool_t* ipcBufPool, uint8* entry)\n\t{\n\t\tOSLockMutex(&ipcBufPool->mutex);\n\t\tsint32 res = 0;\n\t\tif (ipcBufPool->magic == (uint32be)0xBADF00D)\n\t\t{\n\t\t\t// check if entry is actually part of the pool\n\t\t\tuint32 offset = (uint32)(entry - (uint8*)ipcBufPool->entryStartPtr.GetPtr());\n\t\t\tif ((offset % (uint32)ipcBufPool->entrySize2) != 0)\n\t\t\t\tassert_dbg();\n\t\t\tuint32 index = offset / (uint32)ipcBufPool->entrySize2;\n\t\t\tif ((index >= (uint32)ipcBufPool->entryCount))\n\t\t\t\tassert_dbg();\n\t\t\tFIFOPush(&ipcBufPool->fifo, entry);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t\tres = -4;\n\t\t}\n\t\tOSUnlockMutex(&ipcBufPool->mutex);\n\t\treturn res;\n\t}\n\n\tvoid coreinitExport_IPCBufPoolCreate(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamTypePtr(bufferArea, uint8, 0);\n\t\tppcDefineParamU32(bufferSize, 1);\n\t\tppcDefineParamU32(entrySize, 2);\n\t\tppcDefineParamU32BEPtr(entryCountOutput, 3);\n\t\tppcDefineParamU32(uknR7, 4);\n\t\tIPCBufPool_t* ipcBufPool = IPCBufPoolCreate(bufferArea, bufferSize, entrySize, entryCountOutput, uknR7);\n\t\tosLib_returnFromFunction(hCPU, memory_getVirtualOffsetFromPointer(ipcBufPool));\n\t\treturn;\n\t\t// example dump of IPC buffer (at 0x1011FF40):\n\t\t// 0000   0B AD F0 0D 10 11 FF 40  00 00 53 01 00 00 00 01  00 00 00 00 00 00 02 C0  00 00 02 C0 00 00 00 1D\n\t\t// 0020   10 12 00 40 00 00 00 78  00 00 00 00 00 00 00 00  00 00 00 1D 00 00 00 1D  10 11 FF A8 6D 55 74 58\n\t\t// 0040   10 00 87 2C 00 00 00 00  00 00 00 00 00 00 00 00  10 11 FF 7C 00 00 00 00  00 00 00 00 00 00 00 00\n\t\t// 0060   00 00 00 00 00 00 00 00  10 12 00 40 10 12 03 00  10 12 05 C0 10 12 08 80  10 12 0B 40 10 12 0E 00\n\t\t// 0080   10 12 10 C0 10 12 13 80  10 12 16 40 10 12 19 00  10 12 1B C0 10 12 1E 80  10 12 21 40 10 12 24 00\n\t\t// 00A0   10 12 26 C0 10 12 29 80  10 12 2C 40 10 12 2F 00  10 12 31 C0 10 12 34 80  10 12 37 40 10 12 3A 00\n\t\t// 00C0   10 12 3C C0 10 12 3F 80  10 12 42 40 10 12 45 00  10 12 47 C0 10 12 4A 80  10 12 4D 40 00 00 00 00\n\t\t// 00E0   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00\n\t}\n\n\tvoid coreinitExport_IPCBufPoolAllocate(PPCInterpreter_t* hCPU)\n\t{\n\t\tdebug_printf(\"IPCBufPoolAllocate(0x%08x,0x%x)\\n\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\tppcDefineParamStructPtr(ipcBufPool, IPCBufPool_t, 0);\n\t\tppcDefineParamU32(size, 1);\n\t\tuint8* entry = IPCBufPoolAllocate(ipcBufPool, size);\n\t\tosLib_returnFromFunction(hCPU, memory_getVirtualOffsetFromPointer(entry));\n\t}\n\n\tvoid coreinitExport_IPCBufPoolFree(PPCInterpreter_t* hCPU)\n\t{\n\t\tdebug_printf(\"IPCBufPoolFree(0x%08x,0x%08x)\\n\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\tppcDefineParamStructPtr(ipcBufPool, IPCBufPool_t, 0);\n\t\tppcDefineParamTypePtr(entry, uint8, 1);\n\t\tsint32 res = IPCBufPoolFree(ipcBufPool, entry);\n\t\tosLib_returnFromFunction(hCPU, res);\n\t}\n\n\tvoid InitializeIPCBuf()\n\t{\n\t\tosLib_addFunction(\"coreinit\", \"IPCBufPoolCreate\", coreinitExport_IPCBufPoolCreate);\n\t\tosLib_addFunction(\"coreinit\", \"IPCBufPoolAllocate\", coreinitExport_IPCBufPoolAllocate);\n\t\tosLib_addFunction(\"coreinit\", \"IPCBufPoolFree\", coreinitExport_IPCBufPoolFree);\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_IPCBuf.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tstruct FIFOEntry_t\n\t{\n\t\tMEMPTR<uint8> p;\n\t};\n\n\tstruct IPCFifo_t\n\t{\n\t\tuint32be writeIndex;\n\t\tuint32be readIndex;\n\t\tuint32be availableEntries; // number of available entries\n\t\tuint32be entryCount;\n\t\tMEMPTR<FIFOEntry_t> entryArray;\n\t};\n\n\tstruct IPCBufPool_t\n\t{\n\t\t/* +0x00 */ uint32be magic;\n\t\t/* +0x04 */ MEMPTR<void> fullBufferPtr;\n\t\t/* +0x08 */ uint32be fullBufferSize;\n\t\t/* +0x0C */ uint32be uknFromParamR7; // boolean?\n\t\t/* +0x10 */ uint32be ukn10;\t\t\t // set to zero on init\n\t\t/* +0x14 */ uint32be entrySize1;\n\t\t/* +0x18 */ uint32be entrySize2;\t // set to same value as entrySize1\n\t\t/* +0x1C */ uint32be entryCount;\t // actual number of used entries\n\t\t/* +0x20 */ MEMPTR<uint8> entryStartPtr;\n\t\t/* +0x24 */ uint32be entryCountMul4;\n\t\t/* +0x28 */ IPCFifo_t fifo;\n\t\t/* +0x3C */ coreinit::OSMutex mutex;\n\t\t/* +0x68 */ uint32 ukn68;\n\t\t// full size is 0x6C\n\t};\n\n\tstatic_assert(sizeof(IPCBufPool_t) == 0x6C);\n\n\tuint8* IPCBufPoolAllocate(IPCBufPool_t* ipcBufPool, uint32 size);\n\tIPCBufPool_t* IPCBufPoolCreate(uint8* bufferArea, uint32 bufferSize, uint32 entrySize, uint32be* entryCountOutput, uint32 uknR7);\n\tsint32 IPCBufPoolFree(IPCBufPool_t* ipcBufPool, uint8* entry);\n\n\tvoid InitializeIPCBuf();\n} // namespace coreinit\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Init.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/libs/padscore/padscore.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_SysHeap.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"Cafe/OS/libs/vpad/vpad.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_GHS.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_DynLoad.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_FG.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n\nextern MPTR _entryPoint;\nextern RPLModule* applicationRPX;\n\ntypedef struct\n{\n\tMPTR argv[32];\n\tuint32be argc;\n\tchar argStorage[0x1000];\n}coreinitInit_t;\n\ncoreinitInit_t* _coreinitInfo = nullptr;\n\nMPTR OSAllocFromSystem(uint32 size, uint32 alignment)\n{\n\treturn coreinit_allocFromSysArea(size, alignment);\n}\n\nvoid OSFreeToSystem(MPTR mem)\n{\n\tcoreinit_freeToSysArea(mem);\n}\n\nextern std::string _pathToExecutable;\nsint32 argStorageIndex;\n\nvoid _AddArg(const char* arg, sint32 len)\n{\n\tuint32 argc = _coreinitInfo->argc;\n\n\tchar* argStorageStr = _coreinitInfo->argStorage + argStorageIndex;\n\tmemcpy(argStorageStr, arg, len);\n\targStorageStr[len] = '\\0';\n\targStorageIndex += (sint32)strlen(arg) + 1;\n\n\t_coreinitInfo->argv[argc] = _swapEndianU32(memory_getVirtualOffsetFromPointer(argStorageStr));\n\t_coreinitInfo->argc = argc+1;\n}\n\nsint32 _GetArgLength(const char* arg)\n{\n\tsint32 c = 0;\n\twhile (*arg)\n\t{\n\t\tif (*arg == ' ')\n\t\t\tbreak; // end at whitespace\n\t\tcemu_assert_debug(*arg != '\\\"' && *arg != '\\''); // todo\n\t\targ++;\n\t\tc++;\n\t}\n\treturn c;\n}\n\nstatic std::string GetLaunchArgs()\n{\n\tstd::string argStr = CafeSystem::GetForegroundTitleArgStr();\n\tif(std::vector<std::string> overrideArgs; CafeSystem::GetOverrideArgStr(overrideArgs))\n\t{\n\t\t// args are overriden by launch directive (OSLaunchTitleByPath)\n\t\t// keep the rpx path but use the arguments from the override\n\t\tif (size_t pos = argStr.find(' '); pos != std::string::npos)\n\t\t\targStr.resize(pos);\n\t\tfor(size_t i=0; i<overrideArgs.size(); i++)\n\t\t{\n\t\t\targStr += \" \";\n\t\t\targStr += overrideArgs[i];\n\t\t}\n\t}\n\treturn argStr;\n}\n\nvoid CafeInit()\n{\n\t// extract executable filename\n\tsint32 rpxPathStart = (sint32)_pathToExecutable.size() - 1;\n\tif (rpxPathStart > 0)\n\t{\n\t\twhile (rpxPathStart > 0 && _pathToExecutable[rpxPathStart-1] != '/')\n\t\t\trpxPathStart--;\n\t}\n\telse\n\t{\n\t\trpxPathStart = 0;\n\t}\n\t\n\tstd::string_view rpxFileName(_pathToExecutable.data() + rpxPathStart, _pathToExecutable.size() - rpxPathStart);\n\n\targStorageIndex = 0;\n\t_coreinitInfo->argc = 0;\n\t_AddArg(rpxFileName.data(), rpxFileName.size());\n\tstrcpy((char*)_coreinitInfo->argStorage, std::string(rpxFileName).c_str());\n\n\tstd::string _argStr = GetLaunchArgs();\n\tCafeSystem::UnsetOverrideArgs(); // make sure next launch doesn't accidentally use the same arguments\n\tconst char* argString = _argStr.c_str();\n\t// attach parameters from arg string\n\tif (argString && argString[0] != '\\0')\n\t{\n\t\tconst char* t = strstr(argString, \".rpx\");\n\t\tif (t)\n\t\t{\n\t\t\tt += 4;\n\t\t\twhile (*t)\n\t\t\t{\n\t\t\t\t// skip all whitespace\n\t\t\t\twhile (*t)\n\t\t\t\t{\n\t\t\t\t\tif (*t == ' ')\n\t\t\t\t\t{\n\t\t\t\t\t\tt++;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// get length of arg\n\t\t\t\tsint32 argLength = _GetArgLength(t);\n\t\t\t\tif (argLength > 0)\n\t\t\t\t{\n\t\t\t\t\t// add arg\n\t\t\t\t\t_AddArg(t, argLength);\n\t\t\t\t\t// next\n\t\t\t\t\tt += argLength;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unable to find end of rpx file name in arg string\");\n\t\t}\n\t}\n\t// setup UGQR\n\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\thCPU->spr.UGQR[0 + 2] = 0x00040004;\n\thCPU->spr.UGQR[0 + 3] = 0x00050005;\n\thCPU->spr.UGQR[0 + 4] = 0x00060006;\n\thCPU->spr.UGQR[0 + 5] = 0x00070007;\n\tcoreinit::InitForegroundBucket();\n\tcoreinit::InitSysHeap();\n}\n\nstruct PreinitUserHeapStruct\n{\n\tMEMPTR<coreinit::MEMHeapBase> heapTempMEM1;\n\tMEMPTR<coreinit::MEMHeapBase> heapTempFG;\n\tMEMPTR<coreinit::MEMHeapBase> heapTempMEM2;\n};\n\nSysAllocator<PreinitUserHeapStruct> g_preinitUserParam;\n\nvoid InitCafeHeaps()\n{\n\t// init default heaps\n\tg_preinitUserParam->heapTempMEM1 = nullptr;\n\tg_preinitUserParam->heapTempFG = nullptr;\n\tg_preinitUserParam->heapTempMEM2 = nullptr;\n\tcoreinit::InitDefaultHeaps(g_preinitUserParam->heapTempMEM1, g_preinitUserParam->heapTempFG, g_preinitUserParam->heapTempMEM2);\n\t// if __preinit_user export exists in main executable, run it and pass our heaps\n\tMPTR exportAddr = applicationRPX ? RPLLoader_FindRPLExport(applicationRPX, \"__preinit_user\", false) : MPTR_NULL;\n\tif (exportAddr != MPTR_NULL)\n\t{\n\t\tPPCCoreCallback(exportAddr, &g_preinitUserParam->heapTempMEM1, &g_preinitUserParam->heapTempFG, &g_preinitUserParam->heapTempMEM2);\n\t}\n\t// setup heaps\n\tif (g_preinitUserParam->heapTempMEM1 != nullptr)\n\t\tcoreinit::MEMSetBaseHeapHandle(0, g_preinitUserParam->heapTempMEM1);\n\tif (g_preinitUserParam->heapTempFG != nullptr)\n\t\tcoreinit::MEMSetBaseHeapHandle(8, g_preinitUserParam->heapTempFG);\n\tif (g_preinitUserParam->heapTempMEM2 != nullptr)\n\t\tcoreinit::MEMSetBaseHeapHandle(1, g_preinitUserParam->heapTempMEM2);\n}\n\nMPTR CoreInitEntry(sint32 argc, MPTR argv)\n{\n\tconst char* rpxPath = (char*)memory_getPointerFromVirtualOffset(memory_readU32(argv + 0));\n\tInitCafeHeaps();\n\t// do a dummy allocation via the OSDynLoad allocator\n\t// Watch Dogs relies on this to correctly set up its malloc() allocator\n\t// must be larger than 0x190 to trigger creation of a new memory segment. But also must not be close to page alignment (0x1000) or else the bug will trigger\n\tvoid* dummyAlloc = coreinit::OSDynLoad_AllocatorAlloc(0x500, 0x4);\n\tif (dummyAlloc)\n\t\tcoreinit::OSDynLoad_AllocatorFree(dummyAlloc);\n\treturn _entryPoint;\n}\n\nsint32 _coreinitTitleEntryPoint;\n\nvoid coreinit_start(PPCInterpreter_t* hCPU)\n{\n\t_coreinitInfo = (coreinitInit_t*)memory_getPointerFromVirtualOffset(coreinit_allocFromSysArea(sizeof(coreinitInit_t), 32));\n\tmemset(_coreinitInfo, 0, sizeof(coreinitInit_t));\n\n\tCafeInit();\n\t_coreinitTitleEntryPoint = CoreInitEntry(_coreinitInfo->argc, memory_getVirtualOffsetFromPointer(_coreinitInfo->argv));\n\t\n\tRPLLoader_CallEntrypoints();\n\n\t// init vpadbase (todo - simulate entrypoints for HLE modules)\n\tpadscore::start();\n\tvpad::start();\n\n\t// call entry-type callbacks in graphic packs\n\tfor (const auto gp : GraphicPack2::GetActiveGraphicPacks())\n\t{\n\t    for (const auto [callback, type] : gp->GetCallbacks())\n\t\t{\n\t\t    if (type == GPCallbackType::Entry)\n\t\t\t{\n\t\t        PPCCoreCallback(callback);\n\t\t\t}\n\t\t}\n\t}\n\n\t// continue at main executable entrypoint\n\thCPU->gpr[4] = memory_getVirtualOffsetFromPointer(_coreinitInfo->argv);\n\thCPU->gpr[3] = _coreinitInfo->argc;\n\thCPU->instructionPointer = _coreinitTitleEntryPoint;\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n\n/*\n\tLocked cache is mapped to the following memory regions:\n\t\t\toffset\t\tsize\n\tcore0:\t0xFFC00000\t0x4000\n\tcore1:\t0xFFC40000\t0x4000\n\tcore2:\t0xFFC80000\t0x4000\n*/\n\n#define LC_LOCKED_CACHE_GRANULARITY\t\t(0x200)\t // 512B\n#define LC_LOCKED_CACHE_SIZE\t\t\t(0x4000) // 16KB\n\n#define LC_MASK_FREE\t\t\t(0)\n#define LC_MASK_RESERVED\t\t(1)\n#define LC_MASK_RESERVED_END\t(2) // indicates end of reserved block\n\nnamespace coreinit\n{\n\tuint8   lcCacheMask[PPC_CORE_COUNT][(LC_LOCKED_CACHE_SIZE + LC_LOCKED_CACHE_GRANULARITY - 1) / LC_LOCKED_CACHE_GRANULARITY] = { 0 };\n\tuint32  lcAllocatedBlocks[PPC_CORE_COUNT] = { 0 };\n\n\tMPTR lcAddr[] =\n\t{\n\t\t0xFFC00000, // core 0\n\t\t0xFFC40000, // core 1\n\t\t0xFFC80000  // core 2\n\t};\n\n\tvoid coreinitExport_LCGetMaxSize(PPCInterpreter_t* hCPU)\n\t{\n\t\tosLib_returnFromFunction(hCPU, LC_LOCKED_CACHE_SIZE);\n\t}\n\n\tvoid coreinitExport_LCAlloc(PPCInterpreter_t* hCPU)\n\t{\n\t\t//debug_printf(\"LCAlloc(0x%04x) Thread %08x Core %d\", hCPU->gpr[3], coreinitThread_getCurrentThread(hCPU), PPCInterpreter_getCoreIndex(hCPU));\n\t\tuint32 size = hCPU->gpr[3];\n\t\tif (size == 0 || size > LC_LOCKED_CACHE_SIZE)\n\t\t{\n\t\t\tdebug_printf(\"LCAlloc: Invalid alloc size %d\\n\", size);\n\t\t\tosLib_returnFromFunction(hCPU, MPTR_NULL);\n\t\t\treturn;\n\t\t}\n\t\tif ((size % LC_LOCKED_CACHE_GRANULARITY) != 0)\n\t\t{\n\t\t\tdebug_printf(\"LCAlloc: Unaligned alloc size 0x%04x\\n\", size);\n\t\t\tsize += (LC_LOCKED_CACHE_GRANULARITY - 1);\n\t\t\tsize &= ~(LC_LOCKED_CACHE_GRANULARITY - 1);\n\t\t}\n\t\tuint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU);\n\t\tuint8* cacheMask = lcCacheMask[coreIndex];\n\t\tuint32 entryMaskLength = size / LC_LOCKED_CACHE_GRANULARITY;\n\t\tfor (uint32 i = 0; i <= (LC_LOCKED_CACHE_SIZE / LC_LOCKED_CACHE_GRANULARITY) - entryMaskLength; i++)\n\t\t{\n\t\t\t// check if range starting at i is free\n\t\t\tbool rangeIsFree = true;\n\t\t\tfor (uint32 f = 0; f < entryMaskLength; f++)\n\t\t\t{\n\t\t\t\tif (cacheMask[i + f] != LC_MASK_FREE)\n\t\t\t\t{\n\t\t\t\t\trangeIsFree = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (rangeIsFree)\n\t\t\t{\n\t\t\t\t// found space for allocation\n\t\t\t\tMPTR allocAddr = lcAddr[coreIndex] + i * LC_LOCKED_CACHE_GRANULARITY;\n\t\t\t\t// mark range as allocated\n\t\t\t\tfor (uint32 f = 0; f < entryMaskLength - 1; f++)\n\t\t\t\t{\n\t\t\t\t\tcacheMask[i + f] = LC_MASK_RESERVED;\n\t\t\t\t}\n\t\t\t\tcacheMask[i + entryMaskLength - 1] = LC_MASK_RESERVED_END;\n\t\t\t\t// update allocation counter\n\t\t\t\tlcAllocatedBlocks[coreIndex] += entryMaskLength;\n\t\t\t\t// return allocAddr\n\t\t\t\t//debug_printf(\"LCAlloc result %08x Thread %08x Core %d\", (uint32)allocAddr, coreinitThread_getCurrentThread(hCPU), PPCInterpreter_getCoreIndex(hCPU));\n\t\t\t\tosLib_returnFromFunction(hCPU, allocAddr);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// not enough space left\t\n\t\t//debug_printf(\"LCAlloc failed Thread %08x Core %d\", coreinitThread_getCurrentThread(hCPU), PPCInterpreter_getCoreIndex(hCPU));\n\t\tosLib_returnFromFunction(hCPU, MPTR_NULL);\n\t}\n\n\n\tvoid coreinitExport_LCDealloc(PPCInterpreter_t* hCPU)\n\t{\n\t\tuint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU);\n\t\tuint8* cacheMask = lcCacheMask[coreIndex];\n\t\t//printf(\"LCDealloc(0x%08x)\\n\", hCPU->gpr[3]);\n\n\t\tMPTR deallocAddr = hCPU->gpr[3];\n\t\tif (deallocAddr < lcAddr[coreIndex] || deallocAddr >= (lcAddr[coreIndex] + LC_LOCKED_CACHE_SIZE))\n\t\t{\n\t\t\t// out of bounds\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tcemuLog_log(LogType::Force, \"LCDealloc(): Out of bounds\");\n#endif\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\treturn;\n\t\t}\n\t\tuint32 relativeOffset = (uint32)deallocAddr - lcAddr[coreIndex];\n\t\tif ((relativeOffset % LC_LOCKED_CACHE_GRANULARITY) != 0)\n\t\t{\n\t\t\tdebug_printf(\"LCDealloc: Offset alignment is invalid (0x%08x / 0x%08x)\\n\", deallocAddr, relativeOffset);\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\treturn;\n\t\t}\n\t\tuint32 startIndex = relativeOffset / LC_LOCKED_CACHE_GRANULARITY;\n\t\t// check this is really the beginning of an allocated block\n\t\tif (startIndex > 0 && (cacheMask[startIndex - 1] != LC_MASK_RESERVED_END && cacheMask[startIndex - 1] != LC_MASK_FREE))\n\t\t{\n\t\t\tdebug_printf(\"LCDealloc: Offset is invalid (0x%08x / 0x%08x)\\n\", deallocAddr, relativeOffset);\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\treturn;\n\t\t}\n\t\t// free range by reseting mask in allocated region\n\t\tfor (uint32 i = startIndex; i < (LC_LOCKED_CACHE_SIZE / LC_LOCKED_CACHE_GRANULARITY); i++)\n\t\t{\n\t\t\tif (cacheMask[i] == LC_MASK_RESERVED_END)\n\t\t\t{\n\t\t\t\t// end of allocated block reached\n\t\t\t\tcacheMask[i] = LC_MASK_FREE;\n\t\t\t\t// update allocation counter\n\t\t\t\tlcAllocatedBlocks[coreIndex]--;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (cacheMask[i] == LC_MASK_FREE)\n\t\t\t{\n\t\t\t\tdebug_printf(\"LCDealloc: Allocation mask error detected\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcacheMask[i] = LC_MASK_FREE;\n\t\t\t// update allocation counter\n\t\t\tlcAllocatedBlocks[coreIndex]--;\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid coreinitExport_LCGetUnallocated(PPCInterpreter_t* hCPU)\n\t{\n\t\tuint32 unallocatedBytes = 0;\n\t\tuint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU);\n\t\tunallocatedBytes = LC_LOCKED_CACHE_SIZE - (lcAllocatedBlocks[coreIndex] * LC_LOCKED_CACHE_GRANULARITY);\n\t\t//debug_printf(\"LCGetUnallocated() Result: 0x%x\\n\", unallocatedBytes);\n\t\tosLib_returnFromFunction(hCPU, unallocatedBytes);\n\t}\n\n\tvoid coreinitExport_LCGetAllocatableSize(PPCInterpreter_t* hCPU)\n\t{\n\t\tdebug_printf(\"LCGetAllocatableSize()\\n\");\n\t\t// no parameters, returns largest allocatable block size\n\t\t// get core LC parameters\n\t\tuint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU);\n\t\tuint8* cacheMask = lcCacheMask[coreIndex];\n\t\t// scan for largest range of available blocks\n\t\tuint32 largestFreeRange = 0;\n\t\tuint32 currentRangeSize = 0;\n\t\tfor (uint32 i = 0; i < LC_LOCKED_CACHE_SIZE / LC_LOCKED_CACHE_GRANULARITY; i++)\n\t\t{\n\t\t\tif (cacheMask[i] == LC_MASK_FREE)\n\t\t\t{\n\t\t\t\tcurrentRangeSize++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlargestFreeRange = std::max(largestFreeRange, currentRangeSize);\n\t\t\t\tcurrentRangeSize = 0;\n\t\t\t}\n\t\t}\n\t\tlargestFreeRange = std::max(largestFreeRange, currentRangeSize);\n\t\tosLib_returnFromFunction(hCPU, largestFreeRange * LC_LOCKED_CACHE_GRANULARITY);\n\t}\n\n\tuint32 LCIsEnabled[PPC_CORE_COUNT] = { 0 };\n\n\tvoid coreinitExport_LCEnableDMA(PPCInterpreter_t* hCPU)\n\t{\n\t\t//debug_printf(\"LCEnableDMA()\\n\");\n\n\t\tLCIsEnabled[PPCInterpreter_getCoreIndex(hCPU)]++;\n\t\tosLib_returnFromFunction(hCPU, 1);\n\t}\n\n\tsint32 _lcDisableErrorCounter = 0;\n\n\tvoid coreinitExport_LCDisableDMA(PPCInterpreter_t* hCPU)\n\t{\n\t\t//debug_printf(\"LCDisableDMA()\\n\");\n#ifndef PUBLIC_RELASE\n\t\tif (LCIsEnabled[PPCInterpreter_getCoreIndex(hCPU)] == 0)\n\t\t\tassert_dbg();\n#endif\n\t\tLCIsEnabled[PPCInterpreter_getCoreIndex(hCPU)]--;\n#ifdef CEMU_DEBUG_ASSERT\n\t\tif (LCIsEnabled[PPCInterpreter_getCoreIndex(hCPU)] == 0)\n\t\t{\n\t\t\tuint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU);\n\t\t\tuint8* cacheMask = lcCacheMask[coreIndex];\n\t\t\tfor (uint32 i = 0; i <= (LC_LOCKED_CACHE_SIZE / LC_LOCKED_CACHE_GRANULARITY); i++)\n\t\t\t{\n\t\t\t\tif (cacheMask[i] != LC_MASK_FREE)\n\t\t\t\t{\n\t\t\t\t\tif (_lcDisableErrorCounter < 15)\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"LC disabled but there is still memory allocated\");\n\t\t\t\t\t\t_lcDisableErrorCounter++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#endif\n\n\t\tosLib_returnFromFunction(hCPU, 1);\n\t}\n\n\tvoid coreinitExport_LCIsDMAEnabled(PPCInterpreter_t* hCPU)\n\t{\n\t\tosLib_returnFromFunction(hCPU, LCIsEnabled[PPCInterpreter_getCoreIndex(hCPU)] ? 1 : 0);\n\t}\n\n\tvoid coreinitExport_LCHardwareIsAvailable(PPCInterpreter_t* hCPU)\n\t{\n\t\t// on the real HW, LC is shared between processes and not all processes can access it. In the emulator we don't care and always return true.\n\t\tosLib_returnFromFunction(hCPU, 1);\n\t}\n\n\tvoid coreinitExport_LCLoadDMABlocks(PPCInterpreter_t* hCPU)\n\t{\n\t\t//printf(\"LCLoadDMABlocks(0x%08x, 0x%08x, 0x%08x)\\n\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\t\tuint32 numBlocks = hCPU->gpr[5];\n\t\tif (numBlocks == 0)\n\t\t\tnumBlocks = 128;\n\t\tuint32 transferSize = numBlocks * 32;\n\t\tuint8* destPtr = memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\tuint8* srcPtr = memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\t\t// copy right away, we don't emulate the DMAQueue currently\n\t\tmemcpy(destPtr, srcPtr, transferSize);\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid coreinitExport_LCStoreDMABlocks(PPCInterpreter_t* hCPU)\n\t{\n\t\t//printf(\"LCStoreDMABlocks(0x%08x, 0x%08x, 0x%08x)\\n\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\t\tuint32 numBlocks = hCPU->gpr[5];\n\t\tif (numBlocks == 0)\n\t\t\tnumBlocks = 128;\n\t\t//uint32 transferSize = numBlocks*32;\n\t\tuint8* destPtr = memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\tuint8* srcPtr = memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\t\t// copy right away, we don't emulate the DMAQueue currently\n\t\tmemcpy_qwords(destPtr, srcPtr, numBlocks * (32 / sizeof(uint64)));\n\n\t\tLatteBufferCache_notifyDCFlush(hCPU->gpr[3], numBlocks * 32);\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid coreinitExport_LCWaitDMAQueue(PPCInterpreter_t* hCPU)\n\t{\n\t\t//printf(\"LCWaitDMAQueue(%d)\\n\", hCPU->gpr[3]);\n\t\tuint32 len = hCPU->gpr[3];\n\t\t// todo: Implement (be aware DMA queue is per core)\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid InitializeLC()\n\t{\n\t\tfor (sint32 f = 0; f < PPC_CORE_COUNT; f++)\n\t\t{\n\t\t\tmemset(lcCacheMask[f], LC_MASK_FREE, (LC_LOCKED_CACHE_SIZE + LC_LOCKED_CACHE_GRANULARITY - 1) / LC_LOCKED_CACHE_GRANULARITY);\n\t\t}\n\n\t\tosLib_addFunction(\"coreinit\", \"LCGetMaxSize\", coreinitExport_LCGetMaxSize);\n\n\t\tosLib_addFunction(\"coreinit\", \"LCAlloc\", coreinitExport_LCAlloc);\n\t\tosLib_addFunction(\"coreinit\", \"LCDealloc\", coreinitExport_LCDealloc);\n\t\tosLib_addFunction(\"coreinit\", \"LCGetUnallocated\", coreinitExport_LCGetUnallocated);\n\t\tosLib_addFunction(\"coreinit\", \"LCGetAllocatableSize\", coreinitExport_LCGetAllocatableSize);\n\n\t\tosLib_addFunction(\"coreinit\", \"LCEnableDMA\", coreinitExport_LCEnableDMA);\n\t\tosLib_addFunction(\"coreinit\", \"LCDisableDMA\", coreinitExport_LCDisableDMA);\n\t\tosLib_addFunction(\"coreinit\", \"LCIsDMAEnabled\", coreinitExport_LCIsDMAEnabled);\n\t\tosLib_addFunction(\"coreinit\", \"LCHardwareIsAvailable\", coreinitExport_LCHardwareIsAvailable);\n\n\t\tosLib_addFunction(\"coreinit\", \"LCLoadDMABlocks\", coreinitExport_LCLoadDMABlocks);\n\t\tosLib_addFunction(\"coreinit\", \"LCStoreDMABlocks\", coreinitExport_LCStoreDMABlocks);\n\t\tosLib_addFunction(\"coreinit\", \"LCWaitDMAQueue\", coreinitExport_LCWaitDMAQueue);\n\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_LockedCache.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tvoid InitializeLC();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MCP.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/IOSU/legacy/iosu_ioctl.h\"\n#include \"Cafe/IOSU/legacy/iosu_mcp.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IOS.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MCP.h\"\n\n\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"Cafe/OS/libs/nn_act/nn_act.h\"\n#include \"config/CemuConfig.h\"\n\n#include \"Cafe/CafeSystem.h\"\n\n#define mcpPrepareRequest() \\\nStackAllocator<iosuMcpCemuRequest_t> _buf_mcpRequest; \\\nStackAllocator<ioBufferVector_t> _buf_bufferVector; \\\niosuMcpCemuRequest_t* mcpRequest = _buf_mcpRequest.GetPointer(); \\\nioBufferVector_t* mcpBufferVector = _buf_bufferVector.GetPointer(); \\\nmemset(mcpRequest, 0, sizeof(iosuMcpCemuRequest_t)); \\\nmemset(mcpBufferVector, 0, sizeof(ioBufferVector_t)); \\\nmcpBufferVector->buffer = (uint8*)mcpRequest;\n\n#define MCP_FAKE_HANDLE\t\t(0x00000010)\n\ntypedef struct\n{\n\tuint32be n0;\n\tuint32be n1;\n\tuint32be n2;\n}mcpSystemVersion_t;\n\nstatic_assert(sizeof(MCPTitleInfo) == 0x61, \"title entry size is invalid\");\nstatic_assert(offsetof(MCPTitleInfo, appPath) == 0xC, \"title entry appPath has invalid offset\");\nstatic_assert(offsetof(MCPTitleInfo, titleVersion) == 0x48, \"title entry titleVersion has invalid offset\");\nstatic_assert(offsetof(MCPTitleInfo, osVersion) == 0x4A, \"title entry osVersion has invalid offset\");\n\nMCPHANDLE MCP_Open()\n{\n\t// placeholder\n\treturn MCP_FAKE_HANDLE;\n}\n\nvoid MCP_Close(MCPHANDLE mcpHandle)\n{\n\t// placeholder\n}\n\nvoid coreinitExport_MCP_Open(PPCInterpreter_t* hCPU)\n{\n\t// placeholder\n\tosLib_returnFromFunction(hCPU, MCP_Open());\n}\n\nvoid coreinitExport_MCP_Close(PPCInterpreter_t* hCPU)\n{\n\t// placeholder\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nsint32 MCP_GetSysProdSettings(MCPHANDLE mcpHandle, SysProdSettings* sysProdSettings)\n{\n\tmemset(sysProdSettings, 0x00, sizeof(SysProdSettings));\n\t// todo: Other fields are currently unknown\n\n\tsysProdSettings->gameRegion = (uint8)CafeSystem::GetForegroundTitleRegion();\n\tsysProdSettings->platformRegion = (uint8)CafeSystem::GetPlatformRegion();\n\n\t// contains Wii U serial parts at +0x1A and +0x22?\n\treturn 0;\n}\n\nvoid coreinitExport_MCP_GetSysProdSettings(PPCInterpreter_t* hCPU)\n{\n\tsint32 result = MCP_GetSysProdSettings(hCPU->gpr[3], (SysProdSettings*)memory_getPointerFromVirtualOffset(hCPU->gpr[4]));\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid coreinitExport_MCP_TitleListByAppType(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"MCP_TitleListByAppType(0x{:08x},0x{:08x},0x{:08x},0x{:08x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7]);\n\n\tppcDefineParamU32(mcpHandle, 0);\n\tppcDefineParamU32(appType, 1);\n\tppcDefineParamU32BEPtr(countOutput, 2);\n\tppcDefineParamStructPtr(titleList, MCPTitleInfo, 3);\n\tppcDefineParamU32(titleListSize, 4);\n\n\tsint32 maxCount = titleListSize / sizeof(MCPTitleInfo);\n\n\tmcpPrepareRequest();\n\tmcpRequest->requestCode = IOSU_MCP_GET_TITLE_LIST_BY_APP_TYPE;\n\tmcpRequest->titleListRequest.titleCount = maxCount;\n\tmcpRequest->titleListRequest.titleList = titleList;\n\tmcpRequest->titleListRequest.titleListBufferSize = sizeof(MCPTitleInfo) * 1;\n\tmcpRequest->titleListRequest.appType = appType;\n\t__depr__IOS_Ioctlv(IOS_DEVICE_MCP, IOSU_MCP_REQUEST_CEMU, 1, 1, mcpBufferVector);\n\n\t*countOutput = mcpRequest->titleListRequest.titleCount;\n\t\t\t\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid coreinitExport_MCP_TitleList(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(mcpHandle, 0);\n\tppcDefineParamU32BEPtr(countOutput, 1);\n\tppcDefineParamStructPtr(titleList, MCPTitleInfo, 2);\n\tppcDefineParamU32(titleListBufferSize, 3);\n\n\t// todo -> Other parameters?\n\n\tmcpPrepareRequest();\n\tmcpRequest->requestCode = IOSU_MCP_GET_TITLE_LIST;\n\tmcpRequest->titleListRequest.titleCount = *countOutput;\n\tmcpRequest->titleListRequest.titleList = titleList;\n\tmcpRequest->titleListRequest.titleListBufferSize = titleListBufferSize;\n\t__depr__IOS_Ioctlv(IOS_DEVICE_MCP, IOSU_MCP_REQUEST_CEMU, 1, 1, mcpBufferVector);\n\n\t*countOutput = mcpRequest->titleListRequest.titleCount;\n\n\tcemuLog_logDebug(LogType::Force, \"MCP_TitleList(...) returned {} titles\", (uint32)mcpRequest->titleListRequest.titleCount);\n\n\tosLib_returnFromFunction(hCPU, mcpRequest->returnCode);\n}\n\nvoid coreinitExport_MCP_TitleCount(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"MCP_TitleCount(): Untested\");\n\tppcDefineParamU32(mcpHandle, 0);\n\n\tmcpPrepareRequest();\n\tmcpRequest->requestCode = IOSU_MCP_GET_TITLE_COUNT;\n\tmcpRequest->titleListRequest.titleCount = 0;\n\t__depr__IOS_Ioctlv(IOS_DEVICE_MCP, IOSU_MCP_REQUEST_CEMU, 1, 1, mcpBufferVector);\n\n\tosLib_returnFromFunction(hCPU, mcpRequest->titleListRequest.titleCount);\n}\n\nvoid coreinitExport_MCP_GetTitleInfo(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(mcpHandle, 0);\n\tppcDefineParamU64(titleId, 2);\n\tppcDefineParamStructPtr(titleList, MCPTitleInfo, 4);\n\n\tcemuLog_logDebug(LogType::Force, \"MCP_GetTitleInfo() called\");\n\n\tmcpPrepareRequest();\n\tmcpRequest->requestCode = IOSU_MCP_GET_TITLE_INFO;\n\tmcpRequest->titleListRequest.titleCount = 1;\n\tmcpRequest->titleListRequest.titleList = titleList;\n\tmcpRequest->titleListRequest.titleListBufferSize = sizeof(MCPTitleInfo);\n\tmcpRequest->titleListRequest.titleId = titleId;\n\t__depr__IOS_Ioctlv(IOS_DEVICE_MCP, IOSU_MCP_REQUEST_CEMU, 1, 1, mcpBufferVector);\n\n\tif (mcpRequest->titleListRequest.titleCount == 0)\n\t{\n\t\tcemuLog_log(LogType::Force, \"MCP_GetTitleInfo() failed to get title info\");\n\t}\n\n\tosLib_returnFromFunction(hCPU, mcpRequest->returnCode);\n\n}\n\nvoid coreinitExport_MCP_GetTitleInfoByTitleAndDevice(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(mcpHandle, 0);\n\tppcDefineParamU64(titleId, 2);\n\tppcDefineParamStr(device, 4); // e.g. \"odd\"\n\tppcDefineParamStructPtr(titleList, MCPTitleInfo, 5);\n\n\tcemuLog_logDebug(LogType::Force, \"MCP_GetTitleInfoByTitleAndDevice() called (todo - device type support)\");\n\n\tmcpPrepareRequest();\n\tmcpRequest->requestCode = IOSU_MCP_GET_TITLE_INFO;\n\tmcpRequest->titleListRequest.titleCount = 1;\n\tmcpRequest->titleListRequest.titleList = titleList;\n\tmcpRequest->titleListRequest.titleListBufferSize = sizeof(MCPTitleInfo);\n\tmcpRequest->titleListRequest.titleId = titleId;\n\t__depr__IOS_Ioctlv(IOS_DEVICE_MCP, IOSU_MCP_REQUEST_CEMU, 1, 1, mcpBufferVector);\n\n\tif (mcpRequest->titleListRequest.titleCount == 0)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"MCP_GetTitleInfoByTitleAndDevice() no title found\");\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_MCP, 0)); // E-Shop/nn_vctl.rpl expects error to be returned when no title is found\n\t\treturn;\n\t}\n\n\tosLib_returnFromFunction(hCPU, mcpRequest->returnCode);\n}\n\nnamespace coreinit\n{\n\n\tvoid export_MCP_GetSystemVersion(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"MCP_GetSystemVersion({},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\tppcDefineParamU32(mcpHandle, 0);\n\t\tppcDefineParamStructPtr(systemVersion, mcpSystemVersion_t, 1);\n\n\t\tsystemVersion->n0 = 0x5;\n\t\tsystemVersion->n1 = 0x5;\n\t\tsystemVersion->n2 = 0x5;\n\t\t// todo: Load this from \\sys\\title\\00050010\\10041200\\content\\version.bin\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_MCP_Get4SecondOffStatus(PPCInterpreter_t* hCPU)\n\t{\n\t\t// r3 = mcpHandle\n\t\tcemuLog_logDebug(LogType::Force, \"MCP_Get4SecondOffStatus(...) placeholder\");\n\t\t// if this returns 1 then Barista will display the warning about cold-shutdown ('Holding the POWER button for at least four seconds...')\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_MCP_TitleListByDevice(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(mcpHandle, 0);\n\t\tppcDefineParamStr(deviceName, 1);\n\t\tppcDefineParamU32BEPtr(titleCount, 2);\n\t\tppcDefineParamStructPtr(titleList, MCPTitleInfo, 3); // type guessed\n\t\t// purpose of r7 parameter is unknown\n\n\t\tcemu_assert_unimplemented();\n\n\t\ttitleList[0].titleIdHigh = 0x00050000;\n\t\ttitleList[0].titleIdLow = 0x11223344;\n\t\tstrcpy(titleList[0].appPath, \"titlePathTest\");\n\n\t\t*titleCount = 1;\n\n\t\tcemuLog_logDebug(LogType::Force, \"MCP_TitleListByDevice() - placeholder\");\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n#pragma pack(1)\n\tstruct MCPDevice_t\n\t{\n\t\t/* +0x000 */ char storageName[0x8]; // the name in the storage path (mlc, slc, usb?) // volumeId at +8\n\t\t/* +0x008 */ char volumeId[16]; //\n\t\t/* +0x018 */ char ukn[0x90 - 0x18];\n\t\t/* +0x090 */ char storagePath[0x280 - 1]; // /vol/storage_%s%02x\n\t\t/* +0x30F */ uint32be flags; // men.rpx checks for 0x2 and 0x8\n\t\tuint8 ukn313[4];\n\t\tuint8 ukn317[4];\n\t};\n#pragma pack()\n\n\tstatic_assert(sizeof(MCPDevice_t) == 0x31B);\n\n\tstatic_assert(sizeof(MCPDevice_t) == 0x31B);\n\tstatic_assert(offsetof(MCPDevice_t, storagePath) == 0x90);\n\tstatic_assert(offsetof(MCPDevice_t, flags) == 0x30F);\n\tstatic_assert(offsetof(MCPDevice_t, ukn313) == 0x313);\n\tstatic_assert(offsetof(MCPDevice_t, ukn317) == 0x317);\n\n\tvoid MCP_DeviceListEx(uint32 mcpHandle, uint32be* deviceCount, MCPDevice_t* deviceList, uint32 deviceListSize, bool returnFullList)\n\t{\n\t\tsint32 maxDeviceCount = deviceListSize / sizeof(MCPDevice_t);\n\n\t\tcemu_assert(maxDeviceCount >= 2);\n\n\t\tmemset(deviceList, 0, deviceListSize);\n\t\tsint32 index = 0;\n\n\t\tuint32 flags = 2 | 8;\n\t\t// flag 2 is necessary for Wii U menu and Friend List to load\n\t\t// if we dont set flag 0x8 then Wii U menu will show a disk loading icon and screen\n\t\t// slc\n\t\tstrcpy(deviceList[index].storageName, \"slc\");\n\t\tstrcpy(deviceList[index].volumeId, \"VOLID_SLC\");\n\t\tdeviceList[index].flags = flags;\n\t\tstrcpy(deviceList[index].storagePath, \"/vol/system_slc\"); // unsure\n\t\tindex++;\n\t\t// mlc\n\t\tstrcpy(deviceList[index].storageName, \"mlc\");\n\t\tstrcpy(deviceList[index].volumeId, \"VOLID_MLC\");\n\t\tdeviceList[index].flags = flags;\n\t\tsprintf(deviceList[index].storagePath, \"/vol/storage_mlc01\");\n\t\tindex++;\n\n\t\t// we currently dont emulate USB storage\n\n\t\t*deviceCount = index;\n\t}\n\n\tvoid export_MCP_DeviceList(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(mcpHandle, 0);\n\t\tppcDefineParamU32BEPtr(deviceCount, 1);\n\t\tppcDefineParamStructPtr(deviceList, MCPDevice_t, 2);\n\t\tppcDefineParamU32(deviceListSize, 3);\n\n\t\tcemuLog_logDebug(LogType::Force, \"MCP_DeviceList()\");\n\n\t\tsint32 maxDeviceCount = deviceListSize / sizeof(MCPDevice_t);\n\n\t\tif (maxDeviceCount < 2)\n\t\t\tassert_dbg();\n\n\t\t// if this doesnt return both MLC and SLC friendlist (frd.rpx) will softlock during boot\n\n\t\tmemset(deviceList, 0, sizeof(MCPDevice_t) * 1);\n\t\t// 0\n\t\tstrcpy(deviceList[0].storageName, \"mlc\");\n\t\tdeviceList[0].flags = (0x01); // bitmask?\n\t\tsprintf(deviceList[0].storagePath, \"/vol/storage_%s%02x\", deviceList[0].storageName, (sint32)deviceList[0].flags);\n\t\t// 1\n\t\tstrcpy(deviceList[1].storageName, \"slc\");\n\t\tdeviceList[1].flags = (0x01); // bitmask?\n\t\tsprintf(deviceList[1].storagePath, \"/vol/storage_%s%02x\", deviceList[1].storageName, (sint32)deviceList[1].flags);\n\n\t\t// 2\n\t\t//strcpy(deviceList[2].storageName, \"usb\");\n\t\t//deviceList[2].storageSubindex = 1;\n\t\t//sprintf(deviceList[2].storagePath, \"/vol/storage_%s%02x\", deviceList[2].storageName, (sint32)deviceList[2].storageSubindex);\n\n\n\t\t*deviceCount = 2;\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_MCP_FullDeviceList(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(mcpHandle, 0);\n\t\tppcDefineParamU32BEPtr(deviceCount, 1);\n\t\tppcDefineParamStructPtr(deviceList, MCPDevice_t, 2);\n\t\tppcDefineParamU32(deviceListSize, 3);\n\n\t\tcemuLog_logDebug(LogType::Force, \"MCP_FullDeviceList()\");\n\n\t\tMCP_DeviceListEx(mcpHandle, deviceCount, deviceList, deviceListSize, true);\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_MCP_UpdateCheckContext(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(mcpHandle, 0);\n\t\tppcDefineParamU32BEPtr(unknownParam, 1);\n\n\t\tcemuLog_logDebug(LogType::Force, \"MCP_UpdateCheckContext() - placeholder (might be wrong)\");\n\n\t\t*unknownParam = 1;\n\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_MCP_TitleListUpdateGetNext(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(mcpHandle, 0);\n\t\tppcDefineParamMPTR(callbackMPTR, 1);\n\n\t\tcemuLog_logDebug(LogType::Force, \"MCP_TitleListUpdateGetNext() - placeholder/unimplemented\");\n\n\t\t// this callback is to let the app know when the title list changed?\n\n\t\t//PPCCoreCallback(callbackMPTR); // -> If we trigger the callback then the menu will repeat with a call to MCP_GetTitleList(), MCP_DeviceList() and MCP_TitleListUpdateGetNext\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_MCP_GetOverlayAppInfo(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"MCP_GetOverlayAppInfo(...) placeholder\");\n\t\tppcDefineParamU32(mcpHandle, 0);\n\t\tppcDefineParamU32(appType, 1);\n\t\tppcDefineParamU32(uknR5, 2);\n\t\tppcDefineParamStructPtr(titleList, MCPTitleInfo, 3);\n\n\t\t// hacky\n\n\t\tmcpPrepareRequest();\n\t\tmcpRequest->requestCode = IOSU_MCP_GET_TITLE_LIST_BY_APP_TYPE;\n\t\tmcpRequest->titleListRequest.titleCount = 1;\n\t\tmcpRequest->titleListRequest.titleList = titleList;\n\t\tmcpRequest->titleListRequest.titleListBufferSize = sizeof(MCPTitleInfo)*1;\n\t\tmcpRequest->titleListRequest.appType = appType;\n\t\t__depr__IOS_Ioctlv(IOS_DEVICE_MCP, IOSU_MCP_REQUEST_CEMU, 1, 1, mcpBufferVector);\n\n\t\tif (mcpRequest->titleListRequest.titleCount != 1)\n\t\t\tassert_dbg();\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tuint32 MCP_UpdateClearContextAsync(uint32 mcpHandle, betype<MPTR>* callbackPtr)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"MCP_UpdateClearContextAsync() - stubbed\");\n\t\tuint32 clearContextResult = 0;\n\t\tPPCCoreCallback(*callbackPtr, clearContextResult);\n\t\treturn 0;\n\t}\n\n\tuint32 MCP_InstallUtilGetTitleEnability(uint32 mcpHandle, uint32be* enabilityOutput, MCPTitleInfo* title)\n\t{\n\t\t*enabilityOutput = 1;\n\t\treturn 0;\n\t}\n\n\tuint32 MCP_GetEcoSettings(uint32 mcpHandle, uint32be* flagCaffeineEnable, uint32be* uknFlag2, uint32be* uknFlag3)\n\t{\n\t\t*flagCaffeineEnable = 1; // returning 1 here will stop the Wii U Menu from showing the Quick Start setup dialogue\n\t\t*uknFlag2 = 0;\n\t\t*uknFlag3 = 0;\n\t\treturn 0;\n\t}\n\n\tuint32 MCP_RightCheckLaunchable(uint32 mcpHandle, uint64 titleId, uint32be* launchableOut)\n\t{\n\t\t*launchableOut = 1;\n\t\treturn 0;\n\t}\n\n\tuint32 MCP_GetTitleId(uint32 mcpHandle, uint64be* outTitleId)\n\t{\n\t\t*outTitleId = CafeSystem::GetForegroundTitleId();\n\t\treturn 0;\n\t}\n\n\tvoid InitializeMCP()\n\t{\n\t\tosLib_addFunction(\"coreinit\", \"MCP_Open\", coreinitExport_MCP_Open);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_Close\", coreinitExport_MCP_Close);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_GetSysProdSettings\", coreinitExport_MCP_GetSysProdSettings);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_TitleListByAppType\", coreinitExport_MCP_TitleListByAppType);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_TitleList\", coreinitExport_MCP_TitleList);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_TitleCount\", coreinitExport_MCP_TitleCount);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_GetTitleInfo\", coreinitExport_MCP_GetTitleInfo);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_GetTitleInfoByTitleAndDevice\", coreinitExport_MCP_GetTitleInfoByTitleAndDevice);\n\n\t\tosLib_addFunction(\"coreinit\", \"MCP_TitleListByDevice\", export_MCP_TitleListByDevice);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_GetSystemVersion\", export_MCP_GetSystemVersion);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_Get4SecondOffStatus\", export_MCP_Get4SecondOffStatus);\n\n\t\tosLib_addFunction(\"coreinit\", \"MCP_DeviceList\", export_MCP_DeviceList);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_FullDeviceList\", export_MCP_FullDeviceList);\n\n\t\tosLib_addFunction(\"coreinit\", \"MCP_UpdateCheckContext\", export_MCP_UpdateCheckContext);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_TitleListUpdateGetNext\", export_MCP_TitleListUpdateGetNext);\n\t\tosLib_addFunction(\"coreinit\", \"MCP_GetOverlayAppInfo\", export_MCP_GetOverlayAppInfo);\n\t\tcafeExportRegister(\"coreinit\", MCP_UpdateClearContextAsync, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", MCP_InstallUtilGetTitleEnability, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", MCP_RightCheckLaunchable, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", MCP_GetEcoSettings, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", MCP_GetTitleId, LogType::Placeholder);\n\t}\n\n}\n\ntypedef struct  \n{\n\tchar settingName[0x40];\n\tuint32 ukn1;\n\tuint32 ukn2;\n\tuint32 ukn3;\n\tuint32 ukn4_size; // size guessed\n\tMPTR resultPtr; // pointer to output value\n}UCParamStruct_t;\n\nstatic_assert(sizeof(UCParamStruct_t) == 0x54); // unsure\n\n#if BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_BSD\n#define _strcmpi strcasecmp\n#endif\n\nvoid coreinitExport_UCReadSysConfig(PPCInterpreter_t* hCPU)\n{\n\t// parameters:\n\t// r3 = UC handle?\n\t// r4 = Number of values to read (count of UCParamStruct_t entries)\n\t// r5 = UCParamStruct_t*\n\tUCParamStruct_t* ucParamBase = (UCParamStruct_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[5]);\n\tuint32 ucParamCount = hCPU->gpr[4];\n\tfor(uint32 i=0; i<ucParamCount; i++)\n\t{\n\t\tUCParamStruct_t* ucParam = ucParamBase+i;\n\t\tif(_strcmpi(ucParam->settingName, \"cafe.cntry_reg\") == 0)\n\t\t{\n\t\t\t// country code\n\t\t\t// get country from simple address\n\t\t\tuint32be simpleAddress = 0;\n\t\t\tnn::act::GetSimpleAddressIdEx(&simpleAddress, nn::act::ACT_SLOT_CURRENT);\n\n\t\t\tuint32 countryCode = nn::act::getCountryCodeFromSimpleAddress(simpleAddress);\n\n\t\t\tif( ucParam->resultPtr != _swapEndianU32(MPTR_NULL) )\n\t\t\t\tmemory_writeU32(_swapEndianU32(ucParam->resultPtr), countryCode);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"cafe.language\") == 0)\n\t\t{\n\t\t\t// language\n\t\t\t// 0 -> Japanese\n\t\t\t// 1 -> English\n\t\t\t// ...\n\t\t\tuint32 languageId = (uint32)GetConfig().console_language.GetValue();\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU32(_swapEndianU32(ucParam->resultPtr), languageId);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"cafe.initial_launch\") == 0)\n\t\t{\n\t\t\t// initial launch\n\t\t\t// possible ids:\n\t\t\t// 0xFF\t\tSet by SCIFormatSystem (default?)\n\t\t\t// 0x01\t\tInited but no user created yet (setting this will make the home menu go into user creation dialog)\n\t\t\t// 0x02\t\tInited, with user\n\t\t\t// other values are unknown\n\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 2);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"cafe.eula_version\") == 0)\n\t\t{\n\t\t\t// todo - investigate values\n\t\t\tmemory_writeU32(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"cafe.eula_agree\") == 0)\n\t\t{\n\t\t\t// todo - investigate values\n\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"cafe.version\") == 0)\n\t\t{\n\t\t\t// todo - investigate values\n\t\t\tmemory_writeU16(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"cafe.eco\") == 0)\n\t\t{\n\t\t\t// todo - investigate values\n\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"cafe.fast_boot\") == 0)\n\t\t{\n\t\t\t// todo - investigate values\n\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"parent.enable\") == 0)\n\t\t{\n\t\t\t// parental feature enabled\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU32(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"nn.act.account_repaired\") == 0)\n\t\t{\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"p_acct1.net_communication_on_game\") == 0)\n\t\t{\n\t\t\t// get parental online control for online features\n\t\t\t// note: This option is account-bound, the p_acct1 prefix indicates that the account in slot 1 is used\n\t\t\t// a non-zero value means network access is restricted through parental access. 0 means allowed\n\t\t\t// account in slot 1\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0); // data type is guessed\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"p_acct1.int_movie\") == 0)\n\t\t{\n\t\t\t// get parental online control for movies?\n\t\t\t// used by Pikmin HD movies\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0); // 0 -> allowed\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"p_acct1.network_launcher\") == 0)\n\t\t{\n\t\t\t// miiverse restrictions\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0); // data type is guessed (0 -> no restrictions, 1 -> read only, 2 -> no access)\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"s_acct01.uuid\") == 0)\n\t\t{\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL) && ucParam->ukn4_size >= 37)\n\t\t\t{\n\t\t\t\tStackAllocator<uint8, 16> _uuid;\n\t\t\t\tuint8* uuid = _uuid.GetPointer();\n\t\t\t\tnn::act::GetUuidEx(uuid, 1, 0);\n\t\t\t\tchar tempStr[64];\n\t\t\t\tsprintf(tempStr, \"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X\", uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7],\n\t\t\t\t\tuuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);\n\t\t\t\tstrcpy((char*)memory_getPointerFromVirtualOffset(_swapEndianU32(ucParam->resultPtr)), tempStr);\n\t\t\t}\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"s_acct01.nn.ec.eshop_initialized\") == 0)\n\t\t{\n\t\t\t// E-Shop welcome screen\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 1); // data type is guessed\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"p_acct1.int_browser\") == 0)\n\t\t{\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\t/* caffeine settings (Quick Start) */\n\t\telse if (_strcmpi(ucParam->settingName, \"caffeine.enable\") == 0)\n\t\t{\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 1);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"caffeine.ad_enable\") == 0)\n\t\t{\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"caffeine.push_enable\") == 0)\n\t\t{\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\telse if (_strcmpi(ucParam->settingName, \"caffeine.drcled_enable\") == 0)\n\t\t{\n\t\t\tif (ucParam->resultPtr != _swapEndianU32(MPTR_NULL))\n\t\t\t\tmemory_writeU8(_swapEndianU32(ucParam->resultPtr), 0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported SCI value: {} Size {:08x}\", ucParam->settingName, ucParam->ukn4_size);\n\t\t}\n\t}\n\tosLib_returnFromFunction(hCPU, 0); // 0 -> success\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MCP.h",
    "content": "#pragma once\n\nstruct SysProdSettings\n{\n\tuint8 ukn00;\t\t\t// 0x00\n\tuint8 ukn01;\t\t\t// 0x01\n\tuint8 ukn02;\t\t\t// 0x02\n\tuint8 platformRegion;\t// 0x03\n\tuint8 ukn04;\n\tuint8 ukn05;\n\tuint8 ukn06;\n\tuint8 ukn07;\n\tuint8 prevBlock;\n\tuint8 ukn09;\n\tuint8 ukn0A;\n\tuint8 gameRegion;\t\t// game region?\n\tuint8 nextBlock;\n\tuint8 ukn0D;\n\tuint8 ukn0E;\n\tuint8 ukn0F;\n\tuint8 ukn10;\n\tuint8 ukn11;\n\tuint8 ukn12;\n\tuint8 ukn13;\n\tuint8 ukn14[4];\n\tuint8 ukn18[4];\n\tuint8 ukn1C[4];\n\tuint8 ukn20[4];\n\tuint8 ukn24[4];\n\tuint8 ukn28[4];\n\tuint8 ukn2C[4];\n\tuint8 ukn30[4];\n\tuint8 ukn34[4];\n\tuint8 ukn38[4];\n\tuint8 ukn3C[4];\n\tuint8 ukn40[4];\n\tuint8 ukn44;\n\tuint8 ukn45;\n};\n\nstatic_assert(sizeof(SysProdSettings) == 0x46);\n\ntypedef uint32 MCPHANDLE;\n\nMCPHANDLE MCP_Open();\nvoid MCP_Close(MCPHANDLE mcpHandle);\nsint32 MCP_GetSysProdSettings(MCPHANDLE mcpHandle, SysProdSettings* sysProdSettings);\n\nvoid coreinitExport_UCReadSysConfig(PPCInterpreter_t* hCPU);\n\nnamespace coreinit\n{\n\tvoid InitializeMCP();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MEM.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_FG.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Memory.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_FrmHeap.h\"\n#include \"coreinit_DynLoad.h\"\n\n// the system area is a block of memory that exists only in the emulator. It is used to simplify dynamic memory allocation for system data\n// this partially overlaps with the system heap from coreinit_SysHeap.cpp -> Use SysHeap for everything\nMPTR sysAreaAllocatorOffset = 0;\n\nMPTR coreinit_allocFromSysArea(uint32 size, uint32 alignment)\n{\n\tcemu_assert_debug(mmuRange_CEMU_AREA.isMapped());\n\t// deprecated, use OSAllocFromSystem instead (for everything but SysAllocator which probably should use its own allocator?)\n\tstatic std::mutex s_allocator_mutex;\n\ts_allocator_mutex.lock();\n\tsysAreaAllocatorOffset = (sysAreaAllocatorOffset+alignment-1);\n\tsysAreaAllocatorOffset -= (sysAreaAllocatorOffset%alignment);\n\tuint32 newMemOffset =  mmuRange_CEMU_AREA.getBase() + sysAreaAllocatorOffset;\n\tsysAreaAllocatorOffset += (size+3)&~3;\n\tif( sysAreaAllocatorOffset >= mmuRange_CEMU_AREA.getSize() )\n\t{\n\t\tcemuLog_log(LogType::Force, \"Ran out of system memory\");\n\t\tcemu_assert(false); // out of bounds\n\t}\n\ts_allocator_mutex.unlock();\n\treturn newMemOffset;\n}\n\nvoid coreinit_freeToSysArea(MPTR mem)\n{\n\t// todo\n}\n\nnamespace coreinit\n{\n#define MEM_MAX_HEAP_TABLE (0x20)\n\n\tsint32 g_heapTableCount = 0;\n\tMEMHeapBase* g_heapTable[MEM_MAX_HEAP_TABLE] = {};\n\n\tbool g_slockInitialized = false;\n\tbool g_listsInitialized = false;\n\n\tMEMList g_list1;\n\tMEMList g_list2;\n\tMEMList g_list3;\n\n\tstd::array<uint32, 3> gHeapFillValues{ 0xC3C3C3C3, 0xF3F3F3F3, 0xD3D3D3D3 };\n\tSysAllocator<OSSpinLock> gHeapGlobalLock;\n\tMEMHeapBase* gDefaultHeap;\n\n\tbool MEMHeapTable_Add(MEMHeapBase* heap)\n\t{\n\t\tif (g_heapTableCount >= MEM_MAX_HEAP_TABLE)\n\t\t\treturn false;\n\t\tg_heapTable[g_heapTableCount] = heap;\n\t\tg_heapTableCount++;\n\t\treturn true;\n\t}\n\n\tbool MEMHeapTable_Remove(MEMHeapBase* heap)\n\t{\n\t\tif (g_heapTableCount == 0)\n\t\t\treturn false;\n\n\t\tif (g_heapTableCount > MEM_MAX_HEAP_TABLE)\n\t\t\treturn false;\n\n\t\tfor (sint32 i = 0; i < g_heapTableCount; ++i)\n\t\t{\n\t\t\tif (g_heapTable[i] == heap)\n\t\t\t{\n\t\t\t\tg_heapTable[i] = nullptr;\n\t\t\t\tg_heapTableCount--;\n\n\t\t\t\tif (g_heapTableCount == 0)\n\t\t\t\t\treturn true;\n\n\t\t\t\tif (i >= g_heapTableCount)\n\t\t\t\t\treturn true;\n\n\t\t\t\tcemu_assert_debug(i < MEM_MAX_HEAP_TABLE);\n\t\t\t\tfor (; i < g_heapTableCount; ++i)\n\t\t\t\t{\n\t\t\t\t\tg_heapTable[i] = g_heapTable[i + 1];\n\t\t\t\t}\n\n\t\t\t\tcemu_assert_debug(i < MEM_MAX_HEAP_TABLE);\n\t\t\t\tg_heapTable[i] = nullptr;\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tMEMHeapBase* _MEMList_FindContainingHeap(MEMList* list, MEMHeapBase* heap)\n\t{\n\t\tfor (MEMHeapBase* obj = (MEMHeapBase*)MEMGetFirstListObject(list); obj; obj = (MEMHeapBase*)MEMGetNextListObject(list, obj))\n\t\t{\n\t\t\tif (obj->heapStart.GetPtr() <= heap && heap < obj->heapEnd.GetPtr())\n\t\t\t{\n\t\t\t\tconst MEMHeapHandle containHeap = _MEMList_FindContainingHeap(&obj->childList, heap);\n\t\t\t\treturn containHeap ? containHeap : obj;\n\t\t\t}\n\t\t}\n\n\t\treturn nullptr;\n\t}\n\n\tbool MEMList_ContainsHeap(MEMList* list, MEMHeapBase* heap)\n\t{\n\t\tfor (MEMHeapBase* obj = (MEMHeapBase*)MEMGetFirstListObject(list); obj; obj = (MEMHeapBase*)MEMGetNextListObject(list, obj))\n\t\t{\n\t\t\tif (obj == heap)\n\t\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tMEMList* MEMList_FindContainingHeap(MEMHeapBase* head)\n\t{\n\t\tMEMPTR<void> memBound;\n\t\tuint32be memBoundSize;\n\t\tOSGetMemBound(1, &memBound, &memBoundSize);\n\n\t\tMEMPTR<void> bucket;\n\t\tuint32be bucketSize;\n\t\tcoreinit::OSGetForegroundBucket(&bucket, &bucketSize);\n\n\t\tif ((uintptr_t)memBound.GetPtr() > (uintptr_t)head || (uintptr_t)head >= (uintptr_t)memBound.GetPtr() + (uint32)memBoundSize)\n\t\t{\n\t\t\tif ((uintptr_t)bucket.GetPtr() > (uintptr_t)head || (uintptr_t)head >= (uintptr_t)bucket.GetPtr() + (uint32)bucketSize)\n\t\t\t{\n\t\t\t\tMEMHeapBase* containHeap = _MEMList_FindContainingHeap(&g_list1, head);\n\t\t\t\tif (containHeap)\n\t\t\t\t\treturn &containHeap->childList;\n\n\t\t\t\treturn &g_list1;\n\t\t\t}\n\n\t\t\tMEMHeapBase* containHeap = _MEMList_FindContainingHeap(&g_list3, head);\n\t\t\tif (containHeap)\n\t\t\t\treturn &containHeap->childList;\n\n\t\t\treturn &g_list3;\n\t\t}\n\n\t\tMEMHeapBase* containHeap = _MEMList_FindContainingHeap(&g_list2, head);\n\t\tif (containHeap)\n\t\t\treturn &containHeap->childList;\n\n\t\treturn &g_list2;\n\t}\n\n\tvoid MEMInitHeapBase(MEMHeapBase* heap, MEMHeapMagic magic, void* heapStart, void* heapEnd, uint32 createFlags)\n\t{\n\t\tmemset(heap, 0, sizeof(MEMHeapBase));\n\t\theap->magic = magic;\n\t\theap->heapStart = heapStart;\n\t\theap->heapEnd = heapEnd;\n\t\theap->flags = (uint8)createFlags;\n\n\t\tMEMInitList(&heap->childList, 4);\n\n\t\tif (!g_slockInitialized)\n\t\t{\n\t\t\tOSInitSpinLock(&gHeapGlobalLock);\n\t\t\tg_slockInitialized = true;\n\t\t}\n\n\t\tif (!g_listsInitialized)\n\t\t{\n\t\t\tMEMInitList(&g_list1, offsetof(MEMHeapBase, link));\n\t\t\tMEMInitList(&g_list2, offsetof(MEMHeapBase, link));\n\t\t\tMEMInitList(&g_list3, offsetof(MEMHeapBase, link));\n\t\t\tg_listsInitialized = true;\n\t\t}\n\n\t\tOSInitSpinLock(&heap->spinlock);\n\n\t\tOSUninterruptibleSpinLock_Acquire(&gHeapGlobalLock);\n\n\t\tMEMList* list = MEMList_FindContainingHeap(heap);\n\t\tMEMAppendListObject(list, heap);\n\n\t\tOSUninterruptibleSpinLock_Release(&gHeapGlobalLock);\n\t}\n\n\tvoid MEMBaseDestroyHeap(MEMHeapBase* heap)\n\t{\n\t\tOSUninterruptibleSpinLock_Acquire(&gHeapGlobalLock);\n\n\t\tif (HAS_FLAG(heap->flags, MEM_HEAP_OPTION_THREADSAFE))\n\t\t\tOSUninterruptibleSpinLock_Acquire(&heap->spinlock);\n\n\t\tMEMList* containHeap = MEMList_FindContainingHeap(heap);\n\t\tcemu_assert_debug(MEMList_ContainsHeap(containHeap, heap));\n\t\tMEMRemoveListObject(containHeap, heap);\n\n\t\tif (HAS_FLAG(heap->flags, MEM_HEAP_OPTION_THREADSAFE))\n\t\t\tOSUninterruptibleSpinLock_Release(&heap->spinlock);\n\n\t\tOSUninterruptibleSpinLock_Release(&gHeapGlobalLock);\n\t}\n\n\tstd::array<MEMHeapBase*, 9> sHeapBaseHandle{};\n\n\tMEMHeapBase* MEMGetBaseHeapHandle(uint32 index)\n\t{\n\t\tif (index >= sHeapBaseHandle.size())\n\t\t\treturn nullptr;\n\t\treturn sHeapBaseHandle[index];\n\t}\n\n\tMEMHeapBase* MEMSetBaseHeapHandle(uint32 index, MEMHeapBase* heapBase)\n\t{\n\t\tif (index >= sHeapBaseHandle.size())\n\t\t\treturn nullptr;\n\t\tif (sHeapBaseHandle[index] != nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"MEMSetBaseHeapHandle(): Trying to assign heap to non-empty slot\");\n\t\t\treturn sHeapBaseHandle[index];\n\t\t}\n\t\tsHeapBaseHandle[index] = heapBase;\n\t\treturn nullptr;\n\t}\n\n\tuint32 MEMSetFillValForHeap(HEAP_FILL_TYPE type, uint32 value)\n\t{\n\t\tuint32 idx = (uint32)type;\n\t\tcemu_assert(idx < gHeapFillValues.size());\n\t\tOSUninterruptibleSpinLock_Acquire(&gHeapGlobalLock);\n\t\tconst uint32 oldValue = gHeapFillValues[idx];\n\t\tgHeapFillValues[idx] = value;\n\t\tOSUninterruptibleSpinLock_Release(&gHeapGlobalLock);\n\t\treturn oldValue;\n\t}\n\n\tuint32 MEMGetFillValForHeap(HEAP_FILL_TYPE type)\n\t{\n\t\tuint32 idx = (uint32)type;\n\t\tcemu_assert(idx < gHeapFillValues.size());\n\t\tOSUninterruptibleSpinLock_Acquire(&gHeapGlobalLock);\n\t\tconst uint32 value = gHeapFillValues[idx];\n\t\tOSUninterruptibleSpinLock_Release(&gHeapGlobalLock);\n\t\treturn value;\n\t}\n\n\tMEMHeapBase* MEMFindContainHeap(const void* memBlock)\n\t{\n\t\tMEMPTR<void> memBound;\n\t\tuint32be memBoundSize;\n\t\tOSGetMemBound(1, &memBound, &memBoundSize);\n\n\t\tMEMPTR<void> bucket;\n\t\tuint32be bucketSize;\n\t\tcoreinit::OSGetForegroundBucket(&bucket, &bucketSize);\n\n\t\tOSUninterruptibleSpinLock_Acquire(&gHeapGlobalLock);\n\n\t\tMEMHeapBase* result;\n\t\tif ((uintptr_t)memBound.GetPtr() > (uintptr_t)memBlock || (uintptr_t)memBlock >= (uintptr_t)memBound.GetPtr() + (uint32)memBoundSize)\n\t\t{\n\t\t\tif ((uintptr_t)bucket.GetPtr() > (uintptr_t)memBlock || (uintptr_t)memBlock >= (uintptr_t)bucket.GetPtr() + (uint32)bucketSize)\n\t\t\t{\n\t\t\t\tresult = _MEMList_FindContainingHeap(&g_list1, (MEMHeapBase*)memBlock);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (coreinit::OSGetForegroundBucket(nullptr, nullptr) == 0)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_unimplemented(); // foreground required\n\t\t\t\t\tresult = nullptr;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tresult = _MEMList_FindContainingHeap(&g_list3, (MEMHeapBase*)memBlock);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (coreinit::OSGetForegroundBucket(nullptr, nullptr) == 0)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();  // foreground required\n\t\t\t\tresult = nullptr;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult = _MEMList_FindContainingHeap(&g_list2, (MEMHeapBase*)memBlock);\n\t\t\t}\n\t\t}\n\n\t\tOSUninterruptibleSpinLock_Release(&gHeapGlobalLock);\n\n\t\treturn result;\n\t}\n\n\tvoid* MEMCreateUserHeapHandle(void* heapAddress, uint32 heapSize)\n\t{\n\t\tMEMInitHeapBase((MEMHeapBase*)heapAddress, MEMHeapMagic::USER_HEAP, (uint8*)heapAddress + 0x40, (uint8*)heapAddress + heapSize, 0);\n\t\treturn heapAddress;\n\t}\n\n\t/* MEM Heap list */\n\n#define GET_MEM_LINK(__obj__,__offset__) ((MEMLink*)((uintptr_t)__obj__ + (uint16)__offset__))\n\n\tvoid* MEMGetFirstListObject(MEMList* list)\n\t{\n\t\treturn MEMGetNextListObject(list, nullptr);\n\t}\n\n\tvoid MEMList_SetSingleObject(MEMList* list, void* object)\n\t{\n\t\tcemu_assert_debug(list != nullptr);\n\t\tcemu_assert_debug(object != nullptr);\n\n\t\tMEMLink* link = GET_MEM_LINK(object, list->offset);\n\t\tlink->prev = nullptr;\n\t\tlink->next = nullptr;\n\n\t\tlist->numObjects = list->numObjects + 1;\n\t\tlist->head = object;\n\t\tlist->tail = object;\n\t}\n\n\tvoid MEMInitList(MEMList* list, uint32 offset)\n\t{\n\t\tcemu_assert_debug(list != nullptr);\n\t\tcemu_assert(offset <= 0xFFFF);\n\t\tmemset(list, 0x00, sizeof(MEMLink));\n\t\tlist->offset = (uint16)offset;\n\t}\n\n\tvoid MEMAppendListObject(MEMList* list, void* object)\n\t{\n\t\tcemu_assert_debug(list != nullptr);\n\t\tcemu_assert_debug(object != nullptr);\n\n\t\tif (list->head)\n\t\t{\n\t\t\tlist->numObjects = list->numObjects + 1;\n\n\t\t\tMEMLink* link = GET_MEM_LINK(object, list->offset);\n\t\t\tlink->prev = list->tail;\n\t\t\tlink->next = nullptr;\n\n\t\t\tMEMLink* tailLink = GET_MEM_LINK(list->tail.GetPtr(), list->offset);\n\t\t\ttailLink->next = object;\n\n\t\t\tlist->tail = object;\n\t\t}\n\t\telse\n\t\t\tMEMList_SetSingleObject(list, object);\n\t}\n\n\tvoid MEMPrependListObject(MEMList* list, void* object)\n\t{\n\t\tcemu_assert_debug(list != nullptr);\n\t\tcemu_assert_debug(object != nullptr);\n\n\t\tMEMPTR<void> headObject = list->head;\n\t\tif (headObject)\n\t\t{\n\t\t\tlist->numObjects = list->numObjects + 1;\n\n\t\t\tMEMLink* link = GET_MEM_LINK(object, list->offset);\n\t\t\tlink->prev = nullptr;\n\t\t\tlink->next = headObject;\n\n\t\t\tMEMLink* headLink = GET_MEM_LINK(headObject.GetPtr(), list->offset);\n\t\t\theadLink->prev = object;\n\n\t\t\tlist->head = object;\n\t\t}\n\t\telse\n\t\t\tMEMList_SetSingleObject(list, object);\n\t}\n\n\tvoid MEMRemoveListObject(MEMList* list, void* object)\n\t{\n\t\tcemu_assert_debug(list != nullptr);\n\t\tcemu_assert_debug(object != nullptr);\n\n\t\tMEMLink* link = GET_MEM_LINK(object, list->offset);\n\n\t\tMEMPTR<void> prevObject = link->prev;\n\t\tif (prevObject)\n\t\t{\n\t\t\tMEMLink* prevLink = GET_MEM_LINK(prevObject.GetPtr(), list->offset);\n\t\t\tprevLink->next = link->next;\n\t\t}\n\t\telse\n\t\t\tlist->head = link->next;\n\n\t\tMEMPTR<void> nextObject = link->next;\n\t\tif (nextObject)\n\t\t{\n\t\t\tMEMLink* nextLink = GET_MEM_LINK(nextObject.GetPtr(), list->offset);\n\t\t\tnextLink->prev = prevObject;\n\t\t}\n\t\telse\n\t\t\tlist->tail = prevObject;\n\n\t\tlink->prev = nullptr;\n\t\tlink->next = nullptr;\n\n\t\tlist->numObjects = list->numObjects - 1;\n\t}\n\n\tvoid* MEMGetNextListObject(MEMList* list, void* object)\n\t{\n\t\tcemu_assert_debug(list != nullptr);\n\n\t\tif (!object)\n\t\t\treturn list->head.GetPtr();\n\n\t\tMEMLink* result = GET_MEM_LINK(object, list->offset);\n\t\treturn result->next.GetPtr();\n\t}\n\n\tvoid* MEMGetPrevListObject(MEMList* list, void* object)\n\t{\n\t\tcemu_assert_debug(list != nullptr);\n\n\t\tif (!object)\n\t\t\treturn list->tail.GetPtr();\n\n\t\tMEMLink* result = GET_MEM_LINK(object, list->offset);\n\t\treturn result->prev.GetPtr();\n\t}\n\n\tvoid* MEMGetNthListObject(MEMList* list, uint32 index)\n\t{\n\t\tcemu_assert_debug(list != nullptr);\n\n\t\tvoid* result = MEMGetNextListObject(list, nullptr);\n\t\tfor (uint32 i = 0; i != index; ++i)\n\t\t{\n\t\t\tresult = MEMGetNextListObject(list, result);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/* Default allocators */\n\n\tMEMHeapBase* MEMDefaultHeap_Init(void* mem, uint32 size)\n\t{\n\t\tMEMHeapBase* heap = MEMCreateExpHeapEx(mem, size, 4);\n\t\tgDefaultHeap = heap;\n\t\tcemu_assert_debug(heap);\n\t\treturn heap;\n\t}\n\n\tvoid* default_MEMAllocFromDefaultHeap(uint32 size)\n\t{\n\t\tvoid* mem = MEMAllocFromExpHeapEx(gDefaultHeap, size, 0x40);\n\t\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMAllocFromDefaultHeap(0x{:08x}) Result: 0x{:08x}\", size, memory_getVirtualOffsetFromPointer(mem));\n\t\treturn mem;\n\t}\n\n\tvoid export_default_MEMAllocFromDefaultHeap(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(size, 0);\n\t\tMEMPTR<void> mem = default_MEMAllocFromDefaultHeap(size);\n\t\tosLib_returnFromFunction(hCPU, mem.GetMPTR());\n\t}\n\n\tvoid* default_MEMAllocFromDefaultHeapEx(uint32 size, sint32 alignment)\n\t{\n\t\tvoid* mem = MEMAllocFromExpHeapEx(gDefaultHeap, size, alignment);\n\t\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMAllocFromDefaultHeap(0x{:08x},{}) Result: 0x{:08x}\", size, alignment, memory_getVirtualOffsetFromPointer(mem));\n\t\treturn mem;\n\t}\n\n\tvoid export_default_MEMAllocFromDefaultHeapEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(size, 0);\n\t\tppcDefineParamS32(alignment, 1);\n\t\tMEMPTR<void> mem = default_MEMAllocFromDefaultHeapEx(size, alignment);\n\t\tosLib_returnFromFunction(hCPU, mem.GetMPTR());\n\t}\n\n\tvoid default_MEMFreeToDefaultHeap(void* mem)\n\t{\n\t\tMEMFreeToExpHeap(gDefaultHeap, mem);\n\t}\n\n\tvoid export_default_MEMFreeToDefaultHeap(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamMEMPTR(mem, void, 0);\n\t\tdefault_MEMFreeToDefaultHeap(mem.GetPtr());\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid default_DynLoadAlloc(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamS32(size, 0);\n\t\tppcDefineParamS32(alignment, 1);\n\t\tppcDefineParamMEMPTR(memResultPtr, uint32be, 2);\n\t\tMPTR mem = PPCCoreCallback(gCoreinitData->MEMAllocFromDefaultHeapEx.GetMPTR(), size, alignment);\n\t\t*memResultPtr = mem;\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid default_DynLoadFree(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamMEMPTR(mem, void, 0);\n\t\tPPCCoreCallback(gCoreinitData->MEMFreeToDefaultHeap.GetMPTR(), mem);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid* _weak_MEMAllocFromDefaultHeapEx(uint32 size, sint32 alignment)\n\t{\n\t\tMEMPTR<void> r{ PPCCoreCallback(gCoreinitData->MEMAllocFromDefaultHeapEx.GetMPTR(), size, alignment) };\n\t\treturn r.GetPtr();\n\t}\n\n\tvoid* _weak_MEMAllocFromDefaultHeap(uint32 size)\n\t{\n\t\tMEMPTR<void> r{ PPCCoreCallback(gCoreinitData->MEMAllocFromDefaultHeap.GetMPTR(), size) };\n\t\treturn r.GetPtr();\n\t}\n\n\tvoid _weak_MEMFreeToDefaultHeap(void* ptr)\n\t{\n\t\tPPCCoreCallback(gCoreinitData->MEMFreeToDefaultHeap.GetMPTR(), ptr);\n\t}\n\n\tvoid coreinitExport_MEMAllocFromAllocator(PPCInterpreter_t* hCPU)\n\t{\n\t\tMEMAllocator* memAllocator = (MEMAllocator*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\t// redirect execution to allocator alloc callback\n\t\thCPU->instructionPointer = memAllocator->func->funcAlloc.GetMPTR();\n\t}\n\n\tvoid coreinitExport_MEMFreeToAllocator(PPCInterpreter_t* hCPU)\n\t{\n\t\tMEMAllocator* memAllocator = (MEMAllocator*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\t// redirect execution to allocator free callback\n\t\thCPU->instructionPointer = memAllocator->func->funcFree.GetMPTR();\n\t}\n\n\tvoid _DefaultHeapAllocator_Alloc(PPCInterpreter_t* hCPU)\n\t{\n\t\thCPU->gpr[3] = hCPU->gpr[4];\n\t\thCPU->instructionPointer = gCoreinitData->MEMAllocFromDefaultHeap.GetMPTR();\n\t}\n\n\tvoid _DefaultHeapAllocator_Free(PPCInterpreter_t* hCPU)\n\t{\n\t\thCPU->gpr[3] = hCPU->gpr[4];\n\t\thCPU->instructionPointer = gCoreinitData->MEMFreeToDefaultHeap.GetMPTR();\n\t}\n\n\tSysAllocator<MEMAllocatorFunc> gDefaultHeapAllocator;\n\n\tvoid coreinitExport_MEMInitAllocatorForDefaultHeap(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamStructPtr(memAllocator, MEMAllocator, 0);\n\n\t\tgDefaultHeapAllocator->funcAlloc = PPCInterpreter_makeCallableExportDepr(_DefaultHeapAllocator_Alloc);\n\t\tgDefaultHeapAllocator->funcFree = PPCInterpreter_makeCallableExportDepr(_DefaultHeapAllocator_Free);\n\n\t\tmemAllocator->func = gDefaultHeapAllocator.GetPtr();\n\t\tmemAllocator->heap = MEMPTR<void>(MEMGetBaseHeapHandle(1));\n\t\tmemAllocator->param1 = 0;\n\t\tmemAllocator->param2 = 0;\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid InitDefaultHeaps(MEMPTR<MEMHeapBase>& mem1Heap, MEMPTR<MEMHeapBase>& memFGHeap, MEMPTR<MEMHeapBase>& mem2Heap)\n\t{\n\t\tmem1Heap = nullptr;\n\t\tmemFGHeap = nullptr;\n\t\tmem2Heap = nullptr;\n\n\t\tgCoreinitData->MEMAllocFromDefaultHeap = RPLLoader_MakePPCCallable(export_default_MEMAllocFromDefaultHeap);\n\t\tgCoreinitData->MEMAllocFromDefaultHeapEx = RPLLoader_MakePPCCallable(export_default_MEMAllocFromDefaultHeapEx);\n\t\tgCoreinitData->MEMFreeToDefaultHeap = RPLLoader_MakePPCCallable(export_default_MEMFreeToDefaultHeap);\n\n\t\tif (OSGetForegroundBucket(nullptr, nullptr))\n\t\t{\n\t\t\tMEMPTR<void> memBound;\n\t\t\tuint32be memBoundSize;\n\t\t\tOSGetMemBound(1, &memBound, &memBoundSize);\n\t\t\tmem1Heap = MEMCreateFrmHeapEx(memBound.GetPtr(), (uint32)memBoundSize, 0);\n\n\t\t\tOSGetForegroundBucketFreeArea(&memBound, &memBoundSize);\n\t\t\tmemFGHeap = MEMCreateFrmHeapEx(memBound.GetPtr(), (uint32)memBoundSize, 0);\n\t\t}\n\n\t\tMEMPTR<void> memBound;\n\t\tuint32be memBoundSize;\n\t\tOSGetMemBound(2, &memBound, &memBoundSize);\n\t\tmem2Heap = MEMDefaultHeap_Init(memBound.GetPtr(), (uint32)memBoundSize);\n\n\t\t// set DynLoad allocators\n\t\tOSDynLoad_SetAllocator(RPLLoader_MakePPCCallable(default_DynLoadAlloc), RPLLoader_MakePPCCallable(default_DynLoadFree));\n\t\tOSDynLoad_SetTLSAllocator(RPLLoader_MakePPCCallable(default_DynLoadAlloc), RPLLoader_MakePPCCallable(default_DynLoadFree));\n\t}\n\n\tvoid CoreInitDefaultHeap(/* ukn */)\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n    void MEMResetToDefaultState()\n    {\n        for (auto& it : sHeapBaseHandle)\n            it = nullptr;\n\n        g_heapTableCount = 0;\n        g_slockInitialized = false;\n        g_listsInitialized = false;\n        gDefaultHeap = nullptr;\n\n        memset(&g_list1, 0, sizeof(g_list1));\n        memset(&g_list2, 0, sizeof(g_list2));\n        memset(&g_list3, 0, sizeof(g_list3));\n    }\n\n\tvoid InitializeMEM()\n\t{\n        MEMResetToDefaultState();\n\n\t\tcafeExportRegister(\"coreinit\", CoreInitDefaultHeap, LogType::CoreinitMem);\n\n\t\tosLib_addFunction(\"coreinit\", \"MEMInitAllocatorForDefaultHeap\", coreinitExport_MEMInitAllocatorForDefaultHeap);\n\t\tosLib_addFunction(\"coreinit\", \"MEMAllocFromAllocator\", coreinitExport_MEMAllocFromAllocator);\n\t\tosLib_addFunction(\"coreinit\", \"MEMFreeToAllocator\", coreinitExport_MEMFreeToAllocator);\n\n\t\tcafeExportRegister(\"coreinit\", MEMGetBaseHeapHandle, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMSetBaseHeapHandle, LogType::CoreinitMem);\n\n\t\tcafeExportRegister(\"coreinit\", MEMFindContainHeap, LogType::CoreinitMem);\n\n\t\tcafeExportRegister(\"coreinit\", MEMGetFillValForHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMSetFillValForHeap, LogType::CoreinitMem);\n\n\t\tcafeExportRegister(\"coreinit\", MEMCreateUserHeapHandle, LogType::CoreinitMem);\n\n\t\tcafeExportRegister(\"coreinit\", MEMInitList, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMPrependListObject, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMAppendListObject, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMRemoveListObject, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMGetNextListObject, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMGetNthListObject, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMGetPrevListObject, LogType::CoreinitMem);\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MEM.h",
    "content": "#pragma once\n\n#include \"Cafe/OS/libs/coreinit/coreinit_Spinlock.h\"\n\nstruct MEMLink_t\n{\n\tMPTR prevObject; \n\tMPTR nextObject;\n};\n\nstatic_assert(sizeof(MEMLink_t) == 8);\n\nstruct MEMList_t\n{\n\tMPTR headObject;\n\tMPTR tailObject;\n\tuint16 numObjects;\n\tuint16 offset;\n};\n\nstatic_assert(sizeof(MEMList_t) == 0xC);\n\nstruct MEMAllocatorFunc\n{\n\tMEMPTR<void> funcAlloc;\n\tMEMPTR<void> funcFree;\n};\n\nstatic_assert(sizeof(MEMAllocatorFunc) == 8);\n\nstruct MEMAllocator\n{\n\t/* +0x000 */ MEMPTR<MEMAllocatorFunc> func;\n\t/* +0x004 */ MEMPTR<void> heap;\n\t/* +0x00C */ uint32be param1;\n\t/* +0x010 */ uint32be param2;\n};\n\nstatic_assert(sizeof(MEMAllocator) == 0x10);\n\nMPTR coreinit_allocFromSysArea(uint32 size, uint32 alignment);\nvoid coreinit_freeToSysArea(MPTR mem);\n\n// mem exports\nvoid coreinitExport_MEMInitAllocatorForDefaultHeap(PPCInterpreter_t* hCPU);\nvoid coreinitExport_MEMGetBaseHeapHandle(PPCInterpreter_t* hCPU);\n\n/* legacy stuff above */\n\nnamespace coreinit\n{\n#define MEM_HEAP_INVALID_HANDLE (nullptr)\n#define MEM_HEAP_DEFAULT_ALIGNMENT 4\n#define MIN_ALIGNMENT 4\n#define MIN_ALIGNMENT_MINUS_ONE (MIN_ALIGNMENT-1)\n\n#define MEM_HEAP_OPTION_NONE\t\t(0)\n#define MEM_HEAP_OPTION_CLEAR\t\t(1 << 0)\n#define MEM_HEAP_OPTION_FILL\t\t(1 << 1)\n#define MEM_HEAP_OPTION_THREADSAFE\t(1 << 2)\n\n\tenum class MEMHeapMagic : uint32\n\t{\n\t\tUNIT_HEAP = 'UNTH',\n\t\tBLOCK_HEAP = 'BLKH',\n\t\tFRAME_HEAP = 'FRMH',\n\t\tEXP_HEAP = 'EXPH',\n\t\tUSER_HEAP = 'USRH',\n\t};\n\n\tstruct MEMLink\n\t{\n\t\tMEMPTR<void> prev;\n\t\tMEMPTR<void> next;\n\t};\n\tstatic_assert(sizeof(MEMLink) == 0x8);\n\n\tstruct MEMList\n\t{\n\t\t/* 0x00 */ MEMPTR<void> head;\n\t\t/* 0x04 */ MEMPTR<void> tail;\n\t\t/* 0x08 */ uint16be numObjects;\n\t\t/* 0x0A */ uint16be offset;\n\t};\n\tstatic_assert(sizeof(MEMList) == 0xC);\n\n\tvoid MEMInitList(MEMList* list, uint32 offset);\n\tvoid MEMAppendListObject(MEMList* list, void* object);\n\tvoid MEMRemoveListObject(MEMList* list, void* object);\n\n\tvoid* MEMGetFirstListObject(MEMList* list);\n\tvoid* MEMGetNextListObject(MEMList* list, void* object);\n\n\tstruct MEMHeapBase\n\t{\n\t\t/* +0x00 */ betype<MEMHeapMagic> magic;\n\t\t/* +0x04 */ MEMLink link;\n\t\t/* +0x0C */ MEMList childList;\n\t\t/* +0x18 */ MEMPTR<void> heapStart;\n\t\t/* +0x1C */ MEMPTR<void> heapEnd; // heap end + 1\n\t\t/* +0x20 */ OSSpinLock spinlock;\n\t\t/* +0x30 */ uint8 _ukn[3];\n\t\t/* +0x33 */ uint8 flags;\n\n\t\tvoid AcquireLock()\n\t\t{\n\t\t\tif (flags & MEM_HEAP_OPTION_THREADSAFE)\n\t\t\t\tOSUninterruptibleSpinLock_Acquire(&spinlock);\n\t\t}\n\n\t\tvoid ReleaseLock()\n\t\t{\n\t\t\tif (flags & MEM_HEAP_OPTION_THREADSAFE)\n\t\t\t\tOSUninterruptibleSpinLock_Release(&spinlock);\n\t\t}\n\n\t\t// if set, memset allocations to zero\n\t\tbool HasOptionClear() const\n\t\t{\n\t\t\treturn (flags & MEM_HEAP_OPTION_CLEAR) != 0;\n\t\t}\n\n\t\t// if set, memset allocations/releases to specific fill values\n\t\tbool HasOptionFill() const\n\t\t{\n\t\t\treturn (flags & MEM_HEAP_OPTION_FILL) != 0;\n\t\t}\n\t};\n\n\tstatic_assert(offsetof(MEMHeapBase, childList) == 0xC);\n\tstatic_assert(offsetof(MEMHeapBase, spinlock) == 0x20);\n\tstatic_assert(offsetof(MEMHeapBase, flags) == 0x33);\n\tstatic_assert(sizeof(MEMHeapBase) == 0x34); // heap base is actually 0x40 but bytes 0x34 to 0x40 are padding?\n\n\ttypedef MEMHeapBase* MEMHeapHandle;\n\n\t/* Heap base */\n\n\tvoid MEMInitHeapBase(MEMHeapBase* heap, MEMHeapMagic magic, void* heapStart, void* heapEnd, uint32 createFlags);\n\tvoid MEMBaseDestroyHeap(MEMHeapBase* heap);\n\n\tMEMHeapBase* MEMGetBaseHeapHandle(uint32 index);\n\tMEMHeapBase* MEMSetBaseHeapHandle(uint32 index, MEMHeapBase* heapBase);\n\n\t/* Heap list */\n\n\tbool MEMHeapTable_Add(MEMHeapBase* heap);\n\tbool MEMHeapTable_Remove(MEMHeapBase* heap);\n\tMEMHeapBase* _MEMList_FindContainingHeap(MEMList* list, MEMHeapBase* heap);\n\tbool MEMList_ContainsHeap(MEMList* list, MEMHeapBase* heap);\n\tMEMList* MEMList_FindContainingHeap(MEMHeapBase* head);\n\n\t/* Heap settings */\n\n\tenum class HEAP_FILL_TYPE : uint32\n\t{\n\t\tON_HEAP_CREATE = 0,\n\t\tON_ALLOC = 1,\n\t\tON_FREE = 2,\n\t};\n\n\tuint32 MEMGetFillValForHeap(HEAP_FILL_TYPE type);\n\tuint32 MEMSetFillValForHeap(HEAP_FILL_TYPE type, uint32 value);\n\tMEMHeapHandle MEMFindContainHeap(const void* memBlock);\n\n\t/* Heap default allocators */\n\n\tvoid InitDefaultHeaps(MEMPTR<MEMHeapBase>& mem1Heap, MEMPTR<MEMHeapBase>& memFGHeap, MEMPTR<MEMHeapBase>& mem2Heap);\n\n\tvoid* default_MEMAllocFromDefaultHeap(uint32 size);\n\tvoid* default_MEMAllocFromDefaultHeapEx(uint32 size, sint32 alignment);\n\tvoid default_MEMFreeToDefaultHeap(void* mem);\n\n\tvoid* _weak_MEMAllocFromDefaultHeapEx(uint32 size, sint32 alignment);\n\tvoid* _weak_MEMAllocFromDefaultHeap(uint32 size);\n\tvoid _weak_MEMFreeToDefaultHeap(void* ptr);\n\n\t/* Unit heap */\n\n\tvoid InitializeMEMUnitHeap();\n\n\tvoid InitializeMEM();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MEM_BlockHeap.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_BlockHeap.h\"\n\nnamespace coreinit\n{\n\tMEMHeapHandle MEMInitBlockHeap(MEMBlockHeap2_t* memStart, void* startAddr, void* endAddr, void* initTrackMem, uint32 initTrackMemSize, uint32 createFlags)\n\t{\n\t\tif (memStart == nullptr || startAddr == nullptr || endAddr == nullptr || (uintptr_t)startAddr >= (uintptr_t)endAddr)\n\t\t\treturn nullptr;\n\n\t\tif (initTrackMemSize == 0)\n\t\t\tinitTrackMem = nullptr;\n\t\telse if (initTrackMem == nullptr)\n\t\t\tinitTrackMemSize = 0;\n\t\t\n\t\tMEMInitHeapBase(memStart, MEMHeapMagic::BLOCK_HEAP, startAddr, endAddr, createFlags);\n\n\t\tmemStart->track.addrStart = startAddr;\n\t\tmemStart->track.addrEnd = (void*)((uintptr_t)endAddr - 1);\n\t\tmemStart->track.isFree = 1;\n\t\tmemStart->track.previousBlock = nullptr;\n\t\tmemStart->track.nextBlock = nullptr;\n\n\t\tmemStart->headBlock = &memStart->track;\n\t\tmemStart->tailBlock = &memStart->track;\n\t\tmemStart->nextFreeBlock = nullptr;\n\t\tmemStart->freeBlocksLeft = 0;\n\n\t\tuint8 flags = memStart->flags;\n\t\tif(HAS_FLAG(flags, MEM_HEAP_OPTION_FILL))\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\tif(initTrackMemSize != 0)\n\t\t{\n\t\t\tsint32 result = MEMAddBlockHeapTracking(MEMPTR<void>(memStart).GetMPTR(), MEMPTR<void>(initTrackMem).GetMPTR(), initTrackMemSize);\n\t\t\tif(result != 0)\n\t\t\t{\n\t\t\t\tMEMBaseDestroyHeap(memStart);\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t}\n\n\t\tMEMHeapTable_Add(memStart);\n\t\treturn memStart;\n\t}\n\n\tvoid* MEMDestroyBlockHeap(MEMHeapHandle hHeap)\n\t{\n\t\tif (!hHeap)\n\t\t\treturn nullptr;\n\t\tcemu_assert_debug(hHeap->magic == MEMHeapMagic::BLOCK_HEAP);\n\t\tMEMBaseDestroyHeap(hHeap);\n\t\tMEMHeapTable_Remove(hHeap);\n\t\tmemset(hHeap, 0x00, sizeof(MEMBlockHeap2_t));\n\t\treturn hHeap;\n\t}\n\n\tsint32 MEMGetAllocatableSizeForBlockHeapEx(MEMBlockHeap2_t* blockHeap, sint32 alignment)\n\t{\n\t\tif (!blockHeap || blockHeap->magic != MEMHeapMagic::BLOCK_HEAP)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"MEMGetAllocatableSizeForBlockHeapEx(): Not a valid block heap\");\n\t\t\treturn 0;\n\t\t}\n\t\tif (alignment < 0)\n\t\t\talignment = -alignment;\n\t\telse if (alignment == 0)\n\t\t\talignment = 4;\n\n\t\tif (HAS_FLAG(blockHeap->flags, MEM_HEAP_OPTION_THREADSAFE))\n\t\t\tOSUninterruptibleSpinLock_Acquire(&blockHeap->spinlock);\n\n\t\tMEMBlockHeapTrack2_t* track = (MEMBlockHeapTrack2_t*)blockHeap->headBlock.GetPtr();\n\t\tuint32 allocatableSize = 0;\n\t\twhile (track)\n\t\t{\n\t\t\tif (track->isFree != 0)\n\t\t\t{\n\t\t\t\tuint32 addrStart = track->addrStart.GetMPTR();\n\t\t\t\tuint32 addrEnd = track->addrEnd.GetMPTR();\n\t\t\t\tuint32 alignmentMinusOne = alignment - 1;\n\t\t\t\tuint32 alignedAddrStart = ((addrStart + alignmentMinusOne) / alignment) * alignment;\n\t\t\t\tif (alignedAddrStart <= addrEnd)\n\t\t\t\t{\n\t\t\t\t\tuint32 size = (addrEnd + 1) - alignedAddrStart;\n\t\t\t\t\tallocatableSize = std::max(allocatableSize, size);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// next\n\t\t\ttrack = (MEMBlockHeapTrack2_t*)track->nextBlock.GetPtr();\n\t\t}\n\n\t\tif (HAS_FLAG(blockHeap->flags, MEM_HEAP_OPTION_THREADSAFE))\n\t\t\tOSUninterruptibleSpinLock_Release(&blockHeap->spinlock);\n\n\t\treturn allocatableSize;\n\t}\n\n\tvoid MEMDumpBlockHeap(MPTR heap);\n\n\ttypedef struct\n\t{\n\t\t/* +0x00 */ uint32 addrStart;\n\t\t/* +0x04 */ uint32 addrEnd;\n\t\t/* +0x08 */ uint32 isFree; // if 0 -> block is used\n\t\t/* +0x0C */ MPTR previousBlock;\n\t\t/* +0x10 */ MPTR nextBlock;\n\t}MEMBlockHeapTrackDEPR;\n\n\ttypedef struct\n\t{\n\t\t/* +0x00 */ uint32 ukn00;\n\t\t/* +0x04 */ uint32 ukn04;\n\t\t/* +0x08 */ uint32 trackArray;\n\t\t/* +0x0C */ uint32 trackCount;\n\t}MEMBlockHeapGroupDEPR;\n\n\ttypedef struct\n\t{\n\t\t/* +0x000 */ betype<MEMHeapMagic> magic;\n\t\t/* +0x004 */ MEMLink_t\t\tlink;\n\t\t/* +0x00C */ MEMList_t\t\tchildList;\n\t\t/* +0x018 */ MPTR\t\t\theapStart;\n\t\t/* +0x01C */ MPTR\t\t\theapEnd;\n\t\t/* +0x020 */ coreinit::OSSpinLock\tspinlock;\n\t\t/* +0x030 */\n\t\tunion\n\t\t{\n\t\t\tuint32       val;\n\t\t\tuint32\t\tflags;\n\t\t}\n\t\tattribute;\n\t\t// start of block heap header\n\t\t/* +0x034 */ uint8\t\t\tukn034[0x50 - 0x34]; // ?\n\t\t/* +0x050 */ MEMBlockHeapTrackDEPR nullBlockTrack;\n\t\t/* +0x064 */ MPTR\t\t\theadBlock;\n\t\t/* +0x068 */ MPTR\t\t\ttailBlock;\n\t\t/* +0x06C */ MPTR\t\t\tnextFreeBlock;\n\t\t/* +0x070 */ uint32\t\t\tfreeBlocksLeft;\n\t}MEMBlockHeapDEPR;\n\n\tvoid _blockHeapDebugVerifyIfBlockIsLinked(MEMBlockHeapDEPR* blockHeapHead, MEMBlockHeapTrackDEPR* track)\n\t{\n\t\t//MEMBlockHeapTrack_t* trackItr = (MEMBlockHeapTrack_t*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(blockHeapHead->firstBlock));\n\t\t//MEMBlockHeapTrack_t* prevHistory[4];\n\t\t//while( trackItr )\n\t\t//{\n\t\t//\tif( trackItr == track )\n\t\t//\t{\n\t\t//\t\tdebug_printf(\"PrevBlock3 %08x\\n\", memory_getVirtualOffsetFromPointer(prevHistory[0]));\n\t\t//\t\tdebug_printf(\"PrevBlock2 %08x\\n\", memory_getVirtualOffsetFromPointer(prevHistory[1]));\n\t\t//\t\tdebug_printf(\"PrevBlock1 %08x\\n\", memory_getVirtualOffsetFromPointer(prevHistory[2]));\n\t\t//\t\tdebug_printf(\"PrevBlock0 %08x\\n\", memory_getVirtualOffsetFromPointer(prevHistory[3]));\n\t\t//\t\tassert_dbg();\n\t\t//\t}\n\t\t//\tprevHistory[3] = prevHistory[2];\n\t\t//\tprevHistory[2] = prevHistory[1];\n\t\t//\tprevHistory[1] = prevHistory[0];\n\t\t//\tprevHistory[0] = trackItr;\n\t\t//\t// next\n\t\t//\ttrackItr = (MEMBlockHeapTrack_t*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(trackItr->nextBlock));\n\t\t//}\n\t}\n\n\tvoid _blockHeapDebugVerifyLinkOrder(MEMBlockHeapDEPR* blockHeapHead)\n\t{\n\t\t//MEMBlockHeapTrack_t* trackItr = (MEMBlockHeapTrack_t*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(blockHeapHead->firstBlock));\n\t\t//MEMBlockHeapTrack_t* prev = NULL;\n\t\t//while( trackItr )\n\t\t//{\n\t\t//\tMPTR prevMPTR = memory_getVirtualOffsetFromPointer(prev);\n\t\t//\tif( _swapEndianU32(trackItr->previousBlock) != prevMPTR )\n\t\t//\t\tassert_dbg();\n\t\t//\t// next\n\t\t//\tprev = trackItr;\n\t\t//\ttrackItr = (MEMBlockHeapTrack_t*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(trackItr->nextBlock));\n\t\t//}\n\t}\n\n\tsint32 MEMAddBlockHeapTracking(MPTR heap, MPTR trackMem, uint32 trackMemSize)\n\t{\n\t\tMEMBlockHeapDEPR* blockHeapHead = (MEMBlockHeapDEPR*)memory_getPointerFromVirtualOffset(heap);\n\t\tif (blockHeapHead->magic != MEMHeapMagic::BLOCK_HEAP)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\t\tif (trackMem == MPTR_NULL || trackMemSize <= (sizeof(MEMBlockHeapGroupDEPR) + sizeof(MEMBlockHeapTrackDEPR)))\n\t\t{\n\t\t\treturn -4;\n\t\t}\n\t\tuint32 trackCount = (trackMemSize - sizeof(MEMBlockHeapGroupDEPR)) / sizeof(MEMBlockHeapTrackDEPR);\n\t\tMEMBlockHeapGroupDEPR* group = (MEMBlockHeapGroupDEPR*)memory_getPointerFromVirtualOffset(trackMem);\n\t\tgroup->ukn00 = _swapEndianU32(0);\n\t\tgroup->ukn04 = _swapEndianU32(0);\n\t\tgroup->trackArray = _swapEndianU32(trackMem + sizeof(MEMBlockHeapGroupDEPR));\n\t\tgroup->trackCount = _swapEndianU32(trackCount);\n\t\tMEMBlockHeapTrackDEPR* track = (MEMBlockHeapTrackDEPR*)(group + 1);\n\t\ttrack[0].previousBlock = _swapEndianU32(0);\n\t\tif (trackCount > 1)\n\t\t{\n\t\t\tfor (uint32 i = 0; i < trackCount - 1; i++)\n\t\t\t{\n\t\t\t\ttrack[i].nextBlock = _swapEndianU32(memory_getVirtualOffsetFromPointer(track + i + 1));\n\t\t\t\ttrack[i + 1].previousBlock = _swapEndianU32(0);\n\t\t\t}\n\t\t}\n\n\t\t// todo: Use spinlock from heap (and only use it if threadsafe heap flag is set)\n\t\t__OSLockScheduler();\n\t\ttrack[trackCount - 1].nextBlock = blockHeapHead->nextFreeBlock;\n\t\tblockHeapHead->nextFreeBlock = _swapEndianU32(memory_getVirtualOffsetFromPointer(track));\n\t\tblockHeapHead->freeBlocksLeft = _swapEndianU32(_swapEndianU32(blockHeapHead->freeBlocksLeft) + trackCount);\n\t\t__OSUnlockScheduler();\n\t\treturn 0;\n\t}\n\n\tuint32 MEMGetTrackingLeftInBlockHeap(MPTR heap)\n\t{\n\t\tMEMBlockHeapDEPR* blockHeapHead = (MEMBlockHeapDEPR*)memory_getPointerFromVirtualOffset(heap);\n\t\tif (blockHeapHead->magic != MEMHeapMagic::BLOCK_HEAP)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\t\treturn _swapEndianU32(blockHeapHead->freeBlocksLeft);\n\t}\n\n\tMPTR _MEMBlockHeap_GetFreeBlockTrack(MEMBlockHeapDEPR* blockHeapHead)\n\t{\n\t\tMPTR trackMPTR = _swapEndianU32(blockHeapHead->nextFreeBlock);\n\t\tMEMBlockHeapTrackDEPR* track = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(trackMPTR);\n\t\tMPTR nextFreeBlockMPTR = _swapEndianU32(track->nextBlock); // for unreserved tracks, nextBlock holds the next unreserved block\n\t\ttrack->nextBlock = _swapEndianU32(MPTR_NULL);\n\t\tblockHeapHead->nextFreeBlock = _swapEndianU32(nextFreeBlockMPTR);\n\t\tif (_swapEndianU32(blockHeapHead->freeBlocksLeft) == 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"BlockHeap: No free blocks left\");\n\t\t\tassert_dbg();\n\t\t}\n\t\tblockHeapHead->freeBlocksLeft = _swapEndianU32(_swapEndianU32(blockHeapHead->freeBlocksLeft) - 1);\n\t\treturn trackMPTR;\n\t}\n\n\t/*\n\t * Release MEMBlockHeapTrack_t struct for block heap\n\t */\n\tvoid _MEMBlockHeap_ReleaseBlockTrack(MEMBlockHeapDEPR* blockHeapHead, MPTR trackMPTR)\n\t{\n\t\tMEMBlockHeapTrackDEPR* track = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(trackMPTR);\n\t\ttrack->nextBlock = blockHeapHead->nextFreeBlock;\n\t\tblockHeapHead->nextFreeBlock = _swapEndianU32(trackMPTR);\n\t\tblockHeapHead->freeBlocksLeft = _swapEndianU32(_swapEndianU32(blockHeapHead->freeBlocksLeft) + 1);\n\t}\n\n\tsint32 _MEMBlockHeap_AllocAtBlock(MEMBlockHeapDEPR* blockHeapHead, MEMBlockHeapTrackDEPR* track, MPTR allocationAddress, uint32 size)\n\t{\n\t\tMPTR trackMPTR = memory_getVirtualOffsetFromPointer(track);\n\t\tuint32 trackEndAddr = _swapEndianU32(track->addrEnd);\n\t\tuint32 prefixBlockSize = allocationAddress - _swapEndianU32(track->addrStart);\n\t\tuint32 suffixBlockSize = (_swapEndianU32(track->addrEnd) + 1) - (allocationAddress + size);\n\t\tif (prefixBlockSize > 0 && suffixBlockSize > 0)\n\t\t{\n\t\t\t// requires two free blocks\n\t\t\tif (_swapEndianU32(blockHeapHead->freeBlocksLeft) < 2)\n\t\t\t\treturn -1;\n\t\t}\n\t\telse if (prefixBlockSize > 0 || suffixBlockSize > 0)\n\t\t{\n\t\t\t// requires one free block\n\t\t\tif (_swapEndianU32(blockHeapHead->freeBlocksLeft) < 1)\n\t\t\t\treturn -2;\n\t\t}\n\t\tMPTR currentPreviousTrack = _swapEndianU32(track->previousBlock);\n\t\t// remove used block from chain of free blocks (debug)\n\t\tif (track->isFree != _swapEndianU32(0))\n\t\t{\n\t\t\t// check if block is in list of free blocks (it shouldnt be)\n\t\t\tMEMBlockHeapTrackDEPR* trackItr = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(blockHeapHead->nextFreeBlock));\n\t\t\twhile (trackItr)\n\t\t\t{\n\t\t\t\tif (trackItr == track)\n\t\t\t\t\tassert_dbg();\n\t\t\t\t// next\n\t\t\t\ttrackItr = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(trackItr->nextBlock));\n\t\t\t}\n\t\t}\n\t\t_blockHeapDebugVerifyLinkOrder(blockHeapHead);\n\t\t// create prefix block\n\t\tif (prefixBlockSize > 0)\n\t\t{\n\t\t\tuint32 blockRangeStart = _swapEndianU32(track->addrStart);\n\t\t\tuint32 blockRangeEnd = allocationAddress - 1;\n\t\t\tMPTR prefixTrackMPTR = _MEMBlockHeap_GetFreeBlockTrack(blockHeapHead);\n\t\t\tMEMBlockHeapTrackDEPR* prefixTrack = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(prefixTrackMPTR);\n\t\t\tprefixTrack->isFree = _swapEndianU32(1);\n\t\t\tprefixTrack->addrStart = _swapEndianU32(blockRangeStart);\n\t\t\tprefixTrack->addrEnd = _swapEndianU32(blockRangeEnd);\n\t\t\t// register new firstBlock\n\t\t\tif (blockHeapHead->headBlock == _swapEndianU32(trackMPTR))\n\t\t\t\tblockHeapHead->headBlock = _swapEndianU32(prefixTrackMPTR);\n\t\t\t// update link in original previous block\n\t\t\tif (_swapEndianU32(track->previousBlock) != MPTR_NULL)\n\t\t\t{\n\t\t\t\tMEMBlockHeapTrackDEPR* tempTrack = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(_swapEndianU32(track->previousBlock));\n\t\t\t\ttempTrack->nextBlock = _swapEndianU32(prefixTrackMPTR);\n\t\t\t}\n\t\t\t// update previous/next track link\n\t\t\tprefixTrack->nextBlock = _swapEndianU32(trackMPTR);\n\t\t\tprefixTrack->previousBlock = _swapEndianU32(currentPreviousTrack);\n\t\t\t// set prefix track as current previous track\n\t\t\tcurrentPreviousTrack = prefixTrackMPTR;\n\t\t}\n\t\t// update used block\n\t\ttrack->isFree = _swapEndianU32(0);\n\t\ttrack->addrStart = _swapEndianU32(allocationAddress);\n\t\ttrack->addrEnd = _swapEndianU32(allocationAddress + size - 1);\n\t\ttrack->previousBlock = _swapEndianU32(currentPreviousTrack);\n\t\tcurrentPreviousTrack = trackMPTR;\n\t\t// create suffix block\n\t\tif (suffixBlockSize > 0)\n\t\t{\n\t\t\tuint32 blockRangeStart = allocationAddress + size;\n\t\t\tuint32 blockRangeEnd = trackEndAddr;\n\t\t\t// get suffix track\n\t\t\tMPTR suffixTrackMPTR = _MEMBlockHeap_GetFreeBlockTrack(blockHeapHead);\n\t\t\tMEMBlockHeapTrackDEPR* suffixTrack = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(suffixTrackMPTR);\n\t\t\tsuffixTrack->isFree = _swapEndianU32(1);\n\t\t\tsuffixTrack->addrStart = _swapEndianU32(blockRangeStart);\n\t\t\tsuffixTrack->addrEnd = _swapEndianU32(blockRangeEnd);\n\t\t\t// update previous/next track link\n\t\t\tsuffixTrack->previousBlock = _swapEndianU32(currentPreviousTrack);\n\t\t\tsuffixTrack->nextBlock = track->nextBlock;\n\t\t\t// update last block of heap\n\t\t\tif (_swapEndianU32(blockHeapHead->tailBlock) == trackMPTR)\n\t\t\t\tblockHeapHead->tailBlock = _swapEndianU32(suffixTrackMPTR);\n\t\t\t// update link in original next block\n\t\t\tif (_swapEndianU32(track->nextBlock) != MPTR_NULL)\n\t\t\t{\n\t\t\t\tMEMBlockHeapTrackDEPR* tempTrack = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(_swapEndianU32(track->nextBlock));\n\t\t\t\ttempTrack->previousBlock = _swapEndianU32(suffixTrackMPTR);\n\t\t\t}\n\t\t\t// update next block\n\t\t\ttrack->nextBlock = _swapEndianU32(suffixTrackMPTR);\n\t\t}\n\t\t_blockHeapDebugVerifyLinkOrder(blockHeapHead);\n\t\t// todo: Get fill value via MEMGetFillValForHeap\n\t\tmemset(memory_getPointerFromVirtualOffset(allocationAddress), 0x00, size);\n\t\treturn 0;\n\t}\n\n\tMEMBlockHeapTrackDEPR* _MEMBlockHeap_FindBlockContaining(MEMBlockHeapDEPR* blockHeapHead, MPTR memAddr)\n\t{\n\t\tMPTR heapStart = _swapEndianU32(blockHeapHead->heapStart);\n\t\tMPTR heapEnd = _swapEndianU32(blockHeapHead->heapEnd);\n\t\tif (memAddr < heapStart)\n\t\t\treturn NULL;\n\t\tif (memAddr > heapEnd)\n\t\t\treturn NULL;\n\t\tuint32 distanceToStart = memAddr - heapStart;\n\t\tuint32 distanceToEnd = heapEnd - memAddr;\n\t\t// todo: If distanceToStart < distanceToEnd -> Iterate starting from firstBlock, else iterate starting from lastBlock (and continue via track->previousBlock)\n\t\tMEMBlockHeapTrackDEPR* track = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(blockHeapHead->headBlock));\n\t\tif (track == NULL)\n\t\t\treturn NULL;\n\t\twhile (track)\n\t\t{\n\t\t\tif (_swapEndianU32(track->addrStart) == memAddr)\n\t\t\t\treturn track;\n\t\t\t// next\n\t\t\t// todo: Should this be ->previousBlock ?\n\t\t\ttrack = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(track->nextBlock));\n\t\t}\n\t\treturn NULL;\n\t}\n\n\tMPTR MEMAllocFromBlockHeapEx(MPTR heap, uint32 size, sint32 alignment)\n\t{\n\t\tMEMBlockHeapDEPR* blockHeapHead = (MEMBlockHeapDEPR*)memory_getPointerFromVirtualOffset(heap);\n\t\tif (blockHeapHead->magic != MEMHeapMagic::BLOCK_HEAP)\n\t\t{\n\t\t\treturn MPTR_NULL;\n\t\t}\n\t\t// find free block which can hold the data (including alignment)\n\t\t__OSLockScheduler(); // todo: replace with spinlock from heap\n\t\tif (alignment == 0)\n\t\t\talignment = 4;\n\t\tbool allocateAtEndOfBlock = false;\n\t\tif (alignment < 0)\n\t\t{\n\t\t\tallocateAtEndOfBlock = true;\n\t\t\talignment = -alignment;\n\t\t}\n\t\tMEMBlockHeapTrackDEPR* track;\n\t\tif (allocateAtEndOfBlock)\n\t\t\ttrack = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(blockHeapHead->tailBlock));\n\t\telse\n\t\t\ttrack = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(blockHeapHead->headBlock));\n\n\t\tcemu_assert_debug(std::popcount<unsigned int>(alignment) == 1); // not a supported alignment value\n\t\twhile (track)\n\t\t{\n\t\t\tif (track->isFree != _swapEndianU32(0))\n\t\t\t{\n\t\t\t\tuint32 blockRangeStart = _swapEndianU32(track->addrStart);\n\t\t\t\tuint32 blockRangeEnd = _swapEndianU32(track->addrEnd) + 1;\n\t\t\t\tif (allocateAtEndOfBlock == false)\n\t\t\t\t{\n\t\t\t\t\t// calculate remaining size with proper alignment\n\t\t\t\t\tuint32 alignedBlockRangeStart = (blockRangeStart + alignment - 1) & ~(alignment - 1);\n\t\t\t\t\tif (alignedBlockRangeStart < blockRangeEnd)\n\t\t\t\t\t{\n\t\t\t\t\t\tuint32 allocRange = blockRangeEnd - alignedBlockRangeStart;\n\t\t\t\t\t\tif (allocRange >= size)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsint32 allocError = _MEMBlockHeap_AllocAtBlock(blockHeapHead, track, alignedBlockRangeStart, size);\n\t\t\t\t\t\t\t_blockHeapDebugVerifyLinkOrder(blockHeapHead);\n\t\t\t\t\t\t\t__OSUnlockScheduler();\n\t\t\t\t\t\t\tif (allocError == 0)\n\t\t\t\t\t\t\t\treturn alignedBlockRangeStart;\n\t\t\t\t\t\t\treturn MPTR_NULL;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tuint32 alignedBlockRangeStart = (blockRangeEnd + 1 - size) & ~(alignment - 1);\n\t\t\t\t\tif (alignedBlockRangeStart >= blockRangeStart)\n\t\t\t\t\t{\n\t\t\t\t\t\tsint32 allocError = _MEMBlockHeap_AllocAtBlock(blockHeapHead, track, alignedBlockRangeStart, size);\n\t\t\t\t\t\t_blockHeapDebugVerifyLinkOrder(blockHeapHead);\n\t\t\t\t\t\t__OSUnlockScheduler();\n\t\t\t\t\t\tif (allocError == 0)\n\t\t\t\t\t\t\treturn alignedBlockRangeStart;\n\t\t\t\t\t\treturn MPTR_NULL;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// next\n\t\t\tif (allocateAtEndOfBlock)\n\t\t\t\ttrack = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(track->previousBlock));\n\t\t\telse\n\t\t\t\ttrack = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(track->nextBlock));\n\t\t\tif (track == nullptr)\n\t\t\t\tbreak;\n\t\t}\n\t\t__OSUnlockScheduler();\n\t\treturn MPTR_NULL;\n\t}\n\n\tvoid MEMFreeToBlockHeap(MPTR heap, MPTR memAddr)\n\t{\n\t\tMEMBlockHeapDEPR* blockHeapHead = (MEMBlockHeapDEPR*)memory_getPointerFromVirtualOffset(heap);\n\t\tif (blockHeapHead->magic != MEMHeapMagic::BLOCK_HEAP)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\t__OSLockScheduler(); // todo: replace with spinlock from heap (if heap threadsafe flag is set)\n\t\t_blockHeapDebugVerifyLinkOrder(blockHeapHead);\n\t\tMEMBlockHeapTrackDEPR* block = _MEMBlockHeap_FindBlockContaining(blockHeapHead, memAddr);\n\t\tif (block != NULL)\n\t\t{\n\t\t\tMPTR blockMPTR = memory_getVirtualOffsetFromPointer(block);\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tif (block->isFree != 0)\n\t\t\t\tassert_dbg();\n\t\t\t_blockHeapDebugVerifyLinkOrder(blockHeapHead);\n#endif\n\t\t\t// mark current block as free\n\t\t\tblock->isFree = _swapEndianU32(1);\n\t\t\t// attempt to merge with previous block\n\t\t\tif (_swapEndianU32(block->previousBlock) != MPTR_NULL)\n\t\t\t{\n\t\t\t\tMPTR previousBlockMPTR = _swapEndianU32(block->previousBlock);\n\t\t\t\tMEMBlockHeapTrackDEPR* previousBlock = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(previousBlockMPTR);\n\t\t\t\tif (_swapEndianU32(previousBlock->isFree) != 0)\n\t\t\t\t{\n\t\t\t\t\t// merge\n\t\t\t\t\tpreviousBlock->addrEnd = block->addrEnd;\n\t\t\t\t\tpreviousBlock->nextBlock = block->nextBlock;\n\t\t\t\t\tif (_swapEndianU32(block->nextBlock) != MPTR_NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\tMEMBlockHeapTrackDEPR* tempNextBlock = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(_swapEndianU32(block->nextBlock));\n\t\t\t\t\t\ttempNextBlock->previousBlock = _swapEndianU32(previousBlockMPTR);\n\t\t\t\t\t}\n\t\t\t\t\t// release removed block\n\t\t\t\t\t_MEMBlockHeap_ReleaseBlockTrack(blockHeapHead, blockMPTR);\n\t\t\t\t\t// debug\n\t\t\t\t\t_blockHeapDebugVerifyIfBlockIsLinked(blockHeapHead, (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(blockMPTR));\n\t\t\t\t\t// merged block becomes the new current block\n\t\t\t\t\tblockMPTR = previousBlockMPTR;\n\t\t\t\t\tblock = previousBlock;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// attempt to merge with next block\n\t\t\tif (_swapEndianU32(block->nextBlock) != MPTR_NULL)\n\t\t\t{\n\t\t\t\tMPTR nextBlockMPTR = _swapEndianU32(block->nextBlock);\n\t\t\t\tMEMBlockHeapTrackDEPR* nextBlock = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(nextBlockMPTR);\n\t\t\t\tif (_swapEndianU32(nextBlock->isFree) != 0)\n\t\t\t\t{\n\t\t\t\t\t// merge\n\t\t\t\t\tblock->addrEnd = nextBlock->addrEnd;\n\t\t\t\t\tblock->nextBlock = nextBlock->nextBlock;\n\t\t\t\t\tif (_swapEndianU32(nextBlock->nextBlock) != MPTR_NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\tMEMBlockHeapTrackDEPR* tempNextBlock = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(_swapEndianU32(nextBlock->nextBlock));\n\t\t\t\t\t\ttempNextBlock->previousBlock = _swapEndianU32(blockMPTR);\n\t\t\t\t\t}\n\t\t\t\t\t//// merged block becomes the new current block\n\t\t\t\t\t//blockMPTR = previousBlockMPTR;\n\t\t\t\t\t//block = previousBlock;\n\t\t\t\t\t// update last block\n\t\t\t\t\tif (_swapEndianU32(blockHeapHead->tailBlock) == nextBlockMPTR)\n\t\t\t\t\t{\n\t\t\t\t\t\tblockHeapHead->tailBlock = _swapEndianU32(blockMPTR);\n\t\t\t\t\t}\n\t\t\t\t\t// release removed block\n\t\t\t\t\t_MEMBlockHeap_ReleaseBlockTrack(blockHeapHead, nextBlockMPTR);\n\t\t\t\t\t// debug\n\t\t\t\t\t_blockHeapDebugVerifyIfBlockIsLinked(blockHeapHead, (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(nextBlockMPTR));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t_blockHeapDebugVerifyLinkOrder(blockHeapHead);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tuint32 MEMGetTotalFreeSizeForBlockHeap(MEMBlockHeapDEPR* blockHeap)\n\t{\n\t\tif (!blockHeap || blockHeap->magic != MEMHeapMagic::BLOCK_HEAP)\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t\treturn 0;\n\t\t}\n\n\t\t__OSLockScheduler(); // todo: replace with spinlock from heap (if heap threadsafe flag is set)\n\t\tuint32 totalSize = 0;\n\t\t// sum up all free blocks\n\t\tMPTR blockMPTR = _swapEndianU32(blockHeap->headBlock);\n\t\twhile (blockMPTR)\n\t\t{\n\t\t\tMEMBlockHeapTrackDEPR* track = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffset(blockMPTR);\n\t\t\tif (track->isFree != _swapEndianU32(0))\n\t\t\t{\n\t\t\t\t// get block size\n\t\t\t\tuint32 blockSize = _swapEndianU32(track->addrEnd) - _swapEndianU32(track->addrStart) + 1;\n\t\t\t\t// add to totalSize\n\t\t\t\ttotalSize += blockSize;\n\t\t\t}\n\t\t\t// next\n\t\t\tblockMPTR = _swapEndianU32(track->nextBlock);\n\t\t}\n\t\t__OSUnlockScheduler(); // todo: replace with spinlock from heap (if heap threadsafe flag is set)\n\n\t\treturn totalSize;\n\t}\n\n\tvoid MEMDumpBlockHeap(MPTR heap)\n\t{\n\t\tMEMBlockHeapDEPR* blockHeapHead = (MEMBlockHeapDEPR*)memory_getPointerFromVirtualOffset(heap);\n\t\tif (blockHeapHead->magic != MEMHeapMagic::BLOCK_HEAP)\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t\treturn;\n\t\t}\n\t\t// iterate reserved/sized blocks\n\t\tdebug_printf(\"### MEMDumpBlockHeap ###\\n\");\n\t\t__OSLockScheduler(); // todo: replace with spinlock from heap\n\t\tMEMBlockHeapTrackDEPR* track = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(blockHeapHead->headBlock));\n\t\twhile (track)\n\t\t{\n\t\t\tuint32 blockRangeStart = _swapEndianU32(track->addrStart);\n\t\t\tuint32 blockRangeEnd = _swapEndianU32(track->addrEnd) + 1;\n\t\t\tdebug_printf(\" %08x %08x - %08x prev/next %08x %08x isFree: %d\\n\", memory_getVirtualOffsetFromPointer(track), blockRangeStart, blockRangeEnd, _swapEndianU32(track->previousBlock), _swapEndianU32(track->nextBlock), _swapEndianU32(track->isFree));\n\t\t\t// next\n\t\t\ttrack = (MEMBlockHeapTrackDEPR*)memory_getPointerFromVirtualOffsetAllowNull(_swapEndianU32(track->nextBlock));\n\t\t}\n\t\tdebug_printf(\"\\n\");\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid InitializeMEMBlockHeap()\n\t{\n\t\tcafeExportRegister(\"coreinit\", MEMInitBlockHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMDestroyBlockHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMGetAllocatableSizeForBlockHeapEx, LogType::CoreinitMem);\n\n\t\tcafeExportRegister(\"coreinit\", MEMAddBlockHeapTracking, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMGetTrackingLeftInBlockHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMAllocFromBlockHeapEx, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMFreeToBlockHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMGetTotalFreeSizeForBlockHeap, LogType::CoreinitMem);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MEM_BlockHeap.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n\nnamespace coreinit\n{\n\tstruct MEMBlockHeapTrack2_t\n\t{\n\t\t/* +0x00 */ MEMPTR<void> addrStart;\n\t\t/* +0x04 */ MEMPTR<void> addrEnd;\n\t\t/* +0x08 */ uint32be isFree; // if 0 -> block is used\n\t\t/* +0x0C */ MEMPTR<void> previousBlock;\n\t\t/* +0x10 */ MEMPTR<void> nextBlock;\n\t};\n\tstatic_assert(sizeof(MEMBlockHeapTrack2_t) == 0x14);\n\n\tstruct MEMBlockHeap2_t : MEMHeapBase\n\t{\n\t\t/* +0x34 */ uint8 ukn[0x50 - 0x34];\n\t\t/* +0x50 */ MEMBlockHeapTrack2_t track;\n\t\t/* +0x64 */ MEMPTR<void> headBlock;\n\t\t/* +0x68 */ MEMPTR<void> tailBlock;\n\t\t/* +0x6C */ MEMPTR<void> nextFreeBlock;\n\t\t/* +0x70 */ uint32be freeBlocksLeft;\n\t\t/* +0x74 */ uint8 padding[0x80 - 0x74];\n\t};\n\tstatic_assert(sizeof(MEMBlockHeap2_t) == 0x80);\n\n\tMEMHeapHandle MEMInitBlockHeap(MEMBlockHeap2_t* memStart, void* startAddr, void* endAddr, void* initTrackMem, uint32 initTrackMemSize, uint32 createFlags);\n\tvoid* MEMDestroyBlockHeap(MEMHeapHandle hHeap);\n\n\tsint32 MEMAddBlockHeapTracking(MPTR heap, MPTR trackMem, uint32 trackMemSize);\n\n\tvoid InitializeMEMBlockHeap();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.h\"\n\n#define EXP_HEAP_GET_FROM_FREE_BLOCKCHAIN(__blockchain__) (MEMExpHeapHead2*)((uintptr_t)__blockchain__ - offsetof(MEMExpHeapHead2, expHeapHead) - offsetof(MEMExpHeapHead40_t, chainFreeBlocks))\n\nnamespace coreinit\n{\n\t#define MBLOCK_TYPE_FREE ('FR')\n\t#define MBLOCK_TYPE_USED ('UD')\n\n\tstruct MBlock2_t\n\t{\n\t\tuint32be fields; // 0x00\n\t\tuint32be dataSize; // 0x04 | size of raw data (excluding size of this struct)\n\t\tMEMPTR<MBlock2_t> prevBlock; // 0x08\n\t\tMEMPTR<MBlock2_t> nextBlock; // 0x0C\n\t\tuint16be typeCode; // 0x10\n\t\tuint16be padding; // 0x12\n\t};\n\tstatic_assert(sizeof(MBlock2_t) == 0x14);\n\n\tstruct ExpMemBlockRegion\n\t{\n\t\tuintptr_t start;\n\t\tuintptr_t end;\n\t};\n\n#define MBLOCK_GET_HEADER(__mblock__) (MBlock2_t*)((uintptr_t)__mblock__ - sizeof(MBlock2_t))\n#define MBLOCK_GET_MEMORY(__mblock__) ((uintptr_t)__mblock__ + sizeof(MBlock2_t))\n#define MBLOCK_GET_END(__mblock__) ((uintptr_t)__mblock__ + sizeof(MBlock2_t) + (uint32)__mblock__->dataSize)\n\n#pragma region internal\n\tMBlock2_t* _MEMExpHeap_InitMBlock(ExpMemBlockRegion* region, uint16 typeCode)\n\t{\n\t\tMBlock2_t* mBlock = (MBlock2_t*)region->start;\n\t\tmemset(mBlock, 0x00, sizeof(MBlock2_t));\n\t\tmBlock->typeCode = typeCode;\n\t\tmBlock->dataSize = (uint32)(region->end - (region->start + sizeof(MBlock2_t)));\n\t\treturn mBlock;\n\t}\n\n\tbool _MEMExpHeap_CheckMBlock(MBlock2_t* mBlock, MEMHeapHandle heap, uint16 typeCode, const char* debugText, int options)\n\t{\n#ifndef MBLOCK_DEBUG_ASSERT \n\t\treturn true;\n#endif\n\t\tconst uintptr_t mBlockAddr = (uintptr_t)mBlock;\n\t\tconst uintptr_t mBlockRawAddr = MBLOCK_GET_MEMORY(mBlock);\n\t\tuintptr_t heapStart = 0, heapEnd = 0;\n\t\tif (heap)\n\t\t{\n\t\t\theapStart = (uintptr_t)heap->heapStart.GetPtr();\n\t\t\theapEnd = (uintptr_t)heap->heapEnd.GetPtr();\n\t\t\tif (heap == MEM_HEAP_INVALID_HANDLE)\n\t\t\t{\n\t\t\t\tif (mBlockAddr < heapStart || mBlockRawAddr > heapEnd)\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (typeCode == (uint16)mBlock->typeCode)\n\t\t{\n\t\t\tif (heap == MEM_HEAP_INVALID_HANDLE)\n\t\t\t\treturn true;\n\n\t\t\tconst uint32 dataSize = mBlock->dataSize;\n\t\t\tif (mBlockRawAddr + dataSize <= heapEnd)\n\t\t\t\treturn true;\n\t\t\treturn false;\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool _MEMExpHeap_IsValidUsedMBlock(const void* memBlock, MEMHeapHandle heap)\n\t{\n#ifndef MBLOCK_DEBUG_ASSERT \n\t\treturn true;\n#endif\n\t\tif (!memBlock)\n\t\t\treturn false;\n\n\t\theap->AcquireLock();\n\n\t\tbool valid = false;\n\t\tMBlock2_t* mBlock = MBLOCK_GET_HEADER(memBlock);\n\n\t\tif (heap)\n\t\t{\n\t\t\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\t\t\tMEMPTR<MBlock2_t> usedBlock = expHeap->expHeapHead.chainUsedBlocks.headMBlock;\n\t\t\twhile (usedBlock)\n\t\t\t{\n\t\t\t\tif (mBlock == usedBlock.GetPtr())\n\t\t\t\t{\n\t\t\t\t\tvalid = _MEMExpHeap_CheckMBlock(mBlock, heap, MBLOCK_TYPE_USED, \"used\", 0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tusedBlock = usedBlock->nextBlock;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvalid = _MEMExpHeap_CheckMBlock(mBlock, heap, MBLOCK_TYPE_USED, \"used\", 0);\n\t\t}\n\n\t\theap->ReleaseLock();\n\n\t\treturn valid;\n\t}\n\n\tvoid _MEMExpHeap_GetRegionOfMBlock(ExpMemBlockRegion* region, MBlock2_t* memBlock)\n\t{\n\t\tuint32 alignment = ((memBlock->fields) >> 8) & 0x7FFFFF;\n\n\t\tuintptr_t memBlockAddr = (uintptr_t)memBlock;\n\t\tregion->start = memBlockAddr - alignment;\n\t\tregion->end = memBlockAddr + sizeof(MBlock2_t) + (uint32)memBlock->dataSize;\n\t}\n\n\tvoid* _MEMExpHeap_RemoveMBlock(MBlockChain2_t* blockChain, MBlock2_t* block)\n\t{\n\t\tMEMPTR<MBlock2_t> prevBlock = block->prevBlock;\n\t\tMEMPTR<MBlock2_t> nextBlock = block->nextBlock;\n\n\t\tif (prevBlock)\n\t\t\tprevBlock->nextBlock = nextBlock;\n\t\telse\n\t\t\tblockChain->headMBlock = nextBlock;\n\n\t\tif (nextBlock)\n\t\t\tnextBlock->prevBlock = prevBlock;\n\t\telse\n\t\t\tblockChain->tailMBlock = prevBlock;\n\n\t\treturn prevBlock.GetPtr();\n\t}\n\n\tMBlock2_t* _MEMExpHeap_InsertMBlock(MBlockChain2_t* blockChain, MBlock2_t* newBlock, MBlock2_t* prevBlock)\n\t{\n\t\tnewBlock->prevBlock = prevBlock;\n\n\t\tMEMPTR<MBlock2_t> nextBlock;\n\t\tif (prevBlock)\n\t\t{\n\t\t\tnextBlock = prevBlock->nextBlock;\n\t\t\tprevBlock->nextBlock = newBlock;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnextBlock = blockChain->headMBlock;\n\t\t\tblockChain->headMBlock = newBlock;\n\t\t}\n\n\t\tnewBlock->nextBlock = nextBlock;\n\t\tif (nextBlock)\n\t\t\tnextBlock->prevBlock = newBlock;\n\t\telse\n\t\t\tblockChain->tailMBlock = newBlock;\n\n\t\treturn newBlock;\n\t}\n\n\tbool _MEMExpHeap_RecycleRegion(MBlockChain2_t* blockChain, ExpMemBlockRegion* region)\n\t{\n\t\tExpMemBlockRegion newRegion;\n\t\tnewRegion.start = region->start;\n\t\tnewRegion.end = region->end;\n\n\t\tMEMPTR<MBlock2_t> prev;\n\t\tMEMPTR<MBlock2_t> find = blockChain->headMBlock;\n\t\twhile (find)\n\t\t{\n\t\t\tMBlock2_t* findMBlock = find.GetPtr();\n\t\t\tconst uintptr_t blockAddr = (uintptr_t)findMBlock;\n\t\t\tif (blockAddr >= region->start)\n\t\t\t{\n\t\t\t\tif (blockAddr == region->end)\n\t\t\t\t{\n\t\t\t\t\tnewRegion.end = MBLOCK_GET_END(findMBlock);\n\t\t\t\t\t_MEMExpHeap_RemoveMBlock(blockChain, findMBlock);\n\n\t\t\t\t\tMEMExpHeapHead2* heap = EXP_HEAP_GET_FROM_FREE_BLOCKCHAIN(blockChain);\n\t\t\t\t\tuint8 options = heap->flags;\n\t\t\t\t\tif (HAS_FLAG(options, MEM_HEAP_OPTION_FILL))\n\t\t\t\t\t{\n\t\t\t\t\t\tconst uint32 fillVal = MEMGetFillValForHeap(HEAP_FILL_TYPE::ON_FREE);\n\t\t\t\t\t\tmemset(findMBlock, fillVal, sizeof(MBlock2_t));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tprev = find;\n\t\t\tfind = findMBlock->nextBlock;\n\t\t}\n\n\t\tif (prev)\n\t\t{\n\t\t\tMBlock2_t* prevMBlock = prev.GetPtr();\n\t\t\tif (MBLOCK_GET_END(prevMBlock) == region->start)\n\t\t\t{\n\t\t\t\tnewRegion.start = (uintptr_t)prevMBlock;\n\t\t\t\tprev = (MBlock2_t*)_MEMExpHeap_RemoveMBlock(blockChain, prevMBlock);\n\t\t\t}\n\t\t}\n\n\t\tif ((newRegion.end - newRegion.start) < sizeof(MBlock2_t))\n\t\t\treturn false;\n\n\t\tMEMExpHeapHead2* heap = EXP_HEAP_GET_FROM_FREE_BLOCKCHAIN(blockChain);\n\t\tuint8 options = heap->flags;\n\t\tif (HAS_FLAG(options, MEM_HEAP_OPTION_FILL))\n\t\t{\n\t\t\tconst uint32 fillVal = MEMGetFillValForHeap(HEAP_FILL_TYPE::ON_FREE);\n\t\t\tmemset((void*)region->start, fillVal, region->end - region->start);\n\t\t}\n\n\t\tMBlock2_t* newBlock = _MEMExpHeap_InitMBlock(&newRegion, MBLOCK_TYPE_FREE);\n\t\t_MEMExpHeap_InsertMBlock(blockChain, newBlock, prev.GetPtr());\n\t\treturn true;\n\t}\n\nvoid* _MEMExpHeap_AllocUsedBlockFromFreeBlock(MBlockChain2_t* blockChain, MBlock2_t* freeBlock, uintptr_t blockMemStart, uint32 size, MEMExpHeapAllocDirection direction)\n{\n\tMEMExpHeapHead2* heap = EXP_HEAP_GET_FROM_FREE_BLOCKCHAIN(blockChain);\n\n\tExpMemBlockRegion freeRegion;\n\t_MEMExpHeap_GetRegionOfMBlock(&freeRegion, freeBlock);\n\n\tExpMemBlockRegion newRegion = {blockMemStart + size, freeRegion.end};\n\tfreeRegion.end = blockMemStart - sizeof(MBlock2_t);\n\n\tMBlock2_t* prevBlock = (MBlock2_t*)_MEMExpHeap_RemoveMBlock(blockChain, freeBlock);\n\n\tif ((freeRegion.end - freeRegion.start) >= 0x18 && (direction != MEMExpHeapAllocDirection::HEAD || HAS_FLAG(heap->expHeapHead.fields, MEM_EXPHEAP_USE_ALIGN_MARGIN)))\n\t{\n\t\tMBlock2_t* newBlock = _MEMExpHeap_InitMBlock(&freeRegion, MBLOCK_TYPE_FREE);\n\t\tprevBlock = _MEMExpHeap_InsertMBlock(blockChain, newBlock, prevBlock);\n\t}\n\telse\n\t\tfreeRegion.end = freeRegion.start;\n\n\tif ((newRegion.end - newRegion.start) >= 0x18 && (direction != MEMExpHeapAllocDirection::TAIL || HAS_FLAG(heap->expHeapHead.fields, MEM_EXPHEAP_USE_ALIGN_MARGIN)))\n\t{\n\t\tMBlock2_t* newBlock = _MEMExpHeap_InitMBlock(&newRegion, MBLOCK_TYPE_FREE);\n\t\tprevBlock = _MEMExpHeap_InsertMBlock(blockChain, newBlock, prevBlock);\n\t}\n\telse\n\t\tnewRegion.start = newRegion.end;\n\n\tuint8 options = heap->flags;\n\tif (HAS_FLAG(options, MEM_HEAP_OPTION_CLEAR))\n\t{\n\t\tmemset((void*)freeRegion.end, 0x00, newRegion.start - freeRegion.end);\n\t}\n\telse if (HAS_FLAG(options, MEM_HEAP_OPTION_FILL))\n\t{\n\t\tconst uint32 fillValue = MEMGetFillValForHeap(HEAP_FILL_TYPE::ON_ALLOC);\n\t\tmemset((void*)freeRegion.end, fillValue, newRegion.start - freeRegion.end);\n\t}\n\n\tExpMemBlockRegion allocRegion = {blockMemStart - sizeof(MBlock2_t), newRegion.start};\n\tMBlock2_t* newBlock = _MEMExpHeap_InitMBlock(&allocRegion, MBLOCK_TYPE_USED);\n\n\tuint32 fields = (uint32)newBlock->fields;\n\tif(direction == MEMExpHeapAllocDirection::TAIL)\n\t\tfields |= 1 << 31;\n\telse\n\t\tfields &= ~(1 << 31);\n\tuint32 alignmentPadding = (uint32)((uintptr_t)newBlock - (uintptr_t)freeRegion.end);\n\tfields |= (alignmentPadding & 0x7FFFFF) << 8;\n\tfields |= ((uint32)heap->expHeapHead.groupID & 0xFF);\n\tnewBlock->fields = fields;\n\t\n\tMBlock2_t* tailBlock = heap->expHeapHead.chainUsedBlocks.tailMBlock.GetPtr();\n\t_MEMExpHeap_InsertMBlock(&heap->expHeapHead.chainUsedBlocks, newBlock, tailBlock);\n\n\treturn (void*)blockMemStart;\n}\n\nvoid* _MEMExpHeap_AllocFromTail(MEMHeapHandle heap, uint32 size, int alignment)\n{\n\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\n\tconst bool searchForFirstEntry = (expHeap->expHeapHead.fields&1) == MEM_EXPHEAP_ALLOC_MODE_FIRST;\n\tconst int alignmentMinusOne = alignment - 1;\n\n\tMBlock2_t* freeBlock = nullptr;\n\tuintptr_t blockMemStart = 0;\n\tuint32 foundSize = -1;\n\n\tfor (MBlock2_t* findBlock = expHeap->expHeapHead.chainFreeBlocks.tailMBlock.GetPtr(); findBlock != nullptr; findBlock = findBlock->prevBlock.GetPtr())\n\t{\n\t\tconst uintptr_t blockMemory = MBLOCK_GET_MEMORY(findBlock);\n\n\t\tconst uint32 dataSize = (uint32)findBlock->dataSize;\n\t\tconst uintptr_t alignedEndBlockMemory = (blockMemory + dataSize - size) & ~alignmentMinusOne;\n\t\t\n\t\tif (alignedEndBlockMemory < blockMemory)\n\t\t\tcontinue;\n\n\t\tif (foundSize <= dataSize)\n\t\t\tcontinue;\n\n\t\tfreeBlock = findBlock;\n\t\tblockMemStart = alignedEndBlockMemory;\n\t\tfoundSize = dataSize;\n\n\t\tif (searchForFirstEntry)\n\t\t\tbreak;\n\n\t\tif (foundSize == size)\n\t\t\tbreak;\n\t}\n\n\tvoid* mem = nullptr;\n\tif (freeBlock)\n\t\tmem = _MEMExpHeap_AllocUsedBlockFromFreeBlock(&expHeap->expHeapHead.chainFreeBlocks, freeBlock, blockMemStart, size, coreinit::MEMExpHeapAllocDirection::TAIL);\n\n\treturn mem;\n}\n\nvoid* _MEMExpHeap_AllocFromHead(MEMHeapHandle heap, uint32 size, int alignment)\n{\n\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\n\tconst bool searchForFirstEntry = (expHeap->expHeapHead.fields&1) == MEM_EXPHEAP_ALLOC_MODE_FIRST;\n\tconst int alignmentMinusOne = alignment - 1;\n\n\tMBlock2_t* freeBlock = nullptr;\n\tuintptr_t blockMemStart = 0;\n\tuint32 foundSize = -1;\n\n\tfor (MBlock2_t* findBlock = expHeap->expHeapHead.chainFreeBlocks.headMBlock.GetPtr(); findBlock != nullptr; findBlock = findBlock->nextBlock.GetPtr())\n\t{\n\t\tconst uintptr_t blockMemory = MBLOCK_GET_MEMORY(findBlock);\n\t\tconst uintptr_t alignedBlockMemory = (blockMemory + alignmentMinusOne) & ~alignmentMinusOne;\n\t\tconst uint32 dataSize = (uint32)findBlock->dataSize;\n\n\t\tif (dataSize < alignedBlockMemory - blockMemory + size)\n\t\t\tcontinue;\n\n\t\tif (foundSize <= dataSize)\n\t\t\tcontinue;\n\n\t\tfreeBlock = findBlock;\n\t\tblockMemStart = alignedBlockMemory;\n\t\tfoundSize = dataSize;\n\n\t\tif (searchForFirstEntry)\n\t\t\tbreak;\n\n\t\tif (foundSize == size)\n\t\t\tbreak;\n\t}\n\n\tvoid* mem = nullptr;\n\tif (freeBlock)\n\t\tmem = _MEMExpHeap_AllocUsedBlockFromFreeBlock(&expHeap->expHeapHead.chainFreeBlocks, freeBlock, blockMemStart, size, coreinit::MEMExpHeapAllocDirection::HEAD);\n\n\treturn mem;\n}\n\nMEMHeapHandle _MEMExpHeap_InitHeap(void* startAddress, void* endAddress, uint32 createFlags)\n{\n\tMEMExpHeapHead2* header = (MEMExpHeapHead2*)startAddress;\n\tuintptr_t heapStart = (uintptr_t)startAddress + sizeof(MEMExpHeapHead2);\n\n\tMEMInitHeapBase(header, coreinit::MEMHeapMagic::EXP_HEAP, (void*)heapStart, endAddress, createFlags);\n\n\tExpMemBlockRegion region;\n\tregion.start = (uintptr_t)header->heapStart.GetPtr();\n\tregion.end = (uintptr_t)header->heapEnd.GetPtr();\n\n\tMBlock2_t* mBlock = _MEMExpHeap_InitMBlock(&region, MBLOCK_TYPE_FREE);\n\n\theader->expHeapHead.chainFreeBlocks.headMBlock = mBlock;\n\theader->expHeapHead.chainFreeBlocks.tailMBlock = mBlock;\n\n\theader->expHeapHead.chainUsedBlocks.headMBlock = nullptr;\n\theader->expHeapHead.chainUsedBlocks.tailMBlock = nullptr;\n\n\theader->expHeapHead.groupID = 0;\n\theader->expHeapHead.fields = 0;\n\n\treturn (MEMHeapHandle)header;\n}\n\nMEMHeapHandle MEMCreateExpHeap(void* startAddress, uint32 size)\n{\n\treturn MEMCreateExpHeapEx(startAddress, size, MEM_HEAP_OPTION_NONE);\n}\n\nvoid* MEMAllocFromExpHeap(MEMHeapHandle heap, uint32 size)\n{\n\treturn MEMAllocFromExpHeapEx(heap, size, MEM_HEAP_DEFAULT_ALIGNMENT);\n}\n\nuint32 MEMGetAllocatableSizeForExpHeap(MEMHeapHandle heap)\n{\n\treturn MEMGetAllocatableSizeForExpHeapEx(heap, MEM_HEAP_DEFAULT_ALIGNMENT);\n}\n\nvoid IsValidExpHeapHandle_(MEMHeapHandle heap)\n{\n\tcemu_assert_debug(heap != MEM_HEAP_INVALID_HANDLE);\n\tcemu_assert_debug(heap->magic == coreinit::MEMHeapMagic::EXP_HEAP);\n}\n\n#pragma endregion\n\n#pragma region exported\n\nMEMHeapHandle MEMCreateExpHeapEx(void* startAddress, uint32 size, uint32 createFlags)\n{\n\tif (startAddress == nullptr)\n\t\treturn MEM_HEAP_INVALID_HANDLE;\n\n\tconst uintptr_t alignedStart = ((uintptr_t)startAddress + MIN_ALIGNMENT_MINUS_ONE) & (~MIN_ALIGNMENT_MINUS_ONE);\n\tconst uintptr_t alignedEnd = ((uintptr_t)startAddress + size) & (~MIN_ALIGNMENT_MINUS_ONE);\n\n\tif (alignedStart > alignedEnd)\n\t\treturn MEM_HEAP_INVALID_HANDLE;\n\n\tif (alignedEnd - alignedStart < 0x6C)\n\t\treturn MEM_HEAP_INVALID_HANDLE;\n\n\tMEMHeapHandle result = _MEMExpHeap_InitHeap((void*)alignedStart, (void*)alignedEnd, createFlags);\n\tif (result)\n\t\tMEMHeapTable_Add(result);\n\n\treturn result;\n}\n\nvoid* MEMDestroyExpHeap(MEMHeapHandle heap)\n{\n\tIsValidExpHeapHandle_(heap);\n\tMEMBaseDestroyHeap(heap);\n\tMEMHeapTable_Remove(heap);\n\treturn heap;\n}\n\nvoid* MEMAllocFromExpHeapEx(MEMHeapHandle heap, uint32 size, sint32 alignment)\n{\n\tIsValidExpHeapHandle_(heap);\n\tif (alignment == 0)\n\t{\n\t\t// this is a guaranteed crash on the actual console\n\t\tcemuLog_log(LogType::Force, \"MEMAllocFromExpHeapEx(): Alignment 0 not allowed\");\n\t\talignment = 4;\n\t\treturn nullptr;\n\t}\n\n\tif (size == 0)\n\t\tsize = 1;\n\n\tsize = (size + MIN_ALIGNMENT_MINUS_ONE) & ~MIN_ALIGNMENT_MINUS_ONE;\n\n\theap->AcquireLock();\n\n\tvoid* mem;\n\tif (alignment < 0)\n\t{\n\t\talignment = -alignment;\n\t\tmem = _MEMExpHeap_AllocFromTail(heap, size, alignment);\n\t}\n\telse\n\t{\n\t\tmem = _MEMExpHeap_AllocFromHead(heap, size, alignment);\n\t}\n\n\theap->ReleaseLock();\n\n\treturn mem;\n}\n\nvoid MEMFreeToExpHeap(MEMHeapHandle heap, void* mem)\n{\n\tIsValidExpHeapHandle_(heap);\n\tif (mem)\n\t{\n\t\theap->AcquireLock();\n\n\t\tcemu_assert_debug(_MEMExpHeap_IsValidUsedMBlock(mem, heap) == true);\n\t\tcemu_assert_debug((uintptr_t)heap->heapStart.GetPtr() <= (uintptr_t)mem && (uintptr_t)mem < (uintptr_t)heap->heapEnd.GetPtr());\n\n\t\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\n\t\tExpMemBlockRegion region;\n\t\tMBlock2_t* mBlock = MBLOCK_GET_HEADER(mem);\n\t\t_MEMExpHeap_GetRegionOfMBlock(&region, mBlock);\n\n\t\t_MEMExpHeap_RemoveMBlock(&expHeap->expHeapHead.chainUsedBlocks, mBlock);\n\t\t_MEMExpHeap_RecycleRegion(&expHeap->expHeapHead.chainFreeBlocks, &region);\n\n\t\theap->ReleaseLock();\n\t}\n}\n\nuint16 MEMSetAllocModeForExpHeap(MEMHeapHandle heap, uint16 mode)\n{\n\tIsValidExpHeapHandle_(heap);\n\theap->AcquireLock();\n\n\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\tconst uint16 oldMode = expHeap->expHeapHead.fields & 0x1;\n\texpHeap->expHeapHead.fields |= (mode & 0x1);\n\n\theap->ReleaseLock();\n\n\treturn oldMode;\n}\n\nuint16 MEMGetAllocModeForExpHeap(MEMHeapHandle heap)\n{\n\tIsValidExpHeapHandle_(heap);\n\theap->AcquireLock();\n\n\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\tconst uint16 mode = expHeap->expHeapHead.fields & 0x1;\n\n\theap->ReleaseLock();\n\n\treturn mode;\n}\n\nuint32 MEMAdjustExpHeap(MEMHeapHandle heap)\n{\n\tuint32 newSize = 0;\n\n\tIsValidExpHeapHandle_(heap);\n\theap->AcquireLock();\n\n\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\n\tMEMPTR<MBlock2_t> tailBlock = expHeap->expHeapHead.chainFreeBlocks.tailMBlock;\n\tif (tailBlock)\n\t{\n\t\tMBlock2_t* tail = tailBlock.GetPtr();\n\n\t\tuintptr_t blockMemEnd = MBLOCK_GET_END(tail);\n\t\tuintptr_t heapEnd = (uintptr_t)heap->heapEnd.GetPtr();\n\t\tif (blockMemEnd == heapEnd)\n\t\t{\n\t\t\t_MEMExpHeap_RemoveMBlock(&expHeap->expHeapHead.chainFreeBlocks, tail);\n\n\t\t\tuint32 removedBlockSize = sizeof(MBlock2_t) + (uint32)tail->dataSize;\n\t\t\tuintptr_t newHeapEnd = heapEnd - removedBlockSize;\n\t\t\theap->heapEnd = (void*)newHeapEnd;\n\n\t\t\tnewSize = (uint32)(newHeapEnd - (uintptr_t)heap);\n\t\t}\n\t}\n\n\theap->ReleaseLock();\n\n\treturn newSize;\n}\n\nuint32 MEMResizeForMBlockExpHeap(MEMHeapHandle heap, void* memBlock, uint32 size)\n{\n\tuint32 newSize = 0;\n\n\tIsValidExpHeapHandle_(heap);\n\tcemu_assert_debug(memBlock != nullptr);\n\theap->AcquireLock();\n\n\tMBlock2_t* mBlock = MBLOCK_GET_HEADER(memBlock);\n\tconst uint32 dataSize = mBlock->dataSize;\n\tif (dataSize != size)\n\t{\n\t\tcemu_assert_debug(_MEMExpHeap_IsValidUsedMBlock(memBlock, heap));\n\n\t\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\n\t\tif (size <= dataSize)\n\t\t{\n\t\t\tExpMemBlockRegion region;\n\t\t\tregion.start = (uintptr_t)memBlock + size;\n\t\t\tregion.end = MBLOCK_GET_END(mBlock);\n\n\t\t\tmBlock->dataSize = size;\n\n\t\t\tif (!_MEMExpHeap_RecycleRegion(&expHeap->expHeapHead.chainFreeBlocks, &region))\n\t\t\t\tmBlock->dataSize = dataSize;\n\n\t\t\tnewSize = (uint32)mBlock->dataSize;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tMEMPTR<MBlock2_t> free = expHeap->expHeapHead.chainFreeBlocks.headMBlock;\n\t\t\tconst uintptr_t blockEndAddr = MBLOCK_GET_END(mBlock);\n\t\t\twhile (free)\n\t\t\t{\n\t\t\t\tMBlock2_t* freeBlock = free.GetPtr();\n\t\t\t\tif ((uintptr_t)freeBlock == blockEndAddr)\n\t\t\t\t{\n\t\t\t\t\tconst uint32 freeDataSize = freeBlock->dataSize;\n\t\t\t\t\tif (size > (dataSize + freeDataSize + sizeof(MBlock2_t)))\n\t\t\t\t\t{\n\t\t\t\t\t\tnewSize = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tExpMemBlockRegion region;\n\t\t\t\t\t_MEMExpHeap_GetRegionOfMBlock(&region, freeBlock);\n\t\t\t\t\tMBlock2_t* prevBlock = (MBlock2_t*)_MEMExpHeap_RemoveMBlock(&expHeap->expHeapHead.chainFreeBlocks, freeBlock);\n\n\t\t\t\t\tuintptr_t oldStart = region.start;\n\t\t\t\t\tregion.start = (uintptr_t)memBlock + size;\n\n\t\t\t\t\tif (region.end - region.start < sizeof(MBlock2_t))\n\t\t\t\t\t\tregion.start = region.end;\n\n\t\t\t\t\tmBlock->dataSize = (uint32)(region.start - (uintptr_t)memBlock);\n\t\t\t\t\tif (region.end - region.start >= sizeof(MBlock2_t))\n\t\t\t\t\t{\n\t\t\t\t\t\tMBlock2_t* newBlock = _MEMExpHeap_InitMBlock(&region, MBLOCK_TYPE_FREE);\n\t\t\t\t\t\t_MEMExpHeap_InsertMBlock(&expHeap->expHeapHead.chainFreeBlocks, newBlock, prevBlock);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (HAS_FLAG(heap->flags, MEM_HEAP_OPTION_CLEAR))\n\t\t\t\t\t\tmemset((void*)oldStart, 0x00, region.start - oldStart);\n\t\t\t\t\telse if (HAS_FLAG(heap->flags, MEM_HEAP_OPTION_FILL))\n\t\t\t\t\t{\n\t\t\t\t\t\tconst uint32 fillValue = MEMGetFillValForHeap(HEAP_FILL_TYPE::ON_ALLOC);\n\t\t\t\t\t\tmemset((void*)oldStart, fillValue, region.start - oldStart);\n\t\t\t\t\t}\n\n\t\t\t\t\tnewSize = (uint32)mBlock->dataSize;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tfree = freeBlock->nextBlock;\n\t\t\t}\n\n\t\t\tif (!free)\n\t\t\t\tnewSize = 0;\n\t\t}\n\t}\n\n\theap->ReleaseLock();\n\n\treturn newSize;\n}\n\nuint32 MEMGetTotalFreeSizeForExpHeap(MEMHeapHandle heap)\n{\n\tuint32 freeSize = 0;\n\n\tIsValidExpHeapHandle_(heap);\n\theap->AcquireLock();\n\n\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\n\tMEMPTR<MBlock2_t> block = expHeap->expHeapHead.chainFreeBlocks.headMBlock;\n\twhile (block)\n\t{\n\t\tfreeSize += (uint32)block->dataSize;\n\t\tblock = block->nextBlock;\n\t}\n\n\theap->ReleaseLock();\n\n\treturn freeSize;\n}\n\nuint32 MEMGetAllocatableSizeForExpHeapEx(MEMHeapHandle heap, sint32 alignment)\n{\n\tuint32 result = 0;\n\n\tIsValidExpHeapHandle_(heap);\n\tcemu_assert_debug((alignment & 3) == 0);\n\talignment = abs(alignment);\n\n\theap->AcquireLock();\n\n\tMEMExpHeapHead2* exp_heap = (MEMExpHeapHead2*)heap;\n\tconst sint32 alignment_minus_one = alignment - 1;\n\n\tuint32 smallest_alignment_space = -1;\n\tfor(auto free_block = exp_heap->expHeapHead.chainFreeBlocks.headMBlock; free_block; free_block = free_block->nextBlock)\n\t{\n\t\tMBlock2_t* block = free_block.GetPtr();\n\t\tconst uintptr_t block_memory = MBLOCK_GET_MEMORY(block);\n\t\tconst uintptr_t block_end = MBLOCK_GET_END(block);\n\n\t\tconst uintptr_t aligned_memory = (block_memory + alignment_minus_one) & ~alignment_minus_one;\n\t\tif (aligned_memory >= block_end)\n\t\t\tcontinue;\n\n\t\tconst uint32 size = (uint32)(block_end - aligned_memory);\n\t\tconst uint32 alignment_space = (uint32)(aligned_memory - block_memory);\n\t\tif (size < result)\n\t\t\tcontinue;\n\n\t\tif (size == result)\n\t\t{\n\t\t\tif (smallest_alignment_space <= alignment_space)\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tsmallest_alignment_space = alignment_space;\n\t\tresult = size;\n\t}\n\n\theap->ReleaseLock();\n\n\treturn result;\n}\n\nuint16 MEMSetGroupIDForExpHeap(MEMHeapHandle heap, uint16 groupId)\n{\n\tIsValidExpHeapHandle_(heap);\n\n\theap->AcquireLock();\n\n\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\tconst uint16 oldGroupId = expHeap->expHeapHead.groupID;\n\texpHeap->expHeapHead.groupID = groupId;\n\n\theap->ReleaseLock();\n\n\treturn oldGroupId;\n}\n\nuint16 MEMGetGroupIDForExpHeap(MEMHeapHandle heap)\n{\n\tIsValidExpHeapHandle_(heap);\n\n\theap->AcquireLock();\n\n\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\tconst uint16 oldGroupId = expHeap->expHeapHead.groupID;\n\n\theap->ReleaseLock();\n\n\treturn oldGroupId;\n}\n\nvoid MEMVisitAllocatedForExpHeap(MEMHeapHandle heap, const MEMPTR<void>& visitor, uint32 userParam)\n{\n\tIsValidExpHeapHandle_(heap);\n\tcemu_assert_debug(visitor != nullptr);\n\n\theap->AcquireLock();\n\n\tMEMPTR<MEMHeapBase> heapMPTR = heap;\n\n\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heap;\n\tMEMPTR<MBlock2_t> find = expHeap->expHeapHead.chainUsedBlocks.headMBlock;\n\twhile (find)\n\t{\n\t\tMBlock2_t* mBlock = find.GetPtr();\n\n\t\tMEMPTR<void> memMPTR = (void*)MBLOCK_GET_MEMORY(mBlock);\n\t\tPPCCoreCallback(visitor.GetMPTR(), memMPTR.GetMPTR(), heapMPTR.GetMPTR(), userParam);\n\n\t\tfind = mBlock->nextBlock;\n\t}\n\n\theap->ReleaseLock();\n}\n\nuint32 MEMGetSizeForMBlockExpHeap(const void* memBlock)\n{\n\tcemu_assert_debug(_MEMExpHeap_IsValidUsedMBlock(memBlock, nullptr));\n\tMBlock2_t* mBlock = MBLOCK_GET_HEADER(memBlock);\n\treturn mBlock->dataSize;\n}\n\nuint16 MEMGetGroupIDForMBlockExpHeap(const void* memBlock)\n{\n\tcemu_assert_debug(_MEMExpHeap_IsValidUsedMBlock(memBlock, nullptr));\n\tMBlock2_t* mBlock = MBLOCK_GET_HEADER(memBlock);\n\treturn (uint32)mBlock->fields & 0xFF;\n}\n\nuint16 MEMGetAllocDirForMBlockExpHeap(const void* memBlock)\n{\n\tcemu_assert_debug(_MEMExpHeap_IsValidUsedMBlock(memBlock, nullptr));\n\tMBlock2_t* mBlock = MBLOCK_GET_HEADER(memBlock);\n\tconst uint32 fields = mBlock->fields;\n\treturn (fields >> 31) & 1;\n}\n\nbool MEMCheckExpHeap(MEMHeapHandle heap, uint32 options)\n{\n\tif (heap == MEM_HEAP_INVALID_HANDLE || heap->magic != coreinit::MEMHeapMagic::EXP_HEAP)\n\t\treturn false;\n\n\theap->AcquireLock();\n\n\t// todo\n\n\theap->ReleaseLock();\n\n\treturn true;\n}\n\nbool MEMCheckForMBlockExpHeap(const void* memBlock, MEMHeapHandle heap, uint32 options)\n{\n\treturn true;\n}\n\nvoid _DefaultAllocatorForExpHeap_Alloc(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(allocator, MEMAllocator, 0);\n\tppcDefineParamU32(size, 1);\n\tMEMPTR<void> result = MEMAllocFromExpHeapEx((MEMHeapHandle)allocator->heap.GetPtr(), size, (uint32)allocator->param1);\n\tosLib_returnFromFunction(hCPU, result.GetMPTR());\n}\n\nvoid _DefaultAllocatorForExpHeap_Free(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(allocator, MEMAllocator, 0);\n\tppcDefineParamMEMPTR(mem, void, 1);\n\tMEMFreeToExpHeap((MEMHeapHandle)allocator->heap.GetPtr(), mem);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nSysAllocator<MEMAllocatorFunc> gExpHeapDefaultAllocator;\n\nvoid MEMInitAllocatorForExpHeap(MEMAllocator* allocator, MEMHeapHandle heap, sint32 alignment)\n{\n\tallocator->func = gExpHeapDefaultAllocator.GetPtr();\n\tgExpHeapDefaultAllocator->funcAlloc = PPCInterpreter_makeCallableExportDepr(_DefaultAllocatorForExpHeap_Alloc);\n\tgExpHeapDefaultAllocator->funcFree = PPCInterpreter_makeCallableExportDepr(_DefaultAllocatorForExpHeap_Free);\n\n\tallocator->heap = heap;\n\tallocator->param1 = alignment;\n\tallocator->param2 = 0;\n}\n#pragma endregion\n\n#pragma region wrapper\n\nvoid expheap_test();\n\nvoid export_MEMCreateExpHeapEx(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(startAddress, void, 0);\n\tppcDefineParamU32(size, 1);\n\tppcDefineParamU16(options, 2);\n\tMEMPTR<MEMHeapBase> heap = MEMCreateExpHeapEx(startAddress.GetPtr(), size, options);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMCreateExpHeapEx(0x{:08x}, 0x{:x}, 0x{:x}) Result: 0x{:08x}\", startAddress.GetMPTR(), size, options, heap.GetMPTR());\n\tosLib_returnFromFunction(hCPU, heap.GetMPTR());\n}\n\nvoid export_MEMDestroyExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMDestroyExpHeap(0x{:08x})\", heap.GetMPTR());\n\tMEMPTR<MEMHeapBase> oldHeap = (MEMHeapBase*)MEMDestroyExpHeap(heap.GetPtr());\n\tosLib_returnFromFunction(hCPU, oldHeap.GetMPTR());\n}\n\nvoid export_MEMAllocFromExpHeapEx(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tppcDefineParamU32(size, 1);\n\tppcDefineParamS32(alignment, 2);\n\tMEMPTR<void> mem = MEMAllocFromExpHeapEx(heap.GetPtr(), size, alignment);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMAllocFromExpHeapEx(0x{:08x}, 0x{:x}, {}) Result: 0x{:08x}\", heap.GetMPTR(), size, alignment, mem.GetMPTR());\n\tosLib_returnFromFunction(hCPU, mem.GetMPTR());\n}\n\nvoid export_MEMFreeToExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tppcDefineParamMEMPTR(mem, void, 1);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMFreeToExpHeap(0x{:08x}, 0x{:08x})\", heap.GetMPTR(), mem.GetMPTR());\n\tMEMFreeToExpHeap(heap.GetPtr(), mem.GetPtr());\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid export_MEMSetAllocModeForExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tppcDefineParamU16(mode, 1);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMSetAllocModeForExpHeap(0x{:08x}, {})\", heap.GetMPTR(), mode);\n\tuint16 oldMode = MEMSetAllocModeForExpHeap(heap.GetPtr(), mode);\n\tosLib_returnFromFunction(hCPU, oldMode);\n}\n\nvoid export_MEMGetAllocModeForExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMGetAllocModeForExpHeap(0x{:08x})\", heap.GetMPTR());\n\tuint16 oldMode = MEMGetAllocModeForExpHeap(heap.GetPtr());\n\tosLib_returnFromFunction(hCPU, oldMode);\n}\n\nvoid export_MEMAdjustExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMAdjustExpHeap(0x{:08x})\", heap.GetMPTR());\n\tuint32 newSize = MEMAdjustExpHeap(heap.GetPtr());\n\tosLib_returnFromFunction(hCPU, newSize);\n}\n\nvoid export_MEMResizeForMBlockExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tppcDefineParamMEMPTR(mem, void, 1);\n\tppcDefineParamU32(size, 2);\n\tuint32 newSize = MEMResizeForMBlockExpHeap(heap.GetPtr(), mem.GetPtr(), size);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMResizeForMBlockExpHeap(0x{:08x}, 0x{:08x}, 0x{:x}) Result: 0x{:x}\", heap.GetMPTR(), mem.GetMPTR(), size, newSize);\n\tosLib_returnFromFunction(hCPU, newSize);\n}\n\nvoid export_MEMGetTotalFreeSizeForExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tuint32 size = MEMGetTotalFreeSizeForExpHeap(heap.GetPtr());\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMGetTotalFreeSizeForExpHeap(0x{:08x}) Result: 0x{:x}\", heap.GetMPTR(), size);\n\tosLib_returnFromFunction(hCPU, size);\n}\n\nvoid export_MEMGetAllocatableSizeForExpHeapEx(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tppcDefineParamS32(alignment, 1);\n\tuint32 size = MEMGetAllocatableSizeForExpHeapEx(heap.GetPtr(), alignment);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMGetAllocatableSizeForExpHeapEx(0x{:08x}, 0x{:x}) Result: 0x{:x}\", heap.GetMPTR(), alignment, size);\n\tosLib_returnFromFunction(hCPU, size);\n}\n\nvoid export_MEMSetGroupIDForExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tppcDefineParamU16(groupId, 1);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMSetGroupIDForExpHeap(0x{:08x}, {})\", heap.GetMPTR(), groupId);\n#ifdef CEMU_DEBUG_ASSERT\n\tassert_dbg(); // someone test this and the entire groupId feature\n#endif\n\tuint16 oldGroupId = MEMSetGroupIDForExpHeap(heap.GetPtr(), groupId);\n\tosLib_returnFromFunction(hCPU, oldGroupId);\n}\n\nvoid export_MEMGetGroupIDForExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tcemuLog_logDebug(LogType::Force, \"MEMGetGroupIDForExpHeap(0x{:08x})\", heap.GetMPTR());\n\tuint16 oldGroupId = MEMGetGroupIDForExpHeap(heap.GetPtr());\n\tosLib_returnFromFunction(hCPU, oldGroupId);\n}\n\nvoid export_MEMVisitAllocatedForExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tppcDefineParamMEMPTR(visitor, void, 1);\n\tppcDefineParamU32(userParam, 2);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMVisitAllocatedForExpHeap(0x{:08x}, 0x{:08x}, 0x{:x})\", heap.GetMPTR(), visitor.GetMPTR(), userParam);\n\tMEMVisitAllocatedForExpHeap(heap.GetPtr(), visitor, userParam);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid export_MEMGetSizeForMBlockExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(memBlock, void, 0);\n\tuint32 size = MEMGetSizeForMBlockExpHeap(memBlock.GetPtr());\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMGetSizeForMBlockExpHeap(0x{:08x}) Result: 0x{:x}\", memBlock.GetMPTR(), size);\n\tosLib_returnFromFunction(hCPU, size);\n}\n\nvoid export_MEMGetGroupIDForMBlockExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(memBlock, void, 0);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMGetGroupIDForMBlockExpHeap(0x{:08x})\", memBlock.GetMPTR());\n\tuint16 groupId = MEMGetGroupIDForMBlockExpHeap(memBlock.GetPtr());\n\tosLib_returnFromFunction(hCPU, groupId);\n}\n\nvoid export_MEMGetAllocDirForMBlockExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(memBlock, void, 0);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMGetAllocDirForMBlockExpHeap(0x{:08x})\", memBlock.GetMPTR());\n\tuint16 allocDir = MEMGetAllocDirForMBlockExpHeap(memBlock.GetPtr());\n\tosLib_returnFromFunction(hCPU, allocDir);\n}\n\nvoid export_MEMCheckExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 0);\n\tppcDefineParamU32(options, 1);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMCheckExpHeap(0x{:08x}, 0x{:x})\", heap.GetMPTR(), options);\n\tbool result = MEMCheckExpHeap(heap.GetPtr(), options);\n\tosLib_returnFromFunction(hCPU, result ? 1 : 0);\n}\n\nvoid export_MEMCheckForMBlockExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(memBlock, void, 0);\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 1);\n\tppcDefineParamU32(options, 2);\n\tbool result = MEMCheckForMBlockExpHeap(memBlock.GetPtr(), heap.GetPtr(), options);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMCheckForMBlockExpHeap(0x{:08x}, 0x{:08x}, 0x{:x}) Result: {}\", memBlock.GetMPTR(), heap.GetMPTR(), options, result);\n\tosLib_returnFromFunction(hCPU, result ? 1 : 0);\n}\n\nvoid export_MEMInitAllocatorForExpHeap(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(allocator, MEMAllocator, 0);\n\tppcDefineParamMEMPTR(heap, MEMHeapBase, 1);\n\tppcDefineParamS32(alignment, 2);\n\tcemuLog_logDebug(LogType::CoreinitMem, \"MEMInitAllocatorForExpHeap(0x{:08x}, 0x{:08x}, {})\", allocator.GetMPTR(), heap.GetMPTR(), alignment);\n\tMEMInitAllocatorForExpHeap(allocator.GetPtr(), heap.GetPtr(), alignment);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid expheap_test()\n{\n\tsrand(1000);\n\n\tMEMHeapHandle heapHandle = MEMCreateExpHeapEx(memory_getPointerFromVirtualOffset(0x11000000), 0x10000000, 0);\n\tMEMExpHeapHead2* expHeap = (MEMExpHeapHead2*)heapHandle;\n\tsint32 idx = 0;\n\n\tfor (MBlock2_t* findBlock = expHeap->expHeapHead.chainFreeBlocks.headMBlock.GetPtr(); findBlock != nullptr; findBlock = findBlock->nextBlock.GetPtr())\n\t{\n\t\tconst uintptr_t blockMemory = MBLOCK_GET_MEMORY(findBlock);\n\t\tconst uint32 dataSize = (uint32)findBlock->dataSize;\n\n\t\tdebug_printf(\">> freeBlock %04d addr %08x - %08x\\n\", idx, memory_getVirtualOffsetFromPointer((void*)blockMemory), memory_getVirtualOffsetFromPointer((void*)blockMemory) + dataSize);\n\t\tidx++;\n\t}\n\n\tvoid* allocTable[1024];\n\tsint32 allocCount = 0;\n\n\tprintf(\"Run ExpHeap test...\\n\");\n\tfor (sint32 t = 0; t < 2; t++)\n\t{\n\t\t// allocate a bunch of entries\n\t\tsint32 r = rand() % 100;\n\t\t//for (sint32 i = 0; i < r; i++)\n\t\t{\n\t\t\tif( allocCount >= 1024 )\n\t\t\t\tcontinue;\n\n\t\t\tuint32 size = (rand() % 1000) * 12;\n\t\t\tvoid* mem = MEMAllocFromExpHeapEx(heapHandle, size * 12, -0x2000);\n\t\t\tif (mem)\n\t\t\t{\n\t\t\t\tallocTable[allocCount] = mem;\n\t\t\t\tallocCount++;\n\t\t\t\t\n\t\t\t}\n\t\t}\n\t}\n\t// free everything that remains\n\tfor (sint32 i = 0; i < allocCount; i++)\n\t{\n\t\tMEMFreeToExpHeap(heapHandle, allocTable[i]);\n\t}\n\tallocCount = 0;\n\t// debug print free blocks (only one should remain)\n\texpHeap = (MEMExpHeapHead2*)heapHandle;\n\tidx = 0;\n\tfor (MBlock2_t* findBlock = expHeap->expHeapHead.chainFreeBlocks.headMBlock.GetPtr(); findBlock != nullptr; findBlock = findBlock->nextBlock.GetPtr())\n\t{\n\t\tconst uintptr_t blockMemory = MBLOCK_GET_MEMORY(findBlock);\n\t\tconst uint32 dataSize = (uint32)findBlock->dataSize;\n\n\t\tdebug_printf(\"freeBlock %04d addr %08x - %08x\\n\", idx, memory_getVirtualOffsetFromPointer((void*)blockMemory), memory_getVirtualOffsetFromPointer((void*)blockMemory) + dataSize);\n\t\tidx++;\n\t}\n\n\tassert_dbg();\n}\n\nvoid expheap_load()\n{\n\tosLib_addFunction(\"coreinit\", \"MEMCreateExpHeapEx\", export_MEMCreateExpHeapEx);\n\tosLib_addFunction(\"coreinit\", \"MEMDestroyExpHeap\", export_MEMDestroyExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMAllocFromExpHeapEx\", export_MEMAllocFromExpHeapEx);\n\tosLib_addFunction(\"coreinit\", \"MEMFreeToExpHeap\", export_MEMFreeToExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMSetAllocModeForExpHeap\", export_MEMSetAllocModeForExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMGetAllocModeForExpHeap\", export_MEMGetAllocModeForExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMAdjustExpHeap\", export_MEMAdjustExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMResizeForMBlockExpHeap\", export_MEMResizeForMBlockExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMGetTotalFreeSizeForExpHeap\", export_MEMGetTotalFreeSizeForExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMGetAllocatableSizeForExpHeapEx\", export_MEMGetAllocatableSizeForExpHeapEx);\n\tosLib_addFunction(\"coreinit\", \"MEMSetGroupIDForExpHeap\", export_MEMSetGroupIDForExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMGetGroupIDForExpHeap\", export_MEMGetGroupIDForExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMVisitAllocatedForExpHeap\", export_MEMVisitAllocatedForExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMGetSizeForMBlockExpHeap\", export_MEMGetSizeForMBlockExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMGetGroupIDForMBlockExpHeap\", export_MEMGetGroupIDForMBlockExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMGetAllocDirForMBlockExpHeap\", export_MEMGetAllocDirForMBlockExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMCheckExpHeap\", export_MEMCheckExpHeap);\n\tosLib_addFunction(\"coreinit\", \"MEMCheckForMBlockExpHeap\", export_MEMCheckForMBlockExpHeap);\n\n\tosLib_addFunction(\"coreinit\", \"MEMInitAllocatorForExpHeap\", export_MEMInitAllocatorForExpHeap);\n}\n#pragma endregion\n}\n\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.h",
    "content": "#pragma once\n\n#include \"Cafe/OS/libs/coreinit/coreinit_Spinlock.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n\nnamespace coreinit\n{\n\tvoid expheap_load();\n\n#define MEM_EXPHEAP_ALLOC_MODE_FIRST\t(0)\n#define MEM_EXPHEAP_ALLOC_MODE_NEAR\t\t(1)\n#define MEM_EXPHEAP_USE_ALIGN_MARGIN\t(2)\n\n\tenum class MEMExpHeapAllocDirection : uint32\n\t{\n\t\tHEAD = 0,\n\t\tTAIL = 1\n\t};\n\n\tstruct MBlockChain2_t\n\t{\n\t\tMEMPTR<struct MBlock2_t> headMBlock; // 0x00\n\t\tMEMPTR<struct MBlock2_t> tailMBlock; // 0x04\n\t};\n\tstatic_assert(sizeof(MBlockChain2_t) == 8);\n\n\tstruct MEMExpHeapHead40_t\n\t{\n\t\t/* +0x00 */ MBlockChain2_t chainFreeBlocks; // 0x00\n\t\t/* +0x08 */ MBlockChain2_t chainUsedBlocks; // 0x08\n\t\t/* +0x10 */ uint16 groupID;\n\t\t/* +0x12 */ uint16 fields; // Bit 0 -> Alloc mode, Bit 1 -> Allocate within alignment (create free blocks inside alignment padding)\n\t};\n\n\tstatic_assert(sizeof(MEMExpHeapHead40_t) == 0x14);\n\n\tstruct MEMExpHeapHead2 : MEMHeapBase\n\t{\n\t\t// Base\n\t\t/* +0x34 */ uint32be ukn34;\n\t\t/* +0x38 */ uint32be ukn38;\n\t\t/* +0x3C */ uint32be ukn3C;\n\t\t/* +0x40 */ MEMExpHeapHead40_t expHeapHead;\n\t};\n\n\tstatic_assert(sizeof(MEMExpHeapHead2) == 0x54);\n\n\tMEMHeapHandle MEMCreateExpHeapEx(void* startAddress, uint32 size, uint32 createFlags);\n\tvoid* MEMAllocFromExpHeapEx(MEMHeapHandle heap, uint32 size, sint32 alignment);\n\tvoid MEMFreeToExpHeap(MEMHeapHandle heap, void* mem);\n\tuint32 MEMGetAllocatableSizeForExpHeapEx(MEMHeapHandle heap, sint32 alignment);\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MEM_FrmHeap.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_FrmHeap.h\"\n\nnamespace coreinit\n{\n\tbool __FrmHeapDebug_IsValid(MEMFrmHeap* frmHeap, const char* funcName)\n\t{\n\t\tif (!frmHeap)\n\t\t{\n\t\t\tcemuLog_log(LogType::APIErrors, \"{}: Heap is nullptr\", funcName);\n\t\t\treturn false;\n\t\t}\n\t\tif (frmHeap->magic != MEMHeapMagic::FRAME_HEAP)\n\t\t{\n\t\t\tcemuLog_log(LogType::APIErrors, \"{}: Heap has bad magic. Not initialized?\", funcName);\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tMEMFrmHeap* MEMCreateFrmHeapEx(void* memStart, uint32 size, uint32 createFlags)\n\t{\n\t\tcemu_assert_debug(memStart);\n\n\t\tuintptr_t startAddr = (uintptr_t)memStart;\n\t\tuintptr_t endAddr = startAddr + size;\n\n\t\t// align and pad address\n\t\tstartAddr = (startAddr + 3) & ~3;\n\t\tendAddr &= ~3;\n\n\t\tif (startAddr == 0)\n\t\t\treturn nullptr;\n\t\tif (startAddr > endAddr || (endAddr - startAddr) < sizeof(MEMFrmHeap))\n\t\t\treturn nullptr;\n\n\t\tMEMFrmHeap* frmHeap = (MEMFrmHeap*)startAddr;\n\t\tMEMInitHeapBase(frmHeap, MEMHeapMagic::FRAME_HEAP, (void*)((uintptr_t)startAddr + sizeof(MEMFrmHeap)), (void*)endAddr, createFlags);\n\t\tfrmHeap->allocationHead = frmHeap->heapStart;\n\t\tfrmHeap->allocationTail = frmHeap->heapEnd;\n\t\tfrmHeap->recordedStates = nullptr;\n\n\t\tMEMHeapTable_Add(frmHeap);\n\t\treturn frmHeap;\n\t}\n\n\tvoid* MEMDestroyFrmHeap(MEMFrmHeap* frmHeap)\n\t{\n\t\tif (!__FrmHeapDebug_IsValid(frmHeap, \"MEMDestroyFrmHeap\"))\n\t\t\treturn nullptr;\n\t\tMEMBaseDestroyHeap(frmHeap);\n\t\tMEMHeapTable_Remove(frmHeap);\n\t\treturn frmHeap;\n\t}\n\n\tuint32 MEMGetAllocatableSizeForFrmHeapEx(MEMFrmHeap* frmHeap, sint32 alignment)\n\t{\n\t\tif (!__FrmHeapDebug_IsValid(frmHeap, \"MEMGetAllocatableSizeForFrmHeapEx\"))\n\t\t\treturn 0;\n\t\tfrmHeap->AcquireLock();\n\t\tuint32 allocatableSize = 0;\n\t\tbool negativeAlignment = alignment < 0;\n\t\tif (negativeAlignment)\n\t\t\talignment = -alignment;\n\t\tuint32 bits = (uint32)alignment;\n\t\tif (bits == 0 || (bits & (bits - 1)) != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::APIErrors, \"MEMGetAllocatableSizeForFrmHeapEx(): Invalid alignment\");\n\t\t\treturn 0;\n\t\t}\n\t\tif (negativeAlignment)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint32 headAllocator = frmHeap->allocationHead.GetMPTR();\n\t\t\tuint32 tailAllocator = frmHeap->allocationTail.GetMPTR();\n\t\t\tuint32 allocStart = (headAllocator + alignment - 1) & ~(alignment - 1);\n\t\t\tif (allocStart <= tailAllocator)\n\t\t\t{\n\t\t\t\tallocatableSize = tailAllocator - allocStart;\n\t\t\t}\n\t\t}\n\t\tfrmHeap->ReleaseLock();\n\t\treturn allocatableSize;\n\t}\n\n\tvoid* MEMiGetFreeStartForFrmHeap(MEMFrmHeap* heap)\n\t{\n\t\tif (!__FrmHeapDebug_IsValid(heap, \"MEMiGetFreeStartForFrmHeap\"))\n\t\t\treturn nullptr;\n\t\treturn heap->allocationHead;\n\t}\n\n\tvoid* MEMiGetFreeEndForFrmHeap(MEMFrmHeap* heap)\n\t{\n\t\tif (!__FrmHeapDebug_IsValid(heap, \"MEMiGetFreeEndForFrmHeap\"))\n\t\t\treturn nullptr;\n\t\treturn heap->allocationTail;\n\t}\n\n\tvoid* __FrmHeap_AllocFromHead(MEMFrmHeap* frmHeap, uint32 size, sint32 alignment)\n\t{\n\t\tuint32 head = frmHeap->allocationHead.GetMPTR();\n\t\tuint32 tail = frmHeap->allocationTail.GetMPTR();\n\t\tuint32 allocStart = (head + alignment - 1) & ~(alignment - 1);\n\t\tif ((allocStart + size) <= tail)\n\t\t{\n\t\t\tauto prevHead = frmHeap->allocationHead;\n\t\t\tfrmHeap->allocationHead = allocStart + size;\n\t\t\tif (frmHeap->HasOptionClear())\n\t\t\t\tmemset(prevHead.GetPtr(), 0, frmHeap->allocationHead.GetMPTR() - prevHead.GetMPTR());\n\t\t\treturn MEMPTR<void>(allocStart).GetPtr();\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tvoid* __FrmHeap_AllocFromTail(MEMFrmHeap* frmHeap, uint32 size, sint32 alignment)\n\t{\n\t\tuint32 head = frmHeap->allocationHead.GetMPTR();\n\t\tuint32 tail = frmHeap->allocationTail.GetMPTR();\n\t\tuint32 allocStart = (tail - size) & ~(alignment - 1);\n\t\tif (allocStart >= head)\n\t\t{\n\t\t\tauto prevTail = frmHeap->allocationTail;\n\t\t\tfrmHeap->allocationTail = allocStart;\n\t\t\tif (frmHeap->HasOptionClear())\n\t\t\t\tmemset(frmHeap->allocationTail.GetPtr(), 0, prevTail.GetMPTR() - frmHeap->allocationTail.GetMPTR());\n\t\t\treturn MEMPTR<void>(allocStart).GetPtr();\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tvoid* MEMAllocFromFrmHeapEx(MEMFrmHeap* frmHeap, uint32 size, sint32 alignment)\n\t{\n\t\tif (!__FrmHeapDebug_IsValid(frmHeap, \"MEMAllocFromFrmHeapEx\"))\n\t\t\treturn nullptr;\n\t\tif (size == 0)\n\t\t\tsize = 4;\n\t\tsize = (size + 3) & ~3; // pad to 4 byte alignment\n\t\tfrmHeap->AcquireLock();\n\t\tvoid* mem;\n\t\tif (alignment >= 0)\n\t\t\tmem = __FrmHeap_AllocFromHead(frmHeap, size, alignment);\n\t\telse\n\t\t\tmem = __FrmHeap_AllocFromTail(frmHeap, size, -alignment);\n\t\tfrmHeap->ReleaseLock();\n\t\treturn mem;\n\t}\n\n\tvoid __FrmHeap_FreeFromHead(MEMFrmHeap* frmHeap)\n\t{\n\t\tcemu_assert_debug(frmHeap->recordedStates.IsNull());\n\t\tfrmHeap->recordedStates = nullptr;\n\t\tfrmHeap->allocationHead = frmHeap->heapStart;\n\t}\n\n\tvoid __FrmHeap_FreeFromTail(MEMFrmHeap* frmHeap)\n\t{\n\t\tcemu_assert_debug(frmHeap->recordedStates.IsNull());\n\t\tfrmHeap->recordedStates = nullptr;\n\t\tvoid* heapEnd = frmHeap->heapEnd.GetPtr();\n\t\tfrmHeap->allocationTail = heapEnd;\n\t}\n\n\tvoid MEMFreeToFrmHeap(MEMFrmHeap* frmHeap, FrmHeapMode mode)\n\t{\n\t\tif (!__FrmHeapDebug_IsValid(frmHeap, \"MEMFreeToFrmHeap\"))\n\t\t\treturn;\n\t\tfrmHeap->AcquireLock();\n\n\t\tif ((mode & FrmHeapMode::Head) != 0)\n\t\t\t__FrmHeap_FreeFromHead(frmHeap);\n\n\t\tif ((mode & FrmHeapMode::Tail) != 0)\n\t\t\t__FrmHeap_FreeFromTail(frmHeap);\n\n\t\tfrmHeap->ReleaseLock();\n\t}\n\n\tbool MEMRecordStateForFrmHeap(MEMFrmHeap* frmHeap, uint32 id)\n\t{\n\t\tif (!__FrmHeapDebug_IsValid(frmHeap, \"MEMRecordStateForFrmHeap\"))\n\t\t\treturn false;\n\t\tfrmHeap->AcquireLock();\n\t\tauto allocationHead = frmHeap->allocationHead;\n\t\tauto allocationTail = frmHeap->allocationTail;\n\t\tMEMFrmHeapRecordedState* rState = (MEMFrmHeapRecordedState*)__FrmHeap_AllocFromHead(frmHeap, sizeof(MEMFrmHeapRecordedState), 4); // modifies memHeap->allocationHead\n\t\tcemu_assert_debug(rState);\n\t\tif (!rState)\n\t\t{\n\t\t\tfrmHeap->ReleaseLock();\n\t\t\treturn false;\n\t\t}\n\t\trState->id = id;\n\t\trState->allocationHead = allocationHead;\n\t\trState->allocationTail = allocationTail;\n\t\trState->prevRecordedState = frmHeap->recordedStates;\n\t\tfrmHeap->recordedStates = rState;\n\t\tfrmHeap->ReleaseLock();\n\t\treturn true;\n\t}\n\n\tbool MEMFreeByStateToFrmHeap(MEMFrmHeap* frmHeap, uint32 id)\n\t{\n\t\tif (!__FrmHeapDebug_IsValid(frmHeap, \"MEMFreeByStateToFrmHeap\"))\n\t\t\treturn false;\n\t\tfrmHeap->AcquireLock();\n\t\t// find matching state\n\t\tMEMFrmHeapRecordedState* rState = frmHeap->recordedStates.GetPtr();\n\t\twhile (rState)\n\t\t{\n\t\t\tif (id == 0)\n\t\t\t\tbreak;\n\t\t\tif (rState->id == id)\n\t\t\t\tbreak;\n\t\t\trState = rState->prevRecordedState.GetPtr();\n\t\t}\n\t\tif (!rState)\n\t\t{\n\t\t\tfrmHeap->ReleaseLock();\n\t\t\treturn false;\n\t\t}\n\t\t// apply state\n\t\tfrmHeap->allocationHead = rState->allocationHead;\n\t\tfrmHeap->allocationTail = rState->allocationTail;\n\t\tfrmHeap->recordedStates = rState->prevRecordedState;\n\t\tfrmHeap->ReleaseLock();\n\t\treturn true;\n\t}\n\n\tvoid InitializeMEMFrmHeap()\n\t{\n\t\tcafeExportRegister(\"coreinit\", MEMCreateFrmHeapEx, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMDestroyFrmHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMGetAllocatableSizeForFrmHeapEx, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMiGetFreeStartForFrmHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMiGetFreeEndForFrmHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMAllocFromFrmHeapEx, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMFreeToFrmHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMFreeToFrmHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMRecordStateForFrmHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMFreeByStateToFrmHeap, LogType::CoreinitMem);\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MEM_FrmHeap.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n\nnamespace coreinit\n{\n\tstruct MEMFrmHeapRecordedState\n\t{\n\t\tuint32be id;\n\t\tMEMPTR<void> allocationHead;\n\t\tMEMPTR<void> allocationTail;\n\t\tMEMPTR<MEMFrmHeapRecordedState> prevRecordedState;\n\t};\n\tstatic_assert(sizeof(MEMFrmHeapRecordedState) == 0x10);\n\n\tstruct MEMFrmHeap : MEMHeapBase\n\t{\n\t\t/* +0x34 */ uint32be ukn34;\n\t\t/* +0x38 */ uint32be ukn38;\n\t\t/* +0x3C */ uint32be ukn3C;\n\t\t/* +0x40 */ MEMPTR<void> allocationHead;\n\t\t/* +0x44 */ MEMPTR<void> allocationTail;\n\t\t/* +0x48 */ MEMPTR<MEMFrmHeapRecordedState> recordedStates;\n\t};\n\tstatic_assert(sizeof(MEMFrmHeap) == 0x4C);\n\n\tenum class FrmHeapMode : uint32\n\t{\n\t\tHead = (1 << 0),\n\t\tTail = (1 << 1),\n\t\tAll = (Head | Tail),\n\t};\n\n\tMEMFrmHeap* MEMCreateFrmHeapEx(void* memStart, uint32 size, uint32 createFlags);\n\tvoid* MEMDestroyFrmHeap(MEMFrmHeap* frmHeap);\n\n\tvoid* MEMAllocFromFrmHeapEx(MEMFrmHeap* frmHeap, uint32 size, sint32 alignment);\n\tvoid MEMFreeToFrmHeap(MEMFrmHeap* frmHeap, FrmHeapMode mode);\n\n\tvoid InitializeMEMFrmHeap();\n}\nENABLE_BITMASK_OPERATORS(coreinit::FrmHeapMode);"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MEM_UnitHeap.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_UnitHeap.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Spinlock.h\"\n\nnamespace coreinit\n{\n\tvoid _MEMUnitHeap_IsValidHeap(MEMHeapHandle heap)\n\t{\n\t\tcemu_assert(heap != MEM_HEAP_INVALID_HANDLE);\n\t\tcemu_assert(heap->magic == MEMHeapMagic::UNIT_HEAP);\n\t}\n\n\tMEMHeapBase* MEMCreateUnitHeapEx(void* memStart, uint32 heapSize, uint32 blockSize, uint32 alignment, uint32 createFlags)\n\t{\n\t\tcemu_assert_debug(memStart != nullptr);\n\t\tcemu_assert_debug(alignment % MIN_ALIGNMENT == 0);\n\t\tcemu_assert_debug(MIN_ALIGNMENT <= alignment && alignment <= 32);\n\n\t\tuintptr_t startAddr = (uintptr_t)memStart;\n\t\tuintptr_t endAddr = startAddr + heapSize;\n\n\t\tstartAddr = (startAddr + MIN_ALIGNMENT_MINUS_ONE) & (~MIN_ALIGNMENT_MINUS_ONE);\n\t\tendAddr &= (~MIN_ALIGNMENT_MINUS_ONE);\n\n\t\tif (startAddr > endAddr)\n\t\t\treturn nullptr;\n\n\t\tconst uint32 alignmentMinusOne = alignment - 1;\n\n\t\tMEMUnitHeap* unitHeap = (MEMUnitHeap*)startAddr;\n\t\tuintptr_t alignedStart = startAddr + sizeof(MEMUnitHeap) + alignmentMinusOne & ~((uintptr_t)alignmentMinusOne);\n\t\tif (alignedStart > endAddr)\n\t\t\treturn nullptr;\n\n\t\tblockSize = blockSize + alignmentMinusOne & ~alignmentMinusOne;\n\t\tuint32 totalBlockSize = (uint32)(endAddr - alignedStart);\n\t\tuint32 numBlocks = totalBlockSize / blockSize;\n\t\tif (numBlocks == 0)\n\t\t\treturn nullptr;\n\n\t\tMEMInitHeapBase(unitHeap, MEMHeapMagic::UNIT_HEAP, (void*)alignedStart, (void*)(alignedStart + (numBlocks * blockSize)), createFlags);\n\n\t\tunitHeap->firstFreeBlock = (MEMUnitHeapBlock*)alignedStart;\n\t\tunitHeap->blockSize = blockSize;\n\n\t\tMEMUnitHeapBlock* currentBlock = (MEMUnitHeapBlock*)alignedStart;\n\t\tfor (uint32 i = 0; i < numBlocks - 1; ++i)\n\t\t{\n\t\t\tMEMUnitHeapBlock* nextBlock = (MEMUnitHeapBlock*)((uintptr_t)currentBlock + blockSize);\n\t\t\tcurrentBlock->nextBlock = nextBlock;\n\t\t\tcurrentBlock = nextBlock;\n\t\t}\n\n\t\tcurrentBlock->nextBlock = nullptr;\n\n\t\tif ((MEMHeapHandle*)startAddr != nullptr)\n\t\t{\n\t\t\tMEMHeapTable_Add((MEMHeapHandle)startAddr);\n\t\t}\n\n\t\treturn (MEMHeapBase*)startAddr;\n\t}\n\n\tvoid* MEMDestroyUnitHeap(MEMHeapHandle heap)\n\t{\n\t\t_MEMUnitHeap_IsValidHeap(heap);\n\t\tMEMBaseDestroyHeap(heap);\n\t\tMEMHeapTable_Remove(heap);\n\t\treturn heap;\n\t}\n\n\tuint32 MEMCalcHeapSizeForUnitHeap(uint32 blockSize, uint32 blockCount, uint32 alignment)\n\t{\n\t\tuint32 alignedBlockSize = (blockSize + (alignment - 1)) & ~(alignment - 1);\n\t\tuint32 blockTotalSize = blockCount * alignedBlockSize;\n\t\tuint32 heapSize = blockTotalSize + (alignment - 4) + sizeof(MEMUnitHeap);\n\t\treturn heapSize;\n\t}\n\n\tuint32 MEMCountFreeBlockForUnitHeap(coreinit::MEMUnitHeap* heap)\n\t{\n\t\t_MEMUnitHeap_IsValidHeap(heap);\n\t\theap->AcquireLock();\n\t\tMEMUnitHeapBlock* currentBlock = heap->firstFreeBlock;\n\t\tuint32 blockCount = 0;\n\t\twhile (currentBlock)\n\t\t{\n\t\t\tblockCount++;\n\t\t\tcurrentBlock = currentBlock->nextBlock;\n\t\t}\n\t\theap->ReleaseLock();\n\t\treturn blockCount;\n\t}\n\n\tvoid* MEMAllocFromUnitHeap(MEMUnitHeap* heap)\n\t{\n\t\t_MEMUnitHeap_IsValidHeap(heap);\n\t\theap->AcquireLock();\n\t\tMEMUnitHeapBlock* currentBlock = heap->firstFreeBlock;\n\t\tif (!currentBlock)\n\t\t{\n\t\t\theap->ReleaseLock();\n\t\t\treturn nullptr;\n\t\t}\n\t\t// remove from list of free blocks\n\t\theap->firstFreeBlock = currentBlock->nextBlock;\n\t\t// fill block\n\t\tif (heap->HasOptionClear())\n\t\t{\n\t\t\tmemset(currentBlock, 0, heap->blockSize);\n\t\t}\n\t\telse if (heap->HasOptionFill())\n\t\t{\n\t\t\tmemset(currentBlock, coreinit::MEMGetFillValForHeap(coreinit::HEAP_FILL_TYPE::ON_ALLOC), heap->blockSize);\n\t\t}\n\t\theap->ReleaseLock();\n\t\treturn currentBlock;\n\t}\n\n\tvoid MEMFreeToUnitHeap(MEMUnitHeap* heap, void* mem)\n\t{\n\t\t_MEMUnitHeap_IsValidHeap(heap);\n\t\tif (!mem)\n\t\t\treturn;\n\t\theap->AcquireLock();\n\t\tcemu_assert_debug(mem >= heap->heapStart.GetPtr() && mem < heap->heapEnd.GetPtr());\n\t\t// add to list of free blocks\n\t\tMEMUnitHeapBlock* releasedBlock = (MEMUnitHeapBlock*)mem;\n\t\treleasedBlock->nextBlock = heap->firstFreeBlock;\n\t\theap->firstFreeBlock = releasedBlock;\n\t\tif (heap->HasOptionFill())\n\t\t\tmemset(releasedBlock, coreinit::MEMGetFillValForHeap(coreinit::HEAP_FILL_TYPE::ON_FREE), heap->blockSize);\n\t\theap->ReleaseLock();\n\t}\n\n\tvoid InitializeMEMUnitHeap()\n\t{\n\t\tcafeExportRegister(\"coreinit\", MEMCreateUnitHeapEx, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMDestroyUnitHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMCalcHeapSizeForUnitHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMCountFreeBlockForUnitHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMAllocFromUnitHeap, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"coreinit\", MEMFreeToUnitHeap, LogType::CoreinitMem);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MEM_UnitHeap.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n\nnamespace coreinit\n{\n\tstruct MEMUnitHeapBlock\n\t{\n\t\tMEMPTR<MEMUnitHeapBlock> nextBlock;\n\t};\n\tstatic_assert(sizeof(MEMUnitHeapBlock) == 4);\n\n\tstruct MEMUnitHeap : public MEMHeapBase\n\t{\n\t\t/* +0x34 */ uint32 padding034;\n\t\t/* +0x38 */ uint32 padding038;\n\t\t/* +0x3C */ uint32 padding03C;\n\t\t/* +0x40 */ MEMPTR<MEMUnitHeapBlock> firstFreeBlock;\n\t\t/* +0x44 */ uint32be blockSize;\n\t};\n\tstatic_assert(sizeof(MEMUnitHeap) == 0x48);\n\n\tMEMHeapBase* MEMCreateUnitHeapEx(void* memStart, uint32 heapSize, uint32 memBlockSize, uint32 alignment, uint32 createFlags);\n\tvoid* MEMDestroyUnitHeap(MEMHeapHandle hHeap);\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MPQueue.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MPQueue.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"util/helpers/fspinlock.h\"\n\n// titles that utilize MP task queue: Yoshi's Woolly World, Fast Racing Neo, Tokyo Mirage Sessions, Mii Maker\n\n#define AcquireMPQLock() s_workaroundSpinlock.lock()\n#define ReleaseMPQLock() s_workaroundSpinlock.unlock()\n\nnamespace coreinit\n{\n\n\tFSpinlock s_workaroundSpinlock; // workaround for a race condition\n\t/*\n\t\tRace condition pseudo-code:\n\n\t\tWorkerThreads:\n    \t\twhile( task = MPDequeTask() ) MPRunTask(task);\n\t\n\t\tMainThread:\n\t\t\tQueueTasks();\n\t\t\t// wait and reset\n\t\t\tMPWaitForTaskQWithTimeout(DONE)\n\t\t\tMPTermTaskQ()\n\t\t\tMPInitTaskQ()\n\t\n\t\tThe race condition then happens when a worker thread calls MPDequeTask()/MPRunTask while MPInitTaskQ() is being executed on the main thread.\n\t\tSince MPInitTaskQ() (re)initializes the internal spinlock it's not thread-safe, leading to a corruption of the spinlock state for other threads\n\n\t\tWe work around this by using a global spinlock instead of the taskQ specific one\n\t*/\n\n\n\tvoid MPInitTask(MPTask* task, void* func, void* data, uint32 size)\n\t{\n\t\ts_workaroundSpinlock.lock();\n\t\ttask->thisptr = task;\n\t\t\n\t\ttask->coreIndex = PPC_CORE_COUNT;\n\t\t\n\t\ttask->taskFunc.func = func;\n\t\ttask->taskFunc.data = data;\n\t\ttask->taskFunc.size = size;\n\t\t\n\t\ttask->taskState = MP_TASK_STATE_INIT;\n\t\t\n\t\ttask->userdata = nullptr;\n\t\ttask->runtime = 0;\n\t\ts_workaroundSpinlock.unlock();\n\t}\n\n\tbool MPTermTask(MPTask* task)\n\t{\n\t\treturn true;\n\t}\n\n\tbool MPRunTask(MPTask* task)\n\t{\n\t\tif (task->taskState != MP_TASK_STATE_READY)\n\t\t\treturn false;\n\n\t\tauto* taskQ = task->taskQ.GetPtr();\n\n\t\tif(taskQ->state != MP_TASKQ_STATE_STOPPING && taskQ->state != MP_TASKQ_STATE_STOP)\n\t\t{\n\t\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskQ->spinlock);\n\t\t\tif (taskQ->state == MP_TASKQ_STATE_STOPPING || taskQ->state == MP_TASKQ_STATE_STOP)\n\t\t\t{\n\t\t\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskQ->spinlock);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttaskQ->taskReadyCount = taskQ->taskReadyCount - 1;\n\t\t\ttaskQ->taskRunCount = taskQ->taskRunCount + 1;\n\t\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskQ->spinlock);\n\n\t\t\tconst auto startTime = OSGetSystemTime();\n\t\t\t\n\t\t\ttask->coreIndex = OSGetCoreId();\n\t\t\ttask->taskState = MP_TASK_STATE_RUN;\n\t\t\t\n\t\t\ttask->taskFunc.result = PPCCoreCallback(task->taskFunc.func, task->taskFunc.data, task->taskFunc.size);\n\n\t\t\ttask->taskState = MP_TASK_STATE_DONE;\n\n\t\t\tconst auto endTime = OSGetSystemTime();\n\t\t\ttask->runtime = endTime - startTime;\n\n\t\t\tcemu_assert_debug(taskQ->state != MP_TASKQ_STATE_DONE);\n\n\t\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskQ->spinlock);\n\t\t\ttaskQ->taskRunCount = taskQ->taskRunCount - 1;\n\t\t\ttaskQ->taskDoneCount[1] = taskQ->taskDoneCount[1] + 1;\n\t\t\tif (taskQ->state == MP_TASKQ_STATE_STOPPING && taskQ->taskRunCount == 0)\n\t\t\t\ttaskQ->state = MP_TASKQ_STATE_STOP;\n\n\t\t\tif (taskQ->taskCount == taskQ->taskDoneCount[1])\n\t\t\t\ttaskQ->state = MP_TASKQ_STATE_DONE;\n\t\t\t\n\t\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskQ->spinlock);\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tbool MPGetTaskInfo(MPTask* task, MPTaskInfo* info)\n\t{\n\t\tinfo->state = task->taskState;\n\t\tinfo->coreIndex = task->coreIndex;\n\t\tinfo->runtime = task->runtime;\n\t\t// not setting function result?\n\t\treturn true;\n\t}\n\n\tvoid* MPGetTaskUserData(MPTask* task)\n\t{\n\t\treturn task->userdata.GetPtr();\n\t}\n\n\tvoid MPSetTaskUserData(MPTask* task, void* userdata)\n\t{\n\t\ttask->userdata = userdata;\n\t}\n\n\tvoid MPInitTaskQ(MPTaskQ* taskQ, MPTask** tasks, uint32 taskCount)\n\t{\n\t\tAcquireMPQLock();\n\t\ttaskQ->thisptr = taskQ;\n\t\tOSInitSpinLock(&taskQ->spinlock);\n\t\ttaskQ->state = MP_TASKQ_STATE_INIT;\n\t\ttaskQ->taskReadyCount = 0;\n\t\ttaskQ->taskCount = 0;\n\t\ttaskQ->taskRunCount = 0;\n\t\tfor(uint32 i = 0; i < OSGetCoreCount(); ++i)\n\t\t{\n\t\t\ttaskQ->taskDoneCount[i] = 0;\n\t\t\ttaskQ->nextIndex[i] = 0;\n\t\t\ttaskQ->endIndex[i] = 0;\n\t\t}\n\n\t\ttaskQ->taskQueue = (MEMPTR<MPTask>*)tasks;\n\t\ttaskQ->taskQueueSize = taskCount;\n\n\t\tReleaseMPQLock();\n\t}\n\n\tbool MPEnqueTask(MPTaskQ* taskq, MPTask* task)\n\t{\n\t\tbool result = false;\n\t\tif(task->taskState == MP_TASK_STATE_INIT)\n\t\t{\n\t\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\n\t\t\tconst uint32 taskQState = taskq->state;\n\t\t\tif((uint32)taskq->endIndex[1] < taskq->taskQueueSize \n\t\t\t\t&& (taskQState == MP_TASKQ_STATE_INIT || taskQState == MP_TASKQ_STATE_RUN || taskQState == MP_TASKQ_STATE_STOPPING || taskQState == MP_TASKQ_STATE_STOP || taskQState == MP_TASKQ_STATE_DONE))\n\t\t\t{\n\t\t\t\ttask->taskQ = taskq;\n\t\t\t\ttask->taskState = MP_TASK_STATE_READY;\n\t\t\t\t\n\t\t\t\ttaskq->thisptr = taskq;\n\t\t\t\t\n\t\t\t\tconst uint32 endIndex = taskq->endIndex[1];\n\t\t\t\ttaskq->endIndex[1] = endIndex + 1;\n\t\t\t\t\n\t\t\t\ttaskq->taskCount = taskq->taskCount + 1;\n\t\t\t\ttaskq->taskReadyCount = taskq->taskReadyCount + 1;\n\t\t\t\ttaskq->taskQueue[endIndex] = task;\n\n\t\t\t\tif (taskQState == MP_TASKQ_STATE_DONE)\n\t\t\t\t\ttaskq->state = MP_TASKQ_STATE_RUN;\n\n\t\t\t\tresult = true;\n\t\t\t}\n\t\t\t\n\t\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tbool MPTermTaskQ(MPTaskQ* taskq)\n\t{\n\t\t// workaround code for TMS\n\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\t\t//if ((uint32)taskq->taskReadyCount > 0 && taskq->state == MP_TASKQ_STATE_RUN)\n\t\tif (taskq->state == MP_TASKQ_STATE_RUN)\n\t\t{\n\t\t\ttaskq->state = MP_TASKQ_STATE_STOP;\n\t\t}\n\n\t\twhile (taskq->taskRunCount != 0)\n\t\t{\n\t\t\t// wait for tasks to finish\n\t\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\t\tOSYieldThread();\n\t\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\t\t}\n\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\treturn true;\n\t}\n\n\tbool MPGetTaskQInfo(MPTaskQ* taskq, MPTaskQInfo* info)\n\t{\n\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\t\tinfo->state = taskq->state;\n\t\tinfo->taskCount = taskq->taskCount;\n\t\tinfo->taskReadyCount = taskq->taskReadyCount;\n\t\tinfo->taskRunCount = taskq->taskRunCount;\n\t\tinfo->taskDoneCount = taskq->taskDoneCount[1];\n\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\treturn true;\n\t}\n\n\tbool MPStartTaskQ(MPTaskQ* taskq)\n\t{\n\t\tbool result = false;\n\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\t\tif (taskq->state == MP_TASKQ_STATE_INIT || taskq->state == MP_TASKQ_STATE_STOP)\n\t\t{\n\t\t\ttaskq->state = MP_TASKQ_STATE_RUN;\n\t\t\tresult = true;\n\t\t}\n\t\t\n\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\treturn result;\n\t}\n\n\tbool MPRunTasksFromTaskQ(MPTaskQ* taskq, int granularity)\n\t{\n\t\tuint32 result = 0;\n\t\twhile (true)\n\t\t{\n\t\t\tif (taskq->state != MP_TASKQ_STATE_RUN)\n\t\t\t\treturn (taskq->state & MP_TASKQ_STATE_DONE) != 0;\n\n\t\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\t\t\tconst auto nextIndex = taskq->nextIndex[1];\n\t\t\tconst auto endIndex = taskq->endIndex[1];\n\t\t\tif (nextIndex == endIndex) \n\t\t\t\tbreak;\n\n\t\t\tauto newNextIndex = nextIndex + granularity;\n\t\t\tif (endIndex < nextIndex + granularity) \n\t\t\t\tnewNextIndex = endIndex;\n\n\t\t\tconst auto workCount = (newNextIndex - nextIndex);\n\t\t\t\n\t\t\ttaskq->nextIndex[1] = newNextIndex;\n\t\t\ttaskq->taskReadyCount = taskq->taskReadyCount - workCount;\n\t\t\ttaskq->taskRunCount = taskq->taskRunCount + workCount;\n\t\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\n\t\t\t// since we are having a granularity parameter, we might want to give the scheduler the chance for other stuff when having multiple tasks\n\t\t\tif(result != 0)\n\t\t\t\tPPCCore_switchToScheduler();\n\n\t\t\tfor (int i = nextIndex; i < newNextIndex; ++i)\n\t\t\t{\n\t\t\t\tconst auto startTime = OSGetSystemTime();\n\t\t\t\t\n\t\t\t\tconst auto& task = taskq->taskQueue[i];\n\t\t\t\tresult = task->thisptr.GetMPTR();\n\t\t\t\t\n\t\t\t\ttask->taskState = MP_TASK_STATE_RUN;\n\t\t\t\ttask->coreIndex = OSGetCoreId();\n\t\t\t\t\n\t\t\t\ttask->taskFunc.result = PPCCoreCallback(task->taskFunc.func, task->taskFunc.data, task->taskFunc.size);\n\n\t\t\t\ttask->taskState = MP_TASK_STATE_DONE;\n\n\t\t\t\tconst auto endTime = OSGetSystemTime();\n\t\t\t\ttask->runtime = endTime - startTime;\n\t\t\t}\n\n\t\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\t\t\tconst auto runRemaining = taskq->taskRunCount - workCount;\n\t\t\ttaskq->taskRunCount = runRemaining;\n\t\t\t\n\t\t\tconst auto doneCount = taskq->taskDoneCount[1] + workCount;\n\t\t\ttaskq->taskDoneCount[1] = doneCount;\n\t\t\t\n\t\t\tif (taskq->state == 4 && runRemaining == 0) \n\t\t\t\ttaskq->state = MP_TASKQ_STATE_STOP;\n\t\t\t\n\t\t\tif (taskq->taskCount == doneCount) \n\t\t\t\ttaskq->state = MP_TASKQ_STATE_DONE;\n\t\t\t\n\t\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\t}\n\n\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\treturn result != 0;\n\t}\n\n\tbool MPStopTaskQ(MPTaskQ* taskq)\n\t{\n\t\tbool result = false;\n\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\t\tif (taskq->state == MP_TASKQ_STATE_RUN) \n\t\t{\n\t\t\ttaskq->state = MP_TASKQ_STATE_STOPPING;\n\t\t\tif (taskq->taskRunCount == 0) \n\t\t\t\ttaskq->state = MP_TASKQ_STATE_STOP;\n\t\t\t\t\t\t\n\t\t\tresult = true;\n\t\t}\n\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\treturn result;\n\t}\n\n\tbool MPWaitTaskQ(MPTaskQ* taskQ, uint32 waitState)\n\t{\n\t\tbool waitRun = (waitState & MP_TASKQ_STATE_RUN) != 0;\n\t\tbool waitStop = (waitState & MP_TASKQ_STATE_STOP) != 0;\n\t\tbool waitDone = (waitState & MP_TASKQ_STATE_DONE) != 0;\n\t\t\n\t\tsize_t loopCounter = 0;\n\t\twhile (waitStop || waitDone || waitRun)\n\t\t{\n\t\t\tconst uint32 state = taskQ->state;\n\t\t\tif (waitRun && HAS_FLAG(state, MP_TASKQ_STATE_RUN))\n\t\t\t{\n\t\t\t\twaitRun = false;\n\t\t\t\twaitDone = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tif (waitStop && HAS_FLAG(state, MP_TASKQ_STATE_STOP))\n\t\t\t{\n\t\t\t\twaitStop = false;\n\t\t\t\twaitDone = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\tif (waitDone && HAS_FLAG(state, MP_TASKQ_STATE_DONE))\n\t\t\t{\n\t\t\t\twaitDone = false;\n\t\t\t\twaitRun = false;\n\t\t\t\twaitStop = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (loopCounter > 0)\n\t\t\t\tcoreinit::OSSleepTicks(EspressoTime::ConvertNsToTimerTicks(50000)); // sleep thread for 0.05ms to give other threads a chance to run (avoids softlocks in YWW)\n\t\t\telse\n\t\t\t\tPPCCore_switchToScheduler();\n\t\t\tloopCounter++;\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tbool MPWaitTaskQWithTimeout(MPTaskQ* taskQ, uint32 waitState, sint64 timeout)\n\t{\n\t\tbool waitRun = (waitState & MP_TASKQ_STATE_RUN) != 0;\n\t\tbool waitStop = (waitState & MP_TASKQ_STATE_STOP) != 0;\n\t\tbool waitDone = (waitState & MP_TASKQ_STATE_DONE) != 0;\n\n\t\tconst auto startTime = OSGetSystemTime();\n\t\tconst auto timerTicks = EspressoTime::ConvertNsToTimerTicks(timeout);\n\t\tconst auto endTime = startTime + timerTicks;\n\n\t\twhile (waitStop || waitDone || waitRun)\n\t\t{\n\t\t\tconst uint32 state = taskQ->state;\n\t\t\tif (waitRun && HAS_FLAG(state, MP_TASKQ_STATE_RUN))\n\t\t\t{\n\t\t\t\twaitRun = false;\n\t\t\t\twaitDone = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (waitStop && HAS_FLAG(state, MP_TASKQ_STATE_STOP))\n\t\t\t{\n\t\t\t\twaitStop = false;\n\t\t\t\twaitDone = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (waitDone && HAS_FLAG(state, MP_TASKQ_STATE_DONE))\n\t\t\t{\n\t\t\t\twaitDone = false;\n\t\t\t\twaitRun = false;\n\t\t\t\twaitStop = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (OSGetSystemTime() >= endTime)\n\t\t\t{\n\t\t\t\tif (waitState == MP_TASKQ_STATE_DONE)\n\t\t\t\t\tcemuLog_log(LogType::Force, \"MPWaitTaskQWithTimeout(): Timeout occurred while waiting for done-only state\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tPPCCore_switchToScheduler();\n\t\t}\n\t\treturn true;\n\t}\n\n\tMPTask* MPDequeTask(MPTaskQ* taskq)\n\t{\n\t\tMPTask* result = nullptr;\n\t\tif (taskq->state == MP_TASKQ_STATE_RUN) \n\t\t{\n\t\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\t\t\tif (taskq->state == MP_TASKQ_STATE_RUN && taskq->nextIndex[1] != taskq->endIndex[1])\n\t\t\t{\n\t\t\t\tresult = taskq->taskQueue[taskq->nextIndex[1]].GetPtr();\n\t\t\t\ttaskq->nextIndex[1] = taskq->nextIndex[1] + 1;\n\t\t\t}\n\t\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\t}\n\t\treturn result;\n\t}\n\n\tuint32 MPDequeTasks(MPTaskQ* taskq, MPTask** tasks, sint32 maxTasks)\n\t{\n\t\tuint32 dequeCount = 0;\n\t\tif (taskq->state == MP_TASKQ_STATE_RUN)\n\t\t{\n\t\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\t\t\tif (taskq->state == MP_TASKQ_STATE_RUN) \n\t\t\t{\n\t\t\t\tauto nextIndex = (sint32)taskq->nextIndex[1];\n\t\t\t\tauto newEndIndex = nextIndex + maxTasks;\n\t\t\t\tif (taskq->endIndex[1] < nextIndex + maxTasks) \n\t\t\t\t\tnewEndIndex = taskq->endIndex[1];\n\t\t\t\t\n\t\t\t\tdequeCount = newEndIndex - nextIndex;\n\t\t\t\ttaskq->nextIndex[1] = newEndIndex;\n\n\t\t\t\tfor(int i = 0; nextIndex < newEndIndex; ++nextIndex, ++i)\n\t\t\t\t{\n\t\t\t\t\ttasks[i] = taskq->taskQueue[nextIndex].GetPtr();\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tauto idx = 0;\n\t\t\t\twhile (nextIndex < newEndIndex) \n\t\t\t\t{\n\t\t\t\t\ttasks[idx] = taskq->taskQueue[nextIndex].GetPtr();\n\t\t\t\t\tnextIndex = nextIndex + 1;\n\t\t\t\t\tidx = idx + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\t}\n\t\treturn dequeCount;\n\t}\n\n\tbool MPResetTaskQ(MPTaskQ* taskq)\n\t{\n\t\tdebug_printf(\"MPResetTaskQ called\\n\");\n\t\tbool result = false;\n\t\tAcquireMPQLock(); // OSUninterruptibleSpinLock_Acquire(&taskq->spinlock);\n\t\tif (taskq->state == MP_TASKQ_STATE_DONE || taskq->state == MP_TASKQ_STATE_STOP) \n\t\t{\n\t\t\ttaskq->state = MP_TASKQ_STATE_INIT;\n\t\t\ttaskq->taskRunCount = 0;\n\t\t\ttaskq->taskCount = taskq->endIndex[1];\n\t\t\ttaskq->taskReadyCount = taskq->endIndex[1];\n\t\t\t\n\t\t\tfor(uint32 i = 0; i < OSGetCoreCount(); ++i)\n\t\t\t{\n\t\t\t\ttaskq->taskDoneCount[i] = 0;\n\t\t\t\ttaskq->nextIndex[i] = 0;\n\t\t\t}\n\t\t\t\n\t\t\tfor(uint32 i = 0; i < taskq->taskCount; ++i)\n\t\t\t{\n\t\t\t\tconst auto& task = taskq->taskQueue[i];\n\t\t\t\ttask->taskFunc.result = 0;\n\t\t\t\t\n\t\t\t\ttask->coreIndex = PPC_CORE_COUNT;\n\t\t\t\ttask->runtime = 0;\n\t\t\t\ttask->taskState = MP_TASK_STATE_READY;\n\t\t\t}\n\n\t\t\tresult = true;\n\t\t}\n\t\t\n\t\tReleaseMPQLock(); // OSUninterruptibleSpinLock_Release(&taskq->spinlock);\n\t\treturn result;\n\t}\n\n\tvoid InitializeMP()\n\t{\n\t\t// task\n\t\tcafeExportRegister(\"coreinit\", MPInitTask, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPTermTask, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPRunTask, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPGetTaskInfo, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPGetTaskUserData, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPSetTaskUserData, LogType::CoreinitMP);\n\n\t\t// taskq\n\t\tcafeExportRegister(\"coreinit\", MPInitTaskQ, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPResetTaskQ, LogType::CoreinitMP);\n\t\t\n\t\tcafeExportRegister(\"coreinit\", MPEnqueTask, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPDequeTask, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPDequeTasks, LogType::CoreinitMP);\n\n\t\tcafeExportRegister(\"coreinit\", MPRunTasksFromTaskQ, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPStartTaskQ, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPWaitTaskQ, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPWaitTaskQWithTimeout, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPStopTaskQ, LogType::CoreinitMP);\n\t\t\n\t\tcafeExportRegister(\"coreinit\", MPTermTaskQ, LogType::CoreinitMP);\n\t\tcafeExportRegister(\"coreinit\", MPGetTaskQInfo, LogType::CoreinitMP);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MPQueue.h",
    "content": "#pragma once\n\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Spinlock.h\"\n\nnamespace coreinit\n{\n\tenum MPTaskState\n\t{\n\t\tMP_TASK_STATE_INIT = (1 << 0),\n\t\tMP_TASK_STATE_READY = (1 << 1),\n\t\tMP_TASK_STATE_RUN = (1 << 2),\n\t\tMP_TASK_STATE_DONE = (1 << 3)\n\t};\n\n\tenum MPTaskQState\n\t{\n\t\tMP_TASKQ_STATE_INIT = (1 << 0),\n\t\tMP_TASKQ_STATE_RUN = (1 << 1),\n\t\tMP_TASKQ_STATE_STOPPING = (1 << 2),\n\t\tMP_TASKQ_STATE_STOP = (1 << 3),\n\t\tMP_TASKQ_STATE_DONE = (1 << 4)\n\t};\n\n\tstruct MPTaskFunction\n\t{\n\t\t/* +0x00 */ MEMPTR<void> func;\n\t\t/* +0x04 */ MEMPTR<void> data;\n\t\t/* +0x08 */ uint32be size;\n\t\t/* +0x0C */ uint32be result;\n\t};\n\tstatic_assert(sizeof(MPTaskFunction) == 0x10);\n\n#pragma pack(1)\n\n\tstruct MPTask\n\t{\n\t\t/* +0x00 */ MEMPTR<void> thisptr;\n\t\t/* +0x04 */ MEMPTR<struct MPTaskQ> taskQ;\n\t\t/* +0x08 */ uint32be taskState;\n\t\t/* +0x0C */ MPTaskFunction taskFunc;\n\t\t/* +0x1C */ uint32be coreIndex;\n\t\t/* +0x20 */ sint64be runtime;\n\t\t/* +0x28 */ MEMPTR<void> userdata;\n\t};\n\tstatic_assert(sizeof(MPTask) == 0x2C);\n\t\n#pragma pack()\n\n\tstruct MPTaskQ\n\t{\n\t\t/* +0x00 */ MEMPTR<void> thisptr;\n\t\t/* +0x04 */ uint32be state;\n\t\t/* +0x08 */ uint32be taskCount;\n\t\t/* +0x0C */ uint32be taskReadyCount;\n\t\t/* +0x10 */ uint32be taskRunCount;\n\t\t/* +0x14 */ uint32be taskDoneCount[PPC_CORE_COUNT];\n\t\t/* +0x20 */ sint32be nextIndex[PPC_CORE_COUNT];\n\t\t/* +0x2C */ sint32be endIndex[PPC_CORE_COUNT];\n\t\t/* +0x38 */ MEMPTR<MEMPTR<MPTask>> taskQueue;\n\t\t/* +0x3C */ uint32be taskQueueSize;\n\t\t/* +0x40 */\tOSSpinLock spinlock;\n\t};\n\tstatic_assert(sizeof(MPTaskQ) == 0x50);\n\t\n\tstruct MPTaskQInfo\n\t{\n\t\t/* +0x00 */ uint32be state;\n\t\t/* +0x04 */ uint32be taskCount;\n\t\t/* +0x08 */ uint32be taskReadyCount;\n\t\t/* +0x0C */ uint32be taskRunCount;\n\t\t/* +0x10 */ uint32be taskDoneCount;\n\t};\n\tstatic_assert(sizeof(MPTaskQInfo) == 0x14);\n\t\n\tstruct MPTaskInfo\n\t{\n\t\t/* +0x00 */ uint32be state;\n\t\t/* +0x04 */ uint32be funcResult;\n\t\t/* +0x08 */ uint32be coreIndex;\n\t\t/* +0x0C */ sint64be runtime;\n\t};\n\tstatic_assert(sizeof(MPTaskQInfo) == 0x14);\n\n\tvoid MPInitTask(MPTask* task, void* func, void* data, uint32 size);\n\tbool MPTermTask(MPTask* task);\n\tbool MPRunTask(MPTask* task);\n\tbool MPGetTaskInfo(MPTask* task, MPTaskInfo* info);\n\tvoid* MPGetTaskUserData(MPTask* task);\n\tvoid MPSetTaskUserData(MPTask* task, void* userdata);\n\n\tvoid MPInitTaskQ(MPTaskQ* taskq, MPTask** tasks, uint32 taskCount);\n\tbool MPEnqueTask(MPTaskQ* taskq, MPTask* task);\n\tbool MPTermTaskQ(MPTaskQ* taskq);\n\tbool MPGetTaskQInfo(MPTaskQ* taskq, MPTaskQInfo* info);\n\tbool MPStartTaskQ(MPTaskQ* taskq);\n\tbool MPRunTasksFromTaskQ(MPTaskQ* taskq, int granularity);\n\tbool MPStopTaskQ(MPTaskQ* taskq);\n\tbool MPWaitTaskQ(MPTaskQ* taskq, uint32 waitState);\n\tbool MPWaitTaskQWithTimeout(MPTaskQ* taskq, uint32 waitState, sint64 timeout);\n\tMPTask* MPDequeTask(MPTaskQ* taskq);\n\tuint32 MPDequeTasks(MPTaskQ* taskq, MPTask** tasks, sint32 maxTasks);\n\tbool MPResetTaskQ(MPTaskQ* taskq);\n\n\tvoid InitializeMP();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Memory.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"coreinit_Memory.h\"\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"Cafe/CafeSystem.h\"\n\nnamespace coreinit\n{\n\n\tvoid DCInvalidateRange(MPTR addr, uint32 size)\n\t{\n\t\tMPTR addrEnd = (addr + size + 0x1F) & ~0x1F;\n\t\taddr &= ~0x1F;\n\t\t//LatteBufferCache_notifyDCFlush(addr, addrEnd - addr);\n\t}\n\n\tvoid DCFlushRange(MPTR addr, uint32 size)\n\t{\n\t\tMPTR addrEnd = (addr + size + 0x1F) & ~0x1F;\n\t\taddr &= ~0x1F;\n\t\tLatteBufferCache_notifyDCFlush(addr, addrEnd - addr);\n\t}\n\n\tvoid DCFlushRangeNoSync(MPTR addr, uint32 size)\n\t{\n\t\tMPTR addrEnd = (addr + size + 0x1F) & ~0x1F;\n\t\taddr &= ~0x1F;\n\t\tLatteBufferCache_notifyDCFlush(addr, addrEnd - addr);\n\t}\n\n\tvoid DCStoreRange(MPTR addr, uint32 size)\n\t{\n\t\tMPTR addrEnd = (addr + size + 0x1F) & ~0x1F;\n\t\taddr &= ~0x1F;\n\t\t//LatteBufferCache_notifyDCFlush(addr, addrEnd - addr);\n\t}\n\n\tvoid DCStoreRangeNoSync(MPTR addr, uint32 size)\n\t{\n\t\tMPTR addrEnd = (addr + size + 0x1F) & ~0x1F;\n\t\taddr &= ~0x1F;\n\t\tLatteBufferCache_notifyDCFlush(addr, addrEnd - addr);\n\t}\n\n\tvoid DCZeroRange(MPTR addr, uint32 size)\n\t{\n\t\tMPTR alignedAddr = addr & ~31;\n\t\tuint32 cachlineOffset = addr & 31;\n\t\tuint32 blocks = (cachlineOffset + size + 31) / 32;\n\n\t\tif (blocks > 0)\n\t\t{\n\t\t\tmemset(memory_getPointerFromVirtualOffset(alignedAddr), 0x00, blocks * 32);\n\t\t\tLatteBufferCache_notifyDCFlush(alignedAddr, blocks * 32);\n\t\t}\n\t}\n\n\tbool OSIsAddressRangeDCValid(uint32 startOffset, uint32 range)\n\t{\n\t\tuint32 endOffset = startOffset + range - 1;\n\t\tuint32 boundaryLow = 0xE8000000;\n\t\tuint32 boundaryHigh = 0xEC000000;\n\t\tif (startOffset < boundaryLow || startOffset >= boundaryHigh)\n\t\t\treturn false;\n\t\tif (endOffset < boundaryLow || endOffset >= boundaryHigh)\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\tvoid* coreinit_memset(void* dst, uint32 value, uint32 size)\n\t{\n\t\tmemset(dst, value, size);\n\t\treturn dst;\n\t}\n\n\tvoid* coreinit_memcpy(MEMPTR<void> dst, MEMPTR<void> src, uint32 size)\n\t{\n\t\tif (dst.GetMPTR() == 0xFFFFFFFF)\n\t\t{\n\t\t\t// games this was seen in: The Swapper\n\t\t\t// this may be a bug in the game. The last few bytes of the address space are writable, but wrap-around behavior of COS memcpy is unknown\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\tif (size > 0)\n\t\t{\n\t\t\tmemcpy(dst.GetPtr(), src.GetPtr(), size);\n\t\t\t// always flushes the cache!\n\t\t\tLatteBufferCache_notifyDCFlush(dst.GetMPTR(), size);\n\t\t}\n\n\t\treturn dst.GetPtr();\n\t}\n\n\tvoid* coreinit_memmove(MEMPTR<void> dst, void* src, uint32 size)\n\t{\n\t\tif (size > 0)\n\t\t{\n\t\t\tmemmove(dst.GetPtr(), src, size);\n\t\t\t// always flushes the cache!\n\t\t\tLatteBufferCache_notifyDCFlush(dst.GetMPTR(), size);\n\t\t}\n\t\treturn dst.GetPtr();\n\t}\n\n\tvoid* OSBlockMove(MEMPTR<void> dst, MEMPTR<void> src, uint32 size, bool flushDC)\n\t{\n\t\tif (size > 0)\n\t\t{\n\t\t\tmemmove(dst.GetPtr(), src.GetPtr(), size);\n\t\t\tif (flushDC)\n\t\t\t\tLatteBufferCache_notifyDCFlush(dst.GetMPTR(), size);\n\t\t}\n\t\treturn dst.GetPtr();\n\t}\n\n\tvoid* OSBlockSet(MEMPTR<void> dst, uint32 value, uint32 size)\n\t{\n\t\tmemset(dst.GetPtr(), value&0xFF, size);\n\t\treturn dst.GetPtr();\n\t}\n\n\tMPTR OSEffectiveToPhysical(MPTR effectiveAddr)\n\t{\n\t\tMPTR physicalAddr = memory_virtualToPhysical(effectiveAddr);\n\t\treturn physicalAddr;\n\t}\n\n\tvoid OSMemoryBarrier()\n\t{\n\t\t// no-op\n\t}\n\n\tvoid OSGetMemBound(sint32 memType, MEMPTR<void>* offsetOutput, uint32be* sizeOutput)\n\t{\n\t\tMPTR memAddr = MPTR_NULL;\n\t\tuint32 memSize = 0;\n\n\t\t/*\n \t\tData taken from browser dump:\n\t\ttype\tstart\t\tsize\n\t\tMEM1\t0xF4000000\t0x02000000\n\t\tMEM2\t0x106DE000\t0x170C2000\n\t\t*/\n\t\tif (memType == 1)\n\t\t{\n\t\t\t// MEM1\n\t\t\tmemAddr = mmuRange_MEM1.getBase();\n\t\t\tmemSize = mmuRange_MEM1.getSize();\n\t\t}\n\t\telse if (memType == 2)\n\t\t{\n\t\t\t// MEM2\n\t\t\tuint32 currentRPLAllocatorOffset = RPLLoader_GetDataAllocatorAddr();\n\n\t\t\t// due to differences in our library implementations we currently allocate less memory for the OS/RPLs than on the actual hardware,\n\t\t\t// as a result more memory is available to games\n\t\t\t// however, some games crash due to internal overflows if there is too much memory available\n\n\t\t\t// here we artificially reduce the available memory for the affected games\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\tif (\n\t\t\t\ttitleId == 0x0005000010132400ULL || // Lego Marvel Super Heroes (EU)\n\t\t\t\ttitleId == 0x0005000010132B00ULL || // Lego Marvel Super Heroes (US)\n\t\t\t\ttitleId == 0x0005000010194200ull || // Lego Dimensions (US)\n\t\t\t\ttitleId == 0x0005000010195D00ull || // Lego Dimensions (EU)\n\t\t\t\ttitleId == 0x00050000101A6200ull || // Lego Jurassic World (US)\n\t\t\t\ttitleId == 0x00050000101A5C00 || // Lego Jurassic World (EU)\n\t\t\t\ttitleId == 0x000500001014DE00 || // The Lego Movie Videogame (US)\n\t\t\t\ttitleId == 0x000500001014E000 || // The Lego Movie Videogame (EU)\n\t\t\t\ttitleId == 0x0005000010168D00 || // Lego The Hobbit (EU)\n\t\t\t\ttitleId == 0x000500001016A700 || // Lego The Hobbit (JP)\n\t\t\t\t// The Hobbit US title id?\n\t\t\t\ttitleId == 0x00050000101DAB00 || // Lego Star Wars: The Force Awakens  (US)\n\t\t\t\ttitleId == 0x00050000101DAA00 ||  // Lego Star Wars: The Force Awakens  (EU)\n\t\t\t\t// LEGO Batman 3: BEYOND GOTHAM \n\t\t\t\ttitleId == 0x000500001016A400 || // EU\n\t\t\t\ttitleId == 0x000500001016AD00 || // US\n\t\t\t\t// Lego Marvel Avengers\n\t\t\t\ttitleId == 0x00050000101BE900 || // EU\n\t\t\t\ttitleId == 0x00050000101BEF00 || // US\n\t\t\t\t// LEGO BATMAN 2: DC Super Heroes \n\t\t\t\ttitleId == 0x0005000010135500 || // EU\n\t\t\t\ttitleId == 0x0005000010135E00 // US\n\t\t\t\t)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Hack: Reduce available memory to simulate loaded RPLs\");\n\t\t\t\tcurrentRPLAllocatorOffset += (48 * 1024 * 1024); // 48MB\n\t\t\t}\n\t\t\tmemAddr = currentRPLAllocatorOffset;\n\t\t\tmemSize = mmuRange_MEM2.getEnd() - currentRPLAllocatorOffset;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\tif (offsetOutput)\n\t\t\t*offsetOutput = memAddr;\n\t\tif (sizeOutput)\n\t\t\t*sizeOutput = memSize;\n\t}\n\n\tvoid InitializeMemory()\n\t{\n\t\tcafeExportRegister(\"coreinit\", DCInvalidateRange, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", DCFlushRange, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", DCFlushRangeNoSync, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", DCStoreRange, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", DCStoreRangeNoSync, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", DCZeroRange, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSIsAddressRangeDCValid, LogType::Placeholder);\n\n\t\tcafeExportRegisterFunc(coreinit_memcpy, \"coreinit\", \"memcpy\", LogType::Placeholder);\n\t\tcafeExportRegisterFunc(coreinit_memset, \"coreinit\", \"memset\", LogType::Placeholder);\n\t\tcafeExportRegisterFunc(coreinit_memmove, \"coreinit\", \"memmove\", LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSBlockMove, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSBlockSet, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", OSEffectiveToPhysical, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSMemoryBarrier, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", OSGetMemBound, LogType::Placeholder);\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Memory.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tvoid InitializeMemory();\n\n\tvoid OSGetMemBound(sint32 memType, MEMPTR<void>* offsetOutput, uint32be* sizeOutput);\n\n\tvoid* OSBlockMove(MEMPTR<void> dst, MEMPTR<void> src, uint32 size, bool flushDC);\n\tvoid* OSBlockSet(MEMPTR<void> dst, uint32 value, uint32 size);\n\n\tvoid OSMemoryBarrier();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"util/MemMapper/MemMapper.h\"\n\n#define OS_MAP_READ_ONLY\t\t(1)\n#define OS_MAP_READ_WRITE\t\t(2)\n\n#define VIRT_RANGE_ADDR\t\t\t(0xA0000000) // todo: Process specific. For the main ram pid this overlaps with the overlay arena?\n#define VIRT_RANGE_SIZE\t\t\t(0x40000000)\n\n#define PHYS_RANGE_ADDR\t\t\t(0x10000000) // todo: Process specific\n#define PHYS_RANGE_SIZE\t\t\t(0x40000000)\n\nnamespace coreinit\n{\n\tstd::mutex s_memMappingMtx;\n\n\tstruct OSVirtMemoryEntry\n\t{\n\t\tOSVirtMemoryEntry(MPTR virtualAddress, uint32 size, uint32 alignment) : virtualAddress(virtualAddress), size(size), alignment(alignment) {};\n\n\t\tMPTR virtualAddress;\n\t\tuint32 size;\n\t\tuint32 alignment;\n\t};\n\n\tstd::vector<OSVirtMemoryEntry> s_allocatedVirtMemory;\n\n\tMPTR _OSAllocVirtAddr(uint32 size, uint32 alignment)\n\t{\n\t\tstd::lock_guard _l(s_memMappingMtx);\n\t\tuint32 currentAddress = VIRT_RANGE_ADDR;\n\t\tuint32 endAddress = VIRT_RANGE_ADDR + VIRT_RANGE_SIZE;\n\t\tuint32 pageSize = (uint32)MemMapper::GetPageSize();\n\t\tpageSize = std::max<uint32>(pageSize, Espresso::MEM_PAGE_SIZE);\n\t\twhile (true)\n\t\t{\n\t\t\t// calculated aligned start and end address for current region\n\t\t\tcurrentAddress = (currentAddress + alignment - 1) & ~(alignment - 1);\n\t\t\tcurrentAddress = (currentAddress + pageSize - 1) & ~(pageSize - 1);\n\t\t\tuint32 currentEndAddress = currentAddress + size;\n\t\t\tcurrentEndAddress = (currentEndAddress + pageSize - 1) & ~(pageSize - 1);\n\t\t\t// check if out of available space\n\t\t\tif (currentEndAddress > endAddress)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::APIErrors, \"_OSAllocVirtAddr(): Unable to allocate memory\\n\");\n\t\t\t\treturn MPTR_NULL;\n\t\t\t}\n\t\t\t// check for overlapping regions\n\t\t\tbool emptySpaceFound = true;\n\t\t\tfor(auto& virtMemIt : s_allocatedVirtMemory)\n\t\t\t{\n\t\t\t\t// check for range collision\n\t\t\t\tif (currentAddress < (virtMemIt.virtualAddress + virtMemIt.size) && currentEndAddress > virtMemIt.virtualAddress)\n\t\t\t\t{\n\t\t\t\t\t// regions overlap\n\t\t\t\t\t// adjust current address and keep looking\n\t\t\t\t\tcurrentAddress = virtMemIt.virtualAddress + virtMemIt.size;\n\t\t\t\t\temptySpaceFound = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (emptySpaceFound)\n\t\t\t{\n\t\t\t\t// add entry\n\t\t\t\ts_allocatedVirtMemory.emplace_back(currentAddress, currentEndAddress - currentAddress, alignment);\n\t\t\t\treturn currentAddress;\n\t\t\t}\n\t\t}\n\t\treturn MPTR_NULL;\n\t}\n\n\tbool _OSFreeVirtAddr(MPTR virtAddr)\n\t{\n\t\tstd::lock_guard _l(s_memMappingMtx);\n\t\tauto it = s_allocatedVirtMemory.begin();\n\t\twhile (it != s_allocatedVirtMemory.end())\n\t\t{\n\t\t\tif (it->virtualAddress == virtAddr)\n\t\t\t{\n\t\t\t\ts_allocatedVirtMemory.erase(it);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t++it;\n\t\t}\n\t\treturn false;\n\t}\n\n\tvoid OSGetAvailPhysAddrRange(uint32be* physRangeStart, uint32be* physRangeSize)\n\t{\n\t\t*physRangeStart = PHYS_RANGE_ADDR;\n\t\t*physRangeSize = PHYS_RANGE_SIZE;\n\t}\n\n\tvoid* OSAllocVirtAddr(MEMPTR<void> address, uint32 size, uint32 align)\n\t{\n\t\tif (align == 0)\n\t\t\talign = 1;\n\t\tif (align != 0 && align != 1)\n\t\t\tassert_dbg();\n\t\tcemu_assert_debug(address == nullptr); // todo - support for allocation with fixed address\n\n\t\taddress = _OSAllocVirtAddr(size, align);\n\t\tdebug_printf(\"OSAllocVirtAddr(): Allocated virtual memory at 0x%08x\\n\", address.GetMPTR());\n\t\treturn MEMPTR<void>(address);\n\t}\n\n\tuint32 OSFreeVirtAddr(MEMPTR<void> address)\n\t{\n\t\tbool r = _OSFreeVirtAddr(address.GetMPTR());\n\t\tif(!r)\n\t\t\tcemuLog_log(LogType::APIErrors, \"OSFreeVirtAddr: Could not find allocation with address 0x{:08x}\\n\", address.GetMPTR());\n\t\treturn r ? 1 : 0;\n\t}\n\n\tuint32 OSMapMemory(MPTR virtualAddress, MPTR physicalAddress, uint32 size, uint32 mode)\n\t{\n\t\tif (virtualAddress < VIRT_RANGE_ADDR || virtualAddress >= (VIRT_RANGE_ADDR + VIRT_RANGE_SIZE))\n\t\t{\n\t\t\tcemuLog_log(LogType::APIErrors, \"OSMapMemory: Virtual address out of bounds\\n\");\n\t\t\treturn 0;\n\t\t}\n\n\t\tuint8* virtualPtr = memory_getPointerFromVirtualOffset(virtualAddress);\n\n\t\tMemMapper::PAGE_PERMISSION pageProtect = MemMapper::PAGE_PERMISSION::P_NONE;\n\t\tif (mode == OS_MAP_READ_ONLY)\n\t\t\tpageProtect = MemMapper::PAGE_PERMISSION::P_READ;\n\t\telse if (mode == OS_MAP_READ_WRITE)\n\t\t\tpageProtect = MemMapper::PAGE_PERMISSION::P_RW;\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t\tvoid* allocationResult = MemMapper::AllocateMemory(virtualPtr, size, pageProtect, true);\n\t\tif (!allocationResult)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"OSMapMemory failed\");\n\t\t\treturn 0;\n\t\t}\n\t\treturn 1;\n\t}\n\n\tuint32 OSUnmapMemory(MPTR virtualAddress, uint32 size)\n\t{\n\t\tif (virtualAddress < VIRT_RANGE_ADDR || virtualAddress >= (VIRT_RANGE_ADDR + VIRT_RANGE_SIZE))\n\t\t\tcemu_assert_suspicious();\n\n\t\tcemu_assert((size % MemMapper::GetPageSize()) == 0);\n\n\t\tuint8* virtualPtr = memory_getPointerFromVirtualOffset(virtualAddress);\n\n\t\tMemMapper::FreeMemory(virtualPtr, size, true);\n\t\treturn 1;\n\t}\n\n\tvoid InitializeMemoryMapping()\n\t{\n\t\ts_allocatedVirtMemory.clear();\n\t\tcafeExportRegister(\"coreinit\", OSGetAvailPhysAddrRange, LogType::CoreinitMemoryMapping);\n\t\tcafeExportRegister(\"coreinit\", OSAllocVirtAddr, LogType::CoreinitMemoryMapping);\n\t\tcafeExportRegister(\"coreinit\", OSFreeVirtAddr, LogType::CoreinitMemoryMapping);\n\t\tcafeExportRegister(\"coreinit\", OSMapMemory, LogType::CoreinitMemoryMapping);\n\t\tcafeExportRegister(\"coreinit\", OSUnmapMemory, LogType::CoreinitMemoryMapping);\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MemoryMapping.h",
    "content": "\nnamespace coreinit\n{\n\tvoid InitializeMemoryMapping();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MessageQueue.h\"\n\nnamespace coreinit\n{\n\tvoid UpdateSystemMessageQueue();\n\tvoid HandleReceivedSystemMessage(OSMessage* msg);\n\n\tSysAllocator<OSMessageQueue> g_systemMessageQueue;\n\tSysAllocator<OSMessage, 16> _systemMessageQueueArray;\n\n\tvoid OSInitMessageQueueEx(OSMessageQueue* msgQueue, OSMessage* msgArray, uint32 msgCount, void* userData)\n\t{\n\t\tmsgQueue->magic = 'mSgQ';\n\t\tmsgQueue->userData = userData;\n\t\tmsgQueue->msgArray = msgArray;\n\t\tmsgQueue->msgCount = msgCount;\n\t\tmsgQueue->firstIndex = 0;\n\t\tmsgQueue->usedCount = 0;\n\t\tmsgQueue->ukn08 = 0;\n\t\tOSInitThreadQueueEx(&msgQueue->threadQueueReceive, msgQueue);\n\t\tOSInitThreadQueueEx(&msgQueue->threadQueueSend, msgQueue);\n\t}\n\n\tvoid OSInitMessageQueue(OSMessageQueue* msgQueue, OSMessage* msgArray, uint32 msgCount)\n\t{\n\t\tOSInitMessageQueueEx(msgQueue, msgArray, msgCount, nullptr);\n\t}\n\n\tbool OSReceiveMessage(OSMessageQueue* msgQueue, OSMessage* msg, uint32 flags)\n\t{\n\t\tbool isSystemMessageQueue = (msgQueue == g_systemMessageQueue);\n\t\tif(isSystemMessageQueue)\n\t\t\tUpdateSystemMessageQueue();\n\t\t__OSLockScheduler(msgQueue);\n\t\twhile (msgQueue->usedCount == (uint32be)0)\n\t\t{\n\t\t\tif ((flags & OS_MESSAGE_BLOCK))\n\t\t\t{\n\t\t\t\tmsgQueue->threadQueueReceive.queueAndWait(OSGetCurrentThread());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t__OSUnlockScheduler(msgQueue);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\t// copy message\n\t\tsint32 messageIndex = msgQueue->firstIndex;\n\t\tOSMessage* readMsg = &(msgQueue->msgArray[messageIndex]);\n\t\tmemcpy(msg, readMsg, sizeof(OSMessage));\n\t\tmsgQueue->firstIndex = ((uint32)msgQueue->firstIndex + 1) % (uint32)(msgQueue->msgCount);\n\t\tmsgQueue->usedCount = (uint32)msgQueue->usedCount - 1;\n\t\t// wake up any thread waiting to add a message\n\t\tif (!msgQueue->threadQueueSend.isEmpty())\n\t\t\tmsgQueue->threadQueueSend.wakeupSingleThreadWaitQueue(true);\n\t\t__OSUnlockScheduler(msgQueue);\n\t\tif(isSystemMessageQueue)\n\t\t\tHandleReceivedSystemMessage(msg);\n\t\treturn true;\n\t}\n\n\tbool OSPeekMessage(OSMessageQueue* msgQueue, OSMessage* msg)\n\t{\n\t\t__OSLockScheduler(msgQueue);\n\t\tif ((msgQueue->usedCount == (uint32be)0))\n\t\t{\n\t\t\t__OSUnlockScheduler(msgQueue);\n\t\t\treturn false;\n\t\t}\n\t\t// copy message\n\t\tsint32 messageIndex = msgQueue->firstIndex;\n\t\tif (msg)\n\t\t{\n\t\t\tOSMessage* readMsg = &(msgQueue->msgArray[messageIndex]);\n\t\t\tmemcpy(msg, readMsg, sizeof(OSMessage));\n\t\t}\n\t\t__OSUnlockScheduler(msgQueue);\n\t\treturn true;\n\t}\n\n\tsint32 OSSendMessage(OSMessageQueue* msgQueue, OSMessage* msg, uint32 flags)\n\t{\n\t\t__OSLockScheduler();\n\t\twhile (msgQueue->usedCount >= msgQueue->msgCount)\n\t\t{\n\t\t\tif ((flags & OS_MESSAGE_BLOCK))\n\t\t\t{\n\t\t\t\tmsgQueue->threadQueueSend.queueAndWait(OSGetCurrentThread());\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  \n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t__OSUnlockScheduler();\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\t// add message\n\t\tif ((flags & OS_MESSAGE_HIGH_PRIORITY))\n\t\t{\n\t\t\t// decrease firstIndex\n\t\t\tsint32 newFirstIndex = (sint32)((sint32)msgQueue->firstIndex + (sint32)msgQueue->msgCount - 1) % (sint32)msgQueue->msgCount;\n\t\t\tmsgQueue->firstIndex = newFirstIndex;\n\t\t\t// insert message at new first index\n\t\t\tmsgQueue->usedCount = (uint32)msgQueue->usedCount + 1;\n\t\t\tOSMessage* newMsg = &(msgQueue->msgArray[newFirstIndex]);\n\t\t\tmemcpy(newMsg, msg, sizeof(OSMessage));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsint32 messageIndex = (uint32)(msgQueue->firstIndex + msgQueue->usedCount) % (uint32)msgQueue->msgCount;\n\t\t\tmsgQueue->usedCount = (uint32)msgQueue->usedCount + 1;\n\t\t\tOSMessage* newMsg = &(msgQueue->msgArray[messageIndex]);\n\t\t\tmemcpy(newMsg, msg, sizeof(OSMessage));\n\t\t}\n\t\t// wake up any thread waiting to read a message\n\t\tif (!msgQueue->threadQueueReceive.isEmpty())\n\t\t\tmsgQueue->threadQueueReceive.wakeupSingleThreadWaitQueue(true);\n\t\t__OSUnlockScheduler();\n\t\treturn 1;\n\t}\n\n\tOSMessageQueue* OSGetSystemMessageQueue()\n\t{\n\t\treturn g_systemMessageQueue.GetPtr();\n\t}\n\n\tvoid InitializeMessageQueue()\n\t{\n\t\tOSInitMessageQueue(g_systemMessageQueue.GetPtr(), _systemMessageQueueArray.GetPtr(), _systemMessageQueueArray.GetCount());\n\n\t\tcafeExportRegister(\"coreinit\", OSInitMessageQueueEx, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSInitMessageQueue, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSReceiveMessage, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSPeekMessage, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSSendMessage, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetSystemMessageQueue, LogType::CoreinitThread);\n\t}\n};\n\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n\nnamespace coreinit\n{\n\tenum class SysMessageId : uint32\n\t{\n\t\tMsgAcquireForeground = 0xFACEF000,\n\t\tMsgReleaseForeground = 0xFACEBACC,\n\t\tMsgExit = 0xD1E0D1E0,\n\t\tHomeButtonDenied = 0xCCC0FFEE,\n\t\tNetIoStartOrStop = 0xAAC0FFEE,\n\t};\n\n\tstruct OSMessage\n\t{\n\t\tuint32be\t\tmessage;\n\t\tuint32be\t\tdata0;\n\t\tuint32be\t\tdata1;\n\t\tuint32be\t\tdata2;\n\t};\n\n\tstruct OSMessageQueue\n\t{\n\t\t/* +0x00 */ uint32be\t\t\t\tmagic;\n\t\t/* +0x04 */ MEMPTR<void>\t\t\tuserData;\n\t\t/* +0x08 */ uint32be\t\t\t\tukn08;\n\t\t/* +0x0C */ OSThreadQueue\t\t\tthreadQueueSend;\n\t\t/* +0x1C */ OSThreadQueue\t\t\tthreadQueueReceive;\n\t\t/* +0x2C */ MEMPTR<OSMessage>\t\tmsgArray;\n\t\t/* +0x30 */ uint32be\t\t\t\tmsgCount;\n\t\t/* +0x34 */ uint32be\t\t\t\tfirstIndex;\n\t\t/* +0x38 */ uint32be\t\t\t\tusedCount;\n\t};\n\n\tstatic_assert(sizeof(OSMessageQueue) == 0x3C);\n\n\t// flags\n\t#define OS_MESSAGE_BLOCK\t\t\t\t1 // blocking send/receive\n\t#define OS_MESSAGE_HIGH_PRIORITY\t\t2 // put message in front of all queued messages\n\n\tvoid OSInitMessageQueueEx(OSMessageQueue* msgQueue, OSMessage* msgArray, uint32 msgCount, void* userData);\n\tvoid OSInitMessageQueue(OSMessageQueue* msgQueue, OSMessage* msgArray, uint32 msgCount);\n\tbool OSReceiveMessage(OSMessageQueue* msgQueue, OSMessage* msg, uint32 flags);\n\tbool OSPeekMessage(OSMessageQueue* msgQueue, OSMessage* msg);\n\tsint32 OSSendMessage(OSMessageQueue* msgQueue, OSMessage* msg, uint32 flags);\n\n\tOSMessageQueue* OSGetSystemMessageQueue();\n\n\tvoid InitializeMessageQueue();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Misc.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Misc.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MessageQueue.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n#include <pugixml.hpp>\n\nnamespace coreinit\n{\n\tsint32 ppc_vprintf(const char* formatStr, char* strOut, sint32 maxLength, ppc_va_list* vargs)\n\t{\n\t\tchar tempStr[4096];\n\t\tsint32 writeIndex = 0;\n\t\twhile (*formatStr)\n\t\t{\n\t\t\tchar c = *formatStr;\n\t\t\tif (c == '%')\n\t\t\t{\n\t\t\t\tconst char* formatStart = formatStr;\n\t\t\t\tformatStr++;\n\t\t\t\tif (*formatStr == '%')\n\t\t\t\t{\n\t\t\t\t\t// percent sign\n\t\t\t\t\tif (writeIndex >= maxLength)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tstrOut[writeIndex] = '%';\n\t\t\t\t\twriteIndex++;\n\t\t\t\t\tformatStr++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// flags\n\t\t\t\tbool flag_leftJustify = false;\n\t\t\t\tbool flag_zeroPadding = false;\n\t\t\t\tif (*formatStr == '-')\n\t\t\t\t{\n\t\t\t\t\tflag_leftJustify = true;\n\t\t\t\t\tformatStr++;\n\t\t\t\t}\n\t\t\t\tif (*formatStr == '+')\n\t\t\t\t{\n\t\t\t\t\t// todo\n\t\t\t\t\tformatStr++;\n\t\t\t\t}\n\t\t\t\tif (*formatStr == ' ')\n\t\t\t\t{\n\t\t\t\t\t// todo\n\t\t\t\t\tformatStr++;\n\t\t\t\t}\n\t\t\t\tif (*formatStr == '#')\n\t\t\t\t{\n\t\t\t\t\t// todo\n\t\t\t\t\tformatStr++;\n\t\t\t\t}\n\t\t\t\tif (*formatStr == '0')\n\t\t\t\t{\n\t\t\t\t\tflag_zeroPadding = true;\n\t\t\t\t\tformatStr++;\n\t\t\t\t}\n\t\t\t\t// width\n\t\t\t\tif (*formatStr == '*')\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t\tformatStr++;\n\t\t\t\t}\n\t\t\t\tbool widthIsSpecified = false;\n\t\t\t\tsint32 width = 0;\n\t\t\t\twhile (*formatStr >= '0' && *formatStr <= '9')\n\t\t\t\t{\n\t\t\t\t\twidth *= 10;\n\t\t\t\t\twidth += (*formatStr - '0');\n\t\t\t\t\tformatStr++;\n\t\t\t\t\twidthIsSpecified = true;\n\t\t\t\t}\n\t\t\t\t// precision\n\t\t\t\tif (*formatStr == '.')\n\t\t\t\t{\n\t\t\t\t\tformatStr++;\n\t\t\t\t\tif (*formatStr == '*')\n\t\t\t\t\t{\n\t\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t\t}\n\t\t\t\t\twhile (*formatStr >= '0' && *formatStr <= '9')\n\t\t\t\t\t{\n\t\t\t\t\t\tformatStr++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// length + specifier\n\t\t\t\tchar tempFormat[64];\n\t\t\t\tif (*formatStr == 'X' || *formatStr == 'x' || *formatStr == 'u' || *formatStr == 'd' || *formatStr == 'p' || *formatStr == 'i' ||\n\t\t\t\t\t(formatStr[0] == 'l' && formatStr[1] == 'd'))\n\t\t\t\t{\n\t\t\t\t\t// number\n\t\t\t\t\tformatStr++;\n\t\t\t\t\tstrncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));\n\t\t\t\t\tif ((formatStr - formatStart) < sizeof(tempFormat))\n\t\t\t\t\t\ttempFormat[(formatStr - formatStart)] = '\\0';\n\t\t\t\t\telse\n\t\t\t\t\t\ttempFormat[sizeof(tempFormat) - 1] = '\\0';\n\t\t\t\t\tsint32 tempLen = sprintf(tempStr, tempFormat, (uint32)*(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32));\n\t\t\t\t\tfor (sint32 i = 0; i < tempLen; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (writeIndex >= maxLength)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tstrOut[writeIndex] = tempStr[i];\n\t\t\t\t\t\twriteIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (*formatStr == 's')\n\t\t\t\t{\n\t\t\t\t\t// string\n\t\t\t\t\tformatStr++;\n\t\t\t\t\tstrncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));\n\t\t\t\t\tif ((formatStr - formatStart) < sizeof(tempFormat))\n\t\t\t\t\t\ttempFormat[(formatStr - formatStart)] = '\\0';\n\t\t\t\t\telse\n\t\t\t\t\t\ttempFormat[sizeof(tempFormat) - 1] = '\\0';\n\t\t\t\t\tMPTR strOffset = *(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32);\n\t\t\t\t\tsint32 tempLen = 0;\n\t\t\t\t\tif (strOffset == MPTR_NULL)\n\t\t\t\t\t\ttempLen = sprintf(tempStr, \"NULL\");\n\t\t\t\t\telse\n\t\t\t\t\t\ttempLen = sprintf(tempStr, tempFormat, memory_getPointerFromVirtualOffset(strOffset));\n\t\t\t\t\tfor (sint32 i = 0; i < tempLen; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (writeIndex >= maxLength)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tstrOut[writeIndex] = tempStr[i];\n\t\t\t\t\t\twriteIndex++;\n\t\t\t\t\t}\n\t\t\t\t\tstrOut[std::min(maxLength - 1, writeIndex)] = '\\0';\n\t\t\t\t}\n\t\t\t\telse if (*formatStr == 'c')\n\t\t\t\t{\n\t\t\t\t\t// character\n\t\t\t\t\tformatStr++;\n\t\t\t\t\tstrncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));\n\t\t\t\t\tif ((formatStr - formatStart) < sizeof(tempFormat))\n\t\t\t\t\t\ttempFormat[(formatStr - formatStart)] = '\\0';\n\t\t\t\t\telse\n\t\t\t\t\t\ttempFormat[sizeof(tempFormat) - 1] = '\\0';\n\t\t\t\t\tsint32 tempLen = sprintf(tempStr, tempFormat, (uint32)*(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32));\n\t\t\t\t\tfor (sint32 i = 0; i < tempLen; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (writeIndex >= maxLength)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tstrOut[writeIndex] = tempStr[i];\n\t\t\t\t\t\twriteIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (*formatStr == 'f' || *formatStr == 'g' || *formatStr == 'G')\n\t\t\t\t{\n\t\t\t\t\tformatStr++;\n\t\t\t\t\tstrncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));\n\t\t\t\t\tif ((formatStr - formatStart) < sizeof(tempFormat))\n\t\t\t\t\t\ttempFormat[(formatStr - formatStart)] = '\\0';\n\t\t\t\t\telse\n\t\t\t\t\t\ttempFormat[sizeof(tempFormat) - 1] = '\\0';\n\t\t\t\t\tsint32 tempLen = sprintf(tempStr, tempFormat, (double)*(betype<double>*)_ppc_va_arg(vargs, ppc_va_type::FLOAT_OR_DOUBLE));\n\t\t\t\t\tfor (sint32 i = 0; i < tempLen; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (writeIndex >= maxLength)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tstrOut[writeIndex] = tempStr[i];\n\t\t\t\t\t\twriteIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (formatStr[0] == 'l' && formatStr[1] == 'f')\n\t\t\t\t{\n\t\t\t\t\t// double\n\t\t\t\t\tformatStr += 2;\n\t\t\t\t\tstrncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));\n\t\t\t\t\tif ((formatStr - formatStart) < sizeof(tempFormat))\n\t\t\t\t\t\ttempFormat[(formatStr - formatStart)] = '\\0';\n\t\t\t\t\telse\n\t\t\t\t\t\ttempFormat[sizeof(tempFormat) - 1] = '\\0';\n\t\t\t\t\tsint32 tempLen = sprintf(tempStr, tempFormat, (double)*(betype<double>*)_ppc_va_arg(vargs, ppc_va_type::FLOAT_OR_DOUBLE));\n\t\t\t\t\tfor (sint32 i = 0; i < tempLen; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (writeIndex >= maxLength)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tstrOut[writeIndex] = tempStr[i];\n\t\t\t\t\t\twriteIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ((formatStr[0] == 'l' && formatStr[1] == 'l' && (formatStr[2] == 'x' || formatStr[2] == 'X')))\n\t\t\t\t{\n\t\t\t\t\tformatStr += 3;\n\t\t\t\t\t// 64bit int\n\t\t\t\t\tstrncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));\n\t\t\t\t\tif ((formatStr - formatStart) < sizeof(tempFormat))\n\t\t\t\t\t\ttempFormat[(formatStr - formatStart)] = '\\0';\n\t\t\t\t\telse\n\t\t\t\t\t\ttempFormat[sizeof(tempFormat) - 1] = '\\0';\n\t\t\t\t\tsint32 tempLen = sprintf(tempStr, tempFormat, (uint64)*(uint64be*)_ppc_va_arg(vargs, ppc_va_type::INT64));\n\t\t\t\t\tfor (sint32 i = 0; i < tempLen; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (writeIndex >= maxLength)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tstrOut[writeIndex] = tempStr[i];\n\t\t\t\t\t\twriteIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ((formatStr[0] == 'l' && formatStr[1] == 'l' && formatStr[2] == 'd'))\n\t\t\t\t{\n\t\t\t\t\tformatStr += 3;\n\t\t\t\t\t// signed integer (64bit)\n\t\t\t\t\tstrncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));\n\t\t\t\t\tif ((formatStr - formatStart) < sizeof(tempFormat))\n\t\t\t\t\t\ttempFormat[(formatStr - formatStart)] = '\\0';\n\t\t\t\t\telse\n\t\t\t\t\t\ttempFormat[sizeof(tempFormat) - 1] = '\\0';\n\t\t\t\t\tsint32 tempLen = sprintf(tempStr, tempFormat, (sint64)*(sint64be*)_ppc_va_arg(vargs, ppc_va_type::INT64));\n\t\t\t\t\tfor (sint32 i = 0; i < tempLen; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (writeIndex >= maxLength)\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tstrOut[writeIndex] = tempStr[i];\n\t\t\t\t\t\twriteIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// unsupported / unknown specifier\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (writeIndex >= maxLength)\n\t\t\t\t\tbreak;\n\t\t\t\tstrOut[writeIndex] = c;\n\t\t\t\twriteIndex++;\n\t\t\t\tformatStr++;\n\t\t\t}\n\t\t}\n\t\tstrOut[std::min(writeIndex, maxLength - 1)] = '\\0';\n\t\treturn std::min(writeIndex, maxLength - 1);\n\t}\n\n\t/* coreinit logging and string format */\n\n\tsint32 __os_snprintf(char* outputStr, sint32 maxLength, const char* formatStr)\n\t{\n\t\tppc_define_va_list(3, 0);\n\t\tsint32 r = ppc_vprintf(formatStr, outputStr, maxLength, &vargs);\n\t\treturn r;\n\t}\n\n\tenum class CafeLogType\n\t{\n\t\tOSCONSOLE = 0,\n\t};\n\n\tstruct CafeLogBuffer\n\t{\n\t\tstd::array<char, 270> lineBuffer;\n\t\tsize_t lineLength{};\n\t};\n\n\tCafeLogBuffer g_logBuffer_OSReport;\n\n\tCafeLogBuffer& getLogBuffer(CafeLogType cafeLogType)\n\t{\n\t\tif (cafeLogType == CafeLogType::OSCONSOLE)\n\t\t\treturn g_logBuffer_OSReport;\n\t\t// default to OSReport\n\t\treturn g_logBuffer_OSReport;\n\t}\n\n\tstd::string_view getLogBufferName(CafeLogType cafeLogType)\n\t{\n\t\tif (cafeLogType == CafeLogType::OSCONSOLE)\n\t\t\treturn \"OSConsole\";\n\t\treturn \"Unknown\";\n\t}\n\n\tstd::mutex sCafeConsoleMutex;\n\t\n\tvoid WriteCafeConsole(CafeLogType cafeLogType, const char* msg, sint32 len)\n\t{\n\t\tstd::unique_lock _l(sCafeConsoleMutex);\n\t\tCafeLogBuffer& logBuffer = getLogBuffer(cafeLogType);\n\t\t// once a line is full or \\n is written it will be posted to log\n\t\tauto flushLine = [](CafeLogBuffer& cafeLogBuffer, std::string_view cafeLogName) -> void\n\t\t{\n\t\t\tcemuLog_log(LogType::CoreinitLogging, \"[{0}] {1}\", cafeLogName, std::basic_string_view(cafeLogBuffer.lineBuffer.data(), cafeLogBuffer.lineLength));\n\t\t\tcafeLogBuffer.lineLength = 0;\n\t\t};\n\n\t\twhile (len)\n\t\t{\n\t\t\tchar c = *msg;\n\t\t\tmsg++;\n\t\t\tlen--;\n\t\t\tif (c == '\\r')\n\t\t\t\tcontinue;\n\t\t\tif (c == '\\n')\n\t\t\t{\n\t\t\t\t// flush line immediately\n\t\t\t\tflushLine(logBuffer, getLogBufferName(cafeLogType));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlogBuffer.lineBuffer[logBuffer.lineLength] = c;\n\t\t\tlogBuffer.lineLength++;\n\t\t\tif (logBuffer.lineLength >= logBuffer.lineBuffer.size())\n\t\t\t\tflushLine(logBuffer, getLogBufferName(cafeLogType));\n\t\t}\n\t}\n\n\tvoid COSVReport(COSReportModule module, COSReportLevel level, const char* format, ppc_va_list* vargs)\n\t{\n\t\tchar tmpBuffer[1024];\n\t\tsint32 len = ppc_vprintf(format, tmpBuffer, sizeof(tmpBuffer), vargs);\n\t\tWriteCafeConsole(CafeLogType::OSCONSOLE, tmpBuffer, len);\n\t}\n\n\tvoid OSReport(const char* format)\n\t{\n\t\tppc_define_va_list(1, 0);\n\t\tCOSVReport(COSReportModule::coreinit, COSReportLevel::Info, format, &vargs);\n\t}\n\n\tvoid OSVReport(const char* format, ppc_va_list* vargs)\n\t{\n\t\tCOSVReport(COSReportModule::coreinit, COSReportLevel::Info, format, vargs);\n\t}\n\n\tvoid COSWarn(int moduleId, const char* format)\n\t{\n\t\tppc_define_va_list(2, 0);\n\t\tchar tmpBuffer[1024];\n\t\tint prefixLen = sprintf(tmpBuffer, \"[COSWarn-%d] \", moduleId);\n\t\tsint32 len = ppc_vprintf(format, tmpBuffer + prefixLen, sizeof(tmpBuffer) - prefixLen, &vargs);\n\t\tWriteCafeConsole(CafeLogType::OSCONSOLE, tmpBuffer, len + prefixLen);\n\t}\n\n\tvoid OSLogPrintf(int ukn1, int ukn2, int ukn3, const char* format)\n\t{\n\t\tppc_define_va_list(4, 0);\n\t\tchar tmpBuffer[1024];\n\t\tint prefixLen = sprintf(tmpBuffer, \"[OSLogPrintf-%d-%d-%d] \", ukn1, ukn2, ukn3);\n\t\tsint32 len = ppc_vprintf(format, tmpBuffer + prefixLen, sizeof(tmpBuffer) - prefixLen, &vargs);\n\t\tWriteCafeConsole(CafeLogType::OSCONSOLE, tmpBuffer, len + prefixLen);\n\t}\n\n\tvoid OSConsoleWrite(const char* strPtr, sint32 length)\n\t{\n\t\tif (length < 0)\n\t\t\treturn;\n\t\tWriteCafeConsole(CafeLogType::OSCONSOLE, strPtr, length);\n\t}\n\n\t/* home button menu */\n\n\tbool g_homeButtonMenuEnabled = false;\n\n\tbool OSIsHomeButtonMenuEnabled()\n\t{\n\t\treturn g_homeButtonMenuEnabled;\n\t}\n\n\tbool OSEnableHomeButtonMenu(bool enable)\n\t{\n\t\tg_homeButtonMenuEnabled = enable;\n\t\treturn true;\n\t}\n\n\tuint32 OSGetPFID()\n\t{\n\t\treturn 15; // hardcoded as game\n\t}\n\n\tuint32 OSGetUPID()\n\t{\n\t\treturn OSGetPFID();\n\t}\n\n\tuint64 s_currentTitleId;\n\n\tuint64 OSGetTitleID()\n\t{\n\t\treturn s_currentTitleId;\n\t}\n\n\tuint32 s_sdkVersion;\n\n\tuint32 __OSGetProcessSDKVersion()\n\t{\n\t\treturn s_sdkVersion;\n\t}\n\n\t// move this to CafeSystem.cpp?\n\tvoid OSLauncherThread(uint64 titleId)\n\t{\n\t\tCafeSystem::ShutdownTitle();\n\t\tCafeSystem::PrepareForegroundTitle(titleId);\n\t\tCafeSystem::RequestRecreateCanvas();\n\t\tCafeSystem::LaunchForegroundTitle();\n\t}\n\n\tuint32 __LaunchByTitleId(uint64 titleId, uint32 argc, MEMPTR<char>* argv)\n\t{\n\t\t// prepare argument buffer\n\t\t#if 0\n\t\tchar argumentBuffer[4096];\n\t\tuint32 argumentBufferLength = 0;\n\t\tchar* argWriter = argumentBuffer;\n\t\tfor(uint32 i=0; i<argc; i++)\n\t\t{\n\t\t\tconst char* arg = argv[i];\n\t\t\tuint32 argLength = strlen(arg);\n\t\t\tif((argumentBufferLength + argLength + 1) >= sizeof(argumentBuffer))\n\t\t\t{\n\t\t\t\t// argument buffer full\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"LaunchByTitleId: argument buffer full\");\n\t\t\t\treturn 0x80000000;\n\t\t\t}\n\t\t\tmemcpy(argWriter, arg, argLength);\n\t\t\targWriter[argLength] = '\\0';\n\t\t\targWriter += argLength + 1;\n\t\t\targumentBufferLength += argLength + 1;\n\t\t}\n\t\t#endif\n\t\t// normally the above buffer is passed to the PPC kernel via syscall 0x2B and then\n\t\t// the kernel forwards it to IOSU MCP when requesting a title launch\n\t\t// but for now we HLE most of the launching code and can just set the argument array directly\n\t\tstd::vector<std::string> argArray;\n\t\tfor(uint32 i=0; i<argc; i++)\n\t\t\targArray.emplace_back(argv[i]);\n\t\tCafeSystem::SetOverrideArgs(argArray);\n\t\t// spawn launcher thread (this current thread will be destroyed during relaunch)\n\t\tstd::thread launcherThread(OSLauncherThread, titleId);\n\t\tlauncherThread.detach();\n\t\t// suspend this thread\n\t\tcoreinit::OSSuspendThread(coreinit::OSGetCurrentThread());\n\t\treturn 0;\n\t}\n\n\tuint32 OSLaunchTitleByPathl(const char* path, uint32 pathLength, uint32 argc)\n\t{\n\t\tchar appXmlPath[1024];\n\t\tcemu_assert_debug(argc == 0); // custom args not supported yet\n\t\tif(pathLength >= (sizeof(appXmlPath) - 32))\n\t\t{\n\t\t\t// path too long\n\t\t\tcemuLog_logDebug(LogType::Force, \"OSLaunchTitleByPathl: path too long\");\n\t\t\treturn 0x80000000;\n\t\t}\n\t\t// read app.xml to get the titleId\n\t\tmemcpy(appXmlPath, path, pathLength);\n\t\tappXmlPath[pathLength] = '\\0';\n\t\tstrcat(appXmlPath, \"/code/app.xml\");\n\t\tsint32 status;\n\t\tauto fscfile = fsc_open(appXmlPath, FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &status);\n\t\tif (!fscfile)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"OSLaunchTitleByPathl: failed to open target app.xml\");\n\t\t\treturn 0x80000000;\n\t\t}\n\t\tuint32 size = fsc_getFileSize(fscfile);\n\t\tstd::vector<uint8> tmpData(size);\n\t\tfsc_readFile(fscfile, tmpData.data(), size);\n\t\tfsc_close(fscfile);\n\t\t// parse app.xml to get the titleId\n\t\tpugi::xml_document app_doc;\n\t\tif (!app_doc.load_buffer_inplace(tmpData.data(), tmpData.size()))\n\t\t\treturn false;\n\t\tuint64 titleId = std::stoull(app_doc.child(\"app\").child(\"title_id\").child_value(), nullptr, 16);\n\t\tif(titleId == 0)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"OSLaunchTitleByPathl: failed to parse titleId from app.xml\");\n\t\t\treturn 0x80000000;\n\t\t}\n\t\t__LaunchByTitleId(titleId, 0, nullptr);\n\t\treturn 0;\n\t}\n\n\tuint32 OSRestartGame(uint32 argc, MEMPTR<char>* argv)\n\t{\n\t\t__LaunchByTitleId(CafeSystem::GetForegroundTitleId(), argc, argv);\n\t\treturn 0;\n\t}\n\n\tvoid OSReleaseForeground()\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"OSReleaseForeground not implemented\");\n\t}\n\n\tbool s_transitionToBackground = false;\n\tbool s_transitionToForeground = false;\n\n\tvoid StartBackgroundForegroundTransition()\n\t{\n\t\ts_transitionToBackground = true;\n\t\ts_transitionToForeground = true;\n\t}\n\n\t// called at the beginning of OSReceiveMessage if the queue is the system message queue\n\tvoid UpdateSystemMessageQueue()\n\t{\n\t\tif(!OSIsInterruptEnabled())\n\t\t\treturn;\n\t\tcemu_assert_debug(!__OSHasSchedulerLock());\n\t\t// normally syscall 0x2E is used to get the next message\n\t\t// for now we just have some preliminary logic here to allow a fake transition to background & foreground\n\t\tif(s_transitionToBackground)\n\t\t{\n\t\t\t// add transition to background message\n\t\t\tOSMessage msg{};\n\t\t\tmsg.data0 = stdx::to_underlying(SysMessageId::MsgReleaseForeground);\n\t\t\tmsg.data1 = 0; // 1 -> System is shutting down 0 -> Begin transitioning to background\n\t\t\tOSMessageQueue* systemMessageQueue = coreinit::OSGetSystemMessageQueue();\n\t\t\tif(OSSendMessage(systemMessageQueue, &msg, 0))\n\t\t\t\ts_transitionToBackground = false;\n\t\t\treturn;\n\t\t}\n\t\tif(s_transitionToForeground)\n\t\t{\n\t\t\t// add transition to foreground message\n\t\t\tOSMessage msg{};\n\t\t\tmsg.data0 = stdx::to_underlying(SysMessageId::MsgAcquireForeground);\n\t\t\tmsg.data1 = 1; // ?\n\t\t\tmsg.data2 = 1; // ?\n\t\t\tOSMessageQueue* systemMessageQueue = coreinit::OSGetSystemMessageQueue();\n\t\t\tif(OSSendMessage(systemMessageQueue, &msg, 0))\n\t\t\t\ts_transitionToForeground = false;\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// called when OSReceiveMessage returns a message from the system message queue\n\tvoid HandleReceivedSystemMessage(OSMessage* msg)\n\t{\n\t\tcemu_assert_debug(!__OSHasSchedulerLock());\n\t\tcemuLog_log(LogType::Force, \"Receiving message: {:08x}\", (uint32)msg->data0);\n\t}\n\n\tuint32 OSDriver_Register(uint32 moduleHandle, sint32 priority, OSDriverInterface* driverCallbacks, sint32 driverId, uint32be* outUkn1, uint32be* outUkn2, uint32be* outUkn3)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"OSDriver_Register stubbed\");\n\t\treturn 0;\n\t}\n\n\tuint32 OSDriver_Deregister(uint32 moduleHandle, sint32 driverId)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"OSDriver_Deregister stubbed\");\n\t\treturn 0;\n\t}\n\n\tvoid miscInit()\n\t{\n\t\ts_currentTitleId = CafeSystem::GetForegroundTitleId();\n\t\ts_sdkVersion = CafeSystem::GetForegroundTitleSDKVersion();\n\t\ts_transitionToBackground = false;\n\t\ts_transitionToForeground = false;\n\n\t\tcafeExportRegister(\"coreinit\", __os_snprintf, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", COSVReport, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", COSWarn, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSReport, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSVReport, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSLogPrintf, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSConsoleWrite, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", OSGetPFID, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSGetUPID, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSGetTitleID, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __OSGetProcessSDKVersion, LogType::Placeholder);\n\n\t\tg_homeButtonMenuEnabled = true; // enabled by default\n\t\t// Disney Infinity 2.0 actually relies on home button menu being enabled by default. If it's false it will crash due to calling erreula->IsAppearHomeNixSign() before initializing erreula\n\t\tcafeExportRegister(\"coreinit\", OSIsHomeButtonMenuEnabled, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSEnableHomeButtonMenu, LogType::CoreinitThread);\n\n\t\tcafeExportRegister(\"coreinit\", OSLaunchTitleByPathl, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSRestartGame, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", OSReleaseForeground, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", OSDriver_Register, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSDriver_Deregister, LogType::Placeholder);\n\t}\n\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Misc.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tuint32 OSGetUPID();\n\tuint32 OSGetPFID();\n\tuint64 OSGetTitleID();\n\tuint32 __OSGetProcessSDKVersion();\n\tuint32 OSLaunchTitleByPathl(const char* path, uint32 pathLength, uint32 argc);\n\tuint32 OSRestartGame(uint32 argc, MEMPTR<char>* argv);\n\n\tvoid OSReleaseForeground();\n\n\tvoid StartBackgroundForegroundTransition();\n\n\tstruct OSDriverInterface\n\t{\n\t\tMEMPTR<void> getDriverName;\n\t\tMEMPTR<void> init;\n\t\tMEMPTR<void> onAcquireForeground;\n\t\tMEMPTR<void> onReleaseForeground;\n\t\tMEMPTR<void> done;\n\t};\n\tstatic_assert(sizeof(OSDriverInterface) == 0x14);\n\n\tuint32 OSDriver_Register(uint32 moduleHandle, sint32 priority, OSDriverInterface* driverCallbacks, sint32 driverId, uint32be* outUkn1, uint32be* outUkn2, uint32be* outUkn3);\n\tuint32 OSDriver_Deregister(uint32 moduleHandle, sint32 driverId);\n\n\tenum class COSReportModule\n\t{\n\t\tcoreinit = 0,\n\t};\n\n\tenum class COSReportLevel\n\t{\n\t\tError = 0,\n\t\tWarn = 1,\n\t\tInfo = 2\n\t};\n\n\tsint32 ppc_vprintf(const char* formatStr, char* strOut, sint32 maxLength, ppc_va_list* vargs);\n\n\tvoid miscInit();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_OSScreen.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n\n#include \"Cafe/OS/libs/coreinit/coreinit_OSScreen_font.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_OSScreen.h\"\n\n#define OSSCREEN_TV\t\t(0)\n#define OSSCREEN_DRC\t(1)\n\nnamespace coreinit\n{\n\n\tstruct\n\t{\n\t\tsint32 x;\n\t\tsint32 y;\n\t\tsint32 pitch;\n\t}screenSizes[2] =\n\t{\n\t\t{ 1280, 720, 1280}, // TV\n\t\t{ 896, 480, 896 } // DRC (values might be incorrect)\n\t};\n\n\tvoid* currentScreenBasePtr[2] = { 0 };\n\n\tvoid _OSScreen_Clear(uint32 screenIndex, uint32 color)\n\t{\n\t\tif (!currentScreenBasePtr[screenIndex])\n\t\t\treturn;\n\n\t\tuint32* output = (uint32*)currentScreenBasePtr[screenIndex];\n\t\tsint32 sizeInPixels = screenSizes[screenIndex].pitch * screenSizes[screenIndex].y;\n\t\tcolor = _swapEndianU32(color);\n\t\tfor (sint32 i = 0; i < sizeInPixels; i++)\n\t\t{\n\t\t\t*output = color;\n\t\t\toutput++;\n\t\t}\n\t}\n\n\tvoid coreinitExport_OSScreenInit(PPCInterpreter_t* hCPU)\n\t{\n\t\t// todo - init VI registers?\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid coreinitExport_OSScreenGetBufferSizeEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(screenIndex, 0);\n\t\tcemu_assert(screenIndex < 2);\n\t\tuint32 bufferSize = screenSizes[screenIndex].pitch * screenSizes[screenIndex].y * 4 * 2;\n\t\tosLib_returnFromFunction(hCPU, bufferSize);\n\t}\n\n\tvoid _updateCurrentDrawScreen(sint32 screenIndex)\n\t{\n\t\tuint32 screenDataSize = screenSizes[screenIndex].pitch * screenSizes[screenIndex].y * 4;\n\n\t\tif ((LatteGPUState.osScreen.screen[screenIndex].flipRequestCount & 1) != 0)\n\t\t\tcurrentScreenBasePtr[screenIndex] = memory_getPointerFromPhysicalOffset(LatteGPUState.osScreen.screen[screenIndex].physPtr + screenDataSize);\n\t\telse\n\t\t\tcurrentScreenBasePtr[screenIndex] = memory_getPointerFromPhysicalOffset(LatteGPUState.osScreen.screen[screenIndex].physPtr);\n\t}\n\n\tvoid coreinitExport_OSScreenSetBufferEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(screenIndex, 0);\n\t\tppcDefineParamU32(buffer, 1);\n\t\tcemu_assert(screenIndex < 2);\n\t\tLatteGPUState.osScreen.screen[screenIndex].physPtr = buffer;\n\t\t_updateCurrentDrawScreen(screenIndex);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid coreinitExport_OSScreenEnableEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(screenIndex, 0);\n\t\tppcDefineParamU32(isEnabled, 1);\n\t\tcemu_assert(screenIndex < 2);\n\t\tLatteGPUState.osScreen.screen[screenIndex].isEnabled = isEnabled != 0;\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid coreinitExport_OSScreenClearBufferEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(screenIndex, 0);\n\t\tppcDefineParamU32(color, 1);\n\t\tcemu_assert(screenIndex < 2);\n\t\t_OSScreen_Clear(screenIndex, color);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid coreinitExport_OSScreenFlipBuffersEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(screenIndex, 0);\n\t\tcemu_assert(screenIndex < 2);\n\t\tLatteGPUState.osScreen.screen[screenIndex].flipRequestCount++;\n\t\t_updateCurrentDrawScreen(screenIndex);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid coreinitExport_OSScreenPutPixelEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(screenIndex, 0);\n\t\tppcDefineParamS32(x, 1);\n\t\tppcDefineParamS32(y, 2);\n\t\tppcDefineParamU32(color, 3);\n\t\tif (screenIndex >= 2)\n\t\t{\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\treturn;\n\t\t}\n\t\tif (x >= 0 && x < screenSizes[screenIndex].x && y >= 0 && y < screenSizes[screenIndex].y)\n\t\t{\n\t\t\t*(uint32*)((uint8*)currentScreenBasePtr[screenIndex] + (x + y * screenSizes[screenIndex].pitch) * 4) = _swapEndianS32(color);\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tconst char* osScreenCharset = \"!\\\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\";\n\n\tsint32 _getOSScreenFontCharIndex(char c)\n\t{\n\t\tconst char* charset = osScreenCharset;\n\t\twhile (*charset)\n\t\t{\n\t\t\tif (*charset == c)\n\t\t\t{\n\t\t\t\treturn (sint32)(charset - osScreenCharset);\n\t\t\t}\n\t\t\tcharset++;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tvoid coreinitExport_OSScreenPutFontEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(screenIndex, 0);\n\t\tppcDefineParamS32(x, 1);\n\t\tppcDefineParamS32(y, 2);\n\t\tppcDefineParamStr(str, 3);\n\n\t\t// characters are:\n\t\t// 16 x 32 (including the margin)\n\t\t// with a margin of 4 x 8\n\n\t\tif (y < 0)\n\t\t{\n\t\t\tdebug_printf(\"OSScreenPutFontEx: y has invalid value\\n\");\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\treturn;\n\t\t}\n\n\t\tsint32 px = x * 16;\n\t\tsint32 py = y * 24;\n\n\t\twhile (*str)\n\t\t{\n\t\t\tsint32 charIndex = _getOSScreenFontCharIndex(*str);\n\t\t\tif (charIndex >= 0)\n\t\t\t{\n\t\t\t\tconst uint8* charBitmap = osscreenBitmapFont + charIndex * 50;\n\t\t\t\tfor (sint32 fy = 0; fy < 25; fy++)\n\t\t\t\t{\n\t\t\t\t\tfor (sint32 fx = 0; fx < 14; fx++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (((charBitmap[(fx / 8) + (fy) * 2] >> (7 - (fx & 7))) & 1) == 0)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t*(uint32*)((uint8*)currentScreenBasePtr[screenIndex] + ((px + fx) + (py + fy) * screenSizes[screenIndex].pitch) * 4) = 0xFFFFFFFF;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tpx += 16;\n\t\t\tstr++;\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid InitializeOSScreen()\n\t{\n\t\tosLib_addFunction(\"coreinit\", \"OSScreenInit\", coreinitExport_OSScreenInit);\n\t\tosLib_addFunction(\"coreinit\", \"OSScreenGetBufferSizeEx\", coreinitExport_OSScreenGetBufferSizeEx);\n\t\tosLib_addFunction(\"coreinit\", \"OSScreenSetBufferEx\", coreinitExport_OSScreenSetBufferEx);\n\t\tosLib_addFunction(\"coreinit\", \"OSScreenEnableEx\", coreinitExport_OSScreenEnableEx);\n\t\tosLib_addFunction(\"coreinit\", \"OSScreenClearBufferEx\", coreinitExport_OSScreenClearBufferEx);\n\t\tosLib_addFunction(\"coreinit\", \"OSScreenFlipBuffersEx\", coreinitExport_OSScreenFlipBuffersEx);\n\t\tosLib_addFunction(\"coreinit\", \"OSScreenPutPixelEx\", coreinitExport_OSScreenPutPixelEx);\n\t\tosLib_addFunction(\"coreinit\", \"OSScreenPutFontEx\", coreinitExport_OSScreenPutFontEx);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_OSScreen.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tvoid InitializeOSScreen();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_OSScreen_font.h",
    "content": "\n// font 'More Perfect DOS VGA' 20pts\nconst uint8 osscreenBitmapFont[] =\n{\n// @0 '!' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @50 '\"' (14 pixels wide)\n0x00, 0x00, //               \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x18, 0xC0, //    ##   ##    \n0x18, 0xC0, //    ##   ##    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @100 '#' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0xFF, 0xF0, // ############  \n0xFF, 0xF0, // ############  \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0xFF, 0xF0, // ############  \n0xFF, 0xF0, // ############  \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @150 '$' (14 pixels wide)\n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0xE0, 0xE0, // ###     ###   \n0xE0, 0x60, // ###      ##   \n0xE0, 0x60, // ###      ##   \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0x3F, 0x80, //   #######     \n0x38, 0xA0, //   ###   # #   \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0xC0, 0xE0, // ##      ###   \n0xC0, 0xE0, // ##      ###   \n0xE0, 0xE0, // ###     ###   \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @200 '%' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x20, // ###       #   \n0xF0, 0xF0, // ####    ####  \n0xF0, 0xF0, // ####    ####  \n0x01, 0xE0, //        ####   \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x1E, 0x00, //    ####       \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0xF0, 0xE0, // ####    ###   \n0xC0, 0xF0, // ##      ####  \n0xC0, 0xF0, // ##      ####  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @250 '&' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x1F, 0x00, //    #####      \n0x1F, 0x00, //    #####      \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x1F, 0x00, //    #####      \n0x1F, 0x00, //    #####      \n0x3E, 0xE0, //   ##### ###   \n0xB7, 0xE0, // # ## ######   \n0xE7, 0xC0, // ###  #####    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0x3E, 0xE0, //   ##### ###   \n0x3E, 0xE0, //   ##### ###   \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @300 ''' (14 pixels wide)\n0x00, 0x00, //               \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @350 '(' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x07, 0x00, //      ###      \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x07, 0x00, //      ###      \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @400 ')' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x07, 0x00, //      ###      \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x07, 0x00, //      ###      \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @450 '*' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x1F, 0xC0, //    #######    \n0xFF, 0xF8, // ############# \n0xFF, 0xF8, // ############# \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @500 '+' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x3F, 0xE0, //   #########   \n0x3F, 0xE0, //   #########   \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @550 ',' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @600 '-' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xF0, // ############  \n0xFF, 0xF0, // ############  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @650 '.' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @700 '/' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x20, //           #   \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x01, 0xC0, //        ###    \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x0E, 0x00, //     ###       \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0xF0, 0x00, // ####          \n0xC0, 0x00, // ##            \n0xC0, 0x00, // ##            \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @750 '0' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x38, 0xE0, //   ###   ###   \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0x38, 0xE0, //   ###   ###   \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @800 '1' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x0F, 0x80, //     #####     \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x3F, 0xF0, //   ##########  \n0x3F, 0xF0, //   ##########  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @850 '2' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x00, 0xE0, //         ###   \n0x03, 0x80, //       ###     \n0x03, 0x80, //       ###     \n0x07, 0x00, //      ###      \n0x1C, 0x00, //    ###        \n0x1C, 0x00, //    ###        \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0xE0, // ###     ###   \n0xFF, 0xE0, // ###########   \n0xFF, 0xE0, // ###########   \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @900 '3' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x1F, 0xC0, //    #######    \n0x1C, 0x50, //    ###   # #  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @950 '4' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x07, 0xC0, //      #####    \n0x07, 0xC0, //      #####    \n0x1F, 0xC0, //    #######    \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0xE1, 0xC0, // ###    ###    \n0xFF, 0xF0, // ############  \n0xFF, 0xF0, // ############  \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x07, 0xF0, //      #######  \n0x07, 0xF0, //      #######  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1000 '5' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xE0, // ###########   \n0xFF, 0xE0, // ###########   \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xFF, 0x80, // #########     \n0xF0, 0xA0, // ####    # #   \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1050 '6' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x1F, 0x80, //    ######     \n0x1F, 0x80, //    ######     \n0x38, 0x00, //   ###         \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xFF, 0xC0, // ##########    \n0xFF, 0xC0, // ##########    \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1100 '7' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xE0, // ###########   \n0xFF, 0xE0, // ###########   \n0xE0, 0xE0, // ###     ###   \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x03, 0x80, //       ###     \n0x07, 0x80, //      ####     \n0x07, 0x00, //      ###      \n0x1C, 0x00, //    ###        \n0x1C, 0x00, //    ###        \n0x1C, 0x00, //    ###        \n0x1C, 0x00, //    ###        \n0x1C, 0x00, //    ###        \n0x1C, 0x00, //    ###        \n0x1C, 0x00, //    ###        \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1150 '8' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x3F, 0x80, //   #######     \n0xA7, 0xC0, // # #  #####    \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1200 '9' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x3F, 0xF0, //   ##########  \n0x3F, 0xF0, //   ##########  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1250 ':' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1300 ';' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1350 '<' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x01, 0xC0, //        ###    \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x0E, 0x00, //     ###       \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x1C, 0x00, //    ###        \n0x0E, 0x00, //     ###       \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x01, 0xC0, //        ###    \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1400 '=' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0xF0, //   ##########  \n0x3F, 0xF0, //   ##########  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0xF0, //   ##########  \n0x3F, 0xF0, //   ##########  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1450 '>' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x0E, 0x00, //     ###       \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x01, 0xC0, //        ###    \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x00, 0xE0, //         ###   \n0x01, 0xC0, //        ###    \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x0E, 0x00, //     ###       \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1500 '?' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1550 '@' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE7, 0xF0, // ###  #######  \n0xE7, 0xF0, // ###  #######  \n0xE7, 0xF0, // ###  #######  \n0xE7, 0xF0, // ###  #######  \n0xE7, 0xF0, // ###  #######  \n0xE7, 0xC0, // ###  #####    \n0xE7, 0xC0, // ###  #####    \n0xE0, 0x00, // ###           \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1600 'A' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x06, 0x00, //      ##       \n0x06, 0x00, //      ##       \n0x1F, 0x80, //    ######     \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xFF, 0xF0, // ############  \n0xFF, 0xF0, // ############  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1650 'B' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xC0, // ##########    \n0xFF, 0xC0, // ##########    \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0xFF, 0xC0, // ##########    \n0xFF, 0xC0, // ##########    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1700 'C' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x38, 0x70, //   ###    ###  \n0xE0, 0x30, // ###       ##  \n0xE0, 0x30, // ###       ##  \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x30, // ###       ##  \n0xE0, 0x30, // ###       ##  \n0x38, 0x70, //   ###    ###  \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1750 'D' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0x80, // #########     \n0xFF, 0x80, // #########     \n0x39, 0xC0, //   ###  ###    \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x39, 0xC0, //   ###  ###    \n0xFF, 0x80, // #########     \n0xFF, 0x80, // #########     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1800 'E' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xF0, // ############  \n0xFF, 0xF0, // ############  \n0x38, 0x70, //   ###    ###  \n0x38, 0x30, //   ###     ##  \n0x38, 0x30, //   ###     ##  \n0x39, 0x80, //   ###  ##     \n0x39, 0x80, //   ###  ##     \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x39, 0x80, //   ###  ##     \n0x39, 0x80, //   ###  ##     \n0x38, 0x00, //   ###         \n0x38, 0x30, //   ###     ##  \n0x38, 0x30, //   ###     ##  \n0x38, 0x70, //   ###    ###  \n0xFF, 0xF0, // ############  \n0xFF, 0xF0, // ############  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1850 'F' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xF0, // ############  \n0xFF, 0xF0, // ############  \n0x38, 0x70, //   ###    ###  \n0x38, 0x30, //   ###     ##  \n0x38, 0x30, //   ###     ##  \n0x39, 0x80, //   ###  ##     \n0x39, 0x80, //   ###  ##     \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x39, 0x80, //   ###  ##     \n0x39, 0x80, //   ###  ##     \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0xFE, 0x00, // #######       \n0xFE, 0x00, // #######       \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1900 'G' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x38, 0xF0, //   ###   ####  \n0xE0, 0x30, // ###       ##  \n0xE0, 0x20, // ###       #   \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE7, 0xF0, // ###  #######  \n0xE7, 0xF0, // ###  #######  \n0xE0, 0xF0, // ###     ####  \n0xE0, 0xF0, // ###     ####  \n0xE0, 0xF0, // ###     ####  \n0xE0, 0xE0, // ###     ###   \n0x38, 0xE0, //   ###   ###   \n0x1F, 0x20, //    #####  #   \n0x1F, 0x20, //    #####  #   \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @1950 'H' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xFF, 0xE0, // ###########   \n0xFF, 0xE0, // ###########   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2000 'I' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2050 'J' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0xF0, //      #######  \n0x07, 0xF0, //      #######  \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0x3F, 0x00, //   ######      \n0x3F, 0x00, //   ######      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2100 'K' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xF8, 0x70, // #####    ###  \n0xF8, 0x70, // #####    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0xF8, 0x70, // #####    ###  \n0xF8, 0x70, // #####    ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2150 'L' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFE, 0x00, // #######       \n0xFE, 0x00, // #######       \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x30, //   ###     ##  \n0x38, 0x30, //   ###     ##  \n0x38, 0x70, //   ###    ###  \n0xFF, 0xF0, // ############  \n0xFF, 0xF0, // ############  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2200 'M' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xF8, 0xF8, // #####   ##### \n0xF8, 0xF8, // #####   ##### \n0xFF, 0xF8, // ############# \n0xFF, 0xF8, // ############# \n0xFF, 0xF8, // ############# \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2250 'N' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xF8, 0x70, // #####    ###  \n0xFE, 0x70, // #######  ###  \n0xFE, 0x70, // #######  ###  \n0xFF, 0xF0, // ############  \n0xFF, 0xF0, // ############  \n0xE7, 0xF0, // ###  #######  \n0xE7, 0xF0, // ###  #######  \n0xE1, 0xF0, // ###    #####  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2300 'O' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2350 'P' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xC0, // ##########    \n0xFF, 0xC0, // ##########    \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0xFE, 0x00, // #######       \n0xFE, 0x00, // #######       \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2400 'Q' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE6, 0x70, // ###  ##  ###  \n0xE7, 0xF0, // ###  #######  \n0xE7, 0xF0, // ###  #######  \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x01, 0xC0, //        ###    \n0x01, 0xF0, //        #####  \n0x01, 0xF0, //        #####  \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2450 'R' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xC0, // ##########    \n0xFF, 0xC0, // ##########    \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x39, 0xC0, //   ###  ###    \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0xF8, 0x70, // #####    ###  \n0xF8, 0x70, // #####    ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2500 'S' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x1F, 0x80, //    ######     \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2550 'T' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xFC, // ##############\n0xFF, 0xFC, // ##############\n0xE7, 0x3C, // ###  ###  ####\n0xE7, 0x0C, // ###  ###    ##\n0xC7, 0x0C, // ##   ###    ##\n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2600 'U' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2650 'V' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x1F, 0xC0, //    #######    \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2700 'W' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xFF, 0xF8, // ############# \n0xFF, 0xF8, // ############# \n0xF8, 0xF8, // #####   ##### \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2750 'X' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x3F, 0xF0, //   ##########  \n0x3F, 0xF0, //   ##########  \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x3F, 0xF0, //   ##########  \n0x3F, 0xF0, //   ##########  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2800 'Y' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x3C, // ###       ####\n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0x38, 0xF0, //   ###   ####  \n0x38, 0xF0, //   ###   ####  \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2850 'Z' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xFC, // ##############\n0xFF, 0xF8, // ############# \n0xE0, 0x38, // ###       ### \n0xE0, 0xF0, // ###     ####  \n0xC0, 0xF0, // ##      ####  \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x1E, 0x00, //    ####       \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0xE0, 0x0C, // ###         ##\n0xE0, 0x0C, // ###         ##\n0xE0, 0x3C, // ###       ####\n0xFF, 0xFC, // ##############\n0xFF, 0xFC, // ##############\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2900 '[' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x0F, 0xE0, //     #######   \n0x0F, 0xE0, //     #######   \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0F, 0xE0, //     #######   \n0x0F, 0xE0, //     #######   \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @2950 '\\' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xC0, 0x00, // ##            \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xF8, 0x00, // #####         \n0xF8, 0x00, // #####         \n0x3E, 0x00, //   #####       \n0x3F, 0x80, //   #######     \n0x1F, 0x80, //    ######     \n0x07, 0xC0, //      #####    \n0x07, 0xC0, //      #####    \n0x01, 0xF0, //        #####  \n0x01, 0xF0, //        #####  \n0x00, 0x70, //          ###  \n0x00, 0x30, //           ##  \n0x00, 0x30, //           ##  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3000 ']' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3050 '^' (14 pixels wide)\n0x06, 0x00, //      ##       \n0x06, 0x00, //      ##       \n0x1F, 0x80, //    ######     \n0x39, 0xC0, //   ###  ###    \n0xA9, 0x60, // # # #  # ##   \n0xE0, 0x70, // ###      ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3100 '_' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xFC, // ##############\n0xFF, 0xFC, // ##############\n0x00, 0x00, //               \n\n// @3150 '`' (14 pixels wide)\n0x00, 0x00, //               \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x07, 0x00, //      ###      \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3200 'a' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x01, 0xC0, //        ###    \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0x3E, 0x70, //   #####  ###  \n0x3E, 0x70, //   #####  ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3250 'b' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xF8, 0x00, // #####         \n0xF8, 0x00, // #####         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x39, 0xC0, //   ###  ###    \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3300 'c' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3350 'd' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0xC0, //      #####    \n0x07, 0xC0, //      #####    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x39, 0xC0, //   ###  ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0x3E, 0x70, //   #####  ###  \n0x3E, 0x70, //   #####  ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3400 'e' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0xE0, 0xE0, // ###     ###   \n0xFF, 0xE0, // ###########   \n0xFF, 0xE0, // ###########   \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0x00, // ###           \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3450 'f' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0xC0, //      #####    \n0x07, 0xC0, //      #####    \n0x0E, 0x70, //     ###  ###  \n0x0E, 0x30, //     ###   ##  \n0x0E, 0x30, //     ###   ##  \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3500 'g' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3E, 0x70, //   #####  ###  \n0x3E, 0x70, //   #####  ###  \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x01, 0xC0, //        ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n\n// @3550 'h' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xF8, 0x00, // #####         \n0xF8, 0x00, // #####         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x3E, 0x70, //   #####  ###  \n0x3E, 0x70, //   #####  ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0xF8, 0x70, // #####    ###  \n0xF8, 0x70, // #####    ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3600 'i' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x1F, 0x00, //    #####      \n0x1F, 0x00, //    #####      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3650 'j' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x01, 0xF0, //        #####  \n0x01, 0xF0, //        #####  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x0F, 0xC0, //     ######    \n0x0F, 0xC0, //     ######    \n\n// @3700 'k' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xF8, 0x00, // #####         \n0xF8, 0x00, // #####         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x39, 0xC0, //   ###  ###    \n0x3F, 0xC0, //   ########    \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x39, 0xC0, //   ###  ###    \n0x39, 0xC0, //   ###  ###    \n0x38, 0x70, //   ###    ###  \n0xF8, 0x70, // #####    ###  \n0xF8, 0x70, // #####    ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3750 'l' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x1F, 0x00, //    #####      \n0x1F, 0x00, //    #####      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3800 'm' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xF8, 0xE0, // #####   ###   \n0xF8, 0xE0, // #####   ###   \n0xFF, 0xF8, // ############# \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3850 'n' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE7, 0xC0, // ###  #####    \n0xE7, 0xC0, // ###  #####    \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3900 'o' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0xE0, 0xE0, // ###     ###   \n0x3F, 0x80, //   #######     \n0x3F, 0x80, //   #######     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @3950 'p' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE7, 0xC0, // ###  #####    \n0xE7, 0xC0, // ###  #####    \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0xFE, 0x00, // #######       \n0xFE, 0x00, // #######       \n\n// @4000 'q' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3E, 0x70, //   #####  ###  \n0x3E, 0x70, //   #####  ###  \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x01, 0xC0, //        ###    \n0x07, 0xF0, //      #######  \n0x07, 0xF0, //      #######  \n\n// @4050 'r' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE7, 0xC0, // ###  #####    \n0xE7, 0xC0, // ###  #####    \n0x3E, 0x70, //   #####  ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x70, //   ###    ###  \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0xFE, 0x00, // #######       \n0xFE, 0x00, // #######       \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4100 's' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x38, 0x00, //   ###         \n0x1F, 0x80, //    ######     \n0x1F, 0x80, //    ######     \n0x01, 0xC0, //        ###    \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x3F, 0xC0, //   ########    \n0x3F, 0xC0, //   ########    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4150 't' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x06, 0x00, //      ##       \n0x06, 0x00, //      ##       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x7F, 0xC0, //  #########    \n0x7F, 0xC0, //  #########    \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x00, //     ###       \n0x0E, 0x70, //     ###  ###  \n0x0E, 0x70, //     ###  ###  \n0x07, 0xC0, //      #####    \n0x07, 0xC0, //      #####    \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4200 'u' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0xE1, 0xC0, // ###    ###    \n0x3E, 0x70, //   #####  ###  \n0x3E, 0x70, //   #####  ###  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4250 'v' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x3C, // ###       ####\n0xE0, 0x3C, // ###       ####\n0xE0, 0x3C, // ###       ####\n0xE0, 0x3C, // ###       ####\n0xE0, 0x3C, // ###       ####\n0xE0, 0x3C, // ###       ####\n0xE0, 0x3C, // ###       ####\n0x38, 0xF0, //   ###   ####  \n0x38, 0xF0, //   ###   ####  \n0x1F, 0xC0, //    #######    \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4300 'w' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xE7, 0x38, // ###  ###  ### \n0xFF, 0xF8, // ############# \n0x38, 0xE0, //   ###   ###   \n0x38, 0xE0, //   ###   ###   \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4350 'x' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0x38, 0x70, //   ###    ###  \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x1F, 0xC0, //    #######    \n0x38, 0x70, //   ###    ###  \n0xE0, 0x38, // ###       ### \n0xE0, 0x38, // ###       ### \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4400 'y' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0xE0, 0x70, // ###      ###  \n0x3F, 0xF0, //   ##########  \n0x3F, 0xF0, //   ##########  \n0x00, 0x70, //          ###  \n0x00, 0x70, //          ###  \n0x01, 0xC0, //        ###    \n0xFF, 0x80, // #########     \n0xFF, 0x80, // #########     \n\n// @4450 'z' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0xFF, 0xE0, // ###########   \n0xFF, 0xE0, // ###########   \n0xE3, 0x80, // ###   ###     \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x1C, 0x00, //    ###        \n0x1C, 0x00, //    ###        \n0x38, 0x00, //   ###         \n0x38, 0x00, //   ###         \n0xE0, 0xE0, // ###     ###   \n0xFF, 0xE0, // ###########   \n0xFF, 0xE0, // ###########   \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4500 '{' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x01, 0xF0, //        #####  \n0x01, 0xF0, //        #####  \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x3E, 0x00, //   #####       \n0x3E, 0x00, //   #####       \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x01, 0xF0, //        #####  \n0x01, 0xF0, //        #####  \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4550 '|' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4600 '}' (14 pixels wide)\n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x3E, 0x00, //   #####       \n0x3E, 0x00, //   #####       \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x01, 0xE0, //        ####   \n0x01, 0xE0, //        ####   \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x07, 0x00, //      ###      \n0x3E, 0x00, //   #####       \n0x3E, 0x00, //   #####       \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n\n// @4650 '~' (14 pixels wide)\n0x00, 0x00, //               \n0x3C, 0xE0, //   ####  ###   \n0x3C, 0xE0, //   ####  ###   \n0xE7, 0x80, // ###  ####     \n0xE7, 0x80, // ###  ####     \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n0x00, 0x00, //               \n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_OverlayArena.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"coreinit_OverlayArena.h\"\n\nnamespace coreinit\n{\n\tstruct\n\t{\n\t\tbool isEnabled;\n\t}g_coreinitOverlayArena = { 0 };\n\n\tuint32 OSIsEnabledOverlayArena()\n\t{\n\t\treturn g_coreinitOverlayArena.isEnabled ? 1 : 0;\n\t}\n\n\tvoid OSEnableOverlayArena(uint32 uknParam, uint32be* areaOffset, uint32be* areaSize)\n\t{\n\t\tif (g_coreinitOverlayArena.isEnabled == false)\n\t\t{\n\t\t\tmemory_enableOverlayArena();\n\t\t\tg_coreinitOverlayArena.isEnabled = true;\n\t\t}\n\t\t*areaOffset = MEMORY_OVERLAY_AREA_OFFSET;\n\t\t*areaSize = MEMORY_OVERLAY_AREA_SIZE;\n\t}\n\n\tvoid InitializeOverlayArena()\n\t{\n\t\tcafeExportRegister(\"coreinit\", OSIsEnabledOverlayArena, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSEnableOverlayArena, LogType::Placeholder);\n\t\tg_coreinitOverlayArena.isEnabled = false;\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_OverlayArena.h",
    "content": "namespace coreinit\n{\n\tvoid InitializeOverlayArena();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Scheduler.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"coreinit_Scheduler.h\"\n\nthread_local sint32 s_schedulerLockCount = 0;\n\n#if BOOST_OS_WINDOWS\n#include <synchapi.h>\nCRITICAL_SECTION s_csSchedulerLock;\n#else\n#include <pthread.h>\npthread_mutex_t s_ptmSchedulerLock;\n#endif\n\nvoid __OSLockScheduler(void* obj)\n{\n#if BOOST_OS_WINDOWS\n\tEnterCriticalSection(&s_csSchedulerLock);\n#else\n\tpthread_mutex_lock(&s_ptmSchedulerLock);\n#endif\n\ts_schedulerLockCount++;\n\tcemu_assert_debug(s_schedulerLockCount <= 1); // >= 2 should not happen. Scheduler lock does not allow recursion\n}\n\nbool __OSHasSchedulerLock()\n{\n\treturn s_schedulerLockCount > 0;\n}\n\nbool __OSTryLockScheduler(void* obj)\n{\n\tbool r;\n#if BOOST_OS_WINDOWS\n\tr = TryEnterCriticalSection(&s_csSchedulerLock);\n#else\n\tr = pthread_mutex_trylock(&s_ptmSchedulerLock) == 0;\n#endif\n\tif (r)\n\t{\n\t\ts_schedulerLockCount++;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nvoid __OSUnlockScheduler(void* obj)\n{\n\ts_schedulerLockCount--;\n\tcemu_assert_debug(s_schedulerLockCount >= 0);\n#if BOOST_OS_WINDOWS\n\tLeaveCriticalSection(&s_csSchedulerLock);\n#else\n\tpthread_mutex_unlock(&s_ptmSchedulerLock);\n#endif\n}\n\nnamespace coreinit\n{\n\tuint32 OSIsInterruptEnabled()\n\t{\n\t\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\t\tif (hCPU == nullptr)\n\t\t\treturn 0;\n\n\t\treturn hCPU->coreInterruptMask;\n\t}\n\n\t// disables interrupts and scheduling\n\tuint32 OSDisableInterrupts()\n\t{\n\t\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\t\tif (hCPU == nullptr)\n\t\t\treturn 0;\n\t\tuint32 prevInterruptMask = hCPU->coreInterruptMask;\n\t\tif (hCPU->coreInterruptMask != 0)\n\t\t{\n\t\t\t// we have no efficient method to turn off scheduling completely, so instead we just increase the remaining cycles\n\t\t\tif (hCPU->remainingCycles >= 0x40000000)\n\t\t\t\tcemuLog_log(LogType::Force, \"OSDisableInterrupts(): Warning - Interrupts already disabled but the mask was still set? remCycles {:08x} LR {:08x}\", hCPU->remainingCycles, hCPU->spr.LR);\n\t\t\thCPU->remainingCycles += 0x40000000;\n\t\t}\n\t\thCPU->coreInterruptMask = 0;\n\t\treturn prevInterruptMask;\n\t}\n\n\tuint32 OSRestoreInterrupts(uint32 interruptMask)\n\t{\n\t\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\t\tif (hCPU == nullptr)\n\t\t\treturn 0;\n\t\tuint32 prevInterruptMask = hCPU->coreInterruptMask;\n\t\tif (hCPU->coreInterruptMask == 0 && interruptMask != 0)\n\t\t{\n\t\t\thCPU->remainingCycles -= 0x40000000;\n\t\t}\n\t\thCPU->coreInterruptMask = interruptMask;\n\t\treturn prevInterruptMask;\n\t}\n\n\tuint32 OSEnableInterrupts()\n\t{\n\t\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\t\tuint32 prevInterruptMask = hCPU->coreInterruptMask;\n\t\tOSRestoreInterrupts(1);\n\t\treturn prevInterruptMask;\n\t}\n\n\tvoid InitializeSchedulerLock()\n\t{\n#if BOOST_OS_WINDOWS\n\t\tInitializeCriticalSection(&s_csSchedulerLock);\n#else\n\t\tpthread_mutexattr_t ma;\n\t\tpthread_mutexattr_init(&ma);\n\t\tpthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE);\n\t\tpthread_mutex_init(&s_ptmSchedulerLock, &ma);\n#endif\n\t\tcafeExportRegister(\"coreinit\", __OSLockScheduler, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", __OSUnlockScheduler, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", OSDisableInterrupts, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSEnableInterrupts, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSRestoreInterrupts, LogType::CoreinitThread);\n\t}\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Scheduler.h",
    "content": "#pragma once\n\nvoid __OSLockScheduler(void* obj = nullptr);\nbool __OSHasSchedulerLock();\nbool __OSTryLockScheduler(void* obj = nullptr);\nvoid __OSUnlockScheduler(void* obj = nullptr);\n\nnamespace coreinit\n{\n\tuint32 OSIsInterruptEnabled();\n\tuint32 OSDisableInterrupts();\n\tuint32 OSRestoreInterrupts(uint32 interruptMask);\n\tuint32 OSEnableInterrupts();\n\n\tvoid InitializeSchedulerLock();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Spinlock.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Spinlock.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n\nnamespace coreinit\n{\n\tvoid __OSBoostThread(OSThread_t* thread)\n\t{\n\t\t__OSLockScheduler();\n\t\tthread->stateFlags |= 0x20000;\n\t\tthread->context.boostCount += 1;\n\t\t__OSUpdateThreadEffectivePriority(thread); // sets thread->effectivePriority to zero since boostCount != 0\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid __OSDeboostThread(OSThread_t* thread)\n\t{\n\t\t__OSLockScheduler();\n\t\tcemu_assert_debug(thread->context.boostCount != 0);\n\t\tthread->context.boostCount -= 1;\n\t\tif (thread->context.boostCount == 0)\n\t\t{\n\t\t\tthread->stateFlags &= ~0x20000;\n\t\t\t__OSUpdateThreadEffectivePriority(thread);\n\t\t\t// todo - reschedule if lower priority than other threads on current core?\n\t\t}\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid OSInitSpinLock(OSSpinLock* spinlock)\n\t{\n\t\tspinlock->userData = spinlock;\n\t\tspinlock->ownerThread = nullptr;\n\t\tspinlock->count = 0;\n\t\tspinlock->interruptMask = 1;\n\t}\n\n\tbool OSAcquireSpinLock(OSSpinLock* spinlock)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tif (spinlock->ownerThread == currentThread)\n\t\t{\n\t\t\tspinlock->count += 1;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// loop until lock acquired\n\t\t\twhile (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread))\n\t\t\t{\n\t\t\t\tOSYieldThread();\n\t\t\t}\n\t\t}\n\t\t__OSBoostThread(currentThread);\n\t\treturn true;\n\t}\n\n\tbool OSTryAcquireSpinLock(OSSpinLock* spinlock)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tif (spinlock->ownerThread == currentThread)\n\t\t{\n\t\t\tspinlock->count += 1;\n\t\t\treturn true;\n\t\t}\n\t\t// try acquire once\n\t\tif (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread))\n\t\t\treturn false;\n\t\t__OSBoostThread(currentThread);\n\t\treturn true;\n\t}\n\n\tbool OSTryAcquireSpinLockWithTimeout(OSSpinLock* spinlock, uint64 timeout)\n\t{\n\t\t// used by CoD: Ghosts\n\t\tcemu_assert_debug((timeout >> 63) == 0); // negative?\n\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tif (spinlock->ownerThread == currentThread)\n\t\t{\n\t\t\tspinlock->count += 1;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// loop until lock acquired or timeout occurred\n\t\t\tuint64 timeoutValue = OSGetSystemTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout);\n\t\t\twhile (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread))\n\t\t\t{\n\t\t\t\tOSYieldThread();\n\t\t\t\tif (OSGetSystemTime() >= timeoutValue)\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t__OSBoostThread(currentThread);\n\t\treturn true;\n\t}\n\n\tbool OSReleaseSpinLock(OSSpinLock* spinlock)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tcemu_assert_debug(spinlock->ownerThread == currentThread);\n\t\tif (spinlock->count != 0)\n\t\t{\n\t\t\tspinlock->count -= 1;\n\t\t\treturn true;\n\t\t}\n\t\t// release spinlock\n\t\twhile (!spinlock->ownerThread.atomic_compare_exchange(currentThread, nullptr));\n\t\t__OSDeboostThread(currentThread);\n\t\treturn true;\n\t}\n\n\tbool OSUninterruptibleSpinLock_Acquire(OSSpinLock* spinlock)\n\t{\n\t\t// frequently used by VC DS\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tcemu_assert_debug(currentThread != nullptr);\n\t\tif (spinlock->ownerThread == currentThread)\n\t\t{\n\t\t\tspinlock->count += 1;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// loop until lock acquired\n\t\t\tif (coreinit::__CemuIsMulticoreMode())\n\t\t\t{\n\t\t\t\twhile (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread))\n\t\t\t\t{\n\t\t\t\t\t_mm_pause();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// we are in single-core mode and the lock will never be released unless we let other threads resume work\n\t\t\t\t// to avoid an infinite loop we have no choice but to yield the thread even it is in an uninterruptible state\n\t\t\t\tif( !OSIsInterruptEnabled() )\n\t\t\t\t\tcemuLog_logOnce(LogType::APIErrors, \"OSUninterruptibleSpinLock_Acquire(): Lock is occupied which requires a wait but current thread is already in an uninterruptible state (Avoid cascaded OSDisableInterrupts and/or OSUninterruptibleSpinLock)\");\n\t\t\t\twhile (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread))\n\t\t\t\t{\n\t\t\t\t\tOSYieldThread();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t__OSBoostThread(currentThread);\n\t\tspinlock->interruptMask = OSDisableInterrupts();\n\t\tcemu_assert_debug(spinlock->ownerThread == currentThread);\n\t\treturn true;\n\t}\n\n\tbool OSUninterruptibleSpinLock_TryAcquire(OSSpinLock* spinlock)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tif (spinlock->ownerThread == currentThread)\n\t\t{\n\t\t\tspinlock->count += 1;\n\t\t\treturn true;\n\t\t}\n\t\t// try acquire once\n\t\tif (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread))\n\t\t\treturn false;\n\t\t__OSBoostThread(currentThread);\n\t\tspinlock->interruptMask = OSDisableInterrupts();\n\t\treturn true;\n\t}\n\n\tbool OSUninterruptibleSpinLock_TryAcquireWithTimeout(OSSpinLock* spinlock, uint64 timeout)\n\t{\n\t\tcemu_assert_debug((timeout >> 63) == 0); // negative?\n\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tif (spinlock->ownerThread == currentThread)\n\t\t{\n\t\t\tspinlock->count += 1;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// loop until lock acquired or timeout occurred\n\t\t\tuint64 timeoutValue = OSGetSystemTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout);\n\t\t\twhile (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread))\n\t\t\t{\n\t\t\t\tOSYieldThread();\n\t\t\t\tif (OSGetSystemTime() >= timeoutValue)\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t__OSBoostThread(currentThread);\n\t\tspinlock->interruptMask = OSDisableInterrupts();\n\t\treturn true;\n\t}\n\n\tbool OSUninterruptibleSpinLock_Release(OSSpinLock* spinlock)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tcemu_assert_debug(spinlock->ownerThread == currentThread);\n\t\tif (spinlock->count != 0)\n\t\t{\n\t\t\tspinlock->count -= 1;\n\t\t\treturn true;\n\t\t}\n\t\t// release spinlock\n\t\tOSRestoreInterrupts(spinlock->interruptMask);\n\t\tspinlock->interruptMask = 1;\n\t\twhile (!spinlock->ownerThread.atomic_compare_exchange(currentThread, nullptr));\n\t\t__OSDeboostThread(currentThread);\n\t\treturn true;\n\t}\n\n\tvoid InitializeSpinlock()\n\t{\n\t\tcafeExportRegister(\"coreinit\", OSInitSpinLock, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSAcquireSpinLock, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSTryAcquireSpinLock, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSTryAcquireSpinLockWithTimeout, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSReleaseSpinLock, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", OSUninterruptibleSpinLock_Acquire, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSUninterruptibleSpinLock_TryAcquire, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSUninterruptibleSpinLock_TryAcquireWithTimeout, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSUninterruptibleSpinLock_Release, LogType::Placeholder);\n\t}\n#pragma endregion\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Spinlock.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tstruct OSSpinLock\n\t{\n\t\t/* +0x00 */ MEMPTR<struct OSThread_t> ownerThread;\n\t\t/* +0x04 */ MEMPTR<void> userData;\n\t\t/* +0x08 */ uint32be count;\n\t\t/* +0x0C */ uint32be interruptMask;\n\t};\n\n\tstatic_assert(sizeof(OSSpinLock) == 0x10);\n\n\tvoid InitializeSpinlock();\n\n\tvoid OSInitSpinLock(OSSpinLock* spinlock);\n\n\tbool OSAcquireSpinLock(OSSpinLock* spinlock);\n\tbool OSTryAcquireSpinLock(OSSpinLock* spinlock);\n\tbool OSTryAcquireSpinLockWithTimeout(OSSpinLock* spinlock, uint64 timeout);\n\tbool OSReleaseSpinLock(OSSpinLock* spinlock);\n\n\tbool OSUninterruptibleSpinLock_Acquire(OSSpinLock* spinlock);\n\tbool OSUninterruptibleSpinLock_TryAcquire(OSSpinLock* spinlock);\n\tbool OSUninterruptibleSpinLock_TryAcquireWithTimeout(OSSpinLock* spinlock, uint64 timeout);\n\tbool OSUninterruptibleSpinLock_Release(OSSpinLock* spinlock);\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"util/helpers/fspinlock.h\"\n\nnamespace coreinit\n{\n\t/************* OSEvent ************/\n\n\tvoid OSInitEvent(OSEvent* event, OSEvent::EVENT_STATE initialState, OSEvent::EVENT_MODE mode)\n\t{\n\t\tevent->magic = 'eVnT';\n\t\tcemu_assert_debug(event->magic == 0x65566e54);\n\t\tevent->userData = nullptr;\n\t\tevent->ukn08 = 0;\n\t\tevent->state = initialState;\n\t\tevent->mode = mode;\n\t\tOSInitThreadQueueEx(&event->threadQueue, event);\n\t}\n\n\tvoid OSInitEventEx(OSEvent* event, OSEvent::EVENT_STATE initialState, OSEvent::EVENT_MODE mode, void* userData)\n\t{\n\t\tOSInitEvent(event, initialState, mode);\n\t\tevent->userData = userData;\n\t}\n\n\tvoid OSResetEvent(OSEvent* event)\n\t{\n\t\t__OSLockScheduler();\n\t\tif (event->state == OSEvent::EVENT_STATE::STATE_SIGNALED)\n\t\t\tevent->state = OSEvent::EVENT_STATE::STATE_NOT_SIGNALED;\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid OSWaitEventInternal(OSEvent* event)\n\t{\n\t\tif (event->state == OSEvent::EVENT_STATE::STATE_SIGNALED)\n\t\t{\n\t\t\tif (event->mode == OSEvent::EVENT_MODE::MODE_AUTO)\n\t\t\t\tevent->state = OSEvent::EVENT_STATE::STATE_NOT_SIGNALED;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// enter wait queue\n\t\t\tevent->threadQueue.queueAndWait(OSGetCurrentThread());\n\t\t}\n\t}\n\n\tvoid OSWaitEvent(OSEvent* event)\n\t{\n\t\t__OSLockScheduler();\n\t\tOSWaitEventInternal(event);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tstruct WaitEventWithTimeoutData\n\t{\n\t\tOSThread_t* thread;\n\t\tOSThreadQueue* threadQueue;\n\t\tstd::atomic_bool hasTimeout;\n\t};\n\n\tvoid _OSWaitEventWithTimeoutHandler(uint64 currentTick, void* context)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tWaitEventWithTimeoutData* data = (WaitEventWithTimeoutData*)context;\n\t\tif (data->thread->state == OSThread_t::THREAD_STATE::STATE_WAITING)\n\t\t{\n\t\t\tdata->hasTimeout = true;\n\t\t\tdata->threadQueue->cancelWait(data->thread);\n\t\t}\n\t}\n\n\tbool OSWaitEventWithTimeout(OSEvent* event, uint64 timeout)\n\t{\n\t\t__OSLockScheduler();\n\t\tif (event->state == OSEvent::EVENT_STATE::STATE_SIGNALED)\n\t\t{\n\t\t\tif (event->mode == OSEvent::EVENT_MODE::MODE_AUTO)\n\t\t\t\tevent->state = OSEvent::EVENT_STATE::STATE_NOT_SIGNALED;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (timeout == 0)\n\t\t\t{\n\t\t\t\t// fail immediately\n\t\t\t\t__OSUnlockScheduler();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// wait and set timeout\n\n\t\t\t// workaround for a bad implementation in some Unity games (like Qube Directors Cut, see FEventWiiU::Wait)\n\t\t\t// where the the return value of OSWaitEventWithTimeout is ignored and instead the game measures the elapsed time to determine if a timeout occurred\n\t\t\tif (timeout < 0x00FFFFFFFFFFFFFFULL)\n\t\t\t\ttimeout = timeout * 98ULL / 100ULL; // 98% (we want the function to return slightly before the actual timeout)\n\n\t\t\tWaitEventWithTimeoutData data;\n\t\t\tdata.thread = OSGetCurrentThread();\n\t\t\tdata.threadQueue = &event->threadQueue;\n\t\t\tdata.hasTimeout = false;\n\t\t\tauto hostAlarm = coreinit::OSHostAlarmCreate(OSGetTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout), 0, _OSWaitEventWithTimeoutHandler, &data);\n\t\t\tevent->threadQueue.queueAndWait(OSGetCurrentThread());\n\t\t\tcoreinit::OSHostAlarmDestroy(hostAlarm);\n\t\t\tif (data.hasTimeout)\n\t\t\t{\n\t\t\t\t__OSUnlockScheduler();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\t__OSUnlockScheduler();\n\t\treturn true;\n\t}\n\n\tvoid OSSignalEventInternal(OSEvent* event)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tif (event->state == OSEvent::EVENT_STATE::STATE_SIGNALED)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tif (event->mode == OSEvent::EVENT_MODE::MODE_AUTO)\n\t\t{\n\t\t\t// in auto mode wake up one thread or if there is none then set signaled\n\t\t\tif (event->threadQueue.isEmpty())\n\t\t\t\tevent->state = OSEvent::EVENT_STATE::STATE_SIGNALED;\n\t\t\telse\n\t\t\t\tevent->threadQueue.wakeupSingleThreadWaitQueue(true);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// in manual mode wake up all threads and set to signaled\n\t\t\tevent->state = OSEvent::EVENT_STATE::STATE_SIGNALED;\n\t\t\tevent->threadQueue.wakeupEntireWaitQueue(true);\n\t\t}\n\t}\n\n\tvoid OSSignalEvent(OSEvent* event)\n\t{\n\t\t__OSLockScheduler();\n\t\tOSSignalEventInternal(event);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid OSSignalEventAllInternal(OSEvent* event)\n\t{\n\t\tif (event->state == OSEvent::EVENT_STATE::STATE_SIGNALED)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tif (event->mode == OSEvent::EVENT_MODE::MODE_AUTO)\n\t\t{\n\t\t\t// in auto mode wake up one thread or if there is none then set signaled\n\t\t\tif (event->threadQueue.isEmpty())\n\t\t\t\tevent->state = OSEvent::EVENT_STATE::STATE_SIGNALED;\n\t\t\telse\n\t\t\t\tevent->threadQueue.wakeupEntireWaitQueue(true);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// in manual mode wake up all threads and set to signaled\n\t\t\tevent->state = OSEvent::EVENT_STATE::STATE_SIGNALED;\n\t\t\tevent->threadQueue.wakeupEntireWaitQueue(true);\n\t\t}\n\t}\n\n\tvoid OSSignalEventAll(OSEvent* event)\n\t{\n\t\t__OSLockScheduler();\n\t\tOSSignalEventAllInternal(event);\n\t\t__OSUnlockScheduler();\n\t}\n\n\t/************* OSRendezvous ************/\n\n\tSysAllocator<OSEvent> g_rendezvousEvent;\n\n\tvoid OSInitRendezvous(OSRendezvous* rendezvous)\n\t{\n\t\t__OSLockScheduler();\n\t\trendezvous->userData = rendezvous;\n\t\tfor (sint32 i = 0; i < PPC_CORE_COUNT; i++)\n\t\t\trendezvous->coreHit[i] = 0;\n\t\t__OSUnlockScheduler();\n\t}\n\n\tbool OSWaitRendezvous(OSRendezvous* rendezvous, uint32 coreMask)\n\t{\n\t\t__OSLockScheduler();\n\t\trendezvous->coreHit[OSGetCoreId()] = 1;\n\t\tOSSignalEventAllInternal(g_rendezvousEvent.GetPtr());\n\t\twhile (true)\n\t\t{\n\t\t\tbool metAll = true;\n\t\t\tfor(sint32 i=0; i<PPC_CORE_COUNT; i++)\n\t\t\t{ \n\t\t\t\tif( (coreMask & (1<<i)) == 0 )\n\t\t\t\t\tcontinue; // core not required by core mask\n\t\t\t\tif (rendezvous->coreHit[i] == 0)\n\t\t\t\t{\n\t\t\t\t\tmetAll = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (metAll)\n\t\t\t\tbreak;\n\t\t\tOSWaitEventInternal(g_rendezvousEvent.GetPtr());\n\t\t}\n\t\t__OSUnlockScheduler();\n\t\treturn true;\n\t}\n\n\t/************* OSMutex ************/\n\n\tvoid OSInitMutexEx(OSMutex* mutex, void* userData)\n\t{\n\t\tmutex->magic = 'mUtX';\n\t\tmutex->userData = userData;\n\t\tmutex->ukn08 = 0;\n\t\tmutex->owner = nullptr;\n\t\tmutex->lockCount = 0;\n\t\tOSInitThreadQueueEx(&mutex->threadQueue, mutex);\n\t}\n\n\tvoid OSInitMutex(OSMutex* mutex)\n\t{\n\t\tOSInitMutexEx(mutex, nullptr);\n\t}\n\n\tvoid OSLockMutexInternal(OSMutex* mutex)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tint_fast32_t failedAttempts = 0;\n\t\twhile (true)\n\t\t{\n\t\t\tif (mutex->owner == nullptr)\n\t\t\t{\n\t\t\t\t// acquire lock\n\t\t\t\tmutex->owner = currentThread;\n\t\t\t\tcemu_assert_debug(mutex->lockCount == 0);\n\t\t\t\tmutex->lockCount = 1;\n\t\t\t\t// cemu_assert_debug(mutex->next == nullptr && mutex->prev == nullptr); -> not zero initialized\n\t\t\t\tcurrentThread->mutexQueue.addMutex(mutex);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (mutex->owner == currentThread)\n\t\t\t{\n\t\t\t\tmutex->lockCount = mutex->lockCount + 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (failedAttempts >= 0x800)\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Detected long-term contested OSLockMutex\");\n\t\t\t\tcurrentThread->waitingForMutex = mutex;\n\t\t\t\tmutex->threadQueue.queueAndWait(currentThread);\n\t\t\t\tcurrentThread->waitingForMutex = nullptr;\n\t\t\t\tfailedAttempts++;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid OSLockMutex(OSMutex* mutex)\n\t{\n\t\t__OSLockScheduler();\n\t\tOSTestThreadCancelInternal();\n\t\tOSLockMutexInternal(mutex);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tbool OSTryLockMutex(OSMutex* mutex)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\t__OSLockScheduler();\n\t\tOSTestThreadCancelInternal();\n\t\tif (mutex->owner == nullptr)\n\t\t{\n\t\t\t// acquire lock\n\t\t\tmutex->owner = currentThread;\n\t\t\tcemu_assert_debug(mutex->lockCount == 0);\n\t\t\tmutex->lockCount = 1;\n\t\t\t// cemu_assert_debug(mutex->next == nullptr && mutex->prev == nullptr); -> not zero initialized\n\t\t\tcurrentThread->mutexQueue.addMutex(mutex);\n\t\t\t// currentThread->cancelState = currentThread->cancelState | 0x10000;\n\t\t}\n\t\telse if (mutex->owner == currentThread)\n\t\t{\n\t\t\tmutex->lockCount = mutex->lockCount + 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t__OSUnlockScheduler();\n\t\t\treturn false;\n\t\t}\n\t\t__OSUnlockScheduler();\n\t\treturn true;\n\t}\n\n\tvoid OSUnlockMutexInternal(OSMutex* mutex)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tcemu_assert_debug(mutex->owner == currentThread);\n\t\tcemu_assert_debug(mutex->lockCount > 0);\n\t\tmutex->lockCount = mutex->lockCount - 1;\n\t\tif (mutex->lockCount == 0)\n\t\t{\n\t\t\tcurrentThread->mutexQueue.removeMutex(mutex);\n\t\t\tmutex->owner = nullptr;\n\t\t\tif (!mutex->threadQueue.isEmpty())\n\t\t\t\tmutex->threadQueue.wakeupSingleThreadWaitQueue(true, true);\n\t\t}\n\t\t// currentThread->cancelState = currentThread->cancelState & ~0x10000;\n\t}\n\n\tvoid OSUnlockMutex(OSMutex* mutex)\n\t{\n\t\t__OSLockScheduler();\n\t\tOSUnlockMutexInternal(mutex);\n\t\t__OSUnlockScheduler();\n\t}\n\n\t/************* OSCond ************/\n\n\tvoid OSInitCond(OSCond* cond)\n\t{\n\t\tcond->magic = 0x634e6456;\n\t\tcond->userData = nullptr;\n\t\tcond->ukn08 = 0;\n\t\tOSInitThreadQueueEx(&cond->threadQueue, cond);\n\t}\n\n\tvoid OSInitCondEx(OSCond* cond, void* userData)\n\t{\n\t\tOSInitCond(cond);\n\t\tcond->userData = userData;\n\t}\n\n\tvoid OSSignalCond(OSCond* cond)\n\t{\n\t\tOSWakeupThread(&cond->threadQueue);\n\t}\n\n\tvoid OSWaitCond(OSCond* cond, OSMutex* mutex)\n\t{\n\t\t// seen in Bayonetta 2\n\t\t// releases the mutex while waiting for the condition to be signaled\n\t\t__OSLockScheduler();\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tcemu_assert_debug(mutex->owner == currentThread);\n\t\tsint32 prevLockCount = mutex->lockCount;\n\t\t// unlock mutex\n\t\tmutex->lockCount = 0;\n\t\tcurrentThread->mutexQueue.removeMutex(mutex);\n\t\tmutex->owner = nullptr;\n\t\tif (!mutex->threadQueue.isEmpty())\n\t\t\tmutex->threadQueue.wakeupEntireWaitQueue(false);\n\t\t// wait on condition\n\t\tcond->threadQueue.queueAndWait(currentThread);\n\t\t// reacquire mutex\n\t\tOSLockMutexInternal(mutex);\n\t\tmutex->lockCount = prevLockCount;\n\t\t__OSUnlockScheduler();\n\t}\n\n\t/************* OSSemaphore ************/\n\n\tvoid OSInitSemaphoreEx(OSSemaphore* semaphore, sint32 initialCount, void* userData)\n\t{\n\t\t__OSLockScheduler();\n\t\tsemaphore->magic = 0x73506852;\n\t\tsemaphore->userData = userData;\n\t\tsemaphore->ukn08 = 0;\n\t\tsemaphore->count = initialCount;\n\t\tOSInitThreadQueueEx(&semaphore->threadQueue, semaphore);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid OSInitSemaphore(OSSemaphore* semaphore, sint32 initialCount)\n\t{\n\t\tOSInitSemaphoreEx(semaphore, initialCount, nullptr);\n\t}\n\n\tsint32 OSWaitSemaphoreInternal(OSSemaphore* semaphore)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\twhile (true)\n\t\t{\n\t\t\tsint32 prevCount = semaphore->count;\n\t\t\tif (prevCount > 0)\n\t\t\t{\n\t\t\t\tsemaphore->count = prevCount - 1;\n\t\t\t\treturn prevCount;\n\t\t\t}\n\t\t\tsemaphore->threadQueue.queueAndWait(OSGetCurrentThread());\n\t\t}\n\t}\n\n\tsint32 OSWaitSemaphore(OSSemaphore* semaphore)\n\t{\n\t\t__OSLockScheduler();\n\t\tsint32 r = OSWaitSemaphoreInternal(semaphore);\n\t\t__OSUnlockScheduler();\n\t\treturn r;\n\t}\n\n\tsint32 OSTryWaitSemaphore(OSSemaphore* semaphore)\n\t{\n\t\t__OSLockScheduler();\n\t\tsint32 prevCount = semaphore->count;\n\t\tif (prevCount > 0)\n\t\t{\n\t\t\tsemaphore->count = prevCount - 1;\n\t\t}\n\t\t__OSUnlockScheduler();\n\t\treturn prevCount;\n\t}\n\n\tsint32 OSSignalSemaphoreInternal(OSSemaphore* semaphore, bool reschedule)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tsint32 prevCount = semaphore->count;\n\t\tsemaphore->count = prevCount + 1;\n\t\tsemaphore->threadQueue.wakeupEntireWaitQueue(reschedule);\n\t\treturn prevCount;\n\t}\n\n\tsint32 OSSignalSemaphore(OSSemaphore* semaphore)\n\t{\n\t\t__OSLockScheduler();\n\t\tsint32 r = OSSignalSemaphoreInternal(semaphore, true);\n\t\t__OSUnlockScheduler();\n\t\treturn r;\n\t}\n\n\tsint32 OSGetSemaphoreCount(OSSemaphore* semaphore)\n\t{\n\t\t// seen in Assassin's Creed 4\n\t\t__OSLockScheduler();\n\t\tsint32 currentCount = semaphore->count;\n\t\t__OSUnlockScheduler();\n\t\treturn currentCount;\n\t}\n\n\t/************* OSFastMutex ************/\n\n\tvoid OSFastMutex_Init(OSFastMutex* fastMutex, void* userData)\n\t{\n\t\tfastMutex->magic = 0x664d7458;\n\t\tfastMutex->userData = userData;\n\t\tfastMutex->owner = nullptr;\n\t\tfastMutex->lockCount = 0;\n\t\tfastMutex->contendedState = 0;\n\t\tfastMutex->threadQueueSmall.head = nullptr;\n\t\tfastMutex->threadQueueSmall.tail = nullptr;\n\t\tfastMutex->ownedLink.next = nullptr;\n\t\tfastMutex->ownedLink.prev = nullptr;\n\t\tfastMutex->contendedLink.next = nullptr;\n\t\tfastMutex->contendedLink.prev = nullptr;\n\t}\n\n\tFSpinlock g_fastMutexSpinlock;\n\n\tvoid _OSFastMutex_AcquireContention(OSFastMutex* fastMutex)\n\t{\n\t\tg_fastMutexSpinlock.lock();\n\t}\n\n\tvoid _OSFastMutex_ReleaseContention(OSFastMutex* fastMutex)\n\t{\n\t\tg_fastMutexSpinlock.unlock();\n\t}\n\n\tvoid OSFastMutex_LockInternal(OSFastMutex* fastMutex)\n\t{\n\t\tcemu_assert_debug(!__OSHasSchedulerLock());\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\t_OSFastMutex_AcquireContention(fastMutex);\n\t\twhile (true)\n\t\t{\n\t\t\tif (fastMutex->owner.atomic_compare_exchange(nullptr, currentThread))//(fastMutex->owner == nullptr)\n\t\t\t{\n\t\t\t\t// acquire lock\n\t\t\t\tcemu_assert_debug(fastMutex->owner == currentThread);\n\t\t\t\tcemu_assert_debug(fastMutex->lockCount == 0);\n\t\t\t\tfastMutex->lockCount = 1;\n\n\t\t\t\t// todo - add to thread owned fast mutex queue\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (fastMutex->owner == currentThread)\n\t\t\t{\n\t\t\t\tfastMutex->lockCount = fastMutex->lockCount + 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcurrentThread->waitingForFastMutex = fastMutex;\n\t\t\t\t__OSLockScheduler();\n\t\t\t\tfastMutex->threadQueueSmall.queueOnly(currentThread);\n\t\t\t\t_OSFastMutex_ReleaseContention(fastMutex);\n\t\t\t\tPPCCore_switchToSchedulerWithLock();\n\t\t\t\tcurrentThread->waitingForFastMutex = nullptr;\n\t\t\t\t__OSUnlockScheduler();\n\t\t\t\t_OSFastMutex_AcquireContention(fastMutex);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t_OSFastMutex_ReleaseContention(fastMutex);\n\t}\n\n\tvoid OSFastMutex_Lock(OSFastMutex* fastMutex)\n\t{\n\t\tOSFastMutex_LockInternal(fastMutex);\n\t}\n\n\tbool OSFastMutex_TryLock(OSFastMutex* fastMutex)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\t_OSFastMutex_AcquireContention(fastMutex);\n\t\tif (fastMutex->owner.atomic_compare_exchange(nullptr, currentThread))\n\t\t{\n\t\t\t// acquire lock\n\t\t\tcemu_assert_debug(fastMutex->owner == currentThread);\n\t\t\tcemu_assert_debug(fastMutex->lockCount == 0);\n\t\t\tfastMutex->lockCount = 1;\n\n\t\t\t// todo - add to thread owned fast mutex queue\n\t\t}\n\t\telse if (fastMutex->owner == currentThread)\n\t\t{\n\t\t\tfastMutex->lockCount = fastMutex->lockCount + 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_OSFastMutex_ReleaseContention(fastMutex);\n\t\t\treturn false;\n\t\t}\n\t\t_OSFastMutex_ReleaseContention(fastMutex);\n\t\treturn true;\n\t}\n\n\tvoid OSFastMutex_UnlockInternal(OSFastMutex* fastMutex)\n\t{\n\t\tcemu_assert_debug(!__OSHasSchedulerLock());\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\t_OSFastMutex_AcquireContention(fastMutex);\n\t\tif (fastMutex->owner != currentThread)\n\t\t{\n\t\t\t// seen in Paper Mario Color Splash\n\t\t\t//cemuLog_log(LogType::Force, \"OSFastMutex_Unlock() called on mutex which is not owned by current thread\");\n\t\t\t_OSFastMutex_ReleaseContention(fastMutex);\n\t\t\treturn;\n\t\t}\n\t\tcemu_assert_debug(fastMutex->lockCount > 0);\n\t\tfastMutex->lockCount = fastMutex->lockCount - 1;\n\t\tif (fastMutex->lockCount == 0)\n\t\t{\n\t\t\t// set owner to null\n\t\t\tif (!fastMutex->owner.atomic_compare_exchange(currentThread, nullptr))\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false); // should never happen\n\t\t\t}\n\t\t\tif (!fastMutex->threadQueueSmall.isEmpty())\n\t\t\t{\n\t\t\t\t__OSLockScheduler();\n\t\t\t\tfastMutex->threadQueueSmall.wakeupSingleThreadWaitQueue(false);\n\t\t\t\t__OSUnlockScheduler();\n\t\t\t}\n\t\t}\n\t\t_OSFastMutex_ReleaseContention(fastMutex);\n\t}\n\n\tvoid OSFastMutex_Unlock(OSFastMutex* fastMutex)\n\t{\n\t\t//__OSLockScheduler();\n\t\tOSFastMutex_UnlockInternal(fastMutex);\n\t\t//__OSUnlockScheduler();\n\t}\n\n\t/************* OSFastCond ************/\n\n\tvoid OSFastCond_Init(OSFastCond* fastCond, void* userData)\n\t{\n\t\tfastCond->magic = 0x664e6456;\n\t\tfastCond->userData = userData;\n\t\tfastCond->ukn08 = 0;\n\t\tOSInitThreadQueueEx(&fastCond->threadQueue, fastCond);\n\t}\n\n\tvoid OSFastCond_Wait(OSFastCond* fastCond, OSFastMutex* fastMutex)\n\t{\n\t\t// releases the mutex while waiting for the condition to be signaled\n\t\t__OSLockScheduler();\n\t\tcemu_assert_debug(fastMutex->owner == OSGetCurrentThread());\n\t\tsint32 prevLockCount = fastMutex->lockCount;\n\t\t// unlock mutex\n\t\tfastMutex->lockCount = 0;\n\t\tfastMutex->owner = nullptr;\n\t\tif (!fastMutex->threadQueueSmall.isEmpty())\n\t\t\tfastMutex->threadQueueSmall.wakeupEntireWaitQueue(false);\n\t\t// wait on condition\n\t\tfastCond->threadQueue.queueAndWait(OSGetCurrentThread());\n\t\t// reacquire mutex\n\t\t__OSUnlockScheduler();\n\t\tOSFastMutex_LockInternal(fastMutex);\n\t\tfastMutex->lockCount = prevLockCount;\n\t}\n\n\tvoid OSFastCond_Signal(OSFastCond* fastCond)\n\t{\n\t\tOSWakeupThread(&fastCond->threadQueue);\n\t}\n\n\t/************* init ************/\n\n\tvoid InitializeConcurrency()\n\t{\n\t\tOSInitEvent(g_rendezvousEvent.GetPtr(), OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_AUTO);\n\n\t\t// OSEvent\n\t\tcafeExportRegister(\"coreinit\", OSInitEvent, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSInitEventEx, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSResetEvent, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSWaitEvent, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSWaitEventWithTimeout, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSSignalEvent, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSSignalEventAll, LogType::CoreinitThreadSync);\n\n\t\t// OSRendezvous\n\t\tcafeExportRegister(\"coreinit\", OSInitRendezvous, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSWaitRendezvous, LogType::CoreinitThreadSync);\n\n\t\t// OSMutex\n\t\tcafeExportRegister(\"coreinit\", OSInitMutex, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSInitMutexEx, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSLockMutex, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSTryLockMutex, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSUnlockMutex, LogType::CoreinitThreadSync);\n\n\t\t// OSCond\n\t\tcafeExportRegister(\"coreinit\", OSInitCond, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSInitCondEx, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSSignalCond, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSWaitCond, LogType::CoreinitThreadSync);\n\n\t\t// OSSemaphore\n\t\tcafeExportRegister(\"coreinit\", OSInitSemaphore, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSInitSemaphoreEx, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSWaitSemaphore, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSTryWaitSemaphore, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSSignalSemaphore, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSGetSemaphoreCount, LogType::CoreinitThreadSync);\n\n\t\t// OSFastMutex\n\t\tcafeExportRegister(\"coreinit\", OSFastMutex_Init, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSFastMutex_Lock, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSFastMutex_TryLock, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSFastMutex_Unlock, LogType::CoreinitThreadSync);\n\n\t\t// OSFastCond\n\t\tcafeExportRegister(\"coreinit\", OSFastCond_Init, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSFastCond_Wait, LogType::CoreinitThreadSync);\n\t\tcafeExportRegister(\"coreinit\", OSFastCond_Signal, LogType::CoreinitThreadSync);\n\t}\n\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_SysHeap.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_SysHeap.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.h\"\n\nnamespace coreinit\n{\n\tcoreinit::MEMHeapHandle _sysHeapHandle = MPTR_NULL;\n\tsint32 _sysHeapAllocCounter = 0;\n\tsint32 _sysHeapFreeCounter = 0;\n\n\tvoid* OSAllocFromSystem(uint32 size, uint32 alignment)\n\t{\n\t\t_sysHeapAllocCounter++;\n\t\treturn coreinit::MEMAllocFromExpHeapEx(_sysHeapHandle, size, alignment);\n\t}\n\n\tvoid OSFreeToSystem(void* ptr)\n\t{\n\t\t_sysHeapFreeCounter++;\n\t\tcoreinit::MEMFreeToExpHeap(_sysHeapHandle, ptr);\n\t}\n\n\tvoid InitSysHeap()\n\t{\n\t\tuint32 sysHeapSize = 8 * 1024 * 1024; // actual size is unknown\n\t\tMEMPTR<void> heapBaseAddress = memory_getPointerFromVirtualOffset(coreinit_allocFromSysArea(sysHeapSize, 0x1000));\n\t\t_sysHeapHandle = coreinit::MEMCreateExpHeapEx(heapBaseAddress.GetPtr(), sysHeapSize, MEM_HEAP_OPTION_THREADSAFE);\n\t\t_sysHeapAllocCounter = 0;\n\t\t_sysHeapFreeCounter = 0;\n\t}\n\n\tvoid InitializeSysHeap()\n\t{\n\t\tcafeExportRegister(\"h264\", OSAllocFromSystem, LogType::CoreinitMem);\n\t\tcafeExportRegister(\"h264\", OSFreeToSystem, LogType::CoreinitMem);\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_SysHeap.h",
    "content": "#pragma once\n\nnamespace coreinit\n{\n\tvoid InitSysHeap();\n\n\tvoid* OSAllocFromSystem(uint32 size, uint32 alignment);\n\tvoid OSFreeToSystem(void* ptr);\n\n\tvoid InitializeSysHeap();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_SystemInfo.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_SystemInfo.h\"\n\nnamespace coreinit\n{\n\tSysAllocator<OSSystemInfo> g_system_info;\n\n\tconst OSSystemInfo& OSGetSystemInfo()\n\t{\n\t\treturn *g_system_info.GetPtr();\n\t}\n\n\tvoid InitializeSystemInfo()\n\t{\n\t\tcemu_assert(ppcCyclesSince2000 != 0);\n\t\tg_system_info->busClock = ESPRESSO_BUS_CLOCK;\n\t\tg_system_info->coreClock = ESPRESSO_CORE_CLOCK;\n\t\tg_system_info->ticksSince2000 = ESPRESSO_CORE_CLOCK_TO_TIMER_CLOCK(ppcCyclesSince2000);\n\t\tg_system_info->l2cacheSize[0] = 512*1024; // 512KB // 512KB\n\t\tg_system_info->l2cacheSize[1] = 2*1024*1924; // 2MB\n\t\tg_system_info->l2cacheSize[2] = 512*1024; // 512KB\n\t\tg_system_info->coreClockToBusClockRatio = 5;\n\t\tcafeExportRegister(\"coreinit\", OSGetSystemInfo, LogType::Placeholder);\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_SystemInfo.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n\nnamespace coreinit\n{\n\tstruct OSSystemInfo\n\t{\n\t\tuint32be busClock;\n\t\tuint32be coreClock;\n\t\tuint64be ticksSince2000;\n\t\tuint32be l2cacheSize[PPC_CORE_COUNT];\n\t\tuint32be coreClockToBusClockRatio;\n\t};\n\n\tstatic_assert(sizeof(OSSystemInfo) == 0x20);\n\n\tconst OSSystemInfo& OSGetSystemInfo();\n\t\t\n\tvoid InitializeSystemInfo();\n};\n\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/HW/Espresso/Debugger/GDBStub.h\"\n#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n\n#include \"util/helpers/Semaphore.h\"\n#include \"util/helpers/ConcurrentQueue.h\"\n#include \"util/Fiber/Fiber.h\"\n\n#include \"util/helpers/helpers.h\"\n\n#ifdef __arm64__\n#if defined(__clang__)\n#include <arm_acle.h>\n#elif defined(_MSC_VER)\n#include <intrin.h>\n#endif\n#endif\n\nnamespace {\n\nvoid enableFlushDenormalsToZero()\n{\n#if defined(ARCH_X86_64)\n\t_mm_setcsr(_mm_getcsr() | 0x8000);\n#elif defined(__arm64__)\n#if defined(__clang__)\n\t__arm_wsr64(\"fpcr\", __arm_rsr64(\"fpcr\") | (1 << 24));\n#elif defined(__GNUC__)\n\t__builtin_aarch64_set_fpcr(__builtin_aarch64_get_fpcr() | (1 << 24));\n#elif defined(_MSC_VER)\n\t_WriteStatusReg(ARM64_FPCR, _ReadStatusReg(ARM64_FPCR) | (1 << 24));\n#endif\n#endif\n}\n\n}\n\nSlimRWLock srwlock_activeThreadList;\n\n// public list of active threads\nMPTR activeThread[256];\nsint32 activeThreadCount = 0;\n\nvoid nnNfp_update();\n\nnamespace coreinit\n{\n#ifdef __arm64__\n\tvoid __OSFiberThreadEntry(uint32, uint32);\n#else\n\tvoid __OSFiberThreadEntry(void* thread);\n#endif\n\tvoid __OSAddReadyThreadToRunQueue(OSThread_t* thread);\n\tvoid __OSRemoveThreadFromRunQueues(OSThread_t* thread);\n};\n\nnamespace coreinit\n{\n\t// scheduler state\n\tstd::atomic<bool> sSchedulerActive;\n\tstd::vector<std::thread> sSchedulerThreads;\n\tstd::mutex sSchedulerStateMtx;\n\n\tSysAllocator<OSThreadQueue> g_activeThreadQueue; // list of all threads (can include non-detached inactive threads)\n\n\tSysAllocator<OSThreadQueue, 3> g_coreRunQueue;\n\tCounterSemaphore g_coreRunQueueThreadCount[3];\n\n\tbool g_isMulticoreMode;\n\n\tthread_local uint32 t_assignedCoreIndex;\n\tthread_local Fiber* t_schedulerFiber;\n\n\tstruct OSHostThread\n\t{\n\t\tOSHostThread(OSThread_t* thread) : m_thread(thread), m_fiber((void(*)(void*))__OSFiberThreadEntry, this, this)\n\t\t{\n\t\t}\n\n\t\t~OSHostThread() = default;\n\n\t\tOSThread_t* m_thread;\n\t\tFiber m_fiber;\n\t\t// padding (used as stack memory in recompiler)\n\t\tuint8  padding[1024 * 128];\n\t\tPPCInterpreter_t ppcInstance;\n\t\tuint32 selectedCore;\n\t};\n\n\tstd::unordered_map<OSThread_t*, OSHostThread*> s_threadToFiber;\n\n\tbool __CemuIsMulticoreMode()\n\t{\n\t\treturn g_isMulticoreMode;\n\t}\n\n\t// create host thread (fiber) that will be used to run the PPC instance\n\t// note that host threads are fibers and not actual threads\n\tvoid __OSCreateHostThread(OSThread_t* thread)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tcemu_assert_debug(s_threadToFiber.find(thread) == s_threadToFiber.end());\n\n\t\tOSHostThread* hostThread = new OSHostThread(thread);\n\t\ts_threadToFiber.emplace(thread, hostThread);\n\t}\n\n\t// delete host thread\n\tvoid __OSDeleteHostThread(OSThread_t* thread)\n\t{\n\t\tstatic OSHostThread* _deleteQueue = nullptr;\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\n\t\tif (_deleteQueue)\n\t\t{\n\t\t\tdelete _deleteQueue;\n\t\t\t_deleteQueue = nullptr;\n\t\t}\n\n\t\t// delete with a delay (using queue of length 1)\n\t\t// since the fiber might still be in use right now we have to delay the deletion\n\n\t\tauto hostThread = s_threadToFiber[thread];\n\t\ts_threadToFiber.erase(thread);\n\t\t_deleteQueue = hostThread;\n\t}\n\n\n\t// add thread to active queue\n\tvoid __OSActivateThread(OSThread_t* thread)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\n\t\tg_activeThreadQueue->addThread(thread, &thread->activeThreadChain); // todo - check if thread already in queue\n\n\t\tMPTR threadMPTR = memory_getVirtualOffsetFromPointer(thread);\n\n\t\tsrwlock_activeThreadList.LockWrite();\n\t\tbool alreadyActive = false;\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\tif (activeThread[i] == threadMPTR)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false); // should not happen\n\t\t\t\talreadyActive = true;\n\t\t\t}\n\t\t}\n\t\tif (alreadyActive == false)\n\t\t{\n\t\t\tactiveThread[activeThreadCount] = threadMPTR;\n\t\t\tactiveThreadCount++;\n\t\t}\n\n\t\t__OSCreateHostThread(thread);\n\n\t\tsrwlock_activeThreadList.UnlockWrite();\n\t}\n\n\t// remove thread from active queue. Reset id and state\n\tvoid __OSDeactivateThread(OSThread_t* thread)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\n\t\t// remove thread from active thread list\n\t\tMPTR t = memory_getVirtualOffsetFromPointer(thread);\n\t\tsrwlock_activeThreadList.LockWrite();\n\t\tbool noHit = true;\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\tif (activeThread[i] == t)\n\t\t\t{\n\t\t\t\tactiveThread[i] = activeThread[activeThreadCount - 1];\n\t\t\t\tactiveThreadCount--;\n\t\t\t\tnoHit = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tcemu_assert_debug(noHit == false);\n\t\tsrwlock_activeThreadList.UnlockWrite();\n\t\t\n\t\tg_activeThreadQueue->removeThread(thread, &thread->activeThreadChain); // todo - check if thread in queue\n\t\t\n\t\tcemu_assert_debug(thread->state == OSThread_t::THREAD_STATE::STATE_NONE);\n\t\tthread->id = 0x8000;\n\n\t\t__OSDeleteHostThread(thread);\n\t}\n\n\tbool __OSIsThreadActive(OSThread_t* thread)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tMPTR threadMPTR = memory_getVirtualOffsetFromPointer(thread);\n\t\tsrwlock_activeThreadList.LockWrite();\n\t\tbool isRunable = false;\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\tif (activeThread[i] == threadMPTR)\n\t\t\t{\n\t\t\t\tsrwlock_activeThreadList.UnlockWrite();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tsrwlock_activeThreadList.UnlockWrite();\n\t\treturn false;\n\t}\n\n\t// thread\n\tOSThread_t* __currentCoreThread[3] = {};\n\n\tvoid OSSetCurrentThread(uint32 coreIndex, OSThread_t* thread)\n\t{\n\t\tif (coreIndex < 3)\n\t\t\t__currentCoreThread[coreIndex] = thread;\n\t}\n\n\tOSThread_t* OSGetCurrentThread()\n\t{\n\t\tPPCInterpreter_t* currentInstance = PPCInterpreter_getCurrentInstance();\n\t\tif (currentInstance == nullptr)\n\t\t\treturn nullptr;\n\t\treturn __currentCoreThread[currentInstance->spr.UPIR];\n\t}\n\n\tvoid threadEntry(PPCInterpreter_t* hCPU)\n\t{\n\t\tOSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\t\tuint32 r3 = hCPU->gpr[3];\n\t\tuint32 r4 = hCPU->gpr[4];\n\t\tuint32 lr = hCPU->spr.LR;\n\n\t\t// cpp exception init callback\n\t\t//const uint32 im = OSDisableInterrupts(); -> on an actual Wii U interrupts are disabled for this callback, but there are games that yield the thread in the callback (see Angry Birds Star Wars)\n\t\tif (gCoreinitData->__cpp_exception_init_ptr != MPTR_NULL)\n\t\t{\n\t\t\tPPCCoreCallback(_swapEndianU32(gCoreinitData->__cpp_exception_init_ptr), &currentThread->crt.eh_globals);\n\t\t}\n\t\t//OSRestoreInterrupts(im);\n\t\t// forward to thread entrypoint\n\t\thCPU->spr.LR = lr;\n\t\thCPU->gpr[3] = r3;\n\t\thCPU->gpr[4] = r4;\n\t\thCPU->instructionPointer = currentThread->entrypoint.GetMPTR();\n\t}\n\n\tvoid coreinitExport_OSExitThreadDepr(PPCInterpreter_t* hCPU);\n\n\tvoid __OSInitContext(OSContext_t* ctx, MEMPTR<void> initialIP, MEMPTR<void> initialStackPointer)\n\t{\n\t\tctx->SetContextMagic();\n\t\tctx->gpr[0] = 0; // r0 is left uninitialized on console?\n\t\tfor(auto& it : ctx->gpr)\n\t\t\tit = 0;\n\t\tctx->gpr[1] = _swapEndianU32(initialStackPointer.GetMPTR());\n\t\tctx->gpr[2] = _swapEndianU32(RPLLoader_GetSDA2Base());\n\t\tctx->gpr[13] = _swapEndianU32(RPLLoader_GetSDA1Base());\n\t\tctx->srr0 = initialIP.GetMPTR();\n\t\tctx->cr = 0;\n\t\tctx->ukn0A8 = 0;\n\t\tctx->ukn0AC = 0;\n\t\tctx->gqr[0] = 0;\n\t\tctx->gqr[1] = 0;\n\t\tctx->gqr[2] = 0;\n\t\tctx->gqr[3] = 0;\n\t\tctx->gqr[4] = 0;\n\t\tctx->gqr[5] = 0;\n\t\tctx->gqr[6] = 0;\n\t\tctx->gqr[7] = 0;\n\t\tctx->dsi_dar = 0;\n\t\tctx->srr1 = 0x9032;\n\t\tctx->xer = 0;\n\t\tctx->dsi_dsisr = 0;\n\t\tctx->upir = 0;\n\t\tctx->boostCount = 0;\n\t\tctx->state = 0;\n\t\tfor(auto& it : ctx->coretime)\n\t\t\tit = 0;\n\t\tctx->starttime = 0;\n\t\tctx->ghs_errno = 0;\n\t\tctx->upmc1 = 0;\n\t\tctx->upmc2 = 0;\n\t\tctx->upmc3 = 0;\n\t\tctx->upmc4 = 0;\n\t\tctx->ummcr0 = 0;\n\t\tctx->ummcr1 = 0;\n\t}\n\n\tvoid __OSThreadInit(OSThread_t* thread, MEMPTR<void> entrypoint, uint32 argInt, MEMPTR<void> argPtr, MEMPTR<void> stackTop, uint32 stackSize, sint32 priority, uint32 upirCoreIndex, OSThread_t::THREAD_TYPE threadType)\n\t{\n\t\tthread->effectivePriority = priority;\n\t\tthread->type = threadType;\n\t\tthread->basePriority = priority;\n\t\tthread->SetThreadMagic();\n\t\tthread->id = 0x8000;\n\t\tthread->waitAlarm = nullptr;\n\t\tthread->entrypoint = entrypoint;\n\t\tthread->quantumTicks = 0;\n\t\tif(entrypoint)\n\t\t{\n\t\t\tthread->state = OSThread_t::THREAD_STATE::STATE_READY;\n\t\t\tthread->suspendCounter = 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthread->state = OSThread_t::THREAD_STATE::STATE_NONE;\n\t\t\tthread->suspendCounter = 0;\n\t\t}\n\t\tthread->exitValue = (uint32)-1;\n\t\tthread->requestFlags = OSThread_t::REQUEST_FLAG_BIT::REQUEST_FLAG_NONE;\n\t\tthread->pendingSuspend = 0;\n\t\tthread->suspendResult = 0xFFFFFFFF;\n\t\tthread->coretimeSumQuantumStart = 0;\n\t\tthread->deallocatorFunc = nullptr;\n\t\tthread->cleanupCallback = nullptr;\n\t\tthread->waitingForFastMutex = nullptr;\n\t\tthread->stateFlags = 0;\n\t\tthread->waitingForMutex = nullptr;\n\t\tmemset(&thread->crt, 0, sizeof(thread->crt));\n\t\tstatic_assert(sizeof(thread->crt) == 0x1D8);\n\t\tthread->tlsBlocksMPTR = 0;\n\t\tthread->numAllocatedTLSBlocks = 0;\n\t\tthread->tlsStatus = 0;\n\t\tOSInitThreadQueueEx(&thread->joinQueue, thread);\n\t\tOSInitThreadQueueEx(&thread->suspendQueue, thread);\n\t\tthread->mutexQueue.ukn08 = thread;\n\t\tthread->mutexQueue.ukn0C = 0;\n\t\tthread->mutexQueue.tail = nullptr;\n\t\tthread->mutexQueue.head = nullptr;\n\t\tthread->ownedFastMutex.next = nullptr;\n\t\tthread->ownedFastMutex.prev = nullptr;\n\t\tthread->contendedFastMutex.next = nullptr;\n\t\tthread->contendedFastMutex.prev = nullptr;\n\n\t\tMEMPTR<void> alignedStackTop{MEMPTR<void>(stackTop).GetMPTR() & 0xFFFFFFF8};\n\t\tMEMPTR<uint32be> alignedStackTop32{alignedStackTop};\n\t\talignedStackTop32[-1] = 0;\n\t\talignedStackTop32[-2] = 0;\n\n\t\t__OSInitContext(&thread->context, MEMPTR<void>(PPCInterpreter_makeCallableExportDepr(threadEntry)), (void*)(alignedStackTop32.GetPtr() - 2));\n\t\tthread->stackBase = stackTop; // without alignment\n\t\tthread->stackEnd = ((uint8*)stackTop.GetPtr() - stackSize);\n\t\tthread->context.upir = upirCoreIndex;\n\t\tthread->context.lr = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(coreinitExport_OSExitThreadDepr));\n\t\tthread->context.gpr[3] = _swapEndianU32(argInt);\n\t\tthread->context.gpr[4] = _swapEndianU32(argPtr.GetMPTR());\n\n\t\t*(uint32be*)((uint8*)stackTop.GetPtr() - stackSize) = 0xDEADBABE;\n\t\tthread->alarmRelatedUkn = 0;\n\t\tfor(auto& it : thread->specificArray)\n\t\t\tit = nullptr;\n\t\tthread->context.fpscr.fpscr = 4;\n\t\tfor(sint32 i=0; i<32; i++)\n\t\t{\n\t\t\tthread->context.fp_ps0[i] = 0.0;\n\t\t\tthread->context.fp_ps1[i] = 0.0;\n\t\t}\n\t\tthread->context.gqr[2] = 0x40004;\n\t\tthread->context.gqr[3] = 0x50005;\n\t\tthread->context.gqr[4] = 0x60006;\n\t\tthread->context.gqr[5] = 0x70007;\n\n\t\tfor(sint32 i=0; i<Espresso::CORE_COUNT; i++)\n\t\t\tthread->context.coretime[i] = 0;\n\n\t\t// currentRunQueue and waitQueueLink is not initialized by COS and instead overwritten without validation\n\t\t// since we already have integrity checks in other functions, lets initialize it here\n\t\tfor(sint32 i=0; i<Espresso::CORE_COUNT; i++)\n\t\t\tthread->currentRunQueue[i] = nullptr;\n\t\tthread->waitQueueLink.prev = nullptr;\n\t\tthread->waitQueueLink.next = nullptr;\n\n\t\tthread->wakeTimeRelatedUkn2 = 0;\n\t\tthread->wakeUpCount = 0;\n\t\tthread->wakeUpTime = 0;\n\t\tthread->wakeTimeRelatedUkn1 = 0x7FFFFFFFFFFFFFFF;\n\t\tthread->quantumTicks = 0;\n\t\tthread->coretimeSumQuantumStart = 0;\n\t\tthread->totalCycles = 0;\n\n\t\tfor(auto& it : thread->padding68C)\n\t\t\tit = 0;\n\t}\n\n\tvoid SetThreadAffinityToCore(OSThread_t* thread, uint32 coreIndex)\n\t{\n\t\tcemu_assert_debug(coreIndex < 3);\n\t\tthread->attr &= ~(OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE0 | OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE1 | OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE2 | OSThread_t::ATTR_BIT::ATTR_UKN_010);\n\t\tthread->context.affinity &= 0xFFFFFFF8;\n\t\tif (coreIndex == 0)\n\t\t{\n\t\t\tthread->attr |= OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE0;\n\t\t\tthread->context.affinity |= (1<<0);\n\t\t}\n\t\telse if (coreIndex == 1)\n\t\t{\n\t\t\tthread->attr |= OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE1;\n\t\t\tthread->context.affinity |= (1<<1);\n\t\t}\n\t\telse // if (coreIndex == 2)\n\t\t{\n\t\t\tthread->attr |= OSThread_t::ATTR_BIT::ATTR_AFFINITY_CORE2;\n\t\t\tthread->context.affinity |= (1<<2);\n\t\t}\n\t}\n\n\tvoid __OSCreateThreadOnActiveThreadWorkaround(OSThread_t* thread)\n\t{\n\t\t__OSLockScheduler();\n\t\tbool isThreadStillActive = __OSIsThreadActive(thread);\n\t\tif (isThreadStillActive)\n\t\t{\n\t\t\t// workaround for games that restart threads before they correctly entered stopped/moribund state\n\t\t\t// seen in Fast Racing Neo at boot (0x020617BC OSCreateThread)\n\t\t\tcemuLog_log(LogType::Force, \"Game attempting to re-initialize existing thread\");\n\t\t\twhile ((thread->state == OSThread_t::THREAD_STATE::STATE_READY || thread->state == OSThread_t::THREAD_STATE::STATE_RUNNING) && thread->suspendCounter == 0)\n\t\t\t{\n\t\t\t\t// wait for thread to finish\n\t\t\t\t__OSUnlockScheduler();\n\t\t\t\tOSSleepTicks(ESPRESSO_TIMER_CLOCK / 2000); // sleep 0.5ms\n\t\t\t\t__OSLockScheduler();\n\t\t\t}\n\t\t\tif (__OSIsThreadActive(thread) && thread->state == OSThread_t::THREAD_STATE::STATE_MORIBUND)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Calling OSCreateThread() on thread which is still active (Thread exited without detached flag). Forcing OSDetachThread()...\");\n\t\t\t\t__OSUnlockScheduler();\n\t\t\t\tOSDetachThread(thread);\n\t\t\t\t__OSLockScheduler();\n\t\t\t}\n\n\t\t}\n\t\tcemu_assert_debug(__OSIsThreadActive(thread) == false);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tbool __OSCreateThreadInternal2(OSThread_t* thread, MEMPTR<void> entrypoint, uint32 argInt, MEMPTR<void> argPtr, MEMPTR<void> stackBase, uint32 stackSize, sint32 priority, uint32 attrBits, OSThread_t::THREAD_TYPE threadType)\n\t{\n\t\t__OSCreateThreadOnActiveThreadWorkaround(thread);\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tif (priority < 0 || priority >= 32)\n\t\t{\n\t\t\tcemuLog_log(LogType::APIErrors, \"OSCreateThreadInternal: Thread priority must be in range 0-31\");\n\t\t\treturn false;\n\t\t}\n\t\tif (threadType == OSThread_t::THREAD_TYPE::TYPE_IO)\n\t\t{\n\t\t\tpriority = priority + 0x20;\n\t\t}\n\t\telse if (threadType == OSThread_t::THREAD_TYPE::TYPE_APP)\n\t\t{\n\t\t\tpriority = priority + 0x40;\n\t\t}\n\t\tif(attrBits >= 0x20 || stackBase == nullptr || stackSize == 0)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::APIErrors, \"OSCreateThreadInternal: Invalid attributes, stack base or size\");\n\t\t\treturn false;\n\t\t}\n\t\tuint32 im = OSDisableInterrupts();\n\t\t__OSLockScheduler(thread);\n\n\t\tuint32 coreIndex = PPCInterpreter_getCurrentInstance() ? OSGetCoreId() : 1;\n\t\t__OSThreadInit(thread, entrypoint, argInt, argPtr, stackBase, stackSize, priority, coreIndex, threadType);\n\t\tthread->threadName = nullptr;\n\t\tthread->context.affinity = attrBits & 7;\n\t\tthread->attr = attrBits;\n\t\tif ((attrBits & 7) == 0) // if no explicit affinity is given, use the current core\n\t\t\tSetThreadAffinityToCore(thread, OSGetCoreId());\n\t\tif(currentThread)\n\t\t{\n\t\t\tfor(sint32 i=0; i<Espresso::CORE_COUNT; i++)\n\t\t\t{\n\t\t\t\tthread->dsiCallback[i] = currentThread->dsiCallback[i];\n\t\t\t\tthread->isiCallback[i] = currentThread->isiCallback[i];\n\t\t\t\tthread->programCallback[i] = currentThread->programCallback[i];\n\t\t\t\tthread->perfMonCallback[i] = currentThread->perfMonCallback[i];\n\t\t\t\tthread->alignmentExceptionCallback[i] = currentThread->alignmentExceptionCallback[i];\n\t\t\t}\n\t\t\tthread->context.srr1 = thread->context.srr1 | (currentThread->context.srr1 & 0x900);\n\t\t\tthread->context.fpscr.fpscr = thread->context.fpscr.fpscr | (currentThread->context.fpscr.fpscr & 0xF8);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor(sint32 i=0; i<Espresso::CORE_COUNT; i++)\n\t\t\t{\n\t\t\t\tthread->dsiCallback[i] = 0;\n\t\t\t\tthread->isiCallback[i] = 0;\n\t\t\t\tthread->programCallback[i] = 0;\n\t\t\t\tthread->perfMonCallback[i] = 0;\n\t\t\t\tthread->alignmentExceptionCallback[i] = nullptr;\n\t\t\t}\n\t\t}\n\t\tif (entrypoint)\n\t\t{\n\t\t\tthread->id = 0x8000;\n\t\t\t__OSActivateThread(thread); // also handles adding the thread to g_activeThreadQueue\n\t\t}\n\t\t__OSUnlockScheduler(thread);\n\t\tOSRestoreInterrupts(im);\n\t\t// recompile entry point function\n\t\tif (entrypoint)\n\t\t\tPPCRecompiler_recompileIfUnvisited(entrypoint.GetMPTR());\n\t\treturn true;\n\t}\n\n\tbool OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType)\n\t{\n\t\tif(threadType != OSThread_t::THREAD_TYPE::TYPE_APP && threadType != OSThread_t::THREAD_TYPE::TYPE_IO)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::APIErrors, \"OSCreateThreadType: Invalid thread type\");\n\t\t\tcemu_assert_suspicious();\n\t\t\treturn false;\n\t\t}\n\t\treturn __OSCreateThreadInternal2(thread, MEMPTR<void>(entryPoint), numParam, ptrParam, stackTop, stackSize, priority, attr, threadType);\n\t}\n\n\tbool OSCreateThread(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr)\n\t{\n\t\treturn __OSCreateThreadInternal2(thread, MEMPTR<void>(entryPoint), numParam, ptrParam, stackTop, stackSize, priority, attr, OSThread_t::THREAD_TYPE::TYPE_APP);\n\t}\n\n\t// similar to OSCreateThreadType, but can be used to create any type of thread\n\tbool __OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType)\n\t{\n\t\treturn __OSCreateThreadInternal2(thread, MEMPTR<void>(entryPoint), numParam, ptrParam, stackTop, stackSize, priority, attr, threadType);\n\t}\n\n\tbool OSRunThread(OSThread_t* thread, MPTR funcAddress, sint32 numParam, void* ptrParam)\n\t{\n\t\t__OSLockScheduler();\n\n\t\tcemu_assert_debug(PPCInterpreter_getCurrentInstance() == nullptr || OSGetCurrentThread() != thread); // called on self, what should this function do?\n\n\t\tif (thread->state != OSThread_t::THREAD_STATE::STATE_NONE && thread->state != OSThread_t::THREAD_STATE::STATE_MORIBUND)\n\t\t{\n\t\t\t// unsure about this case\n\t\t\tcemuLog_logDebug(LogType::Force, \"OSRunThread called on thread which cannot be ran\");\n\t\t\t__OSUnlockScheduler();\n\t\t\treturn false;\n\t\t}\n\n\t\tif (thread->state == OSThread_t::THREAD_STATE::STATE_MORIBUND)\n\t\t{\n\t\t\tthread->state = OSThread_t::THREAD_STATE::STATE_NONE;\n\t\t\tcoreinit::__OSDeactivateThread(thread);\n\t\t\tcoreinit::__OSRemoveThreadFromRunQueues(thread);\n\t\t}\n\n\t\t// set thread state\n\t\t// todo - this should fully reinitialize the thread?\n\n\t\tthread->entrypoint = funcAddress;\n\t\tthread->context.srr0 = PPCInterpreter_makeCallableExportDepr(threadEntry);\n\t\tthread->context.lr = _swapEndianU32(PPCInterpreter_makeCallableExportDepr(coreinitExport_OSExitThreadDepr));\n\t\tthread->context.gpr[3] = _swapEndianU32(numParam);\n\t\tthread->context.gpr[4] = _swapEndianU32(memory_getVirtualOffsetFromPointer(ptrParam));\n\t\tthread->suspendCounter = 0;\t// verify\n\n\t\tMPTR threadMPTR = memory_getVirtualOffsetFromPointer(thread);\n\n\t\tcoreinit::__OSActivateThread(thread);\n\t\tthread->state = OSThread_t::THREAD_STATE::STATE_READY;\n\n\t\t__OSAddReadyThreadToRunQueue(thread);\n\n\t\t__OSUnlockScheduler();\n\n\t\treturn true;\n\t}\n\n\tvoid OSExitThread(sint32 exitValue)\n\t{\n\t\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\t\thCPU->gpr[3] = exitValue;\n\t\tOSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\n\t\t// thread cleanup callback\n\t\tif (currentThread->cleanupCallback)\n\t\t{\n\t\t\tcurrentThread->stateFlags = _swapEndianU32(_swapEndianU32(currentThread->stateFlags) | 0x00000001);\n\t\t\tPPCCoreCallback(currentThread->cleanupCallback.GetMPTR(), currentThread, currentThread->stackEnd);\n\t\t}\n\t\t// cpp exception cleanup\n\t\tif (gCoreinitData->__cpp_exception_cleanup_ptr != 0 && currentThread->crt.eh_globals != nullptr)\n\t\t{\n\t\t\tPPCCoreCallback(_swapEndianU32(gCoreinitData->__cpp_exception_cleanup_ptr), &currentThread->crt.eh_globals);\n\t\t\tcurrentThread->crt.eh_globals = nullptr;\n\t\t}\n\t\t// set exit code\n\t\tcurrentThread->exitValue = exitValue;\n\n\t\t__OSLockScheduler();\n\n\t\t// release held synchronization primitives\n\t\tif (!currentThread->mutexQueue.isEmpty())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"OSExitThread: Thread is holding mutexes\");\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tOSMutex* mutex = currentThread->mutexQueue.getFirst();\n\t\t\t\tif (!mutex)\n\t\t\t\t\tbreak;\n\t\t\t\tif (mutex->owner != currentThread)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"OSExitThread: Thread is holding mutex which it doesn't own\");\n\t\t\t\t\tcurrentThread->mutexQueue.removeMutex(mutex);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcoreinit::OSUnlockMutexInternal(mutex);\n\t\t\t}\n\t\t}\n\t\t// todo - release all fast mutexes\n\n\t\t// handle join queue\n\t\tif (!currentThread->joinQueue.isEmpty())\n\t\t\tcurrentThread->joinQueue.wakeupEntireWaitQueue(false);\n\t\n\t\tif ((currentThread->attr & 8) != 0)\n\t\t{\n\t\t\t// deactivate thread since it is detached\n\t\t\tcurrentThread->state = OSThread_t::THREAD_STATE::STATE_NONE;\n\t\t\tcoreinit::__OSDeactivateThread(currentThread);\n\t\t\t// queue call to thread deallocator if set\n\t\t\tif (!currentThread->deallocatorFunc.IsNull())\n\t\t\t\t__OSQueueThreadDeallocation(currentThread);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// non-detached threads remain active\n\t\t\tcurrentThread->state = OSThread_t::THREAD_STATE::STATE_MORIBUND;\n\t\t}\n\t\tPPCCore_switchToSchedulerWithLock();\n\t}\n\n\tvoid OSSetThreadSpecific(uint32 index, void* value)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tif (index >= (uint32)currentThread->specificArray.size())\n\t\t\treturn;\n\t\tcurrentThread->specificArray[index] = value;\n\t}\n\n\tvoid* OSGetThreadSpecific(uint32 index)\n\t{\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tif (index >= (uint32)currentThread->specificArray.size())\n\t\t\treturn nullptr;\n\t\treturn currentThread->specificArray[index].GetPtr();\n\t}\n\n\tvoid OSSetThreadName(OSThread_t* thread, const char* name)\n\t{\n\t\tthread->threadName = name;\n\t}\n\n\tconst char* OSGetThreadName(OSThread_t* thread)\n\t{\n\t\treturn thread->threadName.GetPtr();\n\t}\n\n\tvoid coreinitExport_OSExitThreadDepr(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(exitCode, 0);\n\t\tOSExitThread(exitCode);\n\t}\n\n\tvoid OSYieldThread()\n\t{\n\t\tPPCCore_switchToScheduler();\n\t}\n\n\tvoid _OSSleepTicks_alarmHandler(uint64 currentTick, void* context)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tOSThreadQueue* threadQueue = (OSThreadQueue*)context;\n\t\tthreadQueue->wakeupEntireWaitQueue(false);\n\t}\n\n\tvoid OSSleepTicks(uint64 ticks)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock() == false);\n\t\tStackAllocator<OSThreadQueue> _threadQueue;\n\t\tOSInitThreadQueue(_threadQueue.GetPointer());\n\t\t__OSLockScheduler();\n\t\tOSHostAlarm* hostAlarm = OSHostAlarmCreate(OSGetTime() + ticks, 0, _OSSleepTicks_alarmHandler, _threadQueue.GetPointer());\n\t\t_threadQueue.GetPointer()->queueAndWait(OSGetCurrentThread());\n\t\tOSHostAlarmDestroy(hostAlarm);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid OSDetachThread(OSThread_t* thread)\n\t{\n\t\t__OSLockScheduler();\n\t\tthread->attr |= OSThread_t::ATTR_BIT::ATTR_DETACHED;\n\t\tif (thread->state == OSThread_t::THREAD_STATE::STATE_MORIBUND)\n\t\t{\n\t\t\t// exit thread\n\t\t\t// ?\n\n\t\t\t// todo -> call deallocator\n\t\t\tthread->state = OSThread_t::THREAD_STATE::STATE_NONE;\n\t\t\tthread->id = 0x8000;\n\t\t\tcoreinit::__OSDeactivateThread(thread);\n\t\t\tif (!thread->joinQueue.isEmpty())\n\t\t\t{\n\t\t\t\t// handle join queue\n\t\t\t\tthread->joinQueue.wakeupEntireWaitQueue(true);\n\t\t\t}\n\t\t}\n\t\t__OSUnlockScheduler();\n\t}\n\n\tbool OSJoinThread(OSThread_t* thread, uint32be* exitValue)\n\t{\n\t\t__OSLockScheduler();\n\n\t\tif ((thread->attr & OSThread_t::ATTR_DETACHED) == 0 && thread->state != OSThread_t::THREAD_STATE::STATE_MORIBUND)\n\t\t{\n\t\t\tcemu_assert_debug(thread->joinQueue.isEmpty());\n\t\t\t// thread still running, wait in join queue\n\t\t\tthread->joinQueue.queueAndWait(OSGetCurrentThread());\n\t\t}\n\t\telse if (thread->state != OSThread_t::THREAD_STATE::STATE_MORIBUND)\n\t\t{\n\t\t\t// cannot join detached and active threads\n\t\t\tcemuLog_logDebug(LogType::Force, \"Cannot join detached active thread\");\n\t\t\t__OSUnlockScheduler();\n\t\t\treturn false;\n\t\t}\n\n\t\t// thread already ended and is still attached, get return value\n\t\tcemu_assert_debug(thread->state == OSThread_t::THREAD_STATE::STATE_MORIBUND);\n\t\tcemu_assert_debug((thread->attr & OSThread_t::ATTR_DETACHED) == 0);\n\t\tif (exitValue)\n\t\t\t*exitValue = thread->exitValue;\n\t\t// end thread\n\t\tthread->state = OSThread_t::THREAD_STATE::STATE_NONE;\n\t\t__OSDeactivateThread(thread);\n\t\tcoreinit::__OSRemoveThreadFromRunQueues(thread);\n\t\tthread->id = 0x8000;\n\n\t\tif (!thread->deallocatorFunc.IsNull())\n\t\t{\n\t\t\t__OSQueueThreadDeallocation(thread);\n\t\t\tPPCCore_switchToSchedulerWithLock(); // make sure the deallocation function runs before we return\n\t\t}\n\n\t\t__OSUnlockScheduler();\n\n\t\treturn true;\n\t}\n\n\t// adds the thread to each core's run queue if in runable state\n\tvoid __OSAddReadyThreadToRunQueue(OSThread_t* thread)\n\t{\n        cemu_assert_debug(MMU_IsInPPCMemorySpace(thread));\n        cemu_assert_debug(thread->IsValidMagic());\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\n\t\tif (thread->state != OSThread_t::THREAD_STATE::STATE_READY)\n\t\t\treturn;\n\t\tif (thread->suspendCounter != 0)\n\t\t\treturn;\n\t\tfor (sint32 i = 0; i < PPC_CORE_COUNT; i++)\n\t\t{\n\t\t\tif (thread->currentRunQueue[i] != nullptr)\n\t\t\t\tcontinue; // already on the queue\n\t\t\t// check affinity\n\t\t\tif(!thread->context.hasCoreAffinitySet(i))\n\t\t\t\tcontinue;\n\t\t\tg_coreRunQueue.GetPtr()[i].addThread(thread, thread->linkRun + i);\n\t\t\tthread->currentRunQueue[i] = (g_coreRunQueue.GetPtr() + i);\n\t\t\tg_coreRunQueueThreadCount[i].increment();\n\t\t}\n\t}\n\n\tvoid __OSRemoveThreadFromRunQueues(OSThread_t* thread)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tfor (sint32 i = 0; i < PPC_CORE_COUNT; i++)\n\t\t{\n\t\t\tif(thread->currentRunQueue[i] == nullptr)\n\t\t\t\tcontinue;\n\t\t\tg_coreRunQueue.GetPtr()[i].removeThread(thread, thread->linkRun + i);\n\t\t\tthread->currentRunQueue[i] = nullptr;\n\t\t\tg_coreRunQueueThreadCount[i].decrement();\n\t\t}\n\t}\n\n\t// returns true if thread runs on same core and has higher priority\n\tbool __OSCoreShouldSwitchToThread(OSThread_t* currentThread, OSThread_t* newThread, bool sharedPriorityAndAffinityWorkaround)\n\t{\n\t\tuint32 coreIndex = OSGetCoreId();\n\t\tif (!newThread->context.hasCoreAffinitySet(coreIndex))\n\t\t\treturn false;\n\t\t// special case: if current and new thread are running only on the same core then reschedule even if priority is equal\n\t\t// this resolves a deadlock in Just Dance 2019 where one thread would always reacquire the same mutex within it's timeslice, blocking another thread on the same core from acquiring it\n\t\tif (sharedPriorityAndAffinityWorkaround && (1<<coreIndex) == newThread->context.affinity && currentThread->context.affinity == newThread->context.affinity && currentThread->effectivePriority == newThread->effectivePriority)\n\t\t\treturn true;\n\t\t// otherwise reschedule if new thread has higher priority\n\t\treturn newThread->effectivePriority < currentThread->effectivePriority;\n\t}\n\n\tsint32 __OSResumeThreadInternal(OSThread_t* thread, sint32 resumeCount)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tsint32 previousSuspendCount = thread->suspendCounter;\n\t\tcemu_assert_debug(previousSuspendCount >= 0);\n\t\tif (previousSuspendCount == 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::APIErrors, \"OSResumeThread: Resuming thread 0x{:08x} which isn't suspended\", MEMPTR<OSThread_t>(thread).GetMPTR());\n\t\t\treturn 0;\n\t\t}\n\t\tthread->suspendCounter = previousSuspendCount - resumeCount;\n\t\tif (thread->suspendCounter < 0)\n\t\t\tthread->suspendCounter = 0;\n\t\tif (thread->suspendCounter == 0)\n\t\t{\n\t\t\t__OSAddReadyThreadToRunQueue(thread);\n\t\t\t// set awakened time if thread is ready\n\t\t\t// todo - only set this once?\n\t\t\tthread->wakeUpTime = PPCInterpreter_getMainCoreCycleCounter();\n\t\t\t// reschedule if thread has higher priority\n\t\t\tif (PPCInterpreter_getCurrentInstance() && __OSCoreShouldSwitchToThread(coreinit::OSGetCurrentThread(), thread, false))\n\t\t\t\tPPCCore_switchToSchedulerWithLock();\n\t\t}\n\t\treturn previousSuspendCount;\n\t}\n\n\tsint32 OSResumeThread(OSThread_t* thread)\n\t{\n\t\t__OSLockScheduler();\n\t\tsint32 previousSuspendCount = __OSResumeThreadInternal(thread, 1);\n\t\t__OSUnlockScheduler();\n\t\treturn previousSuspendCount;\n\t}\n\n\tvoid OSContinueThread(OSThread_t* thread)\n\t{\n\t\t__OSLockScheduler();\n\t\t__OSResumeThreadInternal(thread, thread->suspendCounter);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid __OSSuspendThreadInternal(OSThread_t* thread)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tcemu_assert_debug(thread->state != OSThread_t::THREAD_STATE::STATE_NONE && thread->state != OSThread_t::THREAD_STATE::STATE_MORIBUND); // how to handle these?\n\n\t\tsint32 previousSuspendCount = thread->suspendCounter;\n\n\t\tif (OSGetCurrentThread() == thread)\n\t\t{\n\t\t\tthread->suspendCounter = thread->suspendCounter + 1;\n\t\t\tPPCCore_switchToSchedulerWithLock();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthread->suspendCounter = thread->suspendCounter + 1;\n\t\t\tif (previousSuspendCount == 0)\n\t\t\t{\n\t\t\t\t__OSRemoveThreadFromRunQueues(thread);\n\t\t\t\t// todo - if thread is still running find a way to cancel it's timeslice immediately\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid OSSuspendThread(OSThread_t* thread)\n\t{\n\t\t__OSLockScheduler();\n\t\t__OSSuspendThreadInternal(thread);\n\t\t__OSUnlockScheduler();\n\t}\n\n    void __OSSuspendThreadNolock(OSThread_t* thread)\n    {\n        __OSSuspendThreadInternal(thread);\n    }\n\n\tvoid OSSleepThread(OSThreadQueue* threadQueue)\n\t{\n\t\t__OSLockScheduler();\n\t\tthreadQueue->queueAndWait(OSGetCurrentThread());\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid OSWakeupThread(OSThreadQueue* threadQueue)\n\t{\n\t\t__OSLockScheduler();\n\t\tthreadQueue->wakeupEntireWaitQueue(true);\n\t\t__OSUnlockScheduler();\n\t}\n\n\tbool OSSetThreadAffinity(OSThread_t* thread, uint32 affinityMask)\n\t{\n\t\tcemu_assert_debug((affinityMask & ~7) == 0);\n\t\t__OSLockScheduler();\n\t\tuint32 prevAffinityMask = thread->context.getAffinity();\n\t\tif (thread->state == OSThread_t::THREAD_STATE::STATE_RUNNING)\n\t\t{\n\t\t\tthread->attr = (thread->attr & ~7) | (affinityMask & 7);\n\t\t\tthread->context.setAffinity(affinityMask);\n\t\t\t// should this reschedule the thread?\n\t\t}\n\t\telse if (prevAffinityMask != affinityMask)\n\t\t{\n            if(thread->state != OSThread_t::THREAD_STATE::STATE_NONE)\n            {\n                __OSRemoveThreadFromRunQueues(thread);\n                thread->attr = (thread->attr & ~7) | (affinityMask & 7);\n                thread->context.setAffinity(affinityMask);\n                __OSAddReadyThreadToRunQueue(thread);\n            }\n            else\n            {\n                thread->attr = (thread->attr & ~7) | (affinityMask & 7);\n                thread->context.setAffinity(affinityMask);\n            }\n\t\t}\n\t\t__OSUnlockScheduler();\n\t\treturn true;\n\t}\n\n\tuint32 OSGetThreadAffinity(OSThread_t* thread)\n\t{\n\t\tauto affinityMask = thread->context.getAffinity();\n\t\tcemu_assert_debug((affinityMask & ~7) == 0);\n\t\treturn affinityMask;\n\t}\n\n\tvoid* OSSetThreadDeallocator(OSThread_t* thread, void* newDeallocatorFunc)\n\t{\n\t\t__OSLockScheduler();\n\t\tvoid* previousFunc = thread->deallocatorFunc.GetPtr();\n\t\tthread->deallocatorFunc = newDeallocatorFunc;\n\t\t__OSUnlockScheduler();\n\t\treturn previousFunc;\n\t}\n\n\tvoid* OSSetThreadCleanupCallback(OSThread_t* thread, void* cleanupCallback)\n\t{\n\t\t__OSLockScheduler();\n\t\tvoid* previousFunc = thread->cleanupCallback.GetPtr();\n\t\tthread->cleanupCallback = cleanupCallback;\n\t\t__OSUnlockScheduler();\n\t\treturn previousFunc;\n\t}\n\n\tvoid __OSSetThreadBasePriority(OSThread_t* thread, sint32 newPriority)\n\t{\n\t\tcemu_assert_debug(newPriority >= 0 && newPriority < 32);\n\t\tnewPriority += OSThread_t::GetTypePriorityBase(thread->type);\n\t\tthread->basePriority = newPriority;\n\t}\n\n\tvoid __OSUpdateThreadEffectivePriority(OSThread_t* thread)\n\t{\n\t\tif (thread->context.boostCount != 0)\n\t\t{\n\t\t\t// temporarily boosted threads have their priority set to 0 (maximum)\n\t\t\tthread->effectivePriority = 0;\n\t\t\treturn;\n\t\t}\n\t\tthread->effectivePriority = thread->basePriority;\n\t}\n\n\tbool OSSetThreadPriority(OSThread_t* thread, sint32 newPriority)\n\t{\n\t\tif (newPriority < 0 || newPriority >= 0x20)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn false; // invalid priority value\n\t\t}\n\t\t__OSLockScheduler();\n\t\t__OSSetThreadBasePriority(thread, newPriority);\n\t\t__OSUpdateThreadEffectivePriority(thread);\n\t\t// reschedule if needed\n\t\tOSThread_t* currentThread = OSGetCurrentThread();\n\t\tif (currentThread && currentThread != thread)\n\t\t{\n\t\t\tif (__OSCoreShouldSwitchToThread(currentThread, thread, false))\n\t\t\t\tPPCCore_switchToSchedulerWithLock();\n\t\t}\n\t\t__OSUnlockScheduler();\n\t\treturn true;\n\t}\n\n\tsint32 OSGetThreadPriority(OSThread_t* thread)\n\t{\n\t\tsint32 threadPriority = thread->basePriority;\n\t\tOSThread_t::THREAD_TYPE threadType = thread->type;\n\t\tthreadPriority -= OSThread_t::GetTypePriorityBase(threadType);\n\t\tcemu_assert_debug(threadPriority >= 0 && threadPriority < 32);\n\t\treturn threadPriority;\n\t}\n\n\tbool OSIsThreadTerminated(OSThread_t* thread)\n\t{\n\t\t__OSLockScheduler();\n\t\tbool isTerminated = false;\n\t\tif (thread->state == OSThread_t::THREAD_STATE::STATE_MORIBUND || thread->state == OSThread_t::THREAD_STATE::STATE_NONE)\n\t\t\tisTerminated = true;\n\t\t__OSUnlockScheduler();\n\t\treturn isTerminated;\n\t}\n\n\tbool OSIsThreadSuspended(OSThread_t* thread)\n\t{\n\t\t__OSLockScheduler();\n\t\tsint32 suspendCounter = thread->suspendCounter;\n\t\t__OSUnlockScheduler();\n\t\treturn suspendCounter > 0;\n\t}\n\n    bool OSIsThreadRunningNoLock(OSThread_t* thread)\n    {\n        cemu_assert_debug(__OSHasSchedulerLock());\n        return thread->state == OSThread_t::THREAD_STATE::STATE_RUNNING;\n    }\n\n    bool OSIsThreadRunning(OSThread_t* thread)\n    {\n        bool isRunning = false;\n        __OSLockScheduler();\n        isRunning = OSIsThreadRunningNoLock(thread);\n        __OSUnlockScheduler();\n        return isRunning;\n    }\n\n    void OSCancelThread(OSThread_t* thread)\n\t{\n\t\t__OSLockScheduler();\n\t\tcemu_assert_debug(thread->requestFlags == 0 || thread->requestFlags == OSThread_t::REQUEST_FLAG_CANCEL); // todo - how to handle cases where other flags are already set?\n\t\tthread->requestFlags = OSThread_t::REQUEST_FLAG_CANCEL;\n\t\t__OSUnlockScheduler();\n\t\t// if the canceled thread is self, then exit immediately\n\t\tif (thread == OSGetCurrentThread())\n\t\t\tOSExitThread(-1);\n\t}\n\n\tvoid OSTestThreadCancelInternal()\n\t{\n\t\t// also handles suspend request ?\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tOSThread_t* thread = OSGetCurrentThread();\n\t\tif (thread->requestFlags == OSThread_t::REQUEST_FLAG_CANCEL)\n\t\t{\n\t\t\t__OSUnlockScheduler();\n\t\t\tOSExitThread(-1);\n\t\t}\n\t}\n\n\tvoid OSTestThreadCancel()\n\t{\n\t\t__OSLockScheduler();\n\t\tOSTestThreadCancelInternal();\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid __OSSwitchToThreadFiber(OSThread_t* thread, uint32 coreIndex)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tcemu_assert_debug(s_threadToFiber.find(thread) != s_threadToFiber.end());\n\n\t\tOSHostThread* hostThread = s_threadToFiber.find(thread)->second;\n\t\thostThread->selectedCore = coreIndex;\n\t\tFiber::Switch(hostThread->m_fiber);\n\t}\n\n\tvoid __OSThreadLoadContext(PPCInterpreter_t* hCPU, OSThread_t* thread)\n\t{\n\t\t// load GPR\n\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t\thCPU->gpr[i] = _swapEndianU32(thread->context.gpr[i]);\n\n\t\t// load SPR cr, lr, ctr, xer\n\t\tppc_setCR(hCPU, thread->context.cr);\n\t\thCPU->spr.LR = _swapEndianU32(thread->context.lr);\n\t\thCPU->spr.CTR = thread->context.ctr;\n\t\tPPCInterpreter_setXER(hCPU, thread->context.xer);\n\n\t\thCPU->fpscr = thread->context.fpscr.fpscr;\n\n\t\t// store floating point and Gekko registers\n\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t{\n\t\t\thCPU->fpr[i].fp0int = thread->context.fp_ps0[i];\n\t\t\thCPU->fpr[i].fp1int = thread->context.fp_ps1[i];\n\t\t}\n\n\t\tfor (uint32 i = 0; i < 8; i++)\n\t\t{\n\t\t\thCPU->spr.UGQR[0 + i] = thread->context.gqr[i];\n\t\t}\n\n\t\thCPU->instructionPointer = thread->context.srr0;\n\t}\n\n\tvoid __OSThreadStoreContext(PPCInterpreter_t* hCPU, OSThread_t* thread)\n\t{\n\t\t// store GPR\n\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t\tthread->context.gpr[i] = _swapEndianU32(hCPU->gpr[i]);\n\t\t// store SPRs\n\t\tthread->context.cr = ppc_getCR(hCPU);\n\t\tthread->context.lr = _swapEndianU32(hCPU->spr.LR);\n\t\tthread->context.ctr = hCPU->spr.CTR;\n\t\tthread->context.xer = PPCInterpreter_getXER(hCPU);\n\n\t\tthread->context.fpscr.fpscr = hCPU->fpscr;\n\t\tthread->context.fpscr.padding = 0;\n\n\t\t// store floating point and Gekko registers\n\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t{\n\t\t\tthread->context.fp_ps0[i] = hCPU->fpr[i].fp0int;\n\t\t\tthread->context.fp_ps1[i] = hCPU->fpr[i].fp1int;\n\t\t}\n\n\t\tfor (uint32 i = 0; i < 8; i++)\n\t\t{\n\t\t\tthread->context.gqr[i] = hCPU->spr.UGQR[0 + i];\n\t\t}\n\n\t\tthread->context.srr0 = hCPU->instructionPointer;\n\t}\n\n\tvoid __OSStoreThread(OSThread_t* thread, PPCInterpreter_t* hCPU)\n\t{\n\t\tif (thread->state == OSThread_t::THREAD_STATE::STATE_RUNNING)\n\t\t{\n\t\t\tthread->state = OSThread_t::THREAD_STATE::STATE_READY;\n\t\t\t__OSAddReadyThreadToRunQueue(thread);\n\t\t}\n\t\telse if (thread->state == OSThread_t::THREAD_STATE::STATE_MORIBUND || thread->state == OSThread_t::THREAD_STATE::STATE_NONE || thread->state == OSThread_t::THREAD_STATE::STATE_WAITING)\n\t\t{\n\t\t\t// thread exited or suspending/waiting\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\n\t\tthread->requestFlags = (OSThread_t::REQUEST_FLAG_BIT)(thread->requestFlags & OSThread_t::REQUEST_FLAG_CANCEL); // remove all flags except cancel flag\n\n\t\t// update total cycles\n\t\tsint64 executedCycles = (sint64)thread->quantumTicks - (sint64)hCPU->remainingCycles;\n\t\texecutedCycles = std::max<sint64>(executedCycles, 0);\n\t\tif (executedCycles < (sint64)hCPU->skippedCycles)\n\t\t\texecutedCycles = 0;\n\t\telse\n\t\t\texecutedCycles -= hCPU->skippedCycles;\n\t\tthread->totalCycles += (uint64)executedCycles;\n\t\t// store context and set current thread to null\n\t\t__OSThreadStoreContext(hCPU, thread);\n\t\tOSSetCurrentThread(OSGetCoreId(), nullptr);\n\t\tPPCInterpreter_setCurrentInstance(nullptr);\n\t}\n\n\tvoid __OSLoadThread(OSThread_t* thread, PPCInterpreter_t* hCPU, uint32 coreIndex)\n\t{\n\t\thCPU->LSQE = 1;\n\t\thCPU->PSE = 1;\n\t\thCPU->reservedMemAddr = MPTR_NULL;\n\t\thCPU->reservedMemValue = 0;\n\t\thCPU->spr.UPIR = coreIndex;\n\t\thCPU->coreInterruptMask = 1;\n\t\tPPCInterpreter_setCurrentInstance(hCPU);\n\t\tOSSetCurrentThread(OSGetCoreId(), thread);\n\t\t__OSThreadLoadContext(hCPU, thread);\n\t\tthread->context.upir = coreIndex;\n\t\tthread->quantumTicks = ppcThreadQuantum;\n\t\t// statistics\n\t\tthread->wakeUpTime = PPCInterpreter_getMainCoreCycleCounter();\n\t\tthread->wakeUpCount = thread->wakeUpCount + 1;\n\t}\n\n\tuint32 s_lehmer_lcg[PPC_CORE_COUNT] = { 0 };\n\n\tvoid __OSThreadStartTimeslice(OSThread_t* thread, PPCInterpreter_t* hCPU)\n\t{\n\t\tuint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU);\n\t\t// run one timeslice\n\t\thCPU->remainingCycles = ppcThreadQuantum;\n\t\thCPU->skippedCycles = 0;\n\t\t// we add a slight randomized variance to the thread quantum to avoid getting stuck in repeated code sequences where one or multiple threads always unload inside a lock\n\t\t// this was seen in Mario Party 10 during early boot where several OSLockMutex operations would align in such a way that one thread would never successfully acquire the lock\n\t\tif (s_lehmer_lcg[coreIndex] == 0)\n\t\t\ts_lehmer_lcg[coreIndex] = 12345;\n\t\thCPU->remainingCycles += (s_lehmer_lcg[coreIndex] & 0x7F);\n\t\ts_lehmer_lcg[coreIndex] = (uint32)((uint64)s_lehmer_lcg[coreIndex] * 279470273ull % 0xfffffffbull);\n\t}\n\n\tOSThread_t* __OSGetNextRunableThread(uint32 coreIndex)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\t// pick thread, then remove from run queue\n\t\tOSThreadQueue* runQueue = g_coreRunQueue.GetPtr() + coreIndex;\n\n\t\tOSThread_t* threadItr = runQueue->head.GetPtr();\n\t\tOSThread_t* selectedThread = nullptr;\n\t\tif (!threadItr)\n\t\t\treturn nullptr;\n\t\tselectedThread = threadItr;\n\n\t\twhile (threadItr)\n\t\t{\n\t\t\tif (threadItr->effectivePriority < selectedThread->effectivePriority)\n\t\t\t\tselectedThread = threadItr;\n\t\t\tthreadItr = threadItr->linkRun[coreIndex].next.GetPtr();\n\t\t}\n\n\t\tcemu_assert_debug(selectedThread->state == OSThread_t::THREAD_STATE::STATE_READY);\n\n\t\t__OSRemoveThreadFromRunQueues(selectedThread);\n\t\tselectedThread->state = OSThread_t::THREAD_STATE::STATE_RUNNING;\n\n\t\treturn selectedThread;\n\t}\n\n    void __OSDeleteAllActivePPCThreads()\n    {\n        __OSLockScheduler();\n        while(activeThreadCount > 0)\n        {\n            MEMPTR<OSThread_t> t{activeThread[0]};\n            t->state = OSThread_t::THREAD_STATE::STATE_NONE;\n            __OSDeactivateThread(t.GetPtr());\n        }\n        __OSUnlockScheduler();\n    }\n\n\tvoid __OSCheckSystemEvents()\n\t{\n\t\t// AX update\n\t\tsnd_core::AXOut_update();\n\t\t// alarm update\n\t\tcoreinit::alarm_update();\n\t\t// nfp update\n\t\tnnNfp_update();\n\t}\n\n\tFiber* g_idleLoopFiber[3]{};\n\n\t// idle fiber per core if no thread is runnable\n\t// this is necessary since we can't block in __OSThreadSwitchToNext() (__OSStoreThread + thread switch must happen inside same scheduler lock)\n\tvoid __OSThreadCoreIdle(void* unusedParam)\n\t{\n\t\tbool isMainCore = g_isMulticoreMode == false || t_assignedCoreIndex == 1;\n\t\tsint32 coreIndex = t_assignedCoreIndex;\n\t\t__OSUnlockScheduler();\n\t\twhile (true)\n\t\t{\n\t\t\tif (!g_coreRunQueueThreadCount[coreIndex].isZero()) // avoid hammering the lock on the main core if there is no runable thread\n\t\t\t{\n\t\t\t\t__OSLockScheduler();\n\t\t\t\tOSThread_t* nextThread = __OSGetNextRunableThread(coreIndex);\n\t\t\t\tif (nextThread)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(nextThread->state == OSThread_t::THREAD_STATE::STATE_RUNNING);\n\t\t\t\t\t__OSSwitchToThreadFiber(nextThread, coreIndex);\n\t\t\t\t}\n\t\t\t\t__OSUnlockScheduler();\n\t\t\t}\n\t\t\tif (isMainCore)\n\t\t\t{\n\t\t\t\t__OSCheckSystemEvents();\n\t\t\t\tif(g_isMulticoreMode == false)\n\t\t\t\t\tcoreIndex = (coreIndex + 1) % 3;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// wait for semaphore (only in multicore mode)\n\t\t\t\tg_coreRunQueueThreadCount[t_assignedCoreIndex].waitUntilNonZero();\n\t\t\t\tif (!sSchedulerActive.load(std::memory_order::relaxed))\n\t\t\t\t\tFiber::Switch(*t_schedulerFiber); // switch back to original thread to exit\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid __OSThreadSwitchToNext()\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\n\t\tOSHostThread* hostThread = (OSHostThread*)Fiber::GetFiberPrivateData();\n        cemu_assert_debug(hostThread);\n\n\t\t//if (ppcInterpreterCurrentInstance)\n\t\t//\tdebug_printf(\"Core %d store thread %08x (t = %d)\\n\", hostThread->ppcInstance.sprNew.UPIR, memory_getVirtualOffsetFromPointer(hostThread->thread), t_assignedCoreIndex);\n\n\t\t// store context of current thread\n\t\t__OSStoreThread(OSGetCurrentThread(), &hostThread->ppcInstance);\n\t\tcemu_assert_debug(PPCInterpreter_getCurrentInstance() == nullptr);\n\n\t\tif (!sSchedulerActive.load(std::memory_order::relaxed))\n\t\t{\n\t\t\t__OSUnlockScheduler();\n\t\t\tFiber::Switch(*t_schedulerFiber); // switch back to original thread entry for it to exit\n\t\t}\n\t\t// choose core\n\t\tstatic uint32 _coreCounter = 0;\n\n\t\tsint32 coreIndex;\n\t\tif (g_isMulticoreMode)\n\t\t\tcoreIndex = t_assignedCoreIndex;\n\t\telse\n\t\t{\n\t\t\tcoreIndex = _coreCounter;\n\t\t\t_coreCounter = (_coreCounter + 1) % 3;\n\t\t}\n\n\t\t// if main thread then dont forget to do update checks\n\t\tbool isMainThread = g_isMulticoreMode == false || t_assignedCoreIndex == 1;\n\n\t\t// find next thread to run\n\t\t// for main thread we force switching to the idle loop since it calls __OSCheckSystemEvents()\n\t\tif(isMainThread)\n\t\t\tFiber::Switch(*g_idleLoopFiber[t_assignedCoreIndex]);\n\t\telse if (OSThread_t* nextThread = __OSGetNextRunableThread(coreIndex))\n\t\t{\n\t\t\tcemu_assert_debug(nextThread->state == OSThread_t::THREAD_STATE::STATE_RUNNING);\n\t\t\t__OSSwitchToThreadFiber(nextThread, coreIndex);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tFiber::Switch(*g_idleLoopFiber[t_assignedCoreIndex]);\n\t\t}\n\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\t\n\t\tcemu_assert_debug(g_isMulticoreMode == false || hostThread->selectedCore == t_assignedCoreIndex);\n\n\t\t// received next time slice, load self again\n\t\t__OSLoadThread(hostThread->m_thread, &hostThread->ppcInstance, hostThread->selectedCore);\n\t\t__OSThreadStartTimeslice(hostThread->m_thread, &hostThread->ppcInstance);\n\t}\n\n#ifdef __arm64__\n\tvoid __OSFiberThreadEntry(uint32 _high, uint32 _low)\n\t{\n\t\tuint64 _thread = (uint64) _high << 32 | _low;\n#else\n\tvoid __OSFiberThreadEntry(void* _thread)\n\t{\n#endif\n\t\tOSHostThread* hostThread = (OSHostThread*)_thread;\n\n\t\tenableFlushDenormalsToZero();\n\n\t\tPPCInterpreter_t* hCPU = &hostThread->ppcInstance;\n\t\t__OSLoadThread(hostThread->m_thread, hCPU, hostThread->selectedCore);\n\t\t__OSThreadStartTimeslice(hostThread->m_thread, &hostThread->ppcInstance);\n\t\t__OSUnlockScheduler(); // lock is always held when switching to a fiber, so we need to unlock it here\n\t\twhile (true)\n\t\t{\n\t\t\tif (hCPU->remainingCycles > 0)\n\t\t\t{\n\t\t\t\t// try to enter recompiler immediately\n\t\t\t\tPPCRecompiler_attemptEnterWithoutRecompile(hCPU, hCPU->instructionPointer);\n\t\t\t\t// keep executing as long as there are cycles left\n\t\t\t\twhile ((--hCPU->remainingCycles) >= 0)\n\t\t\t\t\tPPCInterpreterSlim_executeInstruction(hCPU);\n\t\t\t}\n\n\t\t\t// reset reservation\n\t\t\thCPU->reservedMemAddr = 0;\n\t\t\thCPU->reservedMemValue = 0;\n\n\t\t\t// reschedule\n\t\t\t__OSLockScheduler();\n\t\t\t__OSThreadSwitchToNext();\n\t\t\t__OSUnlockScheduler();\n\t\t}\n\t}\n\n#if BOOST_OS_LINUX\n\t#include <unistd.h>\n\t#include <sys/prctl.h>\n\n\tstd::vector<pid_t> g_schedulerThreadIds;\n\tstd::mutex g_schedulerThreadIdsLock;\n\n\tstd::vector<pid_t>& OSGetSchedulerThreadIds()\n\t{\n\t\tstd::lock_guard schedulerThreadIdsLockGuard(g_schedulerThreadIdsLock);\n\t\treturn g_schedulerThreadIds;\n\t}\n#endif\n\n\tvoid OSSchedulerCoreEmulationThread(void* _assignedCoreIndex)\n\t{\n\t\tSetThreadName(fmt::format(\"OSSched[core={}]\", (uintptr_t)_assignedCoreIndex).c_str());\n\t\tt_assignedCoreIndex = (sint32)(uintptr_t)_assignedCoreIndex;\n\n\t\tenableFlushDenormalsToZero();\n\n#if BOOST_OS_LINUX\n\t\tif (g_gdbstub)\n\t\t{\n\t\t\t// need to allow the GDBStub to attach to our thread\n\t\t\tprctl(PR_SET_DUMPABLE, (unsigned long)1);\n\t\t\tprctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);\n\t\t}\n\n\t\tpid_t tid = gettid();\n\t\t{\n\t\t\tstd::lock_guard schedulerThreadIdsLockGuard(g_schedulerThreadIdsLock);\n\t\t\tg_schedulerThreadIds.emplace_back(tid);\n\t\t}\n#endif\n\n\t\tt_schedulerFiber = Fiber::PrepareCurrentThread();\n\n\t\t// create scheduler idle fiber and switch to it\n\t\tg_idleLoopFiber[t_assignedCoreIndex] = new Fiber(__OSThreadCoreIdle, nullptr, nullptr);\n\t\tcemu_assert_debug(PPCInterpreter_getCurrentInstance() == nullptr);\n\t\t__OSLockScheduler();\n\t\tFiber::Switch(*g_idleLoopFiber[t_assignedCoreIndex]);\n\t\t// returned from scheduler loop, exit thread\n\t\tcemu_assert_debug(!__OSHasSchedulerLock());\n\t}\n\n\tstd::vector<std::thread::native_handle_type> g_schedulerThreadHandles;\n\n\tstd::vector<std::thread::native_handle_type>& OSGetSchedulerThreads()\n\t{\n\t\treturn g_schedulerThreadHandles;\n\t}\n\n\t// starts PPC core emulation\n\tvoid OSSchedulerBegin(sint32 numCPUEmulationThreads)\n\t{\n\t\tstd::unique_lock _lock(sSchedulerStateMtx);\n\t\tif (sSchedulerActive.exchange(true))\n\t\t\treturn;\n\t\tcemu_assert_debug(numCPUEmulationThreads == 1 || numCPUEmulationThreads == 3);\n\t\tg_isMulticoreMode = numCPUEmulationThreads > 1;\n\t\tif (numCPUEmulationThreads == 1)\n\t\t\tsSchedulerThreads.emplace_back(OSSchedulerCoreEmulationThread, (void*)0);\n\t\telse if (numCPUEmulationThreads == 3)\n\t\t{\n\t\t\tfor (size_t i = 0; i < 3; i++)\n\t\t\t\tsSchedulerThreads.emplace_back(OSSchedulerCoreEmulationThread, (void*)i);\n\t\t}\n\t\telse\n\t\t\tcemu_assert_debug(false);\n\t\tfor (auto& it : sSchedulerThreads)\n\t\t\tg_schedulerThreadHandles.emplace_back(it.native_handle());\n\t}\n\n    // shuts down all scheduler host threads and deletes all fibers and ppc threads\n\tvoid OSSchedulerEnd()\n\t{\n\t\tstd::unique_lock _lock(sSchedulerStateMtx);\n\t\tsSchedulerActive.store(false);\n\t\tfor (size_t i = 0; i < Espresso::CORE_COUNT; i++)\n\t\t\tg_coreRunQueueThreadCount[i].increment(); // make sure to wake up cores if they are paused and waiting for runnable threads\n\t\t// wait for threads to stop execution\n\t\tfor (auto& threadItr : sSchedulerThreads)\n\t\t\tthreadItr.join();\n\t\tsSchedulerThreads.clear();\n\t\tg_schedulerThreadHandles.clear();\n#if BOOST_OS_LINUX\n\t\t{\n\t\t\tstd::lock_guard schedulerThreadIdsLockGuard(g_schedulerThreadIdsLock);\n\t\t\tg_schedulerThreadIds.clear();\n\t\t}\n#endif\n\t\t// clean up all fibers\n\t\tfor (auto& it : g_idleLoopFiber)\n\t\t{\n\t\t\tdelete it;\n\t\t\tit = nullptr;\n\t\t}\n\t\tfor (auto& it : s_threadToFiber)\n\t\t{\n\t\t\tOSHostThread* hostThread = it.second;\n\t\t\tdelete hostThread;\n\t\t}\n\t\ts_threadToFiber.clear();\n\t}\n\n\tSysAllocator<OSThread_t, PPC_CORE_COUNT> s_defaultThreads;\n\tSysAllocator<uint8, PPC_CORE_COUNT * 1024 * 1024> s_stack;\n\n\tOSThread_t* OSGetDefaultThread(sint32 coreIndex)\n\t{\n\t\tif (coreIndex < 0 || coreIndex >= PPC_CORE_COUNT)\n\t\t\treturn nullptr;\n\t\treturn s_defaultThreads.GetPtr() + coreIndex;\n\t}\n\n\tvoid* OSGetDefaultThreadStack(sint32 coreIndex, uint32& size)\n\t{\n\t\tif (coreIndex < 0 || coreIndex >= PPC_CORE_COUNT)\n\t\t\treturn nullptr;\n\t\tsize = 1024 * 1024;\n\t\treturn s_stack.GetPtr() + coreIndex * size;\n\t}\n\n\tvoid OSInitThreadQueue(OSThreadQueue* threadQueue)\n\t{\n\t\tthreadQueue->head = nullptr;\n\t\tthreadQueue->tail = nullptr;\n\t\tthreadQueue->userData = nullptr;\n\t\tthreadQueue->ukn0C = 0;\n\t}\n\t\n\tvoid OSInitThreadQueueEx(OSThreadQueue* threadQueue, void* userData)\n\t{\n\t\tthreadQueue->head = nullptr;\n\t\tthreadQueue->tail = nullptr;\n\t\tthreadQueue->userData = userData;\n\t\tthreadQueue->ukn0C = 0;\n\t}\n\t\n\t/* Thread terminator threads (for calling thread deallocators) */\n\tstruct TerminatorThread \n\t{\n\t\tstruct DeallocatorQueueEntry\n\t\t{\n\t\t\tDeallocatorQueueEntry() = default;\n\t\t\tDeallocatorQueueEntry(OSThread_t* thread, MEMPTR<void> stack, MEMPTR<void> deallocatorFunc) : thread(thread), stack(stack), deallocatorFunc(deallocatorFunc) {};\n\n\t\t\tOSThread_t* thread{};\n\t\t\tMEMPTR<void> stack;\n\t\t\tMEMPTR<void> deallocatorFunc;\n\t\t};\n\n\t\tSysAllocator<OSThread_t> terminatorThread;\n\t\tSysAllocator<uint8, 16 * 1024> threadStack;\n\t\tSysAllocator<char, 64> threadName;\n\t\tSysAllocator<OSSemaphore> semaphoreQueuedDeallocators;\n\t\tConcurrentQueue<DeallocatorQueueEntry> queueDeallocators;\n\t};\n\n\tTerminatorThread s_terminatorThreads[PPC_CORE_COUNT];\n\n\tvoid __OSTerminatorThreadFunc(PPCInterpreter_t* hCPU)\n\t{\n\t\tuint32 coreIndex = OSGetCoreId();\n\t\twhile (OSWaitSemaphore(s_terminatorThreads[coreIndex].semaphoreQueuedDeallocators.GetPtr()))\n\t\t{\n\t\t\tTerminatorThread::DeallocatorQueueEntry queueEntry;\n\t\t\ts_terminatorThreads[coreIndex].queueDeallocators.pop(queueEntry);\n\t\t\tPPCCoreCallback(queueEntry.deallocatorFunc, queueEntry.thread, queueEntry.stack);\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\t// queue thread deallocation to run after current thread finishes\n\t// the termination threads run at a higher priority on the same core\n\tvoid __OSQueueThreadDeallocation(OSThread_t* thread)\n\t{\n\t\tuint32 coreIndex = OSGetCoreId();\n\t\tTerminatorThread::DeallocatorQueueEntry queueEntry(thread, thread->stackEnd, thread->deallocatorFunc);\n\t\ts_terminatorThreads[coreIndex].queueDeallocators.push(queueEntry);\n\t\tOSSignalSemaphoreInternal(s_terminatorThreads[coreIndex].semaphoreQueuedDeallocators.GetPtr(), false); // do not reschedule here! Current thread must not be interrupted otherwise deallocator will run too early\n\t}\n\n\tvoid __OSInitTerminatorThreads()\n\t{\n\t\tfor (sint32 i = 0; i < PPC_CORE_COUNT; i++)\n\t\t{\n\t\t\tOSInitSemaphore(s_terminatorThreads[i].semaphoreQueuedDeallocators.GetPtr(), 0);\n\t\t\tsprintf(s_terminatorThreads[i].threadName.GetPtr(), \"{SYS Thread Terminator Core %d}\", i);\n\t\t\tOSCreateThreadType(s_terminatorThreads[i].terminatorThread.GetPtr(), PPCInterpreter_makeCallableExportDepr(__OSTerminatorThreadFunc), 0, nullptr, (uint8*)s_terminatorThreads[i].threadStack.GetPtr() + s_terminatorThreads[i].threadStack.GetByteSize(), (sint32)s_terminatorThreads[i].threadStack.GetByteSize(), 0, 1 << i, OSThread_t::THREAD_TYPE::TYPE_IO);\n\t\t\tOSSetThreadName(s_terminatorThreads[i].terminatorThread.GetPtr(), s_terminatorThreads[i].threadName.GetPtr());\n\t\t\tOSResumeThread(s_terminatorThreads[i].terminatorThread.GetPtr());\n\t\t}\n\t}\n\n\tSysAllocator<char, 64> _defaultThreadName[PPC_CORE_COUNT];\n\n\tvoid __OSInitDefaultThreads()\n\t{\n\t\tfor (sint32 i = 0; i < PPC_CORE_COUNT; i++)\n\t\t{\n\t\t\tsprintf(_defaultThreadName[i].GetPtr(), \"Default Core %d\", i);\n\t\t\tOSThread_t* coreDefaultThread = coreinit::OSGetDefaultThread(i);\n\t\t\tuint32 stackSize;\n\t\t\tvoid* stackBase = coreinit::OSGetDefaultThreadStack(i, stackSize);\n\t\t\tcoreinit::OSCreateThreadType(coreDefaultThread, MPTR_NULL, 0, nullptr, (uint8*)stackBase + stackSize, stackSize, 16, 1 << i, OSThread_t::THREAD_TYPE::TYPE_APP);\n\t\t\tcoreinit::OSSetThreadName(coreDefaultThread, _defaultThreadName[i].GetPtr());\n\t\t}\n\t}\n\n\tvoid MapThreadExports()\n\t{\n\t\tcafeExportRegister(\"coreinit\", OSCreateThreadType, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSCreateThread, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", __OSCreateThreadType, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSExitThread, LogType::CoreinitThread);\n\n\t\tcafeExportRegister(\"coreinit\", OSGetCurrentThread, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSSetThreadSpecific, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetThreadSpecific, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSSetThreadName, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetThreadName, LogType::CoreinitThread);\n\n\t\tcafeExportRegister(\"coreinit\", OSRunThread, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSDetachThread, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSJoinThread, LogType::CoreinitThread);\n\n\t\tcafeExportRegister(\"coreinit\", OSResumeThread, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSContinueThread, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSSuspendThread, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", __OSSuspendThreadNolock, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSSleepThread, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSWakeupThread, LogType::CoreinitThread);\n\n\t\tcafeExportRegister(\"coreinit\", OSYieldThread, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSSleepTicks, LogType::CoreinitThread);\n\n\t\tcafeExportRegister(\"coreinit\", OSSetThreadDeallocator, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSSetThreadCleanupCallback, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSSetThreadPriority, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetThreadPriority, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSSetThreadAffinity, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSGetThreadAffinity, LogType::CoreinitThread);\n\n\t\tcafeExportRegister(\"coreinit\", OSIsThreadTerminated, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSIsThreadSuspended, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSCancelThread, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSTestThreadCancel, LogType::CoreinitThread);\n\n\t\tcafeExportRegister(\"coreinit\", OSGetDefaultThread, LogType::CoreinitThread);\n\n\t\t// OSThreadQueue\n\t\tcafeExportRegister(\"coreinit\", OSInitThreadQueue, LogType::CoreinitThread);\n\t\tcafeExportRegister(\"coreinit\", OSInitThreadQueueEx, LogType::CoreinitThread);\n    }\n\n\tvoid InitializeThread()\n\t{\n\t\tOSInitThreadQueue(g_activeThreadQueue.GetPtr());\n\t\tfor (sint32 i = 0; i < Espresso::CORE_COUNT; i++)\n\t\t\tOSInitThreadQueue(g_coreRunQueue.GetPtr() + i);\n\t\tfor (sint32 i = 0; i < Espresso::CORE_COUNT; i++)\n\t\t\t__currentCoreThread[i] = nullptr;\n\t\t__OSInitDefaultThreads();\n\t\t__OSInitTerminatorThreads();\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Thread.h",
    "content": "#pragma once\n#include \"Cafe/HW/Espresso/Const.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Scheduler.h\"\n\nstruct OSThread_t;\n\nstruct OSContextRegFPSCR_t\n{\n\t// FPSCR is a 32bit register but it's stored as a 64bit double\n\t/* +0x00 */ uint32be padding;\n\t/* +0x04 */ uint32be fpscr;\n};\n\nstruct OSContext_t\n{\n\tstatic constexpr uint32 OS_CONTEXT_MAGIC_0 = 0x4f53436f; // \"OSCo\"\n\tstatic constexpr uint32 OS_CONTEXT_MAGIC_1 = 0x6e747874; // \"ntxt\"\n\n\t/* +0x000 */ betype<uint32> magic0;\n\t/* +0x004 */ betype<uint32> magic1;\n\t/* +0x008 */ uint32 gpr[32];\n\t/* +0x088 */ uint32 cr;\n\t/* +0x08C */ uint32 lr;\n\t/* +0x090 */ uint32 ctr;\n\t/* +0x094 */ uint32 xer;\n\t/* +0x098 */ uint32 srr0;\n\t/* +0x09C */ uint32 srr1;\n\t/* +0x0A0 */ uint32 dsi_dsisr;\n\t/* +0x0A4 */ uint32 dsi_dar;\n\t/* +0x0A8 */ uint32 ukn0A8;\n\t/* +0x0AC */ uint32 ukn0AC;\n\t/* +0x0B0 */ OSContextRegFPSCR_t fpscr;\n\t/* +0x0B8 */ uint64be fp_ps0[32];\n\t/* +0x1B8 */ uint16be boostCount;\n\t/* +0x1BA */ uint16 state;\t\t\t// OS_CONTEXT_STATE_*\n\t/* +0x1BC */ uint32 gqr[8];\t\t\t// GQR/UGQR\n\t/* +0x1DC */ uint32be upir;\t\t\t// set to current core index\n\t/* +0x1E0 */ uint64be fp_ps1[32];\n\t/* +0x2E0 */ uint64be coretime[3];\n\t/* +0x2F8 */ uint64be starttime;\n\t/* +0x300 */ sint32be ghs_errno;         // returned by __gh_errno_ptr() (used by socketlasterr)\n\t/* +0x304 */ uint32be affinity;\n\t/* +0x308 */ uint32be upmc1;\n\t/* +0x30C */ uint32be upmc2;\n\t/* +0x310 */ uint32be upmc3;\n\t/* +0x314 */ uint32be upmc4;\n\t/* +0x318 */ uint32be ummcr0;\n\t/* +0x31C */ uint32be ummcr1;\n\n\tbool checkMagic()\n\t{\n\t\treturn magic0 == (uint32)OS_CONTEXT_MAGIC_0 && magic1 == (uint32)OS_CONTEXT_MAGIC_1;\n\t}\n\n\tvoid SetContextMagic()\n\t{\n\t\tmagic0 = OS_CONTEXT_MAGIC_0;\n\t\tmagic1 = OS_CONTEXT_MAGIC_1;\n\t}\n\n\n\tbool hasCoreAffinitySet(uint32 coreIndex) const\n\t{\n\t\treturn (((uint32)affinity >> coreIndex) & 1) != 0;\n\t}\n\n\tvoid setAffinity(uint32 mask)\n\t{\n\t\taffinity = mask & 7;\n\t}\n\n\tuint32 getAffinity() const\n\t{\n\t\treturn affinity;\n\t}\n};\n\nstatic_assert(sizeof(OSContext_t) == 0x320);\n\ntypedef struct\n{\n\t/* +0x000 | +0x3A0 */ uint32 ukn000[0x68 / 4];\n\t/* +0x068 | +0x408 */ MEMPTR<void> eh_globals;\n\t/* +0x06C | +0x40C */ uint32 eh_mem_manage[9]; // struct\n\t/* +0x090 | +0x430 */ MPTR eh_store_globals[6];\n\t/* +0x0A8 | +0x448 */ MPTR eh_store_globals_tdeh[76];\n}crt_t; // size: 0x1D8\n\nstatic_assert(sizeof(crt_t) == 0x1D8, \"\");\n\n#pragma pack(1)\n\nnamespace coreinit\n{\n\n\t/********* OSThreadQueue *********/\n\n\tstruct OSThreadLink\n\t{\n\t\tMEMPTR<struct OSThread_t> next;\n\t\tMEMPTR<struct OSThread_t> prev;\n\t};\n\n\tstatic_assert(sizeof(OSThreadLink) == 8);\n\n\tstruct OSThreadQueueInternal\n\t{\n\t\tMEMPTR<OSThread_t> head;\n\t\tMEMPTR<OSThread_t> tail;\n\n\t\tbool isEmpty() const\n\t\t{\n\t\t\tcemu_assert_debug((!head.IsNull() == !tail.IsNull()) || (head.IsNull() == tail.IsNull()));\n\t\t\treturn head.IsNull();\n\t\t}\n\n\t\tvoid addThread(OSThread_t* thread, OSThreadLink* threadLink);\n\t\tvoid addThreadByPriority(OSThread_t* thread, OSThreadLink* threadLink);\n\t\tvoid removeThread(OSThread_t* thread, OSThreadLink* threadLink);\n\n\t\t// puts the thread on the waiting queue and changes state to WAITING\n\t\t// relinquishes timeslice\n\t\t// always uses thread->waitQueueLink\n\t\tvoid queueAndWait(OSThread_t* thread);\n\t\tvoid queueOnly(OSThread_t* thread);\n\n\t\t// counterparts for queueAndWait\n\t\tvoid cancelWait(OSThread_t* thread);\n\t\tvoid wakeupEntireWaitQueue(bool reschedule, bool sharedPriorityAndAffinityWorkaround = false);\n\t\tvoid wakeupSingleThreadWaitQueue(bool reschedule, bool sharedPriorityAndAffinityWorkaround = false);\n\n\tprivate:\n\t\tOSThread_t* takeFirstFromQueue(size_t linkOffset)\n\t\t{\n\t\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\t\tif (head == nullptr)\n\t\t\t\treturn nullptr;\n\t\t\tOSThread_t* thread = head.GetPtr();\n\t\t\tOSThreadLink* link = _getThreadLink(thread, linkOffset);\n\t\t\tremoveThread(thread, link);\n\t\t\treturn thread;\n\t\t}\n\n\t\tstatic size_t getLinkOffset(OSThread_t* thread, OSThreadLink* threadLink)\n\t\t{\n\t\t\tcemu_assert_debug((void*)threadLink >= (void*)thread && (void*)threadLink < (void*)((uint8*)thread + 0x680));\n\t\t\treturn (uint8*)threadLink - (uint8*)thread;\n\t\t}\n\n\t\tstatic OSThreadLink* _getThreadLink(OSThread_t* thread, size_t linkOffset)\n\t\t{\n\t\t\treturn (OSThreadLink*)((uint8*)thread + linkOffset);\n\t\t}\n\n\t\tvoid _debugCheckChain(OSThread_t* thread, OSThreadLink* threadLink)\n\t\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\t\tcemu_assert_debug(tail.IsNull() == head.IsNull());\n\t\t\tsize_t linkOffset = getLinkOffset(thread, threadLink);\n\t\t\t// expects thread to be in the chain\n\t\t\tOSThread_t* threadItr = head.GetPtr();\n\t\t\twhile (threadItr)\n\t\t\t{\n\t\t\t\tif (threadItr == thread)\n\t\t\t\t\treturn;\n\t\t\t\tthreadItr = _getThreadLink(threadItr, linkOffset)->next.GetPtr();\n\t\t\t}\n\t\t\tcemu_assert_debug(false); // thread not in list!\n#endif\n\t\t}\n\t};\n\n\tstatic_assert(sizeof(OSThreadQueueInternal) == 0x8);\n\n\tstruct OSThreadQueueSmall : public OSThreadQueueInternal\n\t{\n\t\t// no extra members\n\t};\n\n\tstatic_assert(sizeof(OSThreadQueueSmall) == 8);\n\tstatic_assert(offsetof(OSThreadQueueSmall, head) == 0x0);\n\tstatic_assert(offsetof(OSThreadQueueSmall, tail) == 0x4);\n\n\tstruct OSThreadQueue : public OSThreadQueueInternal\n\t{\n\t\tMEMPTR<void> userData;\n\t\tuint32be ukn0C;\n\t};\n\n\tstatic_assert(sizeof(OSThreadQueue) == 0x10);\n\tstatic_assert(offsetof(OSThreadQueue, head) == 0x0);\n\tstatic_assert(offsetof(OSThreadQueue, tail) == 0x4);\n\tstatic_assert(offsetof(OSThreadQueue, userData) == 0x8);\n\tstatic_assert(offsetof(OSThreadQueue, ukn0C) == 0xC);\n\n\t/********* OSMutex *********/\n\n\tstruct OSMutex\n\t{\n\t\t/* +0x00 */ uint32\t\t\t\tmagic;\n\t\t/* +0x04 */ MEMPTR<void>\t\tuserData;\n\t\t/* +0x08 */ uint32be\t\t\tukn08;\n\t\t/* +0x0C */ OSThreadQueue\t\tthreadQueue;\n\t\t/* +0x1C */ MEMPTR<OSThread_t>\towner;\n\t\t/* +0x20 */ sint32be\t\t\tlockCount;\n\t\t/* +0x24 */ MEMPTR<OSMutex>\t\tnext;\n\t\t/* +0x28 */ MEMPTR<OSMutex>\t\tprev;\n\n\t}; // size: 0x2C\n\n\tstatic_assert(sizeof(OSMutex) == 0x2C);\n\n\tstruct OSMutexQueue\n\t{\n\t\tMEMPTR<OSMutex> head;\n\t\tMEMPTR<OSMutex> tail;\n\t\tMEMPTR<void> ukn08;\n\t\tuint32be ukn0C;\n\n\t\tbool isEmpty() const\n\t\t{\n\t\t\tcemu_assert_debug((!head.IsNull() == !tail.IsNull()) || (head.IsNull() == tail.IsNull()));\n\t\t\treturn head.IsNull();\n\t\t}\n\n\t\tvoid addMutex(OSMutex* mutex)\n\t\t{\n\t\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\t\t// insert at end\n\t\t\tif (tail.IsNull())\n\t\t\t{\n\t\t\t\tmutex->next = nullptr;\n\t\t\t\tmutex->prev = nullptr;\n\t\t\t\thead = mutex;\n\t\t\t\ttail = mutex;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttail->next = mutex;\n\t\t\t\tmutex->prev = tail;\n\t\t\t\tmutex->next = nullptr;\n\t\t\t\ttail = mutex;\n\t\t\t}\n\t\t}\n\n\t\tvoid removeMutex(OSMutex* mutex)\n\t\t{\n\t\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\t\tcemu_assert_debug(!head.IsNull() && !tail.IsNull());\n\t\t\tif (mutex->prev)\n\t\t\t\tmutex->prev->next = mutex->next;\n\t\t\telse\n\t\t\t\thead = mutex->next;\n\t\t\tif (mutex->next)\n\t\t\t\tmutex->next->prev = mutex->prev;\n\t\t\telse\n\t\t\t\ttail = mutex->prev;\n\t\t\tmutex->next = nullptr;\n\t\t\tmutex->prev = nullptr;\n\t\t}\n\n\t\tOSMutex* getFirst()\n\t\t{\n\t\t\treturn head.GetPtr();\n\t\t}\n\t};\n\n\tstatic_assert(sizeof(OSMutexQueue) == 0x10);\n\n\t/********* OSFastMutex *********/\n\n\tstruct OSFastMutexLink\n\t{\n\t\t/* +0x00 */ MEMPTR<struct OSMutex> next;\n\t\t/* +0x04 */ MEMPTR<struct OSMutex> prev;\n\t};\n\n\tstruct OSFastMutex\n\t{\n\t\t/* +0x00 */ uint32be magic;\n\t\t/* +0x04 */ MEMPTR<void> userData;\n\t\t/* +0x08 */ uint32be contendedState; // tracks current contention state\n\t\t/* +0x0C */ OSThreadQueueSmall threadQueueSmall;\n\t\t/* +0x14 */ OSFastMutexLink ownedLink; // part of thread->fastMutexOwnedQueue\n\t\t/* +0x1C */ MEMPTR<OSThread_t> owner;\n\t\t/* +0x20 */ uint32be lockCount;\n\t\t/* +0x24 */ OSFastMutexLink contendedLink;\n\t};\n\n\tstatic_assert(sizeof(OSFastMutex) == 0x2C);\n\n\t/********* OSEvent *********/\n\n\tstruct OSEvent\n\t{\n\t\tenum class EVENT_MODE : uint32\n\t\t{\n\t\t\tMODE_MANUAL = 0,\n\t\t\tMODE_AUTO = 1,\n\t\t};\n\n\t\tenum class EVENT_STATE : uint32\n\t\t{\n\t\t\tSTATE_NOT_SIGNALED = 0,\n\t\t\tSTATE_SIGNALED = 1\n\t\t};\n\n\t\t/* +0x00 */ uint32be magic; // 'eVnT'\n\t\t/* +0x04 */ MEMPTR<void> userData;\n\t\t/* +0x08 */ uint32be ukn08;\n\t\t/* +0x0C */ betype<EVENT_STATE> state; // 0 -> not signaled, 1 -> signaled\n\t\t/* +0x10 */ OSThreadQueue threadQueue;\n\t\t/* +0x20 */ betype<EVENT_MODE> mode;\n\t};\n\n\tstatic_assert(sizeof(OSEvent) == 0x24);\n\n\t/********* OSRendezvous *********/\n\n\tstruct OSRendezvous\n\t{\n\t\t/* +0x00 */ uint32be coreHit[3];\n\t\t/* +0x0C */ MEMPTR<void> userData;\n\t};\n\n\tstatic_assert(sizeof(OSRendezvous) == 0x10);\n\n\t/********* OSCond *********/\n\n\tstruct OSCond\n\t{\n\t\tuint32be magic;\n\t\tMEMPTR<void> userData;\n\t\tuint32be ukn08;\n\t\tOSThreadQueue threadQueue;\n\t};\n\n\tstatic_assert(sizeof(OSCond) == 0x1C);\n\n\t/********* OSSemaphore *********/\n\n\tstruct OSSemaphore\n\t{\n\t\tuint32be magic;\n\t\tMEMPTR<void> userData;\n\t\tuint32be ukn08;\n\t\tsint32be count;\n\t\tOSThreadQueue threadQueue;\n\t};\n\n\tstatic_assert(sizeof(OSSemaphore) == 0x20);\n\n\t/********* OSFastCond *********/\n\n\tstruct OSFastCond\n\t{\n\t\tuint32be magic;\n\t\tMEMPTR<void> userData;\n\t\tuint32be ukn08;\n\t\tOSThreadQueue threadQueue;\n\t};\n\n\tstatic_assert(sizeof(OSFastCond) == 0x1C);\n\n};\n\nstruct OSThread_t\n{\n\tstatic constexpr uint32 MAGIC_THREAD = 0x74487244; // \"tHrD\"\n\n\tenum class THREAD_TYPE : uint32\n\t{\n\t\tTYPE_DRIVER = 0,\n\t\tTYPE_IO = 1,\n\t\tTYPE_APP = 2\n\t};\n\n\tenum class THREAD_STATE : uint8\n\t{\n\t\tSTATE_NONE = 0,\n\t\tSTATE_READY = 1,\n\t\tSTATE_RUNNING = 2,\n\t\tSTATE_WAITING = 4,\n\t\tSTATE_MORIBUND = 8,\n\t};\n\n\tenum ATTR_BIT : uint32\n\t{\n\t\tATTR_AFFINITY_CORE0 = 0x1,\n\t\tATTR_AFFINITY_CORE1 = 0x2,\n\t\tATTR_AFFINITY_CORE2 = 0x4,\n\t\tATTR_DETACHED\t\t= 0x8,\n\t\tATTR_UKN_010\t\t= 0x10,\n\t};\n\n\tenum REQUEST_FLAG_BIT : uint32\n\t{\n\t\tREQUEST_FLAG_NONE = 0,\n\t\tREQUEST_FLAG_SUSPEND = 1,\n\t\tREQUEST_FLAG_CANCEL = 2,\n\t};\n\n\tstatic sint32 GetTypePriorityBase(THREAD_TYPE threadType)\n\t{\n\t\tif (threadType == OSThread_t::THREAD_TYPE::TYPE_DRIVER)\n\t\t\treturn 0;\n\t\telse if (threadType == OSThread_t::THREAD_TYPE::TYPE_IO)\n\t\t\treturn 32;\n\t\telse if (threadType == OSThread_t::THREAD_TYPE::TYPE_APP)\n\t\t\treturn 64;\n\t\treturn 0;\n\t}\n\n    void SetThreadMagic()\n    {\n        magic = MAGIC_THREAD;\n    }\n\n    bool IsValidMagic() const\n    {\n        return magic == MAGIC_THREAD && context.magic0 == OSContext_t::OS_CONTEXT_MAGIC_0 && context.magic1 == OSContext_t::OS_CONTEXT_MAGIC_1;\n    }\n\n\t/* +0x000 */ OSContext_t\t\t\t\t\t\tcontext;\n\t/* +0x320 */ uint32be\t\t\t\t\t\t\tmagic;\t\t\t\t\t\t\t\t// \"tHrD\" (0x74487244)\n\t/* +0x324 */ betype<THREAD_STATE>\t\t\t\tstate;\n\t/* +0x325 */ uint8\t\t\t\t\t\t\t\tattr;\n\t/* +0x326 */ uint16be\t\t\t\t\t\t\tid;\t\t\t\t\t\t\t\t\t// Warriors Orochi 3 uses this to identify threads\n\t/* +0x328 */ betype<sint32>\t\t\t\t\t\tsuspendCounter;\n\t/* +0x32C */ sint32be\t\t\t\t\t\t\teffectivePriority;\t\t\t\t\t// effective priority (lower is higher)\n\t/* +0x330 */ sint32be\t\t\t\t\t\t\tbasePriority;\t\t\t\t\t\t// base priority (lower is higher)\n\t/* +0x334 */ uint32be\t\t\t\t\t\t\texitValue;\t\t\t\t\t\t\t// set by OSExitThread() or by returning from the thread entrypoint\n\n\t/* +0x338 */ MEMPTR<coreinit::OSThreadQueue>\tcurrentRunQueue[Espresso::CORE_COUNT];\t// points to the OSThreadQueue on which this thread is (null if not in queue)\n\t/* +0x344 */ coreinit::OSThreadLink\t\t\t\tlinkRun[Espresso::CORE_COUNT];\n\n\t// general wait queue / thread dependency queue\n\t/* +0x35C */ MEMPTR<coreinit::OSThreadQueueInternal> currentWaitQueue;\t\t\t\t// shared between OSThreadQueue and OSThreadQueueSmall\n\t/* +0x360 */ coreinit::OSThreadLink\t\t\t\twaitQueueLink;\n\n\t/* +0x368 */ coreinit::OSThreadQueue\t\t\tjoinQueue;\n\n\t/* +0x378 */ MEMPTR<coreinit::OSMutex>\t\t\twaitingForMutex;\t\t\t\t\t// set when thread is waiting for OSMutex to unlock\n\t/* +0x37C */ coreinit::OSMutexQueue\t\t\t\tmutexQueue;\n\n\t/* +0x38C */ coreinit::OSThreadLink\t\t\t\tactiveThreadChain;\t\t\t\t\t// queue of active threads (g_activeThreadQueue)\n\n\t/* +0x394 */ MEMPTR<void>\t\t\t\t\t\tstackBase;\t\t\t\t\t\t\t// upper limit of stack\n\t/* +0x398 */ MEMPTR<void>\t\t\t\t\t\tstackEnd;\t\t\t\t\t\t\t// lower limit of stack\n\n\t/* +0x39C */ MEMPTR<void>\t\t\t\t\t\tentrypoint;\n\t/* +0x3A0 */ crt_t\t\t\t\t\t\t\t\tcrt;\n\n\t/* +0x578 */ sint32\t\t\t\t\t\t\t\talarmRelatedUkn;\n\t/* +0x57C */ std::array<MEMPTR<void>, 16>\t\tspecificArray;\n\t/* +0x5BC */ betype<THREAD_TYPE>\t\t\t\ttype;\n\t/* +0x5C0 */ MEMPTR<const char>\t\t\t\t\tthreadName;\n\t/* +0x5C4 */ MEMPTR<void>\t\t\t\t\t\twaitAlarm;\t\t\t\t\t\t\t// used only by OSWaitEventWithTimeout/OSSignalEvent ?\n\n\t/* +0x5C8 */ uint32\t\t\t\t\t\t\t\tuserStackPointer;\n\n\t/* +0x5CC */ MEMPTR<void>\t\t\t\t\t\tcleanupCallback;\n\t/* +0x5D0 */ MEMPTR<void>\t\t\t\t\t\tdeallocatorFunc;\n\n\t/* +0x5D4 */ uint32\t\t\t\t\t\t\t\tstateFlags;\t\t\t\t\t\t// 0x5D4 | various flags? Controls if canceling/suspension is allowed (at cancel points) or not? If 1 -> Cancel/Suspension not allowed, if 0 -> Cancel/Suspension allowed\n\t/* +0x5D8 */ betype<REQUEST_FLAG_BIT>\t\t\trequestFlags;\n\t/* +0x5DC */ sint32\t\t\t\t\t\t\t\tpendingSuspend;\n\t/* +0x5E0 */ sint32\t\t\t\t\t\t\t\tsuspendResult;\n\t/* +0x5E4 */ coreinit::OSThreadQueue\t\t\tsuspendQueue;\n\t/* +0x5F4 */ uint32\t\t\t\t\t\t\t\t_padding5F4;\n\t/* +0x5F8 */ uint64be\t\t\t\t\t\t\tquantumTicks;\n\t/* +0x600 */ uint64\t\t\t\t\t\t\t\tcoretimeSumQuantumStart;\n\n\t/* +0x608 */ uint64be\t\t\t\t\t\t\twakeUpCount;\t\t\t\t\t\t// number of times the thread entered running state\n\t/* +0x610 */ uint64be\t\t\t\t\t\t\ttotalCycles;\t\t\t\t\t\t// sum of cycles this thread was active since it was created\n\t/* +0x618 */ uint64be\t\t\t\t\t\t\twakeUpTime;\t\t\t\t\t\t\t// time when thread first became active (Should only be set once(?) but we currently set this on every timeslice since thats more useful for debugging)\n\t/* +0x620 */ uint64\t\t\t\t\t\t\t\twakeTimeRelatedUkn1;\n\t/* +0x628 */ uint64\t\t\t\t\t\t\t\twakeTimeRelatedUkn2;\n\n\t// set via OSSetExceptionCallback\n\t/* +0x630 */ MPTR\t\t\t\t\t\t\t\tdsiCallback[Espresso::CORE_COUNT];\n\t/* +0x63C */ MPTR\t\t\t\t\t\t\t\tisiCallback[Espresso::CORE_COUNT];\n\t/* +0x648 */ MPTR\t\t\t\t\t\t\t\tprogramCallback[Espresso::CORE_COUNT];\n\t/* +0x654 */ MPTR\t\t\t\t\t\t\t\tperfMonCallback[Espresso::CORE_COUNT];\n\n\t/* +0x660 */ uint32\t\t\t\t\t\t\t\tukn660;\n\n\t// todo - some of the members towards the end of the struct were only added in later COS versions. Figure out the mapping between version and members\n\n\t// TLS\n\t/* +0x664 */ uint16\t\t\t\t\t\t\t\tnumAllocatedTLSBlocks;\n\t/* +0x666 */ sint16\t\t\t\t\t\t\t\ttlsStatus;\n\t/* +0x668 */ MPTR\t\t\t\t\t\t\t\ttlsBlocksMPTR;\n\t\n\t/* +0x66C */ MEMPTR<coreinit::OSFastMutex>\t\twaitingForFastMutex;\n\t/* +0x670 */ coreinit::OSFastMutexLink\t\t\tcontendedFastMutex;\n\t/* +0x678 */ coreinit::OSFastMutexLink\t\t\townedFastMutex;\n\t/* +0x680 */ MEMPTR<void>\t\t\t\t\t\talignmentExceptionCallback[Espresso::CORE_COUNT];\n\n\t/* +0x68C */ uint32\t\t\t\t\t\t\t\tpadding68C[20 / 4];\n};\nstatic_assert(sizeof(OSThread_t) == 0x6A0);\n\nnamespace coreinit\n{\n\tvoid MapThreadExports();\n\tvoid InitializeThread();\n\n\tvoid InitializeConcurrency();\n\n\tbool __CemuIsMulticoreMode();\n\n\tOSThread_t* OSGetDefaultThread(sint32 coreIndex);\n\tvoid* OSGetDefaultThreadStack(sint32 coreIndex, uint32& size);\n\n\tbool OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop2, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType);\n\tbool __OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType);\n\tvoid OSCreateThreadInternal(OSThread_t* thread, uint32 entryPoint, MPTR stackLowerBaseAddr, uint32 stackSize, uint8 affinityMask, OSThread_t::THREAD_TYPE threadType);\n\tbool OSRunThread(OSThread_t* thread, MPTR funcAddress, sint32 numParam, void* ptrParam);\n\tvoid OSExitThread(sint32 exitValue);\n\tvoid OSDetachThread(OSThread_t* thread);\n\n\tOSThread_t* OSGetCurrentThread();\n\tvoid OSSetCurrentThread(uint32 coreIndex, OSThread_t* thread);\n\n\tvoid __OSSetThreadBasePriority(OSThread_t* thread, sint32 newPriority);\n\tvoid __OSUpdateThreadEffectivePriority(OSThread_t* thread);\n\n\tbool OSSetThreadPriority(OSThread_t* thread, sint32 newPriority);\n\tuint32 OSGetThreadAffinity(OSThread_t* thread);\n\n\tvoid OSSetThreadName(OSThread_t* thread, const char* name);\n\tconst char* OSGetThreadName(OSThread_t* thread);\n\n\tsint32 __OSResumeThreadInternal(OSThread_t* thread, sint32 resumeCount);\n\tsint32 OSResumeThread(OSThread_t* thread);\n\tvoid OSContinueThread(OSThread_t* thread);\n\tvoid __OSSuspendThreadInternal(OSThread_t* thread);\n\tvoid __OSSuspendThreadNolock(OSThread_t* thread);\n\tvoid OSSuspendThread(OSThread_t* thread);\n\tvoid OSSleepThread(OSThreadQueue* threadQueue);\n\tvoid OSWakeupThread(OSThreadQueue* threadQueue);\n\tbool OSJoinThread(OSThread_t* thread, uint32be* exitValue);\n\n\tvoid OSTestThreadCancelInternal();\n\n\tvoid OSYieldThread();\n\tvoid OSSleepTicks(uint64 ticks);\n\n\tbool OSIsThreadTerminated(OSThread_t* thread);\n\tbool OSIsThreadSuspended(OSThread_t* thread);\n    bool OSIsThreadRunningNoLock(OSThread_t* thread);\n\tbool OSIsThreadRunning(OSThread_t* thread);\n\n\t// OSThreadQueue\n\tvoid OSInitThreadQueue(OSThreadQueue* threadQueue);\n\tvoid OSInitThreadQueueEx(OSThreadQueue* threadQueue, void* userData);\n\n\t// OSEvent\n\tvoid OSInitEvent(OSEvent* event, OSEvent::EVENT_STATE initialState, OSEvent::EVENT_MODE mode);\n\tvoid OSInitEventEx(OSEvent* event, OSEvent::EVENT_STATE initialState, OSEvent::EVENT_MODE mode, void* userData);\n\tvoid OSResetEvent(OSEvent* event);\n\tvoid OSWaitEventInternal(OSEvent* event); // assumes lock is already held\n\tvoid OSWaitEvent(OSEvent* event);\n\tbool OSWaitEventWithTimeout(OSEvent* event, uint64 timeout);\n\tvoid OSSignalEventInternal(OSEvent* event); // assumes lock is already held\n\tvoid OSSignalEvent(OSEvent* event);\n\tvoid OSSignalEventAllInternal(OSEvent* event); // assumes lock is already held\n\tvoid OSSignalEventAll(OSEvent* event);\n\n\t// OSRendezvous\n\tvoid OSInitRendezvous(OSRendezvous* rendezvous);\n\tbool OSWaitRendezvous(OSRendezvous* rendezvous, uint32 coreMask);\n\n\t// OSMutex\n\tvoid OSInitMutex(OSMutex* mutex);\n\tvoid OSInitMutexEx(OSMutex* mutex, void* userData);\n\tvoid OSLockMutex(OSMutex* mutex);\n\tbool OSTryLockMutex(OSMutex* mutex);\n\tvoid OSUnlockMutex(OSMutex* mutex);\n\tvoid OSUnlockMutexInternal(OSMutex* mutex);\n\n\t// OSCond\n\tvoid OSInitCond(OSCond* cond);\n\tvoid OSInitCondEx(OSCond* cond, void* userData);\n\tvoid OSSignalCond(OSCond* cond);\n\tvoid OSWaitCond(OSCond* cond, OSMutex* mutex);\n\n\t// OSSemaphore\n\tvoid OSInitSemaphore(OSSemaphore* semaphore, sint32 initialCount);\n\tvoid OSInitSemaphoreEx(OSSemaphore* semaphore, sint32 initialCount, void* userData);\n\tsint32 OSWaitSemaphoreInternal(OSSemaphore* semaphore);\n\tsint32 OSWaitSemaphore(OSSemaphore* semaphore);\n\tsint32 OSTryWaitSemaphore(OSSemaphore* semaphore);\n\tsint32 OSSignalSemaphore(OSSemaphore* semaphore);\n\tsint32 OSSignalSemaphoreInternal(OSSemaphore* semaphore, bool reschedule);\n\tsint32 OSGetSemaphoreCount(OSSemaphore* semaphore);\n\n\t// OSFastMutex\n\tvoid OSFastMutex_Init(OSFastMutex* fastMutex, void* userData);\n\tvoid OSFastMutex_Lock(OSFastMutex* fastMutex);\n\tbool OSFastMutex_TryLock(OSFastMutex* fastMutex);\n\tvoid OSFastMutex_Unlock(OSFastMutex* fastMutex);\n\n\t// OSFastCond\n\tvoid OSFastCond_Init(OSFastCond* fastCond, void* userData);\n\tvoid OSFastCond_Wait(OSFastCond* fastCond, OSFastMutex* fastMutex);\n\tvoid OSFastCond_Signal(OSFastCond* fastCond);\n\n\t// scheduler\n\tvoid OSSchedulerBegin(sint32 numCPUEmulationThreads);\n\tvoid OSSchedulerEnd();\n\n\t// internal\n\tvoid __OSAddReadyThreadToRunQueue(OSThread_t* thread);\n\tbool __OSCoreShouldSwitchToThread(OSThread_t* currentThread, OSThread_t* newThread, bool sharedPriorityAndAffinityWorkaround);\n\tvoid __OSQueueThreadDeallocation(OSThread_t* thread);\n\n    bool __OSIsThreadActive(OSThread_t* thread);\n\tvoid __OSDeleteAllActivePPCThreads();\n}\n\n#pragma pack()\n\n// deprecated / clean up required\nextern MPTR activeThread[256];\nextern sint32 activeThreadCount;\n\nextern SlimRWLock srwlock_activeThreadList;"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_ThreadQueue.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n\nnamespace coreinit\n{\n\n\t// puts the thread on the waiting queue and changes state to WAITING\n\t// relinquishes timeslice\n\t// always uses thread->waitQueueLink\n\tvoid OSThreadQueueInternal::queueAndWait(OSThread_t* thread)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tcemu_assert_debug(thread->waitQueueLink.next == nullptr && thread->waitQueueLink.prev == nullptr);\n\t\tthread->currentWaitQueue = this;\n\t\tthis->addThreadByPriority(thread, &thread->waitQueueLink);\n\t\tcemu_assert_debug(thread->state == OSThread_t::THREAD_STATE::STATE_RUNNING);\n\t\tthread->state = OSThread_t::THREAD_STATE::STATE_WAITING;\n\t\tPPCCore_switchToSchedulerWithLock();\n\t\tcemu_assert_debug(thread->state == OSThread_t::THREAD_STATE::STATE_RUNNING);\n\t}\n\n\tvoid OSThreadQueueInternal::queueOnly(OSThread_t* thread)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tcemu_assert_debug(thread->waitQueueLink.next == nullptr && thread->waitQueueLink.prev == nullptr);\n\t\tthread->currentWaitQueue = this;\n\t\tthis->addThreadByPriority(thread, &thread->waitQueueLink);\n\t\tcemu_assert_debug(thread->state == OSThread_t::THREAD_STATE::STATE_RUNNING);\n\t\tthread->state = OSThread_t::THREAD_STATE::STATE_WAITING;\n\t}\n\n\t// remove thread from wait queue and wake it up\n\tvoid OSThreadQueueInternal::cancelWait(OSThread_t* thread)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tthis->removeThread(thread, &thread->waitQueueLink);\n\t\tthread->state = OSThread_t::THREAD_STATE::STATE_READY;\n\t\tthread->currentWaitQueue = nullptr;\n\t\tcoreinit::__OSAddReadyThreadToRunQueue(thread);\n\t\t// todo - if waking up a thread on the same core with higher priority, reschedule\n\t}\n\n\tvoid OSThreadQueueInternal::addThread(OSThread_t* thread, OSThreadLink* threadLink)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tsize_t linkOffset = getLinkOffset(thread, threadLink);\n\t\t// insert after tail\n\t\tif (tail.IsNull())\n\t\t{\n\t\t\tthreadLink->next = nullptr;\n\t\t\tthreadLink->prev = nullptr;\n\t\t\thead = thread;\n\t\t\ttail = thread;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthreadLink->next = nullptr;\n\t\t\tthreadLink->prev = tail;\n\t\t\t_getThreadLink(tail.GetPtr(), linkOffset)->next = thread;\n\t\t\ttail = thread;\n\t\t}\n\t\t_debugCheckChain(thread, threadLink);\n\t}\n\n\tvoid OSThreadQueueInternal::addThreadByPriority(OSThread_t* thread, OSThreadLink* threadLink)\n\t{\n\t\tcemu_assert_debug(tail.IsNull() == head.IsNull()); // either must be set or none at all\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tsize_t linkOffset = getLinkOffset(thread, threadLink);\n\t\tif (tail.IsNull())\n\t\t{\n\t\t\tthreadLink->next = nullptr;\n\t\t\tthreadLink->prev = nullptr;\n\t\t\thead = thread;\n\t\t\ttail = thread;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// insert towards tail based on priority\n\t\t\tOSThread_t* threadItr = tail.GetPtr();\n\t\t\twhile (threadItr && threadItr->effectivePriority > thread->effectivePriority)\n\t\t\t\tthreadItr = _getThreadLink(threadItr, linkOffset)->prev.GetPtr();\n\t\t\tif (threadItr == nullptr)\n\t\t\t{\n\t\t\t\t// insert in front\n\t\t\t\tthreadLink->next = head;\n\t\t\t\tthreadLink->prev = nullptr;\n\t\t\t\t_getThreadLink(head.GetPtr(), linkOffset)->prev = thread;\n\t\t\t\thead = thread;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tthreadLink->prev = threadItr;\n\t\t\t\tthreadLink->next = _getThreadLink(threadItr, linkOffset)->next;\n\t\t\t\tif (_getThreadLink(threadItr, linkOffset)->next)\n\t\t\t\t{\n\t\t\t\t\tOSThread_t* threadAfterItr = _getThreadLink(threadItr, linkOffset)->next.GetPtr();\n\t\t\t\t\t_getThreadLink(threadAfterItr, linkOffset)->prev = thread;\n\t\t\t\t\t_getThreadLink(threadItr, linkOffset)->next = thread;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttail = thread;\n\t\t\t\t\t_getThreadLink(threadItr, linkOffset)->next = thread;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t_debugCheckChain(thread, threadLink);\n\t}\n\n\tvoid OSThreadQueueInternal::removeThread(OSThread_t* thread, OSThreadLink* threadLink)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tsize_t linkOffset = getLinkOffset(thread, threadLink);\n\t\t_debugCheckChain(thread, threadLink);\n\t\tif (threadLink->prev)\n\t\t\t_getThreadLink(threadLink->prev.GetPtr(), linkOffset)->next = threadLink->next;\n\t\telse\n\t\t\thead = threadLink->next;\n\t\tif (threadLink->next)\n\t\t\t_getThreadLink(threadLink->next.GetPtr(), linkOffset)->prev = threadLink->prev;\n\t\telse\n\t\t\ttail = threadLink->prev;\n\n\t\tthreadLink->next = nullptr;\n\t\tthreadLink->prev = nullptr;\n\t}\n\n\t// counterpart for queueAndWait\n\t// if reschedule is true then scheduler will switch to woken up thread (if it is runnable on the same core)\n\t// sharedPriorityAndAffinityWorkaround is currently a hack/placeholder for some special cases. A proper fix likely involves handling all the nuances of thread effective priority\n\tvoid OSThreadQueueInternal::wakeupEntireWaitQueue(bool reschedule, bool sharedPriorityAndAffinityWorkaround)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tbool shouldReschedule = false;\n\t\twhile (OSThread_t* thread = takeFirstFromQueue(offsetof(OSThread_t, waitQueueLink)))\n\t\t{\n\t\t\tcemu_assert_debug(thread->state == OSThread_t::THREAD_STATE::STATE_WAITING);\n\t\t\t//cemu_assert_debug(thread->suspendCounter == 0);\n\t\t\tthread->state = OSThread_t::THREAD_STATE::STATE_READY;\n\t\t\tthread->currentWaitQueue = nullptr;\n\t\t\tcoreinit::__OSAddReadyThreadToRunQueue(thread);\n\t\t\tif (reschedule && thread->suspendCounter == 0 && PPCInterpreter_getCurrentInstance() && __OSCoreShouldSwitchToThread(coreinit::OSGetCurrentThread(), thread, sharedPriorityAndAffinityWorkaround))\n\t\t\t\tshouldReschedule = true;\n\t\t}\n\t\tif (shouldReschedule)\n\t\t\tPPCCore_switchToSchedulerWithLock();\n\t}\n\n\t// counterpart for queueAndWait\n\t// if reschedule is true then scheduler will switch to woken up thread (if it is runnable on the same core)\n\tvoid OSThreadQueueInternal::wakeupSingleThreadWaitQueue(bool reschedule, bool sharedPriorityAndAffinityWorkaround)\n\t{\n\t\tcemu_assert_debug(__OSHasSchedulerLock());\n\t\tOSThread_t* thread = takeFirstFromQueue(offsetof(OSThread_t, waitQueueLink));\n\t\tcemu_assert_debug(thread);\n\t\tbool shouldReschedule = false;\n\t\tif (thread)\n\t\t{\n\t\t\tthread->state = OSThread_t::THREAD_STATE::STATE_READY;\n\t\t\tthread->currentWaitQueue = nullptr;\n\t\t\tcoreinit::__OSAddReadyThreadToRunQueue(thread);\n\t\t\tif (reschedule && thread->suspendCounter == 0 && PPCInterpreter_getCurrentInstance() && __OSCoreShouldSwitchToThread(coreinit::OSGetCurrentThread(), thread, sharedPriorityAndAffinityWorkaround))\n\t\t\t\tshouldReschedule = true;\n\t\t}\n\t\tif (shouldReschedule)\n\t\t\tPPCCore_switchToSchedulerWithLock();\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Time.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n\nnamespace coreinit\n{\n\tuint64 coreinit_GetMFTB()\n\t{\n\t\t// bus clock is 1/5th of core clock\n\t\t// timer clock is 1/4th of bus clock\n\t\treturn PPCInterpreter_getMainCoreCycleCounter() / 20ULL;\n\t}\n\n\tuint64 OSGetSystemTime()\n\t{\n\t\treturn coreinit_GetMFTB();\n\t}\n\n\tuint64 OSGetTime()\n\t{\n\t\treturn OSGetSystemTime() + ppcCyclesSince2000TimerClock;\n\t}\n\n\tuint32 OSGetSystemTick()\n\t{\n\t\treturn static_cast<uint32>(coreinit_GetMFTB());\n\t}\n\n\tuint32 OSGetTick()\n\t{\n\t\tuint64 osTime = OSGetTime();\n\t\treturn static_cast<uint32>(osTime);\n\t}\n\n\tuint32 getLeapDaysUntilYear(uint32 year)\n\t{\n\t\tif (year == 0)\n\t\t\treturn 0;\n\t\treturn (year + 3) / 4 - (year - 1) / 100 + (year - 1) / 400;\n\t}\n\n\tbool IsLeapYear(uint32 year)\n\t{\n\t\tif (((year & 3) == 0) && (year % 100) != 0)\n\t\t\treturn true;\n\t\tif ((year % 400) == 0)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\tuint32 dayToMonth[12] =\n\t{\n\t\t0,31,59,90,120,151,181,212,243,273,304,334\n\t};\n\n\tuint32 dayToMonthLeapYear[12] =\n\t{\n\t\t0,31,60,91,121,152,182,213,244,274,305,335\n\t};\n\n\tuint32 getDayInYearByYearAndMonth(uint32 year, uint32 month)\n\t{\n\t\t// Project Zero Maiden of Black Water (JPN) gives us an invalid calendar object\n\t\tmonth %= 12; // or return 0 if too big?\n\t\t\n\t\tif (IsLeapYear(year))\n\t\t\treturn dayToMonthLeapYear[month];\n\t\t\n\t\treturn dayToMonth[month];\n\t}\n\n\n\tinline const uint64 DAY_BIAS_2000 = 0xB2575;\n\n\tuint64 OSCalendarTimeToTicks(OSCalendarTime_t *calendar)\n\t{\n\t\tuint32 year = calendar->year;\n\n\t\tuint32 leapDays = getLeapDaysUntilYear(year);\n\t\tuint32 startDayOfCurrentMonth = getDayInYearByYearAndMonth(year, calendar->month);\n\n\t\tuint64 dayInYear = (startDayOfCurrentMonth + calendar->dayOfMonth) - 1;\n\t\t\n\t\tuint64 dayCount = dayInYear + year * 365 + leapDays - DAY_BIAS_2000;\n\n\t\t// convert date to seconds\n\t\tuint64 tSeconds = 0;\n\t\ttSeconds += (uint64)dayCount * 24 * 60 * 60;\n\t\ttSeconds += (uint64)calendar->hour * 60 * 60;\n\t\ttSeconds += (uint64)calendar->minute * 60;\n\t\ttSeconds += (uint64)calendar->second;\n\n\t\tuint64 tSubSecondTicks = 0;\n\t\ttSubSecondTicks += (uint64)calendar->millisecond * ESPRESSO_TIMER_CLOCK / 1000;\n\t\ttSubSecondTicks += (uint64)calendar->microsecond * ESPRESSO_TIMER_CLOCK / 1000000;\n\n\t\treturn tSeconds * ESPRESSO_TIMER_CLOCK + tSubSecondTicks;\n\t}\n\n\tvoid OSTicksToCalendarTime(uint64 ticks, OSCalendarTime_t* calenderStruct)\n\t{\n\t\tuint64 tSubSecondTicks = ticks % ESPRESSO_TIMER_CLOCK;\n\t\tuint64 tSeconds = ticks / ESPRESSO_TIMER_CLOCK;\n\n\t\tuint64 microsecond = tSubSecondTicks * 1000000ull / ESPRESSO_TIMER_CLOCK;\n\t\tmicrosecond %= 1000ull;\n\t\tcalenderStruct->microsecond = (uint32)microsecond;\n\n\t\tuint64 millisecond = tSubSecondTicks * 1000ull / ESPRESSO_TIMER_CLOCK;\n\t\tmillisecond %= 1000ull;\n\t\tcalenderStruct->millisecond = (uint32)millisecond;\n\n\t\tuint64 dayOfWeek = (tSeconds/(24ull * 60 * 60) + 6ull) % 7ull;\n\t\tuint64 secondOfDay = (tSeconds % (24ull * 60 * 60));\n\n\t\tcalenderStruct->dayOfWeek = (sint32)dayOfWeek;\n\n\t\tuint64 daysSince0AD = tSeconds / (24ull * 60 * 60) + DAY_BIAS_2000;\n\t\tuint32 year = (uint32)(daysSince0AD / 365ull);\n\t\tuint64 yearStartDay = year * 365 + getLeapDaysUntilYear(year);\n\t\twhile (yearStartDay > daysSince0AD)\n\t\t{\n\t\t\tyear--;\n\t\t\tif (IsLeapYear(year))\n\t\t\t\tyearStartDay -= 366;\n\t\t\telse\n\t\t\t\tyearStartDay -= 365;\n\t\t}\n\n\t\tcalenderStruct->year = year;\n\n\t\t// calculate time of day\n\t\tuint32 tempSecond = (uint32)secondOfDay;\n\t\tcalenderStruct->second = tempSecond % 60;\n\t\ttempSecond /= 60;\n\t\tcalenderStruct->minute = tempSecond % 60;\n\t\ttempSecond /= 60;\n\t\tcalenderStruct->hour = tempSecond % 24;\n\t\ttempSecond /= 24;\n\n\t\t// calculate month and day\n\t\tuint32 dayInYear = (uint32)(daysSince0AD - yearStartDay);\n\t\tbool isLeapYear = IsLeapYear(year);\n\n\t\tuint32 month = 0; // 0-11\n\t\tuint32 dayInMonth = 0;\n\n\t\tif (isLeapYear && dayInYear < (31+29))\n\t\t{\n\t\t\tif (dayInYear < 31)\n\t\t\t{\n\t\t\t\t// January\n\t\t\t\tmonth = 0;\n\t\t\t\tdayInMonth = dayInYear;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// February\n\t\t\t\tmonth = 1;\n\t\t\t\tdayInMonth = dayInYear-31;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (isLeapYear)\n\t\t\t\tdayInYear--;\n\n\t\t\tdayInMonth = dayInYear;\n\t\t\tif (dayInYear >= 334)\n\t\t\t{\n\t\t\t\t// December\n\t\t\t\tmonth = 11;\n\t\t\t\tdayInMonth -= 334;\n\t\t\t}\n\t\t\telse if (dayInYear >= 304)\n\t\t\t{\n\t\t\t\t// November\n\t\t\t\tmonth = 10;\n\t\t\t\tdayInMonth -= 304;\n\t\t\t}\n\t\t\telse if (dayInYear >= 273)\n\t\t\t{\n\t\t\t\t// October\n\t\t\t\tmonth = 9;\n\t\t\t\tdayInMonth -= 273;\n\t\t\t}\n\t\t\telse if (dayInYear >= 243)\n\t\t\t{\n\t\t\t\t// September\n\t\t\t\tmonth = 8;\n\t\t\t\tdayInMonth -= 243;\n\t\t\t}\n\t\t\telse if (dayInYear >= 212)\n\t\t\t{\n\t\t\t\t// August\n\t\t\t\tmonth = 7;\n\t\t\t\tdayInMonth -= 212;\n\t\t\t}\n\t\t\telse if (dayInYear >= 181)\n\t\t\t{\n\t\t\t\t// July\n\t\t\t\tmonth = 6;\n\t\t\t\tdayInMonth -= 181;\n\t\t\t}\n\t\t\telse if (dayInYear >= 151)\n\t\t\t{\n\t\t\t\t// June\n\t\t\t\tmonth = 5;\n\t\t\t\tdayInMonth -= 151;\n\t\t\t}\n\t\t\telse if (dayInYear >= 120)\n\t\t\t{\n\t\t\t\t// May\n\t\t\t\tmonth = 4;\n\t\t\t\tdayInMonth -= 120;\n\t\t\t}\n\t\t\telse if (dayInYear >= 90)\n\t\t\t{\n\t\t\t\t// April\n\t\t\t\tmonth = 3;\n\t\t\t\tdayInMonth -= 90;\n\t\t\t}\n\t\t\telse if (dayInYear >= 59)\n\t\t\t{\n\t\t\t\t// March\n\t\t\t\tmonth = 2;\n\t\t\t\tdayInMonth -= 59;\n\t\t\t}\n\t\t\telse if (dayInYear >= 31)\n\t\t\t{\n\t\t\t\t// February\n\t\t\t\tmonth = 1;\n\t\t\t\tdayInMonth -= 31;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// January\n\t\t\t\tmonth = 0;\n\t\t\t\tdayInMonth -= 0;\n\t\t\t}\n\t\t}\n\n\t\tcalenderStruct->dayOfYear = dayInYear;\n\t\tcalenderStruct->month = month;\n\t\tcalenderStruct->dayOfMonth = dayInMonth + 1;\n\t}\n\n\tuint32 getDaysInMonth(uint32 year, uint32 month)\n\t{\n\t\tswitch (month)\n\t\t{\n\t\tcase 0: // January\n\t\t\treturn 31;\n\t\tcase 1: // February\n\t\t\treturn IsLeapYear(year) ? 29 : 28;\n\t\tcase 2: // March\n\t\t\treturn 31;\n\t\tcase 3: // April\n\t\t\treturn 30;\n\t\tcase 4: // May\n\t\t\treturn 31;\n\t\tcase 5: // June\n\t\t\treturn 30;\n\t\tcase 6: // July\n\t\t\treturn 31;\n\t\tcase 7: // August\n\t\t\treturn 31;\n\t\tcase 8: // September\n\t\t\treturn 30;\n\t\tcase 9: // October\n\t\t\treturn 31;\n\t\tcase 10: // November\n\t\t\treturn 30;\n\t\tcase 11: // December\n\t\t\treturn 31;\n\t\tdefault:\n\t\t\tcemu_assert(false);\n\t\t}\n\t\treturn 31;\n\t}\n\n\tvoid verifyDateMatch(OSCalendarTime_t* ct1, OSCalendarTime_t* ct2)\n\t{\n\t\tsint64 m1 = ct1->millisecond * 1000 + ct1->microsecond;\n\t\tsint64 m2 = ct2->millisecond * 1000 + ct2->microsecond;\n\t\tsint64 microDif = std::abs(m1 - m2);\n\n\t\tif (ct1->year != ct2->year ||\n\t\t\tct1->month != ct2->month ||\n\t\t\tct1->dayOfMonth != ct2->dayOfMonth ||\n\t\t\tct1->hour != ct2->hour ||\n\t\t\tct1->minute != ct2->minute ||\n\t\t\tct1->second != ct2->second ||\n\t\t\tmicroDif > 1ull)\n\t\t{\n\t\t\tdebug_printf(\"Mismatch\\n\");\n\t\t\tassert_dbg();\n\t\t}\n\t}\n\n\tvoid timeTest()\n\t{\n\t\tsint32 iterCount = 0;\n\n\t\tOSCalendarTime_t ct{};\n\t\tct.year = 2000;\n\t\tct.month = 1;\n\t\tct.dayOfMonth = 1;\n\t\tct.hour = 1;\n\t\tct.minute = 1;\n\t\tct.second = 1;\n\t\tct.millisecond = 123;\n\t\tct.microsecond = 321;\n\n\t\twhile (true)\n\t\t{\n\t\t\titerCount++;\n\n\n\t\t\tuint64 ticks = OSCalendarTimeToTicks(&ct);\n\n\t\t\t// make sure converting it back results in the same date\n\t\t\tOSCalendarTime_t ctTemp;\n\t\t\tOSTicksToCalendarTime(ticks, &ctTemp);\n\t\t\tverifyDateMatch(&ct, &ctTemp);\n\n\t\t\t// add a day\n\t\t\tticks += 24ull * 60 * 60 * ESPRESSO_TIMER_CLOCK;\n\n\t\t\tOSCalendarTime_t ctOutput;\n\t\t\tOSTicksToCalendarTime(ticks, &ctOutput);\n\n\t\t\tOSCalendarTime_t ctExpected;\n\t\t\tctExpected = ct;\n\t\t\t// add a day manually\n\t\t\tsint32 daysInMonth = getDaysInMonth(ctExpected.year, ctExpected.month);\n\t\t\tctExpected.dayOfMonth = ctExpected.dayOfMonth + 1;\n\t\t\tif (ctExpected.dayOfMonth >= daysInMonth+1)\n\t\t\t{\n\t\t\t\tctExpected.dayOfMonth = 1;\n\t\t\t\tctExpected.month = ctExpected.month + 1;\n\t\t\t\tif (ctExpected.month > 11)\n\t\t\t\t{\n\t\t\t\t\tctExpected.month = 0;\n\t\t\t\t\tctExpected.year = ctExpected.year + 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tverifyDateMatch(&ctExpected, &ctOutput);\n\n\t\t\tct = ctOutput;\n\t\t}\n\t}\n\n\tvoid InitializeTimeAndCalendar()\n\t{\n\t\tcafeExportRegister(\"coreinit\", OSGetTime, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSGetSystemTime, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSGetTick, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSGetSystemTick, LogType::Placeholder);\n\n\t\tcafeExportRegister(\"coreinit\", OSTicksToCalendarTime, LogType::Placeholder);\n\t\tcafeExportRegister(\"coreinit\", OSCalendarTimeToTicks, LogType::Placeholder);\n\n\t\t//timeTest();\n\t}\n};"
  },
  {
    "path": "src/Cafe/OS/libs/coreinit/coreinit_Time.h",
    "content": "#pragma once\n#include \"Cafe/HW/Espresso/Const.h\"\n\nnamespace coreinit\n{\n\ttypedef struct\n\t{\n\t\t/* +0x00 */ sint32be second;\t\t\t// 0-59\n\t\t/* +0x04 */ sint32be minute;\t\t\t// 0-59\n\t\t/* +0x08 */ sint32be hour;\t\t\t\t// 0-23\n\t\t/* +0x0C */ sint32be dayOfMonth;\t\t// 1-31\n\t\t/* +0x10 */ sint32be month;\t\t\t\t// 0-11\n\t\t/* +0x14 */ sint32be year;\t\t\t\t// 2000-...\n\t\t/* +0x18 */ sint32be dayOfWeek;\t\t\t// 0-6\n\t\t/* +0x1C */ sint32be dayOfYear;\t\t\t// 0-365\n\t\t/* +0x20 */ sint32be millisecond;\t\t// 0-999\n\t\t/* +0x24 */ sint32be microsecond;\t\t// 0-999\n\t}OSCalendarTime_t;\n\n\tstatic_assert(sizeof(OSCalendarTime_t) == 0x28);\n\n\tnamespace EspressoTime\n\t{\n\t\ttypedef sint64 TimerTicks;\n\n\t\tconstexpr sint64 GetCoreClock()\n\t\t{\n\t\t\treturn Espresso::CORE_CLOCK;\n\t\t}\n\n\t\tconstexpr sint64 GetBusClock()\n\t\t{\n\t\t\treturn Espresso::BUS_CLOCK;\n\t\t}\n\n\t\tconstexpr sint64 GetTimerClock()\n\t\t{\n\t\t\treturn Espresso::TIMER_CLOCK;\n\t\t}\n\n\t\tinline TimerTicks ConvertNsToTimerTicks(uint64 ns)\n\t\t{\n\t\t\treturn static_cast<TimerTicks>((static_cast<uint64>(GetTimerClock()) / 31250ULL) * (ns) / 32000ULL);\n\t\t}\n\n\t\tinline TimerTicks ConvertMsToTimerTicks(uint64 ms)\n\t\t{\n\t\t\treturn static_cast<TimerTicks>(ms * static_cast<uint64>(GetTimerClock()) / 1000ULL);\n\t\t}\n\t};\n\n\tvoid OSTicksToCalendarTime(uint64 ticks, OSCalendarTime_t* calenderStruct);\n\n\tuint64 OSGetSystemTime();\n\tuint64 OSGetTime();\n\tuint32 OSGetSystemTick();\n\tuint32 OSGetTick();\n\n\tvoid InitializeTimeAndCalendar();\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/dmae/dmae.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n\n#define DMAE_ENDIAN_NONE\t0\n#define DMAE_ENDIAN_16\t\t1\n#define DMAE_ENDIAN_32\t\t2\n#define DMAE_ENDIAN_64\t\t3\n\nuint64 dmaeRetiredTimestamp = 0;\n\nuint64 dmae_getTimestamp()\n{\n\treturn coreinit::OSGetSystemTime();\n}\n\nvoid dmae_setRetiredTimestamp(uint64 timestamp)\n{\n\tdmaeRetiredTimestamp = timestamp;\n}\n\nvoid dmaeExport_DMAECopyMem(PPCInterpreter_t* hCPU)\n{\n\tif( hCPU->gpr[6] == DMAE_ENDIAN_NONE )\n\t{\n\t\t// don't change endianness\n\t\tmemcpy(memory_getPointerFromVirtualOffset(hCPU->gpr[3]), memory_getPointerFromVirtualOffset(hCPU->gpr[4]), hCPU->gpr[5]*4);\n\t}\n\telse if( hCPU->gpr[6] == DMAE_ENDIAN_32 )\n\t{\n\t\t// swap per uint32\n\t\tuint32* srcBuffer = (uint32*)memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\t\tuint32* dstBuffer = (uint32*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\tfor(uint32 i=0; i<hCPU->gpr[5]; i++)\n\t\t{\n\t\t\tdstBuffer[i] = _swapEndianU32(srcBuffer[i]);\n\t\t}\n\t}\n\telse if( hCPU->gpr[6] == DMAE_ENDIAN_16 )\n\t{\n\t\t// swap per uint16\n\t\tuint16* srcBuffer = (uint16*)memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\t\tuint16* dstBuffer = (uint16*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\tfor(uint32 i=0; i<hCPU->gpr[5]*2; i++)\n\t\t{\n\t\t\tdstBuffer[i] = _swapEndianU16(srcBuffer[i]);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"DMAECopyMem(): Unsupported endian swap\\n\");\n\t}\n\tuint64 dmaeTimestamp = dmae_getTimestamp();\n\tdmae_setRetiredTimestamp(dmaeTimestamp);\n\tif(hCPU->gpr[5] > 0)\n\t\tLatteBufferCache_notifyDCFlush(hCPU->gpr[3], hCPU->gpr[5]*4);\n\tosLib_returnFromFunction64(hCPU, dmaeTimestamp);\n}\n\nvoid dmaeExport_DMAEFillMem(PPCInterpreter_t* hCPU)\n{\n\tuint32* dstBuffer = (uint32*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\tuint32 value = hCPU->gpr[4];\n\tuint32 numU32s = hCPU->gpr[5];\t\n\tvalue = _swapEndianU32(value);\n\tfor(uint32 i=0; i<numU32s; i++)\n\t{\n\t\t*dstBuffer = value;\n\t\tdstBuffer++;\n\t}\n\tuint64 dmaeTimestamp = dmae_getTimestamp();\n\tdmae_setRetiredTimestamp(dmaeTimestamp);\n\tosLib_returnFromFunction64(hCPU, dmaeTimestamp);\n}\n\nvoid dmaeExport_DMAEWaitDone(PPCInterpreter_t* hCPU)\n{\n\t//debug_printf(\"DMAEWaitDone(...)\\n\");\n\t// parameter:\n\t// r3/r4\tuint64  \t\tdmaeTimestamp\n\tosLib_returnFromFunction(hCPU, 1);\n}\n\nvoid dmaeExport_DMAESemaphore(PPCInterpreter_t* hCPU)\n{\n\t// parameter:\n\t// r3\tMPTR\taddr\n\t// r4\tuint32\tactionType\n\n\tuint32 actionType = hCPU->gpr[4];\n\n\tstd::atomic<uint64le>* semaphore = _rawPtrToAtomic((uint64le*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]));\n\n\tif( actionType == 1 )\n\t{\n\t\t// Signal Semaphore\n\t\tsemaphore->fetch_add(1);\n\t}\n\telse if (actionType == 0) // wait\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"DMAESemaphore: Unsupported wait operation\");\n\t\tsemaphore->fetch_sub(1);\n\t}\n\telse\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"DMAESemaphore unknown action type {}\", actionType);\n\t\tcemu_assert_debug(false);\n\t}\n\n\tuint64 dmaeTimestamp = dmae_getTimestamp();\n\tdmae_setRetiredTimestamp(dmaeTimestamp);\n\tosLib_returnFromFunction64(hCPU, dmaeTimestamp);\n}\n\nvoid dmaeExport_DMAEGetRetiredTimeStamp(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"DMAEGetRetiredTimeStamp()\\n\");\n\tosLib_returnFromFunction64(hCPU, dmaeRetiredTimestamp);\n}\n\nnamespace dmae\n{\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"dmae\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"dmae\", \"DMAECopyMem\", dmaeExport_DMAECopyMem);\n\t\t\tosLib_addFunction(\"dmae\", \"DMAEFillMem\", dmaeExport_DMAEFillMem);\n\t\t\tosLib_addFunction(\"dmae\", \"DMAEWaitDone\", dmaeExport_DMAEWaitDone);\n\t\t\tosLib_addFunction(\"dmae\", \"DMAESemaphore\", dmaeExport_DMAESemaphore);\n\t\t\tosLib_addFunction(\"dmae\", \"DMAEGetRetiredTimeStamp\", dmaeExport_DMAEGetRetiredTimeStamp);\n\t\t}\n\t}s_COSDMAEModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSDMAEModule;\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/dmae/dmae.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace dmae\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/drmapp/drmapp.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"drmapp.h\"\n\nnamespace drmapp\n{\n\tuint32 NupChkIsFinished(uint32 ukn)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"drmapp.NupChkIsFinished() - placeholder\");\n\t\treturn 1;\n\t}\n\n\tuint32 PatchChkIsFinished()\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"drmapp.PatchChkIsFinished() - placeholder\");\n\t\treturn 1;\n\t}\n\n\tuint32 AocChkIsFinished()\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"drmapp.AocChkIsFinished() - placeholder\");\n\t\treturn 1;\n\t}\n\n\tuint32 TicketChkIsFinished()\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"drmapp.TicketChkIsFinished__3RplFv() - placeholder\");\n\t\treturn 1;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"drmapp\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegisterFunc(NupChkIsFinished, \"drmapp\", \"NupChkIsFinished__3RplFv\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(PatchChkIsFinished, \"drmapp\", \"PatchChkIsFinished__3RplFv\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(AocChkIsFinished, \"drmapp\", \"AocChkIsFinished__3RplFv\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(TicketChkIsFinished, \"drmapp\", \"TicketChkIsFinished__3RplFv\", LogType::Placeholder);\n\t\t}\n\t}s_COSdrmappModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSdrmappModule;\n\t}\n\n} // namespace drmapp\n"
  },
  {
    "path": "src/Cafe/OS/libs/drmapp/drmapp.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace drmapp\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/erreula/erreula.cpp",
    "content": "﻿#include \"Cafe/OS/common/OSCommon.h\"\n#include \"erreula.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"util/helpers/helpers.h\"\n\n#include <imgui.h>\n#include \"imgui/imgui_extension.h\"\n\n#include \"Cafe/OS/libs/coreinit/coreinit_FS.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/vpad/vpad.h\"\n#include \"OS/libs/coreinit/coreinit_DynLoad.h\"\n\nnamespace nn\n{\nnamespace erreula\n{\n\n\tenum class ErrorDialogType : uint32\n\t{\n\t\tCode = 0,\n\t\tText = 1,\n\t\tTextOneButton = 2,\n\t\tTextTwoButton = 3\n\t};\n\n\tstatic const sint32 FADE_TIME = 80;\n\n\tenum class ErrEulaState : uint32\n\t{\n\t\tHidden = 0,\n\t\tAppearing = 1,\n\t\tVisible = 2,\n\t\tDisappearing = 3\n\t};\n\n\tenum class ResultType : uint32\n\t{\n\t\tNone = 0,\n\t\tFinish = 1,\n\t\tNext = 2,\n\t\tJump = 3,\n\t\tPassword = 4\n\t};\n\n\tstruct AppearError\n\t{\n\t\tAppearError() = default;\n\t\tAppearError(const AppearError& o)\n\t\t{\n\t\t\terrorType = o.errorType;\n\t\t\tscreenType = o.screenType;\n\t\t\tcontrollerType = o.controllerType;\n\t\t\tholdType = o.holdType;\n\t\t\terrorCode = o.errorCode;\n\t\t\tframerate = o.framerate;\n\t\t\ttext = o.text;\n\t\t\tbutton1Text = o.button1Text;\n\t\t\tbutton2Text = o.button2Text;\n\t\t\ttitle = o.title;\n\t\t\tdrawCursor = o.drawCursor;\n\t\t}\n\n\t\tbetype<ErrorDialogType> errorType;\n\t\tuint32be screenType;\n\t\tuint32be controllerType;\n\t\tuint32be holdType;\n\t\tuint32be errorCode;\n\t\tuint32be framerate;\n\t\tMEMPTR<uint16be> text;\n\t\tMEMPTR<uint16be> button1Text;\n\t\tMEMPTR<uint16be> button2Text;\n\t\tMEMPTR<uint16be> title;\n\t\tuint8 padding[3];\n\t\tbool drawCursor{};\n\t};\n\n\tusing AppearArg = AppearError;\n\n\tstatic_assert(sizeof(AppearError) == 0x2C); // maybe larger\n\n\tstruct HomeNixSignArg_t\n\t{\n\t\tuint32be framerate;\n\t};\n\n\tstatic_assert(sizeof(HomeNixSignArg_t) == 0x4); // maybe larger\n\n\tstruct ControllerInfo_t\n\t{\n\t\tMEMPTR<VPADStatus_t> vpadStatus;\n\t\tMEMPTR<KPADStatus_t> kpadStatus[4]; // or 7 now like KPAD_MAX_CONTROLLERS?\n\t};\n\n\tstatic_assert(sizeof(ControllerInfo_t) == 0x14); // maybe larger\n\n\tclass ErrEulaInstance\n\t{\n\t  public:\n\t\tenum class BUTTON_SELECTION : uint32\n\t\t{\n\t\t\tNONE = 0xFFFFFFFF,\n\t\t\tLEFT = 0,\n\t\t\tRIGHT = 1,\n\t\t};\n\n\t\tvoid Init()\n\t\t{\n\t\t\tm_buttonSelection = BUTTON_SELECTION::NONE;\n\t\t\tm_resultCode = -1;\n\t\t\tm_resultCodeForLeftButton = 0;\n\t\t\tm_resultCodeForRightButton = 0;\n\t\t\tSetState(ErrEulaState::Hidden);\n\t\t}\n\n\t\tvoid DoAppearError(AppearArg* arg)\n\t\t{\n\t\t\tm_buttonSelection = BUTTON_SELECTION::NONE;\n\t\t\tm_resultCode = -1;\n\t\t\tm_resultCodeForLeftButton = -1;\n\t\t\tm_resultCodeForRightButton = -1;\n\t\t\t// for standard dialog its 0 and 1?\n\t\t\tm_resultCodeForLeftButton = 0;\n\t\t\tm_resultCodeForRightButton = 1;\n\t\t\tSetState(ErrEulaState::Appearing);\n\t\t}\n\n\t\tvoid DoDisappearError()\n\t\t{\n\t\t\tif(m_state != ErrEulaState::Visible)\n\t\t\t\treturn;\n\t\t\tSetState(ErrEulaState::Disappearing);\n\t\t}\n\n\t\tvoid DoCalc()\n\t\t{\n\t\t\t// appearing and disappearing state will automatically advance after some time\n\t\t\tif (m_state == ErrEulaState::Appearing || m_state == ErrEulaState::Disappearing)\n\t\t\t{\n\t\t\t\tuint32 elapsedTick = coreinit::OSGetTime() - m_lastStateChange;\n\t\t\t\tif (elapsedTick > coreinit::EspressoTime::ConvertMsToTimerTicks(FADE_TIME))\n\t\t\t\t{\n\t\t\t\t\tSetState(m_state == ErrEulaState::Appearing ? ErrEulaState::Visible : ErrEulaState::Hidden);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbool IsDecideSelectButtonError() const\n\t\t{\n\t\t\treturn m_buttonSelection != BUTTON_SELECTION::NONE;\n\t\t}\n\n\t\tbool IsDecideSelectLeftButtonError() const\n\t\t{\n\t\t\treturn m_buttonSelection != BUTTON_SELECTION::LEFT;\n\t\t}\n\n\t\tbool IsDecideSelectRightButtonError() const\n\t\t{\n\t\t\treturn m_buttonSelection != BUTTON_SELECTION::RIGHT;\n\t\t}\n\n\t\tvoid SetButtonSelection(BUTTON_SELECTION selection)\n\t\t{\n\t\t\tcemu_assert_debug(m_buttonSelection == BUTTON_SELECTION::NONE);\n\t\t\tm_buttonSelection = selection;\n\t\t\tcemu_assert_debug(selection == BUTTON_SELECTION::LEFT || selection == BUTTON_SELECTION::RIGHT);\n\t\t\tm_resultCode = selection == BUTTON_SELECTION::LEFT ? m_resultCodeForLeftButton : m_resultCodeForRightButton;\n\t\t}\n\n\t\tErrEulaState GetState() const\n\t\t{\n\t\t\treturn m_state;\n\t\t}\n\n\t\tsint32 GetResultCode() const\n\t\t{\n\t\t\treturn m_resultCode;\n\t\t}\n\n\t\tResultType GetResultType() const\n\t\t{\n\t\t  if(m_resultCode == -1)\n\t\t\t  return ResultType::None;\n\t\t  if(m_resultCode < 10)\n\t\t\t  return ResultType::Finish;\n\t\t  if(m_resultCode >= 9999)\n\t\t\t  return ResultType::Next;\n\t\t  if(m_resultCode == 40)\n\t\t\t  return ResultType::Password;\n\t\t  return ResultType::Jump;\n\t\t}\n\n\t\tfloat GetFadeTransparency() const\n\t\t{\n\t\t\tif(m_state == ErrEulaState::Appearing || m_state == ErrEulaState::Disappearing)\n\t\t\t{\n\t\t\t\tuint32 elapsedTick = coreinit::OSGetTime() - m_lastStateChange;\n\t\t\t\tif(m_state == ErrEulaState::Appearing)\n\t\t\t\t\treturn std::min<float>(1.0f, (float)elapsedTick / (float)coreinit::EspressoTime::ConvertMsToTimerTicks(FADE_TIME));\n\t\t\t\telse\n\t\t\t\t\treturn std::max<float>(0.0f, 1.0f - (float)elapsedTick / (float)coreinit::EspressoTime::ConvertMsToTimerTicks(FADE_TIME));\n\t\t\t}\n\t\t\treturn 1.0f;\n\t\t}\n\n\t  private:\n\t\tvoid SetState(ErrEulaState state)\n\t\t{\n\t\t\tm_state = state;\n\t\t\tm_lastStateChange = coreinit::OSGetTime();\n\t\t}\n\n\t\tErrEulaState m_state;\n\t\tuint32 m_lastStateChange;\n\n\t\t/* +0x30 */ betype<sint32> m_resultCode;\n\t\t/* +0x239C */ betype<BUTTON_SELECTION> m_buttonSelection;\n\t\t/* +0x23A0 */ betype<sint32> m_resultCodeForLeftButton;\n\t\t/* +0x23A4 */ betype<sint32> m_resultCodeForRightButton;\n\t};\n\n\tstruct ErrEula_t\n\t{\n\t\tSysAllocator<coreinit::OSMutex> mutex;\n\t\tuint32 regionType{0};\n\t\tuint32 langType{0};\n\t\tMEMPTR<coreinit::FSClient_t> fsClient;\n\t\tstd::unique_ptr<ErrEulaInstance> errEulaInstance;\n\t\tAppearError currentDialog;\n\t\tbool homeNixSignVisible{false};\n\t} g_errEula = {};\n\t\n\tstd::wstring GetText(uint16be* text)\n\t{\n\t\tstd::wstringstream result;\n\t\twhile(*text != 0)\n\t\t{\n\t\t\tauto c = (uint16)*text;\n\t\t\tresult << static_cast<wchar_t>(c);\n\t\t\ttext++;\n\t\t}\n\n\t\treturn result.str();\n\t}\n\t\n\n\tvoid ErrEulaCreate(void* workmem, uint32 regionType, uint32 langType, coreinit::FSClient_t* fsClient)\n\t{\n\t\tcoreinit::OSLockMutex(&g_errEula.mutex);\n\n\t\tg_errEula.regionType = regionType;\n\t\tg_errEula.langType = langType;\n\t\tg_errEula.fsClient = fsClient;\n\t\tcemu_assert_debug(!g_errEula.errEulaInstance);\n\t\tg_errEula.errEulaInstance = std::make_unique<ErrEulaInstance>();\n\t\tg_errEula.errEulaInstance->Init();\n\n\t\tcoreinit::OSUnlockMutex(&g_errEula.mutex);\n\t}\n\n\tvoid ErrEulaDestroy()\n\t{\n\t\tg_errEula.errEulaInstance.reset();\n\t}\n\n\t// check if any dialog button was selected\n\tbool IsDecideSelectButtonError()\n\t{\n\t\tif(!g_errEula.errEulaInstance)\n\t\t\treturn false;\n\t\treturn g_errEula.errEulaInstance->IsDecideSelectButtonError();\n\t}\n\n\t// check if left dialog button was selected\n\tbool IsDecideSelectLeftButtonError()\n\t{\n\t\tif(!g_errEula.errEulaInstance)\n\t\t\treturn false;\n\t\treturn g_errEula.errEulaInstance->IsDecideSelectLeftButtonError();\n\t}\n\n\t// check if right dialog button was selected\n\tbool IsDecideSelectRightButtonError()\n\t{\n\t\tif(!g_errEula.errEulaInstance)\n\t\t\treturn false;\n\t\treturn g_errEula.errEulaInstance->IsDecideSelectRightButtonError();\n\t}\n\n\tsint32 GetResultCode()\n\t{\n\t\tif(!g_errEula.errEulaInstance)\n\t\t\treturn -1;\n\t\treturn g_errEula.errEulaInstance->GetResultCode();\n\t}\n\n\tResultType GetResultType()\n\t{\n\t\tif(!g_errEula.errEulaInstance)\n\t\t\treturn ResultType::None;\n\t\treturn g_errEula.errEulaInstance->GetResultType();\n\t}\n\n\tvoid export_AppearHomeNixSign(PPCInterpreter_t* hCPU)\n\t{\n\t\tg_errEula.homeNixSignVisible = TRUE;\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid ErrEulaAppearError(AppearArg* arg)\n\t{\n\t\tg_errEula.currentDialog = *arg;\n\t\tif(g_errEula.errEulaInstance)\n\t\t\tg_errEula.errEulaInstance->DoAppearError(arg);\n\t}\n\n\tvoid ErrEulaDisappearError()\n\t{\n\t\tif(g_errEula.errEulaInstance)\n\t\t\tg_errEula.errEulaInstance->DoDisappearError();\n\t}\n\n\tErrEulaState ErrEulaGetStateErrorViewer()\n\t{\n\t\tif(!g_errEula.errEulaInstance)\n\t\t\treturn ErrEulaState::Hidden;\n\t\treturn g_errEula.errEulaInstance->GetState();\n\t}\n\n\tvoid export_ChangeLang(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(langType, 0);\n\t\tg_errEula.langType = langType;\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_IsAppearHomeNixSign(PPCInterpreter_t* hCPU)\n\t{\n\t\tosLib_returnFromFunction(hCPU, g_errEula.homeNixSignVisible);\n\t}\n\n\tvoid export_DisappearHomeNixSign(PPCInterpreter_t* hCPU)\n\t{\n\t\tg_errEula.homeNixSignVisible = FALSE;\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid ErrEulaCalc(ControllerInfo_t* controllerInfo)\n\t{\n\t\tif(g_errEula.errEulaInstance)\n\t\t\tg_errEula.errEulaInstance->DoCalc();\n\t}\n\n\tvoid render(bool mainWindow)\n\t{\n\t\tif(!g_errEula.errEulaInstance)\n\t\t\treturn;\n\t\tif(g_errEula.errEulaInstance->GetState() != ErrEulaState::Visible && g_errEula.errEulaInstance->GetState() != ErrEulaState::Appearing && g_errEula.errEulaInstance->GetState() != ErrEulaState::Disappearing)\n\t\t\treturn;\n\t\tconst AppearError& appearArg = g_errEula.currentDialog;\n\t\tstd::string text;\n\t\tconst uint32 errorCode = (uint32)appearArg.errorCode;\n\t\tif (errorCode != 0)\n\t\t{\n\t\t\tconst uint32 errorCodeHigh = errorCode / 10000;\n\t\t\tconst uint32 errorCodeLow = errorCode % 10000;\n\t\t\ttext = fmt::format(\"Error-Code: {:03}-{:04}\\n\", errorCodeHigh, errorCodeLow);\n\t\t}\n\n\t\tauto font = ImGui_GetFont(32.0f);\n\t\tif (!font)\n\t\t\treturn;\n\n\t\tconst auto kPopupFlags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings;\n\n\t\tauto& io = ImGui::GetIO();\n\t\tImVec2 position = { io.DisplaySize.x / 2.0f, io.DisplaySize.y / 2.0f };\n\t\tImVec2 pivot = { 0.5f, 0.5f };\n\t\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t\tImGui::SetNextWindowBgAlpha(0.9f);\n\t\tImGui::PushFont(font);\n\n\t\tstd::string title;\n\t\tif (appearArg.title)\n\t\t\ttitle = boost::nowide::narrow(GetText(appearArg.title.GetPtr()));\n\t\tif (title.empty()) // ImGui doesn't allow empty titles, so set one if appearArg.title is not set or empty\n\t\t\ttitle = \"ErrEula\";\n\n\t\tfloat fadeTransparency = 1.0f;\n\t\tif (g_errEula.errEulaInstance->GetState() == ErrEulaState::Appearing || g_errEula.errEulaInstance->GetState() == ErrEulaState::Disappearing)\n\t\t{\n\t\t\tfadeTransparency = g_errEula.errEulaInstance->GetFadeTransparency();\n\t\t}\n\n\t\tfloat originalAlpha = ImGui::GetStyle().Alpha;\n\t\tImGui::GetStyle().Alpha = fadeTransparency;\n\t\tImGui::SetNextWindowBgAlpha(0.9f * fadeTransparency);\n\t\tif (ImGui::Begin(title.c_str(), nullptr, kPopupFlags))\n\t\t{\n\t\t\tconst float startx = ImGui::GetWindowSize().x / 2.0f;\n\t\t\tbool hasLeftButtonPressed = false, hasRightButtonPressed = false;\n\n\t\t\tswitch (appearArg.errorType)\n\t\t\t{\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\t// TODO layout based on error code\n\t\t\t\tImGui::TextUnformatted(text.c_str(), text.c_str() + text.size());\n\t\t\t\tImGui::Spacing();\n\t\t\t\tImGui::SetCursorPosX(startx - 50);\n\t\t\t\thasLeftButtonPressed = ImGui::Button(\"OK\", {100, 0});\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ErrorDialogType::Text:\n\t\t\t{\n\t\t\t\tstd::string txtTmp = \"Unknown Error\";\n\t\t\t\tif (appearArg.text)\n\t\t\t\t\ttxtTmp = boost::nowide::narrow(GetText(appearArg.text.GetPtr()));\n\n\t\t\t\ttext += txtTmp;\n\t\t\t\tImGui::TextUnformatted(text.c_str(), text.c_str() + text.size());\n\t\t\t\tImGui::Spacing();\n\t\t\t\t\t\n\t\t\t\tImGui::SetCursorPosX(startx - 50);\n\t\t\t\thasLeftButtonPressed = ImGui::Button(\"OK\", { 100, 0 });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ErrorDialogType::TextOneButton:\n\t\t\t{\n\t\t\t\tstd::string txtTmp = \"Unknown Error\";\n\t\t\t\tif (appearArg.text)\n\t\t\t\t\ttxtTmp = boost::nowide::narrow(GetText(appearArg.text.GetPtr()));\n\n\t\t\t\ttext += txtTmp;\n\t\t\t\tImGui::TextUnformatted(text.c_str(), text.c_str() + text.size());\n\t\t\t\tImGui::Spacing();\n\n\t\t\t\tstd::string button1 = \"Yes\";\n\t\t\t\tif (appearArg.button1Text)\n\t\t\t\t\tbutton1 = boost::nowide::narrow(GetText(appearArg.button1Text.GetPtr()));\n\n\t\t\t\tfloat width = std::max(100.0f, ImGui::CalcTextSize(button1.c_str()).x + 10.0f);\n\t\t\t\tImGui::SetCursorPosX(startx - (width / 2.0f));\n\t\t\t\thasLeftButtonPressed = ImGui::Button(button1.c_str(), { width, 0 });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ErrorDialogType::TextTwoButton:\n\t\t\t{\n\t\t\t\tstd::string txtTmp = \"Unknown Error\";\n\t\t\t\tif (appearArg.text)\n\t\t\t\t\ttxtTmp = boost::nowide::narrow(GetText(appearArg.text.GetPtr()));\n\n\t\t\t\ttext += txtTmp;\n\t\t\t\tImGui::TextUnformatted(text.c_str(), text.c_str() + text.size());\n\t\t\t\tImGui::Spacing();\n\n\t\t\t\tstd::string button1 = \"Yes\";\n\t\t\t\tif (appearArg.button1Text)\n\t\t\t\t\tbutton1 = boost::nowide::narrow(GetText(appearArg.button1Text.GetPtr()));\n\t\t\t\tstd::string button2 = \"No\";\n\t\t\t\tif (appearArg.button2Text)\n\t\t\t\t\tbutton2 = boost::nowide::narrow(GetText(appearArg.button2Text.GetPtr()));\n\n\t\t\t\tfloat width1 = std::max(100.0f, ImGui::CalcTextSize(button1.c_str()).x + 10.0f);\n\t\t\t\tfloat width2 = std::max(100.0f, ImGui::CalcTextSize(button2.c_str()).x + 10.0f);\n\t\t\t\tImGui::SetCursorPosX(startx - (width1 / 2.0f) - (width2 / 2.0f) - 10);\n\t\t\t\t\t\n\t\t\t\thasLeftButtonPressed = ImGui::Button(button1.c_str(), { width1, 0 });\n\t\t\t\tImGui::SameLine();\n\t\t\t\t\t\n\t\t\t\thasRightButtonPressed = ImGui::Button(button2.c_str(), { width2, 0 });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t}\n\t\t\tif (!g_errEula.errEulaInstance->IsDecideSelectButtonError())\n\t\t\t{\n\t\t\t\tif (hasLeftButtonPressed)\n\t\t\t\t\tg_errEula.errEulaInstance->SetButtonSelection(ErrEulaInstance::BUTTON_SELECTION::LEFT);\n\t\t\t\tif (hasRightButtonPressed)\n\t\t\t\t\tg_errEula.errEulaInstance->SetButtonSelection(ErrEulaInstance::BUTTON_SELECTION::RIGHT);\n\t\t\t}\n\t\t}\n\t\tImGui::End();\n\t\tImGui::PopFont();\n\t\tImGui::GetStyle().Alpha = originalAlpha;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"erreula\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegisterFunc(ErrEulaCreate, \"erreula\", \"ErrEulaCreate__3RplFPUcQ3_2nn7erreula10RegionTypeQ3_2nn7erreula8LangTypeP8FSClient\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(ErrEulaDestroy, \"erreula\", \"ErrEulaDestroy__3RplFv\", LogType::Placeholder);\n\n\t\t\tcafeExportRegisterFunc(IsDecideSelectButtonError, \"erreula\", \"ErrEulaIsDecideSelectButtonError__3RplFv\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(IsDecideSelectLeftButtonError, \"erreula\", \"ErrEulaIsDecideSelectLeftButtonError__3RplFv\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(IsDecideSelectRightButtonError, \"erreula\", \"ErrEulaIsDecideSelectRightButtonError__3RplFv\", LogType::Placeholder);\n\n\t\t\tcafeExportRegisterFunc(GetResultCode, \"erreula\", \"ErrEulaGetResultCode__3RplFv\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(GetResultType, \"erreula\", \"ErrEulaGetResultType__3RplFv\", LogType::Placeholder);\n\n\t\t\tcafeExportRegisterFunc(ErrEulaAppearError, \"erreula\", \"ErrEulaAppearError__3RplFRCQ3_2nn7erreula9AppearArg\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(ErrEulaDisappearError, \"erreula\", \"ErrEulaDisappearError__3RplFv\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(ErrEulaGetStateErrorViewer, \"erreula\", \"ErrEulaGetStateErrorViewer__3RplFv\", LogType::Placeholder);\n\n\t\t\tcafeExportRegisterFunc(ErrEulaCalc, \"erreula\", \"ErrEulaCalc__3RplFRCQ3_2nn7erreula14ControllerInfo\", LogType::Placeholder);\n\n\t\t\tosLib_addFunction(\"erreula\", \"ErrEulaAppearHomeNixSign__3RplFRCQ3_2nn7erreula14HomeNixSignArg\", export_AppearHomeNixSign);\n\t\t\tosLib_addFunction(\"erreula\", \"ErrEulaChangeLang__3RplFQ3_2nn7erreula8LangType\", export_ChangeLang);\n\t\t\tosLib_addFunction(\"erreula\", \"ErrEulaIsAppearHomeNixSign__3RplFv\", export_IsAppearHomeNixSign);\n\t\t\tosLib_addFunction(\"erreula\", \"ErrEulaDisappearHomeNixSign__3RplFv\", export_DisappearHomeNixSign);\n\t\t}\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\tg_errEula.errEulaInstance.reset();\n\t\t\t\tOSInitMutexEx(&g_errEula.mutex, nullptr);\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t\tg_errEula.errEulaInstance.reset();\n\t\t\t\t// todo - refactor and clean up these variables to be part of errEulaInstance\n\t\t\t\tg_errEula.regionType = 0;\n\t\t\t\tg_errEula.langType = 0;\n\t\t\t\tg_errEula.fsClient = nullptr;\n\t\t\t\tg_errEula.currentDialog = {};\n\t\t\t\tg_errEula.homeNixSignVisible = {};\n\t\t\t\tg_errEula.currentDialog = {};\n\t\t\t}\n\t\t}\n\t}s_COSErreulaModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSErreulaModule;\n\t}\n}\n}\n \n"
  },
  {
    "path": "src/Cafe/OS/libs/erreula/erreula.h",
    "content": "﻿#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn \n{\n\tnamespace erreula\n\t{\n\t\tvoid render(bool mainWindow);\n\n\t\tCOSModule* GetModule();\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"GX2.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n\n#include \"GX2_Command.h\"\n#include \"GX2_State.h\"\n#include \"GX2_Memory.h\"\n#include \"GX2_Event.h\"\n#include \"GX2_Shader.h\"\n#include \"GX2_Blit.h\"\n#include \"GX2_Draw.h\"\n#include \"GX2_Query.h\"\n#include \"GX2_Misc.h\"\n#include \"GX2_Surface.h\"\n#include \"GX2_Surface_Copy.h\"\n#include \"GX2_Texture.h\"\n\n#include <cinttypes>\n\n#define GX2_TV_RENDER_NONE\t\t\t0\n#define GX2_TV_RENDER_480\t\t\t1\n#define GX2_TV_RENDER_480_WIDE\t\t2\n#define GX2_TV_RENDER_720\t\t\t3\n#define GX2_TV_RENDER_720I\t\t\t4\n#define GX2_TV_RENDER_1080\t\t\t5\n#define GX2_TV_RENDER_COUNT\t\t\t6\n\nstruct\n{\n\tsint32 width;\n\tsint32 height;\n}tvScanBufferResolutions[GX2_TV_RENDER_COUNT] = {\n0,0,\n640,480,\n854,480,\n1280,720,\n1280,720,\n1920,1080\n};\n\nuint64 lastSwapTime = 0;\n\nvoid gx2Export_GX2SwapScanBuffers(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SwapScanBuffers()\");\n\n\tbool isPokken = false;\n\n\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\tif (titleId == 0x00050000101DF500ull || titleId == 0x00050000101C5800ull || titleId == 0x00050000101DF400ull)\n\t\tisPokken = true;\n\n\tif (isPokken)\n\t\tGX2::GX2DrawDone();\n\n\tGX2::GX2ReserveCmdSpace(5+2);\n\n\tuint64 tick64 = PPCInterpreter_getMainCoreCycleCounter() / 20ULL;\n\tlastSwapTime = tick64;\n\t// count flip request\n\t// is this updated via a PM4 MEM_WRITE operation?\n\n\t// Orochi Warriors seems to call GX2SwapScanBuffers on arbitrary threads/cores. The PM4 commands should go through to the GPU as long as there is no active display list and no other core is submitting commands simultaneously\n\t// right now, we work around this by avoiding the infinite loop below (request counter incremented, but PM4 not sent)\n\tuint32 coreIndex = coreinit::OSGetCoreId();\n\tif (GX2::sGX2MainCoreIndex == coreIndex)\n\t\tLatteGPUState.sharedArea->flipRequestCountBE = _swapEndianU32(_swapEndianU32(LatteGPUState.sharedArea->flipRequestCountBE) + 1);\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_REQUEST_SWAP_BUFFERS, 1));\n\tgx2WriteGather_submitU32AsBE(0); // reserved\n\n\t// swap frames\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_TRIGGER_SCANBUFFER_SWAP, 1));\n\tgx2WriteGather_submitU32AsBE(0); // reserved\n\n\t// wait for flip if the CPU is too far ahead\n\t// doing it after swap request is how the actual console does it, but that still causes issues in Pokken\n\twhile ((sint32)(_swapEndianU32(LatteGPUState.sharedArea->flipRequestCountBE) - _swapEndianU32(LatteGPUState.sharedArea->flipExecuteCountBE)) > 5)\n\t{\n\t\tGX2::GX2WaitForFlip();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2CopyColorBufferToScanBuffer(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2CopyColorBufferToScanBuffer(0x{:08x},{})\", hCPU->gpr[3], hCPU->gpr[4]);\n\tGX2::GX2ReserveCmdSpace(10);\n\n\t// todo: proper implementation\n\n\tGX2ColorBuffer* colorBuffer = (GX2ColorBuffer*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_COPY_COLORBUFFER_TO_SCANBUFFER, 9));\n\tgx2WriteGather_submitU32AsBE(memory_virtualToPhysical(colorBuffer->surface.imagePtr));\n\tgx2WriteGather_submitU32AsBE((uint32)colorBuffer->surface.width);\n\tgx2WriteGather_submitU32AsBE((uint32)colorBuffer->surface.height);\n\tgx2WriteGather_submitU32AsBE((uint32)colorBuffer->surface.pitch);\n\tgx2WriteGather_submitU32AsBE((uint32)colorBuffer->surface.tileMode.value());\n\tgx2WriteGather_submitU32AsBE((uint32)colorBuffer->surface.swizzle);\n\tgx2WriteGather_submitU32AsBE((uint32)colorBuffer->viewFirstSlice);\n\tgx2WriteGather_submitU32AsBE((uint32)colorBuffer->surface.format.value());\n\tgx2WriteGather_submitU32AsBE(hCPU->gpr[4]);\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2WaitForFreeScanBuffer(PPCInterpreter_t* hCPU)\n{\n\t// todo: proper implementation\n\tdebug_printf(\"GX2WaitForFreeScanBuffer(): Unimplemented\\n\");\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2GetCurrentScanBuffer(PPCInterpreter_t* hCPU)\n{\n\t// todo: proper implementation\n\tuint32 scanTarget = hCPU->gpr[3];\n\tGX2ColorBuffer* colorBufferBE = (GX2ColorBuffer*)memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\tmemset(colorBufferBE, 0x00, sizeof(GX2ColorBuffer));\n\tcolorBufferBE->surface.width = 100;\n\tcolorBufferBE->surface.height = 100;\n\t// note: For now we abuse the tiling aperture memory area as framebuffer pointers\n\tif( scanTarget == GX2_SCAN_TARGET_TV )\n\t{\n\t\tcolorBufferBE->surface.imagePtr = MEMORY_TILINGAPERTURE_AREA_ADDR+0x200000;\n\t}\n\telse if( scanTarget == GX2_SCAN_TARGET_DRC_FIRST )\n\t{\n\t\tcolorBufferBE->surface.imagePtr = MEMORY_TILINGAPERTURE_AREA_ADDR+0x40000;\n\t}\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid coreinitExport_GX2GetSystemTVScanMode(PPCInterpreter_t* hCPU)\n{\n\t// 1080p = 7\n\tosLib_returnFromFunction(hCPU, 7);\n}\n\nvoid coreinitExport_GX2GetSystemTVAspectRatio(PPCInterpreter_t* hCPU)\n{\n\tosLib_returnFromFunction(hCPU, 1); // 16:9\n}\n\nvoid gx2Export_GX2TempGetGPUVersion(PPCInterpreter_t* hCPU)\n{\n\tosLib_returnFromFunction(hCPU, 2);\n}\n\nvoid _GX2InitScanBuffer(GX2ColorBuffer* colorBuffer, sint32 width, sint32 height, Latte::E_GX2SURFFMT format)\n{\n\tcolorBuffer->surface.resFlag = GX2_RESFLAG_USAGE_TEXTURE | GX2_RESFLAG_USAGE_COLOR_BUFFER;\n\tcolorBuffer->surface.width = width;\n\tcolorBuffer->surface.height = height;\n\tcolorBuffer->viewFirstSlice = 0;\n\tcolorBuffer->viewNumSlices = 1;\n\tcolorBuffer->viewMip = 0;\n\tcolorBuffer->surface.numLevels = 1;\n\tcolorBuffer->surface.dim = Latte::E_DIM::DIM_2D;\n\tcolorBuffer->surface.swizzle = 0;\n\tcolorBuffer->surface.depth = 1;\n\tcolorBuffer->surface.tileMode = Latte::E_GX2TILEMODE::TM_LINEAR_GENERAL;\n\tcolorBuffer->surface.format = format;\n\tcolorBuffer->surface.mipPtr = MPTR_NULL;\n\tcolorBuffer->surface.aa = 0;\n\tGX2::GX2CalcSurfaceSizeAndAlignment(&colorBuffer->surface);\n\tcolorBuffer->surface.resFlag = GX2_RESFLAG_USAGE_TEXTURE | GX2_RESFLAG_USAGE_COLOR_BUFFER | GX2_RESFLAG_USAGE_SCAN_BUFFER;\n}\n\nvoid gx2Export_GX2CalcTVSize(PPCInterpreter_t* hCPU)\n{\n\tuint32 tvRenderMode = hCPU->gpr[3];\n\tLatte::E_GX2SURFFMT format = (Latte::E_GX2SURFFMT)hCPU->gpr[4];\n\tuint32 bufferingMode = hCPU->gpr[5];\n\tuint32 outputSizeMPTR = hCPU->gpr[6];\n\tuint32 outputScaleNeededMPTR = hCPU->gpr[7];\n\n\tcemu_assert(tvRenderMode < GX2_TV_RENDER_COUNT);\n\n\tuint32 width = tvScanBufferResolutions[tvRenderMode].width;\n\tuint32 height = tvScanBufferResolutions[tvRenderMode].height;\n\t\n\tGX2ColorBuffer colorBuffer;\n\tmemset(&colorBuffer, 0, sizeof(GX2ColorBuffer));\n\t_GX2InitScanBuffer(&colorBuffer, width, height, format);\n\n\tuint32 imageSize = colorBuffer.surface.imageSize;\n\tuint32 alignment = colorBuffer.surface.alignment;\n\n\tuint32 alignmentPaddingSize = (alignment - (imageSize%alignment)) % alignment;\n\n\tuint32 uknMult = 1; // probably for interlaced?\n\tif (tvRenderMode == GX2_TV_RENDER_720I)\n\t\tuknMult = 2;\n\n\tuint32 adjustedBufferingMode = bufferingMode;\n\tif (tvRenderMode < GX2_TV_RENDER_720)\n\t\tadjustedBufferingMode = 4;\n\n\tuint32 bufferedImageSize = (imageSize + alignmentPaddingSize) * adjustedBufferingMode;\n\tbufferedImageSize = bufferedImageSize * uknMult - alignmentPaddingSize;\n\t\n\tmemory_writeU32(outputSizeMPTR, bufferedImageSize);\n\tmemory_writeU32(outputScaleNeededMPTR, 0); // todo\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2CalcDRCSize(PPCInterpreter_t* hCPU)\n{\n\n\tppcDefineParamS32(drcMode, 0);\n\tppcDefineParamU32(format, 1);\n\tppcDefineParamU32(bufferingMode, 2);\n\tppcDefineParamMPTR(sizeMPTR, 3);\n\tppcDefineParamMPTR(scaleNeededMPTR, 4);\n\n\tuint32 width = 0;\n\tuint32 height = 0;\n\tif (drcMode > 0)\n\t{\n\t\twidth = 854;\n\t\theight = 480;\n\t}\n\n\tGX2ColorBuffer colorBuffer = {};\n\tmemset(&colorBuffer, 0, sizeof(colorBuffer));\n\t_GX2InitScanBuffer(&colorBuffer, width, height, (Latte::E_GX2SURFFMT)format);\n\n\tuint32 imageSize = colorBuffer.surface.imageSize;\n\tuint32 alignment = colorBuffer.surface.alignment;\n\n\tuint32 alignmentPaddingSize = (alignment - (imageSize%alignment)) % alignment;\n\n\n\tuint32 adjustedBufferingMode = bufferingMode;\n\n\tuint32 bufferedImageSize = (imageSize + alignmentPaddingSize) * adjustedBufferingMode;\n\tbufferedImageSize = bufferedImageSize - alignmentPaddingSize;\n\n\tmemory_writeU32(sizeMPTR, bufferedImageSize);\n\tmemory_writeU32(scaleNeededMPTR, 0);\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SetDRCScale(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetDRCScale({},{})\", hCPU->gpr[3], hCPU->gpr[4]);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SetDRCConnectCallback(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamS32(channel, 0);\n\tppcDefineParamMEMPTR(callback, void, 1);\n\tcemuLog_log(LogType::GX2, \"GX2SetDRCConnectCallback({}, 0x{:08x})\", channel, callback.GetMPTR());\n\tif(callback.GetPtr())\n\t\tPPCCoreCallback(callback, channel, TRUE);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SetSemaphore(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetSemaphore(0x{:08x},{})\", hCPU->gpr[3], hCPU->gpr[4]);\n\tppcDefineParamMPTR(semaphoreMPTR, 0);\n\tppcDefineParamS32(mode, 1);\n\n\tuint32 SEM_SEL;\n\n\tif (mode == 0)\n\t{\n\t\t// wait\n\t\tSEM_SEL = 7;\n\t}\n\telse if (mode == 1)\n\t{\n\t\t// signal\n\t\tSEM_SEL = 6;\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\tuint32 semaphoreControl = (SEM_SEL << 29);\n\tsemaphoreControl |= 0x1000; // WAIT_ON_SIGNAL\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_MEM_SEMAPHORE, 2));\n\tgx2WriteGather_submitU32AsBE(memory_virtualToPhysical(semaphoreMPTR)); // semaphore physical address\n\tgx2WriteGather_submitU32AsBE(semaphoreControl); // control\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nnamespace GX2\n{\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::vector<std::string_view> GetDependencies() override\n\t\t{\n\t\t\treturn {\"avm\", \"coreinit\", \"tcl\"};\n\t\t}\n\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"gx2\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"gx2\", \"GX2GetContextStateDisplayList\", gx2Export_GX2GetContextStateDisplayList);\n\n\t\t\t// swap, vsync & timing\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SwapScanBuffers\", gx2Export_GX2SwapScanBuffers);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2GetSwapStatus\", gx2Export_GX2GetSwapStatus);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2CopyColorBufferToScanBuffer\", gx2Export_GX2CopyColorBufferToScanBuffer);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2WaitForFreeScanBuffer\", gx2Export_GX2WaitForFreeScanBuffer);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2GetCurrentScanBuffer\", gx2Export_GX2GetCurrentScanBuffer);\n\n\t\t\t// shader stuff\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetPixelShader\", gx2Export_GX2SetPixelShader);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetGeometryShader\", gx2Export_GX2SetGeometryShader);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetComputeShader\", gx2Export_GX2SetComputeShader);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetVertexUniformBlock\", gx2Export_GX2SetVertexUniformBlock);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2RSetVertexUniformBlock\", gx2Export_GX2RSetVertexUniformBlock);\n\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetPixelUniformBlock\", gx2Export_GX2SetPixelUniformBlock);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetGeometryUniformBlock\", gx2Export_GX2SetGeometryUniformBlock);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetShaderModeEx\", gx2Export_GX2SetShaderModeEx);\n\n\t\t\tosLib_addFunction(\"gx2\", \"GX2CalcGeometryShaderInputRingBufferSize\", gx2Export_GX2CalcGeometryShaderInputRingBufferSize);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2CalcGeometryShaderOutputRingBufferSize\", gx2Export_GX2CalcGeometryShaderOutputRingBufferSize);\n\n\t\t\t// color/depth buffers\n\t\t\tosLib_addFunction(\"gx2\", \"GX2InitColorBufferRegs\", gx2Export_GX2InitColorBufferRegs);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2InitDepthBufferRegs\", gx2Export_GX2InitDepthBufferRegs);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetColorBuffer\", gx2Export_GX2SetColorBuffer);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetDepthBuffer\", gx2Export_GX2SetDepthBuffer);\n\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetDRCBuffer\", gx2Export_GX2SetDRCBuffer);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2MarkScanBufferCopied\", gx2Export_GX2MarkScanBufferCopied);\n\n\t\t\t// misc\n\t\t\tosLib_addFunction(\"gx2\", \"GX2TempGetGPUVersion\", gx2Export_GX2TempGetGPUVersion);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2CalcTVSize\", gx2Export_GX2CalcTVSize);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2CalcDRCSize\", gx2Export_GX2CalcDRCSize);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetDRCScale\", gx2Export_GX2SetDRCScale);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetDRCConnectCallback\", gx2Export_GX2SetDRCConnectCallback);\n\n\t\t\tosLib_addFunction(\"gx2\", \"GX2GetSystemTVScanMode\", coreinitExport_GX2GetSystemTVScanMode);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2GetSystemTVAspectRatio\", coreinitExport_GX2GetSystemTVAspectRatio);\n\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetSwapInterval\", gx2Export_GX2SetSwapInterval);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2GetSwapInterval\", gx2Export_GX2GetSwapInterval);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2GetGPUTimeout\", gx2Export_GX2GetGPUTimeout);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SampleTopGPUCycle\", gx2Export_GX2SampleTopGPUCycle);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SampleBottomGPUCycle\", gx2Export_GX2SampleBottomGPUCycle);\n\n\t\t\tosLib_addFunction(\"gx2\", \"GX2AllocateTilingApertureEx\", gx2Export_GX2AllocateTilingApertureEx);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2FreeTilingAperture\", gx2Export_GX2FreeTilingAperture);\n\n\t\t\t// context state\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetDefaultState\", gx2Export_GX2SetDefaultState);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetupContextStateEx\", gx2Export_GX2SetupContextStateEx);\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetContextState\", gx2Export_GX2SetContextState);\n\n\t\t\t// semaphore\n\t\t\tosLib_addFunction(\"gx2\", \"GX2SetSemaphore\", gx2Export_GX2SetSemaphore);\n\n\t\t\tGX2::GX2MemInit();\n\t\t\tGX2::GX2ResourceInit();\n\t\t\tGX2::GX2CommandInit();\n\t\t\tGX2::GX2SurfaceInit();\n\t\t\tGX2::GX2SurfaceCopyInit();\n\t\t\tGX2::GX2TextureInit();\n\t\t\tGX2::GX2StateInit();\n\t\t\tGX2::GX2ShaderInit();\n\t\t\tGX2::GX2EventInit();\n\t\t\tGX2::GX2BlitInit();\n\t\t\tGX2::GX2DrawInit();\n\t\t\tGX2::GX2StreamoutInit();\n\t\t\tGX2::GX2QueryInit();\n\t\t\tGX2::GX2MiscInit();\n\t\t};\n\t}s_COSGX2Module;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSGX2Module;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/OS/RPL/COSModule.h\"\n\n// base defines for GX2\n#define GX2_TRUE\t1\n#define GX2_FALSE\t0\n#define GX2_ENABLE\t1\n#define GX2_DISABLE\t0\n\n#include \"GX2_Surface.h\"\n\n// general\n\nnamespace GX2\n{\n\tCOSModule* GetModule();\n}\n\n// shader\n\nvoid gx2Export_GX2SetPixelShader(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetGeometryShader(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetComputeShader(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetVertexUniformBlock(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2RSetVertexUniformBlock(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetPixelUniformBlock(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetGeometryUniformBlock(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetShaderModeEx(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2CalcGeometryShaderInputRingBufferSize(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2CalcGeometryShaderOutputRingBufferSize(PPCInterpreter_t* hCPU);\n\n// write gather / command queue\n\n#define GX2_COMMAND_RING_BUFFER_SIZE\t(64*1024*1024) // 64MB\n\nvoid gx2Export_GX2GetContextStateDisplayList(PPCInterpreter_t* hCPU);\n\n#include \"GX2_Command.h\"\n\n// misc\nvoid gx2Export_GX2AllocateTilingApertureEx(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2FreeTilingAperture(PPCInterpreter_t* hCPU);\n\nvoid gx2Export_GX2SetSwapInterval(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2GetSwapInterval(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2GetSwapStatus(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2GetGPUTimeout(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SampleTopGPUCycle(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SampleBottomGPUCycle(PPCInterpreter_t* hCPU);\n\n// color/depth buffers\n\n#define GX2_SCAN_TARGET_TV\t\t\t\t1\n#define GX2_SCAN_TARGET_TV_RIGH\t\t\t2\n#define GX2_SCAN_TARGET_DRC_FIRST\t\t4\n#define GX2_SCAN_TARGET_DRC_SECOND\t\t8\n\nvoid gx2Export_GX2InitColorBufferRegs(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2InitDepthBufferRegs(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetColorBuffer(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetDepthBuffer(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetDRCBuffer(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2MarkScanBufferCopied(PPCInterpreter_t* hCPU);\n\n// special state\n\n#define GX2_SPECIAL_STATE_COUNT\t\t\t9\n\n// context state\n\nvoid gx2Export_GX2SetDefaultState(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetupContextStateEx(PPCInterpreter_t* hCPU);\nvoid gx2Export_GX2SetContextState(PPCInterpreter_t* hCPU);"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_AddrTest.cpp",
    "content": "#include \"Cafe/OS/libs/coreinit/coreinit_DynLoad.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n\nnamespace GX2\n{\n\tstruct AddrCreate_INPUT\n\t{\n\t\t/* +0x00 */ uint32be structSize;\n\t\t/* +0x04 */ uint32be ukn04_maybeGen;\n\t\t/* +0x08 */ uint32be ukn08;\n\t\t/* +0x0C */ uint32be revision;\n\t\t/* +0x10 */ uint32be func_Alloc;\n\t\t/* +0x14 */ uint32be func_Free;\n\t\t/* +0x18 */ uint32be func_Debug;\n\t\t/* +0x1C */ uint32be ukn1C;\n\t\t/* +0x20 */ uint32be reg263C;\n\t\t/* +0x24 */ uint32be ukn24;\n\t\t/* +0x28 */ uint32be ukn28;\n\t\t/* +0x2C */ uint32be ukn2C;\n\t\t/* +0x30 */ uint32be ukn30;\n\t\t/* +0x34 */ uint32be ukn34;\n\t\t/* +0x38 */ uint32be ukn38;\n\t\t/* +0x3C */ uint32be ukn3C;\n\t\t/* +0x40 */ uint32be ukn40;\n\t};\n\n\tstruct AddrCreate_OUTPUT \n\t{\n\t\tuint32be structSize;\n\t\tMEMPTR<void> addrLibPtr;\n\t};\n\n\tstatic_assert(sizeof(AddrCreate_INPUT) == 0x44);\n\tstatic_assert(sizeof(AddrCreate_OUTPUT) == 8);\n\n\tstruct ADDRAllocParam \n\t{\n\t\tuint32be ukn00; // alignment?\n\t\tuint32be ukn04;\n\t\tuint32be size;\n\t};\n\n\tstruct ADDRComputeSurfaceInfo_INPUT\n\t{\n\t\tuint32be structSize;\n\t\tbetype<Latte::E_HWTILEMODE> tileMode;\n\t\tbetype<Latte::E_HWSURFFMT> format;\n\t\tuint32be bpp;\n\t\tuint32be numSamples;\n\t\tuint32be width;\n\t\tuint32be height;\n\t\tuint32be numSlices;\n\t\tuint32be slice;\n\t\tuint32be mipLevel;\n\t\tuint32be _flags;\n\t\tuint32be numFrags;\n\t\tMEMPTR<void> tileInfo;\n\t\tuint32be tileType;\n\t\tuint32be tileIndex;\n\n\t\tenum FLAG_BITS\n\t\t{\n\t\t\tFLAG_BIT_CUBE = (1 << 27),\n\t\t\tFLAG_BIT_VOLUME = (1 << 26),\n\n\t\t\tFLAG_BIT_OPT4SPACE = (1 << 19),\n\t\t};\n\n\t\tvoid SetFlagCube(bool f)\n\t\t{\n\t\t\tif (f) _flags |= FLAG_BIT_CUBE;\n\t\t\telse _flags &= ~FLAG_BIT_CUBE;\n\t\t}\n\n\t\tvoid SetFlagVolume(bool f)\n\t\t{\n\t\t\tif (f) _flags |= FLAG_BIT_VOLUME;\n\t\t\telse _flags &= ~FLAG_BIT_VOLUME;\n\t\t}\n\n\t\tvoid SetFlagOpt4Space(bool f)\n\t\t{\n\t\t\tif (f) _flags |= FLAG_BIT_OPT4SPACE;\n\t\t\telse _flags &= ~FLAG_BIT_OPT4SPACE;\n\t\t}\n\t};\n\n\tstatic_assert(sizeof(ADDRComputeSurfaceInfo_INPUT) == 0x3C);\n\n\tstruct ADDRComputeSurfaceInfo_OUTPUT\n\t{\n\t\t/* 0x00 */ uint32be structSize;\n\t\t/* 0x04 */ uint32be pitch;\n\t\t/* 0x08 */ uint32be height;\n\t\t/* 0x0C */ uint32be depth;\n\t\t/* 0x10 */ uint64be surfSize;\n\t\t/* 0x18 */ uint32be tileMode;\n\t\t/* 0x1C */ uint32be baseAlign;\n\t\t/* 0x20 */ uint32be pitchAlign;\n\t\t/* 0x24 */ uint32be heightAlign;\n\t\t/* 0x28 */ uint32be depthAlign;\n\t\t/* 0x2C */ uint32be bpp;\n\t\t/* 0x30 */ uint32be pixelPitch;\n\t\t/* 0x34 */ uint32be pixelHeight;\n\t\t/* 0x38 */ uint32be pixelBits;\n\t\t/* 0x3C */ uint32be sliceSize;\n\t\t/* 0x40 */ uint32be pitchTileMax;\n\t\t/* 0x44 */ uint32be heightTileMax;\n\t\t/* 0x48 */ uint32be sliceTileMax;\n\t\t/* 0x4C */ MEMPTR<void> tileInfo;\n\t\t/* 0x50 */ uint32be tileType;\n\t\t/* 0x54 */ uint32be tileIndex;\n\t\t/* 0x58 */ MEMPTR<void> stereoInfo;\n\t\t/* 0x5C */ uint32be _padding;\n\t};\n\n\tstatic_assert(sizeof(ADDRComputeSurfaceInfo_OUTPUT) == 0x60);\n\n\tstatic void _cb_alloc(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamStructPtr(param, ADDRAllocParam, 0);\n\t\tuint32 r = coreinit_allocFromSysArea(param->size, 0x10);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tstatic void _cb_free(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tstatic void _cb_debug(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tstatic void* sAddrLib{};\n\tstatic uint32be tclFunc_AddrCreate = 0;\n\tstatic uint32be tclFunc_AddrComputeSurfaceInfo = 0;\n\n\tvoid _TestAddrLib_Init()\n\t{\n\t\t// load tcl_addr_test.rpl (from /cafelibs/)\n\t\tuint32be tclHandle;\n\t\tuint32 r = coreinit::OSDynLoad_Acquire(\"tcl_addr_test.rpl\", &tclHandle);\n\t\tcemu_assert_debug(r == 0);\n\n\t\t// get imports\n\t\tr = coreinit::OSDynLoad_FindExport(tclHandle, 0, \"AddrCreate\", &tclFunc_AddrCreate);\n\t\tcemu_assert_debug(r == 0);\n\t\tr = coreinit::OSDynLoad_FindExport(tclHandle, 0, \"AddrComputeSurfaceInfo\", &tclFunc_AddrComputeSurfaceInfo);\n\t\tcemu_assert_debug(r == 0);\n\n\t\t// call AddrCreate\n\t\tStackAllocator<AddrCreate_INPUT> addrCreateIn;\n\t\tmemset(addrCreateIn.GetPointer(), 0, sizeof(addrCreateIn));\n\t\taddrCreateIn->structSize = sizeof(addrCreateIn);\n\n\t\taddrCreateIn->ukn04_maybeGen = 6; // R600?\n\t\taddrCreateIn->ukn08 = 0x51;\n\t\taddrCreateIn->revision = 71;\n\t\taddrCreateIn->reg263C = 0x44902;\n\t\taddrCreateIn->ukn24 = 0; // ukn\n\n\t\taddrCreateIn->func_Alloc = PPCInterpreter_makeCallableExportDepr(_cb_alloc);\n\t\taddrCreateIn->func_Free = PPCInterpreter_makeCallableExportDepr(_cb_free);\n\t\taddrCreateIn->func_Debug = PPCInterpreter_makeCallableExportDepr(_cb_debug);\n\n\t\tStackAllocator<AddrCreate_OUTPUT> addrCreateOut;\n\t\tmemset(addrCreateOut.GetPointer(), 0, sizeof(addrCreateOut));\n\t\taddrCreateOut->structSize = sizeof(addrCreateOut);\n\n\t\tr = PPCCoreCallback((uint32)tclFunc_AddrCreate, addrCreateIn.GetPointer(), addrCreateOut.GetPointer());\n\t\tsAddrLib = addrCreateOut->addrLibPtr;\n\t\tcemu_assert_debug(r == 0 && sAddrLib != nullptr);\n\t}\n\n\tvoid _TestAddrLib_CalculateSurfaceInfo(Latte::E_GX2SURFFMT surfaceFormat, uint32 surfaceWidth, uint32 surfaceHeight, uint32 surfaceDepth, Latte::E_DIM surfaceDim, Latte::E_GX2TILEMODE surfaceTileMode, uint32 surfaceAA, uint32 level, ADDRComputeSurfaceInfo_OUTPUT* paramOut)\n\t{\n\t\tStackAllocator<ADDRComputeSurfaceInfo_INPUT> _paramIn;\n\t\tADDRComputeSurfaceInfo_INPUT& paramIn = *_paramIn.GetPointer();\n\t\tmemset(&paramIn, 0, sizeof(ADDRComputeSurfaceInfo_INPUT));\n\t\tmemset(paramOut, 0, sizeof(ADDRComputeSurfaceInfo_OUTPUT));\n\t\tLatte::E_HWSURFFMT hwFormat = GetHWFormat(surfaceFormat);\n\t\tif (surfaceTileMode == Latte::E_GX2TILEMODE::TM_LINEAR_SPECIAL)\n\t\t{\n\t\t\tuint32 numSamples = 1 << surfaceAA;\t\t\t\n\t\t\tuint32 blockSize = IsCompressedFormat(surfaceFormat) ? 4 : 1;\n\t\t\tuint32 width = ((surfaceWidth >> level) + blockSize - 1) & ~(blockSize - 1);\n\t\t\tparamOut->bpp = GetFormatBits(hwFormat);\n\t\t\tparamOut->structSize = sizeof(ADDRComputeSurfaceInfo_OUTPUT);\n\t\t\tparamOut->pitch = width / blockSize;\n\t\t\tparamOut->pixelBits = paramOut->bpp;\n\t\t\tparamOut->baseAlign = 1;\n\t\t\tparamOut->pitchAlign = 1;\n\t\t\tparamOut->heightAlign = 1;\n\t\t\tparamOut->depthAlign = 1;\n\t\t\tswitch (surfaceDim)\n\t\t\t{\n\t\t\tcase Latte::E_DIM::DIM_1D:\n\t\t\t\tparamOut->height = 1;\n\t\t\t\tparamOut->depth = 1;\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_2D:\n\t\t\t\tparamOut->height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tparamOut->depth = 1;\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_3D:\n\t\t\t\tparamOut->height = surfaceHeight >> level;\n\t\t\t\tparamOut->height = std::max<uint32>(paramOut->height, 1);\n\t\t\t\tparamOut->depth = std::max<uint32>(surfaceDepth >> level, 1);\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_CUBEMAP:\n\t\t\t\tparamOut->height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tparamOut->depth = std::max<uint32>(surfaceDepth, 6);\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_1D_ARRAY:\n\t\t\t\tparamOut->height = 1;\n\t\t\t\tparamOut->depth = surfaceDepth;\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_2D_ARRAY:\n\t\t\t\tparamOut->height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tparamOut->depth = surfaceDepth;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tparamOut->height = ((paramOut->height + blockSize - 1) & ~(blockSize - 1)) / (uint64)blockSize;\n\t\t\tparamOut->pixelPitch = ((surfaceWidth >> level) + blockSize - 1) & ~(blockSize - 1);\n\t\t\tparamOut->pixelPitch = std::max<uint32>(paramOut->pixelPitch, blockSize);\n\t\t\tparamOut->pixelHeight = ((surfaceHeight >> level) + blockSize - 1) & ~(blockSize - 1);\n\t\t\tparamOut->pixelHeight = std::max<uint32>(paramOut->pixelHeight, blockSize);;\n\t\t\tparamOut->pitch = std::max<uint32>(paramOut->pitch, 1);\n\t\t\tparamOut->height = std::max<uint32>(paramOut->height, 1);\n\t\t\tparamOut->surfSize = paramOut->bpp * numSamples * paramOut->depth * paramOut->height * paramOut->pitch >> 3;\n\t\t\tif (surfaceDim == Latte::E_DIM::DIM_3D)\n\t\t\t\tparamOut->sliceSize = (uint32)(paramOut->surfSize);\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (paramOut->surfSize == 0 && paramOut->depth == 0)\n\t\t\t\t\tparamOut->sliceSize = 0; // edge case for (1D)_ARRAY textures with 0/0/0 res\n\t\t\t\telse\n\t\t\t\t\tparamOut->sliceSize = ((uint32)paramOut->surfSize.value() / paramOut->depth);\n\t\t\t}\n\t\t\tparamOut->pitchTileMax = (paramOut->pitch >> 3) - 1;\n\t\t\tparamOut->heightTileMax = (paramOut->height >> 3) - 1;\n\t\t\tparamOut->sliceTileMax = (paramOut->height * paramOut->pitch >> 6) - 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tparamIn.structSize = sizeof(paramIn);\n\t\t\tparamIn.tileMode = Latte::MakeHWTileMode(surfaceTileMode);\n\t\t\tparamIn.format = hwFormat;\n\t\t\tparamIn.bpp = GetFormatBits(hwFormat);\n\t\t\tparamIn.numSamples = 1 << surfaceAA;\n\t\t\tparamIn.numFrags = paramIn.numSamples;\n\t\t\tparamIn.width = std::max<uint32>(surfaceWidth >> level, 1);\n\t\t\tswitch (surfaceDim)\n\t\t\t{\n\t\t\tcase Latte::E_DIM::DIM_1D:\n\t\t\t\tparamIn.height = 1;\n\t\t\t\tparamIn.numSlices = 1;\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_2D:\n\t\t\t\tparamIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tparamIn.numSlices = 1;\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_3D:\n\t\t\t\tparamIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tparamIn.numSlices = std::max<uint32>(surfaceDepth >> level, 1);\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_CUBEMAP:\n\t\t\t\tparamIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tparamIn.numSlices = std::max<uint32>(surfaceDepth, 6);\n\t\t\t\tparamIn.SetFlagCube(true);\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_1D_ARRAY:\n\t\t\t\tparamIn.height = 1;\n\t\t\t\tparamIn.numSlices = surfaceDepth;\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_2D_ARRAY:\n\t\t\t\tparamIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tparamIn.numSlices = surfaceDepth;\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_2D_MSAA:\n\t\t\t\tparamIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tparamIn.numSlices = 1;\n\t\t\t\tbreak;\n\t\t\tcase Latte::E_DIM::DIM_2D_ARRAY_MSAA:\n\t\t\t\tparamIn.height = std::max<uint32>(surfaceHeight >> level, 1);\n\t\t\t\tparamIn.numSlices = surfaceDepth;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tparamIn.slice = 0;\n\t\t\tparamIn.mipLevel = level;\n\t\t\tif (surfaceDim == Latte::E_DIM::DIM_3D)\n\t\t\t\tparamIn.SetFlagVolume(true);\n\t\t\tparamIn.SetFlagOpt4Space(level == 0);\n\t\t\tparamOut->structSize = sizeof(ADDRComputeSurfaceInfo_OUTPUT);\n\t\t\tPPCCoreCallback((uint32)tclFunc_AddrComputeSurfaceInfo, sAddrLib, _paramIn.GetPointer(), paramOut);\n\t\t}\n\t}\n\n\tvoid _TestAddrLib_Compare(uint32 surfaceWidth, uint32 surfaceHeight, uint32 surfaceDepth, Latte::E_DIM surfaceDim, Latte::E_GX2SURFFMT surfaceFormat, Latte::E_GX2TILEMODE surfaceTileMode, uint32 surfaceAA, uint32 level)\n\t{\n\t\t// get result from tcl.rpl\n\t\tStackAllocator<ADDRComputeSurfaceInfo_OUTPUT> _paramOut;\n\t\tADDRComputeSurfaceInfo_OUTPUT& tclSurfInfo = *_paramOut.GetPointer();\n\t\t_TestAddrLib_CalculateSurfaceInfo(surfaceFormat, surfaceWidth, surfaceHeight, surfaceDepth, surfaceDim, surfaceTileMode, surfaceAA, level, _paramOut.GetPointer());\n\t\t// get result from our implementation\n\t\tLatteAddrLib::AddrSurfaceInfo_OUT ourSurfInfo;\n\t\tLatteAddrLib::GX2CalculateSurfaceInfo(surfaceFormat, surfaceWidth, surfaceHeight, surfaceDepth, surfaceDim, surfaceTileMode, surfaceAA, level, &ourSurfInfo);\n\t\t// compare\n\t\tcemu_assert(tclSurfInfo.pitchAlign == ourSurfInfo.pitchAlign);\n\t\tcemu_assert((Latte::E_HWTILEMODE)tclSurfInfo.tileMode.value() == ourSurfInfo.hwTileMode);\n\t\tcemu_assert(tclSurfInfo.baseAlign == ourSurfInfo.baseAlign);\n\t\tcemu_assert(tclSurfInfo.surfSize == ourSurfInfo.surfSize);\n\t\tcemu_assert(tclSurfInfo.depthAlign == ourSurfInfo.depthAlign);\n\t\tcemu_assert(tclSurfInfo.pitch == ourSurfInfo.pitch);\n\t\tcemu_assert(tclSurfInfo.sliceSize == ourSurfInfo.sliceSize);\n\t}\n\n\tvoid _TestAddrLib_Run()\n\t{\n\t\tuint32 surfaceAA = 0;\n\n\t\tstd::vector<Latte::E_DIM> dimList = {\n\t\t\tLatte::E_DIM::DIM_1D,\n\t\t\tLatte::E_DIM::DIM_2D,\n\t\t\tLatte::E_DIM::DIM_3D,\n\t\t\tLatte::E_DIM::DIM_CUBEMAP,\n\t\t\tLatte::E_DIM::DIM_1D_ARRAY,\n\t\t\tLatte::E_DIM::DIM_2D_ARRAY,\n\t\t\tLatte::E_DIM::DIM_2D_MSAA,\n\t\t\tLatte::E_DIM::DIM_2D_ARRAY_MSAA\n\t\t};\n\n\t\tstd::vector<Latte::E_GX2TILEMODE> tilemodeList = {\n\t\t\t// linear\n\t\t\tLatte::E_GX2TILEMODE::TM_LINEAR_GENERAL,\n\t\t\tLatte::E_GX2TILEMODE::TM_LINEAR_ALIGNED,\n\t\t\t// micro tiled\n\t\t\tLatte::E_GX2TILEMODE::TM_1D_TILED_THIN1,\n\t\t\tLatte::E_GX2TILEMODE::TM_1D_TILED_THICK,\n\t\t\t// macro tiled\n\t\t\tLatte::E_GX2TILEMODE::TM_2D_TILED_THIN1,\n\t\t\tLatte::E_GX2TILEMODE::TM_2D_TILED_THIN4,\n\t\t\tLatte::E_GX2TILEMODE::TM_2D_TILED_THIN2,\n\t\t\tLatte::E_GX2TILEMODE::TM_2D_TILED_THICK,\n\t\t\tLatte::E_GX2TILEMODE::TM_2B_TILED_THIN1,\n\t\t\tLatte::E_GX2TILEMODE::TM_2B_TILED_THIN2,\n\t\t\tLatte::E_GX2TILEMODE::TM_2B_TILED_THIN4,\n\t\t\tLatte::E_GX2TILEMODE::TM_2B_TILED_THICK,\n\t\t\tLatte::E_GX2TILEMODE::TM_3D_TILED_THIN1,\n\t\t\tLatte::E_GX2TILEMODE::TM_3D_TILED_THICK,\n\t\t\tLatte::E_GX2TILEMODE::TM_3B_TILED_THIN1,\n\t\t\tLatte::E_GX2TILEMODE::TM_3B_TILED_THICK,\n\t\t\t// special\n\t\t\tLatte::E_GX2TILEMODE::TM_LINEAR_SPECIAL,\n\t\t\tLatte::E_GX2TILEMODE::TM_32_SPECIAL, // note: Specific to GX2CalcSurfaceSizeAndAlignment, for AddrLib this should just be interpreted as (tm&0xF)\n\t\t};\n\n\t\tstd::vector<Latte::E_GX2SURFFMT> formatList = {\n\t\t\tLatte::E_GX2SURFFMT::HWFMT_8, Latte::E_GX2SURFFMT::HWFMT_8_8, Latte::E_GX2SURFFMT::HWFMT_8_8_8_8, // 8, 16, 32\n\t\t\tLatte::E_GX2SURFFMT::R32_UINT, Latte::E_GX2SURFFMT::R32_G32_UINT, Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT, // 32, 64, 128\n\t\t\tLatte::E_GX2SURFFMT::HWFMT_BC1, Latte::E_GX2SURFFMT::HWFMT_BC2, Latte::E_GX2SURFFMT::HWFMT_BC3, Latte::E_GX2SURFFMT::HWFMT_BC4, Latte::E_GX2SURFFMT::HWFMT_BC5\n\t\t};\n\n\t\tstd::vector<uint32> resXYList = {\n\t\t\t0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17,\n\t\t\t31, 32, 33, 50, 63, 64, 65, 127, 128, 129, 200, 253, 254, 255, 256, 257,\n\t\t\t511, 512, 513, 1023, 1024, 1025, 2047, 2048, 2049, 4095, 4096, 4097\n\t\t};\n\n\t\tdebug_printf(\"Running AddrLib test...\\n\");\n\n\t\tBenchmarkTimer timer;\n\t\ttimer.Start();\n\t\tsize_t index = 0;\n\t\tfor (auto dim : dimList)\n\t\t{\n\t\t\tdebug_printf(\"%d/%d\\n\", (int)index, (int)dimList.size());\n\t\t\tindex++;\n\t\t\tfor (auto tileMode : tilemodeList)\n\t\t\t{\n\t\t\t\tfor (auto format : formatList)\n\t\t\t\t{\n\t\t\t\t\tfor (uint32 level = 0; level < 16; level++)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (auto depth : resXYList)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfor (auto height : resXYList)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfor (auto width : resXYList)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t_TestAddrLib_Compare(width, height, depth, dim, format, tileMode, surfaceAA, level);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ttimer.Stop();\n\t\tdebug_printf(\"Test complete (in %d seconds)\\n\", (int)(timer.GetElapsedMilliseconds() * 0.001));\n\t\tassert_dbg();\n\t}\n\n\tvoid _test_AddrLib()\n\t{\n\t\treturn;\n\t\t_TestAddrLib_Init();\n\t\t_TestAddrLib_Run();\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Blit.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"GX2_Blit.h\"\n#include \"GX2_Command.h\"\n#include \"GX2_Surface.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"GX2_Resource.h\"\n\nnamespace GX2\n{\n\t// sets the depth/stencil clear registers and updates clear values in DepthBuffer struct\n\tvoid GX2SetClearDepthStencil(GX2DepthBuffer* depthBuffer, float depthClearValue, uint8 stencilClearValue)\n\t{\n\t\tGX2ReserveCmdSpace(4);\n\t\tdepthBuffer->clearDepth = depthClearValue;\n\t\tdepthBuffer->clearStencil = stencilClearValue;\n\t\tLatte::LATTE_DB_STENCIL_CLEAR stencilClearReg;\n\t\tstencilClearReg.set_clearValue(stencilClearValue);\n\t\tLatte::LATTE_DB_DEPTH_CLEAR depthClearReg;\n\t\tdepthClearReg.set_clearValue(depthClearValue);\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 2),\n\t\t\tLatte::REGADDR::DB_STENCIL_CLEAR - 0xA000,\n\t\t\tstencilClearReg, depthClearReg);\n\t}\n\n\t// similar to GX2SetClearDepthStencil but only sets depth\n\tvoid GX2SetClearDepth(GX2DepthBuffer* depthBuffer, float depthClearValue)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\t\tdepthBuffer->clearDepth = depthClearValue;\n\t\tLatte::LATTE_DB_DEPTH_CLEAR depthClearReg;\n\t\tdepthClearReg.set_clearValue(depthClearValue);\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::DB_DEPTH_CLEAR - 0xA000,\n\t\t\tdepthClearReg);\n\t}\n\n\t// similar to GX2SetClearDepthStencil but only sets stencil\n\tvoid GX2SetClearStencil(GX2DepthBuffer* depthBuffer, uint8 stencilClearValue)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\t\tdepthBuffer->clearStencil = stencilClearValue;\n\t\tLatte::LATTE_DB_STENCIL_CLEAR stencilClearReg;\n\t\tstencilClearReg.set_clearValue(stencilClearValue);\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::DB_STENCIL_CLEAR - 0xA000,\n\t\t\tstencilClearReg);\n\t}\n\n\t// update DB_STENCIL_CLEAR and DB_STENCIL_CLEAR based on clear flags\n\tvoid _updateDepthStencilClearRegs(float depthClearValue, uint8 stencilClearValue, GX2ClearFlags clearFlags)\n\t{\n\t\tif ((clearFlags & GX2ClearFlags::SET_DEPTH_REG) != 0 && (clearFlags & GX2ClearFlags::SET_STENCIL_REG) != 0)\n\t\t{\n\t\t\tGX2ReserveCmdSpace(4);\n\t\t\tLatte::LATTE_DB_STENCIL_CLEAR stencilClearReg;\n\t\t\tstencilClearReg.set_clearValue(stencilClearValue);\n\t\t\tLatte::LATTE_DB_DEPTH_CLEAR depthClearReg;\n\t\t\tdepthClearReg.set_clearValue(depthClearValue);\n\t\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 2),\n\t\t\t\tLatte::REGADDR::DB_STENCIL_CLEAR - 0xA000,\n\t\t\t\tstencilClearReg, depthClearReg);\n\t\t}\n\t\telse if ((clearFlags & GX2ClearFlags::SET_DEPTH_REG) != 0)\n\t\t{\n\t\t\tGX2ReserveCmdSpace(3);\n\t\t\tLatte::LATTE_DB_DEPTH_CLEAR depthClearReg;\n\t\t\tdepthClearReg.set_clearValue(depthClearValue);\n\t\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\t\tLatte::REGADDR::DB_DEPTH_CLEAR - 0xA000,\n\t\t\t\tdepthClearReg);\n\t\t}\n\t\telse if ((clearFlags & GX2ClearFlags::SET_STENCIL_REG) != 0)\n\t\t{\n\t\t\tGX2ReserveCmdSpace(3);\n\t\t\tLatte::LATTE_DB_STENCIL_CLEAR stencilClearReg;\n\t\t\tstencilClearReg.set_clearValue(stencilClearValue);\n\t\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\t\tLatte::REGADDR::DB_STENCIL_CLEAR - 0xA000,\n\t\t\t\tstencilClearReg);\n\t\t}\n\t}\n\n\tvoid SubmitHLEClear(GX2ColorBuffer* colorBuffer, float colorRGBA[4], GX2DepthBuffer* depthBuffer, float depthClearValue, uint8 stencilClearValue, bool clearColor, bool clearDepth, bool clearStencil)\n\t{\n\t\tGX2ReserveCmdSpace(50);\n\t\tuint32 hleClearFlags = 0;\n\t\tif (clearColor)\n\t\t\thleClearFlags |= 1;\n\t\tif (clearDepth)\n\t\t\thleClearFlags |= 2;\n\t\tif (clearStencil)\n\t\t\thleClearFlags |= 4;\n\t\t// color buffer\n\t\tMPTR colorPhysAddr = MPTR_NULL;\n\t\tuint32 colorFormat = 0;\n\t\tuint32 colorTileMode = 0;\n\t\tuint32 colorWidth = 0;\n\t\tuint32 colorHeight = 0;\n\t\tuint32 colorPitch = 0;\n\t\tuint32 colorFirstSlice = 0;\n\t\tuint32 colorNumSlices = 0;\n\t\tif (colorBuffer != nullptr)\n\t\t{\n\t\t\tcolorPhysAddr = memory_virtualToPhysical(colorBuffer->surface.imagePtr);\n\t\t\tcolorFormat = (uint32)colorBuffer->surface.format.value();\n\t\t\tcolorTileMode = (uint32)colorBuffer->surface.tileMode.value();\n\t\t\tcolorWidth = colorBuffer->surface.width;\n\t\t\tcolorHeight = colorBuffer->surface.height;\n\t\t\tcolorPitch = colorBuffer->surface.pitch;\n\t\t\tcolorFirstSlice = colorBuffer->viewFirstSlice;\n\t\t\tcolorNumSlices = colorBuffer->viewNumSlices;\n\t\t}\n\t\t// depth buffer\n\t\tMPTR depthPhysAddr = MPTR_NULL;\n\t\tuint32 depthFormat = 0;\n\t\tuint32 depthTileMode = 0;\n\t\tuint32 depthWidth = 0;\n\t\tuint32 depthHeight = 0;\n\t\tuint32 depthPitch = 0;\n\t\tuint32 depthFirstSlice = 0;\n\t\tuint32 depthNumSlices = 0;\n\t\tif (depthBuffer != nullptr)\n\t\t{\n\t\t\tdepthPhysAddr = memory_virtualToPhysical(depthBuffer->surface.imagePtr);\n\t\t\tdepthFormat = (uint32)depthBuffer->surface.format.value();\n\t\t\tdepthTileMode = (uint32)depthBuffer->surface.tileMode.value();\n\t\t\tdepthWidth = depthBuffer->surface.width;\n\t\t\tdepthHeight = depthBuffer->surface.height;\n\t\t\tdepthPitch = depthBuffer->surface.pitch;\n\t\t\tdepthFirstSlice = depthBuffer->viewFirstSlice;\n\t\t\tdepthNumSlices = depthBuffer->viewNumSlices;\n\t\t}\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_HLE_CLEAR_COLOR_DEPTH_STENCIL, 23),\n\t\thleClearFlags,\n\t\tcolorPhysAddr,\n\t\tcolorFormat,\n\t\tcolorTileMode,\n\t\tcolorWidth,\n\t\tcolorHeight,\n\t\tcolorPitch,\n\t\tcolorFirstSlice,\n\t\tcolorNumSlices,\n\t\tdepthPhysAddr,\n\t\tdepthFormat,\n\t\tdepthTileMode,\n\t\tdepthWidth,\n\t\tdepthHeight,\n\t\tdepthPitch,\n\t\tdepthFirstSlice,\n\t\tdepthNumSlices,\n\t\t(uint32)(colorRGBA[0] * 255.0f),\n\t\t(uint32)(colorRGBA[1] * 255.0f),\n\t\t(uint32)(colorRGBA[2] * 255.0f),\n\t\t(uint32)(colorRGBA[3] * 255.0f),\n\t\t*(uint32*)&depthClearValue,\n\t\tstencilClearValue&0xFF);\n\t}\n\n\tvoid GX2ClearColor(GX2ColorBuffer* colorBuffer, float r, float g, float b, float a)\n\t{\n\t\tif ((colorBuffer->surface.resFlag & GX2_RESFLAG_USAGE_COLOR_BUFFER) != 0)\n\t\t{\n\t\t\tfloat colorRGBA[4] = { r, g, b, a };\n\t\t\tSubmitHLEClear(colorBuffer, colorRGBA, nullptr, 0.0f, 0, true, false, false);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebug_printf(\"GX2ClearColor() - unsupported surface flags\\n\");\n\t\t}\n\t}\n\n\tvoid GX2ClearBuffersEx(GX2ColorBuffer* colorBuffer, GX2DepthBuffer* depthBuffer, float r, float g, float b, float a, float depthClearValue, uint8 stencilClearValue, GX2ClearFlags clearFlags)\n\t{\n\t\t_updateDepthStencilClearRegs(depthClearValue, stencilClearValue, clearFlags);\n\n\t\tuint32 hleClearFlags = 0;\n\t\tif ((clearFlags & GX2ClearFlags::CLEAR_DEPTH) != 0)\n\t\t\thleClearFlags |= 2;\n\t\tif ((clearFlags & GX2ClearFlags::CLEAR_STENCIL) != 0)\n\t\t\thleClearFlags |= 4;\n\t\thleClearFlags |= 1;\n\n\t\tfloat colorRGBA[4] = { r, g, b, a };\n\t\tSubmitHLEClear(colorBuffer, colorRGBA, depthBuffer, depthClearValue, stencilClearValue, true, (clearFlags & GX2ClearFlags::CLEAR_DEPTH) != 0, (clearFlags & GX2ClearFlags::CLEAR_STENCIL) != 0);\n\t}\n\n\t// always uses passed depthClearValue/stencilClearValue for clearing, even if clear flags dont specify value updates\n\tvoid GX2ClearDepthStencilEx(GX2DepthBuffer* depthBuffer, float depthClearValue, uint8 stencilClearValue, GX2ClearFlags clearFlags)\n\t{\n\t\tif (!depthBuffer && (depthBuffer->surface.width == 0 || depthBuffer->surface.height == 0))\n\t\t{\n\t\t\t// Super Smash Bros tries to clear an uninitialized depth surface?\n\t\t\tdebug_printf(\"GX2ClearDepthStencilEx(): Attempting to clear invalid depthbuffer\\n\");\n\t\t\treturn;\n\t\t}\n\n\t\t_updateDepthStencilClearRegs(depthClearValue, stencilClearValue, clearFlags);\n\n\t\tfloat colorRGBA[4] = { 0.0f, 0.0f, 0.0f, 0.0f };\n\t\tSubmitHLEClear(nullptr, colorRGBA, depthBuffer, depthClearValue, stencilClearValue, false, (clearFlags & GX2ClearFlags::CLEAR_DEPTH) != 0, (clearFlags & GX2ClearFlags::CLEAR_STENCIL) != 0);\n\t}\n\n\tvoid GX2BlitInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2SetClearDepthStencil, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetClearDepth, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetClearStencil, LogType::GX2);\n\t\t\n\t\tcafeExportRegister(\"gx2\", GX2ClearColor, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2ClearBuffersEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2ClearDepthStencilEx, LogType::GX2);\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Blit.h",
    "content": "#pragma once\n\nnamespace GX2\n{\n\tenum class GX2ClearFlags : uint32\n\t{\n\t\tCLEAR_DEPTH = 0x01, // clear depth to given clear value\n\t\tCLEAR_STENCIL = 0x02, // clear stencil to given stencil clear value\n\t\tSET_DEPTH_REG = 0x04, // \n\t\tSET_STENCIL_REG = 0x08,\n\t};\n\n\tvoid GX2BlitInit();\n}\nENABLE_BITMASK_OPERATORS(GX2::GX2ClearFlags);"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Command.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/TCL/TCL.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"GX2.h\"\n#include \"GX2_Command.h\"\n#include \"GX2_Shader.h\"\n#include \"GX2_Misc.h\"\n#include \"OS/libs/coreinit/coreinit_MEM.h\"\n\nnamespace GX2\n{\n\tGX2PerCoreCBState s_perCoreCBState[Espresso::CORE_COUNT];\n}\n\nvoid gx2WriteGather_submitU32AsBE(uint32 v)\n{\n\tuint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance());\n\tif (GX2::s_perCoreCBState[coreIndex].currentWritePtr == nullptr)\n\t\treturn;\n\t*(uint32*)(GX2::s_perCoreCBState[coreIndex].currentWritePtr) = _swapEndianU32(v);\n\tGX2::s_perCoreCBState[coreIndex].currentWritePtr++;\n\tcemu_assert_debug(GX2::s_perCoreCBState[coreIndex].currentWritePtr <= (GX2::s_perCoreCBState[coreIndex].bufferPtr + GX2::s_perCoreCBState[coreIndex].bufferSizeInU32s));\n}\n\nvoid gx2WriteGather_submitU32AsLE(uint32 v)\n{\n\tuint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance());\n\tif (GX2::s_perCoreCBState[coreIndex].currentWritePtr == nullptr)\n\t\treturn;\n\t*(uint32*)(GX2::s_perCoreCBState[coreIndex].currentWritePtr) = v;\n\tGX2::s_perCoreCBState[coreIndex].currentWritePtr++;\n\tcemu_assert_debug(GX2::s_perCoreCBState[coreIndex].currentWritePtr <= (GX2::s_perCoreCBState[coreIndex].bufferPtr + GX2::s_perCoreCBState[coreIndex].bufferSizeInU32s));\n}\n\nvoid gx2WriteGather_submitU32AsLEArray(uint32* v, uint32 numValues)\n{\n\tuint32 coreIndex = PPCInterpreter_getCoreIndex(PPCInterpreter_getCurrentInstance());\n\tif (GX2::s_perCoreCBState[coreIndex].currentWritePtr == nullptr)\n\t\treturn;\n\tmemcpy_dwords(GX2::s_perCoreCBState[coreIndex].currentWritePtr, v, numValues);\n\tGX2::s_perCoreCBState[coreIndex].currentWritePtr += numValues;\n\tcemu_assert_debug(GX2::s_perCoreCBState[coreIndex].currentWritePtr <= (GX2::s_perCoreCBState[coreIndex].bufferPtr + GX2::s_perCoreCBState[coreIndex].bufferSizeInU32s));\n}\n\nnamespace GX2\n{\n\n\tstruct GX2CommandState // mapped to PPC space since the GPU writes here\n    {\n    \t// command pool\n\t\tMEMPTR<uint32be> commandPoolBase;\n    \tuint32 commandPoolSizeInU32s;\n\t\tMEMPTR<uint32be> gpuCommandReadPtr;\n\t\t// timestamp\n\t\tuint64be lastSubmissionTime;\n    };\n\n\tSysAllocator<GX2CommandState> s_commandState;\n\tGX2PerCoreCBState s_mainCoreLastCommandState;\n\tbool s_cbBufferIsInternallyAllocated;\n\n\tvoid GX2Command_StartNewCommandBuffer(uint32 numU32s);\n\n\t// called from GX2Init. Allocates a 4MB memory chunk from which command buffers are suballocated from\n\tvoid GX2Init_commandBufferPool(void* bufferBase, uint32 bufferSize)\n\t{\n\t\tcemu_assert_debug(!s_commandState->commandPoolBase); // should not be allocated already\n    \t// setup command buffer pool. If not provided allocate a 4MB or custom size buffer\n\t\tuint32 poolSize = bufferSize ? bufferSize : 0x400000; // 4MB (can be overwritten by custom GX2Init parameters?)\n\t\tif (bufferBase)\n\t\t{\n\t\t\ts_commandState->commandPoolBase = (uint32be*)bufferBase;\n\t\t\ts_cbBufferIsInternallyAllocated = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts_commandState->commandPoolBase = (uint32be*)coreinit::_weak_MEMAllocFromDefaultHeapEx(poolSize, 0x100);\n\t\t\ts_cbBufferIsInternallyAllocated = true;\n\t\t}\n\t\tif (!s_commandState->commandPoolBase)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"GX2: Failed to allocate command buffer pool\");\n\t\t}\n\t\ts_commandState->commandPoolSizeInU32s = poolSize / sizeof(uint32be);\n\t\ts_commandState->gpuCommandReadPtr = s_commandState->commandPoolBase;\n\t\t// init per-core command buffer state\n\t\tfor (uint32 i = 0; i < Espresso::CORE_COUNT; i++)\n\t\t{\n\t\t\ts_perCoreCBState[i].bufferPtr = nullptr;\n\t\t\ts_perCoreCBState[i].bufferSizeInU32s = 0;\n\t\t\ts_perCoreCBState[i].currentWritePtr = nullptr;\n\t\t}\n\t\t// start first command buffer for main core\n\t\tGX2Command_StartNewCommandBuffer(0x100);\n\t}\n\n\tvoid GX2Shutdown_commandBufferPool()\n\t{\n\t\tif (!s_commandState->commandPoolBase)\n\t\t\treturn;\n\t\tif (s_cbBufferIsInternallyAllocated)\n\t\t\tcoreinit::_weak_MEMFreeToDefaultHeap(s_commandState->commandPoolBase.GetPtr());\n\t\ts_cbBufferIsInternallyAllocated = false;\n\t\ts_commandState->commandPoolBase = nullptr;\n\t\ts_commandState->commandPoolSizeInU32s = 0;\n\t\ts_commandState->gpuCommandReadPtr = nullptr;\n\t}\n\n\t// current position of where the GPU is reading from. Updated via a memory write command submitted to the GPU\n\tuint32 GX2Command_GetPoolGPUReadIndex()\n\t{\n\t\tstdx::atomic_ref<MEMPTR<uint32be>> _readPtr(s_commandState->gpuCommandReadPtr);\n\t\tMEMPTR<uint32be> currentReadPtr = _readPtr.load();\n\t\tcemu_assert_debug(currentReadPtr);\n\t\treturn (uint32)(currentReadPtr.GetPtr() - s_commandState->commandPoolBase.GetPtr());\n\t}\n\n\tvoid GX2Command_WaitForNextBufferRetired()\n\t{\n\t\tuint64 retiredTimeStamp = GX2GetRetiredTimeStamp();\n\t\tretiredTimeStamp += 1;\n\t\t// but cant be higher than the submission timestamp\n\t\tstdx::atomic_ref<uint64be> _lastSubmissionTime(s_commandState->lastSubmissionTime);\n\t\tuint64 submissionTimeStamp = _lastSubmissionTime.load();\n\t\tif (retiredTimeStamp > submissionTimeStamp)\n\t\t\tretiredTimeStamp = submissionTimeStamp;\n\t\tGX2WaitTimeStamp(retiredTimeStamp);\n\t}\n\n\tvoid GX2Command_SetupCoreCommandBuffer(uint32be* buffer, uint32 sizeInU32s, bool isDisplayList)\n\t{\n\t\tuint32 coreIndex = coreinit::OSGetCoreId();\n\t\tauto& coreCBState = s_perCoreCBState[coreIndex];\n\t\tcoreCBState.bufferPtr = buffer;\n\t\tcoreCBState.bufferSizeInU32s = sizeInU32s;\n\t\tcoreCBState.currentWritePtr = buffer;\n\t\tcoreCBState.isDisplayList = isDisplayList;\n\t}\n\n\tvoid GX2Command_StartNewCommandBuffer(uint32 numU32s)\n\t{\n\t\t// On submission command buffers are padded to 32 byte alignment\n\t\t// but nowhere is it guaranteed that internal command buffers have their size aligned to 32 byte (even on console, but testing is required)\n\t\t// Thus the padding can write out of bounds but this seems to trigger only very rarely in partice. As a workaround we always pad the command buffer size to 32 bytes here\n\t\tnumU32s = (numU32s + 7) & ~0x7;\n\n\t\tuint32 coreIndex = coreinit::OSGetCoreId();\n\t\tauto& coreCBState = s_perCoreCBState[coreIndex];\n\t\tnumU32s = std::max<uint32>(numU32s, 0x100);\n\t\t// grab space from command buffer pool and if necessary wait for it\n\t\tuint32be* bufferPtr = nullptr;\n\t\tuint32 bufferSizeInU32s = 0;\n\t\tuint32 readIndex;\n\t\twhile (true)\n\t\t{\n\t\t\t// try to grab buffer data from first available spot:\n\t\t\t// 1. At the current write location up to the end of the buffer (avoiding an overlap with the read location)\n\t\t\t// 2. From the start of the buffer up to the read location\n\t\t\treadIndex = GX2Command_GetPoolGPUReadIndex();\n\t\t\tuint32be* nextWritePos = coreCBState.bufferPtr ? coreCBState.bufferPtr + coreCBState.bufferSizeInU32s : s_commandState->commandPoolBase.GetPtr();\n\t\t\tuint32 writeIndex = nextWritePos - s_commandState->commandPoolBase;\n\t\t\tuint32 poolSizeInU32s = s_commandState->commandPoolSizeInU32s;\n\t\t\t// readIndex == writeIndex can mean either buffer full or buffer empty\n\t\t\t// we could use GX2GetRetiredTimeStamp() == GX2GetLastSubmittedTimeStamp() to determine if the buffer is truly empty\n\t\t\t// but this can have false negatives since the last submission timestamp is updated independently of the read index\n\t\t\t// so instead we just avoid ever filling the buffer completely\n\t\t\tcemu_assert_debug(readIndex < poolSizeInU32s);\n\t\t\tcemu_assert_debug(writeIndex < poolSizeInU32s);\n\t\t\tif (writeIndex < readIndex)\n\t\t\t{\n\t\t\t\t// writeIndex has wrapped around\n\t\t\t\tuint32 wordsAvailable = readIndex - writeIndex;\n\t\t\t\tif (wordsAvailable > 0)\n\t\t\t\t\twordsAvailable--; // avoid writeIndex becoming equal to readIndex\n\t\t\t\tif (wordsAvailable >= numU32s)\n\t\t\t\t{\n\t\t\t\t\tbufferPtr = s_commandState->commandPoolBase + writeIndex;\n\t\t\t\t\tbufferSizeInU32s = wordsAvailable;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint32 wordsAvailable = poolSizeInU32s - writeIndex;\n\t\t\t\tif (wordsAvailable > 0)\n\t\t\t\t\twordsAvailable--; // avoid writeIndex becoming equal to readIndex\n\t\t\t\tif (wordsAvailable >= numU32s)\n\t\t\t\t{\n\t\t\t\t\tbufferPtr = nextWritePos;\n\t\t\t\t\tbufferSizeInU32s = wordsAvailable;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// not enough space at end of buffer, try to grab from the beginning of the buffer\n\t\t\t\twordsAvailable = readIndex;\n\t\t\t\tif (wordsAvailable > 0)\n\t\t\t\t\twordsAvailable--; // avoid writeIndex becoming equal to readIndex\n\t\t\t\tif (wordsAvailable >= numU32s)\n\t\t\t\t{\n\t\t\t\t\tbufferPtr = s_commandState->commandPoolBase;\n\t\t\t\t\tbufferSizeInU32s = wordsAvailable;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tGX2Command_WaitForNextBufferRetired();\n\t\t}\n\t\tcemu_assert_debug(bufferPtr);\n\t\tbufferSizeInU32s = std::min<uint32>(numU32s, 0x20000); // size cap\n#ifdef CEMU_DEBUG_ASSERT\n\t\tuint32 newWriteIndex = ((bufferPtr - s_commandState->commandPoolBase) + bufferSizeInU32s) % s_commandState->commandPoolSizeInU32s;\n\t\tcemu_assert_debug(newWriteIndex != readIndex);\n#endif\n\t\t// setup buffer and make it the current write gather target\n\t\tcemu_assert_debug(bufferPtr >= s_commandState->commandPoolBase && (bufferPtr + bufferSizeInU32s) <= s_commandState->commandPoolBase + s_commandState->commandPoolSizeInU32s);\n\t\tGX2Command_SetupCoreCommandBuffer(bufferPtr, bufferSizeInU32s, false);\n\t}\n\n\tvoid GX2Command_SubmitCommandBuffer(uint32be* buffer, uint32 sizeInU32s, MEMPTR<uint32be>* completionGPUReadPointer, bool triggerMarkerInterrupt)\n\t{\n\t\tuint32be cmd[10];\n\t\tuint32 cmdLen = 4;\n\t\tcmd[0] = pm4HeaderType3(IT_INDIRECT_BUFFER_PRIV, 3);\n\t\tcmd[1] = memory_virtualToPhysical(MEMPTR<void>(buffer).GetMPTR());\n\t\tcmd[2] = 0x00000000; // address high bits\n\t\tcmd[3] = sizeInU32s;\n\t\tif (completionGPUReadPointer)\n\t\t{\n\t\t\t// append command to update completionGPUReadPointer after the GPU is done with the command buffer\n\t\t\tcmd[4] = pm4HeaderType3(IT_MEM_WRITE, 4);\n\t\t\tcmd[5] = memory_virtualToPhysical(MEMPTR<void>(completionGPUReadPointer).GetMPTR()) | 2;\n\t\t\tcmd[6] = 0x40000;\n\t\t\tcmd[7] = MEMPTR<void>(buffer + sizeInU32s).GetMPTR(); // value to write\n\t\t\tcmd[8] = 0x00000000;\n\t\t\tcmdLen = 9;\n\t\t}\n\n\t\tbetype<TCL::TCLSubmissionFlag> submissionFlags{};\n\t\tif (!triggerMarkerInterrupt)\n\t\t\tsubmissionFlags |= TCL::TCLSubmissionFlag::NO_MARKER_INTERRUPT;\n\t\tsubmissionFlags |= TCL::TCLSubmissionFlag::USE_RETIRED_MARKER;\n\n\t\tTCL::TCLSubmitToRing(cmd, cmdLen, &submissionFlags, &s_commandState->lastSubmissionTime);\n\t}\n\n\tvoid GX2Command_PadCurrentBuffer()\n\t{\n\t\tuint32 coreIndex = coreinit::OSGetCoreId();\n\t\tauto& coreCBState = s_perCoreCBState[coreIndex];\n\t\tif (!coreCBState.currentWritePtr)\n\t\t\treturn;\n\t\tuint32 writeDistance = (uint32)(coreCBState.currentWritePtr - coreCBState.bufferPtr);\n\t\tif ((writeDistance&7) != 0)\n\t\t{\n\t\t\tuint32 distanceToPad = 0x8 - (writeDistance & 0x7);\n\t\t\twhile (distanceToPad)\n\t\t\t{\n\t\t\t\t*coreCBState.currentWritePtr = pm4HeaderType2Filler();\n\t\t\t\tcoreCBState.currentWritePtr++;\n\t\t\t\tdistanceToPad--;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid GX2Command_Flush(uint32 numU32sForNextBuffer, bool triggerMarkerInterrupt)\n\t{\n\t\tuint32 coreIndex = coreinit::OSGetCoreId();\n\t\tauto& coreCBState = s_perCoreCBState[coreIndex];\n\t\tif (coreCBState.isDisplayList)\n\t\t{\n\t\t\t// display list\n\t\t\tcemu_assert_debug((uint32)(coreCBState.currentWritePtr - coreCBState.bufferPtr) < coreCBState.bufferSizeInU32s);\n\t\t\tcemuLog_logDebugOnce(LogType::Force, \"GX2 flush called on display list\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// command buffer\n\t\t\tif (coreCBState.currentWritePtr != coreCBState.bufferPtr)\n\t\t\t{\n\t\t\t\t// pad the command buffer to 32 byte alignment\n\t\t\t\tGX2Command_PadCurrentBuffer();\n\t\t\t\t// submit it to the GPU\n\t\t\t\tuint32 bufferLength = (uint32)(coreCBState.currentWritePtr - coreCBState.bufferPtr);\n\t\t\t\tcemu_assert_debug(bufferLength <= coreCBState.bufferSizeInU32s);\n\t\t\t\tGX2Command_SubmitCommandBuffer(coreCBState.bufferPtr, bufferLength, &s_commandState->gpuCommandReadPtr, triggerMarkerInterrupt);\n\t\t\t\tGX2Command_StartNewCommandBuffer(numU32sForNextBuffer);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// current buffer is empty so we dont need to queue it\n\t\t\t\tif (numU32sForNextBuffer > s_commandState->commandPoolSizeInU32s)\n\t\t\t\t\tGX2Command_StartNewCommandBuffer(numU32sForNextBuffer);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid GX2Flush()\n\t{\n\t\tGX2Command_Flush(256, true);\n\t}\n\n\tuint64 GX2GetLastSubmittedTimeStamp()\n\t{\n\t\tstdx::atomic_ref<uint64be> _lastSubmissionTime(s_commandState->lastSubmissionTime);\n\t\treturn _lastSubmissionTime.load();\n\t}\n\n\tuint64 GX2GetRetiredTimeStamp()\n\t{\n\t\tuint64be ts = 0;\n\t\tTCL::TCLTimestamp(TCL::TCLTimestampId::TIMESTAMP_LAST_BUFFER_RETIRED, &ts);\n\t\treturn ts;\n\t}\n\n\tbool GX2WaitTimeStamp(uint64 tsWait)\n\t{\n\t\t// handle GPU timeout here? But for now we timeout after 60 seconds\n\t\tTCL::TCLWaitTimestamp(TCL::TCLTimestampId::TIMESTAMP_LAST_BUFFER_RETIRED, tsWait, Espresso::TIMER_CLOCK * 60);\n\t\treturn true;\n\t}\n\n\t/*\n\t * Guarantees that the requested amount of space is available on the current command buffer\n\t * If the space is not available, the current command buffer is pushed to the GPU and a new one is allocated\n\t */\n\tvoid GX2ReserveCmdSpace(uint32 reservedFreeSpaceInU32)\n\t{\n\t\tuint32 coreIndex = coreinit::OSGetCoreId();\n\t\tauto& coreCBState = s_perCoreCBState[coreIndex];\n\t\tif (coreCBState.currentWritePtr == nullptr)\n\t\t\treturn;\n\t\tuint32 writeDistance = (uint32)(coreCBState.currentWritePtr - coreCBState.bufferPtr);\n\t\tif (writeDistance + reservedFreeSpaceInU32 > coreCBState.bufferSizeInU32s)\n\t\t{\n\t\t\tGX2Command_Flush(reservedFreeSpaceInU32, true);\n\t\t}\n\t}\n\n\tvoid GX2WriteGather_beginDisplayList(PPCInterpreter_t* hCPU, MPTR buffer, uint32 maxSize)\n\t{\n\t\tuint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU);\n\t\tif (coreIndex == sGX2MainCoreIndex)\n\t\t{\n\t\t\tGX2Command_PadCurrentBuffer();\n\t\t\tcemu_assert_debug(!s_perCoreCBState[coreIndex].isDisplayList);\n\t\t\ts_mainCoreLastCommandState = s_perCoreCBState[coreIndex];\n\t\t}\n\t\tGX2Command_SetupCoreCommandBuffer(MEMPTR<uint32be>(buffer), maxSize/4, true);\n\t}\n\n\tuint32 GX2WriteGather_getDisplayListWriteDistance(sint32 coreIndex)\n\t{\n\t\tauto& coreCBState = s_perCoreCBState[coreIndex];\n\t\tcemu_assert_debug(coreCBState.isDisplayList);\n\t\tif (coreCBState.currentWritePtr == nullptr)\n\t\t\treturn 0;\n\t\treturn (uint32)(coreCBState.currentWritePtr - coreCBState.bufferPtr) * 4;\n\t}\n\n\tuint32 GX2WriteGather_endDisplayList(PPCInterpreter_t* hCPU, MPTR buffer)\n\t{\n\t\tuint32 coreIndex = coreinit::OSGetCoreId();\n\t\tauto& coreCBState = s_perCoreCBState[coreIndex];\n\t\tGX2Command_PadCurrentBuffer();\n\t\tuint32 finalWriteIndex = coreCBState.currentWritePtr - coreCBState.bufferPtr;\n\t\tcemu_assert_debug(finalWriteIndex <= coreCBState.bufferSizeInU32s);\n\t\t// if we are on the main GX2 core then restore the GPU command buffer\n\t\tif (coreIndex == sGX2MainCoreIndex)\n\t\t{\n  \t\t\tcoreCBState = s_mainCoreLastCommandState;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcoreCBState.bufferPtr = nullptr;\n\t\t\tcoreCBState.currentWritePtr = nullptr;\n\t\t\tcoreCBState.bufferSizeInU32s = 0;\n\t\t\tcoreCBState.isDisplayList = false;\n\t\t}\n\t\treturn finalWriteIndex * 4;\n\t}\n\n\tbool GX2GetCurrentDisplayList(MEMPTR<uint32be>* displayListAddr, uint32be* displayListSize)\n\t{\n\t\tuint32 coreIndex = coreinit::OSGetCoreId();\n\t\tauto& coreCBState = s_perCoreCBState[coreIndex];\n\t\tif (!coreCBState.isDisplayList)\n\t\t\treturn false;\n\t\tif (displayListAddr)\n\t\t\t*displayListAddr = coreCBState.bufferPtr;\n\t\tif (displayListSize)\n\t\t\t*displayListSize = coreCBState.bufferSizeInU32s * sizeof(uint32be);\n\t\treturn true;\n\t}\n\n\t// returns true if we are writing to a display list\n\tbool GX2GetDisplayListWriteStatus()\n\t{\n\t\tuint32 coreIndex = coreinit::OSGetCoreId();\n\t\treturn s_perCoreCBState[coreIndex].isDisplayList;\n\t}\n\n\tvoid GX2BeginDisplayList(MEMPTR<void> displayListAddr, uint32 size)\n\t{\n\t\tGX2WriteGather_beginDisplayList(PPCInterpreter_getCurrentInstance(), displayListAddr.GetMPTR(), size);\n\t}\n\n\tvoid GX2BeginDisplayListEx(MEMPTR<void> displayListAddr, uint32 size, bool profiling)\n\t{\n\t\tGX2WriteGather_beginDisplayList(PPCInterpreter_getCurrentInstance(), displayListAddr.GetMPTR(), size);\n\t}\n\n\tuint32 GX2EndDisplayList(MEMPTR<void> displayListAddr)\n\t{\n\t\tcemu_assert_debug(displayListAddr != nullptr);\n\t\tuint32 displayListSize = GX2WriteGather_endDisplayList(PPCInterpreter_getCurrentInstance(), displayListAddr.GetMPTR());\n\t\treturn displayListSize;\n\t}\n\n\tvoid GX2CallDisplayList(MPTR addr, uint32 size)\n\t{\n\t\tcemu_assert_debug((size&3) == 0);\n\t\t// write PM4 command\n\t\tGX2ReserveCmdSpace(4);\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_INDIRECT_BUFFER_PRIV, 3),\n\t\t\tmemory_virtualToPhysical(addr),\n\t\t\t0, // high address bits\n\t\t\tsize / 4);\n\t}\n\n\tvoid GX2DirectCallDisplayList(void* addr, uint32 size)\n\t{\n\t\t// this API submits to TCL directly and bypasses write-gatherer\n\t\t// its basically a way to manually submit a command buffer to the GPU\n\t\tuint32 coreIndex = coreinit::OSGetCoreId();\n\t\tif (coreIndex != sGX2MainCoreIndex)\n\t\t{\n\t\t\tcemuLog_logDebugOnce(LogType::Force, \"GX2DirectCallDisplayList() called on non-main GX2 core\");\n\t\t}\n\t\tif (!s_perCoreCBState[coreIndex].isDisplayList)\n\t\t{\n\t\t\t// make sure any preceeding commands are submitted first\n\t\t\tGX2Command_Flush(0x100, false);\n\t\t}\n\t\tGX2Command_SubmitCommandBuffer(static_cast<uint32be*>(addr), size / 4, nullptr, false);\n\t}\n\n\tvoid GX2CopyDisplayList(MEMPTR<uint32be*> addr, uint32 size)\n\t{\n\t\t// copy display list to write gather\n\t\tuint32* displayListDWords = (uint32*)addr.GetPtr();\n\t\tuint32 dwordCount = size / 4;\n\t\tif (dwordCount > 0)\n\t\t{\n\t\t\tGX2ReserveCmdSpace(dwordCount);\n\t\t\tgx2WriteGather_submitU32AsLEArray(displayListDWords, dwordCount);\n\t\t}\n\t}\n\n\tenum class GX2_PATCH_TYPE : uint32\n\t{\n\t\tFETCH_SHADER\t\t\t= 1,\n\t\tVERTEX_SHADER\t\t\t= 2,\n\t\tGEOMETRY_COPY_SHADER\t= 3,\n\t\tGEOMETRY_SHADER\t\t\t= 4,\n\t\tPIXEL_SHADER\t\t\t= 5,\n\t\tCOMPUTE_SHADER\t\t\t= 6\n\t};\n\n\tvoid GX2PatchDisplayList(uint32be* displayData, GX2_PATCH_TYPE patchType, uint32 patchOffset, void* obj)\n\t{\n\t\tcemu_assert_debug((patchOffset & 3) == 0);\n\n\t\tif (patchType == GX2_PATCH_TYPE::VERTEX_SHADER)\n\t\t{\n\t\t\tGX2VertexShader* vertexShader = (GX2VertexShader*)obj;\n\t\t\tdisplayData[patchOffset / 4 + 2] = memory_virtualToPhysical(vertexShader->GetProgramAddr()) >> 8;\n\t\t}\n\t\telse if (patchType == GX2_PATCH_TYPE::PIXEL_SHADER)\n\t\t{\n\t\t\tGX2PixelShader_t* pixelShader = (GX2PixelShader_t*)obj;\n\t\t\tdisplayData[patchOffset / 4 + 2] = memory_virtualToPhysical(pixelShader->GetProgramAddr()) >> 8;\n\t\t}\n\t\telse if (patchType == GX2_PATCH_TYPE::FETCH_SHADER)\n\t\t{\n\t\t\tGX2FetchShader* fetchShader = (GX2FetchShader*)obj;\n\t\t\tdisplayData[patchOffset / 4 + 2] = memory_virtualToPhysical(fetchShader->GetProgramAddr()) >> 8;\n\t\t}\n\t\telse if (patchType == GX2_PATCH_TYPE::GEOMETRY_COPY_SHADER)\n\t\t{\n\t\t\tGX2GeometryShader_t* geometryShader = (GX2GeometryShader_t*)obj;\n\t\t\tdisplayData[patchOffset / 4 + 2] = memory_virtualToPhysical(geometryShader->GetCopyProgramAddr()) >> 8;\n\t\t}\n\t\telse if (patchType == GX2_PATCH_TYPE::GEOMETRY_SHADER)\n\t\t{\n\t\t\tGX2GeometryShader_t* geometryShader = (GX2GeometryShader_t*)obj;\n\t\t\tdisplayData[patchOffset / 4 + 2] = memory_virtualToPhysical(geometryShader->GetGeometryProgramAddr()) >> 8;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"GX2PatchDisplayList(): unsupported patchType {}\", (uint32)patchType);\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\n\tvoid GX2CommandInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2Flush, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2GetLastSubmittedTimeStamp, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetRetiredTimeStamp, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2WaitTimeStamp, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2BeginDisplayList, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2BeginDisplayListEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2EndDisplayList, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2GetCurrentDisplayList, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetDisplayListWriteStatus, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2CallDisplayList, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2DirectCallDisplayList, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2CopyDisplayList, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2PatchDisplayList, LogType::GX2);\n\t}\n\n    void GX2CommandResetToDefaultState()\n    {\n\t\ts_commandState->commandPoolBase = nullptr;\n\t\ts_commandState->commandPoolSizeInU32s = 0;\n\t\ts_commandState->gpuCommandReadPtr = nullptr;\n\t\ts_cbBufferIsInternallyAllocated = false;\n    }\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Command.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Espresso/Const.h\"\n\nnamespace GX2\n{\n\tstruct GX2PerCoreCBState\n\t{\n\t\tuint32be* bufferPtr;\n\t\tuint32 bufferSizeInU32s;\n\t\tuint32be* currentWritePtr;\n\t\tbool isDisplayList;\n\t};\n\n\textern GX2PerCoreCBState s_perCoreCBState[Espresso::CORE_COUNT];\n};\n\nvoid gx2WriteGather_submitU32AsBE(uint32 v);\nvoid gx2WriteGather_submitU32AsLE(uint32 v);\nvoid gx2WriteGather_submitU32AsLEArray(uint32* v, uint32 numValues);\n\nuint32 PPCInterpreter_getCurrentCoreIndex();\n\n// gx2WriteGather_submit functions\ntemplate <typename ...Targs>\ninline void gx2WriteGather_submit_(uint32 coreIndex, uint32be* writePtr)\n{\n\tGX2::s_perCoreCBState[coreIndex].currentWritePtr = writePtr;\n\tcemu_assert_debug(GX2::s_perCoreCBState[coreIndex].currentWritePtr <= (GX2::s_perCoreCBState[coreIndex].bufferPtr + GX2::s_perCoreCBState[coreIndex].bufferSizeInU32s));\n}\n\ntemplate <typename T, typename ...Targs>\ninline void gx2WriteGather_submit_(uint32 coreIndex, uint32be* writePtr, const betype<T>& arg, Targs... args)\n{\n\tstatic_assert(sizeof(betype<T>) == sizeof(uint32be));\n\t*(betype<T>*)writePtr = arg;\n\twritePtr++;\n\tgx2WriteGather_submit_(coreIndex, writePtr, args...);\n}\n\ntemplate <typename T, typename ...Targs>\n\trequires std::is_floating_point_v<T>\ninline\nvoid gx2WriteGather_submit_(uint32 coreIndex, uint32be* writePtr, const T& arg, Targs... args)\n{\n\tstatic_assert(sizeof(T) == sizeof(uint32));\n\t*writePtr = *(uint32*)&arg;\n\twritePtr++;\n\tgx2WriteGather_submit_(coreIndex, writePtr, args...);\n}\n\ntemplate <typename T, typename ...Targs>\n\trequires std::is_base_of_v<Latte::LATTEREG, T>\ninline\nvoid gx2WriteGather_submit_(uint32 coreIndex, uint32be* writePtr, const T& arg, Targs... args)\n{\n\tstatic_assert(sizeof(Latte::LATTEREG) == sizeof(uint32be));\n\t*writePtr = arg.getRawValue();\n\twritePtr++;\n\tgx2WriteGather_submit_(coreIndex, writePtr, args...);\n}\n\ntemplate <typename T, typename ...Targs>\n\trequires (!std::is_base_of_v<Latte::LATTEREG, T>) && (!std::is_floating_point_v<T>)\ninline\nvoid gx2WriteGather_submit_(uint32 coreIndex, uint32be* writePtr, const T& arg, Targs... args)\n{\n\t*writePtr = arg;\n\twritePtr++;\n\tgx2WriteGather_submit_(coreIndex, writePtr, args...);\n}\n\ntemplate <typename ...Targs>\ninline void gx2WriteGather_submit(Targs... args)\n{\n\tuint32 coreIndex = PPCInterpreter_getCurrentCoreIndex();\n\tif (GX2::s_perCoreCBState[coreIndex].currentWritePtr == nullptr)\n\t{\n\t\tcemu_assert_suspicious(); // writing to command buffer without valid write pointer?\n\t\treturn;\n\t}\n\tuint32be* writePtr = GX2::s_perCoreCBState[coreIndex].currentWritePtr;\n\tgx2WriteGather_submit_(coreIndex, writePtr, std::forward<Targs>(args)...);\n}\n\nnamespace GX2\n{\n\tvoid GX2Command_Flush(uint32 numU32sForNextBuffer, bool triggerMarkerInterrupt = true);\n\tvoid GX2ReserveCmdSpace(uint32 reservedFreeSpaceInU32);\n\n\tuint64 GX2GetLastSubmittedTimeStamp();\n\tuint64 GX2GetRetiredTimeStamp();\n\tbool GX2WaitTimeStamp(uint64 tsWait);\n\n\tvoid GX2BeginDisplayList(MEMPTR<void> displayListAddr, uint32 size);\n\tvoid GX2BeginDisplayListEx(MEMPTR<void> displayListAddr, uint32 size, bool profiling);\n\tuint32 GX2EndDisplayList(MEMPTR<void> displayListAddr);\n\n\tvoid GX2CallDisplayList(MPTR addr, uint32 size);\n\tvoid GX2DirectCallDisplayList(void* addr, uint32 size);\n\n\tbool GX2GetDisplayListWriteStatus();\n\n    void GX2CommandInit();\n\tvoid GX2Init_commandBufferPool(void* bufferBase, uint32 bufferSize);\n\tvoid GX2Shutdown_commandBufferPool();\n    void GX2CommandResetToDefaultState();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_ContextState.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"GX2.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n\n#include \"GX2_Command.h\"\n#include \"GX2_State.h\"\n#include \"Cafe/CafeSystem.h\"\n\n#define GPU7_REG_AREA_SIZE_CONFIG_REG\t0xB00\n#define GPU7_REG_AREA_SIZE_CONTEXT_REG\t0x400\n#define GPU7_REG_AREA_SIZE_ALU_CONST\t0x800\n#define GPU7_REG_AREA_SIZE_LOOP_CONST\t0x60\n#define GPU7_REG_AREA_SIZE_RESOURCE\t\t0xD9E\n#define GPU7_REG_AREA_SIZE_SAMPLER\t\t0xA2 // (guessed)\n\n#define _GX2_CALC_SHADOWMEM_NUM_U32(__v) (((((__v)*4)+0xFF)&~0xFF)/4)\n\nMPTR gx2CurrentContextStateMPTR = MPTR_NULL;\n\ntypedef struct  \n{\n\tuint32 regOffset;\n\tuint32 regCount;\n}GX2RegLoadPktEntry_t;\n\nGX2RegLoadPktEntry_t aluConst_loadPktEntries[1] = // base: 0xC000\n{\n\t{0, 0x800},\n};\n\nGX2RegLoadPktEntry_t loopConst_loadPktEntries[1] = // base: 0xF880\n{\n\t{0, 0x60},\n};\n\nGX2RegLoadPktEntry_t samplerReg_loadPktEntries[3] = // base: 0xF000\n{\n\t{0, 0x36},\n\t{0x36, 0x36},\n\t{0x6C, 0x36},\n};\n\nGX2RegLoadPktEntry_t configReg_loadPktEntries[0xF] = // base: 0x2000\n{\n\t{0x300, 0x6},\n\t{0x900, 0x48},\n\t{0x980, 0x48},\n\t{0xA00, 0x48},\n\t{0x310, 0xC},\n\t{0x542, 0x1},\n\t{0x235, 0x1},\n\t{0x232, 0x2},\n\t{0x23A, 0x1},\n\t{0x256, 0x1},\n\t{0x60C, 0x1},\n\t{0x5C5, 0x1},\n\t{0x2C8, 0x1},\n\t{0x363, 0x1},\n\t{0x404, 0x2}\n};\n\nGX2RegLoadPktEntry_t contextReg_loadPktEntries[0x2D] = // base: 0xA000\n{\n\t{0x0, 0x2},\n\t{0x3, 0x3},\n\t{0xA, 0x4},\n\t{0x10, 0x38},\n\t{0x50, 0x34},\n\t{0x8E, 0x4},\n\t{0x94, 0x40},\n\t{0x100, 0x9},\n\t{0x10C, 0x3},\n\t{0x10F, 0x60},\n\t{0x185, 0xA},\n\t{0x191, 0x27},\n\t{0x1E0, 0x9},\n\t{0x200, 0x1},\n\t{0x202, 0x7},\n\t{0xE0, 0x20},\n\t{0x210, 0x29},\n\t{0x250, 0x34},\n\t{0x290, 0x1},\n\t{0x292, 0x2},\n\t{0x2A1, 0x1},\n\t{0x2A5, 0x1},\n\t{0x2A8, 0x2},\n\t{0x2AC, 0x3},\n\t{0x2CA, 0x1},\n\t{0x2CC, 0x1},\n\t{0x2CE, 0x1},\n\t{0x300, 0x9},\n\t{0x30C, 0x1},\n\t{0x312, 0x1},\n\t{0x316, 0x2},\n\t{0x343, 0x2},\n\t{0x349, 0x3},\n\t{0x34C, 0x2},\n\t{0x351, 0x1},\n\t{0x37E, 0x6},\n\t{0x2B4, 0x3},\n\t{0x2B8, 0x3},\n\t{0x2BC, 0x3},\n\t{0x2C0, 0x3},\n\t{0x2C8, 0x1},\n\t{0x29B, 0x1},\n\t{0x8C, 0x1},\n\t{0xD5, 0x1},\n\t{0x284, 0xC}\n};\n\nGX2RegLoadPktEntry_t resourceReg_loadPktEntries[9] = // base: 0xE000\n{\n\t{0, 0x70},\t// ps tex\n\t{0x380, 0x70},\n\t{0x460, 0x70}, // vs tex\n\t{0x7E0, 0x70},\n\t{0x8B9, 0x7},\n\t{0x8C0, 0x70},\n\t{0x930, 0x70}, // gs tex\n\t{0xCB0, 0x70},\n\t{0xD89, 0x7}\n};\n\ntypedef struct  \n{\n\t// Hardware view of context state (register areas)\n\tuint32 areaConfigReg[_GX2_CALC_SHADOWMEM_NUM_U32(GPU7_REG_AREA_SIZE_CONFIG_REG)];\n\tuint32 areaContextReg[_GX2_CALC_SHADOWMEM_NUM_U32(GPU7_REG_AREA_SIZE_CONTEXT_REG)];\n\tuint32 areaALUConst[_GX2_CALC_SHADOWMEM_NUM_U32(GPU7_REG_AREA_SIZE_ALU_CONST)];\n\tuint32 areaLoopConst[_GX2_CALC_SHADOWMEM_NUM_U32(GPU7_REG_AREA_SIZE_LOOP_CONST)];\n\tuint32 areaResource[_GX2_CALC_SHADOWMEM_NUM_U32(GPU7_REG_AREA_SIZE_RESOURCE)];\n\tuint32 areaSampler[_GX2_CALC_SHADOWMEM_NUM_U32(GPU7_REG_AREA_SIZE_SAMPLER)];\n}GX2HwContextState_t;\n\ntypedef struct  \n{\n\tGX2HwContextState_t hwContext;\n\tuint32 enableProfling;\n\t/* + 0x9804 */ uint32be loadDL_size;\n\tuint8 ukn9808[0x3FC-4];\n\tuint8 ukn9C00[0x200];\n\t/* +0x9E00 */ uint8 loadDL_buffer[0x300]; // this displaylist caches the IT_LOAD_* commands for swapping out context\n}GX2ContextState_t;\n\nstatic_assert(offsetof(GX2ContextState_t, loadDL_size) == 0x9804);\nstatic_assert(sizeof(GX2ContextState_t) == 0xA100);\n\nuint32 _GX2Context_CalcShadowMemSize(uint32 regCount)\n{\n\treturn (regCount*4+0xFF)&~0xFF;\n}\n\nuint32 _GX2Context_CalcStateSize()\n{\n\tuint32 contextStateSize = 0;\n\tcontextStateSize += _GX2Context_CalcShadowMemSize(GPU7_REG_AREA_SIZE_CONFIG_REG);\n\tcontextStateSize += _GX2Context_CalcShadowMemSize(GPU7_REG_AREA_SIZE_CONTEXT_REG);\n\tcontextStateSize += _GX2Context_CalcShadowMemSize(GPU7_REG_AREA_SIZE_ALU_CONST);\n\tcontextStateSize += _GX2Context_CalcShadowMemSize(GPU7_REG_AREA_SIZE_LOOP_CONST);\n\tcontextStateSize += _GX2Context_CalcShadowMemSize(GPU7_REG_AREA_SIZE_RESOURCE);\n\tcontextStateSize += _GX2Context_CalcShadowMemSize(GPU7_REG_AREA_SIZE_SAMPLER);\n\treturn contextStateSize;\n}\n\nvoid _GX2Context_CreateLoadDL()\n{\n\tGX2::GX2ReserveCmdSpace(3);\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_CONTEXT_CONTROL, 2));\n\tgx2WriteGather_submitU32AsBE(0x80000077);\n\tgx2WriteGather_submitU32AsBE(0x80000077);\n}\n\nvoid _GX2Context_WriteCmdDisableStateShadowing()\n{\n\tGX2::GX2ReserveCmdSpace(3);\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_CONTEXT_CONTROL, 2));\n\tgx2WriteGather_submitU32AsBE(0x80000000);\n\tgx2WriteGather_submitU32AsBE(0x80000000);\n}\n\nvoid _GX2Context_cmdLoad(void* gx2ukn, uint32 pm4Header, MPTR physAddrRegArea, uint32 waitForIdle, uint32 numRegOffsetEntries, GX2RegLoadPktEntry_t* regOffsetEntries)\n{\n\tGX2::GX2ReserveCmdSpace(3 + numRegOffsetEntries*2);\n\tgx2WriteGather_submitU32AsBE(pm4Header);\n\tgx2WriteGather_submitU32AsBE(physAddrRegArea);\n\tgx2WriteGather_submitU32AsBE(waitForIdle);\n\tfor(uint32 i=0; i<numRegOffsetEntries; i++)\n\t{\n\t\tgx2WriteGather_submitU32AsBE(regOffsetEntries[i].regOffset); // regOffset\n\t\tgx2WriteGather_submitU32AsBE(regOffsetEntries[i].regCount); // regCount\n\t}\n}\n\n#define __cmdStateLoad(__gx2State, __pm4Command, __regArea, __waitForIdle, __regLoadPktEntries) _GX2Context_cmdLoad(NULL, pm4HeaderType3(__pm4Command, 2+sizeof(__regLoadPktEntries)/sizeof(__regLoadPktEntries[0])*2), memory_virtualToPhysical(memory_getVirtualOffsetFromPointer(__regArea)), __waitForIdle, sizeof(__regLoadPktEntries)/sizeof(__regLoadPktEntries[0]), __regLoadPktEntries)\n\nvoid _GX2Context_WriteCmdRestoreState(GX2ContextState_t* gx2ContextState, uint32 ukn)\n{\n\tMPTR physAddrContextState = memory_virtualToPhysical(memory_getVirtualOffsetFromPointer(gx2ContextState));\n\t_GX2Context_CreateLoadDL();\n\t__cmdStateLoad(NULL, IT_LOAD_CONFIG_REG, gx2ContextState->hwContext.areaConfigReg, 0x80000000, configReg_loadPktEntries);\n\t__cmdStateLoad(NULL, IT_LOAD_CONTEXT_REG, gx2ContextState->hwContext.areaContextReg, 0, contextReg_loadPktEntries);\n\t__cmdStateLoad(NULL, IT_LOAD_ALU_CONST, gx2ContextState->hwContext.areaALUConst, 0, aluConst_loadPktEntries);\n\t__cmdStateLoad(NULL, IT_LOAD_LOOP_CONST, gx2ContextState->hwContext.areaLoopConst, 0, loopConst_loadPktEntries);\n\t__cmdStateLoad(NULL, IT_LOAD_RESOURCE, gx2ContextState->hwContext.areaResource, 0, resourceReg_loadPktEntries);\n\t__cmdStateLoad(NULL, IT_LOAD_SAMPLER, gx2ContextState->hwContext.areaSampler, 0, samplerReg_loadPktEntries);\n}\n\nvoid GX2SetDefaultState()\n{\n\tGX2::GX2ReserveCmdSpace(0x100);\n\n\tLatte::LATTE_PA_CL_VTE_CNTL reg{};\n\treg.set_VPORT_X_OFFSET_ENA(true).set_VPORT_X_SCALE_ENA(true);\n\treg.set_VPORT_Y_OFFSET_ENA(true).set_VPORT_Y_SCALE_ENA(true);\n\treg.set_VPORT_Z_OFFSET_ENA(true).set_VPORT_Z_SCALE_ENA(true);\n\treg.set_VTX_W0_FMT(true);\n\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\tLatte::REGADDR::PA_CL_VTE_CNTL - 0xA000,\n\t\treg);\n\n\tuint32 stencilTestEnable = GX2_FALSE;\n\tuint32 backStencilEnable = GX2_FALSE;\n\tuint32 frontStencilFunc = 0;\n\tuint32 frontStencilZPass = 0;\n\tuint32 frontStencilZFail = 0;\n\tuint32 frontStencilFail = 0; \n\tuint32 backStencilFunc = 0;\n\tuint32 backStencilZPass = 0;\n\tuint32 backStencilZFail = 0;\n\tuint32 backStencilFail = 0;\n\n\tuint32 depthControlReg = 0;\n\t// depth stuff\n\tdepthControlReg |= (1<<1);\n\tdepthControlReg |= (1<<2);\n\tdepthControlReg |= ((1&7)<<4);\n\t// stencil stuff\n\tdepthControlReg |= ((stencilTestEnable&1)<<0);\n\tdepthControlReg |= ((backStencilEnable&1)<<7);\n\tdepthControlReg |= ((frontStencilFunc&7)<<8);\n\tdepthControlReg |= ((frontStencilZPass&7)<<14);\n\tdepthControlReg |= ((frontStencilZFail&7)<<17);\n\tdepthControlReg |= ((frontStencilFail&7)<<11);\n\tdepthControlReg |= ((backStencilFunc&7)<<20);\n\tdepthControlReg |= ((backStencilZPass&7)<<26);\n\tdepthControlReg |= ((backStencilZFail&3)<<29);\n\tdepthControlReg |= ((backStencilFail&7)<<23);\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1+1));\n\tgx2WriteGather_submitU32AsBE(Latte::REGADDR::DB_DEPTH_CONTROL-0xA000);\n\tgx2WriteGather_submitU32AsBE(depthControlReg);\n\n\tGX2::GX2SetAlphaTest(GX2_DISABLE, GX2::GX2_ALPHAFUNC::LESS, 0.0f);\n\tGX2::GX2SetPolygonControl(Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE::CCW, GX2_DISABLE, GX2_DISABLE, Latte::LATTE_PA_SU_SC_MODE_CNTL::E_POLYGONMODE::UKN0, Latte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE::TRIANGLES, Latte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE::TRIANGLES, GX2_DISABLE, GX2_DISABLE, GX2_DISABLE);\n\tGX2::GX2SetPolygonOffset(0.0f, 0.0f, 0.0f, 0.0f, 0.0f);\n\tGX2::GX2SetPrimitiveRestartIndex(0xffffffff);\n\tGX2::GX2SetTargetChannelMasks(0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF);\n\tGX2::GX2SetBlendConstantColor(0.0f, 0.0f, 0.0f, 0.0f);\n\tGX2::GX2SetPointSize(1.0f, 1.0f);\n\tGX2::GX2SetPointLimits(1.0f, 1.0f);\n\tGX2::GX2SetColorControl(GX2::GX2_LOGICOP::COPY, GX2_DISABLE, GX2_DISABLE, GX2_ENABLE);\n\tGX2::GX2SetRasterizerClipControlEx(true, true, false);\n\n\t// Set clear depth to 1.0 (workaround for Darksiders 2. Investigate whether actual GX2 driver also sets this)\n\tfloat depth = 1.0;\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1+1));\n\tgx2WriteGather_submitU32AsBE(mmDB_DEPTH_CLEAR - 0xA000);\n\tgx2WriteGather_submitU32AsBE(*(uint32*)&depth); // depth (as float)\n\n\t// reset HLE special states\n\tfor (sint32 i = 0; i <= GX2_SPECIAL_STATE_COUNT; i++)\n\t{\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_SPECIAL_STATE, 2));\n\t\tgx2WriteGather_submitU32AsBE(i); // state id\n\t\tgx2WriteGather_submitU32AsBE(0); // disable\n\t}\n}\n\nvoid gx2Export_GX2SetDefaultState(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetDefaultState()\");\n\tGX2SetDefaultState();\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid _GX2ContextCreateRestoreStateDL(GX2ContextState_t* gx2ContextState)\n{\n\t// begin display list\n\tcemu_assert_debug(!GX2::GX2GetDisplayListWriteStatus()); // must not already be writing to a display list\n\tGX2::GX2BeginDisplayList((void*)gx2ContextState->loadDL_buffer, sizeof(gx2ContextState->loadDL_buffer));\n\t_GX2Context_WriteCmdRestoreState(gx2ContextState, 0);\n\tuint32 displayListSize = GX2::GX2EndDisplayList((void*)gx2ContextState->loadDL_buffer);\n\tgx2ContextState->loadDL_size = displayListSize;\n}\n\nvoid gx2Export_GX2SetupContextStateEx(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetupContextStateEx(0x{:08x})\", hCPU->gpr[3]);\n\tcemu_assert_debug(hCPU->gpr[4] == 0 || hCPU->gpr[4] == 1);\n\n\tGX2ContextState_t* gx2ContextState = (GX2ContextState_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\n\tuint32 hwContextSize = _GX2Context_CalcStateSize();\n\tif( hwContextSize != sizeof(GX2HwContextState_t) )\n\t\tassert_dbg();\n\tif( sizeof(GX2HwContextState_t) != 0x9800 )\n\t\tassert_dbg(); // GX2 HW context size mismatch\n\tif( sizeof(GX2ContextState_t) != 0xA100 )\n\t\tassert_dbg(); // GX2 context size mismatch\n\n\tmemset(gx2ContextState, 0x00, sizeof(GX2ContextState_t));\n\tgx2ContextState->enableProfling = _swapEndianU32(hCPU->gpr[4]&1);\n\t_GX2Context_WriteCmdRestoreState(gx2ContextState, 1);\n\n\tgx2CurrentContextStateMPTR = hCPU->gpr[3];\n\n\t_GX2Context_CreateLoadDL();\n\tGX2SetDefaultState();\n\t_GX2ContextCreateRestoreStateDL(gx2ContextState);\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SetContextState(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetContextState(0x{:08x})\", hCPU->gpr[3]);\n\t// parameters:\n\tif( hCPU->gpr[3] == MPTR_NULL )\n\t{\n\t\t// disable state shadowing\n\t\t_GX2Context_WriteCmdDisableStateShadowing();\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\t// check if context state changed\n\tbool boiWorkaround = CafeSystem::GetRPXHashBase() == 0x6BCD618E; // workaround for a bug in Binding of Isaac to avoid flicker\n\tif( boiWorkaround )\n\t{\n\t\tif( hCPU->gpr[3] != gx2CurrentContextStateMPTR ) // dont reload same state\n\t\t{\n\t\t\tGX2ContextState_t* gx2ContextState = (GX2ContextState_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\t\t_GX2Context_WriteCmdRestoreState(gx2ContextState, 0);\n\t\t\t_GX2Context_CreateLoadDL();\n\t\t\t// set new context state\n\t\t\tgx2CurrentContextStateMPTR = hCPU->gpr[3];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// even if it's the same context, make sure state shadowing is enabled.\n\t\t\t_GX2Context_CreateLoadDL();\n\t\t}\n\t}\n\telse\n\t{\n\t\tGX2ContextState_t* gx2ContextState = (GX2ContextState_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t\tif (gx2ContextState->loadDL_size == 0)\n\t\t{\n\t\t\t_GX2Context_CreateLoadDL();\n\t\t\t_GX2Context_WriteCmdRestoreState(gx2ContextState, 0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_GX2Context_CreateLoadDL();\n\t\t\tGX2::GX2CallDisplayList(memory_getVirtualOffsetFromPointer(gx2ContextState->loadDL_buffer), gx2ContextState->loadDL_size);\n\t\t}\n\t\t// set new context state\n\t\tgx2CurrentContextStateMPTR = hCPU->gpr[3];\n\n\t}\n\t// todo: Save/restore GX2 special state as well -> handle this by correctly emulating the state\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2GetContextStateDisplayList(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2GetContextStateDisplayList(0x{:08x}, 0x{:08x}, 0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\tppcDefineParamStructPtr(gx2ContextState, GX2ContextState_t, 0);\n\tppcDefineParamU32BEPtr(displayListPtrOut, 1);\n\tppcDefineParamU32BEPtr(displayListSizeOut, 2);\n\n\t*displayListPtrOut = memory_getVirtualOffsetFromPointer(gx2ContextState->loadDL_buffer);\n\t*displayListSizeOut = gx2ContextState->loadDL_size;\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Draw.cpp",
    "content": "#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"GX2.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n\n#include \"Cafe/OS/common/OSCommon.h\"\n\n#include \"GX2_Command.h\"\n#include \"GX2_Draw.h\"\n\nnamespace GX2\n{\n\tvoid GX2SetAttribBuffer(uint32 bufferIndex, uint32 sizeInBytes, uint32 stride, void* data)\n\t{\n\t\tGX2ReserveCmdSpace(9);\n\t\tMPTR physicalAddress = memory_virtualToPhysical(memory_getVirtualOffsetFromPointer(data));\n\t\t// write PM4 command\n\t\tgx2WriteGather_submit(\n\t\t\tpm4HeaderType3(IT_SET_RESOURCE, 8),\n\t\t\t0x8C0 + bufferIndex * 7,\n\t\t\tphysicalAddress,\n\t\t\tsizeInBytes - 1, // size\n\t\t\t(stride & 0xFFFF) << 11, // stride\n\t\t\t0, // ukn\n\t\t\t0, // ukn\n\t\t\t0, // ukn\n\t\t\t0xC0000000); // ukn\n\t}\n\n\tvoid GX2DrawIndexedEx(GX2PrimitiveMode2 primitiveMode, uint32 count, GX2IndexType indexType, void* indexData, uint32 baseVertex, uint32 numInstances)\n\t{\n\t\tGX2ReserveCmdSpace(3 + 3 + 2 + 2 + 6);\n\t\tgx2WriteGather_submit(\n\t\t\t// IT_SET_CTL_CONST\n\t\t\tpm4HeaderType3(IT_SET_CTL_CONST, 2), 0,\n\t\t\tbaseVertex,\n\t\t\t// IT_SET_CONFIG_REG\n\t\t\tpm4HeaderType3(IT_SET_CONFIG_REG, 2), Latte::REGADDR::VGT_PRIMITIVE_TYPE - 0x2000,\n\t\t\t(uint32)primitiveMode,\n\t\t\t// IT_INDEX_TYPE\n\t\t\tpm4HeaderType3(IT_INDEX_TYPE, 1),\n\t\t\t(uint32)indexType,\n\t\t\t// IT_NUM_INSTANCES\n\t\t\tpm4HeaderType3(IT_NUM_INSTANCES, 1),\n\t\t\tnumInstances,\n\t\t\t// IT_DRAW_INDEX_2\n\t\t\tpm4HeaderType3(IT_DRAW_INDEX_2, 5) | 0x00000001,\n\t\t\t-1,\n\t\t\tmemory_virtualToPhysical(memory_getVirtualOffsetFromPointer(indexData)),\n\t\t\t0,\n\t\t\tcount,\n\t\t\t0);\n\t}\n\n\tvoid GX2DrawIndexedEx2(GX2PrimitiveMode2 primitiveMode, uint32 count, GX2IndexType indexType, void* indexData, uint32 baseVertex, uint32 numInstances, uint32 baseInstance)\n\t{\n\t\tGX2ReserveCmdSpace(3 + 3 + 2 + 2 + 6);\n\t\tgx2WriteGather_submit(\n\t\t\t// IT_SET_CTL_CONST\n\t\t\tpm4HeaderType3(IT_SET_CTL_CONST, 2), 0,\n\t\t\tbaseVertex,\n\t\t\t// set base instance\n\t\t\tpm4HeaderType3(IT_SET_CTL_CONST, 2), 1,\n\t\t\tbaseInstance,\n\t\t\t// IT_SET_CONFIG_REG\n\t\t\tpm4HeaderType3(IT_SET_CONFIG_REG, 2), Latte::REGADDR::VGT_PRIMITIVE_TYPE - 0x2000,\n\t\t\t(uint32)primitiveMode,\n\t\t\t// IT_INDEX_TYPE\n\t\t\tpm4HeaderType3(IT_INDEX_TYPE, 1),\n\t\t\t(uint32)indexType,\n\t\t\t// IT_NUM_INSTANCES\n\t\t\tpm4HeaderType3(IT_NUM_INSTANCES, 1),\n\t\t\tnumInstances,\n\t\t\t// IT_DRAW_INDEX_2\n\t\t\tpm4HeaderType3(IT_DRAW_INDEX_2, 5) | 0x00000001,\n\t\t\t-1,\n\t\t\tmemory_virtualToPhysical(memory_getVirtualOffsetFromPointer(indexData)),\n\t\t\t0,\n\t\t\tcount,\n\t\t\t0,\n\t\t\t// reset base instance\n\t\t\tpm4HeaderType3(IT_SET_CTL_CONST, 2), 1,\n\t\t\t0 // baseInstance\n\t\t);\n\t}\n\n\tvoid GX2DrawEx(GX2PrimitiveMode2 primitiveMode, uint32 count, uint32 baseVertex, uint32 numInstances)\n\t{\n\t\tGX2ReserveCmdSpace(3 + 3 + 2 + 2 + 6);\n\t\tgx2WriteGather_submit(\n\t\t\t// IT_SET_CTL_CONST\n\t\t\tpm4HeaderType3(IT_SET_CTL_CONST, 2), 0,\n\t\t\tbaseVertex,\n\t\t\t// IT_SET_CONFIG_REG\n\t\t\tpm4HeaderType3(IT_SET_CONFIG_REG, 2), Latte::REGADDR::VGT_PRIMITIVE_TYPE - 0x2000,\n\t\t\t(uint32)primitiveMode,\n\t\t\t// IT_INDEX_TYPE\n\t\t\tpm4HeaderType3(IT_INDEX_TYPE, 1),\n\t\t\t(uint32)GX2IndexType::U32_BE,\n\t\t\t// IT_NUM_INSTANCES\n\t\t\tpm4HeaderType3(IT_NUM_INSTANCES, 1),\n\t\t\tnumInstances,\n\t\t\t// IT_DRAW_INDEX_2\n\t\t\tpm4HeaderType3(IT_DRAW_INDEX_AUTO, 2) | 0x00000001,\n\t\t\tcount,\n\t\t\t0 // DRAW_INITIATOR\n\t\t);\n\t}\n\n\tvoid GX2DrawIndexedImmediateEx(GX2PrimitiveMode2 primitiveMode, uint32 count, GX2IndexType indexType, void* indexData, uint32 baseVertex, uint32 numInstances)\n\t{\n\t\tuint32* indexDataU32 = (uint32*)indexData;\n\t\tuint32 numIndexU32s;\n\t\tbool use32BitIndices = false;\n\t\tif (indexType == GX2IndexType::U16_BE || indexType == GX2IndexType::U16_LE)\n\t\t{\n\t\t\t// 16bit indices\n\t\t\tnumIndexU32s = (count + 1) / 2;\n\t\t}\n\t\telse if (indexType == GX2IndexType::U32_BE || indexType == GX2IndexType::U32_LE)\n\t\t{\n\t\t\t// 32bit indices\n\t\t\tnumIndexU32s = count;\n\t\t\tuse32BitIndices = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\tGX2ReserveCmdSpace(3 + 3 + 3 + 2 + 2 + 6 + 3 + numIndexU32s);\n\n\t\tif (numIndexU32s > 0x4000 - 2)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"GX2DrawIndexedImmediateEx(): Draw exceeds maximum PM4 command size. Keep index size below 16KiB minus 8 byte\");\n\t\t\treturn;\n\t\t}\n\n\t\t// set base vertex\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CTL_CONST, 2));\n\t\tgx2WriteGather_submitU32AsBE(0);\n\t\tgx2WriteGather_submitU32AsBE(baseVertex);\n\t\t// set primitive mode\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONFIG_REG, 2));\n\t\tgx2WriteGather_submitU32AsBE(Latte::REGADDR::VGT_PRIMITIVE_TYPE - 0x2000);\n\t\tgx2WriteGather_submitU32AsBE((uint32)primitiveMode);\n\t\t// set index type\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_INDEX_TYPE, 1));\n\t\tgx2WriteGather_submitU32AsBE((uint32)indexType);\n\t\t// set number of instances\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_NUM_INSTANCES, 1));\n\t\tgx2WriteGather_submitU32AsBE((uint32)numInstances);\n\t\t// request indexed draw with indices embedded into command buffer\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_DRAW_INDEX_IMMD, 2 + numIndexU32s) | 0x00000001);\n\t\tgx2WriteGather_submitU32AsBE(count);\n\t\tgx2WriteGather_submitU32AsBE(0); // ukn\n\t\tif (use32BitIndices)\n\t\t{\n\t\t\tfor (uint32 i = 0; i < numIndexU32s; i++)\n\t\t\t{\n\t\t\t\tgx2WriteGather_submitU32AsLE(indexDataU32[i]);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (uint32 i = 0; i < numIndexU32s; i++)\n\t\t\t{\n\t\t\t\tuint32 indexPair = indexDataU32[i];\n\t\t\t\t// swap index pair\n\t\t\t\tindexPair = (indexPair >> 16) | (indexPair << 16);\n\t\t\t\tgx2WriteGather_submitU32AsLE(indexPair);\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstruct GX2DispatchComputeParam\n\t{\n\t\t/* +0x00 */ uint32be worksizeX;\n\t\t/* +0x04 */ uint32be worksizeY;\n\t\t/* +0x08 */ uint32be worksizeZ;\n\t};\n\n\tvoid GX2DispatchCompute(GX2DispatchComputeParam* dispatchParam)\n\t{\n\t\tGX2ReserveCmdSpace(9 + 10);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_RESOURCE, 8),\n\t\t\t(mmSQ_CS_DISPATCH_PARAMS - mmSQ_TEX_RESOURCE_WORD0),\n\t\t\tmemory_virtualToPhysical(MEMPTR<GX2DispatchComputeParam>(dispatchParam).GetMPTR()),\n\t\t\t0xF,\n\t\t\t0x862000,\n\t\t\t1,\n\t\t\t0xABCD1234,\n\t\t\t0xABCD1234,\n\t\t\t0xC0000000);\n\n\t\t// IT_EVENT_WRITE with RST_VTX_CNT?\n\n\t\t// set primitive mode\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONFIG_REG, 2));\n\t\tgx2WriteGather_submitU32AsBE(Latte::REGADDR::VGT_PRIMITIVE_TYPE - 0x2000);\n\t\tgx2WriteGather_submitU32AsBE(1); // mode\n\t\t// set number of instances\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_NUM_INSTANCES, 1));\n\t\tgx2WriteGather_submitU32AsBE(1); // numInstances\n\n\t\tuint32 workCount = (uint32)dispatchParam->worksizeX * (uint32)dispatchParam->worksizeY * (uint32)dispatchParam->worksizeZ;\n\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_DRAW_INDEX_AUTO, 2) | 0x00000001);\n\t\tgx2WriteGather_submitU32AsBE(workCount);\n\t\tgx2WriteGather_submitU32AsBE(0); // DRAW_INITIATOR (has source select for index generator + other unknown info)\n\t}\n\n\tvoid GX2DrawInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2SetAttribBuffer, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2DrawIndexedEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2DrawIndexedEx2, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2DrawEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2DrawIndexedImmediateEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2DispatchCompute, LogType::GX2);\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Draw.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n\nnamespace GX2\n{\n\tusing GX2IndexType = Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE;\n\tusing GX2PrimitiveMode2 = Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE;\n\n\tvoid GX2SetAttribBuffer(uint32 bufferIndex, uint32 sizeInBytes, uint32 stride, void* data);\n\tvoid GX2DrawIndexedEx(GX2PrimitiveMode2 primitiveMode, uint32 count, GX2IndexType indexType, void* indexData, uint32 baseVertex, uint32 numInstances);\n\n\tvoid GX2DrawInit();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Event.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"GX2_Command.h\"\n#include \"GX2_Event.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/HW/MMU/MMU.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"GX2.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/helpers/ConcurrentQueue.h\"\n\nnamespace GX2\n{\n\n\tSysAllocator<coreinit::OSThreadQueue> g_vsyncThreadQueue;\n\tSysAllocator<coreinit::OSThreadQueue> g_flipThreadQueue;\n\n\tvoid GX2SetGPUFence(uint32be* fencePtr, uint32 mask, uint32 compareOp, uint32 compareValue)\n\t{\n\t\tGX2ReserveCmdSpace(7);\n\t\tuint8 compareOpTable[] = { 0x7,0x1,0x3,0x2,0x6,0x4,0x5,0x0 };\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_WAIT_REG_MEM, 6));\n\t\tgx2WriteGather_submitU32AsBE((uint32)(compareOpTable[compareOp & 7]) | 0x10); // compare operand + memory select (0x10)\n\t\tgx2WriteGather_submitU32AsBE(memory_virtualToPhysical(memory_getVirtualOffsetFromPointer(fencePtr)) | 2); // physical address + type size flag(?)\n\t\tgx2WriteGather_submitU32AsBE(0); // ukn, always set to 0\n\t\tgx2WriteGather_submitU32AsBE(compareValue); // fence value\n\t\tgx2WriteGather_submitU32AsBE(mask); // fence mask\n\t\tgx2WriteGather_submitU32AsBE(0xA); // unknown purpose\n\t}\n\n\tenum class GX2PipeEventType : uint32\n\t{\n\t\tTOP = 0,\n\t\tBOTTOM = 1,\n\t\tBOTTOM_AFTER_FLUSH = 2\n\t};\n\n\tvoid GX2SubmitUserTimeStamp(uint64* timestampOut, uint64 value, GX2PipeEventType eventType, uint32 triggerInterrupt)\n\t{\n\t\tGX2ReserveCmdSpace(7);\n\n\t\tMPTR physTimestampAddr = memory_virtualToPhysical(memory_getVirtualOffsetFromPointer(timestampOut));\n\t\tuint32 valHigh = (uint32)(value >> 32);\n\t\tuint32 valLow = (uint32)(value & 0xffffffff);\n\n\t\tif (eventType == GX2PipeEventType::TOP)\n\t\t{\n\t\t\t// write when on top of pipe\n\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_MEM_WRITE, 4));\n\t\t\tgx2WriteGather_submitU32AsBE(physTimestampAddr | 0x2);\n\t\t\tgx2WriteGather_submitU32AsBE(0); // 0x40000 -> 32bit write, 0x0 -> 64bit write?\n\t\t\tgx2WriteGather_submitU32AsBE(valLow); // low\n\t\t\tgx2WriteGather_submitU32AsBE(valHigh); // high\n\t\t\tif (triggerInterrupt != 0)\n\t\t\t{\n\t\t\t\t// top callback\n\t\t\t\tgx2WriteGather_submitU32AsBE(0x0000304A);\n\t\t\t\tgx2WriteGather_submitU32AsBE(0x40000000);\n\t\t\t}\n\t\t}\n\t\telse if (eventType == GX2PipeEventType::BOTTOM_AFTER_FLUSH)\n\t\t{\n\t\t\t// write when on bottom of pipe\n\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_MEM_WRITE, 4));\n\t\t\tgx2WriteGather_submitU32AsBE(physTimestampAddr | 0x2);\n\t\t\tgx2WriteGather_submitU32AsBE(0); // 0x40000 -> 32bit write, 0x0 -> 64bit write?\n\t\t\tgx2WriteGather_submitU32AsBE(valLow); // low\n\t\t\tgx2WriteGather_submitU32AsBE(valHigh); // high\n\t\t\t// trigger CB\n\t\t\tif (triggerInterrupt != 0)\n\t\t\t{\n\t\t\t\t// bottom callback\n\t\t\t\t// todo -> Fix this\n\t\t\t\tgx2WriteGather_submitU32AsBE(0x0000304B); // hax -> This event is handled differently and uses a different packet?\n\t\t\t\tgx2WriteGather_submitU32AsBE(0x40000000);\n\t\t\t\t// trigger bottom of pipe callback\n\t\t\t\t// used by Mario & Sonic Rio\n\t\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_BOTTOM_OF_PIPE_CB, 3));\n\t\t\t\tgx2WriteGather_submitU32AsBE(physTimestampAddr);\n\t\t\t\tgx2WriteGather_submitU32AsBE(valLow); // low\n\t\t\t\tgx2WriteGather_submitU32AsBE(valHigh); // high\n\t\t\t}\n\t\t}\n\t\telse if (eventType == GX2PipeEventType::BOTTOM)\n\t\t{\n\t\t\t// fix this\n\t\t\t// write timestamp when on bottom of pipe\n\t\t\tif (triggerInterrupt != 0)\n\t\t\t{\n\t\t\t\t// write value and trigger CB\n\t\t\t\t// todo: Use correct packet\n\t\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_BOTTOM_OF_PIPE_CB, 3));\n\t\t\t\tgx2WriteGather_submitU32AsBE(physTimestampAddr);\n\t\t\t\tgx2WriteGather_submitU32AsBE(valLow); // low\n\t\t\t\tgx2WriteGather_submitU32AsBE(valHigh); // high\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// write value but don't trigger CB\n\t\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_MEM_WRITE, 4));\n\t\t\t\tgx2WriteGather_submitU32AsBE(physTimestampAddr | 0x2);\n\t\t\t\tgx2WriteGather_submitU32AsBE(0); // 0x40000 -> 32bit write, 0x0 -> 64bit write?\n\t\t\t\tgx2WriteGather_submitU32AsBE(valLow); // low\n\t\t\t\tgx2WriteGather_submitU32AsBE(valHigh); // high\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\n\tstruct GX2EventFunc\n\t{\n\t\tMEMPTR<void> callbackFuncPtr;\n\t\tMEMPTR<void> userData;\n\t}s_eventCallback[GX2CallbackEventTypeCount]{};\n\n\tvoid GX2SetEventCallback(GX2CallbackEventType eventType, void* callbackFuncPtr, void* userData)\n\t{\n\t\tif ((size_t)eventType >= GX2CallbackEventTypeCount)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"GX2SetEventCallback(): Unknown eventType\");\n\t\t\treturn;\n\t\t}\n\t\ts_eventCallback[(size_t)eventType].callbackFuncPtr = callbackFuncPtr;\n\t\ts_eventCallback[(size_t)eventType].userData = userData;\n\t}\n\n\tvoid GX2GetEventCallback(GX2CallbackEventType eventType, MEMPTR<void>* callbackFuncPtrOut, MEMPTR<void>* userDataOut)\n\t{\n\t\tif ((size_t)eventType >= GX2CallbackEventTypeCount)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"GX2GetEventCallback(): Unknown eventType\");\n\t\t\treturn;\n\t\t}\n\t\tif (callbackFuncPtrOut)\n\t\t\t*callbackFuncPtrOut = s_eventCallback[(size_t)eventType].callbackFuncPtr;\n\t\tif (userDataOut)\n\t\t\t*userDataOut = s_eventCallback[(size_t)eventType].userData;\n\t}\n\n\t// event callback thread\n\tbool s_callbackThreadLaunched{};\n\tSysAllocator<OSThread_t> s_eventCallbackThread;\n\tSysAllocator<uint8, 0x2000> s_eventCallbackThreadStack;\n\tSysAllocator<char, 64> s_eventCallbackThreadName;\n\t// event callback queue\n\tstruct GX2EventQueueEntry\n\t{\n\t\tGX2EventQueueEntry() {};\n\t\tGX2EventQueueEntry(GX2CallbackEventType eventType) : eventType(eventType) {};\n\t\tGX2CallbackEventType eventType{(GX2CallbackEventType)-1};\n\t};\n\n\tSysAllocator<coreinit::OSSemaphore> s_eventCbQueueSemaphore;\n\tConcurrentQueue<GX2EventQueueEntry> s_eventCbQueue;\n\n\tvoid __GX2NotifyEvent(GX2CallbackEventType eventType)\n\t{\n\t\tif ((size_t)eventType >= GX2CallbackEventTypeCount)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn;\n\t\t}\n\t\tif (s_eventCallback[(size_t)eventType].callbackFuncPtr)\n\t\t{\n\t\t\ts_eventCbQueue.push(eventType);\n\t\t\tcoreinit::OSSignalSemaphore(s_eventCbQueueSemaphore);\n\t\t}\n\t\t// wake up threads that are waiting for VSYNC or FLIP event\n\t\tif (eventType == GX2CallbackEventType::VSYNC)\n\t\t{\n\t\t\t__OSLockScheduler();\n\t\t\tg_vsyncThreadQueue->wakeupEntireWaitQueue(false);\n\t\t\t__OSUnlockScheduler();\n\t\t}\n\t\telse if (eventType == GX2CallbackEventType::FLIP)\n\t\t{\n\t\t\t__OSLockScheduler();\n\t\t\tg_flipThreadQueue->wakeupEntireWaitQueue(false);\n\t\t\t__OSUnlockScheduler();\n\t\t}\n\t}\n\n\tvoid __GX2CallbackThread(PPCInterpreter_t* hCPU)\n\t{\n\t\twhile (coreinit::OSWaitSemaphore(s_eventCbQueueSemaphore))\n\t\t{\n\t\t\tGX2EventQueueEntry entry;\n\t\t\tif (!s_eventCbQueue.peek2(entry))\n\t\t\t\tcontinue;\n\t\t\tif(!s_eventCallback[(size_t)entry.eventType].callbackFuncPtr)\n\t\t\t\tcontinue;\n\t\t\tPPCCoreCallback(s_eventCallback[(size_t)entry.eventType].callbackFuncPtr, (sint32)entry.eventType, s_eventCallback[(size_t)entry.eventType].userData);\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid GX2WaitForVsync()\n\t{\n\t\t__OSLockScheduler();\n\t\tg_vsyncThreadQueue.GetPtr()->queueAndWait(coreinit::OSGetCurrentThread());\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid GX2WaitForFlip()\n\t{\n\t\tif ((sint32)(_swapEndianU32(LatteGPUState.sharedArea->flipRequestCountBE) == _swapEndianU32(LatteGPUState.sharedArea->flipExecuteCountBE)))\n\t\t\treturn; // dont wait if no flip is requested\n\t\t__OSLockScheduler();\n\t\tg_flipThreadQueue.GetPtr()->queueAndWait(coreinit::OSGetCurrentThread());\n\t\t__OSUnlockScheduler();\n\t}\n\n\tvoid GX2DrawDone()\n\t{\n\t\t// optional force full sync (texture readback and occlusion queries)\n\t\tbool forceFullSync = false;\n\t\tif (g_renderer && g_renderer->GetType() == RendererAPI::Vulkan)\n\t\t\tforceFullSync = true;\n\t\tif (forceFullSync || ActiveSettings::WaitForGX2DrawDoneEnabled())\n\t\t{\n\t\t\tGX2ReserveCmdSpace(2);\n\t\t\t// write PM4 command\n\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_SYNC_ASYNC_OPERATIONS, 1));\n\t\t\tgx2WriteGather_submitU32AsBE(0x00000000); // unused\n\t\t}\n\t\t// flush pipeline\n\t\tGX2Command_Flush(0x100, true);\n\n\t\tuint64 ts = GX2GetLastSubmittedTimeStamp();\n\t\tGX2WaitTimeStamp(ts);\n\t}\n\n\tvoid GX2Init_event()\n\t{\n\t\t// clear queue\n\n\t\t// launch event callback thread\n\t\tif (s_callbackThreadLaunched)\n\t\t\treturn;\n\t\ts_callbackThreadLaunched = true;\n\t\tstrcpy(s_eventCallbackThreadName.GetPtr(), \"GX2 event callback\");\n\t\tcoreinit::OSCreateThreadType(s_eventCallbackThread, PPCInterpreter_makeCallableExportDepr(__GX2CallbackThread), 0, nullptr, (uint8*)s_eventCallbackThreadStack.GetPtr() + s_eventCallbackThreadStack.GetByteSize(), (sint32)s_eventCallbackThreadStack.GetByteSize(), 16, OSThread_t::ATTR_DETACHED, OSThread_t::THREAD_TYPE::TYPE_IO);\n\t\tcoreinit::OSSetThreadName(s_eventCallbackThread, s_eventCallbackThreadName);\n\t\tcoreinit::OSResumeThread(s_eventCallbackThread);\n\t}\n\n\tvoid GX2EventInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2SetGPUFence, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SubmitUserTimeStamp, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2SetEventCallback, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetEventCallback, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2WaitForVsync, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2WaitForFlip, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2DrawDone, LogType::GX2);\n\n\t\tcoreinit::OSInitThreadQueue(g_vsyncThreadQueue.GetPtr());\n\t\tcoreinit::OSInitThreadQueue(g_flipThreadQueue.GetPtr());\n\n\t\tcoreinit::OSInitSemaphore(s_eventCbQueueSemaphore, 0);\n\t}\n\n    void GX2EventResetToDefaultState()\n    {\n        s_callbackThreadLaunched = false;\n        for(auto& it : s_eventCallback)\n        {\n            it.callbackFuncPtr = nullptr;\n            it.userData = nullptr;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Event.h",
    "content": "#pragma once\n\nnamespace GX2\n{\n\tvoid GX2Init_event();\n\tvoid GX2EventResetToDefaultState();\n\n\tvoid GX2EventInit();\n\tvoid GX2WaitForVsync();\n\tvoid GX2WaitForFlip();\n\tvoid GX2DrawDone();\n\n\tenum class GX2CallbackEventType\n\t{\n\t\tTIMESTAMP_TOP = 0,\n\t\tTIMESTAMP_BOTTOM = 1,\n\t\tVSYNC = 2,\n\t\tFLIP = 3,\n\t\t// 4 is buffer overrun?\n\t};\n\tinline constexpr size_t GX2CallbackEventTypeCount = 5;\n\n\t// notification callbacks for GPU\n\tvoid __GX2NotifyNewRetirementTimestamp(uint64 tsRetire);\n\tvoid __GX2NotifyEvent(GX2CallbackEventType eventType);\n\n}"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Memory.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"GX2.h\"\n#include \"GX2_Resource.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n\n// default GX2 allocator (not the same as the GX2R allocator, but GX2R uses this allocator by default)\nMPTR gx2Mem_defaultAlloc = MPTR_NULL;\nMPTR gx2Mem_defaultFree = MPTR_NULL;\n\nvoid gx2Memory_GX2SetDefaultAllocator(MPTR defaultAllocFunc, MPTR defaulFreeFunc)\n{\n\tgx2Mem_defaultAlloc = defaultAllocFunc;\n\tgx2Mem_defaultFree = defaulFreeFunc;\n}\n\nvoid _GX2DefaultAlloc_Alloc(PPCInterpreter_t* hCPU)\n{\n\t// parameters:\n\t// r3\tuint32\tuserParam\n\t// r4\tuint32  size\n\t// r5\tsint32\talignment\n\thCPU->gpr[3] = hCPU->gpr[4];\n\thCPU->gpr[4] = hCPU->gpr[5];\n\thCPU->instructionPointer = gCoreinitData->MEMAllocFromDefaultHeapEx.GetMPTR();\n}\n\nvoid _GX2DefaultAlloc_Free(PPCInterpreter_t* hCPU)\n{\n\thCPU->gpr[3] = hCPU->gpr[4];\n\thCPU->instructionPointer = gCoreinitData->MEMFreeToDefaultHeap.GetMPTR();\n}\n\nvoid gx2Export_GX2SetDefaultAllocator(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetDefaultAllocator(0x{:08x}, 0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4]);\n\tgx2Mem_defaultAlloc = hCPU->gpr[3];\n\tgx2Mem_defaultFree = hCPU->gpr[4];\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid _GX2DefaultAllocR_Alloc(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2DefaultAllocate(0x{:08x}, 0x{:08x}, 0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\t// parameters:\n\t// r3\tuint32\tuserParam\n\t// r4\tuint32  size\n\t// r5\tsint32\talignment\n\thCPU->instructionPointer = gx2Mem_defaultAlloc;\n}\n\nvoid _GX2DefaultAllocR_Free(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2DefaultFree(0x{:08x}, 0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4]);\n\t// parameters:\n\t// r3\tuint32\tuserParam\n\t// r4\tvoid*\tmem\n\thCPU->instructionPointer = gx2Mem_defaultFree;\n}\n\nnamespace GX2\n{\n\tvoid GX2MEMAllocatorsInit()\n\t{\n\t\t// set default allocators (can be overwritten by GX2SetDefaultAllocator)\n\t\tgx2Mem_defaultAlloc = PPCInterpreter_makeCallableExportDepr(_GX2DefaultAlloc_Alloc);\n\t\tgx2Mem_defaultFree = PPCInterpreter_makeCallableExportDepr(_GX2DefaultAlloc_Free);\n\t\t// set resource default allocator\n\t\tGX2::GX2RSetAllocator(PPCInterpreter_makeCallableExportDepr(_GX2DefaultAllocR_Alloc), PPCInterpreter_makeCallableExportDepr(_GX2DefaultAllocR_Free));\n\t}\n\n\tvoid GX2MemInit()\n\t{\n\t\tosLib_addFunction(\"gx2\", \"GX2SetDefaultAllocator\", gx2Export_GX2SetDefaultAllocator);\n\t}\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Memory.h",
    "content": "#pragma once\n\nnamespace GX2\n{\n\tvoid GX2MEMAllocatorsInit();\n\n\tvoid GX2MemInit();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Misc.cpp",
    "content": "#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"GX2.h\"\n#include \"config/CemuConfig.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"GX2_Command.h\"\n#include \"GX2_Event.h\"\n#include \"GX2_Misc.h\"\n#include \"GX2_Memory.h\"\n#include \"GX2_Texture.h\"\n\nvoid gx2Export_GX2SetSwapInterval(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetSwapInterval({})\", hCPU->gpr[3]);\n\tif( hCPU->gpr[3] >= 20 )\n\t{\n\t\tcemuLog_log(LogType::Force, \"GX2SetSwapInterval() called with out of range value ({})\", hCPU->gpr[3]);\n\t}\n\telse\n\t\tLatteGPUState.sharedArea->swapInterval = hCPU->gpr[3];\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2GetSwapInterval(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2GetSwapInterval()\");\n\tosLib_returnFromFunction(hCPU, LatteGPUState.sharedArea->swapInterval);\n}\n\nextern uint64 lastSwapTime;\n\nvoid gx2Export_GX2GetSwapStatus(PPCInterpreter_t* hCPU)\n{\n\tmemory_writeU32(hCPU->gpr[3], _swapEndianU32(LatteGPUState.sharedArea->flipRequestCountBE));\n\tmemory_writeU32(hCPU->gpr[4], _swapEndianU32(LatteGPUState.sharedArea->flipExecuteCountBE));\n\tmemory_writeU64(hCPU->gpr[5], lastSwapTime);\n\tmemory_writeU64(hCPU->gpr[6], lastSwapTime);\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2GetGPUTimeout(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2GetGPUTimeout()\");\n\tosLib_returnFromFunction(hCPU, 0x3E8);\n}\n\n#define GX2_INVALID_COUNTER_VALUE_U64 0xFFFFFFFFFFFFFFFFULL\n\nvoid gx2Export_GX2SampleTopGPUCycle(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SampleTopGPUCycle(0x{:08x})\", hCPU->gpr[3]);\n\tmemory_writeU64(hCPU->gpr[3], coreinit::OSGetSystemTime());\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SampleBottomGPUCycle(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SampleBottomGPUCycle(0x{:08x})\", hCPU->gpr[3]);\n\tmemory_writeU64(hCPU->gpr[3], GX2_INVALID_COUNTER_VALUE_U64);\n\n\tosLib_returnFromFunction(hCPU, 0);\n\treturn;\n\t// seems like implementing this correctly causes more harm than good as games will try to dynamically scale their resolution, which our texture cache and graphic packs cant handle well. If we just never return a valid timestamp, it seems like games stop dynamically scaling resolution\n\t// Whats a good solution here? Should we implement it correctly and instead rely on graphic pack patches to patch out the dynamic scaling?\n\t// some known affected games: Wind Waker HD, Super Mario 3D World\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_SAMPLE_TIMER, 1));\n\tgx2WriteGather_submitU32AsBE(hCPU->gpr[3]); \n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nnamespace GX2\n{\n\tSysAllocator<uint8, 640 * 480 * 4, 0x1000> _lastFrame;\n\tuint32 sGX2MainCoreIndex = 0;\n\n\tvoid _test_AddrLib();\n\n\tusing GX2InitArg = uint32;\n\tenum class GX2InitArgId : GX2InitArg\n\t{\n\t\tEndOfArgs = 0,\n\t\tCommandPoolBase = 1,\n\t\tCommandPoolSize = 2,\n\t\tUknArg7 = 7,\n\t\tUknArg8 = 8,\n\t\tUknArg9 = 9,\n\t\tUknArg11 = 11,\n\t};\n\n\tvoid GX2Init(betype<GX2InitArg>* initArgStream)\n\t{\n\t\tif (LatteGPUState.gx2InitCalled)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"GX2Init() called while already initialized\");\n\t\t\treturn;\n\t\t}\n\t\t// parse init params from the stream\n\t\tMEMPTR<void> commandPoolBase = nullptr;\n\t\tuint32 commandPoolSize = 0;\n\t\tif (initArgStream)\n\t\t{\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tGX2InitArgId paramId = static_cast<GX2InitArgId>((GX2InitArg)*initArgStream);\n\t\t\t\tinitArgStream++;\n\t\t\t\tif (paramId == GX2InitArgId::EndOfArgs)\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (paramId == GX2InitArgId::CommandPoolBase)\n\t\t\t\t{\n\t\t\t\t\tcommandPoolBase = MEMPTR<void>(*initArgStream);\n\t\t\t\t\tinitArgStream++;\n\t\t\t\t}\n\t\t\t\telse if (paramId == GX2InitArgId::CommandPoolSize)\n\t\t\t\t{\n\t\t\t\t\tcommandPoolSize = *initArgStream;\n\t\t\t\t\tinitArgStream++;\n\t\t\t\t}\n\t\t\t\telse if (paramId == GX2InitArgId::UknArg7 ||\n\t\t\t\t\tparamId == GX2InitArgId::UknArg8 ||\n\t\t\t\t\tparamId == GX2InitArgId::UknArg9 ||\n\t\t\t\t\tparamId == GX2InitArgId::UknArg11)\n\t\t\t\t{\n\t\t\t\t\tinitArgStream++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"GX2Init: Unsupported init arg {}\", (uint32)paramId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// init main core\n\t\tuint32 coreIndex = coreinit::OSGetCoreId();\n\t\tcemuLog_log(LogType::GX2, \"GX2Init() on core {} by thread 0x{:08x}\", coreIndex, MEMPTR<OSThread_t>(coreinit::OSGetCurrentThread()).GetMPTR());\n\t\tsGX2MainCoreIndex = coreIndex;\n\t\t// init submodules\n\t\tGX2::GX2Init_event();\n\t\tGX2::GX2Init_commandBufferPool(commandPoolBase, commandPoolSize);\n\t\t// init shared area\n\t\tif (LatteGPUState.sharedAreaAddr == MPTR_NULL)\n\t\t{\n\t\t\tLatteGPUState.sharedAreaAddr = coreinit_allocFromSysArea(sizeof(gx2GPUSharedArea_t), 0x20);\n\t\t\tLatteGPUState.sharedArea = (gx2GPUSharedArea_t*)memory_getPointerFromVirtualOffset(LatteGPUState.sharedAreaAddr);\n\t\t}\n\t\t// init shared variables\n\t\tLatteGPUState.sharedArea->flipRequestCountBE = _swapEndianU32(0);\n\t\tLatteGPUState.sharedArea->flipExecuteCountBE = _swapEndianU32(0);\n\t\tLatteGPUState.sharedArea->swapInterval = 1;\n\t\t// init memory handling\n\t\tGX2::GX2MEMAllocatorsInit();\n\t\t// let GPU know that GX2 is initialized\n\t\tLatteGPUState.gx2InitCalled++;\n\t\t// run tests\n\t\t_test_AddrLib();\n\t}\n\n\tvoid GX2Shutdown()\n\t{\n\t\tif (!LatteGPUState.gx2InitCalled)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"GX2Shutdown() called while not initialized\");\n\t\t\treturn;\n\t\t}\n\t\tLatteGPUState.gx2InitCalled--;\n\t\tif (LatteGPUState.gx2InitCalled != 0)\n\t\t\treturn;\n\t\tGX2DrawDone();\n\t\tGX2Shutdown_commandBufferPool();\n\t\tcemuLog_log(LogType::Force, \"GX2 shutdown\");\n\t}\n\n\tvoid _GX2DriverReset()\n\t{\n\t\tLatteGPUState.gx2InitCalled = 0;\n        sGX2MainCoreIndex = 0;\n        GX2CommandResetToDefaultState();\n        GX2EventResetToDefaultState();\n\t}\n\n\tsint32 GX2GetMainCoreId(PPCInterpreter_t* hCPU)\n\t{\n\t\tif (LatteGPUState.gx2InitCalled == 0)\n\t\t\treturn -1;\n\t\treturn sGX2MainCoreIndex;\n\t}\n\n\tvoid GX2ResetGPU(uint32 ukn)\n\t{\n\t\tcemuLog_log(LogType::Force, \"GX2ResetGPU()\"); // always log this\n\t\tGX2::GX2DrawDone();\n\t}\n\n\tvoid GX2SetTVBuffer(void* imageBuffePtr, uint32 imageBufferSize, E_TVRES tvResolutionMode, uint32 _surfaceFormat, E_TVBUFFERMODE bufferMode)\n\t{\n\t\tLatte::E_GX2SURFFMT surfaceFormat = (Latte::E_GX2SURFFMT)_surfaceFormat;\n\t\tLatteGPUState.tvBufferUsesSRGB = HAS_FLAG(surfaceFormat, Latte::E_GX2SURFFMT::FMT_BIT_SRGB);\n\t\t// todo - actually allocate a scanbuffer\n\t}\n\n\tvoid GX2SetTVGamma(float gamma)\n\t{\n\t\tLatteGPUState.tvGamma = (1.0f - gamma);\n\t}\n\n\tvoid GX2SetDRCGamma(float gamma)\n\t{\n\t\tLatteGPUState.drcGamma = (1.0f - gamma);\n\t}\n\n\tbool GX2GetLastFrame(uint32 deviceId, GX2Texture* textureOut)\n\t{\n\t\t// return a 480p image\n\t\ttextureOut->viewFirstMip = 0;\n\t\ttextureOut->viewFirstSlice = 0;\n\t\ttextureOut->viewNumMips = 1;\n\t\ttextureOut->viewNumSlices = 1;\n\t\ttextureOut->compSel = 0x00010203;\n\n\t\ttextureOut->surface.width = 640;\n\t\ttextureOut->surface.height = 480;\n\t\ttextureOut->surface.depth = 1;\n\t\ttextureOut->surface.dim = Latte::E_DIM::DIM_2D;\n\t\ttextureOut->surface.format = Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM;\n\t\ttextureOut->surface.tileMode = Latte::E_GX2TILEMODE::TM_LINEAR_ALIGNED;\n\t\ttextureOut->surface.pitch = 0;\n\t\ttextureOut->surface.resFlag = 0;\n\t\ttextureOut->surface.aa = 0;\n\n\t\tGX2CalcSurfaceSizeAndAlignment(&textureOut->surface);\n\n\t\ttextureOut->surface.imagePtr = _lastFrame.GetMPTR();\n\n\t\tGX2InitTextureRegs(textureOut);\n\n\t\treturn true;\n\t}\n\n\tbool GX2GetLastFrameGammaA(uint32 deviceId, float32be* gamma)\n\t{\n\t\t*gamma = 1.0f;\n\t\treturn true;\n\t}\n\n\tbool GX2GetLastFrameGammaB(uint32 deviceId, float32be* gamma)\n\t{\n\t\t*gamma = 1.0f;\n\t\treturn true;\n\t}\n\n\tuint64 GX2GPUTimeToCPUTime(uint64 gpuTime)\n\t{\n\t\treturn 0; // hack, see note in GX2SampleBottomGPUCycle\n\t}\n\n\tuint32 GX2GetSystemDRCMode()\n\t{\n\t\treturn 1;\n\t}\n\n\tuint32 GX2IsVideoOutReady()\n\t{\n\t\treturn 1;\n\t}\n\n\tvoid GX2Invalidate(uint32 invalidationFlags, MPTR invalidationAddr, uint32 invalidationSize)\n\t{\n\t\tuint32 surfaceSyncFlags = 0;\n\n\t\tif (invalidationFlags & 0x04)\n\t\t{\n\t\t\t// uniform block\n\t\t\tsurfaceSyncFlags |= 0x8800000;\n\t\t}\n\t\tif (invalidationFlags & 0x01)\n\t\t{\n\t\t\t// attribute data\n\t\t\tsurfaceSyncFlags |= 0x800000;\n\t\t}\n\n\t\tif (invalidationFlags & 0x40)\n\t\t{\n\t\t\t// CPU cache\n\t\t\tLatteBufferCache_notifyDCFlush(invalidationAddr, invalidationSize);\n\t\t}\n\n\t\tif (surfaceSyncFlags != 0)\n\t\t{\n\t\t\tGX2ReserveCmdSpace(5);\n\t\t\t// write PM4 command\n\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SURFACE_SYNC, 4)); // IT_SURFACE_SYNC + 4 data dwords\n\t\t\tgx2WriteGather_submitU32AsBE(surfaceSyncFlags);\n\t\t\tgx2WriteGather_submitU32AsBE((invalidationSize + 0xFF) >> 8); // size\n\t\t\tgx2WriteGather_submitU32AsBE(memory_virtualToPhysical(invalidationAddr) >> 8); // base address (divided by 0x100)\n\t\t\tgx2WriteGather_submitU32AsBE(0x00000004); // poll interval\n\t\t}\n\t}\n\n\tvoid GX2MiscInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2Init, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2Shutdown, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetMainCoreId, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2ResetGPU, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2SetTVBuffer, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetTVGamma, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetDRCGamma, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2GetLastFrame, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetLastFrameGammaA, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetLastFrameGammaB, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2GPUTimeToCPUTime, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetSystemDRCMode, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2IsVideoOutReady, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2Invalidate, LogType::GX2);\n\n\t\tsGX2MainCoreIndex = 0;\n\t}\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Misc.h",
    "content": "#pragma once\n\nnamespace GX2\n{\n\textern uint32 sGX2MainCoreIndex;\n\n\tenum class E_TVRES\n\t{\n\t\tTODO,\n\t};\n\n\tenum class E_TVBUFFERMODE\n\t{\n\t\tDOUBLE_BUFFER = 2,\n\t};\n\n\tvoid _GX2DriverReset();\n\n\tvoid GX2SetTVBuffer(void* imageBuffePtr, uint32 imageBufferSize, E_TVRES tvResolutionMode, uint32 surfaceFormat, E_TVBUFFERMODE bufferMode);\n\tvoid GX2SetTVGamma(float gamma);\n\n\tvoid GX2Invalidate(uint32 invalidationFlags, MPTR invalidationAddr, uint32 invalidationSize);\n\n\tvoid GX2MiscInit();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Query.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"GX2.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"GX2_Query.h\"\n\n#define LATTE_GC_NUM_RB\t\t\t\t\t\t\t2\n#define _QUERY_REG_COUNT\t\t\t\t\t\t8 // each reg/result is 64bits, little endian\n\nnamespace GX2\n{\n\tstruct GX2Query\n\t{\n\t\t// 4*2 sets of uint64 results\n\t\tuint32 reg[_QUERY_REG_COUNT * 2];\n\t};\n\n\tstatic_assert(sizeof(GX2Query) == 0x40);\n\n\tvoid _BeginOcclusionQuery(GX2Query* queryInfo, bool isGPUQuery)\n\t{\n\t\tif (isGPUQuery)\n\t\t{\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\t\tif (titleId == 0x00050000101c4c00ULL || titleId == 0x00050000101c4d00 || titleId == 0x0005000010116100) // XCX EU, US, JPN\n\t\t\t{\n\t\t\t\t// in XCX queries are used to determine if certain objects are visible\n\t\t\t\t// if we are not setting the result fast enough and the query still holds a value of 0 (which is the default for GPU queries)\n\t\t\t\t// then XCX will not render affected objects, causing flicker\n\t\t\t\t// note: This is a very old workaround. It may no longer be necessary since the introduction of full sync. Investigate\n\t\t\t\t*(uint64*)(queryInfo->reg + 2) = 0x100000;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tGX2ReserveCmdSpace(5 * _QUERY_REG_COUNT);\n\t\t\t\tMPTR queryInfoPhys = memory_virtualToPhysical(memory_getVirtualOffsetFromPointer(queryInfo));\n\t\t\t\tfor (sint32 i = 0; i < _QUERY_REG_COUNT; i++)\n\t\t\t\t{\n\t\t\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_MEM_WRITE, 4));\n\t\t\t\t\tgx2WriteGather_submitU32AsBE((queryInfoPhys + i * 8) | 0x2);\n\t\t\t\t\tgx2WriteGather_submitU32AsBE(0x20000); // 0x20000 -> ?\n\t\t\t\t\tuint32 v = 0;\n\t\t\t\t\tif (i >= LATTE_GC_NUM_RB * 2)\n\t\t\t\t\t\tv |= 0x80000000;\n\t\t\t\t\tgx2WriteGather_submitU32AsBE(0);\n\t\t\t\t\tgx2WriteGather_submitU32AsBE(v);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmemset(queryInfo, 0, 0x10); // size maybe GPU7_GC_NUM_RB*2*4 ?\n\t\t\tqueryInfo->reg[LATTE_GC_NUM_RB * 4 + 0] = 0;\n\t\t\tqueryInfo->reg[LATTE_GC_NUM_RB * 4 + 1] = _swapEndianU32('OCPU');\n\t\t}\n\t\t// todo: Set mmDB_RENDER_CONTROL\n\t}\n\n\tvoid GX2QueryBegin(uint32 queryType, GX2Query* query)\n\t{\n\t\tif (queryType == GX2_QUERY_TYPE_OCCLUSION_CPU)\n\t\t{\n\t\t\t_BeginOcclusionQuery(query, false);\n\t\t}\n\t\telse if (queryType == GX2_QUERY_TYPE_OCCLUSION_GPU)\n\t\t{\n\t\t\t_BeginOcclusionQuery(query, true);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebug_printf(\"GX2QueryBegin(): Unsupported type %d\\n\", queryType);\n\t\t\tdebugBreakpoint();\n\t\t\treturn;\n\t\t}\n\t\t// HLE packet\n\t\tGX2ReserveCmdSpace(2);\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_BEGIN_OCCLUSION_QUERY, 1));\n\t\tgx2WriteGather_submitU32AsBE(MEMPTR<GX2Query>(query).GetMPTR());\n\t}\n\n\tvoid GX2QueryEnd(uint32 queryType, GX2Query* query)\n\t{\n\t\tGX2ReserveCmdSpace(2);\n\t\tif (queryType == GX2_QUERY_TYPE_OCCLUSION_CPU || queryType == GX2_QUERY_TYPE_OCCLUSION_GPU)\n\t\t{\n\t\t\t// HLE packet\n\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_END_OCCLUSION_QUERY, 1));\n\t\t\tgx2WriteGather_submitU32AsBE(MEMPTR<GX2Query>(query).GetMPTR());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdebug_printf(\"GX2QueryBegin(): Unsupported %d\\n\", queryType);\n\t\t\tdebugBreakpoint();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tuint32 GX2QueryGetOcclusionResult(GX2Query* query, uint64be* resultOut)\n\t{\n\t\tif (query->reg[LATTE_GC_NUM_RB * 4 + 1] == _swapEndianU32('OCPU') && query->reg[LATTE_GC_NUM_RB * 4 + 0] == 0)\n\t\t{\n\t\t\t// CPU query result not ready\n\t\t\treturn GX2_FALSE;\n\t\t}\n\n\t\tuint64 startValue = *(uint64*)(query->reg + 0);\n\t\tuint64 endValue = *(uint64*)(query->reg + 2);\n\t\tif ((startValue & 0x8000000000000000ULL) || (endValue & 0x8000000000000000ULL))\n\t\t{\n\t\t\treturn GX2_FALSE;\n\t\t}\n\t\t*resultOut = endValue - startValue;\n\t\treturn GX2_TRUE;\n\t}\n\n\tvoid GX2QueryBeginConditionalRender(uint32 queryType, GX2Query* query, uint32 dontWaitBool, uint32 pixelsMustPassBool)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\n\t\tuint32 flags = 0;\n\t\tif (pixelsMustPassBool)\n\t\t\tflags |= (1<<31);\n\t\tif (queryType == GX2_QUERY_TYPE_OCCLUSION_GPU)\n\t\t\tflags |= (1 << 13);\n\t\telse\n\t\t\tflags |= (2 << 13);\n\n\t\tflags |= ((dontWaitBool != 0) << 19);\n\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_PREDICATION, 2));\n\t\tgx2WriteGather_submitU32AsBE(memory_virtualToPhysical(MEMPTR<GX2Query>(query).GetMPTR()));\n\t\tgx2WriteGather_submitU32AsBE(flags);\n\t}\n\n\tvoid GX2QueryEndConditionalRender()\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_PREDICATION, 2));\n\t\tgx2WriteGather_submitU32AsBE(MPTR_NULL);\n\t\tgx2WriteGather_submitU32AsBE(0); // unknown / todo\n\t}\n\n\tvoid GX2QueryInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2QueryBegin, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2QueryEnd, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2QueryGetOcclusionResult, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2QueryBeginConditionalRender, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2QueryEndConditionalRender, LogType::GX2);\n\t}\n};"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Query.h",
    "content": "#pragma once\n\n#define GX2_QUERY_TYPE_OCCLUSION_CPU\t\t\t0\n#define GX2_QUERY_TYPE_OCCLUSION_GPU\t\t\t2\n// 1 and 3 are streamout related?\n\nnamespace GX2\n{\n\tvoid GX2QueryInit();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_RenderTarget.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"GX2.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n\n#include \"GX2_Command.h\"\n\nvoid gx2Export_GX2InitColorBufferRegs(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2InitColorBufferRegs(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamStructPtr(colorBuffer, GX2ColorBuffer, 0);\n\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfaceInfo;\n\tLatteAddrLib::GX2CalculateSurfaceInfo(colorBuffer->surface.format, colorBuffer->surface.width, colorBuffer->surface.height, colorBuffer->surface.depth, colorBuffer->surface.dim, colorBuffer->surface.tileMode, colorBuffer->surface.aa, colorBuffer->viewMip, &surfaceInfo);\n\n\tuint32 pitchHeight = (surfaceInfo.height * surfaceInfo.pitch) >> 6;\n#ifdef CEMU_DEBUG_ASSERT\n\tif (colorBuffer->viewNumSlices != 1)\n\t\tcemuLog_logDebug(LogType::Force, \"GX2InitColorBufferRegs(): With unsupported slice count {}\", (uint32)colorBuffer->viewNumSlices);\n\tif (surfaceInfo.pitch < 7)\n\t\tcemuLog_logDebug(LogType::Force, \"GX2InitColorBufferRegs(): Pitch too small (pitch = {})\", surfaceInfo.pitch);\n\tif ((surfaceInfo.pitch & 7) != 0)\n\t\tcemuLog_logDebug(LogType::Force, \"GX2InitColorBufferRegs(): Pitch has invalid alignment (pitch = {})\", surfaceInfo.pitch);\n\tif (pitchHeight == 0)\n\t\tcemuLog_logDebug(LogType::Force, \"GX2InitColorBufferRegs(): Invalid value (pitchHeight = {})\", pitchHeight);\n#endif\n\n\tuint32 cSize = ((surfaceInfo.pitch >> 3) - 1) & 0x3FF;\n\tcSize |= (((pitchHeight - 1) & 0xFFFFF) << 10);\n\tcolorBuffer->reg_size = cSize;\n\tcolorBuffer->reg_mask = 0;\n\t// reg color_info\n\tLatte::E_GX2SURFFMT format = colorBuffer->surface.format;\n\tLatte::E_HWSURFFMT hwFormat = Latte::GetHWFormat(format);\n\tuint32 formatHighBits = (uint32)format & 0xF00;\n\tuint32 regInfo = 0;\n\tregInfo = (uint32)GX2::GetSurfaceFormatSwapMode(colorBuffer->surface.format);\n\tregInfo |= ((uint32)hwFormat<<2);\n\tcemu_assert_debug(LatteAddrLib::IsValidHWTileMode(surfaceInfo.hwTileMode));\n\tregInfo |= ((uint32)surfaceInfo.hwTileMode << 8);\n\tbool clampBlend = false;\n\tif (formatHighBits == 0x000)\n\t{\n\t\tregInfo |= (0 << 12);\n\t\tclampBlend = true;\n\t}\n\telse if (formatHighBits == 0x100) // integer\n\t{\n\t\tregInfo |= (4 << 12);\n\t}\n\telse if (formatHighBits == 0x200) // signed\n\t{\n\t\tregInfo |= (1 << 12);\n\t\tclampBlend = true;\n\t}\n\telse if (formatHighBits == 0x300) // integer + signed\n\t{\n\t\tregInfo |= (5 << 12);\n\t}\n\telse if (formatHighBits == 0x400) // srgb\n\t{\n\t\tclampBlend = true;\n\t\tregInfo |= (6 << 12);\n\t}\n\telse if (formatHighBits == 0x800) // float\n\t{\n\t\tregInfo |= (7 << 12);\n\t}\n\telse\n\t\tcemu_assert_debug(false);\n\tif (hwFormat == Latte::E_HWSURFFMT::HWFMT_5_5_5_1 || hwFormat == Latte::E_HWSURFFMT::HWFMT_10_10_10_2 )\n\t\tregInfo |= (2 << 16);\n\telse\n\t\tregInfo &= ~(3 << 16); // COMP_SWAP_mask\n\tif(colorBuffer->surface.aa != 0)\n\t\tregInfo |= (2 << 18); // TILE_MODE\n\tbool isIntegerFormat = (uint32)(format & Latte::E_GX2SURFFMT::FMT_BIT_INT) != 0;\n\tif (isIntegerFormat == false)\n\t\tregInfo |= (GX2::GetSurfaceColorBufferExportFormat(colorBuffer->surface.format) << 27); // 0 -> full, 1 -> normalized\n\tif (isIntegerFormat\n\t\t|| format ==Latte::E_GX2SURFFMT::R24_X8_UNORM\n\t\t|| format ==Latte::E_GX2SURFFMT::R24_X8_FLOAT\n\t\t|| format ==Latte::E_GX2SURFFMT::R32_X8_FLOAT)\n\t{\n\t\t// set the blend bypass bit for formats which dont support blending\n\t\tregInfo |= (1<<22);\n\t\tclampBlend = false;\n\t}\n\tif (clampBlend)\n\t\tregInfo |= (1<<20); // BLEND_CLAMP_bit\n\tif ((uint32)(format & Latte::E_GX2SURFFMT::FMT_BIT_FLOAT) != 0)\n\t\tregInfo |= (1<<25); // ROUND_MODE_bit\n\tcolorBuffer->reg_info = regInfo;\n\t// reg color_view\n\tuint32 regView = 0;\n\tif (colorBuffer->surface.tileMode != Latte::E_GX2TILEMODE::TM_LINEAR_SPECIAL)\n\t{\n\t\tregView |= ((uint32)colorBuffer->viewFirstSlice & 0x7FF);\n\t\tregView |= ((((uint32)colorBuffer->viewNumSlices + (uint32)colorBuffer->viewFirstSlice - 1) & 0x7FF) << 13);\n\t}\n\tcolorBuffer->reg_view = regView;\n\tcolorBuffer->reg_mask = 0;\n\n\t// todo - aa stuff\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2InitDepthBufferRegs(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2InitDepthBufferRegs(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamStructPtr(depthBuffer, GX2DepthBuffer, 0);\n\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfaceInfo;\n\tLatteAddrLib::GX2CalculateSurfaceInfo(depthBuffer->surface.format, depthBuffer->surface.width, depthBuffer->surface.height, depthBuffer->surface.depth, depthBuffer->surface.dim, depthBuffer->surface.tileMode, depthBuffer->surface.aa, depthBuffer->viewMip, &surfaceInfo);\n\n\tcemu_assert_debug(depthBuffer->viewNumSlices != 0);\n\n\tuint32 cSize = ((surfaceInfo.pitch >> 3) - 1) & 0x3FF;\n\tcSize |= ((((surfaceInfo.height * surfaceInfo.pitch >> 6) - 1) & 0xFFFFF) << 10);\n\n\tdepthBuffer->reg_size = cSize;\n\t// todo - other regs\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\n\nvoid gx2Export_GX2SetColorBuffer(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetColorBuffer(0x{:08x}, {})\", hCPU->gpr[3], hCPU->gpr[4]);\n\tGX2::GX2ReserveCmdSpace(20);\n\n\tGX2ColorBuffer* colorBufferBE = (GX2ColorBuffer*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\n#ifdef CEMU_DEBUG_ASSERT\n\tcemuLog_log(LogType::GX2, \"ColorBuffer tileMode {:01x} PhysAddr {:08x} fmt {:04x} res {}x{} Mip {} Slice {}\", (uint32)colorBufferBE->surface.tileMode.value(), (uint32)colorBufferBE->surface.imagePtr, (uint32)colorBufferBE->surface.format.value(), (uint32)colorBufferBE->surface.width, (uint32)colorBufferBE->surface.height, (uint32)colorBufferBE->viewMip, (uint32)colorBufferBE->viewFirstSlice);\n#endif\n\n\tuint32 targetIndex = hCPU->gpr[4];\n\n\tuint32 viewMip = colorBufferBE->viewMip;\n\tuint32 colorBufferBase = memory_virtualToPhysical(colorBufferBE->surface.imagePtr);\n\n\tif( viewMip != 0 )\n\t{\n\t\tuint32 baseImagePtr = colorBufferBE->surface.mipPtr;\n\t\tif( viewMip == 1 )\n\t\t\tcolorBufferBase = memory_virtualToPhysical(baseImagePtr);\n\t\telse\n\t\t\tcolorBufferBase = memory_virtualToPhysical(baseImagePtr+colorBufferBE->surface.mipOffset[viewMip-1]);\n\n\t}\n\n\tLatte::E_GX2TILEMODE tileMode = colorBufferBE->surface.tileMode;\n\tuint32 viewMipIndex = colorBufferBE->viewMip;\n\tuint32 swizzle = colorBufferBE->surface.swizzle;\n\n\tif (Latte::TM_IsMacroTiled(tileMode) && viewMipIndex < ((swizzle >> 16) & 0xFF))\n\t{\n\t\t// remove swizzle for small mips\n\t\tcolorBufferBase ^= (swizzle & 0xFFFF);\n\t}\n\t// set color buffer pointer for render target\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\tgx2WriteGather_submitU32AsBE(mmCB_COLOR0_BASE - 0xA000 + hCPU->gpr[4]);\n\tgx2WriteGather_submitU32AsBE(colorBufferBase);\n\t// set color buffer size\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\tgx2WriteGather_submitU32AsBE(mmCB_COLOR0_SIZE - 0xA000 + hCPU->gpr[4]);\n\tgx2WriteGather_submitU32AsBE((uint32)colorBufferBE->reg_size);\n\n\tcemu_assert_debug(tileMode != Latte::E_GX2TILEMODE::TM_LINEAR_SPECIAL);\n\n\t// set mmCB_COLOR*_VIEW\n\tgx2WriteGather_submit(\n\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\tmmCB_COLOR0_VIEW - 0xA000 + hCPU->gpr[4],\n\t\tcolorBufferBE->reg_view);\n\n\t// todo: mmCB_COLOR0_TILE and mmCB_COLOR0_FRAG\n\n\t// set mmCB_COLOR*_INFO\n\tgx2WriteGather_submit(\n\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\tmmCB_COLOR0_INFO - 0xA000 + hCPU->gpr[4],\n\t\tcolorBufferBE->reg_info);\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SetDepthBuffer(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetDepthBuffer(0x{:08x})\", hCPU->gpr[3]);\n\tGX2::GX2ReserveCmdSpace(20);\n\n\tGX2DepthBuffer* depthBufferBE = (GX2DepthBuffer*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\n\tcemuLog_log(LogType::GX2, \"DepthBuffer tileMode {:01x} PhysAddr {:08x} fmt {:04x} res {}x{}\", (uint32)depthBufferBE->surface.tileMode.value(), (uint32)depthBufferBE->surface.imagePtr, (uint32)depthBufferBE->surface.format.value(), (uint32)depthBufferBE->surface.width, (uint32)depthBufferBE->surface.height);\n\n\tuint32 viewMip = depthBufferBE->viewMip;\n\n\t// todo: current code for the PM4 packets is a hack, replace with proper implementation\n\n\tuint32 regHTileDataBase = memory_virtualToPhysical(depthBufferBE->surface.imagePtr)>>8;\n\n\tif( viewMip > 0 )\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"GX2SetDepthBuffer: Unsupported non-zero mip ({}) Pointer: {:08x} Base: {:08x}\", viewMip, regHTileDataBase, 0);\n\t}\n\n\t// setup depthbuffer info register\n\tuint32 regDepthBufferInfo = 0;\n\tuint32 depthBufferTileMode = (uint32)depthBufferBE->surface.tileMode.value();\n\tLatte::E_GX2SURFFMT depthBufferFormat = depthBufferBE->surface.format;\n\n\tregDepthBufferInfo |= ((depthBufferTileMode&0xF)<<15);\n\tif (depthBufferFormat == Latte::E_GX2SURFFMT::D16_UNORM)\n\t\tregDepthBufferInfo |= (1 << 0);\n\telse if (depthBufferFormat == Latte::E_GX2SURFFMT::D24_S8_UNORM)\n\t\tregDepthBufferInfo |= (3 << 0);\n\telse if (depthBufferFormat == Latte::E_GX2SURFFMT::D32_FLOAT)\n\t\tregDepthBufferInfo |= (6 << 0);\n\telse if (depthBufferFormat == Latte::E_GX2SURFFMT::D32_S8_FLOAT)\n\t\tregDepthBufferInfo |= (7 << 0);\n\telse if (depthBufferFormat == Latte::E_GX2SURFFMT::D24_S8_FLOAT)\n\t\tregDepthBufferInfo |= (5 << 0);\n\telse\n\t{\n\t\tdebug_printf(\"Unsupported depth buffer format 0x%04x\\n\", depthBufferFormat);\n\t}\n\n\t// set color buffer pointer for render target\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1+1));\n\tgx2WriteGather_submitU32AsBE(mmDB_DEPTH_SIZE - 0xA000);\n\tgx2WriteGather_submitU32AsBE((uint32)depthBufferBE->reg_size); // hack\n\t// set color buffer size\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1+3));\n\tgx2WriteGather_submitU32AsBE(mmDB_DEPTH_BASE - 0xA000);\n\n\tgx2WriteGather_submitU32AsBE(0); // DB_DEPTH_BASE\n\tgx2WriteGather_submitU32AsBE(regDepthBufferInfo); // DB_DEPTH_INFO\n\tgx2WriteGather_submitU32AsBE(regHTileDataBase); // DB_HTILE_DATA_BASE\n\n\t// set DB_DEPTH_VIEW\n\tuint32 db_view = 0;\n\tdb_view |= ((uint32)depthBufferBE->viewFirstSlice&0x7FF);\n\tdb_view |= ((((uint32)depthBufferBE->viewNumSlices+(uint32)depthBufferBE->viewFirstSlice-1)&0x7FF)<<13);\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\tgx2WriteGather_submitU32AsBE(mmDB_DEPTH_VIEW - 0xA000);\n\tgx2WriteGather_submitU32AsBE(db_view);\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SetDRCBuffer(PPCInterpreter_t* hCPU)\n{\n\tLatte::E_GX2SURFFMT format = (Latte::E_GX2SURFFMT)hCPU->gpr[6];\n\tLatteGPUState.drcBufferUsesSRGB = HAS_FLAG(format, Latte::E_GX2SURFFMT::FMT_BIT_SRGB);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2MarkScanBufferCopied(PPCInterpreter_t* hCPU)\n{\n\tuint32 scanTarget = hCPU->gpr[3];\n\tif( scanTarget == GX2_SCAN_TARGET_TV )\n\t{\n\t\tGX2::GX2ReserveCmdSpace(10);\n\n\t\tuint32 physAddr = (MEMORY_TILINGAPERTURE_AREA_ADDR+0x200000);\n\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_COPY_COLORBUFFER_TO_SCANBUFFER, 9));\n\t\tgx2WriteGather_submitU32AsBE(physAddr);\n\t\tgx2WriteGather_submitU32AsBE(1920);\n\t\tgx2WriteGather_submitU32AsBE(1080);\n\n\t\tgx2WriteGather_submitU32AsBE(1920); // pitch\n\t\tgx2WriteGather_submitU32AsBE(4); // tileMode\n\t\tgx2WriteGather_submitU32AsBE(0); // swizzle\n\n\t\tgx2WriteGather_submitU32AsBE(0);\n\t\tgx2WriteGather_submitU32AsBE((uint32)Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM);\n\t\tgx2WriteGather_submitU32AsBE(scanTarget);\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Resource.cpp",
    "content": "#include \"Cafe/HW/Latte/Core/LatteBufferCache.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"GX2.h\"\n#include \"GX2_Command.h\"\n#include \"GX2_Resource.h\"\n#include \"GX2_Streamout.h\"\n#include \"GX2_Draw.h\"\n\nnamespace GX2\n{\n\n\tMPTR GX2RAllocateFunc = MPTR_NULL;\n\tMPTR GX2RFreeFunc = MPTR_NULL;\n\n\tvoid GX2RSetAllocator(MPTR funcAllocMPTR, MPTR funcFreeMPR)\n\t{\n\t\tGX2RAllocateFunc = funcAllocMPTR;\n\t\tGX2RFreeFunc = funcFreeMPR;\n\t}\n\n\tuint32 GX2RGetBufferAllocationSize(GX2RBuffer* buffer)\n\t{\n\t\treturn (buffer->GetSize() + 0x3F) & ~0x3F; // pad to 64 byte alignment\n\t}\n\n\tuint32 GX2RGetBufferAlignment(uint32 resFlags)\n\t{\n\t\tif ((resFlags & GX2R_RESFLAG_USAGE_STREAM_OUTPUT) != 0)\n\t\t\treturn 0x100;\n\t\tif ((resFlags & GX2R_RESFLAG_USAGE_UNIFORM_BLOCK) != 0)\n\t\t\treturn 0x100;\n\t\tif ((resFlags & GX2R_RESFLAG_USAGE_SHADER_PROGRAM) != 0)\n\t\t\treturn 0x100;\n\t\tif ((resFlags & GX2R_RESFLAG_USAGE_GS_RINGBUFFER) != 0)\n\t\t\treturn 0x100;\n\n\t\tif ((resFlags & GX2R_RESFLAG_USAGE_VERTEX_BUFFER) != 0)\n\t\t\treturn 0x40;\n\t\tif ((resFlags & GX2R_RESFLAG_USAGE_INDEX_BUFFER) != 0)\n\t\t\treturn 0x40;\n\t\tif ((resFlags & GX2R_RESFLAG_USAGE_DISPLAY_LIST) != 0)\n\t\t\treturn 0x40;\n\n\t\treturn 0x100;\n\t}\n\n\tbool GX2RCreateBuffer(GX2RBuffer* buffer)\n\t{\n\t\tuint32 bufferAlignment = GX2RGetBufferAlignment(buffer->resFlags);\n\t\tuint32 bufferSize = GX2RGetBufferAllocationSize(buffer);\n\t\tMPTR allocResult = PPCCoreCallback(GX2RAllocateFunc, (uint32)buffer->resFlags, bufferSize, bufferAlignment);\n\t\tbuffer->ptr = allocResult;\n\t\tbuffer->resFlags &= ~GX2R_RESFLAG_LOCKED;\n\t\tbuffer->resFlags |= GX2R_RESFLAG_ALLOCATED_BY_GX2R;\n\t\t// todo: invalidation\n\t\treturn allocResult != MPTR_NULL;\n\t}\n\n\tbool GX2RCreateBufferUserMemory(GX2RBuffer* buffer, void* ptr, uint32 unusedSizeParameter)\n\t{\n\t\tbuffer->ptr = ptr;\n\t\tbuffer->resFlags &= ~GX2R_RESFLAG_LOCKED;\n\t\tbuffer->resFlags &= ~GX2R_RESFLAG_ALLOCATED_BY_GX2R;\n\t\t// todo: invalidation\n\t\treturn true;\n\t}\n\n\tvoid GX2RDestroyBufferEx(GX2RBuffer* buffer, uint32 resFlags)\n\t{\n\t\tif ((buffer->resFlags & GX2R_RESFLAG_ALLOCATED_BY_GX2R) == 0)\n\t\t{\n\t\t\t// this buffer is user-allocated\n\t\t\tbuffer->ptr = nullptr;\n\t\t\treturn;\n\t\t}\n\t\tPPCCoreCallback(GX2RFreeFunc, (uint32)buffer->resFlags, buffer->GetPtr());\n\t\tbuffer->ptr = nullptr;\n\t}\n\n\tbool GX2RBufferExists(GX2RBuffer* buffer)\n\t{\n\t\tif (!buffer)\n\t\t\treturn false;\n\t\tif (!buffer->GetPtr())\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\tvoid GX2RSetBufferName(GX2RBuffer* buffer, const char* name)\n\t{\n\t\t// no-op in production builds\n\t}\n\n\tvoid* GX2RLockBufferEx(GX2RBuffer* buffer, uint32 resFlags)\n\t{\n\t\treturn buffer->GetPtr();\n\t}\n\n\tvoid GX2RUnlockBufferEx(GX2RBuffer* buffer, uint32 resFlags)\n\t{\n\t\t// todo - account for flags, not all buffer types need flushing\n\t\tLatteBufferCache_notifyDCFlush(buffer->GetVirtualAddr(), buffer->GetSize());\n\t}\n\n\tvoid GX2RInvalidateBuffer(GX2RBuffer* buffer, uint32 resFlags)\n\t{\n\t\t// todo - account for flags, not all buffer types need flushing\n\t\tLatteBufferCache_notifyDCFlush(buffer->GetVirtualAddr(), buffer->GetSize());\n\t}\n\n\tvoid GX2RSetAttributeBuffer(GX2RBuffer* buffer, uint32 bufferIndex, uint32 stride, uint32 offset)\n\t{\n\t\tuint32 bufferSize = buffer->GetSize();\n\t\tif (offset > bufferSize)\n\t\t\tcemuLog_log(LogType::Force, \"GX2RSetAttributeBuffer(): Offset exceeds buffer size\");\n\t\tGX2SetAttribBuffer(bufferIndex, bufferSize - offset, stride, ((uint8be*)buffer->GetPtr()) + offset);\n\t}\n\n\tvoid GX2RSetStreamOutBuffer(uint32 bufferIndex, GX2StreamOutBuffer* soBuffer)\n\t{\n\t\t// seen in CoD: Ghosts and CoD: Black Ops 2\n\t\tGX2SetStreamOutBuffer(bufferIndex, soBuffer);\n\t}\n\n\tbool GX2RCreateSurface(GX2Surface* surface, uint32 resFlags)\n\t{\n\t\t// seen in Transformers Prime\n\t\tsurface->resFlag = resFlags;\n\t\tGX2CalcSurfaceSizeAndAlignment(surface);\n\t\tsurface->resFlag &= ~GX2R_RESFLAG_LOCKED;\n\t\tsurface->resFlag |= GX2R_RESFLAG_ALLOCATED_BY_GX2R;\n\t\tMPTR allocResult = PPCCoreCallback(GX2RAllocateFunc, (uint32)surface->resFlag, (uint32)surface->imageSize + (uint32)surface->mipSize, (uint32)surface->alignment);\n\t\tsurface->imagePtr = allocResult;\n\t\tif (surface->imagePtr != MPTR_NULL && surface->mipSize > 0)\n\t\t{\n\t\t\tsurface->mipPtr = (uint32)surface->imagePtr + surface->imageSize;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsurface->mipPtr = MPTR_NULL;\n\t\t}\n\t\t// todo: Cache invalidation based on resourceFlags?\n\t\treturn allocResult != MPTR_NULL;\n\t}\n\n\tbool GX2RCreateSurfaceUserMemory(GX2Surface* surface, void* imagePtr, void* mipPtr, uint32 resFlags)\n\t{\n\t\tsurface->resFlag = resFlags;\n\t\tsurface->resFlag &= ~(GX2R_RESFLAG_LOCKED | GX2R_RESFLAG_ALLOCATED_BY_GX2R);\n\t\tGX2CalcSurfaceSizeAndAlignment(surface);\n\t\tsurface->imagePtr = memory_getVirtualOffsetFromPointer(imagePtr);\n\t\tsurface->mipPtr = memory_getVirtualOffsetFromPointer(mipPtr);\n\t\tif (surface->resFlag & 0x14000)\n\t\t{\n\t\t\t// memory invalidate\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid GX2RDestroySurfaceEx(GX2Surface* surface, uint32 resFlags)\n\t{\n\t\tif ((surface->resFlag & GX2R_RESFLAG_ALLOCATED_BY_GX2R) == 0)\n\t\t{\n\t\t\t// this surface is user-allocated\n\t\t\tsurface->imagePtr = MPTR_NULL;\n\t\t\treturn;\n\t\t}\n\t\tresFlags &= (GX2R_RESFLAG_UKN_BIT_19 | GX2R_RESFLAG_UKN_BIT_20 | GX2R_RESFLAG_UKN_BIT_21 | GX2R_RESFLAG_UKN_BIT_22 | GX2R_RESFLAG_UKN_BIT_23);\n\t\tPPCCoreCallback(GX2RFreeFunc, (uint32)surface->resFlag | resFlags, (uint32)surface->imagePtr);\n\t\tsurface->imagePtr = MPTR_NULL;\n\t}\n\n\tbool GX2RSurfaceExists(GX2Surface* surface)\n\t{\n\t\tif (!surface)\n\t\t\treturn false;\n\t\tif (surface->imagePtr == MPTR_NULL)\n\t\t\treturn false;\n\t\tif ((surface->resFlag & (GX2R_RESFLAG_USAGE_CPU_READ | GX2R_RESFLAG_USAGE_CPU_WRITE | GX2R_RESFLAG_USAGE_GPU_READ | GX2R_RESFLAG_USAGE_GPU_WRITE)) == 0)\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\tvoid* GX2RLockSurfaceEx(GX2Surface* surface, uint32 mipLevel, uint32 resFlags)\n\t{\n\t\t// todo: handle invalidation\n\t\tsurface->resFlag |= GX2R_RESFLAG_LOCKED;\n\t\treturn memory_getPointerFromVirtualOffset(surface->imagePtr);\n\t}\n\n\tvoid GX2RUnlockSurfaceEx(GX2Surface* surface, uint32 mipLevel, uint32 resFlags)\n\t{\n\t\t// todo: handle invalidation\n\t\tsurface->resFlag &= ~GX2R_RESFLAG_LOCKED;\n\t}\n\n\tvoid GX2RBeginDisplayListEx(GX2RBuffer* buffer, bool ukn, uint32 resFlags)\n\t{\n\t\t// todo: handle invalidation\n\t\tGX2::GX2BeginDisplayList(buffer->GetPtr(), buffer->GetSize());\n\t}\n\n\tuint32 GX2REndDisplayList(GX2RBuffer* buffer)\n\t{\n\t\treturn GX2::GX2EndDisplayList(buffer->GetPtr());\n\t}\n\n\tvoid GX2RCallDisplayList(GX2RBuffer* buffer, uint32 size)\n\t{\n\t\tGX2::GX2CallDisplayList(buffer->GetVirtualAddr(), size);\n\t}\n\n\tvoid GX2RDirectCallDisplayList(GX2RBuffer* buffer, uint32 size)\n\t{\n\t\tGX2::GX2DirectCallDisplayList(buffer->GetPtr(), size);\n\t}\n\n\tvoid GX2RDrawIndexed(GX2PrimitiveMode2 primitiveMode, GX2RBuffer* indexBuffer, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, uint32 count, uint32 baseIndex, uint32 baseVertex, uint32 numInstances)\n\t{\n\t\tGX2DrawIndexedEx(primitiveMode, count, indexType, (uint8be*)indexBuffer->GetPtr() + (baseIndex * (uint32)indexBuffer->elementSize), baseVertex, numInstances);\n\t}\n\n\tvoid GX2ResourceInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2RSetAllocator, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RGetBufferAllocationSize, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RGetBufferAlignment, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2RCreateBuffer, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RCreateBufferUserMemory, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RDestroyBufferEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RBufferExists, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RSetBufferName, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RLockBufferEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RUnlockBufferEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RInvalidateBuffer, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2RSetAttributeBuffer, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RSetStreamOutBuffer, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2RCreateSurface, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RCreateSurfaceUserMemory, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RDestroySurfaceEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RSurfaceExists, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RLockSurfaceEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RUnlockSurfaceEx, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2RBeginDisplayListEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2REndDisplayList, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RCallDisplayList, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2RDirectCallDisplayList, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2RDrawIndexed, LogType::GX2);\n\n\t\tGX2RAllocateFunc = MPTR_NULL;\n\t\tGX2RFreeFunc = MPTR_NULL;\n\t}\n};"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Resource.h",
    "content": "#pragma once\n\n// basic resource flags\n#define GX2_RESFLAG_USAGE_TEXTURE\t\t\t\t\t(1<<0)\n#define GX2_RESFLAG_USAGE_COLOR_BUFFER\t\t\t\t(1<<1)\n#define GX2_RESFLAG_USAGE_DEPTH_BUFFER\t\t\t\t(1<<2)\n#define GX2_RESFLAG_USAGE_SCAN_BUFFER\t\t\t\t(1<<3)\n\n// extended resource flags used by GX2R API\n#define GX2R_RESFLAG_USAGE_VERTEX_BUFFER\t\t\t(1<<4)\n#define GX2R_RESFLAG_USAGE_INDEX_BUFFER\t\t\t\t(1<<5)\n#define GX2R_RESFLAG_USAGE_UNIFORM_BLOCK\t\t\t(1<<6)\n#define GX2R_RESFLAG_USAGE_SHADER_PROGRAM\t\t\t(1<<7)\n#define GX2R_RESFLAG_USAGE_STREAM_OUTPUT\t\t\t(1<<8)\n#define GX2R_RESFLAG_USAGE_DISPLAY_LIST\t\t\t\t(1<<9)\n#define GX2R_RESFLAG_USAGE_GS_RINGBUFFER\t\t\t(1<<10)\n\n#define GX2R_RESFLAG_USAGE_CPU_READ\t\t\t\t\t(1<<11)\n#define GX2R_RESFLAG_USAGE_CPU_WRITE\t\t\t\t(1<<12)\n#define GX2R_RESFLAG_USAGE_GPU_READ\t\t\t\t\t(1<<13)\n#define GX2R_RESFLAG_USAGE_GPU_WRITE\t\t\t\t(1<<14)\n\n#define GX2R_RESFLAG_USE_MEM1\t\t\t\t\t\t(1<<17)\n\n#define GX2R_RESFLAG_UKN_BIT_19\t\t\t\t\t\t(1<<19)\n#define GX2R_RESFLAG_UKN_BIT_20\t\t\t\t\t\t(1<<20)\n#define GX2R_RESFLAG_UKN_BIT_21\t\t\t\t\t\t(1<<21)\n#define GX2R_RESFLAG_UKN_BIT_22\t\t\t\t\t\t(1<<22)\n#define GX2R_RESFLAG_UKN_BIT_23\t\t\t\t\t\t(1<<23)\n\n#define GX2R_RESFLAG_ALLOCATED_BY_GX2R\t\t\t\t(1<<29)\n#define GX2R_RESFLAG_LOCKED\t\t\t\t\t\t\t(1<<30)\n\nstruct GX2RBuffer\n{\n\t/* +0x00 */ uint32be\t\tresFlags;\n\t/* +0x04 */ uint32be\t\telementSize;\n\t/* +0x08 */ uint32be\t\telementCount;\n\t/* +0x0C */ MEMPTR<void>\tptr;\n\n\tuint32 GetSize() const\n\t{\n\t\treturn (uint32)elementSize * (uint32)elementCount;\n\t}\n\n\tMPTR GetVirtualAddr() const\n\t{\n\t\treturn ptr.GetMPTR();\n\t}\n\n\tvoid* GetPtr() const\n\t{\n\t\treturn ptr.GetPtr();\n\t}\n};\n\nstatic_assert(sizeof(GX2RBuffer) == 0x10);\n\nnamespace GX2\n{\n\tvoid GX2ResourceInit();\n\n\tvoid GX2RSetAllocator(MPTR funcAllocMPTR, MPTR funcFreeMPR);\n};"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Shader.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"GX2.h\"\n#include \"GX2_Shader.h\"\n#include \"Cafe/HW/Latte/Core/LatteConst.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/ISA/LatteInstructions.h\"\n\nuint32 memory_getVirtualOffsetFromPointer(void* ptr); // remove once we updated everything to MEMPTR\n\nnamespace GX2\n{\n\tusing namespace Latte;\n\n\tLatteConst::VertexFetchEndianMode _getVtxFormatEndianSwapDefault(uint32 vertexFormat)\n\t{\n\t\tswitch (vertexFormat)\n\t\t{\n\t\tcase 0:\n\t\tcase 1:\n\t\tcase 4:\n\t\tcase 10:\n\t\t\treturn LatteConst::VertexFetchEndianMode::SWAP_NONE; // 0\n\t\tcase 2:\n\t\tcase 3:\n\t\tcase 7:\n\t\tcase 8:\n\t\tcase 14:\n\t\tcase 15:\n\t\t\treturn LatteConst::VertexFetchEndianMode::SWAP_U16; // 1\n\t\tcase 5:\n\t\tcase 6:\n\t\tcase 9:\n\t\tcase 11:\n\t\tcase 12:\n\t\tcase 13:\n\t\tcase 16:\n\t\tcase 17:\n\t\tcase 18:\n\t\tcase 19:\n\t\t\treturn LatteConst::VertexFetchEndianMode::SWAP_U32; // 2\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t\tcemu_assert_suspicious();\n\t\treturn LatteConst::VertexFetchEndianMode::SWAP_NONE;\n\t}\n\n\tuint32 rawFormatToFetchFormat[] =\n\t{\n\t\t1, 2, 5, 6,\n\t\t7, 0xD, 0xE, 0xF,\n\t\t0x10, 0x16, 0x1A, 0x19,\n\t\t0x1D, 0x1E, 0x1F, 0x20,\n\t\t0x2F, 0x30, 0x22, 0x23,\n\t};\n\n\tstruct GX2AttribDescription\n\t{\n\t\t/* +0x00 */ uint32 location;\n\t\t/* +0x04 */ uint32 buffer;\n\t\t/* +0x08 */ uint32be offset;\n\t\t/* +0x0C */ uint32 format;\n\t\t/* +0x10 */ uint32 indexType;\n\t\t/* +0x14 */ uint32 aluDivisor;\n\t\t/* +0x18 */ uint32 destSel;\n\t\t/* +0x1C */ betype<LatteConst::VertexFetchEndianMode> endianSwap;\n\t};\n\n\tstatic_assert(sizeof(GX2AttribDescription) == 0x20);\n\tstatic_assert(sizeof(betype<LatteConst::VertexFetchEndianMode>) == 0x4);\n\n\t// calculate size of CF program subpart, includes alignment padding for clause instructions\n\tsize_t _calcFetchShaderCFCodeSize(uint32 attributeCount, GX2FetchShader::FetchShaderType fetchShaderType, uint32 tessellationMode)\n\t{\n\t\tcemu_assert_debug(fetchShaderType == GX2FetchShader::FetchShaderType::NO_TESSELATION);\n\t\tcemu_assert_debug(tessellationMode == 0);\n\t\tuint32 numCFInstructions = ((attributeCount + 15) / 16) + 1; // one VTX clause can have up to 16 instructions + final CF instruction is RETURN\n\t\tsize_t cfSize = numCFInstructions * 8;\n\t\tcfSize = (cfSize + 0xF) & ~0xF; // pad to 16 byte alignment\n\t\treturn cfSize;\n\t}\n\n\tsize_t _calcFetchShaderClauseCodeSize(uint32 attributeCount, GX2FetchShader::FetchShaderType fetchShaderType, uint32 tessellationMode)\n\t{\n\t\tcemu_assert_debug(fetchShaderType == GX2FetchShader::FetchShaderType::NO_TESSELATION);\n\t\tcemu_assert_debug(tessellationMode == 0);\n\t\tuint32 numClauseInstructions = attributeCount;\n\t\tsize_t clauseSize = numClauseInstructions * 16;\n\t\treturn clauseSize;\n\t}\n\n\tvoid _writeFetchShaderCFCode(void* programBufferOut, uint32 attributeCount, GX2FetchShader::FetchShaderType fetchShaderType, uint32 tessellationMode)\n\t{\n\t\tLatteCFInstruction* cfInstructionWriter = (LatteCFInstruction*)programBufferOut;\n\t\tuint32 attributeIndex = 0;\n\t\tuint32 cfSize = (uint32)_calcFetchShaderCFCodeSize(attributeCount, fetchShaderType, tessellationMode);\n\t\twhile (attributeIndex < attributeCount)\n\t\t{\n\t\t\tLatteCFInstruction_DEFAULT defaultInstr;\n\t\t\tdefaultInstr.setField_Opcode(LatteCFInstruction::INST_VTX_TC);\n\t\t\tdefaultInstr.setField_COUNT(std::min(attributeCount - attributeIndex, 16u));\n\t\t\tdefaultInstr.setField_ADDR(cfSize + attributeIndex*16);\n\t\t\tmemcpy(cfInstructionWriter, &defaultInstr, sizeof(LatteCFInstruction));\n\t\t\tattributeIndex += 16;\n\t\t\tcfInstructionWriter++;\n\t\t}\n\t\t// write RETURN instruction\n\t\tLatteCFInstruction_DEFAULT returnInstr;\n\t\treturnInstr.setField_Opcode(LatteCFInstruction::INST_RETURN);\n\t\treturnInstr.setField_BARRIER(true);\n\t\tmemcpy(cfInstructionWriter, &returnInstr, sizeof(LatteCFInstruction));\n\t}\n\n\tvoid _writeFetchShaderVTXCode(GX2FetchShader* fetchShader, void* programOut, uint32 attributeCount, GX2AttribDescription* attributeDescription, GX2FetchShader::FetchShaderType fetchShaderType, uint32 tessellationMode)\n\t{\n\t\tuint8* writePtr = (uint8*)programOut;\n\t\t// one instruction per attribute (hardcoded into _writeFetchShaderCFCode)\n\t\tfor (uint32 i = 0; i < attributeCount; i++)\n\t\t{\n\t\t\tuint32 attrFormat = _swapEndianU32(attributeDescription[i].format);\n\t\t\tuint32 attrDestSel = _swapEndianU32(attributeDescription[i].destSel);\n\t\t\tuint32 attrLocation = _swapEndianU32(attributeDescription[i].location);\n\t\t\tuint32 attrBufferId = _swapEndianU32(attributeDescription[i].buffer);\n\t\t\tuint32 attrIndexType = _swapEndianU32(attributeDescription[i].indexType);\n\t\t\tuint32 attrAluDivisor = _swapEndianU32(attributeDescription[i].aluDivisor);\n\n\t\t\tcemu_assert_debug(attrIndexType <= 1);\n\n\t\t\tLatteConst::VertexFetchEndianMode endianSwap = attributeDescription[i].endianSwap;\n\t\t\tif (endianSwap == LatteConst::VertexFetchEndianMode::SWAP_DEFAULT) // use per-format default\n\t\t\t\tendianSwap = _getVtxFormatEndianSwapDefault(attrFormat & 0x3F);\n\n\t\t\tuint32 srcSelX = 0; // this field is used to store the divisor index/mode (0 -> per-vertex index, 1 -> alu divisor 0, 2 -> alu divisor 1, 3 -> per-instance index)\n\t\t\tif (attrIndexType == 0)\n\t\t\t{\n\t\t\t\tsrcSelX = 0; // increase index per vertex\n\t\t\t}\n\t\t\telse if (attrIndexType == 1)\n\t\t\t{\n\t\t\t\t// instance based index\n\t\t\t\tif (attrAluDivisor == 1)\n\t\t\t\t{\n\t\t\t\t\t// special encoding if alu divisor is 1\n\t\t\t\t\tsrcSelX = 3;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(attrAluDivisor != 0); // divisor should not be zero if instance based index is selected?\n\t\t\t\t\t// store alu divisor in divisor table (up to two entries)\n\t\t\t\t\tuint32 numDivisors = _swapEndianU32(fetchShader->divisorCount);\n\t\t\t\t\tbool divisorFound = false;\n\t\t\t\t\tfor (uint32 i = 0; i < numDivisors; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (fetchShader->divisors[i] == attrAluDivisor)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsrcSelX = i != 0 ? 2 : 1;\n\t\t\t\t\t\t\tdivisorFound = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (divisorFound == false)\n\t\t\t\t\t{\n\t\t\t\t\t\t// add new divisor\n\t\t\t\t\t\tif (numDivisors >= 2)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemu_assert_debug(false); // not enough space for additional divisor\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsrcSelX = numDivisors != 0 ? 2 : 1;\n\t\t\t\t\t\t\tfetchShader->divisors[numDivisors] = attrAluDivisor;\n\t\t\t\t\t\t\tnumDivisors++;\n\t\t\t\t\t\t\tfetchShader->divisorCount = _swapEndianU32(numDivisors);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\n\t\t\t// convert attribute format to fetch format\n\t\t\tuint32 fetchFormat = rawFormatToFetchFormat[attrFormat & 0x3F] & 0x3F;\n\n\t\t\tuint32 nfa = 0;\n\t\t\tif ((attrFormat & 0x800) != 0)\n\t\t\t\tnfa = 2;\n\t\t\telse if ((attrFormat & 0x100) != 0)\n\t\t\t\tnfa = 1;\n\t\t\telse\n\t\t\t\tnfa = 0;\n\n\t\t\tLatteClauseInstruction_VTX vtxInstruction;\n\t\t\tvtxInstruction.setField_VTX_INST(LatteClauseInstruction_VTX::VTX_INST::_VTX_INST_SEMANTIC);\n\t\t\tvtxInstruction.setFieldSEM_SEMANTIC_ID(attrLocation&0xFF);\n\t\t\tvtxInstruction.setField_BUFFER_ID(attrBufferId + 0xA0);\n\t\t\tvtxInstruction.setField_FETCH_TYPE((LatteConst::VertexFetchType2)attrIndexType);\n\t\t\tvtxInstruction.setField_SRC_SEL_X((LatteClauseInstruction_VTX::SRC_SEL)srcSelX);\n\t\t\tvtxInstruction.setField_DATA_FORMAT((LatteConst::VertexFetchFormat)fetchFormat);\n\t\t\tvtxInstruction.setField_NUM_FORMAT_ALL((LatteClauseInstruction_VTX::NUM_FORMAT_ALL)nfa);\n\t\t\tvtxInstruction.setField_OFFSET(attributeDescription[i].offset);\n\t\t\tif ((attrFormat & 0x200) != 0)\n\t\t\t\tvtxInstruction.setField_FORMAT_COMP_ALL(LatteClauseInstruction_VTX::FORMAT_COMP::COMP_SIGNED);\n\t\t\tvtxInstruction.setField_ENDIAN_SWAP((LatteConst::VertexFetchEndianMode)endianSwap);\n\t\t\tvtxInstruction.setField_DST_SEL(0, (LatteClauseInstruction_VTX::DST_SEL)((attrDestSel >> 24) & 0x7));\n\t\t\tvtxInstruction.setField_DST_SEL(1, (LatteClauseInstruction_VTX::DST_SEL)((attrDestSel >> 16) & 0x7));\n\t\t\tvtxInstruction.setField_DST_SEL(2, (LatteClauseInstruction_VTX::DST_SEL)((attrDestSel >> 8) & 0x7));\n\t\t\tvtxInstruction.setField_DST_SEL(3, (LatteClauseInstruction_VTX::DST_SEL)((attrDestSel >> 0) & 0x7));\n\n\t\t\tmemcpy(writePtr, &vtxInstruction, 16);\n\t\t\twritePtr += 16;\n\t\t}\n\t}\n\n\tuint32 GX2CalcFetchShaderSizeEx(uint32 attributeCount, GX2FetchShader::FetchShaderType fetchShaderType, uint32 tessellationMode)\n\t{\n\t\tcemu_assert_debug(fetchShaderType == GX2FetchShader::FetchShaderType::NO_TESSELATION); // other types are todo\n\t\tcemu_assert_debug(tessellationMode == 0); // other modes are todo\n\n\t\tuint32 finalSize =\n\t\t\t(uint32)_calcFetchShaderCFCodeSize(attributeCount, fetchShaderType, tessellationMode) +\n\t\t\t(uint32)_calcFetchShaderClauseCodeSize(attributeCount, fetchShaderType, tessellationMode);\n\n\t\treturn finalSize;\n\t}\n\n\tvoid GX2InitFetchShaderEx(GX2FetchShader* fetchShader, void* programBufferOut, uint32 attributeCount, GX2AttribDescription* attributeDescription, GX2FetchShader::FetchShaderType fetchShaderType, uint32 tessellationMode)\n\t{\n\t\tcemu_assert_debug(fetchShaderType == GX2FetchShader::FetchShaderType::NO_TESSELATION);\n\t\tcemu_assert_debug(tessellationMode == 0);\n\n\t\t/*\n\t\t\tFetch shader program:\n\t\t\t[CF_PROGRAM]\n\t\t\t[Last CF instruction: 0x0 0x8A000000 (INST_RETURN)]\n\t\t\t[PAD_TO_16_ALIGNMENT]\n\t\t\t[CLAUSES]\n\t\t*/\n\n\t\tmemset(fetchShader, 0x00, sizeof(GX2FetchShader));\n\t\tfetchShader->attribCount = _swapEndianU32(attributeCount);\n\t\tfetchShader->shaderPtr = (MPTR)_swapEndianU32(memory_getVirtualOffsetFromPointer(programBufferOut));\n\n\t\tuint8* shaderStart = (uint8*)programBufferOut;\n\t\tuint8* shaderOutput = shaderStart;\n\n\t\t_writeFetchShaderCFCode(shaderOutput, attributeCount, fetchShaderType, tessellationMode);\n\t\tshaderOutput += _calcFetchShaderCFCodeSize(attributeCount, fetchShaderType, tessellationMode);\n\t\t_writeFetchShaderVTXCode(fetchShader, shaderOutput, attributeCount, attributeDescription, fetchShaderType, tessellationMode);\n\t\tshaderOutput += _calcFetchShaderClauseCodeSize(attributeCount, fetchShaderType, tessellationMode);\n\n\t\tuint32 shaderSize = (uint32)(shaderOutput - shaderStart);\n\t\tcemu_assert_debug(shaderSize == GX2CalcFetchShaderSizeEx(attributeCount, GX2FetchShader::FetchShaderType::NO_TESSELATION, tessellationMode));\n\n\t\tfetchShader->shaderSize = _swapEndianU32((uint32)(shaderOutput - shaderStart));\n\n\t\tfetchShader->reg_SQ_PGM_RESOURCES_FS = Latte::LATTE_SQ_PGM_RESOURCES_FS().set_NUM_GPRS(2); // todo - affected by tesselation params?\n\t}\n\n\tuint32 GX2GetVertexShaderGPRs(GX2VertexShader* vertexShader)\n\t{\n\t\treturn vertexShader->regs.SQ_PGM_RESOURCES_VS.value().get_NUM_GPRS();\n\t}\n\n\tuint32 GX2GetVertexShaderStackEntries(GX2VertexShader* vertexShader)\n\t{\n\t\treturn vertexShader->regs.SQ_PGM_RESOURCES_VS.value().get_NUM_STACK_ENTRIES();\n\t}\n\n\tuint32 GX2GetPixelShaderGPRs(GX2PixelShader_t* pixelShader)\n\t{\n\t\treturn _swapEndianU32(pixelShader->regs[0])&0xFF;\n\t}\n\n\tuint32 GX2GetPixelShaderStackEntries(GX2PixelShader_t* pixelShader)\n\t{\n\t\treturn (_swapEndianU32(pixelShader->regs[0]>>8))&0xFF;\n\t}\n\n\tvoid GX2SetFetchShader(GX2FetchShader* fetchShaderPtr)\n\t{\n\t\tGX2ReserveCmdSpace(11);\n\t\tcemu_assert_debug((_swapEndianU32(fetchShaderPtr->shaderPtr) & 0xFF) == 0);\n\n\t\tgx2WriteGather_submit(\n\t\t\t\t// setup fetch shader\n\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1+5),\n\t\t\t\tLatte::REGADDR::SQ_PGM_START_FS-0xA000,\n\t\t\t\t_swapEndianU32(fetchShaderPtr->shaderPtr)>>8,\n\t\t\t\t_swapEndianU32(fetchShaderPtr->shaderSize)>>3,\n\t\t\t\t0x10000, // ukn (ring buffer size?)\n\t\t\t\t0x10000, // ukn (ring buffer size?)\n\t\t\t\tfetchShaderPtr->reg_SQ_PGM_RESOURCES_FS,\n\n\t\t\t\t// write instance step\n\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1+2),\n\t\t\t\tLatte::REGADDR::VGT_INSTANCE_STEP_RATE_0-0xA000,\n\t\t\t\tfetchShaderPtr->divisors[0],\n\t\t\t\tfetchShaderPtr->divisors[1]);\n\t}\n\n\tvoid GX2SetVertexShader(GX2VertexShader* vertexShader)\n\t{\n\t\tuint32 numOutputIds = vertexShader->regs.vsOutIdTableSize;\n\t\tnumOutputIds = std::min<uint32>(numOutputIds, 0xA);\n\t\tuint32 vsSemanticTableSize = vertexShader->regs.semanticTableSize;\n\n\t\tuint32 reserveSize = 31;\n\t\tif (vertexShader->shaderMode == GX2_SHADER_MODE::GEOMETRY_SHADER)\n\t\t{\n\t\t\treserveSize += 7;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treserveSize += 18;\n\t\t\treserveSize += numOutputIds;\n\t\t\tif (vertexShader->usesStreamOut != 0)\n\t\t\t\treserveSize += 2+12;\n\t\t}\n\t\tif (vsSemanticTableSize > 0)\n\t\t{\n\t\t\treserveSize += 5 + vsSemanticTableSize;\n\t\t}\n\t\tGX2ReserveCmdSpace(reserveSize);\n\n\t\tMPTR shaderProgramAddr;\n\t\tuint32 shaderProgramSize;\n\t\tif (vertexShader->shaderPtr)\n\t\t{\n\t\t\t// without R API\n\t\t\tshaderProgramAddr = vertexShader->shaderPtr.GetMPTR();\n\t\t\tshaderProgramSize = vertexShader->shaderSize;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tshaderProgramAddr = vertexShader->rBuffer.GetVirtualAddr();\n\t\t\tshaderProgramSize = vertexShader->rBuffer.GetSize();\n\t\t}\n\n\t\tcemu_assert_debug(shaderProgramAddr != 0);\n\t\tcemu_assert_debug(shaderProgramSize != 0);\n\n\t\tif (vertexShader->shaderMode == GX2_SHADER_MODE::GEOMETRY_SHADER)\n\t\t{\n\t\t\t// in geometry shader mode the vertex shader is written to _ES register and almost all vs control registers are set by GX2SetGeometryShader\n\t\t\tgx2WriteGather_submit(\n\t\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 6),\n\t\t\t\t\tLatte::REGADDR::SQ_PGM_START_ES-0xA000,\n\t\t\t\t\tmemory_virtualToPhysical(shaderProgramAddr)>>8,\n\t\t\t\t\tshaderProgramSize>>3,\n\t\t\t\t\t0x100000,\n\t\t\t\t\t0x100000,\n\t\t\t\t\tvertexShader->regs.SQ_PGM_RESOURCES_VS); // SQ_PGM_RESOURCES_VS/SQ_PGM_RESOURCES_ES\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgx2WriteGather_submit(\n\t\t\t\t\t/* vertex shader program */\n\t\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 6),\n\t\t\t\t\tLatte::REGADDR::SQ_PGM_START_VS-0xA000,\n\t\t\t\t\tmemory_virtualToPhysical(shaderProgramAddr)>>8, // physical address\n\t\t\t\t\tshaderProgramSize>>3,\n\t\t\t\t\t0x100000,\n\t\t\t\t\t0x100000,\n\t\t\t\t\tvertexShader->regs.SQ_PGM_RESOURCES_VS, // SQ_PGM_RESOURCES_VS/ES\n\t\t\t\t\t/* primitive id enable */\n\t\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\t\t\t\tLatte::REGADDR::VGT_PRIMITIVEID_EN-0xA000,\n\t\t\t\t\tvertexShader->regs.VGT_PRIMITIVEID_EN,\n\t\t\t\t\t/* output config */\n\t\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\t\t\t\tLatte::REGADDR::SPI_VS_OUT_CONFIG-0xA000,\n\t\t\t\t\tvertexShader->regs.SPI_VS_OUT_CONFIG,\n\t\t\t\t\t/* PA_CL_VS_OUT_CNTL */\n\t\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\t\t\t\tLatte::REGADDR::PA_CL_VS_OUT_CNTL-0xA000,\n\t\t\t\t\tvertexShader->regs.PA_CL_VS_OUT_CNTL\n\t\t\t\t\t);\n\n\t\t\tcemu_assert_debug(vertexShader->regs.SPI_VS_OUT_CONFIG.value().get_VS_PER_COMPONENT() == false); // not handled on the GPU side\n\n\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1+numOutputIds));\n\t\t\tgx2WriteGather_submitU32AsBE(Latte::REGADDR::SPI_VS_OUT_ID_0-0xA000);\n\t\t\tfor(uint32 i=0; i<numOutputIds; i++)\n\t\t\t\tgx2WriteGather_submitU32AsBE(vertexShader->regs.LATTE_SPI_VS_OUT_ID_N[i].value().getRawValue());\n\n\t\t\t// todo: SQ_PGM_CF_OFFSET_VS\n\t\t\t// todo: VGT_STRMOUT_BUFFER_EN\n\t\t\t// stream out\n\t\t\tif (vertexShader->usesStreamOut != 0)\n\t\t\t{\n\t\t\t\t// stride 0\n\t\t\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\t\t\tLatte::REGADDR::VGT_STRMOUT_VTX_STRIDE_0-0xA000,\n\t\t\t\tvertexShader->streamOutVertexStride[0]>>2,\n\t\t\t\t// stride 1\n\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\t\t\tLatte::REGADDR::VGT_STRMOUT_VTX_STRIDE_1-0xA000,\n\t\t\t\tvertexShader->streamOutVertexStride[1]>>2,\n\t\t\t\t// stride 2\n\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\t\t\tLatte::REGADDR::VGT_STRMOUT_VTX_STRIDE_2-0xA000,\n\t\t\t\tvertexShader->streamOutVertexStride[2]>>2,\n\t\t\t\t// stride 3\n\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\t\t\tLatte::REGADDR::VGT_STRMOUT_VTX_STRIDE_3-0xA000,\n\t\t\t\tvertexShader->streamOutVertexStride[3]>>2);\n\t\t\t}\n\t\t}\n\t\t// update semantic table\n\t\tif (vsSemanticTableSize > 0)\n\t\t{\n\t\t\tgx2WriteGather_submit(\n\t\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1+1),\n\t\t\t\t\tLatte::REGADDR::SQ_VTX_SEMANTIC_CLEAR-0xA000,\n\t\t\t\t\t0xFFFFFFFF);\n\t\t\tif (vsSemanticTableSize == 0)\n\t\t\t{\n\t\t\t\tgx2WriteGather_submit(\n\t\t\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1+1),\n\t\t\t\t\t\tLatte::REGADDR::SQ_VTX_SEMANTIC_0-0xA000,\n\t\t\t\t\t\t0xFFFFFFFF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint32* vsSemanticTable = (uint32*)vertexShader->regs.SQ_VTX_SEMANTIC_N;\n\t\t\t\tvsSemanticTableSize = std::min<uint32>(vsSemanticTableSize, 32);\n\t\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1+vsSemanticTableSize));\n\t\t\t\tgx2WriteGather_submitU32AsBE(Latte::REGADDR::SQ_VTX_SEMANTIC_0-0xA000);\n\t\t\t\tgx2WriteGather_submitU32AsLEArray(vsSemanticTable, vsSemanticTableSize);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid _GX2SubmitUniformReg(uint32 offsetRegBase, uint32 aluRegisterOffset, uint32be* dataWords, uint32 sizeInU32s)\n\t{\n\t\tif(aluRegisterOffset&0x8000)\n\t\t{\n\t\t\tcemuLog_logDebugOnce(LogType::Force, \"_GX2SubmitUniformReg(): Unhandled loop const special case or invalid offset\");\n\t\t\treturn;\n\t\t}\n\t\tif((aluRegisterOffset+sizeInU32s) > 0x400)\n\t\t{\n\t\t\tcemuLog_logOnce(LogType::APIErrors, \"GX2SetVertexUniformReg values are out of range (offset {} + size {} must be equal or smaller than 1024)\", aluRegisterOffset, sizeInU32s);\n\t\t}\n\t\tif( (sizeInU32s&3) != 0)\n\t\t{\n\t\t\tcemuLog_logOnce(LogType::APIErrors, \"GX2Set*UniformReg must be called with a size that is a multiple of 4 (size: {:})\", sizeInU32s);\n\t\t\tsizeInU32s &= ~3;\n\t\t}\n\t\tGX2ReserveCmdSpace(2 + sizeInU32s);\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_ALU_CONST, 1 + sizeInU32s), offsetRegBase + aluRegisterOffset);\n\t\tgx2WriteGather_submitU32AsLEArray((uint32*)dataWords, sizeInU32s);\n\t}\n\n\tvoid GX2SetVertexUniformReg(uint32 offset, uint32 sizeInU32s, uint32be* values)\n\t{\n\t\t_GX2SubmitUniformReg(0x400, offset, values, sizeInU32s);\n\t}\n\n\tvoid GX2SetPixelUniformReg(uint32 offset, uint32 sizeInU32s, uint32be* values)\n\t{\n\t\t_GX2SubmitUniformReg(0, offset, values, sizeInU32s);\n\t}\n\n\tvoid GX2ShaderInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2CalcFetchShaderSizeEx, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2InitFetchShaderEx, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2GetVertexShaderGPRs, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetVertexShaderStackEntries, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetPixelShaderGPRs, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetPixelShaderStackEntries, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetFetchShader, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetVertexShader, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2SetVertexUniformReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPixelUniformReg, LogType::GX2);\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Shader.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"GX2_Streamout.h\"\n\nstruct GX2FetchShader\n{\n\tenum class FetchShaderType : uint32\n\t{\n\t\tNO_TESSELATION = 0,\n\t};\n\n\t/* +0x00 */ betype<FetchShaderType> fetchShaderType;\n\t/* +0x04 */ betype<Latte::LATTE_SQ_PGM_RESOURCES_FS> reg_SQ_PGM_RESOURCES_FS;\n\t/* +0x08 */ uint32 shaderSize;\n\t/* +0x0C */ MPTR shaderPtr;\n\t/* +0x10 */ uint32 attribCount;\n\t/* +0x14 */ uint32 divisorCount;\n\t/* +0x18 */ uint32be divisors[2];\n\n\tMPTR GetProgramAddr() const\n\t{\n\t\treturn _swapEndianU32(shaderPtr);\n\t}\n};\n\nstatic_assert(sizeof(GX2FetchShader) == 0x20);\nstatic_assert(sizeof(betype<GX2FetchShader::FetchShaderType>) == 4);\n\nnamespace GX2\n{\n\n\tvoid GX2ShaderInit();\n}\n\n// code below still needs to be modernized (use betype, enum classes, move to namespace)\n\n// deprecated, use GX2_SHADER_MODE enum class instead\n#define GX2_SHADER_MODE_UNIFORM_REGISTER\t0\n#define GX2_SHADER_MODE_UNIFORM_BLOCK\t\t1\n#define GX2_SHADER_MODE_GEOMETRY_SHADER\t\t2\n#define GX2_SHADER_MODE_COMPUTE_SHADER\t\t3\n\nenum class GX2_SHADER_MODE : uint32\n{\n\tUNIFORM_REGISTER = 0,\n\tUNIFORM_BLOCK = 1,\n\tGEOMETRY_SHADER = 2,\n\tCOMPUTE_SHADER = 3,\n};\n\nstruct GX2VertexShader\n{\n\t/* +0x000 */\n\tstruct\n\t{\n\t\t/* +0x00 */ betype<Latte::LATTE_SQ_PGM_RESOURCES_VS> SQ_PGM_RESOURCES_VS; // compatible with SQ_PGM_RESOURCES_ES\n\t\t/* +0x04 */ betype<Latte::LATTE_VGT_PRIMITIVEID_EN> VGT_PRIMITIVEID_EN;\n\t\t/* +0x08 */ betype<Latte::LATTE_SPI_VS_OUT_CONFIG> SPI_VS_OUT_CONFIG;\n\t\t/* +0x0C */ uint32be vsOutIdTableSize;\n\t\t/* +0x10 */ betype<Latte::LATTE_SPI_VS_OUT_ID_N> LATTE_SPI_VS_OUT_ID_N[10];\n\t\t/* +0x38 */ betype<Latte::LATTE_PA_CL_VS_OUT_CNTL> PA_CL_VS_OUT_CNTL;\n\t\t/* +0x3C */ uint32be uknReg15; // ?\n\t\t/* +0x40 */ uint32be semanticTableSize;\n\t\t/* +0x44 */ betype<Latte::LATTE_SQ_VTX_SEMANTIC_X> SQ_VTX_SEMANTIC_N[32];\n\t\t/* +0xC4 */ uint32be uknReg49; // ?\n\t\t/* +0xC8 */ uint32be uknReg50; // vgt_vertex_reuse_block_cntl\n\t\t/* +0xCC */ uint32be uknReg51; // vgt_hos_reuse_depth\n\t}regs;\n\t/* +0x0D0 */ uint32be shaderSize;\n\t/* +0x0D4 */ MEMPTR<void> shaderPtr;\n\t/* +0x0D8 */ betype<GX2_SHADER_MODE> shaderMode;\n\t/* +0x0DC */ uint32 uniformBlockCount;\n\t/* +0x0E0 */ MPTR uniformBlockInfo;\n\t/* +0x0E4 */ uint32 uniformVarCount;\n\t/* +0x0E8 */ MPTR uniformVarInfo;\n\t/* +0x0EC */ uint32 uknEC;\n\t/* +0x0F0 */ MPTR uknF0;\n\t/* +0x0F4 */ uint32 uknF4;\n\t/* +0x0F8 */ MPTR uknF8; // each entry has 8 byte?\n\t/* +0x0FC */ uint32\tsamplerCount;\n\t/* +0x100 */ MPTR samplerInfo;\n\t/* +0x104 */ uint32 attribCount;\n\t/* +0x108 */ MPTR attribInfo;\n\t/* +0x10C */ uint32be ringItemsize; // for GS\n\t/* +0x110 */ uint32be usesStreamOut;\n\t/* +0x114 */ uint32be streamOutVertexStride[GX2_MAX_STREAMOUT_BUFFERS];\n\t/* +0x124 */ GX2RBuffer rBuffer;\n\n\tMPTR GetProgramAddr() const\n\t{\n\t\tif (this->shaderPtr)\n\t\t\treturn this->shaderPtr.GetMPTR();\n\t\treturn this->rBuffer.GetVirtualAddr();\n\t}\n};\n\nstatic_assert(sizeof(GX2VertexShader) == 0x134);\n\ntypedef struct _GX2PixelShader\n{\n\tuint32  regs[41];\n\t// regs:\n\t// 0 ?\t\tUsed by GPR count API?\n\t// 1 ?\n\t// 2 mmSPI_PS_IN_CONTROL_0\n\t// 3 mmSPI_PS_IN_CONTROL_1\n\t// 4 numInputs\n\t// 5 mmSPI_PS_INPUT_CNTL_0\n\t// ...\n\t// 36 mmSPI_PS_INPUT_CNTL_31\n\t// 37 mmCB_SHADER_MASK\n\t// 38 mmCB_SHADER_CONTROL\n\t// 39 mmDB_SHADER_CONTROL\n\t// 40 mmSPI_INPUT_Z\n\n\t/* +0xA4 */ uint32 shaderSize;\n\t/* +0xA8 */ MPTR shaderPtr;\n\t/* +0xAC */ uint32 shaderMode;\n\t/* +0xB0 */ uint32 uniformBlockCount;\n\t/* +0xB4 */ MPTR uniformBlockInfo;\n\t/* +0xB8 */ uint32 uniformVarCount;\n\t/* +0xBC */ MPTR uniformVarInfo;\n\t/* +0xC0 */ uint32 uknC0;\n\t/* +0xC4 */ MPTR uknC4;\n\t/* +0xC8 */ uint32 uknC8;\n\t/* +0xCC */ MPTR uknCC;\n\t/* +0xD0 */ uint32 samplerCount;\n\t/* +0xD4 */ MPTR samplerInfo;\n\t/* +0xD8 */ GX2RBuffer rBuffer;\n\n\tMPTR GetProgramAddr() const\n\t{\n\t\tif (_swapEndianU32(shaderPtr) != MPTR_NULL)\n\t\t\treturn _swapEndianU32(shaderPtr);\n\t\treturn rBuffer.GetVirtualAddr();\n\t}\n}GX2PixelShader_t;\n\nstatic_assert(sizeof(GX2PixelShader_t) == 0xE8);\n\nstruct GX2GeometryShader_t\n{\n\tunion\n\t{\n\t\t/* +0x00 */ uint32 regs[19];\n\t\tstruct\n\t\t{\n\t\t\tuint32be reg0;\n\t\t\tuint32be reg1;\n\t\t\tuint32be VGT_GS_MODE;\n\t\t\tuint32be reg3;\n\t\t\tuint32be reg4;\n\t\t\tuint32be reg5;\n\t\t\tuint32be reg6;\n\t\t\tuint32be reg7;\n\t\t\t// todo\n\t\t}reg;\n\t};\n\t/* +0x4C */ uint32 shaderSize;\n\t/* +0x50 */ MPTR shaderPtr;\n\t/* +0x54 */ uint32 copyShaderSize;\n\t/* +0x58 */ MPTR copyShaderPtr;\n\t/* +0x5C */ uint32 shaderMode;\n\t/* +0x60 */ uint32 uniformBlockCount;\n\t/* +0x64 */ MPTR uniformBlockInfo;\n\t/* +0x68 */ uint32 uniformVarCount;\n\t/* +0x6C */ MPTR uniformVarInfo;\n\t/* +0x70 */ uint32 ukn70;\n\t/* +0x74 */ MPTR ukn74;\n\t/* +0x78 */ uint32 ukn78;\n\t/* +0x7C */ MPTR ukn7C;\n\t/* +0x80 */ uint32 samplerCount;\n\t/* +0x84 */ MPTR samplerInfo;\n\t/* +0x88 */ uint32 ringItemsize;\n\t/* +0x8C */ uint32 useStreamout;\n\t/* +0x90 */ uint32 streamoutStride[GX2_MAX_STREAMOUT_BUFFERS];\n\t/* +0xA0 */ GX2RBuffer rBuffer;\n\t/* +0xB0 */ GX2RBuffer rBufferCopyProgram;\n\n\tMPTR GetGeometryProgramAddr() const\n\t{\n\t\tif (_swapEndianU32(shaderPtr) != MPTR_NULL)\n\t\t\treturn _swapEndianU32(shaderPtr);\n\t\treturn rBuffer.GetVirtualAddr();\n\t}\n\n\tMPTR GetCopyProgramAddr() const\n\t{\n\t\tif (_swapEndianU32(copyShaderPtr) != MPTR_NULL)\n\t\t\treturn _swapEndianU32(copyShaderPtr);\n\t\treturn rBufferCopyProgram.GetVirtualAddr();\n\t}\n\n};\n\nstatic_assert(sizeof(GX2GeometryShader_t) == 0xC0);\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_State.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"GX2_State.h\"\n#include \"GX2_Command.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n\nnamespace GX2\n{\n\tusing namespace Latte;\n\n\tvoid GX2InitAlphaTestReg(GX2AlphaTestReg* reg, uint32 alphaTestEnable, GX2_ALPHAFUNC alphaFunc, float alphaRef)\n\t{\n\t\tLatte::LATTE_SX_ALPHA_TEST_CONTROL tmpRegCtrl;\n\t\ttmpRegCtrl.set_ALPHA_FUNC(alphaFunc);\n\t\ttmpRegCtrl.set_ALPHA_TEST_ENABLE(alphaTestEnable != 0);\n\t\treg->regAlphaTestControl = tmpRegCtrl;\n\n\t\tLatte::LATTE_SX_ALPHA_REF tmpRegRef;\n\t\ttmpRegRef.set_ALPHA_TEST_REF(alphaRef);\n\t\treg->regAlphaTestRef = tmpRegRef;\n\t}\n\n\tvoid GX2SetAlphaTestReg(GX2AlphaTestReg* reg)\n\t{\n\t\tGX2ReserveCmdSpace(3 + 3);\n\t\tgx2WriteGather_submit(\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::SX_ALPHA_TEST_CONTROL - 0xA000,\n\t\t\treg->regAlphaTestControl,\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::SX_ALPHA_REF - 0xA000,\n\t\t\treg->regAlphaTestRef);\n\t}\n\n\tvoid GX2SetAlphaTest(uint32 alphaTestEnable, GX2_ALPHAFUNC alphaFunc, float alphaRef)\n\t{\n\t\tGX2AlphaTestReg tmpReg;\n\t\tGX2InitAlphaTestReg(&tmpReg, alphaTestEnable, alphaFunc, alphaRef);\n\t\tGX2SetAlphaTestReg(&tmpReg);\n\t}\n\n\tvoid GX2InitColorControlReg(GX2ColorControlReg* reg, GX2_LOGICOP logicOp, uint32 blendMask, uint32 multiwriteEnable, uint32 colorBufferEnable)\n\t{\n\t\tLatte::LATTE_CB_COLOR_CONTROL colorControlReg2;\n\t\tcolorControlReg2.set_MULTIWRITE_ENABLE(multiwriteEnable != 0);\n\t\tif (colorBufferEnable == 0)\n\t\t\tcolorControlReg2.set_SPECIAL_OP(Latte::LATTE_CB_COLOR_CONTROL::E_SPECIALOP::DISABLE);\n\t\telse\n\t\t\tcolorControlReg2.set_SPECIAL_OP(Latte::LATTE_CB_COLOR_CONTROL::E_SPECIALOP::NORMAL);\n\t\tcolorControlReg2.set_BLEND_MASK(blendMask);\n\t\tcolorControlReg2.set_ROP(logicOp);\n\t\treg->reg = colorControlReg2;\n\t}\n\n\tvoid GX2SetColorControlReg(GX2ColorControlReg* reg)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\t\tgx2WriteGather_submit(\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::CB_COLOR_CONTROL - 0xA000,\n\t\t\treg->reg);\n\t}\n\n\tvoid GX2SetColorControl(GX2_LOGICOP logicOp, uint32 blendMask, uint32 multiwriteEnable, uint32 colorBufferEnable)\n\t{\n\t\tGX2ColorControlReg colorControlReg;\n\t\tGX2InitColorControlReg(&colorControlReg, logicOp, blendMask, multiwriteEnable, colorBufferEnable);\n\t\tGX2SetColorControlReg(&colorControlReg);\n\t}\n\n\n\tvoid GX2InitPolygonControlReg(GX2PolygonControlReg* reg,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE frontFace,\n\t\tuint32 cullFront,\n\t\tuint32 cullBack,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_POLYGONMODE usePolygonMode,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE polyModeFront,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE polyModeBack,\n\t\tuint32 polygonOffsetFrontEnable,\n\t\tuint32 polygonOffsetBackEnable,\n\t\tuint32 paraOffsetEnable)\n\t{\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL v;\n\t\tv.set_FRONT_FACE(frontFace);\n\t\tv.set_CULL_FRONT((cullFront & 1) != 0);\n\t\tv.set_CULL_BACK((cullBack & 1) != 0);\n\t\tv.set_POLYGON_MODE(usePolygonMode);\n\t\tv.set_FRONT_POLY_MODE(polyModeFront);\n\t\tv.set_BACK_POLY_MODE(polyModeBack);\n\t\tv.set_OFFSET_PARA_ENABLED((paraOffsetEnable & 1) != 0);\n\t\tv.set_OFFSET_FRONT_ENABLED((polygonOffsetFrontEnable & 1) != 0);\n\t\tv.set_OFFSET_BACK_ENABLED((polygonOffsetBackEnable & 1) != 0);\n\t\treg->reg = v;\n\t}\n\n\tvoid GX2SetPolygonControlReg(GX2PolygonControlReg* reg)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\t\tgx2WriteGather_submit(\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::PA_SU_SC_MODE_CNTL - 0xA000,\n\t\t\treg->reg);\n\t}\n\n\tvoid GX2SetPolygonControl(Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE frontFace,\n\t\tuint32 cullFront,\n\t\tuint32 cullBack,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_POLYGONMODE usePolygonMode,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE polyModeFront,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE polyModeBack,\n\t\tuint32 polygonOffsetFrontEnable,\n\t\tuint32 polygonOffsetBackEnable,\n\t\tuint32 paraOffsetEnable)\n\t{\n\t\tGX2PolygonControlReg reg{};\n\t\tGX2InitPolygonControlReg(&reg, frontFace, cullFront, cullBack, usePolygonMode, polyModeFront, polyModeBack, polygonOffsetFrontEnable, polygonOffsetBackEnable, paraOffsetEnable);\n\t\tGX2SetPolygonControlReg(&reg);\n\t}\n\n\tvoid GX2SetCullOnlyControl(Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE frontFace, uint32 cullFront, uint32 cullBack)\n\t{\n\t\tGX2PolygonControlReg reg{};\n\t\tGX2InitPolygonControlReg(&reg, frontFace, cullFront, cullBack, Latte::LATTE_PA_SU_SC_MODE_CNTL::E_POLYGONMODE::UKN0, Latte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE::POINTS, Latte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE::POINTS, 0, 0, 0);\n\t\tGX2SetPolygonControlReg(&reg);\n\t}\n\n\tvoid GX2InitPolygonOffsetReg(GX2PolygonOffsetReg* reg, float frontOffset, float frontScale, float backOffset, float backScale, float clampOffset)\n\t{\n\t\tfrontScale *= 16.0;\n\t\tbackScale *= 16.0;\n\t\treg->regFrontScale = Latte::LATTE_PA_SU_POLY_OFFSET_FRONT_SCALE().set_SCALE(frontScale);\n\t\treg->regFrontOffset = Latte::LATTE_PA_SU_POLY_OFFSET_FRONT_OFFSET().set_OFFSET(frontOffset);\n\t\treg->regBackScale = Latte::LATTE_PA_SU_POLY_OFFSET_BACK_SCALE().set_SCALE(backScale);\n\t\treg->regBackOffset = Latte::LATTE_PA_SU_POLY_OFFSET_BACK_OFFSET().set_OFFSET(backOffset);\n\t\treg->regClamp = Latte::LATTE_PA_SU_POLY_OFFSET_CLAMP().set_CLAMP(clampOffset);\n\t}\n\n\tvoid GX2SetPolygonOffsetReg(GX2PolygonOffsetReg* reg)\n\t{\n\t\tGX2ReserveCmdSpace(6 + 3);\n\n\t\tgx2WriteGather_submit(\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 4),\n\t\t\tLatte::REGADDR::PA_SU_POLY_OFFSET_FRONT_SCALE - 0xA000,\n\t\t\treg->regFrontScale,\n\t\t\treg->regFrontOffset,\n\t\t\treg->regBackScale,\n\t\t\treg->regBackOffset,\n\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::PA_SU_POLY_OFFSET_CLAMP - 0xA000,\n\t\t\treg->regClamp);\n\t}\n\n\tvoid GX2SetPolygonOffset(float frontOffset, float frontScale, float backOffset, float backScale, float clampOffset)\n\t{\n\t\tGX2PolygonOffsetReg tmpReg;\n\t\tGX2InitPolygonOffsetReg(&tmpReg, frontOffset, frontScale, backOffset, backScale, clampOffset);\n\t\tGX2SetPolygonOffsetReg(&tmpReg);\n\t}\n\n\tvoid GX2SetRasterizerClipControlEx(bool enableRasterizer, bool enableZClip, bool enableHalfZ)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\n\t\t//if (enableHalfZ)\n\t\t//{\n\t\t//\t// Smash has a bug where it enables half space clipping during streamout drawcalls and shadowing and then doesn't turn it off until the next GX2SetRasterizerClipControl call\n\t\t//\t// this leads to some stuff being rendered at the wrong z-plane (e.g. shields behind characters) if the game's default depth range -1 to 1 isn't supported (on OpenGL only Nvidia's glDepthRangedNV allows unclamped values)\n\t\t//\tuint64 titleId = gameMeta_getTitleId();\n\t\t//\tif (titleId == 0x0005000010144F00ULL ||\n\t\t//\t\ttitleId == 0x0005000010145000ULL ||\n\t\t//\t\ttitleId == 0x0005000010110E00ULL)\n\t\t//\t{\n\t\t//\t\t// force disable half space clipping\n\t\t//\t\tif (g_renderer && g_renderer->GetType() == RendererAPI::OpenGL && LatteGPUState.glVendor != GLVENDOR_NVIDIA)\n\t\t//\t\t\tenableHalfZ = false;\n\t\t//\t}\n\t\t//}\n\n\t\tLatte::LATTE_PA_CL_CLIP_CNTL reg{};\n\t\treg.set_ZCLIP_NEAR_DISABLE(!enableZClip).set_ZCLIP_FAR_DISABLE(!enableZClip);\n\t\treg.set_DX_RASTERIZATION_KILL(!enableRasterizer);\n\t\treg.set_DX_CLIP_SPACE_DEF(enableHalfZ);\n\t\treg.set_DX_LINEAR_ATTR_CLIP_ENA(true);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::PA_CL_CLIP_CNTL - 0xA000,\n\t\t\treg);\n\t}\n\n\tvoid GX2SetRasterizerClipControl(bool enableRasterizer, bool enableZClip)\n\t{\n\t\tGX2SetRasterizerClipControlEx(enableRasterizer, enableZClip, false);\n\t}\n\n\tvoid GX2SetRasterizerClipControlHalfZ(bool enableRasterizer, bool enableZClip, bool enableHalfZ)\n\t{\n\t\tGX2SetRasterizerClipControlEx(enableRasterizer, enableZClip, enableHalfZ);\n\t}\n\n\tvoid GX2InitViewportReg(GX2ViewportReg* viewportReg, float x, float y, float width, float height, float nearZ, float farZ)\n\t{\n\t\t// todo: set clipping registers and zMin/zMax registers\n\t\tviewportReg->xScale = Latte::LATTE_PA_CL_VPORT_XSCALE().set_SCALE(width * 0.5f);\n\t\tviewportReg->xOffset = Latte::LATTE_PA_CL_VPORT_XOFFSET().set_OFFSET(x + (width * 0.5f));\n\t\tviewportReg->yScale = Latte::LATTE_PA_CL_VPORT_YSCALE().set_SCALE(height * -0.5f);\n\t\tviewportReg->yOffset = Latte::LATTE_PA_CL_VPORT_YOFFSET().set_OFFSET(y + (height * 0.5f));\n\t\tviewportReg->zScale = Latte::LATTE_PA_CL_VPORT_ZSCALE().set_SCALE((farZ - nearZ) * 0.5f);\n\t\tviewportReg->zOffset = Latte::LATTE_PA_CL_VPORT_ZOFFSET().set_OFFSET((nearZ + farZ) * 0.5f);\n\t}\n\n\tvoid GX2SetViewportReg(GX2ViewportReg* viewportReg)\n\t{\n\t\tGX2ReserveCmdSpace(2 + 6);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 6),\n\t\t\tLatte::REGADDR::PA_CL_VPORT_XSCALE - 0xA000,\n\t\t\tviewportReg->xScale, viewportReg->xOffset,\n\t\t\tviewportReg->yScale, viewportReg->yOffset,\n\t\t\tviewportReg->zScale, viewportReg->zOffset);\n\t}\n\n\tvoid GX2SetViewport(float x, float y, float width, float height, float nearZ, float farZ)\n\t{\n\t\tGX2ViewportReg viewportReg;\n\t\tGX2InitViewportReg(&viewportReg, x, y, width, height, nearZ, farZ);\n\t\tGX2SetViewportReg(&viewportReg);\n\t}\n\n\tvoid GX2InitScissorReg(GX2ScissorReg* scissorReg, uint32 x, uint32 y, uint32 width, uint32 height)\n\t{\n\t\tuint32 tlx = x;\n\t\tuint32 tly = y;\n\t\tuint32 brx = x + width;\n\t\tuint32 bry = y + height;\n\n\t\ttlx = std::min(tlx, 8192u);\n\t\ttly = std::min(tly, 8192u);\n\t\tbrx = std::min(brx, 8192u);\n\t\tbry = std::min(bry, 8192u);\n\n\t\tscissorReg->scissorTL = Latte::LATTE_PA_SC_GENERIC_SCISSOR_TL().set_TL_X(tlx).set_TL_Y(tly).set_WINDOW_OFFSET_DISABLE(true);\n\t\tscissorReg->scissorBR = Latte::LATTE_PA_SC_GENERIC_SCISSOR_BR().set_BR_X(brx).set_BR_Y(bry);\n\t}\n\n\tvoid GX2SetScissorReg(GX2ScissorReg* scissorReg)\n\t{\n\t\tGX2ReserveCmdSpace(4);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 2),\n\t\t\tLatte::REGADDR::PA_SC_GENERIC_SCISSOR_TL - 0xA000,\n\t\t\tscissorReg->scissorTL, scissorReg->scissorBR);\n\t}\n\n\tvoid GX2GetScissorReg(GX2ScissorReg* scissorReg, uint32be* x, uint32be* y, uint32be* width, uint32be* height)\n\t{\n\t\t*x = scissorReg->scissorTL.value().get_TL_X();\n\t\t*y = scissorReg->scissorTL.value().get_TL_Y();\n\t\t*width = scissorReg->scissorBR.value().get_BR_X() - scissorReg->scissorTL.value().get_TL_X();\n\t\t*height = scissorReg->scissorBR.value().get_BR_Y() - scissorReg->scissorTL.value().get_TL_Y();\n\t}\n\n\tvoid GX2SetScissor(uint32 x, uint32 y, uint32 width, uint32 height)\n\t{\n\t\tGX2ScissorReg scissorReg;\n\t\tGX2InitScissorReg(&scissorReg, x, y, width, height);\n\t\tGX2SetScissorReg(&scissorReg);\n\t}\n\n\tvoid GX2SetDepthOnlyControl(bool depthTestEnable, bool depthWriteEnable, LATTE_DB_DEPTH_CONTROL::E_ZFUNC depthFunction)\n\t{\n\t\t// disables any currently set stencil test\n\t\tGX2ReserveCmdSpace(3);\n\n\t\tLatte::LATTE_DB_DEPTH_CONTROL reg{};\n\t\treg.set_Z_ENABLE(depthTestEnable);\n\t\treg.set_Z_WRITE_ENABLE(depthWriteEnable);\n\t\treg.set_Z_FUNC(depthFunction);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::DB_DEPTH_CONTROL - 0xA000,\n\t\t\treg);\n\t}\n\n\tvoid GX2SetDepthStencilControl(\n\t\tbool depthTestEnable, bool depthWriteEnable, LATTE_DB_DEPTH_CONTROL::E_ZFUNC depthFunction,\n\t\tbool stencilTestEnable, bool backStencilTestEnable, \n\t\tLATTE_DB_DEPTH_CONTROL::E_STENCILFUNC frontStencilFunction, \n\t\tLATTE_DB_DEPTH_CONTROL::E_STENCILACTION frontStencilZPass, LATTE_DB_DEPTH_CONTROL::E_STENCILACTION frontStencilZFail, LATTE_DB_DEPTH_CONTROL::E_STENCILACTION frontStencilFail,\n\t\tLATTE_DB_DEPTH_CONTROL::E_STENCILFUNC backStencilFunction, \n\t\tLATTE_DB_DEPTH_CONTROL::E_STENCILACTION backStencilZPass, LATTE_DB_DEPTH_CONTROL::E_STENCILACTION backStencilZFail, LATTE_DB_DEPTH_CONTROL::E_STENCILACTION backStencilFail\n\t)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\n\t\tLatte::LATTE_DB_DEPTH_CONTROL reg{};\n\t\treg.set_Z_ENABLE(depthTestEnable).set_Z_WRITE_ENABLE(depthWriteEnable).set_Z_FUNC(depthFunction);\n\t\treg.set_STENCIL_ENABLE(stencilTestEnable).set_BACK_STENCIL_ENABLE(backStencilTestEnable);\n\t\treg.set_STENCIL_FUNC_F(frontStencilFunction).set_STENCIL_FUNC_B(backStencilFunction);\n\t\treg.set_STENCIL_ZPASS_F(frontStencilZPass).set_STENCIL_ZFAIL_F(frontStencilZFail).set_STENCIL_FAIL_F(frontStencilFail);\n\t\treg.set_STENCIL_ZPASS_B(backStencilZPass).set_STENCIL_ZFAIL_B(backStencilZFail).set_STENCIL_FAIL_B(backStencilFail);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::DB_DEPTH_CONTROL - 0xA000,\n\t\t\treg);\n\t}\n\n\tvoid GX2InitDepthStencilControlReg(\n\t\tGX2DepthStencilControlReg* depthStencilControlReg,\n\t\tbool depthTestEnable, bool depthWriteEnable, LATTE_DB_DEPTH_CONTROL::E_ZFUNC depthFunction,\n\t\tbool stencilTestEnable, bool backStencilTestEnable,\n\t\tLATTE_DB_DEPTH_CONTROL::E_STENCILFUNC frontStencilFunction,\n\t\tLATTE_DB_DEPTH_CONTROL::E_STENCILACTION frontStencilZPass, LATTE_DB_DEPTH_CONTROL::E_STENCILACTION frontStencilZFail, LATTE_DB_DEPTH_CONTROL::E_STENCILACTION frontStencilFail,\n\t\tLATTE_DB_DEPTH_CONTROL::E_STENCILFUNC backStencilFunction,\n\t\tLATTE_DB_DEPTH_CONTROL::E_STENCILACTION backStencilZPass, LATTE_DB_DEPTH_CONTROL::E_STENCILACTION backStencilZFail, LATTE_DB_DEPTH_CONTROL::E_STENCILACTION backStencilFail)\n\t{\n\t\tLatte::LATTE_DB_DEPTH_CONTROL reg{};\n\t\treg.set_Z_ENABLE(depthTestEnable).set_Z_WRITE_ENABLE(depthWriteEnable).set_Z_FUNC(depthFunction);\n\t\treg.set_STENCIL_ENABLE(stencilTestEnable).set_BACK_STENCIL_ENABLE(backStencilTestEnable);\n\t\treg.set_STENCIL_FUNC_F(frontStencilFunction).set_STENCIL_FUNC_B(backStencilFunction);\n\t\treg.set_STENCIL_ZPASS_F(frontStencilZPass).set_STENCIL_ZFAIL_F(frontStencilZFail).set_STENCIL_FAIL_F(frontStencilFail);\n\t\treg.set_STENCIL_ZPASS_B(backStencilZPass).set_STENCIL_ZFAIL_B(backStencilZFail).set_STENCIL_FAIL_B(backStencilFail);\n\t\tdepthStencilControlReg->reg = reg;\n\t}\n\n\tvoid GX2SetDepthStencilControlReg(GX2DepthStencilControlReg* depthStencilControlReg)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::DB_DEPTH_CONTROL - 0xA000,\n\t\t\tdepthStencilControlReg->reg);\n\t}\n\n\tvoid GX2GetDepthStencilControlReg(\n\t\tGX2DepthStencilControlReg* depthStencilControlReg,\n\t\tuint32be* depthTestEnable, uint32be* depthWriteEnable, uint32be* depthFunction,\n\t\tuint32be* stencilTestEnable, uint32be* backStencilTestEnable,\n\t\tuint32be* frontStencilFunction,\n\t\tuint32be* frontStencilZPass, uint32be* frontStencilZFail, uint32be* frontStencilFail,\n\t\tuint32be* backStencilFunction,\n\t\tuint32be* backStencilZPass, uint32be* backStencilZFail, uint32be* backStencilFail)\n\t{\n\t\t// used by Hyrule Warriors\n\n\t\t*depthTestEnable = depthStencilControlReg->reg.value().get_Z_ENABLE();\n\n\t\t*depthWriteEnable = depthStencilControlReg->reg.value().get_Z_WRITE_ENABLE();\n\t\t*depthFunction = (uint32)depthStencilControlReg->reg.value().get_Z_FUNC();\n\n\t\t*stencilTestEnable = depthStencilControlReg->reg.value().get_STENCIL_ENABLE();\n\t\t*backStencilTestEnable = depthStencilControlReg->reg.value().get_BACK_STENCIL_ENABLE();\n\t\n\t\t*frontStencilFunction = (uint32)depthStencilControlReg->reg.value().get_STENCIL_FUNC_F();\n\t\t*backStencilFunction = (uint32)depthStencilControlReg->reg.value().get_STENCIL_FUNC_B();\n\n\t\t*frontStencilZPass = (uint32)depthStencilControlReg->reg.value().get_STENCIL_ZPASS_F();\n\t\t*frontStencilZFail = (uint32)depthStencilControlReg->reg.value().get_STENCIL_ZFAIL_F();\n\t\t*frontStencilFail = (uint32)depthStencilControlReg->reg.value().get_STENCIL_FAIL_F();\n\n\t\t*backStencilZPass = (uint32)depthStencilControlReg->reg.value().get_STENCIL_ZPASS_B();\n\t\t*backStencilZFail = (uint32)depthStencilControlReg->reg.value().get_STENCIL_ZFAIL_B();\n\t\t*backStencilFail = (uint32)depthStencilControlReg->reg.value().get_STENCIL_FAIL_B();\n\t}\n\n\tvoid GX2InitStencilMaskReg(GX2StencilMaskReg* stencilMaskReg, uint8 compareMaskFront, uint8 writeMaskFront, uint8 refFront, uint8 compareMaskBack, uint8 writeMaskBack, uint8 refBack)\n\t{\n\t\tstencilMaskReg->stencilRefMaskFrontReg = LATTE_DB_STENCILREFMASK().set_STENCILREF_F(refFront).set_STENCILMASK_F(compareMaskFront).set_STENCILWRITEMASK_F(writeMaskFront);\n\t\tstencilMaskReg->stencilRefMaskBackReg = LATTE_DB_STENCILREFMASK_BF().set_STENCILREF_B(refBack).set_STENCILMASK_B(compareMaskBack).set_STENCILWRITEMASK_B(writeMaskBack);\n\t}\n\n\tvoid GX2SetStencilMask(uint8 compareMaskFront, uint8 writeMaskFront, uint8 refFront, uint8 compareMaskBack, uint8 writeMaskBack, uint8 refBack)\n\t{\n\t\tGX2ReserveCmdSpace(3 + 3);\n\n\t\tLATTE_DB_STENCILREFMASK frontReg;\n\t\tfrontReg.set_STENCILREF_F(refFront).set_STENCILMASK_F(compareMaskFront).set_STENCILWRITEMASK_F(writeMaskFront);\n\t\tLATTE_DB_STENCILREFMASK_BF backReg;\n\t\tbackReg.set_STENCILREF_B(refBack).set_STENCILMASK_B(compareMaskBack).set_STENCILWRITEMASK_B(writeMaskBack);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\t\t\t\t\tREGADDR::DB_STENCILREFMASK - 0xA000,\n\t\t\t\t\t\t\tfrontReg,\n\t\t\t\t\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\t\t\t\t\tREGADDR::DB_STENCILREFMASK_BF - 0xA000,\n\t\t\t\t\t\t\tbackReg);\n\t}\n\n\tvoid GX2SetStencilMaskReg(GX2StencilMaskReg* stencilMaskReg)\n\t{\n\t\tGX2ReserveCmdSpace(3 + 3);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tREGADDR::DB_STENCILREFMASK - 0xA000,\n\t\t\tstencilMaskReg->stencilRefMaskFrontReg,\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tREGADDR::DB_STENCILREFMASK_BF - 0xA000,\n\t\t\tstencilMaskReg->stencilRefMaskBackReg);\n\t}\n\n\tvoid GX2SetPrimitiveRestartIndex(uint32 restartIndex)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\t\tLatte::LATTE_VGT_MULTI_PRIM_IB_RESET_INDX reg{};\n\t\treg.set_RESTART_INDEX(restartIndex);\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::VGT_MULTI_PRIM_IB_RESET_INDX - 0xA000,\n\t\t\treg);\n\t}\n\n\tvoid GX2InitTargetChannelMasksReg(GX2TargetChannelMaskReg* reg, GX2_CHANNELMASK t0, GX2_CHANNELMASK t1, GX2_CHANNELMASK t2, GX2_CHANNELMASK t3, GX2_CHANNELMASK t4, GX2_CHANNELMASK t5, GX2_CHANNELMASK t6, GX2_CHANNELMASK t7)\n\t{\n\t\tuint32 targetMask = 0;\n\t\ttargetMask |= ((t0 & 0xF) << 0);\n\t\ttargetMask |= ((t1 & 0xF) << 4);\n\t\ttargetMask |= ((t2 & 0xF) << 8);\n\t\ttargetMask |= ((t3 & 0xF) << 12);\n\t\ttargetMask |= ((t4 & 0xF) << 16);\n\t\ttargetMask |= ((t5 & 0xF) << 20);\n\t\ttargetMask |= ((t6 & 0xF) << 24);\n\t\ttargetMask |= ((t7 & 0xF) << 28);\n\t\tLatte::LATTE_CB_TARGET_MASK r;\n\t\tr.set_MASK(targetMask);\n\t\treg->reg = r;\n\t}\n\n\tvoid GX2SetTargetChannelMasksReg(GX2TargetChannelMaskReg* reg)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::CB_TARGET_MASK - 0xA000,\n\t\t\treg->reg);\n\t}\n\n\tvoid GX2SetTargetChannelMasks(GX2_CHANNELMASK t0, GX2_CHANNELMASK t1, GX2_CHANNELMASK t2, GX2_CHANNELMASK t3, GX2_CHANNELMASK t4, GX2_CHANNELMASK t5, GX2_CHANNELMASK t6, GX2_CHANNELMASK t7)\n\t{\n\t\tGX2TargetChannelMaskReg tmpReg;\n\t\tGX2InitTargetChannelMasksReg(&tmpReg, t0, t1, t2, t3, t4, t5, t6, t7);\n\t\tGX2SetTargetChannelMasksReg(&tmpReg);\n\t}\n\n\tstatic_assert(sizeof(GX2_CHANNELMASK) == 4);\n\n\tvoid GX2GetTargetChannelMasksReg(GX2TargetChannelMaskReg* reg, betype<GX2_CHANNELMASK>* t0, betype<GX2_CHANNELMASK>* t1, betype<GX2_CHANNELMASK>* t2, betype<GX2_CHANNELMASK>* t3,\n\t\t\t\t\t\t\t\t\tbetype<GX2_CHANNELMASK>* t4, betype<GX2_CHANNELMASK>* t5, betype<GX2_CHANNELMASK>* t6, betype<GX2_CHANNELMASK>* t7)\n\t{\n\t\tuint32 maskValue = reg->reg.value().get_MASK();\n\t\t*t0 = (maskValue >> 0) & 0xF;\n\t\t*t1 = (maskValue >> 4) & 0xF;\n\t\t*t2 = (maskValue >> 8) & 0xF;\n\t\t*t3 = (maskValue >> 12) & 0xF;\n\t\t*t4 = (maskValue >> 16) & 0xF;\n\t\t*t5 = (maskValue >> 20) & 0xF;\n\t\t*t6 = (maskValue >> 24) & 0xF;\n\t\t*t7 = (maskValue >> 28) & 0xF;\n\t}\n\n\tvoid GX2InitBlendControlReg(GX2BlendControlReg* reg, uint32 renderTargetIndex, GX2_BLENDFACTOR colorSrcFactor, GX2_BLENDFACTOR colorDstFactor, GX2_BLENDFUNC colorCombineFunc, uint32 separateAlphaBlend, GX2_BLENDFACTOR alphaSrcFactor, GX2_BLENDFACTOR alphaDstFactor, GX2_BLENDFUNC alphaCombineFunc)\n\t{\n\t\tLatte::LATTE_CB_BLENDN_CONTROL tmpReg;\n\t\ttmpReg.set_COLOR_SRCBLEND(colorSrcFactor);\n\t\ttmpReg.set_COLOR_DSTBLEND(colorDstFactor);\n\t\ttmpReg.set_COLOR_COMB_FCN(colorCombineFunc);\n\t\ttmpReg.set_ALPHA_SRCBLEND(alphaSrcFactor);\n\t\ttmpReg.set_ALPHA_DSTBLEND(alphaDstFactor);\n\t\ttmpReg.set_ALPHA_COMB_FCN(alphaCombineFunc);\n\t\ttmpReg.set_SEPARATE_ALPHA_BLEND(separateAlphaBlend != 0);\n\n\t\treg->index = renderTargetIndex;\n\t\treg->reg = tmpReg;\n\t}\n\n\tvoid GX2SetBlendControlReg(GX2BlendControlReg* reg)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\t\tgx2WriteGather_submit(\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\t(Latte::REGADDR::CB_BLEND0_CONTROL + (uint32)reg->index) - 0xA000,\n\t\t\treg->reg\n\t\t);\n\t}\n\n\tvoid GX2SetBlendControl(uint32 renderTargetIndex, GX2_BLENDFACTOR colorSrcFactor, GX2_BLENDFACTOR colorDstFactor, GX2_BLENDFUNC colorCombineFunc, uint32 separateAlphaBlend, GX2_BLENDFACTOR alphaSrcFactor, GX2_BLENDFACTOR alphaDstFactor, GX2_BLENDFUNC alphaCombineFunc)\n\t{\n\t\tGX2BlendControlReg tmpReg;\n\t\tGX2InitBlendControlReg(&tmpReg, renderTargetIndex, colorSrcFactor, colorDstFactor, colorCombineFunc, separateAlphaBlend, alphaSrcFactor, alphaDstFactor, alphaCombineFunc);\n\t\tGX2SetBlendControlReg(&tmpReg);\n\t}\n\n\tvoid GX2InitBlendConstantColorReg(GX2BlendConstantColorReg* reg, float red, float green, float blue, float alpha)\n\t{\n\t\treg->regRed = Latte::LATTE_CB_BLEND_RED().set_RED(red);\n\t\treg->regGreen = Latte::LATTE_CB_BLEND_GREEN().set_GREEN(green);\n\t\treg->regBlue = Latte::LATTE_CB_BLEND_BLUE().set_BLUE(blue);\n\t\treg->regAlpha = Latte::LATTE_CB_BLEND_ALPHA().set_ALPHA(alpha);\n\t}\n\n\tvoid GX2SetBlendConstantColorReg(GX2BlendConstantColorReg* reg)\n\t{\n\t\tGX2ReserveCmdSpace(6);\n\t\tgx2WriteGather_submit(\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 4),\n\t\t\tLatte::REGADDR::CB_BLEND_RED - 0xA000,\n\t\t\treg->regRed,\n\t\t\treg->regGreen,\n\t\t\treg->regBlue,\n\t\t\treg->regAlpha\n\t\t);\n\t}\n\n\tvoid GX2SetBlendConstantColor(float red, float green, float blue, float alpha)\n\t{\n\t\tGX2BlendConstantColorReg tmpReg;\n\t\tGX2InitBlendConstantColorReg(&tmpReg, red, green, blue, alpha);\n\t\tGX2SetBlendConstantColorReg(&tmpReg);\n\t}\n\n\tvoid GX2InitHiStencilInfoRegs(GX2HiStencilInfoReg* hiStencilInfo)\n\t{\n\t\t// seen in Color Splash\n\t\t// but the game never calls GX2SetHiStencilInfo thus this has no effect\n\t}\n\n\tvoid GX2InitPointSizeReg(GX2PointSizeReg* reg, float width, float height)\n\t{\n\t\tif (width < 0.0f || height < 0.0f)\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\n\t\tuint32 widthI = (uint32)(width * 8.0f);\n\t\tuint32 heightI = (uint32)(height * 8.0f);\n\n\t\twidthI = std::min<uint32>(widthI, 0xFFFF);\n\t\theightI = std::min<uint32>(heightI, 0xFFFF);\n\n\t\treg->reg = Latte::LATTE_PA_SU_POINT_SIZE().set_WIDTH(widthI).set_HEIGHT(heightI);\n\t}\n\n\tvoid GX2SetPointSizeReg(GX2PointSizeReg* reg)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\t\tgx2WriteGather_submit(\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::PA_SU_POINT_SIZE - 0xA000,\n\t\t\treg->reg\n\t\t);\n\t}\n\n\tvoid GX2SetPointSize(float width, float height)\n\t{\n\t\tGX2PointSizeReg tmpReg;\n\t\tGX2InitPointSizeReg(&tmpReg, width, height);\n\t\tGX2SetPointSizeReg(&tmpReg);\n\t}\n\n\tvoid GX2InitPointLimitsReg(GX2PointLimitsReg* reg, float minSize, float maxSize)\n\t{\n\t\tif (minSize < 0.0f || maxSize < 0.0f)\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\n\t\tuint32 minSizeI = (uint32)(minSize * 8.0f);\n\t\tuint32 maxSizeI = (uint32)(maxSize * 8.0f);\n\n\t\tminSizeI = std::min<uint32>(minSizeI, 0xFFFF);\n\t\tmaxSizeI = std::min<uint32>(maxSizeI, 0xFFFF);\n\n\t\treg->reg = Latte::LATTE_PA_SU_POINT_MINMAX().set_MIN_SIZE(minSizeI).set_MAX_SIZE(maxSizeI);\n\t}\n\n\tvoid GX2SetPointLimitsReg(GX2PointLimitsReg* reg)\n\t{\n\t\tGX2ReserveCmdSpace(3);\n\t\tgx2WriteGather_submit(\n\t\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\tLatte::REGADDR::PA_SU_POINT_MINMAX - 0xA000,\n\t\t\treg->reg\n\t\t);\n\t}\n\n\tvoid GX2SetPointLimits(float minSize, float maxSize)\n\t{\n\t\tGX2PointLimitsReg tmpReg;\n\t\tGX2InitPointLimitsReg(&tmpReg, minSize, maxSize);\n\t\tGX2SetPointLimitsReg(&tmpReg);\n\t}\n\n\tenum class GX2_SPECIAL_STATE : uint32\n\t{\n\t\tFAST_CLEAR = 0,\n\t\tFAST_CLEAR_HIZ = 1,\n\t};\n\n\tvoid _setSpecialState0(bool isEnabled)\n\t{\n\t\tGX2ReserveCmdSpace(6);\n\t\tif (isEnabled)\n\t\t{\n\t\t\t// set PA_CL_VTE_CNTL to 0x300\n\t\t\tLatte::LATTE_PA_CL_VTE_CNTL regVTE{};\n\t\t\tregVTE.set_VTX_XY_FMT(true);\n\t\t\tregVTE.set_VTX_Z_FMT(true);\n\t\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\t\tLatte::REGADDR::PA_CL_VTE_CNTL - 0xA000,\n\t\t\t\tregVTE);\n\t\t\t// set PA_CL_CLIP_CNTL to 0x490000\n\t\t\tLatte::LATTE_PA_CL_CLIP_CNTL regClip{};\n\t\t\tregClip.set_CLIP_DISABLE(true); // 0x10000\n\t\t\tregClip.set_DX_CLIP_SPACE_DEF(true); // 0x80000\n\t\t\tregClip.set_DX_RASTERIZATION_KILL(true); // 0x400000\n\t\t\t\n\t\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\t\tLatte::REGADDR::PA_CL_CLIP_CNTL - 0xA000,\n\t\t\t\tregClip);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// set PA_CL_VTE_CNTL to 0x43F\n\t\t\tLatte::LATTE_PA_CL_VTE_CNTL reg{};\n\t\t\treg.set_VPORT_X_OFFSET_ENA(true).set_VPORT_X_SCALE_ENA(true);\n\t\t\treg.set_VPORT_Y_OFFSET_ENA(true).set_VPORT_Y_SCALE_ENA(true);\n\t\t\treg.set_VPORT_Z_OFFSET_ENA(true).set_VPORT_Z_SCALE_ENA(true);\n\t\t\treg.set_VTX_W0_FMT(true);\n\t\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1),\n\t\t\t\tLatte::REGADDR::PA_CL_VTE_CNTL - 0xA000,\n\t\t\t\treg);\n\t\t\t// reset PA_CL_CLIP_CNTL\n\t\t\tGX2SetRasterizerClipControl(true, true);\n\t\t}\n\t}\n\n\tvoid GX2SetSpecialState(GX2_SPECIAL_STATE stateId, uint32 isEnabled)\n\t{\n\t\tif (stateId == GX2_SPECIAL_STATE::FAST_CLEAR)\n\t\t{\n\t\t\t_setSpecialState0(isEnabled != 0);\n\t\t}\n\t\telse if (stateId == GX2_SPECIAL_STATE::FAST_CLEAR_HIZ)\n\t\t{\n\t\t\t// todo\n\t\t\t// enables additional flags for special state 0\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// legacy style\n\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_SPECIAL_STATE, 2));\n\t\t\tgx2WriteGather_submitU32AsBE((uint32)stateId); // state id\n\t\t\tgx2WriteGather_submitU32AsBE(isEnabled); // enable/disable bool\n\t\t}\n\t}\n\n\tvoid GX2StateInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2InitAlphaTestReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetAlphaTestReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetAlphaTest, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitColorControlReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetColorControl, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetColorControlReg, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitPolygonControlReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPolygonControlReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPolygonControl, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetCullOnlyControl, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitPolygonOffsetReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPolygonOffsetReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPolygonOffset, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2SetRasterizerClipControl, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetRasterizerClipControlHalfZ, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetRasterizerClipControlEx, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitViewportReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetViewportReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetViewport, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitScissorReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetScissorReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetScissorReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetScissor, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitDepthStencilControlReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetDepthStencilControlReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetDepthStencilControlReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetDepthOnlyControl, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetDepthStencilControl, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitStencilMaskReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetStencilMask, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetStencilMaskReg, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2SetPrimitiveRestartIndex, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitTargetChannelMasksReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetTargetChannelMasksReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetTargetChannelMasks, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetTargetChannelMasksReg, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitBlendControlReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetBlendControlReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetBlendControl, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitBlendConstantColorReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetBlendConstantColorReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetBlendConstantColor, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2InitHiStencilInfoRegs, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2InitPointSizeReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPointSizeReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPointSize, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2InitPointLimitsReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPointLimitsReg, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPointLimits, LogType::GX2);\n\n\t\tcafeExportRegister(\"gx2\", GX2SetSpecialState, LogType::GX2);\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_State.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n\nnamespace GX2\n{\n\tstruct GX2AlphaTestReg\n\t{\n\t\tbetype<Latte::LATTE_SX_ALPHA_TEST_CONTROL> regAlphaTestControl;\n\t\tbetype<Latte::LATTE_SX_ALPHA_REF> regAlphaTestRef;\n\t};\n\n\tstatic_assert(sizeof(GX2AlphaTestReg) == 8);\n\n\tstruct GX2ColorControlReg\n\t{\n\t\tbetype<Latte::LATTE_CB_COLOR_CONTROL> reg;\n\t};\n\n\tstatic_assert(sizeof(GX2ColorControlReg) == 4);\n\n\tstruct GX2PolygonControlReg\n\t{\n\t\tbetype<Latte::LATTE_PA_SU_SC_MODE_CNTL> reg;\n\t};\n\n\tstatic_assert(sizeof(GX2PolygonControlReg) == 4);\n\n\tstruct GX2PolygonOffsetReg\n\t{\n\t\tbetype<Latte::LATTE_PA_SU_POLY_OFFSET_FRONT_SCALE> regFrontScale;\n\t\tbetype<Latte::LATTE_PA_SU_POLY_OFFSET_FRONT_OFFSET> regFrontOffset;\n\t\tbetype<Latte::LATTE_PA_SU_POLY_OFFSET_BACK_SCALE> regBackScale;\n\t\tbetype<Latte::LATTE_PA_SU_POLY_OFFSET_BACK_OFFSET> regBackOffset;\n\t\tbetype<Latte::LATTE_PA_SU_POLY_OFFSET_CLAMP> regClamp;\n\t};\n\n\tstatic_assert(sizeof(GX2PolygonOffsetReg) == 0x14);\n\n\tstruct GX2DepthStencilControlReg\n\t{\n\t\tbetype<Latte::LATTE_DB_DEPTH_CONTROL> reg;\n\t};\n\n\tstatic_assert(sizeof(GX2DepthStencilControlReg) == 4);\n\n\tstruct GX2StencilMaskReg\n\t{\n\t\tbetype<Latte::LATTE_DB_STENCILREFMASK> stencilRefMaskFrontReg;\n\t\tbetype<Latte::LATTE_DB_STENCILREFMASK_BF> stencilRefMaskBackReg;\n\t};\n\t\n\tstatic_assert(sizeof(GX2StencilMaskReg) == 8);\n\n\tstruct GX2TargetChannelMaskReg\n\t{\n\t\tbetype<Latte::LATTE_CB_TARGET_MASK> reg;\n\t};\n\n\tstatic_assert(sizeof(GX2TargetChannelMaskReg) == 4);\n\n\tstruct GX2HIStencilInfoData\n\t{\n\t\t/* +0x00 */ uint32be ukn00;\n\t\t/* +0x04 */ uint8be ukn04;\n\t\t/* +0x05 */ uint8be ukn05;\n\t\t/* +0x06 */ uint8be ukn06; // probably padding?\n\t\t/* +0x07 */ uint8be ukn07; // probably padding?\n\t\t/* +0x08 */ uint32be isEnable; // 0 or 1\n\t};\n\n\tstatic_assert(sizeof(GX2HIStencilInfoData) == 0xC);\n\n\tstruct GX2HiStencilInfoReg\n\t{\n\t\tGX2HIStencilInfoData state[2];\n\t\tuint32be reg[2]; // DB_SRESULTS_COMPARE_STATE0 and DB_SRESULTS_COMPARE_STATE1\n\t};\n\n\tstatic_assert(sizeof(GX2HiStencilInfoReg) == 0x20);\n\n\tstruct GX2BlendControlReg\n\t{\n\t\tuint32be index;\n\t\tbetype<Latte::LATTE_CB_BLENDN_CONTROL> reg;\n\t};\n\n\tstatic_assert(sizeof(GX2BlendControlReg) == 8);\n\n\tstruct GX2BlendConstantColorReg\n\t{\n\t\tbetype<Latte::LATTE_CB_BLEND_RED> regRed;\n\t\tbetype<Latte::LATTE_CB_BLEND_GREEN> regGreen;\n\t\tbetype<Latte::LATTE_CB_BLEND_BLUE> regBlue;\n\t\tbetype<Latte::LATTE_CB_BLEND_ALPHA> regAlpha;\n\t};\n\n\tstatic_assert(sizeof(GX2BlendConstantColorReg) == 16);\n\n\tstruct GX2PointSizeReg\n\t{\n\t\tbetype<Latte::LATTE_PA_SU_POINT_SIZE> reg;\n\t};\n\n\tstatic_assert(sizeof(GX2PointSizeReg) == 4);\n\n\tstruct GX2PointLimitsReg\n\t{\n\t\tbetype<Latte::LATTE_PA_SU_POINT_MINMAX> reg;\n\t};\n\n\tstatic_assert(sizeof(GX2PointLimitsReg) == 4);\n\n\tstruct GX2ViewportReg\n\t{\n\t\tbetype<Latte::LATTE_PA_CL_VPORT_XSCALE> xScale;\n\t\tbetype<Latte::LATTE_PA_CL_VPORT_XOFFSET> xOffset;\n\t\tbetype<Latte::LATTE_PA_CL_VPORT_YSCALE> yScale;\n\t\tbetype<Latte::LATTE_PA_CL_VPORT_YOFFSET> yOffset;\n\t\tbetype<Latte::LATTE_PA_CL_VPORT_ZSCALE> zScale;\n\t\tbetype<Latte::LATTE_PA_CL_VPORT_ZOFFSET> zOffset;\n\t\tuint32 ukn[6]; // clipping registers?\n\t};\n\n\tstatic_assert(sizeof(GX2ViewportReg) == 48);\n\n\tstruct GX2ScissorReg\n\t{\n\t\tbetype<Latte::LATTE_PA_SC_GENERIC_SCISSOR_TL> scissorTL;\n\t\tbetype<Latte::LATTE_PA_SC_GENERIC_SCISSOR_BR> scissorBR;\n\t};\n\n\tstatic_assert(sizeof(GX2ScissorReg) == 8);\n\n\tusing GX2_ALPHAFUNC = Latte::LATTE_SX_ALPHA_TEST_CONTROL::E_ALPHA_FUNC; // alias Latte::E_COMPAREFUNC\n\tusing GX2_LOGICOP = Latte::LATTE_CB_COLOR_CONTROL::E_LOGICOP;\n\tusing GX2_CHANNELMASK = uint32;\n\tusing GX2_BLENDFACTOR = Latte::LATTE_CB_BLENDN_CONTROL::E_BLENDFACTOR;\n\tusing GX2_BLENDFUNC = Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC;\n\n\tvoid GX2InitAlphaTestReg(GX2AlphaTestReg* reg, uint32 alphaTestEnable, GX2_ALPHAFUNC alphaFunc, float alphaRef);\n\tvoid GX2SetAlphaTestReg(GX2AlphaTestReg* reg);\n\tvoid GX2SetAlphaTest(uint32 alphaTestEnable, GX2_ALPHAFUNC alphaFunc, float alphaRef);\n\n\tvoid GX2InitColorControlReg(GX2ColorControlReg* reg, GX2_LOGICOP logicOp, uint32 blendMask, uint32 multiwriteEnable, uint32 colorBufferEnable);\n\tvoid GX2SetColorControl(GX2_LOGICOP logicOp, uint32 blendMask, uint32 multiwriteEnable, uint32 colorBufferEnable);\n\tvoid GX2SetColorControlReg(GX2ColorControlReg* reg);\n\n\tvoid GX2InitPolygonControlReg(GX2PolygonControlReg* reg,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE frontFace, uint32 cullFront,\tuint32 cullBack,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_POLYGONMODE usePolygonMode,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE polyModeFront,\n\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE polyModeBack,\n\t\tuint32 polygonOffsetFrontEnable, uint32 polygonOffsetBackEnable, uint32 paraOffsetEnable);\n\tvoid GX2SetPolygonControlReg(GX2PolygonControlReg* reg);\n\tvoid GX2SetPolygonControl(Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE frontFace, uint32 cullFront, uint32 cullBack,\n\t\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_POLYGONMODE usePolygonMode,\n\t\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE polyModeFront,\n\t\t\tLatte::LATTE_PA_SU_SC_MODE_CNTL::E_PTYPE polyModeBack,\n\t\t\tuint32 polygonOffsetFrontEnable, uint32 polygonOffsetBackEnable, uint32 paraOffsetEnable);\n\tvoid GX2SetCullOnlyControl(Latte::LATTE_PA_SU_SC_MODE_CNTL::E_FRONTFACE frontFace, uint32 cullFront, uint32 cullBack);\n\n\tvoid GX2InitPolygonOffsetReg(GX2PolygonOffsetReg* reg, float frontOffset, float frontScale, float backOffset, float backScale, float clampOffset);\n\tvoid GX2SetPolygonOffsetReg(GX2PolygonOffsetReg* reg);\n\tvoid GX2SetPolygonOffset(float frontOffset, float frontScale, float backOffset, float backScale, float clampOffset);\n\n\tvoid GX2InitPointSizeReg(GX2PointSizeReg* reg, float width, float height);\n\tvoid GX2SetPointSizeReg(GX2PointSizeReg* reg);\n\tvoid GX2SetPointSize(float width, float height);\n\tvoid GX2InitPointLimitsReg(GX2PointLimitsReg* reg, float minSize, float maxSize);\n\tvoid GX2SetPointLimitsReg(GX2PointLimitsReg* reg);\n\tvoid GX2SetPointLimits(float minSize, float maxSize);\n\n\tvoid GX2SetRasterizerClipControl(bool enableRasterizer, bool enableZClip);\n\tvoid GX2SetRasterizerClipControlHalfZ(bool enableRasterizer, bool enableZClip, bool enableHalfZ);\n\tvoid GX2SetRasterizerClipControlEx(bool enableRasterizer, bool enableZClip, bool enableHalfZ);\n\n\tvoid GX2SetPrimitiveRestartIndex(uint32 restartIndex);\n\n\tvoid GX2InitTargetChannelMasksReg(GX2TargetChannelMaskReg* reg, GX2_CHANNELMASK t0, GX2_CHANNELMASK t1, GX2_CHANNELMASK t2, GX2_CHANNELMASK t3, GX2_CHANNELMASK t4, GX2_CHANNELMASK t5, GX2_CHANNELMASK t6, GX2_CHANNELMASK t7);\n\tvoid GX2SetTargetChannelMasksReg(GX2TargetChannelMaskReg* reg);\n\tvoid GX2SetTargetChannelMasks(GX2_CHANNELMASK t0, GX2_CHANNELMASK t1, GX2_CHANNELMASK t2, GX2_CHANNELMASK t3, GX2_CHANNELMASK t4, GX2_CHANNELMASK t5, GX2_CHANNELMASK t6, GX2_CHANNELMASK t7);\n\t\n\tvoid GX2InitBlendControlReg(GX2BlendControlReg* reg, uint32 renderTargetIndex, GX2_BLENDFACTOR colorSrcFactor, GX2_BLENDFACTOR colorDstFactor, GX2_BLENDFUNC colorCombineFunc, uint32 separateAlphaBlend, GX2_BLENDFACTOR alphaSrcFactor, GX2_BLENDFACTOR alphaDstFactor, GX2_BLENDFUNC alphaCombineFunc);\n\tvoid GX2SetBlendControlReg(GX2BlendControlReg* reg);\n\tvoid GX2SetBlendControl(uint32 renderTargetIndex, GX2_BLENDFACTOR colorSrcFactor, GX2_BLENDFACTOR colorDstFactor, GX2_BLENDFUNC colorCombineFunc, uint32 separateAlphaBlend, GX2_BLENDFACTOR alphaSrcFactor, GX2_BLENDFACTOR alphaDstFactor, GX2_BLENDFUNC alphaCombineFunc);\n\n\tvoid GX2InitBlendConstantColorReg(GX2BlendConstantColorReg* reg, float red, float green, float blue, float alpha);\n\tvoid GX2SetBlendConstantColorReg(GX2BlendConstantColorReg* reg);\n\tvoid GX2SetBlendConstantColor(float red, float green, float blue, float alpha);\n\n\tvoid GX2StateInit();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Streamout.cpp",
    "content": "#include \"GX2_Streamout.h\"\n#include \"GX2_Command.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n\nnamespace GX2\n{\n\tvoid GX2SetStreamOutBuffer(uint32 bufferIndex, GX2StreamOutBuffer* streamOutBuffer)\n\t{\n\t\tif (bufferIndex >= GX2_MAX_STREAMOUT_BUFFERS)\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t\tdebug_printf(\"GX2SetStreamOutBuffer(): Set out-of-bounds buffer\\n\");\n\t\t\treturn;\n\t\t}\n\n\t\tMPTR bufferAddr;\n\t\tuint32 bufferSize;\n\t\tif (streamOutBuffer->dataPtr.IsNull())\n\t\t{\n\t\t\tbufferAddr = streamOutBuffer->rBuffer.GetVirtualAddr();\n\t\t\tbufferSize = streamOutBuffer->rBuffer.GetSize();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbufferAddr = streamOutBuffer->dataPtr.GetMPTR();\n\t\t\tbufferSize = streamOutBuffer->size;\n\t\t}\n\n\t\tGX2ReserveCmdSpace(3 + 3);\n\t\t// set buffer size\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1));\n\t\tgx2WriteGather_submitU32AsBE((mmVGT_STRMOUT_BUFFER_SIZE_0 + bufferIndex * 4) - 0xA000);\n\t\tgx2WriteGather_submitU32AsBE((bufferSize >> 2));\n\t\t// set buffer base\n\t\tuint32 physMem = memory_virtualToPhysical(bufferAddr);\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1));\n\t\tgx2WriteGather_submitU32AsBE((mmVGT_STRMOUT_BUFFER_BASE_0 + bufferIndex * 4) - 0xA000);\n\t\tgx2WriteGather_submitU32AsBE((physMem >> 8));\n\t\t// todo: Research and send IT_STRMOUT_BASE_UPDATE (0x72)\n\t\t// note: Other stream out registers maybe set in GX2SetVertexShader() or GX2SetGeometryShader()\n\t}\n\n\tvoid GX2SetStreamOutEnable(uint32 enable)\n\t{\n\t\tcemu_assert_debug(enable == 0 || enable == 1);\n\t\tGX2ReserveCmdSpace(3);\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1 + 1));\n\t\tgx2WriteGather_submitU32AsBE(mmVGT_STRMOUT_EN - 0xA000);\n\t\tgx2WriteGather_submitU32AsBE(enable & 1);\n\t}\n\n\tvoid GX2SetStreamOutContext(uint32 bufferIndex, GX2StreamOutBuffer* streamOutBuffer, uint32 mode)\n\t{\n\t\tif (bufferIndex >= GX2_MAX_STREAMOUT_BUFFERS)\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t\tdebug_printf(\"GX2SetStreamOutContext(): Set out-of-bounds buffer\\n\");\n\t\t\treturn;\n\t\t}\n\n\t\tGX2ReserveCmdSpace(6);\n\t\tif (mode == 0)\n\t\t{\n\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_STRMOUT_BUFFER_UPDATE, 5));\n\t\t\tgx2WriteGather_submitU32AsBE((2 << 1) | (bufferIndex << 8));\n\t\t\tgx2WriteGather_submitU32AsBE(MPTR_NULL);\n\t\t\tgx2WriteGather_submitU32AsBE(0);\n\t\t\tgx2WriteGather_submitU32AsBE(memory_virtualToPhysical(streamOutBuffer->ctxPtr.GetMPTR()));\n\t\t\tgx2WriteGather_submitU32AsBE(0);\n\t\t}\n\t\telse if (mode == 1)\n\t\t{\n\t\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_STRMOUT_BUFFER_UPDATE, 5));\n\t\t\tgx2WriteGather_submitU32AsBE((0 << 1) | (bufferIndex << 8));\n\t\t\tgx2WriteGather_submitU32AsBE(MPTR_NULL);\n\t\t\tgx2WriteGather_submitU32AsBE(0);\n\t\t\tgx2WriteGather_submitU32AsBE(memory_virtualToPhysical(streamOutBuffer->ctxPtr.GetMPTR()));\n\t\t\tgx2WriteGather_submitU32AsBE(0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\n\tvoid GX2SaveStreamOutContext(uint32 bufferIndex, GX2StreamOutBuffer* streamOutBuffer)\n\t{\n\t\tif (bufferIndex >= GX2_MAX_STREAMOUT_BUFFERS)\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t\tdebug_printf(\"GX2SaveStreamOutContext(): Set out-of-bounds buffer\\n\");\n\t\t\treturn;\n\t\t}\n\t\tGX2ReserveCmdSpace(6);\n\t\t\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_STRMOUT_BUFFER_UPDATE, 5));\n\t\tgx2WriteGather_submitU32AsBE(1 | (3 << 1) | (bufferIndex << 8));\n\t\tgx2WriteGather_submitU32AsBE(memory_virtualToPhysical(streamOutBuffer->ctxPtr.GetMPTR()));\n\t\tgx2WriteGather_submitU32AsBE(0);\n\t\tgx2WriteGather_submitU32AsBE(MPTR_NULL);\n\t\tgx2WriteGather_submitU32AsBE(0);\n\t}\n\n\tvoid GX2StreamoutInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2SetStreamOutBuffer, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetStreamOutEnable, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetStreamOutContext, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SaveStreamOutContext, LogType::GX2);\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Streamout.h",
    "content": "#pragma once\n#include \"GX2_Resource.h\"\n\n#define GX2_MAX_STREAMOUT_BUFFERS 4\n\nnamespace GX2\n{\n\tstruct GX2StreamOutBuffer\n\t{\n\t\t/* +0x00 */ uint32be size; // size of buffer (if dataPtr is not NULL)\n\t\t/* +0x04 */ MEMPTR<void> dataPtr;\n\t\t/* +0x08 */ uint32be vertexStride;\n\t\t/* +0x0C */ GX2RBuffer rBuffer; // if dataPtr is NULL, use this as the buffer and size\n\t\t/* +0x1C */ MEMPTR<void> ctxPtr; // stream out context\n\t};\n\n\tstatic_assert(sizeof(GX2StreamOutBuffer) == 0x20, \"GX2StreamOutBuffer_t has invalid size\");\n\n\tvoid GX2SetStreamOutBuffer(uint32 bufferIndex, GX2StreamOutBuffer* streamOutBuffer);\n\tvoid GX2StreamoutInit();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Surface.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"GX2.h\"\n#include \"GX2_Surface.h\"\n#include \"GX2_Resource.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n\nnamespace GX2\n{\n\n\tuint32 GX2GetSurfaceMipPitch(GX2Surface* surface, uint32 level)\n\t{\n\t\tLatteAddrLib::AddrSurfaceInfo_OUT surfOut;\n\t\tGX2::GX2CalculateSurfaceInfo(surface, level, &surfOut);\n\t\treturn surfOut.pitch;\n\t}\n\n\tuint32 GX2GetSurfaceFormatBits(Latte::E_GX2SURFFMT surfaceFormat)\n\t{\n\t\tuint32 bpp = Latte::GetFormatBits(surfaceFormat);\n\t\tif (Latte::IsCompressedFormat(surfaceFormat))\n\t\t{\n\t\t\tcemu_assert_debug((bpp & 0xF) == 0);\n\t\t\tbpp /= (4 * 4);\n\t\t}\n\t\treturn bpp;\n\t}\n\n\tuint32 _GX2CalculateSliceSize(GX2Surface* surface, const LatteAddrLib::AddrSurfaceInfo_OUT* surfaceInfo)\n\t{\n\t\tuint32 aaScaler = 1 << surface->aa;\n\t\treturn aaScaler * (surfaceInfo->bpp >> 3) * surfaceInfo->height * surfaceInfo->pitch;\n\t}\n\n\tuint32 GX2GetSurfaceMipSliceSize(GX2Surface* surface, uint32 level)\n\t{\n\t\tLatteAddrLib::AddrSurfaceInfo_OUT surfOut;\n\t\tGX2::GX2CalculateSurfaceInfo(surface, level, &surfOut);\n\t\treturn _GX2CalculateSliceSize(surface, &surfOut);\t\t\n\t}\n\n\tuint32 GX2GetSurfaceSwizzleOffset(GX2Surface* surface, uint32 level)\n\t{\n\t\tuint32 swizzleOffset = 0;\n\t\tuint32 swizzle = surface->swizzle;\n\t\tif (!Latte::TM_IsMacroTiled(surface->tileMode) || level >= ((swizzle >> 16) & 0xFF))\n\t\t\tswizzleOffset = 0;\n\t\telse\n\t\t\tswizzleOffset = swizzle & 0xFFFF;\n\t\treturn swizzleOffset;\n\t}\n\n\tuint32 GX2GetSurfaceSwizzle(GX2Surface* surface)\n\t{\n\t\tuint32 swizzle = surface->swizzle;\n\t\tswizzle = (swizzle >> 8) & 0xFF;\n\t\treturn swizzle;\n\t}\n\n\tuint32 GX2SurfaceIsCompressed(Latte::E_GX2SURFFMT surfaceFormat)\n\t{\n\t\treturn Latte::IsCompressedFormat(surfaceFormat) ? GX2_TRUE : GX2_FALSE;\n\t}\n\n\tvoid GX2CalcDepthBufferHiZInfo(GX2DepthBuffer* depthBuffer, uint32be* sizeOut, uint32be* alignOut)\n\t{\n\t\t*sizeOut = 0x1000;\n\t\t*alignOut = 0x100;\n\n\t\t// todo: implement\n\t}\n\n\tvoid GX2CalcColorBufferAuxInfo(GX2ColorBuffer* colorBuffer, uint32be* sizeOut, uint32be* alignOut)\n\t{\n\t\t*sizeOut = 0x1000;\n\t\t*alignOut = 0x100;\n\n\t\t// todo: implement\n\t}\n\n\tvoid GX2CalculateSurfaceInfo(GX2Surface* surfacePtr, uint32 level, LatteAddrLib::AddrSurfaceInfo_OUT* pSurfOut)\n\t{\n\t\tbool optimizeForDepthBuffer = (surfacePtr->resFlag & GX2_RESFLAG_USAGE_DEPTH_BUFFER) != 0;\n\t\tbool optimizeForScanBuffer = (surfacePtr->resFlag & GX2_RESFLAG_USAGE_SCAN_BUFFER) != 0;\n\t\tLatteAddrLib::GX2CalculateSurfaceInfo(surfacePtr->format, surfacePtr->width, surfacePtr->height, surfacePtr->depth, surfacePtr->dim, surfacePtr->tileMode, surfacePtr->aa, level, pSurfOut, optimizeForDepthBuffer, optimizeForScanBuffer);\n\t}\n\n\tuint32 _CalculateLevels(uint32 resolution)\n\t{\n\t\tuint32 x = 0x80000000;\n\t\tuint32 v = resolution;\n\t\tuint32 n = 0;\n\t\twhile (!(v & x))\n\t\t{\n\t\t\tn++;\n\t\t\tif (n == 32)\n\t\t\t\tbreak;\n\t\t\tx >>= 1;\n\t\t}\n\t\treturn 32 - n;\n\t}\n\n\tuint32 _GX2AdjustLevelCount(GX2Surface* surfacePtr)\n\t{\n\t\tif (surfacePtr->numLevels <= 1)\n\t\t\treturn 1;\n\t\tuint32 levels = std::max(_CalculateLevels(surfacePtr->width), _CalculateLevels(surfacePtr->height));\n\t\tif (surfacePtr->dim == Latte::E_DIM::DIM_3D)\n\t\t\tlevels = std::max(levels, _CalculateLevels(surfacePtr->depth));\n\t\treturn levels;\n\t}\n\n\tvoid _GX2CalcSurfaceSizeAndAlignmentWorkaround(GX2Surface* surface)\n\t{\n\t\t// this workaround catches an issue where the FFL (Mii) library embedded into games tries to use an uninitialized texture\n\t\t// and subsequently crashes. It only happens when FFL files are not present in mlc.\n\t\t// seen in Sonic Lost World and in Super Mario 3D World\n\t\tif ((uint32)surface->dim.value() >= 50 || surface->aa.value() >= 0x100 || (uint32)surface->width.value() >= 0x01000000 || \n\t\t\t(uint32)surface->height.value() >= 0x01000000 || (uint32)surface->depth.value() >= 0x01000000 || (uint32)surface->format.value() >= 0x10000)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"GX2CalcSurfaceSizeAndAlignment(): Uninitialized surface encountered\\n\");\n\t\t\t// overwrite surface parameters with placeholder values to avoid crashing later down the line\n\t\t\tsurface->dim = Latte::E_DIM::DIM_2D;\n\t\t\tsurface->width = 8;\n\t\t\tsurface->height = 8;\n\t\t\tsurface->depth = 1;\n\t\t\tsurface->tileMode = Latte::E_GX2TILEMODE::TM_2D_TILED_THIN1;\n\t\t\tsurface->pitch = 8;\n\t\t\tsurface->numLevels = 0;\n\t\t\tsurface->imagePtr = MEMORY_TILINGAPERTURE_AREA_ADDR;\n\t\t\tsurface->swizzle = 0;\n\t\t\tsurface->aa = 0;\n\t\t\tsurface->format = Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM;\n\t\t\tsurface->alignment = 0x400;\n\t\t}\n\t}\n\n\tvoid GX2CalcSurfaceSizeAndAlignment(GX2Surface* surface)\n\t{\n\t\t_GX2CalcSurfaceSizeAndAlignmentWorkaround(surface);\n\t\tLatteAddrLib::AddrSurfaceInfo_OUT surfOut = { 0 };\n\t\tuint32 firstMipOffset = 0;\n\t\tbool changeTilemode = false;\n\t\tLatte::E_GX2TILEMODE lastTilemode = surface->tileMode;\n\t\tbool hasTileMode32 = surface->tileMode == Latte::E_GX2TILEMODE::TM_32_SPECIAL;\n\t\tif (surface->tileMode == Latte::E_GX2TILEMODE::TM_LINEAR_GENERAL || hasTileMode32)\n\t\t{\n\t\t\tif (surface->dim != Latte::E_DIM::DIM_1D || (surface->resFlag & GX2_RESFLAG_USAGE_DEPTH_BUFFER) != 0 || surface->aa)\n\t\t\t{\n\t\t\t\tif (surface->dim != Latte::E_DIM::DIM_3D || (surface->resFlag & GX2_RESFLAG_USAGE_COLOR_BUFFER) != 0)\n\t\t\t\t\tsurface->tileMode = Latte::E_GX2TILEMODE::TM_2D_TILED_THIN1;\n\t\t\t\telse\n\t\t\t\t\tsurface->tileMode = Latte::E_GX2TILEMODE::TM_2D_TILED_THICK;\n\t\t\t\tchangeTilemode = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsurface->tileMode = Latte::E_GX2TILEMODE::TM_LINEAR_ALIGNED;\n\t\t\t}\n\t\t\tlastTilemode = surface->tileMode;\n\t\t}\n\n\t\tif (surface->numLevels == 0)\n\t\t\tsurface->numLevels = 1;\n\t\tsurface->numLevels = std::min<uint32>(surface->numLevels, _GX2AdjustLevelCount(surface));\n\t\tsurface->mipOffset[0] = 0;\n\t\tif (Latte::TM_IsMacroTiled(surface->tileMode))\n\t\t\tsurface->swizzle = (surface->swizzle & 0xFF00FFFF) | 0xD0000;\n\t\telse\n\t\t\tsurface->swizzle = surface->swizzle & 0xFF00FFFF;\n\t\t// FIX 32\n\t\tuint32 fix32Mode;\n\t\tif (hasTileMode32)\n\t\t{\n\t\t\tif (Latte::IsCompressedFormat(surface->format))\n\t\t\t\tfix32Mode = 2;\n\t\t\telse\n\t\t\t\tfix32Mode = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfix32Mode = 0;\n\t\t}\n\t\t// setup levels\n\t\tuint32 prevSize = 0;\n\t\tfor (uint32 level = 0; level < surface->numLevels; ++level)\n\t\t{\n\t\t\tGX2CalculateSurfaceInfo(surface, level, &surfOut);\n\t\t\tif (level)\n\t\t\t{\n\t\t\t\tuint32 pad = 0;\n\t\t\t\tif (Latte::TM_IsMacroTiled(lastTilemode) && !Latte::TM_IsMacroTiled(surfOut.hwTileMode))\n\t\t\t\t{\n\t\t\t\t\tsurface->swizzle = (surface->swizzle & 0xFF00FFFF) | (level << 16);\n\t\t\t\t\tlastTilemode = (Latte::E_GX2TILEMODE)surfOut.hwTileMode;\n\t\t\t\t\tif (level > 1)\n\t\t\t\t\t\tpad = surface->swizzle & 0xFFFF;\n\t\t\t\t}\n\t\t\t\tpad += (surfOut.baseAlign - prevSize % surfOut.baseAlign) % surfOut.baseAlign;\n\t\t\t\tif (level == 1)\n\t\t\t\t{\n\t\t\t\t\tfirstMipOffset = pad + prevSize;\n\t\t\t\t}\n\t\t\t\telse if (level > 1)\n\t\t\t\t{\n\t\t\t\t\tsurface->mipOffset[level - 1] = pad + prevSize + surface->mipOffset[level - 2];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (changeTilemode)\n\t\t\t\t{\n\t\t\t\t\tif (surface->tileMode != (Latte::E_GX2TILEMODE)surfOut.hwTileMode)\n\t\t\t\t\t{\n\t\t\t\t\t\tsurface->tileMode = (Latte::E_GX2TILEMODE)surfOut.hwTileMode;\n\t\t\t\t\t\tGX2CalculateSurfaceInfo(surface, 0, &surfOut);\n\t\t\t\t\t\tif (!Latte::TM_IsMacroTiled(surface->tileMode))\n\t\t\t\t\t\t\tsurface->swizzle = surface->swizzle & 0xFF00FFFF;\n\t\t\t\t\t\tlastTilemode = surface->tileMode;\n\t\t\t\t\t}\n\t\t\t\t\tif (surface->width < (surfOut.pitchAlign << fix32Mode)\n\t\t\t\t\t\t&& surface->height < (surfOut.heightAlign << fix32Mode))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (surface->tileMode == Latte::E_GX2TILEMODE::TM_2D_TILED_THICK)\n\t\t\t\t\t\t\tsurface->tileMode = Latte::E_GX2TILEMODE::TM_1D_TILED_THICK;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tsurface->tileMode = Latte::E_GX2TILEMODE::TM_1D_TILED_THIN1;\n\t\t\t\t\t\tGX2CalculateSurfaceInfo(surface, 0, &surfOut);\n\t\t\t\t\t\tsurface->swizzle = surface->swizzle & 0xFF00FFFF;\n\t\t\t\t\t\tlastTilemode = surface->tileMode;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsurface->imageSize = (uint32)(surfOut.surfSize);\n\t\t\t\tsurface->alignment = surfOut.baseAlign;\n\t\t\t\tsurface->pitch = surfOut.pitch;\n\t\t\t}\n\t\t\tprevSize = (uint32)(surfOut.surfSize);\n\t\t}\n\t\tif (surface->numLevels > 1)\n\t\t\tsurface->mipSize = prevSize + surface->mipOffset[surface->numLevels - 2];\n\t\telse\n\t\t\tsurface->mipSize = 0;\n\t\tsurface->mipOffset[0] = firstMipOffset;\n\t\tif (surface->format == Latte::E_GX2SURFFMT::NV12_UNORM)\n\t\t{\n\t\t\tuint32 padding = (surface->alignment - surface->imageSize % surface->alignment) % surface->alignment;\n\t\t\tsurface->mipOffset[0] = padding + surface->imageSize;\n\t\t\tsurface->imageSize = surface->mipOffset[0] + ((uint32)surface->imageSize >> 1);\n\t\t}\n\t}\n\n\tLatte::E_ENDIAN_SWAP GetSurfaceFormatSwapMode(Latte::E_GX2SURFFMT fmt)\n\t{\n\t\t// swap mode is 0 for all formats\n\t\treturn Latte::E_ENDIAN_SWAP::SWAP_NONE;\n\t}\n\n\tuint32 GetSurfaceColorBufferExportFormat(Latte::E_GX2SURFFMT fmt)\n\t{\n\t\tconst uint8 table[0x40] = {\n\t\t\t0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01,\n\t\t\t0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,\n\t\t\t0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,\n\t\t\t0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,\n\t\t\t0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00,\n\t\t\t0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n\t\t\t0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,\n\t\t\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\n\t\tuint32 fmtHW = (uint32)fmt & 0x3F;\n\t\treturn table[fmtHW];\n\t}\n\n\tuint32 GX2CheckSurfaceUseVsFormat(uint32 resFlags, uint32 surfaceFormat)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"GX2CheckSurfaceUseVsFormat - stub\");\n\t\treturn 1;\n\t}\n\n\tvoid GX2SetSurfaceSwizzle(GX2Surface* surface, uint32 newSwizzle)\n\t{\n\t\tuint32 currentSwizzle = surface->swizzle;\n\t\tcurrentSwizzle &= ~0xFF00;\n\t\tcurrentSwizzle |= (newSwizzle << 8); // newSwizzle isn't actually masked and some games set it to values above 0xFF\n\t\tsurface->swizzle = currentSwizzle;\n\t}\n\n\tvoid GX2SurfaceInit()\n\t{\n\t\tcafeExportRegister(\"gx2\", GX2GetSurfaceMipPitch, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetSurfaceFormatBits, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetSurfaceMipSliceSize, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetSurfaceSwizzleOffset, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2GetSurfaceSwizzle, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SurfaceIsCompressed, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2CalcDepthBufferHiZInfo, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2CalcColorBufferAuxInfo, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2CalcSurfaceSizeAndAlignment, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2CheckSurfaceUseVsFormat, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetSurfaceSwizzle, LogType::GX2);\n\t}\n};"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Surface.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n\n// todo - move into GX2 namespace\n\nstruct GX2Surface\n{\n\t/* +0x000 */ betype<Latte::E_DIM> dim;\n\t/* +0x004 */ uint32be width;\n\t/* +0x008 */ uint32be height;\n\t/* +0x00C */ uint32be depth;\n\t/* +0x010 */ uint32be numLevels; // number of mipmap levels including base image. Should be at least 1\n\t/* +0x014 */ betype<Latte::E_GX2SURFFMT> format;\n\t/* +0x018 */ uint32be aa; // anti-aliasing mode\n\t/* +0x01C */ uint32be resFlag; // GX2_RESFLAG_* and GX2R_RESFLAG_*\n\t/* +0x020 */ uint32be imageSize;\n\t/* +0x024 */ uint32be imagePtr;\n\t/* +0x028 */ uint32be mipSize;\n\t/* +0x02C */ uint32be mipPtr;\n\t/* +0x030 */ betype<Latte::E_GX2TILEMODE> tileMode;\n\t/* +0x034 */ uint32be swizzle;\n\t/* +0x038 */ uint32be alignment;\n\t/* +0x03C */ uint32be pitch;\n\t/* +0x040 */ uint32be mipOffset[13];\n}; // size: 0x74\n\nstatic_assert(sizeof(betype<Latte::E_DIM>) == 4);\nstatic_assert(sizeof(betype<Latte::E_GX2TILEMODE>) == 4);\nstatic_assert(sizeof(GX2Surface) == 0x74);\n\n// color and depth buffer\n\nstruct GX2ColorBuffer\n{\n\t/* +0x00 */ GX2Surface\t\tsurface;\n\t/* +0x74 */ uint32be\t\tviewMip;\n\t/* +0x78 */ uint32be\t\tviewFirstSlice;\n\t/* +0x7C */ uint32be\t\tviewNumSlices;\n\t/* +0x80 */ MEMPTR<void>\tauxData;\n\t/* +0x84 */ uint32be\t\tauxSize2;\n\t/* +0x88 */ uint32be\t\treg_size; // CB_COLOR*_SIZE\n\t/* +0x8C */ uint32be\t\treg_info; // CB_COLOR*_INFO\n\t/* +0x90 */ uint32be\t\treg_view; // CB_COLOR*_VIEW\n\t/* +0x94 */ uint32be\t\treg_mask; // CB_COLOR*_MASK\n\t/* +0x98 */ uint32be\t\treg4; // ?\n};\n\nstatic_assert(sizeof(GX2ColorBuffer) == 0x9C);\n\nstruct GX2DepthBuffer\n{\n\t/* +0x00 */ GX2Surface\t\tsurface;\n\t/* +0x74 */ uint32be\t\tviewMip;\n\t/* +0x78 */ uint32be\t\tviewFirstSlice;\n\t/* +0x7C */ uint32be\t\tviewNumSlices;\n\t/* +0x80 */ MEMPTR<void>\thiZPtr;\n\t/* +0x84 */ uint32be\t\thiZSize;\n\t/* +0x88 */ float32be\t\tclearDepth;\n\t/* +0x8C */ uint32be\t\tclearStencil;\n\t/* +0x90 */ uint32be\t\treg_size;\n\t/* +0x94 */ uint32be\t\treg_view;\n\t/* +0x98 */ uint32be\t\treg_base;\n\t/* +0x9C */ uint32be\t\treg_htile_surface;\n\t/* +0xA0 */ uint32be\t\treg_prefetch_limit;\n\t/* +0xA4 */ uint32be\t\treg_preload_control;\n\t/* +0xA8 */ uint32be\t\treg_poly_offset_db_fmt_cntl;\n};\n\nstatic_assert(sizeof(GX2DepthBuffer) == 0xAC);\n\nnamespace GX2\n{\n\tvoid GX2CalculateSurfaceInfo(GX2Surface* surfacePtr, uint32 level, LatteAddrLib::AddrSurfaceInfo_OUT* pSurfOut);\n\n\tLatte::E_ENDIAN_SWAP GetSurfaceFormatSwapMode(Latte::E_GX2SURFFMT fmt);\n\tuint32 GetSurfaceColorBufferExportFormat(Latte::E_GX2SURFFMT fmt);\n\n\tvoid GX2CalcSurfaceSizeAndAlignment(GX2Surface* surface);\n\n\tvoid GX2SurfaceInit();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Surface_Copy.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LatteAsyncCommands.h\"\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n#include \"GX2.h\"\n#include \"GX2_Resource.h\"\n\ntemplate<uint32 copyBpp>\nvoid gx2SurfaceCopySoftware_specialized(\n\tuint8* inputData, sint32 surfSrcHeight, sint32 srcPitch, sint32 srcDepth, uint32 srcSlice, uint32 srcSwizzle, uint32 srcHwTileMode,\n\tuint8* outputData, sint32 surfDstHeight, sint32 dstPitch, sint32 dstDepth, uint32 dstSlice, uint32 dstSwizzle, uint32 dstHwTileMode,\n\tuint32 copyWidth, uint32 copyHeight)\n{\n\tuint32 srcPipeSwizzle = (srcSwizzle >> 8) & 1;\n\tuint32 srcBankSwizzle = ((srcSwizzle >> 9) & 3);\n\tuint32 dstPipeSwizzle = (dstSwizzle >> 8) & 1;\n\tuint32 dstBankSwizzle = ((dstSwizzle >> 9) & 3);\n\n\tfor (uint32 y = 0; y < copyHeight; y++)\n\t{\n\t\tfor (uint32 x = 0; x < copyWidth; x++)\n\t\t{\n\t\t\t// calculate address of input block\n\t\t\tuint32 srcOffset = 0;\n\t\t\tif (srcHwTileMode == 0 || srcHwTileMode == 1)\n\t\t\t\tsrcOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordLinear(x, y, srcSlice, 0, copyBpp, srcPitch, surfSrcHeight, srcDepth);\n\t\t\telse if (srcHwTileMode == 2 || srcHwTileMode == 3)\n\t\t\t\tsrcOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMicroTiled(x, y, srcSlice, copyBpp, srcPitch, surfSrcHeight, (Latte::E_HWTILEMODE)srcHwTileMode, false);\n\t\t\telse\n\t\t\t\tsrcOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMacroTiled(x, y, srcSlice, 0, copyBpp, srcPitch, surfSrcHeight, 1 * 1, (Latte::E_HWTILEMODE)srcHwTileMode, false, srcPipeSwizzle, srcBankSwizzle);\n\t\t\tuint8* inputBlockData = inputData + srcOffset;\n\t\t\t// calculate address of output block\n\t\t\tuint32 dstOffset = 0;\n\t\t\tif (dstHwTileMode == 0 || dstHwTileMode == 1)\n\t\t\t\tdstOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordLinear(x, y, dstSlice, 0, copyBpp, dstPitch, surfDstHeight, dstDepth);\n\t\t\telse if (dstHwTileMode == 2 || dstHwTileMode == 3)\n\t\t\t\tdstOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMicroTiled(x, y, dstSlice, copyBpp, dstPitch, surfDstHeight, (Latte::E_HWTILEMODE)dstHwTileMode, false);\n\t\t\telse\n\t\t\t\tdstOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMacroTiled(x, y, dstSlice, 0, copyBpp, dstPitch, surfDstHeight, 1 * 1, (Latte::E_HWTILEMODE)dstHwTileMode, false, dstPipeSwizzle, dstBankSwizzle);\n\t\t\tuint8* outputBlockData = outputData + dstOffset;\n\n\t\t\tif constexpr (copyBpp == 8)\n\t\t\t{\n\t\t\t\toutputBlockData[0] = inputBlockData[0];\n\t\t\t}\n\t\t\telse if constexpr (copyBpp == 16)\n\t\t\t{\n\t\t\t\t*(uint16*)outputBlockData = *(uint16*)inputBlockData;\n\t\t\t}\n\t\t\telse if constexpr (copyBpp == 32)\n\t\t\t{\n\t\t\t\t*(uint32*)outputBlockData = *(uint32*)inputBlockData;\n\t\t\t}\n\t\t\telse if constexpr (copyBpp == 64)\n\t\t\t{\n\t\t\t\t*(uint32*)(outputBlockData + 0) = *(uint32*)(inputBlockData + 0);\n\t\t\t\t*(uint32*)(outputBlockData + 4) = *(uint32*)(inputBlockData + 4);\n\t\t\t}\n\t\t\telse if constexpr (copyBpp == 128)\n\t\t\t{\n\t\t\t\t*(uint32*)(outputBlockData + 0) = *(uint32*)(inputBlockData + 0);\n\t\t\t\t*(uint32*)(outputBlockData + 4) = *(uint32*)(inputBlockData + 4);\n\t\t\t\t*(uint32*)(outputBlockData + 8) = *(uint32*)(inputBlockData + 8);\n\t\t\t\t*(uint32*)(outputBlockData + 12) = *(uint32*)(inputBlockData + 12);\n\t\t\t}\n\t\t}\n\t}\n}\n\n// fast copy for tilemode 4 to tilemode 4\n// assumes aa 1\n// this only supports the cases where every micro tile fits within 256 bytes (group size)\n// we could accelerate this even further if we copied whole macro blocks\nvoid gx2SurfaceCopySoftware_fastPath_tm4Copy(uint8* inputData, sint32 surfSrcHeight, sint32 srcPitch, sint32 srcDepth, uint32 srcSlice, uint32 srcSwizzle,\n\tuint8* outputData, sint32 surfDstHeight, sint32 dstPitch, sint32 dstDepth, uint32 dstSlice, uint32 dstSwizzle,\n\tuint32 copyWidth, uint32 copyHeight, uint32 copyBpp)\n{\n\tcemu_assert_debug((copyWidth & 7) == 0);\n\tcemu_assert_debug((copyHeight & 7) == 0);\n\n\tuint32 srcPipeSwizzle = (srcSwizzle >> 8) & 1;\n\tuint32 srcBankSwizzle = ((srcSwizzle >> 9) & 3);\n\tuint32 dstPipeSwizzle = (dstSwizzle >> 8) & 1;\n\tuint32 dstBankSwizzle = ((dstSwizzle >> 9) & 3);\n\n\tuint32 texelBytes = copyBpp / 8;\n\n\tif (srcSlice == dstSlice && srcSwizzle == dstSwizzle && surfSrcHeight == surfDstHeight && srcPitch == dstPitch)\n\t{\n\t\t// shared tile offsets\n\t\tfor (uint32 y = 0; y < copyHeight; y += 8)\n\t\t{\n\t\t\tfor (uint32 x = 0; x < copyWidth; x += 8)\n\t\t\t{\n\t\t\t\t// copy 8x8 micro tile\n\t\t\t\tuint32 offset = LatteAddrLib::ComputeSurfaceAddrFromCoordMacroTiled(x, y, srcSlice, 0, copyBpp, srcPitch, surfSrcHeight, 1 * 1, Latte::E_HWTILEMODE::TM_2D_TILED_THIN1, false, srcPipeSwizzle, srcBankSwizzle);\n\t\t\t\tuint8* inputBlockData = inputData + offset;\n\t\t\t\tuint8* outputBlockData = outputData + offset;\n\t\t\t\tmemcpy(outputBlockData, inputBlockData, texelBytes * (8 * 8));\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// separate tile offsets\n\t\tfor (uint32 y = 0; y < copyHeight; y += 8)\n\t\t{\n\t\t\tfor (uint32 x = 0; x < copyWidth; x += 8)\n\t\t\t{\n\t\t\t\t// copy 8x8 micro tile\n\t\t\t\tuint32 srcOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMacroTiled(x, y, srcSlice, 0, copyBpp, srcPitch, surfSrcHeight, 1 * 1, Latte::E_HWTILEMODE::TM_2D_TILED_THIN1, false, srcPipeSwizzle, srcBankSwizzle);\n\t\t\t\tuint8* inputBlockData = inputData + srcOffset;\n\t\t\t\tuint32 dstOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMacroTiled(x, y, dstSlice, 0, copyBpp, dstPitch, surfDstHeight, 1 * 1, Latte::E_HWTILEMODE::TM_2D_TILED_THIN1, false, dstPipeSwizzle, dstBankSwizzle);\n\t\t\t\tuint8* outputBlockData = outputData + dstOffset;\n\t\t\t\tmemcpy(outputBlockData, inputBlockData, texelBytes * (8 * 8));\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid gx2SurfaceCopySoftware(\n\tuint8* inputData, sint32 surfSrcHeight, sint32 srcPitch, sint32 srcDepth, uint32 srcSlice, uint32 srcSwizzle, uint32 srcHwTileMode,\n\tuint8* outputData, sint32 surfDstHeight, sint32 dstPitch, sint32 dstDepth, uint32 dstSlice, uint32 dstSwizzle, uint32 dstHwTileMode,\n\tuint32 copyWidth, uint32 copyHeight, uint32 copyBpp)\n{\n\tif (srcHwTileMode == 4 && dstHwTileMode == 4 && (copyWidth & 7) == 0 && (copyHeight & 7) == 0 && copyBpp <= 32) // todo - check sample == 1\n\t{\n\t\tgx2SurfaceCopySoftware_fastPath_tm4Copy(inputData, surfSrcHeight, srcPitch, srcDepth, srcSlice, srcSwizzle, outputData, surfDstHeight, dstPitch, dstDepth, dstSlice, dstSwizzle, copyWidth, copyHeight, copyBpp);\n\t\treturn;\n\t}\n\n\tif (copyBpp == 8)\n\t\tgx2SurfaceCopySoftware_specialized<8>(inputData, surfSrcHeight, srcPitch, srcDepth, srcSlice, srcSwizzle, srcHwTileMode, outputData, surfDstHeight, dstPitch, dstDepth, dstSlice, dstSwizzle, dstHwTileMode, copyWidth, copyHeight);\n\telse if (copyBpp == 16)\n\t\tgx2SurfaceCopySoftware_specialized<16>(inputData, surfSrcHeight, srcPitch, srcDepth, srcSlice, srcSwizzle, srcHwTileMode, outputData, surfDstHeight, dstPitch, dstDepth, dstSlice, dstSwizzle, dstHwTileMode, copyWidth, copyHeight);\n\telse if (copyBpp == 32)\n\t\tgx2SurfaceCopySoftware_specialized<32>(inputData, surfSrcHeight, srcPitch, srcDepth, srcSlice, srcSwizzle, srcHwTileMode, outputData, surfDstHeight, dstPitch, dstDepth, dstSlice, dstSwizzle, dstHwTileMode, copyWidth, copyHeight);\n\telse if (copyBpp == 64)\n\t\tgx2SurfaceCopySoftware_specialized<64>(inputData, surfSrcHeight, srcPitch, srcDepth, srcSlice, srcSwizzle, srcHwTileMode, outputData, surfDstHeight, dstPitch, dstDepth, dstSlice, dstSwizzle, dstHwTileMode, copyWidth, copyHeight);\n\telse if (copyBpp == 128)\n\t\tgx2SurfaceCopySoftware_specialized<128>(inputData, surfSrcHeight, srcPitch, srcDepth, srcSlice, srcSwizzle, srcHwTileMode, outputData, surfDstHeight, dstPitch, dstDepth, dstSlice, dstSwizzle, dstHwTileMode, copyWidth, copyHeight);\n\telse\n\t\tcemu_assert_debug(false);\n}\n\nvoid gx2Surface_GX2CopySurface(GX2Surface* srcSurface, uint32 srcMip, uint32 srcSlice, GX2Surface* dstSurface, uint32 dstMip, uint32 dstSlice)\n{\n\tsint32 dstWidth = dstSurface->width;\n\tsint32 dstHeight = dstSurface->height;\n\tsint32 srcWidth = srcSurface->width;\n\tsint32 srcHeight = srcSurface->height;\n\n\tsint32 dstMipWidth = std::max(dstWidth>>dstMip, 1);\n\tsint32 dstMipHeight = std::max(dstHeight>>dstMip, 1);\n\tsint32 srcMipWidth = std::max(srcWidth>>srcMip, 1);\n\tsint32 srcMipHeight = std::max(srcHeight>>srcMip, 1);\n\n\tif( dstMipWidth != srcMipWidth || dstMipHeight != srcMipHeight )\n\t{\n\t\tcemuLog_logDebugOnce(LogType::Force, \"GX2CopySurface: Mismatching mip resolution\");\n\t\treturn;\n\t}\n\t// handle format\n\tLatte::E_GX2SURFFMT srcFormat = srcSurface->format;\n\tLatte::E_GX2SURFFMT dstFormat = dstSurface->format;\n\tuint32 srcBPP = Latte::GetFormatBits(srcFormat);\n\tuint32 dstBPP = Latte::GetFormatBits(dstFormat);\n\tauto srcHwFormat = Latte::GetHWFormat(srcFormat);\n\tauto dstHwFormat = Latte::GetHWFormat(dstFormat);\n\t// get texture info\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfOutSrc = {0};\n\tGX2::GX2CalculateSurfaceInfo(srcSurface, srcMip, &surfOutSrc);\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfOutDst = {0};\n\tGX2::GX2CalculateSurfaceInfo(dstSurface, dstMip, &surfOutDst);\n\t// check parameters\n\tif (srcSurface->numLevels == 0)\n\t{\n\t\tdebug_printf(\"GX2CopySurface(): mip count is 0\\n\");\n\t\treturn;\n\t}\n\t// get input pointer\n\tuint8* inputData = NULL;\n\tcemu_assert(srcMip < srcSurface->numLevels);\n\tif( srcMip == 0 )\n\t\tinputData = (uint8*)memory_getPointerFromVirtualOffset(srcSurface->imagePtr);\n\telse if( srcMip == 1 )\n\t\tinputData = (uint8*)memory_getPointerFromVirtualOffset(srcSurface->mipPtr);\n\telse\n\t{\n\t\tinputData = (uint8*)memory_getPointerFromVirtualOffset(srcSurface->mipPtr + srcSurface->mipOffset[srcMip - 1]);\n\t}\n\t// get output pointer\n\tuint8* outputData = NULL;\n\tcemu_assert(dstMip < dstSurface->numLevels);\n\tif( dstMip == 0 )\n\t\toutputData = (uint8*)memory_getPointerFromVirtualOffset(dstSurface->imagePtr);\n\telse if( dstMip == 1 )\n\t\toutputData = (uint8*)memory_getPointerFromVirtualOffset(dstSurface->mipPtr);\n\telse\n\t{\n\t\toutputData = (uint8*)memory_getPointerFromVirtualOffset(dstSurface->mipPtr + dstSurface->mipOffset[dstMip - 1]);\n\t}\n\t\n\tif( srcHwFormat != dstHwFormat )\n\t{\n\t\t// mismatching format\n\t\tcemuLog_logDebug(LogType::Force, \"GX2CopySurface(): Format mismatch\");\n\t\treturn;\n\t}\n\n\t// note: Do not trust values from the input GX2Surface* structs but rely on surfOutDst/surfOutSrc instead if possible.\n\t// src\n\tuint32 srcPitch = surfOutSrc.pitch;\n\tuint32 srcSwizzle = srcSurface->swizzle;\n\tuint32 srcHwTileMode = (uint32)surfOutSrc.hwTileMode;\n\tuint32 srcDepth = std::max<uint32>(surfOutSrc.depth, 1);\n\tif (srcHwTileMode == 0) // linear\n\t{\n\t\tsrcPitch = srcSurface->pitch >> srcMip;\n\t\tsrcPitch = std::max<uint32>(srcPitch, 1);\n\t}\n\t// dst\n\tuint32 dstPitch = surfOutDst.pitch;\n\tuint32 dstSwizzle = dstSurface->swizzle;\n\tuint32 dstHwTileMode = (uint32)surfOutDst.hwTileMode;\n\tuint32 dstDepth = std::max<uint32>(surfOutDst.depth, 1);\n\tuint32 dstBpp = surfOutDst.bpp;\n\n\t//debug_printf(\"Src Tex: %08X %dx%d Swizzle: %08x tm: %d fmt: %04x use: %02x\\n\", _swapEndianU32(srcSurface->imagePtr), _swapEndianU32(srcSurface->width), _swapEndianU32(srcSurface->height), _swapEndianU32(srcSurface->swizzle), _swapEndianU32(srcSurface->tileMode), _swapEndianU32(srcSurface->format), (uint32)srcSurface->resFlag);\n\t//debug_printf(\"Dst Tex: %08X %dx%d Swizzle: %08x tm: %d fmt: %04x use: %02x\\n\", _swapEndianU32(dstSurface->imagePtr), _swapEndianU32(dstSurface->width), _swapEndianU32(dstSurface->height), _swapEndianU32(dstSurface->swizzle), _swapEndianU32(dstSurface->tileMode), _swapEndianU32(dstSurface->format), (uint32)dstSurface->resFlag);\n\n\tbool requestGPURAMCopy = false;\n\tbool debugTestForceCPUCopy = false;\n\n\tif (srcSurface->tileMode == Latte::E_GX2TILEMODE::TM_LINEAR_SPECIAL && dstSurface->tileMode == Latte::E_GX2TILEMODE::TM_2D_TILED_THIN1)\n\t\tdebugTestForceCPUCopy = true;\n\n\tif (srcSurface->tileMode == Latte::E_GX2TILEMODE::TM_2D_TILED_THIN1 && dstSurface->tileMode == Latte::E_GX2TILEMODE::TM_LINEAR_SPECIAL )\n\t{\n\t\tLatteAsyncCommands_queueForceTextureReadback(\n\t\t\tsrcSurface->imagePtr,\n\t\t\tsrcSurface->mipPtr,\n\t\t\tsrcSurface->swizzle,\n\t\t\t(uint32)srcSurface->format.value(),\n\t\t\tsrcSurface->width,\n\t\t\tsrcSurface->height,\n\t\t\tsrcSurface->depth,\n\t\t\tsrcSurface->pitch,\n\t\t\tsrcSlice,\n\t\t\t(uint32)srcSurface->dim.value(),\n\t\t\tLatte::MakeHWTileMode(srcSurface->tileMode),\n\t\t\tsrcSurface->aa,\n\t\t\tsrcMip);\n\n\t\tLatteAsyncCommands_waitUntilAllProcessed();\n\n\t\tdebugTestForceCPUCopy = true;\n\t}\n\n\t// send copy command to GPU\n\tif( srcHwTileMode > 0 && srcHwTileMode < 16 && dstHwTileMode > 0 && dstHwTileMode < 16 || requestGPURAMCopy )\n\t{\n\t\tGX2::GX2ReserveCmdSpace(1+13*2);\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_HLE_COPY_SURFACE_NEW, 13*2),\n\t\t// src\n\t\t\t(uint32)srcSurface->imagePtr,\n\t\t\t(uint32)srcSurface->mipPtr,\n\t\t\t(uint32)srcSurface->swizzle,\n\t\t\t(uint32)srcSurface->format.value(),\n\t\t\t(uint32)srcSurface->width,\n\t\t\t(uint32)srcSurface->height,\n\t\t\t(uint32)srcSurface->depth,\n\t\t\t(uint32)srcSurface->pitch,\n\t\t\tsrcSlice,\n\t\t\t(uint32)srcSurface->dim.value(),\n\t\t\t(uint32)srcSurface->tileMode.value(),\n\t\t\t(uint32)srcSurface->aa,\n\t\t\tsrcMip,\n\t\t// dst\n\t\t\t(uint32)dstSurface->imagePtr,\n\t\t\t(uint32)dstSurface->mipPtr,\n\t\t\t(uint32)dstSurface->swizzle,\n\t\t\t(uint32)dstSurface->format.value(),\n\t\t\t(uint32)dstSurface->width,\n\t\t\t(uint32)dstSurface->height,\n\t\t\t(uint32)dstSurface->depth,\n\t\t\t(uint32)dstSurface->pitch,\n\t\t\tdstSlice,\n\t\t\t(uint32)dstSurface->dim.value(),\n\t\t\t(uint32)dstSurface->tileMode.value(),\n\t\t\t(uint32)dstSurface->aa,\n\t\t\tdstMip);\n\t}\n\n\tif (requestGPURAMCopy)\n\t\treturn; // if RAM copy happens on the GPU side we skip it here\n\n\t// manually exclude expensive CPU texture copies for some known game framebuffer textures\n\t// todo - find a better way to solve this\n\tbool isDynamicTexCopy = false;\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->imagePtr >= 0xF4000000 && srcSurface->width >= 800 && srcFormat == Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT); // SM3DW\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->imagePtr >= 0xF4000000 && srcSurface->width >= 800 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM); // Trine 2\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->imagePtr >= 0xF4000000 && srcSurface->width == 0xA0 && srcFormat == Latte::E_GX2SURFFMT::R32_FLOAT); // Little Inferno\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->imagePtr >= 0xF4000000 && srcSurface->width == 1280 && srcFormat == Latte::E_GX2SURFFMT::R32_FLOAT); // Donkey Kong Tropical Freeze\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->imagePtr >= 0xF4000000 && srcSurface->width == 640 && srcSurface->height == 320 && srcFormat == Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT); // SM3DW Switch Scramble Circus\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 1280 && srcSurface->height == 720 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM && srcSurface->tileMode != Latte::E_GX2TILEMODE::TM_LINEAR_ALIGNED ); // Affordable Space Adventures\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 854 && srcSurface->height == 480 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM); // Affordable Space Adventures\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->imagePtr >= 0xF4000000 && srcSurface->width == 1152 && srcSurface->height == 720 && srcFormat == Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT && (srcSurface->resFlag&GX2_RESFLAG_USAGE_COLOR_BUFFER) != 0 ); // Star Fox Zero\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->imagePtr >= 0xF4000000 && srcSurface->width == 680 && srcSurface->height == 480 && srcFormat == Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT && (srcSurface->resFlag&GX2_RESFLAG_USAGE_COLOR_BUFFER) != 0 ); // Star Fox Zero\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->imagePtr >= 0xF4000000 && srcSurface->width == 1280 && srcSurface->height == 720 && srcFormat == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT ); // Qube\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 322 && srcSurface->height == 182 && srcFormat == Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM ); // Qube\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 640 && srcSurface->height == 360 && srcFormat == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT ); // Qube\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 1920 && srcSurface->height == 1080 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM && dstSurface->resFlag == 0x80000003); // Cosmophony\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 854 && srcSurface->height == 480 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM && dstSurface->resFlag == 0x3); // Cosmophony\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 1280 && srcSurface->height == 720 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB && dstSurface->resFlag == 0x3); // The Fall\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 854 && srcSurface->height == 480 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB && dstSurface->resFlag == 0x3); // The Fall\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 1280 && srcSurface->height == 720 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB && dstSurface->resFlag == 0x80000003); // The Fall\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 1280 && srcSurface->height == 720 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB && srcSurface->resFlag == 0x80000003); // Nano Assault Neo\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->imagePtr >= 0xF4000000 && srcSurface->width == 1280 && srcSurface->height == 720 && srcFormat == Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM); // Mario Party 10\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->imagePtr >= 0xF4000000 && srcSurface->width == 854 && srcSurface->height == 480 && srcFormat == Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM); // Mario Party 10\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 1920 && srcSurface->height == 1080 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM && dstSurface->resFlag == 0x3); // Hello Kitty Kruisers\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 1024 && srcSurface->height == 1024 && srcFormat == Latte::E_GX2SURFFMT::R32_FLOAT && dstSurface->resFlag == 0x5); // Art Academy\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 260 && srcSurface->height == 148 && srcFormat == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT && dstSurface->resFlag == 0x3); // Transformers: Rise of the Dark Spark\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 1040 && srcSurface->height == 592 && srcFormat == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT && dstSurface->resFlag == 0x3); // Transformers: Rise of the Dark Spark\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 854 && srcSurface->height == 480 && srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB && srcSurface->resFlag == 0x3); // Nano Assault Neo\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 1024 && srcSurface->height == 576 && srcFormat == Latte::E_GX2SURFFMT::D24_S8_UNORM && srcSurface->resFlag == 0x1); // Skylanders SuperChargers\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 1152 && srcSurface->height == 648 && (srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM || srcFormat == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT) && srcSurface->resFlag == 0x1); // Watch Dogs\n\tisDynamicTexCopy = isDynamicTexCopy || (srcSurface->width == 576 && srcSurface->height == 324 && (srcFormat == Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM || srcFormat == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT) && srcSurface->resFlag == 0x1); // Watch Dogs\n\n\tif( isDynamicTexCopy && debugTestForceCPUCopy == false)\n\t{\n\t\tdebug_printf(\"Software tex copy blocked\\n\");\n\t\treturn;\n\t}\n\n\tsint32 copyWidth = dstMipWidth;\n\tsint32 copyHeight = dstMipHeight;\n\tif (Latte::IsCompressedFormat(dstHwFormat))\n\t{\n\t\tcopyWidth = (copyWidth + 3) / 4;\n\t\tcopyHeight = (copyHeight + 3) / 4;\n\t}\n\n\tgx2SurfaceCopySoftware(inputData, surfOutSrc.height, srcPitch, srcDepth, srcSlice, srcSwizzle, srcHwTileMode,\n\t\toutputData, surfOutDst.height, dstPitch, dstDepth, dstSlice, dstSwizzle, dstHwTileMode,\n\t\tcopyWidth, copyHeight, dstBpp);\n}\n\nvoid gx2Export_GX2CopySurface(PPCInterpreter_t* hCPU)\n{\n\tGX2Surface* srcSurface = (GX2Surface*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\tuint32 srcMip = hCPU->gpr[4];\n\tuint32 srcSlice = hCPU->gpr[5];\n\tGX2Surface* dstSurface = (GX2Surface*)memory_getPointerFromVirtualOffset(hCPU->gpr[6]);\n\tuint32 dstMip = hCPU->gpr[7];\n\tuint32 dstSlice = hCPU->gpr[8];\n\tgx2Surface_GX2CopySurface(srcSurface, srcMip, srcSlice, dstSurface, dstMip, dstSlice);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\ntypedef struct  \n{\n\tsint32 left;\n\tsint32 top;\n\tsint32 right;\n\tsint32 bottom;\n}GX2Rect_t;\n\ntypedef struct  \n{\n\tsint32 x;\n\tsint32 y;\n}GX2Point_t;\n\nvoid gx2Export_GX2CopySurfaceEx(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"GX2CopySurfaceEx(0x{:08x},{},{},0x{:08x},{},{},{},0x{:08x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8], hCPU->gpr[9], hCPU->gpr[10], memory_readU32(hCPU->gpr[1]+0x8));\n\tGX2Surface* srcSurface = (GX2Surface*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\tuint32 srcMip = hCPU->gpr[4];\n\tuint32 srcSlice = hCPU->gpr[5];\n\tGX2Surface* dstSurface = (GX2Surface*)memory_getPointerFromVirtualOffset(hCPU->gpr[6]);\n\tuint32 dstMip = hCPU->gpr[7];\n\tuint32 dstSlice = hCPU->gpr[8];\n\tsint32 rectCount = hCPU->gpr[9];\n\tMPTR rectSrcArrayMPTR = hCPU->gpr[10];\n\tMPTR pointDstArrayMPTR = memory_readU32(hCPU->gpr[1]+0x8);\n\n\tGX2Rect_t* rectSrc = (GX2Rect_t*)memory_getPointerFromVirtualOffset(rectSrcArrayMPTR);\n\tGX2Point_t* rectDst = (GX2Point_t*)memory_getPointerFromVirtualOffset(pointDstArrayMPTR);\n\tfor (sint32 i = 0; i < rectCount; i++)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"rect left-top: {}/{} size: {}/{}\", _swapEndianU32(rectSrc->left), _swapEndianU32(rectSrc->top), _swapEndianU32(rectSrc->right) - _swapEndianU32(rectSrc->left), _swapEndianU32(rectSrc->bottom) - _swapEndianU32(rectSrc->top));\n\t}\n\n#ifdef CEMU_DEBUG_ASSERT\n\tif( rectCount != 1 )\n\t\tassert_dbg();\n\tif( srcMip != 0 )\n\t\tassert_dbg();\n\tif( srcSlice != 0 )\n\t\tassert_dbg();\n\tif( dstMip != 0 )\n\t\tassert_dbg();\n\tif( dstSlice != 0 )\n\t\tassert_dbg();\n#endif\n\n\tfor(sint32 i=0; i<rectCount; i++)\n\t{\n\t\tuint32 srcWidth = srcSurface->width;\n\t\tuint32 srcHeight = srcSurface->height;\n\t\t// calculate rect size\n\t\tsint32 rectSrcX = (sint32)_swapEndianU32((uint32)rectSrc[i].left);\n\t\tsint32 rectSrcY = (sint32)_swapEndianU32((uint32)rectSrc[i].top);\n\t\tsint32 rectWidth = (sint32)_swapEndianU32((uint32)rectSrc[i].right) - rectSrcX;\n\t\tsint32 rectHeight = (sint32)_swapEndianU32((uint32)rectSrc[i].bottom) - rectSrcY;\n\t\tif( rectSrcX == 0 && rectSrcY == 0 && rectWidth == srcWidth && rectHeight == srcHeight )\n\t\t{\n\t\t\t// special case in which GX2CopySurfaceEx acts like GX2CopySurface()\n\t\t\tgx2Surface_GX2CopySurface(srcSurface, srcMip, srcSlice, dstSurface, dstMip, dstSlice);\n\t\t}\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2ResolveAAColorBuffer(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"GX2ResolveAAColorBuffer(0x%08x,0x%08x,%d,%d)\\n\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\tGX2ColorBuffer* srcColorBuffer = (GX2ColorBuffer*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\tGX2Surface* srcSurface = &srcColorBuffer->surface;\n\tGX2Surface* dstSurface = (GX2Surface*)memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\tuint32 srcMip = srcColorBuffer->viewMip;\n\tuint32 dstMip = hCPU->gpr[5];\n\tuint32 srcSlice = srcColorBuffer->viewFirstSlice;\n\tuint32 dstSlice = hCPU->gpr[6];\n\n#ifdef CEMU_DEBUG_ASSERT\n\tif( srcColorBuffer->viewMip != 0 || srcColorBuffer->viewFirstSlice != 0 )\n\t\tassert_dbg();\n#endif\n\n\t// allocate pixel buffer\n\tsint32 dstWidth = dstSurface->width;\n\tsint32 dstHeight = dstSurface->height;\n\tsint32 srcWidth = srcSurface->width;\n\tsint32 srcHeight = srcSurface->height;\n\n\tuint32 dstMipWidth = std::max(dstWidth>>dstMip, 1);\n\tuint32 dstMipHeight = std::max(dstHeight>>dstMip, 1);\n\tuint32 srcMipWidth = std::max(srcWidth>>srcMip, 1);\n\tuint32 srcMipHeight = std::max(srcHeight>>srcMip, 1);\n\n\t// check if surface properties match\n\tif( srcSurface->width != dstSurface->width || srcSurface->height != dstSurface->height )\n\t{\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\tif( dstMipWidth != srcMipWidth || dstMipHeight != srcMipHeight )\n\t{\n\t\tcemu_assert_suspicious();\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\t// handle format\n\tLatte::E_GX2SURFFMT srcFormat = srcSurface->format;\n\tLatte::E_GX2SURFFMT dstFormat = dstSurface->format;\n\tuint32 srcBPP = Latte::GetFormatBits(srcFormat);\n\tuint32 dstBPP = Latte::GetFormatBits(dstFormat);\n\tsint32 srcStepX = 1;\n\tsint32 srcStepY = 1;\n\tsint32 dstStepX = 1;\n\tsint32 dstStepY = 1;\n\tauto srcHwFormat = Latte::GetHWFormat(srcFormat);\n\tauto dstHwFormat = Latte::GetHWFormat(dstFormat);\n\t// get texture info\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfOutSrc = {0};\n\tGX2::GX2CalculateSurfaceInfo(srcSurface, srcMip, &surfOutSrc);\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfOutDst = {0};\n\tGX2::GX2CalculateSurfaceInfo(dstSurface, dstMip, &surfOutDst);\n\t// get input pointer\n\tuint8* inputData = NULL;\n\tcemu_assert(srcMip < srcSurface->numLevels);\n\tif( srcMip == 0 )\n\t\tinputData = (uint8*)memory_getPointerFromVirtualOffset(srcSurface->imagePtr);\n\telse if( srcMip == 1 )\n\t\tinputData = (uint8*)memory_getPointerFromVirtualOffset(srcSurface->mipPtr);\n\telse\n\t\tinputData = (uint8*)memory_getPointerFromVirtualOffset(srcSurface->mipPtr+srcSurface->mipOffset[srcMip-1]);\n\t// get output pointer\n\tuint8* outputData = NULL;\n\tcemu_assert(dstMip < dstSurface->numLevels);\n\tif( dstMip == 0 )\n\t\toutputData = (uint8*)memory_getPointerFromVirtualOffset(dstSurface->imagePtr);\n\telse if( dstMip == 1 )\n\t\toutputData = (uint8*)memory_getPointerFromVirtualOffset(dstSurface->mipPtr);\n\telse\n\t\toutputData = (uint8*)memory_getPointerFromVirtualOffset(dstSurface->mipPtr+dstSurface->mipOffset[dstMip-1]);\n\t// calculate step size for compressed textures\n\tif( Latte::IsCompressedFormat(srcHwFormat) )\n\t{\n\t\tsrcStepX = 4;\n\t\tsrcStepY = 4;\n\t}\n\tif(Latte::IsCompressedFormat(dstHwFormat) )\n\t{\n\t\tdstStepX = 4;\n\t\tdstStepY = 4;\n\t}\n\tif( srcStepX != dstStepX || srcStepY != dstStepY )\n\t\tassert_dbg();\n\n\tif( srcHwFormat != dstHwFormat )\n\t{\n\t\t// mismatching format\n\t\tdebug_printf(\"GX2CopySurface(): Format mismatch\\n\");\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\n\t// src\n\tuint32 srcPitch = surfOutSrc.pitch;\n\tuint32 srcSwizzle = srcSurface->swizzle;\n\tuint32 srcPipeSwizzle = (srcSwizzle>>8)&1;\n\tuint32 srcBankSwizzle = ((srcSwizzle>>9)&3);\n\tuint32 srcTileMode = (uint32)surfOutSrc.hwTileMode;\n\tuint32 srcDepth = std::max<uint32>(surfOutSrc.depth, 1);\n\t// dst\n\tuint32 dstPitch = surfOutDst.pitch;\n\tuint32 dstSwizzle = dstSurface->swizzle;\n\tuint32 dstPipeSwizzle = (dstSwizzle>>8)&1;\n\tuint32 dstBankSwizzle = ((dstSwizzle>>9)&3);\n\tuint32 dstTileMode = (uint32)surfOutDst.hwTileMode;\n\tuint32 dstDepth = std::max<uint32>(surfOutDst.depth, 1);\n\n\t// send copy command to GPU\n\tGX2::GX2ReserveCmdSpace(1 + 13 * 2);\n\tgx2WriteGather_submit(pm4HeaderType3(IT_HLE_COPY_SURFACE_NEW, 13 * 2),\n\t\t// src\n\t\t(uint32)srcSurface->imagePtr,\n\t\t(uint32)srcSurface->mipPtr,\n\t\t(uint32)srcSurface->swizzle,\n\t\t(uint32)srcSurface->format.value(),\n\t\t(uint32)srcSurface->width,\n\t\t(uint32)srcSurface->height,\n\t\t(uint32)srcSurface->depth,\n\t\t(uint32)srcSurface->pitch,\n\t\tsrcSlice,\n\t\t(uint32)srcSurface->dim.value(),\n\t\t(uint32)srcSurface->tileMode.value(),\n\t\t(uint32)srcSurface->aa,\n\t\tsrcMip,\n\t\t// dst\n\t\t(uint32)dstSurface->imagePtr,\n\t\t(uint32)dstSurface->mipPtr,\n\t\t(uint32)dstSurface->swizzle,\n\t\t(uint32)dstSurface->format.value(),\n\t\t(uint32)dstSurface->width,\n\t\t(uint32)dstSurface->height,\n\t\t(uint32)dstSurface->depth,\n\t\t(uint32)dstSurface->pitch,\n\t\tdstSlice,\n\t\t(uint32)dstSurface->dim.value(),\n\t\t(uint32)dstSurface->tileMode.value(),\n\t\t(uint32)dstSurface->aa,\n\t\tdstMip);\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2ConvertDepthBufferToTextureSurface(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2ConvertDepthBufferToTextureSurface(0x{:x}, 0x{:x}, {}, {})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\tGX2DepthBuffer* depthBuffer = (GX2DepthBuffer*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\tGX2Surface* dstSurface = (GX2Surface*)memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\tuint32 dstMip = hCPU->gpr[5];\n\tuint32 dstSlice = hCPU->gpr[6];\n\n\tif (dstMip != 0 || dstSlice != 0)\n\t\tdebugBreakpoint();\n\t// get texture info\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfOutSrc = { 0 };\n\tGX2::GX2CalculateSurfaceInfo(&depthBuffer->surface, 0, &surfOutSrc);\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfOutDst = { 0 };\n\tGX2::GX2CalculateSurfaceInfo(dstSurface, 0, &surfOutDst);\n\n\tif (depthBuffer->surface.imagePtr == dstSurface->imagePtr)\n\t{\n\t\t// in-place re-tiling doesn't need any actual copy operation?\n\t\tif (dstMip != 0 || dstSlice != 0)\n\t\t\tdebugBreakpoint();\n\t\tdebug_printf(\"In-place re-tiling\\n\");\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\n\t// note: Do not trust values from the input GX2Surface* structs but rely on surfOutDst/surfOutSrc instead if possible.\n\t// src\n\tuint32 srcPitch = surfOutSrc.pitch;\n\tuint32 srcSwizzle = depthBuffer->surface.swizzle;\n\tuint32 srcPipeSwizzle = (srcSwizzle >> 8) & 1;\n\tuint32 srcBankSwizzle = ((srcSwizzle >> 9) & 3);\n\tuint32 srcTileMode = (uint32)surfOutSrc.hwTileMode;\n\tuint32 srcDepth = std::max<uint32>(surfOutSrc.depth, 1);\n\t// dst\n\tuint32 dstPitch = surfOutDst.pitch;\n\tuint32 dstSwizzle = dstSurface->swizzle;\n\tuint32 dstPipeSwizzle = (dstSwizzle >> 8) & 1;\n\tuint32 dstBankSwizzle = ((dstSwizzle >> 9) & 3);\n\tuint32 dstTileMode = (uint32)surfOutDst.hwTileMode;\n\tuint32 dstDepth = srcDepth;\n\n\tsint32 srcMip = 0;\n\n\tuint32 numSlices = std::max<uint32>(depthBuffer->viewNumSlices, 1);\n\tGX2::GX2ReserveCmdSpace((1 + 13 * 2) * numSlices);\n\tfor (uint32 subSliceIndex = 0; subSliceIndex < numSlices; subSliceIndex++)\n\t{\n\t\t// send copy command to GPU\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_HLE_COPY_SURFACE_NEW, 13 * 2),\n\t\t\t// src\n\t\t\t(uint32)(depthBuffer->surface.imagePtr),\n\t\t\t(uint32)(depthBuffer->surface.mipPtr),\n\t\t\t(uint32)(depthBuffer->surface.swizzle),\n\t\t\t(uint32)(depthBuffer->surface.format.value()),\n\t\t\t(uint32)(depthBuffer->surface.width),\n\t\t\t(uint32)(depthBuffer->surface.height),\n\t\t\t(uint32)(depthBuffer->surface.depth),\n\t\t\t(uint32)(depthBuffer->surface.pitch),\n\t\t\t(uint32)(depthBuffer->viewFirstSlice) + subSliceIndex,\n\t\t\t(uint32)(depthBuffer->surface.dim.value()),\n\t\t\t(uint32)(depthBuffer->surface.tileMode.value()),\n\t\t\t(uint32)(depthBuffer->surface.aa),\n\t\t\tsrcMip,\n\t\t\t// dst\n\t\t\t(uint32)(dstSurface->imagePtr),\n\t\t\t(uint32)(dstSurface->mipPtr),\n\t\t\t(uint32)(dstSurface->swizzle),\n\t\t\t(uint32)(dstSurface->format.value()),\n\t\t\t(uint32)(dstSurface->width),\n\t\t\t(uint32)(dstSurface->height),\n\t\t\t(uint32)(dstSurface->depth),\n\t\t\t(uint32)(dstSurface->pitch),\n\t\t\tdstSlice + subSliceIndex,\n\t\t\t(uint32)(dstSurface->dim.value()),\n\t\t\t(uint32)(dstSurface->tileMode.value()),\n\t\t\t(uint32)(dstSurface->aa),\n\t\t\tdstMip);\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nnamespace GX2\n{\n\tvoid GX2SurfaceCopyInit()\n\t{\n\t\tosLib_addFunction(\"gx2\", \"GX2CopySurface\", gx2Export_GX2CopySurface);\n\t\tosLib_addFunction(\"gx2\", \"GX2CopySurfaceEx\", gx2Export_GX2CopySurfaceEx);\n\t\tosLib_addFunction(\"gx2\", \"GX2ResolveAAColorBuffer\", gx2Export_GX2ResolveAAColorBuffer);\n\t\tosLib_addFunction(\"gx2\", \"GX2ConvertDepthBufferToTextureSurface\", gx2Export_GX2ConvertDepthBufferToTextureSurface);\n\t}\n};\n\nvoid gx2CopySurfaceTest()\n{\n\n\treturn;\n\n\tBenchmarkTimer bt;\n\n\t// copy 0\n\tbt.Start();\n\tfor(sint32 i=0; i<100; i++)\n\t\tgx2SurfaceCopySoftware(\n\t\t\tmemory_base + 0x10000000, 256, 256, 1, 0, 0, 4,\n\t\t\tmemory_base + 0x20000000, 256, 256, 1, 0, 0, 4,\n\t\t\t64, 64, 32\n\t\t);\n\tbt.Stop();\n\tdebug_printf(\"Copy 0 - %lfms\\n\", bt.GetElapsedMilliseconds());\n\t// copy 1\n\tbt.Start();\n\tfor (sint32 i = 0; i < 100; i++)\n\t\tgx2SurfaceCopySoftware(\n\t\t\tmemory_base + 0x11000000, 256, 256, 1, 0, 0, 4,\n\t\t\tmemory_base + 0x21000000, 256, 256, 1, 0, 0, 2,\n\t\t\t64, 64, 32\n\t\t);\n\tbt.Stop();\n\tdebug_printf(\"Copy 1 - %lfms\\n\", bt.GetElapsedMilliseconds());\n\t// copy 2\n\tbt.Start();\n\tfor (sint32 i = 0; i < 100; i++)\n\t\tgx2SurfaceCopySoftware(\n\t\t\tmemory_base + 0x12000000, 256, 256, 1, 0, 0, 1,\n\t\t\tmemory_base + 0x22000000, 256, 256, 1, 0, 0, 4,\n\t\t\t64, 64, 128\n\t\t);\n\tbt.Stop();\n\tdebug_printf(\"Copy 2 - %lfms\\n\", bt.GetElapsedMilliseconds());\n\t// copy 3\n\tbt.Start();\n\tfor (sint32 i = 0; i < 100; i++)\n\t\tgx2SurfaceCopySoftware(\n\t\t\tmemory_base + 0x12000000, 256, 256, 1, 0, 0, 4,\n\t\t\tmemory_base + 0x22000000, 256, 256, 1, 0, 0, 4,\n\t\t\t64, 512, 32\n\t\t);\n\tbt.Stop();\n\tdebug_printf(\"Copy 3 - %lfms\\n\", bt.GetElapsedMilliseconds());\n\n\tcemu_assert_debug(false);\n\n\t// with bpp switch optimized away:\n\t// Copy 0 - 19.777100ms\n\t// Copy 1 - 14.311300ms\n\t// Copy 2 - 10.837700ms\n\t// Copy 3 - 158.174400ms\n\n\t// Copy 0 - 19.846800ms\n\t// Copy 1 - 14.054000ms\n\t// Copy 2 - 11.013500ms\n\t// Copy 3 - 159.916000ms\n\n\t// with fast path added:\n\t// Copy 0 - 0.222400ms\n\t// Copy 1 - 14.125700ms\n\t// Copy 2 - 13.298100ms\n\t// Copy 3 - 1.764500ms\n\n\t// with shared offset:\n\t// Copy 0 - 0.143300ms\n\t// Copy 1 - 13.814200ms\n\t// Copy 2 - 10.309500ms\n\t// Copy 3 - 1.191900ms\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Surface_Copy.h",
    "content": "#pragma once\n\nnamespace GX2\n{\n\tvoid GX2SurfaceCopyInit();\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Texture.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"GX2.h\"\n#include \"GX2_Texture.h\"\n\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n\nnamespace GX2\n{\n\tusing namespace Latte;\n\n\t/****** Texture functions ******/\n\n\tvoid GX2InitTextureRegs(GX2Texture* texture)\n\t{\n\t\tuint32 _regs[5] = { 0 };\n\n\t\t// some values may not be zero\n\t\tif (texture->viewNumMips == 0)\n\t\t\ttexture->viewNumMips = 1;\n\t\tif (texture->viewNumSlices == 0)\n\t\t\ttexture->viewNumSlices = 1;\n\n\t\tif (texture->surface.height == 0)\n\t\t\ttexture->surface.height = 1;\n\t\tif (texture->surface.depth == 0)\n\t\t\ttexture->surface.depth = 1;\n\t\tif (texture->surface.numLevels == 0)\n\t\t\ttexture->surface.numLevels = 1;\n\n\t\t// texture parameters\n\t\tuint32 viewNumMips = texture->viewNumMips;\n\t\tuint32 viewNumSlices = texture->viewNumSlices;\n\t\tuint32 viewFirstMip = texture->viewFirstMip;\n\t\tuint32 viewFirstSlice = texture->viewFirstSlice;\n\t\tuint32 compSel = texture->compSel;\n\n\t\t// surface parameters\n\t\tuint32 width = texture->surface.width;\n\t\tuint32 height = texture->surface.height;\n\t\tuint32 depth = texture->surface.depth;\n\t\tuint32 pitch = texture->surface.pitch;\n\t\tuint32 numMips = texture->surface.numLevels;\n\t\tLatte::E_GX2SURFFMT format = texture->surface.format;\n\t\tLatte::E_DIM dim = texture->surface.dim;\n\t\tuint32 tileMode = (uint32)texture->surface.tileMode.value();\n\t\tuint32 surfaceFlags = texture->surface.resFlag;\n\t\tuint32 surfaceAA = texture->surface.aa;\n\n\t\t// calculate register word 0\n\t\tLatte::E_HWSURFFMT formatHw = Latte::GetHWFormat(format);\n\n\t\tLatte::LATTE_SQ_TEX_RESOURCE_WORD0_N newRegWord0;\n\t\tnewRegWord0.set_DIM(dim);\n\t\tnewRegWord0.set_TILE_MODE(Latte::MakeHWTileMode(texture->surface.tileMode));\n\t\tnewRegWord0.set_TILE_TYPE((surfaceFlags&4) != 0);\n\n\t\tuint32 pixelPitch = pitch;\n\t\tif (Latte::IsCompressedFormat(formatHw))\n\t\t\tpixelPitch *= 4;\n\n\t\tif(pixelPitch == 0)\n\t\t\tnewRegWord0.set_PITCH(0x7FF);\n\t\telse\n\t\t\tnewRegWord0.set_PITCH((pixelPitch >> 3) - 1);\n\n\t\tif (width == 0)\n\t\t\tnewRegWord0.set_WIDTH(0x1FFF);\n\t\telse\n\t\t\tnewRegWord0.set_WIDTH(width - 1);\n\n\t\ttexture->regTexWord0 = newRegWord0;\n\n\t\t// calculate register word 1\n\t\tLatte::LATTE_SQ_TEX_RESOURCE_WORD1_N newRegWord1;\n\t\tnewRegWord1.set_HEIGHT(height - 1);\n\n\t\tif (dim == Latte::E_DIM::DIM_CUBEMAP)\n\t\t{\n\t\t\tnewRegWord1.set_DEPTH((depth / 6) - 1);\n\t\t}\n\t\telse if (dim == E_DIM::DIM_3D ||\n\t\t\tdim == E_DIM::DIM_2D_ARRAY_MSAA ||\n\t\t\tdim == E_DIM::DIM_2D_ARRAY ||\n\t\t\tdim == E_DIM::DIM_1D_ARRAY)\n\t\t{\n\t\t\tnewRegWord1.set_DEPTH(depth - 1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnewRegWord1.set_DEPTH(0);\n\t\t}\n\t\tnewRegWord1.set_DATA_FORMAT(formatHw);\n\t\ttexture->regTexWord1 = newRegWord1;\n\n\t\t// calculate register word 2\n\t\tLATTE_SQ_TEX_RESOURCE_WORD4_N newRegWord4;\n\n\t\tLATTE_SQ_TEX_RESOURCE_WORD4_N::E_FORMAT_COMP formatComp;\n\t\tif (HAS_FLAG(format, Latte::E_GX2SURFFMT::FMT_BIT_SIGNED))\n\t\t\tformatComp = LATTE_SQ_TEX_RESOURCE_WORD4_N::E_FORMAT_COMP::COMP_SIGNED;\n\t\telse\n\t\t\tformatComp = LATTE_SQ_TEX_RESOURCE_WORD4_N::E_FORMAT_COMP::COMP_UNSIGNED;\n\t\tnewRegWord4.set_FORMAT_COMP_X(formatComp);\n\t\tnewRegWord4.set_FORMAT_COMP_Y(formatComp);\n\t\tnewRegWord4.set_FORMAT_COMP_Z(formatComp);\n\t\tnewRegWord4.set_FORMAT_COMP_W(formatComp);\n\n\t\tif (HAS_FLAG(format, Latte::E_GX2SURFFMT::FMT_BIT_FLOAT))\n\t\t\tnewRegWord4.set_NUM_FORM_ALL(LATTE_SQ_TEX_RESOURCE_WORD4_N::E_NUM_FORMAT_ALL::NUM_FORMAT_SCALED);\n\t\telse if (HAS_FLAG(format, Latte::E_GX2SURFFMT::FMT_BIT_INT))\n\t\t\tnewRegWord4.set_NUM_FORM_ALL(LATTE_SQ_TEX_RESOURCE_WORD4_N::E_NUM_FORMAT_ALL::NUM_FORMAT_INT);\n\t\telse\n\t\t\tnewRegWord4.set_NUM_FORM_ALL(LATTE_SQ_TEX_RESOURCE_WORD4_N::E_NUM_FORMAT_ALL::NUM_FORMAT_NORM);\n\n\t\tif (HAS_FLAG(format, Latte::E_GX2SURFFMT::FMT_BIT_SRGB))\n\t\t\tnewRegWord4.set_FORCE_DEGAMMA(true);\n\n\t\tnewRegWord4.set_ENDIAN_SWAP(GX2::GetSurfaceFormatSwapMode((Latte::E_GX2SURFFMT)format));\n\n\t\tnewRegWord4.set_REQUEST_SIZE(2);\n\n\t\tnewRegWord4.set_DST_SEL_X((Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N::E_SEL)((compSel >> 24) & 0x7));\n\t\tnewRegWord4.set_DST_SEL_Y((Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N::E_SEL)((compSel >> 16) & 0x7));\n\t\tnewRegWord4.set_DST_SEL_Z((Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N::E_SEL)((compSel >> 8) & 0x7));\n\t\tnewRegWord4.set_DST_SEL_W((Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N::E_SEL)((compSel >> 0) & 0x7));\n\n\t\tnewRegWord4.set_BASE_LEVEL(viewFirstMip);\n\t\ttexture->regTexWord4 = newRegWord4;\n\n\t\t// calculate register word 3\n\t\tLATTE_SQ_TEX_RESOURCE_WORD5_N newRegWord5;\n\t\tnewRegWord5.set_LAST_LEVEL(viewFirstMip + viewNumMips - 1);\n\t\tnewRegWord5.set_BASE_ARRAY(viewFirstSlice);\n\t\tnewRegWord5.set_LAST_ARRAY(viewFirstSlice + viewNumSlices - 1);\n\t\tif (dim == Latte::E_DIM::DIM_CUBEMAP && ((depth / 6) - 1) != 0)\n\t\t\tnewRegWord5.set_UKN_BIT_30(true);\n\t\tif(surfaceAA >= 1 && surfaceAA <= 3)\n\t\t\tnewRegWord5.set_LAST_LEVEL(surfaceAA);\n\t\ttexture->regTexWord5 = newRegWord5;\n\t\t// calculate register word 4\n\t\tLATTE_SQ_TEX_RESOURCE_WORD6_N newRegWord6;\n\t\tnewRegWord6.set_MAX_ANISO(4);\n\t\tnewRegWord6.set_PERF_MODULATION(7);\n\t\tnewRegWord6.set_TYPE(Latte::LATTE_SQ_TEX_RESOURCE_WORD6_N::E_TYPE::VTX_VALID_TEXTURE);\n\t\ttexture->regTexWord6 = newRegWord6;\n\t}\n\n\tvoid _GX2SetTexture(GX2Texture* tex, Latte::REGADDR baseRegister, uint32 textureUnitIndex)\n\t{\n\t\tGX2ReserveCmdSpace(2 + 7);\n\n\t\tMPTR imagePtr = tex->surface.imagePtr;\n\t\tMPTR mipPtr = tex->surface.mipPtr;\n\t\tif (mipPtr == MPTR_NULL)\n\t\t\tmipPtr = imagePtr;\n\n\t\tuint32 swizzle = tex->surface.swizzle;\n\n\t\tcemu_assert_debug((swizzle & 0xFF) == 0); // does the low byte in swizzle field have any meaning?\n\n\t\tif (Latte::TM_IsMacroTiled(tex->surface.tileMode))\n\t\t{\n\t\t\tuint32 swizzleStopLevel = (swizzle >> 16) & 0xFF;\n\t\t\t// combine swizzle with image ptr if base level is macro tiled\n\t\t\tif (swizzleStopLevel > 0)\n\t\t\t\timagePtr ^= (swizzle & 0xFFFF);\n\t\t\t// combine swizzle with mip ptr if first mip (level 1) is macro tiled\n\t\t\tif (swizzleStopLevel > 1)\n\t\t\t\tmipPtr ^= (swizzle & 0xFFFF);\n\t\t}\n\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_RESOURCE, 8),\n\t\t\tbaseRegister + textureUnitIndex * 7 - mmSQ_TEX_RESOURCE_WORD0,\n\t\t\ttex->regTexWord0,\n\t\t\ttex->regTexWord1,\n\t\t\tmemory_virtualToPhysical(imagePtr) >> 8,\n\t\t\tmemory_virtualToPhysical(mipPtr) >> 8,\n\t\t\ttex->regTexWord4,\n\t\t\ttex->regTexWord5,\n\t\t\ttex->regTexWord6);\n\t}\n\n\tvoid GX2SetPixelTexture(GX2Texture* tex, uint32 texUnit)\n\t{\n\t\tcemu_assert_debug(texUnit < Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE);\n\t\t_GX2SetTexture(tex, Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_PS, texUnit);\n\t}\n\n\tvoid GX2SetVertexTexture(GX2Texture* tex, uint32 texUnit)\n\t{\n\t\tcemu_assert_debug(texUnit < Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE);\n\t\t_GX2SetTexture(tex, Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_VS, texUnit);\n\t}\n\n\tvoid GX2SetGeometryTexture(GX2Texture* tex, uint32 texUnit)\n\t{\n\t\tcemu_assert_debug(texUnit < Latte::GPU_LIMITS::NUM_TEXTURES_PER_STAGE);\n\t\t_GX2SetTexture(tex, Latte::REGADDR::SQ_TEX_RESOURCE_WORD0_N_GS, texUnit);\n\t}\n\n\tvoid GX2SetComputeTexture(GX2Texture* tex, uint32 texUnit)\n\t{\n\t\tGX2SetVertexTexture(tex, texUnit);\n\t}\n\n\t/****** Sampler functions ******/\n\n\tvoid GX2InitSampler(GX2Sampler* sampler, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_CLAMP clampXYZ, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER filterMinMag)\n\t{\n\t\tLATTE_SQ_TEX_SAMPLER_WORD0_0 word0{};\n\t\tword0.set_CLAMP_X(clampXYZ).set_CLAMP_Y(clampXYZ).set_CLAMP_Z(clampXYZ);\n\t\tword0.set_XY_MAG_FILTER(filterMinMag).set_XY_MIN_FILTER(filterMinMag);\n\t\tword0.set_Z_FILTER(LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::POINT);\n\t\tword0.set_MIP_FILTER(LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::POINT);\n\t\tword0.set_TEX_ARRAY_OVERRIDE(true);\n\n\t\tLATTE_SQ_TEX_SAMPLER_WORD1_0 word1{};\n\t\tword1.set_MAX_LOD(0x3FF);\n\n\t\tLATTE_SQ_TEX_SAMPLER_WORD2_0 word2{};\n\t\tword2.set_TYPE(LATTE_SQ_TEX_SAMPLER_WORD2_0::E_SAMPLER_TYPE::UKN1);\n\n\t\tsampler->word0 = word0;\n\t\tsampler->word1 = word1;\n\t\tsampler->word2 = word2;\n\t}\n\n\tvoid GX2InitSamplerXYFilter(GX2Sampler* sampler, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER magFilter, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER minFilter, uint32 maxAnisoRatio)\n\t{\n\t\tLATTE_SQ_TEX_SAMPLER_WORD0_0 word0 = sampler->word0;\n\t\tif (maxAnisoRatio == 0)\n\t\t{\n\t\t\tword0.set_XY_MAG_FILTER(magFilter);\n\t\t\tword0.set_XY_MIN_FILTER(minFilter);\n\t\t\tword0.set_MAX_ANISO_RATIO(0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto getAnisoFilter = [](LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER filter) -> LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER\n\t\t\t{\n\t\t\t\tif (filter == LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::POINT)\n\t\t\t\t\treturn LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::ANISO_POINT;\n\t\t\t\telse if (filter == LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::BILINEAR)\n\t\t\t\t\treturn LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::ANISO_BILINEAR;\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\treturn LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::POINT;\n\t\t\t};\n\t\t\tword0.set_XY_MAG_FILTER(getAnisoFilter(magFilter));\n\t\t\tword0.set_XY_MIN_FILTER(getAnisoFilter(minFilter));\n\t\t\tword0.set_MAX_ANISO_RATIO(maxAnisoRatio);\n\t\t}\n\t\tsampler->word0 = word0;\n\t}\n\n\tvoid GX2InitSamplerZMFilter(GX2Sampler* sampler, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER zFilter, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER mipFilter)\n\t{\n\t\tLATTE_SQ_TEX_SAMPLER_WORD0_0 word0 = sampler->word0;\n\t\tword0.set_Z_FILTER(zFilter);\n\t\tword0.set_MIP_FILTER(mipFilter);\n\t\tsampler->word0 = word0;\n\t}\n\n\tvoid GX2InitSamplerLOD(GX2Sampler* sampler, float minLod, float maxLod, float lodBias)\n\t{\n\t\t// known special cases: Mario & Sonic Rio passes minimum and maximum float values for minLod/maxLod\n\t\tif (minLod < 0.0)\n\t\t\tminLod = 0.0;\n\t\tif (maxLod > 16.0)\n\t\t\tmaxLod = 16.0;\n\n\t\tuint32 iMinLod = ((uint32)floorf(minLod * 64.0f));\n\t\tuint32 iMaxLod = ((uint32)floorf(maxLod * 64.0f));\n\t\tsint32 iLodBias = (sint32)((sint32)floorf(lodBias * 64.0f)); // input range: -32.0 to 32.0\n\t\tiMinLod = std::clamp(iMinLod, 0u, 1023u);\n\t\tiMaxLod = std::clamp(iMaxLod, 0u, 1023u);\n\t\tiLodBias = std::clamp(iLodBias, -2048, 2047);\n\n\t\tLATTE_SQ_TEX_SAMPLER_WORD1_0 word1 = sampler->word1;\n\t\tword1.set_MIN_LOD(iMinLod);\n\t\tword1.set_MAX_LOD(iMaxLod);\n\t\tword1.set_LOD_BIAS(iLodBias);\n\n\t\tsampler->word1 = word1;\n\t}\n\n\tvoid GX2InitSamplerClamping(GX2Sampler* sampler, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_CLAMP clampX, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_CLAMP clampY, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_CLAMP clampZ)\n\t{\n\t\tLATTE_SQ_TEX_SAMPLER_WORD0_0 word0 = sampler->word0;\n\t\tword0.set_CLAMP_X(clampX);\n\t\tword0.set_CLAMP_Y(clampY);\n\t\tword0.set_CLAMP_Z(clampZ);\n\t\tsampler->word0 = word0;\n\t}\n\n\tvoid GX2InitSamplerBorderType(GX2Sampler* sampler, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE borderColorType)\n\t{\n\t\tLATTE_SQ_TEX_SAMPLER_WORD0_0 word0 = sampler->word0;\n\t\tword0.set_BORDER_COLOR_TYPE(borderColorType);\n\t\tsampler->word0 = word0;\n\t}\n\n\tvoid GX2InitSamplerDepthCompare(GX2Sampler* sampler, LATTE_SQ_TEX_SAMPLER_WORD0_0::E_DEPTH_COMPARE depthCompareFunction)\n\t{\n\t\tLATTE_SQ_TEX_SAMPLER_WORD0_0 word0 = sampler->word0;\n\t\tword0.set_DEPTH_COMPARE_FUNCTION(depthCompareFunction);\n\t\tsampler->word0 = word0;\n\t}\n\n\tvoid _GX2SetSampler(GX2Sampler* sampler, uint32 samplerIndex)\n\t{\n\t\tGX2ReserveCmdSpace(5);\n\t\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_SAMPLER, 1 + 3),\n\t\t\tsamplerIndex * 3,\n\t\t\tsampler->word0, sampler->word1, sampler->word2);\n\t}\n\n\tvoid GX2SetPixelSampler(GX2Sampler* sampler, uint32 samplerIndex)\n\t{\n\t\t_GX2SetSampler(sampler, samplerIndex + SAMPLER_BASE_INDEX_PIXEL);\n\t}\n\n\tvoid GX2SetVertexSampler(GX2Sampler* sampler, uint32 vertexSamplerIndex)\n\t{\n\t\t_GX2SetSampler(sampler, vertexSamplerIndex + SAMPLER_BASE_INDEX_VERTEX);\n\t}\n\n\tvoid GX2SetGeometrySampler(GX2Sampler* sampler, uint32 geometrySamplerIndex)\n\t{\n\t\t_GX2SetSampler(sampler, geometrySamplerIndex + SAMPLER_BASE_INDEX_GEOMETRY);\n\t}\n\n\tvoid GX2SetComputeSampler(GX2Sampler* sampler, uint32 computeSamplerIndex)\n\t{\n\t\t_GX2SetSampler(sampler, computeSamplerIndex + SAMPLER_BASE_INDEX_VERTEX); // uses vertex shader stage\n\t}\n\n\tvoid GX2SetSamplerBorderColor(uint32 registerBaseOffset, uint32 samplerIndex, float red, float green, float blue, float alpha)\n\t{\n\t\tGX2ReserveCmdSpace(6);\n\t\tgx2WriteGather_submit(\n\t\t\tpm4HeaderType3(IT_SET_CONFIG_REG, 1 + 4),\n\t\t\tregisterBaseOffset + samplerIndex * 4 - LATTE_REG_BASE_CONFIG,\n\t\t\tred, green, blue, alpha);\n\t}\n\n\tvoid GX2SetPixelSamplerBorderColor(uint32 pixelSamplerIndex, float red, float green, float blue, float alpha)\n\t{\n\t\tGX2SetSamplerBorderColor(REGADDR::TD_PS_SAMPLER0_BORDER_RED, pixelSamplerIndex, red, green, blue, alpha);\n\t}\n\n\tvoid GX2SetVertexSamplerBorderColor(uint32 vertexSamplerIndex, float red, float green, float blue, float alpha)\n\t{\n\t\tGX2SetSamplerBorderColor(REGADDR::TD_VS_SAMPLER0_BORDER_RED, vertexSamplerIndex, red, green, blue, alpha);\n\t}\n\n\tvoid GX2SetGeometrySamplerBorderColor(uint32 geometrySamplerIndex, float red, float green, float blue, float alpha)\n\t{\n\t\tGX2SetSamplerBorderColor(REGADDR::TD_GS_SAMPLER0_BORDER_RED, geometrySamplerIndex, red, green, blue, alpha);\n\t}\n\n\tvoid GX2TextureInit()\n\t{\n\t\t// texture\n\t\tcafeExportRegister(\"gx2\", GX2InitTextureRegs, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPixelTexture, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetVertexTexture, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetGeometryTexture, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetComputeTexture, LogType::GX2);\n\n\t\t// sampler\n\t\tcafeExportRegister(\"gx2\", GX2InitSampler, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2InitSamplerXYFilter, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2InitSamplerZMFilter, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2InitSamplerLOD, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2InitSamplerClamping, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2InitSamplerBorderType, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2InitSamplerDepthCompare, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPixelSampler, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetVertexSampler, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetGeometrySampler, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetComputeSampler, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetPixelSamplerBorderColor, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetVertexSamplerBorderColor, LogType::GX2);\n\t\tcafeExportRegister(\"gx2\", GX2SetGeometrySamplerBorderColor, LogType::GX2);\n\t}\n\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_Texture.h",
    "content": "#pragma once\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"GX2_Surface.h\"\n\nnamespace GX2\n{\n\tstruct GX2Texture\n\t{\n\t\t/* +0x00 */ GX2Surface surface;\n\t\t/* +0x74 */ uint32be viewFirstMip;\n\t\t/* +0x78 */ uint32be viewNumMips;\n\t\t/* +0x7C */ uint32be viewFirstSlice;\n\t\t/* +0x80 */ uint32be viewNumSlices;\n\t\t/* +0x84 */ uint32be compSel;\n\t\t/* +0x88 */ betype<Latte::LATTE_SQ_TEX_RESOURCE_WORD0_N> regTexWord0;\n\t\t/* +0x8C */ betype<Latte::LATTE_SQ_TEX_RESOURCE_WORD1_N> regTexWord1;\n\t\t// word2 and word3 are the base/mip address and are not stored\n\t\t/* +0x90 */ betype<Latte::LATTE_SQ_TEX_RESOURCE_WORD4_N> regTexWord4;\n\t\t/* +0x94 */ betype<Latte::LATTE_SQ_TEX_RESOURCE_WORD5_N> regTexWord5;\n\t\t/* +0x98 */ betype<Latte::LATTE_SQ_TEX_RESOURCE_WORD6_N> regTexWord6;\n\t};\n\n\tstatic_assert(sizeof(GX2Texture) == 0x9C);\n\n\tstruct GX2Sampler\n\t{\n\t\tbetype<Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0> word0;\n\t\tbetype<Latte::LATTE_SQ_TEX_SAMPLER_WORD1_0> word1;\n\t\tbetype<Latte::LATTE_SQ_TEX_SAMPLER_WORD2_0> word2;\n\t};\n\n\tstatic_assert(sizeof(GX2Sampler) == 12);\n\n\tvoid GX2InitTextureRegs(GX2Texture* texture);\n\n\tvoid GX2TextureInit();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_TilingAperture.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"GX2.h\"\n#include \"Cafe/HW/Latte/LatteAddrLib/LatteAddrLib.h\"\n#include \"Cafe/HW/Latte/Core/LatteTextureLoader.h\"\n\n#define GX2_MAX_ACTIVE_TILING_APERATURES\t(32)\n\nstruct ActiveTilingAperature\n{\n\tuint32 addr;\n\tuint32 size;\n\tuint32 handle;\n\tuint32 endianMode;\n\t// surface info\n\tGX2Surface surface;\n\tuint32 sliceIndex;\n\tuint32 mipLevel;\n};\n\nActiveTilingAperature activeTilingAperature[GX2_MAX_ACTIVE_TILING_APERATURES];\nsint32 activeTilingAperatureCount = 0;\n\nMPTR GX2TilingAperature_allocateTilingMemory(uint32 size)\n{\n\tuint32 currentOffset = 0;\n\twhile( true )\n\t{\n\t\t// align offset\n\t\tcurrentOffset = (currentOffset+0xFFF)&~0xFFF;\n\t\t// check if out of range\n\t\tif( (currentOffset+size) >= MEMORY_TILINGAPERTURE_AREA_SIZE )\n\t\t\tbreak;\n\t\t// check if range intersects with any already allocated range\n\t\tbool isAvailable = true;\n\t\tuint32 nextOffset = 0xFFFFFFFF;\n\t\tfor(sint32 i=0; i<activeTilingAperatureCount; i++)\n\t\t{\n\t\t\tuint32 startA = currentOffset;\n\t\t\tuint32 endA = startA+size;\n\t\t\tuint32 startB = activeTilingAperature[i].addr - MEMORY_TILINGAPERTURE_AREA_ADDR;\n\t\t\tuint32 endB = startB+activeTilingAperature[i].size;\n\t\t\tif( startA < endB && endA >= startB )\n\t\t\t{\n\t\t\t\tisAvailable = false;\n\t\t\t\tnextOffset = std::min(nextOffset, endB);\n\t\t\t}\n\t\t}\n\t\tif( isAvailable )\n\t\t\treturn currentOffset + MEMORY_TILINGAPERTURE_AREA_ADDR;\n\t\tcurrentOffset = nextOffset;\n\t}\n\treturn MPTR_NULL;\n}\n\nstd::atomic<uint32> sGenAperatureHandle{1};\n\nuint32 GX2TilingAperature_GenerateHandle()\n{\n\treturn sGenAperatureHandle.fetch_add(1);\n}\n\ntemplate<typename copyType, int count, bool isWrite>\nvoid copyValue(uint8* outputBlockData, uint8* inputBlockData)\n{\n\tif (isWrite)\n\t{\n\t\t*(copyType*)outputBlockData = *(copyType*)inputBlockData;\n\t\tif (count >= 2)\n\t\t\t((copyType*)outputBlockData)[1] = ((copyType*)inputBlockData)[1];\n\t\tif (count >= 3)\n\t\t\t((copyType*)outputBlockData)[2] = ((copyType*)inputBlockData)[2];\n\t\tif (count >= 4)\n\t\t\t((copyType*)outputBlockData)[3] = ((copyType*)inputBlockData)[3];\n\t}\n\telse\n\t{\n\t\t*(copyType*)inputBlockData = *(copyType*)outputBlockData;\n\t\tif (count >= 2)\n\t\t\t((copyType*)inputBlockData)[1] = ((copyType*)outputBlockData)[1];\n\t\tif (count >= 3)\n\t\t\t((copyType*)inputBlockData)[2] = ((copyType*)outputBlockData)[2];\n\t\tif (count >= 4)\n\t\t\t((copyType*)inputBlockData)[3] = ((copyType*)outputBlockData)[3];\n\t}\n}\n\ntemplate<int bpp, bool isWrite, int surfaceTileMode>\nvoid retileTexture(ActiveTilingAperature* tilingAperture, uint8* inputData, uint8* outputData, sint32 texelWidth, sint32 texelHeight, sint32 surfaceSlice, sint32 surfacePitch, sint32 surfaceHeight, sint32 surfaceDepth, LatteAddrLib::CachedSurfaceAddrInfo* cachedInfo)\n{\n\tfor (sint32 y = 0; y < texelHeight; y++)\n\t{\n\t\tuint32 srcOffset;\n\t\tuint8* inputBlockData;\n\t\tif (bpp != 8)\n\t\t{\n\t\t\tsrcOffset = (0 + y*surfacePitch)*(bpp / 8);\n\t\t\tinputBlockData = inputData + srcOffset;\n\t\t}\n\t\tfor (sint32 x = 0; x < texelWidth; x++)\n\t\t{\n\t\t\t// calculate address of input block\n\t\t\tsint32 texelX = x;\n\t\t\tsint32 texelY = y;\n\t\t\tif (bpp == 8)\n\t\t\t{\n\t\t\t\ttexelX ^= 8;\n\t\t\t\ttexelY ^= 2;\n\t\t\t\tsrcOffset = (texelX + texelY*surfacePitch)*(bpp / 8);\n\t\t\t\tinputBlockData = inputData + srcOffset;\n\t\t\t}\n\t\t\t// calculate address of output block\n\t\t\tuint32 dstBitPos = 0;\n\t\t\tuint32 dstOffset = 0;\n\t\t\tif (surfaceTileMode == 4)\n\t\t\t\tdstOffset = ComputeSurfaceAddrFromCoordMacroTiledCached_tm04_sample1(x, y, cachedInfo);\n\t\t\telse if (surfaceTileMode == 2 || surfaceTileMode == 3)\n\t\t\t{\n\t\t\t\tdstOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMicroTiled(x, y, cachedInfo->slice, cachedInfo->bpp, cachedInfo->pitch, cachedInfo->height, (Latte::E_HWTILEMODE)cachedInfo->tileMode, false);\n\t\t\t}\n\t\t\telse if (surfaceTileMode == 1 || surfaceTileMode == 0)\n\t\t\t{\n\t\t\t\tdstOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordLinear(x, y, cachedInfo->slice, 0, cachedInfo->bpp, cachedInfo->pitch, cachedInfo->height, cachedInfo->depth);\n\t\t\t}\n\t\t\telse\n\t\t\t\tdstOffset = LatteAddrLib::ComputeSurfaceAddrFromCoordMacroTiledCached(x, y, cachedInfo);\n\t\t\tuint8* outputBlockData = outputData + dstOffset;\n\t\t\tif (bpp == 32)\n\t\t\t\tcopyValue<uint32, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\telse if (bpp == 16)\n\t\t\t\tcopyValue<uint16, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\telse if (bpp == 8)\n\t\t\t\tcopyValue<uint8, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\telse if (bpp == 64)\n\t\t\t\tcopyValue<uint64, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\telse if (bpp == 128)\n\t\t\t\tcopyValue<uint64, 2, isWrite>(outputBlockData, inputBlockData);\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\tif (bpp != 8)\n\t\t\t{\n\t\t\t\tinputBlockData += (bpp / 8);\n\t\t\t}\n\t\t}\n\t}\n}\n\ntemplate<int bpp, bool isWrite>\nvoid retileTexture_tm04_sample1(ActiveTilingAperature* tilingAperture, uint8* inputData, uint8* outputData, sint32 texelWidth, sint32 texelHeight, sint32 surfaceSlice, sint32 surfacePitch, sint32 surfaceHeight, sint32 surfaceDepth, LatteAddrLib::CachedSurfaceAddrInfo* cachedInfo)\n{\n\tuint16* tableBase = cachedInfo->microTilePixelIndexTable + ((cachedInfo->slice & 7) << 6);\n\tfor (sint32 y = 0; y < texelHeight; y++)\n\t{\n\t\tuint32 srcOffset;\n\t\tuint8* inputBlockData;\n\t\tif (bpp != 8)\n\t\t{\n\t\t\tsrcOffset = (0 + y*surfacePitch)*(bpp / 8);\n\t\t\tinputBlockData = inputData + srcOffset;\n\t\t}\n\t\tfor (sint32 bx = 0; bx < texelWidth; bx += 8)\n\t\t{\n\t\t\tuint16* pixelOffsets = tableBase + ((y&7) << 3);\n\t\t\tuint32 baseOffset = ComputeSurfaceAddrFromCoordMacroTiledCached_tm04_sample1(bx, y, cachedInfo);\n\t\t\tfor (sint32 x = bx; x < bx+8; x++)\n\t\t\t{\n\t\t\t\t// calculate address of input block\n\t\t\t\tif (bpp == 8)\n\t\t\t\t{\n\t\t\t\t\tsint32 texelX = x;\n\t\t\t\t\tsint32 texelY = y;\n\t\t\t\t\ttexelX ^= 8;\n\t\t\t\t\ttexelY ^= 2;\n\t\t\t\t\tsrcOffset = (texelX + texelY*surfacePitch)*(bpp / 8);\n\t\t\t\t\tinputBlockData = inputData + srcOffset;\n\t\t\t\t}\n\t\t\t\t// calculate address of output block\n\t\t\t\tuint32 dstBitPos = 0;\n\t\t\t\tuint32 pixelIndex = *pixelOffsets;\n\t\t\t\tpixelOffsets++;\n\t\t\t\tuint32 pixelOffset = pixelIndex * (bpp/8);\n\t\t\t\tuint32 elemOffset = pixelOffset;\n\t\t\t\tif ((bpp * 8) > 256)\n\t\t\t\t{\n\t\t\t\t\t// separate group bytes, for small formats this step is not necessary since elemOffset is never over 0xFF (maximum is 8*8*bpp)\n\t\t\t\t\telemOffset = (elemOffset & 0xFF) | ((elemOffset&~0xFF) << 3);\n\t\t\t\t}\n\t\t\t\tsint32 offset = baseOffset + elemOffset;\n\n\t\t\t\tuint8* outputBlockData = outputData + offset;\n\t\t\t\tif (bpp == 32)\n\t\t\t\t\tcopyValue<uint32, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\t\telse if (bpp == 16)\n\t\t\t\t\tcopyValue<uint16, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\t\telse if (bpp == 8)\n\t\t\t\t\tcopyValue<uint8, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\t\telse if (bpp == 64)\n\t\t\t\t\tcopyValue<uint64, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\t\telse if (bpp == 128)\n\t\t\t\t\tcopyValue<uint64, 2, isWrite>(outputBlockData, inputBlockData);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t}\n\t\t\t\tif (bpp != 8)\n\t\t\t\t{\n\t\t\t\t\tinputBlockData += (bpp / 8);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// copy remaining partial block\n\t\tfor (sint32 x = (texelWidth&~7); x < texelWidth; x++)\n\t\t{\n\t\t\t// calculate address of input block\n\t\t\tsint32 texelX = x;\n\t\t\tsint32 texelY = y;\n\t\t\tif (bpp == 8)\n\t\t\t{\n\t\t\t\ttexelX ^= 8;\n\t\t\t\ttexelY ^= 2;\n\t\t\t\tsrcOffset = (texelX + texelY*surfacePitch)*(bpp / 8);\n\t\t\t\tinputBlockData = inputData + srcOffset;\n\t\t\t}\n\t\t\t// calculate address of output block\n\t\t\tuint32 dstBitPos = 0;\n\t\t\tuint32 dstOffset = 0;\n\t\t\tdstOffset = ComputeSurfaceAddrFromCoordMacroTiledCached_tm04_sample1(x, y, cachedInfo);\n\n\t\t\tuint8* outputBlockData = outputData + dstOffset;\n\t\t\tif (bpp == 32)\n\t\t\t\tcopyValue<uint32, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\telse if (bpp == 16)\n\t\t\t\tcopyValue<uint16, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\telse if (bpp == 8)\n\t\t\t\tcopyValue<uint8, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\telse if (bpp == 64)\n\t\t\t\tcopyValue<uint64, 1, isWrite>(outputBlockData, inputBlockData);\n\t\t\telse if (bpp == 128)\n\t\t\t\tcopyValue<uint64, 2, isWrite>(outputBlockData, inputBlockData);\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\tif (bpp != 8)\n\t\t\t{\n\t\t\t\tinputBlockData += (bpp / 8);\n\t\t\t}\n\t\t}\n\t}\n}\n\ntemplate<int bpp, bool isWrite>\nvoid retileTextureWrapper(ActiveTilingAperature* tilingAperture, uint8* inputData, uint8* outputData, sint32 texelWidth, sint32 texelHeight, sint32 surfaceSlice, sint32 surfaceTileMode, sint32 surfacePitch, sint32 surfaceHeight, sint32 surfaceDepth, LatteAddrLib::CachedSurfaceAddrInfo* cachedInfo)\n{\n\tif (surfaceTileMode == 0)\n\t\tretileTexture<bpp, isWrite, 0>(tilingAperture, inputData, outputData, texelWidth, texelHeight, surfaceSlice, surfacePitch, surfaceHeight, surfaceDepth, cachedInfo);\n\telse if (surfaceTileMode == 1)\n\t\tretileTexture<bpp, isWrite, 1>(tilingAperture, inputData, outputData, texelWidth, texelHeight, surfaceSlice, surfacePitch, surfaceHeight, surfaceDepth, cachedInfo);\n\telse if (surfaceTileMode == 2)\n\t\tretileTexture<bpp, isWrite, 2>(tilingAperture, inputData, outputData, texelWidth, texelHeight, surfaceSlice, surfacePitch, surfaceHeight, surfaceDepth, cachedInfo);\n\telse if (surfaceTileMode == 3)\n\t\tretileTexture<bpp, isWrite, 3>(tilingAperture, inputData, outputData, texelWidth, texelHeight, surfaceSlice, surfacePitch, surfaceHeight, surfaceDepth, cachedInfo);\n\telse if (surfaceTileMode == 4)\n\t\tretileTexture<bpp, isWrite, 4>(tilingAperture, inputData, outputData, texelWidth, texelHeight, surfaceSlice, surfacePitch, surfaceHeight, surfaceDepth, cachedInfo);\n\telse if (surfaceTileMode == 7)\n\t\tretileTexture<bpp, isWrite, 7>(tilingAperture, inputData, outputData, texelWidth, texelHeight, surfaceSlice, surfacePitch, surfaceHeight, surfaceDepth, cachedInfo);\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n}\n\nvoid LatteTextureLoader_begin(LatteTextureLoaderCtx* textureLoader, uint32 sliceIndex, uint32 mipIndex, MPTR physImagePtr, MPTR physMipPtr, Latte::E_GX2SURFFMT format, Latte::E_DIM dim, uint32 width, uint32 height, uint32 depth, uint32 mipLevels, uint32 pitch, Latte::E_HWTILEMODE tileMode, uint32 swizzle);\n\nvoid GX2TilingAperature_RetileTexture(ActiveTilingAperature* tilingAperture, bool doWrite)\n{\n\t//uint64 timerTilingStart = benchmarkTimer_start();\n\n\tLatte::E_GX2SURFFMT surfaceFormat = tilingAperture->surface.format;\n\tuint32 surfaceSlice = tilingAperture->sliceIndex;\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfaceInfo = {0};\n\tGX2::GX2CalculateSurfaceInfo(&tilingAperture->surface, tilingAperture->mipLevel, &surfaceInfo);\n\tuint32 surfacePitch = surfaceInfo.pitch;\n\tuint32 surfaceSwizzle = tilingAperture->surface.swizzle;\n\tuint32 surfacePipeSwizzle = (surfaceSwizzle>>8)&1;\n\tuint32 surfaceBankSwizzle = ((surfaceSwizzle>>9)&3);\n\tLatte::E_HWTILEMODE surfaceTileMode = surfaceInfo.hwTileMode;\n\tuint32 surfaceDepth = std::max<uint32>(surfaceInfo.depth, 1);\n\tsint32 width = std::max<uint32>((uint32)tilingAperture->surface.width >> tilingAperture->mipLevel, 1);\n\tsint32 height = std::max<uint32>((uint32)tilingAperture->surface.height >> tilingAperture->mipLevel, 1);\n\n\tLatte::E_DIM surfaceDim = tilingAperture->surface.dim;\n\tuint32 surfaceMipSwizzle = 0; // todo\n\tuint32 mipLevels = tilingAperture->surface.numLevels;\n\t// get texture info\n\tuint8* inputData = (uint8*)memory_getPointerFromVirtualOffset(tilingAperture->addr);\n\tuint8* outputData;\n\tif( tilingAperture->mipLevel == 0 )\n\t\toutputData = (uint8*)memory_getPointerFromVirtualOffset(tilingAperture->surface.imagePtr);\n\telse if( tilingAperture->mipLevel == 1 )\n\t\toutputData = (uint8*)memory_getPointerFromVirtualOffset(tilingAperture->surface.mipPtr);\n\telse\n\t\toutputData = (uint8*)memory_getPointerFromVirtualOffset(tilingAperture->surface.mipPtr + tilingAperture->surface.mipOffset[tilingAperture->mipLevel-1]);\n\n\tsint32 stepX = 1;\n\tsint32 stepY = 1;\n\tbool isCompressed = false;\n\tif( Latte::IsCompressedFormat(surfaceFormat) )\n\t{\n\t\tisCompressed = true;\n\t\tstepX = 4;\n\t\tstepY = 4;\n\t}\n\tuint32 bpp = surfaceInfo.bpp;\n\tuint32 bytesPerPixel = bpp/8;\n\n\tLatteAddrLib::CachedSurfaceAddrInfo computeAddrInfo = { 0 };\n\n\tSetupCachedSurfaceAddrInfo(&computeAddrInfo, surfaceSlice, 0, bpp, surfacePitch, surfaceInfo.height, surfaceInfo.depth, 1 * 1, surfaceTileMode, false, surfacePipeSwizzle, surfaceBankSwizzle);\n\n\t// init info for swizzle encoder/decoder\n\tLatteTextureLoaderCtx textureLoaderCtx{};\n\tLatteTextureLoader_begin(&textureLoaderCtx, surfaceSlice, 0, tilingAperture->surface.imagePtr, tilingAperture->surface.mipPtr, surfaceFormat, surfaceDim, width, height, surfaceDepth, mipLevels, surfacePitch, surfaceTileMode, surfaceSwizzle);\n\n\ttextureLoaderCtx.decodedTexelCountX = surfacePitch;\n\ttextureLoaderCtx.decodedTexelCountY = isCompressed ? (height + 3) / 4 : height;\n\n\tif( doWrite )\n\t{\n\t\tif (surfaceTileMode == Latte::E_HWTILEMODE::TM_2D_TILED_THIN1 && bpp == 32 && isCompressed == false)\n\t\t{\n\t\t\toptimizedDecodeLoops<uint32, 1, true, false>(&textureLoaderCtx, inputData);\n\t\t}\n\t\telse if (bpp == 8)\n\t\t\tretileTextureWrapper<8, true>(tilingAperture, inputData, outputData, width / stepX, height / stepY, surfaceSlice, (uint32)surfaceTileMode, surfacePitch, surfaceInfo.height, surfaceDepth, &computeAddrInfo);\n\t\telse if (bpp == 16)\n\t\t\tretileTextureWrapper<16, true>(tilingAperture, inputData, outputData, width / stepX, height / stepY, surfaceSlice, (uint32)surfaceTileMode, surfacePitch, surfaceInfo.height, surfaceDepth, &computeAddrInfo);\n\t\telse if (bpp == 32)\n\t\t\tretileTextureWrapper<32, true>(tilingAperture, inputData, outputData, width / stepX, height / stepY, surfaceSlice, (uint32)surfaceTileMode, surfacePitch, surfaceInfo.height, surfaceDepth, &computeAddrInfo);\n\t\telse if (bpp == 64)\n\t\t\tretileTextureWrapper<64, true>(tilingAperture, inputData, outputData, width / stepX, height / stepY, surfaceSlice, (uint32)surfaceTileMode, surfacePitch, surfaceInfo.height, surfaceDepth, &computeAddrInfo);\n\t\telse if (bpp == 128)\n\t\t\tretileTextureWrapper<128, true>(tilingAperture, inputData, outputData, width / stepX, height / stepY, surfaceSlice, (uint32)surfaceTileMode, surfacePitch, surfaceInfo.height, surfaceDepth, &computeAddrInfo);\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (surfaceTileMode == Latte::E_HWTILEMODE::TM_2D_TILED_THIN1 && bpp == 32 && isCompressed == false)\n\t\t{\n\t\t\toptimizedDecodeLoops<uint32, 1, false, false>(&textureLoaderCtx, inputData);\n\t\t}\n\t\telse if (bpp == 8)\n\t\t\tretileTextureWrapper<8, false>(tilingAperture, inputData, outputData, width / stepX, height / stepY, surfaceSlice, (uint32)surfaceTileMode, surfacePitch, surfaceInfo.height, surfaceDepth, &computeAddrInfo);\n\t\telse if (bpp == 16)\n\t\t\tretileTextureWrapper<16, false>(tilingAperture, inputData, outputData, width / stepX, height / stepY, surfaceSlice, (uint32)surfaceTileMode, surfacePitch, surfaceInfo.height, surfaceDepth, &computeAddrInfo);\n\t\telse if (bpp == 32)\n\t\t\tretileTextureWrapper<32, false>(tilingAperture, inputData, outputData, width / stepX, height / stepY, surfaceSlice, (uint32)surfaceTileMode, surfacePitch, surfaceInfo.height, surfaceDepth, &computeAddrInfo);\n\t\telse if (bpp == 64)\n\t\t\tretileTextureWrapper<64, false>(tilingAperture, inputData, outputData, width / stepX, height / stepY, surfaceSlice, (uint32)surfaceTileMode, surfacePitch, surfaceInfo.height, surfaceDepth, &computeAddrInfo);\n\t\telse if (bpp == 128)\n\t\t\tretileTextureWrapper<128, false>(tilingAperture, inputData, outputData, width / stepX, height / stepY, surfaceSlice, (uint32)surfaceTileMode, surfacePitch, surfaceInfo.height, surfaceDepth, &computeAddrInfo);\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t}\n\n\t//double benchmarkTime = benchmarkTimer_stop(timerTilingStart);\n\t//cemuLog_logDebug(LogType::Force, \"TilingAperture res {:04}x{:04} fmt {:04x} tm {:02x} mip {} isWrite {}\", (uint32)tilingAperture->surface.width, (uint32)tilingAperture->surface.height, (uint32)tilingAperture->surface.format, (uint32)tilingAperture->surface.tileMode, tilingAperture->mipLevel, doWrite?1:0);\n\t//cemuLog_logDebug(LogType::Force, \"Tiling took {:.4}ms\", benchmarkTime);\n}\n\nvoid gx2Export_GX2AllocateTilingApertureEx(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2AllocateTilingApertureEx(0x{:08x}, {}, {}, {}, 0x{:08x}, 0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8]);\n\tGX2Surface* surface = (GX2Surface*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\tcemuLog_log(LogType::GX2, \"Tiling Tex: {:08x} {}x{} Swizzle: {:08x} tm: {} fmt: {:04x} use: {:02x}\", (uint32)surface->imagePtr, (uint32)surface->width, (uint32)surface->height, (uint32)surface->swizzle, (uint32)surface->tileMode.value(), (uint32)surface->format.value(), (uint32)surface->resFlag);\n\n\tif( activeTilingAperatureCount >= GX2_MAX_ACTIVE_TILING_APERATURES )\n\t{\n\t\tdebugBreakpoint();\n\t\tmemory_writeU32(hCPU->gpr[8], MPTR_NULL);\n\t\tmemory_writeU32(hCPU->gpr[7], 0);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\tuint32 mipLevel = hCPU->gpr[4];\n\tuint32 sliceIndex = hCPU->gpr[5];\n\t\n\tuint32 tilingSize = 0;\n\t// calculate size of texture\n\tLatte::E_GX2SURFFMT surfaceFormat = surface->format;\n\tuint32 bitsPerPixel = Latte::GetFormatBits(surfaceFormat);\n\tif (Latte::IsCompressedFormat(surfaceFormat))\n\t\tbitsPerPixel /= (4*4);\n\n\t// get surface pitch\n\tLatteAddrLib::AddrSurfaceInfo_OUT surfaceInfo = {0};\n\tGX2::GX2CalculateSurfaceInfo(surface, 0, &surfaceInfo);\n\tuint32 surfacePitch = surfaceInfo.pitch;\n\tuint32 width = std::max<uint32>((uint32)surface->width >> mipLevel, 1);\n\tuint32 height = std::max<uint32>((uint32)surface->height >> mipLevel, 1);\n\tuint32 alignedWidth = (width+3)&~3;\n\tuint32 alignedHeight = (height+3)&~3;\n\ttilingSize = (surfacePitch*alignedHeight*bitsPerPixel+7)/8;\n\tuint32 taHandle = GX2TilingAperature_GenerateHandle();\n\t// allocate memory for tiling space\n\tMPTR tilingAddress = GX2TilingAperature_allocateTilingMemory(tilingSize);\n\tif( tilingAddress == MPTR_NULL )\n\t{\n\t\tcemu_assert_suspicious();\n\t\tmemory_writeU32(hCPU->gpr[8], MPTR_NULL);\n\t\tmemory_writeU32(hCPU->gpr[7], 0);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\t// add tiling aperture entry\n\tactiveTilingAperature[activeTilingAperatureCount].addr = tilingAddress;\n\tactiveTilingAperature[activeTilingAperatureCount].size = tilingSize;\n\tactiveTilingAperature[activeTilingAperatureCount].handle = taHandle;\n\tactiveTilingAperature[activeTilingAperatureCount].endianMode = hCPU->gpr[6];\n\tactiveTilingAperature[activeTilingAperatureCount].sliceIndex = sliceIndex;\n\tactiveTilingAperature[activeTilingAperatureCount].mipLevel = mipLevel;\n\tmemcpy(&activeTilingAperature[activeTilingAperatureCount].surface, surface, sizeof(GX2Surface));\n\tactiveTilingAperatureCount++;\n\t// return values\n\tmemory_writeU32(hCPU->gpr[8], tilingAddress);\n\tmemory_writeU32(hCPU->gpr[7], taHandle);\n\t// load texture data into tiling area\n\tGX2TilingAperature_RetileTexture(activeTilingAperature+activeTilingAperatureCount-1, false);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2FreeTilingAperture(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2FreeTilingAperture(0x{:08x})\", hCPU->gpr[3]);\n\tuint32 handle = hCPU->gpr[3];\n\tfor(sint32 i=0; i<activeTilingAperatureCount; i++)\n\t{\n\t\tif( activeTilingAperature[i].handle == handle )\n\t\t{\n\t\t\t// flush texture\n\t\t\tGX2TilingAperature_RetileTexture(activeTilingAperature+i, true);\n\t\t\t// remove entry\n\t\t\tif( i+1 < activeTilingAperatureCount )\n\t\t\t{\n\t\t\t\tmemcpy(activeTilingAperature+i, activeTilingAperature+activeTilingAperatureCount-1, sizeof(ActiveTilingAperature));\n\t\t\t}\n\t\t\tactiveTilingAperatureCount--;\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/gx2/GX2_shader_legacy.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n#include \"Cafe/HW/Latte/ISA/LatteReg.h\"\n#include \"Cafe/HW/Latte/Core/LattePM4.h\"\n\n#include \"GX2.h\"\n#include \"GX2_Shader.h\"\n\nvoid gx2Export_GX2SetPixelShader(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetPixelShader(0x{:08x})\", hCPU->gpr[3]);\n\tGX2PixelShader_t* pixelShader = (GX2PixelShader_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\n\tuint32 numInputs = _swapEndianU32(pixelShader->regs[4]);\n\tif( numInputs > 0x20 )\n\t\tnumInputs = 0x20;\n\n\tGX2::GX2ReserveCmdSpace(26 + numInputs);\n\n\tMPTR shaderProgramAddr;\n\tuint32 shaderProgramSize;\n\n\tif( _swapEndianU32(pixelShader->shaderPtr) != MPTR_NULL )\n\t{\n\t\t// old format\n\t\tshaderProgramAddr = _swapEndianU32(pixelShader->shaderPtr);\n\t\tshaderProgramSize = _swapEndianU32(pixelShader->shaderSize);\n\t}\n\telse\n\t{\n\t\tshaderProgramAddr = pixelShader->rBuffer.GetVirtualAddr();\n\t\tshaderProgramSize = pixelShader->rBuffer.GetSize();\n\t}\n\n\tgx2WriteGather_submit(\n\t\t/* pixel shader program */\n\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 6),\n\t\tmmSQ_PGM_START_PS - 0xA000,\n\t\tmemory_virtualToPhysical(shaderProgramAddr)>>8, // address\n\t\tshaderProgramSize>>3, // size\n\t\t0x100000,\n\t\t0x100000,\n\t\t_swapEndianU32(pixelShader->regs[0]), // ukn\n  \t\t/* setup pixel shader input control */\n\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 3),\n\t\tmmSPI_PS_IN_CONTROL_0-0xA000,\n\t\t_swapEndianU32(pixelShader->regs[2]),\n\t\t_swapEndianU32(pixelShader->regs[3]));\n\t// setup pixel shader extended inputs control\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1+numInputs));\n\tgx2WriteGather_submitU32AsBE(mmSPI_PS_INPUT_CNTL_0-0xA000);\n\tfor(uint32 i=0; i<numInputs; i++)\n\t{\n\t\tuint32 inputData = _swapEndianU32(pixelShader->regs[5+i]);\n\t\tgx2WriteGather_submitU32AsBE(inputData);\n\t}\n\n\tgx2WriteGather_submit(\n\t\t/* mmCB_SHADER_MASK */\n\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\tmmCB_SHADER_MASK-0xA000,\n\t\t_swapEndianU32(pixelShader->regs[37]),\n\t\t/* mmCB_SHADER_CONTROL */\n\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\tmmCB_SHADER_CONTROL-0xA000,\n\t\t_swapEndianU32(pixelShader->regs[38]),\n\t\t/* mmDB_SHADER_CONTROL */\n\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\tmmDB_SHADER_CONTROL-0xA000,\n\t\t_swapEndianU32(pixelShader->regs[39]),\n\t\t/* SPI_INPUT_Z */\n\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\tmmSPI_INPUT_Z-0xA000,\n\t\t_swapEndianU32(pixelShader->regs[40]));\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SetGeometryShader(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetGeometryShader(0x{:08x})\", hCPU->gpr[3]);\n\n\tGX2GeometryShader_t* geometryShader = (GX2GeometryShader_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\tuint32 numOutputIds = _swapEndianU32(geometryShader->regs[7]);\n\tnumOutputIds = std::min<uint32>(numOutputIds, 0xA);\n\tuint32 reserveSize = 38; // 38 fixed parameters\n\tif (numOutputIds != 0)\n\t\treserveSize += 2 + numOutputIds;\n\tif( _swapEndianU32(geometryShader->useStreamout) != 0 )\n\t\treserveSize += 2 + 12;\n\n\tGX2::GX2ReserveCmdSpace(reserveSize);\n\n\tMPTR shaderProgramAddr;\n\tuint32 shaderProgramSize;\n\n\tif( _swapEndianU32(geometryShader->shaderPtr) != MPTR_NULL )\n\t{\n\t\t// old format\n\t\tshaderProgramAddr = _swapEndianU32(geometryShader->shaderPtr);\n\t\tshaderProgramSize = _swapEndianU32(geometryShader->shaderSize);\n\t}\n\telse\n\t{\n\t\tshaderProgramAddr = geometryShader->rBuffer.GetVirtualAddr();\n\t\tshaderProgramSize = geometryShader->rBuffer.GetSize();\n\t}\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 6));\n\tgx2WriteGather_submitU32AsBE(mmSQ_PGM_START_GS-0xA000);\n\tgx2WriteGather_submitU32AsBE(memory_virtualToPhysical(shaderProgramAddr)>>8);\n\tgx2WriteGather_submitU32AsBE(shaderProgramSize>>3);\n\tgx2WriteGather_submitU32AsBE(0x100000);\n\tgx2WriteGather_submitU32AsBE(0x100000);\n\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->regs[0])); // unknown content (SQ_PGM_RESOURCES_GS)\n\n\tuint32 primitiveOut = _swapEndianU32(geometryShader->regs[1]);\n\t\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\tgx2WriteGather_submitU32AsBE(mmVGT_GS_OUT_PRIM_TYPE-0xA000);\n\tgx2WriteGather_submitU32AsLE(geometryShader->regs[1]);\n\n\tgx2WriteGather_submit(\n\t\tpm4HeaderType3(IT_SET_CONTEXT_REG, 2),\n\t\tLatte::REGADDR::VGT_GS_MODE - 0xA000,\n\t\tgeometryShader->reg.VGT_GS_MODE\n\t);\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\tgx2WriteGather_submitU32AsBE(mmSQ_PGM_RESOURCES_GS-0xA000);\n\tgx2WriteGather_submitU32AsLE(geometryShader->regs[0]);\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\tgx2WriteGather_submitU32AsBE(mmSQ_GS_VERT_ITEMSIZE-0xA000);\n\tgx2WriteGather_submitU32AsLE(geometryShader->regs[5]);\n\t\n\tif( _swapEndianU32(geometryShader->useStreamout) != 0 )\n\t{\n\t\t// todo - IT_EVENT_WRITE packet here\n\t\t// stride 0\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\t\tgx2WriteGather_submitU32AsBE(mmVGT_STRMOUT_VTX_STRIDE_0-0xA000);\n\t\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->streamoutStride[0])>>2);\n\t\t// stride 1\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\t\tgx2WriteGather_submitU32AsBE(mmVGT_STRMOUT_VTX_STRIDE_1-0xA000);\n\t\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->streamoutStride[1])>>2);\n\t\t// stride 2\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\t\tgx2WriteGather_submitU32AsBE(mmVGT_STRMOUT_VTX_STRIDE_2-0xA000);\n\t\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->streamoutStride[2])>>2);\n\t\t// stride 3\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\t\tgx2WriteGather_submitU32AsBE(mmVGT_STRMOUT_VTX_STRIDE_3-0xA000);\n\t\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->streamoutStride[3])>>2);\n\t}\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\tgx2WriteGather_submitU32AsBE(mmVGT_STRMOUT_BUFFER_EN-0xA000);\n\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->regs[18]));\n\n\t// set copy shader (written to vertex shader registers, vs in turn is written to es registers)\n\tMPTR copyShaderProgramAddr;\n\tuint32 copyShaderProgramSize;\n\tif( _swapEndianU32(geometryShader->copyShaderPtr) != MPTR_NULL )\n\t{\n\t\tcopyShaderProgramAddr = _swapEndianU32(geometryShader->copyShaderPtr);\n\t\tcopyShaderProgramSize = _swapEndianU32(geometryShader->copyShaderSize);\n\t}\n\telse\n\t{\n\t\tcopyShaderProgramAddr = geometryShader->rBufferCopyProgram.GetVirtualAddr();\n\t\tcopyShaderProgramSize = geometryShader->rBufferCopyProgram.GetSize();\n\t}\n\n\tcemu_assert_debug((copyShaderProgramAddr>>8) != 0);\n\tcemu_assert_debug((copyShaderProgramSize>>3) != 0);\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 6));\n\tgx2WriteGather_submitU32AsBE(mmSQ_PGM_START_VS-0xA000);\n\tgx2WriteGather_submitU32AsBE(memory_virtualToPhysical(copyShaderProgramAddr)>>8);\n\tgx2WriteGather_submitU32AsBE(copyShaderProgramSize>>3);\n\tgx2WriteGather_submitU32AsBE(0x100000);\n\tgx2WriteGather_submitU32AsBE(0x100000);\n\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->regs[4])); // mmSQ_PGM_RESOURCES_VS\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\tgx2WriteGather_submitU32AsBE(mmPA_CL_VS_OUT_CNTL-0xA000);\n\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->regs[3]));\n\n\t// GS outputs\n\tif( numOutputIds != 0 )\n\t{\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 1+numOutputIds));\n\t\tgx2WriteGather_submitU32AsBE(mmSPI_VS_OUT_ID_0-0xA000);\n\t\tfor(uint32 i=0; i<numOutputIds; i++)\n\t\t{\n\t\t\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->regs[8+i]));\n\t\t}\n\t}\n\n\t// output config\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\tgx2WriteGather_submitU32AsBE(mmSPI_VS_OUT_CONFIG-0xA000);\n\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->regs[6]));\n\n\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\tgx2WriteGather_submitU32AsBE(mmSQ_GSVS_RING_ITEMSIZE-0xA000);\n\tgx2WriteGather_submitU32AsBE(_swapEndianU32(geometryShader->ringItemsize)&0x7FFF);\n\n\t/*\n\t  Geometry shader registers in regs[19]:\n\t  0\t\tSQ_PGM_RESOURCES_GS ?\n\t  1\t\tmmVGT_GS_OUT_PRIM_TYPE\n\t  2\t\tmmVGT_GS_MODE\n\t  3\t\tmmPA_CL_VS_OUT_CNTL\n\t  4\t\tmmSQ_PGM_RESOURCES_VS (set in combination with mmSQ_PGM_START_VS)\n\t  5\t\tmmSQ_GS_VERT_ITEMSIZE\n\t  6\t\tmmSPI_VS_OUT_CONFIG\n\t  7\t\tnumber of active mmSPI_VS_OUT_ID_* fields?\n\t  8-17  mmSPI_VS_OUT_ID_*\n\t  18\tmmVGT_STRMOUT_BUFFER_EN\n\t */\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nstruct GX2ComputeShader\n{\n\t/* +0x00 */ uint32be regs[12];\n\t/* +0x30 */ uint32be programSize;\n\t/* +0x34 */ uint32be programPtr;\n\t/* +0x38 */ uint32be ukn38;\n\t/* +0x3C */ uint32be ukn3C;\n\t/* +0x40 */ uint32be ukn40[8];\n\t/* +0x60 */ uint32be workgroupSizeX;\n\t/* +0x64 */ uint32be workgroupSizeY;\n\t/* +0x68 */ uint32be workgroupSizeZ;\n\t/* +0x6C */ uint32be workgroupSizeSpecial;\n\t/* +0x70 */ uint32be ukn70;\n\t/* +0x74 */ GX2RBuffer rBuffer;\n};\n\nstatic_assert(offsetof(GX2ComputeShader, programSize) == 0x30);\nstatic_assert(offsetof(GX2ComputeShader, workgroupSizeX) == 0x60);\nstatic_assert(offsetof(GX2ComputeShader, rBuffer) == 0x74);\n\nvoid gx2Export_GX2SetComputeShader(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamTypePtr(computeShader, GX2ComputeShader, 0);\n\tcemuLog_log(LogType::GX2, \"GX2SetComputeShader(0x{:08x})\", hCPU->gpr[3]);\n\n\tMPTR shaderPtr;\n\tuint32 shaderSize;\n\tif (computeShader->programPtr)\n\t{\n\t\tshaderPtr = computeShader->programPtr;\n\t\tshaderSize = computeShader->programSize;\n\t}\n\telse\n\t{\n\t\tshaderPtr = computeShader->rBuffer.GetVirtualAddr();\n\t\tshaderSize = computeShader->rBuffer.GetSize();\n\t}\n\tGX2::GX2ReserveCmdSpace(0x11);\n\n\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_CONTEXT_REG, 6),\n\t\tmmSQ_PGM_START_ES-0xA000,\n\t\tmemory_virtualToPhysical(shaderPtr) >> 8,\n\t\tshaderSize >> 3,\n\t\t0x100000,\n\t\t0x100000,\n\t\tcomputeShader->regs[0]);\n\n\t// todo: Other registers\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid _GX2SubmitUniformBlock(uint32 registerBase, uint32 index, MPTR virtualAddress, uint32 size)\n{\n\tGX2::GX2ReserveCmdSpace(9);\n\tgx2WriteGather_submit(pm4HeaderType3(IT_SET_RESOURCE, 8),\n\t\tregisterBase + index * 7,\n\t\tmemory_virtualToPhysical(virtualAddress),\n\t\tsize - 1,\n\t\t0,\n\t\t1,\n\t\t0, // ukn\n\t\t0, // ukn\n\t\t0xC0000000);\n}\n\nvoid gx2Export_GX2SetVertexUniformBlock(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetVertexUniformBlock(0x{:08x},0x{:x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\t_GX2SubmitUniformBlock(mmSQ_VTX_UNIFORM_BLOCK_START - mmSQ_TEX_RESOURCE_WORD0, hCPU->gpr[3], hCPU->gpr[5], hCPU->gpr[4]);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SetPixelUniformBlock(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetPixelUniformBlock(0x{:08x},0x{:x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\t_GX2SubmitUniformBlock(mmSQ_PS_UNIFORM_BLOCK_START - mmSQ_TEX_RESOURCE_WORD0, hCPU->gpr[3], hCPU->gpr[5], hCPU->gpr[4]);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SetGeometryUniformBlock(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::GX2, \"GX2SetGeometryUniformBlock(0x{:08x},0x{:x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\t_GX2SubmitUniformBlock(mmSQ_GS_UNIFORM_BLOCK_START - mmSQ_TEX_RESOURCE_WORD0, hCPU->gpr[3], hCPU->gpr[5], hCPU->gpr[4]);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2RSetVertexUniformBlock(PPCInterpreter_t* hCPU)\n{\n\tGX2::GX2ReserveCmdSpace(9);\n\n\tGX2RBuffer* bufferPtr = (GX2RBuffer*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\tuint32 index = hCPU->gpr[4];\n\tuint32 offset = hCPU->gpr[5];\n\n\t_GX2SubmitUniformBlock(mmSQ_VTX_UNIFORM_BLOCK_START - mmSQ_TEX_RESOURCE_WORD0, index, bufferPtr->GetVirtualAddr() + offset, bufferPtr->GetSize() - offset);\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2SetShaderModeEx(PPCInterpreter_t* hCPU)\n{\n\tGX2::GX2ReserveCmdSpace(8+4);\n\tuint32 mode = hCPU->gpr[3];\n\n\tuint32 sqConfig = hCPU->gpr[3] == 0 ? 4 : 0;\n\tif (mode == GX2_SHADER_MODE_COMPUTE_SHADER)\n\t\tsqConfig |= 0xE4000000; // ES/GS/PS priority?\n\t// todo - other sqConfig bits\n\n\tgx2WriteGather_submit((uint32)(pm4HeaderType3(IT_SET_CONFIG_REG, 7)),\n\t\t\t(uint32)(mmSQ_CONFIG - 0x2000),\n\t\t\tsqConfig,\n\t\t\t0, // ukn / todo\n\t\t\t0, // ukn / todo\n\t\t\t0, // ukn / todo\n\t\t\t0, // ukn / todo\n\t\t\t0 // ukn / todo\n\t\t);\n\n\t// if not GS, then update mmVGT_GS_MODE\n\tif( mode != GX2_SHADER_MODE_GEOMETRY_SHADER )\n\t{\n\t\t// update VGT_GS_MODE only if no geometry shader is used (else this register is already set by GX2SetGeometryShader)\n\t\tgx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SET_CONTEXT_REG, 2));\n\t\tgx2WriteGather_submitU32AsBE(Latte::REGADDR::VGT_GS_MODE-0xA000);\n\t\tif (mode == GX2_SHADER_MODE_COMPUTE_SHADER)\n\t\t\tgx2WriteGather_submitU32AsBE(Latte::LATTE_VGT_GS_MODE().set_MODE(Latte::LATTE_VGT_GS_MODE::E_MODE::SCENARIO_G).set_COMPUTE_MODE(Latte::LATTE_VGT_GS_MODE::E_COMPUTE_MODE::ON).set_PARTIAL_THD_AT_EOI(true).getRawValueBE());\n\t\telse\n\t\t\tgx2WriteGather_submitU32AsBE(_swapEndianU32(0));\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid gx2Export_GX2CalcGeometryShaderInputRingBufferSize(PPCInterpreter_t* hCPU)\n{\n\tuint32 size = (hCPU->gpr[3]*4) * 0x1000;\n\tosLib_returnFromFunction(hCPU, size);\n}\n\nvoid gx2Export_GX2CalcGeometryShaderOutputRingBufferSize(PPCInterpreter_t* hCPU)\n{\n\tuint32 size = (hCPU->gpr[3]*4) * 0x1000;\n\tosLib_returnFromFunction(hCPU, size);\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/h264_avc/H264Dec.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/libs/h264_avc/parser/H264Parser.h\"\n#include \"Cafe/OS/libs/h264_avc/H264DecInternal.h\"\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n#include \"Cafe/CafeSystem.h\"\n\n#include \"h264dec.h\"\n\nenum class H264DEC_STATUS : uint32\n{\n\tSUCCESS = 0x0,\n\tBAD_STREAM = 0x1000000,\n\tINVALID_PARAM = 0x1010000,\n};\n\nnamespace H264\n{\n\tbool H264_IsBotW()\n\t{\n\t\t// Cemuhook has a hack where it always returns a small size for H264DECMemoryRequirement (256 bytes)\n\t\t// it also outputs images pre-cropped instead of giving the game raw uncropped images\n\t\t// both of these are required to allow Breath of the Wild to playback the higher res (1080p) videos from the Switch version\n\t\t// we mirror these hacks for user convenience and because there are no downsides\n\t\tuint64 currentTitleId = CafeSystem::GetForegroundTitleId();\n\t\tif (currentTitleId == 0x00050000101c9500 || currentTitleId == 0x00050000101c9400 || currentTitleId == 0x00050000101c9300)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\tstruct H264Context\n\t{\n\t\tstruct\n\t\t{\n\t\t\tMEMPTR<void> ptr{ nullptr };\n\t\t\tuint32be length{ 0 };\n\t\t\tfloat64be timestamp;\n\t\t}BitStream;\n\t\tstruct\n\t\t{\n\t\t\tMEMPTR<void> outputFunc{ nullptr };\n\t\t\tuint8be outputPerFrame{ 0 }; // whats the default?\n\t\t\tMEMPTR<void> userMemoryParam{ nullptr };\n\t\t}Param;\n\t\t// misc\n\t\tuint32be sessionHandle;\n\n\t\t// decoder state\n\t\tstruct\n\t\t{\n\t\t\tuint32 numFramesInFlight{0};\n\t\t}decoderState;\n\t};\n\n\tuint32 H264DECMemoryRequirement(uint32 codecProfile, uint32 codecLevel, uint32 width, uint32 height, uint32be* sizeRequirementOut)\n\t{\n\t\tif (H264_IsBotW())\n\t\t{\n\t\t\tstatic_assert(sizeof(H264Context) < 256);\n\t\t\t*sizeRequirementOut = 256;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// note: On console this seems to check if maxWidth or maxHeight < 64 but Pikmin 3 passes 32x32 and crashes if this function fails ?\n\t\tif (width < 0x20 || height < 0x20 || width > 2800 || height > 1408 || sizeRequirementOut == MPTR_NULL || codecLevel >= 52 || (codecProfile != 0x42 && codecProfile != 0x4D && codecProfile != 0x64))\n\t\t\treturn 0x1010000;\n\n\t\tuint32 workbufferSize = 0;\n\t\tif (codecLevel < 0xB)\n\t\t{\n\t\t\tworkbufferSize = 0x18C << 10;\n\t\t}\n\t\telse if (codecLevel == 0xB)\n\t\t{\n\t\t\tworkbufferSize = 0x384 << 10;\n\t\t}\n\t\telse if (codecLevel >= 0xC && codecLevel <= 0x14)\n\t\t{\n\t\t\tworkbufferSize = 0x948 << 10;\n\t\t}\n\t\telse if (codecLevel == 0x15)\n\t\t{\n\t\t\tworkbufferSize = 0x1290 << 10;\n\t\t}\n\t\telse if (codecLevel >= 0x16 && codecLevel <= 0x1E)\n\t\t{\n\t\t\tworkbufferSize = 0x1FA4 << 10;\n\t\t}\n\t\telse if (codecLevel == 0x1F)\n\t\t{\n\t\t\tworkbufferSize = 0x4650 << 10;\n\t\t}\n\t\telse if (codecLevel == 0x20)\n\t\t{\n\t\t\tworkbufferSize = 0x1400000;\n\t\t}\n\t\telse if (codecLevel >= 0x21 && codecLevel <= 0x29)\n\t\t{\n\t\t\tworkbufferSize = 0x8000 << 10;\n\t\t}\n\t\telse if (codecLevel == 0x2A)\n\t\t{\n\t\t\tworkbufferSize = 0x2200000;\n\t\t}\n\t\telse if (codecLevel >= 0x2B && codecLevel <= 0x32)\n\t\t{\n\t\t\tworkbufferSize = 0x1AF40 << 10;\n\t\t}\n\t\telse if (codecLevel >= 0x33)\n\t\t{\n\t\t\tworkbufferSize = 0x2D000 << 10;\n\t\t}\n\t\tworkbufferSize += 0x447;\n\t\t*sizeRequirementOut = workbufferSize;\n\t\treturn 0;\n\t}\n\n\tuint32 H264DECCheckMemSegmentation(MPTR memory, uint32 size)\n\t{\n\t\t// return 0 for valid, 1 for invalid\n\t\t// currently we allow any range\n\t\treturn 0;\n\t}\n\n\tH264DEC_STATUS H264DECFindDecstartpoint(uint8* ptr, uint32 length, uint32be* offsetOut)\n\t{\n\t\tif (!ptr || length < 4 || !offsetOut)\n\t\t\treturn H264DEC_STATUS::INVALID_PARAM;\n\t\tfor (uint32 i = 0; i < length - 4; ++i)\n\t\t{\n\t\t\tuint8 b = ptr[i];\n\t\t\tif (b != 0)\n\t\t\t\tcontinue;\n\n\t\t\tb = ptr[i + 1];\n\t\t\tif (b != 0)\n\t\t\t\tcontinue;\n\n\t\t\tb = ptr[i + 2];\n\t\t\tif (b != 1)\n\t\t\t\tcontinue;\n\n\t\t\tb = ptr[i + 3];\n\t\t\tb &= 0x9F;\n\t\t\tif (b != 7) // check for NAL type SPS\n\t\t\t\tcontinue;\n\n\t\t\tif (i > 0)\n\t\t\t\t*offsetOut = i - 1;\n\t\t\telse\n\t\t\t\t*offsetOut = 0;\n\n\t\t\treturn H264DEC_STATUS::SUCCESS;\n\t\t}\n\t\treturn H264DEC_STATUS::BAD_STREAM;\n\t}\n\n\tH264DEC_STATUS H264DECFindIdrpoint(uint8* ptr, uint32 length, uint32be* offsetOut)\n\t{\n\t\tif (!ptr || length < 4 || !offsetOut)\n\t\t\treturn H264DEC_STATUS::INVALID_PARAM;\n\n\t\tfor (uint32 i = 0; i < length - 4; ++i)\n\t\t{\n\t\t\tuint8 b = ptr[i];\n\t\t\tif (b != 0)\n\t\t\t\tcontinue;\n\n\t\t\tb = ptr[i + 1];\n\t\t\tif (b != 0)\n\t\t\t\tcontinue;\n\n\t\t\tb = ptr[i + 2];\n\t\t\tif (b != 1)\n\t\t\t\tcontinue;\n\n\t\t\tb = ptr[i + 3];\n\t\t\tb &= 0x9F;\n\t\t\tif (b != 5 && b != 7 && b != 8) // check for NAL type IDR slice, but also accept SPS or PPS slices\n\t\t\t\tcontinue;\n\n\t\t\tif (i > 0)\n\t\t\t\t*offsetOut = i - 1;\n\t\t\telse\n\t\t\t\t*offsetOut = 0;\n\n\t\t\treturn H264DEC_STATUS::SUCCESS;\n\t\t}\n\t\treturn H264DEC_STATUS::BAD_STREAM;\n\t}\n\n\tH264DEC_STATUS H264DECGetImageSize(uint8* stream, uint32 length, uint32 offset, uint32be* outputWidth, uint32be* outputHeight)\n\t{\n\t\tif(!stream || length < 4 || !outputWidth || !outputHeight)\n\t\t\treturn H264DEC_STATUS::INVALID_PARAM;\n\t\tif( (offset+4) > length )\n\t\t\treturn H264DEC_STATUS::INVALID_PARAM;\n\t\tuint8* cur = stream + offset;\n\t\tuint8* end = stream + length;\n\t\tcur += 2; // we access cur[-2] and cur[-1] so we need to start at offset 2\n\t\twhile(cur < end-2)\n\t\t{\n\t\t\t// check for start code\n\t\t\tif(*cur != 1)\n\t\t\t{\n\t\t\t\tcur++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// check if this is a valid NAL header\n\t\t\tif(cur[-2] != 0 || cur[-1] != 0 || cur[0] != 1)\n\t\t\t{\n\t\t\t\tcur++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tuint8 nalHeader = cur[1];\n\t\t\tif((nalHeader & 0x1F) != 7)\n\t\t\t{\n\t\t\t\tcur++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\th264State_seq_parameter_set_t psp;\n\t\t\tbool r = h264Parser_ParseSPS(cur+2, end-cur-2, psp);\n\t\t\tif(!r)\n\t\t\t{\n\t\t\t\tcemu_assert_suspicious(); // should not happen\n\t\t\t\treturn H264DEC_STATUS::BAD_STREAM;\n\t\t\t}\n\t\t\t*outputWidth = (psp.pic_width_in_mbs_minus1 + 1) * 16;\n\t\t\t*outputHeight = (psp.pic_height_in_map_units_minus1 + 1) * 16; // affected by frame_mbs_only_flag?\n\t\t\treturn H264DEC_STATUS::SUCCESS;\n\t\t}\n\t\treturn H264DEC_STATUS::BAD_STREAM;\n\t}\n\n\tuint32 H264DECInitParam(uint32 workMemorySize, void* workMemory)\n\t{\n\t\tH264Context* ctx = (H264Context*)workMemory;\n\t\t*ctx = {};\n\t\treturn 0;\n\t}\n\n\tstd::unordered_map<uint32, H264DecoderBackend*> sDecoderSessions;\n\tstd::mutex sDecoderSessionsMutex;\n\tstd::atomic_uint32_t sCurrentSessionHandle{ 1 };\n\n\tH264DecoderBackend* CreateAVCDecoder();\n\n\tstatic H264DecoderBackend* _CreateDecoderSession(uint32& handleOut)\n\t{\n\t\tstd::unique_lock _lock(sDecoderSessionsMutex);\n\t\thandleOut = sCurrentSessionHandle.fetch_add(1);\n\t\tH264DecoderBackend* session = CreateAVCDecoder();\n\t\tsDecoderSessions.try_emplace(handleOut, session);\n\t\treturn session;\n\t}\n\n\tstatic H264DecoderBackend* _AcquireDecoderSession(uint32 handle)\n\t{\n\t\tstd::unique_lock _lock(sDecoderSessionsMutex);\n\t\tauto it = sDecoderSessions.find(handle);\n\t\tif (it == sDecoderSessions.end())\n\t\t\treturn nullptr;\n\t\tH264DecoderBackend* session = it->second;\n\t\tif (sDecoderSessions.size() >= 5)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"H264: Warning - more than 5 active sessions\");\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t\treturn session;\n\t}\n\n\tstatic void _ReleaseDecoderSession(H264DecoderBackend* session)\n\t{\n\t\tstd::unique_lock _lock(sDecoderSessionsMutex);\n\n\t}\n\n\tstatic void _DestroyDecoderSession(uint32 handle)\n\t{\n\t\tstd::unique_lock _lock(sDecoderSessionsMutex);\n\t\tauto it = sDecoderSessions.find(handle);\n\t\tif (it == sDecoderSessions.end())\n\t\t\treturn;\n\t\tH264DecoderBackend* session = it->second;\n\t\tsession->Destroy();\n\t\tdelete session;\n\t\tsDecoderSessions.erase(it);\n\t}\n\n\tuint32 H264DECOpen(void* workMemory)\n\t{\n\t\tH264Context* ctx = (H264Context*)workMemory;\n\t\tuint32 sessionHandle;\n\t\t_CreateDecoderSession(sessionHandle);\n\t\tctx->sessionHandle = sessionHandle;\n\t\treturn 0;\n\t}\n\n\tuint32 H264DECClose(void* workMemory)\n\t{\n\t\tif (workMemory)\n\t\t{\n\t\t\tH264Context* ctx = (H264Context*)workMemory;\n\t\t\t_DestroyDecoderSession(ctx->sessionHandle);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tuint32 H264DECBegin(void* workMemory)\n\t{\n\t\tH264Context* ctx = (H264Context*)workMemory;\n\t\tH264DecoderBackend* session = _AcquireDecoderSession(ctx->sessionHandle);\n\t\tif (!session)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"H264DECBegin(): Invalid session\");\n\t\t\treturn 0;\n\t\t}\n\t\tsession->Init(ctx->Param.outputPerFrame == 0);\n\t\tctx->decoderState.numFramesInFlight = 0;\n\t\t_ReleaseDecoderSession(session);\n\t\treturn 0;\n\t}\n\n\tvoid H264DoFrameOutputCallback(H264Context* ctx, H264DecoderBackend::DecodeResult& decodeResult);\n\n\tH264DEC_STATUS H264DECEnd(void* workMemory)\n\t{\n\t\tH264Context* ctx = (H264Context*)workMemory;\n\t\tH264DecoderBackend* session = _AcquireDecoderSession(ctx->sessionHandle);\n\t\tif (!session)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"H264DECEnd(): Invalid session\");\n\t\t\treturn H264DEC_STATUS::SUCCESS;\n\t\t}\n\t\tcoreinit::OSEvent* flushEvt = &session->GetFlushEvent();\n\t\tcoreinit::OSResetEvent(flushEvt);\n\t\tsession->QueueFlush();\n\t\tcoreinit::OSWaitEvent(flushEvt);\n\t\twhile(true)\n\t\t{\n\t\t\tH264DecoderBackend::DecodeResult decodeResult;\n\t\t\tif( !session->GetFrameOutputIfReady(decodeResult) )\n\t\t\t\tbreak;\n\t\t\t// todo - output all frames in a single callback?\n\t\t\tH264DoFrameOutputCallback(ctx, decodeResult);\n\t\t\tctx->decoderState.numFramesInFlight--;\n\t\t}\n\t\tcemu_assert_debug(ctx->decoderState.numFramesInFlight == 0); // no frames should be in flight anymore. Exact behavior is not well understood but we may have to output dummy frames if necessary\n\t\t_ReleaseDecoderSession(session);\n\t\treturn H264DEC_STATUS::SUCCESS;\n\t}\n\n\tH264DEC_STATUS H264DECSetParam_FPTR_OUTPUT(H264Context* ctx, void* outputFunc)\n\t{\n\t\tctx->Param.outputFunc = outputFunc;\n\t\treturn H264DEC_STATUS::SUCCESS;\n\t}\n\n\tH264DEC_STATUS H264DECSetParam_OUTPUT_PER_FRAME(H264Context* ctx, uint32 outputPerFrame)\n\t{\n\t\tctx->Param.outputPerFrame = outputPerFrame != 0 ? 1 : 0;\n\t\treturn H264DEC_STATUS::SUCCESS;\n\t}\n\n\tH264DEC_STATUS H264DECSetParam_USER_MEMORY(H264Context* ctx, MEMPTR<void*>* userMemoryParamPtr)\n\t{\n\t\tctx->Param.userMemoryParam = *userMemoryParamPtr;\n\t\treturn H264DEC_STATUS::SUCCESS;\n\t}\n\n\tH264DEC_STATUS H264DECSetParam(H264Context* ctx, uint32 paramId, void* paramValue)\n\t{\n\t\tconst uint32 PARAMID_FPTR_OUTPUT = 0x1;\n\t\tconst uint32 PARAMID_OUTPUT_PER_FRAME = 0x20000002;\n\t\tconst uint32 PARAMID_USER_MEMORY = 0x70000001;\n\t\tconst uint32 PARAMID_UKN = 0x20000030;\n\n\t\tif (paramId == PARAMID_FPTR_OUTPUT)\n\t\t{\n\t\t\tctx->Param.outputFunc = paramValue;\n\t\t}\n\t\telse if (paramId == PARAMID_USER_MEMORY)\n\t\t{\n\t\t\tctx->Param.userMemoryParam = paramValue;\n\t\t}\n\t\telse if (paramId == PARAMID_OUTPUT_PER_FRAME)\n\t\t{\n\t\t\tctx->Param.outputPerFrame = *(uint8be*)paramValue != 0;\n\t\t}\n\t\telse if (paramId == PARAMID_UKN)\n\t\t{\n\t\t\t// unknown purpose, seen in MK8. paramValue points to a bool\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"h264Export_H264DECSetParam(): Unsupported parameterId 0x{:08x}\\n\", paramId);\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\treturn H264DEC_STATUS::SUCCESS;\n\t}\n\n\tuint32 H264DECSetBitstream(void* workMemory, void* ptr, uint32 length, double timestamp)\n\t{\n\t\tH264Context* ctx = (H264Context*)workMemory;\n\t\tctx->BitStream.ptr = ptr;\n\t\tctx->BitStream.length = length;\n\t\tctx->BitStream.timestamp = timestamp;\n\t\treturn 0;\n\t}\n\n\tstruct H264DECFrameOutput\n\t{\n\t\t/* +0x00 */ uint32be result;\n\t\t/* +0x04 */ uint32be padding04;\n\t\t/* +0x08 */ betype<double> timestamp;\n\t\t/* +0x10 */ uint32be frameWidth;\n\t\t/* +0x14 */ uint32be frameHeight;\n\t\t/* +0x18 */ uint32be bytesPerRow;\n\t\t/* +0x1C */ uint32be cropEnable;\n\t\t/* +0x20 */ uint32be cropTop;\n\t\t/* +0x24 */ uint32be cropBottom;\n\t\t/* +0x28 */ uint32be cropLeft;\n\t\t/* +0x2C */ uint32be cropRight;\n\n\t\t/* +0x30 */ uint32be ukn30;\n\t\t/* +0x34 */ uint32be ukn34;\n\t\t/* +0x38 */ uint32be ukn38;\n\t\t/* +0x3C */ uint32be ukn3C;\n\t\t/* +0x40 */ uint32be ukn40;\n\n\t\t/* +0x44 */ MEMPTR<uint8> imagePtr;\n\n\t\t/* +0x48 */ uint32 vuiEnable;\n\t\t/* +0x4C */ MPTR   vuiPtr;\n\t\t/* +0x50 */ sint32 unused[10];\n\t};\n\n\tstruct H264OutputCBStruct\n\t{\n\t\tuint32be frameCount;\n\t\tMEMPTR<MEMPTR<H264DECFrameOutput>> resultArray;\n\t\tuint32be userParam;\n\t};\n\n\tstatic_assert(sizeof(H264OutputCBStruct) == 12);\n\n\tvoid H264DoFrameOutputCallback(H264Context* ctx, H264DecoderBackend::DecodeResult& decodeResult)\n\t{\n\t\tsint32 outputFrameCount = 1;\n\n\t\tcemu_assert(outputFrameCount < 8);\n\n\t\tStackAllocator<MEMPTR<void>, 8> stack_resultPtrArray;\n\t\tStackAllocator<H264DECFrameOutput, 8> stack_decodedFrameResult;\n\n\t\tfor (sint32 i = 0; i < outputFrameCount; i++)\n\t\t\tstack_resultPtrArray[i] = &stack_decodedFrameResult + i;\n\n\t\tH264DECFrameOutput* frameOutput = &stack_decodedFrameResult + 0;\n\t\tmemset(frameOutput, 0x00, sizeof(H264DECFrameOutput));\n\t\tframeOutput->imagePtr = (uint8*)decodeResult.imageOutput;\n\t\tframeOutput->result = 100;\n\t\tframeOutput->timestamp = decodeResult.timestamp;\n\t\tframeOutput->frameWidth = decodeResult.frameWidth;\n\t\tframeOutput->frameHeight = decodeResult.frameHeight;\n\t\tframeOutput->bytesPerRow = decodeResult.bytesPerRow;\n\t\tframeOutput->cropEnable = decodeResult.cropEnable;\n\t\tframeOutput->cropTop = decodeResult.cropTop;\n\t\tframeOutput->cropBottom = decodeResult.cropBottom;\n\t\tframeOutput->cropLeft = decodeResult.cropLeft;\n\t\tframeOutput->cropRight = decodeResult.cropRight;\n\n\t\tStackAllocator<H264OutputCBStruct> stack_fptrOutputData;\n\t\tstack_fptrOutputData->frameCount = outputFrameCount;\n\t\tstack_fptrOutputData->resultArray = (MEMPTR<H264DECFrameOutput>*)stack_resultPtrArray.GetPointer();\n\t\tstack_fptrOutputData->userParam = ctx->Param.userMemoryParam.GetBEValue();\n\n\t\t// FPTR callback\n\t\tif (!ctx->Param.outputFunc.IsNull())\n\t\t{\n\t\t\tcemuLog_log(LogType::H264, \"H264: Outputting frame via callback. Timestamp: {} Buffer 0x{:08x} UserParam 0x{:08x}\", (double)decodeResult.timestamp, (uint32)frameOutput->imagePtr.GetMPTR(), ctx->Param.userMemoryParam.GetMPTR());\n\t\t\tPPCCoreCallback(ctx->Param.outputFunc.GetMPTR(), stack_fptrOutputData.GetMPTR());\n\t\t}\n\t}\n\n\tuint32 H264DECExecute(void* workMemory, void* imageOutput)\n\t{\n\t\tBenchmarkTimer bt;\n\t\tbt.Start();\n\t\tH264Context* ctx = (H264Context*)workMemory;\n\t\tH264DecoderBackend* session = _AcquireDecoderSession(ctx->sessionHandle);\n\t\tif (!session)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"H264DECExecute(): Invalid session\");\n\t\t\treturn 0;\n\t\t}\n\t\t// feed data to backend\n\t\tsession->QueueForDecode((uint8*)ctx->BitStream.ptr.GetPtr(), ctx->BitStream.length, ctx->BitStream.timestamp, imageOutput);\n\t\tctx->decoderState.numFramesInFlight++;\n\t\t// H264DECExecute is synchronous and will return a frame after either every call (non-buffered) or after 6 calls (buffered)\n\t\t// normally frame decoding happens only during H264DECExecute, but in order to hide the latency of our CPU decoder we will decode asynchronously in buffered mode\n\t\tuint32 numFramesToBuffer = (ctx->Param.outputPerFrame == 0) ? 5 : 0;\n\t\tif(ctx->decoderState.numFramesInFlight > numFramesToBuffer)\n\t\t{\n\t\t\tctx->decoderState.numFramesInFlight--;\n\t\t\twhile(true)\n\t\t\t{\n\t\t\t\tcoreinit::OSEvent& evt = session->GetFrameOutputEvent();\n\t\t\t\tcoreinit::OSWaitEvent(&evt);\n\t\t\t\tH264DecoderBackend::DecodeResult decodeResult;\n\t\t\t\tif( !session->GetFrameOutputIfReady(decodeResult) )\n\t\t\t\t\tcontinue;\n\t\t\t\tH264DoFrameOutputCallback(ctx, decodeResult);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t_ReleaseDecoderSession(session);\n\t\tbt.Stop();\n\t\tdouble callTime = bt.GetElapsedMilliseconds();\n\t\tcemuLog_log(LogType::H264, \"H264Bench | H264DECExecute took {}ms\", callTime);\n\t\treturn 0x80 | 100;\n\t}\n\n\tH264DEC_STATUS H264DECCheckDecunitLength(void* workMemory, uint8* data, uint32 maxLength, uint32 offset, uint32be* unitLengthOut)\n\t{\n\t\t// todo: our implementation for this currently doesn't parse slice headers and instead assumes that each frame is encoded into a single NAL slice. For all known cases this is sufficient but it doesn't match console behavior for cases where frames are split into multiple NALs\n\t\tif (offset >= maxLength || maxLength < 4)\n\t\t{\n\t\t\treturn H264DEC_STATUS::INVALID_PARAM;\n\t\t}\n\n\t\tdata += offset;\n\t\tmaxLength -= offset;\n\n\t\tNALInputBitstream nalStream(data, maxLength);\n\n\t\tif (nalStream.hasError())\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn H264DEC_STATUS::BAD_STREAM;\n\t\t}\n\n\t\t// search for start code\n\t\tsint32 startCodeOffset = 0;\n\t\tbool hasStartcode = false;\n\t\twhile (startCodeOffset < (sint32)(maxLength - 3))\n\t\t{\n\t\t\tif (data[startCodeOffset + 0] == 0x00 && data[startCodeOffset + 1] == 0x00 && data[startCodeOffset + 2] == 0x01)\n\t\t\t{\n\t\t\t\thasStartcode = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tstartCodeOffset++;\n\t\t}\n\t\tif (hasStartcode == false)\n\t\t\treturn H264DEC_STATUS::BAD_STREAM;\n\t\tdata += startCodeOffset;\n\t\tmaxLength -= startCodeOffset;\n\n\t\t// parse NAL data\n\t\twhile (true)\n\t\t{\n\t\t\tif (nalStream.isEndOfStream())\n\t\t\t\tbreak;\n\t\t\tRBSPInputBitstream rbspStream;\n\t\t\tif (nalStream.getNextRBSP(rbspStream, true) == false)\n\t\t\t\tbreak;\n\n\t\t\tsint32 streamSubOffset = (sint32)(rbspStream.getBasePtr() - data);\n\t\t\tsint32 streamSubLength = rbspStream.getBaseLength();\n\n\t\t\t// parse NAL header\n\t\t\tuint8 nalHeaderByte = rbspStream.readU8();\n\t\t\tif ((nalHeaderByte & 0x80) != 0)\n\t\t\t{\n\t\t\t\t// MSB must be zero\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tuint8 nal_ref_idc = (nalHeaderByte >> 5) & 0x3;\n\t\t\tuint8 nal_unit_type = (nalHeaderByte >> 0) & 0x1f;\n\t\t\tif (nal_unit_type == 14 || nal_unit_type == 20 || nal_unit_type == 21)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tswitch (nal_unit_type)\n\t\t\t{\n\t\t\tcase 1:\n\t\t\tcase 5:\n\t\t\t{\n\t\t\t\t*unitLengthOut = (sint32)((rbspStream.getBasePtr() + rbspStream.getBaseLength()) - data) + startCodeOffset;\n\t\t\t\treturn H264DEC_STATUS::SUCCESS;\n\t\t\t}\n\t\t\tcase 6:\n\t\t\t\t// SEI\n\t\t\t\tbreak;\n\t\t\tcase 7:\n\t\t\t\t// SPS\n\t\t\t\tbreak;\n\t\t\tcase 8:\n\t\t\t\t// PPS\n\t\t\t\tbreak;\n\t\t\tcase 9:\n\t\t\t\t// access unit delimiter\n\t\t\t\tbreak;\n\t\t\tcase 10:\n\t\t\t\t// end of sequence\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported NAL unit type {}\", nal_unit_type);\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t// todo\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn H264DEC_STATUS::BAD_STREAM;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"h264\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"h264\", H264DECCheckMemSegmentation, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECMemoryRequirement, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECFindDecstartpoint, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECFindIdrpoint, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECGetImageSize, LogType::H264);\n\n\t\t\tcafeExportRegister(\"h264\", H264DECInitParam, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECOpen, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECClose, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECBegin, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECEnd, LogType::H264);\n\n\t\t\tcafeExportRegister(\"h264\", H264DECSetParam_FPTR_OUTPUT, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECSetParam_OUTPUT_PER_FRAME, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECSetParam_USER_MEMORY, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECSetParam, LogType::H264);\n\n\t\t\tcafeExportRegister(\"h264\", H264DECSetBitstream, LogType::H264);\n\t\t\tcafeExportRegister(\"h264\", H264DECExecute, LogType::H264);\n\n\t\t\tcafeExportRegister(\"h264\", H264DECCheckDecunitLength, LogType::H264);\n\t\t};\n\t}s_COSh264Module;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSh264Module;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/h264_avc/H264DecBackendAVC.cpp",
    "content": "#include \"H264DecInternal.h\"\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n\nextern \"C\"\n{\n#include \"../dependencies/ih264d/common/ih264_typedefs.h\"\n#include \"../dependencies/ih264d/decoder/ih264d.h\"\n};\n\nnamespace H264\n{\n\tbool H264_IsBotW();\n\n\tclass H264AVCDecoder : public H264DecoderBackend\n\t{\n\t\tstatic void* ivd_aligned_malloc(void* ctxt, WORD32 alignment, WORD32 size)\n\t\t{\n#ifdef _WIN32\n\t\t\treturn _aligned_malloc(size, alignment);\n#else\n\t\t\t// alignment is atleast sizeof(void*)\n\t\t\talignment = std::max<WORD32>(alignment, sizeof(void*));\n\n\t\t\t//smallest multiple of 2 at least as large as alignment\n\t\t\talignment--;\n\t\t\talignment |= alignment << 1;\n\t\t\talignment |= alignment >> 1;\n\t\t\talignment |= alignment >> 2;\n\t\t\talignment |= alignment >> 4;\n\t\t\talignment |= alignment >> 8;\n\t\t\talignment |= alignment >> 16;\n\t\t\talignment ^= (alignment >> 1);\n\n\t\t\tvoid* temp;\n\t\t\tposix_memalign(&temp, (size_t)alignment, (size_t)size);\n\t\t\treturn temp;\n#endif\n\t\t}\n\n\t\tstatic void ivd_aligned_free(void* ctxt, void* buf)\n\t\t{\n#ifdef _WIN32\n\t\t\t_aligned_free(buf);\n#else\n\t\t\tfree(buf);\n#endif\n\t\t}\n\n\t  public:\n\t\tH264AVCDecoder()\n\t\t{\n\t\t\tm_decoderThread = std::thread(&H264AVCDecoder::DecoderThread, this);\n\t\t}\n\n\t\t~H264AVCDecoder()\n\t\t{\n\t\t\tm_threadShouldExit = true;\n\t\t\tm_decodeSem.increment();\n\t\t\tif (m_decoderThread.joinable())\n\t\t\t\tm_decoderThread.join();\n\t\t}\n\n\t\tvoid Init(bool isBufferedMode)\n\t\t{\n\t\t\tih264d_create_ip_t s_create_ip{ 0 };\n\t\t\tih264d_create_op_t s_create_op{ 0 };\n\n\t\t\ts_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ih264d_create_ip_t);\n\t\t\ts_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;\n\t\t\ts_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 1; // shared display buffer mode -> We give the decoder a list of buffers that it will use (?)\n\n\t\t\ts_create_op.s_ivd_create_op_t.u4_size = sizeof(ih264d_create_op_t);\n\t\t\ts_create_ip.s_ivd_create_ip_t.e_output_format = IV_YUV_420SP_UV;\n\t\t\ts_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;\n\t\t\ts_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;\n\t\t\ts_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;\n\n\t\t\tWORD32 status = ih264d_api_function(m_codecCtx, &s_create_ip, &s_create_op);\n\t\t\tcemu_assert(!status);\n\n\t\t\tm_codecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;\n\t\t\tm_codecCtx->pv_fxns = (void*)&ih264d_api_function;\n\t\t\tm_codecCtx->u4_size = sizeof(iv_obj_t);\n\n\t\t\tSetDecoderCoreCount(1);\n\n\t\t\tm_isBufferedMode = isBufferedMode;\n\n\t\t\tUpdateParameters(false);\n\n\t\t\tm_numDecodedFrames = 0;\n\t\t\tm_hasBufferSizeInfo = false;\n\t\t}\n\n\t\tvoid Destroy()\n\t\t{\n\t\t\tif (!m_codecCtx)\n\t\t\t\treturn;\n\t\t\tih264d_delete_ip_t s_delete_ip{ 0 };\n\t\t\tih264d_delete_op_t s_delete_op{ 0 };\n\t\t\ts_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ih264d_delete_ip_t);\n\t\t\ts_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;\n\t\t\ts_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ih264d_delete_op_t);\n\t\t\tWORD32 status = ih264d_api_function(m_codecCtx, &s_delete_ip, &s_delete_op);\n\t\t\tcemu_assert_debug(!status);\n\t\t\tm_codecCtx = nullptr;\n\t\t}\n\n\t\tvoid PushDecodedFrame(ivd_video_decode_op_t& s_dec_op)\n\t\t{\n\t\t\t// copy image data outside of lock since its an expensive operation\n\t\t\tCopyImageToResultBuffer((uint8*)s_dec_op.s_disp_frm_buf.pv_y_buf, (uint8*)s_dec_op.s_disp_frm_buf.pv_u_buf, (uint8*)m_decodedSliceArray[s_dec_op.u4_ts].result.imageOutput, s_dec_op);\n\n\t\t\tstd::unique_lock _l(m_decodeQueueMtx);\n\t\t\tcemu_assert(s_dec_op.u4_ts < m_decodedSliceArray.size());\n\t\t\tauto& result = m_decodedSliceArray[s_dec_op.u4_ts];\n\t\t\tcemu_assert_debug(result.isUsed);\n\t\t\tcemu_assert_debug(s_dec_op.u4_output_present != 0);\n\n\t\t\tresult.result.isDecoded = true;\n\t\t\tresult.result.hasFrame = s_dec_op.u4_output_present != 0;\n\t\t\tresult.result.frameWidth = s_dec_op.u4_pic_wd;\n\t\t\tresult.result.frameHeight = s_dec_op.u4_pic_ht;\n\t\t\tresult.result.bytesPerRow = (s_dec_op.u4_pic_wd + 0xFF) & ~0xFF;\n\t\t\tresult.result.cropEnable = s_dec_op.u1_frame_cropping_flag;\n\t\t\tresult.result.cropTop = s_dec_op.u1_frame_cropping_rect_top_ofst;\n\t\t\tresult.result.cropBottom = s_dec_op.u1_frame_cropping_rect_bottom_ofst;\n\t\t\tresult.result.cropLeft = s_dec_op.u1_frame_cropping_rect_left_ofst;\n\t\t\tresult.result.cropRight = s_dec_op.u1_frame_cropping_rect_right_ofst;\n\n\t\t\tm_displayQueue.push_back(s_dec_op.u4_ts);\n\n\t\t\t_l.unlock();\n\t\t\tcoreinit::OSSignalEvent(m_displayQueueEvt);\n\t\t}\n\n\t\t// called from async worker thread\n\t\tvoid Decode(DecodedSlice& decodedSlice)\n\t\t{\n\t\t\tif (!m_hasBufferSizeInfo)\n\t\t\t{\n\t\t\t\tuint32 numByteConsumed = 0;\n\t\t\t\tif (!DetermineBufferSizes(decodedSlice.dataToDecode.m_data, decodedSlice.dataToDecode.m_length, numByteConsumed))\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"H264AVC: Unable to determine picture size. Ignoring decode input\");\n\t\t\t\t\tstd::unique_lock _l(m_decodeQueueMtx);\n\t\t\t\t\tdecodedSlice.result.isDecoded = true;\n\t\t\t\t\tdecodedSlice.result.hasFrame = false;\n\t\t\t\t\tcoreinit::OSSignalEvent(m_displayQueueEvt);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdecodedSlice.dataToDecode.m_length -= numByteConsumed;\n\t\t\t\tdecodedSlice.dataToDecode.m_data = (uint8*)decodedSlice.dataToDecode.m_data + numByteConsumed;\n\t\t\t\tm_hasBufferSizeInfo = true;\n\t\t\t}\n\n\t\t\tivd_video_decode_ip_t s_dec_ip{ 0 };\n\t\t\tivd_video_decode_op_t s_dec_op{ 0 };\n\t\t\ts_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);\n\t\t\ts_dec_op.u4_size = sizeof(ivd_video_decode_op_t);\n\n\t\t\ts_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;\n\n\t\t\ts_dec_ip.u4_ts = std::distance(m_decodedSliceArray.data(), &decodedSlice);\n\t\t\tcemu_assert_debug(s_dec_ip.u4_ts < m_decodedSliceArray.size());\n\n\t\t\ts_dec_ip.pv_stream_buffer = (uint8*)decodedSlice.dataToDecode.m_data;\n\t\t\ts_dec_ip.u4_num_Bytes = decodedSlice.dataToDecode.m_length;\n\n\t\t\ts_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = 0;\n\t\t\ts_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = 0;\n\t\t\ts_dec_ip.s_out_buffer.u4_num_bufs = 0;\n\n\t\t\tBenchmarkTimer bt;\n\t\t\tbt.Start();\n\t\t\tWORD32 status = ih264d_api_function(m_codecCtx, &s_dec_ip, &s_dec_op);\n\t\t\tif (status != 0 && (s_dec_op.u4_error_code&0xFF) == IVD_RES_CHANGED)\n\t\t\t{\n\t\t\t\t// resolution change\n\t\t\t\tResetDecoder();\n\t\t\t\tm_hasBufferSizeInfo = false;\n\t\t\t\tDecode(decodedSlice);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (status != 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"H264: Failed to decode frame (error 0x{:08x})\", status);\n\t\t\t\tdecodedSlice.result.hasFrame = false;\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbt.Stop();\n\t\t\tdouble decodeTime = bt.GetElapsedMilliseconds();\n\n\t\t\tcemu_assert(s_dec_op.u4_frame_decoded_flag);\n\t\t\tcemu_assert_debug(s_dec_op.u4_num_bytes_consumed == decodedSlice.dataToDecode.m_length);\n\n\t\t\tcemu_assert_debug(m_isBufferedMode || s_dec_op.u4_output_present); // if buffered mode is disabled, then every input should output a frame (except for partial slices?)\n\n\t\t\tif (s_dec_op.u4_output_present)\n\t\t\t{\n\t\t\t\tcemu_assert(s_dec_op.e_output_format == IV_YUV_420SP_UV);\n\t\t\t\tif (H264_IsBotW())\n\t\t\t\t{\n\t\t\t\t\tif (s_dec_op.s_disp_frm_buf.u4_y_wd == 1920 && s_dec_op.s_disp_frm_buf.u4_y_ht == 1088)\n\t\t\t\t\t\ts_dec_op.s_disp_frm_buf.u4_y_ht = 1080;\n\t\t\t\t}\n\t\t\t\tbt.Start();\n\t\t\t\tPushDecodedFrame(s_dec_op);\n\t\t\t\tbt.Stop();\n\t\t\t\tdouble copyTime = bt.GetElapsedMilliseconds();\n\t\t\t\t// release buffer\n\t\t\t\tsint32 bufferId = -1;\n\t\t\t\tfor (size_t i = 0; i < m_displayBuf.size(); i++)\n\t\t\t\t{\n\t\t\t\t\tif (s_dec_op.s_disp_frm_buf.pv_y_buf >= m_displayBuf[i].data() && s_dec_op.s_disp_frm_buf.pv_y_buf < (m_displayBuf[i].data() + m_displayBuf[i].size()))\n\t\t\t\t\t{\n\t\t\t\t\t\tbufferId = (sint32)i;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcemu_assert_debug(bufferId == s_dec_op.u4_disp_buf_id);\n\t\t\t\tcemu_assert(bufferId >= 0);\n\t\t\t\tivd_rel_display_frame_ip_t s_video_rel_disp_ip{ 0 };\n\t\t\t\tivd_rel_display_frame_op_t s_video_rel_disp_op{ 0 };\n\t\t\t\ts_video_rel_disp_ip.e_cmd = IVD_CMD_REL_DISPLAY_FRAME;\n\t\t\t\ts_video_rel_disp_ip.u4_size = sizeof(ivd_rel_display_frame_ip_t);\n\t\t\t\ts_video_rel_disp_op.u4_size = sizeof(ivd_rel_display_frame_op_t);\n\t\t\t\ts_video_rel_disp_ip.u4_disp_buf_id = bufferId;\n\t\t\t\tstatus = ih264d_api_function(m_codecCtx, &s_video_rel_disp_ip, &s_video_rel_disp_op);\n\t\t\t\tcemu_assert(!status);\n\n\t\t\t\tcemuLog_log(LogType::H264, \"H264Bench | DecodeTime {}ms CopyTime {}ms\", decodeTime, copyTime);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::H264, \"H264Bench | DecodeTime {}ms (no frame output)\", decodeTime);\n\t\t\t}\n\n\t\t\tif (s_dec_op.u4_frame_decoded_flag)\n\t\t\t\tm_numDecodedFrames++;\n\t\t\t// get VUI\n\t\t\t//ih264d_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;\n\t\t\t//ih264d_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;\n\n\t\t\t//s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;\n\t\t\t//s_ctl_get_vui_params_ip.e_sub_cmd = (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_GET_VUI_PARAMS;\n\t\t\t//s_ctl_get_vui_params_ip.u4_size = sizeof(ih264d_ctl_get_vui_params_ip_t);\n\t\t\t//s_ctl_get_vui_params_op.u4_size = sizeof(ih264d_ctl_get_vui_params_op_t);\n\n\t\t\t//status = ih264d_api_function(mCodecCtx, &s_ctl_get_vui_params_ip, &s_ctl_get_vui_params_op);\n\t\t\t//cemu_assert(status == 0);\n\t\t}\n\n\t\tvoid Flush()\n\t\t{\n\t\t\t// set flush mode\n\t\t\tivd_ctl_flush_ip_t s_video_flush_ip{ 0 };\n\t\t\tivd_ctl_flush_op_t s_video_flush_op{ 0 };\n\t\t\ts_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;\n\t\t\ts_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;\n\t\t\ts_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);\n\t\t\ts_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);\n\t\t\tWORD32 status = ih264d_api_function(m_codecCtx, &s_video_flush_ip, &s_video_flush_op);\n\t\t\tif (status != 0)\n\t\t\t\tcemuLog_log(LogType::Force, \"H264Dec: Unexpected error during flush ({})\", status);\n\t\t\t// get all frames from the decoder\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tivd_video_decode_ip_t s_dec_ip{ 0 };\n\t\t\t\tivd_video_decode_op_t s_dec_op{ 0 };\n\t\t\t\ts_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);\n\t\t\t\ts_dec_op.u4_size = sizeof(ivd_video_decode_op_t);\n\t\t\t\ts_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;\n\t\t\t\ts_dec_ip.pv_stream_buffer = NULL;\n\t\t\t\ts_dec_ip.u4_num_Bytes = 0;\n\t\t\t\ts_dec_ip.s_out_buffer.u4_min_out_buf_size[0] = 0;\n\t\t\t\ts_dec_ip.s_out_buffer.u4_min_out_buf_size[1] = 0;\n\t\t\t\ts_dec_ip.s_out_buffer.u4_num_bufs = 0;\n\t\t\t\tstatus = ih264d_api_function(m_codecCtx, &s_dec_ip, &s_dec_op);\n\t\t\t\tif (status != 0)\n\t\t\t\t\tbreak;\n\t\t\t\tcemu_assert_debug(s_dec_op.u4_output_present != 0); // should never be false?\n\t\t\t\tif(s_dec_op.u4_output_present == 0)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (H264_IsBotW())\n\t\t\t\t{\n\t\t\t\t\tif (s_dec_op.s_disp_frm_buf.u4_y_wd == 1920 && s_dec_op.s_disp_frm_buf.u4_y_ht == 1088)\n\t\t\t\t\t\ts_dec_op.s_disp_frm_buf.u4_y_ht = 1080;\n\t\t\t\t}\n\t\t\t\tPushDecodedFrame(s_dec_op);\n\t\t\t}\n\t\t}\n\n\t\tvoid CopyImageToResultBuffer(uint8* yIn, uint8* uvIn, uint8* bufOut, ivd_video_decode_op_t& decodeInfo)\n\t\t{\n\t\t\tuint32 imageWidth = decodeInfo.s_disp_frm_buf.u4_y_wd;\n\t\t\tuint32 imageHeight = decodeInfo.s_disp_frm_buf.u4_y_ht;\n\n\t\t\tsize_t inputStride = decodeInfo.s_disp_frm_buf.u4_y_strd;\n\t\t\tsize_t outputStride = (imageWidth + 0xFF) & ~0xFF;\n\n\t\t\t// copy Y\n\t\t\tuint8* yOut = bufOut;\n\t\t\tfor (uint32 row = 0; row < imageHeight; row++)\n\t\t\t{\n\t\t\t\tmemcpy(yOut, yIn, imageWidth);\n\t\t\t\tyIn += inputStride;\n\t\t\t\tyOut += outputStride;\n\t\t\t}\n\n\t\t\t// copy UV\n\t\t\tuint8* uvOut = bufOut + outputStride * imageHeight;\n\t\t\tfor (uint32 row = 0; row < imageHeight/2; row++)\n\t\t\t{\n\t\t\t\tmemcpy(uvOut, uvIn, imageWidth);\n\t\t\t\tuvIn += inputStride;\n\t\t\t\tuvOut += outputStride;\n\t\t\t}\n\t\t}\n\t  private:\n\t\tvoid SetDecoderCoreCount(uint32 coreCount)\n\t\t{\n\t\t\tih264d_ctl_set_num_cores_ip_t s_set_cores_ip;\n\t\t\tih264d_ctl_set_num_cores_op_t s_set_cores_op;\n\t\t\ts_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;\n\t\t\ts_set_cores_ip.e_sub_cmd = (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_SET_NUM_CORES;\n\t\t\ts_set_cores_ip.u4_num_cores = coreCount; // valid numbers are 1-4\n\t\t\ts_set_cores_ip.u4_size = sizeof(ih264d_ctl_set_num_cores_ip_t);\n\t\t\ts_set_cores_op.u4_size = sizeof(ih264d_ctl_set_num_cores_op_t);\n\t\t\tIV_API_CALL_STATUS_T status = ih264d_api_function(m_codecCtx, (void *)&s_set_cores_ip, (void *)&s_set_cores_op);\n\t\t\tcemu_assert(status == IV_SUCCESS);\n\t\t}\n\n\t\tbool DetermineBufferSizes(void* data, uint32 length, uint32& numByteConsumed)\n\t\t{\n\t\t\tnumByteConsumed = 0;\n\t\t\tUpdateParameters(true);\n\n\t\t\tivd_video_decode_ip_t s_dec_ip{ 0 };\n\t\t\tivd_video_decode_op_t s_dec_op{ 0 };\n\t\t\ts_dec_ip.u4_size = sizeof(ivd_video_decode_ip_t);\n\t\t\ts_dec_op.u4_size = sizeof(ivd_video_decode_op_t);\n\n\t\t\ts_dec_ip.e_cmd = IVD_CMD_VIDEO_DECODE;\n\t\t\ts_dec_ip.pv_stream_buffer =\t(uint8*)data;\n\t\t\ts_dec_ip.u4_num_Bytes = length;\n\t\t\ts_dec_ip.s_out_buffer.u4_num_bufs = 0;\n\t\t\tWORD32 status = ih264d_api_function(m_codecCtx, &s_dec_ip, &s_dec_op);\n\t\t\tif (status != 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"H264: Unable to determine buffer sizes for stream\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tnumByteConsumed = s_dec_op.u4_num_bytes_consumed;\n\t\t\tcemu_assert(status == 0);\n\t\t\tif (s_dec_op.u4_pic_wd == 0 || s_dec_op.u4_pic_ht == 0)\n\t\t\t\treturn false;\n\t\t\tUpdateParameters(false);\n\t\t\tReinitBuffers();\n\t\t\treturn true;\n\t\t}\n\n\t\tvoid ReinitBuffers()\n\t\t{\n\t\t\tivd_ctl_getbufinfo_ip_t s_ctl_ip{ 0 };\n\t\t\tivd_ctl_getbufinfo_op_t s_ctl_op{ 0 };\n\t\t\tWORD32 outlen = 0;\n\n\t\t\ts_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;\n\t\t\ts_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETBUFINFO;\n\t\t\ts_ctl_ip.u4_size = sizeof(ivd_ctl_getbufinfo_ip_t);\n\t\t\ts_ctl_op.u4_size = sizeof(ivd_ctl_getbufinfo_op_t);\n\n\t\t\tWORD32 status = ih264d_api_function(m_codecCtx, &s_ctl_ip, &s_ctl_op);\n\t\t\tcemu_assert(!status);\n\n\t\t\t//away with the old.\n\t\t\tm_displayBuf.clear();\n\t\t\t// allocate\n\t\t\tfor (uint32 i = 0; i < s_ctl_op.u4_num_disp_bufs; i++)\n\t\t\t{\n\t\t\t\tm_displayBuf.emplace_back().resize(s_ctl_op.u4_min_out_buf_size[0] + s_ctl_op.u4_min_out_buf_size[1]);\n\t\t\t}\n\t\t\t// set\n\t\t\tivd_set_display_frame_ip_t s_set_display_frame_ip{ 0 }; // make sure to zero-initialize this. The codec seems to check the first 3 pointers/sizes per frame, regardless of the value of u4_num_bufs\n\t\t\tivd_set_display_frame_op_t s_set_display_frame_op{ 0 };\n\n\t\t\ts_set_display_frame_ip.e_cmd = IVD_CMD_SET_DISPLAY_FRAME;\n\t\t\ts_set_display_frame_ip.u4_size = sizeof(ivd_set_display_frame_ip_t);\n\t\t\ts_set_display_frame_op.u4_size = sizeof(ivd_set_display_frame_op_t);\n\n\t\t\tcemu_assert_debug(s_ctl_op.u4_min_num_out_bufs == 2);\n\t\t\tcemu_assert_debug(s_ctl_op.u4_min_out_buf_size[0] != 0 && s_ctl_op.u4_min_out_buf_size[1] != 0);\n\n\t\t\ts_set_display_frame_ip.num_disp_bufs = s_ctl_op.u4_num_disp_bufs;\n\n\t\t\tfor (uint32 i = 0; i < s_ctl_op.u4_num_disp_bufs; i++)\n\t\t\t{\n\t\t\t\ts_set_display_frame_ip.s_disp_buffer[i].u4_num_bufs = 2;\n\t\t\t\ts_set_display_frame_ip.s_disp_buffer[i].u4_min_out_buf_size[0] = s_ctl_op.u4_min_out_buf_size[0];\n\t\t\t\ts_set_display_frame_ip.s_disp_buffer[i].u4_min_out_buf_size[1] = s_ctl_op.u4_min_out_buf_size[1];\n\t\t\t\ts_set_display_frame_ip.s_disp_buffer[i].pu1_bufs[0] = m_displayBuf[i].data() + 0;\n\t\t\t\ts_set_display_frame_ip.s_disp_buffer[i].pu1_bufs[1] = m_displayBuf[i].data() + s_ctl_op.u4_min_out_buf_size[0];\n\t\t\t}\n\n\t\t\tstatus = ih264d_api_function(m_codecCtx, &s_set_display_frame_ip, &s_set_display_frame_op);\n\t\t\tcemu_assert(!status);\n\n\n\t\t\t// mark all as released (available)\n\t\t\tfor (uint32 i = 0; i < s_ctl_op.u4_num_disp_bufs; i++)\n\t\t\t{\n\t\t\t\tivd_rel_display_frame_ip_t s_video_rel_disp_ip{ 0 };\n\t\t\t\tivd_rel_display_frame_op_t s_video_rel_disp_op{ 0 };\n\n\t\t\t\ts_video_rel_disp_ip.e_cmd = IVD_CMD_REL_DISPLAY_FRAME;\n\t\t\t\ts_video_rel_disp_ip.u4_size = sizeof(ivd_rel_display_frame_ip_t);\n\t\t\t\ts_video_rel_disp_op.u4_size = sizeof(ivd_rel_display_frame_op_t);\n\t\t\t\ts_video_rel_disp_ip.u4_disp_buf_id = i;\n\n\t\t\t\tstatus = ih264d_api_function(m_codecCtx, &s_video_rel_disp_ip, &s_video_rel_disp_op);\n\t\t\t\tcemu_assert(!status);\n\t\t\t}\n\t\t}\n\n\t\tvoid ResetDecoder()\n\t\t{\n\t\t\tivd_ctl_reset_ip_t s_ctl_ip;\n\t\t\tivd_ctl_reset_op_t s_ctl_op;\n\n\t\t\ts_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;\n\t\t\ts_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;\n\t\t\ts_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);\n\t\t\ts_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);\n\n\t\t\tWORD32 status = ih264d_api_function(m_codecCtx, (void*)&s_ctl_ip, (void*)&s_ctl_op);\n\t\t\tcemu_assert_debug(status == 0);\n\t\t}\n\n\t\tvoid UpdateParameters(bool headerDecodeOnly)\n\t\t{\n\t\t\tih264d_ctl_set_config_ip_t s_h264d_ctl_ip{ 0 };\n\t\t\tih264d_ctl_set_config_op_t s_h264d_ctl_op{ 0 };\n\t\t\tivd_ctl_set_config_ip_t* ps_ctl_ip = &s_h264d_ctl_ip.s_ivd_ctl_set_config_ip_t;\n\t\t\tivd_ctl_set_config_op_t* ps_ctl_op = &s_h264d_ctl_op.s_ivd_ctl_set_config_op_t;\n\n\t\t\tps_ctl_ip->u4_disp_wd = 0;\n\t\t\tps_ctl_ip->e_frm_skip_mode = IVD_SKIP_NONE;\n\t\t\tps_ctl_ip->e_frm_out_mode = m_isBufferedMode ? IVD_DISPLAY_FRAME_OUT : IVD_DECODE_FRAME_OUT;\n\t\t\tps_ctl_ip->e_vid_dec_mode = headerDecodeOnly ? IVD_DECODE_HEADER : IVD_DECODE_FRAME;\n\t\t\tps_ctl_ip->e_cmd = IVD_CMD_VIDEO_CTL;\n\t\t\tps_ctl_ip->e_sub_cmd = IVD_CMD_CTL_SETPARAMS;\n\t\t\tps_ctl_ip->u4_size = sizeof(ih264d_ctl_set_config_ip_t);\n\t\t\tps_ctl_op->u4_size = sizeof(ih264d_ctl_set_config_op_t);\n\n\t\t\tWORD32 status = ih264d_api_function(m_codecCtx, &s_h264d_ctl_ip, &s_h264d_ctl_op);\n\t\t\tcemu_assert(status == 0);\n\t\t}\n\n\t  private:\n\t\tvoid DecoderThread()\n\t\t{\n\t\t\twhile(!m_threadShouldExit)\n\t\t\t{\n\t\t\t\tm_decodeSem.decrementWithWait();\n\t\t\t\tstd::unique_lock _l(m_decodeQueueMtx);\n\t\t\t\tif (m_decodeQueue.empty())\n\t\t\t\t\tcontinue;\n\t\t\t\tuint32 decodeIndex = m_decodeQueue.front();\n\t\t\t\tm_decodeQueue.erase(m_decodeQueue.begin());\n\t\t\t\t_l.unlock();\n\t\t\t\tif(decodeIndex == CMD_FLUSH)\n\t\t\t\t{\n\t\t\t\t\tFlush();\n\t\t\t\t\t_l.lock();\n\t\t\t\t\tcemu_assert_debug(m_decodeQueue.empty()); // after flushing the queue should be empty since the sender is waiting for the flush to complete\n\t\t\t\t\t_l.unlock();\n\t\t\t\t\tcoreinit::OSSignalEvent(m_flushEvt);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto& decodedSlice = m_decodedSliceArray[decodeIndex];\n\t\t\t\t\tDecode(decodedSlice);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tiv_obj_t* m_codecCtx{nullptr};\n\t\tbool m_hasBufferSizeInfo{ false };\n\t\tbool m_isBufferedMode{ false };\n\t\tuint32 m_numDecodedFrames{0};\n\t\tstd::vector<std::vector<uint8>> m_displayBuf;\n\n\t\tstd::thread m_decoderThread;\n\t\tstd::atomic_bool m_threadShouldExit{false};\n\t};\n\n\tH264DecoderBackend* CreateAVCDecoder()\n\t{\n\t\treturn new H264AVCDecoder();\n\t}\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/h264_avc/H264DecInternal.h",
    "content": "#pragma once\n\n#include \"util/helpers/Semaphore.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_SysHeap.h\"\n\n#include \"Cafe/OS/libs/h264_avc/parser/H264Parser.h\"\n\nnamespace H264\n{\n\tclass H264DecoderBackend\n\t{\n\t  protected:\n\t\tstruct DataToDecode\n\t\t{\n\t\t\tuint8* m_data;\n\t\t\tuint32 m_length;\n\t\t\tstd::vector<uint8> m_buffer;\n\t\t};\n\n\t\tstatic constexpr uint32 CMD_FLUSH = 0xFFFFFFFF;\n\n\t  public:\n\t\tstruct DecodeResult\n\t\t{\n\t\t\tbool isDecoded{false};\n\t\t\tbool hasFrame{false}; // set to true if a full frame was successfully decoded\n\t\t\tdouble timestamp{};\n\t\t\tvoid* imageOutput{nullptr};\n\t\t\tsint32 frameWidth{0};\n\t\t\tsint32 frameHeight{0};\n\t\t\tuint32 bytesPerRow{0};\n\t\t\tbool cropEnable{false};\n\t\t\tsint32 cropTop{0};\n\t\t\tsint32 cropBottom{0};\n\t\t\tsint32 cropLeft{0};\n\t\t\tsint32 cropRight{0};\n\t\t};\n\n\t\tstruct DecodedSlice\n\t\t{\n\t\t\tbool isUsed{false};\n\t\t\tDecodeResult result;\n\t\t\tDataToDecode dataToDecode;\n\t\t};\n\n\t\tH264DecoderBackend()\n\t\t{\n\t\t\tm_displayQueueEvt = (coreinit::OSEvent*)coreinit::OSAllocFromSystem(sizeof(coreinit::OSEvent), 4);\n\t\t\tcoreinit::OSInitEvent(m_displayQueueEvt, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);\n\t\t\tm_flushEvt = (coreinit::OSEvent*)coreinit::OSAllocFromSystem(sizeof(coreinit::OSEvent), 4);\n\t\t\tcoreinit::OSInitEvent(m_flushEvt, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);\n\t\t};\n\n\t\tvirtual ~H264DecoderBackend()\n\t\t{\n\t\t\tcoreinit::OSFreeToSystem(m_displayQueueEvt);\n\t\t\tcoreinit::OSFreeToSystem(m_flushEvt);\n\t\t};\n\n\t\tvirtual void Init(bool isBufferedMode) = 0;\n\t\tvirtual void Destroy() = 0;\n\n\t\tvoid QueueForDecode(uint8* data, uint32 length, double timestamp, void* imagePtr)\n\t\t{\n\t\t\tstd::unique_lock _l(m_decodeQueueMtx);\n\n\t\t\tDecodedSlice& ds = GetFreeDecodedSliceEntry();\n\n\t\t\tds.dataToDecode.m_buffer.assign(data, data + length);\n\t\t\tds.dataToDecode.m_data = ds.dataToDecode.m_buffer.data();\n\t\t\tds.dataToDecode.m_length = length;\n\n\t\t\tds.result.isDecoded = false;\n\t\t\tds.result.imageOutput = imagePtr;\n\t\t\tds.result.timestamp = timestamp;\n\n\t\t\tm_decodeQueue.push_back(std::distance(m_decodedSliceArray.data(), &ds));\n\t\t\tm_decodeSem.increment();\n\t\t}\n\n\t\tvoid QueueFlush()\n\t\t{\n\t\t\tstd::unique_lock _l(m_decodeQueueMtx);\n\t\t\tm_decodeQueue.push_back(CMD_FLUSH);\n\t\t\tm_decodeSem.increment();\n\t\t}\n\n\t\tbool GetFrameOutputIfReady(DecodeResult& result)\n\t\t{\n\t\t\tstd::unique_lock _l(m_decodeQueueMtx);\n\t\t\tif(m_displayQueue.empty())\n\t\t\t\treturn false;\n\t\t\tuint32 sliceIndex = m_displayQueue.front();\n\t\t\tDecodedSlice& ds = m_decodedSliceArray[sliceIndex];\n\t\t\tcemu_assert_debug(ds.result.isDecoded);\n\t\t\tstd::swap(result, ds.result);\n\t\t\tds.isUsed = false;\n\t\t\tm_displayQueue.erase(m_displayQueue.begin());\n\t\t\treturn true;\n\t\t}\n\n\t\tcoreinit::OSEvent& GetFrameOutputEvent()\n\t\t{\n\t\t\treturn *m_displayQueueEvt;\n\t\t}\n\n\t\tcoreinit::OSEvent& GetFlushEvent()\n\t\t{\n\t\t\treturn *m_flushEvt;\n\t\t}\n\n\t  protected:\n\t\tDecodedSlice& GetFreeDecodedSliceEntry()\n\t\t{\n\t\t\tfor (auto& slice : m_decodedSliceArray)\n\t\t\t{\n\t\t\t\tif (!slice.isUsed)\n\t\t\t\t{\n\t\t\t\t\tslice.isUsed = true;\n\t\t\t\t\treturn slice;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcemu_assert_suspicious();\n\t\t\treturn m_decodedSliceArray[0];\n\t\t}\n\n\t\tstd::mutex m_decodeQueueMtx;\n\t\tstd::vector<uint32> m_decodeQueue; // indices into m_decodedSliceArray, in order of decode input\n\t\tCounterSemaphore m_decodeSem;\n\t\tstd::vector<uint32> m_displayQueue; // indices into m_decodedSliceArray, in order of frame display output\n\t\tcoreinit::OSEvent* m_displayQueueEvt; // signalled when a new frame is ready for display\n\t\tcoreinit::OSEvent* m_flushEvt; // signalled after flush operation finished and all queued slices are decoded\n\n\t\t// frame output queue\n\t\tstd::mutex m_frameOutputMtx;\n\t\tstd::array<DecodedSlice, 32> m_decodedSliceArray;\n\t};\n}"
  },
  {
    "path": "src/Cafe/OS/libs/h264_avc/h264dec.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace H264\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/h264_avc/parser/H264Parser.cpp",
    "content": "#include \"Cafe/OS/libs/h264_avc/parser/H264Parser.h\"\n\nvoid parse_hrd_parameters(h264ParserState_t* h264ParserState, RBSPInputBitstream& nalStream)\n{\n\tuint32 cpb_cnt_minus1 = nalStream.readUV_E();\n\tuint8 bit_rate_scale = nalStream.readBits<4>();\n\tuint8 cpb_size_scale = nalStream.readBits<4>();\n\tfor (uint8 schedSelIdx = 0; schedSelIdx <= cpb_cnt_minus1; schedSelIdx++)\n\t{\n\t\tuint32 bit_rate_value_minus1 = nalStream.readUV_E();\n\t\tuint32 cpb_size_value_minus1 = nalStream.readUV_E();\n\t\tuint8 cbr_flag = nalStream.readBit();\n\t}\n\tuint8 initial_cpb_removal_delay_length_minus1 = nalStream.readBits<5>();\n\tuint8 cpb_removal_delay_length_minus1 = nalStream.readBits<5>();\n\tuint8 dpb_output_delay_length_minus1 = nalStream.readBits<5>();\n\tuint8 time_offset_length = nalStream.readBits<5>();\n}\n\nvoid parseNAL_scaling_list4x4(RBSPInputBitstream& rbspStream, h264_scaling_matrix4x4_t& scalingMatrix4x4)\n{\n\tif (rbspStream.readBit() == 0)\n\t{\n\t\tscalingMatrix4x4.isPresent = 0;\n\t\treturn;\n\t}\n\tscalingMatrix4x4.isPresent = 1;\n\n\tcemu_assert_debug(false); // needs testing\n\tsint32 lastScale = 8;\n\tsint32 nextScale = 8;\n\tfor (sint32 j = 0; j < 4 * 4; j++)\n\t{\n\t\tif (nextScale != 0)\n\t\t{\n\t\t\tsint32 delta_scale = rbspStream.readSV_E();\n\t\t\tnextScale = (lastScale + delta_scale + 256) % 256;\n\t\t\tscalingMatrix4x4.UseDefaultScalingMatrix = (j == 0 && nextScale == 0);\n\t\t}\n\t\tscalingMatrix4x4.list[j] = (nextScale == 0) ? lastScale : nextScale;\n\t\tlastScale = scalingMatrix4x4.list[j];\n\t}\n}\n\nvoid parseNAL_scaling_list8x8(RBSPInputBitstream& rbspStream, h264_scaling_matrix8x8_t& scalingMatrix8x8)\n{\n\tif (rbspStream.readBit() == 0)\n\t{\n\t\tscalingMatrix8x8.isPresent = 0;\n\t\treturn;\n\t}\n\tscalingMatrix8x8.isPresent = 1;\n\n\tcemu_assert_debug(false); // needs testing\n\tsint32 lastScale = 8;\n\tsint32 nextScale = 8;\n\tfor (sint32 j = 0; j < 8 * 8; j++)\n\t{\n\t\tif (nextScale != 0)\n\t\t{\n\t\t\tsint32 delta_scale = rbspStream.readSV_E();\n\t\t\tnextScale = (lastScale + delta_scale + 256) % 256;\n\t\t\tscalingMatrix8x8.UseDefaultScalingMatrix = (j == 0 && nextScale == 0);\n\t\t}\n\t\tscalingMatrix8x8.list[j] = (nextScale == 0) ? lastScale : nextScale;\n\t\tlastScale = scalingMatrix8x8.list[j];\n\t}\n}\n\nvoid parseNAL_pps_scaling_lists(h264ParserState_t* h264ParserState, RBSPInputBitstream& nalStream)\n{\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[0]);\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[1]);\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[2]);\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[3]);\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[4]);\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->pps.ScalingList4x4[5]);\n\n\tif (h264ParserState->pps.transform_8x8_mode_flag)\n\t{\n\t\tparseNAL_scaling_list8x8(nalStream, h264ParserState->pps.ScalingList8x8[0]);\n\t\tparseNAL_scaling_list8x8(nalStream, h264ParserState->pps.ScalingList8x8[1]);\n\n\t\tif (h264ParserState->sps.chroma_format_idc == 3)\n\t\t\tcemu_assert(false); // todo - more scaling lists to parse\n\t}\n}\n\nvoid parseNAL_sps_scaling_lists(h264ParserState_t* h264ParserState, RBSPInputBitstream& nalStream)\n{\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[0]);\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[1]);\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[2]);\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[3]);\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[4]);\n\tparseNAL_scaling_list4x4(nalStream, h264ParserState->sps.ScalingList4x4[5]);\n\n\tparseNAL_scaling_list8x8(nalStream, h264ParserState->sps.ScalingList8x8[0]);\n\tparseNAL_scaling_list8x8(nalStream, h264ParserState->sps.ScalingList8x8[1]);\n\n\tif (h264ParserState->sps.chroma_format_idc == 3)\n\t\tcemu_assert(false); // todo - more scaling lists to parse\n}\n\nbool parseNAL_seq_parameter_set_rbsp(h264ParserState_t* h264ParserState, h264ParserOutput_t* output, RBSPInputBitstream& nalStream)\n{\n\tmemset(&h264ParserState->sps, 0, sizeof(h264State_seq_parameter_set_t));\n\n\th264ParserState->sps.profile_idc = nalStream.readU8(); // 0x64 = high profile\n\th264ParserState->sps.constraint = nalStream.readU8(); // 6 flags + 2 reserved bits\n\th264ParserState->sps.level_idc = nalStream.readU8(); // 0x29 = level 4.1\n\n\t// some default values in case flags are not set\n\th264ParserState->sps.separate_colour_plane_flag = 0;\n\th264ParserState->sps.chroma_format_idc = 1; // Spec 7.4.2.1.1\n\th264ParserState->sps.qpprime_y_zero_transform_bypass_flag = 0;\n\th264ParserState->sps.seq_scaling_matrix_present_flag = 0;\n\t//h264ParserState->sps.mb_adaptive_frame_field_flag = 0;\n\n\n\n\tuint32 seq_parameter_set_id = nalStream.readUV_E();\n\tif (h264ParserState->sps.profile_idc == 100 || h264ParserState->sps.profile_idc == 110 || h264ParserState->sps.profile_idc == 122 ||\n\t\th264ParserState->sps.profile_idc == 244 || h264ParserState->sps.profile_idc == 44 || h264ParserState->sps.profile_idc == 83 ||\n\t\th264ParserState->sps.profile_idc == 86 || h264ParserState->sps.profile_idc == 118 || h264ParserState->sps.profile_idc == 128 ||\n\t\th264ParserState->sps.profile_idc == 138 || h264ParserState->sps.profile_idc == 139 || h264ParserState->sps.profile_idc == 134 || h264ParserState->sps.profile_idc == 135)\n\t{\n\t\th264ParserState->sps.chroma_format_idc = nalStream.readUV_E();\n\t\tif (h264ParserState->sps.chroma_format_idc == 3)\n\t\t{\n\t\t\th264ParserState->sps.separate_colour_plane_flag = nalStream.readBit();\n\t\t}\n\t\th264ParserState->sps.bit_depth_luma_minus8 = nalStream.readUV_E();\n\t\th264ParserState->sps.bit_depth_chroma_minus8 = nalStream.readUV_E();\n\t\th264ParserState->sps.qpprime_y_zero_transform_bypass_flag = nalStream.readBit();\n\t\th264ParserState->sps.seq_scaling_matrix_present_flag = nalStream.readBit();\n\t\tif (h264ParserState->sps.seq_scaling_matrix_present_flag)\n\t\t{\n\t\t\tparseNAL_sps_scaling_lists(h264ParserState, nalStream);\n\t\t}\n\t}\n\n\th264ParserState->sps.log2_max_frame_num_minus4 = nalStream.readUV_E();\n\th264ParserState->sps.pic_order_cnt_type = nalStream.readUV_E();\n\tif (h264ParserState->sps.pic_order_cnt_type == 0)\n\t{\n\t\th264ParserState->sps.log2_max_pic_order_cnt_lsb_minus4 = nalStream.readUV_E();\n\t}\n\telse if (h264ParserState->sps.pic_order_cnt_type == 2)\n\t{\n\t\t// nothing to parse\n\t}\n\telse\n\t{\n\t\t// todo - parse fields\n\t\tcemu_assert_debug(false);\n\t}\n\th264ParserState->sps.num_ref_frames = nalStream.readUV_E();\n\th264ParserState->sps.gaps_in_frame_num_value_allowed_flag = nalStream.readBit();\n\th264ParserState->sps.pic_width_in_mbs_minus1 = nalStream.readUV_E();\n\th264ParserState->sps.pic_height_in_map_units_minus1 = nalStream.readUV_E();\n\th264ParserState->sps.frame_mbs_only_flag = nalStream.readBit();\n\tif (h264ParserState->sps.frame_mbs_only_flag == 0)\n\t{\n\t\th264ParserState->sps.mb_adaptive_frame_field_flag = nalStream.readBit();\n\t\tcemu_assert_debug(false);\n\t}\n\telse\n\t\th264ParserState->sps.mb_adaptive_frame_field_flag = 0; // default is zero?\n\n\th264ParserState->sps.direct_8x8_inference_flag = nalStream.readBit();\n\tif (h264ParserState->sps.frame_mbs_only_flag == 0 && h264ParserState->sps.direct_8x8_inference_flag != 1)\n\t{\n\t\tcemu_assert_debug(false); // not allowed\n\t}\n\n\th264ParserState->sps.frame_cropping_flag = nalStream.readBit();\n\tif (h264ParserState->sps.frame_cropping_flag)\n\t{\n\t\th264ParserState->sps.frame_crop_left_offset = nalStream.readUV_E();\n\t\th264ParserState->sps.frame_crop_right_offset = nalStream.readUV_E();\n\t\th264ParserState->sps.frame_crop_top_offset = nalStream.readUV_E();\n\t\th264ParserState->sps.frame_crop_bottom_offset = nalStream.readUV_E();\n\t}\n\tuint8 vui_parameters_present_flag = nalStream.readBit();\n\tif (vui_parameters_present_flag)\n\t{\n\t\t// vui_parameters\n\t\tuint8 aspect_ratio_info_present_flag = nalStream.readBit();\n\t\tif (aspect_ratio_info_present_flag)\n\t\t{\n\t\t\tuint32 aspect_ratio_idc = nalStream.readBits<8>();\n\t\t\tif (aspect_ratio_idc == 255) // Extended_SAR\n\t\t\t{\n\t\t\t\tuint16 sar_width = nalStream.readBits<16>();\n\t\t\t\tuint16 sar_height = nalStream.readBits<16>();\n\t\t\t}\n\t\t}\n\t\tuint8 overscan_info_present_flag = nalStream.readBit();\n\t\tif (overscan_info_present_flag)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\tuint8 video_signal_type_present_flag = nalStream.readBit();\n\t\tif (video_signal_type_present_flag)\n\t\t{\n\t\t\tuint8 video_format = nalStream.readBits<3>();\n\t\t\tuint8 video_full_range_flag = nalStream.readBit();\n\t\t\tuint8 colour_description_present_flag = nalStream.readBit();\n\t\t\tif (colour_description_present_flag)\n\t\t\t{\n\t\t\t\tuint8 colour_primaries = nalStream.readBits<8>();\n\t\t\t\tuint8 transfer_characteristics = nalStream.readBits<8>();\n\t\t\t\tuint8 matrix_coefficients = nalStream.readBits<8>();\n\t\t\t}\n\t\t}\n\t\tuint8 chroma_loc_info_present_flag = nalStream.readBit();\n\t\tif (chroma_loc_info_present_flag)\n\t\t{\n\t\t\tuint32 chroma_sample_loc_type_top_field = nalStream.readUV_E();\n\t\t\tuint32 chroma_sample_loc_type_bottom_field = nalStream.readUV_E();\n\t\t}\n\t\tuint8 timing_info_present_flag = nalStream.readBit();\n\t\tif (timing_info_present_flag)\n\t\t{\n\t\t\tuint32 num_units_in_tick = nalStream.readBits<32>();\n\t\t\tuint32 time_scale = nalStream.readBits<32>();\n\t\t\tuint8 fixed_frame_rate_flag = nalStream.readBits<1>();\n\t\t}\n\t\tuint8 nal_hrd_parameters_present_flag = nalStream.readBit();\n\t\tif (nal_hrd_parameters_present_flag)\n\t\t{\n\t\t\tparse_hrd_parameters(h264ParserState, nalStream);\n\t\t}\n\t\tuint8 vcl_hrd_parameters_present_flag = nalStream.readBit();\n\t\tif (vcl_hrd_parameters_present_flag)\n\t\t{\n\t\t\tparse_hrd_parameters(h264ParserState, nalStream);\n\t\t}\n\t\tif (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag)\n\t\t{\n\t\t\tuint8 low_delay_hrd_flag = nalStream.readBit();\n\t\t}\n\t\tuint8 pic_struct_present_flag = nalStream.readBit();\n\t\tuint8 bitstream_restriction_flag = nalStream.readBit();\n\t\tif (bitstream_restriction_flag)\n\t\t{\n\t\t\tuint8 motion_vectors_over_pic_boundaries_flag = nalStream.readBit();\n\t\t\tuint32 max_bytes_per_pic_denom = nalStream.readUV_E();\n\t\t\tuint32 max_bits_per_mb_denom = nalStream.readUV_E();\n\t\t\tuint32 log2_max_mv_length_horizontal = nalStream.readUV_E();\n\t\t\tuint32 log2_max_mv_length_vertical = nalStream.readUV_E();\n\t\t\tuint32 max_num_reorder_frames = nalStream.readUV_E();\n\t\t\tuint32 max_dec_frame_buffering = nalStream.readUV_E();\n\t\t}\n\t}\n\t// trailing bits\n\tbool nalValid = true;\n\tif (nalStream.readTrailingRBSPBits() == false)\n\t\tnalValid = false;\n\tif (nalValid)\n\t{\n\t\tif(output)\n\t\t\toutput->hasSPS = true;\n\t\th264ParserState->hasSPS = true;\n\t}\n\treturn true;\n}\n\nbool parseNAL_pic_parameter_set_rbsp(h264ParserState_t* h264ParserState, h264ParserOutput_t* output, RBSPInputBitstream& nalStream)\n{\n\tmemset(&h264ParserState->pps, 0, sizeof(h264State_pic_parameter_set_t));\n\n\th264ParserState->pps.pic_parameter_set_id = nalStream.readUV_E();\n\th264ParserState->pps.seq_parameter_set_id = nalStream.readUV_E();\n\th264ParserState->pps.entropy_coding_mode_flag = nalStream.readBit();\n\th264ParserState->pps.bottom_field_pic_order_in_frame_present_flag = nalStream.readBit();\n\n\th264ParserState->pps.num_slice_groups_minus1 = nalStream.readUV_E();\n\tif (h264ParserState->pps.num_slice_groups_minus1 > 0)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn false;\n\t}\n\n\th264ParserState->pps.num_ref_idx_l0_default_active_minus1 = nalStream.readUV_E();\n\th264ParserState->pps.num_ref_idx_l1_default_active_minus1 = nalStream.readUV_E();\n\th264ParserState->pps.weighted_pred_flag = nalStream.readBit();\n\th264ParserState->pps.weighted_bipred_idc = nalStream.readBits<2>();\n\th264ParserState->pps.pic_init_qp_minus26 = nalStream.readSV_E();\n\th264ParserState->pps.pic_init_qs_minus26 = nalStream.readSV_E();\n\th264ParserState->pps.chroma_qp_index_offset = nalStream.readSV_E();\n\n\th264ParserState->pps.deblocking_filter_control_present_flag = nalStream.readBit();\n\th264ParserState->pps.constrained_intra_pred_flag = nalStream.readBit();\n\th264ParserState->pps.redundant_pic_cnt_present_flag = nalStream.readBit();\n\n\tif (nalStream.more_rbsp_data())\n\t{\n\t\th264ParserState->pps.transform_8x8_mode_flag = nalStream.readBit();\n\t\th264ParserState->pps.pic_scaling_matrix_present_flag = nalStream.readBit();\n\t\tif (h264ParserState->pps.pic_scaling_matrix_present_flag)\n\t\t{\n\t\t\tparseNAL_pps_scaling_lists(h264ParserState, nalStream);\n\t\t}\n\t\th264ParserState->pps.second_chroma_qp_index_offset = nalStream.readSV_E();\n\t}\n\n\t// trailing bits\n\tbool nalValid = true;\n\tif (nalStream.readTrailingRBSPBits() == false)\n\t\tnalValid = false;\n\tif (nalValid)\n\t{\n\t\tif(output)\n\t\t\toutput->hasPPS = true;\n\t\th264ParserState->hasPPS = true;\n\t}\n\treturn true;\n}\n\nbool h264Parser_ParseSPS(uint8* data, uint32 length, h264State_seq_parameter_set_t& sps)\n{\n\th264ParserState_t parserState;\n\tRBSPInputBitstream nalStream(data, length);\n\tbool r = parseNAL_seq_parameter_set_rbsp(&parserState, nullptr, nalStream);\n\tif(!r || !parserState.hasSPS)\n\t\treturn false;\n\tsps = parserState.sps;\n\treturn true;\n}\n\nvoid parseNAL_ref_pic_list_modification(const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, RBSPInputBitstream& nalStream, nal_slice_header_t* sliceHeader)\n{\n\tif (!sliceHeader->slice_type.isSliceTypeI() && !sliceHeader->slice_type.isSliceTypeSI())\n\t{\n\t\tuint8 ref_pic_list_modification_flag_l0 = nalStream.readBit();\n\t\tif (ref_pic_list_modification_flag_l0)\n\t\t{\n\t\t\tsliceHeader->pic_list_modification0Count = 0;\n\t\t\tuint32 modType;\n\t\t\twhile(true)\n\t\t\t{\n\t\t\t\tif (sliceHeader->pic_list_modification0Count >= 32)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tmodType = nalStream.readUV_E();\n\t\t\t\tsliceHeader->pic_list_modification0Array[sliceHeader->pic_list_modification0Count].type = modType;\n\t\t\t\tif (modType == 0 || modType == 1)\n\t\t\t\t{\n\t\t\t\t\tsliceHeader->pic_list_modification0Array[sliceHeader->pic_list_modification0Count].abs_diff_pic_num_minus1 = nalStream.readUV_E();\n\t\t\t\t}\n\t\t\t\telse if (modType == 2)\n\t\t\t\t{\n\t\t\t\t\tsliceHeader->pic_list_modification0Array[sliceHeader->pic_list_modification0Count].long_term_pic_num = nalStream.readUV_E();\n\t\t\t\t}\n\t\t\t\telse if (modType == 3)\n\t\t\t\t{\n\t\t\t\t\t// end of list\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(false); // invalid type\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsliceHeader->pic_list_modification0Count++;\n\t\t\t}\n\t\t}\n\t}\n\tif (sliceHeader->slice_type.isSliceTypeB())\n\t{\n\t\tuint8 ref_pic_list_modification_flag_l1 = nalStream.readBit();\n\t\tif (ref_pic_list_modification_flag_l1)\n\t\t{\n\t\t\tcemu_assert_debug(false); // testing required\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tif (sliceHeader->pic_list_modification1Count >= 32)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tuint32 modType = nalStream.readUV_E(); // aka modification_of_pic_nums_idc\n\t\t\t\tsliceHeader->pic_list_modification1Array[sliceHeader->pic_list_modification1Count].type = modType;\n\t\t\t\tif (modType == 0 || modType == 1)\n\t\t\t\t{\n\t\t\t\t\tsliceHeader->pic_list_modification1Array[sliceHeader->pic_list_modification1Count].abs_diff_pic_num_minus1 = nalStream.readUV_E();\n\t\t\t\t}\n\t\t\t\telse if (modType == 2)\n\t\t\t\t{\n\t\t\t\t\tsliceHeader->pic_list_modification1Array[sliceHeader->pic_list_modification1Count].long_term_pic_num = nalStream.readUV_E();\n\t\t\t\t}\n\t\t\t\telse if(modType == 3)\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(false); // invalid mode\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tsliceHeader->pic_list_modification0Count++;\n\t\t\t}\n\t\t\tif (sliceHeader->pic_list_modification1Count > 0)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"sliceHeader->pic_list_modification1Count non-zero is not supported\");\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid parseNAL_dec_ref_pic_marking(const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, RBSPInputBitstream& nalStream, nal_slice_header_t* sliceHeader)\n{\n\tsliceHeader->memory_management_control_operation_num = 0;\n\tif (sliceHeader->IdrPicFlag)\n\t{\n\t\tuint8 no_output_of_prior_pics_flag = nalStream.readBit();\n\t\tif (no_output_of_prior_pics_flag)\n\t\t\tcemu_assert_debug(false);\n\t\tuint8 long_term_reference_flag = nalStream.readBit();\n\t\tif (long_term_reference_flag)\n\t\t\tcemu_assert_debug(false);\n\n\t\tsliceHeader->adaptive_ref_pic_marking_mode_flag = 1;\n\t}\n\telse\n\t{\n\t\tsliceHeader->adaptive_ref_pic_marking_mode_flag = nalStream.readBit();\n\t\tif (sliceHeader->adaptive_ref_pic_marking_mode_flag)\n\t\t{\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tuint32 memory_management_control_operation = nalStream.readUV_E();\n\t\t\t\tif (memory_management_control_operation == nal_slice_header_t::MEMOP_END)\n\t\t\t\t\tbreak;\n\t\t\t\tif (sliceHeader->memory_management_control_operation_num >= 16)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsliceHeader->memory_management_control_operation[sliceHeader->memory_management_control_operation_num].op = memory_management_control_operation;\n\t\t\t\tif (memory_management_control_operation == nal_slice_header_t::MEMOP_REMOVE_REF_FROM_SHORT_TERM || memory_management_control_operation == nal_slice_header_t::MEMOP_MAKE_LONG_TERM_REF)\n\t\t\t\t{\n\t\t\t\t\tsliceHeader->memory_management_control_operation[sliceHeader->memory_management_control_operation_num].difference_of_pic_nums_minus1 = nalStream.readUV_E();\n\t\t\t\t}\n\t\t\t\telse if (memory_management_control_operation == nal_slice_header_t::MEMOP_REMOVE_REF_FROM_LONG_TERM)\n\t\t\t\t{\n\t\t\t\t\tsliceHeader->memory_management_control_operation[sliceHeader->memory_management_control_operation_num].long_term_pic_num = nalStream.readUV_E();\n\t\t\t\t}\n\t\t\t\tif (memory_management_control_operation == nal_slice_header_t::MEMOP_MAKE_LONG_TERM_REF || memory_management_control_operation == nal_slice_header_t::MEMOP_MAKE_CURRENT_LONG_TERM_REF)\n\t\t\t\t{\n\t\t\t\t\tsliceHeader->memory_management_control_operation[sliceHeader->memory_management_control_operation_num].long_term_frame_idx = nalStream.readUV_E();\n\t\t\t\t}\n\t\t\t\tif (memory_management_control_operation == nal_slice_header_t::MEMOP_MAX_LONG_TERM_INDEX)\n\t\t\t\t{\n\t\t\t\t\tsliceHeader->memory_management_control_operation[sliceHeader->memory_management_control_operation_num].max_long_term_frame_idx_plus1 = nalStream.readUV_E();\n\t\t\t\t}\n\t\t\t\tsliceHeader->memory_management_control_operation_num++;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid parseNAL_pred_weight_table(const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, RBSPInputBitstream& nalStream, nal_slice_header_t* sliceHeader)\n{\n\tuint8 luma_log2_weight_denom = nalStream.readUV_E();\n\n\tuint32 ChromaArrayType;\n\tif (sps.separate_colour_plane_flag == 0)\n\t\tChromaArrayType = sps.chroma_format_idc;\n\telse\n\t\tChromaArrayType = 0;\n\n\tif (ChromaArrayType != 0)\n\t{\n\t\tuint32 chroma_log2_weight_denom = nalStream.readUV_E();\n\t}\n\n\tfor (uint32 i = 0; i <= sliceHeader->num_ref_idx_l0_active_minus1; i++)\n\t{\n\t\tuint8 luma_weight_l0_flag = nalStream.readBit();\n\t\tif (luma_weight_l0_flag) \n\t\t{\n\t\t\tuint32 luma_weight_l0 = nalStream.readSV_E();\n\t\t\tuint32 luma_offset_l0 = nalStream.readSV_E();\n\t\t}\n\t\tif (ChromaArrayType != 0)\n\t\t{\n\t\t\tuint8 chroma_weight_l0_flag = nalStream.readBit();\n\t\t\tif (chroma_weight_l0_flag)\n\t\t\t{\n\t\t\t\tfor (sint32 j = 0; j < 2; j++)\n\t\t\t\t{\n\t\t\t\t\tuint32 chroma_weight_l0 = nalStream.readSV_E();\n\t\t\t\t\tuint32 chroma_offset_l0 = nalStream.readSV_E();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif (sliceHeader->slice_type.isSliceTypeB())\n\t{\n\t\tfor (uint32 i = 0; i <= sliceHeader->num_ref_idx_l1_active_minus1; i++)\n\t\t{\n\t\t\tuint8 luma_weight_l1_flag = nalStream.readBit();\n\t\t\tif (luma_weight_l1_flag)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t//luma_weight_l1[i]\n\t\t\t\t//luma_offset_l1[i]\n\t\t\t}\n\t\t\tif (ChromaArrayType != 0)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t//chroma_weight_l1_flag\n\t\t\t\t//if (chroma_weight_l1_flag)\n\t\t\t\t//{\n\t\t\t\t//\tfor (j = 0; j < 2; j++)\n\t\t\t\t//\t{\n\t\t\t\t//\t\tchroma_weight_l1[i][j]\n\t\t\t\t//\t\t\tchroma_offset_l1[i][j]\n\t\t\t\t//\t}\n\t\t\t\t//}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid parseNAL_slice_header(const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, RBSPInputBitstream& nalStream, uint8 nal_unit_type, uint8 nal_ref_idc, nal_slice_header_t* sliceHeader)\n{\n\tbool IdrPicFlag = nal_unit_type == 5;\n\n\tmemset(sliceHeader, 0, sizeof(nal_slice_header_t));\n\tsliceHeader->nal_ref_idc = nal_ref_idc;\n\tsliceHeader->nal_unit_type = nal_unit_type;\n\tsliceHeader->first_mb_in_slice = nalStream.readUV_E(); // address of first macroblock in slice\n\tsliceHeader->slice_type = { nalStream.readUV_E() };\n\tsliceHeader->pic_parameter_set_id = nalStream.readUV_E();\n\n\tif (sps.separate_colour_plane_flag == 1)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\n\tsliceHeader->frame_num = nalStream.readBits(sps.log2_max_frame_num_minus4 + 4);\n\n\tif (sps.frame_mbs_only_flag == 0)\n\t{\n\t\tsliceHeader->field_pic_flag = nalStream.readBit();\n\t\tif (sliceHeader->field_pic_flag)\n\t\t{\n\t\t\tsliceHeader->bottom_field_flag = nalStream.readBit();\n\t\t}\n\t}\n\n\tsliceHeader->IdrPicFlag = IdrPicFlag?1:0;\n\n\tif (IdrPicFlag)\n\t{\n\t\tsliceHeader->idr_pic_id = nalStream.readUV_E();\n\t}\n\tif (sps.pic_order_cnt_type == 0)\n\t{\n\t\tsliceHeader->pic_order_cnt_lsb = nalStream.readBits(sps.log2_max_pic_order_cnt_lsb_minus4 + 4);\n\t\tif (pps.bottom_field_pic_order_in_frame_present_flag && sliceHeader->field_pic_flag == 0)\n\t\t\tsliceHeader->delta_pic_order_cnt_bottom = nalStream.readSV_E();\n\t}\n\telse if (sps.pic_order_cnt_type == 1)\n\t{\n\t\tcemu_assert(false);\n\t}\n\tif (pps.redundant_pic_cnt_present_flag)\n\t{\n\t\tsliceHeader->redundant_pic_cnt = nalStream.readUV_E();\n\t}\n\n\tif (sliceHeader->slice_type.isSliceTypeB())\n\t{\n\t\tsliceHeader->direct_spatial_mv_pred_flag = nalStream.readBit();\n\t}\n\n\tsliceHeader->num_ref_idx_l0_active_minus1 = pps.num_ref_idx_l0_default_active_minus1;\n\tsliceHeader->num_ref_idx_l1_active_minus1 = pps.num_ref_idx_l1_default_active_minus1;\n\n\tif (sliceHeader->slice_type.isSliceTypeP() || sliceHeader->slice_type.isSliceTypeSP() || sliceHeader->slice_type.isSliceTypeB())\n\t{\n\t\tsliceHeader->num_ref_idx_active_override_flag = nalStream.readBit();\n\t\tif (sliceHeader->num_ref_idx_active_override_flag)\n\t\t{\n\t\t\tsliceHeader->num_ref_idx_l0_active_minus1 = nalStream.readUV_E();\n\t\t\tif (sliceHeader->slice_type.isSliceTypeB())\n\t\t\t{\n\t\t\t\tsliceHeader->num_ref_idx_l1_active_minus1 = nalStream.readUV_E();\n\t\t\t}\n\t\t}\n\t}\n\n\t// todo - ref_pic_list_mvc_modification etc\n\tif (nal_unit_type == 20 || nal_unit_type == 21)\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n\telse\n\t{\n\t\tparseNAL_ref_pic_list_modification(sps, pps, nalStream, sliceHeader);\n\t}\n\n\tif ((pps.weighted_pred_flag && (sliceHeader->slice_type.isSliceTypeP() || sliceHeader->slice_type.isSliceTypeSP())) || (pps.weighted_bipred_idc == 1 && sliceHeader->slice_type.isSliceTypeB()))\n\t{\n\t\tparseNAL_pred_weight_table(sps, pps, nalStream, sliceHeader);\n\t}\n\n\tif (sliceHeader->nal_ref_idc != 0)\n\t{\n\t\tparseNAL_dec_ref_pic_marking(sps, pps, nalStream, sliceHeader);\n\t}\n\n\tif (pps.entropy_coding_mode_flag && !sliceHeader->slice_type.isSliceTypeI() && !sliceHeader->slice_type.isSliceTypeSI())\n\t{\n\t\tuint32 cabac_init_idc = nalStream.readUV_E();\n\t\tcemu_assert_debug(cabac_init_idc <= 2); // invalid value\n\t}\n\n\tsint32 slice_qp_delta = nalStream.readSV_E();\n\tif (sliceHeader->slice_type.isSliceTypeSP() || sliceHeader->slice_type.isSliceTypeSI())\n\t{\n\t\tif (sliceHeader->slice_type.isSliceTypeSP())\n\t\t{\n\t\t\tuint8 sp_for_switch_flag = nalStream.readBit();\n\t\t}\n\t\tsint32 slice_qs_delta = nalStream.readSV_E();\n\t}\n\n\tif (pps.deblocking_filter_control_present_flag)\n\t{\n\t\tuint32 disable_deblocking_filter_idc = nalStream.readUV_E();\n\t\tif (disable_deblocking_filter_idc != 1)\n\t\t{\n\t\t\tsint32 slice_alpha_c0_offset_div2 = nalStream.readSV_E();\n\t\t\tsint32 slice_beta_offset_div2 = nalStream.readSV_E();\n\t\t}\n\t}\n\tif (pps.num_slice_groups_minus1 > 0 && pps.slice_group_map_type >= 3 && pps.slice_group_map_type <= 5)\n\t{\n\t\tcemu_assert_debug(false); // todo\n\t}\n}\n\nvoid _calculateFrameOrder(h264ParserState_t* h264ParserState, const h264State_seq_parameter_set_t& sps, const h264State_pic_parameter_set_t& pps, nal_slice_header_t* sliceHeader)\n{\n\tif (sps.pic_order_cnt_type == 0)\n\t{\n\t\t// calculate TopFieldOrderCnt\n\t\tuint32 prevPicOrderCntMsb;\n\t\tuint32 prevPicOrderCntLsb;\n\t\tif (sliceHeader->IdrPicFlag)\n\t\t{\n\t\t\tsliceHeader->calculated.TopFieldOrderCnt = 0;\n\n\t\t\tprevPicOrderCntMsb = 0;\n\t\t\tprevPicOrderCntLsb = 0;\n\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint32 prevRefPic_PicOrderCntMsb = h264ParserState->picture_order.prevPicOrderCntMsb;\n\t\t\tuint32 prevRefPic_pic_order_cnt_lsb = h264ParserState->picture_order.prevPicOrderCntLsb; // todo\n\n\t\t\tprevPicOrderCntMsb = prevRefPic_PicOrderCntMsb;\n\t\t\tprevPicOrderCntLsb = prevRefPic_pic_order_cnt_lsb;\n\n\t\t}\n\n\t\tuint32 MaxPicOrderCntLsb = 1 << (sps.log2_max_pic_order_cnt_lsb_minus4 + 4); // todo - verify\n\n\t\tuint32 PicOrderCntMsb;\n\n\t\tif ((sliceHeader->pic_order_cnt_lsb < prevPicOrderCntLsb) && (((sint32)prevPicOrderCntLsb - (sint32)sliceHeader->pic_order_cnt_lsb) >= (sint32)(MaxPicOrderCntLsb / 2)))\n\t\t\tPicOrderCntMsb = prevPicOrderCntMsb + MaxPicOrderCntLsb;\n\t\telse if ((sliceHeader->pic_order_cnt_lsb > prevPicOrderCntLsb) && (((sint32)sliceHeader->pic_order_cnt_lsb - (sint32)prevPicOrderCntLsb) > (sint32)(MaxPicOrderCntLsb / 2)))\n\t\t\tPicOrderCntMsb = prevPicOrderCntMsb - MaxPicOrderCntLsb;\n\t\telse\n\t\t\tPicOrderCntMsb = prevPicOrderCntMsb;\n\n\t\tuint32 TopFieldOrderCnt = PicOrderCntMsb + sliceHeader->pic_order_cnt_lsb;\n\n\t\tif (sliceHeader->IdrPicFlag != 0 && TopFieldOrderCnt != 0)\n\t\t\tcemu_assert(false);\n\n\t\tsliceHeader->calculated.TopFieldOrderCnt = TopFieldOrderCnt;\n\n\t\th264ParserState->picture_order.prevPicOrderCntMsb = PicOrderCntMsb;\n\t\th264ParserState->picture_order.prevPicOrderCntLsb = sliceHeader->pic_order_cnt_lsb;\n\t}\n\telse if (sps.pic_order_cnt_type == 2)\n\t{\n\t\t// display order matches decode order\n\t\tuint32 prevFrameNum = h264ParserState->picture_order.prevFrameNum;\n\n\t\tuint32 FrameNumOffset;\n\t\tif (sliceHeader->IdrPicFlag)\n\t\t{\n\t\t\tFrameNumOffset = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// todo - check for memory_management_control_operation 5\n\t\t\t// prevFrameNumOffset is set equal to the value of FrameNumOffset of the previous picture in decoding order.\n\t\t\tuint32 prevFrameNumOffset = h264ParserState->picture_order.prevFrameNumOffset;\n\n\t\t\tif (prevFrameNum > sliceHeader->frame_num)\n\t\t\t\tFrameNumOffset = prevFrameNumOffset + sps.getMaxFrameNum();\n\t\t\telse\n\t\t\t\tFrameNumOffset = prevFrameNumOffset;\n\t\t}\n\n\t\tuint32 tempPicOrderCnt;\n\t\tif (sliceHeader->IdrPicFlag == 1)\n\t\t\ttempPicOrderCnt = 0;\n\t\telse if (sliceHeader->nal_ref_idc == 0)\n\t\t\ttempPicOrderCnt = 2 * (FrameNumOffset + sliceHeader->frame_num) - 1;\n\t\telse\n\t\t\ttempPicOrderCnt = 2 * (FrameNumOffset + sliceHeader->frame_num);\n\n\t\tuint32 TopFieldOrderCnt = 0;\n\t\tuint32 BottomFieldOrderCnt = 0;\n\n\t\tif (sliceHeader->field_pic_flag == 0)\n\t\t{\n\t\t\tTopFieldOrderCnt = tempPicOrderCnt;\n\t\t\tBottomFieldOrderCnt = tempPicOrderCnt;\n\t\t}\n\t\telse if (sliceHeader->bottom_field_flag != 0)\n\t\t{\n\t\t\tcemu_assert_debug(false); // fields aren't supported\n\t\t\tBottomFieldOrderCnt = tempPicOrderCnt;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false); // fields aren't supported\n\t\t\tTopFieldOrderCnt = tempPicOrderCnt;\n\t\t}\n\n\t\tsliceHeader->calculated.TopFieldOrderCnt = TopFieldOrderCnt;\n\n\t\th264ParserState->picture_order.prevFrameNum = sliceHeader->frame_num;\n\t\th264ParserState->picture_order.prevFrameNumOffset = FrameNumOffset;\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n}\n\nvoid parseNAL_slice_layer_without_partitioning_rbsp(h264ParserState_t* h264ParserState, h264ParserOutput_t* output, sint32 streamSubOffset, sint32 streamSubLength, RBSPInputBitstream& nalStream, uint8 nal_ref_idc, uint8 nal_unit_type)\n{\n\tnal_slice_t slice = {};\n\tcemu_assert_debug(h264ParserState->hasPPS && h264ParserState->hasSPS);\n\tparseNAL_slice_header(h264ParserState->sps, h264ParserState->pps, nalStream, nal_unit_type, nal_ref_idc, &slice.slice_header);\n\t_calculateFrameOrder(h264ParserState, h264ParserState->sps, h264ParserState->pps, &slice.slice_header);\n\tif (output->sliceCount >= output->sliceInfo.size())\n\t{\n\t\tcemu_assert_debug(false); // internal slice buffer full\n\t\treturn;\n\t}\n\toutput->sliceInfo[output->sliceCount].header = slice.slice_header;\n\toutput->sliceInfo[output->sliceCount].streamSubOffset = streamSubOffset;\n\toutput->sliceInfo[output->sliceCount].streamSubSize = streamSubLength;\n\toutput->sliceCount++;\n}\n\nvoid h264Parse(h264ParserState_t* h264ParserState, h264ParserOutput_t* output, uint8* data, uint32 length, bool parseSlices)\n{\n\tmemset(output, 0, sizeof(h264ParserOutput_t));\n\tNALInputBitstream nalStream(data, length);\n\n\tif (nalStream.hasError())\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\n\t// parse NAL data\n\twhile (true)\n\t{\n\t\tif (nalStream.isEndOfStream())\n\t\t\tbreak;\n\t\tRBSPInputBitstream rbspStream;\n\t\tif (nalStream.getNextRBSP(rbspStream) == false)\n\t\t\tbreak;\n\n\t\tsint32 streamSubOffset = (sint32)(rbspStream.getBasePtr() - data);\n\t\tsint32 streamSubLength = rbspStream.getBaseLength();\n\n\t\t// parse NAL header\n\t\tuint8 nalHeaderByte = rbspStream.readU8();\n\t\tif ((nalHeaderByte & 0x80) != 0)\n\t\t{\n\t\t\t// MSB must be zero\n\t\t\tcemu_assert_debug(false);\n\t\t\tcontinue;\n\t\t}\n\t\tuint8 nal_ref_idc = (nalHeaderByte >> 5) & 0x3;\n\t\tuint8 nal_unit_type = (nalHeaderByte >> 0) & 0x1f;\n\t\t// nal_ref_idc -> If not 0, reference picture. Contains sequence set ??\n\t\t// nal_unit_type -> RBSP type\n\t\t// nal_unit_type:\n\t\t// 0 - unspecified\n\t\t// 1 - Coded slice of a non-IDR picture\tslice_layer_without_partitioning_rbsp()\n\t\t// 2 - Coded slice data partition A slice_data_partition_a_layer_rbsp()\n\t\t// 3 - Coded slice data partition B\tslice_data_partition_b_layer_rbsp()\n\t\t// 4 - Coded slice data partition C\tslice_data_partition_c_layer_rbsp()\n\t\t// 5 - Coded slice of an IDR picture slice_layer_without_partitioning_rbsp()\n\t\t// 6 - Supplemental enhancement information (SEI) sei_rbsp()\n\t\t// 7 - Sequence parameter set seq_parameter_set_rbsp()\n\t\t// 8 - Picture parameter set pic_parameter_set_rbsp()\n\t\t// 9 - Access unit delimiter access_unit_delimiter_rbsp()\n\t\t// 10 - End of sequence end_of_seq_rbsp()\n\t\t// 11 - End of stream end_of_stream_rbsp()\n\t\t// 12 - Filler data\tfiller_data_rbsp()\n\t\t// 13 to 23 - reserved\n\t\t// 24 to 31 - unspecified\n\t\t// VCL NAL -> nal_unit_type 1,2,3,4,5\n\t\t// non-VCL NAL -> All other nal_unit_type values\n\n\t\tif (nal_unit_type == 14 || nal_unit_type == 20 || nal_unit_type == 21)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\t// todo - there are fields to parse here\n\t\t}\n\t\tswitch (nal_unit_type)\n\t\t{\n\t\tcase 1:\n\t\t\tif (parseSlices)\n\t\t\t\tparseNAL_slice_layer_without_partitioning_rbsp(h264ParserState, output, streamSubOffset, streamSubLength, rbspStream, nal_ref_idc, nal_unit_type);\n\t\t\tbreak;\n\t\tcase 5:\n\t\t\tif (parseSlices)\n\t\t\t\tparseNAL_slice_layer_without_partitioning_rbsp(h264ParserState, output, streamSubOffset, streamSubLength, rbspStream, nal_ref_idc, nal_unit_type);\n\t\t\tbreak;\n\t\tcase 6:\n\t\t\t// SEI\n\t\t\tbreak;\n\t\tcase 7:\n\t\t\tcemu_assert_debug(parseNAL_seq_parameter_set_rbsp(h264ParserState, output, rbspStream));\n\t\t\tbreak;\n\t\tcase 8:\n\t\t\tcemu_assert_debug(parseNAL_pic_parameter_set_rbsp(h264ParserState, output, rbspStream));\n\t\t\tbreak;\n\t\tcase 9:\n\t\t\t// access unit delimiter\n\t\t\tbreak;\n\t\tcase 10:\n\t\t\t// end of sequence\n\t\t\tbreak;\n\t\tcase 12:\n\t\t\t// filler data\n\t\t\t// seen in Cocoto Magic Circus 2 intro video\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported NAL unit type {}\", nal_unit_type);\n\t\t\tcemu_assert_debug(false);\n\t\t\t// todo\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nsint32 h264GetUnitLength(h264ParserState_t* h264ParserState, uint8* data, uint32 length)\n{\n\tNALInputBitstream nalStream(data, length);\n\n\tif (nalStream.hasError())\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn -1;\n\t}\n\n\t// search for start code\n\tsint32 startCodeOffset = 0;\n\tbool hasStartcode = false;\n\twhile (startCodeOffset < (sint32)(length - 3))\n\t{\n\t\tif (data[startCodeOffset + 0] == 0x00 && data[startCodeOffset + 1] == 0x00 && data[startCodeOffset + 2] == 0x01)\n\t\t{\n\t\t\thasStartcode = true;\n\t\t\tbreak;\n\t\t}\n\t\tstartCodeOffset++;\n\t}\n\tif (hasStartcode == false)\n\t\treturn -1;\n\tdata += startCodeOffset;\n\tlength -= startCodeOffset;\n\n\t// parse NAL data\n\twhile (true)\n\t{\n\t\tif (nalStream.isEndOfStream())\n\t\t\tbreak;\n\t\tRBSPInputBitstream rbspStream;\n\t\tif (nalStream.getNextRBSP(rbspStream, true) == false)\n\t\t\tbreak;\n\n\t\tsint32 streamSubOffset = (sint32)(rbspStream.getBasePtr() - data);\n\t\tsint32 streamSubLength = rbspStream.getBaseLength();\n\n\t\t// parse NAL header\n\t\tuint8 nalHeaderByte = rbspStream.readU8();\n\t\tif ((nalHeaderByte & 0x80) != 0)\n\t\t{\n\t\t\t// MSB must be zero\n\t\t\tcemu_assert_debug(false);\n\t\t\tcontinue;\n\t\t}\n\t\tuint8 nal_ref_idc = (nalHeaderByte >> 5) & 0x3;\n\t\tuint8 nal_unit_type = (nalHeaderByte >> 0) & 0x1f;\n\t\tif (nal_unit_type == 14 || nal_unit_type == 20 || nal_unit_type == 21)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tcontinue;\n\t\t}\n\t\tswitch (nal_unit_type)\n\t\t{\n\t\tcase 1:\n\t\tcase 5:\n\t\t{\n\t\t\t// note: We cant parse the slice data because we dont have SPS and PPS data reliably available\n\t\t\t// \n\t\t\t// currently we just assume there is 1 slice per unit\n\t\t\treturn (sint32)((rbspStream.getBasePtr() + rbspStream.getBaseLength()) - data) + startCodeOffset;\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tcase 6:\n\t\t\t// SEI\n\t\t\tbreak;\n\t\tcase 7:\n\t\t\tcemu_assert_debug(parseNAL_seq_parameter_set_rbsp(h264ParserState, nullptr, rbspStream));\n\t\t\tbreak;\n\t\tcase 8:\n\t\t\tcemu_assert_debug(parseNAL_pic_parameter_set_rbsp(h264ParserState, nullptr, rbspStream));\n\t\t\tbreak;\n\t\tcase 9:\n\t\t\t// access unit delimiter\n\t\t\tbreak;\n\t\tcase 10:\n\t\t\t// end of sequence\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unsupported NAL unit type {}\", nal_unit_type);\n\t\t\tassert_dbg(); // todo - NAL 10 is used in DKC TF\n\t\t\t// todo\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn -1;\n}\n\nstatic const unsigned char h264_default_4x4_Intra[16] =\n{\n\t6, 13, 13, 20,\n\t20, 20, 28, 28,\n\t28, 28, 32, 32,\n\t32, 37, 37, 42\n};\n\nstatic const unsigned char h264_default_4x4_Inter[16] =\n{\n\t10, 14, 14, 20,\n\t20, 20, 24, 24,\n\t24, 24, 27, 27,\n\t27, 30, 30, 34\n};\n\nstatic const unsigned char h264_default_8x8_Intra[64] =\n{\n\t6, 10, 10, 13, 11, 13, 16, 16,\n\t16, 16, 18, 18, 18, 18, 18, 23,\n\t23, 23, 23, 23, 23, 25, 25, 25,\n\t25, 25, 25, 25, 27, 27, 27, 27,\n\t27, 27, 27, 27, 29, 29, 29, 29,\n\t29, 29, 29, 31, 31, 31, 31, 31,\n\t31, 33, 33, 33, 33, 33, 36, 36,\n\t36, 36, 38, 38, 38, 40, 40, 42\n};\n\nstatic const unsigned char h264_default_8x8_Inter[64] =\n{\n\t9, 13, 13, 15, 13, 15, 17, 17,\n\t17, 17, 19, 19, 19, 19, 19, 21,\n\t21, 21, 21, 21, 21, 22, 22, 22,\n\t22, 22, 22, 22, 24, 24, 24, 24,\n\t24, 24, 24, 24, 25, 25, 25, 25,\n\t25, 25, 25, 27, 27, 27, 27, 27,\n\t27, 28, 28, 28, 28, 28, 30, 30,\n\t30, 30, 32, 32, 32, 33, 33, 35\n};\n\nvoid h264Parser_getScalingMatrix4x4(h264State_seq_parameter_set_t* sps, h264State_pic_parameter_set_t* pps, nal_slice_header_t* sliceHeader, sint32 index, uint8* matrix4x4)\n{\n\t// use scaling lists from PPS first\n\tif (pps->pic_scaling_matrix_present_flag)\n\t{\n\t\tif (pps->ScalingList4x4[index].isPresent)\n\t\t{\n\t\t\tcemu_assert(false); // testing needed (what about UseDefaultScalingMatrix?)\n\t\t\tmemcpy(matrix4x4, pps->ScalingList4x4[index].list, 4 * 4 * sizeof(uint8));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (index < 3)\n\t\t\t\tmemcpy(matrix4x4, h264_default_4x4_Intra, 4 * 4 * sizeof(uint8));\n\t\t\telse\n\t\t\t\tmemcpy(matrix4x4, h264_default_4x4_Inter, 4 * 4 * sizeof(uint8));\n\t\t}\n\t\treturn;\n\t}\n\t// use scaling lists from SPS\n\tif (sps->seq_scaling_matrix_present_flag)\n\t{\n\t\tif (sps->ScalingList4x4[index].isPresent)\n\t\t{\n\t\t\tcemu_assert(false); // testing needed (what about UseDefaultScalingMatrix?)\n\t\t\tmemcpy(matrix4x4, sps->ScalingList4x4[index].list, 4 * 4 * sizeof(uint8));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (index < 3)\n\t\t\t\tmemcpy(matrix4x4, h264_default_4x4_Intra, 4 * 4 * sizeof(uint8));\n\t\t\telse\n\t\t\t\tmemcpy(matrix4x4, h264_default_4x4_Inter, 4 * 4 * sizeof(uint8));\n\t\t}\n\t\treturn;\n\t}\n\t// default (Flat_4x4_16)\n\tmemset(matrix4x4, 16, 4 * 4 * sizeof(uint8));\n}\n\nvoid h264Parser_getScalingMatrix8x8(h264State_seq_parameter_set_t* sps, h264State_pic_parameter_set_t* pps, nal_slice_header_t* sliceHeader, sint32 index, uint8* matrix8x8)\n{\n\t// use scaling lists from PPS first\n\tif (pps->pic_scaling_matrix_present_flag)\n\t{\n\t\tif (pps->ScalingList8x8[index].isPresent)\n\t\t{\n\t\t\tcemu_assert(false); // testing needed (what about UseDefaultScalingMatrix?)\n\t\t\tmemcpy(matrix8x8, pps->ScalingList8x8[index].list, 8 * 8 * sizeof(uint8));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((index&1) == 0)\n\t\t\t\tmemcpy(matrix8x8, h264_default_8x8_Intra, 8 * 8 * sizeof(uint8));\n\t\t\telse\n\t\t\t\tmemcpy(matrix8x8, h264_default_8x8_Inter, 8 * 8 * sizeof(uint8));\n\t\t}\n\t\treturn;\n\t}\n\t// use scaling lists from SPS\n\tif (sps->seq_scaling_matrix_present_flag)\n\t{\n\t\tif (sps->ScalingList8x8[index].isPresent)\n\t\t{\n\t\t\tcemu_assert(false); // testing needed (what about UseDefaultScalingMatrix?)\n\t\t\tmemcpy(matrix8x8, sps->ScalingList8x8[index].list, 8 * 8 * sizeof(uint8));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((index & 1) == 0)\n\t\t\t\tmemcpy(matrix8x8, h264_default_8x8_Intra, 8 * 8 * sizeof(uint8));\n\t\t\telse\n\t\t\t\tmemcpy(matrix8x8, h264_default_8x8_Inter, 8 * 8 * sizeof(uint8));\n\t\t}\n\t\treturn;\n\t}\n\t// default (Flat_8x8_16)\n\tmemset(matrix8x8, 16, 8 * 8 * sizeof(uint8));\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/h264_avc/parser/H264Parser.h",
    "content": "#pragma once\n\n/* stream parsers */\n\nclass RBSPInputBitstream\n{\npublic:\n\tRBSPInputBitstream() {};\n\n\tRBSPInputBitstream(uint8* stream, uint32 length)\n\t{\n\t\tthis->streamPtr = stream;\n\t\tthis->streamLength = length;\n\t\tif (streamLength >= 1)\n\t\t\tcurrentRBSPByte = streamPtr[0];\n\t\telse\n\t\t\tcurrentRBSPByte = 0;\n\t\terrorFlag = false;\n\t}\n\n\tbool hasError() const\n\t{\n\t\treturn errorFlag;\n\t}\n\n\tbool isByteAligned() const\n\t{\n\t\treturn bitIndex == 0;\n\t}\n\n\tuint8 readU8()\n\t{\n\t\tif (readIndex >= streamLength)\n\t\t\treturn 0;\n\t\tcemu_assert_debug(bitIndex == 0);\n\t\tuint8 v = _getCurrentRBSPByte();\n\t\t_nextRBSPByte();\n\t\treturn v;\n\t}\n\n\tuint8 readBit()\n\t{\n\t\tif (readIndex >= streamLength)\n\t\t\treturn 0;\n\t\tuint8 v = _getCurrentRBSPByte();\n\t\tuint8 bitValue = (v >> (7 - bitIndex)) & 1;\n\t\tbitIndex += 1;\n\t\tif (bitIndex >= 8)\n\t\t{\n\t\t\tbitIndex = 0;\n\t\t\t_nextRBSPByte();\n\t\t}\n\t\treturn bitValue;\n\t}\n\n\ttemplate<int N>\n\tuint32 readBits()\n\t{\n\t\tuint32 v = 0;\n\t\tfor (sint32 i = 0; i < N; i++)\n\t\t{\n\t\t\tv <<= 1;\n\t\t\tv |= (readBit() ? 1 : 0);\n\t\t}\n\t\treturn v;\n\t}\n\n\tuint32 readBits(sint32 N)\n\t{\n\t\tuint32 v = 0;\n\t\tfor (sint32 i = 0; i < N; i++)\n\t\t{\n\t\t\tv <<= 1;\n\t\t\tv |= (readBit() ? 1 : 0);\n\t\t}\n\t\treturn v;\n\t}\n\n\tuint32 readUV_E()\n\t{\n\t\tif (readBit() != 0)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\t\tfor (sint32 i = 1; i < 31; i++)\n\t\t{\n\t\t\tuint8 bitValue = readBit();\n\t\t\tif (bitValue)\n\t\t\t{\n\t\t\t\tuint32 rangeBase = (1 << i) - 1;\n\t\t\t\t// read range bits\n\t\t\t\tuint32 suffixBits = 0;\n\t\t\t\tfor (sint32 b = 0; b < i; b++)\n\t\t\t\t{\n\t\t\t\t\tsuffixBits <<= 1;\n\t\t\t\t\tsuffixBits |= (readBit() ? 1 : 0);\n\t\t\t\t}\n\t\t\t\treturn rangeBase + suffixBits;\n\t\t\t}\n\t\t}\n\t\tcemu_assert_debug(false);\n\t\treturn 0;\n\t}\n\n\tsint32 readSV_E()\n\t{\n\t\tuint32 t = readUV_E();\n\t\tif (t == 0)\n\t\t\treturn 0;\n\t\tif ((t & 1) != 0)\n\t\t{\n\t\t\t// positive\n\t\t\treturn (sint32)((t + 1) / 2);\n\t\t}\n\t\t// negative\n\t\treturn -(sint32)((t + 1) / 2);\n\t}\n\n\tbool readTrailingRBSPBits()\n\t{\n\t\t// read the stop bit which must always be 1\n\t\tif (readBit() == 0)\n\t\t\treturn false;\n\t\t// read zero bits until byte aligned\n\t\twhile (bitIndex != 0)\n\t\t{\n\t\t\tif (readBit() != 0)\n\t\t\t\treturn false; // invalid padding bit\n\t\t}\n\t\t// check if we reached end of stream\n\t\tif (readIndex >= streamLength)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\tbool more_rbsp_data()\n\t{\n\t\tuint32 storedReadIndex = readIndex;\n\t\tuint32 storedBitIndex = bitIndex;\n\t\tbool hasMoreRBSPData = readTrailingRBSPBits() == false;\n\t\treadIndex = storedReadIndex;\n\t\tbitIndex = storedBitIndex;\n\t\tcurrentRBSPByte = streamPtr[readIndex];\n\t\treturn hasMoreRBSPData;\n\t}\n\n\tbool isEndOfStream()\n\t{\n\t\treturn readIndex >= streamLength;\n\t}\n\n\n\tuint8* getBasePtr()\n\t{\n\t\treturn streamPtr;\n\t}\n\n\tsint32 getBaseLength()\n\t{\n\t\treturn streamLength;\n\t}\n\nprivate:\n\tuint8 _getCurrentRBSPByte()\n\t{\n\t\treturn currentRBSPByte;\n\t}\n\n\tvoid _nextRBSPByte()\n\t{\n\t\treadIndex += sizeof(uint8);\n\t\tif (readIndex >= 2 && streamPtr[readIndex - 2] == 0x00 && streamPtr[readIndex - 1] == 0x00 && streamPtr[readIndex] == 0x03)\n\t\t{\n\t\t\treadIndex += 1;\n\t\t\tcurrentRBSPByte = streamPtr[readIndex];\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcurrentRBSPByte = streamPtr[readIndex];\n\t\t}\n\t}\n\nprivate:\n\tuint8* streamPtr;\n\tuint32 streamLength;\n\tuint32 readIndex{};\n\tuint8  currentRBSPByte{};\n\tsint32 bitIndex{};\n\tbool errorFlag{};\n};\n\nclass NALInputBitstream\n{\npublic:\n\tNALInputBitstream(uint8* stream, uint32 length)\n\t{\n\t\tthis->nalStreamPtr = stream;\n\t\tthis->nalStreamLength = length;\n\t\terrorFlag = false;\n\t}\n\n\tbool hasError()\n\t{\n\t\treturn errorFlag;\n\t}\n\n\tbool getNextRBSP(RBSPInputBitstream& rbspInputBitstream, bool mustEndAtStartCode = false)\n\t{\n\t\tsint32 indexNextStartSignature = findNextStartSignature();\n\n\t\tif (indexNextStartSignature < 0)\n\t\t{\n\t\t\tif (mustEndAtStartCode)\n\t\t\t\treturn false;\n\t\t\tindexNextStartSignature = nalStreamLength;\n\t\t}\n\t\tif (indexNextStartSignature <= readIndex)\n\t\t\treturn false;\n\t\t// skip current start signature\n\t\tif ((nalStreamLength - readIndex) >= 3 && nalStreamPtr[readIndex + 0] == 0 && nalStreamPtr[readIndex + 1] == 0 && nalStreamPtr[readIndex + 2] == 1)\n\t\t{\n\t\t\treadIndex += 3;\n\t\t}\n\t\telse if ((nalStreamLength - readIndex) >= 3 && nalStreamPtr[readIndex + 0] == 0 && nalStreamPtr[readIndex + 1] == 0 && nalStreamPtr[readIndex + 2] == 0 && nalStreamPtr[readIndex + 3] == 1)\n\t\t{\n\t\t\treadIndex += 4;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// no start signature\n\t\t}\n\t\tcemu_assert(readIndex <= indexNextStartSignature);\n\t\tcemu_assert_debug(readIndex != indexNextStartSignature);\n\t\t// create rbsp substream\n\t\trbspInputBitstream = RBSPInputBitstream(nalStreamPtr + readIndex, indexNextStartSignature - readIndex);\n\t\treadIndex = indexNextStartSignature;\n\t\treturn true;\n\t}\n\n\tbool isEndOfStream()\n\t{\n\t\treturn readIndex >= nalStreamLength;\n\t}\n\nprivate:\n\tsint32 findNextStartSignature()\n\t{\n\t\tif (readIndex >= nalStreamLength)\n\t\t\treturn -1;\n\t\tsint32 offset = readIndex;\n\t\t// if there is a start signature at the current address, skip it\n\t\tif ((offset + 3) <= nalStreamLength && nalStreamPtr[offset + 0] == 0x00 && nalStreamPtr[offset + 1] == 0x00 && nalStreamPtr[offset + 2] == 0x01)\n\t\t{\n\t\t\toffset += 3;\n\t\t}\n\t\telse if ((offset + 4) <= nalStreamLength && nalStreamPtr[offset + 0] == 0x00 && nalStreamPtr[offset + 1] == 0x00 && nalStreamPtr[offset + 2] == 0x00 && nalStreamPtr[offset + 3] == 0x01)\n\t\t{\n\t\t\toffset += 4;\n\t\t}\n\t\twhile (offset < (nalStreamLength - 3))\n\t\t{\n\t\t\tif (nalStreamPtr[offset + 0] == 0x00 && nalStreamPtr[offset + 1] == 0x00)\n\t\t\t{\n\t\t\t\tif (nalStreamPtr[offset + 2] == 0x01)\n\t\t\t\t{\n\t\t\t\t\treturn offset;\n\t\t\t\t}\n\t\t\t\telse if ((nalStreamLength - offset) >= 4 && nalStreamPtr[offset + 2] == 0x00 && nalStreamPtr[offset + 3] == 0x01)\n\t\t\t\t{\n\t\t\t\t\treturn offset;\n\t\t\t\t}\n\t\t\t}\n\t\t\toffset++;\n\t\t}\n\t\treturn -1;\n\t}\n\nprivate:\n\tuint8* nalStreamPtr;\n\tsint32 nalStreamLength;\n\tsint32 readIndex{};\n\tbool errorFlag{};\n};\n\n/* H264 NAL parser */\n\nstruct h264_scaling_matrix4x4_t\n{\n\tuint8 isPresent;\n\tuint8 UseDefaultScalingMatrix;\n\tsint32 list[4*4];\n};\n\nstruct h264_scaling_matrix8x8_t\n{\n\tuint8 isPresent;\n\tuint8 UseDefaultScalingMatrix;\n\tsint32 list[8*8];\n};\n\nstruct h264State_pic_parameter_set_t\n{\n\tuint32 pic_parameter_set_id;\n\tuint32 seq_parameter_set_id;\n\tuint8 entropy_coding_mode_flag;\n\tuint8 bottom_field_pic_order_in_frame_present_flag; // alias pic_order_present_flag\n\tuint32 num_slice_groups_minus1;\n\t// slice group\n\tuint32 slice_group_map_type;\n\t// todo - some variable sized fields\n\n\tuint32 slice_group_change_rate_minus1; // todo\n\n\tuint32 num_ref_idx_l0_default_active_minus1;\n\tuint32 num_ref_idx_l1_default_active_minus1;\n\tuint8 weighted_pred_flag;\n\tuint8 weighted_bipred_idc;\n\tsint32 pic_init_qp_minus26;\n\tsint32 pic_init_qs_minus26;\n\tsint32 chroma_qp_index_offset;\n\n\tuint8 deblocking_filter_control_present_flag;\n\tuint8 constrained_intra_pred_flag;\n\tuint8 redundant_pic_cnt_present_flag;\n\n\tuint8 transform_8x8_mode_flag;\n\tuint8 pic_scaling_matrix_present_flag;\n\th264_scaling_matrix4x4_t ScalingList4x4[6];\n\th264_scaling_matrix8x8_t ScalingList8x8[6];\n\n\tsint32 second_chroma_qp_index_offset;\n};\n\n\nstruct h264State_seq_parameter_set_t\n{\n\tuint8 profile_idc; // 0x64 = high profile\n\tuint8 constraint; // 6 flags + 2 reserved bits\n\tuint8 level_idc; // 0x29 = level 4.1\n\n\tuint32 seq_parameter_set_id;\n\tuint32 chroma_format_idc;\n\n\tuint8 separate_colour_plane_flag; // aka residual_colour_transform_flag\n\n\tuint32 bit_depth_luma_minus8;\n\tuint32 bit_depth_chroma_minus8;\n\tuint8 qpprime_y_zero_transform_bypass_flag;\n\tuint8 seq_scaling_matrix_present_flag;\n\th264_scaling_matrix4x4_t ScalingList4x4[6];\n\th264_scaling_matrix8x8_t ScalingList8x8[6];\n\n\tuint32 log2_max_frame_num_minus4;\n\tuint32 pic_order_cnt_type;\n\n\t// picture order count type 0\n\tuint32 log2_max_pic_order_cnt_lsb_minus4;\n\n\tuint32 num_ref_frames;\n\tuint32 gaps_in_frame_num_value_allowed_flag;\n\tuint32 pic_width_in_mbs_minus1;\n\tuint32 pic_height_in_map_units_minus1;\n\tuint8 frame_mbs_only_flag;\n\tuint8 mb_adaptive_frame_field_flag;\n\n\tuint8 direct_8x8_inference_flag;\n\t\n\tuint8 frame_cropping_flag;\n\tuint32 frame_crop_left_offset;\n\tuint32 frame_crop_right_offset;\n\tuint32 frame_crop_top_offset;\n\tuint32 frame_crop_bottom_offset;\n\n\tuint32 getMaxFrameNum() const\n\t{\n\t\treturn 1<<(log2_max_frame_num_minus4+4);\n\t}\n\n};\n\nstruct H264SliceType\n{\n\tH264SliceType() {};\n\tH264SliceType(uint32 slice_type) : m_sliceType(slice_type) {};\n\n\tbool isSliceTypeP() const { return (this->m_sliceType % 5) == 0; };\n\tbool isSliceTypeB() const { return (this->m_sliceType % 5) == 1; };\n\tbool isSliceTypeI() const { return (this->m_sliceType % 5) == 2; };\n\tbool isSliceTypeSP() const { return (this->m_sliceType % 5) == 3; };\n\tbool isSliceTypeSI() const { return (this->m_sliceType % 5) == 4; };\n\nprivate:\n\tuint32 m_sliceType{};\n};\n\ntypedef struct\n{\n\tuint8 nal_ref_idc;\n\tuint8 nal_unit_type;\n\n\tuint32 first_mb_in_slice;\n\tH264SliceType slice_type;\n\tuint32 pic_parameter_set_id;\n\n\tuint32 frame_num;\n\n\tuint8 field_pic_flag;\n\tuint8 bottom_field_flag;\n\n\tuint32 idr_pic_id;\n\t\n\tuint32 pic_order_cnt_lsb;\n\tsint32 delta_pic_order_cnt_bottom;\n\n\tuint32 redundant_pic_cnt;\n\n\t// slice type B\n\tuint8 direct_spatial_mv_pred_flag;\n\n\t// slice type P, SP, B\n\tuint8 num_ref_idx_active_override_flag;\n\tuint32 num_ref_idx_l0_active_minus1;\n\tuint32 num_ref_idx_l1_active_minus1;\n\n\t// ref_pic_list_modification_flag_l0\n\tstruct  \n\t{\n\t\tuint8 type;\n\t\tuint32 abs_diff_pic_num_minus1;\n\t\tuint32 long_term_pic_num;\n\t}pic_list_modification0Array[32];\n\tsint32 pic_list_modification0Count;\n\n\t// ref_pic_list_modification_flag_l1\n\tstruct  \n\t{\n\t\tuint8 type;\n\t\tuint32 abs_diff_pic_num_minus1;\n\t\tuint32 long_term_pic_num;\n\t}pic_list_modification1Array[32];\n\tsint32 pic_list_modification1Count;\n\n\t// memory_management_control_operation\n\tenum\n\t{\n\t\tMEMOP_END = 0,\n\t\tMEMOP_REMOVE_REF_FROM_SHORT_TERM = 1,\n\t\tMEMOP_REMOVE_REF_FROM_LONG_TERM = 2,\n\t\tMEMOP_MAKE_LONG_TERM_REF = 3,\n\t\tMEMOP_MAX_LONG_TERM_INDEX = 4,\n\t\tMEMOP_REMOVE_ALL_REFS = 5,\n\t\tMEMOP_MAKE_CURRENT_LONG_TERM_REF = 6\n\t};\n\n\tuint8 adaptive_ref_pic_marking_mode_flag;\n\tstruct  \n\t{\n\t\tuint8 op;\n\t\tuint32 difference_of_pic_nums_minus1;\n\t\tuint32 long_term_pic_num;\n\t\tuint32 long_term_frame_idx;\n\t\tuint32 max_long_term_frame_idx_plus1;\n\t}memory_management_control_operation[16];\n\tsint32 memory_management_control_operation_num;\n\n\t// derived values\n\tuint8 IdrPicFlag;\n\n\tstruct  \n\t{\n\t\tuint32 TopFieldOrderCnt;\n\t}calculated;\n}nal_slice_header_t;\n\ntypedef struct\n{\n\tsint32 streamSubOffset;\n\tsint32 streamSubSize;\n\tnal_slice_header_t header;\n}nal_slice_info_t;\n\ntypedef struct  \n{\n\tbool hasSPS;\n\tbool hasPPS;\n\t// list of NAL slices\n\tsint32 sliceCount;\n\tstd::array<nal_slice_info_t, 32> sliceInfo;\n}h264ParserOutput_t;\n\ntypedef struct\n{\n\tnal_slice_header_t slice_header;\n}nal_slice_t;\n\ntypedef struct  \n{\n\t//static const int MAX_SLICES = 32;\n\tbool hasSPS;\n\tbool hasPPS;\n\th264State_seq_parameter_set_t sps;\n\th264State_pic_parameter_set_t pps;\n\tstruct  \n\t{\n\t\tuint32 prevPicOrderCntMsb;\n\t\tuint32 prevPicOrderCntLsb;\n\t\tuint32 prevFrameNum;\n\t\tuint32 prevFrameNumOffset;\n\t}picture_order;\n}h264ParserState_t;\n\nvoid h264Parse(h264ParserState_t* h264ParserState, h264ParserOutput_t* output, uint8* data, uint32 length, bool parseSlices = true);\nsint32 h264GetUnitLength(h264ParserState_t* h264ParserState, uint8* data, uint32 length);\n\nbool h264Parser_ParseSPS(uint8* data, uint32 length, h264State_seq_parameter_set_t& sps);\n\nvoid h264Parser_getScalingMatrix4x4(h264State_seq_parameter_set_t* sps, h264State_pic_parameter_set_t* pps, nal_slice_header_t* sliceHeader, sint32 index, uint8* matrix4x4);\nvoid h264Parser_getScalingMatrix8x8(h264State_seq_parameter_set_t* sps, h264State_pic_parameter_set_t* pps, nal_slice_header_t* sliceHeader, sint32 index, uint8* matrix8x8);\n\nstatic sint32 h264GetFramePitch(sint32 width)\n{\n\treturn (width+0xFF)&~0xFF;\n}\n\nstatic sint32 h264GetFrameSize(sint32 width, sint32 height)\n{\n\tsint32 pitch = h264GetFramePitch(width);\n\treturn height * pitch + (height / 2) * pitch;\n}"
  },
  {
    "path": "src/Cafe/OS/libs/mic/mic.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"input/InputManager.h\"\n#include \"audio/IAudioInputAPI.h\"\n#include \"config/CemuConfig.h\"\n\nenum class MIC_RESULT\n{\n\tSUCCESS\t\t\t=  0,\n\tBAD_PARAM\t\t= -2,\n\tALREADY_OPEN\t= -5,\n\tNOT_OPEN\t\t= -6,\n\tNOT_INITIALIZED\t= -7,\n\tNOT_CONNECTED\t= -8\n};\n\n#define MIC_SAMPLERATE\t\t\t\t32000\n\nconst int MIC_SAMPLES_PER_3MS_32KHZ = (96);  // 32000*3/1000\n\nenum class MIC_STATUS_FLAGS : uint32\n{\n\tFORMAT_PCM16\t= (1 << 0),\n\tIS_OPEN\t\t\t= (1 << 1),\n\tIS_CONNECTED\t= (1 << 2)\n};\nDEFINE_ENUM_FLAG_OPERATORS(MIC_STATUS_FLAGS);\n\n#define MIC_HANDLE_DRC0\t\t\t\t0\n#define MIC_HANDLE_DRC1\t\t\t\t1\n\nenum class MIC_STATEID\n{\n\tSAMPLERATE\t\t\t= 0,\n\tGAIN_DB\t\t\t\t= 1,\n\tGAIN_MIN\t\t\t= 2,\n\tGAIN_MAX\t\t\t= 3,\n\tGAIN_STEP\t\t\t= 4,\n\tMUTE\t\t\t\t= 5,\n\tECHO_CANCELLATION\t= 7,\n\tAUTO_SELECTION\t\t= 8\n};\n\nstruct  \n{\n\tstruct  \n\t{\n\t\tbool isInited;\n\t\tbool isOpen;\n\t\t// ringbuffer information\n\t\tvoid* ringbufferSampleData;\n\t\tuint32 ringbufferSize;\n\t\tuint32 readIndex;\n\t\tuint32 writeIndex;\n\t\t// state\n\t\tuint32 echoCancellation;\n\t\tuint32 autoSelection;\n\t\tuint32 gainDB;\n\t}drc[2];\n}MICStatus = {0};\n\ntypedef struct  \n{\n\tuint32 size;\n\tMPTR samples;\n}micRingbuffer_t;\n\nstruct micStatus_t\n{\n\tbetype<MIC_STATUS_FLAGS> flags;\n\tuint32be numSamplesAvailable;\n\tuint32be readIndex;\n};\n\nstatic_assert(sizeof(micStatus_t) == 0xC);\n\nbool mic_isConnected(uint32 drcIndex)\n{\n\tif( drcIndex != 0 )\n\t\treturn false;\n\n\treturn InputManager::instance().get_vpad_controller(drcIndex) != nullptr;\n}\n\nsint32 mic_availableSamples(uint32 drcIndex)\n{\n\treturn (MICStatus.drc[drcIndex].ringbufferSize+MICStatus.drc[drcIndex].writeIndex-MICStatus.drc[drcIndex].readIndex) % MICStatus.drc[drcIndex].ringbufferSize;\n}\n\nbool mic_isActive(uint32 drcIndex)\n{\n\treturn MICStatus.drc[drcIndex].isOpen;\n}\n\nvoid mic_feedSamples(uint32 drcIndex, sint16* sampleData, sint32 numSamples)\n{\n\tuint16* sampleDataU16 = (uint16*)sampleData;\n\tsint32 ringBufferSize = MICStatus.drc[0].ringbufferSize;\n\tsint32 writeIndex = MICStatus.drc[0].writeIndex;\n\tuint16* ringBufferBase = (uint16*)MICStatus.drc[0].ringbufferSampleData;\n\tdo\n\t{\n\t\tringBufferBase[writeIndex] = _swapEndianU16(*sampleDataU16);\n\t\tsampleDataU16++;\n\t\twriteIndex++;\n\t\twriteIndex %= ringBufferSize;\n\t}while( (--numSamples) > 0 );\n\tMICStatus.drc[0].writeIndex = writeIndex;\n}\n\nvoid micExport_MICInit(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"MICInit(%d,%d,0x%08x,0x%08x)\\n\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\tuint32 drcIndex = hCPU->gpr[3];\n\tif( drcIndex > 1 || (drcIndex == 0 && mic_isConnected(drcIndex) == false) )\n\t{\n\t\tmemory_writeU32(hCPU->gpr[6], (uint32)MIC_RESULT::NOT_CONNECTED);\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\tif( drcIndex != 0 )\n\t{\n\t\t// DRC1 microphone is not supported (only DRC0)\n\t\tmemory_writeU32(hCPU->gpr[6], (uint32)MIC_RESULT::NOT_CONNECTED);\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\tif( MICStatus.drc[drcIndex].isInited )\n\t{\n\t\tmemory_writeU32(hCPU->gpr[6], (uint32)MIC_RESULT::ALREADY_OPEN);\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\tmicRingbuffer_t* micRingbuffer = (micRingbuffer_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[5]);\n\tMICStatus.drc[drcIndex].ringbufferSampleData = memory_getPointerFromVirtualOffset(_swapEndianU32(micRingbuffer->samples));\n\tMICStatus.drc[drcIndex].ringbufferSize = _swapEndianU32(micRingbuffer->size);\n\tMICStatus.drc[drcIndex].readIndex = 0;\n\tMICStatus.drc[drcIndex].writeIndex = 0;\n\tMICStatus.drc[drcIndex].isInited = true;\n\t// init default states\n\tMICStatus.drc[drcIndex].echoCancellation = 1; // guessed\n\tMICStatus.drc[drcIndex].autoSelection = 1; // guessed\n\t// return status\n\tmemory_writeU32(hCPU->gpr[6], 0); // no error\n\tosLib_returnFromFunction(hCPU, (drcIndex==0)?MIC_HANDLE_DRC0:MIC_HANDLE_DRC1); // success\n\n\tauto& config = GetConfig();\n\tconst auto audio_api = IAudioInputAPI::Cubeb; // change this if more input apis get implemented\n\n\tstd::unique_lock lock(g_audioInputMutex);\n\tif (!g_inputAudio)\n\t{\n\t\tIAudioInputAPI::DeviceDescriptionPtr device_description;\n\t\tif (IAudioInputAPI::IsAudioInputAPIAvailable(audio_api))\n\t\t{\n\t\t\tauto devices = IAudioInputAPI::GetDevices(audio_api);\n\t\t\tconst auto it = std::find_if(devices.begin(), devices.end(), [&config](const auto& d) {return d->GetIdentifier() == config.input_device; });\n\t\t\tif (it != devices.end())\n\t\t\t\tdevice_description = *it;\n\t\t}\n\n\t\tif (device_description)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tg_inputAudio = IAudioInputAPI::CreateDevice(audio_api, device_description, MIC_SAMPLERATE, 1, MIC_SAMPLES_PER_3MS_32KHZ, 16);\n\t\t\t\tg_inputAudio->SetVolume(config.input_volume);\n\t\t\t}\n\t\t\tcatch (std::runtime_error& ex)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"can't initialize audio input: {}\", ex.what());\n\t\t\t\texit(0);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid micExport_MICOpen(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"MICOpen(%d)\\n\", hCPU->gpr[3]);\n\tuint32 micHandle = hCPU->gpr[3];\n\tif( micHandle != MIC_HANDLE_DRC0 && micHandle != MIC_HANDLE_DRC1 )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::BAD_PARAM);\n\t\treturn;\n\t}\n\tuint32 drcIndex = (micHandle==MIC_HANDLE_DRC0)?0:1;\n\tif( MICStatus.drc[drcIndex].isInited == false )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::NOT_INITIALIZED);\n\t\treturn;\n\t}\n\t// check if already open\n\tif( MICStatus.drc[drcIndex].isOpen )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::ALREADY_OPEN);\n\t\treturn;\n\t}\n\t// check if DRC is connected\n\tbool hasDRCConnected = InputManager::instance().get_vpad_controller(drcIndex) != nullptr;\n\tif( hasDRCConnected == false )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::NOT_CONNECTED);\n\t\treturn;\n\t}\n\t// success\n\tMICStatus.drc[drcIndex].isOpen = true;\n\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::SUCCESS);\n\n\tstd::shared_lock lock(g_audioInputMutex);\n\tif(g_inputAudio)\n\t\tg_inputAudio->Play();\n}\n\nvoid micExport_MICClose(PPCInterpreter_t* hCPU)\n{\n\t// debug_printf(\"MICClose(%d)\\n\", hCPU->gpr[3]);\n\tuint32 micHandle = hCPU->gpr[3];\n\tif( micHandle != MIC_HANDLE_DRC0 && micHandle != MIC_HANDLE_DRC1 )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::BAD_PARAM);\n\t\treturn;\n\t}\n\tuint32 drcIndex = (micHandle==MIC_HANDLE_DRC0)?0:1;\n\tif( MICStatus.drc[drcIndex].isInited == false )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::NOT_INITIALIZED);\n\t\treturn;\n\t}\n\t// check if already closed\n\tif( MICStatus.drc[drcIndex].isOpen == false )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::ALREADY_OPEN);\n\t\treturn;\n\t}\n\t// success\n\tMICStatus.drc[drcIndex].isOpen = false;\n\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::SUCCESS);\n\n\tstd::shared_lock lock(g_audioInputMutex);\n\tif (g_inputAudio)\n\t\tg_inputAudio->Stop();\n}\n\nvoid micExport_MICGetStatus(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"MICGetStatus(%d,0x%08x)\\n\", hCPU->gpr[3], hCPU->gpr[4]);\n\tuint32 micHandle = hCPU->gpr[3];\n\tif( micHandle != MIC_HANDLE_DRC0 && micHandle != MIC_HANDLE_DRC1 )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::BAD_PARAM);\n\t\treturn;\n\t}\n\tuint32 drcIndex = (micHandle==MIC_HANDLE_DRC0)?0:1;\n\tif( MICStatus.drc[drcIndex].isInited == false )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::NOT_INITIALIZED);\n\t\treturn;\n\t}\n\tmicStatus_t* micStatus = (micStatus_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\tMIC_STATUS_FLAGS micFlags = MIC_STATUS_FLAGS::FORMAT_PCM16;\n\tif( mic_isConnected(drcIndex) )\n\t\tmicFlags |= MIC_STATUS_FLAGS::IS_CONNECTED;\n\tif( MICStatus.drc[drcIndex].isOpen )\n\t\tmicFlags |= MIC_STATUS_FLAGS::IS_OPEN;\n\tmicStatus->flags = micFlags;\n\tmicStatus->numSamplesAvailable = mic_availableSamples(drcIndex);\n\tmicStatus->readIndex = MICStatus.drc[drcIndex].readIndex;\n\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::SUCCESS);\n}\n\nvoid micExport_MICGetState(PPCInterpreter_t* hCPU)\n{\n\t// debug_printf(\"MICGetState(%d,%d,0x%08x)\\n\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\t// parameters:\n\t// r3\tuint32\t\tmicHandle\n\t// r4\tuint32\t\tstateId\n\t// r5\tuint32*\t\tvalue\n\tuint32 micHandle = hCPU->gpr[3];\n\tif( micHandle != MIC_HANDLE_DRC0 && micHandle != MIC_HANDLE_DRC1 )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::BAD_PARAM);\n\t\treturn;\n\t}\n\tuint32 drcIndex = (micHandle==MIC_HANDLE_DRC0)?0:1;\n\tif( MICStatus.drc[drcIndex].isInited == false )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::NOT_INITIALIZED);\n\t\treturn;\n\t}\n\t// get state\n\tMIC_STATEID stateId = (MIC_STATEID)hCPU->gpr[4];\n\tif (stateId == MIC_STATEID::SAMPLERATE)\n\t{\n\t\tmemory_writeU32(hCPU->gpr[5], MIC_SAMPLERATE);\n\t}\n\telse if (stateId == MIC_STATEID::AUTO_SELECTION)\n\t{\n\t\tmemory_writeU32(hCPU->gpr[5], MICStatus.drc[drcIndex].autoSelection);\n\t}\n\telse if (stateId == MIC_STATEID::GAIN_MIN)\n\t{\n\t\t// value guessed\n\t\tmemory_writeU32(hCPU->gpr[5], 0x0000); // S7.8\n\t}\n\telse if (stateId == MIC_STATEID::GAIN_MAX)\n\t{\n\t\t// value guessed\n\t\tmemory_writeU32(hCPU->gpr[5], 0x0200); // S7.8\n\t}\n\telse if (stateId == MIC_STATEID::GAIN_STEP)\n\t{\n\t\t// value guessed\n\t\tmemory_writeU32(hCPU->gpr[5], 0x0001); // S7.8\n\t}\n\telse if (stateId == MIC_STATEID::ECHO_CANCELLATION)\n\t{\n\t\tmemory_writeU32(hCPU->gpr[5], MICStatus.drc[drcIndex].echoCancellation);\n\t}\n\telse if (stateId == MIC_STATEID::GAIN_DB)\n\t{\n\t\t// value guessed\n\t\tmemory_writeU32(hCPU->gpr[5], MICStatus.drc[drcIndex].gainDB); // S7.8\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::SUCCESS);\n\treturn;\n}\n\nvoid micExport_MICSetState(PPCInterpreter_t* hCPU)\n{\n\tuint32 micHandle = hCPU->gpr[3];\n\tif( micHandle != MIC_HANDLE_DRC0 && micHandle != MIC_HANDLE_DRC1 )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::BAD_PARAM);\n\t\treturn;\n\t}\n\tuint32 drcIndex = (micHandle==MIC_HANDLE_DRC0)?0:1;\n\tif( MICStatus.drc[drcIndex].isInited == false )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::NOT_INITIALIZED);\n\t\treturn;\n\t}\n\t// set state\n\tMIC_STATEID stateId = (MIC_STATEID)hCPU->gpr[4];\n\tuint32 newValue = hCPU->gpr[5];\n\tif( stateId == MIC_STATEID::ECHO_CANCELLATION )\n\t{\n\t\tMICStatus.drc[drcIndex].echoCancellation = (newValue!=0)?1:0;\n\t}\n\telse if( stateId == MIC_STATEID::AUTO_SELECTION )\n\t{\n\t\tMICStatus.drc[drcIndex].autoSelection = (newValue!=0)?1:0;\n\t}\n\telse if( stateId == MIC_STATEID::GAIN_DB )\n\t{\n\t\tMICStatus.drc[drcIndex].gainDB = newValue;\n\t}\n\telse\n\t\tassert_dbg();\n\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::SUCCESS);\n\treturn;\n}\n\nvoid micExport_MICSetDataConsumed(PPCInterpreter_t* hCPU)\n{\n\t// debug_printf(\"MICSetDataConsumed(%d,%d)\\n\", hCPU->gpr[3], hCPU->gpr[4]);\n\t// parameters:\n\t// r3\tuint32\t\tmicHandle\n\t// r4\tuint32\t\tnumConsumedSamples\n\tuint32 micHandle = hCPU->gpr[3];\n\tif( micHandle != MIC_HANDLE_DRC0 && micHandle != MIC_HANDLE_DRC1 )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::BAD_PARAM);\n\t\treturn;\n\t}\n\tuint32 drcIndex = (micHandle==MIC_HANDLE_DRC0)?0:1;\n\tif( MICStatus.drc[drcIndex].isInited == false )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::NOT_INITIALIZED);\n\t\treturn;\n\t}\n\tif( MICStatus.drc[drcIndex].isOpen == false )\n\t{\n\t\tosLib_returnFromFunction(hCPU, (uint32)MIC_RESULT::NOT_OPEN);\n\t\treturn;\n\t}\n\tsint32 numConsumedSamples = (sint32)hCPU->gpr[4];\n\t//debug_printf(\"MIC consume samples 0x%04x\\n\", numConsumedSamples);\n\tif( mic_availableSamples(drcIndex) < numConsumedSamples )\n\t{\n\t\tMICStatus.drc[drcIndex].readIndex = MICStatus.drc[drcIndex].writeIndex;\n\t\tosLib_returnFromFunction(hCPU, -81);\n\t}\n\telse\n\t{\n\t\tMICStatus.drc[drcIndex].readIndex += numConsumedSamples;\n\t\tMICStatus.drc[drcIndex].readIndex %= MICStatus.drc[drcIndex].ringbufferSize;\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\treturn;\n}\n\nvoid mic_updateDevicePlayState(bool isPlaying)\n{\n\tif (g_inputAudio)\n\t{\n\t\tif (isPlaying)\n\t\t\tg_inputAudio->Play();\n\t\telse\n\t\t\tg_inputAudio->Stop();\n\t}\n}\n\nvoid mic_updateOnAXFrame()\n{\n\tsint32 drcIndex = 0;\n\tif( mic_isActive(0) == false ) \n\t{\n\t\tdrcIndex = 1;\n\t\tif (mic_isActive(1) == false) \n\t\t{\n\t\t\tstd::shared_lock lock(g_audioInputMutex);\n\t\t\tmic_updateDevicePlayState(false);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tstd::shared_lock lock(g_audioInputMutex);\n\tmic_updateDevicePlayState(true);\n\tif (g_inputAudio)\n\t{\n\t\tsint16 micSampleData[MIC_SAMPLES_PER_3MS_32KHZ];\n\t\tg_inputAudio->ConsumeBlock(micSampleData);\n\t\tmic_feedSamples(0, micSampleData, MIC_SAMPLES_PER_3MS_32KHZ);\n\t}\n\telse\n\t{\n\t\tconst sint32 micSampleCount = 32000 / 32;\n\t\tsint16 micSampleData[micSampleCount];\n\n\t\tauto controller = InputManager::instance().get_vpad_controller(drcIndex);\n\t\tif( controller && controller->is_mic_active() )\n\t\t{\n\t\t\tfor(sint32 i=0; i<micSampleCount; i++)\n\t\t\t{\n\t\t\t\tmicSampleData[i] = (sint16)(sin((float)GetTickCount()*0.1f+sin((float)GetTickCount()*0.0001f)*100.0f)*30000.0f);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmemset(micSampleData, 0x00, sizeof(micSampleData));\n\t\t}\n\t\tmic_feedSamples(0, micSampleData, micSampleCount);\n\t}\n}\n\nnamespace mic\n{\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"mic\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"mic\", \"MICInit\", micExport_MICInit);\n\t\t\tosLib_addFunction(\"mic\", \"MICOpen\", micExport_MICOpen);\n\t\t\tosLib_addFunction(\"mic\", \"MICClose\", micExport_MICClose);\n\t\t\tosLib_addFunction(\"mic\", \"MICGetStatus\", micExport_MICGetStatus);\n\t\t\tosLib_addFunction(\"mic\", \"MICGetState\", micExport_MICGetState);\n\t\t\tosLib_addFunction(\"mic\", \"MICSetState\", micExport_MICSetState);\n\t\t\tosLib_addFunction(\"mic\", \"MICSetDataConsumed\", micExport_MICSetDataConsumed);\n\t\t}\n\t}s_COSmicModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSmicModule;\n\t}\n\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/mic/mic.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nbool mic_isActive(uint32 drcIndex);\nvoid mic_updateOnAXFrame();\n\nnamespace mic\n{\n\tCOSModule* GetModule();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/nfc/TLV.cpp",
    "content": "#include \"TLV.h\"\n#include \"stream.h\"\n\n#include <cassert>\n\nTLV::TLV()\n{\n}\n\nTLV::TLV(Tag tag, std::vector<std::byte> value)\n : mTag(tag), mValue(std::move(value))\n{\n}\n\nTLV::~TLV()\n{\n}\n\nstd::vector<TLV> TLV::FromBytes(const std::span<std::byte>& data)\n{\n\tbool hasTerminator = false;\n\tstd::vector<TLV> tlvs;\n\tSpanStream stream(data, std::endian::big);\n\n\twhile (stream.GetRemaining() > 0 && !hasTerminator)\n\t{\n\t\t// Read the tag\n\t\tuint8 byte;\n\t\tstream >> byte;\n\t\tTag tag = static_cast<Tag>(byte);\n\n\t\tswitch (tag)\n\t\t{\n\t\t\tcase TLV::TAG_NULL:\n\t\t\t\t// Don't need to do anything for NULL tags\n\t\t\t\tbreak;\n\t\t\t\n\t\t\tcase TLV::TAG_TERMINATOR:\n\t\t\t\ttlvs.emplace_back(tag, std::vector<std::byte>{});\n\t\t\t\thasTerminator = true;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\t// Read the length\n\t\t\t\tuint16 length;\n\t\t\t\tstream >> byte;\n\t\t\t\tlength = byte;\n\n\t\t\t\t// If the length is 0xff, 2 bytes with length follow\n\t\t\t\tif (length == 0xff) {\n\t\t\t\t\tstream >> length;\n\t\t\t\t}\n\n\t\t\t\tstd::vector<std::byte> value;\n\t\t\t\tvalue.resize(length);\n\t\t\t\tstream.Read(value);\n\n\t\t\t\ttlvs.emplace_back(tag, value);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (stream.GetError() != Stream::ERROR_OK)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Error: TLV parsing read past end of stream\");\n\t\t\t// Clear tlvs to prevent further havoc while parsing ndef data\n\t\t\ttlvs.clear();\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// This seems to be okay, at least NTAGs don't add a terminator tag\n\t// if (!hasTerminator)\n\t// {\n\t//     cemuLog_log(LogType::Force, \"Warning: TLV parsing reached end of stream without terminator tag\");\n\t// }\n\n\treturn tlvs;\n}\n\nstd::vector<std::byte> TLV::ToBytes() const\n{\n\tstd::vector<std::byte> bytes;\n\tVectorStream stream(bytes, std::endian::big);\n\n\t// Write tag\n\tstream << uint8(mTag);\n\n\tswitch (mTag)\n\t{\n\t\tcase TLV::TAG_NULL:\n\t\tcase TLV::TAG_TERMINATOR:\n\t\t\t// Nothing to do here\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t{\n\t\t\t// Write length (decide if as a 8-bit or 16-bit value)\n\t\t\tif (mValue.size() >= 0xff)\n\t\t\t{\n\t\t\t\tstream << uint8(0xff);\n\t\t\t\tstream << uint16(mValue.size());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstream << uint8(mValue.size());\n\t\t\t}\n\n\t\t\t// Write value\n\t\t\tstream.Write(mValue);\n\t\t}\n\t}\n\n\treturn bytes;\n}\n\nTLV::Tag TLV::GetTag() const\n{\n\treturn mTag;\n}\n\nconst std::vector<std::byte>& TLV::GetValue() const\n{\n\treturn mValue;\n}\n\nvoid TLV::SetTag(Tag tag)\n{\n\tmTag = tag;\n}\n\nvoid TLV::SetValue(const std::span<const std::byte>& value)\n{\n\t// Can only write max 16-bit lengths into TLV\n\tcemu_assert(value.size() < 0x10000);\n\n\tmValue.assign(value.begin(), value.end());\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nfc/TLV.h",
    "content": "#pragma once\n\n#include <cstdint>\n#include <span>\n#include <vector>\n\nclass TLV\n{\npublic:\n\tenum Tag\n\t{\n\t\tTAG_NULL        = 0x00,\n\t\tTAG_LOCK_CTRL   = 0x01,\n\t\tTAG_MEM_CTRL    = 0x02,\n\t\tTAG_NDEF        = 0x03,\n\t\tTAG_PROPRIETARY = 0xFD,\n\t\tTAG_TERMINATOR  = 0xFE,\n\t};\n\npublic:\n\tTLV();\n\tTLV(Tag tag, std::vector<std::byte> value);\n\tvirtual ~TLV();\n\n\tstatic std::vector<TLV> FromBytes(const std::span<std::byte>& data);\n\tstd::vector<std::byte> ToBytes() const;\n\n\tTag GetTag() const;\n\tconst std::vector<std::byte>& GetValue() const;\n\n\tvoid SetTag(Tag tag);\n\tvoid SetValue(const std::span<const std::byte>& value);\n\nprivate:\n\tTag mTag;\n\tstd::vector<std::byte> mValue;\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/nfc/TagV0.cpp",
    "content": "#include \"TagV0.h\"\n#include \"TLV.h\"\n\n#include <algorithm>\n\nnamespace\n{\n\nconstexpr std::size_t kTagSize = 512u;\nconstexpr std::size_t kMaxBlockCount = kTagSize / sizeof(TagV0::Block);\n\nconstexpr uint8 kLockbyteBlock0 = 0xe;\nconstexpr uint8 kLockbytesStart0 = 0x0;\nconstexpr uint8 kLockbytesEnd0 = 0x2;\nconstexpr uint8 kLockbyteBlock1 = 0xf;\nconstexpr uint8 kLockbytesStart1 = 0x2;\nconstexpr uint8 kLockbytesEnd1 = 0x8;\n\nconstexpr uint8 kNDEFMagicNumber = 0xe1;\n\n// These blocks are not part of the locked area\nconstexpr bool IsBlockLockedOrReserved(uint8 blockIdx)\n{\n\t// Block 0 is the UID\n\tif (blockIdx == 0x0)\n\t{\n\t\treturn true;\n\t}\n\n\t// Block 0xd is reserved\n\tif (blockIdx == 0xd)\n\t{\n\t\treturn true;\n\t}\n\n\t// Block 0xe and 0xf contains lock / reserved bytes\n\tif (blockIdx == 0xe || blockIdx == 0xf)\n\t{\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n} // namespace\n\nTagV0::TagV0()\n{\n}\n\nTagV0::~TagV0()\n{\n}\n\nstd::shared_ptr<TagV0> TagV0::FromBytes(const std::span<const std::byte>& data)\n{\n\t// Version 0 tags need at least 512 bytes\n\tif (data.size() != kTagSize)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error: Version 0 tags should be {} bytes in size\", kTagSize);\n\t\treturn {};\n\t}\n\n\tstd::shared_ptr<TagV0> tag = std::make_shared<TagV0>();\n\n\t// Parse the locked area before continuing\n\tif (!tag->ParseLockedArea(data))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error: Failed to parse locked area\");\n\t\treturn {};\n\t}\n\n\t// Now that the locked area is known, parse the data area\n\tstd::vector<std::byte> dataArea;\n\tif (!tag->ParseDataArea(data, dataArea))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error: Failed to parse data area\");\n\t\treturn {};\n\t}\n\n\t// The first few bytes in the dataArea make up the capability container\n\tstd::copy_n(dataArea.begin(), tag->mCapabilityContainer.size(), std::as_writable_bytes(std::span(tag->mCapabilityContainer)).begin());\n\tif (!tag->ValidateCapabilityContainer())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error: Failed to validate capability container\");\n\t\treturn {};\n\t}\n\n\t// The rest of the dataArea contains the TLVs\n\ttag->mTLVs = TLV::FromBytes(std::span(dataArea).subspan(tag->mCapabilityContainer.size()));\n\tif (tag->mTLVs.empty())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error: Tag contains no TLVs\");\n\t\treturn {};\n\t}\n\n\t// Look for the NDEF tlv\n\ttag->mNdefTlvIdx = static_cast<size_t>(-1);\n\tfor (std::size_t i = 0; i < tag->mTLVs.size(); i++)\n\t{\n\t\tif (tag->mTLVs[i].GetTag() == TLV::TAG_NDEF)\n\t\t{\n\t\t\ttag->mNdefTlvIdx = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (tag->mNdefTlvIdx == static_cast<size_t>(-1))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error: Tag contains no NDEF TLV\");\n\t\treturn {};\n\t}\n\n\t// Append locked data\n\tfor (const auto& [key, value] : tag->mLockedBlocks)\n\t{\n\t\ttag->mLockedArea.insert(tag->mLockedArea.end(), value.begin(), value.end());\n\t}\n\n\treturn tag;\n}\n\nstd::vector<std::byte> TagV0::ToBytes() const\n{\n\tstd::vector<std::byte> bytes(kTagSize);\n\n\t// Insert locked or reserved blocks\n\tfor (const auto& [key, value] : mLockedOrReservedBlocks)\n\t{\n\t\tstd::copy(value.begin(), value.end(), bytes.begin() + key * sizeof(Block));\n\t}\n\n\t// Insert locked area\n\tauto lockedDataIterator = mLockedArea.begin();\n\tfor (const auto& [key, value] : mLockedBlocks)\n\t{\n\t\tstd::copy_n(lockedDataIterator, sizeof(Block), bytes.begin() + key * sizeof(Block));\n\t\tlockedDataIterator += sizeof(Block);\n\t}\n\n\t// Pack the dataArea into a linear buffer\n\tstd::vector<std::byte> dataArea;\n\tconst auto ccBytes = std::as_bytes(std::span(mCapabilityContainer));\n\tdataArea.insert(dataArea.end(), ccBytes.begin(), ccBytes.end());\n\tfor (const TLV& tlv : mTLVs)\n\t{\n\t\tconst auto tlvBytes = tlv.ToBytes();\n\t\tdataArea.insert(dataArea.end(), tlvBytes.begin(), tlvBytes.end());\n\t}\n\n\t// Make sure the dataArea is block size aligned\n\tdataArea.resize((dataArea.size() + (sizeof(Block)-1)) & ~(sizeof(Block)-1));\n\n\t// The rest will be the data area\n\tauto dataIterator = dataArea.begin();\n\tfor (uint8 currentBlock = 0; currentBlock < kMaxBlockCount; currentBlock++)\n\t{\n\t\t// All blocks which aren't locked make up the dataArea\n\t\tif (!IsBlockLocked(currentBlock))\n\t\t{\n\t\t\tstd::copy_n(dataIterator, sizeof(Block), bytes.begin() + currentBlock * sizeof(Block));\n\t\t\tdataIterator += sizeof(Block);\n\t\t}\n\t}\n\n\treturn bytes;\n}\n\nconst TagV0::Block& TagV0::GetUIDBlock() const\n{\n\treturn mLockedOrReservedBlocks.at(0);\n}\n\nconst std::vector<std::byte>& TagV0::GetNDEFData() const\n{\n\treturn mTLVs[mNdefTlvIdx].GetValue();\n}\n\nconst std::vector<std::byte>& TagV0::GetLockedArea() const\n{\n\treturn mLockedArea;\n}\n\nvoid TagV0::SetNDEFData(const std::span<const std::byte>& data)\n{\n\t// Update the ndef value\n\tmTLVs[mNdefTlvIdx].SetValue(data);\n}\n\nbool TagV0::ParseLockedArea(const std::span<const std::byte>& data)\n{\n\tuint8 currentBlock = 0;\n\n\t// Start by parsing the first set of lock bytes\n\tfor (uint8 i = kLockbytesStart0; i < kLockbytesEnd0; i++)\n\t{\n\t\tuint8 lockByte = uint8(data[kLockbyteBlock0 * sizeof(Block) + i]);\n\n\t\t// Iterate over the individual bits in the lock byte\n\t\tfor (uint8 j = 0; j < 8; j++)\n\t\t{\n\t\t\t// Is block locked?\n\t\t\tif (lockByte & (1u << j))\n\t\t\t{\n\t\t\t\tBlock blk;\n\t\t\t\tstd::copy_n(data.begin() + currentBlock * sizeof(Block), sizeof(Block), blk.begin());\n\n\t\t\t\t// The lock bytes themselves are not part of the locked area\n\t\t\t\tif (!IsBlockLockedOrReserved(currentBlock))\n\t\t\t\t{\n\t\t\t\t\tmLockedBlocks.emplace(currentBlock, blk);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmLockedOrReservedBlocks.emplace(currentBlock, blk);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcurrentBlock++;\n\t\t}\n\t}\n\n\t// Parse the second set of lock bytes\n\tfor (uint8 i = kLockbytesStart1; i < kLockbytesEnd1; i++) {\n\t\tuint8 lockByte = uint8(data[kLockbyteBlock1 * sizeof(Block) + i]);\n\n\t\t// Iterate over the individual bits in the lock byte\n\t\tfor (uint8 j = 0; j < 8; j++)\n\t\t{\n\t\t\t// Is block locked?\n\t\t\tif (lockByte & (1u << j))\n\t\t\t{\n\t\t\t\tBlock blk;\n\t\t\t\tstd::copy_n(data.begin() + currentBlock * sizeof(Block), sizeof(Block), blk.begin());\n\n\t\t\t\t// The lock bytes themselves are not part of the locked area\n\t\t\t\tif (!IsBlockLockedOrReserved(currentBlock))\n\t\t\t\t{\n\t\t\t\t\tmLockedBlocks.emplace(currentBlock, blk);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmLockedOrReservedBlocks.emplace(currentBlock, blk);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcurrentBlock++;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nbool TagV0::IsBlockLocked(uint8 blockIdx) const\n{\n\treturn mLockedBlocks.contains(blockIdx) || IsBlockLockedOrReserved(blockIdx);\n}\n\nbool TagV0::ParseDataArea(const std::span<const std::byte>& data, std::vector<std::byte>& dataArea)\n{\n\tfor (uint8 currentBlock = 0; currentBlock < kMaxBlockCount; currentBlock++)\n\t{\n\t\t// All blocks which aren't locked make up the dataArea\n\t\tif (!IsBlockLocked(currentBlock))\n\t\t{\n\t\t\tauto blockOffset = data.begin() + sizeof(Block) * currentBlock;\n\t\t\tdataArea.insert(dataArea.end(), blockOffset, blockOffset + sizeof(Block));\n\t\t}\n\t}\n\n\treturn true;\n}\n\nbool TagV0::ValidateCapabilityContainer()\n{\n\t// NDEF Magic Number\n\tuint8 nmn = mCapabilityContainer[0];\n\tif (nmn != kNDEFMagicNumber)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error: CC: Invalid NDEF Magic Number\");\n\t\treturn false;\n\t}\n\n\t// Version Number\n\tuint8 vno = mCapabilityContainer[1];\n\tif (vno >> 4 != 1)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error: CC: Invalid Version Number\");\n\t\treturn false;\n\t}\n\n\t// Tag memory size\n\tuint8 tms = mCapabilityContainer[2];\n\tif (8u * (tms + 1) < kTagSize)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error: CC: Incomplete tag memory size\");\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nfc/TagV0.h",
    "content": "#pragma once\n\n#include <memory>\n#include <span>\n#include <map>\n\n#include \"TLV.h\"\n\nclass TagV0\n{\npublic:\n\tusing Block = std::array<std::byte, 0x8>;\n\npublic:\n\tTagV0();\n\tvirtual ~TagV0();\n\n\tstatic std::shared_ptr<TagV0> FromBytes(const std::span<const std::byte>& data);\n\tstd::vector<std::byte> ToBytes() const;\n\n\tconst Block& GetUIDBlock() const;\n\tconst std::vector<std::byte>& GetNDEFData() const;\n\tconst std::vector<std::byte>& GetLockedArea() const;\n\n\tvoid SetNDEFData(const std::span<const std::byte>& data);\n\nprivate:\n\tbool ParseLockedArea(const std::span<const std::byte>& data);\n\tbool IsBlockLocked(uint8 blockIdx) const;\n\tbool ParseDataArea(const std::span<const std::byte>& data, std::vector<std::byte>& dataArea);\n\tbool ValidateCapabilityContainer();\n\n\tstd::map<uint8, Block> mLockedOrReservedBlocks;\n\tstd::map<uint8, Block> mLockedBlocks;\n\tstd::array<uint8, 0x4> mCapabilityContainer;\n\tstd::vector<TLV> mTLVs;\n\tstd::size_t mNdefTlvIdx;\n\tstd::vector<std::byte> mLockedArea;\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/nfc/ndef.cpp",
    "content": "#include \"ndef.h\"\n\n#include <cassert>\n\nnamespace ndef\n{\n\n\tRecord::Record()\n\t : mFlags(0), mTNF(NDEF_TNF_EMPTY)\n\t{\n\t}\n\n\tRecord::~Record()\n\t{\n\t}\n\n\tstd::optional<Record> Record::FromStream(Stream& stream)\n\t{\n\t\tRecord rec;\n\n\t\t// Read record header\n\t\tuint8 recHdr;\n\t\tstream >> recHdr;\n\t\trec.mFlags = recHdr & ~NDEF_TNF_MASK;\n\t\trec.mTNF = static_cast<TypeNameFormat>(recHdr & NDEF_TNF_MASK);\n\n\t\t// Type length\n\t\tuint8 typeLen;\n\t\tstream >> typeLen;\n\n\t\t// Payload length;\n\t\tuint32 payloadLen;\n\t\tif (recHdr & NDEF_SR)\n\t\t{\n\t\t\tuint8 len;\n\t\t\tstream >> len;\n\t\t\tpayloadLen = len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstream >> payloadLen;\n\t\t}\n\n\t\t// Some sane limits for the payload size\n\t\tif (payloadLen > 2 * 1024 * 1024)\n\t\t{\n\t\t\treturn {};\n\t\t}\n\n\t\t// ID length\n\t\tuint8 idLen = 0;\n\t\tif (recHdr & NDEF_IL)\n\t\t{\n\t\t\tstream >> idLen;\n\t\t}\n\n\t\t// Make sure we didn't read past the end of the stream yet\n\t\tif (stream.GetError() != Stream::ERROR_OK)\n\t\t{\n\t\t\treturn {};\n\t\t}\n\n\t\t// Type\n\t\trec.mType.resize(typeLen);\n\t\tstream.Read(rec.mType);\n\n\t\t// ID\n\t\trec.mID.resize(idLen);\n\t\tstream.Read(rec.mID);\n\n\t\t// Payload\n\t\trec.mPayload.resize(payloadLen);\n\t\tstream.Read(rec.mPayload);\n\n\t\t// Make sure we didn't read past the end of the stream again\n\t\tif (stream.GetError() != Stream::ERROR_OK)\n\t\t{\n\t\t\treturn {};\n\t\t}\n\n\t\treturn rec;\n\t}\n\n\tstd::vector<std::byte> Record::ToBytes(uint8 flags) const\n\t{\n\t\tstd::vector<std::byte> bytes;\n\t\tVectorStream stream(bytes, std::endian::big);\n\n\t\t// Combine flags (clear message begin and end flags)\n\t\tuint8 finalFlags = mFlags & ~(NDEF_MB | NDEF_ME);\n\t\tfinalFlags |= flags;\n\n\t\t// Write flags + tnf\n\t\tstream << uint8(finalFlags | uint8(mTNF));\n\n\t\t// Type length\n\t\tstream << uint8(mType.size());\n\n\t\t// Payload length\n\t\tif (IsShort())\n\t\t{\n\t\t\tstream << uint8(mPayload.size());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstream << uint32(mPayload.size());\n\t\t}\n\n\t\t// ID length\n\t\tif (mFlags & NDEF_IL)\n\t\t{\n\t\t\tstream << uint8(mID.size());\n\t\t}\n\n\t\t// Type\n\t\tstream.Write(mType);\n\n\t\t// ID\n\t\tstream.Write(mID);\n\n\t\t// Payload\n\t\tstream.Write(mPayload);\n\n\t\treturn bytes;\n\t}\n\n\tRecord::TypeNameFormat Record::GetTNF() const\n\t{\n\t\treturn mTNF;\n\t}\n\n\tconst std::vector<std::byte>& Record::GetID() const\n\t{\n\t\treturn mID;\n\t}\n\n\tconst std::vector<std::byte>& Record::GetType() const\n\t{\n\t\treturn mType;\n\t}\n\n\tconst std::vector<std::byte>& Record::GetPayload() const\n\t{\n\t\treturn mPayload;\n\t}\n\n\tvoid Record::SetTNF(TypeNameFormat tnf)\n\t{\n\t\tmTNF = tnf;\n\t}\n\n\tvoid Record::SetID(const std::span<const std::byte>& id)\n\t{\n\t\tcemu_assert(id.size() < 0x100);\n\n\t\tif (id.size() > 0)\n\t\t{\n\t\t\tmFlags |= NDEF_IL;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmFlags &= ~NDEF_IL;\n\t\t}\n\n\t\tmID.assign(id.begin(), id.end());\n\t}\n\n\tvoid Record::SetType(const std::span<const std::byte>& type)\n\t{\n\t\tcemu_assert(type.size() < 0x100);\n\n\t\tmType.assign(type.begin(), type.end());\n\t}\n\n\tvoid Record::SetPayload(const std::span<const std::byte>& payload)\n\t{\n\t\t// Update short record flag\n\t\tif (payload.size() < 0xff)\n\t\t{\n\t\t\tmFlags |= NDEF_SR;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmFlags &= ~NDEF_SR;\n\t\t}\n\n\t\tmPayload.assign(payload.begin(), payload.end());\n\t}\n\n\tbool Record::IsLast() const\n\t{\n\t\treturn mFlags & NDEF_ME;\n\t}\n\n\tbool Record::IsShort() const\n\t{\n\t\treturn mFlags & NDEF_SR;\n\t}\n\n\tMessage::Message()\n\t{\n\t}\n\n\tMessage::~Message()\n\t{\n\t}\n\n\tstd::optional<Message> Message::FromBytes(const std::span<const std::byte>& data)\n\t{\n\t\tMessage msg;\n\t\tSpanStream stream(data, std::endian::big);\n\n\t\twhile (stream.GetRemaining() > 0)\n\t\t{\n\t\t\tstd::optional<Record> rec = Record::FromStream(stream);\n\t\t\tif (!rec)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Warning: Failed to parse NDEF Record #{}.\"\n\t\t\t\t\t\t\t\"Ignoring the remaining {} bytes in NDEF message\", msg.mRecords.size(), stream.GetRemaining());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tmsg.mRecords.emplace_back(*rec);\n\n\t\t\tif ((*rec).IsLast() && stream.GetRemaining() > 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Warning: Ignoring {} bytes in NDEF message\", stream.GetRemaining());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (msg.mRecords.empty())\n\t\t{\n\t\t\treturn {};\n\t\t}\n\n\t\tif (!msg.mRecords.back().IsLast())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Error: NDEF message missing end record\");\n\t\t\treturn {}; \n\t\t}\n\n\t\treturn msg;\n\t}\n\n\tstd::vector<std::byte> Message::ToBytes() const\n\t{\n\t\tstd::vector<std::byte> bytes;\n\n\t\tfor (std::size_t i = 0; i < mRecords.size(); i++)\n\t\t{\n\t\t\tuint8 flags = 0;\n\n\t\t\t// Add message begin flag to first record\n\t\t\tif (i == 0)\n\t\t\t{\n\t\t\t\tflags |= Record::NDEF_MB;\n\t\t\t}\n\n\t\t\t// Add message end flag to last record\n\t\t\tif (i == mRecords.size() - 1)\n\t\t\t{\n\t\t\t\tflags |= Record::NDEF_ME;\n\t\t\t}\n\n\t\t\tstd::vector<std::byte> recordBytes = mRecords[i].ToBytes(flags);\n\t\t\tbytes.insert(bytes.end(), recordBytes.begin(), recordBytes.end());\n\t\t}\n\n\t\treturn bytes;\n\t}\n\n\tvoid Message::append(const Record& r)\n\t{\n\t\tmRecords.push_back(r);\n\t}\n\n} // namespace ndef\n"
  },
  {
    "path": "src/Cafe/OS/libs/nfc/ndef.h",
    "content": "#pragma once\n\n#include <span>\n#include <vector>\n#include <optional>\n\n#include \"stream.h\"\n\nnamespace ndef\n{\n\n\tclass Record\n\t{\n\tpublic:\n\t\tenum HeaderFlag\n\t\t{\n\t\t\tNDEF_IL         = 0x08,\n\t\t\tNDEF_SR         = 0x10,\n\t\t\tNDEF_CF         = 0x20,\n\t\t\tNDEF_ME         = 0x40,\n\t\t\tNDEF_MB         = 0x80,\n\t\t\tNDEF_TNF_MASK   = 0x07,\n\t\t};\n\n\t\tenum TypeNameFormat\n\t\t{\n\t\t\tNDEF_TNF_EMPTY      = 0,\n\t\t\tNDEF_TNF_WKT        = 1,\n\t\t\tNDEF_TNF_MEDIA      = 2,\n\t\t\tNDEF_TNF_URI        = 3,\n\t\t\tNDEF_TNF_EXT        = 4,\n\t\t\tNDEF_TNF_UNKNOWN    = 5,\n\t\t\tNDEF_TNF_UNCHANGED  = 6,\n\t\t\tNDEF_TNF_RESERVED   = 7,\n\t\t};\n\n\tpublic:\n\t\tRecord();\n\t\tvirtual ~Record();\n\n\t\tstatic std::optional<Record> FromStream(Stream& stream);\n\t\tstd::vector<std::byte> ToBytes(uint8 flags = 0) const;\n\n\t\tTypeNameFormat GetTNF() const;\n\t\tconst std::vector<std::byte>& GetID() const;\n\t\tconst std::vector<std::byte>& GetType() const;\n\t\tconst std::vector<std::byte>& GetPayload() const;\n\n\t\tvoid SetTNF(TypeNameFormat tnf);\n\t\tvoid SetID(const std::span<const std::byte>& id);\n\t\tvoid SetType(const std::span<const std::byte>& type);\n\t\tvoid SetPayload(const std::span<const std::byte>& payload);\n\n\t\tbool IsLast() const;\n\t\tbool IsShort() const;\n\n\tprivate:\n\t\tuint8 mFlags;\n\t\tTypeNameFormat mTNF;\n\t\tstd::vector<std::byte> mID;\n\t\tstd::vector<std::byte> mType;\n\t\tstd::vector<std::byte> mPayload;\n\t};\n\n\tclass Message\n\t{\n\tpublic:\n\t\tMessage();\n\t\tvirtual ~Message();\n\n\t\tstatic std::optional<Message> FromBytes(const std::span<const std::byte>& data);\n\t\tstd::vector<std::byte> ToBytes() const;\n\n\t\tRecord& operator[](int i) { return mRecords[i]; }\n\t\tconst Record& operator[](int i) const { return mRecords[i]; }\n\n\t\tvoid append(const Record& r);\n\n\t\tauto begin() { return mRecords.begin(); }\n\t\tauto end() { return mRecords.end(); }\n\t\tauto begin() const { return mRecords.begin(); }\n\t\tauto end() const { return mRecords.end(); }\n\n\tprivate:\n\t\tstd::vector<Record> mRecords;\n\t};\n\n} // namespace ndef\n"
  },
  {
    "path": "src/Cafe/OS/libs/nfc/nfc.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/libs/nfc/nfc.h\"\n#include \"Cafe/OS/libs/nn_nfp/nn_nfp.h\"\n#include \"Common/FileStream.h\"\n\n#include \"TagV0.h\"\n#include \"ndef.h\"\n\n#define NFC_MODE_INVALID\t-1\n#define NFC_MODE_IDLE\t\t0\n#define NFC_MODE_ACTIVE\t\t1\n\n#define NFC_STATE_UNINITIALIZED\t\t0x0\n#define NFC_STATE_INITIALIZED\t\t0x1\n#define NFC_STATE_IDLE\t\t\t0x2\n#define NFC_STATE_READ\t\t\t0x3\n#define NFC_STATE_WRITE\t\t\t0x4\n#define NFC_STATE_ABORT\t\t\t0x5\n#define NFC_STATE_FORMAT\t\t0x6\n#define NFC_STATE_SET_READ_ONLY\t\t0x7\n#define NFC_STATE_TAG_PRESENT\t\t0x8\n#define NFC_STATE_DETECT\t\t0x9\n#define NFC_STATE_SEND_RAW_DATA\t\t0xA\n\n#define NFC_STATUS_COMMAND_COMPLETE\t0x1\n#define NFC_STATUS_READY\t\t0x2\n#define NFC_STATUS_HAS_TAG\t\t0x4\n\nnamespace nfc\n{\n\tstruct NFCContext\n\t{\n\t\tbool isInitialized;\n\t\tuint32 state;\n\t\tsint32 mode;\n\t\tbool hasTag;\n\n\t\tuint32 nfcStatus;\n\t\tstd::chrono::time_point<std::chrono::system_clock> touchTime;\n\t\tstd::chrono::time_point<std::chrono::system_clock> discoveryTimeout;\n\t\tstruct {\n\t\t\tNFCUid uid;\n\t\t\tNFCUid mask;\n\t\t} filter;\n\n\t\tMPTR tagDetectCallback;\n\t\tvoid* tagDetectContext;\n\t\tMPTR abortCallback;\n\t\tvoid* abortContext;\n\t\tMPTR rawCallback;\n\t\tvoid* rawContext;\n\t\tMPTR readCallback;\n\t\tvoid* readContext;\n\t\tMPTR writeCallback;\n\t\tvoid* writeContext;\n\t\tMPTR getTagInfoCallback;\n\n\t\tSysAllocator<NFCTagInfo> tagInfo;\n\n\t\tfs::path tagPath;\n\t\tstd::shared_ptr<TagV0> tag;\n\n\t\tndef::Message writeMessage;\n\t};\n\tNFCContext gNFCContexts[2];\n\n\tsint32 NFCInit(uint32 chan)\n\t{\n\t\treturn NFCInitEx(chan, 0);\n\t}\n\n\tvoid __NFCClearContext(NFCContext* context)\n\t{\n\t\tcontext->isInitialized = false;\n\t\tcontext->state = NFC_STATE_UNINITIALIZED;\n\t\tcontext->mode = NFC_MODE_IDLE;\n\t\tcontext->hasTag = false;\n\n\t\tcontext->nfcStatus = NFC_STATUS_READY;\n\t\tcontext->discoveryTimeout = {};\n\n\t\tcontext->tagDetectCallback = MPTR_NULL;\n\t\tcontext->tagDetectContext = nullptr;\n\t\tcontext->abortCallback = MPTR_NULL;\n\t\tcontext->abortContext = nullptr;\n\t\tcontext->rawCallback = MPTR_NULL;\n\t\tcontext->rawContext = nullptr;\n\t\tcontext->readCallback = MPTR_NULL;\n\t\tcontext->readContext = nullptr;\n\t\tcontext->writeCallback = MPTR_NULL;\n\t\tcontext->writeContext = nullptr;\n\n\t\tcontext->tagPath = \"\";\n\t\tcontext->tag = {};\n\t}\n\n\tsint32 NFCInitEx(uint32 chan, uint32 powerMode)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\t__NFCClearContext(ctx);\n\t\tctx->isInitialized = true;\n\t\tctx->state = NFC_STATE_INITIALIZED;\n\n\t\treturn NFC_RESULT_SUCCESS;\n\t}\n\n\tsint32 NFCShutdown(uint32 chan)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\t__NFCClearContext(ctx);\n\n\t\treturn NFC_RESULT_SUCCESS;\n\t}\n\n\tbool NFCIsInit(uint32 chan)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\treturn gNFCContexts[chan].isInitialized;\n\t}\n\n\tbool __NFCCompareUid(NFCUid* uid, NFCUid* filterUid, NFCUid* filterMask)\n\t{\n\t\tfor (int i = 0; i < sizeof(uid->uid); i++)\n\t\t{\n\t\t\tif ((uid->uid[i] & filterMask->uid[i]) != filterUid->uid[i])\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tvoid __NFCHandleRead(uint32 chan)\n\t{\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tctx->state = NFC_STATE_IDLE;\n\n\t\tsint32 result;\n\t\tStackAllocator<NFCUid> uid;\n\t\tbool readOnly = false;\n\t\tuint32 dataSize = 0;\n\t\tStackAllocator<uint8, 0x200> data;\n\t\tuint32 lockedDataSize = 0;\n\t\tStackAllocator<uint8, 0x200> lockedData;\n\n\t\tif (ctx->tag)\n\t\t{\n\t\t\t// Compare UID\n\t\t\tmemcpy(uid.GetPointer(), ctx->tag->GetUIDBlock().data(), sizeof(NFCUid));\n\t\t\tif (__NFCCompareUid(uid.GetPointer(), &ctx->filter.uid, &ctx->filter.mask))\n\t\t\t{\n\t\t\t\t// Try to parse ndef message\n\t\t\t\tauto ndefMsg = ndef::Message::FromBytes(ctx->tag->GetNDEFData());\n\t\t\t\tif (ndefMsg)\n\t\t\t\t{\n\t\t\t\t\t// Look for the unknown TNF which contains the data we care about\n\t\t\t\t\tfor (const auto& rec : *ndefMsg)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (rec.GetTNF() == ndef::Record::NDEF_TNF_UNKNOWN)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdataSize = rec.GetPayload().size();\n\t\t\t\t\t\t\tcemu_assert(dataSize < 0x200);\n\t\t\t\t\t\t\tmemcpy(data.GetPointer(), rec.GetPayload().data(), dataSize);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (dataSize)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Get locked data\n\t\t\t\t\t\tlockedDataSize = ctx->tag->GetLockedArea().size();\n\t\t\t\t\t\tmemcpy(lockedData.GetPointer(), ctx->tag->GetLockedArea().data(), lockedDataSize);\n\n\t\t\t\t\t\tresult = NFC_RESULT_SUCCESS;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tresult = NFC_MAKE_RESULT(NFC_RESULT_BASE_TAG_PARSE, NFC_RESULT_INVALID_TAG);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tresult = NFC_MAKE_RESULT(NFC_RESULT_BASE_TAG_PARSE, NFC_RESULT_INVALID_TAG);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult = NFC_MAKE_RESULT(NFC_RESULT_BASE_READ, NFC_RESULT_UID_MISMATCH);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult = NFC_MAKE_RESULT(NFC_RESULT_BASE_READ, NFC_RESULT_NO_TAG);\n\t\t}\n\n\t\tPPCCoreCallback(ctx->readCallback, chan, result, uid.GetPointer(), readOnly, dataSize, data.GetPointer(), lockedDataSize, lockedData.GetPointer(), ctx->readContext);\n\t}\n\n\tvoid __NFCHandleWrite(uint32 chan)\n\t{\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tctx->state = NFC_STATE_IDLE;\n\n\t\tsint32 result;\n\n\t\tif (ctx->tag)\n\t\t{\n\t\t\tNFCUid uid;\n\t\t\tmemcpy(&uid, ctx->tag->GetUIDBlock().data(), sizeof(NFCUid));\n\t\t\tif (__NFCCompareUid(&uid, &ctx->filter.uid, &ctx->filter.mask))\n\t\t\t{\n\t\t\t\t// Update tag NDEF data\n\t\t\t\tctx->tag->SetNDEFData(ctx->writeMessage.ToBytes());\n\n\t\t\t\t// open file for writing\n\t\t\t\tFileStream* fs = FileStream::openFile2(ctx->tagPath, true);\n\t\t\t\tif (!fs)\n\t\t\t\t{\n\t\t\t\t\tresult = NFC_MAKE_RESULT(NFC_RESULT_BASE_WRITE, 0x22);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto tagBytes = ctx->tag->ToBytes();\n\t\t\t\t\tfs->writeData(tagBytes.data(), tagBytes.size());\n\t\t\t\t\tdelete fs;\n\n\t\t\t\t\tresult = NFC_RESULT_SUCCESS;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult = NFC_MAKE_RESULT(NFC_RESULT_BASE_WRITE, NFC_RESULT_UID_MISMATCH);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult = NFC_MAKE_RESULT(NFC_RESULT_BASE_WRITE, NFC_RESULT_NO_TAG);\n\t\t}\n\n\t\tPPCCoreCallback(ctx->writeCallback, chan, result, ctx->writeContext);\n\t}\n\n\tvoid __NFCHandleAbort(uint32 chan)\n\t{\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tctx->state = NFC_STATE_IDLE;\n\n\t\tPPCCoreCallback(ctx->abortCallback, chan, 0, ctx->abortContext);\n\t}\n\n\tvoid __NFCHandleRaw(uint32 chan)\n\t{\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tctx->state = NFC_STATE_IDLE;\n\n\t\tsint32 result;\n\t\tif (ctx->nfcStatus & NFC_STATUS_HAS_TAG)\n\t\t{\n\t\t\tresult = NFC_RESULT_SUCCESS;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult = NFC_MAKE_RESULT(NFC_RESULT_BASE_SEND_RAW_DATA, NFC_RESULT_NO_TAG);\n\t\t}\n\n\t\t// We don't actually send any commands/responses\n\t\tuint32 responseSize = 0;\n\t\tvoid* responseData = nullptr;\n\n\t\tPPCCoreCallback(ctx->rawCallback, chan, result, responseSize, responseData, ctx->rawContext);\n\t}\n\n\tbool __NFCShouldHandleState(NFCContext* ctx)\n\t{\n\t\t// Always handle abort\n\t\tif (ctx->state == NFC_STATE_ABORT)\n\t\t{\n\t\t\treturn true;\n\t\t}\n\n\t\t// Do we have a tag?\n\t\tif (ctx->nfcStatus & NFC_STATUS_HAS_TAG)\n\t\t{\n\t\t\treturn true;\n\t\t}\n\n\t\t// Did the timeout expire?\n\t\tif (ctx->discoveryTimeout < std::chrono::system_clock::now())\n\t\t{\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tvoid NFCProc(uint32 chan)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tif (!ctx->isInitialized)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif (ctx->state == NFC_STATE_INITIALIZED)\n\t\t{\n\t\t\tctx->state = NFC_STATE_IDLE;\n\t\t}\n\n\t\t// Check if the detect callback should be called\n\t\tif (ctx->nfcStatus & NFC_STATUS_HAS_TAG)\n\t\t{\n\t\t\tif (!ctx->hasTag && ctx->state > NFC_STATE_IDLE && ctx->state != NFC_STATE_ABORT)\n\t\t\t{\n\t\t\t\tif (ctx->tagDetectCallback)\n\t\t\t\t{\n\t\t\t\t\tPPCCoreCallback(ctx->tagDetectCallback, chan, true, ctx->tagDetectContext);\n\t\t\t\t}\n\n\t\t\t\tctx->hasTag = true;\n\t\t\t}\n\n\t\t\t// Check if the tag should be removed again\n\t\t\tif (ctx->touchTime + std::chrono::seconds(2) < std::chrono::system_clock::now())\n\t\t\t{\n\t\t\t\tctx->nfcStatus &= ~NFC_STATUS_HAS_TAG;\n\t\t\t\tctx->tag = {};\n\t\t\t\tctx->tagPath = \"\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (ctx->hasTag && ctx->state == NFC_STATE_IDLE)\n\t\t\t{\n\t\t\t\tif (ctx->tagDetectCallback)\n\t\t\t\t{\n\t\t\t\t\tPPCCoreCallback(ctx->tagDetectCallback, chan, false, ctx->tagDetectContext);\n\t\t\t\t}\n\n\t\t\t\tctx->hasTag = false;\n\t\t\t}\n\t\t}\n\n\t\tif (__NFCShouldHandleState(ctx))\n\t\t{\n\t\t\tswitch (ctx->state)\n\t\t\t{\n\t\t\tcase NFC_STATE_READ:\n\t\t\t\t__NFCHandleRead(chan);\n\t\t\t\tbreak;\n\t\t\tcase NFC_STATE_WRITE:\n\t\t\t\t__NFCHandleWrite(chan);\n\t\t\t\tbreak;\n\t\t\tcase NFC_STATE_ABORT:\n\t\t\t\t__NFCHandleAbort(chan);\n\t\t\t\tbreak;\n\t\t\tcase NFC_STATE_SEND_RAW_DATA:\n\t\t\t\t__NFCHandleRaw(chan);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Return back to idle mode\n\t\t\tctx->mode = NFC_MODE_IDLE;\n\t\t}\n\t}\n\n\tsint32 NFCGetMode(uint32 chan)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tif (!NFCIsInit(chan) || ctx->state == NFC_STATE_UNINITIALIZED)\n\t\t{\n\t\t\treturn NFC_MODE_INVALID;\n\t\t}\n\n\t\treturn ctx->mode;\n\t}\n\n\tsint32 NFCSetMode(uint32 chan, sint32 mode)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tif (!NFCIsInit(chan))\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_SET_MODE, NFC_RESULT_UNINITIALIZED);\n\t\t}\n\n\t\tif (ctx->state == NFC_STATE_UNINITIALIZED)\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_SET_MODE, NFC_RESULT_INVALID_STATE);\n\t\t}\n\n\t\tctx->mode = mode;\n\n\t\treturn NFC_RESULT_SUCCESS;\n\t}\n\n\tvoid NFCSetTagDetectCallback(uint32 chan, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\t\tctx->tagDetectCallback = callback;\n\t\tctx->tagDetectContext = context;\n\t}\n\n\tsint32 NFCAbort(uint32 chan, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tif (!NFCIsInit(chan))\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_ABORT, NFC_RESULT_UNINITIALIZED);\n\t\t}\n\n\t\tif (ctx->state <= NFC_STATE_IDLE)\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_ABORT, NFC_RESULT_INVALID_STATE);\n\t\t}\n\n\t\tctx->state = NFC_STATE_ABORT;\n\t\tctx->abortCallback = callback;\n\t\tctx->abortContext = context;\n\n\t\treturn NFC_RESULT_SUCCESS;\n\t}\n\n\tsint32 __NFCConvertGetTagInfoResult(sint32 result)\n\t{\n\t\tif (result == NFC_MAKE_RESULT(NFC_RESULT_BASE_SEND_RAW_DATA, NFC_RESULT_NO_TAG))\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_GET_TAG_INFO, NFC_RESULT_TAG_INFO_TIMEOUT);\n\t\t}\n\n\t\t// TODO convert the rest of the results\n\t\treturn result;\n\t}\n\n\tvoid __NFCGetTagInfoCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(chan, 0);\n\t\tppcDefineParamS32(error, 1);\n\t\tppcDefineParamU32(responseSize, 2);\n\t\tppcDefineParamPtr(responseData, void, 3);\n\t\tppcDefineParamPtr(context, void, 4);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\terror = __NFCConvertGetTagInfoResult(error);\n\t\tif (error == 0 && ctx->tag)\n\t\t{\n\t\t\t// this is usually parsed from response data\n\t\t\tctx->tagInfo->uidSize = sizeof(NFCUid);\n\t\t\tmemcpy(ctx->tagInfo->uid, ctx->tag->GetUIDBlock().data(), ctx->tagInfo->uidSize);\n\t\t\tctx->tagInfo->technology = NFC_TECHNOLOGY_A;\n\t\t\tctx->tagInfo->protocol = NFC_PROTOCOL_T1T;            \n\t\t}\n\n\t\tPPCCoreCallback(ctx->getTagInfoCallback, chan, error, ctx->tagInfo.GetPtr(), context);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tsint32 NFCGetTagInfo(uint32 chan, uint32 discoveryTimeout, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\t// Forward this request to nn_nfp, if the title initialized it\n\t\t// TODO integrate nn_nfp/ntag/nfc\n\t\tif (nnNfp_isInitialized())\n\t\t{\n\t\t\treturn nn::nfp::NFCGetTagInfo(chan, discoveryTimeout, callback, context);\n\t\t}\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tctx->getTagInfoCallback = callback;\n\n\t\tsint32 result = NFCSendRawData(chan, true, discoveryTimeout, 1000U, 0, 0, nullptr, RPLLoader_MakePPCCallable(__NFCGetTagInfoCallback), context);\n\t\treturn __NFCConvertGetTagInfoResult(result);\n\t}\n\n\tsint32 NFCSendRawData(uint32 chan, bool startDiscovery, uint32 discoveryTimeout, uint32 commandTimeout, uint32 commandSize, uint32 responseSize, void* commandData, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tif (!NFCIsInit(chan))\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_SEND_RAW_DATA, NFC_RESULT_UNINITIALIZED);\n\t\t}\n\n\t\t// Only allow discovery\n\t\tif (!startDiscovery)\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_SEND_RAW_DATA, NFC_RESULT_INVALID_MODE);\n\t\t}\n\n\t\tif (NFCGetMode(chan) == NFC_MODE_ACTIVE && NFCSetMode(chan, NFC_MODE_IDLE) < 0)\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_SEND_RAW_DATA, NFC_RESULT_INVALID_MODE);\n\t\t}\n\n\t\tif (ctx->state != NFC_STATE_IDLE)\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_SEND_RAW_DATA, NFC_RESULT_INVALID_STATE);\n\t\t}\n\n\t\tctx->state = NFC_STATE_SEND_RAW_DATA;\n\t\tctx->rawCallback = callback;\n\t\tctx->rawContext = context;\n\n\t\t// If the discoveryTimeout is 0, no timeout\n\t\tif (discoveryTimeout == 0)\n\t\t{\n\t\t\tctx->discoveryTimeout = std::chrono::time_point<std::chrono::system_clock>::max();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tctx->discoveryTimeout = std::chrono::system_clock::now() + std::chrono::milliseconds(discoveryTimeout);\n\t\t}\n\n\t\treturn NFC_RESULT_SUCCESS;\n\t}\n\n\tsint32 NFCRead(uint32 chan, uint32 discoveryTimeout, NFCUid* uid, NFCUid* uidMask, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tif (!NFCIsInit(chan))\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_READ, NFC_RESULT_UNINITIALIZED);\n\t\t}\n\n\t\tif (NFCGetMode(chan) == NFC_MODE_ACTIVE && NFCSetMode(chan, NFC_MODE_IDLE) < 0)\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_READ, NFC_RESULT_INVALID_MODE);\n\t\t}\n\n\t\tif (ctx->state != NFC_STATE_IDLE)\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_READ, NFC_RESULT_INVALID_STATE);\n\t\t}\n\n\t\tctx->state = NFC_STATE_READ;\n\t\tctx->readCallback = callback;\n\t\tctx->readContext = context;\n\n\t\t// If the discoveryTimeout is 0, no timeout\n\t\tif (discoveryTimeout == 0)\n\t\t{\n\t\t\tctx->discoveryTimeout = std::chrono::time_point<std::chrono::system_clock>::max();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tctx->discoveryTimeout = std::chrono::system_clock::now() + std::chrono::milliseconds(discoveryTimeout);\n\t\t}\n\n\t\tmemcpy(&ctx->filter.uid, uid, sizeof(*uid));\n\t\tmemcpy(&ctx->filter.mask, uidMask, sizeof(*uidMask));\n\n\t\treturn NFC_RESULT_SUCCESS;\n\t}\n\n\tsint32 NFCWrite(uint32 chan, uint32 discoveryTimeout, NFCUid* uid, NFCUid* uidMask, uint32 size, void* data, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tNFCContext* ctx = &gNFCContexts[chan];\n\n\t\tif (!NFCIsInit(chan))\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_WRITE, NFC_RESULT_UNINITIALIZED);\n\t\t}\n\n\t\tif (NFCGetMode(chan) == NFC_MODE_ACTIVE && NFCSetMode(chan, NFC_MODE_IDLE) < 0)\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_WRITE, NFC_RESULT_INVALID_MODE);\n\t\t}\n\n\t\tif (ctx->state != NFC_STATE_IDLE)\n\t\t{\n\t\t\treturn NFC_MAKE_RESULT(NFC_RESULT_BASE_WRITE, NFC_RESULT_INVALID_STATE);\n\t\t}\n\n\t\t// Create unknown record which contains the rw area\n\t\tndef::Record rec;\n\t\trec.SetTNF(ndef::Record::NDEF_TNF_UNKNOWN);\n\t\trec.SetPayload(std::span(reinterpret_cast<std::byte*>(data), size));\n\n\t\t// Create ndef message which contains the record\n\t\tndef::Message msg;\n\t\tmsg.append(rec);\n\t\tctx->writeMessage = msg; \n\n\t\tctx->state = NFC_STATE_WRITE;\n\t\tctx->writeCallback = callback;\n\t\tctx->writeContext = context;\n\n\t\t// If the discoveryTimeout is 0, no timeout\n\t\tif (discoveryTimeout == 0)\n\t\t{\n\t\t\tctx->discoveryTimeout = std::chrono::time_point<std::chrono::system_clock>::max();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tctx->discoveryTimeout = std::chrono::system_clock::now() + std::chrono::milliseconds(discoveryTimeout);\n\t\t}\n\n\t\tmemcpy(&ctx->filter.uid, uid, sizeof(*uid));\n\t\tmemcpy(&ctx->filter.mask, uidMask, sizeof(*uidMask));\n\n\t\treturn NFC_RESULT_SUCCESS;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nfc\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"nfc\", NFCInit, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCInitEx, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCShutdown, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCIsInit, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCProc, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCGetMode, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCSetMode, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCSetTagDetectCallback, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCGetTagInfo, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCSendRawData, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCAbort, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCRead, LogType::NFC);\n\t\t\tcafeExportRegister(\"nfc\", NFCWrite, LogType::NFC);\n\t\t};\n\t}s_COSnfcModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnfcModule;\n\t}\n\n\tbool TouchTagFromFile(const fs::path& filePath, uint32* nfcError)\n\t{\n\t\t// Forward this request to nn_nfp, if the title initialized it\n\t\t// TODO integrate nn_nfp/ntag/nfc\n\t\tif (nnNfp_isInitialized())\n\t\t{\n\t\t\treturn nnNfp_touchNfcTagFromFile(filePath, nfcError);\n\t\t}\n\n\t\tNFCContext* ctx = &gNFCContexts[0];\n\n\t\tauto nfcData = FileStream::LoadIntoMemory(filePath);\n\t\tif (!nfcData)\n\t\t{\n\t\t\t*nfcError = NFC_TOUCH_TAG_ERROR_NO_ACCESS;\n\t\t\treturn false;\n\t\t}\n\n\t\tctx->tag = TagV0::FromBytes(std::as_bytes(std::span(nfcData->data(), nfcData->size())));\n\t\tif (!ctx->tag)\n\t\t{\n\t\t\t*nfcError = NFC_TOUCH_TAG_ERROR_INVALID_FILE_FORMAT;\n\t\t\treturn false;\n\t\t}\n\n\t\tctx->nfcStatus |= NFC_STATUS_HAS_TAG;\n\t\tctx->tagPath = filePath;\n\t\tctx->touchTime = std::chrono::system_clock::now();\n\n\t\t*nfcError = NFC_TOUCH_TAG_ERROR_NONE;\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nfc/nfc.h",
    "content": "#pragma once\n\n#include \"Cafe/OS/RPL/COSModule.h\"\n\n// CEMU NFC error codes\n#define NFC_TOUCH_TAG_ERROR_NONE\t\t\t(0)\n#define NFC_TOUCH_TAG_ERROR_NO_ACCESS\t\t\t(1)\n#define NFC_TOUCH_TAG_ERROR_INVALID_FILE_FORMAT\t\t(2)\n\n// NFC result base\n#define NFC_RESULT_BASE_INIT\t\t(-0x100)\n#define NFC_RESULT_BASE_READ\t\t(-0x200)\n#define NFC_RESULT_BASE_WRITE\t\t(-0x300)\n#define NFC_RESULT_BASE_FORMAT\t\t(-0x400)\n#define NFC_RESULT_BASE_SET_READ_ONLY\t(-0x500)\n#define NFC_RESULT_BASE_IS_TAG_PRESENT\t(-0x600)\n#define NFC_RESULT_BASE_ABORT\t\t(-0x700)\n#define NFC_RESULT_BASE_SHUTDOWN\t(-0x800)\n#define NFC_RESULT_BASE_DETECT\t\t(-0x900)\n#define NFC_RESULT_BASE_SEND_RAW_DATA\t(-0xA00)\n#define NFC_RESULT_BASE_SET_MODE\t(-0xB00)\n#define NFC_RESULT_BASE_TAG_PARSE\t(-0xC00)\n#define NFC_RESULT_BASE_GET_TAG_INFO\t(-0x1400)\n\n// NFC result status\n#define NFC_RESULT_NO_TAG\t\t(0x01)\n#define NFC_RESULT_INVALID_TAG\t\t(0x02)\n#define NFC_RESULT_UID_MISMATCH\t\t(0x0A)\n#define NFC_RESULT_UNINITIALIZED\t(0x20)\n#define NFC_RESULT_INVALID_STATE\t(0x21)\n#define NFC_RESULT_INVALID_MODE\t\t(0x24)\n#define NFC_RESULT_TAG_INFO_TIMEOUT\t(0x7A)\n\n// Result macros\n#define NFC_RESULT_SUCCESS\t\t(0)\n#define NFC_RESULT_BASE_MASK\t\t(0xFFFFFF00)\n#define NFC_RESULT_MASK\t\t\t(0x000000FF)\n#define NFC_MAKE_RESULT(base, result)\t((base) | (result))\n\n#define NFC_PROTOCOL_T1T\t0x1\n#define NFC_PROTOCOL_T2T\t0x2\n\n#define NFC_TECHNOLOGY_A\t0x0\n#define NFC_TECHNOLOGY_B\t0x1\n#define NFC_TECHNOLOGY_F\t0x2\n\nnamespace nfc\n{\n\tstruct NFCUid\n\t{\n\t\t/* +0x00 */ uint8 uid[7];\n\t};\n\tstatic_assert(sizeof(NFCUid) == 0x7);\n\n\tstruct NFCTagInfo\n\t{\n\t\t/* +0x00 */ uint8 uidSize;\n\t\t/* +0x01 */ uint8 uid[10];\n\t\t/* +0x0B */ uint8 technology;\n\t\t/* +0x0C */ uint8 protocol;\n\t\t/* +0x0D */ uint8 reserved[0x20];\n\t};\n\tstatic_assert(sizeof(NFCTagInfo) == 0x2D);\n\n\tsint32 NFCInit(uint32 chan);\n\n\tsint32 NFCInitEx(uint32 chan, uint32 powerMode);\n\n\tsint32 NFCShutdown(uint32 chan);\n\n\tbool NFCIsInit(uint32 chan);\n\n\tvoid NFCProc(uint32 chan);\n\n\tsint32 NFCGetMode(uint32 chan);\n\n\tsint32 NFCSetMode(uint32 chan, sint32 mode);\n\n\tvoid NFCSetTagDetectCallback(uint32 chan, MPTR callback, void* context);\n\n\tsint32 NFCGetTagInfo(uint32 chan, uint32 discoveryTimeout, MPTR callback, void* context);\n\n\tsint32 NFCSendRawData(uint32 chan, bool startDiscovery, uint32 discoveryTimeout, uint32 commandTimeout, uint32 commandSize, uint32 responseSize, void* commandData, MPTR callback, void* context);\n\n\tsint32 NFCAbort(uint32 chan, MPTR callback, void* context);\n\n\tsint32 NFCRead(uint32 chan, uint32 discoveryTimeout, NFCUid* uid, NFCUid* uidMask, MPTR callback, void* context);\n\n\tsint32 NFCWrite(uint32 chan, uint32 discoveryTimeout, NFCUid* uid, NFCUid* uidMask, uint32 size, void* data, MPTR callback, void* context);\n\n\tCOSModule* GetModule();\n\n\tbool TouchTagFromFile(const fs::path& filePath, uint32* nfcError);\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nfc/stream.cpp",
    "content": "#include \"stream.h\"\n\n#include <algorithm>\n\nStream::Stream(std::endian endianness)\n : mError(ERROR_OK), mEndianness(endianness)\n{\n}\n\nStream::~Stream()\n{\n}\n\nStream::Error Stream::GetError() const\n{\n\treturn mError;\n}\n\nvoid Stream::SetEndianness(std::endian endianness)\n{\n\tmEndianness = endianness;\n}\n\nstd::endian Stream::GetEndianness() const\n{\n\treturn mEndianness;\n}\n\nStream& Stream::operator>>(bool& val)\n{\n\tuint8 i;\n\t*this >> i;\n\tval = !!i;\n\n\treturn *this;\n}\n\nStream& Stream::operator>>(float& val)\n{\n\tuint32 i;\n\t*this >> i;\n\tval = std::bit_cast<float>(i);\n\n\treturn *this;\n}\n\nStream& Stream::operator>>(double& val)\n{\n\tuint64 i;\n\t*this >> i;\n\tval = std::bit_cast<double>(i);\n\n\treturn *this;\n}\n\nStream& Stream::operator<<(bool val)\n{\n\tuint8 i = val;\n\t*this >> i;\n\n\treturn *this;\n}\n\nStream& Stream::operator<<(float val)\n{\n\tuint32 i = std::bit_cast<uint32>(val);\n\t*this >> i;\n\n\treturn *this;\n}\n\nStream& Stream::operator<<(double val)\n{\n\tuint64 i = std::bit_cast<uint64>(val);\n\t*this >> i;\n\n\treturn *this;\n}\n\nvoid Stream::SetError(Error error)\n{\n\tmError = error;\n}\n\nbool Stream::NeedsSwap()\n{\n\treturn mEndianness != std::endian::native;\n}\n\nVectorStream::VectorStream(std::vector<std::byte>& vector, std::endian endianness)\n : Stream(endianness), mVector(vector), mPosition(0)\n{\n}\n\nVectorStream::~VectorStream()\n{\n}\n\nstd::size_t VectorStream::Read(const std::span<std::byte>& data)\n{\n\tif (data.size() > GetRemaining())\n\t{\n\t\tSetError(ERROR_READ_FAILED);\n\t\tstd::fill(data.begin(), data.end(), std::byte(0));\n\t\treturn 0;\n\t}\n\n\tstd::copy_n(mVector.get().begin() + mPosition, data.size(), data.begin());\n\tmPosition += data.size();\n\treturn data.size();\n}\n\nstd::size_t VectorStream::Write(const std::span<const std::byte>& data)\n{\n\t// Resize vector if not enough bytes remain\n\tif (mPosition + data.size() > mVector.get().size())\n\t{\n\t\tmVector.get().resize(mPosition + data.size());\n\t}\n\n\tstd::copy(data.begin(), data.end(), mVector.get().begin() + mPosition);\n\tmPosition += data.size();\n\treturn data.size();\n}\n\nbool VectorStream::SetPosition(std::size_t position)\n{\n\tif (position >= mVector.get().size())\n\t{\n\t\treturn false;\n\t}\n\n\tmPosition = position;\n\treturn true;\n}\n\nstd::size_t VectorStream::GetPosition() const\n{\n\treturn mPosition;\n}\n\nstd::size_t VectorStream::GetRemaining() const\n{\n\treturn mVector.get().size() - mPosition;\n}\n\nSpanStream::SpanStream(std::span<const std::byte> span, std::endian endianness)\n : Stream(endianness), mSpan(std::move(span)), mPosition(0)\n{\n}\n\nSpanStream::~SpanStream()\n{\n}\n\nstd::size_t SpanStream::Read(const std::span<std::byte>& data)\n{\n\tif (data.size() > GetRemaining())\n\t{\n\t\tSetError(ERROR_READ_FAILED);\n\t\tstd::fill(data.begin(), data.end(), std::byte(0));\n\t\treturn 0;\n\t}\n\n\tstd::copy_n(mSpan.begin() + mPosition, data.size(), data.begin());\n\tmPosition += data.size();\n\treturn data.size();\n}\n\nstd::size_t SpanStream::Write(const std::span<const std::byte>& data)\n{\n\t// Cannot write to const span\n\tSetError(ERROR_WRITE_FAILED);\n\treturn 0;\n}\n\nbool SpanStream::SetPosition(std::size_t position)\n{\n\tif (position >= mSpan.size())\n\t{\n\t\treturn false;\n\t}\n\n\tmPosition = position;\n\treturn true;\n}\n\nstd::size_t SpanStream::GetPosition() const\n{\n\treturn mPosition;\n}\n\nstd::size_t SpanStream::GetRemaining() const\n{\n\tif (mPosition > mSpan.size())\n\t{\n\t\treturn 0;\n\t}\n\n\treturn mSpan.size() - mPosition;\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nfc/stream.h",
    "content": "#pragma once\n\n#include <cstdint>\n#include <vector>\n#include <span>\n#include <bit>\n\n#include \"Common/precompiled.h\"\n\nclass Stream\n{\npublic:\n\tenum Error\n\t{\n\t\tERROR_OK,\n\t\tERROR_READ_FAILED,\n\t\tERROR_WRITE_FAILED,\n\t};\n\npublic:\n\tStream(std::endian endianness = std::endian::native);\n\tvirtual ~Stream();\n\n\tError GetError() const;\n\n\tvoid SetEndianness(std::endian endianness);\n\tstd::endian GetEndianness() const;\n\n\tvirtual std::size_t Read(const std::span<std::byte>& data) = 0;\n\tvirtual std::size_t Write(const std::span<const std::byte>& data) = 0;\n\n\tvirtual bool SetPosition(std::size_t position) = 0;\n\tvirtual std::size_t GetPosition() const = 0;\n\n\tvirtual std::size_t GetRemaining() const = 0;\n\n\t// Stream read operators\n\ttemplate<std::integral T>\n\tStream& operator>>(T& val)\n\t{\n\t\tval = 0;\n\t\tif (Read(std::as_writable_bytes(std::span(std::addressof(val), 1))) == sizeof(val))\n\t\t{\n\t\t\tif (NeedsSwap())\n\t\t\t{\n\t\t\t\tif (sizeof(T) == 2)\n\t\t\t\t{\n\t\t\t\t\tval = _swapEndianU16(val);\n\t\t\t\t}\n\t\t\t\telse if (sizeof(T) == 4)\n\t\t\t\t{\n\t\t\t\t\tval = _swapEndianU32(val);\n\t\t\t\t}\n\t\t\t\telse if (sizeof(T) == 8)\n\t\t\t\t{\n\t\t\t\t\tval = _swapEndianU64(val);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn *this;\n\t}\n\tStream& operator>>(bool& val);\n\tStream& operator>>(float& val);\n\tStream& operator>>(double& val);\n\n\t// Stream write operators\n\ttemplate<std::integral T>\n\tStream& operator<<(T val)\n\t{\n\t\tif (NeedsSwap())\n\t\t{\n\t\t\tif (sizeof(T) == 2)\n\t\t\t{\n\t\t\t\tval = _swapEndianU16(val);\n\t\t\t}\n\t\t\telse if (sizeof(T) == 4)\n\t\t\t{\n\t\t\t\tval = _swapEndianU32(val);\n\t\t\t}\n\t\t\telse if (sizeof(T) == 8)\n\t\t\t{\n\t\t\t\tval = _swapEndianU64(val);\n\t\t\t}\n\t\t}\n\n\t\tWrite(std::as_bytes(std::span(std::addressof(val), 1)));\n\t\treturn *this;\n\t}\n\tStream& operator<<(bool val);\n\tStream& operator<<(float val);\n\tStream& operator<<(double val);\n\nprotected:\n\tvoid SetError(Error error);\n\n\tbool NeedsSwap();\n\n\tError mError;\n\tstd::endian mEndianness;\n};\n\nclass VectorStream : public Stream\n{\npublic:\n\tVectorStream(std::vector<std::byte>& vector, std::endian endianness = std::endian::native);\n\tvirtual ~VectorStream();\n\n\tvirtual std::size_t Read(const std::span<std::byte>& data) override;\n\tvirtual std::size_t Write(const std::span<const std::byte>& data) override;\n\n\tvirtual bool SetPosition(std::size_t position) override;\n\tvirtual std::size_t GetPosition() const override;\n\n\tvirtual std::size_t GetRemaining() const override;\n\nprivate:\n\tstd::reference_wrapper<std::vector<std::byte>> mVector;\n\tstd::size_t mPosition;\n};\n\nclass SpanStream : public Stream\n{\npublic:\n\tSpanStream(std::span<const std::byte> span, std::endian endianness = std::endian::native);\n\tvirtual ~SpanStream();\n\n\tvirtual std::size_t Read(const std::span<std::byte>& data) override;\n\tvirtual std::size_t Write(const std::span<const std::byte>& data) override;\n\n\tvirtual bool SetPosition(std::size_t position) override;\n\tvirtual std::size_t GetPosition() const override;\n\n\tvirtual std::size_t GetRemaining() const override;\n\nprivate:\n\tstd::span<const std::byte> mSpan;\n\tstd::size_t mPosition;\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/nlibcurl/nlibcurl.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/common/OSUtil.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"nlibcurl.h\"\n\n#include \"openssl/bn.h\"\n#include \"openssl/x509.h\"\n#include \"openssl/ssl.h\"\n\n#define CURL_STRICTER\n\n#include \"curl/curl.h\"\n#include <unordered_map>\n#include <atomic>\n\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n#include \"Cafe/OS/libs/nsysnet/nsysnet.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n\n#include \"util/helpers/ConcurrentQueue.h\"\n#include \"Cafe/OS/common/PPCConcurrentQueue.h\"\n#include \"Common/FileStream.h\"\n#include \"config/ActiveSettings.h\"\n\nnamespace nlibcurl\n{\n#define CURL_MULTI_HANDLE\t\t(0x000bab1e)\n\n#define NSSL_VERIFY_NONE\t\t(0x0)\n#define NSSL_VERIFY_PEER\t\t(1<<0)\n#define NSSL_VERIFY_HOSTNAME\t(1<<1)\n#define NSSL_VERIFY_DATE\t\t(1<<2)\n\n\tenum QueueOrder\n\t{\n\t\tQueueOrder_None,\n\n\t\tQueueOrder_Result,\n\t\tQueueOrder_CBDone,\n\n\t\tQueueOrder_HeaderCB,\n\t\tQueueOrder_ReadCB,\n\t\tQueueOrder_WriteCB,\n\t\tQueueOrder_ProgressCB,\n\n\t\tQueueOrder_Perform,\n\t\tQueueOrder_Pause,\n\t};\n\n\tstruct QueueMsg_t\n\t{\n\t\tQueueOrder order;\n\t\tunion\n\t\t{\n\t\t\tuint32 result;\n\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tchar* buffer;\n\t\t\t\tuint32 size;\n\t\t\t\tuint32 nitems;\n\t\t\t} header_cb;\n\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tchar* buffer;\n\t\t\t\tuint32 size;\n\t\t\t\tuint32 nitems;\n\t\t\t} read_cb;\n\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tchar* buffer;\n\t\t\t\tuint32 size;\n\t\t\t\tuint32 nmemb;\n\t\t\t} write_cb;\n\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tuint32 clientp;\n\t\t\t\tdouble dltotal;\n\t\t\t\tdouble dlnow;\n\t\t\t\tdouble ultotal;\n\t\t\t\tdouble ulnow;\n\t\t\t} progress_cb;\n\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tsint32 bitmask;\n\t\t\t} pause;\n\n\t\t};\n\n\t};\n\nstruct MEMPTRHash_t\n{\n\tsize_t operator()(const MEMPTR<void>& p) const\n\t{\n\t\treturn p.GetMPTR();\n\t}\n};\n\nstruct WU_curl_slist\n{\n\tMEMPTR<char> data;\n\tMEMPTR<WU_curl_slist> next;\n};\n\nenum class WU_CURLcode\n{\n\tplaceholder = 0,\n};\n\nstruct\n{\n\tsint32 initialized;\n\n\tMEMPTR<void> proxyConfig;\n\tMEMPTR<curl_malloc_callback> malloc;\n\tMEMPTR<curl_free_callback> free;\n\tMEMPTR<curl_realloc_callback> realloc;\n\tMEMPTR<curl_strdup_callback> strdup;\n\tMEMPTR<curl_calloc_callback> calloc;\n} g_nlibcurl = {};\n\nusing WU_CURL_off_t = uint64be;\n\nenum class WU_HTTPREQ : uint32\n{\n\tHTTPREQ_GET = 0x1,\n\tHTTPREQ_POST = 0x2,\n\tUKN_3 = 0x3,\n};\n\nstruct WU_UserDefined\n{\n\t// starting at 0xD8 (probably) in CURL_t\n\t/* 0x0D8 / +0x00 */ uint32be ukn0D8;\n\t/* 0x0DC / +0x04 */ uint32be ukn0DC;\n\t/* 0x0E0 / +0x08 */ MEMPTR<WU_curl_slist> headers;\n\t/* 0x0E4 / +0x0C */ uint32be ukn0E4;\n\t/* 0x0E8 / +0x10 */ uint32be ukn0E8;\n\t/* 0x0EC / +0x14 */ uint32be ukn0EC;\n\t/* 0x0F0 / +0x18 */ uint32be ukn0F0[4];\n\t/* 0x100 / +0x28 */ uint32be ukn100[4];\n\t/* 0x110 / +0x38 */ uint32be ukn110[4]; // +0x40 -> WU_CURL_off_t postfieldsize ?\n\t/* 0x120 / +0x48 */ uint32be ukn120[4];\n\t/* 0x130 / +0x58 */ uint32be ukn130[4];\n\t/* 0x140 / +0x68 */ uint32be ukn140[4];\n\t/* 0x150 / +0x78 */ uint32be ukn150[4];\n\t/* 0x160 / +0x88 */ uint32be ukn160[4];\n\t/* 0x170 / +0x98 */ uint32be ukn170[4];\n\t/* 0x180 / +0xA8 */ uint32be ukn180[4];\n\t/* 0x190 / +0xB0 */ sint64be infilesize_190{0};\n\t/* 0x198 / +0xB8 */ uint32be ukn198;\n\t/* 0x19C / +0xBC */ uint32be ukn19C;\n\t/* 0x1A0 / +0xC8 */ uint32be ukn1A0[4];\n\t/* 0x1B0 / +0xD8 */ uint32be ukn1B0[4];\n\t/* 0x1C0 / +0xE8 */ uint32be ukn1C0[4];\n\t/* 0x1D0 / +0xF8 */ uint32be ukn1D0[4];\n\t/* 0x1E0 / +0x108 */ uint32be ukn1E0;\n\t/* 0x1E4 / +0x108 */ uint32be ukn1E4;\n\t/* 0x1E8 / +0x108 */ uint32be ukn1E8;\n\t/* 0x1EC / +0x108 */ betype<WU_HTTPREQ> httpreq_1EC;\n\t/* 0x1F0 / +0x118 */ uint32be ukn1F0[4];\n\n\tvoid SetToDefault()\n\t{\n\t\tmemset(this, 0, sizeof(WU_UserDefined));\n\t\thttpreq_1EC = WU_HTTPREQ::HTTPREQ_GET;\n\t}\n};\n\nstruct CURL_t\n{\n\tCURL* curl;\n\n\tuint32be hNSSL;\n\tuint32be nsslVerifyOptions;\n\tMEMPTR<void> out; // CURLOPT_WRITEDATA\n\tMEMPTR<void> in_set; // CURLOPT_READDATA\n\tMEMPTR<void> writeheader; // CURLOPT_HEADERDATA\n\n\tMEMPTR<void> fwrite_func; // CURLOPT_WRITEFUNCTION\n\tMEMPTR<void> fwrite_header; // CURLOPT_HEADERFUNCTION\n\tMEMPTR<void> fread_func_set; // CURLOPT_READFUNCTION\n\n\tMEMPTR<void> progress_client; // CURLOPT_PROGRESSDATA\n\tMEMPTR<void> fprogress; // CURLOPT_PROGRESSFUNCTION\n\n\tMEMPTR<void> fsockopt; // CURLOPT_SOCKOPTFUNCTION\n\tMEMPTR<void> sockopt_client; // CURLOPT_SOCKOPTDATA\n\n\t// Cemu specific\n\tOSThread_t* curlThread;\n\tMEMPTR<char> info_redirectUrl; // stores CURLINFO_REDIRECT_URL ptr\n\tMEMPTR<char> info_contentType; // stores CURLINFO_CONTENT_TYPE ptr\n\tbool isDirty{true};\n\n\t// debug\n\tstruct  \n\t{\n\t\tuint32 activeRequestIndex{};\n\t\tuint32 responseRequestIndex{}; // set to activeRequestIndex once perform is called\n\t\tbool hasDumpedResultInfo{}; // set once the response info has been dumped (reset when next request is performed)\n\t\tFileStream* file_requestParam{};\n\t\tFileStream* file_responseHeaders{};\n\t\tFileStream* file_responseRaw{};\n\t}debug;\n\n\t// fields below match the actual memory layout, above still needs refactoring\n\t/* 0x78 */ uint32be ukn078;\n\t/* 0x7C */ uint32be ukn07C;\n\t/* 0x80 */ uint32be ukn080;\n\t/* 0x84 */ uint32be ukn084;\n\t/* 0x88 */ uint32be ukn088;\n\t/* 0x8C */ uint32be ukn08C;\n\t/* 0x90 */ uint32be ukn090[4];\n\t/* 0xA0 */ uint32be ukn0A0[4];\n\t/* 0xB0 */ uint32be ukn0B0[4];\n\t/* 0xC0 */ uint32be ukn0C0[4];\n\t/* 0xD0 */ uint32be ukn0D0;\n\t/* 0xD4 */ uint32be ukn0D4;\n\t/* 0xD8 */ WU_UserDefined set;\n\t/* 0x200 */ uint32be ukn200[4];\n\t/* 0x210 */ uint32be ukn210[4];\n\t/* 0x220 */ uint32be ukn220[4];\n\t/* 0x230 */ uint32be ukn230[4];\n\t/* 0x240 */ uint32be ukn240[4];\n\t/* 0x250 */ uint32be ukn250[4];\n\t/* 0x260 */ uint32be ukn260[4];\n\t/* 0x270 */ uint32be ukn270[4];\n\t/* 0x280 */ uint8be ukn280;\n\t/* 0x281 */ uint8be opt_no_body_281;\n\t/* 0x282 */ uint8be ukn282;\n\t/* 0x283 */ uint8be upload_283;\n};\nstatic_assert(sizeof(CURL_t) <= 0x8698);\nstatic_assert(offsetof(CURL_t, ukn078) == 0x78);\nstatic_assert(offsetof(CURL_t, set) == 0xD8);\nstatic_assert(offsetof(CURL_t, set) + offsetof(WU_UserDefined, headers) == 0xE0);\nstatic_assert(offsetof(CURL_t, set) + offsetof(WU_UserDefined, infilesize_190) == 0x190);\nstatic_assert(offsetof(CURL_t, set) + offsetof(WU_UserDefined, httpreq_1EC) == 0x1EC);\nstatic_assert(offsetof(CURL_t, opt_no_body_281) == 0x281);\ntypedef MEMPTR<CURL_t> CURLPtr;\n\n#pragma pack(1) // may affect structs below, we can probably remove this but lets keep it for now as the code below is fragile\n\ntypedef struct\n{\n\t//uint32be specifier; // 0x00\n\t//uint32be dirty; // 0x04\n\tMEMPTR<void> lockfunc; // 0x08\n\tMEMPTR<void> unlockfunc; // 0x0C\n\tMEMPTR<void> data; // 0x10\n\t//MEMPTR<void> uk14; // 0x14\n\t//MEMPTR<void> uk18; // 0x18\n\n\tCURLSH* curlsh;\n\tMEMPTR <CURL_t> curl;\n\tuint32 uk1;\n}CURLSH_t; // SCURL\nstatic_assert(sizeof(CURLSH_t) <= 0x1C);\ntypedef MEMPTR<CURLSH_t> CURLSHPtr;\n\ntypedef struct\n{\n\tCURLM* curlm;\n\tstd::vector<MEMPTR<CURL_t>> curl;\n}CURLM_t;\nstatic_assert(sizeof(CURLM_t) <= 0x80, \"sizeof(CURLM_t)\");\ntypedef MEMPTR<CURLM_t> CURLMPtr;\n\nstatic_assert(sizeof(WU_curl_slist) <= 0x8, \"sizeof(curl_slist_t)\");\n\nstruct CURLMsg_t\n{\n\tuint32be msg;\n\tMEMPTR<CURL_t> curl;\n\tuint32be result; // CURLcode\n};\n\nstatic_assert(sizeof(CURLMsg_t) <= 0xC, \"sizeof(CURLMsg_t)\");\n\n#pragma pack()\n\n#include \"nlibcurlDebug.hpp\"\n\nsize_t header_callback(char* buffer, size_t size, size_t nitems, void* userdata);\n\nthread_local PPCConcurrentQueue<QueueMsg_t>* g_callerQueue;\nthread_local ConcurrentQueue<QueueMsg_t>* g_threadQueue;\nvoid CurlWorkerThread(CURL_t* curl, PPCConcurrentQueue<QueueMsg_t>* callerQueue, ConcurrentQueue<QueueMsg_t>* threadQueue)\n{\n\tg_callerQueue = callerQueue;\n\tg_threadQueue = threadQueue;\n\n\tconst QueueMsg_t msg = threadQueue->pop();\n\n\tQueueMsg_t resultMsg = {};\n\tresultMsg.order = QueueOrder_Result;\n\n\tif (msg.order == QueueOrder_Perform)\n\t\tresultMsg.result = ::curl_easy_perform(curl->curl);\n\telse if(msg.order == QueueOrder_Pause)\n\t\tresultMsg.result = ::curl_easy_pause(curl->curl, msg.pause.bitmask);\n\telse\n\t\tassert_dbg();\n\n\tcallerQueue->push(resultMsg, curl->curlThread);\n}\n\nuint32 SendOrderToWorker(CURL_t* curl, QueueOrder order, uint32 arg1 = 0)\n{\n\tOSThread_t* currentThread = coreinit::OSGetCurrentThread();\n\tcurl->curlThread = currentThread;\n\n\t// cemuLog_logDebug(LogType::Force, \"CURRENTTHREAD: 0x{} -> {}\",currentThread, order)\n\n\tPPCConcurrentQueue<QueueMsg_t> callerQueue;\n\tConcurrentQueue<QueueMsg_t> threadQueue;\n\tstd::thread worker(CurlWorkerThread, curl, &callerQueue, &threadQueue);\n\tworker.detach();\n\n\tQueueMsg_t orderMsg = {};\n\torderMsg.order = order;\n\n\tif (order == QueueOrder_Pause)\n\t\torderMsg.pause.bitmask = arg1;\n\n\tthreadQueue.push(orderMsg);\n\n\tuint32 result;\n\twhile (true)\n\t{\n\t\tconst QueueMsg_t msg = callerQueue.pop(currentThread);\n\t\tif (msg.order == QueueOrder_ProgressCB)\n\t\t{\n\t\t\tQueueMsg_t sendMsg = {};\n\t\t\tsendMsg.order = QueueOrder_CBDone;\n\t\t\tsendMsg.result = PPCCoreCallback(curl->fprogress.GetMPTR(), curl->progress_client.GetMPTR(), msg.progress_cb.dltotal, msg.progress_cb.dlnow, msg.progress_cb.ultotal, msg.progress_cb.ulnow);\n\t\t\tthreadQueue.push(sendMsg);\n\t\t}\n\t\telse if (msg.order == QueueOrder_HeaderCB)\n\t\t{\n\t\t\tStackAllocator<char> tmp(msg.header_cb.size * msg.header_cb.nitems);\n\t\t\tmemcpy(tmp.GetPointer(), msg.header_cb.buffer, msg.header_cb.size * msg.header_cb.nitems);\n\n\t\t\tQueueMsg_t sendMsg = {};\n\t\t\tsendMsg.order = QueueOrder_CBDone;\n\t\t\tsendMsg.result = PPCCoreCallback(curl->fwrite_header.GetMPTR(), tmp.GetMPTR(), msg.header_cb.size, msg.header_cb.nitems, curl->writeheader.GetMPTR());\n\t\t\tthreadQueue.push(sendMsg);\n\t\t}\n\t\telse if (msg.order == QueueOrder_ReadCB)\n\t\t{\n\t\t\tStackAllocator<char> tmp(msg.read_cb.size * msg.read_cb.nitems);\n\n\t\t\tQueueMsg_t sendMsg = {};\n\t\t\tsendMsg.order = QueueOrder_CBDone;\n\t\t\tcemuLog_logDebug(LogType::Force, \"QueueOrder_ReadCB size: {} nitems: {}\", msg.read_cb.size, msg.read_cb.nitems);\n\t\t\tsendMsg.result = PPCCoreCallback(curl->fread_func_set.GetMPTR(), tmp.GetMPTR(), msg.read_cb.size, msg.read_cb.nitems, curl->in_set.GetMPTR());\n\t\t\tcemuLog_logDebug(LogType::Force, \"readcb size: {}\", (sint32)sendMsg.result);\n\t\t\tif (sendMsg.result > 0)\n\t\t\t\tmemcpy(msg.read_cb.buffer, tmp.GetPointer(), sendMsg.result);\n\n\t\t\tthreadQueue.push(sendMsg);\n\t\t}\n\t\telse if (msg.order == QueueOrder_WriteCB)\n\t\t{\n\t\t\tStackAllocator<char> tmp(msg.write_cb.size * msg.write_cb.nmemb);\n\t\t\tmemcpy(tmp.GetPointer(), msg.write_cb.buffer, msg.write_cb.size * msg.write_cb.nmemb);\n\n\t\t\tQueueMsg_t sendMsg = {};\n\t\t\tsendMsg.order = QueueOrder_CBDone;\n\t\t\tsendMsg.result = PPCCoreCallback(curl->fwrite_func.GetMPTR(), tmp.GetMPTR(), msg.write_cb.size, msg.write_cb.nmemb, curl->out.GetMPTR());\n\t\t\tthreadQueue.push(sendMsg);\n\t\t}\n\t\telse if (msg.order == QueueOrder_Result)\n\t\t{\n\t\t\tresult = msg.result;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nstatic int curl_closesocket(void *clientp, curl_socket_t item)\n{\n\tnsysnet_notifyCloseSharedSocket((SOCKET)item);\n\tclosesocket(item);\n\treturn 0;\n}\n\nvoid _curl_set_default_parameters(CURL_t* curl)\n{\n\tcurl->set.SetToDefault();\n\n\t// default parameters\n\tcurl_easy_setopt(curl->curl, CURLOPT_HEADERFUNCTION, header_callback);\n\tcurl_easy_setopt(curl->curl, CURLOPT_HEADERDATA, curl);\n\n\tcurl_easy_setopt(curl->curl, CURLOPT_CLOSESOCKETFUNCTION, curl_closesocket);\n\tcurl_easy_setopt(curl->curl, CURLOPT_CLOSESOCKETDATA, nullptr);\n}\n\nvoid _curl_sync_parameters(CURL_t* curl)\n{\n\t// sync ppc curl to actual curl state\n\t// not all parameters are covered yet, many are still set directly in easy_setopt\n\tbool isPost = curl->set.httpreq_1EC == WU_HTTPREQ::HTTPREQ_POST;\n\t// http request type\n\tif(curl->set.httpreq_1EC == WU_HTTPREQ::HTTPREQ_GET)\n\t{\n\t\t::curl_easy_setopt(curl->curl, CURLOPT_HTTPGET, 1);\n\t\tcemu_assert_debug(curl->opt_no_body_281 == 0);\n\t\tcemu_assert_debug(curl->upload_283 == 0);\n\t}\n\telse if(curl->set.httpreq_1EC == WU_HTTPREQ::HTTPREQ_POST)\n\t{\n\t\t::curl_easy_setopt(curl->curl, CURLOPT_POST, 1);\n\t\tcemu_assert_debug(curl->upload_283 == 0);\n\t\t::curl_easy_setopt(curl->curl, CURLOPT_NOBODY, curl->opt_no_body_281 ? 1 : 0);\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\t// CURLOPT_HTTPHEADER\n\tstd::optional<uint64> manualHeaderContentLength;\n\tif (curl->set.headers)\n\t{\n\t\tstruct curl_slist* list = nullptr;\n\t\tWU_curl_slist* ppcList = curl->set.headers;\n\t\twhile(ppcList)\n\t\t{\n\t\t\tif(isPost)\n\t\t\t{\n\t\t\t\t// for recent libcurl manually adding Content-Length header is undefined behavior. Instead CURLOPT_INFILESIZE(_LARGE) should be set\n\t\t\t\t// here we remove Content-Length and instead substitute it with CURLOPT_INFILESIZE (NEX DataStore in Super Mario Maker requires this)\n\t\t\t\tif(strncmp(ppcList->data.GetPtr(), \"Content-Length:\", 15) == 0)\n\t\t\t\t{\n\t\t\t\t\tmanualHeaderContentLength = std::stoull(ppcList->data.GetPtr() + 15);\n\t\t\t\t\tppcList = ppcList->next;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcemuLog_logDebug(LogType::Force, \"curl_slist_append: {}\", ppcList->data.GetPtr());\n\t\t\tcurlDebug_logEasySetOptStr(curl, \"CURLOPT_HTTPHEADER\", (const char*)ppcList->data.GetPtr());\n\t\t\tlist = ::curl_slist_append(list, ppcList->data.GetPtr());\n\t\t\tppcList = ppcList->next;\n\t\t}\n\t\t::curl_easy_setopt(curl->curl, CURLOPT_HTTPHEADER, list);\n\t\t// todo - prevent leaking of list (maybe store in host curl object, similar to how our zlib implementation does stuff)\n\t}\n\telse\n\t\t::curl_easy_setopt(curl->curl, CURLOPT_HTTPHEADER, nullptr);\n\n\t// infile size (post data size)\n\tif (curl->set.infilesize_190)\n\t{\n\t\tcemu_assert_debug(manualHeaderContentLength == 0); // should not have both?\n\t\t::curl_easy_setopt(curl->curl, CURLOPT_INFILESIZE_LARGE, curl->set.infilesize_190);\n\t}\n\telse\n\t{\n\t\tif(isPost && manualHeaderContentLength > 0)\n\t\t\t::curl_easy_setopt(curl->curl, CURLOPT_INFILESIZE_LARGE, manualHeaderContentLength);\n\t\telse\n\t\t\t::curl_easy_setopt(curl->curl, CURLOPT_INFILESIZE_LARGE, 0);\n\t}\n}\n\nvoid export_malloc(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(size, 0);\n\tMPTR memAddr = PPCCoreCallback(gCoreinitData->MEMAllocFromDefaultHeap, size);\n\tosLib_returnFromFunction(hCPU, memAddr);\n}\n\nvoid export_calloc(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(count, 0);\n\tppcDefineParamU32(size, 1);\n\n\tMPTR memAddr = PPCCoreCallback(gCoreinitData->MEMAllocFromDefaultHeap, count*size);\n\n\tosLib_returnFromFunction(hCPU, memAddr);\n}\nvoid export_free(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(mem, void, 0);\n\tPPCCoreCallback(gCoreinitData->MEMFreeToDefaultHeap, mem.GetMPTR());\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\nvoid export_strdup(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(str, const char, 0);\n\tint len = (int)strlen(str.GetPtr()) + 1;\n\tMEMPTR<char> result = (char*)coreinit::default_MEMAllocFromDefaultHeap(len);\n\tstrcpy(result.GetPtr(), str.GetPtr());\n\tosLib_returnFromFunction(hCPU, result.GetMPTR());\n}\n\nvoid export_realloc(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(mem, void, 0);\n\tppcDefineParamU32(size, 1);\n\tMEMPTR<void> result = coreinit::default_MEMAllocFromDefaultHeap(size);\n\tmemcpy(result.GetPtr(), mem.GetPtr(), size);\n\tcoreinit::default_MEMFreeToDefaultHeap(mem.GetPtr());\n\tosLib_returnFromFunction(hCPU, result.GetMPTR());\n}\n\nCURLcode curl_global_init(uint32 flags)\n{\n\tif (g_nlibcurl.initialized++)\n\t{\n\t\treturn CURLE_OK;\n\t}\n\n\tg_nlibcurl.malloc = PPCInterpreter_makeCallableExportDepr(export_malloc);\n\tg_nlibcurl.calloc = PPCInterpreter_makeCallableExportDepr(export_calloc);\n\tg_nlibcurl.free = PPCInterpreter_makeCallableExportDepr(export_free);\n\tg_nlibcurl.strdup = PPCInterpreter_makeCallableExportDepr(export_strdup);\n\tg_nlibcurl.realloc = PPCInterpreter_makeCallableExportDepr(export_realloc);\n\n\t// curl_read_default_proxy_config()\n\n\treturn ::curl_global_init(flags);\n}\n\nvoid export_curl_multi_init(PPCInterpreter_t* hCPU)\n{\n\tCURLMPtr result{ PPCCoreCallback(g_nlibcurl.calloc, 1, ppcsizeof<CURLM_t>()) };\n\tcemuLog_logDebug(LogType::Force, \"curl_multi_init() -> 0x{:08x}\", result.GetMPTR());\n\tif (result)\n\t{\n\t\tmemset(result.GetPtr(), 0, sizeof(CURLM_t));\n\t\t*result = {};\n\t\tresult->curlm = curl_multi_init();\n\t}\n\n\tosLib_returnFromFunction(hCPU, result.GetMPTR());\n}\n\nvoid export_curl_multi_add_handle(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curlm, CURLM_t, 0);\n\tppcDefineParamMEMPTR(curl, CURL_t, 1);\n\n\tcurlDebug_markActiveRequest(curl.GetPtr());\n\tcurlDebug_notifySubmitRequest(curl.GetPtr());\n\n\tCURLMcode result = ::curl_multi_add_handle(curlm->curlm, curl->curl);\n\tif (result == CURLM_OK)\n\t\tcurlm->curl.push_back(curl.GetPtr());\n\n\tcemuLog_logDebug(LogType::Force, \"curl_multi_add_handle(0x{:08x}, 0x{:08x}) -> 0x{:x}\", curlm.GetMPTR(), curl.GetMPTR(), result);\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid export_curl_multi_remove_handle(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curlm, CURLM_t, 0);\n\tppcDefineParamMEMPTR(curl, CURL_t, 1);\n\n\tCURLMcode result = curl_multi_remove_handle(curlm->curlm, curl->curl);\n\n\tif (result == CURLM_OK)\n\t{\n\t\tcurlm->curl.erase(std::remove(curlm->curl.begin(), curlm->curl.end(), (void*)curl.GetPtr()), curlm->curl.end());\n\t}\n\n\tcemuLog_logDebug(LogType::Force, \"curl_multi_remove_handle(0x{:08x}, 0x{:08x}) -> 0x{:x}\", curlm.GetMPTR(), curl.GetMPTR(), result);\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid export_curl_multi_timeout(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curlm, CURLM_t, 0);\n\tppcDefineParamMEMPTR(timeoParam, uint32be, 1);\n\n\tlong timeoutLE = (long)(uint32)*timeoParam;\n\n\tCURLMcode result = ::curl_multi_timeout(curlm->curlm, &timeoutLE);\n\t*timeoParam = (uint32)timeoutLE;\n\n\tcemuLog_logDebug(LogType::Force, \"curl_multi_timeout(0x{:08x}, 0x{:08x} [{}]) -> 0x{:x}\", curlm.GetMPTR(), timeoParam.GetMPTR(), timeoutLE, result);\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid export_curl_multi_cleanup(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curlm, CURLM_t, 0);\n\tCURLMcode result = ::curl_multi_cleanup(curlm->curlm);\n\tcemuLog_logDebug(LogType::Force, \"curl_multi_cleanup(0x{:08x}) -> 0x{:x}\", curlm.GetMPTR(), result);\n\tcurlm->curl.clear();\n\tPPCCoreCallback(g_nlibcurl.free.GetMPTR(), curlm.GetMPTR());\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid export_curl_multi_perform(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curlm, CURLM_t, 0);\n\tppcDefineParamMEMPTR(runningHandles, uint32be, 1);\n\n\t//cemuLog_logDebug(LogType::Force, \"curl_multi_perform(0x{:08x}, 0x{:08x})\", curlm.GetMPTR(), runningHandles.GetMPTR());\n\n\t//curl_multi_get_handles(curlm->curlm);\n\n\tfor(auto _curl : curlm->curl)\n\t{\n\t\tCURL_t* curl = (CURL_t*)_curl.GetPtr();\n\t\tif(curl->isDirty)\n\t\t{\n\t\t\tcurl->isDirty = false;\n\t\t\t_curl_sync_parameters(curl);\n\t\t}\n\t}\n\n\t//g_callerQueue = curlm->callerQueue;\n\t//g_threadQueue = curlm->threadQueue;\n\tint tempRunningHandles = 0;\n\tCURLMcode result = curl_multi_perform(curlm->curlm, &tempRunningHandles);\n\t*(runningHandles.GetPtr()) = tempRunningHandles;\n\tcemuLog_logDebug(LogType::Force, \"curl_multi_perform(0x{:08x}, 0x{:08x}) -> 0x{:x} (running handles: {})\", curlm.GetMPTR(), runningHandles.GetMPTR(), result, tempRunningHandles);\n\t//const uint32 result = SendOrderToWorker(curlm.GetPtr(), QueueOrder_MultiPerform);\n\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid export_curl_multi_fdset(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curlm, CURLM_t, 0);\n\tppcDefineParamMEMPTR(readFd, wu_fd_set, 1);\n\tppcDefineParamMEMPTR(writeFd, wu_fd_set, 2);\n\tppcDefineParamMEMPTR(exceptionFd, wu_fd_set, 3);\n\tppcDefineParamU32BEPtr(maxFd, 4);\n\n\tfd_set h_readFd;\n\tfd_set h_writeFd;\n\tfd_set h_exceptionFd;\n\tFD_ZERO(&h_readFd);\n\tFD_ZERO(&h_writeFd);\n\tFD_ZERO(&h_exceptionFd);\n\tsint32 h_maxFd = 0;\n\n\tCURLMcode result = curl_multi_fdset(curlm->curlm, &h_readFd, &h_writeFd, &h_exceptionFd, &h_maxFd);\n\n\tnsysnet::wuResetFD(readFd.GetPtr());\n\tnsysnet::wuResetFD(writeFd.GetPtr());\n\tnsysnet::wuResetFD(exceptionFd.GetPtr());\n\n\tsint32 c_maxFD = -1;\n\n\tauto hostFdSet = [&](SOCKET s, wu_fd_set* fds)\n\t{\n\t\tsint32 wuSocket = nsysnet_getVirtualSocketHandleFromHostHandle(s);\n\t\tif (wuSocket < 0)\n\t\t\twuSocket = nsysnet_createVirtualSocketFromExistingSocket(s);\n\t\tif (wuSocket >= 0)\n\t\t{\n\t\t\tc_maxFD = std::max(wuSocket, c_maxFD);\n\t\t\tnsysnet::wuSetFD(fds, wuSocket);\n\t\t}\n\t};\n\n#if BOOST_OS_UNIX\n\tfor (int s = 0; s < h_maxFd + 1; s++) \n\t{\n\t\tif(FD_ISSET(s, &h_readFd))\n\t\t\thostFdSet(s, readFd.GetPtr());\n\n\t\tif(FD_ISSET(s, &h_writeFd))\n\t\t\thostFdSet(s, writeFd.GetPtr());\n\n\t\tif(FD_ISSET(s, &h_exceptionFd))\n\t\t\thostFdSet(s, exceptionFd.GetPtr());\n\t}\n#else\n\t// fd read set\n\tfor (uint32 i = 0; i < h_readFd.fd_count; i++)\n\t{\n\t\thostFdSet(h_readFd.fd_array[i], readFd.GetPtr());\n\t}\n\t// fd write set\n\tfor (uint32 i = 0; i < h_writeFd.fd_count; i++)\n\t{\n\t\thostFdSet(h_writeFd.fd_array[i], writeFd.GetPtr());\n\t}\n\t// fd exception set\n\tfor (uint32 i = 0; i < h_exceptionFd.fd_count; i++)\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n#endif\n\n\t*maxFd = c_maxFD;\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid export_curl_multi_setopt(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curlm, CURLM_t, 0);\n\tppcDefineParamU32(option, 1);\n\tppcDefineParamMEMPTR(parameter, void, 2);\n\tppcDefineParamU64(parameterU64, 2);\n\n\tCURLMcode result = CURLM_OK;\n\tswitch (option)\n\t{\n\tcase CURLMOPT_MAXCONNECTS:\n\t\tresult = ::curl_multi_setopt(curlm->curlm, (CURLMoption)option, parameter.GetMPTR());\n\t\tbreak;\n\tdefault:\n\t\tcemuLog_logDebug(LogType::Force, \"curl_multi_setopt(0x{:08x}, {}, 0x{:08x}) unsupported option\", curlm.GetMPTR(), option, parameter.GetMPTR());\n\t}\n\n\tcemuLog_logDebug(LogType::Force, \"curl_multi_setopt(0x{:08x}, {}, 0x{:08x}) -> 0x{:x}\", curlm.GetMPTR(), option, parameter.GetMPTR(), result);\n\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid export_curl_multi_info_read(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curlm, CURLM_t, 0);\n\tppcDefineParamMEMPTR(msgsInQueue, int, 1);\n\n\tCURLMsg* msg = ::curl_multi_info_read(curlm->curlm, msgsInQueue.GetPtr());\n\n\tcemuLog_logDebug(LogType::Force, \"curl_multi_info_read - todo\");\n\tif (msg)\n\t{\n\t\tMEMPTR<CURLMsg_t> result{ PPCCoreCallback(g_nlibcurl.malloc.GetMPTR(), ppcsizeof<CURLMsg_t>()) };\n\t\tresult->msg = msg->msg;\n\t\tresult->result = msg->data.result;\n\t\tif (msg->easy_handle)\n\t\t{\n\t\t\tconst auto it = find_if(curlm->curl.cbegin(), curlm->curl.cend(),\n\t\t\t\t[msg](const MEMPTR<CURL_t>& curl)\n\t\t\t{\n\t\t\t\tconst MEMPTR<CURL_t> _curl{ curl };\n\t\t\t\treturn _curl->curl = msg->easy_handle;\n\t\t\t});\n\n\t\t\tif (it != curlm->curl.cend())\n\t\t\t\tresult->curl = (CURL_t*)(*it).GetPtr();\n\n\t\t}\n\t\telse\n\t\t\tresult->curl = nullptr;\n\n\t\tcemuLog_logDebug(LogType::Force, \"curl_multi_info_read(0x{:08x}, 0x{:08x} [{}]) -> 0x{:08x} (0x{:x}, 0x{:08x}, 0x{:x})\", curlm.GetMPTR(), msgsInQueue.GetMPTR(), *msgsInQueue.GetPtr(),\t\t\t\n\t\t\tresult.GetMPTR(), msg->msg, result->curl.GetMPTR(), msg->data.result);\n\t\tosLib_returnFromFunction(hCPU, result.GetMPTR());\n\t}\n\telse\n\t{\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n}\n\nvoid lock_function(CURL* handle, curl_lock_data data, curl_lock_access access, void* userptr)\n{\n\tCURLSH_t* share = (CURLSH_t*)userptr;\n\tPPCCoreCallback(share->lockfunc.GetMPTR(), share->curl.GetMPTR(), (uint32)data, (uint32)access, share->data.GetMPTR());\n}\n\nvoid unlock_function(CURL* handle, curl_lock_data data, void* userptr)\n{\n\tCURLSH_t* share = (CURLSH_t*)userptr;\n\tPPCCoreCallback(share->unlockfunc.GetMPTR(), share->curl.GetMPTR(), (uint32)data, share->data.GetMPTR());\n}\n\nvoid export_curl_share_setopt(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(share, CURLSH_t, 0);\n\tppcDefineParamU32(option, 1);\n\tppcDefineParamMEMPTR(parameter, void, 2);\n\n\t/*if(share->dirty)\n\t{\n\t\tosLib_returnFromFunction(hCPU, CURLSHE_IN_USE);\n\t\treturn;\n\t}*/\n\n\tCURLSH* curlSh = share->curlsh;\n\n\tCURLSHcode result = CURLSHE_OK;\n\tswitch (option)\n\t{\n\t\tcase CURLSHOPT_USERDATA:\n\t\t\tshare->data = parameter;\n\t\t\tresult = curl_share_setopt(curlSh, CURLSHOPT_USERDATA, share.GetPtr());\n\t\t\tbreak;\n\t\tcase CURLSHOPT_LOCKFUNC:\n\t\t\tshare->lockfunc = parameter;\n\t\t\tresult = curl_share_setopt(curlSh, CURLSHOPT_LOCKFUNC, lock_function);\n\t\t\tbreak;\n\t\tcase CURLSHOPT_UNLOCKFUNC:\n\t\t\tshare->unlockfunc = parameter;\n\t\t\tresult = curl_share_setopt(curlSh, CURLSHOPT_UNLOCKFUNC, unlock_function);\n\t\t\tbreak;\n\t\tcase CURLSHOPT_SHARE:\n\t\t{\n\t\t\tconst sint32 type = parameter.GetMPTR();\n\t\t\tresult = curl_share_setopt(curlSh, CURLSHOPT_SHARE, type);\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLSHOPT_UNSHARE:\n\t\t{\n\t\t\tconst sint32 type = parameter.GetMPTR();\n\t\t\tresult = curl_share_setopt(curlSh, CURLSHOPT_UNSHARE, type);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tcemu_assert_unimplemented();\n\t}\n\tcemuLog_logDebug(LogType::Force, \"curl_share_setopt(0x{:08x}, 0x{:x}, 0x{:08x}) -> 0x{:x}\", share.GetMPTR(), option, parameter.GetMPTR(), result);\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid export_curl_share_init(PPCInterpreter_t* hCPU)\n{\n\tCURLSHPtr result{ PPCCoreCallback(g_nlibcurl.calloc.GetMPTR(), (uint32)1, ppcsizeof<CURLSH_t>()) };\n\tcemuLog_logDebug(LogType::Force, \"curl_share_init() -> 0x{:08x}\", result.GetMPTR());\n\tif (result)\n\t{\n\t\tmemset(result.GetPtr(), 0, sizeof(CURLSH_t));\n\t\t*result = {};\n\t\tresult->curlsh = curl_share_init();\n\t}\n\n\tosLib_returnFromFunction(hCPU, result.GetMPTR());\n}\n\nvoid export_curl_share_cleanup(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curlsh, CURLSH_t, 0);\n\tuint32 result = ::curl_share_cleanup(curlsh->curlsh);\n\tcemuLog_logDebug(LogType::Force, \"curl_share_cleanup(0x{:08x}) -> 0x{:x}\", curlsh.GetMPTR(), result);\n\tPPCCoreCallback(g_nlibcurl.free.GetMPTR(), curlsh.GetMPTR());\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nCURL_t* curl_easy_init()\n{\n\tif (g_nlibcurl.initialized == 0)\n\t{\n\t\tif (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK)\n\t\t{\n\t\t\treturn nullptr;\n\t\t}\n\t}\n\n\t// Curl_open\n\tMEMPTR<CURL_t> result{ PPCCoreCallback(g_nlibcurl.calloc.GetMPTR(), (uint32)1, ppcsizeof<CURL_t>()) };\n\tcemuLog_logDebug(LogType::Force, \"curl_easy_init() -> 0x{:08x}\", result.GetMPTR());\n\tif (result)\n\t{\n\t\tmemset(result.GetPtr(), 0, sizeof(CURL_t));\n\t\t*result = {};\n\t\tresult->curl = ::curl_easy_init();\n\t\tresult->curlThread = coreinit::OSGetCurrentThread();\n\n\t\tresult->info_contentType = nullptr;\n\t\tresult->info_redirectUrl = nullptr;\n\n\t\t_curl_set_default_parameters(result.GetPtr());\n\n\t\tif (g_nlibcurl.proxyConfig)\n\t\t{\n\t\t\t// todo\n\t\t}\n\t}\n\n\treturn result;\n}\n\nCURL_t* mw_curl_easy_init()\n{\n\treturn curl_easy_init();\n}\n\nvoid export_curl_easy_pause(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curl, CURL_t, 0);\n\tppcDefineParamS32(bitmask, 1);\n\tcemuLog_logDebug(LogType::Force, \"curl_easy_pause(0x{:08x}, 0x{:x})\", curl.GetMPTR(), bitmask);\n\n\t//const CURLcode result = ::curl_easy_pause(curl->curl, bitmask);\n\tconst uint32 result = SendOrderToWorker(curl.GetPtr(), QueueOrder_Pause, bitmask);\n\tcemuLog_logDebug(LogType::Force, \"curl_easy_pause(0x{:08x}, 0x{:x}) DONE\", curl.GetMPTR(), bitmask);\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid export_curl_easy_cleanup(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curl, CURL_t, 0);\n\tcemuLog_logDebug(LogType::Force, \"curl_easy_cleanup(0x{:08x})\", curl.GetMPTR());\n\n\tcurlDebug_cleanup(curl.GetPtr());\n\n\t::curl_easy_cleanup(curl->curl);\n\tPPCCoreCallback(g_nlibcurl.free.GetMPTR(), curl.GetMPTR());\n\n\tif (curl->info_contentType.IsNull() == false)\n\t\tPPCCoreCallback(g_nlibcurl.free.GetMPTR(), curl->info_contentType.GetMPTR());\n\tif (curl->info_redirectUrl.IsNull() == false)\n\t\tPPCCoreCallback(g_nlibcurl.free.GetMPTR(), curl->info_redirectUrl.GetMPTR());\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid export_curl_easy_reset(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curl, CURL_t, 0);\n\tcemuLog_logDebug(LogType::Force, \"curl_easy_reset(0x{:08x})\", curl.GetMPTR());\n\t// curl_apply_default_proxy_config();\n\t::curl_easy_reset(curl->curl);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nint ssl_verify_callback(int preverify_ok, X509_STORE_CTX* ctx)\n{\n\tif (preverify_ok) return preverify_ok;\n\tint err = X509_STORE_CTX_get_error(ctx);\n\tif(err != 0)\n\t\tcemuLog_logDebug(LogType::Force, \"ssl_verify_callback: Error {} but allow certificate anyway\", err);\n\tX509_STORE_CTX_set_error(ctx, 0);\n\treturn 1;\n}\n\nCURLcode ssl_ctx_callback(CURL* curl, void* sslctx, void* param)\n{\n\t//peterBreak();\n\tCURL_t* ppcCurl = (CURL_t*)param;\n\tnsysnet::NSSLInternalState_t* nssl = nsysnet::GetNSSLContext((uint32)ppcCurl->hNSSL);\n\n\tfor (uint32 i : nssl->serverPKIs)\n\t{\n\t\tif (iosuCrypto_addCACertificate(sslctx, i) == false)\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t\treturn CURLE_SSL_CACERT;\n\t\t}\n\t}\n\tfor (auto& customPKI : nssl->serverCustomPKIs)\n\t{\n\t\tif (iosuCrypto_addCustomCACertificate(sslctx, &customPKI[0], (sint32)customPKI.size()) == false)\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t\treturn CURLE_SSL_CACERT;\n\t\t}\n\t}\n\n\tif (nssl->clientPKI != 0 && iosuCrypto_addClientCertificate(sslctx, nssl->clientPKI) == false)\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn CURLE_SSL_CERTPROBLEM;\n\t}\n\n\tuint32 flags = ppcCurl->nsslVerifyOptions;\n\tif (HAS_FLAG(flags, NSSL_VERIFY_PEER))\n\t{\n\t\t::SSL_CTX_set_cipher_list((SSL_CTX*)sslctx, \"AES256-SHA\"); // TLS_RSA_WITH_AES_256_CBC_SHA (in CURL it's called rsa_aes_256_sha)\n\t\t::SSL_CTX_set_mode((SSL_CTX*)sslctx, SSL_MODE_AUTO_RETRY);\n\t\t::SSL_CTX_set_verify_depth((SSL_CTX*)sslctx, 2);\n\t\t::SSL_CTX_set_verify((SSL_CTX*)sslctx, SSL_VERIFY_PEER, ssl_verify_callback);\n\t}\n\telse\n\t{\n\t\t::SSL_CTX_set_verify((SSL_CTX*)sslctx, SSL_VERIFY_NONE, nullptr);\n\t}\n\t\n\treturn CURLE_OK;\n}\n\nsize_t header_callback(char* buffer, size_t size, size_t nitems, void* userdata)\n{\n\t//peterBreak();\n\tCURL_t* curl = (CURL_t*)userdata;\n\n\tcurlDebug_headerWrite(curl, buffer, size, nitems);\n\n\tif (curl->fwrite_header.IsNull())\n\t{\n\t\treturn size * nitems;\n\t}\n\n\tif (g_callerQueue == nullptr || g_threadQueue == nullptr)\n\t{\n\t\tStackAllocator<char> tmp((uint32)(size * nitems));\n\t\tmemcpy(tmp.GetPointer(), buffer, size * nitems);\n\t\treturn PPCCoreCallback(curl->fwrite_header.GetMPTR(), tmp.GetMPTR(), (uint32)size, (uint32)nitems, curl->writeheader.GetMPTR());\n\t}\n\n\tQueueMsg_t msg = {};\n\tmsg.order = QueueOrder_HeaderCB;\n\tmsg.header_cb.buffer = buffer;\n\tmsg.header_cb.size = (uint32)size;\n\tmsg.header_cb.nitems = (uint32)nitems;\n\tg_callerQueue->push(msg, curl->curlThread);\n\n\tmsg = g_threadQueue->pop();\n\tif (msg.order != QueueOrder_CBDone)\n\t\tcemu_assert_suspicious();\n\n#ifdef CEMU_DEBUG_ASSERT\n\tchar debug[500];\n\tcemu_assert_debug((size*nitems) < 500);\n\tmemcpy(debug, buffer, size*nitems);\n\tdebug[size*nitems] = 0;\n\tcemuLog_logDebug(LogType::Force, \"header_callback(0x{}, 0x{:x}, 0x{:x}, 0x{:08x}) [{}]\", (void*)buffer, size, nitems, curl->writeheader.GetMPTR(), debug);\n#endif\n\treturn msg.result;\n}\n\nsize_t write_callback(char* ptr, size_t size, size_t nmemb, void* userdata)\n{\n\tCURL_t* curl = (CURL_t*)userdata;\n\n\tcurlDebug_resultWrite(curl, ptr, size, nmemb);\n\t//StackAllocator<char> tmp(size * nmemb);\n\t//memcpy(tmp.GetPointer(), ptr, size * nmemb);\n\n\tcemuLog_logDebug(LogType::Force, \"write_callback(0x{} 0x{:x}, 0x{:x}, 0x{:08x})\", (void*)ptr, size, nmemb, curl->out.GetMPTR());\n\n\tif (g_callerQueue == nullptr || g_threadQueue == nullptr)\n\t{\n\t\tStackAllocator<char> tmp((uint32)(size * nmemb));\n\t\tmemcpy(tmp.GetPointer(), ptr, size * nmemb);\n\t\tint r = PPCCoreCallback(curl->fwrite_func.GetMPTR(), tmp.GetMPTR(), (uint32)size, (uint32)nmemb, curl->out.GetMPTR());\n\t\treturn r;\n\t}\n\n\tQueueMsg_t msg = {};\n\tmsg.order = QueueOrder_WriteCB;\n\tmsg.write_cb.buffer = ptr;\n\tmsg.write_cb.size = (uint32)size;\n\tmsg.write_cb.nmemb = (uint32)nmemb;\n\tg_callerQueue->push(msg, curl->curlThread);\n\n\tmsg = g_threadQueue->pop();\n\tif (msg.order != QueueOrder_CBDone)\n\t\tcemu_assert_suspicious();\n\n\treturn msg.result;\n}\n\nint sockopt_callback(void* clientp, curl_socket_t curlfd, curlsocktype purpose)\n{\n\tCURL_t* curl = (CURL_t*)clientp;\n\n\tcemuLog_logDebug(LogType::Force, \"sockopt_callback called!\");\n\n\tsint32 r = 0;\n\n\treturn r;\n}\n\nsize_t read_callback(char* buffer, size_t size, size_t nitems, void* instream)\n{\t\n\tnitems = std::min<uint32>(nitems, 0x4000);\n\tCURL_t* curl = (CURL_t*)instream;\n\n\tcemuLog_logDebug(LogType::Force, \"read_callback(0x{}, 0x{:x}, 0x{:x}, 0x{:08x}) [func: 0x{:x}]\", (void*)buffer, size, nitems, curl->in_set.GetMPTR(), curl->fread_func_set.GetMPTR());\n\n\tif (g_callerQueue == nullptr || g_threadQueue == nullptr)\n\t{\n\t\tStackAllocator<char> tmp((uint32)(size * nitems));\n\t\tconst sint32 result = PPCCoreCallback(curl->fread_func_set.GetMPTR(), tmp.GetMPTR(), (uint32)size, (uint32)nitems, curl->in_set.GetMPTR());\n\t\tmemcpy(buffer, tmp.GetPointer(), result);\n\t\treturn result;\n\t}\n\n\tQueueMsg_t msg = {};\n\tmsg.order = QueueOrder_ReadCB;\n\tmsg.read_cb.buffer = buffer;\n\tmsg.read_cb.size = (uint32)size;\n\tmsg.read_cb.nitems = (uint32)std::min<uint32>(nitems, 0x4000); // limit this to 16KB which is the limit in nlibcurl.rpl (Super Mario Maker crashes on level upload if the size is too big)\n\n\tcemuLog_logDebug(LogType::Force, \"read_callback(0x{}, 0x{:x}, 0x{:x}, 0x{:08x}) [func: 0x{:x}] PUSH\", (void*)buffer, size, nitems, curl->in_set.GetMPTR(), curl->fread_func_set.GetMPTR());\n\tg_callerQueue->push(msg, curl->curlThread);\n\n\tmsg = g_threadQueue->pop();\n\tif (msg.order != QueueOrder_CBDone)\n\t\tcemu_assert_suspicious();\n\n\tcemuLog_logDebug(LogType::Force, \"read_callback(0x{}, 0x{:x}, 0x{:x}, 0x{:08x}) DONE Result: {}\", (void*)buffer, size, nitems, curl->in_set.GetMPTR(), msg.result);\n\n\treturn msg.result;\n}\n\n\nint progress_callback(void* clientp, double dltotal, double dlnow, double ultotal, double ulnow)\n{\n\t//peterBreak();\n\tCURL_t* curl = (CURL_t*)clientp;\n\t//int result = PPCCoreCallback(curl->fprogress.GetMPTR(), curl->progress_client.GetMPTR(), dltotal, dlnow, ultotal, ulnow);\n\tif(g_callerQueue == nullptr || g_threadQueue == nullptr)\n\t\treturn PPCCoreCallback(curl->fprogress.GetMPTR(), curl->progress_client.GetMPTR(), dltotal, dlnow, ultotal, ulnow);\n\n\tQueueMsg_t msg = {};\n\tmsg.order = QueueOrder_ProgressCB;\n\tmsg.progress_cb.dltotal = dltotal;\n\tmsg.progress_cb.dlnow = dlnow;\n\tmsg.progress_cb.ultotal = ultotal;\n\tmsg.progress_cb.ulnow = ulnow;\n\tg_callerQueue->push(msg, curl->curlThread);\n\n\tmsg = g_threadQueue->pop();\n\tif (msg.order != QueueOrder_CBDone)\n\t\tcemu_assert_suspicious();\n\t\n\tcemuLog_logDebug(LogType::Force, \"progress_callback({:.02}, {:.02}, {:.02}, {:.02}) -> {}\", dltotal, dlnow, ultotal, ulnow, msg.result);\n\treturn msg.result;\n}\n\nvoid export_curl_easy_setopt(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curl, CURL_t, 0);\n\tppcDefineParamU32(option, 1);\n\tppcDefineParamMEMPTR(parameter, void, 2);\n\tppcDefineParamU64(parameterU64, 2);\n\n\tCURL* curlObj = curl->curl;\n\tcurl->isDirty = true;\n\n\tCURLcode result = CURLE_OK;\n\tswitch (option)\n\t{\n\t\tcase CURLOPT_POST:\n\t\t{\n\t\t\tif(parameter)\n\t\t\t{\n\t\t\t\tcurl->set.httpreq_1EC = WU_HTTPREQ::HTTPREQ_POST;\n\t\t\t\tcurl->opt_no_body_281 = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t\tcurl->set.httpreq_1EC = WU_HTTPREQ::HTTPREQ_GET;\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_HTTPGET:\n\t\t{\n\t\t\tif (parameter)\n\t\t\t{\n\t\t\t\tcurl->set.httpreq_1EC = WU_HTTPREQ::HTTPREQ_GET;\n\t\t\t\tcurl->opt_no_body_281 = 0;\n\t\t\t\tcurl->upload_283 = 0;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_INFILESIZE:\n\t\t{\n\t\t\tcurl->set.infilesize_190 = (sint64)(sint32)(uint32)parameter.GetBEValue();\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_INFILESIZE_LARGE:\n\t\t{\n\t\t\tcurl->set.infilesize_190 = (sint64)(uint64)parameterU64;\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_NOSIGNAL:\n\t\tcase CURLOPT_FOLLOWLOCATION:\n\t\tcase CURLOPT_BUFFERSIZE:\n\t\tcase CURLOPT_TIMEOUT:\n\t\tcase CURLOPT_CONNECTTIMEOUT_MS:\n\t\tcase CURLOPT_NOPROGRESS:\n\t\tcase CURLOPT_LOW_SPEED_LIMIT:\n\t\tcase CURLOPT_LOW_SPEED_TIME:\n\t\tcase CURLOPT_CONNECTTIMEOUT:\n\t\t{\n\t\t\tresult = ::curl_easy_setopt(curlObj, (CURLoption)option, parameter.GetMPTR());\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_URL:\n\t\t{\n\t\t\tcurlDebug_logEasySetOptStr(curl.GetPtr(), \"CURLOPT_URL\", (const char*)parameter.GetPtr());\n\t\t\tcemuLog_logDebug(LogType::Force, \"curl_easy_setopt({}) [{}]\", option, parameter.GetPtr());\n\t\t\tresult = ::curl_easy_setopt(curlObj, (CURLoption)option, parameter.GetPtr());\n\t\t\tbreak;\n\t\t}\n\n\t\tcase CURLOPT_PROXY:\n\t\tcase CURLOPT_USERAGENT:\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"curl_easy_setopt({}) [{}]\", option, parameter.GetPtr());\n\t\t\tresult = ::curl_easy_setopt(curlObj, (CURLoption)option, parameter.GetPtr());\n\t\t\tbreak;\n\t\t}\n\n\t\tcase CURLOPT_POSTFIELDS:\n\t\t{\n\t\t\tcurlDebug_logEasySetOptStr(curl.GetPtr(), \"CURLOPT_POSTFIELDS\", (const char*)parameter.GetPtr());\n\t\t\tcemuLog_logDebug(LogType::Force, \"curl_easy_setopt({}) [{}]\", option, parameter.GetPtr());\n\t\t\tresult = ::curl_easy_setopt(curlObj, (CURLoption)option, parameter.GetPtr());\n\t\t\tbreak;\n\t\t}\n\n\t\tcase CURLOPT_MAX_SEND_SPEED_LARGE:\n\t\tcase CURLOPT_MAX_RECV_SPEED_LARGE:\n\t\tcase CURLOPT_POSTFIELDSIZE_LARGE:\n\t\t{\n\t\t\tresult = ::curl_easy_setopt(curlObj, (CURLoption)option, parameterU64);\n\t\t\tbreak;\n\t\t}\n\t\tcase 211: // verifyOpt\n\t\t{\n\t\t\tuint32 flags = parameter.GetMPTR();\n\t\t\tcurl->nsslVerifyOptions = flags;\n\n\t\t\tif (HAS_FLAG(flags, NSSL_VERIFY_PEER))\n\t\t\t\t::curl_easy_setopt(curlObj, CURLOPT_SSL_VERIFYPEER, 1);\n\t\t\telse\n\t\t\t\t::curl_easy_setopt(curlObj, CURLOPT_SSL_VERIFYPEER, 0);\n\n\t\t\tif (HAS_FLAG(flags, NSSL_VERIFY_HOSTNAME))\n\t\t\t\t::curl_easy_setopt(curlObj, CURLOPT_SSL_VERIFYHOST, 2);\n\t\t\telse\n\t\t\t\t::curl_easy_setopt(curlObj, CURLOPT_SSL_VERIFYHOST, 0);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase 210: // SSL_CONTEXT -> set context created with NSSLCreateContext before\n\t\t{\n\t\t\tconst uint32 nsslIndex = parameter.GetMPTR();\n\n\t\t\tnsysnet::NSSLInternalState_t* nssl = nsysnet::GetNSSLContext(nsslIndex);\n\t\t\tif (nssl)\n\t\t\t{\n\t\t\t\tcurl->hNSSL = nsslIndex;\n\t\t\t\tresult = ::curl_easy_setopt(curlObj, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback);\n\t\t\t\t::curl_easy_setopt(curlObj, CURLOPT_SSL_CTX_DATA, curl.GetPtr());\n\n\t\t\t\tif (nssl->sslVersion == 2)\n\t\t\t\t\t::curl_easy_setopt(curlObj, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3);\n\t\t\t\telse // auto = highest = 0 || 2 for v3\n\t\t\t\t\t::curl_easy_setopt(curlObj, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);\n\t\t\t}\n\t\t\telse\n\t\t\t\tcemu_assert_suspicious();\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_SHARE:\n\t\t{\n\t\t\tCURLSH* shObj = nullptr;\n\t\t\tif (parameter)\n\t\t\t{\n\t\t\t\tauto curlSh = (MEMPTR<CURLSH_t>)parameter;\n\t\t\t\tcurlSh->curl = curl;\n\t\t\t\tshObj = curlSh->curlsh;\n\t\t\t}\n\t\t\tresult = ::curl_easy_setopt(curlObj, CURLOPT_SHARE, shObj);\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_HEADERFUNCTION:\n\t\t{\n\t\t\tcurlDebug_logEasySetOptPtr(curl.GetPtr(), \"CURLOPT_HEADERFUNCTION\", parameter.GetMPTR());\n\t\t\tcurl->fwrite_header = parameter;\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_HEADERDATA:\n\t\t{\n\t\t\tcurlDebug_logEasySetOptPtr(curl.GetPtr(), \"CURLOPT_HEADERDATA\", parameter.GetMPTR());\n\t\t\tcurl->writeheader = parameter;\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_WRITEFUNCTION:\n\t\t{\n\t\t\tcurlDebug_logEasySetOptPtr(curl.GetPtr(), \"CURLOPT_WRITEFUNCTION\", parameter.GetMPTR());\n\t\t\tcurl->fwrite_func = parameter;\n\t\t\tresult = ::curl_easy_setopt(curlObj, CURLOPT_WRITEFUNCTION, write_callback);\n\t\t\t::curl_easy_setopt(curlObj, CURLOPT_WRITEDATA, curl.GetPtr());\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_WRITEDATA: // aka CURLOPT_FILE\n\t\t{\n\t\t\tcurlDebug_logEasySetOptPtr(curl.GetPtr(), \"CURLOPT_WRITEDATA\", parameter.GetMPTR());\n\t\t\tcurl->out = parameter;\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_HTTPHEADER:\n\t\t{\n\t\t\tcurl->set.headers = (WU_curl_slist*)parameter.GetPtr();\n\t\t\tresult = CURLE_OK;\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_SOCKOPTFUNCTION:\n\t\t{\n\t\t\tcurl->fsockopt = parameter;\n\t\t\tresult = ::curl_easy_setopt(curlObj, CURLOPT_SOCKOPTFUNCTION, sockopt_callback);\n\t\t\t::curl_easy_setopt(curlObj, CURLOPT_SOCKOPTDATA, curl.GetPtr());\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_SOCKOPTDATA:\n\t\t{\n\t\t\tcurl->sockopt_client = parameter;\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_READFUNCTION:\n\t\t{\n\t\t\tcurlDebug_logEasySetOptPtr(curl.GetPtr(), \"CURLOPT_READFUNCTION\", parameter.GetMPTR());\n\t\t\tcurl->fread_func_set = parameter;\n\t\t\tresult = ::curl_easy_setopt(curlObj, CURLOPT_READFUNCTION, read_callback);\n\t\t\t::curl_easy_setopt(curlObj, CURLOPT_READDATA, curl.GetPtr());\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_READDATA:\n\t\t{\n\t\t\tcurlDebug_logEasySetOptPtr(curl.GetPtr(), \"CURLOPT_READDATA\", parameter.GetMPTR());\n\t\t\tcurl->in_set = parameter;\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_PROGRESSFUNCTION:\n\t\t{\n\t\t\tcurlDebug_logEasySetOptPtr(curl.GetPtr(), \"CURLOPT_PROGRESSFUNCTION\", parameter.GetMPTR());\n\t\t\tcurl->fprogress = parameter;\n\t\t\tresult = ::curl_easy_setopt(curlObj, CURLOPT_PROGRESSFUNCTION, progress_callback);\n\t\t\t::curl_easy_setopt(curlObj, CURLOPT_PROGRESSDATA, curl.GetPtr());\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLOPT_PROGRESSDATA:\n\t\t{\n\t\t\tcurlDebug_logEasySetOptPtr(curl.GetPtr(), \"CURLOPT_PROGRESSDATA\", parameter.GetMPTR());\n\t\t\tcurl->progress_client = parameter;\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tcemuLog_logDebug(LogType::Force, \"curl_easy_setopt(0x{:08x}, {}, 0x{:08x}) unsupported option\", curl.GetMPTR(), option, parameter.GetMPTR());\n\t}\n\n\tcemuLog_logDebug(LogType::Force, \"curl_easy_setopt(0x{:08x}, {}, 0x{:08x}) -> 0x{:x}\", curl.GetMPTR(), option, parameter.GetMPTR(), result);\n\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nWU_CURLcode curl_easy_perform(CURL_t* curl)\n{\n\tcurlDebug_markActiveRequest(curl);\n\tcurlDebug_notifySubmitRequest(curl);\n\n\tif(curl->isDirty)\n\t{\n\t\tcurl->isDirty = false;\n\t\t_curl_sync_parameters(curl);\n\t}\n\tconst uint32 result = SendOrderToWorker(curl, QueueOrder_Perform);\n\treturn static_cast<WU_CURLcode>(result);\n}\n\nvoid _updateGuestString(CURL_t* curl, MEMPTR<char>& ppcStr, char* hostStr)\n{\n\t// free current string\n\tif (ppcStr.IsNull() == false)\n\t{\n\t\tPPCCoreCallback(g_nlibcurl.free.GetMPTR(), ppcStr);\n\t\tppcStr = nullptr;\n\t}\n\tif (hostStr == nullptr)\n\t\treturn;\n\tsint32 length = (sint32)strlen(hostStr);\n\tppcStr = PPCCoreCallback(g_nlibcurl.malloc.GetMPTR(), length+1);\n\tmemcpy(ppcStr.GetPtr(), hostStr, length + 1);\n}\n\nvoid export_curl_easy_getinfo(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(curl, CURL_t, 0);\n\tppcDefineParamU32(info, 1);\n\tppcDefineParamMEMPTR(parameter, void, 2);\n\n\tCURL* curlObj = curl->curl;\n\n\tCURLcode result = CURLE_OK;\n\tswitch (info)\n\t{\n\t\tcase CURLINFO_SIZE_DOWNLOAD:\n\t\tcase CURLINFO_SPEED_DOWNLOAD:\n\t\tcase CURLINFO_SIZE_UPLOAD:\n\t\tcase CURLINFO_SPEED_UPLOAD:\n\t\tcase CURLINFO_CONTENT_LENGTH_DOWNLOAD:\n\t\t{\n\t\t\tdouble tempDouble = 0.0;\n\t\t\tresult = curl_easy_getinfo(curlObj, (CURLINFO)info, &tempDouble);\n\t\t\t*(uint64*)parameter.GetPtr() = _swapEndianU64(*(uint64*)&tempDouble);\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLINFO_RESPONSE_CODE:\n\t\tcase CURLINFO_SSL_VERIFYRESULT:\n\t\t{\n\t\t\tlong tempLong = 0;\n\t\t\tresult = curl_easy_getinfo(curlObj, (CURLINFO)info, &tempLong);\n\t\t\t*(uint32*)parameter.GetPtr() = _swapEndianU32((uint32)tempLong);\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLINFO_CONTENT_TYPE:\n\t\t{\n\t\t\tchar* contentType = nullptr;\n\t\t\tresult = curl_easy_getinfo(curlObj, CURLINFO_REDIRECT_URL, &contentType);\n\t\t\t_updateGuestString(curl.GetPtr(), curl->info_contentType, contentType);\n\t\t\t*(MEMPTR<char>*)parameter.GetPtr() = curl->info_contentType;\n\t\t\tbreak;\n\t\t}\n\t\tcase CURLINFO_REDIRECT_URL:\n\t\t{\n\t\t\tchar* redirectUrl = nullptr;\n\t\t\tresult = curl_easy_getinfo(curlObj, CURLINFO_REDIRECT_URL, &redirectUrl);\n\t\t\t_updateGuestString(curl.GetPtr(), curl->info_redirectUrl, redirectUrl);\n\t\t\t*(MEMPTR<char>*)parameter.GetPtr() = curl->info_redirectUrl;\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tcemu_assert_unimplemented();\n\t\t\tresult = curl_easy_getinfo(curlObj, (CURLINFO)info, (double*)parameter.GetPtr());\n\t}\n\n\tcemuLog_logDebug(LogType::Force, \"curl_easy_getinfo(0x{:08x}, 0x{:x}, 0x{:08x}) -> 0x{:x}\", curl.GetMPTR(), info, parameter.GetMPTR(), result);\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid export_curl_easy_strerror(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(code, 0);\n\tMEMPTR<char> result;\n\n\tconst char* error = curl_easy_strerror((CURLcode)code);\n\tif (error)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"curl_easy_strerror: {}\", error);\n\t\tint len = (int)strlen(error) + 1;\n\t\tresult = coreinit_allocFromSysArea(len, 4);\n\t\tmemcpy(result.GetPtr(), error, len);\n\t}\n\tosLib_returnFromFunction(hCPU, result.GetMPTR());\n}\n\nWU_curl_slist* curl_slist_append(WU_curl_slist* list, const char* data)\n{\n\tMEMPTR<char> dupdata{ PPCCoreCallback(g_nlibcurl.strdup.GetMPTR(), data) };\n\tif (!dupdata)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"curl_slist_append(): Failed to duplicate string\");\n\t\treturn nullptr;\n\t}\n\n\tMEMPTR<WU_curl_slist> result{ PPCCoreCallback(g_nlibcurl.malloc.GetMPTR(), ppcsizeof<WU_curl_slist>()) };\n\tif (result)\n\t{\n\t\tresult->data = dupdata;\n\t\tresult->next = nullptr;\n\n\t\t// update last obj of list\n\t\tif (list)\n\t\t{\n\t\t\tMEMPTR<WU_curl_slist> tmp = list;\n\t\t\twhile (tmp->next)\n\t\t\t{\n\t\t\t\ttmp = tmp->next;\n\t\t\t}\n\n\t\t\ttmp->next = result;\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"curl_slist_append(): Failed to allocate memory\");\n\t\tPPCCoreCallback(g_nlibcurl.free.GetMPTR(), dupdata.GetMPTR());\n\t}\n\tif(list)\n\t\treturn list;\n\treturn result;\n}\n\t\nvoid curl_slist_free_all(WU_curl_slist* list)\n{\n\tcemuLog_logDebug(LogType::Force, \"export_curl_slist_free_all: TODO\");\n}\n\nCURLcode curl_global_init_mem(uint32 flags, MEMPTR<curl_malloc_callback> malloc_callback, MEMPTR<curl_free_callback> free_callback, MEMPTR<curl_realloc_callback> realloc_callback, MEMPTR<curl_strdup_callback> strdup_callback, MEMPTR<curl_calloc_callback> calloc_callback)\n{\n\tif(!malloc_callback || !free_callback || !realloc_callback || !strdup_callback || !calloc_callback)\n\t\treturn CURLE_FAILED_INIT;\n\n\tCURLcode result = CURLE_OK;\n\tif (g_nlibcurl.initialized == 0)\n\t{\n\t\tresult = curl_global_init(flags);\n\t\tif (result == CURLE_OK)\n\t\t{\n\t\t\tg_nlibcurl.malloc = malloc_callback;\n\t\t\tg_nlibcurl.free = free_callback;\n\t\t\tg_nlibcurl.realloc = realloc_callback;\n\t\t\tg_nlibcurl.strdup = strdup_callback;\n\t\t\tg_nlibcurl.calloc = calloc_callback;\n\t\t}\n\t}\n\treturn result;\n}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nlibcurl\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"nlibcurl\", curl_global_init_mem, LogType::nlibcurl);\n\t\t\tcafeExportRegister(\"nlibcurl\", curl_global_init, LogType::nlibcurl);\n\n\t\t\tcafeExportRegister(\"nlibcurl\", curl_slist_append, LogType::nlibcurl);\n\t\t\tcafeExportRegister(\"nlibcurl\", curl_slist_free_all, LogType::nlibcurl);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_easy_strerror\", export_curl_easy_strerror);\n\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_share_init\", export_curl_share_init);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_share_setopt\", export_curl_share_setopt);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_share_cleanup\", export_curl_share_cleanup);\n\n\t\t\tcafeExportRegister(\"nlibcurl\", mw_curl_easy_init, LogType::nlibcurl);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_multi_init\", export_curl_multi_init);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_multi_add_handle\", export_curl_multi_add_handle);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_multi_perform\", export_curl_multi_perform);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_multi_info_read\", export_curl_multi_info_read);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_multi_remove_handle\", export_curl_multi_remove_handle);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_multi_setopt\", export_curl_multi_setopt);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_multi_fdset\", export_curl_multi_fdset);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_multi_cleanup\", export_curl_multi_cleanup);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_multi_timeout\", export_curl_multi_timeout);\n\n\t\t\tcafeExportRegister(\"nlibcurl\", curl_easy_init, LogType::nlibcurl);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_easy_reset\", export_curl_easy_reset);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_easy_setopt\", export_curl_easy_setopt);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_easy_getinfo\", export_curl_easy_getinfo);\n\t\t\tcafeExportRegister(\"nlibcurl\", curl_easy_perform, LogType::nlibcurl);\n\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_easy_cleanup\", export_curl_easy_cleanup);\n\t\t\tosLib_addFunction(\"nlibcurl\", \"curl_easy_pause\", export_curl_easy_pause);\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\t// todo\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t\t// todo\n\t\t\t}\n\t\t}\n\t}s_COSnlibcurlModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnlibcurlModule;\n\t}\n\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nlibcurl/nlibcurl.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nlibcurl\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nlibcurl/nlibcurlDebug.hpp",
    "content": "\nuint32 _curlDebugSessionId = 0;\n\n// begin a new request if one is not already active\nvoid curlDebug_markActiveRequest(CURL_t* curl)\n{\n\tif (!ActiveSettings::DumpLibcurlRequestsEnabled())\n\t\treturn;\n\n\tif (curl->debug.activeRequestIndex != 0)\n\t\treturn; // already tracking request\n\n\tif (_curlDebugSessionId == 0)\n\t{\n\t\t_curlDebugSessionId = (uint32)std::chrono::seconds(std::time(NULL)).count();\n\t\tif (_curlDebugSessionId == 0)\n\t\t\t_curlDebugSessionId = 1;\n\t\twchar_t filePath[256];\n\t\tswprintf(filePath, sizeof(filePath), L\"dump//curl//session%u\", _curlDebugSessionId);\n\t\tfs::create_directories(fs::path(filePath));\n\t}\n\n\tstatic uint32 _nextRequestIndex = 1;\n\tcurl->debug.activeRequestIndex = _nextRequestIndex;\n\t_nextRequestIndex++;\n\n\twchar_t filePath[256];\n\tswprintf(filePath, sizeof(filePath) / sizeof(wchar_t), L\"dump//curl//session%u//request%04d_param.txt\", _curlDebugSessionId, (sint32)curl->debug.activeRequestIndex);\n\tcurl->debug.file_requestParam = FileStream::createFile(filePath);\n\tauto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());\n\tif (curl->debug.file_requestParam)\n\t{\n\t\tauto t = std::localtime(&now);\n\t\tcurl->debug.file_requestParam->writeStringFmt(\"Request %d %d-%d-%d %d:%02d:%02d\\r\\n\", (sint32)curl->debug.activeRequestIndex, t->tm_year+1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);\n\t}\n}\n\nvoid curlDebug_notifySubmitRequest(CURL_t* curl)\n{\n\t// start new response\n\tcurl->debug.responseRequestIndex = curl->debug.activeRequestIndex;\n\tif (curl->debug.file_responseRaw)\n\t{\n\t\tdelete curl->debug.file_responseRaw;\n\t\tcurl->debug.file_responseRaw = nullptr;\n\t}\n\tif (curl->debug.file_responseHeaders)\n\t{\n\t\tdelete curl->debug.file_responseHeaders;\n\t\tcurl->debug.file_responseHeaders = nullptr;\n\t}\n\tcurl->debug.hasDumpedResultInfo = false;\n\t// end current request\n\tcurl->debug.activeRequestIndex = 0;\n\tif (curl->debug.file_requestParam)\n\t{\n\t\tdelete curl->debug.file_requestParam;\n\t\tcurl->debug.file_requestParam = nullptr;\n\t}\n}\n\nvoid curlDebug_logEasySetOptStr(CURL_t* curl, const char* optName, const char* optValue)\n{\n\tcurlDebug_markActiveRequest(curl);\n\tif (curl->debug.file_requestParam)\n\t{\n\t\tcurl->debug.file_requestParam->writeStringFmt(\"SetOpt %s: \", optName, optValue ? optValue : \"NULL\");\n\t\tif(optValue)\n\t\t\tcurl->debug.file_requestParam->writeString(optValue);\n\t\telse\n\t\t\tcurl->debug.file_requestParam->writeString(\"NULL\");\n\t\tcurl->debug.file_requestParam->writeString(\"\\r\\n\");\n\t}\n}\n\nvoid curlDebug_logEasySetOptPtr(CURL_t* curl, const char* optName, uint32 ppcPtr)\n{\n\tcurlDebug_markActiveRequest(curl);\n\tif (curl->debug.file_requestParam)\n\t{\n\t\tcurl->debug.file_requestParam->writeStringFmt(\"SetOpt %s: 0x%08x\\r\\n\", optName, ppcPtr);\n\t}\n}\n\nvoid curlDebug_resultWrite(CURL_t* curl, char* ptr, size_t size, size_t nmemb)\n{\n\tif (!ActiveSettings::DumpLibcurlRequestsEnabled())\n\t\treturn;\n\tif (curl->debug.responseRequestIndex == 0)\n\t\treturn;\n\tif (curl->debug.file_responseRaw == nullptr)\n\t{\n\t\twchar_t filePath[256];\n\t\tswprintf(filePath, sizeof(filePath) / sizeof(wchar_t), L\"dump//curl//session%u//request%04d_responseRaw.bin\", _curlDebugSessionId, (sint32)curl->debug.responseRequestIndex);\n\t\tcurl->debug.file_responseRaw = FileStream::createFile(filePath);\n\t}\n\tif (curl->debug.file_responseRaw)\n\t{\n\t\tcurl->debug.file_responseRaw->writeData(ptr, size*nmemb);\n\t}\n}\n\nvoid curlDebug_headerWrite(CURL_t* curl, char* ptr, size_t size, size_t nmemb)\n{\n\tif (!ActiveSettings::DumpLibcurlRequestsEnabled())\n\t\treturn;\n\tif (curl->debug.responseRequestIndex == 0)\n\t\treturn;\n\tif (curl->debug.file_responseHeaders == nullptr)\n\t{\n\t\twchar_t filePath[256];\n\t\tswprintf(filePath, sizeof(filePath) / sizeof(wchar_t), L\"dump//curl//session%u//request%04d_responseHeaders.txt\", _curlDebugSessionId, (sint32)curl->debug.responseRequestIndex);\n\t\tcurl->debug.file_responseHeaders = FileStream::createFile(filePath);\n\t}\n\tif (curl->debug.file_responseHeaders)\n\t{\n\t\tcurl->debug.file_responseHeaders->writeData(ptr, size*nmemb);\n\t}\n}\n\nvoid curlDebug_cleanup(CURL_t* curl)\n{\n\tif (curl->debug.file_requestParam)\n\t{\n\t\tdelete curl->debug.file_requestParam;\n\t\tcurl->debug.file_requestParam = nullptr;\n\t}\n\tif (curl->debug.file_responseRaw)\n\t{\n\t\tdelete curl->debug.file_responseRaw;\n\t\tcurl->debug.file_responseRaw = nullptr;\n\t}\n\tif (curl->debug.file_responseHeaders)\n\t{\n\t\tdelete curl->debug.file_responseHeaders;\n\t\tcurl->debug.file_responseHeaders = nullptr;\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nlibnss/nlibnss.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"nlibnss.h\"\n\nnamespace nlibnss\n{\n\tint NSSExportDeviceCertChain(uint8* uknPtr1, uint32be* uknLength1, uint8* uknPtr2, uint32be* uknLength2, uint32 uknR7, uint32 uknR8)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"NSSExportDeviceCertChain called but not implemented\");\n\t\tcemu_assert_debug(false);\n\n\t\t// uknR3 = pointer (can be null, in which case only length is written)\n\t\t// uknR4 = length\n\t\t// uknR5 = pointer2\n\t\t// uknR6 = length2\n\t\t// uknR7 = some integer\n\t\t// uknR8 = ???\n\n\t\t*uknLength1 = 0x100;\n\t\t*uknLength2 = 0x100;\n\n\n\t\treturn 0; // failed\n\t}\n\n\tint NSSSignatureGetSignatureLength()\n\t{\n\t\t// parameters are unknown\n\t\tcemu_assert_debug(false);\n\t\treturn 0x1C; // signature length\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nlibnss\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"nlibnss\", NSSSignatureGetSignatureLength, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"nlibnss\", NSSExportDeviceCertChain, LogType::Placeholder);\n\t\t};\n\n\t}s_COSnlibnssModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnlibnssModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nlibnss/nlibnss.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nlibnss\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_ac/nn_ac.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"nn_ac.h\"\n\n#if BOOST_OS_WINDOWS\n#include <iphlpapi.h>\n#endif\n\n// AC lib (manages internet connection)\n\nenum class AC_STATUS : uint32\n{\n\tFAILED = (uint32)-1,\n\tOK = 0,\n};\n\nstatic_assert(TRUE == 1, \"TRUE not 1\");\n\nvoid _GetLocalIPAndSubnetMaskFallback(uint32& localIp, uint32& subnetMask)\n{\n\t// default to some hardcoded values\n\tlocalIp = (192 << 24) | (168 << 16) | (0 << 8) | (100 << 0);\n\tsubnetMask = (255 << 24) | (255 << 16) | (255 << 8) | (0 << 0);\n}\n\n#if BOOST_OS_WINDOWS\nvoid _GetLocalIPAndSubnetMask(uint32& localIp, uint32& subnetMask)\n{\n\tstd::vector<IP_ADAPTER_ADDRESSES> buf_adapter_addresses;\n\tbuf_adapter_addresses.resize(32);\n\tDWORD buf_size;\n\tDWORD r;\n\n\tfor (uint32 i = 0; i < 6; i++) \n\t{\n\t\tbuf_size = (uint32)(buf_adapter_addresses.size() * sizeof(IP_ADAPTER_ADDRESSES));\n\t\tr = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_GATEWAYS, nullptr, buf_adapter_addresses.data(), &buf_size);\n\t\tif (r != ERROR_BUFFER_OVERFLOW)\n\t\t\tbreak;\n\t\tbuf_adapter_addresses.resize(buf_adapter_addresses.size() * 2);\n\t}\n\tif (r != ERROR_SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to acquire local IP and subnet mask\");\n\t\t_GetLocalIPAndSubnetMaskFallback(localIp, subnetMask);\n\t\treturn;\n\t}\n\tIP_ADAPTER_ADDRESSES* currentAddress = buf_adapter_addresses.data();\n\twhile (currentAddress)\n\t{\n\t\tif (currentAddress->OperStatus != IfOperStatusUp)\n\t\t{\n\t\t\tcurrentAddress = currentAddress->Next;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!currentAddress->FirstUnicastAddress || !currentAddress->FirstUnicastAddress->Address.lpSockaddr)\n\t\t{\n\t\t\tcurrentAddress = currentAddress->Next;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!currentAddress->FirstGatewayAddress)\n\t\t{\n\t\t\tcurrentAddress = currentAddress->Next;\n\t\t\tcontinue;\n\t\t}\n\n\t\tSOCKADDR* sockAddr = currentAddress->FirstUnicastAddress->Address.lpSockaddr;\n\t\tif (sockAddr->sa_family == AF_INET)\n\t\t{\n\t\t\tULONG mask = 0;\n\t\t\tif (ConvertLengthToIpv4Mask(currentAddress->FirstUnicastAddress->OnLinkPrefixLength, &mask) != NO_ERROR)\n\t\t\t\tmask = 0;\n\t\t\tsockaddr_in* inAddr = (sockaddr_in*)sockAddr;\n\t\t\tlocalIp = _byteswap_ulong(inAddr->sin_addr.S_un.S_addr);\n\t\t\tsubnetMask = _byteswap_ulong(mask);\n\t\t\treturn;\n\t\t}\n\t\tcurrentAddress = currentAddress->Next;\n\t}\n\tcemuLog_logDebug(LogType::Force, \"_GetLocalIPAndSubnetMask(): Failed to find network IP and subnet mask\");\n\t_GetLocalIPAndSubnetMaskFallback(localIp, subnetMask);\n}\n#else\nvoid _GetLocalIPAndSubnetMask(uint32& localIp, uint32& subnetMask)\n{\n\tcemuLog_logDebug(LogType::Force, \"_GetLocalIPAndSubnetMask(): Not implemented\");\n\t_GetLocalIPAndSubnetMaskFallback(localIp, subnetMask);\n}\n#endif\n\nvoid nnAcExport_GetAssignedAddress(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"GetAssignedAddress() called\");\n\tppcDefineParamU32BEPtr(ipAddrOut, 0);\n\n\tuint32 localIp;\n\tuint32 subnetMask;\n\t_GetLocalIPAndSubnetMask(localIp, subnetMask);\n\n\t*ipAddrOut = localIp;\n\n\tconst uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);\n\tosLib_returnFromFunction(hCPU, nnResultCode);\n}\n\nvoid nnAcExport_GetAssignedSubnet(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"GetAssignedSubnet() called\");\n\n\tppcDefineParamU32BEPtr(subnetMaskOut, 0);\n\n\tuint32 localIp;\n\tuint32 subnetMask;\n\t_GetLocalIPAndSubnetMask(localIp, subnetMask);\n\n\t*subnetMaskOut = subnetMask;\n\n\tconst uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);\n\tosLib_returnFromFunction(hCPU, nnResultCode);\n}\n\nvoid nnAcExport_ACGetAssignedAddress(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32BEPtr(ipAddrOut, 0);\n\n\tuint32 localIp;\n\tuint32 subnetMask;\n\t_GetLocalIPAndSubnetMask(localIp, subnetMask);\n\t*ipAddrOut = localIp;\n\n\tconst uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);\n\tosLib_returnFromFunction(hCPU, nnResultCode);\n}\n\nvoid nnAcExport_IsSystemConnected(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamTypePtr(isConnectedOut, uint8, 0);\n\tppcDefineParamTypePtr(apTypeOut, uint32be, 1);\n\n\tcemuLog_logDebug(LogType::Force, \"nn_ac.IsSystemConnected() - placeholder\");\n\t*apTypeOut = 0; // ukn\n\t*isConnectedOut = 1;\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnAcExport_IsConfigExisting(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_ac.IsConfigExisting() - placeholder\");\n\n\tppcDefineParamU32(configId, 0);\n\tppcDefineParamTypePtr(isConfigExisting, uint8, 1);\n\t\n\t*isConfigExisting = 0;\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nnamespace nn_ac\n{\n\tnnResult Initialize()\n\t{\n\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);\n\t}\n\n\tnnResult ConnectAsync()\n\t{\n\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);\n\t}\n\n\tnnResult IsApplicationConnected(uint8be* connected)\n\t{\n\t\tif (connected)\n\t\t\t*connected = TRUE;\n\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);\n\t}\n\n\tuint32 Connect()\n\t{\n\t\t// Terraria expects this (or GetLastErrorCode) to return 0 on success\n\t\t// investigate on the actual console\n\t\t// maybe all success codes are always 0 and dont have any of the other fields set?\n\t\tuint32 nnResultCode = 0;// BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0); // Splatoon freezes if this function fails?\n\t\treturn nnResultCode;\n\t}\n\n\tnnResult GetConnectStatus(betype<AC_STATUS>* status)\n\t{\n\t\tif (status)\n\t\t\t*status = AC_STATUS::OK;\n\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);\n\t}\n\n\tnnResult GetStatus(betype<AC_STATUS>* status)\n\t{\n\t\treturn GetConnectStatus(status);\n\t}\n\n\tnnResult GetLastErrorCode(uint32be* errorCode)\n\t{\n\t\tif (errorCode)\n\t\t\t*errorCode = 0;\n\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);\n\t}\n\n\tnnResult GetConnectResult(uint32be* connectResult)\n\t{\n\t\tconst uint32 nnResultCode = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_AC, 0);\n\t\tif (connectResult)\n\t\t\t*connectResult = nnResultCode;\n\t\treturn nnResultCode;\n\t}\n\n\tstatic_assert(sizeof(betype<AC_STATUS>) == 4);\n\tstatic_assert(sizeof(betype<nnResult>) == 4);\n\n\tnnResult ACInitialize()\n\t{\n\t\treturn Initialize();\n\t}\n\n\tbool ACIsSuccess(betype<nnResult>* r)\n\t{\n\t\treturn NN_RESULT_IS_SUCCESS(*r) ? 1 : 0;\n\t}\n\n\tbool ACIsFailure(betype<nnResult>* r)\n\t{\n\t\treturn NN_RESULT_IS_FAILURE(*r) ? 1 : 0;\n\t}\n\n\tnnResult ACGetConnectStatus(betype<AC_STATUS>* connectionStatus)\n\t{\n\t\treturn GetConnectStatus(connectionStatus);\n\t}\n\n\tnnResult ACGetStatus(betype<AC_STATUS>* connectionStatus)\n\t{\n\t\treturn GetStatus(connectionStatus);\n\t}\n\n\tnnResult ACConnectAsync()\n\t{\n\t\treturn ConnectAsync();\n\t}\n\n\tnnResult ACIsApplicationConnected(uint32be* connectedU32)\n\t{\n\t\tuint8be connected = 0;\n\t\tnnResult r = IsApplicationConnected(&connected);\n\t\t*connectedU32 = connected; // convert to uint32\n\t\treturn r;\n\t}\n\n\tvoid load()\n\t{\n\t\tcafeExportRegisterFunc(Initialize, \"nn_ac\", \"Initialize__Q2_2nn2acFv\", LogType::Placeholder);\n\n\t\tcafeExportRegisterFunc(Connect, \"nn_ac\", \"Connect__Q2_2nn2acFv\", LogType::Placeholder);\n\t\tcafeExportRegisterFunc(ConnectAsync, \"nn_ac\", \"ConnectAsync__Q2_2nn2acFv\", LogType::Placeholder);\n\n\t\tcafeExportRegisterFunc(GetConnectResult, \"nn_ac\", \"GetConnectResult__Q2_2nn2acFPQ2_2nn6Result\", LogType::Placeholder);\n\t\tcafeExportRegisterFunc(GetLastErrorCode, \"nn_ac\", \"GetLastErrorCode__Q2_2nn2acFPUi\", LogType::Placeholder);\n\t\tcafeExportRegisterFunc(GetConnectStatus, \"nn_ac\", \"GetConnectStatus__Q2_2nn2acFPQ3_2nn2ac6Status\", LogType::Placeholder);\n\t\tcafeExportRegisterFunc(GetStatus, \"nn_ac\", \"GetStatus__Q2_2nn2acFPQ3_2nn2ac6Status\", LogType::Placeholder);\n\t\tcafeExportRegisterFunc(IsApplicationConnected, \"nn_ac\", \"IsApplicationConnected__Q2_2nn2acFPb\", LogType::Placeholder);\n\n\t\t// AC also offers C-style wrappers\n\t\tcafeExportRegister(\"nn_ac\", ACInitialize, LogType::Placeholder);\n\t\tcafeExportRegister(\"nn_ac\", ACIsSuccess, LogType::Placeholder);\n\t\tcafeExportRegister(\"nn_ac\", ACIsFailure, LogType::Placeholder);\n\t\tcafeExportRegister(\"nn_ac\", ACGetConnectStatus, LogType::Placeholder);\n\t\tcafeExportRegister(\"nn_ac\", ACGetStatus, LogType::Placeholder);\n\t\tcafeExportRegister(\"nn_ac\", ACConnectAsync, LogType::Placeholder);\n\t\tcafeExportRegister(\"nn_ac\", ACIsApplicationConnected, LogType::Placeholder);\n\t}\n\n}\n\nvoid nnAc_load()\n{\n\n}\n\nnamespace nn::ac\n{\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_ac\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"nn_ac\", \"GetAssignedAddress__Q2_2nn2acFPUl\", nnAcExport_GetAssignedAddress);\n\t\t\tosLib_addFunction(\"nn_ac\", \"GetAssignedSubnet__Q2_2nn2acFPUl\", nnAcExport_GetAssignedSubnet);\n\n\t\t\tosLib_addFunction(\"nn_ac\", \"IsSystemConnected__Q2_2nn2acFPbPQ3_2nn2ac6ApType\", nnAcExport_IsSystemConnected);\n\n\t\t\tosLib_addFunction(\"nn_ac\", \"IsConfigExisting__Q2_2nn2acFQ3_2nn2ac11ConfigIdNumPb\", nnAcExport_IsConfigExisting);\n\n\t\t\tosLib_addFunction(\"nn_ac\", \"ACGetAssignedAddress\", nnAcExport_ACGetAssignedAddress);\n\n\t\t\tnn_ac::load();\n\t\t};\n\t}s_COSnnAcModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnAcModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_ac/nn_ac.h",
    "content": "void nnAc_load();\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn_ac\n{\n\tnnResult IsApplicationConnected(uint8be* connected);\n}\n\nnamespace nn::ac\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_acp/nn_acp.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n#include \"nn_acp.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IOS.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n\n#include <cinttypes>\n#include <filesystem>\n#include <fstream>\n\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/IOSU/legacy/iosu_acp.h\"\n#include \"Cafe/IOSU/legacy/iosu_ioctl.h\"\n\n#include \"Cafe/OS/libs/sysapp/sysapp.h\"\n#include \"Common/FileStream.h\"\n#include \"Cafe/CafeSystem.h\"\n\nusing ACPDeviceType = iosu::acp::ACPDeviceType;\n\n#define acpPrepareRequest() \\\nStackAllocator<iosuAcpCemuRequest_t> _buf_acpRequest; \\\nStackAllocator<ioBufferVector_t> _buf_bufferVector; \\\niosuAcpCemuRequest_t* acpRequest = _buf_acpRequest.GetPointer(); \\\nioBufferVector_t* acpBufferVector = _buf_bufferVector.GetPointer(); \\\nmemset(acpRequest, 0, sizeof(iosuAcpCemuRequest_t)); \\\nmemset(acpBufferVector, 0, sizeof(ioBufferVector_t)); \\\nacpBufferVector->buffer = (uint8*)acpRequest;\n\nnamespace nn\n{\nnamespace acp\n{\n\tACPStatus ACPConvertResultToACPStatus(uint32* nnResult, const char* functionName, uint32 lineNumber)\n\t{\n\t\t// todo\n\t\treturn ACPStatus::SUCCESS;\n\t}\n\n\t#define _ACPConvertResultToACPStatus(nnResult) ACPConvertResultToACPStatus(nnResult, __func__, __LINE__)\n\n\tACPStatus ACPGetApplicationBox(uint32be* applicationBox, uint64 titleId)\n\t{\n\t\t// todo\n\t\t*applicationBox = 3; // storage mlc\n\t\treturn ACPStatus::SUCCESS;\n\t}\n\n\tACPStatus ACPGetOlvAccesskey(uint32be* accessKey)\n\t{\n\t\tnnResult r = iosu::acp::ACPGetOlvAccesskey(accessKey);\n\t\treturn _ACPConvertResultToACPStatus(&r);\n\t}\n\n    bool sSaveDirMounted{false};\n\n\tACPStatus ACPMountSaveDir()\n\t{\n        cemu_assert_debug(!sSaveDirMounted);\n\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\t\tuint32 high = GetTitleIdHigh(titleId) & (~0xC);\n\t\tuint32 low = GetTitleIdLow(titleId);\n\n\t\t// mount save path\n\t\tconst auto mlc = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/user/\", high, low);\n\t\tFSCDeviceHostFS_Mount(\"/vol/save/\", _pathToUtf8(mlc), FSC_PRIORITY_BASE);\n\t\tnnResult mountResult = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACP, 0);\n\t\treturn _ACPConvertResultToACPStatus(&mountResult);\n\t}\n\n    ACPStatus ACPUnmountSaveDir()\n    {\n        cemu_assert_debug(!sSaveDirMounted);\n        fsc_unmount(\"/vol/save/\", FSC_PRIORITY_BASE);\n        return ACPStatus::SUCCESS;\n    }\n\n\tACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType)\n\t{\n\t\tnnResult r = iosu::acp::ACPUpdateSaveTimeStamp(persistentId, titleId, deviceType);\n\t\treturn ACPStatus::SUCCESS;\n\t}\n\n\tACPStatus ACPCheckApplicationDeviceEmulation(uint32be* isEmulated)\n\t{\n\t\t*isEmulated = 0;\n\t\treturn ACPStatus::SUCCESS;\n\t}\n\n\tACPStatus ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type)\n\t{\n\t\tnnResult result = iosu::acp::ACPCreateSaveDir(persistentId, type);\n\t\treturn _ACPConvertResultToACPStatus(&result);\n\t}\n\n\tnnResult ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId)\n\t{\n\t\tacpPrepareRequest();\n\t\tacpRequest->requestCode = IOSU_ACP_CREATE_SAVE_DIR_EX;\n\t\tacpRequest->accountSlot = accountSlot;\n\t\tacpRequest->titleId = titleId;\n\n\t\t__depr__IOS_Ioctlv(IOS_DEVICE_ACP_MAIN, IOSU_ACP_REQUEST_CEMU, 1, 1, acpBufferVector);\n\t\t\n\t\tnnResult result = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACP, 0);\n\t\treturn result;\n\t}\n\n\tvoid nnACPExport_ACPCreateSaveDirEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU8(accountSlot, 0);\n\t\tppcDefineParamU64(titleId, 2); // index 2 because of alignment -> guessed parameters\n\t\tnnResult result = ACPCreateSaveDirEx(accountSlot, titleId);\n\t\tosLib_returnFromFunction(hCPU, _ACPConvertResultToACPStatus(&result));\n\t}\n\n\tvoid export_ACPGetSaveDataTitleIdList(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(uknType, 0);\n\t\tppcDefineParamStructPtr(titleIdList, acpTitleId_t, 1);\n\t\tppcDefineParamU32(maxCount, 2);\n\t\tppcDefineParamU32BEPtr(count, 3);\n\n\t\tif (uknType != 3)\n\t\t\tassert_dbg();\n\n\t\tacpPrepareRequest();\n\t\tacpRequest->requestCode = IOSU_ACP_GET_SAVE_DATA_TITLE_ID_LIST;\n\t\tacpRequest->ptr = titleIdList;\n\t\tacpRequest->maxCount = maxCount;\n\t\tacpRequest->type = uknType;\n\n\t\t__depr__IOS_Ioctlv(IOS_DEVICE_ACP_MAIN, IOSU_ACP_REQUEST_CEMU, 1, 1, acpBufferVector);\n\n\t\t*count = acpRequest->resultU32.u32;\n\n\t\tosLib_returnFromFunction(hCPU, acpRequest->returnCode);\n\t}\n\n\tvoid export_ACPGetTitleSaveMetaXml(PPCInterpreter_t* hCPU)\n\t{\n\t\t// r3/r4 = titleId\n\t\t// r5 = pointer\n\t\t// r6 = 3 (probably some sort of type? Same as in ACPGetSaveDataTitleIdList?)\n\t\tppcDefineParamU64(titleId, 0);\n\t\tppcDefineParamStructPtr(acpMetaXml, acpMetaXml_t, 2);\n\t\tppcDefineParamU32(uknR6, 3);\n\n\t\tif (uknR6 != 3)\n\t\t\tassert_dbg();\n\n\t\tacpPrepareRequest();\n\t\tacpRequest->requestCode = IOSU_ACP_GET_TITLE_SAVE_META_XML;\n\t\tacpRequest->ptr = acpMetaXml;\n\t\tacpRequest->titleId = titleId;\n\t\tacpRequest->type = uknR6;\n\n\t\t__depr__IOS_Ioctlv(IOS_DEVICE_ACP_MAIN, IOSU_ACP_REQUEST_CEMU, 1, 1, acpBufferVector);\n\n\t\tosLib_returnFromFunction(hCPU, acpRequest->returnCode);\n\t}\n\n\tstatic_assert(sizeof(acpSaveDirInfo_t) == 0x80, \"acpSaveDirInfo_t has invalid size\");\n\n\tvoid export_ACPGetTitleSaveDirEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU64(titleId, 0);\n\t\tppcDefineParamU32(uknR5, 2); // storage device id?\n\t\tppcDefineParamU32(uknR6, 3); // ukn\n\t\tppcDefineParamStructPtr(saveDirInfoOut, acpSaveDirInfo_t, 4);\n\t\tppcDefineParamU32(uknR8, 5); // max count?\n\t\tppcDefineParamU32BEPtr(countOut, 6);\n\n\t\tif (uknR5 != 3)\n\t\t\tassert_dbg();\n\t\tif (uknR6 != 0)\n\t\t\tassert_dbg();\n\n\t\tacpPrepareRequest();\n\t\tacpRequest->requestCode = IOSU_ACP_GET_TITLE_SAVE_DIR;\n\t\tacpRequest->ptr = saveDirInfoOut;\n\t\tacpRequest->titleId = titleId;\n\t\tacpRequest->type = uknR5;\n\t\tacpRequest->maxCount = uknR8;\n\n\t\t__depr__IOS_Ioctlv(IOS_DEVICE_ACP_MAIN, IOSU_ACP_REQUEST_CEMU, 1, 1, acpBufferVector);\n\t\t*countOut = acpRequest->resultU32.u32;\n\n\t\tosLib_returnFromFunction(hCPU, acpRequest->returnCode);\n\t}\n\n\tvoid export_ACPCheckTitleNotReferAccountLaunch(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU64(titleId, 0);\n\t\tcemuLog_logDebug(LogType::Force, \"ACPCheckTitleNotReferAccountLaunch(): Placeholder\");\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_ACPGetLaunchMetaData(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamStructPtr(acpMetaData, acpMetaData_t, 0);\n\t\t\n\t\tcemuLog_logDebug(LogType::Force, \"ACPGetLaunchMetaData(): Placeholder\");\n\n\t\tacpPrepareRequest();\n\t\tacpRequest->requestCode = IOSU_ACP_GET_TITLE_META_DATA;\n\t\tacpRequest->ptr = acpMetaData;\n\t\tacpRequest->titleId = CafeSystem::GetForegroundTitleId();\n\n\t\t__depr__IOS_Ioctlv(IOS_DEVICE_ACP_MAIN, IOSU_ACP_REQUEST_CEMU, 1, 1, acpBufferVector);\n\n\t\tosLib_returnFromFunction(hCPU, acpRequest->returnCode);\n\t}\n\n\tvoid export_ACPGetLaunchMetaXml(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamStructPtr(acpMetaXml, acpMetaXml_t, 0);\n\n\t\tcemuLog_logDebug(LogType::Force, \"ACPGetLaunchMetaXml(): Placeholder\");\n\n\t\tacpPrepareRequest();\n\t\tacpRequest->requestCode = IOSU_ACP_GET_TITLE_META_XML;\n\t\tacpRequest->ptr = acpMetaXml;\n\t\tacpRequest->titleId = CafeSystem::GetForegroundTitleId();\n\n\t\t__depr__IOS_Ioctlv(IOS_DEVICE_ACP_MAIN, IOSU_ACP_REQUEST_CEMU, 1, 1, acpBufferVector);\n\n\t\tosLib_returnFromFunction(hCPU, acpRequest->returnCode);\n\t}\n\n\tvoid export_ACPGetTitleIdOfMainApplication(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamTypePtr(titleId, uint64be, 0);\n\n\t\tuint64 currentTitleId = CafeSystem::GetForegroundTitleId();\n\t\t*titleId = currentTitleId;\n\n\t\t// for applets we return the menu titleId\n\t\tif (((currentTitleId >> 32) & 0xFF) == 0x30)\n\t\t{\n\t\t\t// get menu titleId\n\t\t\tuint64 menuTitleId = _SYSGetSystemApplicationTitleId(0);\n\t\t\t*titleId = menuTitleId;\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_ACPGetTitleMetaDirByDevice(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU64(titleId, 0);\n\t\tppcDefineParamStr(path, 2);\n\t\tppcDefineParamU32(pathSize, 3);\n\t\tppcDefineParamU32(deviceId, 4);\n\n\t\tif (deviceId != 3)\n\t\t\tassert_dbg();\n\n\t\tif (((titleId >> 32) & 0xFF) == 0x10 || ((titleId >> 32) & 0xFF) == 0x30)\n\t\t{\n\t\t\tsprintf(path, \"/vol/storage_mlc01/sys/title/%08x/%08x/meta\", (uint32)(titleId>>32), (uint32)(titleId&0xFFFFFFFF));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsprintf(path, \"/vol/storage_mlc01/usr/title/%08x/%08x/meta\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_ACPGetTitleMetaXmlByDevice(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU64(titleId, 0);\n\t\tppcDefineParamStructPtr(acpMetaXml, acpMetaXml_t, 2);\n\t\tppcDefineParamU32(deviceId, 3);\n\n\t\tif (deviceId != 3)\n\t\t\tcemuLog_logDebug(LogType::Force, \"ACPGetTitleMetaXmlByDevice(): Unsupported deviceId\");\n\n\t\tacpPrepareRequest();\n\t\tacpRequest->requestCode = IOSU_ACP_GET_TITLE_META_XML;\n\t\tacpRequest->ptr = acpMetaXml;\n\t\tacpRequest->titleId = titleId;//CafeSystem::GetForegroundTitleId();\n\n\t\t__depr__IOS_Ioctlv(IOS_DEVICE_ACP_MAIN, IOSU_ACP_REQUEST_CEMU, 1, 1, acpBufferVector);\n\n\t\tosLib_returnFromFunction(hCPU, acpRequest->returnCode);\n\t}\n\n\tuint32 ACPGetTitleMetaXml(uint64 titleId, acpMetaXml_t* acpMetaXml)\n\t{\n\t\tacpPrepareRequest();\n\t\tacpRequest->requestCode = IOSU_ACP_GET_TITLE_META_XML;\n\t\tacpRequest->ptr = acpMetaXml;\n\t\tacpRequest->titleId = titleId;\n\n\t\t__depr__IOS_Ioctlv(IOS_DEVICE_ACP_MAIN, IOSU_ACP_REQUEST_CEMU, 1, 1, acpBufferVector);\n\n\t\treturn acpRequest->returnCode;\n\t}\n\n\tvoid export_ACPIsOverAgeEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(age, 0);\n\t\tppcDefineParamU8(slot, 1);\n\n\t\tbool isOverAge = true;\n\t\tosLib_returnFromFunction(hCPU, isOverAge ? 1 : 0);\n\t}\n\n\tvoid export_ACPGetNetworkTime(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32BEPtr(timestamp64, 0);\n\t\tppcDefineParamU32BEPtr(ukn, 1); // probably timezone or offset? Could also be a bool for success/failed\n\n\t\tuint64 t = coreinit::OSGetTime() + (uint64)((sint64)(ppcCyclesSince2000_UTC - ppcCyclesSince2000) / 20LL);\n\n\t\ttimestamp64[0] = (uint32)(t >> 32);\n\t\ttimestamp64[1] = (uint32)(t & 0xFFFFFFFF);\n\n\t\t*ukn = 1; // E-Shop doesnt want this to be zero (games also check for it)\n\n\t\tosLib_returnFromFunction(hCPU, 0); // error code\n\t}\n\n\tvoid export_ACPConvertNetworkTimeToOSCalendarTime(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU64(networkTime, 0);\n\t\tppcDefineParamStructPtr(calendarTime, coreinit::OSCalendarTime_t, 2);\n\n\t\tcoreinit::OSTicksToCalendarTime(networkTime, calendarTime);\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_acp\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"nn_acp\", ACPCheckApplicationDeviceEmulation, LogType::Placeholder);\n\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPCreateSaveDirEx\", nnACPExport_ACPCreateSaveDirEx);\n\t\t\tcafeExportRegister(\"nn_acp\", ACPUpdateSaveTimeStamp, LogType::Placeholder);\n\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPGetSaveDataTitleIdList\", export_ACPGetSaveDataTitleIdList);\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPGetTitleSaveMetaXml\", export_ACPGetTitleSaveMetaXml);\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPGetTitleSaveDirEx\", export_ACPGetTitleSaveDirEx);\n\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPCheckTitleNotReferAccountLaunch\", export_ACPCheckTitleNotReferAccountLaunch);\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPGetLaunchMetaData\", export_ACPGetLaunchMetaData);\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPGetLaunchMetaXml\", export_ACPGetLaunchMetaXml);\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPGetTitleIdOfMainApplication\", export_ACPGetTitleIdOfMainApplication);\n\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPGetTitleMetaDirByDevice\", export_ACPGetTitleMetaDirByDevice);\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPGetTitleMetaXmlByDevice\", export_ACPGetTitleMetaXmlByDevice);\n\t\t\tcafeExportRegister(\"nn_acp\", ACPGetTitleMetaXml, LogType::Placeholder);\n\n\t\t\tcafeExportRegister(\"nn_acp\", ACPGetApplicationBox, LogType::Placeholder);\n\n\t\t\tcafeExportRegister(\"nn_acp\", ACPGetOlvAccesskey, LogType::Placeholder);\n\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPIsOverAgeEx\", export_ACPIsOverAgeEx);\n\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPGetNetworkTime\", export_ACPGetNetworkTime);\n\t\t\tosLib_addFunction(\"nn_acp\", \"ACPConvertNetworkTimeToOSCalendarTime\", export_ACPConvertNetworkTimeToOSCalendarTime);\n\t\t};\n\n\t}s_COSnnAcpModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnAcpModule;\n\t}\n}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_acp/nn_acp.h",
    "content": "#pragma once\n#include \"Cafe/IOSU/legacy/iosu_acp.h\"\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn\n{\nnamespace acp\n{\n\tenum ACPStatus : uint32\n\t{\n\t\tSUCCESS = 0,\n\t};\n\n\tusing ACPDeviceType = iosu::acp::ACPDeviceType;\n\n\tACPStatus ACPGetApplicationBox(uint32be* applicationBox, uint64 titleId);\n\tACPStatus ACPMountSaveDir();\n    ACPStatus ACPUnmountSaveDir();\n\tACPStatus ACPCreateSaveDir(uint32 persistentId, iosu::acp::ACPDeviceType type);\n\tACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, iosu::acp::ACPDeviceType deviceType);\n\n\tCOSModule* GetModule();\n}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_act/nn_act.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IOS.h\"\n#include \"Cafe/IOSU/legacy/iosu_act.h\"\n#include \"Cafe/IOSU/legacy/iosu_ioctl.h\"\n#include \"nn_act.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Common/CafeString.h\"\n\nsint32 numAccounts = 1;\n\n#define actPrepareRequest() \\\nStackAllocator<iosuActCemuRequest_t> _buf_actRequest; \\\nStackAllocator<ioBufferVector_t> _buf_bufferVector; \\\niosuActCemuRequest_t* actRequest = _buf_actRequest.GetPointer(); \\\nioBufferVector_t* actBufferVector = _buf_bufferVector.GetPointer(); \\\nmemset(actRequest, 0, sizeof(iosuActCemuRequest_t)); \\\nmemset(actBufferVector, 0, sizeof(ioBufferVector_t)); \\\nactBufferVector->buffer = (uint8*)actRequest;\n\n#define actPrepareRequest2() \\\nStackAllocator<iosuActCemuRequest_t> _buf_actRequest; \\\niosuActCemuRequest_t* actRequest = _buf_actRequest.GetPointer(); \\\nmemset(actRequest, 0, sizeof(iosuActCemuRequest_t));\n\nuint32 getNNReturnCode(uint32 iosError, iosuActCemuRequest_t* actRequest)\n{\n\tif ((iosError & 0x80000000) != 0)\n\t\treturn iosError;\n\treturn actRequest->returnCode;\n}\n\nuint32 _doCemuActRequest(iosuActCemuRequest_t* actRequest)\n{\n\tStackAllocator<ioBufferVector_t> _buf_bufferVector;\n\tioBufferVector_t* actBufferVector = _buf_bufferVector.GetPointer();\n\tmemset(actBufferVector, 0, sizeof(ioBufferVector_t));\n\tactBufferVector->buffer = (uint8*)actRequest;\n\n\tuint32 ioctlResult = __depr__IOS_Ioctlv(IOS_DEVICE_ACT, IOSU_ACT_REQUEST_CEMU, 1, 1, actBufferVector);\n\treturn getNNReturnCode(ioctlResult, actRequest);\n}\n\nnamespace nn\n{\nnamespace act\n{\n\t\t\n\t\tuint32 GetPersistentIdEx(uint8 slot)\n\t\t{\n\t\t\tactPrepareRequest();\n\t\t\tactRequest->requestCode = IOSU_ARC_PERSISTENTID;\n\t\t\tactRequest->accountSlot = slot;\n\n\t\t\t__depr__IOS_Ioctlv(IOS_DEVICE_ACT, IOSU_ACT_REQUEST_CEMU, 1, 1, actBufferVector);\n\n\t\t\treturn actRequest->resultU32.u32;\n\t\t}\n\n\t\tuint32 GetMiiEx(void* miiData, uint8 slot)\n\t\t{\n\t\t\tactPrepareRequest2();\n\t\t\tactRequest->requestCode = IOSU_ARC_MIIDATA;\n\t\t\tactRequest->accountSlot = slot;\n\n\t\t\tuint32 result = _doCemuActRequest(actRequest);\n\t\t\tmemcpy(miiData, actRequest->resultBinary.binBuffer, MII_FFL_STORAGE_SIZE);\n\n\t\t\treturn result;\n\t\t}\n\n\t\tuint32 GetUuidEx(uint8* uuid, uint8 slot, sint32 name)\n\t\t{\n\t\t\tactPrepareRequest2();\n\t\t\tactRequest->requestCode = IOSU_ARC_UUID;\n\t\t\tactRequest->accountSlot = slot;\n\t\t\tactRequest->uuidName = name;\n\n\t\t\tuint32 result = _doCemuActRequest(actRequest);\n\n\t\t\tmemcpy(uuid, actRequest->resultBinary.binBuffer, 16);\n\n\t\t\treturn result;\n\t\t}\n\n\t\tuint32 GetSimpleAddressIdEx(uint32be* simpleAddressId, uint8 slot)\n\t\t{\n\t\t\tactPrepareRequest2();\n\t\t\tactRequest->requestCode = IOSU_ARC_SIMPLEADDRESS;\n\t\t\tactRequest->accountSlot = slot;\n\n\t\t\tuint32 result = _doCemuActRequest(actRequest);\n\n\t\t\t*simpleAddressId = actRequest->resultU32.u32;\n\n\t\t\treturn result;\n\t\t}\n\n\t\tuint32 GetTransferableIdEx(uint64* transferableId, uint32 unique, uint8 slot)\n\t\t{\n\t\t\tactPrepareRequest2();\n\t\t\tactRequest->requestCode = IOSU_ARC_TRANSFERABLEID;\n\t\t\tactRequest->accountSlot = slot;\n\t\t\tactRequest->unique = unique;\n\n\t\t\tuint32 result = _doCemuActRequest(actRequest);\n\n\t\t\t*transferableId = _swapEndianU64(actRequest->resultU64.u64);\n\n\t\t\treturn result;\n\t\t}\n\n\t\tuint32 AcquireIndependentServiceToken(independentServiceToken_t* token, const char* clientId, uint32 cacheDurationInSeconds)\n\t\t{\n\t\t\tmemset(token, 0, sizeof(independentServiceToken_t));\n\t\t\tactPrepareRequest();\n\t\t\tactRequest->accountSlot = iosu::act::ACT_SLOT_CURRENT;\n\t\t\tactRequest->requestCode = IOSU_ARC_ACQUIREINDEPENDENTTOKEN;\n\t\t\tactRequest->titleId = CafeSystem::GetForegroundTitleId();\n\t\t\tactRequest->titleVersion = CafeSystem::GetForegroundTitleVersion();\n\t\t\tactRequest->expiresIn = cacheDurationInSeconds;\n\t\t\tstrcpy(actRequest->clientId, clientId);\n\n\t\t\tuint32 resultCode = __depr__IOS_Ioctlv(IOS_DEVICE_ACT, IOSU_ACT_REQUEST_CEMU, 1, 1, actBufferVector);\n\n\t\t\tmemcpy(token, actRequest->resultBinary.binBuffer, sizeof(independentServiceToken_t));\n\t\t\treturn getNNReturnCode(resultCode, actRequest);\n\t\t}\n\n\t\tsint64 GetUtcOffset()\n\t\t{\n\t\t\treturn ((ppcCyclesSince2000 / ESPRESSO_CORE_CLOCK) - (ppcCyclesSince2000_UTC / ESPRESSO_CORE_CLOCK)) * 1'000'000;\n\t\t}\n\n\t\tsint32 GetUtcOffsetEx(sint64be* pOutOffset, uint8 slotNo)\n\t\t{\n\n\t\t\tif (!pOutOffset)\n\t\t\t\treturn 0xc0712c80;\n\n\t\t\t*pOutOffset = GetUtcOffset();\n\t\t\treturn 0;\n\t\t}\n\n\t\tnnResult GetTimeZoneId(CafeString<65>* outTimezoneId)\n\t\t{\n\t\t\t// return a placeholder timezone id for now\n\t\t\t// in the future we should emulated this correctly and read the timezone from the account via IOSU\n\t\t\toutTimezoneId->assign(\"Europe/London\");\n\t\t\treturn 0;\n\t\t}\n\n\t\tsint32 g_initializeCount = 0; // inc in Initialize and dec in Finalize\n\t\tuint32 Initialize()\n\t\t{\n\t\t\t// usually uses a mutex which is initialized in -> global constructor keyed to'_17_act_shim_util_cpp\n\t\t\tif (g_initializeCount == 0)\n\t\t\t{\n\t\t\t\tactPrepareRequest();\n\t\t\t\tactRequest->requestCode = IOSU_ARC_INIT;\n\n\t\t\t\t__depr__IOS_Ioctlv(IOS_DEVICE_ACT, IOSU_ACT_REQUEST_CEMU, 1, 1, actBufferVector);\n\t\t\t}\n\n\t\t\tg_initializeCount++;\n\n\t\t\treturn 0;\n\t\t}\n\n\t\tNN_ERROR_CODE GetErrorCode(betype<nnResult>* nnResult)\n\t\t{\n\t\t\tNN_ERROR_CODE errCode = NNResultToErrorCode(*nnResult, NN_RESULT_MODULE_NN_ACT);\n\t\t\treturn errCode;\n\t\t}\n\t}\n}\n\n\nvoid nnActExport_CreateConsoleAccount(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"CreateConsoleAccount(...)\");\n\t//numAccounts++;\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnActExport_GetNumOfAccounts(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetNumOfAccounts()\");\n\tosLib_returnFromFunction(hCPU, numAccounts); // account count\n}\n\nvoid nnActExport_IsSlotOccupied(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.IsSlotOccupied({})\", hCPU->gpr[3]);\n\tppcDefineParamU8(slot, 0);\n\t\n\tosLib_returnFromFunction(hCPU, nn::act::GetPersistentIdEx(slot) != 0 ? 1 : 0);\n}\n\nuint32 GetAccountIdEx(char* accountId, uint8 slot)\n{\n\t// returns zero for non-network accounts?\n\tactPrepareRequest2();\n\tactRequest->requestCode = IOSU_ARC_ACCOUNT_ID;\n\tactRequest->accountSlot = slot;\n\n\tuint32 result = _doCemuActRequest(actRequest);\n\n\tstrcpy(accountId, actRequest->resultString.strBuffer);\n\n\treturn result;\n}\n\nuint32 GetPrincipalIdEx(uint32be* principalId, uint8 slot)\n{\n\tactPrepareRequest2();\n\tactRequest->requestCode = IOSU_ARC_PRINCIPALID;\n\tactRequest->accountSlot = slot;\n\n\tuint32 result = _doCemuActRequest(actRequest);\n\n\t*principalId = actRequest->resultU32.u32;\n\n\treturn result;\n}\n\nuint32 GetCountryEx(char* country, uint8 slot)\n{\n\tactPrepareRequest2();\n\tactRequest->requestCode = IOSU_ARC_COUNTRY;\n\tactRequest->accountSlot = slot;\n\n\tuint32 result = _doCemuActRequest(actRequest);\n\n\tstrcpy(country, actRequest->resultString.strBuffer);\n\n\treturn result;\n}\n\nuint32 IsNetworkAccount(uint8* isNetworkAccount, uint8 slot)\n{\n\tactPrepareRequest2();\n\tactRequest->requestCode = IOSU_ARC_ISNETWORKACCOUNT;\n\tactRequest->accountSlot = slot;\n\n\tuint32 result = _doCemuActRequest(actRequest);\n\n\t*isNetworkAccount = (actRequest->resultU32.u32 != 0) ? 1 : 0;\n\n\treturn result;\n}\n\nvoid nnActExport_IsNetworkAccount(PPCInterpreter_t* hCPU)\n{\n\t//cemuLog_logDebug(LogType::Force, \"nn_act.IsNetworkAccount()\");\n\tuint8 isNetAcc = 0;\n\tIsNetworkAccount(&isNetAcc, 0xFE);\n\tosLib_returnFromFunction(hCPU, isNetAcc);\n}\n\nvoid nnActExport_IsNetworkAccountEx(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU8(slot, 0);\n\tcemuLog_logDebug(LogType::Force, \"nn_act.IsNetworkAccountEx({})\", slot);\n\tuint8 isNetAcc = 0;\n\tIsNetworkAccount(&isNetAcc, slot);\n\tosLib_returnFromFunction(hCPU, isNetAcc);\n}\n\nvoid nnActExport_GetSimpleAddressId(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetSimpleAddressId()\");\n\n\tuint32be simpleAddressId;\n\tnn::act::GetSimpleAddressIdEx(&simpleAddressId, iosu::act::ACT_SLOT_CURRENT);\n\n\tosLib_returnFromFunction(hCPU, (uint32)simpleAddressId);\n}\n\nvoid nnActExport_GetSimpleAddressIdEx(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetSimpleAddressIdEx(0x{:08x}, {})\", hCPU->gpr[3], hCPU->gpr[4] & 0xFF);\n\n\tppcDefineParamU32BEPtr(simpleAddressId, 0);\n\tppcDefineParamU8(slot, 1);\n\n\tnn::act::GetSimpleAddressIdEx(simpleAddressId, slot);\n\n\tosLib_returnFromFunction(hCPU, 0); // ResultSuccess\n}\n\nvoid nnActExport_GetPrincipalId(PPCInterpreter_t* hCPU)\n{\n\t// return error for non-nnid accounts?\n\tuint32be principalId;\n\tGetPrincipalIdEx(&principalId, iosu::act::ACT_SLOT_CURRENT);\n\tosLib_returnFromFunction(hCPU, (uint32)principalId);\n}\n\nvoid nnActExport_GetPrincipalIdEx(PPCInterpreter_t* hCPU)\n{\n\t// return error for non-nnid accounts?\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetPrincipalIdEx(0x{:08x}, {})\", hCPU->gpr[3], hCPU->gpr[4]&0xFF);\n\tppcDefineParamU32BEPtr(principalId, 0);\n\tppcDefineParamU8(slot, 1);\n\tGetPrincipalIdEx(principalId, slot);\n\t\n\tosLib_returnFromFunction(hCPU, 0); // ResultSuccess\n}\n\nvoid nnActExport_GetTransferableId(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(unique, 0);\n\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetTransferableId(0x{:08x})\", hCPU->gpr[3]);\n\n\tuint64 transferableId;\n\tuint32 r = nn::act::GetTransferableIdEx(&transferableId, unique, iosu::act::ACT_SLOT_CURRENT);\n\tif (NN_RESULT_IS_FAILURE(r))\n\t{\n\t\ttransferableId = 0;\n\t}\n\n\tosLib_returnFromFunction64(hCPU, _swapEndianU64(transferableId));\n}\n\nvoid nnActExport_GetTransferableIdEx(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(transferableId, uint64, 0);\n\tppcDefineParamU32(unique, 1);\n\tppcDefineParamU8(slot, 2);\n\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetTransferableIdEx(0x{:08x}, 0x{:08x}, {})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5] & 0xFF);\n\t\n\tuint32 r = nn::act::GetTransferableIdEx(transferableId, unique, slot);\n\n\tosLib_returnFromFunction(hCPU, 0); // ResultSuccess\n}\n\nvoid nnActExport_GetPersistentId(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetPersistentId()\");\n\tuint32 persistentId = nn::act::GetPersistentIdEx(iosu::act::ACT_SLOT_CURRENT);\n\tosLib_returnFromFunction(hCPU, persistentId);\n}\n\nvoid nnActExport_GetPersistentIdEx(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU8(slot, 0);\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetPersistentIdEx({})\", slot);\n\n\tuint32 persistentId = nn::act::GetPersistentIdEx(slot);\n\n\tosLib_returnFromFunction(hCPU, persistentId);\n}\n\nvoid nnActExport_GetCountry(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetCountry(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamStr(country, 0);\n\tuint32 r = GetCountryEx(country, iosu::act::ACT_SLOT_CURRENT);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nbool g_isParentalControlCheckEnabled = false;\nvoid nnActExport_EnableParentalControlCheck(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.EnableParentalControlCheck({})\", hCPU->gpr[3]);\n\tppcDefineParamU8(isEnabled, 0);\n\tg_isParentalControlCheckEnabled = isEnabled != 0;\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnActExport_IsParentalControlCheckEnabled(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.IsParentalControlCheckEnabled() -> {}\", g_isParentalControlCheckEnabled);\n\tosLib_returnFromFunction(hCPU, g_isParentalControlCheckEnabled);\n}\n\nvoid nnActExport_GetHostServerSettings(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"GetHostServerSettings() - stub\");\n\tppcDefineParamStr(ukn, 1);\n\tstrcpy(ukn, \"\");\n\tosLib_returnFromFunction(hCPU, 0x00000000);\n}\n\nvoid nnActExport_GetMii(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetMii(...)\");\n\tppcDefineParamUStr(miiData, 0);\n\tuint32 r = nn::act::GetMiiEx(miiData, iosu::act::ACT_SLOT_CURRENT);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nnActExport_GetMiiEx(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetMiiEx(...)\");\n\tppcDefineParamUStr(miiData, 0);\n\tppcDefineParamU8(slot, 1);\n\tuint32 r = nn::act::GetMiiEx(miiData, slot);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nnActExport_GetMiiImageEx(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"GetMiiImageEx unimplemented\");\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnActExport_GetMiiName(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"GetMiiName(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamWStrBE(miiName, 0);\n\n\tStackAllocator<FFLData_t> miiData;\n\n\tuint32 r = nn::act::GetMiiEx(&miiData, iosu::act::ACT_SLOT_CURRENT);\n\t// extract name\n\tsint32 miiNameLength = 0;\n\tfor (sint32 i = 0; i < MII_FFL_NAME_LENGTH; i++)\n\t{\n\t\tmiiName[i] = miiData->miiName[i];\n\t\tif (miiData->miiName[i] == (const uint16be)'\\0')\n\t\t\tbreak;\n\t\tmiiNameLength = i+1;\n\t}\n\tmiiName[miiNameLength] = '\\0';\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnActExport_GetMiiNameEx(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"GetMiiNameEx(0x{:08x}, {})\", hCPU->gpr[3], hCPU->gpr[4] & 0xFF);\n\tppcDefineParamWStrBE(miiName, 0);\n\tppcDefineParamU8(slot, 1);\n\n\tStackAllocator<FFLData_t> miiData;\n\n\tuint32 r = nn::act::GetMiiEx(&miiData, slot);\n\t// extract name\n\tsint32 miiNameLength = 0;\n\tfor (sint32 i = 0; i < MII_FFL_NAME_LENGTH; i++)\n\t{\n\t\tmiiName[i] = miiData->miiName[i];\n\t\tif (miiData->miiName[i] == (const uint16be)'\\0')\n\t\t\tbreak;\n\t\tmiiNameLength = i + 1;\n\t}\n\tmiiName[miiNameLength] = '\\0';\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\ntypedef struct  \n{\n\tuint32be ukn00;\n\tuint32be ukn04; // transferable id high?\n\tuint32be accountTransferableIdLow; //\n\tuint32be ukn0C;\n\tuint32be ukn10;\n\tuint32be ukn14;\n\tuint32be ukn18;\n\tuint32be ukn1C;\n\tuint32be ukn20;\n\tuint32be ukn24;\n\tuint32be ukn28;\n\tuint32be ukn2C;\n\tuint32be ukn30;\n\tuint32be ukn34;\n\tuint32be ukn38;\n\tuint32be ukn3C;\n\tuint32be ukn40;\n\tuint32be ukn44;\n\tuint32be ukn48;\n\tuint32be ukn4C;\n\tuint32be ukn50;\n\tuint32be ukn54;\n\tuint32be tlsModuleIndex;\n\tuint32be ukn5C;\n}FFLStoreDataDepr_t;\n\nstatic_assert(sizeof(FFLStoreDataDepr_t) == 96);\n\nvoid nnActExport_UpdateMii(PPCInterpreter_t* hCPU)\n{\n\tif (sizeof(FFLStoreDataDepr_t) != MII_FFL_STORAGE_SIZE)\n\t\tassert_dbg();\n\n\tppcDefineParamU8(slot, 0);\n\tppcDefineParamStructPtr(fflStoreData, FFLStoreDataDepr_t, 1);\n\tppcDefineParamStructPtr(uknName, uint16, 2); // mii name\n\tppcDefineParamStructPtr(uknNameR6, uint8, 3);\n\tppcDefineParamStructPtr(uknNameR7, uint8, 4);\n\tppcDefineParamStructPtr(uknNameR8, uint8, 5);\n\tppcDefineParamStructPtr(uknNameR9, uint8, 6);\n\tppcDefineParamStructPtr(uknNameR10, uint8, 7);\n\tppcDefineParamStructPtr(uknNameSP4, uint8, 8);\n\t\n\tcemu_assert_unimplemented();\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnActExport_GetUuid(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetUuid(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamUStr(uuid, 0);\n\tnn::act::GetUuidEx(uuid, iosu::act::ACT_SLOT_CURRENT);\n\tosLib_returnFromFunction(hCPU, 0); // 0 -> result ok\n}\n\nvoid nnActExport_GetUuidEx(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetUuidEx(0x{:08x},0x{:02x})\", hCPU->gpr[3], hCPU->gpr[3]&0xFF);\n\tppcDefineParamUStr(uuid, 0);\n\tppcDefineParamU8(slot, 1);\n\tnn::act::GetUuidEx(uuid, slot);\n\tosLib_returnFromFunction(hCPU, 0); // 0 -> result ok\n}\n\nvoid nnActExport_GetUuidEx2(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetUuidEx(0x{:08x},0x{:02x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\tppcDefineParamUStr(uuid, 0);\n\tppcDefineParamU8(slot, 1);\n\tppcDefineParamS32(name, 2);\n\tnn::act::GetUuidEx(uuid, iosu::act::ACT_SLOT_CURRENT, name);\n\tosLib_returnFromFunction(hCPU, 0); // 0 -> result ok\n}\n\nvoid nnActExport_GetAccountId(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetAccountId(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamUStr(accId, 0);\n\tGetAccountIdEx((char*)accId, iosu::act::ACT_SLOT_CURRENT);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnActExport_GetAccountIdEx(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetAccountIdEx(0x{:08x}, 0x{:02x})\", hCPU->gpr[3], hCPU->gpr[3] & 0xFF);\n\tppcDefineParamUStr(accId, 0);\n\tppcDefineParamU8(slot, 1);\n\tGetAccountIdEx((char*)accId, slot);\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnActExport_GetParentalControlSlotNoEx(PPCInterpreter_t* hCPU)\n{\n\t// GetParentalControlSlotNoEx(uint8* output, uint8 slot)\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetParentalControlSlotNoEx(0x{:08x}, 0x{:02x})\", hCPU->gpr[3], hCPU->gpr[4]);\n\t//memory_writeU8(hCPU->gpr[3], 0x01); // returned slot no (slot indices start at 1)\n\tmemory_writeU8(hCPU->gpr[3], 1); // 0 -> No parental control for slot?\n\t//memory_writeU8(hCPU->gpr[3], 0); // 0 -> No parental control for slot?\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnActExport_GetDefaultAccount(PPCInterpreter_t* hCPU)\n{\n\t// todo\n\tcemuLog_logDebug(LogType::Force, \"GetDefaultAccount(): Return 1?\");\n\tosLib_returnFromFunction(hCPU, 1);\n}\n\nvoid nnActExport_GetSlotNo(PPCInterpreter_t* hCPU)\n{\n\t// id of active account\n\tosLib_returnFromFunction(hCPU, 1); // 1 is the first slot (0 is invalid)\n}\n\nvoid nnActExport_GetSlotNoEx(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.GetSlotNoEx(...)\");\n\t// get slot no by uuid\n\tppcDefineParamUStr(uuid, 0);\n\n\t// get slot no for a specific uuid\n\tfor (uint8 i = 1; i < 12; i++)\n\t{\n\t\tuint8 accUuid[16]{};\n\t\tnn::act::GetUuidEx(accUuid, i);\n\t\tif (memcmp(uuid, accUuid, 16) == 0)\n\t\t{\n\t\t\tosLib_returnFromFunction(hCPU, i);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tcemu_assert_debug(false); // suspicious behavior?\n\n\tosLib_returnFromFunction(hCPU, 0); // account not found\n}\n\nvoid nnActExport_Initialize(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"nn_act.Initialize()\");\n\n\tnn::act::Initialize();\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnActExport_HasNfsAccount(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"Called nn_act.HasNfsAccount\");\n\tosLib_returnFromFunction(hCPU, 1); // Nfs = Nintendo Friend System? (Splatoon tries to call nn_fp.RegisterAccount if we set this to false)\n}\n\ntypedef struct  \n{\n\t/* +0x000 */ char token[0x201]; // /nex_token/token\n\t/* +0x201 */ uint8 padding201[3];\n\t/* +0x204 */ char nexPassword[0x41]; // /nex_token/nex_password\n\t/* +0x245 */ uint8 padding245[3];\n\t/* +0x248 */ char host[0x10]; // /nex_token/host\n\t/* +0x258 */ uint16be port; // /nex_token/port\n\t/* +0x25A */ uint16be padding25A;\n}nexServiceToken_t;\n\nstatic_assert(sizeof(nexServiceToken_t) == 0x25C, \"nexServiceToken_t has invalid size\");\n\nvoid nnActExport_AcquireNexServiceToken(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(token, nexServiceToken_t, 0);\n\tppcDefineParamU32(serverId, 1);\n\tmemset(token, 0, sizeof(nexServiceToken_t));\n\tactPrepareRequest();\n\tactRequest->accountSlot = iosu::act::ACT_SLOT_CURRENT;\n\tactRequest->requestCode = IOSU_ARC_ACQUIRENEXTOKEN;\n\tactRequest->titleId = CafeSystem::GetForegroundTitleId();\n\tactRequest->titleVersion = CafeSystem::GetForegroundTitleVersion();\n\tactRequest->serverId = serverId;\n\n\tuint32 resultCode = __depr__IOS_Ioctlv(IOS_DEVICE_ACT, IOSU_ACT_REQUEST_CEMU, 1, 1, actBufferVector);\n\n\tmemcpy(token, actRequest->resultBinary.binBuffer, sizeof(nexServiceToken_t));\n\n\tcemuLog_logDebug(LogType::Force, \"Called nn_act.AcquireNexServiceToken\");\n\tosLib_returnFromFunction(hCPU, getNNReturnCode(resultCode, actRequest));\n}\n\nvoid nnActExport_AcquireIndependentServiceToken(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(token, independentServiceToken_t, 0);\n\tppcDefineParamMEMPTR(clientId, const char, 1);\n\tuint32 result = nn::act::AcquireIndependentServiceToken(token.GetPtr(), clientId.GetPtr(), 0);\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid nnActExport_AcquireIndependentServiceToken2(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(token, independentServiceToken_t, 0);\n\tppcDefineParamMEMPTR(clientId, const char, 1);\n\tppcDefineParamU32(cacheDurationInSeconds, 2); \n\tuint32 result = nn::act::AcquireIndependentServiceToken(token, clientId.GetPtr(), cacheDurationInSeconds);\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid nnActExport_AcquireEcServiceToken(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(pEcServiceToken, independentServiceToken_t, 0);\n\tuint32 result = nn::act::AcquireIndependentServiceToken(pEcServiceToken.GetPtr(), \"71a6f5d6430ea0183e3917787d717c46\", 0);\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nvoid nnActExport_AcquirePrincipalIdByAccountId(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamMEMPTR(principalId, uint32be, 0);\n\tppcDefineParamMEMPTR(nnid, char, 1);\n\tppcDefineParamU32(ukn, 2); // some option, can be 0 or 1 ?\n\tcemuLog_logDebug(LogType::Force, \"nn_act.AcquirePrincipalIdByAccountId(0x{:08x},\\\"{}\\\", {}) - last param unknown\", principalId.GetMPTR(), nnid.GetPtr(), ukn);\n\tactPrepareRequest2();\n\tactRequest->requestCode = IOSU_ARC_ACQUIREPIDBYNNID;\n\tstrcpy(actRequest->clientId, nnid.GetPtr());\n\n\tuint32 result = _doCemuActRequest(actRequest);\n\n\t*principalId.GetPtr() = actRequest->resultU32.u32;\n\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nnamespace nn::act\n{\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_act\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"nn_act\", \"Initialize__Q2_2nn3actFv\", nnActExport_Initialize);\n\n\t\t\tosLib_addFunction(\"nn_act\", \"CreateConsoleAccount__Q2_2nn3actFv\", nnActExport_CreateConsoleAccount);\n\n\t\t\tosLib_addFunction(\"nn_act\", \"GetNumOfAccounts__Q2_2nn3actFv\", nnActExport_GetNumOfAccounts);\n\t\t\tosLib_addFunction(\"nn_act\", \"IsSlotOccupied__Q2_2nn3actFUc\", nnActExport_IsSlotOccupied);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetSlotNo__Q2_2nn3actFv\", nnActExport_GetSlotNo);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetSlotNoEx__Q2_2nn3actFRC7ACTUuid\", nnActExport_GetSlotNoEx);\n\t\t\tosLib_addFunction(\"nn_act\", \"IsNetworkAccount__Q2_2nn3actFv\", nnActExport_IsNetworkAccount);\n\t\t\tosLib_addFunction(\"nn_act\", \"IsNetworkAccountEx__Q2_2nn3actFUc\", nnActExport_IsNetworkAccountEx);\n\t\t\t// account id\n\t\t\tosLib_addFunction(\"nn_act\", \"GetAccountId__Q2_2nn3actFPc\", nnActExport_GetAccountId);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetAccountIdEx__Q2_2nn3actFPcUc\", nnActExport_GetAccountIdEx);\n\t\t\t// simple address\n\t\t\tosLib_addFunction(\"nn_act\", \"GetSimpleAddressId__Q2_2nn3actFv\", nnActExport_GetSimpleAddressId);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetSimpleAddressIdEx__Q2_2nn3actFPUiUc\", nnActExport_GetSimpleAddressIdEx);\n\t\t\t// principal id\n\t\t\tosLib_addFunction(\"nn_act\", \"GetPrincipalId__Q2_2nn3actFv\", nnActExport_GetPrincipalId);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetPrincipalIdEx__Q2_2nn3actFPUiUc\", nnActExport_GetPrincipalIdEx);\n\t\t\t// transferable id\n\t\t\tosLib_addFunction(\"nn_act\", \"GetTransferableId__Q2_2nn3actFUi\", nnActExport_GetTransferableId);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetTransferableIdEx__Q2_2nn3actFPULUiUc\", nnActExport_GetTransferableIdEx);\n\t\t\t// persistent id\n\t\t\tosLib_addFunction(\"nn_act\", \"GetPersistentId__Q2_2nn3actFv\", nnActExport_GetPersistentId);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetPersistentIdEx__Q2_2nn3actFUc\", nnActExport_GetPersistentIdEx);\n\t\t\t// country\n\t\t\tosLib_addFunction(\"nn_act\", \"GetCountry__Q2_2nn3actFPc\", nnActExport_GetCountry);\n\t\t\t// timezone\n\t\t\tcafeExportRegisterFunc(nn::act::GetTimeZoneId, \"nn_act\", \"GetTimeZoneId__Q2_2nn3actFPc\", LogType::Placeholder);\n\n\t\t\t// parental\n\t\t\tosLib_addFunction(\"nn_act\", \"EnableParentalControlCheck__Q2_2nn3actFb\", nnActExport_EnableParentalControlCheck);\n\t\t\tosLib_addFunction(\"nn_act\", \"IsParentalControlCheckEnabled__Q2_2nn3actFv\", nnActExport_IsParentalControlCheckEnabled);\n\n\t\t\tosLib_addFunction(\"nn_act\", \"GetMii__Q2_2nn3actFP12FFLStoreData\", nnActExport_GetMii);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetMiiEx__Q2_2nn3actFP12FFLStoreDataUc\", nnActExport_GetMiiEx);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetMiiImageEx__Q2_2nn3actFPUiPvUi15ACTMiiImageTypeUc\", nnActExport_GetMiiImageEx);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetMiiName__Q2_2nn3actFPw\", nnActExport_GetMiiName);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetMiiNameEx__Q2_2nn3actFPwUc\", nnActExport_GetMiiNameEx);\n\n\t\t\tosLib_addFunction(\"nn_act\", \"UpdateMii__Q2_2nn3actFUcRC12FFLStoreDataPCwPCvUiT4T5T4T5T4T5T4T5T4T5T4T5T4T5T4T5\", nnActExport_UpdateMii);\n\n\t\t\tosLib_addFunction(\"nn_act\", \"GetUuid__Q2_2nn3actFP7ACTUuid\", nnActExport_GetUuid);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetUuidEx__Q2_2nn3actFP7ACTUuidUc\", nnActExport_GetUuidEx);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetUuidEx__Q2_2nn3actFP7ACTUuidUcUi\", nnActExport_GetUuidEx2);\n\n\t\t\tosLib_addFunction(\"nn_act\", \"GetParentalControlSlotNoEx__Q2_2nn3actFPUcUc\", nnActExport_GetParentalControlSlotNoEx);\n\n\t\t\tosLib_addFunction(\"nn_act\", \"GetDefaultAccount__Q2_2nn3actFv\", nnActExport_GetDefaultAccount);\n\n\t\t\tosLib_addFunction(\"nn_act\", \"AcquireEcServiceToken__Q2_2nn3actFPc\", nnActExport_AcquireEcServiceToken);\n\t\t\tosLib_addFunction(\"nn_act\", \"AcquireNexServiceToken__Q2_2nn3actFP26ACTNexAuthenticationResultUi\", nnActExport_AcquireNexServiceToken);\n\t\t\tosLib_addFunction(\"nn_act\", \"AcquireIndependentServiceToken__Q2_2nn3actFPcPCc\", nnActExport_AcquireIndependentServiceToken);\n\t\t\tosLib_addFunction(\"nn_act\", \"AcquireIndependentServiceToken__Q2_2nn3actFPcPCcUibT4\", nnActExport_AcquireIndependentServiceToken2);\n\t\t\tosLib_addFunction(\"nn_act\", \"AcquireIndependentServiceToken__Q2_2nn3actFPcPCcUi\", nnActExport_AcquireIndependentServiceToken2);\n\n\t\t\tosLib_addFunction(\"nn_act\", \"AcquirePrincipalIdByAccountId__Q2_2nn3actFPUiPA17_CcUi\", nnActExport_AcquirePrincipalIdByAccountId);\n\n\t\t\tcafeExportRegisterFunc(nn::act::GetErrorCode, \"nn_act\", \"GetErrorCode__Q2_2nn3actFRCQ2_2nn6Result\", LogType::Placeholder);\n\n\t\t\t// placeholders / incomplete implementations\n\t\t\tosLib_addFunction(\"nn_act\", \"HasNfsAccount__Q2_2nn3actFv\", nnActExport_HasNfsAccount);\n\t\t\tosLib_addFunction(\"nn_act\", \"GetHostServerSettings__Q2_2nn3actFPcT1Uc\", nnActExport_GetHostServerSettings);\n\t\t\tcafeExportRegisterFunc(nn::act::GetUtcOffset, \"nn_act\", \"GetUtcOffset__Q2_2nn3actFv\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(nn::act::GetUtcOffsetEx, \"nn_act\", \"GetUtcOffsetEx__Q2_2nn3actFPLUc\", LogType::Placeholder);\n\n\t\t};\n\n\t}s_COSnnActModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnActModule;\n\t}\n}\n\n\n\n\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_act/nn_act.h",
    "content": "#pragma once\n\n#include \"Cafe/IOSU/legacy/iosu_act.h\"\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nstruct independentServiceToken_t\n{\n\t/* +0x000 */ char token[0x201];\n};\nstatic_assert(sizeof(independentServiceToken_t) == 0x201); // todo - verify size\n\nnamespace nn\n{\nnamespace act\n{\n\tuint32 Initialize();\n\n\tuint32 GetPersistentIdEx(uint8 slot);\n\tuint32 GetUuidEx(uint8* uuid, uint8 slot, sint32 name = -2);\n\tuint32 GetSimpleAddressIdEx(uint32be* simpleAddressId, uint8 slot);\n\tuint32 GetTransferableIdEx(uint64* transferableId, uint32 unique, uint8 slot);\n\n\tsint64 GetUtcOffset();\n\tsint32 GetUtcOffsetEx(sint64be* pOutOffset, uint8 slotNo);\n\n\tuint32 AcquireIndependentServiceToken(independentServiceToken_t* token, const char* clientId, uint32 cacheDurationInSeconds);\n\n\tstatic uint32 getCountryCodeFromSimpleAddress(uint32 simpleAddressId)\n\t{\n\t\treturn (simpleAddressId>>24)&0xFF;\n\t}\n\n\tconst uint8 ACT_SLOT_CURRENT = 0xFE;\n\n\tCOSModule* GetModule();\n}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_aoc/nn_aoc.cpp",
    "content": "#include \"config/ActiveSettings.h\"\n\n#include \"Cafe/OS/libs/nn_aoc/nn_aoc.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n#include \"Cafe/TitleList/TitleId.h\"\n\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"Common/FileStream.h\"\n\nnamespace nn\n{\n\tnamespace aoc\n\t{\n\t\tstruct AOCTitle\n\t\t{\n\t\t\tuint64be titleId;\n\t\t\tuint32be groupId;\n\t\t\tuint16be titleVersion;\n\t\t\tchar path[88];\n\t\t\tuint8 padding[2];\n\t\t};\n\t\tstatic_assert(sizeof(AOCTitle) == 0x68);\n\n\t\tenum class AOC_RESULT : uint32\n\t\t{\n\t\t\tERROR_OK = 0,\n\t\t};\n\n\t\tuint32 AOC_CalculateWorkBufferSize(uint32 count)\n\t\t{\n\t\t\tcount = std::min(count, (uint32)256);\n\t\t\tuint32 workBufferSize = 0x80 + count * 0x61;\n\t\t\treturn workBufferSize;\n\t\t}\n\n\t\tstruct AOCCacheEntry\n\t\t{\n\t\t\tAOCCacheEntry(uint64 titleId) : aocTitleId(titleId) {};\n\n\t\t\tuint64 aocTitleId;\n\t\t\tstd::string GetPath()\n\t\t\t{\n\t\t\t\treturn fmt::format(\"/vol/aoc{:016x}\", aocTitleId);\n\t\t\t}\n\t\t};\n\n\t\tstd::vector<AOCCacheEntry> sAocCache;\n\t\tbool sAocCacheGenerated = false;\n\n\t\tvoid generateAOCList()\n\t\t{\n\t\t\tif (sAocCacheGenerated)\n\t\t\t\treturn;\n\t\t\tsAocCacheGenerated = true;\n\n\t\t\tsint32 fscStatus;\n\t\t\tFSCVirtualFile* volDirIterator = fsc_openDirIterator(\"/vol\", &fscStatus);\n\t\t\tcemu_assert_debug(volDirIterator); // for valid titles /vol should always exist\n\t\t\tif (volDirIterator)\n\t\t\t{\n\t\t\t\tFSCDirEntry dirEntry;\n\t\t\t\twhile (fsc_nextDir(volDirIterator, &dirEntry))\n\t\t\t\t{\n\t\t\t\t\tstd::string_view dirName = dirEntry.GetPath();\n\t\t\t\t\tif(!dirEntry.isDirectory)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t// check for pattern: aoc<titleId>\n\t\t\t\t\tif(dirName.size() != (3+16))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif(dirName[0] != 'a' ||\n\t\t\t\t\t\tdirName[1] != 'o' ||\n\t\t\t\t\t\tdirName[2] != 'c')\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tTitleId aocTitleId;\n\t\t\t\t\tif( !TitleIdParser::ParseFromStr(dirName.substr(3), aocTitleId) )\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t// add to list of known AOC\n\t\t\t\t\tsAocCache.emplace_back(aocTitleId);\n\t\t\t\t}\n\t\t\t\tfsc_close(volDirIterator);\n\t\t\t}\n\t\t}\n\n\t\tAOC_RESULT AOC_ListTitle(uint32be* titleCountOut, AOCTitle* titleList, uint32 maxCount, void* workBuffer, uint32 workBufferSize)\n\t\t{\n\t\t\tgenerateAOCList();\n\t\t\tfor (uint32 i = 0; i < std::min(maxCount, (uint32)sAocCache.size()); i++)\n\t\t\t{\n\t\t\t\ttitleList[i].titleId = sAocCache[i].aocTitleId;\n\t\t\t\ttitleList[i].groupId = 0; // todo\n\t\t\t\ttitleList[i].titleVersion = 0; // todo\n\t\t\t\tstrcpy(titleList[i].path, sAocCache[i].GetPath().c_str());\n\t\t\t}\n\t\t\t*titleCountOut = std::min(maxCount, (uint32)sAocCache.size());\n\t\t\treturn AOC_RESULT::ERROR_OK;\n\t\t}\n\n\t\tAOC_RESULT AOC_OpenTitle(char* pathOut, AOCTitle* aocTitleInfo, void* workBuffer, uint32 workBufferSize)\n\t\t{\n\t\t\tstrcpy(pathOut, aocTitleInfo->path);\n\t\t\treturn AOC_RESULT::ERROR_OK;\n\t\t}\n\n\t\tAOC_RESULT AOC_CloseTitle(void* ukn)\n\t\t{\n\t\t\treturn AOC_RESULT::ERROR_OK;\n\t\t}\n\n\t\tAOC_RESULT AOC_GetPurchaseInfo(uint32be* purchaseBoolArrayOut, uint64 titleId, uint16be* entryIds, uint32 entryCount, void* workBuffer, uint32 workBufferSize)\n\t\t{\n\t\t\t// open ticket file\n\t\t\t// on an actual Wii U they get stored to SLC but the download manager places these in the code folder currently\n\t\t\tconst auto ticketPath = ActiveSettings::GetMlcPath(L\"usr/title/{:08x}/{:08x}/code/title.tik\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\t\tuint32 tikFileSize = 0;\n\t\t\tstd::unique_ptr<FileStream> fileStream(FileStream::openFile2(ticketPath));\n\t\t\tstd::vector<uint8> tikData;\n\t\t\tif (fileStream)\n\t\t\t\tfileStream->extract(tikData);\n\t\t\tif (tikData.size() > 0)\n\t\t\t{\n\t\t\t\tNCrypto::ETicketParser eTicket;\n\t\t\t\tif (eTicket.parse(tikData.data(), tikData.size()))\n\t\t\t\t{\n\t\t\t\t\tfor (uint32 i = 0; i < entryCount; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tuint16 id = entryIds[i];\n\t\t\t\t\t\tif (eTicket.CheckRight(id))\n\t\t\t\t\t\t\tpurchaseBoolArrayOut[i] = 1;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tpurchaseBoolArrayOut[i] = 0;\n\t\t\t\t\t}\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Using content rights from AOC title.tik\");\n\t\t\t\t\treturn AOC_RESULT::ERROR_OK;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Unable to parse AOC title.tik\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// fallback: return true for all contentIds\n\t\t\tfor (uint32 i = 0; i < entryCount; i++)\n\t\t\t{\n\t\t\t\tuint16 id = entryIds[i];\n\t\t\t\tpurchaseBoolArrayOut[i] = 1;\n\t\t\t}\n\n\t\t\treturn AOC_RESULT::ERROR_OK;\n\t\t}\n\n\t\tclass : public COSModule\n\t\t{\n\t\t\tpublic:\n\t\t\tstd::string_view GetName() override\n\t\t\t{\n\t\t\t\treturn \"nn_aoc\";\n\t\t\t}\n\n\t\t\tvoid RPLMapped() override\n\t\t\t{\n\t\t\t\tcafeExportRegister(\"nn_aoc\", AOC_CalculateWorkBufferSize, LogType::NN_AOC);\n\t\t\t\tcafeExportRegister(\"nn_aoc\", AOC_ListTitle, LogType::NN_AOC);\n\n\t\t\t\tcafeExportRegister(\"nn_aoc\", AOC_OpenTitle, LogType::NN_AOC);\n\t\t\t\tcafeExportRegister(\"nn_aoc\", AOC_CloseTitle, LogType::NN_AOC);\n\t\t\t\tcafeExportRegister(\"nn_aoc\", AOC_GetPurchaseInfo, LogType::NN_AOC);\n\t\t\t};\n\t\t}s_COSnnAocModule;\n\n\t\tCOSModule* GetModule()\n\t\t{\n\t\t\treturn &s_COSnnAocModule;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_aoc/nn_aoc.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::aoc\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_boss/nn_boss.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"Cafe/OS/libs/nn_client_service.h\"\n#include \"Cafe/OS/libs/nn_act/nn_act.h\"\n#include \"Cafe/OS/libs/nn_ac/nn_ac.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n#include \"Cafe/IOSU/legacy/iosu_act.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n#include \"Common/CafeString.h\"\n#include \"Cafe/IOSU/nn/boss/boss_common.h\"\n\nnamespace nn\n{\nnamespace boss\n{\n\tIPCServiceClient s_ipcClient;\n\n\tstatic constexpr BossResult resultSuccess = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_BOSS, 0x80);\n\tstatic constexpr BossResult resultInvalidParam = BUILD_NN_RESULT(NN_RESULT_LEVEL_LVL6, NN_RESULT_MODULE_NN_BOSS, 0x3780);\n\tstatic constexpr BossResult resultUknA0220300 = BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_BOSS, 0x20300);\n\n\tSysAllocator<coreinit::OSMutex> g_mutex;\n\tsint32 g_initCounter = 0;\n\tbool g_isInitialized = false;\n\n\t#define DTOR_WRAPPER(__TYPE) RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) { dtor(MEMPTR<__TYPE>(hCPU->gpr[3]), hCPU->gpr[4]); osLib_returnFromFunction(hCPU, 0); })\n\n\tSysAllocator<uint8, 0x10000, 64> s_ipcBuffer;\n\n\tconstexpr uint32 BOSS_MEM_MAGIC = 0xCAFE4321;\n\n\ttemplate<typename T>\n\tMEMPTR<T> boss_new()\n\t{\n\t\tuint32 objSize = sizeof(T);\n\t\tuint32be* basePtr = (uint32be*)coreinit::_weak_MEMAllocFromDefaultHeapEx(objSize + 8, 0x8);\n\t\tbasePtr[0] = BOSS_MEM_MAGIC;\n\t\tbasePtr[1] = objSize;\n\t\treturn (T*)(basePtr+2);\n\t}\n\n\tvoid boss_delete(MEMPTR<void> mem)\n\t{\n\t\tif(!mem)\n\t\t\treturn;\n\t\tuint32be* basePtr = (uint32be*)mem.GetPtr() - 2;\n\t\tif(basePtr[0] != BOSS_MEM_MAGIC)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"nn_boss: Detected memory corruption\");\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t\tcoreinit::_weak_MEMFreeToDefaultHeap(basePtr);\n\t}\n\n\tBossResult Initialize() // Initialize__Q2_2nn4bossFv\n\t{\n\t\tcoreinit::OSLockMutex(&g_mutex);\n\t\tBossResult result = 0;\n\t\tif(g_initCounter == 0)\n\t\t{\n\t\t\tg_isInitialized = true;\n\t\t\ts_ipcClient.Initialize(\"/dev/boss\", s_ipcBuffer.GetPtr(), s_ipcBuffer.GetByteSize());\n\t\t\tresult = resultSuccess;\n\t\t}\n\t\tg_initCounter++;\n\t\tcoreinit::OSUnlockMutex(&g_mutex);\n\t\treturn NN_RESULT_IS_SUCCESS(result) ? 0 : result;\n\t}\n\n\tuint32 IsInitialized() // IsInitialized__Q2_2nn4bossFv\n\t{\n\t\treturn g_isInitialized;\n\t}\n\n\tvoid Finalize() // Finalize__Q2_2nn4bossFv\n\t{\n\t\tcoreinit::OSLockMutex(&g_mutex);\n\t\tif(g_initCounter == 0)\n\t\t\tcemuLog_log(LogType::Force, \"nn_boss: Finalize() called without corresponding Initialize()\");\n\t\tif(g_initCounter == 1)\n\t\t{\n\t\t\ts_ipcClient.Shutdown();\n\t\t\tg_isInitialized = false;\n\t\t}\n\t\tg_initCounter--;\n\t\tcoreinit::OSUnlockMutex(&g_mutex);\n\t}\n\n\tuint32 GetBossState(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_logDebugOnce(LogType::Force, \"nn_boss.GetBossState() - stub\");\n\t\treturn 7;\n\t}\n\n\t/* TitleId */\n\n\tbool TitleId::IsValid(TitleId* _thisptr)\n\t{\n\t\treturn _thisptr->u64 != 0;\n\t}\n\n\tTitleId* TitleId::ctorDefault(TitleId* _thisptr)\n\t{\n\t\tif (!_thisptr)\n\t\t\t_thisptr = boss_new<TitleId>();\n\t\t_thisptr->u64 = 0;\n\t\treturn _thisptr;\n\t}\n\n\tTitleId* TitleId::ctorFromTitleId(TitleId* _thisptr, uint64 titleId) // __ct__Q3_2nn4boss7TitleIDFUL\n\t{\n\t\tif (!_thisptr)\n\t\t\t_thisptr = boss_new<TitleId>();\n\t\t_thisptr->u64 = titleId;\n\t\treturn _thisptr;\n\t}\n\n\tTitleId* TitleId::ctorCopy(TitleId* _thisptr, TitleId* titleId) // __ct__Q3_2nn4boss7TitleIDFRCQ3_2nn4boss7TitleID\n\t{\n\t\tif (!_thisptr)\n\t\t\t_thisptr = boss_new<TitleId>();\n\t\t_thisptr->u64 = titleId->u64;\n\t\treturn _thisptr;\n\t}\n\n\tbool TitleId::operator_ne(TitleId* _thisptr, TitleId* titleId)\n\t{\n\t\treturn _thisptr->u64 != titleId->u64;\n\t}\n\t/* TaskId */\n\n\tTaskId* TaskId::ctorDefault(TaskId* _thisptr)\n\t{\n\t\tif (!_thisptr)\n\t\t\t_thisptr = boss_new<TaskId>();\n\t\t_thisptr->id.data[0] = 0;\n\t\treturn _thisptr;\n\t}\n\n\tTaskId* TaskId::ctorFromString(TaskId* _thisptr, const char* taskId)\n\t{\n\t\tif (!_thisptr)\n\t\t\t_thisptr = boss_new<TaskId>();\n\t\t_thisptr->id.assign(taskId);\n\t\treturn _thisptr;\n\t}\n\n\t/* Title */\n\t\n\tTitle* Title::ctor(Title* _this)\n\t{\n\t\tif (!_this)\n\t\t\t_this = boss_new<Title>();\n\t\t*_this = {};\n\t\t_this->vTablePtr = s_titleVTable;\n\t\treturn _this;\n\t}\n\n\tvoid Title::dtor(Title* _this, uint32 options)\n\t{\n\t\tif (_this && (options & 1))\n\t\t\tboss_delete(_this);\n\t}\n\n\tvoid Title::InitVTable()\n\t{\n\t\ts_titleVTable->rtti.ptr = nullptr; // todo\n\t\ts_titleVTable->dtor.ptr = DTOR_WRAPPER(Title);\n\t}\n\n\t/* DirectoryName */\n\n\tDirectoryName* DirectoryName::ctor(DirectoryName* _thisptr)\n\t{\n\t\tif (!_thisptr)\n\t\t\t_thisptr = boss_new<DirectoryName>();\n\t\t_thisptr->name2.ClearAllBytes();\n\t\treturn _thisptr;\n\t}\n\n\tconst char* DirectoryName::operator_const_char(DirectoryName* _thisptr)\n\t{\n\t\treturn _thisptr->name2.c_str();\n\t}\n\n\t/* BossAccount */\n\n\tBossAccount* BossAccount::ctor(BossAccount* _this, uint32 accountId)\n\t{\n\t\tif (!_this)\n\t\t\t_this = boss_new<BossAccount>();\n\t\t_this->accountId = accountId;\n\t\t_this->vTablePtr = s_VTable;\n\t\treturn _this;\n\t}\n\n\tvoid BossAccount::dtor(BossAccount* _this, uint32 options)\n\t{\n\t\tif(_this && options & 1)\n\t\t\tboss_delete(_this);\n\t}\n\n\tvoid BossAccount::InitVTable()\n\t{\n\t\ts_VTable->rtti.ptr = nullptr; // todo\n\t\ts_VTable->dtor.ptr = DTOR_WRAPPER(BossAccount);\n\t}\n\n\t/* TaskSetting */\n\n\tTaskSetting* TaskSetting::ctor(TaskSetting* _thisptr)\n\t{\n\t\tif(!_thisptr)\n\t\t\t_thisptr = boss_new<TaskSetting>();\n\t\t_thisptr->vTablePtr = s_VTable;\n\t\tInitializeSetting(_thisptr);\n\t\treturn _thisptr;\n\t}\n\n\tvoid TaskSetting::dtor(TaskSetting* _this, uint32 options)\n\t{\n\t\tif(options & 1)\n\t\t\tboss_delete(_this);\n\t}\n\n\tbool TaskSetting::IsPrivileged(TaskSetting* _thisptr)\n\t{\n\t\tconst TaskType taskType = _thisptr->taskType;\n\t\treturn taskType == TaskType::RawDlTaskSetting_1 || taskType == TaskType::RawDlTaskSetting_9 || taskType == TaskType::PlayLogUploadTaskSetting;\n\t}\n\n\tvoid TaskSetting::InitializeSetting(TaskSetting* _thisptr)\n\t{\n\t\tmemset(_thisptr, 0x00, 0x1000);\n\t\t_thisptr->persistentId = 0;\n\t\t_thisptr->ukn08 = 0;\n\t\t_thisptr->ukn0C = 0;\n\t\t_thisptr->priority = 125;\n\t\t_thisptr->intervalB = 28800;\n\t\t_thisptr->lifeTime.high = 0;\n\t\t_thisptr->lifeTime.low = 0x76A700;\n\t}\n\n\tvoid TaskSetting::InitVTable()\n\t{\n\t\ts_VTable->rtti.ptr = nullptr; // todo\n\t\ts_VTable->dtor.ptr = DTOR_WRAPPER(TaskSetting);\n\t\ts_VTable->RegisterPreprocess.ptr = nullptr; // todo\n\t\ts_VTable->unk1.ptr = nullptr; // todo\n\t}\n\n\t/* NetTaskSetting */\n\n\tNetTaskSetting* NetTaskSetting::ctor(NetTaskSetting* _thisptr)\n\t{\n\t\tif (!_thisptr)\n\t\t\t_thisptr = boss_new<NetTaskSetting>();\n\t\tTaskSetting::ctor(_thisptr);\n\t\t_thisptr->httpTimeout = 120;\n\t\t_thisptr->vTablePtr = s_VTable;\n\t\treturn _thisptr;\n\t}\n\n\tBossResult NetTaskSetting::AddCaCert(NetTaskSetting* _thisptr, const char* name)\n\t{\n\t\tif(name == nullptr || strnlen(name, 0x80) == 0x80)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nn_boss_NetTaskSetting_AddCaCert: name size is invalid\");\n\t\t\treturn resultInvalidParam;\n\t\t}\n\n\t\tcemu_assert_unimplemented();\n\n\t\treturn 0xA0220D00;\n\t}\n\n\tBossResult NetTaskSetting::SetServiceToken(NetTaskSetting* _thisptr, const uint8* serviceToken) // input is uint8[512]?\n\t{\n\t\tmemcpy(_thisptr->serviceToken.data, serviceToken, _thisptr->serviceToken.Size());\n\t\treturn resultSuccess;\n\t}\n\n\tBossResult NetTaskSetting::AddInternalCaCert(NetTaskSetting* _thisptr, char certId)\n\t{\n\t\tfor(int i = 0; i < 3; i++)\n\t\t{\n\t\t\tif(_thisptr->internalCaCert[i] == 0)\n\t\t\t{\n\t\t\t\t_thisptr->internalCaCert[i] = (uint8)certId;\n\t\t\t\treturn resultSuccess;\n\t\t\t}\n\t\t}\n\t\tcemuLog_logDebug(LogType::Force, \"nn_boss_NetTaskSetting_AddInternalCaCert: Cannot store more than 3 certificates\");\n\t\treturn 0xA0220D00;\n\t}\n\n\tvoid NetTaskSetting::SetInternalClientCert(NetTaskSetting* _thisptr, char certId)\n\t{\n\t\t_thisptr->internalClientCert = (uint8)certId;\n\t}\n\n\tvoid NetTaskSetting::InitVTable()\n\t{\n\t\ts_VTable->rtti.ptr = nullptr; // todo\n\t\ts_VTable->dtor.ptr = DTOR_WRAPPER(NetTaskSetting);\n\t\ts_VTable->RegisterPreprocess.ptr = nullptr; // todo\n\t\ts_VTable->unk1.ptr = nullptr; // todo\n\t}\n\n\t/* NbdlTaskSetting */\n\n\tNbdlTaskSetting* NbdlTaskSetting::ctor(NbdlTaskSetting* _thisptr)\n\t{\n\t\tif (!_thisptr)\n\t\t\t_thisptr = boss_new<NbdlTaskSetting>();\n\t\tNetTaskSetting::ctor(_thisptr);\n\t\t_thisptr->vTablePtr = s_VTable;\n\t\treturn _thisptr;\n\t}\n\n\tBossResult NbdlTaskSetting::Initialize(NbdlTaskSetting* _thisptr, const char* bossCode, uint64 directorySizeLimit, const char* bossDirectory) // Initialize__Q3_2nn4boss15NbdlTaskSettingFPCcLT1\n\t{\n\t\tif (!bossCode || !_thisptr->nbdl.bossCode.CanHoldString(bossCode))\n\t\t\treturn resultInvalidParam;\n\t\tif (bossDirectory && !_thisptr->nbdl.bossDirectory.CanHoldString(bossDirectory))\n\t\t\treturn resultInvalidParam; // directory is optional, but if a string is passed it must fit\n\t\t_thisptr->nbdl.bossCode.assign(bossCode);\n\t\tif (bossDirectory)\n\t\t\t_thisptr->nbdl.bossDirectory.assign(bossDirectory);\n\t\t_thisptr->nbdl.directorySizeLimitHigh = (uint32be)(directorySizeLimit >> 32);\n\t\t_thisptr->nbdl.directorySizeLimitLow = (uint32be)(directorySizeLimit & 0xFFFFFFFF);\n\t\t_thisptr->taskType = TaskType::NbdlTaskSetting;\n\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_BOSS, 0x80);\n\t}\n\n\tBossResult NbdlTaskSetting::SetFileName(NbdlTaskSetting* _thisptr, const char* fileName)\n\t{\n\t\tif (!fileName || !_thisptr->nbdl.fileName.CanHoldString(fileName))\n\t\t\treturn resultInvalidParam;\n\t\t_thisptr->nbdl.fileName.assign(fileName);\n\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_BOSS, 0x80);\n\t}\n\n\tvoid NbdlTaskSetting::InitVTable()\n\t{\n\t\ts_VTable->rtti.ptr = nullptr; // todo\n\t\ts_VTable->dtor.ptr = DTOR_WRAPPER(NbdlTaskSetting);\n\t\ts_VTable->RegisterPreprocess.ptr = nullptr; // todo\n\t\ts_VTable->unk1.ptr = nullptr; // todo\n\t\ts_VTable->rttiNetTaskSetting.ptr = nullptr; // todo\n\t}\n\n\t/* RawUlTaskSetting */\n\n\tRawUlTaskSetting* RawUlTaskSetting::ctor(RawUlTaskSetting* _thisptr)\n\t{\n\t\tif (!_thisptr)\n\t\t\t_thisptr = boss_new<RawUlTaskSetting>();\n\t\tNetTaskSetting::ctor(_thisptr);\n\t\t_thisptr->vTablePtr = s_VTable;\n\t\t_thisptr->ukRaw1 = 0;\n\t\t_thisptr->ukRaw2 = 0;\n\t\t_thisptr->ukRaw3 = 0;\n\t\tmemset(_thisptr->rawSpace, 0x00, 0x200);\n\t\treturn _thisptr;\n\t}\n\n\tvoid RawUlTaskSetting::dtor(RawUlTaskSetting* _this, uint32 options)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"nn::boss::RawUlTaskSetting::dtor() is todo\");\n\t}\n\n\tvoid RawUlTaskSetting::InitVTable()\n\t{\n\t\ts_VTable->rtti.ptr = nullptr; // todo\n\t\ts_VTable->dtor.ptr = DTOR_WRAPPER(RawUlTaskSetting);\n\t\ts_VTable->RegisterPreprocess.ptr = nullptr; // todo\n\t\ts_VTable->unk1.ptr = nullptr; // todo\n\t\ts_VTable->rttiNetTaskSetting.ptr = nullptr; // todo\n\t}\n\n\t/* RawDlTaskSetting */\n\n\tRawDlTaskSetting* RawDlTaskSetting::ctor(RawDlTaskSetting* _thisptr)\n\t{\n\t\tif (!_thisptr)\n\t\t\t_thisptr = boss_new<RawDlTaskSetting>();\n\t\tNetTaskSetting::ctor(_thisptr);\n\t\t_thisptr->vTablePtr = s_VTable;\n\t\treturn _thisptr;\n\t}\n\n\tBossResult RawDlTaskSetting::Initialize(RawDlTaskSetting* _thisptr, const char* url, bool newArrival, bool led, const char* fileName, const char* bossDirectory)\n\t{\n\t\tif (!url || !_thisptr->url.CanHoldString(url))\n\t\t\treturn resultInvalidParam;\n\t\tcemuLog_logDebug(LogType::Force, \"RawDlTaskSetting::Initialize url: {}\", url);\n\t\tif (fileName && !_thisptr->rawDl.fileName.CanHoldString(fileName))\n\t\t\treturn resultInvalidParam; // fileName is optional, but if a string is passed it must fit\n\t\tif (!bossDirectory || !_thisptr->rawDl.bossDirectory.CanHoldString(bossDirectory))\n\t\t\treturn resultInvalidParam;\n\n\t\t_thisptr->url.assign(url);\n\t\t_thisptr->rawDl.fileName.assign(fileName ? fileName : \"rawcontent.dat\");\n\t\t_thisptr->rawDl.bossDirectory.assign(bossDirectory);\n\t\t_thisptr->rawDl.newArrival = newArrival;\n\t\t_thisptr->rawDl.led = led;\n\t\t_thisptr->taskType = TaskType::RawDlTaskSetting_3;\n\t\treturn resultSuccess;\n\t}\n\n\tvoid RawDlTaskSetting::InitVTable()\n\t{\n\t\ts_VTable->rtti.ptr = nullptr; // todo\n\t\ts_VTable->dtor.ptr = DTOR_WRAPPER(RawDlTaskSetting);\n\t\ts_VTable->RegisterPreprocess.ptr = nullptr; // todo\n\t\ts_VTable->unk1.ptr = nullptr; // todo\n\t\ts_VTable->rttiNetTaskSetting.ptr = nullptr; // todo\n\t}\n\n\t/* PlayReportSetting */\n\n\tPlayReportSetting* PlayReportSetting::ctor(PlayReportSetting* _this)\n\t{\n\t\tif(!_this)\n\t\t\t_this = boss_new<PlayReportSetting>();\n\t\tRawUlTaskSetting::ctor(_this);\n\t\t_this->vTablePtr = s_VTable;\n\t\t_this->ukn1210_ptr = nullptr;\n\t\t_this->ukn1214_size = 0;\n\t\t_this->ukPlay3 = 0;\n\t\t_this->ukPlay4 = 0;\n\t\treturn _this;\n\t}\n\n\tvoid PlayReportSetting::dtor(PlayReportSetting* _this, uint32 options)\n\t{\n\t\tRawUlTaskSetting::dtor(_this, 0);\n\t\tif(options&1)\n\t\t\tboss_delete(_this->ukn1210_ptr.GetPtr());\n\t}\n\n\tvoid PlayReportSetting::Initialize(PlayReportSetting* _this, uint8* ptr, uint32 size)\n\t{\n\t\tif (!ptr || size == 0 || size > 0x19000)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nn::boss::PlayReportSetting::Initialize: invalid parameter\");\n\t\t\treturn;\n\t\t}\n\n\t\t*ptr = 0;\n\n\t\t_this->taskType = TaskType::PlayReportSetting;\n\t\t_this->mode |= 3;\n\t\t_this->rawUl.optionValue |= 2;\n\t\t_this->permission |= 0xA;\n\n\t\t_this->ukn1210_ptr = ptr;\n\t\t_this->ukn1214_size = size;\n\t\t_this->ukPlay3 = 0;\n\t\t_this->ukPlay4 = 0;\n\n\t\t_this->AddInternalCaCert(_this, 102);\n\t\t_this->SetInternalClientCert(_this, 1);\n\n\t\t// todo - incomplete\n\t}\n\n\tbool PlayReportSetting::Set(PlayReportSetting* _this, const char* keyname, uint32 value)\n\t{\n\t\t// TODO\n\t\treturn true;\n\t}\n\n\tvoid PlayReportSetting::InitVTable()\n\t{\n\t\ts_VTable->rtti.ptr = nullptr; // todo\n\t\ts_VTable->dtor.ptr = DTOR_WRAPPER(PlayReportSetting);\n\t\ts_VTable->RegisterPreprocess.ptr = nullptr; // todo\n\t\ts_VTable->unk1.ptr = nullptr; // todo\n\t\ts_VTable->rttiNetTaskSetting.ptr = nullptr; // todo\n\t}\n\n\t/* Task */\n\n\tstruct Task\n\t{\n\t\tstruct VTableTask\n\t\t{\n\t\t\tVTableEntry rtti;\n\t\t\tVTableEntry dtor;\n\t\t};\n\t\tstatic inline SysAllocator<VTableTask> s_vTable;\n\n\t\tuint32be persistentId; // 0x00\n\t\tuint32be uk2; // 0x04\n\t\tTaskId taskId; // 0x08\n\t\tTitleId titleId; // 0x10\n\t\tMEMPTR<VTableTask> vTablePtr; // 0x18\n\t\tuint32be padding; // 0x1C\n\n\t\tstatic BossResult Initialize1(Task* _thisptr, const char* taskId, uint32 persistentId) // Initialize__Q3_2nn4boss4TaskFPCcUi\n\t\t{\n\t\t\tif (!taskId || !_thisptr->taskId.id.CanHoldString(taskId))\n\t\t\t\treturn resultInvalidParam;\n\t\t\t_thisptr->persistentId = persistentId;\n\t\t\t_thisptr->taskId.id.assign(taskId);\n\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_BOSS, 0x80);\n\t\t}\n\n\t\tstatic BossResult Initialize2(Task* _thisptr, uint8 slot, const char* taskId) // Initialize__Q3_2nn4boss4TaskFUcPCc\n\t\t{\n\t\t\tconst uint32 persistentId = slot == 0 ? 0 : act::GetPersistentIdEx(slot);\n\t\t\treturn Initialize1(_thisptr, taskId, persistentId);\n\t\t}\n\n\t\tstatic BossResult Initialize3(Task* _thisptr, const char* taskId) // Initialize__Q3_2nn4boss4TaskFPCc\n\t\t{\n\t\t\treturn Initialize1(_thisptr, taskId, 0);\n\t\t}\n\n\t\tstatic Task* ctor2(Task* _thisptr, const char* taskId, uint32 persistentId) // __ct__Q3_2nn4boss4TaskFPCcUi\n\t\t{\n\t\t\tif (!_thisptr)\n\t\t\t\t_thisptr = boss_new<Task>();\n\t\t\t_thisptr->persistentId = 0;\n\t\t\t_thisptr->vTablePtr = s_vTable;\n\t\t\tTaskId::ctorDefault(&_thisptr->taskId);\n\t\t\tTitleId::ctorFromTitleId(&_thisptr->titleId, 0);\n\t\t\tauto r = Initialize1(_thisptr, taskId, persistentId);\n\t\t\tcemu_assert_debug(NN_RESULT_IS_SUCCESS(r));\n\t\t\treturn _thisptr;\n\t\t}\n\n\t\tstatic Task* ctor1(Task* _thisptr, uint8 slot, const char* taskId) // __ct__Q3_2nn4boss4TaskFUcPCc\n\t\t{\n\t\t\tif (!_thisptr)\n\t\t\t\t_thisptr = boss_new<Task>();\n\t\t\t_thisptr->persistentId = 0;\n\t\t\t_thisptr->vTablePtr = s_vTable;\n\t\t\tTaskId::ctorDefault(&_thisptr->taskId);\n\t\t\tTitleId::ctorFromTitleId(&_thisptr->titleId, 0);\n\t\t\tauto r = Initialize2(_thisptr, slot, taskId);\n\t\t\tcemu_assert_debug(NN_RESULT_IS_SUCCESS(r));\n\t\t\treturn _thisptr;\n\t\t}\n\n\t\tstatic Task* ctor3(Task* _thisptr, const char* taskId) // __ct__Q3_2nn4boss4TaskFPCc\n\t\t{\n\t\t\tif (!_thisptr)\n\t\t\t\t_thisptr = boss_new<Task>();\n\t\t\t_thisptr->persistentId = 0;\n\t\t\t_thisptr->vTablePtr = s_vTable;\n\t\t\tTaskId::ctorDefault(&_thisptr->taskId);\n\t\t\tTitleId::ctorFromTitleId(&_thisptr->titleId, 0);\n\t\t\tauto r = Initialize3(_thisptr, taskId);\n\t\t\tcemu_assert_debug(NN_RESULT_IS_SUCCESS(r));\n\t\t\treturn _thisptr;\n\t\t}\n\n\t\tstatic Task* ctor4(Task* _thisptr) // __ct__Q3_2nn4boss4TaskFv\n\t\t{\n\t\t\tif (!_thisptr)\n\t\t\t\t_thisptr = boss_new<Task>();\n\t\t\t_thisptr->persistentId = 0;\n\t\t\t_thisptr->vTablePtr = s_vTable;\n\t\t\tTaskId::ctorDefault(&_thisptr->taskId);\n\t\t\tTitleId::ctorFromTitleId(&_thisptr->titleId, 0);\n\t\t\tmemset(&_thisptr->taskId, 0x00, sizeof(TaskId));\n\t\t\treturn _thisptr;\n\t\t}\n\n\t\tstatic void dtor(Task* _this, uint32 options) // __dt__Q3_2nn4boss4TaskFv\n\t\t{\n\t\t\t// todo - Task::Finalize\n\t\t\tif(options & 1)\n\t\t\t\tboss_delete(_this);\n\t\t}\n\n\t\tstatic BossResult Run(Task* _thisptr, bool isForegroundRun)\n\t\t{\n\t\t\tuint8be isConnected = 0;\n\t\t\tnn_ac::IsApplicationConnected(&isConnected);\n\t\t\tif (isForegroundRun && !isConnected)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"nn::boss::Task::Run: Application is not connected, returning error\");\n\t\t\t\treturn 0xA0223A00;\n\t\t\t}\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskRun));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\tserviceCall.WriteParam<uint8>(isForegroundRun ? 1 : 0);\n\t\t\treturn serviceCall.Submit();\n\t\t}\n\n\t\tstatic BossResult StartScheduling(Task* _thisptr, uint8 executeImmediately)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskStartScheduling));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\tserviceCall.WriteParam<uint8be>(executeImmediately);\n\t\t\treturn serviceCall.Submit();\n\t\t}\n\n\t\tstatic nnResult StopScheduling(Task* _thisptr)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskStopScheduling));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\treturn serviceCall.Submit();\n\t\t}\n\n\t\tstatic bool IsRegistered(Task* _thisptr)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskIsRegistered));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn false;\n\t\t\treturn serviceCall.ReadResponse<uint8be>() != 0;\n\t\t}\n\n\t\tstatic bool Wait(Task* _thisptr, uint32 timeout, TaskWaitState waitState) // Wait__Q3_2nn4boss4TaskFUiQ3_2nn4boss13TaskWaitState\n\t\t{\n\t\t\tstatic_assert(sizeof(TaskSettingCore) == 0xC00);\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskWaitA));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\tserviceCall.WriteParam<betype<TaskWaitState>>(waitState);\n\t\t\tserviceCall.WriteParam<uint32be>(timeout);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn false;\n\t\t\tuint8 isNotTimeout = serviceCall.ReadResponse<uint8be>();\n\t\t\treturn isNotTimeout;\n\t\t}\n\n\t\tstatic BossResult RegisterForImmediateRun(Task* _thisptr, TaskSetting* settings) // RegisterForImmediateRun__Q3_2nn4boss4TaskFRCQ3_2nn4boss11TaskSetting\n\t\t{\n\t\t\tstatic_assert(sizeof(TaskSettingCore) == 0xC00);\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskRegisterForImmediateRunA));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\tserviceCall.WriteParamBuffer(settings, sizeof(TaskSettingCore));\n\t\t\treturn serviceCall.Submit();\n\t\t}\n\n\t\tstatic BossResult Unregister(Task* _thisptr)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskUnregister));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\treturn serviceCall.Submit();\n\t\t}\n\n\t\tstatic BossResult Register(Task* _thisptr, TaskSetting* settings)\n\t\t{\n\t\t\tstatic_assert(sizeof(TaskSettingCore) == 0xC00);\n\t\t\tif (!settings)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"nn_boss_Task_Register - crash workaround (fix me)\"); // settings should never be zero\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t// todo - missing vcall which leads to nn::boss::PlayReportSetting::RegisterPreprocess (and other functions?) being called?\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskRegisterA));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\tserviceCall.WriteParamBuffer(settings, sizeof(TaskSettingCore));\n\t\t\treturn serviceCall.Submit();\n\t\t}\n\n\t\tstatic TaskTurnState GetTurnState(Task* _thisptr, uint32be* executionCounter)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskGetTurnState));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn (TaskTurnState)0;\n\t\t\tuint32 executionCount = serviceCall.ReadResponse<uint32be>();\n\t\t\tif (executionCounter)\n\t\t\t\t*executionCounter = executionCount;\n\t\t\treturn serviceCall.ReadResponse<betype<TaskTurnState>>();\n\t\t}\n\n\t\tstatic uint64 GetContentLength(Task* _thisptr, uint32be* executionCounter)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskGetContentLength));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn 0;\n\t\t\tuint32 executionCount = serviceCall.ReadResponse<uint32be>();\n\t\t\tif (executionCounter)\n\t\t\t\t*executionCounter = executionCount;\n\t\t\treturn serviceCall.ReadResponse<uint64be>();\n\t\t}\n\n\t\tstatic uint64 GetProcessedLength(Task* _thisptr, uint32be* executionCounter)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskGetProcessedLength));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn 0;\n\t\t\tuint32 executionCount = serviceCall.ReadResponse<uint32be>();\n\t\t\tif (executionCounter)\n\t\t\t\t*executionCounter = executionCount;\n\t\t\treturn serviceCall.ReadResponse<uint64be>();\n\t\t}\n\n\t\tstatic uint32 GetHttpStatusCode(Task* _thisptr, uint32be* executionCounter)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::TaskGetHttpStatusCodeA));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<TaskId>(_thisptr->taskId);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn 0;\n\t\t\tuint32 executionCount = serviceCall.ReadResponse<uint32be>();\n\t\t\tif (executionCounter)\n\t\t\t\t*executionCounter = executionCount;\n\t\t\treturn serviceCall.ReadResponse<uint32be>();\n\t\t}\n\n\t\tstatic void InitVTable()\n\t\t{\n\t\t\ts_vTable->rtti.ptr = nullptr; // todo\n\t\t\ts_vTable->dtor.ptr = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) { Task::dtor(MEMPTR<Task>(hCPU->gpr[3]), hCPU->gpr[4]); osLib_returnFromFunction(hCPU, 0); });\n\t\t}\n\t};\n\n\tstatic_assert(sizeof(Task) == 0x20);\n\n\tstruct PrivilegedTask : Task\n\t{\n\t\tstruct VTablePrivilegedTask : public VTableTask\n\t\t{\n\t\t\tVTableEntry rttiTask;\n\t\t};\n\t\tstatic_assert(sizeof(VTablePrivilegedTask) == 8*3);\n\t\tstatic inline SysAllocator<VTablePrivilegedTask> s_VTable;\n\n\t\tstatic PrivilegedTask* ctor(PrivilegedTask* _thisptr)\n\t\t{\n\t\t\tif (!_thisptr)\n\t\t\t\t_thisptr = boss_new<PrivilegedTask>();\n\t\t\tTask::ctor4(_thisptr);\n\t\t\t_thisptr->vTablePtr = s_VTable;\n\t\t\treturn _thisptr;\n\t\t}\n\n\t\tstatic void dtor(PrivilegedTask* _this, uint32 options)\n\t\t{\n\t\t\tif(!_this)\n\t\t\t\treturn;\n\t\t\tTask::dtor(_this, 0);\n\t\t\tif(options & 1)\n\t\t\t\tboss_delete(_this);\n\t\t}\n\n\t\tstatic void InitVTable()\n\t\t{\n\t\t\ts_VTable->rtti.ptr = nullptr; // todo\n\t\t\ts_VTable->dtor.ptr = DTOR_WRAPPER(PrivilegedTask);\n\t\t\ts_VTable->rttiTask.ptr = nullptr; // todo\n\t\t}\n\t};\n\tstatic_assert(sizeof(PrivilegedTask) == 0x20);\n\n\tstruct AlmightyTask : PrivilegedTask\n\t{\n\t\tstruct VTableAlmightyTask : public VTablePrivilegedTask\n\t\t{};\n\t\tstatic_assert(sizeof(VTableAlmightyTask) == 8*3);\n\t\tstatic inline SysAllocator<VTableAlmightyTask> s_VTable;\n\n\t\tstatic AlmightyTask* ctor(AlmightyTask* _thisptr)\n\t\t{\n\t\t\tif (!_thisptr)\n\t\t\t\t_thisptr = boss_new<AlmightyTask>();\n\t\t\tPrivilegedTask::ctor(_thisptr);\n\t\t\t_thisptr->vTablePtr = s_VTable;\n\t\t\treturn _thisptr;\n\t\t}\n\n\t\tstatic void dtor(AlmightyTask* _thisptr, uint32 options)\n\t\t{\n\t\t\tif (!_thisptr)\n\t\t\t\treturn;\n\t\t\tPrivilegedTask::dtor(_thisptr, 0);\n\t\t\tif(options&1)\n\t\t\t\tboss_delete(_thisptr);\n\t\t}\n\n\t\tstatic uint32 Initialize(AlmightyTask* _thisptr, TitleId* titleId, const char* taskId, uint32 accountId)\n\t\t{\n\t\t\tif (!_thisptr)\n\t\t\t\treturn resultInvalidParam;\n\t\t\t_thisptr->persistentId = accountId;\n\t\t\t_thisptr->titleId.u64 = titleId->u64;\n\t\t\t_thisptr->taskId.id.assign(taskId);\n\t\t\treturn resultSuccess;\n\t\t}\n\n\t\tstatic void InitVTable()\n\t\t{\n\t\t\ts_VTable->rtti.ptr = nullptr; // todo\n\t\t\ts_VTable->dtor.ptr = DTOR_WRAPPER(AlmightyTask);\n\t\t\ts_VTable->rttiTask.ptr = nullptr; // todo\n\t\t}\n\t};\n\tstatic_assert(sizeof(AlmightyTask) == 0x20);\n\n\tDataName* DataName::ctor(DataName* _this)\n\t{\n\t\tif(!_this)\n\t\t\t_this = boss_new<DataName>();\n\t\t_this->name.ClearAllBytes();\n\t\treturn _this;\n\t}\n\n\tconst char* DataName::operator_const_char(DataName* _this)\n\t{\n\t\treturn _this->name.c_str();\n\t}\n\n\tstruct BossStorageFadEntry\n\t{\n\t\tCafeString<32> name;\n\t\tuint32be dataId;\n\t\tuint32 ukn24;\n\t\tuint32 ukn28;\n\t\tuint32 ukn2C;\n\t\tuint32 ukn30;\n\t\tuint32be timestampRelated; // unsure\n\t};\n\tstatic_assert(sizeof(BossStorageFadEntry) == 0x38);\n\n\tstruct Storage\n\t{\n\t\tstatic_assert(sizeof(DirectoryName) == 8);\n\t\tstruct VTableStorage\n\t\t{\n\t\t\tVTableEntry rtti;\n\t\t\tVTableEntry dtor;\n\t\t};\n\t\tstatic inline SysAllocator<VTableStorage> s_vTable;\n\n\t\tenum StorageKind\n\t\t{\n\t\t\tkStorageKind_NBDL,\n\t\t\tkStorageKind_RawDl,\n\t\t};\n\n\t\t/* +0x00 */ uint32be persistentId;\n\t\t/* +0x04 */ uint32be storageKind;\n\t\t/* +0x08 */ uint8 ukn08Array[3];\n\t\t/* +0x0B */ DirectoryName storageName;\n\t\tuint8 ukn13;\n\t\tuint8 ukn14;\n\t\tuint8 ukn15;\n\t\tuint8 ukn16;\n\t\tuint8 ukn17;\n\t\t/* +0x18 */ nn::boss::TitleId titleId;\n\t\t/* +0x20 */ MEMPTR<VTableStorage> vTablePtr;\n\t\t/* +0x24 */ uint32be ukn24;\n\n\t\tstatic nn::boss::Storage* ctor1(nn::boss::Storage* _this) // __ct__Q3_2nn4boss7StorageFv\n\t\t{\n\t\t\tif(!_this)\n\t\t\t\t_this = boss_new<nn::boss::Storage>();\n\t\t\t_this->vTablePtr = s_vTable;\n\t\t\t_this->titleId.u64 = 0;\n\t\t\treturn _this;\n\t\t}\n\n\t\tstatic void dtor(nn::boss::Storage* _this, uint32 options) // __dt__Q3_2nn4boss7StorageFv\n\t\t{\n\t\t\tFinalize(_this);\n\t\t\tif(options & 1)\n\t\t\t\tboss_delete(_this);\n\t\t}\n\n\t\tstatic BossResult Initialize(Storage* _thisptr, const char* storageName, uint32 accountId, StorageKind type)\n\t\t{\n\t\t\tif (!storageName)\n\t\t\t\treturn resultInvalidParam;\n\t\t\t_thisptr->storageKind = type;\n\t\t\t_thisptr->titleId.u64 = 0;\n\t\t\t_thisptr->storageName.name2.assign(storageName);\n\t\t\t_thisptr->persistentId = accountId;\n\t\t\treturn resultSuccess;\n\t\t}\n\n\t\tstatic BossResult Initialize2(Storage* _thisptr, const char* dirName, StorageKind type)\n\t\t{\n\t\t\treturn Initialize(_thisptr, dirName, 0, type);\n\t\t}\n\n\t\tstatic void Finalize(Storage* _this)\n\t\t{\n\t\t\tmemset(_this, 0, sizeof(Storage)); // todo - not all fields might be cleared\n\t\t}\n\n\t\tstatic bool Exist(nn::boss::Storage* _thisptr)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::StorageExist));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<DirectoryName>(_thisptr->storageName);\n\t\t\tserviceCall.WriteParam<betype<StorageKind>>(_thisptr->storageKind);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn 0;\n\t\t\treturn serviceCall.ReadResponse<uint8be>();\n\t\t}\n\n\t\tstatic nnResult GetDataList(nn::boss::Storage* _thisptr, DataName* dataList, sint32 maxEntries, uint32be* outputEntryCount, uint32 startIndex) // GetDataList__Q3_2nn4boss7StorageCFPQ3_2nn4boss8DataNameUiPUiT2\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::StorageGetDataList));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->persistentId);\n\t\t\tserviceCall.WriteParam<DirectoryName>(_thisptr->storageName);\n\t\t\tserviceCall.WriteParam<betype<StorageKind>>(_thisptr->storageKind);\n\t\t\tserviceCall.WriteResponseBuffer(dataList, sizeof(DataName) * maxEntries);\n\t\t\tserviceCall.WriteParam<uint32be>(startIndex);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tuint32be outputCount = serviceCall.ReadResponse<uint32be>();\n\t\t\tbool isSuccessByte = serviceCall.ReadResponse<uint8be>() != 0;\n\t\t\tif (!isSuccessByte)\n\t\t\t\treturn resultUknA0220300;\n\t\t\tif (outputEntryCount)\n\t\t\t\t*outputEntryCount = outputCount;\n\t\t\treturn r;\n\t\t}\n\n\t\tstatic void InitVTable()\n\t\t{\n\t\t\ts_vTable->rtti.ptr = nullptr; // todo\n\t\t\ts_vTable->dtor.ptr = DTOR_WRAPPER(Storage);\n\t\t}\n\t};\n\n\tstatic_assert(sizeof(Storage) == 0x28);\n\tstatic_assert(offsetof(Storage, storageKind) == 0x04);\n\tstatic_assert(offsetof(Storage, ukn08Array) == 0x08);\n\tstatic_assert(offsetof(Storage, storageName) == 0x0B);\n\tstatic_assert(offsetof(Storage, titleId) == 0x18);\n\n\tstruct AlmightyStorage : Storage\n\t{\n\t\tstruct VTableAlmightyStorage : public VTableStorage\n\t\t{\n\t\t\tVTableEntry rttiStorage;\n\t\t};\n\t\tstatic_assert(sizeof(VTableAlmightyStorage) == 8*3);\n\t\tstatic inline SysAllocator<VTableAlmightyStorage> s_VTable;\n\n\t\tstatic AlmightyStorage* ctor(AlmightyStorage* _thisptr)\n\t\t{\n\t\t\tif (!_thisptr)\n\t\t\t\t_thisptr = boss_new<AlmightyStorage>();\n\t\t\tStorage::ctor1(_thisptr);\n\t\t\t_thisptr->vTablePtr = s_VTable;\n\t\t\treturn _thisptr;\n\t\t}\n\n\t\tstatic uint32 Initialize(AlmightyStorage* _thisptr, TitleId* titleId, const char* storageName, uint32 accountId, StorageKind storageKind)\n\t\t{\n\t\t\tif (!_thisptr)\n\t\t\t\treturn resultInvalidParam;\n\n\t\t\t_thisptr->persistentId = accountId;\n\t\t\t_thisptr->storageKind = storageKind;\n\t\t\t_thisptr->titleId.u64 = titleId->u64;\n\n\t\t\t_thisptr->storageName.name2.assign(storageName);\n\n\t\t\treturn resultSuccess;\n\t\t}\n\n\t\tstatic void InitVTable()\n\t\t{\n\t\t\ts_VTable->rtti.ptr = nullptr; // todo\n\t\t\ts_VTable->dtor.ptr = DTOR_WRAPPER(AlmightyStorage);\n\t\t\ts_VTable->rttiStorage.ptr = nullptr; // todo\n\t\t}\n\t};\n\tstatic_assert(sizeof(AlmightyStorage) == 0x28);\n\n\t// NsData\n\n\tstruct NsData\n\t{\n\t\tstruct VTableNsData\n\t\t{\n\t\t\tVTableEntry rtti;\n\t\t\tVTableEntry dtor;\n\t\t};\n\t\tstatic inline SysAllocator<VTableNsData> s_vTable;\n\n\t\t/* +0x00 */ DataName name;\n\t\t/* +0x20 */ Storage storage;\n\t\t/* +0x48 */ uint64be currentSeek;\n\t\t/* +0x50 */ MEMPTR<void> vTablePtr;\n\t\t/* +0x54 */ uint32 ukn54;\n\n\t\tstatic NsData* ctor(NsData* _this)\n\t\t{\n\t\t\tif (!_this)\n\t\t\t\t_this = boss_new<NsData>();\n\t\t\t_this->vTablePtr = s_vTable;\n\t\t\tDataName::ctor(&_this->name);\n\t\t\t_this->storage.ctor1(&_this->storage);\n\t\t\t_this->currentSeek = 0;\n\t\t\treturn _this;\n\t\t}\n\n\t\tstatic void dtor(NsData* _this, uint32 options) // __dt__Q3_2nn4boss6NsDataFv\n\t\t{\n\t\t\t_this->storage.dtor(&_this->storage, 0);\n\t\t\t// todo\n\t\t\tif(options & 1)\n\t\t\t\tboss_delete(_this);\n\t\t}\n\n\t\tstatic BossResult Initialize(NsData* _this, nn::boss::Storage* storage, const char* dataName)\n\t\t{\n\t\t\tif(dataName == nullptr)\n\t\t\t{\n\t\t\t\tif (storage->storageKind != 1)\n\t\t\t\t{\n\t\t\t\t\treturn resultInvalidParam;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t_this->storage.persistentId = storage->persistentId;\n\t\t\t_this->storage.storageKind = storage->storageKind;\n\t\t\tmemcpy(_this->storage.ukn08Array, storage->ukn08Array, 3);\n\t\t\t_this->storage.storageName = storage->storageName;\n\t\t\t_this->storage.titleId = storage->titleId;\n\t\t\t_this->storage = *storage;\n\n\t\t\tif (dataName != nullptr || storage->storageKind != 1)\n\t\t\t\t_this->name.name.assign(dataName);\n\t\t\telse\n\t\t\t\t_this->name.name.assign(\"rawcontent.dat\");\n\t\t\t_this->currentSeek = 0;\n\n\t\t\treturn resultSuccess;\n\t\t}\n\n\t\tstatic std::string _GetPath(NsData* nsData)\n\t\t{\n\t\t\tuint32 accountId = nsData->storage.persistentId;\n\t\t\tif (accountId == 0)\n\t\t\t\taccountId = iosuAct_getAccountIdOfCurrentAccount();\n\n\t\t\tuint64 title_id = nsData->storage.titleId.u64;\n\t\t\tif (title_id == 0)\n\t\t\t\ttitle_id = CafeSystem::GetForegroundTitleId();\n\n\t\t\tfs::path path = fmt::format(\"cemuBossStorage/{:08x}/{:08x}/user/{:08x}\", (uint32)(title_id >> 32), (uint32)(title_id & 0xFFFFFFFF), accountId);\n\t\t\tpath /= nsData->storage.storageName.name2.c_str();\n\t\t\tpath /= nsData->name.c_str();\n\t\t\treturn path.string();\n\t\t}\n\n\t\tstatic BossResult DeleteRealFile(NsData* _thisptr)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::NsDataDeleteFile));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->storage.persistentId);\n\t\t\tserviceCall.WriteParam<DirectoryName>(_thisptr->storage.storageName);\n\t\t\tserviceCall.WriteParam<betype<StorageKind>>(_thisptr->storage.storageKind);\n\t\t\tserviceCall.WriteParam<DataName>(_thisptr->name);\n\t\t\treturn serviceCall.Submit();\n\t\t}\n\n\t\tstatic BossResult DeleteRealFileWithHistory(NsData* _thisptr)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::NsDataDeleteFileWithHistory));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->storage.persistentId);\n\t\t\tserviceCall.WriteParam<DirectoryName>(_thisptr->storage.storageName);\n\t\t\tserviceCall.WriteParam<betype<StorageKind>>(_thisptr->storage.storageKind);\n\t\t\tserviceCall.WriteParam<DataName>(_thisptr->name);\n\t\t\treturn serviceCall.Submit();\n\t\t}\n\n\t\tstatic uint32 Exist(NsData* _thisptr)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::NsDataExist));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->storage.persistentId);\n\t\t\tserviceCall.WriteParam<DirectoryName>(_thisptr->storage.storageName);\n\t\t\tserviceCall.WriteParam<betype<StorageKind>>(_thisptr->storage.storageKind);\n\t\t\tserviceCall.WriteParam<DataName>(_thisptr->name);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn 0;\n\t\t\treturn serviceCall.ReadResponse<uint8be>();\n\t\t}\n\n\t\tstatic uint64 GetSize(NsData* _thisptr)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::NsDataGetSize));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->storage.persistentId);\n\t\t\tserviceCall.WriteParam<DirectoryName>(_thisptr->storage.storageName);\n\t\t\tserviceCall.WriteParam<betype<StorageKind>>(_thisptr->storage.storageKind);\n\t\t\tserviceCall.WriteParam<DataName>(_thisptr->name);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn 0;\n\t\t\treturn serviceCall.ReadResponse<uint64be>();\n\t\t}\n\n\t\tstatic uint64 GetCreatedTime(NsData* nsData)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nn_boss.NsData_GetCreatedTime() not implemented. Returning 0\");\n\t\t\tuint64 createdTime = 0;\n\t\t\t// cmdId 0x97\n\t\t\t// probably uses FS stat query\n\t\t\treturn createdTime;\n\t\t}\n\n\t\tstatic sint32 ReadWithSizeOut(NsData* _thisptr, uint64be* sizeOut, uint8* buffer, sint32 length)\n\t\t{\n\t\t\tIPCServiceClient::IPCServiceCall serviceCall = s_ipcClient.Begin(0, stdx::to_underlying(BossCommandId::NsDataRead));\n\t\t\tserviceCall.WriteParam<uint32be>(_thisptr->storage.persistentId);\n\t\t\tserviceCall.WriteParam<DirectoryName>(_thisptr->storage.storageName);\n\t\t\tserviceCall.WriteParam<betype<StorageKind>>(_thisptr->storage.storageKind);\n\t\t\tserviceCall.WriteParam<DataName>(_thisptr->name);\n\t\t\tserviceCall.WriteResponseBuffer(buffer, length);\n\t\t\tuint64 readOffset = _thisptr->currentSeek;\n\t\t\tserviceCall.WriteParam<uint64be>(readOffset);\n\t\t\tnnResult r = serviceCall.Submit();\n\t\t\tif (NN_RESULT_IS_FAILURE(r))\n\t\t\t\treturn r;\n\t\t\tuint64 numReadBytes = serviceCall.ReadResponse<uint64be>();\n\t\t\t_thisptr->currentSeek += numReadBytes;\n\t\t\tcemu_assert(sizeOut);\n\t\t\tcemu_assert(numReadBytes <= length);\n\t\t\t*sizeOut = numReadBytes;\n\t\t\treturn r;\n\t\t}\n\n\t\tstatic sint32 Read(NsData* _thisptr, uint8* buffer, sint32 length)\n\t\t{\n\t\t\tuint64be bytesRead = 0;\n\t\t\treturn ReadWithSizeOut(_thisptr, &bytesRead, buffer, length);\n\t\t}\n\n\t\tenum class NsDataSeekMode\n\t\t{\n\t\t\tBeginning = 0,\n\t\t\tRelative = 1,\n\t\t\tEnding = 2\n\t\t};\n\n\t\tstatic BossResult Seek(NsData* _thisptr, sint64 seekPos, NsDataSeekMode mode)\n\t\t{\n\t\t\tif (mode == NsDataSeekMode::Beginning)\n\t\t\t{\n\t\t\t\t_thisptr->currentSeek = seekPos;\n\t\t\t}\n\t\t\telse if (mode == NsDataSeekMode::Relative)\n\t\t\t{\n\t\t\t\t_thisptr->currentSeek += seekPos;\n\t\t\t}\n\t\t\telse if (mode == NsDataSeekMode::Ending)\n\t\t\t{\n\t\t\t\tuint64 fileSize = GetSize(_thisptr);\n\t\t\t\t_thisptr->currentSeek = fileSize + seekPos;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\treturn resultSuccess;\n\t\t}\n\n\t\tstatic void InitVTable()\n\t\t{\n\t\t\ts_vTable->rtti.ptr = nullptr; // todo\n\t\t\ts_vTable->dtor.ptr = DTOR_WRAPPER(NsData);\n\t\t}\n\t};\n\tstatic_assert(sizeof(NsData) == 0x58);\n\n}\n}\n\nnamespace nn::boss\n{\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_boss\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegisterFunc(nn::boss::GetBossState, \"nn_boss\", \"GetBossState__Q2_2nn4bossFv\", LogType::NN_BOSS);\n\n\t\t\t// boss lib\n\t\t\tcafeExportRegisterFunc(nn::boss::Initialize, \"nn_boss\", \"Initialize__Q2_2nn4bossFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::IsInitialized, \"nn_boss\", \"IsInitialized__Q2_2nn4bossFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Finalize, \"nn_boss\", \"Finalize__Q2_2nn4bossFv\", LogType::NN_BOSS);\n\n\t\t\t// taskId\n\t\t\tcafeExportRegisterFunc(nn::boss::TaskId::ctorDefault, \"nn_boss\", \"__ct__Q3_2nn4boss6TaskIDFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::TaskId::ctorFromString, \"nn_boss\", \"__ct__Q3_2nn4boss6TaskIDFPCc\", LogType::NN_BOSS);\n\n\t\t\t// task\n\t\t\tnn::boss::Task::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::ctor1, \"nn_boss\", \"__ct__Q3_2nn4boss4TaskFUcPCc\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::ctor2, \"nn_boss\", \"__ct__Q3_2nn4boss4TaskFPCcUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::ctor3, \"nn_boss\", \"__ct__Q3_2nn4boss4TaskFPCc\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::ctor4, \"nn_boss\", \"__ct__Q3_2nn4boss4TaskFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss4TaskFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::Initialize1, \"nn_boss\", \"Initialize__Q3_2nn4boss4TaskFPCcUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::Initialize2, \"nn_boss\", \"Initialize__Q3_2nn4boss4TaskFUcPCc\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::Initialize3, \"nn_boss\", \"Initialize__Q3_2nn4boss4TaskFPCc\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::Run, \"nn_boss\", \"Run__Q3_2nn4boss4TaskFb\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::Wait, \"nn_boss\", \"Wait__Q3_2nn4boss4TaskFUiQ3_2nn4boss13TaskWaitState\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::GetTurnState, \"nn_boss\", \"GetTurnState__Q3_2nn4boss4TaskCFPUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::GetHttpStatusCode, \"nn_boss\", \"GetHttpStatusCode__Q3_2nn4boss4TaskCFPUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::GetContentLength, \"nn_boss\", \"GetContentLength__Q3_2nn4boss4TaskCFPUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::GetProcessedLength, \"nn_boss\", \"GetProcessedLength__Q3_2nn4boss4TaskCFPUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::Register, \"nn_boss\", \"Register__Q3_2nn4boss4TaskFRQ3_2nn4boss11TaskSetting\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::Unregister, \"nn_boss\", \"Unregister__Q3_2nn4boss4TaskFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::IsRegistered, \"nn_boss\", \"IsRegistered__Q3_2nn4boss4TaskCFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::RegisterForImmediateRun, \"nn_boss\", \"RegisterForImmediateRun__Q3_2nn4boss4TaskFRCQ3_2nn4boss11TaskSetting\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::StartScheduling, \"nn_boss\", \"StartScheduling__Q3_2nn4boss4TaskFb\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Task::StopScheduling, \"nn_boss\", \"StopScheduling__Q3_2nn4boss4TaskFv\", LogType::NN_BOSS);\n\n\t\t\t// TaskSetting\n\t\t\tnn::boss::TaskSetting::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::TaskSetting::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss11TaskSettingFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::TaskSetting::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss11TaskSettingFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::TaskSetting::IsPrivileged, \"nn_boss\", \"Initialize__Q3_2nn4boss11TaskSettingFPCcUi\", LogType::NN_BOSS);\n\n\t\t\t// NbdlTaskSetting\n\t\t\tnn::boss::NbdlTaskSetting::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::NbdlTaskSetting::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss15NbdlTaskSettingFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NbdlTaskSetting::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss15NbdlTaskSettingFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NbdlTaskSetting::Initialize, \"nn_boss\", \"Initialize__Q3_2nn4boss15NbdlTaskSettingFPCcLT1\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NbdlTaskSetting::SetFileName, \"nn_boss\", \"SetFileName__Q3_2nn4boss15NbdlTaskSettingFPCc\", LogType::NN_BOSS);\n\n\t\t\t// PlayReportSetting\n\t\t\tnn::boss::PlayReportSetting::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::PlayReportSetting::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss17PlayReportSettingFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::PlayReportSetting::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss17PlayReportSettingFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::PlayReportSetting::Initialize, \"nn_boss\", \"Initialize__Q3_2nn4boss17PlayReportSettingFPvUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::PlayReportSetting::Set, \"nn_boss\", \"Set__Q3_2nn4boss17PlayReportSettingFPCcUi\", LogType::NN_BOSS);\n\n\t\t\t// RawDlTaskSetting\n\t\t\tnn::boss::RawDlTaskSetting::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::RawDlTaskSetting::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss16RawDlTaskSettingFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::RawDlTaskSetting::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss16RawDlTaskSettingFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::RawDlTaskSetting::Initialize, \"nn_boss\", \"Initialize__Q3_2nn4boss16RawDlTaskSettingFPCcbT2N21\", LogType::NN_BOSS);\n\n\t\t\t// NetTaskSetting\n\t\t\tnn::boss::NetTaskSetting::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::NetTaskSetting::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss14NetTaskSettingFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NetTaskSetting::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss14NetTaskSettingFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NetTaskSetting::SetServiceToken, \"nn_boss\", \"SetServiceToken__Q3_2nn4boss14NetTaskSettingFPCUc\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NetTaskSetting::AddInternalCaCert, \"nn_boss\", \"AddInternalCaCert__Q3_2nn4boss14NetTaskSettingFSc\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NetTaskSetting::SetInternalClientCert, \"nn_boss\", \"SetInternalClientCert__Q3_2nn4boss14NetTaskSettingFSc\", LogType::NN_BOSS);\n\n\t\t\t// Title\n\t\t\tnn::boss::Title::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::Title::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss5TitleFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Title::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss5TitleFv\", LogType::NN_BOSS);\n\t\t\t// cafeExportMakeWrapper<nn::boss::Title::SetNewArrivalFlagOff>(\"nn_boss\", \"SetNewArrivalFlagOff__Q3_2nn4boss5TitleFv\"); SMM bookmarks\n\n\t\t\t// TitleId\n\t\t\tcafeExportRegisterFunc(nn::boss::TitleId::ctorDefault, \"nn_boss\", \"__ct__Q3_2nn4boss7TitleIDFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::TitleId::ctorFromTitleId, \"nn_boss\", \"__ct__Q3_2nn4boss7TitleIDFUL\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::TitleId::ctorCopy, \"nn_boss\", \"__ct__Q3_2nn4boss7TitleIDFRCQ3_2nn4boss7TitleID\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::TitleId::operator_ne, \"nn_boss\", \"__ne__Q3_2nn4boss7TitleIDCFRCQ3_2nn4boss7TitleID\", LogType::NN_BOSS);\n\n\t\t\t// DataName\n\t\t\tcafeExportRegisterFunc(nn::boss::DataName::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss8DataNameFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::DataName::operator_const_char, \"nn_boss\", \"__opPCc__Q3_2nn4boss8DataNameCFv\", LogType::NN_BOSS);\n\n\t\t\t// DirectoryName\n\t\t\tcafeExportRegisterFunc(nn::boss::DirectoryName::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss13DirectoryNameFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::DirectoryName::operator_const_char, \"nn_boss\", \"__opPCc__Q3_2nn4boss13DirectoryNameCFv\", LogType::NN_BOSS);\n\n\t\t\t// Account\n\t\t\tnn::boss::BossAccount::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::BossAccount::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss7AccountFUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::BossAccount::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss7AccountFv\", LogType::NN_BOSS);\n\n\t\t\t// AlmightyTask\n\t\t\tnn::boss::AlmightyTask::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::AlmightyTask::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss12AlmightyTaskFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::AlmightyTask::Initialize, \"nn_boss\", \"Initialize__Q3_2nn4boss12AlmightyTaskFQ3_2nn4boss7TitleIDPCcUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::AlmightyTask::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss12AlmightyTaskFv\", LogType::NN_BOSS);\n\n\t\t\t// Storage\n\t\t\tnn::boss::Storage::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::Storage::ctor1, \"nn_boss\", \"__ct__Q3_2nn4boss7StorageFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Storage::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss7StorageFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Storage::Finalize, \"nn_boss\", \"Finalize__Q3_2nn4boss7StorageFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Storage::Exist, \"nn_boss\", \"Exist__Q3_2nn4boss7StorageCFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Storage::GetDataList, \"nn_boss\", \"GetDataList__Q3_2nn4boss7StorageCFPQ3_2nn4boss8DataNameUiPUiT2\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Storage::Initialize, \"nn_boss\", \"Initialize__Q3_2nn4boss7StorageFPCcUiQ3_2nn4boss11StorageKind\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::Storage::Initialize2, \"nn_boss\", \"Initialize__Q3_2nn4boss7StorageFPCcQ3_2nn4boss11StorageKind\", LogType::NN_BOSS);\n\n\t\t\t// AlmightyStorage\n\t\t\tnn::boss::AlmightyStorage::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::AlmightyStorage::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss15AlmightyStorageFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::AlmightyStorage::Initialize, \"nn_boss\", \"Initialize__Q3_2nn4boss15AlmightyStorageFQ3_2nn4boss7TitleIDPCcUiQ3_2nn4boss11StorageKind\", LogType::NN_BOSS);\n\n\t\t\t// NsData\n\t\t\tnn::boss::NsData::InitVTable();\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::ctor, \"nn_boss\", \"__ct__Q3_2nn4boss6NsDataFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::dtor, \"nn_boss\", \"__dt__Q3_2nn4boss6NsDataFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::Initialize, \"nn_boss\", \"Initialize__Q3_2nn4boss6NsDataFRCQ3_2nn4boss7StoragePCc\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::DeleteRealFile, \"nn_boss\", \"DeleteRealFile__Q3_2nn4boss6NsDataFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::DeleteRealFileWithHistory, \"nn_boss\", \"DeleteRealFileWithHistory__Q3_2nn4boss6NsDataFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::Exist, \"nn_boss\", \"Exist__Q3_2nn4boss6NsDataCFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::GetSize, \"nn_boss\", \"GetSize__Q3_2nn4boss6NsDataCFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::GetCreatedTime, \"nn_boss\", \"GetCreatedTime__Q3_2nn4boss6NsDataCFv\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::Read, \"nn_boss\", \"Read__Q3_2nn4boss6NsDataFPvUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::ReadWithSizeOut, \"nn_boss\", \"Read__Q3_2nn4boss6NsDataFPLPvUi\", LogType::NN_BOSS);\n\t\t\tcafeExportRegisterFunc(nn::boss::NsData::Seek, \"nn_boss\", \"Seek__Q3_2nn4boss6NsDataFLQ3_2nn4boss12PositionBase\", LogType::NN_BOSS);\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\tOSInitMutexEx(&nn::boss::g_mutex, nullptr);\n\t\t\t\tnn::boss::g_initCounter = 0;\n\t\t\t\tnn::boss::g_isInitialized = false;\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t}\n\t\t}\n\t}s_COSnnBossModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnBossModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_boss/nn_boss.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::boss\n{\n\tCOSModule* GetModule();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_ccr/nn_ccr.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"nn_ccr.h\"\n\nnamespace nn::ccr\n{\n\tsint32 CCRSysCaffeineBootCheck()\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"CCRSysCaffeineBootCheck()\");\n\t\treturn -1;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_ccr\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"nn_ccr\", CCRSysCaffeineBootCheck, LogType::Placeholder);\n\t\t};\n\n\t}s_COSnnccrModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnccrModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_ccr/nn_ccr.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::ccr\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_client_service.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/coreinit/coreinit_IPC.h\"\n#include <boost/container/static_vector.hpp>\n\nclass IPCServiceClient\n{\npublic:\n\tclass IPCServiceCall\n\t{\n\t\tstruct IOVectorBuffer\n\t\t{\n\t\t\tIOVectorBuffer() = default;\n\t\t\tIOVectorBuffer(uint8* ptr, uint32 size, bool isExternalBuffer = false) : ptr(ptr), size(size), isExternalBuffer(isExternalBuffer) {}\n\n\t\t\tuint8* ptr;\n\t\t\tuint32 size;\n\t\t\tbool isExternalBuffer{false}; // buffer provided by caller\n\t\t};\n\tpublic:\n\t\tIPCServiceCall(IPCServiceClient& client, uint32 serviceId, uint32 commandId) : m_client(client)\n\t\t{\n\t\t\t// allocate a parameter and response buffer\n\t\t\tIPCBuffer* cmdBuf = client.AllocateCommandBuffer();\n\t\t\tm_paramBuffers.emplace_back(cmdBuf->data, sizeof(IPCBuffer));\n\t\t\tcmdBuf = client.AllocateCommandBuffer();\n\t\t\tm_responseBuffers.emplace_back(cmdBuf->data, sizeof(IPCBuffer));\n\t\t\t// write the request header\n\t\t\tWriteParam<uint32be>(0); // ukn00\n\t\t\tWriteParam<uint32be>(serviceId); // serviceId\n\t\t\tWriteParam<uint32be>(0); // ukn08\n\t\t\tWriteParam<uint32be>(commandId); // commandId\n\t\t}\n\n\t\t~IPCServiceCall()\n\t\t{\n\t\t\tfor (auto& buf : m_paramBuffers)\n\t\t\t{\n\t\t\t\tif (buf.isExternalBuffer)\n\t\t\t\t\tcontinue;\n\t\t\t\tm_client.ReleaseCommandBuffer((IPCBuffer*)buf.ptr);\n\t\t\t}\n\t\t\tfor (auto& buf : m_responseBuffers)\n\t\t\t{\n\t\t\t\tif (buf.isExternalBuffer)\n\t\t\t\t\tcontinue;\n\t\t\t\tm_client.ReleaseCommandBuffer((IPCBuffer*)buf.ptr);\n\t\t\t}\n\t\t}\n\n\t\tIPCServiceCall(const IPCServiceCall&) = delete;\n\t\tIPCServiceCall& operator=(const IPCServiceCall&) = delete;\n\n\t\ttemplate<typename T>\n\t\tvoid WriteParam(const T& value)\n\t\t{\n\t\t\tcemu_assert(m_paramWriteIndex + sizeof(T) <= m_paramBuffers[0].size);\n\t\t\tmemcpy(m_paramBuffers[0].ptr + m_paramWriteIndex, &value, sizeof(T));\n\t\t\tm_paramWriteIndex += sizeof(T);\n\t\t}\n\n\t\t// ptr and size defines an input buffer (PPC->IOSU)\n\t\tvoid WriteParamBuffer(MEMPTR<void> ptr, uint32 size)\n\t\t{\n\t\t\tWriteInOutBuffer(MEMPTR<uint8>(ptr), size, false);\n\t\t}\n\n\t\t// ptr and size defines an output buffer (IOSU->PPC)\n\t\tvoid WriteResponseBuffer(MEMPTR<void> ptr, uint32 size)\n\t\t{\n\t\t\tWriteInOutBuffer(MEMPTR<uint8>(ptr), size, true);\n\t\t}\n\n\t\tnnResult Submit()\n\t\t{\n\t\t\tStackAllocator<IPCIoctlVector, 16> vectorArray;\n\t\t\tuint32 ioVecCount = m_paramBuffers.size() + m_responseBuffers.size();\n\t\t\tcemu_assert(ioVecCount <= 16);\n\t\t\t// output buffers come first\n\t\t\tfor (size_t i = 0; i < m_responseBuffers.size(); ++i)\n\t\t\t{\n\t\t\t\tvectorArray[i].baseVirt = MEMPTR<uint8>(m_responseBuffers[i].ptr);\n\t\t\t\tvectorArray[i].basePhys = nullptr;\n\t\t\t\tvectorArray[i].size = m_responseBuffers[i].size;\n\t\t\t}\n\t\t\t// input buffers\n\t\t\tfor (size_t i = 0; i < m_paramBuffers.size(); ++i)\n\t\t\t{\n\t\t\t\tvectorArray[m_responseBuffers.size() + i].baseVirt = MEMPTR<uint8>(m_paramBuffers[i].ptr);\n\t\t\t\tvectorArray[m_responseBuffers.size() + i].basePhys = nullptr;\n\t\t\t\tvectorArray[m_responseBuffers.size() + i].size = m_paramBuffers[i].size;\n\t\t\t}\n\t\t\tIOS_ERROR r = coreinit::IOS_Ioctlv(m_client.GetDevHandle(), 0, m_responseBuffers.size(), m_paramBuffers.size(), vectorArray.GetPointer());\n\t\t\tif ( (r&0x80000000) != 0)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented(); // todo - handle submission errors\n\t\t\t}\n\t\t\tuint32be resultCode = ReadResponse<uint32be>();\n\t\t\tif (!NN_RESULT_IS_FAILURE((uint32)resultCode))\n\t\t\t{\n\t\t\t\tfor (auto& bufCopy : m_bufferCopiesOut)\n\t\t\t\t{\n\t\t\t\t\tmemcpy(bufCopy.dst, bufCopy.src, bufCopy.size);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn static_cast<nnResult>(resultCode);\n\t\t}\n\n\t\ttemplate<typename T>\n\t\tT ReadResponse()\n\t\t{\n\t\t\tcemu_assert(m_responseReadIndex + sizeof(T) <= m_responseBuffers[0].size);\n\t\t\tT value;\n\t\t\tmemcpy(&value, m_responseBuffers[0].ptr + m_responseReadIndex, sizeof(T));\n\t\t\tm_responseReadIndex += sizeof(T);\n\t\t\treturn value;\n\t\t}\n\n\tprivate:\n\t\tstruct BufferCopyOut\n\t\t{\n\t\t\tBufferCopyOut(void* dst, void* src, uint32 size) : dst(dst), src(src), size(size) {}\n\n\t\t\tvoid* dst;\n\t\t\tvoid* src;\n\t\t\tuint32 size;\n\t\t};\n\n\t\tvoid WriteInOutBuffer(MEMPTR<uint8> ptr, uint32 size, bool isOutput)\n\t\t{\n\t\t\tuint32 headSize = (0x40 - (ptr.GetMPTR()&0x3F))&0x3F;\n\t\t\theadSize = std::min<uint32>(headSize, size);\n\t\t\tuint32 alignedSize = size - headSize;\n\t\t\tuint32 tailSize = alignedSize - (alignedSize&~0x3F);\n\t\t\talignedSize -= tailSize;\n\t\t\t// verify\n\t\t\tcemu_assert_debug(headSize + alignedSize + tailSize == size);\n\t\t\tcemu_assert_debug(alignedSize == 0 || ((ptr.GetMPTR()+headSize)&0x3F) == 0);\n\t\t\tcemu_assert_debug(tailSize == 0 || ((ptr.GetMPTR()+headSize+alignedSize)&0x3F) == 0);\n\n\t\t\tif (isOutput)\n\t\t\t\tcemu_assert(m_responseBuffers.size()+2 <= m_responseBuffers.capacity());\n\t\t\telse\n\t\t\t\tcemu_assert(m_paramBuffers.size()+2 <= m_paramBuffers.capacity());\n\t\t\tIOVectorBuffer alignedBuffer;\n\t\t\talignedBuffer.ptr = ptr + headSize;\n\t\t\talignedBuffer.size = alignedSize;\n\t\t\talignedBuffer.isExternalBuffer = true;\n\t\t\tif (isOutput)\n\t\t\t\tm_responseBuffers.emplace_back(alignedBuffer);\n\t\t\telse\n\t\t\t\tm_paramBuffers.emplace_back(alignedBuffer);\n\t\t\tIPCBuffer* headAndTailBuffer = m_client.AllocateCommandBuffer();\n\t\t\tIOVectorBuffer headAndTail;\n\t\t\theadAndTail.ptr = headAndTailBuffer->data + (0x40 - headSize);\n\t\t\theadAndTail.size = 128 - (0x40 - headSize);\n\t\t\theadAndTail.isExternalBuffer = false;\n\t\t\tif (headSize > 0)\n\t\t\t{\n\t\t\t\tif (isOutput)\n\t\t\t\t\tm_bufferCopiesOut.emplace_back(ptr, headAndTailBuffer->data + 0x40 - headSize, headSize);\n\t\t\t\telse\n\t\t\t\t\tmemcpy(headAndTailBuffer->data + 0x40 - headSize, ptr, headSize);\n\t\t\t}\n\t\t\tif (tailSize > 0)\n\t\t\t{\n\t\t\t\tif (isOutput)\n\t\t\t\t\tm_bufferCopiesOut.emplace_back(ptr + headSize + alignedSize, headAndTailBuffer->data + 0x40, tailSize);\n\t\t\t\telse\n\t\t\t\t\tmemcpy(headAndTailBuffer->data + 0x40, ptr + headSize + alignedSize, tailSize);\n\t\t\t}\n\t\t\tif (isOutput)\n\t\t\t\tm_responseBuffers.emplace_back(headAndTail);\n\t\t\telse\n\t\t\t\tm_paramBuffers.emplace_back(headAndTail);\n\t\t\t// serialize into parameter stream\n\t\t\tWriteParam<uint32be>(alignedSize);\n\t\t\tWriteParam<uint8be>(0); // ukn4\n\t\t\tWriteParam<uint8be>(0); // ukn5\n\t\t\tWriteParam<uint8be>((uint8)headSize);\n\t\t\tWriteParam<uint8be>((uint8)tailSize);\n\t\t}\n\n\t\tIPCServiceClient& m_client;\n\t\tboost::container::static_vector<IOVectorBuffer, 8> m_paramBuffers;\n\t\tboost::container::static_vector<IOVectorBuffer, 8> m_responseBuffers;\n\t\tsint32 m_paramWriteIndex{0};\n\t\tsint32 m_responseReadIndex{0};\n\t\tboost::container::static_vector<BufferCopyOut, 16> m_bufferCopiesOut;\n\t};\n\n    IPCServiceClient()\n    {\n    }\n\n    ~IPCServiceClient()\n    {\n    \tShutdown();\n    }\n\n\tvoid Initialize(std::string_view devicePath, uint8_t* buffer, uint32_t bufferSize)\n    {\n    \tm_devicePath = devicePath;\n    \tm_buffer = buffer;\n    \tm_bufferSize = bufferSize;\n\n    \tstatic_assert(sizeof(IPCBuffer) == 256);\n    \tsize_t numCommandBuffers = m_bufferSize / sizeof(IPCBuffer);\n\n    \tm_commandBuffersFree.resize(numCommandBuffers);\n    \tfor (size_t i = 0; i < numCommandBuffers; ++i)\n    \t{\n    \t\tm_commandBuffersFree[i] = reinterpret_cast<IPCBuffer*>(m_buffer + i * sizeof(IPCBuffer));\n    \t}\n    \tm_clientHandle = coreinit::IOS_Open(m_devicePath.c_str(), 0);\n    }\n\n    void Shutdown()\n    {\n        if (m_clientHandle != 0)\n        {\n\t        coreinit::IOS_Close(m_clientHandle);\n            m_clientHandle = 0;\n        }\n    }\n\n    IPCServiceCall Begin(uint32_t serviceId, uint32_t commandId)\n    {\n        return IPCServiceCall(*this, serviceId, commandId);\n    }\n\n\tIOSDevHandle GetDevHandle() const\n\t{\n    \tcemu_assert(m_clientHandle != 0);\n\t\treturn m_clientHandle;\n\t}\nprivate:\n    struct IPCBuffer\n    {\n\t\tuint8 data[256];\n    };\n\n    IPCBuffer* AllocateCommandBuffer()\n    {\n        cemu_assert(m_commandBuffersFree.size() > 0);\n    \tIPCBuffer* buf = m_commandBuffersFree.back();\n    \tm_commandBuffersFree.pop_back();\n        return buf;\n    }\n\n    void ReleaseCommandBuffer(IPCBuffer* buffer)\n    {\n    \tm_commandBuffersFree.emplace_back(buffer);\n    }\n\nprivate:\n    std::string m_devicePath;\n    IOSDevHandle m_clientHandle{0};\n    uint8_t* m_buffer{nullptr};\n    uint32_t m_bufferSize{0};\n    std::vector<IPCBuffer*> m_commandBuffersFree;\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_cmpt/nn_cmpt.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"nn_cmpt.h\"\n\nnamespace nn::cmpt\n{\n\tuint32 CMPTAcctGetPcConf(uint32be* pcConf)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"CMPTAcctGetPcConf() - todo\");\n\t\tpcConf[0] = 0;\n\t\tpcConf[1] = 0;\n\t\tpcConf[2] = 0;\n\t\treturn 0;\n\t}\n\n\tuint32 CMPTGetDataSize(uint32be* sizeOut)\n\t{\n\t\t*sizeOut = 0xC0000;\n\t\treturn 0;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_cmpt\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"nn_cmpt\", CMPTAcctGetPcConf, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"nn_cmpt\", CMPTGetDataSize, LogType::Placeholder);\n\t\t};\n\n\t}s_COSnnCmptModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnCmptModule;\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_cmpt/nn_cmpt.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::cmpt\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_common.h",
    "content": "#pragma once\n\nusing nnResult = uint32;\n\ninline bool NN_RESULT_IS_SUCCESS(nnResult r) \n{\n\treturn (r & 0x80000000) == 0;\n}\n\ninline bool NN_RESULT_IS_FAILURE(nnResult r)\n{\n\treturn (r & 0x80000000) != 0;\n}\n\n// any level with MSB set is considered an error\n#define NN_RESULT_LEVEL_FATAL\t\t(0x7) // 111\n#define NN_RESULT_LEVEL_LVL6\t\t(0x6) // 110\n#define NN_RESULT_LEVEL_STATUS\t\t(0x5) // 101\n#define NN_RESULT_LEVEL_SUCCESS\t\t(0x0) // 000\n\n#define BUILD_NN_RESULT(__level, __module, __detailedErrorCode) ((((uint32)(__level)&0x7)<<29) | ((uint32)(__module)<<20)  | ((uint32)(__detailedErrorCode)<<0) )\n#define BUILD_NN_RESULT_STATUS(__module, __detailedErrorCode) ((((uint32)NN_RESULT_LEVEL_STATUS)<<29) | ((uint32)(__module)<<20) | ((uint32)(__detailedErrorCode)<<0) )\n\n#define NN_RESULT_SUCCESS\t((nnResult)0)\n#define NN_RESULT_PLACEHOLDER_ERROR\t((nnResult)0x80000000)\n\nenum NN_RESULT_MODULE : uint32\n{\n\tNN_RESULT_MODULE_COMMON\t\t\t= 0,\n\tNN_RESULT_MODULE_NN_IPC\t\t\t= 1,\n\tNN_RESULT_MODULE_NN_BOSS\t\t= 2,\n\tNN_RESULT_MODULE_NN_ACP\t\t\t= 3,\n\tNN_RESULT_MODULE_NN_IOS\t\t\t= 4,\n\tNN_RESULT_MODULE_NN_NIM\t\t\t= 5,\n\tNN_RESULT_MODULE_NN_PDM\t\t\t= 6,\n\tNN_RESULT_MODULE_NN_ACT\t\t\t= 7,\n\tNN_RESULT_MODULE_NN_NUP\t\t\t= 10,\n\tNN_RESULT_MODULE_NN_NDM\t\t\t= 11,\n\tNN_RESULT_MODULE_NN_FP\t\t\t= 12,\n\tNN_RESULT_MODULE_NN_AC\t\t\t= 13,\n\tNN_RESULT_MODULE_NN_DRMAPP\t\t= 15,\n\tNN_RESULT_MODULE_NN_OLV\t\t\t= 17,\n\tNN_RESULT_MODULE_NN_VCTL\t\t= 18,\n\tNN_RESULT_MODULE_NN_SPM\t\t\t= 20,\n\tNN_RESULT_MODULE_NN_EC\t\t\t= 22,\n\tNN_RESULT_MODULE_NN_SL\t\t\t= 24,\n\tNN_RESULT_MODULE_NN_ECO\t\t\t= 25,\n\tNN_RESULT_MODULE_NN_NFP\t\t\t= 27,\n\n\tNN_RESULT_MODULE_MCP\t\t\t= 511,\n};\n\n// 0000-9999\n// these are the user-facing error codes you see in ErrEula. Usually combined with a module-specific prefix. E.g. 102-1234\n// in nnResult these are stored in the description field left-shifted by 7\nenum class NN_ERROR_CODE : uint32\n{\n\tACT_UNKNOWN_SERVER_ERROR = 2932,\n};\n\n// takes simplified error code in range 0-9999\nconstexpr inline nnResult nnResultStatus(NN_RESULT_MODULE module, NN_ERROR_CODE errorCode)\n{\n\tuint32 description = (uint32)errorCode;\n\tdescription <<= 7;\n\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, (uint32)module, description);\n}\n\n// nn_act description codes - todo: define these as NN_ERROR_CODE\n#define NN_ACT_RESULT_ACCOUNT_DOES_NOT_EXIST\t128128\n\n// nn_nfp description codes\n#define NN_RESULT_NFP_CODE_APPAREAIDMISMATCH\t0x11300\n#define NN_RESULT_NFP_CODE_NOAPPAREA\t\t\t0x10400\n\nnamespace nn\n{\n\tinline NN_RESULT_MODULE nnResult_GetModule(const nnResult res) { return (NN_RESULT_MODULE)((res >> 20) & 0x1FF); };\n\tinline uint32 nnResult_GetDescription(const nnResult res) { return (uint32)((res >> 0) & 0xFFFFF); };\n\n\t#define\tNN_ERRCODE_MODULE_PREFIX_ACT\t1020000\n\n\tinline NN_ERROR_CODE NNResultToErrorCode(nnResult result, NN_RESULT_MODULE expectedModule)\n\t{\n\t\tif (((uint32)result & 0x18000000) == 0x18000000)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\tuint32 errorCodeBase = 0;\n\t\tif (expectedModule == NN_RESULT_MODULE_NN_ACT)\n\t\t\terrorCodeBase = NN_ERRCODE_MODULE_PREFIX_ACT;\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\n\t\tNN_RESULT_MODULE module = nnResult_GetModule(result);\n\t\tif (module != expectedModule)\n\t\t\treturn (NN_ERROR_CODE)(errorCodeBase + 9999);\n\t\tuint32 desc = nnResult_GetDescription(result);\n\t\tuint32 errCode = (desc >> 7);\n\t\tif (errCode > 9999)\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t\treturn (NN_ERROR_CODE)(errorCodeBase + 9999);\n\t\t}\n\t\treturn (NN_ERROR_CODE)(errorCodeBase + errCode);\n\t}\n\n}\n\n// tests\nstatic_assert(BUILD_NN_RESULT_STATUS(NN_RESULT_MODULE_NN_ACT, 317696) == 0xA074D900);\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_ec/nn_ec.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"nn_ec.h\"\n\ntypedef struct  \n{\n\t/* +0x00 */ uint8 ukn00[0x10];\n\t/* +0x10 */ uint8 ukn10[0x0C];\n\t/* +0x2C */ uint8 ukn2C[0x10]; // currency string?\n\t/* +0x3C */ uint32 ukn3C; // money amount?\n\t// size of struct is 0x40\n}nnEcUknMoneyStruct_t;\n\nvoid nnEcExport___ct__Q3_2nn2ec5MoneyFPCcN21(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"nn_ec.__ct__Q3_2nn2ec5MoneyFPCcN21(0x%08x, ...)\\n\", hCPU->gpr[3]);\n\tnnEcUknMoneyStruct_t* moneyStruct = (nnEcUknMoneyStruct_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\t// todo -> Setup struct\n\tosLib_returnFromFunction(hCPU, memory_getVirtualOffsetFromPointer(moneyStruct));\n}\n\nnamespace nn::ec\n{\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_ec\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"nn_ec\", \"__ct__Q3_2nn2ec5MoneyFPCcN21\", nnEcExport___ct__Q3_2nn2ec5MoneyFPCcN21);\n\t\t};\n\n\t}s_COSnnEcModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnEcModule;\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_ec/nn_ec.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nvoid nnEc_load();\n\nnamespace nn::ec\n{\n\tCOSModule* GetModule();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_fp/nn_fp.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/IOSU/legacy/iosu_act.h\"\n#include \"Cafe/IOSU/legacy/iosu_fpd.h\"\n#include \"Cafe/IOSU/legacy/iosu_ioctl.h\" // deprecated\n#include \"Cafe/IOSU/iosu_ipc_common.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IOS.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IPC.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"util/ChunkedHeap/ChunkedHeap.h\"\n#include \"Common/CafeString.h\"\n\nnamespace nn\n{\n\tnamespace fp\n\t{\n\t\tstatic const auto FPResult_OkZero = 0;\n\t\tstatic const auto FPResult_Ok = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_FP, 0);\n\t\tstatic const auto FPResult_InvalidIPCParam = BUILD_NN_RESULT(NN_RESULT_LEVEL_LVL6, NN_RESULT_MODULE_NN_FP, 0x680);\n\t\tstatic const auto FPResult_RequestFailed = BUILD_NN_RESULT(NN_RESULT_LEVEL_FATAL, NN_RESULT_MODULE_NN_FP, 0); // figure out proper error code\n\n\t\tstruct\n\t\t{\n\t\t\tuint32 initCounter;\n\t\t\tbool isAdminMode;\n\t\t\tbool isLoggedIn;\n\t\t\tIOSDevHandle fpdHandle;\n\t\t\tSysAllocator<coreinit::OSMutex> fpMutex;\n\t\t\tSysAllocator<uint8, 0x12000> g_fpdAllocatorSpace;\n\t\t\tVHeap* fpBufferHeap{nullptr};\n\t\t\t// PPC buffers for async notification query\n\t\t\tSysAllocator<uint32be> notificationCount;\n\t\t\tSysAllocator<iosu::fpd::FPDNotification, 256> notificationBuffer;\n\t\t\tbool getNotificationCalled{false};\n\t\t\t// notification handler\n\t\t\tMEMPTR<void> notificationHandler{nullptr};\n\t\t\tMEMPTR<void> notificationHandlerParam{nullptr};\n\t\t}g_fp = { };\n\n\t\tclass\n\t\t{\n\t\t  public:\n\t\t\tvoid Init()\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(m_mtx);\n\t\t\t\tg_fp.fpBufferHeap = new VHeap(g_fp.g_fpdAllocatorSpace.GetPtr(), g_fp.g_fpdAllocatorSpace.GetByteSize());\n\t\t\t}\n\n\t\t\tvoid Destroy()\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(m_mtx);\n\t\t\t\tdelete g_fp.fpBufferHeap;\n\t\t\t}\n\n\t\t\tvoid* Allocate(uint32 size, uint32 alignment)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(m_mtx);\n\t\t\t\tvoid* p = g_fp.fpBufferHeap->alloc(size, 32);\n\t\t\t\tif (!p)\n\t\t\t\t\tcemuLog_log(LogType::Force, \"nn_fp: Internal heap is full\");\n\t\t\t\treturn p;\n\t\t\t}\n\n\t\t\tvoid Free(void* ptr)\n\t\t\t{\n\t\t\t\tstd::unique_lock _l(m_mtx);\n\t\t\t\tg_fp.fpBufferHeap->free(ptr);\n\t\t\t}\n\n\t\t  private:\n\t\t\tstd::mutex m_mtx;\n\t\t}FPIpcBufferAllocator;\n\n\t\tclass FPIpcContext {\n\t\t\tstatic inline constexpr uint32 MAX_VEC_COUNT = 8;\n\t\t  public:\n\t\t\t// use FP heap for this class\n\t\t\tstatic void* operator new(size_t size)\n\t\t\t{\n\t\t\t\treturn FPIpcBufferAllocator.Allocate(size, (uint32)alignof(FPIpcContext));\n\t\t\t}\n\n\t\t\tstatic void operator delete(void* ptr)\n\t\t\t{\n\t\t\t\tFPIpcBufferAllocator.Free(ptr);\n\t\t\t}\n\n\t\t\tFPIpcContext(iosu::fpd::FPD_REQUEST_ID requestId) : m_requestId(requestId)\n\t\t\t{\n\t\t\t}\n\n\t\t\t~FPIpcContext()\n\t\t\t{\n\t\t\t\tif(m_dataBuffer)\n\t\t\t\t\tFPIpcBufferAllocator.Free(m_dataBuffer);\n\t\t\t}\n\n\t\t\tvoid AddInput(void* ptr, uint32 size)\n\t\t\t{\n\t\t\t\tsize_t vecIndex = GetVecInIndex(m_numVecIn);\n\t\t\t\tm_vec[vecIndex].baseVirt = ptr;\n\t\t\t\tm_vec[vecIndex].size = size;\n\t\t\t\tm_numVecIn = m_numVecIn + 1;\n\t\t\t}\n\n\t\t\tvoid AddOutput(void* ptr, uint32 size)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(m_numVecIn == 0); // all outputs need to be added before any inputs\n\t\t\t\tsize_t vecIndex = GetVecOutIndex(m_numVecOut);\n\t\t\t\tm_vec[vecIndex].baseVirt = ptr;\n\t\t\t\tm_vec[vecIndex].size = size;\n\t\t\t\tm_numVecOut = m_numVecOut + 1;\n\t\t\t}\n\n\t\t\tuint32 Submit(std::unique_ptr<FPIpcContext> owner)\n\t\t\t{\n\t\t\t\tInitSubmissionBuffer();\n\t\t\t\t// note: While generally, Ioctlv() usage has the order as input (app->IOSU) followed by output (IOSU->app), FP uses it the other way around\n\t\t\t\tnnResult r = coreinit::IOS_Ioctlv(g_fp.fpdHandle, (uint32)m_requestId.value(), m_numVecOut, m_numVecIn, m_vec);\n\t\t\t\tCopyBackOutputs();\n\t\t\t\towner.reset();\n\t\t\t\treturn r;\n\t\t\t}\n\n\t\t\tnnResult SubmitAsync(std::unique_ptr<FPIpcContext> owner, MEMPTR<void> callbackFunc, MEMPTR<void> callbackParam)\n\t\t\t{\n\t\t\t\tInitSubmissionBuffer();\n\t\t\t\tthis->m_callbackFunc = callbackFunc;\n\t\t\t\tthis->m_callbackParam = callbackParam;\n\t\t\t\tnnResult r = coreinit::IOS_IoctlvAsync(g_fp.fpdHandle, (uint32)m_requestId.value(), m_numVecOut, m_numVecIn, m_vec, MEMPTR<void>(PPCInterpreter_makeCallableExportDepr(AsyncHandler)), MEMPTR<void>(this));\n\t\t\t\towner.release();\n\t\t\t\treturn r;\n\t\t\t}\n\n\t\t  private:\n\t\t\tsize_t GetVecInIndex(uint8 inIndex)\n\t\t\t{\n\t\t\t\treturn m_numVecOut + inIndex;\n\t\t\t}\n\n\t\t\tsize_t GetVecOutIndex(uint8 outIndex)\n\t\t\t{\n\t\t\t\treturn outIndex;\n\t\t\t}\n\n\t\t\tvoid InitSubmissionBuffer()\n\t\t\t{\n\t\t\t\t// allocate a chunk of memory to hold the input/output vectors and their data\n\t\t\t\tuint32 vecOffset[MAX_VEC_COUNT];\n\t\t\t\tuint32 totalBufferSize = 0;\n\t\t\t\tfor(uint8 i=0; i<m_numVecIn + m_numVecOut; i++)\n\t\t\t\t{\n\t\t\t\t\tvecOffset[i] = totalBufferSize;\n\t\t\t\t\ttotalBufferSize += m_vec[i].size;\n\t\t\t\t\ttotalBufferSize = (totalBufferSize+31)&~31;\n\t\t\t\t}\n\t\t\t\tif(totalBufferSize > 0)\n\t\t\t\t{\n\t\t\t\t\tm_dataBuffer = FPIpcBufferAllocator.Allocate(totalBufferSize, 32);\n\t\t\t\t\tcemu_assert_debug(m_dataBuffer);\n\t\t\t\t}\n\t\t\t\t// update Ioctl vector addresses\n\t\t\t\tfor(uint8 i=0; i<m_numVecIn + m_numVecOut; i++)\n\t\t\t\t{\n\t\t\t\t\tvoid* bufferAddr = (uint8be*)m_dataBuffer.GetPtr() + vecOffset[i];\n\t\t\t\t\tm_vecOriginalAddress[i] = m_vec[i].baseVirt;\n\t\t\t\t\tm_vec[i].baseVirt = bufferAddr;\n\t\t\t\t}\n\t\t\t\t// copy input data to buffer\n\t\t\t\tfor(uint8 i=0; i<m_numVecIn; i++)\n\t\t\t\t{\n\t\t\t\t\tuint8 vecIndex = GetVecInIndex(i);\n\t\t\t\t\tmemcpy(MEMPTR<void>(m_vec[vecIndex].baseVirt).GetPtr(), MEMPTR<void>(m_vecOriginalAddress[vecIndex]).GetPtr(), m_vec[vecIndex].size);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatic void AsyncHandler(PPCInterpreter_t* hCPU)\n\t\t\t{\n\t\t\t\tppcDefineParamU32(result, 0);\n\t\t\t\tppcDefineParamPtr(ipcCtx, FPIpcContext, 1);\n\t\t\t\tipcCtx->m_asyncResult = result; // store result in variable since FP callbacks pass a pointer to nnResult and not the value directly\n\t\t\t\tipcCtx->CopyBackOutputs();\n\t\t\t\tPPCCoreCallback(ipcCtx->m_callbackFunc, &ipcCtx->m_asyncResult, ipcCtx->m_callbackParam);\n\t\t\t\tdelete ipcCtx;\n\t\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\t}\n\n\t\t\tvoid CopyBackOutputs()\n\t\t\t{\n\t\t\t\tif(m_numVecOut > 0)\n\t\t\t\t{\n\t\t\t\t\t// copy output from temporary output buffers to the original addresses\n\t\t\t\t\tfor(uint8 i=0; i<m_numVecOut; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tuint32 vecOffset = (uint32)m_vec[GetVecOutIndex(i)].baseVirt.GetMPTR() - (uint32)m_vec[0].baseVirt.GetMPTR();\n\t\t\t\t\t\tmemcpy(m_vecOriginalAddress[GetVecOutIndex(i)].GetPtr(), (uint8be*)m_dataBuffer.GetPtr() + vecOffset, m_vec[GetVecOutIndex(i)].size);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbetype<iosu::fpd::FPD_REQUEST_ID> m_requestId;\n\t\t\tuint8be m_numVecIn{0};\n\t\t\tuint8be m_numVecOut{0};\n\t\t\tIPCIoctlVector m_vec[MAX_VEC_COUNT];\n\t\t\tMEMPTR<void> m_vecOriginalAddress[MAX_VEC_COUNT]{};\n\t\t\tMEMPTR<void> m_dataBuffer{nullptr};\n\t\t\tMEMPTR<void> m_callbackFunc{nullptr};\n\t\t\tMEMPTR<void> m_callbackParam{nullptr};\n\t\t\tbetype<nnResult> m_asyncResult;\n\t\t};\n\n\t\tstruct FPGlobalLock\n\t\t{\n\t\t\tFPGlobalLock()\n\t\t\t{\n\t\t\t\tcoreinit::OSLockMutex(&g_fp.fpMutex);\n\t\t\t}\n\t\t\t~FPGlobalLock()\n\t\t\t{\n\t\t\t\tcoreinit::OSUnlockMutex(&g_fp.fpMutex);\n\t\t\t}\n\t\t};\n\t\t#define FP_API_BASE() if (g_fp.initCounter == 0) return 0xC0C00580; FPGlobalLock _fpLock;\n\t\t#define FP_API_BASE_ZeroOnError() if (g_fp.initCounter == 0) return 0; FPGlobalLock _fpLock;\n\n\t\tnnResult Initialize()\n\t\t{\n\t\t\tFPGlobalLock _fpLock;\n\t\t\tif (g_fp.initCounter == 0)\n\t\t\t{\n\t\t\t\tg_fp.fpdHandle = coreinit::IOS_Open(\"/dev/fpd\", 0);\n\t\t\t}\n\t\t\tg_fp.initCounter++;\n\t\t\treturn FPResult_OkZero;\n\t\t}\n\n\t\tuint32 IsInitialized()\n\t\t{\n\t\t\tFPGlobalLock _fpLock;\n\t\t\treturn g_fp.initCounter > 0 ? 1 : 0;\n\t\t}\n\n\t\tnnResult InitializeAdmin(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tFPGlobalLock _fpLock;\n\t\t\tg_fp.isAdminMode = true;\n\t\t\treturn Initialize();\n\t\t}\n\n\t\tuint32 IsInitializedAdmin()\n\t\t{\n\t\t\tFPGlobalLock _fpLock;\n\t\t\treturn g_fp.initCounter > 0 ? 1 : 0;\n\t\t}\n\n\t\tnnResult Finalize()\n\t\t{\n\t\t\tFPGlobalLock _fpLock;\n\t\t\tif (g_fp.initCounter == 1)\n\t\t\t{\n\t\t\t\tg_fp.initCounter = 0;\n\t\t\t\tg_fp.isAdminMode = false;\n\t\t\t\tg_fp.isLoggedIn = false;\n\t\t\t\tcoreinit::IOS_Close(g_fp.fpdHandle);\n\t\t\t\tg_fp.getNotificationCalled = false;\n\t\t\t}\n\t\t\telse if (g_fp.initCounter > 0)\n\t\t\t\tg_fp.initCounter--;\n\t\t\treturn FPResult_OkZero;\n\t\t}\n\n\t\tnnResult FinalizeAdmin()\n\t\t{\n\t\t\treturn Finalize();\n\t\t}\n\n\t\tvoid GetNextNotificationAsync();\n\n\t\tnnResult SetNotificationHandler(uint32 notificationMask, void* funcPtr, void* userParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tg_fp.notificationHandler = funcPtr;\n\t\t\tg_fp.notificationHandlerParam = userParam;\n\t\t\tStackAllocator<uint32be> notificationMaskBuf; notificationMaskBuf = notificationMask;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::SetNotificationMask);\n\t\t\tipcCtx->AddInput(&notificationMaskBuf, sizeof(uint32be));\n\t\t\tnnResult r = ipcCtx->Submit(std::move(ipcCtx));\n\t\t\tif (NN_RESULT_IS_SUCCESS(r))\n\t\t\t{\n\t\t\t\t// async query for notifications\n\t\t\t\tGetNextNotificationAsync();\n\t\t\t}\n\t\t\treturn r;\n\t\t}\n\n\t\tvoid GetNextNotificationAsyncHandler(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tcoreinit::OSLockMutex(&g_fp.fpMutex);\n\t\t\tcemu_assert_debug(g_fp.getNotificationCalled);\n\t\t\tg_fp.getNotificationCalled = false;\n\t\t\tauto bufPtr = g_fp.notificationBuffer.GetPtr();\n\t\t\tuint32 count = g_fp.notificationCount->value();\n\t\t\tif (count == 0)\n\t\t\t{\n\t\t\t\tGetNextNotificationAsync();\n\t\t\t\tcoreinit::OSUnlockMutex(&g_fp.fpMutex);\n\t\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// copy notifications to temporary buffer using std::copy\n\t\t\tiosu::fpd::FPDNotification tempBuffer[256];\n\t\t\tstd::copy(g_fp.notificationBuffer.GetPtr(), g_fp.notificationBuffer.GetPtr() + count, tempBuffer);\n\t\t\t// call handler for each notification, but do it outside of the lock\n\t\t\tvoid* notificationHandler = g_fp.notificationHandler;\n\t\t\tvoid* notificationHandlerParam = g_fp.notificationHandlerParam;\n\t\t\tcoreinit::OSUnlockMutex(&g_fp.fpMutex);\n\t\t\tiosu::fpd::FPDNotification* notificationBuffer = g_fp.notificationBuffer.GetPtr();\n\t\t\tfor (uint32 i = 0; i < count; i++)\n\t\t\t\tPPCCoreCallback(notificationHandler, (uint32)notificationBuffer[i].type, notificationBuffer[i].pid, notificationHandlerParam);\n\t\t\tcoreinit::OSLockMutex(&g_fp.fpMutex);\n\t\t\t// query more notifications\n\t\t\tGetNextNotificationAsync();\n\t\t\tcoreinit::OSUnlockMutex(&g_fp.fpMutex);\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\tvoid GetNextNotificationAsync()\n\t\t{\n\t\t\tif (g_fp.getNotificationCalled)\n\t\t\t\treturn;\n\t\t\tg_fp.getNotificationCalled = true;\n\t\t\tg_fp.notificationCount = 0;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetNotificationAsync);\n\t\t\tipcCtx->AddOutput(g_fp.notificationBuffer.GetPtr(), g_fp.notificationBuffer.GetByteSize());\n\t\t\tipcCtx->AddOutput(g_fp.notificationCount.GetPtr(), sizeof(uint32be));\n\t\t\tcemu_assert_debug(g_fp.notificationBuffer.GetByteSize() == 0x800);\n\t\t\tnnResult r = ipcCtx->SubmitAsync(std::move(ipcCtx), MEMPTR<void>(PPCInterpreter_makeCallableExportDepr(GetNextNotificationAsyncHandler)), nullptr);\n\t\t}\n\n\t\tnnResult LoginAsync(void* funcPtr, void* userParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::LoginAsync);\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, userParam);\n\t\t}\n\n\t\tuint32 HasLoggedIn()\n\t\t{\n\t\t\tFP_API_BASE_ZeroOnError();\n\t\t\t// Sonic All Star Racing uses this\n\t\t\t// and Monster Hunter 3 Ultimate needs this to return false at least once to initiate login and not get stuck\n\t\t\t// this returns false until LoginAsync was called and has completed (?) even if the user is already logged in\n\t\t\tStackAllocator<uint32be> resultBuf;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::HasLoggedIn);\n\t\t\tipcCtx->AddOutput(&resultBuf, sizeof(uint32be));\n\t\t\tipcCtx->Submit(std::move(ipcCtx));\n\t\t\treturn resultBuf != 0 ? 1 : 0;\n\t\t}\n\n\t\tuint32 IsOnline()\n\t\t{\n\t\t\tFP_API_BASE_ZeroOnError();\n\t\t\tStackAllocator<uint32be> resultBuf;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::IsOnline);\n\t\t\tipcCtx->AddOutput(&resultBuf, sizeof(uint32be));\n\t\t\tipcCtx->Submit(std::move(ipcCtx));\n\t\t\treturn resultBuf != 0 ? 1 : 0;\n\t\t}\n\n\t\tnnResult GetFriendList(uint32be* pidList, uint32be* returnedCount, uint32 startIndex, uint32 maxCount)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> startIndexBuf; startIndexBuf = startIndex;\n\t\t\tStackAllocator<uint32be> maxCountBuf; maxCountBuf = maxCount;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetFriendList);\n\t\t\tipcCtx->AddOutput(pidList, sizeof(uint32be) * maxCount);\n\t\t\tipcCtx->AddOutput(returnedCount, sizeof(uint32be));\n\t\t\tipcCtx->AddInput(&startIndexBuf, sizeof(uint32be));\n\t\t\tipcCtx->AddInput(&maxCountBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetFriendRequestList(uint32be* pidList, uint32be* returnedCount, uint32 startIndex, uint32 maxCount)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> startIndexBuf; startIndexBuf = startIndex;\n\t\t\tStackAllocator<uint32be> maxCountBuf; maxCountBuf = maxCount;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetFriendRequestList);\n\t\t\tipcCtx->AddOutput(pidList, sizeof(uint32be) * maxCount);\n\t\t\tipcCtx->AddOutput(returnedCount, sizeof(uint32be));\n\t\t\tipcCtx->AddInput(&startIndexBuf, sizeof(uint32be));\n\t\t\tipcCtx->AddInput(&maxCountBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetFriendListAll(uint32be* pidList, uint32be* returnedCount, uint32 startIndex, uint32 maxCount)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> startIndexBuf; startIndexBuf = startIndex;\n\t\t\tStackAllocator<uint32be> maxCountBuf; maxCountBuf = maxCount;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetFriendListAll);\n\t\t\tipcCtx->AddOutput(pidList, sizeof(uint32be) * maxCount);\n\t\t\tipcCtx->AddOutput(returnedCount, sizeof(uint32be));\n\t\t\tipcCtx->AddInput(&startIndexBuf, sizeof(uint32be));\n\t\t\tipcCtx->AddInput(&maxCountBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetFriendListEx(iosu::fpd::FriendData* friendData, uint32be* pidList, uint32 count)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> countBuf; countBuf = count;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetFriendListEx);\n\t\t\tipcCtx->AddOutput(friendData, sizeof(iosu::fpd::FriendData) * count);\n\t\t\tipcCtx->AddInput(pidList, sizeof(uint32be) * count);\n\t\t\tipcCtx->AddInput(&countBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetFriendRequestListEx(iosu::fpd::FriendRequest* friendRequest, uint32be* pidList, uint32 count)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> countBuf; countBuf = count;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetFriendRequestListEx);\n\t\t\tipcCtx->AddOutput(friendRequest, sizeof(iosu::fpd::FriendRequest) * count);\n\t\t\tipcCtx->AddInput(pidList, sizeof(uint32be) * count);\n\t\t\tipcCtx->AddInput(&countBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetBasicInfoAsync(iosu::fpd::FriendBasicInfo* basicInfo, uint32be* pidList, uint32 count, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> countBuf; countBuf = count;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetBasicInfoAsync);\n\t\t\tipcCtx->AddOutput(basicInfo, sizeof(iosu::fpd::FriendBasicInfo) * count);\n\t\t\tipcCtx->AddInput(pidList, sizeof(uint32be) * count);\n\t\t\tipcCtx->AddInput(&countBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tuint32 GetMyPrincipalId()\n\t\t{\n\t\t\tFP_API_BASE_ZeroOnError();\n\t\t\tStackAllocator<uint32be> resultBuf;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetMyPrincipalId);\n\t\t\tipcCtx->AddOutput(&resultBuf, sizeof(uint32be));\n\t\t\tipcCtx->Submit(std::move(ipcCtx));\n\t\t\treturn resultBuf->value();\n\t\t}\n\n\t\tnnResult GetMyAccountId(uint8be* accountId)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetMyAccountId);\n\t\t\tipcCtx->AddOutput(accountId, ACT_ACCOUNTID_LENGTH);\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetMyScreenName(uint16be* screenname)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetMyScreenName);\n\t\t\tipcCtx->AddOutput(screenname, ACT_NICKNAME_SIZE*sizeof(uint16));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetMyPlayingGame(iosu::fpd::GameKey* myPlayingGame)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetMyPlayingGame);\n\t\t\tipcCtx->AddOutput(myPlayingGame, sizeof(iosu::fpd::GameKey));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetMyPreference(iosu::fpd::FPDPreference* myPreference)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetMyPreference);\n\t\t\tipcCtx->AddOutput(myPreference, sizeof(iosu::fpd::FPDPreference));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetMyComment(uint16be* myComment)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetMyComment);\n\t\t\tipcCtx->AddOutput(myComment, iosu::fpd::MY_COMMENT_LENGTH * sizeof(uint16be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetMyMii(FFLData_t* fflData)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetMyMii);\n\t\t\tipcCtx->AddOutput(fflData, sizeof(FFLData_t));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetFriendAccountId(uint8be* accountIdArray, uint32be* pidList, uint32 count)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tif (count == 0)\n\t\t\t\treturn 0;\n\t\t\tStackAllocator<uint32be> countBuf; countBuf = count;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetFriendAccountId);\n\t\t\tipcCtx->AddOutput(accountIdArray, ACT_ACCOUNTID_LENGTH * count);\n\t\t\tipcCtx->AddInput(pidList, sizeof(uint32be) * count);\n\t\t\tipcCtx->AddInput(&countBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetFriendScreenName(uint16be* nameList, uint32be* pidList, uint32 count, uint8 replaceNonAscii, uint8be* languageList)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tif (count == 0)\n\t\t\t\treturn 0;\n\t\t\tStackAllocator<uint32be> countBuf; countBuf = count;\n\t\t\tStackAllocator<uint32be> replaceNonAsciiBuf; replaceNonAsciiBuf = replaceNonAscii;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetFriendScreenName);\n\t\t\tipcCtx->AddOutput(nameList, ACT_NICKNAME_SIZE * sizeof(uint16be) * count);\n\t\t\tipcCtx->AddOutput(languageList, languageList ? sizeof(uint8be) * count : 0);\n\t\t\tipcCtx->AddInput(pidList, sizeof(uint32be) * count);\n\t\t\tipcCtx->AddInput(&countBuf, sizeof(uint32be));\n\t\t\tipcCtx->AddInput(&replaceNonAsciiBuf, sizeof(uint8be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetFriendMii(FFLData_t* miiList, uint32be* pidList, uint32 count)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tif(count == 0)\n\t\t\t\treturn 0;\n\t\t\tStackAllocator<uint32be> countBuf; countBuf = count;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetFriendMii);\n\t\t\tipcCtx->AddOutput(miiList, sizeof(FFLData_t) * count);\n\t\t\tipcCtx->AddInput(pidList, sizeof(uint32be) * count);\n\t\t\tipcCtx->AddInput(&countBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetFriendPresence(iosu::fpd::FriendPresence* presenceList, uint32be* pidList, uint32 count)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tif(count == 0)\n\t\t\t\treturn 0;\n\t\t\tStackAllocator<uint32be> countBuf; countBuf = count;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetFriendPresence);\n\t\t\tipcCtx->AddOutput(presenceList, sizeof(iosu::fpd::FriendPresence) * count);\n\t\t\tipcCtx->AddInput(pidList, sizeof(uint32be) * count);\n\t\t\tipcCtx->AddInput(&countBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult GetFriendRelationship(uint8* relationshipList, uint32be* pidList, uint32 count)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tif(count == 0)\n\t\t\t\treturn 0;\n\t\t\tStackAllocator<uint32be> countBuf; countBuf = count;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetFriendRelationship);\n\t\t\tipcCtx->AddOutput(relationshipList, sizeof(uint8) * count);\n\t\t\tipcCtx->AddInput(pidList, sizeof(uint32be) * count);\n\t\t\tipcCtx->AddInput(&countBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tuint32 IsJoinable(iosu::fpd::FriendPresence* presence, uint64 joinMask)\n\t\t{\n\t\t\tif (presence->isValid == 0 ||\n\t\t\t\tpresence->isOnline == 0 ||\n\t\t\t\tpresence->gameMode.joinGameId == 0 ||\n\t\t\t\tpresence->gameMode.matchmakeType == 0 ||\n\t\t\t\tpresence->gameMode.groupId == 0 ||\n\t\t\t\tpresence->gameMode.joinGameMode >= 64 )\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tuint32 joinGameMode = presence->gameMode.joinGameMode;\n\t\t\tuint64 joinModeMask = (1ULL<<joinGameMode);\n\t\t\tif ((joinModeMask&joinMask) == 0)\n\t\t\t\treturn 0;\n\n\t\t\t// check relation ship\n\t\t\tuint32 joinFlagMask = presence->gameMode.joinFlagMask;\n\t\t\tif (joinFlagMask == 0)\n\t\t\t\treturn 0;\n\t\t\tif (joinFlagMask == 1)\n\t\t\t\treturn 1;\n\t\t\tif (joinFlagMask == 2)\n\t\t\t{\n\t\t\t\t// check relationship\n\t\t\t\tuint8 relationship[1] = { 0 };\n\t\t\t\tStackAllocator<uint32be, 1> pidList;\n\t\t\t\tpidList = presence->gameMode.hostPid;\n\t\t\t\tGetFriendRelationship(relationship, &pidList, 1);\n\t\t\t\tif(relationship[0] == iosu::fpd::RELATIONSHIP_FRIEND)\n\t\t\t\t\treturn 1;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (joinFlagMask == 0x65 || joinFlagMask == 0x66)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Unsupported friend invite\");\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\tnnResult CheckSettingStatusAsync(uint8* status, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::CheckSettingStatusAsync);\n\t\t\tipcCtx->AddOutput(status, sizeof(uint8be));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tuint32 IsPreferenceValid()\n\t\t{\n\t\t\tFP_API_BASE_ZeroOnError();\n\t\t\tStackAllocator<uint32be> resultBuf;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::IsPreferenceValid);\n\t\t\tipcCtx->AddOutput(&resultBuf, sizeof(uint32be));\n\t\t\tipcCtx->Submit(std::move(ipcCtx));\n\t\t\treturn resultBuf != 0 ? 1 : 0;\n\t\t}\n\n\t\tnnResult UpdateCommentAsync(uint16be* newComment, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::UpdateCommentAsync);\n\t\t\tuint32 commentLen = CafeStringHelpers::Length(newComment, iosu::fpd::MY_COMMENT_LENGTH-1);\n\t\t\tif (commentLen >= iosu::fpd::MY_COMMENT_LENGTH-1)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"UpdateCommentAsync: message too long\");\n\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t}\n\t\t\tipcCtx->AddInput(newComment, sizeof(uint16be) * commentLen + 2);    \n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tnnResult UpdatePreferenceAsync(iosu::fpd::FPDPreference* newPreference, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::UpdatePreferenceAsync);\n\t\t\tipcCtx->AddInput(newPreference, sizeof(iosu::fpd::FPDPreference));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tnnResult UpdateGameModeWithUnusedParam(iosu::fpd::GameMode* gameMode, uint16be* gameModeMessage, uint32 unusedParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tuint32 messageLen = CafeStringHelpers::Length(gameModeMessage, iosu::fpd::GAMEMODE_MAX_MESSAGE_LENGTH);\n\t\t\tif(messageLen >= iosu::fpd::GAMEMODE_MAX_MESSAGE_LENGTH)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"UpdateGameMode: message too long\");\n\t\t\t\treturn FPResult_InvalidIPCParam;\n\t\t\t}\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::UpdateGameModeVariation2);\n\t\t\tipcCtx->AddInput(gameMode, sizeof(iosu::fpd::GameMode));\n\t\t\tipcCtx->AddInput(gameModeMessage, sizeof(uint16be) * (messageLen + 1));\n\t\t\treturn ipcCtx->Submit(std::move(ipcCtx));\n\t\t}\n\n\t\tnnResult UpdateGameMode(iosu::fpd::GameMode* gameMode, uint16be* gameModeMessage)\n\t\t{\n\t\t\treturn UpdateGameModeWithUnusedParam(gameMode, gameModeMessage, 0);\n\t\t}\n\n\t\tnnResult GetRequestBlockSettingAsync(uint8* blockSettingList, uint32be* pidList, uint32 count, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> countBuf; countBuf = count;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetRequestBlockSettingAsync);\n\t\t\tipcCtx->AddOutput(blockSettingList, sizeof(uint8be) * count);\n\t\t\tipcCtx->AddInput(pidList, sizeof(uint32be) * count);\n\t\t\tipcCtx->AddInput(&countBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\t// overload of AddFriendAsync\n\t\tnnResult AddFriendAsyncByPid(uint32 pid, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> pidBuf; pidBuf = pid;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::AddFriendAsyncByPid);\n\t\t\tipcCtx->AddInput(&pidBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tnnResult DeleteFriendFlagsAsync(uint32be* pidList, uint32 pidCount, uint32 ukn, void* funcPtr, void* customParam)\n\t\t{\n\t\t\t// admin function?\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> pidCountBuf; pidCountBuf = pidCount;\n\t\t\tStackAllocator<uint32be> uknBuf; uknBuf = ukn;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::DeleteFriendFlagsAsync);\n\t\t\tipcCtx->AddInput(pidList, sizeof(uint32be) * pidCount);\n\t\t\tipcCtx->AddInput(&pidCountBuf, sizeof(uint32be));\n\t\t\tipcCtx->AddInput(&uknBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\t// overload of AddFriendRequestAsync\n\t\tnnResult AddFriendRequestByPlayRecordAsync(iosu::fpd::RecentPlayRecordEx* playRecord, uint16be* message, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::AddFriendRequestByPlayRecordAsync);\n\t\t\tuint32 messageLen = 0;\n\t\t\twhile(message[messageLen] != 0)\n\t\t\t\tmessageLen++;\n\t\t\tipcCtx->AddInput(playRecord, sizeof(iosu::fpd::RecentPlayRecordEx));\n\t\t\tipcCtx->AddInput(message, sizeof(uint16be) * (messageLen+1));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tnnResult RemoveFriendAsync(uint32 pid, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> pidBuf; pidBuf = pid;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::RemoveFriendAsync);\n\t\t\tipcCtx->AddInput(&pidBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tnnResult MarkFriendRequestsAsReceivedAsync(uint64be* messageIdList, uint32 count, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint32be> countBuf; countBuf = count;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::MarkFriendRequestsAsReceivedAsync);\n\t\t\tipcCtx->AddInput(messageIdList, sizeof(uint64be) * count);\n\t\t\tipcCtx->AddInput(&countBuf, sizeof(uint32be));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tnnResult CancelFriendRequestAsync(uint64 requestId, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint64be> requestIdBuf; requestIdBuf = requestId;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::CancelFriendRequestAsync);\n\t\t\tipcCtx->AddInput(&requestIdBuf, sizeof(uint64be));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tnnResult DeleteFriendRequestAsync(uint64 requestId, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint64be> requestIdBuf; requestIdBuf = requestId;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::DeleteFriendRequestAsync);\n\t\t\tipcCtx->AddInput(&requestIdBuf, sizeof(uint64be));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tnnResult AcceptFriendRequestAsync(uint64 requestId, void* funcPtr, void* customParam)\n\t\t{\n\t\t\tFP_API_BASE();\n\t\t\tStackAllocator<uint64be> requestIdBuf; requestIdBuf = requestId;\n\t\t\tauto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::AcceptFriendRequestAsync);\n\t\t\tipcCtx->AddInput(&requestIdBuf, sizeof(uint64be));\n\t\t\treturn ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);\n\t\t}\n\n\t\tclass : public COSModule\n\t\t{\n\t\t\tpublic:\n\t\t\tstd::string_view GetName() override\n\t\t\t{\n\t\t\t\treturn \"nn_fp\";\n\t\t\t}\n\n\t\t\tvoid RPLMapped() override\n\t\t\t{\n\t\t\t\tg_fp.initCounter = 0;\n\t\t\t\tg_fp.isAdminMode = false;\n\t\t\t\tg_fp.isLoggedIn = false;\n\t\t\t\tg_fp.getNotificationCalled = false;\n\t\t\t\tg_fp.notificationHandler = nullptr;\n\t\t\t\tg_fp.notificationHandlerParam = nullptr;\n\n\t\t\t\tcoreinit::OSInitMutex(&g_fp.fpMutex);\n\t\t\t\tFPIpcBufferAllocator.Init();\n\n\t\t\t\tcafeExportRegisterFunc(Initialize, \"nn_fp\", \"Initialize__Q2_2nn2fpFv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(InitializeAdmin, \"nn_fp\", \"InitializeAdmin__Q2_2nn2fpFv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(IsInitialized, \"nn_fp\", \"IsInitialized__Q2_2nn2fpFv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(IsInitializedAdmin, \"nn_fp\", \"IsInitializedAdmin__Q2_2nn2fpFv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(Finalize, \"nn_fp\", \"Finalize__Q2_2nn2fpFv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(FinalizeAdmin, \"nn_fp\", \"FinalizeAdmin__Q2_2nn2fpFv\", LogType::NN_FP);\n\n\t\t\t\tcafeExportRegisterFunc(SetNotificationHandler, \"nn_fp\", \"SetNotificationHandler__Q2_2nn2fpFUiPFQ3_2nn2fp16NotificationTypeUiPv_vPv\", LogType::NN_FP);\n\n\t\t\t\tcafeExportRegisterFunc(LoginAsync, \"nn_fp\", \"LoginAsync__Q2_2nn2fpFPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(HasLoggedIn, \"nn_fp\", \"HasLoggedIn__Q2_2nn2fpFv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(IsOnline, \"nn_fp\", \"IsOnline__Q2_2nn2fpFv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetFriendList, \"nn_fp\", \"GetFriendList__Q2_2nn2fpFPUiT1UiT3\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetFriendRequestList, \"nn_fp\", \"GetFriendRequestList__Q2_2nn2fpFPUiT1UiT3\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetFriendListAll, \"nn_fp\", \"GetFriendListAll__Q2_2nn2fpFPUiT1UiT3\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetFriendListEx, \"nn_fp\", \"GetFriendListEx__Q2_2nn2fpFPQ3_2nn2fp10FriendDataPCUiUi\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetFriendRequestListEx, \"nn_fp\", \"GetFriendRequestListEx__Q2_2nn2fpFPQ3_2nn2fp13FriendRequestPCUiUi\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetBasicInfoAsync, \"nn_fp\", \"GetBasicInfoAsync__Q2_2nn2fpFPQ3_2nn2fp9BasicInfoPCUiUiPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\n\t\t\t\tcafeExportRegisterFunc(GetMyPrincipalId, \"nn_fp\", \"GetMyPrincipalId__Q2_2nn2fpFv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetMyAccountId, \"nn_fp\", \"GetMyAccountId__Q2_2nn2fpFPc\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetMyScreenName, \"nn_fp\", \"GetMyScreenName__Q2_2nn2fpFPw\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetMyMii, \"nn_fp\", \"GetMyMii__Q2_2nn2fpFP12FFLStoreData\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetMyPlayingGame, \"nn_fp\", \"GetMyPlayingGame__Q2_2nn2fpFPQ3_2nn2fp7GameKey\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetMyPreference, \"nn_fp\", \"GetMyPreference__Q2_2nn2fpFPQ3_2nn2fp10Preference\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetMyComment, \"nn_fp\", \"GetMyComment__Q2_2nn2fpFPQ3_2nn2fp7Comment\", LogType::NN_FP);\n\n\t\t\t\tcafeExportRegisterFunc(GetFriendAccountId, \"nn_fp\", \"GetFriendAccountId__Q2_2nn2fpFPA17_cPCUiUi\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetFriendScreenName, \"nn_fp\", \"GetFriendScreenName__Q2_2nn2fpFPA11_wPCUiUibPUc\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetFriendMii, \"nn_fp\", \"GetFriendMii__Q2_2nn2fpFP12FFLStoreDataPCUiUi\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetFriendPresence, \"nn_fp\", \"GetFriendPresence__Q2_2nn2fpFPQ3_2nn2fp14FriendPresencePCUiUi\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetFriendRelationship, \"nn_fp\", \"GetFriendRelationship__Q2_2nn2fpFPUcPCUiUi\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(IsJoinable, \"nn_fp\", \"IsJoinable__Q2_2nn2fpFPCQ3_2nn2fp14FriendPresenceUL\", LogType::NN_FP);\n\n\t\t\t\tcafeExportRegisterFunc(CheckSettingStatusAsync, \"nn_fp\", \"CheckSettingStatusAsync__Q2_2nn2fpFPUcPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(IsPreferenceValid, \"nn_fp\", \"IsPreferenceValid__Q2_2nn2fpFv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(UpdateCommentAsync, \"nn_fp\", \"UpdateCommentAsync__Q2_2nn2fpFPCwPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(UpdatePreferenceAsync, \"nn_fp\", \"UpdatePreferenceAsync__Q2_2nn2fpFPCQ3_2nn2fp10PreferencePFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(GetRequestBlockSettingAsync, \"nn_fp\", \"GetRequestBlockSettingAsync__Q2_2nn2fpFPUcPCUiUiPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\n\t\t\t\tcafeExportRegisterFunc(UpdateGameModeWithUnusedParam, \"nn_fp\", \"UpdateGameMode__Q2_2nn2fpFPCQ3_2nn2fp8GameModePCwUi\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(UpdateGameMode, \"nn_fp\", \"UpdateGameMode__Q2_2nn2fpFPCQ3_2nn2fp8GameModePCw\", LogType::NN_FP);\n\n\t\t\t\tcafeExportRegisterFunc(AddFriendAsyncByPid, \"nn_fp\", \"AddFriendAsync__Q2_2nn2fpFUiPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(AddFriendRequestByPlayRecordAsync, \"nn_fp\", \"AddFriendRequestAsync__Q2_2nn2fpFPCQ3_2nn2fp18RecentPlayRecordExPCwPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(DeleteFriendFlagsAsync, \"nn_fp\", \"DeleteFriendFlagsAsync__Q2_2nn2fpFPCUiUiT2PFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(RemoveFriendAsync, \"nn_fp\", \"RemoveFriendAsync__Q2_2nn2fpFUiPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(MarkFriendRequestsAsReceivedAsync, \"nn_fp\", \"MarkFriendRequestsAsReceivedAsync__Q2_2nn2fpFPCULUiPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(CancelFriendRequestAsync, \"nn_fp\", \"CancelFriendRequestAsync__Q2_2nn2fpFULPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(DeleteFriendRequestAsync, \"nn_fp\", \"DeleteFriendRequestAsync__Q2_2nn2fpFULPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t\tcafeExportRegisterFunc(AcceptFriendRequestAsync, \"nn_fp\", \"AcceptFriendRequestAsync__Q2_2nn2fpFULPFQ2_2nn6ResultPv_vPv\", LogType::NN_FP);\n\t\t\t};\n\n\t\t}s_COSnnFpModule;\n\n\t\tCOSModule* GetModule()\n\t\t{\n\t\t\treturn &s_COSnnFpModule;\n\t\t}\n\n\t}\n}\n\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_fp/nn_fp.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\nnamespace nn::fp\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_idbe/nn_idbe.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/nn_acp/nn_acp.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"util/crypto/aes128.h\"\n#include \"openssl/sha.h\"\n#include \"Cemu/napi/napi.h\"\n\nnamespace nn\n{\n\tnamespace idbe\n\t{\n\t\tstruct nnIdbeIconDataV0_t\n\t\t{\n\t\t\t// raw icon data as byte array\n\t\t\t// check NAPI::IDBEIconDataV0 for exact data layout\n\t\t\tuint8 rawData[0x12060];\n\t\t\tuint8* GetTGAData()\n\t\t\t{\n\t\t\t\treturn rawData + 0x2030;\n\t\t\t}\n\t\t};\n\n\t\tstatic_assert(sizeof(nnIdbeIconDataV0_t) == 0x12060, \"\");\n\n\t\tstruct nnIdbeHeader_t\n\t\t{\n\t\t\tuint8 formatVersion;\n\t\t\tuint8 keyIndex;\n\t\t};\n\n\t\tstruct nnIdbeEncryptedIcon_t\n\t\t{\n\t\t\tnnIdbeHeader_t header;\n\t\t\tuint8 hashSHA256[32];\n\t\t\tnnIdbeIconDataV0_t iconData;\n\t\t};\n\n\t\tstatic_assert(offsetof(nnIdbeEncryptedIcon_t, hashSHA256) == 2, \"\");\n\t\tstatic_assert(offsetof(nnIdbeEncryptedIcon_t, iconData) == 0x22, \"\");\n\t\tstatic_assert(sizeof(nnIdbeEncryptedIcon_t) == 0x12082);\n\n\t\tvoid asyncDownloadIconFile(uint64 titleId, nnIdbeEncryptedIcon_t* iconOut, coreinit::OSEvent* event)\n\t\t{\n\t\t\tstd::vector<uint8> idbeData = NAPI::IDBE_RequestRawEncrypted(ActiveSettings::GetNetworkService(), titleId);\n\t\t\tif (idbeData.size() != sizeof(nnIdbeEncryptedIcon_t))\n\t\t\t{\n\t\t\t\t// icon does not exist or has the wrong size\n\t\t\t\tcemuLog_log(LogType::Force, \"IDBE: Failed to retrieve icon for title {:016x}\", titleId);\n\t\t\t\tmemset(iconOut, 0, sizeof(nnIdbeEncryptedIcon_t));\n\t\t\t\tcoreinit::OSSignalEvent(event);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tmemcpy(iconOut, idbeData.data(), sizeof(nnIdbeEncryptedIcon_t));\n\t\t\tcoreinit::OSSignalEvent(event);\n\t\t}\n\n\t\tvoid export_DownloadIconFile(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tppcDefineParamTypePtr(encryptedIconData, nnIdbeEncryptedIcon_t, 0);\n\t\t\tppcDefineParamU64(titleId, 2);\n\t\t\tppcDefineParamU32(uknR7, 4);\n\t\t\tppcDefineParamU32(uknR8, 5);\n\n\t\t\tStackAllocator<coreinit::OSEvent> event;\n\t\t\tcoreinit::OSInitEvent(&event, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);\n\t\t\tauto asyncTask = std::async(std::launch::async, asyncDownloadIconFile, titleId, encryptedIconData, &event);\n\t\t\tcoreinit::OSWaitEvent(&event);\n\t\t\tosLib_returnFromFunction(hCPU, 1);\n\t\t}\n\n\t\tstatic_assert(sizeof(nnIdbeHeader_t) == 0x2, \"\");\n\n\t\tstatic uint8 idbeAesKeys[4 * 16] =\n\t\t{\n\t\t\t0x4A,0xB9,0xA4,0x0E,0x14,0x69,0x75,0xA8,0x4B,0xB1,0xB4,0xF3,0xEC,0xEF,0xC4,0x7B,\n\t\t\t0x90,0xA0,0xBB,0x1E,0x0E,0x86,0x4A,0xE8,0x7D,0x13,0xA6,0xA0,0x3D,0x28,0xC9,0xB8,\n\t\t\t0xFF,0xBB,0x57,0xC1,0x4E,0x98,0xEC,0x69,0x75,0xB3,0x84,0xFC,0xF4,0x07,0x86,0xB5,\n\t\t\t0x80,0x92,0x37,0x99,0xB4,0x1F,0x36,0xA6,0xA7,0x5F,0xB8,0xB4,0x8C,0x95,0xF6,0x6F\n\t\t};\n\n\t\tstatic uint8 idbeAesIv[16] =\n\t\t{\n\t\t\t0xA4,0x69,0x87,0xAE,0x47,0xD8,0x2B,0xB4,0xFA,0x8A,0xBC,0x04,0x50,0x28,0x5F,0xA4\n\t\t};\n\n\t\tbool decryptIcon(nnIdbeEncryptedIcon_t* iconInput, nnIdbeIconDataV0_t* iconOutput)\n\t\t{\n\t\t\t// check header\n\t\t\tnnIdbeHeader_t* idbeHeader = (nnIdbeHeader_t*)iconInput;\n\t\t\tif (idbeHeader->formatVersion != 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"idbe header version unknown ({})\", (sint32)idbeHeader->formatVersion);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (idbeHeader->keyIndex >= 4)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"idbe header key count invalid ({})\", (sint32)idbeHeader->keyIndex);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// decrypt data\n\t\t\tuint8 iv[16];\n\t\t\tmemcpy(iv, idbeAesIv, sizeof(iv));\n\t\t\tuint8 decryptedSHA256[SHA256_DIGEST_LENGTH];\n\t\t\tAES128_CBC_decrypt_updateIV(decryptedSHA256, iconInput->hashSHA256, sizeof(decryptedSHA256), idbeAesKeys + 16 * idbeHeader->keyIndex, iv);\n\t\t\tAES128_CBC_decrypt((uint8*)iconOutput, (uint8*)&iconInput->iconData, sizeof(iconInput->iconData), idbeAesKeys + 16 * idbeHeader->keyIndex, iv);\n\t\t\t// calculate and compare sha256\n\t\t\tuint8 calculatedSHA256[SHA256_DIGEST_LENGTH];\n\t\t\tSHA256((const unsigned char*)iconOutput, sizeof(nnIdbeIconDataV0_t), calculatedSHA256);\n\t\t\tif (memcmp(calculatedSHA256, decryptedSHA256, SHA256_DIGEST_LENGTH) != 0)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Idbe icon has incorrect sha256 hash\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tstruct TGAHeader\n\t\t{\n\t\t\t/* +0x00 */ uint8 idLength;\n\t\t\t/* +0x01 */ uint8 colorMap;\n\t\t\t/* +0x02 */ uint8 imageType;\n\t\t\t/* +0x03 */\tuint8 colorMap_firstIndex_low;\n\t\t\t/* +0x04 */ uint8 colorMap_firstIndex_high;\n\t\t\t/* +0x05 */ uint8 colorMap_len_low;\n\t\t\t/* +0x06 */ uint8 colorMap_len_high;\n\t\t\t/* +0x07 */ uint8 colorMap_bpp;\n\t\t\t/* +0x08 */ uint16 image_xOrigin;\n\t\t\t/* +0x0A */ uint16 image_yOrigin;\n\t\t\t/* +0x0C */ uint16 image_width;\n\t\t\t/* +0x0E */ uint16 image_height;\n\t\t\t/* +0x10 */ uint8 image_bpp;\n\t\t\t/* +0x11 */ uint8 image_desc;\n\t\t};\n\n\t\tstatic_assert(offsetof(TGAHeader, colorMap_firstIndex_low) == 0x03);\n\t\tstatic_assert(sizeof(TGAHeader) == 0x12);\n\n\t\tvoid export_DecryptIconFile(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tppcDefineParamTypePtr(output, nnIdbeIconDataV0_t, 0);\n\t\t\tppcDefineParamTypePtr(input, nnIdbeEncryptedIcon_t, 1);\n\t\t\tppcDefineParamU32(platformMode, 2);\n\n\t\t\tcemuLog_logDebug(LogType::Force, \"nn_idbe.DecryptIconFile(...)\");\n\n\t\t\tif (decryptIcon(input, output))\n\t\t\t{\n\t\t\t\tosLib_returnFromFunction(hCPU, 1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcemuLog_logDebug(LogType::Force, \"Unable to decrypt idbe icon file, using default icon\");\n\n\t\t\t// return default icon\n\t\t\tTGAHeader* tgaHeader = (TGAHeader*)(output->GetTGAData());\n\t\t\tmemset(tgaHeader, 0, sizeof(TGAHeader));\n\t\t\ttgaHeader->imageType = 2;\n\n\t\t\ttgaHeader->image_width = 256;\n\t\t\ttgaHeader->image_height = 256;\n\t\t\ttgaHeader->image_bpp = 32;\n\t\t\ttgaHeader->image_desc = (1 << 3);\n\n\t\t\tosLib_returnFromFunction(hCPU, 1);\n\t\t}\n\n\t\t// this module is used by:\n\t\t// Daily Log app\n\t\t// Download Manager app\n\t\t// and possibly other system titles?\n\n\t\tclass : public COSModule\n\t\t{\n\t\t\tpublic:\n\t\t\tstd::string_view GetName() override\n\t\t\t{\n\t\t\t\treturn \"nn_idbe\";\n\t\t\t}\n\n\t\t\tvoid RPLMapped() override\n\t\t\t{\n\t\t\t\tosLib_addFunction(\"nn_idbe\", \"DownloadIconFile__Q2_2nn4idbeFPvULUsb\", export_DownloadIconFile);\n\t\t\t\tosLib_addFunction(\"nn_idbe\", \"DecryptIconFile__Q2_2nn4idbeFPvPCv\", export_DecryptIconFile);\n\t\t\t};\n\n\t\t}s_COSnnIdbeModule;\n\n\t\tCOSModule* GetModule()\n\t\t{\n\t\t\treturn &s_COSnnIdbeModule;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_idbe/nn_idbe.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::idbe\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_ndm/nn_ndm.cpp",
    "content": "#include \"nn_ndm.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n\nnamespace nn\n{\n\tnamespace ndm\n\t{\n\n\t\tenum class DAEMON_NAME : uint32\n\t\t{\n\t\t\tUKN_0, // Boss related?\n\t\t\tUKN_1, // Download Manager? scope.rpx (Download Manager app) expects this to have status 0 or 1. Otherwise it will display downloads as disabled\n\t\t\tUKN_2,\n\t\t};\n\n\t\tenum class DAEMON_STATUS : uint32\n\t\t{\n\t\t\tSTATUS_UKN_0 = 0, // probably: Ready or initializing?\n\t\t\tRUNNING = 1, // most likely running, but not 100% sure\n\t\t\tSTATUS_UKN_2 = 2, // probably: ready, starting or something like that?\n\t\t\tSUSPENDED = 3,\n\t\t};\n\n\t\tconstexpr size_t NUM_DAEMONS = 3;\n\t\tDAEMON_STATUS s_daemonStatus[NUM_DAEMONS];\n\t\tuint32 s_initializeRefCount;\n\n\t\tuint32 Initialize()\n\t\t{\n\t\t\ts_initializeRefCount++;\n\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NDM, 0);\n\t\t}\n\n\t\tuint32 IsInitialized()\n\t\t{\n\t\t\treturn s_initializeRefCount != 0 ? 1 : 0;\n\t\t}\n\n\t\tuint32 Finalize()\n\t\t{\n\t\t\tif(s_initializeRefCount == 0)\n\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NDM, 0);\n\t\t\ts_initializeRefCount++;\n\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NDM, 0);\n\t\t}\n\n\t\tuint32 GetDaemonStatus(betype<DAEMON_STATUS>* statusOut, DAEMON_NAME daemonName)\n\t\t{\n\t\t\tsize_t daemonIndex = (size_t)daemonName;\n\t\t\tif(daemonIndex >= NUM_DAEMONS)\n\t\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NDM, 0);\n\t\t\t*statusOut = s_daemonStatus[daemonIndex];\n\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NDM, 0);\n\t\t}\n\n\t\tuint32 SuspendDaemons(uint32 daemonNameBitmask)\n\t\t{\n\t\t\tfor(size_t i=0; i<NUM_DAEMONS; i++)\n\t\t\t{\n\t\t\t\tif(daemonNameBitmask & (1 << i))\n\t\t\t\t\ts_daemonStatus[i] = DAEMON_STATUS::SUSPENDED;\n\t\t\t}\n\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NDM, 0);\n\t\t}\n\n\t\tuint32 ResumeDaemons(uint32 daemonNameBitmask)\n\t\t{\n\t\t\tfor(size_t i=0; i<NUM_DAEMONS; i++)\n\t\t\t{\n\t\t\t\tif(daemonNameBitmask & (1 << i))\n\t\t\t\t\ts_daemonStatus[i] = DAEMON_STATUS::RUNNING;\n\t\t\t}\n\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NDM, 0);\n\t\t}\n\n\t\tclass : public COSModule\n\t\t{\n\t\t\tpublic:\n\t\t\tstd::string_view GetName() override\n\t\t\t{\n\t\t\t\treturn \"nn_ndm\";\n\t\t\t}\n\n\t\t\tvoid RPLMapped() override\n\t\t\t{\n\t\t\t\tfor(size_t i=0; i<NUM_DAEMONS; i++)\n\t\t\t\t\ts_daemonStatus[i] = DAEMON_STATUS::RUNNING;\n\t\t\t\ts_initializeRefCount = 0;\n\n\t\t\t\tcafeExportRegisterFunc(Initialize, \"nn_ndm\", \"Initialize__Q2_2nn3ndmFv\", LogType::Placeholder);\n\t\t\t\tcafeExportRegisterFunc(Finalize, \"nn_ndm\", \"Finalize__Q2_2nn3ndmFv\", LogType::Placeholder);\n\t\t\t\tcafeExportRegisterFunc(IsInitialized, \"nn_ndm\", \"IsInitialized__Q2_2nn3ndmFv\", LogType::Placeholder);\n\t\t\t\tcafeExportRegisterFunc(GetDaemonStatus, \"nn_ndm\", \"GetDaemonStatus__Q2_2nn3ndmFPQ4_2nn3ndm7IDaemon6StatusQ4_2nn3ndm4Cafe10DaemonName\", LogType::Placeholder);\n\t\t\t\tcafeExportRegisterFunc(SuspendDaemons, \"nn_ndm\", \"SuspendDaemons__Q2_2nn3ndmFUi\", LogType::Placeholder);\n\t\t\t\tcafeExportRegisterFunc(ResumeDaemons, \"nn_ndm\", \"ResumeDaemons__Q2_2nn3ndmFUi\", LogType::Placeholder);\n\t\t\t};\n\n\t\t}s_COSnnNdmModule;\n\n\t\tCOSModule* GetModule()\n\t\t{\n\t\t\treturn &s_COSnnNdmModule;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_ndm/nn_ndm.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn\n{\n\tnamespace ndm\n\t{\n\t\tCOSModule* GetModule();\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_nfp/AmiiboCrypto.h",
    "content": "#pragma once\n#include \"util/crypto/aes128.h\"\n#include \"openssl/evp.h\"\n#include \"openssl/hmac.h\"\n\ntypedef struct\n{\n\tchar typeString[14];\n\tuint8 magicBytes[16];\n\tuint8 magicBytesLen;\n\tuint8 xorPad[32];\n\tuint8 hmacKey[16];\n}amiiboInternalKeys_t;\n\nvoid amiiboCalcSeed(AmiiboInternal* internalData, uint8* seed)\n{\n\tmemcpy(seed + 0x00, (uint8*)internalData + 0x029, 0x02);\n\tmemset(seed + 0x02, 0x00, 0x0E);\n\tmemcpy(seed + 0x10, (uint8*)internalData + 0x1D4, 0x08);\n\tmemcpy(seed + 0x18, (uint8*)internalData + 0x1D4, 0x08);\n\tmemcpy(seed + 0x20, (uint8*)internalData + 0x1E8, 0x20);\n}\n\nvoid amiiboGenKeyInternalPrepare(amiiboInternalKeys_t* keys, uint8* seed, uint8* output, sint32& outputLen)\n{\n\tsint32 index = 0;\n\n\t// concat:\n\t// typeString (including '\\0')\n\tsint32 typeStringLen = (sint32)strlen(keys->typeString)+1;\n\tmemcpy(output + index, keys->typeString, typeStringLen);\n\tindex += typeStringLen;\n\t// seed (16 - magic byte len)\n\tsint32 seedPart1Len = 16 - keys->magicBytesLen;\n\tmemcpy(output + index, seed, seedPart1Len);\n\tindex += seedPart1Len;\n\t// magic bytes + 16 bytes at +0x10 from input seed\n\tmemcpy(output + index, keys->magicBytes, keys->magicBytesLen);\n\tindex += keys->magicBytesLen;\n\t// seed 16 bytes at +0x10\n\tmemcpy(output + index, seed + 0x10, 16);\n\tindex += 16;\n\t// 32 bytes at +0x20 from input seed xored with xor pad\n\tfor (sint32 i = 0; i < 32; i++)\n\t\toutput[index + i] = seed[i + 32] ^ keys->xorPad[i];\n\tindex += 32;\n\n\toutputLen = index;\n}\n\ntypedef struct \n{\n\tuint8 hmacKey[16];\n\tuint8 buffer[sizeof(uint16) + 480];\n\tsint32 bufferSize;\n\tuint16 counter;\n}amiiboCryptCtx_t;\n\ntypedef struct\n{\n\tuint8 raw[32];\n}drgbOutput32_t;\n\nvoid amiiboCryptInit(amiiboCryptCtx_t* ctx, const uint8* hmacKey, size_t hmacKeySize, const uint8* seed, sint32 seedSize)\n{\n\tctx->counter = 0;\n\tctx->bufferSize = (sint32)sizeof(ctx->counter) + seedSize;\n\tmemcpy(ctx->hmacKey, hmacKey, 16);\n\n\t// set static part of buffer\n\tmemcpy(ctx->buffer + sizeof(uint16), seed, seedSize);\n}\n\nvoid amiiboCryptStep(amiiboCryptCtx_t* ctx, drgbOutput32_t* output)\n{\n\t// update counter\n\tctx->buffer[0] = ctx->counter >> 8;\n\tctx->buffer[1] = ctx->counter >> 0;\n\tctx->counter++;\n\t// generate bytes\n\tuint32 mdLen = (uint32)sizeof(drgbOutput32_t);\n\tHMAC(EVP_sha256(), ctx->hmacKey, sizeof(ctx->hmacKey), (const unsigned char *)ctx->buffer, ctx->bufferSize, output->raw, &mdLen);\n}\n\ntypedef struct\n{\n\tuint8 aesKey[16];\n\tuint8 aesIV[16];\n\tuint8 hmacKey[16];\n}amiiboDerivedKeys_t;\n\nstatic_assert(sizeof(amiiboDerivedKeys_t) == 0x30);\n\nvoid amiiboCrypto_genKey(amiiboInternalKeys_t* keys, AmiiboInternal* internalData, amiiboDerivedKeys_t* derivedKeys)\n{\n\t// generate seed\n\tuint8 seed[0x40];\n\tamiiboCalcSeed(internalData, seed);\n\n\t// generate internal seed\n\tuint8 internalKey[512];\n\tsint32 internalKeyLen = 0;\n\tamiiboGenKeyInternalPrepare(keys, seed, internalKey, internalKeyLen);\n\n\t// gen bytes for derived keys\n\tdrgbOutput32_t temp[2];\n\tamiiboCryptCtx_t rngCtx;\n\tamiiboCryptInit(&rngCtx, keys->hmacKey, sizeof(keys->hmacKey), internalKey, internalKeyLen);\n\tamiiboCryptStep(&rngCtx, temp + 0);\n\tamiiboCryptStep(&rngCtx, temp + 1);\n\tmemcpy(derivedKeys, temp, sizeof(amiiboDerivedKeys_t));\n}\n\nvoid amiiboCrypto_nfcFormatToInternal(AmiiboRawNFCData* nfcData, AmiiboInternal* internalData)\n{\n\tuint8* tag = (uint8*)nfcData;\n\tuint8* intl = (uint8*)internalData;\n\n\tmemcpy(intl + 0x000, tag + 0x008, 0x008);\n\tmemcpy(intl + 0x008, tag + 0x080, 0x020); // tag hmac\n\tmemcpy(intl + 0x028, tag + 0x010, 0x024);\n\tmemcpy(intl + 0x04C, tag + 0x0A0, 0x168);\n\tmemcpy(intl + 0x1B4, tag + 0x034, 0x020); // data hmac\n\tmemcpy(intl + 0x1D4, tag + 0x000, 0x008);\n\tmemcpy(intl + 0x1DC, tag + 0x054, 0x02C);\n}\n\nvoid amiiboCrypto_internalToNfcFormat(AmiiboInternal* internalData, AmiiboRawNFCData* nfcData)\n{\n\tuint8* tag = (uint8*)nfcData;\n\tuint8* intl = (uint8*)internalData;\n\n\tmemcpy(tag + 0x008, intl + 0x000, 0x008);\n\tmemcpy(tag + 0x080, intl + 0x008, 0x020); // tag hmac\n\tmemcpy(tag + 0x010, intl + 0x028, 0x024);\n\tmemcpy(tag + 0x0A0, intl + 0x04C, 0x168);\n\tmemcpy(tag + 0x034, intl + 0x1B4, 0x020); // data hmac\n\tmemcpy(tag + 0x000, intl + 0x1D4, 0x008);\n\tmemcpy(tag + 0x054, intl + 0x1DC, 0x02C);\n}\n\nvoid amiiboCrypto_transform(const amiiboDerivedKeys_t * keys, uint8 * in, uint8 * out)\n{\n\tuint8 nonce[16];\n\n\tmemcpy(nonce, keys->aesIV, sizeof(nonce));\n\t\n\tAmiiboInternal internalCopy;\n\tmemcpy(&internalCopy, in, sizeof(internalCopy));\n\n\tif (out != in)\n\t\tmemcpy(out, in, 0x188 + 0x2C);\n\tAES128CTR_transform(out + 0x2C, 0x188, (uint8*)keys->aesKey, nonce);\n\n\tmemcpy(out + 0x000, ((uint8*)&internalCopy) + 0x000, 0x008);\n\tmemcpy(out + 0x028, ((uint8*)&internalCopy) + 0x028, 0x004);\n\tmemcpy(out + 0x1D4, ((uint8*)&internalCopy) + 0x1D4, 0x034);\n}\n\nvoid AES128_init();\n\nvoid amiiboInitMasterKeys(amiiboInternalKeys_t& kData, amiiboInternalKeys_t& kTag)\n{\n\tuint8 dataKey_hmacKey[16] = { 0x1D, 0x16, 0x4B, 0x37, 0x5B, 0x72, 0xA5, 0x57, 0x28, 0xB9, 0x1D, 0x64, 0xB6, 0xA3, 0xC2, 0x05 };\n\tuint8 dataKey_typeString[14] = { \"unfixed infos\" };\n\tuint8 dataKey_magicBytesSize = 0x0E;\n\tuint8 dataKey_magicBytes[14] = { 0xDB, 0x4B, 0x9E, 0x3F, 0x45, 0x27, 0x8F, 0x39, 0x7E, 0xFF, 0x9B, 0x4F, 0xB9, 0x93 };\n\tuint8 dataKey_xorPad[32] = { 0x04, 0x49, 0x17, 0xDC, 0x76, 0xB4, 0x96, 0x40, 0xD6, 0xF8, 0x39, 0x39, 0x96, 0x0F, 0xAE, 0xD4, 0xEF, 0x39, 0x2F, 0xAA, 0xB2, 0x14, 0x28, 0xAA, 0x21, 0xFB, 0x54, 0xE5, 0x45, 0x05, 0x47, 0x66 };\n\n\tuint8 tagKey_hmacKey[16] = { 0x7F, 0x75, 0x2D, 0x28, 0x73, 0xA2, 0x00, 0x17, 0xFE, 0xF8, 0x5C, 0x05, 0x75, 0x90, 0x4B, 0x6D };\n\tuint8 tagKey_typeString[14] = { \"locked secret\" };\n\tuint8 tagKey_magicBytesSize = 0x10;\n\tuint8 tagKey_magicBytes[16] = { 0xFD, 0xC8, 0xA0, 0x76, 0x94, 0xB8, 0x9E, 0x4C, 0x47, 0xD3, 0x7D, 0xE8, 0xCE, 0x5C, 0x74, 0xC1 };\n\tuint8 tagKey_xorPad[32] = { 0x04, 0x49, 0x17, 0xDC, 0x76, 0xB4, 0x96, 0x40, 0xD6, 0xF8, 0x39, 0x39, 0x96, 0x0F, 0xAE, 0xD4, 0xEF, 0x39, 0x2F, 0xAA, 0xB2, 0x14, 0x28, 0xAA, 0x21, 0xFB, 0x54, 0xE5, 0x45, 0x05, 0x47, 0x66 };\n\n\tmemcpy(kData.hmacKey, dataKey_hmacKey, 16);\n\tmemcpy(kData.typeString, dataKey_typeString, 13);\n\tkData.magicBytesLen = dataKey_magicBytesSize;\n\tmemcpy(kData.magicBytes, dataKey_magicBytes, 14);\n\tmemcpy(kData.xorPad, dataKey_xorPad, 32);\n\n\tmemcpy(kTag.hmacKey, tagKey_hmacKey, 16);\n\tmemcpy(kTag.typeString, tagKey_typeString, 13);\n\tkTag.magicBytesLen = tagKey_magicBytesSize;\n\tmemcpy(kTag.magicBytes, tagKey_magicBytes, 16);\n\tmemcpy(kTag.xorPad, tagKey_xorPad, 32);\n}\n\nvoid amiiboDecrypt()\n{\n\tamiiboInternalKeys_t kData{};\n\tamiiboInternalKeys_t kTag{};\n\tamiiboInitMasterKeys(kData, kTag);\n\n\tamiiboDerivedKeys_t derivedKeysData{};\n\tamiiboDerivedKeys_t derivedKeysTag{};\n\n\tamiiboCrypto_nfcFormatToInternal(&nfp_data.amiiboNFCData, &nfp_data.amiiboInternal);\n\n\tamiiboCrypto_genKey(&kData, &nfp_data.amiiboInternal, &derivedKeysData);\n\tamiiboCrypto_genKey(&kTag, &nfp_data.amiiboInternal, &derivedKeysTag);\n\n\tamiiboCrypto_transform(&derivedKeysData, (uint8*)&nfp_data.amiiboInternal, (uint8*)&nfp_data.amiiboInternal);\n\n\t// generate tag hmac\n\tuint32 mdLen = 32;\n\tHMAC(EVP_sha256(), derivedKeysTag.hmacKey, 16, (((uint8*)&nfp_data.amiiboInternal) + 0x1D4), 0x34,\n\t\tnfp_data.amiiboInternal.tagHMAC, &mdLen);\n\t// generate data hmac\n\tmdLen = 32;\n\tHMAC(EVP_sha256(), derivedKeysData.hmacKey, 16, (((uint8*)&nfp_data.amiiboInternal) + 0x29), 0x1DF,\n\t\t((uint8*)&nfp_data.amiiboInternal) + 0x8, &mdLen);\n\n\tbool isValidTagHMAC = memcmp(nfp_data.amiiboNFCData.tagHMAC, nfp_data.amiiboInternal.tagHMAC, 32) == 0;\n\tbool isValidDataHMAC = memcmp(nfp_data.amiiboNFCData.dataHMAC, nfp_data.amiiboInternal.dataHMAC, 32) == 0;\n\tif (!isValidTagHMAC)\n\t\tcemuLog_log(LogType::Force, \"Decrypt amiibo has invalid tag HMAC\");\n\tif (!isValidDataHMAC)\n\t\tcemuLog_log(LogType::Force, \"Decrypt amiibo has invalid data HMAC\");\n\tnfp_data.hasInvalidHMAC = !isValidTagHMAC || !isValidDataHMAC;\n}\n\nvoid amiiboEncrypt(AmiiboRawNFCData* nfcOutput)\n{\n\tamiiboInternalKeys_t kData{};\n\tamiiboInternalKeys_t kTag{};\n\tamiiboInitMasterKeys(kData, kTag);\n\n\tamiiboDerivedKeys_t derivedKeysData{};\n\tamiiboDerivedKeys_t derivedKeysTag{};\n\n\t// copy internal Amiibo data\n\tAmiiboInternal internalCopy;\n\tmemcpy(&internalCopy, &nfp_data.amiiboInternal, sizeof(AmiiboInternal));\n\n\t// gen key\n\tamiiboCrypto_genKey(&kData, &internalCopy, &derivedKeysData);\n\tamiiboCrypto_genKey(&kTag, &internalCopy, &derivedKeysTag);\n\n\t// generate new HMACs\n\tuint8 tagHMAC[32];\n\tuint32 mdLen = 32;\n\tHMAC(EVP_sha256(), derivedKeysTag.hmacKey, 16, (((uint8*)&internalCopy) + 0x1D4), 0x34,\n\t\ttagHMAC, &mdLen);\n\tmdLen = 32;\n\tuint8 dataHMAC[32];\n\tHMAC(EVP_sha256(), derivedKeysData.hmacKey, 16, (((uint8*)&internalCopy) + 0x29), 0x1DF,\n\t\tdataHMAC, &mdLen);\n\n\tmemset(internalCopy.tagHMAC, 0, 32);\n\tmemset(internalCopy.dataHMAC, 0, 32);\n\n\t// transform\n\tamiiboCrypto_transform(&derivedKeysData, (uint8*)&internalCopy, (uint8*)&internalCopy);\n\n\t// set HMACs\n\tmemcpy(internalCopy.tagHMAC, tagHMAC, 32);\n\tmemcpy(internalCopy.dataHMAC, dataHMAC, 32);\n\n\t// convert back to nfc order\n\tamiiboCrypto_internalToNfcFormat(&internalCopy, nfcOutput);\n\n\t// restore NFC values that aren't part of the internal representation\n\tmemcpy(nfcOutput->dynamicLock, nfp_data.amiiboNFCData.dynamicLock, 4);\n\tmemcpy(nfcOutput->cfg0, nfp_data.amiiboNFCData.cfg0, 4);\n\tmemcpy(nfcOutput->cfg1, nfp_data.amiiboNFCData.cfg1, 4);\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_nfp/nn_nfp.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"nn_nfp.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Common/FileStream.h\"\n#include \"Cafe/CafeSystem.h\"\n\nstd::recursive_mutex g_nfpMutex;\n\nvoid nnNfpLock()\n{\n\tg_nfpMutex.lock();\n}\n\nbool nnNfpTryLock()\n{\n\treturn g_nfpMutex.try_lock();\n}\n\nvoid nnNfpUnlock()\n{\n\tg_nfpMutex.unlock();\n}\n\nstruct AmiiboInternal\n{\n\t/* +0x000 */ uint16 lockBytes;\n\t/* +0x002 */ uint16 staticLock;\n\t/* +0x004 */ uint32 cc;\n\t/* +0x008 */ uint8 dataHMAC[32];\n\t/* +0x028 */ uint8 ukn_A5; // always 0xA5\n\t/* +0x029 */ uint8 writeCounterHigh;\n\t/* +0x029 */ uint8 writeCounterLow;\n\t/* +0x02B */ uint8 unk02B;\n\t/* encrypted region starts here */\n\tstruct\n\t{\n\t\t/* +0x02C */ uint8 flags;\n\t\t/* +0x02D */ uint8 countryCode;\n\t\t/* +0x02E */ uint16be crcWriteCounter;\n\t\t/* +0x030 */ uint16be date1;\n\t\t/* +0x032 */ uint16be date2;\n\t\t/* +0x034 */ uint32be crc;\n\t\t/* +0x038 */ uint16be nickname[10];\n\t\t/* +0x04C */ uint8 mii[0x60];\n\t\t/* +0x0AC */ uint32be appDataTitleIdHigh;\n\t\t/* +0x0B0 */ uint32be appDataTitleIdLow;\n\t\t/* +0x0B4 */ uint16be appWriteCounter;\n\t\t/* +0x0B6 */ uint16be appDataIdHigh;\n\t\t/* +0x0B8 */ uint16be appDataIdLow;\n\t\t/* +0x0BA */ uint16be ukn0BA;\n\t\t/* +0x0BC */ uint32be ukn0BC;\n\t\t/* +0x0C0 */ uint32be ukn0C0;\n\t\t/* +0x0C4 */ uint32be ukn0C4;\n\t\t/* +0x0C8 */ uint32be ukn0C8;\n\t\t/* +0x0CC */ uint32be ukn0CC;\n\t\t/* +0x0D0 */ uint32be ukn0D0;\n\t\t/* +0x0D4 */ uint32be ukn0D4;\n\t\t/* +0x0D8 */ uint32be ukn0D8;\n\t\tuint32 getAppDataAppId()\n\t\t{\n\t\t\tuint32 appId = (uint32)appDataIdHigh << 16;\n\t\t\tappId |= (uint32)appDataIdLow;\n\t\t\treturn appId;\n\t\t}\n\n\t\tvoid setAppDataAppId(uint32 appId)\n\t\t{\n\t\t\tappDataIdHigh = (uint16)(appId >> 16);\n\t\t\tappDataIdLow = (uint16)(appId & 0xFFFF);\n\t\t}\n\t}amiiboSettings;\n\t/* +0x0DC */ uint8 applicationData[0xD8];\n\t/* encrypted region ends here */\n\t/* +0x1B4 */ uint8 tagHMAC[32];\n\t/* +0x1D4 */ uint8 ntagSerial[7];\n\t/* +0x1DB */ uint8 nintendoId;\n\tstruct\n\t{\n\t\t/* +0x1DC */ uint8 gameAndCharacterId[2];\n\t\t/* +0x1DE */ uint8 characterVariation;\n\t\t/* +0x1DF */ uint8 amiiboFigureType;\n\t\t/* +0x1E0 */ uint8 amiiboModelNumber[2];\n\t\t/* +0x1E2 */ uint8 amiiboSeries;\n\t\t/* +0x1E3 */ uint8 ukn_02; // always 0x02 ?\n\t\t/* +0x1E4 */ uint8 ukn5C[4];\n\t}amiiboIdentificationBlock;\n\t/* +0x1E8 */ uint8 keygenSalt[32];\n};\n\nstatic_assert(sizeof(AmiiboInternal) == 0x208);\nstatic_assert(offsetof(AmiiboInternal, dataHMAC) == 0x8);\nstatic_assert(offsetof(AmiiboInternal, amiiboSettings.appDataIdHigh) == 0xB6);\nstatic_assert(offsetof(AmiiboInternal, amiiboSettings.ukn0D8) == 0xD8);\nstatic_assert(offsetof(AmiiboInternal, tagHMAC) == 0x1B4);\n\n\nunion AmiiboRawNFCData\n{\n\t// each page is 4 bytes\n\tstruct\n\t{\n\t\tuint8 page0[4];\n\t\tuint8 page1[4];\n\t\tuint8 page2[4];\n\t\tuint8 page3[4];\n\t\tuint8 page4[4];\n\t\tuint8 page5[4];\n\t\tuint8 page6[4];\n\t\tuint8 page7[4];\n\t\tuint8 page8[4];\n\t\tuint8 page9[4];\n\t\tuint8 page10[4];\n\t\tuint8 page11[4];\n\t\tuint8 page12[4];\n\t\tuint8 page13[4];\n\t\tuint8 page14[4];\n\t\tuint8 page15[4];\n\t\tuint8 page16[4];\n\t};\n\tstruct\n\t{\n\t\tuint8 rawByte[16 * 4];\n\t};\n\tstruct\n\t{\n\t\t/* +0x000 */ uint8 ntagSerial[7];\n\t\t/* +0x007 */ uint8 nintendoId;\n\t\t/* +0x008 */ uint8 lockBytes[2];\n\t\t/* +0x00A */ uint8 staticLock[2];\n\t\t/* +0x00C */ uint8 cc[4]; // compatibility container\n\t\t/* +0x010 */ uint8 ukn_A5; // always 0xA5\n\t\t/* +0x011 */ uint8 writeCounter[2];\n\t\t/* +0x013 */ uint8 unk013;\n\t\t/* +0x014 */ uint8 encryptedSettings[32];\n\t\t/* +0x034 */ uint8 tagHMAC[32]; // data hmac\n\t\t/* +0x054 */\n\t\tstruct\n\t\t{\n\t\t\t/* +0x54 */ uint8 gameAndCharacterId[2];\n\t\t\t/* +0x56 */ uint8 characterVariation;\n\t\t\t/* +0x57 */ uint8 amiiboFigureType;\n\t\t\t/* +0x58 */ uint8 amiiboModelNumber[2];\n\t\t\t/* +0x5A */ uint8 amiiboSeries;\n\t\t\t/* +0x5B */ uint8 ukn_02; // always 0x02 ?\n\t\t\t/* +0x5C */ uint8 ukn5C[4];\n\t\t}amiiboIdentificationBlock;\n\t\t/* +0x060 */ uint8 keygenSalt[32];\n\t\t/* +0x080 */ uint8 dataHMAC[32];\n\t\t/* +0x0A0 */ uint8 encryptedMii[0x60];\n\t\t/* +0x100 */ uint8 encryptedTitleId[8];\n\t\t/* +0x108 */ uint8 encryptedApplicationWriteCounter[2];\n\t\t/* +0x10A */ uint8 encryptedApplicationAreaId[4];\n\t\t/* +0x10E */ uint8 ukn10E[2];\n\t\t/* +0x110 */ uint8 unk110[32];\n\t\t/* +0x130 */ uint8 encryptedApplicationArea[0xD8];\n\t\t/* +0x208 */ uint8 dynamicLock[4];\n\t\t/* +0x20C */ uint8 cfg0[4];\n\t\t/* +0x210 */ uint8 cfg1[4];\n\t};\n};\n\nstatic_assert(sizeof(AmiiboRawNFCData) == 532);\n\nstruct AmiiboProcessedData\n{\n\tuint8 uidLength;\n\tuint8 uid[7];\n};\n\nstruct  \n{\n\tbool nfpIsInitialized;\n\tMPTR activateEvent;\n\tMPTR deactivateEvent;\n\tbool isDetecting;\n\tbool isMounted;\n\tbool isReadOnly;\n\tbool hasOpenApplicationArea; // set to true if application area was opened or created\n\t// currently active Amiibo\n\tbool hasActiveAmiibo;\n\tfs::path amiiboPath;\n\tbool hasInvalidHMAC;\n\tuint32 amiiboTouchTime;\n\tAmiiboRawNFCData amiiboNFCData; // raw data\n\tAmiiboInternal amiiboInternal; // decrypted internal format\n\tAmiiboProcessedData amiiboProcessedData;\n}nfp_data = { 0 };\n\nbool nnNfp_writeCurrentAmiibo();\n\n#include \"AmiiboCrypto.h\"\n\nvoid nnNfpExport_SetActivateEvent(PPCInterpreter_t* hCPU)\n{\n\t// parameters:\n\t// r3\tOSEvent_t*\n\tppcDefineParamStructPtr(osEvent, coreinit::OSEvent, 0);\n\tppcDefineParamMPTR(osEventMPTR, 0);\n\n\tdebug_printf(\"nn_nfp.SetActivateEvent(0x%08x)\\n\", osEventMPTR);\n\n\tcoreinit::OSInitEvent(osEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);\n\n\tnnNfpLock();\n\tnfp_data.activateEvent = osEventMPTR;\n\tnnNfpUnlock();\n\n\tosLib_returnFromFunction(hCPU, 0); // return value ukn\n}\n\nvoid nnNfpExport_SetDeactivateEvent(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(osEvent, coreinit::OSEvent, 0);\n\tppcDefineParamMPTR(osEventMPTR, 0);\n\n\tcemuLog_log(LogType::NN_NFP, \"SetDeactivateEvent(0x{:08x})\", osEventMPTR);\n\n\tcoreinit::OSInitEvent(osEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);\n\n\tnnNfpLock();\n\tnfp_data.deactivateEvent = osEventMPTR;\n\tnnNfpUnlock();\n\n\tosLib_returnFromFunction(hCPU, 0); // return value ukn\n}\n\nvoid nnNfpExport_Initialize(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"Nfp Initialize()\\n\");\n\tnfp_data.nfpIsInitialized = true;\n\tnfp_data.isDetecting = false;\n\tnfp_data.hasActiveAmiibo = false;\n\tnfp_data.hasOpenApplicationArea = false;\n\tnfp_data.activateEvent = MPTR_NULL;\n\tnfp_data.deactivateEvent = MPTR_NULL;\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nnNfpExport_StartDetection(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"StartDetection()\");\n\tnnNfpLock();\n\tnfp_data.isDetecting = true;\n\tnnNfpUnlock();\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_StopDetection(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"StopDetection()\");\n\tnnNfpLock();\n\tnfp_data.isDetecting = false;\n\tnnNfpUnlock();\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\n#define NFP_TAG_MAX_LENGTH\t(10)\n\ntypedef struct  \n{\n\t/* +0x00 */ uint8 uidLength;\n\t/* +0x01 */ uint8 uid[0xA];\n\t/* +0x0B */ uint8 unused0B[0x15];\n\t/* +0x20 */ uint32 ukn20[4];\n\tuint32 ukn30[4];\n\tuint32 ukn40[4];\n\tuint32 ukn50;\n}nfpTagInfo_t;\n\nstatic_assert(sizeof(nfpTagInfo_t) == 0x54, \"nfpTagInfo_t has invalid size\");\n\nvoid nnNfpExport_GetTagInfo(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"GetTagInfo(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamStructPtr(tagInfo, nfpTagInfo_t, 0);\n\n\tnnNfpLock();\n\tif (nfp_data.hasActiveAmiibo == false)\n\t{\n\t\tnnNfpUnlock();\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0)); // todo: Return correct error code\n\t\treturn;\n\t}\n\tmemset(tagInfo, 0x00, sizeof(nfpTagInfo_t));\n\n\tmemcpy(tagInfo->uid, nfp_data.amiiboProcessedData.uid, nfp_data.amiiboProcessedData.uidLength);\n\ttagInfo->uidLength = (uint8)nfp_data.amiiboProcessedData.uidLength;\n\t// todo - remaining values\n\n\tnnNfpUnlock();\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_Mount(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"Mount()\");\n\tnnNfpLock();\n\tif (nfp_data.hasActiveAmiibo == false)\n\t{\n\t\tnnNfpUnlock();\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0)); // todo: Return correct error code\n\t\treturn;\n\t}\n\tnfp_data.isMounted = true;\n\tnfp_data.isReadOnly = false;\n\tnfp_data.isDetecting = false;\n\tnnNfpUnlock();\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_Unmount(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"Unmount()\");\n\tnfp_data.hasOpenApplicationArea = false;\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_MountRom(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"MountRom()\");\n\tnnNfpLock();\n\tif (nfp_data.hasActiveAmiibo == false)\n\t{\n\t\tnnNfpUnlock();\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0)); // todo: Return correct error code\n\t\treturn;\n\t}\n\tnfp_data.isMounted = true;\n\tnfp_data.isReadOnly = true;\n\tnfp_data.isDetecting = false;\n\tnnNfpUnlock();\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nnamespace nn::nfp\n{\n\tstruct RomInfo\n\t{\n\t\t/* +0x00 */ uint8 characterId[3];\n\t\t/* +0x03 */ uint8 amiiboSeries;\n\t\t/* +0x04 */ uint16be number;\n\t\t/* +0x06 */ uint8 nfpType;\n\t\t/* +0x07 */ uint8 unused[0x2F];\n\t};\n\n\tstatic_assert(offsetof(RomInfo, amiiboSeries) == 0x3);\n\tstatic_assert(offsetof(RomInfo, number) == 0x4);\n\tstatic_assert(offsetof(RomInfo, nfpType) == 0x6);\n\tstatic_assert(sizeof(RomInfo) == 0x36);\n\n\tusing ReadOnlyInfo = RomInfo; // same layout\n\n\tvoid GetRomInfo(RomInfo* romInfo)\n\t{\n\t\tcemu_assert_debug(nfp_data.hasActiveAmiibo);\n\t\tmemset(romInfo, 0x00, sizeof(RomInfo));\n\t\tromInfo->characterId[0] = nfp_data.amiiboNFCData.amiiboIdentificationBlock.gameAndCharacterId[0];\n\t\tromInfo->characterId[1] = nfp_data.amiiboNFCData.amiiboIdentificationBlock.gameAndCharacterId[1];\n\t\tromInfo->characterId[2] = nfp_data.amiiboNFCData.amiiboIdentificationBlock.characterVariation; // guessed\n\t\tromInfo->amiiboSeries = nfp_data.amiiboNFCData.amiiboIdentificationBlock.amiiboSeries; // guessed\n\t\tromInfo->number = *(uint16be*)nfp_data.amiiboNFCData.amiiboIdentificationBlock.amiiboModelNumber; // guessed\n\t\tromInfo->nfpType = nfp_data.amiiboNFCData.amiiboIdentificationBlock.amiiboFigureType; // guessed\n\t\tmemset(romInfo->unused, 0x00, sizeof(romInfo->unused));\n\t}\n\n\tnnResult GetNfpRomInfo(RomInfo* romInfo)\n\t{\n\t\tnnNfpLock();\n\t\tif (nfp_data.hasActiveAmiibo == false)\n\t\t{\n\t\t\tnnNfpUnlock();\n\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0); // todo: Return correct error code\n\t\t}\n\t\tGetRomInfo(romInfo);\n\t\tnnNfpUnlock();\n\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0);\n\t}\n\n\tnnResult GetNfpReadOnlyInfo(ReadOnlyInfo* readOnlyInfo)\n\t{\n\t\tnnNfpLock();\n\t\tif (nfp_data.hasActiveAmiibo == false)\n\t\t{\n\t\t\tnnNfpUnlock();\n\t\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0); // todo: Return correct error code\n\t\t}\n\t\tGetRomInfo(readOnlyInfo);\n\t\tnnNfpUnlock();\n\t\treturn BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0);\n\t}\n};\n\ntypedef struct  \n{\n\tuint16be year;\n\tuint8 month;\n\tuint8 day;\n}nfpDate_t;\n\ntypedef struct  \n{\n\t/* +0x00 */ nfpDate_t date;\n\t/* +0x04 */ uint8 writeCount[2];\n\t/* +0x06 */ uint8 characterId[3];\n\t/* +0x09 */ uint8 amiiboSeries;\n\t/* +0x0A */ uint16be number;\n\t/* +0x0C */ uint8 nfpType;\n\t/* +0x0D */ uint8 nfpVersion;\n\t/* +0x0E */ uint16be applicationAreaSize;\n\t/* +0x10 */ uint8 unused[0x30];\n}nfpCommonData_t;\n\nstatic_assert(sizeof(nfpCommonData_t) == 0x40, \"nfpCommonData_t has invalid size\");\nstatic_assert(offsetof(nfpCommonData_t, writeCount) == 0x4, \"nfpCommonData.writeCount has invalid offset\");\nstatic_assert(offsetof(nfpCommonData_t, amiiboSeries) == 0x9, \"nfpCommonData.seriesId has invalid offset\");\nstatic_assert(offsetof(nfpCommonData_t, nfpType) == 0xC, \"nfpCommonData.nfpType has invalid offset\");\nstatic_assert(offsetof(nfpCommonData_t, applicationAreaSize) == 0xE, \"nfpCommonData.applicationAreaSize has invalid offset\");\n\nvoid nnNfpExport_GetNfpCommonInfo(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"GetNfpCommonInfo(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamStructPtr(commonInfo, nfpCommonData_t, 0);\n\n\tnnNfpLock();\n\tif (nfp_data.hasActiveAmiibo == false)\n\t{\n\t\tnnNfpUnlock();\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0)); // todo: Return correct error code\n\t\treturn;\n\t}\n\t// tag info format is currently unknown, so we just set it to all zeros for now\n\tif (sizeof(nfpCommonData_t) != 0x40 )\n\t\tassert_dbg();\n\tmemset(commonInfo, 0x00, sizeof(nfpCommonData_t));\n\n\tcemuLog_logDebug(LogType::Force, \"GetNfpCommonInfo(0x{:08x})\");\n\n\tcommonInfo->writeCount[0] = nfp_data.amiiboNFCData.writeCounter[0];\n\tcommonInfo->writeCount[1] = nfp_data.amiiboNFCData.writeCounter[1];\n\n\tcommonInfo->characterId[0] = nfp_data.amiiboNFCData.amiiboIdentificationBlock.gameAndCharacterId[0];\n\tcommonInfo->characterId[1] = nfp_data.amiiboNFCData.amiiboIdentificationBlock.gameAndCharacterId[1];\n\tcommonInfo->characterId[2] = nfp_data.amiiboNFCData.amiiboIdentificationBlock.characterVariation;\n\n\tcommonInfo->number = *(uint16be*)nfp_data.amiiboNFCData.amiiboIdentificationBlock.amiiboModelNumber;\n\tcommonInfo->amiiboSeries = nfp_data.amiiboNFCData.amiiboIdentificationBlock.amiiboSeries;\n\tcommonInfo->nfpType = nfp_data.amiiboNFCData.amiiboIdentificationBlock.amiiboFigureType; // guessed\n\n\tcommonInfo->applicationAreaSize = sizeof(nfp_data.amiiboInternal.applicationData); // not 100% sure if this is always set to the maximum\n\n\tnnNfpUnlock();\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\ntypedef struct  \n{\n\t/* +0x00 */ uint8 ownerMii[0x60]; \n\t/* +0x60 */ uint8 nickname[0x14];\n\t/* +0x74 */ uint16be ukn74;\n\t/* +0x76 */ uint8 ukn76;\n\t/* +0x77 */ uint8 _padding77;\n\t/* +0x78 */ nfpDate_t registerDate;\n\t/* +0x7C */ uint8 ukn7C[0x2C];\n}nfpRegisterInfo_t;\n\ntypedef struct  \n{\n\t/* +0x00 */ uint8 ownerMii[0x60];\n\t/* +0x60 */ uint8 nickname[0x14];\n\t// maybe has more fields?\n}nfpRegisterInfoSet_t;\n\nvoid nnNfpExport_GetNfpRegisterInfo(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"GetNfpRegisterInfo(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamStructPtr(registerInfo, nfpRegisterInfo_t, 0);\n\n\tif(!registerInfo)\n\t{\n\t\tosLib_returnFromFunction(hCPU, 0xC1B03780);\n\t\treturn;\n\t}\n\n\tmemset(registerInfo, 0, sizeof(nfpRegisterInfo_t));\n\tif ((nfp_data.amiiboInternal.amiiboSettings.flags & 0x10) != 0)\n\t{\n\t\tmemcpy(registerInfo->ownerMii, nfp_data.amiiboInternal.amiiboSettings.mii, sizeof(nfp_data.amiiboInternal.amiiboSettings.mii));\n\t\tmemcpy(registerInfo->nickname, nfp_data.amiiboInternal.amiiboSettings.nickname, sizeof(nfp_data.amiiboInternal.amiiboSettings.nickname));\n\t}\n\t\n\t// todo - missing fields\n\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_InitializeRegisterInfoSet(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"InitializeRegisterInfoSet(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamStructPtr(registerInfoSet, nfpRegisterInfoSet_t, 0);\n\n\tmemset(registerInfoSet, 0, sizeof(nfpRegisterInfoSet_t));\n\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_SetNfpRegisterInfo(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"SetNfpRegisterInfo(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamStructPtr(registerInfoSet, nfpRegisterInfoSet_t, 0);\n\n\tmemcpy(nfp_data.amiiboInternal.amiiboSettings.mii, registerInfoSet->ownerMii, sizeof(nfp_data.amiiboInternal.amiiboSettings.mii));\n\tmemcpy(nfp_data.amiiboInternal.amiiboSettings.nickname, registerInfoSet->nickname, sizeof(nfp_data.amiiboInternal.amiiboSettings.nickname));\n\t// todo - set register date and other values\n\tnfp_data.amiiboInternal.amiiboSettings.flags |= 0x10; // set registered bit\n\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_IsExistApplicationArea(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"IsExistApplicationArea()\");\n\tif (!nfp_data.hasActiveAmiibo || !nfp_data.isMounted)\n\t{\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\tbool appAreaExists = (nfp_data.amiiboInternal.amiiboSettings.flags & 0x20) != 0;\n\tosLib_returnFromFunction(hCPU, appAreaExists ? 1 : 0);\n}\n\nvoid nnNfpExport_OpenApplicationArea(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"OpenApplicationArea(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamU32(appAreaId, 0);\n\n\t// note - this API doesn't fail if the application area has already been opened?\n\n\tif (!(nfp_data.amiiboInternal.amiiboSettings.flags & 0x20))\n\t{\n\t\t// no application data set\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, NN_RESULT_NFP_CODE_NOAPPAREA));\n\t\treturn;\n\t}\n\n\tuint32 nfpAppAreaId = nfp_data.amiiboInternal.amiiboSettings.getAppDataAppId();\n\tif (nfpAppAreaId != appAreaId)\n\t{\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, NN_RESULT_NFP_CODE_APPAREAIDMISMATCH));\n\t\treturn;\n\t}\n\tnfp_data.hasOpenApplicationArea = true;\n\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_ReadApplicationArea(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"ReadApplicationArea(0x{:08x}, 0x{:x})\", hCPU->gpr[3], hCPU->gpr[4]);\n\tppcDefineParamPtr(bufferPtr, uint8*, 0);\n\tppcDefineParamU32(len, 1);\n\n\tif (!nfp_data.hasOpenApplicationArea)\n\t{\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\tlen = std::min(len, (uint32)sizeof(nfp_data.amiiboInternal.applicationData));\n\tmemcpy(bufferPtr, nfp_data.amiiboInternal.applicationData, len);\n\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_WriteApplicationArea(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"WriteApplicationArea(0x{:08x}, 0x{:x}, 0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\tppcDefineParamPtr(bufferPtr, uint8*, 0);\n\tppcDefineParamU32(len, 1);\n\t\n\tif (!nfp_data.hasOpenApplicationArea)\n\t{\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\tif (nfp_data.isReadOnly)\n\t{\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\n\tlen = std::min(len, (uint32)sizeof(nfp_data.amiiboInternal.applicationData));\n\tmemcpy(nfp_data.amiiboInternal.applicationData, bufferPtr, len);\n\t// remaining data is filled with random bytes\n\tfor (uint32 i = len; i < sizeof(nfp_data.amiiboInternal.applicationData); i++)\n\t\tnfp_data.amiiboInternal.applicationData[i] = rand() & 0xFF;\n\n\tnfp_data.amiiboInternal.amiiboSettings.appWriteCounter = nfp_data.amiiboInternal.amiiboSettings.appWriteCounter + 1;\n\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\ntypedef struct  \n{\n\tuint32be appAreaId;\n\tMEMPTR<uint8> initialData;\n\tuint32be initialLen;\n\t// more?\n}NfpCreateInfo_t;\n\nvoid nnNfpExport_CreateApplicationArea(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"CreateApplicationArea(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamPtr(createInfo, NfpCreateInfo_t, 0);\n\n\tif (nfp_data.hasOpenApplicationArea || (nfp_data.amiiboInternal.amiiboSettings.flags&0x20))\n\t{\n\t\t// cant create app area if it already exists\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\tif (nfp_data.isReadOnly)\n\t{\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\n\tvoid* writePtr = createInfo->initialData.GetPtr();\n\tuint32 writeSize = createInfo->initialLen;\n\tif (writeSize > sizeof(nfp_data.amiiboInternal.applicationData))\n\t{\n\t\t// requested write size larger than available space\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\n\tnfp_data.amiiboInternal.amiiboSettings.setAppDataAppId(createInfo->appAreaId);\n\tnfp_data.amiiboInternal.amiiboSettings.flags |= 0x20; // set application data exists bit\n\tnfp_data.amiiboInternal.amiiboSettings.appWriteCounter = nfp_data.amiiboInternal.amiiboSettings.appWriteCounter + 1;\n\n\tnfp_data.hasOpenApplicationArea = false;\n\n\t// write initial data to application area\n\tmemcpy(nfp_data.amiiboInternal.applicationData, writePtr, writeSize);\n\t// remaining data is filled with random bytes\n\tfor (uint32 i = writeSize; i < sizeof(nfp_data.amiiboInternal.applicationData); i++)\n\t\tnfp_data.amiiboInternal.applicationData[i] = rand() & 0xFF;\n\n\t// this API forces a flush (unsure, but without this data written by Smash doesn't stick)\n\tif (!nnNfp_writeCurrentAmiibo())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to write Amiibo file data when trying to remove appArea\");\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_DeleteApplicationArea(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"DeleteApplicationArea()\");\n\n\tif (nfp_data.isReadOnly)\n\t{\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\tif ((nfp_data.amiiboInternal.amiiboSettings.flags & 0x20) == 0)\n\t{\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\n\tnfp_data.amiiboInternal.amiiboSettings.setAppDataAppId(0);\n\tnfp_data.amiiboInternal.amiiboSettings.flags &= ~0x20;\n\tnfp_data.amiiboInternal.amiiboSettings.appWriteCounter = nfp_data.amiiboInternal.amiiboSettings.appWriteCounter + 1;\n\n\t// this API forces a flush\n\tif (!nnNfp_writeCurrentAmiibo())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to write Amiibo file data when trying to remove appArea\");\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfpExport_Flush(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"Flush()\");\n\n\t// write Amiibo data\n\tif (nfp_data.isReadOnly) \n\t{\n\t\tcemuLog_log(LogType::Force, \"Cannot write to Amiibo when it is mounted in read-only mode\");\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\n\tif (!nnNfp_writeCurrentAmiibo())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to write Amiibo data\");\n\t\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_NFP, 0));\n\t\treturn;\n\t}\n\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\ntypedef struct  \n{\n\t/* +0x000 */ uint8 ukn00[0x10];\n\t/* +0x010 */ uint32be mode;\n\t/* +0x014 */ uint8 tagInfo[0x54];\n\t/* +0x068 */ uint8 isRegistered; // could be uint32be?\n\t/* +0x069 */ uint8 _padding69[3];\n\t/* +0x06C */ uint8 registerInfo[0xA8];\n\t/* +0x114 */ uint8 commonInfo[0x40];\n\t/* +0x154 */ uint8 ukn154[0x20];\n}AmiiboSettingsArgs_t;\n\nstatic_assert(sizeof(AmiiboSettingsArgs_t) == 0x174);\nstatic_assert(offsetof(AmiiboSettingsArgs_t, mode) == 0x10);\nstatic_assert(offsetof(AmiiboSettingsArgs_t, tagInfo) == 0x14);\nstatic_assert(offsetof(AmiiboSettingsArgs_t, isRegistered) == 0x68);\nstatic_assert(offsetof(AmiiboSettingsArgs_t, registerInfo) == 0x6C);\nstatic_assert(offsetof(AmiiboSettingsArgs_t, commonInfo) == 0x114);\n\nvoid nnNfpExport_GetAmiiboSettingsArgs(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"GetAmiiboSettingsArgs(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamStructPtr(settingsArg, AmiiboSettingsArgs_t, 0);\n\n\tmemset(settingsArg, 0, sizeof(AmiiboSettingsArgs_t));\n\n\t// modes:\n\t// 0 -> Register owner and nickname\n\t// 0x64 -> Launch normally\n\n\tsettingsArg->mode = 0x64;\n\n\tosLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0));\n}\n\nvoid nnNfp_unloadAmiibo()\n{\n\tnnNfpLock();\n\tnfp_data.isMounted = false;\n\tnfp_data.hasActiveAmiibo = false;\n\tnnNfpUnlock();\n}\n\nbool nnNfp_isInitialized()\n{\n\treturn nfp_data.nfpIsInitialized;\n}\n\n// CEMU NFC error codes\n#define NFC_ERROR_NONE\t\t\t\t\t(0)\n#define NFC_ERROR_NO_ACCESS\t\t\t\t(1)\n#define NFC_ERROR_INVALID_FILE_FORMAT\t(2)\n\nbool nnNfp_touchNfcTagFromFile(const fs::path& filePath, uint32* nfcError)\n{\n\tAmiiboRawNFCData rawData = { 0 };\n\tauto nfcData = FileStream::LoadIntoMemory(filePath);\n\tif (!nfcData)\n\t{\n\t\t*nfcError = NFC_ERROR_NO_ACCESS;\n\t\treturn false;\n\t}\n\tif (nfcData->size() < sizeof(AmiiboRawNFCData))\n\t{\n\t\t*nfcError = NFC_ERROR_INVALID_FILE_FORMAT;\n\t\treturn false;\n\t}\n\tmemcpy(&rawData, nfcData->data(), sizeof(AmiiboRawNFCData));\n\n\t// verify if the file is a valid ntag215/amiibo file\n\tif (rawData.dynamicLock[0] != 0x01 || rawData.dynamicLock[1] != 0x00 || rawData.dynamicLock[2] != 0x0F || rawData.dynamicLock[3] != 0xBD)\n\t{\n\t\t// Temporary workaround to fix corrupted files by old cemu versions\n\t\trawData.dynamicLock[0] = 0x01;\n\t\trawData.dynamicLock[1] = 0x00;\n\t\trawData.dynamicLock[2] = 0x0F;\n\t\trawData.dynamicLock[3] = 0xBD;\n\n\t\t// *nfcError = NFC_ERROR_INVALID_FILE_FORMAT;\n\t\t// return false;\n\t}\n\tif (rawData.cfg0[0] != 0x00 || rawData.cfg0[1] != 0x00 || rawData.cfg0[2] != 0x00 || rawData.cfg0[3] != 0x04)\n\t{\n\t\t*nfcError = NFC_ERROR_INVALID_FILE_FORMAT;\n\t\treturn false;\n\t}\n\tif (rawData.cfg1[0] != 0x5F || rawData.cfg1[1] != 0x00 || rawData.cfg1[2] != 0x00 || rawData.cfg1[3] != 0x00)\n\t{\n\t\t*nfcError = NFC_ERROR_INVALID_FILE_FORMAT;\n\t\treturn false;\n\t}\n\tif (rawData.staticLock[0] != 0x0F || rawData.staticLock[1] != 0xE0)\n\t{\n\t\t*nfcError = NFC_ERROR_INVALID_FILE_FORMAT;\n\t\treturn false;\n\t}\n\tif (rawData.cc[0] != 0xF1 || rawData.cc[1] != 0x10 || rawData.cc[2] != 0xFF || rawData.cc[3] != 0xEE)\n\t{\n\t\t*nfcError = NFC_ERROR_INVALID_FILE_FORMAT;\n\t\treturn false;\n\t}\n\n\t// process uid\n\tuint8 serialNumber[7];\n\tserialNumber[0] = rawData.ntagSerial[0];\n\tserialNumber[1] = rawData.ntagSerial[1];\n\tserialNumber[2] = rawData.ntagSerial[2];\n\tserialNumber[3] = rawData.ntagSerial[4];\n\tserialNumber[4] = rawData.ntagSerial[5];\n\tserialNumber[5] = rawData.ntagSerial[6];\n\tserialNumber[6] = rawData.nintendoId;\n\n\tuint8 serialCheckByte0 = rawData.ntagSerial[3];\n\tuint8 serialCheckByte1 = rawData.lockBytes[0];\n\n\tuint8 bcc0 = serialNumber[0] ^ serialNumber[1] ^ serialNumber[2] ^ 0x88;\n\tuint8 bcc1 = serialNumber[3] ^ serialNumber[4] ^ serialNumber[5] ^ serialNumber[6];\n\n\tif (serialCheckByte0 != bcc0 || serialCheckByte1 != bcc1)\n\t{\n\t\tcemuLog_log(LogType::Force, \"nn_nfp: Mismatch in serial checksum of scanned NFC tag\");\n\t}\n\tnfp_data.amiiboProcessedData.uidLength = 7;\n\tmemcpy(nfp_data.amiiboProcessedData.uid, serialNumber, 7);\n\t// signal activation event\n\tnnNfp_unloadAmiibo();\n\tnnNfpLock();\n\tmemcpy(&nfp_data.amiiboNFCData, &rawData, sizeof(AmiiboRawNFCData));\n\t// decrypt amiibo\n\tamiiboDecrypt();\n\tnfp_data.amiiboPath = filePath;\n\tnfp_data.hasActiveAmiibo = true;\n\tif (nfp_data.activateEvent)\n\t{\n\t\tMEMPTR<coreinit::OSEvent> osEvent(nfp_data.activateEvent);\n\t\tcoreinit::OSSignalEvent(osEvent);\n\t}\n\tnfp_data.amiiboTouchTime = GetTickCount();\n\tnnNfpUnlock();\n\t*nfcError = NFC_ERROR_NO_ACCESS;\n\treturn true;\n}\n\nbool nnNfp_writeCurrentAmiibo()\n{\n\tnnNfpLock();\n\tif (!nfp_data.hasActiveAmiibo)\n\t{\n\t\tnnNfpUnlock();\n\t\treturn false;\n\t}\n\n\tuint16 writeCounter = nfp_data.amiiboInternal.writeCounterLow + (nfp_data.amiiboInternal.writeCounterHigh << 8);\n\twriteCounter++;\n\tnfp_data.amiiboInternal.writeCounterLow = writeCounter & 0xFF;\n\tnfp_data.amiiboInternal.writeCounterHigh = (writeCounter >> 8) & 0xFF;\n\n\t// open file for writing\n\tFileStream* fs = FileStream::openFile2(nfp_data.amiiboPath, true);\n\tif (!fs)\n\t{\n\t\tnnNfpUnlock();\n\t\treturn false;\n\t}\n\t// encrypt Amiibo and convert to NFC format\n\tAmiiboRawNFCData nfcData;\n\tamiiboEncrypt(&nfcData);\n\t// write to file\n\tfs->writeData(&nfcData, sizeof(AmiiboRawNFCData));\n\tdelete fs;\n\n\tnnNfpUnlock();\n\treturn true;\n}\n\nvoid nnNfp_update()\n{\n\t// lock-free check if amiibo is touching\n\tif (nfp_data.hasActiveAmiibo == false)\n\t\treturn;\n\tif (!nnNfpTryLock())\n\t\treturn;\n\t// make sure amiibo is still touching after acquiring lock\n\tif (nfp_data.hasActiveAmiibo == false)\n\t\treturn;\n\tuint32 amiiboElapsedTouchTime = GetTickCount() - nfp_data.amiiboTouchTime;\n\tif (amiiboElapsedTouchTime >= 1500)\n\t{\n\t\tnnNfp_unloadAmiibo();\n\t\tif (nfp_data.deactivateEvent)\n\t\t{\n\t\t\tcoreinit::OSEvent* osEvent = (coreinit::OSEvent*)memory_getPointerFromVirtualOffset(nfp_data.deactivateEvent);\n\t\t\tcoreinit::OSSignalEvent(osEvent);\n\t\t}\n\t}\n\tnnNfpUnlock();\n}\n\nvoid nnNfpExport_GetNfpState(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::NN_NFP, \"GetNfpState()\");\n\n\t// workaround for Mario Party 10 eating CPU cycles in an infinite loop (maybe due to incorrect NFP detection handling?)\n\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\tif (titleId == 0x0005000010162d00 || titleId == 0x0005000010162e00)\n\t{\n\t\tcoreinit::OSSleepTicks(ESPRESSO_CORE_CLOCK / 100); // pause for 10ms\n\t}\n\n\tuint32 nfpState;\n\tif (nfp_data.nfpIsInitialized == false)\n\t{\n\t\tnfpState = NFP_STATE_NONE;\n\t}\n\telse\n\t{\n\t\tif (nfp_data.isMounted && nfp_data.hasActiveAmiibo)\n\t\t{\n\t\t\tif (nfp_data.isReadOnly)\n\t\t\t\tnfpState = NFP_STATE_RW_MOUNT_ROM;\n\t\t\telse\n\t\t\t\tnfpState = NFP_STATE_RW_MOUNT;\n\t\t}\n\t\telse if (nfp_data.isDetecting)\n\t\t{\n\t\t\t// todo: is this handled correctly?\n\t\t\tif (nfp_data.hasActiveAmiibo)\n\t\t\t{\n\t\t\t\tnfpState = NFP_STATE_RW_ACTIVE;\n\t\t\t}\n\t\t\telse\n\t\t\t\tnfpState = NFP_STATE_RW_SEARCH;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnfpState = NFP_STATE_INIT;\n\t\t}\n\t}\n\t// returns state of nfp library\n\tosLib_returnFromFunction(hCPU, nfpState);\n}\n\nnamespace nn::nfp\n{\n\ttypedef struct  \n\t{\n\t\t/* +0x00 */ uint8 uidLength;\n\t\t/* +0x01 */ uint8 uid[0xA];\n\t\t/* +0x0B */ uint8 ukn0B;\n\t\t/* +0x0C */ uint8 ukn0C;\n\t\t/* +0x0D */ uint8 ukn0D;\n\t\t// more?\n\t}NFCTagInfoCallbackParam_t;\n\n\tuint32 NFCGetTagInfo(uint32 index, uint32 timeout, MPTR functionPtr, void* userParam)\n\t{\n\t\tcemuLog_log(LogType::NN_NFP, \"NFCGetTagInfo({},{},0x{:08x},0x{:08x})\", index, timeout, functionPtr, userParam ? memory_getVirtualOffsetFromPointer(userParam) : 0);\n\n\n\t\tcemu_assert(index == 0);\n\n\t\tnnNfpLock();\n\n\t\tStackAllocator<NFCTagInfoCallbackParam_t> _callbackParam;\n\t\tNFCTagInfoCallbackParam_t* callbackParam = _callbackParam.GetPointer();\n\n\t\tmemset(callbackParam, 0x00, sizeof(NFCTagInfoCallbackParam_t));\n\n\t\tmemcpy(callbackParam->uid, nfp_data.amiiboProcessedData.uid, nfp_data.amiiboProcessedData.uidLength);\n\t\tcallbackParam->uidLength = (uint8)nfp_data.amiiboProcessedData.uidLength;\n\n\t\tPPCCoreCallback(functionPtr, index, 0, _callbackParam.GetPointer(), userParam);\n\n\t\tnnNfpUnlock();\n\n\n\t\treturn 0; // 0 -> success\n\t}\n\n\tuint32 GetErrorCode(uint32 result)\n\t{\n\t\tuint32 level = (result >> 0x1b) & 3;\n\t\tuint32 mask = 0x7f00000;\n\t\tif (level != 3) \n\t\t{\n\t\t\tmask = 0x1ff00000;\n\t\t}\n\t\tif (((result & mask) == 0x1b00000) && ((result & 0x80000000) != 0)) \n\t\t{\n\t\t\tmask = 0x3ff;\n\t\t\tif (level != 3) \n\t\t\t{\n\t\t\t\tmask = 0xfffff;\n\t\t\t}\n\t\t\treturn ((result & mask) >> 7) + 1680000;\n\t\t}\n\t\treturn 1680000;\n\t}\n\n\tvoid nnNfp_load()\n\t{\n\t\tosLib_addFunction(\"nn_nfp\", \"SetActivateEvent__Q2_2nn3nfpFP7OSEvent\", nnNfpExport_SetActivateEvent);\n\t\tosLib_addFunction(\"nn_nfp\", \"SetDeactivateEvent__Q2_2nn3nfpFP7OSEvent\", nnNfpExport_SetDeactivateEvent);\n\t\tosLib_addFunction(\"nn_nfp\", \"StartDetection__Q2_2nn3nfpFv\", nnNfpExport_StartDetection);\n\t\tosLib_addFunction(\"nn_nfp\", \"StopDetection__Q2_2nn3nfpFv\", nnNfpExport_StopDetection);\n\n\t\tosLib_addFunction(\"nn_nfp\", \"GetTagInfo__Q2_2nn3nfpFPQ3_2nn3nfp7TagInfo\", nnNfpExport_GetTagInfo);\n\t\tosLib_addFunction(\"nn_nfp\", \"Mount__Q2_2nn3nfpFv\", nnNfpExport_Mount);\n\t\tosLib_addFunction(\"nn_nfp\", \"MountRom__Q2_2nn3nfpFv\", nnNfpExport_MountRom);\n\t\tosLib_addFunction(\"nn_nfp\", \"Unmount__Q2_2nn3nfpFv\", nnNfpExport_Unmount);\n\t\tosLib_addFunction(\"nn_nfp\", \"GetNfpCommonInfo__Q2_2nn3nfpFPQ3_2nn3nfp10CommonInfo\", nnNfpExport_GetNfpCommonInfo);\n\t\tosLib_addFunction(\"nn_nfp\", \"GetNfpRegisterInfo__Q2_2nn3nfpFPQ3_2nn3nfp12RegisterInfo\", nnNfpExport_GetNfpRegisterInfo);\n\n\t\tosLib_addFunction(\"nn_nfp\", \"InitializeRegisterInfoSet__Q2_2nn3nfpFPQ3_2nn3nfp15RegisterInfoSet\", nnNfpExport_InitializeRegisterInfoSet);\n\t\tosLib_addFunction(\"nn_nfp\", \"SetNfpRegisterInfo__Q2_2nn3nfpFRCQ3_2nn3nfp15RegisterInfoSet\", nnNfpExport_SetNfpRegisterInfo);\n\n\t\tosLib_addFunction(\"nn_nfp\", \"IsExistApplicationArea__Q2_2nn3nfpFv\", nnNfpExport_IsExistApplicationArea);\n\t\tosLib_addFunction(\"nn_nfp\", \"OpenApplicationArea__Q2_2nn3nfpFUi\", nnNfpExport_OpenApplicationArea);\n\t\tosLib_addFunction(\"nn_nfp\", \"CreateApplicationArea__Q2_2nn3nfpFRCQ3_2nn3nfp25ApplicationAreaCreateInfo\", nnNfpExport_CreateApplicationArea);\n\t\tosLib_addFunction(\"nn_nfp\", \"DeleteApplicationArea__Q2_2nn3nfpFv\", nnNfpExport_DeleteApplicationArea);\n\t\tosLib_addFunction(\"nn_nfp\", \"ReadApplicationArea__Q2_2nn3nfpFPvUi\", nnNfpExport_ReadApplicationArea);\n\t\tosLib_addFunction(\"nn_nfp\", \"WriteApplicationArea__Q2_2nn3nfpFPCvUiRCQ3_2nn3nfp5TagId\", nnNfpExport_WriteApplicationArea);\n\n\t\tosLib_addFunction(\"nn_nfp\", \"Flush__Q2_2nn3nfpFv\", nnNfpExport_Flush);\n\n\t\tosLib_addFunction(\"nn_nfp\", \"Initialize__Q2_2nn3nfpFv\", nnNfpExport_Initialize);\n\t\tosLib_addFunction(\"nn_nfp\", \"GetNfpState__Q2_2nn3nfpFv\", nnNfpExport_GetNfpState);\n\n\t\tosLib_addFunction(\"nn_nfp\", \"GetAmiiboSettingsArgs__Q2_2nn3nfpFPQ3_2nn3nfp18AmiiboSettingsArgs\", nnNfpExport_GetAmiiboSettingsArgs);\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_nfp\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tnnNfp_load(); // legacy interface, update these to use cafeExportRegister / cafeExportRegisterFunc\n\n\t\t\tcafeExportRegisterFunc(nn::nfp::GetErrorCode, \"nn_nfp\", \"GetErrorCode__Q2_2nn3nfpFRCQ2_2nn6Result\", LogType::NN_NFP);\n\t\t\tcafeExportRegisterFunc(nn::nfp::GetNfpRomInfo, \"nn_nfp\", \"GetNfpRomInfo__Q2_2nn3nfpFPQ3_2nn3nfp7RomInfo\", LogType::NN_NFP);\n\t\t\tcafeExportRegisterFunc(nn::nfp::GetNfpReadOnlyInfo, \"nn_nfp\", \"GetNfpReadOnlyInfo__Q2_2nn3nfpFPQ3_2nn3nfp12ReadOnlyInfo\", LogType::NN_NFP);\n\t\t};\n\n\t}s_COSnnNfpModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnNfpModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_nfp/nn_nfp.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::nfp\n{\n\tuint32 NFCGetTagInfo(uint32 index, uint32 timeout, MPTR functionPtr, void* userParam);\n\n\tCOSModule* GetModule();\n}\n\nvoid nnNfp_load();\nvoid nnNfp_update();\n\nbool nnNfp_isInitialized();\nbool nnNfp_touchNfcTagFromFile(const fs::path& filePath, uint32* nfcError);\n\n#define NFP_STATE_NONE\t\t\t(0)\n#define NFP_STATE_INIT\t\t\t(1)\n#define NFP_STATE_RW_SEARCH\t\t(2)\n#define NFP_STATE_RW_ACTIVE\t\t(3)\n#define NFP_STATE_RW_DEACTIVE\t(4)\n#define NFP_STATE_RW_MOUNT\t\t(5)\n#define NFP_STATE_UNEXPECTED\t(6)\n#define NFP_STATE_RW_MOUNT_ROM\t(7)\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_nim/nn_nim.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/IOSU/legacy/iosu_ioctl.h\"\n#include \"Cafe/IOSU/legacy/iosu_nim.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IOS.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n\n#define nimPrepareRequest() \\\nStackAllocator<iosu::nim::iosuNimCemuRequest_t> _buf_nimRequest; \\\nStackAllocator<ioBufferVector_t> _buf_bufferVector; \\\niosu::nim::iosuNimCemuRequest_t* nimRequest = _buf_nimRequest.GetPointer(); \\\nioBufferVector_t* nimBufferVector = _buf_bufferVector.GetPointer(); \\\nmemset(nimRequest, 0, sizeof(iosu::nim::iosuNimCemuRequest_t)); \\\nmemset(nimBufferVector, 0, sizeof(ioBufferVector_t)); \\\nnimBufferVector->buffer = (uint8*)nimRequest;\n\nnamespace nn\n{\n\tnamespace nim\n\t{\n\n\t\tvoid export_NeedsNetworkUpdate(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"NeedsNetworkUpdate() - placeholder\");\n\t\t\tppcDefineParamTypePtr(needsUpdate, uint8, 0);\n\n\t\t\t*needsUpdate = 0;\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\ttypedef struct  \n\t\t{\n\t\t\tuint32be ukn00;\n\t\t\tuint32be ukn04;\n\t\t\tuint32be ukn08;\n\t\t\tuint32be ukn0C;\n\t\t\tuint32be ukn10;\n\t\t\tuint32be ukn14;\n\t\t\tuint32be ukn18;\n\t\t}updatePackageProgress_t;\n\n\t\tvoid export_GetUpdatePackageProgress(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"GetUpdatePackageProgress() - placeholder\");\n\t\t\tppcDefineParamTypePtr(updatePackageProgress, updatePackageProgress_t, 0);\n\t\t\t// status of system update download\n\t\t\t// values are unknown\n\t\t\tupdatePackageProgress->ukn00 = 0;\n\t\t\tupdatePackageProgress->ukn04 = 0;\n\t\t\tupdatePackageProgress->ukn18 = 0;\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\tvoid export_NeedsNotifyToUsers(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"NeedsNotifyToUsers() - placeholder\");\n\t\t\tppcDefineParamTypePtr(updatePackageProgress, updatePackageProgress_t, 0);\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\tvoid export_GetNumTitlePackages(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tnimPrepareRequest();\n\n\t\t\tnimRequest->requestCode = IOSU_NIM_GET_PACKAGE_COUNT;\n\n\t\t\t__depr__IOS_Ioctlv(IOS_DEVICE_NIM, IOSU_NIM_REQUEST_CEMU, 1, 1, nimBufferVector);\n\n\t\t\tuint32 numTitlePackages = nimRequest->resultU32.u32;\n\n\t\t\tosLib_returnFromFunction(hCPU, numTitlePackages);\n\t\t}\n\n\t\tstatic_assert(sizeof(iosu::nim::titlePackageInfo_t) == 0x50, \"titlePackageInfo_t has invalid size\");\n\t\tstatic_assert(offsetof(iosu::nim::titlePackageInfo_t, ukn28DLProgressRelatedMax_u64be) == 0x28, \"ukn28_u64be has invalid offset\");\n\n\t\tvoid export_ListTitlePackagesStatically(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"ListTitlePackagesStatically() - placeholder\");\n\t\t\tppcDefineParamTypePtr(titleIdList, uint64, 0);\n\t\t\tppcDefineParamS32(maxCount, 1);\n\n\t\t\tnimPrepareRequest();\n\t\t\t\n\t\t\tnimRequest->requestCode = IOSU_NIM_GET_PACKAGES_TITLEID;\n\t\t\tnimRequest->maxCount = maxCount;\n\t\t\tnimRequest->ptr = (uint8*)(titleIdList);\n\n\t\t\t__depr__IOS_Ioctlv(IOS_DEVICE_NIM, IOSU_NIM_REQUEST_CEMU, 1, 1, nimBufferVector);\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\tvoid export_GetTitlePackageInfos(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"GetTitlePackageInfos() - placeholder\");\n\t\t\tppcDefineParamTypePtr(titlePackageInfo, iosu::nim::titlePackageInfo_t, 0);\n\t\t\tppcDefineParamTypePtr(titleIdList, uint64, 1);\n\t\t\tppcDefineParamU32(count, 2);\n\n\t\t\tnimPrepareRequest();\n\n\t\t\tnimRequest->requestCode = IOSU_NIM_GET_PACKAGES_INFO;\n\t\t\tnimRequest->maxCount = count;\n\t\t\tnimRequest->ptr = (uint8*)(titleIdList);\n\t\t\tnimRequest->ptr2 = (uint8*)(titlePackageInfo);\n\n\t\t\t__depr__IOS_Ioctlv(IOS_DEVICE_NIM, IOSU_NIM_REQUEST_CEMU, 1, 1, nimBufferVector);\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\tvoid export_NeedsNotifyToUsersTitlePackage(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"NeedsNotifyToUsers() - placeholder\");\n\t\t\tppcDefineParamTypePtr(titlePackageInfo, iosu::nim::titlePackageInfo_t, 0);\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\tusing IDBE_DATA = uint8[0x12060];\n\n\t\tvoid export_GetIconDatabaseEntries(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"GetIconDatabaseEntries() - placeholder\");\n\t\t\tppcDefineParamTypePtr(iconDatabaseEntries, IDBE_DATA, 0);\n\t\t\tppcDefineParamTypePtr(titleIdList, uint64, 1);\n\t\t\tppcDefineParamS32(count, 2);\n\n\t\t\tcemu_assert_debug(count == 1); // other count values are untested\n\n\t\t\tfor (sint32 i = 0; i < count; i++)\n\t\t\t{\n\t\t\t\tnimPrepareRequest();\n\n\t\t\t\tnimRequest->requestCode = IOSU_NIM_GET_ICON_DATABASE_ENTRY;\n\t\t\t\tnimRequest->titleId = _swapEndianU64(titleIdList[i]);\n\t\t\t\tnimRequest->ptr = (uint8*)(iconDatabaseEntries + i);\n\n\t\t\t\t__depr__IOS_Ioctlv(IOS_DEVICE_NIM, IOSU_NIM_REQUEST_CEMU, 1, 1, nimBufferVector);\n\n\t\t\t}\n\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\tvoid export_QuerySchedulerStatus(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"QuerySchedulerStatus() - placeholder\");\n\n\t\t\t// scheduler status seems to be either a 4 byte array or 8 byte array (or structs)?\n\t\t\t// scope.rpx only checks the second byte and if it matches 0x01 then the scheduler is considered paused/stopped (displays that downloads are inactive)\n\t\t\t// men.rpx checks the first byte for == 1 and if true, it will show the download manager icon as downloading\n\n\t\t\t// downloads disabled:\n\t\t\t//memory_writeU32(hCPU->gpr[3], (0x00010000));\n\t\t\t// downloads enabled:\n\t\t\tmemory_writeU32(hCPU->gpr[3], (0x00000000));\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\tstruct nimResultError\n\t\t{\n\t\t\tuint32be iosError;\n\t\t\tuint32be ukn04;\n\t\t};\n\n\t\tvoid ConstructResultError(nimResultError* resultError, uint32be* nimErrorCodePtr, uint32 uknParam)\n\t\t{\n\t\t\tuint32 nnResultCode = *nimErrorCodePtr;\n\t\t\tresultError->iosError = nnResultCode;\n\t\t\tresultError->ukn04 = uknParam;\n\n\t\t\tif (nnResultCode == 0xFFFFFFFF)\n\t\t\t{\n\t\t\t\t// not a valid code, used by a Wii U menu\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// IOS errors need to be translated\n\t\t\tif ( (nnResultCode&0x18000000) == 0x18000000)\n\t\t\t{\n\t\t\t\t// alternative error format\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tauto moduleId = nn::nnResult_GetModule(nnResultCode);\n\t\t\t\tif (moduleId == NN_RESULT_MODULE_NN_IOS)\n\t\t\t\t{\n\t\t\t\t\t// ios error\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// other error\n\t\t\t\t\tresultError->iosError = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid export_GetECommerceInfrastructureCountry(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tppcDefineParamU32BEPtr(country, 0);\n\n\t\t\tcemuLog_logDebug(LogType::Force, \"GetECommerceInfrastructureCountry - todo\");\n\n\t\t\t*country = 0;\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\ttypedef struct\n\t\t{\n\t\t\tbetype<uint32> titleIdHigh;\n\t\t\tbetype<uint32> titleIdLow;\n\t\t\tuint32 regionOrLanguageRelated;\n\t\t\tuint8 uknByte0C;\n\t\t\tuint8 applicationBoxDevice1; // this is what E-Shop app reads to determine device (0 -> mlc, 1 -> extern storage?)\n\t\t\tuint8 uknByte0E;\n\t\t\tuint8 applicationBoxDevice2;\n\t\t\tuint32 ukn10;\n\t\t\tuint8 uknByte14; // set to 0\n\t\t\tuint8 uknByte15; // set to 1\n\t\t\tuint8 postDownloadAction; // 0 -> ?, 1 -> ?, 2 -> Use bg install policy\n\t\t\tuint8 uknBytes17;\n\t\t}TitlePackageTaskConfig_t;\n\n\t\tstatic_assert(sizeof(TitlePackageTaskConfig_t) == 0x18, \"\");\n\n\t\tvoid export_MakeTitlePackageTaskConfigAutoUsingBgInstallPolicy(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tppcDefineParamPtr(titlePackageTastConfig, TitlePackageTaskConfig_t, 0);\n\t\t\tppcDefineParamU64(titleId, 2);\n\t\t\tppcDefineParamU32(regionOrLanguage, 4);\n\t\t\tppcDefineParamU32(uknR8, 5); // title type?\n\n\t\t\tcemuLog_logDebug(LogType::Force, \"MakeTitlePackageTaskConfigAutoUsingBgInstallPolicy - placeholder\");\n\n\t\t\ttitlePackageTastConfig->titleIdHigh = (uint32)(titleId >> 32);\n\t\t\ttitlePackageTastConfig->titleIdLow = (uint32)(titleId & 0xFFFFFFFF);\n\t\t\ttitlePackageTastConfig->regionOrLanguageRelated = 0; // ?\n\t\t\ttitlePackageTastConfig->uknByte0C = uknR8;\n\t\t\ttitlePackageTastConfig->applicationBoxDevice1 = 1; // 1 -> mlc\n\t\t\ttitlePackageTastConfig->applicationBoxDevice2 = 1; // 1 -> mlc\n\n\t\t\ttitlePackageTastConfig->uknByte0E = 0; // ?\n\t\t\ttitlePackageTastConfig->ukn10 = 0; // ?\n\t\t\ttitlePackageTastConfig->uknByte14 = 0; // ?\n\t\t\ttitlePackageTastConfig->uknByte15 = 1; // ?\n\n\t\t\ttitlePackageTastConfig->postDownloadAction = 0; // ?\n\n\t\t\ttitlePackageTastConfig->uknBytes17 = 0; // ?\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\tvoid export_CalculateTitleInstallSize(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tppcDefineParamTypePtr(installSize, betype<uint64>, 0);\n\t\t\tppcDefineParamPtr(titlePackageTastConfig, TitlePackageTaskConfig_t, 1);\n\n\t\t\t// get install size of currently installed title, otherwise return -1 as size\n\t\t\tcemuLog_logDebug(LogType::Force, \"CalculateTitleInstallSize - todo\");\n\n\t\t\t*installSize = 0xFFFFFFFFFFFFFFFF;\n\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t}\n\n\t\tclass : public COSModule\n\t\t{\n\t\t\tpublic:\n\t\t\tstd::string_view GetName() override\n\t\t\t{\n\t\t\t\treturn \"nn_nim\";\n\t\t\t}\n\n\t\t\tvoid RPLMapped() override\n\t\t\t{\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"NeedsNetworkUpdate__Q2_2nn3nimFPb\", export_NeedsNetworkUpdate);\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"GetUpdatePackageProgress__Q2_2nn3nimFPQ3_2nn3nim21UpdatePackageProgress\", export_GetUpdatePackageProgress);\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"NeedsNotifyToUsers__Q3_2nn3nim4utilFPCQ3_2nn3nim21UpdatePackageProgress\", export_NeedsNotifyToUsers);\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"GetNumTitlePackages__Q2_2nn3nimFv\", export_GetNumTitlePackages);\n\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"GetTitlePackageInfos__Q2_2nn3nimFPQ3_2nn3nim16TitlePackageInfoPCULUi\", export_GetTitlePackageInfos);\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"NeedsNotifyToUsers__Q3_2nn3nim4utilFPCQ3_2nn3nim16TitlePackageInfoPCQ3_2nn3nim11ResultError\", export_NeedsNotifyToUsersTitlePackage);\n\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"ListTitlePackagesStatically__Q2_2nn3nimFPULUi\", export_ListTitlePackagesStatically);\n\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"GetECommerceInfrastructureCountry__Q2_2nn3nimFPQ3_2nn3nim7Country\", export_GetECommerceInfrastructureCountry);\n\n\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"QuerySchedulerStatus__Q2_2nn3nimFPQ3_2nn3nim15SchedulerStatus\", export_QuerySchedulerStatus);\n\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"GetIconDatabaseEntries__Q2_2nn3nimFPQ3_2nn3nim17IconDatabaseEntryPCULUi\", export_GetIconDatabaseEntries);\n\n\t\t\t\tcafeExportRegisterFunc(ConstructResultError, \"nn_nim\", \"Construct__Q3_2nn3nim11ResultErrorFQ2_2nn6Resulti\", LogType::Placeholder);\n\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"MakeTitlePackageTaskConfigAutoUsingBgInstallPolicy__Q3_2nn3nim4utilFULiQ3_2nn4Cafe9TitleType\", export_MakeTitlePackageTaskConfigAutoUsingBgInstallPolicy);\n\t\t\t\tosLib_addFunction(\"nn_nim\", \"CalculateTitleInstallSize__Q2_2nn3nimFPLRCQ3_2nn3nim22TitlePackageTaskConfigPCUsUi\", export_CalculateTitleInstallSize);\n\t\t\t};\n\n\t\t}s_COSnnNimModule;\n\n\t\tCOSModule* GetModule()\n\t\t{\n\t\t\treturn &s_COSnnNimModule;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_nim/nn_nim.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn\n{\n\tnamespace nim\n\t{\n\t\tCOSModule* GetModule();\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv.cpp",
    "content": "#include \"nn_olv.h\"\n\n#include \"nn_olv_InitializeTypes.h\"\n#include \"nn_olv_UploadCommunityTypes.h\"\n#include \"nn_olv_DownloadCommunityTypes.h\"\n#include \"nn_olv_UploadFavoriteTypes.h\"\n#include \"nn_olv_PostTypes.h\"\n#include \"nn_olv_OfflineDB.h\"\n\n#include \"Cafe/OS/libs/proc_ui/proc_ui.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Misc.h\"\n\nnamespace nn\n{\n\tnamespace olv\n\t{\n\t\tstatic SysAllocator<OSThread_t> s_OlvReleaseBgThread;\n\t\tSysAllocator<uint8, 1024> s_OlvReleaseBgThreadStack;\n\t\tSysAllocator<char, 32> s_OlvReleaseBgThreadName;\n\n\t\tvoid StubPostAppReleaseBackground(PPCInterpreter_t* hCPU)\n\t\t{\n\t\t\tcoreinit::OSSleepTicks(ESPRESSO_TIMER_CLOCK * 2); // Sleep 2s\n\t\t\tcoreinit::StartBackgroundForegroundTransition();\n\t\t}\n\n\t\tsint32 StubPostApp(void* pAnyPostParam)\n\t\t{\n\t\t\tcoreinit::OSCreateThreadType(s_OlvReleaseBgThread.GetPtr(), RPLLoader_MakePPCCallable(StubPostAppReleaseBackground), 0, nullptr, s_OlvReleaseBgThreadStack.GetPtr() + s_OlvReleaseBgThreadStack.GetByteSize(), (sint32)s_OlvReleaseBgThreadStack.GetByteSize(), 0, (1 << 1) | (1 << 3), OSThread_t::THREAD_TYPE::TYPE_APP);\n\t\t\tcoreinit::OSResumeThread(s_OlvReleaseBgThread.GetPtr());\n\t\t\tstrcpy(s_OlvReleaseBgThreadName.GetPtr(), \"StubPostApp!\");\n\t\t\tcoreinit::OSSetThreadName(s_OlvReleaseBgThread.GetPtr(),s_OlvReleaseBgThreadName.GetPtr());\n\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t}\n\n\t\tsint32 StubPostAppResult()\n\t\t{\n\t\t\treturn OLV_RESULT_STATUS(301); // Cancelled post app\n\t\t}\n\n\t\t// Somehow required, MK8 doesn't even seem to care about the error codes lol\n\t\tchar* UploadedPostData_GetPostId(char* pPostData)\n\t\t{\n\t\t\tpPostData[4] = '\\0';\n\t\t\treturn &pPostData[4];\n\t\t}\n\n\t\t// https://github.com/kinnay/NintendoClients/wiki/Wii-U-Error-Codes#act-error-codes\n\t\tconstexpr uint32 GetErrorCodeImpl(uint32 in)\n\t\t{\n\t\t\tuint32_t errorCode = in;\n\t\t\tuint32_t errorVersion = (errorCode >> 27) & 3;\n\t\t\tuint32_t errorModuleMask = (errorVersion != 3) ? 0x1FF00000 : 0x7F00000;\n\t\t\tbool isCodeFailure = errorCode & 0x80000000;\n\n\t\t\tif (((errorCode & errorModuleMask) >> 20) == NN_RESULT_MODULE_NN_ACT)\n\t\t\t{\n\t\t\t\t// BANNED_ACCOUNT_IN_INDEPENDENT_SERVICE or BANNED_ACCOUNT_IN_INDEPENDENT_SERVICE_TEMPORARILY\n\t\t\t\tif (errorCode == OLV_ACT_RESULT_STATUS(2805) || errorCode == OLV_ACT_RESULT_STATUS(2825))\n\t\t\t\t{\n\t\t\t\t\tuint32 tmpCode = OLV_RESULT_STATUS(1008);\n\t\t\t\t\treturn GetErrorCodeImpl(tmpCode);\n\t\t\t\t}\n\t\t\t\t// BANNED_DEVICE_IN_INDEPENDENT_SERVICE or  BANNED_DEVICE_IN_INDEPENDENT_SERVICE_TEMPORARILY\n\t\t\t\telse if (errorCode == OLV_ACT_RESULT_STATUS(2815) || errorCode == OLV_ACT_RESULT_STATUS(2835))\n\t\t\t\t{\n\t\t\t\t\tuint32 tmpCode = OLV_RESULT_STATUS(1009);\n\t\t\t\t\treturn GetErrorCodeImpl(tmpCode);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Check ACT error code\n\t\t\t\t\treturn 1159999;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (((errorCode & errorModuleMask) >> 20) == NN_RESULT_MODULE_NN_OLV && isCodeFailure)\n\t\t\t\t{\n\t\t\t\t\tuint32_t errorValueMask = (errorVersion != 3) ? 0xFFFFF : 0x3FF;\n\t\t\t\t\treturn ((errorCode & errorValueMask) >> 7) + 1150000;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn 1159999;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tuint32 GetErrorCode(uint32be* pResult)\n\t\t{\n\t\t\treturn GetErrorCodeImpl(pResult->value());\n\t\t}\n\n\t\tstatic_assert(GetErrorCodeImpl(0xa119c600) == 1155004);\n\n\t\tclass : public COSModule\n\t\t{\n\t\t\tpublic:\n\t\t\tstd::string_view GetName() override\n\t\t\t{\n\t\t\t\treturn \"nn_olv\";\n\t\t\t}\n\n\t\t\tvoid RPLMapped() override\n\t\t\t{\n\t\t\t\tloadOliveInitializeTypes();\n\t\t\t\tloadOliveUploadCommunityTypes();\n\t\t\t\tloadOliveDownloadCommunityTypes();\n\t\t\t\tloadOliveUploadFavoriteTypes();\n\t\t\t\tloadOlivePostAndTopicTypes();\n\n\t\t\t\tcafeExportRegisterFunc(GetErrorCode, \"nn_olv\", \"GetErrorCode__Q2_2nn3olvFRCQ2_2nn6Result\", LogType::NN_OLV);\n\n\t\t\t\tcafeExportRegisterFunc(StubPostApp, \"nn_olv\", \"UploadPostDataByPostApp__Q2_2nn3olvFPCQ3_2nn3olv28UploadPostDataByPostAppParam\", LogType::NN_OLV);\n\t\t\t\tcafeExportRegisterFunc(StubPostApp, \"nn_olv\", \"UploadCommentDataByPostApp__Q2_2nn3olvFPCQ3_2nn3olv31UploadCommentDataByPostAppParam\", LogType::NN_OLV);\n\t\t\t\tcafeExportRegisterFunc(StubPostApp, \"nn_olv\", \"UploadDirectMessageDataByPostApp__Q2_2nn3olvFPCQ3_2nn3olv37UploadDirectMessageDataByPostAppParam\", LogType::NN_OLV);\n\n\t\t\t\tcafeExportRegisterFunc(StubPostAppResult, \"nn_olv\", \"GetResultByPostApp__Q2_2nn3olvFv\", LogType::NN_OLV);\n\t\t\t\tcafeExportRegisterFunc(StubPostAppResult, \"nn_olv\", \"GetResultWithUploadedPostDataByPostApp__Q2_2nn3olvFPQ3_2nn3olv16UploadedPostData\", LogType::NN_OLV);\n\t\t\t\tcafeExportRegisterFunc(StubPostAppResult, \"nn_olv\", \"GetResultWithUploadedDirectMessageDataByPostApp__Q2_2nn3olvFPQ3_2nn3olv25UploadedDirectMessageData\", LogType::NN_OLV);\n\t\t\t\tcafeExportRegisterFunc(StubPostAppResult, \"nn_olv\", \"GetResultWithUploadedCommentDataByPostApp__Q2_2nn3olvFPQ3_2nn3olv19UploadedCommentData\", LogType::NN_OLV);\n\n\t\t\t\tcafeExportRegisterFunc(UploadedPostData_GetPostId, \"nn_olv\", \"GetPostId__Q3_2nn3olv16UploadedPostDataCFv\", LogType::NN_OLV);\n\t\t\t};\n\n\t\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t\t{\n\t\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t\t{\n\t\t\t\t\tg_ReportTypes = 0;\n\t\t\t\t\tg_IsOnlineMode = false;\n\t\t\t\t\tg_IsInitialized = false;\n\t\t\t\t\tg_IsOfflineDBMode = false;\n\t\t\t\t}\n\t\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t\t{\n\t\t\t\t\tOfflineDB_Shutdown();\n\t\t\t\t}\n\t\t\t}\n\t\t}s_COSnnOlvModule;\n\n\t\tCOSModule* GetModule()\n\t\t{\n\t\t\treturn &s_COSnnOlvModule;\n\t\t}\n\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv.h",
    "content": "#pragma once\n\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"Cafe/OS/libs/nn_act/nn_act.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cemu/napi/napi.h\"\n#include \"Cafe/OS/RPL/COSModule.h\"\n\n#include \"nn_olv_Common.h\"\n\nnamespace nn::olv\n{\n\textern ParamPackStorage g_ParamPack;\n\textern DiscoveryResultStorage g_DiscoveryResults;\n\n\tsint32 GetOlvAccessKey(uint32* pOutKey);\n\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_Common.cpp",
    "content": "#include \"nn_olv_Common.h\"\r\n#include <zlib.h>\r\n\r\nnamespace nn\r\n{\r\n\tnamespace olv\r\n\t{\r\n\r\n\t\tsint32 olv_copy_wstr(char16_t* dest, const char16_t* src, uint32_t maxSize, uint32_t destSize)\r\n\t\t{\r\n\t\t\tsize_t len = maxSize + 1;\r\n\t\t\tif (olv_wstrnlen(src, len) > maxSize)\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\tmemset(dest, 0, 2 * destSize);\r\n\t\t\tolv_wstrncpy(dest, src, len);\r\n\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t}\r\n\r\n\t\tsize_t olv_wstrnlen(const char16_t* str, size_t max_len)\r\n\t\t{\r\n\t\t\tsize_t len = 0;\r\n\t\t\twhile (len < max_len && str[len] != u'\\0')\r\n\t\t\t\tlen++;\r\n\r\n\t\t\treturn len;\r\n\t\t}\r\n\r\n\t\tchar16_t* olv_wstrncpy(char16_t* dest, const char16_t* src, size_t n)\r\n\t\t{\r\n\t\t\tchar16_t* ret = dest;\r\n\t\t\twhile (n > 0 && *src != u'\\0')\r\n\t\t\t{\r\n\t\t\t\t*dest++ = *src++;\r\n\t\t\t\tn--;\r\n\t\t\t}\r\n\t\t\twhile (n > 0)\r\n\t\t\t{\r\n\t\t\t\t*dest++ = u'\\0';\r\n\t\t\t\tn--;\r\n\t\t\t}\r\n\t\t\treturn ret;\r\n\t\t}\r\n\r\n\t\tbool CheckTGA(const uint8* pTgaFile, uint32 pTgaFileLen, TGACheckType checkType)\r\n\t\t{\r\n\t\t\tconst TGAHeader* header = (const TGAHeader*)pTgaFile;\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\tif (checkType == TGACheckType::CHECK_PAINTING)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (\r\n\t\t\t\t\t\theader->idLength ||\r\n\t\t\t\t\t\theader->colorMapType ||\r\n\t\t\t\t\t\theader->imageType != 2 || // Uncompressed true color\r\n\t\t\t\t\t\theader->first_entry_idx ||\r\n\t\t\t\t\t\theader->colormap_length ||\r\n\t\t\t\t\t\theader->bpp ||\r\n\t\t\t\t\t\theader->x_origin ||\r\n\t\t\t\t\t\theader->y_origin ||\r\n\t\t\t\t\t\theader->width != 320 ||\r\n\t\t\t\t\t\theader->height != 120 ||\r\n\t\t\t\t\t\theader->pixel_depth_bpp != 32 ||\r\n\t\t\t\t\t\theader->image_desc_bits != 8\r\n\t\t\t\t\t\t)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tthrow std::runtime_error(\"TGACheckType::CHECK_PAINTING - Invalid TGA file!\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse if (checkType == TGACheckType::CHECK_COMMUNITY_ICON)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (header->width != 128 || header->height != 128 || header->pixel_depth_bpp != 32)\r\n\t\t\t\t\t\tthrow std::runtime_error(\"TGACheckType::CHECK_COMMUNITY_ICON - Invalid TGA file -> width, height or bpp is wrong\");\r\n\t\t\t\t}\r\n\t\t\t\telse if (checkType == TGACheckType::CHECK_100x100_200x200)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (header->pixel_depth_bpp != 32)\r\n\t\t\t\t\t\tthrow std::runtime_error(\"TGACheckType::CHECK_100x100_200x200 - Invalid TGA file -> bpp is wrong\");\r\n\r\n\t\t\t\t\tif (header->width == 100)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tif (header->height != 100)\r\n\t\t\t\t\t\t\tthrow std::runtime_error(\"TGACheckType::CHECK_100x100_200x200 - Invalid TGA file -> Not 100x100\");\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (header->width != 200 || header->height != 200)\r\n\t\t\t\t\t\tthrow std::runtime_error(\"TGACheckType::CHECK_100x100_200x200 - Invalid TGA file -> Not 100x100 or 200x200\");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcatch (const std::runtime_error& error)\r\n\t\t\t{\r\n\t\t\t\t// TGA Check Error! illegal format\r\n\t\t\t\tcemuLog_log(LogType::Force, error.what());\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tsint32 DecodeTGA(uint8* pInBuffer, uint32 inSize, uint8* pOutBuffer, uint32 outSize, TGACheckType checkType)\r\n\t\t{\r\n\t\t\tuint32 decompressedSize = outSize;\r\n\t\t\tif (DecompressTGA(pOutBuffer, &decompressedSize, pInBuffer, inSize))\r\n\t\t\t{\r\n\t\t\t\tif (CheckTGA(pOutBuffer, decompressedSize, checkType))\r\n\t\t\t\t\treturn decompressedSize;\r\n\t\t\t\t\r\n\t\t\t\treturn -2;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE uncompress error.\\n\");\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tsint32 EncodeTGA(uint8* pInBuffer, uint32 inSize, uint8* pOutBuffer, uint32 outSize, TGACheckType checkType)\r\n\t\t{\r\n\t\t\tif (inSize == outSize)\r\n\t\t\t{\r\n\t\t\t\tif (!CheckTGA(pInBuffer, inSize, checkType))\r\n\t\t\t\t\treturn -1;\r\n\t\t\t\t\r\n\t\t\t\t\tuint32 compressedSize = outSize;\r\n\t\t\t\t\tif (CompressTGA(pOutBuffer, &compressedSize, pInBuffer, inSize))\r\n\t\t\t\t\t\treturn compressedSize;\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE compress error.\\n\");\r\n\t\t\t\t\t\treturn -1;\r\n\t\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"compress buffer size check error. uSrcBufSize({}) != uDstBufSize({})\\n\", inSize, outSize);\r\n\t\t\t\treturn -1;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tbool DecompressTGA(uint8* pOutBuffer, uint32* pOutSize, uint8* pInBuffer, uint32 inSize)\r\n\t\t{\r\n\t\t\tif (pOutBuffer == nullptr || pOutSize == nullptr || pInBuffer == nullptr || inSize == 0)\r\n\t\t\t\treturn false;\r\n\r\n\t\t\tuLongf bufferSize = *pOutSize;\r\n\t\t\tint result = uncompress(pOutBuffer, &bufferSize, pInBuffer, inSize);\r\n\r\n\t\t\tif (result == Z_OK)\r\n\t\t\t{\r\n\t\t\t\t*pOutSize = static_cast<unsigned int>(bufferSize);\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tconst char* error_msg = (result == Z_MEM_ERROR) ? \"Insufficient memory\" : \"Unknown decompression error\";\r\n\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE ZLIB - ERROR: {}\\n\", error_msg);\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tbool CompressTGA(uint8* pOutBuffer, uint32* pOutSize, uint8* pInBuffer, uint32 inSize)\r\n\t\t{\r\n\t\t\tif (pOutBuffer == nullptr || pOutSize == nullptr || pInBuffer == nullptr || inSize == 0)\r\n\t\t\t\treturn false;\r\n\r\n\t\t\tuLongf bufferSize = *pOutSize;\r\n\t\t\tint result = compress(pOutBuffer, &bufferSize, pInBuffer, inSize);\r\n\r\n\t\t\tif (result == Z_OK)\r\n\t\t\t{\r\n\t\t\t\t*pOutSize = static_cast<unsigned int>(bufferSize);\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tconst char* error_msg = (result == Z_MEM_ERROR) ? \"Insufficient memory\" : \"Unknown compression error\";\r\n\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE ZLIB - ERROR: {}\\n\", error_msg);\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconstexpr uint32 CreateCommunityCodeById(uint32 communityId)\r\n\t\t{\r\n\t\t\tuint32 res = communityId ^ (communityId << 18) ^ (communityId << 24) ^ (communityId << 30);\r\n\t\t\treturn res ^ (16 * (res & 0xF0F0F0F)) ^ ((res ^ (16 * (res & 0xF0F0F0F))) >> 17) ^ ((res ^ (16 * (res & 0xF0F0F0F))) >> 23) ^ ((res ^ (16 * (res & 0xF0F0F0F))) >> 29) ^ 0x20121002;\r\n\t\t}\r\n\r\n\t\tconstexpr uint32 CreateCommunityIdByCode(uint32 code)\r\n\t\t{\r\n\t\t\tuint32 res = code ^ 0x20121002 ^ ((code ^ 0x20121002u) >> 17) ^ ((code ^ 0x20121002u) >> 23) ^ ((code ^ 0x20121002u) >> 29);\r\n\t\t\treturn res ^ (16 * (res & 0xF0F0F0F)) ^ ((res ^ (16 * (res & 0xF0F0F0F))) << 18) ^ ((res ^ (16 * (res & 0xF0F0F0F))) << 24) ^ ((res ^ (16 * (res & 0xF0F0F0F))) << 30);\r\n\t\t}\r\n\r\n\r\n\t\tconstexpr uint32 GetCommunityCodeTopByte(uint32 communityId)\r\n\t\t{\r\n\t\t\tuint8 code_byte3 = (uint8_t)(communityId >> 0x18);\r\n\t\t\tuint8 code_byte2 = (uint8_t)(communityId >> 0x10);\r\n\t\t\tuint8 code_byte1 = (uint8_t)(communityId >> 8);\r\n\t\t\tuint8 code_byte0 = (uint8_t)(communityId >> 0);\r\n\t\t\treturn code_byte3 ^ code_byte2 ^ code_byte1 ^ code_byte0 ^ 0xff;\r\n\t\t}\r\n\r\n\t\tconstexpr uint64 GetRealCommunityCode(uint32_t communityId)\r\n\t\t{\r\n\t\t\tuint64 topByte = GetCommunityCodeTopByte(communityId);\r\n\t\t\tif ((0xe7 < topByte) && ((0xe8 < topByte || (0xd4a50fff < communityId))))\r\n\t\t\t\treturn ((topByte << 32) | communityId) & 0x7fffffffff;\r\n\r\n\t\t\treturn ((topByte << 32) | communityId);\r\n\t\t}\r\n\r\n\t\tvoid WriteCommunityCode(char* pOutCode, uint32 communityId)\r\n\t\t{\r\n\t\t\tuint32 code = CreateCommunityCodeById(communityId);\r\n\t\t\tuint64 communityCode = GetRealCommunityCode(code);\r\n\t\t\tsprintf(pOutCode, \"%012llu\", communityCode);\r\n\t\t}\r\n\r\n\t\tbool EnsureCommunityCode(char* pCode)\r\n\t\t{\r\n\t\t\tuint64 code;\r\n\t\t\tif (sscanf(pCode, \"%012llu\", &code) > 0)\r\n\t\t\t{\r\n\t\t\t\tuint32 lowerCode = code;\r\n\t\t\t\tuint64 newCode = GetRealCommunityCode(code);\r\n\t\t\t\treturn code == newCode;\r\n\t\t\t}\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tbool FormatCommunityCode(char* pOutCode, uint32* outLen, uint32 communityId)\r\n\t\t{\r\n\t\t\tbool result = false;\r\n\t\t\tif (communityId != -1)\r\n\t\t\t{\r\n\t\t\t\tif (communityId)\r\n\t\t\t\t{\r\n\t\t\t\t\tWriteCommunityCode(pOutCode, communityId);\r\n\t\t\t\t\t*outLen = strnlen(pOutCode, 12);\r\n\t\t\t\t\tif (EnsureCommunityCode(pOutCode))\r\n\t\t\t\t\t\tresult = 1;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn result;\r\n\t\t}\r\n\r\n\t\tstatic_assert(GetRealCommunityCode(CreateCommunityCodeById(140500)) == 717651734336, \"Wrong community code generation code, result must match.\");\r\n\r\n\t\tuint32 ExtractCommunityIdFromCode(char* pCode)\r\n\t\t{\r\n\t\t\tuint32 id = 0;\r\n\t\t\tuint64 code;\r\n\t\t\tif (sscanf(pCode, \"%012llu\", &code) > 0)\r\n\t\t\t{\r\n\t\t\t\tuint32 lower_code = code;\r\n\t\t\t\tid = CreateCommunityIdByCode(lower_code);\r\n\t\t\t}\r\n\t\t\treturn id;\r\n\t\t}\r\n\r\n\t\tbool GetCommunityIdFromCode(uint32* pOutId, const char* pCode)\r\n\t\t{\r\n\t\t\tif (!EnsureCommunityCode((char*)pCode))\r\n\t\t\t\treturn false;\r\n\r\n\t\t\t*pOutId = ExtractCommunityIdFromCode((char*)pCode);\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tsint32 olv_curlformcode_to_error(CURLFORMcode code)\r\n\t\t{\r\n\t\t\tswitch (code)\r\n\t\t\t{\r\n\t\t\t\tcase CURL_FORMADD_OK:\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\r\n\t\t\t\tcase CURL_FORMADD_MEMORY:\r\n\t\t\t\t\treturn OLV_RESULT_FATAL(25);\r\n\r\n\t\t\t\tcase CURL_FORMADD_OPTION_TWICE:\r\n\t\t\t\tdefault:\r\n\t\t\t\t\treturn OLV_RESULT_LVL6(50);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_Common.h",
    "content": "#pragma once\r\n\r\n#include \"Cafe/OS/libs/nn_common.h\"\r\n#include \"Cafe/OS/common/OSCommon.h\"\r\n#include \"Cemu/napi/napi_helper.h\"\r\n#include \"util/helpers/StringHelpers.h\"\r\n#include \"pugixml.hpp\"\r\n\r\n// https://github.com/kinnay/NintendoClients/wiki/Wii-U-Error-Codes#act-error-codes\r\n#define OLV_ACT_RESULT_STATUS(code) (BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_OLV, ((code) << 7)))\r\n\r\n#define OLV_RESULT_STATUS(code) (BUILD_NN_RESULT(NN_RESULT_LEVEL_STATUS, NN_RESULT_MODULE_NN_OLV, ((code) << 7)))\r\n#define OLV_RESULT_LVL6(code) (BUILD_NN_RESULT(NN_RESULT_LEVEL_LVL6, NN_RESULT_MODULE_NN_OLV, ((code) << 7)))\r\n#define OLV_RESULT_FATAL(code) (BUILD_NN_RESULT(NN_RESULT_LEVEL_FATAL, NN_RESULT_MODULE_NN_OLV, ((code) << 7)))\r\n#define OLV_RESULT_SUCCESS (BUILD_NN_RESULT(0, NN_RESULT_MODULE_NN_OLV, 1 << 7))\r\n\r\n#define OLV_RESULT_INVALID_PARAMETER (OLV_RESULT_LVL6(201))\r\n#define OLV_RESULT_INVALID_DATA (OLV_RESULT_LVL6(202))\r\n#define OLV_RESULT_NOT_ENOUGH_SIZE (OLV_RESULT_LVL6(203))\r\n#define OLV_RESULT_INVALID_PTR (OLV_RESULT_LVL6(204))\r\n#define OLV_RESULT_NOT_INITIALIZED (OLV_RESULT_LVL6(205))\r\n#define OLV_RESULT_ALREADY_INITIALIZED (OLV_RESULT_LVL6(206))\r\n#define OLV_RESULT_OFFLINE_MODE_REQUEST (OLV_RESULT_LVL6(207))\r\n#define OLV_RESULT_MISSING_DATA (OLV_RESULT_LVL6(208))\r\n#define OLV_RESULT_INVALID_SIZE (OLV_RESULT_LVL6(209))\r\n\r\n#define OLV_RESULT_BAD_VERSION (OLV_RESULT_STATUS(2001))\r\n#define OLV_RESULT_FAILED_REQUEST (OLV_RESULT_STATUS(2003))\r\n#define OLV_RESULT_INVALID_XML (OLV_RESULT_STATUS(2004))\r\n#define OLV_RESULT_INVALID_TEXT_FIELD (OLV_RESULT_STATUS(2006))\r\n#define OLV_RESULT_INVALID_INTEGER_FIELD (OLV_RESULT_STATUS(2007))\r\n\r\n#define OLV_CLIENT_ID \"87cd32617f1985439ea608c2746e4610\"\r\n\r\n#define OLV_VERSION_MAJOR 5\r\n#define OLV_VERSION_MINOR 0\r\n#define OLV_VERSION_PATCH 3\r\n\r\nnamespace nn\r\n{\r\n\tnamespace olv\r\n\t{\r\n\t\tstruct ParamPackStorage\r\n\t\t{\r\n\t\t\tuint64_t titleId;\r\n\t\t\tuint32_t accessKey;\r\n\t\t\tuint32_t platformId;\r\n\t\t\tuint8_t regionId, languageId, countryId, areaId;\r\n\t\t\tuint8_t networkRestriction, friendRestriction;\r\n\t\t\tuint32_t ratingRestriction;\r\n\t\t\tuint8_t ratingOrganization;\r\n\t\t\tuint64_t transferableId;\r\n\t\t\tchar tzName[72];\r\n\t\t\tuint64_t utcOffset;\r\n\t\t\tchar encodedParamPack[512];\r\n\t\t};\r\n\r\n\t\tstruct DiscoveryResultStorage\r\n\t\t{\r\n\t\t\tsint32 has_error;\r\n\t\t\tchar serviceToken[512];\r\n\t\t\tchar userAgent[64];\r\n\t\t\tchar apiEndpoint[256];\r\n\t\t\tchar portalEndpoint[256];\r\n\t\t};\r\n\r\n\t\textern ParamPackStorage g_ParamPack;\r\n\t\textern DiscoveryResultStorage g_DiscoveryResults;\r\n\t\textern uint32_t g_ReportTypes;\r\n\t\textern bool g_IsInitialized;\r\n\t\textern bool g_IsOnlineMode;\r\n\t\textern bool g_IsOfflineDBMode; // use offline cache for posts\r\n\r\n\t\tstatic void InitializeOliveRequest(CurlRequestHelper& req)\r\n\t\t{\r\n\t\t\treq.addHeaderField(\"X-Nintendo-ServiceToken\", g_DiscoveryResults.serviceToken);\r\n\t\t\treq.addHeaderField(\"X-Nintendo-ParamPack\", g_ParamPack.encodedParamPack);\r\n\t\t\tcurl_easy_setopt(req.getCURL(), CURLOPT_USERAGENT, g_DiscoveryResults.userAgent);\r\n\t\t}\r\n\r\n\t\tstatic void appendQueryToURL(char* url, const char* query)\r\n\t\t{\r\n\t\t\tsize_t urlLength = strlen(url);\r\n\t\t\tsize_t queryLength = strlen(query);\r\n\r\n\t\t\tchar* delimiter = strchr(url, '?');\r\n\t\t\tif (delimiter)\r\n\t\t\t\tsnprintf(url + urlLength, queryLength + 2, \"&%s\", query);\r\n\t\t\telse\r\n\t\t\t\tsnprintf(url + urlLength, queryLength + 2, \"?%s\", query);\r\n\t\t}\r\n\r\n\t\tstatic sint32 CheckOliveResponse(pugi::xml_document& doc)\r\n\t\t{\r\n\r\n\t\t\t/*\r\n\t\t\t\t<result>\r\n\t\t\t\t\t<has_error>1</has_error>\r\n\t\t\t\t\t<version>1</version>\r\n\t\t\t\t\t<code>400</code>\r\n\t\t\t\t\t<error_code>4</error_code>\r\n\t\t\t\t\t<message>SERVICE_CLOSED</message>\r\n\t\t\t\t</result>\r\n\t\t\t*/\r\n\r\n\t\t\tpugi::xml_node resultNode = doc.child(\"result\");\r\n\t\t\tif (!resultNode)\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Discovery response doesn't contain <result>...</result>\");\r\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\r\n\t\t\t}\r\n\r\n\t\t\tstd::string_view has_error = resultNode.child_value(\"has_error\");\r\n\t\t\tstd::string_view version = resultNode.child_value(\"version\");\r\n\t\t\tstd::string_view code = resultNode.child_value(\"code\");\r\n\t\t\tstd::string_view error_code = resultNode.child_value(\"error_code\");\r\n\r\n\t\t\tif (has_error.compare(\"1\") == 0)\r\n\t\t\t{\r\n\t\t\t\tint codeVal = StringHelpers::ToInt(error_code, -1);\r\n\t\t\t\tif (codeVal < 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tcodeVal = StringHelpers::ToInt(code, -1);\r\n\t\t\t\t\treturn OLV_RESULT_STATUS(codeVal + 4000);\r\n\t\t\t\t}\r\n\t\t\t\treturn OLV_RESULT_STATUS(codeVal + 5000);\r\n\r\n\t\t\t}\r\n\r\n\t\t\tif (version.compare(\"1\") != 0)\r\n\t\t\t\treturn OLV_RESULT_BAD_VERSION; // Version mismatch\r\n\r\n\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t}\r\n\r\n\t\tsint32 olv_copy_wstr(char16_t* dest, const char16_t* src, uint32_t maxSize, uint32_t destSize);\r\n\t\tsize_t olv_wstrnlen(const char16_t* str, size_t max_len);\r\n\t\tchar16_t* olv_wstrncpy(char16_t* dest, const char16_t* src, size_t n);\r\n\r\n#pragma pack(push, 1)\r\n\t\tstruct TGAHeader\r\n\t\t{\r\n\t\t\tuint8 idLength;\r\n\t\t\tuint8 colorMapType;\r\n\t\t\tuint8 imageType;\r\n\t\t\tuint16 first_entry_idx;\r\n\t\t\tuint16 colormap_length;\r\n\t\t\tuint8 bpp;\r\n\t\t\tuint16 x_origin;\r\n\t\t\tuint16 y_origin;\r\n\t\t\tuint16 width;\r\n\t\t\tuint16 height;\r\n\t\t\tuint8 pixel_depth_bpp;\r\n\t\t\tuint8 image_desc_bits;\r\n\t\t};\r\n#pragma pack(pop)\r\n\t\tstatic_assert(sizeof(nn::olv::TGAHeader) == 0x12, \"sizeof(nn::olv::TGAHeader != 0x12\");\r\n\r\n\t\tenum TGACheckType : uint32\r\n\t\t{\r\n\t\t\tCHECK_PAINTING = 0,\r\n\t\t\tCHECK_COMMUNITY_ICON = 1,\r\n\t\t\tCHECK_100x100_200x200 = 2\r\n\t\t};\r\n\r\n\r\n\t\tbool CheckTGA(const uint8* pTgaFile, uint32 pTgaFileLen, TGACheckType checkType);\r\n\t\tsint32 DecodeTGA(uint8* pInBuffer, uint32 inSize, uint8* pOutBuffer, uint32 outSize, TGACheckType checkType);\r\n\t\tsint32 EncodeTGA(uint8* pInBuffer, uint32 inSize, uint8* pOutBuffer, uint32 outSize, TGACheckType checkTyp);\r\n\t\t\r\n\t\tbool CompressTGA(uint8* pOutBuffer, uint32* pOutSize, uint8* pInBuffer, uint32 inSize);\r\n\t\tbool DecompressTGA(uint8* pOutBuffer, uint32* pOutSize, uint8* pInBuffer, uint32 inSize);\r\n\r\n\r\n\t\tbool GetCommunityIdFromCode(uint32* pOutId, const char* pCode);\r\n\t\tbool FormatCommunityCode(char* pOutCode, uint32* outLen, uint32 communityId);\r\n\r\n\t\tsint32 olv_curlformcode_to_error(CURLFORMcode code);\r\n\r\n\t\t// convert and copy utf8 string into UC2 big-endian array\r\n\t\ttemplate<size_t TLength>\r\n\t\tuint32 SetStringUC2(uint16be(&str)[TLength], std::string_view sv, bool unescape = false)\r\n\t\t{\r\n\t\t\tif(unescape)\r\n\t\t\t{\r\n\t\t\t\t// todo\r\n\t\t\t}\r\n\t\t\tstd::wstring ws = boost::nowide::widen(sv);\r\n\t\t\tsize_t copyLen = std::min<size_t>(TLength-1, ws.size());\r\n\t\t\tfor(size_t i=0; i<copyLen; i++)\r\n\t\t\t\tstr[i] = ws[i];\r\n\t\t\tstr[copyLen] = '\\0';\r\n\t\t\treturn copyLen;\r\n\t\t}\r\n\r\n\t\t// safely copy null-terminated UC2 big-endian string into UC2 big-endian array\r\n\t\ttemplate<size_t TLength>\r\n\t\tuint32 SetStringUC2(uint16be(&str)[TLength], const uint16be* strIn)\r\n\t\t{\r\n\t\t\tsize_t copyLen = TLength-1;\r\n\t\t\tfor(size_t i=0; i<copyLen; i++)\r\n\t\t\t{\r\n\t\t\t\tif(strIn[i] == 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tstr[i] = 0;\r\n\t\t\t\t\treturn i;\r\n\t\t\t\t}\r\n\t\t\t\tstr[i] = strIn[i];\r\n\t\t\t}\r\n\t\t\tstr[copyLen] = '\\0';\r\n\t\t\treturn copyLen;\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp",
    "content": "#include \"nn_olv_DownloadCommunityTypes.h\"\r\n\r\nnamespace nn\r\n{\r\n\tnamespace olv\r\n\t{\r\n\r\n\t\tsint32 DownloadCommunityDataList_AsyncRequestImpl(\r\n\t\t\tCurlRequestHelper& req, const char* reqUrl,\r\n\t\t\tDownloadedCommunityData* pOutList, uint32* pOutNum, uint32 numMaxList, const DownloadCommunityDataListParam* pParam);\r\n\r\n\r\n\t\tsint32 DownloadCommunityDataList_AsyncRequest(\r\n\t\t\tCurlRequestHelper& req, const char* reqUrl, coreinit::OSEvent* requestDoneEvent,\r\n\t\t\tDownloadedCommunityData* pOutList, uint32* pOutNum, uint32 numMaxList, const DownloadCommunityDataListParam* pParam\r\n\t\t)\r\n\t\t{\r\n\t\t\tsint32 res = DownloadCommunityDataList_AsyncRequestImpl(req, reqUrl, pOutList, pOutNum, numMaxList, pParam);\r\n\t\t\tcoreinit::OSSignalEvent(requestDoneEvent);\r\n\t\t\treturn res;\r\n\t\t}\r\n\r\n\t\tsint32 DownloadCommunityDataList(DownloadedCommunityData* pOutList, uint32* pOutNum, uint32 numMaxList, const DownloadCommunityDataListParam* pParam)\r\n\t\t{\r\n\t\t\tif (!g_IsInitialized)\r\n\t\t\t\treturn OLV_RESULT_NOT_INITIALIZED;\r\n\r\n\t\t\tif (!g_IsOnlineMode)\r\n\t\t\t\treturn OLV_RESULT_OFFLINE_MODE_REQUEST;\r\n\r\n\t\t\tif (!pOutList || !pOutNum || !pParam)\r\n\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\tif (!numMaxList)\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\tfor (int i = 0; i < numMaxList; i++)\r\n\t\t\t\tDownloadedCommunityData::Clean(&pOutList[i]);\r\n\r\n\t\t\tchar reqUrl[2048];\r\n\t\t\tsint32 res = pParam->GetRawDataUrl(reqUrl, sizeof(reqUrl));\r\n\t\t\tif (res < 0)\r\n\t\t\t\treturn res;\r\n\r\n\t\t\tCurlRequestHelper req;\r\n\t\t\treq.initate(ActiveSettings::GetNetworkService(), reqUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);\r\n\t\t\tInitializeOliveRequest(req);\r\n\r\n\t\t\tStackAllocator<coreinit::OSEvent> requestDoneEvent;\r\n\t\t\tcoreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);\r\n\t\t\tstd::future<sint32> requestRes = std::async(std::launch::async, DownloadCommunityDataList_AsyncRequest,\r\n\t\t\t\tstd::ref(req), reqUrl, requestDoneEvent.GetPointer(), pOutList, pOutNum, numMaxList, pParam);\r\n\t\t\tcoreinit::OSWaitEvent(&requestDoneEvent);\r\n\r\n\t\t\treturn requestRes.get();\t\r\n\t\t}\r\n\r\n\t\tsint32 DownloadCommunityDataList_AsyncRequestImpl(\r\n\t\t\tCurlRequestHelper& req, const char* reqUrl,\r\n\t\t\tDownloadedCommunityData* pOutList, uint32* pOutNum, uint32 numMaxList, const DownloadCommunityDataListParam* pParam\r\n\t\t)\r\n\t\t{\r\n\r\n\t\t\tbool reqResult = req.submitRequest();\r\n\t\t\tlong httpCode = 0;\r\n\t\t\tcurl_easy_getinfo(req.getCURL(), CURLINFO_RESPONSE_CODE, &httpCode);\r\n\r\n\r\n\t\t\tif (!reqResult)\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed request: {} ({})\", reqUrl, httpCode);\r\n\t\t\t\tif (!(httpCode >= 400))\r\n\t\t\t\t\treturn OLV_RESULT_FAILED_REQUEST;\r\n\t\t\t}\r\n\r\n\t\t\tpugi::xml_document doc;\r\n\t\t\tif (!doc.load_buffer(req.getReceivedData().data(), req.getReceivedData().size()))\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Invalid XML in community download response\"));\r\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\r\n\t\t\t}\r\n\r\n\t\t\tsint32 responseError = CheckOliveResponse(doc);\r\n\t\t\tif (responseError < 0)\r\n\t\t\t\treturn responseError;\r\n\r\n\t\t\tif (httpCode != 200)\r\n\t\t\t\treturn OLV_RESULT_STATUS(httpCode + 4000);\r\n\r\n\t\t\tstd::string request_name = doc.select_node(\"//request_name\").node().child_value();\r\n\t\t\tif (request_name.size() == 0)\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Community download response doesn't contain <request_name>\");\r\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\r\n\t\t\t}\r\n\r\n\t\t\tif ((request_name.compare(\"communities\") != 0) && (request_name.compare(\"specified_communities\") != 0))\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Community download response <request_name> isn't \\\"communities\\\" or \\\"specified_communities\\\"\");\r\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\r\n\t\t\t}\r\n\r\n\t\t\tpugi::xml_node communities = doc.select_node(\"//communities\").node();\r\n\t\t\tif (!communities)\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Community download response doesn't contain <communities>\");\r\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\r\n\t\t\t}\r\n\r\n\t\t\tint idx = 0;\r\n\t\t\tfor (pugi::xml_node communityNode : communities.children(\"community\"))\r\n\t\t\t{\r\n\t\t\t\tif (idx >= numMaxList)\r\n\t\t\t\t\tbreak;\r\n\r\n\t\t\t\tDownloadedCommunityData* pOutData = &pOutList[idx];\r\n\r\n\t\t\t\tstd::string_view app_data = communityNode.child_value(\"app_data\");\r\n\t\t\t\tstd::string_view community_id = communityNode.child_value(\"community_id\");\r\n\t\t\t\tstd::string_view name = communityNode.child_value(\"name\");\r\n\t\t\t\tstd::string_view description = communityNode.child_value(\"description\");\r\n\t\t\t\tstd::string_view pid = communityNode.child_value(\"pid\");\r\n\t\t\t\tstd::string_view icon = communityNode.child_value(\"icon\");\r\n\t\t\t\tstd::string_view mii = communityNode.child_value(\"mii\");\r\n\t\t\t\tstd::string_view screen_name = communityNode.child_value(\"screen_name\");\r\n\r\n\t\t\t\tif (app_data.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto app_data_bin = NCrypto::base64Decode(app_data);\r\n\t\t\t\t\tif (app_data_bin.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tmemcpy(pOutData->appData, app_data_bin.data(), std::min(size_t(0x400), app_data_bin.size()));\r\n\t\t\t\t\t\tpOutData->flags |= DownloadedCommunityData::FLAG_HAS_APP_DATA;\r\n\t\t\t\t\t\tpOutData->appDataLen = app_data_bin.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsint64 community_id_val = StringHelpers::ToInt64(community_id, -1);\r\n\t\t\t\tif (community_id_val == -1)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_INTEGER_FIELD;\r\n\r\n\t\t\t\tpOutData->communityId = community_id_val;\r\n\r\n\t\t\t\tif (name.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto name_utf16 = StringHelpers::FromUtf8(name);\r\n\t\t\t\t\tname_utf16.resize(std::min<size_t>(name_utf16.size(), 128));\r\n\t\t\t\t\tif (name_utf16.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfor (int i = 0; i < name_utf16.size(); i++)\r\n\t\t\t\t\t\t\tpOutData->titleText[i] = name_utf16.at(i).bevalue();\r\n\r\n\t\t\t\t\t\tpOutData->flags |= DownloadedCommunityData::FLAG_HAS_TITLE_TEXT;\r\n\t\t\t\t\t\tpOutData->titleTextMaxLen = name_utf16.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (description.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto description_utf16 = StringHelpers::FromUtf8(description);\r\n\t\t\t\t\tdescription_utf16.resize(std::min<size_t>(description_utf16.size(), 256));\r\n\t\t\t\t\tif (description_utf16.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfor (int i = 0; i < description_utf16.size(); i++)\r\n\t\t\t\t\t\t\tpOutData->description[i] = description_utf16.at(i).bevalue();\r\n\r\n\t\t\t\t\t\tpOutData->flags |= DownloadedCommunityData::FLAG_HAS_DESC_TEXT;\r\n\t\t\t\t\t\tpOutData->descriptionMaxLen = description_utf16.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsint64 pid_val = StringHelpers::ToInt64(pid, -1);\r\n\t\t\t\tif (pid_val == -1)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_INTEGER_FIELD;\r\n\r\n\t\t\t\tpOutData->pid = pid_val;\r\n\r\n\t\t\t\tif (icon.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto icon_bin = NCrypto::base64Decode(icon);\r\n\t\t\t\t\tif (icon_bin.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tmemcpy(pOutData->iconData, icon_bin.data(), std::min(size_t(0x1002c), icon_bin.size()));\r\n\t\t\t\t\t\tpOutData->flags |= DownloadedCommunityData::FLAG_HAS_ICON_DATA;\r\n\t\t\t\t\t\tpOutData->iconDataSize = icon_bin.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (mii.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto mii_bin = NCrypto::base64Decode(mii);\r\n\t\t\t\t\tif (mii_bin.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tmemcpy(pOutData->miiFFLStoreData, mii_bin.data(), std::min(size_t(96), mii_bin.size()));\r\n\t\t\t\t\t\tpOutData->flags |= DownloadedCommunityData::FLAG_HAS_MII_DATA;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (screen_name.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto screen_name_utf16 = StringHelpers::FromUtf8(screen_name);\r\n\t\t\t\t\tscreen_name_utf16.resize(std::min<size_t>(screen_name_utf16.size(), 32));\r\n\t\t\t\t\tif (screen_name_utf16.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfor (int i = 0; i < screen_name_utf16.size(); i++)\r\n\t\t\t\t\t\t\tpOutData->miiDisplayName[i] = screen_name_utf16.at(i).bevalue();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tidx++;\r\n\r\n\t\t\t}\r\n\r\n\t\t\t*pOutNum = _swapEndianU32(idx);\r\n\t\t\tsint32 res = OLV_RESULT_SUCCESS;\r\n\t\t\tif (idx > 0)\r\n\t\t\t\tres = 0; // nn_olv doesn't do it like that, but it's the same effect. I have no clue why it returns 0 when you have 1+ communities downloaded\r\n\r\n\t\t\treturn res;\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.h",
    "content": "#pragma once\r\n\r\n#include \"Cemu/ncrypto/ncrypto.h\"\r\n#include \"config/ActiveSettings.h\"\r\n\r\n#include \"Cafe/OS/libs/nn_olv/nn_olv_Common.h\"\r\n\r\nnamespace nn\r\n{\r\n\tnamespace olv\r\n\t{\r\n\r\n\t\tclass DownloadedCommunityData\r\n\t\t{\r\n\t\tpublic:\r\n\t\t\tstatic const inline uint32 FLAG_HAS_TITLE_TEXT = (1 << 0);\r\n\t\t\tstatic const inline uint32 FLAG_HAS_DESC_TEXT = (1 << 1);\r\n\t\t\tstatic const inline uint32 FLAG_HAS_APP_DATA = (1 << 2);\r\n\t\t\tstatic const inline uint32 FLAG_HAS_ICON_DATA = (1 << 3);\r\n\t\t\tstatic const inline uint32 FLAG_HAS_MII_DATA = (1 << 4);\r\n\r\n\t\t\tDownloadedCommunityData()\r\n\t\t\t{\r\n\t\t\t\tthis->titleTextMaxLen = 0;\r\n\t\t\t\tthis->appDataLen = 0;\r\n\t\t\t\tthis->descriptionMaxLen = 0;\r\n\t\t\t\tthis->pid = 0;\r\n\t\t\t\tthis->communityId = 0;\r\n\t\t\t\tthis->flags = 0;\r\n\t\t\t\tthis->iconDataSize = 0;\r\n\t\t\t\tthis->miiDisplayName[0] = 0;\r\n\t\t\t}\r\n\t\t\tstatic DownloadedCommunityData* __ctor(DownloadedCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\tif (!_this)\r\n\t\t\t\t{\r\n\t\t\t\t\tassert_dbg(); // DO NOT CONTINUE, SHOULD NEVER HAPPEN\r\n\t\t\t\t\treturn nullptr;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t\treturn new (_this) DownloadedCommunityData();\r\n\t\t\t}\r\n\r\n\t\t\tstatic DownloadedCommunityData* Clean(DownloadedCommunityData* data)\r\n\t\t\t{\r\n\t\t\t\tdata->flags = 0;\r\n\t\t\t\tdata->communityId = 0;\r\n\t\t\t\tdata->pid = 0;\r\n\t\t\t\tdata->iconData[0] = 0;\r\n\t\t\t\tdata->titleTextMaxLen = 0;\r\n\t\t\t\tdata->appData[0] = 0;\r\n\t\t\t\tdata->appDataLen = 0;\r\n\t\t\t\tdata->description[0] = 0;\r\n\t\t\t\tdata->descriptionMaxLen = 0;\r\n\t\t\t\tdata->iconDataSize = 0;\r\n\t\t\t\tdata->titleText[0] = 0;\r\n\t\t\t\tdata->miiDisplayName[0] = 0;\r\n\t\t\t\treturn data;\r\n\t\t\t}\r\n\r\n\t\t\tbool TestFlags(uint32 flags) const\r\n\t\t\t{\r\n\t\t\t\treturn (this->flags & flags) != 0;\r\n\t\t\t}\r\n\t\t\tstatic bool __TestFlags(DownloadedCommunityData* _this, uint32 flags)\r\n\t\t\t{\r\n\t\t\t\treturn _this->TestFlags(flags);\r\n\t\t\t}\r\n\r\n\t\t\tuint32 GetCommunityId() const\r\n\t\t\t{\r\n\t\t\t\treturn this->communityId;\r\n\t\t\t}\r\n\t\t\tstatic uint32 __GetCommunityId(DownloadedCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetCommunityId();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetCommunityCode(char* pBuffer, uint32 bufferSize) const\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (bufferSize <= 12)\r\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\t\tuint32 len = 0;\r\n\t\t\t\tif (FormatCommunityCode(pBuffer, &len, this->communityId))\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\r\n\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetCommunityCode(DownloadedCommunityData* _this, char* pBuffer, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetCommunityCode(pBuffer, bufferSize);\r\n\t\t\t}\r\n\r\n\t\t\tuint32 GetOwnerPid() const\r\n\t\t\t{\r\n\t\t\t\treturn this->pid;\r\n\t\t\t}\r\n\t\t\tstatic uint32 __GetOwnerPid(DownloadedCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetOwnerPid();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetTitleText(char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (numChars)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (!this->TestFlags(FLAG_HAS_TITLE_TEXT))\r\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\t\tmemset(pBuffer, 0, 2 * numChars);\r\n\t\t\t\t\tuint32 readSize = this->titleTextMaxLen;\r\n\t\t\t\t\tif (numChars < readSize)\r\n\t\t\t\t\t\treadSize = numChars;\r\n\r\n\t\t\t\t\tolv_wstrncpy(pBuffer, this->titleText, readSize);\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetTitleText(DownloadedCommunityData* _this, char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetTitleText(pBuffer, numChars);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetDescriptionText(char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (numChars)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (!this->TestFlags(FLAG_HAS_DESC_TEXT))\r\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\t\tmemset(pBuffer, 0, 2 * numChars);\r\n\t\t\t\t\tolv_wstrncpy(pBuffer, this->description, numChars);\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetDescriptionText(DownloadedCommunityData* _this, char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetDescriptionText(pBuffer, numChars);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetAppData(uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\tuint32 appDataSize = bufferSize;\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (bufferSize)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (!this->TestFlags(FLAG_HAS_APP_DATA))\r\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\t\tif (this->appDataLen < appDataSize)\r\n\t\t\t\t\t\tappDataSize = this->appDataLen;\r\n\r\n\t\t\t\t\tmemcpy(pBuffer, this->appData, appDataSize);\r\n\t\t\t\t\tif (pOutSize)\r\n\t\t\t\t\t\t*pOutSize = appDataSize;\r\n\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetAppData(DownloadedCommunityData* _this, uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetAppData(pBuffer, pOutSize, bufferSize);\r\n\t\t\t}\r\n\r\n\t\t\tuint32 GetAppDataSize() const\r\n\t\t\t{\r\n\t\t\t\tif (this->TestFlags(FLAG_HAS_APP_DATA))\r\n\t\t\t\t\treturn this->appDataLen;\r\n\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t\tstatic uint32 __GetAppDataSize(DownloadedCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetAppDataSize();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetIconData(uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (bufferSize < sizeof(this->iconData))\r\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\t\tif (!this->TestFlags(FLAG_HAS_ICON_DATA))\r\n\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\tsint32 decodeRes = DecodeTGA(this->iconData, this->iconDataSize, pBuffer, bufferSize, TGACheckType::CHECK_COMMUNITY_ICON);\r\n\t\t\t\tif (decodeRes >= 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (pOutSize)\r\n\t\t\t\t\t\t*pOutSize = (uint32)decodeRes;\r\n\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pOutSize)\r\n\t\t\t\t\t*pOutSize = 0;\r\n\r\n\t\t\t\tif (decodeRes == -1)\r\n\t\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE - icon uncompress failed.\\n\");\r\n\t\t\t\telse if (decodeRes == -2)\r\n\t\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE - icon decode error. NOT TGA.\\n\");\r\n\r\n\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetIconData(DownloadedCommunityData* _this, uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetIconData(pBuffer, pOutSize, bufferSize);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetOwnerMiiData(/* FFLStoreData* */void* pBuffer) const\r\n\t\t\t{\r\n\t\t\t\tif (!this->TestFlags(FLAG_HAS_MII_DATA))\r\n\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tmemcpy(pBuffer, this->miiFFLStoreData, sizeof(this->miiFFLStoreData));\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetOwnerMiiData(DownloadedCommunityData* _this, /* FFLStoreData* */void* pBuffer)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetOwnerMiiData(pBuffer);\r\n\t\t\t}\r\n\r\n\t\t\tconst char16_t* GetOwnerMiiNickname() const\r\n\t\t\t{\r\n\t\t\t\tif (this->miiDisplayName[0])\r\n\t\t\t\t\treturn this->miiDisplayName;\r\n\r\n\t\t\t\treturn nullptr;\r\n\t\t\t}\r\n\t\t\tstatic const char16_t* __GetOwnerMiiNickname(DownloadedCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetOwnerMiiNickname();\r\n\t\t\t}\r\n\r\n\t\tpublic:\r\n\t\t\tuint32be flags;\r\n\t\t\tuint32be communityId;\r\n\t\t\tuint32be pid;\r\n\t\t\tchar16_t titleText[128];\r\n\t\t\tuint32be titleTextMaxLen;\r\n\t\t\tchar16_t description[256];\r\n\t\t\tuint32be descriptionMaxLen;\r\n\t\t\tuint8 appData[1024];\r\n\t\t\tuint32be appDataLen;\r\n\t\t\tuint8 iconData[65580];\r\n\t\t\tuint32be iconDataSize;\r\n\t\t\tuint8 miiFFLStoreData[96];\r\n\t\t\tchar16_t miiDisplayName[32];\r\n\t\t\tuint8 unk[6168];\r\n\t\t};\r\n\t\tstatic_assert(sizeof(nn::olv::DownloadedCommunityData) == 0x12000, \"sizeof(nn::olv::DownloadedCommunityData) != 0x12000\");\r\n\r\n\t\tclass DownloadCommunityDataListParam\r\n\t\t{\r\n\t\tpublic:\r\n\t\t\tstatic const inline uint32 FLAG_FILTER_FAVORITES = (1 << 0);\r\n\t\t\tstatic const inline uint32 FLAG_FILTER_OFFICIALS = (1 << 1);\r\n\t\t\tstatic const inline uint32 FLAG_FILTER_OWNED = (1 << 2);\r\n\t\t\tstatic const inline uint32 FLAG_QUERY_MII_DATA = (1 << 3);\r\n\t\t\tstatic const inline uint32 FLAG_QUERY_ICON_DATA = (1 << 4);\r\n\r\n\t\t\tDownloadCommunityDataListParam()\r\n\t\t\t{\r\n\t\t\t\tthis->flags = 0;\r\n\t\t\t\tthis->communityDownloadLimit = 0;\r\n\t\t\t\tthis->communityId = 0;\r\n\r\n\t\t\t\tfor (int i = 0; i < 20; i++)\r\n\t\t\t\t\tthis->additionalCommunityIdList[i] = -2;\r\n\t\t\t}\r\n\t\t\tstatic DownloadCommunityDataListParam* __ctor(DownloadCommunityDataListParam* _this)\r\n\t\t\t{\r\n\t\t\t\tif (!_this)\r\n\t\t\t\t{\r\n\t\t\t\t\tassert_dbg(); // DO NOT CONTINUE, SHOULD NEVER HAPPEN\r\n\t\t\t\t\treturn nullptr;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t\treturn new (_this) DownloadCommunityDataListParam();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetFlags(uint32 flags)\r\n\t\t\t{\r\n\t\t\t\tthis->flags = flags;\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetFlags(DownloadCommunityDataListParam* _this, uint32 flags)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetFlags(flags);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetCommunityId(uint32 communityId)\r\n\t\t\t{\r\n\t\t\t\tif (communityId == -1)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\tthis->communityId = communityId;\r\n\t\t\t\tif (communityId)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (!this->communityDownloadLimit)\r\n\t\t\t\t\t\tthis->communityDownloadLimit = 1;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetCommunityId(DownloadCommunityDataListParam* _this, uint32 communityId)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetCommunityId(communityId);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetCommunityId(uint32 communityId, uint8 idx)\r\n\t\t\t{\r\n\t\t\t\tif (communityId == -1)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\tif (idx >= 20)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\tthis->additionalCommunityIdList[idx] = communityId;\r\n\t\t\t\tint validIdsCount = 0;\r\n\t\t\t\tfor (int i = 0; i < 20; i++ )\r\n\t\t\t\t{\r\n\t\t\t\t\tif (this->additionalCommunityIdList[i] != -2)\r\n\t\t\t\t\t\t++validIdsCount;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (validIdsCount > this->communityDownloadLimit)\r\n\t\t\t\t\tthis->communityDownloadLimit = validIdsCount;\r\n\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetCommunityId(DownloadCommunityDataListParam* _this, uint32 communityId, uint8 idx)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetCommunityId(communityId, idx);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetCommunityDataMaxNum(uint32 num)\r\n\t\t\t{\r\n\t\t\t\tif (!num)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\tint validIdsCount = 0;\r\n\t\t\t\tfor (int i = 0; i < 20; ++i)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (this->additionalCommunityIdList[i] != -2)\r\n\t\t\t\t\t\t++validIdsCount;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (validIdsCount > num)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\tthis->communityDownloadLimit = num;\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetCommunityDataMaxNum(DownloadCommunityDataListParam* _this, uint32 num)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetCommunityDataMaxNum(num);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetRawDataUrl(char* pBuffer, uint32 bufferSize) const\r\n\t\t\t{\r\n\t\t\t\tif (!g_IsOnlineMode)\r\n\t\t\t\t\treturn OLV_RESULT_OFFLINE_MODE_REQUEST;\r\n\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (!bufferSize)\r\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\t\tchar tmpFormatBuffer[64];\r\n\t\t\t\tchar urlBuffer[1024];\r\n\t\t\t\tmemset(urlBuffer, 0, sizeof(urlBuffer));\r\n\r\n\t\t\t\tuint32 communityId;\r\n\t\t\t\tint validIdsCount = 0;\r\n\t\t\t\tfor (int i = 0; i < 20; ++i)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (this->additionalCommunityIdList[i] != -2)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tcommunityId = this->additionalCommunityIdList[i];\r\n\t\t\t\t\t\t++validIdsCount;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (validIdsCount)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (this->communityId && this->communityId != -2)\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\t\tuint32 unkFlag = this->flags & 0xFFFFFFE7;\r\n\t\t\t\t\tif (unkFlag)\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\t\t// It's how it's done in the real nn_olv, what even the fuck is this, never seen used yet.\r\n\t\t\t\t\tsnprintf(urlBuffer, sizeof(urlBuffer), \"%s/v1/communities/%u.search\", g_DiscoveryResults.apiEndpoint, communityId);\r\n\r\n\t\t\t\t\tfor (int i = 0; i < 20; ++i)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tif (this->additionalCommunityIdList[i] != -2)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tsnprintf(tmpFormatBuffer, 64, \"community_id=%u\", this->additionalCommunityIdList[i].value());\r\n\t\t\t\t\t\t\tappendQueryToURL(urlBuffer, tmpFormatBuffer);\r\n\t\t\t\t\t\t\t++unkFlag;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t\tsnprintf(urlBuffer, sizeof(urlBuffer), \"%s/v1/communities\", g_DiscoveryResults.apiEndpoint);\r\n\r\n\t\t\t\tif (this->communityId)\r\n\t\t\t\t{\r\n\t\t\t\t\tsnprintf(tmpFormatBuffer, 64, \"community_id=%u\", this->communityId.value());\r\n\t\t\t\t\tappendQueryToURL(urlBuffer, tmpFormatBuffer);\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tuint32 filterBy_favorite = (this->flags & FLAG_FILTER_FAVORITES) != 0;\r\n\t\t\t\t\tuint32 filterBy_official = (this->flags & FLAG_FILTER_OFFICIALS) != 0;\r\n\t\t\t\t\tuint32 filterBy_selfmade = (this->flags & FLAG_FILTER_OWNED) != 0;\r\n\t\t\t\t\r\n\t\t\t\t\tif ((filterBy_favorite + filterBy_official + filterBy_selfmade) != 1)\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\t\tsnprintf(tmpFormatBuffer, 64, \"limit=%u\", this->communityDownloadLimit.value());\r\n\t\t\t\t\tappendQueryToURL(urlBuffer, tmpFormatBuffer);\r\n\r\n\t\t\t\t\tif (filterBy_favorite)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tstrncpy(tmpFormatBuffer, \"type=favorite\", 64);\r\n\t\t\t\t\t\tappendQueryToURL(urlBuffer, tmpFormatBuffer);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (filterBy_official)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tstrncpy(tmpFormatBuffer, \"type=official\", 64);\r\n\t\t\t\t\t\tappendQueryToURL(urlBuffer, tmpFormatBuffer);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tstrncpy(tmpFormatBuffer, \"type=my\", 64);\r\n\t\t\t\t\t\tappendQueryToURL(urlBuffer, tmpFormatBuffer);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (this->flags & FLAG_QUERY_MII_DATA)\r\n\t\t\t\t{\r\n\t\t\t\t\tstrncpy(tmpFormatBuffer, \"with_mii=1\", 64);\r\n\t\t\t\t\tappendQueryToURL(urlBuffer, tmpFormatBuffer);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (this->flags & FLAG_QUERY_ICON_DATA)\r\n\t\t\t\t{\r\n\t\t\t\t\tstrncpy(tmpFormatBuffer, \"with_icon=1\", 64);\r\n\t\t\t\t\tappendQueryToURL(urlBuffer, tmpFormatBuffer);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tint res = snprintf(pBuffer, bufferSize, \"%s\", urlBuffer);\r\n\t\t\t\tif (res < 0)\r\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetRawDataUrl(DownloadCommunityDataListParam* _this, char* pBuffer, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetRawDataUrl(pBuffer, bufferSize);\r\n\t\t\t}\r\n\r\n\t\tpublic:\r\n\t\t\tuint32be flags;\r\n\t\t\tuint32be communityId;\r\n\t\t\tuint32be communityDownloadLimit;\r\n\t\t\tuint32be additionalCommunityIdList[20]; // Additional community ID filter list\r\n\t\t\tuint8 unk[4004]; // Looks unused lol, probably reserved data\r\n\t\t};\r\n\t\tstatic_assert(sizeof(nn::olv::DownloadCommunityDataListParam) == 0x1000, \"sizeof(nn::olv::DownloadCommunityDataListParam) != 0x1000\");\r\n\r\n\t\tsint32 DownloadCommunityDataList(DownloadedCommunityData* pOutList, uint32* pOutNum, uint32 numMaxList, const DownloadCommunityDataListParam* pParam);\r\n\r\n\t\tstatic void loadOliveDownloadCommunityTypes()\r\n\t\t{\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__ctor, \"nn_olv\", \"__ct__Q3_2nn3olv23DownloadedCommunityDataFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__TestFlags, \"nn_olv\", \"TestFlags__Q3_2nn3olv23DownloadedCommunityDataCFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__GetCommunityId, \"nn_olv\", \"GetCommunityId__Q3_2nn3olv23DownloadedCommunityDataCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__GetCommunityCode, \"nn_olv\", \"GetCommunityCode__Q3_2nn3olv23DownloadedCommunityDataCFPcUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__GetOwnerPid, \"nn_olv\", \"GetOwnerPid__Q3_2nn3olv23DownloadedCommunityDataCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__GetTitleText, \"nn_olv\", \"GetTitleText__Q3_2nn3olv23DownloadedCommunityDataCFPwUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__GetDescriptionText, \"nn_olv\", \"GetDescriptionText__Q3_2nn3olv23DownloadedCommunityDataCFPwUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__GetAppData, \"nn_olv\", \"GetAppData__Q3_2nn3olv23DownloadedCommunityDataCFPUcPUiUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__GetAppDataSize, \"nn_olv\", \"GetAppDataSize__Q3_2nn3olv23DownloadedCommunityDataCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__GetIconData, \"nn_olv\", \"GetIconData__Q3_2nn3olv23DownloadedCommunityDataCFPUcPUiUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__GetOwnerMiiData, \"nn_olv\", \"GetOwnerMiiData__Q3_2nn3olv23DownloadedCommunityDataCFP12FFLStoreData\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadedCommunityData::__GetOwnerMiiNickname, \"nn_olv\", \"GetOwnerMiiNickname__Q3_2nn3olv23DownloadedCommunityDataCFv\", LogType::NN_OLV);\r\n\r\n\t\t\tcafeExportRegisterFunc(DownloadCommunityDataListParam::__ctor, \"nn_olv\", \"__ct__Q3_2nn3olv30DownloadCommunityDataListParamFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadCommunityDataListParam::__SetFlags, \"nn_olv\", \"SetFlags__Q3_2nn3olv30DownloadCommunityDataListParamFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadCommunityDataListParam::__SetCommunityDataMaxNum, \"nn_olv\", \"SetCommunityDataMaxNum__Q3_2nn3olv30DownloadCommunityDataListParamFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(DownloadCommunityDataListParam::__GetRawDataUrl, \"nn_olv\", \"GetRawDataUrl__Q3_2nn3olv30DownloadCommunityDataListParamCFPcUi\", LogType::NN_OLV);\r\n\r\n\t\t\tcafeExportRegisterFunc((sint32 (*)(DownloadCommunityDataListParam*, uint32))DownloadCommunityDataListParam::__SetCommunityId,\r\n\t\t\t\t\"nn_olv\", \"SetCommunityId__Q3_2nn3olv30DownloadCommunityDataListParamFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc((sint32(*)(DownloadCommunityDataListParam*, uint32, uint8))DownloadCommunityDataListParam::__SetCommunityId,\r\n\t\t\t\t\"nn_olv\", \"SetCommunityId__Q3_2nn3olv30DownloadCommunityDataListParamFUiUc\", LogType::NN_OLV);\r\n\t\t\r\n\t\t\tcafeExportRegisterFunc(DownloadCommunityDataList, \"nn_olv\", \"DownloadCommunityDataList__Q2_2nn3olvFPQ3_2nn3olv23DownloadedCommunityDataPUiUiPCQ3_2nn3olv30DownloadCommunityDataListParam\", LogType::NN_OLV);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.cpp",
    "content": "#include \"nn_olv_InitializeTypes.h\"\r\n#include \"CafeSystem.h\"\r\n#include \"Cafe/OS/libs/nn_act/nn_act.h\"\r\n#include <time.h>\r\n\r\nnamespace nn\r\n{\r\n\tnamespace olv\r\n\t{\r\n\t\tuint32_t g_ReportTypes = 0;\r\n\t\tbool g_IsOnlineMode = false;\r\n\t\tbool g_IsInitialized = false;\r\n\t\tbool g_IsOfflineDBMode = false;\r\n\t\tParamPackStorage g_ParamPack;\r\n\t\tDiscoveryResultStorage g_DiscoveryResults;\r\n\r\n\t\tsint32 GetOlvAccessKey(uint32* pOutKey)\r\n\t\t{\r\n\t\t\t*pOutKey = 0;\r\n\t\t\tuint32 accessKey = CafeSystem::GetForegroundTitleOlvAccesskey();\r\n\t\t\tif (accessKey == -1)\r\n\t\t\t\treturn OLV_RESULT_STATUS(1102);\r\n\r\n\t\t\t*pOutKey = accessKey;\r\n\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t}\r\n\r\n\t\tsint32 CreateParamPack(uint64_t titleId, uint32_t accessKey)\r\n\t\t{\r\n\t\t\tg_ParamPack.languageId = uint8(GetConfig().console_language.GetValue());\r\n\r\n\t\t\tuint32be simpleAddress = 0;\r\n\t\t\tnn::act::GetSimpleAddressIdEx(&simpleAddress, nn::act::ACT_SLOT_CURRENT);\r\n\t\t\tuint32 countryCode = nn::act::getCountryCodeFromSimpleAddress(simpleAddress);\r\n\r\n\t\t\tg_ParamPack.countryId = countryCode;\r\n\t\t\tg_ParamPack.titleId = titleId;\r\n\t\t\tg_ParamPack.platformId = 1;\r\n\r\n\t\t\tg_ParamPack.areaId = (simpleAddress >> 8) & 0xff;\r\n\r\n\t\t\tMCPHANDLE handle = MCP_Open();\r\n\t\t\tSysProdSettings sysProdSettings;\r\n\t\t\tMCP_GetSysProdSettings(handle, &sysProdSettings);\r\n\t\t\tMCP_Close(handle);\r\n\r\n\t\t\tg_ParamPack.regionId = sysProdSettings.platformRegion;\r\n\t\t\tg_ParamPack.accessKey = accessKey;\r\n\r\n\t\t\tg_ParamPack.networkRestriction = 0;\r\n\t\t\tg_ParamPack.friendRestriction = 0;\r\n\t\t\tg_ParamPack.ratingRestriction = 18;\r\n\t\t\tg_ParamPack.ratingOrganization = 4; // PEGI ?\r\n\r\n\t\t\tuint64 transferrableId;\r\n\t\t\tnn::act::GetTransferableIdEx(&transferrableId, (titleId >> 8) & 0xFFFFF, nn::act::ACT_SLOT_CURRENT);\r\n\t\t\tg_ParamPack.transferableId = transferrableId;\r\n\r\n\t\t\tstrcpy(g_ParamPack.tzName, \"CEMU/Olive\"); // Should be nn::act::GetTimeZoneId\r\n\t\t\tg_ParamPack.utcOffset = (uint64_t)nn::act::GetUtcOffset() / 1'000'000;\r\n\r\n\t\t\tchar paramPackStr[1024];\r\n\t\t\tsnprintf(\r\n\t\t\t\tparamPackStr,\r\n\t\t\t\tsizeof(paramPackStr),\r\n\t\t\t\t\"\\\\%s\\\\%llu\\\\%s\\\\%u\\\\%s\\\\%u\\\\%s\\\\%d\\\\%s\\\\%d\\\\%s\\\\%d\\\\%s\\\\%d\\\\%s\\\\%d\\\\%s\\\\%d\\\\%s\\\\%u\\\\%s\\\\%d\\\\%s\\\\%llu\\\\\"\r\n\t\t\t\t\"%s\\\\%s\\\\%s\\\\%lld\\\\\",\r\n\t\t\t\t\"title_id\",\r\n\t\t\t\tg_ParamPack.titleId,\r\n\t\t\t\t\"access_key\",\r\n\t\t\t\tg_ParamPack.accessKey,\r\n\t\t\t\t\"platform_id\",\r\n\t\t\t\tg_ParamPack.platformId,\r\n\t\t\t\t\"region_id\",\r\n\t\t\t\tg_ParamPack.regionId,\r\n\t\t\t\t\"language_id\",\r\n\t\t\t\tg_ParamPack.languageId,\r\n\t\t\t\t\"country_id\",\r\n\t\t\t\tg_ParamPack.countryId,\r\n\t\t\t\t\"area_id\",\r\n\t\t\t\tg_ParamPack.areaId,\r\n\t\t\t\t\"network_restriction\",\r\n\t\t\t\tg_ParamPack.networkRestriction,\r\n\t\t\t\t\"friend_restriction\",\r\n\t\t\t\tg_ParamPack.friendRestriction,\r\n\t\t\t\t\"rating_restriction\",\r\n\t\t\t\tg_ParamPack.ratingRestriction,\r\n\t\t\t\t\"rating_organization\",\r\n\t\t\t\tg_ParamPack.ratingOrganization,\r\n\t\t\t\t\"transferable_id\",\r\n\t\t\t\tg_ParamPack.transferableId,\r\n\t\t\t\t\"tz_name\",\r\n\t\t\t\tg_ParamPack.tzName,\r\n\t\t\t\t\"utc_offset\",\r\n\t\t\t\tg_ParamPack.utcOffset);\r\n\t\t\tstd::string encodedParamPack = NCrypto::base64Encode(paramPackStr, strnlen(paramPackStr, 1024));\r\n\t\t\tmemset(&g_ParamPack.encodedParamPack, 0, sizeof(g_ParamPack.encodedParamPack));\r\n\t\t\tmemcpy(&g_ParamPack.encodedParamPack, encodedParamPack.data(), encodedParamPack.size());\r\n\r\n\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t}\r\n\r\n\t\tsint32 MakeDiscoveryRequest_AsyncRequestImpl(CurlRequestHelper& req, const char* reqUrl)\r\n\t\t{\r\n\t\t\tbool reqResult = req.submitRequest();\r\n\t\t\tlong httpCode = 0;\r\n\t\t\tcurl_easy_getinfo(req.getCURL(), CURLINFO_RESPONSE_CODE, &httpCode);\r\n\t\t\tif (!reqResult)\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed request: {} ({})\", reqUrl, httpCode);\r\n\t\t\t\tif (!(httpCode >= 400))\r\n\t\t\t\t\treturn OLV_RESULT_FAILED_REQUEST;\r\n\t\t\t}\r\n\r\n\t\t\tpugi::xml_document doc;\r\n\t\t\tif (!doc.load_buffer(req.getReceivedData().data(), req.getReceivedData().size()))\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Invalid XML in discovery service response\"));\r\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\r\n\t\t\t}\r\n\r\n\t\t\tsint32 responseError = CheckOliveResponse(doc);\r\n\t\t\tif (responseError < 0)\r\n\t\t\t\treturn responseError;\r\n\r\n\t\t\tif (httpCode != 200)\r\n\t\t\t\treturn OLV_RESULT_STATUS(httpCode + 4000);\r\n\r\n\r\n\t\t\t/*\r\n\t\t\t\t<result>\r\n\t\t\t\t\t<has_error>0</has_error>\r\n\t\t\t\t\t<version>1</version>\r\n\t\t\t\t\t<endpoint>\r\n\t\t\t\t\t\t<host>api.olv.pretendo.cc</host>\r\n\t\t\t\t\t\t<api_host>api.olv.pretendo.cc</api_host>\r\n\t\t\t\t\t\t<portal_host>portal.olv.pretendo.cc</portal_host>\r\n\t\t\t\t\t\t<n3ds_host>ctr.olv.pretendo.cc</n3ds_host>\r\n\t\t\t\t\t</endpoint>\r\n\t\t\t\t</result>\r\n\t\t\t*/\r\n\r\n\t\t\tpugi::xml_node resultNode = doc.child(\"result\");\r\n\t\t\tif (!resultNode)\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Discovery response doesn't contain <result>\");\r\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\r\n\t\t\t}\r\n\r\n\t\t\tpugi::xml_node endpointNode = resultNode.child(\"endpoint\");\r\n\t\t\tif (!endpointNode)\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Discovery response doesn't contain <result><endpoint>\");\r\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\r\n\t\t\t}\r\n\r\n\t\t\t// Yes it only uses <host> and <portal_host>\r\n\t\t\tstd::string_view host = endpointNode.child_value(\"host\");\r\n\t\t\tstd::string_view portal_host = endpointNode.child_value(\"portal_host\");\r\n\r\n\t\t\tsnprintf(g_DiscoveryResults.apiEndpoint, sizeof(g_DiscoveryResults.apiEndpoint), \"https://%s\", host.data());\r\n\t\t\tsnprintf(g_DiscoveryResults.portalEndpoint, sizeof(g_DiscoveryResults.portalEndpoint), \"https://%s\", portal_host.data());\r\n\r\n\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t}\r\n\r\n\t\tsint32 MakeDiscoveryRequest_AsyncRequest(CurlRequestHelper& req, const char* reqUrl, coreinit::OSEvent* requestDoneEvent)\r\n\t\t{\r\n\t\t\tsint32 res = MakeDiscoveryRequest_AsyncRequestImpl(req, reqUrl);\r\n\t\t\tcoreinit::OSSignalEvent(requestDoneEvent);\r\n\t\t\treturn res;\r\n\t\t}\r\n\r\n\t\tsint32 MakeDiscoveryRequest()\r\n\t\t{\r\n\t\t\t// =============================================================================\r\n\t\t\t// Discovery request | https://discovery.olv.nintendo.net/v1/endpoint\r\n\t\t\t// =============================================================================\r\n\r\n\t\t\tCurlRequestHelper req;\r\n\t\t\tstd::string requestUrl;\r\n\t\t\tswitch (ActiveSettings::GetNetworkService())\r\n\t\t\t{\r\n\t\t\t\tcase NetworkService::Pretendo:\r\n\t\t\t\t\trequestUrl = PretendoURLs::OLVURL;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase NetworkService::Custom:\r\n\t\t\t\t\trequestUrl = GetNetworkConfig().urls.OLV.GetValue();\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase NetworkService::Nintendo:\r\n\t\t\t\tdefault:\r\n\t\t\t\t\trequestUrl = NintendoURLs::OLVURL;\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\r\n\t\t\treq.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);\r\n\t\t\tInitializeOliveRequest(req);\r\n\r\n\t\t\tStackAllocator<coreinit::OSEvent> requestDoneEvent;\r\n\t\t\tcoreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);\r\n\t\t\tstd::future<sint32> requestRes = std::async(std::launch::async, MakeDiscoveryRequest_AsyncRequest, std::ref(req), requestUrl.c_str(), requestDoneEvent.GetPointer());\r\n\t\t\tcoreinit::OSWaitEvent(&requestDoneEvent);\r\n\r\n\t\t\treturn requestRes.get();\r\n\t\t}\r\n\r\n\t\tsint32 Initialize(nn::olv::InitializeParam* pParam)\r\n\t\t{\r\n\t\t\tif (g_IsInitialized)\r\n\t\t\t\treturn OLV_RESULT_ALREADY_INITIALIZED;\r\n\r\n\t\t\tif (!pParam->m_Work)\r\n\t\t\t{\r\n\t\t\t\tg_IsInitialized = false;\r\n\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\t\t\t}\r\n\r\n\t\t\tif (pParam->m_WorkSize < 0x10000)\r\n\t\t\t{\r\n\t\t\t\tg_IsInitialized = false;\r\n\t\t\t\treturn OLV_RESULT_INVALID_SIZE;\r\n\t\t\t}\r\n\r\n\t\t\tuint32_t accessKey;\r\n\t\t\tint32_t olvAccessKeyStatus = GetOlvAccessKey(&accessKey);\r\n\t\t\tif (olvAccessKeyStatus < 0)\r\n\t\t\t{\r\n\t\t\t\tg_IsInitialized = false;\r\n\t\t\t\treturn olvAccessKeyStatus;\r\n\t\t\t}\r\n\r\n\t\t\tuint64_t tid = CafeSystem::GetForegroundTitleId();\r\n\t\t\tint32_t createParamPackResult = CreateParamPack(tid, accessKey);\r\n\t\t\tif (createParamPackResult < 0)\r\n\t\t\t{\r\n\t\t\t\tg_IsInitialized = false;\r\n\t\t\t\treturn createParamPackResult;\r\n\t\t\t}\r\n\r\n\t\t\tg_IsInitialized = true;\r\n\r\n\t\t\tif(ActiveSettings::GetNetworkService() == NetworkService::Nintendo)\r\n\t\t\t{\r\n\t\t\t\t// since the official Miiverse was shut down, use local post archive instead\r\n\t\t\t\tg_IsOnlineMode = true;\r\n\t\t\t\tg_IsOfflineDBMode = true;\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tif ((pParam->m_Flags & InitializeParam::FLAG_OFFLINE_MODE) == 0)\r\n\t\t\t{\r\n\t\t\t\tg_IsOnlineMode = true;\r\n\r\n\t\t\t\tindependentServiceToken_t token;\r\n\t\t\t\tsint32 res = (sint32)nn::act::AcquireIndependentServiceToken(&token, OLV_CLIENT_ID, 0);\r\n\t\t\t\tif (res < 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tg_IsInitialized = false;\r\n\t\t\t\t\treturn res;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Assuming we're always a production WiiU (non-dev)\r\n\t\t\t\tuint32 uniqueId = (CafeSystem::GetForegroundTitleId() >> 8) & 0xFFFFF;\r\n\r\n\t\t\t\tchar versionBuffer[32];\r\n\t\t\t\tsnprintf(versionBuffer, sizeof(versionBuffer), \"%d.%d.%d\", OLV_VERSION_MAJOR, OLV_VERSION_MINOR, OLV_VERSION_PATCH);\r\n\t\t\t\tsnprintf(g_DiscoveryResults.userAgent, sizeof(g_DiscoveryResults.userAgent), \"%s/%s-%s/%d\", \"WiiU\", \"POLV\", versionBuffer, uniqueId);\r\n\r\n\t\t\t\tmemcpy(g_DiscoveryResults.serviceToken, token.token, sizeof(g_DiscoveryResults.serviceToken));\r\n\r\n\t\t\t\tsint32 discoveryRes = MakeDiscoveryRequest();\r\n\t\t\t\tif (discoveryRes < 0)\r\n\t\t\t\t\tg_IsInitialized = false;\r\n\r\n\t\t\t\treturn discoveryRes;\r\n\t\t\t}\r\n\r\n\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t}\r\n\r\n\t\tsint32 InitializePortalApp(nn::olv::PortalAppParam* pPortalAppParam, nn::olv::InitializeParam* pInitializeParam)\r\n\t\t{\r\n\t\t\tsint32 result = Initialize(pInitializeParam);\r\n\t\t\tif (result != OLV_RESULT_SUCCESS)\r\n\t\t\t\treturn result;\r\n\r\n\t\t\tmemcpy(pPortalAppParam->m_ParamPack, g_ParamPack.encodedParamPack, sizeof(g_ParamPack.encodedParamPack));\r\n\t\t\tmemcpy(pPortalAppParam->m_ServiceToken, g_DiscoveryResults.serviceToken, sizeof(g_DiscoveryResults.serviceToken));\r\n\r\n\t\t\tsnprintf(reinterpret_cast<char*>(pPortalAppParam->m_StartUrl), sizeof(pPortalAppParam->m_StartUrl),\r\n\t\t\t\t\"%s/titles/show?src=menu\", g_DiscoveryResults.portalEndpoint);\r\n\r\n\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t}\r\n\r\n\t\tnamespace Report\r\n\t\t{\r\n\t\t\tuint32 GetReportTypes()\r\n\t\t\t{\r\n\t\t\t\treturn g_ReportTypes;\r\n\t\t\t}\r\n\r\n\t\t\tvoid SetReportTypes(uint32 reportTypes)\r\n\t\t\t{\r\n\t\t\t\tg_ReportTypes = reportTypes | 0x1000;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tbool IsInitialized()\r\n\t\t{\r\n\t\t\treturn g_IsInitialized;\r\n\t\t}\r\n\t}\r\n}\r"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_InitializeTypes.h",
    "content": "#pragma once\r\n\r\n#include \"Cemu/ncrypto/ncrypto.h\"\r\n#include \"config/ActiveSettings.h\"\r\n\r\n#include \"Cafe/OS/libs/nn_olv/nn_olv_Common.h\"\r\n#include \"Cafe/OS/libs/coreinit/coreinit_MCP.h\"\r\n\r\n\r\nnamespace nn\r\n{\r\n\tnamespace olv\r\n\t{\r\n\r\n\t\tclass InitializeParam\r\n\t\t{\r\n\t\tpublic:\r\n\t\t\tstatic const inline uint32 FLAG_OFFLINE_MODE = (1 << 0);\r\n\r\n\t\t\tInitializeParam()\r\n\t\t\t{\r\n\t\t\t\tthis->m_Flags = 0;\r\n\t\t\t\tthis->m_ReportTypes = 7039;\r\n\t\t\t\tthis->m_SysArgsSize = 0;\r\n\t\t\t\tthis->m_Work = MEMPTR<uint8_t>(nullptr);\r\n\t\t\t\tthis->m_SysArgs = MEMPTR<const void>(nullptr);\r\n\t\t\t\tthis->m_WorkSize = 0;\r\n\t\t\t}\r\n\t\t\tstatic InitializeParam* __ctor(InitializeParam* _this)\r\n\t\t\t{\r\n\t\t\t\tif (!_this)\r\n\t\t\t\t{\r\n\t\t\t\t\tassert_dbg(); // DO NOT CONTINUE, SHOULD NEVER HAPPEN\r\n\t\t\t\t\treturn nullptr;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t\treturn new (_this) InitializeParam();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetFlags(uint32 flags)\r\n\t\t\t{\r\n\t\t\t\tthis->m_Flags = flags;\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetFlags(InitializeParam* _this, uint32 flags)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetFlags(flags);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetWork(MEMPTR<uint8_t> pWorkData, uint32 workDataSize)\r\n\t\t\t{\r\n\t\t\t\tif (!pWorkData)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\t\t\t\tif (workDataSize < 0x10000)\r\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\t\tthis->m_Work = pWorkData;\r\n\t\t\t\tthis->m_WorkSize = workDataSize;\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic uint32 __SetWork(InitializeParam* _this, MEMPTR<uint8> pWorkData, uint32 workDataSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetWork(pWorkData, workDataSize);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetReportTypes(uint32 reportTypes)\r\n\t\t\t{\r\n\t\t\t\tthis->m_ReportTypes = reportTypes;\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetReportTypes(InitializeParam* _this, uint32 reportTypes)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetReportTypes(reportTypes);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetSysArgs(MEMPTR<const void> pSysArgs, uint32 sysArgsSize)\r\n\t\t\t{\r\n\t\t\t\tif (!pSysArgs)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (!sysArgsSize)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\tthis->m_SysArgs = pSysArgs;\r\n\t\t\t\tthis->m_SysArgsSize = sysArgsSize;\r\n\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetSysArgs(InitializeParam* _this, MEMPTR<const void> pSysArgs, uint32 sysArgsSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetSysArgs(pSysArgs, sysArgsSize);\r\n\t\t\t}\r\n\r\n\t\t\tuint32be m_Flags;\r\n\t\t\tuint32be m_ReportTypes;\r\n\t\t\tMEMPTR<uint8_t> m_Work;\r\n\t\t\tuint32be m_WorkSize;\r\n\t\t\tMEMPTR<const void> m_SysArgs;\r\n\t\t\tuint32be m_SysArgsSize;\r\n\t\t\tchar unk[0x28];\r\n\t\t};\r\n\t\tstatic_assert(sizeof(nn::olv::InitializeParam) == 0x40, \"sizeof(nn::olv::InitializeParam) != 0x40\");\r\n\r\n\t\tclass PortalAppParam\r\n\t\t{\r\n\t\tpublic:\r\n\t\t\tPortalAppParam()\r\n\t\t\t{\r\n\t\t\t\tm_ParamPack[0] = 0;\r\n\t\t\t\tm_ServiceToken[0] = 0;\r\n\t\t\t\tm_StartUrl[0] = 0;\r\n\t\t\t}\r\n\t\t\tstatic PortalAppParam* __ctor(PortalAppParam* _this)\r\n\t\t\t{\r\n\t\t\t\tif (!_this)\r\n\t\t\t\t{\r\n\t\t\t\t\tassert_dbg(); // DO NOT CONTINUE, SHOULD NEVER HAPPEN\r\n\t\t\t\t\treturn nullptr;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t\treturn new (_this) PortalAppParam();\r\n\t\t\t}\r\n\r\n\t\t\tuint8be* GetParamPack()\r\n\t\t\t{\r\n\t\t\t\treturn m_ParamPack;\r\n\t\t\t}\r\n\t\t\tstatic uint8be* __GetParamPack(PortalAppParam* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetParamPack();\r\n\t\t\t}\r\n\r\n\t\t\tuint8be* GetServiceToken()\r\n\t\t\t{\r\n\t\t\t\treturn m_ServiceToken;\r\n\t\t\t}\r\n\t\t\tstatic uint8be* __GetServiceToken(PortalAppParam* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetServiceToken();\r\n\t\t\t}\r\n\r\n\t\t\tuint8be* GetStartUrl()\r\n\t\t\t{\r\n\t\t\t\treturn m_StartUrl;\r\n\t\t\t}\r\n\t\t\tstatic uint8be* __GetStartUrl(PortalAppParam* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetStartUrl();\r\n\t\t\t}\r\n\r\n\t\tpublic:\r\n\t\t\t/* +0x1A5C3C */ uint8be m_ParamPack[0x200];\r\n\t\t\t/* +0x1A663B */ uint8be m_ServiceToken[0x201]; // IndependentServiceToken for Miiverse title\r\n\t\t\t/* +0x1A5E3C */ uint8be m_StartUrl[0x7ff]; // https://portal-us.olv.nintendo.net/titles/show?src=menu\r\n\t\t};\r\n\r\n\t\tnamespace Report\r\n\t\t{\r\n\t\t\tuint32 GetReportTypes();\r\n\t\t\tvoid SetReportTypes(uint32 reportTypes);\r\n\t\t}\r\n\r\n\t\tbool IsInitialized();\r\n\t\tsint32 Initialize(nn::olv::InitializeParam* pParam);\r\n\t\tsint32 InitializePortalApp(nn::olv::PortalAppParam* pPortalAppParam, nn::olv::InitializeParam* pInitializeParam);\r\n\r\n\t\tstatic void loadOliveInitializeTypes()\r\n\t\t{\r\n\t\t\tcafeExportRegisterFunc(Initialize, \"nn_olv\", \"Initialize__Q2_2nn3olvFPCQ3_2nn3olv15InitializeParam\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(IsInitialized, \"nn_olv\", \"IsInitialized__Q2_2nn3olvFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(Report::GetReportTypes, \"nn_olv\", \"GetReportTypes__Q3_2nn3olv6ReportFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(Report::SetReportTypes, \"nn_olv\", \"SetReportTypes__Q3_2nn3olv6ReportFUi\", LogType::NN_OLV);\r\n\r\n\t\t\tcafeExportRegisterFunc(InitializeParam::__ctor, \"nn_olv\", \"__ct__Q3_2nn3olv15InitializeParamFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(InitializeParam::__SetFlags, \"nn_olv\", \"SetFlags__Q3_2nn3olv15InitializeParamFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(InitializeParam::__SetWork, \"nn_olv\", \"SetWork__Q3_2nn3olv15InitializeParamFPUcUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(InitializeParam::__SetReportTypes, \"nn_olv\", \"SetReportTypes__Q3_2nn3olv15InitializeParamFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(InitializeParam::__SetSysArgs, \"nn_olv\", \"SetSysArgs__Q3_2nn3olv15InitializeParamFPCvUi\", LogType::NN_OLV);\r\n\r\n\t\t\tcafeExportRegisterFunc(InitializePortalApp, \"nn_olv\", \"InitializePortalApp__Q3_2nn3olv6hiddenFPQ4_2nn3olv6hidden14PortalAppParamPCQ3_2nn3olv15InitializeParam\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(PortalAppParam::__ctor, \"nn_olv\", \"__ct__Q4_2nn3olv6hidden14PortalAppParamFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(PortalAppParam::__GetParamPack, \"nn_olv\", \"GetParamPack__Q4_2nn3olv6hidden14PortalAppParamCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(PortalAppParam::__GetServiceToken, \"nn_olv\", \"GetServiceToken__Q4_2nn3olv6hidden14PortalAppParamCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(PortalAppParam::__GetStartUrl, \"nn_olv\", \"GetStartUrl__Q4_2nn3olv6hidden14PortalAppParamCFv\", LogType::NN_OLV);\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.cpp",
    "content": "#include \"nn_olv_Common.h\"\n#include \"nn_olv_PostTypes.h\"\n#include \"nn_olv_OfflineDB.h\"\n#include \"Cemu/ncrypto/ncrypto.h\" // for base64 encoder/decoder\n#include \"util/helpers/helpers.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/CafeSystem.h\"\n#include <pugixml.hpp>\n#include <zlib.h>\n#include <zarchive/zarchivereader.h>\n\nnamespace nn\n{\n\tnamespace olv\n\t{\n\t\tstd::mutex g_offlineDBMutex;\n\t\tbool g_offlineDBInitialized = false;\n\t\tZArchiveReader* g_offlineDBArchive{nullptr};\n\n\t\tvoid OfflineDB_LazyInit()\n\t\t{\n\t\t\tstd::scoped_lock _l(g_offlineDBMutex);\n\t\t\tif(g_offlineDBInitialized)\n\t\t\t\treturn;\n\t\t\t// open archive\n\t\t\tg_offlineDBArchive = ZArchiveReader::OpenFromFile(ActiveSettings::GetUserDataPath(\"resources/miiverse/OfflineDB.zar\"));\n\t\t\tif(!g_offlineDBArchive)\n\t\t\t\tcemuLog_log(LogType::Force, \"Offline miiverse posts are not available\");\n\t\t\tg_offlineDBInitialized = true;\n\t\t}\n\n\t\tvoid OfflineDB_Shutdown()\n\t\t{\n\t\t\tstd::scoped_lock _l(g_offlineDBMutex);\n\t\t\tif(!g_offlineDBInitialized)\n\t\t\t\treturn;\n\t\t\tdelete g_offlineDBArchive;\n\t\t\tg_offlineDBInitialized = false;\n\t\t}\n\n\t\tbool CheckForOfflineDBFile(const char* filePath, uint32* fileSize)\n\t\t{\n\t\t\tif(!g_offlineDBArchive)\n\t\t\t\treturn false;\n\t\t\tZArchiveNodeHandle fileHandle = g_offlineDBArchive->LookUp(filePath);\n\t\t\tif (!g_offlineDBArchive->IsFile(fileHandle))\n\t\t\t\treturn false;\n\t\t\tif(fileSize)\n\t\t\t\t*fileSize = g_offlineDBArchive->GetFileSize(fileHandle);\n\t\t\treturn true;\n\t\t}\n\n\t\tbool LoadOfflineDBFile(const char* filePath, std::vector<uint8>& fileData)\n\t\t{\n\t\t\tfileData.clear();\n\t\t\tif(!g_offlineDBArchive)\n\t\t\t\treturn false;\n\t\t\tZArchiveNodeHandle fileHandle = g_offlineDBArchive->LookUp(filePath);\n\t\t\tif (!g_offlineDBArchive->IsFile(fileHandle))\n\t\t\t\treturn false;\n\t\t\tfileData.resize(g_offlineDBArchive->GetFileSize(fileHandle));\n\t\t\tg_offlineDBArchive->ReadFromFile(fileHandle, 0, fileData.size(), fileData.data());\n\t\t\treturn true;\n\t\t}\n\n\t\tvoid TryLoadCompressedMemoImage(DownloadedPostData& downloadedPostData)\n\t\t{\n\t\t\tconst unsigned char tgaHeader_320x120_32BPP[] = {0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x1,0x78,0x0,0x20,0x8};\n\t\t\tstd::string memoImageFilename = fmt::format(\"memo/{}\", (char*)downloadedPostData.downloadedDataBase.postId);\n\t\t\tstd::vector<uint8> bitmaskCompressedImg;\n\t\t\tif (!LoadOfflineDBFile(memoImageFilename.c_str(), bitmaskCompressedImg))\n\t\t\t\treturn;\n\t\t\tif (bitmaskCompressedImg.size() != (320*120)/8)\n\t\t\t\treturn;\n\t\t\tstd::vector<uint8> decompressedImage;\n\t\t\tdecompressedImage.resize(sizeof(tgaHeader_320x120_32BPP) + 320 * 120 * 4);\n\t\t\tmemcpy(decompressedImage.data(), tgaHeader_320x120_32BPP, sizeof(tgaHeader_320x120_32BPP));\n\t\t\tuint8* pOut = decompressedImage.data() + sizeof(tgaHeader_320x120_32BPP);\n\t\t\tfor(int i=0; i<320*120; i++)\n\t\t\t{\n\t\t\t\tbool isWhite = (bitmaskCompressedImg[i/8] & (1 << (i%8))) != 0;\n\t\t\t\tif(isWhite)\n\t\t\t\t{\n\t\t\t\t\tpOut[0] = pOut[1] = pOut[2] = pOut[3] = 0xFF;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tpOut[0] = pOut[1] = pOut[2] = 0;\n\t\t\t\t\tpOut[3] = 0xFF;\n\t\t\t\t}\n\t\t\t\tpOut += 4;\n\t\t\t}\n\t\t\t// store compressed image\n\t\t\tuLongf compressedDestLen = 40960;\n\t\t\tint r = compress((uint8*)downloadedPostData.downloadedDataBase.compressedMemoBody, &compressedDestLen, decompressedImage.data(), decompressedImage.size());\n\t\t\tif( r != Z_OK)\n\t\t\t\treturn;\n\t\t\tdownloadedPostData.downloadedDataBase.compressedMemoBodySize = compressedDestLen;\n\t\t\tdownloadedPostData.downloadedDataBase.SetFlag(DownloadedDataBase::FLAGS::HAS_BODY_MEMO);\n\t\t}\n\n\t\tvoid CheckForExternalImage(DownloadedPostData& downloadedPostData)\n\t\t{\n\t\t\tstd::string externalImageFilename = fmt::format(\"image/{}.jpg\", (char*)downloadedPostData.downloadedDataBase.postId);\n\t\t\tuint32 fileSize;\n\t\t\tif (!CheckForOfflineDBFile(externalImageFilename.c_str(), &fileSize))\n\t\t\t\treturn;\n\t\t\tstrcpy((char*)downloadedPostData.downloadedDataBase.externalImageDataUrl, externalImageFilename.c_str());\n\t\t\tdownloadedPostData.downloadedDataBase.SetFlag(DownloadedDataBase::FLAGS::HAS_EXTERNAL_IMAGE);\n\t\t\tdownloadedPostData.downloadedDataBase.externalImageDataSize = fileSize;\n\t\t}\n\n\t\tnnResult _Async_OfflineDB_DownloadPostDataListParam_DownloadPostDataList(coreinit::OSEvent* event, DownloadedTopicData* downloadedTopicData, DownloadedPostData* downloadedPostData, uint32be* postCountOut, uint32 maxCount, DownloadPostDataListParam* param)\n\t\t{\n\t\t\tstdx::scope_exit _se([&](){coreinit::OSSignalEvent(event);});\n\n\t\t\tuint64 titleId = CafeSystem::GetForegroundTitleId();\n\n\t\t\tmemset(downloadedTopicData, 0, sizeof(DownloadedTopicData));\n\t\t\tmemset(downloadedPostData, 0, sizeof(DownloadedPostData) * maxCount);\n\t\t\t*postCountOut = 0;\n\n\t\t\tconst char* postXmlFilename = nullptr;\n\t\t\tif(titleId == 0x0005000010143400 || titleId == 0x0005000010143500 || titleId == 0x0005000010143600)\n\t\t\t\tpostXmlFilename = \"PostList_WindWakerHD.xml\";\n\n\t\t\tif (!postXmlFilename)\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\n\t\t\t// load post XML\n\t\t\tstd::vector<uint8> xmlData;\n\t\t\tif (!LoadOfflineDBFile(postXmlFilename, xmlData))\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\tpugi::xml_document doc;\n\t\t\tpugi::xml_parse_result result = doc.load_buffer(xmlData.data(), xmlData.size());\n\t\t\tif (!result)\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t// collect list of all post xml nodes\n\t\t\tstd::vector<pugi::xml_node> postXmlNodes;\n\t\t\tfor (pugi::xml_node postNode = doc.child(\"posts\").child(\"post\"); postNode; postNode = postNode.next_sibling(\"post\"))\n\t\t\t\tpostXmlNodes.push_back(postNode);\n\n\t\t\t// randomly select up to maxCount posts\n\t\t\tsrand(GetTickCount());\n\t\t\tuint32 postCount = 0;\n\t\t\twhile(!postXmlNodes.empty() && postCount < maxCount)\n\t\t\t{\n\t\t\t\tuint32 index = rand() % postXmlNodes.size();\n\t\t\t\tpugi::xml_node& postNode = postXmlNodes[index];\n\n\t\t\t\tauto& addedPost = downloadedPostData[postCount];\n\t\t\t\tmemset(&addedPost, 0, sizeof(DownloadedPostData));\n\t\t\t\tif (!ParseXML_DownloadedPostData(addedPost, postNode) )\n\t\t\t\t\tcontinue;\n\t\t\t\tTryLoadCompressedMemoImage(addedPost);\n\t\t\t\tCheckForExternalImage(addedPost);\n\t\t\t\tpostCount++;\n\t\t\t\t// remove from post list\n\t\t\t\tpostXmlNodes[index] = postXmlNodes.back();\n\t\t\t\tpostXmlNodes.pop_back();\n\t\t\t}\n\t\t\t*postCountOut = postCount;\n\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult OfflineDB_DownloadPostDataListParam_DownloadPostDataList(DownloadedTopicData* downloadedTopicData, DownloadedPostData* downloadedPostData, uint32be* postCountOut, uint32 maxCount, DownloadPostDataListParam* param)\n\t\t{\n\t\t\tOfflineDB_LazyInit();\n\n\t\t\tmemset(downloadedTopicData, 0, sizeof(DownloadedTopicData));\n\t\t\tdownloadedTopicData->communityId = param->communityId;\n\t\t\t*postCountOut = 0;\n\n\t\t\tif(param->_HasFlag(DownloadPostDataListParam::FLAGS::SELF_ONLY))\n\t\t\t\treturn OLV_RESULT_SUCCESS; // the offlineDB doesn't contain any self posts\n\n\t\t\tStackAllocator<coreinit::OSEvent> doneEvent;\n\t\t\tcoreinit::OSInitEvent(&doneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);\n\t\t\tauto asyncTask = std::async(std::launch::async, _Async_OfflineDB_DownloadPostDataListParam_DownloadPostDataList, doneEvent.GetPointer(), downloadedTopicData, downloadedPostData, postCountOut, maxCount, param);\n\t\t\tcoreinit::OSWaitEvent(&doneEvent);\n\t\t\tnnResult r = asyncTask.get();\n\t\t\treturn r;\n\t\t}\n\n\t\tnnResult _Async_OfflineDB_DownloadPostDataListParam_DownloadExternalImageData(coreinit::OSEvent* event, DownloadedDataBase* _this, void* imageDataOut, uint32be* imageSizeOut, uint32 maxSize)\n\t\t{\n\t\t\tstdx::scope_exit _se([&](){coreinit::OSSignalEvent(event);});\n\n\t\t\tif (!_this->TestFlags(_this, DownloadedDataBase::FLAGS::HAS_EXTERNAL_IMAGE))\n\t\t\t\treturn OLV_RESULT_MISSING_DATA;\n\n\t\t\t// not all games may use JPEG files?\n\t\t\tstd::string externalImageFilename = fmt::format(\"image/{}.jpg\", (char*)_this->postId);\n\t\t\tstd::vector<uint8> jpegData;\n\t\t\tif (!LoadOfflineDBFile(externalImageFilename.c_str(), jpegData))\n\t\t\t\treturn OLV_RESULT_FAILED_REQUEST;\n\n\t\t\tmemcpy(imageDataOut, jpegData.data(), jpegData.size());\n\t\t\t*imageSizeOut = jpegData.size();\n\n\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult OfflineDB_DownloadPostDataListParam_DownloadExternalImageData(DownloadedDataBase* _this, void* imageDataOut, uint32be* imageSizeOut, uint32 maxSize)\n\t\t{\n\t\t\tStackAllocator<coreinit::OSEvent> doneEvent;\n\t\t\tcoreinit::OSInitEvent(&doneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);\n\t\t\tauto asyncTask = std::async(std::launch::async, _Async_OfflineDB_DownloadPostDataListParam_DownloadExternalImageData, doneEvent.GetPointer(), _this, imageDataOut, imageSizeOut, maxSize);\n\t\t\tcoreinit::OSWaitEvent(&doneEvent);\n\t\t\tnnResult r = asyncTask.get();\n\t\t\treturn r;\n\t\t}\n\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_OfflineDB.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/nn_common.h\"\n#include \"nn_olv_Common.h\"\n\nnamespace nn\n{\n\tnamespace olv\n\t{\n\t\tvoid OfflineDB_Init();\n\t\tvoid OfflineDB_Shutdown();\n\n\t\tnnResult OfflineDB_DownloadPostDataListParam_DownloadPostDataList(DownloadedTopicData* downloadedTopicData, DownloadedPostData* downloadedPostData, uint32be* postCountOut, uint32 maxCount, DownloadPostDataListParam* param);\n\t\tnnResult OfflineDB_DownloadPostDataListParam_DownloadExternalImageData(DownloadedDataBase* _this, void* imageDataOut, uint32be* imageSizeOut, uint32 maxSize);\n\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_PostTypes.cpp",
    "content": "#include \"Cafe/OS/libs/nn_olv/nn_olv_Common.h\"\n#include \"nn_olv_PostTypes.h\"\n#include \"nn_olv_OfflineDB.h\"\n#include \"Cemu/ncrypto/ncrypto.h\" // for base64 decoder\n#include \"util/helpers/helpers.h\"\n#include <pugixml.hpp>\n#include <zlib.h>\n\nnamespace nn\n{\n\tnamespace olv\n\t{\n\t\tbool ParseXml_DownloadedDataBase(DownloadedDataBase& obj, pugi::xml_node& xmlNode)\n\t\t{\n\t\t\t// todo:\n\t\t\t// painting with url?\n\n\t\t\tpugi::xml_node tokenNode;\n\t\t\tif(tokenNode = xmlNode.child(\"body\"); tokenNode)\n\t\t\t{\n\t\t\t\tobj.bodyTextLength = SetStringUC2(obj.bodyText, tokenNode.child_value(), true);\n\t\t\t\tif(obj.bodyTextLength > 0)\n\t\t\t\t\tobj.SetFlag(DownloadedDataBase::FLAGS::HAS_BODY_TEXT);\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"topic_tag\"); tokenNode)\n\t\t\t{\n\t\t\t\tSetStringUC2(obj.topicTag, tokenNode.child_value(), true);\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"feeling_id\"); tokenNode)\n\t\t\t{\n\t\t\t\tobj.feeling = ConvertString<sint8>(tokenNode.child_value());\n\t\t\t\tif(obj.feeling < 0 || obj.feeling >= 5)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] DownloadedDataBase::ParseXml: feeling_id out of range\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"id\"); tokenNode)\n\t\t\t{\n\t\t\t\tstd::string_view id_sv = tokenNode.child_value();\n\t\t\t\tif(id_sv.size() > 22)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] DownloadedDataBase::ParseXml: id too long\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tmemcpy(obj.postId, id_sv.data(), id_sv.size());\n\t\t\t\tobj.postId[id_sv.size()] = '\\0';\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"is_autopost\"); tokenNode)\n\t\t\t{\n\t\t\t\tuint8 isAutopost = ConvertString<sint8>(tokenNode.child_value());\n\t\t\t\tif(isAutopost == 1)\n\t\t\t\t\tobj.SetFlag(DownloadedDataBase::FLAGS::IS_AUTOPOST);\n\t\t\t\telse if(isAutopost == 0)\n\t\t\t\t\tobj.SetFlag(DownloadedDataBase::FLAGS::IS_NOT_AUTOPOST);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] DownloadedDataBase::ParseXml: is_autopost has invalid value\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"empathy_added\"); tokenNode)\n\t\t\t{\n\t\t\t\tif(ConvertString<sint32>(tokenNode.child_value()) > 0)\n\t\t\t\t\tobj.SetFlag(DownloadedDataBase::FLAGS::HAS_EMPATHY_ADDED);\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"is_spoiler\"); tokenNode)\n\t\t\t{\n\t\t\t\tif(ConvertString<sint32>(tokenNode.child_value()) > 0)\n\t\t\t\t\tobj.SetFlag(DownloadedDataBase::FLAGS::IS_SPOILER);\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"mii\"); tokenNode)\n\t\t\t{\n\t\t\t\tstd::vector<uint8> miiData = NCrypto::base64Decode(tokenNode.child_value());\n\t\t\t\tif(miiData.size() != 96)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] DownloadedSystemTopicData mii data is not valid (incorrect size)\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tmemcpy(obj.miiData, miiData.data(), miiData.size());\n\t\t\t\tobj.SetFlag(DownloadedDataBase::FLAGS::HAS_MII_DATA);\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"pid\"); tokenNode)\n\t\t\t{\n\t\t\t\tobj.userPid = ConvertString<uint32>(tokenNode.child_value());\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"screen_name\"); tokenNode)\n\t\t\t{\n\t\t\t\tSetStringUC2(obj.miiNickname, tokenNode.child_value(), true);\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"region_id\"); tokenNode)\n\t\t\t{\n\t\t\t\tobj.regionId = ConvertString<uint32>(tokenNode.child_value());\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"platform_id\"); tokenNode)\n\t\t\t{\n\t\t\t\tobj.platformId = ConvertString<uint8>(tokenNode.child_value());\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"language_id\"); tokenNode)\n\t\t\t{\n\t\t\t\tobj.languageId = ConvertString<uint8>(tokenNode.child_value());\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"country_id\"); tokenNode)\n\t\t\t{\n\t\t\t\tobj.countryId = ConvertString<uint8>(tokenNode.child_value());\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"painting\"); tokenNode)\n\t\t\t{\n\t\t\t\tif(pugi::xml_node subNode = tokenNode.child(\"content\"); subNode)\n\t\t\t\t{\n\t\t\t\t\tstd::vector<uint8> paintingData = NCrypto::base64Decode(subNode.child_value());\n\t\t\t\t\tif (paintingData.size() > 0xA000)\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] DownloadedDataBase painting content is too large\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tmemcpy(obj.compressedMemoBody, paintingData.data(), paintingData.size());\n\t\t\t\t\tobj.SetFlag(DownloadedDataBase::FLAGS::HAS_BODY_MEMO);\n\t\t\t\t}\n\t\t\t\tif(pugi::xml_node subNode = tokenNode.child(\"size\"); subNode)\n\t\t\t\t{\n\t\t\t\t\tobj.compressedMemoBodySize = ConvertString<uint32>(subNode.child_value());\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"app_data\"); tokenNode)\n\t\t\t{\n\t\t\t\tstd::vector<uint8> appData = NCrypto::base64Decode(tokenNode.child_value());\n\t\t\t\tif (appData.size() > 0x400)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] DownloadedDataBase AppData is too large\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tmemcpy(obj.appData, appData.data(), appData.size());\n\t\t\t\tobj.appDataLength = appData.size();\n\t\t\t\tobj.SetFlag(DownloadedDataBase::FLAGS::HAS_APP_DATA);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tbool ParseXML_DownloadedPostData(DownloadedPostData& obj, pugi::xml_node& xmlNode)\n\t\t{\n\t\t\tpugi::xml_node tokenNode;\n\t\t\tif(tokenNode = xmlNode.child(\"community_id\"); tokenNode)\n\t\t\t\tobj.communityId = ConvertString<uint32>(tokenNode.child_value());\n\t\t\tif(tokenNode = xmlNode.child(\"empathy_count\"); tokenNode)\n\t\t\t\tobj.empathyCount = ConvertString<uint32>(tokenNode.child_value());\n\t\t\tif(tokenNode = xmlNode.child(\"reply_count\"); tokenNode)\n\t\t\t\tobj.commentCount = ConvertString<uint32>(tokenNode.child_value());\n\t\t\treturn ParseXml_DownloadedDataBase(obj.downloadedDataBase, xmlNode);\n\t\t}\n\n\t\tbool ParseXML_DownloadedSystemPostData(hidden::DownloadedSystemPostData& obj, pugi::xml_node& xmlNode)\n\t\t{\n\t\t\tpugi::xml_node tokenNode;\n\t\t\tif(tokenNode = xmlNode.child(\"title_id\"); tokenNode)\n\t\t\t\tobj.titleId = ConvertString<uint64>(tokenNode.child_value());\n\t\t\treturn ParseXML_DownloadedPostData(obj.downloadedPostData, xmlNode);\n\t\t}\n\n\t\tbool ParseXML_DownloadedTopicData(DownloadedTopicData& obj, pugi::xml_node& xmlNode)\n\t\t{\n\t\t\tpugi::xml_node tokenNode;\n\t\t\tif(tokenNode = xmlNode.child(\"community_id\"); tokenNode)\n\t\t\t\tobj.communityId = ConvertString<uint32>(tokenNode.child_value());\n\t\t\treturn true;\n\t\t}\n\n\t\tbool Parse_DownloadedSystemTopicData(hidden::DownloadedSystemTopicData& obj, pugi::xml_node& xmlNode)\n\t\t{\n\t\t\tif(!ParseXML_DownloadedTopicData(obj.downloadedTopicData, xmlNode))\n\t\t\t\treturn false;\n\t\t\tpugi::xml_node tokenNode;\n\t\t\tif(tokenNode = xmlNode.child(\"name\"); tokenNode)\n\t\t\t{\n\t\t\t\tSetStringUC2(obj.titleText, tokenNode.child_value(), true);\n\t\t\t\tobj.downloadedTopicData.SetFlag(DownloadedTopicData::FLAGS::HAS_TITLE);\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"is_recommended\"); tokenNode)\n\t\t\t{\n\t\t\t\tuint32 isRecommended = ConvertString<uint32>(tokenNode.child_value());\n\t\t\t\tif(isRecommended != 0)\n\t\t\t\t\tobj.downloadedTopicData.SetFlag(DownloadedTopicData::FLAGS::IS_RECOMMENDED);\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"title_id\"); tokenNode)\n\t\t\t{\n\t\t\t\tobj.titleId = ConvertString<uint64>(tokenNode.child_value());\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"title_ids\"); tokenNode)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\tif(tokenNode = xmlNode.child(\"icon\"); tokenNode)\n\t\t\t{\n\t\t\t\tstd::vector<uint8> iconData = NCrypto::base64Decode(tokenNode.child_value());\n\t\t\t\tif(iconData.size() > sizeof(obj.iconData))\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] DownloadedSystemTopicData icon data is not valid\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tobj.iconDataSize = iconData.size();\n\t\t\t\tmemcpy(obj.iconData, iconData.data(), iconData.size());\n\t\t\t\tobj.downloadedTopicData.SetFlag(DownloadedTopicData::FLAGS::HAS_ICON_DATA);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tuint32 GetSystemTopicDataListFromRawData(hidden::DownloadedSystemTopicDataList* downloadedSystemTopicDataList, hidden::DownloadedSystemPostData* downloadedSystemPostData, uint32be* postCountOut, uint32 postCountMax, void* xmlData, uint32 xmlDataSize)\n\t\t{\n\t\t\t// copy xmlData into a temporary buffer since load_buffer_inplace will modify it\n\t\t\tstd::vector<uint8> buffer;\n\t\t\tbuffer.resize(xmlDataSize);\n\t\t\tmemcpy(buffer.data(), xmlData, xmlDataSize);\n\t\t\tpugi::xml_document doc;\n\t\t\tif (!doc.load_buffer_inplace(buffer.data(), xmlDataSize, pugi::parse_default, pugi::xml_encoding::encoding_utf8))\n\t\t\t\treturn -1;\n\n\t\t\tmemset(downloadedSystemTopicDataList, 0, sizeof(hidden::DownloadedSystemTopicDataList));\n\t\t\tdownloadedSystemTopicDataList->topicDataNum = 0;\n\t\t\n\t\t\tcemu_assert_debug(doc.child(\"result\").child(\"topics\"));\n\n\t\t\tsize_t postCount = 0;\n\n\t\t\t// parse topics\n\t\t\tfor (pugi::xml_node topicsChildNode : doc.child(\"result\").child(\"topics\").children())\n\t\t\t{\n\t\t\t\tconst char* name = topicsChildNode.name();\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"topicsChildNode.name() = {}\", name);\n\t\t\t\tif (strcmp(topicsChildNode.name(), \"topic\"))\n\t\t\t\t\tcontinue;\n\t\t\t\t// parse topic\n\t\t\t\tif(downloadedSystemTopicDataList->topicDataNum > 10)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] DownloadedSystemTopicDataList exceeded maximum topic count (10)\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tauto& topicEntry = downloadedSystemTopicDataList->topicData[downloadedSystemTopicDataList->topicDataNum];\n\t\t\t\tmemset(&topicEntry, 0, sizeof(hidden::DownloadedSystemTopicDataList::DownloadedSystemTopicWrapped));\n\t\t\t\tParse_DownloadedSystemTopicData(topicEntry.downloadedSystemTopicData, topicsChildNode);\n\t\t\t\tdownloadedSystemTopicDataList->topicDataNum = downloadedSystemTopicDataList->topicDataNum + 1;\n\n\t\t\t\ttopicEntry.postDataNum = 0;\n\t\t\t\t// parse all posts within the current topic\n\t\t\t\tfor (pugi::xml_node personNode : topicsChildNode.child(\"people\").children(\"person\"))\n\t\t\t\t{\n\t\t\t\t\tfor (pugi::xml_node postNode : personNode.child(\"posts\").children(\"post\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tif(postCount >= postCountMax)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] GetSystemTopicDataListFromRawData exceeded maximum post count\");\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tauto& postEntry = downloadedSystemPostData[postCount];\n\t\t\t\t\t\tmemset(&postEntry, 0, sizeof(hidden::DownloadedSystemPostData));\n\t\t\t\t\t\tbool r = ParseXML_DownloadedSystemPostData(postEntry, postNode);\n\t\t\t\t\t\tif(!r)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] DownloadedSystemPostData parsing failed\");\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpostCount++;\n\t\t\t\t\t\t// add post to topic\n\t\t\t\t\t\tif(topicEntry.postDataNum >= hidden::DownloadedSystemTopicDataList::MAX_POSTS_PER_TOPIC)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"[Olive-XML] DownloadedSystemTopicDataList has too many posts for a single topic (up to {})\", hidden::DownloadedSystemTopicDataList::MAX_POSTS_PER_TOPIC);\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttopicEntry.postDataList[topicEntry.postDataNum] = &postEntry;\n\t\t\t\t\t\ttopicEntry.postDataNum = topicEntry.postDataNum + 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t*postCountOut = postCount;\n\t\t\treturn 0;\n\t\t}\n\n\t\tnnResult DownloadedDataBase::DownloadExternalImageData(DownloadedDataBase* _this, void* imageDataOut, uint32be* imageSizeOut, uint32 maxSize)\n\t\t{\n\t\t\tif(g_IsOfflineDBMode)\n\t\t\t\treturn OfflineDB_DownloadPostDataListParam_DownloadExternalImageData(_this, imageDataOut, imageSizeOut, maxSize);\n\n\t\t\tif(!g_IsOnlineMode)\n\t\t\t\treturn OLV_RESULT_OFFLINE_MODE_REQUEST;\n\t\t\tif (!TestFlags(_this, FLAGS::HAS_EXTERNAL_IMAGE))\n\t\t\t\treturn OLV_RESULT_MISSING_DATA;\n\n\t\t\tcemuLog_logDebug(LogType::Force, \"DownloadedDataBase::DownloadExternalImageData not implemented\");\n\t\t\treturn OLV_RESULT_FAILED_REQUEST; // placeholder error\n\t\t}\n\n\t\tnnResult DownloadPostDataListParam::GetRawDataUrl(DownloadPostDataListParam* _this, char* urlOut, uint32 urlMaxSize)\n\t\t{\n\t\t\tif(!g_IsOnlineMode)\n\t\t\t\treturn OLV_RESULT_OFFLINE_MODE_REQUEST;\n\t\t\t//if(_this->communityId == 0)\n\t\t\t//\tcemuLog_log(LogType::Force, \"DownloadPostDataListParam::GetRawDataUrl called with invalid communityId\");\n\n\t\t\t// get base url\n\t\t\tstd::string baseUrl;\n\t\t\tbaseUrl.append(g_DiscoveryResults.apiEndpoint);\n\t\t\t//baseUrl.append(fmt::format(\"/v1/communities/{}/posts\", (uint32)_this->communityId));\n\t\t\tcemu_assert_debug(_this->communityId == 0);\n\t\t\tbaseUrl.append(fmt::format(\"/v1/posts.search\", (uint32)_this->communityId));\n\n\t\t\t// \"v1/posts.search\"\n\n\t\t\t// build parameter string\n\t\t\tstd::string params;\n\n\t\t\t// this function behaves differently for the Wii U menu? Where it can lookup posts by titleId?\n\t\t\tif(_this->titleId != 0)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented(); // Wii U menu mode\n\t\t\t}\n\n\t\t\t// todo: Generic parameters. Which includes: language_id, limit, type=text/memo\n\n\t\t\t// handle postIds\n\t\t\tfor(size_t i=0; i<_this->MAX_NUM_POST_ID; i++)\n\t\t\t{\n\t\t\t\tif(_this->searchPostId[i].str[0] == '\\0')\n\t\t\t\t\tcontinue;\n\t\t\t\tcemu_assert_unimplemented(); // todo\n\t\t\t\t// todo - postId parameter\n\t\t\t\t// handle filters\n\t\t\t\tif(_this->_HasFlag(DownloadPostDataListParam::FLAGS::WITH_MII))\n\t\t\t\t\tparams.append(\"&with_mii=1\");\n\t\t\t\tif(_this->_HasFlag(DownloadPostDataListParam::FLAGS::WITH_EMPATHY))\n\t\t\t\t\tparams.append(\"&with_empathy_added=1\");\n\t\t\t\tif(_this->bodyTextMaxLength != 0)\n\t\t\t\t\tparams.append(fmt::format(\"&max_body_length={}\", _this->bodyTextMaxLength));\n\t\t\t}\n\n\t\t\tif(_this->titleId != 0)\n\t\t\t\tparams.append(fmt::format(\"&title_id={}\", (uint64)_this->titleId));\n\n\t\t\tif (_this->_HasFlag(DownloadPostDataListParam::FLAGS::FRIENDS_ONLY))\n\t\t\t\tparams.append(\"&by=friend\");\n\t\t\tif (_this->_HasFlag(DownloadPostDataListParam::FLAGS::FOLLOWERS_ONLY))\n\t\t\t\tparams.append(\"&by=followings\");\n\t\t\tif (_this->_HasFlag(DownloadPostDataListParam::FLAGS::SELF_ONLY))\n\t\t\t\tparams.append(\"&by=self\");\n\n\t\t\tif(!params.empty())\n\t\t\t\tparams[0] = '?'; // replace the leading ampersand\n\n\t\t\tbaseUrl.append(params);\n\t\t\tif(baseUrl.size()+1 > urlMaxSize)\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\n\t\t\tstrncpy(urlOut, baseUrl.c_str(), urlMaxSize);\n\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t}\n\n\t\tnnResult DownloadPostDataList(DownloadedTopicData* downloadedTopicData, DownloadedPostData* downloadedPostData, uint32be* postCountOut, uint32 maxCount, DownloadPostDataListParam* param)\n\t\t{\n\t\t\tif(g_IsOfflineDBMode)\n\t\t\t\treturn OfflineDB_DownloadPostDataListParam_DownloadPostDataList(downloadedTopicData, downloadedPostData, postCountOut, maxCount, param);\n\t\t\tmemset(downloadedTopicData, 0, sizeof(DownloadedTopicData));\n\t\t\tdownloadedTopicData->communityId = param->communityId;\n\t\t\t*postCountOut = 0;\n\n\t\t\tchar urlBuffer[2048];\n\t\t\tif (NN_RESULT_IS_FAILURE(DownloadPostDataListParam::GetRawDataUrl(param, urlBuffer, sizeof(urlBuffer))))\n\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\n\n\t\t\t/*\n\t\t\tCurlRequestHelper req;\n\t\t\treq.initate(urlBuffer, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);\n\t\t\tInitializeOliveRequest(req);\n\t\t\tbool reqResult = req.submitRequest();\n\t\t\tif (!reqResult)\n\t\t\t{\n\t\t\t\tlong httpCode = 0;\n\t\t\t\tcurl_easy_getinfo(req.getCURL(), CURLINFO_RESPONSE_CODE, &httpCode);\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed request: {} ({})\", urlBuffer, httpCode);\n\t\t\t\tif (!(httpCode >= 400))\n\t\t\t\t\treturn OLV_RESULT_FAILED_REQUEST;\n\t\t\t}\n\t\t\tpugi::xml_document doc;\n\t\t\tif (!doc.load_buffer(req.getReceivedData().data(), req.getReceivedData().size()))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Invalid XML in community download response\"));\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\n\t\t\t}\n\t\t\t*/\n\n\t\t\t*postCountOut = 0;\n\n\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t}\n\n\t\tvoid loadOlivePostAndTopicTypes()\n\t\t{\n\t\t\tcafeExportRegisterFunc(GetSystemTopicDataListFromRawData, \"nn_olv\", \"GetSystemTopicDataListFromRawData__Q3_2nn3olv6hiddenFPQ4_2nn3olv6hidden29DownloadedSystemTopicDataListPQ4_2nn3olv6hidden24DownloadedSystemPostDataPUiUiPCUcT4\", LogType::NN_OLV);\n\n\t\t\t// DownloadedDataBase getters\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::TestFlags, \"nn_olv\", \"TestFlags__Q3_2nn3olv18DownloadedDataBaseCFUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetUserPid, \"nn_olv\", \"GetUserPid__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetPostDate, \"nn_olv\", \"GetPostDate__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetFeeling, \"nn_olv\", \"GetFeeling__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetRegionId, \"nn_olv\", \"GetRegionId__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetPlatformId, \"nn_olv\", \"GetPlatformId__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetLanguageId, \"nn_olv\", \"GetLanguageId__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetCountryId, \"nn_olv\", \"GetCountryId__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetExternalUrl, \"nn_olv\", \"GetExternalUrl__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetMiiData1, \"nn_olv\", \"GetMiiData__Q3_2nn3olv18DownloadedDataBaseCFP12FFLStoreData\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetMiiNickname, \"nn_olv\", \"GetMiiNickname__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetBodyText, \"nn_olv\", \"GetBodyText__Q3_2nn3olv18DownloadedDataBaseCFPwUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetBodyMemo, \"nn_olv\", \"GetBodyMemo__Q3_2nn3olv18DownloadedDataBaseCFPUcPUiUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetTopicTag, \"nn_olv\", \"GetTopicTag__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetAppData, \"nn_olv\", \"GetAppData__Q3_2nn3olv18DownloadedDataBaseCFPUcPUiUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetAppDataSize, \"nn_olv\", \"GetAppDataSize__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetPostId, \"nn_olv\", \"GetPostId__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetMiiData2, \"nn_olv\", \"GetMiiData__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::DownloadExternalImageData, \"nn_olv\", \"DownloadExternalImageData__Q3_2nn3olv18DownloadedDataBaseCFPvPUiUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedDataBase::GetExternalImageDataSize, \"nn_olv\", \"GetExternalImageDataSize__Q3_2nn3olv18DownloadedDataBaseCFv\", LogType::NN_OLV);\n\n\t\t\t// DownloadedPostData getters\n\t\t\tcafeExportRegisterFunc(DownloadedPostData::GetCommunityId, \"nn_olv\", \"GetCommunityId__Q3_2nn3olv18DownloadedPostDataCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedPostData::GetEmpathyCount, \"nn_olv\", \"GetEmpathyCount__Q3_2nn3olv18DownloadedPostDataCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedPostData::GetCommentCount, \"nn_olv\", \"GetCommentCount__Q3_2nn3olv18DownloadedPostDataCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadedPostData::GetPostId, \"nn_olv\", \"GetPostId__Q3_2nn3olv18DownloadedPostDataCFv\", LogType::NN_OLV);\n\n\t\t\t// DownloadedSystemPostData getters\n\t\t\tcafeExportRegisterFunc(hidden::DownloadedSystemPostData::GetTitleId, \"nn_olv\", \"GetTitleId__Q4_2nn3olv6hidden24DownloadedSystemPostDataCFv\", LogType::NN_OLV);\n\n\t\t\t// DownloadedTopicData getters\n\t\t\tcafeExportRegisterFunc(DownloadedTopicData::GetCommunityId, \"nn_olv\", \"GetCommunityId__Q3_2nn3olv19DownloadedTopicDataCFv\", LogType::NN_OLV);\n\n\t\t\t// DownloadedSystemTopicData getters\n\t\t\tcafeExportRegisterFunc(hidden::DownloadedSystemTopicData::TestFlags, \"nn_olv\", \"TestFlags__Q4_2nn3olv6hidden25DownloadedSystemTopicDataCFUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(hidden::DownloadedSystemTopicData::GetTitleId, \"nn_olv\", \"GetTitleId__Q4_2nn3olv6hidden25DownloadedSystemTopicDataCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(hidden::DownloadedSystemTopicData::GetTitleIdNum, \"nn_olv\", \"GetTitleIdNum__Q4_2nn3olv6hidden25DownloadedSystemTopicDataCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(hidden::DownloadedSystemTopicData::GetTitleText, \"nn_olv\", \"GetTitleText__Q4_2nn3olv6hidden25DownloadedSystemTopicDataCFPwUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(hidden::DownloadedSystemTopicData::GetTitleIconData, \"nn_olv\", \"GetTitleIconData__Q4_2nn3olv6hidden25DownloadedSystemTopicDataCFPUcPUiUi\", LogType::NN_OLV);\n\n\t\t\t// DownloadedSystemTopicDataList getters\n\t\t\tcafeExportRegisterFunc(hidden::DownloadedSystemTopicDataList::GetDownloadedSystemTopicDataNum, \"nn_olv\", \"GetDownloadedSystemTopicDataNum__Q4_2nn3olv6hidden29DownloadedSystemTopicDataListCFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(hidden::DownloadedSystemTopicDataList::GetDownloadedSystemPostDataNum, \"nn_olv\", \"GetDownloadedSystemPostDataNum__Q4_2nn3olv6hidden29DownloadedSystemTopicDataListCFi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(hidden::DownloadedSystemTopicDataList::GetDownloadedSystemTopicData, \"nn_olv\", \"GetDownloadedSystemTopicData__Q4_2nn3olv6hidden29DownloadedSystemTopicDataListCFi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(hidden::DownloadedSystemTopicDataList::GetDownloadedSystemPostData, \"nn_olv\", \"GetDownloadedSystemPostData__Q4_2nn3olv6hidden29DownloadedSystemTopicDataListCFiT1\", LogType::NN_OLV);\n\n\t\t\t// DownloadPostDataListParam constructor and getters\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::Construct, \"nn_olv\", \"__ct__Q3_2nn3olv25DownloadPostDataListParamFv\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::SetFlags, \"nn_olv\", \"SetFlags__Q3_2nn3olv25DownloadPostDataListParamFUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::SetLanguageId, \"nn_olv\", \"SetLanguageId__Q3_2nn3olv25DownloadPostDataListParamFUc\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::SetCommunityId, \"nn_olv\", \"SetCommunityId__Q3_2nn3olv25DownloadPostDataListParamFUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::SetSearchKey, \"nn_olv\", \"SetSearchKey__Q3_2nn3olv25DownloadPostDataListParamFPCwUc\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::SetSearchKeySingle, \"nn_olv\", \"SetSearchKey__Q3_2nn3olv25DownloadPostDataListParamFPCw\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::SetSearchPid, \"nn_olv\", \"SetSearchPid__Q3_2nn3olv25DownloadPostDataListParamFUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::SetPostId, \"nn_olv\", \"SetPostId__Q3_2nn3olv25DownloadPostDataListParamFPCcUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::SetPostDate, \"nn_olv\", \"SetPostDate__Q3_2nn3olv25DownloadPostDataListParamFL\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::SetPostDataMaxNum, \"nn_olv\", \"SetPostDataMaxNum__Q3_2nn3olv25DownloadPostDataListParamFUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::SetBodyTextMaxLength, \"nn_olv\", \"SetBodyTextMaxLength__Q3_2nn3olv25DownloadPostDataListParamFUi\", LogType::NN_OLV);\n\n\t\t\t// URL and downloading functions\n\t\t\tcafeExportRegisterFunc(DownloadPostDataListParam::GetRawDataUrl, \"nn_olv\", \"GetRawDataUrl__Q3_2nn3olv25DownloadPostDataListParamCFPcUi\", LogType::NN_OLV);\n\t\t\tcafeExportRegisterFunc(DownloadPostDataList, \"nn_olv\", \"DownloadPostDataList__Q2_2nn3olvFPQ3_2nn3olv19DownloadedTopicDataPQ3_2nn3olv18DownloadedPostDataPUiUiPCQ3_2nn3olv25DownloadPostDataListParam\", LogType::NN_OLV);\n\n\t\t}\n\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_PostTypes.h",
    "content": "#pragma once\n#include <zlib.h>\n#include \"nn_olv_Common.h\"\n\nnamespace nn\n{\n\tnamespace olv\n\t{\n\t\tstruct DownloadedDataBase\n\t\t{\n\t\t\tenum class FLAGS : uint32\n\t\t\t{\n\t\t\t\tHAS_BODY_TEXT = 0x01,\n\t\t\t\tHAS_BODY_MEMO = 0x02,\n\t\t\t\tHAS_EXTERNAL_IMAGE = 0x04,\n\t\t\t\tHAS_EXTERNAL_BINARY_DATA = 0x08,\n\t\t\t\tHAS_MII_DATA = 0x10,\n\t\t\t\tHAS_EXTERNAL_URL = 0x20,\n\t\t\t\tHAS_APP_DATA = 0x40,\n\t\t\t\tHAS_EMPATHY_ADDED = 0x80,\n\t\t\t\tIS_AUTOPOST = 0x100,\n\t\t\t\tIS_SPOILER = 0x200,\n\t\t\t\tIS_NOT_AUTOPOST = 0x400, // autopost flag was explicitly set to false\n\t\t\t};\n\n\t\t\tvoid Reset()\n\t\t\t{\n\t\t\t\tmemset(this, 0, sizeof(DownloadedDataBase));\n\t\t\t}\n\n\t\t\tvoid SetFlag(FLAGS flag)\n\t\t\t{\n\t\t\t\tflags =  (FLAGS)((uint32)flags.value() | (uint32)flag);\n\t\t\t}\n\n\t\t\tbetype<FLAGS> flags;\n\t\t\tuint32be userPid;\n\t\t\tuint8be postId[32]; // string, up to 22 characters but the buffer is 32 bytes\n\t\t\tuint64be postDate;\n\t\t\tsint8be feeling;\n\t\t\tuint8be _padding0031[3];\n\t\t\tuint32be regionId;\n\t\t\tuint8be platformId;\n\t\t\tuint8be languageId;\n\t\t\tuint8be countryId;\n\t\t\tuint8be _padding003B;\n\t\t\tuint16be bodyText[256];\n\t\t\tuint32be bodyTextLength;\n\t\t\tuint8be compressedMemoBody[40960];\n\t\t\tuint32be compressedMemoBodySize;\n\t\t\tuint16be topicTag[152];\n\t\t\tuint8be appData[1024];\n\t\t\tuint32be appDataLength;\n\t\t\tuint8be externalBinaryUrl[256];\n\t\t\tuint32be externalBinaryDataSize;\n\t\t\tuint8be externalImageDataUrl[256];\n\t\t\tuint32be externalImageDataSize;\n\t\t\tuint8be externalURL[256];\n\t\t\tuint8be miiData[96];\n\t\t\tuint16be miiNickname[16];\n\t\t\tuint32be _paddingAB00[1344];\n\t\t\tuint32be uknC000_someVTableMaybe;\n\t\t\tuint32be uknC004;\n\n\t\t\t// getters\n\t\t\t// TestFlags__Q3_2nn3olv18DownloadedDataBaseCFUi\n\t\t\tstatic bool TestFlags(DownloadedDataBase* _this, DownloadedDataBase::FLAGS flag)\n\t\t\t{\n\t\t\t\treturn HAS_FLAG((uint32)_this->flags.value(), (uint32)flag);\n\t\t\t}\n\n\t\t\t// GetUserPid__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint32 GetUserPid(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\treturn _this->userPid;\n\t\t\t}\n\n\t\t\t// GetPostDate__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint64 GetPostDate(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\treturn _this->postDate;\n\t\t\t}\n\n\t\t\t// GetFeeling__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint32 GetFeeling(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\tif(_this->feeling >= 6)\n\t\t\t\t\treturn 0;\n\t\t\t\treturn _this->feeling;\n\t\t\t}\n\n\t\t\t// GetRegionId__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint32 GetRegionId(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\treturn _this->regionId;\n\t\t\t}\n\n\t\t\t// GetPlatformId__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint32 GetPlatformId(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\treturn _this->platformId;\n\t\t\t}\n\n\t\t\t// GetLanguageId__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint32 GetLanguageId(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\treturn _this->languageId;\n\t\t\t}\n\n\t\t\t// GetCountryId__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint32 GetCountryId(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\treturn _this->countryId;\n\t\t\t}\n\n\t\t\t// GetExternalUrl__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint8be* GetExternalUrl(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\tif (!TestFlags(_this, FLAGS::HAS_EXTERNAL_URL))\n\t\t\t\t\treturn nullptr;\n\t\t\t\treturn _this->externalURL;\n\t\t\t}\n\n\t\t\t// GetMiiData__Q3_2nn3olv18DownloadedDataBaseCFP12FFLStoreData\n\t\t\tstatic nnResult GetMiiData1(DownloadedDataBase* _this, void* miiDataOut)\n\t\t\t{\n\t\t\t\tif (!TestFlags(_this, FLAGS::HAS_MII_DATA))\n\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\n\t\t\t\tif (!miiDataOut)\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\n\t\t\t\tmemcpy(miiDataOut, _this->miiData, 96);\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// GetMiiData__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint8be* GetMiiData2(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\tif (!TestFlags(_this, FLAGS::HAS_MII_DATA))\n\t\t\t\t\treturn nullptr;\n\t\t\t\treturn _this->miiData;\n\t\t\t}\n\n\t\t\t// GetMiiNickname__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint16be* GetMiiNickname(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\tif (_this->miiNickname[0] == 0)\n\t\t\t\t\treturn nullptr;\n\t\t\t\treturn _this->miiNickname;\n\t\t\t}\n\n\t\t\t// GetBodyText__Q3_2nn3olv18DownloadedDataBaseCFPwUi\n\t\t\tstatic nnResult GetBodyText(DownloadedDataBase* _this, uint16be* bodyTextOut, uint32 maxLength)\n\t\t\t{\n\t\t\t\tif (!bodyTextOut)\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\n\t\t\t\tif (maxLength == 0)\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\n\t\t\t\tif (!TestFlags(_this, FLAGS::HAS_BODY_TEXT))\n\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\n\t\t\t\tmemset(bodyTextOut, 0, maxLength * sizeof(uint16));\n\t\t\t\tuint32 outputLength = std::min<uint32>(_this->bodyTextLength, maxLength);\n\t\t\t\tolv_wstrncpy((char16_t*)bodyTextOut, (char16_t*)_this->bodyText, outputLength);\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// GetBodyMemo__Q3_2nn3olv18DownloadedDataBaseCFPUcPUiUi\n\t\t\tstatic nnResult GetBodyMemo(DownloadedDataBase* _this, uint8be* bodyMemoOut, uint32* bodyMemoSizeOut, uint32 maxSize)\n\t\t\t{\n\t\t\t\tif (!bodyMemoOut)\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\n\t\t\t\tif (maxSize < 0x2582C)\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\n\t\t\t\tif (!TestFlags(_this, FLAGS::HAS_BODY_MEMO))\n\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\n\t\t\t\t// uncompress TGA\n\t\t\t\tuLongf decompressedSize = maxSize;\n\t\t\t\tif (uncompress((uint8*)bodyMemoOut, &decompressedSize, (uint8*)_this->compressedMemoBody, _this->compressedMemoBodySize) != Z_OK)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"DownloadedSystemTopicData::GetTitleIconData: uncompress failed\");\n\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD; // status\n\t\t\t\t}\n\t\t\t\tif(bodyMemoSizeOut)\n\t\t\t\t\t*bodyMemoSizeOut = decompressedSize;\n\t\t\t\t// todo - verify TGA header\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// GetTopicTag__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint16be* GetTopicTag(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\treturn _this->topicTag;\n\t\t\t}\n\n\t\t\t// GetAppData__Q3_2nn3olv18DownloadedDataBaseCFPUcPUiUi\n\t\t\tstatic nnResult GetAppData(DownloadedDataBase* _this, uint8be* appDataOut, uint32* appDataSizeOut, uint32 maxSize)\n\t\t\t{\n\t\t\t\tif (!appDataOut)\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\n\t\t\t\tif (!TestFlags(_this, FLAGS::HAS_APP_DATA))\n\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\n\t\t\t\tuint32 outputSize = std::min<uint32>(maxSize, _this->appDataLength);\n\t\t\t\tmemcpy(appDataOut, _this->appData, outputSize);\n\t\t\t\tif(appDataSizeOut)\n\t\t\t\t\t*appDataSizeOut = outputSize;\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// GetAppDataSize__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint32 GetAppDataSize(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\treturn _this->appDataLength;\n\t\t\t}\n\n\t\t\t// GetPostId__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint8be* GetPostId(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\treturn _this->postId;\n\t\t\t}\n\n\t\t\t// DownloadExternalImageData__Q3_2nn3olv18DownloadedDataBaseCFPvPUiUi\n\t\t\tstatic nnResult DownloadExternalImageData(DownloadedDataBase* _this, void* imageDataOut, uint32be* imageSizeOut, uint32 maxSize);\n\n\t\t\t// GetExternalImageDataSize__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t\tstatic uint32 GetExternalImageDataSize(DownloadedDataBase* _this)\n\t\t\t{\n\t\t\t\tif (!TestFlags(_this, FLAGS::HAS_EXTERNAL_IMAGE))\n\t\t\t\t\treturn 0;\n\t\t\t\treturn _this->externalImageDataSize;\n\t\t\t}\n\n\t\t\t// todo:\n\t\t\t// DownloadExternalImageData__Q3_2nn3olv18DownloadedDataBaseCFPvPUiUi (implement downloading)\n\t\t\t// DownloadExternalBinaryData__Q3_2nn3olv18DownloadedDataBaseCFPvPUiUi\n\t\t\t// GetExternalBinaryDataSize__Q3_2nn3olv18DownloadedDataBaseCFv\n\t\t};\n\n\t\tstatic_assert(sizeof(DownloadedDataBase) == 0xC008);\n\n\t\tstruct DownloadedPostData\n\t\t{\n\t\t\tDownloadedDataBase downloadedDataBase;\n\t\t\tuint32be communityId;\n\t\t\tuint32be empathyCount;\n\t\t\tuint32be commentCount;\n\t\t\tuint32be paddingC014[125]; // probably unused?\n\n\t\t\t// getters\n\t\t\t// GetCommunityId__Q3_2nn3olv18DownloadedPostDataCFv\n\t\t\tstatic uint32 GetCommunityId(DownloadedPostData* _this)\n\t\t\t{\n\t\t\t\treturn _this->communityId;\n\t\t\t}\n\n\t\t\t// GetEmpathyCount__Q3_2nn3olv18DownloadedPostDataCFv\n\t\t\tstatic uint32 GetEmpathyCount(DownloadedPostData* _this)\n\t\t\t{\n\t\t\t\treturn _this->empathyCount;\n\t\t\t}\n\n\t\t\t// GetCommentCount__Q3_2nn3olv18DownloadedPostDataCFv\n\t\t\tstatic uint32 GetCommentCount(DownloadedPostData* _this)\n\t\t\t{\n\t\t\t\treturn _this->commentCount;\n\t\t\t}\n\n\t\t\t// GetPostId__Q3_2nn3olv18DownloadedPostDataCFv\n\t\t\tstatic uint8be* GetPostId(DownloadedPostData* _this)\n\t\t\t{\n\t\t\t\treturn _this->downloadedDataBase.postId;\n\t\t\t}\n\n\t\t};\n\n\t\tstatic_assert(sizeof(DownloadedPostData) == 0xC208);\n\n\t\tstruct DownloadedTopicData\n\t\t{\n\t\t\tenum class FLAGS\n\t\t\t{\n\t\t\t\tIS_RECOMMENDED = 0x01,\n\t\t\t\tHAS_TITLE = 0x02,\n\t\t\t\tHAS_ICON_DATA = 0x04,\n\t\t\t};\n\t\t\tbetype<FLAGS> flags;\n\t\t\tuint32be communityId;\n\t\t\tint ukn[1022];\n\n\t\t\tvoid SetFlag(FLAGS flag)\n\t\t\t{\n\t\t\t\tflags = (FLAGS)((uint32)flags.value() | (uint32)flag);\n\t\t\t}\n\n\t\t\t// GetCommunityId__Q3_2nn3olv19DownloadedTopicDataCFv\n\t\t\tstatic uint32 GetCommunityId(DownloadedTopicData* _this)\n\t\t\t{\n\t\t\t\treturn _this->communityId;\n\t\t\t}\n\t\t};\n\n\t\tstatic_assert(sizeof(DownloadedTopicData) == 0x1000);\n\n\t\tnamespace hidden\n\t\t{\n\t\t\tstruct DownloadedSystemPostData\n\t\t\t{\n\t\t\t\tDownloadedPostData downloadedPostData;\n\t\t\t\tuint64be titleId;\n\t\t\t\tuint32be uknC210[124];\n\t\t\t\tuint32be uknC400;\n\t\t\t\tuint32be uknC404;\n\n\t\t\t\t// getters\n\t\t\t\t// GetTitleId__Q4_2nn3olv6hidden24DownloadedSystemPostDataCFv\n\t\t\t\tstatic uint64 GetTitleId(DownloadedSystemPostData* _this)\n\t\t\t\t{\n\t\t\t\t\treturn _this->titleId;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tstatic_assert(sizeof(DownloadedSystemPostData) == 0xC408);\n\n\t\t\tstruct DownloadedSystemTopicData\n\t\t\t{\n\t\t\t\tDownloadedTopicData downloadedTopicData;\n\t\t\t\tuint64be titleId;\n\t\t\t\tuint16be titleText[128];\n\t\t\t\tuint8be ukn1108[256];\n\t\t\t\tuint8be iconData[0x1002C];\n\t\t\t\tuint32be iconDataSize;\n\t\t\t\tuint64be titleIds[32];\n\t\t\t\tuint32be titleIdsCount;\n\t\t\t\tuint32be ukn1133C[1841];\n\n\t\t\t\t// implement getters as static methods for compatibility with CafeExportRegisterFunc()\n\t\t\t\t// TestFlags__Q4_2nn3olv6hidden25DownloadedSystemTopicDataCFUi\n\t\t\t\tstatic bool TestFlags(DownloadedSystemTopicData* _this, DownloadedTopicData::FLAGS flag)\n\t\t\t\t{\n\t\t\t\t\treturn HAS_FLAG((uint32)_this->downloadedTopicData.flags.value(), (uint32)flag);\n\t\t\t\t}\n\n\t\t\t\t// GetTitleId__Q4_2nn3olv6hidden25DownloadedSystemTopicDataCFv\n\t\t\t\tstatic uint64 GetTitleId(DownloadedSystemTopicData* _this)\n\t\t\t\t{\n\t\t\t\t\treturn _this->titleId;\n\t\t\t\t}\n\n\t\t\t\t// GetTitleIdNum__Q4_2nn3olv6hidden25DownloadedSystemTopicDataCFv\n\t\t\t\tstatic uint32 GetTitleIdNum(DownloadedSystemTopicData* _this)\n\t\t\t\t{\n\t\t\t\t\treturn _this->titleIdsCount;\n\t\t\t\t}\n\n\t\t\t\t// GetTitleText__Q4_2nn3olv6hidden25DownloadedSystemTopicDataCFPwUi\n\t\t\t\tstatic nnResult GetTitleText(DownloadedSystemTopicData* _this, uint16be* titleTextOut, uint32 maxLength)\n\t\t\t\t{\n\t\t\t\t\tif (!TestFlags(_this, DownloadedTopicData::FLAGS::HAS_TITLE))\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\n\t\t\t\t\tif (!titleTextOut)\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\n\t\t\t\t\tmemset(titleTextOut, 0, maxLength * sizeof(uint16be));\n\t\t\t\t\tif (maxLength > 128)\n\t\t\t\t\t\tmaxLength = 128;\n\t\t\t\t\tolv_wstrncpy((char16_t*)titleTextOut, (char16_t*)_this->titleText, maxLength);\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t\t}\n\n\t\t\t\t// GetTitleIconData__Q4_2nn3olv6hidden25DownloadedSystemTopicDataCFPUcPUiUi\n\t\t\t\tstatic nnResult GetTitleIconData(DownloadedSystemTopicData* _this, void* iconDataOut, uint32be* iconSizeOut, uint32 iconDataMaxSize)\n\t\t\t\t{\n\t\t\t\t\tif (!TestFlags(_this, DownloadedTopicData::FLAGS::HAS_ICON_DATA))\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\n\t\t\t\t\tif (!iconDataOut)\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\n\t\t\t\t\tif (iconDataMaxSize < 0x1002C)\n\t\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\n\t\t\t\t\tuLongf decompressedSize = iconDataMaxSize;\n\t\t\t\t\tif (uncompress((uint8*)iconDataOut, &decompressedSize, (uint8*)_this->iconData, _this->iconDataSize) != Z_OK)\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"DownloadedSystemTopicData::GetTitleIconData: uncompress failed\");\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD; // status\n\t\t\t\t\t}\n\t\t\t\t\t*iconSizeOut = decompressedSize;\n\t\t\t\t\t// todo - check for TGA\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tstatic_assert(sizeof(DownloadedSystemTopicData) == 0x13000);\n\n\t\t\tstruct DownloadedSystemTopicDataList\n\t\t\t{\n\t\t\t\tstatic constexpr size_t MAX_TOPIC_COUNT = 10;\n\t\t\t\tstatic constexpr size_t MAX_POSTS_PER_TOPIC = 300;\n\n\t\t\t\t// 0x134B8 sized wrapper of DownloadedSystemTopicData\n\t\t\t\tstruct DownloadedSystemTopicWrapped\n\t\t\t\t{\n\t\t\t\t\tDownloadedSystemTopicData downloadedSystemTopicData;\n\t\t\t\t\tuint32be postDataNum;\n\t\t\t\t\tMEMPTR<DownloadedSystemPostData> postDataList[MAX_POSTS_PER_TOPIC];\n\t\t\t\t\tuint32 uknPadding;\n\t\t\t\t};\n\t\t\t\tstatic_assert(offsetof(DownloadedSystemTopicWrapped, postDataNum) == 0x13000);\n\t\t\t\tstatic_assert(sizeof(DownloadedSystemTopicWrapped) == 0x134B8);\n\n\t\t\t\tstatic uint32 GetDownloadedSystemTopicDataNum(DownloadedSystemTopicDataList* _this)\n\t\t\t\t{\n\t\t\t\t\treturn _this->topicDataNum;\n\t\t\t\t};\n\n\t\t\t\tstatic uint32 GetDownloadedSystemPostDataNum(DownloadedSystemTopicDataList* _this, uint32 topicIndex)\n\t\t\t\t{\n\t\t\t\t\tif(topicIndex >= MAX_TOPIC_COUNT)\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\treturn _this->topicData[topicIndex].postDataNum;\n\t\t\t\t};\n\n\t\t\t\tstatic DownloadedSystemTopicData* GetDownloadedSystemTopicData(DownloadedSystemTopicDataList* _this, uint32 topicIndex)\n\t\t\t\t{\n\t\t\t\t\tif(topicIndex >= MAX_TOPIC_COUNT)\n\t\t\t\t\t\treturn nullptr;\n\t\t\t\t\treturn &_this->topicData[topicIndex].downloadedSystemTopicData;\n\t\t\t\t};\n\n\t\t\t\tstatic DownloadedSystemPostData* GetDownloadedSystemPostData(DownloadedSystemTopicDataList* _this, sint32 topicIndex, sint32 postIndex)\n\t\t\t\t{\n\t\t\t\t\tif (topicIndex >= MAX_TOPIC_COUNT || postIndex >= MAX_POSTS_PER_TOPIC)\n\t\t\t\t\t\treturn nullptr;\n\t\t\t\t\treturn _this->topicData[topicIndex].postDataList[postIndex];\n\t\t\t\t}\n\n\t\t\t\t// member variables\n\t\t\t\tuint32be topicDataNum;\n\t\t\t\tuint32be ukn4;\n\t\t\t\tDownloadedSystemTopicWrapped topicData[MAX_TOPIC_COUNT];\n\t\t\t\tuint32be uknC0F38[50];\n\t\t\t};\n\n\t\t\tstatic_assert(sizeof(DownloadedSystemTopicDataList) == 0xC1000);\n\t\t}\n\n\n\t\tstruct DownloadPostDataListParam\n\t\t{\n\t\t\tstatic constexpr size_t MAX_NUM_SEARCH_PID = 12;\n\t\t\tstatic constexpr size_t MAX_NUM_SEARCH_KEY = 5;\n\t\t\tstatic constexpr size_t MAX_NUM_POST_ID = 20;\n\n\t\t\tenum class FLAGS\n\t\t\t{\n\t\t\t\tFRIENDS_ONLY = 0x01, // friends only\n\t\t\t\tFOLLOWERS_ONLY = 0x02, // followers only\n\t\t\t\tSELF_ONLY = 0x04, // self only\n\t\t\t\tONLY_TYPE_TEXT = 0x08,\n\t\t\t\tONLY_TYPE_MEMO = 0x10,\n\t\t\t\tUKN_20 = 0x20,\n\t\t\t\tWITH_MII = 0x40, // with mii\n\t\t\t\tWITH_EMPATHY = 0x80, // with yeahs added\n\t\t\t\tUKN_100 = 0x100,\n\t\t\t\tUKN_200 = 0x200, // \"is_delay\" parameter\n\t\t\t\tUKN_400 = 0x400, // \"is_hot\" parameter\n\n\n\t\t\t};\n\n\t\t\tstruct SearchKey\n\t\t\t{\n\t\t\t\tuint16be str[152];\n\t\t\t};\n\n\t\t\tstruct PostId\n\t\t\t{\n\t\t\t\tchar str[32];\n\t\t\t};\n\n\t\t\tbetype<FLAGS> flags;\n\t\t\tuint32be communityId;\n\t\t\tuint32be searchPid[MAX_NUM_SEARCH_PID];\n\t\t\tuint8 languageId;\n\t\t\tuint8 hasLanguageId_039;\n\t\t\tuint8 padding03A[2];\n\t\t\tuint32be postDataMaxNum;\n\t\t\tSearchKey searchKeyArray[MAX_NUM_SEARCH_KEY];\n\t\t\tPostId searchPostId[MAX_NUM_POST_ID];\n\t\t\tuint64be postDate; // OSTime?\n\t\t\tuint64be titleId; // only used by System posts?\n\t\t\tuint32be bodyTextMaxLength;\n\t\t\tuint8 padding8C4[1852];\n\n\t\t\tbool _HasFlag(FLAGS flag)\n\t\t\t{\n\t\t\t\treturn ((uint32)flags.value() & (uint32)flag) != 0;\n\t\t\t}\n\n\t\t\tvoid _SetFlags(FLAGS flag)\n\t\t\t{\n\t\t\t\tflags = (FLAGS)((uint32)flags.value() | (uint32)flag);\n\t\t\t}\n\n\t\t\t// constructor and getters\n\t\t\t// __ct__Q3_2nn3olv25DownloadPostDataListParamFv\n\t\t\tstatic DownloadPostDataListParam* Construct(DownloadPostDataListParam* _this)\n\t\t\t{\n\t\t\t\tmemset(_this, 0, sizeof(DownloadPostDataListParam));\n\t\t\t\treturn _this;\n\t\t\t}\n\n\t\t\t// SetFlags__Q3_2nn3olv25DownloadPostDataListParamFUi\n\t\t\tstatic nnResult SetFlags(DownloadPostDataListParam* _this, FLAGS flags)\n\t\t\t{\n\t\t\t\t// todo - verify flag combos\n\t\t\t\t_this->flags = flags;\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// SetLanguageId__Q3_2nn3olv25DownloadPostDataListParamFUc\n\t\t\tstatic nnResult SetLanguageId(DownloadPostDataListParam* _this, uint8 languageId)\n\t\t\t{\n\t\t\t\t_this->languageId = languageId;\n\t\t\t\t_this->hasLanguageId_039 = 1;\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// SetCommunityId__Q3_2nn3olv25DownloadPostDataListParamFUi\n\t\t\tstatic nnResult SetCommunityId(DownloadPostDataListParam* _this, uint32 communityId)\n\t\t\t{\n\t\t\t\t_this->communityId = communityId;\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// SetSearchKey__Q3_2nn3olv25DownloadPostDataListParamFPCwUc\n\t\t\tstatic nnResult SetSearchKey(DownloadPostDataListParam* _this, const uint16be* searchKey, uint8 searchKeyIndex)\n\t\t\t{\n\t\t\t\tif( !searchKey )\n\t\t\t\t{\n\t\t\t\t\tmemset(&_this->searchKeyArray[searchKeyIndex], 0, sizeof(SearchKey));\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t\t}\n\t\t\t\tif (searchKeyIndex >= MAX_NUM_SEARCH_KEY)\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\n\t\t\t\tmemset(&_this->searchKeyArray[searchKeyIndex], 0, sizeof(SearchKey));\n\t\t\t\tif(olv_wstrnlen((const char16_t*)searchKey, 152) > 50)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"DownloadPostDataListParam::SetSearchKey: searchKey is too long\\n\");\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\n\t\t\t\t}\n\t\t\t\tSetStringUC2(_this->searchKeyArray[searchKeyIndex].str, searchKey);\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// SetSearchKey__Q3_2nn3olv25DownloadPostDataListParamFPCw\n\t\t\tstatic nnResult SetSearchKeySingle(DownloadPostDataListParam* _this, const uint16be* searchKey)\n\t\t\t{\n\t\t\t\tif (searchKey == nullptr)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_logDebug(LogType::NN_OLV, \"DownloadPostDataListParam::SetSearchKeySingle: searchKeySingle is Null\\n\");\t\t\t\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\n\t\t\t\t}\n\t\t\t\treturn SetSearchKey(_this, searchKey, 0);\n\t\t\t}\n\n\t\t\t// SetSearchPid__Q3_2nn3olv25DownloadPostDataListParamFUi\n\t\t\tstatic nnResult SetSearchPid(DownloadPostDataListParam* _this, uint32 searchPid)\n\t\t\t{\n\t\t\t\tif(_this->_HasFlag(FLAGS::FRIENDS_ONLY) || _this->_HasFlag(FLAGS::FOLLOWERS_ONLY) || _this->_HasFlag(FLAGS::SELF_ONLY))\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\n\t\t\t\t_this->searchPid[0] = searchPid;\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// SetPostId__Q3_2nn3olv25DownloadPostDataListParamFPCcUi\n\t\t\tstatic nnResult SetPostId(DownloadPostDataListParam* _this, const char* postId, uint32 postIdIndex)\n\t\t\t{\n\t\t\t\tif (postIdIndex >= MAX_NUM_POST_ID)\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\n\t\t\t\tmemset(&_this->searchPostId[postIdIndex], 0, sizeof(PostId));\n\t\t\t\tif (strlen(postId) > 22)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"DownloadPostDataListParam::SetPostId: postId is too long\\n\");\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\n\t\t\t\t}\n\t\t\t\tstrcpy(_this->searchPostId[postIdIndex].str, postId);\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// SetPostDate__Q3_2nn3olv25DownloadPostDataListParamFL\n\t\t\tstatic nnResult SetPostDate(DownloadPostDataListParam* _this, uint64 postDate)\n\t\t\t{\n\t\t\t\t_this->postDate = postDate;\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// SetPostDataMaxNum__Q3_2nn3olv25DownloadPostDataListParamFUi\n\t\t\tstatic nnResult SetPostDataMaxNum(DownloadPostDataListParam* _this, uint32 postDataMaxNum)\n\t\t\t{\n\t\t\t\tif(postDataMaxNum == 0)\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\n\t\t\t\t_this->postDataMaxNum = postDataMaxNum;\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// SetBodyTextMaxLength__Q3_2nn3olv25DownloadPostDataListParamFUi\n\t\t\tstatic nnResult SetBodyTextMaxLength(DownloadPostDataListParam* _this, uint32 bodyTextMaxLength)\n\t\t\t{\n\t\t\t\tif(bodyTextMaxLength >= 256)\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\n\t\t\t\t_this->bodyTextMaxLength = bodyTextMaxLength;\n\t\t\t\treturn OLV_RESULT_SUCCESS;\n\t\t\t}\n\n\t\t\t// GetRawDataUrl__Q3_2nn3olv25DownloadPostDataListParamCFPcUi\n\t\t\tstatic nnResult GetRawDataUrl(DownloadPostDataListParam* _this, char* urlOut, uint32 urlMaxSize);\n\t\t};\n\n\t\tstatic_assert(sizeof(DownloadPostDataListParam) == 0x1000);\n\n\t\t// parsing functions\n\t\tbool ParseXML_DownloadedPostData(DownloadedPostData& obj, pugi::xml_node& xmlNode);\n\n\t\tvoid loadOlivePostAndTopicTypes();\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp",
    "content": "#include \"nn_olv_UploadCommunityTypes.h\"\r\n#include <algorithm>\r\n\r\nnamespace nn\r\n{\r\n\tnamespace olv\r\n\t{\r\n\r\n\t\tsint32 UploadCommunityData_AsyncRequestImpl(CurlRequestHelper& req, const char* reqUrl,\r\n\t\t\tUploadedCommunityData* pOutData, UploadCommunityDataParam const* pParam);\r\n\r\n\t\tsint32 UploadCommunityData_AsyncRequest(CurlRequestHelper& req, const char* reqUrl, coreinit::OSEvent* requestDoneEvent,\r\n\t\t\tUploadedCommunityData* pOutData, UploadCommunityDataParam const* pParam\r\n\t\t)\r\n\t\t{\r\n\t\t\tsint32 res = UploadCommunityData_AsyncRequestImpl(req, reqUrl, pOutData, pParam);\r\n\t\t\tcoreinit::OSSignalEvent(requestDoneEvent);\r\n\t\t\treturn res;\r\n\t\t}\r\n\r\n\t\tsint32 UploadCommunityData(UploadedCommunityData* pOutData, UploadCommunityDataParam const* pParam)\r\n\t\t{\r\n\t\t\tif (!nn::olv::g_IsInitialized)\r\n\t\t\t\treturn OLV_RESULT_NOT_INITIALIZED;\r\n\t\t\t\r\n\t\t\tif (!nn::olv::g_IsOnlineMode)\r\n\t\t\t\treturn OLV_RESULT_OFFLINE_MODE_REQUEST;\r\n\r\n\t\t\tif (!pParam)\r\n\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\tif (pOutData)\r\n\t\t\t\tUploadedCommunityData::Clean(pOutData);\r\n\r\n\t\t\tchar requestUrl[512];\r\n\t\t\tif (pParam->flags & UploadCommunityDataParam::FLAG_DELETION)\r\n\t\t\t{\r\n\t\t\t\tif (!pParam->communityId)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\tsnprintf(requestUrl, sizeof(requestUrl), \"%s/v1/communities/%u.delete\", g_DiscoveryResults.apiEndpoint, pParam->communityId.value());\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tif (pParam->communityId)\r\n\t\t\t\t\tsnprintf(requestUrl, sizeof(requestUrl), \"%s/v1/communities/%u\", g_DiscoveryResults.apiEndpoint, pParam->communityId.value());\r\n\t\t\t\telse\r\n\t\t\t\t\tsnprintf(requestUrl, sizeof(requestUrl), \"%s/v1/communities\", g_DiscoveryResults.apiEndpoint);\r\n\t\t\t}\r\n\r\n\t\t\t\r\n\t\t\tCurlRequestHelper req;\r\n\t\t\treq.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);\r\n\t\t\tInitializeOliveRequest(req);\r\n\r\n\t\t\tStackAllocator<coreinit::OSEvent> requestDoneEvent;\r\n\t\t\tcoreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);\r\n\t\t\tstd::future<sint32> requestRes = std::async(std::launch::async, UploadCommunityData_AsyncRequest, std::ref(req), requestUrl, requestDoneEvent.GetPointer(), pOutData, pParam);\r\n\t\t\tcoreinit::OSWaitEvent(&requestDoneEvent);\r\n\r\n\t\t\treturn requestRes.get();\r\n\t\t}\r\n\r\n\t\tsint32 UploadCommunityData(UploadCommunityDataParam const* pParam)\r\n\t\t{\r\n\t\t\treturn UploadCommunityData(nullptr, pParam);\r\n\t\t}\r\n\r\n\t\tsint32 UploadCommunityData_AsyncRequestImpl(CurlRequestHelper& req, const char* reqUrl,\r\n\t\t\tUploadedCommunityData* pOutData, UploadCommunityDataParam const* pParam)\r\n\t\t{\r\n\t\t\tsint32 res = OLV_RESULT_SUCCESS;\r\n\r\n\t\t\tstd::string base64icon;\r\n\t\t\tstd::string form_name;\r\n\t\t\tstd::string form_desc;\r\n\t\t\tstd::string form_searchKey[5];\r\n\t\t\tstd::string encodedAppData;\r\n\t\t\tuint8* encodedIcon = nullptr;\r\n\r\n\t\t\tstruct curl_httppost* post = nullptr;\r\n\t\t\tstruct curl_httppost* last = nullptr;\r\n\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\tif (!pParam->iconData.IsNull())\r\n\t\t\t\t{\r\n\t\t\t\t\tencodedIcon = new uint8[pParam->iconDataLen];\r\n\t\t\t\t\tif (encodedIcon)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tsint32 iconEncodeRes = EncodeTGA(pParam->iconData.GetPtr(), pParam->iconDataLen, encodedIcon, pParam->iconDataLen, TGACheckType::CHECK_COMMUNITY_ICON);\r\n\t\t\t\t\t\tif (iconEncodeRes <= 0)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tdelete[] encodedIcon;\r\n\t\t\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE; // ?\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tbase64icon = NCrypto::base64Encode(encodedIcon, iconEncodeRes);\r\n\t\t\t\t\t\tres = olv_curlformcode_to_error(\r\n\t\t\t\t\t\t\tcurl_formadd(&post, &last,\r\n\t\t\t\t\t\t\t\tCURLFORM_COPYNAME, \"icon\",\r\n\t\t\t\t\t\t\t\tCURLFORM_PTRCONTENTS, base64icon.data(),\r\n\t\t\t\t\t\t\t\tCURLFORM_CONTENTSLENGTH, base64icon.size(),\r\n\t\t\t\t\t\t\t\tCURLFORM_END)\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tif (res < 0)\r\n\t\t\t\t\t\t\tthrow std::runtime_error(\"curl_formadd() error! - icon\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pParam->titleText[0])\r\n\t\t\t\t{\r\n\t\t\t\t\tform_name = StringHelpers::ToUtf8((const uint16be*)pParam->titleText, 127);\r\n\t\t\t\t\tres = olv_curlformcode_to_error(\r\n\t\t\t\t\t\tcurl_formadd(&post, &last,\r\n\t\t\t\t\t\t\tCURLFORM_COPYNAME, \"name\",\r\n\t\t\t\t\t\t\tCURLFORM_PTRCONTENTS, form_name.data(),\r\n\t\t\t\t\t\t\tCURLFORM_CONTENTSLENGTH, form_name.size(),\r\n\t\t\t\t\t\t\tCURLFORM_END)\r\n\t\t\t\t\t);\r\n\r\n\t\t\t\t\tif (res < 0)\r\n\t\t\t\t\t\tthrow std::runtime_error(\"curl_formadd() error! - name\");\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pParam->description[0])\r\n\t\t\t\t{\r\n\t\t\t\t\tform_desc = StringHelpers::ToUtf8((const uint16be*)pParam->description, 255);\r\n\t\t\t\t\tres = olv_curlformcode_to_error(\r\n\t\t\t\t\t\tcurl_formadd(&post, &last,\r\n\t\t\t\t\t\t\tCURLFORM_COPYNAME, \"description\",\r\n\t\t\t\t\t\t\tCURLFORM_PTRCONTENTS, form_desc.data(),\r\n\t\t\t\t\t\t\tCURLFORM_CONTENTSLENGTH, form_desc.size(),\r\n\t\t\t\t\t\t\tCURLFORM_END)\r\n\t\t\t\t\t);\r\n\r\n\r\n\t\t\t\t\tif (res < 0)\r\n\t\t\t\t\t\tthrow std::runtime_error(\"curl_formadd() error! - description\");\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor (int i = 0; i < 5; i++)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (pParam->searchKeys[i][0])\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tform_searchKey[i] = StringHelpers::ToUtf8((const uint16be*)pParam->searchKeys[i], 151);\r\n\t\t\t\t\t\tres = olv_curlformcode_to_error(\r\n\t\t\t\t\t\t\tcurl_formadd(&post, &last,\r\n\t\t\t\t\t\t\t\tCURLFORM_COPYNAME, \"search_key\",\r\n\t\t\t\t\t\t\t\tCURLFORM_PTRCONTENTS, form_searchKey[i].data(),\r\n\t\t\t\t\t\t\t\tCURLFORM_CONTENTSLENGTH, form_searchKey[i].size(),\r\n\t\t\t\t\t\t\t\tCURLFORM_END)\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tif (res < 0)\r\n\t\t\t\t\t\t\tthrow std::runtime_error(\"curl_formadd() error! - search_key\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (!pParam->appData.IsNull())\r\n\t\t\t\t{\r\n\t\t\t\t\tencodedAppData = NCrypto::base64Encode(pParam->appData.GetPtr(), pParam->appDataLen);\r\n\t\t\t\t\tif (encodedAppData.size() < pParam->appDataLen)\r\n\t\t\t\t\t\tres = OLV_RESULT_FATAL(101);\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tres = olv_curlformcode_to_error(\r\n\t\t\t\t\t\t\tcurl_formadd(&post, &last,\r\n\t\t\t\t\t\t\t\tCURLFORM_COPYNAME, \"app_data\",\r\n\t\t\t\t\t\t\t\tCURLFORM_PTRCONTENTS, encodedAppData.data(),\r\n\t\t\t\t\t\t\t\tCURLFORM_CONTENTSLENGTH, encodedAppData.size(),\r\n\t\t\t\t\t\t\t\tCURLFORM_END)\r\n\t\t\t\t\t\t);\r\n\r\n\t\t\t\t\t\tif (res < 0)\r\n\t\t\t\t\t\t\tthrow std::runtime_error(\"curl_formadd() error! - app_data\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tcatch (const std::runtime_error& error)\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Error in multipart curl -> {}\", error.what());\r\n\t\t\t\tcurl_formfree(post);\r\n\r\n\t\t\t\tif (encodedIcon)\r\n\t\t\t\t\tdelete[] encodedIcon;\r\n\r\n\t\t\t\treturn res;\r\n\t\t\t}\r\n\r\n\t\t\tcurl_easy_setopt(req.getCURL(), CURLOPT_HTTPPOST, post);\r\n\t\t\treq.setUseMultipartFormData(true);\r\n\r\n\t\t\tbool reqResult = req.submitRequest(true);\r\n\t\t\tlong httpCode = 0;\r\n\t\t\tcurl_easy_getinfo(req.getCURL(), CURLINFO_RESPONSE_CODE, &httpCode);\r\n\r\n\t\t\tif (encodedIcon)\r\n\t\t\t\tdelete[] encodedIcon;\r\n\r\n\t\t\tif (!reqResult)\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed request: {} ({})\", reqUrl, httpCode);\r\n\t\t\t\tif (!(httpCode >= 400))\r\n\t\t\t\t\treturn OLV_RESULT_FAILED_REQUEST;\r\n\t\t\t}\r\n\r\n\t\t\tpugi::xml_document doc;\r\n\t\t\tif (!doc.load_buffer(req.getReceivedData().data(), req.getReceivedData().size()))\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Invalid XML in community upload response\"));\r\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\r\n\t\t\t}\r\n\r\n\t\t\tsint32 responseError = CheckOliveResponse(doc);\r\n\t\t\tif (responseError < 0)\r\n\t\t\t\treturn responseError;\r\n\r\n\t\t\tif (httpCode != 200)\r\n\t\t\t\treturn OLV_RESULT_STATUS(httpCode + 4000);\r\n\t\t\t\r\n\t\t\tif (pOutData)\r\n\t\t\t{\r\n\r\n\t\t\t\tstd::string_view app_data = doc.select_node(\"//app_data\").node().child_value();\r\n\t\t\t\tstd::string_view community_id = doc.select_node(\"//community_id\").node().child_value();\r\n\t\t\t\tstd::string_view name = doc.select_node(\"//name\").node().child_value();\r\n\t\t\t\tstd::string_view description = doc.select_node(\"//description\").node().child_value();\r\n\t\t\t\tstd::string_view pid = doc.select_node(\"//pid\").node().child_value();\r\n\t\t\t\tstd::string_view icon = doc.select_node(\"//icon\").node().child_value();\r\n\r\n\t\t\t\tif (app_data.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto app_data_bin = NCrypto::base64Decode(app_data);\r\n\t\t\t\t\tif (app_data_bin.size() != 0) {\r\n\t\t\t\t\t\tmemcpy(pOutData->appData, app_data_bin.data(), std::min(size_t(0x400), app_data_bin.size()));\r\n\t\t\t\t\t\tpOutData->flags |= UploadedCommunityData::FLAG_HAS_APP_DATA;\r\n\t\t\t\t\t\tpOutData->appDataLen = app_data_bin.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsint64 community_id_val = StringHelpers::ToInt64(community_id, -1);\r\n\t\t\t\tif (community_id_val == -1)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_INTEGER_FIELD;\r\n\r\n\t\t\t\tpOutData->communityId = community_id_val;\r\n\r\n\t\t\t\tif (name.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto name_utf16 = StringHelpers::FromUtf8(name);\r\n\t\t\t\t\tname_utf16.resize(std::min<size_t>(name_utf16.size(), 128));\r\n\t\t\t\t\tif (name_utf16.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfor (int i = 0; i < name_utf16.size(); i++)\r\n\t\t\t\t\t\t\tpOutData->titleText[i] = name_utf16.at(i);\r\n\r\n\t\t\t\t\t\tpOutData->flags |= UploadedCommunityData::FLAG_HAS_TITLE_TEXT;\r\n\t\t\t\t\t\tpOutData->titleTextMaxLen = name_utf16.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (description.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto description_utf16 = StringHelpers::FromUtf8(description);\r\n\t\t\t\t\tdescription_utf16.resize(std::min<size_t>(description_utf16.size(), 256));\r\n\t\t\t\t\tif (description_utf16.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfor (int i = 0; i < description_utf16.size(); i++)\r\n\t\t\t\t\t\t\tpOutData->description[i] = description_utf16.at(i);\r\n\r\n\t\t\t\t\t\tpOutData->flags |= UploadedCommunityData::FLAG_HAS_DESC_TEXT;\r\n\t\t\t\t\t\tpOutData->descriptionMaxLen = description_utf16.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsint64 pid_val = StringHelpers::ToInt64(pid, -1);\r\n\t\t\t\tif (pid_val == -1)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_INTEGER_FIELD;\r\n\r\n\t\t\t\tpOutData->pid = pid_val;\r\n\r\n\t\t\t\tif (icon.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto icon_bin = NCrypto::base64Decode(icon);\r\n\t\t\t\t\tif (icon_bin.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tmemcpy(pOutData->iconData, icon_bin.data(), std::min(size_t(0x1002c), icon_bin.size()));\r\n\t\t\t\t\t\tpOutData->flags |= UploadedCommunityData::FLAG_HAS_ICON_DATA;\r\n\t\t\t\t\t\tpOutData->iconDataSize = icon_bin.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t}\r\n\t}\r\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_UploadCommunityTypes.h",
    "content": "#pragma once\r\n\r\n#include \"Cemu/ncrypto/ncrypto.h\"\r\n#include \"config/ActiveSettings.h\"\r\n\r\n#include \"Cafe/OS/libs/nn_olv/nn_olv_Common.h\"\r\n\r\nnamespace nn\r\n{\r\n\tnamespace olv\r\n\t{\r\n\t\tclass UploadedCommunityData\r\n\t\t{\r\n\t\tpublic:\r\n\t\t\tstatic const inline uint32 FLAG_HAS_TITLE_TEXT = (1 << 0);\r\n\t\t\tstatic const inline uint32 FLAG_HAS_DESC_TEXT = (1 << 1);\r\n\t\t\tstatic const inline uint32 FLAG_HAS_APP_DATA = (1 << 2);\r\n\t\t\tstatic const inline uint32 FLAG_HAS_ICON_DATA = (1 << 3);\r\n\t\t\r\n\t\t\tUploadedCommunityData()\r\n\t\t\t{\r\n\t\t\t\tthis->titleTextMaxLen = 0;\r\n\t\t\t\tthis->appDataLen = 0;\r\n\t\t\t\tthis->descriptionMaxLen = 0;\r\n\t\t\t\tthis->pid = 0;\r\n\t\t\t\tthis->communityId = 0;\r\n\t\t\t\tthis->flags = 0;\r\n\t\t\t\tthis->iconDataSize = 0;\r\n\t\t\t}\r\n\t\t\tstatic UploadedCommunityData* __ctor(UploadedCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\tif (!_this)\r\n\t\t\t\t{\r\n\t\t\t\t\tassert_dbg(); // DO NOT CONTINUE, SHOULD NEVER HAPPEN\r\n\t\t\t\t\treturn nullptr;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t\treturn new (_this) UploadedCommunityData();\r\n\t\t\t}\r\n\r\n\t\t\tstatic UploadedCommunityData* Clean(UploadedCommunityData* data)\r\n\t\t\t{\r\n\t\t\t\tdata->appDataLen = 0;\r\n\t\t\t\tdata->pid = 0;\r\n\t\t\t\tdata->titleText[0] = 0;\r\n\t\t\t\tdata->description[0] = 0;\r\n\t\t\t\tdata->appData[0] = 0;\r\n\t\t\t\tdata->titleTextMaxLen = 0;\r\n\t\t\t\tdata->iconData[0] = 0;\r\n\t\t\t\tdata->descriptionMaxLen = 0;\r\n\t\t\t\tdata->communityId = 0;\r\n\t\t\t\tdata->flags = 0;\r\n\t\t\t\tdata->iconDataSize = 0;\r\n\t\t\t\treturn data;\r\n\t\t\t}\r\n\r\n\t\t\tbool TestFlags(uint32 flags) const\r\n\t\t\t{\r\n\t\t\t\treturn (this->flags & flags) != 0;\r\n\t\t\t}\r\n\t\t\tstatic bool __TestFlags(UploadedCommunityData* _this, uint32 flags)\r\n\t\t\t{\r\n\t\t\t\treturn _this->TestFlags(flags);\r\n\t\t\t}\r\n\r\n\t\t\tuint32 GetCommunityId() const\r\n\t\t\t{\r\n\t\t\t\treturn this->communityId;\r\n\t\t\t}\r\n\t\t\tstatic uint32 __GetCommunityId(UploadedCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetCommunityId();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetCommunityCode(char* pBuffer, uint32 bufferSize) const\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (bufferSize <= 12)\r\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\t\tuint32 len = 0;\r\n\t\t\t\tif (FormatCommunityCode(pBuffer, &len, this->communityId))\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t\r\n\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetCommunityCode(UploadedCommunityData* _this, char* pBuffer, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetCommunityCode(pBuffer, bufferSize);\r\n\t\t\t}\r\n\r\n\t\t\tuint32 GetOwnerPid() const\r\n\t\t\t{\r\n\t\t\t\treturn this->pid;\r\n\t\t\t}\r\n\t\t\tstatic uint32 __GetOwnerPid(UploadedCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetOwnerPid();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetTitleText(char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\t\t\t\t\r\n\t\t\t\tif (numChars)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (!this->TestFlags(FLAG_HAS_TITLE_TEXT))\r\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\t\tmemset(pBuffer, 0, 2 * numChars);\r\n\t\t\t\t\tuint32 readSize = this->titleTextMaxLen;\r\n\t\t\t\t\tif (numChars < readSize)\r\n\t\t\t\t\t\treadSize = numChars;\r\n\r\n\t\t\t\t\tolv_wstrncpy(pBuffer, this->titleText, readSize);\r\n\t\t\t\t\treturn  OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetTitleText(UploadedCommunityData* _this, char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetTitleText(pBuffer, numChars);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetDescriptionText(char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (numChars)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (!this->TestFlags(FLAG_HAS_DESC_TEXT))\r\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\t\tmemset(pBuffer, 0, 2 * numChars);\r\n\t\t\t\t\tolv_wstrncpy(pBuffer, this->description, numChars);\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetDescriptionText(UploadedCommunityData* _this, char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetDescriptionText(pBuffer, numChars);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetAppData(uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\tuint32 appDataSize = bufferSize;\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\t\t\t\t\r\n\t\t\t\tif (bufferSize)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (!this->TestFlags(FLAG_HAS_APP_DATA))\r\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\t\tif (this->appDataLen < appDataSize)\r\n\t\t\t\t\t\tappDataSize = this->appDataLen;\r\n\r\n\t\t\t\t\tmemcpy(pBuffer, this->appData, appDataSize);\r\n\t\t\t\t\tif (pOutSize)\r\n\t\t\t\t\t\t*pOutSize = appDataSize;\r\n\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetAppData(UploadedCommunityData* _this, uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetAppData(pBuffer, pOutSize, bufferSize);\r\n\t\t\t}\r\n\r\n\t\t\tuint32 GetAppDataSize() const\r\n\t\t\t{\r\n\t\t\t\tif (this->TestFlags(FLAG_HAS_APP_DATA))\r\n\t\t\t\t\treturn this->appDataLen;\r\n\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t\tstatic uint32 __GetAppDataSize(UploadedCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetAppDataSize();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetIconData(uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (bufferSize < sizeof(this->iconData))\r\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\t\tif (!this->TestFlags(FLAG_HAS_ICON_DATA))\r\n\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\tsint32 decodeRes = DecodeTGA(this->iconData, this->iconDataSize, pBuffer, bufferSize, TGACheckType::CHECK_COMMUNITY_ICON);\r\n\t\t\t\tif (decodeRes >= 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (pOutSize)\r\n\t\t\t\t\t\t*pOutSize = (uint32)decodeRes;\r\n\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pOutSize)\r\n\t\t\t\t\t*pOutSize = 0;\r\n\r\n\t\t\t\tif (decodeRes == -1)\r\n\t\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE - icon uncompress failed.\\n\");\r\n\t\t\t\telse if (decodeRes == -2)\r\n\t\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE - icon decode error. NOT TGA.\\n\");\r\n\r\n\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetIconData(UploadedCommunityData* _this, uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetIconData(pBuffer, pOutSize, bufferSize);\r\n\t\t\t}\r\n\r\n\t\tpublic:\r\n\t\t\tuint32be flags;\r\n\t\t\tuint32be communityId;\r\n\t\t\tuint32be pid;\r\n\t\t\tchar16_t titleText[128];\r\n\t\t\tuint32be titleTextMaxLen;\r\n\t\t\tchar16_t description[256];\r\n\t\t\tuint32be descriptionMaxLen;\r\n\t\t\tuint8 appData[1024];\r\n\t\t\tuint32be appDataLen;\r\n\t\t\tuint8 iconData[65580];\r\n\t\t\tuint32be iconDataSize;\r\n\t\t\tuint8 unk[6328];\r\n\t\t};\r\n\t\tstatic_assert(sizeof(nn::olv::UploadedCommunityData) == 0x12000, \"sizeof(nn::olv::UploadedCommunityData) != 0x12000\");\r\n\r\n\r\n\t\tclass UploadCommunityDataParam\r\n\t\t{\r\n\t\tpublic:\r\n\t\t\tstatic const inline uint32 FLAG_DELETION = (1 << 0);\r\n\t\t\r\n\t\t\tUploadCommunityDataParam()\r\n\t\t\t{\r\n\t\t\t\tthis->appDataLen = 0;\r\n\t\t\t\tthis->communityId = 0;\r\n\t\t\t\tthis->titleId = 0;\r\n\t\t\t\tthis->iconData = MEMPTR<uint8>(nullptr);\r\n\t\t\t\tthis->appData = MEMPTR<uint8>(nullptr);\r\n\t\t\t\tthis->iconDataLen = 0;\r\n\t\t\t\tthis->flags = 0;\r\n\t\t\t\tmemset(this->titleText, 0, sizeof(this->titleText));\r\n\t\t\t\tmemset(this->description, 0, sizeof(this->description));\r\n\t\t\t\tfor (int i = 0; i < 5; i++)\r\n\t\t\t\t\tmemset(this->searchKeys[i], 0, sizeof(this->searchKeys[0]));\r\n\t\t\t}\r\n\t\t\tstatic UploadCommunityDataParam* __ctor(UploadCommunityDataParam* _this)\r\n\t\t\t{\r\n\t\t\t\tif (!_this)\r\n\t\t\t\t{\r\n\t\t\t\t\tassert_dbg(); // DO NOT CONTINUE, SHOULD NEVER HAPPEN\r\n\t\t\t\t\treturn nullptr;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t\treturn new (_this) UploadCommunityDataParam();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetFlags(uint32 flags)\r\n\t\t\t{\r\n\t\t\t\tthis->flags = flags;\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetFlags(UploadCommunityDataParam* _this, uint32 flags)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetFlags(flags);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetCommunityId(uint32 communityId)\r\n\t\t\t{\r\n\t\t\t\tif (communityId == -1)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\tthis->communityId = communityId;\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetCommunityId(UploadCommunityDataParam* _this, uint32 communityId)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetCommunityId(communityId);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetAppData(MEMPTR<uint8> pBuffer, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer.IsNull())\r\n\t\t\t\t{\r\n\t\t\t\t\tif (bufferSize - 1 >= 0x400)\r\n\t\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\t\t\tthis->appData = pBuffer;\r\n\t\t\t\t\tthis->appDataLen = bufferSize;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tthis->appData = MEMPTR<uint8>(nullptr);\r\n\t\t\t\t\tthis->appDataLen = 0;\r\n\t\t\t\t}\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetAppData(UploadCommunityDataParam* _this, MEMPTR<uint8> pBuffer, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetAppData(pBuffer, bufferSize);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetTitleText(char16_t const* pText)\r\n\t\t\t{\r\n\t\t\t\tif (pText)\r\n\t\t\t\t\treturn olv_copy_wstr(this->titleText, pText, 127, 128);\r\n\t\t\t\r\n\t\t\t\tmemset(this->titleText, 0, sizeof(this->titleText));\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetTitleText(UploadCommunityDataParam* _this, char16_t const* pText)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetTitleText(pText);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetDescriptionText(char16_t const* pText)\r\n\t\t\t{\r\n\t\t\t\tif (pText)\r\n\t\t\t\t\treturn olv_copy_wstr(this->description, pText, 255, 256);\r\n\r\n\t\t\t\tmemset(this->description, 0, sizeof(this->description));\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetDescriptionText(UploadCommunityDataParam* _this, char16_t const* pText)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetDescriptionText(pText);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetIconData(MEMPTR<uint8> pBuffer, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer.IsNull())\r\n\t\t\t\t{\r\n\t\t\t\t\tif (bufferSize)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tif (bufferSize - 0x10012 < 0x1B)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tif (CheckTGA(pBuffer.GetPtr(), bufferSize, TGACheckType::CHECK_COMMUNITY_ICON))\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tthis->iconData = pBuffer;\r\n\t\t\t\t\t\t\t\tthis->iconDataLen = bufferSize;\r\n\t\t\t\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE - SetIconData: TGA Check Failed.\\n\");\r\n\t\t\t\t\t\t\t\treturn OLV_RESULT_INVALID_DATA;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tthis->iconData = MEMPTR<uint8>(nullptr);\r\n\t\t\t\t\tthis->iconDataLen = 0;\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetIconData(UploadCommunityDataParam* _this, MEMPTR<uint8> pBuffer, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetIconData(pBuffer, bufferSize);\r\n\t\t\t}\r\n\r\n\t\tpublic:\r\n\t\t\tuint32be flags;\r\n\t\t\tsint32be ___padding_0c;\r\n\t\t\tuint64be titleId;\r\n\t\t\tuint32be communityId;\r\n\t\t\tchar16_t titleText[128];\r\n\t\t\tchar16_t description[256];\r\n\t\t\tchar16_t searchKeys[5][152];\r\n\t\t\tMEMPTR<uint8_t> appData;\r\n\t\t\tuint32be appDataLen;\r\n\t\t\tMEMPTR<uint8_t> iconData;\r\n\t\t\tuint32be iconDataLen;\r\n\t\t\tchar unk3[1772];\r\n\t\t};\r\n\t\tstatic_assert(sizeof(nn::olv::UploadCommunityDataParam) == 0x1000, \"sizeof(nn::olv::UploadCommunityDataParam) != 0x1000\");\r\n\r\n\t\tsint32 UploadCommunityData(UploadCommunityDataParam const* pParam);\r\n\t\tsint32 UploadCommunityData(UploadedCommunityData* pOutData, UploadCommunityDataParam const* pParam);\r\n\r\n\t\tstatic void loadOliveUploadCommunityTypes()\r\n\t\t{\r\n\t\t\tcafeExportRegisterFunc(UploadedCommunityData::__ctor, \"nn_olv\", \"__ct__Q3_2nn3olv21UploadedCommunityDataFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedCommunityData::__TestFlags, \"nn_olv\", \"TestFlags__Q3_2nn3olv21UploadedCommunityDataCFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedCommunityData::__GetCommunityId, \"nn_olv\", \"GetCommunityId__Q3_2nn3olv21UploadedCommunityDataCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedCommunityData::__GetCommunityCode, \"nn_olv\", \"GetCommunityCode__Q3_2nn3olv21UploadedCommunityDataCFPcUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedCommunityData::__GetOwnerPid, \"nn_olv\", \"GetOwnerPid__Q3_2nn3olv21UploadedCommunityDataCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedCommunityData::__GetTitleText, \"nn_olv\", \"GetTitleText__Q3_2nn3olv21UploadedCommunityDataCFPwUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedCommunityData::__GetDescriptionText, \"nn_olv\", \"GetDescriptionText__Q3_2nn3olv21UploadedCommunityDataCFPwUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedCommunityData::__GetAppData, \"nn_olv\", \"GetAppData__Q3_2nn3olv21UploadedCommunityDataCFPUcPUiUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedCommunityData::__GetAppDataSize, \"nn_olv\", \"GetAppDataSize__Q3_2nn3olv21UploadedCommunityDataCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedCommunityData::__GetIconData, \"nn_olv\", \"GetIconData__Q3_2nn3olv21UploadedCommunityDataCFPUcPUiUi\", LogType::NN_OLV);\r\n\t\t\r\n\t\t\tcafeExportRegisterFunc(UploadCommunityDataParam::__ctor, \"nn_olv\", \"__ct__Q3_2nn3olv24UploadCommunityDataParamFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadCommunityDataParam::__SetFlags, \"nn_olv\", \"SetFlags__Q3_2nn3olv24UploadCommunityDataParamFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadCommunityDataParam::__SetCommunityId, \"nn_olv\", \"SetCommunityId__Q3_2nn3olv24UploadCommunityDataParamFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadCommunityDataParam::__SetAppData, \"nn_olv\", \"SetAppData__Q3_2nn3olv24UploadCommunityDataParamFPCUcUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadCommunityDataParam::__SetTitleText, \"nn_olv\", \"SetTitleText__Q3_2nn3olv24UploadCommunityDataParamFPCw\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadCommunityDataParam::__SetDescriptionText, \"nn_olv\", \"SetDescriptionText__Q3_2nn3olv24UploadCommunityDataParamFPCw\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadCommunityDataParam::__SetIconData, \"nn_olv\", \"SetIconData__Q3_2nn3olv24UploadCommunityDataParamFPCUcUi\", LogType::NN_OLV);\r\n\r\n\t\t\tcafeExportRegisterFunc((sint32(*)(UploadCommunityDataParam const*))UploadCommunityData,\r\n\t\t\t\t\"nn_olv\", \"UploadCommunityData__Q2_2nn3olvFPCQ3_2nn3olv24UploadCommunityDataParam\", LogType::NN_OLV);\r\n\t\t\r\n\t\t\tcafeExportRegisterFunc((sint32(*)(UploadedCommunityData *, UploadCommunityDataParam const*))UploadCommunityData,\r\n\t\t\t\t\"nn_olv\", \"UploadCommunityData__Q2_2nn3olvFPQ3_2nn3olv21UploadedCommunityDataPCQ3_2nn3olv24UploadCommunityDataParam\", LogType::NN_OLV);\r\n\t\t}\r\n\r\n\t}\r\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp",
    "content": "#include \"nn_olv_UploadFavoriteTypes.h\"\r\n#include <algorithm>\r\n#include <cstddef>\r\n\r\nnamespace nn\r\n{\r\n\tnamespace olv\r\n\t{\r\n\t\r\n\t\tsint32 UploadFavoriteToCommunityData_AsyncRequestImpl(CurlRequestHelper& req, const char* reqUrl,\r\n\t\t\tUploadedFavoriteToCommunityData* pOutData, const UploadFavoriteToCommunityDataParam* pParam\r\n\t\t);\r\n\r\n\t\tsint32 UploadFavoriteToCommunityData_AsyncRequest(CurlRequestHelper& req, const char* reqUrl, coreinit::OSEvent* requestDoneEvent,\r\n\t\t\tUploadedFavoriteToCommunityData* pOutData, const UploadFavoriteToCommunityDataParam* pParam\r\n\t\t)\r\n\t\t{\r\n\t\t\tsint32 res = UploadFavoriteToCommunityData_AsyncRequestImpl(req, reqUrl, pOutData, pParam);\r\n\t\t\tcoreinit::OSSignalEvent(requestDoneEvent);\r\n\t\t\treturn res;\r\n\t\t}\r\n\r\n\t\tsint32 UploadFavoriteToCommunityData(UploadedFavoriteToCommunityData* pOutData, const UploadFavoriteToCommunityDataParam* pParam)\r\n\t\t{\r\n\t\t\tif (!nn::olv::g_IsInitialized)\r\n\t\t\t\treturn OLV_RESULT_NOT_INITIALIZED;\r\n\r\n\t\t\tif (!nn::olv::g_IsOnlineMode)\r\n\t\t\t\treturn OLV_RESULT_OFFLINE_MODE_REQUEST;\r\n\r\n\t\t\tif (!pParam)\r\n\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\tif (pOutData)\r\n\t\t\t\tUploadedFavoriteToCommunityData::Clean(pOutData);\r\n\r\n\t\t\tchar requestUrl[512];\r\n\t\t\tif (pParam->flags & UploadFavoriteToCommunityDataParam::FLAG_DELETION)\r\n\t\t\t\tsnprintf(requestUrl, sizeof(requestUrl), \"%s/v1/communities/%u.unfavorite\", g_DiscoveryResults.apiEndpoint, pParam->communityId.value());\r\n\t\t\telse \r\n\t\t\t\tsnprintf(requestUrl, sizeof(requestUrl), \"%s/v1/communities/%u.favorite\", g_DiscoveryResults.apiEndpoint, pParam->communityId.value());\r\n\t\t\t\r\n\t\t\tCurlRequestHelper req;\r\n\t\t\treq.initate(ActiveSettings::GetNetworkService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::OLIVE);\r\n\t\t\tInitializeOliveRequest(req);\r\n\r\n\t\t\tStackAllocator<coreinit::OSEvent> requestDoneEvent;\r\n\t\t\tcoreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);\r\n\t\t\tstd::future<sint32> requestRes = std::async(std::launch::async, UploadFavoriteToCommunityData_AsyncRequest, std::ref(req), requestUrl, requestDoneEvent.GetPointer(), pOutData, pParam);\r\n\t\t\tcoreinit::OSWaitEvent(&requestDoneEvent);\r\n\r\n\t\t\treturn requestRes.get();\r\n\t\t}\r\n\r\n\t\tsint32 UploadFavoriteToCommunityData(const UploadFavoriteToCommunityDataParam* pParam)\r\n\t\t{\r\n\t\t\treturn UploadFavoriteToCommunityData(nullptr, pParam);\r\n\t\t}\r\n\r\n\t\tsint32 UploadFavoriteToCommunityData_AsyncRequestImpl(CurlRequestHelper& req, const char* reqUrl,\r\n\t\t\tUploadedFavoriteToCommunityData* pOutData, const UploadFavoriteToCommunityDataParam* pParam\r\n\t\t)\r\n\t\t{\r\n\t\t\tbool reqResult = req.submitRequest(true);\r\n\t\t\tlong httpCode = 0;\r\n\t\t\tcurl_easy_getinfo(req.getCURL(), CURLINFO_RESPONSE_CODE, &httpCode);\r\n\r\n\t\t\tif (!reqResult)\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed request: {} ({})\", reqUrl, httpCode);\r\n\t\t\t\tif (!(httpCode >= 400))\r\n\t\t\t\t\treturn OLV_RESULT_FAILED_REQUEST;\r\n\t\t\t}\r\n\r\n\t\t\tpugi::xml_document doc;\r\n\t\t\tif (!doc.load_buffer(req.getReceivedData().data(), req.getReceivedData().size()))\r\n\t\t\t{\r\n\t\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Invalid XML in community favorite upload response\"));\r\n\t\t\t\treturn OLV_RESULT_INVALID_XML;\r\n\t\t\t}\r\n\r\n\t\t\tsint32 responseError = CheckOliveResponse(doc);\r\n\t\t\tif (responseError < 0)\r\n\t\t\t\treturn responseError;\r\n\r\n\t\t\tif (httpCode != 200)\r\n\t\t\t\treturn OLV_RESULT_STATUS(httpCode + 4000);\r\n\r\n\t\t\tif (pOutData)\r\n\t\t\t{\r\n\t\t\t\tstd::string_view app_data = doc.select_node(\"//app_data\").node().child_value();\r\n\t\t\t\tstd::string_view community_id = doc.select_node(\"//community_id\").node().child_value();\r\n\t\t\t\tstd::string_view name = doc.select_node(\"//name\").node().child_value();\r\n\t\t\t\tstd::string_view description = doc.select_node(\"//description\").node().child_value();\r\n\t\t\t\tstd::string_view pid = doc.select_node(\"//pid\").node().child_value();\r\n\t\t\t\tstd::string_view icon = doc.select_node(\"//icon\").node().child_value();\r\n\r\n\t\t\t\tif (app_data.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto app_data_bin = NCrypto::base64Decode(app_data);\r\n\t\t\t\t\tif (app_data_bin.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tmemcpy(pOutData->appData, app_data_bin.data(), std::min(size_t(0x400), app_data_bin.size()));\r\n\t\t\t\t\t\tpOutData->flags |= UploadedFavoriteToCommunityData::FLAG_HAS_APP_DATA;\r\n\t\t\t\t\t\tpOutData->appDataLen = app_data_bin.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsint64 community_id_val = StringHelpers::ToInt64(community_id, -1);\r\n\t\t\t\tif (community_id_val == -1)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_INTEGER_FIELD;\r\n\r\n\t\t\t\tpOutData->communityId = community_id_val;\r\n\r\n\t\t\t\tif (name.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto name_utf16 = StringHelpers::FromUtf8(name);\r\n\t\t\t\t\tname_utf16.resize(std::min<size_t>(name_utf16.size(), 128));\r\n\t\t\t\t\tif (name_utf16.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfor (int i = 0; i < name_utf16.size(); i++)\r\n\t\t\t\t\t\t\tpOutData->titleText[i] = name_utf16.at(i);\r\n\r\n\t\t\t\t\t\tpOutData->flags |= UploadedFavoriteToCommunityData::FLAG_HAS_TITLE_TEXT;\r\n\t\t\t\t\t\tpOutData->titleTextMaxLen = name_utf16.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (description.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto description_utf16 = StringHelpers::FromUtf8(description);\r\n\t\t\t\t\tdescription_utf16.resize(std::min<size_t>(description_utf16.size(), 256));\r\n\t\t\t\t\tif (description_utf16.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfor (int i = 0; i < description_utf16.size(); i++)\r\n\t\t\t\t\t\t\tpOutData->description[i] = description_utf16.at(i);\r\n\r\n\t\t\t\t\t\tpOutData->flags |= UploadedFavoriteToCommunityData::FLAG_HAS_DESC_TEXT;\r\n\t\t\t\t\t\tpOutData->descriptionMaxLen = description_utf16.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tsint64 pid_val = StringHelpers::ToInt64(pid, -1);\r\n\t\t\t\tif (pid_val == -1)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_INTEGER_FIELD;\r\n\r\n\t\t\t\tpOutData->pid = pid_val;\r\n\r\n\t\t\t\tif (icon.size() != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tauto icon_bin = NCrypto::base64Decode(icon);\r\n\t\t\t\t\tif (icon_bin.size() != 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tmemcpy(pOutData->iconData, icon_bin.data(), std::min(size_t(0x1002c), icon_bin.size()));\r\n\t\t\t\t\t\tpOutData->flags |= UploadedFavoriteToCommunityData::FLAG_HAS_ICON_DATA;\r\n\t\t\t\t\t\tpOutData->iconDataSize = icon_bin.size();\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t}\r\n\t}\r\n}\r\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.h",
    "content": "#pragma once\r\n\r\n#include \"Cemu/ncrypto/ncrypto.h\"\r\n#include \"config/ActiveSettings.h\"\r\n\r\n#include \"Cafe/OS/libs/nn_olv/nn_olv_Common.h\"\r\n\r\nnamespace nn\r\n{\r\n\tnamespace olv\r\n\t{\r\n\t\tclass UploadedFavoriteToCommunityData\r\n\t\t{\r\n\t\tpublic:\r\n\t\t\tstatic const inline uint32 FLAG_HAS_TITLE_TEXT = (1 << 0);\r\n\t\t\tstatic const inline uint32 FLAG_HAS_DESC_TEXT = (1 << 1);\r\n\t\t\tstatic const inline uint32 FLAG_HAS_APP_DATA = (1 << 2);\r\n\t\t\tstatic const inline uint32 FLAG_HAS_ICON_DATA = (1 << 3);\r\n\t\t\r\n\t\t\tUploadedFavoriteToCommunityData()\r\n\t\t\t{\r\n\t\t\t\tthis->titleTextMaxLen = 0;\r\n\t\t\t\tthis->appDataLen = 0;\r\n\t\t\t\tthis->descriptionMaxLen = 0;\r\n\t\t\t\tthis->pid = 0;\r\n\t\t\t\tthis->communityId = 0;\r\n\t\t\t\tthis->flags = 0;\r\n\t\t\t\tthis->iconDataSize = 0;\r\n\t\t\t}\r\n\t\t\tstatic UploadedFavoriteToCommunityData* __ctor(UploadedFavoriteToCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\tif (!_this)\r\n\t\t\t\t{\r\n\t\t\t\t\tassert_dbg(); // DO NOT CONTINUE, SHOULD NEVER HAPPEN\r\n\t\t\t\t\treturn nullptr;\r\n\t\t\t\t} \r\n\t\t\t\telse\r\n\t\t\t\t\treturn new (_this) UploadedFavoriteToCommunityData();\r\n\t\t\t}\r\n\r\n\t\t\tstatic UploadedFavoriteToCommunityData* Clean(UploadedFavoriteToCommunityData* data)\r\n\t\t\t{\r\n\t\t\t\tdata->appDataLen = 0;\r\n\t\t\t\tdata->pid = 0;\r\n\t\t\t\tdata->titleText[0] = 0;\r\n\t\t\t\tdata->description[0] = 0;\r\n\t\t\t\tdata->appData[0] = 0;\r\n\t\t\t\tdata->titleTextMaxLen = 0;\r\n\t\t\t\tdata->iconData[0] = 0;\r\n\t\t\t\tdata->descriptionMaxLen = 0;\r\n\t\t\t\tdata->communityId = 0;\r\n\t\t\t\tdata->flags = 0;\r\n\t\t\t\tdata->iconDataSize = 0;\r\n\t\t\t\treturn data;\r\n\t\t\t}\r\n\r\n\t\t\tbool TestFlags(uint32 flags) const\r\n\t\t\t{\r\n\t\t\t\treturn (this->flags & flags) != 0;\r\n\t\t\t}\r\n\t\t\tstatic bool __TestFlags(UploadedFavoriteToCommunityData* _this, uint32 flags)\r\n\t\t\t{\r\n\t\t\t\treturn _this->TestFlags(flags);\r\n\t\t\t}\r\n\r\n\t\t\tuint32 GetCommunityId() const\r\n\t\t\t{\r\n\t\t\t\treturn this->communityId;\r\n\t\t\t}\r\n\t\t\tstatic uint32 __GetCommunityId(UploadedFavoriteToCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetCommunityId();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetCommunityCode(char* pBuffer, uint32 bufferSize) const\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (bufferSize <= 12)\r\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\t\tuint32 len = 0;\r\n\t\t\t\tif (FormatCommunityCode(pBuffer, &len, this->communityId))\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t\r\n\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetCommunityCode(UploadedFavoriteToCommunityData* _this, char* pBuffer, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetCommunityCode(pBuffer, bufferSize);\r\n\t\t\t}\r\n\r\n\t\t\tuint32 GetOwnerPid() const\r\n\t\t\t{\r\n\t\t\t\treturn this->pid;\r\n\t\t\t}\r\n\t\t\tstatic uint32 __GetOwnerPid(UploadedFavoriteToCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetOwnerPid();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetTitleText(char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\t\t\t\t\r\n\t\t\t\tif (numChars)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (!this->TestFlags(FLAG_HAS_TITLE_TEXT))\r\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\t\tmemset(pBuffer, 0, 2 * numChars);\r\n\t\t\t\t\tuint32 readSize = this->titleTextMaxLen;\r\n\t\t\t\t\tif (numChars < readSize)\r\n\t\t\t\t\t\treadSize = numChars;\r\n\r\n\t\t\t\t\tolv_wstrncpy(pBuffer, this->titleText, readSize);\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetTitleText(UploadedFavoriteToCommunityData* _this, char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetTitleText(pBuffer, numChars);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetDescriptionText(char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (numChars)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (!this->TestFlags(FLAG_HAS_DESC_TEXT))\r\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\t\tmemset(pBuffer, 0, 2 * numChars);\r\n\t\t\t\t\tolv_wstrncpy(pBuffer, this->description, numChars);\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetDescriptionText(UploadedFavoriteToCommunityData* _this, char16_t* pBuffer, uint32 numChars)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetDescriptionText(pBuffer, numChars);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetAppData(uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\tuint32 appDataSize = bufferSize;\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\t\t\t\t\r\n\t\t\t\tif (bufferSize)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (!this->TestFlags(FLAG_HAS_APP_DATA))\r\n\t\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\t\tif (this->appDataLen < appDataSize)\r\n\t\t\t\t\t\tappDataSize = this->appDataLen;\r\n\r\n\t\t\t\t\tmemcpy(pBuffer, this->appData, appDataSize);\r\n\t\t\t\t\tif (pOutSize)\r\n\t\t\t\t\t\t*pOutSize = appDataSize;\r\n\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetAppData(UploadedFavoriteToCommunityData* _this, uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetAppData(pBuffer, pOutSize, bufferSize);\r\n\t\t\t}\r\n\r\n\t\t\tuint32 GetAppDataSize() const\r\n\t\t\t{\r\n\t\t\t\tif (this->TestFlags(FLAG_HAS_APP_DATA))\r\n\t\t\t\t\treturn this->appDataLen;\r\n\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\t\t\tstatic uint32 __GetAppDataSize(UploadedFavoriteToCommunityData* _this)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetAppDataSize();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 GetIconData(uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\tif (!pBuffer)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PTR;\r\n\r\n\t\t\t\tif (bufferSize < sizeof(this->iconData))\r\n\t\t\t\t\treturn OLV_RESULT_NOT_ENOUGH_SIZE;\r\n\r\n\t\t\t\tif (!this->TestFlags(FLAG_HAS_ICON_DATA))\r\n\t\t\t\t\treturn OLV_RESULT_MISSING_DATA;\r\n\r\n\t\t\t\tsint32 decodeRes = DecodeTGA(this->iconData, this->iconDataSize, pBuffer, bufferSize, TGACheckType::CHECK_COMMUNITY_ICON);\r\n\t\t\t\tif (decodeRes >= 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (pOutSize)\r\n\t\t\t\t\t\t*pOutSize = (uint32)decodeRes;\r\n\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pOutSize)\r\n\t\t\t\t\t*pOutSize = 0;\r\n\r\n\t\t\t\tif (decodeRes == -1)\r\n\t\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE - icon uncompress failed.\\n\");\r\n\t\t\t\telse if (decodeRes == -2)\r\n\t\t\t\t\tcemuLog_log(LogType::Force, \"OLIVE - icon decode error. NOT TGA.\\n\");\r\n\r\n\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __GetIconData(UploadedFavoriteToCommunityData* _this, uint8* pBuffer, uint32be* pOutSize, uint32 bufferSize)\r\n\t\t\t{\r\n\t\t\t\treturn _this->GetIconData(pBuffer, pOutSize, bufferSize);\r\n\t\t\t}\r\n\r\n\t\tpublic:\r\n\t\t\tuint32be flags;\r\n\t\t\tuint32be communityId;\r\n\t\t\tuint32be pid;\r\n\t\t\tchar16_t titleText[128];\r\n\t\t\tuint32be titleTextMaxLen;\r\n\t\t\tchar16_t description[256];\r\n\t\t\tuint32be descriptionMaxLen;\r\n\t\t\tuint8 appData[1024];\r\n\t\t\tuint32be appDataLen;\r\n\t\t\tuint8 iconData[65580];\r\n\t\t\tuint32be iconDataSize;\r\n\t\t\tuint8 unk[6328];\r\n\t\t};\r\n\t\tstatic_assert(sizeof(nn::olv::UploadedFavoriteToCommunityData) == 0x12000, \"sizeof(nn::olv::UploadedFavoriteToCommunityData) != 0x12000\");\r\n\r\n\t\tclass UploadFavoriteToCommunityDataParam\r\n\t\t{\r\n\r\n\t\tpublic:\r\n\t\t\tstatic const inline uint32 FLAG_DELETION = (1 << 0);\r\n\r\n\t\t\tUploadFavoriteToCommunityDataParam()\r\n\t\t\t{\r\n\t\t\t\tthis->communityId = 0;\r\n\t\t\t\tthis->flags = 0;\r\n\t\t\t}\r\n\t\t\tstatic UploadFavoriteToCommunityDataParam* __ctor(UploadFavoriteToCommunityDataParam* _this)\r\n\t\t\t{\r\n\t\t\t\tif (!_this)\r\n\t\t\t\t{\r\n\t\t\t\t\tassert_dbg(); // DO NOT CONTINUE, SHOULD NEVER HAPPEN\r\n\t\t\t\t\treturn nullptr;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t\treturn new (_this) UploadFavoriteToCommunityDataParam();\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetFlags(uint32 flags)\r\n\t\t\t{\r\n\t\t\t\tthis->flags = flags;\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetFlags(UploadFavoriteToCommunityDataParam* _this, uint32 flags)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetFlags(flags);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetCommunityCode(const char* pBuffer)\r\n\t\t\t{\r\n\t\t\t\tif (strnlen(pBuffer, 13) != 12)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_TEXT_FIELD;\r\n\r\n\t\t\t\tuint32_t id;\r\n\t\t\t\tif (GetCommunityIdFromCode(&id, pBuffer))\r\n\t\t\t\t{\r\n\t\t\t\t\tthis->communityId = id;\r\n\t\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn OLV_RESULT_STATUS(1901);\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetCommunityCode(UploadFavoriteToCommunityDataParam* _this, char* pBuffer)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetCommunityCode(pBuffer);\r\n\t\t\t}\r\n\r\n\t\t\tsint32 SetCommunityId(uint32 communityId)\r\n\t\t\t{\r\n\t\t\t\tif (communityId == -1)\r\n\t\t\t\t\treturn OLV_RESULT_INVALID_PARAMETER;\r\n\r\n\t\t\t\tthis->communityId = communityId;\r\n\t\t\t\treturn OLV_RESULT_SUCCESS;\r\n\t\t\t}\r\n\t\t\tstatic sint32 __SetCommunityId(UploadFavoriteToCommunityDataParam* _this, uint32 communityId)\r\n\t\t\t{\r\n\t\t\t\treturn _this->SetCommunityId(communityId);\r\n\t\t\t}\r\n\r\n\t\tpublic:\r\n\t\t\tuint32be flags;\r\n\t\t\tuint32be communityId;\r\n\t\t\tuint8 unk[54]; // Unused\r\n\t\t};\r\n\t\tstatic_assert(sizeof(nn::olv::UploadFavoriteToCommunityDataParam) == 64, \"sizeof(nn::olv::UploadFavoriteToCommunityDataParam) != 64\");\r\n\r\n\t\tsint32 UploadFavoriteToCommunityData(const UploadFavoriteToCommunityDataParam* pParam);\r\n\t\tsint32 UploadFavoriteToCommunityData(UploadedFavoriteToCommunityData* pOutData, const UploadFavoriteToCommunityDataParam* pParam);\r\n\r\n\t\tstatic void loadOliveUploadFavoriteTypes()\r\n\t\t{\r\n\t\t\tcafeExportRegisterFunc(UploadedFavoriteToCommunityData::__ctor, \"nn_olv\", \"__ct__Q3_2nn3olv31UploadedFavoriteToCommunityDataFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedFavoriteToCommunityData::__TestFlags, \"nn_olv\", \"TestFlags__Q3_2nn3olv31UploadedFavoriteToCommunityDataCFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedFavoriteToCommunityData::__GetCommunityId, \"nn_olv\", \"GetCommunityId__Q3_2nn3olv31UploadedFavoriteToCommunityDataCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedFavoriteToCommunityData::__GetCommunityCode, \"nn_olv\", \"GetCommunityCode__Q3_2nn3olv31UploadedFavoriteToCommunityDataCFPcUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedFavoriteToCommunityData::__GetOwnerPid, \"nn_olv\", \"GetOwnerPid__Q3_2nn3olv31UploadedFavoriteToCommunityDataCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedFavoriteToCommunityData::__GetTitleText, \"nn_olv\", \"GetTitleText__Q3_2nn3olv31UploadedFavoriteToCommunityDataCFPwUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedFavoriteToCommunityData::__GetDescriptionText, \"nn_olv\", \"GetDescriptionText__Q3_2nn3olv31UploadedFavoriteToCommunityDataCFPwUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedFavoriteToCommunityData::__GetAppData, \"nn_olv\", \"GetAppData__Q3_2nn3olv31UploadedFavoriteToCommunityDataCFPUcPUiUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedFavoriteToCommunityData::__GetAppDataSize, \"nn_olv\", \"GetAppDataSize__Q3_2nn3olv31UploadedFavoriteToCommunityDataCFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadedFavoriteToCommunityData::__GetIconData, \"nn_olv\", \"GetIconData__Q3_2nn3olv31UploadedFavoriteToCommunityDataCFPUcPUiUi\", LogType::NN_OLV);\r\n\t\t\t\r\n\t\t\tcafeExportRegisterFunc(UploadFavoriteToCommunityDataParam::__ctor, \"nn_olv\", \"__ct__Q3_2nn3olv34UploadFavoriteToCommunityDataParamFv\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadFavoriteToCommunityDataParam::__SetFlags, \"nn_olv\", \"SetFlags__Q3_2nn3olv34UploadFavoriteToCommunityDataParamFUi\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadFavoriteToCommunityDataParam::__SetCommunityCode, \"nn_olv\", \"SetCommunityCode__Q3_2nn3olv34UploadFavoriteToCommunityDataParamFPCc\", LogType::NN_OLV);\r\n\t\t\tcafeExportRegisterFunc(UploadFavoriteToCommunityDataParam::__SetCommunityId, \"nn_olv\", \"SetCommunityId__Q3_2nn3olv34UploadFavoriteToCommunityDataParamFUi\", LogType::NN_OLV);\r\n\r\n\t\t\tcafeExportRegisterFunc((sint32(*)(const UploadFavoriteToCommunityDataParam*))UploadFavoriteToCommunityData,\r\n\t\t\t\t\"nn_olv\", \"UploadFavoriteToCommunityData__Q2_2nn3olvFPCQ3_2nn3olv34UploadFavoriteToCommunityDataParam\", LogType::NN_OLV);\r\n\r\n\t\t\tcafeExportRegisterFunc((sint32(*)(UploadedFavoriteToCommunityData*, const UploadFavoriteToCommunityDataParam*))UploadFavoriteToCommunityData,\r\n\t\t\t\t\"nn_olv\", \"UploadFavoriteToCommunityData__Q2_2nn3olvFPQ3_2nn3olv31UploadedFavoriteToCommunityDataPCQ3_2nn3olv34UploadFavoriteToCommunityDataParam\", LogType::NN_OLV);\r\n\t\t}\r\n\r\n\t}\r\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_pdm/nn_pdm.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/TitleList/TitleId.h\"\n\n#include \"Cafe/IOSU/PDM/iosu_pdm.h\"\n\n#include \"nn_pdm.h\"\n\nnamespace nn\n{\n\tnamespace pdm\n\t{\n\t\tusing PlayDiary = iosu::pdm::PlayDiaryEntry;\n\n\t\tuint32 GetPlayDiaryMaxLength(uint32be* count)\n\t\t{\n\t\t\t*count = iosu::pdm::NUM_PLAY_DIARY_ENTRIES_MAX;\n\t\t\treturn 0;\n\t\t}\n\n\t\tuint32 GetPlayStatsMaxLength(uint32be* count)\n\t\t{\n\t\t\t*count = iosu::pdm::NUM_PLAY_STATS_ENTRIES;\n\t\t\treturn 0;\n\t\t}\n\n\t\tuint32 GetPlayDiary(uint32be* ukn1, PlayDiary* playDiary, uint32 accountSlot, uint32 maxNumEntries)\n\t\t{\n\t\t\tuint32 numReadEntries = iosu::pdm::GetDiaryEntries(accountSlot, playDiary, maxNumEntries);\n\t\t\t*ukn1 = numReadEntries;\n\t\t\treturn 0;\n\t\t}\n\n\t\tclass : public COSModule\n\t\t{\n\t\t\tpublic:\n\t\t\tstd::string_view GetName() override\n\t\t\t{\n\t\t\t\treturn \"nn_pdm\";\n\t\t\t}\n\n\t\t\tvoid RPLMapped() override\n\t\t\t{\n\t\t\t\tcafeExportRegisterFunc(GetPlayDiaryMaxLength, \"nn_pdm\", \"GetPlayDiaryMaxLength__Q2_2nn3pdmFPi\", LogType::NN_PDM);\n\t\t\t\tcafeExportRegisterFunc(GetPlayStatsMaxLength, \"nn_pdm\", \"GetPlayStatsMaxLength__Q2_2nn3pdmFPi\", LogType::NN_PDM);\n\n\t\t\t\tcafeExportRegisterFunc(GetPlayDiary, \"nn_pdm\", \"GetPlayDiary__Q2_2nn3pdmFPiPQ3_2nn3pdm9PlayDiaryiT3\", LogType::NN_PDM);\n\t\t\t};\n\n\t\t}s_COSnnPdmModule;\n\n\t\tCOSModule* GetModule()\n\t\t{\n\t\t\treturn &s_COSnnPdmModule;\n\t\t}\n\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_pdm/nn_pdm.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::pdm\n{\n\tCOSModule* GetModule();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/nn_save/nn_save.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"nn_save.h\"\n\n#include \"Cafe/OS/libs/nn_acp/nn_acp.h\"\n#include \"Cafe/OS/libs/nn_act/nn_act.h\"\n\n#include <filesystem>\n#include <sstream>\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_FS.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/Filesystem/fsc.h\"\n\n#define SAVE_STATUS_OK ((FSStatus)FS_RESULT::SUCCESS)\n#define SAVE_MAX_PATH_SIZE (FSA_CMD_PATH_MAX_LENGTH)\n\n#define SAVE_ACCOUNT_ID_MIN (1)\n#define SAVE_ACCOUNT_ID_MAX (0xC)\n\n#define SAVE_UNIQUE_TO_TITLE_ID(_unique_) (((((uint64)_unique_ >> 24ULL) | 0x50000) << 32ULL) | ((_unique_ << 8) | 0x10000000))\n#define SAVE_UNIQUE_TO_TITLE_ID_VARIATION(_unique_,_variation_) (((((uint64)_unique_ >> 24ULL) | 0x50000 ) << 32) | ((_unique_ << 8) | 0x10000000 | _variation_))\n#define SAVE_UNIQUE_DEMO_TO_TITLE_ID(_unique_) (((((uint64)_unique_ >> 24ULL) | 0x50002) << 32ULL) | ((_unique_ << 8) | 0x10000000))\n#define SAVE_UNIQUE_DEMO_TO_TITLE_ID_VARIATION(_unique_,_variation_) (((((uint64)_unique_ >> 24ULL) | 0x50002 ) << 32ULL) | ((_unique_ << 8) | 0x10000000 | _variation_))\n\nnamespace nn\n{\nnamespace save\n{\n\ttypedef FSStatus SAVEStatus;\n\n\ttypedef struct\n\t{\n\t\tbool initialized;\n\t\tcoreinit::OSMutex mutex;\n\t\tcoreinit::FSClient_t fsClient;\n\t\tcoreinit::FSCmdBlock_t fsCmdBlock;\n\t\tuint32 persistentIdCache[0xC];\n\t}nn_save_t;\n\n\tSysAllocator<nn_save_t> g_nn_save;\n\n\tuint32 GetPersistentIdFromLocalCache(uint8 accountSlot)\n\t{\n\t\taccountSlot--;\n\t\tif (accountSlot >= 0xC)\n\t\t\treturn 0;\n\n\t\treturn g_nn_save->persistentIdCache[accountSlot];\n\t}\n\n\tvoid SetPersistentIdToLocalCache(uint8 accountSlot, uint32 persistentId)\n\t{\n\t\taccountSlot--;\n\t\tif (accountSlot >= 0xC)\n\t\t\treturn;\n\n\t\tg_nn_save->persistentIdCache[accountSlot] = persistentId;\n\t}\n\n\tbool GetPersistentIdEx(uint8 accountSlot, uint32* persistentId)\n\t{\n\t\tif (accountSlot == 0xFF)\n\t\t{\n\t\t\t*persistentId = 0;\n\t\t\treturn true;\n\t\t}\n\n\t\tconst uint32 result = GetPersistentIdFromLocalCache(accountSlot);\n\t\t*persistentId = result;\n\t\treturn result != 0;\n\t}\n\n\tbool GetCurrentTitleApplicationBox(nn::acp::ACPDeviceType* deviceType)\n\t{\n\t\tif (deviceType)\n\t\t{\n\t\t\t*deviceType = nn::acp::ACPDeviceType::InternalDeviceType;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tvoid UpdateSaveTimeStamp(uint32 persistentId)\n\t{\n\t\tnn::acp::ACPDeviceType deviceType;\n\t\tif (GetCurrentTitleApplicationBox(&deviceType))\n\t\t\tACPUpdateSaveTimeStamp(persistentId, CafeSystem::GetForegroundTitleId(), deviceType);\n\t}\n\n\tSAVEStatus ConvertACPToSaveStatus(acp::ACPStatus status)\n\t{\n\t\tcemu_assert_debug(status == 0); // todo\n\t\treturn 0;\n\t}\n\n\tbool GetAbsoluteFullPath(uint32 persistentId, const char* subDir, char* outPath)\n\t{\n\t\tint size;\n\t\tif (persistentId != 0)\n\t\t{\n\t\t\tif (subDir)\n\t\t\t\tsize = snprintf(outPath, SAVE_MAX_PATH_SIZE - 1, \"/vol/save/%08x/%s\", persistentId, subDir);\n\t\t\telse\n\t\t\t\tsize = snprintf(outPath, SAVE_MAX_PATH_SIZE - 1, \"/vol/save/%08x/\", persistentId);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (subDir)\n\t\t\t\tsize = snprintf(outPath, SAVE_MAX_PATH_SIZE - 1, \"/vol/save/common/%s\", subDir);\n\t\t\telse\n\t\t\t\tsize = snprintf(outPath, SAVE_MAX_PATH_SIZE - 1, \"/vol/save/common/\");\n\t\t}\n\n\t\tif (size < SAVE_MAX_PATH_SIZE - 1)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\tFS_RESULT GetAbsoluteFullPathOtherApplication(uint32 persistentId, uint64 titleId, const char* subDir, char* outPath)\n\t{\n\t\tuint32be applicationBox;\n\t\tif(acp::ACPGetApplicationBox(&applicationBox, titleId) != acp::ACPStatus::SUCCESS)\n\t\t\treturn FS_RESULT::NOT_FOUND;\n\n\t\tsint32 written = 0;\n\t\tif(applicationBox == 3)\t\n\t\t{\n\t\t\tif(persistentId != 0)\n\t\t\t{\n\t\t\t\tif (subDir)\n\t\t\t\t\twritten = snprintf(outPath, SAVE_MAX_PATH_SIZE - 1, \"/vol/storage_mlc01/usr/save/%08x/%08x/user/%08x/%s\",\n\t\t\t\t\t\tGetTitleIdHigh(titleId), GetTitleIdLow(titleId), persistentId, subDir);\n\t\t\t\telse\n\t\t\t\t\twritten = snprintf(outPath, SAVE_MAX_PATH_SIZE - 1, \"/vol/storage_mlc01/usr/save/%08x/%08x/user/%08x/\",\n\t\t\t\t\t\tGetTitleIdHigh(titleId), GetTitleIdLow(titleId), persistentId);\n\t\t\t}\t\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (subDir)\n\t\t\t\t\twritten = snprintf(outPath, SAVE_MAX_PATH_SIZE - 1, \"/vol/storage_mlc01/usr/save/%08x/%08x/user/common/%s\",\n\t\t\t\t\t\tGetTitleIdHigh(titleId), GetTitleIdLow(titleId), subDir);\n\t\t\t\telse\n\t\t\t\t\twritten = snprintf(outPath, SAVE_MAX_PATH_SIZE - 1, \"/vol/storage_mlc01/usr/save/%08x/%08x/user/common/\",\n\t\t\t\t\t\tGetTitleIdHigh(titleId), GetTitleIdLow(titleId));\n\t\t\t}\n\t\t}\n\t\telse if(applicationBox == 4)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\telse \n\t\t\treturn FS_RESULT::NOT_FOUND;\n\n\t\tif (written < SAVE_MAX_PATH_SIZE - 1)\n\t\t\treturn FS_RESULT::SUCCESS;\n\n\t\tcemu_assert_suspicious();\n\t\treturn FS_RESULT::FATAL_ERROR;\n\t}\n\n\tstruct AsyncResultData\n\t{\n\t\tMEMPTR<coreinit::OSEvent> event;\n\t\tbetype<SAVEStatus> returnStatus;\n\t};\n\n\tvoid SaveAsyncFinishCallback(PPCInterpreter_t* hCPU);\n\n\tstruct AsyncToSyncWrapper : public FSAsyncParams\n\t{\n\t\tAsyncToSyncWrapper()\n\t\t{\n\t\t\tcoreinit::OSInitEvent(&_event, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);\n\t\t\tioMsgQueue = nullptr;\n\t\t\tuserContext = &_result;\n\t\t\tuserCallback = RPLLoader_MakePPCCallable(SaveAsyncFinishCallback);\n\t\t\t_result.returnStatus = 0;\n\t\t\t_result.event = &_event;\n\t\t}\n\n\t\t~AsyncToSyncWrapper()\n\t\t{\n\n\t\t}\n\n\t\tFSAsyncParams* GetAsyncParams()\n\t\t{\n\t\t\treturn this;\n\t\t}\n\n\t\tSAVEStatus GetResult()\n\t\t{\n\t\t\treturn _result.returnStatus;\n\t\t}\n\n\t\tvoid WaitForEvent()\n\t\t{\n\t\t\tcoreinit::OSWaitEvent(&_event);\n\t\t}\n\t  private:\n\t\tcoreinit::OSEvent _event;\n\t\tAsyncResultData _result;\n\t};\n\n\tvoid SaveAsyncFinishCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamMEMPTR(client, coreinit::FSClient_t, 0);\n\t\tppcDefineParamMEMPTR(block, coreinit::FSCmdBlock_t, 1);\n\t\tppcDefineParamU32(returnStatus, 2);\n\t\tppcDefineParamMEMPTR(userContext, void, 3);\n\n\t\tMEMPTR<AsyncResultData> resultPtr{ userContext };\n\t\tresultPtr->returnStatus = returnStatus;\n\t\tcoreinit::OSSignalEvent(resultPtr->event);\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tSAVEStatus SAVEMountSaveDir()\n\t{\n\t\tacp::ACPStatus status = acp::ACPMountSaveDir();\n\t\treturn ConvertACPToSaveStatus(status);\n\t}\n\n    SAVEStatus SAVEUnmountSaveDir()\n    {\n        return ConvertACPToSaveStatus(acp::ACPUnmountSaveDir());\n    }\n\n\n\tSAVEStatus SAVEInit()\n\t{\n\t\tconst uint64 titleId = CafeSystem::GetForegroundTitleId();\n\n\t\tif (!g_nn_save->initialized)\n\t\t{\n\t\t\tOSInitMutexEx(&g_nn_save->mutex, nullptr);\n\t\t\tact::Initialize();\n\t\t\tcoreinit::FSAddClientEx(&g_nn_save->fsClient, 0, 0);\n\t\t\tcoreinit::FSInitCmdBlock(&g_nn_save->fsCmdBlock);\n\t\t\tfor(uint8 accountId = SAVE_ACCOUNT_ID_MIN; accountId <= SAVE_ACCOUNT_ID_MAX; ++accountId)\n\t\t\t{\n\t\t\t\tuint32 persistentId = act::GetPersistentIdEx(accountId);\n\t\t\t\tSetPersistentIdToLocalCache(accountId, persistentId);\n\t\t\t}\n\t\t\t\n\t\t\tSAVEMountSaveDir();\n\t\t\tg_nn_save->initialized = true;\n\n\t\t\tuint32 high = GetTitleIdHigh(titleId) & (~0xC);\n\t\t\tuint32 low = GetTitleIdLow(titleId);\n\n\t\t\tsint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;\n\t\t\tchar path[256];\n\t\t\tsprintf(path, \"%susr/save/%08x/\", \"/vol/storage_mlc01/\", high);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/save/%08x/%08x/\", \"/vol/storage_mlc01/\", high, low);\n\t\t\tfsc_createDir(path, &fscStatus);\n\t\t\tsprintf(path, \"%susr/save/%08x/%08x/meta/\", \"/vol/storage_mlc01/\", high, low);\n\t\t\tfsc_createDir(path, &fscStatus);\n\n\t\t\tiosu::acp::CreateSaveMetaFiles(ActiveSettings::GetPersistentId(), titleId);\n\t\t}\n\n\t\treturn SAVE_STATUS_OK;\n\t}\n\n\tSAVEStatus SAVEInitSaveDir(uint8 accountSlot)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\t\tOSLockMutex(&g_nn_save->mutex);\n\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tacp::ACPStatus status = nn::acp::ACPCreateSaveDir(persistentId, iosu::acp::ACPDeviceType::InternalDeviceType);\n\t\t\tresult = ConvertACPToSaveStatus(status);\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEOpenDirAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPath(persistentId, path, fullPath))\n\t\t\t\tresult = coreinit::FSOpenDirAsync(client, block, fullPath, hDir, errHandling, (FSAsyncParams*)asyncParams);\n\t\t\t\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEOpenDir(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVEOpenDirAsync(client, block, accountSlot, path, hDir, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVEOpenDirOtherApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPathOtherApplication(persistentId, titleId, path, fullPath) == FS_RESULT::SUCCESS)\n\t\t\t\tresult = coreinit::FSOpenDirAsync(client, block, fullPath, hDir, errHandling, (FSAsyncParams*)asyncParams);\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEOpenDirOtherApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVEOpenDirOtherApplicationAsync(client, block, titleId, accountSlot, path, hDir, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVEOpenDirOtherNormalApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);\n\t\treturn SAVEOpenDirOtherApplicationAsync(client, block, titleId, accountSlot, path, hDir, errHandling, asyncParams);\n\t}\n\n\tSAVEStatus SAVEOpenDirOtherNormalApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);\n\t\treturn SAVEOpenDirOtherApplication(client, block, titleId, accountSlot, path, hDir, errHandling);\n\t}\n\n\tSAVEStatus SAVEOpenDirOtherNormalApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);\n\t\treturn SAVEOpenDirOtherApplicationAsync(client, block, titleId, accountSlot, path, hDir, errHandling, asyncParams);\n\t}\n\n\tSAVEStatus SAVEOpenDirOtherNormalApplicationVariation(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSDirHandlePtr hDir, FS_ERROR_MASK errHandling)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);\n\t\treturn SAVEOpenDirOtherApplication(client, block, titleId, accountSlot, path, hDir, errHandling);\n\t}\n\n\tSAVEStatus SAVEOpenFileAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPath(persistentId, path, fullPath))\n\t\t\t\tresult = coreinit::FSOpenFileAsync(client, block, fullPath, (char*)mode, outFileHandle, errHandling, (FSAsyncParams*)asyncParams);\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEOpenFileOtherApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tif (strcmp(mode, \"r\") != 0)\n\t\t\treturn (SAVEStatus)(FS_RESULT::PERMISSION_ERROR);\n\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPathOtherApplication(persistentId, titleId, path, fullPath) == FS_RESULT::SUCCESS)\n\t\t\t\tresult = coreinit::FSOpenFileAsync(client, block, fullPath, (char*)mode, outFileHandle, errHandling, (FSAsyncParams*)asyncParams);\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEOpenFileOtherApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVEOpenFileOtherApplicationAsync(client, block, titleId, accountSlot, path, mode, outFileHandle, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVEOpenFileOtherNormalApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);\n\t\treturn SAVEOpenFileOtherApplicationAsync(client, block, titleId, accountSlot, path, mode, outFileHandle, errHandling, asyncParams);\n\t}\n\n\tSAVEStatus SAVEOpenFileOtherNormalApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);\n\t\treturn SAVEOpenFileOtherApplication(client, block, titleId, accountSlot, path, mode, outFileHandle, errHandling);\n\t}\n\n\tSAVEStatus SAVEOpenFileOtherNormalApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);\n\t\treturn SAVEOpenFileOtherApplicationAsync(client, block, titleId, accountSlot, path, mode, outFileHandle, errHandling, asyncParams);\n\t}\n\n\tSAVEStatus SAVEOpenFileOtherNormalApplicationVariation(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);\n\t\treturn SAVEOpenFileOtherApplication(client, block, titleId, accountSlot, path, mode, outFileHandle, errHandling);\n\t}\n\n\tSAVEStatus SAVEGetStatAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPath(persistentId, path, fullPath))\n\t\t\t\tresult = coreinit::__FSQueryInfoAsync(client, block, (uint8*)fullPath, FSA_QUERY_TYPE_STAT, stat, errHandling, (FSAsyncParams*)asyncParams); // FSGetStatAsync(...)\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEGetStat(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVEGetStatAsync(client, block, accountSlot, path, stat, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVEGetStatOtherApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPathOtherApplication(persistentId, titleId, path, fullPath) == FS_RESULT::SUCCESS)\n\t\t\t\tresult = coreinit::__FSQueryInfoAsync(client, block, (uint8*)fullPath, FSA_QUERY_TYPE_STAT, stat, errHandling, (FSAsyncParams*)asyncParams); // FSGetStatAsync(...)\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEGetStatOtherApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint64 titleId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVEGetStatOtherApplicationAsync(client, block, titleId, accountSlot, path, stat, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVEGetStatOtherNormalApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);\n\t\treturn SAVEGetStatOtherApplicationAsync(client, block, titleId, accountSlot, path, stat, errHandling, asyncParams);\n\t}\n\n\tSAVEStatus SAVEGetStatOtherNormalApplication(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID(uniqueId);\n\t\treturn SAVEGetStatOtherApplication(client, block, titleId, accountSlot, path, stat, errHandling);\n\t}\n\n\tSAVEStatus SAVEGetStatOtherDemoApplicationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_DEMO_TO_TITLE_ID(uniqueId);\n\t\treturn SAVEGetStatOtherApplicationAsync(client, block, titleId, accountSlot, path, stat, errHandling, asyncParams);\n\t}\n\n\tSAVEStatus SAVEGetStatOtherNormalApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);\n\t\treturn SAVEGetStatOtherApplicationAsync(client, block, titleId, accountSlot, path, stat, errHandling, asyncParams);\n\t}\n\n\tSAVEStatus SAVEGetStatOtherDemoApplicationVariationAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tuint64 titleId = SAVE_UNIQUE_DEMO_TO_TITLE_ID_VARIATION(uniqueId, variation);\n\t\treturn SAVEGetStatOtherApplicationAsync(client, block, titleId, accountSlot, path, stat, errHandling, asyncParams);\n\t}\n\n\tSAVEStatus SAVEGetStatOtherNormalApplicationVariation(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint32 uniqueId, uint8 variation, uint8 accountSlot, const char* path, FSStat_t* stat, FS_ERROR_MASK errHandling)\n\t{\n\t\t//peterBreak();\n\n\t\tuint64 titleId = SAVE_UNIQUE_TO_TITLE_ID_VARIATION(uniqueId, variation);\n\t\treturn SAVEGetStatOtherApplication(client, block, titleId, accountSlot, path, stat, errHandling);\n\t}\n\n\tSAVEStatus SAVEGetFreeSpaceSizeAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, FSLargeSize* freeSize, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPath(persistentId, nullptr, fullPath))\n\t\t\t\tresult = coreinit::FSGetFreeSpaceSizeAsync(client, block, fullPath, freeSize, errHandling, (FSAsyncParams*)asyncParams);\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEGetFreeSpaceSize(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, FSLargeSize* freeSize, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVEGetFreeSpaceSizeAsync(client, block, accountSlot, freeSize, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVERemoveAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPath(persistentId, path, fullPath))\n\t\t\t\tresult = coreinit::FSRemoveAsync(client, block, (uint8*)fullPath, errHandling, (FSAsyncParams*)asyncParams);\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVERemove(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVERemoveAsync(client, block, accountSlot, path, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVERenameAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* oldPath, const char* newPath, FS_ERROR_MASK errHandling, FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\t\tOSLockMutex(&g_nn_save->mutex);\n\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullOldPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPath(persistentId, oldPath, fullOldPath))\n\t\t\t{\n\t\t\t\tchar fullNewPath[SAVE_MAX_PATH_SIZE];\n\t\t\t\tif (GetAbsoluteFullPath(persistentId, newPath, fullNewPath))\n\t\t\t\t\tresult = coreinit::FSRenameAsync(client, block, fullOldPath, fullNewPath, errHandling, asyncParams);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVERename(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* oldPath, const char* newPath, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVERenameAsync(client, block, accountSlot, oldPath, newPath, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVEMakeDirAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPath(persistentId, path, fullPath))\n\t\t\t\tresult = coreinit::FSMakeDirAsync(client, block, fullPath, errHandling, (FSAsyncParams*)asyncParams);\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEMakeDir(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVEMakeDirAsync(client, block, accountSlot, path, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVEOpenFile(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, const char* mode, FSFileHandlePtr outFileHandle, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVEOpenFileAsync(client, block, accountSlot, path, mode, outFileHandle, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVEGetSharedDataTitlePath(uint64 titleId, const char* dataFileName, char* output, sint32 outputLength)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\t\tsint32 written = snprintf(output, outputLength, \"/vol/storage_mlc01/sys/title/%08x/%08x/content/%s\", GetTitleIdHigh(titleId), GetTitleIdLow(titleId), dataFileName);\n\t\tif (written >= 0 && written < outputLength)\n\t\t\tresult = (FSStatus)FS_RESULT::SUCCESS;\n\t\tcemu_assert_debug(result != (FSStatus)(FS_RESULT::FATAL_ERROR));\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEGetSharedSaveDataPath(uint64 titleId, const char* dataFileName, char* output, uint32 outputLength)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\t\tint written = snprintf(output, outputLength, \"/vol/storage_mlc01/usr/save/%08x/%08x/user/common/%s\", GetTitleIdHigh(titleId), GetTitleIdLow(titleId), dataFileName);\n\t\tif (written >= 0 && written < (sint32)outputLength)\n\t\t\tresult = (FSStatus)FS_RESULT::SUCCESS;\n\t\tcemu_assert_debug(result != (FSStatus)(FS_RESULT::FATAL_ERROR));\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEChangeDirAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPath(persistentId, path, fullPath))\n\t\t\t\tresult = coreinit::FSChangeDirAsync(client, block, fullPath, errHandling, (FSAsyncParams*)asyncParams);\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEChangeDir(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, const char* path, FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVEChangeDirAsync(client, block, accountSlot, path, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n\tSAVEStatus SAVEFlushQuotaAsync(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot, FS_ERROR_MASK errHandling, const FSAsyncParams* asyncParams)\n\t{\n\t\tSAVEStatus result = (FSStatus)(FS_RESULT::FATAL_ERROR);\n\n\t\tOSLockMutex(&g_nn_save->mutex);\n\t\tuint32 persistentId;\n\t\tif (GetPersistentIdEx(accountSlot, &persistentId))\n\t\t{\n\t\t\tchar fullPath[SAVE_MAX_PATH_SIZE];\n\t\t\tif (GetAbsoluteFullPath(persistentId, nullptr, fullPath))\n\t\t\t{\n\t\t\t\tresult = coreinit::FSFlushQuotaAsync(client, block, fullPath, errHandling, (FSAsyncParams*)asyncParams);\n\t\t\t\t// if(OSGetUPID != 0xF)\n\t\t\t\tUpdateSaveTimeStamp(persistentId);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tresult = (FSStatus)FS_RESULT::NOT_FOUND;\n\t\tOSUnlockMutex(&g_nn_save->mutex);\n\n\t\treturn result;\n\t}\n\n\tSAVEStatus SAVEFlushQuota(coreinit::FSClient_t* client, coreinit::FSCmdBlock_t* block, uint8 accountSlot,  FS_ERROR_MASK errHandling)\n\t{\n\t\tStackAllocator<AsyncToSyncWrapper> asyncData;\n\t\tSAVEStatus status = SAVEFlushQuotaAsync(client, block, accountSlot, errHandling, asyncData->GetAsyncParams());\n\t\tif (status != (FSStatus)FS_RESULT::SUCCESS)\n\t\t\treturn status;\n\t\tasyncData->WaitForEvent();\n\t\treturn asyncData->GetResult();\n\t}\n\n    void ResetToDefaultState()\n    {\n        if(g_nn_save->initialized)\n        {\n            SAVEUnmountSaveDir();\n            g_nn_save->initialized = false;\n        }\n    }\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_save\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"nn_save\", SAVEInit, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEInitSaveDir, LogType::Save);\n\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetSharedDataTitlePath, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetSharedSaveDataPath, LogType::Save);\n\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetFreeSpaceSize, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetFreeSpaceSizeAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEMakeDir, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEMakeDirAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVERemove, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVERemoveAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEChangeDir, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEChangeDirAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVERename, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVERenameAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEFlushQuota, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEFlushQuotaAsync, LogType::Save);\n\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetStat, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetStatAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetStatOtherApplication, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetStatOtherApplicationAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetStatOtherNormalApplication, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetStatOtherNormalApplicationAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetStatOtherNormalApplicationVariation, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEGetStatOtherNormalApplicationVariationAsync, LogType::Save);\n\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenFile, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenFileAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenFileOtherApplication, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenFileOtherApplicationAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenFileOtherNormalApplication, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenFileOtherNormalApplicationAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenFileOtherNormalApplicationVariation, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenFileOtherNormalApplicationVariationAsync, LogType::Save);\n\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenDir, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenDirAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenDirOtherApplication, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenDirOtherApplicationAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenDirOtherNormalApplication, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenDirOtherNormalApplicationVariation, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenDirOtherNormalApplicationAsync, LogType::Save);\n\t\t\tcafeExportRegister(\"nn_save\", SAVEOpenDirOtherNormalApplicationVariationAsync, LogType::Save);\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\tResetToDefaultState();\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t\tResetToDefaultState();\n\t\t\t}\n\t\t}\n\t}s_COSnnSaveModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnSaveModule;\n\t}\n\n}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_save/nn_save.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::save\n{\n    void ResetToDefaultState();\n\n\tbool GetPersistentIdEx(uint8 accountSlot, uint32* persistentId);\n\n\tCOSModule* GetModule();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_sl/nn_sl.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IOS.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/CafeSystem.h\"\n\nnamespace nn\n{\n\ttypedef uint32 Result;\n\tnamespace sl\n\t{\n\t\tstruct VTableEntry\n\t\t{\n\t\t\tuint16be offsetA{0};\n\t\t\tuint16be offsetB{0};\n\t\t\tMEMPTR<void> ptr;\n\t\t};\n\t\tstatic_assert(sizeof(VTableEntry) == 8);\n\n\t\tconstexpr uint32 SL_MEM_MAGIC = 0xCAFE4321;\n\n#define DTOR_WRAPPER(__TYPE) RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) { dtor(MEMPTR<__TYPE>(hCPU->gpr[3]), hCPU->gpr[4]); osLib_returnFromFunction(hCPU, 0); })\n\n\t\ttemplate<typename T>\n\t\tMEMPTR<T> sl_new()\n\t\t{\n\t\t\tuint32 objSize = sizeof(T);\n\t\t\tuint32be* basePtr = (uint32be*)coreinit::_weak_MEMAllocFromDefaultHeapEx(objSize + 8, 0x8);\n\t\t\tbasePtr[0] = SL_MEM_MAGIC;\n\t\t\tbasePtr[1] = objSize;\n\t\t\treturn (T*)(basePtr + 2);\n\t\t}\n\n\t\tvoid sl_delete(MEMPTR<void> mem)\n\t\t{\n\t\t\tif (!mem)\n\t\t\t\treturn;\n\t\t\tuint32be* basePtr = (uint32be*)mem.GetPtr() - 2;\n\t\t\tif (basePtr[0] != SL_MEM_MAGIC)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"nn_sl: Detected memory corruption\");\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t}\n\t\t\tcoreinit::_weak_MEMFreeToDefaultHeap(basePtr);\n\t\t}\n\n#pragma pack(1)\n\t\tstruct WhiteList\n\t\t{\n\t\t\tuint32be titleTypes[50];\n\t\t\tuint32be titleTypesCount;\n\t\t\tuint32be padding;\n\t\t\tuint64be titleIds[50];\n\t\t\tuint32be titleIdCount;\n\t\t};\n\t\tstatic_assert(sizeof(WhiteList) == 0x264);\n#pragma pack()\n\t\t\n\t\tstruct WhiteListAccessor\n\t\t{\n\t\t\tMEMPTR<void> vTablePtr{}; // 0x00\n\n\t\t\tstruct VTable\n\t\t\t{\n\t\t\t\tVTableEntry rtti;\n\t\t\t\tVTableEntry dtor;\n\t\t\t\tVTableEntry get;\n\t\t\t};\n\t\t\tstatic inline SysAllocator<VTable> s_titleVTable;\n\n\t\t\tstatic WhiteListAccessor* ctor(WhiteListAccessor* _this)\n\t\t\t{\n\t\t\t\tif (!_this)\n\t\t\t\t\t_this = sl_new<WhiteListAccessor>();\n\t\t\t\t*_this = {};\n\t\t\t\t_this->vTablePtr = s_titleVTable;\n\t\t\t\treturn _this;\n\t\t\t}\n\n\t\t\tstatic void dtor(WhiteListAccessor* _this, uint32 options)\n\t\t\t{\n\t\t\t\tif (_this && (options & 1))\n\t\t\t\t\tsl_delete(_this);\n\t\t\t}\n\n\t\t\tstatic void Get(WhiteListAccessor* _this, nn::sl::WhiteList* outWhiteList)\n\t\t\t{\n\t\t\t\t*outWhiteList = {};\n\t\t\t}\n\n\t\t\tstatic void InitVTable()\n\t\t\t{\n\t\t\t\ts_titleVTable->rtti.ptr = nullptr; // todo\n\t\t\t\ts_titleVTable->dtor.ptr = DTOR_WRAPPER(WhiteListAccessor);\n\t\t\t\ts_titleVTable->get.ptr = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) { Get(MEMPTR<WhiteListAccessor>(hCPU->gpr[3]), MEMPTR<WhiteList>(hCPU->gpr[4])); osLib_returnFromFunction(hCPU, 0); });\n\t\t\t}\n\t\t};\n\t\tstatic_assert(sizeof(WhiteListAccessor) == 0x04);\n\n\t\tSysAllocator<WhiteListAccessor> s_defaultWhiteListAccessor;\n\n\t\tWhiteListAccessor* GetDefaultWhiteListAccessor()\n\t\t{\n\t\t\treturn s_defaultWhiteListAccessor;\n\t\t}\n\n\t\tclass : public COSModule\n\t\t{\n\t\t\tpublic:\n\t\t\tstd::string_view GetName() override\n\t\t\t{\n\t\t\t\treturn \"nn_sl\";\n\t\t\t}\n\n\t\t\tvoid RPLMapped() override\n\t\t\t{\n\t\t\t\tcafeExportRegisterFunc(nn::sl::GetDefaultWhiteListAccessor, \"nn_sl\", \"GetDefaultWhiteListAccessor__Q2_2nn2slFv\", LogType::NN_SL);\n\t\t\t};\n\n\t\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t\t{\n\t\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t\t{\n\t\t\t\t\tnn::sl::WhiteListAccessor::InitVTable();\n\t\t\t\t\tnn::sl::WhiteListAccessor::ctor(nn::sl::s_defaultWhiteListAccessor);\n\t\t\t\t}\n\t\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t\t{\n\t\t\t\t\t// nothing to clean up\n\t\t\t\t}\n\t\t\t}\n\t\t}s_COSnnSlModule;\n\n\t\tCOSModule* GetModule()\n\t\t{\n\t\t\treturn &s_COSnnSlModule;\n\t\t}\n\t} // namespace sl\n} // namespace nn\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_sl/nn_sl.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::sl\n{\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_spm/nn_spm.cpp",
    "content": "#include \"nn_spm.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n\nnamespace nn\n{\n\tnamespace spm\n\t{\n\n\t\tstruct StorageIndex\n\t\t{\n\t\t\tvoid SetInvalid() { idHigh = 0; idLow = 0; }\n\t\t\tvoid Set(uint64 id) { idHigh = id >> 32; idLow = id & 0xFFFFFFFF; }\n\n\t\t\tuint64 Get() const { return ((uint64)idHigh << 32) | (uint64)idLow; }\n\n\t\t\tuint32be idHigh;\n\t\t\tuint32be idLow;\n\t\t};\n\n\t\tenum class CemuStorageIndex\n\t\t{\n\t\t\tMLC = 1,\n\t\t\tSLC = 2,\n\t\t\tUSB = 3,\n\t\t};\n\n\t\tstatic_assert(sizeof(StorageIndex) == 8);\n\n\t\tstruct VolumeId\n\t\t{\n\t\t\tchar id[16];\n\t\t};\n\n\t\tstatic_assert(sizeof(VolumeId) == 16);\n\n\t\tenum class StorageType : uint32\n\t\t{\n\t\t\tRAW,\n\t\t\tWFS,\n\t\t};\n\n\t\tstruct StorageInfo\n\t\t{\n\t\t\tchar mountPath[640]; // For example: /vol/storage_usb01\n\t\t\tchar connectionType[8]; // usb\n\t\t\tchar formatStr[8]; // raw / wfs\n\t\t\tuint8 ukn[4];\n\t\t\tbetype<StorageType> type;\n\t\t\tVolumeId volumeId;\n\t\t};\n\n\t\tstatic_assert(sizeof(StorageInfo) == 680);\n\n\t\tstruct StorageListItem\n\t\t{\n\t\t\tStorageIndex index;\n\t\t\tuint32be ukn04;\n\t\t\tbetype<StorageType> type;\n\t\t};\n\n\t\tstatic_assert(sizeof(StorageListItem) == 16);\n\n\t\tsint32 GetDefaultExtendedStorageVolumeId(StorageIndex* storageIndex)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"GetDefaultExtendedStorageVolumeId() - stub\");\n\t\t\tstorageIndex->SetInvalid(); // we dont emulate USB storage yet\n\t\t\treturn 0;\n\t\t}\n\n\t\tsint32 GetExtendedStorageIndex(StorageIndex* storageIndex)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"GetExtendedStorageIndex() - stub\");\n\t\t\tstorageIndex->SetInvalid(); // we dont emulate USB storage yet\n\t\t\treturn -1; // this fails if there is none?\n\t\t}\n\n\t\t// nn::spm::GetStorageList((nn::spm::StorageListItem *, unsigned int))\n\n\t\tuint32 GetStorageList(StorageListItem* storageList, uint32 maxItems)\n\t\t{\n\t\t\tcemu_assert(maxItems >= 2);\n\t\t\tuint32 numItems = 0;\n\n\t\t\t// This should only return USB storages?\n\t\t\t// If we return two entries (for SLC and MLC supposedly) then the Wii U menu will complain about two usb storages\n\n//\t\t\t// mlc\n//\t\t\tstorageList[numItems].index.Set((uint32)CemuStorageIndex::MLC);\n//\t\t\tstorageList[numItems].ukn04 = 0;\n//\t\t\tstorageList[numItems].type = StorageType::WFS;\n//\t\t\tnumItems++;\n//\t\t\t// slc\n//\t\t\tstorageList[numItems].index.Set((uint32)CemuStorageIndex::SLC);\n//\t\t\tstorageList[numItems].ukn04 = 0;\n//\t\t\tstorageList[numItems].type = StorageType::WFS;\n\t\t\tnumItems++;\n\t\t\treturn numItems;\n\t\t}\n\n\t\tsint32 GetStorageInfo(StorageInfo* storageInfo, StorageIndex* storageIndex)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"GetStorageInfo() - stub\");\n\t\t\tif(storageIndex->Get() == (uint64)CemuStorageIndex::MLC)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse if(storageIndex->Get() == (uint64)CemuStorageIndex::SLC)\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\tsint32 VolumeId_Compare(VolumeId* volumeIdThis, VolumeId* volumeIdOther)\n\t\t{\n\t\t\tauto r = strncmp(volumeIdThis->id, volumeIdOther->id, 16);\n\t\t\tcemuLog_logDebug(LogType::Force, \"VolumeId_Compare(\\\"{}\\\", \\\"{}\\\")\", volumeIdThis->id, volumeIdOther->id);\n\t\t\treturn (sint32)r;\n\t\t}\n\n\t\tsint32 WaitStateUpdated(uint64be* waitState)\n\t\t{\n\t\t\t// WaitStateUpdated__Q2_2nn3spmFPUL\n\t\t\tcemuLog_logDebug(LogType::Force, \"WaitStateUpdated() called\");\n\t\t\t*waitState = 1;\n\t\t\treturn 0;\n\t\t}\n\n\t\tclass : public COSModule\n\t\t{\n\t\t\tpublic:\n\t\t\tstd::string_view GetName() override\n\t\t\t{\n\t\t\t\treturn \"nn_spm\";\n\t\t\t}\n\n\t\t\tvoid RPLMapped() override\n\t\t\t{\n\t\t\t\tcafeExportRegisterFunc(GetDefaultExtendedStorageVolumeId, \"nn_spm\", \"GetDefaultExtendedStorageVolumeId__Q2_2nn3spmFv\", LogType::Placeholder);\n\t\t\t\tcafeExportRegisterFunc(GetExtendedStorageIndex, \"nn_spm\", \"GetExtendedStorageIndex__Q2_2nn3spmFPQ3_2nn3spm12StorageIndex\", LogType::Placeholder);\n\t\t\t\tcafeExportRegisterFunc(GetStorageList, \"nn_spm\", \"GetStorageList__Q2_2nn3spmFPQ3_2nn3spm15StorageListItemUi\", LogType::Placeholder);\n\n\t\t\t\tcafeExportRegisterFunc(GetStorageInfo, \"nn_spm\", \"GetStorageInfo__Q2_2nn3spmFPQ3_2nn3spm11StorageInfoQ3_2nn3spm12StorageIndex\", LogType::Placeholder);\n\n\t\t\t\tcafeExportRegisterFunc(VolumeId_Compare, \"nn_spm\", \"Compare__Q3_2nn3spm8VolumeIdCFRCQ3_2nn3spm8VolumeId\", LogType::Placeholder);\n\n\t\t\t\tcafeExportRegisterFunc(WaitStateUpdated, \"nn_spm\", \"WaitStateUpdated__Q2_2nn3spmFPUL\", LogType::Placeholder);\n\t\t\t};\n\n\t\t}s_COSnnSpmModule;\n\n\t\tCOSModule* GetModule()\n\t\t{\n\t\t\treturn &s_COSnnSpmModule;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_spm/nn_spm.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn\n{\n\tnamespace spm\n\t{\n\t\tCOSModule* GetModule();\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_temp/nn_temp.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n\nnamespace nn::temp\n{\n\tuint64 tempIdGenerator = 0xdc1b04bd961f2c04ULL;\n\n\tvoid nnTempExport_TEMPCreateAndInitTempDir(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"TEMPCreateAndInitTempDir(...) - placeholder\");\n\n\t\t// create random temp id\n\t\tmemory_writeU64(hCPU->gpr[5], tempIdGenerator);\n\t\ttempIdGenerator = (tempIdGenerator << 3) | (tempIdGenerator >> 61);\n\t\ttempIdGenerator += 0x56e28bd5f4ULL;\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_temp\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"nn_temp\", \"TEMPCreateAndInitTempDir\", nnTempExport_TEMPCreateAndInitTempDir);\n\t\t};\n\n\t}s_COSnnTempModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnTempModule;\n\t}\n};\n\n"
  },
  {
    "path": "src/Cafe/OS/libs/nn_temp/nn_temp.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::temp\n{\n\tCOSModule* GetModule();\n};"
  },
  {
    "path": "src/Cafe/OS/libs/nn_uds/nn_uds.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n\ntypedef struct  \n{\n\tuint32 reserved;\n}udsWorkspace_t;\n\nudsWorkspace_t* udsWorkspace = nullptr;\n\nvoid nnUdsExport___sti___11_uds_Api_cpp_f5d9abb2(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"__sti___11_uds_Api_cpp_f5d9abb2()\\n\");\n\tif( udsWorkspace == NULL )\n\t\tudsWorkspace = (udsWorkspace_t*)memory_getPointerFromVirtualOffset(coreinit_allocFromSysArea(32, 32));\n\tosLib_returnFromFunction(hCPU, memory_getVirtualOffsetFromPointer(udsWorkspace));\n}\n\nnamespace nn::uds\n{\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nn_uds\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"nn_uds\", \"__sti___11_uds_Api_cpp_f5d9abb2\", nnUdsExport___sti___11_uds_Api_cpp_f5d9abb2);\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\tudsWorkspace = nullptr;\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t\tudsWorkspace = nullptr;\n\t\t\t}\n\t\t}\n\t}s_COSnnUdsModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnnUdsModule;\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nn_uds/nn_uds.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nn::uds\n{\n\tCOSModule* GetModule();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/AttachDefaultBackends.cpp",
    "content": "#include \"nsyshid.h\"\n#include \"Backend.h\"\n#include \"BackendEmulated.h\"\n#include \"BackendLibusb.h\"\n\nnamespace nsyshid::backend\n{\n\tvoid AttachDefaultBackends()\n\t{\n\t\t// add libusb backend\n\t\t{\n\t\t\tauto backendLibusb = std::make_shared<backend::libusb::BackendLibusb>();\n\t\t\tif (backendLibusb->IsInitialisedOk())\n\t\t\t{\n\t\t\t\tAttachBackend(backendLibusb);\n\t\t\t}\n\t\t}\n\t   // add emulated backend\n\t\t{\n\t\t\tauto backendEmulated = std::make_shared<backend::emulated::BackendEmulated>();\n\t\t\tif (backendEmulated->IsInitialisedOk())\n\t\t\t{\n\t\t\t\tAttachBackend(backendEmulated);\n\t\t\t}\n\t\t}\n\t}\n} // namespace nsyshid::backend\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/Backend.h",
    "content": "#pragma once\n\n#include <list>\n#include <memory>\n#include <mutex>\n\n#include \"Common/precompiled.h\"\n\nnamespace nsyshid\n{\n\ttypedef struct\n\t{\n\t\t/* +0x00 */ uint32be handle;\n\t\t/* +0x04 */ uint32 ukn04;\n\t\t/* +0x08 */ uint16 vendorId;  // little-endian ?\n\t\t/* +0x0A */ uint16 productId; // little-endian ?\n\t\t/* +0x0C */ uint8 ifIndex;\n\t\t/* +0x0D */ uint8 subClass;\n\t\t/* +0x0E */ uint8 protocol;\n\t\t/* +0x0F */ uint8 paddingGuessed0F;\n\t\t/* +0x10 */ uint16be maxPacketSizeRX;\n\t\t/* +0x12 */ uint16be maxPacketSizeTX;\n\t} HID_t;\n\n\tstruct TransferCommand\n\t{\n\t\tuint8* data;\n\t\tuint32 length;\n\n\t\tTransferCommand(uint8* data, uint32 length)\n\t\t\t: data(data), length(length)\n\t\t{\n\t\t}\n\t\tvirtual ~TransferCommand() = default;\n\t};\n\n\tstruct ReadMessage final : TransferCommand\n\t{\n\t\tsint32 bytesRead;\n\n\t\tReadMessage(uint8* data, uint32 length, sint32 bytesRead)\n\t\t\t: bytesRead(bytesRead), TransferCommand(data, length)\n\t\t{\n\t\t}\n\t\tusing TransferCommand::TransferCommand;\n\t};\n\n\tstruct WriteMessage final : TransferCommand\n\t{\n\t\tsint32 bytesWritten;\n\n\t\tWriteMessage(uint8* data, uint32 length, sint32 bytesWritten)\n\t\t\t: bytesWritten(bytesWritten), TransferCommand(data, length)\n\t\t{\n\t\t}\n\t\tusing TransferCommand::TransferCommand;\n\t};\n\n\tstruct ReportMessage final : TransferCommand\n\t{\n\t\tuint8 reportType;\n\t\tuint8 reportId;\n\n\t\tReportMessage(uint8 reportType, uint8 reportId, uint8* data, uint32 length)\n\t\t\t: reportType(reportType), reportId(reportId), TransferCommand(data, length)\n\t\t{\n\t\t}\n\t\tusing TransferCommand::TransferCommand;\n\t};\n\n\tstatic_assert(offsetof(HID_t, vendorId) == 0x8, \"\");\n\tstatic_assert(offsetof(HID_t, productId) == 0xA, \"\");\n\tstatic_assert(offsetof(HID_t, ifIndex) == 0xC, \"\");\n\tstatic_assert(offsetof(HID_t, protocol) == 0xE, \"\");\n\n\tclass Device\n\t{\n\t  public:\n\t\tDevice() = delete;\n\n\t\tDevice(uint16 vendorId,\n\t\t\t   uint16 productId,\n\t\t\t   uint8 interfaceIndex,\n\t\t\t   uint8 interfaceSubClass,\n\t\t\t   uint8 protocol);\n\n\t\tDevice(const Device& device) = delete;\n\n\t\tDevice& operator=(const Device& device) = delete;\n\n\t\tvirtual ~Device() = default;\n\n\t\tHID_t* m_hid; // this info is passed to applications and must remain intact\n\n\t\tuint16 m_vendorId;\n\t\tuint16 m_productId;\n\t\tuint8 m_interfaceIndex;\n\t\tuint8 m_interfaceSubClass;\n\t\tuint8 m_protocol;\n\t\tuint16 m_maxPacketSizeRX;\n\t\tuint16 m_maxPacketSizeTX;\n\n\t\tvirtual void AssignHID(HID_t* hid);\n\n\t\tvirtual bool Open() = 0;\n\n\t\tvirtual void Close() = 0;\n\n\t\tvirtual bool IsOpened() = 0;\n\n\t\tenum class ReadResult\n\t\t{\n\t\t\tSuccess,\n\t\t\tError,\n\t\t\tErrorTimeout,\n\t\t};\n\n\t\tvirtual ReadResult Read(ReadMessage* message) = 0;\n\n\t\tenum class WriteResult\n\t\t{\n\t\t\tSuccess,\n\t\t\tError,\n\t\t\tErrorTimeout,\n\t\t};\n\n\t\tvirtual WriteResult Write(WriteMessage* message) = 0;\n\n\t\tvirtual bool GetDescriptor(uint8 descType,\n\t\t\t\t\t\t\t\t   uint8 descIndex,\n\t\t\t\t\t\t\t\t   uint16 lang,\n\t\t\t\t\t\t\t\t   uint8* output,\n\t\t\t\t\t\t\t\t   uint32 outputMaxLength) = 0;\n\n\t\tvirtual bool SetIdle(uint8 ifIndex,\n\t\t\t\t\t\t\t uint8 reportId,\n\t\t\t\t\t\t\t uint8 duration) = 0;\n\n\t\tvirtual bool SetProtocol(uint8 ifIndex, uint8 protocol) = 0;\n\n\t\tvirtual bool SetReport(ReportMessage* message) = 0;\n\t};\n\n\tclass Backend\n\t{\n\t  public:\n\t\tBackend();\n\n\t\tBackend(const Backend& backend) = delete;\n\n\t\tBackend& operator=(const Backend& backend) = delete;\n\n\t\tvirtual ~Backend() = default;\n\n\t\tvoid DetachAllDevices();\n\n\t\t// called from nsyshid when this backend is attached - do not call this yourself!\n\t\tvoid OnAttach();\n\n\t\t// called from nsyshid when this backend is detached - do not call this yourself!\n\t\tvoid OnDetach();\n\n\t\tbool IsBackendAttached();\n\n\t\tvirtual bool IsInitialisedOk() = 0;\n\n\t  protected:\n\t\t// try to attach a device - only works if this backend is attached\n\t\tbool AttachDevice(const std::shared_ptr<Device>& device);\n\n\t\tvoid DetachDevice(const std::shared_ptr<Device>& device);\n\n\t\tstd::shared_ptr<Device> FindDevice(std::function<bool(const std::shared_ptr<Device>&)> isWantedDevice);\n\n\t\tstd::shared_ptr<Device> FindDeviceById(uint16 vendorId, uint16 productId);\n\n\t\tbool IsDeviceWhitelisted(uint16 vendorId, uint16 productId);\n\n\t\t// called from OnAttach() - attach devices that your backend can see here\n\t\tvirtual void AttachVisibleDevices() = 0;\n\n\t  private:\n\t\tstd::list<std::shared_ptr<Device>> m_devices;\n\t\tstd::recursive_mutex m_devicesMutex;\n\t\tbool m_isAttached;\n\t};\n\n\tnamespace backend\n\t{\n\t\tvoid AttachDefaultBackends();\n\t}\n} // namespace nsyshid\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/BackendEmulated.cpp",
    "content": "#include \"BackendEmulated.h\"\n\n#include \"Dimensions.h\"\n#include \"Infinity.h\"\n#include \"Skylander.h\"\n#include \"config/CemuConfig.h\"\n#include \"SkylanderXbox360.h\"\n\nnamespace nsyshid::backend::emulated\n{\n\tBackendEmulated::BackendEmulated()\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::BackendEmulated: emulated backend initialised\");\n\t}\n\n\tBackendEmulated::~BackendEmulated() = default;\n\n\tbool BackendEmulated::IsInitialisedOk()\n\t{\n\t\treturn true;\n\t}\n\n\tvoid BackendEmulated::AttachVisibleDevices()\n\t{\n\t\tif (GetConfig().emulated_usb_devices.emulate_skylander_portal && !FindDeviceById(0x1430, 0x0150))\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Attaching Emulated Portal\");\n\t\t\t// Add Skylander Portal\n\t\t\tauto device = std::make_shared<SkylanderPortalDevice>();\n\t\t\tAttachDevice(device);\n\t\t}\n\t\telse if (auto usb_portal = FindDeviceById(0x1430, 0x1F17))\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Attaching Xbox 360 Portal\");\n\t\t\t// Add Skylander Xbox 360 Portal\n\t\t\tauto device = std::make_shared<SkylanderXbox360PortalLibusb>(usb_portal);\n\t\t\tAttachDevice(device);\n\t\t}\n\t\tif (GetConfig().emulated_usb_devices.emulate_infinity_base && !FindDeviceById(0x0E6F, 0x0129))\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Attaching Emulated Base\");\n\t\t\t// Add Infinity Base\n\t\t\tauto device = std::make_shared<InfinityBaseDevice>();\n\t\t\tAttachDevice(device);\n\t\t}\n\t\tif (GetConfig().emulated_usb_devices.emulate_dimensions_toypad && !FindDeviceById(0x0E6F, 0x0241))\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Attaching Emulated Toypad\");\n\t\t\t// Add Dimensions Toypad\n\t\t\tauto device = std::make_shared<DimensionsToypadDevice>();\n\t\t\tAttachDevice(device);\n\t\t}\n\t}\n} // namespace nsyshid::backend::emulated"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/BackendEmulated.h",
    "content": "#include \"nsyshid.h\"\n#include \"Backend.h\"\n\nnamespace nsyshid::backend::emulated\n{\n\tclass BackendEmulated : public nsyshid::Backend {\n\t  public:\n\t\tBackendEmulated();\n\t\t~BackendEmulated();\n\n\t\tbool IsInitialisedOk() override;\n\n\t  protected:\n\t\tvoid AttachVisibleDevices() override;\n\t};\n} // namespace nsyshid::backend::emulated\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/BackendLibusb.cpp",
    "content": "#include \"BackendLibusb.h\"\n\nnamespace nsyshid::backend::libusb\n{\n\tBackendLibusb::BackendLibusb()\n\t\t: m_ctx(nullptr),\n\t\t  m_initReturnCode(0),\n\t\t  m_callbackRegistered(false),\n\t\t  m_hotplugCallbackHandle(0),\n\t\t  m_hotplugThreadStop(false)\n\t{\n\t\tm_initReturnCode = libusb_init(&m_ctx);\n\t\tif (m_initReturnCode < 0)\n\t\t{\n\t\t\tm_ctx = nullptr;\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::BackendLibusb: failed to initialize libusb, return code: {}\",\n\t\t\t\t\t\t\t m_initReturnCode);\n\t\t\treturn;\n\t\t}\n\n\t\tif (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))\n\t\t{\n\t\t\tint ret = libusb_hotplug_register_callback(m_ctx,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED |\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),\n\t\t\t\t\t\t\t\t\t\t\t\t\t   (libusb_hotplug_flag)0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   LIBUSB_HOTPLUG_MATCH_ANY,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   LIBUSB_HOTPLUG_MATCH_ANY,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   LIBUSB_HOTPLUG_MATCH_ANY,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   HotplugCallback,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   this,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   &m_hotplugCallbackHandle);\n\t\t\tif (ret != LIBUSB_SUCCESS)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t\t\t \"nsyshid::BackendLibusb: failed to register hotplug callback with return code {}\",\n\t\t\t\t\t\t\t\t ret);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::BackendLibusb: registered hotplug callback\");\n\t\t\t\tm_callbackRegistered = true;\n\t\t\t\tm_hotplugThread = std::thread([this] {\n\t\t\t\t\twhile (!m_hotplugThreadStop)\n\t\t\t\t\t{\n\t\t\t\t\t\ttimeval timeout{\n\t\t\t\t\t\t\t.tv_sec = 1,\n\t\t\t\t\t\t\t.tv_usec = 0,\n\t\t\t\t\t\t};\n\t\t\t\t\t\tint ret = libusb_handle_events_timeout_completed(m_ctx, &timeout, nullptr);\n\t\t\t\t\t\tif (ret != 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t\t\t\t\t\t \"nsyshid::BackendLibusb: hotplug thread: error handling events: {}\",\n\t\t\t\t\t\t\t\t\t\t\t ret);\n\t\t\t\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1000));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::BackendLibusb: hotplug not supported by this version of libusb\");\n\t\t}\n\t}\n\n\tbool BackendLibusb::IsInitialisedOk()\n\t{\n\t\treturn m_initReturnCode == 0;\n\t}\n\n\tvoid BackendLibusb::AttachVisibleDevices()\n\t{\n\t\t// add all currently connected devices\n\t\tlibusb_device** devices;\n\t\tssize_t deviceCount = libusb_get_device_list(m_ctx, &devices);\n\t\tif (deviceCount < 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"nsyshid::BackendLibusb: failed to get usb devices\");\n\t\t\treturn;\n\t\t}\n\t\tlibusb_device* dev;\n\t\tfor (int i = 0; (dev = devices[i]) != nullptr; i++)\n\t\t{\n\t\t\tauto device = CheckAndCreateDevice(dev);\n\t\t\tif (device != nullptr)\n\t\t\t{\n\t\t\t\tif (IsDeviceWhitelisted(device->m_vendorId, device->m_productId))\n\t\t\t\t{\n\t\t\t\t\tif (!AttachDevice(device))\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force,\n\t\t\t\t\t\t\t\t\t\"nsyshid::BackendLibusb: failed to attach device: {:04x}:{:04x}\",\n\t\t\t\t\t\t\t\t\tdevice->m_vendorId,\n\t\t\t\t\t\t\t\t\tdevice->m_productId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force,\n\t\t\t\t\t\t\t\t\"nsyshid::BackendLibusb: device not on whitelist: {:04x}:{:04x}\",\n\t\t\t\t\t\t\t\tdevice->m_vendorId,\n\t\t\t\t\t\t\t\tdevice->m_productId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlibusb_free_device_list(devices, 1);\n\t}\n\n\tint BackendLibusb::HotplugCallback(libusb_context* ctx,\n\t\t\t\t\t\t\t\t\t   libusb_device* dev,\n\t\t\t\t\t\t\t\t\t   libusb_hotplug_event event,\n\t\t\t\t\t\t\t\t\t   void* user_data)\n\t{\n\t\tif (user_data)\n\t\t{\n\t\t\tBackendLibusb* backend = static_cast<BackendLibusb*>(user_data);\n\t\t\treturn backend->OnHotplug(dev, event);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tint BackendLibusb::OnHotplug(libusb_device* dev, libusb_hotplug_event event)\n\t{\n\t\tstruct libusb_device_descriptor desc;\n\t\tint ret = libusb_get_device_descriptor(dev, &desc);\n\t\tif (ret < 0)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::BackendLibusb::OnHotplug(): failed to get device descriptor\");\n\t\t\treturn 0;\n\t\t}\n\n\t\tswitch (event)\n\t\t{\n\t\tcase LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::BackendLibusb::OnHotplug(): device arrived: {:04x}:{:04x}\",\n\t\t\t\t\t\t\t desc.idVendor,\n\t\t\t\t\t\t\t desc.idProduct);\n\t\t\tauto device = CheckAndCreateDevice(dev);\n\t\t\tif (device != nullptr)\n\t\t\t{\n\t\t\t\tif (IsDeviceWhitelisted(device->m_vendorId, device->m_productId))\n\t\t\t\t{\n\t\t\t\t\tif (!AttachDevice(device))\n\t\t\t\t\t{\n\t\t\t\t\t\tcemuLog_log(LogType::Force,\n\t\t\t\t\t\t\t\t\t\"nsyshid::BackendLibusb::OnHotplug(): failed to attach device: {:04x}:{:04x}\",\n\t\t\t\t\t\t\t\t\tdevice->m_vendorId,\n\t\t\t\t\t\t\t\t\tdevice->m_productId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force,\n\t\t\t\t\t\t\t\t\"nsyshid::BackendLibusb::OnHotplug(): device not on whitelist: {:04x}:{:04x}\",\n\t\t\t\t\t\t\t\tdevice->m_vendorId,\n\t\t\t\t\t\t\t\tdevice->m_productId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t\tcase LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::BackendLibusb::OnHotplug(): device left: {:04x}:{:04x}\",\n\t\t\t\t\t\t\t desc.idVendor,\n\t\t\t\t\t\t\t desc.idProduct);\n\t\t\tauto device = FindLibusbDevice(dev);\n\t\t\tif (device != nullptr)\n\t\t\t{\n\t\t\t\tDetachDevice(device);\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tBackendLibusb::~BackendLibusb()\n\t{\n\t\tif (m_callbackRegistered)\n\t\t{\n\t\t\tm_hotplugThreadStop = true;\n\t\t\tlibusb_hotplug_deregister_callback(m_ctx, m_hotplugCallbackHandle);\n\t\t\tm_hotplugThread.join();\n\t\t}\n\t\tDetachAllDevices();\n\t\tif (m_ctx)\n\t\t{\n\t\t\tlibusb_exit(m_ctx);\n\t\t\tm_ctx = nullptr;\n\t\t}\n\t}\n\n\tstd::shared_ptr<Device> BackendLibusb::FindLibusbDevice(libusb_device* dev)\n\t{\n\t\tlibusb_device_descriptor desc;\n\t\tint ret = libusb_get_device_descriptor(dev, &desc);\n\t\tif (ret < 0)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t\t \"nsyshid::BackendLibusb::FindLibusbDevice(): failed to get device descriptor\");\n\t\t\treturn nullptr;\n\t\t}\n\t\tuint8 busNumber = libusb_get_bus_number(dev);\n\t\tuint8 deviceAddress = libusb_get_device_address(dev);\n\t\tauto device = FindDevice([desc, busNumber, deviceAddress](const std::shared_ptr<Device>& d) -> bool {\n\t\t\tauto device = std::dynamic_pointer_cast<DeviceLibusb>(d);\n\t\t\tif (device != nullptr &&\n\t\t\t\tdesc.idVendor == device->m_vendorId &&\n\t\t\t\tdesc.idProduct == device->m_productId &&\n\t\t\t\tbusNumber == device->m_libusbBusNumber &&\n\t\t\t\tdeviceAddress == device->m_libusbDeviceAddress)\n\t\t\t{\n\t\t\t\t// we found our device!\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\t\tif (device != nullptr)\n\t\t{\n\t\t\treturn device;\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tstd::pair<int, ConfigDescriptor> MakeConfigDescriptor(libusb_device* device, uint8 config_num)\n\t{\n\t\tlibusb_config_descriptor* descriptor = nullptr;\n\t\tconst int ret = libusb_get_config_descriptor(device, config_num, &descriptor);\n\t\tif (ret == LIBUSB_SUCCESS)\n\t\t\treturn {ret, ConfigDescriptor{descriptor, libusb_free_config_descriptor}};\n\n\t\treturn {ret, ConfigDescriptor{nullptr, [](auto) {\n\t\t\t\t\t\t\t\t\t  }}};\n\t}\n\n\tstd::shared_ptr<Device> BackendLibusb::CheckAndCreateDevice(libusb_device* dev)\n\t{\n\t\tstruct libusb_device_descriptor desc;\n\t\tint ret = libusb_get_device_descriptor(dev, &desc);\n\t\tif (ret < 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force,\n\t\t\t\t\t\t\"nsyshid::BackendLibusb::CheckAndCreateDevice(): failed to get device descriptor; return code: %i\",\n\t\t\t\t\t\tret);\n\t\t\treturn nullptr;\n\t\t}\n\t\tstd::vector<ConfigDescriptor> config_descriptors{};\n\t\tfor (uint8 i = 0; i < desc.bNumConfigurations; ++i)\n\t\t{\n\t\t\tauto [ret, config_descriptor] = MakeConfigDescriptor(dev, i);\n\t\t\tif (ret != LIBUSB_SUCCESS || !config_descriptor)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to make config descriptor {} for {:04x}:{:04x}: {}\",\n\t\t\t\t\t\t\ti, desc.idVendor, desc.idProduct, libusb_error_name(ret));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconfig_descriptors.emplace_back(std::move(config_descriptor));\n\t\t\t}\n\t\t}\n\t\tif (desc.idVendor == 0x0e6f && desc.idProduct == 0x0241)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t\t \"nsyshid::BackendLibusb::CheckAndCreateDevice(): lego dimensions portal detected\");\n\t\t}\n\t\tauto device = std::make_shared<DeviceLibusb>(m_ctx,\n\t\t\t\t\t\t\t\t\t\t\t\t\t desc.idVendor,\n\t\t\t\t\t\t\t\t\t\t\t\t\t desc.idProduct,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t libusb_get_bus_number(dev),\n\t\t\t\t\t\t\t\t\t\t\t\t\t libusb_get_device_address(dev),\n\t\t\t\t\t\t\t\t\t\t\t\t\t std::move(config_descriptors));\n\t\t// figure out device endpoints\n\t\tif (!FindDefaultDeviceEndpoints(dev,\n\t\t\t\t\t\t\t\t\t\tdevice->m_libusbHasEndpointIn,\n\t\t\t\t\t\t\t\t\t\tdevice->m_libusbEndpointIn,\n\t\t\t\t\t\t\t\t\t\tdevice->m_maxPacketSizeRX,\n\t\t\t\t\t\t\t\t\t\tdevice->m_libusbHasEndpointOut,\n\t\t\t\t\t\t\t\t\t\tdevice->m_libusbEndpointOut,\n\t\t\t\t\t\t\t\t\t\tdevice->m_maxPacketSizeTX))\n\t\t{\n\t\t\t// most likely couldn't read config descriptor\n\t\t\tcemuLog_log(LogType::Force,\n\t\t\t\t\t\t\"nsyshid::BackendLibusb::CheckAndCreateDevice(): failed to find default endpoints for device: {:04x}:{:04x}\",\n\t\t\t\t\t\tdevice->m_vendorId,\n\t\t\t\t\t\tdevice->m_productId);\n\t\t\treturn nullptr;\n\t\t}\n\t\treturn device;\n\t}\n\n\tbool BackendLibusb::FindDefaultDeviceEndpoints(libusb_device* dev, bool& endpointInFound, uint8& endpointIn,\n\t\t\t\t\t\t\t\t\t\t\t\t   uint16& endpointInMaxPacketSize, bool& endpointOutFound,\n\t\t\t\t\t\t\t\t\t\t\t\t   uint8& endpointOut, uint16& endpointOutMaxPacketSize)\n\t{\n\t\tendpointInFound = false;\n\t\tendpointIn = 0;\n\t\tendpointInMaxPacketSize = 0;\n\t\tendpointOutFound = false;\n\t\tendpointOut = 0;\n\t\tendpointOutMaxPacketSize = 0;\n\n\t\tstruct libusb_config_descriptor* conf = nullptr;\n\t\tint ret = libusb_get_active_config_descriptor(dev, &conf);\n\n\t\tif (ret == 0)\n\t\t{\n\t\t\tfor (uint8 interfaceIndex = 0; interfaceIndex < conf->bNumInterfaces; interfaceIndex++)\n\t\t\t{\n\t\t\t\tconst struct libusb_interface& interface = conf->interface[interfaceIndex];\n\t\t\t\tfor (int altsettingIndex = 0; altsettingIndex < interface.num_altsetting; altsettingIndex++)\n\t\t\t\t{\n\t\t\t\t\tconst struct libusb_interface_descriptor& altsetting = interface.altsetting[altsettingIndex];\n\t\t\t\t\tfor (uint8 endpointIndex = 0; endpointIndex < altsetting.bNumEndpoints; endpointIndex++)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst struct libusb_endpoint_descriptor& endpoint = altsetting.endpoint[endpointIndex];\n\t\t\t\t\t\t// figure out direction\n\t\t\t\t\t\tif ((endpoint.bEndpointAddress & (1 << 7)) != 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// in\n\t\t\t\t\t\t\tif (!endpointInFound)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tendpointInFound = true;\n\t\t\t\t\t\t\t\tendpointIn = endpoint.bEndpointAddress;\n\t\t\t\t\t\t\t\tendpointInMaxPacketSize = endpoint.wMaxPacketSize;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// out\n\t\t\t\t\t\t\tif (!endpointOutFound)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tendpointOutFound = true;\n\t\t\t\t\t\t\t\tendpointOut = endpoint.bEndpointAddress;\n\t\t\t\t\t\t\t\tendpointOutMaxPacketSize = endpoint.wMaxPacketSize;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tlibusb_free_config_descriptor(conf);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tDeviceLibusb::DeviceLibusb(libusb_context* ctx,\n\t\t\t\t\t\t\t   uint16 vendorId,\n\t\t\t\t\t\t\t   uint16 productId,\n\t\t\t\t\t\t\t   uint8 interfaceIndex,\n\t\t\t\t\t\t\t   uint8 interfaceSubClass,\n\t\t\t\t\t\t\t   uint8 protocol,\n\t\t\t\t\t\t\t   uint8 libusbBusNumber,\n\t\t\t\t\t\t\t   uint8 libusbDeviceAddress,\n\t\t\t\t\t\t\t   std::vector<ConfigDescriptor> configs)\n\t\t: Device(vendorId,\n\t\t\t\t productId,\n\t\t\t\t interfaceIndex,\n\t\t\t\t interfaceSubClass,\n\t\t\t\t protocol),\n\t\t  m_ctx(ctx),\n\t\t  m_libusbHandle(nullptr),\n\t\t  m_handleInUseCounter(-1),\n\t\t  m_libusbBusNumber(libusbBusNumber),\n\t\t  m_libusbDeviceAddress(libusbDeviceAddress),\n\t\t  m_libusbHasEndpointIn(false),\n\t\t  m_libusbEndpointIn(0),\n\t\t  m_libusbHasEndpointOut(false),\n\t\t  m_libusbEndpointOut(0)\n\t{\n\t\tm_config_descriptors = std::move(configs);\n\t}\n\n\tDeviceLibusb::~DeviceLibusb()\n\t{\n\t\tCloseDevice();\n\t}\n\n\tbool DeviceLibusb::Open()\n\t{\n\t\tstd::unique_lock<std::mutex> lock(m_handleMutex);\n\t\tif (IsOpened())\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\t// we may still be in the process of closing the device; wait for that to finish\n\t\twhile (m_handleInUseCounter != -1)\n\t\t{\n\t\t\tm_handleInUseCounterDecremented.wait(lock);\n\t\t}\n\n\t\tlibusb_device** devices;\n\t\tssize_t deviceCount = libusb_get_device_list(m_ctx, &devices);\n\t\tif (deviceCount < 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"nsyshid::DeviceLibusb::open(): failed to get usb devices\");\n\t\t\treturn false;\n\t\t}\n\t\tlibusb_device* dev;\n\t\tlibusb_device* found = nullptr;\n\t\tfor (int i = 0; (dev = devices[i]) != nullptr; i++)\n\t\t{\n\t\t\tstruct libusb_device_descriptor desc;\n\t\t\tint ret = libusb_get_device_descriptor(dev, &desc);\n\t\t\tif (ret < 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force,\n\t\t\t\t\t\t\t\"nsyshid::DeviceLibusb::open(): failed to get device descriptor, return code: {}\",\n\t\t\t\t\t\t\tret);\n\t\t\t\tlibusb_free_device_list(devices, 1);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (desc.idVendor == this->m_vendorId &&\n\t\t\t\tdesc.idProduct == this->m_productId &&\n\t\t\t\tlibusb_get_bus_number(dev) == this->m_libusbBusNumber &&\n\t\t\t\tlibusb_get_device_address(dev) == this->m_libusbDeviceAddress)\n\t\t\t{\n\t\t\t\t// we found our device!\n\t\t\t\tfound = dev;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (found != nullptr)\n\t\t{\n\t\t\t{\n\t\t\t\tint ret = libusb_open(dev, &(this->m_libusbHandle));\n\t\t\t\tif (ret < 0)\n\t\t\t\t{\n\t\t\t\t\tthis->m_libusbHandle = nullptr;\n\t\t\t\t\tcemuLog_log(LogType::Force,\n\t\t\t\t\t\t\t\t\"nsyshid::DeviceLibusb::open(): failed to open device: {}\",\n\t\t\t\t\t\t\t\tlibusb_strerror(ret));\n\t\t\t\t\tlibusb_free_device_list(devices, 1);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tthis->m_handleInUseCounter = 0;\n\t\t\t}\n\n\t\t\tint ret = ClaimAllInterfaces(0);\n\n\t\t\tif (ret != 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"nsyshid::DeviceLibusb::open(): cannot claim interface for config 0\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tlibusb_free_device_list(devices, 1);\n\t\treturn found != nullptr;\n\t}\n\n\tvoid DeviceLibusb::Close()\n\t{\n\t\tCloseDevice();\n\t}\n\n\tvoid DeviceLibusb::CloseDevice()\n\t{\n\t\tstd::unique_lock<std::mutex> lock(m_handleMutex);\n\t\tif (IsOpened())\n\t\t{\n\t\t\tauto handle = m_libusbHandle;\n\t\t\tm_libusbHandle = nullptr;\n\t\t\twhile (m_handleInUseCounter > 0)\n\t\t\t{\n\t\t\t\tm_handleInUseCounterDecremented.wait(lock);\n\t\t\t}\n\t\t\tReleaseAllInterfacesForCurrentConfig();\n\t\t\tlibusb_close(handle);\n\t\t\tm_handleInUseCounter = -1;\n\t\t\tm_handleInUseCounterDecremented.notify_all();\n\t\t}\n\t}\n\n\tbool DeviceLibusb::IsOpened()\n\t{\n\t\treturn m_libusbHandle != nullptr && m_handleInUseCounter >= 0;\n\t}\n\n\tDevice::ReadResult DeviceLibusb::Read(ReadMessage* message)\n\t{\n\t\tauto handleLock = AquireHandleLock();\n\t\tif (!handleLock->IsValid())\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t\t \"nsyshid::DeviceLibusb::read(): cannot read from a non-opened device\\n\");\n\t\t\treturn ReadResult::Error;\n\t\t}\n\n\t\tfor (int i = 0; i < m_config_descriptors.size(); i++)\n\t\t{\n\t\t\tClaimAllInterfaces(i);\n\t\t}\n\n\t\tconst unsigned int timeout = 50;\n\t\tint actualLength = 0;\n\t\tint ret = 0;\n\t\tdo\n\t\t{\n\t\t\tret = libusb_interrupt_transfer(handleLock->GetHandle(),\n\t\t\t\t\t\t\t\t\t\t\tthis->m_libusbEndpointIn,\n\t\t\t\t\t\t\t\t\t\t\tmessage->data,\n\t\t\t\t\t\t\t\t\t\t\tmessage->length,\n\t\t\t\t\t\t\t\t\t\t\t&actualLength,\n\t\t\t\t\t\t\t\t\t\t\ttimeout);\n\t\t}\n\t\twhile (ret == LIBUSB_ERROR_TIMEOUT && actualLength == 0 && IsOpened());\n\n\t\tif (ret == 0 || ret == LIBUSB_ERROR_TIMEOUT)\n\t\t{\n\t\t\t// success\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::DeviceLibusb::read(): read {} of {} bytes\",\n\t\t\t\t\t\t\t actualLength,\n\t\t\t\t\t\t\t message->length);\n\t\t\tmessage->bytesRead = actualLength;\n\t\t\treturn ReadResult::Success;\n\t\t}\n\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t \"nsyshid::DeviceLibusb::read(): failed at endpoint 0x{:02x} with error message: {}\", this->m_libusbEndpointIn,\n\t\t\t\t\t\t libusb_error_name(ret));\n\t\treturn ReadResult::Error;\n\t}\n\n\tDevice::WriteResult DeviceLibusb::Write(WriteMessage* message)\n\t{\n\t\tauto handleLock = AquireHandleLock();\n\t\tif (!handleLock->IsValid())\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t\t \"nsyshid::DeviceLibusb::write(): cannot write to a non-opened device\\n\");\n\t\t\treturn WriteResult::Error;\n\t\t}\n\n\t\tfor (int i = 0; i < m_config_descriptors.size(); i++)\n\t\t{\n\t\t\tClaimAllInterfaces(i);\n\t\t}\n\n\t\tmessage->bytesWritten = 0;\n\t\tint actualLength = 0;\n\t\tint ret = libusb_interrupt_transfer(handleLock->GetHandle(),\n\t\t\t\t\t\t\t\t\t\t\tthis->m_libusbEndpointOut,\n\t\t\t\t\t\t\t\t\t\t\tmessage->data,\n\t\t\t\t\t\t\t\t\t\t\tmessage->length,\n\t\t\t\t\t\t\t\t\t\t\t&actualLength,\n\t\t\t\t\t\t\t\t\t\t\t0);\n\n\t\tif (ret == 0)\n\t\t{\n\t\t\t// success\n\t\t\tmessage->bytesWritten = actualLength;\n\t\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t\t \"nsyshid::DeviceLibusb::write(): wrote {} of {} bytes\",\n\t\t\t\t\t\t\t message->bytesWritten,\n\t\t\t\t\t\t\t message->length);\n\t\t\treturn WriteResult::Success;\n\t\t}\n\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t \"nsyshid::DeviceLibusb::write(): failed with error code: {}\",\n\t\t\t\t\t\t ret);\n\t\treturn WriteResult::Error;\n\t}\n\n\tbool DeviceLibusb::GetDescriptor(uint8 descType,\n\t\t\t\t\t\t\t\t\t uint8 descIndex,\n\t\t\t\t\t\t\t\t\t uint16 lang,\n\t\t\t\t\t\t\t\t\t uint8* output,\n\t\t\t\t\t\t\t\t\t uint32 outputMaxLength)\n\t{\n\t\tauto handleLock = AquireHandleLock();\n\t\tif (!handleLock->IsValid())\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::DeviceLibusb::getDescriptor(): device is not opened\");\n\t\t\treturn false;\n\t\t}\n\n\t\tif (descType == 0x02)\n\t\t{\n\t\t\tstruct libusb_config_descriptor* conf = nullptr;\n\t\t\tlibusb_device* dev = libusb_get_device(handleLock->GetHandle());\n\t\t\tint ret = libusb_get_active_config_descriptor(dev, &conf);\n\t\t\tif (ret == 0)\n\t\t\t{\n\t\t\t\tstd::vector<uint8> configurationDescriptor(conf->wTotalLength);\n\t\t\t\tuint8* currentWritePtr = &configurationDescriptor[0];\n\n\t\t\t\t// configuration descriptor\n\t\t\t\tcemu_assert_debug(conf->bLength == LIBUSB_DT_CONFIG_SIZE);\n\t\t\t\t*(uint8*)(currentWritePtr + 0) = conf->bLength;\t\t\t\t// bLength\n\t\t\t\t*(uint8*)(currentWritePtr + 1) = conf->bDescriptorType;\t\t// bDescriptorType\n\t\t\t\t*(uint16be*)(currentWritePtr + 2) = conf->wTotalLength;\t\t// wTotalLength\n\t\t\t\t*(uint8*)(currentWritePtr + 4) = conf->bNumInterfaces;\t\t// bNumInterfaces\n\t\t\t\t*(uint8*)(currentWritePtr + 5) = conf->bConfigurationValue; // bConfigurationValue\n\t\t\t\t*(uint8*)(currentWritePtr + 6) = conf->iConfiguration;\t\t// iConfiguration\n\t\t\t\t*(uint8*)(currentWritePtr + 7) = conf->bmAttributes;\t\t// bmAttributes\n\t\t\t\t*(uint8*)(currentWritePtr + 8) = conf->MaxPower;\t\t\t// MaxPower\n\t\t\t\tcurrentWritePtr = currentWritePtr + conf->bLength;\n\n\t\t\t\tfor (uint8_t interfaceIndex = 0; interfaceIndex < conf->bNumInterfaces; interfaceIndex++)\n\t\t\t\t{\n\t\t\t\t\tconst struct libusb_interface& interface = conf->interface[interfaceIndex];\n\t\t\t\t\tfor (int altsettingIndex = 0; altsettingIndex < interface.num_altsetting; altsettingIndex++)\n\t\t\t\t\t{\n\t\t\t\t\t\t// interface descriptor\n\t\t\t\t\t\tconst struct libusb_interface_descriptor& altsetting = interface.altsetting[altsettingIndex];\n\t\t\t\t\t\tcemu_assert_debug(altsetting.bLength == LIBUSB_DT_INTERFACE_SIZE);\n\t\t\t\t\t\t*(uint8*)(currentWritePtr + 0) = altsetting.bLength;\t\t\t// bLength\n\t\t\t\t\t\t*(uint8*)(currentWritePtr + 1) = altsetting.bDescriptorType;\t// bDescriptorType\n\t\t\t\t\t\t*(uint8*)(currentWritePtr + 2) = altsetting.bInterfaceNumber;\t// bInterfaceNumber\n\t\t\t\t\t\t*(uint8*)(currentWritePtr + 3) = altsetting.bAlternateSetting;\t// bAlternateSetting\n\t\t\t\t\t\t*(uint8*)(currentWritePtr + 4) = altsetting.bNumEndpoints;\t\t// bNumEndpoints\n\t\t\t\t\t\t*(uint8*)(currentWritePtr + 5) = altsetting.bInterfaceClass;\t// bInterfaceClass\n\t\t\t\t\t\t*(uint8*)(currentWritePtr + 6) = altsetting.bInterfaceSubClass; // bInterfaceSubClass\n\t\t\t\t\t\t*(uint8*)(currentWritePtr + 7) = altsetting.bInterfaceProtocol; // bInterfaceProtocol\n\t\t\t\t\t\t*(uint8*)(currentWritePtr + 8) = altsetting.iInterface;\t\t\t// iInterface\n\t\t\t\t\t\tcurrentWritePtr = currentWritePtr + altsetting.bLength;\n\n\t\t\t\t\t\tif (altsetting.extra_length > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// unknown descriptors - copy the ones that we can identify ourselves\n\t\t\t\t\t\t\tconst unsigned char* extraReadPointer = altsetting.extra;\n\t\t\t\t\t\t\twhile (extraReadPointer - altsetting.extra < altsetting.extra_length)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuint8 bLength = *(uint8*)(extraReadPointer + 0);\n\t\t\t\t\t\t\t\tif (bLength == 0)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// prevent endless loop\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (extraReadPointer + bLength - altsetting.extra > altsetting.extra_length)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// prevent out of bounds read\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tuint8 bDescriptorType = *(uint8*)(extraReadPointer + 1);\n\t\t\t\t\t\t\t\t// HID descriptor\n\t\t\t\t\t\t\t\tif (bDescriptorType == LIBUSB_DT_HID && bLength == 9)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 0) =\n\t\t\t\t\t\t\t\t\t\t*(uint8*)(extraReadPointer + 0); // bLength\n\t\t\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 1) =\n\t\t\t\t\t\t\t\t\t\t*(uint8*)(extraReadPointer + 1); // bDescriptorType\n\t\t\t\t\t\t\t\t\t*(uint16be*)(currentWritePtr + 2) =\n\t\t\t\t\t\t\t\t\t\t*(uint16*)(extraReadPointer + 2); // bcdHID\n\t\t\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 4) =\n\t\t\t\t\t\t\t\t\t\t*(uint8*)(extraReadPointer + 4); // bCountryCode\n\t\t\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 5) =\n\t\t\t\t\t\t\t\t\t\t*(uint8*)(extraReadPointer + 5); // bNumDescriptors\n\t\t\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 6) =\n\t\t\t\t\t\t\t\t\t\t*(uint8*)(extraReadPointer + 6); // bDescriptorType\n\t\t\t\t\t\t\t\t\t*(uint16be*)(currentWritePtr + 7) =\n\t\t\t\t\t\t\t\t\t\t*(uint16*)(extraReadPointer + 7); // wDescriptorLength\n\t\t\t\t\t\t\t\t\tcurrentWritePtr += bLength;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\textraReadPointer += bLength;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (int endpointIndex = 0; endpointIndex < altsetting.bNumEndpoints; endpointIndex++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// endpoint descriptor\n\t\t\t\t\t\t\tconst struct libusb_endpoint_descriptor& endpoint = altsetting.endpoint[endpointIndex];\n\t\t\t\t\t\t\tcemu_assert_debug(endpoint.bLength == LIBUSB_DT_ENDPOINT_SIZE ||\n\t\t\t\t\t\t\t\t\t\t\t  endpoint.bLength == LIBUSB_DT_ENDPOINT_AUDIO_SIZE);\n\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 0) = endpoint.bLength;\n\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 1) = endpoint.bDescriptorType;\n\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 2) = endpoint.bEndpointAddress;\n\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 3) = endpoint.bmAttributes;\n\t\t\t\t\t\t\t*(uint16be*)(currentWritePtr + 4) = endpoint.wMaxPacketSize;\n\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 6) = endpoint.bInterval;\n\t\t\t\t\t\t\tif (endpoint.bLength == LIBUSB_DT_ENDPOINT_AUDIO_SIZE)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 7) = endpoint.bRefresh;\n\t\t\t\t\t\t\t\t*(uint8*)(currentWritePtr + 8) = endpoint.bSynchAddress;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcurrentWritePtr += endpoint.bLength;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tuint32 bytesWritten = currentWritePtr - &configurationDescriptor[0];\n\t\t\t\tlibusb_free_config_descriptor(conf);\n\t\t\t\tcemu_assert_debug(bytesWritten <= conf->wTotalLength);\n\t\t\t\tmemcpy(output, &configurationDescriptor[0],\n\t\t\t\t\t   std::min<uint32>(outputMaxLength, bytesWritten));\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint16 wValue = uint16(descType) << 8 | uint16(descIndex);\n\t\t\t// HID Get_Descriptor requests are handled via libusb_control_transfer\n\t\t\tint ret = libusb_control_transfer(handleLock->GetHandle(),\n\t\t\t\t\t\t\t\t\t\t\t  LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_ENDPOINT_IN,\n\t\t\t\t\t\t\t\t\t\t\t  LIBUSB_REQUEST_GET_DESCRIPTOR,\n\t\t\t\t\t\t\t\t\t\t\t  wValue,\n\t\t\t\t\t\t\t\t\t\t\t  lang,\n\t\t\t\t\t\t\t\t\t\t\t  output,\n\t\t\t\t\t\t\t\t\t\t\t  outputMaxLength,\n\t\t\t\t\t\t\t\t\t\t\t  0);\n\t\t\tif (ret != outputMaxLength)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::DeviceLibusb::GetDescriptor(): Control Transfer Failed: {}\", libusb_error_name(ret));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool DeviceLibusb::SetIdle(uint8 ifIndex,\n\t\t\t\t\t\t\t   uint8 reportId,\n\t\t\t\t\t\t\t   uint8 duration)\n\t{\n\t\tauto handleLock = AquireHandleLock();\n\t\tif (!handleLock->IsValid())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"nsyshid::DeviceLibusb::SetIdle(): device is not opened\");\n\t\t\treturn false;\n\t\t}\n\n\t\tuint16 wValue = uint16(duration) << 8 | uint16(reportId);\n\n\t\t// HID Set_Idle requests are handled via libusb_control_transfer\n\t\tint ret = libusb_control_transfer(handleLock->GetHandle(),\n\t\t\t\t\t\t\t\t\t\t  LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,\n\t\t\t\t\t\t\t\t\t\t  HID_CLASS_SET_IDLE, // Defined in HID Class Specific Requests (7.2)\n\t\t\t\t\t\t\t\t\t\t  wValue,\n\t\t\t\t\t\t\t\t\t\t  ifIndex,\n\t\t\t\t\t\t\t\t\t\t  nullptr,\n\t\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t\t  0);\n\n\t\tif (ret != 0)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::DeviceLibusb::SetIdle(): Control Transfer Failed: {}\", libusb_error_name(ret));\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\ttemplate<typename Configs, typename Function>\n\tstatic int DoForEachInterface(const Configs& configs, uint8 config_num, Function action)\n\t{\n\t\tint ret = LIBUSB_ERROR_NOT_FOUND;\n\t\tif (configs.size() <= config_num || !configs[config_num])\n\t\t\treturn ret;\n\t\tfor (uint8 i = 0; i < configs[config_num]->bNumInterfaces; ++i)\n\t\t{\n\t\t\tret = action(i);\n\t\t\tif (ret < LIBUSB_SUCCESS)\n\t\t\t\tbreak;\n\t\t}\n\t\treturn ret;\n\t}\n\n\tint DeviceLibusb::ClaimAllInterfaces(uint8 config_num)\n\t{\n\t\tconst int ret = DoForEachInterface(m_config_descriptors, config_num, [this](uint8 i) {\n\t\t// On macos detaching would fail without root or entitlement.\n\t\t// We assume user is using GCAdapterDriver and therefore don't want to detach anything\n#if !defined(__APPLE__)\n\t\t\tif (libusb_kernel_driver_active(this->m_libusbHandle, i))\n\t\t\t{\n\t\t\t\tconst int ret2 = libusb_detach_kernel_driver(this->m_libusbHandle, i);\n\t\t\t\tif (ret2 < LIBUSB_SUCCESS && ret2 != LIBUSB_ERROR_NOT_FOUND &&\n\t\t\t\t\tret2 != LIBUSB_ERROR_NOT_SUPPORTED)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Failed to detach kernel driver {}\", libusb_error_name(ret2));\n\t\t\t\t\treturn ret2;\n\t\t\t\t}\n\t\t\t}\n#endif\n\t\t\treturn libusb_claim_interface(this->m_libusbHandle, i);\n\t\t});\n\t\tif (ret < LIBUSB_SUCCESS)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to release all interfaces for config {}\", config_num);\n\t\t}\n\t\treturn ret;\n\t}\n\n\tint DeviceLibusb::ReleaseAllInterfaces(uint8 config_num)\n\t{\n\t\tconst int ret = DoForEachInterface(m_config_descriptors, config_num, [this](uint8 i) {\n\t\t\treturn libusb_release_interface(AquireHandleLock()->GetHandle(), i);\n\t\t});\n\t\tif (ret < LIBUSB_SUCCESS && ret != LIBUSB_ERROR_NO_DEVICE && ret != LIBUSB_ERROR_NOT_FOUND)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to release all interfaces for config {}\", config_num);\n\t\t}\n\t\treturn ret;\n\t}\n\n\tint DeviceLibusb::ReleaseAllInterfacesForCurrentConfig()\n\t{\n\t\tint config_num;\n\t\tconst int get_config_ret = libusb_get_configuration(AquireHandleLock()->GetHandle(), &config_num);\n\t\tif (get_config_ret < LIBUSB_SUCCESS)\n\t\t\treturn get_config_ret;\n\t\treturn ReleaseAllInterfaces(config_num);\n\t}\n\n\tbool DeviceLibusb::SetProtocol(uint8 ifIndex, uint8 protocol)\n\t{\n\t\tauto handleLock = AquireHandleLock();\n\t\tif (!handleLock->IsValid())\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::DeviceLibusb::SetProtocol(): device is not opened\");\n\t\t\treturn false;\n\t\t}\n\n\t\tint ret = libusb_control_transfer(handleLock->GetHandle(),\n\t\t\t\t\t\t\t\t\t\t  LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,\n\t\t\t\t\t\t\t\t\t\t  HID_CLASS_SET_PROTOCOL, // Defined in HID Class Specific Requests (7.2)\n\t\t\t\t\t\t\t\t\t\t  protocol,\n\t\t\t\t\t\t\t\t\t\t  ifIndex,\n\t\t\t\t\t\t\t\t\t\t  nullptr,\n\t\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t\t  0);\n\n\t\tif (ret != 0)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::DeviceLibusb::SetProtocol(): Control Transfer Failed: {}\", libusb_error_name(ret));\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool DeviceLibusb::SetReport(ReportMessage* message)\n\t{\n\t\tauto handleLock = AquireHandleLock();\n\t\tif (!handleLock->IsValid())\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::DeviceLibusb::SetReport(): device is not opened\");\n\t\t\treturn false;\n\t\t}\n\n\t\tuint16 wValue = uint16(message->reportType) << 8 | uint16(message->reportId);\n\n\t\tint ret = libusb_control_transfer(handleLock->GetHandle(),\n\t\t\t\t\t\t\t\t\t\t  LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,\n\t\t\t\t\t\t\t\t\t\t  HID_CLASS_SET_REPORT, // Defined in HID Class Specific Requests (7.2)\n\t\t\t\t\t\t\t\t\t\t  wValue,\n\t\t\t\t\t\t\t\t\t\t  m_interfaceIndex,\n\t\t\t\t\t\t\t\t\t\t  message->data,\n\t\t\t\t\t\t\t\t\t\t  uint16(message->length & 0xFFFF),\n\t\t\t\t\t\t\t\t\t\t  0);\n\n\t\tif (ret != message->length)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid::DeviceLibusb::SetReport(): Control Transfer Failed at interface {} : {}\", m_interfaceIndex, libusb_error_name(ret));\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tstd::unique_ptr<DeviceLibusb::HandleLock> DeviceLibusb::AquireHandleLock()\n\t{\n\t\treturn std::make_unique<HandleLock>(&m_libusbHandle,\n\t\t\t\t\t\t\t\t\t\t\tm_handleMutex,\n\t\t\t\t\t\t\t\t\t\t\tm_handleInUseCounter,\n\t\t\t\t\t\t\t\t\t\t\tm_handleInUseCounterDecremented,\n\t\t\t\t\t\t\t\t\t\t\t*this);\n\t}\n\n\tDeviceLibusb::HandleLock::HandleLock(libusb_device_handle** handle,\n\t\t\t\t\t\t\t\t\t\t std::mutex& handleMutex,\n\t\t\t\t\t\t\t\t\t\t std::atomic<sint32>& handleInUseCounter,\n\t\t\t\t\t\t\t\t\t\t std::condition_variable& handleInUseCounterDecremented,\n\t\t\t\t\t\t\t\t\t\t DeviceLibusb& device)\n\t\t: m_handle(nullptr),\n\t\t  m_handleMutex(handleMutex),\n\t\t  m_handleInUseCounter(handleInUseCounter),\n\t\t  m_handleInUseCounterDecremented(handleInUseCounterDecremented)\n\t{\n\t\tstd::lock_guard<std::mutex> lock(handleMutex);\n\t\tif (device.IsOpened() && handle != nullptr && handleInUseCounter >= 0)\n\t\t{\n\t\t\tthis->m_handle = *handle;\n\t\t\tthis->m_handleInUseCounter++;\n\t\t}\n\t}\n\n\tDeviceLibusb::HandleLock::~HandleLock()\n\t{\n\t\tif (IsValid())\n\t\t{\n\t\t\tstd::lock_guard<std::mutex> lock(m_handleMutex);\n\t\t\tm_handleInUseCounter--;\n\t\t\tm_handleInUseCounterDecremented.notify_all();\n\t\t}\n\t}\n\n\tbool DeviceLibusb::HandleLock::IsValid()\n\t{\n\t\treturn m_handle != nullptr;\n\t}\n\n\tlibusb_device_handle* DeviceLibusb::HandleLock::GetHandle()\n\t{\n\t\treturn m_handle;\n\t}\n} // namespace nsyshid::backend::libusb\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/BackendLibusb.h",
    "content": "#include \"nsyshid.h\"\n\n#if BOOST_OS_BSD\n#include <libusb.h>\n#else\n#include <libusb-1.0/libusb.h>\n#endif\n#include \"Backend.h\"\n\nnamespace nsyshid::backend::libusb\n{\n\tenum : uint8\n\t{\n\t\tHID_CLASS_GET_REPORT   = 0x01,\n\t\tHID_CLASS_GET_IDLE     = 0x02,\n\t\tHID_CLASS_GET_PROTOCOL = 0x03,\n\t\tHID_CLASS_SET_REPORT   = 0x09,\n\t\tHID_CLASS_SET_IDLE     = 0x0A,\n\t\tHID_CLASS_SET_PROTOCOL = 0x0B\n\t};\n\n\tclass BackendLibusb : public nsyshid::Backend {\n\t  public:\n\t\tBackendLibusb();\n\n\t\t~BackendLibusb();\n\n\t\tbool IsInitialisedOk() override;\n\n\t  protected:\n\t\tvoid AttachVisibleDevices() override;\n\n\t  private:\n\t\tlibusb_context* m_ctx;\n\t\tint m_initReturnCode;\n\t\tbool m_callbackRegistered;\n\t\tlibusb_hotplug_callback_handle m_hotplugCallbackHandle;\n\t\tstd::thread m_hotplugThread;\n\t\tstd::atomic<bool> m_hotplugThreadStop;\n\n\t\t// called by libusb\n\t\tstatic int HotplugCallback(libusb_context* ctx, libusb_device* dev,\n\t\t\t\t\t\t\t\t   libusb_hotplug_event event, void* user_data);\n\n\t\tint OnHotplug(libusb_device* dev, libusb_hotplug_event event);\n\n\t\tstd::shared_ptr<Device> CheckAndCreateDevice(libusb_device* dev);\n\n\t\tstd::shared_ptr<Device> FindLibusbDevice(libusb_device* dev);\n\n\t\tbool FindDefaultDeviceEndpoints(libusb_device* dev,\n\t\t\t\t\t\t\t\t\t\tbool& endpointInFound, uint8& endpointIn, uint16& endpointInMaxPacketSize,\n\t\t\t\t\t\t\t\t\t\tbool& endpointOutFound, uint8& endpointOut, uint16& endpointOutMaxPacketSize);\n\t};\n\n\ttemplate<typename T>\n\tusing UniquePtr = std::unique_ptr<T, void (*)(T*)>;\n\n\tusing ConfigDescriptor = UniquePtr<libusb_config_descriptor>;\n\n\tclass DeviceLibusb : public nsyshid::Device {\n\t  public:\n\t\tDeviceLibusb(libusb_context* ctx,\n\t\t\t\t\t uint16 vendorId,\n\t\t\t\t\t uint16 productId,\n\t\t\t\t\t uint8 interfaceIndex,\n\t\t\t\t\t uint8 interfaceSubClass,\n\t\t\t\t\t uint8 protocol,\n\t\t\t\t\t uint8 libusbBusNumber,\n\t\t\t\t\t uint8 libusbDeviceAddress,\n\t\t\t\t\t std::vector<ConfigDescriptor> configs);\n\n\t\t~DeviceLibusb() override;\n\n\t\tbool Open() override;\n\n\t\tvoid Close() override;\n\n\t\tbool IsOpened() override;\n\n\t\tReadResult Read(ReadMessage* message) override;\n\n\t\tWriteResult Write(WriteMessage* message) override;\n\n\t\tbool GetDescriptor(uint8 descType,\n\t\t\t\t\t\t   uint8 descIndex,\n\t\t\t\t\t\t   uint16 lang,\n\t\t\t\t\t\t   uint8* output,\n\t\t\t\t\t\t   uint32 outputMaxLength) override;\n\n\t\tbool SetIdle(uint8 ifIndex,\n\t\t\t\t\t uint8 reportId,\n\t\t\t\t\t uint8 duration) override;\n\n\t\tbool SetProtocol(uint8 ifIndex, uint8 protocol) override;\n\n\t\tint ClaimAllInterfaces(uint8 config_num);\n\t\tint ReleaseAllInterfaces(uint8 config_num);\n\t\tint ReleaseAllInterfacesForCurrentConfig();\n\n\t\tbool SetReport(ReportMessage* message) override;\n\n\t\tuint8 m_libusbBusNumber;\n\t\tuint8 m_libusbDeviceAddress;\n\t\tbool m_libusbHasEndpointIn;\n\t\tuint8 m_libusbEndpointIn;\n\t\tbool m_libusbHasEndpointOut;\n\t\tuint8 m_libusbEndpointOut;\n\n\t  private:\n\t\tvoid CloseDevice();\n\n\t\tlibusb_context* m_ctx;\n\t\tstd::mutex m_handleMutex;\n\t\tstd::atomic<sint32> m_handleInUseCounter;\n\t\tstd::condition_variable m_handleInUseCounterDecremented;\n\t\tlibusb_device_handle* m_libusbHandle;\n\t\tstd::vector<ConfigDescriptor> m_config_descriptors;\n\n\t\tclass HandleLock {\n\t\t  public:\n\t\t\tHandleLock() = delete;\n\n\t\t\tHandleLock(libusb_device_handle** handle,\n\t\t\t\t\t   std::mutex& handleMutex,\n\t\t\t\t\t   std::atomic<sint32>& handleInUseCounter,\n\t\t\t\t\t   std::condition_variable& handleInUseCounterDecremented,\n\t\t\t\t\t   DeviceLibusb& device);\n\n\t\t\t~HandleLock();\n\n\t\t\tHandleLock(const HandleLock&) = delete;\n\n\t\t\tHandleLock& operator=(const HandleLock&) = delete;\n\n\t\t\tbool IsValid();\n\n\t\t\tlibusb_device_handle* GetHandle();\n\n\t\t  private:\n\t\t\tlibusb_device_handle* m_handle;\n\t\t\tstd::mutex& m_handleMutex;\n\t\t\tstd::atomic<sint32>& m_handleInUseCounter;\n\t\t\tstd::condition_variable& m_handleInUseCounterDecremented;\n\t\t};\n\n\t\tstd::unique_ptr<HandleLock> AquireHandleLock();\n\t};\n} // namespace nsyshid::backend::libusb\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/Dimensions.cpp",
    "content": "#include \"Dimensions.h\"\n\n#include \"nsyshid.h\"\n#include \"Backend.h\"\n\n#include \"Common/FileStream.h\"\n\n#include <array>\n#include <random>\n\nnamespace nsyshid\n{\n\tstatic constexpr std::array<uint8, 16> COMMAND_KEY = {0x55, 0xFE, 0xF6, 0xB0, 0x62, 0xBF, 0x0B, 0x41,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  0xC9, 0xB3, 0x7C, 0xB4, 0x97, 0x3E, 0x29, 0x7B};\n\n\tstatic constexpr std::array<uint8, 17> CHAR_CONSTANT = {0xB7, 0xD5, 0xD7, 0xE6, 0xE7, 0xBA, 0x3C, 0xA8,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t0xD8, 0x75, 0x47, 0x68, 0xCF, 0x23, 0xE9, 0xFE, 0xAA};\n\n\tstatic constexpr std::array<uint8, 25> PWD_CONSTANT = {0x28, 0x63, 0x29, 0x20, 0x43, 0x6F, 0x70, 0x79,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t   0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x4C, 0x45,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t   0x47, 0x4F, 0x20, 0x32, 0x30, 0x31, 0x34, 0xAA, 0xAA};\n\n\tDimensionsUSB g_dimensionstoypad;\n\n\tconst std::map<const uint32, const char*> s_listMinis = {\n\t\t{0, \"Blank Tag\"},\n\t\t{1, \"Batman\"},\n\t\t{2, \"Gandalf\"},\n\t\t{3, \"Wyldstyle\"},\n\t\t{4, \"Aquaman\"},\n\t\t{5, \"Bad Cop\"},\n\t\t{6, \"Bane\"},\n\t\t{7, \"Bart Simpson\"},\n\t\t{8, \"Benny\"},\n\t\t{9, \"Chell\"},\n\t\t{10, \"Cole\"},\n\t\t{11, \"Cragger\"},\n\t\t{12, \"Cyborg\"},\n\t\t{13, \"Cyberman\"},\n\t\t{14, \"Doc Brown\"},\n\t\t{15, \"The Doctor\"},\n\t\t{16, \"Emmet\"},\n\t\t{17, \"Eris\"},\n\t\t{18, \"Gimli\"},\n\t\t{19, \"Gollum\"},\n\t\t{20, \"Harley Quinn\"},\n\t\t{21, \"Homer Simpson\"},\n\t\t{22, \"Jay\"},\n\t\t{23, \"Joker\"},\n\t\t{24, \"Kai\"},\n\t\t{25, \"ACU Trooper\"},\n\t\t{26, \"Gamer Kid\"},\n\t\t{27, \"Krusty the Clown\"},\n\t\t{28, \"Laval\"},\n\t\t{29, \"Legolas\"},\n\t\t{30, \"Lloyd\"},\n\t\t{31, \"Marty McFly\"},\n\t\t{32, \"Nya\"},\n\t\t{33, \"Owen Grady\"},\n\t\t{34, \"Peter Venkman\"},\n\t\t{35, \"Slimer\"},\n\t\t{36, \"Scooby-Doo\"},\n\t\t{37, \"Sensei Wu\"},\n\t\t{38, \"Shaggy\"},\n\t\t{39, \"Stay Puft\"},\n\t\t{40, \"Superman\"},\n\t\t{41, \"Unikitty\"},\n\t\t{42, \"Wicked Witch of the West\"},\n\t\t{43, \"Wonder Woman\"},\n\t\t{44, \"Zane\"},\n\t\t{45, \"Green Arrow\"},\n\t\t{46, \"Supergirl\"},\n\t\t{47, \"Abby Yates\"},\n\t\t{48, \"Finn the Human\"},\n\t\t{49, \"Ethan Hunt\"},\n\t\t{50, \"Lumpy Space Princess\"},\n\t\t{51, \"Jake the Dog\"},\n\t\t{52, \"Harry Potter\"},\n\t\t{53, \"Lord Voldemort\"},\n\t\t{54, \"Michael Knight\"},\n\t\t{55, \"B.A. Baracus\"},\n\t\t{56, \"Newt Scamander\"},\n\t\t{57, \"Sonic the Hedgehog\"},\n\t\t{58, \"Future Update (unreleased)\"},\n\t\t{59, \"Gizmo\"},\n\t\t{60, \"Stripe\"},\n\t\t{61, \"E.T.\"},\n\t\t{62, \"Tina Goldstein\"},\n\t\t{63, \"Marceline the Vampire Queen\"},\n\t\t{64, \"Batgirl\"},\n\t\t{65, \"Robin\"},\n\t\t{66, \"Sloth\"},\n\t\t{67, \"Hermione Granger\"},\n\t\t{68, \"Chase McCain\"},\n\t\t{69, \"Excalibur Batman\"},\n\t\t{70, \"Raven\"},\n\t\t{71, \"Beast Boy\"},\n\t\t{72, \"Betelgeuse\"},\n\t\t{73, \"Lord Vortech (unreleased)\"},\n\t\t{74, \"Blossom\"},\n\t\t{75, \"Bubbles\"},\n\t\t{76, \"Buttercup\"},\n\t\t{77, \"Starfire\"},\n\t\t{78, \"World 15 (unreleased)\"},\n\t\t{79, \"World 16 (unreleased)\"},\n\t\t{80, \"World 17 (unreleased)\"},\n\t\t{81, \"World 18 (unreleased)\"},\n\t\t{82, \"World 19 (unreleased)\"},\n\t\t{83, \"World 20 (unreleased)\"},\n\t\t{768, \"Unknown 768\"},\n\t\t{769, \"Supergirl Red Lantern\"},\n\t\t{770, \"Unknown 770\"}};\n\n\tconst std::map<const uint32, const char*> s_listTokens = {\n\t\t{1000, \"Police Car\"},\n\t\t{1001, \"Aerial Squad Car\"},\n\t\t{1002, \"Missile Striker\"},\n\t\t{1003, \"Gravity Sprinter\"},\n\t\t{1004, \"Street Shredder\"},\n\t\t{1005, \"Sky Clobberer\"},\n\t\t{1006, \"Batmobile\"},\n\t\t{1007, \"Batblaster\"},\n\t\t{1008, \"Sonic Batray\"},\n\t\t{1009, \"Benny's Spaceship\"},\n\t\t{1010, \"Lasercraft\"},\n\t\t{1011, \"The Annihilator\"},\n\t\t{1012, \"DeLorean Time Machine\"},\n\t\t{1013, \"Electric Time Machine\"},\n\t\t{1014, \"Ultra Time Machine\"},\n\t\t{1015, \"Hoverboard\"},\n\t\t{1016, \"Cyclone Board\"},\n\t\t{1017, \"Ultimate Hoverjet\"},\n\t\t{1018, \"Eagle Interceptor\"},\n\t\t{1019, \"Eagle Sky Blazer\"},\n\t\t{1020, \"Eagle Swoop Diver\"},\n\t\t{1021, \"Swamp Skimmer\"},\n\t\t{1022, \"Cragger's Fireship\"},\n\t\t{1023, \"Croc Command Sub\"},\n\t\t{1024, \"Cyber-Guard\"},\n\t\t{1025, \"Cyber-Wrecker\"},\n\t\t{1026, \"Laser Robot Walker\"},\n\t\t{1027, \"K-9\"},\n\t\t{1028, \"K-9 Ruff Rover\"},\n\t\t{1029, \"K-9 Laser Cutter\"},\n\t\t{1030, \"TARDIS\"},\n\t\t{1031, \"Laser-Pulse TARDIS\"},\n\t\t{1032, \"Energy-Burst TARDIS\"},\n\t\t{1033, \"Emmet's Excavator\"},\n\t\t{1034, \"Destroy Dozer\"},\n\t\t{1035, \"Destruct-o-Mech\"},\n\t\t{1036, \"Winged Monkey\"},\n\t\t{1037, \"Battle Monkey\"},\n\t\t{1038, \"Commander Monkey\"},\n\t\t{1039, \"Axe Chariot\"},\n\t\t{1040, \"Axe Hurler\"},\n\t\t{1041, \"Soaring Chariot\"},\n\t\t{1042, \"Shelob the Great\"},\n\t\t{1043, \"8-Legged Stalker\"},\n\t\t{1044, \"Poison Slinger\"},\n\t\t{1045, \"Homer's Car\"},\n\t\t{1047, \"The SubmaHomer\"},\n\t\t{1046, \"The Homercraft\"},\n\t\t{1048, \"Taunt-o-Vision\"},\n\t\t{1050, \"The MechaHomer\"},\n\t\t{1049, \"Blast Cam\"},\n\t\t{1051, \"Velociraptor\"},\n\t\t{1053, \"Venom Raptor\"},\n\t\t{1052, \"Spike Attack Raptor\"},\n\t\t{1054, \"Gyrosphere\"},\n\t\t{1055, \"Sonic Beam Gyrosphere\"},\n\t\t{1056, \" Gyrosphere\"},\n\t\t{1057, \"Clown Bike\"},\n\t\t{1058, \"Cannon Bike\"},\n\t\t{1059, \"Anti-Gravity Rocket Bike\"},\n\t\t{1060, \"Mighty Lion Rider\"},\n\t\t{1061, \"Lion Blazer\"},\n\t\t{1062, \"Fire Lion\"},\n\t\t{1063, \"Arrow Launcher\"},\n\t\t{1064, \"Seeking Shooter\"},\n\t\t{1065, \"Triple Ballista\"},\n\t\t{1066, \"Mystery Machine\"},\n\t\t{1067, \"Mystery Tow & Go\"},\n\t\t{1068, \"Mystery Monster\"},\n\t\t{1069, \"Boulder Bomber\"},\n\t\t{1070, \"Boulder Blaster\"},\n\t\t{1071, \"Cyclone Jet\"},\n\t\t{1072, \"Storm Fighter\"},\n\t\t{1073, \"Lightning Jet\"},\n\t\t{1074, \"Electro-Shooter\"},\n\t\t{1075, \"Blade Bike\"},\n\t\t{1076, \"Flight Fire Bike\"},\n\t\t{1077, \"Blades of Fire\"},\n\t\t{1078, \"Samurai Mech\"},\n\t\t{1079, \"Samurai Shooter\"},\n\t\t{1080, \"Soaring Samurai Mech\"},\n\t\t{1081, \"Companion Cube\"},\n\t\t{1082, \"Laser Deflector\"},\n\t\t{1083, \"Gold Heart Emitter\"},\n\t\t{1084, \"Sentry Turret\"},\n\t\t{1085, \"Turret Striker\"},\n\t\t{1086, \"Flight Turret Carrier\"},\n\t\t{1087, \"Scooby Snack\"},\n\t\t{1088, \"Scooby Fire Snack\"},\n\t\t{1089, \"Scooby Ghost Snack\"},\n\t\t{1090, \"Cloud Cuckoo Car\"},\n\t\t{1091, \"X-Stream Soaker\"},\n\t\t{1092, \"Rainbow Cannon\"},\n\t\t{1093, \"Invisible Jet\"},\n\t\t{1094, \"Laser Shooter\"},\n\t\t{1095, \"Torpedo Bomber\"},\n\t\t{1096, \"NinjaCopter\"},\n\t\t{1097, \"Glaciator\"},\n\t\t{1098, \"Freeze Fighter\"},\n\t\t{1099, \"Travelling Time Train\"},\n\t\t{1100, \"Flight Time Train\"},\n\t\t{1101, \"Missile Blast Time Train\"},\n\t\t{1102, \"Aqua Watercraft\"},\n\t\t{1103, \"Seven Seas Speeder\"},\n\t\t{1104, \"Trident of Fire\"},\n\t\t{1105, \"Drill Driver\"},\n\t\t{1106, \"Bane Dig 'n' Drill\"},\n\t\t{1107, \"Bane Drill 'n' Blast\"},\n\t\t{1108, \"Quinn Mobile\"},\n\t\t{1109, \"Quinn Ultra Racer\"},\n\t\t{1110, \"Missile Launcher\"},\n\t\t{1111, \"The Joker's Chopper\"},\n\t\t{1112, \"Mischievous Missile Blaster\"},\n\t\t{1113, \"Lock 'n' Laser Jet\"},\n\t\t{1114, \"Hover Pod\"},\n\t\t{1115, \"Krypton Striker\"},\n\t\t{1116, \"Super Stealth Pod\"},\n\t\t{1117, \"Dalek\"},\n\t\t{1118, \"Fire 'n' Ride Dalek\"},\n\t\t{1119, \"Silver Shooter Dalek\"},\n\t\t{1120, \"Ecto-1\"},\n\t\t{1121, \"Ecto-1 Blaster\"},\n\t\t{1122, \"Ecto-1 Water Diver\"},\n\t\t{1123, \"Ghost Trap\"},\n\t\t{1124, \"Ghost Stun 'n' Trap\"},\n\t\t{1125, \"Proton Zapper\"},\n\t\t{1126, \"Unknown\"},\n\t\t{1127, \"Unknown\"},\n\t\t{1128, \"Unknown\"},\n\t\t{1129, \"Unknown\"},\n\t\t{1130, \"Unknown\"},\n\t\t{1131, \"Unknown\"},\n\t\t{1132, \"Lloyd's Golden Dragon\"},\n\t\t{1133, \"Sword Projector Dragon\"},\n\t\t{1134, \"Unknown\"},\n\t\t{1135, \"Unknown\"},\n\t\t{1136, \"Unknown\"},\n\t\t{1137, \"Unknown\"},\n\t\t{1138, \"Unknown\"},\n\t\t{1139, \"Unknown\"},\n\t\t{1140, \"Unknown\"},\n\t\t{1141, \"Unknown\"},\n\t\t{1142, \"Unknown\"},\n\t\t{1143, \"Unknown\"},\n\t\t{1144, \"Mega Flight Dragon\"},\n\t\t{1145, \"Unknown\"},\n\t\t{1146, \"Unknown\"},\n\t\t{1147, \"Unknown\"},\n\t\t{1148, \"Unknown\"},\n\t\t{1149, \"Unknown\"},\n\t\t{1150, \"Unknown\"},\n\t\t{1151, \"Unknown\"},\n\t\t{1152, \"Unknown\"},\n\t\t{1153, \"Unknown\"},\n\t\t{1154, \"Unknown\"},\n\t\t{1155, \"Flying White Dragon\"},\n\t\t{1156, \"Golden Fire Dragon\"},\n\t\t{1157, \"Ultra Destruction Dragon\"},\n\t\t{1158, \"Arcade Machine\"},\n\t\t{1159, \"8-Bit Shooter\"},\n\t\t{1160, \"The Pixelator\"},\n\t\t{1161, \"G-6155 Spy Hunter\"},\n\t\t{1162, \"Interdiver\"},\n\t\t{1163, \"Aerial Spyhunter\"},\n\t\t{1164, \"Slime Shooter\"},\n\t\t{1165, \"Slime Exploder\"},\n\t\t{1166, \"Slime Streamer\"},\n\t\t{1167, \"Terror Dog\"},\n\t\t{1168, \"Terror Dog Destroyer\"},\n\t\t{1169, \"Soaring Terror Dog\"},\n\t\t{1170, \"Ancient Psychic Tandem War Elephant\"},\n\t\t{1171, \"Cosmic Squid\"},\n\t\t{1172, \"Psychic Submarine\"},\n\t\t{1173, \"BMO\"},\n\t\t{1174, \"DOGMO\"},\n\t\t{1175, \"SNAKEMO\"},\n\t\t{1176, \"Jakemobile\"},\n\t\t{1177, \"Snail Dude Jake\"},\n\t\t{1178, \"Hover Jake\"},\n\t\t{1179, \"Lumpy Car\"},\n\t\t{1181, \"Lumpy Land Whale\"},\n\t\t{1180, \"Lumpy Truck\"},\n\t\t{1182, \"Lunatic Amp\"},\n\t\t{1183, \"Shadow Scorpion\"},\n\t\t{1184, \"Heavy Metal Monster\"},\n\t\t{1185, \"B.A.'s Van\"},\n\t\t{1186, \"Fool Smasher\"},\n\t\t{1187, \"Pain Plane\"},\n\t\t{1188, \"Phone Home\"},\n\t\t{1189, \"Mobile Uplink\"},\n\t\t{1190, \"Super-Charged Satellite\"},\n\t\t{1191, \"Niffler\"},\n\t\t{1192, \"Sinister Scorpion\"},\n\t\t{1193, \"Vicious Vulture\"},\n\t\t{1194, \"Swooping Evil\"},\n\t\t{1195, \"Brutal Bloom\"},\n\t\t{1196, \"Crawling Creeper\"},\n\t\t{1197, \"Ecto-1 (2016)\"},\n\t\t{1198, \"Ectozer\"},\n\t\t{1199, \"PerfEcto\"},\n\t\t{1200, \"Flash 'n' Finish\"},\n\t\t{1201, \"Rampage Record Player\"},\n\t\t{1202, \"Stripe's Throne\"},\n\t\t{1203, \"R.C. Racer\"},\n\t\t{1204, \"Gadget-O-Matic\"},\n\t\t{1205, \"Scarlet Scorpion\"},\n\t\t{1206, \"Hogwarts Express\"},\n\t\t{1208, \"Steam Warrior\"},\n\t\t{1207, \"Soaring Steam Plane\"},\n\t\t{1209, \"Enchanted Car\"},\n\t\t{1210, \"Shark Sub\"},\n\t\t{1211, \"Monstrous Mouth\"},\n\t\t{1212, \"IMF Scrambler\"},\n\t\t{1213, \"Shock Cycle\"},\n\t\t{1214, \"IMF Covert Jet\"},\n\t\t{1215, \"IMF Sports Car\"},\n\t\t{1216, \"IMF Tank\"},\n\t\t{1217, \"IMF Splorer\"},\n\t\t{1218, \"Sonic Speedster\"},\n\t\t{1219, \"Blue Typhoon\"},\n\t\t{1220, \"Moto Bug\"},\n\t\t{1221, \"The Tornado\"},\n\t\t{1222, \"Crabmeat\"},\n\t\t{1223, \"Eggcatcher\"},\n\t\t{1224, \"K.I.T.T.\"},\n\t\t{1225, \"Goliath Armored Semi\"},\n\t\t{1226, \"K.I.T.T. Jet\"},\n\t\t{1227, \"Police Helicopter\"},\n\t\t{1228, \"Police Hovercraft\"},\n\t\t{1229, \"Police Plane\"},\n\t\t{1230, \"Bionic Steed\"},\n\t\t{1231, \"Bat-Raptor\"},\n\t\t{1232, \"Ultrabat\"},\n\t\t{1233, \"Batwing\"},\n\t\t{1234, \"The Black Thunder\"},\n\t\t{1235, \"Bat-Tank\"},\n\t\t{1236, \"Skeleton Organ\"},\n\t\t{1237, \"Skeleton Jukebox\"},\n\t\t{1238, \"Skele-Turkey\"},\n\t\t{1239, \"One-Eyed Willy's Pirate Ship\"},\n\t\t{1240, \"Fanged Fortune\"},\n\t\t{1241, \"Inferno Cannon\"},\n\t\t{1242, \"Buckbeak\"},\n\t\t{1243, \"Giant Owl\"},\n\t\t{1244, \"Fierce Falcon\"},\n\t\t{1245, \"Saturn's Sandworm\"},\n\t\t{1247, \"Haunted Vacuum\"},\n\t\t{1246, \"Spooky Spider\"},\n\t\t{1248, \"PPG Smartphone\"},\n\t\t{1249, \"PPG Hotline\"},\n\t\t{1250, \"Powerpuff Mag-Net\"},\n\t\t{1253, \"Mega Blast Bot\"},\n\t\t{1251, \"Ka-Pow Cannon\"},\n\t\t{1252, \"Slammin' Guitar\"},\n\t\t{1254, \"Octi\"},\n\t\t{1255, \"Super Skunk\"},\n\t\t{1256, \"Sonic Squid\"},\n\t\t{1257, \"T-Car\"},\n\t\t{1258, \"T-Forklift\"},\n\t\t{1259, \"T-Plane\"},\n\t\t{1260, \"Spellbook of Azarath\"},\n\t\t{1261, \"Raven Wings\"},\n\t\t{1262, \"Giant Hand\"},\n\t\t{1263, \"Titan Robot\"},\n\t\t{1264, \"T-Rocket\"},\n\t\t{1265, \"Robot Retriever\"}};\n\n\tDimensionsToypadDevice::DimensionsToypadDevice()\n\t\t: Device(0x0E6F, 0x0241, 1, 2, 0)\n\t{\n\t\tm_IsOpened = false;\n\t}\n\n\tbool DimensionsToypadDevice::Open()\n\t{\n\t\tif (!IsOpened())\n\t\t{\n\t\t\tm_IsOpened = true;\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid DimensionsToypadDevice::Close()\n\t{\n\t\tif (IsOpened())\n\t\t{\n\t\t\tm_IsOpened = false;\n\t\t}\n\t}\n\n\tbool DimensionsToypadDevice::IsOpened()\n\t{\n\t\treturn m_IsOpened;\n\t}\n\n\tDevice::ReadResult DimensionsToypadDevice::Read(ReadMessage* message)\n\t{\n\t\tmemcpy(message->data, g_dimensionstoypad.GetStatus().data(), message->length);\n\t\tmessage->bytesRead = message->length;\n\t\treturn Device::ReadResult::Success;\n\t}\n\n\tDevice::WriteResult DimensionsToypadDevice::Write(WriteMessage* message)\n\t{\n\t\tif (message->length != 32)\n\t\t\treturn Device::WriteResult::Error;\n\n\t\tg_dimensionstoypad.SendCommand(std::span<const uint8, 32>{message->data, 32});\n\t\tmessage->bytesWritten = message->length;\n\t\treturn Device::WriteResult::Success;\n\t}\n\n\tbool DimensionsToypadDevice::GetDescriptor(uint8 descType,\n\t\t\t\t\t\t\t\t\t\t\t   uint8 descIndex,\n\t\t\t\t\t\t\t\t\t\t\t   uint16 lang,\n\t\t\t\t\t\t\t\t\t\t\t   uint8* output,\n\t\t\t\t\t\t\t\t\t\t\t   uint32 outputMaxLength)\n\t{\n\t\tuint8 configurationDescriptor[0x29];\n\n\t\tuint8* currentWritePtr;\n\n\t\t// configuration descriptor\n\t\tcurrentWritePtr = configurationDescriptor + 0;\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 2;\t\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 2) = 0x0029; // wTotalLength\n\t\t*(uint8*)(currentWritePtr + 4) = 1;\t\t\t// bNumInterfaces\n\t\t*(uint8*)(currentWritePtr + 5) = 1;\t\t\t// bConfigurationValue\n\t\t*(uint8*)(currentWritePtr + 6) = 0;\t\t\t// iConfiguration\n\t\t*(uint8*)(currentWritePtr + 7) = 0x80;\t\t// bmAttributes\n\t\t*(uint8*)(currentWritePtr + 8) = 0xFA;\t\t// MaxPower\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// configuration descriptor\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t   // bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x04; // bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 2) = 0;\t   // bInterfaceNumber\n\t\t*(uint8*)(currentWritePtr + 3) = 0;\t   // bAlternateSetting\n\t\t*(uint8*)(currentWritePtr + 4) = 2;\t   // bNumEndpoints\n\t\t*(uint8*)(currentWritePtr + 5) = 3;\t   // bInterfaceClass\n\t\t*(uint8*)(currentWritePtr + 6) = 0;\t   // bInterfaceSubClass\n\t\t*(uint8*)(currentWritePtr + 7) = 0;\t   // bInterfaceProtocol\n\t\t*(uint8*)(currentWritePtr + 8) = 0;\t   // iInterface\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// configuration descriptor\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x21;\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 2) = 0x0111; // bcdHID\n\t\t*(uint8*)(currentWritePtr + 4) = 0x00;\t\t// bCountryCode\n\t\t*(uint8*)(currentWritePtr + 5) = 0x01;\t\t// bNumDescriptors\n\t\t*(uint8*)(currentWritePtr + 6) = 0x22;\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 7) = 0x001D; // wDescriptorLength\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// endpoint descriptor 1\n\t\t*(uint8*)(currentWritePtr + 0) = 7;\t\t  // bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x05;\t  // bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 2) = 0x81;\t  // bEndpointAddress\n\t\t*(uint8*)(currentWritePtr + 3) = 0x03;\t  // bmAttributes\n\t\t*(uint16be*)(currentWritePtr + 4) = 0x40; // wMaxPacketSize\n\t\t*(uint8*)(currentWritePtr + 6) = 0x01;\t  // bInterval\n\t\tcurrentWritePtr = currentWritePtr + 7;\n\t\t// endpoint descriptor 2\n\t\t*(uint8*)(currentWritePtr + 0) = 7;\t\t  // bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x05;\t  // bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 1) = 0x02;\t  // bEndpointAddress\n\t\t*(uint8*)(currentWritePtr + 2) = 0x03;\t  // bmAttributes\n\t\t*(uint16be*)(currentWritePtr + 3) = 0x40; // wMaxPacketSize\n\t\t*(uint8*)(currentWritePtr + 5) = 0x01;\t  // bInterval\n\t\tcurrentWritePtr = currentWritePtr + 7;\n\n\t\tcemu_assert_debug((currentWritePtr - configurationDescriptor) == 0x29);\n\n\t\tmemcpy(output, configurationDescriptor,\n\t\t\t   std::min<uint32>(outputMaxLength, sizeof(configurationDescriptor)));\n\t\treturn true;\n\t}\n\n\tbool DimensionsToypadDevice::SetIdle(uint8 ifIndex,\n\t\t\t\t\t\t\t\t\t\t uint8 reportId,\n\t\t\t\t\t\t\t\t\t\t uint8 duration)\n\t{\n\t\treturn true;\n\t}\n\n\tbool DimensionsToypadDevice::SetProtocol(uint8 ifIndex, uint8 protocol)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Toypad Protocol\");\n\t\treturn true;\n\t}\n\n\tbool DimensionsToypadDevice::SetReport(ReportMessage* message)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Toypad Report\");\n\t\treturn true;\n\t}\n\n\tstd::array<uint8, 32> DimensionsUSB::GetStatus()\n\t{\n\t\tstd::array<uint8, 32> response = {};\n\n\t\tbool responded = false;\n\t\tdo\n\t\t{\n\t\t\tif (!m_queries.empty())\n\t\t\t{\n\t\t\t\tresponse = m_queries.front();\n\t\t\t\tm_queries.pop();\n\t\t\t\tresponded = true;\n\t\t\t}\n\t\t\telse if (!m_figureAddedRemovedResponses.empty() && m_isAwake)\n\t\t\t{\n\t\t\t\tstd::lock_guard lock(m_dimensionsMutex);\n\t\t\t\tresponse = m_figureAddedRemovedResponses.front();\n\t\t\t\tm_figureAddedRemovedResponses.pop();\n\t\t\t\tresponded = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t\t\t}\n\t\t}\n\t\twhile (responded == false);\n\t\treturn response;\n\t}\n\n\tvoid DimensionsUSB::SendCommand(std::span<const uint8, 32> buf)\n\t{\n\t\tconst uint8 command = buf[2];\n\t\tconst uint8 sequence = buf[3];\n\n\t\tstd::array<uint8, 32> q_result{};\n\n\t\tswitch (command)\n\t\t{\n\t\tcase 0xB0: // Wake\n\t\t{\n\t\t\t// Consistent device response to the wake command\n\t\t\tq_result = {0x55, 0x0e, 0x01, 0x28, 0x63, 0x29,\n\t\t\t\t\t\t0x20, 0x4c, 0x45, 0x47, 0x4f, 0x20,\n\t\t\t\t\t\t0x32, 0x30, 0x31, 0x34, 0x46};\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xB1: // Seed\n\t\t{\n\t\t\t// Initialise a random number generator using the seed provided\n\t\t\tg_dimensionstoypad.GenerateRandomNumber(std::span<const uint8, 8>{buf.begin() + 4, 8}, sequence, q_result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xB3: // Challenge\n\t\t{\n\t\t\t// Get the next number in the sequence based on the RNG from 0xB1 command\n\t\t\tg_dimensionstoypad.GetChallengeResponse(std::span<const uint8, 8>{buf.begin() + 4, 8}, sequence, q_result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xC0: // Color\n\t\tcase 0xC1: // Get Pad Color\n\t\tcase 0xC2: // Fade\n\t\tcase 0xC3: // Flash\n\t\tcase 0xC4: // Fade Random\n\t\tcase 0xC6: // Fade All\n\t\tcase 0xC7: // Flash All\n\t\tcase 0xC8: // Color All\n\t\t{\n\t\t\t// Send a blank response to acknowledge color has been sent to toypad\n\t\t\tq_result = {0x55, 0x01, sequence};\n\t\t\tq_result[3] = GenerateChecksum(q_result, 3);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xD2: // Read\n\t\t{\n\t\t\t// Read 4 pages from the figure at index (buf[4]), starting with page buf[5]\n\t\t\tg_dimensionstoypad.QueryBlock(buf[4], buf[5], q_result, sequence);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xD3: // Write\n\t\t{\n\t\t\t// Write 4 bytes to page buf[5] to the figure at index buf[4]\n\t\t\tg_dimensionstoypad.WriteBlock(buf[4], buf[5], std::span<const uint8, 4>{buf.begin() + 6, 4}, q_result, sequence);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xD4: // Model\n\t\t{\n\t\t\t// Get the model id of the figure at index buf[4]\n\t\t\tg_dimensionstoypad.GetModel(std::span<const uint8, 8>{buf.begin() + 4, 8}, sequence, q_result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xD0: // Tag List\n\t\tcase 0xE1: // PWD\n\t\tcase 0xE5: // Active\n\t\tcase 0xFF: // LEDS Query\n\t\t{\n\t\t\t// Further investigation required\n\t\t\tcemuLog_log(LogType::Force, \"Unimplemented LD Function: {:x}\", command);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Unknown LD Function: {:x}\", command);\n\t\t\tbreak;\n\t\t}\n\t\t}\n\n\t\tm_queries.push(q_result);\n\t}\n\n\tuint32 DimensionsUSB::LoadFigure(const std::array<uint8, 0x2D * 0x04>& buf, std::unique_ptr<FileStream> file, uint8 pad, uint8 index)\n\t{\n\t\tstd::lock_guard lock(m_dimensionsMutex);\n\n\t\tconst uint32 id = GetFigureId(buf);\n\n\t\tDimensionsMini& figure = GetFigureByIndex(index);\n\t\tfigure.dimFile = std::move(file);\n\t\tfigure.id = id;\n\t\tfigure.pad = pad;\n\t\tfigure.index = index + 1;\n\t\tfigure.data = buf;\n\t\t// When a figure is added to the toypad, respond to the game with the pad they were added to, their index,\n\t\t// the direction (0x00 in byte 6 for added) and their UID\n\t\tstd::array<uint8, 32> figureChangeResponse = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x00, buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]};\n\t\tfigureChangeResponse[13] = GenerateChecksum(figureChangeResponse, 13);\n\t\tm_figureAddedRemovedResponses.push(figureChangeResponse);\n\n\t\treturn id;\n\t}\n\n\tbool DimensionsUSB::RemoveFigure(uint8 pad, uint8 index, bool fullRemove)\n\t{\n\t\tstd::lock_guard lock(m_dimensionsMutex);\n\n\t\tDimensionsMini& figure = GetFigureByIndex(index);\n\t\tif (figure.index == 255)\n\t\t\treturn false;\n\n\t\t// When a figure is removed from the toypad, respond to the game with the pad they were removed from, their index,\n\t\t// the direction (0x01 in byte 6 for removed) and their UID\n\t\tif (fullRemove)\n\t\t{\n\t\t\tstd::array<uint8, 32> figureChangeResponse = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x01,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  figure.data[0], figure.data[1], figure.data[2],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  figure.data[4], figure.data[5], figure.data[6], figure.data[7]};\n\t\t\tfigureChangeResponse[13] = GenerateChecksum(figureChangeResponse, 13);\n\t\t\tm_figureAddedRemovedResponses.push(figureChangeResponse);\n\t\t\tfigure.Save();\n\t\t\tfigure.dimFile.reset();\n\t\t}\n\n\t\tfigure.index = 255;\n\t\tfigure.pad = 255;\n\t\tfigure.id = 0;\n\n\t\treturn true;\n\t}\n\n\tbool DimensionsUSB::TempRemove(uint8 index)\n\t{\n\t\tstd::lock_guard lock(m_dimensionsMutex);\n\n\t\tDimensionsMini& figure = GetFigureByIndex(index);\n\t\tif (figure.index == 255)\n\t\t\treturn false;\n\n\t\t// Send a response to the game that the figure has been \"Picked up\" from existing slot,\n\t\t// until either the movement is cancelled, or user chooses a space to move to\n\t\tstd::array<uint8, 32> figureChangeResponse = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x01,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  figure.data[0], figure.data[1], figure.data[2],\n\t\t\t\t\t\t\t\t\t\t\t\t\t  figure.data[4], figure.data[5], figure.data[6], figure.data[7]};\n\n\t\tfigureChangeResponse[13] = GenerateChecksum(figureChangeResponse, 13);\n\t\tm_figureAddedRemovedResponses.push(figureChangeResponse);\n\t\treturn true;\n\t}\n\n\tbool DimensionsUSB::CancelRemove(uint8 index)\n\t{\n\t\tstd::lock_guard lock(m_dimensionsMutex);\n\n\t\tDimensionsMini& figure = GetFigureByIndex(index);\n\t\tif (figure.index == 255)\n\t\t\treturn false;\n\n\t\t// Cancel the previous movement of the figure\n\t\tstd::array<uint8, 32> figureChangeResponse = {0x56, 0x0b, figure.pad, 0x00, figure.index, 0x00,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  figure.data[0], figure.data[1], figure.data[2],\n\t\t\t\t\t\t\t\t\t\t\t\t\t  figure.data[4], figure.data[5], figure.data[6], figure.data[7]};\n\n\t\tfigureChangeResponse[13] = GenerateChecksum(figureChangeResponse, 13);\n\t\tm_figureAddedRemovedResponses.push(figureChangeResponse);\n\n\t\treturn true;\n\t}\n\n\tbool DimensionsUSB::CreateFigure(fs::path pathName, uint32 id)\n\t{\n\t\tFileStream* dimFile(FileStream::createFile2(pathName));\n\t\tif (!dimFile)\n\t\t\treturn false;\n\n\t\tstd::array<uint8, 0x2D * 0x04> fileData{};\n\t\tRandomUID(fileData);\n\t\tfileData[3] = id & 0xFF;\n\n\t\tstd::array<uint8, 7> uid = {fileData[0], fileData[1], fileData[2], fileData[4], fileData[5], fileData[6], fileData[7]};\n\n\t\t// Only characters are created with their ID encrypted and stored in pages 36 and 37,\n\t\t// as well as a password stored in page 43. Blank tags have their information populated\n\t\t// by the game when it calls the write_block command.\n\t\tif (id != 0)\n\t\t{\n\t\t\tconst std::array<uint8, 16> figureKey = GenerateFigureKey(fileData);\n\n\t\t\tstd::array<uint8, 8> valueToEncrypt = {uint8(id & 0xFF), uint8((id >> 8) & 0xFF), uint8((id >> 16) & 0xFF), uint8((id >> 24) & 0xFF),\n\t\t\t\t\t\t\t\t\t\t\t\t   uint8(id & 0xFF), uint8((id >> 8) & 0xFF), uint8((id >> 16) & 0xFF), uint8((id >> 24) & 0xFF)};\n\n\t\t\tstd::array<uint8, 8> encrypted = Encrypt(valueToEncrypt, figureKey);\n\n\t\t\tstd::memcpy(&fileData[36 * 4], &encrypted[0], 4);\n\t\t\tstd::memcpy(&fileData[37 * 4], &encrypted[4], 4);\n\n\t\t\tstd::memcpy(&fileData[43 * 4], PWDGenerate(fileData).data(), 4);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Page 38 is used as verification for blank tags\n\t\t\tfileData[(38 * 4) + 1] = 1;\n\t\t}\n\n\t\tif (fileData.size() != dimFile->writeData(fileData.data(), fileData.size()))\n\t\t{\n\t\t\tdelete dimFile;\n\t\t\treturn false;\n\t\t}\n\t\tdelete dimFile;\n\t\treturn true;\n\t}\n\n\tbool DimensionsUSB::MoveFigure(uint8 pad, uint8 index, uint8 oldPad, uint8 oldIndex)\n\t{\n\t\tif (oldIndex == index)\n\t\t{\n\t\t\t// Don't bother removing and loading again, just send response to the game\n\t\t\tCancelRemove(index);\n\t\t\treturn true;\n\t\t}\n\n\t\t// When moving figures between spaces on the toypad, remove any figure from the space they are moving to,\n\t\t// then remove them from their current space, then load them to the space they are moving to\n\t\tRemoveFigure(pad, index, true);\n\n\t\tDimensionsMini& figure = GetFigureByIndex(oldIndex);\n\t\tconst std::array<uint8, 0x2D * 0x04> data = figure.data;\n\t\tstd::unique_ptr<FileStream> inFile = std::move(figure.dimFile);\n\n\t\tRemoveFigure(oldPad, oldIndex, false);\n\n\t\tLoadFigure(data, std::move(inFile), pad, index);\n\n\t\treturn true;\n\t}\n\n\tvoid DimensionsUSB::GenerateRandomNumber(std::span<const uint8, 8> buf, uint8 sequence,\n\t\t\t\t\t\t\t\t\t\t\t std::array<uint8, 32>& replyBuf)\n\t{\n\t\t// Decrypt payload into an 8 byte array\n\t\tstd::array<uint8, 8> value = Decrypt(buf, std::nullopt);\n\t\t// Seed is the first 4 bytes (little endian) of the decrypted payload\n\t\tuint32 seed = (uint32&)value[0];\n\t\t// Confirmation is the second 4 bytes (big endian) of the decrypted payload\n\t\tuint32 conf = (uint32be&)value[4];\n\t\t// Initialize rng using the seed from decrypted payload\n\t\tInitializeRNG(seed);\n\t\t// Encrypt 8 bytes, first 4 bytes is the decrypted confirmation from payload, 2nd 4 bytes are blank\n\t\tstd::array<uint8, 8> valueToEncrypt = {value[4], value[5], value[6], value[7], 0, 0, 0, 0};\n\t\tstd::array<uint8, 8> encrypted = Encrypt(valueToEncrypt, std::nullopt);\n\t\treplyBuf[0] = 0x55;\n\t\treplyBuf[1] = 0x09;\n\t\treplyBuf[2] = sequence;\n\t\t// Copy encrypted value to response data\n\t\tmemcpy(&replyBuf[3], encrypted.data(), encrypted.size());\n\t\treplyBuf[11] = GenerateChecksum(replyBuf, 11);\n\t}\n\n\tvoid DimensionsUSB::GetChallengeResponse(std::span<const uint8, 8> buf, uint8 sequence,\n\t\t\t\t\t\t\t\t\t\t\t std::array<uint8, 32>& replyBuf)\n\t{\n\t\t// Decrypt payload into an 8 byte array\n\t\tstd::array<uint8, 8> value = Decrypt(buf, std::nullopt);\n\t\t// Confirmation is the first 4 bytes of the decrypted payload\n\t\tuint32 conf = (uint32be&)value[0];\n\t\t// Generate next random number based on RNG\n\t\tuint32 nextRandom = GetNext();\n\t\t// Encrypt an 8 byte array, first 4 bytes are the next random number (little endian)\n\t\t// followed by the confirmation from the decrypted payload\n\t\tstd::array<uint8, 8> valueToEncrypt = {uint8(nextRandom & 0xFF), uint8((nextRandom >> 8) & 0xFF),\n\t\t\t\t\t\t\t\t\t\t\t   uint8((nextRandom >> 16) & 0xFF), uint8((nextRandom >> 24) & 0xFF),\n\t\t\t\t\t\t\t\t\t\t\t   value[0], value[1], value[2], value[3]};\n\t\tstd::array<uint8, 8> encrypted = Encrypt(valueToEncrypt, std::nullopt);\n\t\treplyBuf[0] = 0x55;\n\t\treplyBuf[1] = 0x09;\n\t\treplyBuf[2] = sequence;\n\t\t// Copy encrypted value to response data\n\t\tmemcpy(&replyBuf[3], encrypted.data(), encrypted.size());\n\t\treplyBuf[11] = GenerateChecksum(replyBuf, 11);\n\n\t\tif (!m_isAwake)\n\t\t\tm_isAwake = true;\n\t}\n\n\tvoid DimensionsUSB::InitializeRNG(uint32 seed)\n\t{\n\t\tm_randomA = 0xF1EA5EED;\n\t\tm_randomB = seed;\n\t\tm_randomC = seed;\n\t\tm_randomD = seed;\n\n\t\tfor (int i = 0; i < 42; i++)\n\t\t{\n\t\t\tGetNext();\n\t\t}\n\t}\n\n\tuint32 DimensionsUSB::GetNext()\n\t{\n\t\tuint32 e = m_randomA - std::rotl(m_randomB, 21);\n\t\tm_randomA = m_randomB ^ std::rotl(m_randomC, 19);\n\t\tm_randomB = m_randomC + std::rotl(m_randomD, 6);\n\t\tm_randomC = m_randomD + e;\n\t\tm_randomD = e + m_randomA;\n\t\treturn m_randomD;\n\t}\n\n\tstd::array<uint8, 8> DimensionsUSB::Decrypt(std::span<const uint8, 8> buf, std::optional<std::array<uint8, 16>> key)\n\t{\n\t\t// Value to decrypt is separated in to two little endian 32 bit unsigned integers\n\t\tuint32 dataOne = (uint32&)buf[0];\n\t\tuint32 dataTwo = (uint32&)buf[4];\n\n\t\t// Use the key as 4 32 bit little endian unsigned integers\n\t\tuint32 keyOne;\n\t\tuint32 keyTwo;\n\t\tuint32 keyThree;\n\t\tuint32 keyFour;\n\n\t\tif (key)\n\t\t{\n\t\t\tkeyOne = (uint32&)key.value()[0];\n\t\t\tkeyTwo = (uint32&)key.value()[4];\n\t\t\tkeyThree = (uint32&)key.value()[8];\n\t\t\tkeyFour = (uint32&)key.value()[12];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tkeyOne = (uint32&)COMMAND_KEY[0];\n\t\t\tkeyTwo = (uint32&)COMMAND_KEY[4];\n\t\t\tkeyThree = (uint32&)COMMAND_KEY[8];\n\t\t\tkeyFour = (uint32&)COMMAND_KEY[12];\n\t\t}\n\n\t\tuint32 sum = 0xC6EF3720;\n\t\tuint32 delta = 0x9E3779B9;\n\n\t\tfor (int i = 0; i < 32; i++)\n\t\t{\n\t\t\tdataTwo -= (((dataOne << 4) + keyThree) ^ (dataOne + sum) ^ ((dataOne >> 5) + keyFour));\n\t\t\tdataOne -= (((dataTwo << 4) + keyOne) ^ (dataTwo + sum) ^ ((dataTwo >> 5) + keyTwo));\n\t\t\tsum -= delta;\n\t\t}\n\n\t\tcemu_assert(sum == 0);\n\n\t\tstd::array<uint8, 8> decrypted = {uint8(dataOne & 0xFF), uint8((dataOne >> 8) & 0xFF),\n\t\t\t\t\t\t\t\t\t\t  uint8((dataOne >> 16) & 0xFF), uint8((dataOne >> 24) & 0xFF),\n\t\t\t\t\t\t\t\t\t\t  uint8(dataTwo & 0xFF), uint8((dataTwo >> 8) & 0xFF),\n\t\t\t\t\t\t\t\t\t\t  uint8((dataTwo >> 16) & 0xFF), uint8((dataTwo >> 24) & 0xFF)};\n\t\treturn decrypted;\n\t}\n\tstd::array<uint8, 8> DimensionsUSB::Encrypt(std::span<const uint8, 8> buf, std::optional<std::array<uint8, 16>> key)\n\t{\n\t\t// Value to encrypt is separated in to two little endian 32 bit unsigned integers\n\t\tuint32 dataOne = (uint32&)buf[0];\n\t\tuint32 dataTwo = (uint32&)buf[4];\n\n\t\t// Use the key as 4 32 bit little endian unsigned integers\n\t\tuint32 keyOne;\n\t\tuint32 keyTwo;\n\t\tuint32 keyThree;\n\t\tuint32 keyFour;\n\n\t\tif (key)\n\t\t{\n\t\t\tkeyOne = (uint32&)key.value()[0];\n\t\t\tkeyTwo = (uint32&)key.value()[4];\n\t\t\tkeyThree = (uint32&)key.value()[8];\n\t\t\tkeyFour = (uint32&)key.value()[12];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tkeyOne = (uint32&)COMMAND_KEY[0];\n\t\t\tkeyTwo = (uint32&)COMMAND_KEY[4];\n\t\t\tkeyThree = (uint32&)COMMAND_KEY[8];\n\t\t\tkeyFour = (uint32&)COMMAND_KEY[12];\n\t\t}\n\n\t\tuint32 sum = 0;\n\t\tuint32 delta = 0x9E3779B9;\n\n\t\tfor (int i = 0; i < 32; i++)\n\t\t{\n\t\t\tsum += delta;\n\t\t\tdataOne += (((dataTwo << 4) + keyOne) ^ (dataTwo + sum) ^ ((dataTwo >> 5) + keyTwo));\n\t\t\tdataTwo += (((dataOne << 4) + keyThree) ^ (dataOne + sum) ^ ((dataOne >> 5) + keyFour));\n\t\t}\n\n\t\tcemu_assert(sum == 0xC6EF3720);\n\n\t\tstd::array<uint8, 8> encrypted = {uint8(dataOne & 0xFF), uint8((dataOne >> 8) & 0xFF),\n\t\t\t\t\t\t\t\t\t\t  uint8((dataOne >> 16) & 0xFF), uint8((dataOne >> 24) & 0xFF),\n\t\t\t\t\t\t\t\t\t\t  uint8(dataTwo & 0xFF), uint8((dataTwo >> 8) & 0xFF),\n\t\t\t\t\t\t\t\t\t\t  uint8((dataTwo >> 16) & 0xFF), uint8((dataTwo >> 24) & 0xFF)};\n\t\treturn encrypted;\n\t}\n\n\tstd::array<uint8, 16> DimensionsUSB::GenerateFigureKey(const std::array<uint8, 0x2D * 0x04>& buf)\n\t{\n\t\tstd::array<uint8, 7> uid = {buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]};\n\n\t\tuint32 scrambleA = Scramble(uid, 3);\n\t\tuint32 scrambleB = Scramble(uid, 4);\n\t\tuint32 scrambleC = Scramble(uid, 5);\n\t\tuint32 scrambleD = Scramble(uid, 6);\n\n\t\treturn {uint8((scrambleA >> 24) & 0xFF), uint8((scrambleA >> 16) & 0xFF),\n\t\t\t\tuint8((scrambleA >> 8) & 0xFF), uint8(scrambleA & 0xFF),\n\t\t\t\tuint8((scrambleB >> 24) & 0xFF), uint8((scrambleB >> 16) & 0xFF),\n\t\t\t\tuint8((scrambleB >> 8) & 0xFF), uint8(scrambleB & 0xFF),\n\t\t\t\tuint8((scrambleC >> 24) & 0xFF), uint8((scrambleC >> 16) & 0xFF),\n\t\t\t\tuint8((scrambleC >> 8) & 0xFF), uint8(scrambleC & 0xFF),\n\t\t\t\tuint8((scrambleD >> 24) & 0xFF), uint8((scrambleD >> 16) & 0xFF),\n\t\t\t\tuint8((scrambleD >> 8) & 0xFF), uint8(scrambleD & 0xFF)};\n\t}\n\n\tuint32 DimensionsUSB::Scramble(const std::array<uint8, 7>& uid, uint8 count)\n\t{\n\t\tstd::vector<uint8> toScramble;\n\t\ttoScramble.reserve(uid.size() + CHAR_CONSTANT.size());\n\t\tfor (uint8 x : uid)\n\t\t{\n\t\t\ttoScramble.push_back(x);\n\t\t}\n\t\tfor (uint8 c : CHAR_CONSTANT)\n\t\t{\n\t\t\ttoScramble.push_back(c);\n\t\t}\n\t\ttoScramble[(count * 4) - 1] = 0xaa;\n\n\t\tstd::array<uint8, 4> randomized = DimensionsRandomize(toScramble, count);\n\n\t\treturn (uint32be&)randomized[0];\n\t}\n\n\tstd::array<uint8, 4> DimensionsUSB::PWDGenerate(const std::array<uint8, 0x2D * 0x04>& buf)\n\t{\n\t\tstd::array<uint8, 7> uid = {buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]};\n\n\t\tstd::vector<uint8> pwdCalc = {PWD_CONSTANT.begin(), PWD_CONSTANT.end() - 1};\n\t\tfor (uint8 i = 0; i < uid.size(); i++)\n\t\t{\n\t\t\tpwdCalc.insert(pwdCalc.begin() + i, uid[i]);\n\t\t}\n\n\t\treturn DimensionsRandomize(pwdCalc, 8);\n\t}\n\n\tstd::array<uint8, 4> DimensionsUSB::DimensionsRandomize(const std::vector<uint8> key, uint8 count)\n\t{\n\t\tuint32 scrambled = 0;\n\t\tfor (uint8 i = 0; i < count; i++)\n\t\t{\n\t\t\tconst uint32 v4 = std::rotr(scrambled, 25);\n\t\t\tconst uint32 v5 = std::rotr(scrambled, 10);\n\t\t\tconst uint32 b = (uint32&)key[i * 4];\n\t\t\tscrambled = b + v4 + v5 - scrambled;\n\t\t}\n\t\treturn {uint8(scrambled & 0xFF), uint8(scrambled >> 8 & 0xFF), uint8(scrambled >> 16 & 0xFF), uint8(scrambled >> 24 & 0xFF)};\n\t}\n\n\tuint32 DimensionsUSB::GetFigureId(const std::array<uint8, 0x2D * 0x04>& buf)\n\t{\n\t\tconst std::array<uint8, 16> figureKey = GenerateFigureKey(buf);\n\n\t\tconst std::span<const uint8, 8> modelNumber = std::span<const uint8, 8>{buf.begin() + (36 * 4), 8};\n\n\t\tconst std::array<uint8, 8> decrypted = Decrypt(modelNumber, figureKey);\n\n\t\tconst uint32 figNum = (uint32&)decrypted[0];\n\t\t// Characters have their model number encrypted in page 36\n\t\tif (figNum < 1000)\n\t\t{\n\t\t\treturn figNum;\n\t\t}\n\t\t// Vehicles/Gadgets have their model number written as little endian in page 36\n\t\treturn (uint32&)modelNumber[0];\n\t}\n\n\tDimensionsUSB::DimensionsMini&\n\tDimensionsUSB::GetFigureByIndex(uint8 index)\n\t{\n\t\treturn m_figures[index];\n\t}\n\n\tvoid DimensionsUSB::QueryBlock(uint8 index, uint8 page,\n\t\t\t\t\t\t\t\t   std::array<uint8, 32>& replyBuf,\n\t\t\t\t\t\t\t\t   uint8 sequence)\n\t{\n\t\tstd::lock_guard lock(m_dimensionsMutex);\n\n\t\treplyBuf[0] = 0x55;\n\t\treplyBuf[1] = 0x12;\n\t\treplyBuf[2] = sequence;\n\t\treplyBuf[3] = 0x00;\n\n\t\t// Index from game begins at 1 rather than 0, so minus 1 here\n\t\tif (const uint8 figureIndex = index - 1; figureIndex < 7)\n\t\t{\n\t\t\tconst DimensionsMini& figure = GetFigureByIndex(figureIndex);\n\n\t\t\t// Query 4 pages of 4 bytes from the figure, copy this to the response\n\t\t\tif (figure.index != 255 && (4 * page) < ((0x2D * 4) - 16))\n\t\t\t{\n\t\t\t\tstd::memcpy(&replyBuf[4], figure.data.data() + (4 * page), 16);\n\t\t\t}\n\t\t}\n\t\treplyBuf[20] = GenerateChecksum(replyBuf, 20);\n\t}\n\n\tvoid DimensionsUSB::WriteBlock(uint8 index, uint8 page, std::span<const uint8, 4> toWriteBuf,\n\t\t\t\t\t\t\t\t   std::array<uint8, 32>& replyBuf, uint8 sequence)\n\t{\n\t\tstd::lock_guard lock(m_dimensionsMutex);\n\n\t\treplyBuf[0] = 0x55;\n\t\treplyBuf[1] = 0x02;\n\t\treplyBuf[2] = sequence;\n\t\treplyBuf[3] = 0x00;\n\n\t\t// Index from game begins at 1 rather than 0, so minus 1 here\n\t\tif (const uint8 figureIndex = index - 1; figureIndex < 7)\n\t\t{\n\t\t\tDimensionsMini& figure = GetFigureByIndex(figureIndex);\n\n\t\t\t// Copy 4 bytes to the page on the figure requested by the game\n\t\t\tif (figure.index != 255 && page < 0x2D)\n\t\t\t{\n\t\t\t\t// Id is written to page 36\n\t\t\t\tif (page == 36)\n\t\t\t\t{\n\t\t\t\t\tfigure.id = (uint32&)toWriteBuf[0];\n\t\t\t\t}\n\t\t\t\tstd::memcpy(figure.data.data() + (page * 4), toWriteBuf.data(), 4);\n\t\t\t\tfigure.Save();\n\t\t\t}\n\t\t}\n\t\treplyBuf[4] = GenerateChecksum(replyBuf, 4);\n\t}\n\n\tvoid DimensionsUSB::GetModel(std::span<const uint8, 8> buf, uint8 sequence,\n\t\t\t\t\t\t\t\t std::array<uint8, 32>& replyBuf)\n\t{\n\t\t// Decrypt payload to 8 byte array, byte 1 is the index, 4-7 are the confirmation\n\t\tstd::array<uint8, 8> value = Decrypt(buf, std::nullopt);\n\t\tuint8 index = value[0];\n\t\tuint32 conf = (uint32be&)value[4];\n\t\t// Response is the figure's id (little endian) followed by the confirmation from payload\n\t\t// Index from game begins at 1 rather than 0, so minus 1 here\n\t\tstd::array<uint8, 8> valueToEncrypt = {};\n\t\tif (const uint8 figureIndex = index - 1; figureIndex < 7)\n\t\t{\n\t\t\tconst DimensionsMini& figure = GetFigureByIndex(figureIndex);\n\t\t\tvalueToEncrypt = {uint8(figure.id & 0xFF), uint8((figure.id >> 8) & 0xFF),\n\t\t\t\t\t\t\t  uint8((figure.id >> 16) & 0xFF), uint8((figure.id >> 24) & 0xFF),\n\t\t\t\t\t\t\t  value[4], value[5], value[6], value[7]};\n\t\t}\n\t\tstd::array<uint8, 8> encrypted = Encrypt(valueToEncrypt, std::nullopt);\n\t\treplyBuf[0] = 0x55;\n\t\treplyBuf[1] = 0x0a;\n\t\treplyBuf[2] = sequence;\n\t\treplyBuf[3] = 0x00;\n\t\tmemcpy(&replyBuf[4], encrypted.data(), encrypted.size());\n\t\treplyBuf[12] = GenerateChecksum(replyBuf, 12);\n\t}\n\n\tvoid DimensionsUSB::RandomUID(std::array<uint8, 0x2D * 0x04>& uid_buffer)\n\t{\n\t\tuid_buffer[0] = 0x04;\n\t\tuid_buffer[7] = 0x80;\n\n\t\tstd::random_device rd;\n\t\tstd::mt19937 mt(rd());\n\t\tstd::uniform_int_distribution<int> dist(0, 255);\n\n\t\tuid_buffer[1] = dist(mt);\n\t\tuid_buffer[2] = dist(mt);\n\t\tuid_buffer[4] = dist(mt);\n\t\tuid_buffer[5] = dist(mt);\n\t\tuid_buffer[6] = dist(mt);\n\t}\n\n\tuint8 DimensionsUSB::GenerateChecksum(const std::array<uint8, 32>& data,\n\t\t\t\t\t\t\t\t\t\t  int num_of_bytes) const\n\t{\n\t\tint checksum = 0;\n\t\tfor (int i = 0; i < num_of_bytes; i++)\n\t\t{\n\t\t\tchecksum += data[i];\n\t\t}\n\t\treturn (checksum & 0xFF);\n\t}\n\n\tvoid DimensionsUSB::DimensionsMini::Save()\n\t{\n\t\tif (!dimFile)\n\t\t\treturn;\n\n\t\tdimFile->SetPosition(0);\n\t\tdimFile->writeData(data.data(), data.size());\n\t}\n\n\tstd::map<const uint32, const char*> DimensionsUSB::GetListMinifigs()\n\t{\n\t\treturn s_listMinis;\n\t}\n\n\tstd::map<const uint32, const char*> DimensionsUSB::GetListTokens()\n\t{\n\t\treturn s_listTokens;\n\t}\n\n\tstd::string DimensionsUSB::FindFigure(uint32 figNum)\n\t{\n\t\tfor (const auto& it : GetListMinifigs())\n\t\t{\n\t\t\tif (it.first == figNum)\n\t\t\t{\n\t\t\t\treturn it.second;\n\t\t\t}\n\t\t}\n\t\tfor (const auto& it : GetListTokens())\n\t\t{\n\t\t\tif (it.first == figNum)\n\t\t\t{\n\t\t\t\treturn it.second;\n\t\t\t}\n\t\t}\n\t\treturn fmt::format(\"Unknown ({})\", figNum);\n\t}\n} // namespace nsyshid"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/Dimensions.h",
    "content": "#include <mutex>\n\n#include \"nsyshid.h\"\n#include \"Backend.h\"\n\n#include \"Common/FileStream.h\"\n\nnamespace nsyshid\n{\n\tclass DimensionsToypadDevice final : public Device\n\t{\n\t  public:\n\t\tDimensionsToypadDevice();\n\t\t~DimensionsToypadDevice() = default;\n\n\t\tbool Open() override;\n\n\t\tvoid Close() override;\n\n\t\tbool IsOpened() override;\n\n\t\tReadResult Read(ReadMessage* message) override;\n\n\t\tWriteResult Write(WriteMessage* message) override;\n\n\t\tbool GetDescriptor(uint8 descType,\n\t\t\t\t\t\t   uint8 descIndex,\n\t\t\t\t\t\t   uint16 lang,\n\t\t\t\t\t\t   uint8* output,\n\t\t\t\t\t\t   uint32 outputMaxLength) override;\n\n\t\tbool SetIdle(uint8 ifIndex,\n\t\t\t\t\t uint8 reportId,\n\t\t\t\t\t uint8 duration) override;\n\n\t\tbool SetProtocol(uint8 ifIndex, uint8 protocol) override;\n\n\t\tbool SetReport(ReportMessage* message) override;\n\n\t  private:\n\t\tbool m_IsOpened;\n\t};\n\n\tclass DimensionsUSB\n\t{\n\t  public:\n\t\tstruct DimensionsMini final\n\t\t{\n\t\t\tstd::unique_ptr<FileStream> dimFile;\n\t\t\tstd::array<uint8, 0x2D * 0x04> data{};\n\t\t\tuint8 index = 255;\n\t\t\tuint8 pad = 255;\n\t\t\tuint32 id = 0;\n\t\t\tvoid Save();\n\t\t};\n\n\t\tvoid SendCommand(std::span<const uint8, 32> buf);\n\t\tstd::array<uint8, 32> GetStatus();\n\n\t\tvoid GenerateRandomNumber(std::span<const uint8, 8> buf, uint8 sequence,\n\t\t\t\t\t\t\t\t  std::array<uint8, 32>& replyBuf);\n\t\tvoid InitializeRNG(uint32 seed);\n\t\tvoid GetChallengeResponse(std::span<const uint8, 8> buf, uint8 sequence,\n\t\t\t\t\t\t\t\t  std::array<uint8, 32>& replyBuf);\n\t\tvoid QueryBlock(uint8 index, uint8 page, std::array<uint8, 32>& replyBuf,\n\t\t\t\t\t\tuint8 sequence);\n\t\tvoid WriteBlock(uint8 index, uint8 page, std::span<const uint8, 4> toWriteBuf, std::array<uint8, 32>& replyBuf,\n\t\t\t\t\t\tuint8 sequence);\n\t\tvoid GetModel(std::span<const uint8, 8> buf, uint8 sequence,\n\t\t\t\t\t  std::array<uint8, 32>& replyBuf);\n\n\t\tbool RemoveFigure(uint8 pad, uint8 index, bool fullRemove);\n\t\tbool TempRemove(uint8 index);\n\t\tbool CancelRemove(uint8 index);\n\t\tuint32 LoadFigure(const std::array<uint8, 0x2D * 0x04>& buf, std::unique_ptr<FileStream> file, uint8 pad, uint8 index);\n\t\tbool CreateFigure(fs::path pathName, uint32 id);\n\t\tbool MoveFigure(uint8 pad, uint8 index, uint8 oldPad, uint8 oldIndex);\n\t\tstatic std::map<const uint32, const char*> GetListMinifigs();\n\t\tstatic std::map<const uint32, const char*> GetListTokens();\n\t\tstd::string FindFigure(uint32 figNum);\n\n\t  protected:\n\t\tstd::mutex m_dimensionsMutex;\n\t\tstd::array<DimensionsMini, 7> m_figures{};\n\n\t  private:\n\t\tvoid RandomUID(std::array<uint8, 0x2D * 0x04>& uidBuffer);\n\t\tuint8 GenerateChecksum(const std::array<uint8, 32>& data,\n\t\t\t\t\t\t\t   int numOfBytes) const;\n\t\tstd::array<uint8, 8> Decrypt(std::span<const uint8, 8> buf, std::optional<std::array<uint8, 16>> key);\n\t\tstd::array<uint8, 8> Encrypt(std::span<const uint8, 8> buf, std::optional<std::array<uint8, 16>> key);\n\t\tstd::array<uint8, 16> GenerateFigureKey(const std::array<uint8, 0x2D * 0x04>& uid);\n\t\tstd::array<uint8, 4> PWDGenerate(const std::array<uint8, 0x2D * 0x04>& uid);\n\t\tstd::array<uint8, 4> DimensionsRandomize(const std::vector<uint8> key, uint8 count);\n\t\tuint32 GetFigureId(const std::array<uint8, 0x2D * 0x04>& buf);\n\t\tuint32 Scramble(const std::array<uint8, 7>& uid, uint8 count);\n\t\tuint32 GetNext();\n\t\tDimensionsMini& GetFigureByIndex(uint8 index);\n\n\t\tuint32 m_randomA;\n\t\tuint32 m_randomB;\n\t\tuint32 m_randomC;\n\t\tuint32 m_randomD;\n\n\t\tbool m_isAwake = false;\n\n\t\tstd::queue<std::array<uint8, 32>> m_figureAddedRemovedResponses;\n\t\tstd::queue<std::array<uint8, 32>> m_queries;\n\t};\n\textern DimensionsUSB g_dimensionstoypad;\n\n} // namespace nsyshid"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/Infinity.cpp",
    "content": "#include \"Infinity.h\"\n\n#include <random>\n\n#include \"nsyshid.h\"\n#include \"Backend.h\"\n\n#include \"util/crypto/aes128.h\"\n\n#include <openssl/crypto.h>\n#include \"openssl/sha.h\"\n\nnamespace nsyshid\n{\n\tstatic constexpr std::array<uint8, 32> SHA1_CONSTANT = {\n\t\t0xAF, 0x62, 0xD2, 0xEC, 0x04, 0x91, 0x96, 0x8C, 0xC5, 0x2A, 0x1A, 0x71, 0x65, 0xF8, 0x65, 0xFE,\n\t\t0x28, 0x63, 0x29, 0x20, 0x44, 0x69, 0x73, 0x6e, 0x65, 0x79, 0x20, 0x32, 0x30, 0x31, 0x33};\n\n\tInfinityUSB g_infinitybase;\n\n\tconst std::map<const uint32, const std::pair<const uint8, const char*>> s_listFigures = {\n\t\t{0x0F4241, {1, \"Mr. Incredible\"}},\n\t\t{0x0F4242, {1, \"Sulley\"}},\n\t\t{0x0F4243, {1, \"Jack Sparrow\"}},\n\t\t{0x0F4244, {1, \"Lone Ranger\"}},\n\t\t{0x0F4245, {1, \"Tonto\"}},\n\t\t{0x0F4246, {1, \"Lightning McQueen\"}},\n\t\t{0x0F4247, {1, \"Holley Shiftwell\"}},\n\t\t{0x0F4248, {1, \"Buzz Lightyear\"}},\n\t\t{0x0F4249, {1, \"Jessie\"}},\n\t\t{0x0F424A, {1, \"Mike\"}},\n\t\t{0x0F424B, {1, \"Mrs. Incredible\"}},\n\t\t{0x0F424C, {1, \"Hector Barbossa\"}},\n\t\t{0x0F424D, {1, \"Davy Jones\"}},\n\t\t{0x0F424E, {1, \"Randy\"}},\n\t\t{0x0F424F, {1, \"Syndrome\"}},\n\t\t{0x0F4250, {1, \"Woody\"}},\n\t\t{0x0F4251, {1, \"Mater\"}},\n\t\t{0x0F4252, {1, \"Dash\"}},\n\t\t{0x0F4253, {1, \"Violet\"}},\n\t\t{0x0F4254, {1, \"Francesco Bernoulli\"}},\n\t\t{0x0F4255, {1, \"Sorcerer's Apprentice Mickey\"}},\n\t\t{0x0F4256, {1, \"Jack Skellington\"}},\n\t\t{0x0F4257, {1, \"Rapunzel\"}},\n\t\t{0x0F4258, {1, \"Anna\"}},\n\t\t{0x0F4259, {1, \"Elsa\"}},\n\t\t{0x0F425A, {1, \"Phineas\"}},\n\t\t{0x0F425B, {1, \"Agent P\"}},\n\t\t{0x0F425C, {1, \"Wreck-It Ralph\"}},\n\t\t{0x0F425D, {1, \"Vanellope\"}},\n\t\t{0x0F425E, {1, \"Mr. Incredible (Crystal)\"}},\n\t\t{0x0F425F, {1, \"Jack Sparrow (Crystal)\"}},\n\t\t{0x0F4260, {1, \"Sulley (Crystal)\"}},\n\t\t{0x0F4261, {1, \"Lightning McQueen (Crystal)\"}},\n\t\t{0x0F4262, {1, \"Lone Ranger (Crystal)\"}},\n\t\t{0x0F4263, {1, \"Buzz Lightyear (Crystal)\"}},\n\t\t{0x0F4264, {1, \"Agent P (Crystal)\"}},\n\t\t{0x0F4265, {1, \"Sorcerer's Apprentice Mickey (Crystal)\"}},\n\t\t{0x0F4266, {1, \"Buzz Lightyear (Glowing)\"}},\n\t\t{0x0F42A4, {2, \"Captain America\"}},\n\t\t{0x0F42A5, {2, \"Hulk\"}},\n\t\t{0x0F42A6, {2, \"Iron Man\"}},\n\t\t{0x0F42A7, {2, \"Thor\"}},\n\t\t{0x0F42A8, {2, \"Groot\"}},\n\t\t{0x0F42A9, {2, \"Rocket Raccoon\"}},\n\t\t{0x0F42AA, {2, \"Star-Lord\"}},\n\t\t{0x0F42AB, {2, \"Spider-Man\"}},\n\t\t{0x0F42AC, {2, \"Nick Fury\"}},\n\t\t{0x0F42AD, {2, \"Black Widow\"}},\n\t\t{0x0F42AE, {2, \"Hawkeye\"}},\n\t\t{0x0F42AF, {2, \"Drax\"}},\n\t\t{0x0F42B0, {2, \"Gamora\"}},\n\t\t{0x0F42B1, {2, \"Iron Fist\"}},\n\t\t{0x0F42B2, {2, \"Nova\"}},\n\t\t{0x0F42B3, {2, \"Venom\"}},\n\t\t{0x0F42B4, {2, \"Donald Duck\"}},\n\t\t{0x0F42B5, {2, \"Aladdin\"}},\n\t\t{0x0F42B6, {2, \"Stitch\"}},\n\t\t{0x0F42B7, {2, \"Merida\"}},\n\t\t{0x0F42B8, {2, \"Tinker Bell\"}},\n\t\t{0x0F42B9, {2, \"Maleficent\"}},\n\t\t{0x0F42BA, {2, \"Hiro\"}},\n\t\t{0x0F42BB, {2, \"Baymax\"}},\n\t\t{0x0F42BC, {2, \"Loki\"}},\n\t\t{0x0F42BD, {2, \"Ronan\"}},\n\t\t{0x0F42BE, {2, \"Green Goblin\"}},\n\t\t{0x0F42BF, {2, \"Falcon\"}},\n\t\t{0x0F42C0, {2, \"Yondu\"}},\n\t\t{0x0F42C1, {2, \"Jasmine\"}},\n\t\t{0x0F42C6, {2, \"Black Suit Spider-Man\"}},\n\t\t{0x0F42D6, {3, \"Sam Flynn\"}},\n\t\t{0x0F42D7, {3, \"Quorra\"}},\n\t\t{0x0F4308, {3, \"Anakin Skywalker\"}},\n\t\t{0x0F4309, {3, \"Obi-Wan Kenobi\"}},\n\t\t{0x0F430A, {3, \"Yoda\"}},\n\t\t{0x0F430B, {3, \"Ahsoka Tano\"}},\n\t\t{0x0F430C, {3, \"Darth Maul\"}},\n\t\t{0x0F430E, {3, \"Luke Skywalker\"}},\n\t\t{0x0F430F, {3, \"Han Solo\"}},\n\t\t{0x0F4310, {3, \"Princess Leia\"}},\n\t\t{0x0F4311, {3, \"Chewbacca\"}},\n\t\t{0x0F4312, {3, \"Darth Vader\"}},\n\t\t{0x0F4313, {3, \"Boba Fett\"}},\n\t\t{0x0F4314, {3, \"Ezra Bridger\"}},\n\t\t{0x0F4315, {3, \"Kanan Jarrus\"}},\n\t\t{0x0F4316, {3, \"Sabine Wren\"}},\n\t\t{0x0F4317, {3, \"Zeb Orrelios\"}},\n\t\t{0x0F4318, {3, \"Joy\"}},\n\t\t{0x0F4319, {3, \"Anger\"}},\n\t\t{0x0F431A, {3, \"Fear\"}},\n\t\t{0x0F431B, {3, \"Sadness\"}},\n\t\t{0x0F431C, {3, \"Disgust\"}},\n\t\t{0x0F431D, {3, \"Mickey Mouse\"}},\n\t\t{0x0F431E, {3, \"Minnie Mouse\"}},\n\t\t{0x0F431F, {3, \"Mulan\"}},\n\t\t{0x0F4320, {3, \"Olaf\"}},\n\t\t{0x0F4321, {3, \"Vision\"}},\n\t\t{0x0F4322, {3, \"Ultron\"}},\n\t\t{0x0F4323, {3, \"Ant-Man\"}},\n\t\t{0x0F4325, {3, \"Captain America - The First Avenger\"}},\n\t\t{0x0F4326, {3, \"Finn\"}},\n\t\t{0x0F4327, {3, \"Kylo Ren\"}},\n\t\t{0x0F4328, {3, \"Poe Dameron\"}},\n\t\t{0x0F4329, {3, \"Rey\"}},\n\t\t{0x0F432B, {3, \"Spot\"}},\n\t\t{0x0F432C, {3, \"Nick Wilde\"}},\n\t\t{0x0F432D, {3, \"Judy Hopps\"}},\n\t\t{0x0F432E, {3, \"Hulkbuster\"}},\n\t\t{0x0F432F, {3, \"Anakin Skywalker (Light FX)\"}},\n\t\t{0x0F4330, {3, \"Obi-Wan Kenobi (Light FX)\"}},\n\t\t{0x0F4331, {3, \"Yoda (Light FX)\"}},\n\t\t{0x0F4332, {3, \"Luke Skywalker (Light FX)\"}},\n\t\t{0x0F4333, {3, \"Darth Vader (Light FX)\"}},\n\t\t{0x0F4334, {3, \"Kanan Jarrus (Light FX)\"}},\n\t\t{0x0F4335, {3, \"Kylo Ren (Light FX)\"}},\n\t\t{0x0F4336, {3, \"Black Panther\"}},\n\t\t{0x0F436C, {3, \"Nemo\"}},\n\t\t{0x0F436D, {3, \"Dory\"}},\n\t\t{0x0F436E, {3, \"Baloo\"}},\n\t\t{0x0F436F, {3, \"Alice\"}},\n\t\t{0x0F4370, {3, \"Mad Hatter\"}},\n\t\t{0x0F4371, {3, \"Time\"}},\n\t\t{0x0F4372, {3, \"Peter Pan\"}},\n\t\t{0x1E8481, {1, \"Starter Play Set\"}},\n\t\t{0x1E8482, {1, \"Lone Ranger Play Set\"}},\n\t\t{0x1E8483, {1, \"Cars Play Set\"}},\n\t\t{0x1E8484, {1, \"Toy Story in Space Play Set\"}},\n\t\t{0x1E84E4, {2, \"Marvel's The Avengers Play Set\"}},\n\t\t{0x1E84E5, {2, \"Marvel's Spider-Man Play Set\"}},\n\t\t{0x1E84E6, {2, \"Marvel's Guardians of the Galaxy Play Set\"}},\n\t\t{0x1E84E7, {2, \"Assault on Asgard\"}},\n\t\t{0x1E84E8, {2, \"Escape from the Kyln\"}},\n\t\t{0x1E84E9, {2, \"Stitch's Tropical Rescue\"}},\n\t\t{0x1E84EA, {2, \"Brave Forest Siege\"}},\n\t\t{0x1E8548, {3, \"Inside Out Play Set\"}},\n\t\t{0x1E8549, {3, \"Star Wars: Twilight of the Republic Play Set\"}},\n\t\t{0x1E854A, {3, \"Star Wars: Rise Against the Empire Play Set\"}},\n\t\t{0x1E854B, {3, \"Star Wars: The Force Awakens Play Set\"}},\n\t\t{0x1E854C, {3, \"Marvel Battlegrounds Play Set\"}},\n\t\t{0x1E854D, {3, \"Toy Box Speedway\"}},\n\t\t{0x1E854E, {3, \"Toy Box Takeover\"}},\n\t\t{0x1E85AC, {3, \"Finding Dory Play Set\"}},\n\t\t{0x2DC6C3, {1, \"Bolt's Super Strength\"}},\n\t\t{0x2DC6C4, {1, \"Ralph's Power of Destruction\"}},\n\t\t{0x2DC6C5, {1, \"Chernabog's Power\"}},\n\t\t{0x2DC6C6, {1, \"C.H.R.O.M.E. Damage Increaser\"}},\n\t\t{0x2DC6C7, {1, \"Dr. Doofenshmirtz's Damage-Inator!\"}},\n\t\t{0x2DC6C8, {1, \"Electro-Charge\"}},\n\t\t{0x2DC6C9, {1, \"Fix-It Felix's Repair Power\"}},\n\t\t{0x2DC6CA, {1, \"Rapunzel's Healing\"}},\n\t\t{0x2DC6CB, {1, \"C.H.R.O.M.E. Armor Shield\"}},\n\t\t{0x2DC6CC, {1, \"Star Command Shield\"}},\n\t\t{0x2DC6CD, {1, \"Violet's Force Field\"}},\n\t\t{0x2DC6CE, {1, \"Pieces of Eight\"}},\n\t\t{0x2DC6CF, {1, \"Scrooge McDuck's Lucky Dime\"}},\n\t\t{0x2DC6D0, {1, \"User Control\"}},\n\t\t{0x2DC6D1, {1, \"Sorcerer Mickey's Hat\"}},\n\t\t{0x2DC6FE, {1, \"Emperor Zurg's Wrath\"}},\n\t\t{0x2DC6FF, {1, \"Merlin's Summon\"}},\n\t\t{0x2DC765, {2, \"Enchanted Rose\"}},\n\t\t{0x2DC766, {2, \"Mulan's Training Uniform\"}},\n\t\t{0x2DC767, {2, \"Flubber\"}},\n\t\t{0x2DC768, {2, \"S.H.I.E.L.D. Helicarrier Strike\"}},\n\t\t{0x2DC769, {2, \"Zeus' Thunderbolts\"}},\n\t\t{0x2DC76A, {2, \"King Louie's Monkeys\"}},\n\t\t{0x2DC76B, {2, \"Infinity Gauntlet\"}},\n\t\t{0x2DC76D, {2, \"Sorcerer Supreme\"}},\n\t\t{0x2DC76E, {2, \"Maleficent's Spell Cast\"}},\n\t\t{0x2DC76F, {2, \"Chernabog's Spirit Cyclone\"}},\n\t\t{0x2DC770, {2, \"Marvel Team-Up: Capt. Marvel\"}},\n\t\t{0x2DC771, {2, \"Marvel Team-Up: Iron Patriot\"}},\n\t\t{0x2DC772, {2, \"Marvel Team-Up: Ant-Man\"}},\n\t\t{0x2DC773, {2, \"Marvel Team-Up: White Tiger\"}},\n\t\t{0x2DC774, {2, \"Marvel Team-Up: Yondu\"}},\n\t\t{0x2DC775, {2, \"Marvel Team-Up: Winter Soldier\"}},\n\t\t{0x2DC776, {2, \"Stark Arc Reactor\"}},\n\t\t{0x2DC777, {2, \"Gamma Rays\"}},\n\t\t{0x2DC778, {2, \"Alien Symbiote\"}},\n\t\t{0x2DC779, {2, \"All for One\"}},\n\t\t{0x2DC77A, {2, \"Sandy Claws Surprise\"}},\n\t\t{0x2DC77B, {2, \"Glory Days\"}},\n\t\t{0x2DC77C, {2, \"Cursed Pirate Gold\"}},\n\t\t{0x2DC77D, {2, \"Sentinel of Liberty\"}},\n\t\t{0x2DC77E, {2, \"The Immortal Iron Fist\"}},\n\t\t{0x2DC77F, {2, \"Space Armor\"}},\n\t\t{0x2DC780, {2, \"Rags to Riches\"}},\n\t\t{0x2DC781, {2, \"Ultimate Falcon\"}},\n\t\t{0x2DC788, {3, \"Tomorrowland Time Bomb\"}},\n\t\t{0x2DC78E, {3, \"Galactic Team-Up: Mace Windu\"}},\n\t\t{0x2DC791, {3, \"Luke's Rebel Alliance Flight Suit Costume\"}},\n\t\t{0x2DC798, {3, \"Finn's Stormtrooper Costume\"}},\n\t\t{0x2DC799, {3, \"Poe's Resistance Jacket\"}},\n\t\t{0x2DC79A, {3, \"Resistance Tactical Strike\"}},\n\t\t{0x2DC79E, {3, \"Officer Nick Wilde\"}},\n\t\t{0x2DC79F, {3, \"Meter Maid Judy\"}},\n\t\t{0x2DC7A2, {3, \"Darkhawk's Blast\"}},\n\t\t{0x2DC7A3, {3, \"Cosmic Cube Blast\"}},\n\t\t{0x2DC7A4, {3, \"Princess Leia's Boushh Disguise\"}},\n\t\t{0x2DC7A6, {3, \"Nova Corps Strike\"}},\n\t\t{0x2DC7A7, {3, \"King Mickey\"}},\n\t\t{0x3D0912, {1, \"Mickey's Car\"}},\n\t\t{0x3D0913, {1, \"Cinderella's Coach\"}},\n\t\t{0x3D0914, {1, \"Electric Mayhem Bus\"}},\n\t\t{0x3D0915, {1, \"Cruella De Vil's Car\"}},\n\t\t{0x3D0916, {1, \"Pizza Planet Delivery Truck\"}},\n\t\t{0x3D0917, {1, \"Mike's New Car\"}},\n\t\t{0x3D0919, {1, \"Parking Lot Tram\"}},\n\t\t{0x3D091A, {1, \"Captain Hook's Ship\"}},\n\t\t{0x3D091B, {1, \"Dumbo\"}},\n\t\t{0x3D091C, {1, \"Calico Helicopter\"}},\n\t\t{0x3D091D, {1, \"Maximus\"}},\n\t\t{0x3D091E, {1, \"Angus\"}},\n\t\t{0x3D091F, {1, \"Abu the Elephant\"}},\n\t\t{0x3D0920, {1, \"Headless Horseman's Horse\"}},\n\t\t{0x3D0921, {1, \"Phillipe\"}},\n\t\t{0x3D0922, {1, \"Khan\"}},\n\t\t{0x3D0923, {1, \"Tantor\"}},\n\t\t{0x3D0924, {1, \"Dragon Firework Cannon\"}},\n\t\t{0x3D0925, {1, \"Stitch's Blaster\"}},\n\t\t{0x3D0926, {1, \"Toy Story Mania Blaster\"}},\n\t\t{0x3D0927, {1, \"Flamingo Croquet Mallet\"}},\n\t\t{0x3D0928, {1, \"Carl Fredricksen's Cane\"}},\n\t\t{0x3D0929, {1, \"Hangin' Ten Stitch With Surfboard\"}},\n\t\t{0x3D092A, {1, \"Condorman Glider\"}},\n\t\t{0x3D092B, {1, \"WALL-E's Fire Extinguisher\"}},\n\t\t{0x3D092C, {1, \"On the Grid\"}},\n\t\t{0x3D092D, {1, \"WALL-E's Collection\"}},\n\t\t{0x3D092E, {1, \"King Candy's Dessert Toppings\"}},\n\t\t{0x3D0930, {1, \"Victor's Experiments\"}},\n\t\t{0x3D0931, {1, \"Jack's Scary Decorations\"}},\n\t\t{0x3D0933, {1, \"Frozen Flourish\"}},\n\t\t{0x3D0934, {1, \"Rapunzel's Kingdom\"}},\n\t\t{0x3D0935, {1, \"TRON Interface\"}},\n\t\t{0x3D0936, {1, \"Buy N Large Atmosphere\"}},\n\t\t{0x3D0937, {1, \"Sugar Rush Sky\"}},\n\t\t{0x3D0939, {1, \"New Holland Skyline\"}},\n\t\t{0x3D093A, {1, \"Halloween Town Sky\"}},\n\t\t{0x3D093C, {1, \"Chill in the Air\"}},\n\t\t{0x3D093D, {1, \"Rapunzel's Birthday Sky\"}},\n\t\t{0x3D0940, {1, \"Astro Blasters Space Cruiser\"}},\n\t\t{0x3D0941, {1, \"Marlin's Reef\"}},\n\t\t{0x3D0942, {1, \"Nemo's Seascape\"}},\n\t\t{0x3D0943, {1, \"Alice's Wonderland\"}},\n\t\t{0x3D0944, {1, \"Tulgey Wood\"}},\n\t\t{0x3D0945, {1, \"Tri-State Area Terrain\"}},\n\t\t{0x3D0946, {1, \"Danville Sky\"}},\n\t\t{0x3D0965, {2, \"Stark Tech\"}},\n\t\t{0x3D0966, {2, \"Spider-Streets\"}},\n\t\t{0x3D0967, {2, \"World War Hulk\"}},\n\t\t{0x3D0968, {2, \"Gravity Falls Forest\"}},\n\t\t{0x3D0969, {2, \"Neverland\"}},\n\t\t{0x3D096A, {2, \"Simba's Pridelands\"}},\n\t\t{0x3D096C, {2, \"Calhoun's Command\"}},\n\t\t{0x3D096D, {2, \"Star-Lord's Galaxy\"}},\n\t\t{0x3D096E, {2, \"Dinosaur World\"}},\n\t\t{0x3D096F, {2, \"Groot's Roots\"}},\n\t\t{0x3D0970, {2, \"Mulan's Countryside\"}},\n\t\t{0x3D0971, {2, \"The Sands of Agrabah\"}},\n\t\t{0x3D0974, {2, \"A Small World\"}},\n\t\t{0x3D0975, {2, \"View from the Suit\"}},\n\t\t{0x3D0976, {2, \"Spider-Sky\"}},\n\t\t{0x3D0977, {2, \"World War Hulk Sky\"}},\n\t\t{0x3D0978, {2, \"Gravity Falls Sky\"}},\n\t\t{0x3D0979, {2, \"Second Star to the Right\"}},\n\t\t{0x3D097A, {2, \"The King's Domain\"}},\n\t\t{0x3D097C, {2, \"CyBug Swarm\"}},\n\t\t{0x3D097D, {2, \"The Rip\"}},\n\t\t{0x3D097E, {2, \"Forgotten Skies\"}},\n\t\t{0x3D097F, {2, \"Groot's View\"}},\n\t\t{0x3D0980, {2, \"The Middle Kingdom\"}},\n\t\t{0x3D0984, {2, \"Skies of the World\"}},\n\t\t{0x3D0985, {2, \"S.H.I.E.L.D. Containment Truck\"}},\n\t\t{0x3D0986, {2, \"Main Street Electrical Parade Float\"}},\n\t\t{0x3D0987, {2, \"Mr. Toad's Motorcar\"}},\n\t\t{0x3D0988, {2, \"Le Maximum\"}},\n\t\t{0x3D0989, {2, \"Alice in Wonderland's Caterpillar\"}},\n\t\t{0x3D098A, {2, \"Eglantine's Motorcycle\"}},\n\t\t{0x3D098B, {2, \"Medusa's Swamp Mobile\"}},\n\t\t{0x3D098C, {2, \"Hydra Motorcycle\"}},\n\t\t{0x3D098D, {2, \"Darkwing Duck's Ratcatcher\"}},\n\t\t{0x3D098F, {2, \"The USS Swinetrek\"}},\n\t\t{0x3D0991, {2, \"Spider-Copter\"}},\n\t\t{0x3D0992, {2, \"Aerial Area Rug\"}},\n\t\t{0x3D0993, {2, \"Jack-O-Lantern's Glider\"}},\n\t\t{0x3D0994, {2, \"Spider-Buggy\"}},\n\t\t{0x3D0995, {2, \"Jack Skellington's Reindeer\"}},\n\t\t{0x3D0996, {2, \"Fantasyland Carousel Horse\"}},\n\t\t{0x3D0997, {2, \"Odin's Horse\"}},\n\t\t{0x3D0998, {2, \"Gus the Mule\"}},\n\t\t{0x3D099A, {2, \"Darkwing Duck's Grappling Gun\"}},\n\t\t{0x3D099C, {2, \"Ghost Rider's Chain Whip\"}},\n\t\t{0x3D099D, {2, \"Lew Zealand's Boomerang Fish\"}},\n\t\t{0x3D099E, {2, \"Sergeant Calhoun's Blaster\"}},\n\t\t{0x3D09A0, {2, \"Falcon's Wings\"}},\n\t\t{0x3D09A1, {2, \"Mabel's Kittens for Fists\"}},\n\t\t{0x3D09A2, {2, \"Jim Hawkins' Solar Board\"}},\n\t\t{0x3D09A3, {2, \"Black Panther's Vibranium Knives\"}},\n\t\t{0x3D09A4, {2, \"Cloak of Levitation\"}},\n\t\t{0x3D09A5, {2, \"Aladdin's Magic Carpet\"}},\n\t\t{0x3D09A6, {2, \"Honey Lemon's Ice Capsules\"}},\n\t\t{0x3D09A7, {2, \"Jasmine's Palace View\"}},\n\t\t{0x3D09C1, {2, \"Lola\"}},\n\t\t{0x3D09C2, {2, \"Spider-Cycle\"}},\n\t\t{0x3D09C3, {2, \"The Avenjet\"}},\n\t\t{0x3D09C4, {2, \"Spider-Glider\"}},\n\t\t{0x3D09C5, {2, \"Light Cycle\"}},\n\t\t{0x3D09C6, {2, \"Light Jet\"}},\n\t\t{0x3D09C9, {3, \"Retro Ray Gun\"}},\n\t\t{0x3D09CA, {3, \"Tomorrowland Futurescape\"}},\n\t\t{0x3D09CB, {3, \"Tomorrowland Stratosphere\"}},\n\t\t{0x3D09CC, {3, \"Skies Over Felucia\"}},\n\t\t{0x3D09CD, {3, \"Forests of Felucia\"}},\n\t\t{0x3D09CF, {3, \"General Grievous' Wheel Bike\"}},\n\t\t{0x3D09D2, {3, \"Slave I Flyer\"}},\n\t\t{0x3D09D3, {3, \"Y-Wing Fighter\"}},\n\t\t{0x3D09D4, {3, \"Arlo\"}},\n\t\t{0x3D09D5, {3, \"Nash\"}},\n\t\t{0x3D09D6, {3, \"Butch\"}},\n\t\t{0x3D09D7, {3, \"Ramsey\"}},\n\t\t{0x3D09DC, {3, \"Stars Over Sahara Square\"}},\n\t\t{0x3D09DD, {3, \"Sahara Square Sands\"}},\n\t\t{0x3D09E0, {3, \"Ghost Rider's Motorcycle\"}},\n\t\t{0x3D09E5, {3, \"Quad Jumper\"}}};\n\n\tInfinityBaseDevice::InfinityBaseDevice()\n\t\t: Device(0x0E6F, 0x0129, 1, 2, 0)\n\t{\n\t\tm_IsOpened = false;\n\t}\n\n\tbool InfinityBaseDevice::Open()\n\t{\n\t\tif (!IsOpened())\n\t\t{\n\t\t\tm_IsOpened = true;\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid InfinityBaseDevice::Close()\n\t{\n\t\tif (IsOpened())\n\t\t{\n\t\t\tm_IsOpened = false;\n\t\t}\n\t}\n\n\tbool InfinityBaseDevice::IsOpened()\n\t{\n\t\treturn m_IsOpened;\n\t}\n\n\tDevice::ReadResult InfinityBaseDevice::Read(ReadMessage* message)\n\t{\n\t\tmemcpy(message->data, g_infinitybase.GetStatus().data(), message->length);\n\t\tmessage->bytesRead = message->length;\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\treturn Device::ReadResult::Success;\n\t}\n\n\tDevice::WriteResult InfinityBaseDevice::Write(WriteMessage* message)\n\t{\n\t\tg_infinitybase.SendCommand(message->data, message->length);\n\t\tmessage->bytesWritten = message->length;\n\t\treturn Device::WriteResult::Success;\n\t}\n\n\tbool InfinityBaseDevice::GetDescriptor(uint8 descType,\n\t\t\t\t\t\t\t\t\t\t   uint8 descIndex,\n\t\t\t\t\t\t\t\t\t\t   uint16 lang,\n\t\t\t\t\t\t\t\t\t\t   uint8* output,\n\t\t\t\t\t\t\t\t\t\t   uint32 outputMaxLength)\n\t{\n\t\tuint8 configurationDescriptor[0x29];\n\n\t\tuint8* currentWritePtr;\n\n\t\t// configuration descriptor\n\t\tcurrentWritePtr = configurationDescriptor + 0;\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 2;\t\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 2) = 0x0029; // wTotalLength\n\t\t*(uint8*)(currentWritePtr + 4) = 1;\t\t\t// bNumInterfaces\n\t\t*(uint8*)(currentWritePtr + 5) = 1;\t\t\t// bConfigurationValue\n\t\t*(uint8*)(currentWritePtr + 6) = 0;\t\t\t// iConfiguration\n\t\t*(uint8*)(currentWritePtr + 7) = 0x80;\t\t// bmAttributes\n\t\t*(uint8*)(currentWritePtr + 8) = 0xFA;\t\t// MaxPower\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// configuration descriptor\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t   // bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x04; // bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 2) = 0;\t   // bInterfaceNumber\n\t\t*(uint8*)(currentWritePtr + 3) = 0;\t   // bAlternateSetting\n\t\t*(uint8*)(currentWritePtr + 4) = 2;\t   // bNumEndpoints\n\t\t*(uint8*)(currentWritePtr + 5) = 3;\t   // bInterfaceClass\n\t\t*(uint8*)(currentWritePtr + 6) = 0;\t   // bInterfaceSubClass\n\t\t*(uint8*)(currentWritePtr + 7) = 0;\t   // bInterfaceProtocol\n\t\t*(uint8*)(currentWritePtr + 8) = 0;\t   // iInterface\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// configuration descriptor\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x21;\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 2) = 0x0111; // bcdHID\n\t\t*(uint8*)(currentWritePtr + 4) = 0x00;\t\t// bCountryCode\n\t\t*(uint8*)(currentWritePtr + 5) = 0x01;\t\t// bNumDescriptors\n\t\t*(uint8*)(currentWritePtr + 6) = 0x22;\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 7) = 0x001D; // wDescriptorLength\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// endpoint descriptor 1\n\t\t*(uint8*)(currentWritePtr + 0) = 7;\t\t  // bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x05;\t  // bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 2) = 0x81;\t  // bEndpointAddress\n\t\t*(uint8*)(currentWritePtr + 3) = 0x03;\t  // bmAttributes\n\t\t*(uint16be*)(currentWritePtr + 4) = 0x40; // wMaxPacketSize\n\t\t*(uint8*)(currentWritePtr + 6) = 0x01;\t  // bInterval\n\t\tcurrentWritePtr = currentWritePtr + 7;\n\t\t// endpoint descriptor 2\n\t\t*(uint8*)(currentWritePtr + 0) = 7;\t\t  // bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x05;\t  // bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 1) = 0x02;\t  // bEndpointAddress\n\t\t*(uint8*)(currentWritePtr + 2) = 0x03;\t  // bmAttributes\n\t\t*(uint16be*)(currentWritePtr + 3) = 0x40; // wMaxPacketSize\n\t\t*(uint8*)(currentWritePtr + 5) = 0x01;\t  // bInterval\n\t\tcurrentWritePtr = currentWritePtr + 7;\n\n\t\tcemu_assert_debug((currentWritePtr - configurationDescriptor) == 0x29);\n\n\t\tmemcpy(output, configurationDescriptor,\n\t\t\t   std::min<uint32>(outputMaxLength, sizeof(configurationDescriptor)));\n\t\treturn true;\n\t}\n\n\tbool InfinityBaseDevice::SetIdle(uint8 ifIndex,\n\t\t\t\t\t\t\t\t\t\t uint8 reportId,\n\t\t\t\t\t\t\t\t\t\t uint8 duration)\n\t{\n\t\treturn true;\n\t}\n\n\tbool InfinityBaseDevice::SetProtocol(uint8 ifIndex, uint8 protocol)\n\t{\n\t\treturn true;\n\t}\n\n\tbool InfinityBaseDevice::SetReport(ReportMessage* message)\n\t{\n\t\treturn true;\n\t}\n\n\tstd::array<uint8, 32> InfinityUSB::GetStatus()\n\t{\n\t\tstd::array<uint8, 32> response = {};\n\n\t\tbool responded = false;\n\n\t\tdo\n\t\t{\n\t\t\tif (!m_figureAddedRemovedResponses.empty())\n\t\t\t{\n\t\t\t\tmemcpy(response.data(), m_figureAddedRemovedResponses.front().data(),\n\t\t\t\t\t   0x20);\n\t\t\t\tm_figureAddedRemovedResponses.pop();\n\t\t\t\tresponded = true;\n\t\t\t}\n\t\t\telse if (!m_queries.empty())\n\t\t\t{\n\t\t\t\tmemcpy(response.data(), m_queries.front().data(), 0x20);\n\t\t\t\tm_queries.pop();\n\t\t\t\tresponded = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t\t\t}\n\t\t\t/* code */\n\t\t}\n\t\twhile (!responded);\n\n\t\treturn response;\n\t}\n\n\tvoid InfinityUSB::SendCommand(uint8* buf, uint32 length)\n\t{\n\t\tconst uint8 command = buf[2];\n\t\tconst uint8 sequence = buf[3];\n\n\t\tstd::array<uint8, 32> q_result{};\n\n\t\tswitch (command)\n\t\t{\n\t\tcase 0x80:\n\t\t{\n\t\t\tq_result = {0xaa, 0x15, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x03,\n\t\t\t\t\t\t0x02, 0x09, 0x09, 0x43, 0x20, 0x32, 0x62, 0x36,\n\t\t\t\t\t\t0x36, 0x4b, 0x34, 0x99, 0x67, 0x31, 0x93, 0x8c};\n\t\t\tbreak;\n\t\t}\n\t\tcase 0x81:\n\t\t{\n\t\t\t// Initiate Challenge\n\t\t\tg_infinitybase.DescrambleAndSeed(buf, sequence, q_result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0x83:\n\t\t{\n\t\t\t// Challenge Response\n\t\t\tg_infinitybase.GetNextAndScramble(sequence, q_result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0x90:\n\t\tcase 0x92:\n\t\tcase 0x93:\n\t\tcase 0x95:\n\t\tcase 0x96:\n\t\t{\n\t\t\t// Color commands\n\t\t\tg_infinitybase.GetBlankResponse(sequence, q_result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xA1:\n\t\t{\n\t\t\t// Get Present Figures\n\t\t\tg_infinitybase.GetPresentFigures(sequence, q_result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xA2:\n\t\t{\n\t\t\t// Read Block from Figure\n\t\t\tg_infinitybase.QueryBlock(buf[4], buf[5], q_result, sequence);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xA3:\n\t\t{\n\t\t\t// Write block to figure\n\t\t\tg_infinitybase.WriteBlock(buf[4], buf[5], &buf[7], q_result, sequence);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xB4:\n\t\t{\n\t\t\t// Get figure ID\n\t\t\tg_infinitybase.GetFigureIdentifier(buf[4], sequence, q_result);\n\t\t\tbreak;\n\t\t}\n\t\tcase 0xB5:\n\t\t{\n\t\t\t// Get status?\n\t\t\tg_infinitybase.GetBlankResponse(sequence, q_result);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tcemu_assert_error();\n\t\t\tbreak;\n\t\t}\n\n\t\tm_queries.push(q_result);\n\t}\n\n\tuint8 InfinityUSB::GenerateChecksum(const std::array<uint8, 32>& data,\n\t\t\t\t\t\t\t\t\t\tint numOfBytes) const\n\t{\n\t\tint checksum = 0;\n\t\tfor (int i = 0; i < numOfBytes; i++)\n\t\t{\n\t\t\tchecksum += data[i];\n\t\t}\n\t\treturn (checksum & 0xFF);\n\t}\n\n\tvoid InfinityUSB::GetBlankResponse(uint8 sequence,\n\t\t\t\t\t\t\t\t\t   std::array<uint8, 32>& replyBuf)\n\t{\n\t\treplyBuf[0] = 0xaa;\n\t\treplyBuf[1] = 0x01;\n\t\treplyBuf[2] = sequence;\n\t\treplyBuf[3] = GenerateChecksum(replyBuf, 3);\n\t}\n\n\tvoid InfinityUSB::DescrambleAndSeed(uint8* buf, uint8 sequence,\n\t\t\t\t\t\t\t\t\t\tstd::array<uint8, 32>& replyBuf)\n\t{\n\t\tuint64 value = uint64(buf[4]) << 56 | uint64(buf[5]) << 48 |\n\t\t\t\t\t   uint64(buf[6]) << 40 | uint64(buf[7]) << 32 |\n\t\t\t\t\t   uint64(buf[8]) << 24 | uint64(buf[9]) << 16 |\n\t\t\t\t\t   uint64(buf[10]) << 8 | uint64(buf[11]);\n\t\tuint32 seed = Descramble(value);\n\t\tGenerateSeed(seed);\n\t\tGetBlankResponse(sequence, replyBuf);\n\t}\n\n\tvoid InfinityUSB::GetNextAndScramble(uint8 sequence,\n\t\t\t\t\t\t\t\t\t\t std::array<uint8, 32>& replyBuf)\n\t{\n\t\tconst uint32 nextRandom = GetNext();\n\t\tconst uint64 scrambledNextRandom = Scramble(nextRandom, 0);\n\t\treplyBuf = {0xAA, 0x09, sequence};\n\t\treplyBuf[3] = uint8((scrambledNextRandom >> 56) & 0xFF);\n\t\treplyBuf[4] = uint8((scrambledNextRandom >> 48) & 0xFF);\n\t\treplyBuf[5] = uint8((scrambledNextRandom >> 40) & 0xFF);\n\t\treplyBuf[6] = uint8((scrambledNextRandom >> 32) & 0xFF);\n\t\treplyBuf[7] = uint8((scrambledNextRandom >> 24) & 0xFF);\n\t\treplyBuf[8] = uint8((scrambledNextRandom >> 16) & 0xFF);\n\t\treplyBuf[9] = uint8((scrambledNextRandom >> 8) & 0xFF);\n\t\treplyBuf[10] = uint8(scrambledNextRandom & 0xFF);\n\t\treplyBuf[11] = GenerateChecksum(replyBuf, 11);\n\t}\n\n\tuint32 InfinityUSB::Descramble(uint64 numToDescramble)\n\t{\n\t\tuint64 mask = 0x8E55AA1B3999E8AA;\n\t\tuint32 ret = 0;\n\n\t\tfor (int i = 0; i < 64; i++)\n\t\t{\n\t\t\tif (mask & 0x8000000000000000)\n\t\t\t{\n\t\t\t\tret = (ret << 1) | (numToDescramble & 0x01);\n\t\t\t}\n\n\t\t\tnumToDescramble >>= 1;\n\t\t\tmask <<= 1;\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\tuint64 InfinityUSB::Scramble(uint32 numToScramble, uint32 garbage)\n\t{\n\t\tuint64 mask = 0x8E55AA1B3999E8AA;\n\t\tuint64 ret = 0;\n\n\t\tfor (int i = 0; i < 64; i++)\n\t\t{\n\t\t\tret <<= 1;\n\n\t\t\tif ((mask & 1) != 0)\n\t\t\t{\n\t\t\t\tret |= (numToScramble & 1);\n\t\t\t\tnumToScramble >>= 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tret |= (garbage & 1);\n\t\t\t\tgarbage >>= 1;\n\t\t\t}\n\n\t\t\tmask >>= 1;\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\tvoid InfinityUSB::GenerateSeed(uint32 seed)\n\t{\n\t\tm_randomA = 0xF1EA5EED;\n\t\tm_randomB = seed;\n\t\tm_randomC = seed;\n\t\tm_randomD = seed;\n\n\t\tfor (int i = 0; i < 23; i++)\n\t\t{\n\t\t\tGetNext();\n\t\t}\n\t}\n\n\tuint32 InfinityUSB::GetNext()\n\t{\n\t\tuint32 a = m_randomA;\n\t\tuint32 b = m_randomB;\n\t\tuint32 c = m_randomC;\n\t\tuint32 ret = std::rotl(m_randomB, 27);\n\n\t\tconst uint32 temp = (a + ((ret ^ 0xFFFFFFFF) + 1));\n\t\tb ^= std::rotl(c, 17);\n\t\ta = m_randomD;\n\t\tc += a;\n\t\tret = b + temp;\n\t\ta += temp;\n\n\t\tm_randomC = a;\n\t\tm_randomA = b;\n\t\tm_randomB = c;\n\t\tm_randomD = ret;\n\n\t\treturn ret;\n\t}\n\n\tvoid InfinityUSB::GetPresentFigures(uint8 sequence,\n\t\t\t\t\t\t\t\t\t\tstd::array<uint8, 32>& replyBuf)\n\t{\n\t\tint x = 3;\n\t\tfor (uint8 i = 0; i < m_figures.size(); i++)\n\t\t{\n\t\t\tuint8 slot = i == 0 ? 0x10 : (i < 4) ? 0x20\n\t\t\t\t\t\t\t\t\t\t\t\t : 0x30;\n\t\t\tif (m_figures[i].present)\n\t\t\t{\n\t\t\t\treplyBuf[x] = slot + m_figures[i].orderAdded;\n\t\t\t\treplyBuf[x + 1] = 0x09;\n\t\t\t\tx += 2;\n\t\t\t}\n\t\t}\n\t\treplyBuf[0] = 0xaa;\n\t\treplyBuf[1] = x - 2;\n\t\treplyBuf[2] = sequence;\n\t\treplyBuf[x] = GenerateChecksum(replyBuf, x);\n\t}\n\n\tInfinityUSB::InfinityFigure&\n\tInfinityUSB::GetFigureByOrder(uint8 orderAdded)\n\t{\n\t\tfor (uint8 i = 0; i < m_figures.size(); i++)\n\t\t{\n\t\t\tif (m_figures[i].orderAdded == orderAdded)\n\t\t\t{\n\t\t\t\treturn m_figures[i];\n\t\t\t}\n\t\t}\n\t\treturn m_figures[0];\n\t}\n\n\tvoid InfinityUSB::QueryBlock(uint8 fig_num, uint8 block,\n\t\t\t\t\t\t\t\t std::array<uint8, 32>& replyBuf,\n\t\t\t\t\t\t\t\t uint8 sequence)\n\t{\n\t\tstd::lock_guard lock(m_infinityMutex);\n\n\t\tInfinityFigure& figure = GetFigureByOrder(fig_num);\n\n\t\treplyBuf[0] = 0xaa;\n\t\treplyBuf[1] = 0x12;\n\t\treplyBuf[2] = sequence;\n\t\treplyBuf[3] = 0x00;\n\t\tconst uint8 file_block = (block == 0) ? 1 : (block * 4);\n\t\tif (figure.present && file_block < 20)\n\t\t{\n\t\t\tmemcpy(&replyBuf[4], figure.data.data() + (16 * file_block), 16);\n\t\t}\n\t\treplyBuf[20] = GenerateChecksum(replyBuf, 20);\n\t}\n\n\tvoid InfinityUSB::WriteBlock(uint8 fig_num, uint8 block,\n\t\t\t\t\t\t\t\t const uint8* to_write_buf,\n\t\t\t\t\t\t\t\t std::array<uint8, 32>& replyBuf,\n\t\t\t\t\t\t\t\t uint8 sequence)\n\t{\n\t\tstd::lock_guard lock(m_infinityMutex);\n\n\t\tInfinityFigure& figure = GetFigureByOrder(fig_num);\n\n\t\treplyBuf[0] = 0xaa;\n\t\treplyBuf[1] = 0x02;\n\t\treplyBuf[2] = sequence;\n\t\treplyBuf[3] = 0x00;\n\t\tconst uint8 file_block = (block == 0) ? 1 : (block * 4);\n\t\tif (figure.present && file_block < 20)\n\t\t{\n\t\t\tmemcpy(figure.data.data() + (file_block * 16), to_write_buf, 16);\n\t\t\tfigure.Save();\n\t\t}\n\t\treplyBuf[4] = GenerateChecksum(replyBuf, 4);\n\t}\n\n\tvoid InfinityUSB::GetFigureIdentifier(uint8 fig_num, uint8 sequence,\n\t\t\t\t\t\t\t\t\t\t  std::array<uint8, 32>& replyBuf)\n\t{\n\t\tstd::lock_guard lock(m_infinityMutex);\n\n\t\tInfinityFigure& figure = GetFigureByOrder(fig_num);\n\n\t\treplyBuf[0] = 0xaa;\n\t\treplyBuf[1] = 0x09;\n\t\treplyBuf[2] = sequence;\n\t\treplyBuf[3] = 0x00;\n\n\t\tif (figure.present)\n\t\t{\n\t\t\tmemcpy(&replyBuf[4], figure.data.data(), 7);\n\t\t}\n\t\treplyBuf[11] = GenerateChecksum(replyBuf, 11);\n\t}\n\n\tstd::pair<uint8, std::string> InfinityUSB::FindFigure(uint32 figNum)\n\t{\n\t\tfor (const auto& it : GetFigureList())\n\t\t{\n\t\t\tif (it.first == figNum)\n\t\t\t{\n\t\t\t\treturn it.second;\n\t\t\t}\n\t\t}\n\t\treturn {0, fmt::format(\"Unknown Figure ({})\", figNum)};\n\t}\n\n\tstd::map<const uint32, const std::pair<const uint8, const char*>> InfinityUSB::GetFigureList()\n\t{\n\t\treturn s_listFigures;\n\t}\n\n\tvoid InfinityUSB::InfinityFigure::Save()\n\t{\n\t\tif (!infFile)\n\t\t\treturn;\n\n\t\tinfFile->SetPosition(0);\n\t\tinfFile->writeData(data.data(), data.size());\n\t}\n\n\tbool InfinityUSB::RemoveFigure(uint8 position)\n\t{\n\t\tstd::lock_guard lock(m_infinityMutex);\n\t\tInfinityFigure& figure = m_figures[position];\n\n\t\tfigure.Save();\n\t\tfigure.infFile.reset();\n\n\t\tif (figure.present)\n\t\t{\n\t\t\tfigure.present = false;\n\n\t\t\tposition = DeriveFigurePosition(position);\n\t\t\tif (position == 0)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tstd::array<uint8, 32> figureChangeResponse = {0xab, 0x04, position, 0x09, figure.orderAdded,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  0x01};\n\t\t\tfigureChangeResponse[6] = GenerateChecksum(figureChangeResponse, 6);\n\t\t\tm_figureAddedRemovedResponses.push(figureChangeResponse);\n\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tuint32\n\tInfinityUSB::LoadFigure(const std::array<uint8, INF_FIGURE_SIZE>& buf,\n\t\t\t\t\t\t\tstd::unique_ptr<FileStream> inFile, uint8 position)\n\t{\n\t\tstd::lock_guard lock(m_infinityMutex);\n\t\tuint8 orderAdded;\n\n\t\tstd::vector<uint8> sha1Calc = {SHA1_CONSTANT.begin(), SHA1_CONSTANT.end() - 1};\n\t\tfor (int i = 0; i < 7; i++)\n\t\t{\n\t\t\tsha1Calc.push_back(buf[i]);\n\t\t}\n\n\t\tstd::array<uint8, 16> key = GenerateInfinityFigureKey(sha1Calc);\n\n\t\tstd::array<uint8, 16> infinity_decrypted_block = {};\n\t\tstd::array<uint8, 16> encryptedBlock = {};\n\t\tmemcpy(encryptedBlock.data(), &buf[16], 16);\n\n\t\tAES128_ECB_decrypt(encryptedBlock.data(), key.data(), infinity_decrypted_block.data());\n\n\t\tuint32 number = uint32(infinity_decrypted_block[1]) << 16 | uint32(infinity_decrypted_block[2]) << 8 |\n\t\t\t\t\t\tuint32(infinity_decrypted_block[3]);\n\n\t\tInfinityFigure& figure = m_figures[position];\n\n\t\tfigure.infFile = std::move(inFile);\n\t\tmemcpy(figure.data.data(), buf.data(), figure.data.size());\n\t\tfigure.present = true;\n\t\tif (figure.orderAdded == 255)\n\t\t{\n\t\t\tfigure.orderAdded = m_figureOrder;\n\t\t\tm_figureOrder++;\n\t\t}\n\t\torderAdded = figure.orderAdded;\n\n\t\tposition = DeriveFigurePosition(position);\n\t\tif (position == 0)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tstd::array<uint8, 32> figureChangeResponse = {0xab, 0x04, position, 0x09, orderAdded, 0x00};\n\t\tfigureChangeResponse[6] = GenerateChecksum(figureChangeResponse, 6);\n\t\tm_figureAddedRemovedResponses.push(figureChangeResponse);\n\n\t\treturn number;\n\t}\n\n\tstatic uint32 InfinityCRC32(const std::array<uint8, 16>& buffer)\n\t{\n\t\tstatic constexpr std::array<uint32, 256> CRC32_TABLE{\n\t\t\t0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535,\n\t\t\t0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd,\n\t\t\t0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,\n\t\t\t0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,\n\t\t\t0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,\n\t\t\t0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,\n\t\t\t0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac,\n\t\t\t0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,\n\t\t\t0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,\n\t\t\t0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,\n\t\t\t0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,\n\t\t\t0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,\n\t\t\t0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,\n\t\t\t0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce,\n\t\t\t0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,\n\t\t\t0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,\n\t\t\t0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,\n\t\t\t0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,\n\t\t\t0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739,\n\t\t\t0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,\n\t\t\t0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268,\n\t\t\t0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0,\n\t\t\t0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,\n\t\t\t0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n\t\t\t0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,\n\t\t\t0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703,\n\t\t\t0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,\n\t\t\t0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,\n\t\t\t0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,\n\t\t\t0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n\t\t\t0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6,\n\t\t\t0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,\n\t\t\t0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,\n\t\t\t0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5,\n\t\t\t0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,\n\t\t\t0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,\n\t\t\t0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};\n\n\t\t// Infinity m_figures calculate their CRC32 based on 12 bytes in the block of 16\n\t\tuint32 ret = 0;\n\t\tfor (uint32 i = 0; i < 12; ++i)\n\t\t{\n\t\t\tuint8 index = uint8(ret & 0xFF) ^ buffer[i];\n\t\t\tret = ((ret >> 8) ^ CRC32_TABLE[index]);\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\tbool InfinityUSB::CreateFigure(fs::path pathName, uint32 figureNum, uint8 series)\n\t{\n\t\tFileStream* infFile(FileStream::createFile2(pathName));\n\t\tif (!infFile)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\tstd::array<uint8, INF_FIGURE_SIZE> fileData{};\n\t\tuint32 firstBlock = 0x17878E;\n\t\tuint32 otherBlocks = 0x778788;\n\t\tfor (sint8 i = 2; i >= 0; i--)\n\t\t{\n\t\t\tfileData[0x38 - i] = uint8((firstBlock >> i * 8) & 0xFF);\n\t\t}\n\t\tfor (uint32 index = 1; index < 0x05; index++)\n\t\t{\n\t\t\tfor (sint8 i = 2; i >= 0; i--)\n\t\t\t{\n\t\t\t\tfileData[((index * 0x40) + 0x38) - i] = uint8((otherBlocks >> i * 8) & 0xFF);\n\t\t\t}\n\t\t}\n\t\t// Create the vector to calculate the SHA1 hash with\n\t\tstd::vector<uint8> sha1Calc = {SHA1_CONSTANT.begin(), SHA1_CONSTANT.end() - 1};\n\n\t\t// Generate random UID, used for AES encrypt/decrypt\n\t\tstd::random_device rd;\n\t\tstd::mt19937 mt(rd());\n\t\tstd::uniform_int_distribution<int> dist(0, 255);\n\t\tstd::array<uint8, 16> uid_data = {0, 0, 0, 0, 0, 0, 0, 0x89, 0x44, 0x00, 0xC2};\n\t\tuid_data[0] = dist(mt);\n\t\tuid_data[1] = dist(mt);\n\t\tuid_data[2] = dist(mt);\n\t\tuid_data[3] = dist(mt);\n\t\tuid_data[4] = dist(mt);\n\t\tuid_data[5] = dist(mt);\n\t\tuid_data[6] = dist(mt);\n\t\tfor (sint8 i = 0; i < 7; i++)\n\t\t{\n\t\t\tsha1Calc.push_back(uid_data[i]);\n\t\t}\n\t\tstd::array<uint8, 16> figureData = GenerateBlankFigureData(figureNum, series);\n\t\tif (figureData[1] == 0x00)\n\t\t\treturn false;\n\n\t\tstd::array<uint8, 16> key = GenerateInfinityFigureKey(sha1Calc);\n\n\t\tstd::array<uint8, 16> encryptedBlock = {};\n\t\tstd::array<uint8, 16> blankBlock = {};\n\t\tstd::array<uint8, 16> encryptedBlank = {};\n\n\t\tAES128_ECB_encrypt(figureData.data(), key.data(), encryptedBlock.data());\n\t\tAES128_ECB_encrypt(blankBlock.data(), key.data(), encryptedBlank.data());\n\n\t\tmemcpy(&fileData[0], uid_data.data(), uid_data.size());\n\t\tmemcpy(&fileData[16], encryptedBlock.data(), encryptedBlock.size());\n\t\tmemcpy(&fileData[16 * 0x04], encryptedBlank.data(), encryptedBlank.size());\n\t\tmemcpy(&fileData[16 * 0x08], encryptedBlank.data(), encryptedBlank.size());\n\t\tmemcpy(&fileData[16 * 0x0C], encryptedBlank.data(), encryptedBlank.size());\n\t\tmemcpy(&fileData[16 * 0x0D], encryptedBlank.data(), encryptedBlank.size());\n\n\t\tinfFile->writeData(fileData.data(), fileData.size());\n\n\t\tdelete infFile;\n\n\t\treturn true;\n\t}\n\n\tstd::array<uint8, 16> InfinityUSB::GenerateInfinityFigureKey(const std::vector<uint8>& sha1Data)\n\t{\n\t\tstd::array<uint8, 20> digest = {};\n\t\tSHA1(sha1Data.data(), sha1Data.size(), digest.data());\n\t\t// Infinity AES keys are the first 16 bytes of the SHA1 Digest, every set of 4 bytes need to be\n\t\t// reversed due to endianness\n\t\tstd::array<uint8, 16> key = {};\n\t\tfor (int i = 0; i < 4; i++)\n\t\t{\n\t\t\tfor (int x = 3; x >= 0; x--)\n\t\t\t{\n\t\t\t\tkey[(3 - x) + (i * 4)] = digest[x + (i * 4)];\n\t\t\t}\n\t\t}\n\t\treturn key;\n\t}\n\n\tstd::array<uint8, 16> InfinityUSB::GenerateBlankFigureData(uint32 figureNum, uint8 series)\n\t{\n\t\tstd::array<uint8, 16> figureData = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t\t\t\t\t\t\t\t\t\t0x00, 0x00, 0x00, 0x01, 0xD1, 0x1F};\n\n\t\t// Figure Number, input by end user\n\t\tfigureData[1] = uint8((figureNum >> 16) & 0xFF);\n\t\tfigureData[2] = uint8((figureNum >> 8) & 0xFF);\n\t\tfigureData[3] = uint8(figureNum & 0xFF);\n\n\t\t// Manufacture date, formatted as YY/MM/DD. Set to release date of figure's series\n\t\tif (series == 1)\n\t\t{\n\t\t\tfigureData[4] = 0x0D;\n\t\t\tfigureData[5] = 0x08;\n\t\t\tfigureData[6] = 0x12;\n\t\t}\n\t\telse if (series == 2)\n\t\t{\n\t\t\tfigureData[4] = 0x0E;\n\t\t\tfigureData[5] = 0x09;\n\t\t\tfigureData[6] = 0x12;\n\t\t}\n\t\telse if (series == 3)\n\t\t{\n\t\t\tfigureData[4] = 0x0F;\n\t\t\tfigureData[5] = 0x08;\n\t\t\tfigureData[6] = 0x1C;\n\t\t}\n\n\t\tuint32 checksum = InfinityCRC32(figureData);\n\t\tfor (sint8 i = 3; i >= 0; i--)\n\t\t{\n\t\t\tfigureData[15 - i] = uint8((checksum >> i * 8) & 0xFF);\n\t\t}\n\t\treturn figureData;\n\t}\n\n\tuint8 InfinityUSB::DeriveFigurePosition(uint8 position)\n\t{\n\t\t// In the added/removed response, position needs to be 1 for the hexagon, 2 for Player 1 and\n\t\t// Player 1's abilities, and 3 for Player 2 and Player 2's abilities. In the UI, positions 0, 1\n\t\t// and 2 represent the hexagon slot, 3, 4 and 5 represent Player 1's slot and 6, 7 and 8 represent\n\t\t// Player 2's slot.\n\n\t\tswitch (position)\n\t\t{\n\t\tcase 0:\n\t\tcase 1:\n\t\tcase 2:\n\t\t\treturn 1;\n\t\tcase 3:\n\t\tcase 4:\n\t\tcase 5:\n\t\t\treturn 2;\n\t\tcase 6:\n\t\tcase 7:\n\t\tcase 8:\n\t\t\treturn 3;\n\n\t\tdefault:\n\t\t\treturn 0;\n\t\t}\n\t}\n} // namespace nsyshid"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/Infinity.h",
    "content": "#pragma once\n\n#include <mutex>\n\n#include \"nsyshid.h\"\n#include \"Backend.h\"\n\n#include \"Common/FileStream.h\"\n\nnamespace nsyshid\n{\n\tclass InfinityBaseDevice final : public Device {\n\t  public:\n\t\tInfinityBaseDevice();\n\t\t~InfinityBaseDevice() = default;\n\n\t\tbool Open() override;\n\n\t\tvoid Close() override;\n\n\t\tbool IsOpened() override;\n\n\t\tReadResult Read(ReadMessage* message) override;\n\n\t\tWriteResult Write(WriteMessage* message) override;\n\n\t\tbool GetDescriptor(uint8 descType,\n\t\t\t\t\t\t   uint8 descIndex,\n\t\t\t\t\t\t   uint16 lang,\n\t\t\t\t\t\t   uint8* output,\n\t\t\t\t\t\t   uint32 outputMaxLength) override;\n\n\t\tbool SetIdle(uint8 ifIndex,\n\t\t\t\t\t uint8 reportId,\n\t\t\t\t\t uint8 duration) override;\n\n\t\tbool SetProtocol(uint8 ifIndex, uint8 protocol) override;\n\n\t\tbool SetReport(ReportMessage* message) override;\n\n\t  private:\n\t\tbool m_IsOpened;\n\t};\n\n\tconstexpr uint16 INF_BLOCK_COUNT = 0x14;\n\tconstexpr uint16 INF_BLOCK_SIZE = 0x10;\n\tconstexpr uint16 INF_FIGURE_SIZE = INF_BLOCK_COUNT * INF_BLOCK_SIZE;\n\tconstexpr uint8 MAX_FIGURES = 9;\n\tclass InfinityUSB {\n\t  public:\n\t\tstruct InfinityFigure final\n\t\t{\n\t\t\tstd::unique_ptr<FileStream> infFile;\n\t\t\tstd::array<uint8, INF_FIGURE_SIZE> data{};\n\t\t\tbool present = false;\n\t\t\tuint8 orderAdded = 255;\n\t\t\tvoid Save();\n\t\t};\n\n\t\tvoid SendCommand(uint8* buf, uint32 length);\n\t\tstd::array<uint8, 32> GetStatus();\n\n\t\tvoid GetBlankResponse(uint8 sequence, std::array<uint8, 32>& replyBuf);\n\t\tvoid DescrambleAndSeed(uint8* buf, uint8 sequence,\n\t\t\t\t\t\t\t   std::array<uint8, 32>& replyBuf);\n\t\tvoid GetNextAndScramble(uint8 sequence, std::array<uint8, 32>& replyBuf);\n\t\tvoid GetPresentFigures(uint8 sequence, std::array<uint8, 32>& replyBuf);\n\t\tvoid QueryBlock(uint8 figNum, uint8 block, std::array<uint8, 32>& replyBuf,\n\t\t\t\t\t\tuint8 sequence);\n\t\tvoid WriteBlock(uint8 figNum, uint8 block, const uint8* toWriteBuf,\n\t\t\t\t\t\tstd::array<uint8, 32>& replyBuf, uint8 sequence);\n\t\tvoid GetFigureIdentifier(uint8 figNum, uint8 sequence,\n\t\t\t\t\t\t\t\t std::array<uint8, 32>& replyBuf);\n\n\t\tbool RemoveFigure(uint8 position);\n\t\tuint32 LoadFigure(const std::array<uint8, INF_FIGURE_SIZE>& buf,\n\t\t\t\t\t\t  std::unique_ptr<FileStream>, uint8 position);\n\t\tbool CreateFigure(fs::path pathName, uint32 figureNum, uint8 series);\n\t\tstatic std::map<const uint32, const std::pair<const uint8, const char*>> GetFigureList();\n\t\tstd::pair<uint8, std::string> FindFigure(uint32 figNum);\n\n\t  protected:\n\t\tstd::shared_mutex m_infinityMutex;\n\t\tstd::array<InfinityFigure, 9> m_figures;\n\n\t  private:\n\t\tuint8 GenerateChecksum(const std::array<uint8, 32>& data,\n\t\t\t\t\t\t\t   int numOfBytes) const;\n\t\tuint32 Descramble(uint64 numToDescramble);\n\t\tuint64 Scramble(uint32 numToScramble, uint32 garbage);\n\t\tvoid GenerateSeed(uint32 seed);\n\t\tuint32 GetNext();\n\t\tInfinityFigure& GetFigureByOrder(uint8 orderAdded);\n\t\tuint8 DeriveFigurePosition(uint8 position);\n\t\tstd::array<uint8, 16> GenerateInfinityFigureKey(const std::vector<uint8>& sha1Data);\n\t\tstd::array<uint8, 16> GenerateBlankFigureData(uint32 figureNum, uint8 series);\n\n\t\tuint32 m_randomA;\n\t\tuint32 m_randomB;\n\t\tuint32 m_randomC;\n\t\tuint32 m_randomD;\n\n\t\tuint8 m_figureOrder = 0;\n\t\tstd::queue<std::array<uint8, 32>> m_figureAddedRemovedResponses;\n\t\tstd::queue<std::array<uint8, 32>> m_queries;\n\t};\n\textern InfinityUSB g_infinitybase;\n\n} // namespace nsyshid"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/Skylander.cpp",
    "content": "#include \"Skylander.h\"\n\n#include <random>\n\n#include \"nsyshid.h\"\n#include \"Backend.h\"\n\n#include \"Common/FileStream.h\"\n#include \"audio/IAudioAPI.h\"\n#include \"config/CemuConfig.h\"\n\nnamespace nsyshid\n{\n\tSkylanderUSB g_skyportal;\n\n\tconst std::map<const std::pair<const uint16, const uint16>, const char*>\n\t\ts_listSkylanders = {\n\t\t\t{{0, 0x0000}, \"Whirlwind\"},\n\t\t\t{{0, 0x1801}, \"Series 2 Whirlwind\"},\n\t\t\t{{0, 0x1C02}, \"Polar Whirlwind\"},\n\t\t\t{{0, 0x2805}, \"Horn Blast Whirlwind\"},\n\t\t\t{{0, 0x3810}, \"Eon's Elite Whirlwind\"},\n\t\t\t{{1, 0x0000}, \"Sonic Boom\"},\n\t\t\t{{1, 0x1801}, \"Series 2 Sonic Boom\"},\n\t\t\t{{2, 0x0000}, \"Warnado\"},\n\t\t\t{{2, 0x2206}, \"LightCore Warnado\"},\n\t\t\t{{3, 0x0000}, \"Lightning Rod\"},\n\t\t\t{{3, 0x1801}, \"Series 2 Lightning Rod\"},\n\t\t\t{{4, 0x0000}, \"Bash\"},\n\t\t\t{{4, 0x1801}, \"Series 2 Bash\"},\n\t\t\t{{5, 0x0000}, \"Terrafin\"},\n\t\t\t{{5, 0x1801}, \"Series 2 Terrafin\"},\n\t\t\t{{5, 0x2805}, \"Knockout Terrafin\"},\n\t\t\t{{5, 0x3810}, \"Eon's Elite Terrafin\"},\n\t\t\t{{6, 0x0000}, \"Dino Rang\"},\n\t\t\t{{6, 0x4810}, \"Eon's Elite Dino Rang\"},\n\t\t\t{{7, 0x0000}, \"Prism Break\"},\n\t\t\t{{7, 0x1801}, \"Series 2 Prism Break\"},\n\t\t\t{{7, 0x2805}, \"Hyper Beam Prism Break\"},\n\t\t\t{{7, 0x1206}, \"LightCore Prism Break\"},\n\t\t\t{{8, 0x0000}, \"Sunburn\"},\n\t\t\t{{9, 0x0000}, \"Eruptor\"},\n\t\t\t{{9, 0x1801}, \"Series 2 Eruptor\"},\n\t\t\t{{9, 0x2C02}, \"Volcanic Eruptor\"},\n\t\t\t{{9, 0x2805}, \"Lava Barf Eruptor\"},\n\t\t\t{{9, 0x1206}, \"LightCore Eruptor\"},\n\t\t\t{{9, 0x3810}, \"Eon's Elite Eruptor\"},\n\t\t\t{{10, 0x0000}, \"Ignitor\"},\n\t\t\t{{10, 0x1801}, \"Series 2 Ignitor\"},\n\t\t\t{{10, 0x1C03}, \"Legendary Ignitor\"},\n\t\t\t{{11, 0x0000}, \"Flameslinger\"},\n\t\t\t{{11, 0x1801}, \"Series 2 Flameslinger\"},\n\t\t\t{{12, 0x0000}, \"Zap\"},\n\t\t\t{{12, 0x1801}, \"Series 2 Zap\"},\n\t\t\t{{13, 0x0000}, \"Wham Shell\"},\n\t\t\t{{13, 0x2206}, \"LightCore Wham Shell\"},\n\t\t\t{{14, 0x0000}, \"Gill Grunt\"},\n\t\t\t{{14, 0x1801}, \"Series 2 Gill Grunt\"},\n\t\t\t{{14, 0x2805}, \"Anchors Away Gill Grunt\"},\n\t\t\t{{14, 0x3805}, \"Tidal Wave Gill Grunt\"},\n\t\t\t{{14, 0x3810}, \"Eon's Elite Gill Grunt\"},\n\t\t\t{{15, 0x0000}, \"Slam Bam\"},\n\t\t\t{{15, 0x1801}, \"Series 2 Slam Bam\"},\n\t\t\t{{15, 0x1C03}, \"Legendary Slam Bam\"},\n\t\t\t{{15, 0x4810}, \"Eon's Elite Slam Bam\"},\n\t\t\t{{16, 0x0000}, \"Spyro\"},\n\t\t\t{{16, 0x1801}, \"Series 2 Spyro\"},\n\t\t\t{{16, 0x2C02}, \"Dark Mega Ram Spyro\"},\n\t\t\t{{16, 0x2805}, \"Mega Ram Spyro\"},\n\t\t\t{{16, 0x3810}, \"Eon's Elite Spyro\"},\n\t\t\t{{17, 0x0000}, \"Voodood\"},\n\t\t\t{{17, 0x4810}, \"Eon's Elite Voodood\"},\n\t\t\t{{18, 0x0000}, \"Double Trouble\"},\n\t\t\t{{18, 0x1801}, \"Series 2 Double Trouble\"},\n\t\t\t{{18, 0x1C02}, \"Royal Double Trouble\"},\n\t\t\t{{19, 0x0000}, \"Trigger Happy\"},\n\t\t\t{{19, 0x1801}, \"Series 2 Trigger Happy\"},\n\t\t\t{{19, 0x2C02}, \"Springtime Trigger Happy\"},\n\t\t\t{{19, 0x2805}, \"Big Bang Trigger Happy\"},\n\t\t\t{{19, 0x3810}, \"Eon's Elite Trigger Happy\"},\n\t\t\t{{20, 0x0000}, \"Drobot\"},\n\t\t\t{{20, 0x1801}, \"Series 2 Drobot\"},\n\t\t\t{{20, 0x1206}, \"LightCore Drobot\"},\n\t\t\t{{21, 0x0000}, \"Drill Seargeant\"},\n\t\t\t{{21, 0x1801}, \"Series 2 Drill Seargeant\"},\n\t\t\t{{22, 0x0000}, \"Boomer\"},\n\t\t\t{{22, 0x4810}, \"Eon's Elite Boomer\"},\n\t\t\t{{23, 0x0000}, \"Wrecking Ball\"},\n\t\t\t{{23, 0x1801}, \"Series 2 Wrecking Ball\"},\n\t\t\t{{24, 0x0000}, \"Camo\"},\n\t\t\t{{24, 0x2805}, \"Thorn Horn Camo\"},\n\t\t\t{{25, 0x0000}, \"Zook\"},\n\t\t\t{{25, 0x1801}, \"Series 2 Zook\"},\n\t\t\t{{25, 0x4810}, \"Eon's Elite Zook\"},\n\t\t\t{{26, 0x0000}, \"Stealth Elf\"},\n\t\t\t{{26, 0x1801}, \"Series 2 Stealth Elf\"},\n\t\t\t{{26, 0x2C02}, \"Dark Stealth Elf\"},\n\t\t\t{{26, 0x1C03}, \"Legendary Stealth Elf\"},\n\t\t\t{{26, 0x2805}, \"Ninja Stealth Elf\"},\n\t\t\t{{26, 0x3810}, \"Eon's Elite Stealth Elf\"},\n\t\t\t{{27, 0x0000}, \"Stump Smash\"},\n\t\t\t{{27, 0x1801}, \"Series 2 Stump Smash\"},\n\t\t\t{{28, 0x0000}, \"Dark Spyro\"},\n\t\t\t{{29, 0x0000}, \"Hex\"},\n\t\t\t{{29, 0x1801}, \"Series 2 Hex\"},\n\t\t\t{{29, 0x1206}, \"LightCore Hex\"},\n\t\t\t{{30, 0x0000}, \"Chop Chop\"},\n\t\t\t{{30, 0x1801}, \"Series 2 Chop Chop\"},\n\t\t\t{{30, 0x2805}, \"Twin Blade Chop Chop\"},\n\t\t\t{{30, 0x3810}, \"Eon's Elite Chop Chop\"},\n\t\t\t{{31, 0x0000}, \"Ghost Roaster\"},\n\t\t\t{{31, 0x4810}, \"Eon's Elite Ghost Roaster\"},\n\t\t\t{{32, 0x0000}, \"Cynder\"},\n\t\t\t{{32, 0x1801}, \"Series 2 Cynder\"},\n\t\t\t{{32, 0x2805}, \"Phantom Cynder\"},\n\t\t\t{{100, 0x0000}, \"Jet Vac\"},\n\t\t\t{{100, 0x1403}, \"Legendary Jet Vac\"},\n\t\t\t{{100, 0x2805}, \"Turbo Jet Vac\"},\n\t\t\t{{100, 0x3805}, \"Full Blast Jet Vac\"},\n\t\t\t{{100, 0x1206}, \"LightCore Jet Vac\"},\n\t\t\t{{101, 0x0000}, \"Swarm\"},\n\t\t\t{{102, 0x0000}, \"Crusher\"},\n\t\t\t{{102, 0x1602}, \"Granite Crusher\"},\n\t\t\t{{103, 0x0000}, \"Flashwing\"},\n\t\t\t{{103, 0x1402}, \"Jade Flash Wing\"},\n\t\t\t{{103, 0x2206}, \"LightCore Flashwing\"},\n\t\t\t{{104, 0x0000}, \"Hot Head\"},\n\t\t\t{{105, 0x0000}, \"Hot Dog\"},\n\t\t\t{{105, 0x1402}, \"Molten Hot Dog\"},\n\t\t\t{{105, 0x2805}, \"Fire Bone Hot Dog\"},\n\t\t\t{{106, 0x0000}, \"Chill\"},\n\t\t\t{{106, 0x1603}, \"Legendary Chill\"},\n\t\t\t{{106, 0x2805}, \"Blizzard Chill\"},\n\t\t\t{{106, 0x1206}, \"LightCore Chill\"},\n\t\t\t{{107, 0x0000}, \"Thumpback\"},\n\t\t\t{{108, 0x0000}, \"Pop Fizz\"},\n\t\t\t{{108, 0x1402}, \"Punch Pop Fizz\"},\n\t\t\t{{108, 0x3C02}, \"Love Potion Pop Fizz\"},\n\t\t\t{{108, 0x2805}, \"Super Gulp Pop Fizz\"},\n\t\t\t{{108, 0x3805}, \"Fizzy Frenzy Pop Fizz\"},\n\t\t\t{{108, 0x1206}, \"LightCore Pop Fizz\"},\n\t\t\t{{109, 0x0000}, \"Ninjini\"},\n\t\t\t{{109, 0x1602}, \"Scarlet Ninjini\"},\n\t\t\t{{110, 0x0000}, \"Bouncer\"},\n\t\t\t{{110, 0x1603}, \"Legendary Bouncer\"},\n\t\t\t{{111, 0x0000}, \"Sprocket\"},\n\t\t\t{{111, 0x2805}, \"Heavy Duty Sprocket\"},\n\t\t\t{{112, 0x0000}, \"Tree Rex\"},\n\t\t\t{{112, 0x1602}, \"Gnarly Tree Rex\"},\n\t\t\t{{113, 0x0000}, \"Shroomboom\"},\n\t\t\t{{113, 0x3805}, \"Sure Shot Shroomboom\"},\n\t\t\t{{113, 0x1206}, \"LightCore Shroomboom\"},\n\t\t\t{{114, 0x0000}, \"Eye Brawl\"},\n\t\t\t{{115, 0x0000}, \"Fright Rider\"},\n\t\t\t{{200, 0x0000}, \"Anvil Rain\"},\n\t\t\t{{201, 0x0000}, \"Hidden Treasure\"},\n\t\t\t{{201, 0x2000}, \"Platinum Hidden Treasure\"},\n\t\t\t{{202, 0x0000}, \"Healing Elixir\"},\n\t\t\t{{203, 0x0000}, \"Ghost Pirate Swords\"},\n\t\t\t{{204, 0x0000}, \"Time Twist Hourglass\"},\n\t\t\t{{205, 0x0000}, \"Sky Iron Shield\"},\n\t\t\t{{206, 0x0000}, \"Winged Boots\"},\n\t\t\t{{207, 0x0000}, \"Sparx the Dragonfly\"},\n\t\t\t{{208, 0x0000}, \"Dragonfire Cannon\"},\n\t\t\t{{208, 0x1602}, \"Golden Dragonfire Cannon\"},\n\t\t\t{{209, 0x0000}, \"Scorpion Striker\"},\n\t\t\t{{210, 0x3002}, \"Biter's Bane\"},\n\t\t\t{{210, 0x3008}, \"Sorcerous Skull\"},\n\t\t\t{{210, 0x300B}, \"Axe of Illusion\"},\n\t\t\t{{210, 0x300E}, \"Arcane Hourglass\"},\n\t\t\t{{210, 0x3012}, \"Spell Slapper\"},\n\t\t\t{{210, 0x3014}, \"Rune Rocket\"},\n\t\t\t{{211, 0x3001}, \"Tidal Tiki\"},\n\t\t\t{{211, 0x3002}, \"Wet Walter\"},\n\t\t\t{{211, 0x3006}, \"Flood Flask\"},\n\t\t\t{{211, 0x3406}, \"Legendary Flood Flask\"},\n\t\t\t{{211, 0x3007}, \"Soaking Staff\"},\n\t\t\t{{211, 0x300B}, \"Aqua Axe\"},\n\t\t\t{{211, 0x3016}, \"Frost Helm\"},\n\t\t\t{{212, 0x3003}, \"Breezy Bird\"},\n\t\t\t{{212, 0x3006}, \"Drafty Decanter\"},\n\t\t\t{{212, 0x300D}, \"Tempest Timer\"},\n\t\t\t{{212, 0x3010}, \"Cloudy Cobra\"},\n\t\t\t{{212, 0x3011}, \"Storm Warning\"},\n\t\t\t{{212, 0x3018}, \"Cyclone Saber\"},\n\t\t\t{{213, 0x3004}, \"Spirit Sphere\"},\n\t\t\t{{213, 0x3404}, \"Legendary Spirit Sphere\"},\n\t\t\t{{213, 0x3008}, \"Spectral Skull\"},\n\t\t\t{{213, 0x3408}, \"Legendary Spectral Skull\"},\n\t\t\t{{213, 0x300B}, \"Haunted Hatchet\"},\n\t\t\t{{213, 0x300C}, \"Grim Gripper\"},\n\t\t\t{{213, 0x3010}, \"Spooky Snake\"},\n\t\t\t{{213, 0x3017}, \"Dream Piercer\"},\n\t\t\t{{214, 0x3000}, \"Tech Totem\"},\n\t\t\t{{214, 0x3007}, \"Automatic Angel\"},\n\t\t\t{{214, 0x3009}, \"Factory Flower\"},\n\t\t\t{{214, 0x300C}, \"Grabbing Gadget\"},\n\t\t\t{{214, 0x3016}, \"Makers Mana\"},\n\t\t\t{{214, 0x301A}, \"Topsy Techy\"},\n\t\t\t{{215, 0x3005}, \"Eternal Flame\"},\n\t\t\t{{215, 0x3009}, \"Fire Flower\"},\n\t\t\t{{215, 0x3011}, \"Scorching Stopper\"},\n\t\t\t{{215, 0x3012}, \"Searing Spinner\"},\n\t\t\t{{215, 0x3017}, \"Spark Spear\"},\n\t\t\t{{215, 0x301B}, \"Blazing Belch\"},\n\t\t\t{{216, 0x3000}, \"Banded Boulder\"},\n\t\t\t{{216, 0x3003}, \"Rock Hawk\"},\n\t\t\t{{216, 0x300A}, \"Slag Hammer\"},\n\t\t\t{{216, 0x300E}, \"Dust Of Time\"},\n\t\t\t{{216, 0x3013}, \"Spinning Sandstorm\"},\n\t\t\t{{216, 0x301A}, \"Rubble Trouble\"},\n\t\t\t{{217, 0x3003}, \"Oak Eagle\"},\n\t\t\t{{217, 0x3005}, \"Emerald Energy\"},\n\t\t\t{{217, 0x300A}, \"Weed Whacker\"},\n\t\t\t{{217, 0x3010}, \"Seed Serpent\"},\n\t\t\t{{217, 0x3018}, \"Jade Blade\"},\n\t\t\t{{217, 0x301B}, \"Shrub Shrieker\"},\n\t\t\t{{218, 0x3000}, \"Dark Dagger\"},\n\t\t\t{{218, 0x3014}, \"Shadow Spider\"},\n\t\t\t{{218, 0x301A}, \"Ghastly Grimace\"},\n\t\t\t{{219, 0x3000}, \"Shining Ship\"},\n\t\t\t{{219, 0x300F}, \"Heavenly Hawk\"},\n\t\t\t{{219, 0x301B}, \"Beam Scream\"},\n\t\t\t{{220, 0x301E}, \"Kaos Trap\"},\n\t\t\t{{220, 0x351F}, \"Ultimate Kaos Trap\"},\n\t\t\t{{230, 0x0000}, \"Hand of Fate\"},\n\t\t\t{{230, 0x3403}, \"Legendary Hand of Fate\"},\n\t\t\t{{231, 0x0000}, \"Piggy Bank\"},\n\t\t\t{{232, 0x0000}, \"Rocket Ram\"},\n\t\t\t{{233, 0x0000}, \"Tiki Speaky\"},\n\t\t\t{{300, 0x0000}, \"Dragon’s Peak\"},\n\t\t\t{{301, 0x0000}, \"Empire of Ice\"},\n\t\t\t{{302, 0x0000}, \"Pirate Seas\"},\n\t\t\t{{303, 0x0000}, \"Darklight Crypt\"},\n\t\t\t{{304, 0x0000}, \"Volcanic Vault\"},\n\t\t\t{{305, 0x0000}, \"Mirror of Mystery\"},\n\t\t\t{{306, 0x0000}, \"Nightmare Express\"},\n\t\t\t{{307, 0x0000}, \"Sunscraper Spire\"},\n\t\t\t{{308, 0x0000}, \"Midnight Museum\"},\n\t\t\t{{404, 0x0000}, \"Legendary Bash\"},\n\t\t\t{{416, 0x0000}, \"Legendary Spyro\"},\n\t\t\t{{419, 0x0000}, \"Legendary Trigger Happy\"},\n\t\t\t{{430, 0x0000}, \"Legendary Chop Chop\"},\n\t\t\t{{450, 0x0000}, \"Gusto\"},\n\t\t\t{{451, 0x0000}, \"Thunderbolt\"},\n\t\t\t{{452, 0x0000}, \"Fling Kong\"},\n\t\t\t{{453, 0x0000}, \"Blades\"},\n\t\t\t{{453, 0x3403}, \"Legendary Blades\"},\n\t\t\t{{454, 0x0000}, \"Wallop\"},\n\t\t\t{{455, 0x0000}, \"Head Rush\"},\n\t\t\t{{455, 0x3402}, \"Nitro Head Rush\"},\n\t\t\t{{456, 0x0000}, \"Fist Bump\"},\n\t\t\t{{457, 0x0000}, \"Rocky Roll\"},\n\t\t\t{{458, 0x0000}, \"Wildfire\"},\n\t\t\t{{458, 0x3402}, \"Dark Wildfire\"},\n\t\t\t{{459, 0x0000}, \"Ka Boom\"},\n\t\t\t{{460, 0x0000}, \"Trail Blazer\"},\n\t\t\t{{461, 0x0000}, \"Torch\"},\n\t\t\t{{462, 0x3000}, \"Snap Shot\"},\n\t\t\t{{462, 0x3402}, \"Dark Snap Shot\"},\n\t\t\t{{463, 0x0000}, \"Lob Star\"},\n\t\t\t{{463, 0x3402}, \"Winterfest Lob-Star\"},\n\t\t\t{{464, 0x0000}, \"Flip Wreck\"},\n\t\t\t{{465, 0x0000}, \"Echo\"},\n\t\t\t{{466, 0x0000}, \"Blastermind\"},\n\t\t\t{{467, 0x0000}, \"Enigma\"},\n\t\t\t{{468, 0x0000}, \"Deja Vu\"},\n\t\t\t{{468, 0x3403}, \"Legendary Deja Vu\"},\n\t\t\t{{469, 0x0000}, \"Cobra Candabra\"},\n\t\t\t{{469, 0x3402}, \"King Cobra Cadabra\"},\n\t\t\t{{470, 0x0000}, \"Jawbreaker\"},\n\t\t\t{{470, 0x3403}, \"Legendary Jawbreaker\"},\n\t\t\t{{471, 0x0000}, \"Gearshift\"},\n\t\t\t{{472, 0x0000}, \"Chopper\"},\n\t\t\t{{473, 0x0000}, \"Tread Head\"},\n\t\t\t{{474, 0x0000}, \"Bushwack\"},\n\t\t\t{{474, 0x3403}, \"Legendary Bushwack\"},\n\t\t\t{{475, 0x0000}, \"Tuff Luck\"},\n\t\t\t{{476, 0x0000}, \"Food Fight\"},\n\t\t\t{{476, 0x3402}, \"Dark Food Fight\"},\n\t\t\t{{477, 0x0000}, \"High Five\"},\n\t\t\t{{478, 0x0000}, \"Krypt King\"},\n\t\t\t{{478, 0x3402}, \"Nitro Krypt King\"},\n\t\t\t{{479, 0x0000}, \"Short Cut\"},\n\t\t\t{{480, 0x0000}, \"Bat Spin\"},\n\t\t\t{{481, 0x0000}, \"Funny Bone\"},\n\t\t\t{{482, 0x0000}, \"Knight Light\"},\n\t\t\t{{483, 0x0000}, \"Spotlight\"},\n\t\t\t{{484, 0x0000}, \"Knight Mare\"},\n\t\t\t{{485, 0x0000}, \"Blackout\"},\n\t\t\t{{502, 0x0000}, \"Bop\"},\n\t\t\t{{505, 0x0000}, \"Terrabite\"},\n\t\t\t{{506, 0x0000}, \"Breeze\"},\n\t\t\t{{508, 0x0000}, \"Pet Vac\"},\n\t\t\t{{508, 0x3402}, \"Power Punch Pet Vac\"},\n\t\t\t{{507, 0x0000}, \"Weeruptor\"},\n\t\t\t{{507, 0x3402}, \"Eggcellent Weeruptor\"},\n\t\t\t{{509, 0x0000}, \"Small Fry\"},\n\t\t\t{{510, 0x0000}, \"Drobit\"},\n\t\t\t{{519, 0x0000}, \"Trigger Snappy\"},\n\t\t\t{{526, 0x0000}, \"Whisper Elf\"},\n\t\t\t{{540, 0x0000}, \"Barkley\"},\n\t\t\t{{540, 0x3402}, \"Gnarly Barkley\"},\n\t\t\t{{541, 0x0000}, \"Thumpling\"},\n\t\t\t{{514, 0x0000}, \"Gill Runt\"},\n\t\t\t{{542, 0x0000}, \"Mini-Jini\"},\n\t\t\t{{503, 0x0000}, \"Spry\"},\n\t\t\t{{504, 0x0000}, \"Hijinx\"},\n\t\t\t{{543, 0x0000}, \"Eye Small\"},\n\t\t\t{{601, 0x0000}, \"King Pen\"},\n\t\t\t{{602, 0x0000}, \"Tri-Tip\"},\n\t\t\t{{603, 0x0000}, \"Chopscotch\"},\n\t\t\t{{604, 0x0000}, \"Boom Bloom\"},\n\t\t\t{{605, 0x0000}, \"Pit Boss\"},\n\t\t\t{{606, 0x0000}, \"Barbella\"},\n\t\t\t{{607, 0x0000}, \"Air Strike\"},\n\t\t\t{{608, 0x0000}, \"Ember\"},\n\t\t\t{{609, 0x0000}, \"Ambush\"},\n\t\t\t{{610, 0x0000}, \"Dr. Krankcase\"},\n\t\t\t{{611, 0x0000}, \"Hood Sickle\"},\n\t\t\t{{612, 0x0000}, \"Tae Kwon Crow\"},\n\t\t\t{{613, 0x0000}, \"Golden Queen\"},\n\t\t\t{{614, 0x0000}, \"Wolfgang\"},\n\t\t\t{{615, 0x0000}, \"Pain-Yatta\"},\n\t\t\t{{616, 0x0000}, \"Mysticat\"},\n\t\t\t{{617, 0x0000}, \"Starcast\"},\n\t\t\t{{618, 0x0000}, \"Buckshot\"},\n\t\t\t{{619, 0x0000}, \"Aurora\"},\n\t\t\t{{620, 0x0000}, \"Flare Wolf\"},\n\t\t\t{{621, 0x0000}, \"Chompy Mage\"},\n\t\t\t{{622, 0x0000}, \"Bad Juju\"},\n\t\t\t{{623, 0x0000}, \"Grave Clobber\"},\n\t\t\t{{624, 0x0000}, \"Blaster-Tron\"},\n\t\t\t{{625, 0x0000}, \"Ro-Bow\"},\n\t\t\t{{626, 0x0000}, \"Chain Reaction\"},\n\t\t\t{{627, 0x0000}, \"Kaos\"},\n\t\t\t{{628, 0x0000}, \"Wild Storm\"},\n\t\t\t{{629, 0x0000}, \"Tidepool\"},\n\t\t\t{{630, 0x0000}, \"Crash Bandicoot\"},\n\t\t\t{{631, 0x0000}, \"Dr. Neo Cortex\"},\n\t\t\t{{1000, 0x0000}, \"Boom Jet (Bottom)\"},\n\t\t\t{{1001, 0x0000}, \"Free Ranger (Bottom)\"},\n\t\t\t{{1001, 0x2403}, \"Legendary Free Ranger (Bottom)\"},\n\t\t\t{{1002, 0x0000}, \"Rubble Rouser (Bottom)\"},\n\t\t\t{{1003, 0x0000}, \"Doom Stone (Bottom)\"},\n\t\t\t{{1004, 0x0000}, \"Blast Zone (Bottom)\"},\n\t\t\t{{1004, 0x2402}, \"Dark Blast Zone (Bottom)\"},\n\t\t\t{{1005, 0x0000}, \"Fire Kraken (Bottom)\"},\n\t\t\t{{1005, 0x2402}, \"Jade Fire Kraken (Bottom)\"},\n\t\t\t{{1006, 0x0000}, \"Stink Bomb (Bottom)\"},\n\t\t\t{{1007, 0x0000}, \"Grilla Drilla (Bottom)\"},\n\t\t\t{{1008, 0x0000}, \"Hoot Loop (Bottom)\"},\n\t\t\t{{1008, 0x2402}, \"Enchanted Hoot Loop (Bottom)\"},\n\t\t\t{{1009, 0x0000}, \"Trap Shadow (Bottom)\"},\n\t\t\t{{1010, 0x0000}, \"Magna Charge (Bottom)\"},\n\t\t\t{{1010, 0x2402}, \"Nitro Magna Charge (Bottom)\"},\n\t\t\t{{1011, 0x0000}, \"Spy Rise (Bottom)\"},\n\t\t\t{{1012, 0x0000}, \"Night Shift (Bottom)\"},\n\t\t\t{{1012, 0x2403}, \"Legendary Night Shift (Bottom)\"},\n\t\t\t{{1013, 0x0000}, \"Rattle Shake (Bottom)\"},\n\t\t\t{{1013, 0x2402}, \"Quick Draw Rattle Shake (Bottom)\"},\n\t\t\t{{1014, 0x0000}, \"Freeze Blade (Bottom)\"},\n\t\t\t{{1014, 0x2402}, \"Nitro Freeze Blade (Bottom)\"},\n\t\t\t{{1015, 0x0000}, \"Wash Buckler (Bottom)\"},\n\t\t\t{{1015, 0x2402}, \"Dark Wash Buckler (Bottom)\"},\n\t\t\t{{2000, 0x0000}, \"Boom Jet (Top)\"},\n\t\t\t{{2001, 0x0000}, \"Free Ranger (Top)\"},\n\t\t\t{{2001, 0x2403}, \"Legendary Free Ranger (Top)\"},\n\t\t\t{{2002, 0x0000}, \"Rubble Rouser (Top)\"},\n\t\t\t{{2003, 0x0000}, \"Doom Stone (Top)\"},\n\t\t\t{{2004, 0x0000}, \"Blast Zone (Top)\"},\n\t\t\t{{2004, 0x2402}, \"Dark Blast Zone (Top)\"},\n\t\t\t{{2005, 0x0000}, \"Fire Kraken (Top)\"},\n\t\t\t{{2005, 0x2402}, \"Jade Fire Kraken (Top)\"},\n\t\t\t{{2006, 0x0000}, \"Stink Bomb (Top)\"},\n\t\t\t{{2007, 0x0000}, \"Grilla Drilla (Top)\"},\n\t\t\t{{2008, 0x0000}, \"Hoot Loop (Top)\"},\n\t\t\t{{2008, 0x2402}, \"Enchanted Hoot Loop (Top)\"},\n\t\t\t{{2009, 0x0000}, \"Trap Shadow (Top)\"},\n\t\t\t{{2010, 0x0000}, \"Magna Charge (Top)\"},\n\t\t\t{{2010, 0x2402}, \"Nitro Magna Charge (Top)\"},\n\t\t\t{{2011, 0x0000}, \"Spy Rise (Top)\"},\n\t\t\t{{2012, 0x0000}, \"Night Shift (Top)\"},\n\t\t\t{{2012, 0x2403}, \"Legendary Night Shift (Top)\"},\n\t\t\t{{2013, 0x0000}, \"Rattle Shake (Top)\"},\n\t\t\t{{2013, 0x2402}, \"Quick Draw Rattle Shake (Top)\"},\n\t\t\t{{2014, 0x0000}, \"Freeze Blade (Top)\"},\n\t\t\t{{2014, 0x2402}, \"Nitro Freeze Blade (Top)\"},\n\t\t\t{{2015, 0x0000}, \"Wash Buckler (Top)\"},\n\t\t\t{{2015, 0x2402}, \"Dark Wash Buckler (Top)\"},\n\t\t\t{{3000, 0x0000}, \"Scratch\"},\n\t\t\t{{3001, 0x0000}, \"Pop Thorn\"},\n\t\t\t{{3002, 0x0000}, \"Slobber Tooth\"},\n\t\t\t{{3002, 0x2402}, \"Dark Slobber Tooth\"},\n\t\t\t{{3003, 0x0000}, \"Scorp\"},\n\t\t\t{{3004, 0x0000}, \"Fryno\"},\n\t\t\t{{3004, 0x3805}, \"Hog Wild Fryno\"},\n\t\t\t{{3005, 0x0000}, \"Smolderdash\"},\n\t\t\t{{3005, 0x2206}, \"LightCore Smolderdash\"},\n\t\t\t{{3006, 0x0000}, \"Bumble Blast\"},\n\t\t\t{{3006, 0x2402}, \"Jolly Bumble Blast\"},\n\t\t\t{{3006, 0x2206}, \"LightCore Bumble Blast\"},\n\t\t\t{{3007, 0x0000}, \"Zoo Lou\"},\n\t\t\t{{3007, 0x2403}, \"Legendary Zoo Lou\"},\n\t\t\t{{3008, 0x0000}, \"Dune Bug\"},\n\t\t\t{{3009, 0x0000}, \"Star Strike\"},\n\t\t\t{{3009, 0x2602}, \"Enchanted Star Strike\"},\n\t\t\t{{3009, 0x2206}, \"LightCore Star Strike\"},\n\t\t\t{{3010, 0x0000}, \"Countdown\"},\n\t\t\t{{3010, 0x2402}, \"Kickoff Countdown\"},\n\t\t\t{{3010, 0x2206}, \"LightCore Countdown\"},\n\t\t\t{{3011, 0x0000}, \"Wind Up\"},\n\t\t\t{{3011, 0x2404}, \"Gear Head VVind Up\"},\n\t\t\t{{3012, 0x0000}, \"Roller Brawl\"},\n\t\t\t{{3013, 0x0000}, \"Grim Creeper\"},\n\t\t\t{{3013, 0x2603}, \"Legendary Grim Creeper\"},\n\t\t\t{{3013, 0x2206}, \"LightCore Grim Creeper\"},\n\t\t\t{{3014, 0x0000}, \"Rip Tide\"},\n\t\t\t{{3015, 0x0000}, \"Punk Shock\"},\n\t\t\t{{3200, 0x0000}, \"Battle Hammer\"},\n\t\t\t{{3201, 0x0000}, \"Sky Diamond\"},\n\t\t\t{{3202, 0x0000}, \"Platinum Sheep\"},\n\t\t\t{{3203, 0x0000}, \"Groove Machine\"},\n\t\t\t{{3204, 0x0000}, \"UFO Hat\"},\n\t\t\t{{3300, 0x0000}, \"Sheep Wreck Island\"},\n\t\t\t{{3301, 0x0000}, \"Tower of Time\"},\n\t\t\t{{3302, 0x0000}, \"Fiery Forge\"},\n\t\t\t{{3303, 0x0000}, \"Arkeyan Crossbow\"},\n\t\t\t{{3220, 0x0000}, \"Jet Stream\"},\n\t\t\t{{3221, 0x0000}, \"Tomb Buggy\"},\n\t\t\t{{3222, 0x0000}, \"Reef Ripper\"},\n\t\t\t{{3223, 0x0000}, \"Burn Cycle\"},\n\t\t\t{{3224, 0x0000}, \"Hot Streak\"},\n\t\t\t{{3224, 0x4402}, \"Dark Hot Streak\"},\n\t\t\t{{3224, 0x4004}, \"E3 Hot Streak\"},\n\t\t\t{{3224, 0x441E}, \"Golden Hot Streak\"},\n\t\t\t{{3225, 0x0000}, \"Shark Tank\"},\n\t\t\t{{3226, 0x0000}, \"Thump Truck\"},\n\t\t\t{{3227, 0x0000}, \"Crypt Crusher\"},\n\t\t\t{{3228, 0x0000}, \"Stealth Stinger\"},\n\t\t\t{{3228, 0x4402}, \"Nitro Stealth Stinger\"},\n\t\t\t{{3231, 0x0000}, \"Dive Bomber\"},\n\t\t\t{{3231, 0x4402}, \"Spring Ahead Dive Bomber\"},\n\t\t\t{{3232, 0x0000}, \"Sky Slicer\"},\n\t\t\t{{3233, 0x0000}, \"Clown Cruiser (Nintendo Only)\"},\n\t\t\t{{3233, 0x4402}, \"Dark Clown Cruiser (Nintendo Only)\"},\n\t\t\t{{3234, 0x0000}, \"Gold Rusher\"},\n\t\t\t{{3234, 0x4402}, \"Power Blue Gold Rusher\"},\n\t\t\t{{3235, 0x0000}, \"Shield Striker\"},\n\t\t\t{{3236, 0x0000}, \"Sun Runner\"},\n\t\t\t{{3236, 0x4403}, \"Legendary Sun Runner\"},\n\t\t\t{{3237, 0x0000}, \"Sea Shadow\"},\n\t\t\t{{3237, 0x4402}, \"Dark Sea Shadow\"},\n\t\t\t{{3238, 0x0000}, \"Splatter Splasher\"},\n\t\t\t{{3238, 0x4402}, \"Power Blue Splatter Splasher\"},\n\t\t\t{{3239, 0x0000}, \"Soda Skimmer\"},\n\t\t\t{{3239, 0x4402}, \"Nitro Soda Skimmer\"},\n\t\t\t{{3240, 0x0000}, \"Barrel Blaster (Nintendo Only)\"},\n\t\t\t{{3240, 0x4402}, \"Dark Barrel Blaster (Nintendo Only)\"},\n\t\t\t{{3241, 0x0000}, \"Buzz Wing\"},\n\t\t\t{{3400, 0x0000}, \"Fiesta\"},\n\t\t\t{{3400, 0x4515}, \"Frightful Fiesta\"},\n\t\t\t{{3401, 0x0000}, \"High Volt\"},\n\t\t\t{{3402, 0x0000}, \"Splat\"},\n\t\t\t{{3402, 0x4502}, \"Power Blue Splat\"},\n\t\t\t{{3406, 0x0000}, \"Stormblade\"},\n\t\t\t{{3411, 0x0000}, \"Smash Hit\"},\n\t\t\t{{3411, 0x4502}, \"Steel Plated Smash Hit\"},\n\t\t\t{{3412, 0x0000}, \"Spitfire\"},\n\t\t\t{{3412, 0x4502}, \"Dark Spitfire\"},\n\t\t\t{{3413, 0x0000}, \"Hurricane Jet Vac\"},\n\t\t\t{{3413, 0x4503}, \"Legendary Hurricane Jet Vac\"},\n\t\t\t{{3414, 0x0000}, \"Double Dare Trigger Happy\"},\n\t\t\t{{3414, 0x4502}, \"Power Blue Double Dare Trigger Happy\"},\n\t\t\t{{3415, 0x0000}, \"Super Shot Stealth Elf\"},\n\t\t\t{{3415, 0x4502}, \"Dark Super Shot Stealth Elf\"},\n\t\t\t{{3416, 0x0000}, \"Shark Shooter Terrafin\"},\n\t\t\t{{3417, 0x0000}, \"Bone Bash Roller Brawl\"},\n\t\t\t{{3417, 0x4503}, \"Legendary Bone Bash Roller Brawl\"},\n\t\t\t{{3420, 0x0000}, \"Big Bubble Pop Fizz\"},\n\t\t\t{{3420, 0x450E}, \"Birthday Bash Big Bubble Pop Fizz\"},\n\t\t\t{{3421, 0x0000}, \"Lava Lance Eruptor\"},\n\t\t\t{{3422, 0x0000}, \"Deep Dive Gill Grunt\"},\n\t\t\t{{3423, 0x0000}, \"Turbo Charge Donkey Kong (Nintendo Only)\"},\n\t\t\t{{3423, 0x4502}, \"Dark Turbo Charge Donkey Kong (Nintendo Only)\"},\n\t\t\t{{3424, 0x0000}, \"Hammer Slam Bowser (Nintendo Only)\"},\n\t\t\t{{3424, 0x4502}, \"Dark Hammer Slam Bowser (Nintendo Only)\"},\n\t\t\t{{3425, 0x0000}, \"Dive-Clops\"},\n\t\t\t{{3425, 0x450E}, \"Missile-Tow Dive-Clops\"},\n\t\t\t{{3426, 0x0000}, \"Astroblast\"},\n\t\t\t{{3426, 0x4503}, \"Legendary Astroblast\"},\n\t\t\t{{3427, 0x0000}, \"Nightfall\"},\n\t\t\t{{3428, 0x0000}, \"Thrillipede\"},\n\t\t\t{{3428, 0x450D}, \"Eggcited Thrillipede\"},\n\t\t\t{{3500, 0x0000}, \"Sky Trophy\"},\n\t\t\t{{3501, 0x0000}, \"Land Trophy\"},\n\t\t\t{{3502, 0x0000}, \"Sea Trophy\"},\n\t\t\t{{3503, 0x0000}, \"Kaos Trophy\"},\n\t};\n\n\tuint16 SkylanderUSB::SkylanderCRC16(uint16 initValue, const uint8* buffer, uint32 size)\n\t{\n\t\tconst unsigned short CRC_CCITT_TABLE[256] = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64,\n\t\t\t\t\t\t\t\t\t\t\t\t\t 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};\n\n\t\tuint16 crc = initValue;\n\n\t\tfor (uint32 i = 0; i < size; i++)\n\t\t{\n\t\t\tconst uint16 tmp = (crc >> 8) ^ buffer[i];\n\t\t\tcrc = (crc << 8) ^ CRC_CCITT_TABLE[tmp];\n\t\t}\n\n\t\treturn crc;\n\t}\n\tSkylanderPortalDevice::SkylanderPortalDevice()\n\t\t: Device(0x1430, 0x0150, 1, 2, 0)\n\t{\n\t\tm_IsOpened = false;\n\t}\n\n\tbool SkylanderPortalDevice::Open()\n\t{\n\t\tif (!IsOpened())\n\t\t{\n\t\t\tm_IsOpened = true;\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid SkylanderPortalDevice::Close()\n\t{\n\t\tif (IsOpened())\n\t\t{\n\t\t\tm_IsOpened = false;\n\t\t}\n\t}\n\n\tbool SkylanderPortalDevice::IsOpened()\n\t{\n\t\treturn m_IsOpened;\n\t}\n\n\tDevice::ReadResult SkylanderPortalDevice::Read(ReadMessage* message)\n\t{\n\t\tmemcpy(message->data, g_skyportal.GetStatus().data(), message->length);\n\t\tmessage->bytesRead = message->length;\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(10));\n\t\treturn Device::ReadResult::Success;\n\t}\n\n\tDevice::WriteResult SkylanderPortalDevice::Write(WriteMessage* message)\n\t{\n\t\tif (message->length != 64) {\n\t\t\tcemu_assert_error();\n\t\t}\n\n\t\tif (!g_portalAudio)\n\t\t{\n\t\t\t// Portal audio is mono channel, 16 bit audio.\n\t\t\t// Audio is unsigned 16 bit, supplied as 64 bytes which is 32 samples per block\n\t\t\tg_portalAudio = IAudioAPI::CreateDeviceFromConfig(IAudioAPI::AudioType::Portal, 8000, 32, 16);\n\t\t}\n\t\tstd::array<sint16, 32> mono_samples;\n\t\tfor (unsigned int i = 0; i < mono_samples.size(); ++i)\n\t\t{\n\t\t\tsint16 sample = static_cast<uint16>(message->data[i * 2 + 1]) << 8 | static_cast<uint16>(message->data[i * 2]);\n\t\t\tmono_samples[i] = sample;\n\t\t}\n\t\tif (g_portalAudio)\n\t\t{\n\t\t\tg_portalAudio->FeedBlock(mono_samples.data());\n\t\t}\n\t\tmessage->bytesWritten = message->length;\n\t\treturn Device::WriteResult::Success;\n\t}\n\n\tbool SkylanderPortalDevice::GetDescriptor(uint8 descType,\n\t\t\t\t\t\t\t\t\t\t\t  uint8 descIndex,\n\t\t\t\t\t\t\t\t\t\t\t  uint16 lang,\n\t\t\t\t\t\t\t\t\t\t\t  uint8* output,\n\t\t\t\t\t\t\t\t\t\t\t  uint32 outputMaxLength)\n\t{\n\t\tuint8 configurationDescriptor[0x29];\n\n\t\tuint8* currentWritePtr;\n\n\t\t// configuration descriptor\n\t\tcurrentWritePtr = configurationDescriptor + 0;\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 2;\t\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 2) = 0x0029; // wTotalLength\n\t\t*(uint8*)(currentWritePtr + 4) = 1;\t\t\t// bNumInterfaces\n\t\t*(uint8*)(currentWritePtr + 5) = 1;\t\t\t// bConfigurationValue\n\t\t*(uint8*)(currentWritePtr + 6) = 0;\t\t\t// iConfiguration\n\t\t*(uint8*)(currentWritePtr + 7) = 0x80;\t\t// bmAttributes\n\t\t*(uint8*)(currentWritePtr + 8) = 0xFA;\t\t// MaxPower\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// interface descriptor\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t   // bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x04; // bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 2) = 0;\t   // bInterfaceNumber\n\t\t*(uint8*)(currentWritePtr + 3) = 0;\t   // bAlternateSetting\n\t\t*(uint8*)(currentWritePtr + 4) = 2;\t   // bNumEndpoints\n\t\t*(uint8*)(currentWritePtr + 5) = 3;\t   // bInterfaceClass\n\t\t*(uint8*)(currentWritePtr + 6) = 0;\t   // bInterfaceSubClass\n\t\t*(uint8*)(currentWritePtr + 7) = 0;\t   // bInterfaceProtocol\n\t\t*(uint8*)(currentWritePtr + 8) = 0;\t   // iInterface\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// HID descriptor\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x21;\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 2) = 0x0111; // bcdHID\n\t\t*(uint8*)(currentWritePtr + 4) = 0x00;\t\t// bCountryCode\n\t\t*(uint8*)(currentWritePtr + 5) = 0x01;\t\t// bNumDescriptors\n\t\t*(uint8*)(currentWritePtr + 6) = 0x22;\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 7) = 0x001D; // wDescriptorLength\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// endpoint descriptor 1\n\t\t*(uint8*)(currentWritePtr + 0) = 7;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x05;\t\t// bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 2) = 0x81;\t\t// bEndpointAddress\n\t\t*(uint8*)(currentWritePtr + 3) = 0x03;\t\t// bmAttributes\n\t\t*(uint16be*)(currentWritePtr + 4) = 0x0040; // wMaxPacketSize\n\t\t*(uint8*)(currentWritePtr + 6) = 0x01;\t\t// bInterval\n\t\tcurrentWritePtr = currentWritePtr + 7;\n\t\t// endpoint descriptor 2\n\t\t*(uint8*)(currentWritePtr + 0) = 7;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x05;\t\t// bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 2) = 0x02;\t\t// bEndpointAddress\n\t\t*(uint8*)(currentWritePtr + 3) = 0x03;\t\t// bmAttributes\n\t\t*(uint16be*)(currentWritePtr + 4) = 0x0040; // wMaxPacketSize\n\t\t*(uint8*)(currentWritePtr + 6) = 0x01;\t\t// bInterval\n\t\tcurrentWritePtr = currentWritePtr + 7;\n\n\t\tcemu_assert_debug((currentWritePtr - configurationDescriptor) == 0x29);\n\n\t\tmemcpy(output, configurationDescriptor,\n\t\t\t   std::min<uint32>(outputMaxLength, sizeof(configurationDescriptor)));\n\t\treturn true;\n\t}\n\n\tbool SkylanderPortalDevice::SetIdle(uint8 ifIndex,\n\t\t\t\t\t\t\t\t\t\tuint8 reportId,\n\t\t\t\t\t\t\t\t\t\tuint8 duration)\n\t{\n\t\treturn true;\n\t}\n\n\tbool SkylanderPortalDevice::SetProtocol(uint8 ifIndex, uint8 protocol)\n\t{\n\t\treturn true;\n\t}\n\n\tbool SkylanderPortalDevice::SetReport(ReportMessage* message)\n\t{\n\t\tg_skyportal.ControlTransfer(message->data, message->length);\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\treturn true;\n\t}\n\n\tvoid SkylanderUSB::ControlTransfer(uint8* buf, uint32 length)\n\t{\n\t\tstd::array<uint8, 64> interruptResponse = {};\n\t\tswitch (buf[0])\n\t\t{\n\t\tcase 'A':\n\t\t{\n\t\t\tinterruptResponse = {buf[0], buf[1], 0xFF, 0x77};\n\t\t\tg_skyportal.Activate();\n\t\t\tbreak;\n\t\t}\n\t\tcase 'C':\n\t\t{\n\t\t\tg_skyportal.SetLeds(0x01, buf[1], buf[2], buf[3]);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'J':\n\t\t{\n\t\t\tg_skyportal.SetLeds(buf[1], buf[2], buf[3], buf[4]);\n\t\t\tinterruptResponse = {buf[0]};\n\t\t\tbreak;\n\t\t}\n\t\tcase 'L':\n\t\t{\n\t\t\tuint8 side = buf[1];\n\t\t\tif (side == 0x02)\n\t\t\t{\n\t\t\t\tside = 0x04;\n\t\t\t}\n\t\t\tg_skyportal.SetLeds(side, buf[2], buf[3], buf[4]);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'M':\n\t\t{\n\t\t\tinterruptResponse = {buf[0], buf[1], 0x00, 0x19};\n\t\t\tbreak;\n\t\t}\n\t\tcase 'Q':\n\t\t{\n\t\t\tconst uint8 skyNum = buf[1] & 0xF;\n\t\t\tconst uint8 block = buf[2];\n\t\t\tg_skyportal.QueryBlock(skyNum, block, interruptResponse.data());\n\t\t\tbreak;\n\t\t}\n\t\tcase 'R':\n\t\t{\n\t\t\tinterruptResponse = {buf[0], 0x02, 0x1b};\n\t\t\tbreak;\n\t\t}\n\t\tcase 'S':\n\t\tcase 'V':\n\t\t{\n\t\t\t// No response needed\n\t\t\tbreak;\n\t\t}\n\t\tcase 'W':\n\t\t{\n\t\t\tconst uint8 skyNum = buf[1] & 0xF;\n\t\t\tconst uint8 block = buf[2];\n\t\t\tg_skyportal.WriteBlock(skyNum, block, &buf[3], interruptResponse.data());\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tcemu_assert_error();\n\t\t\tbreak;\n\t\t}\n\t\tif (interruptResponse[0] != 0)\n\t\t{\n\t\t\tstd::lock_guard lock(m_queryMutex);\n\t\t\tm_queries.push(interruptResponse);\n\t\t}\n\t}\n\n\tvoid SkylanderUSB::Activate()\n\t{\n\t\tstd::lock_guard lock(m_skyMutex);\n\t\tif (m_activated)\n\t\t{\n\t\t\t// If the portal was already active no change is needed\n\t\t\treturn;\n\t\t}\n\n\t\t// If not we need to advertise change to all the figures present on the portal\n\t\tfor (auto& s : m_skylanders)\n\t\t{\n\t\t\tif (s.status & 1)\n\t\t\t{\n\t\t\t\ts.queuedStatus.push(3);\n\t\t\t\ts.queuedStatus.push(1);\n\t\t\t}\n\t\t}\n\n\t\tm_activated = true;\n\t}\n\n\tvoid SkylanderUSB::Deactivate()\n\t{\n\t\tstd::lock_guard lock(m_skyMutex);\n\n\t\tfor (auto& s : m_skylanders)\n\t\t{\n\t\t\t// check if at the end of the updates there would be a figure on the portal\n\t\t\tif (!s.queuedStatus.empty())\n\t\t\t{\n\t\t\t\ts.status = s.queuedStatus.back();\n\t\t\t\ts.queuedStatus = std::queue<uint8>();\n\t\t\t}\n\n\t\t\ts.status &= 1;\n\t\t}\n\n\t\tm_activated = false;\n\t}\n\n\tvoid SkylanderUSB::SetLeds(uint8 side, uint8 r, uint8 g, uint8 b)\n\t{\n\t\tstd::lock_guard lock(m_skyMutex);\n\t\tif (side == 0x00)\n\t\t{\n\t\t\tm_colorRight.red = r;\n\t\t\tm_colorRight.green = g;\n\t\t\tm_colorRight.blue = b;\n\t\t}\n\t\telse if (side == 0x01)\n\t\t{\n\t\t\tm_colorRight.red = r;\n\t\t\tm_colorRight.green = g;\n\t\t\tm_colorRight.blue = b;\n\n\t\t\tm_colorLeft.red = r;\n\t\t\tm_colorLeft.green = g;\n\t\t\tm_colorLeft.blue = b;\n\t\t}\n\t\telse if (side == 0x02)\n\t\t{\n\t\t\tm_colorLeft.red = r;\n\t\t\tm_colorLeft.green = g;\n\t\t\tm_colorLeft.blue = b;\n\t\t}\n\t\telse if (side == 0x03)\n\t\t{\n\t\t\tm_colorTrap.red = r;\n\t\t\tm_colorTrap.green = g;\n\t\t\tm_colorTrap.blue = b;\n\t\t}\n\t}\n\n\tuint8 SkylanderUSB::LoadSkylander(uint8* buf, std::unique_ptr<FileStream> file)\n\t{\n\t\tstd::lock_guard lock(m_skyMutex);\n\n\t\tuint32 skySerial = 0;\n\t\tfor (int i = 3; i > -1; i--)\n\t\t{\n\t\t\tskySerial <<= 8;\n\t\t\tskySerial |= buf[i];\n\t\t}\n\t\tuint8 foundSlot = 0xFF;\n\n\t\t// mimics spot retaining on the portal\n\t\tfor (auto i = 0; i < 16; i++)\n\t\t{\n\t\t\tif ((m_skylanders[i].status & 1) == 0)\n\t\t\t{\n\t\t\t\tif (m_skylanders[i].lastId == skySerial)\n\t\t\t\t{\n\t\t\t\t\tfoundSlot = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (i < foundSlot)\n\t\t\t\t{\n\t\t\t\t\tfoundSlot = i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (foundSlot != 0xFF)\n\t\t{\n\t\t\tauto& skylander = m_skylanders[foundSlot];\n\t\t\tmemcpy(skylander.data.data(), buf, skylander.data.size());\n\t\t\tskylander.skyFile = std::move(file);\n\t\t\tskylander.status = Skylander::ADDED;\n\t\t\tskylander.queuedStatus.push(Skylander::ADDED);\n\t\t\tskylander.queuedStatus.push(Skylander::READY);\n\t\t\tskylander.lastId = skySerial;\n\t\t}\n\t\treturn foundSlot;\n\t}\n\n\tbool SkylanderUSB::RemoveSkylander(uint8 skyNum)\n\t{\n\t\tstd::lock_guard lock(m_skyMutex);\n\t\tauto& thesky = m_skylanders[skyNum];\n\n\t\tif (thesky.status & 1)\n\t\t{\n\t\t\tthesky.status = 2;\n\t\t\tthesky.queuedStatus.push(2);\n\t\t\tthesky.queuedStatus.push(0);\n\t\t\tthesky.Save();\n\t\t\tthesky.skyFile.reset();\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tbool SkylanderUSB::CreateSkylander(fs::path pathName, uint16 skyId, uint16 skyVar)\n\t{\n\t\tFileStream* skyFile(FileStream::createFile2(pathName));\n\t\tif (!skyFile)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tstd::array<uint8, SKY_FIGURE_SIZE> data{};\n\n\t\tuint32 first_block = 0x690F0F0F;\n\t\tuint32 other_blocks = 0x69080F7F;\n\t\tmemcpy(&data[0x36], &first_block, sizeof(first_block));\n\t\tfor (size_t index = 1; index < 0x10; index++)\n\t\t{\n\t\t\tmemcpy(&data[(index * 0x40) + 0x36], &other_blocks, sizeof(other_blocks));\n\t\t}\n\t\tstd::random_device rd;\n\t\tstd::mt19937 mt(rd());\n\t\tstd::uniform_int_distribution<int> dist(0, 255);\n\t\tdata[0] = dist(mt);\n\t\tdata[1] = dist(mt);\n\t\tdata[2] = dist(mt);\n\t\tdata[3] = dist(mt);\n\t\tdata[4] = data[0] ^ data[1] ^ data[2] ^ data[3];\n\t\tdata[5] = 0x81;\n\t\tdata[6] = 0x01;\n\t\tdata[7] = 0x0F;\n\n\t\tmemcpy(&data[0x10], &skyId, sizeof(skyId));\n\t\tmemcpy(&data[0x1C], &skyVar, sizeof(skyVar));\n\n\t\tuint16 crc = nsyshid::g_skyportal.SkylanderCRC16(0xFFFF, data.data(), 0x1E);\n\n\t\tmemcpy(&data[0x1E], &crc, sizeof(crc));\n\n\t\tskyFile->writeData(data.data(), data.size());\n\n\t\tdelete skyFile;\n\n\t\treturn true;\n\t}\n\n\tvoid SkylanderUSB::QueryBlock(uint8 skyNum, uint8 block, uint8* replyBuf)\n\t{\n\t\tstd::lock_guard lock(m_skyMutex);\n\n\t\tconst auto& skylander = m_skylanders[skyNum];\n\n\t\treplyBuf[0] = 'Q';\n\t\treplyBuf[2] = block;\n\t\tif (skylander.status & 1)\n\t\t{\n\t\t\treplyBuf[1] = (0x10 | skyNum);\n\t\t\tmemcpy(replyBuf + 3, skylander.data.data() + (16 * block), 16);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treplyBuf[1] = skyNum;\n\t\t}\n\t}\n\n\tvoid SkylanderUSB::WriteBlock(uint8 skyNum, uint8 block,\n\t\t\t\t\t\t\t\t  const uint8* toWriteBuf, uint8* replyBuf)\n\t{\n\t\tstd::lock_guard lock(m_skyMutex);\n\n\t\tauto& skylander = m_skylanders[skyNum];\n\n\t\treplyBuf[0] = 'W';\n\t\treplyBuf[2] = block;\n\n\t\tif (skylander.status & 1)\n\t\t{\n\t\t\treplyBuf[1] = (0x10 | skyNum);\n\t\t\tmemcpy(skylander.data.data() + (block * 16), toWriteBuf, 16);\n\t\t\tskylander.Save();\n\t\t}\n\t\telse\n\t\t{\n\t\t\treplyBuf[1] = skyNum;\n\t\t}\n\t}\n\n\tstd::array<uint8, 64> SkylanderUSB::GetStatus()\n\t{\n\t\tstd::lock_guard lock(m_queryMutex);\n\t\tstd::array<uint8, 64> interruptResponse = {};\n\n\t\tif (!m_queries.empty())\n\t\t{\n\t\t\tinterruptResponse = m_queries.front();\n\t\t\tm_queries.pop();\n\t\t\t// This needs to happen after ~22 milliseconds\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint32 status = 0;\n\t\t\tuint8 active = 0x00;\n\t\t\tif (m_activated)\n\t\t\t{\n\t\t\t\tactive = 0x01;\n\t\t\t}\n\n\t\t\tfor (int i = 16 - 1; i >= 0; i--)\n\t\t\t{\n\t\t\t\tauto& s = m_skylanders[i];\n\n\t\t\t\tif (!s.queuedStatus.empty())\n\t\t\t\t{\n\t\t\t\t\ts.status = s.queuedStatus.front();\n\t\t\t\t\ts.queuedStatus.pop();\n\t\t\t\t}\n\t\t\t\tstatus <<= 2;\n\t\t\t\tstatus |= s.status;\n\t\t\t}\n\t\t\tinterruptResponse = {0x53, 0x00, 0x00, 0x00, 0x00, m_interruptCounter++,\n\t\t\t\t\t\t\t\t active, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t\t\t\t\t\t\t 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t\t\t\t\t\t\t 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t\t\t\t\t\t\t 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t\t\t\t\t\t\t\t 0x00, 0x00};\n\t\t\tmemcpy(&interruptResponse[1], &status, sizeof(status));\n\t\t}\n\t\treturn interruptResponse;\n\t}\n\n\tstd::string SkylanderUSB::FindSkylander(uint16 skyId, uint16 skyVar)\n\t{\n\t\tfor (const auto& it : GetListSkylanders())\n\t\t{\n\t\t\tif (it.first.first == skyId && it.first.second == skyVar)\n\t\t\t{\n\t\t\t\treturn it.second;\n\t\t\t}\n\t\t}\n\t\treturn fmt::format(\"Unknown ({} {})\", skyId, skyVar);\n\t}\n\n\tstd::map<const std::pair<const uint16, const uint16>, const char*> SkylanderUSB::GetListSkylanders()\n\t{\n\t\treturn s_listSkylanders;\n\t}\n\n\tvoid SkylanderUSB::Skylander::Save()\n\t{\n\t\tif (!skyFile)\n\t\t\treturn;\n\n\t\tskyFile->SetPosition(0);\n\t\tskyFile->writeData(data.data(), data.size());\n\t}\n} // namespace nsyshid"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/Skylander.h",
    "content": "#pragma once\n\n#include <mutex>\n\n#include \"nsyshid.h\"\n#include \"Backend.h\"\n\n#include \"Common/FileStream.h\"\n\nnamespace nsyshid\n{\n\tclass SkylanderPortalDevice final : public Device {\n\t  public:\n\t\tSkylanderPortalDevice();\n\t\t~SkylanderPortalDevice() = default;\n\n\t\tbool Open() override;\n\n\t\tvoid Close() override;\n\n\t\tbool IsOpened() override;\n\n\t\tReadResult Read(ReadMessage* message) override;\n\n\t\tWriteResult Write(WriteMessage* message) override;\n\n\t\tbool GetDescriptor(uint8 descType,\n\t\t\t\t\t\t   uint8 descIndex,\n\t\t\t\t\t\t   uint16 lang,\n\t\t\t\t\t\t   uint8* output,\n\t\t\t\t\t\t   uint32 outputMaxLength) override;\n\n\t\tbool SetIdle(uint8 ifIndex,\n\t\t\t\t\t uint8 reportId,\n\t\t\t\t\t uint8 duration) override;\n\n\t\tbool SetProtocol(uint8 ifIndex, uint8 protocol) override;\n\n\t\tbool SetReport(ReportMessage* message) override;\n\n\t  private:\n\t\tbool m_IsOpened;\n\t};\n\n\tconstexpr uint16 SKY_BLOCK_COUNT = 0x40;\n\tconstexpr uint16 SKY_BLOCK_SIZE = 0x10;\n\tconstexpr uint16 SKY_FIGURE_SIZE = SKY_BLOCK_COUNT * SKY_BLOCK_SIZE;\n\tconstexpr uint8 MAX_SKYLANDERS = 16;\n\n\tclass SkylanderUSB {\n\t  public:\n\t\tstruct Skylander final\n\t\t{\n\t\t\tstd::unique_ptr<FileStream> skyFile;\n\t\t\tuint8 status = 0;\n\t\t\tstd::queue<uint8> queuedStatus;\n\t\t\tstd::array<uint8, SKY_FIGURE_SIZE> data{};\n\t\t\tuint32 lastId = 0;\n\t\t\tvoid Save();\n\n\t\t\tenum : uint8\n\t\t\t{\n\t\t\t\tREMOVED = 0,\n\t\t\t\tREADY = 1,\n\t\t\t\tREMOVING = 2,\n\t\t\t\tADDED = 3\n\t\t\t};\n\t\t};\n\n\t\tstruct SkylanderLEDColor final\n\t\t{\n\t\t\tuint8 red = 0;\n\t\t\tuint8 green = 0;\n\t\t\tuint8 blue = 0;\n\t\t};\n\n\t\tvoid ControlTransfer(uint8* buf, uint32 length);\n\n\t\tvoid Activate();\n\t\tvoid Deactivate();\n\t\tvoid SetLeds(uint8 side, uint8 r, uint8 g, uint8 b);\n\n\t\tstd::array<uint8, 64> GetStatus();\n\t\tvoid QueryBlock(uint8 skyNum, uint8 block, uint8* replyBuf);\n\t\tvoid WriteBlock(uint8 skyNum, uint8 block, const uint8* toWriteBuf,\n\t\t\t\t\t\tuint8* replyBuf);\n\n\t\tuint8 LoadSkylander(uint8* buf, std::unique_ptr<FileStream> file);\n\t\tbool RemoveSkylander(uint8 skyNum);\n\t\tbool CreateSkylander(fs::path pathName, uint16 skyId, uint16 skyVar);\n\t\tuint16 SkylanderCRC16(uint16 initValue, const uint8* buffer, uint32 size);\n\t\tstatic std::map<const std::pair<const uint16, const uint16>, const char*> GetListSkylanders();\n\t\tstd::string FindSkylander(uint16 skyId, uint16 skyVar);\n\n\t  protected:\n\t\tstd::mutex m_skyMutex;\n\t\tstd::mutex m_queryMutex;\n\t\tstd::array<Skylander, MAX_SKYLANDERS> m_skylanders;\n\n\t  private:\n\t\tstd::queue<std::array<uint8, 64>> m_queries;\n\t\tbool m_activated = true;\n\t\tuint8 m_interruptCounter = 0;\n\t\tSkylanderLEDColor m_colorRight = {};\n\t\tSkylanderLEDColor m_colorLeft = {};\n\t\tSkylanderLEDColor m_colorTrap = {};\n\t};\n\textern SkylanderUSB g_skyportal;\n} // namespace nsyshid"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/SkylanderXbox360.cpp",
    "content": "#include \"SkylanderXbox360.h\"\n\nnamespace nsyshid\n{\n\tSkylanderXbox360PortalLibusb::SkylanderXbox360PortalLibusb(std::shared_ptr<Device> usbPortal)\n\t\t: Device(0x1430, 0x0150, 1, 2, 0)\n\t{\n\t\tm_IsOpened = false;\n\t\tm_usbPortal = std::static_pointer_cast<backend::libusb::DeviceLibusb>(usbPortal);\n\t}\n\n\tbool SkylanderXbox360PortalLibusb::Open()\n\t{\n\t\treturn m_usbPortal->Open();\n\t}\n\n\tvoid SkylanderXbox360PortalLibusb::Close()\n\t{\n\t\treturn m_usbPortal->Close();\n\t}\n\n\tbool SkylanderXbox360PortalLibusb::IsOpened()\n\t{\n\t\treturn m_usbPortal->IsOpened();\n\t}\n\n\tDevice::ReadResult SkylanderXbox360PortalLibusb::Read(ReadMessage* message)\n\t{\n\t\tstd::vector<uint8> xboxData(std::min<uint32>(32, message->length + sizeof(XBOX_DATA_HEADER)));\n\t\tmemcpy(xboxData.data(), XBOX_DATA_HEADER, sizeof(XBOX_DATA_HEADER));\n\t\tmemcpy(xboxData.data() + sizeof(XBOX_DATA_HEADER), message->data, message->length - sizeof(XBOX_DATA_HEADER));\n\n\t\tReadMessage xboxMessage(xboxData.data(), xboxData.size(), 0);\n\t\tauto result = m_usbPortal->Read(&xboxMessage);\n\n\t\tmemcpy(message->data, xboxData.data() + sizeof(XBOX_DATA_HEADER), message->length);\n\t\tmessage->bytesRead = xboxMessage.bytesRead;\n\n\t\treturn result;\n\t}\n\n\t// Use InterruptTransfer instead of ControlTransfer\n\tbool SkylanderXbox360PortalLibusb::SetReport(ReportMessage* message)\n\t{\n\t\tif (message->data[0] == 'M' && message->data[1] == 0x01) // Enables Speaker\n\t\t\tg72x_init_state(&m_state);\n\n\t\tstd::vector<uint8> xboxData(message->length + sizeof(XBOX_DATA_HEADER));\n\t\tmemcpy(xboxData.data(), XBOX_DATA_HEADER, sizeof(XBOX_DATA_HEADER));\n\t\tmemcpy(xboxData.data() + sizeof(XBOX_DATA_HEADER), message->data, message->length);\n\n\t\tWriteMessage xboxMessage(xboxData.data(), xboxData.size(), 0);\n\t\tauto result = m_usbPortal->Write(&xboxMessage);\n\n\t\tmemcpy(message->data, xboxData.data() + sizeof(XBOX_DATA_HEADER), message->length);\n\n\t\treturn result == WriteResult::Success;\n\t}\n\n\tDevice::WriteResult SkylanderXbox360PortalLibusb::Write(WriteMessage* message)\n\t{\n\t\tstd::vector<uint8> audioData(message->data, message->data + message->length);\n\n\t\tstd::vector<uint8_t> xboxAudioData(audioData.size() / 4);\n\t\tfor (size_t i = 0; i < audioData.size(); i += 4)\n\t\t{\n\t\t\tint16_t sample1 = (static_cast<int16_t>(audioData[i + 1]) << 8) | audioData[i];\n\t\t\tint16_t sample2 = (static_cast<int16_t>(audioData[i + 3]) << 8) | audioData[i + 2];\n\n\t\t\tuint8_t encoded1 = g721_encoder(sample1, &m_state) & 0x0F;\n\t\t\tuint8_t encoded2 = g721_encoder(sample2, &m_state) & 0x0F;\n\n\t\t\txboxAudioData[i / 4] = ((encoded2 << 4) | encoded1);\n\t\t}\n\n\t\tstd::vector<uint8> xboxData(xboxAudioData.size() + sizeof(XBOX_AUDIO_DATA_HEADER));\n\t\tmemcpy(xboxData.data(), XBOX_AUDIO_DATA_HEADER, sizeof(XBOX_AUDIO_DATA_HEADER));\n\t\tmemcpy(xboxData.data() + sizeof(XBOX_AUDIO_DATA_HEADER), xboxAudioData.data(), xboxAudioData.size());\n\n\t\tWriteMessage xboxMessage(xboxData.data(), xboxData.size(), 0);\n\t\tauto result = m_usbPortal->Write(&xboxMessage);\n\n\t\tmemcpy(message->data, xboxData.data() + sizeof(XBOX_AUDIO_DATA_HEADER), xboxAudioData.size());\n\t\tmessage->bytesWritten = xboxMessage.bytesWritten - sizeof(XBOX_AUDIO_DATA_HEADER);\n\t\treturn result;\n\t}\n\n\tbool SkylanderXbox360PortalLibusb::GetDescriptor(uint8 descType, uint8 descIndex, uint16 lang, uint8* output, uint32 outputMaxLength)\n\t{\n\t\tuint8 configurationDescriptor[0x29];\n\n\t\tuint8* currentWritePtr;\n\n\t\t// configuration descriptor\n\t\tcurrentWritePtr = configurationDescriptor + 0;\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 2;\t\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 2) = 0x0029; // wTotalLength\n\t\t*(uint8*)(currentWritePtr + 4) = 1;\t\t\t// bNumInterfaces\n\t\t*(uint8*)(currentWritePtr + 5) = 1;\t\t\t// bConfigurationValue\n\t\t*(uint8*)(currentWritePtr + 6) = 0;\t\t\t// iConfiguration\n\t\t*(uint8*)(currentWritePtr + 7) = 0x80;\t\t// bmAttributes\n\t\t*(uint8*)(currentWritePtr + 8) = 0xFA;\t\t// MaxPower\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// interface descriptor\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t   // bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x04; // bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 2) = 0;\t   // bInterfaceNumber\n\t\t*(uint8*)(currentWritePtr + 3) = 0;\t   // bAlternateSetting\n\t\t*(uint8*)(currentWritePtr + 4) = 2;\t   // bNumEndpoints\n\t\t*(uint8*)(currentWritePtr + 5) = 3;\t   // bInterfaceClass\n\t\t*(uint8*)(currentWritePtr + 6) = 0;\t   // bInterfaceSubClass\n\t\t*(uint8*)(currentWritePtr + 7) = 0;\t   // bInterfaceProtocol\n\t\t*(uint8*)(currentWritePtr + 8) = 0;\t   // iInterface\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// HID descriptor\n\t\t*(uint8*)(currentWritePtr + 0) = 9;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x21;\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 2) = 0x0111; // bcdHID\n\t\t*(uint8*)(currentWritePtr + 4) = 0x00;\t\t// bCountryCode\n\t\t*(uint8*)(currentWritePtr + 5) = 0x01;\t\t// bNumDescriptors\n\t\t*(uint8*)(currentWritePtr + 6) = 0x22;\t\t// bDescriptorType\n\t\t*(uint16be*)(currentWritePtr + 7) = 0x001D; // wDescriptorLength\n\t\tcurrentWritePtr = currentWritePtr + 9;\n\t\t// endpoint descriptor 1\n\t\t*(uint8*)(currentWritePtr + 0) = 7;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x05;\t\t// bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 2) = 0x81;\t\t// bEndpointAddress\n\t\t*(uint8*)(currentWritePtr + 3) = 0x03;\t\t// bmAttributes\n\t\t*(uint16be*)(currentWritePtr + 4) = 0x0040; // wMaxPacketSize\n\t\t*(uint8*)(currentWritePtr + 6) = 0x01;\t\t// bInterval\n\t\tcurrentWritePtr = currentWritePtr + 7;\n\t\t// endpoint descriptor 2\n\t\t*(uint8*)(currentWritePtr + 0) = 7;\t\t\t// bLength\n\t\t*(uint8*)(currentWritePtr + 1) = 0x05;\t\t// bDescriptorType\n\t\t*(uint8*)(currentWritePtr + 2) = 0x02;\t\t// bEndpointAddress\n\t\t*(uint8*)(currentWritePtr + 3) = 0x03;\t\t// bmAttributes\n\t\t*(uint16be*)(currentWritePtr + 4) = 0x0040; // wMaxPacketSize\n\t\t*(uint8*)(currentWritePtr + 6) = 0x01;\t\t// bInterval\n\t\tcurrentWritePtr = currentWritePtr + 7;\n\n\t\tcemu_assert_debug((currentWritePtr - configurationDescriptor) == 0x29);\n\n\t\tmemcpy(output, configurationDescriptor,\n\t\t\t   std::min<uint32>(outputMaxLength, sizeof(configurationDescriptor)));\n\t\treturn true;\n\t}\n\n\tbool SkylanderXbox360PortalLibusb::SetIdle(uint8 ifIndex,\n\t\t\t\t\t\t\t\t\t\t\t   uint8 reportId,\n\t\t\t\t\t\t\t\t\t\t\t   uint8 duration)\n\t{\n\t\treturn true;\n\t}\n\n\tbool SkylanderXbox360PortalLibusb::SetProtocol(uint8 ifIndex, uint8 protocol)\n\t{\n\t\treturn true;\n\t}\n} // namespace nsyshid"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/SkylanderXbox360.h",
    "content": "#pragma once\n\n#include \"nsyshid.h\"\n#include \"BackendLibusb.h\"\n#include \"g721/g721.h\"\n\nnamespace nsyshid\n{\n\tclass SkylanderXbox360PortalLibusb final : public Device {\n\t  public:\n\t\tSkylanderXbox360PortalLibusb(std::shared_ptr<Device> usbPortal);\n\t\t~SkylanderXbox360PortalLibusb() = default;\n\n\t\tbool Open() override;\n\n\t\tvoid Close() override;\n\n\t\tbool IsOpened() override;\n\n\t\tReadResult Read(ReadMessage* message) override;\n\n\t\tWriteResult Write(WriteMessage* message) override;\n\n\t\tbool GetDescriptor(uint8 descType,\n\t\t\tuint8 descIndex,\n\t\t\tuint16 lang,\n\t\t\tuint8* output,\n\t\t\tuint32 outputMaxLength) override;\n\n\t\tbool SetIdle(uint8 ifIndex,\n\t\t\tuint8 reportId,\n\t\t\tuint8 duration) override;\n\n\t\tbool SetProtocol(uint8 ifIndex, uint8 protocol) override;\n\n\t\tbool SetReport(ReportMessage* message) override;\n\t\t\n\t  private:\n\t\tstd::shared_ptr<backend::libusb::DeviceLibusb> m_usbPortal;\n\t\tbool m_IsOpened;\n\t\tstruct g72x_state m_state;\n\t};\n\n\tconstexpr uint8 XBOX_DATA_HEADER[] = { 0x0B, 0x14 };\n\tconstexpr uint8 XBOX_AUDIO_DATA_HEADER[] = { 0x0B, 0x17 };\n} // namespace nsyshid"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/Whitelist.cpp",
    "content": "#include \"Whitelist.h\"\n\nnamespace nsyshid\n{\n\tWhitelist& Whitelist::GetInstance()\n\t{\n\t\tstatic Whitelist whitelist;\n\t\treturn whitelist;\n\t}\n\n\tWhitelist::Whitelist()\n\t{\n\t\t// add known devices\n\t\t{\n\t\t\t// lego dimensions portal\n\t\t\tm_devices.emplace_back(0x0e6f, 0x0241);\n\t\t\t// skylanders portal\n\t\t\tm_devices.emplace_back(0x1430, 0x0150);\n\t\t\t// skylanders 360 portal\n\t\t\tm_devices.emplace_back(0x1430, 0x1F17);\n\t\t\t// disney infinity base\n\t\t\tm_devices.emplace_back(0x0e6f, 0x0129);\n\t\t\t// kamen rider ride gate\n\t\t\tm_devices.emplace_back(0x0e6f, 0x200A);\n\t\t}\n\t}\n\n\tbool Whitelist::IsDeviceWhitelisted(uint16 vendorId, uint16 productId)\n\t{\n\t\tauto it = std::find(m_devices.begin(), m_devices.end(),\n\t\t\t\t\t\t\tstd::tuple<uint16, uint16>(vendorId, productId));\n\t\treturn it != m_devices.end();\n\t}\n\n\tvoid Whitelist::AddDevice(uint16 vendorId, uint16 productId)\n\t{\n\t\tif (!IsDeviceWhitelisted(vendorId, productId))\n\t\t{\n\t\t\tm_devices.emplace_back(vendorId, productId);\n\t\t}\n\t}\n\n\tvoid Whitelist::RemoveDevice(uint16 vendorId, uint16 productId)\n\t{\n\t\tm_devices.remove(std::tuple<uint16, uint16>(vendorId, productId));\n\t}\n\n\tstd::list<std::tuple<uint16, uint16>> Whitelist::GetDevices()\n\t{\n\t\treturn m_devices;\n\t}\n\n\tvoid Whitelist::RemoveAllDevices()\n\t{\n\t\tm_devices.clear();\n\t}\n} // namespace nsyshid\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/Whitelist.h",
    "content": "#ifndef CEMU_NSYSHID_WHITELIST_H\n#define CEMU_NSYSHID_WHITELIST_H\n\nnamespace nsyshid\n{\n\tclass Whitelist {\n\t  public:\n\t\tstatic Whitelist& GetInstance();\n\n\t\tWhitelist(const Whitelist&) = delete;\n\n\t\tWhitelist& operator=(const Whitelist&) = delete;\n\n\t\tbool IsDeviceWhitelisted(uint16 vendorId, uint16 productId);\n\n\t\tvoid AddDevice(uint16 vendorId, uint16 productId);\n\n\t\tvoid RemoveDevice(uint16 vendorId, uint16 productId);\n\n\t\tstd::list<std::tuple<uint16, uint16>> GetDevices();\n\n\t\tvoid RemoveAllDevices();\n\n\t  private:\n\t\tWhitelist();\n\n\t\t// vendorId, productId\n\t\tstd::list<std::tuple<uint16, uint16>> m_devices;\n\t};\n} // namespace nsyshid\n\n#endif // CEMU_NSYSHID_WHITELIST_H\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/g721/g721.cpp",
    "content": "/*\n * This source code is a product of Sun Microsystems, Inc. and is provided\n * for unrestricted use.  Users may copy or modify this source code without\n * charge.\n *\n * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING\n * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.\n *\n * Sun source code is provided with no support and without any obligation on\n * the part of Sun Microsystems, Inc. to assist in its use, correction,\n * modification or enhancement.\n *\n * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE\n * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE\n * OR ANY PART THEREOF.\n *\n * In no event will Sun Microsystems, Inc. be liable for any lost revenue\n * or profits or other special, indirect and consequential damages, even if\n * Sun has been advised of the possibility of such damages.\n *\n * Sun Microsystems, Inc.\n * 2550 Garcia Avenue\n * Mountain View, California  94043\n */\n\n/*\n * g721.c\n *\n * Description:\n *\n * g721_encoder(), g721_decoder()\n *\n * These routines comprise an implementation of the CCITT G.721 ADPCM\n * coding algorithm.  Essentially, this implementation is identical to\n * the bit level description except for a few deviations which\n * take advantage of work station attributes, such as hardware 2's\n * complement arithmetic and large memory.  Specifically, certain time\n * consuming operations such as multiplications are replaced\n * with lookup tables and software 2's complement operations are\n * replaced with hardware 2's complement.\n *\n * The deviation from the bit level specification (lookup tables)\n * preserves the bit level performance specifications.\n *\n * As outlined in the G.721 Recommendation, the algorithm is broken\n * down into modules.  Each section of code below is preceded by\n * the name of the module which it is implementing.\n *\n */\n#include \"g721.h\"\n#include <stdlib.h>\n\nstatic short qtab_721[7] = { -124, 80, 178, 246, 300, 349, 400 };\n/*\n * Maps G.721 code word to reconstructed scale factor normalized log\n * magnitude values.\n */\nstatic short _dqlntab[16] = { -2048, 4,   135, 213, 273, 323, 373, 425,\n                              425,   373, 323, 273, 213, 135, 4,   -2048 };\n\n/* Maps G.721 code word to log of scale factor multiplier. */\nstatic short _witab[16] = { -12,  18,  41,  64,  112, 198, 355, 1122,\n                            1122, 355, 198, 112, 64,  41,  18,  -12 };\n/*\n * Maps G.721 code words to a set of values whose long and short\n * term averages are computed and then compared to give an indication\n * how stationary (steady state) the signal is.\n */\nstatic short _fitab[16] = { 0,     0,     0,     0x200, 0x200, 0x200, 0x600, 0xE00,\n                            0xE00, 0x600, 0x200, 0x200, 0x200, 0,     0,     0 };\n\n/*\n * g721_encoder()\n *\n * Encodes the input value of linear PCM from sl and returns\n * the resulting code. \n */\nint g721_encoder(int sl, struct g72x_state* state_ptr)\n{\n    short sezi, se, sez; /* ACCUM */\n    short d;             /* SUBTA */\n    short sr;            /* ADDB */\n    short y;             /* MIX */\n    short dqsez;         /* ADDC */\n    short dq, i;\n\n    sl >>= 2; /* linearize input sample to 14-bit PCM */\n\n    sezi = predictor_zero(state_ptr);\n    sez = sezi >> 1;\n    se = (sezi + predictor_pole(state_ptr)) >> 1; /* estimated signal */\n\n    d = sl - se; /* estimation difference */\n\n    /* quantize the prediction difference */\n    y = step_size(state_ptr);        /* quantizer step size */\n    i = quantize(d, y, qtab_721, 7); /* i = ADPCM code */\n\n    dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */\n\n    sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconst. signal */\n\n    dqsez = sr + sez - se; /* pole prediction diff. */\n\n    update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);\n\n    return (i);\n}\n\n/*\n * g721_decoder()\n *\n * Description:\n *\n * Decodes a 4-bit code of G.721 encoded data of i and\n * returns the resulting linear PCM\n */\nint g721_decoder(int i, struct g72x_state* state_ptr)\n{\n    short sezi, sei, sez, se; /* ACCUM */\n    short y;                  /* MIX */\n    short sr;                 /* ADDB */\n    short dq;\n    short dqsez;\n\n    i &= 0x0f; /* mask to get proper bits */\n    sezi = predictor_zero(state_ptr);\n    sez = sezi >> 1;\n    sei = sezi + predictor_pole(state_ptr);\n    se = sei >> 1; /* se = estimated signal */\n\n    y = step_size(state_ptr); /* dynamic quantizer step size */\n\n    dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */\n\n    sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */\n\n    dqsez = sr - se + sez; /* pole prediction diff. */\n\n    update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);\n\n    return (sr << 2);\n}\n\n\nstatic short power2[15] = { 1,     2,     4,     8,     0x10,   0x20,   0x40,  0x80,\n                            0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000 };\n\n/*\n * quan()\n *\n * quantizes the input val against the table of size short integers.\n * It returns i if table[i - 1] <= val < table[i].\n *\n * Using linear search for simple coding.\n */\nstatic int quan(int val, short* table, int size)\n{\n    int i;\n\n    for (i = 0; i < size; i++)\n        if (val < *table++)\n            break;\n    return (i);\n}\n\n/*\n * fmult()\n *\n * returns the integer product of the 14-bit integer \"an\" and\n * \"floating point\" representation (4-bit exponent, 6-bit mantessa) \"srn\".\n */\nstatic int fmult(int an, int srn)\n{\n    short anmag, anexp, anmant;\n    short wanexp, wanmant;\n    short retval;\n\n    anmag = (an > 0) ? an : ((-an) & 0x1FFF);\n    anexp = quan(anmag, power2, 15) - 6;\n    anmant = (anmag == 0) ? 32 : (anexp >= 0) ? anmag >> anexp : anmag << -anexp;\n    wanexp = anexp + ((srn >> 6) & 0xF) - 13;\n\n    wanmant = (anmant * (srn & 077) + 0x30) >> 4;\n    retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) : (wanmant >> -wanexp);\n\n    return (((an ^ srn) < 0) ? -retval : retval);\n}\n\n\n\n/*\n * update()\n *\n * updates the state variables for each output code\n */\nvoid update(int code_size,                /* distinguish 723_40 with others */\n            int y,                        /* quantizer step size */\n            int wi,                       /* scale factor multiplier */\n            int fi,                       /* for long/short term energies */\n            int dq,                       /* quantized prediction difference */\n            int sr,                       /* reconstructed signal */\n            int dqsez,                    /* difference from 2-pole predictor */\n            struct g72x_state* state_ptr) /* coder state pointer */\n{\n    int cnt;\n    short mag, exp; /* Adaptive predictor, FLOAT A */\n    short a2p = 0;  /* LIMC */\n    short a1ul;     /* UPA1 */\n    short pks1;     /* UPA2 */\n    short fa1;\n    char tr; /* tone/transition detector */\n    short ylint, thr2, dqthr;\n    short ylfrac, thr1;\n    short pk0;\n\n    pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */\n\n    mag = dq & 0x7FFF; /* prediction difference magnitude */\n    /* TRANS */\n    ylint = state_ptr->yl >> 15;           /* exponent part of yl */\n    ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */\n    thr1 = (32 + ylfrac) << ylint;         /* threshold */\n    thr2 = (ylint > 9) ? 31 << 10 : thr1;  /* limit thr2 to 31 << 10 */\n    dqthr = (thr2 + (thr2 >> 1)) >> 1;     /* dqthr = 0.75 * thr2 */\n    if (state_ptr->td == 0)                /* signal supposed voice */\n        tr = 0;\n    else if (mag <= dqthr) /* supposed data, but small mag */\n        tr = 0;            /* treated as voice */\n    else                   /* signal is data (modem) */\n        tr = 1;\n\n    /*\n     * Quantizer scale factor adaptation.\n     */\n\n    /* FUNCTW & FILTD & DELAY */\n    /* update non-steady state step size multiplier */\n    state_ptr->yu = y + ((wi - y) >> 5);\n\n    /* LIMB */\n    if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */\n        state_ptr->yu = 544;\n    else if (state_ptr->yu > 5120)\n        state_ptr->yu = 5120;\n\n    /* FILTE & DELAY */\n    /* update steady state step size multiplier */\n    state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6);\n\n    /*\n     * Adaptive predictor coefficients.\n     */\n    if (tr == 1) { /* reset a's and b's for modem signal */\n        state_ptr->a[0] = 0;\n        state_ptr->a[1] = 0;\n        state_ptr->b[0] = 0;\n        state_ptr->b[1] = 0;\n        state_ptr->b[2] = 0;\n        state_ptr->b[3] = 0;\n        state_ptr->b[4] = 0;\n        state_ptr->b[5] = 0;\n    } else {                           /* update a's and b's */\n        pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */\n\n        /* update predictor pole a[1] */\n        a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7);\n        if (dqsez != 0) {\n            fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0];\n            if (fa1 < -8191) /* a2p = function of fa1 */\n                a2p -= 0x100;\n            else if (fa1 > 8191)\n                a2p += 0xFF;\n            else\n                a2p += fa1 >> 5;\n\n            if (pk0 ^ state_ptr->pk[1])\n                /* LIMC */\n                if (a2p <= -12160)\n                    a2p = -12288;\n                else if (a2p >= 12416)\n                    a2p = 12288;\n                else\n                    a2p -= 0x80;\n            else if (a2p <= -12416)\n                a2p = -12288;\n            else if (a2p >= 12160)\n                a2p = 12288;\n            else\n                a2p += 0x80;\n        }\n\n        /* TRIGB & DELAY */\n        state_ptr->a[1] = a2p;\n\n        /* UPA1 */\n        /* update predictor pole a[0] */\n        state_ptr->a[0] -= state_ptr->a[0] >> 8;\n        if (dqsez != 0) {\n            if (pks1 == 0)\n                state_ptr->a[0] += 192;\n            else\n                state_ptr->a[0] -= 192;\n        }\n\n        /* LIMD */\n        a1ul = 15360 - a2p;\n        if (state_ptr->a[0] < -a1ul)\n            state_ptr->a[0] = -a1ul;\n        else if (state_ptr->a[0] > a1ul)\n            state_ptr->a[0] = a1ul;\n\n        /* UPB : update predictor zeros b[6] */\n        for (cnt = 0; cnt < 6; cnt++) {\n            if (code_size == 5) /* for 40Kbps G.723 */\n                state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9;\n            else /* for G.721 and 24Kbps G.723 */\n                state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8;\n            if (dq & 0x7FFF) { /* XOR */\n                if ((dq ^ state_ptr->dq[cnt]) >= 0)\n                    state_ptr->b[cnt] += 128;\n                else\n                    state_ptr->b[cnt] -= 128;\n            }\n        }\n    }\n\n    for (cnt = 5; cnt > 0; cnt--)\n        state_ptr->dq[cnt] = state_ptr->dq[cnt - 1];\n    /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */\n    if (mag == 0) {\n        state_ptr->dq[0] = (dq >= 0) ? 0x20 : 0xFC20;\n    } else {\n        exp = quan(mag, power2, 15);\n        state_ptr->dq[0] = (dq >= 0) ? (exp << 6) + ((mag << 6) >> exp)\n                                     : (exp << 6) + ((mag << 6) >> exp) - 0x400;\n    }\n\n    state_ptr->sr[1] = state_ptr->sr[0];\n    /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */\n    if (sr == 0) {\n        state_ptr->sr[0] = 0x20;\n    } else if (sr > 0) {\n        exp = quan(sr, power2, 15);\n        state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp);\n    } else if (sr > -32768) {\n        mag = -sr;\n        exp = quan(mag, power2, 15);\n        state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400;\n    } else\n        state_ptr->sr[0] = 0xFC20;\n\n    /* DELAY A */\n    state_ptr->pk[1] = state_ptr->pk[0];\n    state_ptr->pk[0] = pk0;\n\n    /* TONE */\n    if (tr == 1)           /* this sample has been treated as data */\n        state_ptr->td = 0; /* next one will be treated as voice */\n    else if (a2p < -11776) /* small sample-to-sample correlation */\n        state_ptr->td = 1; /* signal may be data */\n    else                   /* signal is voice */\n        state_ptr->td = 0;\n\n    /*\n     * Adaptation speed control.\n     */\n    state_ptr->dms += (fi - state_ptr->dms) >> 5;          /* FILTA */\n    state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */\n\n    if (tr == 1)\n        state_ptr->ap = 256;\n    else if (y < 1536) /* SUBTC */\n        state_ptr->ap += (0x200 - state_ptr->ap) >> 4;\n    else if (state_ptr->td == 1)\n        state_ptr->ap += (0x200 - state_ptr->ap) >> 4;\n    else if (abs((state_ptr->dms << 2) - state_ptr->dml) >= (state_ptr->dml >> 3))\n        state_ptr->ap += (0x200 - state_ptr->ap) >> 4;\n    else\n        state_ptr->ap += (-state_ptr->ap) >> 4;\n}\n\n\n/*\n * g72x_init_state()\n *\n * This routine initializes and/or resets the g72x_state structure\n * pointed to by 'state_ptr'.\n * All the initial state values are specified in the CCITT G.721 document.\n */\nvoid g72x_init_state(struct g72x_state* state_ptr)\n{\n    int cnta;\n\n    state_ptr->yl = 34816;\n    state_ptr->yu = 544;\n    state_ptr->dms = 0;\n    state_ptr->dml = 0;\n    state_ptr->ap = 0;\n    for (cnta = 0; cnta < 2; cnta++) {\n        state_ptr->a[cnta] = 0;\n        state_ptr->pk[cnta] = 0;\n        state_ptr->sr[cnta] = 32;\n    }\n    for (cnta = 0; cnta < 6; cnta++) {\n        state_ptr->b[cnta] = 0;\n        state_ptr->dq[cnta] = 32;\n    }\n    state_ptr->td = 0;\n}\n\n/*\n * predictor_zero()\n *\n * computes the estimated signal from 6-zero predictor.\n *\n */\nint predictor_zero(struct g72x_state* state_ptr)\n{\n    int i;\n    int sezi;\n\n    sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]);\n    for (i = 1; i < 6; i++) /* ACCUM */\n        sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]);\n    return (sezi);\n}\n/*\n * predictor_pole()\n *\n * computes the estimated signal from 2-pole predictor.\n *\n */\nint predictor_pole(struct g72x_state* state_ptr)\n{\n    return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) +\n            fmult(state_ptr->a[0] >> 2, state_ptr->sr[0]));\n}\n/*\n * step_size()\n *\n * computes the quantization step size of the adaptive quantizer.\n *\n */\nint step_size(struct g72x_state* state_ptr)\n{\n    int y;\n    int dif;\n    int al;\n\n    if (state_ptr->ap >= 256)\n        return (state_ptr->yu);\n    else {\n        y = state_ptr->yl >> 6;\n        dif = state_ptr->yu - y;\n        al = state_ptr->ap >> 2;\n        if (dif > 0)\n            y += (dif * al) >> 6;\n        else if (dif < 0)\n            y += (dif * al + 0x3F) >> 6;\n        return (y);\n    }\n}\n\n/*\n * quantize()\n *\n * Given a raw sample, 'd', of the difference signal and a\n * quantization step size scale factor, 'y', this routine returns the\n * ADPCM codeword to which that sample gets quantized.  The step\n * size scale factor division operation is done in the log base 2 domain\n * as a subtraction.\n */\nint quantize(int d,        /* Raw difference signal sample */\n             int y,        /* Step size multiplier */\n             short* table, /* quantization table */\n             int size)     /* table size of short integers */\n{\n    short dqm;  /* Magnitude of 'd' */\n    short exp;  /* Integer part of base 2 log of 'd' */\n    short mant; /* Fractional part of base 2 log */\n    short dl;   /* Log of magnitude of 'd' */\n    short dln;  /* Step size scale factor normalized log */\n    int i;\n\n    /*\n     * LOG\n     *\n     * Compute base 2 log of 'd', and store in 'dl'.\n     */\n    dqm = abs(d);\n    exp = quan(dqm >> 1, power2, 15);\n    mant = ((dqm << 7) >> exp) & 0x7F; /* Fractional portion. */\n    dl = (exp << 7) + mant;\n\n    /*\n     * SUBTB\n     *\n     * \"Divide\" by step size multiplier.\n     */\n    dln = dl - (y >> 2);\n\n    /*\n     * QUAN\n     *\n     * Obtain codword i for 'd'.\n     */\n    i = quan(dln, table, size);\n    if (d < 0) /* take 1's complement of i */\n        return ((size << 1) + 1 - i);\n    else if (i == 0)              /* take 1's complement of 0 */\n        return ((size << 1) + 1); /* new in 1988 */\n    else\n        return (i);\n}\n/*\n * reconstruct()\n *\n * Returns reconstructed difference signal 'dq' obtained from\n * codeword 'i' and quantization step size scale factor 'y'.\n * Multiplication is performed in log base 2 domain as addition.\n */\nint reconstruct(int sign, /* 0 for non-negative value */\n                int dqln, /* G.72x codeword */\n                int y)    /* Step size multiplier */\n{\n    short dql; /* Log of 'dq' magnitude */\n    short dex; /* Integer part of log */\n    short dqt;\n    short dq; /* Reconstructed difference signal sample */\n\n    dql = dqln + (y >> 2); /* ADDA */\n\n    if (dql < 0) {\n        return ((sign) ? -0x8000 : 0);\n    } else { /* ANTILOG */\n        dex = (dql >> 7) & 15;\n        dqt = 128 + (dql & 127);\n        dq = (dqt << 7) >> (14 - dex);\n        return ((sign) ? (dq - 0x8000) : dq);\n    }\n}"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/g721/g721.h",
    "content": "/*\n * This source code is a product of Sun Microsystems, Inc. and is provided\n * for unrestricted use.  Users may copy or modify this source code without\n * charge.\n *\n * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING\n * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR\n * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.\n *\n * Sun source code is provided with no support and without any obligation on\n * the part of Sun Microsystems, Inc. to assist in its use, correction,\n * modification or enhancement.\n *\n * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE\n * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE\n * OR ANY PART THEREOF.\n *\n * In no event will Sun Microsystems, Inc. be liable for any lost revenue\n * or profits or other special, indirect and consequential damages, even if\n * Sun has been advised of the possibility of such damages.\n *\n * Sun Microsystems, Inc.\n * 2550 Garcia Avenue\n * Mountain View, California  94043\n */\n\n/*\n * g72x.h\n *\n * Header file for CCITT conversion routines.\n *\n */\n#ifndef _G72X_H\n#define _G72X_H\n\n/*\n * The following is the definition of the state structure\n * used by the G.721/G.723 encoder and decoder to preserve their internal\n * state between successive calls.  The meanings of the majority\n * of the state structure fields are explained in detail in the\n * CCITT Recommendation G.721.  The field names are essentially identical\n * to variable names in the bit level description of the coding algorithm\n * included in this Recommendation.\n */\nstruct g72x_state {\n    long yl;   /* Locked or steady state step size multiplier. */\n    short yu;  /* Unlocked or non-steady state step size multiplier. */\n    short dms; /* Short term energy estimate. */\n    short dml; /* Long term energy estimate. */\n    short ap;  /* Linear weighting coefficient of 'yl' and 'yu'. */\n\n    short a[2];  /* Coefficients of pole portion of prediction filter. */\n    short b[6];  /* Coefficients of zero portion of prediction filter. */\n    short pk[2]; /*\n                  * Signs of previous two samples of a partially\n                  * reconstructed signal.\n                  */\n    short dq[6]; /*\n                  * Previous 6 samples of the quantized difference\n                  * signal represented in an internal floating point\n                  * format.\n                  */\n    short sr[2]; /*\n                  * Previous 2 samples of the quantized difference\n                  * signal represented in an internal floating point\n                  * format.\n                  */\n    char td;     /* delayed tone detect, new in 1988 version */\n};\n\n/* External function definitions. */\n\nvoid g72x_init_state(struct g72x_state*);\nint g721_encoder(int sample, struct g72x_state* state_ptr);\nint g721_decoder(int code, struct g72x_state* state_ptr);\n\n\nint quantize(int d, int y, short* table, int size);\nint reconstruct(int, int, int);\nvoid\n\n    update(int code_size,\n                  int y,\n                  int wi,\n                  int fi,\n                  int dq,\n                  int sr,\n                  int dqsez,\n                  struct g72x_state* state_ptr);\n\nint predictor_zero(struct g72x_state* state_ptr);\n\nint predictor_pole(struct g72x_state* state_ptr);\nint step_size(struct g72x_state* state_ptr);\n#endif /* !_G72X_H */\n\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/nsyshid.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include <bitset>\n#include <mutex>\n#include \"nsyshid.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Backend.h\"\n#include \"Whitelist.h\"\n\nnamespace nsyshid\n{\n\n\tstd::list<std::shared_ptr<Backend>> backendList;\n\n\tstd::list<std::shared_ptr<Device>> deviceList;\n\n\ttypedef struct _HIDClient_t\n\t{\n\t\tuint32be callbackFunc; // attach/detach callback\n\t} HIDClient_t;\n\n\tstd::list<HIDClient_t*> HIDClientList;\n\n\tstd::recursive_mutex hidMutex;\n\n\tvoid AttachClientToList(HIDClient_t* hidClient)\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\t// todo - append at the beginning or end of the list? List order matters because it also controls the order in which attach callbacks are called\n\t\tHIDClientList.push_front(hidClient);\n\t}\n\n\tvoid DetachClientFromList(HIDClient_t* hidClient)\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\tHIDClientList.remove(hidClient);\n\t}\n\n\tstd::shared_ptr<Device> GetDeviceByHandle(uint32 handle, bool openIfClosed = false)\n\t{\n\t\tstd::shared_ptr<Device> device;\n\t\t{\n\t\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\t\tfor (const auto& d : deviceList)\n\t\t\t{\n\t\t\t\tif (d->m_hid->handle == handle)\n\t\t\t\t{\n\t\t\t\t\tdevice = d;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (device != nullptr)\n\t\t{\n\t\t\tif (openIfClosed && !device->IsOpened())\n\t\t\t{\n\t\t\t\tif (!device->Open())\n\t\t\t\t{\n\t\t\t\t\treturn nullptr;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn device;\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tuint32 _lastGeneratedHidHandle = 1;\n\n\tuint32 GenerateHIDHandle()\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\t_lastGeneratedHidHandle++;\n\t\treturn _lastGeneratedHidHandle;\n\t}\n\n\tconst int HID_MAX_NUM_DEVICES = 128;\n\n\tSysAllocator<HID_t, HID_MAX_NUM_DEVICES> HIDPool;\n\tstd::queue<size_t> HIDPoolIndexQueue;\n\n\tvoid InitHIDPoolIndexQueue()\n\t{\n\t\tstatic bool HIDPoolIndexQueueInitialized = false;\n\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\tif (HIDPoolIndexQueueInitialized)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\tHIDPoolIndexQueueInitialized = true;\n\t\tfor (size_t i = 0; i < HID_MAX_NUM_DEVICES; i++)\n\t\t{\n\t\t\tHIDPoolIndexQueue.push(i);\n\t\t}\n\t}\n\n\tHID_t* GetFreeHID()\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\tInitHIDPoolIndexQueue();\n\t\tif (HIDPoolIndexQueue.empty())\n\t\t{\n\t\t\treturn nullptr;\n\t\t}\n\t\tsize_t index = HIDPoolIndexQueue.front();\n\t\tHIDPoolIndexQueue.pop();\n\t\treturn HIDPool.GetPtr() + index;\n\t}\n\n\tvoid ReleaseHID(HID_t* device)\n\t{\n\t\t// this should never happen, but having a safeguard can't hurt\n\t\tif (device == nullptr)\n\t\t{\n\t\t\tcemu_assert_error();\n\t\t}\n\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\tInitHIDPoolIndexQueue();\n\t\tsize_t index = device - HIDPool.GetPtr();\n\t\tHIDPoolIndexQueue.push(index);\n\t}\n\n\tconst int HID_CALLBACK_DETACH = 0;\n\tconst int HID_CALLBACK_ATTACH = 1;\n\n\tuint32 DoAttachCallback(HIDClient_t* hidClient, const std::shared_ptr<Device>& device)\n\t{\n\t\treturn PPCCoreCallback(hidClient->callbackFunc, memory_getVirtualOffsetFromPointer(hidClient),\n\t\t\t\t\t\t\t   memory_getVirtualOffsetFromPointer(device->m_hid), HID_CALLBACK_ATTACH);\n\t}\n\n\tvoid DoAttachCallbackAsync(HIDClient_t* hidClient, const std::shared_ptr<Device>& device)\n\t{\n\t\tcoreinitAsyncCallback_add(hidClient->callbackFunc, 3, memory_getVirtualOffsetFromPointer(hidClient),\n\t\t\t\t\t\t\t\t  memory_getVirtualOffsetFromPointer(device->m_hid), HID_CALLBACK_ATTACH);\n\t}\n\n\tvoid DoDetachCallback(HIDClient_t* hidClient, const std::shared_ptr<Device>& device)\n\t{\n\t\tPPCCoreCallback(hidClient->callbackFunc, memory_getVirtualOffsetFromPointer(hidClient),\n\t\t\t\t\t\tmemory_getVirtualOffsetFromPointer(device->m_hid), HID_CALLBACK_DETACH);\n\t}\n\n\tvoid DoDetachCallbackAsync(HIDClient_t* hidClient, const std::shared_ptr<Device>& device)\n\t{\n\t\tcoreinitAsyncCallback_add(hidClient->callbackFunc, 3, memory_getVirtualOffsetFromPointer(hidClient),\n\t\t\t\t\t\t\t\t  memory_getVirtualOffsetFromPointer(device->m_hid), HID_CALLBACK_DETACH);\n\t}\n\n\tvoid AttachBackend(const std::shared_ptr<Backend>& backend)\n\t{\n\t\t{\n\t\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\t\tbackendList.push_back(backend);\n\t\t}\n\t\tbackend->OnAttach();\n\t}\n\n\tvoid DetachBackend(const std::shared_ptr<Backend>& backend)\n\t{\n\t\t{\n\t\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\t\tbackendList.remove(backend);\n\t\t}\n\t\tbackend->OnDetach();\n\t}\n\n\tvoid DetachAllBackends()\n\t{\n\t\tstd::list<std::shared_ptr<Backend>> backendListCopy;\n\t\t{\n\t\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\t\tbackendListCopy = backendList;\n\t\t\tbackendList.clear();\n\t\t}\n\t\tfor (const auto& backend : backendListCopy)\n\t\t{\n\t\t\tbackend->OnDetach();\n\t\t}\n\t}\n\n\tvoid AttachDefaultBackends()\n\t{\n\t\tbackend::AttachDefaultBackends();\n\t}\n\n\tbool AttachDevice(const std::shared_ptr<Device>& device)\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\n\t\t// is the device already attached?\n\t\t{\n\t\t\tauto it = std::find(deviceList.begin(), deviceList.end(), device);\n\t\t\tif (it != deviceList.end())\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t\t\t \"nsyshid.AttachDevice(): failed to attach device: {:04x}:{:04x}: already attached\",\n\t\t\t\t\t\t\t\t device->m_vendorId,\n\t\t\t\t\t\t\t\t device->m_productId);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tHID_t* hidDevice = GetFreeHID();\n\t\tif (hidDevice == nullptr)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force,\n\t\t\t\t\t\t\t \"nsyshid.AttachDevice(): failed to attach device: {:04x}:{:04x}: no free device slots left\",\n\t\t\t\t\t\t\t device->m_vendorId,\n\t\t\t\t\t\t\t device->m_productId);\n\t\t\treturn false;\n\t\t}\n\t\thidDevice->handle = GenerateHIDHandle();\n\t\tdevice->AssignHID(hidDevice);\n\t\tdeviceList.push_back(device);\n\n\t\t// do attach callbacks\n\t\tfor (auto client : HIDClientList)\n\t\t{\n\t\t\tDoAttachCallbackAsync(client, device);\n\t\t}\n\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.AttachDevice(): device attached: {:04x}:{:04x}\",\n\t\t\t\t\t\t device->m_vendorId,\n\t\t\t\t\t\t device->m_productId);\n\t\treturn true;\n\t}\n\n\tvoid DetachDevice(const std::shared_ptr<Device>& device)\n\t{\n\t\t{\n\t\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\n\t\t\t// remove from list\n\t\t\tauto it = std::find(deviceList.begin(), deviceList.end(), device);\n\t\t\tif (it == deviceList.end())\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.DetachDevice(): device not found: {:04x}:{:04x}\",\n\t\t\t\t\t\t\t\t device->m_vendorId,\n\t\t\t\t\t\t\t\t device->m_productId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdeviceList.erase(it);\n\n\t\t\t// do detach callbacks\n\t\t\tfor (auto client : HIDClientList)\n\t\t\t{\n\t\t\t\tDoDetachCallbackAsync(client, device);\n\t\t\t}\n\t\t\tReleaseHID(device->m_hid);\n\t\t}\n\n\t\tdevice->Close();\n\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.DetachDevice(): device removed: {:04x}:{:04x}\",\n\t\t\t\t\t\t device->m_vendorId,\n\t\t\t\t\t\t device->m_productId);\n\t}\n\n\tstd::shared_ptr<Device> FindDeviceById(uint16 vendorId, uint16 productId)\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\tfor (const auto& device : deviceList)\n\t\t{\n\t\t\tif (device->m_vendorId == vendorId && device->m_productId == productId)\n\t\t\t{\n\t\t\t\treturn device;\n\t\t\t}\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tvoid export_HIDAddClient(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamTypePtr(hidClient, HIDClient_t, 0);\n\t\tppcDefineParamMPTR(callbackFuncMPTR, 1);\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.HIDAddClient(0x{:08x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\thidClient->callbackFunc = callbackFuncMPTR;\n\n\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\tAttachClientToList(hidClient);\n\n\t\t// do attach callbacks\n\t\tfor (const auto& device : deviceList)\n\t\t{\n\t\t\tDoAttachCallback(hidClient, device);\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_HIDDelClient(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamTypePtr(hidClient, HIDClient_t, 0);\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.HIDDelClient(0x{:08x})\", hCPU->gpr[3]);\n\n\t\tstd::lock_guard<std::recursive_mutex> lock(hidMutex);\n\t\tDetachClientFromList(hidClient);\n\n\t\t// do detach callbacks\n\t\tfor (const auto& device : deviceList)\n\t\t{\n\t\t\tDoDetachCallback(hidClient, device);\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid _debugPrintHex(const std::string prefix, const uint8* data, size_t size)\n\t{\n\t\tconstexpr size_t BYTES_PER_LINE = 16;\n\n\t\tstd::string out;\n\t\tfor (size_t row_start = 0; row_start < size; row_start += BYTES_PER_LINE)\n\t\t{\n\t\t\tout += fmt::format(\"{:06x}: \", row_start);\n\t\t\tfor (size_t i = 0; i < BYTES_PER_LINE; ++i)\n\t\t\t{\n\t\t\t\tif (row_start + i < size)\n\t\t\t\t{\n\t\t\t\t\tout += fmt::format(\"{:02x} \", data[row_start + i]);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tout += \"   \";\n\t\t\t\t}\n\t\t\t}\n\t\t\tout += \" \";\n\t\t\tfor (size_t i = 0; i < BYTES_PER_LINE; ++i)\n\t\t\t{\n\t\t\t\tif (row_start + i < size)\n\t\t\t\t{\n\t\t\t\t\tchar c = static_cast<char>(data[row_start + i]);\n\t\t\t\t\tout += std::isprint(c, std::locale::classic()) ? c : '.';\n\t\t\t\t}\n\t\t\t}\n\t\t\tout += \"\\n\";\n\t\t}\n\t\tcemuLog_logDebug(LogType::Force, \"[{}] Data: \\n{}\", prefix, out);\n\t}\n\n\tvoid DoHIDTransferCallback(MPTR callbackFuncMPTR, MPTR callbackParamMPTR, uint32 hidHandle, uint32 errorCode,\n\t\t\t\t\t\t\t   MPTR buffer, sint32 length)\n\t{\n\t\tcoreinitAsyncCallback_add(callbackFuncMPTR, 5, hidHandle, errorCode, buffer, length, callbackParamMPTR);\n\t}\n\n\tvoid _hidGetDescriptorAsync(std::shared_ptr<Device> device, uint8 descType, uint8 descIndex, uint16 lang, uint8* output, uint32 outputMaxLength, MPTR callbackFuncMPTR, MPTR callbackParamMPTR)\n\t{\n\t\tif (device->GetDescriptor(descType, descIndex, lang, output, outputMaxLength))\n\t\t{\n\t\t\tDoHIDTransferCallback(callbackFuncMPTR,\n\t\t\t\t\t\t\t\t  callbackParamMPTR,\n\t\t\t\t\t\t\t\t  device->m_hid->handle,\n\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t  0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDoHIDTransferCallback(callbackFuncMPTR,\n\t\t\t\t\t\t\t\t  callbackParamMPTR,\n\t\t\t\t\t\t\t\t  device->m_hid->handle,\n\t\t\t\t\t\t\t\t  -1,\n\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t  0);\n\t\t}\n\t}\n\n\tvoid export_HIDGetDescriptor(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(hidHandle, 0);\t   // r3\n\t\tppcDefineParamU8(descType, 1);\t\t   // r4\n\t\tppcDefineParamU8(descIndex, 2);\t\t   // r5\n\t\tppcDefineParamU16(lang, 3);\t\t\t   // r6\n\t\tppcDefineParamUStr(output, 4);\t\t   // r7\n\t\tppcDefineParamU32(outputMaxLength, 5); // r8\n\t\tppcDefineParamMPTR(cbFuncMPTR, 6);\t   // r9\n\t\tppcDefineParamMPTR(cbParamMPTR, 7);\t   // r10\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.HIDGetDescriptor(0x{:08x}, 0x{:02x}, 0x{:02x}, 0x{:04x}, 0x{:x}, 0x{:08x}, 0x{:08x}, 0x{:08x})\",\n\t\t\t\t\thCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8], hCPU->gpr[9], hCPU->gpr[10]);\n\n\t\tstd::shared_ptr<Device> device = GetDeviceByHandle(hidHandle, true);\n\t\tif (device == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"nsyshid.HIDGetDescriptor(): Unable to find device with hid handle {}\", hidHandle);\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\n\t\t// issue request (synchronous or asynchronous)\n\t\tsint32 returnCode = 0;\n\t\tif (cbFuncMPTR == MPTR_NULL)\n\t\t{\n\t\t\t// synchronous\n\t\t\treturnCode = -1;\n\t\t\tif (device->GetDescriptor(descType, descIndex, lang, output, outputMaxLength))\n\t\t\t{\n\t\t\t\treturnCode = outputMaxLength;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// asynchronous\n\t\t\tstd::thread(&_hidGetDescriptorAsync, device, descType, descIndex, lang, output, outputMaxLength, cbFuncMPTR, cbParamMPTR)\n\t\t\t\t.detach();\n\t\t\treturnCode = 0;\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, returnCode);\n\t}\n\n\tvoid _hidSetIdleAsync(std::shared_ptr<Device> device, uint8 ifIndex, uint8 reportId, uint8 duration, MPTR callbackFuncMPTR, MPTR callbackParamMPTR)\n\t{\n\t\tif (device->SetIdle(ifIndex, reportId, duration))\n\t\t{\n\t\t\tDoHIDTransferCallback(callbackFuncMPTR,\n\t\t\t\t\t\t\t\t  callbackParamMPTR,\n\t\t\t\t\t\t\t\t  device->m_hid->handle,\n\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t  0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDoHIDTransferCallback(callbackFuncMPTR,\n\t\t\t\t\t\t\t\t  callbackParamMPTR,\n\t\t\t\t\t\t\t\t  device->m_hid->handle,\n\t\t\t\t\t\t\t\t  -1,\n\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t  0);\n\t\t}\n\t}\n\n\tvoid export_HIDSetIdle(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(hidHandle, 0);\t\t  // r3\n\t\tppcDefineParamU8(ifIndex, 1);\t\t\t  // r4\n\t\tppcDefineParamU8(reportId, 2);\t\t\t  // r5\n\t\tppcDefineParamU8(duration, 3);\t\t\t  // r6\n\t\tppcDefineParamMPTR(callbackFuncMPTR, 4);  // r7\n\t\tppcDefineParamMPTR(callbackParamMPTR, 5); // r8\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.HIDSetIdle(0x{:08x}, 0x{:02x}, 0x{:02x}, 0x{:02x}, 0x{:08x}, 0x{:08x})\", hCPU->gpr[3],\n\t\t\t\t\thCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8]);\n\n\t\tstd::shared_ptr<Device> device = GetDeviceByHandle(hidHandle, true);\n\t\tif (device == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"nsyshid.HIDSetIdle(): Unable to find device with hid handle {}\", hidHandle);\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\n\t\t// issue request (synchronous or asynchronous)\n\t\tsint32 returnCode = 0;\n\t\tif (callbackFuncMPTR == MPTR_NULL)\n\t\t{\n\t\t\t// synchronous\n\t\t\treturnCode = -1;\n\t\t\tif (device->SetIdle(ifIndex, reportId, duration))\n\t\t\t{\n\t\t\t\treturnCode = 0;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// asynchronous\n\t\t\tstd::thread(&_hidSetIdleAsync, device, ifIndex, reportId, duration, callbackFuncMPTR, callbackParamMPTR)\n\t\t\t\t.detach();\n\t\t\treturnCode = 0;\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, returnCode);\n\t}\n\n\tvoid _hidSetProtocolAsync(std::shared_ptr<Device> device, uint8 ifIndex, uint8 protocol, MPTR callbackFuncMPTR, MPTR callbackParamMPTR)\n\t{\n\t\tif (device->SetProtocol(ifIndex, protocol))\n\t\t{\n\t\t\tDoHIDTransferCallback(callbackFuncMPTR,\n\t\t\t\t\t\t\t\t  callbackParamMPTR,\n\t\t\t\t\t\t\t\t  device->m_hid->handle,\n\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t  0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDoHIDTransferCallback(callbackFuncMPTR,\n\t\t\t\t\t\t\t\t  callbackParamMPTR,\n\t\t\t\t\t\t\t\t  device->m_hid->handle,\n\t\t\t\t\t\t\t\t  -1,\n\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t  0);\n\t\t}\n\t}\n\n\tvoid export_HIDSetProtocol(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(hidHandle, 0);\t\t  // r3\n\t\tppcDefineParamU8(ifIndex, 1);\t\t\t  // r4\n\t\tppcDefineParamU8(protocol, 2);\t\t\t  // r5\n\t\tppcDefineParamMPTR(callbackFuncMPTR, 3);  // r6\n\t\tppcDefineParamMPTR(callbackParamMPTR, 4); // r7\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.HIDSetProtocol(0x{:08x}, 0x{:02x}, 0x{:02x}, 0x{:08x}, 0x{:08x})\", hCPU->gpr[3],\n\t\t\t\t\thCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7]);\n\n\t\tstd::shared_ptr<Device> device = GetDeviceByHandle(hidHandle, true);\n\t\tif (device == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"nsyshid.HIDSetProtocol(): Unable to find device with hid handle {}\", hidHandle);\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\t\t// issue request (synchronous or asynchronous)\n\t\tsint32 returnCode = 0;\n\t\tif (callbackFuncMPTR == MPTR_NULL)\n\t\t{\n\t\t\t// synchronous\n\t\t\treturnCode = -1;\n\t\t\tif (device->SetProtocol(ifIndex, protocol))\n\t\t\t{\n\t\t\t\treturnCode = 0;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// asynchronous\n\t\t\tstd::thread(&_hidSetProtocolAsync, device, ifIndex, protocol, callbackFuncMPTR, callbackParamMPTR)\n\t\t\t\t.detach();\n\t\t\treturnCode = 0;\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, returnCode);\n\t}\n\n\t// handler for async HIDSetReport transfers\n\tvoid _hidSetReportAsync(std::shared_ptr<Device> device, uint8 reportType, uint8 reportId, uint8* data, uint32 length,\n\t\t\t\t\t\t\tMPTR callbackFuncMPTR, MPTR callbackParamMPTR)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"_hidSetReportAsync begin\");\n\t\tReportMessage message(reportType, reportId, data, length);\n\t\tif (device->SetReport(&message))\n\t\t{\n\t\t\tDoHIDTransferCallback(callbackFuncMPTR,\n\t\t\t\t\t\t\t\t  callbackParamMPTR,\n\t\t\t\t\t\t\t\t  device->m_hid->handle,\n\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t  memory_getVirtualOffsetFromPointer(data),\n\t\t\t\t\t\t\t\t  length);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDoHIDTransferCallback(callbackFuncMPTR,\n\t\t\t\t\t\t\t\t  callbackParamMPTR,\n\t\t\t\t\t\t\t\t  device->m_hid->handle,\n\t\t\t\t\t\t\t\t  -1,\n\t\t\t\t\t\t\t\t  memory_getVirtualOffsetFromPointer(data),\n\t\t\t\t\t\t\t\t  length);\n\t\t}\n\t}\n\n\t// handler for synchronous HIDSetReport transfers\n\tsint32 _hidSetReportSync(std::shared_ptr<Device> device, uint8 reportType, uint8 reportId,\n\t\t\t\t\t\t\t uint8* data, uint32 length, coreinit::OSEvent* event)\n\t{\n\t\t_debugPrintHex(\"_hidSetReportSync Begin\", data, length);\n\t\tsint32 returnCode = 0;\n\t\tReportMessage message(reportType, reportId, data, length);\n\t\tif (device->SetReport(&message))\n\t\t{\n\t\t\treturnCode = length;\n\t\t}\n\t\tcemuLog_logDebug(LogType::Force, \"_hidSetReportSync end. returnCode: {}\", returnCode);\n\t\tcoreinit::OSSignalEvent(event);\n\t\treturn returnCode;\n\t}\n\n\tvoid export_HIDSetReport(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(hidHandle, 0);\t\t  // r3\n\t\tppcDefineParamU8(reportType, 1);\t\t  // r4\n\t\tppcDefineParamU8(reportId, 2);\t\t\t  // r5\n\t\tppcDefineParamUStr(data, 3);\t\t\t  // r6\n\t\tppcDefineParamU32(dataLength, 4);\t\t  // r7\n\t\tppcDefineParamMPTR(callbackFuncMPTR, 5);  // r8\n\t\tppcDefineParamMPTR(callbackParamMPTR, 6); // r9\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.HIDSetReport(0x{:08x}, 0x{:02x}, 0x{:02x}, 0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x})\", hCPU->gpr[3],\n\t\t\t\t\thCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8], hCPU->gpr[9]);\n\n\t\t_debugPrintHex(\"HIDSetReport\", data, dataLength);\n\n#ifdef CEMU_DEBUG_ASSERT\n\t\tif (reportType != 2 || reportId != 0)\n\t\t\tassert_dbg();\n#endif\n\n\t\tstd::shared_ptr<Device> device = GetDeviceByHandle(hidHandle, true);\n\t\tif (device == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"nsyshid.HIDSetReport(): Unable to find device with hid handle {}\", hidHandle);\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\n\t\t// issue request (synchronous or asynchronous)\n\t\tsint32 returnCode = 0;\n\t\tif (callbackFuncMPTR == MPTR_NULL)\n\t\t{\n\t\t\t// synchronous\n\t\t\tStackAllocator<coreinit::OSEvent> event;\n\t\t\tcoreinit::OSInitEvent(&event, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);\n\t\t\tstd::future<sint32> res = std::async(std::launch::async, &_hidSetReportSync, device, reportType, reportId, data, dataLength, &event);\n\t\t\tcoreinit::OSWaitEvent(&event);\n\t\t\treturnCode = res.get();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// asynchronous\n\t\t\tstd::thread(&_hidSetReportAsync, device, reportType, reportId, data, dataLength,\n\t\t\t\t\t\tcallbackFuncMPTR, callbackParamMPTR)\n\t\t\t\t.detach();\n\t\t\treturnCode = 0;\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, returnCode);\n\t}\n\n\tsint32 _hidReadInternalSync(std::shared_ptr<Device> device, uint8* data, sint32 maxLength)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"HidRead Begin (Length 0x{:08x})\", maxLength);\n\t\tif (!device->IsOpened())\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.hidReadInternalSync(): cannot read from a non-opened device\");\n\t\t\treturn -1;\n\t\t}\n\t\tmemset(data, 0, maxLength);\n\t\tReadMessage message(data, maxLength, 0);\n\t\tDevice::ReadResult readResult = device->Read(&message);\n\t\tswitch (readResult)\n\t\t{\n\t\tcase Device::ReadResult::Success:\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.hidReadInternalSync(): read {} of {} bytes\",\n\t\t\t\t\t\t\t message.bytesRead,\n\t\t\t\t\t\t\t maxLength);\n\t\t\treturn message.bytesRead;\n\t\t}\n\t\tbreak;\n\t\tcase Device::ReadResult::Error:\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.hidReadInternalSync(): read error\");\n\t\t\treturn -1;\n\t\t}\n\t\tbreak;\n\t\tcase Device::ReadResult::ErrorTimeout:\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.hidReadInternalSync(): read error: timeout\");\n\t\t\treturn -108;\n\t\t}\n\t\tbreak;\n\t\t}\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.hidReadInternalSync(): read error: unknown\");\n\t\treturn -1;\n\t}\n\n\tvoid _hidReadAsync(std::shared_ptr<Device> device,\n\t\t\t\t\t   uint8* data, sint32 maxLength,\n\t\t\t\t\t   MPTR callbackFuncMPTR,\n\t\t\t\t\t   MPTR callbackParamMPTR)\n\t{\n\t\tsint32 returnCode = _hidReadInternalSync(device, data, maxLength);\n\t\tsint32 errorCode = 0;\n\t\tif (returnCode < 0)\n\t\t\terrorCode = returnCode; // don't return number of bytes in error code\n\t\tDoHIDTransferCallback(callbackFuncMPTR, callbackParamMPTR, device->m_hid->handle, errorCode,\n\t\t\t\t\t\t\t  memory_getVirtualOffsetFromPointer(data), (returnCode > 0) ? returnCode : 0);\n\t}\n\n\tsint32 _hidReadSync(std::shared_ptr<Device> device,\n\t\t\t\t\t\tuint8* data,\n\t\t\t\t\t\tsint32 maxLength,\n\t\t\t\t\t\tcoreinit::OSEvent* event)\n\t{\n\t\tsint32 returnCode = _hidReadInternalSync(device, data, maxLength);\n\t\tcoreinit::OSSignalEvent(event);\n\t\treturn returnCode;\n\t}\n\n\tvoid export_HIDRead(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(hidHandle, 0);\t\t  // r3\n\t\tppcDefineParamUStr(data, 1);\t\t\t  // r4\n\t\tppcDefineParamU32(maxLength, 2);\t\t  // r5\n\t\tppcDefineParamMPTR(callbackFuncMPTR, 3);  // r6\n\t\tppcDefineParamMPTR(callbackParamMPTR, 4); // r7\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.HIDRead(0x{:x},0x{:08x},0x{:08x},0x{:08x},0x{:08x})\", hCPU->gpr[3],\n\t\t\t\t\thCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7]);\n\n\t\tstd::shared_ptr<Device> device = GetDeviceByHandle(hidHandle, true);\n\t\tif (device == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"nsyshid.HIDRead(): Unable to find device with hid handle {}\", hidHandle);\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\t\tsint32 returnCode = 0;\n\t\tif (callbackFuncMPTR != MPTR_NULL)\n\t\t{\n\t\t\t// asynchronous transfer\n\t\t\tstd::thread(&_hidReadAsync, device, data, maxLength, callbackFuncMPTR, callbackParamMPTR).detach();\n\t\t\treturnCode = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// synchronous transfer\n\t\t\tStackAllocator<coreinit::OSEvent> event;\n\t\t\tcoreinit::OSInitEvent(&event, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);\n\t\t\tstd::future<sint32> res = std::async(std::launch::async, &_hidReadSync, device, data, maxLength, &event);\n\t\t\tcoreinit::OSWaitEvent(&event);\n\t\t\treturnCode = res.get();\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, returnCode);\n\t}\n\n\tsint32 _hidWriteInternalSync(std::shared_ptr<Device> device, uint8* data, sint32 maxLength)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"HidWrite Begin (Length 0x{:08x})\", maxLength);\n\t\tif (!device->IsOpened())\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.hidWriteInternalSync(): cannot write to a non-opened device\");\n\t\t\treturn -1;\n\t\t}\n\t\tWriteMessage message(data, maxLength, 0);\n\t\tDevice::WriteResult writeResult = device->Write(&message);\n\t\tswitch (writeResult)\n\t\t{\n\t\tcase Device::WriteResult::Success:\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.hidWriteInternalSync(): wrote {} of {} bytes\", message.bytesWritten,\n\t\t\t\t\t\t\t maxLength);\n\t\t\treturn message.bytesWritten;\n\t\t}\n\t\tbreak;\n\t\tcase Device::WriteResult::Error:\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.hidWriteInternalSync(): write error\");\n\t\t\treturn -1;\n\t\t}\n\t\tbreak;\n\t\tcase Device::WriteResult::ErrorTimeout:\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.hidWriteInternalSync(): write error: timeout\");\n\t\t\treturn -108;\n\t\t}\n\t\tbreak;\n\t\t}\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.hidWriteInternalSync(): write error: unknown\");\n\t\treturn -1;\n\t}\n\n\tvoid _hidWriteAsync(std::shared_ptr<Device> device,\n\t\t\t\t\t\tuint8* data,\n\t\t\t\t\t\tsint32 maxLength,\n\t\t\t\t\t\tMPTR callbackFuncMPTR,\n\t\t\t\t\t\tMPTR callbackParamMPTR)\n\t{\n\t\tsint32 returnCode = _hidWriteInternalSync(device, data, maxLength);\n\t\tsint32 errorCode = 0;\n\t\tif (returnCode < 0)\n\t\t\terrorCode = returnCode; // don't return number of bytes in error code\n\t\tDoHIDTransferCallback(callbackFuncMPTR, callbackParamMPTR, device->m_hid->handle, errorCode,\n\t\t\t\t\t\t\t  memory_getVirtualOffsetFromPointer(data), (returnCode > 0) ? returnCode : 0);\n\t}\n\n\tsint32 _hidWriteSync(std::shared_ptr<Device> device,\n\t\t\t\t\t\t uint8* data,\n\t\t\t\t\t\t sint32 maxLength,\n\t\t\t\t\t\t coreinit::OSEvent* event)\n\t{\n\t\tsint32 returnCode = _hidWriteInternalSync(device, data, maxLength);\n\t\tcoreinit::OSSignalEvent(event);\n\t\treturn returnCode;\n\t}\n\n\tvoid export_HIDWrite(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(hidHandle, 0);\t\t  // r3\n\t\tppcDefineParamUStr(data, 1);\t\t\t  // r4\n\t\tppcDefineParamU32(maxLength, 2);\t\t  // r5\n\t\tppcDefineParamMPTR(callbackFuncMPTR, 3);  // r6\n\t\tppcDefineParamMPTR(callbackParamMPTR, 4); // r7\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.HIDWrite(0x{:x},0x{:08x},0x{:08x},0x{:08x},0x{:08x})\", hCPU->gpr[3],\n\t\t\t\t\thCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7]);\n\n\t\tstd::shared_ptr<Device> device = GetDeviceByHandle(hidHandle, true);\n\t\tif (device == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"nsyshid.HIDWrite(): Unable to find device with hid handle {}\", hidHandle);\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\t\tsint32 returnCode = 0;\n\t\tif (callbackFuncMPTR != MPTR_NULL)\n\t\t{\n\t\t\t// asynchronous transfer\n\t\t\tstd::thread(&_hidWriteAsync, device, data, maxLength, callbackFuncMPTR, callbackParamMPTR).detach();\n\t\t\treturnCode = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// synchronous transfer\n\t\t\tStackAllocator<coreinit::OSEvent> event;\n\t\t\tcoreinit::OSInitEvent(&event, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_AUTO);\n\t\t\tstd::future<sint32> res = std::async(std::launch::async, &_hidWriteSync, device, data, maxLength, &event);\n\t\t\tcoreinit::OSWaitEvent(&event);\n\t\t\treturnCode = res.get();\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, returnCode);\n\t}\n\n\tvoid export_HIDDecodeError(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(errorCode, 0);\n\t\tppcDefineParamTypePtr(ukn0, uint32be, 1);\n\t\tppcDefineParamTypePtr(ukn1, uint32be, 2);\n\t\tcemuLog_logDebug(LogType::Force, \"nsyshid.HIDDecodeError(0x{:08x},0x{:08x},0x{:08x})\", hCPU->gpr[3],\n\t\t\t\t\thCPU->gpr[4], hCPU->gpr[5]);\n\n\t\t// todo\n\t\t*ukn0 = 0x3FF;\n\t\t*ukn1 = (uint32)-0x7FFF;\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid Backend::DetachAllDevices()\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(this->m_devicesMutex);\n\t\tif (m_isAttached)\n\t\t{\n\t\t\tfor (const auto& device : this->m_devices)\n\t\t\t{\n\t\t\t\tnsyshid::DetachDevice(device);\n\t\t\t}\n\t\t\tthis->m_devices.clear();\n\t\t}\n\t}\n\n\tbool Backend::AttachDevice(const std::shared_ptr<Device>& device)\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(this->m_devicesMutex);\n\t\tif (m_isAttached && nsyshid::AttachDevice(device))\n\t\t{\n\t\t\tthis->m_devices.push_back(device);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tvoid Backend::DetachDevice(const std::shared_ptr<Device>& device)\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(this->m_devicesMutex);\n\t\tif (m_isAttached)\n\t\t{\n\t\t\tnsyshid::DetachDevice(device);\n\t\t\tthis->m_devices.remove(device);\n\t\t}\n\t}\n\n\tstd::shared_ptr<Device> Backend::FindDevice(std::function<bool(const std::shared_ptr<Device>&)> isWantedDevice)\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(this->m_devicesMutex);\n\t\tauto it = std::find_if(this->m_devices.begin(), this->m_devices.end(), std::move(isWantedDevice));\n\t\tif (it != this->m_devices.end())\n\t\t{\n\t\t\treturn *it;\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tstd::shared_ptr<Device> Backend::FindDeviceById(uint16 vendorId, uint16 productId)\n\t{\n\t\treturn nsyshid::FindDeviceById(vendorId, productId);\n\t}\n\n\tbool Backend::IsDeviceWhitelisted(uint16 vendorId, uint16 productId)\n\t{\n\t\treturn Whitelist::GetInstance().IsDeviceWhitelisted(vendorId, productId);\n\t}\n\n\tBackend::Backend()\n\t\t: m_isAttached(false)\n\t{\n\t}\n\n\tvoid Backend::OnAttach()\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(this->m_devicesMutex);\n\t\tm_isAttached = true;\n\t\tAttachVisibleDevices();\n\t}\n\n\tvoid Backend::OnDetach()\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(this->m_devicesMutex);\n\t\tDetachAllDevices();\n\t\tm_isAttached = false;\n\t}\n\n\tbool Backend::IsBackendAttached()\n\t{\n\t\tstd::lock_guard<std::recursive_mutex> lock(this->m_devicesMutex);\n\t\treturn m_isAttached;\n\t}\n\n\tDevice::Device(uint16 vendorId,\n\t\t\t\t   uint16 productId,\n\t\t\t\t   uint8 interfaceIndex,\n\t\t\t\t   uint8 interfaceSubClass,\n\t\t\t\t   uint8 protocol)\n\t\t: m_hid(nullptr),\n\t\t  m_vendorId(vendorId),\n\t\t  m_productId(productId),\n\t\t  m_interfaceIndex(interfaceIndex),\n\t\t  m_interfaceSubClass(interfaceSubClass),\n\t\t  m_protocol(protocol),\n\t\t  m_maxPacketSizeRX(0x20),\n\t\t  m_maxPacketSizeTX(0x20)\n\t{\n\t}\n\n\tvoid Device::AssignHID(HID_t* hid)\n\t{\n\t\tif (hid != nullptr)\n\t\t{\n\t\t\thid->vendorId = this->m_vendorId;\n\t\t\thid->productId = this->m_productId;\n\t\t\thid->ifIndex = this->m_interfaceIndex;\n\t\t\thid->subClass = this->m_interfaceSubClass;\n\t\t\thid->protocol = this->m_protocol;\n\t\t\thid->ukn04 = 0x11223344;\n\t\t\thid->paddingGuessed0F = 0;\n\t\t\thid->maxPacketSizeRX = this->m_maxPacketSizeRX;\n\t\t\thid->maxPacketSizeTX = this->m_maxPacketSizeTX;\n\t\t}\n\t\tthis->m_hid = hid;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nsyshid\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"nsyshid\", \"HIDAddClient\", export_HIDAddClient);\n\t\t\tosLib_addFunction(\"nsyshid\", \"HIDDelClient\", export_HIDDelClient);\n\t\t\tosLib_addFunction(\"nsyshid\", \"HIDGetDescriptor\", export_HIDGetDescriptor);\n\t\t\tosLib_addFunction(\"nsyshid\", \"HIDSetIdle\", export_HIDSetIdle);\n\t\t\tosLib_addFunction(\"nsyshid\", \"HIDSetProtocol\", export_HIDSetProtocol);\n\t\t\tosLib_addFunction(\"nsyshid\", \"HIDSetReport\", export_HIDSetReport);\n\n\t\t\tosLib_addFunction(\"nsyshid\", \"HIDRead\", export_HIDRead);\n\t\t\tosLib_addFunction(\"nsyshid\", \"HIDWrite\", export_HIDWrite);\n\n\t\t\tosLib_addFunction(\"nsyshid\", \"HIDDecodeError\", export_HIDDecodeError);\n\n\t\t};\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\t// initialise whitelist\n\t\t\t\tWhitelist::GetInstance();\n\t\t\t\tAttachDefaultBackends();\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t}\n\t\t}\n\t}s_COSnsyshidModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnsyshidModule;\n\t}\n\n} // namespace nsyshid\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyshid/nsyshid.h",
    "content": "#pragma once\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nsyshid\n{\n\tclass Backend;\n\n\tvoid AttachBackend(const std::shared_ptr<Backend>& backend);\n\tvoid DetachBackend(const std::shared_ptr<Backend>& backend);\n\n\tCOSModule* GetModule();\n} // namespace nsyshid\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyskbd/nsyskbd.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/nn_common.h\"\n\nnamespace nsyskbd\n{\n\tbool IsValidChannel(uint32 channel)\n\t{\n\t\treturn channel >= 0 && channel < 4;\n\t}\n\n\tuint32 KBDGetChannelStatus(uint32 channel, uint32be* status)\n\t{\n\t\tstatic bool loggedError = false;\n\t\tif (loggedError == false)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"KBDGetChannelStatus() placeholder\");\n\t\t\tloggedError = true;\n\t\t}\n\t\t*status = 1; // disconnected\n\n\t\treturn 0;\n\t}\n\n#pragma pack(push, 1)\n\tstruct KeyState\n\t{\n\t\tuint8be channel;\n\t\tuint8be ukn1;\n\t\tuint8be _padding[2];\n\t\tuint32be ukn4;\n\t\tuint32be ukn8;\n\t\tuint16be uknC;\n\t};\n#pragma pack(pop)\n\tstatic_assert(sizeof(KeyState) == 0xE); // actual size might be padded to 0x10?\n\n\tuint32 KBDGetKey(uint32 channel, KeyState* keyState)\n\t{\n\t\t// used by MSX VC\n\t\tif(!IsValidChannel(channel) || !keyState)\n\t\t{\n\t\t\tcemuLog_log(LogType::APIErrors, \"KBDGetKey(): Invalid parameter\");\n\t\t\treturn 0;\n\t\t}\n\t\tkeyState->channel = channel;\n\t\tkeyState->ukn1 = 0;\n\t\tkeyState->ukn4 = 0;\n\t\tkeyState->ukn8 = 0;\n\t\tkeyState->uknC = 0;\n\t\treturn 0;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nsyskbd\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"nsyskbd\", KBDGetChannelStatus, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"nsyskbd\", KBDGetKey, LogType::Placeholder);\n\t\t};\n\n\t\tvoid RPLUnmapped() override\n\t\t{\n\n\t\t}\n\t}s_COSnsyskbdModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnsyskbdModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsyskbd/nsyskbd.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace nsyskbd\n{\n\tCOSModule* GetModule();\n}\n\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsysnet/nsysnet.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"nsysnet.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_GHS.h\"\n\n#include \"Common/socket.h\"\n\n#if BOOST_OS_UNIX\n\n#define WSAEWOULDBLOCK EWOULDBLOCK\n#define WSAEINPROGRESS EINPROGRESS\n#define WSAESHUTDOWN ESHUTDOWN\n#define WSAECONNABORTED ECONNABORTED\n#define WSAHOST_NOT_FOUND EAI_NONAME\n#define WSAENOTCONN ENOTCONN\n\n#define GETLASTERR errno\n\n#endif // BOOST_OS_UNIX\n\n#if BOOST_OS_WINDOWS\n\n#define GETLASTERR WSAGetLastError()\n\n#endif //BOOST_OS_WINDOWS\n\n#define WU_AF_INET\t\t\t2\n\n#define WU_SOCK_STREAM\t\t1\n#define WU_SOCK_DGRAM\t\t2\n\n#define WU_IPPROTO_IP\t\t0\n#define WU_IPPROTO_TCP\t\t6\n#define WU_IPPROTO_UDP\t\t17\n\n#define WU_SO_REUSEADDR\t\t0x0004\n#define WU_SO_KEEPALIVE\t\t0x0008\n#define WU_SO_DONTROUTE\t\t0x0010\n#define WU_SO_BROADCAST\t\t0x0020\n#define WU_SO_LINGER\t\t0x0080\n#define WU_SO_OOBINLINE\t\t0x0100\n#define WU_SO_TCPSACK\t\t0x0200\n#define WU_SO_WINSCALE\t\t0x0400\n#define WU_SO_SNDBUF\t\t0x1001\n#define WU_SO_RCVBUF\t\t0x1002\n#define WU_SO_SNDLOWAT\t\t0x1003\n#define WU_SO_RCVLOWAT\t\t0x1004\n#define WU_SO_LASTERROR\t\t0x1007\n#define WU_SO_TYPE\t\t\t0x1008\n#define WU_SO_HOPCNT\t\t0x1009\n#define WU_SO_MAXMSG\t\t0x1010\n#define WU_SO_RXDATA\t\t0x1011\n#define WU_SO_TXDATA\t\t0x1012\n#define WU_SO_MYADDR\t\t0x1013\n#define WU_SO_NBIO\t\t\t0x1014\n#define WU_SO_BIO\t\t\t0x1015\n#define WU_SO_NONBLOCK\t\t0x1016\n#define WU_SO_UNKNOWN1019\t0x1019 // tcp related\n#define WU_SO_UNKNOWN101A\t0x101A // tcp related\n#define WU_SO_UNKNOWN101B\t0x101B // tcp related\n#define WU_SO_NOSLOWSTART\t0x4000\n#define WU_SO_RUSRBUF\t\t0x10000\n\n#define WU_TCP_ACKDELAYTIME\t\t0x2001\n#define WU_TCP_NOACKDELAY\t\t0x2002\n#define WU_TCP_MAXSEG\t\t\t0x2003\n#define WU_TCP_NODELAY\t\t\t0x2004\n#define WU_TCP_UNKNOWN\t\t\t0x2005 // amount of mss received before sending an ack\n\n#define WU_IP_TOS\t\t\t\t3\n#define WU_IP_TTL\t\t\t\t4\n#define WU_IP_MULTICAST_IF\t\t9\n#define WU_IP_MULTICAST_TTL\t\t10\n#define WU_IP_MULTICAST_LOOP\t11\n#define WU_IP_ADD_MEMBERSHIP\t12\n#define WU_IP_DROP_MEMBERSHIP\t13\n#define WU_IP_UNKNOWN\t\t\t14\n\n#define WU_SOL_SOCKET\t\t-1 // this constant differs from Win32 socket API\n\n#define WU_MSG_PEEK\t\t\t0x02\n#define WU_MSG_DONTWAIT\t\t0x20\n\n// error codes\n#define WU_SO_SUCCESS\t\t0x0000\n#define WU_SO_EWOULDBLOCK\t0x0006\n#define WU_SO_ECONNRESET\t0x0008\n#define WU_SO_ENOTCONN\t\t0x0009\n#define WU_SO_EINVAL\t\t0x000B\n#define WU_SO_EINPROGRESS\t0x0016\n#define WU_SO_EAFNOSUPPORT  0x0021\n\n#define WU_SO_ESHUTDOWN\t\t0x000F\n\n\ntypedef signed int WUSOCKET;\n\nbool sockLibReady = false;\n\nvoid nsysnetExport_socket_lib_init(PPCInterpreter_t* hCPU)\n{\n\tsockLibReady = true;\n#if BOOST_OS_WINDOWS\n\tWSADATA wsa;\n\tWSAStartup(MAKEWORD(2, 2), &wsa);\n#endif // BOOST_OS_WINDOWS\n\tosLib_returnFromFunction(hCPU, 0); // 0 -> Success\n}\n\nvoid nsysnetExport_socket_lib_finish(PPCInterpreter_t* hCPU)\n{\n\tsockLibReady = false;\n#if BOOST_OS_WINDOWS\n\tWSACleanup();\n#endif // BOOST_OS_WINDOWS\n\tosLib_returnFromFunction(hCPU, 0); // 0 -> Success\n}\n\nvoid _setSockError(sint32 errCode)\n{\n\tcoreinit::__gh_set_errno(errCode);\n}\n\nsint32 _getSockError()\n{\n\treturn coreinit::__gh_get_errno();\n}\n\n// error translation modes for _translateError\n#define _ERROR_MODE_DEFAULT\t\t0\n#define _ERROR_MODE_CONNECT\t\t1\n#define _ERROR_MODE_ACCEPT\t\t2\n\nsint32 _translateError(sint32 returnCode, sint32 wsaError, sint32 mode = _ERROR_MODE_DEFAULT)\n{\n\tif (mode == _ERROR_MODE_ACCEPT)\n\t{\n\t\t// accept mode\n\t\tif (returnCode >= 0)\n\t\t{\n\t\t\t_setSockError(WU_SO_SUCCESS);\n\t\t\treturn returnCode;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// any other mode\n\t\tif (returnCode == 0)\n\t\t{\n\t\t\t_setSockError(WU_SO_SUCCESS);\n\t\t\treturn 0;\n\t\t}\n\t}\n\t// handle WSA error\n\tswitch (wsaError)\n\t{\n\tcase 0:\n\t\t_setSockError(WU_SO_SUCCESS);\n\t\tbreak;\n\tcase WSAEWOULDBLOCK:\n\t\tif( mode == _ERROR_MODE_CONNECT )\n\t\t\t_setSockError(WU_SO_EINPROGRESS);\n\t\telse\n\t\t\t_setSockError(WU_SO_EWOULDBLOCK);\n\t\tbreak;\n\tcase WSAEINPROGRESS:\n\t\t_setSockError(WU_SO_EINPROGRESS);\n\t\tbreak;\n\tcase WSAECONNABORTED:\n\t\tdebug_printf(\"WSAECONNABORTED\\n\");\n#ifdef CEMU_DEBUG_ASSERT\n\t\tassert_dbg();\n#endif\n\t\tbreak;\n\tcase WSAESHUTDOWN:\n\t\t_setSockError(WU_SO_ESHUTDOWN);\n\t\tbreak;\n\tcase WSAENOTCONN:\n\t\t_setSockError(WU_SO_ENOTCONN);\n\t\tbreak;\n\tdefault:\n\t\tcemuLog_logDebug(LogType::Force, \"Unhandled wsaError {}\", wsaError);\n\t\t_setSockError(99999); // unhandled error\n\t}\n\treturn -1;\n}\n\nvoid nsysnetExport_socketlasterr(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Socket, \"socketlasterr() -> {}\", _getSockError());\n\tosLib_returnFromFunction(hCPU, _getSockError());\n}\n\ntypedef struct  \n{\n\tuint32 handle;\n\tbool isShutdownRecv;\n\tbool isShutdownSend;\n\t// socket creation info\n\tsint32 family;\n\tsint32 type;\n\tsint32 protocol;\n\t// host side info\n\tSOCKET s;\n\t// socket options\n\tbool isNonBlocking;\n}virtualSocket_t;\n\ntypedef struct\n{\n\tuint32 wu_s_addr;\n}wu_in_addr;\n\nstruct wu_sockaddr\n{\n\tuint16 sa_family;\n\tuint8  sa_data[14]; // IPv4\n};\n\nvoid sockaddr_guest2host(wu_sockaddr* input, sockaddr* output)\n{\n\toutput->sa_family = _swapEndianU16(input->sa_family);\n\tmemcpy(output->sa_data, input->sa_data, 14);\n}\n\nvoid sockaddr_host2guest(sockaddr* input, wu_sockaddr* output)\n{\n\toutput->sa_family = _swapEndianU16(input->sa_family);\n\tmemcpy(output->sa_data, input->sa_data, 14);\n}\n\nstruct wu_addrinfo \n{\n\tsint32 ai_flags;\n\tsint32 ai_family;\n\tsint32 ai_socktype;\n\tsint32 ai_protocol;\n\tsint32 ai_addrlen;\n\tMPTR   ai_canonname;\n\tMPTR   ai_addr;\n\tMPTR   ai_next;\n};\n\n#define WU_SOCKET_LIMIT\t\t\t(32) // only 32 socket handles are supported per running process\n\nvirtualSocket_t* virtualSocketTable[WU_SOCKET_LIMIT] = { 0 };\n\nsint32 _getFreeSocketHandle()\n{\n\tfor (sint32 i = 0; i < WU_SOCKET_LIMIT; i++)\n\t{\n\t\tif (virtualSocketTable[i] == NULL)\n\t\t\treturn i + 1;\n\t}\n\treturn 0;\n}\n\n#if BOOST_OS_WINDOWS\n#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)\n#endif // BOOST_OS_WINDOWS\n\nWUSOCKET nsysnet_createVirtualSocket(sint32 family, sint32 type, sint32 protocol)\n{\n\tsint32 s = _getFreeSocketHandle();\n\tif (s == 0)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Ran out of socket handles\");\n\t\tcemu_assert(false);\n\t}\n\tvirtualSocket_t* vs = (virtualSocket_t*)malloc(sizeof(virtualSocket_t));\n\tmemset(vs, 0, sizeof(virtualSocket_t));\n\tvs->family = family;\n\tvs->type = type;\n\tvs->protocol = protocol;\n\tvs->handle = s;\n\tvirtualSocketTable[s - 1] = vs;\n\t// init host socket\n\tvs->s = socket(family, type, protocol);\n\t#if BOOST_OS_WINDOWS\n\t// disable reporting of PORT_UNREACHABLE for UDP sockets\n\tif (protocol == IPPROTO_UDP)\n\t{\n\t\tBOOL bNewBehavior = FALSE;\n\t\tDWORD dwBytesReturned = 0;\n\t\tWSAIoctl(vs->s, SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL);\n\t}\n\t#endif // BOOST_OS_WINDOWS\n\treturn vs->handle;\n}\n\nWUSOCKET nsysnet_createVirtualSocketFromExistingSocket(SOCKET existingSocket)\n{\n\tcemuLog_logDebug(LogType::Force, \"nsysnet_createVirtualSocketFromExistingSocket - incomplete\");\n\n\n\tsint32 s = _getFreeSocketHandle();\n\tif (s == 0)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Ran out of socket handles\");\n\t\tcemu_assert(false);\n\t}\n\tvirtualSocket_t* vs = (virtualSocket_t*)malloc(sizeof(virtualSocket_t));\n\tmemset(vs, 0, sizeof(virtualSocket_t));\n#if BOOST_OS_WINDOWS\n\t// SO_TYPE -> type\n\t// SO_BSP_STATE -> protocol + other info\n\t// SO_PROTOCOL_INFO -> protocol + type?\n\n\tWSAPROTOCOL_INFO protocolInfo = { 0 };\n\tint optLen = sizeof(protocolInfo);\n\tgetsockopt(existingSocket, SOL_SOCKET, SO_PROTOCOL_INFO, (char*)&protocolInfo, &optLen);\n\t// todo - translate protocolInfo \n\tvs->family = protocolInfo.iAddressFamily;\n\tvs->type = protocolInfo.iSocketType;\n\tvs->protocol = protocolInfo.iSocketType;\n#else\n\t{\n\t\tint type;\n\t\tsocklen_t optlen;\n\t\tgetsockopt(vs->s, SOL_SOCKET, SO_TYPE, &type, &optlen);\n\t\tvs->type = type;\n\t\tvs->protocol = type;\n\t}\n\t{\n\t\tsockaddr saddr;\n\t\tsocklen_t len;\n\t\tgetsockname(vs->s, &saddr, &len);\n\t\tvs->family = saddr.sa_family;\n\t}\n#endif\n\n\tvs->handle = s;\n\tvirtualSocketTable[s - 1] = vs;\n\tvs->s = existingSocket;\n\treturn vs->handle;\n}\n\nvoid nsysnet_notifyCloseSharedSocket(SOCKET existingSocket)\n{\n\tfor (sint32 i = 0; i < WU_SOCKET_LIMIT; i++)\n\t{\n\t\tif (virtualSocketTable[i] && virtualSocketTable[i]->s == existingSocket)\n\t\t{\n\t\t\t// remove entry\n\t\t\tfree(virtualSocketTable[i]);\n\t\t\tvirtualSocketTable[i] = nullptr;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nvirtualSocket_t* nsysnet_getVirtualSocketObject(WUSOCKET s)\n{\n\tuint8 handleType = 0;\n\ts--;\n\tif (s < 0 || s >= WU_SOCKET_LIMIT)\n\t\treturn NULL;\n\treturn virtualSocketTable[s];\n}\n\nsint32 nsysnet_getVirtualSocketHandleFromHostHandle(SOCKET s)\n{\n\tfor (sint32 i = 0; i < WU_SOCKET_LIMIT; i++)\n\t{\n\t\tif (virtualSocketTable[i] && virtualSocketTable[i]->s == s)\n\t\t\treturn i + 1;\n\t}\n\treturn -1;\n}\n\nvoid nsysnetExport_socket(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"socket({},{},{})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\tppcDefineParamS32(family, 0);\n\tppcDefineParamS32(type, 1);\n\tppcDefineParamS32(protocol, 2);\n\n\tif (sockLibReady == false)\n\t{\n\t\t_setSockError(0x2B);\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\t// below here Ioctl code should start\n\n\t// check family param\n\tif (family != WU_AF_INET)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"socket(): Unsupported family\");\n\t\t// todo - error code\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\t// check type param\n\tif (type != WU_SOCK_STREAM && type != WU_SOCK_DGRAM)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"socket(): Unsupported family\");\n\t\t// todo - error code\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\n\tif (protocol != WU_IPPROTO_TCP && protocol != WU_IPPROTO_UDP && protocol != WU_IPPROTO_IP)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"socket(): Unsupported protocol\");\n\t\t// todo - error code\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\n\tWUSOCKET s = nsysnet_createVirtualSocket(family, type, protocol);\n\tcemuLog_log(LogType::Socket, \"Created socket handle {}\", s);\n\tosLib_returnFromFunction(hCPU, s);\n}\n\nvoid nsysnetExport_mw_socket(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"mw_socket\");\n\tnsysnetExport_socket(hCPU);\n}\n\nvoid nsysnetExport_shutdown(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"shutdown({},{})\", hCPU->gpr[3], hCPU->gpr[4]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamS32(how, 1);\n\n\tsint32 r = 0;\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t}\n\telse\n\t{\n\t\tr = shutdown(vs->s, how);\n\t\tif (how == 0)\n\t\t{\n\t\t\t// shutdown recv\n\t\t\tvs->isShutdownRecv = true;\n\t\t}\n\t\telse if (how == 1)\n\t\t{\n\t\t\t// shutdown send\n\t\t\tvs->isShutdownSend = true;\n\t\t}\n\t\telse if (how == 2)\n\t\t{\n\t\t\t// shutdown recv & send\n\t\t\tvs->isShutdownRecv = true;\n\t\t\tvs->isShutdownSend = true;\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n\t_setSockError(0); // todo\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nsysnetExport_socketclose(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"socketclose({})\", hCPU->gpr[3]);\n\tppcDefineParamS32(s, 0);\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tif (vs)\n\t{\n\t\tclosesocket(vs->s);\n\t\tfree(vs);\n\t\tvirtualSocketTable[s - 1] = NULL;\n\t}\n\tosLib_returnFromFunction(hCPU, 0);\n}\nsint32 _socket_nonblock(SOCKET s, u_long mode)\n{\n#if BOOST_OS_WINDOWS\n\treturn ioctlsocket(s, FIONBIO, &mode);\n#else\n\tint flags = fcntl(s, F_GETFL);\n\tif(mode)\n\t\tflags |= O_NONBLOCK;\n\telse\n\t\tflags &= ~O_NONBLOCK;\n\treturn fcntl(s, F_SETFL, flags);\n#endif\n}\nvoid nsysnetExport_setsockopt(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"setsockopt({},0x{:x},0x{:05x},0x{:08x},{})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamS32(level, 1);\n\tppcDefineParamS32(optname, 2);\n\tppcDefineParamStr(optval, 3);\n\tppcDefineParamS32(optlen, 4);\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tif (!vs)\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n\telse\n\t{\n\t\t// translate level to host API\n\t\tsint32 hostLevel;\n\t\tif (level == WU_SOL_SOCKET)\n\t\t{\n\t\t\thostLevel = SOL_SOCKET;\n\t\t\t// handle op\n\t\t\tif (optname == WU_SO_REUSEADDR)\n\t\t\t{\n\t\t\t\tif (optlen != 4)\n\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\tsint32 optvalLE = _swapEndianU32(*(uint32*)optval);\n\t\t\t\tsint32 r = setsockopt(vs->s, hostLevel, SO_REUSEADDR, (char*)&optvalLE, 4);\n\t\t\t\tif (r != 0)\n\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t}\n\t\t\telse if (optname == WU_SO_NBIO || optname == WU_SO_BIO)\n\t\t\t{\n\t\t\t\t// similar to WU_SO_NONBLOCK but always sets blocking (_BIO) or non-blocking (_NBIO) mode regardless of option value\n\t\t\t\tif (optlen == 4)\n\t\t\t\t{\n\t\t\t\t\tsint32 optvalLE = _swapEndianU32(*(uint32*)optval);\n\t\t\t\t}\n\t\t\t\telse if (optlen == 0)\n\t\t\t\t{\n\t\t\t\t\t// no opt needed\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\tbool setNonBlocking = optname == WU_SO_NBIO;\n\t\t\t\tu_long mode = setNonBlocking ? 1 : 0;\n\t\t\t\t_socket_nonblock(vs->s,  mode);\n\t\t\t\tvs->isNonBlocking = setNonBlocking;\n\t\t\t}\n\t\t\telse if (optname == WU_SO_NONBLOCK)\n\t\t\t{\n\t\t\t\tif (optlen != 4)\n\t\t\t\t\tassert_dbg();\n\t\t\t\tsint32 optvalLE = _swapEndianU32(*(uint32*)optval);\n\t\t\t\tu_long mode = optvalLE;  // 1 -> enable, 0 -> disable\n\t\t\t\t_socket_nonblock(vs->s,  mode);\n\t\t\t\tvs->isNonBlocking = mode != 0;\n\t\t\t}\n\t\t\telse if (optname == WU_SO_KEEPALIVE)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Socket, \"todo: setsockopt() for WU_SO_KEEPALIVE\");\n\t\t\t}\n\t\t\telse if (optname == WU_SO_WINSCALE)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Socket, \"todo: setsockopt() for WU_SO_WINSCALE\");\n\t\t\t}\n\t\t\telse if (optname == WU_SO_RCVBUF)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Socket, \"Set receive buffer size to 0x{:08x}\", _swapEndianU32(*(uint32*)optval));\n\t\t\t\tif (optlen != 4)\n\t\t\t\t\tassert_dbg();\n\t\t\t\tsint32 optvalLE = _swapEndianU32(*(uint32*)optval);\n\t\t\t\tu_long mode = optvalLE;\n\t\t\t\tif (setsockopt(vs->s, SOL_SOCKET, SO_RCVBUF, (const char*)&mode, sizeof(u_long)) != 0)\n\t\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t\telse if (optname == WU_SO_SNDBUF)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Socket, \"Set send buffer size to 0x{:08x}\", _swapEndianU32(*(uint32*)optval));\n\t\t\t\tif (optlen != 4)\n\t\t\t\t\tassert_dbg();\n\t\t\t\tsint32 optvalLE = _swapEndianU32(*(uint32*)optval);\n\t\t\t\tu_long mode = optvalLE;\n\t\t\t\tif (setsockopt(vs->s, SOL_SOCKET, SO_SNDBUF, (const char*)&mode, sizeof(u_long)) != 0)\n\t\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"setsockopt(WU_SOL_SOCKET): Unsupported optname 0x{:08x}\", optname);\n\t\t\t}\n\t\t}\n\t\telse if (level == WU_IPPROTO_TCP)\n\t\t{\n\t\t\thostLevel = IPPROTO_TCP;\n\t\t\tif (optname == WU_TCP_NODELAY)\n\t\t\t{\n\t\t\t\tif (optlen != 4)\n\t\t\t\t\tassert_dbg();\n\t\t\t\tsint32 optvalLE = _swapEndianU32(*(uint32*)optval);\n\t\t\t\tu_long mode = optvalLE;  // 1 -> enable, 0 -> disable\n\t\t\t\tif (setsockopt(vs->s, IPPROTO_TCP, TCP_NODELAY, (const char*)&mode, sizeof(u_long)) != 0)\n\t\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"setsockopt(WU_IPPROTO_TCP): Unsupported optname 0x{:08x}\", optname);\n\t\t\t}\n\t\t}\n\t\telse if (level == WU_IPPROTO_IP)\n\t\t{\n\t\t\thostLevel = IPPROTO_IP;\n\t\t\tif (optname == WU_IP_MULTICAST_IF || optname == WU_IP_MULTICAST_TTL ||\n\t\t\t\toptname == WU_IP_MULTICAST_LOOP || optname == WU_IP_ADD_MEMBERSHIP ||\n\t\t\t\toptname == WU_IP_DROP_MEMBERSHIP)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Socket, \"todo: setsockopt() for multicast\");\n\t\t\t}\n\t\t\telse if(optname == WU_IP_TTL || optname == WU_IP_TOS)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"setsockopt(WU_IPPROTO_IP): Unsupported optname 0x{:08x}\", optname);\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid nsysnetExport_getsockopt(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"getsockopt({},0x{:x},0x{:05x},0x{:08x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamS32(level, 1);\n\tppcDefineParamS32(optname, 2);\n\tppcDefineParamStr(optval, 3);\n\tppcDefineParamMPTR(optlenMPTR, 4);\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tif (vs == NULL)\n\t{\n\t\tcemu_assert_debug(false); // todo\n\t\treturn;\n\t}\n\n\tsint32 r = 0;\n\n\t// translate level to host API\n\tsint32 hostLevel;\n\tif (level == WU_SOL_SOCKET)\n\t{\n\t\thostLevel = SOL_SOCKET;\n\t\t// handle op\n\t\tif (optname == WU_SO_LASTERROR)\n\t\t{\n\t\t\tint optvalLE = 0;\n\t\t\tsocklen_t optlenLE = 4;\n\t\t\tr = getsockopt(vs->s, hostLevel, SO_ERROR, (char*)&optvalLE, &optlenLE);\n\t\t\tr = _translateError(r, GETLASTERR);\n\t\t\tif (memory_readU32(optlenMPTR) != 4)\n\t\t\t\tassert_dbg();\n\t\t\tmemory_writeU32(optlenMPTR, 4);\n\t\t\tif (optvalLE != 0)\n\t\t\t\tassert_dbg(); // todo -> Translate error code/status\n\t\t\t*(uint32*)optval = _swapEndianU32(optvalLE);\n\t\t\t// YouTube app uses this to check if the connection attempt was successful after non-blocking connect()\n\t\t}\n\t\telse if (optname == WU_SO_RCVBUF)\n\t\t{\n\t\t\tint optvalLE = 0;\n\t\t\tsocklen_t optlenLE = 4;\n\t\t\tr = getsockopt(vs->s, hostLevel, SO_RCVBUF, (char*)&optvalLE, &optlenLE);\n\t\t\tr = _translateError(r, GETLASTERR);\n\t\t\tif (memory_readU32(optlenMPTR) != 4)\n\t\t\t\tassert_dbg();\n\t\t\tmemory_writeU32(optlenMPTR, 4);\n\t\t\t*(uint32*)optval = _swapEndianU32(optvalLE);\n\t\t\t// used by Amazon Video app when a video starts playing\n\t\t}\n\t\telse if (optname == WU_SO_SNDBUF)\n\t\t{\n\t\t\tint optvalLE = 0;\n\t\t\tsocklen_t optlenLE = 4;\n\t\t\tr = getsockopt(vs->s, hostLevel, SO_SNDBUF, (char*)&optvalLE, &optlenLE);\n\t\t\tr = _translateError(r, GETLASTERR);\n\t\t\tif (memory_readU32(optlenMPTR) != 4)\n\t\t\t\tassert_dbg();\n\t\t\tmemory_writeU32(optlenMPTR, 4);\n\t\t\t*(uint32*)optval = _swapEndianU32(optvalLE);\n\t\t\t// used by Lost Reavers after some loading screens\n\t\t}\n\t\telse if (optname == WU_SO_TYPE)\n\t\t{\n\t\t\tif (memory_readU32(optlenMPTR) != 4)\n\t\t\t\tassert_dbg();\n\t\t\tint optvalLE = 0;\n\t\t\tsocklen_t optlenLE = 4;\n\t\t\tmemory_writeU32(optlenMPTR, 4);\n\t\t\t*(uint32*)optval = _swapEndianU32(vs->type);\n\t\t\tr = WU_SO_SUCCESS;\n\t\t}\n        else if (optname == WU_SO_NONBLOCK)\n        {\n            if (memory_readU32(optlenMPTR) != 4)\n                assert_dbg();\n            int optvalLE = 0;\n            socklen_t optlenLE = 4;\n            memory_writeU32(optlenMPTR, 4);\n            *(uint32*)optval = _swapEndianU32(vs->isNonBlocking ? 1 : 0);\n            r = WU_SO_SUCCESS;\n        }\n\t\telse\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"getsockopt(WU_SOL_SOCKET): Unsupported optname 0x{:08x}\", optname);\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"getsockopt(): Unsupported level 0x{:08x}\", level);\n\t}\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nsysnetExport_inet_aton(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStr(ip, 0);\n\tppcDefineParamStructPtr(addr, wu_in_addr, 1);\n\tcemuLog_log(LogType::Socket, \"inet_aton(\\\"{}\\\",0x{:08x})\", ip, hCPU->gpr[4]);\n\n\t// _parse_ipad -> todo\n\tsint32 d0, d1, d2, d3;\n\tif (sscanf(ip, \"%d.%d.%d.%d\", &d0, &d1, &d2, &d3) != 4)\n\t{\n\t\tcemu_assert_debug(false);\n\t\tosLib_returnFromFunction(hCPU,  0); // todo - return correct error code\n\t\treturn;\n\t}\n\n\tif (d0 < 0 || d0 > 255 ||\n\t\td1 < 0 || d1 > 255 ||\n\t\td2 < 0 || d2 > 255 ||\n\t\td3 < 0 || d3 > 255)\n\t{\n\t\tcemu_assert_debug(false);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\n\taddr->wu_s_addr = _swapEndianU32((d0 << 24) | (d1 << 16) | (d2 << 8) | (d3 << 0));\n\n\tosLib_returnFromFunction(hCPU, 1); // 0 -> error, 1 -> success\n}\n\nvoid nsysnetExport_inet_pton(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamS32(af, 0);\n\tppcDefineParamStr(ip, 1);\n\tppcDefineParamStructPtr(addr, wu_in_addr, 2);\n\t\n\tif (af != 2)\n\t{\n\t\tcemuLog_log(LogType::Force, \"inet_pton() only supports AF_INET\");\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\n\tsint32 d0, d1, d2, d3;\n\tbool invalidIp = false;\n\tif (sscanf(ip, \"%d.%d.%d.%d\", &d0, &d1, &d2, &d3) != 4)\n\t\tinvalidIp = true;\n\tif (d0 < 0 || d0 > 255)\n\t\tinvalidIp = true;\n\tif (d1 < 0 || d1 > 255)\n\t\tinvalidIp = true;\n\tif (d2 < 0 || d2 > 255)\n\t\tinvalidIp = true;\n\tif (d3 < 0 || d3 > 255)\n\t\tinvalidIp = true;\n\tif (invalidIp)\n\t{\n\t\tcemuLog_log(LogType::Socket, \"inet_pton({}, \\\"{}\\\", 0x{:08x}) -> Invalid ip\", af, ip, hCPU->gpr[5]);\n        _setSockError(WU_SO_EAFNOSUPPORT);\n\t\tosLib_returnFromFunction(hCPU, 0); // 0 -> invalid address\n\t\treturn;\n\t}\n\n\taddr->wu_s_addr = _swapEndianU32((d0 << 24) | (d1 << 16) | (d2 << 8) | (d3 << 0));\n\tcemuLog_log(LogType::Socket, \"inet_pton({}, \\\"{}\\\", 0x{:08x}) -> Ok\", af, ip, hCPU->gpr[5]);\n\n\tosLib_returnFromFunction(hCPU, 1); // 1 -> success\n}\n\nnamespace nsysnet\n{\n    const char* inet_ntop(sint32 af, const void* src, char* dst, uint32 size)\n    {\n        if( af != WU_AF_INET)\n        {\n            // set error\n            _setSockError(WU_SO_EAFNOSUPPORT);\n            return nullptr;\n        }\n        const uint8* ip = (const uint8*)src;\n        char buf[32];\n        sprintf(buf, \"%d.%d.%d.%d\", ip[0], ip[1], ip[2], ip[3]);\n        size_t bufLen = strlen(buf);\n        if( (bufLen+1) > size )\n        {\n            // set error\n            _setSockError(WU_SO_EAFNOSUPPORT);\n            return nullptr;\n        }\n        strcpy(dst, buf);\n        cemuLog_log(LogType::Socket, \"inet_ntop -> {}\", buf);\n        return dst;\n    }\n}\n\nMEMPTR<char> _ntoa_tempString = nullptr;\n\nvoid nsysnetExport_inet_ntoa(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(addr, wu_in_addr, 0);\n\tcemuLog_log(LogType::Socket, \"inet_ntoa(0x{:08x})\", hCPU->gpr[3]);\n\n\tif (_ntoa_tempString == nullptr)\n\t\t_ntoa_tempString = (char*)memory_getPointerFromVirtualOffset(OSAllocFromSystem(64, 4));\n\n\tsprintf(_ntoa_tempString.GetPtr(), \"%d.%d.%d.%d\", ((uint8*)addr)[0], ((uint8*)addr)[1], ((uint8*)addr)[2], ((uint8*)addr)[3]);\n\n\tosLib_returnFromFunction(hCPU, _ntoa_tempString.GetMPTR());\n}\n\nvoid nsysnetExport_htons(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"htons(0x{:04x})\", hCPU->gpr[3]);\n\tppcDefineParamU32(v, 0);\n\tosLib_returnFromFunction(hCPU, v); // return value as-is\n}\n\nvoid nsysnetExport_htonl(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"htonl(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamU32(v, 0);\n\tosLib_returnFromFunction(hCPU, v); // return value as-is\n}\n\nvoid nsysnetExport_ntohs(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"ntohs(0x{:04x})\", hCPU->gpr[3]);\n\tppcDefineParamU32(v, 0);\n\tosLib_returnFromFunction(hCPU, v); // return value as-is\n}\n\nvoid nsysnetExport_ntohl(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"ntohl(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamU32(v, 0);\n\tosLib_returnFromFunction(hCPU, v); // return value as-is\n}\n\nvoid nsysnetExport_bind(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"bind({},0x{:08x},{})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStructPtr(addr, struct wu_sockaddr, 1);\n\tppcDefineParamS32(len, 2);\n\n\n\tif (len != sizeof(struct wu_sockaddr))\n\t\tassert_dbg();\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tsint32 r = 0;\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t}\n\telse\n\t{\n\t\tif (sizeof(sockaddr) != 16)\n\t\t\tassert_dbg();\n\t\tsockaddr hostAddr;\n\t\thostAddr.sa_family = _swapEndianU16(addr->sa_family);\n\t\tmemcpy(hostAddr.sa_data, addr->sa_data, 14);\n\t\tsint32 hr = bind(vs->s, &hostAddr, sizeof(sockaddr));\n\t\tr = _translateError(hr, GETLASTERR);\n\n\n\t\tcemuLog_log(LogType::Socket, \"bind address: {}.{}.{}.{}:{} result: {}\", addr->sa_data[2], addr->sa_data[3], addr->sa_data[4], addr->sa_data[5], _swapEndianU16(*(uint16*)addr->sa_data), hr);\n\n\t}\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nsysnetExport_listen(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"listen({},{})\", hCPU->gpr[3], hCPU->gpr[4]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamS32(queueSize, 1);\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tsint32 r = 0;\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t}\n\telse\n\t{\n\t\tsint32 hr = listen(vs->s, queueSize);\n\t\tif (hr != 0)\n\t\t\tr = -1;\n\t\t// todo: Set proper coreinit errno (via _setSockError)\n\t}\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nsysnetExport_accept(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"accept({},0x{:08x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStructPtr(addr, struct wu_sockaddr, 1);\n\tppcDefineParamMPTR(lenMPTR, 2);\n\n\tsint32 r = 0;\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t\t// todo\n\t\treturn;\n\t}\n\n\tif (memory_readU32(lenMPTR) != 16)\n\t{\n\t\tcemuLog_log(LogType::Force, \"invalid sockaddr len in accept()\");\n\t\tcemu_assert_debug(false);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\n\tif (vs->isNonBlocking)\n\t{\n\t\tsockaddr hostAddr;\n\t\tsocklen_t hostLen = sizeof(sockaddr);\n\t\tSOCKET hr = accept(vs->s, &hostAddr, &hostLen);\n\t\tif (hr != SOCKET_ERROR)\n\t\t{\n\t\t\tr = nsysnet_createVirtualSocketFromExistingSocket(hr);\n\t\t\t_setSockError(WU_SO_SUCCESS);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tr = _translateError((sint32)hr, (sint32)GETLASTERR, _ERROR_MODE_ACCEPT);\n\t\t}\n\t\tsockaddr_host2guest(&hostAddr, addr);\n\t}\n\telse\n\t{\n\t\t// blocking accept is not supported yet\n\t\tcemuLog_log(LogType::Force, \"blocking accept() not supported\");\n\t\tcemu_assert_debug(false);\n\t}\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nsysnetExport_connect(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"connect({},0x{:08x},{})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStructPtr(addr, struct wu_sockaddr, 1);\n\tppcDefineParamS32(len, 2);\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tsint32 r = 0;\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t\treturn;\n\t}\n\n\tif (sizeof(sockaddr) != 16)\n\t\tassert_dbg();\n\tsockaddr hostAddr;\n\thostAddr.sa_family = _swapEndianU16(addr->sa_family);\n\tmemcpy(hostAddr.sa_data, addr->sa_data, 14);\n\tsint32 hr = connect(vs->s, &hostAddr, sizeof(sockaddr));\n\tcemuLog_log(LogType::Force, \"Attempt connect to {}.{}.{}.{}:{}\", (sint32)(uint8)hostAddr.sa_data[2], (sint32)(uint8)hostAddr.sa_data[3], (sint32)(uint8)hostAddr.sa_data[4], (sint32)(uint8)hostAddr.sa_data[5], _swapEndianU16(*(uint16*)hostAddr.sa_data+0));\n\n\tr = _translateError(hr, GETLASTERR, _ERROR_MODE_CONNECT);\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid _setSocketSendRecvNonBlockingMode(SOCKET s, bool isNonBlocking)\n{\n\tu_long mode = isNonBlocking ? 1 : 0;\n\tsint32 r = _socket_nonblock(s,  mode);\n}\n\nvoid nsysnetExport_send(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"send({},0x{:08x},{},0x{:x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStr(msg, 1);\n\tppcDefineParamS32(len, 2);\n\tppcDefineParamS32(flags, 3);\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tsint32 r = 0;\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t\treturn;\n\t}\n\tint hostFlags = 0;\n\tbool requestIsNonBlocking = (flags&WU_MSG_DONTWAIT) != 0;\n\tflags &= ~WU_MSG_DONTWAIT;\n\tif (requestIsNonBlocking != vs->isNonBlocking && vs->isNonBlocking == false)\n\t\tassert_dbg();\n\n\tif (flags)\n\t\tassert_dbg();\n\n\tsint32 hr = send(vs->s, msg, len, hostFlags);\n\tcemuLog_log(LogType::Socket, \"Sent {} bytes\", hr);\n\t_translateError(hr <= 0 ? -1 : 0, GETLASTERR);\n\tr = hr;\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nsysnetExport_recv(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"recv({},0x{:08x},{},0x{:x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStr(msg, 1);\n\tppcDefineParamS32(len, 2);\n\tppcDefineParamS32(flags, 3);\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tsint32 r = 0;\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t\treturn;\n\t}\n\tint hostFlags = 0;\n\tbool requestIsNonBlocking = (flags&WU_MSG_DONTWAIT) != 0;\n\tflags &= ~WU_MSG_DONTWAIT;\n\tif (flags&WU_MSG_PEEK)\n\t{\n\t\thostFlags |= MSG_PEEK;\n\t\tflags &= ~WU_MSG_PEEK;\n\t}\n\n\tif (vs->isNonBlocking)\n\t\trequestIsNonBlocking = vs->isNonBlocking; // non-blocking sockets always operate in MSG_DONTWAIT mode?\n\n\tif (flags)\n\t\tassert_dbg();\n\tif (requestIsNonBlocking != vs->isNonBlocking)\n\t\t_setSocketSendRecvNonBlockingMode(vs->s, requestIsNonBlocking);\n\t// if blocking, yield thread until there is an error or at least 1 byte was received\n\tif (requestIsNonBlocking == false)\n\t{\n\t\t_setSocketSendRecvNonBlockingMode(vs->s, true);\n\t\twhile (true)\n\t\t{\n\t\t\tchar tempBuffer[1];\n\t\t\tsint32 tr = recv(vs->s, tempBuffer, 1, MSG_PEEK);\n\t\t\tif (tr == 1)\n\t\t\t\tbreak;\n\t\t\tif (tr == 0)\n\t\t\t\tbreak; // connection closed\n\t\t\tif (tr < 0 && GETLASTERR != WSAEWOULDBLOCK)\n\t\t\t\tbreak;\n\t\t\t// yield thread\n\t\t\tcoreinit::OSSleepTicks(coreinit::EspressoTime::GetTimerClock() / 5000); // let thread wait 0.2ms to give other threads CPU time\n\t\t\t// todo - eventually we should find a way to asynchronously signal recv instead of busy-looping here\n\t\t}\n\t\t_setSocketSendRecvNonBlockingMode(vs->s, requestIsNonBlocking);\n\t}\n\t// receive\n\tsint32 hr = recv(vs->s, msg, len, hostFlags);\n\t_translateError(hr <= 0 ? -1 : 0, GETLASTERR);\n\tif (requestIsNonBlocking != vs->isNonBlocking)\n\t\t_setSocketSendRecvNonBlockingMode(vs->s, vs->isNonBlocking);\n\tcemuLog_log(LogType::Socket, \"Received {} bytes\", hr);\n\tr = hr;\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nstruct wu_timeval \n{\n\tuint32 tv_sec;\n\tuint32 tv_usec;\n};\n\nvoid _translateFDSet(fd_set* hostSet, struct wu_fd_set* fdset, sint32 nfds, int *hostnfds)\n{\n\tFD_ZERO(hostSet);\n\tif (fdset == NULL)\n\t\treturn;\n\n#if BOOST_OS_UNIX\n\tint maxfd;\n\tif(hostnfds)\n\t\tmaxfd = *hostnfds;\n\telse\n\t\tmaxfd = -1;\n#endif\n\n\tuint32 mask = fdset->mask;\n\tfor (sint32 i = 0; i < nfds; i++)\n\t{\n\t\tif( ((mask>>i)&1) == 0 )\n\t\t\tcontinue;\n\t\tsint32 socketHandle = i;\n\t\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(socketHandle);\n\t\tif(vs == NULL)\n\t\t\tcontinue; // socket invalid\n\n#if BOOST_OS_UNIX\n\t\tif(vs->s > maxfd)\n\t\t\tmaxfd = vs->s;\n#endif\n\n\t\tFD_SET(vs->s, hostSet);\n\t}\n\n#if BOOST_OS_UNIX\n\tif(hostnfds)\n\t\t*hostnfds = maxfd;\n#endif\n}\n\nvoid _translateFDSetRev(struct wu_fd_set* fdset, fd_set* hostSet, sint32 nfds)\n{\n\tif (fdset == NULL)\n\t\treturn;\n\tuint32 mask = _swapEndianU32(0);\n#if BOOST_OS_WINDOWS\n\tfor (sint32 i = 0; i < (sint32)hostSet->fd_count; i++)\n\t{\n\t\tsint32 virtualSocketHandle = nsysnet_getVirtualSocketHandleFromHostHandle(hostSet->fd_array[i]);\n\t\tif (virtualSocketHandle < 0)\n\t\t\tcemu_assert_debug(false);\n\t\tmask |= (1<<virtualSocketHandle);\n\t}\n#else\n\tfor (sint32 i = 0; i < WU_SOCKET_LIMIT; i++)\n\t{\n\t\tif (virtualSocketTable[i] && virtualSocketTable[i]->s && FD_ISSET(virtualSocketTable[i]->s, hostSet))\n\t\t\tmask |= (1 << virtualSocketTable[i]->handle);\n\t}\n#endif\n\tfdset->mask = mask;\n\n}\n\nvoid nsysnetExport_select(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"select({},0x{:08x},0x{:08x},0x{:08x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7]);\n\tppcDefineParamS32(nfds, 0);\n\tppcDefineParamStructPtr(readfds, struct wu_fd_set, 1);\n\tppcDefineParamStructPtr(writefds, struct wu_fd_set, 2);\n\tppcDefineParamStructPtr(exceptfds, struct wu_fd_set, 3);\n\tppcDefineParamStructPtr(timeOut, struct wu_timeval, 4);\n\n\t//cemuLog_log(LogType::Socket, \"rm {:08x} wm {:08x} em {:08x}\", readfds ? _swapEndianU32(readfds->mask) : 0, writefds ? _swapEndianU32(writefds->mask) : 0, exceptfds ? _swapEndianU32(exceptfds->mask) : 0);\n\n\tsint32 r = 0;\n\n\t// translate fd_set\n\tfd_set _readfds, _writefds, _exceptfds;\n\n\t// handle empty select\n\tif ((readfds == NULL || readfds->mask == 0) && (writefds == NULL || writefds->mask == 0) && (exceptfds == NULL || exceptfds->mask == 0))\n\t{\n\t\tif (timeOut == NULL || (timeOut->tv_sec == 0 && timeOut->tv_usec == 0))\n\t\t{\n\t\t\t// return immediately\n\t\t\tcemuLog_log(LogType::Socket, \"select returned immediately because of empty fdsets without timeout\");\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//// empty select with timeout is not allowed\n\t\t\t//_setSockError(WU_SO_EINVAL);\n\t\t\t//osLib_returnFromFunction(hCPU, -1);\n\t\t\t//cemuLog_log(LogType::Socket, \"select returned SO_EINVAL because of empty fdsets with timeout\");\n\n\t\t\t// when fd sets are empty but timeout is set, then just wait and do nothing?\n\t\t\t// Lost Reavers seems to expect this case to return 0 (it hardcodes empty fd sets and timeout comes from curl_multi_timeout)\n\n\t\t\ttimeval tv;\n\t\t\ttv.tv_sec = timeOut->tv_sec;\n\t\t\ttv.tv_usec = timeOut->tv_usec;\n\t\t\tselect(0, nullptr, nullptr, nullptr, &tv);\n\t\t\tcemuLog_log(LogType::Socket, \"select returned 0 because of empty fdsets with timeout\");\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\t\n\t\t\treturn;\n\t\t}\n\t}\n\n\n\n\ttimeval tv = { 0 };\n\n\tif (timeOut == NULL)\n\t{\n\t\t// return immediately\n\t\tcemuLog_log(LogType::Socket, \"select returned immediately because of null timeout\");\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\n\tuint64 msTimeout = (_swapEndianU32(timeOut->tv_usec) / 1000) + (_swapEndianU32(timeOut->tv_sec) * 1000);\n\tuint32 startTime = GetTickCount();\n\twhile (true)\n\t{\n\t\tint hostnfds = -1;\n\t\t_translateFDSet(&_readfds, readfds, nfds, &hostnfds);\n\t\t_translateFDSet(&_writefds, writefds, nfds, &hostnfds);\n\t\t_translateFDSet(&_exceptfds, exceptfds, nfds, &hostnfds);\n\t\tr = select(hostnfds + 1, readfds ? &_readfds : NULL, writefds ? &_writefds : NULL, exceptfds ? &_exceptfds : NULL, &tv);\n\t\tif (r < 0)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"select() failed\");\n\t\t\t// timeout\n\t\t\t_translateError(r, GETLASTERR);\n\t\t\t//_setSockError(WU_SO_SUCCESS);\n\t\t\t// in case of error, clear all FD sets (?)\n\t\t\tif (readfds)\n\t\t\t\treadfds->mask = 0;\n\t\t\tif (writefds)\n\t\t\t\twritefds->mask = 0;\n\t\t\tif (exceptfds)\n\t\t\t\texceptfds->mask = 0;\n\t\t\tbreak;\n\t\t}\n\t\telse if (r == 0)\n\t\t{\n\t\t\t// check for timeout\n\t\t\tif ((GetTickCount() - startTime) >= msTimeout )\n\t\t\t{\n\t\t\t\t// timeout\n\t\t\t\t_setSockError(WU_SO_SUCCESS);\n\t\t\t\tr = 0;\n\t\t\t\t// in case of timeout, clear all FD sets\n\t\t\t\tif (readfds)\n\t\t\t\t\treadfds->mask = 0;\n\t\t\t\tif (writefds)\n\t\t\t\t\twritefds->mask = 0;\n\t\t\t\tif (exceptfds)\n\t\t\t\t\texceptfds->mask = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// yield thread\n\t\t\tPPCCore_switchToScheduler();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// cemuLog_log(LogType::Socket, \"select returned {}. Read {} Write {} Except {}\", r, _readfds.fd_count, _writefds.fd_count, _exceptfds.fd_count);\n\t\t\tcemuLog_log(LogType::Socket, \"select returned {}.\", r);\n\n\t\t\t_translateFDSetRev(readfds, &_readfds, nfds);\n\t\t\t_translateFDSetRev(writefds, &_writefds, nfds);\n\t\t\t_translateFDSetRev(exceptfds, &_exceptfds, nfds);\n\t\t\tbreak;\n\t\t}\n\t}\n\t//cemuLog_log(LogType::Force, \"selectEndTime {}\", timeGetTime());\n\n\n\t//extern int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,\n\t//\tstruct timeval *timeout);\n\n\tcemuLog_log(LogType::Socket, \"select returned {}\", r);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nsysnetExport_getsockname(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"getsockname({},0x{:08x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStructPtr(addr, struct wu_sockaddr, 1);\n\tppcDefineParamStructPtr(lenPtr, uint32, 2);\n\tsint32 r = 0;\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t}\n\telse\n\t{\n\t\tstruct sockaddr hostAddr;\n\t\tsocklen_t hostLen = sizeof(struct sockaddr);\n\t\tsint32 hr = getsockname(vs->s, &hostAddr, &hostLen);\n\t\tif (hr == 0)\n\t\t{\n\t\t\taddr->sa_family = _swapEndianU16(hostAddr.sa_family);\n\t\t\tmemcpy(addr->sa_data, hostAddr.sa_data, 14);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t\t//sint32 hr = listen(vs->s, queueSize);\n\t\t//if (hr != 0)\n\t\t//\tr = -1;\n\t\t//// todo: Set proper coreinit errno (via _setSockError)\n\t}\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nsysnetExport_getpeername(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStructPtr(name, struct wu_sockaddr, 1);\n\tppcDefineParamU32BEPtr(nameLen, 2);\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tif (vs == NULL)\n\t{\n\t\t// todo: Return correct error\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\n\tsockaddr saddr;\n\tsocklen_t saddrLen = sizeof(sockaddr);\n\n\tif (*nameLen < (uint32be)16)\n\t\tassert_dbg();\n\n\tsint32 r = getpeername(vs->s, &saddr, &saddrLen);\n\tr = _translateError(r, GETLASTERR);\n\n\tname->sa_family = _swapEndianU16(saddr.sa_family);\n\tmemcpy(name->sa_data, saddr.sa_data, 14);\n\t*nameLen = 16;\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\ntypedef struct\n{\n\tMPTR h_name;\n\tMPTR h_aliases;\n\tsint32 h_addrType;\n\tsint32 h_length;\n\tMPTR h_addr_list;\n}wu_hostent;\n\nMPTR _allocString(char* str)\n{\n\tsint32 len = (sint32)strlen(str);\n\tMPTR strMPTR = coreinit_allocFromSysArea(len+1, 4);\n\tstrcpy((char*)memory_getPointerFromVirtualOffset(strMPTR), str);\n\treturn strMPTR;\n}\n\nvoid nsysnetExport_gethostbyname(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStr(name, 0);\n\n\tcemuLog_log(LogType::Socket, \"gethostbyname(\\\"{}\\\")\", name);\n\n\thostent* he = gethostbyname(name);\n\tif (he == NULL)\n\t{\n\t\tosLib_returnFromFunction(hCPU, MPTR_NULL);\n\t\treturn;\n\t}\n\n\n\tMPTR hostentMPTR = coreinit_allocFromSysArea(sizeof(wu_hostent)*1, 4);\n\tMPTR hostentAddrListMPTR = coreinit_allocFromSysArea(sizeof(MPTR) * 2, 4);\n\tMPTR hostentAddrListEntriesMPTR = coreinit_allocFromSysArea(sizeof(wu_in_addr) * 1, 4);\n\n\twu_hostent* wuHostent = (wu_hostent*)memory_getPointerFromVirtualOffset(hostentMPTR);\n\tMPTR* addrList = (MPTR*)memory_getPointerFromVirtualOffset(hostentAddrListMPTR);\n\n\twuHostent->h_addrType = _swapEndianU32((uint32)he->h_addrtype);\n\twuHostent->h_length = _swapEndianU32((uint32)he->h_length);\n\n\twuHostent->h_name = _swapEndianU32(_allocString(he->h_name));\n\twuHostent->h_addr_list = _swapEndianU32(hostentAddrListMPTR);\n\n\t//memory_writeU32(hostentAddrListEntriesMPTR, _swapEndianU32(*(uint32*)he->h_addr_list[0]));\n \n\twu_in_addr* addrListEntries = (wu_in_addr*)memory_getPointerFromVirtualOffset(hostentAddrListEntriesMPTR);\n\taddrListEntries->wu_s_addr = *(uint32*)he->h_addr_list[0]; // address is already in network (big-endian) order\n\n\tmemory_writeU32(hostentAddrListMPTR + 4 * 0, hostentAddrListEntriesMPTR);\n\tmemory_writeU32(hostentAddrListMPTR + 4 * 1, MPTR_NULL);\n\n\tosLib_returnFromFunction(hCPU, hostentMPTR);\n\treturn;\n}\n\nSysAllocator<wu_hostent> _staticHostent;\nSysAllocator<char, 256> _staticHostentName;\nSysAllocator<MPTR, 32> _staticHostentPtrList;\nSysAllocator<wu_in_addr> _staticHostentEntries;\n\nvoid nsysnetExport_gethostbyaddr(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStr(addr, 0);\n\tppcDefineParamS32(len, 1);\n\tppcDefineParamS32(type, 2);\n\n\tsint32 maxNumEntries = 31;\n\n\tcemuLog_log(LogType::Socket, \"gethostbyaddr(\\\"{}\\\", {}, {})\", addr, len, type);\n\n\thostent* he = gethostbyaddr(addr, len, type);\n\tif (he == nullptr)\n\t{\n\t\tcemuLog_log(LogType::Socket, \"gethostbyaddr(\\\"{}\\\", {}, {}) failed\", addr, len, type);\n\t\tosLib_returnFromFunction(hCPU, MPTR_NULL);\n\t\treturn;\n\t}\n\n#ifdef CEMU_DEBUG_ASSERT\n\tif (he->h_addrtype != AF_INET)\n\t\tassert_dbg();\n\tif (he->h_length != sizeof(in_addr))\n\t\tassert_dbg();\n#endif\n\n\twu_hostent* wuHostent = _staticHostent.GetPtr();\n\t// setup wuHostent->h_name\t\n\twuHostent->h_name = _swapEndianU32(_staticHostentName.GetMPTR());\n\tif (he->h_name && strlen(he->h_name) < 255)\n\t{\n\t\tstrcpy(_staticHostentName.GetPtr(), he->h_name);\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"he->h_name not set or name too long\");\n\t\tstrcpy(_staticHostentName.GetPtr(), \"\");\n\t}\n\t// setup wuHostent address list\n\twuHostent->h_addrType = _swapEndianU32(WU_AF_INET);\n\twuHostent->h_addr_list = _swapEndianU32(_staticHostentPtrList.GetMPTR());\n\twuHostent->h_length = _swapEndianU32(sizeof(wu_in_addr));\n\tfor (sint32 i = 0; i < maxNumEntries; i++)\n\t{\n\t\tif (he->h_addr_list[i] == nullptr)\n\t\t{\n\t\t\t_staticHostentPtrList.GetPtr()[i] = MPTR_NULL;\n\t\t\tbreak;\n\t\t}\n\t\tmemcpy(_staticHostentEntries.GetPtr() + i, he->h_addr_list[i], sizeof(in_addr));\n\t\t_staticHostentPtrList.GetPtr()[i] = _swapEndianU32(memory_getVirtualOffsetFromPointer(_staticHostentEntries.GetPtr() + i));\n\t}\n\t_staticHostentPtrList.GetPtr()[31] = MPTR_NULL;\n\t// aliases are ignored for now\n\twuHostent->h_aliases = MPTR_NULL;\n\n\tosLib_returnFromFunction(hCPU, _staticHostent.GetMPTR());\n\treturn;\n}\n\nvoid nsysnetExport_getaddrinfo(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStr(nodeName, 0);\n\tppcDefineParamStr(serviceName, 1);\n\tppcDefineParamStructPtr(hints, struct wu_addrinfo, 2);\n\tppcDefineParamMPTR(results, 3);\n\n\tcemuLog_log(LogType::Socket, \"getaddrinfo(\\\"{}\\\",0x{:08x},0x{:08x},0x{:08x})\", nodeName, hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\t\n\tsint32 r = 0;\n\n\t// todo1: This is really slow. Make it asynchronous\n\t// todo2: Should this set the socket last error code? \n\n\tstruct addrinfo hint = { 0 };\n\tif (hints)\n\t{\n\t\thint.ai_family = _swapEndianU32(hints->ai_family);\n\t\thint.ai_socktype = _swapEndianU32(hints->ai_socktype);\n\t\thint.ai_flags = _swapEndianU32(hints->ai_flags);\n\t\thint.ai_protocol = _swapEndianU32(hints->ai_protocol);\n\t}\n\telse\n\t{\n\t\thint.ai_family = 0;\n\t\thint.ai_socktype = 0;\n\t\thint.ai_flags = 0;\n\t\thint.ai_protocol = 0;\n\t}\n\tstruct addrinfo* result;\n\tsint32 hr = getaddrinfo(nodeName, serviceName, &hint, &result);\n\tif (hr != 0)\n\t{\n\t\tcemuLog_log(LogType::Socket, \"getaddrinfo failed with error {}\", hr);\n\t\tswitch (hr)\n\t\t{\n\t\tcase WSAHOST_NOT_FOUND:\n\t\t\tr = WU_SO_ECONNRESET; // todo - verify error code\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t// unhandled error\n\t\t\tcemu_assert_debug(false);\n\t\t\tcemuLog_log(LogType::Socket, \"getaddrinfo unhandled error code\");\n\t\t\tr = 1;\n\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// count how many results there are\n\t\tsint32 resultCount = 0;\n\t\tstruct addrinfo* currentAddrInfo = result;\n\t\twhile (currentAddrInfo)\n\t\t{\n\t\t\tresultCount++;\n\t\t\tcurrentAddrInfo = currentAddrInfo->ai_next;\n\t\t}\n\t\tif (resultCount == 0)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\t// allocate entries\n\t\tMPTR addrInfoMPTR = coreinit_allocFromSysArea(sizeof(wu_addrinfo)*resultCount + sizeof(wu_sockaddr)*resultCount, 4);\n\t\tMPTR addrInfoSockAddrMPTR = addrInfoMPTR + sizeof(wu_addrinfo)*resultCount;\n\t\twu_addrinfo* wuAddrInfo = (wu_addrinfo*)memory_getPointerFromVirtualOffset(addrInfoMPTR);\n\t\t// fill entries\n\t\tcurrentAddrInfo = result;\n\t\tsint32 entryIndex = 0;\n\t\twu_addrinfo* previousWuAddrInfo = NULL;\n\t\twhile (currentAddrInfo)\n\t\t{\n\t\t\tif (currentAddrInfo->ai_addrlen != 16)\n\t\t\t{ \n\t\t\t\t// skip this entry (IPv6)\n\t\t\t\tcurrentAddrInfo = currentAddrInfo->ai_next;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmemset(&wuAddrInfo[entryIndex], 0, sizeof(wu_addrinfo));\n\t\t\t// setup pointers\n\t\t\twuAddrInfo[entryIndex].ai_addr = _swapEndianU32(addrInfoSockAddrMPTR + sizeof(wu_sockaddr)*entryIndex);\n\t\t\twuAddrInfo[entryIndex].ai_next = MPTR_NULL;\n\t\t\twuAddrInfo[entryIndex].ai_canonname = _swapEndianU32(MPTR_NULL);\n\t\t\t// set ai_next for previous element\n\t\t\tif (previousWuAddrInfo)\n\t\t\t{\n\t\t\t\tpreviousWuAddrInfo->ai_next = _swapEndianU32(memory_getVirtualOffsetFromPointer(&wuAddrInfo[entryIndex]));\n\t\t\t}\n\t\t\tpreviousWuAddrInfo = &wuAddrInfo[entryIndex];\n\t\t\t// fill addrinfo struct\n\t\t\twuAddrInfo[entryIndex].ai_addrlen = _swapEndianU32((uint32)currentAddrInfo->ai_addrlen);\n\t\t\t//wuAddrInfo[entryIndex].ai_canonname; todo\n\t\t\twuAddrInfo[entryIndex].ai_family = _swapEndianU32(currentAddrInfo->ai_family);\n\t\t\twuAddrInfo[entryIndex].ai_flags = _swapEndianU32(currentAddrInfo->ai_flags); // todo: These flags might need to be translated\n\t\t\twuAddrInfo[entryIndex].ai_protocol = _swapEndianU32(currentAddrInfo->ai_protocol);\n\t\t\twuAddrInfo[entryIndex].ai_socktype = _swapEndianU32(currentAddrInfo->ai_socktype);\n\n\t\t\t// fill ai_addr\n\t\t\twu_sockaddr* sockAddr = (wu_sockaddr*)memory_getPointerFromVirtualOffset(_swapEndianU32(wuAddrInfo[entryIndex].ai_addr));\n\t\t\tsockAddr->sa_family = _swapEndianU16(currentAddrInfo->ai_addr->sa_family);\n\t\t\tmemcpy(sockAddr->sa_data, currentAddrInfo->ai_addr->sa_data, 14);\n\n\t\t\t// next\n\t\t\tentryIndex++;\n\t\t\tcurrentAddrInfo = currentAddrInfo->ai_next;\n\t\t}\n\t\tif (entryIndex == 0)\n\t\t\tassert_dbg();\n\t\t// set results\n\t\tmemory_writeU32(results, addrInfoMPTR);\n\t}\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid nsysnetExport_recvfrom(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"recvfrom({},0x{:08x},{},0x{:x},0x{:x},0x{:x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStr(msg, 1);\n\tppcDefineParamS32(len, 2);\n\tppcDefineParamS32(flags, 3);\n\tppcDefineParamStructPtr(fromAddr, wu_sockaddr, 4);\n\tppcDefineParamU32BEPtr(fromLen, 5);\n\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tsint32 r = 0;\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t\treturn;\n\t}\n\n\tint hostFlags = 0;\n\tbool requestIsNonBlocking = (flags&WU_MSG_DONTWAIT) != 0;\n\tflags &= ~WU_MSG_DONTWAIT;\n\tif (flags&WU_MSG_PEEK)\n\t{\n\t\tassert_dbg();\n\t\thostFlags |= MSG_PEEK;\n\t\tflags &= ~WU_MSG_PEEK;\n\t}\n\tif (vs->isNonBlocking)\n\t\trequestIsNonBlocking = vs->isNonBlocking;\n\n\tsockaddr fromAddrHost;\n\tsocklen_t fromLenHost = sizeof(fromAddrHost);\n\tsint32 wsaError = 0;\n\n\twhile( true )\n\t{\n\t\t// is socket recv shutdown?\n\t\tif (vs->isShutdownRecv)\n\t\t{\n\t\t\t// return with error\n\t\t\t_setSockError(WU_SO_ESHUTDOWN);\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\t\t// use select to check for exceptions and read data\n\t\tfd_set fd_read;\n\t\tfd_set fd_exceptions;\n\t\tFD_ZERO(&fd_read);\n\t\tFD_ZERO(&fd_exceptions);\n\t\tFD_SET(vs->s, &fd_read);\n\t\tFD_SET(vs->s, &fd_exceptions);\n\t\ttimeval t;\n\t\tt.tv_sec = 0;\n\t\tt.tv_usec = 0;\n\t\tint nfds = 0;\n#if BOOST_OS_UNIX\n\t\tnfds = vs->s + 1;\n#endif\n\t\tsint32 count = select(nfds, &fd_read, NULL, &fd_exceptions, &t);\n\t\tif (count > 0)\n\t\t{\n\t\t\tif (FD_ISSET(vs->s, &fd_exceptions))\n\t\t\t{\n\t\t\t\tassert_dbg(); // exception\n\t\t\t}\n\t\t\tif (FD_ISSET(vs->s, &fd_read))\n\t\t\t{\n\t\t\t\t// data available\n\t\t\t\tr = recvfrom(vs->s, msg, len, hostFlags, &fromAddrHost, &fromLenHost);\n\t\t\t\twsaError = GETLASTERR;\n\t\t\t\tif (r < 0)\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"recvfrom returned {} bytes\", r);\n\n\t\t\t\t// fromAddr and fromLen can be NULL\n\t\t\t\tif (fromAddr && fromLen) {\n\t\t\t\t\t*fromLen = fromLenHost;\n\t\t\t\t\tfromAddr->sa_family = _swapEndianU16(fromAddrHost.sa_family);\n\t\t\t\t\tmemcpy(fromAddr->sa_data, fromAddrHost.sa_data, 14);\n\t\t\t\t}\n\n\t\t\t\t_setSockError(0);\n\t\t\t\tosLib_returnFromFunction(hCPU, r);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// nothing to do\n\t\tif (requestIsNonBlocking)\n\t\t{\n\t\t\t// return with error\n\t\t\t_setSockError(WU_SO_EWOULDBLOCK);\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// pause for a while and check again later\n\t\t\tcoreinit::OSSleepTicks(ESPRESSO_CORE_CLOCK / 1000); // pause for 1ms\n\t\t\tPPCCore_switchToScheduler();\n\t\t}\n\t}\n\tassert_dbg(); // should no longer be reached\n\n\tif (requestIsNonBlocking == false)\n\t{\n\t\t// blocking\n\t\t_setSocketSendRecvNonBlockingMode(vs->s, true);\n\t\twhile (true)\n\t\t{\n\t\t\tr = recvfrom(vs->s, msg, len, hostFlags, &fromAddrHost, &fromLenHost);\n\t\t\twsaError = GETLASTERR;\n\t\t\tif (r < 0)\n\t\t\t{\n\t\t\t\tif (wsaError != WSAEWOULDBLOCK)\n\t\t\t\t\tbreak;\n\t\t\t\tcoreinit::OSSleepTicks(ESPRESSO_CORE_CLOCK/100); // pause for 10ms\n\t\t\t\tPPCCore_switchToScheduler();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tassert_dbg();\n\t\t}\n\t\t_setSocketSendRecvNonBlockingMode(vs->s, vs->isNonBlocking);\n\t}\n\telse\n\t{\n\t\t// non blocking\n\t\tassert_dbg();\n\t}\n\n\t// fromAddr and fromLen can be NULL\n\tif (fromAddr && fromLen) {\n\t\t*fromLen = fromLenHost;\n\t\tfromAddr->sa_family = _swapEndianU16(fromAddrHost.sa_family);\n\t\tmemcpy(fromAddr->sa_data, fromAddrHost.sa_data, 14);\n\t}\n\n\t_translateError(r <= 0 ? -1 : 0, wsaError);\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\n\nvoid nsysnetExport_recvfrom_ex(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"recvfrom_ex({},0x{:08x},{},0x{:x},0x{:08x},0x{:08x},0x{:08x},{})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8], hCPU->gpr[9], hCPU->gpr[10]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStr(msg, 1);\n\tppcDefineParamS32(len, 2);\n\tppcDefineParamS32(flags, 3);\n\tppcDefineParamStructPtr(fromAddr, wu_sockaddr, 4);\n\tppcDefineParamU32BEPtr(fromLen, 5);\n\tppcDefineParamUStr(extraData, 6);\n\tppcDefineParamS32(extraDataLen, 7);\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tsint32 r = 0;\n\tif (vs == NULL)\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\n\tint hostFlags = 0;\n\tbool requestIsNonBlocking = (flags&WU_MSG_DONTWAIT) != 0;\n\tflags &= ~WU_MSG_DONTWAIT;\n\tif (flags&WU_MSG_PEEK)\n\t{\n\t\tcemu_assert_debug(false);\n\t\thostFlags |= MSG_PEEK;\n\t\tflags &= ~WU_MSG_PEEK;\n\t}\n\tif (flags & 0x40)\n\t{\n\t\t// read TTL\n\t\tif (extraDataLen != 1)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\textraData[0] = 0x5; // we currently always return 5 as TTL\n\t\tflags &= ~0x40;\n\t}\n\n\tif (vs->isNonBlocking)\n\t\trequestIsNonBlocking = vs->isNonBlocking;\n\n\tsocklen_t fromLenHost = *fromLen;\n\tsockaddr fromAddrHost;\n\tsint32 wsaError = 0;\n\n\twhile (true)\n\t{\n\t\t// is socket recv shutdown?\n\t\tif (vs->isShutdownRecv)\n\t\t{\n\t\t\t// return with error\n\t\t\t_setSockError(WU_SO_ESHUTDOWN);\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\t\t// use select to check for exceptions and read data\n\t\tfd_set fd_read;\n\t\tfd_set fd_exceptions;\n\t\tFD_ZERO(&fd_read);\n\t\tFD_ZERO(&fd_exceptions);\n\t\tFD_SET(vs->s, &fd_read);\n\t\tFD_SET(vs->s, &fd_exceptions);\n\t\ttimeval t;\n\t\tt.tv_sec = 0;\n\t\tt.tv_usec = 0;\n\t\tint nfds = 0;\n#if BOOST_OS_UNIX\n\t\tnfds = vs->s + 1;\n#endif\n\t\tsint32 count = select(nfds, &fd_read, NULL, &fd_exceptions, &t);\n\t\tif (count > 0)\n\t\t{\n\t\t\tif (FD_ISSET(vs->s, &fd_exceptions))\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false); // exception\n\t\t\t}\n\t\t\tif (FD_ISSET(vs->s, &fd_read))\n\t\t\t{\n\t\t\t\t// data available\n\t\t\t\tr = recvfrom(vs->s, msg, len, hostFlags, &fromAddrHost, &fromLenHost);\n\t\t\t\twsaError = GETLASTERR;\n\t\t\t\tif (r < 0)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t}\n\t\t\t\t*fromLen = fromLenHost;\n\t\t\t\tfromAddr->sa_family = _swapEndianU16(fromAddrHost.sa_family);\n\t\t\t\tmemcpy(fromAddr->sa_data, fromAddrHost.sa_data, 14);\n\n\t\t\t\t_setSockError(0);\n\t\t\t\tosLib_returnFromFunction(hCPU, r);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// nothing to do\n\t\tif (requestIsNonBlocking)\n\t\t{\n\t\t\t// return with error\n\t\t\t_setSockError(WU_SO_EWOULDBLOCK);\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// pause for a while and check again later\n\t\t\tcoreinit::OSSleepTicks(ESPRESSO_CORE_CLOCK / 100); // pause for 10ms\n\t\t\tPPCCore_switchToScheduler();\n\t\t}\n\t}\n\tcemu_assert_debug(false); // should no longer be reached\n}\n\n\nvoid _convertSockaddrToHostFormat(wu_sockaddr* sockaddru, sockaddr* sockaddrHost)\n{\n\tsockaddrHost->sa_family = _swapEndianU16(sockaddru->sa_family);\n\tmemcpy(sockaddrHost->sa_data, sockaddru->sa_data, 14);\n}\n\n\nvoid nsysnetExport_sendto(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"sendto({},0x{:08x},{},0x{:x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStr(msg, 1);\n\tppcDefineParamS32(len, 2);\n\tppcDefineParamS32(flags, 3);\n\tppcDefineParamStructPtr(toAddr, wu_sockaddr, 4);\n\tppcDefineParamU32(toLen, 5);\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tsint32 r = 0;\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t\treturn;\n\t}\n\n\tint hostFlags = 0;\n\tbool requestIsNonBlocking = (flags&WU_MSG_DONTWAIT) != 0;\n\tflags &= ~WU_MSG_DONTWAIT;\n\tif (flags&WU_MSG_PEEK)\n\t{\n\t\tassert_dbg();\n\t\thostFlags |= MSG_PEEK;\n\t\tflags &= ~WU_MSG_PEEK;\n\t}\n\tif (vs->isNonBlocking)\n\t\trequestIsNonBlocking = vs->isNonBlocking;\n\n\tsockaddr toAddrHost;\n\ttoAddrHost.sa_family = _swapEndianU16(toAddr->sa_family);\n\tmemcpy(toAddrHost.sa_data, toAddr->sa_data, 14);\n\n\tsint32 wsaError = 0;\n\tif (requestIsNonBlocking == false)\n\t{\n\t\t// blocking\n\t\t_setSocketSendRecvNonBlockingMode(vs->s, true);\n\t\twhile (true)\n\t\t{\n\t\t\tr = sendto(vs->s, msg, len, hostFlags, &toAddrHost, toLen);\n\t\t\twsaError = GETLASTERR;\n\t\t\tif (r < 0)\n\t\t\t{\n\t\t\t\tif (wsaError != WSAEWOULDBLOCK)\n\t\t\t\t\tbreak;\n\t\t\t\tcoreinit::OSSleepTicks(ESPRESSO_CORE_CLOCK / 100); // pause for 10ms\n\t\t\t\tPPCCore_switchToScheduler();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\t_setSocketSendRecvNonBlockingMode(vs->s, vs->isNonBlocking);\n\t}\n\telse\n\t{\n\t\t// non blocking\n\t\t_setSocketSendRecvNonBlockingMode(vs->s, true);\n\t\tr = sendto(vs->s, msg, len, hostFlags, &toAddrHost, toLen);\n\t\twsaError = GETLASTERR;\n\t\t_setSocketSendRecvNonBlockingMode(vs->s, vs->isNonBlocking);\n\t}\n\n\t_translateError(r <= 0 ? -1 : 0, wsaError);\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\n\nvoid nsysnetExport_sendto_multi(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"sendto_multi({},0x{:08x},0x{:08x},{})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamStr(data, 1);\n\tppcDefineParamS32(dataLen, 2);\n\tppcDefineParamU32(flags, 3);\n\tppcDefineParamStructPtr(destinationArray, wu_sockaddr, 4);\n\tppcDefineParamU32(destinationCount, 5);\n\n\tif (flags != 0)\n\t\tassert_dbg();\n\n\t// todo - somehow handle non-blocking\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t\treturn;\n\t}\n\n\tfor (uint32 i = 0; i < destinationCount; i++)\n\t{\n\t\tsockaddr destinationHost;\n\t\t_convertSockaddrToHostFormat(&destinationArray[i], &destinationHost);\n\t\tsint32 r = sendto(vs->s, (char*)data, (int)dataLen, 0, &destinationHost, sizeof(sockaddr));\n\t\tif (r < dataLen)\n\t\t\tassert_dbg(); // todo\n\t}\n\t// success\n\t_setSockError(0);\n\tosLib_returnFromFunction(hCPU, dataLen);\n}\n\ntypedef struct\n{\n\tMEMPTR<uint8>\t\t\t\tdata;\n\tuint32be\t\t\t\t\tdataLen;\n\tMEMPTR<uint32be>\t\t\tsendLenArray;\n\tuint32be\t\t\t\t\tsendLenArraySize;\n\tMEMPTR<wu_sockaddr>\t\t\tdestArray;\n\tuint32be\t\t\t\t\tdestArraySize;\n\tMEMPTR<uint32be>\t\t\tresultArray;\n\tuint32be\t\t\t\t\tresultArrayLen;\n}sendtomultiBuffer_t;\n\nvoid nsysnetExport_sendto_multi_ex(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::Socket, \"sendto_multi_ex({},0x{:08x},0x{:08x},{})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\tppcDefineParamS32(s, 0);\n\tppcDefineParamU32(flags, 1);\n\tppcDefineParamStructPtr(multiBuf, sendtomultiBuffer_t, 2);\n\tppcDefineParamU32(num, 3);\n\n\tassert_dbg(); // todo - needs testing\n\n\tvirtualSocket_t* vs = nsysnet_getVirtualSocketObject(s);\n\tif (vs == NULL)\n\t{\n\t\tassert_dbg();\n\t\treturn;\n\t}\n\n\t// todo - lots of validation for multiBuf parameters (pointers must not be null and must be aligned, lens must be padded to alignment too)\n\t// verify multiBuf\n\tif ((uint32)multiBuf->sendLenArraySize < num ||\n\t\t(uint32)multiBuf->destArraySize < num ||\n\t\t(uint32)multiBuf->resultArrayLen < num )\n\t{\n\t\tcemu_assert_debug(false);\n\t}\n\n\tfor (uint32 i = 0; i < num; i++)\n\t{\n\t\tmultiBuf->resultArray[i] = 0;\n\t}\n\n\tuint8* data = multiBuf->data.GetPtr();\n\tsint32 sendLenSum = 0;\n\tfor (uint32 i = 0; i < num; i++)\n\t{\n\t\tsockaddr destination;\n\t\t_convertSockaddrToHostFormat(&multiBuf->destArray[i], &destination);\n\n\t\tuint32 sendLen = (uint32)(multiBuf->sendLenArray[i]);\n\t\tsint32 r = sendto(vs->s, (char*)data, (int)sendLen, 0, &destination, sizeof(sockaddr));\n\t\tif (r < (sint32)sendLen)\n\t\t\tcemu_assert_debug(false);\n\t\telse\n\t\t\tmultiBuf->resultArray[i] = r;\n\t\tdata += sendLen;\n\t\tsendLenSum += sendLenSum;\n\t}\n\tosLib_returnFromFunction(hCPU, sendLenSum); // return value correct?\n}\n\nnamespace nsysnet\n{\n\tstd::vector<NSSLInternalState_t> g_nsslInternalStates;\n\n\tNSSLInternalState_t* GetNSSLContext(sint32 index)\n\t{\n\t\tif (g_nsslInternalStates.size() <= index)\n\t\t\treturn nullptr;\n\n\t\tif (g_nsslInternalStates[index].destroyed)\n\t\t\tcemu_assert_suspicious();\n\t\n\t\treturn &g_nsslInternalStates[index];\n\t}\n\n\tvoid export_NSSLCreateContext(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(version, 0);\n\n\t\tNSSLInternalState_t ssl = {};\n\t\tssl.sslVersion = version;\n\t\tg_nsslInternalStates.push_back(ssl);\n\n\t\tuint32 nsslHandle = (uint32)g_nsslInternalStates.size() - 1;\n\n\t\tcemuLog_logDebug(LogType::Force, \"NSSLCreateContext(0x{:x}) -> 0x{:x}\", version, nsslHandle);\n\n\t\tosLib_returnFromFunction(hCPU, nsslHandle);\n\t}\n\n\tvoid export_NSSLSetClientPKI(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(nsslHandle, 0);\n\t\tppcDefineParamU32(clientPKI, 1);\n\t\tcemuLog_logDebug(LogType::Force, \"NSSLSetClientPKI(0x{:x}, 0x{:x})\", nsslHandle, clientPKI);\n\n\t\tif (g_nsslInternalStates.size() <= nsslHandle || g_nsslInternalStates[nsslHandle].destroyed)\n\t\t{\n\t\t\tosLib_returnFromFunction(hCPU, NSSL_INVALID_CTX);\n\t\t\treturn;\n\t\t}\n\n\t\tg_nsslInternalStates[nsslHandle].clientPKI = clientPKI;\n\t\tosLib_returnFromFunction(hCPU, NSSL_OK);\n\t}\n\n\tvoid export_NSSLAddServerPKI(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(nsslHandle, 0);\n\t\tppcDefineParamU32(serverPKI, 1);\n\t\tcemuLog_logDebug(LogType::Force, \"NSSLAddServerPKI(0x{:x}, 0x{:x})\", nsslHandle, serverPKI);\n\n\t\tif (g_nsslInternalStates.size() <= nsslHandle || g_nsslInternalStates[nsslHandle].destroyed)\n\t\t{\n\t\t\tosLib_returnFromFunction(hCPU, NSSL_INVALID_CTX);\n\t\t\treturn;\n\t\t}\n\n\t\tg_nsslInternalStates[nsslHandle].serverPKIs.insert(serverPKI);\n\t\tosLib_returnFromFunction(hCPU, NSSL_OK);\n\t}\n\n\tvoid export_NSSLAddServerPKIExternal(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(nsslHandle, 0);\n\t\tppcDefineParamMEMPTR(certData, uint8, 1);\n\t\tppcDefineParamS32(certLen, 2);\n\t\tppcDefineParamS32(certType, 3);\n\n\t\tcemuLog_logDebug(LogType::Force, \"NSSLAddServerPKIExternal(0x{:x}, 0x{:08x}, 0x{:x}, {})\", nsslHandle, certData.GetMPTR(), certLen, certType);\n\t\tif (g_nsslInternalStates.size() <= nsslHandle || g_nsslInternalStates[nsslHandle].destroyed)\n\t\t{\n\t\t\tosLib_returnFromFunction(hCPU, NSSL_INVALID_CTX);\n\t\t\treturn;\n\t\t}\n\n\t\tg_nsslInternalStates[nsslHandle].serverCustomPKIs.push_back(std::vector<uint8>(certData.GetPtr(), certData.GetPtr()+certLen));\n\n\t\tosLib_returnFromFunction(hCPU, NSSL_OK);\n\t}\n\n\tvoid export_NSSLAddServerPKIGroups(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(nsslHandle, 0);\n\t\tppcDefineParamU32(groupMask, 1);\n\t\tppcDefineParamMEMPTR(validCountOut, sint32, 2);\n\t\tppcDefineParamMEMPTR(invalidCountOut, sint32, 3);\n\t\tcemuLog_logDebug(LogType::Force, \"NSSLAddServerPKIGroups(0x{:x}, 0x{:x}, 0x{:08x}, 0x{:08x})\", nsslHandle, groupMask, validCountOut.GetMPTR(), invalidCountOut.GetMPTR());\n\n\t\tif (g_nsslInternalStates.size() <= nsslHandle || g_nsslInternalStates[nsslHandle].destroyed)\n\t\t{\n\t\t\tosLib_returnFromFunction(hCPU, NSSL_INVALID_CTX);\n\t\t\treturn;\n\t\t}\n\n\t\tif (HAS_FLAG(groupMask, 1))\n\t\t{\n\t\t\tg_nsslInternalStates[nsslHandle].serverPKIs.insert({ 100,101,102,103,104,105 });\n\t\t}\n\n\t\tif (HAS_FLAG(groupMask, 2))\n\t\t{\n\t\t\tg_nsslInternalStates[nsslHandle].serverPKIs.insert({\n\t\t\t\t1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009,\n\t\t\t\t1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019,\n\t\t\t\t1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029,\n\t\t\t\t1030, 1031, 1032, 1033 });\n\t\t}\n\n\t\tif (validCountOut)\n\t\t\t*validCountOut = (sint32)g_nsslInternalStates[nsslHandle].serverPKIs.size();\n\n\t\tif (invalidCountOut)\n\t\t\t*invalidCountOut = 0;\n\n\t\tosLib_returnFromFunction(hCPU, NSSL_OK);\n\t}\n\n\tvoid export_NSSLDestroyContext(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(nsslHandle, 0);\n\t\tcemuLog_logDebug(LogType::Force, \"NSSLDestroyContext(0x{:x})\", nsslHandle);\n\n\t\tif (g_nsslInternalStates.size() <= nsslHandle || g_nsslInternalStates[nsslHandle].destroyed)\n\t\t{\n\t\t\tosLib_returnFromFunction(hCPU, NSSL_INVALID_CTX);\n\t\t\treturn;\n\t\t}\n\n\t\tg_nsslInternalStates[nsslHandle].destroyed = true;\n\t\tosLib_returnFromFunction(hCPU, NSSL_OK);\n\t}\n\n\tvoid export_NSSLExportInternalServerCertificate(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(serverCertId, 0);\n\t\tppcDefineParamUStr(output, 1);\n\t\tppcDefineParamU32BEPtr(outputSize, 2);\n\t\tppcDefineParamU32BEPtr(certType, 3);\n\n\t\tsint32 certificateSize = 0;\n\t\tuint8* certificateData = iosuCrypto_getCertificateDataById(serverCertId, &certificateSize);\n\t\tif (certificateData == nullptr)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\n\t\tif( output )\n\t\t\tmemcpy(output, certificateData, certificateSize);\n\t\t*outputSize = (uint32)certificateSize;\n\t\t*certType = 0;\n\n\t\tosLib_returnFromFunction(hCPU, NSSL_OK);\n\t}\n\n\tvoid export_NSSLExportInternalClientCertificate(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(serverCertId, 0);\n\t\tppcDefineParamUStr(output, 1);\n\t\tppcDefineParamU32BEPtr(outputSize, 2);\n\t\tppcDefineParamU32BEPtr(certType, 3);\n\t\tppcDefineParamUStr(pkeyOutput, 4);\n\t\tppcDefineParamU32BEPtr(pkeyOutputSize, 5);\n\t\tppcDefineParamU32BEPtr(pkeyCertType, 6);\n\n\t\t// certificate\n\t\tsint32 certificateSize = 0;\n\t\tuint8* certificateData = iosuCrypto_getCertificateDataById(serverCertId, &certificateSize);\n\t\tif (certificateData == nullptr)\n\t\t{\n\t\t\tassert_dbg(); // todo\n\t\t}\n\t\tif (output)\n\t\t\tmemcpy(output, certificateData, certificateSize);\n\t\t*outputSize = (uint32)certificateSize;\n\t\t*certType = 0;\n\n\t\t// private key\n\t\tsint32 pkeySize = 0;\n\t\tuint8* pkeyData = iosuCrypto_getCertificatePrivateKeyById(serverCertId, &pkeySize);\n\t\tif (pkeyData == nullptr)\n\t\t{\n\t\t\tassert_dbg(); // todo\n\t\t}\n\t\tif (pkeyOutput)\n\t\t\tmemcpy(pkeyOutput, pkeyData, pkeySize);\n\t\t*pkeyOutputSize = (uint32)pkeySize;\n\t\t*pkeyCertType = 0;\n\n\t\tosLib_returnFromFunction(hCPU, NSSL_OK);\n\t}\n\n\tvoid wuResetFD(struct wu_fd_set* fdset)\n\t{\n\t\tfdset->mask = 0;\n\t}\n\n\tvoid wuSetFD(struct wu_fd_set* fdset, sint32 fd)\n\t{\n\t\tfdset->mask |= (1 << fd);\n\t}\n\n}\n\nnamespace nsysnet\n{\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"nsysnet\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"nsysnet\", inet_ntop, LogType::Socket);\n\n\t\t    // the below code is the old way of registering API which is deprecated\n\n\t\t    osLib_addFunction(\"nsysnet\", \"socket_lib_init\", nsysnetExport_socket_lib_init);\n\t\t\tosLib_addFunction(\"nsysnet\", \"socket_lib_finish\", nsysnetExport_socket_lib_finish);\n\n\t\t\t// socket API\n\t\t\tosLib_addFunction(\"nsysnet\", \"socket\", nsysnetExport_socket);\n\t\t\tosLib_addFunction(\"nsysnet\", \"mw_socket\", nsysnetExport_mw_socket);\n\t\t\tosLib_addFunction(\"nsysnet\", \"shutdown\", nsysnetExport_shutdown);\n\t\t\tosLib_addFunction(\"nsysnet\", \"socketclose\", nsysnetExport_socketclose);\n\t\t\tosLib_addFunction(\"nsysnet\", \"setsockopt\", nsysnetExport_setsockopt);\n\t\t\tosLib_addFunction(\"nsysnet\", \"getsockopt\", nsysnetExport_getsockopt);\n\t\t\tosLib_addFunction(\"nsysnet\", \"bind\", nsysnetExport_bind);\n\t\t\tosLib_addFunction(\"nsysnet\", \"listen\", nsysnetExport_listen);\n\t\t\tosLib_addFunction(\"nsysnet\", \"accept\", nsysnetExport_accept);\n\t\t\tosLib_addFunction(\"nsysnet\", \"connect\", nsysnetExport_connect);\n\t\t\tosLib_addFunction(\"nsysnet\", \"send\", nsysnetExport_send);\n\t\t\tosLib_addFunction(\"nsysnet\", \"recv\", nsysnetExport_recv);\n\t\t\tosLib_addFunction(\"nsysnet\", \"select\", nsysnetExport_select);\n\t\t\tosLib_addFunction(\"nsysnet\", \"getsockname\", nsysnetExport_getsockname);\n\t\t\tosLib_addFunction(\"nsysnet\", \"getpeername\", nsysnetExport_getpeername);\n\n\t\t\tosLib_addFunction(\"nsysnet\", \"inet_aton\", nsysnetExport_inet_aton);\n\t\t\tosLib_addFunction(\"nsysnet\", \"inet_pton\", nsysnetExport_inet_pton);\n\t\t\tosLib_addFunction(\"nsysnet\", \"inet_ntoa\", nsysnetExport_inet_ntoa);\n\t\t\tosLib_addFunction(\"nsysnet\", \"htons\", nsysnetExport_htons);\n\t\t\tosLib_addFunction(\"nsysnet\", \"htonl\", nsysnetExport_htonl);\n\t\t\tosLib_addFunction(\"nsysnet\", \"ntohs\", nsysnetExport_ntohs);\n\t\t\tosLib_addFunction(\"nsysnet\", \"ntohl\", nsysnetExport_ntohl);\n\t\t\tosLib_addFunction(\"nsysnet\", \"gethostbyname\", nsysnetExport_gethostbyname);\n\t\t\tosLib_addFunction(\"nsysnet\", \"gethostbyaddr\", nsysnetExport_gethostbyaddr);\n\t\t\tosLib_addFunction(\"nsysnet\", \"getaddrinfo\", nsysnetExport_getaddrinfo);\n\n\t\t\tosLib_addFunction(\"nsysnet\", \"socketlasterr\", nsysnetExport_socketlasterr);\n\n\t\t\t// unfinished implementations\n\t\t\tosLib_addFunction(\"nsysnet\", \"recvfrom\", nsysnetExport_recvfrom);\n\t\t\tosLib_addFunction(\"nsysnet\", \"recvfrom_ex\", nsysnetExport_recvfrom_ex);\n\t\t\tosLib_addFunction(\"nsysnet\", \"sendto\", nsysnetExport_sendto);\n\n\t\t\tosLib_addFunction(\"nsysnet\", \"sendto_multi\", nsysnetExport_sendto_multi);\n\t\t\tosLib_addFunction(\"nsysnet\", \"sendto_multi_ex\", nsysnetExport_sendto_multi_ex);\n\n\n\t\t\t// NSSL API\n\t\t\tosLib_addFunction(\"nsysnet\", \"NSSLCreateContext\", nsysnet::export_NSSLCreateContext);\n\t\t\tosLib_addFunction(\"nsysnet\", \"NSSLSetClientPKI\", nsysnet::export_NSSLSetClientPKI);\n\t\t\tosLib_addFunction(\"nsysnet\", \"NSSLAddServerPKI\", nsysnet::export_NSSLAddServerPKI);\n\t\t\tosLib_addFunction(\"nsysnet\", \"NSSLAddServerPKIExternal\", nsysnet::export_NSSLAddServerPKIExternal);\n\t\t\tosLib_addFunction(\"nsysnet\", \"NSSLAddServerPKIGroups\", nsysnet::export_NSSLAddServerPKIGroups);\n\t\t\tosLib_addFunction(\"nsysnet\", \"NSSLDestroyContext\", nsysnet::export_NSSLDestroyContext);\n\n\t\t\tosLib_addFunction(\"nsysnet\", \"NSSLExportInternalServerCertificate\", nsysnet::export_NSSLExportInternalServerCertificate);\n\t\t\tosLib_addFunction(\"nsysnet\", \"NSSLExportInternalClientCertificate\", nsysnet::export_NSSLExportInternalClientCertificate);\n\t\t};\n\t}s_COSnsysnetModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSnsysnetModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/nsysnet/nsysnet.h",
    "content": "#pragma once\n#include <set>\n#include <vector>\n#include \"Cafe/OS/RPL/COSModule.h\"\n\n#if BOOST_OS_WINDOWS\n#include <WinSock2.h>\n#else\n#include <sys/socket.h>\n#define SOCKET int\n#define closesocket close\n#endif\n\ntypedef signed int WUSOCKET;\n\nWUSOCKET nsysnet_createVirtualSocketFromExistingSocket(SOCKET existingSocket);\nvoid nsysnet_notifyCloseSharedSocket(SOCKET existingSocket);\n\nstruct wu_fd_set\n{\n\tuint32be mask;\n};\n\nvoid _translateFDSet(fd_set* hostSet, struct wu_fd_set* fdset, sint32 nfds);\nvoid _translateFDSetRev(struct wu_fd_set* fdset, fd_set* hostSet, sint32 nfds);\n\nsint32 nsysnet_getVirtualSocketHandleFromHostHandle(SOCKET s);\n\nnamespace nsysnet\n{\n\n#define NSSL_OK (0)\n#define NSSL_INVALID_CTX (0xFFD7FFFF)\n\n\tstruct NSSLInternalState_t\n\t{\n\t\tbool destroyed;\n\t\tuint32 sslVersion;\n\t\tuint32 clientPKI;\n\t\tstd::set<uint32> serverPKIs;\n\t\tstd::vector<std::vector<uint8>> serverCustomPKIs;\n\t};\n\n\tNSSLInternalState_t* GetNSSLContext(sint32 index);\n\n\tvoid wuResetFD(struct wu_fd_set* fdset);\n\tvoid wuSetFD(struct wu_fd_set* fdset, sint32 fd);\n\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/ntag/ntag.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/libs/ntag/ntag.h\"\n#include \"Cafe/OS/libs/nfc/nfc.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_IPC.h\"\n#include \"Cafe/IOSU/ccr_nfc/iosu_ccr_nfc.h\"\n\nnamespace ntag\n{\n\tstruct NTAGWriteData\n\t{\n\t\tuint16 size;\n\t\tuint8 data[0x1C8];\n\t\tnfc::NFCUid uid;\n\t\tnfc::NFCUid uidMask;\n\t};\n\tNTAGWriteData gWriteData[2];\n\n\tbool ccrNfcOpened = false;\n\tIOSDevHandle gCcrNfcHandle;\n\n\tNTAGFormatSettings gFormatSettings;\n\n\tMPTR gDetectCallbacks[2];\n\tMPTR gAbortCallbacks[2];\n\tMPTR gReadCallbacks[2];\n\tMPTR gWriteCallbacks[2];\n\n\tsint32 __NTAGConvertNFCResult(sint32 result)\n\t{\n\t\tif (result == NFC_RESULT_SUCCESS)\n\t\t{\n\t\t\treturn NTAG_RESULT_SUCCESS;\n\t\t}\n\n\t\tswitch (result & NFC_RESULT_MASK)\n\t\t{\n\t\tcase NFC_RESULT_UNINITIALIZED:\n\t\t\treturn NTAG_RESULT_UNINITIALIZED;\n\t\tcase NFC_RESULT_INVALID_STATE:\n\t\t\treturn NTAG_RESULT_INVALID_STATE;\n\t\tcase NFC_RESULT_NO_TAG:\n\t\t\treturn NTAG_RESULT_NO_TAG;\n\t\tcase NFC_RESULT_UID_MISMATCH:\n\t\t\treturn NTAG_RESULT_UID_MISMATCH;\n\t\t}\n\n\t\t// TODO convert more errors\n\t\treturn NTAG_RESULT_INVALID;\n\t}\n\n\tsint32 NTAGInit(uint32 chan)\n\t{\n\t\treturn NTAGInitEx(chan);\n\t}\n\n\tsint32 NTAGInitEx(uint32 chan)\n\t{\n\t\tsint32 result = nfc::NFCInitEx(chan, 1);\n\t\treturn __NTAGConvertNFCResult(result);\n\t}\n\n\tsint32 NTAGShutdown(uint32 chan)\n\t{\n\t\tsint32 result = nfc::NFCShutdown(chan);\n\n\t\tif (ccrNfcOpened)\n\t\t{\n\t\t\tcoreinit::IOS_Close(gCcrNfcHandle);\n\t\t\tccrNfcOpened = false;\n\t\t}\n\n\t\tgDetectCallbacks[chan] = MPTR_NULL;\n\t\tgAbortCallbacks[chan] = MPTR_NULL;\n\t\tgReadCallbacks[chan] = MPTR_NULL;\n\t\tgWriteCallbacks[chan] = MPTR_NULL;\n\n\t\treturn __NTAGConvertNFCResult(result);\n\t}\n\n\tbool NTAGIsInit(uint32 chan)\n\t{\n\t\treturn nfc::NFCIsInit(chan);\n\t}\n\n\tvoid NTAGProc(uint32 chan)\n\t{\n\t\tnfc::NFCProc(chan);\n\t}\n\n\tvoid NTAGSetFormatSettings(NTAGFormatSettings* formatSettings)\n\t{\n\t\tgFormatSettings.version = formatSettings->version;\n\t\tgFormatSettings.makerCode = _swapEndianU32(formatSettings->makerCode);\n\t\tgFormatSettings.identifyCode = _swapEndianU32(formatSettings->identifyCode);\n\t}\n\n\tvoid __NTAGDetectCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(chan, 0);\n\t\tppcDefineParamU32(hasTag, 1);\n\t\tppcDefineParamPtr(context, void, 2);\n\n\t\tcemuLog_log(LogType::NTAG, \"__NTAGDetectCallback: {} {} {}\", chan, hasTag, context);\n\n\t\tPPCCoreCallback(gDetectCallbacks[chan], chan, hasTag, context);\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid NTAGSetTagDetectCallback(uint32 chan, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tgDetectCallbacks[chan] = callback;\n\t\tnfc::NFCSetTagDetectCallback(chan, RPLLoader_MakePPCCallable(__NTAGDetectCallback), context);\n\t}\n\n\tvoid __NTAGAbortCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(chan, 0);\n\t\tppcDefineParamS32(error, 1);\n\t\tppcDefineParamPtr(context, void, 2);\n\n\t\tPPCCoreCallback(gAbortCallbacks[chan], chan, __NTAGConvertNFCResult(error), context);\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tsint32 NTAGAbort(uint32 chan, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\t\t\n\t\t// TODO is it normal that Rumble U calls this?\n\n\t\tgAbortCallbacks[chan] = callback;\n\t\tsint32 result = nfc::NFCAbort(chan, RPLLoader_MakePPCCallable(__NTAGAbortCallback), context);\n\t\treturn __NTAGConvertNFCResult(result);\n\t}\n\n\tbool __NTAGRawDataToNfcData(iosu::ccr_nfc::CCRNFCCryptData* raw, iosu::ccr_nfc::CCRNFCCryptData* nfc)\n\t{  \n\t\tmemcpy(nfc, raw, sizeof(iosu::ccr_nfc::CCRNFCCryptData));\n\n\t\tif (raw->version == 0)\n\t\t{\n\t\t\tnfc->version = 0;\n\t\t\tnfc->dataSize = 0x1C8;\n\t\t\tnfc->seedOffset = 0x25;\n\t\t\tnfc->keyGenSaltOffset = 0x1A8;\n\t\t\tnfc->uuidOffset = 0x198;\n\t\t\tnfc->unfixedInfosOffset = 0x28;\n\t\t\tnfc->unfixedInfosSize = 0x120;\n\t\t\tnfc->lockedSecretOffset = 0x168;\n\t\t\tnfc->lockedSecretSize = 0x30;\n\t\t\tnfc->unfixedInfosHmacOffset = 0;\n\t\t\tnfc->lockedSecretHmacOffset = 0x148;\n\t\t}\n\t\telse if (raw->version == 2)\n\t\t{\n\t\t\tnfc->version = 2;\n\t\t\tnfc->dataSize = 0x208;\n\t\t\tnfc->seedOffset = 0x29;\n\t\t\tnfc->keyGenSaltOffset = 0x1E8;\n\t\t\tnfc->uuidOffset = 0x1D4;\n\t\t\tnfc->unfixedInfosOffset = 0x2C;\n\t\t\tnfc->unfixedInfosSize = 0x188;\n\t\t\tnfc->lockedSecretOffset = 0x1DC;\n\t\t\tnfc->lockedSecretSize = 0;\n\t\t\tnfc->unfixedInfosHmacOffset = 0x8;\n\t\t\tnfc->lockedSecretHmacOffset = 0x1B4;\n\n\t\t\tmemcpy(nfc->data + 0x1d4, raw->data, 0x8);\n\t\t\tmemcpy(nfc->data, raw->data + 0x8, 0x8);\n\t\t\tmemcpy(nfc->data + 0x28, raw->data + 0x10, 0x4);\n\t\t\tmemcpy(nfc->data + nfc->unfixedInfosOffset, raw->data + 0x14, 0x20);\n\t\t\tmemcpy(nfc->data + nfc->lockedSecretHmacOffset, raw->data + 0x34, 0x20);\n\t\t\tmemcpy(nfc->data + nfc->lockedSecretOffset, raw->data + 0x54, 0xC);\n\t\t\tmemcpy(nfc->data + nfc->keyGenSaltOffset, raw->data + 0x60, 0x20);\n\t\t\tmemcpy(nfc->data + nfc->unfixedInfosHmacOffset, raw->data + 0x80, 0x20);\n\t\t\tmemcpy(nfc->data + nfc->unfixedInfosOffset + 0x20, raw->data + 0xa0, 0x168);\n\t\t\tmemcpy(nfc->data + 0x208, raw->data + 0x208, 0x14);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool __NTAGNfcDataToRawData(iosu::ccr_nfc::CCRNFCCryptData* nfc, iosu::ccr_nfc::CCRNFCCryptData* raw)\n\t{\n\t\tmemcpy(raw, nfc, sizeof(iosu::ccr_nfc::CCRNFCCryptData));\n\n\t\tif (nfc->version == 0)\n\t\t{\n\t\t\traw->version = 0;\n\t\t\traw->dataSize = 0x1C8;\n\t\t\traw->seedOffset = 0x25;\n\t\t\traw->keyGenSaltOffset = 0x1A8;\n\t\t\traw->uuidOffset = 0x198;\n\t\t\traw->unfixedInfosOffset = 0x28;\n\t\t\traw->unfixedInfosSize = 0x120;\n\t\t\traw->lockedSecretOffset = 0x168;\n\t\t\traw->lockedSecretSize = 0x30;\n\t\t\traw->unfixedInfosHmacOffset = 0;\n\t\t\traw->lockedSecretHmacOffset = 0x148;\n\t\t}\n\t\telse if (nfc->version == 2)\n\t\t{\n\t\t\traw->version = 2;\n\t\t\traw->dataSize = 0x208;\n\t\t\traw->seedOffset = 0x11;\n\t\t\traw->keyGenSaltOffset = 0x60;\n\t\t\traw->uuidOffset = 0;\n\t\t\traw->unfixedInfosOffset = 0x14;\n\t\t\traw->unfixedInfosSize = 0x188;\n\t\t\traw->lockedSecretOffset = 0x54;\n\t\t\traw->lockedSecretSize = 0xC;\n\t\t\traw->unfixedInfosHmacOffset = 0x80;\n\t\t\traw->lockedSecretHmacOffset = 0x34;\n\n\t\t\tmemcpy(raw->data + 0x8, nfc->data, 0x8);\n\t\t\tmemcpy(raw->data + raw->unfixedInfosHmacOffset, nfc->data + 0x8, 0x20);\n\t\t\tmemcpy(raw->data + 0x10, nfc->data + 0x28, 0x4);\n\t\t\tmemcpy(raw->data + raw->unfixedInfosOffset, nfc->data + 0x2C, 0x20);\n\t\t\tmemcpy(raw->data + 0xa0, nfc->data + 0x4C, 0x168);\n\t\t\tmemcpy(raw->data + raw->lockedSecretHmacOffset, nfc->data + 0x1B4, 0x20);\n\t\t\tmemcpy(raw->data + raw->uuidOffset, nfc->data + 0x1D4, 0x8);\n\t\t\tmemcpy(raw->data + raw->lockedSecretOffset, nfc->data + 0x1DC, 0xC);\n\t\t\tmemcpy(raw->data + raw->keyGenSaltOffset, nfc->data + 0x1E8, 0x20);\n\t\t\tmemcpy(raw->data + 0x208, nfc->data + 0x208, 0x14);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tsint32 __NTAGDecryptData(void* decryptedData, const void* rawData)\n\t{\n\t\tStackAllocator<iosu::ccr_nfc::CCRNFCCryptData> nfcRawData, nfcInData, nfcOutData;\n\n\t\tif (!ccrNfcOpened)\n\t\t{\n\t\t\tgCcrNfcHandle = coreinit::IOS_Open(\"/dev/ccr_nfc\", 0);\n\t\t}\n\n\t\t// Prepare nfc buffer\n\t\tnfcRawData->version = 0;\n\t\tmemcpy(nfcRawData->data, rawData, 0x1C8);\n\t\t__NTAGRawDataToNfcData(nfcRawData.GetPointer(), nfcInData.GetPointer());\n\n\t\t// Decrypt\n\t\tsint32 result = coreinit::IOS_Ioctl(gCcrNfcHandle, 2, nfcInData.GetPointer(), sizeof(iosu::ccr_nfc::CCRNFCCryptData), nfcOutData.GetPointer(), sizeof(iosu::ccr_nfc::CCRNFCCryptData));\n\n\t\t// Unpack nfc buffer\n\t\t__NTAGNfcDataToRawData(nfcOutData.GetPointer(), nfcRawData.GetPointer());\n\t\tmemcpy(decryptedData, nfcRawData->data, 0x1C8);\n\n\t\t// Convert result\n\t\tif (result == CCR_NFC_INVALID_UNFIXED_INFOS)\n\t\t{\n\t\t\treturn -0x2708;\n\t\t}\n\t\telse if (result == CCR_NFC_INVALID_LOCKED_SECRET)\n\t\t{\n\t\t\treturn -0x2707;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tsint32 __NTAGValidateHeaders(NTAGNoftHeader* noftHeader, NTAGInfoHeader* infoHeader, NTAGAreaHeader* rwHeader, NTAGAreaHeader* roHeader)\n\t{\n\t\tif (infoHeader->formatVersion != gFormatSettings.version || noftHeader->version != 0x1)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Invalid format version\");\n\t\t\treturn -0x2710;\n\t\t}\n\n\t\tif (_swapEndianU32(noftHeader->magic) != 0x4E4F4654 /* 'NOFT' */ ||\n\t\t\t_swapEndianU16(rwHeader->magic) != 0x5257 /* 'RW' */ ||\n\t\t\t_swapEndianU16(roHeader->magic) != 0x524F /* 'RO' */)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Invalid header magic\");\n\t\t\treturn -0x270F;\n\t\t}\n\n\t\tif (_swapEndianU32(rwHeader->makerCode) != gFormatSettings.makerCode ||\n\t\t\t_swapEndianU32(roHeader->makerCode) != gFormatSettings.makerCode)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Invalid maker code\");\n\t\t\treturn -0x270E;\n\t\t}\n\n\t\tif (infoHeader->formatVersion != 0 &&\n\t\t\t(_swapEndianU32(rwHeader->identifyCode) != gFormatSettings.identifyCode ||\n\t\t\t _swapEndianU32(roHeader->identifyCode) != gFormatSettings.identifyCode))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Invalid identify code\");\n\t\t\treturn -0x2709;\n\t\t}\n\n\t\tif (_swapEndianU16(rwHeader->size) + _swapEndianU16(roHeader->size) != 0x130)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Invalid data size\");\n\t\t\treturn -0x270D;\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tsint32 __NTAGParseHeaders(const uint8* data, NTAGNoftHeader* noftHeader, NTAGInfoHeader* infoHeader, NTAGAreaHeader* rwHeader, NTAGAreaHeader* roHeader)\n\t{\n\t\tmemcpy(noftHeader, data + 0x20, sizeof(NTAGNoftHeader));\n\t\tmemcpy(infoHeader, data + 0x198, sizeof(NTAGInfoHeader));\n\n\t\tcemu_assert(_swapEndianU16(infoHeader->rwHeaderOffset) + sizeof(NTAGAreaHeader) < 0x200);\n\t\tcemu_assert(_swapEndianU16(infoHeader->roHeaderOffset) + sizeof(NTAGAreaHeader) < 0x200);\n\n\t\tmemcpy(rwHeader, data + _swapEndianU16(infoHeader->rwHeaderOffset), sizeof(NTAGAreaHeader));\n\t\tmemcpy(roHeader, data + _swapEndianU16(infoHeader->roHeaderOffset), sizeof(NTAGAreaHeader));\n\n\t\treturn __NTAGValidateHeaders(noftHeader, infoHeader, rwHeader, roHeader);\n\t}\n\n\tsint32 __NTAGParseData(void* rawData, void* rwData, void* roData, nfc::NFCUid* uid, uint32 lockedDataSize, NTAGNoftHeader* noftHeader, NTAGInfoHeader* infoHeader, NTAGAreaHeader* rwHeader, NTAGAreaHeader* roHeader)\n\t{\n\t\tuint8 decryptedData[0x1C8];\n\t\tsint32 result = __NTAGDecryptData(decryptedData, rawData);\n\t\tif (result < 0)\n\t\t{\n\t\t\treturn result;\n\t\t}\n\n\t\tresult = __NTAGParseHeaders(decryptedData, noftHeader, infoHeader, rwHeader, roHeader);\n\t\tif (result < 0)\n\t\t{\n\t\t\treturn result;\n\t\t}\n\n\t\tif (_swapEndianU16(roHeader->size) + 0x70 != lockedDataSize)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Invalid locked area size\");\n\t\t\treturn -0x270C;\n\t\t}\n\n\t\tif (memcmp(infoHeader->uid.uid, uid->uid, sizeof(nfc::NFCUid)) != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"UID mismatch\");\n\t\t\treturn -0x270B;\n\t\t}\n\n\t\tcemu_assert(_swapEndianU16(rwHeader->offset) + _swapEndianU16(rwHeader->size) < 0x200);\n\t\tcemu_assert(_swapEndianU16(roHeader->offset) + _swapEndianU16(roHeader->size) < 0x200);\n\n\t\tmemcpy(rwData, decryptedData + _swapEndianU16(rwHeader->offset), _swapEndianU16(rwHeader->size));\n\t\tmemcpy(roData, decryptedData + _swapEndianU16(roHeader->offset), _swapEndianU16(roHeader->size));\n\n\t\treturn 0;\n\t}\n\n\tvoid __NTAGReadCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(chan, 0);\n\t\tppcDefineParamS32(error, 1);\n\t\tppcDefineParamPtr(uid, nfc::NFCUid, 2);\n\t\tppcDefineParamU32(readOnly, 3);\n\t\tppcDefineParamU32(dataSize, 4);\n\t\tppcDefineParamPtr(data, void, 5);\n\t\tppcDefineParamU32(lockedDataSize, 6);\n\t\tppcDefineParamPtr(lockedData, void, 7);\n\t\tppcDefineParamPtr(context, void, 8);\n\n\t\tuint8 rawData[0x1C8]{};\n\t\tStackAllocator<NTAGData> readResult;\n\t\tStackAllocator<uint8, 0x1C8> rwData;\n\t\tStackAllocator<uint8, 0x1C8> roData;\n\t\tNTAGNoftHeader noftHeader;\n\t\tNTAGInfoHeader infoHeader;\n\t\tNTAGAreaHeader rwHeader;\n\t\tNTAGAreaHeader roHeader;\n\n\t\treadResult->readOnly = readOnly;\n\n\t\terror = __NTAGConvertNFCResult(error);\n\t\tif (error == 0)\n\t\t{\n\t\t\tmemset(rwData.GetPointer(), 0, 0x1C8);\n\t\t\tmemset(roData.GetPointer(), 0, 0x1C8);\n\n\t\t\t// Copy raw and locked data into a contigous buffer\n\t\t\tmemcpy(rawData, data, dataSize);\n\t\t\tmemcpy(rawData + dataSize, lockedData, lockedDataSize);\n\n\t\t\terror = __NTAGParseData(rawData, rwData.GetPointer(), roData.GetPointer(), uid, lockedDataSize, &noftHeader, &infoHeader, &rwHeader, &roHeader);\n\t\t\tif (error == 0)\n\t\t\t{\n\t\t\t\tmemcpy(readResult->uid.uid, uid->uid, sizeof(uid->uid));\n\t\t\t\treadResult->rwInfo.data = _swapEndianU32(rwData.GetMPTR());\n\t\t\t\treadResult->roInfo.data = _swapEndianU32(roData.GetMPTR());\n\t\t\t\treadResult->rwInfo.makerCode = rwHeader.makerCode;\n\t\t\t\treadResult->rwInfo.size = rwHeader.size;\n\t\t\t\treadResult->roInfo.makerCode = roHeader.makerCode;\n\t\t\t\treadResult->rwInfo.identifyCode = rwHeader.identifyCode;\n\t\t\t\treadResult->roInfo.identifyCode = roHeader.identifyCode;\n\t\t\t\treadResult->formatVersion = infoHeader.formatVersion;\n\t\t\t\treadResult->roInfo.size = roHeader.size;\n\n\t\t\t\tcemuLog_log(LogType::NTAG, \"__NTAGReadCallback: {} {} {}\", chan, error, context);\n\n\t\t\t\tPPCCoreCallback(gReadCallbacks[chan], chan, 0, readResult.GetPointer(), context);\n\t\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (uid)\n\t\t{\n\t\t\tmemcpy(readResult->uid.uid, uid->uid, sizeof(uid->uid));\n\t\t}\n\t\treadResult->roInfo.size = 0;\n\t\treadResult->rwInfo.size = 0;\n\t\treadResult->roInfo.data = MPTR_NULL;\n\t\treadResult->formatVersion = 0;\n\t\treadResult->rwInfo.data = MPTR_NULL;\n\t\tcemuLog_log(LogType::NTAG, \"__NTAGReadCallback: {} {} {}\", chan, error, context);\n\t\tPPCCoreCallback(gReadCallbacks[chan], chan, error, readResult.GetPointer(), context);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tsint32 NTAGRead(uint32 chan, uint32 timeout, nfc::NFCUid* uid, nfc::NFCUid* uidMask, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\tgReadCallbacks[chan] = callback;\n\n\t\tnfc::NFCUid _uid{}, _uidMask{};\n\t\tif (uid && uidMask)\n\t\t{\n\t\t\tmemcpy(&_uid, uid, sizeof(*uid));\n\t\t\tmemcpy(&_uidMask, uidMask, sizeof(*uidMask));\n\t\t}\n\n\t\tsint32 result = nfc::NFCRead(chan, timeout, &_uid, &_uidMask, RPLLoader_MakePPCCallable(__NTAGReadCallback), context);\n\t\treturn __NTAGConvertNFCResult(result);\n\t}\n\n\tsint32 __NTAGEncryptData(void* encryptedData, const void* rawData)\n\t{\n\t\tStackAllocator<iosu::ccr_nfc::CCRNFCCryptData> nfcRawData, nfcInData, nfcOutData;\n\n\t\tif (!ccrNfcOpened)\n\t\t{\n\t\t\tgCcrNfcHandle = coreinit::IOS_Open(\"/dev/ccr_nfc\", 0);\n\t\t}\n\n\t\t// Prepare nfc buffer\n\t\tnfcRawData->version = 0;\n\t\tmemcpy(nfcRawData->data, rawData, 0x1C8);\n\t\t__NTAGRawDataToNfcData(nfcRawData.GetPointer(), nfcInData.GetPointer());\n\n\t\t// Encrypt\n\t\tsint32 result = coreinit::IOS_Ioctl(gCcrNfcHandle, 1, nfcInData.GetPointer(), sizeof(iosu::ccr_nfc::CCRNFCCryptData), nfcOutData.GetPointer(), sizeof(iosu::ccr_nfc::CCRNFCCryptData));\n\n\t\t// Unpack nfc buffer\n\t\t__NTAGNfcDataToRawData(nfcOutData.GetPointer(), nfcRawData.GetPointer());\n\t\tmemcpy(encryptedData, nfcRawData->data, 0x1C8);\n\n\t\treturn result;\n\t}\n\n\tsint32 __NTAGPrepareWriteData(void* outBuffer, uint32 dataSize, const void* data, const void* tagData, NTAGNoftHeader* noftHeader, NTAGAreaHeader* rwHeader)\n\t{\n\t\tuint8 decryptedBuffer[0x1C8];\n\t\tuint8 encryptedBuffer[0x1C8];\n\n\t\tmemcpy(decryptedBuffer, tagData, 0x1C8);\n\n\t\t// Fill the rest of the rw area with random data\n\t\tif (dataSize < _swapEndianU16(rwHeader->size))\n\t\t{\n\t\t\tuint8 randomBuffer[0x1C8];\n\t\t\tfor (int i = 0; i < sizeof(randomBuffer); i++)\n\t\t\t{\n\t\t\t\trandomBuffer[i] = rand() & 0xFF;\n\t\t\t}\n\n\t\t\tmemcpy(decryptedBuffer + _swapEndianU16(rwHeader->offset) + dataSize, randomBuffer, _swapEndianU16(rwHeader->size) - dataSize);\n\t\t}\n\t\t\n\t\t// Make sure the data fits into the rw area\n\t\tif (_swapEndianU16(rwHeader->size) < dataSize)\n\t\t{\n\t\t\treturn -0x270D;\n\t\t}\n\n\t\t// Update write count (check for overflow)\n\t\tif ((_swapEndianU16(noftHeader->writeCount) & 0x7fff) == 0x7fff)\n\t\t{\n\t\t\tnoftHeader->writeCount = _swapEndianU16(_swapEndianU16(noftHeader->writeCount) & 0x8000);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnoftHeader->writeCount = _swapEndianU16(_swapEndianU16(noftHeader->writeCount) + 1);\n\t\t}\n\n\t\tmemcpy(decryptedBuffer + 0x20, noftHeader, sizeof(NTAGNoftHeader));\n\t\tmemcpy(decryptedBuffer + _swapEndianU16(rwHeader->offset), data, dataSize);\n\n\t\t// Encrypt\n\t\tsint32 result = __NTAGEncryptData(encryptedBuffer, decryptedBuffer);\n\t\tif (result < 0)\n\t\t{\n\t\t\treturn result;\n\t\t}\n\n\t\tmemcpy(outBuffer, encryptedBuffer, _swapEndianU16(rwHeader->size) + 0x28);\n\t\treturn 0;\n\t}\n\n\tvoid __NTAGWriteCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(chan, 0);\n\t\tppcDefineParamS32(error, 1);\n\t\tppcDefineParamPtr(context, void, 2);\n\n\t\tPPCCoreCallback(gWriteCallbacks[chan], chan, __NTAGConvertNFCResult(error), context);\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid __NTAGReadBeforeWriteCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(chan, 0);\n\t\tppcDefineParamS32(error, 1);\n\t\tppcDefineParamPtr(uid, nfc::NFCUid, 2);\n\t\tppcDefineParamU32(readOnly, 3);\n\t\tppcDefineParamU32(dataSize, 4);\n\t\tppcDefineParamPtr(data, void, 5);\n\t\tppcDefineParamU32(lockedDataSize, 6);\n\t\tppcDefineParamPtr(lockedData, void, 7);\n\t\tppcDefineParamPtr(context, void, 8);\n\n\t\tuint8 rawData[0x1C8]{};\n\t\tuint8 rwData[0x1C8]{};\n\t\tuint8 roData[0x1C8]{};\n\t\tNTAGNoftHeader noftHeader;\n\t\tNTAGInfoHeader infoHeader;\n\t\tNTAGAreaHeader rwHeader;\n\t\tNTAGAreaHeader roHeader;\n\t\tuint8 writeBuffer[0x1C8]{};\n\n\t\terror = __NTAGConvertNFCResult(error);\n\t\tif (error == 0)\n\t\t{\n\t\t\t// Copy raw and locked data into a contigous buffer\n\t\t\tmemcpy(rawData, data, dataSize);\n\t\t\tmemcpy(rawData + dataSize, lockedData, lockedDataSize);\n\n\t\t\terror = __NTAGParseData(rawData, rwData, roData, uid, lockedDataSize, &noftHeader, &infoHeader, &rwHeader, &roHeader);\n\t\t\tif (error < 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to parse data before write\");\n\t\t\t\tPPCCoreCallback(gWriteCallbacks[chan], chan, -0x3E3, context);\n\t\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Prepare data\n\t\t\tmemcpy(rawData + _swapEndianU16(infoHeader.rwHeaderOffset), &rwHeader, sizeof(rwHeader));\n\t\t\tmemcpy(rawData + _swapEndianU16(infoHeader.roHeaderOffset), &roHeader, sizeof(roHeader));\n\t\t\tmemcpy(rawData + _swapEndianU16(roHeader.offset), roData, _swapEndianU16(roHeader.size));\n\t\t\terror = __NTAGPrepareWriteData(writeBuffer, gWriteData[chan].size, gWriteData[chan].data, rawData, &noftHeader, &rwHeader);\n\t\t\tif (error < 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to prepare write data\");\n\t\t\t\tPPCCoreCallback(gWriteCallbacks[chan], chan, -0x3E3, context);\n\t\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Write data to tag\n\t\t\terror = nfc::NFCWrite(chan, 200, &gWriteData[chan].uid, &gWriteData[chan].uidMask,\n\t\t\t\t_swapEndianU16(rwHeader.size) + 0x28, writeBuffer, RPLLoader_MakePPCCallable(__NTAGWriteCallback), context);\n\t\t\tif (error >= 0)\n\t\t\t{\n\t\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\terror = __NTAGConvertNFCResult(error);\n\t\t}\n\n\t\tPPCCoreCallback(gWriteCallbacks[chan], chan, error, context);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tsint32 NTAGWrite(uint32 chan, uint32 timeout, nfc::NFCUid* uid, uint32 rwSize, void* rwData, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\t\tcemu_assert(rwSize < 0x1C8);\n\n\t\tgWriteCallbacks[chan] = callback;\n\n\t\tif (uid)\n\t\t{\n\t\t\tmemcpy(&gWriteData[chan].uid, uid, sizeof(nfc::NFCUid));\n\t\t}\n\t\tmemset(&gWriteData[chan].uidMask, 0xff, sizeof(nfc::NFCUid));\n\n\t\tgWriteData[chan].size = rwSize;\n\t\tmemcpy(gWriteData[chan].data, rwData, rwSize);\n\n\t\tsint32 result = nfc::NFCRead(chan, timeout, &gWriteData[chan].uid, &gWriteData[chan].uidMask, RPLLoader_MakePPCCallable(__NTAGReadBeforeWriteCallback), context);\n\t\treturn __NTAGConvertNFCResult(result);\n\t}\n\n\tsint32 NTAGFormat(uint32 chan, uint32 timeout, nfc::NFCUid* uid, uint32 rwSize, void* rwData, MPTR callback, void* context)\n\t{\n\t\tcemu_assert(chan < 2);\n\n\t\t// TODO\n\t\tcemu_assert_debug(false);\n\n\t\treturn NTAG_RESULT_INVALID;\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"ntag\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"ntag\", NTAGInit, LogType::NTAG);\n\t\t\tcafeExportRegister(\"ntag\", NTAGInitEx, LogType::NTAG);\n\t\t\tcafeExportRegister(\"ntag\", NTAGShutdown, LogType::NTAG);\n\t\t\tcafeExportRegister(\"ntag\", NTAGIsInit, LogType::Placeholder); // disabled logging, since this gets spammed\n\t\t\tcafeExportRegister(\"ntag\", NTAGProc, LogType::Placeholder); // disabled logging, since this gets spammed\n\t\t\tcafeExportRegister(\"ntag\", NTAGSetFormatSettings, LogType::NTAG);\n\t\t\tcafeExportRegister(\"ntag\", NTAGSetTagDetectCallback, LogType::NTAG);\n\t\t\tcafeExportRegister(\"ntag\", NTAGAbort, LogType::NTAG);\n\t\t\tcafeExportRegister(\"ntag\", NTAGRead, LogType::NTAG);\n\t\t\tcafeExportRegister(\"ntag\", NTAGWrite, LogType::NTAG);\n\t\t\tcafeExportRegister(\"ntag\", NTAGFormat, LogType::NTAG);\n\t\t};\n\t}s_COSntagModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSntagModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/ntag/ntag.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/nfc/nfc.h\"\n#include \"Cafe/OS/RPL/COSModule.h\"\n\n#define NTAG_RESULT_SUCCESS\t\t(0)\n#define NTAG_RESULT_UNINITIALIZED\t(-0x3E7)\n#define NTAG_RESULT_INVALID_STATE\t(-0x3E6)\n#define NTAG_RESULT_NO_TAG\t\t(-0x3E5)\n#define NTAG_RESULT_INVALID\t\t(-0x3E1)\n#define NTAG_RESULT_UID_MISMATCH\t(-0x3DB)\n\nnamespace ntag\n{\n\tstruct NTAGFormatSettings\n\t{\n\t\t/* +0x00 */ uint8 version;\n\t\t/* +0x04 */ uint32 makerCode;\n\t\t/* +0x08 */ uint32 identifyCode;\n\t\t/* +0x0C */ uint8 reserved[0x1C];\n\t};\n\tstatic_assert(sizeof(NTAGFormatSettings) == 0x28);\n\n#pragma pack(1)\n\tstruct NTAGNoftHeader\n\t{\n\t\t/* +0x00 */ uint32 magic;\n\t\t/* +0x04 */ uint8 version;\n\t\t/* +0x05 */ uint16 writeCount;\n\t\t/* +0x07 */ uint8 unknown;\n\t};\n\tstatic_assert(sizeof(NTAGNoftHeader) == 0x8);\n#pragma pack()\n\n\tstruct NTAGInfoHeader\n\t{\n\t\t/* +0x00 */ uint16 rwHeaderOffset;\n\t\t/* +0x02 */ uint16 rwSize;\n\t\t/* +0x04 */ uint16 roHeaderOffset;\n\t\t/* +0x06 */ uint16 roSize;\n\t\t/* +0x08 */ nfc::NFCUid uid;\n\t\t/* +0x0F */ uint8 formatVersion;\n\t};\n\tstatic_assert(sizeof(NTAGInfoHeader) == 0x10);\n\n\tstruct NTAGAreaHeader\n\t{\n\t\t/* +0x00 */ uint16 magic;\n\t\t/* +0x02 */ uint16 offset;\n\t\t/* +0x04 */ uint16 size;\n\t\t/* +0x06 */ uint16 padding;\n\t\t/* +0x08 */ uint32 makerCode;\n\t\t/* +0x0C */ uint32 identifyCode;\n\t};\n\tstatic_assert(sizeof(NTAGAreaHeader) == 0x10);\n\n\tstruct NTAGAreaInfo\n\t{\n\t\t/* +0x00 */ MPTR data;\n\t\t/* +0x04 */ uint16 size;\n\t\t/* +0x06 */ uint16 padding;\n\t\t/* +0x08 */ uint32 makerCode;\n\t\t/* +0x0C */ uint32 identifyCode;\n\t\t/* +0x10 */ uint8 reserved[0x20];\n\t};\n\tstatic_assert(sizeof(NTAGAreaInfo) == 0x30);\n\n\tstruct NTAGData\n\t{\n\t\t/* +0x00 */ nfc::NFCUid uid;\n\t\t/* +0x07 */ uint8 readOnly;\n\t\t/* +0x08 */ uint8 formatVersion;\n\t\t/* +0x09 */ uint8 padding[3];\n\t\t/* +0x0C */ NTAGAreaInfo rwInfo;\n\t\t/* +0x3C */ NTAGAreaInfo roInfo;\n\t\t/* +0x6C */ uint8 reserved[0x20];\n\t};\n\tstatic_assert(sizeof(NTAGData) == 0x8C);\n\n\tsint32 NTAGInit(uint32 chan);\n\n\tsint32 NTAGInitEx(uint32 chan);\n\n\tsint32 NTAGShutdown(uint32 chan);\n\n\tbool NTAGIsInit(uint32 chan);\n\n\tvoid NTAGProc(uint32 chan);\n\n\tvoid NTAGSetFormatSettings(NTAGFormatSettings* formatSettings);\n\n\tvoid NTAGSetTagDetectCallback(uint32 chan, MPTR callback, void* context);\n\n\tsint32 NTAGAbort(uint32 chan, MPTR callback, void* context);\n\n\tsint32 NTAGRead(uint32 chan, uint32 timeout, nfc::NFCUid* uid, nfc::NFCUid* uidMask, MPTR callback, void* context);\n\n\tsint32 NTAGWrite(uint32 chan, uint32 timeout, nfc::NFCUid* uid, uint32 rwSize, void* rwData, MPTR callback, void* context);\n\n\tsint32 NTAGFormat(uint32 chan, uint32 timeout, nfc::NFCUid* uid, uint32 rwSize, void* rwData, MPTR callback, void* context);\n\n\tCOSModule* GetModule();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/padscore/padscore.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/libs/padscore/padscore.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_SystemInfo.h\"\n#include \"WindowSystem.h\"\n#include \"input/InputManager.h\"\n\n// KPAD\n\nenum class KPAD_ERROR : sint32\n{\n\tNONE = 0,\n\tNO_SAMPLE_DATA = -1,\n\tNO_CONTROLLER = -2,\n\tNOT_INITIALIZED = -5,\n};\n\n// WPAD (Wii Controller stuff)\n\nenum WPADRumble\n{\n\tkStopRumble = 0,\n\tkStartRumble = 1,\n};\n\nenum class WPADBatteryLevel : uint8\n{\n\tFULL = 4,\n};\n\nenum class WPADLed : uint8\n{\n\tCHAN0 = (1 << 0),\n\tCHAN1 = (1 << 1),\n\tCHAN2 = (1 << 2),\n\tCHAN3 = (1 << 3),\n};\n\nnamespace padscore \n{\n\tenum WPADState_t\n\t{\n\t\tkWPADStateMaster = 0,\n\t\tkWPADStateShutdown,\n\t\tkWPADStateInitializing,\n\t\tkWPADStateAcquired,\n\t\tkWPADStateReleased,\n\t};\n\tKPADUnifiedWpadStatus_t* g_kpad_ringbuffer = nullptr;\n\tuint32 g_kpad_ringbuffer_length = 0;\n\tbool g_wpad_callback_by_kpad = false;\n\n\tWPADState_t g_wpad_state = kWPADStateMaster;\n\n\tstruct {\n\t\tSysAllocator<coreinit::OSAlarm_t> alarm;\n\t\tbool kpad_initialized = false;\n\n\t\tstruct WPADData\n\t\t{\n\t\t\tMEMPTR<void> extension_callback;\n\t\t\tMEMPTR<void> connectCallback;\n\t\t\tMEMPTR<void> sampling_callback;\n\t\t\tMEMPTR<void> dpd_callback;\n\t\t\tbool dpd_enabled = true;\n\n\t\t\tbool disconnectCalled = false;\n\n\t\t\tBtnRepeat btn_repeat{};\n\t\t} controller_data[InputManager::kMaxWPADControllers] = {};\n\n\t\tint max_controllers = kWPADMaxControllers; // max bt controllers?\n\t} g_padscore;\n}\n\n\n#pragma region WPAD\n\nvoid padscoreExport_WPADGetStatus(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::InputAPI, \"WPADGetStatus()\");\n\tuint32 status = 1;\n\tosLib_returnFromFunction(hCPU, status);\n}\n\nvoid padscoreExport_WPADGetBatteryLevel(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::InputAPI, \"WPADGetBatteryLevel()\");\n\tosLib_returnFromFunction(hCPU, (uint32)WPADBatteryLevel::FULL);\n}\n\nvoid padscoreExport_WPADProbe(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(type, uint32be, 1);\n\n\tcemuLog_log(LogType::InputAPI, \"WPADProbe({})\", channel);\n\n\tif(const auto controller = InputManager::instance().get_wpad_controller(channel))\n\t{\n\t\tif(type)\n\t\t\t*type = controller->get_device_type();\n\n\t\tosLib_returnFromFunction(hCPU, WPAD_ERR_NONE);\n\t}\n\telse\n\t{\n\t\tif(type)\n\t\t\t*type = 253;\n\n\t\tosLib_returnFromFunction(hCPU, WPAD_ERR_NO_CONTROLLER);\n\t}\n}\n\ntypedef struct\n{\n\tuint32be dpd;\n\tuint32be speaker;\n\tuint32be attach;\n\tuint32be lowBat;\n\tuint32be nearempty;\n\tbetype<WPADBatteryLevel> batteryLevel;\n\tbetype<WPADLed> led;\n\tuint8 protocol;\n\tuint8 firmware;\n}WPADInfo_t;\n\nstatic_assert(sizeof(WPADInfo_t) == 0x18); // unsure\n\nvoid padscoreExport_WPADGetInfoAsync(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamStructPtr(wpadInfo, WPADInfo_t, 1);\n\tppcDefineParamMPTR(callbackFunc, 2);\n\tcemuLog_log(LogType::InputAPI, \"WPADGetInfoAsync({}, 0x{:08x}, 0x{:08x})\", channel, memory_getVirtualOffsetFromPointer(wpadInfo), callbackFunc);\n\n\tif (channel < InputManager::kMaxWPADControllers)\n\t{\n\t\tif (const auto controller = InputManager::instance().get_wpad_controller(channel))\n\t\t{\n\t\t\twpadInfo->dpd = FALSE;\n\t\t\twpadInfo->speaker = FALSE;\n\t\t\twpadInfo->attach = FALSE;\n\t\t\twpadInfo->lowBat = FALSE;\n\t\t\twpadInfo->nearempty = FALSE;\n\t\t\twpadInfo->batteryLevel = WPADBatteryLevel::FULL;\n\t\t\twpadInfo->led = WPADLed::CHAN0;\n\n\t\t\tif(callbackFunc != MPTR_NULL)\n\t\t\t\tcoreinitAsyncCallback_add(callbackFunc, 2, channel, (uint32)KPAD_ERROR::NONE);\n\n\t\t\tosLib_returnFromFunction(hCPU, WPAD_ERR_NONE);\n\t\t\treturn;\n\t\t}\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tif (callbackFunc != MPTR_NULL)\n\t\tcoreinitAsyncCallback_add(callbackFunc, 2, channel, (uint32)KPAD_ERROR::NO_CONTROLLER);\n\n\tosLib_returnFromFunction(hCPU, WPAD_ERR_NO_CONTROLLER);\n}\n\nvoid padscoreExport_WPADRead(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(wpadStatus, WPADStatus_t, 1);\n\tcemuLog_log(LogType::InputAPI, \"WPADRead({}, {:x})\", channel, fmt::ptr(wpadStatus));\n\n\tif (channel < InputManager::kMaxWPADControllers)\n\t{\n\t\tif(const auto controller = InputManager::instance().get_wpad_controller(channel) )\n\t\t{\n\t\t\tcontroller->WPADRead(wpadStatus);\n\t\t}\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\tosLib_returnFromFunction(hCPU, WPAD_ERR_NO_CONTROLLER);\n}\n\nvoid padscoreExport_WPADSetDataFormat(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamU32(fmt, 1);\n\tcemuLog_log(LogType::InputAPI, \"WPADSetDataFormat({}, {})\", channel, fmt);\n\n\tif (channel < InputManager::kMaxWPADControllers)\n\t{\n\t\tif (const auto controller = InputManager::instance().get_wpad_controller(channel))\n\t\t\tcontroller->set_data_format((WPADDataFormat)fmt);\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid padscoreExport_WPADGetDataFormat(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tcemuLog_log(LogType::InputAPI, \"WPADGetDataFormat({})\", channel);\n\n\tsint32 dataFormat = kDataFormat_CORE;\n\tif (channel < InputManager::kMaxWPADControllers)\n\t{\n\t\tif (const auto controller = InputManager::instance().get_wpad_controller(channel))\n\t\t\tdataFormat = controller->get_data_format();\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, dataFormat);\n}\n\nvoid padscoreExport_WPADGetInfo(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamStructPtr(wpadInfo, WPADInfo_t, 1);\n\tcemuLog_log(LogType::InputAPI, \"WPADGetInfo({}, 0x{:08x})\", channel, fmt::ptr(wpadInfo));\n\n\tif (channel < InputManager::kMaxWPADControllers)\n\t{\n\t\tif (const auto controller = InputManager::instance().get_wpad_controller(channel))\n\t\t{\n\t\t\twpadInfo->dpd = FALSE;\n\t\t\twpadInfo->speaker = FALSE;\n\t\t\twpadInfo->attach = FALSE;\n\t\t\twpadInfo->lowBat = FALSE;\n\t\t\twpadInfo->nearempty = FALSE;\n\t\t\twpadInfo->batteryLevel = WPADBatteryLevel::FULL;\n\t\t\twpadInfo->led = WPADLed::CHAN0;\n\n\t\t\tosLib_returnFromFunction(hCPU, WPAD_ERR_NONE);\n\t\t\treturn;\n\t\t}\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, WPAD_ERR_NO_CONTROLLER);\n}\n\n\nvoid padscoreExport_WPADIsMotorEnabled(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_log(LogType::InputAPI, \"WPADIsMotorEnabled()\");\n\tosLib_returnFromFunction(hCPU, TRUE);\n}\n\nvoid padscoreExport_WPADControlMotor(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamU32(command, 1);\n\tcemuLog_log(LogType::InputAPI, \"WPADControlMotor({}, {})\", channel, command);\n\t\n\tif (channel < InputManager::kMaxWPADControllers)\n\t{\n\t\tif (const auto controller = InputManager::instance().get_wpad_controller(channel))\n\t\t{\n\t\t\tif( command == kStartRumble )\n\t\t\t\tcontroller->start_rumble();\n\t\t\telse\n\t\t\t\tcontroller->stop_rumble();\n\t\t}\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n#pragma endregion\n\n\n\n#pragma region KPAD\nvoid padscoreExport_KPADGetUnifiedWpadStatus(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(status, KPADUnifiedWpadStatus_t, 1);\n\tppcDefineParamU32(count, 2);\n\n\tcemuLog_log(LogType::InputAPI, \"KPADGetUnifiedWpadStatus({}, 0x{:08x}, 0x{:x})\", channel, MEMPTR<void>(status).GetMPTR(), count);\n\n\tif (channel < InputManager::kMaxWPADControllers)\n\t{\n\t\tmemset(status, 0x00, sizeof(KPADUnifiedWpadStatus_t) * count);\n\n\t\tif (const auto controller = InputManager::instance().get_wpad_controller(channel))\n\t\t{\n\t\t\tswitch (controller->get_data_format())\n\t\t\t{\n\t\t\tcase WPAD_FMT_CORE:\n\t\t\tcase WPAD_FMT_CORE_ACC:\n\t\t\tcase WPAD_FMT_CORE_ACC_DPD:\n\t\t\t{\n\t\t\t\tstatus->fmt = controller->get_data_format();\n\t\t\t\tcontroller->WPADRead(&status->u.core);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tdebugBreakpoint();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstatus->u.core.err = WPAD_ERR_NO_CONTROLLER;\n\t\t}\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid padscoreExport_KPADSetBtnRepeat(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tfloat delaySec = hCPU->fpr[1].fpr;\n\tfloat pulseSec = hCPU->fpr[2].fpr;\n\tcemuLog_log(LogType::InputAPI, \"KPADSetBtnRepeat({}, {}, {})\", channel, delaySec, pulseSec);\n\n\tif (channel < InputManager::kMaxWPADControllers)\n\t{\n\t\tpadscore::g_padscore.controller_data[channel].btn_repeat = { (int)delaySec, (int)pulseSec };\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid padscoreExport_KPADSetSamplingCallback(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamMPTR(callback, 1);\n\n\tcemuLog_log(LogType::InputAPI, \"KPADSetSamplingCallback({}, 0x{:x})\", channel, callback);\n\n\tif (channel >= InputManager::kMaxWPADControllers)\n\t{\n\t\tdebugBreakpoint();\n\t\tosLib_returnFromFunction(hCPU, MPTR_NULL);\n\t\treturn;\n\t}\n\n\tconst auto old_callback = padscore::g_padscore.controller_data[channel].sampling_callback;\n\tpadscore::g_padscore.controller_data[channel].sampling_callback = callback;\n\tosLib_returnFromFunction(hCPU, old_callback.GetMPTR());\n}\n\nvoid padscoreExport_WPADControlDpd(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamU32(command, 1);\n\tppcDefineParamMPTR(callback, 2);\n\n\tcemuLog_log(LogType::InputAPI, \"WPADControlDpd({}, {}, 0x{:x})\", channel, command, callback);\n\n\tif (channel < InputManager::kMaxWPADControllers)\n\t{\n\t\tif (const auto controller = InputManager::instance().get_wpad_controller(channel))\n\t\t{\n\t\t\tpadscore::g_padscore.controller_data[channel].dpd_callback = callback;\n\t\t\tif (callback)\n\t\t\t{\n\t\t\t\tcoreinitAsyncCallback_add(callback, 2, channel, WPAD_ERR_NONE);\n\t\t\t}\n\n\t\t\tosLib_returnFromFunction(hCPU, WPAD_ERR_NONE);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tosLib_returnFromFunction(hCPU, WPAD_ERR_NO_CONTROLLER);\n}\n\nvoid padscoreExport_WPADSetExtensionCallback(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamMPTR(callback, 1);\n\n\tcemuLog_log(LogType::InputAPI, \"WPADSetExtensionCallback({}, 0x{:x})\", channel, callback);\n\n\tif (channel >= InputManager::kMaxWPADControllers)\n\t{\n\t\tdebugBreakpoint();\n\t\tosLib_returnFromFunction(hCPU, MPTR_NULL);\n\t\treturn;\n\t}\n\n\tconst auto old_callback = padscore::g_padscore.controller_data[channel].extension_callback;\n\tpadscore::g_padscore.controller_data[channel].extension_callback = callback;\n\tosLib_returnFromFunction(hCPU, old_callback.GetMPTR());\n}\n\nvoid padscoreExport_KPADSetConnectCallback(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamMPTR(callback, 1);\n\n\tcemuLog_log(LogType::InputAPI, \"KPADSetConnectCallback({}, 0x{:x})\",channel, callback);\n\n\tif (channel >= InputManager::kMaxWPADControllers)\n\t{\n\t\tdebugBreakpoint();\n\t\tosLib_returnFromFunction(hCPU, MPTR_NULL);\n\t\treturn;\n\t}\n\n\tconst auto old_callback = padscore::g_padscore.controller_data[channel].connectCallback;\n\tpadscore::g_padscore.controller_data[channel].connectCallback = callback;\n\tosLib_returnFromFunction(hCPU, old_callback.GetMPTR());\n}\n\nuint64 g_kpadLastRead[InputManager::kMaxWPADControllers] = {0};\nbool g_kpadIsInited = true;\n\nsint32 _KPADRead(uint32 channel, KPADStatus_t* samplingBufs, uint32 length, betype<KPAD_ERROR>* errResult)\n{\n\n\tif (channel >= InputManager::kMaxWPADControllers)\n\t{\n\t\tdebugBreakpoint();\n\t\treturn 0;\n\t}\n\t\n\tif (g_kpadIsInited == false)\n\t{\n\t\tif (errResult)\n\t\t\t*errResult = KPAD_ERROR::NOT_INITIALIZED;\n\n\t\treturn 0;\n\t}\n\n\tconst auto controller = InputManager::instance().get_wpad_controller(channel);\n\tif (!controller)\n\t{\n\t\tif (errResult)\n\t\t\t*errResult = KPAD_ERROR::NO_CONTROLLER;\n\n\t\treturn 0;\n\t}\n\n\t// On console new input samples are only received every few ms and calling KPADRead(Ex) clears the internal queue regardless of length value\n\t// thus calling KPADRead(Ex) again too soon on the same channel will result in no data being returned\n\t// Games that depend on this: Affordable Space Adventures\n\tuint64 currentTime = coreinit::OSGetTime();\n\tuint64 timeDif = currentTime - g_kpadLastRead[channel];\n\tif(length == 0 || timeDif < coreinit::EspressoTime::ConvertNsToTimerTicks(1000000))\n\t{\n\t\tif (errResult)\n\t\t\t*errResult = KPAD_ERROR::NO_SAMPLE_DATA;\n\t\treturn 0;\n\t}\n\tg_kpadLastRead[channel] = currentTime;\n\n\tmemset(samplingBufs, 0x00, sizeof(KPADStatus_t));\n\tsamplingBufs->wpadErr = WPAD_ERR_NONE;\n\tsamplingBufs->data_format = controller->get_data_format();\n\tsamplingBufs->devType = controller->get_device_type();\n\tif(!WindowSystem::InputConfigWindowHasFocus())\n\t{\n\t\tconst auto btn_repeat = padscore::g_padscore.controller_data[channel].btn_repeat;\n\t\tcontroller->KPADRead(*samplingBufs, btn_repeat);\n\t}\n\n\tif (errResult)\n\t\t*errResult = KPAD_ERROR::NONE;\n\n\treturn 1;\n}\n\nvoid padscoreExport_KPADReadEx(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(kpadStatus, KPADStatus_t, 1);\n\tppcDefineParamU32(length, 2);\n\tppcDefineParamPtr(errResult, betype<KPAD_ERROR>, 3);\n\tcemuLog_log(LogType::InputAPI, \"KPADReadEx({}, 0x{:x})\", channel, length);\n\n\tsint32 samplesRead = _KPADRead(channel, kpadStatus, length, errResult);\n\tosLib_returnFromFunction(hCPU, samplesRead);\n}\n\nvoid padscoreExport_KPADRead(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(kpadStatus, KPADStatus_t, 1);\n\tppcDefineParamU32(length, 2);\n\tcemuLog_log(LogType::InputAPI, \"KPADRead({}, 0x{:x})\", channel, length);\n\n\tsint32 samplesRead = _KPADRead(channel, kpadStatus, length, nullptr);\n\tosLib_returnFromFunction(hCPU, samplesRead);\n}\n\n\n\n\n\n\n#pragma endregion\n\n\n\nnamespace padscore\n{\n\tvoid export_KPADEnableDPD(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamS32(channel, 0);\n\t\tcemuLog_log(LogType::InputAPI, \"KPADEnableDPD({})\", channel);\n\t\tcemu_assert_debug(0 <= channel && channel < InputManager::kMaxWPADControllers);\n\n\t\tif(const auto controller = InputManager::instance().get_wpad_controller(channel))\n\t\t{\n\t\t\tif (controller->get_data_format() != kDataFormat_FREESTYLE && controller->get_data_format() != 0x1F)\n\t\t\t\tg_padscore.controller_data[channel].dpd_enabled = true;\n\t\t}\n\t\t\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_KPADGetMplsWorkSize(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"KPADGetMplsWorkSize()\");\n\t\tosLib_returnFromFunction(hCPU, 0x5FE0);\n\t}\n\n\tvoid KPADInitEx(KPADUnifiedWpadStatus_t ring_buffer[], uint32 length)\n\t{\n\t\tif (g_padscore.kpad_initialized)\n\t\t\treturn;\n\n\t\tfor (uint32 i = 0; i < InputManager::kMaxWPADControllers; i++)\n\t\t{\n\t\t\tg_padscore.controller_data[i].dpd_enabled = true;\n\n\n\t\t}\n\n\t\tg_kpad_ringbuffer = ring_buffer;\n\t\tg_kpad_ringbuffer_length = length;\n\t\tg_padscore.kpad_initialized = true;\n\t}\n\n\tvoid export_KPADInit(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"KPADInit()\");\n\t\tKPADInitEx(nullptr, 0);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_KPADInitEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamMEMPTR(ring_buffer, KPADUnifiedWpadStatus_t, 0);\n\t\tppcDefineParamU32(length, 1);\n\t\tcemuLog_log(LogType::InputAPI, \"KPADInitEx(0x{:08x}, 0x{:x})\", ring_buffer.GetMPTR(), length);\n\t\tKPADInitEx(ring_buffer.GetPtr(), length);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid WPADSetCallbackByKPAD(bool state)\n\t{\n\t\tg_wpad_callback_by_kpad = state;\n\t}\n\n\tvoid export_WPADSetCallbackByKPAD(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(state, 0);\n\t\tcemuLog_log(LogType::InputAPI, \"WPADSetCallbackByKPAD({})\", state);\n\t\tWPADSetCallbackByKPAD(state);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_KPADGetMaxControllers(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"KPADGetMaxControllers()\");\n\t\tsint32 max_controllers = g_padscore.max_controllers;\n\t\tosLib_returnFromFunction(hCPU, max_controllers);\n\t}\n\n\tbool WPADIsUsedCallbackByKPAD()\n\t{\n\t\treturn g_wpad_callback_by_kpad == TRUE;\n\t}\n\n\tvoid* WPADSetSamplingCallback(sint32 channel, void* callback)\n\t{\n\t\tcemu_assert_debug(0 <= channel && channel < kKPADMaxControllers);\n\n\t\tconst auto result = g_padscore.controller_data[channel].sampling_callback;\n\t\tg_padscore.controller_data[channel].sampling_callback = callback;\n\t\treturn result.GetPtr();\n\t}\n\n\tvoid export_KPADSetMaxControllers(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamU32(new_max_count, 0);\n\t\tcemuLog_log(LogType::InputAPI, \"KPADSetMaxControllers({})\", new_max_count);\n\n\t\tif (new_max_count != kKPADMaxControllers && new_max_count != kWPADMaxControllers)\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t\tosLib_returnFromFunction(hCPU, -4);\n\t\t\treturn;\n\t\t}\n\n\n\t\tconst uint32 max_controllers = g_padscore.max_controllers;\n\t\tif (max_controllers == new_max_count)\n\t\t{\n\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\treturn;\n\t\t}\n\n\t\tWPADSetCallbackByKPAD(FALSE);\n\t\tfor (sint32 i = 0; i < kKPADMaxControllers; i++)\n\t\t{\n\t\t\t//WPADSetSamplingCallback(i, 0); TODO\n\t\t}\n\n\t\tg_padscore.max_controllers = new_max_count;\n\t\t\n\t\tWPADSetCallbackByKPAD(true);\n\t\tosLib_returnFromFunction(hCPU, new_max_count);\n\t}\n\n\tvoid export_WPADInit()\n\t{\n\t\tif (g_wpad_state != kWPADStateShutdown)\n\t\t{\n\t\t\tif (g_wpad_state == kWPADStateInitializing || g_wpad_state == kWPADStateAcquired)\n\t\t\t\treturn;\n\t\t}\n\t\tg_wpad_state = kWPADStateInitializing;\n\t}\n\n\n\tenum class WPADStatus : sint32\n\t{\n\t\tSuccess = 0,\n\t\tNoController = -1,\n\t\tBusy = -2,\n\t};\n\n\tWPADStatus WPADIsMplsAttached(sint32 index, uint32be* attached, void* callback)\n\t{\n\t\tif (index >= kKPADMaxControllers)\n\t\t\treturn WPADStatus::NoController;\n\n\t\tconst auto controller = InputManager::instance().get_wpad_controller(index);\n\t\t*attached = controller && controller->is_mpls_attached();\n\n\t\tif (callback)\n\t\t\tPPCCoreCallback(MEMPTR(callback), index, controller ? WPADStatus::Success : WPADStatus::NoController);\n\n\t\treturn WPADStatus::Success;\n\t}\n\n\tstruct WPADAcc\n\t{\n\t\tsint32be x;\n\t\tsint32be y;\n\t\tsint32be z;\n\t};\n\tvoid WPADGetAccGravityUnit(sint32 index, uint32 type, WPADAcc* acc)\n\t{\n\t\tif (index >= kKPADMaxControllers)\n\t\t\treturn;\n\n\t\t// default values for wiimote usually are around 99\n\t\tacc->x = 99;\n\t\tacc->y = 99;\n\t\tacc->z = 99;\n\t}\n\n\n#pragma endregion\n\n\tvoid TickFunction(PPCInterpreter_t* hCPU)\n\t{\n\t\tauto& instance = InputManager::instance();\n\t\t// test for connected/disconnected controllers\n\t\tfor (auto i = 0; i < InputManager::kMaxWPADControllers; ++i)\n\t\t{\n\t\t\tif (g_padscore.controller_data[i].connectCallback) \n\t\t\t{\n\t\t\t\tif(!g_padscore.controller_data[i].disconnectCalled)\n\t\t\t\t{\n\t\t\t\t\tg_padscore.controller_data[i].disconnectCalled = true;\n\t\t\t\t\tcemuLog_log(LogType::InputAPI, \"Calling WPADConnectCallback({}, {})\", i, WPAD_ERR_NO_CONTROLLER);\n\t\t\t\t\tPPCCoreCallback(g_padscore.controller_data[i].connectCallback, i, WPAD_ERR_NO_CONTROLLER);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (const auto controller = instance.get_wpad_controller(i))\n\t\t\t\t{\n\t\t\t\t\tif (controller->m_status == WPADController::ConnectCallbackStatus::ReportDisconnect || controller->was_home_button_down()) // fixed!\n\t\t\t\t\t{\n\t\t\t\t\t\tcontroller->m_status = WPADController::ConnectCallbackStatus::ReportConnect;\n\n\t\t\t\t\t\tcemuLog_log(LogType::InputAPI, \"Calling WPADConnectCallback({}, {})\", i, WPAD_ERR_NO_CONTROLLER);\n\t\t\t\t\t\tPPCCoreCallback(g_padscore.controller_data[i].connectCallback, i, WPAD_ERR_NO_CONTROLLER);\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\telse if (controller->m_status == WPADController::ConnectCallbackStatus::ReportConnect) \n\t\t\t\t\t{\n\t\t\t\t\t\tcontroller->m_status = WPADController::ConnectCallbackStatus::None;\n\t\t\t\t\t\tcemuLog_log(LogType::InputAPI, \"Calling WPADConnectCallback({}, {})\", i, WPAD_ERR_NONE);\n\t\t\t\t\t\tPPCCoreCallback(g_padscore.controller_data[i].connectCallback, i, WPAD_ERR_NONE);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// test for connected/disconnected extensions\n\t\tfor (auto i = 0; i < InputManager::kMaxWPADControllers; ++i)\n\t\t{\n\t\t\tif (g_padscore.controller_data[i].extension_callback) \n\t\t\t{\n\t\t\t\tif (const auto controller = instance.get_wpad_controller(i))\n\t\t\t\t{\n\t\t\t\t\tif (controller->m_extension_status == WPADController::ConnectCallbackStatus::ReportConnect)\n\t\t\t\t\t{\n\t\t\t\t\t\tcontroller->m_extension_status = WPADController::ConnectCallbackStatus::None;\n\t\t\t\t\t\tcemuLog_log(LogType::InputAPI, \"Calling WPADextensionCallback({})\", i);\n\t\t\t\t\t\tPPCCoreCallback(g_padscore.controller_data[i].extension_callback, i, controller->get_device_type());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// call sampling callback\n\t\tfor (auto i = 0; i < InputManager::kMaxWPADControllers; ++i)\n\t\t{\n\t\t\tif (g_padscore.controller_data[i].sampling_callback)\n\t\t\t{\n\t\t\t\tif (const auto controller = instance.get_wpad_controller(i))\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::InputAPI, \"Calling WPADsamplingCallback({})\", i);\n\t\t\t\t\tPPCCoreCallback(g_padscore.controller_data[i].sampling_callback, i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\tvoid start()\n\t{\n\t\tOSCreateAlarm(&g_padscore.alarm);\n\t\tconst uint64 start_tick = coreinit::OSGetTime();\n\t\tconst uint64 period_tick = coreinit::EspressoTime::GetTimerClock() / 200; // every 5ms\n\t\tMPTR handler = PPCInterpreter_makeCallableExportDepr(TickFunction);\n\t\tOSSetPeriodicAlarm(&g_padscore.alarm, start_tick, period_tick, handler);\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"padscore\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"padscore\", WPADIsMplsAttached, LogType::InputAPI);\n\t\t\tcafeExportRegister(\"padscore\", WPADGetAccGravityUnit, LogType::InputAPI);\n\n\t\t\t// wpad\n\t\t\t//osLib_addFunction(\"padscore\", \"WPADInit\", padscore::export_WPADInit);\n\n\t\t\t// kpad\n\t\t\tosLib_addFunction(\"padscore\", \"KPADSetMaxControllers\", padscore::export_KPADSetMaxControllers);\n\t\t\tosLib_addFunction(\"padscore\", \"KPADGetMaxControllers\", padscore::export_KPADGetMaxControllers);\n\t\t\tosLib_addFunction(\"padscore\", \"KPADEnableDPD\", padscore::export_KPADEnableDPD);\n\t\t\tosLib_addFunction(\"padscore\", \"KPADGetMplsWorkSize\", padscore::export_KPADGetMplsWorkSize);\n\t\t\tosLib_addFunction(\"padscore\", \"KPADInit\", padscore::export_KPADInit);\n\t\t\tosLib_addFunction(\"padscore\", \"KPADInitEx\", padscore::export_KPADInitEx);\n\n\t\t\tosLib_addFunction(\"padscore\", \"KPADSetConnectCallback\", padscoreExport_KPADSetConnectCallback);\n\t\t\tosLib_addFunction(\"padscore\", \"KPADReadEx\", padscoreExport_KPADReadEx);\n\t\t\tosLib_addFunction(\"padscore\", \"KPADRead\", padscoreExport_KPADRead);\n\t\t\tosLib_addFunction(\"padscore\", \"KPADGetUnifiedWpadStatus\", padscoreExport_KPADGetUnifiedWpadStatus);\n\t\t\tosLib_addFunction(\"padscore\", \"KPADSetSamplingCallback\", padscoreExport_KPADSetSamplingCallback);\n\t\t\tosLib_addFunction(\"padscore\", \"KPADSetBtnRepeat\", padscoreExport_KPADSetBtnRepeat);\n\n\t\t\tosLib_addFunction(\"padscore\", \"WPADGetBatteryLevel\", padscoreExport_WPADGetBatteryLevel);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADControlMotor\", padscoreExport_WPADControlMotor);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADIsMotorEnabled\", padscoreExport_WPADIsMotorEnabled);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADGetStatus\", padscoreExport_WPADGetStatus);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADProbe\", padscoreExport_WPADProbe);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADGetInfoAsync\", padscoreExport_WPADGetInfoAsync);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADGetInfo\", padscoreExport_WPADGetInfo);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADSetConnectCallback\", padscoreExport_KPADSetConnectCallback);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADSetDataFormat\", padscoreExport_WPADSetDataFormat);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADGetDataFormat\", padscoreExport_WPADGetDataFormat);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADRead\", padscoreExport_WPADRead);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADSetExtensionCallback\", padscoreExport_WPADSetExtensionCallback);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADSetSamplingCallback\", padscoreExport_KPADSetSamplingCallback);\n\t\t\tosLib_addFunction(\"padscore\", \"WPADControlDpd\", padscoreExport_WPADControlDpd);\n\n\t\t\tosLib_addFunction(\"padscore\", \"WPADSetCallbackByKPAD\", padscore::export_WPADSetCallbackByKPAD);\n\t\t};\n\n\t}s_COSCoreinitModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSCoreinitModule;\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/padscore/padscore.h",
    "content": "#pragma once\n\n#include \"util/math/vector3.h\"\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace padscore\n{\n\tvoid start();\n\tCOSModule* GetModule();\n}\n\nconstexpr int kWPADMaxControllers = 4;\nconstexpr int kKPADMaxControllers = 7;\n\n#define WPAD_ERR_NONE\t\t\t\t0\n#define WPAD_ERR_NO_CONTROLLER\t\t-1\n#define WPAD_ERR_BUSY\t\t\t\t-2\n#define WPAD_ERR_INVALID\t\t\t-4\n\n#define WPAD_PRESS_UNITS\t\t\t4\n\n#define WPAD_FMT_CORE\t\t\t\t0\n#define WPAD_FMT_CORE_ACC\t\t\t1\n#define WPAD_FMT_CORE_ACC_DPD\t\t2\n\ntypedef struct\n{\n\tfloat x;\n\tfloat y;\n\tfloat z;\n}padVec3D_t;\n\nstatic_assert(sizeof(padVec3D_t) == 0xC);\n\ntypedef struct beVec3D\n{\n\tfloat32be x;\n\tfloat32be y;\n\tfloat32be z;\n\n\tbeVec3D() = default;\n\n\tbeVec3D(const Vector3<float>& v)\n\t\t: x(v.x), y(v.y), z(v.z) {}\n\n\tbeVec3D(const float32be& x, const float32be& y, const float32be& z)\n\t\t: x(x), y(y), z(z) {}\n\n}beVec3D_t;\n\nstatic_assert(sizeof(beVec3D_t) == 0xC);\n\ntypedef struct\n{\n\tfloat x;\n\tfloat y;\n}padVec2D_t;\n\nstatic_assert(sizeof(padVec2D_t) == 0x8);\n\ntypedef struct\n{\n\tfloat32be x;\n\tfloat32be y;\n}beVec2D_t;\n\nstatic_assert(sizeof(beVec2D_t) == 0x8);\n\nunion KPADEXStatus_t\n{\n\tstruct\n\t{\n\t\tbeVec2D_t stick;\n\t\tbeVec3D_t acc;\n\t\tfloat32be accValue;\n\t\tfloat32be accSpeed;\n\t}fs;\n\tstruct\n\t{\n\t\tuint32be hold;\n\t\tuint32be trig;\n\t\tuint32be release;\n\t\tbeVec2D_t lstick;\n\t\tbeVec2D_t rstick;\n\t\tfloat32be ltrigger;\n\t\tfloat32be rtrigger;\n\t}cl;\n\tstruct\n\t{\n\t\tuint32be hold;\n\t\tuint32be trig;\n\t\tuint32be release;\n\t\tbeVec2D_t lstick;\n\t\tbeVec2D_t rstick;\n\t\tuint32be charge;\n\t\tuint32be cable;\n\t}uc;\n\tstruct\n\t{\n\t\tuint32be hold;\n\t\tuint32be trig;\n\t\tuint32be release;\n\t}cm;\n\tuint8 _padding[0x50];\n};\n\nstatic_assert(sizeof(KPADEXStatus_t) == 0x50);\n\nstruct KPADMPDir_t\n{\n\tpadVec3D_t X;\n\tpadVec3D_t Y;\n\tpadVec3D_t Z;\n};\n\nstatic_assert(sizeof(KPADMPDir_t) == 0x24);\n\nstruct KPADMPStatus_t\n{\n\tpadVec3D_t mpls;\n\tpadVec3D_t angle;\n\tKPADMPDir_t dir;\n};\n\nstatic_assert(sizeof(KPADMPStatus_t) == 0x3C);\n\nstruct KPADStatus_t\n{\n\tuint32be hold;\n\tuint32be trig;\n\tuint32be release;\n\tbeVec3D_t acc;\n\tfloat32be acc_value;\n\tfloat32be acc_speed;\n\tbeVec2D_t pos;\n\tbeVec2D_t vec;\n\tfloat32be speed;\n\tbeVec2D_t horizon;\n\tbeVec2D_t horiVec;\n\tfloat32be horiSpeed;\n\tfloat32be dist;\n\tfloat32be distVec;\n\tfloat32be distSpeed;\n\tbeVec2D_t accVertical;\n\tuint8 devType;\n\tsint8 wpadErr;\n\tsint8 dpd_valid_fg;\n\tuint8 data_format;\n\tKPADEXStatus_t ex_status;\n\tKPADMPStatus_t mpls;\n\tuint8 _unused[4];\n};\n\nstatic_assert(sizeof(KPADStatus_t) == 0xF0);\n\n#define WPAD_DPD_MAX_OBJECTS (4)\n\nstruct DPDObject_t\n{ \n\tuint16be x;\n\tuint16be y;\n\tuint16be size;\n\tuint8 traceId;\n\tuint8 padding;\n};\n\nstatic_assert(sizeof(DPDObject_t) == 0x8);\n\nstruct WPADStatus_t\n{\n\tuint16be button;\n\tuint16be accX;\n\tuint16be accY;\n\tuint16be accZ;\n\tDPDObject_t obj[WPAD_DPD_MAX_OBJECTS];\n\tuint8 dev;\n\tsint8 err;\n};\n\nstatic_assert(sizeof(WPADStatus_t) == 0x2A);\n\nstruct WPADFSStatus_t : WPADStatus_t\n{\n\tuint16be fsAccX;\n\tuint16be fsAccY;\n\tuint16be fsAccZ;\n\tsint8 fsStickX;\n\tsint8 fsStickY;\n};\n\nstruct WPADCLStatus_t : WPADStatus_t\n{\n\tuint16be clButton;\n\tuint16be clLStickX;\n\tuint16be clLStickY;\n\tuint16be clRStickX;\n\tuint16be clRStickY;\n\tuint8 clTriggerL;\n\tuint8 clTriggerR;\n};\n\nstruct WPADUCStatus_t : WPADStatus_t\n{\n\tuint8 padding1[2]; // unsure\n\tuint32be ucButton;\n\tuint16be ucLStickX;\n\tuint16be ucLStickY;\n\tuint16be ucRStickX;\n\tuint16be ucRStickY;\n\tuint32be charge;\n\tuint32be cable;\n};\n\nstatic_assert(sizeof(WPADUCStatus_t) == 0x40);\n\nstruct WPADTRStatus_t : WPADStatus_t\n{\n\tuint16 trButton;\n\tuint8 brake;\n\tuint8 mascon;\n};\n\nstruct WPADBLStatus_t : WPADStatus_t\n{\n\tuint16be press[WPAD_PRESS_UNITS];\n\tsint8 temp;\n\tuint8 battery;\n} ;\n\nstatic_assert(sizeof(WPADBLStatus_t) == 0x34);\n\nstruct WPADMPStatus_t : WPADStatus_t\n{\n\tunion\n\t{\n\t\t// for Nunchuk\n\t\tstruct\n\t\t{\n\t\t\tuint16be fsAccX;\n\t\t\tuint16be fsAccY;\n\t\t\tuint16be fsAccZ;\n\t\t\tsint8 fsStickX;\n\t\t\tsint8 fsStickY;\n\t\t}fs;\n\n\t\t// for Classic\n\t\tstruct\n\t\t{\n\t\t\tuint16be clButton;\n\t\t\tuint16be clLStickX;\n\t\t\tuint16be clLStickY;\n\t\t\tuint16be clRStickX;\n\t\t\tuint16be clRStickY;\n\t\t\tuint8 clTriggerL;\n\t\t\tuint8 clTriggerR;\n\t\t}cl;\n\t}status;\n\tuint8 stat;\n\tuint8 _ukn;\n\tuint16be pitch;\n\tuint16be yaw;\n\tuint16be roll;\n};\n\nstatic_assert(sizeof(WPADMPStatus_t) == 0x3E);\n\ntypedef struct KPADUnifiedWpadStatus\n{\n\tunion\n\t{\n\t\tWPADStatus_t core;\n\t\tWPADFSStatus_t fs;\n\t\tWPADCLStatus_t cl;\n\t\tWPADTRStatus_t tr;\n\t\tWPADBLStatus_t bl;\n\t\tWPADMPStatus_t mp;\n\t}u;\n\tuint8 fmt;\n\tuint8 padding;\n\tuint32 _40; // padding?\n}KPADUnifiedWpadStatus_t;\n\nstatic_assert(sizeof(KPADUnifiedWpadStatus_t) == 0x44);\n\n"
  },
  {
    "path": "src/Cafe/OS/libs/proc_ui/proc_ui.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MessageQueue.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Misc.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Memory.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_FG.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_DynLoad.h\"\n#include \"Cafe/OS/libs/gx2/GX2_Misc.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Common/CafeString.h\"\n#include \"proc_ui.h\"\n\n// proc_ui is a utility wrapper to help apps with the transition between foreground and background\n// some games (like Xenoblades Chronicles X) bypass proc_ui.rpl and listen to OSGetSystemMessageQueue() directly\n\nusing namespace coreinit;\n\nnamespace proc_ui\n{\n\tenum class ProcUICoreThreadCommand\n\t{\n\t\tAcquireForeground = 0x0,\n\t\tReleaseForeground = 0x1,\n\t\tExit = 0x2,\n\t\tNetIoStart = 0x3,\n\t\tNetIoStop = 0x4,\n\t\tHomeButtonDenied = 0x5,\n\t\tInitial = 0x6\n\t};\n\n\tstruct ProcUIInternalCallbackEntry\n\t{\n\t\tcoreinit::OSAlarm_t alarm;\n\t\tuint64be tickDelay;\n\t\tMEMPTR<void> funcPtr;\n\t\tMEMPTR<void> userParam;\n\t\tsint32be priority;\n\t\tMEMPTR<ProcUIInternalCallbackEntry> next;\n\t};\n\tstatic_assert(sizeof(ProcUIInternalCallbackEntry) == 0x70);\n\n\tstruct ProcUICallbackList\n\t{\n\t\tMEMPTR<ProcUIInternalCallbackEntry> first;\n\t};\n\tstatic_assert(sizeof(ProcUICallbackList) == 0x4);\n\n\tstd::atomic_bool s_isInitialized;\n\tbool s_isInForeground;\n\tbool s_isInShutdown;\n\tbool s_isForegroundProcess;\n\tbool s_previouslyWasBlocking;\n\tProcUIStatus s_currentProcUIStatus;\n\tMEMPTR<void> s_saveCallback; // no param and no return value, set by ProcUIInit()\n\tMEMPTR<void> s_saveCallbackEx; // with custom param and return value, set by ProcUIInitEx()\n\tMEMPTR<void> s_saveCallbackExUserParam;\n\tMEMPTR<coreinit::OSMessageQueue> s_systemMessageQueuePtr;\n\tSysAllocator<coreinit::OSEvent> s_eventStateMessageReceived;\n\tSysAllocator<coreinit::OSEvent> s_eventWaitingBeforeReleaseForeground;\n\tSysAllocator<coreinit::OSEvent> s_eventBackgroundThreadGotMessage;\n\t// procUI core threads\n\tuint32 s_coreThreadStackSize;\n\tbool s_coreThreadsCreated;\n\tstd::atomic<ProcUICoreThreadCommand> s_commandForCoreThread;\n\tSysAllocator<OSThread_t> s_coreThreadArray[Espresso::CORE_COUNT];\n\tMEMPTR<void> s_coreThreadStackPerCore[Espresso::CORE_COUNT];\n\tSysAllocator<CafeString<22>> s_coreThread0NameBuffer;\n\tSysAllocator<CafeString<22>> s_coreThread1NameBuffer;\n\tSysAllocator<CafeString<22>> s_coreThread2NameBuffer;\n\tSysAllocator<coreinit::OSEvent> s_eventCoreThreadsNewCommandReady;\n\tSysAllocator<coreinit::OSEvent> s_eventCoreThreadsCommandDone;\n\tSysAllocator<coreinit::OSRendezvous> s_coreThreadRendezvousA;\n\tSysAllocator<coreinit::OSRendezvous> s_coreThreadRendezvousB;\n\tSysAllocator<coreinit::OSRendezvous> s_coreThreadRendezvousC;\n\t// background thread\n\tMEMPTR<void> s_backgroundThreadStack;\n\tSysAllocator<OSThread_t> s_backgroundThread;\n\t// user defined heap\n\tMEMPTR<void> s_memoryPoolHeapPtr;\n\tMEMPTR<void> s_memAllocPtr;\n\tMEMPTR<void> s_memFreePtr;\n\t// draw done release\n\tbool s_drawDoneReleaseCalled;\n\t// memory storage\n\tMEMPTR<void> s_bucketStorageBasePtr;\n\tMEMPTR<void> s_mem1StorageBasePtr;\n\t// callbacks\n\tProcUICallbackList s_callbacksType0_AcquireForeground[Espresso::CORE_COUNT];\n\tProcUICallbackList s_callbacksType1_ReleaseForeground[Espresso::CORE_COUNT];\n\tProcUICallbackList s_callbacksType2_Exit[Espresso::CORE_COUNT];\n\tProcUICallbackList s_callbacksType3_NetIoStart[Espresso::CORE_COUNT];\n\tProcUICallbackList s_callbacksType4_NetIoStop[Espresso::CORE_COUNT];\n\tProcUICallbackList s_callbacksType5_HomeButtonDenied[Espresso::CORE_COUNT];\n\tProcUICallbackList* const s_CallbackTables[stdx::to_underlying(ProcUICallbackId::COUNT)] =\n\t\t{s_callbacksType0_AcquireForeground, s_callbacksType1_ReleaseForeground, s_callbacksType2_Exit, s_callbacksType3_NetIoStart, s_callbacksType4_NetIoStop, s_callbacksType5_HomeButtonDenied};\n\tProcUICallbackList s_backgroundCallbackList;\n\t// driver\n\tbool s_driverIsActive;\n\tuint32be s_driverArgUkn1;\n\tuint32be s_driverArgUkn2;\n\tbool s_driverInBackground;\n\tSysAllocator<OSDriverInterface> s_ProcUIDriver;\n\tSysAllocator<CafeString<16>> s_ProcUIDriverName;\n\n\n\tvoid* _AllocMem(uint32 size)\n\t{\n\t\tMEMPTR<void> r{PPCCoreCallback(s_memAllocPtr, size)};\n\t\treturn r.GetPtr();\n\t}\n\n\tvoid _FreeMem(void* ptr)\n\t{\n\t\tPPCCoreCallback(s_memFreePtr.GetMPTR(), ptr);\n\t}\n\n\tvoid ClearCallbacksWithoutMemFree()\n\t{\n\t\tfor (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)\n\t\t{\n\t\t\tfor (sint32 i = 0; i < stdx::to_underlying(ProcUICallbackId::COUNT); i++)\n\t\t\t\ts_CallbackTables[i][coreIndex].first = nullptr;\n\t\t}\n\t\ts_backgroundCallbackList.first = nullptr;\n\t}\n\n\tvoid ShutdownThreads()\n\t{\n\t\tif ( !s_coreThreadsCreated)\n\t\t\treturn;\n\t\ts_commandForCoreThread = ProcUICoreThreadCommand::Initial;\n\t\tcoreinit::OSMemoryBarrier();\n\t\tOSSignalEvent(&s_eventCoreThreadsNewCommandReady);\n\t\tfor (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)\n\t\t{\n\t\t\tcoreinit::OSJoinThread(&s_coreThreadArray[coreIndex], nullptr);\n\t\t\tfor (sint32 i = 0; i < stdx::to_underlying(ProcUICallbackId::COUNT); i++)\n\t\t\t{\n\t\t\t\ts_CallbackTables[i][coreIndex].first = nullptr; // memory is not cleanly released?\n\t\t\t}\n\t\t}\n\t\tOSResetEvent(&s_eventCoreThreadsNewCommandReady);\n\t\tfor (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)\n\t\t{\n\t\t\t_FreeMem(s_coreThreadStackPerCore[coreIndex]);\n\t\t\ts_coreThreadStackPerCore[coreIndex] = nullptr;\n\t\t}\n\t\t_FreeMem(s_backgroundThreadStack);\n\t\ts_backgroundThreadStack = nullptr;\n\t\ts_backgroundCallbackList.first = nullptr; // memory is not cleanly released?\n\t\ts_coreThreadsCreated = false;\n\t}\n\n\tvoid DoCallbackChain(ProcUIInternalCallbackEntry* entry)\n\t{\n\t\twhile (entry)\n\t\t{\n\t\t\tuint32 r = PPCCoreCallback(entry->funcPtr, entry->userParam);\n\t\t\tif ( r )\n\t\t\t\tcemuLog_log(LogType::APIErrors, \"ProcUI: Callback returned error {}\\n\", r);\n\t\t\tentry = entry->next;\n\t\t}\n\t}\n\n\tvoid AlarmDoBackgroundCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tcoreinit::OSAlarm_t* arg = MEMPTR<coreinit::OSAlarm_t>(hCPU->gpr[3]);\n\t\tProcUIInternalCallbackEntry* entry = (ProcUIInternalCallbackEntry*)arg;\n\t\tuint32 r = PPCCoreCallback(entry->funcPtr, entry->userParam);\n\t\tif ( r )\n\t\t\tcemuLog_log(LogType::APIErrors, \"ProcUI: Background callback returned error {}\\n\", r);\n\t\tosLib_returnFromFunction(hCPU, 0); // return type is void\n\t}\n\n\tvoid StartBackgroundAlarms()\n\t{\n\t\tProcUIInternalCallbackEntry* cb = s_backgroundCallbackList.first;\n\t\twhile(cb)\n\t\t{\n\t\t\tcoreinit::OSCreateAlarm(&cb->alarm);\n\t\t\tuint64 currentTime = coreinit::OSGetTime();\n\t\t\tcoreinit::OSSetPeriodicAlarm(&cb->alarm, currentTime, cb->tickDelay, RPLLoader_MakePPCCallable(AlarmDoBackgroundCallback));\n\t\t\tcb = cb->next;\n\t\t}\n\t}\n\n\tvoid CancelBackgroundAlarms()\n\t{\n\t\tProcUIInternalCallbackEntry* entry = s_backgroundCallbackList.first;\n\t\twhile (entry)\n\t\t{\n\t\t\tOSCancelAlarm(&entry->alarm);\n\t\t\tentry = entry->next;\n\t\t}\n\t}\n\n\tvoid ProcUICoreThread(PPCInterpreter_t* hCPU)\n\t{\n\t\tuint32 coreIndex = hCPU->gpr[3];\n\t\tcemu_assert_debug(coreIndex == OSGetCoreId());\n\t\twhile (true)\n\t\t{\n\t\t\tOSWaitEvent(&s_eventCoreThreadsNewCommandReady);\n\t\t\tProcUIInternalCallbackEntry* cbChain = nullptr;\n\t\t\tcemuLog_logDebug(LogType::Force, \"ProcUI: Core {} got command {}\", coreIndex, (uint32)s_commandForCoreThread.load());\n\t\t\tauto cmd = s_commandForCoreThread.load();\n\t\t\tswitch(cmd)\n\t\t\t{\n\t\t\tcase ProcUICoreThreadCommand::Initial:\n\t\t\t{\n\t\t\t\t// signal to shut down thread\n\t\t\t\tosLib_returnFromFunction(hCPU, 0);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase ProcUICoreThreadCommand::AcquireForeground:\n\t\t\t\tcbChain = s_callbacksType0_AcquireForeground[coreIndex].first;\n\t\t\t\tbreak;\n\t\t\tcase ProcUICoreThreadCommand::ReleaseForeground:\n\t\t\t\tcbChain = s_callbacksType1_ReleaseForeground[coreIndex].first;\n\t\t\t\tbreak;\n\t\t\tcase ProcUICoreThreadCommand::Exit:\n\t\t\t\tcbChain = s_callbacksType2_Exit[coreIndex].first;\n\t\t\t\tbreak;\n\t\t\tcase ProcUICoreThreadCommand::NetIoStart:\n\t\t\t\tcbChain = s_callbacksType3_NetIoStart[coreIndex].first;\n\t\t\t\tbreak;\n\t\t\tcase ProcUICoreThreadCommand::NetIoStop:\n\t\t\t\tcbChain = s_callbacksType4_NetIoStop[coreIndex].first;\n\t\t\t\tbreak;\n\t\t\tcase ProcUICoreThreadCommand::HomeButtonDenied:\n\t\t\t\tcbChain = s_callbacksType5_HomeButtonDenied[coreIndex].first;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemu_assert_suspicious(); // invalid command\n\t\t\t}\n\t\t\tif(cmd == ProcUICoreThreadCommand::AcquireForeground)\n\t\t\t{\n\t\t\t\tif (coreIndex == 2)\n\t\t\t\t\tCancelBackgroundAlarms();\n\t\t\t\tcbChain = s_callbacksType0_AcquireForeground[coreIndex].first;\n\t\t\t}\n\t\t\telse if(cmd == ProcUICoreThreadCommand::ReleaseForeground)\n\t\t\t{\n\t\t\t\tif (coreIndex == 2)\n\t\t\t\t\tStartBackgroundAlarms();\n\t\t\t\tcbChain = s_callbacksType1_ReleaseForeground[coreIndex].first;\n\t\t\t}\n\t\t\tDoCallbackChain(cbChain);\n\t\t\tOSWaitRendezvous(&s_coreThreadRendezvousA, 7);\n\t\t\tif ( !coreIndex )\n\t\t\t{\n\t\t\t\tOSInitRendezvous(&s_coreThreadRendezvousC);\n\t\t\t\tOSResetEvent(&s_eventCoreThreadsNewCommandReady);\n\t\t\t}\n\t\t\tOSWaitRendezvous(&s_coreThreadRendezvousB, 7);\n\t\t\tif ( !coreIndex )\n\t\t\t{\n\t\t\t\tOSInitRendezvous(&s_coreThreadRendezvousA);\n\t\t\t\tOSSignalEvent(&s_eventCoreThreadsCommandDone);\n\t\t\t}\n\t\t\tOSWaitRendezvous(&s_coreThreadRendezvousC, 7);\n\t\t\tif ( !coreIndex )\n\t\t\t\tOSInitRendezvous(&s_coreThreadRendezvousB);\n\t\t\tif (cmd == ProcUICoreThreadCommand::ReleaseForeground)\n\t\t\t{\n\t\t\t\tOSWaitEvent(&s_eventWaitingBeforeReleaseForeground);\n\t\t\t\tOSReleaseForeground();\n\t\t\t}\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid RecreateProcUICoreThreads()\n\t{\n\t\tShutdownThreads();\n\t\tfor (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)\n\t\t{\n\t\t\ts_coreThreadStackPerCore[coreIndex] = _AllocMem(s_coreThreadStackSize);\n\t\t}\n\t\ts_backgroundThreadStack = _AllocMem(s_coreThreadStackSize);\n\t\tfor (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)\n\t\t{\n\t\t\t__OSCreateThreadType(&s_coreThreadArray[coreIndex], RPLLoader_MakePPCCallable(ProcUICoreThread), coreIndex, nullptr,\n\t\t\t\t(uint8*)s_coreThreadStackPerCore[coreIndex].GetPtr() + s_coreThreadStackSize, s_coreThreadStackSize, 16,\n\t\t\t\t(1<<coreIndex), OSThread_t::THREAD_TYPE::TYPE_DRIVER);\n\t\t\tOSResumeThread(&s_coreThreadArray[coreIndex]);\n\t\t}\n\t\ts_coreThread0NameBuffer->assign(\"{SYS ProcUI Core 0}\");\n\t\ts_coreThread1NameBuffer->assign(\"{SYS ProcUI Core 1}\");\n\t\ts_coreThread2NameBuffer->assign(\"{SYS ProcUI Core 2}\");\n\t\tOSSetThreadName(&s_coreThreadArray[0], s_coreThread0NameBuffer->c_str());\n\t\tOSSetThreadName(&s_coreThreadArray[1], s_coreThread1NameBuffer->c_str());\n\t\tOSSetThreadName(&s_coreThreadArray[2], s_coreThread2NameBuffer->c_str());\n\t\ts_coreThreadsCreated = true;\n\t}\n\n\tvoid _SubmitCommandToCoreThreads(ProcUICoreThreadCommand cmd)\n\t{\n\t\ts_commandForCoreThread = cmd;\n\t\tOSMemoryBarrier();\n\t\tOSResetEvent(&s_eventCoreThreadsCommandDone);\n\t\tOSSignalEvent(&s_eventCoreThreadsNewCommandReady);\n\t\tOSWaitEvent(&s_eventCoreThreadsCommandDone);\n\t}\n\n\tvoid ProcUIInitInternal()\n\t{\n\t\tif( s_isInitialized.exchange(true) )\n\t\t\treturn;\n\t\tif (!s_memoryPoolHeapPtr)\n\t\t{\n\t\t\t// user didn't specify a custom heap, use default heap instead\n\t\t\ts_memAllocPtr = gCoreinitData->MEMAllocFromDefaultHeap.GetMPTR();\n\t\t\ts_memFreePtr = gCoreinitData->MEMFreeToDefaultHeap.GetMPTR();\n\t\t}\n\t\tOSInitEvent(&s_eventStateMessageReceived, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_MANUAL);\n\t\tOSInitEvent(&s_eventCoreThreadsNewCommandReady, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_MANUAL);\n\t\tOSInitEvent(&s_eventWaitingBeforeReleaseForeground, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_MANUAL);\n\t\tOSInitEvent(&s_eventCoreThreadsCommandDone, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_MANUAL);\n\t\tOSInitRendezvous(&s_coreThreadRendezvousA);\n\t\tOSInitRendezvous(&s_coreThreadRendezvousB);\n\t\tOSInitRendezvous(&s_coreThreadRendezvousC);\n\t\tOSInitEvent(&s_eventBackgroundThreadGotMessage, OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_MANUAL);\n\t\ts_currentProcUIStatus = ProcUIStatus::Foreground;\n\t\ts_drawDoneReleaseCalled = false;\n\t\ts_isInForeground = true;\n\t\ts_coreThreadStackSize = 0x2000;\n\t\ts_systemMessageQueuePtr = coreinit::OSGetSystemMessageQueue();\n\t\tuint32 upid = coreinit::OSGetUPID();\n\t\ts_isForegroundProcess = upid == 2 || upid == 15; // either Wii U Menu or game title, both are RAMPID 7 (foreground process)\n\t\tRecreateProcUICoreThreads();\n\t\tClearCallbacksWithoutMemFree();\n\t}\n\n\tvoid ProcUIInit(MEMPTR<void> callbackReadyToRelease)\n\t{\n\t\ts_saveCallback = callbackReadyToRelease;\n\t\ts_saveCallbackEx = nullptr;\n\t\ts_saveCallbackExUserParam = nullptr;\n\t\tProcUIInitInternal();\n\t}\n\n\tvoid ProcUIInitEx(MEMPTR<void> callbackReadyToReleaseEx, MEMPTR<void> userParam)\n\t{\n\t\ts_saveCallback = nullptr;\n\t\ts_saveCallbackEx = callbackReadyToReleaseEx;\n\t\ts_saveCallbackExUserParam = userParam;\n\t\tProcUIInitInternal();\n\t}\n\n\tvoid ProcUIShutdown()\n\t{\n\t\tif (!s_isInitialized.exchange(false))\n\t\t\treturn;\n\t\tif ( !s_isInForeground )\n\t\t\tCancelBackgroundAlarms();\n\t\tfor (sint32 i = 0; i < Espresso::CORE_COUNT; i++)\n\t\t\tOSSetThreadPriority(&s_coreThreadArray[i], 0);\n\t\t_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::Exit);\n\t\tProcUIClearCallbacks();\n\t\tShutdownThreads();\n\t}\n\n\tbool ProcUIIsRunning()\n\t{\n\t\treturn s_isInitialized;\n\t}\n\n\tbool ProcUIInForeground()\n\t{\n\t\treturn s_isInForeground;\n\t}\n\n\tbool ProcUIInShutdown()\n\t{\n\t\treturn s_isInShutdown;\n\t}\n\n\tvoid AddCallbackInternal(void* funcPtr, void* userParam, uint64 tickDelay, sint32 priority, ProcUICallbackList& callbackList)\n\t{\n\t\tif ( __OSGetProcessSDKVersion() < 21102 )\n\t\t{\n\t\t\t// in earlier COS versions it was possible/allowed to register a callback before initializing ProcUI\n\t\t\ts_memAllocPtr = gCoreinitData->MEMAllocFromDefaultHeap.GetMPTR();\n\t\t\ts_memFreePtr = gCoreinitData->MEMFreeToDefaultHeap.GetMPTR();\n\t\t}\n\t\telse if ( !s_isInitialized )\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"ProcUI: Trying to register callback before init\");\n\t\t\tcemu_assert_suspicious();\n\t\t\t// this shouldn't happen but lets set the memory pointers anyway to prevent a crash in case the user has incorrect meta info\n\t\t\ts_memAllocPtr = gCoreinitData->MEMAllocFromDefaultHeap.GetMPTR();\n\t\t\ts_memFreePtr = gCoreinitData->MEMFreeToDefaultHeap.GetMPTR();\n\t\t}\n\t\tProcUIInternalCallbackEntry* entry = (ProcUIInternalCallbackEntry*)_AllocMem(sizeof(ProcUIInternalCallbackEntry));\n\t\tentry->funcPtr = funcPtr;\n\t\tentry->userParam = userParam;\n\t\tentry->tickDelay = tickDelay;\n\t\tentry->priority = priority;\n\t\tProcUIInternalCallbackEntry* cur = callbackList.first;\n\t\tcur = callbackList.first;\n\t\tif (!cur || cur->priority > priority)\n\t\t{\n\t\t\t// insert as the first element\n\t\t\tentry->next = cur;\n\t\t\tcallbackList.first = entry;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// find the correct position to insert\n\t\t\twhile (cur->next && cur->next->priority < priority)\n\t\t\t\tcur = cur->next;\n\t\t\tentry->next = cur->next;\n\t\t\tcur->next = entry;\n\t\t}\n\t}\n\n\tvoid ProcUIRegisterCallbackCore(ProcUICallbackId callbackType, void* funcPtr, void* userParam, sint32 priority, uint32 coreIndex)\n\t{\n\t\tif(callbackType >= ProcUICallbackId::COUNT)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"ProcUIRegisterCallback: Invalid callback type {}\", stdx::to_underlying(callbackType));\n\t\t\treturn;\n\t\t}\n\t\tif(callbackType != ProcUICallbackId::AcquireForeground)\n\t\t\tpriority = -priority;\n\t\tAddCallbackInternal(funcPtr, userParam, 0, priority, s_CallbackTables[stdx::to_underlying(callbackType)][coreIndex]);\n\t}\n\n\tvoid ProcUIRegisterCallback(ProcUICallbackId callbackType, void* funcPtr, void* userParam, sint32 priority)\n\t{\n\t\tProcUIRegisterCallbackCore(callbackType, funcPtr, userParam, priority, OSGetCoreId());\n\t}\n\n\tvoid ProcUIRegisterBackgroundCallback(void* funcPtr, void* userParam, uint64 tickDelay)\n\t{\n\t\tAddCallbackInternal(funcPtr, userParam, tickDelay, 0, s_backgroundCallbackList);\n\t}\n\n\tvoid FreeCallbackChain(ProcUICallbackList& callbackList)\n\t{\n\t\tProcUIInternalCallbackEntry* entry = callbackList.first;\n\t\twhile (entry)\n\t\t{\n\t\t\tProcUIInternalCallbackEntry* next = entry->next;\n\t\t\t_FreeMem(entry);\n\t\t\tentry = next;\n\t\t}\n\t\tcallbackList.first = nullptr;\n\t}\n\n\tvoid ProcUIClearCallbacks()\n\t{\n\t\tfor (sint32 coreIndex = 0; coreIndex < Espresso::CORE_COUNT; coreIndex++)\n\t\t{\n\t\t\tfor (sint32 i = 0; i < stdx::to_underlying(ProcUICallbackId::COUNT); i++)\n\t\t\t{\n\t\t\t\tFreeCallbackChain(s_CallbackTables[i][coreIndex]);\n\t\t\t}\n\t\t}\n\t\tif (!s_isInForeground)\n\t\t\tCancelBackgroundAlarms();\n\t\tFreeCallbackChain(s_backgroundCallbackList);\n\t}\n\n\tvoid ProcUISetSaveCallback(void* funcPtr, void* userParam)\n\t{\n\t\ts_saveCallback = nullptr;\n\t\ts_saveCallbackEx = funcPtr;\n\t\ts_saveCallbackExUserParam = userParam;\n\t}\n\n\tvoid ProcUISetCallbackStackSize(uint32 newStackSize)\n\t{\n\t\ts_coreThreadStackSize = newStackSize;\n\t\tif( s_isInitialized )\n\t\t\tRecreateProcUICoreThreads();\n\t}\n\n\tuint32 ProcUICalcMemorySize(uint32 numCallbacks)\n\t{\n\t\t// each callback entry is 0x70 bytes with 0x14 bytes of allocator overhead (for ExpHeap). But for some reason proc_ui on 5.5.5 seems to reserve 0x8C0 bytes per callback?\n\t\tuint32 stackReserveSize = (Espresso::CORE_COUNT + 1) * s_coreThreadStackSize; // 3 core threads + 1 message receive thread\n\t\tuint32 callbackReserveSize = 0x8C0 * numCallbacks;\n\t\treturn stackReserveSize + callbackReserveSize + 100;\n\t}\n\n\tvoid _MemAllocFromMemoryPool(PPCInterpreter_t* hCPU)\n\t{\n\t\tuint32 size = hCPU->gpr[3];\n\t\tMEMPTR<void> r = MEMAllocFromExpHeapEx((MEMHeapHandle)s_memoryPoolHeapPtr.GetPtr(), size, 4);\n\t\tosLib_returnFromFunction(hCPU, r.GetMPTR());\n\t}\n\n\tvoid _FreeToMemoryPoolExpHeap(PPCInterpreter_t* hCPU)\n\t{\n\t\tMEMPTR<void> mem{hCPU->gpr[3]};\n\t\tMEMFreeToExpHeap((MEMHeapHandle)s_memoryPoolHeapPtr.GetPtr(), mem.GetPtr());\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tsint32 ProcUISetMemoryPool(void* memBase, uint32 size)\n\t{\n\t\ts_memAllocPtr = RPLLoader_MakePPCCallable(_MemAllocFromMemoryPool);\n\t\ts_memFreePtr = RPLLoader_MakePPCCallable(_FreeToMemoryPoolExpHeap);\n\t\ts_memoryPoolHeapPtr = MEMCreateExpHeapEx(memBase, size, MEM_HEAP_OPTION_THREADSAFE);\n\t\treturn s_memoryPoolHeapPtr ? 0 : -1;\n\t}\n\n\tvoid ProcUISetBucketStorage(void* memBase, uint32 size)\n\t{\n\t\tMEMPTR<void> fgBase;\n\t\tuint32be fgFreeSize;\n\t\tOSGetForegroundBucketFreeArea(&fgBase, &fgFreeSize);\n\t\tif(fgFreeSize < size)\n\t\t\tcemuLog_log(LogType::Force, \"ProcUISetBucketStorage: Buffer size too small\");\n\t\ts_bucketStorageBasePtr = memBase;\n\t}\n\n\tvoid ProcUISetMEM1Storage(void* memBase, uint32 size)\n\t{\n\t\tMEMPTR<void> memBound;\n\t\tuint32be memBoundSize;\n\t\tOSGetMemBound(1, &memBound, &memBoundSize);\n\t\tif(memBoundSize < size)\n\t\t\tcemuLog_log(LogType::Force, \"ProcUISetMEM1Storage: Buffer size too small\");\n\t\ts_mem1StorageBasePtr = memBase;\n\t}\n\n\tvoid ProcUIDrawDoneRelease()\n\t{\n\t\ts_drawDoneReleaseCalled = true;\n\t}\n\n\tOSMessage g_lastMsg;\n\n\tvoid ProcUI_BackgroundThread_ReceiveSingleMessage(PPCInterpreter_t* hCPU)\n\t{\n\t\t// the background thread receives messages in a loop until the title is either exited or foreground is acquired\n\t\twhile ( true )\n\t\t{\n\t\t\tOSReceiveMessage(s_systemMessageQueuePtr, &g_lastMsg, OS_MESSAGE_BLOCK); // blocking receive\n\t\t\tSysMessageId lastMsgId = static_cast<SysMessageId>((uint32)g_lastMsg.data0);\n\t\t\tif(lastMsgId == SysMessageId::MsgExit || lastMsgId == SysMessageId::MsgAcquireForeground)\n\t\t\t\tbreak;\n\t\t\telse if (lastMsgId == SysMessageId::HomeButtonDenied)\n\t\t\t{\n\t\t\t\tcemu_assert_suspicious(); // Home button denied should not be sent to background app\n\t\t\t}\n\t\t\telse if ( lastMsgId == SysMessageId::NetIoStartOrStop )\n\t\t\t{\n\t\t\t\tif (g_lastMsg.data1 )\n\t\t\t\t{\n\t\t\t\t\t// NetIo start message\n\t\t\t\t\tfor (sint32 i = 0; i < Espresso::CORE_COUNT; i++)\n\t\t\t\t\t\tDoCallbackChain(s_callbacksType3_NetIoStart[i].first);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// NetIo stop message\n\t\t\t\t\tfor (sint32 i = 0; i < Espresso::CORE_COUNT; i++)\n\t\t\t\t\t\tDoCallbackChain(s_callbacksType4_NetIoStop[i].first);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"ProcUI: BackgroundThread received invalid message 0x{:08x}\", lastMsgId);\n\t\t\t}\n\t\t}\n\t\tOSSignalEvent(&s_eventBackgroundThreadGotMessage);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\t// handle received message\n\t// if the message is Exit this function returns false, in all other cases it returns true\n\tbool ProcessSysMessage(OSMessage* msg)\n\t{\n\t\tSysMessageId lastMsgId = static_cast<SysMessageId>((uint32)msg->data0);\n\t\tif ( lastMsgId == SysMessageId::MsgAcquireForeground )\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"ProcUI: Received Acquire Foreground message\");\n\t\t\ts_isInShutdown = false;\n\t\t\t_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::AcquireForeground);\n\t\t\ts_currentProcUIStatus = ProcUIStatus::Foreground;\n\t\t\ts_isInForeground = true;\n\t\t\tOSMemoryBarrier();\n\t\t\tOSSignalEvent(&s_eventStateMessageReceived);\n\t\t\treturn true;\n\t\t}\n\t\telse if (lastMsgId == SysMessageId::MsgExit)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"ProcUI: Received Exit message\");\n\t\t\ts_isInShutdown = true;\n\t\t\t_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::Exit);\n\t\t\tfor (sint32 i = 0; i < Espresso::CORE_COUNT; i++)\n\t\t\t\tFreeCallbackChain(s_callbacksType2_Exit[i]);\n\t\t\ts_currentProcUIStatus = ProcUIStatus::Exit;\n\t\t\tOSMemoryBarrier();\n\t\t\tOSSignalEvent(&s_eventStateMessageReceived);\n\t\t\treturn 0;\n\t\t}\n\t\tif (lastMsgId == SysMessageId::MsgReleaseForeground)\n\t\t{\n\t\t\tif (msg->data1 != 0)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"ProcUI: Received Release Foreground message as part of shutdown initiation\");\n\t\t\t\ts_isInShutdown = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"ProcUI: Received Release Foreground message\");\n\t\t\t}\n\t\t\ts_currentProcUIStatus = ProcUIStatus::Releasing;\n\t\t\tOSResetEvent(&s_eventStateMessageReceived);\n\t\t\t// dont submit a command for the core threads yet, we need to wait for ProcUIDrawDoneRelease()\n\t\t}\n\t\telse if (lastMsgId == SysMessageId::HomeButtonDenied)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"ProcUI: Received Home Button Denied message\");\n\t\t\t_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::HomeButtonDenied);\n\t\t}\n\t\telse if ( lastMsgId == SysMessageId::NetIoStartOrStop )\n\t\t{\n\t\t\tif (msg->data1 != 0)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"ProcUI: Received Net IO Start message\");\n\t\t\t\t_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::NetIoStart);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"ProcUI: Received Net IO Stop message\");\n\t\t\t\t_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::NetIoStop);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"ProcUI: Received unknown message 0x{:08x}\", (uint32)lastMsgId);\n\t\t}\n\t\treturn true;\n\t}\n\n\tProcUIStatus ProcUIProcessMessages(bool isBlockingInBackground)\n\t{\n\t\tOSMessage msg;\n\t\tif (!s_isInitialized)\n\t\t{\n\t\t\tcemuLog_logOnce(LogType::Force, \"ProcUIProcessMessages: ProcUI not initialized\");\n\t\t\tcemu_assert_suspicious();\n\t\t\treturn ProcUIStatus::Foreground;\n\t\t}\n\t\tif ( !isBlockingInBackground && OSGetCoreId() != 2 )\n\t\t{\n\t\t\tcemuLog_logOnce(LogType::Force, \"ProcUIProcessMessages: Non-blocking call must run on core 2\");\n\t\t}\n\t\tif (s_previouslyWasBlocking && isBlockingInBackground )\n\t\t{\n\t\t\tcemuLog_logOnce(LogType::Force, \"ProcUIProcessMessages: Cannot switch to blocking mode when in background\");\n\t\t}\n\t\ts_currentProcUIStatus = s_isInForeground ? ProcUIStatus::Foreground : ProcUIStatus::Background;\n\t\tif (s_drawDoneReleaseCalled)\n\t\t{\n\t\t\ts_isInForeground = false;\n\t\t\ts_currentProcUIStatus = ProcUIStatus::Background;\n\t\t\t_SubmitCommandToCoreThreads(ProcUICoreThreadCommand::ReleaseForeground);\n\t\t\tOSResetEvent(&s_eventWaitingBeforeReleaseForeground);\n\t\t\tif(s_saveCallback)\n\t\t\t\tPPCCoreCallback(s_saveCallback);\n\t\t\tif(s_saveCallbackEx)\n\t\t\t\tPPCCoreCallback(s_saveCallbackEx, s_saveCallbackExUserParam);\n\t\t\tif (s_isForegroundProcess && isBlockingInBackground)\n\t\t\t{\n\t\t\t\t// start background thread\n\t\t\t\t__OSCreateThreadType(&s_backgroundThread, RPLLoader_MakePPCCallable(ProcUI_BackgroundThread_ReceiveSingleMessage),\n\t\t\t\t\t0, nullptr, (uint8*)s_backgroundThreadStack.GetPtr() + s_coreThreadStackSize, s_coreThreadStackSize,\n\t\t\t\t\t16, (1<<2), OSThread_t::THREAD_TYPE::TYPE_DRIVER);\n\t\t\t\tOSResumeThread(&s_backgroundThread);\n\t\t\t\ts_previouslyWasBlocking = true;\n\t\t\t}\n\t\t\tcemuLog_logDebug(LogType::Force, \"ProcUI: Releasing foreground\");\n\t\t\tOSSignalEvent(&s_eventWaitingBeforeReleaseForeground);\n\t\t\ts_drawDoneReleaseCalled = false;\n\t\t}\n\t\tif (s_isInForeground || !isBlockingInBackground)\n\t\t{\n\t\t\t// non-blocking mode\n\t\t\tif ( OSReceiveMessage(s_systemMessageQueuePtr, &msg, 0) )\n\t\t\t{\n\t\t\t\ts_previouslyWasBlocking = false;\n\t\t\t\tif ( !ProcessSysMessage(&msg) )\n\t\t\t\t\treturn s_currentProcUIStatus;\n\t\t\t\t// continue below, if we are now in background then ProcUIProcessMessages enters blocking mode\n\t\t\t}\n\t\t}\n\t\t// blocking mode (if in background and param is true)\n\t\twhile (!s_isInForeground && isBlockingInBackground)\n\t\t{\n\t\t\tif ( !s_isForegroundProcess)\n\t\t\t{\n\t\t\t\tOSReceiveMessage(s_systemMessageQueuePtr, &msg, OS_MESSAGE_BLOCK);\n\t\t\t\ts_previouslyWasBlocking = false;\n\t\t\t\tif ( !ProcessSysMessage(&msg) )\n\t\t\t\t\treturn s_currentProcUIStatus;\n\t\t\t}\n\t\t\t// this code should only run if the background thread was started? Maybe rearrange the code to make this more clear\n\t\t\tOSWaitEvent(&s_eventBackgroundThreadGotMessage);\n\t\t\tOSResetEvent(&s_eventBackgroundThreadGotMessage);\n\t\t\tOSJoinThread(&s_backgroundThread, nullptr);\n\t\t\tmsg = g_lastMsg; // g_lastMsg is set by the background thread\n\t\t\ts_previouslyWasBlocking = false;\n\t\t\tif ( !ProcessSysMessage(&msg) )\n\t\t\t\treturn s_currentProcUIStatus;\n\t\t}\n\t\treturn s_currentProcUIStatus;\n\t}\n\n\tProcUIStatus ProcUISubProcessMessages(bool isBlockingInBackground)\n\t{\n\t\tif (isBlockingInBackground)\n\t\t{\n\t\t\twhile (s_currentProcUIStatus == ProcUIStatus::Background)\n\t\t\t\tOSWaitEvent(&s_eventStateMessageReceived);\n\t\t}\n\t\treturn s_currentProcUIStatus;\n\t}\n\n\tconst char* ProcUIDriver_GetName()\n\t{\n\t\ts_ProcUIDriverName->assign(\"ProcUI\");\n\t\treturn s_ProcUIDriverName->c_str();\n\t}\n\n\tvoid ProcUIDriver_Init(/* parameters unknown */)\n\t{\n\t\ts_driverIsActive = true;\n\t\tOSMemoryBarrier();\n\t}\n\n\tvoid ProcUIDriver_OnDone(/* parameters unknown */)\n\t{\n\t\tif (s_driverIsActive)\n\t\t{\n\t\t\tProcUIShutdown();\n\t\t\ts_driverIsActive = false;\n\t\t\tOSMemoryBarrier();\n\t\t}\n\t}\n\n\tvoid StoreMEM1AndFGBucket()\n\t{\n\t\tif (s_mem1StorageBasePtr)\n\t\t{\n\t\t\tMEMPTR<void> memBound;\n\t\t\tuint32be memBoundSize;\n\t\t\tOSGetMemBound(1, &memBound, &memBoundSize);\n\t\t\tOSBlockMove(s_mem1StorageBasePtr.GetPtr(), memBound.GetPtr(), memBoundSize, true);\n\t\t}\n\t\tif (s_bucketStorageBasePtr)\n\t\t{\n\t\t\tMEMPTR<void> memBound;\n\t\t\tuint32be memBoundSize;\n\t\t\tOSGetForegroundBucketFreeArea(&memBound, &memBoundSize);\n\t\t\tOSBlockMove(s_bucketStorageBasePtr.GetPtr(), memBound.GetPtr(), memBoundSize, true);\n\t\t}\n\t}\n\n\tvoid RestoreMEM1AndFGBucket()\n\t{\n\t\tif (s_mem1StorageBasePtr)\n\t\t{\n\t\t\tMEMPTR<void> memBound;\n\t\t\tuint32be memBoundSize;\n\t\t\tOSGetMemBound(1, &memBound, &memBoundSize);\n\t\t\tOSBlockMove(memBound.GetPtr(), s_mem1StorageBasePtr, memBoundSize, true);\n\t\t\tGX2::GX2Invalidate(0x40, s_mem1StorageBasePtr.GetMPTR(), memBoundSize);\n\t\t}\n\t\tif (s_bucketStorageBasePtr)\n\t\t{\n\t\t\tMEMPTR<void> memBound;\n\t\t\tuint32be memBoundSize;\n\t\t\tOSGetForegroundBucketFreeArea(&memBound, &memBoundSize);\n\t\t\tOSBlockMove(memBound.GetPtr(), s_bucketStorageBasePtr, memBoundSize, true);\n\t\t\tGX2::GX2Invalidate(0x40, memBound.GetMPTR(), memBoundSize);\n\t\t}\n\t}\n\n\tvoid ProcUIDriver_OnAcquiredForeground(/* parameters unknown */)\n\t{\n\t\tif (s_driverInBackground)\n\t\t{\n\t\t\tProcUIDriver_Init();\n\t\t\ts_driverInBackground = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tRestoreMEM1AndFGBucket();\n\t\t\ts_driverIsActive = true;\n\t\t\tOSMemoryBarrier();\n\t\t}\n\t}\n\n\tvoid ProcUIDriver_OnReleaseForeground(/* parameters unknown */)\n\t{\n\t\tStoreMEM1AndFGBucket();\n\t\ts_driverIsActive = false;\n\t\tOSMemoryBarrier();\n\t}\n\n\tvoid reset()\n\t{\n\t\t// set variables to their initial state as if the RPL was just loaded\n\t\ts_isInitialized = false;\n\t\ts_isInShutdown = false;\n\t\ts_isInForeground = false; // ProcUIInForeground returns false until ProcUIInit(Ex) is called\n\t\ts_isForegroundProcess = true;\n\t\ts_saveCallback = nullptr;\n\t\ts_saveCallbackEx = nullptr;\n\t\ts_systemMessageQueuePtr = nullptr;\n\t\tClearCallbacksWithoutMemFree();\n\t\ts_currentProcUIStatus = ProcUIStatus::Foreground;\n\t\ts_bucketStorageBasePtr = nullptr;\n\t\ts_mem1StorageBasePtr = nullptr;\n\t\ts_drawDoneReleaseCalled = false;\n\t\ts_previouslyWasBlocking = false;\n\t\t// core threads\n\t\ts_coreThreadStackSize = 0;\n\t\ts_coreThreadsCreated = false;\n\t\ts_commandForCoreThread = ProcUICoreThreadCommand::Initial;\n\t\t// background thread\n\t\ts_backgroundThreadStack = nullptr;\n\t\t// user defined heap\n\t\ts_memoryPoolHeapPtr = nullptr;\n\t\ts_memAllocPtr = nullptr;\n\t\ts_memFreePtr = nullptr;\n\t\t// driver\n\t\ts_driverIsActive = false;\n\t\ts_driverInBackground = false;\n\t}\n\n\tvoid load()\n\t{\n\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"proc_ui\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\treset();\n\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIInit, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIInitEx, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIShutdown, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIIsRunning, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIInForeground, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIInShutdown, LogType::ProcUi);\n\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIRegisterCallbackCore, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIRegisterCallback, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIRegisterBackgroundCallback, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIClearCallbacks, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUISetSaveCallback, LogType::ProcUi);\n\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUISetCallbackStackSize, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUICalcMemorySize, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUISetMemoryPool, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUISetBucketStorage, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUISetMEM1Storage, LogType::ProcUi);\n\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIDrawDoneRelease, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUIProcessMessages, LogType::ProcUi);\n\t\t\tcafeExportRegister(\"proc_ui\", ProcUISubProcessMessages, LogType::ProcUi);\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif ( reason == RplEntryReason::Loaded )\n\t\t\t{\n\t\t\t\ts_ProcUIDriver->getDriverName = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) {MEMPTR<const char> namePtr(ProcUIDriver_GetName()); osLib_returnFromFunction(hCPU, namePtr.GetMPTR()); });\n\t\t\t\ts_ProcUIDriver->init = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) {ProcUIDriver_Init(); osLib_returnFromFunction(hCPU, 0); });\n\t\t\t\ts_ProcUIDriver->onAcquireForeground = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) {ProcUIDriver_OnAcquiredForeground(); osLib_returnFromFunction(hCPU, 0); });\n\t\t\t\ts_ProcUIDriver->onReleaseForeground = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) {ProcUIDriver_OnReleaseForeground(); osLib_returnFromFunction(hCPU, 0); });\n\t\t\t\ts_ProcUIDriver->done = RPLLoader_MakePPCCallable([](PPCInterpreter_t* hCPU) {ProcUIDriver_OnDone(); osLib_returnFromFunction(hCPU, 0); });\n\n\t\t\t\ts_driverIsActive = false;\n\t\t\t\ts_driverArgUkn1 = 0;\n\t\t\t\ts_driverArgUkn2 = 0;\n\t\t\t\ts_driverInBackground = false;\n\t\t\t\tuint32be ukn3;\n\t\t\t\tOSDriver_Register(moduleHandle, 200, &s_ProcUIDriver, 0, &s_driverArgUkn1, &s_driverArgUkn2, &ukn3);\n\t\t\t\tif ( ukn3 )\n\t\t\t\t{\n\t\t\t\t\tif ( OSGetForegroundBucket(nullptr, nullptr) )\n\t\t\t\t\t{\n\t\t\t\t\t\tProcUIDriver_Init();\n\t\t\t\t\t\tOSMemoryBarrier();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\ts_driverInBackground = true;\n\t\t\t\t}\n\t\t\t\tOSMemoryBarrier();\n\t\t\t}\n\t\t\telse if ( reason == RplEntryReason::Unloaded )\n\t\t\t{\n\t\t\t\tProcUIDriver_OnDone();\n\t\t\t\tOSDriver_Deregister(moduleHandle, 0);\n\t\t\t}\n\t\t}\n\t}s_COSprocuiModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSprocuiModule;\n\t}\n\n};\n"
  },
  {
    "path": "src/Cafe/OS/libs/proc_ui/proc_ui.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace proc_ui\n{\n\tenum class ProcUIStatus\n\t{\n\t\tForeground = 0,\n\t\tBackground = 1,\n\t\tReleasing = 2,\n\t\tExit = 3\n\t};\n\n\tenum class ProcUICallbackId\n\t{\n\t\tAcquireForeground = 0,\n\t\tReleaseForeground = 1,\n\t\tExit = 2,\n\t\tNetIoStart = 3,\n\t\tNetIoStop = 4,\n\t\tHomeButtonDenied = 5,\n\t\tCOUNT = 6\n\t};\n\n\tvoid ProcUIInit(MEMPTR<void> callbackReadyToRelease);\n\tvoid ProcUIInitEx(MEMPTR<void> callbackReadyToReleaseEx, MEMPTR<void> userParam);\n\tvoid ProcUIShutdown();\n\tbool ProcUIIsRunning();\n\tbool ProcUIInForeground();\n\tbool ProcUIInShutdown();\n\tvoid ProcUIRegisterCallback(ProcUICallbackId callbackType, void* funcPtr, void* userParam, sint32 priority);\n\tvoid ProcUIRegisterCallbackCore(ProcUICallbackId callbackType, void* funcPtr, void* userParam, sint32 priority, uint32 coreIndex);\n\tvoid ProcUIRegisterBackgroundCallback(void* funcPtr, void* userParam, uint64 tickDelay);\n\tvoid ProcUIClearCallbacks();\n\tvoid ProcUISetSaveCallback(void* funcPtr, void* userParam);\n\tvoid ProcUISetCallbackStackSize(uint32 newStackSize);\n\tuint32 ProcUICalcMemorySize(uint32 numCallbacks);\n\tsint32 ProcUISetMemoryPool(void* memBase, uint32 size);\n\tvoid ProcUISetBucketStorage(void* memBase, uint32 size);\n\tvoid ProcUISetMEM1Storage(void* memBase, uint32 size);\n\tvoid ProcUIDrawDoneRelease();\n\tProcUIStatus ProcUIProcessMessages(bool isBlockingInBackground);\n\tProcUIStatus ProcUISubProcessMessages(bool isBlockingInBackground);\n\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/snd_core/ax.h",
    "content": "#pragma once\n\n#include \"util/helpers/fspinlock.h\"\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nstruct PPCInterpreter_t;\n\nnamespace snd_core\n{\n\t// sndcore2 - AX init param config\n\tconst int AX_RENDERER_FREQ_32KHZ = 0;\n\tconst int AX_RENDERER_FREQ_48KHZ = 1;\n\tconst int AX_FRAMELENGTH_3MS = 0;\n\n\tconst int AX_SAMPLES_PER_3MS_48KHZ = (144); // 48000*3/1000\n\tconst int AX_SAMPLES_PER_3MS_32KHZ = (96);  // 32000*3/1000\n\tconst int AX_SAMPLES_MAX = AX_SAMPLES_PER_3MS_48KHZ; // the maximum amount of samples in a single frame\n\n\tconst int AX_DEV_TV = 0;\n\tconst int AX_DEV_DRC = 1;\n\tconst int AX_DEV_RMT = 2;\n\tconst int AX_DEV_COUNT = 3;\n\n\tconst int AX_UPSAMPLE_STAGE_BEFORE_FINALMIX = 0;\n\tconst int AX_UPSAMPLE_STAGE_AFTER_FINALMIX = 1;\n\n\tconst int AX_PIPELINE_SINGLE = 0;\n\n\tstruct AXINITPARAM\n\t{\n\t\tuint32be freq; // AX_RENDERER_FREQ_*\n\t\tuint32be frameLength; // AX_FRAMELENGTH_*\n\t\tuint32be pipelineMode; // AX_PIPELINE_*\n\t};\n\n\t// maximum number of supported channels per device\n\tconst int AX_TV_CHANNEL_COUNT = 6;\n\tconst int AX_DRC_CHANNEL_COUNT = 4;\n\tconst int AX_RMT_CHANNEL_COUNT = 1;\n\t\n\tconst int AX_APP_FRAME_CALLBACK_MAX = 64;\n\n\tconst int AX_MODE_STEREO = 0;\n\tconst int AX_MODE_SURROUND = 1;\n\tconst int AX_MODE_DPL2 = 2;\n\tconst int AX_MODE_6CH = 3;\n\tconst int AX_MODE_MONO = 5;\n\n\tconst int AX_PRIORITY_MAX = 32;\n\tconst int AX_PRIORITY_FREE = 0;\n\tconst int AX_PRIORITY_NODROP = 31;\n\tconst int AX_PRIORITY_LOWEST = 1;\n\tconst int AX_MAX_VOICES = 96;\n\n\tconst int AX_AUX_BUS_COUNT = 3;\n\tconst int AX_MAX_NUM_BUS = 4;\n\n\tconst int AX_FORMAT_ADPCM = 0x0;\n\tconst int AX_FORMAT_PCM16 = 0xA;\n\tconst int AX_FORMAT_PCM8 = 0x19;\n\n\tconst int AX_LPF_OFF = 0x0;\n\n\tconst int AX_BIQUAD_OFF = 0x0;\n\n\tconst int AX_SRC_TYPE_NONE = 0x0;\n\tconst int AX_SRC_TYPE_LINEAR = 0x1;\n\tconst int AX_SRC_TYPE_LOWPASS1 = 0x2;\n\tconst int AX_SRC_TYPE_LOWPASS2 = 0x3;\n\tconst int AX_SRC_TYPE_LOWPASS3 = 0x4;\n\n\tconst int AX_FILTER_MODE_TAP = 0x0;\n\tconst int AX_FILTER_MODE_LINEAR = 0x1;\n\tconst int AX_FILTER_MODE_NONE = 0x2;\n\n\tconst int AX_FILTER_LOWPASS_8K = 0x0;\n\tconst int AX_FILTER_LOWPASS_12K = 0x1;\n\tconst int AX_FILTER_LOWPASS_16K = 0x2;\n\n\tbool isInitialized();\n\tvoid reset();\n\n\t// AX VPB\n\n\tstruct AXAUXCBCHANNELINFO\n\t{\n\t\t/* +0x00 */ uint32be numChannels;\n\t\t/* +0x04 */ uint32be numSamples;\n\t};\n\n\tstruct AXPBOFFSET_t\n\t{\n\t\t/* +0x00 | +0x34 */ uint16\t\tformat;\n\t\t/* +0x02 | +0x36 */ uint16\t\tloopFlag;\n\t\t/* +0x04 | +0x38 */ uint32\t\tloopOffset;\n\t\t/* +0x08 | +0x3C */ uint32\t\tendOffset;\n\t\t/* +0x0C | +0x40 */ uint32\t\tcurrentOffset;\n\t\t/* +0x10 | +0x44 */ MPTR\t\tsamples;\n\t};\n\n\tstruct AXPBVE\n\t{\n\t\tuint16be currentVolume;\n\t\tsint16be currentDelta; \n\t};\n\n\tstruct AXVPBItd\n\t{\n\t\tuint8 ukn[64];\n\t};\n\n\tstruct AXVPB\n\t{\n\t\t/* +0x00 */ uint32be\t\t\tindex;\n\t\t/* +0x04 */ uint32be\t\t\tplaybackState;\n\t\t/* +0x08 */ uint32be\t\t\tukn08;\n\t\t/* +0x0C */ uint32be\t\t\tmixerSelect;\n\t\t/* +0x10 */ MEMPTR<AXVPB>\t\tnext;\n\t\t/* +0x14 */ MEMPTR<AXVPB>\t\tprev;\n\t\t/* +0x18 */ uint32be\t\t\tukn18;\n\t\t/* +0x1C */ uint32be\t\t\tpriority;\n\t\t/* +0x20 */ uint32be\t\t\tcallback;\n\t\t/* +0x24 */ uint32be\t\t\tuserParam;\n\t\t/* +0x28 */ uint32be\t\t\tsync;\n\t\t/* +0x2C */ uint32be\t\t\tdepop;\n\t\t/* +0x30 */ MEMPTR<AXVPBItd>\titd;\n\t\t/* +0x34 */ AXPBOFFSET_t\t\toffsets;\n\t\t/* +0x48 */ uint32be\t\t\tcallbackEx; // AXAcquireVoiceEx\n\t\t/* +0x4C */ uint32be\t\t\tukn4C_dropReason;\n\t\t/* +0x50 */ float32be\t\t\tdspLoad;\n\t\t/* +0x54 */ float32be\t\t\tppcLoad;\n\t};\n\n\tstruct AXPBLPF_t\n\t{\n\t\t/* +0x00 */ uint16 on;\n\t\t/* +0x02 */ sint16 yn1;\n\t\t/* +0x04 */ sint16 a0;\n\t\t/* +0x06 */ sint16 b0;\n\t};\n\n\tstruct AXPBBIQUAD_t\n\t{\n\t\t/* +0x00 */ uint16 on;\n\t\t/* +0x02 */ sint16 xn1;\n\t\t/* +0x04 */ sint16 xn2;\n\t\t/* +0x06 */ sint16 yn1;\n\t\t/* +0x08 */ sint16 yn2;\n\t\t/* +0x0A */ uint16 b0;\n\t\t/* +0x0C */ uint16 b1;\n\t\t/* +0x0E */ uint16 b2;\n\t\t/* +0x10 */ uint16 a1;\n\t\t/* +0x12 */ uint16 a2;\n\t};\n\n\tstruct AXRemixMatrix_t\n\t{\n\t\t/* +0x00 */ uint32be channelIn;\n\t\t/* +0x04 */ uint32be channelOut;\n\t\t/* +0x08 */ MEMPTR<float32be> matrix;\n\t};\n\t\n\tstruct AXRemixMatrices_t\n\t{\n\t\t/* +0x00 */ AXRemixMatrix_t deviceEntry[3]; // tv, drc, remote\n\t};\n\n\tstruct AXPBADPCM_t\n\t{\n\t\tuint16 a[16];\n\t\tuint16 gain;\n\t\tuint16 scale;\n\t\tuint16 yn1;\n\t\tuint16 yn2;\n\t};\n\n\tstruct AXPBADPCMLOOP_t\n\t{\n\t\tuint16 loopScale;\n\t\tuint16 loopYn1;\n\t\tuint16 loopYn2;\n\t};\n\n\tstruct AXPBSRC_t\n\t{\n\t\t/* +0x1B8 */ uint16 ratioHigh;\n\t\t/* +0x1BA */ uint16 ratioLow;\n\t\t/* +0x1BC */ uint16 currentFrac;\n\t\t/* +0x1BE */ uint16 historySamples[4];\n\n\t\tuint32 GetSrcRatio32() const\n\t\t{\n\t\t\tuint32 offset = (uint32)_swapEndianU16(ratioHigh) << 16;\n\t\t\treturn offset | (uint32)_swapEndianU16(ratioLow);\n\t\t}\n\t};\n\n\tstruct AXCHMIX_DEPR\n\t{\n\t\tuint16 vol;\n\t\tsint16 delta;\n\t};\n\n\tstruct AXCHMIX2\n\t{\n\t\tuint16be vol;\n\t\tsint16be delta;\n\t};\n\n\tvoid AXVPB_Init();\n    void AXResetToDefaultState();\n\n\tsint32 AXIsValidDevice(sint32 device, sint32 deviceIndex);\n\n\tAXVPB* AXAcquireVoiceEx(uint32 priority, MPTR callbackEx, MPTR userParam);\n\tvoid AXFreeVoice(AXVPB* vpb);\n\n\tbool AXUserIsProtected();\n\tsint32 AXUserBegin();\n\tsint32 AXUserEnd();\n\n\tbool AXVoiceProtection_IsProtectedByAnyThread(AXVPB* vpb);\n\tbool AXVoiceProtection_IsProtectedByCurrentThread(AXVPB* vpb);\n\n\tsint32 AXVoiceBegin(AXVPB* voice);\n\tsint32 AXVoiceEnd(AXVPB* voice);\n\tsint32 AXSetVoiceDeviceMix(AXVPB* vpb, sint32 device, sint32 deviceIndex, AXCHMIX_DEPR* mix);\n\tvoid AXSetVoiceState(AXVPB* vpb, sint32 voiceState);\n\tsint32 AXIsVoiceRunning(AXVPB* vpb);\n\tvoid AXSetVoiceType(AXVPB* vpb, uint16 voiceType);\n\tvoid AXSetVoiceAdpcm(AXVPB* vpb, AXPBADPCM_t* adpcm);\n\tvoid AXSetVoiceAdpcmLoop(AXVPB* vpb, AXPBADPCMLOOP_t* adpcmLoop);\n\tvoid AXSetVoiceSrc(AXVPB* vpb, AXPBSRC_t* src);\n\tvoid AXSetVoiceSrcType(AXVPB* vpb, uint32 srcType);\n\tsint32 AXSetVoiceSrcRatio(AXVPB* vpb, float ratio);\n\tvoid AXSetVoiceVe(AXVPB* vpb, AXPBVE* ve);\n\tvoid AXComputeLpfCoefs(uint32 freq, uint16be* a0, uint16be* b0);\n\tvoid AXSetVoiceLpf(AXVPB* vpb, AXPBLPF_t* lpf);\n\tvoid AXSetVoiceLpfCoefs(AXVPB* vpb, uint16 a0, uint16 b0);\n\tvoid AXSetVoiceBiquad(AXVPB* vpb, AXPBBIQUAD_t* biquad);\n\tvoid AXSetVoiceBiquadCoefs(AXVPB* vpb, uint16 b0, uint16 b1, uint16 b2, uint16 a1, uint16 a2);\n\tvoid AXSetVoiceOffsets(AXVPB* vpb, AXPBOFFSET_t* pbOffset);\n\tvoid AXSetVoiceOffsetsEx(AXVPB* vpb, AXPBOFFSET_t* pbOffset, void* sampleBase);\n\tvoid AXGetVoiceOffsets(AXVPB* vpb, AXPBOFFSET_t* pbOffset);\n\tvoid AXGetVoiceOffsetsEx(AXVPB* vpb, AXPBOFFSET_t* pbOffset, MPTR sampleBase);\n\tvoid AXSetVoiceSamplesAddr(AXVPB* vpb, void* sampleBase);\n\tvoid AXSetVoiceCurrentOffset(AXVPB* vpb, uint32 currentOffset);\n\tvoid AXSetVoiceLoopOffset(AXVPB* vpb, uint32 loopOffset);\n\tvoid AXSetVoiceEndOffset(AXVPB* vpb, uint32 endOffset);\n\tvoid AXSetVoiceCurrentOffsetEx(AXVPB* vpb, uint32 currentOffset, MPTR sampleBase);\n\tvoid AXSetVoiceLoopOffsetEx(AXVPB* vpb, uint32 loopOffset, MPTR sampleBase);\n\tvoid AXSetVoiceEndOffsetEx(AXVPB* vpb, uint32 endOffset, MPTR sampleBase);\n\tuint32 AXGetVoiceCurrentOffsetEx(AXVPB* vpb, MPTR sampleBase);\n\tvoid AXSetVoiceLoop(AXVPB* vpb, uint16 loopState);\n\tsint32 AXGetVoiceLoopCount(AXVPB* vpb);\n\n\t// AXIst\n\n\tvoid AXIst_Init();\n\tvoid AXIst_ThreadEntry(PPCInterpreter_t* hCPU);\n\tvoid AXIst_QueueFrame();\n\n\tvoid AXResetCallbacks();\n\n\tbool AXIst_IsFrameBeingProcessed();\n\n\tsint32 AXSetDeviceUpsampleStage(sint32 device, int upsampleStage);\n\tsint32 AXGetDeviceUpsampleStage(sint32 device, uint32be* upsampleStage);\n\n\tsint32 AXGetDeviceFinalMixCallback(sint32 device, uint32be* funcAddrPtr);\n\tsint32 AXRegisterDeviceFinalMixCallback(sint32 device, MPTR funcAddr);\n\n\tsint32 AXSetDeviceRemixMatrix(sint32 deviceId, uint32 inputChannelCount, uint32 outputChannelCount, const MEMPTR<float32be>& matrix);\n\tsint32 AXGetDeviceRemixMatrix(uint32 deviceId, uint32 inputChannelCount, uint32 outputChannelCount, MEMPTR<MEMPTR<float32be>>& matrix);\n\n\tsint32 AXRegisterAppFrameCallback(MPTR funcAddr);\n\tsint32 AXDeregisterAppFrameCallback(MPTR funcAddr);\n\tMPTR AXRegisterFrameCallback(MPTR funcAddr);\n\n\tsint32 AXGetInputSamplesPerFrame();\n\tsint32 AXGetInputSamplesPerSec();\n\n\t// AXOut\n\n\tvoid resetNumProcessedFrames();\n\tuint32 getNumProcessedFrames();\n\n\tvoid AXOut_Init();\n\n\tsint32 AIGetSamplesPerChannel(uint32 device);\n\tsint32 AIGetChannelCount(uint32 device);\n\tsint16* AIGetCurrentDMABuffer(uint32 device);\n\n\tvoid AXOut_SubmitTVFrame(sint32 frameIndex);\n\tvoid AXOut_SubmitDRCFrame(sint32 frameIndex);\n\n\tsint32 AXGetDeviceMode(sint32 device);\n\n\textern uint32 numProcessedFrames;\n\n\t// AUX\n\n\tvoid AXAux_Init();\n\n\tvoid AXAux_Process();\n\t\n\tsint32be* AXAux_GetInputBuffer(sint32 device, sint32 deviceIndex, sint32 auxBus);\n\tsint32be* AXAux_GetOutputBuffer(sint32 device, sint32 deviceIndex, sint32 auxBus);\n\n\tsint32 AXGetAuxCallback(sint32 device, sint32 deviceIndex, uint32 auxBusIndex, MEMPTR<uint32be> funcPtrOut, MEMPTR<uint32be> contextPtrOut);\n\tsint32 AXRegisterAuxCallback(sint32 device, sint32 deviceIndex, uint32 auxBusIndex, MPTR funcMPTR, MPTR userParam);\n\n\tsint32 AXSetAuxReturnVolume(uint32 device, uint32 deviceIndex, uint32 auxBus, uint16 volume);\n\n\textern uint16 __AXTVAuxReturnVolume[AX_AUX_BUS_COUNT];\n\n\t// AXMix\n\t// mixer select constants (for AXSetDefaultMixerSelect / AXGetDefaultMixerSelect)\n\tconst int AX_MIXER_SELECT_DSP = (0);\n\tconst int AX_MIXER_SELECT_PPC = (1);\n\tconst int AX_MIXER_SELECT_BOTH = (2);\n\n\tvoid AXMix_Init();\n\tvoid AXSetDefaultMixerSelect(uint32 mixerSelect);\n\tuint32 AXGetDefaultMixerSelect();\n\n\tvoid AXMix_DepopVoice(struct AXVPBInternal_t* internalShadowCopy);\n\n\tvoid AXMix_process(struct AXVPBInternal_t* internalShadowCopyHead);\n\n\textern FSpinlock __AXVoiceListSpinlock;\n\n\t// AX multi voice\n\tstruct AXVPBMULTI\n\t{\n\t\t/* +0x00 */ betype<uint32> isUsed;\n\t\t/* +0x04 */ betype<uint32> channelCount;\n\t\t/* +0x08 */ MEMPTR<AXVPB> voice[6];\n\t\t// size: 0x20\n\t};\n\tstatic_assert(sizeof(AXVPBMULTI) == 0x20);\n\n\tstruct AXMULTIVOICEUKNSTRUCT\n\t{\n\t\tuint8 ukn[0x4A];\n\t\tbetype<sint16> channelCount;\n\t};\n\n\tstruct AXDSPADPCM\n\t{\n\t\t/* +0x00 */ uint32be numSamples;\n\t\t/* +0x04 */ uint32be ukn04;\n\t\t/* +0x08 */ uint32be sampleRate;\n\t\t/* +0x0C */ uint16be isLooped;\n\t\t/* +0x0E */ uint16be format;\n\t\t/* +0x10 */ uint32be ukn10;\n\t\t/* +0x14 */ uint32be ukn14;\n\t\t/* +0x18 */ uint32be ukn18;\n\t\t/* +0x1C */ uint16be coef[16];\n\t\t/* +0x3C */ uint16be gain;\n\t\t/* +0x3E */ uint16be scale;\n\t\t/* +0x40 */ uint16be yn1;\n\t\t/* +0x42 */ uint16be yn2;\n\t\t/* +0x44 */ uint16be ukn44;\n\t\t/* +0x46 */ uint16be ukn46;\n\t\t/* +0x48 */ uint16be ukn48;\n\t\t/* +0x4A */ uint16be channelCount;\n\t\t/* +0x4C */ uint16be ukn4C;\n\t\t/* +0x4E */ uint8 _padding4E[0x12];\n\t};\n\tstatic_assert(sizeof(AXDSPADPCM) == 0x60);\n\n\tvoid AXMultiVoice_Init();\n\n\tsint32 AXAcquireMultiVoice(sint32 voicePriority, void* cbFunc, void* cbData, AXMULTIVOICEUKNSTRUCT* uknR6, MEMPTR<AXVPBMULTI>* multiVoiceOut);\n\tvoid AXFreeMultiVoice(AXVPBMULTI* multiVoice);\n\tsint32 AXGetMultiVoiceReformatBufferSize(sint32 voiceFormat, uint32 channelCount, uint32 sizeInBytes, uint32be* sizeOutput);\n\tvoid AXSetMultiVoiceType(AXVPBMULTI* mv, uint16 type);\n\tvoid AXSetMultiVoiceAdpcm(AXVPBMULTI* mv, AXDSPADPCM* data);\n\tvoid AXSetMultiVoiceSrcType(AXVPBMULTI* mv, uint32 type);\n\tvoid AXSetMultiVoiceOffsets(AXVPBMULTI* mv, AXPBOFFSET_t* offsets);\n\tvoid AXSetMultiVoiceVe(AXVPBMULTI* mv, AXPBVE* ve);\n\tvoid AXSetMultiVoiceSrcRatio(AXVPBMULTI* mv, float ratio);\n\tvoid AXSetMultiVoiceSrc(AXVPBMULTI* mv, AXPBSRC_t* src);\n\tvoid AXSetMultiVoiceLoop(AXVPBMULTI* mv, uint16 loop);\n\tvoid AXSetMultiVoiceState(AXVPBMULTI* mv, uint16 state);\n\tvoid AXSetMultiVoiceAdpcmLoop(AXVPBMULTI* mv, AXPBADPCMLOOP_t* loops);\n\tsint32 AXIsMultiVoiceRunning(AXVPBMULTI* mv);\n\t\n\tvoid AXOut_init();\n\tvoid AXOut_reset();\n\tvoid AXOut_update();\n\n\tCOSModule* GetModuleSndCore1();\n\tCOSModule* GetModuleSndCore2();\n}"
  },
  {
    "path": "src/Cafe/OS/libs/snd_core/ax_aux.cpp",
    "content": "#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/snd_core/ax_internal.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n\nnamespace snd_core\n{\n\tconst int AX_AUX_FRAME_COUNT = 2;\n\n\t// old (deprecated) style AUX callbacks\n\tMPTR __AXOldAuxDRCCallbackFunc[AX_AUX_BUS_COUNT * 2];\n\tMPTR __AXOldAuxDRCCallbackUserParam[AX_AUX_BUS_COUNT * 2];\n\n\tMPTR __AXOldAuxTVCallbackFunc[AX_AUX_BUS_COUNT];\n\tMPTR __AXOldAuxTVCallbackUserParam[AX_AUX_BUS_COUNT];\n\n\t// new style AUX callbacks\n\tMPTR __AXAuxDRCCallbackFunc[AX_AUX_BUS_COUNT * 2]; // 2 DRCs\n\tMPTR __AXAuxDRCCallbackUserParam[AX_AUX_BUS_COUNT * 2];\n\n\tMPTR __AXAuxTVCallbackFunc[AX_AUX_BUS_COUNT];\n\tMPTR __AXAuxTVCallbackUserParam[AX_AUX_BUS_COUNT];\n\n\tstruct AUXTVBuffer\n\t{\n\t\tsint32be _buf[AX_AUX_FRAME_COUNT * AX_TV_CHANNEL_COUNT * AX_AUX_BUS_COUNT * AX_SAMPLES_MAX];\n\n\t\tsint32be* GetBuffer(uint32 auxBus, uint32 auxFrame, uint32 channel = 0)\n\t\t{\n\t\t\tconst size_t samplesPerChannel = AXGetInputSamplesPerFrame();\n\t\t\tconst size_t samplesPerBus = AX_SAMPLES_PER_3MS_48KHZ * AX_TV_CHANNEL_COUNT;\n\t\t\tconst size_t samplesPerFrame = samplesPerBus * AX_AUX_BUS_COUNT;\n\t\t\treturn _buf + auxFrame * samplesPerFrame + auxBus * samplesPerBus + channel * samplesPerChannel;\n\t\t}\n\n\t\tvoid ClearBuffer()\n\t\t{\n\t\t\tmemset(_buf, 0, sizeof(_buf));\n\t\t}\n\t};\n\n\tstruct AUXDRCBuffer\n\t{\n\t\tsint32be _buf[AX_AUX_FRAME_COUNT * AX_DRC_CHANNEL_COUNT * AX_AUX_BUS_COUNT * AX_SAMPLES_MAX];\n\n\t\tsint32be* GetBuffer(uint32 auxBus, uint32 auxFrame, uint32 channel = 0)\n\t\t{\n\t\t\tconst size_t samplesPerChannel = AXGetInputSamplesPerFrame();\n\t\t\tconst size_t samplesPerBus = AX_SAMPLES_PER_3MS_48KHZ * AX_DRC_CHANNEL_COUNT;\n\t\t\tconst size_t samplesPerFrame = samplesPerBus * AX_AUX_BUS_COUNT;\n\t\t\treturn _buf + auxFrame * samplesPerFrame + auxBus * samplesPerBus + channel * samplesPerChannel;\n\t\t}\n\n\t\tvoid ClearBuffer()\n\t\t{\n\t\t\tmemset(_buf, 0, sizeof(_buf));\n\t\t}\n\t};\n\n\tSysAllocator<AUXTVBuffer>\t\t\t__AXAuxTVBuffer;\n\tSysAllocator<AUXDRCBuffer, 2>\t\t__AXAuxDRCBuffer;\n\n\tuint32 __AXCurrentAuxInputFrameIndex = 0;\n\n\tuint32 AXAux_GetOutputFrameIndex()\n\t{\n\t\treturn 1 - __AXCurrentAuxInputFrameIndex;\n\t}\n\n\tsint32be* AXAux_GetInputBuffer(sint32 device, sint32 deviceIndex, sint32 auxBus)\n\t{\n\t\tif (auxBus < 0 || auxBus >= AX_AUX_BUS_COUNT)\n\t\t\treturn nullptr;\n\t\tif (device == AX_DEV_TV)\n\t\t{\n\t\t\tcemu_assert_debug(deviceIndex == 0);\n\t\t\tif (__AXOldAuxTVCallbackFunc[auxBus] == MPTR_NULL && __AXAuxTVCallbackFunc[auxBus] == MPTR_NULL)\n\t\t\t\treturn nullptr;\n\t\t\treturn __AXAuxTVBuffer->GetBuffer(auxBus, __AXCurrentAuxInputFrameIndex);\n\t\t}\n\t\telse if (device == AX_DEV_DRC)\n\t\t{\n\t\t\tcemu_assert_debug(deviceIndex >= 0 && deviceIndex <= 1);\n\t\t\tif (__AXOldAuxDRCCallbackFunc[deviceIndex * AX_AUX_BUS_COUNT + auxBus] == MPTR_NULL && __AXAuxDRCCallbackFunc[deviceIndex * AX_AUX_BUS_COUNT + auxBus] == MPTR_NULL)\n\t\t\t\treturn nullptr;\n\t\t\treturn __AXAuxDRCBuffer[deviceIndex].GetBuffer(auxBus, __AXCurrentAuxInputFrameIndex);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tsint32be* AXAux_GetOutputBuffer(sint32 device, sint32 deviceIndex, sint32 auxBus)\n\t{\n\t\tuint32 outputFrameIndex = AXAux_GetOutputFrameIndex();\n\n\t\tif (device == AX_DEV_TV)\n\t\t{\n\t\t\tcemu_assert_debug(deviceIndex == 0);\n\t\t\tif (__AXOldAuxTVCallbackFunc[auxBus] == MPTR_NULL && __AXAuxTVCallbackFunc[auxBus] == MPTR_NULL)\n\t\t\t\treturn nullptr;\n\t\t\treturn __AXAuxTVBuffer->GetBuffer(auxBus, outputFrameIndex);\n\t\t}\n\t\telse if (device == AX_DEV_DRC)\n\t\t{\n\t\t\tcemu_assert_debug(deviceIndex >= 0 && deviceIndex <= 1);\n\t\t\tif (__AXOldAuxDRCCallbackFunc[deviceIndex * AX_AUX_BUS_COUNT + auxBus] == MPTR_NULL && __AXAuxDRCCallbackFunc[deviceIndex * AX_AUX_BUS_COUNT + auxBus] == MPTR_NULL)\n\t\t\t\treturn nullptr;\n\t\t\treturn __AXAuxDRCBuffer[deviceIndex].GetBuffer(auxBus, outputFrameIndex);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tvoid AXAux_Init()\n\t{\n\t\t__AXCurrentAuxInputFrameIndex = 0;\n\t\t__AXAuxTVBuffer->ClearBuffer();\n\t\t__AXAuxDRCBuffer[0].ClearBuffer();\n\t\t__AXAuxDRCBuffer[1].ClearBuffer();\n\n\t\tmemset(__AXAuxTVCallbackFunc, 0, sizeof(__AXAuxTVCallbackFunc));\n\t\tmemset(__AXAuxTVCallbackUserParam, 0, sizeof(__AXAuxTVCallbackUserParam));\n\t\tmemset(__AXOldAuxTVCallbackFunc, 0, sizeof(__AXOldAuxTVCallbackFunc));\n\t\tmemset(__AXOldAuxTVCallbackUserParam, 0, sizeof(__AXOldAuxTVCallbackUserParam));\n\n\t\tmemset(__AXAuxDRCCallbackFunc, 0, sizeof(__AXAuxDRCCallbackFunc));\n\t\tmemset(__AXAuxDRCCallbackUserParam, 0, sizeof(__AXAuxDRCCallbackUserParam));\n\t\tmemset(__AXOldAuxDRCCallbackFunc, 0, sizeof(__AXOldAuxDRCCallbackFunc));\n\t\tmemset(__AXOldAuxDRCCallbackUserParam, 0, sizeof(__AXOldAuxDRCCallbackUserParam));\n\t\t// init aux return volume\n\t\t__AXTVAuxReturnVolume[0] = 0x8000;\n\t\t__AXTVAuxReturnVolume[1] = 0x8000;\n\t\t__AXTVAuxReturnVolume[2] = 0x8000;\n\t}\n\n\tsint32 AXRegisterAuxCallback(sint32 device, sint32 deviceIndex, uint32 auxBusIndex, MPTR funcMPTR, MPTR userParam)\n\t{\n\t\tsint32 r = AXIsValidDevice(device, deviceIndex);\n\t\tif (r != 0)\n\t\t\treturn r;\n\t\tif (auxBusIndex >= AX_AUX_BUS_COUNT)\n\t\t\treturn -5;\n\t\tif (device == AX_DEV_TV)\n\t\t{\n\t\t\t__AXAuxTVCallbackFunc[auxBusIndex] = funcMPTR;\n\t\t\t__AXAuxTVCallbackUserParam[auxBusIndex] = userParam;\n\t\t}\n\t\telse if (device == AX_DEV_DRC)\n\t\t{\n\t\t\t__AXAuxDRCCallbackFunc[auxBusIndex + deviceIndex * 3] = funcMPTR;\n\t\t\t__AXAuxDRCCallbackUserParam[auxBusIndex + deviceIndex * 3] = userParam;\n\t\t}\n\t\telse if (device == AX_DEV_RMT)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tsint32 AXGetAuxCallback(sint32 device, sint32 deviceIndex, uint32 auxBusIndex, MEMPTR<uint32be> funcPtrOut, MEMPTR<uint32be> contextPtrOut)\n\t{\n\t\tsint32 r = AXIsValidDevice(device, deviceIndex);\n\t\tif (r != 0)\n\t\t\treturn r;\n\t\tif (auxBusIndex >= AX_AUX_BUS_COUNT)\n\t\t\treturn -5;\n\t\tif (device == AX_DEV_TV)\n\t\t{\n\t\t\t*funcPtrOut = __AXAuxTVCallbackFunc[auxBusIndex];\n\t\t\t*contextPtrOut = __AXAuxTVCallbackUserParam[auxBusIndex];\n\t\t}\n\t\telse if (device == AX_DEV_DRC)\n\t\t{\n\t\t\t*funcPtrOut = __AXAuxDRCCallbackFunc[auxBusIndex + deviceIndex * 3];\n\t\t\t*contextPtrOut = __AXAuxDRCCallbackUserParam[auxBusIndex + deviceIndex * 3];\n\t\t}\n\t\telse if (device == AX_DEV_RMT)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\t*funcPtrOut = MPTR_NULL;\n\t\t\t*contextPtrOut = MPTR_NULL;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tSysAllocator<MEMPTR<sint32be>, 6> __AXAuxCB_dataPtrs;\n\tSysAllocator<AXAUXCBCHANNELINFO> __AXAuxCB_auxCBStruct;\n\n\tvoid AXAux_Process()\n\t{\n\t\tuint32 processedAuxFrameIndex = AXAux_GetOutputFrameIndex();\n\t\tuint32 sampleCount = AXGetInputSamplesPerFrame();\n\t\t// TV aux callbacks\n\t\tuint32 tvChannelCount = AX_TV_CHANNEL_COUNT;\n\t\tfor (sint32 auxBusIndex = 0; auxBusIndex < AX_AUX_BUS_COUNT; auxBusIndex++)\n\t\t{\n\t\t\tMPTR auxCBFuncMPTR = MPTR_NULL;\n\t\t\tauxCBFuncMPTR = __AXAuxTVCallbackFunc[auxBusIndex];\n\t\t\tif (auxCBFuncMPTR == MPTR_NULL)\n\t\t\t\tauxCBFuncMPTR = __AXOldAuxTVCallbackFunc[auxBusIndex];\n\t\t\tif (auxCBFuncMPTR == MPTR_NULL)\n\t\t\t{\n\t\t\t\tvoid* auxOutput = __AXAuxTVBuffer->GetBuffer(auxBusIndex, processedAuxFrameIndex);\n\t\t\t\tmemset(auxOutput, 0, sampleCount * AX_TV_CHANNEL_COUNT * sizeof(sint32));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (sint32 channelIndex = 0; channelIndex < AX_TV_CHANNEL_COUNT; channelIndex++)\n\t\t\t\t__AXAuxCB_dataPtrs[channelIndex] = __AXAuxTVBuffer->GetBuffer(auxBusIndex, processedAuxFrameIndex, channelIndex);\n\t\t\t// do callback\n\t\t\tif (__AXAuxTVCallbackFunc[auxBusIndex] != MPTR_NULL)\n\t\t\t{\n\t\t\t\t// new style callback\n\t\t\t\tAXAUXCBCHANNELINFO* cbStruct = __AXAuxCB_auxCBStruct.GetPtr();\n\t\t\t\tcbStruct->numChannels = tvChannelCount;\n\t\t\t\tcbStruct->numSamples = sampleCount;\n\t\t\t\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\t\t\t\thCPU->gpr[3] = __AXAuxCB_dataPtrs.GetMPTR();\n\t\t\t\thCPU->gpr[4] = __AXAuxTVCallbackUserParam[auxBusIndex];\n\t\t\t\thCPU->gpr[5] = __AXAuxCB_auxCBStruct.GetMPTR();\n\t\t\t\tPPCCore_executeCallbackInternal(auxCBFuncMPTR);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// old style callback\n\t\t\t\tcemu_assert_debug(false); // todo\n\t\t\t}\n\t\t}\n\t\t// DRC aux callbacks\n\t\tfor (sint32 drcIndex = 0; drcIndex < 2; drcIndex++)\n\t\t{\n\t\t\tuint32 drcChannelCount = AX_DRC_CHANNEL_COUNT;\n\t\t\tfor (sint32 auxBusIndex = 0; auxBusIndex < AX_AUX_BUS_COUNT; auxBusIndex++)\n\t\t\t{\n\t\t\t\tMPTR auxCBFuncMPTR = MPTR_NULL;\n\t\t\t\tauxCBFuncMPTR = __AXAuxDRCCallbackFunc[auxBusIndex + drcIndex * 3];\n\t\t\t\tif (auxCBFuncMPTR == MPTR_NULL)\n\t\t\t\t{\n\t\t\t\t\tauxCBFuncMPTR = __AXOldAuxDRCCallbackFunc[auxBusIndex + drcIndex * 3];\n\t\t\t\t}\n\t\t\t\tif (auxCBFuncMPTR == MPTR_NULL)\n\t\t\t\t{\n\t\t\t\t\tvoid* auxOutput = __AXAuxDRCBuffer[drcIndex].GetBuffer(auxBusIndex, processedAuxFrameIndex);\n\t\t\t\t\tmemset(auxOutput, 0, 96 * 4 * sizeof(sint32));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (__AXAuxDRCCallbackFunc[auxBusIndex + drcIndex * 3] != MPTR_NULL)\n\t\t\t\t{\n\t\t\t\t\t// new style callback\n\t\t\t\t\tfor (sint32 channelIndex = 0; channelIndex < AX_DRC_CHANNEL_COUNT; channelIndex++)\n\t\t\t\t\t\t__AXAuxCB_dataPtrs[channelIndex] = __AXAuxDRCBuffer[drcIndex].GetBuffer(auxBusIndex, processedAuxFrameIndex, channelIndex);\n\t\t\t\t\tAXAUXCBCHANNELINFO* cbStruct = __AXAuxCB_auxCBStruct.GetPtr();\n\t\t\t\t\tcbStruct->numChannels = drcChannelCount;\n\t\t\t\t\tcbStruct->numSamples = sampleCount;\n\t\t\t\t\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\t\t\t\t\thCPU->gpr[3] = __AXAuxCB_dataPtrs.GetMPTR();\n\t\t\t\t\thCPU->gpr[4] = __AXAuxDRCCallbackUserParam[auxBusIndex + drcIndex * 3];\n\t\t\t\t\thCPU->gpr[5] = __AXAuxCB_auxCBStruct.GetMPTR();\n\t\t\t\t\tPPCCore_executeCallbackInternal(auxCBFuncMPTR);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// old style callback\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid AXAux_incrementBufferIndex()\n\t{\n\t\t__AXCurrentAuxInputFrameIndex = 1 - __AXCurrentAuxInputFrameIndex;\n\t}\n\n\tsint32 AXSetAuxReturnVolume(uint32 device, uint32 deviceIndex, uint32 auxBus, uint16 volume)\n\t{\n\t\tsint32 r = AXIsValidDevice(device, deviceIndex);\n\t\tif (r)\n\t\t\treturn r;\n\t\tif (auxBus >= AX_AUX_BUS_COUNT)\n\t\t\treturn -5;\n\t\tif( device == AX_DEV_TV )\n\t\t{ \n\t\t\t__AXTVAuxReturnVolume[auxBus] = volume;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"sndcore2.AXSetAuxReturnVolume() - unsupported device {}\", device);\n\t\t}\n\t\treturn 0;\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/snd_core/ax_exports.cpp",
    "content": "#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/snd_core/ax_internal.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MessageQueue.h\"\n#include \"OS/libs/coreinit/coreinit_DynLoad.h\"\n\nnamespace snd_core\n{\n\tsndGeneric_t sndGeneric;\n\n\tvoid AXResetToDefaultState()\n\t{\n\t\tsndGeneric = {};\n\t\tresetNumProcessedFrames();\n        AXVBP_Reset();\n    }\n\n\tbool AXIsInit()\n\t{\n\t\treturn sndGeneric.isInitialized;\n\t}\n\n\tvoid __AXInit(bool isSoundCore2, uint32 frameLength, uint32 rendererFreq, uint32 pipelineMode)\n\t{\n\t\tcemu_assert(frameLength == AX_FRAMELENGTH_3MS);\n\t\tcemu_assert(rendererFreq == AX_RENDERER_FREQ_32KHZ || rendererFreq == AX_RENDERER_FREQ_48KHZ);\n\t\tsndGeneric.isSoundCore2 = isSoundCore2;\n\t\tsndGeneric.initParam.frameLength = frameLength;\n\t\tsndGeneric.initParam.rendererFreq = rendererFreq;\n\t\tsndGeneric.initParam.pipelineMode = pipelineMode;\n\t\t// init submodules\n\t\tAXIst_Init();\n\t\tAXOut_Init();\n\t\tAXVPB_Init();\n\t\tAXAux_Init();\n\t\tAXMix_Init();\n\t\tAXMultiVoice_Init();\n\t\tAXIst_InitThread();\n\t\tsndGeneric.isInitialized = true;\n\t}\n\n\tvoid sndcore2_AXInitWithParams(AXINITPARAM* initParam)\n\t{\n\t\tif (sndGeneric.isInitialized)\n\t\t\treturn;\n\t\t__AXInit(true, initParam->frameLength, initParam->freq, initParam->pipelineMode);\n\t}\n\n\tvoid sndcore2_AXInit()\n\t{\n\t\tif (sndGeneric.isInitialized)\n\t\t\treturn;\n\t\t__AXInit(true, AX_FRAMELENGTH_3MS, AX_RENDERER_FREQ_32KHZ, AX_PIPELINE_SINGLE);\n\t}\n\n\tvoid sndcore1_AXInit()\n\t{\n\t\tif (sndGeneric.isInitialized)\n\t\t\treturn;\n\t\t__AXInit(false, AX_FRAMELENGTH_3MS, AX_RENDERER_FREQ_32KHZ, AX_PIPELINE_SINGLE);\n\t}\n\n\tvoid sndcore2_AXInitEx(uint32 uknParam)\n\t{\n\t\tcemu_assert_debug(uknParam == 0);\n\t\tif (sndGeneric.isInitialized)\n\t\t\treturn;\n\t\t__AXInit(true, AX_FRAMELENGTH_3MS, AX_RENDERER_FREQ_32KHZ, AX_PIPELINE_SINGLE);\n\t}\n\n\tvoid sndcore1_AXInitEx(uint32 uknParam)\n\t{\n\t\tcemu_assert_debug(uknParam == 0);\n\t\tif (sndGeneric.isInitialized)\n\t\t\treturn;\n\t\t__AXInit(false, AX_FRAMELENGTH_3MS, AX_RENDERER_FREQ_32KHZ, AX_PIPELINE_SINGLE);\n\t}\n\n\tvoid AXQuit()\n\t{\n        AXResetCallbacks();\n        // todo - should we wait to make sure any active callbacks are finished with execution before we exit AXQuit?\n        // request worker thread stop and wait until complete\n        AXIst_StopThread();\n        // clean up subsystems\n        AXVBP_Reset();\n\t\tsndGeneric.isInitialized = false;\n\t}\n\n\tsint32 AXGetMaxVoices()\n\t{\n\t\treturn sndGeneric.isInitialized ? AX_MAX_VOICES : 0;\n\t}\n\n\tvoid export_AXGetDeviceFinalMixCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamS32(device, 0);\n\t\tppcDefineParamU32BEPtr(funcAddrPtr, 1);\n\t\tsint32 r = AXGetDeviceFinalMixCallback(device, funcAddrPtr);\n\t\tcemuLog_log(LogType::SoundAPI, \"AXGetDeviceFinalMixCallback({},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXRegisterDeviceFinalMixCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamS32(device, 0);\n\t\tppcDefineParamMPTR(funcAddr, 1);\n\t\tcemuLog_log(LogType::SoundAPI, \"AXRegisterDeviceFinalMixCallback({},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\tsint32 r = AXRegisterDeviceFinalMixCallback(device, funcAddr);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXRegisterAppFrameCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXRegisterAppFrameCallback(0x{:08x})\", hCPU->gpr[3]);\n\t\tppcDefineParamMPTR(funcAddr, 0);\n\t\tsint32 r = AXRegisterAppFrameCallback(funcAddr);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXDeregisterAppFrameCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXDeregisterAppFrameCallback(0x{:08x})\", hCPU->gpr[3]);\n\t\tppcDefineParamMPTR(funcAddr, 0);\n\t\tsint32 r = AXDeregisterAppFrameCallback(funcAddr);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXRegisterFrameCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXRegisterFrameCallback(0x{:08x})\", hCPU->gpr[3]);\n\t\tppcDefineParamMPTR(funcAddr, 0);\n\t\tsint32 r = AXRegisterFrameCallback(funcAddr);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXRegisterCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXRegisterCallback(0x{:08x})\", hCPU->gpr[3]);\n\t\tppcDefineParamMPTR(funcAddr, 0);\n\t\tsint32 r = AXRegisterFrameCallback(funcAddr);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXRegisterAuxCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXRegisterAuxCallback(0x{:08x},0x{:08x},0x{:08x},0x{:08x},0x{:08x}) LR {:08x}\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->spr.LR);\n\t\tppcDefineParamU32(device, 0);\n\t\tppcDefineParamU32(deviceIndex, 1);\n\t\tppcDefineParamU32(auxBusIndex, 2);\n\t\tppcDefineParamMPTR(funcAddr, 3);\n\t\tppcDefineParamMPTR(userParam, 4);\n\t\tsint32 r = AXRegisterAuxCallback(device, deviceIndex, auxBusIndex, funcAddr, userParam);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXGetAuxCallback(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXGetAuxCallback(0x{:08x},0x{:08x},0x{:08x},0x{:08x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7]);\n\t\tppcDefineParamU32(device, 0);\n\t\tppcDefineParamU32(deviceIndex, 1);\n\t\tppcDefineParamU32(auxBusIndex, 2);\n\t\tppcDefineParamMEMPTR(funcAddrOut, uint32be, 3);\n\t\tppcDefineParamMEMPTR(userParamOut, uint32be, 4);\n\t\tsint32 r = AXGetAuxCallback(device, deviceIndex, auxBusIndex, funcAddrOut, userParamOut);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXSetAuxReturnVolume(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXSetAuxReturnVolume(0x{:08x},0x{:08x},0x{:08x},0x{:04x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\t\tppcDefineParamU32(device, 0);\n\t\tppcDefineParamU32(deviceIndex, 1);\n\t\tppcDefineParamU32(auxBusIndex, 2);\n\t\tppcDefineParamU16(volume, 3);\n\t\tsint32 r = AXSetAuxReturnVolume(device, deviceIndex, auxBusIndex, volume);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXGetDeviceMode(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXGetDeviceMode({})\", hCPU->gpr[3]);\n\t\tppcDefineParamS32(device, 0);\n\t\tppcDefineParamU32BEPtr(mode, 1);\n\t\t*mode = AXGetDeviceMode(device);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_AXSetDeviceUpsampleStage(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXSetDeviceUpsampleStage({},{})\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\tppcDefineParamS32(device, 0);\n\t\tppcDefineParamS32(upsampleStage, 1);\n\t\tsint32 r = AXSetDeviceUpsampleStage(device, upsampleStage);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXGetDeviceUpsampleStage(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXGetDeviceUpsampleStage({},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4]);\n\t\tppcDefineParamS32(device, 0);\n\t\tppcDefineParamU32BEPtr(upsampleStagePtr, 1);\n\t\tsint32 r = AXGetDeviceUpsampleStage(device, upsampleStagePtr);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXAcquireVoiceEx(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamS32(priority, 0);\n\t\tppcDefineParamMPTR(callbackEx, 1);\n\t\tppcDefineParamMPTR(userParam, 2);\n\t\tcemuLog_log(LogType::SoundAPI, \"AXAcquireVoiceEx({},0x{:08x},0x{:08x})\", priority, callbackEx, userParam);\n\t\tMEMPTR<AXVPB> r = AXAcquireVoiceEx(priority, callbackEx, userParam);\n\t\tosLib_returnFromFunction(hCPU, r.GetMPTR());\n\t}\n\n\tvoid export_AXAcquireVoice(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamS32(priority, 0);\n\t\tppcDefineParamMPTR(callback, 1);\n\t\tppcDefineParamMPTR(userParam, 2);\n\t\tcemuLog_log(LogType::SoundAPI, \"AXAcquireVoice({},0x{:08x},0x{:08x})\", priority, callback, userParam);\n\t\tMEMPTR<AXVPB> r = AXAcquireVoiceEx(priority, MPTR_NULL, MPTR_NULL);\n\t\tif (r.IsNull() == false)\n\t\t{\n\t\t\tr->callback = (uint32be)callback;\n\t\t\tr->userParam = (uint32be)userParam;\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, r.GetMPTR());\n\t}\n\n\tvoid export_AXFreeVoice(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamStructPtr(vpb, AXVPB, 0);\n\t\tcemuLog_log(LogType::SoundAPI, \"AXFreeVoice(0x{:08x})\", hCPU->gpr[3]);\n\t\tAXFreeVoice(vpb);\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid export_AXUserIsProtected(PPCInterpreter_t* hCPU)\n\t{\n\t\tsint32 r = AXUserIsProtected();\n\t\tcemuLog_log(LogType::SoundAPI, \"AXUserIsProtected() -> {}\", r!=0?\"true\":\"false\");\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXUserBegin(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXUserBegin()\");\n\t\tsint32 r = AXUserBegin();\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXUserEnd(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXUserEnd()\");\n\t\tsint32 r = AXUserEnd();\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXVoiceBegin(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamStructPtr(vpb, AXVPB, 0);\n\t\tcemuLog_log(LogType::SoundAPI, \"AXVoiceBegin(0x{:08x})\", hCPU->gpr[3]);\n\t\tsint32 r = AXVoiceBegin(vpb);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXVoiceEnd(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamStructPtr(vpb, AXVPB, 0);\n\t\tcemuLog_log(LogType::SoundAPI, \"AXVoiceEnd(0x{:08x})\", hCPU->gpr[3]);\n\t\tsint32 r = AXVoiceEnd(vpb);\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tvoid export_AXVoiceIsProtected(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamStructPtr(vpb, AXVPB, 0);\n\t\tcemuLog_log(LogType::SoundAPI, \"AXVoiceIsProtected(0x{:08x})\", hCPU->gpr[3]);\n\t\tsint32 r = AXVoiceProtection_IsProtectedByCurrentThread(vpb)?1:0;\n\t\tosLib_returnFromFunction(hCPU, r);\n\t}\n\n\tuint32 __AXCalculatePointerHighExtension(uint16 format, MPTR sampleBase, uint32 offset)\n\t{\n\t\tsampleBase = memory_virtualToPhysical(sampleBase);\n\t\tuint32 ptrHighExtension;\n\t\tif (format == AX_FORMAT_PCM8)\n\t\t{\n\t\t\tptrHighExtension = ((sampleBase + offset) >> 29);\n\t\t}\n\t\telse if (format == AX_FORMAT_PCM16)\n\t\t{\n\t\t\tptrHighExtension = ((sampleBase + offset * 2) >> 29);\n\t\t}\n\t\telse if (format == AX_FORMAT_ADPCM)\n\t\t{\n\t\t\tptrHighExtension = ((sampleBase + offset / 2) >> 29);\n\t\t}\n\t\treturn ptrHighExtension;\n\t}\n\n\tvoid export_AXCheckVoiceOffsets(PPCInterpreter_t* hCPU)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"AXCheckVoiceOffsets(0x{:08x})\", hCPU->gpr[3]);\n\t\tppcDefineParamStructPtr(pbOffset, AXPBOFFSET_t, 0);\n\n\t\tuint16 format = _swapEndianU16(pbOffset->format);\n\t\tMPTR sampleBase = _swapEndianU32(pbOffset->samples);\n\n\t\tuint32 highExtLoop = __AXCalculatePointerHighExtension(format, sampleBase, _swapEndianU32(pbOffset->loopOffset));\n\t\tuint32 highExtEnd = __AXCalculatePointerHighExtension(format, sampleBase, _swapEndianU32(pbOffset->endOffset));\n\t\tuint32 highExtCurrent = __AXCalculatePointerHighExtension(format, sampleBase, _swapEndianU32(pbOffset->currentOffset));\n\n\t\tbool isSameRange;\n\t\tif (highExtLoop == highExtEnd && highExtEnd == highExtCurrent)\n\t\t\tisSameRange = true;\n\t\telse\n\t\t\tisSameRange = false;\n\n\t\tosLib_returnFromFunction(hCPU, isSameRange ? 1 : 0);\n\t}\n\t\t\n\tvoid export_AXSetDeviceRemixMatrix(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamS32(device, 0);\n\t\tppcDefineParamU32(chanIn, 1);\n\t\tppcDefineParamU32(chanOut, 2);\n\t\tppcDefineParamMEMPTR(matrix, float32be, 3);\n\t\tcemuLog_log(LogType::SoundAPI, \"AXSetDeviceRemixMatrix({},{},{},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\t\tconst auto result = AXSetDeviceRemixMatrix(device, chanIn, chanOut, matrix);\n\t\tosLib_returnFromFunction(hCPU, result);\n\t}\n\t\n\tvoid export_AXGetDeviceRemixMatrix(PPCInterpreter_t* hCPU)\n\t{\n\t\tppcDefineParamS32(device, 0);\n\t\tppcDefineParamU32(chanIn, 1);\n\t\tppcDefineParamU32(chanOut, 2);\n\t\tppcDefineParamMEMPTR(matrix, MEMPTR<float32be>, 3);\n\t\tcemuLog_log(LogType::SoundAPI, \"AXGetDeviceRemixMatrix({},{},{},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\t\tconst auto result = AXGetDeviceRemixMatrix(device, chanIn, chanOut, matrix);\n\t\tosLib_returnFromFunction(hCPU, result);\n\t}\n\n\tstruct AXGetDeviceFinalOutput_t \n\t{\n\t\t/* +0x00 */ uint32be channelCount;\n\t\t/* +0x04 */ uint32be uknValue;\n\t\t/* +0x08 */ uint32be ukn08;\n\t\t/* +0x0C */ uint32be ukn0C;\n\t\t/* +0x10 */ uint32be size;\n\t\t// struct might be bigger?\n\t};\n\n\tsint32 AXGetDeviceFinalOutput(uint32 device, sint16be* sampleBufferOutput, uint32 bufferSize, AXGetDeviceFinalOutput_t* output)\n\t{\n\t\tif (device != AX_DEV_TV && device != AX_DEV_DRC)\n\t\t\treturn -1;\n\t\tsint32 channelCount = AIGetChannelCount(device);\n\t\tsint32 samplesPerChannel = AIGetSamplesPerChannel(device);\n\t\tsint32 samplesToCopy = samplesPerChannel * channelCount;\n\n\t\tif (bufferSize < (samplesToCopy * sizeof(sint16be)))\n\t\t\treturn -11; // buffer not large enough\n\n\t\t// copy samples to buffer\n\t\tsint16* samplesBuffer = AIGetCurrentDMABuffer(device);\n\t\tfor (sint32 i = 0; i < samplesToCopy; i++)\n\t\t\tsampleBufferOutput[i] = samplesBuffer[i];\n\n\t\t// set output struct\n\t\toutput->size = samplesToCopy * sizeof(sint16be);\n\t\toutput->channelCount = channelCount;\n\t\toutput->uknValue = 1; // always set to 1/true?\n\n\t\treturn 0;\n\t}\n\n\t// void loadExportsSndCore1()\n\t// {\n\t// \tcafeExportRegisterFunc(sndcore1_AXInit, \"snd_core\", \"AXInit\", LogType::SoundAPI);\n\t// \tcafeExportRegisterFunc(sndcore1_AXInitEx, \"snd_core\", \"AXInitEx\", LogType::SoundAPI);\n\t// \tcafeExportRegister(\"snd_core\", AXIsInit, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"snd_core\", AXQuit, LogType::SoundAPI);\n\t//\n\t// \tcafeExportRegister(\"snd_core\", AXGetMaxVoices, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"snd_core\", AXGetInputSamplesPerFrame, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"snd_core\", AXGetInputSamplesPerSec, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"snd_core\", AXSetDefaultMixerSelect, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"snd_core\", AXGetDefaultMixerSelect, LogType::SoundAPI);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXGetDeviceFinalMixCallback\", export_AXGetDeviceFinalMixCallback);\n\t// \tosLib_addFunction(\"snd_core\", \"AXRegisterDeviceFinalMixCallback\", export_AXRegisterDeviceFinalMixCallback);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXRegisterAppFrameCallback\", export_AXRegisterAppFrameCallback);\n\t// \tosLib_addFunction(\"snd_core\", \"AXDeregisterAppFrameCallback\", export_AXDeregisterAppFrameCallback);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXRegisterFrameCallback\", export_AXRegisterFrameCallback);\n\t// \tosLib_addFunction(\"snd_core\", \"AXRegisterCallback\", export_AXRegisterCallback);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXRegisterAuxCallback\", export_AXRegisterAuxCallback);\n\t// \tosLib_addFunction(\"snd_core\", \"AXGetAuxCallback\", export_AXGetAuxCallback);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXSetAuxReturnVolume\", export_AXSetAuxReturnVolume);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXGetDeviceMode\", export_AXGetDeviceMode);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXSetDeviceUpsampleStage\", export_AXSetDeviceUpsampleStage);\n\t// \tosLib_addFunction(\"snd_core\", \"AXGetDeviceUpsampleStage\", export_AXGetDeviceUpsampleStage);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXAcquireVoiceEx\", export_AXAcquireVoiceEx);\n\t// \tosLib_addFunction(\"snd_core\", \"AXAcquireVoice\", export_AXAcquireVoice);\n\t// \tosLib_addFunction(\"snd_core\", \"AXFreeVoice\", export_AXFreeVoice);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXUserIsProtected\", export_AXUserIsProtected);\n\t// \tosLib_addFunction(\"snd_core\", \"AXUserBegin\", export_AXUserBegin);\n\t// \tosLib_addFunction(\"snd_core\", \"AXUserEnd\", export_AXUserEnd);\n\t// \tosLib_addFunction(\"snd_core\", \"AXVoiceBegin\", export_AXVoiceBegin);\n\t// \tosLib_addFunction(\"snd_core\", \"AXVoiceEnd\", export_AXVoiceEnd);\n\t// \tosLib_addFunction(\"snd_core\", \"AXVoiceIsProtected\", export_AXVoiceIsProtected);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXCheckVoiceOffsets\", export_AXCheckVoiceOffsets);\n\t//\n\t// \tosLib_addFunction(\"snd_core\", \"AXSetDeviceRemixMatrix\", export_AXSetDeviceRemixMatrix);\n\t// \tosLib_addFunction(\"snd_core\", \"AXGetDeviceRemixMatrix\", export_AXGetDeviceRemixMatrix);\n\t//\n\t// \tcafeExportRegister(\"snd_core\", AXGetDeviceFinalOutput, LogType::SoundAPI);\n\t// }\n\t//\n\t// void loadExportsSndCore2()\n\t// {\n\t// \tcafeExportRegisterFunc(sndcore2_AXInitWithParams, \"sndcore2\", \"AXInitWithParams\", LogType::SoundAPI);\n\t// \tcafeExportRegisterFunc(sndcore2_AXInit, \"sndcore2\", \"AXInit\", LogType::SoundAPI);\n\t// \tcafeExportRegisterFunc(sndcore2_AXInitEx, \"sndcore2\", \"AXInitEx\", LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXIsInit, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXQuit, LogType::SoundAPI);\n\t//\n\t// \tcafeExportRegister(\"sndcore2\", AXGetMaxVoices, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXGetInputSamplesPerFrame, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXGetInputSamplesPerSec, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetDefaultMixerSelect, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXGetDefaultMixerSelect, LogType::SoundAPI);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXGetDeviceFinalMixCallback\", export_AXGetDeviceFinalMixCallback);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXRegisterDeviceFinalMixCallback\", export_AXRegisterDeviceFinalMixCallback);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXRegisterAppFrameCallback\", export_AXRegisterAppFrameCallback);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXDeregisterAppFrameCallback\", export_AXDeregisterAppFrameCallback);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXRegisterFrameCallback\", export_AXRegisterFrameCallback);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXRegisterCallback\", export_AXRegisterCallback);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXRegisterAuxCallback\", export_AXRegisterAuxCallback);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXGetAuxCallback\", export_AXGetAuxCallback);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXSetAuxReturnVolume\", export_AXSetAuxReturnVolume);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXGetDeviceMode\", export_AXGetDeviceMode);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXSetDeviceUpsampleStage\", export_AXSetDeviceUpsampleStage);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXGetDeviceUpsampleStage\", export_AXGetDeviceUpsampleStage);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXAcquireVoiceEx\", export_AXAcquireVoiceEx);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXAcquireVoice\", export_AXAcquireVoice);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXFreeVoice\", export_AXFreeVoice);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXUserIsProtected\", export_AXUserIsProtected);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXUserBegin\", export_AXUserBegin);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXUserEnd\", export_AXUserEnd);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXVoiceBegin\", export_AXVoiceBegin);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXVoiceEnd\", export_AXVoiceEnd);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXVoiceIsProtected\", export_AXVoiceIsProtected);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXCheckVoiceOffsets\", export_AXCheckVoiceOffsets);\n\t//\n\t// \tosLib_addFunction(\"sndcore2\", \"AXSetDeviceRemixMatrix\", export_AXSetDeviceRemixMatrix);\n\t// \tosLib_addFunction(\"sndcore2\", \"AXGetDeviceRemixMatrix\", export_AXGetDeviceRemixMatrix);\n\t//\n\t// \tcafeExportRegister(\"sndcore2\", AXGetDeviceFinalOutput, LogType::SoundAPI);\n\t//\n\t// \t// multi voice\n\t// \tcafeExportRegister(\"sndcore2\", AXAcquireMultiVoice, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXFreeMultiVoice, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXGetMultiVoiceReformatBufferSize, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceType, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceAdpcm, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceSrcType, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceOffsets, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceVe, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceSrcRatio, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceSrc, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceLoop, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceState, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceAdpcmLoop, LogType::SoundAPI);\n\t// \tcafeExportRegister(\"sndcore2\", AXIsMultiVoiceRunning, LogType::SoundAPI);\n\t// }\n\n\t// void loadExports()\n\t// {\n //        AXResetToDefaultState();\n //\n\t// \tloadExportsSndCore1();\n\t// \tloadExportsSndCore2();\n\t// }\n\n\tbool isInitialized()\n\t{\n\t\treturn sndGeneric.isInitialized;\n\t}\n\n\tvoid reset()\n\t{\n        AXOut_reset();\n        AXResetToDefaultState();\n        sndGeneric.isInitialized = false;\n\t}\n\n\tvoid RegisterVoiceFunctions()\n\t{\n\t\t// snd_core\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceDeviceMix, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXComputeLpfCoefs, LogType::SoundAPI);\n\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceState, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceType, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceAdpcmLoop, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceSrc, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceSrcType, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceSrcRatio, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceVe, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceAdpcm, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceLoop, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceLpf, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceLpfCoefs, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceBiquad, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceBiquadCoefs, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceOffsets, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceOffsetsEx, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceCurrentOffset, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceCurrentOffsetEx, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceLoopOffset, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceLoopOffsetEx, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceEndOffset, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceEndOffsetEx, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXSetVoiceSamplesAddr, LogType::SoundAPI);\n\n\t\tcafeExportRegister(\"snd_core\", AXIsVoiceRunning, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXGetVoiceLoopCount, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXGetVoiceOffsets, LogType::SoundAPI);\n\t\tcafeExportRegister(\"snd_core\", AXGetVoiceCurrentOffsetEx, LogType::SoundAPI);\n\n\t\t// sndcore2\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceDeviceMix, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXComputeLpfCoefs, LogType::SoundAPI);\n\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceState, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceType, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceAdpcmLoop, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceSrc, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceSrcType, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceSrcRatio, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceVe, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceAdpcm, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceLoop, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceLpf, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceLpfCoefs, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceBiquad, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceBiquadCoefs, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceOffsets, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceOffsetsEx, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceCurrentOffset, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceCurrentOffsetEx, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceLoopOffset, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceLoopOffsetEx, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceEndOffset, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceEndOffsetEx, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXSetVoiceSamplesAddr, LogType::SoundAPI);\n\n\t\tcafeExportRegister(\"sndcore2\", AXIsVoiceRunning, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXGetVoiceLoopCount, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXGetVoiceOffsets, LogType::SoundAPI);\n\t\tcafeExportRegister(\"sndcore2\", AXGetVoiceCurrentOffsetEx, LogType::SoundAPI);\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"snd_core\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tAXResetToDefaultState();\n\t\t\tcafeExportRegisterFunc(sndcore1_AXInit, \"snd_core\", \"AXInit\", LogType::SoundAPI);\n\t\t\tcafeExportRegisterFunc(sndcore1_AXInitEx, \"snd_core\", \"AXInitEx\", LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_core\", AXIsInit, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_core\", AXQuit, LogType::SoundAPI);\n\n\t\t\tcafeExportRegister(\"snd_core\", AXGetMaxVoices, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_core\", AXGetInputSamplesPerFrame, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_core\", AXGetInputSamplesPerSec, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_core\", AXSetDefaultMixerSelect, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_core\", AXGetDefaultMixerSelect, LogType::SoundAPI);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXGetDeviceFinalMixCallback\", export_AXGetDeviceFinalMixCallback);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXRegisterDeviceFinalMixCallback\", export_AXRegisterDeviceFinalMixCallback);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXRegisterAppFrameCallback\", export_AXRegisterAppFrameCallback);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXDeregisterAppFrameCallback\", export_AXDeregisterAppFrameCallback);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXRegisterFrameCallback\", export_AXRegisterFrameCallback);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXRegisterCallback\", export_AXRegisterCallback);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXRegisterAuxCallback\", export_AXRegisterAuxCallback);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXGetAuxCallback\", export_AXGetAuxCallback);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXSetAuxReturnVolume\", export_AXSetAuxReturnVolume);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXGetDeviceMode\", export_AXGetDeviceMode);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXSetDeviceUpsampleStage\", export_AXSetDeviceUpsampleStage);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXGetDeviceUpsampleStage\", export_AXGetDeviceUpsampleStage);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXAcquireVoiceEx\", export_AXAcquireVoiceEx);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXAcquireVoice\", export_AXAcquireVoice);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXFreeVoice\", export_AXFreeVoice);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXUserIsProtected\", export_AXUserIsProtected);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXUserBegin\", export_AXUserBegin);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXUserEnd\", export_AXUserEnd);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXVoiceBegin\", export_AXVoiceBegin);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXVoiceEnd\", export_AXVoiceEnd);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXVoiceIsProtected\", export_AXVoiceIsProtected);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXCheckVoiceOffsets\", export_AXCheckVoiceOffsets);\n\n\t\t\tosLib_addFunction(\"snd_core\", \"AXSetDeviceRemixMatrix\", export_AXSetDeviceRemixMatrix);\n\t\t\tosLib_addFunction(\"snd_core\", \"AXGetDeviceRemixMatrix\", export_AXGetDeviceRemixMatrix);\n\n\t\t\tcafeExportRegister(\"snd_core\", AXGetDeviceFinalOutput, LogType::SoundAPI);\n\n\t\t\tRegisterVoiceFunctions();\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\tAXResetToDefaultState();\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t\tAXResetToDefaultState();\n\t\t\t}\n\t\t}\n\t}s_COSsndcore1Module;\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"sndcore2\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegisterFunc(sndcore2_AXInitWithParams, \"sndcore2\", \"AXInitWithParams\", LogType::SoundAPI);\n\t\t\tcafeExportRegisterFunc(sndcore2_AXInit, \"sndcore2\", \"AXInit\", LogType::SoundAPI);\n\t\t\tcafeExportRegisterFunc(sndcore2_AXInitEx, \"sndcore2\", \"AXInitEx\", LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXIsInit, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXQuit, LogType::SoundAPI);\n\n\t\t\tcafeExportRegister(\"sndcore2\", AXGetMaxVoices, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXGetInputSamplesPerFrame, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXGetInputSamplesPerSec, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetDefaultMixerSelect, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXGetDefaultMixerSelect, LogType::SoundAPI);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXGetDeviceFinalMixCallback\", export_AXGetDeviceFinalMixCallback);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXRegisterDeviceFinalMixCallback\", export_AXRegisterDeviceFinalMixCallback);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXRegisterAppFrameCallback\", export_AXRegisterAppFrameCallback);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXDeregisterAppFrameCallback\", export_AXDeregisterAppFrameCallback);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXRegisterFrameCallback\", export_AXRegisterFrameCallback);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXRegisterCallback\", export_AXRegisterCallback);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXRegisterAuxCallback\", export_AXRegisterAuxCallback);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXGetAuxCallback\", export_AXGetAuxCallback);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXSetAuxReturnVolume\", export_AXSetAuxReturnVolume);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXGetDeviceMode\", export_AXGetDeviceMode);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXSetDeviceUpsampleStage\", export_AXSetDeviceUpsampleStage);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXGetDeviceUpsampleStage\", export_AXGetDeviceUpsampleStage);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXAcquireVoiceEx\", export_AXAcquireVoiceEx);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXAcquireVoice\", export_AXAcquireVoice);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXFreeVoice\", export_AXFreeVoice);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXUserIsProtected\", export_AXUserIsProtected);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXUserBegin\", export_AXUserBegin);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXUserEnd\", export_AXUserEnd);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXVoiceBegin\", export_AXVoiceBegin);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXVoiceEnd\", export_AXVoiceEnd);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXVoiceIsProtected\", export_AXVoiceIsProtected);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXCheckVoiceOffsets\", export_AXCheckVoiceOffsets);\n\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXSetDeviceRemixMatrix\", export_AXSetDeviceRemixMatrix);\n\t\t\tosLib_addFunction(\"sndcore2\", \"AXGetDeviceRemixMatrix\", export_AXGetDeviceRemixMatrix);\n\n\t\t\tcafeExportRegister(\"sndcore2\", AXGetDeviceFinalOutput, LogType::SoundAPI);\n\n\t\t\t// multi voice\n\t\t\tcafeExportRegister(\"sndcore2\", AXAcquireMultiVoice, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXFreeMultiVoice, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXGetMultiVoiceReformatBufferSize, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceType, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceAdpcm, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceSrcType, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceOffsets, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceVe, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceSrcRatio, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceSrc, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceLoop, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceState, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXSetMultiVoiceAdpcmLoop, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"sndcore2\", AXIsMultiVoiceRunning, LogType::SoundAPI);\n\n\t\t\tRegisterVoiceFunctions();\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\tAXResetToDefaultState();\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t\tAXResetToDefaultState();\n\t\t\t}\n\t\t}\n\t}s_COSsndcore2Module;\n\n\tCOSModule* GetModuleSndCore1()\n\t{\n\t\treturn &s_COSsndcore1Module;\n\t}\n\n\tCOSModule* GetModuleSndCore2()\n\t{\n\t\treturn &s_COSsndcore2Module;\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/snd_core/ax_internal.h",
    "content": "#pragma once\n#include \"Cafe/OS/libs/snd_core/ax.h\"\n\nnamespace snd_core\n{\n\tstruct sndGeneric_t\n\t{\n\t\tbool isInitialized{false};\n\t\tbool isSoundCore2{false};\n\t\t// init params\n\t\tstruct\n\t\t{\n\t\t\tuint32 rendererFreq{0}; // 32Khz or 48Khz\n\t\t\tuint32 frameLength{0}; // 3MS\n\t\t\tuint32 pipelineMode{0};\n\t\t}initParam;\n\t};\n\n\textern sndGeneric_t sndGeneric;\n\n\tconst uint32 AX_SYNCFLAG_SRCFILTER = 0x1;\t\t\t\t// Voice src type (AXSetVoiceSrcType)\n\tconst uint32 AX_SYNCFLAG_DEVICEMIXMASK = 0x2;\t\t\t// Voice mix related (AXSetVoiceDeviceMix)\n\tconst uint32 AX_SYNCFLAG_PLAYBACKSTATE = 0x4;\t\t\t// Voice play state (AXSetVoiceState)\n\tconst uint32 AX_SYNCFLAG_VOICETYPE = 0x8;\t\t\t\t// Voice type (AXSetVoiceType)\n\tconst uint32 AX_SYNCFLAG_DEVICEMIX = 0x10;\t\t\t\t// Voice mix related (AXSetVoiceDeviceMix)\n\tconst uint32 AX_SYNCFLAG_ITD20 = 0x20;\t\t\t\t\t// Voice initial time delay (AXSetVoiceItdOn)\n\tconst uint32 AX_SYNCFLAG_ITD40 = 0x40;\t\t\t\t\t// Voice initial time delay (AXSetVoiceItdOn, AXSetVoiceItdTarget)\n\tconst uint32 AX_SYNCFLAG_VE = 0x100;\t\t\t\t\t// Voice ve (AXSetVoiceVe)\n\tconst uint32 AX_SYNCFLAG_VEDELTA = 0x200;\t\t\t\t// Voice ve delta (AXSetVoiceVeDelta)\n\tconst uint32 AX_SYNCFLAG_OFFSETS = 0x400;\t\t\t\t// Voice offset data (AXSetVoiceOffsets)\n\tconst uint32 AX_SYNCFLAG_LOOPFLAG = 0x800;\t\t\t\t// Voice loop flag (AXSetVoiceLoop)\n\tconst uint32 AX_SYNCFLAG_LOOPOFFSET = 0x1000;\t\t\t// Voice loop offset (AXSetVoiceLoopOffset)\n\tconst uint32 AX_SYNCFLAG_ENDOFFSET = 0x2000;\t\t\t// Voice end offset (AXSetVoiceEndOffset)\n\tconst uint32 AX_SYNCFLAG_CURRENTOFFSET = 0x4000;\t\t// Voice current offset (AXSetVoiceCurrentOffset)\n\tconst uint32 AX_SYNCFLAG_ADPCMDATA = 0x8000;\t\t\t// Voice adpcm data (AXSetVoiceAdpcm)\n\tconst uint32 AX_SYNCFLAG_SRCDATA = 0x10000;\t\t\t\t// Voice src + src ratio (AXSetVoiceSrc)\n\tconst uint32 AX_SYNCFLAG_SRCRATIO = 0x20000;\t\t\t// Voice src ratio (AXSetVoiceSrcRatio)\n\tconst uint32 AX_SYNCFLAG_ADPCMLOOP = 0x40000;\t\t\t// Voice adpcm loop (AXSetVoiceAdpcmLoop)\n\tconst uint32 AX_SYNCFLAG_LPFDATA = 0x80000;\t\t\t\t// Voice lpf (AXSetVoiceLpf)\n\tconst uint32 AX_SYNCFLAG_LPFCOEF = 0x100000;\t\t\t// Voice lpf coef (AXSetVoiceLpfCoefs)\n\tconst uint32 AX_SYNCFLAG_BIQUADDATA = 0x200000;\t\t\t// Voice biquad (AXSetVoiceBiquad)\n\tconst uint32 AX_SYNCFLAG_BIQUADCOEF = 0x400000;\t\t\t// Voice biquad coef (AXSetVoiceBiquadCoefs)\n\tconst uint32 AX_SYNCFLAG_VOICEREMOTEON = 0x800000;\t\t// ??? (AXSetVoiceRmtOn?)\n\tconst uint32 AX_SYNCFLAG_4000000 = 0x4000000;\t\t\t// ???\n\tconst uint32 AX_SYNCFLAG_8000000 = 0x8000000;\t\t\t// ???\n\n\tstruct axADPCMInternal_t\n\t{\n\t\t/* +0x00 | +0x190 */ uint16 coef[16];\n\t\t/* +0x20 | +0x1B0 */ uint16 gain;\n\t\t/* +0x22 | +0x1B2 */ uint16 scale;\n\t\t/* +0x24 | +0x1B4 */ uint16 yn1;\n\t\t/* +0x26 | +0x1B6 */ uint16 yn2;\n\t\t// size: 0x28\n\t};\n\n\tstruct axADPCMLoopInternal_t\n\t{\n\t\t/* +0x00 | 0x1C6 */ uint16 loopScale;\n\t\t/* +0x02 | 0x1C8 */ uint16 loopYn1;\n\t\t/* +0x04 | 0x1CA */ uint16 loopYn2;\n\t\t// size: 0x6\n\t};\n\n\tstruct axOffsetsInternal_t\n\t{\n\t\t/* +0x00 / 0x17E */ uint16 loopFlag;\n\t\t/* +0x02 / 0x180 */ uint16 format;\n\t\t/* +0x04 / 0x182 */ uint16 ptrHighExtension; // defines 512mb range (highest 3 bit of current offset ptr counted in bytes)\n\t\t// offsets (relative to NULL, counted in sample words)\n\t\t// note: All offset ptr variables can only store values up to 512MB (PCM8 mask -> 0x1FFFFFFF, PCM16 mask -> 0x0FFFFFFF, ADPCM mask -> 0x3FFFFFFF)\n\t\t/* +0x06 / 0x184 */ uint16 loopOffsetPtrHigh;\n\t\t/* +0x08 / 0x186 */ uint16 loopOffsetPtrLow;\n\t\t/* +0x0A / 0x188 */ uint16 endOffsetPtrHigh;\n\t\t/* +0x0C / 0x18A */ uint16 endOffsetPtrLow;\n\t\t/* +0x0E / 0x18C */ uint16 currentOffsetPtrHigh;\n\t\t/* +0x10 / 0x18E */ uint16 currentOffsetPtrLow;\n\n\t\tuint32 GetLoopOffset32() const\n\t\t{\n\t\t\tuint32 offset = (uint32)_swapEndianU16(loopOffsetPtrHigh) << 16;\n\t\t\treturn offset | (uint32)_swapEndianU16(loopOffsetPtrLow);\n\t\t}\n\n\t\tuint32 GetEndOffset32() const\n\t\t{\n\t\t\tuint32 offset = (uint32)_swapEndianU16(endOffsetPtrHigh) << 16;\n\t\t\treturn offset | (uint32)_swapEndianU16(endOffsetPtrLow);\n\t\t}\n\n\t\tuint32 GetCurrentOffset32() const\n\t\t{\n\t\t\tuint32 offset = (uint32)_swapEndianU16(currentOffsetPtrHigh) << 16;\n\t\t\treturn offset | (uint32)_swapEndianU16(currentOffsetPtrLow);\n\t\t}\n\t};\n\n\tconst int AX_BUS_COUNT = 4;\n\n\tstruct AXVPBInternal_t\n\t{\n\t\t/* matches what the DSP expects */\n\t\t/* +0x000 */ uint16be nextAddrHigh; // points to next shadow copy (physical pointer, NULL for last voice in list)\n\t\t/* +0x002 */ uint16be nextAddrLow;\n\t\t/* +0x004 */ uint16be selfAddrHigh; // points to shadow copy of self (physical pointer)\n\t\t/* +0x006 */ uint16be selfAddrLow;\n\t\t/* +0x008 */ uint16 srcFilterMode; // AX_FILTER_MODE_*\n\t\t/* +0x00A */ uint16 srcTapFilter; // AX_FILTER_TAP_*\n\t\t/* +0x00C */ uint16be mixerSelect;\n\t\t/* +0x00E */ uint16 voiceType;\n\t\t/* +0x010 */ uint16 deviceMixMaskTV[4];\n\t\t/* +0x018 */ uint16 deviceMixMaskDRC[4 * 2];\n\t\t/* +0x028 */ AXCHMIX_DEPR deviceMixTV[AX_BUS_COUNT * AX_TV_CHANNEL_COUNT]; // TV device mix\n\t\t/* +0x088 */ AXCHMIX_DEPR deviceMixDRC[AX_BUS_COUNT * AX_DRC_CHANNEL_COUNT * 2]; // DRC device mix\n\t\t/* +0x108 */ AXCHMIX_DEPR deviceMixRMT[0x40 / 4]; // RMT device mix (size unknown)\n\t\t/* +0x148 */ uint16 reserved148_voiceRmtOn;\n\t\t/* +0x14A */ uint16 deviceMixMaskRMT[0x10];\n\t\t/* +0x16A */ uint16 playbackState;\n\t\t// itd (0x16C - 0x1B4?)\n\t\t/* +0x16C */ uint16 reserved16C;\n\t\t/* +0x16E */ uint16be itdAddrHigh; // points to AXItd_t (physical pointer)\n\t\t/* +0x170 */ uint16be itdAddrLow;\n\t\t/* +0x172 */ uint16 reserved172;\n\t\t/* +0x174 */ uint16 reserved174;\n\t\t/* +0x176 */ uint16 reserved176_itdRelated;\n\t\t/* +0x178 */ uint16 reserved178_itdRelated;\n\t\t/* +0x17A */ uint16be veVolume;\n\t\t/* +0x17C */ uint16be veDelta;\n\t\t/* +0x17E */ axOffsetsInternal_t internalOffsets;\n\t\t/* +0x190 */ axADPCMInternal_t adpcmData;\n\t\t/* +0x1B8 */ AXPBSRC_t src;\n\t\t/* +0x1C6 */ axADPCMLoopInternal_t adpcmLoop;\n\t\tstruct\n\t\t{\n\t\t\t/* +0x1CC */ uint16 on;\n\t\t\t/* +0x1CE */ uint16 yn1;\n\t\t\t/* +0x1D0 */ uint16 a0;\n\t\t\t/* +0x1D2 */ uint16 b0;\n\t\t}lpf;\n\t\tstruct\n\t\t{\n\t\t\t/* +0x1D4 */ uint16 on;\n\t\t\t/* +0x1D6 */ sint16 xn1;\n\t\t\t/* +0x1D8 */ sint16 xn2;\n\t\t\t/* +0x1DA */ sint16 yn1;\n\t\t\t/* +0x1DC */ sint16 yn2;\n\t\t\t/* +0x1DE */ uint16 b0;\n\t\t\t/* +0x1E0 */ uint16 b1;\n\t\t\t/* +0x1E2 */ uint16 b2;\n\t\t\t/* +0x1E4 */ uint16 a1;\n\t\t\t/* +0x1E6 */ uint16 a2;\n\t\t}biquad;\n\t\tuint16 reserved1E8[0x18];\n\t\tuint16 reserved218[0x20]; // not related to device mix?\n\t\tuint16 reserved258[0x10]; // not related to device mix?\n\t\t// rmt src related\n\t\tuint16 reserved278;\n\t\tuint16 reserved27A;\n\t\tuint16 reserved27C;\n\t\tuint16 reserved27E;\n\t\tuint16 reserved280;\n\t\tuint16 reserved282_rmtIIRGuessed;\n\t\tuint32 reserved284;\n\t\tuint32 reserved288;\n\t\tuint32 reserved28C;\n\t\tuint32 reserved290;\n\t\tuint16 reserved294;\n\t\tuint16 reserved296;\n\t\t/* +0x298 */ uint16 reserved298;\n\t\t/* +0x29A */ uint16 reserved29A;\n\t\t/* +0x29C */ uint16 reserved29C;\n\t\t/* +0x29E */ uint16 reserved29E;\n\t\t/* +0x2A0 */ uint16be index;\n\t\t/* +0x2A2 */ uint16be ukn2A2; // voice active/valid and being processed?\n\t\tuint16 reserved2A4;\n\t\tuint16 reserved2A6;\n\t\tuint16 reserved2A8;\n\t\tuint16 reserved2AA;\n\t\t/* +0x2AC */ MEMPTR<AXVPBInternal_t> nextToProcess;\n\t\tuint32 reserved2B0;\n\t\tuint32 reserved2B4;\n\t\tuint32 reserved2B8;\n\t\tuint32 reserved2BC;\n\t\t// size: 0x2C0\n\t};\n\n\tstatic_assert(sizeof(AXVPBInternal_t) == 0x2C0);\n\n\textern AXVPBInternal_t* __AXVPBInternalVoiceArray;\n\textern AXVPBInternal_t* __AXVPBInternalVoiceShadowCopyArrayPtr;\n\textern AXVPB* __AXVPBArrayPtr;\n\n\tvoid AXResetVoiceLoopCount(AXVPB* vpb);\n\n\tstd::vector<AXVPB*>& AXVoiceList_GetListByPriority(uint32 priority);\n\tstd::vector<AXVPB*>& AXVoiceList_GetFreeVoices();\n\n\tinline AXVPBInternal_t* GetInternalVoice(const AXVPB* vpb)\n\t{\n\t\treturn __AXVPBInternalVoiceArray + (size_t)vpb->index;\n\t}\n\n\tinline uint32 GetVoiceIndex(const AXVPB* vpb)\n\t{\n\t\treturn (uint32)vpb->index;\n\t}\n\n    void AXVBP_Reset();\n\n\t// AXIst\n\tvoid AXIst_InitThread();\n\tOSThread_t* AXIst_GetThread();\n\tvoid AXIst_StopThread();\n\n\tvoid AXIst_HandleFrameCallbacks();\n\n\t// AXAux\n\tvoid AXAux_incrementBufferIndex();\n\n\t// internal mix buffers\n\textern SysAllocator<sint32, AX_SAMPLES_MAX * AX_TV_CHANNEL_COUNT> __AXTVOutputBuffer;\n\textern SysAllocator<sint32, AX_SAMPLES_MAX * AX_DRC_CHANNEL_COUNT * 2> __AXDRCOutputBuffer;\n\n}"
  },
  {
    "path": "src/Cafe/OS/libs/snd_core/ax_ist.cpp",
    "content": "#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/snd_core/ax_internal.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MessageQueue.h\"\n\nnamespace snd_core\n{\n\tsint32 __AXDeviceUpsampleStage[AX_DEV_COUNT]; // AX_UPSAMPLE_STAGE_*\n\n\tsint32 AXSetDeviceUpsampleStage(sint32 device, int upsampleStage)\n\t{\n\t\tif (device != AX_DEV_TV && device != AX_DEV_DRC)\n\t\t\treturn -1;\n\t\t__AXDeviceUpsampleStage[device] = upsampleStage;\n\t\treturn 0;\n\t}\n\n\tsint32 AXGetDeviceUpsampleStage(sint32 device, uint32be* upsampleStage)\n\t{\n\t\tif (device != AX_DEV_TV && device != AX_DEV_DRC)\n\t\t\treturn -1;\n\t\t*upsampleStage = __AXDeviceUpsampleStage[device];\n\t\treturn 0;\n\t}\n\n\tsint32 AXGetInputSamplesPerFrame()\n\t{\n\t\tif (sndGeneric.initParam.rendererFreq == AX_RENDERER_FREQ_48KHZ)\n\t\t\treturn AX_SAMPLES_PER_3MS_48KHZ;\n\t\treturn AX_SAMPLES_PER_3MS_32KHZ;\n\t}\n\n\tsint32 AXGetInputSamplesPerSec()\n\t{\n\t\tsint32 samplesPerFrame = AXGetInputSamplesPerFrame();\n\t\tsint32 samplesPerSecond = (samplesPerFrame * 1000) / 3;\n\t\treturn samplesPerSecond;\n\t}\n\n\tstruct AXUpsampler\n\t{\n\t\tsint32 samples[AX_SAMPLES_MAX];\n\t};\n\n\tstruct\n\t{\n\t\tAXUpsampler upsamplerArray[6];\n\t\tbool useLinearUpsampler; // false -> FIR, true -> linear\n\t}__AXTVUpsampler;\n\n\tstruct\n\t{\n\t\tAXUpsampler upsamplerArray[4];\n\t\tbool useLinearUpsampler; // false -> FIR, true -> linear\n\t}__AXDRCUpsampler[2];\n\n\tvoid AXUpsampler_Init(AXUpsampler* upsampler)\n\t{\n\t\tmemset(upsampler, 0, sizeof(AXUpsampler));\n\t}\n\n\tstruct AXFINALMIXCBPARAM\n\t{\n\t\t/* +0x00 */ MEMPTR<MEMPTR<sint32>> data;\n\t\t/* +0x04 */ uint16be numChannelInput;\n\t\t/* +0x06 */ uint16be numSamples;\n\t\t/* +0x08 */ uint16be numDevices;\n\t\t/* +0x0A */ uint16be numChannelOutput;\n\t};\n\n\tstatic_assert(offsetof(AXFINALMIXCBPARAM, data) == 0x00);\n\tstatic_assert(offsetof(AXFINALMIXCBPARAM, numChannelInput) == 0x04);\n\tstatic_assert(offsetof(AXFINALMIXCBPARAM, numSamples) == 0x06);\n\tstatic_assert(offsetof(AXFINALMIXCBPARAM, numDevices) == 0x08);\n\tstatic_assert(offsetof(AXFINALMIXCBPARAM, numChannelOutput) == 0x0A);\n\n\tSysAllocator<AXFINALMIXCBPARAM> __AXFinalMixCBStructTV;\n\tSysAllocator<AXFINALMIXCBPARAM> __AXFinalMixCBStructDRC;\n\tSysAllocator<AXFINALMIXCBPARAM> __AXFinalMixCBStructRMT;\n\n\tSysAllocator<MEMPTR<sint32>, 6> __AXFinalMixCBStructTV_dataPtrArray;\n\tSysAllocator<MEMPTR<sint32>, 4 * 2> __AXFinalMixCBStructDRC_dataPtrArray;\n\n\tsint32 __AXFinalMixOutputChannelCount[AX_DEV_COUNT] = { 0 }; // number of output channels returned by final mix callback\n\n\t// callbacks\n\tMPTR __AXFrameCallback = MPTR_NULL; // set via AXRegisterFrameCallback()\n\tMPTR __AXAppFrameCallback[AX_APP_FRAME_CALLBACK_MAX];\n\tMPTR __AXDeviceFinalMixCallback[AX_DEV_COUNT];\n\tSysAllocator<coreinit::OSMutex, 1> __AXAppFrameCallbackMutex;\n\n\tvoid AXResetCallbacks()\n\t{\n\t\t__AXFrameCallback = MPTR_NULL;\n\t\tfor (sint32 i = 0; i < AX_APP_FRAME_CALLBACK_MAX; i++)\n\t\t{\n\t\t\t__AXAppFrameCallback[i] = MPTR_NULL;\n\t\t}\n\t\tcoreinit::OSInitMutexEx(__AXAppFrameCallbackMutex.GetPtr(), NULL);\n\t\tfor (sint32 i = 0; i < AX_DEV_COUNT; i++)\n\t\t\t__AXDeviceFinalMixCallback[i] = MPTR_NULL;\n\t}\n\n\tsint32 AXRegisterAppFrameCallback(MPTR funcAddr)\n\t{\n\t\tif (funcAddr == MPTR_NULL)\n\t\t\treturn -17;\n\t\tOSLockMutex(__AXAppFrameCallbackMutex.GetPtr());\n\t\tfor (sint32 i = 0; i < AX_APP_FRAME_CALLBACK_MAX; i++)\n\t\t{\n\t\t\tif (__AXAppFrameCallback[i] == MPTR_NULL)\n\t\t\t{\n\t\t\t\t__AXAppFrameCallback[i] = funcAddr;\n\t\t\t\tOSUnlockMutex(__AXAppFrameCallbackMutex.GetPtr());\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\tOSUnlockMutex(__AXAppFrameCallbackMutex.GetPtr());\n\t\treturn -15;\n\t}\n\n\tsint32 AXDeregisterAppFrameCallback(MPTR funcAddr)\n\t{\n\t\tif (funcAddr == MPTR_NULL)\n\t\t\treturn -17;\n\t\tOSLockMutex(__AXAppFrameCallbackMutex.GetPtr());\n\t\tfor (sint32 i = 0; i < AX_APP_FRAME_CALLBACK_MAX; i++)\n\t\t{\n\t\t\tif (__AXAppFrameCallback[i] == funcAddr)\n\t\t\t{\n\t\t\t\t__AXAppFrameCallback[i] = MPTR_NULL;\n\t\t\t\tOSUnlockMutex(__AXAppFrameCallbackMutex.GetPtr());\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\tOSUnlockMutex(__AXAppFrameCallbackMutex.GetPtr());\n\t\treturn -16; // not found\n\t}\n\n\tMPTR AXRegisterFrameCallback(MPTR funcAddr)\n\t{\n\t\tMPTR prevCallbackFunc = __AXFrameCallback;\n\t\t__AXFrameCallback = funcAddr;\n\t\treturn prevCallbackFunc;\n\t}\n\n\tsint32 __AXTVUpsamplerSampleHistory[AX_TV_CHANNEL_COUNT] = { 0 };\n\tsint32 __AXDRC0UpsamplerSampleHistory[AX_DRC_CHANNEL_COUNT] = { 0 };\n\tsint32 __AXDRC1UpsamplerSampleHistory[AX_DRC_CHANNEL_COUNT] = { 0 };\n\n\tvoid AXIst_Init()\n\t{\n\t\t// todo - double check defaults\n\t\t__AXDeviceUpsampleStage[AX_DEV_TV] = AX_UPSAMPLE_STAGE_BEFORE_FINALMIX;\n\t\t__AXDeviceUpsampleStage[AX_DEV_DRC] = AX_UPSAMPLE_STAGE_BEFORE_FINALMIX;\n\t\t__AXDeviceUpsampleStage[AX_DEV_RMT] = AX_UPSAMPLE_STAGE_BEFORE_FINALMIX;\n\t\tfor (sint32 i = 0; i < AX_TV_CHANNEL_COUNT; i++)\n\t\t\tAXUpsampler_Init(__AXTVUpsampler.upsamplerArray + i);\n\t\tfor (sint32 i = 0; i < AX_DRC_CHANNEL_COUNT; i++)\n\t\t{\n\t\t\tAXUpsampler_Init(__AXDRCUpsampler[0].upsamplerArray + i);\n\t\t\tAXUpsampler_Init(__AXDRCUpsampler[1].upsamplerArray + i);\n\t\t}\n\t\t__AXTVUpsampler.useLinearUpsampler = false;\n\t\t__AXDRCUpsampler[0].useLinearUpsampler = false;\n\t\t__AXDRCUpsampler[1].useLinearUpsampler = false;\n\t\tmemset(__AXTVUpsamplerSampleHistory, 0, sizeof(__AXTVUpsamplerSampleHistory));\n\t\tmemset(__AXDRC0UpsamplerSampleHistory, 0, sizeof(__AXDRC0UpsamplerSampleHistory));\n\t\tmemset(__AXDRC1UpsamplerSampleHistory, 0, sizeof(__AXDRC1UpsamplerSampleHistory));\n\t\tAXResetCallbacks();\n\t}\n\n\tvoid AXOut_ResetFinalMixCBData()\n\t{\n\t\tsint32 inputSamplesPerFrame = AXGetInputSamplesPerFrame();\n\t\t// TV\n\t\t__AXFinalMixCBStructTV->data = nullptr;\n\t\t__AXFinalMixCBStructTV->numChannelInput = 6;\n\t\t__AXFinalMixCBStructTV->numChannelOutput = 6;\n\t\t__AXFinalMixCBStructTV->numSamples = inputSamplesPerFrame;\n\t\t__AXFinalMixCBStructTV->numDevices = 1;\n\t\t// DRC\n\t\t__AXFinalMixCBStructDRC->data = nullptr;\n\t\t__AXFinalMixCBStructDRC->numChannelInput = 4;\n\t\t__AXFinalMixCBStructDRC->numChannelOutput = 4;\n\t\t__AXFinalMixCBStructDRC->numSamples = inputSamplesPerFrame;\n\t\t__AXFinalMixCBStructDRC->numDevices = 2;\n\t\t// RMT\n\t\t__AXFinalMixCBStructRMT->data = nullptr;\n\t\t__AXFinalMixCBStructRMT->numChannelInput = 1;\n\t\t__AXFinalMixCBStructRMT->numChannelOutput = 1;\n\t\t__AXFinalMixCBStructRMT->numSamples = 18; // verify\n\t\t__AXFinalMixCBStructRMT->numDevices = 4;\n\t}\n\n\tsint32 AXGetDeviceFinalMixCallback(sint32 device, uint32be* funcAddrPtr)\n\t{\n\t\tif (device != AX_DEV_TV && device != AX_DEV_DRC)\n\t\t\treturn -1;\n\t\t*funcAddrPtr = __AXDeviceFinalMixCallback[device];\n\t\treturn 0;\n\t}\n\n\tsint32 AXRegisterDeviceFinalMixCallback(sint32 device, MPTR funcAddr)\n\t{\n\t\tif (device != AX_DEV_TV && device != AX_DEV_DRC)\n\t\t\treturn -1;\n\t\t__AXDeviceFinalMixCallback[device] = funcAddr;\n\t\treturn 0;\n\t}\n\n\n\tSysAllocator<AXRemixMatrices_t, 12> g_remix_matrices;\n\n\tsint32 AXSetDeviceRemixMatrix(sint32 deviceId, uint32 inputChannelCount, uint32 outputChannelCount, const MEMPTR<float32be>& matrix)\n\t{\n\t\t// validate parameters\n\t\tif (deviceId == AX_DEV_TV)\n\t\t{\n\t\t\tif(inputChannelCount > AX_TV_CHANNEL_COUNT)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::APIErrors, \"AXSetDeviceRemixMatrix: Input channel count must be smaller or equal to 6 for TV device\");\n\t\t\t\treturn -7;\n\t\t\t}\n\t\t\tif(outputChannelCount != 1 && outputChannelCount != 2 && outputChannelCount != 6)\n\t\t\t{\n\t\t\t\t// seems like Watch Dogs uses 4 as outputChannelCount for some reason?\n\t\t\t\tcemuLog_log(LogType::APIErrors, \"AXSetDeviceRemixMatrix: Output channel count must be 1, 2 or 6 for TV device\");\n\t\t\t\treturn -8;\n\t\t\t}\n\t\t}\n\t\telse if (deviceId == AX_DEV_DRC)\n\t\t{\n\t\t\tif(inputChannelCount > AX_DRC_CHANNEL_COUNT)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::APIErrors, \"AXSetDeviceRemixMatrix: Input channel count must be smaller or equal to 4 for DRC device\");\n\t\t\t\treturn -7;\n\t\t\t}\n\t\t\tif(outputChannelCount != 1 && outputChannelCount != 2 && outputChannelCount != 4)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::APIErrors, \"AXSetDeviceRemixMatrix: Output channel count must be 1, 2 or 4 for DRC device\");\n\t\t\t\treturn -8;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::APIErrors, \"AXSetDeviceRemixMatrix: Only TV (0) and DRC (1) device are supported\");\n\t\t\treturn -1;\n\t\t}\n\t\tauto matrices = g_remix_matrices.GetPtr();\n\n\t\t// test if we already have an entry and just need to update the matrix data\n\t\tfor (uint32 i = 0; i < g_remix_matrices.GetCount(); ++i)\n\t\t{\n\t\t\tif (g_remix_matrices[i].deviceEntry[deviceId].channelIn == inputChannelCount && g_remix_matrices[i].deviceEntry[deviceId].channelOut == outputChannelCount)\n\t\t\t{\n\t\t\t\tg_remix_matrices[i].deviceEntry[deviceId].matrix = matrix;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\t// add new entry\n\t\tfor (uint32 i = 0; i < g_remix_matrices.GetCount(); ++i)\n\t\t{\n\t\t\tif (g_remix_matrices[i].deviceEntry[deviceId].channelIn == 0 && g_remix_matrices[i].deviceEntry[deviceId].channelOut == 0)\n\t\t\t{\n\t\t\t\tg_remix_matrices[i].deviceEntry[deviceId].channelIn = inputChannelCount;\n\t\t\t\tg_remix_matrices[i].deviceEntry[deviceId].channelOut = outputChannelCount;\n\t\t\t\tg_remix_matrices[i].deviceEntry[deviceId].matrix = matrix;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\treturn -9;\n\t}\n\n\tsint32 AXGetDeviceRemixMatrix(uint32 deviceId, uint32 inputChannelCount, uint32 outputChannelCount, MEMPTR<MEMPTR<float32be>>& matrix)\n\t{\n\t\t// validate parameters\n\t\tif (deviceId == AX_DEV_TV)\n\t\t{\n\t\t\tcemu_assert(inputChannelCount <= AX_TV_CHANNEL_COUNT);\n\t\t\tcemu_assert(outputChannelCount == 2 || outputChannelCount == 6);\n\t\t}\n\t\telse if (deviceId == AX_DEV_DRC)\n\t\t{\n\t\t\tcemu_assert(inputChannelCount <= AX_DRC_CHANNEL_COUNT);\n\t\t\tcemu_assert(outputChannelCount == 1 || outputChannelCount == 2);\n\t\t}\n\t\telse if (deviceId == AX_DEV_RMT)\n\t\t{\n\t\t\tcemu_assert(false);\n\t\t}\n\t\telse\n\t\t\treturn -1;\n\n\t\tfor (uint32 i = 0; i < g_remix_matrices.GetCount(); ++i)\n\t\t{\n\t\t\tif (g_remix_matrices[i].deviceEntry[deviceId].channelIn == inputChannelCount && g_remix_matrices[i].deviceEntry[deviceId].channelOut == outputChannelCount)\n\t\t\t{\n\t\t\t\t*matrix = g_remix_matrices[i].deviceEntry[deviceId].matrix;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\treturn -10;\n\t}\n\n\tSysAllocator<sint32, AX_SAMPLES_MAX * AX_TV_CHANNEL_COUNT> __AXTVOutputBuffer;\n\tSysAllocator<sint32, AX_SAMPLES_MAX * AX_DRC_CHANNEL_COUNT * 2> __AXDRCOutputBuffer;\n\n\tSysAllocator<sint32, AX_SAMPLES_MAX * AX_TV_CHANNEL_COUNT> __AXTempFinalMixTVBuffer;\n\tSysAllocator<sint32, AX_SAMPLES_MAX * AX_DRC_CHANNEL_COUNT * 2> __AXTempFinalMixDRCBuffer;\n\n\t// 48KHz buffers\n\tSysAllocator<sint32, AX_SAMPLES_MAX * AX_TV_CHANNEL_COUNT> __AXTVBuffer48;\n\tSysAllocator<sint32, AX_SAMPLES_MAX * AX_DRC_CHANNEL_COUNT * 2> __AXDRCBuffer48;\n\n\tsint32 AXUpsampleLinear32To48(sint32* inputBuffer, sint32* outputBuffer, sint32* sampleHistory, sint32 sampleCount, bool shiftSamples, sint32 channelCount)\n\t{\n\t\tif (shiftSamples)\n\t\t{\n\t\t\tfor (sint32 c = 0; c < channelCount; c++)\n\t\t\t{\n\t\t\t\tfloat samplePrev = (float)sampleHistory[c];\n\t\t\t\tfor (sint32 i = 0; i < sampleCount; i += 2)\n\t\t\t\t{\n\t\t\t\t\tfloat sample0 = (float)_swapEndianS32(inputBuffer[0]);\n\t\t\t\t\tfloat sample1 = (float)_swapEndianS32(inputBuffer[1]);\n\n\t\t\t\t\tinputBuffer += 2;\n\t\t\t\t\tfloat s0 = samplePrev * 0.66666669f + sample0 * 0.33333331f;\n\t\t\t\t\tfloat s1 = sample0;\n\t\t\t\t\tfloat s2 = sample1 * 0.66666669f + sample0 * 0.33333331f;\n\t\t\t\t\toutputBuffer[0] = _swapEndianS32(((sint32)s0) >> 8);\n\t\t\t\t\toutputBuffer[1] = _swapEndianS32(((sint32)s1) >> 8);\n\t\t\t\t\toutputBuffer[2] = _swapEndianS32(((sint32)s2) >> 8);\n\t\t\t\t\toutputBuffer += 3;\n\t\t\t\t\tsamplePrev = sample1;\n\t\t\t\t}\n\t\t\t\tsampleHistory[c] = (sint32)samplePrev;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (sint32 c = 0; c < channelCount; c++)\n\t\t\t{\n\t\t\t\tfloat samplePrev = (float)sampleHistory[c];\n\t\t\t\tfor (sint32 i = 0; i < sampleCount; i += 2)\n\t\t\t\t{\n\t\t\t\t\tfloat sample0 = (float)_swapEndianS32(inputBuffer[0]);\n\t\t\t\t\tfloat sample1 = (float)_swapEndianS32(inputBuffer[1]);\n\t\t\t\t\tinputBuffer += 2;\n\t\t\t\t\tfloat s0 = samplePrev * 0.66666669f + sample0 * 0.33333331f;\n\t\t\t\t\tfloat s1 = sample0;\n\t\t\t\t\tfloat s2 = sample1 * 0.66666669f + sample0 * 0.33333331f;\n\t\t\t\t\toutputBuffer[0] = _swapEndianS32(((sint32)s0));\n\t\t\t\t\toutputBuffer[1] = _swapEndianS32(((sint32)s1));\n\t\t\t\t\toutputBuffer[2] = _swapEndianS32(((sint32)s2));\n\t\t\t\t\toutputBuffer += 3;\n\t\t\t\t\tsamplePrev = sample1;\n\t\t\t\t}\n\t\t\t\tsampleHistory[c] = (sint32)samplePrev;\n\t\t\t}\n\t\t}\n\t\treturn (sampleCount / 2) * 3;\n\t}\n\n\tvoid AXTransferSamples(sint32* input, sint32* output, sint32 count, bool shiftSamples)\n\t{\n\t\tif (shiftSamples)\n\t\t{\n\t\t\tfor (sint32 i = 0; i < count; i++)\n\t\t\t{\n\t\t\t\tsint32 s = _swapEndianS32(input[i]);\n\t\t\t\ts >>= 8;\n\t\t\t\toutput[i] = _swapEndianS32(s);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (sint32 i = 0; i < count; i++)\n\t\t\t\toutput[i] = input[i];\n\t\t}\n\t}\n\n\tvoid AXIst_ProcessFinalMixCallback()\n\t{\n\t\tbool forceLinearUpsampler = true;\n\t\tbool isRenderer48 = sndGeneric.initParam.rendererFreq == AX_RENDERER_FREQ_48KHZ;\n\t\tsint32 inputSampleCount = AXGetInputSamplesPerFrame();\n\t\t// TV\n\t\tif (isRenderer48 || __AXDeviceUpsampleStage[AX_DEV_TV] != AX_UPSAMPLE_STAGE_BEFORE_FINALMIX)\n\t\t{\n\t\t\t// only copy\n\t\t\tsint32* inputBuffer = __AXTVOutputBuffer;\n\t\t\tsint32* outputBuffer = __AXTempFinalMixTVBuffer.GetPtr();\n\t\t\tsint32 sampleCount = inputSampleCount * AX_TV_CHANNEL_COUNT;\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t{\n\t\t\t\tsint32 sample0 = _swapEndianS32(inputBuffer[0]);\n\t\t\t\tsample0 >>= 8;\n\t\t\t\tinputBuffer++;\n\t\t\t\t*outputBuffer = _swapEndianS32(sample0);\n\t\t\t\toutputBuffer++;\n\t\t\t}\n\t\t\tfor (sint32 c = 0; c < AX_TV_CHANNEL_COUNT; c++)\n\t\t\t{\n\t\t\t\t__AXFinalMixCBStructTV_dataPtrArray[c] = __AXTempFinalMixTVBuffer.GetPtr() + c * inputSampleCount;\n\t\t\t}\n\t\t\t__AXFinalMixCBStructTV->numSamples = (uint16)inputSampleCount;\n\t\t\t__AXFinalMixCBStructTV->data = __AXFinalMixCBStructTV_dataPtrArray.GetPtr();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// upsample\n\t\t\tsint32 upsampledSampleCount;\n\t\t\tif (__AXTVUpsampler.useLinearUpsampler || forceLinearUpsampler)\n\t\t\t{\n\t\t\t\tupsampledSampleCount = AXUpsampleLinear32To48(__AXTVOutputBuffer, __AXTVBuffer48.GetPtr(), __AXTVUpsamplerSampleHistory, inputSampleCount, true, AX_TV_CHANNEL_COUNT);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert(false); // todo\n\t\t\t}\n\t\t\tfor (sint32 c = 0; c < AX_TV_CHANNEL_COUNT; c++)\n\t\t\t{\n\t\t\t\t__AXFinalMixCBStructTV_dataPtrArray[c] = __AXTVBuffer48.GetPtr() + c * upsampledSampleCount;\n\t\t\t}\n\t\t\t__AXFinalMixCBStructTV->numSamples = (uint16)upsampledSampleCount;\n\t\t\t__AXFinalMixCBStructTV->data = __AXFinalMixCBStructTV_dataPtrArray.GetPtr();\n\t\t}\n\t\t// DRC\n\t\tif (isRenderer48 || __AXDeviceUpsampleStage[AX_DEV_DRC] != AX_UPSAMPLE_STAGE_BEFORE_FINALMIX)\n\t\t{\n\t\t\t// only copy\n\t\t\tsint32* inputBuffer = __AXDRCOutputBuffer;\n\t\t\tsint32* outputBuffer = __AXTempFinalMixDRCBuffer.GetPtr();\n\t\t\tsint32 sampleCount = inputSampleCount * AX_DRC_CHANNEL_COUNT * 2;\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t{\n\t\t\t\tsint32 sample0 = _swapEndianS32(inputBuffer[0]);\n\t\t\t\tsample0 >>= 8;\n\t\t\t\tinputBuffer++;\n\t\t\t\t*outputBuffer = _swapEndianS32(sample0);\n\t\t\t\toutputBuffer++;\n\t\t\t}\n\t\t\tfor (sint32 c = 0; c < AX_DRC_CHANNEL_COUNT*2; c++)\n\t\t\t{\n\t\t\t\t__AXFinalMixCBStructDRC_dataPtrArray[c] = __AXTempFinalMixDRCBuffer.GetPtr() + c * inputSampleCount;\n\t\t\t}\n\t\t\t__AXFinalMixCBStructDRC->numSamples = (uint16)inputSampleCount;\n\t\t\t__AXFinalMixCBStructDRC->data = __AXFinalMixCBStructDRC_dataPtrArray.GetPtr();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// upsample\n\t\t\tsint32 upsampledSampleCount;\n\t\t\t// DRC0\n\t\t\tif (__AXDRCUpsampler[0].useLinearUpsampler || forceLinearUpsampler)\n\t\t\t\tupsampledSampleCount = AXUpsampleLinear32To48(__AXDRCOutputBuffer, __AXDRCBuffer48.GetPtr(), __AXDRC0UpsamplerSampleHistory, inputSampleCount, true, AX_DRC_CHANNEL_COUNT);\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert(false); // todo\n\t\t\t}\n\t\t\t// DRC1\n\t\t\tif (__AXDRCUpsampler[1].useLinearUpsampler || forceLinearUpsampler)\n\t\t\t\tupsampledSampleCount = AXUpsampleLinear32To48(__AXDRCOutputBuffer + (upsampledSampleCount*AX_DRC_CHANNEL_COUNT), __AXDRCBuffer48.GetPtr()+inputSampleCount*AX_DRC_CHANNEL_COUNT, __AXDRC1UpsamplerSampleHistory, inputSampleCount, true, AX_DRC_CHANNEL_COUNT);\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert(false); // todo\n\t\t\t}\n\t\t\tfor (sint32 c = 0; c < AX_DRC_CHANNEL_COUNT * 2; c++)\n\t\t\t\t__AXFinalMixCBStructDRC_dataPtrArray[c] = __AXDRCBuffer48.GetPtr() + c * upsampledSampleCount;\n\t\t\t__AXFinalMixCBStructDRC->numSamples = (uint16)upsampledSampleCount;\n\t\t\t__AXFinalMixCBStructDRC->data = __AXFinalMixCBStructDRC_dataPtrArray.GetPtr();\n\t\t}\n\t\t\n\n\t\t// do callbacks\n\t\t__AXFinalMixOutputChannelCount[0] = AX_TV_CHANNEL_COUNT;\n\t\t__AXFinalMixOutputChannelCount[1] = AX_DRC_CHANNEL_COUNT;\n\t\t__AXFinalMixOutputChannelCount[2] = AX_RMT_CHANNEL_COUNT;\n\t\tfor (sint32 i = 0; i < AX_DEV_COUNT; i++)\n\t\t{\n\t\t\tif (__AXDeviceFinalMixCallback[i] == MPTR_NULL)\n\t\t\t\tcontinue;\n\t\t\tMEMPTR<AXFINALMIXCBPARAM> cbStruct;\n\t\t\tif (i == AX_DEV_TV)\n\t\t\t\tcbStruct = &__AXFinalMixCBStructTV;\n\t\t\telse if (i == AX_DEV_DRC)\n\t\t\t\tcbStruct = &__AXFinalMixCBStructDRC;\n\t\t\telse if (i == AX_DEV_RMT)\n\t\t\t\tcbStruct = &__AXFinalMixCBStructRMT;\n\n\t\t\tif (i == 2 && __AXDeviceFinalMixCallback[i])\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false); // RMT callbacks need testing\n\t\t\t}\n\n\t\t\tPPCCoreCallback(__AXDeviceFinalMixCallback[i], cbStruct);\n\t\t\t__AXFinalMixOutputChannelCount[i] = (sint32)cbStruct->numChannelOutput;\n\t\t}\n\n\t\t// handle upsampling\n\t\tif (isRenderer48)\n\t\t{\n\t\t\t// copy TV\n\t\t\tAXTransferSamples(__AXTempFinalMixTVBuffer.GetPtr(), __AXTVBuffer48.GetPtr(), AX_SAMPLES_PER_3MS_48KHZ*AX_TV_CHANNEL_COUNT, false);\n\t\t\t// copy DRC 0\n\t\t\tAXTransferSamples(__AXTempFinalMixDRCBuffer.GetPtr(), __AXDRCBuffer48.GetPtr(), AX_SAMPLES_PER_3MS_48KHZ*AX_DRC_CHANNEL_COUNT, false);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (__AXDeviceUpsampleStage[AX_DEV_TV] == AX_UPSAMPLE_STAGE_BEFORE_FINALMIX)\n\t\t\t{\n\t\t\t\t// final mix is 48KHz\n\t\t\t\t// no need to copy since samples are already in right buffer\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// final mix is 32KHz -> upsample\n\t\t\t\t// TV\n\t\t\t\tsint32 upsampledSampleCount;\n\t\t\t\tif (__AXTVUpsampler.useLinearUpsampler || forceLinearUpsampler)\n\t\t\t\t{\n\t\t\t\t\tupsampledSampleCount = AXUpsampleLinear32To48(__AXTempFinalMixTVBuffer.GetPtr(), __AXTVBuffer48.GetPtr(), __AXTVUpsamplerSampleHistory, inputSampleCount, false, AX_TV_CHANNEL_COUNT);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemu_assert(false);\n\t\t\t\t}\n\t\t\t\t// DRC0\n\t\t\t\tif (__AXDRCUpsampler[0].useLinearUpsampler || forceLinearUpsampler)\n\t\t\t\t{\n\t\t\t\t\tAXUpsampleLinear32To48(__AXTempFinalMixDRCBuffer.GetPtr(), __AXDRCBuffer48.GetPtr(), __AXDRC0UpsamplerSampleHistory, inputSampleCount, false, AX_DRC_CHANNEL_COUNT);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemu_assert(false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid AXIst_SyncSingleVPB(AXVPB* vpb)\n\t{\n\t\tuint32 index = vpb->index;\n\t\tuint32 sync = vpb->sync;\n\t\tAXVPBInternal_t* internalVPB = __AXVPBInternalVoiceArray + index;\n\t\tAXVPBInternal_t* internalShadowCopy = __AXVPBInternalVoiceShadowCopyArrayPtr + index;\n\n\t\t// shadow copy -> internal data\n\t\tinternalShadowCopy->nextAddrHigh = internalVPB->nextAddrHigh;\n\t\tinternalShadowCopy->nextAddrLow = internalVPB->nextAddrLow;\n\t\tif (internalVPB->nextToProcess != nullptr)\n\t\t\tinternalShadowCopy->nextToProcess = __AXVPBInternalVoiceShadowCopyArrayPtr + (sint32)internalVPB->nextToProcess->index;\n\t\telse\n\t\t\tinternalShadowCopy->nextToProcess = nullptr;\n\n\t\tinternalShadowCopy->mixerSelect = internalVPB->mixerSelect;\n\n\t\tinternalShadowCopy->ukn2A2 = internalVPB->ukn2A2;\n\n\t\tinternalShadowCopy->reserved296 = internalVPB->reserved296;\n\t\tinternalShadowCopy->reserved298 = internalVPB->reserved298;\n\t\tinternalShadowCopy->reserved29A = internalVPB->reserved29A;\n\t\tinternalShadowCopy->reserved29C = internalVPB->reserved29C;\n\t\tinternalShadowCopy->reserved29E = internalVPB->reserved29E;\n\n\t\t// sync current playback state\n\t\tif ((sync&AX_SYNCFLAG_PLAYBACKSTATE) == 0)\n\t\t{\n\t\t\tuint32 playbackState = _swapEndianU16(internalShadowCopy->playbackState);\n\t\t\tvpb->playbackState = playbackState;\n\t\t\tinternalVPB->playbackState = _swapEndianU16(playbackState);\n\t\t}\n\t\t// sync current offset\n\t\tif ((sync&(AX_SYNCFLAG_CURRENTOFFSET | AX_SYNCFLAG_OFFSETS)) == 0)\n\t\t{\n\t\t\tinternalVPB->internalOffsets.currentOffsetPtrHigh = internalShadowCopy->internalOffsets.currentOffsetPtrHigh;\n\t\t\tinternalVPB->internalOffsets.currentOffsetPtrLow = internalShadowCopy->internalOffsets.currentOffsetPtrLow;\n\t\t}\n\t\t// sync volume\n\t\tif ((sync&AX_SYNCFLAG_VE) == 0)\n\t\t{\n\t\t\tinternalVPB->veVolume = internalShadowCopy->veVolume;\n\t\t}\n\t\t// sync adpcm data\n\t\tif ((sync&AX_SYNCFLAG_ADPCMDATA) == 0)\n\t\t{\n\t\t\tfor (sint32 i = 0; i < 16; i++)\n\t\t\t\tinternalVPB->adpcmData.coef[i] = internalShadowCopy->adpcmData.coef[i];\n\t\t\tinternalVPB->adpcmData.gain = internalShadowCopy->adpcmData.gain;\n\t\t\tinternalVPB->adpcmData.scale = internalShadowCopy->adpcmData.scale;\n\t\t\tinternalVPB->adpcmData.yn1 = internalShadowCopy->adpcmData.yn1;\n\t\t\tinternalVPB->adpcmData.yn2 = internalShadowCopy->adpcmData.yn2;\n\t\t}\n\t\t// sync src data\n\t\tif ((sync&AX_SYNCFLAG_SRCDATA) == 0)\n\t\t{\n\t\t\tinternalVPB->src.currentFrac = internalShadowCopy->src.currentFrac;\n\t\t\tinternalVPB->src.historySamples[0] = internalShadowCopy->src.historySamples[0];\n\t\t\tinternalVPB->src.historySamples[1] = internalShadowCopy->src.historySamples[1];\n\t\t\tinternalVPB->src.historySamples[2] = internalShadowCopy->src.historySamples[2];\n\t\t\tinternalVPB->src.historySamples[3] = internalShadowCopy->src.historySamples[3];\n\t\t}\n\t\tif (AXVoiceProtection_IsProtectedByAnyThread(vpb))\n\t\t{\n\t\t\t// if voice is currently protected, dont sync remaining flags\n\t\t\treturn;\n\t\t}\n\t\t// internal data -> shadow copy\n\t\t// sync src type\n\t\tif ((sync&AX_SYNCFLAG_SRCFILTER) != 0)\n\t\t{\n\t\t\tinternalShadowCopy->srcFilterMode = internalVPB->srcFilterMode;\n\t\t\tinternalShadowCopy->srcTapFilter = internalVPB->srcTapFilter;\n\t\t}\n\t\t// Sync device mix\n\t\tif ((sync&AX_SYNCFLAG_DEVICEMIXMASK) != 0)\n\t\t{\n\t\t\tmemcpy(internalShadowCopy->deviceMixMaskTV, internalVPB->deviceMixMaskTV, 8);\n\t\t\tmemcpy(internalShadowCopy->deviceMixMaskDRC, internalVPB->deviceMixMaskDRC, 0x10);\n\t\t\tmemcpy(internalShadowCopy->deviceMixMaskRMT, internalVPB->deviceMixMaskRMT, 0x20);\n\t\t}\n\t\t// sync device mix\n\t\tif ((sync & AX_SYNCFLAG_DEVICEMIX) != 0)\n\t\t{\n\t\t\tmemcpy(internalShadowCopy->deviceMixTV, internalVPB->deviceMixTV, 0x60);\n\t\t\tmemcpy(internalShadowCopy->deviceMixDRC, internalVPB->deviceMixDRC, 0x80);\n\t\t\tmemcpy(internalShadowCopy->deviceMixRMT, internalVPB->deviceMixRMT, 0x40);\n\t\t}\n\t\t// sync playback state\n\t\tif ((sync&AX_SYNCFLAG_PLAYBACKSTATE) != 0)\n\t\t{\n\t\t\tinternalShadowCopy->playbackState = internalVPB->playbackState;\n\t\t}\n\t\t// sync voice type\n\t\tif ((sync&AX_SYNCFLAG_VOICETYPE) != 0)\n\t\t{\n\t\t\tinternalShadowCopy->voiceType = internalVPB->voiceType;\n\t\t}\n\t\t// itd\n\t\tif ((sync&AX_SYNCFLAG_ITD40) == 0)\n\t\t{\n\t\t\tif ((sync&AX_SYNCFLAG_ITD20) != 0)\n\t\t\t{\n\t\t\t\t//cemu_assert_debug(false); // sync PB itd\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// sync itd\n\t\t\tinternalShadowCopy->reserved176_itdRelated = internalVPB->reserved176_itdRelated;\n\t\t\tinternalShadowCopy->reserved178_itdRelated = internalVPB->reserved178_itdRelated;\n\t\t}\n\t\t// sync volume envelope\n\t\t// the part below could be incorrect (it seems strange that the delta flag overwrites the full ve flag? But PPC code looks like this)\n\t\tif ((sync&AX_SYNCFLAG_VEDELTA) != 0)\n\t\t{\n\t\t\tinternalShadowCopy->veDelta = internalVPB->veDelta;\n\t\t}\n\t\telse if ((sync&AX_SYNCFLAG_VE) != 0)\n\t\t{\n\t\t\tinternalShadowCopy->veVolume = internalVPB->veVolume;\n\t\t\tinternalShadowCopy->veDelta = internalVPB->veDelta;\n\t\t}\n\t\t// sync offsets\n\t\tif ((sync&AX_SYNCFLAG_OFFSETS) != 0)\n\t\t{\n\t\t\t// sync entire offsets block\n\t\t\tmemcpy(&internalShadowCopy->internalOffsets, &internalVPB->internalOffsets, sizeof(axOffsetsInternal_t));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// sync individual offset fields\n\t\t\tif ((sync&AX_SYNCFLAG_LOOPFLAG) != 0)\n\t\t\t{\n\t\t\t\t// sync loop flag\n\t\t\t\tinternalShadowCopy->internalOffsets.loopFlag = internalVPB->internalOffsets.loopFlag;\n\t\t\t}\n\t\t\tif ((sync&AX_SYNCFLAG_LOOPOFFSET) != 0)\n\t\t\t{\n\t\t\t\t// sync loop offset\n\t\t\t\tinternalShadowCopy->internalOffsets.loopOffsetPtrLow = internalVPB->internalOffsets.loopOffsetPtrLow;\n\t\t\t\tinternalShadowCopy->internalOffsets.loopOffsetPtrHigh = internalVPB->internalOffsets.loopOffsetPtrHigh;\n\t\t\t}\n\t\t\tif ((sync&AX_SYNCFLAG_ENDOFFSET) != 0)\n\t\t\t{\n\t\t\t\t// sync end offset\n\t\t\t\tinternalShadowCopy->internalOffsets.endOffsetPtrLow = internalVPB->internalOffsets.endOffsetPtrLow;\n\t\t\t\tinternalShadowCopy->internalOffsets.endOffsetPtrHigh = internalVPB->internalOffsets.endOffsetPtrHigh;\n\t\t\t}\n\t\t\tif ((sync&AX_SYNCFLAG_CURRENTOFFSET) != 0)\n\t\t\t{\n\t\t\t\t// sync current offset\n\t\t\t\tinternalShadowCopy->internalOffsets.currentOffsetPtrLow = internalVPB->internalOffsets.currentOffsetPtrLow;\n\t\t\t\tinternalShadowCopy->internalOffsets.currentOffsetPtrHigh = internalVPB->internalOffsets.currentOffsetPtrHigh;\n\t\t\t}\n\t\t}\n\t\tif ((sync&AX_SYNCFLAG_ADPCMDATA) != 0)\n\t\t{\n\t\t\t// sync adpcm data\n\t\t\tfor (sint32 i = 0; i < 16; i++)\n\t\t\t\tinternalShadowCopy->adpcmData.coef[i] = internalVPB->adpcmData.coef[i];\n\t\t\tinternalShadowCopy->adpcmData.gain = internalVPB->adpcmData.gain;\n\t\t\tinternalShadowCopy->adpcmData.scale = internalVPB->adpcmData.scale;\n\t\t}\n\t\tif ((sync&AX_SYNCFLAG_SRCDATA) != 0)\n\t\t{\n\t\t\t// sync voice all src data\n\t\t\tinternalShadowCopy->src.ratioHigh = internalVPB->src.ratioHigh;\n\t\t\tinternalShadowCopy->src.ratioLow = internalVPB->src.ratioLow;\n\t\t\tinternalShadowCopy->src.currentFrac = internalVPB->src.currentFrac;\n\t\t\tinternalShadowCopy->src.historySamples[0] = internalVPB->src.historySamples[0];\n\t\t\tinternalShadowCopy->src.historySamples[1] = internalVPB->src.historySamples[1];\n\t\t\tinternalShadowCopy->src.historySamples[2] = internalVPB->src.historySamples[2];\n\t\t\tinternalShadowCopy->src.historySamples[3] = internalVPB->src.historySamples[3];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((sync&AX_SYNCFLAG_SRCRATIO) != 0)\n\t\t\t{\n\t\t\t\t// sync voice src ratio\n\t\t\t\tinternalShadowCopy->src.ratioHigh = internalVPB->src.ratioHigh;\n\t\t\t\tinternalShadowCopy->src.ratioLow = internalVPB->src.ratioLow;\n\t\t\t}\n\t\t}\n\t\tif ((sync&AX_SYNCFLAG_ADPCMLOOP) != 0)\n\t\t{\n\t\t\t// sync voice adpcm loop\n\t\t\tinternalShadowCopy->adpcmLoop.loopScale = internalVPB->adpcmLoop.loopScale;\n\t\t\tinternalShadowCopy->adpcmLoop.loopYn1 = internalVPB->adpcmLoop.loopYn1;\n\t\t\tinternalShadowCopy->adpcmLoop.loopYn2 = internalVPB->adpcmLoop.loopYn2;\n\t\t}\n\t\tif ((sync&AX_SYNCFLAG_LPFCOEF) != 0)\n\t\t{\n\t\t\t// sync lpf coef\n\t\t\tinternalShadowCopy->lpf.a0 = internalVPB->lpf.a0;\n\t\t\tinternalShadowCopy->lpf.b0 = internalVPB->lpf.b0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((sync&AX_SYNCFLAG_LPFDATA) != 0)\n\t\t\t{\n\t\t\t\t// sync lpf\n\t\t\t\tinternalShadowCopy->lpf.on = internalVPB->lpf.on;\n\t\t\t\tinternalShadowCopy->lpf.yn1 = internalVPB->lpf.yn1;\n\t\t\t\tinternalShadowCopy->lpf.a0 = internalVPB->lpf.a0;\n\t\t\t\tinternalShadowCopy->lpf.b0 = internalVPB->lpf.b0;\n\t\t\t}\n\t\t}\n\t\tif ((sync&AX_SYNCFLAG_BIQUADCOEF) != 0)\n\t\t{\n\t\t\t// sync biquad coef\n\t\t\tinternalShadowCopy->biquad.b0 = internalVPB->biquad.b0;\n\t\t\tinternalShadowCopy->biquad.b1 = internalVPB->biquad.b1;\n\t\t\tinternalShadowCopy->biquad.b2 = internalVPB->biquad.b2;\n\t\t\tinternalShadowCopy->biquad.a1 = internalVPB->biquad.a1;\n\t\t\tinternalShadowCopy->biquad.a2 = internalVPB->biquad.a2;\n\t\t}\n\t\telse if ((sync&AX_SYNCFLAG_BIQUADDATA) != 0)\n\t\t{\n\t\t\t// sync biquad\n\t\t\tinternalShadowCopy->biquad.on = internalVPB->biquad.on;\n\t\t\tinternalShadowCopy->biquad.xn1 = internalVPB->biquad.xn1;\n\t\t\tinternalShadowCopy->biquad.xn2 = internalVPB->biquad.xn2;\n\t\t\tinternalShadowCopy->biquad.yn1 = internalVPB->biquad.yn1;\n\t\t\tinternalShadowCopy->biquad.yn2 = internalVPB->biquad.yn2;\n\t\t\tinternalShadowCopy->biquad.b0 = internalVPB->biquad.b0;\n\t\t\tinternalShadowCopy->biquad.b1 = internalVPB->biquad.b1;\n\t\t\tinternalShadowCopy->biquad.b2 = internalVPB->biquad.b2;\n\t\t\tinternalShadowCopy->biquad.a1 = internalVPB->biquad.a1;\n\t\t\tinternalShadowCopy->biquad.a2 = internalVPB->biquad.a2;\n\t\t}\n\t\tif ((sync&AX_SYNCFLAG_VOICEREMOTEON) != 0)\n\t\t{\n\t\t\t// sync VoiceRmtOn (AXSetVoiceRmtOn)\n\t\t\tinternalShadowCopy->reserved148_voiceRmtOn = internalVPB->reserved148_voiceRmtOn;\n\t\t}\n\t\tif ((sync&AX_SYNCFLAG_4000000) != 0)\n\t\t{\n\t\t\t// todo\n\t\t}\n\t\tif ((sync&AX_SYNCFLAG_8000000) != 0)\n\t\t{\n\t\t\t// todo\n\t\t\t// AXSetVoiceRmtSrc\n\t\t}\n\t\t// other flags todo: 0x10000000, 0x20000000, 0x40000000 for RmtIIR\n\t}\n\n\tvoid AXIst_SyncVPB(AXVPBInternal_t** lastProcessedDSPShadowCopy, AXVPBInternal_t** lastProcessedPPCShadowCopy)\n\t{\n\t\t__AXVoiceListSpinlock.lock();\n\n\t\tAXVPBInternal_t* previousInternalDSP = nullptr;\n\t\tAXVPBInternal_t* previousInternalPPC = nullptr;\n\t\tfor (sint32 priority = AX_PRIORITY_MAX - 1; priority >= AX_PRIORITY_LOWEST; priority--)\n\t\t{\n\t\t\tauto& voiceArray = AXVoiceList_GetListByPriority(priority);\n\t\t\tfor(auto vpb : voiceArray)\n\t\t\t{\n\t\t\t\tsint32 index = vpb->index;\n\t\t\t\tsint32 depop = vpb->depop;\n\t\t\t\tAXVPBInternal_t* internalVPB = __AXVPBInternalVoiceArray + index;\n\t\t\t\tAXVPBInternal_t* internalShadowCopy = __AXVPBInternalVoiceShadowCopyArrayPtr + index;\n\t\t\t\tinternalVPB->mixerSelect = vpb->mixerSelect;\n\t\t\t\tAXVPB* nextVpb = vpb->next.GetPtr();\n\t\t\t\tif (depop)\n\t\t\t\t{\n\t\t\t\t\tAXMix_DepopVoice(internalShadowCopy);\n\t\t\t\t\tvpb->depop = 0;\n\t\t\t\t}\n\t\t\t\tif (internalVPB->playbackState != _swapEndianU16(1) && vpb->sync == 0)\n\t\t\t\t{\n\t\t\t\t\tinternalVPB->ukn2A2 = 2;\n\t\t\t\t\tinternalShadowCopy->ukn2A2 = 2;\n\t\t\t\t\tinternalVPB->nextAddrHigh = 0;\n\t\t\t\t\tinternalVPB->nextAddrLow = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tinternalVPB->ukn2A2 = 1;\n\t\t\t\t\tif (previousInternalPPC)\n\t\t\t\t\t{\n\t\t\t\t\t\tinternalVPB->nextAddrHigh = previousInternalPPC->selfAddrHigh;\n\t\t\t\t\t\tinternalVPB->nextAddrLow = previousInternalPPC->selfAddrLow;\n\t\t\t\t\t\tinternalVPB->nextToProcess = previousInternalPPC;\n\t\t\t\t\t\tpreviousInternalPPC = internalVPB;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tinternalVPB->nextAddrHigh = 0;\n\t\t\t\t\t\tinternalVPB->nextAddrLow = 0;\n\t\t\t\t\t\tinternalVPB->nextToProcess = nullptr;\n\t\t\t\t\t\tpreviousInternalPPC = internalVPB;\n\t\t\t\t\t}\n\t\t\t\t\tAXIst_SyncSingleVPB(vpb);\n\t\t\t\t\tif (!AXVoiceProtection_IsProtectedByAnyThread(vpb))\n\t\t\t\t\t{\n\t\t\t\t\t\tvpb->depop = 0;\n\t\t\t\t\t\tvpb->sync = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// depop and reset voices which just stopped playing\n\t\tauto& freeVoicesArray = AXVoiceList_GetFreeVoices();\n\t\tfor(auto vpb : freeVoicesArray)\n\t\t{\n\t\t\tAXVPBInternal_t* internalVPB = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\t\tAXVPBInternal_t* internalShadowCopy = __AXVPBInternalVoiceShadowCopyArrayPtr + (sint32)vpb->index;\n\t\t\tif (vpb->depop != (uint32be)0)\n\t\t\t{\n\t\t\t\tAXMix_DepopVoice(internalShadowCopy);\n\t\t\t\tvpb->depop = 0;\n\t\t\t}\n\t\t\tvpb->playbackState = 0;\n\t\t\tinternalVPB->ukn2A2 = 2;\n\t\t\tinternalShadowCopy->ukn2A2 = 2;\n\t\t\tinternalVPB->playbackState = 0;\n\t\t\tinternalShadowCopy->playbackState = 0;\n\t\t}\n\t\t// return last processed DSP/PPC voice internal shadow copy\n\t\tif (lastProcessedDSPShadowCopy)\n\t\t{\n\t\t\tif (previousInternalDSP)\n\t\t\t{\n\t\t\t\tAXVPBInternal_t* internalShadowCopy = __AXVPBInternalVoiceShadowCopyArrayPtr + (sint32)previousInternalDSP->index;\n\t\t\t\t*lastProcessedDSPShadowCopy = internalShadowCopy;\n\t\t\t}\n\t\t\telse\n\t\t\t\t*lastProcessedDSPShadowCopy = nullptr;\n\t\t}\n\t\tif (lastProcessedPPCShadowCopy)\n\t\t{\n\t\t\tif (previousInternalPPC)\n\t\t\t{\n\t\t\t\tAXVPBInternal_t* internalShadowCopy = __AXVPBInternalVoiceShadowCopyArrayPtr + (sint32)previousInternalPPC->index;\n\t\t\t\t*lastProcessedPPCShadowCopy = internalShadowCopy;\n\t\t\t}\n\t\t\telse\n\t\t\t\t*lastProcessedPPCShadowCopy = nullptr;\n\t\t}\n\t\t__AXVoiceListSpinlock.unlock();\n\t}\n\n\tvoid AXIst_HandleFrameCallbacks()\n\t{\n\t\t// frame callback\n\t\tif (__AXFrameCallback != MPTR_NULL)\n\t\t{\n\t\t\t// execute frame callback (no params)\n\t\t\tPPCCore_executeCallbackInternal(__AXFrameCallback);\n\t\t}\n\t\t// app frame callback\n\t\tfor (sint32 i = 0; i < AX_APP_FRAME_CALLBACK_MAX; i++)\n\t\t{\n\t\t\tif (__AXAppFrameCallback[i] == MPTR_NULL)\n\t\t\t\tcontinue;\n\t\t\t// execute app frame callback (no params)\n\t\t\tPPCCore_executeCallbackInternal(__AXAppFrameCallback[i]);\n\t\t}\n\t}\n\n\tvoid AXIst_ApplyDeviceRemix(sint32be* samples, float32be* matrix, sint32 inputChannelCount, sint32 outputChannelCount, sint32 sampleCount)\n\t{\n\t\tfor (auto i = 0; i < sampleCount; ++i)\n\t\t{\n\t\t\tfloat tmp[6]{};\n\t\t\tfor(auto j = 0; j < inputChannelCount; ++j)\n\t\t\t{\n\t\t\t\ttmp[j] = (float)samples[j * sampleCount + i];\n\t\t\t}\n\n\t\t\tfloat32be* mtx = matrix;\n\t\t\tint tmpOut[10]{};\n\t\t\tfor(auto j = 0; j < outputChannelCount; ++j)\n\t\t\t{\n\t\t\t\ttmpOut[j] = 0;\n\t\t\t\tfor (auto k = 0; k < inputChannelCount; ++k)\n\t\t\t\t{\n\t\t\t\t\ttmpOut[j] += (int)(tmp[k] * (*mtx));\n\t\t\t\t\tmtx++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (auto j = 0; j < outputChannelCount; ++j)\n\t\t\t{\n\t\t\t\tsamples[j * sampleCount + i] = tmpOut[j];\n\t\t\t}\n\t\t}\n\t}\n\t\n\tvoid AXIst_HandleDeviceRemix()\n\t{\n\t\textern SysAllocator<AXRemixMatrices_t, 12> g_remix_matrices;\n\t\textern sint32 __AXOutTVOutputChannelCount;\n\t\textern sint32 __AXOutDRCOutputChannelCount;\n\n\t\t// tv remix matrix\n\t\tfor(uint32 i = 0; i < g_remix_matrices.GetCount(); ++i)\n\t\t{\n\t\t\tconst auto& entry = g_remix_matrices[i];\n\t\t\tif(entry.deviceEntry[0].channelIn == __AXFinalMixCBStructTV->numChannelInput && entry.deviceEntry[0].channelOut == __AXOutTVOutputChannelCount && !entry.deviceEntry[0].matrix.IsNull())\n\t\t\t{\n\t\t\t\tAXIst_ApplyDeviceRemix((sint32be*)__AXTVBuffer48.GetPtr(), entry.deviceEntry[0].matrix.GetPtr(), __AXFinalMixCBStructTV->numChannelInput, __AXOutTVOutputChannelCount, AX_SAMPLES_PER_3MS_48KHZ);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// drc remix matrix\n\t\tfor (uint32 i = 0; i < g_remix_matrices.GetCount(); ++i)\n\t\t{\n\t\t\tconst auto& entry = g_remix_matrices[i];\n\t\t\tif (entry.deviceEntry[1].channelIn == __AXFinalMixCBStructDRC->numChannelInput && entry.deviceEntry[1].channelOut == __AXOutDRCOutputChannelCount && !entry.deviceEntry[0].matrix.IsNull())\n\t\t\t{\n\t\t\t\tAXIst_ApplyDeviceRemix((sint32be*)__AXDRCBuffer48.GetPtr(), entry.deviceEntry[1].matrix.GetPtr(), __AXFinalMixCBStructDRC->numChannelInput, __AXOutDRCOutputChannelCount, AX_SAMPLES_PER_3MS_48KHZ);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tstd::atomic_bool __AXIstIsProcessingFrame = false;\n\n\tSysAllocator<OSThread_t> __AXIstThread;\n\tSysAllocator<uint8, 0x4000> __AXIstThreadStack;\n\n\tSysAllocator<coreinit::OSMessage, 0x10> __AXIstThreadMsgArray;\n\tSysAllocator<coreinit::OSMessageQueue, 1> __AXIstThreadMsgQueue;\n\n\tvoid AXIst_InitThread()\n\t{\n        __AXIstIsProcessingFrame = false;\n\t\t// create ist message queue\n\t\tOSInitMessageQueue(__AXIstThreadMsgQueue.GetPtr(), __AXIstThreadMsgArray.GetPtr(), 0x10);\n\t\t// create thread\n\t\tuint8 istThreadAttr = 0;\n\t\tcoreinit::__OSCreateThreadType(__AXIstThread.GetPtr(), PPCInterpreter_makeCallableExportDepr(AXIst_ThreadEntry), 0, &__AXIstThreadMsgQueue, __AXIstThreadStack.GetPtr() + 0x4000, 0x4000, 14, istThreadAttr, OSThread_t::THREAD_TYPE::TYPE_DRIVER);\n\t\tcoreinit::OSResumeThread(__AXIstThread.GetPtr());\n\t}\n\n\tOSThread_t* AXIst_GetThread()\n\t{\n\t\treturn __AXIstThread.GetPtr();\n\t}\n\n\tvoid AXIst_GenerateFrame()\n\t{\n\t\t// generate one frame (3MS) of audio\n\t\t__AXIstIsProcessingFrame.store(true);\n\n\t\tmemset(__AXTVOutputBuffer.GetPtr(), 0, AX_SAMPLES_PER_3MS_48KHZ * AX_TV_CHANNEL_COUNT * sizeof(sint32));\n\t\tmemset(__AXDRCOutputBuffer.GetPtr(), 0, AX_SAMPLES_PER_3MS_48KHZ * AX_DRC_CHANNEL_COUNT * sizeof(sint32));\n\n\t\tAXVPBInternal_t* internalShadowCopyDSPHead = nullptr;\n\t\tAXVPBInternal_t* internalShadowCopyPPCHead = nullptr;\n\n\t\tAXIst_SyncVPB(&internalShadowCopyDSPHead, &internalShadowCopyPPCHead);\n\n\t\tif (internalShadowCopyDSPHead)\n\t\t\tassert_dbg();\n\n\t\tAXMix_process(internalShadowCopyPPCHead);\n\n\t\tAXOut_ResetFinalMixCBData();\n\t\tAXIst_ProcessFinalMixCallback();\n\t\tAXIst_HandleDeviceRemix();\n\n\t\t// todo - additional phases. See unimplemented API:\n\t\t// AXSetDRCVSMode\n\t\t// AXSetDeviceCompressor\n\t\t// AXRegisterPostFinalMixCallback\n\n\t\tAXOut_SubmitTVFrame(0);\n\t\tAXOut_SubmitDRCFrame(0);\n\n\t\t__AXIstIsProcessingFrame.store(false);\n\t}\n\n\tvoid AXIst_ThreadEntry(PPCInterpreter_t* hCPU)\n\t{\n\t\twhile (true)\n\t\t{\n\t\t\tStackAllocator<coreinit::OSMessage, 1> msg;\n\t\t\tOSReceiveMessage(__AXIstThreadMsgQueue.GetPtr(), msg.GetPointer(), OS_MESSAGE_BLOCK);\n\t\t\tif (msg.GetPointer()->message == 2)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Shut down of AX thread requested\");\n\t\t\t\tcoreinit::OSExitThread(0);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (msg.GetPointer()->message != 1)\n\t\t\t\tassert_dbg();\n\t\t\tAXIst_GenerateFrame();\n\t\t\tnumProcessedFrames++;\n\t\t}\n\t}\n\n\tSysAllocator<coreinit::OSMessage> _queueFrameMsg;\n\n\tvoid AXIst_QueueFrame()\n\t{\n\t\tcoreinit::OSMessage* msg = _queueFrameMsg.GetPtr();\n\t\tmsg->message = 1;\n\t\tmsg->data0 = 0;\n\t\tmsg->data1 = 0;\n\t\tmsg->data2 = 0;\n\t\tOSSendMessage(__AXIstThreadMsgQueue.GetPtr(), msg, 0);\n\t}\n\n\tvoid AXIst_StopThread()\n\t{\n\t\tcemu_assert_debug(coreinit::OSIsThreadTerminated(AXIst_GetThread()) == false);\n\t\t// request thread stop\n\t\tcoreinit::OSMessage* msg = _queueFrameMsg.GetPtr();\n\t\tmsg->message = 2;\n\t\tmsg->data0 = 0;\n\t\tmsg->data1 = 0;\n\t\tmsg->data2 = 0;\n\t\tOSSendMessage(__AXIstThreadMsgQueue.GetPtr(), msg, 0);\n\t\twhile (coreinit::OSIsThreadTerminated(AXIst_GetThread()) == false)\n\t\t\tPPCCore_switchToScheduler();\n\t}\n\n\tbool AXIst_IsFrameBeingProcessed()\n\t{\n\t\treturn __AXIstIsProcessingFrame.load();\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/snd_core/ax_mix.cpp",
    "content": "#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/snd_core/ax_internal.h\"\n#include \"Cafe/HW/MMU/MMU.h\"\n#include \"config/ActiveSettings.h\"\n\nvoid mic_updateOnAXFrame();\n\nnamespace snd_core\n{\n\tuint32 __AXDefaultMixerSelect = AX_MIXER_SELECT_BOTH;\n\n\tuint16 __AXTVAuxReturnVolume[AX_AUX_BUS_COUNT];\n\n\tvoid AXSetDefaultMixerSelect(uint32 mixerSelect)\n\t{\n\t\t__AXDefaultMixerSelect = mixerSelect;\n\t}\n\n\tuint32 AXGetDefaultMixerSelect()\n\t{\n\t\treturn __AXDefaultMixerSelect;\n\t}\n\n\tvoid AXMix_Init()\n\t{\n\t\tAXSetDefaultMixerSelect(AX_MIXER_SELECT_PPC);\n\t}\n\n\tvoid AXMix_DepopVoice(AXVPBInternal_t* internalShadowCopy)\n\t{\n\t\t// todo\n\t}\n\n#define handleAdpcmDecodeLoop() \\\n\tif (internalShadowCopy->internalOffsets.loopFlag != 0) \\\n\t{\t\\\n\t\tscale = _swapEndianU16(internalShadowCopy->adpcmLoop.loopScale); \\\n\t\tdelta = 1 << (scale & 0xF); \\\n\t\tcoefIndex = (scale >> 4) & 7; \\\n\t\tcoefA = (sint32)(sint16)_swapEndianU16(internalShadowCopy->adpcmData.coef[coefIndex * 2 + 0]); \\\n\t\tcoefB = (sint32)(sint16)_swapEndianU16(internalShadowCopy->adpcmData.coef[coefIndex * 2 + 1]); \\\n\t\tplaybackNibbleOffset = vpbLoopOffset; \\\n\t} \\\n\telse \\\n\t{ \\\n\t\t/* no loop */ \\\n\t\tinternalShadowCopy->playbackState = 0; \\\n\t\tmemset(outputWriter, 0, sampleCount * sizeof(sint16)); \\\n\t\tbreak; \\\n\t}\n\n\tuint32 _AX_fixAdpcmEndOffset(uint32 adpcmOffset)\n\t{\n\t\t// How to Survive uses an end offset of 0x40000 which is not a valid adpcm sample offset and thus can never be reached (the ppc side decoder jumps from 0x3FFFF to 0x40002)\n\t\t// todo - investigate if the DSP decoder routines can handle invalid ADPCM end offsets\n\n\t\t// for now we use this workaround to force a valid address\n\t\tif ((adpcmOffset & 0xF) <= 1)\n\t\t\treturn adpcmOffset + 2;\n\t\treturn adpcmOffset;\n\t}\n\n\tvoid AX_readADPCMSamples(AXVPBInternal_t* internalShadowCopy, sint16* output, sint32 sampleCount)\n\t{\n\t\tif (internalShadowCopy->playbackState == 0)\n\t\t{\n\t\t\tmemset(output, 0, sampleCount * sizeof(sint16));\n\t\t\treturn;\n\t\t}\n\n\t\tAXVPB* vpb = __AXVPBArrayPtr + (sint32)internalShadowCopy->index;\n\n\t\tuint8* sampleBase = (uint8*)memory_getPointerFromVirtualOffset(_swapEndianU32(vpb->offsets.samples));\n\n\t\tuint32 vpbLoopOffset = _swapEndianU32(*(uint32*)&vpb->offsets.loopOffset);\n\t\tuint32 vpbEndOffset = _swapEndianU32(*(uint32*)&vpb->offsets.endOffset);\n\t\t\n\t\tvpbEndOffset = _AX_fixAdpcmEndOffset(vpbEndOffset);\n\n\t\tuint32 internalCurrentOffset = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.currentOffsetPtrHigh);\n\t\tuint32 internalLoopOffset = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.loopOffsetPtrHigh);\n\n\t\tsint32 scale = (sint32)_swapEndianU16(internalShadowCopy->adpcmData.scale);\n\t\tsint32 delta = 1 << (scale & 0xF);\n\t\tsint32 coefIndex = (scale >> 4) & 7;\n\n\t\tsint32 coefA = (sint32)(sint16)_swapEndianU16(internalShadowCopy->adpcmData.coef[coefIndex * 2 + 0]);\n\t\tsint32 coefB = (sint32)(sint16)_swapEndianU16(internalShadowCopy->adpcmData.coef[coefIndex * 2 + 1]);\n\n\t\tsint32 hist0 = (sint32)_swapEndianS16(internalShadowCopy->adpcmData.yn1);\n\t\tsint32 hist1 = (sint32)_swapEndianS16(internalShadowCopy->adpcmData.yn2);\n\n\t\tuint32 playbackNibbleOffset = vpbLoopOffset + (internalCurrentOffset - internalLoopOffset);\n\t\tuint32 playbackNibbleOffsetStart = playbackNibbleOffset;\n\n\t\tsint16* outputWriter = output;\n\t\t// decode samples from current partial ADPCM block\n\t\twhile (sampleCount && (playbackNibbleOffset & 0xF))\n\t\t{\n\t\t\tsint8 nibble = (sint8)sampleBase[(sint32)playbackNibbleOffset >> 1];\n\t\t\tnibble <<= (4 * ((playbackNibbleOffset & 1)));\n\t\t\tnibble &= 0xF0;\n\t\t\tsint32 v = (sint32)nibble;\n\t\t\tv <<= (11 - 4);\n\t\t\tv *= delta;\n\t\t\tv += (hist0 * coefA + hist1 * coefB);\n\t\t\tv = (v + 0x400) >> 11;\n\t\t\tv = std::clamp(v, -32768, 32767);\n\n\t\t\thist1 = hist0;\n\t\t\thist0 = v;\n\t\t\t*outputWriter = v;\n\t\t\toutputWriter++;\n\n\t\t\t// check for loop / end offset\n\t\t\tif (playbackNibbleOffset == vpbEndOffset)\n\t\t\t{\n\t\t\t\thandleAdpcmDecodeLoop();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tplaybackNibbleOffset++;\n\t\t\t}\n\t\t\tsampleCount--;\n\t\t}\n\t\t// optimized code to decode whole blocks\n\t\tif (!(playbackNibbleOffset <= vpbEndOffset && ((uint64)playbackNibbleOffset + (uint64)(sampleCount * 16 / 14)) >= (uint64)vpbEndOffset))\n\t\t{\n\t\t\twhile (sampleCount >= 14) // 14 samples per 16 byte block\n\t\t\t{\n\t\t\t\t// decode header\n\t\t\t\tsint8* sampleInputData = (sint8*)sampleBase + ((sint32)playbackNibbleOffset >> 1);\n\t\t\t\tscale = (uint8)sampleInputData[0];\n\t\t\t\tdelta = 1 << (scale & 0xF);\n\t\t\t\tcoefIndex = (scale >> 4) & 7;\n\t\t\t\tcoefA = (sint32)(sint16)_swapEndianU16(internalShadowCopy->adpcmData.coef[coefIndex * 2 + 0]);\n\t\t\t\tcoefB = (sint32)(sint16)_swapEndianU16(internalShadowCopy->adpcmData.coef[coefIndex * 2 + 1]);\n\t\t\t\tplaybackNibbleOffset += 2;\n\t\t\t\t// decode samples\n\t\t\t\tsampleInputData++;\n\t\t\t\tfor (sint32 i = 0; i < 7; i++)\n\t\t\t\t{\n\t\t\t\t\t// n0\n\t\t\t\t\tsint8 nibble = *sampleInputData;\n\t\t\t\t\tsampleInputData++;\n\t\t\t\t\tsint32 v;\n\t\t\t\t\t// upper nibble\n\t\t\t\t\tv = (sint32)(sint8)(nibble & 0xF0);\n\t\t\t\t\tv <<= (11 - 4);\n\t\t\t\t\tv *= delta;\n\t\t\t\t\tv += (hist0 * coefA + hist1 * coefB);\n\t\t\t\t\tv = (v + 0x400) >> 11;\n\n\t\t\t\t\tv = std::min(v, 32767);\n\t\t\t\t\tv = std::max(v, -32768);\n\n\t\t\t\t\thist1 = hist0;\n\t\t\t\t\thist0 = v;\n\t\t\t\t\t*outputWriter = v;\n\t\t\t\t\toutputWriter++;\n\t\t\t\t\t// lower nibble\n\t\t\t\t\tv = (sint32)(sint8)(nibble << 4);\n\t\t\t\t\tv <<= (11 - 4);\n\t\t\t\t\tv *= delta;\n\t\t\t\t\tv += (hist0 * coefA + hist1 * coefB);\n\t\t\t\t\tv = (v + 0x400) >> 11;\n\n\t\t\t\t\tv = std::min(v, 32767);\n\t\t\t\t\tv = std::max(v, -32768);\n\n\t\t\t\t\thist1 = hist0;\n\t\t\t\t\thist0 = v;\n\n\t\t\t\t\t*outputWriter = v;\n\t\t\t\t\toutputWriter++;\n\t\t\t\t}\n\t\t\t\tplaybackNibbleOffset += 7 * 2;\n\t\t\t\tsampleCount -= 7 * 2;\n\t\t\t}\n\t\t}\n\t\t// decode remaining samples\n\t\twhile (sampleCount)\n\t\t{\n\t\t\tif ((playbackNibbleOffset & 0xF) == 0)\n\t\t\t{\n\t\t\t\tscale = sampleBase[(sint32)playbackNibbleOffset >> 1];\n\t\t\t\tdelta = 1 << (scale & 0xF);\n\t\t\t\tcoefIndex = (scale >> 4) & 7;\n\t\t\t\tcoefA = (sint32)(sint16)_swapEndianU16(internalShadowCopy->adpcmData.coef[coefIndex * 2 + 0]);\n\t\t\t\tcoefB = (sint32)(sint16)_swapEndianU16(internalShadowCopy->adpcmData.coef[coefIndex * 2 + 1]);\n\t\t\t\tplaybackNibbleOffset += 2;\n\t\t\t}\n\t\t\tsint8 nibble = (sint8)sampleBase[(sint32)playbackNibbleOffset >> 1];\n\t\t\tnibble <<= (4 * ((playbackNibbleOffset & 1)));\n\t\t\tnibble &= 0xF0;\n\t\t\tsint32 v = (sint32)nibble;\n\t\t\tv <<= (11 - 4);\n\t\t\tv *= delta;\n\t\t\tv += (hist0 * coefA + hist1 * coefB);\n\t\t\tv = (v + 0x400) >> 11;\n\n\t\t\tv = std::min(v, 32767);\n\t\t\tv = std::max(v, -32768);\n\n\t\t\thist1 = hist0;\n\t\t\thist0 = v;\n\t\t\t*outputWriter = v;\n\t\t\toutputWriter++;\n\n\t\t\t// check for loop / end offset\n\t\t\tif (playbackNibbleOffset == vpbEndOffset)\n\t\t\t{\n\t\t\t\thandleAdpcmDecodeLoop();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tplaybackNibbleOffset++;\n\t\t\t}\n\t\t\tsampleCount--;\n\t\t}\n\n\t\t// write updated values\n\t\tinternalShadowCopy->adpcmData.scale = _swapEndianU16(scale);\n\t\tinternalShadowCopy->adpcmData.yn1 = (uint16)_swapEndianS16(hist0);\n\t\tinternalShadowCopy->adpcmData.yn2 = (uint16)_swapEndianS16(hist1);\n\n\t\tuint32 newInternalCurrentOffset = internalCurrentOffset + (playbackNibbleOffset - playbackNibbleOffsetStart);\n\t\t*(uint32*)&internalShadowCopy->internalOffsets.currentOffsetPtrHigh = _swapEndianU32(newInternalCurrentOffset);\n\n\t}\n\n\tvoid AX_DecodeSamplesADPCM_NoSrc(AXVPBInternal_t* internalShadowCopy, float* output, sint32 sampleCount)\n\t{\n\t\tsint16 sampleBuffer[1024];\n\t\tcemu_assert(sampleCount <= (sizeof(sampleBuffer) / sizeof(sampleBuffer[0])));\n\t\tAX_readADPCMSamples(internalShadowCopy, sampleBuffer, sampleCount);\n\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t{\n\t\t\t// decode next sample\n\t\t\tsint32 s = sampleBuffer[i];\n\t\t\ts <<= 8;\n\t\t\t*output = (float)s;\n\t\t\toutput++;\n\t\t}\n\t}\n\n\tvoid AX_DecodeSamplesADPCM_Linear(AXVPBInternal_t* internalShadowCopy, float* output, sint32 sampleCount)\n\t{\n\t\tuint32 currentFracPos = (uint32)_swapEndianU16(internalShadowCopy->src.currentFrac);\n\t\tuint32 ratio = _swapEndianU32(*(uint32*)&internalShadowCopy->src.ratioHigh);\n\n\t\tsint16 historySamples[4];\n\t\thistorySamples[0] = _swapEndianS16(internalShadowCopy->src.historySamples[0]);\n\t\thistorySamples[1] = _swapEndianS16(internalShadowCopy->src.historySamples[1]);\n\t\thistorySamples[2] = _swapEndianS16(internalShadowCopy->src.historySamples[2]);\n\t\thistorySamples[3] = _swapEndianS16(internalShadowCopy->src.historySamples[3]);\n\n\t\tsint32 historyIndex = 0;\n\n\t\tsint32 numberOfDecodedAdpcmSamples = (sint32)((currentFracPos + ratio * sampleCount) >> 16);\n\t\tsint16 adpcmSampleBuffer[4096];\n\t\tif (numberOfDecodedAdpcmSamples >= 4096)\n\t\t{\n\t\t\tmemset(output, 0, sizeof(float)*sampleCount);\n\t\t\tcemuLog_log(LogType::Force, \"Too many ADPCM samples to decode. ratio = {:08x}\", ratio);\n\t\t\treturn;\n\t\t}\n\t\tAX_readADPCMSamples(internalShadowCopy, adpcmSampleBuffer, numberOfDecodedAdpcmSamples);\n\n\t\tsint32 readSampleCount = 0;\n\n\t\tif (ratio == 0x10000 && currentFracPos == 0)\n\t\t{\n\t\t\t// optimized path when accessing only fully aligned samples\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(readSampleCount < numberOfDecodedAdpcmSamples);\n\t\t\t\t// get next sample\n\t\t\t\tsint16 s = adpcmSampleBuffer[readSampleCount];\n\t\t\t\treadSampleCount++;\n\t\t\t\thistoryIndex = (historyIndex + 1) & 3;\n\t\t\t\thistorySamples[historyIndex] = s;\n\t\t\t\t// use previous sample\n\t\t\t\tsint32 previousSample = historySamples[(historyIndex + 3) & 3];\n\t\t\t\tsint32 p0 = previousSample << 8;\n\t\t\t\t*output = (float)p0;\n\t\t\t\toutput++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t{\n\t\t\t\t// move playback pos\n\t\t\t\tcurrentFracPos += ratio;\n\t\t\t\t// get more samples if needed\n\t\t\t\twhile (currentFracPos >= 0x10000)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(readSampleCount < numberOfDecodedAdpcmSamples);\n\t\t\t\t\tsint16 s = adpcmSampleBuffer[readSampleCount];\n\t\t\t\t\treadSampleCount++;\n\t\t\t\t\tcurrentFracPos -= 0x10000;\n\t\t\t\t\thistoryIndex = (historyIndex + 1) & 3;\n\t\t\t\t\thistorySamples[historyIndex] = s;\n\t\t\t\t}\n\t\t\t\t// linear interpolation of current sample\n\t\t\t\tsint32 previousSample = historySamples[(historyIndex + 3) & 3];\n\t\t\t\tsint32 nextSample = historySamples[historyIndex];\n\n\t\t\t\tsint32 p0 = (sint32)previousSample * (sint32)(0x10000 - currentFracPos);\n\t\t\t\tsint32 p1 = (sint32)nextSample * (sint32)(currentFracPos);\n\n\t\t\t\tp0 >>= 7;\n\t\t\t\tp1 >>= 7;\n\n\t\t\t\tsint32 interpolatedSample = p0 + p1;\n\t\t\t\tinterpolatedSample >>= 1;\n\n\t\t\t\t*output = (float)interpolatedSample;\n\t\t\t\toutput++;\n\t\t\t}\n\t\t}\n\t\tcemu_assert_debug(readSampleCount == numberOfDecodedAdpcmSamples);\n\t\t// set variables\n\t\tinternalShadowCopy->src.currentFrac = _swapEndianU16((uint16)(currentFracPos));\n\t\tinternalShadowCopy->src.historySamples[0] = _swapEndianS16(historySamples[(historyIndex + 0) & 3]);\n\t\tinternalShadowCopy->src.historySamples[1] = _swapEndianS16(historySamples[(historyIndex + 1) & 3]);\n\t\tinternalShadowCopy->src.historySamples[2] = _swapEndianS16(historySamples[(historyIndex + 2) & 3]);\n\t\tinternalShadowCopy->src.historySamples[3] = _swapEndianS16(historySamples[(historyIndex + 3) & 3]);\n\t}\n\n\tvoid AX_DecodeSamplesADPCM_Tap(AXVPBInternal_t* internalShadowCopy, float* output, sint32 sampleCount)\n\t{\n\t\t// todo - implement this\n\t\tAX_DecodeSamplesADPCM_Linear(internalShadowCopy, output, sampleCount);\n\t}\n\n\tvoid AX_DecodeSamplesPCM8_Linear(AXVPBInternal_t* internalShadowCopy, float* output, sint32 sampleCount)\n\t{\n\t\t// get variables\n\t\tuint32 currentFracPos = (uint32)_swapEndianU16(internalShadowCopy->src.currentFrac);\n\t\tuint32 ratio = _swapEndianU32(*(uint32*)&internalShadowCopy->src.ratioHigh);\n\n\t\tuint32 endOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.endOffsetPtrHigh);\n\t\tuint32 currentOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.currentOffsetPtrHigh);\n\t\tuint32 loopOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.loopOffsetPtrHigh);\n\t\tuint32 ptrHighExtension = _swapEndianU16(internalShadowCopy->internalOffsets.ptrHighExtension);\n\n\t\tuint8* endOffsetAddr = memory_base + (endOffsetPtr | (ptrHighExtension << 29));\n\t\tuint8* currentOffsetAddr = memory_base + (currentOffsetPtr | (ptrHighExtension << 29));\n\n\t\tsint16 historySamples[4];\n\t\thistorySamples[0] = _swapEndianS16(internalShadowCopy->src.historySamples[0]);\n\t\thistorySamples[1] = _swapEndianS16(internalShadowCopy->src.historySamples[1]);\n\t\thistorySamples[2] = _swapEndianS16(internalShadowCopy->src.historySamples[2]);\n\t\thistorySamples[3] = _swapEndianS16(internalShadowCopy->src.historySamples[3]);\n\n\t\tsint32 historyIndex = 0;\n\n\t\tfor (sint32 i = 0; i<sampleCount; i++)\n\t\t{\n\t\t\tcurrentFracPos += ratio;\n\t\t\twhile (currentFracPos >= 0x10000)\n\t\t\t{\n\t\t\t\t// read next sample\n\t\t\t\thistoryIndex = (historyIndex + 1) & 3;\n\t\t\t\tif (internalShadowCopy->playbackState)\n\t\t\t\t{\n\t\t\t\t\tsint32 s = (sint32)(sint8)*currentOffsetAddr;\n\t\t\t\t\ts <<= 8;\n\t\t\t\t\thistorySamples[historyIndex] = s;\n\t\t\t\t\tif (currentOffsetAddr == endOffsetAddr)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (internalShadowCopy->internalOffsets.loopFlag)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// loop\n\t\t\t\t\t\t\tcurrentOffsetAddr = memory_base + (loopOffsetPtr | (ptrHighExtension << 29));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// stop playing\n\t\t\t\t\t\t\tinternalShadowCopy->playbackState = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tcurrentOffsetAddr++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// voice not playing, read sample as 0\n\t\t\t\t\thistorySamples[historyIndex] = 0;\n\t\t\t\t}\n\t\t\t\tcurrentFracPos -= 0x10000;\n\t\t\t}\n\t\t\t// interpolate sample\n\t\t\tsint32 previousSample = historySamples[(historyIndex + 3) & 3];\n\t\t\tsint32 nextSample = historySamples[historyIndex];\n\t\t\tsint32 p0 = (sint32)previousSample * (sint32)(0x10000 - currentFracPos);\n\t\t\tsint32 p1 = (sint32)nextSample * (sint32)(currentFracPos);\n\t\t\tp0 >>= 7;\n\t\t\tp1 >>= 7;\n\t\t\tsint32 interpolatedSample = p0 + p1;\n\t\t\tinterpolatedSample >>= 1;\n\t\t\t*output = (float)interpolatedSample;\n\t\t\toutput++;\n\t\t}\n\t\t// set variables\n\t\tinternalShadowCopy->src.currentFrac = _swapEndianU16((uint16)(currentFracPos));\n\t\tinternalShadowCopy->src.historySamples[0] = _swapEndianS16(historySamples[(historyIndex + 0) & 3]);\n\t\tinternalShadowCopy->src.historySamples[1] = _swapEndianS16(historySamples[(historyIndex + 1) & 3]);\n\t\tinternalShadowCopy->src.historySamples[2] = _swapEndianS16(historySamples[(historyIndex + 2) & 3]);\n\t\tinternalShadowCopy->src.historySamples[3] = _swapEndianS16(historySamples[(historyIndex + 3) & 3]);\n\t\t// store current offset\n\t\tcurrentOffsetPtr = (uint32)((uint8*)currentOffsetAddr - memory_base);\n\t\tcurrentOffsetPtr &= 0x1FFFFFFF; // is this correct?\n\t\t*(uint32*)&internalShadowCopy->internalOffsets.currentOffsetPtrHigh = _swapEndianU32(currentOffsetPtr);\n\t}\n\n\tvoid AX_DecodeSamplesPCM8_Tap(AXVPBInternal_t* internalShadowCopy, float* output, sint32 sampleCount)\n\t{\n\t\t// todo - implement this\n\t\tAX_DecodeSamplesPCM8_Linear(internalShadowCopy, output, sampleCount);\n\t}\n\n\tvoid AX_DecodeSamplesPCM8_NoSrc(AXVPBInternal_t* internalShadowCopy, float* output, sint32 sampleCount)\n\t{\n\t\t// get variables\n\t\tuint32 currentFracPos = (uint32)_swapEndianU16(internalShadowCopy->src.currentFrac);\n\t\tuint32 ratio = _swapEndianU32(*(uint32*)&internalShadowCopy->src.ratioHigh);\n\n\t\tuint32 endOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.endOffsetPtrHigh);\n\t\tuint32 currentOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.currentOffsetPtrHigh);\n\t\tuint32 ptrHighExtension = _swapEndianU16(internalShadowCopy->internalOffsets.ptrHighExtension);\n\n\t\tuint8* endOffsetAddr = memory_base + (endOffsetPtr | (ptrHighExtension << 29));\n\t\tuint8* currentOffsetAddr = memory_base + (currentOffsetPtr | (ptrHighExtension << 29));\n\n\t\tsint16 historySamples[4];\n\t\thistorySamples[0] = _swapEndianS16(internalShadowCopy->src.historySamples[0]);\n\t\thistorySamples[1] = _swapEndianS16(internalShadowCopy->src.historySamples[1]);\n\t\thistorySamples[2] = _swapEndianS16(internalShadowCopy->src.historySamples[2]);\n\t\thistorySamples[3] = _swapEndianS16(internalShadowCopy->src.historySamples[3]);\n\n\t\tcemu_assert_debug(false); // todo\n\t}\n\n\tvoid AX_DecodeSamplesPCM16_Linear(AXVPBInternal_t* internalShadowCopy, float* output, sint32 sampleCount)\n\t{\n\t\tuint32 currentFracPos = (uint32)_swapEndianU16(internalShadowCopy->src.currentFrac);\n\t\tuint32 ratio = _swapEndianU32(*(uint32*)&internalShadowCopy->src.ratioHigh);\n\n\t\tuint32 endOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.endOffsetPtrHigh);\n\t\tuint32 currentOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.currentOffsetPtrHigh);\n\t\tuint32 loopOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.loopOffsetPtrHigh);\n\t\tuint32 ptrHighExtension = _swapEndianU16(internalShadowCopy->internalOffsets.ptrHighExtension);\n\n\t\tuint16* endOffsetAddr = (uint16*)(memory_base + ((endOffsetPtr * 2) | (ptrHighExtension << 29)));\n\t\tuint16* currentOffsetAddr = (uint16*)(memory_base + ((currentOffsetPtr * 2) | (ptrHighExtension << 29)));\n\n\t\tuint16* loopOffsetAddrDebug = (uint16*)(memory_base + ((loopOffsetPtr * 2) | (ptrHighExtension << 29)));\n\n\t\tsint16 historySamples[4];\n\t\thistorySamples[0] = _swapEndianS16(internalShadowCopy->src.historySamples[0]);\n\t\thistorySamples[1] = _swapEndianS16(internalShadowCopy->src.historySamples[1]);\n\t\thistorySamples[2] = _swapEndianS16(internalShadowCopy->src.historySamples[2]);\n\t\thistorySamples[3] = _swapEndianS16(internalShadowCopy->src.historySamples[3]);\n\n\t\tsint32 historyIndex = 0;\n\n\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t{\n\t\t\tcurrentFracPos += ratio;\n\t\t\twhile (currentFracPos >= 0x10000)\n\t\t\t{\n\t\t\t\t// read next sample\n\t\t\t\thistoryIndex = (historyIndex + 1) & 3;\n\t\t\t\tif (internalShadowCopy->playbackState)\n\t\t\t\t{\n\t\t\t\t\tsint32 s = _swapEndianS16(*currentOffsetAddr);\n\t\t\t\t\thistorySamples[historyIndex] = s;\n\t\t\t\t\tif (currentOffsetAddr == endOffsetAddr)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (internalShadowCopy->internalOffsets.loopFlag)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// loop\n\t\t\t\t\t\t\tcurrentOffsetAddr = (uint16*)(memory_base + ((loopOffsetPtr * 2) | (ptrHighExtension << 29)));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// stop playing\n\t\t\t\t\t\t\tinternalShadowCopy->playbackState = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tcurrentOffsetAddr++; // increment pointer only if not at end offset\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// voice not playing -> sample is silent\n\t\t\t\t\thistorySamples[historyIndex] = 0;\n\t\t\t\t}\n\t\t\t\tcurrentFracPos -= 0x10000;\n\t\t\t}\n\t\t\t// interpolate sample\n\t\t\tsint32 previousSample = historySamples[(historyIndex + 3) & 3];\n\t\t\tsint32 nextSample = historySamples[historyIndex];\n\n\t\t\tsint32 p0 = (sint32)previousSample * (sint32)(0x10000 - currentFracPos);\n\t\t\tsint32 p1 = (sint32)nextSample * (sint32)(currentFracPos);\n\t\t\tp0 >>= 7;\n\t\t\tp1 >>= 7;\n\t\t\tsint32 interpolatedSample = p0 + p1;\n\t\t\tinterpolatedSample >>= 1;\n\n\t\t\t*output = (float)interpolatedSample;\n\t\t\toutput++;\n\t\t}\n\n\t\t// set variables\n\t\tinternalShadowCopy->src.currentFrac = _swapEndianU16((uint16)(currentFracPos));\n\t\tinternalShadowCopy->src.historySamples[0] = _swapEndianS16(historySamples[(historyIndex + 0) & 3]);\n\t\tinternalShadowCopy->src.historySamples[1] = _swapEndianS16(historySamples[(historyIndex + 1) & 3]);\n\t\tinternalShadowCopy->src.historySamples[2] = _swapEndianS16(historySamples[(historyIndex + 2) & 3]);\n\t\tinternalShadowCopy->src.historySamples[3] = _swapEndianS16(historySamples[(historyIndex + 3) & 3]);\n\t\t// store current offset\n\t\tcurrentOffsetPtr = (uint32)((uint8*)currentOffsetAddr - memory_base);\n\t\tcurrentOffsetPtr &= 0x1FFFFFFF;\n\t\tcurrentOffsetPtr >>= 1;\n\t\t*(uint32*)&internalShadowCopy->internalOffsets.currentOffsetPtrHigh = _swapEndianU32(currentOffsetPtr);\n\t}\n\n\tvoid AX_DecodeSamplesPCM16_Tap(AXVPBInternal_t* internalShadowCopy, float* output, sint32 sampleCount)\n\t{\n\t\t// todo - implement this\n\t\tAX_DecodeSamplesPCM16_Linear(internalShadowCopy, output, sampleCount);\n\t}\n\n\tvoid AX_DecodeSamplesPCM16_NoSrc(AXVPBInternal_t* internalShadowCopy, float* output, sint32 sampleCount)\n\t{\n\t\t// get variables\n\t\tuint32 currentFracPos = (uint32)_swapEndianU16(internalShadowCopy->src.currentFrac);\n\t\tuint32 ratio = _swapEndianU32(*(uint32*)&internalShadowCopy->src.ratioHigh);\n\n\t\tuint32 endOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.endOffsetPtrHigh);\n\t\tuint32 currentOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.currentOffsetPtrHigh);\n\t\tuint32 loopOffsetPtr = _swapEndianU32(*(uint32*)&internalShadowCopy->internalOffsets.loopOffsetPtrHigh);\n\t\tuint32 ptrHighExtension = _swapEndianU16(internalShadowCopy->internalOffsets.ptrHighExtension);\n\n\t\tuint16* endOffsetAddr = (uint16*)(memory_base + (endOffsetPtr * 2 | (ptrHighExtension << 29)));\n\t\tuint16* currentOffsetAddr = (uint16*)(memory_base + (currentOffsetPtr * 2 | (ptrHighExtension << 29)));\n\n\t\tif (internalShadowCopy->playbackState == 0)\n\t\t{\n\t\t\tmemset(output, 0, sizeof(float)*sampleCount);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t{\n\t\t\tsint32 s = _swapEndianS16(*currentOffsetAddr);\n\t\t\ts <<= 8;\n\t\t\toutput[i] = (float)s;\n\t\t\tif (currentOffsetAddr == endOffsetAddr)\n\t\t\t{\n\t\t\t\tif (internalShadowCopy->internalOffsets.loopFlag)\n\t\t\t\t{\n\t\t\t\t\tcurrentOffsetAddr = (uint16*)(memory_base + (loopOffsetPtr * 2 | (ptrHighExtension << 29)));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tinternalShadowCopy->playbackState = 0;\n\t\t\t\t\tfor (; i < sampleCount; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\toutput[i] = 0.0f;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tcurrentOffsetAddr++;\n\t\t}\n\t\t// store current offset\n\t\tcurrentOffsetPtr = (uint32)((uint8*)currentOffsetAddr - memory_base);\n\t\tcurrentOffsetPtr &= 0x1FFFFFFF;\n\t\tcurrentOffsetPtr >>= 1;\n\n\t\t*(uint32*)&internalShadowCopy->internalOffsets.currentOffsetPtrHigh = _swapEndianU32(currentOffsetPtr);\n\t}\n\n\tvoid AXVoiceMix_DecodeSamples(AXVPBInternal_t* internalShadowCopy, float* output, sint32 sampleCount)\n\t{\n\t\tuint32 srcFilterMode = _swapEndianU16(internalShadowCopy->srcFilterMode);\n\t\tuint16 format = _swapEndianU16(internalShadowCopy->internalOffsets.format);\n\n\t\tif (srcFilterMode == AX_FILTER_MODE_TAP)\n\t\t{\n\t\t\tif (format == AX_FORMAT_ADPCM)\n\t\t\t\tAX_DecodeSamplesADPCM_Tap(internalShadowCopy, output, sampleCount);\n\t\t\telse if (format == AX_FORMAT_PCM16)\n\t\t\t\tAX_DecodeSamplesPCM16_Tap(internalShadowCopy, output, sampleCount);\n\t\t\telse if (format == AX_FORMAT_PCM8)\n\t\t\t\tAX_DecodeSamplesPCM8_Tap(internalShadowCopy, output, sampleCount);\n\t\t\telse\n\t\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\telse if (srcFilterMode == AX_FILTER_MODE_LINEAR)\n\t\t{\n\t\t\tif (format == AX_FORMAT_ADPCM)\n\t\t\t\tAX_DecodeSamplesADPCM_Linear(internalShadowCopy, output, sampleCount);\n\t\t\telse if (format == AX_FORMAT_PCM16)\n\t\t\t\tAX_DecodeSamplesPCM16_Linear(internalShadowCopy, output, sampleCount);\n\t\t\telse if (format == AX_FORMAT_PCM8)\n\t\t\t\tAX_DecodeSamplesPCM8_Linear(internalShadowCopy, output, sampleCount);\n\t\t\telse\n\t\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\telse if (srcFilterMode == AX_FILTER_MODE_NONE)\n\t\t{\n\t\t\tif (format == AX_FORMAT_ADPCM)\n\t\t\t\tAX_DecodeSamplesADPCM_NoSrc(internalShadowCopy, output, sampleCount);\n\t\t\telse if (format == AX_FORMAT_PCM16)\n\t\t\t\tAX_DecodeSamplesPCM16_NoSrc(internalShadowCopy, output, sampleCount);\n\t\t\telse if (format == AX_FORMAT_PCM8)\n\t\t\t\tAX_DecodeSamplesPCM8_NoSrc(internalShadowCopy, output, sampleCount);\n\t\t\telse\n\t\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\n\tsint32 AXVoiceMix_MergeInto(float* inputSamples, float* outputSamples, sint32 sampleCount, AXCHMIX_DEPR* mix, sint16 deltaI)\n\t{\n\t\tfloat vol = (float)_swapEndianU16(mix->vol) / (float)0x8000;\n\t\tif (deltaI != 0)\n\t\t{\n\t\t\tfloat delta = (float)deltaI / (float)0x8000;\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t{\n\t\t\t\tvol += delta;\n\t\t\t\toutputSamples[i] += inputSamples[i] * vol;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// optimized version for delta == 0.0\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t{\n\t\t\t\toutputSamples[i] += inputSamples[i] * vol;\n\t\t\t}\n\t\t}\n\t\tuint16 volI = (uint16)(vol * 32768.0f);\n\t\tmix->vol = _swapEndianU16(volI);\n\t\treturn volI;\n\t}\n\n\tfloat __AXMixBufferTV[AX_SAMPLES_MAX * AX_TV_CHANNEL_COUNT * AX_BUS_COUNT];\n\tfloat __AXMixBufferDRC[2 * AX_SAMPLES_MAX * AX_DRC_CHANNEL_COUNT * AX_BUS_COUNT];\n\n\tvoid AXVoiceMix_ApplyADSR(AXVPBInternal_t* internalShadowCopy, float* sampleData, sint32 sampleCount)\n\t{\n\t\tuint16 volume = internalShadowCopy->veVolume;\n\t\tsint16 volumeDelta = (sint16)internalShadowCopy->veDelta;\n\t\tif (volume == 0x8000 && volumeDelta == 0)\n\t\t\treturn;\n\t\tfloat volumeScaler = (float)volume / 32768.0f;\n\t\tif (volumeDelta == 0)\n\t\t{\n\t\t\t// without delta\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t\tsampleData[i] *= volumeScaler;\n\t\t\treturn;\n\t\t}\n\t\t// with delta\n\t\tdouble volumeScalerDelta = (double)volumeDelta / 32768.0;\n\t\tvolumeScalerDelta = volumeScalerDelta + volumeScalerDelta;\n\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t{\n\t\t\tvolumeScaler += (float)volumeScalerDelta;\n\t\t\tsampleData[i] *= volumeScaler;\n\t\t}\n\t\tif (volumeDelta != 0)\n\t\t{\n\t\t\tvolume = (uint16)(volumeScaler * 32768.0);\n\t\t\tinternalShadowCopy->veVolume = volume;\n\t\t}\n\t}\n\n\tvoid AXVoiceMix_ApplyBiquad(AXVPBInternal_t* internalShadowCopy, float* sampleData, sint32 sampleCount)\n\t{\n\t\tif (internalShadowCopy->biquad.on == AX_BIQUAD_OFF)\n\t\t\treturn;\n#ifdef CEMU_DEBUG_ASSERT\n\t\tif (internalShadowCopy->biquad.on != 0x0200)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"AX_ApplyBiquad() with incorrect biquad.on value 0x{:04x}\", _swapEndianU16(internalShadowCopy->biquad.on));\n\t\t}\n#endif\n\n\t\tfloat a1 = (float)(sint16)_swapEndianS16(internalShadowCopy->biquad.a1) / 16384.0f;\n\t\tfloat a2 = (float)(sint16)_swapEndianS16(internalShadowCopy->biquad.a2) / 16384.0f;\n\t\tfloat b0 = (float)(sint16)_swapEndianS16(internalShadowCopy->biquad.b0) / 16384.0f;\n\t\tfloat b1 = (float)(sint16)_swapEndianS16(internalShadowCopy->biquad.b1) / 16384.0f;\n\t\tfloat b2 = (float)(sint16)_swapEndianS16(internalShadowCopy->biquad.b2) / 16384.0f;\n\n\t\tfloat yn1 = (float)_swapEndianS16(internalShadowCopy->biquad.yn1);\n\t\tfloat yn2 = (float)_swapEndianS16(internalShadowCopy->biquad.yn2);\n\t\tfloat xn1 = (float)_swapEndianS16(internalShadowCopy->biquad.xn1);\n\t\tfloat xn2 = (float)_swapEndianS16(internalShadowCopy->biquad.xn2);\n\t\tif (internalShadowCopy->biquad.b1 != 0)\n\t\t{\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t{\n\t\t\t\tfloat inputSample = sampleData[i] / 256.0f;\n\t\t\t\tfloat temp = b0 * inputSample + b1 * xn1 + b2 * xn2 + a1 * yn1 + a2 * yn2;\n\t\t\t\tsampleData[i] = temp * 256.0f;\n\t\t\t\ttemp = std::min(32767.0f, temp);\n\t\t\t\ttemp = std::max(-32768.0f, temp);\n\t\t\t\tyn2 = yn1;\n\t\t\t\txn2 = xn1;\n\t\t\t\tyn1 = temp;\n\t\t\t\txn1 = inputSample;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// optimized variant where voiceInternal->biquad.b1 is hardcoded as zero (used heavily in BotW and Splatoon)\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t{\n\t\t\t\tfloat inputSample = sampleData[i] / 256.0f;\n\t\t\t\tfloat temp = b0 * inputSample + b2 * xn2 + a1 * yn1 + a2 * yn2;\n\t\t\t\tsampleData[i] = temp * 256.0f;\n\t\t\t\ttemp = std::min(32767.0f, temp);\n\t\t\t\ttemp = std::max(-32768.0f, temp);\n\t\t\t\tyn2 = yn1;\n\t\t\t\txn2 = xn1;\n\t\t\t\tyn1 = temp;\n\t\t\t\txn1 = inputSample;\n\t\t\t}\n\t\t}\n\n\t\tinternalShadowCopy->biquad.yn1 = _swapEndianU16((sint16)(yn1));\n\t\tinternalShadowCopy->biquad.yn2 = _swapEndianU16((sint16)(yn2));\n\t\tinternalShadowCopy->biquad.xn1 = _swapEndianU16((sint16)(xn1));\n\t\tinternalShadowCopy->biquad.xn2 = _swapEndianU16((sint16)(xn2));\n\t}\n\n\tvoid AXVoiceMix_ApplyLowPass(AXVPBInternal_t* internalShadowCopy, float* sampleData, sint32 sampleCount)\n\t{\n\t\tif (internalShadowCopy->lpf.on == _swapEndianU16(AX_LPF_OFF))\n\t\t\treturn;\n\t\tfloat a0 = (float)_swapEndianS16(internalShadowCopy->lpf.a0) / 32767.0f;\n\t\tfloat b0 = (float)_swapEndianS16(internalShadowCopy->lpf.b0) / 32767.0f;\n\t\tfloat prevSample = (float)_swapEndianS16((sint16)internalShadowCopy->lpf.yn1) * 256.0f / 32767.0f;\n\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t{\n\t\t\tsampleData[i] = a0 * sampleData[i] - b0 * prevSample;\n\t\t\tprevSample = sampleData[i];\n\t\t}\n\t\tinternalShadowCopy->lpf.yn1 = (uint16)_swapEndianS16((sint16)(prevSample / 256.0f * 32767.0f));\n\t}\n\n\t// mix audio generated from voice into main bus and aux buses\n\tvoid AXVoiceMix_MixIntoBuses(AXVPBInternal_t* internalShadowCopy, float* sampleData, sint32 sampleCount, sint32 samplesPerFrame)\n\t{\n\t\t// TV mixing\n\t\tfor (sint32 busIndex = 0; busIndex < AX_BUS_COUNT; busIndex++)\n\t\t{\n\t\t\tfor (sint32 channel = 0; channel < 6; channel++)\n\t\t\t{\n\t\t\t\tuint32 channelMixMask = (_swapEndianU16(internalShadowCopy->deviceMixMaskTV[busIndex]) >> (channel * 2)) & 3;\n\t\t\t\tif (channelMixMask == 0)\n\t\t\t\t{\n\t\t\t\t\tinternalShadowCopy->reserved1E8[busIndex*AX_TV_CHANNEL_COUNT + channel] = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tAXCHMIX_DEPR* mix = internalShadowCopy->deviceMixTV + channel * 4 + busIndex;\n\t\t\t\tfloat* output = __AXMixBufferTV + (busIndex * 6 + channel) * samplesPerFrame;\n\t\t\t\tAXVoiceMix_MergeInto(sampleData, output, sampleCount, mix, _swapEndianS16(mix->delta));\n\t\t\t\tinternalShadowCopy->reserved1E8[busIndex*AX_TV_CHANNEL_COUNT + channel] = mix->vol;\n\t\t\t}\n\t\t}\n\t\t// DRC0 mixing\n\t\tfor (sint32 busIndex = 0; busIndex < AX_BUS_COUNT; busIndex++)\n\t\t{\n\t\t\tfor (sint32 channel = 0; channel < AX_DRC_CHANNEL_COUNT; channel++)\n\t\t\t{\n\t\t\t\tuint32 channelMixMask = (_swapEndianU16(internalShadowCopy->deviceMixMaskDRC[busIndex]) >> (channel * 2)) & 3;\n\n\t\t\t\tif (channelMixMask == 0)\n\t\t\t\t{\n\t\t\t\t\t//internalShadowCopy->reserved1E8[busIndex*AX_DRC_CHANNEL_COUNT + channel] = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tAXCHMIX_DEPR* mix = internalShadowCopy->deviceMixDRC + channel * 4 + busIndex;\n\t\t\t\tfloat* output = __AXMixBufferDRC + (busIndex * AX_DRC_CHANNEL_COUNT + channel) * samplesPerFrame;\n\t\t\t\tAXVoiceMix_MergeInto(sampleData, output, sampleCount, mix, _swapEndianS16(mix->delta));\n\t\t\t}\n\t\t}\n\n\t\t// DRC1 mixing + RMT mixing\n\t\t// todo\n\t}\n\n\tvoid AXMix_ProcessVoices(AXVPBInternal_t* firstVoice)\n\t{\n\t\tif (firstVoice == nullptr)\n\t\t\treturn;\n\t\tsize_t sampleCount = AXGetInputSamplesPerFrame();\n\t\tAXVPBInternal_t* internalVoice = firstVoice;\n\t\tcemu_assert_debug(sndGeneric.initParam.frameLength == 0);\n\t\tfloat tmpSampleBuffer[AX_SAMPLES_MAX];\n\t\twhile (internalVoice)\n\t\t{\n\t\t\tAXVoiceMix_DecodeSamples(internalVoice, tmpSampleBuffer, sampleCount);\n\t\t\tAXVoiceMix_ApplyADSR(internalVoice, tmpSampleBuffer, sampleCount);\n\t\t\tAXVoiceMix_ApplyBiquad(internalVoice, tmpSampleBuffer, sampleCount);\n\t\t\tAXVoiceMix_ApplyLowPass(internalVoice, tmpSampleBuffer, sampleCount);\n\t\t\tAXVoiceMix_MixIntoBuses(internalVoice, tmpSampleBuffer, sampleCount, sampleCount);\n\t\t\t// next\n\t\t\tinternalVoice = internalVoice->nextToProcess.GetPtr();\n\t\t}\n\t}\n\n\tvoid AXMix_MergeBusSamples(float* input, sint32* output, sint32 sampleCount, uint16& volume, sint16 delta)\n\t{\n\t\tfloat volumeF = (float)volume / 32768.0f;\n\t\tfloat deltaF = (float)delta / 32768.0f;\n\n\t\tif (delta)\n\t\t{\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t{\n\t\t\t\tfloat s = *input;\n\t\t\t\tinput++;\n\t\t\t\ts *= volumeF;\n\t\t\t\tvolumeF += deltaF;\n\t\t\t\t*output = _swapEndianS32(_swapEndianS32(*output) + (sint32)s);\n\t\t\t\toutput++;\n\t\t\t}\n\t\t\tvolume = (uint16)(volumeF * 32768.0f);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// no delta\n\t\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t\t{\n\t\t\t\tfloat s = *input;\n\t\t\t\tinput++;\n\t\t\t\ts *= volumeF;\n\t\t\t\t*output = _swapEndianS32(_swapEndianS32(*output) + (sint32)s);\n\t\t\t\toutput++;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid AXAuxMix_StoreAuxSamples(float* input, sint32be* output, sint32 sampleCount)\n\t{\n\t\t// Not 100% sure why but we need to temporarily right shift the aux samples by 8 to get the sample range the games expect for the AUX callback\n\t\t// without this, Color Splash will apply it's effects incorrectly\n\t\t// Its probably because AUX mixing always goes through the DSP which uses 16bit arithmetic?\n\n\t\t// no delta\n\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t{\n\t\t\tfloat s = *input;\n\t\t\tinput++;\n\t\t\t*output = ((sint32)s) >> 8;\n\t\t\toutput++;\n\t\t}\n\t}\n\n\tvoid AXAuxMix_MixProcessedAuxSamplesIntoOutput(sint32be* input, float* output, sint32 sampleCount, uint16* volumePtr, sint16 delta)\n\t{\n\t\tuint16 volume = *volumePtr;\n\t\tfloat volumeF = (float)volume / 32768.0f;\n\t\tfloat deltaF = (float)delta / 32768.0f;\n\n\t\tcemu_assert_debug(delta == 0); // todo\n\n\t\tfor (sint32 i = 0; i < sampleCount; i++)\n\t\t{\n\t\t\tfloat s = (float)(((sint32)*input)<<8);\n\t\t\tinput++;\n\t\t\ts *= volumeF;\n\t\t\t*output += s;\n\t\t\toutput++;\n\t\t}\n\t\t*volumePtr = volume;\n\t}\n\n\tuint16 __AXMasterVolume = 0x8000;\n\tuint16 __AXDRCMasterVolume = 0x8000;\n\n\t// mix into __AXTVOutputBuffer\n\tvoid AXMix_mergeTVBuses()\n\t{\n\t\tsize_t sampleCount = AXGetInputSamplesPerFrame();\n\n\t\t// debug - Erase main bus and only output AUX\n\t\tif (ActiveSettings::AudioOutputOnlyAux())\n\t\t{\n\t\t\tmemset(__AXMixBufferTV, 0, sizeof(float) * sampleCount * 6);\n\t\t}\n\t\t// Mix aux into TV main bus\n\t\tfor (sint32 auxBus = 0; auxBus < AX_AUX_BUS_COUNT; auxBus++)\n\t\t{\n\t\t\tsint32be* auxOutput = AXAux_GetOutputBuffer(AX_DEV_TV, 0, auxBus);\n\t\t\tif (auxOutput == nullptr)\n\t\t\t\tcontinue;\n\t\t\t// AUX return from output buffer\n\t\t\tuint16 auxReturnVolume = __AXTVAuxReturnVolume[auxBus];\n\t\t\tsint16 auxReturnDelta = 0;\n\t\t\tAXAuxMix_MixProcessedAuxSamplesIntoOutput(auxOutput, __AXMixBufferTV, sampleCount * AX_TV_CHANNEL_COUNT, &auxReturnVolume, auxReturnDelta);\n\t\t}\n\t\t// mix TV main bus into output\n\t\tfloat* input = __AXMixBufferTV;\n\t\tuint16 masterVolume = __AXMasterVolume;\n\t\tsint32* output = __AXTVOutputBuffer.GetPtr();\n\t\tcemu_assert_debug(masterVolume == 0x8000); // todo -> Calculate delta between old master volume and new volume\n\t\tsint16 delta = 0;\n\t\tuint16 volVar;\n\t\tfor (uint16 c = 0; c < AX_TV_CHANNEL_COUNT; c++)\n\t\t{\n\t\t\tvolVar = _swapEndianU16(masterVolume);\n\t\t\tAXMix_MergeBusSamples(input, output, sampleCount, masterVolume, delta);\n\t\t\toutput += sampleCount;\n\t\t\tinput += sampleCount;\n\t\t}\n\t}\n\n\t// mix into __AXDRCOutputBuffer\n\tvoid AXMix_mergeDRC0Buses()\n\t{\n\t\tsint32* output = __AXDRCOutputBuffer.GetPtr();\n\t\tuint16 masterVolume = __AXDRCMasterVolume;\t\t\n\t\tsize_t sampleCount = AXGetInputSamplesPerFrame();\n\n\t\t// todo - drc0 AUX\n\n\t\t// mix DRC0 main bus into output\n\t\tfloat* input = __AXMixBufferDRC;\n\t\tcemu_assert_debug(masterVolume == 0x8000); // todo -> Calculate delta between old master volume and new volume\n\t\tsint16 delta = 0;\n\t\tfor (uint16 c = 0; c < AX_DRC_CHANNEL_COUNT; c++)\n\t\t{\n\t\t\tAXMix_MergeBusSamples(input, output, sampleCount, masterVolume, delta);\n\t\t\toutput += sampleCount;\n\t\t\tinput += sampleCount;\n\t\t}\n\t}\n\n\tvoid AXMix_process(AXVPBInternal_t* internalShadowCopyHead)\n\t{\n\t\tmemset(__AXMixBufferTV, 0, sizeof(__AXMixBufferTV));\n\t\tmemset(__AXMixBufferDRC, 0, sizeof(__AXMixBufferDRC));\n\n\t\tAXMix_ProcessVoices(internalShadowCopyHead);\n\t\tAXAux_Process(); // apply AUX effects to previous frame\n\t\tAXIst_HandleFrameCallbacks();\n\n\t\tsize_t sampleCount = AXGetInputSamplesPerFrame();\n\t\t// TV aux store\n\t\tfor (sint32 auxBus = 0; auxBus < AX_AUX_BUS_COUNT; auxBus++)\n\t\t{\n\t\t\tsint32be* auxInput = AXAux_GetInputBuffer(AX_DEV_TV, 0, auxBus);\n\t\t\tif (auxInput == nullptr)\n\t\t\t\tcontinue;\n\t\t\tfloat* tvInput = __AXMixBufferTV + (1 + auxBus) * (sampleCount * AX_TV_CHANNEL_COUNT);\n\t\t\tAXAuxMix_StoreAuxSamples(tvInput, auxInput, sampleCount * AX_TV_CHANNEL_COUNT);\n\t\t}\n\n\t\t// DRC aux store\n\t\t// todo\n\n\t\t// merge main and aux buses\n\t\tAXMix_mergeTVBuses();\n\t\tAXMix_mergeDRC0Buses();\n\n\t\tAXAux_incrementBufferIndex();\n\t\t// update microphone\n\t\tmic_updateOnAXFrame();\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/snd_core/ax_multivoice.cpp",
    "content": "#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/snd_core/ax_internal.h\"\n#include \"Cafe/HW/MMU/MMU.h\"\n\nnamespace snd_core\n{\n\tstatic_assert(sizeof(AXVPBMULTI) == 0x20, \"\");\n\n\tSysAllocator<AXVPBMULTI, AX_MAX_VOICES> _buffer__AXVPBMultiVoiceArray;\n\tAXVPBMULTI* __AXVPBMultiVoiceArray;\n\n\tvoid AXMultiVoice_Init()\n\t{\n\t\t__AXVPBMultiVoiceArray = _buffer__AXVPBMultiVoiceArray.GetPtr();\n\t\tfor (sint32 i = 0; i < AX_MAX_VOICES; i++)\n\t\t{\n\t\t\t__AXVPBMultiVoiceArray[i].isUsed = 0;\n\t\t}\n\t}\n\n\tsint32 AXAcquireMultiVoice(sint32 voicePriority, void* cbFunc, void* cbData, AXMULTIVOICEUKNSTRUCT* uknR6, MEMPTR<AXVPBMULTI>* multiVoiceOut)\n\t{\n\t\tfor (sint32 i = 0; i < AX_MAX_VOICES; i++)\n\t\t{\n\t\t\tif (__AXVPBMultiVoiceArray[i].isUsed == (uint32)0)\n\t\t\t{\n\t\t\t\tsint16 channelCount = uknR6->channelCount;\n\t\t\t\tif (channelCount <= 0 || channelCount > 6)\n\t\t\t\t{\n\t\t\t\t\treturn -0x15;\n\t\t\t\t}\n\t\t\t\tfor (sint32 f = 0; f < channelCount; f++)\n\t\t\t\t{\n\t\t\t\t\t__AXVPBMultiVoiceArray[i].voice[f] = nullptr;\n\t\t\t\t}\n\t\t\t\t__AXVPBMultiVoiceArray[i].isUsed = 1;\n\t\t\t\tfor (sint32 f = 0; f < channelCount; f++)\n\t\t\t\t{\n\t\t\t\t\tAXVPB* vpb = AXAcquireVoiceEx(voicePriority, memory_getVirtualOffsetFromPointer(cbFunc), memory_getVirtualOffsetFromPointer(cbData));\n\t\t\t\t\tif (vpb == nullptr)\n\t\t\t\t\t{\n\t\t\t\t\t\tAXFreeMultiVoice(__AXVPBMultiVoiceArray + i);\n\t\t\t\t\t\treturn -0x16;\n\t\t\t\t\t}\n\t\t\t\t\t__AXVPBMultiVoiceArray[i].voice[f] = vpb;\n\t\t\t\t}\n\t\t\t\t__AXVPBMultiVoiceArray[i].channelCount = channelCount;\n\t\t\t\t*multiVoiceOut = (__AXVPBMultiVoiceArray+i);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\treturn -0x14;\n\t}\n\n\tvoid AXFreeMultiVoice(AXVPBMULTI* multiVoice)\n\t{\n\t\tcemu_assert_debug(multiVoice->isUsed != (uint32)0);\n\t\tuint16 numChannels = multiVoice->channelCount;\n\t\tfor (uint16 i = 0; i < numChannels; i++)\n\t\t{\n\t\t\tif(multiVoice->voice[i] != nullptr)\n\t\t\t\tAXFreeVoice(multiVoice->voice[i].GetPtr());\n\t\t\tmultiVoice->voice[i] = nullptr;\n\t\t}\n\t\tmultiVoice->isUsed = 0;\n\t}\n\n\tsint32 AXGetMultiVoiceReformatBufferSize(sint32 voiceFormat, uint32 channelCount, uint32 sizeInBytes, uint32be* sizeOutput)\n\t{\n\t\t// used by Axiom Verge\n\t\tif (voiceFormat == AX_FORMAT_ADPCM)\n\t\t{\n\t\t\tsint32 alignedSize = (sizeInBytes + 7) & ~7;\n\t\t\t*sizeOutput = alignedSize * channelCount;\n\t\t}\n\t\telse if (voiceFormat == AX_FORMAT_PCM16)\n\t\t{\n\t\t\t*sizeOutput = sizeInBytes;\n\t\t}\n\t\telse if (voiceFormat == AX_FORMAT_PCM8)\n\t\t{\n\t\t\t*sizeOutput = sizeInBytes<<1;\n\t\t}\n\t\telse\n\t\t\treturn -23;\n\t\treturn 0;\n\t}\n\n\tvoid AXSetMultiVoiceType(AXVPBMULTI* mv, uint16 type)\n\t{\n\t\tfor(uint32 i = 0; i < mv->channelCount; ++i)\n\t\t\tAXSetVoiceType(mv->voice[i].GetPtr(), type);\n\t}\n\n\tvoid AXSetMultiVoiceAdpcm(AXVPBMULTI* mv, AXDSPADPCM* adpcm)\n\t{\n\t\tstatic_assert(sizeof(AXDSPADPCM) == 0x60);\n\t\tfor (uint32 i = 0; i < mv->channelCount; ++i)\n\t\t{\n\t\t\tAXPBADPCM_t tmp;\n\t\t\ttmp.gain = adpcm[i].gain.bevalue();\n\t\t\ttmp.yn1 = adpcm[i].yn1.bevalue();\n\t\t\ttmp.yn2 = adpcm[i].yn2.bevalue();\n\t\t\ttmp.scale = adpcm[i].scale.bevalue();\n\n\t\t\tstatic_assert(sizeof(tmp.a) == sizeof(adpcm->coef));\n\t\t\tmemcpy(tmp.a, adpcm[i].coef, sizeof(tmp.a));\n\n\t\t\tAXSetVoiceAdpcm(mv->voice[i].GetPtr(), &tmp);\n\t\t}\n\t}\n\n\tvoid AXSetMultiVoiceSrcType(AXVPBMULTI* mv, uint32 type)\n\t{\n\t\tfor (uint32 i = 0; i < mv->channelCount; ++i)\n\t\t\tAXSetVoiceSrcType(mv->voice[i].GetPtr(), type);\n\t}\n\n\tvoid AXSetMultiVoiceOffsets(AXVPBMULTI* mv, AXPBOFFSET_t* offsets)\n\t{\n\t\tfor (uint32 i = 0; i < mv->channelCount; ++i)\n\t\t\tAXSetVoiceOffsets(mv->voice[i].GetPtr(), offsets + i);\n\t}\n\n\tvoid AXSetMultiVoiceVe(AXVPBMULTI* mv, AXPBVE* ve)\n\t{\n\t\tfor (uint32 i = 0; i < mv->channelCount; ++i)\n\t\t\tAXSetVoiceVe(mv->voice[i].GetPtr(), ve);\n\t}\n\t\n\tvoid AXSetMultiVoiceSrcRatio(AXVPBMULTI* mv, float ratio)\n\t{\n\t\tfor (uint32 i = 0; i < mv->channelCount; ++i)\n\t\t\tAXSetVoiceSrcRatio(mv->voice[i].GetPtr(), ratio);\n\t}\n\t\n\tvoid AXSetMultiVoiceSrc(AXVPBMULTI* mv, AXPBSRC_t* src)\n\t{\n\t\tfor (uint32 i = 0; i < mv->channelCount; ++i)\n\t\t\tAXSetVoiceSrc(mv->voice[i].GetPtr(), src);\n\t}\n\t\n\tvoid AXSetMultiVoiceLoop(AXVPBMULTI* mv, uint16 loop)\n\t{\n\t\tfor (uint32 i = 0; i < mv->channelCount; ++i)\n\t\t\tAXSetVoiceLoop(mv->voice[i].GetPtr(), loop);\n\t}\n\t\n\tvoid AXSetMultiVoiceState(AXVPBMULTI* mv, uint16 state)\n\t{\n\t\tfor (uint32 i = 0; i < mv->channelCount; ++i)\n\t\t\tAXSetVoiceState(mv->voice[i].GetPtr(), state);\n\t}\n\t\n\tvoid AXSetMultiVoiceAdpcmLoop(AXVPBMULTI* mv, AXPBADPCMLOOP_t* loops)\n\t{\n\t\tfor (uint32 i = 0; i < mv->channelCount; ++i)\n\t\t\tAXSetVoiceAdpcmLoop(mv->voice[i].GetPtr(), loops + i);\n\t}\n\n\tsint32 AXIsMultiVoiceRunning(AXVPBMULTI* mv)\n\t{\n\t\tconst sint32 result = AXIsVoiceRunning(mv->voice[0].GetPtr());\n\t\treturn result;\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/snd_core/ax_out.cpp",
    "content": "#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/snd_core/ax_internal.h\"\n#include \"Cafe/HW/MMU/MMU.h\"\n#include \"audio/IAudioAPI.h\"\n//#include \"ax.h\"\n#include \"config/CemuConfig.h\"\n\nnamespace snd_core\n{\n\tuint32 numProcessedFrames = 0;\n\n\tvoid resetNumProcessedFrames()\n\t{\n\t\tnumProcessedFrames = 0;\n\t}\n\n\tuint32 getNumProcessedFrames()\n\t{\n\t\treturn numProcessedFrames;\n\t}\n\n\tsint32 __AXMode[AX_DEV_COUNT]; // audio mode (AX_MODE_*) per device\n\n\n\tbool AVMGetTVAudioMode(uint32be* tvAudioMode)\n\t{\n\t\t// 0 -> mono\n\t\t// 1,2 -> stereo\n\t\t// 3 -> surround\n\t\t// 4 -> unknown mode\n\t\tswitch (GetConfig().tv_channels)\n\t\t{\n\t\tcase kMono:\n\t\t\t*tvAudioMode = 0;\n\t\t\tbreak;\n\t\tcase kSurround:\n\t\t\t*tvAudioMode = 3;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t*tvAudioMode = 2;\n\t\t\tbreak;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool AVMGetDRCSystemAudioMode(uint32be* drcAudioMode)\n\t{\n\t\t*drcAudioMode = 1; // apparently the default is Stereo(?), MH3U exits if AXGetDeviceMode doesn't return 0 (DRCSystemAudioMode must return 1 to set DRC mode to 0)\n\t\treturn true;\n\t}\n\n\tsint32 __AXOutTVOutputChannelCount;\n\tsint32 __AXOutDRCOutputChannelCount;\n\n\tvoid __AXSetTVMode(sint32 mode)\n\t{\n\t\tcemu_assert(mode == AX_MODE_STEREO || mode == AX_MODE_6CH || mode == AX_MODE_MONO);\n\t\t__AXMode[AX_DEV_TV] = mode;\n\t}\n\n\tvoid __AXSetDeviceMode(sint32 device, sint32 mode)\n\t{\n\t\tif (device == AX_DEV_TV)\n\t\t\t__AXMode[AX_DEV_TV] = mode;\n\t\telse if (device == AX_DEV_DRC)\n\t\t\t__AXMode[AX_DEV_DRC] = mode;\n\t\telse if (device == AX_DEV_RMT)\n\t\t\t__AXMode[AX_DEV_RMT] = mode;\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\n\tsint32 AXGetDeviceMode(sint32 device)\n\t{\n\t\tif (device == AX_DEV_TV || device == AX_DEV_DRC || device == AX_DEV_RMT)\n\t\t\treturn __AXMode[device];\n\t\tcemu_assert_debug(false);\n\t\treturn 0;\n\t}\n\n\tvoid _AXOutInitDeviceModes()\n\t{\n\t\t// TV mode\n\t\tuint32be tvAudioMode;\n\t\tAVMGetTVAudioMode(&tvAudioMode);\n\t\tif (tvAudioMode == 0)\n\t\t{\n\t\t\t// mono\n\t\t\t__AXSetTVMode(AX_MODE_MONO);\n\t\t\t__AXOutTVOutputChannelCount = 1;\n\t\t}\n\t\telse if (tvAudioMode == 1 || tvAudioMode == 2)\n\t\t{\n\t\t\t// stereo\n\t\t\t__AXSetTVMode(AX_MODE_STEREO);\n\t\t\t__AXOutTVOutputChannelCount = 2;\n\t\t}\n\t\telse if (tvAudioMode == 3)\n\t\t{\n\t\t\t// surround (6ch)\n\t\t\t__AXSetTVMode(AX_MODE_6CH);\n\t\t\t__AXOutTVOutputChannelCount = 6;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t\t// DRC mode\n\t\tuint32be drcAudioMode;\n\t\tAVMGetDRCSystemAudioMode(&drcAudioMode);\n\t\tif (drcAudioMode == 0)\n\t\t{\n\t\t\t// mono\n\t\t\t__AXSetDeviceMode(1, AX_MODE_MONO);\n\t\t\t__AXOutDRCOutputChannelCount = 1;\n\t\t}\n\t\telse if (drcAudioMode == 2)\n\t\t{\n\t\t\t// surround\n\t\t\t__AXSetDeviceMode(1, AX_MODE_SURROUND);\n\t\t\t__AXOutDRCOutputChannelCount = 2; // output channel count still 2 for DRC 'surround'\n\t\t}\n\t\telse if (drcAudioMode == 1)\n\t\t{\n\t\t\t// stereo\n\t\t\t__AXSetDeviceMode(1, AX_MODE_STEREO);\n\t\t\t__AXOutDRCOutputChannelCount = 2;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t}\n\n\tvoid AXOut_Init()\n\t{\n\t\t_AXOutInitDeviceModes();\n\t}\n\n\textern SysAllocator<sint32, AX_SAMPLES_MAX * AX_TV_CHANNEL_COUNT> __AXTVBuffer48;\n\textern SysAllocator<sint32, AX_SAMPLES_MAX* AX_DRC_CHANNEL_COUNT * 2> __AXDRCBuffer48;\n\n\tsint16 __buf_AXTVDMABuffers_0[AX_SAMPLES_MAX * AX_TV_CHANNEL_COUNT];\n\tsint16 __buf_AXTVDMABuffers_1[AX_SAMPLES_MAX * AX_TV_CHANNEL_COUNT];\n\tsint16 __buf_AXTVDMABuffers_2[AX_SAMPLES_MAX * AX_TV_CHANNEL_COUNT];\n\tsint16* __AXTVDMABuffers[3] = {__buf_AXTVDMABuffers_0, __buf_AXTVDMABuffers_1, __buf_AXTVDMABuffers_2};\n\n\t#define AX_FRAMES_PER_GROUP\t\t(4)\n\n\tsint16 tempTVChannelData[AX_SAMPLES_MAX * AX_TV_CHANNEL_COUNT * AX_FRAMES_PER_GROUP] = {};\n\tsint32 tempAudioBlockCounter = 0;\n\n\n\tsint16 __buf_AXDRCDMABuffers_0[AX_SAMPLES_MAX * 6];\n\tsint16 __buf_AXDRCDMABuffers_1[AX_SAMPLES_MAX * 6];\n\tsint16 __buf_AXDRCDMABuffers_2[AX_SAMPLES_MAX * 6];\n\tsint16* __AXDRCDMABuffers[3] = { __buf_AXDRCDMABuffers_0, __buf_AXDRCDMABuffers_1, __buf_AXDRCDMABuffers_2 };\n\n\tsint16 tempDRCChannelData[AX_SAMPLES_MAX * 6 * AX_FRAMES_PER_GROUP] = {};\n\tsint32 tempDRCAudioBlockCounter = 0;\n\n\tvoid AIInitDMA(sint16* sampleData, sint32 size)\n\t{\n\t\tsint32 sampleCount = size / sizeof(sint16); // sample count in total (summed up for all channels)\n\n\t\tif (sndGeneric.initParam.frameLength != 0)\n\t\t{\n\t\t\tcemu_assert(false);\n\t\t}\n\n\t\tstd::shared_lock lock(g_audioMutex);\n\n\t\tconst uint32 channels = g_tvAudio ? g_tvAudio->GetChannels() : AX_TV_CHANNEL_COUNT;\n\t\tsint16* outputChannel = tempTVChannelData + AX_SAMPLES_PER_3MS_48KHZ * tempAudioBlockCounter * channels;\n\t\tfor (sint32 i = 0; i < sampleCount; ++i)\n\t\t{\n\t\t\toutputChannel[i] = _swapEndianS16(sampleData[i]);\n\t\t}\n\n\t\ttempAudioBlockCounter++;\n\t\tif (tempAudioBlockCounter == AX_FRAMES_PER_GROUP)\n\t\t{\n\t\t\tif(g_tvAudio)\n\t\t\t\tg_tvAudio->FeedBlock(tempTVChannelData);\n\n\t\t\ttempAudioBlockCounter = 0;\n\t\t}\n\t}\n\n\tsint32 AIGetSamplesPerChannel(uint32 device)\n\t{\n\t\t// TV and DRC output the same number of samples\n\t\treturn AX_SAMPLES_PER_3MS_48KHZ;\n\t}\n\n\tsint32 AIGetChannelCount(uint32 device)\n\t{\n\t\tif (__AXMode[device] == AX_MODE_6CH)\n\t\t\treturn 6;\n\t\tif (__AXMode[device] == AX_MODE_STEREO)\n\t\t\treturn 2;\n\t\t// default to mono\n\t\treturn 1;\n\t}\n\n\tsint16* AIGetCurrentDMABuffer(uint32 device)\n\t{\n\t\tif (device == AX_DEV_TV)\n\t\t\treturn __AXTVDMABuffers[0];\n\t\telse if (device == AX_DEV_DRC)\n\t\t\treturn __AXDRCDMABuffers[0];\n\t\tcemu_assert_debug(false);\n\t\treturn nullptr;\n\t}\n\n\tvoid AXOut_SubmitTVFrame(sint32 frameIndex)\n\t{\n\t\tsint32 numSamples = AIGetSamplesPerChannel(AX_DEV_TV);\n\t\tif (__AXMode[AX_DEV_TV] == AX_MODE_6CH)\n\t\t{\n\t\t\tsint32* inputChannel0 = __AXTVBuffer48.GetPtr() + numSamples * 0;\n\t\t\tsint32* inputChannel1 = __AXTVBuffer48.GetPtr() + numSamples * 1;\n\t\t\tsint32* inputChannel2 = __AXTVBuffer48.GetPtr() + numSamples * 2;\n\t\t\tsint32* inputChannel3 = __AXTVBuffer48.GetPtr() + numSamples * 3;\n\t\t\tsint32* inputChannel4 = __AXTVBuffer48.GetPtr() + numSamples * 4;\n\t\t\tsint32* inputChannel5 = __AXTVBuffer48.GetPtr() + numSamples * 5;\n\t\t\tsint16* dmaOutputBuffer = AIGetCurrentDMABuffer(AX_DEV_TV);\n\t\t\tfor (sint32 i = 0; i < numSamples; i++)\n\t\t\t{\n\t\t\t\t/*\n\t\t\t\t* DirectSound surround order\n\t\t\t\tLEFT\t\t\t\t0\n\t\t\t\tRIGHT\t\t\t\t1\n\t\t\t\tSUR_LEFT\t\t\t2\n\t\t\t\tSUR_RIGHT\t\t\t3\n\t\t\t\tCH_FC\t\t\t\t4\n\t\t\t\tCH_LFE\t\t\t\t5\n\t\t\t\t=>\n\t\t\t\tFront Left - FL\t\t\t0\n\t\t\t\tFront Right - FR\t\t1\n\t\t\t\tFront Center - FC\t\t2\n\t\t\t\tLow Frequency - LF\t\t3\n\t\t\t\tBack Left - BL\t\t\t4\n\t\t\t\tBack Right - BR\t\t\t5\n\t\t\t\t*/\n\t\t\t\tdmaOutputBuffer[0] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel0), -32768), 32767));\n\t\t\t\tdmaOutputBuffer[1] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel1), -32768), 32767));\n\n\t\t\t\tdmaOutputBuffer[4] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel2), -32768), 32767));\n\t\t\t\tdmaOutputBuffer[5] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel3), -32768), 32767));\n\n\t\t\t\tdmaOutputBuffer[2] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel4), -32768), 32767));\n\t\t\t\tdmaOutputBuffer[3] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel5), -32768), 32767));\n\t\t\t\tdmaOutputBuffer += 6;\n\t\t\t\t// next sample\n\t\t\t\tinputChannel0++;\n\t\t\t\tinputChannel1++;\n\t\t\t\tinputChannel2++;\n\t\t\t\tinputChannel3++;\n\t\t\t\tinputChannel4++;\n\t\t\t\tinputChannel5++;\n\t\t\t}\n\t\t\tAIInitDMA(__AXTVDMABuffers[frameIndex], numSamples * 6 * sizeof(sint16)); // 6ch output\n\t\t}\n\t\telse if (__AXMode[AX_DEV_TV] == AX_MODE_STEREO)\n\t\t{\n\t\t\tsint32* inputChannel0 = __AXTVBuffer48.GetPtr() + numSamples * 0;\n\t\t\tsint32* inputChannel1 = __AXTVBuffer48.GetPtr() + numSamples * 1;\n\t\t\tsint16* dmaOutputBuffer = __AXTVDMABuffers[frameIndex];\n\t\t\tfor (sint32 i = 0; i < numSamples; i++)\n\t\t\t{\n\t\t\t\tdmaOutputBuffer[0] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel0), -32768), 32767));\n\t\t\t\tdmaOutputBuffer[1] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel1), -32768), 32767));\n\t\t\t\tdmaOutputBuffer += 2;\n\t\t\t\t// next sample\n\t\t\t\tinputChannel0++;\n\t\t\t\tinputChannel1++;\n\t\t\t}\n\t\t\tAIInitDMA(__AXTVDMABuffers[frameIndex], numSamples * 2 * sizeof(sint16)); // 2ch output\n\t\t}\n\t\telse if (__AXMode[AX_DEV_TV] == AX_MODE_MONO)\n\t\t{\n\t\t\tsint32* inputChannel0 = __AXTVBuffer48.GetPtr() + numSamples * 0;\n\t\t\tsint16* dmaOutputBuffer = __AXTVDMABuffers[frameIndex];\n\t\t\tfor (sint32 i = 0; i < numSamples; i++)\n\t\t\t{\n\t\t\t\tdmaOutputBuffer[0] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel0), -32768), 32767));\n\t\t\t\tdmaOutputBuffer++;\n\t\t\t\t// next sample\n\t\t\t\tinputChannel0++;\n\t\t\t}\n\t\t\tAIInitDMA(__AXTVDMABuffers[frameIndex], numSamples * 1 * sizeof(sint16)); // 1ch (output as stereo)\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n\n\tvoid AIInitDRCDMA(sint16* sampleData, sint32 size)\n\t{\n\t\tsint32 sampleCount = size / sizeof(sint16); // sample count in total (summed up for all channels)\n\n\t\tif (sndGeneric.initParam.frameLength != 0)\n\t\t{\n\t\t\tcemu_assert(false);\n\t\t}\n\n\t\tstd::shared_lock lock(g_audioMutex);\n\n\t\tconst uint32 channels = g_padAudio ? g_padAudio->GetChannels() : AX_DRC_CHANNEL_COUNT;\n\t\tsint16* outputChannel = tempDRCChannelData + AX_SAMPLES_PER_3MS_48KHZ * tempDRCAudioBlockCounter * channels;\n\t\tfor (sint32 i = 0; i < sampleCount; ++i)\n\t\t{\n\t\t\toutputChannel[i] = _swapEndianS16(sampleData[i]);\n\t\t}\n\n\t\ttempDRCAudioBlockCounter++;\n\t\tif (tempDRCAudioBlockCounter == AX_FRAMES_PER_GROUP)\n\t\t{\n\t\t\tif (g_padAudio)\n\t\t\t\tg_padAudio->FeedBlock(tempDRCChannelData);\n\n\t\t\ttempDRCAudioBlockCounter = 0;\n\t\t}\n\t}\n\n\tvoid AXOut_SubmitDRCFrame(sint32 frameIndex)\n\t{\n\t\tsint32 numSamples = AIGetSamplesPerChannel(AX_DEV_DRC);\n\t\tif (__AXMode[AX_DEV_DRC] == AX_MODE_6CH)\n\t\t{\n\t\t\tsint32* inputChannel0 = __AXDRCBuffer48.GetPtr() + numSamples * 0;\n\t\t\tsint32* inputChannel1 = __AXDRCBuffer48.GetPtr() + numSamples * 1;\n\t\t\tsint32* inputChannel2 = __AXDRCBuffer48.GetPtr() + numSamples * 2;\n\t\t\tsint32* inputChannel3 = __AXDRCBuffer48.GetPtr() + numSamples * 3;\n\t\t\tsint16* dmaOutputBuffer = AIGetCurrentDMABuffer(AX_DEV_DRC);\n\t\t\tfor (sint32 i = 0; i < numSamples; i++)\n\t\t\t{\n\t\t\t\tdmaOutputBuffer[0] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel0), -32768), 32767));\n\t\t\t\tdmaOutputBuffer[1] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel1), -32768), 32767));\n\n\t\t\t\tdmaOutputBuffer[4] = 0;\n\t\t\t\tdmaOutputBuffer[5] = 0;\n\n\t\t\t\tdmaOutputBuffer[2] = 0;\n\t\t\t\tdmaOutputBuffer[3] = 0;\n\t\t\t\tdmaOutputBuffer += 6;\n\t\t\t\t// next sample\n\t\t\t\tinputChannel0++;\n\t\t\t\tinputChannel1++;\n\t\t\t\tinputChannel2++;\n\t\t\t\tinputChannel3++;\n\t\t\t}\n\t\t\tAIInitDRCDMA(__AXDRCDMABuffers[frameIndex], numSamples * 6 * sizeof(sint16)); // 6ch output\n\t\t}\n\t\telse if (__AXMode[AX_DEV_DRC] == AX_MODE_STEREO)\n\t\t{\n\t\t\tsint32* inputChannel0 = __AXDRCBuffer48.GetPtr() + numSamples * 0;\n\t\t\tsint32* inputChannel1 = __AXDRCBuffer48.GetPtr() + numSamples * 1;\n\t\t\tsint16* dmaOutputBuffer = __AXDRCDMABuffers[frameIndex];\n\t\t\tfor (sint32 i = 0; i < numSamples; i++)\n\t\t\t{\n\t\t\t\tdmaOutputBuffer[0] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel0), -32768), 32767));\n\t\t\t\tdmaOutputBuffer[1] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel1), -32768), 32767));\n\t\t\t\tdmaOutputBuffer += 2;\n\t\t\t\t// next sample\n\t\t\t\tinputChannel0++;\n\t\t\t\tinputChannel1++;\n\t\t\t}\n\n\t\t\tAIInitDRCDMA(__AXDRCDMABuffers[frameIndex], numSamples * 2 * sizeof(sint16)); // 2ch output\n\t\t}\n\t\telse if (__AXMode[AX_DEV_DRC] == AX_MODE_MONO)\n\t\t{\n\t\t\tsint32* inputChannel0 = __AXDRCBuffer48.GetPtr() + numSamples * 0;\n\t\t\tsint16* dmaOutputBuffer = __AXDRCDMABuffers[frameIndex];\n\t\t\tfor (sint32 i = 0; i < numSamples; i++)\n\t\t\t{\n\t\t\t\t// write mono input as stereo output\n\t\t\t\tdmaOutputBuffer[1] = dmaOutputBuffer[0] = _swapEndianS16((sint16)std::min(std::max(_swapEndianS32(*inputChannel0), -32768), 32767));\n\t\t\t\tdmaOutputBuffer += 2;\n\t\t\t\t// next sample\n\t\t\t\tinputChannel0++;\n\t\t\t}\n\t\t\tAIInitDRCDMA(__AXDRCDMABuffers[frameIndex], numSamples * 2 * sizeof(sint16)); // 1ch (output as stereo)\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t}\n\n\t/* AX output */\n\n\tuint32 numQueuedFramesSndGeneric = 0;\n\n\tvoid AXOut_init()\n\t{\n\n\t\tnumQueuedFramesSndGeneric = 0;\n\n\t\tstd::unique_lock lock(g_audioMutex);\n\t\tif (!g_tvAudio)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tg_tvAudio = IAudioAPI::CreateDeviceFromConfig(IAudioAPI::AudioType::TV, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16);\n\t\t\t}\n\t\t\tcatch (std::runtime_error& ex)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"can't initialize tv audio: {}\", ex.what());\n\t\t\t}\n\t\t}\n\n\t\tg_padVolume = GetConfig().pad_volume;\n\t\tif (!g_padAudio)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tg_padAudio = IAudioAPI::CreateDeviceFromConfig(IAudioAPI::AudioType::Gamepad, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16);\n\t\t\t}\n\t\t\tcatch (std::runtime_error& ex)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"can't initialize pad audio: {}\", ex.what());\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid AXOut_reset()\n\t{\n\t\tstd::unique_lock lock(g_audioMutex);\n\t\tif (g_tvAudio)\n\t\t{\n\t\t\tg_tvAudio->Stop();\n\t\t\tg_tvAudio.reset();\n\t\t}\n\t\tif (g_padAudio)\n\t\t{\n\t\t\tg_padAudio->Stop();\n\t\t\tg_padAudio.reset();\n\t\t}\n\t\tif (g_portalAudio)\n\t\t{\n\t\t\tg_portalAudio->Stop();\n\t\t\tg_portalAudio.reset();\n\t\t}\n\t}\n\n\tvoid AXOut_updateDevicePlayState(bool isPlaying)\n\t{\n\t\tstd::shared_lock lock(g_audioMutex);\n\t\tif (g_tvAudio)\n\t\t{\n\t\t\tif (isPlaying)\n\t\t\t\tg_tvAudio->Play();\n\t\t\telse\n\t\t\t\tg_tvAudio->Stop();\n\t\t}\n\n\t\tif (g_padAudio)\n\t\t{\n\t\t\tif (isPlaying)\n\t\t\t\tg_padAudio->Play();\n\t\t\telse\n\t\t\t\tg_padAudio->Stop();\n\t\t}\n\n\t\tif (g_portalAudio)\n\t\t{\n\t\t\tif (isPlaying)\n\t\t\t\tg_portalAudio->Play();\n\t\t\telse\n\t\t\t\tg_portalAudio->Stop();\n\t\t}\n\t}\n\n\t// called periodically to check for AX updates\n\tvoid AXOut_update()\n\t{\n\t\tconstexpr static auto kTimeout = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(((IAudioAPI::kBlockCount * 3) / 4) * (AX_FRAMES_PER_GROUP * 3)));\n\t\tconstexpr static auto kWaitDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(3));\n\t\tconstexpr static auto kWaitDurationFast = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::microseconds(2900));\n\t\tconstexpr static auto kWaitDurationMinimum = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::microseconds(1700));\n\n\t\t// if we haven't buffered any blocks, we will wait less time than usual\n\t\tbool additional_blocks_required = false;\n\t\t{\n\t\t\tconst std::shared_lock lock(g_audioMutex, std::try_to_lock);\n\t\t\tif (lock)\n\t\t\t\tadditional_blocks_required = (g_tvAudio && g_tvAudio->NeedAdditionalBlocks()) || (g_padAudio && g_padAudio->NeedAdditionalBlocks());\n\t\t}\n\n\t\tconst auto wait_duration = additional_blocks_required ? kWaitDurationFast : kWaitDuration;\n\n\t\t// s_ax_interval_timer increases by the wait period\n\t\t// it can lag behind by multiple periods (up to kTimeout) if there is minor stutter in the CPU thread\n\t\t// s_last_check is always set to the timestamp at the time of firing\n\t\t// it's used to enforce the minimum wait delay (we want to avoid calling AX update in quick succession because other threads may need to do work first) \n\n\t\tstatic auto s_ax_interval_timer = now_cached() - kWaitDuration;\n\t\tstatic auto s_last_check = now_cached();\n\n\t\tconst auto now = now_cached();\n\t\tconst auto diff = (now - s_ax_interval_timer);\n\n\t\tif (diff < wait_duration)\n\t\t\treturn;\n\n\t\t// handle minimum wait time (1.7MS)\n\t\tif ((now - s_last_check) < kWaitDurationMinimum)\n\t\t\treturn;\n\t\ts_last_check = now;\n\n\t\t// if we're too far behind, skip forward\n\t\tif (diff >= kTimeout)\n\t\t\ts_ax_interval_timer = (now - wait_duration);\n\t\telse\n\t\t\ts_ax_interval_timer += wait_duration;\n\n\n\t\tif (snd_core::isInitialized())\n\t\t{\n\t\t\tif (numQueuedFramesSndGeneric == snd_core::getNumProcessedFrames())\n\t\t\t{\n\t\t\t\tAXOut_updateDevicePlayState(true);\n\t\t\t\tsnd_core::AXIst_QueueFrame();\n\t\t\t\tnumQueuedFramesSndGeneric++;\n\t\t\t}\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/snd_core/ax_voice.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/snd_core/ax_internal.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"util/helpers/fspinlock.h\"\n\nnamespace snd_core\n{\n\tinline void AXSetSyncFlag(AXVPB* vpb, uint32 flags)\n\t{\n\t\tvpb->sync = (uint32be)((uint32)vpb->sync | flags);\n\t}\n\n\tinline void AXResetSyncFlag(AXVPB* vpb, uint32 flags)\n\t{\n\t\tvpb->sync = (uint32be)((uint32)vpb->sync & ~flags);\n\t}\n\n\t/* voice lists */\n\tFSpinlock __AXVoiceListSpinlock;\n\n\tstd::vector<AXVPB*> __AXVoicesPerPriority[AX_PRIORITY_MAX];\n\tstd::vector<AXVPB*> __AXFreeVoices;\n\n\tvoid AXVoiceList_AddFreeVoice(AXVPB* vpb)\n\t{\n\t\tcemu_assert(vpb->priority != AX_PRIORITY_FREE);\n\t\t__AXFreeVoices.push_back(vpb);\n\t\tvpb->prev = nullptr;\n\t\tvpb->next = nullptr;\n\t}\n\n\tAXVPB* AXVoiceList_GetFreeVoice()\n\t{\n\t\tif (__AXFreeVoices.empty())\n\t\t\treturn nullptr;\n\t\tAXVPB* vpb = __AXFreeVoices.back();\n\t\t__AXFreeVoices.pop_back();\n\t\treturn vpb;\n\t}\n\n\tstd::vector<AXVPB*>& AXVoiceList_GetFreeVoices()\n\t{\n\t\treturn __AXFreeVoices;\n\t}\n\n\tvoid AXVoiceList_AddVoice(AXVPB* vpb, sint32 priority)\n\t{\n\t\tcemu_assert(priority != AX_PRIORITY_FREE && priority < AX_PRIORITY_MAX);\n\t\t__AXVoicesPerPriority[priority].push_back(vpb);\n\t\tvpb->next = nullptr;\n\t\tvpb->prev = nullptr;\n\t\tvpb->priority = priority;\n\t}\n\n\tvoid AXVoiceList_RemoveVoice(AXVPB* vpb)\n\t{\n\t\tuint32 priority = (uint32)vpb->priority;\n\t\tcemu_assert(priority != AX_PRIORITY_FREE && priority < AX_PRIORITY_MAX);\n\t\tvectorRemoveByValue(__AXVoicesPerPriority[priority], vpb);\n\t}\n\n\tAXVPB* AXVoiceList_GetLeastRecentVoiceByPriority(uint32 priority)\n\t{\n\t\tcemu_assert(priority != AX_PRIORITY_FREE && priority < AX_PRIORITY_MAX);\n\t\tif (__AXVoicesPerPriority[priority].empty())\n\t\t\treturn nullptr;\n\t\treturn __AXVoicesPerPriority[priority].front();\n\t}\n\n\tstd::vector<AXVPB*>& AXVoiceList_GetListByPriority(uint32 priority)\n\t{\n\t\tcemu_assert(priority != AX_PRIORITY_FREE && priority < AX_PRIORITY_MAX);\n\t\treturn __AXVoicesPerPriority[priority];\n\t}\n\n    void AXVoiceList_Reset()\n    {\n        __AXFreeVoices.clear();\n        for (uint32 i = 0; i < AX_PRIORITY_MAX; i++)\n            __AXVoicesPerPriority[i].clear();\n    }\n\n\tSysAllocator<AXVPBInternal_t, AX_MAX_VOICES> _buffer__AXVPBInternalVoiceArray;\n\tAXVPBInternal_t* __AXVPBInternalVoiceArray;\n\n\tSysAllocator<AXVPBInternal_t, AX_MAX_VOICES> _buffer__AXVPBInternalVoiceShadowCopyArray;\n\tAXVPBInternal_t* __AXVPBInternalVoiceShadowCopyArrayPtr; // this is the array used by audio mixing (it's synced at the beginning of every audio frame with __AXVPBInternalVoiceArray)\n\n\tSysAllocator<AXVPBItd, AX_MAX_VOICES> _buffer__AXVPBItdArray;\n\tAXVPBItd* __AXVPBItdArrayPtr;\n\n\tSysAllocator<AXVPB, AX_MAX_VOICES> _buffer__AXVPBArray;\n\tAXVPB* __AXVPBArrayPtr;\n\n\tstruct AXUSERPROTECTION\n\t{\n\t\tMPTR threadMPTR;\n\t\tuint32 count;\n\t};\n\n\tuint32 __AXUserProtectionArraySize = 0;\n\tAXUSERPROTECTION __AXUserProtectionArray[AX_MAX_VOICES] = { 0 };\n\tAXUSERPROTECTION __AXVoiceProtection[AX_MAX_VOICES] = { 0 };\n\n\tbool AXUserIsProtected()\n\t{\n\t\treturn __AXUserProtectionArraySize != 0;\n\t}\n\n\tsint32 AXUserBegin()\n\t{\n\t\t// some games (e.g. Color Splash) can block themselves from calling AXSetVoice* API in time if a thread gets \n\t\t// rescheduled while inside a AXUserBegin() + AXUserEnd() block\n\t\t// to prevent this from happening we extend the current thread's quantum while the protection is raised\n\t\tPPCCore_boostQuantum(10000);\n\n\t\tif (AXIst_IsFrameBeingProcessed())\n\t\t{\n\t\t\treturn -2;\n\t\t}\n\t\tMPTR currentThreadMPTR = memory_getVirtualOffsetFromPointer(coreinit::OSGetCurrentThread());\n\t\tfor (sint32 i = __AXUserProtectionArraySize - 1; i >= 0; i--)\n\t\t{\n\t\t\tif (__AXUserProtectionArray[i].threadMPTR == currentThreadMPTR)\n\t\t\t{\n\t\t\t\tsint32 newCount = __AXUserProtectionArray[i].count + 1;\n\t\t\t\t__AXUserProtectionArray[i].count = newCount;\n\t\t\t\treturn newCount;\n\t\t\t}\n\t\t}\n\t\t// no matching entry found\n\t\tif (__AXUserProtectionArraySize >= AX_MAX_VOICES)\n\t\t{\n\t\t\t// no entry available\n\t\t\treturn -4;\n\t\t}\n\t\t// create new entry\n\t\tif (__AXUserProtectionArraySize < 0)\n\t\t\tassert_dbg();\n\t\tsint32 entryIndex = __AXUserProtectionArraySize;\n\t\t__AXUserProtectionArray[entryIndex].threadMPTR = currentThreadMPTR;\n\t\t__AXUserProtectionArray[entryIndex].count = 1;\n\t\t__AXUserProtectionArraySize++;\n\t\treturn 1;\n\t}\n\n\tsint32 AXUserEnd()\n\t{\n\t\tPPCCore_deboostQuantum(10000);\n\t\tif (AXIst_IsFrameBeingProcessed())\n\t\t\treturn -2;\n\t\tMPTR currentThreadMPTR = memory_getVirtualOffsetFromPointer(coreinit::OSGetCurrentThread());\n\t\tfor (sint32 i = __AXUserProtectionArraySize - 1; i >= 0; i--)\n\t\t{\n\t\t\tif (__AXUserProtectionArray[i].threadMPTR == currentThreadMPTR)\n\t\t\t{\n\t\t\t\tsint32 newCount = __AXUserProtectionArray[i].count - 1;\n\t\t\t\t__AXUserProtectionArray[i].count = newCount;\n\t\t\t\tif (__AXUserProtectionArray[i].count == 0)\n\t\t\t\t{\n\t\t\t\t\t// count == 0 -> remove entry\n\t\t\t\t\tif (i >= (sint32)(__AXUserProtectionArraySize - 1))\n\t\t\t\t\t{\n\t\t\t\t\t\t// entry is last in array, can just decrease array size\n\t\t\t\t\t\t__AXUserProtectionArraySize--;\n\t\t\t\t\t\t__AXUserProtectionArray[i].threadMPTR = MPTR_NULL;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// remove entry by shifting all remaining entries\n\t\t\t\t\t\t//for (sint32 f = i; f >= 0; f--)\n\t\t\t\t\t\t//{\n\t\t\t\t\t\t//\t__AXUserProtectionArray[f].threadMPTR = __AXUserProtectionArray[f + 1].threadMPTR;\n\t\t\t\t\t\t//\t__AXUserProtectionArray[f].count = __AXUserProtectionArray[f + 1].count;\n\t\t\t\t\t\t//}\n\t\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t\t}\n\t\t\t\t\t// remove entries associated with the current thread from __AXVoiceProtection[] if the count is zero\n\t\t\t\t\tfor (sint32 f = 0; f < AX_MAX_VOICES; f++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (__AXVoiceProtection[f].threadMPTR == currentThreadMPTR && __AXVoiceProtection[f].count == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t__AXVoiceProtection[f].threadMPTR = MPTR_NULL;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn newCount;\n\t\t\t}\n\t\t}\n\t\tcemu_assert_debug(false); // voice not found in list, did the game not call AXUserBegin()?\n\t\treturn -3;\n\t}\n\n\tbool AXVoiceProtection_IsProtectedByAnyThread(AXVPB* vpb)\n\t{\n\t\tsint32 index = vpb->index;\n\t\treturn __AXVoiceProtection[index].threadMPTR != MPTR_NULL;\n\t}\n\n\tbool AXVoiceProtection_IsProtectedByCurrentThread(AXVPB* vpb)\n\t{\n\t\tsint32 index = vpb->index;\n\t\tbool isProtected = false;\n\t\tif (AXIst_IsFrameBeingProcessed())\n\t\t\tisProtected = __AXVoiceProtection[index].threadMPTR != MPTR_NULL;\n\t\telse\n\t\t\tisProtected = __AXVoiceProtection[index].threadMPTR != memory_getVirtualOffsetFromPointer(coreinit::OSGetCurrentThread());\n\t\treturn isProtected;\n\t}\n\n\tvoid AXVoiceProtection_Acquire(AXVPB* vpb)\n\t{\n\t\tsint32 index = vpb->index;\n\t\tif (AXUserIsProtected() == false)\n\t\t\treturn;\n\t\tif (AXIst_IsFrameBeingProcessed())\n\t\t\treturn;\n\t\tif (__AXVoiceProtection[index].threadMPTR == MPTR_NULL)\n\t\t{\n\t\t\t__AXVoiceProtection[index].threadMPTR = memory_getVirtualOffsetFromPointer(coreinit::OSGetCurrentThread());\n\t\t\t// does not set count?\n\t\t}\n\t}\n\n\tvoid AXVoiceProtection_Release(AXVPB* vpb)\n\t{\n\t\tsint32 index = vpb->index;\n\t\t__AXVoiceProtection[index].threadMPTR = MPTR_NULL;\n\t\t__AXVoiceProtection[index].count = 0;\n\t}\n\n\tsint32 AXVoiceBegin(AXVPB* voice)\n\t{\n\t\tif (voice == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"AXVoiceBegin(): Invalid voice\");\n\t\t\treturn -1;\n\t\t}\n\t\tuint32 index = (uint32)voice->index;\n\t\tif (index >= AX_MAX_VOICES)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"AXVoiceBegin(): Invalid voice index\");\n\t\t\treturn -1;\n\t\t}\n\t\tif (AXIst_IsFrameBeingProcessed())\n\t\t\treturn -2;\n\t\tMPTR currentThreadMPTR = memory_getVirtualOffsetFromPointer(coreinit::OSGetCurrentThread());\n\t\tif (__AXVoiceProtection[index].threadMPTR == MPTR_NULL)\n\t\t{\n\t\t\t__AXVoiceProtection[index].threadMPTR = currentThreadMPTR;\n\t\t\t__AXVoiceProtection[index].count = 1;\n\t\t\treturn 1;\n\t\t}\n\t\telse if (__AXVoiceProtection[index].threadMPTR == currentThreadMPTR)\n\t\t{\n\t\t\t__AXVoiceProtection[index].count++;\n\t\t\treturn __AXVoiceProtection[index].count;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tsint32 __GetThreadProtection(MPTR threadMPTR)\n\t{\n\t\tfor (sint32 i = __AXUserProtectionArraySize - 1; i >= 0; i--)\n\t\t{\n\t\t\tif (__AXUserProtectionArray[i].threadMPTR == threadMPTR)\n\t\t\t\treturn i;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tsint32 AXVoiceEnd(AXVPB* voice)\n\t{\n\t\tif (voice == nullptr)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"AXVoiceBegin(): Invalid voice\");\n\t\t\treturn -1;\n\t\t}\n\t\tuint32 index = (uint32)voice->index;\n\t\tif (index >= AX_MAX_VOICES)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"AXVoiceBegin(): Invalid voice index\");\n\t\t\treturn -1;\n\t\t}\n\t\tif (AXIst_IsFrameBeingProcessed())\n\t\t\treturn -2;\n\t\tMPTR currentThreadMPTR = memory_getVirtualOffsetFromPointer(coreinit::OSGetCurrentThread());\n\t\tif (__AXVoiceProtection[index].threadMPTR == currentThreadMPTR)\n\t\t{\n\t\t\tif (__AXVoiceProtection[index].count > 0)\n\t\t\t\t__AXVoiceProtection[index].count--;\n\t\t\tif (__AXVoiceProtection[index].count == 0)\n\t\t\t{\n\t\t\t\tif (__GetThreadProtection(currentThreadMPTR) == -1)\n\t\t\t\t{\n\t\t\t\t\t__AXVoiceProtection[index].threadMPTR = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsint32 count = __AXVoiceProtection[index].count;\n\t\t\treturn count;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (__AXVoiceProtection[index].threadMPTR == MPTR_NULL)\n\t\t\t{\n\t\t\t\treturn -3;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid AXVPB_SetVoiceDefault(AXVPB* vpb)\n\t{\n\t\tAXVPBInternal_t* internal = GetInternalVoice(vpb);\n\t\tuint32 index = GetVoiceIndex(vpb);\n\t\tvpb->playbackState = 0;\n\t\tvpb->sync = 0;\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_PLAYBACKSTATE);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_SRCDATA);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_LPFDATA);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_BIQUADDATA);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_VOICEREMOTEON);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_ITD20);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_8000000);\n\t\tAXSetSyncFlag(vpb, 0x10000000);\n\t\tinternal->reserved282_rmtIIRGuessed = 0;\n\t\tinternal->reserved16C = 0;\n\t\tinternal->reserved148_voiceRmtOn = 0;\n\t\tinternal->biquad.on = 0;\n\t\tinternal->lpf.on = 0;\n\t\tinternal->playbackState = 0;\n\t\tuint32 defaultMixer = AXGetDefaultMixerSelect();\n\t\tinternal->mixerSelect = defaultMixer;\n\t\tvpb->mixerSelect = defaultMixer;\n\t\tAXResetVoiceLoopCount(vpb);\n\t\tinternal->reserved280 = 0;\n\t\tinternal->src.currentFrac = 0;\n\t\tinternal->src.historySamples[0] = 0;\n\t\tinternal->src.historySamples[1] = 0;\n\t\tinternal->src.historySamples[2] = 0;\n\t\tinternal->src.historySamples[3] = 0;\n\t\tinternal->reserved278 = 0;\n\t\tinternal->reserved27A = 0;\n\t\tinternal->reserved27C = 0;\n\t\tinternal->reserved27E = 0;\n\t\tinternal->srcFilterMode = 0;\n\t\tmemset(&internal->deviceMixMaskTV, 0, 8);\n\t\tmemset(&internal->deviceMixMaskDRC, 0, 16);\n\t\tmemset(&internal->deviceMixMaskRMT, 0, 0x20);\n\t\tmemset(&internal->reserved1E8, 0, 0x30);\n\t\tmemset(&internal->reserved218, 0, 0x40);\n\t\tmemset(&internal->reserved258, 0, 0x20);\n\t}\n\n\tAXVPB* AXVPB_DropVoice(sint32 priority)\n\t{\n\t\tfor (sint32 i = 1; i < priority; i++)\n\t\t{\n\t\t\tAXVPB* voiceItr = AXVoiceList_GetLeastRecentVoiceByPriority(i);\n\t\t\tif (voiceItr)\n\t\t\t{\n\t\t\t\t// get last voice in chain\n\t\t\t\twhile (voiceItr->next)\n\t\t\t\t\tvoiceItr = voiceItr->next.GetPtr();\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"Dropped voice {}\", (uint32)voiceItr->index);\n\t\t\t\t// drop voice\n\t\t\t\tif (voiceItr->playbackState != 0)\n\t\t\t\t{\n\t\t\t\t\tvoiceItr->depop = 1;\n\t\t\t\t}\n\t\t\t\t// do drop callback\n\t\t\t\tif (voiceItr->callback)\n\t\t\t\t{\n\t\t\t\t\tPPCCoreCallback(voiceItr->callback, voiceItr);\n\t\t\t\t}\n\t\t\t\tvoiceItr->ukn4C_dropReason = 0; // probably drop reason?\n\t\t\t\tif (voiceItr->callbackEx)\n\t\t\t\t{\n\t\t\t\t\tPPCCoreCallback(voiceItr->callbackEx, voiceItr, voiceItr->userParam, voiceItr->ukn4C_dropReason);\n\t\t\t\t}\n\t\t\t\t// move voice to new stack\n\t\t\t\tAXVoiceList_RemoveVoice(voiceItr);\n\t\t\t\tAXVoiceList_AddVoice(voiceItr, priority);\n\t\t\t\treturn voiceItr;\n\t\t\t}\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tAXVPB* AXAcquireVoiceEx(uint32 priority, MPTR callbackEx, MPTR userParam)\n\t{\n\t\tcemu_assert(priority != AX_PRIORITY_FREE && priority < AX_PRIORITY_MAX);\n\t\t__AXVoiceListSpinlock.lock();\n\t\tAXVPB* vpb = AXVoiceList_GetFreeVoice();\n\t\tif (vpb != nullptr)\n\t\t{\n\t\t\tAXVoiceList_AddVoice(vpb, priority);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// no free voice available, try to drop a voice with lower priority\n\t\t\tvpb = AXVPB_DropVoice(priority);\n\t\t\tif (!vpb)\n\t\t\t{\n\t\t\t\t// no voice available\n\t\t\t\t__AXVoiceListSpinlock.unlock();\n\t\t\t\treturn nullptr;\n\t\t\t}\n\t\t}\n\t\tvpb->userParam = userParam;\n\t\tvpb->callback = MPTR_NULL;\n\t\tvpb->callbackEx = callbackEx;\n\t\tAXVPB_SetVoiceDefault(vpb);\n\t\t__AXVoiceListSpinlock.unlock();\n\t\treturn vpb;\n\t}\n\n\tvoid AXFreeVoice(AXVPB* vpb)\n\t{\n\t\tcemu_assert(vpb != nullptr);\n\t\t__AXVoiceListSpinlock.lock();\n\t\tif (vpb->priority == (uint32be)AX_PRIORITY_FREE)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"AXFreeVoice() called on free voice\");\n\t\t\t__AXVoiceListSpinlock.unlock();\n\t\t\treturn;\n\t\t}\n\t\tAXVoiceProtection_Release(vpb);\n\t\tAXVoiceList_RemoveVoice(vpb);\n\t\tif (vpb->playbackState != (uint32be)0)\n\t\t{\n\t\t\tvpb->depop = (uint32be)1;\n\t\t}\n\t\tAXVPB_SetVoiceDefault(vpb);\n\t\tvpb->callback = MPTR_NULL;\n\t\tvpb->callbackEx = MPTR_NULL;\n\t\tAXVoiceList_AddFreeVoice(vpb);\n\t\t__AXVoiceListSpinlock.unlock();\n\t}\n\n    void __AXVPBResetVoices()\n    {\n        __AXVPBInternalVoiceArray = _buffer__AXVPBInternalVoiceArray.GetPtr();\n        __AXVPBInternalVoiceShadowCopyArrayPtr = _buffer__AXVPBInternalVoiceShadowCopyArray.GetPtr();\n        __AXVPBArrayPtr = _buffer__AXVPBArray.GetPtr();\n        __AXVPBItdArrayPtr = _buffer__AXVPBItdArray.GetPtr();\n\n        memset(__AXVPBInternalVoiceShadowCopyArrayPtr, 0, sizeof(AXVPBInternal_t)*AX_MAX_VOICES);\n        memset(__AXVPBInternalVoiceArray, 0, sizeof(AXVPBInternal_t)*AX_MAX_VOICES);\n        memset(__AXVPBItdArrayPtr, 0, sizeof(AXVPBItd)*AX_MAX_VOICES);\n        memset(__AXVPBArrayPtr, 0, sizeof(AXVPB)*AX_MAX_VOICES);\n    }\n\n\tvoid AXVPBInit()\n\t{\n        __AXVPBResetVoices();\n\t\tfor (sint32 i = 0; i < AX_MAX_VOICES; i++)\n\t\t{\n\t\t\tAXVPBItd* itd = __AXVPBItdArrayPtr + i;\n\t\t\tAXVPBInternal_t* internalShadowCopy = __AXVPBInternalVoiceShadowCopyArrayPtr + i;\n\t\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + i;\n\t\t\tAXVPB* vpb = __AXVPBArrayPtr + i;\n\n\t\t\tMPTR internalShadowCopyPhys = memory_virtualToPhysical(memory_getVirtualOffsetFromPointer(internalShadowCopy));\n\t\t\tMPTR itdPhys = memory_virtualToPhysical(memory_getVirtualOffsetFromPointer(itd));\n\n\t\t\tvpb->callbackEx = MPTR_NULL;\n\t\t\tvpb->itd = itd;\n\t\t\tvpb->callback = MPTR_NULL;\n\t\t\tvpb->index = i;\n\t\t\tAXVPB_SetVoiceDefault(vpb);\n\n\t\t\tif (i == (AX_MAX_VOICES - 1))\n\t\t\t{\n\t\t\t\tinternal->nextAddrHigh = 0;\n\t\t\t\tinternal->nextAddrLow = 0;\n\t\t\t\tinternalShadowCopy->nextAddrHigh = 0;\n\t\t\t\tinternalShadowCopy->nextAddrLow = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tMPTR nextShadowCopyPhys = internalShadowCopyPhys + sizeof(AXVPBInternal_t);\n\t\t\t\tinternalShadowCopy->nextAddrHigh = internal->nextAddrHigh = (nextShadowCopyPhys >> 16);\n\t\t\t\tinternalShadowCopy->nextAddrLow = internal->nextAddrLow = (nextShadowCopyPhys & 0xFFFF);\n\t\t\t}\n\t\t\tinternalShadowCopy->index = internal->index = i;\n\t\t\tinternalShadowCopy->selfAddrHigh = internal->selfAddrHigh = (internalShadowCopyPhys >> 16);\n\t\t\tinternalShadowCopy->selfAddrLow = internal->selfAddrLow = (internalShadowCopyPhys & 0xFFFF);\n\t\t\tinternalShadowCopy->itdAddrHigh = internal->itdAddrHigh = (itdPhys >> 16);\n\t\t\tinternalShadowCopy->itdAddrLow = internal->itdAddrLow = (itdPhys & 0xFFFF);\n\t\t\tvpb->priority = 1;\n\t\t\tAXVoiceList_AddFreeVoice(vpb);\n\t\t}\n\t}\n\n\tvoid AXVPB_Init()\n\t{\n\t\t__AXVPBResetVoices();\n\t\tAXVPBInit();\n\t}\n\n    void AXVBP_Reset()\n    {\n        AXVoiceList_Reset();\n        __AXVPBResetVoices();\n    }\n\n\tsint32 AXIsValidDevice(sint32 device, sint32 deviceIndex)\n\t{\n\t\tif (device == AX_DEV_TV)\n\t\t{\n\t\t\tif (deviceIndex != 0)\n\t\t\t\treturn -2;\n\t\t}\n\t\telse if (device == AX_DEV_DRC)\n\t\t{\n\t\t\tif (deviceIndex != 0 && deviceIndex != 1)\n\t\t\t\treturn -2;\n\t\t}\n\t\telse if (device == AX_DEV_TV)\n\t\t{\n\t\t\tif (deviceIndex < 0 || deviceIndex >= 4)\n\t\t\t\treturn -2;\n\t\t}\n\t\telse\n\t\t\treturn -1;\n\t\treturn 0;\n\t}\n\n\n\tvoid __AXSetVoiceChannelMix(AXCHMIX_DEPR* mixOut, AXCHMIX_DEPR* mixIn, sint16* mixMask)\n\t{\n\t\tfor (sint32 i = 0; i < AX_BUS_COUNT; i++)\n\t\t{\n\t\t\tmixOut[i].vol = mixIn[i].vol;\n\t\t\tmixOut[i].delta = mixIn[i].delta;\n\t\t\tif (mixIn[i].delta)\n\t\t\t\tmixMask[i] = 3;\n\t\t\telse if (mixIn[i].vol)\n\t\t\t\tmixMask[i] = 1;\n\t\t\telse\n\t\t\t\tmixMask[i] = 0;\n\t\t}\n\t}\n\n\tsint32 AXSetVoiceDeviceMix(AXVPB* vpb, sint32 device, sint32 deviceIndex, AXCHMIX_DEPR* mix)\n\t{\n\t\tif (vpb == nullptr)\n\t\t\treturn -4;\n\t\tif (mix == nullptr)\n\t\t\treturn -3;\n\t\tsint32 r = AXIsValidDevice(device, deviceIndex);\n\t\tif (r)\n\t\t\treturn r;\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tsint32 channelCount;\n\n\t\tuint16* deviceMixMask;\n\t\tAXCHMIX_DEPR* voiceMix;\n\t\tif (device == AX_DEV_TV)\n\t\t{\n\t\t\tchannelCount = AX_TV_CHANNEL_COUNT;\n\t\t\tvoiceMix = internal->deviceMixTV + deviceIndex * 0x60 / 4;\n\t\t\tdeviceMixMask = internal->deviceMixMaskTV;\n\t\t}\n\t\telse if (device == AX_DEV_DRC)\n\t\t{\n\t\t\tchannelCount = AX_DRC_CHANNEL_COUNT;\n\t\t\tvoiceMix = internal->deviceMixDRC + deviceIndex * 16;\n\t\t\tdeviceMixMask = internal->deviceMixMaskDRC;\n\t\t}\n\t\telse if (device == AX_DEV_RMT)\n\t\t{\n\t\t\tassert_dbg();\n\t\t\tchannelCount = AX_RMT_CHANNEL_COUNT;\n\t\t}\n\t\tsint16 updatedMixMask[AX_BUS_COUNT];\n\t\tfor (sint32 i = 0; i < AX_BUS_COUNT; i++)\n\t\t{\n\t\t\tupdatedMixMask[i] = 0;\n\t\t}\n\t\tsint16 channelMixMask[AX_BUS_COUNT];\n\t\tfor (sint32 c = 0; c < channelCount; c++)\n\t\t{\n\t\t\t__AXSetVoiceChannelMix(voiceMix, mix, channelMixMask);\n\t\t\tfor (sint32 i = 0; i < AX_BUS_COUNT; i++)\n\t\t\t{\n\t\t\t\tupdatedMixMask[i] |= (channelMixMask[i] << (c * 2));\n\t\t\t}\n\t\t\t// next channel\n\t\t\tvoiceMix += AX_BUS_COUNT;\n\t\t\tmix += AX_BUS_COUNT;\n\t\t}\n\t\tfor (sint32 i = 0; i < AX_BUS_COUNT; i++)\n\t\t{\n\t\t\tdeviceMixMask[i] = _swapEndianU16(updatedMixMask[i]);\n\t\t}\n\t\tvpb->sync = (uint32)vpb->sync | (AX_SYNCFLAG_DEVICEMIXMASK | AX_SYNCFLAG_DEVICEMIX);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t\treturn 0;\n\t}\n\n\tvoid AXSetVoiceState(AXVPB* vpb, sint32 voiceState)\n\t{\n\t\tif (vpb->playbackState != (uint32be)voiceState)\n\t\t{\n\t\t\tvpb->playbackState = voiceState;\n\t\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\t\tinternal->playbackState = _swapEndianU16(voiceState);\n\t\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_PLAYBACKSTATE);\n\t\t\tAXVoiceProtection_Acquire(vpb);\n\t\t\tif (voiceState == 0)\n\t\t\t{\n\t\t\t\tvpb->depop = (uint32be)1;\n\t\t\t}\n\t\t}\n\t}\n\n\tsint32 AXIsVoiceRunning(AXVPB* vpb)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\treturn (_swapEndianU16(internal->playbackState) == 1) ? 1 : 0;\n\t}\n\n\tvoid AXSetVoiceType(AXVPB* vpb, uint16 voiceType)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tinternal->voiceType = _swapEndianU16(voiceType);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_VOICETYPE);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXSetVoiceAdpcm(AXVPB* vpb, AXPBADPCM_t* adpcm)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)(vpb->index);\n\t\tfor (sint32 i = 0; i < 16; i++)\n\t\t\tinternal->adpcmData.coef[i] = adpcm->a[i];\n\t\tinternal->adpcmData.gain = adpcm->gain;\n\t\tinternal->adpcmData.scale = adpcm->scale;\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_ADPCMDATA);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXSetVoiceAdpcmLoop(AXVPB* vpb, AXPBADPCMLOOP_t* adpcmLoop)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tinternal->adpcmLoop.loopScale = adpcmLoop->loopScale;\n\t\tif (internal->voiceType == 0)\n\t\t{\n\t\t\tinternal->adpcmLoop.loopYn1 = adpcmLoop->loopYn1;\n\t\t\tinternal->adpcmLoop.loopYn2 = adpcmLoop->loopYn2;\n\t\t}\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_ADPCMLOOP);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXSetVoiceSrc(AXVPB* vpb, AXPBSRC_t* src)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tinternal->src.ratioHigh = src->ratioHigh;\n\t\tinternal->src.ratioLow = src->ratioLow;\n\t\tinternal->src.currentFrac = src->currentFrac;\n\t\tinternal->src.historySamples[0] = src->historySamples[0];\n\t\tinternal->src.historySamples[1] = src->historySamples[1];\n\t\tinternal->src.historySamples[2] = src->historySamples[2];\n\t\tinternal->src.historySamples[3] = src->historySamples[3];\n\t\tAXResetSyncFlag(vpb, AX_SYNCFLAG_SRCRATIO);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_SRCDATA);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXSetVoiceSrcType(AXVPB* vpb, uint32 srcType)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tif (srcType == AX_SRC_TYPE_NONE)\n\t\t{\n\t\t\tinternal->srcFilterMode = _swapEndianU16(AX_FILTER_MODE_NONE);\n\t\t}\n\t\telse if (srcType == AX_SRC_TYPE_LINEAR)\n\t\t{\n\t\t\tinternal->srcFilterMode = _swapEndianU16(AX_FILTER_MODE_LINEAR);\n\t\t}\n\t\telse if (srcType == AX_SRC_TYPE_LOWPASS1)\n\t\t{\n\t\t\tinternal->srcFilterMode = _swapEndianU16(AX_FILTER_MODE_TAP);\n\t\t\tinternal->srcTapFilter = _swapEndianU16(AX_FILTER_LOWPASS_8K);\n\t\t}\n\t\telse if (srcType == AX_SRC_TYPE_LOWPASS2)\n\t\t{\n\t\t\tinternal->srcFilterMode = _swapEndianU16(AX_FILTER_MODE_TAP);\n\t\t\tinternal->srcTapFilter = _swapEndianU16(AX_FILTER_LOWPASS_12K);\n\t\t}\n\t\telse if (srcType == AX_SRC_TYPE_LOWPASS3)\n\t\t{\n\t\t\tinternal->srcFilterMode = _swapEndianU16(AX_FILTER_MODE_TAP);\n\t\t\tinternal->srcTapFilter = _swapEndianU16(AX_FILTER_LOWPASS_16K);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"AXSetVoiceSrcType(): Unsupported src type {}\", srcType);\n\t\t}\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_SRCFILTER);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tsint32 AXSetVoiceSrcRatio(AXVPB* vpb, float ratio)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tratio *= 65536.0f;\n#ifdef CEMU_DEBUG_ASSERT\n\t\tif (ratio >= 4294967296.0f)\n\t\t\tassert_dbg();\n#endif\n\t\tsint32 ratioI = (sint32)ratio;\n\t\tif (ratioI < 0)\n\t\t\tratioI = 0;\n\t\telse if (ratioI > 0x80000)\n\t\t\tratioI = 0x80000;\n\n\t\tuint16 ratioHigh = (uint16)(ratioI >> 16);\n\t\tuint16 ratioLow = (uint16)(ratioI & 0xFFFF);\n\n\t\tratioHigh = _swapEndianU16(ratioHigh);\n\t\tratioLow = _swapEndianU16(ratioLow);\n\n\t\tif (internal->src.ratioHigh != ratioHigh || internal->src.ratioLow != ratioLow)\n\t\t{\n\t\t\tinternal->src.ratioHigh = ratioHigh;\n\t\t\tinternal->src.ratioLow = ratioLow;\n\t\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_SRCRATIO);\n\t\t\tAXVoiceProtection_Acquire(vpb);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tvoid AXSetVoiceVe(AXVPB* vpb, AXPBVE* ve)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tinternal->veVolume = ve->currentVolume;\n\t\tinternal->veDelta = ve->currentDelta;\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_VE);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXComputeLpfCoefs(uint32 freq, uint16be* a0, uint16be* b0)\n\t{\n\t\t// todo - verify algorithm\n\t\tfloat t1 = cos((float)freq / 32000.0f * 6.2831855f);\n\t\tfloat t2 = 2.0f - t1;\n\t\tt1 = (float)sqrt(t2 * t2 - 1.0f);\n\t\tt1 = t1 - t2;\n\t\tt1 = t1 * 32768.0f;\n\t\tt1 = -t1;\n\t\tuint32 r = (uint16)t1;\n\t\t*a0 = 0x7FFF - r;\n\t\t*b0 = r;\n\t}\n\n\tvoid AXSetVoiceLpf(AXVPB* vpb, AXPBLPF_t* lpf)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tinternal->lpf.on = lpf->on;\n\t\tinternal->lpf.yn1 = lpf->yn1;\n\t\tinternal->lpf.a0 = lpf->a0;\n\t\tinternal->lpf.b0 = lpf->b0;\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_LPFDATA);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXSetVoiceLpfCoefs(AXVPB* vpb, uint16 a0, uint16 b0)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tinternal->lpf.a0 = _swapEndianU16(a0);\n\t\tinternal->lpf.b0 = _swapEndianU16(b0);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_LPFCOEF);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXSetVoiceBiquad(AXVPB* vpb, AXPBBIQUAD_t* biquad)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tinternal->biquad.on = biquad->on;\n\t\tinternal->biquad.xn1 = biquad->xn1;\n\t\tinternal->biquad.xn2 = biquad->xn2;\n\t\tinternal->biquad.yn1 = biquad->yn1;\n\t\tinternal->biquad.yn2 = biquad->yn2;\n\t\tinternal->biquad.b0 = biquad->b0;\n\t\tinternal->biquad.b1 = biquad->b1;\n\t\tinternal->biquad.b2 = biquad->b2;\n\t\tinternal->biquad.a1 = biquad->a1;\n\t\tinternal->biquad.a2 = biquad->a2;\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_BIQUADDATA);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXSetVoiceBiquadCoefs(AXVPB* vpb, uint16 b0, uint16 b1, uint16 b2, uint16 a1, uint16 a2)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\t\tinternal->biquad.b0 = _swapEndianU16(b0);\n\t\tinternal->biquad.b1 = _swapEndianU16(b1);\n\t\tinternal->biquad.b2 = _swapEndianU16(b2);\n\t\tinternal->biquad.a1 = _swapEndianU16(a1);\n\t\tinternal->biquad.a2 = _swapEndianU16(a2);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_BIQUADCOEF);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid __AXSetVoiceAddr(AXVPB* vpb, axOffsetsInternal_t* voiceAddr)\n\t{\n\t\tsint32 voiceIndex = (sint32)(vpb->index);\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + voiceIndex;\n\t\tmemcpy(&internal->internalOffsets, voiceAddr, sizeof(axOffsetsInternal_t));\n\t\tuint16 format = _swapEndianU16(voiceAddr->format);\n\t\tif (format == AX_FORMAT_PCM8)\n\t\t{\n\t\t\tmemset(&internal->adpcmData, 0x00, sizeof(axADPCMInternal_t));\n\t\t\tinternal->adpcmData.gain = 0x100;\n\t\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_ADPCMDATA);\n\t\t\tAXResetSyncFlag(vpb, AX_SYNCFLAG_LOOPFLAG | AX_SYNCFLAG_LOOPOFFSET | AX_SYNCFLAG_ENDOFFSET | AX_SYNCFLAG_CURRENTOFFSET);\n\t\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_OFFSETS);\n\t\t\tAXVoiceProtection_Acquire(vpb);\n\t\t}\n\t\telse if (format == AX_FORMAT_PCM16)\n\t\t{\n\t\t\tmemset(&internal->adpcmData, 0x00, sizeof(axADPCMInternal_t));\n\t\t\tinternal->adpcmData.gain = 0x800;\n\t\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_ADPCMDATA);\n\t\t\tAXResetSyncFlag(vpb, AX_SYNCFLAG_LOOPFLAG | AX_SYNCFLAG_LOOPOFFSET | AX_SYNCFLAG_ENDOFFSET | AX_SYNCFLAG_CURRENTOFFSET);\n\t\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_OFFSETS);\n\t\t\tAXVoiceProtection_Acquire(vpb);\n\t\t}\n\t\telse if (format == AX_FORMAT_ADPCM)\n\t\t{\n\t\t\t// .adpcmData is left intact\n\t\t\tAXResetSyncFlag(vpb, AX_SYNCFLAG_LOOPFLAG | AX_SYNCFLAG_LOOPOFFSET | AX_SYNCFLAG_ENDOFFSET | AX_SYNCFLAG_CURRENTOFFSET);\n\t\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_OFFSETS);\n\t\t\tAXVoiceProtection_Acquire(vpb);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\n\tvoid AXSetVoiceOffsets(AXVPB* vpb, AXPBOFFSET_t* pbOffset)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, fmt::format(\"AXSetVoiceOffsets() -> Format: {0:04x} Current: {1:08x} End: {2:08x} Loop: {3:08x}\", _swapEndianU16(pbOffset->format), _swapEndianU32(pbOffset->currentOffset), _swapEndianU32(pbOffset->endOffset), _swapEndianU32(pbOffset->loopOffset)));\n\t\tMPTR sampleBase = _swapEndianU32(pbOffset->samples);\n\t\tif (sampleBase == MPTR_NULL)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"AXSetVoiceOffsets(): Invalid sample address\");\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn;\n\t\t}\n\t\tmemcpy(&vpb->offsets, pbOffset, sizeof(AXPBOFFSET_t));\n\t\tsampleBase = memory_virtualToPhysical(sampleBase);\n\t\tuint16 format = _swapEndianU16(pbOffset->format);\n\n\t\taxOffsetsInternal_t voiceAddr;\n\t\tif (format == AX_FORMAT_PCM8)\n\t\t{\n\t\t\tuint32 loopOffsetPtr = sampleBase + _swapEndianU32(pbOffset->loopOffset);\n\t\t\tuint32 endOffsetPtr = sampleBase + _swapEndianU32(pbOffset->endOffset);\n\t\t\tuint32 currentOffsetPtr = sampleBase + _swapEndianU32(pbOffset->currentOffset);\n\t\t\tvoiceAddr.format = _swapEndianU16(pbOffset->format);\n\t\t\tvoiceAddr.loopFlag = _swapEndianU16(pbOffset->loopFlag);\n\t\t\tvoiceAddr.loopOffsetPtrHigh = (loopOffsetPtr >> 16) & 0x1FFF;\n\t\t\tvoiceAddr.loopOffsetPtrLow = loopOffsetPtr & 0xFFFF;\n\t\t\tvoiceAddr.endOffsetPtrHigh = (endOffsetPtr >> 16) & 0x1FFF;\n\t\t\tvoiceAddr.endOffsetPtrLow = endOffsetPtr & 0xFFFF;\n\t\t\tvoiceAddr.currentOffsetPtrHigh = (currentOffsetPtr >> 16) & 0x1FFF;\n\t\t\tvoiceAddr.currentOffsetPtrLow = currentOffsetPtr & 0xFFFF;\n\t\t\tvoiceAddr.ptrHighExtension = (currentOffsetPtr >> 29);\n\t\t\t// convert to big endian\n\t\t\tvoiceAddr.format = _swapEndianU16(voiceAddr.format);\n\t\t\tvoiceAddr.loopFlag = _swapEndianU16(voiceAddr.loopFlag);\n\t\t\tvoiceAddr.loopOffsetPtrHigh = _swapEndianU16(voiceAddr.loopOffsetPtrHigh);\n\t\t\tvoiceAddr.loopOffsetPtrLow = _swapEndianU16(voiceAddr.loopOffsetPtrLow);\n\t\t\tvoiceAddr.endOffsetPtrHigh = _swapEndianU16(voiceAddr.endOffsetPtrHigh);\n\t\t\tvoiceAddr.endOffsetPtrLow = _swapEndianU16(voiceAddr.endOffsetPtrLow);\n\t\t\tvoiceAddr.currentOffsetPtrHigh = _swapEndianU16(voiceAddr.currentOffsetPtrHigh);\n\t\t\tvoiceAddr.currentOffsetPtrLow = _swapEndianU16(voiceAddr.currentOffsetPtrLow);\n\t\t\tvoiceAddr.ptrHighExtension = _swapEndianU16(voiceAddr.ptrHighExtension);\n\t\t\t__AXSetVoiceAddr(vpb, &voiceAddr);\n\t\t}\n\t\telse if (format == AX_FORMAT_PCM16)\n\t\t{\n\t\t\tuint32 loopOffsetPtr = sampleBase / 2 + _swapEndianU32(pbOffset->loopOffset);\n\t\t\tuint32 endOffsetPtr = sampleBase / 2 + _swapEndianU32(pbOffset->endOffset);\n\t\t\tuint32 currentOffset = _swapEndianU32(pbOffset->currentOffset);\n\t\t\tuint32 currentOffsetPtr = sampleBase / 2 + currentOffset;\n\t\t\tvoiceAddr.format = _swapEndianU16(pbOffset->format);\n\t\t\tvoiceAddr.loopFlag = _swapEndianU16(pbOffset->loopFlag);\n\t\t\tvoiceAddr.loopOffsetPtrHigh = (loopOffsetPtr >> 16) & 0x0FFF;\n\t\t\tvoiceAddr.loopOffsetPtrLow = loopOffsetPtr & 0xFFFF;\n\t\t\tvoiceAddr.endOffsetPtrHigh = (endOffsetPtr >> 16) & 0x0FFF;\n\t\t\tvoiceAddr.endOffsetPtrLow = endOffsetPtr & 0xFFFF;\n\t\t\tvoiceAddr.currentOffsetPtrHigh = (currentOffsetPtr >> 16) & 0x0FFF;\n\t\t\tvoiceAddr.currentOffsetPtrLow = currentOffsetPtr & 0xFFFF;\n\t\t\tvoiceAddr.ptrHighExtension = ((sampleBase + currentOffset * 2) >> 29);\n\t\t\t// convert to big endian\n\t\t\tvoiceAddr.format = _swapEndianU16(voiceAddr.format);\n\t\t\tvoiceAddr.loopFlag = _swapEndianU16(voiceAddr.loopFlag);\n\t\t\tvoiceAddr.loopOffsetPtrHigh = _swapEndianU16(voiceAddr.loopOffsetPtrHigh);\n\t\t\tvoiceAddr.loopOffsetPtrLow = _swapEndianU16(voiceAddr.loopOffsetPtrLow);\n\t\t\tvoiceAddr.endOffsetPtrHigh = _swapEndianU16(voiceAddr.endOffsetPtrHigh);\n\t\t\tvoiceAddr.endOffsetPtrLow = _swapEndianU16(voiceAddr.endOffsetPtrLow);\n\t\t\tvoiceAddr.currentOffsetPtrHigh = _swapEndianU16(voiceAddr.currentOffsetPtrHigh);\n\t\t\tvoiceAddr.currentOffsetPtrLow = _swapEndianU16(voiceAddr.currentOffsetPtrLow);\n\t\t\tvoiceAddr.ptrHighExtension = _swapEndianU16(voiceAddr.ptrHighExtension);\n\t\t\t__AXSetVoiceAddr(vpb, &voiceAddr);\n\t\t}\n\t\telse if (format == AX_FORMAT_ADPCM)\n\t\t{\n\t\t\tuint32 loopOffsetPtr = sampleBase * 2 + _swapEndianU32(pbOffset->loopOffset);\n\t\t\tuint32 endOffsetPtr = sampleBase * 2 + _swapEndianU32(pbOffset->endOffset);\n\t\t\tuint32 currentOffset = _swapEndianU32(pbOffset->currentOffset);\n\t\t\tuint32 currentOffsetPtr = sampleBase * 2 + currentOffset;\n\t\t\tvoiceAddr.format = _swapEndianU16(pbOffset->format);\n\t\t\tvoiceAddr.loopFlag = _swapEndianU16(pbOffset->loopFlag);\n\t\t\tvoiceAddr.loopOffsetPtrHigh = (loopOffsetPtr >> 16) & 0x3FFF;\n\t\t\tvoiceAddr.loopOffsetPtrLow = loopOffsetPtr & 0xFFFF;\n\t\t\tvoiceAddr.endOffsetPtrHigh = (endOffsetPtr >> 16) & 0x3FFF;\n\t\t\tvoiceAddr.endOffsetPtrLow = endOffsetPtr & 0xFFFF;\n\t\t\tvoiceAddr.currentOffsetPtrHigh = (currentOffsetPtr >> 16) & 0x3FFF;\n\t\t\tvoiceAddr.currentOffsetPtrLow = currentOffsetPtr & 0xFFFF;\n\t\t\tvoiceAddr.ptrHighExtension = ((sampleBase + currentOffset / 2) >> 29);\n\t\t\t// convert to big endian\n\t\t\tvoiceAddr.format = _swapEndianU16(voiceAddr.format);\n\t\t\tvoiceAddr.loopFlag = _swapEndianU16(voiceAddr.loopFlag);\n\t\t\tvoiceAddr.loopOffsetPtrHigh = _swapEndianU16(voiceAddr.loopOffsetPtrHigh);\n\t\t\tvoiceAddr.loopOffsetPtrLow = _swapEndianU16(voiceAddr.loopOffsetPtrLow);\n\t\t\tvoiceAddr.endOffsetPtrHigh = _swapEndianU16(voiceAddr.endOffsetPtrHigh);\n\t\t\tvoiceAddr.endOffsetPtrLow = _swapEndianU16(voiceAddr.endOffsetPtrLow);\n\t\t\tvoiceAddr.currentOffsetPtrHigh = _swapEndianU16(voiceAddr.currentOffsetPtrHigh);\n\t\t\tvoiceAddr.currentOffsetPtrLow = _swapEndianU16(voiceAddr.currentOffsetPtrLow);\n\t\t\tvoiceAddr.ptrHighExtension = _swapEndianU16(voiceAddr.ptrHighExtension);\n\t\t\t__AXSetVoiceAddr(vpb, &voiceAddr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\n\tvoid AXSetVoiceOffsetsEx(AXVPB* vpb, AXPBOFFSET_t* pbOffset, void* sampleBase)\n\t{\n\t\t// used by F1 Racing\n\t\tcemu_assert(vpb != NULL && sampleBase != MPTR_NULL);\n\n\t\tAXPBOFFSET_t tmpOffsets = *pbOffset;\n\t\ttmpOffsets.samples = _swapEndianU32(memory_getVirtualOffsetFromPointer(sampleBase));\n\t\tAXSetVoiceOffsets(vpb, &tmpOffsets);\n\t}\n\n\tvoid AXSetVoiceSamplesAddr(AXVPB* vpb, void* sampleBase)\n\t{\n\t\tvpb->offsets.samples = _swapEndianU32(memory_getVirtualOffsetFromPointer(sampleBase));\n\t\tAXGetVoiceOffsets(vpb, &vpb->offsets);\n\t}\n\n\tvoid AXGetVoiceOffsets(AXVPB* vpb, AXPBOFFSET_t* pbOffset)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index;\n\n\t\tmemcpy(pbOffset, &vpb->offsets, sizeof(AXPBOFFSET_t));\n\t\tMPTR sampleBase = _swapEndianU32(vpb->offsets.samples);\n\t\tsampleBase = memory_virtualToPhysical(sampleBase);\n\t\tuint16 format = _swapEndianU16(pbOffset->format);\n\t\tuint32 loopOffsetPtrLow = _swapEndianU16(internal->internalOffsets.loopOffsetPtrLow);\n\t\tuint32 loopOffsetPtrHigh = _swapEndianU16(internal->internalOffsets.loopOffsetPtrHigh);\n\t\tuint32 endOffsetPtrLow = _swapEndianU16(internal->internalOffsets.endOffsetPtrLow);\n\t\tuint32 endOffsetPtrHigh = _swapEndianU16(internal->internalOffsets.endOffsetPtrHigh);\n\t\tuint32 currentOffsetPtrLow = _swapEndianU16(internal->internalOffsets.currentOffsetPtrLow);\n\t\tuint32 currentOffsetPtrHigh = _swapEndianU16(internal->internalOffsets.currentOffsetPtrHigh);\n\t\tuint32 ptrHighExtension = _swapEndianU16(internal->internalOffsets.ptrHighExtension);\n\n\t\tif (format == AX_FORMAT_PCM8)\n\t\t{\n\t\t\tuint32 loopOffset = (loopOffsetPtrLow | (loopOffsetPtrHigh << 16) | (ptrHighExtension << 29)) - sampleBase;\n\t\t\tuint32 endOffset = (endOffsetPtrLow | (endOffsetPtrHigh << 16) | (ptrHighExtension << 29)) - sampleBase;\n\t\t\tuint32 currentOffset = (currentOffsetPtrLow | (currentOffsetPtrHigh << 16) | (ptrHighExtension << 29)) - sampleBase;\n\n\t\t\tpbOffset->loopOffset = _swapEndianU32(loopOffset);\n\t\t\tpbOffset->endOffset = _swapEndianU32(endOffset);\n\t\t\tpbOffset->currentOffset = _swapEndianU32(currentOffset);\n\t\t}\n\t\telse if (format == AX_FORMAT_PCM16)\n\t\t{\n\t\t\tuint32 loopOffset = (loopOffsetPtrLow | (loopOffsetPtrHigh << 16) | ((ptrHighExtension << 29) / 2)) - sampleBase / 2;\n\t\t\tuint32 endOffset = (endOffsetPtrLow | (endOffsetPtrHigh << 16) | ((ptrHighExtension << 29) / 2)) - sampleBase / 2;\n\t\t\tuint32 currentOffset = (currentOffsetPtrLow | (currentOffsetPtrHigh << 16) | ((ptrHighExtension << 29) / 2)) - sampleBase / 2;\n\n\t\t\tpbOffset->loopOffset = _swapEndianU32(loopOffset);\n\t\t\tpbOffset->endOffset = _swapEndianU32(endOffset);\n\t\t\tpbOffset->currentOffset = _swapEndianU32(currentOffset);\n\t\t}\n\t\telse if (format == AX_FORMAT_ADPCM)\n\t\t{\n\t\t\tuint32 loopOffset = (loopOffsetPtrLow | (loopOffsetPtrHigh << 16) | ((ptrHighExtension << 29) * 2)) - sampleBase * 2;\n\t\t\tuint32 endOffset = (endOffsetPtrLow | (endOffsetPtrHigh << 16) | ((ptrHighExtension << 29) * 2)) - sampleBase * 2;\n\t\t\tuint32 currentOffset = (currentOffsetPtrLow | (currentOffsetPtrHigh << 16) | ((ptrHighExtension << 29) * 2)) - sampleBase * 2;\n\n\t\t\tpbOffset->loopOffset = _swapEndianU32(loopOffset);\n\t\t\tpbOffset->endOffset = _swapEndianU32(endOffset);\n\t\t\tpbOffset->currentOffset = _swapEndianU32(currentOffset);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\tcemuLog_log(LogType::SoundAPI, \"Retrieved voice offsets for voice {:08x} - base {:08x} current {:08x} loopFlag {:04x} loop {:08x} end {:08x}\", memory_getVirtualOffsetFromPointer(vpb), _swapEndianU32(pbOffset->samples), _swapEndianU32(pbOffset->currentOffset), _swapEndianU16(pbOffset->loopFlag), _swapEndianU32(pbOffset->loopOffset), _swapEndianU32(pbOffset->endOffset));\n\t}\n\n\tvoid AXGetVoiceOffsetsEx(AXVPB* vpb, AXPBOFFSET_t* pbOffset, MPTR sampleBase)\n\t{\n\t\tcemu_assert(vpb != NULL && sampleBase != MPTR_NULL);\n\n\t\tvpb->offsets.samples = _swapEndianU32(sampleBase);\n\t\tAXGetVoiceOffsets(vpb, pbOffset);\n\t\tmemcpy(&vpb->offsets, pbOffset, sizeof(AXPBOFFSET_t));\n\t}\n\n\tvoid AXSetVoiceCurrentOffset(AXVPB* vpb, uint32 currentOffset)\n\t{\n\t\t// untested\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)(vpb->index);\n\t\tMPTR sampleBase = memory_virtualToPhysical(_swapEndianU32(vpb->offsets.samples));\n\t\tvpb->offsets.currentOffset = _swapEndianU32(currentOffset);\n\t\tuint16 voiceFormat = _swapEndianU16(internal->internalOffsets.format);\n\t\tuint32 currentOffsetPtr;\n\t\tsampleBase &= 0x1FFFFFFF;\n\t\tif (voiceFormat == AX_FORMAT_PCM8)\n\t\t{\n\t\t\t// calculate offset (in bytes)\n\t\t\tcurrentOffsetPtr = sampleBase + currentOffset;\n\t\t}\n\t\telse if (voiceFormat == AX_FORMAT_PCM16)\n\t\t{\n\t\t\t// calculate offset (in shorts)\n\t\t\tcurrentOffsetPtr = sampleBase / 2 + currentOffset;\n\t\t}\n\t\telse if (voiceFormat == AX_FORMAT_ADPCM)\n\t\t{\n\t\t\t// calculate offset (in nibbles)\n\t\t\tcurrentOffsetPtr = sampleBase * 2 + currentOffset;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\tinternal->internalOffsets.currentOffsetPtrHigh = _swapEndianU16(currentOffsetPtr >> 16);\n\t\tinternal->internalOffsets.currentOffsetPtrLow = _swapEndianU16(currentOffsetPtr & 0xFFFF);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_CURRENTOFFSET);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXSetVoiceLoopOffset(AXVPB* vpb, uint32 loopOffset)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)(vpb->index);\n\t\tMPTR sampleBase = memory_virtualToPhysical(_swapEndianU32(vpb->offsets.samples));\n\t\tvpb->offsets.loopOffset = _swapEndianU32(loopOffset);\n\t\tuint16 voiceFormat = _swapEndianU16(internal->internalOffsets.format);\n\t\tuint32 loopOffsetPtr;\n\t\tsampleBase &= 0x1FFFFFFF;\n\t\tif (voiceFormat == AX_FORMAT_PCM8)\n\t\t{\n\t\t\t// calculate offset (in bytes)\n\t\t\tloopOffsetPtr = sampleBase + loopOffset;\n\t\t}\n\t\telse if (voiceFormat == AX_FORMAT_PCM16)\n\t\t{\n\t\t\t// calculate offset (in shorts)\n\t\t\tloopOffsetPtr = sampleBase / 2 + loopOffset;\n\t\t}\n\t\telse if (voiceFormat == AX_FORMAT_ADPCM)\n\t\t{\n\t\t\t// calculate offset (in nibbles)\n\t\t\tloopOffsetPtr = sampleBase * 2 + loopOffset;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\tinternal->internalOffsets.loopOffsetPtrHigh = _swapEndianU16(loopOffsetPtr >> 16);\n\t\tinternal->internalOffsets.loopOffsetPtrLow = _swapEndianU16(loopOffsetPtr & 0xFFFF);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_LOOPOFFSET);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXSetVoiceEndOffset(AXVPB* vpb, uint32 endOffset)\n\t{\n\t\t// untested\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)(vpb->index);\n\t\tMPTR sampleBase = memory_virtualToPhysical(_swapEndianU32(vpb->offsets.samples));\n\t\tvpb->offsets.endOffset = _swapEndianU32(endOffset);\n\t\tuint16 voiceFormat = _swapEndianU16(internal->internalOffsets.format);\n\t\tuint32 endOffsetPtr;\n\t\tsampleBase &= 0x1FFFFFFF;\n\t\tif (voiceFormat == AX_FORMAT_PCM8)\n\t\t{\n\t\t\t// calculate offset (in bytes)\n\t\t\tendOffsetPtr = sampleBase + endOffset;\n\t\t}\n\t\telse if (voiceFormat == AX_FORMAT_PCM16)\n\t\t{\n\t\t\t// calculate offset (in shorts)\n\t\t\tendOffsetPtr = sampleBase / 2 + endOffset;\n\t\t}\n\t\telse if (voiceFormat == AX_FORMAT_ADPCM)\n\t\t{\n\t\t\t// calculate offset (in nibbles)\n\t\t\tendOffsetPtr = sampleBase * 2 + endOffset;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\tinternal->internalOffsets.endOffsetPtrHigh = _swapEndianU16(endOffsetPtr >> 16);\n\t\tinternal->internalOffsets.endOffsetPtrLow = _swapEndianU16(endOffsetPtr & 0xFFFF);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_ENDOFFSET);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tvoid AXSetVoiceCurrentOffsetEx(AXVPB* vpb, uint32 currentOffset, MPTR sampleBase)\n\t{\n\t\tcemu_assert(vpb != NULL && sampleBase != MPTR_NULL);\n\t\tAXPBOFFSET_t pbOffset;\n\t\tvpb->offsets.samples = _swapEndianU32(sampleBase);\n\t\tAXGetVoiceOffsets(vpb, &pbOffset);\n\t\tAXSetVoiceCurrentOffset(vpb, currentOffset);\n\t}\n\n\tvoid AXSetVoiceLoopOffsetEx(AXVPB* vpb, uint32 loopOffset, MPTR sampleBase)\n\t{\n\t\tcemu_assert(vpb != NULL && sampleBase != MPTR_NULL);\n\t\tAXPBOFFSET_t pbOffset;\n\t\tvpb->offsets.samples = _swapEndianU32(sampleBase);\n\t\tAXGetVoiceOffsets(vpb, &pbOffset);\n\t\tAXSetVoiceLoopOffset(vpb, loopOffset);\n\t}\n\n\tvoid AXSetVoiceEndOffsetEx(AXVPB* vpb, uint32 endOffset, MPTR sampleBase)\n\t{\n\t\tcemu_assert(vpb != NULL && sampleBase != MPTR_NULL);\n\t\tAXPBOFFSET_t pbOffset;\n\t\tvpb->offsets.samples = _swapEndianU32(sampleBase);\n\t\tAXGetVoiceOffsets(vpb, &pbOffset);\n\t\tAXSetVoiceEndOffset(vpb, endOffset);\n\t}\n\n\tuint32 AXGetVoiceCurrentOffsetEx(AXVPB* vpb, MPTR sampleBase)\n\t{\n\t\tcemu_assert(vpb != NULL && sampleBase != MPTR_NULL);\n\t\tAXPBOFFSET_t pbOffset;\n\t\tAXGetVoiceOffsetsEx(vpb, &pbOffset, sampleBase);\n\t\treturn _swapEndianU32(pbOffset.currentOffset);\n\t}\n\n\tvoid AXSetVoiceLoop(AXVPB* vpb, uint16 loopState)\n\t{\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)(vpb->index);\n\t\tvpb->offsets.loopFlag = _swapEndianU16(loopState);\n\t\tinternal->internalOffsets.loopFlag = _swapEndianU16(loopState);\n\t\tAXSetSyncFlag(vpb, AX_SYNCFLAG_LOOPFLAG);\n\t\tAXVoiceProtection_Acquire(vpb);\n\t}\n\n\tuint32 vpbLoopTracker_loopCount[AX_MAX_VOICES];\n\tuint32 vpbLoopTracker_prevCurrentOffset[AX_MAX_VOICES];\n\n\tvoid AXResetVoiceLoopCount(AXVPB* vpb)\n\t{\n\t\tif (!vpb)\n\t\t\treturn;\n\t\tuint32 voiceIndex = vpb->index;\n\t\tvpbLoopTracker_loopCount[voiceIndex] = 0;\n\t\tvpbLoopTracker_prevCurrentOffset[voiceIndex] = 0;\n\t}\n\n\tsint32 AXGetVoiceLoopCount(AXVPB* vpb)\n\t{\n\t\tif (!vpb)\n\t\t\treturn 0;\n\t\tuint32 voiceIndex = vpb->index;\n\t\tAXVPBInternal_t* internal = __AXVPBInternalVoiceArray + voiceIndex;\n\n\t\tuint32 loopOffset = internal->internalOffsets.GetLoopOffset32();\n\t\tuint32 endOffset = internal->internalOffsets.GetEndOffset32();\n\t\tuint32 currentOffset = internal->internalOffsets.GetCurrentOffset32();\n\n\t\tuint32 srcRatio;\n\t\tif (internal->srcFilterMode == AX_FILTER_MODE_NONE)\n\t\t\tsrcRatio = 0x10000;\n\t\telse \n\t\t\tsrcRatio = internal->src.GetSrcRatio32();\n\n\t\tuint32 loopLength = 0;\n\t\tif (srcRatio != 0)\n\t\t\tloopLength = ((endOffset - loopOffset) * 0x10000) / srcRatio;\n\n\t\tuint32 prevCurrentOffset = vpbLoopTracker_prevCurrentOffset[voiceIndex];\n\t\tuint32 voiceSamplesPerFrame = AXGetInputSamplesPerFrame();\n\n\t\tif (loopOffset < endOffset && srcRatio != 0 && loopLength <= voiceSamplesPerFrame)\n\t\t{\n\t\t\t// handle loops shorter than one frame\n\t\t\tuint32 loopsInFrame = ((prevCurrentOffset - loopOffset) + voiceSamplesPerFrame) / loopLength;\n\t\t\tvpbLoopTracker_loopCount[voiceIndex] += loopsInFrame;\n\t\t}\n\t\telse // loopOffset >= endOffset\n\t\t{\n\t\t\tif (prevCurrentOffset <= endOffset) // loop could only happen if playback cursor was before end\n\t\t\t{\n\t\t\t\tif (loopOffset > endOffset && currentOffset >= loopOffset)\n\t\t\t\t\tvpbLoopTracker_loopCount[voiceIndex]++;\n\t\t\t\telse if (currentOffset < prevCurrentOffset && currentOffset >= loopOffset)\n\t\t\t\t\tvpbLoopTracker_loopCount[voiceIndex]++;\n\t\t\t}\n\t\t}\n\t\tvpbLoopTracker_prevCurrentOffset[voiceIndex] = currentOffset;\n\t\treturn vpbLoopTracker_loopCount[voiceIndex];\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/snd_user/snd_user.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/OS/libs/snd_user/snd_user.h\"\n#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_MEM.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n\nusing namespace snd_core;\n\nnamespace snd_user\n{\n#define AX_MAX_NUM_DRC (2)\n#define AX_MAX_NUM_RMT (4)\n\n#define AX_UPDATE_MODE_10000000 (0x10000000)\n#define AX_UPDATE_MODE_20000000 (0x20000000)\n#define AX_UPDATE_MODE_40000000_VOLUME (0x40000000)\n#define AX_UPDATE_MODE_50000000 (0x50000000)\n#define AX_UPDATE_MODE_40000007 (0x40000007)\n#define AX_UPDATE_MODE_80000000 (0x80000000)\n\n\tstruct VolumeData\n\t{\n\t\tsint16 volume; // 0x00\n\t\tsint16 volume_target; // 0x02\n\t};\n\tstatic_assert(sizeof(VolumeData) == 0x4, \"sizeof(VolumeData)\");\n\n\tstruct MixControl\n\t{\n\t\tsint16 aux[AX_AUX_BUS_COUNT];\n\t\tsint16 pan;\n\t\tsint16 span;\n\t\tsint16 fader;\n\t\tsint16 lfe;\n\t};\n\tstatic_assert(sizeof(MixControl) == 0xE, \"sizeof(MixControl)\");\n\n\tusing MixMode = uint32_t;\n\n\tstruct MixChannel\n\t{\n\t\tMEMPTR<AXVPB> voice;\n\n\t\tuint32 update_mode;\n\t\tsint16 input_level;\n\t\tVolumeData volume;\n\n\t\tMixControl tv_control;\n\t\tsint16 tv_channels[AX_TV_CHANNEL_COUNT];\n\t\tVolumeData tv_volume[AX_MAX_NUM_BUS][AX_TV_CHANNEL_COUNT];\n\t\tMixMode tv_mode;\n\n\t\tMixControl drc_control[AX_MAX_NUM_DRC];\n\t\tsint16 drc_channels[AX_MAX_NUM_DRC][AX_DRC_CHANNEL_COUNT];\n\t\tVolumeData drc_volume[AX_MAX_NUM_DRC][AX_MAX_NUM_BUS][AX_DRC_CHANNEL_COUNT];\n\t\tMixMode drc_mode[AX_MAX_NUM_DRC];\n\n\t\tMixControl rmt_control[AX_MAX_NUM_RMT];\n\t\tsint16 rmt_channels[AX_MAX_NUM_RMT][AX_RMT_CHANNEL_COUNT];\n\t\tVolumeData rmt_volume[AX_MAX_NUM_RMT][AX_MAX_NUM_BUS][AX_RMT_CHANNEL_COUNT];\n\t\tMixMode rmt_mode[AX_MAX_NUM_RMT];\n\n\t\tMixControl& GetMixControl(uint32 device, uint32 deviceIndex)\n\t\t{\n\t\t\tif (device == AX_DEV_TV)\n\t\t\t{\n\t\t\t\tcemu_assert(deviceIndex == 0);\n\t\t\t\treturn tv_control;\n\t\t\t}\n\t\t\telse if (device == AX_DEV_DRC)\n\t\t\t{\n\t\t\t\tcemu_assert(deviceIndex < AX_MAX_NUM_DRC);\n\t\t\t\treturn drc_control[deviceIndex];\n\t\t\t}\n\t\t\telse if (device == AX_DEV_RMT)\n\t\t\t{\n\t\t\t\tcemu_assert(deviceIndex < AX_MAX_NUM_RMT);\n\t\t\t\treturn rmt_control[deviceIndex];\n\t\t\t}\n\t\t\tcemuLog_log(LogType::Force, \"GetMixControl({}, {}): Invalid device/deviceIndex\", device, deviceIndex);\n\t\t\tcemu_assert(false);\n\t\t\treturn tv_control;\n\t\t}\n\n\t\tMixMode& GetMode(uint32 device, uint32 deviceIndex)\n\t\t{\n\t\t\tif (device == AX_DEV_TV)\n\t\t\t{\n\t\t\t\tcemu_assert(deviceIndex == 0);\n\t\t\t\treturn tv_mode;\n\t\t\t}\n\t\t\telse if (device == AX_DEV_DRC)\n\t\t\t{\n\t\t\t\tcemu_assert(deviceIndex < AX_MAX_NUM_DRC);\n\t\t\t\treturn drc_mode[deviceIndex];\n\t\t\t}\n\t\t\telse if (device == AX_DEV_RMT)\n\t\t\t{\n\t\t\t\tcemu_assert(deviceIndex < AX_MAX_NUM_RMT);\n\t\t\t\treturn rmt_mode[deviceIndex];\n\t\t\t}\n\t\t\tcemuLog_log(LogType::Force, \"GetMode({}, {}): Invalid device/deviceIndex\", device, deviceIndex);\n\t\t\tcemu_assert(false);\n\t\t\treturn tv_mode;\n\t\t}\n\n\t\tsint16* GetChannels(uint32 device, uint32 deviceIndex)\n\t\t{\n\t\t\tif (device == AX_DEV_TV)\n\t\t\t{\n\t\t\t\tcemu_assert(deviceIndex == 0);\n\t\t\t\treturn tv_channels;\n\t\t\t}\n\t\t\telse if (device == AX_DEV_DRC)\n\t\t\t{\n\t\t\t\tcemu_assert(deviceIndex < AX_MAX_NUM_DRC);\n\t\t\t\treturn drc_channels[deviceIndex];\n\t\t\t}\n\t\t\telse if (device == AX_DEV_RMT)\n\t\t\t{\n\t\t\t\tcemu_assert(deviceIndex < AX_MAX_NUM_RMT);\n\t\t\t\treturn rmt_channels[deviceIndex];\n\t\t\t}\n\t\t\tcemuLog_log(LogType::Force, \"GetChannels({}, {}): Invalid device/deviceIndex\", device, deviceIndex);\n\t\t\tcemu_assert(false);\n\t\t\treturn tv_channels;\n\t\t}\n\t};\n\tstatic_assert(sizeof(MixChannel) == 0x1D0, \"sizeof(MixChannel)\");\n\n\tstruct DeviceInfo\n\t{\n\t\tuint32 tv_sound_mode; // 0x00\n\t\tuint32 drc_sound_mode; // 0x04\n\t\tuint32 rmt_sound_mode; // 0x08\n\t};\n\n\tstruct snd_user_data_t\n\t{\n\t\tbool initialized;\n\n\t\tDeviceInfo device_info;\n\t\tsint32 max_voices;\n\n\t\tMixChannel mix_channel[AX_MAX_VOICES];\n\n\t\tconst uint16 volume[0x388 + 0x3C + 1] =\n\t\t{\n\t\t\t0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n\t\t\t2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,\n\t\t\t5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0xC,\n\t\t\t0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xE, 0xE, 0xE, 0xE, 0xE, 0xE, 0xF, 0xF, 0xF, 0xF, 0xF, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13,\n\t\t\t0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1E,\n\t\t\t0x1E, 0x1E, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E,\n\t\t\t0x2F, 0x2F, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x37, 0x38, 0x38, 0x39, 0x3A, 0x3A, 0x3B, 0x3C, 0x3D, 0x3D, 0x3E, 0x3F, 0x3F, 0x40, 0x41, 0x42, 0x42, 0x43, 0x44, 0x45, 0x46, 0x46, 0x47, 0x48,\n\t\t\t 0x49, 0x4A, 0x4B, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x6D, 0x6F, 0x70,\n\t\t\t0x71, 0x72, 0x74, 0x75, 0x76, 0x78, 0x79, 0x7B, 0x7C, 0x7E, 0x7F, 0x80, 0x82, 0x83, 0x85, 0x87, 0x88, 0x8A, 0x8B, 0x8D, 0x8F, 0x90, 0x92, 0x94, 0x95, 0x97, 0x99, 0x9B, 0x9C, 0x9E, 0xA0, 0xA2, 0xA4, 0xA6, 0xA8, 0xAA, 0xAB, 0xAD,\n\t\t\t0xAF, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBE, 0xC0, 0xC3, 0xC5, 0xC7, 0xCA, 0xCC, 0xCE, 0xD1, 0xD3, 0xD6, 0xD8, 0xDB, 0xDD, 0xE0, 0xE2, 0xE5, 0xE7, 0xEA, 0xED, 0xF0, 0xF2, 0xF5, 0xF8, 0xFB, 0xFE, 0x101, 0x104, 0x107, 0x10A, 0x10D,\n\t\t\t0x110, 0x113, 0x116, 0x11A, 0x11D, 0x120, 0x124, 0x127, 0x12A, 0x12E, 0x131, 0x135, 0x138, 0x13C, 0x140, 0x143, 0x147, 0x14B, 0x14F, 0x153, 0x157, 0x15B, 0x15F, 0x163, 0x167, 0x16B, 0x16F, 0x173, 0x178, 0x17C, 0x180, 0x185, 0x189,\n\t\t\t0x18E, 0x193, 0x197, 0x19C, 0x1A1, 0x1A6, 0x1AB, 0x1AF, 0x1B4, 0x1BA, 0x1BF, 0x1C4, 0x1C9, 0x1CE, 0x1D4, 0x1D9, 0x1DF, 0x1E4, 0x1EA, 0x1EF, 0x1F5, 0x1FB, 0x201, 0x207, 0x20D, 0x213, 0x219, 0x21F, 0x226, 0x22C, 0x232, 0x239, 0x240,\n\t\t\t0x246, 0x24D, 0x254, 0x25B, 0x262, 0x269, 0x270, 0x277, 0x27E, 0x286, 0x28D, 0x295, 0x29D, 0x2A4, 0x2AC, 0x2B4, 0x2BC, 0x2C4, 0x2CC, 0x2D5, 0x2DD, 0x2E6, 0x2EE, 0x2F7, 0x300, 0x309, 0x312, 0x31B, 0x324, 0x32D, 0x337, 0x340, 0x34A,\n\t\t\t0x354, 0x35D, 0x367, 0x371, 0x37C, 0x386, 0x390, 0x39B, 0x3A6, 0x3B1, 0x3BB, 0x3C7, 0x3D2, 0x3DD, 0x3E9, 0x3F4, 0x400, 0x40C, 0x418, 0x424, 0x430, 0x43D, 0x449, 0x456, 0x463, 0x470, 0x47D, 0x48A, 0x498, 0x4A5, 0x4B3, 0x4C1, 0x4CF,\n\t\t\t0x4DD, 0x4EC, 0x4FA, 0x509, 0x518, 0x527, 0x536, 0x546, 0x555, 0x565, 0x575, 0x586, 0x596, 0x5A6, 0x5B7, 0x5C8, 0x5D9, 0x5EB, 0x5FC, 0x60E, 0x620, 0x632, 0x644, 0x657, 0x66A, 0x67D, 0x690, 0x6A4, 0x6B7, 0x6CB, 0x6DF, 0x6F4, 0x708,\n\t\t\t0x71D, 0x732, 0x748, 0x75D, 0x773, 0x789, 0x79F, 0x7B6, 0x7CD, 0x7E4, 0x7FB, 0x813, 0x82B, 0x843, 0x85C, 0x874, 0x88E, 0x8A7, 0x8C1, 0x8DA, 0x8F5, 0x90F, 0x92A, 0x945, 0x961, 0x97D, 0x999, 0x9B5, 0x9D2, 0x9EF, 0xA0D, 0xA2A, 0xA48,\n\t\t\t0xA67, 0xA86, 0xAA5, 0xAC5, 0xAE5, 0xB05, 0xB25, 0xB47, 0xB68, 0xB8A, 0xBAC, 0xBCF, 0xBF2, 0xC15, 0xC39, 0xC5D, 0xC82, 0xCA7, 0xCCC, 0xCF2, 0xD19, 0xD3F, 0xD67, 0xD8E, 0xDB7, 0xDDF, 0xE08, 0xE32, 0xE5C, 0xE87, 0xEB2, 0xEDD, 0xF09,\n\t\t\t0xF36, 0xF63, 0xF91, 0xFBF, 0xFEE, 0x101D, 0x104D, 0x107D, 0x10AE, 0x10DF, 0x1111, 0x1144, 0x1177, 0x11AB, 0x11DF, 0x1214, 0x124A, 0x1280, 0x12B7, 0x12EE, 0x1326, 0x135F, 0x1399, 0x13D3, 0x140D, 0x1449, 0x1485, 0x14C2, 0x14FF, 0x153E,\n\t\t\t0x157D, 0x15BC, 0x15FD, 0x163E, 0x1680, 0x16C3, 0x1706, 0x174A, 0x178F, 0x17D5, 0x181C, 0x1863, 0x18AC, 0x18F5, 0x193F, 0x198A, 0x19D5, 0x1A22, 0x1A6F, 0x1ABE, 0x1B0D, 0x1B5D, 0x1BAE, 0x1C00, 0x1C53, 0x1CA7, 0x1CFC, 0x1D52, 0x1DA9,\n\t\t\t0x1E01, 0x1E5A, 0x1EB4, 0x1F0F, 0x1F6B, 0x1FC8, 0x2026, 0x2086, 0x20E6, 0x2148, 0x21AA, 0x220E, 0x2273, 0x22D9, 0x2341, 0x23A9, 0x2413, 0x247E, 0x24EA, 0x2557, 0x25C6, 0x2636, 0x26A7, 0x271A, 0x278E, 0x2803, 0x287A, 0x28F2, 0x296B,\n\t\t\t0x29E6, 0x2A62, 0x2AE0, 0x2B5F, 0x2BDF, 0x2C61, 0x2CE5, 0x2D6A, 0x2DF1, 0x2E79, 0x2F03, 0x2F8E, 0x301B, 0x30AA, 0x313A, 0x31CC, 0x325F, 0x32F5, 0x338C, 0x3425, 0x34BF, 0x355B, 0x35FA, 0x369A, 0x373C, 0x37DF, 0x3885, 0x392C, 0x39D6,\n\t\t\t0x3A81, 0x3B2F, 0x3BDE, 0x3C90, 0x3D43, 0x3DF9, 0x3EB1, 0x3F6A, 0x4026, 0x40E5, 0x41A5, 0x4268, 0x432C, 0x43F4, 0x44BD, 0x4589, 0x4657, 0x4727, 0x47FA, 0x48D0, 0x49A8, 0x4A82, 0x4B5F, 0x4C3E, 0x4D20, 0x4E05, 0x4EEC, 0x4FD6, 0x50C3,\n\t\t\t0x51B2, 0x52A4, 0x5399, 0x5491, 0x558C, 0x5689, 0x578A, 0x588D, 0x5994, 0x5A9D, 0x5BAA, 0x5CBA, 0x5DCD, 0x5EE3, 0x5FFC, 0x6119, 0x6238, 0x635C, 0x6482, 0x65AC, 0x66D9, 0x680A, 0x693F, 0x6A77, 0x6BB2, 0x6CF2, 0x6E35, 0x6F7B, 0x70C6,\n\t\t\t0x7214, 0x7366, 0x74BC, 0x7616, 0x7774, 0x78D6, 0x7A3D, 0x7BA7, 0x7D16, 0x7E88, 0x7FFF, 0x817B, 0x82FB, 0x847F, 0x8608, 0x8795, 0x8927, 0x8ABE, 0x8C59, 0x8DF9, 0x8F9E, 0x9148, 0x92F6, 0x94AA, 0x9663, 0x9820, 0x99E3, 0x9BAB, 0x9D79,\n\t\t\t0x9F4C, 0xA124, 0xA302, 0xA4E5, 0xA6CE, 0xA8BC, 0xAAB0, 0xACAA, 0xAEAA, 0xB0B0, 0xB2BC, 0xB4CE, 0xB6E5, 0xB904, 0xBB28, 0xBD53, 0xBF84, 0xC1BC, 0xC3FA, 0xC63F, 0xC88B, 0xCADD, 0xCD37, 0xCF97, 0xD1FE, 0xD46D, 0xD6E3, 0xD960, 0xDBE4,\n\t\t\t0xDE70, 0xE103, 0xE39E, 0xE641, 0xE8EB, 0xEB9E, 0xEE58, 0xF11B, 0xF3E6, 0xF6B9, 0xF994, 0xFC78, 0xFF64\n\t\t};\n\n\t\tconst uint32 pan_values[128] =\n\t\t{\n\t\t\t00, 00,\n\t\t\t0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFD, 0xFFFFFFFC, 0xFFFFFFFC, 0xFFFFFFFC, 0xFFFFFFFB, 0xFFFFFFFB, 0xFFFFFFFB,\n\t\t\t0xFFFFFFFA, 0xFFFFFFFA, 0xFFFFFFF9, 0xFFFFFFF9, 0xFFFFFFF9, 0xFFFFFFF8, 0xFFFFFFF8, 0xFFFFFFF7, 0xFFFFFFF7, 0xFFFFFFF6, 0xFFFFFFF6, 0xFFFFFFF6, 0xFFFFFFF5, 0xFFFFFFF5,\n\t\t\t0xFFFFFFF4, 0xFFFFFFF4, 0xFFFFFFF3, 0xFFFFFFF3, 0xFFFFFFF2, 0xFFFFFFF2, 0xFFFFFFF2, 0xFFFFFFF1, 0xFFFFFFF1, 0xFFFFFFF0, 0xFFFFFFF0, 0xFFFFFFEF, 0xFFFFFFEF, 0xFFFFFFEE,\n\t\t\t0xFFFFFFEE,\t0xFFFFFFED, 0xFFFFFFEC, 0xFFFFFFEC, 0xFFFFFFEB, 0xFFFFFFEB, 0xFFFFFFEA, 0xFFFFFFEA, 0xFFFFFFE9, 0xFFFFFFE9, 0xFFFFFFE8, 0xFFFFFFE7, 0xFFFFFFE7, 0xFFFFFFE6,\n\t\t\t0xFFFFFFE6,\t0xFFFFFFE5, 0xFFFFFFE4, 0xFFFFFFE4, 0xFFFFFFE3, 0xFFFFFFE2, 0xFFFFFFE2, 0xFFFFFFE1, 0xFFFFFFE0, 0xFFFFFFDF, 0xFFFFFFDF, 0xFFFFFFDE, 0xFFFFFFDD, 0xFFFFFFDC,\n\t\t\t0xFFFFFFDC, 0xFFFFFFDB,\t0xFFFFFFDA, 0xFFFFFFD9, 0xFFFFFFD8, 0xFFFFFFD8, 0xFFFFFFD7, 0xFFFFFFD6, 0xFFFFFFD5, 0xFFFFFFD4, 0xFFFFFFD3, 0xFFFFFFD2, 0xFFFFFFD1, 0xFFFFFFD0,\n\t\t\t0xFFFFFFCF, 0xFFFFFFCE, 0xFFFFFFCD, 0xFFFFFFCC, 0xFFFFFFCA, 0xFFFFFFC9, 0xFFFFFFC8, 0xFFFFFFC7, 0xFFFFFFC5, 0xFFFFFFC4, 0xFFFFFFC3, 0xFFFFFFC1, 0xFFFFFFC0, 0xFFFFFFBE,\n\t\t\t0xFFFFFFBD, 0xFFFFFFBB, 0xFFFFFFB9,\t0xFFFFFFB8, 0xFFFFFFB6, 0xFFFFFFB4, 0xFFFFFFB2, 0xFFFFFFB0, 0xFFFFFFAD, 0xFFFFFFAB, 0xFFFFFFA9, 0xFFFFFFA6, 0xFFFFFFA3, 0xFFFFFFA0,\n\t\t\t0xFFFFFF9D, 0xFFFFFF9A, 0xFFFFFF96,\t0xFFFFFF92, 0xFFFFFF8D, 0xFFFFFF88, 0xFFFFFF82, 0xFFFFFF7B, 0xFFFFFF74, 0xFFFFFF6A, 0xFFFFFF5D, 0xFFFFFF4C, 0xFFFFFF2E, 0xFFFFFC78\n\t\t};\n\n\t\tconst uint16 pan_values_low[128] =\n\t\t{\n\t\t 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFE, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFC, 0xFFFC, 0xFFFC, 0xFFFB, 0xFFFB, 0xFFFA, 0xFFFA, 0xFFFA, 0xFFF9, 0xFFF9, 0xFFF8, 0xFFF8,\n\t\t0xFFF7, 0xFFF7, 0xFFF6, 0xFFF5, 0xFFF5, 0xFFF4, 0xFFF4, 0xFFF3, 0xFFF2, 0xFFF2, 0xFFF1, 0xFFF0, 0xFFEF, 0xFFEF, 0xFFEE, 0xFFED, 0xFFEC, 0xFFEB, 0xFFEB, 0xFFEA, 0xFFE9, 0xFFE8, 0xFFE7, 0xFFE6, 0xFFE5, 0xFFE4, 0xFFE3, 0xFFE2, 0xFFE1,\n\t\t0xFFE0, 0xFFDE, 0xFFDD, 0xFFDC, 0xFFDB, 0xFFDA, 0xFFD8, 0xFFD7, 0xFFD6, 0xFFD4, 0xFFD3, 0xFFD1, 0xFFD0, 0xFFCE, 0xFFCC, 0xFFCB, 0xFFC9, 0xFFC7, 0xFFC6, 0xFFC4, 0xFFC2, 0xFFC0, 0xFFBE, 0xFFBC, 0xFFBA, 0xFFB7, 0xFFB5, 0xFFB3, 0xFFB0,\n\t\t0xFFAE, 0xFFAB, 0xFFA8, 0xFFA6, 0xFFA3, 0xFFA0, 0xFF9C, 0xFF99, 0xFF96, 0xFF92, 0xFF8E, 0xFF8A, 0xFF86, 0xFF82, 0xFF7D, 0xFF78, 0xFF73, 0xFF6E, 0xFF68, 0xFF61, 0xFF5A, 0xFF53, 0xFF4B, 0xFF42, 0xFF37, 0xFF2C, 0xFF1F, 0xFF0F, 0xFEFB,\n\t\t0xFEE2, 0xFEBF, 0xFE83, 0xFC40\n\t\t};\n\n\t\tconst uint16 pan_values_high[128] =\n\t\t{\n\t\t0xFFC3, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC5, 0xFFC6, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC8, 0xFFC9, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCB, 0xFFCC, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCE, 0xFFCF, 0xFFCF, 0xFFD0, 0xFFD0, 0xFFD1, 0xFFD1, 0xFFD2, 0xFFD2, 0xFFD3,\n\t\t0xFFD3, 0xFFD4, 0xFFD4, 0xFFD5, 0xFFD5, 0xFFD6, 0xFFD6, 0xFFD7, 0xFFD7, 0xFFD8, 0xFFD8, 0xFFD9, 0xFFD9, 0xFFDA, 0xFFDA, 0xFFDA, 0xFFDB, 0xFFDB, 0xFFDC, 0xFFDC, 0xFFDD, 0xFFDD, 0xFFDD, 0xFFDE, 0xFFDE, 0xFFDF, 0xFFDF, 0xFFE0, 0xFFE0,\n\t\t0xFFE0, 0xFFE1, 0xFFE1, 0xFFE1, 0xFFE2, 0xFFE2, 0xFFE3, 0xFFE3, 0xFFE3, 0xFFE4, 0xFFE4, 0xFFE4, 0xFFE5, 0xFFE5, 0xFFE5, 0xFFE6, 0xFFE6, 0xFFE6, 0xFFE7, 0xFFE7, 0xFFE7, 0xFFE8, 0xFFE8, 0xFFE8, 0xFFE9, 0xFFE9, 0xFFE9, 0xFFEA, 0xFFEA,\n\t\t0xFFEA, 0xFFEB, 0xFFEB, 0xFFEB, 0xFFEC, 0xFFEC, 0xFFEC, 0xFFEC, 0xFFED, 0xFFED, 0xFFED, 0xFFEE, 0xFFEE, 0xFFEE, 0xFFEE, 0xFFEF, 0xFFEF, 0xFFEF, 0xFFEF, 0xFFF0, 0xFFF0, 0xFFF0, 0xFFF0, 0xFFF1, 0xFFF1, 0xFFF1, 0xFFF1, 0xFFF2, 0xFFF2,\n\t\t0xFFF2, 0xFFF2, 0xFFF3, 0xFFF3, 0xFFF3, 0xFFF3, 0xFFF3, 0xFFF4, 0xFFF4, 0xFFF4, 0xFFF4, 0xFFF5\n\t\t};\n\n\t} g_snd_user_data{};\n\n\tvoid _MIXChannelResetTV(MixChannel* channel, sint32 index)\n\t{\n\t\tassert(index == 0);\n\n\t\tchannel->tv_mode = 0;\n\n\t\tchannel->tv_control.pan = 0x40;\n\t\tchannel->tv_control.span = 0x7F;\n\t\tchannel->tv_control.fader = 0;\n\t\tchannel->tv_control.lfe = -960;\n\n\t\tfor (size_t i = 0; i < AX_AUX_BUS_COUNT; ++i)\n\t\t{\n\t\t\tchannel->tv_control.aux[i] = -960;\n\t\t}\n\n\t\tfor (size_t i = 0; i < AX_MAX_NUM_BUS; ++i)\n\t\t{\n\t\t\tfor (size_t j = 0; j < AX_TV_CHANNEL_COUNT; ++j)\n\t\t\t{\n\t\t\t\tchannel->tv_volume[i][j].volume = 0;\n\t\t\t\tchannel->tv_volume[i][j].volume_target = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid _MIXChannelResetDRC(MixChannel* channel, sint32 index)\n\t{\n\t\tassert(index < AX_MAX_NUM_DRC);\n\t\tchannel->drc_mode[index] = 0;\n\n\t\tchannel->drc_control[index].pan = 0x40;\n\t\tchannel->drc_control[index].span = 0x7F;\n\t\tchannel->drc_control[index].fader = 0;\n\t\tchannel->drc_control[index].lfe = -960;\n\n\t\tfor (size_t i = 0; i < AX_AUX_BUS_COUNT; ++i)\n\t\t{\n\t\t\tchannel->drc_control[index].aux[i] = -960;\n\t\t}\n\n\t\tfor (size_t i = 0; i < AX_MAX_NUM_BUS; ++i)\n\t\t{\n\t\t\tfor (size_t j = 0; j < AX_DRC_CHANNEL_COUNT; ++j)\n\t\t\t{\n\t\t\t\tchannel->drc_volume[index][i][j].volume = 0;\n\t\t\t\tchannel->drc_volume[index][i][j].volume_target = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid _MIXChannelResetRmt(MixChannel* channel, sint32 index)\n\t{\n\t\tassert(index < AX_MAX_NUM_RMT);\n\t\tchannel->rmt_mode[index] = 0;\n\n\t\tchannel->rmt_control[index].pan = 0x40;\n\t\tchannel->rmt_control[index].span = 0x7F;\n\t\tchannel->rmt_control[index].fader = 0;\n\t\tchannel->rmt_control[index].lfe = -960;\n\n\t\tfor (size_t i = 0; i < AX_AUX_BUS_COUNT; ++i)\n\t\t{\n\t\t\tchannel->rmt_control[index].aux[i] = -960;\n\t\t}\n\n\t\tfor (size_t i = 0; i < AX_MAX_NUM_BUS; ++i)\n\t\t{\n\t\t\tfor (size_t j = 0; j < AX_RMT_CHANNEL_COUNT; ++j)\n\t\t\t{\n\t\t\t\tchannel->rmt_volume[index][i][j].volume = 0;\n\t\t\t\tchannel->rmt_volume[index][i][j].volume_target = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid MIXResetChannelData(MixChannel* channel)\n\t{\n\t\tchannel->update_mode = AX_UPDATE_MODE_50000000;\n\t\tchannel->input_level = 0;\n\t\tchannel->volume.volume = 0;\n\t\tchannel->volume.volume_target = 0;\n\n\t\t_MIXChannelResetTV(channel, 0);\n\n\t\tfor (int i = 0; i < AX_MAX_NUM_DRC; ++i)\n\t\t\t_MIXChannelResetDRC(channel, i);\n\n\t\tfor (int i = 0; i < AX_MAX_NUM_RMT; ++i)\n\t\t\t_MIXChannelResetRmt(channel, i);\n\t}\n\n\tvoid _MIXControl_SetDevicePan(MixControl* control, int device_type, sint16 channels[])\n\t{\n\t\tconst auto pandiff = 0x7F - control->pan;\n\t\tconst auto spandiff = 0x7F - control->span;\n\n\t\tif (device_type == AX_DEV_TV)\n\t\t{\n\t\t\tconst uint32 sound_mode = g_snd_user_data.device_info.tv_sound_mode;\n\t\t\tif (sound_mode == 3)\n\t\t\t{\n\t\t\t\tchannels[0] = g_snd_user_data.pan_values_low[control->pan];\n\t\t\t\tchannels[1] = g_snd_user_data.pan_values_low[pandiff];\n\t\t\t\tchannels[2] = g_snd_user_data.pan_values_high[pandiff];\n\t\t\t\tchannels[3] = g_snd_user_data.pan_values_high[control->pan];\n\t\t\t\tchannels[4] = g_snd_user_data.pan_values_high[spandiff];\n\t\t\t\tchannels[5] = g_snd_user_data.pan_values_high[control->span];\n\t\t\t}\n\t\t\telse if (sound_mode != 4)\n\t\t\t{\n\t\t\t\tchannels[0] = g_snd_user_data.pan_values[control->pan];\n\t\t\t\tchannels[1] = g_snd_user_data.pan_values[pandiff];\n\t\t\t\tchannels[2] = 0;\n\t\t\t\tchannels[3] = 0;\n\t\t\t\tchannels[4] = g_snd_user_data.pan_values[spandiff];\n\t\t\t\tchannels[5] = g_snd_user_data.pan_values[control->span];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint32 pan = 0x7F;\n\t\t\t\tif (((uint32)control->pan >> 1) < 0x7F)\n\t\t\t\t\tpan = (uint32)control->pan >> 1;\n\n\t\t\t\tchannels[0] = g_snd_user_data.pan_values[pan] + g_snd_user_data.pan_values[spandiff];\n\n\t\t\t\tuint32 span = 0x7F;\n\t\t\t\tif (((uint32)pandiff >> 1) < 0x7E)\n\t\t\t\t\tspan = (uint32)pandiff >> 1;\n\n\t\t\t\tchannels[1] = g_snd_user_data.pan_values[span] + g_snd_user_data.pan_values[spandiff];\n\n\t\t\t\t// TODO\n\t\t\t}\n\t\t}\n\t\telse if (device_type == AX_DEV_DRC)\n\t\t{\n\t\t\t// TODO\n\t\t}\n\t}\n\n\tsint16 __MIXTranslateVolume(sint16 input)\n\t{\n\t\tif (input <= -904)\n\t\t\treturn 0;\n\n\t\tif (input > 0x3C)\n\t\t\treturn -156;\n\n\t\treturn (sint16)g_snd_user_data.volume[input + 903];\n\t}\n\n\tvoid AXFXInitDefaultHooks();\n\n\tvoid MIXInit()\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXInit()\");\n\n\t\tif (g_snd_user_data.initialized)\n\t\t\treturn;\n\n\t\tg_snd_user_data.max_voices = AX_MAX_VOICES; // AXGetMaxVoices();\n\t\tfor (sint32 i = 0; i < g_snd_user_data.max_voices; ++i)\n\t\t{\n\t\t\tMIXResetChannelData(&g_snd_user_data.mix_channel[i]);\n\t\t}\n\n\t\tg_snd_user_data.initialized = true;\n\t\tg_snd_user_data.device_info.tv_sound_mode = 1;\n\t\tg_snd_user_data.device_info.drc_sound_mode = 1;\n\t\tg_snd_user_data.device_info.rmt_sound_mode = 0;\n\n\t\tAXFXInitDefaultHooks();\n\t}\n\n\tvoid MIXSetSoundMode(uint32 sound_mode)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXSetSoundMode(0x{:x})\", sound_mode);\n\n\t\tif (sound_mode >= 2)\n\t\t\tsound_mode = 1;\n\n\t\tg_snd_user_data.device_info.tv_sound_mode = sound_mode;\n\t}\n\n\tuint32 MIXGetSoundMode()\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXGetSoundMode()\");\n\t\treturn g_snd_user_data.device_info.tv_sound_mode;\n\t}\n\n\tvoid _MIXUpdateTV(MixChannel* channel, sint32 index)\n\t{\n\t\tassert(index == 0);\n\n\t\tbool updated_volume = false;\n\t\tif ((channel->tv_mode & AX_UPDATE_MODE_80000000) != 0)\n\t\t{\n\t\t\tfor (size_t i = 0; i < AX_MAX_NUM_BUS; ++i)\n\t\t\t{\n\t\t\t\tfor (size_t j = 0; j < AX_TV_CHANNEL_COUNT; ++j)\n\t\t\t\t{\n\t\t\t\t\tchannel->tv_volume[i][j].volume = channel->tv_volume[i][j].volume_target;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tchannel->tv_mode &= ~AX_UPDATE_MODE_80000000;\n\t\t\tupdated_volume = true;\n\t\t}\n\n\t\tif ((channel->tv_mode & AX_UPDATE_MODE_40000000_VOLUME) == 0)\n\t\t{\n\t\t\tif (!updated_volume)\n\t\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (g_snd_user_data.device_info.tv_sound_mode == 0)\n\t\t\t{\n\t\t\t\tsint32 chan4 = channel->tv_channels[4];\n\t\t\t\tif (chan4 < -0x78)\n\t\t\t\t\tchan4 = -0x78;\n\n\t\t\t\tconst sint32 fader = channel->tv_control.fader;\n\n\t\t\t\tchannel->tv_volume[0][0].volume_target = __MIXTranslateVolume(chan4 + fader);\n\t\t\t\tchannel->tv_volume[0][1].volume_target = __MIXTranslateVolume(chan4 + fader);\n\t\t\t\tchannel->tv_volume[0][2].volume_target = 0;\n\t\t\t\tchannel->tv_volume[0][3].volume_target = 0;\n\t\t\t\tchannel->tv_volume[0][4].volume_target = 0;\n\t\t\t\tchannel->tv_volume[0][5].volume_target = 0;\n\n\t\t\t\tfor (int i = 0; i < 3; ++i)\n\t\t\t\t{\n\t\t\t\t\tconst sint32 aux = channel->tv_control.aux[i];\n\t\t\t\t\tif ((channel->tv_mode & (1 << i)) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tchannel->tv_volume[1 + i][0].volume_target = __MIXTranslateVolume(chan4 + fader + aux);\n\t\t\t\t\t\tchannel->tv_volume[1 + i][1].volume_target = __MIXTranslateVolume(chan4 + fader + aux);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tchannel->tv_volume[1 + i][0].volume_target = __MIXTranslateVolume(chan4 + aux);\n\t\t\t\t\t\tchannel->tv_volume[1 + i][1].volume_target = __MIXTranslateVolume(chan4 + aux);\n\t\t\t\t\t}\n\n\t\t\t\t\tchannel->tv_volume[1 + i][2].volume_target = 0;\n\t\t\t\t\tchannel->tv_volume[1 + i][3].volume_target = 0;\n\t\t\t\t\tchannel->tv_volume[1 + i][4].volume_target = 0;\n\t\t\t\t\tchannel->tv_volume[1 + i][5].volume_target = 0;\n\t\t\t\t}\n\n\t\t\t\tchannel->tv_mode &= ~AX_UPDATE_MODE_40000000_VOLUME;\n\t\t\t\tchannel->tv_mode |= AX_UPDATE_MODE_80000000;\n\t\t\t}\n\t\t\telse if (g_snd_user_data.device_info.tv_sound_mode < 3)\n\t\t\t{\n\t\t\t\tsint32 chan4 = channel->tv_channels[4];\n\t\t\t\tif (chan4 < -0x78)\n\t\t\t\t\tchan4 = -0x78;\n\n\t\t\t\tconst sint32 fader = channel->tv_control.fader;\n\n\t\t\t\tconst sint32 chan0 = channel->tv_channels[0];\n\t\t\t\tconst sint32 chan1 = channel->tv_channels[1];\n\t\t\t\tchannel->tv_volume[0][0].volume_target = __MIXTranslateVolume(chan4 + chan0 + fader);\n\t\t\t\tchannel->tv_volume[0][1].volume_target = __MIXTranslateVolume(chan4 + chan1 + fader);\n\t\t\t\tchannel->tv_volume[0][2].volume_target = 0;\n\t\t\t\tchannel->tv_volume[0][3].volume_target = 0;\n\t\t\t\tchannel->tv_volume[0][4].volume_target = 0;\n\t\t\t\tchannel->tv_volume[0][5].volume_target = 0;\n\n\t\t\t\tfor (int i = 0; i < 3; ++i)\n\t\t\t\t{\n\t\t\t\t\tconst sint32 aux = channel->tv_control.aux[i];\n\t\t\t\t\tif ((channel->tv_mode & (1 << i)) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tchannel->tv_volume[1 + i][0].volume_target = __MIXTranslateVolume(chan4 + chan0 + fader + aux);\n\t\t\t\t\t\tchannel->tv_volume[1 + i][1].volume_target = __MIXTranslateVolume(chan4 + chan1 + fader + aux);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tchannel->tv_volume[1 + i][0].volume_target = __MIXTranslateVolume(chan4 + chan0 + aux);\n\t\t\t\t\t\tchannel->tv_volume[1 + i][1].volume_target = __MIXTranslateVolume(chan4 + chan1 + aux);\n\t\t\t\t\t}\n\n\t\t\t\t\tchannel->tv_volume[1 + i][2].volume_target = 0;\n\t\t\t\t\tchannel->tv_volume[1 + i][3].volume_target = 0;\n\t\t\t\t\tchannel->tv_volume[1 + i][4].volume_target = 0;\n\t\t\t\t\tchannel->tv_volume[1 + i][5].volume_target = 0;\n\t\t\t\t}\n\n\t\t\t\tchannel->tv_mode &= ~AX_UPDATE_MODE_40000000_VOLUME;\n\t\t\t\tchannel->tv_mode |= AX_UPDATE_MODE_80000000;\n\t\t\t}\n\t\t\telse if (g_snd_user_data.device_info.tv_sound_mode == 3)\n\t\t\t{\n\t\t\t\t// TODO\n\t\t\t}\n\t\t\telse if (g_snd_user_data.device_info.tv_sound_mode == 4)\n\t\t\t{\n\t\t\t\t// TODO\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tchannel->tv_mode &= ~AX_UPDATE_MODE_40000000_VOLUME;\n\t\t\t\tchannel->tv_mode |= AX_UPDATE_MODE_80000000;\n\t\t\t}\n\t\t}\n\n\t\tAXCHMIX2 mix[AX_TV_CHANNEL_COUNT][AX_MAX_NUM_BUS];\n\t\tfor (size_t i = 0; i < AX_MAX_NUM_BUS; ++i)\n\t\t{\n\t\t\tfor (size_t j = 0; j < AX_TV_CHANNEL_COUNT; ++j)\n\t\t\t{\n\t\t\t\tconst sint16 target = channel->tv_volume[i][j].volume_target;\n\t\t\t\tconst sint16 volume = channel->tv_volume[i][j].volume;\n\n\t\t\t\tmix[j][i].vol = volume;\n\t\t\t\tmix[j][i].delta = (target - volume) / 96; // 32000HZ SAMPLES_3MS\n\t\t\t}\n\t\t}\n\t\tAXSetVoiceDeviceMix(channel->voice.GetPtr(), AX_DEV_TV, index, (snd_core::AXCHMIX_DEPR*)&mix[0][0]);\n\t}\n\n\tvoid _MIXUpdateDRC(MixChannel* channel, sint32 index)\n\t{\n\t\t// todo\n\t}\n\n\tvoid _MIXUpdateRmt(MixChannel* channel, sint32 index)\n\t{\n\t\t// todo\n\t}\n\n\tvoid MIXInitChannel(AXVPB* voice, uint16 mode, uint16 input, uint16 aux1, uint16 aux2, uint16 aux3, uint16 pan, uint16 span, uint16 fader)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXInitChannel(0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x})\", MEMPTR(voice).GetMPTR(), mode, input, aux1, aux2, aux3, pan, span, fader);\n\t\tcemu_assert_debug(voice);\n\n\t\tAXVoiceBegin(voice);\n\n\t\tMIXAssignChannel(voice);\n\t\tMIXInitInputControl(voice, input, mode);\n\n\t\tconst uint32 index = voice->index;\n\t\tauto& channel = g_snd_user_data.mix_channel[index];\n\n\t\tchannel.tv_control.aux[0] = aux1;\n\t\tchannel.tv_control.aux[1] = aux2;\n\t\tchannel.tv_control.aux[2] = aux3;\n\n\t\tchannel.tv_control.pan = pan;\n\t\tchannel.tv_control.span = span;\n\t\tchannel.tv_control.fader = fader;\n\t\t// channel.tv_control.lfe = lfe; // 0x1A -> not set?\n\n\t\tchannel.tv_mode = AX_UPDATE_MODE_40000007 & mode;\n\t\t_MIXControl_SetDevicePan(&channel.tv_control, AX_DEV_TV, channel.tv_channels);\n\n\t\tchannel.tv_mode |= AX_UPDATE_MODE_40000000_VOLUME;\n\t\t_MIXUpdateTV(&channel, 0);\n\n\t\tAXVoiceEnd(voice);\n\t}\n\n\tvoid MIXAssignChannel(AXVPB* voice)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXAssignChannel(0x{:x})\", MEMPTR(voice).GetMPTR());\n\t\tcemu_assert_debug(voice);\n\n\t\tAXVoiceBegin(voice);\n\n\t\tconst uint32 voice_index = voice->index;\n\t\tauto channel = &g_snd_user_data.mix_channel[voice_index];\n\t\tMIXResetChannelData(channel);\n\t\tchannel->voice = voice;\n\n\t\tAXVoiceEnd(voice);\n\t}\n\n\tvoid MIXDRCInitChannel(AXVPB* voice, uint16 mode, uint16 vol1, uint16 vol2, uint16 vol3)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXDRCInitChannel(0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x})\", MEMPTR(voice).GetMPTR(), mode, vol1, vol2, vol3);\n\t\tcemu_assert_debug(voice);\n\n\t\tAXVoiceBegin(voice);\n\n\t\tconst uint32 index = voice->index;\n\t\tauto& channel = g_snd_user_data.mix_channel[index];\n\n\t\t_MIXChannelResetDRC(&channel, 0);\n\n\t\tchannel.drc_volume[1][1][1].volume = vol1;\n\t\tchannel.drc_volume[1][1][2].volume_target = vol2;\n\t\tchannel.drc_volume[1][1][3].volume_target = vol3;\n\n\t\tchannel.drc_mode[0] = AX_UPDATE_MODE_40000007 & mode;\n\t\t_MIXControl_SetDevicePan(&channel.drc_control[0], AX_DEV_DRC, &channel.drc_channels[0][0]);\n\n\t\tchannel.drc_mode[0] |= AX_UPDATE_MODE_40000000_VOLUME;\n\t\t_MIXUpdateDRC(&channel, 0);\n\n\t\tAXVoiceEnd(voice);\n\t}\n\n\tvoid MIXSetInput(AXVPB* voice, uint16 input)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXSetInput(0x{:x}, 0x{:x})\", MEMPTR(voice).GetMPTR(), input);\n\n\t\tconst uint32 voice_index = voice->index;\n\t\tconst auto channel = &g_snd_user_data.mix_channel[voice_index];\n\n\t\tchannel->input_level = input;\n\t\tchannel->update_mode |= AX_UPDATE_MODE_10000000;\n\n\t}\n\n\tvoid MIXUpdateSettings()\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXUpdateSettings()\");\n\n\t\tif (!g_snd_user_data.initialized)\n\t\t\treturn;\n\n\t\tif (g_snd_user_data.max_voices <= 0)\n\t\t\treturn;\n\n\t\tfor (sint32 i = 0; i < g_snd_user_data.max_voices; ++i)\n\t\t{\n\t\t\tauto& channel = g_snd_user_data.mix_channel[i];\n\t\t\tif (!channel.voice)\n\t\t\t\tcontinue;\n\n\t\t\tconst auto voice = channel.voice.GetPtr();\n\n\t\t\tAXVoiceBegin(voice);\n\n\t\t\tbool volume_updated = false;\n\t\t\tif ((channel.update_mode & AX_UPDATE_MODE_20000000) != 0)\n\t\t\t{\n\t\t\t\tchannel.volume.volume = channel.volume.volume_target;\n\t\t\t\tchannel.update_mode &= ~AX_UPDATE_MODE_20000000;\n\t\t\t\tvolume_updated = true;\n\t\t\t}\n\n\t\t\tif ((channel.update_mode & AX_UPDATE_MODE_10000000) == 0)\n\t\t\t{\n\t\t\t\tif (volume_updated)\n\t\t\t\t{\n\t\t\t\t\tAXPBVE ve;\n\t\t\t\t\tve.currentVolume = channel.volume.volume;\n\t\t\t\t\tve.currentDelta = (channel.volume.volume_target - channel.volume.volume) / 96;\n\t\t\t\t\tAXSetVoiceVe(voice, &ve);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsint32 volume = 0;\n\t\t\t\tif ((channel.update_mode & 8) == 0)\n\t\t\t\t\tvolume = __MIXTranslateVolume(channel.input_level);\n\n\t\t\t\tchannel.volume.volume_target = volume;\n\n\t\t\t\tchannel.update_mode &= ~AX_UPDATE_MODE_10000000;\n\t\t\t\tchannel.update_mode |= AX_UPDATE_MODE_20000000;\n\n\t\t\t\tAXPBVE ve;\n\t\t\t\tve.currentVolume = channel.volume.volume;\n\t\t\t\tve.currentDelta = (channel.volume.volume_target - channel.volume.volume) / 96;\n\t\t\t\tAXSetVoiceVe(voice, &ve);\n\t\t\t}\n\n\t\t\t_MIXUpdateTV(&channel, 0);\n\n\t\t\tfor (int i = 0; i < 2; ++i)\n\t\t\t\t_MIXUpdateDRC(&channel, i);\n\n\t\t\t// TODO remote mix\n\t\t\tAXCHMIX2 mix[4];\n\t\t\tfor (int j = 0; j < 4; ++j)\n\t\t\t{\n\t\t\t\tAXSetVoiceDeviceMix(voice, AX_DEV_RMT, i, (snd_core::AXCHMIX_DEPR*)mix);\n\t\t\t}\n\n\n\t\t\tAXVoiceEnd(voice);\n\t\t}\n\n\t\t// TODO\n\t}\n\n\tvoid MIXSetDeviceSoundMode(uint32 device, uint32 mode)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXSetDeviceSoundMode(0x{:x}, 0x{:x})\", device, mode);\n\t\tcemu_assert_debug(device < AX_DEV_COUNT);\n\t\tcemu_assert_debug(mode <= 4);\n\n\t\tbool is_tv_device = false;\n\t\tbool is_drc_device = false;\n\t\tif (device == AX_DEV_TV)\n\t\t{\n\t\t\tg_snd_user_data.device_info.tv_sound_mode = mode;\n\t\t\tis_tv_device = true;\n\t\t}\n\t\telse if (device == AX_DEV_DRC)\n\t\t{\n\t\t\tcemu_assert_debug(mode <= 2);\n\t\t\tg_snd_user_data.device_info.drc_sound_mode = mode;\n\t\t\tis_drc_device = true;\n\t\t}\n\t\telse if (device == AX_DEV_RMT)\n\t\t{\n\t\t\tcemu_assert_debug(mode == 0);\n\t\t\tg_snd_user_data.device_info.rmt_sound_mode = mode;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::SoundAPI, \"ERROR: MIXSetDeviceSoundMode(0x{:x}, 0x{:x}) -> wrong device\", device, mode);\n\t\t}\n\n\t\tfor (sint32 i = 0; i < g_snd_user_data.max_voices; ++i)\n\t\t{\n\t\t\tauto& channel = g_snd_user_data.mix_channel[i];\n\t\t\tif (!channel.voice)\n\t\t\t\tcontinue;\n\n\t\t\tconst auto voice = channel.voice.GetPtr();\n\t\t\tAXVoiceBegin(voice);\n\n\t\t\tif (is_tv_device)\n\t\t\t{\n\t\t\t\tchannel.tv_mode |= AX_UPDATE_MODE_40000000_VOLUME;\n\t\t\t\t_MIXControl_SetDevicePan(&channel.tv_control, AX_DEV_TV, channel.tv_channels);\n\t\t\t}\n\n\t\t\tif (is_drc_device)\n\t\t\t{\n\t\t\t\tfor (sint32 j = 0; j < AX_MAX_NUM_DRC; ++j)\n\t\t\t\t{\n\t\t\t\t\tchannel.drc_mode[j] |= AX_UPDATE_MODE_40000000_VOLUME;\n\t\t\t\t\t_MIXControl_SetDevicePan(&channel.drc_control[j], AX_DEV_DRC, channel.drc_channels[j]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tAXVoiceEnd(voice);\n\t\t}\n\t}\n\n\tvoid MIXInitDeviceControl(AXVPB* voice, uint32 device_type, uint32 index, MixControl* control, uint32 mode)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXInitDeviceControl(0x{:0x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x} )\", MEMPTR(voice).GetMPTR(), device_type, index, MEMPTR(control).GetMPTR(), mode);\n\n\t\tcemu_assert_debug(device_type < AX_DEV_COUNT);\n\t\tcemu_assert_debug(voice);\n\t\tcemu_assert_debug(control);\n\n\t\tAXVoiceBegin(voice);\n\n\t\tconst uint32 voice_index = voice->index;\n\t\tauto& channel = g_snd_user_data.mix_channel[voice_index];\n\n\t\tchannel.voice = voice;\n\n\t\tif (device_type == AX_DEV_TV)\n\t\t{\n\t\t\tcemu_assert_debug(index == 0);\n\t\t\t_MIXChannelResetTV(&channel, index);\n\n\t\t\tmemcpy(&channel.tv_control, control, sizeof(MixControl));\n\t\t\t_MIXControl_SetDevicePan(&channel.tv_control, device_type, channel.tv_channels);\n\n\t\t\tchannel.tv_mode |= AX_UPDATE_MODE_40000000_VOLUME;\n\t\t\t_MIXUpdateTV(&channel, index);\n\t\t}\n\t\telse if (device_type == AX_DEV_DRC)\n\t\t{\n\t\t\tcemu_assert_debug(index < 2);\n\t\t\t_MIXChannelResetDRC(&channel, index);\n\n\t\t\tmemcpy(&channel.drc_control[index], control, sizeof(MixControl));\n\t\t\t_MIXControl_SetDevicePan(&channel.drc_control[index], device_type, channel.drc_channels[index]);\n\n\t\t\tchannel.drc_mode[index] |= AX_UPDATE_MODE_40000000_VOLUME;\n\t\t\t_MIXUpdateDRC(&channel, index);\n\t\t}\n\t\telse if (device_type == AX_DEV_RMT)\n\t\t{\n\t\t\tcemu_assert_debug(index < 4);\n\t\t\t_MIXChannelResetRmt(&channel, index);\n\n\t\t\tmemcpy(&channel.rmt_control[index], control, sizeof(MixControl));\n\t\t\t_MIXControl_SetDevicePan(&channel.rmt_control[index], device_type, channel.rmt_channels[index]);\n\n\t\t\tchannel.rmt_mode[index] = mode & 0xf;\n\t\t\t_MIXUpdateRmt(&channel, index);\n\t\t}\n\n\t\tAXVoiceEnd(voice);\n\t}\n\n\n\tvoid MIXInitInputControl(AXVPB* voice, uint16 input, uint32 mode)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"MIXInitInputControl(0x{:x}, 0x{:x}, 0x{:x} )\", MEMPTR(voice).GetMPTR(), input, mode);\n\t\tcemu_assert_debug(voice);\n\n\t\tAXVoiceBegin(voice);\n\n\t\tconst uint32 voice_index = voice->index;\n\t\tauto& channel = g_snd_user_data.mix_channel[voice_index];\n\n\t\tmode &= 8;\n\t\tmode |= AX_UPDATE_MODE_10000000;\n\t\tchannel.update_mode = mode;\n\n\t\tchannel.input_level = input;\n\n\t\tAXVoiceEnd(voice);\n\t}\n\n\tvoid MIXSetDeviceFader(AXVPB* vpb, uint32 device, uint32 deviceIndex, sint16 newFader)\n\t{\n\t\t// not well tested\n\t\tcemu_assert(device < AX_DEV_COUNT);\n\t\tMixChannel& mixChannel = g_snd_user_data.mix_channel[vpb->index];\n\n\t\tAXVoiceBegin(vpb);\n\n\t\tMixControl& mixControl = mixChannel.GetMixControl(device, deviceIndex);\n\t\tMixMode& mixMode = mixChannel.GetMode(device, deviceIndex);\n\n\t\tif (mixControl.fader == newFader)\n\t\t{\n\t\t\tAXVoiceEnd(vpb);\n\t\t\treturn;\n\t\t}\n\n\t\tmixControl.fader = newFader;\n\t\tmixMode |= AX_UPDATE_MODE_40000000_VOLUME;\n\t\tAXVoiceEnd(vpb);\n\t}\n\n\tvoid MIXSetDevicePan(AXVPB* vpb, uint32 device, uint32 deviceIndex, sint16 newPan)\n\t{\n\t\t// not well tested\n\t\tcemu_assert(device < AX_DEV_COUNT);\n\t\tMixChannel& mixChannel = g_snd_user_data.mix_channel[vpb->index];\n\n\t\tAXVoiceBegin(vpb);\n\n\t\tMixControl& mixControl = mixChannel.GetMixControl(device, deviceIndex);\n\t\tMixMode& mixMode = mixChannel.GetMode(device, deviceIndex);\n\t\tsint16* deviceChannels = mixChannel.GetChannels(device, deviceIndex);\n\n\t\tif (mixControl.fader == newPan)\n\t\t{\n\t\t\tAXVoiceEnd(vpb);\n\t\t\treturn;\n\t\t}\n\n\t\tmixControl.pan = newPan;\n\t\t_MIXControl_SetDevicePan(&mixControl, device, deviceChannels);\n\t\tmixMode |= AX_UPDATE_MODE_40000000_VOLUME;\n\t\tAXVoiceEnd(vpb);\n\t}\n\n\tstruct AXPBADPCM\n\t{\n\t\tuint16be table[8][2]; // 0x00\n\t\tuint16be gain;\n\t\tuint16be predicator;\n\t\tuint16be yn1;\n\t\tuint16be yn2;\n\t};\n\n\tstruct AXPBADPCMLOOP\n\t{\n\t\tuint16be predicator; // 0x00\n\t\tuint16be yn1; // 0x02\n\t\tuint16be yn2; // 0x04\n\t};\n\n\tstruct SPAdpcmEntry\n\t{\n\t\tAXPBADPCM adpcm;\n\t\tAXPBADPCMLOOP adpcmLoop;\n\t};\n\n\tstruct SPSoundEntry\n\t{\n\t\tuint32be type; // 0x00\n\t\tuint32be sampleRate; // 0x04\n\t\tuint32be loopAddress; // 0x08\n\t\tuint32be loopEndAddress; // 0x0C\n\t\tuint32be endOffset; // 0x10\n\t\tuint32be currentOffset; // 0x14\n\t\tMEMPTR<SPAdpcmEntry> adpcmEntry; // 0x18\n\t};\n\tstatic_assert(sizeof(SPSoundEntry) == 0x1C);\n\n\tstruct SPSoundTable\n\t{\n\t\tuint32be count;\n\t\tSPSoundEntry entries[1];\n\t};\n\n\tvoid SPInitSoundTable(SPSoundTable* soundTable, uint8* samples, uint32be* endOffsetPtr)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"SPInitSoundTable(0x{:x}, 0x{:x}, 0x{:x} )\", MEMPTR(soundTable).GetMPTR(), MEMPTR(samples).GetMPTR(), MEMPTR(endOffsetPtr).GetMPTR());\n\t\tif (!soundTable)\n\t\t\treturn;\n\n\t\tif (!samples)\n\t\t\treturn;\n\n\t\tuint32be endOffset = 0;\n\t\tfor(uint32 i = 0; i < soundTable->count; ++i)\n\t\t{\n\t\t\tauto& entryPtr = soundTable->entries[i];\n\t\t\tif(entryPtr.type == 0)\n\t\t\t{\n\t\t\t\tentryPtr.loopAddress = entryPtr.currentOffset;\n\t\t\t\tentryPtr.loopEndAddress = 0;\n\t\t\t\tuint32be tmp = entryPtr.endOffset >> 1;\n\t\t\t\tif (tmp > endOffset)\n\t\t\t\t\tendOffset = tmp;\n\t\t\t\t/// ???\n\t\t\t}\n\t\t\telse if (entryPtr.type == 1)\n\t\t\t{\n\t\t\t\tuint32be tmp = entryPtr.endOffset >> 1;\n\t\t\t\tif (tmp > endOffset)\n\t\t\t\t\tendOffset = tmp;\n\t\t\t\t/// ???\n\t\t\t}\n\t\t\telse if (entryPtr.type == 2)\n\t\t\t{\n\t\t\t\tentryPtr.loopAddress = entryPtr.currentOffset;\n\t\t\t\tentryPtr.loopEndAddress = 0;\n\t\t\t\tuint32be tmp = entryPtr.endOffset << 1;\n\t\t\t\tif (tmp > endOffset)\n\t\t\t\t\tendOffset = tmp;\n\t\t\t}\n\t\t\telse if (entryPtr.type == 3)\n\t\t\t{\n\t\t\t\tuint32be tmp = entryPtr.endOffset << 1;\n\t\t\t\tif (tmp > endOffset)\n\t\t\t\t\tendOffset = tmp;\n\t\t\t}\n\t\t\telse if (entryPtr.type == 4)\n\t\t\t{\n\t\t\t\tentryPtr.loopAddress = entryPtr.currentOffset;\n\t\t\t\tentryPtr.loopEndAddress = 0;\n\n\t\t\t\tif (entryPtr.endOffset > endOffset)\n\t\t\t\t\tendOffset = entryPtr.endOffset;\n\t\t\t}\n\t\t\telse if (entryPtr.type == 5)\n\t\t\t{\n\t\t\t\tif (entryPtr.endOffset > endOffset)\n\t\t\t\t\tendOffset = entryPtr.endOffset;\n\t\t\t}\n\t\t}\n\n\n\t\tif (endOffsetPtr)\n\t\t\t*endOffsetPtr = endOffset;\n\n\t}\n\n\tSPSoundEntry* SPGetSoundEntry(SPSoundTable* soundTable, uint32 index)\n\t{\n\t\tcemuLog_log(LogType::SoundAPI, \"SPGetSoundEntry(0x{:x}, {})\", MEMPTR(soundTable).GetMPTR(), index);\n\t\tif (!soundTable)\n\t\t\treturn nullptr;\n\n\t\tif (soundTable->count <= index)\n\t\t\treturn nullptr;\n\n\t\treturn &soundTable->entries[index];\n\t}\n\n\tMEMPTR<void> s_fxAlloc = nullptr;\n\tMEMPTR<void> s_fxFree = nullptr;\n\n\tvoid _AXDefaultHook_alloc(PPCInterpreter_t* hCPU)\n\t{\n\t\tuint32 size = hCPU->gpr[3];\n\t\tMEMPTR<void> mem = coreinit::_weak_MEMAllocFromDefaultHeap(size);\n\t\tosLib_returnFromFunction(hCPU, mem.GetMPTR());\n\t}\n\n\tvoid _AXDefaultHook_free(PPCInterpreter_t* hCPU)\n\t{\n\t\tMEMPTR<void> mem{ hCPU->gpr[3] };\n\t\treturn coreinit::_weak_MEMFreeToDefaultHeap(mem.GetPtr());\n\t}\n\n\tvoid AXFXInitDefaultHooks()\n\t{\n\t\t// todo - this should only be applied when the library is loaded? MIXInit() does not affect this?\n\t\tif (!s_fxAlloc)\n\t\t{\n\t\t\ts_fxAlloc = RPLLoader_MakePPCCallable(_AXDefaultHook_alloc);\n\t\t\ts_fxFree = RPLLoader_MakePPCCallable(_AXDefaultHook_free);\n\t\t}\n\t}\n\n\tvoid AXFXSetHooks(void* allocFunc, void* freeFunc)\n\t{\n\t\ts_fxAlloc = allocFunc;\n\t\ts_fxFree = freeFunc;\n\t}\n\n\tvoid AXFXGetHooks(MEMPTR<void>* allocFuncOut, MEMPTR<void>* freeFuncOut)\n\t{\n\t\t*allocFuncOut = s_fxAlloc;\n\t\t*freeFuncOut = s_fxFree;\n\t}\n\n\tvoid* AXFXInternalAlloc(uint32 size, bool clearToZero)\n\t{\n\t\tif (s_fxAlloc)\n\t\t{\n\t\t\tMEMPTR<void> mem{ PPCCoreCallback(s_fxAlloc, size) };\n\t\t\tif (clearToZero)\n\t\t\t\tmemset(mem.GetPtr(), 0, size);\n\t\t\treturn mem.GetPtr();\n\t\t}\n\t\tvoid* mem = coreinit::_weak_MEMAllocFromDefaultHeapEx(size, 4);\n\t\tif (clearToZero)\n\t\t\tmemset(mem, 0, size);\n\t\treturn mem;\n\t}\n\n\tvoid AXFXInternalFree(void* mem)\n\t{\n\t\tif (s_fxFree)\n\t\t{\n\t\t\tPPCCoreCallback(s_fxFree, mem);\n\t\t\treturn;\n\t\t}\n\t\tcoreinit::_weak_MEMFreeToDefaultHeap(mem);\n\t}\n\n\t/* AUX callback */\n\n\tstruct AUXCBSAMPLEDATA\n\t{\n\t\tMEMPTR<sint32be> channelSamples[6];\n\t};\n\n\tbool gUnsupportedSoundEffectWarning = false;\n\tvoid PrintUnsupportedSoundEffectWarning()\n\t{\n\t\tif (gUnsupportedSoundEffectWarning)\n\t\t\treturn;\n\t\tcemuLog_log(LogType::Force, \"The currently running title is trying to utilize an unsupported audio effect\");\n\t\tcemuLog_log(LogType::Force, \"To emulate these correctly, place snd_user.rpl and snduser2.rpl from the original Wii U firmware in /cafeLibs/ folder\");\n\t\tgUnsupportedSoundEffectWarning = true;\n\t}\n\n\tvoid __UnimplementedFXCallback(AUXCBSAMPLEDATA* auxSamples, size_t sampleCount, bool clearCh0, bool clearCh1, bool clearCh2, bool clearCh3, bool clearCh4, bool clearCh5)\n\t{\n\t\tPrintUnsupportedSoundEffectWarning();\n\t\tbool clearChannel[6] = { clearCh0, clearCh1, clearCh2, clearCh3, clearCh4, clearCh5 };\n\n\t\tfor (sint32 channel = 0; channel < 6; channel++)\n\t\t{\n\t\t\tif(!clearChannel[channel])\n\t\t\t\tcontinue;\n\t\t\tsint32be* channelPtr = auxSamples->channelSamples[channel].GetPtr();\n\t\t\twhile (sampleCount)\n\t\t\t{\n\t\t\t\t*channelPtr = 0;\n\t\t\t\tchannelPtr++;\n\t\t\t\tsampleCount--;\n\t\t\t}\n\t\t}\n\n\t}\n\n\t/* AXFXReverbHi */\n\n\tstruct AXFXReverbHiData\n\t{\n\t\t// todo - implement\n\t\tuint32be placeholder;\n\t};\n\n\tvoid AXFXReverbHiInit(AXFXReverbHiData* param)\n\t{\n\t\tcemuLog_log(LogType::Force, \"AXFXReverbHiInit - stub\");\n\t}\n\n\tvoid AXFXReverbHiSettings(AXFXReverbHiData* param)\n\t{\n\t\tcemuLog_log(LogType::Force, \"AXFXReverbHiSettings - stub\");\n\t}\n\n\tvoid AXFXReverbHiShutdown(AXFXReverbHiData* param)\n\t{\n\t\tcemuLog_log(LogType::Force, \"AXFXReverbHiShutdown - stub\");\n\t}\n\n\tvoid AXFXReverbHiCallback(AUXCBSAMPLEDATA* auxSamples, AXFXReverbHiData* reverbHi)\n\t{\n\t\t// todo - implement me\n\t\t__UnimplementedFXCallback(auxSamples, 96, true, true, true, false, false, false);\n\t}\n\n\t/* AXFXMultiChReverb */\n\n\tstruct AXFXMultiChReverbData\n\t{\n\t\t// todo - implement\n\t\tuint32 placeholder;\n\t};\n\n\tvoid AXFXMultiChReverbInit(AXFXMultiChReverbData* param, int ukn2, int ukn3)\n\t{\n\t\tcemuLog_log(LogType::Force, \"AXFXMultiChReverbInit (Stubbed)\");\n\t}\n\n\tvoid AXFXMultiChReverbSettingsUpdate(AXFXMultiChReverbData* param)\n\t{\n\t\t// todo\n\t}\n\n\tvoid AXFXMultiChReverbShutdown(AXFXMultiChReverbData* param)\n\t{\n\t\t// todo\n\t}\n\n\tvoid AXFXMultiChReverbCallback(AUXCBSAMPLEDATA* auxSamples, AXFXMultiChReverbData* reverbHi, AXAUXCBCHANNELINFO* auxInfo)\n\t{\n\t\t// todo - implement me\n\t\t__UnimplementedFXCallback(auxSamples, auxInfo->numSamples, true, true, true, true, true, true);\n\t}\n\n\t/* AXFXReverbStd */\n\n\tstruct AXFXReverbStdData\n\t{\n\t\tuint32be placeholder;\n\t};\n\n\tuint32 AXFXReverbStdExpGetMemSize(AXFXReverbStdData* reverbParam)\n\t{\n\t\treturn 0xC; // placeholder size\n\t}\n\n\tbool AXFXReverbStdExpInit(AXFXReverbStdData* reverbParam)\n\t{\n\t\treturn true;\n\t}\n\n\tvoid AXFXReverbStdExpShutdown(AXFXReverbStdData* reverbParam)\n\t{\n\n\t}\n\n\tvoid AXFXReverbStdExpCallback(AUXCBSAMPLEDATA* auxSamples, AXFXReverbStdData* reverbData)\n\t{\n\t\t// todo - implement me\n\t\t__UnimplementedFXCallback(auxSamples, 96, true, true, true, false, false, false);\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"snd_user\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\t/* snd_user */\n\t\t\tcafeExportRegister(\"snd_user\", MIXInit, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXSetSoundMode, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXGetSoundMode, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXInitChannel, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXAssignChannel, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXDRCInitChannel, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXSetInput, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXUpdateSettings, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXSetDeviceSoundMode, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXSetDeviceFader, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXSetDevicePan, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXInitDeviceControl, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", MIXInitInputControl, LogType::SoundAPI);\n\n\t\t\tcafeExportRegister(\"snd_user\", SPInitSoundTable, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", SPGetSoundEntry, LogType::SoundAPI);\n\t\t\t//cafeExportRegister(\"snd_user\", SPPrepareSound);\n\t\t\tcafeExportRegister(\"snd_user\", AXFXSetHooks, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", AXFXGetHooks, LogType::SoundAPI);\n\n\t\t\tcafeExportRegister(\"snd_user\", AXFXReverbHiInit, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", AXFXReverbHiSettings, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", AXFXReverbHiShutdown, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", AXFXReverbHiCallback, LogType::SoundAPI);\n\n\t\t\tcafeExportRegister(\"snd_user\", AXFXMultiChReverbInit, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", AXFXMultiChReverbSettingsUpdate, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", AXFXMultiChReverbShutdown, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snd_user\", AXFXMultiChReverbCallback, LogType::SoundAPI);\n\t\t};\n\n\t}s_COSsnduser1Module;\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"snduser2\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\t/* snduser2 */\n\t\t\tcafeExportRegister(\"snduser2\", MIXInit, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXSetSoundMode, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXGetSoundMode, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXInitChannel, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXAssignChannel, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXDRCInitChannel, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXSetInput, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXUpdateSettings, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXSetDeviceSoundMode, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXSetDeviceFader, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXSetDevicePan, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXInitDeviceControl, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", MIXInitInputControl, LogType::SoundAPI);\n\n\t\t\tcafeExportRegister(\"snduser2\", AXFXSetHooks, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXGetHooks, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXReverbStdExpGetMemSize, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXReverbStdExpInit, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXReverbStdExpShutdown, LogType::Placeholder);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXReverbStdExpCallback, LogType::Placeholder);\n\n\t\t\tcafeExportRegister(\"snduser2\", AXFXReverbHiInit, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXReverbHiSettings, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXReverbHiShutdown, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXReverbHiCallback, LogType::SoundAPI);\n\n\t\t\tcafeExportRegister(\"snduser2\", AXFXMultiChReverbInit, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXMultiChReverbSettingsUpdate, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXMultiChReverbShutdown, LogType::SoundAPI);\n\t\t\tcafeExportRegister(\"snduser2\", AXFXMultiChReverbCallback, LogType::SoundAPI);\n\t\t};\n\n\t}s_COSsnduser2Module;\n\n\tCOSModule* GetModuleSndUser1()\n\t{\n\t\treturn &s_COSsnduser1Module;\n\t}\n\n\tCOSModule* GetModuleSndUser2()\n\t{\n\t\treturn &s_COSsnduser2Module;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/snd_user/snd_user.h",
    "content": "#pragma once\n\n#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace snd_user\n{\n\tstruct MixControl;\n\n\tvoid MIXInit();\n\tvoid MIXInitInputControl(snd_core::AXVPB* voice, uint16 input, uint32 mode);\n\tvoid MIXInitDeviceControl(snd_core::AXVPB* voice, uint32 device_type, uint32 index, MixControl* control, uint32 mode);\n\tvoid MIXSetDeviceSoundMode(uint32 device, uint32 mode);\n\tvoid MIXUpdateSettings();\n\tvoid MIXSetInput(snd_core::AXVPB* voice, uint16 input);\n\tvoid MIXDRCInitChannel(snd_core::AXVPB* voice, uint16 mode, uint16 vol1, uint16 vol2, uint16 vol3);\n\tvoid MIXAssignChannel(snd_core::AXVPB* voice);\n\tvoid MIXInitChannel(snd_core::AXVPB* voice, uint16 mode, uint16 input, uint16 aux1, uint16 aux2, uint16 aux3, uint16 pan, uint16 span, uint16 fader);\n\tuint32 MIXGetSoundMode();\n\tvoid MIXSetSoundMode(uint32 sound_mode);\n\n\tCOSModule* GetModuleSndUser1();\n\tCOSModule* GetModuleSndUser2();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/swkbd/swkbd.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Latte/ISA/RegDefines.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/HW/Latte/Core/LatteDraw.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n\n#include <imgui.h>\n#include \"imgui/imgui_extension.h\"\n#include \"util/helpers/helpers.h\"\n#include \"resource/IconsFontAwesome5.h\"\n\n#define SWKBD_FORM_STRING_MAX_LENGTH\t(4096) // counted in 16-bit characters\n\n#define SWKBD_STATE_BLANK\t\t\t\t(0)\t// not visible\n#define SWKBD_STATE_APPEARING\t\t\t(1)\t// fade-in ?\n#define SWKBD_STATE_DISPLAYED\t\t\t(2)\t// visible\n#define SWKBD_STATE_DISAPPEARING\t\t(3)\t// fade-out ?\n\ntypedef struct  \n{\n\tuint32 ukn00; // constructor?\n\tuint32 ukn04; // destructor?\n\tuint32 ukn08; // ?\n\tMEMPTR<void> changeString; // some function address\n}SwkbdIEventReceiverVTable_t;\n\ntypedef struct  \n{\n\tMEMPTR<SwkbdIEventReceiverVTable_t> vTable;\n\t// todo - more elements? (currently separated from this struct)\n}SwkbdIEventReceiver_t;\n\nstruct swkbdReceiverArg_t\n{\n\tMEMPTR<SwkbdIEventReceiver_t> IEventReceiver;\n\tMEMPTR<sint16be> stringBuf;\n\tsint32be stringBufSize;\n\tsint32be fixedCharLimit;\n\tsint32be cursorPos;\n\tsint32be selectFrom;\n};\n\ntypedef struct  \n{\n\tuint32 ukn000;\n\tuint32 controllerType;\n\tuint32 keyboardMode; // guessed\n\tuint32 ukn00C;\n\tuint32 ukn010;\n\tuint32 ukn014;\n\tuint32 ukn018;\n\tuint32 ukn01C; // ok string?\n\tuint32 ukn020[4];\n\tuint32 ukn030[4];\n\tuint32 ukn040[4];\n\tuint32 ukn050[4];\n\tuint32 ukn060[4];\n\tuint32 ukn070[4];\n\tuint32 ukn080[4];\n\tuint32 ukn090[4];\n\tuint32 ukn0A0;\n\tuint32 ukn0A4;\n\t//uint32 ukn0A8;\n\t//MEMPTR<SwkbdIEventReceiver_t> IEventReceiver;\n\tswkbdReceiverArg_t receiverArg;\n}SwkbdKeyboardArg_t;\n\ntypedef struct  \n{\n\t// this structure resides in PPC addressable memory space\n\twchar_t formStringBuffer[SWKBD_FORM_STRING_MAX_LENGTH];\n\tsint32 formStringLength;\n\t// big endian version of the string buffer (converted whenever GetInputFormString is called)\n\tuint16 formStringBufferBE[SWKBD_FORM_STRING_MAX_LENGTH];\n\tbool isActive; // set when SwkbdAppearInputForm() is called\n\t//bool isDisplayed; // set when keyboard is rendering\n\tbool decideButtonWasPressed; // set to false when keyboard appears, and set to true when enter is pressed. Remains on true after the keyboard is disappeared (todo: Investigate how this really works)\n\t// keyboard only mode (no input form)\n\tbool keyboardOnlyMode;\n\tSwkbdKeyboardArg_t keyboardArg;\n\t// input form appear args\n\tsint32 maxTextLength;\n\t// imgui keyboard drawing stuff\n\tbool shiftActivated;\n\tbool returnState;\n\tbool cancelState;\n\t\n}swkbdInternalState_t;\n\nswkbdInternalState_t* swkbdInternalState = NULL;\n\nvoid swkbdExport_SwkbdCreate(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"swkbd.SwkbdCreate(0x{:08x},0x{:08x},0x{:08x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\tif( swkbdInternalState == NULL )\n\t{\n\t\tMPTR swkbdInternalStateMPTR = coreinit_allocFromSysArea(sizeof(swkbdInternalState_t), 4);\n\t\tswkbdInternalState = (swkbdInternalState_t*)memory_getPointerFromVirtualOffset(swkbdInternalStateMPTR);\n\t\tmemset(swkbdInternalState, 0x00, sizeof(swkbdInternalState_t));\n\t}\n\tosLib_returnFromFunction(hCPU, 0); // should return true?\n}\n\nvoid swkbdExport_SwkbdGetStateKeyboard(PPCInterpreter_t* hCPU)\n{\n\tuint32 r = SWKBD_STATE_BLANK;\n\tif( swkbdInternalState->isActive )\n\t\tr = SWKBD_STATE_DISPLAYED;\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid swkbdExport_SwkbdGetStateInputForm(PPCInterpreter_t* hCPU)\n{\n\t//debug_printf(\"SwkbdGetStateInputForm__3RplFv LR: %08x\\n\", hCPU->sprNew.LR);\n\tuint32 r = SWKBD_STATE_BLANK;\n\tif( swkbdInternalState->isActive )\n\t\tr = SWKBD_STATE_DISPLAYED;\n\tosLib_returnFromFunction(hCPU, r);\n}\n\n//ReceiverArg:\n//+0x00\tIEventReceiver*\n//+0x04\tstringBuf\n//+ 0x08\tstringBufSize\n//+ 0x0C\tfixedCharNumLimit(-1)\n//+ 0x10\tcursorPos\n//+ 0x14\tselectFrom(-1)\n//\n//IEventReceiver:\n//+0x00 IEventReceiver_vTable*\n//+0x04 ?\n//+0x08 ?\n//+0x0C ?\n//\n//IEventReceiver_vTable :\n//\t+0x00 ?\n//\t+0x04 ?\n//\t+0x08 ?\n//\t+0x0C\tfunctionPtr onDirtyString(const DirtyInfo& info) = 0; ->DirtyInfo is just two DWORDs.From and to ?\n//\t?\n\n\ntypedef struct  \n{\n\tMPTR vTable; // guessed\n}swkdbIEventReceiver_t;\n\ntypedef struct  \n{\n\tuint32 ukn00;\n\tuint32 ukn04;\n\tuint32 ukn08;\n\tMPTR   onDirtyString;\n}swkdbIEventReceiverVTable_t;\n\nvoid swkbdExport_SwkbdSetReceiver(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"SwkbdSetReceiver(0x%08x)\\n\", hCPU->gpr[3]);\n\tswkbdReceiverArg_t* receiverArg = (swkbdReceiverArg_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\n\tif(swkbdInternalState == nullptr)\n\t{\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t\treturn;\n\t}\n\n\tswkbdInternalState->keyboardArg.receiverArg = *receiverArg;\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\ntypedef struct  \n{\n\t/* +0x00 */ uint32 ukn00;\n\t/* +0x04 */ uint32 ukn04;\n\t/* +0x08 */ uint32 ukn08;\n\t/* +0x0C */ uint32 ukn0C;\n\t/* +0x10 */ uint32 ukn10;\n\t/* +0x14 */ uint32 ukn14;\n\t/* +0x18 */ uint32 ukn18;\n\t/* +0x1C */ uint32 ukn1C; // pointer to OK string\n\t/* +0x20 */ uint32 ukn20[4];\n\t/* +0x30 */ uint32 ukn30[4];\n\t/* +0x40 */ uint32 ukn40[4];\n\t/* +0x50 */ uint32 ukn50[4];\n\t/* +0x60 */ uint32 ukn60[4];\n\t/* +0x70 */ uint32 ukn70[4];\n\t/* +0x80 */ uint32 ukn80[4];\n\t/* +0x90 */ uint32 ukn90[4];\n\t/* +0xA0 */ uint32 uknA0[4];\n\t/* +0xB0 */ uint32 uknB0[4];\n\t/* +0xC0 */ uint32 inputFormType;\n\t/* +0xC4 */ uint32be cursorIndex;\n\t/* +0xC8 */ MEMPTR<uint16be> initialText;\n\t/* +0xCC */ MEMPTR<uint16be> infoText;\n\t/* +0xD0 */ uint32be maxTextLength;\n\n}swkbdAppearArg_t;\n\nstatic_assert(offsetof(swkbdAppearArg_t, cursorIndex) == 0xC4, \"appearArg.cursorIndex has invalid offset\");\n\nvoid swkbdExport_SwkbdAppearInputForm(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(appearArg, swkbdAppearArg_t, 0);\n\tcemuLog_logDebug(LogType::Force, \"SwkbdAppearInputForm__3RplFRCQ3_2nn5swkbd9AppearArg\");\n\tswkbdInternalState->formStringLength = 0;\n\tswkbdInternalState->isActive = true;\n\tswkbdInternalState->decideButtonWasPressed = false;\n\tswkbdInternalState->keyboardOnlyMode = false;\n\n\t// setup max text length\n\tswkbdInternalState->maxTextLength = (sint32)(uint32)appearArg->maxTextLength;\n\tif (swkbdInternalState->maxTextLength <= 0)\n\t\tswkbdInternalState->maxTextLength = SWKBD_FORM_STRING_MAX_LENGTH - 1;\n\telse\n\t\tswkbdInternalState->maxTextLength = std::min(swkbdInternalState->maxTextLength, SWKBD_FORM_STRING_MAX_LENGTH - 1);\n\t// setup initial string\n\tuint16be* initialString = appearArg->initialText.GetPtr();\n\tif (initialString)\n\t{\n\t\tswkbdInternalState->formStringLength = 0;\n\t\tfor (sint32 i = 0; i < swkbdInternalState->maxTextLength; i++)\n\t\t{\n\t\t\twchar_t c = (uint16)initialString[i];\n\t\t\tif( c == '\\0' )\n\t\t\t\tbreak;\n\t\t\tswkbdInternalState->formStringBuffer[i] = c;\n\t\t\tswkbdInternalState->formStringLength++;\n\t\t}\n\t}\n\telse\n\t{\n\t\tswkbdInternalState->formStringBuffer[0] = '\\0';\n\t\tswkbdInternalState->formStringLength = 0;\n\t}\n\tosLib_returnFromFunction(hCPU, 1);\n}\n\nvoid swkbdExport_SwkbdAppearKeyboard(PPCInterpreter_t* hCPU)\n{\n\t// todo: Figure out what the difference between AppearInputForm and AppearKeyboard is?\n\tcemuLog_logDebug(LogType::Force, \"SwkbdAppearKeyboard__3RplFRCQ3_2nn5swkbd11KeyboardArg\");\n\tSwkbdKeyboardArg_t* keyboardArg = (SwkbdKeyboardArg_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\n\tuint32 argPtr = hCPU->gpr[3];\n\tfor(sint32 i=0; i<0x180; i += 4)\n\t{\n\t\tdebug_printf(\"+0x%03x: 0x%08x\\n\", i, memory_readU32(argPtr+i));\n\t}\n\n\tswkbdInternalState->formStringLength = 0;\n\tswkbdInternalState->isActive = true;\n\tswkbdInternalState->keyboardOnlyMode = true;\n\tswkbdInternalState->decideButtonWasPressed = false;\n\tswkbdInternalState->formStringBuffer[0] = '\\0';\n\tswkbdInternalState->formStringLength = 0;\n\tswkbdInternalState->keyboardArg = *keyboardArg;\n\tosLib_returnFromFunction(hCPU, 1);\n}\n\nvoid swkbdExport_SwkbdDisappearInputForm(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"SwkbdDisappearInputForm__3RplFv LR: %08x\\n\", hCPU->spr.LR);\n\tswkbdInternalState->isActive = false;\n\tosLib_returnFromFunction(hCPU, 1);\n}\n\nvoid swkbdExport_SwkbdDisappearKeyboard(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"SwkbdDisappearKeyboard__3RplFv LR: %08x\\n\", hCPU->spr.LR);\n\tswkbdInternalState->isActive = false;\n\tosLib_returnFromFunction(hCPU, 1);\n}\n\nvoid swkbdExport_SwkbdGetInputFormString(PPCInterpreter_t* hCPU)\n{\n\tfor(sint32 i=0; i<swkbdInternalState->formStringLength; i++)\n\t{\n\t\tswkbdInternalState->formStringBufferBE[i] = _swapEndianU16(swkbdInternalState->formStringBuffer[i]);\n\t}\n\tswkbdInternalState->formStringBufferBE[swkbdInternalState->formStringLength] = '\\0';\n\tosLib_returnFromFunction(hCPU, memory_getVirtualOffsetFromPointer(swkbdInternalState->formStringBufferBE));\n}\n\nvoid swkbdExport_SwkbdIsDecideOkButton(PPCInterpreter_t* hCPU)\n{\n\tif (swkbdInternalState->decideButtonWasPressed)\n\t\tosLib_returnFromFunction(hCPU, 1);\n\telse\n\t\tosLib_returnFromFunction(hCPU, 0);\n}\n\ntypedef struct  \n{\n\tuint32be ukn00;\n\tuint32be ukn04;\n\tuint32be ukn08;\n\tuint32be ukn0C;\n\tuint32be ukn10;\n\tuint32be ukn14;\n\tuint8 ukn18;\n\t// there might be padding here?\n}SwkbdDrawStringInfo_t;\n\nstatic_assert(sizeof(SwkbdDrawStringInfo_t) != 0x19, \"SwkbdDrawStringInfo_t has invalid size\");\n\nvoid swkbdExport_SwkbdGetDrawStringInfo(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"SwkbdGetDrawStringInfo(0x{:08x})\", hCPU->gpr[3]);\n\tppcDefineParamStructPtr(drawStringInfo, SwkbdDrawStringInfo_t, 0);\n\n\tdrawStringInfo->ukn00 = -1;\n\tdrawStringInfo->ukn04 = -1;\n\tdrawStringInfo->ukn08 = -1;\n\tdrawStringInfo->ukn0C = -1;\n\tdrawStringInfo->ukn10 = -1;\n\tdrawStringInfo->ukn14 = -1;\n\tdrawStringInfo->ukn18 = 0;\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid swkbdExport_SwkbdInitLearnDic(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"SwkbdInitLearnDic(0x{:08x})\", hCPU->gpr[3]);\n\t// todo\n\n\t// this has to fail (at least once?) or MH3U will not boot\n\tosLib_returnFromFunction(hCPU, 1);\n}\n\nbool isNeedCalc0 = true;\nbool isNeedCalc1 = true;\n\nvoid swkbdExport_SwkbdIsNeedCalcSubThreadFont(PPCInterpreter_t* hCPU)\n{\n\t// SwkbdIsNeedCalcSubThreadFont__3RplFv\n\tbool r = false;\n\tosLib_returnFromFunction(hCPU, r?1:0);\n}\n\nvoid swkbdExport_SwkbdIsNeedCalcSubThreadPredict(PPCInterpreter_t* hCPU)\n{\n\t// SwkbdIsNeedCalcSubThreadPredict__3RplFv\n\tbool r = false;\n\n\tosLib_returnFromFunction(hCPU, r?1:0);\n}\n\nvoid swkbd_keyInput(uint32 keyCode);\nvoid swkbd_render(bool mainWindow)\n{\n\t// only render if active\n\tif( swkbdInternalState == NULL || swkbdInternalState->isActive == false)\n\t\treturn;\n\t\n\tauto& io = ImGui::GetIO();\n\tconst auto font = ImGui_GetFont(48.0f);\n\tconst auto textFont = ImGui_GetFont(24.0f);\n\tif (!font || !textFont)\n\t\treturn;\n\n\tconst auto kPopupFlags = ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings;\n\n\tImGui::PushStyleColor(ImGuiCol_WindowBg, 0);\n\n\tImGui::SetNextWindowPos({ 0,0 }, ImGuiCond_Always);\n\tImGui::SetNextWindowSize(io.DisplaySize, ImGuiCond_Always);\n\tImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);\n\tImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0,0 });\n\tImGui::SetNextWindowBgAlpha(0.8f);\n\tImGui::Begin(\"Background overlay\", nullptr, kPopupFlags | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoBringToFrontOnFocus);\n\tImGui::End();\n\tImGui::PopStyleVar(2);\n\n\tImVec2 position = { io.DisplaySize.x / 2.0f, io.DisplaySize.y / 3.0f };\n\tImVec2 pivot = { 0.5f, 0.5f };\n\n\tconst auto button_len = font->GetCharAdvance('W');\n\tconst float len = button_len * std::max(4, std::max(swkbdInternalState->maxTextLength, (sint32)swkbdInternalState->keyboardArg.receiverArg.stringBufSize));\n\n\tImVec2 box_size = { std::min(io.DisplaySize.x * 0.9f, len + 90), 0 };\n\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\tImGui::SetNextWindowSize(box_size, ImGuiCond_Always);\n\tImGui::SetNextWindowBgAlpha(0.9f);\n\tImGui::PushFont(font);\n\tif (ImGui::Begin(\"Keyboard Input\", nullptr, kPopupFlags))\n\t{\n\t\tImGui::Text(\"%s\", _utf8WrapperPtr(ICON_FA_KEYBOARD));\n\t\tImGui::SameLine(70);\n\t\tauto text = boost::nowide::narrow(fmt::format(L\"{}\", swkbdInternalState->formStringBuffer));\n\n\t\tstatic std::chrono::steady_clock::time_point s_last_tick = tick_cached();\n\t\tstatic bool s_blink_state = false;\n\t\tconst auto now = tick_cached();\n\n\t\tif (std::chrono::duration_cast<std::chrono::milliseconds>(now - s_last_tick).count() >= 500)\n\t\t{\n\t\t\ts_blink_state = !s_blink_state;\n\t\t\ts_last_tick = now;\n\t\t}\n\n\t\tif (s_blink_state)\n\t\t\ttext += \"|\";\n\n\t\tImGui::PushTextWrapPos();\n\t\tImGui::TextUnformatted(text.c_str(), text.c_str() + text.size());\n\t\tImGui::PopTextWrapPos();\n\n\t\tposition.y += ImGui::GetWindowSize().y + 100.0f;\n\t}\n\tImGui::End();\n\tImGui::PopFont();\n\n\tImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);\n\t//ImGui::SetNextWindowSize({ io.DisplaySize.x * 0.9f , 0.0f}, ImGuiCond_Always);\n\tImGui::SetNextWindowBgAlpha(0.9f);\n\tImGui::PushFont(textFont);\n\n\tif (ImGui::Begin(fmt::format(\"Software keyboard##SoftwareKeyboard{}\",mainWindow).c_str(), nullptr, kPopupFlags))\n\t{\n\t\tif(swkbdInternalState->shiftActivated)\n\t\t{\n\t\t\tconst char* keys[] =\n\t\t\t{\n\t\t\t\t\"#\", \"[\", \"]\", \"$\", \"%\", \"^\", \"&\", \"*\", \"(\", \")\", \"_\", _utf8WrapperPtr(ICON_FA_ARROW_CIRCLE_LEFT), \"\\n\",\n\t\t\t\t\"Q\", \"W\", \"E\", \"R\", \"T\", \"Y\", \"U\", \"I\", \"O\", \"P\", \"@\", \"\\n\",\n\t\t\t\t\"A\", \"S\", \"D\", \"F\", \"G\", \"H\", \"J\", \"K\", \"L\", \";\", \"\\\"\", \"\\n\",\n\t\t\t\t\"Z\", \"X\", \"C\", \"V\", \"B\", \"N\", \"M\", \"<\", \">\", \"+\", \"=\", \"\\n\",\n\t\t\t\t_utf8WrapperPtr(ICON_FA_ARROW_UP), \" \", _utf8WrapperPtr(ICON_FA_CHECK)\n\t\t\t};\n\t\t\tfor (auto key : keys)\n\t\t\t{\n\t\t\t\tif (*key != '\\n')\n\t\t\t\t{\n\t\t\t\t\tif (ImGui::Button(key, { *key == ' ' ? 537 : (button_len + 5), 0}))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (strcmp(key, _utf8WrapperPtr(ICON_FA_ARROW_CIRCLE_LEFT)) == 0)\n\t\t\t\t\t\t\tswkbd_keyInput(8);\n\t\t\t\t\t\telse if (strcmp(key, _utf8WrapperPtr(ICON_FA_ARROW_UP)) == 0)\n\t\t\t\t\t\t\tswkbdInternalState->shiftActivated = !swkbdInternalState->shiftActivated;\n\t\t\t\t\t\telse if (strcmp(key, _utf8WrapperPtr(ICON_FA_CHECK)) == 0)\n\t\t\t\t\t\t\tswkbd_keyInput(13);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tswkbd_keyInput(*key);\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui::SameLine();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tImGui::NewLine();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconst char* keys[] =\n\t\t\t{\n\t\t\t\t\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\", \"-\", _utf8WrapperPtr(ICON_FA_ARROW_CIRCLE_LEFT), \"\\n\",\n\t\t\t\t\"q\", \"w\", \"e\", \"r\", \"t\", \"y\", \"u\", \"i\", \"o\", \"p\", \"/\", \"\\n\",\n\t\t\t\t\"a\", \"s\", \"d\", \"f\", \"g\", \"h\", \"j\", \"k\", \"l\", \":\", \"'\", \"\\n\",\n\t\t\t\t\"z\", \"x\", \"c\", \"v\", \"b\", \"n\", \"m\", \",\", \".\", \"?\", \"!\", \"\\n\",\n\t\t\t\t_utf8WrapperPtr(ICON_FA_ARROW_UP), \" \", _utf8WrapperPtr(ICON_FA_CHECK)\n\t\t\t};\n\t\t\tfor (auto key : keys)\n\t\t\t{\n\t\t\t\tif (*key != '\\n')\n\t\t\t\t{\n\t\t\t\t\tif (ImGui::Button(key, { *key == ' ' ? 537 : (button_len + 5), 0 }))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (strcmp(key, _utf8WrapperPtr(ICON_FA_ARROW_CIRCLE_LEFT)) == 0)\n\t\t\t\t\t\t\tswkbd_keyInput(8);\n\t\t\t\t\t\telse if (strcmp(key, _utf8WrapperPtr(ICON_FA_ARROW_UP)) == 0)\n\t\t\t\t\t\t\tswkbdInternalState->shiftActivated = !swkbdInternalState->shiftActivated;\n\t\t\t\t\t\telse if (strcmp(key, _utf8WrapperPtr(ICON_FA_CHECK)) == 0)\n\t\t\t\t\t\t\tswkbd_keyInput(13);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tswkbd_keyInput(*key);\n\t\t\t\t\t}\n\n\t\t\t\t\tImGui::SameLine();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tImGui::NewLine();\n\t\t\t}\n\t\t}\n\t\tImGui::NewLine();\n\t}\n\tImGui::End();\n\n\tif (io.NavInputs[ImGuiNavInput_Cancel] > 0)\n\t{\n\t\tif(!swkbdInternalState->cancelState)\n\t\t\tswkbd_keyInput(8); // backspace\n\t\tswkbdInternalState->cancelState = true;\n\t}\n\telse\n\t\tswkbdInternalState->cancelState = false;\n\n\tif (io.NavInputs[ImGuiNavInput_Input] > 0)\n\t{\n\t\tif (!swkbdInternalState->returnState)\n\t\t\tswkbd_keyInput(13); // return\n\t\tswkbdInternalState->returnState = true;\n\t}\n\telse\n\t\tswkbdInternalState->returnState = false;\n\n\tImGui::PopFont();\n\tImGui::PopStyleColor();\n}\n\nbool swkbd_hasKeyboardInputHook()\n{\n\treturn swkbdInternalState != NULL && swkbdInternalState->isActive;\n}\n\nvoid swkbd_finishInput()\n{\n\tswkbdInternalState->decideButtonWasPressed = true; // currently we always accept the input\n}\n\ntypedef struct  \n{\n\tuint32be beginIndex;\n\tuint32be endIndex;\n}changeStringParam_t;\n\nSysAllocator<changeStringParam_t> _changeStringParam;\n\nvoid swkbd_inputStringChanged()\n{\n\tif( true )//swkbdInternalState->keyboardOnlyMode )\n\t{\n\t\t// write changed string to application's string buffer\n\t\tuint32 stringBufferSize = swkbdInternalState->keyboardArg.receiverArg.stringBufSize; // in 2-byte words\n\t\tif( stringBufferSize > 1 )\n\t\t{\n\t\t\tstringBufferSize--; // don't count the null-termination character\n\t\t\tconst auto stringBufferBE = swkbdInternalState->keyboardArg.receiverArg.stringBuf.GetPtr();\n\t\t\tsint32 copyLength = std::min((sint32)stringBufferSize, swkbdInternalState->formStringLength);\n\t\t\tfor(sint32 i=0; i<copyLength; i++)\n\t\t\t{\n\t\t\t\tstringBufferBE[i] = swkbdInternalState->formStringBuffer[i];\n\t\t\t}\n\t\t\tstringBufferBE[copyLength] = '\\0';\n\n\t\t\t//swkbdInternalState->keyboardArg.cursorPos = copyLength;\n\t\t}\n\t\t// IEventReceiver callback\n\t\tif (swkbdInternalState->keyboardArg.receiverArg.IEventReceiver)\n\t\t{\n\t\t\tSwkbdIEventReceiver_t* eventReceiver = swkbdInternalState->keyboardArg.receiverArg.IEventReceiver.GetPtr();\n\t\t\tMPTR cbChangeString = eventReceiver->vTable->changeString.GetMPTR();\n\t\t\tif (cbChangeString)\n\t\t\t{\n\t\t\t\tchangeStringParam_t* changeStringParam = _changeStringParam.GetPtr();\n\t\t\t\tchangeStringParam->beginIndex = 0;\n\t\t\t\tchangeStringParam->endIndex = 0;\n\t\t\t\tcoreinitAsyncCallback_add(cbChangeString, 2, memory_getVirtualOffsetFromPointer(eventReceiver), _changeStringParam.GetMPTR());\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid swkbd_keyInput(uint32 keyCode)\n{\n\tif (keyCode == 8 || keyCode == 127) // backspace || backwards delete\n\t{\n\t\tif (swkbdInternalState->formStringLength > 0)\n\t\t\tswkbdInternalState->formStringLength--;\n\t\tswkbdInternalState->formStringBuffer[swkbdInternalState->formStringLength] = '\\0';\n\t\tswkbd_inputStringChanged();\n\t\treturn;\n\t}\n\telse if (keyCode == 13) // return\n\t{\n\t\tswkbd_finishInput();\n\t\treturn;\n\t}\n\t// check if allowed character\n\tif ((keyCode >= 'a' && keyCode <= 'z') ||\n\t\t(keyCode >= 'A' && keyCode <= 'Z'))\n\t{\n\t\t// allowed\n\t}\n\telse if ((keyCode >= '0' && keyCode <= '9'))\n\t{\n\t\t// allowed\n\t}\n\telse if (keyCode == ' ' || keyCode == '.' || keyCode == '/' || keyCode == '?' || keyCode == '=')\n\t{\n\t\t// allowed\n\t}\n\telse if (keyCode < 32)\n\t{\n\t\t// control key\n\t\treturn;\n\t}\n\telse\n\t\t;// return;\n\t// get max length\n\tsint32 maxLength = swkbdInternalState->maxTextLength;\n\tif (swkbdInternalState->keyboardOnlyMode)\n\t{\n\t\tuint32 stringBufferSize = swkbdInternalState->keyboardArg.receiverArg.stringBufSize;\n\t\tif (stringBufferSize > 1)\n\t\t{\n\t\t\tmaxLength = stringBufferSize - 1; // don't count the null-termination character\n\t\t}\n\t\telse\n\t\t\tmaxLength = 0;\n\t}\n\t// append character\n\tif (swkbdInternalState->formStringLength < maxLength)\n\t{\n\t\tswkbdInternalState->formStringBuffer[swkbdInternalState->formStringLength] = keyCode;\n\t\tswkbdInternalState->formStringLength++;\n\t\tswkbdInternalState->formStringBuffer[swkbdInternalState->formStringLength] = '\\0';\n\t\tswkbd_inputStringChanged();\n\t}\n}\n\nnamespace swkbd\n{\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"swkbd\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdCreate__3RplFPUcQ3_2nn5swkbd10RegionTypeUiP8FSClient\", swkbdExport_SwkbdCreate);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdGetStateKeyboard__3RplFv\", swkbdExport_SwkbdGetStateKeyboard);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdGetStateInputForm__3RplFv\", swkbdExport_SwkbdGetStateInputForm);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdSetReceiver__3RplFRCQ3_2nn5swkbd11ReceiverArg\", swkbdExport_SwkbdSetReceiver);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdAppearInputForm__3RplFRCQ3_2nn5swkbd9AppearArg\", swkbdExport_SwkbdAppearInputForm);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdDisappearInputForm__3RplFv\", swkbdExport_SwkbdDisappearInputForm);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdDisappearKeyboard__3RplFv\", swkbdExport_SwkbdDisappearKeyboard);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdAppearKeyboard__3RplFRCQ3_2nn5swkbd11KeyboardArg\", swkbdExport_SwkbdAppearKeyboard);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdGetInputFormString__3RplFv\", swkbdExport_SwkbdGetInputFormString);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdIsDecideOkButton__3RplFPb\", swkbdExport_SwkbdIsDecideOkButton);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdInitLearnDic__3RplFPv\", swkbdExport_SwkbdInitLearnDic);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdGetDrawStringInfo__3RplFPQ3_2nn5swkbd14DrawStringInfo\", swkbdExport_SwkbdGetDrawStringInfo);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdIsNeedCalcSubThreadFont__3RplFv\", swkbdExport_SwkbdIsNeedCalcSubThreadFont);\n\t\t\tosLib_addFunction(\"swkbd\", \"SwkbdIsNeedCalcSubThreadPredict__3RplFv\", swkbdExport_SwkbdIsNeedCalcSubThreadPredict);\n\t\t};\n\n\t\tvoid rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override\n\t\t{\n\t\t\tif (reason == coreinit::RplEntryReason::Loaded)\n\t\t\t{\n\t\t\t\t// todo\n\t\t\t}\n\t\t\telse if (reason == coreinit::RplEntryReason::Unloaded)\n\t\t\t{\n\t\t\t\t// todo\n\t\t\t}\n\t\t}\n\t}s_COSswkbdModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSswkbdModule;\n\t}\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/swkbd/swkbd.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nvoid swkbd_render(bool mainWindow);\nbool swkbd_hasKeyboardInputHook();\nvoid swkbd_keyInput(uint32 keyCode);\n\nnamespace swkbd\n{\n\tCOSModule* GetModule();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/sysapp/sysapp.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"sysapp.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_FG.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Misc.h\"\n\ntypedef struct  \n{\n\tMEMPTR<char> argStr;\n\tuint32be size;\n}sysStandardArguments_t;\n\ntypedef struct\n{\n\t// guessed\n\t/* +0x00 */ MEMPTR<uint8>\tsysAnchor;\n\t/* +0x04 */ uint32be\t\tsysAnchorSize;\n\t/* +0x08 */ MEMPTR<uint8>\tsysResult;\n\t/* +0x0C */ uint32be\t\tsysResultSize;\n}sysDeserializeStandardArguments_t;\n\ntypedef struct\n{\n\t// used for setting arguments, maybe wrong?\n\t/* +0x00 */ sysStandardArguments_t standardArguments;\n\t/* +0x08 */ uint32be mode;\n\t/* +0x0C */ uint32be slot_id;\n\t/* +0x10 */ MEMPTR<uint8> mii;\n}sysMiiStudioArguments_t;\n\ntypedef struct  \n{\n\t// used for getting arguments\n\t/* +0x00 */ sysStandardArguments_t standardArguments; // ?\n\t/* +0x08 */ uint32 ukn08;\n\t/* +0x0C */ uint32 ukn0C;\n\t/* +0x10 */ uint32be mode;\n\t/* +0x14 */ uint32be slot_id;\n\t/* +0x18 */ MEMPTR<uint8> mii;\n\t/* +0x1C */ uint32be miiSize;\n}sysMiiStudioArguments2_t;\n\ntypedef struct  \n{\n\t/* +0x00 */ sysDeserializeStandardArguments_t standardArguments;\n\t/* +0x10 */ uint32be jumpTo; // see below for list of available values\n\t/* +0x14 */ uint32be needsReturn;\n\t/* +0x18 */ uint32be firstBootMode;\n}sysSettingsArguments_t;\n\nstatic_assert(sizeof(sysSettingsArguments_t) == 0x1C);\nstatic_assert(offsetof(sysSettingsArguments_t, jumpTo) == 0x10);\nstatic_assert(offsetof(sysSettingsArguments_t, needsReturn) == 0x14);\nstatic_assert(offsetof(sysSettingsArguments_t, firstBootMode) == 0x18);\n\n/*\nSys settings jumpTo values:\n0x00 -> Normal launch\n0x01 -> Internet settings\n0x02 -> Data management\n0x03 -> TV remote\n0x04 -> Date settings\n0x05 -> Country settings\n0x06 -> System update\n\n0x64 -> Initial system configuration (after Wii U GamePad was configured)\n0x65 -> Crashes\n0x66 -> Delete All Content and Settings (throws erreula after a second)\n0x67 -> Quick Start Settings\n0x68 -> TV connection type\n0x69 -> Data management\n0xFF -> Data transfer\n*/\n\ntypedef struct\n{\n\t/* +0x00 */ sysDeserializeStandardArguments_t standardArguments; // guessed\n\t/* +0x10 */ uint32be ukn10;\n\t/* +0x14 */ uint32be ukn14;\n}eshopArguments_t;\n\nstatic_assert(sizeof(eshopArguments_t) == 0x18);\n\n#define SYS_STANDARD_ARGS_MAX_LEN\t\t0x1000\n\n#define OS_COPY_MAX_DATA_SIZE\t\t\t(0x400000-4)\n\nvoid appendDataToBuffer(uint32 currentCopyDataSize, char* str, sint32 size)\n{\n\tcemu_assert_unimplemented();\n}\n\nsint32 _serializeArgsToBuffer(uint32 currentCopyDataSize, const char* argName, char* str, sint32 size, void (*appendFunc)(uint32 currentCopyDataSize, char* str, sint32 size))\n{\n\tif (strnlen(argName, 0x41) == 0x40)\n\t\treturn -0x2710;\n\tif (size > 0x200000)\n\t\treturn -0x7530;\n\tchar tempStr[0x80];\n\tif (size != 0 && str != nullptr)\n\t{\n\t\tsint32 textSize = sprintf(tempStr, \"<%s %s=%u>\", argName, \"size\", size);\n\t\tif ((currentCopyDataSize + textSize + size) >= OS_COPY_MAX_DATA_SIZE)\n\t\t\treturn 0xFFFF63C0;\n\t\tappendFunc(currentCopyDataSize, str, size);\n\t\tappendFunc(currentCopyDataSize, tempStr, textSize);\n\t}\n\telse\n\t{\n\t\tsint32 textSize = sprintf(tempStr, \"<%s>\", argName);\n\t\tappendFunc(currentCopyDataSize, tempStr, textSize);\n\t}\n\treturn 0;\n}\n\nsint32 SYSPackArgs()\n{\n\tuint32 currentCopyDataSize = coreinit::__OSGetCopyDataSize();\n\tchar sysPackStr[128];\n\tsint32 textSize = sprintf(sysPackStr, \"<%s %s=%u>\", \"sys:pack\", \"size\", currentCopyDataSize);\n\tif ((currentCopyDataSize + textSize) > OS_COPY_MAX_DATA_SIZE)\n\t\treturn 0xFFFF4480;\n\tcoreinit::__OSAppendCopyData((uint8*)sysPackStr, textSize);\n\treturn 0;\n}\n\nsint32 SYSSerializeSysArgs(const char* argName, char* str, sint32 size)\n{\n\tuint32 currentCopyDataSize = coreinit::__OSGetCopyDataSize();\n\tsint32 r = _serializeArgsToBuffer(currentCopyDataSize, argName, str, size, appendDataToBuffer);\n\tif (r < 0)\n\t\treturn r;\n\treturn 0;\n}\n\nsint32 _SYSSerializeStandardArgsIn(sysStandardArguments_t* standardArgs)\n{\n\tif (strnlen(standardArgs->argStr.GetPtr(), SYS_STANDARD_ARGS_MAX_LEN + 4) > SYS_STANDARD_ARGS_MAX_LEN)\n\t{\n\t\treturn 0xFFFF63C0;\n\t}\n\tSYSSerializeSysArgs(\"sys:anchor\", standardArgs->argStr.GetPtr(), standardArgs->size);\n\tSYSPackArgs();\n\treturn 0;\n}\n\nsint32 _SYSAppendCallerInfo()\n{\n\t// todo\n\treturn 0;\n}\n\ntypedef struct  \n{\n\tuint32be id;\n\tuint32be type;\n\t// union data here - todo\n}sysArgSlot_t;\n\n#define SYS_ARG_ID_END\t\t\t\t0\t// indicates end of sysArgSlot_t array\n#define SYS_ARG_ID_ANCHOR\t\t\t100\n\ntypedef struct\n{\n\tchar* argument;\n\tuint32 size;\n\tuint8* data;\n}deserializedArg_t;\n\nuint32 _sysArg_packSize = 0;\n\nvoid clearSysArgs()\n{\n\t_sysArg_packSize = 0;\n}\n\nvoid deserializeSysArg(deserializedArg_t* deserializedArg)\n{\n\tif (strcmp(deserializedArg->argument, \"sys:pack\") == 0)\n\t\t_sysArg_packSize = deserializedArg->size;\n\t// todo\n}\n\nsint32 _deserializeSysArgsEx2(uint8* copyDataPtr, sint32 copyDataSize, void(*cbDeserializeArg)(deserializedArg_t* deserializedArg, void* customParam), void* customParam)\n{\n\tsint32 idx = copyDataSize - 1;\n\tsint32 argSlotIndex = 0;\n\twhile (idx >= 0)\n\t{\n\t\tif (copyDataPtr[idx] == '>')\n\t\t{\n\t\t\t// find matching '<'\n\t\t\tsint32 idxStart = idx;\n\t\t\twhile (true)\n\t\t\t{\n\t\t\t\tidxStart--;\n\t\t\t\tif (idxStart < 0)\n\t\t\t\t\treturn 1;\n\t\t\t\tif (copyDataPtr[idxStart] == '<')\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tsint32 idxDataEnd = idxStart;\n\t\t\tidxStart++;\n\t\t\t// parse argument name\n\t\t\tchar argumentName[64];\n\t\t\tsint32 idxCurrent = idxStart;\n\t\t\twhile( idxCurrent <= idx )\n\t\t\t{\n\t\t\t\targumentName[idxCurrent - idxStart] = copyDataPtr[idxCurrent];\n\t\t\t\tif ((idxCurrent - idxStart) >= 60)\n\t\t\t\t\treturn 1;\n\t\t\t\tif (copyDataPtr[idxCurrent] == ' ' || copyDataPtr[idxCurrent] == '>')\n\t\t\t\t{\n\t\t\t\t\targumentName[idxCurrent - idxStart] = '\\0';\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tidxCurrent++;\n\t\t\t}\n\t\t\t// parse size (if any)\n\t\t\twhile (copyDataPtr[idxCurrent] == ' ')\n\t\t\t\tidxCurrent++;\n\t\t\tsint32 argumentDataSize;\n\t\t\tif (copyDataPtr[idxCurrent] == '>')\n\t\t\t{\n\t\t\t\targumentDataSize = 0;\n\t\t\t}\n\t\t\telse if ((copyDataSize - idxCurrent) >= 5 && memcmp(copyDataPtr+idxCurrent, \"size\", 4) == 0)\n\t\t\t{\n\t\t\t\tidxCurrent += 4;\n\t\t\t\t// skip whitespaces and '='\n\t\t\t\twhile (copyDataPtr[idxCurrent] == ' ' || copyDataPtr[idxCurrent] == '=')\n\t\t\t\t\tidxCurrent++;\n\t\t\t\t// parse size value\n\t\t\t\tchar tempSizeStr[32];\n\t\t\t\tsint32 sizeParamLen = idx - idxCurrent;\n\t\t\t\tif (sizeParamLen < 0 || sizeParamLen >= 30)\n\t\t\t\t\treturn 1;\n\t\t\t\tmemcpy(tempSizeStr, copyDataPtr+idxCurrent, sizeParamLen);\n\t\t\t\ttempSizeStr[sizeParamLen] = '\\0';\n\t\t\t\targumentDataSize = atol(tempSizeStr);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tassert_dbg();\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tidx = idxStart - argumentDataSize - 1; // beginning of data\n\t\t\tdeserializedArg_t deserializedArg = { 0 };\n\t\t\tdeserializedArg.argument = argumentName;\n\t\t\tdeserializedArg.size = argumentDataSize;\n\t\t\tdeserializedArg.data = copyDataPtr + idx;\n\t\t\tdeserializeSysArg(&deserializedArg);\n\t\t\tif (cbDeserializeArg)\n\t\t\t\tcbDeserializeArg(&deserializedArg, customParam);\n\n\t\t\tidx--;\n\t\t}\n\t\telse if (copyDataPtr[idx] == ']')\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t\telse\n\t\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nvoid _deserializeSysArgsEx(void(*cbDeserializeArg)(deserializedArg_t* deserializedArg, void* customParam), void* customParam)\n{\n\tsint32 copyDataSize = coreinit::__OSGetCopyDataSize();\n\tuint8* copyDataPtr = coreinit::__OSGetCopyDataPtr();\n\t_deserializeSysArgsEx2(copyDataPtr, copyDataSize, cbDeserializeArg, customParam);\n}\n\nvoid SYSDeserializeSysArgs(void(*cbDeserializeArg)(deserializedArg_t* deserializedArg, void* customParam), sysArgSlot_t* argSlots)\n{\n\t_deserializeSysArgsEx(cbDeserializeArg, argSlots);\n}\n\nsint32 _deserializeArgs(void* customParam, sint32 customParamSize, void(*cbDeserializeArg)(deserializedArg_t* deserializedArg, void* customParam))\n{\n\tmemset(customParam, 0, customParamSize);\n\tclearSysArgs();\n\t_deserializeSysArgsEx(cbDeserializeArg, customParam);\n\treturn 0;\n}\n\nvoid _unpackSysWorkaround()\n{\n\t// unpack sys\n\tclearSysArgs();\n\t_deserializeSysArgsEx(NULL, NULL);\n\tif (_sysArg_packSize != 0)\n\t{\n\t\tcoreinit::__OSResizeCopyData(_sysArg_packSize);\n\t}\n}\n\nvoid cbDeserializeArg_MiiMaker(deserializedArg_t* deserializedArg, void* customParam)\n{\n\tsysMiiStudioArguments2_t* miiStudioArgs = (sysMiiStudioArguments2_t*)customParam;\n\n\tif (strcmp(deserializedArg->argument, \"mode\") == 0)\n\t{\n\t\tmiiStudioArgs->mode = *(uint32be*)deserializedArg->data;\n\t}\n\telse if (strcmp(deserializedArg->argument, \"mii\") == 0)\n\t{\n\t\tassert_dbg();\n\t}\n\telse if (strcmp(deserializedArg->argument, \"slot_id\") == 0)\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tassert_dbg();\n#endif\n\t}\n\telse\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tassert_dbg();\n#endif\n\t}\n}\n\nsint32 _SYSGetMiiStudioArgs(sysMiiStudioArguments2_t* miiStudioArgs)\n{\n\t_unpackSysWorkaround();\n\t_deserializeArgs(miiStudioArgs, sizeof(sysMiiStudioArguments2_t), cbDeserializeArg_MiiMaker);\n\treturn 0;\n}\n\nvoid sysappExport__SYSGetMiiStudioArgs(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(miiStudioArgs, sysMiiStudioArguments2_t, 0);\n\tsint32 r = _SYSGetMiiStudioArgs(miiStudioArgs);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid cbDeserializeArg_SysSettings(deserializedArg_t* deserializedArg, void* customParam)\n{\n\tsysSettingsArguments_t* settingsArgs = (sysSettingsArguments_t*)customParam;\n\tif (boost::iequals(deserializedArg->argument, \"jump_to\"))\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\telse if (boost::iequals(deserializedArg->argument, \"first_boot_kind\"))\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\telse if (boost::iequals(deserializedArg->argument, \"needs_return\"))\n\t{\n\t\tsettingsArgs->needsReturn = 1;\n\t}\n\telse\n\t\tcemu_assert_unimplemented();\n}\n\nsint32 _SYSGetSettingsArgs(sysSettingsArguments_t* settingsArgs)\n{\n\t_unpackSysWorkaround();\n\tmemset(settingsArgs, 0, sizeof(sysSettingsArguments_t));\n\treturn _deserializeArgs(settingsArgs, sizeof(sysSettingsArguments_t), cbDeserializeArg_SysSettings);\n}\n\nvoid sysappExport__SYSGetSettingsArgs(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(settingsArgs, sysSettingsArguments_t, 0);\n\tsint32 r = _SYSGetSettingsArgs(settingsArgs);\n\n\tif (settingsArgs->jumpTo == 0) // workaround when launching sys settings directly\n\t\tsettingsArgs->jumpTo = 0x00;\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nstruct  \n{\n\tuint64 t0;\n\tuint64 t1;\n\tuint64 t2;\n}systemApplicationTitleId[] = {\n\t{ 0x5001010040000, 0x5001010040100, 0x5001010040200 }, // Wii U Menu \n\t{ 0x5001010047000, 0x5001010047100, 0x5001010047200 }, // System Settings \n\t{ 0x5001010048000, 0x5001010048100, 0x5001010048200 }, // Parental Controls\n\t{ 0x5001010049000, 0x5001010049100, 0x5001010049200 }, // User Settings \n\t{ 0x500101004A000, 0x500101004A100, 0x500101004A200 }, // Mii Maker \n\t{ 0x500101004B000, 0x500101004B100, 0x500101004B200 }, // Account Settings\n\t{ 0x500101004C000, 0x500101004C100, 0x500101004C200 }, // Daily Log \n\t{ 0x500101004D000, 0x500101004D100, 0x500101004D200 }, // Notifications\n\t{ 0x500101004E000, 0x500101004E100, 0x500101004E200 }, // Health and Safety Information \n\t{ 0x5001B10059000, 0x5001B10059100, 0x5001B10059200 }, // Wii U Electronic Manual \n\t{ 0x500101005A000, 0x500101005A100, 0x500101005A200 }, // Wii U Chat \n\t{ 0x5001010062000, 0x5001010062100, 0x5001010062200 }  // Software/Data Transfer \n};\n\nuint64 _SYSGetSystemApplicationTitleIdByProdArea(uint32 systemApplicationId, uint32 platformRegion)\n{\n\tif (systemApplicationId >= (sizeof(systemApplicationTitleId) / sizeof(systemApplicationTitleId[0])) )\n\t\tassert_dbg();\n\n\tif (platformRegion == 1)\n\t{\n\t\treturn systemApplicationTitleId[systemApplicationId].t0;\n\t}\n\telse if (platformRegion == 4 || platformRegion == 8)\n\t{\n\t\treturn systemApplicationTitleId[systemApplicationId].t2;\n\t}\n\treturn systemApplicationTitleId[systemApplicationId].t1;\n}\n\nuint64 _SYSGetSystemApplicationTitleId(sint32 index)\n{\n\tuint32 region = (uint32)CafeSystem::GetPlatformRegion();\n\treturn _SYSGetSystemApplicationTitleIdByProdArea(index, region);\n}\n\nvoid sysappExport__SYSGetSystemApplicationTitleId(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(systemApplicationId, 0);\n\tcemuLog_logDebug(LogType::Force, \"_SYSGetSystemApplicationTitleId(0x{:x})\", hCPU->gpr[3]);\n\n\tuint64 titleId = _SYSGetSystemApplicationTitleId(systemApplicationId);\n\tosLib_returnFromFunction64(hCPU, titleId);\n}\n\nvoid __LaunchMiiMaker(sysMiiStudioArguments_t* args, uint32 platformRegion)\n{\n\tcoreinit::__OSClearCopyData();\n\tif (args)\n\t{\n\t\t_SYSSerializeStandardArgsIn(&args->standardArguments);\n\t\tSYSSerializeSysArgs(\"mode\", (char*)&args->mode, 4);\n\t\tSYSSerializeSysArgs(\"slot_id\", (char*)&args->slot_id, 4);\n\t\tif(args->mii)\n\t\t\tSYSSerializeSysArgs(\"mii\", (char*)args->mii.GetPtr(), 0x60);\n\t}\n\t_SYSAppendCallerInfo();\n\tuint64 titleIdToLaunch = _SYSGetSystemApplicationTitleIdByProdArea(4, platformRegion);\n\tcemu_assert_unimplemented();\n}\n\nvoid _SYSLaunchMiiStudio(sysMiiStudioArguments_t* args)\n{\n\t__LaunchMiiMaker(args, (uint32)CafeSystem::GetPlatformRegion());\n}\n\nvoid sysappExport__SYSLaunchMiiStudio(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(args, sysMiiStudioArguments_t, 0);\n\t_SYSLaunchMiiStudio(args);\n}\n\nvoid sysappExport__SYSReturnToCallerWithStandardResult(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32BEPtr(resultPtr, 0);\n\tcemuLog_log(LogType::Force, \"_SYSReturnToCallerWithStandardResult(0x{:08x}) result: 0x{:08x}\", hCPU->gpr[3], (uint32)*resultPtr);\n\twhile (true) std::this_thread::sleep_for(std::chrono::milliseconds(10));\n}\n\nvoid sysappExport__SYSGetEShopArgs(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(args, eshopArguments_t, 0);\n\tcemuLog_logDebug(LogType::Force, \"_SYSGetEShopArgs() - placeholder\");\n\tmemset(args, 0, sizeof(eshopArguments_t));\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid sysappExport_SYSGetUPIDFromTitleID(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU64(titleId, 0);\n\tuint32 titleIdHigh = (titleId >> 32);\n\tuint32 titleIdLow = (uint32)(titleId & 0xFFFFFFFF);\n\tif ((titleIdHigh & 0xFFFF0000) != 0x50000)\n\t{\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\tif ((titleIdLow & 0xF0000000) != 0x10000000)\n\t{\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\tuint32 titleId_type = (titleIdHigh & 0xFF);\n\n\tif (titleId_type == 0x30)\n\t{\n\t\t// applet\n\t\tuint32 ukn = ((titleIdLow >> 12) & 0xFFFF);\n\t\tif (ukn < 0x10)\n\t\t{\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\t\telse if (ukn <= 0x19)\n\t\t{\n\t\t\tuint8 appletTable10[10] = { 5,6,8,3,0xA,0xB,9,4,0xC,7 };\n\t\t\tosLib_returnFromFunction(hCPU, appletTable10[ukn - 0x10]);\n\t\t\treturn;\n\t\t}\n\t\telse if (ukn <= 0x20)\n\t\t{\n\t\t\tassert_dbg();\n\t\t\tosLib_returnFromFunction(hCPU, -1);\n\t\t\treturn;\n\t\t}\n\t\telse if (ukn <= 0x29)\n\t\t{\n\t\t\tuint8 appletTable20[10] = {5,6,8,3,0xA,0xB,9,4,0xC,7};\n\t\t\tosLib_returnFromFunction(hCPU, appletTable20[ukn-0x20]);\n\t\t\treturn;\n\t\t}\n\t\tassert_dbg();\n\t\tosLib_returnFromFunction(hCPU, -1);\n\t\treturn;\n\t}\n\telse if (titleId_type == 0x10)\n\t{\n\t\t// system application\n\t\tif (((titleIdLow >> 12) & 0xFFFF) == 0x40)\n\t\t{\n\t\t\t// Wii U menu\n\t\t\tosLib_returnFromFunction(hCPU, 2);\n\t\t\treturn;\n\t\t}\n\t\tosLib_returnFromFunction(hCPU, 0xF);\n\t\treturn;\n\t}\n\telse if (titleId_type == 0x00 || titleId_type == 0x02)\n\t{\n\t\tosLib_returnFromFunction(hCPU, 0xF);\n\t\treturn;\n\t}\n\tosLib_returnFromFunction(hCPU, -1);\n}\n\nvoid sysappExport_SYSGetVodArgs(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"SYSGetVodArgs() - todo\");\n\tosLib_returnFromFunction(hCPU, 1);\n}\n\nstruct SysLauncherArgs18\n{\n\tuint64be caller_id; // titleId\n\tuint64be launch_title; // titleId\n\tuint32be mode;\n\tuint32be slot_id;\n};\n\nstatic_assert(sizeof(SysLauncherArgs18) == 0x18);\n\nstruct SysLauncherArgs28\n{\n\tuint32 ukn00;\n\tuint32 ukn04;\n\tuint32 ukn08;\n\tuint32 ukn0C;\n\t// standard args above\n\tuint64be caller_id; // titleId\n\tuint64be launch_title; // titleId\n\tuint32be mode;\n\tuint32be slot_id;\n};\n\nstatic_assert(sizeof(SysLauncherArgs28) == 0x28);\n\nuint32 _SYSGetLauncherArgs(void* argsOut)\n{\n\tuint32 sdkVersion = coreinit::__OSGetProcessSDKVersion();\n\tif(sdkVersion < 21103)\n\t{\n\t\t// old format\n\t\tSysLauncherArgs18* launcherArgs18 = (SysLauncherArgs18*)argsOut;\n\t\tmemset(launcherArgs18, 0, sizeof(SysLauncherArgs18));\n\t}\n\telse\n\t{\n\t\t// new format\n\t\tSysLauncherArgs28* launcherArgs28 = (SysLauncherArgs28*)argsOut;\n\t\tmemset(launcherArgs28, 0, sizeof(SysLauncherArgs28));\n\t}\n\treturn 0; // return argument is todo\n}\n\nstruct SysAccountArgs18\n{\n\tuint32be ukn00;\n\tuint32be ukn04;\n\tuint32be ukn08;\n\tuint32be ukn0C;\n\t// shares part above with Standard arg\n\tuint32be slotId; // \"slot_id\"\n\tuint32be mode; // \"mode\"\n};\n\nuint32 _SYSGetAccountArgs(SysAccountArgs18* argsOut)\n{\n\tmemset(argsOut, 0, sizeof(SysAccountArgs18));\n\n\t// sysDeserializeStandardArguments_t ?\n\n\treturn 0;\n}\n\nvoid sysappExport_SYSGetStandardResult(PPCInterpreter_t* hCPU)\n{\n\tcemuLog_logDebug(LogType::Force, \"SYSGetStandardResult(0x{:08x},0x{:08x},0x{:08x})\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5]);\n\tmemset(memory_getPointerFromVirtualOffset(hCPU->gpr[3]), 0, 4);\n\n\t// r3 = uint32be* output\n\t// r4 = pointer to data to parse?\n\t// r5 = size to parse?\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nnamespace sysapp\n{\n\tvoid SYSClearSysArgs()\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"SYSClearSysArgs()\");\n\t\tcoreinit::__OSClearCopyData();\n\t}\n\n\tuint32 _SYSLaunchTitleByPathFromLauncher(const char* path, uint32 pathLength)\n\t{\n\t\tcoreinit::__OSClearCopyData();\n\t\t_SYSAppendCallerInfo();\n\t\treturn coreinit::OSLaunchTitleByPathl(path, pathLength, 0);\n\t}\n\n\tuint32 SYSRelaunchTitle(uint32 argc, MEMPTR<char>* argv)\n\t{\n\t\t// calls ACPCheckSelfTitleNotReferAccountLaunch?\n\t\tcoreinit::__OSClearCopyData();\n\t\t_SYSAppendCallerInfo();\n\t\treturn coreinit::OSRestartGame(argc, argv);\n\t}\n\n\tstruct EManualArgs\n\t{\n\t\tsysStandardArguments_t stdArgs;\n\t\tuint64be titleId;\n\t};\n\tstatic_assert(sizeof(EManualArgs) == 0x10);\n\n\tvoid _SYSSwitchToEManual(EManualArgs* args)\n\t{\n\t\t// the struct has the titleId at offset 8 and standard args at 0 (total size is most likely 0x10)\n\t\tcemuLog_log(LogType::Force, \"SYSSwitchToEManual called. Opening the manual is not supported\");\n\t\tcoreinit::StartBackgroundForegroundTransition();\n\t}\n\n\tvoid SYSSwitchToEManual()\n\t{\n\t\tEManualArgs args{};\n\t\targs.titleId = coreinit::OSGetTitleID();\n\t\t_SYSSwitchToEManual(&args);\n\t}\n\n\tvoid load()\n\t{\n\t\tcafeExportRegisterFunc(SYSClearSysArgs, \"sysapp\", \"SYSClearSysArgs\", LogType::Placeholder);\n\t\tcafeExportRegisterFunc(_SYSLaunchTitleByPathFromLauncher, \"sysapp\", \"_SYSLaunchTitleByPathFromLauncher\", LogType::Placeholder);\n\t\tcafeExportRegisterFunc(SYSRelaunchTitle, \"sysapp\", \"SYSRelaunchTitle\", LogType::Placeholder);\n\t\tcafeExportRegister(\"sysapp\", _SYSSwitchToEManual, LogType::Placeholder);\n\t\tcafeExportRegister(\"sysapp\", SYSSwitchToEManual, LogType::Placeholder);\n\t}\n}\n\nnamespace sysapp\n{\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"sysapp\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"sysapp\", \"_SYSLaunchMiiStudio\", sysappExport__SYSLaunchMiiStudio);\n\t\t\tosLib_addFunction(\"sysapp\", \"_SYSGetMiiStudioArgs\", sysappExport__SYSGetMiiStudioArgs);\n\t\t\tosLib_addFunction(\"sysapp\", \"_SYSGetSettingsArgs\", sysappExport__SYSGetSettingsArgs);\n\t\t\tosLib_addFunction(\"sysapp\", \"_SYSReturnToCallerWithStandardResult\", sysappExport__SYSReturnToCallerWithStandardResult);\n\n\t\t\tosLib_addFunction(\"sysapp\", \"_SYSGetSystemApplicationTitleId\", sysappExport__SYSGetSystemApplicationTitleId);\n\t\t\tosLib_addFunction(\"sysapp\", \"SYSGetUPIDFromTitleID\", sysappExport_SYSGetUPIDFromTitleID);\n\n\t\t\tosLib_addFunction(\"sysapp\", \"_SYSGetEShopArgs\", sysappExport__SYSGetEShopArgs);\n\n\t\t\tosLib_addFunction(\"sysapp\", \"SYSGetVodArgs\", sysappExport_SYSGetVodArgs);\n\n\t\t\tosLib_addFunction(\"sysapp\", \"SYSGetStandardResult\", sysappExport_SYSGetStandardResult);\n\n\t\t\tcafeExportRegisterFunc(_SYSGetLauncherArgs, \"sysapp\", \"_SYSGetLauncherArgs\", LogType::Placeholder);\n\t\t\tcafeExportRegisterFunc(_SYSGetAccountArgs, \"sysapp\", \"_SYSGetAccountArgs\", LogType::Placeholder);\n\n\t\t\tsysapp::load();\n\t\t};\n\n\t}s_COSsysappModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSsysappModule;\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/sysapp/sysapp.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace sysapp\n{\n\tCOSModule* GetModule();\n}\n\nuint64 _SYSGetSystemApplicationTitleId(sint32 index);"
  },
  {
    "path": "src/Cafe/OS/libs/vpad/vpad.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n#include \"Cafe/OS/libs/vpad/vpad.h\"\n#include \"audio/IAudioAPI.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Alarm.h\"\n#include \"input/InputManager.h\"\n#include \"WindowSystem.h\"\n\n#ifdef PUBLIC_RELASE\n#define vpadbreak() \n#else\n#define vpadbreak()// __debugbreak();\n#endif\n\n#define VPAD_READ_ERR_NONE\t\t\t0\n#define VPAD_READ_ERR_NO_DATA\t\t-1\n#define VPAD_READ_ERR_NO_CONTROLLER\t-2\n#define VPAD_READ_ERR_SETUP\t\t\t-3\n#define VPAD_READ_ERR_LOCKED\t\t-4\n#define VPAD_READ_ERR_INIT\t\t\t-5\n\n#define VPAD_TP_VALIDITY_VALID\t\t0\n#define VPAD_TP_VALIDITY_INVALID_X\t1\n#define VPAD_TP_VALIDITY_INVALID_Y\t2\n#define VPAD_TP_VALIDITY_INVALID_XY\t(VPAD_TP_VALIDITY_INVALID_X | VPAD_TP_VALIDITY_INVALID_Y)\n\n#define VPAD_GYRO_ZERODRIFT_LOOSE\t\t0\n#define VPAD_GYRO_ZERODRIFT_STANDARD\t1\n#define VPAD_GYRO_ZERODRIFT_TIGHT\t\t2\n#define VPAD_GYRO_ZERODRIFT_NONE\t\t3\n\n#define VPAD_PLAY_MODE_LOOSE\t\t\t0\n#define VPAD_PLAY_MODE_TIGHT\t\t\t1\n\n#define VPAD_BUTTON_PROC_MODE_LOOSE\t\t0\n#define VPAD_BUTTON_PROC_MODE_TIGHT\t\t1\n\n#define VPAD_LCD_MODE_MUTE\t\t\t\t0\n#define VPAD_LCD_MODE_GAME_CONTROLLER\t1\n#define VPAD_LCD_MODE_ON\t\t\t\t0xFF\n\n#define VPAD_MOTOR_PATTERN_SIZE_MAX\t\t15\n#define VPAD_MOTOR_PATTERN_LENGTH_MAX\t120\n\n#define VPAD_TP_1920x1080\t\t\t\t0\n#define VPAD_TP_1280x720\t\t\t\t1\n#define VPAD_TP_854x480\t\t\t\t\t2\n\nextern bool isLaunchTypeELF;\n\nVPADDir g_vpadGyroDirOverwrite[VPAD_MAX_CONTROLLERS] =\n{\n\t\t{{1.0f,0.0f,0.0f}, {0.0f,1.0f,0.0f}, {0.0f, 0.0f, 0.1f}},\n\t\t{{1.0f,0.0f,0.0f}, {0.0f,1.0f,0.0f}, {0.0f, 0.0f, 0.1f}}\n};\nuint32 g_vpadGyroZeroDriftMode[VPAD_MAX_CONTROLLERS] = { VPAD_GYRO_ZERODRIFT_STANDARD, VPAD_GYRO_ZERODRIFT_STANDARD };\n\nstruct VPACGyroDirRevise_t\n{\n\tbool enabled;\n\tVPADDir vpadGyroDirReviseBase;\n\tfloat weight;\n} g_vpadGyroDirRevise[VPAD_MAX_CONTROLLERS] = {};\n\nstruct VPADAccParam_t\n{ // TODO P: use\n\tfloat playRadius;\n\tfloat sensitivity;\n} g_vpadAccParam[VPAD_MAX_CONTROLLERS] = { {0, 1}, {0, 1} };\n\nuint32 g_vpadPlayMode[VPAD_MAX_CONTROLLERS] = { VPAD_PLAY_MODE_TIGHT, VPAD_PLAY_MODE_TIGHT }; // TODO P: use\n\n#define VPAD_MIN_CLAMP\t(0x102)\n#define VPAD_MAX_CLAMP\t(0x397)\n\nstruct VPADStickClamp\n{ // TODO P: use\n\tbool crossMode; // default is circular mode\n\n\tsint32 leftMax;\n\tsint32 leftMin;\n\n\tsint32 rightMax;\n\tsint32 rightMin;\n} vpadStickClamp[VPAD_MAX_CONTROLLERS] = { {false, VPAD_MAX_CLAMP, VPAD_MIN_CLAMP}, {false, VPAD_MAX_CLAMP, VPAD_MIN_CLAMP} };\n\nstruct VPADCrossStickEmulationParams\n{ // TODO P: use\n\tfloat leftRotation;\n\tfloat leftInputRange;\n\tfloat leftRadius;\n\n\tfloat rightRotation;\n\tfloat rightInputRange;\n\tfloat rightRadius;\n} vpadCrossStickEmulationParams[VPAD_MAX_CONTROLLERS] = {};\n\nuint8 vpadButtonProcMode[VPAD_MAX_CONTROLLERS] = { VPAD_BUTTON_PROC_MODE_TIGHT, VPAD_BUTTON_PROC_MODE_TIGHT }; // TODO P: use\nuint32 vpadLcdMode[VPAD_MAX_CONTROLLERS] = { VPAD_LCD_MODE_ON, VPAD_LCD_MODE_ON };\n\nstruct VPADTPCalibrationParam\n{ // TODO P: use\n\tuint16be offsetX;\n\tuint16be offsetY;\n\tfloat32be scaleX;\n\tfloat32be scaleY;\n} vpadTPCalibrationParam[VPAD_MAX_CONTROLLERS] = { {92, 254, (1280.0f / 3883.0f), (720.0f / 3694.0f)}, {92, 254, (1280.0f / 3883.0f), (720.0f / 3694.0f)} };\n\nvoid _tpRawToResolution(sint32 x, sint32 y, sint32* outX, sint32* outY, sint32 width, sint32 height)\n{\n\tx -= 92;\n\ty = 4095.0 - y - 254;\n\n\tx = std::max(x, 0);\n\ty = std::max(y, 0);\n\n\t*outX = (sint32)(((double)x / 3883.0) * (double)width);\n\t*outY = (sint32)(((double)y / 3694.0) * (double)height);\n}\n\n\nnamespace vpad\n{\n\tenum class PlayMode : sint32\n\t{\n\t\tLoose = 0,\n\t\tTight = 1\n\t};\n\n\tenum class LcdMode\n\t{\n\t\tOff = 0,\n\t\tControllerOnly = 1,\n\t\tOn = 0xFF,\n\t};\n\n\tstruct VPADTPCalibrationParam\n\t{\n\t\tsint16be x, y;\n\t\tfloat32be scale_x, scale_y;\n\t};\n\n\tstruct VPADTPData\n\t{\n\t\tuint16be x, y, touch, valid;\n\t};\n\n\tenum class VPADTPResolution\n\t{\n\t\t_1920x1080 = 0,\n\t\t_1280x720 = 1,\n\t\t_854_480 = 2,\n\t};\n\n\tenum class ButtonProcMode : uint8\n\t{\n\t\tLoose = 0,\n\t\tTight = 1,\n\t};\n\t\n\tstruct\n\t{\n\t\tSysAllocator<coreinit::OSAlarm_t> alarm;\n\n\t\tstruct\n\t\t{\n\t\t\tuint64 drcLastCallTime = 0;\n\n\t\t\tstruct AccParam\n\t\t\t{\n\t\t\t\tfloat radius, sensitivity;\n\t\t\t} acc_param;\n\t\t\tBtnRepeat btn_repeat;\n\n\t\t\tMEMPTR<void> sampling_callback;\n\t\t\tPlayMode acc_play_mode;\n\n\t\t\tVPADTPCalibrationParam tp_calibration_param{};\n\t\t\tuint16 tp_size = 0xc;\n\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tfloat rotation, range, radius;\n\t\t\t}cross_stick_emulation_l{}, cross_stick_emulation_r{};\n\n\t\t\tButtonProcMode button_proc_mode;\n\n\t\t\tstruct\n\t\t\t{\n\t\t\t\tbool enabled = false;\n\t\t\t\tstruct\n\t\t\t\t{\n\t\t\t\t\tsint32 min = 0x102, max = 0x397;\n\t\t\t\t} left{}, right{};\n\t\t\t}stick_cross_clamp{};\n\n\t\t}controller_data[VPAD_MAX_CONTROLLERS]{};\n\t} g_vpad;\n\n\t\n\n\tvoid VPADSetAccParam(sint32 channel, float radius, float sensitivity)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetAccParam({}, {}, {})\", channel, radius, sensitivity);\n\t\tvpadbreak();\n\t\tg_vpad.controller_data[channel].acc_param.radius = radius;\n\t\tg_vpad.controller_data[channel].acc_param.sensitivity = sensitivity;\n\t}\n\n\tvoid VPADGetAccParam(sint32 channel, float* radius, float* sensitivity)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADGetAccParam({}, {}, {})\", channel, (void*)radius, (void*)sensitivity);\n\t\tvpadbreak();\n\t\t*radius = g_vpad.controller_data[channel].acc_param.radius;\n\t\t*sensitivity = g_vpad.controller_data[channel].acc_param.sensitivity;\n\t}\n\n\tsint32 VPADRead(sint32 channel, VPADStatus* status, uint32 length, sint32be* error) \n\t{\n\t\t//printf(\"VPADRead(%d,0x%08X,%d,0x%08x)\\n\", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6]);\n\t\t/*ppcDefineParamU32(channel, 0);\n\t\tppcDefineParamStructPtr(status, VPADStatus_t, 1);\n\t\tppcDefineParamU32(length, 2);\n\t\tppcDefineParamPtr(error, uint32be, 3);\n\t\tcemuLog_log(LogType::InputAPI, \"VPADRead({}, _, {})\", channel, length);*/\n\t\n\t\t// default init which should be always set\n\t\tmemset(status, 0x00, sizeof(VPADStatus_t));\n\n\t\t// default misc\n\t\tstatus->batteryLevel = 0xC0; // full battery\n\t\tstatus->slideVolume = status->slideVolume2 = (uint8)((g_padVolume * 0xFF) / 100);\n\n\t\t// default touch\n\t\tstatus->tpData.validity = VPAD_TP_VALIDITY_INVALID_XY;\n\t\tstatus->tpProcessed1.validity = VPAD_TP_VALIDITY_INVALID_XY;\n\t\tstatus->tpProcessed2.validity = VPAD_TP_VALIDITY_INVALID_XY;\n\n\t\tconst auto controller = InputManager::instance().get_vpad_controller(channel);\n\t\tif (!controller)\n\t\t{\n\t\t\t// most games expect the Wii U GamePad to be connected, so even if the user has not set it up we should still return empty samples for channel 0\n\t\t\tif(channel != 0)\n\t\t\t{\n\t\t\t\tif (error)\n\t\t\t\t\t*error = VPAD_READ_ERR_NO_CONTROLLER;\n\t\t\t\tif (length > 0)\n\t\t\t\t\tstatus->vpadErr = -1;\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (error)\n\t\t\t\t*error = VPAD_READ_ERR_NONE;\n\t\t\treturn 1;\n\t\t}\n\n\t\tconst bool vpadDelayEnabled = ActiveSettings::VPADDelayEnabled();\n\n\t\tif (isLaunchTypeELF)\n\t\t{\n\t\t\t// hacky workaround for homebrew games calling VPADRead in an infinite loop\n\t\t\tPPCCore_switchToScheduler();\n\t\t}\n\n\t\tif (!WindowSystem::InputConfigWindowHasFocus())\n\t\t{\n\t\t\tif (channel <= 1 && vpadDelayEnabled)\n\t\t\t{\n\t\t\t\tuint64 currentTime = coreinit::OSGetTime();\n\t\t\t\tconst auto dif = currentTime - vpad::g_vpad.controller_data[channel].drcLastCallTime;\n\t\t\t\tif (dif <= (ESPRESSO_TIMER_CLOCK / 60ull))\n\t\t\t\t{\n\t\t\t\t\t// not ready yet\n\t\t\t\t\tif (error)\n\t\t\t\t\t\t*error = VPAD_READ_ERR_NONE;\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\telse if (dif <= ESPRESSO_TIMER_CLOCK)\n\t\t\t\t{\n\t\t\t\t\tvpad::g_vpad.controller_data[channel].drcLastCallTime += (ESPRESSO_TIMER_CLOCK / 60ull);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tvpad::g_vpad.controller_data[channel].drcLastCallTime = currentTime;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontroller->VPADRead(*status, vpad::g_vpad.controller_data[channel].btn_repeat);\n\t\t\tif (error)\n\t\t\t\t*error = VPAD_READ_ERR_NONE;\n\t\t\treturn 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (error)\n\t\t\t\t*error = VPAD_READ_ERR_NONE;\n\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tvoid VPADSetBtnRepeat(sint32 channel, float delay, float pulse)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetBtnRepeat({}, {}, {})\", channel, delay, pulse);\n\t\tif(pulse == 0)\n\t\t{\n\t\t\tg_vpad.controller_data[channel].btn_repeat.delay = 40000;\n\t\t\tg_vpad.controller_data[channel].btn_repeat.pulse = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tg_vpad.controller_data[channel].btn_repeat.delay = (sint32)((delay * 200.0f) + 0.5f);\n\t\t\tg_vpad.controller_data[channel].btn_repeat.pulse = (sint32)((pulse * 200.0f) + 0.5f);\n\t\t}\n\t}\n\n\n\tvoid VPADSetAccPlayMode(sint32 channel, PlayMode play_mode)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetAccPlayMode({}, {})\", channel, (int)play_mode);\n\t\tvpadbreak();\n\t\tg_vpad.controller_data[channel].acc_play_mode = play_mode;\n\t}\n\n\tPlayMode VPADGetAccPlayMode(sint32 channel)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADGetAccPlayMode({})\", channel);\n\t\tvpadbreak();\n\t\treturn g_vpad.controller_data[channel].acc_play_mode;\n\t}\n\n\tvoid* VPADSetSamplingCallback(sint32 channel, void* callback)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetSamplingCallback({}, 0x{:x})\", channel, MEMPTR(callback).GetMPTR());\n\t\tvpadbreak();\n\n\t\tvoid* result = g_vpad.controller_data[channel].sampling_callback;\n\t\tg_vpad.controller_data[channel].sampling_callback = callback;\n\t\treturn result;\n\t}\n\n\tsint32 VPADCalcTPCalibrationParam(VPADTPCalibrationParam* p, uint16 raw_x1, uint16 raw_y1, uint16 x1, uint16 y1, uint16 raw_x2, uint16 raw_y2, uint16 x2, uint16 y2)\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn 1;\n\t}\n\n\tvoid VPADGetTPCalibrationParam(sint32 channel, VPADTPCalibrationParam* param)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADGetTPCalibrationParam({}, 0x{:x})\", channel, MEMPTR(param).GetMPTR());\n\t\tvpadbreak();\n\n\t\t*param = g_vpad.controller_data[channel].tp_calibration_param;\n\t}\n\n\tvoid VPADSetTPCalibrationParam(sint32 channel, VPADTPCalibrationParam* param)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetTPCalibrationParam({}, 0x{:x})\", channel, MEMPTR(param).GetMPTR());\n\t\tvpadbreak();\n\n\t\tg_vpad.controller_data[channel].tp_calibration_param = *param;\n\t}\n\n\tvoid VPADGetTPCalibratedPoint(sint32 channel, VPADTPData* data, VPADTPData* raw)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADGetTPCalibratedPoint({}, 0x{:x}, 0x{:x})\", channel, MEMPTR(data).GetMPTR(), MEMPTR(raw).GetMPTR());\n\t\tvpadbreak();\n\n\t\tconst auto& controller_data = g_vpad.controller_data[channel];\n\t\tuint16 x = (uint16)((float)raw->x - ((float)controller_data.tp_calibration_param.x * controller_data.tp_calibration_param.scale_x));\n\t\tuint16 y = (uint16)((float)raw->x - ((float)controller_data.tp_calibration_param.y * controller_data.tp_calibration_param.scale_y));\n\n\t\tconst int tp_size = (int)controller_data.tp_size;\n\n\t\tint tmpx = x;\n\t\tif(x <= (int)controller_data.tp_size)\n\t\t\ttmpx = (int)controller_data.tp_size;\n\n\t\tint tmpy = y;\n\t\tif(y <= (int)controller_data.tp_size)\n\t\t\ttmpy = (int)controller_data.tp_size;\n\n\t\tif((0x500 - tp_size) <= tmpx)\n\t\t\tx = (0x500 - tp_size);\n\n\t\tif((0x2d0 - tp_size) <= tmpy)\n\t\t\ty = (0x2d0 - tp_size);\n\n\t\tdata->x = x;\n\t\tdata->y = y;\n\t\tdata->touch = raw->touch;\n\t\tdata->valid = raw->valid;\n\t}\n\n\tvoid VPADGetTPCalibratedPointEx(sint32 channel, VPADTPResolution resolution, VPADTPData* data, VPADTPData* raw)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADGetTPCalibratedPointEx({}, {}, 0x{:x}, 0x{:x})\", channel, (int)resolution, MEMPTR(data).GetMPTR(), MEMPTR(raw).GetMPTR());\n\t\tvpadbreak();\n\n\t}\n\n\tvoid VPADSetCrossStickEmulationParamsL(sint32 channel, float rotation, float range, float radius)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetCrossStickEmulationParamsL({}, {}, {}, {})\", channel, rotation, range, radius);\n\t\tvpadbreak();\n\n\t\tif (range < 0 || 90.0f < range) \n\t\t\treturn;\n\n\t\tif (radius < 0 || 1.0f < radius) \n\t\t\treturn;\n  \n\t\tg_vpad.controller_data[channel].cross_stick_emulation_l.rotation = rotation;\n\t\tg_vpad.controller_data[channel].cross_stick_emulation_l.range = range;\n\t\tg_vpad.controller_data[channel].cross_stick_emulation_l.radius = radius;\n\t}\n\n\tvoid VPADSetCrossStickEmulationParamsR(sint32 channel, float rotation, float range, float radius)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetCrossStickEmulationParamsR({}, {}, {}, {})\", channel, rotation, range, radius);\n\t\tvpadbreak();\n\n\t\tif (range < 0 || 90.0f < range) \n\t\t\treturn;\n\n\t\tif (radius < 0 || 1.0f < radius) \n\t\t\treturn;\n  \n\t\tg_vpad.controller_data[channel].cross_stick_emulation_r.rotation = rotation;\n\t\tg_vpad.controller_data[channel].cross_stick_emulation_r.range = range;\n\t\tg_vpad.controller_data[channel].cross_stick_emulation_r.radius = radius;\n\t}\n\n\tvoid VPADGetCrossStickEmulationParamsL(sint32 channel, float* rotation, float* range, float* radius)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADGetCrossStickEmulationParamsL({}, 0x{:x}, 0x{:x}, 0x{:x})\", channel, MEMPTR(rotation).GetMPTR(),  MEMPTR(range).GetMPTR(),  MEMPTR(radius).GetMPTR());\n\t\tvpadbreak();\n\n\t\t*rotation = g_vpad.controller_data[channel].cross_stick_emulation_l.rotation;\n\t\t*range = g_vpad.controller_data[channel].cross_stick_emulation_l.range;\n\t\t*radius = g_vpad.controller_data[channel].cross_stick_emulation_l.radius;\n\t}\n\n\tvoid VPADGetCrossStickEmulationParamsR(sint32 channel, float* rotation, float* range, float* radius)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADGetCrossStickEmulationParamsR({}, 0x{:x}, 0x{:x}, 0x{:x})\", channel, MEMPTR(rotation).GetMPTR(),  MEMPTR(range).GetMPTR(),  MEMPTR(radius).GetMPTR());\n\t\tvpadbreak();\n\n\t\t*rotation = g_vpad.controller_data[channel].cross_stick_emulation_r.rotation;\n\t\t*range = g_vpad.controller_data[channel].cross_stick_emulation_r.range;\n\t\t*radius = g_vpad.controller_data[channel].cross_stick_emulation_r.radius;\n\t}\n\n\tButtonProcMode VPADGetButtonProcMode(sint32 channel)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADGetButtonProcMode({})\", channel);\n\t\tvpadbreak();\n\n\t\treturn g_vpad.controller_data[channel].button_proc_mode;\n\t}\n\n\tvoid VPADSetButtonProcMode(sint32 channel, ButtonProcMode mode)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetButtonProcMode({}, {})\", channel, (int)mode);\n\t\tvpadbreak();\n\n\t\tg_vpad.controller_data[channel].button_proc_mode = mode;\n\t}\n\n\tvoid VPADEnableStickCrossClamp(sint32 channel)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADEnableStickCrossClamp({})\", channel);\n\t\tvpadbreak();\n\t\tg_vpad.controller_data[channel].stick_cross_clamp.enabled = true;\n\t}\n\n\tvoid VPADDisableStickCrossClamp(sint32 channel)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADDisableStickCrossClamp({})\", channel);\n\t\tvpadbreak();\n\t\tg_vpad.controller_data[channel].stick_cross_clamp.enabled = false;\n\t}\n\n\tvoid VPADSetLStickClampThreshold(sint32 channel, sint32 max, sint32 min)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetLStickClampThreshold({}, {}, {})\", channel, max, min);\n\t\tvpadbreak();\n\t\tg_vpad.controller_data[channel].stick_cross_clamp.left.max = std::min(0x397, max);\n\t\tg_vpad.controller_data[channel].stick_cross_clamp.left.min = std::max(0x102, min);\n\t}\n\n\tvoid VPADSetRStickClampThreshold(sint32 channel, sint32 max, sint32 min)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetRStickClampThreshold({}, {}, {})\", channel, max, min);\n\t\tvpadbreak();\n\t\tg_vpad.controller_data[channel].stick_cross_clamp.right.max = std::min(0x397, max);\n\t\tg_vpad.controller_data[channel].stick_cross_clamp.right.min = std::max(0x102, min);\n\t}\n\n\tvoid VPADGetLStickClampThreshold(sint32 channel, sint32* max, sint32* min)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADGetLStickClampThreshold({}, 0x{:x}, 0x{:x})\", channel, MEMPTR(max).GetMPTR(), MEMPTR(min).GetMPTR());\n\t\tvpadbreak();\n\t\t*max = g_vpad.controller_data[channel].stick_cross_clamp.left.max;\n\t\t*min = g_vpad.controller_data[channel].stick_cross_clamp.left.min;\n\t}\n\n\tvoid VPADGetRStickClampThreshold(sint32 channel, sint32* max, sint32* min)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADGetRStickClampThreshold({}, 0x{:x}, 0x{:x})\", channel, MEMPTR(max).GetMPTR(), MEMPTR(min).GetMPTR());\n\t\tvpadbreak();\n\t\t*max = g_vpad.controller_data[channel].stick_cross_clamp.right.max;\n\t\t*min = g_vpad.controller_data[channel].stick_cross_clamp.right.min;\n\t}\n}\n\n\nvoid vpadExport_VPADGetAccParam(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(playRadius, float32be, 1);\n\tppcDefineParamPtr(sensitivity, float32be, 2);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetAccParam({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\t*playRadius = g_vpadAccParam[channel].playRadius;\n\t\t*sensitivity = g_vpadAccParam[channel].sensitivity;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADSetAccParam(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetAccParam({}, {}, {})\", channel, hCPU->fpr[1].fpr, hCPU->fpr[2].fpr);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tg_vpadAccParam[channel].playRadius = hCPU->fpr[1].fpr;\n\t\tg_vpadAccParam[channel].sensitivity = hCPU->fpr[2].fpr;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetAccPlayMode(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetAccPlayMode({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tosLib_returnFromFunction(hCPU, g_vpadPlayMode[channel]);\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t\tosLib_returnFromFunction(hCPU, VPAD_PLAY_MODE_TIGHT);\n\t}\n}\n\nvoid vpadExport_VPADSetAccPlayMode(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamU32(playMode, 1);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetAccPlayMode({}, {})\", channel, playMode);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tg_vpadPlayMode[channel] = playMode;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADEnableStickCrossClamp(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tcemuLog_log(LogType::InputAPI, \"VPADEnableStickCrossClamp({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tvpadStickClamp[channel].crossMode = true;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADDisableStickCrossClamp(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tcemuLog_log(LogType::InputAPI, \"VPADDisableStickCrossClamp({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tvpadStickClamp[channel].crossMode = false;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADSetLStickClampThreshold(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamS32(maxValue, 1);\n\tppcDefineParamS32(minValue, 2);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetLStickClampThreshold({}, {}, {})\", channel, maxValue, minValue);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tvpadStickClamp[channel].leftMax = std::min(VPAD_MAX_CLAMP, maxValue);\n\t\tvpadStickClamp[channel].leftMin = std::max(VPAD_MIN_CLAMP, minValue);\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADSetRStickClampThreshold(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamS32(maxValue, 1);\n\tppcDefineParamS32(minValue, 2);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetRStickClampThreshold({}, {}, {})\", channel, maxValue, minValue);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tvpadStickClamp[channel].rightMax = std::min(VPAD_MAX_CLAMP, maxValue);\n\t\tvpadStickClamp[channel].rightMin = std::max(VPAD_MIN_CLAMP, minValue);\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetLStickClampThreshold(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(maxValue, uint32be, 1);\n\tppcDefineParamPtr(minValue, uint32be, 2);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetLStickClampThreshold({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\t*maxValue = vpadStickClamp[channel].leftMax;\n\t\t*minValue = vpadStickClamp[channel].leftMin;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetRStickClampThreshold(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(maxValue, uint32be, 1);\n\tppcDefineParamPtr(minValue, uint32be, 2);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetRStickClampThreshold({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\t*maxValue = vpadStickClamp[channel].rightMax;\n\t\t*minValue = vpadStickClamp[channel].rightMin;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADSetCrossStickEmulationParamsL(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetCrossStickEmulationParamsL({}, {}, {}, {})\", channel, hCPU->fpr[1].fpr, hCPU->fpr[2].fpr, hCPU->fpr[3].fpr);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tvpadCrossStickEmulationParams[channel].leftRotation = hCPU->fpr[1].fpr;\n\t\tvpadCrossStickEmulationParams[channel].leftInputRange = hCPU->fpr[2].fpr;\n\t\tvpadCrossStickEmulationParams[channel].leftRadius = hCPU->fpr[3].fpr;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADSetCrossStickEmulationParamsR(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetCrossStickEmulationParamsR({}, {}, {}, {})\", channel, hCPU->fpr[1].fpr, hCPU->fpr[2].fpr, hCPU->fpr[3].fpr);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tvpadCrossStickEmulationParams[channel].rightRotation = hCPU->fpr[1].fpr;\n\t\tvpadCrossStickEmulationParams[channel].rightInputRange = hCPU->fpr[2].fpr;\n\t\tvpadCrossStickEmulationParams[channel].rightRadius = hCPU->fpr[3].fpr;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetCrossStickEmulationParamsL(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(rotation, float32be, 1);\n\tppcDefineParamPtr(inputRange, float32be, 2);\n\tppcDefineParamPtr(radius, float32be, 3);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetCrossStickEmulationParamsL({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\t*rotation = vpadCrossStickEmulationParams[channel].leftRotation;\n\t\t*inputRange = vpadCrossStickEmulationParams[channel].leftInputRange;\n\t\t*radius = vpadCrossStickEmulationParams[channel].leftRadius;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetCrossStickEmulationParamsR(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(rotation, float32be, 1);\n\tppcDefineParamPtr(inputRange, float32be, 2);\n\tppcDefineParamPtr(radius, float32be, 3);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetCrossStickEmulationParamsR({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\t*rotation = vpadCrossStickEmulationParams[channel].rightRotation;\n\t\t*inputRange = vpadCrossStickEmulationParams[channel].rightInputRange;\n\t\t*radius = vpadCrossStickEmulationParams[channel].rightRadius;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetButtonProcMode(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetButtonProcMode({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tosLib_returnFromFunction(hCPU, vpadButtonProcMode[channel]);\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t\tosLib_returnFromFunction(hCPU, VPAD_BUTTON_PROC_MODE_TIGHT);\n\t}\n}\n\nvoid vpadExport_VPADSetButtonProcMode(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamU8(mode, 1);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetButtonProcMode({}, {})\", channel, mode);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tvpadButtonProcMode[channel] = mode;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADSetLcdMode(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamU32(mode, 1);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetLcdMode({}, {})\", channel, mode);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tvpadLcdMode[channel] = mode;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetLcdMode(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamPtr(mode, uint32be, 1);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetLcdMode({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\t*mode = vpadLcdMode[channel];\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADControlMotor(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamUStr(pattern, 1);\n\tppcDefineParamU8(length, 2);\n\tcemuLog_log(LogType::InputAPI, \"VPADControlMotor({}, _, {})\", channel, length);\n\n\tif (length > 120)\n\t{\n\t\tcemuLog_log(LogType::InputAPI, \"VPADControlMotor() - length too high with {} of 120\", length);\n\t\tlength = 120;\n\t}\n\n\tif (const auto controller = InputManager::instance().get_vpad_controller(channel))\n\t{\n\t\t// if length is zero -> stop vibration\n\t\tif (length == 0)\n\t\t{\n\t\t\tcontroller->clear_rumble();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// check for max queue length\n\t\t\tif (!controller->push_rumble(pattern, length))\n\t\t\t{\n\t\t\t\tosLib_returnFromFunction(hCPU, -1); // TODO P: not sure about the exact return value\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADStopMotor(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tcemuLog_log(LogType::InputAPI, \"VPADStopMotor({})\", channel);\n\n\tif (const auto controller = InputManager::instance().get_vpad_controller(channel))\n\t{\n\t\tcontroller->clear_rumble();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADSetTPCalibrationParam(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamMEMPTR(params, VPADTPCalibrationParam, 1);\n\n\tdebugBreakpoint();\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tVPADTPCalibrationParam* calibrationParam = params.GetPtr();\n\n\t\tcemuLog_log(LogType::InputAPI, \"VPADSetTPCalibrationParam({}, {}, {}, {}, {})\", channel, (uint16)calibrationParam->offsetX, (uint16)calibrationParam->offsetX, (float)calibrationParam->scaleX, (float)calibrationParam->scaleY);\n\n\t\tvpadTPCalibrationParam[channel].offsetX = calibrationParam->offsetX;\n\t\tvpadTPCalibrationParam[channel].offsetX = calibrationParam->offsetY;\n\t\tvpadTPCalibrationParam[channel].scaleX = calibrationParam->scaleX;\n\t\tvpadTPCalibrationParam[channel].scaleY = calibrationParam->scaleY;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetTPCalibrationParam(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamStructPtr(calibrationParam, VPADTPCalibrationParam, 1);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetTPCalibrationParam({})\", channel);\n\n\tcalibrationParam->offsetX = vpadTPCalibrationParam[channel].offsetX;\n\tcalibrationParam->offsetY = vpadTPCalibrationParam[channel].offsetY;\n\tcalibrationParam->scaleX = vpadTPCalibrationParam[channel].scaleX;\n\tcalibrationParam->scaleY = vpadTPCalibrationParam[channel].scaleY;\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetTPCalibratedPoint(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamStructPtr(outputDisplay, VPADTPData_t, 1);\n\tppcDefineParamStructPtr(inputRaw, VPADTPData_t, 2);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetTPCalibratedPoint({})\", channel);\n\n\tmemmove(outputDisplay, inputRaw, sizeof(VPADTPData_t));\n\n\t// vpadTPCalibrationParam[channel]\n\n\tsint16 x = outputDisplay->x;\n\tsint16 y = outputDisplay->y;\n\n\tsint32 outputX;\n\tsint32 outputY;\n\t_tpRawToResolution(x, y, &outputX, &outputY, 1280, 720);\n\n\toutputDisplay->x = outputX;\n\toutputDisplay->y = outputY;\n\toutputDisplay->touch = inputRaw->touch;\n\toutputDisplay->validity = inputRaw->validity;\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetTPCalibratedPointEx(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamS32(tpResolution, 1);\n\tppcDefineParamStructPtr(outputDisplay, VPADTPData_t, 2);\n\tppcDefineParamStructPtr(inputRaw, VPADTPData_t, 3);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetTPCalibratedPointEx({})\", channel);\n\n\t//debug_printf(\"TPInput: %d %d %04x %04x\\n\", _swapEndianU16(inputRaw->touch), _swapEndianU16(inputRaw->validity), _swapEndianU16(inputRaw->x), _swapEndianU16(inputRaw->y));\n\tmemmove(outputDisplay, inputRaw, sizeof(VPADTPData_t));\n\n\t//debug_printf(\"VPADGetTPCalibratedPointEx(): Resolution %d\\n\", hCPU->gpr[4]);\n\n\tsint16 x = outputDisplay->x;\n\tsint16 y = outputDisplay->y;\n\n\tsint32 outputX = 0;\n\tsint32 outputY = 0;\n\tif (tpResolution == VPAD_TP_1920x1080)\n\t{\n\t\t_tpRawToResolution(x, y, &outputX, &outputY, 1920, 1080);\n\t}\n\telse if (tpResolution == VPAD_TP_1280x720)\n\t{\n\t\t_tpRawToResolution(x, y, &outputX, &outputY, 1280, 720);\n\t}\n\telse if (tpResolution == VPAD_TP_854x480)\n\t{\n\t\t_tpRawToResolution(x, y, &outputX, &outputY, 854, 480);\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t\tdebug_printf(\"VPADGetTPCalibratedPointEx(): Unsupported tp resolution\\n\");\n\t}\n\toutputDisplay->x = outputX;\n\toutputDisplay->y = outputY;\n\toutputDisplay->touch = inputRaw->touch;\n\toutputDisplay->validity = inputRaw->validity;\n\n\t//debug_printf(\"VPADGetTPCalibratedPointEx %d %d\\n\", _swapEndianU16(outputDisplay->x), _swapEndianU16(outputDisplay->y));\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\n\nvoid vpadExport_VPADSetGyroDirection(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamStructPtr(dir, VPADDir, 1);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetGyroDirection({}, <<{:f}, {:f}, {:f}>, <{:f}, {:f}, {:f}>, <{:f}, {:f}, {:f}>>)\", channel\n\t\t, (float)dir->x.x, (float)dir->x.y, (float)dir->x.z\n\t\t, (float)dir->y.x, (float)dir->y.y, (float)dir->y.z\n\t\t, (float)dir->z.x, (float)dir->z.y, (float)dir->z.z);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tg_vpadGyroDirOverwrite[channel] = *dir;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADGetGyroZeroDriftMode(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamMEMPTR(gyroMode, uint32be, 1);\n\tcemuLog_log(LogType::InputAPI, \"VPADGetGyroZeroDriftMode({})\", channel);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\t*gyroMode = g_vpadGyroZeroDriftMode[channel];\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t\t*gyroMode = VPAD_GYRO_ZERODRIFT_NONE;\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADSetGyroZeroDriftMode(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamU32(gyroMode, 1);\n\tcemuLog_log(LogType::InputAPI, \"VPADSetGyroZeroDriftMode({}, {})\", channel, gyroMode);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tif (gyroMode > VPAD_GYRO_ZERODRIFT_NONE)\n\t\t{\n\t\t\tdebugBreakpoint();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tg_vpadGyroZeroDriftMode[channel] = gyroMode;\n\t\t}\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADSetGyroDirReviseBase(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\tppcDefineParamStructPtr(dir, VPADDir, 1);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tg_vpadGyroDirRevise[channel].vpadGyroDirReviseBase = *dir;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADDisableGyroDirRevise(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tg_vpadGyroDirRevise[channel].enabled = false;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nvoid vpadExport_VPADSetGyroDirReviseParam(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(channel, 0);\n\n\tif (channel < VPAD_MAX_CONTROLLERS)\n\t{\n\t\tg_vpadGyroDirRevise[channel].weight = (float)hCPU->fpr[1].fpr;\n\t}\n\telse\n\t{\n\t\tdebugBreakpoint();\n\t}\n\n\tosLib_returnFromFunction(hCPU, 0);\n}\n\nnamespace vpad\n{\n\tvoid TickFunction(PPCInterpreter_t* hCPU)\n\t{\n\t\t// check if homebutton is pressed\n\t\t// check connection to drc\n\t\tconst auto& instance = InputManager::instance();\n\t\tfor (auto i = 0; i < InputManager::kMaxVPADControllers; ++i)\n\t\t{\n\t\t\tif (!g_vpad.controller_data[i].sampling_callback)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tif(const auto controller = instance.get_vpad_controller(i))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::InputAPI, \"Calling VPADSamplingCallback({})\", i);\n\t\t\t\tPPCCoreCallback(g_vpad.controller_data[i].sampling_callback, i);\n\t\t\t}\n\t\t}\n\n\t\tosLib_returnFromFunction(hCPU, 0);\n\t}\n\n\tvoid start()\n\t{\n\t\tcoreinit::OSCreateAlarm(&g_vpad.alarm);\n\t\tconst uint64 start_tick = coreinit::OSGetTime();\n\t\tconst uint64 period_tick = coreinit::EspressoTime::GetTimerClock() * 5 / 1000;\n\t\tconst MPTR handler = PPCInterpreter_makeCallableExportDepr(TickFunction);\n\t\tcoreinit::OSSetPeriodicAlarm(&g_vpad.alarm, start_tick, period_tick, handler);\n\t}\n\n\tvoid load()\n\t{\n\n\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"vpad\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tcafeExportRegister(\"vpad\", VPADSetBtnRepeat, LogType::InputAPI);\n\t\t\tcafeExportRegister(\"vpad\", VPADSetSamplingCallback, LogType::InputAPI);\n\t\t\tcafeExportRegister(\"vpad\", VPADRead, LogType::InputAPI);\n\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetAccParam\", vpadExport_VPADGetAccParam);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetAccParam\", vpadExport_VPADSetAccParam);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetAccPlayMode\", vpadExport_VPADGetAccPlayMode);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetAccPlayMode\", vpadExport_VPADSetAccPlayMode);\n\n\t\t\tosLib_addFunction(\"vpad\", \"VPADEnableStickCrossClamp\", vpadExport_VPADEnableStickCrossClamp);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADDisableStickCrossClamp\", vpadExport_VPADDisableStickCrossClamp);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetLStickClampThreshold\", vpadExport_VPADSetLStickClampThreshold);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetRStickClampThreshold\", vpadExport_VPADSetRStickClampThreshold);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetLStickClampThreshold\", vpadExport_VPADGetLStickClampThreshold);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetRStickClampThreshold\", vpadExport_VPADGetRStickClampThreshold);\n\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetCrossStickEmulationParamsL\", vpadExport_VPADSetCrossStickEmulationParamsL);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetCrossStickEmulationParamsR\", vpadExport_VPADSetCrossStickEmulationParamsR);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetCrossStickEmulationParamsL\", vpadExport_VPADGetCrossStickEmulationParamsL);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetCrossStickEmulationParamsR\", vpadExport_VPADGetCrossStickEmulationParamsR);\n\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetButtonProcMode\", vpadExport_VPADGetButtonProcMode);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetButtonProcMode\", vpadExport_VPADSetButtonProcMode);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetLcdMode\", vpadExport_VPADGetLcdMode);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetLcdMode\", vpadExport_VPADSetLcdMode);\n\n\t\t\tosLib_addFunction(\"vpad\", \"VPADControlMotor\", vpadExport_VPADControlMotor);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADStopMotor\", vpadExport_VPADStopMotor);\n\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetTPCalibrationParam\", vpadExport_VPADGetTPCalibrationParam);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetTPCalibrationParam\", vpadExport_VPADSetTPCalibrationParam);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetTPCalibratedPoint\", vpadExport_VPADGetTPCalibratedPoint);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetTPCalibratedPointEx\", vpadExport_VPADGetTPCalibratedPointEx);\n\n\t\t\t//osLib_addFunction(\"vpad\", \"VPADRead\", vpadExport_VPADRead);\n\t\t\t//osLib_addFunction(\"vpad\", \"VPADSetSamplingCallback\", vpadExport_VPADSetSamplingCallback);\n\t\t\t//osLib_addFunction(\"vpad\", \"VPADSetBtnRepeat\", vpadExport_VPADSetBtnRepeat);\n\n\t\t\tosLib_addFunction(\"vpad\", \"VPADGetGyroZeroDriftMode\", vpadExport_VPADGetGyroZeroDriftMode);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetGyroDirection\", vpadExport_VPADSetGyroDirection);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetGyroZeroDriftMode\", vpadExport_VPADSetGyroZeroDriftMode);\n\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetGyroDirReviseBase\", vpadExport_VPADSetGyroDirReviseBase);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADDisableGyroDirRevise\", vpadExport_VPADDisableGyroDirRevise);\n\t\t\tosLib_addFunction(\"vpad\", \"VPADSetGyroDirReviseParam\", vpadExport_VPADSetGyroDirReviseParam);\n\t\t};\n\t}s_COSVPADModule;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSVPADModule;\n\t}\n\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/vpad/vpad.h",
    "content": "#pragma once\n\n#include \"Cafe/OS/libs/padscore/padscore.h\"\n#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace vpad\n{\n\tvoid load();\n\tvoid start();\n}\n\n#define VPAD_MAX_CONTROLLERS (2)\n\nstruct BtnRepeat\n{\n\tsint32 delay, pulse;\n};\n\nenum VPADTouchValidity\n{\n\tkTpValid = 0,\n\tkTpInvalidX = 1, // only x invalid\n\tkTpInvalidY = 2, // only y invalid\n\tkTpInvalid = kTpInvalidX | kTpInvalidY,\n};\n\nenum VPADTouchState\n{\n\tkTpTouchOff = 0,\n\tkTpTouchOn = 1,\n};\n\nstruct VPADDir\n{\n\tbeVec3D_t x;\n\tbeVec3D_t y;\n\tbeVec3D_t z;\n\n\tVPADDir() = default;\n\tVPADDir(const beVec3D_t& x, const beVec3D_t& y, const beVec3D_t& z)\n\t\t: x(x), y(y), z(z) {}\n\n};\n\nstatic_assert(sizeof(VPADDir) == 0x24);\n\nstruct VPADTPData_t\n{\n\tuint16be x;\n\tuint16be y;\n\tuint16be touch;\n\tuint16be validity;\n};\n\nstatic_assert(sizeof(VPADTPData_t) == 8);\n\ntypedef struct VPADStatus\n{\n\t/* +0x00 */ uint32be hold;\n\t/* +0x04 */ uint32be trig;\n\t/* +0x08 */ uint32be release;\n\t/* +0x0C */ beVec2D_t leftStick;\n\t/* +0x14 */ beVec2D_t rightStick;\n\t/* +0x1C */ beVec3D_t acc;\n\t/* +0x28 */ float32be accMagnitude;\n\t/* +0x2C */ float32be accAcceleration;\n\t/* +0x30 */ beVec2D_t accXY;\n\t/* +0x38 */ beVec3D_t gyroChange;\n\t/* +0x44 */ beVec3D_t gyroOrientation;\n\t/* +0x50 */ sint8 vpadErr;\n\t/* +0x51 */ uint8 padding1[1];\n\t/* +0x52 */ VPADTPData_t tpData;\n\t/* +0x5A */ VPADTPData_t tpProcessed1;\n\t/* +0x62 */ VPADTPData_t tpProcessed2;\n\t/* +0x6A */\tuint8 padding2[2];\n\t/* +0x6C */ VPADDir dir;\n\t/* +0x90 */ uint8 headphoneStatus;\n\t/* +0x91 */ uint8 padding3[3];\n\t/* +0x94 */ beVec3D_t magnet;\n\t/* +0xA0 */ uint8 slideVolume;\n\t/* +0xA1 */ uint8 batteryLevel;\n\t/* +0xA2 */ uint8 micStatus;\n\t/* +0xA3 */ uint8 slideVolume2;\n\t/* +0xA4 */ uint8 padding4[8];\n}VPADStatus_t;\n\nstatic_assert(sizeof(VPADStatus) == 0xAC);\n\nnamespace vpad\n{\n\tCOSModule* GetModule();\n}\n"
  },
  {
    "path": "src/Cafe/OS/libs/zlib125/zlib125.cpp",
    "content": "#include \"Cafe/OS/common/OSCommon.h\"\n#include \"zlib125.h\"\n#include \"zlib.h\"\n\ntypedef struct {\n\t/* +0x00 */ MEMPTR<uint8>\t\tnext_in;     /* next input byte */\n\t/* +0x04 */ uint32be\t\t\tavail_in;  /* number of bytes available at next_in */\n\t/* +0x08 */ uint32be\t\t\ttotal_in;  /* total number of input bytes read so far */\n\n\t/* +0x0C */ MEMPTR<uint8>\t\tnext_out; /* next output byte should be put there */\n\t/* +0x10 */ uint32be\t\t\tavail_out; /* remaining free space at next_out */\n\t/* +0x14 */ uint32be\t\t\ttotal_out; /* total number of bytes output so far */\n\n\t/* +0x18 */ MEMPTR<char>\t\tmsg;  /* last error message, NULL if no error */\n\t/* +0x1C */ MEMPTR<void>\t\tstate; /* not visible by applications */\n\n\t/* +0x20 */ MEMPTR<void>\t\tzalloc;  /* used to allocate the internal state */\n\t/* +0x24 */ MEMPTR<void>\t\tzfree;   /* used to free the internal state */\n\t/* +0x28 */ MEMPTR<void>\t\topaque;  /* private data object passed to zalloc and zfree */\n\n\t/* +0x2C */ uint32be\t\t\tdata_type;  /* best guess about the data type: binary or text */\n\t/* +0x30 */ uint32be\t\t\tadler;      /* adler32 value of the uncompressed data */\n\t/* +0x34 */ uint32be\t\t\treserved;   /* reserved for future use */\n}z_stream_ppc2;\n\nstatic_assert(sizeof(z_stream_ppc2) == 0x38);\n\nvoidpf zcallocWrapper(voidpf opaque, uInt items, uInt size)\n{\n\tz_stream_ppc2* zstream = (z_stream_ppc2*)opaque;\n\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\thCPU->gpr[3] = zstream->opaque.GetMPTR();\n\thCPU->gpr[4] = items;\n\thCPU->gpr[5] = size;\n\tPPCCore_executeCallbackInternal(zstream->zalloc.GetMPTR());\n\tmemset(memory_getPointerFromVirtualOffset(hCPU->gpr[3]), 0, items*size);\n\treturn memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n}\n\nvoid zcfreeWrapper(voidpf opaque, voidpf baseIndex)\n{\n\tz_stream_ppc2* zstream = (z_stream_ppc2*)opaque;\n\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n\thCPU->gpr[3] = zstream->opaque.GetMPTR();\n\thCPU->gpr[4] = memory_getVirtualOffsetFromPointer(baseIndex);\n\tPPCCore_executeCallbackInternal(zstream->zfree.GetMPTR());\n\treturn;\n}\n\nvoid zlib125_zcalloc(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(opaque, 0);\n\tppcDefineParamU32(items, 1);\n\tppcDefineParamU32(size, 2);\n\n\thCPU->gpr[3] = items*size;\n\thCPU->instructionPointer = gCoreinitData->MEMAllocFromDefaultHeap.GetMPTR();\n}\n\nvoid zlib125_zcfree(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamU32(opaque, 0);\n\tppcDefineParamMPTR(baseIndex, 1);\n\n\thCPU->gpr[3] = baseIndex;\n\thCPU->instructionPointer = gCoreinitData->MEMFreeToDefaultHeap.GetMPTR();\n}\n\nvoid zlib125_setupHostZStream(z_stream_ppc2* input, z_stream* output, bool fixInternalStreamPtr = true)\n{\n\toutput->next_in = input->next_in.GetPtr();\n\toutput->avail_in = (uint32)input->avail_in;\n\toutput->total_in = (uint32)input->total_in;\n\n\toutput->next_out = input->next_out.GetPtr();\n\toutput->avail_out = (uint32)input->avail_out;\n\toutput->total_out = (uint32)input->total_out;\n\n\toutput->msg = input->msg.GetPtr();\n\toutput->state = (internal_state*)input->state.GetPtr();\n\n\toutput->zalloc = zcallocWrapper;\n\toutput->zfree = zcfreeWrapper;\n\toutput->opaque = (void*)input;\n\n\toutput->data_type = input->data_type;\n\toutput->adler = (uint32)input->adler;\n\toutput->reserved = (uint32)input->reserved;\n\n\tif (fixInternalStreamPtr && output->state)\n\t{\n\t\t// in newer zLib versions the internal state has a pointer to the stream at the beginning, we have to update it manually\n\t\t// todo - find better solution\n\t\t(*(void**)(output->state)) = output;\n\t}\n}\n\nvoid zlib125_setupUpdateZStream(z_stream* input, z_stream_ppc2* output)\n{\n\toutput->next_in = input->next_in;\n\toutput->avail_in = (uint32)input->avail_in;\n\toutput->total_in = (uint32)input->total_in;\n\n\toutput->next_out = input->next_out;\n\toutput->avail_out = (uint32)input->avail_out;\n\toutput->total_out = (uint32)input->total_out;\n\n\toutput->msg = input->msg;\n\toutput->state = (void*)input->state;\n\n\toutput->data_type = input->data_type;\n\toutput->adler = input->adler;\n\toutput->reserved = input->reserved;\n\n}\n\nvoid zlib125Export_inflateInit_(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\tppcDefineParamStr(version, 1);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs, false);\n\n\t// setup internal memory allocator if requested\n\tif (zstream->zalloc == nullptr)\n\t\tzstream->zalloc = PPCInterpreter_makeCallableExportDepr(zlib125_zcalloc);\n\tif (zstream->zfree == nullptr)\n\t\tzstream->zfree = PPCInterpreter_makeCallableExportDepr(zlib125_zcfree);\n\n\tsint32 r = inflateInit_(&hzs, version, sizeof(z_stream));\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_inflateInit2_(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\tppcDefineParamS32(windowBits, 1);\n\tppcDefineParamStr(version, 2);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs, false);\n\n\t// setup internal memory allocator if requested\n\tif (zstream->zalloc == nullptr)\n\t\tzstream->zalloc = PPCInterpreter_makeCallableExportDepr(zlib125_zcalloc);\n\tif (zstream->zfree == nullptr)\n\t\tzstream->zfree = PPCInterpreter_makeCallableExportDepr(zlib125_zcfree);\n\n\tsint32 r = inflateInit2_(&hzs, windowBits, version, sizeof(z_stream));\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_inflate(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\tppcDefineParamS32(flushParam, 1);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs);\n\n\tsint32 r = inflate(&hzs, flushParam);\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_inflateEnd(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs);\n\n\tsint32 r = inflateEnd(&hzs);\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_inflateReset(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"inflateReset(0x%08x)\\n\", hCPU->gpr[3]);\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs);\n\n\tsint32 r = inflateReset(&hzs);\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_inflateReset2(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"inflateReset2(0x%08x,0x%08x)\\n\", hCPU->gpr[3], hCPU->gpr[4]);\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\tppcDefineParamS32(windowBits, 1);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs);\n\n\tsint32 r = inflateReset2(&hzs, windowBits);\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_deflateInit_(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\tppcDefineParamS32(level, 1);\n\tppcDefineParamStr(version, 2);\n\tppcDefineParamS32(streamsize, 3);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs, false);\n\n\t// setup internal memory allocator if requested\n\tif (zstream->zalloc == nullptr)\n\t\tzstream->zalloc = PPCInterpreter_makeCallableExportDepr(zlib125_zcalloc);\n\tif (zstream->zfree == nullptr)\n\t\tzstream->zfree = PPCInterpreter_makeCallableExportDepr(zlib125_zcfree);\n\n\tif (streamsize != sizeof(z_stream_ppc2))\n\t\tassert_dbg();\n\n\tsint32 r = deflateInit_(&hzs, level, version, sizeof(z_stream));\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_deflateInit2_(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\tppcDefineParamS32(level, 1);\n\tppcDefineParamS32(method, 2);\n\tppcDefineParamS32(windowBits, 3);\n\tppcDefineParamS32(memLevel, 4);\n\tppcDefineParamS32(strategy, 5);\n\tppcDefineParamStr(version, 6);\n\tppcDefineParamS32(streamsize, 7);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs, false);\n\n\t// setup internal memory allocator if requested\n\tif (zstream->zalloc == nullptr)\n\t\tzstream->zalloc = PPCInterpreter_makeCallableExportDepr(zlib125_zcalloc);\n\tif (zstream->zfree == nullptr)\n\t\tzstream->zfree = PPCInterpreter_makeCallableExportDepr(zlib125_zcfree);\n\n\t// workaround for Splatoon (it allocates a too small buffer for our version of zLib and its zalloc returns NULL)\n\tzstream->zalloc = PPCInterpreter_makeCallableExportDepr(zlib125_zcalloc);\n\tzstream->zfree = PPCInterpreter_makeCallableExportDepr(zlib125_zcfree);\n\n\tif (streamsize != sizeof(z_stream_ppc2))\n\t\tassert_dbg();\n\n\tsint32 r = deflateInit2_(&hzs, level, method, windowBits, memLevel, strategy, version, sizeof(z_stream));\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_deflateBound(PPCInterpreter_t* hCPU)\n{\n\tdebug_printf(\"deflateBound(0x%08x,0x%08x)\\n\", hCPU->gpr[3], hCPU->gpr[4]);\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\tppcDefineParamS32(sourceLen, 1);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs);\n\n\tsint32 r = deflateBound(&hzs, sourceLen);\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_deflate(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\tppcDefineParamS32(flushParam, 1);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs);\n\n\tsint32 r = deflate(&hzs, flushParam);\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_deflateEnd(PPCInterpreter_t* hCPU)\n{\n\tppcDefineParamStructPtr(zstream, z_stream_ppc2, 0);\n\n\tz_stream hzs;\n\tzlib125_setupHostZStream(zstream, &hzs);\n\n\tsint32 r = deflateEnd(&hzs);\n\n\tzlib125_setupUpdateZStream(&hzs, zstream);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_uncompress(PPCInterpreter_t* hCPU)\n{\n\t// Bytef * dest, uLongf * destLen, const Bytef * source, uLong sourceLen\n\tuint8* memDst = memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\tuint8* memSrc = memory_getPointerFromVirtualOffset(hCPU->gpr[5]);\n\tuint32* pDestLenBE = (uint32*)memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\tuint32 sourceLen = hCPU->gpr[6];\n\tuLong destLen = _swapEndianU32(*pDestLenBE);\n\tsint32 r = uncompress(memDst, &destLen, memSrc, sourceLen);\n\t*pDestLenBE = _swapEndianU32(destLen);\n\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_compress(PPCInterpreter_t* hCPU)\n{\n\t// Bytef* dest, uLongf* destLen, const Bytef* source, uLong sourceLen\n\tuint8* memDst = memory_getPointerFromVirtualOffset(hCPU->gpr[3]);\n\tuint8* memSrc = memory_getPointerFromVirtualOffset(hCPU->gpr[5]);\n\tuint32* pDestLenBE = (uint32*)memory_getPointerFromVirtualOffset(hCPU->gpr[4]);\n\tuint32 sourceLen = hCPU->gpr[6];\n\tuLong destLen = _swapEndianU32(*pDestLenBE);\n\tsint32 r = compress(memDst, &destLen, memSrc, sourceLen);\n\t*pDestLenBE = _swapEndianU32(destLen);\n\tosLib_returnFromFunction(hCPU, r);\n}\n\nvoid zlib125Export_crc32(PPCInterpreter_t* hCPU)\n{\n\tuint32 crc = hCPU->gpr[3];\n\tuint8* buf = (uint8*)memory_getPointerFromVirtualOffsetAllowNull(hCPU->gpr[4]);\n\tuint32 len = hCPU->gpr[5];\n\n\tuint32 crcResult = crc32(crc, buf, len);\n\n\tosLib_returnFromFunction(hCPU, crcResult);\n}\n\nvoid zlib125Export_compressBound(PPCInterpreter_t* hCPU)\n{\n\tuint32 result = compressBound(hCPU->gpr[3]);\n\tosLib_returnFromFunction(hCPU, result);\n}\n\nnamespace zlib\n{\n\tvoid load()\n\t{\n\n\t}\n\n\tclass : public COSModule\n\t{\n\t\tpublic:\n\t\tstd::string_view GetName() override\n\t\t{\n\t\t\treturn \"zlib125\";\n\t\t}\n\n\t\tvoid RPLMapped() override\n\t\t{\n\t\t\tosLib_addFunction(\"zlib125\", \"inflateInit2_\", zlib125Export_inflateInit2_);\n\t\t\tosLib_addFunction(\"zlib125\", \"inflateInit_\", zlib125Export_inflateInit_);\n\t\t\tosLib_addFunction(\"zlib125\", \"inflateEnd\", zlib125Export_inflateEnd);\n\t\t\tosLib_addFunction(\"zlib125\", \"inflate\", zlib125Export_inflate);\n\t\t\tosLib_addFunction(\"zlib125\", \"inflateReset\", zlib125Export_inflateReset);\n\t\t\tosLib_addFunction(\"zlib125\", \"inflateReset2\", zlib125Export_inflateReset2);\n\n\t\t\tosLib_addFunction(\"zlib125\", \"deflateInit_\", zlib125Export_deflateInit_);\n\t\t\tosLib_addFunction(\"zlib125\", \"deflateInit2_\", zlib125Export_deflateInit2_);\n\t\t\tosLib_addFunction(\"zlib125\", \"deflateBound\", zlib125Export_deflateBound);\n\t\t\tosLib_addFunction(\"zlib125\", \"deflate\", zlib125Export_deflate);\n\t\t\tosLib_addFunction(\"zlib125\", \"deflateEnd\", zlib125Export_deflateEnd);\n\n\t\t\tosLib_addFunction(\"zlib125\", \"uncompress\", zlib125Export_uncompress);\n\t\t\tosLib_addFunction(\"zlib125\", \"compress\", zlib125Export_compress);\n\n\t\t\tosLib_addFunction(\"zlib125\", \"crc32\", zlib125Export_crc32);\n\t\t\tosLib_addFunction(\"zlib125\", \"compressBound\", zlib125Export_compressBound);\n\t\t};\n\n\t}s_COSZlib125Module;\n\n\tCOSModule* GetModule()\n\t{\n\t\treturn &s_COSZlib125Module;\n\t}\n}"
  },
  {
    "path": "src/Cafe/OS/libs/zlib125/zlib125.h",
    "content": "#include \"Cafe/OS/RPL/COSModule.h\"\n\nnamespace zlib\n{\n\tvoid load();\n\n\tCOSModule* GetModule();\n}"
  },
  {
    "path": "src/Cafe/TitleList/AppType.h",
    "content": "#pragma once\n\nenum class APP_TYPE : uint32\n{\n\tGAME = 0x80000000,\n\tGAME_UPDATE = 0x0800001B,\n\tGAME_DLC = 0x0800000E,\n\t// data titles\n\tVERSION_DATA_TITLE = 0x10000015,\n\tDRC_FIRMWARE = 0x10000013,\n\tDRC_TEXTURE_ATLAS = 0x1000001A,\n};\n\n// allow direct comparison with uint32\ninline bool operator==(APP_TYPE lhs, uint32 rhs)\n{\n\treturn static_cast<uint32>(lhs) == rhs;\n}\n\ninline bool operator==(uint32 lhs, APP_TYPE rhs)\n{\n\treturn lhs == static_cast<uint32>(rhs);\n}\n"
  },
  {
    "path": "src/Cafe/TitleList/GameInfo.h",
    "content": "#pragma once\n\n#include \"config/CemuConfig.h\"\n#include \"TitleInfo.h\"\n#include \"config/ActiveSettings.h\"\n\nclass GameInfo2\n{\npublic:\n\t~GameInfo2()\n\t{\n\t\tm_base.UnmountAll();\n\t\tm_update.UnmountAll();\n\t\tfor (auto& it : m_aoc)\n\t\t\tit.UnmountAll();\n\t}\n\n\tbool IsValid() const\n\t{\n\t\treturn m_base.IsValid(); // at least the base must be valid for this to be a runnable title\n\t}\n\n\tbool IsSystemDataTitle() const\n\t{\n\t\treturn m_base.IsSystemDataTitle();\n\t}\n\n\tvoid SetBase(const TitleInfo& titleInfo)\n\t{\n\t\tif (IsPrioritizedVersionOrFormat(m_base, titleInfo))\n\t\t\tm_base = titleInfo;\n\t}\n\n\tvoid SetUpdate(const TitleInfo& titleInfo)\n\t{\n\t\tif (IsPrioritizedVersionOrFormat(m_update, titleInfo))\n\t\t\tm_update = titleInfo;\n\t}\n\n\tbool HasUpdate() const\n\t{\n\t\treturn m_update.IsValid();\n\t}\n\n\tvoid AddAOC(const TitleInfo& titleInfo)\n\t{\n\t\tTitleId aocTitleId = titleInfo.GetAppTitleId();\n\t\tuint16 aocVersion = titleInfo.GetAppTitleVersion();\n\t\tauto it = std::find_if(m_aoc.begin(), m_aoc.end(), [aocTitleId](const TitleInfo& rhs) { return rhs.GetAppTitleId() == aocTitleId; });\n\t\tif (it != m_aoc.end())\n\t\t{\n\t\t\tif (!IsPrioritizedVersionOrFormat(*it, titleInfo))\n\t\t\t\treturn;\n\t\t\tm_aoc.erase(it);\n\t\t}\n\t\tm_aoc.emplace_back(titleInfo);\n\t}\n\n\tbool HasAOC() const\n\t{\n\t\treturn !m_aoc.empty();\n\t}\n\n\tTitleInfo& GetBase()\n\t{\n\t\treturn m_base;\n\t}\n\n\tTitleInfo& GetUpdate()\n\t{\n\t\treturn m_update;\n\t}\n\n\tstd::span<TitleInfo> GetAOC()\n\t{\n\t\treturn m_aoc;\n\t}\n\n\tTitleId GetBaseTitleId()\n\t{\n\t\tcemu_assert_debug(m_base.IsValid());\n\t\treturn m_base.GetAppTitleId();\n\t}\n\n\tstd::string GetTitleName()\n\t{\n\t\tcemu_assert_debug(m_base.IsValid());\n\t\treturn m_base.GetMetaTitleName(); // long name\n\t}\n\n\tuint16 GetVersion() const\n\t{\n\t\tif (m_update.IsValid())\n\t\t\treturn m_update.GetAppTitleVersion();\n\t\treturn m_base.GetAppTitleVersion();\n\t}\n\n\tuint32 GetSDKVersion() const\n\t{\n\t\tif (m_update.IsValid())\n\t\t\treturn m_update.GetAppSDKVersion();\n\t\treturn m_base.GetAppSDKVersion();\n\t}\n\n\tCafeConsoleRegion GetRegion() const\n\t{\n\t\tif (m_update.IsValid())\n\t\t\treturn m_update.GetMetaRegion();\n\t\treturn m_base.GetMetaRegion();\n\t}\n\n\tuint16 GetAOCVersion() const\n\t{\n\t\tif (m_aoc.empty())\n\t\t\treturn 0;\n\t\treturn m_aoc.front().GetAppTitleVersion();\n\t}\n\n\tfs::path GetSaveFolder()\n\t{\n\t\treturn ActiveSettings::GetMlcPath(fmt::format(\"usr/save/{:08x}/{:08x}\", (GetBaseTitleId() >> 32), GetBaseTitleId() & 0xFFFFFFFF));\n\t}\n\nprivate:\n  \tbool IsPrioritizedVersionOrFormat(const TitleInfo& currentTitle, const TitleInfo& newTitle)\n\t{\n\t\tif (!currentTitle.IsValid())\n\t\t\treturn true; // always prefer a valid title over an invalid one\n\t\t// always prefer higher version\n\t\tif (newTitle.GetAppTitleVersion() > currentTitle.GetAppTitleVersion())\n\t\t\treturn true;\n\t\t// never prefer lower version\n\t\tif (newTitle.GetAppTitleVersion() < currentTitle.GetAppTitleVersion())\n\t\t\treturn false;\n\t\t// for users which have both NUS and non-NUS titles in their games folder we want to prioritize non-NUS formats\n\t\t// this is to stay consistent with previous Cemu versions which did not support NUS format at all\n\t\tTitleInfo::TitleDataFormat currentFormat = currentTitle.GetFormat();\n\t\tTitleInfo::TitleDataFormat newFormat = newTitle.GetFormat();\n\t\tif (currentFormat != TitleInfo::TitleDataFormat::NUS && newFormat == TitleInfo::TitleDataFormat::NUS)\n\t\t\treturn false;\n\t\treturn true;\n\t};\n\n\tTitleInfo m_base;\n\tTitleInfo m_update;\n\tstd::vector<TitleInfo> m_aoc;\n};"
  },
  {
    "path": "src/Cafe/TitleList/ParsedMetaXml.h",
    "content": "#pragma once\n\n#include <pugixml.hpp>\n#include \"config/CemuConfig.h\"\n\nstruct ParsedMetaXml\n{\n\tuint32 m_version;\n\tstd::string m_product_code;\n\tstd::string m_company_code;\n\tstd::string m_content_platform;\n\tuint64 m_title_id;\n\tCafeConsoleRegion m_region;\n\n\tstd::array<std::string, 12> m_long_name;\n\tstd::array<std::string, 12> m_short_name;\n\tstd::array<std::string, 12> m_publisher;\n\n\tuint32 m_olv_accesskey;\n\n\tstd::string GetShortName(CafeConsoleLanguage languageId) const\n\t{\n\t\treturn m_short_name[(size_t)languageId].empty() ? m_short_name[(size_t)CafeConsoleLanguage::EN] : m_short_name[(size_t)languageId];\n\t}\n\n\tstd::string GetLongName(CafeConsoleLanguage languageId) const\n\t{\n\t\treturn m_long_name[(size_t)languageId].empty() ? m_long_name[(size_t)CafeConsoleLanguage::EN] : m_long_name[(size_t)languageId];\n\t}\n\n\tTitleId GetTitleId() const\n\t{\n\t\treturn m_title_id;\n\t}\n\n\tuint16 GetTitleVersion() const\n\t{\n\t\treturn (uint16)m_version;\n\t}\n\n\tCafeConsoleRegion GetRegion() const\n\t{\n\t\treturn m_region;\n\t}\n\n\tstd::string GetProductCode() const\n\t{\n\t\treturn m_product_code;\n\t}\n\n\tstd::string GetCompanyCode() const\n\t{\n\t\treturn m_company_code;\n\t}\n\n\tuint32 GetOlvAccesskey() const\n\t{\n\t\treturn m_olv_accesskey;\n\t}\n\n\tstatic ParsedMetaXml* Parse(uint8* xmlData, size_t xmlSize)\n\t{\n\t\tif (xmlSize == 0)\n\t\t\treturn nullptr;\n\t\tpugi::xml_document meta_doc;\n\t\tif (!meta_doc.load_buffer_inplace(xmlData, xmlSize))\n\t\t\treturn nullptr;\n\n\t\tconst auto root = meta_doc.child(\"menu\");\n\t\tif (!root)\n\t\t\treturn nullptr;\n\n\t\tParsedMetaXml* parsedMetaXml = new ParsedMetaXml();\n\n\t\tfor (const auto& child : root.children())\n\t\t{\n\t\t\tstd::string_view name = child.name();\n\t\t\tif (name == \"title_version\")\n\t\t\t\tparsedMetaXml->m_version = child.text().as_uint();\n\t\t\telse if (name == \"product_code\")\n\t\t\t\tparsedMetaXml->m_product_code = child.text().as_string();\n\t\t\telse if (name == \"company_code\")\n\t\t\t\tparsedMetaXml->m_company_code = child.text().as_string();\n\t\t\telse if (name == \"content_platform\")\n\t\t\t\tparsedMetaXml->m_content_platform = child.text().as_string();\n\t\t\telse if (name == \"title_id\")\n\t\t\t\tparsedMetaXml->m_title_id = std::stoull(child.text().as_string(), nullptr, 16);\n\t\t\telse if (name == \"region\")\n\t\t\t\tparsedMetaXml->m_region = (CafeConsoleRegion)child.text().as_uint();\n\t\t\telse if (boost::starts_with(name, \"longname_\"))\n\t\t\t{\n\t\t\t\tconst sint32 index = GetLanguageIndex(name.substr(std::size(\"longname_\") - 1));\n\t\t\t\tif (index != -1){\n\t\t\t\t\tstd::string longname = child.text().as_string();\n\t\t\t\t\tstd::replace_if(longname.begin(), longname.end(), [](char c) { return c == '\\r' || c == '\\n';}, ' ');\n\t\t\t\t\tparsedMetaXml->m_long_name[index] = longname;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (boost::starts_with(name, L\"shortname_\"))\n\t\t\t{\n\t\t\t\tconst sint32 index = GetLanguageIndex(name.substr(std::size(\"shortname_\") - 1));\n\t\t\t\tif (index != -1)\n\t\t\t\t\tparsedMetaXml->m_short_name[index] = child.text().as_string();\n\t\t\t}\n\t\t\telse if (boost::starts_with(name, L\"publisher_\"))\n\t\t\t{\n\t\t\t\tconst sint32 index = GetLanguageIndex(name.substr(std::size(\"publisher_\") - 1));\n\t\t\t\tif (index != -1)\n\t\t\t\t\tparsedMetaXml->m_publisher[index] = child.text().as_string();\n\t\t\t}\n\t\t\telse if (boost::starts_with(name, L\"olv_accesskey\"))\n\t\t\t\tparsedMetaXml->m_olv_accesskey = child.text().as_uint(-1);\n\t\t}\n\t\tif (parsedMetaXml->m_title_id == 0)\n\t\t{\n\t\t\t// not valid\n\t\t\tdelete parsedMetaXml;\n\t\t\treturn nullptr;\n\t\t}\n\t\treturn parsedMetaXml;\n\t}\n\nprivate:\n\tstatic sint32 GetLanguageIndex(std::string_view language) // move to NCrypto ?\n\t{\n\t\tif (language == \"ja\")\n\t\t\treturn (sint32)CafeConsoleLanguage::JA;\n\t\telse if (language == \"en\")\n\t\t\treturn (sint32)CafeConsoleLanguage::EN;\n\t\telse if (language == \"fr\")\n\t\t\treturn (sint32)CafeConsoleLanguage::FR;\n\t\telse if (language == \"de\")\n\t\t\treturn (sint32)CafeConsoleLanguage::DE;\n\t\telse if (language == \"it\")\n\t\t\treturn (sint32)CafeConsoleLanguage::IT;\n\t\telse if (language == \"es\")\n\t\t\treturn (sint32)CafeConsoleLanguage::ES;\n\t\telse if (language == \"zhs\")\n\t\t\treturn (sint32)CafeConsoleLanguage::ZH;\n\t\telse if (language == \"ko\")\n\t\t\treturn (sint32)CafeConsoleLanguage::KO;\n\t\telse if (language == \"nl\")\n\t\t\treturn (sint32)CafeConsoleLanguage::NL;\n\t\telse if (language == \"pt\")\n\t\t\treturn (sint32)CafeConsoleLanguage::PT;\n\t\telse if (language == \"ru\")\n\t\t\treturn (sint32)CafeConsoleLanguage::RU;\n\t\telse if (language == \"zht\")\n\t\t\treturn (sint32)CafeConsoleLanguage::TW; // if return ZH here, xxx_zht values may cover xxx_zh values in function Parse()\n\t\treturn -1;\n\t}\n};\n"
  },
  {
    "path": "src/Cafe/TitleList/SaveInfo.cpp",
    "content": "#include \"SaveInfo.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Common/FileStream.h\"\n#include \"ParsedMetaXml.h\"\n\nSaveInfo::SaveInfo(TitleId titleId) : m_titleId(titleId)\n{\n\tm_path = GetSavePath(titleId);\n\tstd::error_code ec;\n\tm_isValid = fs::is_directory(m_path, ec);\n}\n\nstd::string SaveInfo::GetStorageSubpathByTitleId(TitleId titleId)\n{\n\t// usr/save/<titleIdHigh>/<titleIdLow>/\n\treturn fmt::format(\"usr/save/{:08x}/{:08x}\", ((uint64)titleId) >> 32, (uint64)titleId & 0xFFFFFFFF);\n}\n\nfs::path SaveInfo::GetSavePath(TitleId titleId)\n{\n\treturn ActiveSettings::GetMlcPath(GetStorageSubpathByTitleId(titleId));\n}\n\nbool SaveInfo::ParseMetaData()\n{\n\tif (m_hasMetaLoaded)\n\t\treturn m_parsedMetaXml != nullptr;\n\tm_hasMetaLoaded = true;\n\tauto xmlData = FileStream::LoadIntoMemory(m_path / \"meta/meta.xml\");\n\tif (!xmlData)\n\t\treturn false;\n\tm_parsedMetaXml = ParsedMetaXml::Parse(xmlData->data(), xmlData->size());\n\treturn m_parsedMetaXml != nullptr;\n}"
  },
  {
    "path": "src/Cafe/TitleList/SaveInfo.h",
    "content": "#pragma once\n\n#include \"TitleId.h\"\n#include \"ParsedMetaXml.h\"\n\nclass SaveInfo\n{\npublic:\n\tSaveInfo() {};\n\tSaveInfo(TitleId titleId);\n\n\tbool IsValid() const { return m_isValid; }\n\n\tTitleId GetTitleId() const { return m_titleId; }\n\tfs::path GetPath() const { return m_path; }\n\n\t// meta data\n\tbool ParseMetaData();\n\tParsedMetaXml* GetMetaInfo() { return m_parsedMetaXml; }\n\nprivate:\n\tstatic std::string GetStorageSubpathByTitleId(TitleId titleId);\n\tstatic fs::path GetSavePath(TitleId titleId);\n\n\tTitleId m_titleId;\n\tfs::path m_path;\n\tbool m_isValid{false};\n\tbool m_hasMetaLoaded{false};\n\tParsedMetaXml* m_parsedMetaXml{nullptr};\n};"
  },
  {
    "path": "src/Cafe/TitleList/SaveList.cpp",
    "content": "#include \"SaveList.h\"\n#include <charconv>\n#include <util/helpers/helpers.h>\n\nstd::mutex sSLMutex;\nfs::path sSLMLCPath;\n\nstd::vector<SaveInfo*> sSLList;\n\n// callback list\nstruct SaveListCallbackEntry\n{\n\tSaveListCallbackEntry(void(*cb)(CafeSaveListCallbackEvent* evt, void* ctx), void* ctx, uint64 uniqueId) :\n\t\tcb(cb), ctx(ctx), uniqueId(uniqueId) {};\n\tvoid (*cb)(CafeSaveListCallbackEvent* evt, void* ctx);\n\tvoid* ctx;\n\tuint64 uniqueId;\n};\nstd::vector<SaveListCallbackEntry> sSLCallbackList;\n\n// worker thread\nstd::atomic_bool sSLWorkerThreadActive{false};\n\n\nvoid CafeSaveList::Initialize()\n{\n\n}\n\nvoid CafeSaveList::SetMLCPath(fs::path mlcPath)\n{\n\tstd::unique_lock _lock(sSLMutex);\n\tsSLMLCPath = mlcPath;\n}\n\nvoid CafeSaveList::Refresh()\n{\n\tstd::unique_lock _lock(sSLMutex);\n\tif (sSLWorkerThreadActive)\n\t\treturn;\n\tsSLWorkerThreadActive = true;\n\tstd::thread t(RefreshThreadWorker);\n\tt.detach();\n}\n\nvoid CafeSaveList::RefreshThreadWorker()\n{\n\tSetThreadName(\"SaveListWorker\");\n\t// clear save list\n\tfor (auto& itSaveInfo : sSLList)\n\t{\n\t\tfor (auto& it : sSLCallbackList)\n\t\t{\n\t\t\tCafeSaveListCallbackEvent evt;\n\t\t\tevt.eventType = CafeSaveListCallbackEvent::TYPE::SAVE_REMOVED;\n\t\t\tevt.saveInfo = itSaveInfo;\n\t\t\tit.cb(&evt, it.ctx);\n\t\t}\n\t\tdelete itSaveInfo;\n\t}\n\tsSLList.clear();\n\n\tsSLMutex.lock();\n\tfs::path mlcPath = sSLMLCPath;\n\tsSLMutex.unlock();\n\tstd::error_code ec;\n\tfor (auto it_titleHigh : fs::directory_iterator(mlcPath / \"usr/save\", ec))\n\t{\n\t\tif(!it_titleHigh.is_directory(ec))\n\t\t\tcontinue;\n\t\tstd::string dirName = _pathToUtf8(it_titleHigh.path().filename());\n\t\tif(dirName.empty())\n\t\t\tcontinue;\t\t\n\t\tuint32 titleIdHigh;\n\t\tstd::from_chars_result r = std::from_chars(dirName.data(), dirName.data() + dirName.size(), titleIdHigh, 16);\n\t\tif (r.ec != std::errc())\n\t\t\tcontinue;\n\t\tfs::path tmp = it_titleHigh.path();\n\t\tfor (auto it_titleLow : fs::directory_iterator(tmp, ec))\n\t\t{\n\t\t\tif (!it_titleLow.is_directory(ec))\n\t\t\t\tcontinue;\n\t\t\tdirName = _pathToUtf8(it_titleLow.path().filename());\n\t\t\tif (dirName.empty())\n\t\t\t\tcontinue;\n\t\t\tuint32 titleIdLow;\n\t\t\tstd::from_chars_result r = std::from_chars(dirName.data(), dirName.data() + dirName.size(), titleIdLow, 16);\n\t\t\tif (r.ec != std::errc())\n\t\t\t\tcontinue;\n\t\t\t// found save\n\t\t\tTitleId titleId = (uint64)titleIdHigh << 32 | (uint64)titleIdLow;\n\t\t\tSaveInfo* saveInfo = new SaveInfo(titleId);\n\t\t\tif (saveInfo->IsValid())\n\t\t\t\tDiscoveredSave(saveInfo);\n\t\t\telse\n\t\t\t\tdelete saveInfo;\n\t\t}\n\t}\n\tsSLMutex.lock();\n\tsSLWorkerThreadActive = false;\n\tsSLMutex.unlock();\n\t// send notification about finished scan\n\tfor (auto& it : sSLCallbackList)\n\t{\n\t\tCafeSaveListCallbackEvent evt;\n\t\tevt.eventType = CafeSaveListCallbackEvent::TYPE::SCAN_FINISHED;\n\t\tevt.saveInfo = nullptr;\n\t\tit.cb(&evt, it.ctx);\n\t}\n}\n\nvoid CafeSaveList::DiscoveredSave(SaveInfo* saveInfo)\n{\n\tif (!saveInfo->ParseMetaData())\n\t{\n\t\tdelete saveInfo;\n\t\treturn;\n\t}\n\tstd::unique_lock _lock(sSLMutex);\n\tauto it = std::find_if(sSLList.begin(), sSLList.end(), [saveInfo](const SaveInfo* rhs) { return saveInfo->GetTitleId() == rhs->GetTitleId(); });\n\tif (it != sSLList.end())\n\t{\n\t\t// save already known\n\t\tdelete saveInfo;\n\t\treturn;\n\t}\n\tsSLList.emplace_back(saveInfo);\n\t// send notification\n\tfor (auto& it : sSLCallbackList)\n\t{\n\t\tCafeSaveListCallbackEvent evt;\n\t\tevt.eventType = CafeSaveListCallbackEvent::TYPE::SAVE_DISCOVERED;\n\t\tevt.saveInfo = saveInfo;\n\t\tit.cb(&evt, it.ctx);\n\t}\n}\n\nuint64 CafeSaveList::RegisterCallback(void(*cb)(CafeSaveListCallbackEvent* evt, void* ctx), void* ctx)\n{\n\tstatic std::atomic<uint64_t> sCallbackIdGen = 1;\n\tuint64 id = sCallbackIdGen.fetch_add(1);\n\tstd::unique_lock _lock(sSLMutex);\n\tsSLCallbackList.emplace_back(cb, ctx, id);\n\t// immediately notify of all known titles\n\tfor (auto& it : sSLList)\n\t{\n\t\tCafeSaveListCallbackEvent evt;\n\t\tevt.eventType = CafeSaveListCallbackEvent::TYPE::SAVE_DISCOVERED;\n\t\tevt.saveInfo = it;\n\t\tcb(&evt, ctx);\n\t}\n\t// if not scanning then send out scan finished notification\n\tif (!sSLWorkerThreadActive)\n\t{\n\t\tCafeSaveListCallbackEvent evt;\n\t\tevt.eventType = CafeSaveListCallbackEvent::TYPE::SCAN_FINISHED;\n\t\tevt.saveInfo = nullptr;\n\t\tfor (auto& it : sSLCallbackList)\n\t\t\tit.cb(&evt, it.ctx);\n\t}\n\treturn id;\n}\n\nvoid CafeSaveList::UnregisterCallback(uint64 id)\n{\n\tstd::unique_lock _lock(sSLMutex);\n\tauto it = std::find_if(sSLCallbackList.begin(), sSLCallbackList.end(), [id](auto& e) { return e.uniqueId == id; });\n\tcemu_assert(it != sSLCallbackList.end());\n\tsSLCallbackList.erase(it);\n}\n\nSaveInfo CafeSaveList::GetSaveByTitleId(TitleId titleId)\n{\n\tstd::unique_lock _lock(sSLMutex);\n\tfor (auto& it : sSLList)\n\t\tif (it->GetTitleId() == titleId)\n\t\t\treturn *it;\n\treturn {};\n}"
  },
  {
    "path": "src/Cafe/TitleList/SaveList.h",
    "content": "#pragma once\n\n#include \"SaveInfo.h\"\n\nstruct CafeSaveListCallbackEvent\n{\n\tenum class TYPE\n\t{\n\t\tSAVE_DISCOVERED,\n\t\tSAVE_REMOVED,\n\t\tSCAN_FINISHED,\n\t};\n\tTYPE eventType;\n\tSaveInfo* saveInfo;\n};\n\nclass CafeSaveList\n{\npublic:\n\tstatic void Initialize();\n\tstatic void SetMLCPath(fs::path mlcPath);\n\tstatic void Refresh();\n\n\tstatic SaveInfo GetSaveByTitleId(TitleId titleId);\n\n\t// callback\n\tstatic uint64 RegisterCallback(void(*cb)(CafeSaveListCallbackEvent* evt, void* ctx), void* ctx); // on register, the callback will be invoked for every already known save\n\tstatic void UnregisterCallback(uint64 id);\n\nprivate:\n\tstatic void RefreshThreadWorker();\n\tstatic void DiscoveredSave(SaveInfo* saveInfo);\n};"
  },
  {
    "path": "src/Cafe/TitleList/TitleId.h",
    "content": "#pragma once\n\nusing TitleId = uint64;\n\nstatic_assert(sizeof(TitleId) == 8);\n\nclass TitleIdParser\n{\npublic:\n\tenum class TITLE_TYPE\n\t{\n\t\t/* XX */ UNKNOWN = 0xFF, // placeholder\n\t\t/* 00 */ BASE_TITLE = 0x00, // eShop and disc titles\n\t\t/* 02 */ BASE_TITLE_DEMO = 0x02,\n\t\t/* 0E */ BASE_TITLE_UPDATE = 0x0E, // update for BASE_TITLE (and maybe BASE_TITLE_DEMO?)\n\t\t/* 0F */ HOMEBREW = 0x0F,\n\t\t/* 0C */ AOC = 0x0C, // DLC\n\t\t/* 10 */ SYSTEM_TITLE = 0x10, // eShop etc\n\t\t/* 1B */ SYSTEM_DATA = 0x1B,\n\t\t/* 30 */ SYSTEM_OVERLAY_TITLE = 0x30,\n\t};\n\n\tTitleIdParser(uint64 titleId) : m_titleId(titleId) {};\n\n\t// controls whether this title installs to /usr/title or /sys/title\n\tbool IsSystemTitle() const \n\t{\n\t\treturn (GetTypeByte() & 0x10) != 0;\n\t};\n\n\tbool IsBaseTitleUpdate() const\n\t{\n\t\treturn GetType() == TITLE_TYPE::BASE_TITLE_UPDATE;\n\t}\n\n\tTITLE_TYPE GetType() const\n\t{\n\t\tuint8 b = GetTypeByte();\n\t\tswitch (b)\n\t\t{\n\t\tcase 0x00:\n\t\t\treturn TITLE_TYPE::BASE_TITLE;\n\t\tcase 0x02:\n\t\t\treturn TITLE_TYPE::BASE_TITLE_DEMO;\n\t\tcase 0x0E:\n\t\t\treturn TITLE_TYPE::BASE_TITLE_UPDATE;\n\t\tcase 0x0F:\n\t\t\treturn TITLE_TYPE::HOMEBREW;\n\t\tcase 0x0C:\n\t\t\treturn TITLE_TYPE::AOC;\n\t\tcase 0x10:\n\t\t\treturn TITLE_TYPE::SYSTEM_TITLE;\n\t\tcase 0x1B:\n\t\t\treturn TITLE_TYPE::SYSTEM_DATA;\n\t\tcase 0x30:\n\t\t\treturn TITLE_TYPE::SYSTEM_OVERLAY_TITLE;\n\t\t}\n\t\tcemuLog_log(LogType::Force, \"Unknown title type ({0:016x})\", m_titleId);\n\t\treturn TITLE_TYPE::UNKNOWN;\n\t}\n\n\tbool IsPlatformCafe() const\n\t{\n\t\treturn GetPlatformWord() == 0x0005;\n\t}\n\n\tbool CanHaveSeparateUpdateTitleId() const\n\t{\n\t\treturn GetType() == TITLE_TYPE::BASE_TITLE;\n\t}\n\n\tTitleId GetSeparateUpdateTitleId() const\n\t{\n\t\tcemu_assert_debug(CanHaveSeparateUpdateTitleId());\n\t\treturn MakeTitleIdWithType(TITLE_TYPE::BASE_TITLE_UPDATE); // e.g. 00050000-11223344 -> 0005000E-11223344\n\t}\n\n\tstatic TitleId MakeBaseTitleId(TitleId titleId)\n\t{\n\t\tTitleIdParser titleIdParser(titleId);\n\t\tif (titleIdParser.GetType() == TITLE_TYPE::BASE_TITLE_UPDATE)\n\t\t\treturn titleIdParser.MakeTitleIdWithType(TITLE_TYPE::BASE_TITLE);\n\t\treturn titleId;\n\t}\n\n\tstatic bool ParseFromStr(std::string_view strView, TitleId& titleIdOut)\n\t{\n\t\tif (strView.size() < 16)\n\t\t\treturn false;\n\t\tuint64 tmp = 0;\n\t\tfor (size_t i = 0; i < 8*2; i++)\n\t\t{\n\t\t\ttmp <<= 4;\n\t\t\tchar c = strView[i];\n\t\t\tif (c >= 'A' && c <= 'F')\n\t\t\t\ttmp += (uint64)(c - 'A' + 10);\n\t\t\telse if (c >= 'a' && c <= 'f')\n\t\t\t\ttmp += (uint64)(c - 'a' + 10);\n\t\t\telse if (c >= '0' && c <= '9')\n\t\t\t\ttmp += (uint64)(c - '0');\n\t\t\telse\n\t\t\t\treturn false;\n\t\t}\n\t\ttitleIdOut = tmp;\n\t\treturn true;\n\t}\n\nprivate:\n\tuint8 GetTypeByte() const\n\t{\n\t\treturn (m_titleId >> 32) & 0xFF;\n\t}\n\n\tTitleId MakeTitleIdWithType(TITLE_TYPE newType) const\n\t{\n\t\tTitleId t = m_titleId;\n\t\tt &= ~(0xFFull << 32);\n\t\tt |= ((uint64)newType << 32);\n\t\treturn t;\n\t}\n\n\tuint16 GetPlatformWord() const // might not be a whole word?\n\t{\n\t\treturn (m_titleId >> 48) & 0xFFFF;\n\t}\n\n\tTitleId m_titleId;\n};\n"
  },
  {
    "path": "src/Cafe/TitleList/TitleInfo.cpp",
    "content": "#include \"TitleInfo.h\"\n#include \"Cafe/Filesystem/fscDeviceHostFS.h\"\n#include \"Cafe/Filesystem/WUHB/WUHBReader.h\"\n#include \"Cafe/Filesystem/FST/FST.h\"\n#include \"pugixml.hpp\"\n#include \"Common/FileStream.h\"\n#include <zarchive/zarchivereader.h>\n#include \"util/IniParser/IniParser.h\"\n#include \"util/crypto/crc32.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/helpers/helpers.h\"\n\n// detect format by reading file header/footer\nCafeTitleFileType DetermineCafeSystemFileType(fs::path filePath)\n{\n\tstd::unique_ptr<FileStream> fs(FileStream::openFile2(filePath));\n\tif (!fs)\n\t\treturn CafeTitleFileType::UNKNOWN;\n\t// very small files (<32 bytes) are always considered unknown\n\tuint64 fileSize = fs->GetSize();\n\tif (fileSize < 32)\n\t\treturn CafeTitleFileType::UNKNOWN;\n\t// read header bytes\n\tuint8 headerRaw[32]{};\n\tfs->readData(headerRaw, sizeof(headerRaw));\n\t// check for WUX\n\tuint8 wuxHeaderMagic[8] = { 0x57,0x55,0x58,0x30,0x2E,0xD0,0x99,0x10 };\n\tif (memcmp(headerRaw, wuxHeaderMagic, sizeof(wuxHeaderMagic)) == 0)\n\t\treturn CafeTitleFileType::WUX;\n\t// check for RPX\n\tuint8 rpxHeaderMagic[9] = { 0x7F,0x45,0x4C,0x46,0x01,0x02,0x01,0xCA,0xFE };\n\tif (memcmp(headerRaw, rpxHeaderMagic, sizeof(rpxHeaderMagic)) == 0)\n\t\treturn CafeTitleFileType::RPX;\n\t// check for ELF\n\tuint8 elfHeaderMagic[9] = { 0x7F,0x45,0x4C,0x46,0x01,0x02,0x01,0x00,0x00 };\n\tif (memcmp(headerRaw, elfHeaderMagic, sizeof(elfHeaderMagic)) == 0)\n\t\treturn CafeTitleFileType::ELF;\n\t// check for WUD\n\tuint8 wudMagic1[4] = { 0x57,0x55,0x50,0x2D }; // wud files should always start with \"WUP-...\"\n\tuint8 wudMagic2[4] = { 0xCC,0x54,0x9E,0xB9 };\n\tif (fileSize >= 0x10000)\n\t{\n\t\tuint8 magic1[4];\n\t\tfs->SetPosition(0);\n\t\tfs->readData(magic1, 4);\n\t\tif (memcmp(magic1, wudMagic1, 4) == 0)\n\t\t{\n\t\t\tuint8 magic2[4];\n\t\t\tfs->SetPosition(0x10000);\n\t\t\tfs->readData(magic2, 4);\n\t\t\tif (memcmp(magic2, wudMagic2, 4) == 0)\n\t\t\t{\n\t\t\t\treturn CafeTitleFileType::WUD;\n\t\t\t}\n\t\t}\n\t}\n\t// check for WUA\n\t// todo\n\treturn CafeTitleFileType::UNKNOWN;\n}\n\nTitleInfo::TitleInfo(const fs::path& path)\n{\n\tm_isValid = DetectFormat(path, m_fullPath, m_titleFormat);\n\tif (!m_isValid)\n\t\tm_titleFormat = TitleDataFormat::INVALID_STRUCTURE;\n\telse\n\t{\n\t\tm_isValid = ParseXmlInfo();\n\t}\n\tif (m_isValid)\n\t\tCalcUID();\n}\n\nTitleInfo::TitleInfo(const fs::path& path, std::string_view subPath)\n{\n\t// path must point to a (wua) file\n\tif (!path.has_filename())\n\t{\n\t\tm_isValid = false;\n\t\tSetInvalidReason(InvalidReason::BAD_PATH_OR_INACCESSIBLE);\n\t\treturn;\n\t}\n\tm_isValid = true;\n\tm_titleFormat = TitleDataFormat::WIIU_ARCHIVE;\n\tm_fullPath = path;\n\tm_subPath = subPath;\n\tm_isValid = ParseXmlInfo();\n\tif (m_isValid)\n\t\tCalcUID();\n}\n\nTitleInfo::TitleInfo(const TitleInfo::CachedInfo& cachedInfo)\n{\n\tm_cachedInfo = new CachedInfo(cachedInfo);\n\tm_fullPath = cachedInfo.path;\n\tm_subPath = cachedInfo.subPath;\n\tm_titleFormat = cachedInfo.titleDataFormat;\n\t// verify some parameters\n\tm_isValid = false;\n\tif (cachedInfo.titleDataFormat != TitleDataFormat::HOST_FS &&\n\t\tcachedInfo.titleDataFormat != TitleDataFormat::WIIU_ARCHIVE &&\n\t\tcachedInfo.titleDataFormat != TitleDataFormat::WUHB &&\n\t\tcachedInfo.titleDataFormat != TitleDataFormat::WUD &&\n\t\tcachedInfo.titleDataFormat != TitleDataFormat::NUS &&\n\t\tcachedInfo.titleDataFormat != TitleDataFormat::INVALID_STRUCTURE)\n\t\treturn;\n\tif (cachedInfo.path.empty())\n\t\treturn;\n\tif (cachedInfo.titleDataFormat == TitleDataFormat::WIIU_ARCHIVE && m_subPath.empty())\n\t\treturn; // for wua files the subpath must never be empty (title must not be stored in root of archive)\n\tm_isValid = true;\n\tCalcUID();\n}\n\nTitleInfo::~TitleInfo()\n{\n\tcemu_assert(m_mountpoints.empty());\n\tdelete m_parsedMetaXml;\n\tdelete m_parsedAppXml;\n\tdelete m_parsedCosXml;\n\tdelete m_cachedInfo;\n}\n\nTitleInfo::CachedInfo TitleInfo::MakeCacheEntry()\n{\n\tcemu_assert_debug(IsValid());\n\tCachedInfo e;\n\te.titleDataFormat = m_titleFormat;\n\te.path = m_fullPath;\n\te.subPath = m_subPath;\n\te.titleId = GetAppTitleId();\n\te.titleVersion = GetAppTitleVersion();\n\te.sdkVersion = GetAppSDKVersion();\n\te.titleName = GetMetaTitleName();\n\te.region = GetMetaRegion();\n\te.group_id = GetAppGroup();\n\te.app_type = GetAppType();\n\treturn e;\n}\n\n// WUA can contain multiple titles. Root directory contains one directory for each title. The name must match: <titleId>_v<version>\nbool TitleInfo::ParseWuaTitleFolderName(std::string_view name, TitleId& titleIdOut, uint16& titleVersionOut)\n{\n\tstd::string_view sv = name;\n\tif (sv.size() < 16 + 2)\n\t\treturn false;\n\tTitleId parsedId;\n\tif (!TitleIdParser::ParseFromStr(sv, parsedId))\n\t\treturn false;\n\tsv.remove_prefix(16);\n\tif (sv[0] != '_' || (sv[1] != 'v' && sv[1] != 'v'))\n\t\treturn false;\n\tsv.remove_prefix(2);\n\tif (sv.empty())\n\t\treturn false;\n\tif (sv[0] == '0' && sv.size() != 1) // leading zero not allowed\n\t\treturn false;\n\tuint32 v = 0;\n\twhile (!sv.empty())\n\t{\n\t\tuint8 c = sv[0];\n\t\tsv.remove_prefix(1);\n\t\tv *= 10;\n\t\tif (c >= '0' && c <= '9')\n\t\t\tv += (uint32)(c - '0');\n\t\telse\n\t\t{\n\t\t\tv = 0xFFFFFFFF;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (v > 0xFFFF)\n\t\treturn false;\n\ttitleIdOut = parsedId;\n\ttitleVersionOut = v;\n\treturn true;\n}\n\nbool TitleInfo::DetectFormat(const fs::path& path, fs::path& pathOut, TitleDataFormat& formatOut)\n{\n\tstd::error_code ec;\n\tif (path.has_extension() && fs::is_regular_file(path, ec))\n\t{\n\t\tstd::string filenameStr = _pathToUtf8(path.filename());\n\t\tif (boost::iends_with(filenameStr, \".rpx\"))\n\t\t{\n\t\t\t// is in code folder?\n\t\t\tfs::path parentPath = path.parent_path();\n\t\t\tif (boost::iequals(_pathToUtf8(parentPath.filename()), \"code\"))\n\t\t\t{\n\t\t\t\tparentPath = parentPath.parent_path();\n\t\t\t\t// next to content and meta?\n\t\t\t\tstd::error_code ec;\n\t\t\t\tif (fs::exists(parentPath / \"content\", ec) && fs::exists(parentPath / \"meta\", ec))\n\t\t\t\t{\n\t\t\t\t\tformatOut = TitleDataFormat::HOST_FS;\n\t\t\t\t\tpathOut = parentPath;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (boost::iends_with(filenameStr, \".wud\") ||\n\t\t\t\t boost::iends_with(filenameStr, \".wux\") ||\n\t\t\t\t boost::iends_with(filenameStr, \".iso\"))\n\t\t{\n\t\t\tformatOut = TitleDataFormat::WUD;\n\t\t\tpathOut = path;\n\t\t\treturn true;\n\t\t}\n\t\telse if (boost::iequals(filenameStr, \"title.tmd\"))\n\t\t{\n\t\t\tformatOut = TitleDataFormat::NUS;\n\t\t\tpathOut = path;\n\t\t\treturn true;\n\t\t}\n\t\telse if (boost::iends_with(filenameStr, \".wua\"))\n\t\t{\n\t\t\tformatOut = TitleDataFormat::WIIU_ARCHIVE;\n\t\t\tpathOut = path;\n\t\t\t// a Wii U archive file can contain multiple titles but TitleInfo only maps to one\n\t\t\t// we use the first base title that we find. This is the most intuitive behavior when someone launches \"game.wua\"\n\t\t\tZArchiveReader* zar = ZArchiveReader::OpenFromFile(path);\n\t\t\tif (!zar)\n\t\t\t\treturn false;\n\t\t\tZArchiveNodeHandle rootDir = zar->LookUp(\"\", false, true);\n\t\t\tbool foundBase = false;\n\t\t\tfor (uint32 i = 0; i < zar->GetDirEntryCount(rootDir); i++)\n\t\t\t{\n\t\t\t\tZArchiveReader::DirEntry dirEntry;\n\t\t\t\tif (!zar->GetDirEntry(rootDir, i, dirEntry))\n\t\t\t\t\tcontinue;\n\t\t\t\tif (!dirEntry.isDirectory)\n\t\t\t\t\tcontinue;\n\t\t\t\tTitleId parsedId;\n\t\t\t\tuint16 parsedVersion;\n\t\t\t\tif (!TitleInfo::ParseWuaTitleFolderName(dirEntry.name, parsedId, parsedVersion))\n\t\t\t\t\tcontinue;\n\t\t\t\tTitleIdParser tip(parsedId);\n\t\t\t\tTitleIdParser::TITLE_TYPE tt = tip.GetType();\n\t\t\t\tif (tt == TitleIdParser::TITLE_TYPE::BASE_TITLE || tt == TitleIdParser::TITLE_TYPE::BASE_TITLE_DEMO ||\n\t\t\t\t\ttt == TitleIdParser::TITLE_TYPE::SYSTEM_TITLE || tt == TitleIdParser::TITLE_TYPE::SYSTEM_OVERLAY_TITLE)\n\t\t\t\t{\n\t\t\t\t\tm_subPath = dirEntry.name;\n\t\t\t\t\tfoundBase = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tdelete zar;\n\t\t\treturn foundBase;\n\t\t}\n\t\telse if (boost::iends_with(filenameStr, \".wuhb\"))\n\t\t{\n\t\t\tstd::unique_ptr<WUHBReader> reader{WUHBReader::FromPath(path)};\n\t\t\tif(reader)\n\t\t\t{\n\t\t\t\tformatOut = TitleDataFormat::WUHB;\n\t\t\t\tpathOut = path;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t// note: Since a Wii U archive file (.wua) contains multiple titles we shouldn't auto-detect them here\n\t\t// instead TitleInfo has a second constructor which takes a subpath\n\t\t// unable to determine type by extension, check contents\n\t\tCafeTitleFileType fileType = DetermineCafeSystemFileType(path);\n\t\tif (fileType == CafeTitleFileType::WUD ||\n\t\t\tfileType == CafeTitleFileType::WUX)\n\t\t{\n\t\t\tformatOut = TitleDataFormat::WUD;\n\t\t\tpathOut = path;\n\t\t\treturn true;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// does it point to the root folder of a title?\n\t\tstd::error_code ec;\n\t\tif (fs::exists(path / \"content\", ec) && fs::exists(path / \"meta\", ec) && fs::exists(path / \"code\", ec))\n\t\t{\n\t\t\tformatOut = TitleDataFormat::HOST_FS;\n\t\t\tpathOut = path;\n\t\t\treturn true;\n\t\t}\n\t}\n\tSetInvalidReason(InvalidReason::UNKNOWN_FORMAT);\n\treturn false;\n}\n\nbool TitleInfo::IsValid() const\n{\n\treturn m_isValid;\n}\n\nfs::path TitleInfo::GetPath() const\n{\n\tif (!m_isValid)\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn {};\n\t}\n\treturn m_fullPath;\n}\n\nvoid TitleInfo::CalcUID()\n{\n\tcemu_assert_debug(m_isValid);\n\tif (!m_isValid)\n\t{\n\t\tm_uid = 0;\n\t\treturn;\n\t}\n\t// get absolute normalized path\n\tfs::path normalizedPath;\n\tif (m_fullPath.is_relative())\n\t{\n\t\tnormalizedPath = ActiveSettings::GetUserDataPath();\n\t\tnormalizedPath /= m_fullPath;\n\t}\n\telse\n\t\tnormalizedPath = m_fullPath;\n\tnormalizedPath = normalizedPath.lexically_normal();\n\tuint64 h = fs::hash_value(normalizedPath);\n\t// for WUA files also hash the subpath\n\tif (m_titleFormat == TitleDataFormat::WIIU_ARCHIVE)\n\t{\n\t\tuint64 subHash = std::hash<std::string_view>{}(m_subPath);\n\t\th += subHash;\n\t}\n\tm_uid = h;\n}\n\nuint64 TitleInfo::GetUID()\n{\n\tcemu_assert_debug(m_isValid);\n\treturn m_uid;\n}\n\nvoid TitleInfo::SetInvalidReason(InvalidReason reason)\n{\n\tif(m_invalidReason == InvalidReason::NONE)\n\t\tm_invalidReason = reason; // only update reason when it hasn't been set before\n}\n\nstd::mutex sZArchivePoolMtx;\nstd::map<fs::path, std::pair<uint32, ZArchiveReader*>> sZArchivePool;\n\nZArchiveReader* _ZArchivePool_AcquireInstance(const fs::path& path)\n{\n\tstd::unique_lock _lock(sZArchivePoolMtx);\n\tauto it = sZArchivePool.find(path);\n\tif (it != sZArchivePool.end())\n\t{\n\t\tit->second.first++; // increment ref count\n\t\treturn it->second.second;\n\t}\n\t_lock.unlock();\n\t// opening wua files can be expensive, so we do it outside of the lock\n\tZArchiveReader* zar = ZArchiveReader::OpenFromFile(path);\n\tif (!zar)\n\t\treturn nullptr;\n\t_lock.lock();\n\t// check if another instance was allocated in the meantime\n\tit = sZArchivePool.find(path);\n\tif (it != sZArchivePool.end())\n\t{\n\t\tdelete zar;\n\t\tit->second.first++; // increment ref count\n\t\treturn it->second.second;\n\t}\n\tsZArchivePool.emplace(std::piecewise_construct,\n\t\tstd::forward_as_tuple(path),\n\t\tstd::forward_as_tuple(1, zar)\n\t);\n\treturn zar;\n}\n\nvoid _ZArchivePool_ReleaseInstance(const fs::path& path, ZArchiveReader* zar)\n{\n\tstd::unique_lock _lock(sZArchivePoolMtx);\n\tauto it = sZArchivePool.find(path);\n\tcemu_assert(it != sZArchivePool.end());\n\tcemu_assert(it->second.second == zar);\n\tit->second.first--; // decrement ref count\n\tif (it->second.first == 0)\n\t{\n\t\tdelete it->second.second;\n\t\tsZArchivePool.erase(it);\n\t}\n}\n\nbool TitleInfo::Mount(std::string_view virtualPath, std::string_view subfolder, sint32 mountPriority)\n{\n\tcemu_assert_debug(subfolder.empty() || (subfolder.front() != '/' || subfolder.front() != '\\\\')); // only relative subfolder allowed\n\n\tcemu_assert(m_isValid);\n\tif (m_titleFormat == TitleDataFormat::HOST_FS)\n\t{\n\t\tfs::path hostFSPath = m_fullPath;\n\t\thostFSPath.append(subfolder);\n\t\tbool r = FSCDeviceHostFS_Mount(std::string(virtualPath).c_str(), _pathToUtf8(hostFSPath), mountPriority);\n\t\tcemu_assert_debug(r);\n\t\tif (!r)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to mount {} to {}\", virtualPath, subfolder);\n\t\t\tSetInvalidReason(InvalidReason::BAD_PATH_OR_INACCESSIBLE);\n\t\t\treturn false;\n\t\t}\n\t}\n\telse if (m_titleFormat == TitleDataFormat::WUD || m_titleFormat == TitleDataFormat::NUS)\n\t{\n\t\tFSTVolume::ErrorCode fstError;\n\t\tif (m_mountpoints.empty())\n\t\t{\n\t\t\tcemu_assert_debug(!m_wudVolume);\n\t\t\tif(m_titleFormat == TitleDataFormat::WUD)\n\t\t\t\tm_wudVolume = FSTVolume::OpenFromDiscImage(m_fullPath, &fstError); // open wud/wux\n\t\t\telse\n\t\t\t\tm_wudVolume = FSTVolume::OpenFromContentFolder(m_fullPath.parent_path(), &fstError); // open from .app files directory, the path points to /title.tmd\n\t\t}\n\t\tif (!m_wudVolume)\n\t\t{\n\t\t\tif (fstError == FSTVolume::ErrorCode::DISC_KEY_MISSING)\n\t\t\t\tSetInvalidReason(InvalidReason::NO_DISC_KEY);\n\t\t\telse if (fstError == FSTVolume::ErrorCode::TITLE_TIK_MISSING)\n\t\t\t\tSetInvalidReason(InvalidReason::NO_TITLE_TIK);\n\t\t\treturn false;\n\t\t}\n\t\tbool r = FSCDeviceWUD_Mount(virtualPath, subfolder, m_wudVolume, mountPriority);\n\t\tcemu_assert_debug(r);\n\t\tif (!r)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to mount {} to {}\", virtualPath, subfolder);\n\t\t\tdelete m_wudVolume;\n\t\t\treturn false;\n\t\t}\n\t}\n\telse if (m_titleFormat == TitleDataFormat::WIIU_ARCHIVE)\n\t{\n\t\tif (!m_zarchive)\n\t\t{\n\t\t\tm_zarchive = _ZArchivePool_AcquireInstance(m_fullPath);\n\t\t\tif (!m_zarchive)\n\t\t\t\treturn false;\n\t\t}\n\t\tbool r = FSCDeviceWUA_Mount(virtualPath, std::string(m_subPath).append(\"/\").append(subfolder), m_zarchive, mountPriority);\n\t\tif (!r)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to mount {} to {}\", virtualPath, subfolder);\n\t\t\t_ZArchivePool_ReleaseInstance(m_fullPath, m_zarchive);\n\t\t\treturn false;\n\t\t}\n\t}\n\telse if (m_titleFormat == TitleDataFormat::WUHB)\n\t{\n\t\tif (!m_wuhbreader)\n\t\t{\n\t\t\tm_wuhbreader = WUHBReader::FromPath(m_fullPath);\n\t\t\tif (!m_wuhbreader)\n\t\t\t\treturn false;\n\t\t}\n\t\tbool r = FSCDeviceWUHB_Mount(virtualPath, subfolder, m_wuhbreader, mountPriority);\n\t\tif (!r)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to mount {} to {}\", virtualPath, subfolder);\n\t\t\tdelete m_wuhbreader;\n\t\t\tm_wuhbreader = nullptr;\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\tm_mountpoints.emplace_back(mountPriority, virtualPath);\n\treturn true;\n}\n\nvoid TitleInfo::Unmount(std::string_view virtualPath)\n{\n\tfor (auto& itr : m_mountpoints)\n\t{\n\t\tif (!boost::equals(itr.second, virtualPath))\n\t\t\tcontinue;\n\t\tfsc_unmount(itr.second.c_str(), itr.first);\n\t\tstd::erase(m_mountpoints, itr);\n\t\t// if the last mount point got unmounted, close any open devices\n\t\tif (m_mountpoints.empty())\n\t\t{\n\t\t\tif (m_wudVolume)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(m_titleFormat == TitleDataFormat::WUD || m_titleFormat == TitleDataFormat::NUS);\n\t\t\t\tdelete m_wudVolume;\n\t\t\t\tm_wudVolume = nullptr;\n\t\t\t}\n            if (m_zarchive)\n            {\n                _ZArchivePool_ReleaseInstance(m_fullPath, m_zarchive);\n                if (m_mountpoints.empty())\n                    m_zarchive = nullptr;\n            }\n\t\t\tif (m_wuhbreader)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(m_titleFormat == TitleDataFormat::WUHB);\n\t\t\t\tdelete m_wuhbreader;\n\t\t\t\tm_wuhbreader = nullptr;\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\tcemu_assert_suspicious(); // unmount on unknown path\n}\n\nvoid TitleInfo::UnmountAll()\n{\n\twhile (!m_mountpoints.empty())\n\t\tUnmount(m_mountpoints.front().second);\n}\n\nstd::atomic_uint64_t sTempMountingPathCounter = 1;\n\nstd::string TitleInfo::GetUniqueTempMountingPath()\n{\n\tuint64_t v = sTempMountingPathCounter.fetch_add(1);\n\treturn fmt::format(\"/internal/tempMount{:016x}/\", v);\n}\n\nbool TitleInfo::ParseXmlInfo()\n{\n\tcemu_assert(m_isValid);\n\tif (m_hasParsedXmlFiles)\n\t\treturn m_isValid;\n\tm_hasParsedXmlFiles = true;\n\n\tstd::string mountPath = GetUniqueTempMountingPath();\n\tbool r = Mount(mountPath, \"\", FSC_PRIORITY_BASE);\n\tif (!r)\n\t\treturn false;\n\t// meta/meta.xml\n\tauto xmlData = fsc_extractFile(fmt::format(\"{}meta/meta.xml\", mountPath).c_str());\n\tif(xmlData)\n\t\tm_parsedMetaXml = ParsedMetaXml::Parse(xmlData->data(), xmlData->size());\n\n\tif(!m_parsedMetaXml)\n\t{\n\t\t// meta/meta.ini (WUHB)\n\t\tauto iniData = fsc_extractFile(fmt::format(\"{}meta/meta.ini\", mountPath).c_str());\n\t\tif (iniData)\n\t\t\tm_parsedMetaXml = ParseAromaIni(*iniData);\n\t\tif(m_parsedMetaXml)\n\t\t{\n\t\t\tm_parsedCosXml = new ParsedCosXml{.argstr = \"root.rpx\"};\n\t\t\tm_parsedAppXml = new ParsedAppXml{m_parsedMetaXml->m_title_id, 0, 0, 0, 0};\n\t\t}\n\t}\n\n\t// code/app.xml\n\txmlData = fsc_extractFile(fmt::format(\"{}code/app.xml\", mountPath).c_str());\n\tif(xmlData)\n\t\tParseAppXml(*xmlData);\n\t// code/cos.xml\n\txmlData = fsc_extractFile(fmt::format(\"{}code/cos.xml\", mountPath).c_str());\n\tif (xmlData)\n\t\tm_parsedCosXml = ParsedCosXml::Parse(xmlData->data(), xmlData->size());\n\n\tUnmount(mountPath);\n\n\t// some system titles dont have a meta.xml file\n\tbool allowMissingMetaXml = false;\n\tif(m_parsedAppXml && this->IsSystemDataTitle())\n\t{\n\t\tallowMissingMetaXml = true;\n\t}\n\n\tif ((allowMissingMetaXml == false && !m_parsedMetaXml) || !m_parsedAppXml || !m_parsedCosXml)\n\t{\n\t\tbool hasAnyXml = m_parsedMetaXml || m_parsedAppXml || m_parsedCosXml;\n\t\tif (hasAnyXml)\n\t\t\tcemuLog_log(LogType::Force, \"Title has missing meta .xml files. Title path: {}\", _pathToUtf8(m_fullPath));\n\t\tdelete m_parsedMetaXml;\n\t\tdelete m_parsedAppXml;\n\t\tdelete m_parsedCosXml;\n\t\tm_parsedMetaXml = nullptr;\n\t\tm_parsedAppXml = nullptr;\n\t\tm_parsedCosXml = nullptr;\n\t\tm_isValid = false;\n\t\tSetInvalidReason(InvalidReason::MISSING_XML_FILES);\n\t\treturn false;\n\t}\n\tm_isValid = true;\n\treturn true;\n}\n\nParsedMetaXml* TitleInfo::ParseAromaIni(std::span<unsigned char> content)\n{\n\tIniParser parser{content};\n\twhile (parser.NextSection() && parser.GetCurrentSectionName() != \"menu\")\n\t\tcontinue;\n\tif (parser.GetCurrentSectionName() != \"menu\")\n\t\treturn nullptr;\n\n\tauto parsed = std::make_unique<ParsedMetaXml>();\n\n\tconst auto author = parser.FindOption(\"author\");\n\tif (author)\n\t\tparsed->m_publisher[(size_t)CafeConsoleLanguage::EN] = *author;\n\n\tconst auto longName = parser.FindOption(\"longname\");\n\tif (longName)\n\t\tparsed->m_long_name[(size_t)CafeConsoleLanguage::EN] = *longName;\n\n\tconst auto shortName = parser.FindOption(\"shortname\");\n\tif (shortName)\n\t\tparsed->m_short_name[(size_t)CafeConsoleLanguage::EN] = *shortName;\n\n\tauto checksumInput = std::string{*author}.append(*longName).append(*shortName);\n\tparsed->m_title_id = (0x0005000Full<<32) | crc32_calc(checksumInput.data(), checksumInput.length());\n\n\treturn parsed.release();\n}\n\nbool TitleInfo::ParseAppXml(std::vector<uint8>& appXmlData)\n{\n\tpugi::xml_document app_doc;\n\tif (!app_doc.load_buffer_inplace(appXmlData.data(), appXmlData.size()))\n\t\treturn false;\n\n\tconst auto root = app_doc.child(\"app\");\n\tif (!root)\n\t\treturn false;\n\n\tm_parsedAppXml = new ParsedAppXml();\n\n\tfor (const auto& child : root.children())\n\t{\n\t\tstd::string_view name = child.name();\n\t\tif (name == \"title_version\")\n\t\t\tm_parsedAppXml->title_version = (uint16)std::stoull(child.text().as_string(), nullptr, 16);\n\t\telse if (name == \"title_id\")\n\t\t\tm_parsedAppXml->title_id = std::stoull(child.text().as_string(), nullptr, 16);\n\t\telse if (name == \"app_type\")\n\t\t\tm_parsedAppXml->app_type = (uint32)std::stoull(child.text().as_string(), nullptr, 16);\n\t\telse if (name == \"group_id\")\n\t\t\tm_parsedAppXml->group_id = (uint32)std::stoull(child.text().as_string(), nullptr, 16);\n\t\telse if (name == \"sdk_version\")\n\t\t\tm_parsedAppXml->sdk_version = (uint32)std::stoull(child.text().as_string(), nullptr, 10);\n\t}\n\treturn true;\n}\n\nTitleId TitleInfo::GetAppTitleId() const\n{\n\tcemu_assert_debug(m_isValid);\n\tif (m_parsedAppXml)\n\t\treturn m_parsedAppXml->title_id;\n\tif (m_cachedInfo)\n\t\treturn m_cachedInfo->titleId;\n\tcemu_assert_suspicious();\n\treturn 0;\n}\n\nuint16 TitleInfo::GetAppTitleVersion() const\n{\n\tcemu_assert_debug(m_isValid);\n\tif (m_parsedAppXml)\n\t\treturn m_parsedAppXml->title_version;\n\tif (m_cachedInfo)\n\t\treturn m_cachedInfo->titleVersion;\n\tcemu_assert_suspicious();\n\treturn 0;\n}\n\nuint32 TitleInfo::GetAppSDKVersion() const\n{\n\tcemu_assert_debug(m_isValid);\n\tif (m_parsedAppXml)\n\t\treturn m_parsedAppXml->sdk_version;\n\tif (m_cachedInfo)\n\t\treturn m_cachedInfo->sdkVersion;\n\tcemu_assert_suspicious();\n\treturn 0;\n}\n\nuint32 TitleInfo::GetAppGroup() const\n{\n\tcemu_assert_debug(m_isValid);\n\tif (m_parsedAppXml)\n\t\treturn m_parsedAppXml->group_id;\n\tif (m_cachedInfo)\n\t\treturn m_cachedInfo->group_id;\n\tcemu_assert_suspicious();\n\treturn 0;\n}\n\nuint32 TitleInfo::GetAppType() const\n{\n\tcemu_assert_debug(m_isValid);\n\tif (m_parsedAppXml)\n\t\treturn m_parsedAppXml->app_type;\n\tif (m_cachedInfo)\n\t\treturn m_cachedInfo->app_type;\n\tcemu_assert_suspicious();\n\treturn 0;\n}\n\nTitleIdParser::TITLE_TYPE TitleInfo::GetTitleType()\n{\n\tTitleIdParser tip(GetAppTitleId());\n\treturn tip.GetType();\n}\n\nstd::string TitleInfo::GetMetaTitleName() const\n{\n\tcemu_assert_debug(m_isValid);\n\tif (m_parsedMetaXml)\n\t{\n\t\tstd::string titleNameCfgLanguage;\n\t\ttitleNameCfgLanguage = m_parsedMetaXml->GetLongName(GetConfig().console_language);\n\t\tif (titleNameCfgLanguage.empty()) //Get English Title\n\t\t\ttitleNameCfgLanguage = m_parsedMetaXml->GetLongName(CafeConsoleLanguage::EN);\n\t\tif (titleNameCfgLanguage.empty()) //Unknown Title\n\t\t\ttitleNameCfgLanguage = \"Unknown Title\";\n\t\treturn titleNameCfgLanguage;\n\t}\n\tif (m_cachedInfo)\n\t\treturn m_cachedInfo->titleName;\n\treturn \"\";\n}\n\nCafeConsoleRegion TitleInfo::GetMetaRegion() const\n{\n\tcemu_assert_debug(m_isValid);\n\tif (m_parsedMetaXml)\n\t\treturn m_parsedMetaXml->GetRegion();\n\tif (m_cachedInfo)\n\t\treturn m_cachedInfo->region;\n\treturn CafeConsoleRegion::JPN;\n}\n\nuint32 TitleInfo::GetOlvAccesskey() const\n{\n\tcemu_assert_debug(m_isValid);\n\tif (m_parsedMetaXml)\n\t\treturn m_parsedMetaXml->GetOlvAccesskey();\n\n\tcemu_assert_suspicious();\n\treturn -1;\n}\n\nstd::string TitleInfo::GetArgStr() const\n{\n\tcemu_assert_debug(m_parsedCosXml);\n\tif (!m_parsedCosXml)\n\t\treturn \"\";\n\treturn m_parsedCosXml->argstr;\n}\n\nstd::string TitleInfo::GetPrintPath() const\n{\n\tif (!m_isValid)\n\t\treturn \"invalid\";\n\tstd::string tmp;\n\ttmp.append(_pathToUtf8(m_fullPath));\n\tswitch (m_titleFormat)\n\t{\n\tcase TitleDataFormat::HOST_FS:\n\t\ttmp.append(\" [Folder]\");\n\t\tbreak;\n\tcase TitleDataFormat::WUD:\n\t\ttmp.append(\" [WUD]\");\n\t\tbreak;\n\tcase TitleDataFormat::NUS:\n\t\ttmp.append(\" [NUS]\");\n\t\tbreak;\n\tcase TitleDataFormat::WIIU_ARCHIVE:\n\t\ttmp.append(\" [WUA]\");\n\t\tbreak;\n\tcase TitleDataFormat::WUHB:\n\t\ttmp.append(\" [WUHB]\");\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\tif (m_titleFormat == TitleDataFormat::WIIU_ARCHIVE)\n\t\ttmp.append(fmt::format(\" [{}]\", m_subPath));\n\treturn tmp;\n}\n\nstd::string TitleInfo::GetInstallPath() const\n{\n\tTitleId titleId = GetAppTitleId();\n\tTitleIdParser tip(titleId);\n\tstd::string tmp;\n\tif (tip.IsSystemTitle())\n\t\ttmp = fmt::format(\"sys/title/{:08x}/{:08x}\", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));\n    else\n\t\ttmp = fmt::format(\"usr/title/{:08x}/{:08x}\", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));\n\treturn tmp;\n}\n\nParsedCosXml* ParsedCosXml::Parse(uint8* xmlData, size_t xmlLen)\n{\n\tpugi::xml_document app_doc;\n\tif (!app_doc.load_buffer_inplace(xmlData, xmlLen))\n\t\treturn nullptr;\n\n\tconst auto root = app_doc.child(\"app\");\n\tif (!root)\n\t\treturn nullptr;\n\n\tParsedCosXml* parsedCos = new ParsedCosXml();\n\n\tauto node = root.child(\"argstr\");\n\tif (node)\n\t\tparsedCos->argstr = node.text().as_string();\n\n\t// parse permissions\n\tauto permissionsNode = root.child(\"permissions\");\n\tfor(uint32 permissionIndex = 0; permissionIndex < 19; ++permissionIndex)\n\t{\n\t\tstd::string permissionName = fmt::format(\"p{}\", permissionIndex);\n\t\tauto permissionNode = permissionsNode.child(permissionName.c_str());\n\t\tif (!permissionNode)\n\t\t\tbreak;\n\t\tparsedCos->permissions[permissionIndex].group = static_cast<CosCapabilityGroup>(ConvertString<uint32>(permissionNode.child(\"group\").text().as_string(), 10));\n\t\tparsedCos->permissions[permissionIndex].mask = static_cast<CosCapabilityBits>(ConvertString<uint64>(permissionNode.child(\"mask\").text().as_string(), 16));\n\t}\n\n\treturn parsedCos;\n}"
  },
  {
    "path": "src/Cafe/TitleList/TitleInfo.h",
    "content": "#pragma once\n\n#include \"Cafe/Filesystem/fsc.h\"\n#include \"config/CemuConfig.h\" // for CafeConsoleRegion. Move to NCrypto?\n#include \"TitleId.h\"\n#include \"AppType.h\"\n#include \"ParsedMetaXml.h\"\n\nenum class CafeTitleFileType\n{\n\tUNKNOWN,\n\tWUD,\n\tWUX,\n\tRPX,\n\tELF,\n};\n\nCafeTitleFileType DetermineCafeSystemFileType(fs::path filePath);\n\nstruct ParsedAppXml\n{\n\tuint64 title_id;\n\tuint16 title_version;\n\tuint32 app_type;\n\tuint32 group_id;\n\tuint32 sdk_version;\n};\n\nenum class CosCapabilityGroup : uint32\n{\n\tNone = 0,\n\tBSP  =  1,\n\tDK   =  3,\n\tUSB  =  9,\n\tUHS  = 12,\n\tFS   = 11,\n\tMCP  = 13,\n\tNIM  = 14,\n\tACT  = 15,\n\tFPD  = 16,\n\tBOSS = 17,\n\tACP  = 18,\n\tPDM  = 19,\n\tAC   = 20,\n\tNDM  = 21,\n\tNSEC = 22\n};\n\nenum class CosCapabilityBits : uint64\n{\n\tAll = 0xFFFFFFFFFFFFFFFFull\n};\n\nenum class CosCapabilityBitsFS : uint64\n{\n\tODD_READ         = (1llu << 0),\n\tODD_WRITE        = (1llu << 1),\n\tODD_RAW_OPEN     = (1llu << 2),\n\tODD_MOUNT        = (1llu << 3),\n\tSLCCMPT_READ     = (1llu << 4),\n\tSLCCMPT_WRITE    = (1llu << 5),\n\tSLCCMPT_RAW_OPEN = (1llu << 6),\n\tSLCCMPT_MOUNT    = (1llu << 7),\n\tSLC_READ         = (1llu << 8),\n\tSLC_WRITE        = (1llu << 9),\n\tSLC_RAW_OPEN     = (1llu << 10),\n\tSLC_MOUNT        = (1llu << 11),\n\tMLC_READ         = (1llu << 12),\n\tMLC_WRITE        = (1llu << 13),\n\tMLC_RAW_OPEN     = (1llu << 14),\n\tMLC_MOUNT        = (1llu << 15),\n\tSDCARD_READ      = (1llu << 16),\n\tSDCARD_WRITE     = (1llu << 17),\n\tSDCARD_RAW_OPEN  = (1llu << 18),\n\tSDCARD_MOUNT     = (1llu << 19),\n\tHFIO_READ        = (1llu << 20),\n\tHFIO_WRITE       = (1llu << 21),\n\tHFIO_RAW_OPEN    = (1llu << 22),\n\tHFIO_MOUNT       = (1llu << 23),\n\tRAMDISK_READ     = (1llu << 24),\n\tRAMDISK_WRITE    = (1llu << 25),\n\tRAMDISK_RAW_OPEN = (1llu << 26),\n\tRAMDISK_MOUNT    = (1llu << 27),\n\tUSB_READ         = (1llu << 28),\n\tUSB_WRITE        = (1llu << 29),\n\tUSB_RAW_OPEN     = (1llu << 30),\n\tUSB_MOUNT        = (1llu << 31),\n\tOTHER_READ       = (1llu << 32),\n\tOTHER_WRITE      = (1llu << 33),\n\tOTHER_RAW_OPEN   = (1llu << 34),\n\tOTHER_MOUNT      = (1llu << 35)\n};\nENABLE_BITMASK_OPERATORS(CosCapabilityBitsFS);\n\nstruct ParsedCosXml \n{\n  public:\n\n\tstd::string argstr;\n\n\tstruct Permission\n\t{\n\t\tCosCapabilityGroup group{CosCapabilityGroup::None};\n\t\tCosCapabilityBits mask{CosCapabilityBits::All};\n\t};\n\tPermission permissions[19]{};\n\n\tstatic ParsedCosXml* Parse(uint8* xmlData, size_t xmlLen);\n\n\tCosCapabilityBits GetCapabilityBits(CosCapabilityGroup group) const\n\t{\n\t\tfor (const auto& perm : permissions)\n\t\t{\n\t\t\tif (perm.group == group)\n\t\t\t\treturn perm.mask;\n\t\t}\n\t\treturn CosCapabilityBits::All;\n\t}\n};\n\nclass TitleInfo\n{\npublic:\n\tenum class TitleDataFormat\n\t{\n\t\tHOST_FS = 1, // host filesystem directory (fullPath points to root with content/code/meta subfolders)\n\t\tWUD = 2, // WUD or WUX\n\t\tWIIU_ARCHIVE = 3, // Wii U compressed single-file archive (.wua)\n\t  \tNUS = 4, // NUS format. Directory with .app files, title.tik and title.tmd\n\t  \tWUHB = 5,\n\t\t// error\n\t\tINVALID_STRUCTURE = 0,\n\t};\n\n\tenum class InvalidReason : uint8\n\t{\n\t\tNONE = 0,\n\t\tBAD_PATH_OR_INACCESSIBLE = 1,\n\t\tUNKNOWN_FORMAT = 2,\n\t\tNO_DISC_KEY = 3,\n\t\tNO_TITLE_TIK = 4,\n\t\tMISSING_XML_FILES = 4,\n\t};\n\n\tstruct CachedInfo\n\t{\n\t\tTitleDataFormat titleDataFormat;\n\t\tfs::path path;\n\t\tstd::string subPath; // for WUA\n\t\tuint64 titleId;\n\t\tuint16 titleVersion;\n\t\tuint32 sdkVersion;\n\t\tstd::string titleName;\n\t\tCafeConsoleRegion region;\n\t\tuint32 group_id;\n\t\tuint32 app_type;\n\t};\n\n\tTitleInfo() : m_isValid(false) {};\n\tTitleInfo(const fs::path& path);\n\tTitleInfo(const fs::path& path, std::string_view subPath);\n\tTitleInfo(const CachedInfo& cachedInfo);\n\t~TitleInfo();\n\n\tTitleInfo(const TitleInfo& other)\n\t{\n\t\tCopy(other);\n\t}\n\n\tTitleInfo& operator=(TitleInfo other)\n\t{\n\t\tCopy(other);\n\t\treturn *this;\n\t}\n\n\tbool IsCached() { return m_cachedInfo; }; // returns true if this TitleInfo was loaded from cache and has not yet been parsed\n\n\tCachedInfo MakeCacheEntry();\n\n\tbool IsValid() const;\n\tInvalidReason GetInvalidReason() const { return m_invalidReason; }\n\tuint64 GetUID(); // returns a unique identifier derived from the absolute canonical title location which can be used to identify this title by its location. May not persist across sessions, especially when Cemu is used portable\n\n\tfs::path GetPath() const;\n\tTitleDataFormat GetFormat() const { return m_titleFormat; };\n\n\tbool Mount(std::string_view virtualPath, std::string_view subfolder, sint32 mountPriority);\n\tvoid Unmount(std::string_view virtualPath);\n\tvoid UnmountAll();\n\tbool IsMounted() const { return !m_mountpoints.empty(); }\n\n\tbool ParseXmlInfo();\n\tbool HasValidXmlInfo() const { return m_parsedMetaXml && m_parsedAppXml && m_parsedCosXml; };\n\n\tbool IsEqualByLocation(const TitleInfo& rhs) const\n\t{\n\t\treturn m_uid == rhs.m_uid;\n\t}\n\n\tbool IsSystemDataTitle() const\n\t{\n\t\tif(!IsValid())\n\t\t\treturn false;\n\t\tuint32 appType = GetAppType();\n\t\treturn appType == APP_TYPE::DRC_FIRMWARE || appType == APP_TYPE::DRC_TEXTURE_ATLAS || appType == APP_TYPE::VERSION_DATA_TITLE;\n\t}\n\n\t// API which requires parsed meta data or cached info\n\tTitleId GetAppTitleId() const; // from app.xml\n\tuint16 GetAppTitleVersion() const; // from app.xml\n\tuint32 GetAppSDKVersion() const; // from app.xml\n\tuint32 GetAppGroup() const; // from app.xml\n\tuint32 GetAppType() const; // from app.xml\n\tstd::string GetMetaTitleName() const; // from meta.xml\n\tCafeConsoleRegion GetMetaRegion() const; // from meta.xml\n\tuint32 GetOlvAccesskey() const;\n\n\t// cos.xml\n\tstd::string GetArgStr() const;\n\n\t// meta.xml also contains a version field which seems to match the one from app.xml\n\t// the titleId in meta.xml seems to be the title id of the base game for updates specifically. For AOC content it's the AOC's titleId\n\n\tTitleIdParser::TITLE_TYPE GetTitleType();\n\tParsedMetaXml* GetMetaInfo()\n\t{\n\t\treturn m_parsedMetaXml;\n\t}\n\n\tParsedCosXml* GetCosInfo()\n\t{\n\t\treturn m_parsedCosXml;\n\t}\n\n\tstd::string GetPrintPath() const; // formatted path including type and WUA subpath. Intended for logging and user-facing information\n\tstd::string GetInstallPath() const; // installation subpath, relative to storage base. E.g. \"usr/title/.../...\" or \"sys/title/.../...\"\n\n\tstatic std::string GetUniqueTempMountingPath();\n\tstatic bool ParseWuaTitleFolderName(std::string_view name, TitleId& titleIdOut, uint16& titleVersionOut);\n\nprivate:\n\tvoid Copy(const TitleInfo& other)\n\t{\n\t\tm_isValid = other.m_isValid;\n\t\tm_titleFormat = other.m_titleFormat;\n\t\tm_fullPath = other.m_fullPath;\n\t\tm_subPath = other.m_subPath;\n\t\tm_hasParsedXmlFiles = other.m_hasParsedXmlFiles;\n\t\tm_parsedMetaXml = nullptr;\n\t\tm_parsedAppXml = nullptr;\n\n\t\tif (other.m_parsedMetaXml)\n\t\t\tm_parsedMetaXml = new ParsedMetaXml(*other.m_parsedMetaXml);\n\t\tif (other.m_parsedAppXml)\n\t\t\tm_parsedAppXml = new ParsedAppXml(*other.m_parsedAppXml);\n\t\tif (other.m_parsedCosXml)\n\t\t\tm_parsedCosXml = new ParsedCosXml(*other.m_parsedCosXml);\n\n\t\tif (other.m_cachedInfo)\n\t\t\tm_cachedInfo = new CachedInfo(*other.m_cachedInfo);\n\n\t\tm_mountpoints.clear();\n\t\tm_wudVolume = nullptr;\n\t}\n\n\tbool DetectFormat(const fs::path& path, fs::path& pathOut, TitleDataFormat& formatOut);\n\tvoid CalcUID();\n\tvoid SetInvalidReason(InvalidReason reason);\n\tParsedMetaXml* ParseAromaIni(std::span<unsigned char> content);\n\tbool ParseAppXml(std::vector<uint8>& appXmlData);\n\n\tbool m_isValid{ false };\n\tTitleDataFormat m_titleFormat{ TitleDataFormat::INVALID_STRUCTURE };\n\tfs::path m_fullPath;\n\tstd::string m_subPath; // used for formats where fullPath isn't unique on its own (like WUA)\n\tuint64 m_uid{};\n\tInvalidReason m_invalidReason{ InvalidReason::NONE }; // if m_isValid == false, this contains a more detailed error code\n\t// mounting info\n\tstd::vector<std::pair<sint32, std::string>> m_mountpoints;\n\tclass FSTVolume* m_wudVolume{};\n\tclass ZArchiveReader* m_zarchive{};\n\tclass WUHBReader* m_wuhbreader{};\n\t// xml info\n\tbool m_hasParsedXmlFiles{ false };\n\tParsedMetaXml* m_parsedMetaXml{};\n\tParsedAppXml* m_parsedAppXml{};\n\tParsedCosXml* m_parsedCosXml{};\n\t// cached info if called with cache constructor\n\tCachedInfo* m_cachedInfo{nullptr};\n};"
  },
  {
    "path": "src/Cafe/TitleList/TitleList.cpp",
    "content": "#include \"TitleList.h\"\n#include \"Common/FileStream.h\"\n\n#include \"util/helpers/helpers.h\"\n\n#include <zarchive/zarchivereader.h>\n\nbool sTLInitialized{ false };\nfs::path sTLCacheFilePath;\n\n// lists for tracking known titles\n// note: The list may only contain titles with valid meta data (except for certain system titles). Entries loaded from the cache may not have been parsed yet, but they will use a cached value for titleId and titleVersion\nstd::mutex sTLMutex;\nstd::vector<TitleInfo*> sTLList;\nstd::vector<TitleInfo*> sTLListPending;\nstd::unordered_multimap<uint64, TitleInfo*> sTLMap;\nbool sTLCacheDirty{false};\n\n// paths\nfs::path sTLMLCPath;\nstd::vector<fs::path> sTLScanPaths;\n\n// worker\nstd::thread sTLRefreshWorker;\nbool sTLRefreshWorkerActive{false};\nstd::atomic_uint32_t sTLRefreshRequests{};\nstd::atomic_bool sTLIsScanMandatory{ false };\n\n// callback list\nstruct TitleListCallbackEntry \n{\n\tTitleListCallbackEntry(void(*cb)(CafeTitleListCallbackEvent* evt, void* ctx), void* ctx, uint64 uniqueId) :\n\t\tcb(cb), ctx(ctx), uniqueId(uniqueId) {};\n\tvoid (*cb)(CafeTitleListCallbackEvent* evt, void* ctx);\n\tvoid* ctx;\n\tuint64 uniqueId;\n};\n\nstd::vector<TitleListCallbackEntry> sTLCallbackList;\n\nvoid CafeTitleList::Initialize(const fs::path cacheXmlFile)\n{\n\tstd::unique_lock _lock(sTLMutex);\n\tsTLInitialized = true;\n\tsTLCacheFilePath = cacheXmlFile;\n\tLoadCacheFile();\n}\n\nvoid CafeTitleList::LoadCacheFile()\n{\n\tsTLIsScanMandatory = true;\n\tcemu_assert_debug(sTLInitialized);\n\tcemu_assert_debug(sTLList.empty());\n\tauto xmlData = FileStream::LoadIntoMemory(sTLCacheFilePath);\n\tif (!xmlData)\n\t\treturn;\n\tpugi::xml_document doc;\n\tif (!doc.load_buffer_inplace(xmlData->data(), xmlData->size(), pugi::parse_default, pugi::xml_encoding::encoding_utf8))\n\t\treturn;\n\tauto titleListNode = doc.child(\"title_list\");\n\tpugi::xml_node itNode = titleListNode.first_child();\n\tfor (const auto& titleInfoNode : doc.child(\"title_list\"))\n\t{\n\t\tTitleId titleId;\n\t\tif( !TitleIdParser::ParseFromStr(titleInfoNode.attribute(\"titleId\").as_string(), titleId))\n\t\t\tcontinue;\n\t\tuint16 titleVersion = titleInfoNode.attribute(\"version\").as_uint();\n\t\tuint32 sdkVersion = titleInfoNode.attribute(\"sdk_version\").as_uint();\n\t\tTitleInfo::TitleDataFormat format = (TitleInfo::TitleDataFormat)ConvertString<uint32>(titleInfoNode.child_value(\"format\"));\n\t\tCafeConsoleRegion region = (CafeConsoleRegion)ConvertString<uint32>(titleInfoNode.child_value(\"region\"));\n\t\tstd::string name = titleInfoNode.child_value(\"name\");\n\t\tstd::string path = titleInfoNode.child_value(\"path\");\n\t\tstd::string sub_path = titleInfoNode.child_value(\"sub_path\");\n\t\tuint32 group_id = ConvertString<uint32>(titleInfoNode.attribute(\"group_id\").as_string(), 16);\n\t\tuint32 app_type = ConvertString<uint32>(titleInfoNode.attribute(\"app_type\").as_string(), 16);\n\n\t\tTitleInfo::CachedInfo cacheEntry;\n\t\tcacheEntry.titleId = titleId;\n\t\tcacheEntry.titleVersion = titleVersion;\n\t\tcacheEntry.sdkVersion = sdkVersion;\n\t\tcacheEntry.titleDataFormat = format;\n\t\tcacheEntry.region = region;\n\t\tcacheEntry.titleName = std::move(name);\n\t\tcacheEntry.path = _utf8ToPath(path);\n\t\tcacheEntry.subPath = std::move(sub_path);\n\t\tcacheEntry.group_id = group_id;\n\t\tcacheEntry.app_type = app_type;\n\n\t\tTitleInfo* ti = new TitleInfo(cacheEntry);\n\t\tif (!ti->IsValid())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Title cache contained invalid title\");\n\t\t\tdelete ti;\n\t\t\tcontinue;\n\t\t}\n\t\tAddTitle(ti);\n\t}\n\tsTLIsScanMandatory = false;\n}\n\nvoid CafeTitleList::StoreCacheFile()\n{\n\tcemu_assert_debug(sTLInitialized);\n\tif (sTLCacheFilePath.empty())\n\t\treturn;\n\tstd::unique_lock _lock(sTLMutex);\n\n\tpugi::xml_document doc;\n\tauto declarationNode = doc.append_child(pugi::node_declaration);\n\tdeclarationNode.append_attribute(\"version\") = \"1.0\";\n\tdeclarationNode.append_attribute(\"encoding\") = \"UTF-8\";\n\tauto title_list_node = doc.append_child(\"title_list\");\n\n\tfor (auto& tiIt : sTLList)\n\t{\n\t\tTitleInfo::CachedInfo info = tiIt->MakeCacheEntry();\n\t\tauto titleInfoNode = title_list_node.append_child(\"title\");\n\t\ttitleInfoNode.append_attribute(\"titleId\").set_value(fmt::format(\"{:016x}\", info.titleId).c_str());\n\t\ttitleInfoNode.append_attribute(\"version\").set_value(fmt::format(\"{:}\", info.titleVersion).c_str());\n\t\ttitleInfoNode.append_attribute(\"sdk_version\").set_value(fmt::format(\"{:}\", info.sdkVersion).c_str());\n\t\ttitleInfoNode.append_attribute(\"group_id\").set_value(fmt::format(\"{:08x}\", info.group_id).c_str());\n\t\ttitleInfoNode.append_attribute(\"app_type\").set_value(fmt::format(\"{:08x}\", info.app_type).c_str());\n\t\ttitleInfoNode.append_child(\"region\").append_child(pugi::node_pcdata).set_value(fmt::format(\"{}\", (uint32)info.region).c_str());\n\t\ttitleInfoNode.append_child(\"name\").append_child(pugi::node_pcdata).set_value(info.titleName.c_str());\n\t\ttitleInfoNode.append_child(\"format\").append_child(pugi::node_pcdata).set_value(fmt::format(\"{}\", (uint32)info.titleDataFormat).c_str());\n\t\ttitleInfoNode.append_child(\"path\").append_child(pugi::node_pcdata).set_value(_pathToUtf8(info.path).c_str());\n\t\tif(!info.subPath.empty())\n\t\t\ttitleInfoNode.append_child(\"sub_path\").append_child(pugi::node_pcdata).set_value(_pathToUtf8(info.subPath).c_str());\n\t}\n\n\tfs::path tmpPath = fs::path(sTLCacheFilePath.parent_path()).append(fmt::format(\"{}__tmp\", _pathToUtf8(sTLCacheFilePath.filename())));\n\tstd::ofstream fileOut(tmpPath, std::ios::out | std::ios::binary | std::ios::trunc);\n\tif (!fileOut.is_open())\n\t{\n\t\tcemuLog_log(LogType::Force, \"Unable to store title list in {}\", _pathToUtf8(tmpPath));\n\t\treturn;\n\t}\n\tdoc.save(fileOut, \" \", 1, pugi::xml_encoding::encoding_utf8);\n\tfileOut.flush();\n\tfileOut.close();\n\n\tstd::error_code ec;\n\tfs::rename(tmpPath, sTLCacheFilePath, ec);\n}\n\nvoid CafeTitleList::ClearScanPaths()\n{\n\tstd::unique_lock _lock(sTLMutex);\n\tsTLScanPaths.clear();\n}\n\nvoid CafeTitleList::AddScanPath(fs::path path)\n{\t\n\tstd::unique_lock _lock(sTLMutex);\n\tsTLScanPaths.emplace_back(path);\n}\n\nvoid CafeTitleList::SetMLCPath(fs::path path)\n{\n\tstd::unique_lock _lock(sTLMutex);\n\tstd::error_code ec;\n\tif (!fs::is_directory(path, ec))\n\t{\n\t\tcemuLog_log(LogType::Force, \"MLC set to invalid path: {}\", _pathToUtf8(path));\n\t\treturn;\n\t}\n\tsTLMLCPath = path;\n}\n\nvoid CafeTitleList::Refresh()\n{\n\tstd::unique_lock _lock(sTLMutex);\n\tcemu_assert_debug(sTLInitialized);\n\tsTLRefreshRequests++;\n\tif (!sTLRefreshWorkerActive)\n\t{\n\t\tif (sTLRefreshWorker.joinable())\n\t\t\tsTLRefreshWorker.join();\n\t\tsTLRefreshWorkerActive = true;\n\t\tsTLRefreshWorker = std::thread(RefreshWorkerThread);\n\t}\n\tsTLIsScanMandatory = false;\n}\n\nbool CafeTitleList::IsScanning()\n{\n\tstd::unique_lock _lock(sTLMutex);\n\treturn sTLRefreshWorkerActive;\n}\n\nvoid CafeTitleList::WaitForMandatoryScan()\n{\n\tif (!sTLIsScanMandatory)\n\t\treturn;\n\twhile (IsScanning())\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(100));\n}\n\nvoid _RemoveTitleFromMultimap(TitleInfo* titleInfo)\n{\n\tauto mapRange = sTLMap.equal_range(titleInfo->GetAppTitleId());\n\tfor (auto mapIt = mapRange.first; mapIt != mapRange.second; ++mapIt)\n\t{\n\t\tif (mapIt->second == titleInfo)\n\t\t{\n\t\t\tsTLMap.erase(mapIt);\n\t\t\treturn;\n\t\t}\n\t}\n\tcemu_assert_suspicious();\n}\n\n// check if path is a valid title and if it is, permanently add it to the title list\n// in the special case that path points to a WUA file, all contained titles will be added\nvoid CafeTitleList::AddTitleFromPath(fs::path path)\n{\n\tif (path.has_extension() && boost::iequals(_pathToUtf8(path.extension()), \".wua\"))\n\t{\n\t\tZArchiveReader* zar = ZArchiveReader::OpenFromFile(path);\n\t\tif (!zar)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Found {} but it is not a valid Wii U archive file\", _pathToUtf8(path));\n\t\t\treturn;\n\t\t}\n\t\t// enumerate all contained titles\n\t\tZArchiveNodeHandle rootDir = zar->LookUp(\"\", false, true);\n\t\tcemu_assert(rootDir != ZARCHIVE_INVALID_NODE);\n\t\tfor (uint32 i = 0; i < zar->GetDirEntryCount(rootDir); i++)\n\t\t{\n\t\t\tZArchiveReader::DirEntry dirEntry;\n\t\t\tif( !zar->GetDirEntry(rootDir, i, dirEntry) )\n\t\t\t\tcontinue;\n\t\t\tif(!dirEntry.isDirectory)\n\t\t\t\tcontinue;\n\t\t\tTitleId parsedId;\n\t\t\tuint16 parsedVersion;\n\t\t\tif (!TitleInfo::ParseWuaTitleFolderName(dirEntry.name, parsedId, parsedVersion))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Invalid title directory in {}: \\\"{}\\\"\", _pathToUtf8(path), dirEntry.name);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// valid subdirectory\n\t\t\tTitleInfo* titleInfo = new TitleInfo(path, dirEntry.name);\n\t\t\tif (titleInfo->IsValid())\n\t\t\t\tAddDiscoveredTitle(titleInfo);\n\t\t\telse\n\t\t\t\tdelete titleInfo;\n\t\t}\n\t\tdelete zar;\n\t\treturn;\n\t}\n\tTitleInfo* titleInfo = new TitleInfo(path);\n\tif (titleInfo->IsValid())\n\t\tAddDiscoveredTitle(titleInfo);\n\telse\n\t\tdelete titleInfo;\n}\n\nbool CafeTitleList::RefreshWorkerThread()\n{\n\tSetThreadName(\"TitleListWorker\");\n\twhile (sTLRefreshRequests.load())\n\t{\n\t\tsTLRefreshRequests.store(0);\n\t\t// create copies of all the paths\n\t\tsTLMutex.lock();\n\t\tfs::path mlcPath = sTLMLCPath;\n\t\tstd::vector<fs::path> gamePaths = sTLScanPaths;\n\t\t// remember the current list of known titles\n\t\t// during the scanning process we will erase matches from the pending list\n\t\t// at the end of scanning, we can then use this list to identify and remove any titles that are no longer discoverable\n\t\tsTLListPending = sTLList;\n\t\tsTLMutex.unlock();\n\t\t// scan game paths\n\t\tfor (auto& it : gamePaths)\n\t\t\tScanGamePath(it);\n\t\t// scan MLC\n\t\tif (!mlcPath.empty())\n\t\t{\n\t\t\tstd::error_code ec;\n\t\t\tfor (auto& it : fs::directory_iterator(mlcPath / \"usr/title\", ec))\n\t\t\t{\n\t\t\t\tif (!it.is_directory(ec))\n\t\t\t\t\tcontinue;\n\t\t\t\tScanMLCPath(it.path());\n\t\t\t}\n\t\t\tScanMLCPath(mlcPath / \"sys/title/00050010\");\n\t\t\tScanMLCPath(mlcPath / \"sys/title/00050030\");\n\t\t}\n\n\t\t// remove any titles that are still pending\n\t\tfor (auto& itPending : sTLListPending)\n\t\t{\n\t\t\t_RemoveTitleFromMultimap(itPending);\n\t\t\tstd::erase(sTLList, itPending);\n\t\t}\n\t\t// send notifications for removed titles, but only if there exists no other title with the same titleId and version\n\t\tif (!sTLListPending.empty())\n\t\t\tsTLCacheDirty = true;\n\t\tfor (auto& itPending : sTLListPending)\n\t\t{\n\t\t\tCafeTitleListCallbackEvent evt;\n\t\t\tevt.eventType = CafeTitleListCallbackEvent::TYPE::TITLE_REMOVED;\n\t\t\tevt.titleInfo = itPending;\n\t\t\tfor (auto& it : sTLCallbackList)\n\t\t\t\tit.cb(&evt, it.ctx);\n\t\t\tdelete itPending;\n\t\t}\n\t\tsTLListPending.clear();\n\t}\n\tsTLMutex.lock();\n\tsTLRefreshWorkerActive = false;\n\t// send notification that scanning finished\n\tCafeTitleListCallbackEvent evt;\n\tevt.eventType = CafeTitleListCallbackEvent::TYPE::SCAN_FINISHED;\n\tevt.titleInfo = nullptr;\n\tfor (auto& it : sTLCallbackList)\n\t\tit.cb(&evt, it.ctx);\n\tsTLMutex.unlock();\n\tif (sTLCacheDirty)\n\t{\n\t\tStoreCacheFile();\n\t\tsTLCacheDirty = false;\n\t}\n\treturn true;\n}\n\nbool _IsKnownFileNameOrExtension(const fs::path& path)\n{\n\tstd::string fileExtension = _pathToUtf8(path.extension());\n\tfor (auto& it : fileExtension)\n\t\tit = _ansiToLower(it);\n\tif(fileExtension == \".tmd\")\n\t{\n\t\t// must be \"title.tmd\"\n\t\tstd::string fileName = _pathToUtf8(path.filename());\n\t\tfor (auto& it : fileName)\n\t\t\tit = _ansiToLower(it);\n\t\treturn fileName == \"title.tmd\";\n\t}\n\treturn\n\t\tfileExtension == \".wud\" ||\n\t\tfileExtension == \".wux\" ||\n\t\tfileExtension == \".iso\" ||\n\t\tfileExtension == \".wua\" ||\n\t\tfileExtension == \".wuhb\";\n\t// note: To detect extracted titles with RPX we rely on the presence of the content,code,meta directory structure\n}\n\nvoid CafeTitleList::ScanGamePath(const fs::path& path)\n{\n\t// scan the whole directory first to determine if this is a title folder\n\tstd::vector<fs::path> filesInDirectory;\n\tstd::vector<fs::path> dirsInDirectory;\n\tbool hasContentFolder = false, hasCodeFolder = false, hasMetaFolder = false;\n\tstd::error_code ec;\n\tfor (auto& it : fs::directory_iterator(path, ec))\n\t{\t\t\n\t\tif (it.is_regular_file(ec))\n\t\t{\n\t\t\tfilesInDirectory.emplace_back(it.path());\n\t\t}\n\t\telse if (it.is_directory(ec))\n\t\t{\n\t\t\tdirsInDirectory.emplace_back(it.path());\n\t\t\tstd::string dirName = _pathToUtf8(it.path().filename());\n\t\t\tif (boost::iequals(dirName, \"content\"))\n\t\t\t\thasContentFolder = true;\n\t\t\telse if (boost::iequals(dirName, \"code\"))\n\t\t\t\thasCodeFolder = true;\n\t\t\telse if (boost::iequals(dirName, \"meta\"))\n\t\t\t\thasMetaFolder = true;\n\t\t}\n\t}\n\t// always check individual files\n\tfor (auto& it : filesInDirectory)\n\t{\n\t\t// since checking individual files is slow, we limit it to known file names or extensions\n\t\tif (!it.has_extension())\n\t\t\tcontinue;\n\t\tif (!_IsKnownFileNameOrExtension(it))\n\t\t\tcontinue;\n\t\tAddTitleFromPath(it);\n\t}\n\t// is the current directory a title folder?\n\tif (hasContentFolder && hasCodeFolder && hasMetaFolder)\n\t{\n\t\t// verify if this folder is a valid title\n\t\tTitleInfo* titleInfo = new TitleInfo(path);\n\t\tif (titleInfo->IsValid())\n\t\t\tAddDiscoveredTitle(titleInfo);\n\t\telse\n\t\t\tdelete titleInfo;\n\t\t// if there are other folders besides content/code/meta then traverse those\n\t\tif (dirsInDirectory.size() > 3)\n\t\t{\n\t\t\tfor (auto& it : dirsInDirectory)\n\t\t\t{\n\t\t\t\tstd::string dirName = _pathToUtf8(it.filename());\n\t\t\t\tif (!boost::iequals(dirName, \"content\") &&\n\t\t\t\t\t!boost::iequals(dirName, \"code\") &&\n\t\t\t\t\t!boost::iequals(dirName, \"meta\"))\n\t\t\t\t\tScanGamePath(it);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// scan subdirectories\n\t\tfor (auto& it : dirsInDirectory)\n\t\t\tScanGamePath(it);\n\t}\n}\n\nvoid CafeTitleList::ScanMLCPath(const fs::path& path)\n{\n\tstd::error_code ec;\n\tfor (auto& it : fs::directory_iterator(path, ec))\n\t{\n\t\tif (!it.is_directory())\n\t\t\tcontinue;\n\t\t// only scan directories which match the title id naming scheme\n\t\tstd::string dirName = _pathToUtf8(it.path().filename());\n\t\tif(dirName.size() != 8)\n\t\t\tcontinue;\n\t\tbool containsNoHexCharacter = false;\n\t\tfor (auto& it : dirName)\n\t\t{\n\t\t\tif(it >= 'A' && it <= 'F' ||\n\t\t\t\tit >= 'a' && it <= 'f' ||\n\t\t\t\tit >= '0' && it <= '9')\n\t\t\t\tcontinue;\n\t\t\tcontainsNoHexCharacter = true;\n\t\t\tbreak;\n\t\t}\n\t\tif(containsNoHexCharacter)\n\t\t\tcontinue;\n\n\t\tif (fs::is_directory(it.path() / \"code\", ec) &&\n\t\t\tfs::is_directory(it.path() / \"content\", ec) &&\n\t\t\tfs::is_directory(it.path() / \"meta\", ec))\n\t\t{\n\t\t\tTitleInfo* titleInfo = new TitleInfo(it);\n\t\t\tif (titleInfo->IsValid() && titleInfo->ParseXmlInfo())\n\t\t\t\tAddDiscoveredTitle(titleInfo);\n\t\t\telse\n\t\t\t\tdelete titleInfo;\n\t\t}\n\t}\n}\n\nvoid CafeTitleList::AddDiscoveredTitle(TitleInfo* titleInfo)\n{\n\tcemu_assert_debug(titleInfo->ParseXmlInfo());\n\tstd::unique_lock _lock(sTLMutex);\n\t// remove from pending list\n\tauto pendingIt = std::find_if(sTLListPending.begin(), sTLListPending.end(), [titleInfo](const TitleInfo* it) { return it->IsEqualByLocation(*titleInfo); });\n\tif (pendingIt != sTLListPending.end())\n\t\tsTLListPending.erase(pendingIt);\n\tAddTitle(titleInfo);\t\n}\n\nvoid CafeTitleList::AddTitle(TitleInfo* titleInfo)\n{\n\t// check if title is already known\n\tif (titleInfo->IsCached())\n\t{\n\t\tbool isKnown = std::any_of(sTLList.cbegin(), sTLList.cend(), [&titleInfo](const TitleInfo* ti) { return titleInfo->IsEqualByLocation(*ti); });\n\t\tif (isKnown)\n\t\t{\n\t\t\tdelete titleInfo;\n\t\t\treturn;\n\t\t}\n\t}\n\telse\n\t{\n\t\tauto it = std::find_if(sTLList.begin(), sTLList.end(), [titleInfo](const TitleInfo* it) { return it->IsEqualByLocation(*titleInfo); });\n\t\tif (it != sTLList.end())\n\t\t{\n\t\t\tif ((*it)->IsCached())\n\t\t\t{\n\t\t\t\t// replace cached entry with newly parsed title\n\t\t\t\tTitleInfo* deletedInfo = *it;\n\t\t\t\tsTLList.erase(it);\n\t\t\t\t_RemoveTitleFromMultimap(deletedInfo);\n\t\t\t\tdelete deletedInfo;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// title already known\n\t\t\t\tdelete titleInfo;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\tsTLList.emplace_back(titleInfo);\n\tsTLMap.emplace(titleInfo->GetAppTitleId(), titleInfo);\n\t// send out notification\n\tCafeTitleListCallbackEvent evt;\n\tevt.eventType = CafeTitleListCallbackEvent::TYPE::TITLE_DISCOVERED;\n\tevt.titleInfo = titleInfo;\n\tfor (auto& it : sTLCallbackList)\n\t\tit.cb(&evt, it.ctx);\n\tsTLCacheDirty = true;\n}\n\nuint64 CafeTitleList::RegisterCallback(void(*cb)(CafeTitleListCallbackEvent* evt, void* ctx), void* ctx)\n{\n\tstatic std::atomic<uint64_t> sCallbackIdGen = 1;\n\tuint64 id = sCallbackIdGen.fetch_add(1);\n\tstd::unique_lock _lock(sTLMutex);\n\tsTLCallbackList.emplace_back(cb, ctx, id);\n\t// immediately notify of all known titles\n\tfor (auto& it : sTLList)\n\t{\n\t\tCafeTitleListCallbackEvent evt;\n\t\tevt.eventType = CafeTitleListCallbackEvent::TYPE::TITLE_DISCOVERED;\n\t\tevt.titleInfo = it;\n\t\tcb(&evt, ctx);\n\t}\n\t// if not scanning then send out scan finished notification\n\tif (!sTLRefreshWorkerActive)\n\t{\n\t\tCafeTitleListCallbackEvent evt;\n\t\tevt.eventType = CafeTitleListCallbackEvent::TYPE::SCAN_FINISHED;\n\t\tevt.titleInfo = nullptr;\n\t\tfor (auto& it : sTLCallbackList)\n\t\t\tit.cb(&evt, it.ctx);\n\t}\n\treturn id;\n}\n\nvoid CafeTitleList::UnregisterCallback(uint64 id)\n{\n\tstd::unique_lock _lock(sTLMutex);\n\tauto it = std::find_if(sTLCallbackList.begin(), sTLCallbackList.end(), [id](auto& e) { return e.uniqueId == id; });\n\tcemu_assert(it != sTLCallbackList.end()); // must be a valid callback\n\tsTLCallbackList.erase(it);\n}\n\nbool CafeTitleList::HasTitle(TitleId titleId, uint16& versionOut)\n{\n\t// todo - optimize?\n\tbool matchFound = false;\n\tversionOut = 0;\n\tstd::unique_lock _lock(sTLMutex);\n\tfor (auto& it : sTLList)\n\t{\n\t\tif (it->GetAppTitleId() == titleId)\n\t\t{\n\t\t\tuint16 titleVersion = it->GetAppTitleVersion();\n\t\t\tif (titleVersion > versionOut)\n\t\t\t\tversionOut = titleVersion;\n\t\t\tmatchFound = true;\n\t\t}\n\t}\n\treturn matchFound;\n}\n\nbool CafeTitleList::HasTitleAndVersion(TitleId titleId, uint16 version)\n{\n\tstd::unique_lock _lock(sTLMutex);\n\tfor (auto& it : sTLList)\n\t{\n\t\tif (it->GetAppTitleId() == titleId && it->GetAppTitleVersion() == version)\n\t\t\treturn true;\n\t}\n\treturn false;\n}\n\nstd::vector<TitleId> CafeTitleList::GetAllTitleIds()\n{\n\tstd::unordered_set<TitleId> visitedTitleIds;\n\tstd::unique_lock _lock(sTLMutex);\n\tstd::vector<TitleId> titleIds;\n\ttitleIds.reserve(sTLList.size());\n\tfor (auto& it : sTLList)\n\t{\n\t\tTitleId tid = it->GetAppTitleId();\n\t\tif (visitedTitleIds.find(tid) != visitedTitleIds.end())\n\t\t\tcontinue;\n\t\ttitleIds.emplace_back(tid);\n\t\tvisitedTitleIds.emplace(tid);\n\t}\n\treturn titleIds;\n}\n\nstd::span<TitleInfo*> CafeTitleList::AcquireInternalList()\n{\n\tsTLMutex.lock();\n\treturn { sTLList.data(), sTLList.size() };\n}\n\nvoid CafeTitleList::ReleaseInternalList()\n{\n\tsTLMutex.unlock();\n}\n\nbool CafeTitleList::GetFirstByTitleId(TitleId titleId, TitleInfo& titleInfoOut)\n{\n\tstd::unique_lock _lock(sTLMutex);\n\tauto it = sTLMap.find(titleId);\n\tif (it != sTLMap.end())\n\t{\n\t\tcemu_assert_debug(it->first == titleId);\n\t\ttitleInfoOut = *it->second;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// takes update or AOC title id and returns the title id of the associated base title\n// this can fail if trying to translate an AOC title id without having the base title meta information\nbool CafeTitleList::FindBaseTitleId(TitleId titleId, TitleId& titleIdBaseOut)\n{\n\ttitleId = TitleIdParser::MakeBaseTitleId(titleId);\n\n\t// aoc to base\n\t// todo - this requires scanning all base titles and their updates to see if they reference this title id\n\t// for now we assume there is a direct match of ids\n\tif (((titleId >> 32) & 0xFF) == 0x0C)\n\t{\n\t\ttitleId &= ~0xFF00000000;\n\t\ttitleId |= 0x0000000000;\n\t}\n\ttitleIdBaseOut = titleId;\n\treturn true;\n}\n\nGameInfo2 CafeTitleList::GetGameInfo(TitleId titleId)\n{\n\tGameInfo2 gameInfo;\n\n\t// find base title id\n\tuint64 baseTitleId;\n\tif (!FindBaseTitleId(titleId, baseTitleId))\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n\t// determine if an optional update title id exists\n\tTitleIdParser tip(baseTitleId);\n\tbool hasSeparateUpdateTitleId = tip.CanHaveSeparateUpdateTitleId();\n\tuint64 updateTitleId = 0;\n\tif (hasSeparateUpdateTitleId)\n\t\tupdateTitleId = tip.GetSeparateUpdateTitleId();\t\n\t// scan the title list for base and update\n\tstd::unique_lock _lock(sTLMutex);\n\tfor (auto& it : sTLList)\n\t{\n\t\tTitleId appTitleId = it->GetAppTitleId();\n\t\tif (appTitleId == baseTitleId)\n\t\t{\n\t\t\tgameInfo.SetBase(*it);\n\t\t}\n\t\tif (hasSeparateUpdateTitleId && appTitleId == updateTitleId)\n\t\t{\n\t\t\tgameInfo.SetUpdate(*it);\n\t\t}\n\t}\n\n\t// if this title can have AOC content then do a second scan\n\t// todo - get a list of all AOC title ids from the base/update meta information\n\t// for now we assume there is a direct match between the base titleId and the aoc titleId\n\tif (tip.CanHaveSeparateUpdateTitleId())\n\t{\n\t\tuint64 aocTitleId = baseTitleId | 0xC00000000;\n\t\tfor (auto& it : sTLList)\n\t\t{\n\t\t\tTitleId appTitleId = it->GetAppTitleId();\n\t\t\tif (appTitleId == aocTitleId)\n\t\t\t{\n\t\t\t\tgameInfo.AddAOC(*it); // stores the AOC with the highest title version\n\t\t\t}\n\t\t}\n\t}\n\treturn gameInfo;\n}\n\nTitleInfo CafeTitleList::GetTitleInfoByUID(uint64 uid)\n{\n\tTitleInfo titleInfo;\n\tstd::unique_lock _lock(sTLMutex);\n\tfor (auto& it : sTLList)\n\t{\n\t\tif (it->GetUID() == uid)\n\t\t{\n\t\t\ttitleInfo = *it;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn titleInfo;\n}"
  },
  {
    "path": "src/Cafe/TitleList/TitleList.h",
    "content": "#pragma once\n\n#include \"TitleInfo.h\"\n#include \"GameInfo.h\"\n\nstruct CafeTitleListCallbackEvent\n{\n\tenum class TYPE\n\t{\n\t\tTITLE_DISCOVERED,\n\t\tTITLE_REMOVED,\n\t\tSCAN_FINISHED,\n\t};\n\tTYPE eventType;\n\tTitleInfo* titleInfo;\n};\n\nclass CafeTitleList\n{\npublic:\n\n\tstatic void Initialize(const fs::path cacheXmlFile);\n\tstatic void LoadCacheFile();\n\tstatic void StoreCacheFile();\n\n\tstatic void ClearScanPaths();\n\tstatic void AddScanPath(fs::path path);\n\tstatic void SetMLCPath(fs::path path);\n\tstatic void Refresh(); // scan all paths\n\tstatic bool IsScanning(); // returns true if async refresh is currently active\n\tstatic void WaitForMandatoryScan(); // wait for current scan result if no cached info is available\n\tstatic void AddTitleFromPath(fs::path path);\n\n\tstatic uint64 RegisterCallback(void(*cb)(CafeTitleListCallbackEvent* evt, void* ctx), void* ctx); // on register, the callback will be invoked for every already known title\n\tstatic void UnregisterCallback(uint64 id);\n\n\t// utility functions\n\tstatic bool HasTitle(TitleId titleId, uint16& versionOut);\n\tstatic bool HasTitleAndVersion(TitleId titleId, uint16 version);\n\tstatic std::vector<TitleId> GetAllTitleIds();\n\tstatic bool GetFirstByTitleId(TitleId titleId, TitleInfo& titleInfoOut);\n\tstatic bool FindBaseTitleId(TitleId titleId, TitleId& titleIdBaseOut);\n\n\tstatic std::span<TitleInfo*> AcquireInternalList();\n\tstatic void ReleaseInternalList();\n\n\tstatic GameInfo2 GetGameInfo(TitleId titleId);\n\tstatic TitleInfo GetTitleInfoByUID(uint64 uid);\n\nprivate:\n\tstatic bool RefreshWorkerThread();\n\tstatic void ScanGamePath(const fs::path& path);\n\tstatic void ScanMLCPath(const fs::path& path);\n\n\tstatic void AddDiscoveredTitle(TitleInfo* titleInfo);\n\tstatic void AddTitle(TitleInfo* titleInfo);\n};"
  },
  {
    "path": "src/Cemu/CMakeLists.txt",
    "content": "add_library(CemuComponents\n  ExpressionParser/ExpressionParser.cpp\n  ExpressionParser/ExpressionParser.h\n  FileCache/FileCache.cpp\n  FileCache/FileCache.h\n  Logging/CemuDebugLogging.h\n  Logging/CemuLogging.cpp\n  Logging/CemuLogging.h\n  napi/napi_act.cpp\n  napi/napi_ec.cpp\n  napi/napi.h\n  napi/napi_helper.cpp\n  napi/napi_helper.h\n  napi/napi_idbe.cpp\n  napi/napi_version.cpp\n  ncrypto/ncrypto.cpp\n  ncrypto/ncrypto.h\n  nex/nex.cpp\n  nex/nexFriends.cpp\n  nex/nexFriends.h\n  nex/nex.h\n  nex/nexThread.cpp\n  nex/nexThread.h\n  nex/nexTypes.h\n  nex/prudp.cpp\n  nex/prudp.h\n  PPCAssembler/ppcAssembler.cpp\n  PPCAssembler/ppcAssembler.h\n  Tools/DownloadManager/DownloadManager.cpp\n  Tools/DownloadManager/DownloadManager.h\n)\n\nif(ENABLE_DISCORD_RPC)\ntarget_sources(CemuComponents PRIVATE\n\t\tDiscordPresence/DiscordPresence.cpp\n\t\tDiscordPresence/DiscordPresence.h\n\t\tDiscordPresence/DiscordRPCLite.cpp\n\t\tDiscordPresence/DiscordRPCLite.h)\nendif()\n\nset_property(TARGET CemuComponents PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\ntarget_include_directories(CemuComponents PUBLIC \"../\")\n\ntarget_link_libraries(CemuComponents PRIVATE\n\tCemuCommon\n  CemuGui\n)\n\n# PUBLIC because fmt/format.h is included in ExpressionParser/ExpressionParser.h\ntarget_link_libraries(CemuComponents PUBLIC fmt::fmt)\n"
  },
  {
    "path": "src/Cemu/DiscordPresence/DiscordPresence.cpp",
    "content": "#include \"DiscordPresence.h\"\n#include \"Common/version.h\"\n#include \"DiscordRPCLite.h\"\n\nDiscordPresence::DiscordPresence()\n{\n\tm_rpcClient = new DiscordRPCLite(\"460807638964371468\");\n\tUpdatePresence(Idling);\n}\n\nDiscordPresence::~DiscordPresence()\n{\n\tClearPresence();\n\tif (m_rpcClient)\n\t\tdelete m_rpcClient;\n}\n\nvoid DiscordPresence::UpdatePresence(State state, const std::string& text) const\n{\n\tif (!m_rpcClient)\n\t\treturn;\n\tDiscordLiteRichPresence discordPresence{};\n\tstd::string stateString, detailsString;\n\tswitch (state)\n\t{\n\tcase Idling:\n\t\tdetailsString = \"Idling\";\n\t\tstateString = \"\";\n\t\tbreak;\n\tcase Playing:\n\t\tdetailsString = \"Ingame\";\n\t\tstateString = \"Playing \" + text;\n\t\tbreak;\n\tdefault:\n\t\tassert(false);\n\t\tbreak;\n\t}\n\tdiscordPresence.details = detailsString;\n\tdiscordPresence.state = stateString;\n\tdiscordPresence.startTimestamp = time(nullptr);\n\tdiscordPresence.largeImageText = BUILD_VERSION_WITH_NAME_STRING;\n\tdiscordPresence.largeImageKey = \"logo_icon_big_png\";\n\tm_rpcClient->UpdateRichPresence(discordPresence);\n}\n\nvoid DiscordPresence::ClearPresence() const\n{\n\tif (!m_rpcClient)\n\t\treturn;\n\tm_rpcClient->ClearRichPresence();\n}"
  },
  {
    "path": "src/Cemu/DiscordPresence/DiscordPresence.h",
    "content": "#pragma once\n\nclass DiscordPresence\n{\npublic:\n\tenum State\n\t{\n\t\tIdling,\n\t\tPlaying,\n\t};\n\n\tDiscordPresence();\n\t~DiscordPresence();\n\n\tvoid UpdatePresence(State state, const std::string& text = {}) const;\n\tvoid ClearPresence() const;\n\nprivate:\n\tclass DiscordRPCLite* m_rpcClient = nullptr;\n};\n"
  },
  {
    "path": "src/Cemu/DiscordPresence/DiscordRPCLite.cpp",
    "content": "#include \"DiscordRPCLite.h\"\n\n#include <string_view>\n#include <optional>\n#include <chrono>\n\n#if defined(__cpp_lib_format)\n#include <format>\nnamespace shim\n{\n\tusing std::format;\n}\n#else\n#include <fmt/format.h>\nnamespace shim\n{\n\tusing fmt::format;\n}\n#endif\n\n#ifdef _WIN32\n#include <windows.h>\n#else\n#include <fcntl.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#endif\n\nenum RPCOpcode : uint32_t\n{\n\tOpcodeHandshake = 0,\n\tOpcodeFrame = 1,\n\tOpcodeClose = 2,\n\tOpcodePing = 3,\n\tOpcodePong = 4,\n};\n\n#ifdef _WIN32\nclass NamedPipeImpl\n{\n  public:\n\tNamedPipeImpl()\n\t{\n\t\tm_readEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);\n\t}\n\n\t~NamedPipeImpl()\n\t{\n\t\tCloseHandle(m_readEvent);\n\t\tClosePipe();\n\t}\n\n\tbool OpenPipe()\n\t{\n\t\tstd::string fullPipeName = R\"(\\\\.\\pipe\\discord-ipc-0)\";\n\t\tm_handle = CreateFileA(fullPipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);\n\t\tif (m_handle == INVALID_HANDLE_VALUE)\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\n\tvoid ClosePipe()\n\t{\n\t\tif (m_handle != INVALID_HANDLE_VALUE)\n\t\t{\n\t\t\tCloseHandle(m_handle);\n\t\t\tm_handle = INVALID_HANDLE_VALUE;\n\t\t}\n\t}\n\n\tbool IsOpen() const\n\t{\n\t\treturn m_handle != INVALID_HANDLE_VALUE;\n\t}\n\n\tint Read(uint8_t* buffer, size_t maxSize, int timeoutMs)\n\t{\n\t\tif (m_handle == INVALID_HANDLE_VALUE || m_readEvent == nullptr)\n\t\t\treturn -1;\n\t\tOVERLAPPED overlapped = {0};\n\t\toverlapped.hEvent = m_readEvent;\n\t\tResetEvent(m_readEvent);\n\t\tDWORD bytesRead = 0;\n\t\tBOOL success = ReadFile(m_handle, buffer, static_cast<DWORD>(maxSize), nullptr, &overlapped);\n\t\tif (!success && GetLastError() == ERROR_IO_PENDING)\n\t\t{\n\t\t\tDWORD waitResult = WaitForSingleObject(m_readEvent, timeoutMs);\n\t\t\tif (waitResult == WAIT_TIMEOUT)\n\t\t\t{\n\t\t\t\tCancelIo(m_handle);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\telse if (waitResult != WAIT_OBJECT_0) // error\n\t\t\t{\n\t\t\t\tClosePipe();\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif (!GetOverlappedResult(m_handle, &overlapped, &bytesRead, FALSE))\n\t\t\t{\n\t\t\t\tClosePipe();\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t\telse if (!success)\n\t\t{\n\t\t\tClosePipe();\n\t\t\treturn -1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tGetOverlappedResult(m_handle, &overlapped, &bytesRead, FALSE); // immediate completion\n\t\t}\n\t\treturn static_cast<int>(bytesRead);\n\t}\n\n\tint Write(const uint8_t* buffer, size_t size)\n\t{\n\t\tif (m_handle == INVALID_HANDLE_VALUE)\n\t\t{\n\t\t\treturn -1;\n\t\t}\n\t\tDWORD bytesWritten = 0;\n\t\tif (!WriteFile(m_handle, buffer, static_cast<DWORD>(size), &bytesWritten, nullptr))\n\t\t{\n\t\t\tClosePipe();\n\t\t\treturn -1;\n\t\t}\n\t\treturn static_cast<int>(bytesWritten);\n\t}\n\n  private:\n\tHANDLE m_handle = INVALID_HANDLE_VALUE;\n\tHANDLE m_readEvent;\n};\n\n#else\n\nclass NamedPipeImpl // posix\n{\n  public:\n\tNamedPipeImpl() {}\n\t~NamedPipeImpl()\n\t{\n\t\tClosePipe();\n\t}\n\n\tbool OpenPipe()\n\t{\n\t\tconst char* tempPath = getenv(\"XDG_RUNTIME_DIR\");\n\t\tif (!tempPath)\n\t\t\ttempPath = getenv(\"TMPDIR\");\n\t\tif (!tempPath)\n\t\t\ttempPath = getenv(\"TMP\");\n\t\tif (!tempPath)\n\t\t\ttempPath = getenv(\"TEMP\");\n\t\tif (!tempPath)\n\t\t\ttempPath = \"/tmp\";\n\t\tsockaddr_un pipeAddr{};\n\t\tpipeAddr.sun_family = AF_UNIX;\n\t\tm_fd = socket(AF_UNIX, SOCK_STREAM, 0);\n\t\tif (m_fd == -1)\n\t\t\treturn false;\n\t\tfcntl(m_fd, F_SETFL, O_NONBLOCK);\n#ifdef SO_NOSIGPIPE\n\t\tint optval = 1;\n\t\tsetsockopt(m_fd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval));\n#endif\n\t\tfor (int pipeIndex = 0; pipeIndex < 10; pipeIndex++)\n\t\t{\n\t\t\tsnprintf(pipeAddr.sun_path, sizeof(pipeAddr.sun_path), \"%s/discord-ipc-%d\", tempPath, pipeIndex);\n\t\t\tint r = connect(m_fd, (const sockaddr*)&pipeAddr, sizeof(pipeAddr));\n\t\t\tif (r == 0)\n\t\t\t\treturn true;\n\t\t}\n\t\tClosePipe();\n\t\treturn false;\n\t}\n\n\tvoid ClosePipe()\n\t{\n\t\tif (m_fd != -1)\n\t\t{\n\t\t\tclose(m_fd);\n\t\t\tm_fd = -1;\n\t\t}\n\t}\n\n\tbool IsOpen() const\n\t{\n\t\treturn m_fd != -1;\n\t}\n\n\tint Read(uint8_t* buffer, size_t maxSize, int timeoutMs)\n\t{\n\t\tif (m_fd == -1)\n\t\t\treturn -1;\n\t\tif (!buffer || maxSize == 0)\n\t\t\treturn -1;\n\t\tstruct pollfd pfd;\n\t\tpfd.fd = m_fd;\n\t\tpfd.events = POLLIN;\n\t\tpfd.revents = 0;\n\t\tint ret = poll(&pfd, 1, timeoutMs);\n\t\tif (ret < 0)\n\t\t{\n\t\t\tClosePipe();\n\t\t\treturn -1;\n\t\t}\n\t\telse if (ret == 0)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\t\telse if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL))\n\t\t{\n\t\t\tClosePipe();\n\t\t\treturn -1;\n\t\t}\n#ifdef MSG_NOSIGNAL\n\t\tint MsgFlags = MSG_NOSIGNAL;\n#else\n\t\tint MsgFlags = 0;\n#endif\n\t\tint res = (int)recv(m_fd, buffer, maxSize, MsgFlags);\n\t\tif (res <= 0)\n\t\t{\n\t\t\tClosePipe();\n\t\t\treturn -1;\n\t\t}\n\t\treturn res;\n\t}\n\n\tint Write(const uint8_t* buffer, size_t size)\n\t{\n\t\tif (m_fd == -1 || !buffer || size == 0)\n\t\t\treturn -1;\n#ifdef MSG_NOSIGNAL\n\t\tint MsgFlags = MSG_NOSIGNAL;\n#else\n\t\tint MsgFlags = 0;\n#endif\n\t\tint sentBytes = send(m_fd, buffer, size, MsgFlags);\n\t\tif (sentBytes == -1)\n\t\t{\n\t\t\tClosePipe();\n\t\t\treturn -1;\n\t\t}\n\t\treturn sentBytes;\n\t}\n\n  private:\n\tint m_fd = -1;\n};\n\n#endif\n\n#ifdef _WIN32\nint GetProcessId()\n{\n\treturn (int)GetCurrentProcessId();\n}\n#else\nint GetProcessId()\n{\n\treturn getpid();\n}\n#endif\n\nclass NamedPipe : public NamedPipeImpl\n{\n  public:\n\tNamedPipe()\n\t\t: NamedPipeImpl() {};\n\n\tvoid SendJsonMsg(uint32_t opcode, std::string_view jsonText)\n\t{\n\t\tstd::vector<uint8_t> buffer;\n\t\tbuffer.resize(8 + jsonText.size());\n\t\tbuffer[0] = (opcode >> 0) & 0xFF;\n\t\tbuffer[1] = (opcode >> 8) & 0xFF;\n\t\tbuffer[2] = (opcode >> 16) & 0xFF;\n\t\tbuffer[3] = (opcode >> 24) & 0xFF;\n\t\tuint32_t length = static_cast<uint32_t>(jsonText.size());\n\t\tbuffer[4] = (length >> 0) & 0xFF;\n\t\tbuffer[5] = (length >> 8) & 0xFF;\n\t\tbuffer[6] = (length >> 16) & 0xFF;\n\t\tbuffer[7] = (length >> 24) & 0xFF;\n\t\tstd::copy(jsonText.begin(), jsonText.end(), buffer.begin() + 8);\n\t\tWrite(buffer.data(), buffer.size());\n\t}\n\n\tvoid SendPresenceUpdate(const DiscordLiteRichPresence& presence)\n\t{\n\t\t// note: According to older documentation SET_ACTIVITY has a rate limit of 15 seconds\n\t\tstd::string jsonPayload;\n\t\tjsonPayload.append(\"{\");\n\t\tjsonPayload.append(R\"(\"cmd\": \"SET_ACTIVITY\")\");\n\t\tjsonPayload.append(shim::format(R\"(,\"nonce\": \"{}\")\", GetNonceStr()));\n\t\tjsonPayload.append(R\"(,\"args\": {)\");\n\t\t// args\n\t\tstd::string pidStr = shim::format(\"{}\", GetProcessId());\n\t\tjsonPayload.append(R\"(\"pid\": )\").append(pidStr).append(R\"(,)\");\n\t\t// args->activity\n\t\tif (!presence.state.empty() || !presence.details.empty())\n\t\t{\n\t\t\tjsonPayload.append(R\"(\"activity\": {)\");\n\t\t\tif (!presence.state.empty())\n\t\t\t\tjsonPayload.append(shim::format(R\"(\"state\": \"{}\",)\", presence.state));\n\t\t\tif (!presence.details.empty())\n\t\t\t\tjsonPayload.append(shim::format(R\"(\"details\": \"{}\",)\", presence.details));\n\t\t\tif (presence.startTimestamp || presence.endTimestamp)\n\t\t\t{\n\t\t\t\tjsonPayload.append(R\"(\"timestamps\": {)\");\n\t\t\t\tif (presence.startTimestamp)\n\t\t\t\t\tjsonPayload.append(shim::format(R\"(\"start\": {},)\", presence.startTimestamp));\n\t\t\t\tif (presence.endTimestamp)\n\t\t\t\t\tjsonPayload.append(shim::format(R\"(\"end\": {},)\", presence.endTimestamp));\n\t\t\t\tif (jsonPayload.back() == ',')\n\t\t\t\t\tjsonPayload.pop_back();\n\t\t\t\tjsonPayload.append(\"},\");\n\t\t\t}\n\t\t\tif (!presence.largeImageKey.empty() && !presence.largeImageText.empty() && !presence.smallImageKey.empty() && !presence.smallImageText.empty())\n\t\t\t{\n\t\t\t\tjsonPayload.append(R\"(\"assets\": {)\");\n\t\t\t\tjsonPayload.append(shim::format(R\"(\"large_image\": \"{}\",)\", presence.largeImageKey));\n\t\t\t\tjsonPayload.append(shim::format(R\"(\"large_text\": \"{}\",)\", presence.largeImageText));\n\t\t\t\tjsonPayload.append(shim::format(R\"(\"small_image\": \"{}\",)\", presence.smallImageKey));\n\t\t\t\tjsonPayload.append(shim::format(R\"(\"small_text\": \"{}\",)\", presence.smallImageText));\n\t\t\t\tjsonPayload.append(\"},\");\n\t\t\t}\n\t\t\t// party\n\t\t\tif (!presence.partyId.empty() || (presence.partySize > 0 && presence.partyMax > 0))\n\t\t\t{\n\t\t\t\tjsonPayload.append(R\"(\"party\": {)\");\n\t\t\t\tif (!presence.partyId.empty())\n\t\t\t\t\tjsonPayload.append(shim::format(R\"(\"id\": \"{}\",)\", presence.partyId));\n\t\t\t\tif (presence.partySize > 0 && presence.partyMax > 0)\n\t\t\t\t\tjsonPayload.append(shim::format(R\"(\"size\": [{}, {}],)\", presence.partySize, presence.partyMax));\n\t\t\t\tjsonPayload.append(R\"(\"privacy\": )\").append(std::to_string(presence.partyPrivacy)).append(\",\");\n\t\t\t\tjsonPayload.append(\"},\");\n\t\t\t}\n\t\t\t// match secret\n\t\t\tif (!presence.matchSecret.empty() || !presence.joinSecret.empty() || !presence.spectateSecret.empty())\n\t\t\t{\n\t\t\t\tjsonPayload.append(R\"(\"secrets\": {)\");\n\t\t\t\tif (!presence.matchSecret.empty())\n\t\t\t\t\tjsonPayload.append(shim::format(R\"(\"match\": \"{}\",)\", presence.matchSecret));\n\t\t\t\tif (!presence.joinSecret.empty())\n\t\t\t\t\tjsonPayload.append(shim::format(R\"(\"join\": \"{}\",)\", presence.joinSecret));\n\t\t\t\tif (!presence.spectateSecret.empty())\n\t\t\t\t\tjsonPayload.append(shim::format(R\"(\"spectate\": \"{}\",)\", presence.spectateSecret));\n\t\t\t\tif (jsonPayload.back() == ',')\n\t\t\t\t\tjsonPayload.pop_back();\n\t\t\t\tjsonPayload.append(\"},\");\n\t\t\t}\n\t\t\tif (jsonPayload.back() == ',')\n\t\t\t\tjsonPayload.pop_back();\n\t\t\t// end of args->activity\n\t\t\tjsonPayload.append(\"}\");\n\t\t}\n\t\tif (jsonPayload.back() == ',')\n\t\t\tjsonPayload.pop_back();\n\t\tjsonPayload.append(\"}}\");\n\t\tSendJsonMsg(OpcodeFrame, jsonPayload);\n\t}\n\n  private:\n\tstd::string GetNonceStr()\n\t{\n\t\tstd::string nonceStr = shim::format(\"{:016x}\", nonce);\n\t\tnonce++;\n\t\treturn nonceStr;\n\t}\n\tint64_t nonce = 1;\n};\n\nstatic std::optional<std::string> ParseJSONField(std::string_view json, std::string_view fieldPath)\n{\n\tsize_t pos = 0;\n\tauto skipWhitespace = [&]() {\n\t\twhile (pos < json.size() && isspace(json[pos]))\n\t\t\t++pos;\n\t};\n\tauto nextToken = [&]() -> std::string_view {\n\t\tskipWhitespace();\n\t\tif (pos >= json.size())\n\t\t\treturn \"\";\n\t\tchar c = json[pos];\n\t\tif (c == '{' || c == '}' || c == '[' || c == ']' || c == ':' || c == ',')\n\t\t{\n\t\t\treturn json.substr(pos++, 1);\n\t\t}\n\t\tif (c == '\"')\n\t\t{\n\t\t\tsize_t start = ++pos;\n\t\t\twhile (pos < json.size() && json[pos] != '\"')\n\t\t\t\t++pos;\n\t\t\tauto tok = json.substr(start, pos > start ? pos - start : 0);\n\t\t\tif (pos < json.size())\n\t\t\t\t++pos;\n\t\t\treturn tok;\n\t\t}\n\t\tsize_t start = pos;\n\t\twhile (pos < json.size() && !isspace(json[pos]) && json[pos] != ',' && json[pos] != '}' && json[pos] != ']')\n\t\t\t++pos;\n\t\treturn json.substr(start, pos - start);\n\t};\n\tauto skipValue = [&]() {\n\t\tskipWhitespace();\n\t\tif (pos >= json.size())\n\t\t\treturn;\n\t\tchar c = json[pos];\n\t\tif (c == '{')\n\t\t{\n\t\t\tint depth = 1;\n\t\t\t++pos;\n\t\t\twhile (pos < json.size() && depth > 0)\n\t\t\t{\n\t\t\t\tauto tok = nextToken();\n\t\t\t\tif (tok == \"{\")\n\t\t\t\t\t++depth;\n\t\t\t\telse if (tok == \"}\")\n\t\t\t\t\t--depth;\n\t\t\t}\n\t\t}\n\t\telse if (c == '[')\n\t\t{\n\t\t\tint depth = 1;\n\t\t\t++pos;\n\t\t\twhile (pos < json.size() && depth > 0)\n\t\t\t{\n\t\t\t\tauto tok = nextToken();\n\t\t\t\tif (tok == \"[\")\n\t\t\t\t\t++depth;\n\t\t\t\telse if (tok == \"]\")\n\t\t\t\t\t--depth;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnextToken();\n\t\t}\n\t};\n\tauto findField = [&](std::string_view key) {\n\t\twhile (true)\n\t\t{\n\t\t\tauto tok = nextToken();\n\t\t\tif (tok == \"}\")\n\t\t\t\treturn false;\n\t\t\tif (tok == \"\")\n\t\t\t\treturn false;\n\t\t\tif (tok == key)\n\t\t\t{\n\t\t\t\tif (nextToken() == \":\")\n\t\t\t\t\treturn true;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (nextToken() != \":\")\n\t\t\t\treturn false;\n\t\t\tskipValue();\n\t\t\tauto sep = nextToken();\n\t\t\tif (sep == \"}\")\n\t\t\t\treturn false;\n\t\t\tif (sep != \",\")\n\t\t\t\treturn false;\n\t\t}\n\t};\n\t// initial \"{\"\n\tskipWhitespace();\n\tif (nextToken() != \"{\")\n\t\treturn std::nullopt;\n\t// traverse the path\n\tsize_t off = 0;\n\twhile (off <= fieldPath.size())\n\t{\n\t\tsize_t sep = fieldPath.find('/', off);\n\t\tif (sep == std::string_view::npos)\n\t\t\tsep = fieldPath.size();\n\t\tstd::string_view seg = fieldPath.substr(off, sep - off);\n\t\tif (!findField(seg))\n\t\t\treturn std::nullopt;\n\t\tauto val = nextToken(); // after \":\"\n\t\tif (sep == fieldPath.size())\n\t\t\treturn std::string(val);\n\t\tif (val == \"{\")\n\t\t{\n\t\t\t// traverse object\n\t\t}\n\t\telse if (val == \"[\")\n\t\t{\n\t\t\t// array\n\t\t\treturn std::nullopt;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn std::nullopt; // not object\n\t\t}\n\t\toff = sep + 1;\n\t}\n\treturn std::nullopt;\n}\n\nDiscordRPCLite::DiscordRPCLite(const char* applicationId)\n{\n\tm_workerThread = std::thread(&DiscordRPCLite::WorkerThread, this, std::string(applicationId));\n}\n\nDiscordRPCLite::~DiscordRPCLite()\n{\n\tm_shutdownSignal.store(true);\n\tif (m_workerThread.joinable())\n\t\tm_workerThread.join();\n}\n\nstatic bool CompareStringI(std::string_view a, std::string_view b)\n{\n\tauto toLower = [](char c) -> char {\n\t\tif (c >= 'A' && c <= 'Z')\n\t\t\treturn c + ('a' - 'A');\n\t\treturn c;\n\t};\n\tif (a.size() != b.size())\n\t\treturn false;\n\tfor (size_t i = 0; i < a.size(); i++)\n\t{\n\t\tif (toLower(a[i]) != toLower(b[i]))\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\nstatic int64_t GetMs()\n{\n\tauto now = std::chrono::system_clock::now();\n\tauto duration = now.time_since_epoch();\n\treturn std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();\n}\n\nvoid DiscordRPCLite::WorkerThread(std::string applicationId)\n{\n\tenum class ConnectionState\n\t{\n\t\tDisconnected,\n\t\tConnectingBeforeHandshake,\n\t\tConnectingAfterHandshake,\n\t\tConnected\n\t};\n\tConnectionState connectionState = ConnectionState::Disconnected;\n\n\tstd::vector<uint8_t> recvBuffer;\n\tuint8_t recvMsgHeader[8] = {0};\n\tsize_t recvSize = 0; // if < 8 then we are still receiving the header. If >= 8 then we are receiving the body\n\tNamedPipe pipe;\n\tauto SetDisconnected = [&]() {\n\t\tpipe.ClosePipe();\n\t\tconnectionState = ConnectionState::Disconnected;\n\t\trecvSize = 0;\n\t\tm_richPresenceDirty = true; // set so we always send current rich presence after (re)connecting\n\t};\n\tSetDisconnected(); // set initial state\n\tint64_t lastConnectionAttempt = 0;\n\tint32_t numFailedConnectionAttempts = 0; // increases every time we try to connect but fail, resets to 0 when we successfully connect and receive a READY event\n\tint64_t lastRichPresenceUpdate = 0;\n\twhile (!m_shutdownSignal)\n\t{\n\t\tif (connectionState == ConnectionState::Disconnected)\n\t\t{\n\t\t\t// wait at least one second before trying to reconnect\n\t\t\tint64_t now = GetMs();\n\t\t\tint64_t delayTime = 1000 + (numFailedConnectionAttempts * 500); // increase delay by 500ms for each failed connection attempt\n\t\t\tif (delayTime >= 90000)\n\t\t\t\tdelayTime = 90000; // max delay of 90 seconds\n\t\t\tif ((now - lastConnectionAttempt) < delayTime)\n\t\t\t{\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(200));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlastConnectionAttempt = now;\n\t\t\tnumFailedConnectionAttempts++;\n\t\t\tif (!pipe.OpenPipe())\n\t\t\t{\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconnectionState = ConnectionState::ConnectingBeforeHandshake;\n\t\t\tcontinue;\n\t\t}\n\t\tif (connectionState == ConnectionState::ConnectingBeforeHandshake)\n\t\t{\n\t\t\tstd::string handshakeJson = shim::format(R\"({{\"v\":1,\"client_id\":\"{}\"}})\", applicationId);\n\t\t\tpipe.SendJsonMsg(OpcodeHandshake, handshakeJson);\n\t\t\tconnectionState = ConnectionState::ConnectingAfterHandshake;\n\t\t}\n\t\t// check if we should send a presence update (rate limited to 1 per 15 seconds)\n\t\tif (connectionState == ConnectionState::Connected && m_richPresenceDirty)\n\t\t{\n\t\t\tint64_t now = GetMs();\n\t\t\tif ((now - lastRichPresenceUpdate) >= 15000)\n\t\t\t{\n\t\t\t\tDiscordLiteRichPresence presence = {};\n\t\t\t\t{\n\t\t\t\t\tstd::lock_guard lock(m_presenceMutex);\n\t\t\t\t\tpresence = m_presence;\n\t\t\t\t\tm_richPresenceDirty = false;\n\t\t\t\t}\n\t\t\t\tpipe.SendPresenceUpdate(presence);\n\t\t\t\tlastRichPresenceUpdate = now;\n\t\t\t}\n\t\t}\n\t\t// continue receiving messages\n\t\tif (recvSize < 8)\n\t\t{\n\t\t\t// receive header\n\t\t\tint readSize = pipe.Read(recvMsgHeader + recvSize, 8 - recvSize, 200);\n\t\t\tif (readSize < 0)\n\t\t\t{\n\t\t\t\tSetDisconnected();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trecvSize += readSize;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// receive body\n\t\t\tuint32_t opcode = (recvMsgHeader[0] << 0) | (recvMsgHeader[1] << 8) | (recvMsgHeader[2] << 16) | (recvMsgHeader[3] << 24);\n\t\t\tuint32_t bodyLength = (recvMsgHeader[4] << 0) | (recvMsgHeader[5] << 8) | (recvMsgHeader[6] << 16) | (recvMsgHeader[7] << 24);\n\t\t\tif (bodyLength >= 8 * 1024 * 1024)\n\t\t\t{\n\t\t\t\tSetDisconnected();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (recvBuffer.size() < bodyLength)\n\t\t\t\trecvBuffer.resize(bodyLength);\n\t\t\tint readSize = pipe.Read(recvBuffer.data() + (recvSize - 8), bodyLength - (recvSize - 8), 1000);\n\t\t\tif (readSize < 0)\n\t\t\t{\n\t\t\t\tSetDisconnected();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\trecvSize += readSize;\n\t\t\tif (recvSize == bodyLength + 8)\n\t\t\t{\n\t\t\t\tstd::string_view jsonText((const char*)recvBuffer.data(), bodyLength);\n\t\t\t\trecvSize = 0;\n\t\t\t\t// full message received\n\t\t\t\tif (opcode == OpcodeFrame)\n\t\t\t\t{\n\t\t\t\t\tstd::optional<std::string> cmd = ParseJSONField(jsonText, \"cmd\");\n\t\t\t\t\tstd::optional<std::string> evt = ParseJSONField(jsonText, \"evt\");\n\t\t\t\t\tif (CompareStringI(*cmd, \"DISPATCH\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (evt && CompareStringI(*evt, \"READY\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (connectionState == ConnectionState::ConnectingAfterHandshake)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tconnectionState = ConnectionState::Connected;\n\t\t\t\t\t\t\t\tnumFailedConnectionAttempts = 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (opcode == OpcodePing)\n\t\t\t\t{\n\t\t\t\t\tpipe.SendJsonMsg(OpcodePong, jsonText);\n\t\t\t\t}\n\t\t\t\telse if (opcode == OpcodeClose)\n\t\t\t\t{\n\t\t\t\t\tSetDisconnected();\n\t\t\t\t}\n\t\t\t\tif (recvBuffer.size() > 2048)\n\t\t\t\t{\n\t\t\t\t\trecvBuffer.resize(2048);\n\t\t\t\t\trecvBuffer.shrink_to_fit();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\t// if we are still connected then explicitly clear presence just in case\n\tif (pipe.IsOpen())\n\t{\n\t\tpipe.SendPresenceUpdate({});\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(75));\n\t}\n}"
  },
  {
    "path": "src/Cemu/DiscordPresence/DiscordRPCLite.h",
    "content": "/* Standalone client for Discord RPC for the sole purpose of updating rich presence */\n\n#pragma once\n#include <thread>\n#include <atomic>\n#include <string>\n#include <cstdint>\n#include <mutex>\n\nstruct DiscordLiteRichPresence\n{\n\tstd::string state;\n\tstd::string details;\n\tint64_t startTimestamp;\n\tint64_t endTimestamp;\n\tstd::string largeImageKey;\n\tstd::string largeImageText;\n\tstd::string smallImageKey;\n\tstd::string smallImageText;\n\tstd::string partyId;\n\tint partySize;\n\tint partyMax;\n\tint partyPrivacy;\n\tstd::string matchSecret;\n\tstd::string joinSecret;\n\tstd::string spectateSecret;\n\tint8_t instance;\n};\n\nclass DiscordRPCLite\n{\n  public:\n\tDiscordRPCLite(const char* applicationId);\n\t~DiscordRPCLite();\n\n\tvoid UpdateRichPresence(const DiscordLiteRichPresence& presence)\n\t{\n\t\tstd::unique_lock _l(m_presenceMutex);\n\t\tm_presence = presence;\n\t\tm_richPresenceDirty = true;\n\t}\n\n\tvoid ClearRichPresence()\n\t{\n\t\tstd::unique_lock _l(m_presenceMutex);\n\t\tm_presence = {};\n\t\tm_richPresenceDirty = false;\n\t}\n\n  private:\n\tvoid WorkerThread(std::string applicationId);\n\n\tstd::thread m_workerThread;\n\tstd::atomic_bool m_shutdownSignal{false};\n\t// rich presence state\n\tstd::mutex m_presenceMutex;\n\tstd::atomic_bool m_richPresenceDirty{false};\n\tDiscordLiteRichPresence m_presence;\n};"
  },
  {
    "path": "src/Cemu/ExpressionParser/ExpressionParser.cpp",
    "content": "#include \"ExpressionParser.h\"\n\ntemplate<typename T, typename TInternalType = double>\nT _testEvaluateToType(const char* expr)\n{\n\tTExpressionParser<TInternalType> ep;\n\tT result = (T)ep.Evaluate(expr);\n\treturn result;\n}\n\nvoid ExpressionParser_test()\n{\n\tExpressionParser ep;\n\tcemu_assert_debug(_testEvaluateToType<sint64>(\"0x100005E0\") == 0x100005E0);\n\tcemu_assert_debug(_testEvaluateToType<uint64>(\"0x10+0x20+0x40\") == 0x70);\n\tcemu_assert_debug(_testEvaluateToType<sint64>(\"0+-3\") == -3);\n\tcemu_assert_debug(_testEvaluateToType<sint64>(\"0x0-3\") == -3);\n\tcemu_assert_debug(_testEvaluateToType<sint64>(\"01C+0x10\") == 0x2C);\n\tcemu_assert_debug(_testEvaluateToType<sint64>(\"+0x10\") == 0x10);\n\tcemu_assert_debug(_testEvaluateToType<sint64>(\"01C++0x10\") == 0x2C);\n\tcemu_assert_debug(_testEvaluateToType<sint64>(\"01C+(+0x10)\") == 0x2C);\n\n\t// arithmetic\n\tcemu_assert_debug(_testEvaluateToType<sint64>(\"(62156250 / 1000) * 30\") == 1864687); // truncated 1864687.5\n\n\t// arithmetic with internal type sint64\n\tcemu_assert_debug(_testEvaluateToType<sint64, sint64>(\"(62156250 / 1000) * 30\") == 1864680);\n\n\t// comparison operators\n\tcemu_assert_debug(_testEvaluateToType<sint64>(\"5 > 3\") == 0x1);\n\tcemu_assert_debug(_testEvaluateToType<sint64>(\"5 < -10\") == 0x0);\n\tcemu_assert_debug(_testEvaluateToType<float>(\"5 > 3\") == 1.0f);\n\tcemu_assert_debug(_testEvaluateToType<float>(\"-5 > 3\") == 0.0f);\n\tcemu_assert_debug(_testEvaluateToType<float>(\"5 < 10\") == 1.0f);\n\tcemu_assert_debug(_testEvaluateToType<float>(\"5 <= 5\") == 1.0f);\n\tcemu_assert_debug(_testEvaluateToType<float>(\"5 <= 4.999\") == 0.0f);\n\tcemu_assert_debug(_testEvaluateToType<float>(\"5 <= (4+0.999)\") == 0.0f);\n\tcemu_assert_debug(_testEvaluateToType<float>(\"5 >= 3\") == 1.0f);\n\tcemu_assert_debug(_testEvaluateToType<float>(\"5 >= 10\") == 0.0f);\n\tcemu_assert_debug(_testEvaluateToType<float>(\"10 >= 5\") == 1.0f);\n\n\t// complex operations\n\tcemu_assert_debug(_testEvaluateToType<float>(\"5 > 4 > 3 > 2\") == 0.0f); // this should evaluate the operations from left to right, (5 > 4) -> 0.0, (0.0 > 4) -> 0.0, (0.0 > 3) -> 0.0, (0.0 > 2) -> 0.0\n\tcemu_assert_debug(_testEvaluateToType<float>(\"5 > 4 > 3 > -2\") == 1.0f); // this should evaluate the operations from left to right, (5 > 4) -> 0.0, (0.0 > 4) -> 0.0, (0.0 > 3) -> 0.0, (0.0 > -2) -> 1.0\n\tcemu_assert_debug(_testEvaluateToType<float>(\"(5 == 5) > (5 == 6)\") == 1.0f);\n}"
  },
  {
    "path": "src/Cemu/ExpressionParser/ExpressionParser.h",
    "content": "#pragma once\n#include \"Common/precompiled.h\"\n\n#include <string>\n#include <queue>\n#include <stack>\n#include <unordered_map>\n#include <memory>\n#include <charconv>\n\n#include \"boost/functional/hash_fwd.hpp\"\n#include <fmt/format.h>\n\n#ifdef __clang__\n#include \"Common/unix/fast_float.h\"\n #define _EP_FROM_CHARS_DBL(...) _convFastFloatResult(fast_float::from_chars(__VA_ARGS__))\n\ninline std::from_chars_result _convFastFloatResult(fast_float::from_chars_result r)\n{\n\tstd::from_chars_result nr;\n\tnr.ptr = r.ptr;\n\tnr.ec = r.ec;\n\treturn nr;\n}\n#else\n #define _EP_FROM_CHARS_DBL(...) std::from_chars(__VA_ARGS__)\n#endif\n\ntemplate<class TType = double>\nclass TExpressionParser\n{\npublic:\n\tstatic_assert(std::is_arithmetic_v<TType>);\n\tusing ConstantCallback_t = TType(*)(std::string_view var_name);\n\tusing FunctionCallback_t = TType(*)(std::string_view var_name, TType parameter);\n\n\ttemplate<typename T>\n\tT Evaluate(std::string_view expression) const\n\t{\n\t\tstatic_assert(std::is_arithmetic_v<T>, \"type T must be an arithmetic type\");\n\t\treturn (T)Evaluate(expression);\n\t}\n\n\t[[nodiscard]] TType Evaluate(std::string_view expression) const\n\t{\n\t\tstd::queue<std::shared_ptr<TokenBase>> output;\n\t\tstd::stack<std::shared_ptr<TokenBase>> operators;\n\n\t\tif (expression.empty())\n\t\t{\n\t\t\tthrow std::runtime_error(fmt::format(\"empty expression is not allowed\"));\n\t\t}\n\n\t\tbool last_operator_token = true;\n\n\t\t// tokenize and apply shunting-yard\n\t\tfor (size_t i = 0; i < expression.size(); )\n\t\t{\n\t\t\tconst char c = expression[i];\n\n\t\t\t// skip whitespaces\n\t\t\tif (isblank(c))\n\t\t\t{\n\t\t\t\t++i;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// extract numbers\n\t\t\tif (isdigit(c) || (last_operator_token && (c == '-' || c == '+')))\n\t\t\t{\n\t\t\t\tconst std::string_view view(expression.data() + i, expression.size() - i);\n\t\t\t\tsize_t offset = 0;\n\t\t\t\tauto converted = (TType)ConvertString(view, &offset);\n\t\t\t\toutput.emplace(std::make_shared<TokenNumber>(converted));\n\t\t\t\ti += offset;\n\n\t\t\t\tlast_operator_token = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// check for variables\n\t\t\tif (isalpha(c) || c == '_' || c == '$')\n\t\t\t{\n\t\t\t\tsize_t j;\n\t\t\t\tfor (j = i + 1; j < expression.size(); ++j)\n\t\t\t\t{\n\t\t\t\t\tconst char v = expression[j];\n\t\t\t\t\tif (!isalpha(v) && !isdigit(v) && v != '_' && v != '@' && v != '.')\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst size_t len = j - i;\n\t\t\t\tconst std::string_view view = expression.substr(i, len);\n\n\t\t\t\t// check for function\n\t\t\t\tif (m_function_callback)\n\t\t\t\t{\n\t\t\t\t\t// todo skip whitespaces\n\t\t\t\t\tif (j < expression.size() && expression[j] == '(')\n\t\t\t\t\t{\n\t\t\t\t\t\toperators.emplace(std::make_shared<TokenUnaryOperator>(TokenUnaryOperator::kFunction, view));\n\t\t\t\t\t\toperators.emplace(std::make_shared<TokenParenthese>());\n\t\t\t\t\t\ti += len + 1;\n\n\t\t\t\t\t\tlast_operator_token = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tTType value;\n\t\t\t\tconst auto it = m_constants.find(std::string{ view });\n\t\t\t\tif (it == m_constants.cend())\n\t\t\t\t{\n\t\t\t\t\tif (m_constant_callback == nullptr)\n\t\t\t\t\t\tthrow std::runtime_error(fmt::format(\"unknown constant found \\\"{}\\\" in expression: {}\", view, expression));\n\n\t\t\t\t\tvalue = m_constant_callback(view);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tvalue = it->second;\n\n\t\t\t\toutput.emplace(std::make_shared<TokenNumber>(value));\n\t\t\t\ti += len;\n\n\t\t\t\tlast_operator_token = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// parenthese\n\t\t\tif (c == '(')\n\t\t\t{\n\t\t\t\toperators.emplace(std::make_shared<TokenParenthese>());\n\t\t\t\t++i;\n\n\t\t\t\tlast_operator_token = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (c == ')')\n\t\t\t{\n\t\t\t\tbool match = false;\n\t\t\t\twhile (!operators.empty())\n\t\t\t\t{\n\t\t\t\t\tconst auto op = std::dynamic_pointer_cast<TokenParenthese>(operators.top());\n\t\t\t\t\tif (!op)\n\t\t\t\t\t{\n\t\t\t\t\t\toutput.emplace(operators.top());\n\t\t\t\t\t\toperators.pop();\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\toperators.pop();\n\t\t\t\t\tmatch = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (!match && operators.empty())\n\t\t\t\t{\n\t\t\t\t\tthrow std::runtime_error(fmt::format(\"parentheses mismatch: {}\", expression));\n\t\t\t\t}\n\n\t\t\t\t++i;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// supported operations\n\t\t\tstd::shared_ptr<TokenOperator> operator_token;\n\t\t\tswitch (c)\n\t\t\t{\n\t\t\tcase '+':\n\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kAddition, 2);\n\t\t\t\tbreak;\n\t\t\tcase '-':\n\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kSubtraction, 2);\n\t\t\t\tbreak;\n\t\t\tcase '*':\n\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kMultiplication, 3);\n\t\t\t\tbreak;\n\t\t\tcase '/':\n\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kDivision, 3);\n\t\t\t\tbreak;\n\t\t\tcase '^':\n\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kPow, 4, true);\n\t\t\t\tbreak;\n\t\t\tcase '%':\n\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kModulo, 3);\n\t\t\t\tbreak;\n\t\t\tcase '=':\n\t\t\t\tif ((i + 1) < expression.size() && expression[i + 1] == '=')\n\t\t\t\t{\n\t\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kEqual, 1);\n\t\t\t\t\t++i;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '!':\n\t\t\t\tif ((i + 1) < expression.size() && expression[i + 1] == '=')\n\t\t\t\t{\n\t\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kNotEqual, 1);\n\t\t\t\t\t++i;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '<':\n\t\t\t\tif ((i + 1) < expression.size() && expression[i + 1] == '=')\n\t\t\t\t{\n\t\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kLessOrEqual, 1);\n\t\t\t\t\t++i;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kLessThan, 1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '>':\n\t\t\t\tif ((i + 1) < expression.size() && expression[i + 1] == '=')\n\t\t\t\t{\n\t\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kGreaterOrEqual, 1);\n\t\t\t\t\t++i;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\toperator_token = std::make_shared<TokenOperator>(TokenOperator::kGreaterThan, 1);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (!operator_token)\n\t\t\t\tthrow std::runtime_error(fmt::format(\"invalid operator found in expression: {}\", expression));\n\n\t\t\twhile (!operators.empty())\n\t\t\t{\n\t\t\t\tconst auto op = std::dynamic_pointer_cast<TokenOperator>(operators.top());\n\t\t\t\tif (op && ((!operator_token->right_ass && operator_token->prec <= op->prec) || (operator_token->right_ass && operator_token->prec < op->prec)))\n\t\t\t\t{\n\t\t\t\t\toutput.emplace(operators.top());\n\t\t\t\t\toperators.pop();\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\toperators.emplace(operator_token);\n\t\t\t++i;\n\t\t\tlast_operator_token = true;\n\t\t}\n\n\t\twhile (!operators.empty())\n\t\t{\n\t\t\tconst auto parenthese = std::dynamic_pointer_cast<TokenParenthese>(operators.top());\n\t\t\tif (parenthese)\n\t\t\t{\n\t\t\t\tthrow std::runtime_error(fmt::format(\"parentheses mismatch in expression: {}\", expression));\n\t\t\t}\n\n\t\t\toutput.push(operators.top());\n\t\t\toperators.pop();\n\t\t}\n\n\t\t// evaluate tokens in output queue\n\t\tstd::stack<TType> evaluation;\n\t\twhile (!output.empty())\n\t\t{\n\t\t\tconst auto number = std::dynamic_pointer_cast<TokenNumber>(output.front());\n\t\t\tif (number)\n\t\t\t{\n\t\t\t\tevaluation.emplace(number->number);\n\t\t\t\toutput.pop();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (const auto unop = std::dynamic_pointer_cast<TokenUnaryOperator>(output.front()))\n\t\t\t{\n\t\t\t\tif (evaluation.size() < 1)\n\t\t\t\t\tthrow std::runtime_error(\"not enough parameters for equation\");\n\n\t\t\t\tconst auto parameter = evaluation.top();\n\t\t\t\tevaluation.pop();\n\n\t\t\t\tswitch (unop->op)\n\t\t\t\t{\n\t\t\t\tcase TokenUnaryOperator::kFunction:\n\t\t\t\t\tevaluation.emplace(m_function_callback(unop->symbol, parameter));\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow std::runtime_error(\"unsupported operation constant\");\n\t\t\t\t}\n\n\t\t\t\toutput.pop();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (const auto op = std::dynamic_pointer_cast<TokenOperator>(output.front()))\n\t\t\t{\n\t\t\t\tif (evaluation.size() < 2)\n\t\t\t\t\tthrow std::runtime_error(\"not enough parameters for equation\");\n\n\t\t\t\tconst auto rhs = evaluation.top();\n\t\t\t\tevaluation.pop();\n\n\t\t\t\tconst auto lhs = evaluation.top();\n\t\t\t\tevaluation.pop();\n\n\t\t\t\tswitch (op->op)\n\t\t\t\t{\n\t\t\t\tcase TokenOperator::kAddition:\n\t\t\t\t\tevaluation.emplace(lhs + rhs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kSubtraction:\n\t\t\t\t\tevaluation.emplace(lhs - rhs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kMultiplication:\n\t\t\t\t\tevaluation.emplace(lhs * rhs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kDivision:\n\t\t\t\t\tif (rhs == 0.0) evaluation.emplace((TType)0.0);\n\t\t\t\t\telse evaluation.emplace(lhs / rhs);\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kPow:\n\t\t\t\t\tevaluation.emplace((TType)std::pow(lhs, rhs));\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kModulo:\n\t\t\t\t\tif (std::round(rhs) == 0.0)\n\t\t\t\t\t\tevaluation.emplace((TType)0.0);\n\t\t\t\t\telse\n\t\t\t\t\t\tevaluation.emplace((TType)((sint64)std::round(lhs) % (sint64)std::round(rhs)));\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kEqual:\n\t\t\t\t\tif constexpr (std::is_floating_point_v<TType>)\n\t\t\t\t\t\tevaluation.emplace((TType)(std::abs(lhs - rhs) <= 0.0000000001 ? 1 : 0));\n\t\t\t\t\telse\n\t\t\t\t\t\tevaluation.emplace(lhs == rhs ? 1 : 0);\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kNotEqual:\n\t\t\t\t\tif constexpr (std::is_floating_point_v<TType>)\n\t\t\t\t\t\tevaluation.emplace((TType)(std::abs(lhs - rhs) > 0.0000000001 ? 1 : 0));\n\t\t\t\t\telse\n\t\t\t\t\t\tevaluation.emplace(lhs != rhs ? 1 : 0);\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kLessThan:\n\t\t\t\t\tevaluation.emplace((TType)(lhs < rhs ? 1 : 0));\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kLessOrEqual:\n\t\t\t\t\tevaluation.emplace((TType)(lhs <= rhs ? 1 : 0));\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kGreaterThan:\n\t\t\t\t\tevaluation.emplace((TType)(lhs > rhs ? 1 : 0));\n\t\t\t\t\tbreak;\n\t\t\t\tcase TokenOperator::kGreaterOrEqual:\n\t\t\t\t\tevaluation.emplace((TType)(lhs >= rhs ? 1 : 0));\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthrow std::runtime_error(\"unsupported operation constant\");\n\t\t\t\t}\n\n\t\t\t\toutput.pop();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\treturn evaluation.top();\n\t}\n\n\t[[nodiscard]] bool IsValidExpression(std::string_view expression) const\n\t{\n\t\ttry\n\t\t{\n\t\t\tTExpressionParser<TType> ep;\n\t\t\tep.AddConstantCallback(\n\t\t\t\t[](std::string_view sv) -> TType\n\t\t\t\t{\n\t\t\t\t\treturn (TType)1;\n\t\t\t\t});\n\t\t\tstatic_cast<void>(ep.Evaluate(expression));\n\t\t\treturn true;\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t[[nodiscard]] bool IsConstantExpression(std::string_view expression) const\n\t{\n\t\ttry\n\t\t{\n\t\t\tstatic_cast<void>(this->Evaluate(expression));\n\t\t\treturn true;\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tvoid AddConstant(std::string_view name, TType value)\n\t{\n\t\tm_constants[std::string(name)] = value;\n\t}\n\n\t// only adds constant if not added yet\n\tvoid TryAddConstant(std::string_view name, TType value)\n\t{\n\t\tm_constants.try_emplace(std::string{ name }, value);\n\t}\n\n\tvoid AddConstant(std::string_view name, std::string_view value)\n\t{\n\t\tAddConstant(name, ConvertString(value));\n\t}\n\n\tvoid AddConstantCallback(ConstantCallback_t callback)\n\t{\n\t\tm_constant_callback = callback;\n\t}\n\n\tvoid SetFunctionCallback(FunctionCallback_t callback)\n\t{\n\t\tm_function_callback = callback;\n\t}\n\nprivate:\n\tstd::unordered_map<std::string, TType> m_constants;\n\tConstantCallback_t m_constant_callback = nullptr;\n\tFunctionCallback_t m_function_callback = nullptr;\n\n\tstatic bool _isNumberWithDecimalPoint(std::string_view str)\n\t{\n\t\treturn str.find('.') != std::string_view::npos;\n\t}\n\n\tdouble ConvertString(std::string_view str, size_t* index_after = nullptr) const\n\t{\n\t\tconst char* strInitial = str.data();\n\t\tif (str.empty())\n\t\t\tthrow std::runtime_error(\"can't parse empty number\");\n\n\t\tdouble result;\n\t\tstd::from_chars_result chars_result;\n\n\t\tconst bool is_negative = str[0] == '-';\n\t\tif (is_negative || str[0] == '+')\n\t\t\tstr = str.substr(1);\n\n\t\tif (str.size() >= 3 && str[0] == '0' && tolower(str[1]) == 'x')\n\t\t{\n\t\t\tstr = str.substr(2);\n\t\t\t// find end of number\n\t\t\tconst auto end = std::find_if_not(str.cbegin(), str.cend(), isxdigit);\n\n\t\t\tint64_t tmp;\n\t\t\tchars_result = std::from_chars(str.data(), str.data() + std::distance(str.cbegin(), end), tmp, 16);\n\t\t\tresult = (double)tmp;\n\t\t}\n\t\t// a number prefixed with 0 and no decimal point is considered a hex number\n\t\telse if (str.size() >= 2 && str[0] == '0' && isxdigit(str[1]) && !_isNumberWithDecimalPoint(str))\n\t\t{\n\t\t\tstr = str.substr(1);\n\t\t\t// find end of number\n\t\t\tconst auto end = std::find_if_not(str.cbegin(), str.cend(), isxdigit);\n\n\t\t\tint64_t tmp;\n\t\t\tchars_result = std::from_chars(str.data(), str.data() + std::distance(str.cbegin(), end), tmp, 16);\n\t\t\tresult = (double)tmp;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (str[0] == '+')\n\t\t\t\tstr = str.substr(1);\n\n\t\t\tbool has_point = false;\n\t\t\tbool has_exponent = false;\n\t\t\tconst auto end = std::find_if_not(str.cbegin(), str.cend(),\n\t\t\t\t[&has_point, &has_exponent](char c) -> bool\n\t\t\t\t{\n\t\t\t\t\tif (isdigit(c))\n\t\t\t\t\t\treturn true;\n\n\t\t\t\t\tif (c == '.' && !has_point)\n\t\t\t\t\t{\n\t\t\t\t\t\thas_point = true;\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (tolower(c) == 'e' && !has_exponent)\n\t\t\t\t\t{\n\t\t\t\t\t\thas_exponent = true;\n\t\t\t\t\t\t// TODO: after exponent might be + and - allowed?\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\n\t\t\t\t});\n\t\t\tchars_result = _EP_FROM_CHARS_DBL(str.data(), str.data() + std::distance(str.cbegin(), end), result);\n\t\t}\n\n\t\tif (chars_result.ec == std::errc())\n\t\t{\n\t\t\tif (index_after)\n\t\t\t\t*index_after = chars_result.ptr - strInitial;\n\n\t\t\tif (is_negative)\n\t\t\t\tresult *= -1.0;\n\n\t\t\treturn result;\n\t\t}\n\t\telse\n\t\t\tthrow std::runtime_error(fmt::format(\"can't parse number: {}\", str));\n\t}\n\n\tstruct TokenBase\n\t{\n\t\tvirtual ~TokenBase() = default;\n\t};\n\n\tstruct TokenUnaryOperator : TokenBase\n\t{\n\t\tenum Operator\n\t\t{\n\t\t\tkFunction,\n\t\t};\n\n\t\tTokenUnaryOperator(Operator op) : op(op) {}\n\t\tTokenUnaryOperator(Operator op, std::string_view symbol) : op(op), symbol(symbol) {}\n\n\t\tOperator op;\n\t\tstd::string_view symbol;\n\t};\n\n\tstruct TokenOperator : TokenBase\n\t{\n\t\tenum Operator\n\t\t{\n\t\t\tkAddition,\n\t\t\tkSubtraction,\n\t\t\tkMultiplication,\n\t\t\tkDivision,\n\t\t\tkPow,\n\t\t\tkModulo,\n\t\t\tkEqual,\n\t\t\tkNotEqual,\n\t\t\tkLessThan,\n\t\t\tkLessOrEqual,\n\t\t\tkGreaterThan,\n\t\t\tkGreaterOrEqual,\n\t\t};\n\n\t\tTokenOperator(Operator op, int prec, bool right_ass = false) : op(op), prec(prec), right_ass(right_ass) {}\n\t\tOperator op;\n\t\tint prec;\n\t\tbool right_ass;\n\t};\n\n\tstruct TokenParenthese : TokenBase {};\n\n\tstruct TokenNumber : TokenBase\n\t{\n\t\tTokenNumber(TType number) : number(number) {}\n\t\tTType number;\n\t};\n};\n\nclass ExpressionParser : public TExpressionParser<double> {};\n\nvoid ExpressionParser_test();\n\n"
  },
  {
    "path": "src/Cemu/FileCache/FileCache.cpp",
    "content": "#include \"FileCache.h\"\n#include \"util/helpers/helpers.h\"\n\n#include <mutex>\n#include <condition_variable>\n#include \"zlib.h\"\n#include \"Common/FileStream.h\"\n\nstruct FileCacheAsyncJob\n{\n\tFileCache* fileCache;\n\tuint64 name1;\n\tuint64 name2;\n\tstd::vector<uint8> fileData;\n};\n\nstruct _FileCacheAsyncWriter\n{\n\t_FileCacheAsyncWriter()\n\t{\n\t\tm_isRunning.store(true);\n\t\tm_fileCacheThread = std::thread(&_FileCacheAsyncWriter::FileCacheThread, this);\n\t}\n\n\t~_FileCacheAsyncWriter()\n\t{\n\t\tif (m_isRunning.load())\n\t\t{\n\t\t\tm_isRunning.store(false);\n\t\t\tm_fileCacheCondVar.notify_one();\n\t\t\tm_fileCacheThread.join();\n\t\t}\n\t}\n\n\tvoid AddJob(FileCache* fileCache, const FileCache::FileName& name, const uint8* fileData, sint32 fileSize)\n\t{\n\t\tFileCacheAsyncJob async;\n\t\tasync.fileCache = fileCache;\n\t\tasync.name1 = name.name1;\n\t\tasync.name2 = name.name2;\n\t\tasync.fileData = { fileData, fileData + fileSize };\n\n\t\tstd::unique_lock lock(m_fileCacheMutex);\n\t\tm_writeRequests.emplace_back(std::move(async));\n\n\t\tlock.unlock();\n\t\tm_fileCacheCondVar.notify_one();\n\t}\n\nprivate:\n\tvoid FileCacheThread()\n\t{\n\t\tSetThreadName(\"fileCache\");\n\t\twhile (true)\n\t\t{\n\t\t\tstd::unique_lock lock(m_fileCacheMutex);\n\t\t\twhile (m_writeRequests.empty())\n\t\t\t{\n\t\t\t\tm_fileCacheCondVar.wait(lock);\n\t\t\t\tif (!m_isRunning.load(std::memory_order::relaxed))\n\t\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstd::vector<FileCacheAsyncJob> requestsCopy;\n\t\t\trequestsCopy.swap(m_writeRequests); // fast copy & clear\n\t\t\tlock.unlock();\n\n\t\t\tfor (const auto& entry : requestsCopy)\n\t\t\t{\n\t\t\t\tentry.fileCache->AddFile({ entry.name1, entry.name2 }, entry.fileData.data(), (sint32)entry.fileData.size());\n\t\t\t}\n\t\t}\n\t}\n\n\tstd::thread m_fileCacheThread;\n\tstd::mutex m_fileCacheMutex;\n\tstd::condition_variable m_fileCacheCondVar;\n\tstd::vector<FileCacheAsyncJob> m_writeRequests;\n\tstd::atomic_bool m_isRunning;\n}FileCacheAsyncWriter;\n\n#define FILECACHE_MAGIC_V1\t\t\t\t\t0x8371b694 // used prior to Cemu 1.7.4, only supported caches up to 4GB\n#define FILECACHE_MAGIC_V2\t\t\t\t\t0x8371b695 // added support for large caches\n#define FILECACHE_MAGIC_V3\t\t\t\t\t0x8371b696 // introduced in Cemu 1.16.0 (non-WIP). Adds zlib compression\n#define FILECACHE_HEADER_RESV\t\t\t\t128 // number of bytes reserved for the header\n#define FILECACHE_FILETABLE_NAME1\t\t\t0xEFEFEFEFEFEFEFEFULL\n#define FILECACHE_FILETABLE_NAME2\t\t\t0xFEFEFEFEFEFEFEFEULL\n#define FILECACHE_FILETABLE_FREE_NAME\t\t0ULL\n\nFileCache* FileCache::Create(const fs::path& path, uint32 extraVersion)\n{\n\tFileStream* fs = FileStream::createFile2(path);\n\tif (!fs)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to create cache file \\\"{}\\\"\", _pathToUtf8(path));\n\t\treturn nullptr;\n\t}\n\t// init file cache\n\tauto* fileCache = new FileCache();\n\tfileCache->fileStream = fs;\n\tfileCache->dataOffset = FILECACHE_HEADER_RESV;\n\tfileCache->fileTableEntryCount = 32;\n\tfileCache->fileTableOffset = 0;\n\tfileCache->fileTableSize = sizeof(FileTableEntry) * fileCache->fileTableEntryCount;\n\tfileCache->fileTableEntries = (FileTableEntry*)malloc(fileCache->fileTableSize);\n\tfileCache->extraVersion = extraVersion;\n\tmemset(fileCache->fileTableEntries, 0, fileCache->fileTableSize);\n\t// file table stores info about itself\n\tfileCache->fileTableEntries[0].name1 = FILECACHE_FILETABLE_NAME1;\n\tfileCache->fileTableEntries[0].name2 = FILECACHE_FILETABLE_NAME2;\n\tfileCache->fileTableEntries[0].fileOffset = fileCache->fileTableOffset;\n\tfileCache->fileTableEntries[0].fileSize = fileCache->fileTableSize;\n\t// write header\n\n\tfs->writeU32(FILECACHE_MAGIC_V3);\n\tfs->writeU32(fileCache->extraVersion);\n\tfs->writeU64(fileCache->dataOffset);\n\tfs->writeU64(fileCache->fileTableOffset);\n\tfs->writeU32(fileCache->fileTableSize);\n\t// write file table\n\tfs->SetPosition(fileCache->dataOffset+fileCache->fileTableOffset);\n\tfs->writeData(fileCache->fileTableEntries, fileCache->fileTableSize);\n\t// done\n\treturn fileCache;\n}\n\nFileCache* FileCache::_OpenExisting(const fs::path& path, bool compareExtraVersion, uint32 extraVersion)\n{\n\tFileStream* fs = FileStream::openFile2(path, true);\n\tif (!fs)\n\t\treturn nullptr;\n\t// read header\n\tuint32 headerMagic = 0;\n\tfs->readU32(headerMagic);\n\tbool isV2 = false;\n\tif (headerMagic != FILECACHE_MAGIC_V1 && headerMagic != FILECACHE_MAGIC_V2 && headerMagic != FILECACHE_MAGIC_V3)\n\t{\n\t\tdelete fs;\n\t\treturn nullptr;\n\t}\n\tif (headerMagic == FILECACHE_MAGIC_V1)\n\t{\n\t\t// support for V1 file format removed with the addition of V3\n\t\tdelete fs;\n\t\treturn nullptr;\n\t}\n\tif (headerMagic == FILECACHE_MAGIC_V2)\n\t\tisV2 = true;\n\tuint32 headerExtraVersion = 0xFFFFFFFF;\n\tfs->readU32(headerExtraVersion);\n\tif (compareExtraVersion && headerExtraVersion != extraVersion)\n\t{\n\t\tdelete fs;\n\t\treturn nullptr;\n\t}\n\tif (!compareExtraVersion)\n\t{\n\t\textraVersion = headerExtraVersion;\n\t}\n\n\tuint64 headerDataOffset = 0;\n\tuint64 headerFileTableOffset = 0;\n\tuint32 headerFileTableSize = 0;\n\tfs->readU64(headerDataOffset);\n\tfs->readU64(headerFileTableOffset);\n\tif (!fs->readU32(headerFileTableSize))\n\t{\n\t\tcemuLog_log(LogType::Force, \"\\\"{}\\\" is corrupted\", _pathToUtf8(path));\n\t\tdelete fs;\n\t\treturn nullptr;\n\t}\n\tuint32 fileTableEntryCount = 0;\n\tbool invalidFileTableSize = false;\n\t// V2 and V3\n\tfileTableEntryCount = headerFileTableSize / sizeof(FileTableEntry);\n\tinvalidFileTableSize = (headerFileTableSize % sizeof(FileTableEntry)) != 0;\n\tif (invalidFileTableSize)\n\t{\n\t\tcemuLog_log(LogType::Force, \"\\\"{}\\\" is corrupted\", _pathToUtf8(path));\n\t\tdelete fs;\n\t\treturn nullptr;\n\t}\n\t// init struct\n\tauto* fileCache = new FileCache();\n\tfileCache->fileStream = fs;\n\tfileCache->extraVersion = extraVersion;\n\tfileCache->dataOffset = headerDataOffset;\n\tfileCache->fileTableEntryCount = fileTableEntryCount;\n\tfileCache->fileTableOffset = headerFileTableOffset;\n\tfileCache->fileTableSize = fileTableEntryCount * sizeof(FileTableEntry);\n\tfileCache->fileTableEntries = (FileTableEntry*)malloc(fileTableEntryCount * sizeof(FileTableEntry));\n\tmemset(fileCache->fileTableEntries, 0, fileTableEntryCount * sizeof(FileTableEntry));\n\t// read file table\n\tfileCache->fileStream->SetPosition(fileCache->dataOffset + fileCache->fileTableOffset);\n\tbool incompleteFileTable = false;\n\tif (isV2)\n\t{\n\t\t// read file table entries in old format\n\t\tincompleteFileTable = fileCache->fileStream->readData(fileCache->fileTableEntries, fileCache->fileTableSize) != fileCache->fileTableSize;\n\t\t// in V2 the extra field wasn't guaranteed to have well defined values\n\t\tfor (uint32 i = 0; i < fileTableEntryCount; i++)\n\t\t{\n\t\t\tfileCache->fileTableEntries[i].flags = FileTableEntry::FLAGS::FLAG_NONE;\n\t\t\tfileCache->fileTableEntries[i].extraReserved1 = 0;\n\t\t\tfileCache->fileTableEntries[i].extraReserved2 = 0;\n\t\t\tfileCache->fileTableEntries[i].extraReserved3 = 0;\n\t\t}\n\t}\n\telse\n\t{\n\t\tincompleteFileTable = fileCache->fileStream->readData(fileCache->fileTableEntries, fileCache->fileTableSize) != fileCache->fileTableSize;\n\t}\n\tif (incompleteFileTable)\n\t{\n\t\tcemuLog_log(LogType::Force, \"\\\"{}\\\" is corrupted (incomplete file table)\", _pathToUtf8(path));\n\t\tdelete fileCache;\n\t\treturn nullptr;\n\t}\n\treturn fileCache;\n}\n\nFileCache* FileCache::Open(const fs::path& path, bool allowCreate, uint32 extraVersion)\n{\n\tFileCache* fileCache = _OpenExisting(path, true, extraVersion);\n\tif (fileCache)\n\t\treturn fileCache;\n\tif (!allowCreate)\n\t\treturn nullptr;\n\treturn Create(path, extraVersion);\n}\n\nFileCache* FileCache::Open(const fs::path& path)\n{\n\treturn _OpenExisting(path, false, 0);\n}\n\nFileCache::~FileCache()\n{\n\tfree(this->fileTableEntries);\n\tdelete fileStream;\n}\n\nvoid FileCache::fileCache_updateFiletable(sint32 extraEntriesToAllocate)\n{\n\t// recreate file table with bigger size (optional)\n\tthis->fileTableEntries[0].name1 = FILECACHE_FILETABLE_FREE_NAME;\n\tthis->fileTableEntries[0].name2 = FILECACHE_FILETABLE_FREE_NAME;\n\tsint32 newFileTableEntryCount = this->fileTableEntryCount + extraEntriesToAllocate;\n\tthis->fileTableEntries = (FileTableEntry*)realloc(this->fileTableEntries, sizeof(FileTableEntry)*newFileTableEntryCount);\n\tfor (sint32 f = this->fileTableEntryCount; f < newFileTableEntryCount; f++)\n\t{\n\t\tthis->fileTableEntries[f].name1 = FILECACHE_FILETABLE_FREE_NAME;\n\t\tthis->fileTableEntries[f].name2 = FILECACHE_FILETABLE_FREE_NAME;\n\t\tthis->fileTableEntries[f].fileOffset = 0;\n\t\tthis->fileTableEntries[f].fileSize = 0;\n\t\tthis->fileTableEntries[f].flags = FileTableEntry::FLAGS::FLAG_NONE;\n\t\tthis->fileTableEntries[f].extraReserved1 = 0;\n\t\tthis->fileTableEntries[f].extraReserved2 = 0;\n\t\tthis->fileTableEntries[f].extraReserved3 = 0;\n\t}\n\tthis->fileTableEntryCount = newFileTableEntryCount;\n\tthis->_addFileInternal(FILECACHE_FILETABLE_NAME1, FILECACHE_FILETABLE_NAME2, (uint8*)this->fileTableEntries, sizeof(FileTableEntry)*newFileTableEntryCount, true);\n\t// update file table info in struct\n\tif (this->fileTableEntries[0].name1 != FILECACHE_FILETABLE_NAME1 || this->fileTableEntries[0].name2 != FILECACHE_FILETABLE_NAME2)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Corruption in cache file detected\");\n\t\tassert_dbg();\n\t}\n\tthis->fileTableOffset = this->fileTableEntries[0].fileOffset;\n\tthis->fileTableSize = this->fileTableEntries[0].fileSize;\n\t// update header\n\tfileStream->SetPosition(0);\n\tfileStream->writeU32(FILECACHE_MAGIC_V3);\n\tfileStream->writeU32(this->extraVersion);\n\tfileStream->writeU64(this->dataOffset);\n\tfileStream->writeU64(this->fileTableOffset);\n\tfileStream->writeU32(this->fileTableSize);\n}\n\nuint8* _fileCache_compressFileData(const uint8* fileData, uint32 fileSize, sint32& compressedSize)\n{\n\t// compress data using zlib deflate\n\t// stores the size of the uncompressed file in the first 4 bytes\n\tBytef* uncompressedInput = (Bytef*)fileData;\n\tuLongf uncompressedLen = fileSize;\n\tuLongf compressedLen = compressBound(fileSize);\n\tBytef* compressedData = (Bytef*)malloc(4 + compressedLen);\n\tint zret = compress2(compressedData + 4, &compressedLen, uncompressedInput, uncompressedLen, 4); // level 4 has good compression to performance ratio\n\tif (zret != Z_OK)\n\t{\n\t\tfree(compressedData);\n\t\treturn nullptr;\n\t}\n\tcompressedData[0] = ((uint32)fileSize >> 24) & 0xFF;\n\tcompressedData[1] = ((uint32)fileSize >> 16) & 0xFF;\n\tcompressedData[2] = ((uint32)fileSize >> 8) & 0xFF;\n\tcompressedData[3] = ((uint32)fileSize >> 0) & 0xFF;\n\tcompressedSize = 4 + compressedLen;\n\treturn compressedData;\n}\n\nbool _uncompressFileData(const uint8* rawData, size_t rawSize, std::vector<uint8>& dataOut)\n{\n\tif (rawSize < 4)\n\t{\n\t\tdataOut.clear();\n\t\treturn false;\n\t}\n\t// get size of uncompressed file\n\tuint32 fileSize = 0;\n\tfileSize |= ((uint32)rawData[0] << 24);\n\tfileSize |= ((uint32)rawData[1] << 16);\n\tfileSize |= ((uint32)rawData[2] << 8);\n\tfileSize |= ((uint32)rawData[3] << 0);\n\t// allocate buffer\n\tBytef* compressedInput = (Bytef*)rawData + 4;\n\tuLongf compressedLen = (uLongf)(rawSize - 4);\n\tuLongf uncompressedLen = fileSize;\n\tdataOut.resize(fileSize);\n\tint zret = uncompress2(dataOut.data(), &uncompressedLen, compressedInput, &compressedLen);\n\tif (zret != Z_OK)\n\t{\n\t\tdataOut.clear();\n\t\treturn false;\n\t}\n\tif (uncompressedLen != fileSize || compressedLen != (rawSize - 4))\n\t{\n\t\t// uncompressed size does not match stored size\n\t\tdataOut.clear();\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nvoid FileCache::_addFileInternal(uint64 name1, uint64 name2, const uint8* fileData, sint32 fileSize, bool noCompression)\n{\n\tif (fileSize < 0)\n\t\treturn;\n\tif (!enableCompression)\n\t\tnoCompression = true;\n\t// compress data\n\tsint32 rawSize = 0;\n\tuint8* rawData = nullptr;\n\tbool isCompressed = false;\n\tif (noCompression)\n\t{\n\t\trawData = (uint8*)fileData;\n\t\trawSize = fileSize;\n\t}\n\telse\n\t{\n\t\t// compress file\n\t\trawData = _fileCache_compressFileData(fileData, fileSize, rawSize);\n\t\tif (rawData)\n\t\t{\n\t\t\tisCompressed = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\trawData = (uint8*)fileData;\n\t\t\trawSize = fileSize;\n\t\t}\n\t}\n\tstd::unique_lock lock(this->mutex);\n\t// find free entry in file table\n\tsint32 entryIndex = -1;\n\t// scan for already existing entry\n\tfor (sint32 i = 0; i < this->fileTableEntryCount; i++)\n\t{\n\t\tif (this->fileTableEntries[i].name1 == name1 && this->fileTableEntries[i].name2 == name2)\n\t\t{\n\t\t\tentryIndex = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (entryIndex == -1)\n\t{\n\t\twhile (true)\n\t\t{\n\t\t\t// if no entry exists, search for empty one\n\t\t\tfor (sint32 i = 0; i < this->fileTableEntryCount; i++)\n\t\t\t{\n\t\t\t\tif (this->fileTableEntries[i].name1 == FILECACHE_FILETABLE_FREE_NAME && this->fileTableEntries[i].name2 == FILECACHE_FILETABLE_FREE_NAME)\n\t\t\t\t{\n\t\t\t\t\tentryIndex = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entryIndex == -1)\n\t\t\t{\n\t\t\t\tif (name1 == FILECACHE_FILETABLE_NAME1 && name2 == FILECACHE_FILETABLE_NAME2)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Error in cache file\");\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t}\n\t\t\t\t// no free entry, recreate file table with larger size\n\t\t\t\tfileCache_updateFiletable(64);\n\t\t\t\t// try again\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t}\n\t// find free space\n\tsint64 currentStartOffset = 0;\n\twhile (true)\n\t{\n\t\tbool hasCollision = false;\n\t\tsint64 currentEndOffset = currentStartOffset + rawSize;\n\t\tFileTableEntry* entry = this->fileTableEntries;\n\t\tFileTableEntry* entryLast = this->fileTableEntries + this->fileTableEntryCount;\n\t\twhile (entry < entryLast)\n\t\t{\n\t\t\tif (entry->name1 == FILECACHE_FILETABLE_FREE_NAME && entry->name2 == FILECACHE_FILETABLE_FREE_NAME)\n\t\t\t{\n\t\t\t\tentry++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (currentEndOffset >= (sint64)entry->fileOffset && currentStartOffset < (sint64)(entry->fileOffset + entry->fileSize))\n\t\t\t{\n\t\t\t\tcurrentStartOffset = entry->fileOffset + entry->fileSize;\n\t\t\t\thasCollision = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tentry++;\n\t\t}\n\t\t// optimized logic to speed up scanning for free offsets\n\t\t// assumes that most of the time entries are stored in direct succession (holds true more often than not)\n\t\tif (hasCollision && (entry + 1) < entryLast)\n\t\t{\n\t\t\tentry++;\n\t\t\twhile (entry < entryLast)\n\t\t\t{\n\t\t\t\tif (entry->name1 == FILECACHE_FILETABLE_FREE_NAME && entry->name2 == FILECACHE_FILETABLE_FREE_NAME)\n\t\t\t\t{\n\t\t\t\t\tentry++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (entry->fileOffset == currentStartOffset)\n\t\t\t\t{\n\t\t\t\t\tcurrentStartOffset = entry->fileOffset + entry->fileSize;\n\t\t\t\t\tentry++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// retry in case of collision\n\t\tif (hasCollision == false)\n\t\t\tbreak;\n\t}\n\t// update file table entry\n\tthis->fileTableEntries[entryIndex].name1 = name1;\n\tthis->fileTableEntries[entryIndex].name2 = name2;\n\tthis->fileTableEntries[entryIndex].fileOffset = currentStartOffset;\n\tthis->fileTableEntries[entryIndex].fileSize = rawSize;\n\tthis->fileTableEntries[entryIndex].flags = isCompressed ? FileTableEntry::FLAGS::FLAG_COMPRESSED : FileTableEntry::FLAGS::FLAG_NONE;\n\tthis->fileTableEntries[entryIndex].extraReserved1 = 0;\n\tthis->fileTableEntries[entryIndex].extraReserved2 = 0;\n\tthis->fileTableEntries[entryIndex].extraReserved3 = 0;\n\t// write file data\n\tfileStream->SetPosition(this->dataOffset + currentStartOffset);\n\tfileStream->writeData(rawData, rawSize);\n#ifdef __APPLE__\n    fileStream->Flush();\n#endif\n\t// write file table entry\n\tfileStream->SetPosition(this->dataOffset + this->fileTableOffset + (uint64)(sizeof(FileTableEntry)*entryIndex));\n\tfileStream->writeData(this->fileTableEntries + entryIndex, sizeof(FileTableEntry));\n#ifdef __APPLE__\n    fileStream->Flush();\n#endif\n\tif (isCompressed)\n\t\tfree(rawData);\n}\n\nvoid FileCache::AddFile(const FileName&& name, const uint8* fileData, sint32 fileSize)\n{\n\tthis->_addFileInternal(name.name1, name.name2, fileData, fileSize, false);\n}\n\nbool FileCache::DeleteFile(const FileName&& name)\n{\n\tif( name.name1 == FILECACHE_FILETABLE_NAME1 && name.name2 == FILECACHE_FILETABLE_NAME2 )\n\t\treturn false; // prevent filetable from being deleted\n\tstd::unique_lock lock(this->mutex);\n\tFileTableEntry* entry = this->fileTableEntries;\n\tFileTableEntry* entryLast = this->fileTableEntries+this->fileTableEntryCount;\n\twhile( entry < entryLast )\n\t{\n\t\tif( entry->name1 == name.name1 && entry->name2 == name.name2 )\n\t\t{\n\t\t\tentry->name1 = FILECACHE_FILETABLE_FREE_NAME;\n\t\t\tentry->name2 = FILECACHE_FILETABLE_FREE_NAME;\n\t\t\tentry->fileOffset = 0;\n\t\t\tentry->fileSize = 0;\n\t\t\t// store updated entry to file cache\n\t\t\tsize_t entryIndex = entry - this->fileTableEntries;\n\t\t\tfileStream->SetPosition(this->dataOffset+this->fileTableOffset+(uint64)(sizeof(FileTableEntry)*entryIndex));\n\t\t\tfileStream->writeData(this->fileTableEntries+entryIndex, sizeof(FileTableEntry));\n\t\t\treturn true;\n\t\t}\n\t\tentry++;\n\t}\n\treturn false;\n}\n\nvoid FileCache::AddFileAsync(const FileName& name, const uint8* fileData, sint32 fileSize)\n{\n\tFileCacheAsyncWriter.AddJob(this, name, fileData, fileSize);\n}\n\nbool FileCache::_getFileDataInternal(const FileTableEntry* entry, std::vector<uint8>& dataOut)\n{\n\tstd::vector<uint8> rawData(entry->fileSize);\n\n\tfileStream->SetPosition(this->dataOffset + entry->fileOffset);\n\tfileStream->readData(rawData.data(), entry->fileSize);\n\n\tif ((entry->flags&FileTableEntry::FLAG_COMPRESSED) == 0)\n\t{\n\t\t// uncompressed\n\t\tstd::swap(rawData, dataOut);\n\t\treturn true;\n\t}\n\t// decompress\n\tsint32 uncompressedSize = 0;\n\tif (!_uncompressFileData(rawData.data(), rawData.size(), dataOut))\n\t{\n\t\tdataOut.clear();\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool FileCache::GetFile(const FileName&& name, std::vector<uint8>& dataOut)\n{\n\tstd::unique_lock lock(this->mutex);\n\tFileTableEntry* entry = this->fileTableEntries;\n\tFileTableEntry* entryLast = this->fileTableEntries+this->fileTableEntryCount;\n\twhile( entry < entryLast )\n\t{\n\t\tif( entry->name1 == name.name1 && entry->name2 == name.name2 )\n\t\t{\n\t\t\treturn _getFileDataInternal(entry, dataOut);\n\t\t}\n\t\tentry++;\n\t}\n\tdataOut.clear();\n\treturn false;\n}\n\nbool FileCache::GetFileByIndex(sint32 index, uint64* name1, uint64* name2, std::vector<uint8>& dataOut)\n{\n\tif (index < 0 || index >= this->fileTableEntryCount)\n\t\treturn false;\n\tFileTableEntry* entry = this->fileTableEntries + index;\n\tif (this->fileTableEntries == nullptr)\n\t{\n\t\tcemuLog_log(LogType::Force, \"GetFileByIndex() fileTable is NULL\");\n\t\treturn false;\n\t}\n\tif (entry->name1 == FILECACHE_FILETABLE_FREE_NAME && entry->name2 == FILECACHE_FILETABLE_FREE_NAME)\n\t\treturn false;\n\tif (entry->name1 == FILECACHE_FILETABLE_NAME1 && entry->name2 == FILECACHE_FILETABLE_NAME2)\n\t\treturn false;\n\n\tstd::unique_lock lock(this->mutex);\n\tif(name1)\n\t\t*name1 = entry->name1;\n\tif(name2)\n\t\t*name2 = entry->name2;\n\treturn _getFileDataInternal(entry, dataOut);\n}\n\nbool FileCache::HasFile(const FileName&& name)\n{\n\tstd::unique_lock lock(this->mutex);\n\tFileTableEntry* entry = this->fileTableEntries;\n\tFileTableEntry* entryLast = this->fileTableEntries + this->fileTableEntryCount;\n\twhile (entry < entryLast)\n\t{\n\t\tif (entry->name1 == name.name1 && entry->name2 == name.name2)\n\t\t\treturn true;\n\t\tentry++;\n\t}\n\treturn false;\n}\n\nsint32 FileCache::GetMaximumFileIndex()\n{\n\treturn this->fileTableEntryCount;\n}\n\nsint32 FileCache::GetFileCount()\n{\n\tstd::unique_lock lock(this->mutex);\n\tsint32 fileCount = 0;\n\tFileTableEntry* entry = this->fileTableEntries;\n\tFileTableEntry* entryLast = this->fileTableEntries+this->fileTableEntryCount;\n\twhile( entry < entryLast )\n\t{\n\t\tif( entry->name1 == FILECACHE_FILETABLE_FREE_NAME && entry->name2 == FILECACHE_FILETABLE_FREE_NAME )\n\t\t{\n\t\t\tentry++;\n\t\t\tcontinue;\n\t\t}\n\t\tif( entry->name1 == FILECACHE_FILETABLE_NAME1 && entry->name2 == FILECACHE_FILETABLE_NAME2 )\n\t\t{\n\t\t\tentry++;\n\t\t\tcontinue;\n\t\t}\n\t\tfileCount++;\n\t\tentry++;\n\t}\n\n\treturn fileCount;\n}\n\nvoid fileCache_test()\n{\n\tFileCache* fc = FileCache::Create(\"testCache.bin\", 0);\n\tuint32 time1 = GetTickCount();\n\n\tchar* testString1 = (char*)malloc(1024 * 1024 * 8);\n\tchar* testString2 = (char*)malloc(1024 * 1024 * 8);\n\tchar* testString3 = (char*)malloc(1024 * 1024 * 8);\n\tfor (sint32 f = 0; f < 1024 * 1024 * 8; f++)\n\t{\n\t\ttestString1[f] = 'a' + (f & 7);\n\t\ttestString2[f] = 'd' + (f & 3);\n\t\ttestString3[f] = 'f' + (f & 3);\n\t}\n\n\tfor(sint32 i=0; i<2200; i++)\n\t{\n\t\tfc->AddFile({ 0x1000001ULL, (uint64)i }, (uint8*)testString1, 1024 * 1024 * 1);\n\t\tfc->AddFile({ 0x1000002ULL, (uint64)i }, (uint8*)testString2, 1024 * 1024 * 1);\n\t\tfc->AddFile({ 0x1000003ULL, (uint64)i }, (uint8*)testString3, 1024 * 1024 * 1);\n\t}\n\tuint32 time2 = GetTickCount();\n\tdebug_printf(\"Writing took %dms\\n\", time2-time1);\n\tdelete fc;\n\t// verify if all entries are still valid\n\tFileCache* fcRead = FileCache::Open(\"testCache.bin\", 0);\n\tuint32 time3 = GetTickCount();\n\tfor(sint32 i=0; i<2200; i++)\n\t{\n\t\tstd::vector<uint8> fileData;\n\t\tbool r = fcRead->GetFile({ 0x1000001ULL, (uint64)i }, fileData);\n\t\tif (!r || fileData.size() != 1024 * 1024 * 1 || memcmp(fileData.data(), testString1, 1024 * 1024 * 1) != 0)\n\t\t\tcemu_assert_debug(false);\n\t\tr = fcRead->GetFile({ 0x1000002ULL, (uint64)i }, fileData);\n\t\tif( !r || fileData.size() != 1024 * 1024 * 1 || memcmp(fileData.data(), testString2, 1024 * 1024 * 1) != 0 )\n\t\t\tcemu_assert_debug(false);\n\t\tr = fcRead->GetFile({ 0x1000003ULL, (uint64)i }, fileData);\n\t\tif( !r || fileData.size() != 1024 * 1024 * 1 || memcmp(fileData.data(), testString3, 1024 * 1024 * 1) != 0 )\n\t\t\tcemu_assert_debug(false);\n\t}\n\tuint32 time4 = GetTickCount();\n\tdebug_printf(\"Reading took %dms\\n\", time4-time3);\n\tdelete fcRead;\n\tcemu_assert_debug(false);\n\texit(0);\n}\n"
  },
  {
    "path": "src/Cemu/FileCache/FileCache.h",
    "content": "#pragma once\n\n#include <mutex>\n\nclass FileCache\n{\npublic:\n\tstruct FileName \n\t{\n\t\tFileName(uint64 name1, uint64 name2) : name1(name1), name2(name2) {};\n\t\tFileName(std::string_view filePath)\n\t\t{\n\t\t\t// name from string hash\n\t\t\tuint64 h1 = 0xa2cc2c49386a75fdull;\n\t\t\tuint64 h2 = 0x5182d367734c2ce8ull;\n\t\t\tconst char* c = filePath.data();\n\t\t\tconst char* cEnd = filePath.data() + filePath.size();\n\t\t\twhile (c < cEnd)\n\t\t\t{\n\t\t\t\tuint64 t = (uint64)*c;\n\t\t\t\tc++;\n\t\t\t\th1 = (h1 << 7) | (h1 >> (64 - 7));\n\t\t\t\th1 += t;\n\t\t\t\th2 = h2 * 7841u + t;\n\t\t\t}\n\t\t\tname1 = h1;\n\t\t\tname2 = h2;\n\t\t};\n\n\t\tFileName(const std::string& filePath) : FileName(std::basic_string_view(filePath.data(), filePath.size())) {};\n\n\t\tuint64 name1;\n\t\tuint64 name2;\n\t};\n\n\t~FileCache();\n\n\tstatic FileCache* Create(const fs::path& path, uint32 extraVersion = 0);\n\tstatic FileCache* Open(const fs::path& path, bool allowCreate, uint32 extraVersion = 0);\n\tstatic FileCache* Open(const fs::path& path); // open without extraVersion check\n\n\tvoid UseCompression(bool enable) { enableCompression = enable; };\n\n\tvoid AddFile(const FileName&& name, const uint8* fileData, sint32 fileSize);\n\tvoid AddFileAsync(const FileName& name, const uint8* fileData, sint32 fileSize);\n\tbool DeleteFile(const FileName&& name);\n\tbool GetFile(const FileName&& name, std::vector<uint8>& dataOut);\n\tbool GetFileByIndex(sint32 index, uint64* name1, uint64* name2, std::vector<uint8>& dataOut);\n\tbool HasFile(const FileName&& name);\n\n\tsint32 GetFileCount();\n\n\tsint32 GetMaximumFileIndex();\n\nprivate:\n\tstruct FileTableEntry\n\t{\n\t\tenum FLAGS : uint8\n\t\t{\n\t\t\tFLAG_NONE = 0x00,\n\t\t\tFLAG_COMPRESSED = (1 << 0), // zLib compressed\n\t\t};\n\t\tuint64 name1;\n\t\tuint64 name2;\n\t\tuint64 fileOffset;\n\t\tuint32 fileSize;\n\t\tFLAGS flags;\n\t\tuint8 extraReserved1;\n\t\tuint8 extraReserved2;\n\t\tuint8 extraReserved3;\n\t};\n\n\tstatic_assert(sizeof(FileTableEntry) == 0x20);\n\n\tFileCache() {};\n\n\tstatic FileCache* _OpenExisting(const fs::path& path, bool compareExtraVersion, uint32 extraVersion = 0);\n\n\tvoid fileCache_updateFiletable(sint32 extraEntriesToAllocate);\n\tvoid _addFileInternal(uint64 name1, uint64 name2, const uint8* fileData, sint32 fileSize, bool noCompression);\n\tbool _getFileDataInternal(const FileTableEntry* entry, std::vector<uint8>& dataOut);\n\n\tclass FileStream* fileStream{};\n\tuint64 dataOffset{};\n\tuint32 extraVersion{};\n\t// file table\n\tFileTableEntry* fileTableEntries{};\n\tsint32 fileTableEntryCount{};\n\t// file table (as stored in file)\n\tuint64 fileTableOffset{};\n\tuint32 fileTableSize{};\n\t// options\n\tbool enableCompression{true};\n\n\tstd::recursive_mutex mutex;\n};\n"
  },
  {
    "path": "src/Cemu/Logging/CemuDebugLogging.h",
    "content": "#pragma once\n\n// printf-style macros that are only active in non-release builds\n\n#ifndef CEMU_DEBUG_ASSERT\n#define debug_printf(...)\nstatic void debugBreakpoint() { }\n#else\n#define debug_printf(...) printf(__VA_ARGS__)\nstatic void debugBreakpoint() {}\n#endif"
  },
  {
    "path": "src/Cemu/Logging/CemuLogging.cpp",
    "content": "#include \"CemuLogging.h\"\n#include \"Common/precompiled.h\"\n#include \"util/helpers/helpers.h\"\n#include \"config/CemuConfig.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/LaunchSettings.h\"\n\n#include <mutex>\n#include <condition_variable>\n#include <chrono>\n\n#include <fmt/printf.h>\n\nuint64 s_loggingFlagMask = cemuLog_getFlag(LogType::Force);\n\nclass LoggingDispatcher\n{\n  private:\n\tstatic inline class DefaultLoggingCallbacks : public LoggingCallbacks\n\t{\n\t} s_defaultCallbacks;\n\n\tLoggingCallbacks* m_loggingCallbacks = &s_defaultCallbacks;\n\tstd::shared_mutex m_mutex;\n\n  public:\n\tvoid Log(std::string_view filter, std::string_view message)\n\t{\n\t\tstd::shared_lock lock(m_mutex);\n\t\tm_loggingCallbacks->Log(filter, message);\n\t}\n\n\tvoid Log(std::string_view message)\n\t{\n\t\tLog(\"\", message);\n\t}\n\n\tvoid Log(std::string_view filter, std::wstring_view message)\n\t{\n\t\tstd::shared_lock lock(m_mutex);\n\t\tm_loggingCallbacks->Log(filter, message);\n\t}\n\n\tvoid Log(std::wstring_view message)\n\t{\n\t\tLog(\"\", message);\n\t}\n\n\tvoid setCallbacks(LoggingCallbacks* loggingCallbacks)\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\tcemu_assert_debug(m_loggingCallbacks == &s_defaultCallbacks);\n\t\tm_loggingCallbacks = loggingCallbacks;\n\t}\n\n\tvoid clearCallbacks()\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\tcemu_assert_debug(m_loggingCallbacks != &s_defaultCallbacks);\n\t\tm_loggingCallbacks = &s_defaultCallbacks;\n\t}\n} s_loggingDispatcher;\n\nvoid cemuLog_setCallbacks(LoggingCallbacks* loggingCallbacks)\n{\n\ts_loggingDispatcher.setCallbacks(loggingCallbacks);\n}\n\nvoid cemuLog_clearCallbacks()\n{\n\ts_loggingDispatcher.clearCallbacks();\n}\n\nstruct _LogContext\n{\n\tstd::condition_variable_any log_condition;\n\tstd::recursive_mutex log_mutex;\n\tstd::ofstream file_stream;\n\tstd::vector<std::string> text_cache;\n\tstd::thread log_writer;\n\tstd::atomic<bool> threadRunning = false;\n\n\t~_LogContext()\n\t{\n\t\t// safely shut down the log writer thread\n\t\tthreadRunning.store(false);\n\t\tif (log_writer.joinable())\n\t\t{\n\t\t\tlog_condition.notify_one();\n\t\t\tlog_writer.join();\n\t\t}\n\t}\n}LogContext;\n\nconst std::map<LogType, std::string> g_logging_window_mapping\n{\n\t{LogType::UnsupportedAPI,     \"Unsupported API calls\"},\n\t{LogType::APIErrors, \t\t  \"Invalid API usage\"},\n\t{LogType::CoreinitLogging,    \"Coreinit Logging\"},\n\t{LogType::CoreinitFile,       \"Coreinit File-Access\"},\n\t{LogType::CoreinitThreadSync, \"Coreinit Thread-Synchronization\"},\n\t{LogType::CoreinitMem,        \"Coreinit Memory\"},\n\t{LogType::CoreinitMP,         \"Coreinit MP\"},\n\t{LogType::CoreinitThread,     \"Coreinit Thread\"},\n\t{LogType::NN_NFP,             \"nn::nfp\"},\n\t{LogType::NN_FP,              \"nn::fp\"},\n\t{LogType::NN_BOSS,            \"nn::boss\"},\n\t{LogType::GX2,                \"GX2\"},\n\t{LogType::SoundAPI,           \"Audio\"},\n\t{LogType::InputAPI,           \"Input\"},\n\t{LogType::Socket,             \"Socket\"},\n\t{LogType::Save,               \"Save\"},\n\t{LogType::H264,               \"H264\"},\n\t{LogType::NFC,                \"NFC\"},\n\t{LogType::NTAG,               \"NTAG\"},\n\t{LogType::Patches,            \"Graphic pack patches\"},\n\t{LogType::TextureCache,       \"Texture cache\"},\n\t{LogType::TextureReadback,    \"Texture readback\"},\n\t{LogType::OpenGLLogging,      \"OpenGL debug output\"},\n\t{LogType::VulkanValidation,   \"Vulkan validation layer\"},\n};\n\nbool cemuLog_advancedPPCLoggingEnabled()\n{\n\treturn GetConfig().advanced_ppc_logging;\n}\n\nvoid cemuLog_thread()\n{\n\tSetThreadName(\"cemuLog_thread\");\n\twhile (true)\n\t{\n\t\tstd::unique_lock lock(LogContext.log_mutex);\n\t\twhile (LogContext.text_cache.empty())\n\t\t{\n\t\t\tLogContext.log_condition.wait(lock);\n\t\t\tif (!LogContext.threadRunning.load(std::memory_order::relaxed))\n\t\t\t\treturn;\n\t\t}\n\n\t\tstd::vector<std::string> cache_copy;\n\t\tcache_copy.swap(LogContext.text_cache); // fast copy & clear\n\t\tlock.unlock();\n\n\t\tfor (const auto& entry : cache_copy)\n\t\t\tLogContext.file_stream.write(entry.data(), entry.size());\n\n\t\tLogContext.file_stream.flush();\n\t}\n}\n\nfs::path cemuLog_GetLogFilePath()\n{\n    return ActiveSettings::GetUserDataPath(\"log.txt\");\n}\n\nvoid cemuLog_createLogFile(bool triggeredByCrash)\n{\n\tstd::unique_lock lock(LogContext.log_mutex);\n\tif (LogContext.file_stream.is_open())\n\t\treturn;\n\n\tconst auto path = cemuLog_GetLogFilePath();\n\tLogContext.file_stream.open(path, std::ios::out);\n\tif (LogContext.file_stream.fail())\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\n\tLogContext.threadRunning.store(true);\n\tLogContext.log_writer = std::thread(cemuLog_thread);\n\tlock.unlock();\n}\n\nvoid cemuLog_writeLineToLog(std::string_view text, bool date, bool new_line)\n{\n\tstd::unique_lock lock(LogContext.log_mutex);\n\n\tif (date)\n\t{\n\t\tconst auto now = std::chrono::system_clock::now();\n\t\tconst auto temp_time = std::chrono::system_clock::to_time_t(now);\n\t\tconst auto& time = *std::localtime(&temp_time);\n\n\t\tauto time_str = fmt::format(\"[{:02d}:{:02d}:{:02d}.{:03d}] \", time.tm_hour, time.tm_min, time.tm_sec,\n\t\t\tstd::chrono::duration_cast<std::chrono::milliseconds>(now - std::chrono::time_point_cast<std::chrono::seconds>(now)).count());\n\n\t\tLogContext.text_cache.emplace_back(std::move(time_str));\n\t}\n\n\tLogContext.text_cache.emplace_back(text);\n\n\tif (new_line)\n\t\tLogContext.text_cache.emplace_back(\"\\n\");\n\n\tlock.unlock();\n\tLogContext.log_condition.notify_one();\n}\n\nbool cemuLog_log(LogType type, std::string_view text)\n{\n\tif (!cemuLog_isLoggingEnabled(type))\n\t\treturn false;\n\n\tif (LaunchSettings::Verbose())\n\t\tstd::cout << text << std::endl;\n\n\tcemuLog_writeLineToLog(text);\n\n\tconst auto it = std::find_if(g_logging_window_mapping.cbegin(), g_logging_window_mapping.cend(),\n\t\t[type](const auto& entry) { return entry.first == type; });\n\tif (it == g_logging_window_mapping.cend())\n\t\ts_loggingDispatcher.Log(text);\n\telse\n\t\ts_loggingDispatcher.Log(it->second, text);\n\n\treturn true;\n}\n\nbool cemuLog_log(LogType type, std::u8string_view text)\n{\n\tstd::basic_string_view<char> s((char*)text.data(), text.size());\n\treturn cemuLog_log(type, s);\n}\n\nvoid cemuLog_logHexDump(LogType type, const void* data, size_t size, size_t lineSize)\n{\n\tconst uint8* dataU8 = static_cast<const uint8*>(data);\n\tstd::vector<char> hexLine;\n\thexLine.resize(6 + lineSize * 3 + 1, ' ');\n\tfor (size_t i = 0; i < size; i += lineSize)\n\t{\n\t\tsprintf(hexLine.data(), \"%04X: \", (int)i);\n\t\tsize_t remainingSize = std::min<size_t>(lineSize, size - i);\n\t\tfor (size_t j=0; j<remainingSize; j++)\n\t\t\tsprintf(hexLine.data() + 6 + j * 3, \"%02X \", dataU8[j]);\n\t\tdataU8 += remainingSize;\n\t\tif (remainingSize == lineSize)\n\t\t\thexLine.resize(6 + remainingSize * 3 + 1);\n\t\tcemuLog_log(type, hexLine.data());\n\t}\n}\n\nvoid cemuLog_waitForFlush()\n{\n\tcemuLog_createLogFile(false);\n\tstd::unique_lock lock(LogContext.log_mutex);\n\twhile(!LogContext.text_cache.empty())\n\t{\n\t\tlock.unlock();\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\tstd::this_thread::yield();\n\t\tlock.lock();\n\t}\n}\n\n// used to atomically write multiple lines to the log\nstd::unique_lock<decltype(LogContext.log_mutex)> cemuLog_acquire()\n{\n\treturn std::unique_lock(LogContext.log_mutex);\n}\n\nvoid cemuLog_setActiveLoggingFlags(uint64 flagMask)\n{\n\ts_loggingFlagMask = flagMask | cemuLog_getFlag(LogType::Force);\n}\n"
  },
  {
    "path": "src/Cemu/Logging/CemuLogging.h",
    "content": "#pragma once\n\nextern uint64 s_loggingFlagMask;\n\nenum class LogType : sint32\n{\n\t// note: IDs must be in range 1-64\n\tForce = 63, // always enabled\n\tPlaceholder = 62, // always disabled\n\tAPIErrors = 61, // Logs bad parameters or other API usage mistakes or unintended errors in OS libs. Intended for homebrew developers\n\n\tCoreinitFile = 0,\n\tGX2 = 1,\n\tUnsupportedAPI = 2,\n\tSoundAPI = 4, // any audio related API\n\tInputAPI = 5, // any input related API\n\tSocket = 6,\n\tSave = 7,\n\tH264 = 9,\n\tOpenGLLogging = 10, // OpenGL debug logging\n\tTextureCache = 11, // texture cache warnings and info\n\tVulkanValidation = 12, // Vulkan validation layer\n\tPatches = 14,\n\tCoreinitMem = 8, // coreinit memory functions\n\tCoreinitMP = 15,\n\tCoreinitThread = 16,\n\tCoreinitLogging = 17, // OSReport, OSConsoleWrite etc.\n\tCoreinitMemoryMapping = 18, // OSGetAvailPhysAddrRange, OSAllocVirtAddr, OSMapMemory etc.\n\tCoreinitAlarm = 22,\n\tCoreinitThreadSync = 3,\n\n\tPPC_IPC = 19,\n\tNN_AOC = 20,\n\tNN_PDM = 21,\n\tNN_OLV = 23,\n\tNN_NFP = 13,\n\tNN_FP = 24,\n\tNN_BOSS = 25,\n\tNN_SL = 26,\n\n\tTextureReadback = 29,\n\tProcUi = 39,\n\tnlibcurl = 41,\n\n\tPRUDP = 40,\n\n\tNFC\t= 41,\n\tNTAG = 42,\n\tRecompiler = 60,\n};\n\ntemplate <>\nstruct fmt::formatter<std::u8string_view> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(std::u8string_view v, FormatContext& ctx)\n\t{\n\t\tstring_view s((char*)v.data(), v.size());\n\t\treturn formatter<string_view>::format(s, ctx);\n\t}\n};\n\nvoid cemuLog_writeLineToLog(std::string_view text, bool date = true, bool new_line = true);\ninline void cemuLog_writePlainToLog(std::string_view text) { cemuLog_writeLineToLog(text, false, false); }\n\nvoid cemuLog_setActiveLoggingFlags(uint64 flagMask);\n\ninline uint64 cemuLog_getFlag(LogType type)\n{\n\treturn 1ULL << (uint64)type;\n}\n\ninline bool cemuLog_isLoggingEnabled(LogType type)\n{\n\treturn (s_loggingFlagMask & cemuLog_getFlag(type)) != 0;\n}\n\nbool cemuLog_log(LogType type, std::string_view text);\nbool cemuLog_log(LogType type, std::u8string_view text);\nvoid cemuLog_waitForFlush(); // wait until all log lines are written\n\ntemplate<typename T, typename ... TArgs>\nbool cemuLog_log(LogType type, std::basic_string<T> formatStr, TArgs&&... args)\n{\n\tif (!cemuLog_isLoggingEnabled(type))\n\t\treturn false;\n\tif constexpr (sizeof...(TArgs) == 0)\n\t{\n\t\tcemuLog_log(type, std::basic_string_view<T>(formatStr.data(), formatStr.size()));\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tconst auto format_view = fmt::basic_string_view<T>(formatStr);\n#if FMT_VERSION >= 110000\n\t\tconst auto text = fmt::vformat(format_view, fmt::make_format_args<fmt::buffered_context<T>>(args...));\n#else\n\t\tconst auto text = fmt::vformat(format_view, fmt::make_format_args<fmt::buffer_context<T>>(args...));\n#endif\n\t\tcemuLog_log(type, std::basic_string_view(text.data(), text.size()));\n\t}\n\treturn true;\n}\n\ntemplate<typename T, typename ... TArgs>\nbool cemuLog_log(LogType type, const T* format, TArgs&&... args)\n{\n\tif (!cemuLog_isLoggingEnabled(type))\n\t\treturn false;\n\tauto format_str = std::basic_string<T>(format);\n\treturn cemuLog_log(type, format_str, std::forward<TArgs>(args)...);\n}\n\n#define cemuLog_logOnce(...) { static bool _not_first_call = false; if (!_not_first_call) { _not_first_call = true; cemuLog_log(__VA_ARGS__); } }\n\n// same as cemuLog_log, but only outputs in debug mode\ntemplate<typename TFmt, typename ... TArgs>\nbool cemuLog_logDebug(LogType type, TFmt format, TArgs&&... args)\n{\n#ifdef CEMU_DEBUG_ASSERT\n\treturn cemuLog_log(type, format, std::forward<TArgs>(args)...);\n#else\n\treturn false;\n#endif\n}\n\n#define cemuLog_logDebugOnce(...) { static bool _not_first_call = false; if (!_not_first_call) { _not_first_call = true; cemuLog_logDebug(__VA_ARGS__); } }\n\n// utility function for logging binary data as a hex dump\nvoid cemuLog_logHexDump(LogType type, const void* data, size_t size, size_t lineSize = 16);\n\n// cafe lib calls\nbool cemuLog_advancedPPCLoggingEnabled();\n\nuint64 cemuLog_getFlag(LogType type);\n\nfs::path cemuLog_GetLogFilePath();\nvoid cemuLog_createLogFile(bool triggeredByCrash);\n[[nodiscard]] std::unique_lock<std::recursive_mutex> cemuLog_acquire(); // used for logging multiple lines at once\n\nclass LoggingCallbacks\n{\n  public:\n\tvirtual void Log(std::string_view filter, std::string_view message) {};\n\tvirtual void Log(std::string_view filter, std::wstring_view message) {};\n\tvirtual ~LoggingCallbacks() = default;\n};\n\nvoid cemuLog_setCallbacks(LoggingCallbacks* loggingCallbacks);\nvoid cemuLog_clearCallbacks();\n"
  },
  {
    "path": "src/Cemu/PPCAssembler/ppcAssembler.cpp",
    "content": "#include \"Cemu/PPCAssembler/ppcAssembler.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h\"\n#include \"Cemu/ExpressionParser/ExpressionParser.h\"\n#include \"util/helpers/helpers.h\"\n\n#include <boost/container/small_vector.hpp>\n#include <boost/static_string/static_string.hpp>\n\nstruct ppcAssemblerStr_t\n{\n\tppcAssemblerStr_t(const char* start, const char* end) : str(start, end - start) {};\n\tppcAssemblerStr_t(const char* start, size_t len) : str(start, len) {};\n\n\tstd::string_view str;\n};\n\nstruct PPCAssemblerContext\n{\n\tPPCAssemblerInOut* ctx;\n\tboost::container::small_vector<ppcAssemblerStr_t, 8> listOperandStr;\n\tstruct PPCInstructionDef* iDef;\n\tuint32 opcode;\n};\n\n// table based assembler/disassembler\n\n#define operand0Bit\t(1<<0)\n#define operand1Bit\t(1<<1)\n#define operand2Bit\t(1<<2)\n#define operand3Bit\t(1<<3)\n#define operand4Bit\t(1<<4)\n\n#define OPC_NONE\t\t\t(0xFFFF)\n#define OPC_EXTENDED_BIT\t(0x8000) // use extended sub opcode\n\nenum\n{\n\tOP_FORM_UNUSED,\n\tOP_FORM_XL_CR, // CRXOR, CRAND etc.\n\tOP_FORM_OP3_A_CMP, \n\tOP_FORM_OP3_A_IMM, // rA, rS, rB is imm - has RC bit\n\tOP_FORM_BRANCH_S16,\n\tOP_FORM_BRANCH_S24,\n\tOP_FORM_OP2_D_HSIMM, // rD, signed imm shifted imm (high half)\n\tOP_FORM_RLWINM,\n\tOP_FORM_RLWINM_EXTENDED, // alternative mnemonics of rlwinm\n\tOP_FORM_RLWNM,\n\tOP_FORM_RLWNM_EXTENDED, // alternative mnemonics of rlwnm\n\tOP_FORM_CMP_SIMM, // cr, rD, r\n\tOP_FORM_NO_OPERAND,\n\t// FP\n\tOP_FORM_X_FP_CMP,\n\n\t// new generic form with operand encoding stored in the table entry, everything above is deprecated\n\tOP_FORM_DYNAMIC,\n};\n\nconst char* ppcAssembler_getInstructionName(uint32 ppcAsmOp)\n{\n\tswitch (ppcAsmOp)\n\t{\n\tcase PPCASM_OP_UKN: return \"UKN\";\n\n\tcase PPCASM_OP_ADDI: return \"ADDI\";\n\tcase PPCASM_OP_SUBI: return \"SUBI\";\n\tcase PPCASM_OP_ADDIS: return \"ADDIS\";\n\tcase PPCASM_OP_ADDIC: return \"ADDIC\";\n\tcase PPCASM_OP_ADDIC_: return \"ADDIC.\";\n\n\tcase PPCASM_OP_ADD: return \"ADD\";\n\tcase PPCASM_OP_ADD_: return \"ADD.\";\n\tcase PPCASM_OP_SUBF: return \"SUBF\";\n\tcase PPCASM_OP_SUBF_: return \"SUBF.\";\n\tcase PPCASM_OP_SUBFC: return \"SUBFC\";\n\tcase PPCASM_OP_SUBFC_: return \"SUBFC.\";\n\tcase PPCASM_OP_SUBFE: return \"SUBFE\";\n\tcase PPCASM_OP_SUBFE_: return \"SUBFE.\";\n\tcase PPCASM_OP_SUBFIC: return \"SUBFIC\";\n\n\tcase PPCASM_OP_SUB: return \"SUB\";\n\tcase PPCASM_OP_SUB_: return \"SUB.\";\n\n\tcase PPCASM_OP_MULLI: return \"MULLI\";\n\tcase PPCASM_OP_MULLW: return \"MULLW\";\n\tcase PPCASM_OP_MULLW_: return \"MULLW.\";\n\tcase PPCASM_OP_MULHW: return \"MULHW\";\n\tcase PPCASM_OP_MULHW_: return \"MULHW.\";\n\tcase PPCASM_OP_MULHWU: return \"MULHWU\";\n\tcase PPCASM_OP_MULHWU_: return \"MULHWU.\";\n\n\tcase PPCASM_OP_DIVW: return \"DIVW\";\n\tcase PPCASM_OP_DIVW_: return \"DIVW.\";\n\tcase PPCASM_OP_DIVWU: return \"DIVWU\";\n\tcase PPCASM_OP_DIVWU_: return \"DIVWU.\";\n\n\tcase PPCASM_OP_AND:\t\treturn \"AND\";\n\tcase PPCASM_OP_AND_:\treturn \"AND.\";\n\tcase PPCASM_OP_ANDC:\treturn \"ANDC\";\n\tcase PPCASM_OP_ANDC_:\treturn \"ANDC.\";\n\n\tcase PPCASM_OP_ANDI_:\treturn \"ANDI.\";\n\tcase PPCASM_OP_ANDIS_:\treturn \"ANDIS.\";\n\tcase PPCASM_OP_OR:\t\treturn \"OR\";\n\tcase PPCASM_OP_OR_:\t\treturn \"OR.\";\n\tcase PPCASM_OP_ORI:\t\treturn \"ORI\";\n\tcase PPCASM_OP_ORIS:\treturn \"ORIS\";\n\tcase PPCASM_OP_ORC:\t\treturn \"ORC\";\n\tcase PPCASM_OP_XOR:\t\treturn \"XOR\";\n\tcase PPCASM_OP_NOR:\t\treturn \"NOR\";\n\tcase PPCASM_OP_NOR_:\treturn \"NOR.\";\n\tcase PPCASM_OP_NOT:\t\treturn \"NOT\";\n\tcase PPCASM_OP_NOT_:\treturn \"NOT.\";\n\tcase PPCASM_OP_NEG:\t\treturn \"NEG\";\n\tcase PPCASM_OP_NEG_:\treturn \"NEG.\";\n\tcase PPCASM_OP_XORI:\treturn \"XORI\";\n\tcase PPCASM_OP_XORIS:\treturn \"XORIS\";\n\tcase PPCASM_OP_SRAW:\treturn \"SRAW\";\n\tcase PPCASM_OP_SRAW_:\treturn \"SRAW.\";\n\tcase PPCASM_OP_SRAWI:\treturn \"SRAWI\";\n\tcase PPCASM_OP_SRAWI_:\treturn \"SRAWI.\";\n\tcase PPCASM_OP_SLW:\t\treturn \"SLW\";\n\tcase PPCASM_OP_SLW_:\treturn \"SLW.\";\n\tcase PPCASM_OP_SRW:\t\treturn \"SRW\";\n\tcase PPCASM_OP_SRW_:\treturn \"SRW.\";\n\n\tcase PPCASM_OP_RLWINM:\treturn \"RLWINM\";\n\tcase PPCASM_OP_RLWINM_:\treturn \"RLWINM.\";\n\tcase PPCASM_OP_RLWIMI:\treturn \"RLWIMI\";\n\tcase PPCASM_OP_RLWIMI_:\treturn \"RLWIMI.\";\n\n\tcase PPCASM_OP_EXTLWI: return \"EXTLWI\";\n\tcase PPCASM_OP_EXTLWI_: return \"EXTLWI.\";\n\tcase PPCASM_OP_EXTRWI: return \"EXTRWI\";\n\tcase PPCASM_OP_EXTRWI_: return \"EXTRWI.\";\n\n\tcase PPCASM_OP_ROTLWI: return \"ROTLWI\";\n\tcase PPCASM_OP_ROTLWI_: return \"ROTLWI.\";\n\tcase PPCASM_OP_ROTRWI: return \"ROTRWI\";\n\tcase PPCASM_OP_ROTRWI_: return \"ROTRWI.\";\n\n\tcase PPCASM_OP_SLWI: return \"SLWI\";\n\tcase PPCASM_OP_SLWI_: return \"SLWI.\";\n\tcase PPCASM_OP_SRWI: return \"SRWI\";\n\tcase PPCASM_OP_SRWI_: return \"SRWI.\";\n\n\tcase PPCASM_OP_CLRLWI: return \"CLRLWI\";\n\tcase PPCASM_OP_CLRLWI_: return \"CLRLWI.\";\n\tcase PPCASM_OP_CLRRWI: return \"CLRRWI\";\n\tcase PPCASM_OP_CLRRWI_: return \"CLRRWI.\";\n\n\tcase PPCASM_OP_RLWNM: return \"RLWNM\";\n\tcase PPCASM_OP_RLWNM_: return \"RLWNM.\";\n\n\tcase PPCASM_OP_ROTLW: return \"ROTLW\";\n\tcase PPCASM_OP_ROTLW_: return \"ROTLW.\";\n\n\tcase PPCASM_OP_CMPWI: return \"CMPWI\";\n\tcase PPCASM_OP_CMPLWI: return \"CMPLWI\";\n\tcase PPCASM_OP_CMPW: return \"CMPW\";\n\tcase PPCASM_OP_CMPLW: return \"CMPLW\";\n\n\tcase PPCASM_OP_MR: return \"MR\";\n\tcase PPCASM_OP_MR_: return \"MR.\";\n\n\tcase PPCASM_OP_EXTSB: return \"EXTSB\";\n\tcase PPCASM_OP_EXTSH: return \"EXTSH\";\n\tcase PPCASM_OP_CNTLZW: return \"CNTLZW\";\n\tcase PPCASM_OP_EXTSB_: return \"EXTSB.\";\n\tcase PPCASM_OP_EXTSH_: return \"EXTSH.\";\n\tcase PPCASM_OP_CNTLZW_: return \"CNTLZW.\";\n\n\tcase PPCASM_OP_MFSPR: return \"MFSPR\";\n\tcase PPCASM_OP_MTSPR: return \"MTSPR\";\n\n\tcase PPCASM_OP_LMW: return \"LMW\";\n\tcase PPCASM_OP_LWZ: return \"LWZ\";\n\tcase PPCASM_OP_LWZU: return \"LWZU\";\n\tcase PPCASM_OP_LWZX: return \"LWZX\";\n\tcase PPCASM_OP_LWZUX: return \"LWZUX\";\n\tcase PPCASM_OP_LHZ: return \"LHZ\";\n\tcase PPCASM_OP_LHZU: return \"LHZU\";\n\tcase PPCASM_OP_LHZX: return \"LHZX\";\n\tcase PPCASM_OP_LHZUX: return \"LHZUX\";\n\tcase PPCASM_OP_LHA: return \"LHA\";\n\tcase PPCASM_OP_LHAU: return \"LHAU\";\n\tcase PPCASM_OP_LHAX: return \"LHAX\";\n\tcase PPCASM_OP_LHAUX: return \"LHAUX\";\n\tcase PPCASM_OP_LBZ: return \"LBZ\";\n\tcase PPCASM_OP_LBZU: return \"LBZU\";\n\tcase PPCASM_OP_LBZX: return \"LBZX\";\n\tcase PPCASM_OP_LBZUX: return \"LBZUX\";\n\tcase PPCASM_OP_STMW: return \"STMW\";\n\tcase PPCASM_OP_STW: return \"STW\";\n\tcase PPCASM_OP_STWU: return \"STWU\";\n\tcase PPCASM_OP_STWX: return \"STWX\";\n\tcase PPCASM_OP_STWUX: return \"STWUX\";\n\tcase PPCASM_OP_STH: return \"STH\";\n\tcase PPCASM_OP_STHU: return \"STHU\";\n\tcase PPCASM_OP_STHX: return \"STHX\";\n\tcase PPCASM_OP_STHUX: return \"STHUX\";\n\tcase PPCASM_OP_STB: return \"STB\";\n\tcase PPCASM_OP_STBU: return \"STBU\";\n\tcase PPCASM_OP_STBX: return \"STBX\";\n\tcase PPCASM_OP_STBUX: return \"STBUX\";\n\tcase PPCASM_OP_STSWI: return \"STSWI\";\n\tcase PPCASM_OP_STWBRX: return \"STWBRX\";\n\tcase PPCASM_OP_STHBRX: return \"STHBRX\";\n\n\tcase PPCASM_OP_LWARX: return \"LWARX\";\n\tcase PPCASM_OP_STWCX_: return \"STWCX.\";\n\n\tcase PPCASM_OP_B: return \"B\";\n\tcase PPCASM_OP_BL: return \"BL\";\n\tcase PPCASM_OP_BA: return \"BA\";\n\tcase PPCASM_OP_BLA: return \"BLA\";\n\t\t\n\tcase PPCASM_OP_BC: return \"BC\";\n\tcase PPCASM_OP_BNE: return \"BNE\";\n\tcase PPCASM_OP_BEQ: return \"BEQ\";\n\tcase PPCASM_OP_BGE: return \"BGE\";\n\tcase PPCASM_OP_BGT: return \"BGT\";\n\tcase PPCASM_OP_BLT: return \"BLT\";\n\tcase PPCASM_OP_BLE:\treturn \"BLE\";\n\tcase PPCASM_OP_BDZ: return \"BDZ\";\n\tcase PPCASM_OP_BDNZ: return \"BDNZ\";\n\n\tcase PPCASM_OP_BLR:   return \"BLR\";\n\tcase PPCASM_OP_BLTLR: return \"BLTLR\";\n\tcase PPCASM_OP_BLELR: return \"BLELR\";\n\tcase PPCASM_OP_BEQLR: return \"BEQLR\";\n\tcase PPCASM_OP_BGELR: return \"BGELR\";\n\tcase PPCASM_OP_BGTLR: return \"BGTLR\";\n\tcase PPCASM_OP_BNELR: return \"BNELR\";\n\n\tcase PPCASM_OP_BCTR: return \"BCTR\";\n\tcase PPCASM_OP_BCTRL: return \"BCTRL\";\n\t\t\n\tcase PPCASM_OP_LFS:\treturn \"LFS\";\n\tcase PPCASM_OP_LFSU: return \"LFSU\";\n\tcase PPCASM_OP_LFSX: return \"LFSX\";\n\tcase PPCASM_OP_LFSUX: return \"LFSUX\";\n\tcase PPCASM_OP_LFD: return \"LFD\";\n\tcase PPCASM_OP_LFDU: return \"LFDU\";\n\tcase PPCASM_OP_LFDX: return \"LFDX\";\n\tcase PPCASM_OP_LFDUX: return \"LFDUX\";\n\tcase PPCASM_OP_STFS: return \"STFS\";\n\tcase PPCASM_OP_STFSU: return \"STFSU\";\n\tcase PPCASM_OP_STFSX: return \"STFSX\";\n\tcase PPCASM_OP_STFSUX: return \"STFSUX\";\n\tcase PPCASM_OP_STFD: return \"STFD\";\n\tcase PPCASM_OP_STFDU: return \"STFDU\";\n\tcase PPCASM_OP_STFDX: return \"STFDX\";\n\tcase PPCASM_OP_STFDUX: return \"STFDUX\";\n\n\tcase PPCASM_OP_STFIWX: return \"STFIWX\";\n\n\tcase PPCASM_OP_PS_MERGE00: return \"PS_MERGE00\";\n\tcase PPCASM_OP_PS_MERGE01: return \"PS_MERGE01\";\n\tcase PPCASM_OP_PS_MERGE10: return \"PS_MERGE10\";\n\tcase PPCASM_OP_PS_MERGE11: return \"PS_MERGE11\";\n\tcase PPCASM_OP_PS_ADD: return \"PS_ADD\";\n\tcase PPCASM_OP_PS_SUB: return \"PS_SUB\";\n\tcase PPCASM_OP_PS_DIV: return \"PS_DIV\";\n\tcase PPCASM_OP_PS_MUL: return \"PS_MUL\";\n\tcase PPCASM_OP_PS_MADD: return \"PS_MADD\";\n\tcase PPCASM_OP_PS_MSUB: return \"PS_MSUB\";\n\tcase PPCASM_OP_PS_NMADD: return \"PS_NMADD\";\n\tcase PPCASM_OP_PS_NMSUB: return \"PS_NMSUB\";\n\n\tcase PPCASM_OP_FMR: return \"FMR\";\n\tcase PPCASM_OP_FABS: return \"FABS\";\n\tcase PPCASM_OP_FNEG: return \"FNEG\";\n\tcase PPCASM_OP_FRSP: return \"FRSP\";\n\tcase PPCASM_OP_FRSQRTE: return \"FRSQRTE\";\n\tcase PPCASM_OP_FADD: return \"FADD\";\n\tcase PPCASM_OP_FADDS: return \"FADDS\";\n\tcase PPCASM_OP_FSUB: return \"FSUB\";\n\tcase PPCASM_OP_FSUBS: return \"FSUBS\";\n\tcase PPCASM_OP_FMUL: return \"FMUL\";\n\tcase PPCASM_OP_FMULS: return \"FMULS\";\n\tcase PPCASM_OP_FDIV: return \"FDIV\";\n\tcase PPCASM_OP_FDIVS: return \"FDIVS\";\n\n\tcase PPCASM_OP_FMADD: return \"FMADD\";\n\tcase PPCASM_OP_FMADDS: return \"FMADDS\";\n\tcase PPCASM_OP_FNMADD: return \"FNMADD\";\n\tcase PPCASM_OP_FNMADDS: return \"FNMADDS\";\n\tcase PPCASM_OP_FMSUB: return \"FMSUB\";\n\tcase PPCASM_OP_FMSUBS: return \"FMSUBS\";\n\tcase PPCASM_OP_FNMSUB: return \"FNMSUB\";\n\tcase PPCASM_OP_FNMSUBS: return \"FNMSUBS\";\n\n\tcase PPCASM_OP_FCTIWZ: return \"FCTIWZ\";\n\n\tcase PPCASM_OP_FCMPU: return \"FCMPU\";\n\tcase PPCASM_OP_FCMPO: return \"FCMPO\";\n\n\tcase PPCASM_OP_ISYNC: return \"ISYNC\";\n\n\tcase PPCASM_OP_NOP: return \"NOP\";\n\tcase PPCASM_OP_LI: return \"LI\";\n\tcase PPCASM_OP_LIS: return \"LIS\";\n\n\tcase PPCASM_OP_MFLR: return \"MFLR\";\n\tcase PPCASM_OP_MTLR: return \"MTLR\";\n\tcase PPCASM_OP_MFCTR: return \"MFCTR\";\n\tcase PPCASM_OP_MTCTR: return \"MTCTR\";\n\n\tcase PPCASM_OP_CROR: return \"CROR\";\n\tcase PPCASM_OP_CRNOR: return \"CRNOR\";\n\tcase PPCASM_OP_CRORC: return \"CRORC\";\n\tcase PPCASM_OP_CRXOR: return \"CRXOR\";\n\tcase PPCASM_OP_CREQV: return \"CREQV\";\n\tcase PPCASM_OP_CRAND: return \"CRAND\";\n\tcase PPCASM_OP_CRNAND: return \"CRNAND\";\n\tcase PPCASM_OP_CRANDC: return \"CRANDC\";\n\n\tcase PPCASM_OP_CRSET: return \"CRSET\";\n\tcase PPCASM_OP_CRCLR: return \"CRCLR\";\n\tcase PPCASM_OP_CRMOVE: return \"CRMOVE\";\n\tcase PPCASM_OP_CRNOT: return \"CRNOT\";\n\n\n\tdefault:\n\t\treturn \"UNDEF\";\n\t}\n\treturn \"\";\n}\n\n#define C_MASK_RC\t\t(PPC_OPC_RC)\n#define C_MASK_LK\t\t(PPC_OPC_LK)\n#define C_MASK_AA\t\t(PPC_OPC_AA)\n#define C_MASK_OE\t\t(1<<10)\n#define C_MASK_BO\t\t(0x1F<<21)\n#define C_MASK_BO_COND\t(0x1E<<21) // BO mask for true/false conditions. With hint bit excluded\n#define C_MASK_BI_CRBIT\t(0x3<<16)\n#define C_MASK_BI_CRIDX\t(0x7<<18)\n\n#define C_BIT_RC\t\t(PPC_OPC_RC)\n#define C_BIT_LK\t\t(PPC_OPC_LK)\n#define C_BIT_AA\t\t(PPC_OPC_AA)\n#define C_BIT_BO_FALSE\t(0x4<<21)\t// CR bit not set\n#define C_BIT_BO_TRUE\t(0xC<<21)\t// CR bit set\n#define C_BIT_BO_ALWAYS\t(0x14<<21)\n#define C_BIT_BO_DNZ\t(0x10<<21)\n#define C_BIT_BO_DZ\t\t(0x12<<21)\n\n#define C_BITS_BI_LT\t(0x0<<16)\t\n#define C_BITS_BI_GT\t(0x1<<16)\t\n#define C_BITS_BI_EQ\t(0x2<<16)\t\n#define C_BITS_BI_SO\t(0x3<<16)\t\n\nvoid ppcAssembler_setError(PPCAssemblerInOut* ctx, std::string_view errorMsg);\n\nbool ppcOp_extraCheck_extlwi(uint32 opcode)\n{\n\tsint32 rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\n\treturn MB == 0;\n}\n\nbool ppcOp_extraCheck_extrwi(uint32 opcode)\n{\n\tsint32 rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\tif (ME != 31)\n\t\treturn false;\n\tsint8 n = 32 - MB;\n\tsint8 b = SH - n;\n\treturn b >= 0;\n}\n\nbool ppcOp_extraCheck_slwi(uint32 opcode)\n{\n\tsint32 rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\treturn MB == 0 && SH == (31 - ME);\n}\n\nbool ppcOp_extraCheck_srwi(uint32 opcode)\n{\n\tsint32 rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\treturn ME == 31 && (32 - SH) == MB;\n}\n\nbool ppcOp_extraCheck_clrlwi(uint32 opcode)\n{\n\tsint32 rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\treturn SH == 0 && ME == 31;\n}\n\nbool ppcOp_extraCheck_clrrwi(uint32 opcode)\n{\n\tsint32 rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\treturn SH == 0 && MB == 0;\n}\n\nbool ppcOp_extraCheck_rotlw(uint32 opcode)\n{\n\tsint32 rS, rA, SH, MB, ME;\n\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\treturn MB == 0 && ME == 31;\n}\n\n#define FLG_DEFAULT\t0\n#define FLG_SKIP_OP0 operand0Bit\n#define FLG_SKIP_OP1 operand1Bit\n#define FLG_SKIP_OP2 operand2Bit\n#define FLG_SKIP_OP3 operand3Bit\n#define FLG_SKIP_OP4 operand4Bit\n\n#define FLG_SWAP_OP0_OP1\t(1<<6)\t// todo - maybe this should be implemented as a fully configurable matrix of indices instead of predefined constants?\n#define FLG_SWAP_OP1_OP2\t(1<<7)\n#define FLG_SWAP_OP2_OP3\t(1<<8)\n\n#define FLG_UNSIGNED_IMM\t(1<<10) // always consider immediate unsigned but still allow signed values when assembling\n\nclass EncodedOperand_None\n{\npublic:\n\tEncodedOperand_None() {}\n\n\tbool AssembleOperand(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode, size_t index)\n\t{\n\t\tif (index < assemblerCtx->listOperandStr.size() && !assemblerCtx->listOperandStr[index].str.empty())\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, \"Too many operands\");\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid DisassembleOperand(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode, size_t index)\n\t{\n\n\t}\n};\n\nstatic int _parseRegIndex(std::string_view sv, const char* prefix)\n{\n\twhile (*prefix)\n\t{\n\t\tif (sv.empty())\n\t\t\treturn -1;\n\t\tchar c = sv[0];\n\t\tif (c >= 'A' && c <= 'Z')\n\t\t\tc -= ('A' - 'a');\n\t\tif (c != *prefix)\n\t\t\treturn -1;\n\t\tsv.remove_prefix(1);\n\t\tprefix++;\n\t}\n\tint r = 0;\n\tconst std::from_chars_result result = std::from_chars(sv.data(), sv.data() + sv.size(), r);\n\tif (result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range)\n\t\treturn -1;\n\tif (result.ptr != sv.data() + sv.size())\n\t\treturn -1;\n\treturn r;\n}\n\ntemplate<bool TAllowEAZero = false> // if true, \"r0\" can be substituted with \"0\"\nclass EncodedOperand_GPR\n{\npublic:\n\tEncodedOperand_GPR(uint8 bitPos) : m_bitPos(bitPos) {}\n\n\tbool AssembleOperand(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode, size_t index)\n\t{\n\t\tif (index >= assemblerCtx->listOperandStr.size())\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, \"Missing operand\");\n\t\t\treturn false;\n\t\t}\n\t\tauto operandStr = assemblerCtx->listOperandStr[index].str;\n\t\tif constexpr (TAllowEAZero)\n\t\t{\n\t\t\tif (operandStr.size() == 1 && operandStr[0] == '0')\n\t\t\t{\n\t\t\t\topcode &= ~((uint32)0x1F << m_bitPos);\n\t\t\t\topcode |= ((uint32)0 << m_bitPos);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tsint32 regIndex = _parseRegIndex(operandStr, \"r\");\n\t\tif (regIndex < 0 || regIndex >= 32)\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, fmt::format(\"Operand \\\"{}\\\" is not a valid GPR (expected r0 - r31)\", assemblerCtx->listOperandStr[index].str));\n\t\t\treturn false;\n\t\t}\n\t\topcode &= ~((uint32)0x1F << m_bitPos);\n\t\topcode |= ((uint32)regIndex << m_bitPos);\n\t\treturn true;\n\t}\n\n\tvoid DisassembleOperand(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode, size_t index)\n\t{\n\t\tuint32 regIndex = (opcode >> m_bitPos) & 0x1F;\n\t\tdisInstr->operandMask |= (1 << index);\n\t\tdisInstr->operand[index].type = PPCASM_OPERAND_TYPE_GPR;\n\t\tdisInstr->operand[index].registerIndex = regIndex;\n\t}\nprivate:\n\tuint8 m_bitPos;\n};\n\nclass EncodedOperand_FPR\n{\npublic:\n\tEncodedOperand_FPR(uint8 bitPos) : m_bitPos(bitPos) {}\n\n\tbool AssembleOperand(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode, size_t index)\n\t{\n\t\tif (index >= assemblerCtx->listOperandStr.size())\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, \"Missing operand\");\n\t\t\treturn false;\n\t\t}\n\t\tsint32 regIndex = _parseRegIndex(assemblerCtx->listOperandStr[index].str, \"f\");\n\t\tif (regIndex < 0 || regIndex >= 32)\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, fmt::format(\"Operand \\\"{}\\\" is not a valid FPR (expected f0 - f31)\", assemblerCtx->listOperandStr[index].str));\n\t\t\treturn false;\n\t\t}\n\t\topcode &= ~((uint32)0x1F << m_bitPos);\n\t\topcode |= ((uint32)regIndex << m_bitPos);\n\t\treturn true;\n\t}\n\n\tvoid DisassembleOperand(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode, size_t index)\n\t{\n\t\tuint32 regIndex = (opcode >> m_bitPos) & 0x1F;\n\t\tdisInstr->operandMask |= (1<<index);\n\t\tdisInstr->operand[index].type = PPCASM_OPERAND_TYPE_FPR;\n\t\tdisInstr->operand[index].registerIndex = regIndex;\n\t}\nprivate:\n\tuint8 m_bitPos;\n};\n\nclass EncodedOperand_SPR\n{\npublic:\n\tEncodedOperand_SPR() {}\n\n\tbool AssembleOperand(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode, size_t index)\n\t{\n\t\tif (index >= assemblerCtx->listOperandStr.size())\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, \"Missing operand\");\n\t\t\treturn false;\n\t\t}\n\t\tsint32 regIndex = _parseRegIndex(assemblerCtx->listOperandStr[index].str, \"spr\");\n\t\tif (regIndex < 0 || regIndex >= 1024)\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, fmt::format(\"Operand \\\"{}\\\" is not a valid GPR (expected spr0 - spr1023)\", assemblerCtx->listOperandStr[index].str));\n\t\t\treturn false;\n\t\t}\n\t\tsint32 sprLow = (regIndex) & 0x1F;\n\t\tsint32 sprHigh = (regIndex>>5) & 0x1F;\n\t\topcode &= ~((uint32)0x1F << 16);\n\t\topcode |= ((uint32)sprLow << 16);\n\t\topcode &= ~((uint32)0x1F << 11);\n\t\topcode |= ((uint32)sprHigh << 11);\n\t\treturn true;\n\t}\n\n\tvoid DisassembleOperand(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode, size_t index)\n\t{\n\t\tuint32 sprLow = (opcode >> 16) & 0x1F;\n\t\tuint32 sprHigh = (opcode >> 11) & 0x1F;\n\t\tdisInstr->operandMask |= (1 << index);\n\t\tdisInstr->operand[index].type = PPCASM_OPERAND_TYPE_SPR;\n\t\tdisInstr->operand[index].registerIndex = sprLow | (sprHigh << 5);\n\t}\n};\n\nclass EncodedOperand_MemLoc\n{\npublic:\n\tEncodedOperand_MemLoc()  {}\n\n\tbool AssembleOperand(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode, size_t index)\n\t{\n\t\tif (index >= assemblerCtx->listOperandStr.size())\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, \"Missing operand\");\n\t\t\treturn false;\n\t\t}\n\t\tstd::basic_string_view<char> svOpText(assemblerCtx->listOperandStr[index].str);\n\t\t// first we parse the memory register part at the end\n\t\tauto startPtr = svOpText.data();\n\t\tauto endPtr = startPtr + svOpText.size();\n\t\t// trim whitespaces\n\t\twhile (endPtr > startPtr)\n\t\t{\n\t\t\tconst char c = endPtr[-1];\n\t\t\tif (c != ' ' && c != '\\t')\n\t\t\t\tbreak;\n\t\t\tendPtr--;\n\t\t}\n\t\tif (endPtr == startPtr || endPtr[-1] != ')')\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, fmt::format(\"\\'{}\\' does not end with valid memory register syntax. Memory operand must have the form offset(gpr). Example: 0x20(r3)\", svOpText));\n\t\t\treturn false;\n\t\t}\n\t\tendPtr--;\n\t\t// find parenthesis open\n\t\tauto memoryRegEnd = endPtr;\n\t\tconst char* memoryRegBegin = nullptr;\n\t\twhile (endPtr > startPtr)\n\t\t{\n\t\t\tconst char c = endPtr[-1];\n\t\t\tif (c == '(')\n\t\t\t{\n\t\t\t\tmemoryRegBegin = endPtr;\n\t\t\t\tendPtr--; // move end pointer beyond the parenthesis\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tendPtr--;\n\t\t}\n\t\tif (memoryRegBegin == nullptr)\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, fmt::format(\"\\'{}\\' does not end with valid memory register syntax. Memory operand must have the form offset(gpr). Example: 0x20(r3)\", svOpText));\n\t\t\treturn false;\n\t\t}\n\t\tstd::string_view svExpressionPart(startPtr, endPtr - startPtr);\n\t\tstd::string_view svRegPart(memoryRegBegin, memoryRegEnd - memoryRegBegin);\n\t\tsint32 memGpr = _parseRegIndex(svRegPart, \"r\");\n\t\t//if (_ppcAssembler_parseRegister(svRegPart, \"r\", memGpr) == false || (memGpr < 0 || memGpr >= 32))\n\t\t//{\n\t\t//\tsprintf(_assemblerErrorMessageDepr, \"\\'%.*s\\' is not a valid GPR\", (int)(memoryRegEnd - memoryRegBegin), memoryRegBegin);\n\t\t//\tppcAssembler_setError(internalCtx.ctx, _assemblerErrorMessageDepr);\n\t\t//\treturn false;\n\t\t//}\n\t\tif (memGpr < 0 || memGpr >= 32)\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, fmt::format(\"Memory operand register \\\"{}\\\" is not a valid GPR (expected r0 - r31)\", svRegPart));\n\t\t\treturn false;\n\t\t}\n\t\topcode &= ~(0x1F << 16);\n\t\topcode |= (memGpr << 16);\n\t\t// parse expression\n\t\tExpressionParser ep;\n\t\tdouble immD = 0.0f;\n\t\ttry\n\t\t{\n\t\t\tif (ep.IsConstantExpression(svExpressionPart))\n\t\t\t{\n\t\t\t\timmD = ep.Evaluate(svExpressionPart);\n\t\t\t\tsint32 imm = (sint32)immD;\n\t\t\t\tif (imm < -32768 || imm > 32767)\n\t\t\t\t{\n\t\t\t\t\tstd::string msg = fmt::format(\"\\\"{}\\\" evaluates to offset out of range (Valid range is -32768 to 32767)\", svExpressionPart);\n\t\t\t\t\tppcAssembler_setError(assemblerCtx->ctx, msg);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\topcode &= ~0xFFFF;\n\t\t\t\topcode |= ((uint32)imm & 0xFFFF);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tassemblerCtx->ctx->list_relocs.emplace_back(PPCASM_RELOC::U32_MASKED_IMM, std::string(svExpressionPart), 0, 0, 16);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tcatch (std::exception* e)\n\t\t{\n\t\t\tstd::string msg = fmt::format(\"\\\"{}\\\" could not be evaluated. Error: {}\", svExpressionPart, e->what());\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, msg);\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid DisassembleOperand(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode, size_t index)\n\t{\n\t\tuint32 imm = (opcode & 0xFFFF);\n\t\tif (imm & 0x8000)\n\t\t\timm |= 0xFFFF0000;\n\t\tuint32 regIndex = (opcode >> 16) & 0x1F;\n\t\tdisInstr->operandMask |= (1 << index);\n\t\tdisInstr->operand[index].type = PPCASM_OPERAND_TYPE_MEM;\n\t\tdisInstr->operand[index].registerIndex = regIndex;\n\t\tdisInstr->operand[index].immS32 = (sint32)imm;\n\t\tdisInstr->operand[index].immWidth = 16;\n\t\tdisInstr->operand[index].isSignedImm = true;\n\t}\n};\n\nbool _CanStoreInteger(uint32 value, uint32 numBits, bool isSigned)\n{\n\tif (isSigned)\n\t{\n\t\tsint32 storedValue = (sint32)value;\n\t\tstoredValue <<= (32 - numBits);\n\t\tstoredValue >>= (32 - numBits);\n\t\treturn (uint32)storedValue == value;\n\t}\n\t// unsigned\n\tuint32 storedValue = value;\n\tstoredValue <<= (32 - numBits);\n\tstoredValue >>= (32 - numBits);\n\treturn storedValue == value;\n}\n\nclass EncodedOperand_IMM\n{\npublic:\n\tEncodedOperand_IMM(uint8 bitPos, uint8 bits, bool isSigned, bool negate = false, bool extendedRange = false) : m_bitPos(bitPos), m_bits(bits), m_isSigned(isSigned), m_negate(negate), m_extendedRange(extendedRange) {}\n\n\tbool AssembleOperand(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode, size_t index)\n\t{\n\t\tif (index >= assemblerCtx->listOperandStr.size())\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, \"Missing operand\");\n\t\t\treturn false;\n\t\t}\n\t\t// parse expression\n\t\tstd::string expressionString(assemblerCtx->listOperandStr[index].str);\n\t\tif (m_negate)\n\t\t{\n\t\t\texpressionString.insert(0, \"0-(\");\n\t\t\texpressionString.append(\")\");\n\t\t}\n\t\tExpressionParser ep;\n\t\tdouble immD = 0.0f;\n\t\ttry\n\t\t{\n\t\t\tif (ep.IsConstantExpression(expressionString))\n\t\t\t{\n\t\t\t\timmD = ep.Evaluate(expressionString);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tassemblerCtx->ctx->list_relocs.emplace_back(PPCASM_RELOC::U32_MASKED_IMM, expressionString, 0, m_bitPos, m_bits);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tcatch (std::exception* e)\n\t\t{\n\t\t\t// check if expression is invalid or if it contains unknown constants\n\t\t\tstd::string msg = fmt::format(\"\\\"{}\\\" could not be evaluated. Error: {}\", expressionString.c_str(), e->what());\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, msg);\n\t\t\treturn false;\n\t\t}\n\t\tuint32 imm = (uint32)(sint32)immD;\n\t\tbool canStore = _CanStoreInteger(imm, m_bits, m_isSigned);\n\t\tif(!canStore && m_extendedRange) // always allow unsigned\n\t\t\tcanStore = _CanStoreInteger(imm, m_bits, false);\n\t\tif (!canStore)\n\t\t{\n\t\t\tstd::string msg = fmt::format(\"Value of operand \\\"{}\\\" is out of range\", assemblerCtx->listOperandStr[index].str);\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, msg);\n\t\t\treturn false;\n\t\t}\n\t\tuint32 mask = (1<<m_bits)-1;\n\t\timm &= mask;\n\t\topcode &= ~(mask << m_bitPos);\n\t\topcode |= (imm << m_bitPos);\n\t\treturn true;\n\t}\n\n\tvoid DisassembleOperand(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode, size_t index)\n\t{\n\t\tuint32 mask = (1 << m_bits) - 1;\n\t\tuint32 immValue = (opcode >> m_bitPos) & mask;\n\t\tif (m_isSigned)\n\t\t{\n\t\t\tsint32 tmpValue = (sint32)immValue;\n\t\t\ttmpValue <<= (32 - m_bits);\n\t\t\ttmpValue >>= (32 - m_bits);\n\t\t\timmValue = (uint32)tmpValue;\n\t\t}\n\t\tdisInstr->operandMask |= (1 << index);\n\t\tdisInstr->operand[index].type = PPCASM_OPERAND_TYPE_IMM;\n\t\tdisInstr->operand[index].immS32 = immValue;\n\t\tdisInstr->operand[index].immWidth = m_bits;\n\t\tdisInstr->operand[index].isSignedImm = m_isSigned;\n\t}\nprivate:\n\tuint8 m_bitPos;\n\tuint8 m_bits;\n\tbool m_isSigned;\n\tbool m_negate;\n\tbool m_extendedRange;\n};\n\nclass EncodedOperand_U5Reverse\n{\npublic:\n\tEncodedOperand_U5Reverse(uint8 bitPos, uint8 base) : m_bitPos(bitPos), m_base(base) {}\n\n\tbool AssembleOperand(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode, size_t index)\n\t{\n\t\tif (index >= assemblerCtx->listOperandStr.size())\n\t\t{\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, \"Missing operand\");\n\t\t\treturn false;\n\t\t}\n\t\t// parse expression\n\t\tstd::string expressionString(assemblerCtx->listOperandStr[index].str);\n\t\texpressionString.insert(0, fmt::format(\"{}-(\", m_base));\n\t\texpressionString.append(\")\");\n\t\tExpressionParser ep;\n\t\tdouble immD = 0.0f;\n\t\ttry\n\t\t{\n\t\t\tif (ep.IsConstantExpression(expressionString))\n\t\t\t{\n\t\t\t\timmD = ep.Evaluate(expressionString);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tassemblerCtx->ctx->list_relocs.emplace_back(PPCASM_RELOC::U32_MASKED_IMM, expressionString, 0, m_bitPos, 5);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tcatch (std::exception* e)\n\t\t{\n\t\t\t// check if expression is invalid or if it contains unknown constants\n\t\t\tstd::string msg = fmt::format(\"\\\"{}\\\" could not be evaluated. Error: {}\", expressionString.c_str(), e->what());\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, msg);\n\t\t\treturn false;\n\t\t}\n\t\tuint32 imm = (uint32)(sint32)immD;\n\t\tbool canStore = _CanStoreInteger(imm, 5, false);\n\t\tif (!canStore)\n\t\t{\n\t\t\tstd::string msg = fmt::format(\"Value of operand \\\"{}\\\" is out of range\", assemblerCtx->listOperandStr[index].str);\n\t\t\tppcAssembler_setError(assemblerCtx->ctx, msg);\n\t\t\treturn false;\n\t\t}\n\t\tuint32 mask = (1 << 5) - 1;\n\t\timm &= mask;\n\t\topcode &= ~(mask << m_bitPos);\n\t\topcode |= (imm << m_bitPos);\n\t\treturn true;\n\t}\n\n\tvoid DisassembleOperand(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode, size_t index)\n\t{\n\t\tuint32 mask = (1 << 5) - 1;\n\t\tuint32 immValue = (opcode >> m_bitPos) & mask;\n\t\timmValue = m_base - immValue;\n\t\tdisInstr->operandMask |= (1 << index);\n\t\tdisInstr->operand[index].type = PPCASM_OPERAND_TYPE_IMM;\n\t\tdisInstr->operand[index].immS32 = immValue;\n\t\tdisInstr->operand[index].immWidth = 5;\n\t\tdisInstr->operand[index].isSignedImm = false;\n\t}\nprivate:\n\tuint8 m_bitPos;\n\tuint8 m_base;\n};\n\nclass EncodedConstraint_None\n{\npublic:\n\tEncodedConstraint_None() {}\n\n\tvoid AssembleConstraint(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode)\n\t{\n\t}\n\n\tbool DisassembleCheckConstraint(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode)\n\t{\n\t\treturn true;\n\t}\n};\n\nclass EncodedConstraint_MirrorU5\n{\npublic:\n\tEncodedConstraint_MirrorU5(uint8 srcBitPos, uint8 dstBitPos) : m_srcBitPos(srcBitPos), m_dstBitPos(dstBitPos) {}\n\n\tvoid AssembleConstraint(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode)\n\t{\n\t\tuint32 regIndex = (opcode >> m_srcBitPos) & 0x1F;\n\t\topcode &= ~((uint32)0x1F << m_dstBitPos);\n\t\topcode |= ((uint32)regIndex << m_dstBitPos);\n\t}\n\n\tbool DisassembleCheckConstraint(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode)\n\t{\n\t\tuint32 regSrc = (opcode >> m_srcBitPos) & 0x1F;\n\t\tuint32 regDst = (opcode >> m_dstBitPos) & 0x1F;\n\t\treturn regSrc == regDst;\n\t}\n\nprivate:\n\tconst uint8 m_srcBitPos, m_dstBitPos;\n};\n\n// same as _MirrorU5, but the destination must match invBase - src\nclass EncodedConstraint_MirrorReverseU5\n{\npublic:\n\tEncodedConstraint_MirrorReverseU5(uint8 srcBitPos, uint8 dstBitPos, uint8 invBase) : m_srcBitPos(srcBitPos), m_dstBitPos(dstBitPos), m_invBase(invBase) {}\n\n\tvoid AssembleConstraint(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode)\n\t{\n\t\tuint32 regIndex = (opcode >> m_srcBitPos) & 0x1F;\n\t\tregIndex = m_invBase - regIndex;\n\t\topcode &= ~((uint32)0x1F << m_dstBitPos);\n\t\topcode |= ((uint32)regIndex << m_dstBitPos);\n\t}\n\n\tbool DisassembleCheckConstraint(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode)\n\t{\n\t\tuint32 regSrc = (opcode >> m_srcBitPos) & 0x1F;\n\t\tuint32 regDst = (opcode >> m_dstBitPos) & 0x1F;\n\t\tregSrc = m_invBase - regSrc;\n\t\tif (regSrc >= 32)\n\t\t\treturn false;\n\t\treturn regSrc == regDst;\n\t}\n\nprivate:\n\tconst uint8 m_srcBitPos, m_dstBitPos, m_invBase;\n};\n\nclass EncodedConstraint_FixedU5\n{\npublic:\n\tEncodedConstraint_FixedU5(uint8 bitPos, uint8 expectedReg) : m_bitPos(bitPos), m_expectedReg(expectedReg) {}\n\n\tvoid AssembleConstraint(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode)\n\t{\n\t\tuint32 regIndex = m_expectedReg;\n\t\topcode &= ~((uint32)0x1F << m_bitPos);\n\t\topcode |= ((uint32)regIndex << m_bitPos);\n\t}\n\n\tbool DisassembleCheckConstraint(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode)\n\t{\n\t\tuint32 reg = (opcode >> m_bitPos) & 0x1F;\n\t\treturn (uint8)reg == m_expectedReg;\n\t}\n\nprivate:\n\tconst uint8 m_bitPos;\n\tconst uint8 m_expectedReg;\n};\n\nusing EncodedConstraint_FixedRegister = EncodedConstraint_FixedU5;\nusing EncodedConstraint_MirrorRegister = EncodedConstraint_MirrorU5;\n\n// checks bit value, but does not overwrite it on assemble\nclass EncodedConstraint_CheckSignBit\n{\npublic:\n\tEncodedConstraint_CheckSignBit(uint8 bitPos, uint8 expectedValue) : m_bitPos(bitPos), m_expectedValue(expectedValue) {}\n\n\tvoid AssembleConstraint(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode)\n\t{\n\t\t// dont overwrite the existing sign bit\n\t}\n\n\tbool DisassembleCheckConstraint(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode)\n\t{\n\t\treturn ((opcode >> m_bitPos) & 1) == m_expectedValue;\n\t}\n\nprivate:\n\tconst uint8 m_bitPos;\n\tconst uint8 m_expectedValue;\n};\n\n//class EncodedConstraint_ExpectBit\n//{\n//public:\n//\tEncodedConstraint_ExpectBit(uint8 bitPos, bool val) : m_bitPos(bitPos), m_expectedValue(val ? 1 : 0) {}\n//\n//\tvoid AssembleConstraint(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode)\n//\t{\n//\t\tif (m_expectedValue)\n//\t\t\topcode |= (1 << m_bitPos);\n//\t\telse\n//\t\t\topcode &= ~(1 << m_bitPos);\n//\t}\n//\n//\tbool DisassembleCheckConstraint(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode)\n//\t{\n//\t\treturn ((opcode >> m_bitPos) & 1) == m_expectedValue;\n//\t}\n//\n//private:\n//\tconst uint8 m_bitPos;\n//\tconst uint8 m_expectedValue;\n//};\n\nclass EncodedConstraint_FixedSPR\n{\npublic:\n\tEncodedConstraint_FixedSPR(uint16 sprIndex) : m_sprIndex(sprIndex) {}\n\n\tvoid AssembleConstraint(PPCAssemblerContext* assemblerCtx, PPCInstructionDef* iDef, uint32& opcode)\n\t{\n\t\tsint32 sprLow = (m_sprIndex) & 0x1F;\n\t\tsint32 sprHigh = (m_sprIndex >> 5) & 0x1F;\n\t\topcode &= ~((uint32)0x1F << 16);\n\t\topcode |= ((uint32)sprLow << 16);\n\t\topcode &= ~((uint32)0x1F << 11);\n\t\topcode |= ((uint32)sprHigh << 11);\n\t}\n\n\tbool DisassembleCheckConstraint(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, const uint32 opcode)\n\t{\n\t\tuint32 sprLow = (opcode >> 16) & 0x1F;\n\t\tuint32 sprHigh = (opcode >> 11) & 0x1F;\n\t\tuint32 sprIndex = sprLow | (sprHigh << 5);\n\t\treturn (uint16)sprIndex == m_sprIndex;\n\t}\n\nprivate:\n\tconst uint16 m_sprIndex;\n};\n\nstruct PPCInstructionDef\n{\n\tuint16 ppcAsmOp; // instruction type identifier\n\tuint8 priority;\n\tuint16 opc0;\n\tuint16 opc1;\n\tuint16 opc2;\n\tuint8 instructionForm; // encoding\n\tuint16 flags;\n\tuint32 maskBits;\n\tuint32 compareBits;\n\tbool(*extraCheck)(uint32 opcode); // used for unique criteria (e.g. SRWI checks SH/mask) -> Replaced by constraints\n\n\tstd::array<std::variant<EncodedOperand_None, EncodedOperand_GPR<false>, EncodedOperand_GPR<true>, EncodedOperand_FPR, EncodedOperand_SPR, EncodedOperand_IMM, EncodedOperand_U5Reverse, EncodedOperand_MemLoc>, 4> encodedOperands{}; // note: The default constructor of std::variant will default-construct the first type (which we want to be EncodedOperand_None)\n\tstd::array<std::variant<EncodedConstraint_None, EncodedConstraint_MirrorRegister, EncodedConstraint_MirrorReverseU5, EncodedConstraint_FixedRegister, EncodedConstraint_FixedSPR, EncodedConstraint_CheckSignBit>, 3> constraints{};\n};\n\nPPCInstructionDef ppcInstructionTable[] =\n{\n\t{PPCASM_OP_PS_MERGE00, 0, 4, 16, 16, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11)}},\n\t{PPCASM_OP_PS_MERGE01, 0, 4, 16, 17, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11)}},\n\t{PPCASM_OP_PS_MERGE10, 0, 4, 16, 18, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11)}},\n\t{PPCASM_OP_PS_MERGE11, 0, 4, 16, 19, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11)}},\n\n\t{PPCASM_OP_PS_DIV, 0, 4, 18, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11)}},\n\t{PPCASM_OP_PS_SUB, 0, 4, 20, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11)}},\n\t{PPCASM_OP_PS_ADD, 0, 4, 21, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11)}},\n\t{PPCASM_OP_PS_MUL, 0, 4, 25, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6)}},\n\n\t{PPCASM_OP_PS_MSUB, 0, 4, 28, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11)}},\n\t{PPCASM_OP_PS_MADD, 0, 4, 29, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11)}},\n\t{PPCASM_OP_PS_NMSUB, 0, 4, 30, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11)}},\n\t{PPCASM_OP_PS_NMADD, 0, 4, 31, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11)}},\n\n\t{PPCASM_OP_MULLI, 0, 7, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_IMM(0, 16, true)}},\n\n\t{PPCASM_OP_SUBFIC, 0, 8, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_IMM(0, 16, true)} },\n\n\t{PPCASM_OP_CMPLWI, 0, 10, OPC_NONE, OPC_NONE, OP_FORM_CMP_SIMM, FLG_DEFAULT, 0, 0, nullptr},\n\t{PPCASM_OP_CMPWI, 0, 11, OPC_NONE, OPC_NONE, OP_FORM_CMP_SIMM, FLG_DEFAULT, 0, 0, nullptr},\n\t{PPCASM_OP_ADDIC, 0, 12, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_IMM(0, 16, true)}},\n\t{PPCASM_OP_ADDIC_, 0, 13, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_IMM(0, 16, true)}},\n\t{PPCASM_OP_ADDI, 0, 14, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_IMM(0, 16, true)}},\n\t{PPCASM_OP_SUBI, 1, 14, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_IMM(0, 16, true, true)}, {EncodedConstraint_CheckSignBit(15, 1)}}, // special form of ADDI for negative immediate\n\t{PPCASM_OP_LI, 1, 14, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_IMM(0, 16, true, false, true)}, {EncodedConstraint_FixedRegister(16, 0)}},\n\t{PPCASM_OP_ADDIS, 0, 15, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_IMM(0, 16, true, false, true)}},\n\t{PPCASM_OP_LIS, 1, 15, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_IMM(0, 16, true, false, true)}, {EncodedConstraint_FixedRegister(16, 0)}},\n\n\t{PPCASM_OP_BC, 0, 16, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S16, FLG_DEFAULT, 0, 0, nullptr},\n\n\t{PPCASM_OP_BNE, 1, 16, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S16, FLG_DEFAULT, C_MASK_BO_COND | C_MASK_BI_CRBIT, C_BIT_BO_FALSE | C_BITS_BI_EQ, nullptr},\n\t{PPCASM_OP_BEQ, 1, 16, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S16, FLG_DEFAULT, C_MASK_BO_COND | C_MASK_BI_CRBIT, C_BIT_BO_TRUE | C_BITS_BI_EQ, nullptr},\n\t{PPCASM_OP_BGE, 1, 16, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S16, FLG_DEFAULT, C_MASK_BO_COND | C_MASK_BI_CRBIT, C_BIT_BO_FALSE | C_BITS_BI_LT, nullptr},\n\t{PPCASM_OP_BGT, 1, 16, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S16, FLG_DEFAULT, C_MASK_BO_COND | C_MASK_BI_CRBIT, C_BIT_BO_TRUE | C_BITS_BI_GT, nullptr},\n\t{PPCASM_OP_BLT, 1, 16, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S16, FLG_DEFAULT, C_MASK_BO_COND | C_MASK_BI_CRBIT, C_BIT_BO_TRUE | C_BITS_BI_LT, nullptr},\n\t{PPCASM_OP_BLE, 1, 16, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S16, FLG_DEFAULT, C_MASK_BO_COND | C_MASK_BI_CRBIT, C_BIT_BO_FALSE | C_BITS_BI_GT, nullptr},\n\n\t{PPCASM_OP_BDZ, 1, 16, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S16, FLG_DEFAULT, C_MASK_BO, C_BIT_BO_DZ, nullptr},\n\t{PPCASM_OP_BDNZ, 1, 16, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S16, FLG_DEFAULT, C_MASK_BO, C_BIT_BO_DNZ, nullptr},\n\n\t{PPCASM_OP_B, 0, 18, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S24, FLG_DEFAULT, C_MASK_LK | C_MASK_AA, 0, nullptr},\n\t{PPCASM_OP_BL, 0, 18, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S24, FLG_DEFAULT, C_MASK_LK | C_MASK_AA, C_BIT_LK, nullptr},\n\t{PPCASM_OP_BA, 0, 18, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S24, FLG_DEFAULT, C_MASK_LK | C_MASK_AA, C_BIT_AA, nullptr},\n\t{PPCASM_OP_BLA, 0, 18, OPC_NONE, OPC_NONE, OP_FORM_BRANCH_S24, FLG_DEFAULT, C_MASK_LK | C_MASK_AA, C_BIT_LK|C_BIT_AA, nullptr},\n\n\t{PPCASM_OP_BLR, 0, 19, 16, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, C_MASK_BO | C_MASK_LK, C_BIT_BO_ALWAYS, nullptr},\n\n\t{PPCASM_OP_BLTLR, 0, 19, 16, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, C_MASK_BO | C_MASK_BI_CRBIT | C_MASK_LK, C_BIT_BO_TRUE | C_BITS_BI_LT, nullptr}, // less\n\t{PPCASM_OP_BGTLR, 0, 19, 16, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, C_MASK_BO | C_MASK_BI_CRBIT | C_MASK_LK, C_BIT_BO_TRUE | C_BITS_BI_GT, nullptr}, // greater\n\t{PPCASM_OP_BEQLR, 0, 19, 16, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, C_MASK_BO | C_MASK_BI_CRBIT | C_MASK_LK, C_BIT_BO_TRUE | C_BITS_BI_EQ, nullptr}, // equal\n\t{PPCASM_OP_BLELR, 0, 19, 16, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, C_MASK_BO | C_MASK_BI_CRBIT | C_MASK_LK, C_BIT_BO_FALSE | C_BITS_BI_GT, nullptr}, // less or equal (not greater)\n\t{PPCASM_OP_BGELR, 0, 19, 16, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, C_MASK_BO | C_MASK_BI_CRBIT | C_MASK_LK, C_BIT_BO_FALSE | C_BITS_BI_LT, nullptr}, // greater or equal (not less)\n\t{PPCASM_OP_BNELR, 0, 19, 16, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, C_MASK_BO | C_MASK_BI_CRBIT | C_MASK_LK, C_BIT_BO_FALSE | C_BITS_BI_EQ, nullptr}, // not equal\n\n\t{PPCASM_OP_ISYNC, 0, 19, 150, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, 0, 0, nullptr},\n\n\t{PPCASM_OP_CRNOR, 0, 19, 33, OPC_NONE, OP_FORM_XL_CR, FLG_DEFAULT, 0, 0, nullptr},\n\t{PPCASM_OP_CRANDC, 0, 19, 129, OPC_NONE, OP_FORM_XL_CR, FLG_DEFAULT, 0, 0, nullptr},\n\t{PPCASM_OP_CRXOR, 0, 19, 193, OPC_NONE, OP_FORM_XL_CR, FLG_DEFAULT, 0, 0, nullptr},\n\t{PPCASM_OP_CRNAND, 0, 19, 255, OPC_NONE, OP_FORM_XL_CR, FLG_DEFAULT, 0, 0, nullptr},\n\t{PPCASM_OP_CRAND, 0, 19, 257, OPC_NONE, OP_FORM_XL_CR, FLG_DEFAULT, 0, 0, nullptr},\n\t{PPCASM_OP_CREQV, 0, 19, 289, OPC_NONE, OP_FORM_XL_CR, FLG_DEFAULT, 0, 0, nullptr},\n\t{PPCASM_OP_CRORC, 0, 19, 417, OPC_NONE, OP_FORM_XL_CR, FLG_DEFAULT, 0, 0, nullptr},\n\t{PPCASM_OP_CROR, 0, 19, 449, OPC_NONE, OP_FORM_XL_CR, FLG_DEFAULT, 0, 0, nullptr},\n\n\t{PPCASM_OP_BCTR, 0, 19, 528, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, C_MASK_BO | C_MASK_LK, C_BIT_BO_ALWAYS, nullptr},\n\t{PPCASM_OP_BCTRL, 0, 19, 528, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, C_MASK_BO | C_MASK_LK, C_BIT_BO_ALWAYS | C_BIT_LK, nullptr},\n\n\t{PPCASM_OP_RLWIMI, 0, 20, OPC_NONE, OPC_NONE, OP_FORM_RLWINM, FLG_DEFAULT, C_MASK_RC, 0, nullptr},\n\t{PPCASM_OP_RLWIMI_, 0, 20, OPC_NONE, OPC_NONE, OP_FORM_RLWINM, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr},\n\t{PPCASM_OP_RLWINM, 0, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM, FLG_DEFAULT, C_MASK_RC, 0, nullptr},\n\t{PPCASM_OP_RLWINM_, 0, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr},\n\n\t{PPCASM_OP_ROTLWI, 2, 21, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_IMM(11, 5, false)}, {EncodedConstraint_FixedU5(6, 0), EncodedConstraint_FixedU5(1, 31)}},\n\t{PPCASM_OP_ROTLWI_, 2, 21, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_IMM(11, 5, false)}, {EncodedConstraint_FixedU5(6, 0), EncodedConstraint_FixedU5(1, 31)}},\n\n\t// rotrwi RA, RS, n -> rlwinm RA, RS, 32-n, 0, 31\n\t// only assembler\n\t{PPCASM_OP_ROTRWI, 0, 21, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_U5Reverse(11, 32)}, {EncodedConstraint_FixedU5(6, 0), EncodedConstraint_FixedU5(1, 31)}},\n\t{PPCASM_OP_ROTRWI_, 0, 21, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_U5Reverse(11, 32)}, {EncodedConstraint_FixedU5(6, 0), EncodedConstraint_FixedU5(1, 31)}},\n\n\t{PPCASM_OP_EXTLWI, 1, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, 0, ppcOp_extraCheck_extlwi},\n\t{PPCASM_OP_EXTLWI_, 1, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, ppcOp_extraCheck_extlwi},\n\t{PPCASM_OP_EXTRWI, 1, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, 0, ppcOp_extraCheck_extrwi},\n\t{PPCASM_OP_EXTRWI_, 1, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, ppcOp_extraCheck_extrwi},\n\n\t{PPCASM_OP_SLWI, 2, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, 0, ppcOp_extraCheck_slwi},\n\t{PPCASM_OP_SLWI_, 2, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, ppcOp_extraCheck_slwi},\n\t{PPCASM_OP_SRWI, 2, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, 0, ppcOp_extraCheck_srwi},\n\t{PPCASM_OP_SRWI_, 2, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, ppcOp_extraCheck_srwi},\n\n\t{PPCASM_OP_CLRLWI, 2, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, 0, ppcOp_extraCheck_clrlwi},\n\t{PPCASM_OP_CLRLWI_, 2, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, ppcOp_extraCheck_clrlwi},\n\t{PPCASM_OP_CLRRWI, 2, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, 0, ppcOp_extraCheck_clrrwi},\n\t{PPCASM_OP_CLRRWI_, 2, 21, OPC_NONE, OPC_NONE, OP_FORM_RLWINM_EXTENDED, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, ppcOp_extraCheck_clrrwi},\n\n\t{PPCASM_OP_RLWNM, 0, 23, OPC_NONE, OPC_NONE, OP_FORM_RLWNM, FLG_DEFAULT, C_MASK_RC, 0, nullptr},\n\t{PPCASM_OP_RLWNM_, 0, 23, OPC_NONE, OPC_NONE, OP_FORM_RLWNM, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr},\n\n\t{PPCASM_OP_ROTLW, 0, 23, OPC_NONE, OPC_NONE, OP_FORM_RLWNM_EXTENDED, FLG_DEFAULT, C_MASK_RC, 0, ppcOp_extraCheck_rotlw},\n\t{PPCASM_OP_ROTLW_, 0, 23, OPC_NONE, OPC_NONE, OP_FORM_RLWNM_EXTENDED, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, ppcOp_extraCheck_rotlw},\n\n\n\t{PPCASM_OP_ORI, 0, 24, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_IMM(0, 16, false)}},\n\t{PPCASM_OP_NOP, 1, 24, OPC_NONE, OPC_NONE, OP_FORM_NO_OPERAND, FLG_DEFAULT, 0x3FFFFFF, 0, nullptr}, // ORI r0, r0, 0 -> NOP\n\t{PPCASM_OP_ORIS, 0, 25, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_IMM(0, 16, true, false, true)}},\n\n\t{PPCASM_OP_XORI, 0, 26, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_IMM(0, 16, false)} },\n\t{PPCASM_OP_XORIS, 0, 27, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_IMM(0, 16, true, false, true)} },\n\n\t{PPCASM_OP_ANDI_, 0, 28, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_IMM(0, 16, false)} },\n\t{PPCASM_OP_ANDIS_, 0, 29, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_IMM(0, 16, true, false, true)} },\n\n\t// group 31\n\t{PPCASM_OP_CMPW, 0, 31, 0, OPC_NONE, OP_FORM_OP3_A_CMP, FLG_DEFAULT, 0, 0, nullptr},\n\n\t{PPCASM_OP_SUBFC, 1, 31, 8, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_SUBFC_, 1, 31, 8, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_MULHWU, 0, 31, 11, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_MULHWU_, 0, 31, 11, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_CMPLW, 0, 31, 32, OPC_NONE, OP_FORM_OP3_A_CMP, FLG_DEFAULT, 0, 0, nullptr},\n\n\t{PPCASM_OP_SUBF, 1, 31, 40, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_SUBF_, 1, 31, 40, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_SUB, 0, 31, 40, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(11), EncodedOperand_GPR(16)} },\n\t{PPCASM_OP_SUB_, 0, 31, 40, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(11), EncodedOperand_GPR(16)} },\n\n\t{PPCASM_OP_MULHW, 0, 31, 75, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_MULHW_, 0, 31, 75, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_NEG, 0, 31, 104, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC | C_MASK_OE, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16)}},\n\t{PPCASM_OP_NEG_, 0, 31, 104, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC | C_MASK_OE, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16)} },\n\n\t{PPCASM_OP_NOR, 0, 31, 124, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_NOR_, 0, 31, 124, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\n\t// alias for NOR where rA == rB\n\t{PPCASM_OP_NOT, 1, 31, 124, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(11)}, {EncodedConstraint_MirrorRegister(11, 21)}},\n\t{PPCASM_OP_NOT_, 1, 31, 124, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(11)}, {EncodedConstraint_MirrorRegister(11, 21)} },\n\n\t{PPCASM_OP_SUBFE, 1, 31, 136, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_SUBFE_, 1, 31, 136, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_MULLW, 0, 31, 235, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_MULLW_, 0, 31, 235, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_MFSPR, 0, 31, 339, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_SPR()} },\n\t{PPCASM_OP_MTSPR, 0, 31, 467, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_SPR(), EncodedOperand_GPR(21)} },\n\n\t{PPCASM_OP_MFLR, 0, 31, 339, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21)}, {EncodedConstraint_FixedSPR(8)}},\n\t{PPCASM_OP_MTLR, 0, 31, 467, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21)}, {EncodedConstraint_FixedSPR(8)} },\n\t{PPCASM_OP_MFCTR, 0, 31, 339, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21)}, {EncodedConstraint_FixedSPR(9)} },\n\t{PPCASM_OP_MTCTR, 0, 31, 467, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21)}, {EncodedConstraint_FixedSPR(9)} },\n\n\t{PPCASM_OP_ADD, 0, 31, 266, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_ADD_, 0, 31, 266, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_SLW, 0, 31, 24, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_SLW_, 0, 31, 24, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_SRW, 0, 31, 536, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_SRW_, 0, 31, 536, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_SRAW, 0, 31, 792, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_SRAW_, 0, 31, 792, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_AND, 0, 31, 28, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_AND_, 0, 31, 28, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_ANDC, 0, 31, 60, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_ANDC_, 0, 31, 60, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_XOR, 0, 31, 316, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_ORC, 0, 31, 412, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} }, // has RC?\n\t{PPCASM_OP_OR, 0, 31, 444, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_OR_, 0, 31, 444, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_MR, 1, 31, 444, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(11)}, {EncodedConstraint_MirrorRegister(11, 21)} },\n\t{PPCASM_OP_MR_, 1, 31, 444, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(11)}, {EncodedConstraint_MirrorRegister(11, 21)} },\n\n\t{PPCASM_OP_DIVWU, 0, 31, 459, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_DIVWU_, 0, 31, 459, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_DIVW, 0, 31, 491, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_DIVW_, 0, 31, 491, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_SRAWI, 0, 31, 824, OPC_NONE, OP_FORM_OP3_A_IMM, FLG_DEFAULT, C_MASK_RC, 0, nullptr},\n\t{PPCASM_OP_SRAWI_, 0, 31, 824, OPC_NONE, OP_FORM_OP3_A_IMM, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr},\n\n\t{PPCASM_OP_CNTLZW, 0, 31, 26, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21)} },\n\t{PPCASM_OP_EXTSB, 0, 31, 954, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21)} },\n\t{PPCASM_OP_EXTSH, 0, 31, 922, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, 0, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21)} },\n\n\t{PPCASM_OP_CNTLZW_, 0, 31, 26, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21)} },\n\t{PPCASM_OP_EXTSB_, 0, 31, 954, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21)} },\n\t{PPCASM_OP_EXTSH_, 0, 31, 922, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(16), EncodedOperand_GPR(21)} },\n\n\t{PPCASM_OP_LWZX, 0, 31, 23, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_LWZUX, 0, 31, 55, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_LBZX, 0, 31, 87, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_LBZUX, 0, 31, 119, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_LHZX, 0, 31, 279, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_LHZUX, 0, 31, 311, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_LHAX, 0, 31, 343, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_LHAUX, 0, 31, 375, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STWX, 0, 31, 151, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STWUX, 0, 31, 183, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STHX, 0, 31, 407, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STHUX, 0, 31, 439, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STBX, 0, 31, 215, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STBUX, 0, 31, 247, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STWBRX, 0, 31, 662, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STHBRX, 0, 31, 918, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_LFSX, 0, 31, 535, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_LFSUX, 0, 31, 567, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STFSX, 0, 31, 663, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STFSUX, 0, 31, 695, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_STSWI, 0, 31, 725, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR(16), EncodedOperand_IMM(11, 5, false)} },\n\n\t{PPCASM_OP_LWARX, 0, 31, 20, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STWCX_, 0, 31, 150, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, C_MASK_RC, C_BIT_RC, nullptr, {EncodedOperand_GPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_LFDX, 0, 31, 599, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_LFDUX, 0, 31, 631, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STFDX, 0, 31, 727, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\t{PPCASM_OP_STFDUX, 0, 31, 759, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\n\t{PPCASM_OP_STFIWX, 0, 31, 983, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_GPR<true>(16), EncodedOperand_GPR(11)} },\n\n\t// load/store\n\t{PPCASM_OP_LWZ, 0, 32, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LWZU, 0, 33, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LBZ, 0, 34, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LBZU, 0, 35, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STW, 0, 36, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STWU, 0, 37, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STB, 0, 38, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STBU, 0, 39, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LHZ, 0, 40, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LHZU, 0, 41, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LHA, 0, 42, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LHAU, 0, 43, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STH, 0, 44, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STHU, 0, 45, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LMW, 0, 46, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STMW, 0, 47, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_GPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LFS, 0, 48, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LFSU, 0, 49, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LFD, 0, 50, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_LFDU, 0, 51, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STFS, 0, 52, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STFSU, 0, 53, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STFD, 0, 54, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_MemLoc()} },\n\t{PPCASM_OP_STFDU, 0, 55, OPC_NONE, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_MemLoc()} },\n\n\t// FP\n\t{PPCASM_OP_FDIVS, 0, 59, 18, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FSUBS, 0, 59, 20, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FADDS, 0, 59, 21, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FMULS, 0, 59, 25, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6) } },\n\t{PPCASM_OP_FMSUBS, 0, 59, 28, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FMADDS, 0, 59, 29, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FNMSUBS, 0, 59, 30, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FNMADDS, 0, 59, 31, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11) } },\n\n\t{PPCASM_OP_FCMPU, 0, 63, 0, OPC_NONE, OP_FORM_X_FP_CMP, FLG_DEFAULT, 0, 0, nullptr },\n\t{PPCASM_OP_FCTIWZ, 0, 63, 15, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, {EncodedOperand_FPR(21), EncodedOperand_FPR(11)}},\n\t{PPCASM_OP_FDIV, 0, 63, 18, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FSUB, 0, 63, 20, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FADD, 0, 63, 21, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FMUL, 0, 63, 25, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6) } },\n\t{PPCASM_OP_FRSQRTE, 0, 63, 26, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FMSUB, 0, 63, 28, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FMADD, 0, 63, 29, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FNMSUB, 0, 63, 30, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FNMADD, 0, 63, 31, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(16), EncodedOperand_FPR(6), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FRSP, 0, 63, 12, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(11) } },\n\n\t// 63 extended opcode\n\t{PPCASM_OP_FCMPO, 0, 63, 32|OPC_EXTENDED_BIT, OPC_NONE, OP_FORM_X_FP_CMP, FLG_DEFAULT, 0, 0, nullptr },\n\t{PPCASM_OP_FNEG, 0, 63, 40|OPC_EXTENDED_BIT, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FMR, 0, 63, 72|OPC_EXTENDED_BIT, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(11) } },\n\t{PPCASM_OP_FABS, 0, 63, 264|OPC_EXTENDED_BIT, OPC_NONE, OP_FORM_DYNAMIC, FLG_DEFAULT, 0, 0, nullptr, { EncodedOperand_FPR(21), EncodedOperand_FPR(11) } },\n\n};\n\n#define opcMask_setBits(__index, __bitCount, __value) opcodeMask |= (((1<<__bitCount)-1)<<(31-__index)); opcodeBits |= ((__value)<<(31-__index));\n\nvoid ppcAssembler_buildOpcMask(PPCInstructionDef* iDef, uint32& maskOut, uint32& bitsOut)\n{\n\tuint32 opc0 = iDef->opc0;\n\tuint32 opc1 = iDef->opc1;\n\tuint32 opc2 = iDef->opc2;\n\n\tuint32 opcodeMask = 0x3F<<26;\n\tuint32 opcodeBits = opc0<<26;\n\n\t// handle groups\n\tif (opc0 == 31)\n\t{\n\t\t// group 31\n\t\topcMask_setBits(30, 10, opc1);\n\t}\n\telse if (opc0 == 19)\n\t{\n\t\t// group 19\n\t\topcMask_setBits(30, 10, opc1);\n\t}\n\telse if (opc0 == 4)\n\t{\n\t\t// group 4 (paired single)\n\t\topcMask_setBits(30, 5, opc1);\n\t\t//opc1 = PPC_getBits(opcode, 30, 5);\n\t\tif (opc1 == 16)\n\t\t{\n\t\t\t// group 4->16 (ps_merge)\n\t\t\topcMask_setBits(25, 5, opc2);\n\t\t\t//opc2 = PPC_getBits(opcode, 25, 5);\n\t\t}\n\t}\n\telse if (opc0 == 59)\n\t{\n\t\t// group 59 (FP float)\n\t\topcMask_setBits(30, 5, opc1);\n\t\t//opc1 = PPC_getBits(opcode, 30, 5);\n\t}\n\telse if (opc0 == 63)\n\t{\n\t\t// group 63 (FP double)\n\t\tif ((opc1&OPC_EXTENDED_BIT) != 0)\n\t\t{\n\t\t\topcMask_setBits(30, 10, (opc1&~OPC_EXTENDED_BIT));\n\t\t}\n\t\telse\n\t\t{\n\t\t\topcMask_setBits(30, 5, opc1);\n\t\t}\n\t}\n\tmaskOut = opcodeMask;\n\tbitsOut = opcodeBits;\n}\n\n// given an internal instruction operand index, return the text encoding index\nsint32 _getOpIndex(PPCInstructionDef* iDef, sint32 operandIndex)\n{\n\tif ((operandIndex == 0 || operandIndex == 1) && (iDef->flags & FLG_SWAP_OP0_OP1) != 0)\n\t\toperandIndex ^= 1;\n\tif ((iDef->flags & FLG_SWAP_OP1_OP2) != 0)\n\t{\n\t\tif (operandIndex == 1) operandIndex = 2;\n\t\telse if (operandIndex == 2) operandIndex = 1;\n\t}\n\tif ((iDef->flags & FLG_SWAP_OP2_OP3) != 0)\n\t{\n\t\tif (operandIndex == 2) operandIndex = 3;\n\t\telse if (operandIndex == 3) operandIndex = 2;\n\t}\n\treturn operandIndex;\n}\n\n// given an internal instruction operand index, return the operand index for the text encoding. Returns -1 when operand is not present\n// replaces _getOpIndex\n//sint32 _operandInternalToTextIndex(ppcInstructionDef_t* iDef, sint32 operandIndex)\n//{\n//\tif ((operandIndex == 0 || operandIndex == 1) && (iDef->flags & FLG_SWAP_OP0_OP1) != 0)\n//\t\toperandIndex ^= 1;\n//\tif ((operandIndex == 2 || operandIndex == 3) && (iDef->flags & FLG_SWAP_OP2_OP3) != 0)\n//\t\toperandIndex ^= 1;\n//\tsint32 outputIndex = operandIndex;\n//\tif ((iDef->flags & (1 << outputIndex)))\n//\t\treturn -1;\n//\tfor (sint32 i = 0; i < operandIndex; i++)\n//\t{\n//\t\tif ((iDef->flags & (1 << i)))\n//\t\t\toutputIndex--;\n//\t}\n//\treturn outputIndex;\n//}\n//\n//int _operandTextToInternalIndex(ppcInstructionDef_t* iDef, sint32 operandIndex)\n//{\n//\tfor (sint32 i = 0; i < 8; i++)\n//\t{\n//\t\tif (_operandInternalToTextIndex(iDef, i) == operandIndex)\n//\t\t\treturn i;\n//\t}\n//\treturn -1;\n//}\n\nvoid _disasmOpGPR(PPCDisassembledInstruction* disInstr, PPCInstructionDef* iDef, uint32 operandIndex, sint32 regIndex)\n{\n\tif ((iDef->flags & (FLG_SKIP_OP0 << operandIndex)) != 0)\n\t\treturn;\n\tdisInstr->operandMask |= (1 << operandIndex);\n\tsint32 opIdx = _getOpIndex(iDef, operandIndex);\n\tdisInstr->operand[opIdx].type = PPCASM_OPERAND_TYPE_GPR;\n\tdisInstr->operand[opIdx].registerIndex = regIndex;\n}\n\nvoid ppcAssembler_disassemble(uint32 virtualAddress, uint32 opcode, PPCDisassembledInstruction* disInstr)\n{\n\tauto makeOpCRBit = [&](size_t opIndex, uint8 regIndex)\n\t{\n\t\tdisInstr->operandMask |= (1 << opIndex);\n\t\tdisInstr->operand[opIndex].type = PPCASM_OPERAND_TYPE_CR_BIT;\n\t\tdisInstr->operand[opIndex].registerIndex = regIndex;\n\t};\n\n\tauto makeOpFPR = [&](size_t opIndex, uint8 regIndex)\n\t{\n\t\tdisInstr->operandMask |= (1 << opIndex);\n\t\tdisInstr->operand[opIndex].type = PPCASM_OPERAND_TYPE_FPR;\n\t\tdisInstr->operand[opIndex].registerIndex = regIndex;\n\t};\n\n\tmemset(disInstr, 0, sizeof(PPCDisassembledInstruction));\n\t// find match in table\n\tsint32 bestMatchIndex = -1;\n\tuint8 bestMatchPriority = 0;\n\tfor (sint32 i = 0; i < sizeof(ppcInstructionTable) / sizeof(PPCInstructionDef); i++)\n\t{\n\t\tPPCInstructionDef* iDef = ppcInstructionTable + i;\n\t\t// check opcode\n\t\tuint32 opcMask;\n\t\tuint32 opcBits;\n\t\tppcAssembler_buildOpcMask(iDef, opcMask, opcBits);\n\t\tif ((opcode&opcMask) != opcBits)\n\t\t\tcontinue;\t\t\n\t\t// check bits\n\t\tif((opcode&iDef->maskBits) != iDef->compareBits)\n\t\t\tcontinue;\n\t\t// check special condition\n\t\tif(iDef->extraCheck && iDef->extraCheck(opcode) == false )\n\t\t\tcontinue;\n\t\t// check priority\n\t\tif(iDef->priority < bestMatchPriority)\n\t\t\tcontinue;\n\t\t// check constraints\n\t\tbool allConstraintsMatch = true;\n\t\tfor (auto& it : iDef->constraints)\n\t\t{\n\t\t\tif (!std::visit([&](auto&& op) -> bool {\n\t\t\t\treturn op.DisassembleCheckConstraint(disInstr, iDef, opcode);\n\t\t\t\t}, it))\n\t\t\t{\n\t\t\t\tallConstraintsMatch = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!allConstraintsMatch)\n\t\t\tcontinue;\n\t\t// select entry\n\t\tbestMatchIndex = i;\n\t\tbestMatchPriority = iDef->priority;\n\t}\n\t// if we have found an entry, parse operand data\n\tif (bestMatchIndex >= 0)\n\t{\n\t\tPPCInstructionDef* iDef = ppcInstructionTable + bestMatchIndex;\n\t\t// setup general instruction info\n\t\tdisInstr->ppcAsmCode = iDef->ppcAsmOp;\n\t\t// parse operands\n\t\tif (iDef->instructionForm == OP_FORM_DYNAMIC)\n\t\t{\n\t\t\tdisInstr->operandMask = 0;\n\t\t\tfor (size_t i = 0; i < iDef->encodedOperands.size(); i++)\n\t\t\t{\n\t\t\t\tstd::visit([&](auto&& op) {\n\t\t\t\t\top.DisassembleOperand(disInstr, iDef, opcode, i);\n\t\t\t\t\t}, iDef->encodedOperands[i]);\n\t\t\t}\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_OP3_A_CMP)\n\t\t{\n\t\t\tsint32 rS, rA, rB;\n\t\t\tPPC_OPC_TEMPL_X(opcode, rS, rA, rB);\n\t\t\tdisInstr->operandMask = (rS!=0?operand0Bit:0);\n\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_CR;\n\t\t\tdisInstr->operand[0].registerIndex = rS >> 2;\n\t\t\tif((rS & 3) != 0)\n\t\t\t\tcemuLog_log(LogType::Force, \"[PPC-Disassembler] Unexpected CR encoding for instruction 0x{0:08x}\", opcode);\n\t\t\t_disasmOpGPR(disInstr, iDef, 1, rA);\n\t\t\t_disasmOpGPR(disInstr, iDef, 2, rB);\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_OP3_A_IMM)\n\t\t{\n\t\t\tsint32 rS, rA, SH;\n\t\t\tPPC_OPC_TEMPL_X(opcode, rS, rA, SH);\n\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit;\n\t\t\tsint32 op0Idx = _getOpIndex(iDef, 0);\n\t\t\tsint32 op1Idx = _getOpIndex(iDef, 1);\n\t\t\tsint32 op2Idx = _getOpIndex(iDef, 2);\n\t\t\t// operand 0\n\t\t\tdisInstr->operand[op0Idx].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[op0Idx].registerIndex = rA;\n\t\t\t// operand 1\n\t\t\tdisInstr->operand[op1Idx].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[op1Idx].registerIndex = rS;\n\t\t\t// operand 2\n\t\t\tdisInstr->operand[op2Idx].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\tdisInstr->operand[op2Idx].immS32 = SH;\n\t\t\tdisInstr->operand[op2Idx].immWidth = 5;\n\t\t\tdisInstr->operand[op2Idx].isSignedImm = false;\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_BRANCH_S16)\n\t\t{\n\t\t\tuint32 BO, BI, dest;\n\t\t\tPPC_OPC_TEMPL_B(opcode, BO, BI, dest);\n\t\t\tuint8 crIndex = BI >> 2;\n\t\t\tif ((opcode & PPC_OPC_AA) == 0)\n\t\t\t\tdest += virtualAddress;\n\t\t\tif (iDef->ppcAsmOp == PPCASM_OP_BC)\n\t\t\t{\n\t\t\t\t// generic conditional branch of form <BO>, CR+LT/GT/EQ/SO, <dst>\n\t\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit;\n\t\t\t\t// operand 0\n\t\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_CIMM;\n\t\t\t\tdisInstr->operand[0].registerIndex = BO;\n\t\t\t\t// operand 1\n\t\t\t\tdisInstr->operand[1].type = PPCASM_OPERAND_TYPE_CR_BIT;\n\t\t\t\tdisInstr->operand[1].registerIndex = BI;\n\t\t\t\t// operand 2\n\t\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_CIMM;\n\t\t\t\tdisInstr->operand[2].immU32 = dest;\n\t\t\t\t// hint bit\n\t\t\t\tdisInstr->branchHintBitSet = (BO & 1) != 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (crIndex != 0)\n\t\t\t\t{\n\t\t\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit;\n\t\t\t\t\t// operand 0\n\t\t\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_CR;\n\t\t\t\t\tdisInstr->operand[0].registerIndex = crIndex;\n\t\t\t\t\t// operand 1\n\t\t\t\t\tdisInstr->operand[1].type = PPCASM_OPERAND_TYPE_CIMM;\n\t\t\t\t\tdisInstr->operand[1].immU32 = dest;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tdisInstr->operandMask = operand0Bit;\n\t\t\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_CIMM;\n\t\t\t\t\tdisInstr->operand[0].immU32 = dest;\n\t\t\t\t}\n\t\t\t\t// hint bit\n\t\t\t\tdisInstr->branchHintBitSet = (BO & 1) != 0;\n\t\t\t}\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_BRANCH_S24)\n\t\t{\n\t\t\tuint32 dest;\n\t\t\tPPC_OPC_TEMPL_I(opcode, dest);\n\t\t\tif ((opcode & PPC_OPC_AA) == 0)\n\t\t\t\tdest += virtualAddress;\n\t\t\tdisInstr->operandMask = operand0Bit;\n\t\t\t// operand 0\n\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_CIMM;\n\t\t\tdisInstr->operand[0].immU32 = dest;\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_OP2_D_HSIMM)\n\t\t{\n\t\t\tsint32 rD, rA;\n\t\t\tuint32 imm;\n\t\t\tPPC_OPC_TEMPL_D_SImm(opcode, rD, rA, imm);\n\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit;\n\t\t\t// operand 0\n\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[0].registerIndex = rD;\n\t\t\t// operand 1\n\t\t\tdisInstr->operand[1].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\tdisInstr->operand[1].immS32 = imm & 0xFFFF;\n\t\t\tdisInstr->operand[1].immWidth = 16;\n\t\t\tdisInstr->operand[1].isSignedImm = true;\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_CMP_SIMM)\n\t\t{\n\t\t\tuint32 cr;\n\t\t\tsint32 rA;\n\t\t\tuint32 imm;\n\t\t\tPPC_OPC_TEMPL_D_SImm(opcode, cr, rA, imm);\n\t\t\tcr /= 4;\n\t\t\t// rS is cr\n\t\t\tdisInstr->operandMask = operand1Bit | operand2Bit;\n\t\t\tif (cr != 0)\n\t\t\t\tdisInstr->operandMask |= operand0Bit;\n\t\t\t// operand 0\n\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_CR;\n\t\t\tdisInstr->operand[0].registerIndex = cr;\n\t\t\t// operand 1\n\t\t\tdisInstr->operand[1].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[1].registerIndex = rA;\n\t\t\t// operand 2\n\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\tdisInstr->operand[2].immS32 = imm;\n\t\t\tdisInstr->operand[2].immWidth = 16;\n\t\t\tdisInstr->operand[2].isSignedImm = true;\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_NO_OPERAND)\n\t\t{\n\t\t\tdisInstr->operandMask = 0;\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_X_FP_CMP)\n\t\t{\n\t\t\tsint32 rA, crIndex, rB;\n\t\t\tPPC_OPC_TEMPL_X(opcode, crIndex, rA, rB);\n\t\t\tcemu_assert_debug((crIndex % 4) == 0);\n\t\t\tcrIndex /= 4;\n\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit;\n\t\t\t// operand 0\n\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_CR;\n\t\t\tdisInstr->operand[0].registerIndex = crIndex;\n\t\t\t// operand 1\n\t\t\tdisInstr->operand[1].type = PPCASM_OPERAND_TYPE_FPR;\n\t\t\tdisInstr->operand[1].registerIndex = rA;\n\t\t\t// operand 2\n\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_FPR;\n\t\t\tdisInstr->operand[2].registerIndex = rB;\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_RLWINM)\n\t\t{\n\t\t\tsint32 rS, rA, SH, MB, ME;\n\t\t\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit | operand3Bit | operand4Bit;\n\t\t\t// operand 0\n\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[0].registerIndex = rA;\n\t\t\t// operand 1\n\t\t\tdisInstr->operand[1].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[1].registerIndex = rS;\n\t\t\t// operand 2\n\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\tdisInstr->operand[2].immS32 = SH;\n\t\t\tdisInstr->operand[2].immWidth = 8;\n\t\t\t// operand 3\n\t\t\tdisInstr->operand[3].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\tdisInstr->operand[3].immS32 = MB;\n\t\t\tdisInstr->operand[3].immWidth = 8;\n\t\t\t// operand 4\n\t\t\tdisInstr->operand[4].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\tdisInstr->operand[4].immS32 = ME;\n\t\t\tdisInstr->operand[4].immWidth = 8;\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_RLWINM_EXTENDED)\n\t\t{\n\t\t\tsint32 rS, rA, SH, MB, ME;\n\t\t\tPPC_OPC_TEMPL_M(opcode, rS, rA, SH, MB, ME);\n\n\t\t\t// operand 0\n\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[0].registerIndex = rA;\n\t\t\t// operand 1\n\t\t\tdisInstr->operand[1].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[1].registerIndex = rS;\n\n\t\t\tif (iDef->ppcAsmOp == PPCASM_OP_EXTLWI || iDef->ppcAsmOp == PPCASM_OP_EXTLWI_)\n\t\t\t{\n\t\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit | operand3Bit;\n\t\t\t\t// operand 2\n\t\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\t\tdisInstr->operand[2].immS32 = ME + 1;\n\t\t\t\tdisInstr->operand[2].immWidth = 8;\n\t\t\t\t// operand 3\n\t\t\t\tdisInstr->operand[3].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\t\tdisInstr->operand[3].immS32 = SH;\n\t\t\t\tdisInstr->operand[3].immWidth = 8;\n\t\t\t}\t\t\n\t\t\telse if (iDef->ppcAsmOp == PPCASM_OP_EXTRWI || iDef->ppcAsmOp == PPCASM_OP_EXTRWI_)\n\t\t\t{\n\t\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit | operand3Bit;\n\t\t\t\tsint8 n = 32 - MB;\n\t\t\t\tsint8 b = SH - n;\n\t\t\t\t// operand 2\n\t\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\t\tdisInstr->operand[2].immS32 = n;\n\t\t\t\tdisInstr->operand[2].immWidth = 8;\n\t\t\t\t// operand 3\n\t\t\t\tdisInstr->operand[3].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\t\tdisInstr->operand[3].immS32 = b;\n\t\t\t\tdisInstr->operand[3].immWidth = 8;\n\t\t\t}\n\t\t\telse if (iDef->ppcAsmOp == PPCASM_OP_SLWI || iDef->ppcAsmOp == PPCASM_OP_SLWI_)\n\t\t\t{\n\t\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit;\n\t\t\t\tsint8 n = SH;\n\t\t\t\t// operand 2\n\t\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\t\tdisInstr->operand[2].immS32 = n;\n\t\t\t\tdisInstr->operand[2].immWidth = 8;\n\t\t\t}\n\t\t\telse if (iDef->ppcAsmOp == PPCASM_OP_SRWI || iDef->ppcAsmOp == PPCASM_OP_SRWI_)\n\t\t\t{\n\t\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit;\n\t\t\t\tsint8 n = 32 - SH;\n\t\t\t\t// operand 2\n\t\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\t\tdisInstr->operand[2].immS32 = n;\n\t\t\t\tdisInstr->operand[2].immWidth = 8;\n\t\t\t}\n\t\t\telse if (iDef->ppcAsmOp == PPCASM_OP_CLRLWI || iDef->ppcAsmOp == PPCASM_OP_CLRLWI_)\n\t\t\t{\n\t\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit;\n\t\t\t\tsint8 n = MB;\n\t\t\t\t// operand 2\n\t\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\t\tdisInstr->operand[2].immS32 = n;\n\t\t\t\tdisInstr->operand[2].immWidth = 8;\n\t\t\t}\n\t\t\telse if (iDef->ppcAsmOp == PPCASM_OP_CLRRWI || iDef->ppcAsmOp == PPCASM_OP_CLRRWI_)\n\t\t\t{\n\t\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit;\n\t\t\t\tsint8 n = 31 - ME;\n\t\t\t\t// operand 2\n\t\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\t\tdisInstr->operand[2].immS32 = n;\n\t\t\t\tdisInstr->operand[2].immWidth = 8;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_RLWNM)\n\t\t{\n\t\t\tsint32 rS, rA, rB, MB, ME;\n\t\t\tPPC_OPC_TEMPL_M(opcode, rS, rA, rB, MB, ME);\n\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit | operand3Bit | operand4Bit;\n\t\t\t// operand 0\n\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[0].registerIndex = rA;\n\t\t\t// operand 1\n\t\t\tdisInstr->operand[1].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[1].registerIndex = rS;\n\t\t\t// operand 2\n\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[2].registerIndex = rB;\n\t\t\t// operand 3\n\t\t\tdisInstr->operand[3].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\tdisInstr->operand[3].immS32 = MB;\n\t\t\tdisInstr->operand[3].immWidth = 8;\n\t\t\t// operand 4\n\t\t\tdisInstr->operand[4].type = PPCASM_OPERAND_TYPE_IMM;\n\t\t\tdisInstr->operand[4].immS32 = ME;\n\t\t\tdisInstr->operand[4].immWidth = 8;\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_RLWNM_EXTENDED)\n\t\t{\n\t\t\tsint32 rS, rA, rB, MB, ME;\n\t\t\tPPC_OPC_TEMPL_M(opcode, rS, rA, rB, MB, ME);\n\t\t\t// operand 0\n\t\t\tdisInstr->operand[0].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[0].registerIndex = rA;\n\t\t\t// operand 1\n\t\t\tdisInstr->operand[1].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[1].registerIndex = rS;\n\t\t\t// operand 2\n\t\t\tdisInstr->operand[2].type = PPCASM_OPERAND_TYPE_GPR;\n\t\t\tdisInstr->operand[2].registerIndex = rB;\n\n\t\t\tif (iDef->ppcAsmOp == PPCASM_OP_ROTLW || iDef->ppcAsmOp == PPCASM_OP_ROTLW_)\n\t\t\t{\n\t\t\t\tdisInstr->operandMask = operand0Bit | operand1Bit | operand2Bit;\n\t\t\t\t// no additional operands displayed\n\t\t\t}\n\t\t}\n\t\telse if (iDef->instructionForm == OP_FORM_XL_CR)\n\t\t{\n\t\t\tPPC_OPC_TEMPL_X_CR();\n\t\t\t// todo - detect and emit simplified mnemonics (e.g. CRSET)\n\t\t\tmakeOpCRBit(0, crD);\n\t\t\tmakeOpCRBit(1, crA);\n\t\t\tmakeOpCRBit(2, crB);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\tdisInstr->operandMask &= ~(iDef->flags & 0x1F);\n\t}\n\telse\n\t{\n\t\t// no match\n\t\tdisInstr->ppcAsmCode = PPCASM_OP_UKN;\n\t}\n}\n\nvoid ppcAssembler_setError(PPCAssemblerInOut* ctx, char const* errorMsg)\n{\n\tctx->errorMsg = errorMsg;\n}\n\nvoid ppcAssembler_setError(PPCAssemblerInOut* ctx, std::string_view errorMsg)\n{\n\tctx->errorMsg = errorMsg;\n}\n\nchar _assemblerErrorMessageDepr[1024];\n\nbool _ppcAssembler_getOperandTextIndex(PPCAssemblerContext& internalCtx, sint32 operandIndex, sint32& textIndex)\n{\n\t// get swapped index\n\toperandIndex = _getOpIndex(internalCtx.iDef, operandIndex);\n\t// check if operand is optional\n\tif ((internalCtx.iDef->flags&(1 << operandIndex)))\n\t{\n\t\t// operand not used\n\t\ttextIndex = -1;\n\t\treturn true;\n\t}\n\t// get operand text index\n\tsint32 opTextIdx = 0;\n\tfor (sint32 i = 0; i < operandIndex; i++)\n\t{\n\t\tif ((internalCtx.iDef->flags&(1 << i)))\n\t\t\tcontinue; // skip operand\n\t\topTextIdx++;\n\t}\n\tif (opTextIdx >= internalCtx.listOperandStr.size())\n\t{\n\t\tppcAssembler_setError(internalCtx.ctx, \"Missing operand\");\n\t\treturn false;\n\t}\n\ttextIndex = opTextIdx;\n\treturn true;\n}\n\nbool _ppcAssembler_parseRegister(std::string_view str, const char* prefix, sint32& regIndex)\n{\n\tconst char* startPtr = str.data();\n\tconst char* endPtr = str.data() + str.size();\n\t// skip whitespaces\n\twhile (startPtr < endPtr)\n\t{\n\t\tif (*startPtr != ' ')\n\t\t\tbreak;\n\t\tstartPtr++;\n\t}\n\t// trim whitespaces at end\n\twhile (endPtr > startPtr)\n\t{\n\t\tif (endPtr[-1] != ' ')\n\t\t\tbreak;\n\t\tendPtr--;\n\t}\n\t// parse register name\n\tif (startPtr + 2 > endPtr)\n\t\treturn false;\n\twhile (true)\n\t{\n\t\tif (startPtr >= endPtr)\n\t\t\treturn false;\n\t\tif (*prefix == '\\0')\n\t\t\tbreak;\n\t\tif (tolower(*prefix) != tolower(*startPtr))\n\t\t\treturn false;\n\t\tprefix++;\n\t\tstartPtr++;\n\t}\n\tsint32 parsedIndex = 0;\n\twhile (startPtr < endPtr)\n\t{\n\t\tparsedIndex *= 10;\n\t\tif (*startPtr < '0' || *startPtr > '9')\n\t\t\treturn false;\n\t\tparsedIndex += (*startPtr - '0');\n\t\tstartPtr++;\n\t}\n\tif (parsedIndex >= 32)\n\t\treturn false;\n\tregIndex = parsedIndex;\n\treturn true;\n}\n\nbool _ppcAssembler_processRegisterOperand(PPCAssemblerContext& internalCtx, sint32 operandIndex, sint32 bitIndex, const char* prefix, const sint32 registerCount)\n{\n\tsint32 opTextIdx;\n\tif (_ppcAssembler_getOperandTextIndex(internalCtx, operandIndex, opTextIdx) == false)\n\t\treturn false;\n\tif (opTextIdx < 0)\n\t\treturn true; // skipped operand\n\t// parse GPR\n\tsint32 gprIndex;\n\tif (_ppcAssembler_parseRegister(internalCtx.listOperandStr[opTextIdx].str, prefix, gprIndex) == false)\n\t{\n\t\tppcAssembler_setError(internalCtx.ctx, fmt::format(\"\\'{0}\\' is not a valid register operand (must be {1}0 to {1}{2})\", internalCtx.listOperandStr[opTextIdx].str, prefix, registerCount-1));\n\t\treturn false;\n\t}\n\tif (gprIndex < 0 || gprIndex >= registerCount)\n\t{\n\t\tppcAssembler_setError(internalCtx.ctx, fmt::format(\"\\'{0}\\' is not a valid register operand (must be {1}0 to {1}{2})\", internalCtx.listOperandStr[opTextIdx].str, prefix, registerCount - 1));\n\t\treturn false;\n\t}\n\tinternalCtx.opcode |= (gprIndex << bitIndex);\n\treturn true;\n}\n\nbool _ppcAssembler_processGPROperand(PPCAssemblerContext& internalCtx, sint32 operandIndex, sint32 bitIndex)\n{\n\treturn _ppcAssembler_processRegisterOperand(internalCtx, operandIndex, bitIndex, \"r\", 32);\n}\n\nbool _ppcAssembler_processCROperand(PPCAssemblerContext& internalCtx, sint32 operandIndex, sint32 bitIndex, bool isEncodedAsBitIndex)\n{\n\treturn _ppcAssembler_processRegisterOperand(internalCtx, operandIndex, bitIndex + (isEncodedAsBitIndex?2:0), \"cr\", 8);\n}\n\ntemplate<typename TExprResult>\nbool _ppcAssembler_evaluateConstantExpression(PPCAssemblerContext& internalCtx, TExpressionParser<TExprResult>& ep, std::string_view expr, TExprResult& result)\n{\n\tif (!ep.IsValidExpression(expr))\n\t{\n\t\tppcAssembler_setError(internalCtx.ctx, fmt::format(\"'{}' is not a valid expression\", expr));\n\t\treturn false;\n\t}\n\tif (!ep.IsConstantExpression(expr))\n\t{\n\t\tppcAssembler_setError(internalCtx.ctx, fmt::format(\"'{}' does not evaluate to a constant expression\", expr));\n\t\treturn false;\n\t}\n\ttry\n\t{\n\t\tresult = ep.Evaluate(expr);\n\t}\n\tcatch (std::exception* e)\n\t{\n\t\tppcAssembler_setError(internalCtx.ctx, fmt::format(\"\\'{0}\\' could not be evaluated. Error: {1}\", expr, e->what()));\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool _ppcAssembler_processBIOperand(PPCAssemblerContext& internalCtx, sint32 operandIndex, sint32 bitIndex)\n{\n\tsint32 opTextIdx;\n\tif (_ppcAssembler_getOperandTextIndex(internalCtx, operandIndex, opTextIdx) == false)\n\t\treturn false;\n\tif (opTextIdx < 0)\n\t\treturn true; // skipped operand\n\t// parse expression\n\t// syntax examples:\n\t// single condition bit of cr0: lt, gt, eq, so\n\t// condition bit with cr index: 4*cr1+lt\n\tTExpressionParser<sint32> ep;\n\tep.AddConstant(\"lt\", 0);\n\tep.AddConstant(\"gt\", 1);\n\tep.AddConstant(\"eq\", 2);\n\tep.AddConstant(\"so\", 3);\n\tep.AddConstant(\"cr0\", 0);\n\tep.AddConstant(\"cr1\", 1);\n\tep.AddConstant(\"cr2\", 2);\n\tep.AddConstant(\"cr3\", 3);\n\tep.AddConstant(\"cr4\", 4);\n\tep.AddConstant(\"cr5\", 5);\n\tep.AddConstant(\"cr6\", 6);\n\tep.AddConstant(\"cr7\", 7);\n\tstd::string_view expr = internalCtx.listOperandStr[opTextIdx].str;\n\tsint32 bi = 0;\n\tif (!_ppcAssembler_evaluateConstantExpression(internalCtx, ep, expr, bi))\n\t\treturn false;\n\tif (bi < 0 || bi >= (8 * 4))\n\t{\n\t\tppcAssembler_setError(internalCtx.ctx, fmt::format(\"CR bit operand \\'{0}\\' evaluated to {1} which is out of range\", expr, bi));\n\t\treturn false;\n\t}\n\tinternalCtx.opcode &= ~(0x1F << bitIndex);\n\tinternalCtx.opcode |= (bi << bitIndex);\n\treturn true;\n}\n\nbool _ppcAssembler_processFPROperand(PPCAssemblerContext& internalCtx, sint32 operandIndex, sint32 bitIndex)\n{\n\treturn _ppcAssembler_processRegisterOperand(internalCtx, operandIndex, bitIndex, \"f\", 32);\n}\n\nbool _ppcAssembler_processImmediateOperandS16(PPCAssemblerContext& internalCtx, sint32 operandIndex, sint32 bitIndex, bool isNegative = false)\n{\n\tsint32 opTextIdx;\n\tif (_ppcAssembler_getOperandTextIndex(internalCtx, operandIndex, opTextIdx) == false)\n\t\treturn false;\n\tif (opTextIdx < 0)\n\t\treturn true; // skipped operand\n\t// parse expression\n\tstd::string expressionString(internalCtx.listOperandStr[opTextIdx].str);\n\n\tif (isNegative)\n\t{\n\t\texpressionString.insert(0, \"0-(\");\n\t\texpressionString.append(\")\");\n\t}\n\tExpressionParser ep;\n\tdouble immD = 0.0f;\n\ttry\n\t{\n\t\tif (ep.IsConstantExpression(expressionString))\n\t\t{\n\t\t\timmD = ep.Evaluate(expressionString);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tinternalCtx.ctx->list_relocs.emplace_back(PPCASM_RELOC::U32_MASKED_IMM, expressionString, 0, bitIndex, 16);\n\t\t\treturn true;\n\t\t}\n\t}\n\tcatch (std::exception* e)\n\t{\n\t\t// check if expression is invalid or if it contains unknown constants\n\t\tsprintf(_assemblerErrorMessageDepr, \"\\'%s\\' could not be evaluated. Error: %s\", expressionString.c_str(), e->what());\n\t\tppcAssembler_setError(internalCtx.ctx, _assemblerErrorMessageDepr);\n\t\treturn false;\n\t}\n\tuint32 imm = (uint32)(sint32)immD;\n\timm &= 0xFFFF;\n\tinternalCtx.opcode |= (imm << bitIndex);\n\treturn true;\n}\n\nbool _ppcAssembler_processImmediateOperandU5(PPCAssemblerContext& internalCtx, sint32 operandIndex, sint32 bitIndex)\n{\n\tsint32 opTextIdx;\n\tif (_ppcAssembler_getOperandTextIndex(internalCtx, operandIndex, opTextIdx) == false)\n\t\treturn false;\n\tif (opTextIdx < 0)\n\t\treturn true; // skipped operand\n\t// parse expression\n\tExpressionParser ep;\n\tdouble immD = 0.0f;\n\ttry\n\t{\n\t\timmD = ep.Evaluate(internalCtx.listOperandStr[opTextIdx].str);\n\t}\n\tcatch (std::exception*)\n\t{\n\t\t// check if expression is invalid or if it contains unknown constants\n\t\tppcAssembler_setError(internalCtx.ctx, fmt::format(\"\\'{}\\' is not a valid expression\", internalCtx.listOperandStr[opTextIdx].str));\n\t\treturn false;\n\t}\n\tsint32 immS32 = (sint32)immD;\n\tif (immS32 < 0 || immS32 >= 32)\n\t{\n\t\tppcAssembler_setError(internalCtx.ctx, fmt::format(\"\\'{}\\' is not in range 0-31\", internalCtx.listOperandStr[opTextIdx].str));\n\t\treturn false;\n\t}\n\tuint32 imm = (uint32)immS32;\n\timm &= 0x1F;\n\tinternalCtx.opcode |= (imm << bitIndex);\n\treturn true;\n}\n\nbool _ppcAssembler_processImmediateOperandU5Const(PPCAssemblerContext& internalCtx, sint32 operandIndex, sint8& value)\n{\n\tsint32 opTextIdx;\n\tif (_ppcAssembler_getOperandTextIndex(internalCtx, operandIndex, opTextIdx) == false)\n\t\treturn false;\n\tif (opTextIdx < 0)\n\t\treturn true; // skipped operand\n\t// parse expression\n\tTExpressionParser<sint32> ep;\n\tauto expr = internalCtx.listOperandStr[opTextIdx].str;\n\tsint32 r;\n\tif (!_ppcAssembler_evaluateConstantExpression(internalCtx, ep, expr, r))\n\t\treturn false;\n\tif (r < 0 || r >= 32)\n\t{\n\t\tppcAssembler_setError(internalCtx.ctx, fmt::format(\"Expression '\\'{0}\\' which evaluates to {1} is not in range 0-31\", expr, r));\n\t\treturn false;\n\t}\n\tvalue = (sint8)r;\n\treturn true;\n}\n\nbool _ppcAssembler_isConstantBranchTargetExpr(std::string& expressionString, sint32& relativeAddr)\n{\n\tif (expressionString.length() > 0 && expressionString[0] == '.')\n\t{\n\t\tExpressionParser ep;\n\t\tdouble branchDistance = 0.0f;\n\t\ttry\n\t\t{\n\t\t\tbranchDistance = ep.Evaluate(expressionString.substr(1).insert(0, \"0\"));\n\t\t}\n\t\tcatch (std::exception&)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\trelativeAddr = (sint32)branchDistance;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nbool _ppcAssembler_processBranchOperandS16(PPCAssemblerContext& internalCtx, sint32 operandIndex)\n{\n\tsint32 opTextIdx;\n\tif (_ppcAssembler_getOperandTextIndex(internalCtx, operandIndex, opTextIdx) == false)\n\t\treturn false;\n\tif (opTextIdx < 0)\n\t\treturn true; // skipped operand\n\tstd::string expressionString(internalCtx.listOperandStr[opTextIdx].str);\n\tsint32 relativeAddr;\n\tif (_ppcAssembler_isConstantBranchTargetExpr(expressionString, relativeAddr))\n\t{\n\t\tif (relativeAddr < -32768 || relativeAddr > 32767)\n\t\t{\n\t\t\tsprintf(_assemblerErrorMessageDepr, \"Branch target out of range\");\n\t\t\tppcAssembler_setError(internalCtx.ctx, _assemblerErrorMessageDepr);\n\t\t\treturn false;\n\t\t}\n\t\tif (relativeAddr&3)\n\t\t{\n\t\t\tsprintf(_assemblerErrorMessageDepr, \"Branch target must be aligned to 4\");\n\t\t\tppcAssembler_setError(internalCtx.ctx, _assemblerErrorMessageDepr);\n\t\t\treturn false;\n\t\t}\n\t\tinternalCtx.opcode |= (relativeAddr & 0xFFFC);\n\t\treturn true;\n\t}\t\t\t \n\t// create reloc\n\tinternalCtx.ctx->list_relocs.emplace_back(PPCASM_RELOC::BRANCH_S16, expressionString, 0, 0, 0);\n\treturn true;\n}\n\nbool _ppcAssembler_processBranchOperandS26(PPCAssemblerContext& internalCtx, sint32 operandIndex)\n{\n\tsint32 opTextIdx;\n\tif (_ppcAssembler_getOperandTextIndex(internalCtx, operandIndex, opTextIdx) == false)\n\t\treturn false;\n\tif (opTextIdx < 0)\n\t\treturn true; // skipped operand\n\tstd::string expressionString(internalCtx.listOperandStr[opTextIdx].str);\n\tsint32 relativeAddr;\n\tif (_ppcAssembler_isConstantBranchTargetExpr(expressionString, relativeAddr))\n\t{\n\t\tif (relativeAddr < -33554432 || relativeAddr > 33554431)\n\t\t{\n\t\t\tppcAssembler_setError(internalCtx.ctx, \"Branch target out of range\");\n\t\t\treturn false;\n\t\t}\n\t\tif (relativeAddr & 3)\n\t\t{\n\t\t\tppcAssembler_setError(internalCtx.ctx, \"Branch target must be aligned to 4\");\n\t\t\treturn false;\n\t\t}\n\t\tinternalCtx.opcode |= (relativeAddr & 0x3FFFFFC);\n\t\treturn true;\n\t}\n\t// create reloc\n\tinternalCtx.ctx->list_relocs.emplace_back(PPCASM_RELOC::BRANCH_S26, expressionString, 0, 0, 0);\n\treturn true;\n}\n\nvoid _ppcAssembler_setAlignment(PPCAssemblerContext& internalInfo, uint32 alignment)\n{\n\tif (internalInfo.ctx->forceNoAlignment)\n\t{\n\t\tinternalInfo.ctx->alignmentRequirement = 1;\n\t\tinternalInfo.ctx->alignmentPaddingSize = 0;\n\t\tinternalInfo.ctx->virtualAddressAligned = internalInfo.ctx->virtualAddress;\n\t\treturn;\n\t}\n\tinternalInfo.ctx->alignmentRequirement = alignment;\n\tif (alignment == 0)\n\t{\n\t\tinternalInfo.ctx->alignmentPaddingSize = 0;\n\t\tinternalInfo.ctx->virtualAddressAligned = internalInfo.ctx->virtualAddress;\n\t\treturn;\n\t}\n\tuint32 alignedVA = (internalInfo.ctx->virtualAddress + alignment - 1) & ~(alignment - 1);\n\tinternalInfo.ctx->alignmentPaddingSize = alignedVA - internalInfo.ctx->virtualAddress;\n\tinternalInfo.ctx->virtualAddressAligned = alignedVA;\n}\n\nenum class ASM_DATA_DIRECTIVE\n{\n\tNONE,\n\tFLOAT,\n\tDOUBLE,\n\tU32,\n\tU16,\n\tU8, // alias to .string\n};\n\nbool _ppcAssembler_emitDataDirective(PPCAssemblerContext& internalInfo, ASM_DATA_DIRECTIVE dataDirective)\n{\n\tPPCASM_RELOC relocType;\n\n\tswitch (dataDirective)\n\t{\n\tcase ASM_DATA_DIRECTIVE::FLOAT:\n\t\trelocType = PPCASM_RELOC::FLOAT;\n\t\tbreak;\n\tcase ASM_DATA_DIRECTIVE::DOUBLE:\n\t\trelocType = PPCASM_RELOC::DOUBLE;\n\t\tbreak;\n\tcase ASM_DATA_DIRECTIVE::U32:\n\t\trelocType = PPCASM_RELOC::U32;\n\t\tbreak;\n\tcase ASM_DATA_DIRECTIVE::U16:\n\t\trelocType = PPCASM_RELOC::U16;\n\t\tbreak;\n\tcase ASM_DATA_DIRECTIVE::U8:\n\t\trelocType = PPCASM_RELOC::U8;\n\t\tbreak;\n\tdefault:\n\t\tcemu_assert_debug(false);\n\t\treturn false;\n\t}\n\n\tuint32 elementSize = 0;\n\t\n\tif (relocType == PPCASM_RELOC::FLOAT)\n\t\telementSize = 4;\n\telse if (relocType == PPCASM_RELOC::DOUBLE)\n\t\telementSize = 8;\n\telse if (relocType == PPCASM_RELOC::U32)\n\t\telementSize = 4;\n\telse if (relocType == PPCASM_RELOC::U16)\n\t\telementSize = 2;\n\telse if (relocType == PPCASM_RELOC::U8)\n\t\telementSize = 1;\n\telse\n\t\tcemu_assert_debug(false);\n\t\n\t_ppcAssembler_setAlignment(internalInfo, elementSize);\n\tsize_t elementCount = internalInfo.listOperandStr.size();\n\tinternalInfo.ctx->outputData.reserve(elementSize * elementCount);\n\tsize_t writeIndex = 0;\n\tfor (size_t i = 0; i < elementCount; i++)\n\t{\n\t\tstd::string_view expressionStr = internalInfo.listOperandStr[i].str;\n\t\t// handle string constants\n\t\tif (internalInfo.listOperandStr[i].str.size() >= 1 && expressionStr[0] == '\"')\n\t\t{\n\t\t\tif (dataDirective != ASM_DATA_DIRECTIVE::U8)\n\t\t\t{\n\t\t\t\tppcAssembler_setError(internalInfo.ctx, \"Strings constants are only allowed in .byte or .string data directives\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (expressionStr.size() < 2 || expressionStr[expressionStr.size()-1] != '\"')\n\t\t\t{\n\t\t\t\tppcAssembler_setError(internalInfo.ctx, \"String constants must end with a quotation mark. Example: \\\"text\\\"\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// write string bytes + null-termination character\n\t\t\tsize_t strConstantLength = expressionStr.size() - 2;\n\t\t\tinternalInfo.ctx->outputData.insert(internalInfo.ctx->outputData.end(), expressionStr.data() + 1, expressionStr.data() + 1 + strConstantLength);\n\t\t\tinternalInfo.ctx->outputData.emplace_back(0);\n\t\t\tcontinue;\n\t\t}\n\t\t// numeric constants\n\t\tinternalInfo.ctx->outputData.resize(writeIndex + elementSize);\n\t\tuint8* elementPtr = internalInfo.ctx->outputData.data() + writeIndex;\n\t\tfor (uint32 b = 0; b < elementSize; b++)\n\t\t{\n\t\t\tinternalInfo.ctx->outputData[writeIndex] = 0;\n\t\t\twriteIndex++;\n\t\t}\n\t\tExpressionParser ep;\n\t\tif (ep.IsConstantExpression(expressionStr))\n\t\t{\n\t\t\tdouble solution = ep.Evaluate(expressionStr);\n\t\t\tswitch (relocType)\n\t\t\t{\n\t\t\tcase PPCASM_RELOC::U32:\n\t\t\t\t*(uint32be*)elementPtr = (uint32)solution;\n\t\t\t\tbreak;\n\t\t\tcase PPCASM_RELOC::U16:\n\t\t\t\t*(uint16be*)elementPtr = (uint16)solution;\n\t\t\t\tbreak;\n\t\t\tcase PPCASM_RELOC::U8:\n\t\t\t\t*(uint8be*)elementPtr = (uint8)solution;\n\t\t\t\tbreak;\n\t\t\tcase PPCASM_RELOC::DOUBLE:\n\t\t\t\t*(float64be*)elementPtr = solution;\n\t\t\t\tbreak;\n\t\t\tcase PPCASM_RELOC::FLOAT:\n\t\t\t\t*(float32be*)elementPtr = (float)solution;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// generate reloc if we cant resolve immediately\n\t\t\tinternalInfo.ctx->list_relocs.emplace_back(relocType, std::string(internalInfo.listOperandStr[i].str), (uint32)(elementPtr - internalInfo.ctx->outputData.data()), 0, 0);\n\t\t}\n\t}\n\treturn true;\n}\n\nvoid _ppcAssembler_emitAlignDirective(PPCAssemblerContext& internalInfo, sint32 alignmentValue)\n{\n\t_ppcAssembler_setAlignment(internalInfo, 1);\n\tuint32 currentAddr = internalInfo.ctx->virtualAddress;\n\twhile ((currentAddr % (uint32)alignmentValue))\n\t{\n\t\tinternalInfo.ctx->outputData.emplace_back(0);\n\t\tcurrentAddr++;\n\t}\n}\n\nvoid _ppcAssembler_translateAlias(boost::static_string<32>& instructionName)\n{\n\tif (instructionName.compare(\"BNL\") == 0)\n\t\tinstructionName.assign(\"BGT\");\n\tif (instructionName.compare(\"BNG\") == 0)\n\t\tinstructionName.assign(\"BLE\");\n}\n\nbool ppcAssembler_assembleSingleInstruction(char const* text, PPCAssemblerInOut* ctx)\n{\n\tPPCAssemblerContext internalInfo;\n\tinternalInfo.ctx = ctx;\n\t// tokenize input\n\tchar const* currentPtr = text;\n\tchar const* startPtr = text;\n\tchar const* endPtr = startPtr+strlen(startPtr);\n\t// cut off comments\n\tfor (const char* itrPtr = startPtr; itrPtr < endPtr; itrPtr++)\n\t{\n\t\tif (*itrPtr == '#')\n\t\t{\n\t\t\tendPtr = itrPtr;\n\t\t\tbreak;\n\t\t}\n\t}\n\t// trim whitespaces at end and beginning\n\twhile (endPtr > currentPtr)\n\t{\n\t\tif (endPtr[-1] != ' ' && endPtr[-1] != '\\t')\n\t\t\tbreak;\n\t\tendPtr--;\n\t}\n\twhile (currentPtr < endPtr)\n\t{\n\t\tif (currentPtr[0] != ' ' && currentPtr[0] != '\\t')\n\t\t\tbreak;\n\t\tcurrentPtr++;\n\t}\n\t// parse name of instruction\n\tboost::static_string<32> instructionName;\n\twhile (*currentPtr != ' ' && *currentPtr != '\\t' && currentPtr < endPtr)\n\t{\n\t\tif (instructionName.size() >= instructionName.capacity())\n\t\t{\n\t\t\tppcAssembler_setError(ctx, \"Instruction name exceeds maximum allowed length\");\n\t\t\treturn false;\n\t\t}\n\t\tinstructionName.push_back((char)toupper(*currentPtr));\n\t\tcurrentPtr++;\n\t}\n\tif (instructionName.empty())\n\t{\n\t\tppcAssembler_setError(ctx, \"Instruction name is invalid\");\n\t\treturn false;\n\t}\n\t// handle branch hint suffix\n\tbool hasBranchHint = false;\n\tbool branchHintTaken = false; // '+' -> true, '-' -> false\n\tif (instructionName.back() == '+')\n\t{\n\t\thasBranchHint = true;\n\t\tbranchHintTaken = true;\n\t\tinstructionName.pop_back();\n\t}\n\tif (instructionName.back() == '-')\n\t{\n\t\thasBranchHint = true;\n\t\tbranchHintTaken = false;\n\t\tinstructionName.pop_back();\n\t}\n\t// handle instruction name aliases\n\t_ppcAssembler_translateAlias(instructionName);\n\t// parse operands\n\tinternalInfo.listOperandStr.clear();\n\n\tbool isInString = false;\n\n\twhile (currentPtr < endPtr)\n\t{\n\t\tcurrentPtr++;\n\t\tstartPtr = currentPtr;\n\t\t// find end of operand\n\t\twhile (currentPtr < endPtr)\n\t\t{\n\t\t\tif (*currentPtr == '\"')\n\t\t\t\tisInString=!isInString;\n\n\t\t\tif (*currentPtr == ',' && !isInString)\n\t\t\t\tbreak;\n\t\t\tcurrentPtr++;\n\t\t}\n\t\t// trim whitespaces at the beginning and end\n\t\tconst char* operandStartPtr = startPtr;\n\t\tconst char* operandEndPtr = currentPtr;\n\t\twhile (operandStartPtr < endPtr)\n\t\t{\n\t\t\tif (*operandStartPtr != ' ' && *operandStartPtr != '\\t')\n\t\t\t\tbreak;\n\t\t\toperandStartPtr++;\n\t\t}\n\t\twhile (operandEndPtr > operandStartPtr)\n\t\t{\n\t\t\tif (operandEndPtr[-1] != ' ' && operandEndPtr[-1] != '\\t')\n\t\t\t\tbreak;\n\t\t\toperandEndPtr--;\n\t\t}\n\t\tinternalInfo.listOperandStr.emplace_back(operandStartPtr, operandEndPtr);\n\t}\n\t// check for data directives\n\tASM_DATA_DIRECTIVE dataDirective = ASM_DATA_DIRECTIVE::NONE;\n\tif (instructionName.compare(\".FLOAT\") == 0)\n\t\tdataDirective = ASM_DATA_DIRECTIVE::FLOAT;\n\telse if (instructionName.compare(\".DOUBLE\") == 0)\n\t\tdataDirective = ASM_DATA_DIRECTIVE::DOUBLE;\n\telse if (instructionName.compare(\".INT\") == 0 || instructionName.compare(\".UINT\") == 0 || instructionName.compare(\".PTR\") == 0 || instructionName.compare(\".U32\") == 0 || instructionName.compare(\".LONG\") == 0)\n\t\tdataDirective = ASM_DATA_DIRECTIVE::U32;\n\telse if (instructionName.compare(\".WORD\") == 0 || instructionName.compare(\".U16\") == 0 || instructionName.compare(\".SHORT\") == 0)\n\t\tdataDirective = ASM_DATA_DIRECTIVE::U16;\n\telse if (instructionName.compare(\".BYTE\") == 0 || instructionName.compare(\".STRING\") == 0 || instructionName.compare(\".U8\") == 0 || instructionName.compare(\".CHAR\") == 0)\n\t\tdataDirective = ASM_DATA_DIRECTIVE::U8;\n\n\tif (dataDirective != ASM_DATA_DIRECTIVE::NONE)\n\t{\n\t\tif (internalInfo.listOperandStr.size() < 1)\n\t\t{\n\t\t\tppcAssembler_setError(ctx, fmt::format(\"Value expected after data directive {}\", instructionName.c_str()));\n\t\t\treturn false;\n\t\t}\n\t\treturn _ppcAssembler_emitDataDirective(internalInfo, dataDirective);\n\t}\n\t// handle .align directive\n\tif (instructionName.compare(\".ALIGN\") == 0)\n\t{\n\t\t// handle align data directive\n\t\tif (internalInfo.listOperandStr.size() != 1)\n\t\t{\n\t\t\tppcAssembler_setError(ctx, \".align directive must have exactly one operand\");\n\t\t\treturn false;\n\t\t}\n\t\tExpressionParser ep;\n\t\ttry\n\t\t{\n\t\t\tif (ep.IsConstantExpression(internalInfo.listOperandStr[0].str))\n\t\t\t{\n\t\t\t\tsint32 alignmentValue = ep.Evaluate<sint32>(internalInfo.listOperandStr[0].str);\n\t\t\t\tif (alignmentValue <= 0 || alignmentValue >= 256)\n\t\t\t\t{\n\t\t\t\t\tppcAssembler_setError(ctx, fmt::format(\"Alignment value \\'{}\\' is not within the allowed range (1-256)\", alignmentValue));\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t_ppcAssembler_emitAlignDirective(internalInfo, alignmentValue);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tppcAssembler_setError(ctx, fmt::format(\"Expression \\'{}\\' for .align directive is not a constant\", internalInfo.listOperandStr[0].str));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\tcatch (std::exception* e)\n\t\t{\n\t\t\tppcAssembler_setError(ctx, fmt::format(\"Expression \\'{}\\' for .align directive could not be evaluated. Error: {}\", internalInfo.listOperandStr[0].str, e->what()));\n\t\t\treturn false;\n\t\t}\n\t}\n\t// find match in instruction definition table\n\tPPCInstructionDef* iDef = nullptr;\n\tfor (sint32 i = 0; i < sizeof(ppcInstructionTable) / sizeof(PPCInstructionDef); i++)\n\t{\n\t\tPPCInstructionDef* instr = ppcInstructionTable + i;\n\t\tif (instructionName.compare(ppcAssembler_getInstructionName(instr->ppcAsmOp)) == 0)\n\t\t{\n\t\t\tiDef = instr;\n\t\t\tinternalInfo.iDef = iDef;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (iDef == nullptr)\n\t{\n\t\tppcAssembler_setError(ctx, fmt::format(\"Instruction \\'{}\\' is unknown or not supported\", instructionName.c_str()));\n\t\treturn false;\n\t}\n\t// build opcode\n\t_ppcAssembler_setAlignment(internalInfo, 4);\n\tuint32 opcMask;\n\tuint32 opcBits;\n\tppcAssembler_buildOpcMask(iDef, opcMask, opcBits);\n\tinternalInfo.opcode = opcBits & opcMask;\n\tinternalInfo.opcode |= (iDef->compareBits&iDef->maskBits);\n\t// handle operands\n\tif (iDef->instructionForm == OP_FORM_DYNAMIC)\n\t{\n\t\tfor (size_t i = 0; i < iDef->encodedOperands.size(); i++)\n\t\t{\n\t\t\tbool r = std::visit([&](auto&& op) -> bool {\n\t\t\t\treturn op.AssembleOperand(&internalInfo, iDef, internalInfo.opcode, i);\n\t\t\t\t}, iDef->encodedOperands[i]);\n\t\t\tif (!r)\n\t\t\t\treturn false;\n\t\t}\n\t\tfor(auto& it : iDef->constraints)\n\t\t{\n\t\t\tstd::visit([&](auto&& op) {\n\t\t\t\top.AssembleConstraint(&internalInfo, iDef, internalInfo.opcode);\n\t\t\t\t}, it);\n\t\t}\n\t}\n\telse if (iDef->instructionForm == OP_FORM_NO_OPERAND)\n\t{\n\t\t// do nothing\n\t}\n\telse if (iDef->instructionForm == OP_FORM_OP3_A_CMP)\n\t{\n\t\tif (internalInfo.listOperandStr.size() == 2)\n\t\t{\n\t\t\t// implicit cr0\n\t\t\tif (_ppcAssembler_processGPROperand(internalInfo, 0, 16) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processGPROperand(internalInfo, 1, 11) == false)\n\t\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (_ppcAssembler_processCROperand(internalInfo, 0, 21, true) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processGPROperand(internalInfo, 1, 16) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processGPROperand(internalInfo, 2, 11) == false)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\telse if (iDef->instructionForm == OP_FORM_CMP_SIMM)\n\t{\n\t\tif (internalInfo.listOperandStr.size() == 2)\n\t\t{\n\t\t\t// implicit cr0\n\t\t\tif (_ppcAssembler_processGPROperand(internalInfo, 0, 16) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processImmediateOperandS16(internalInfo, 1, 0) == false)\n\t\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (_ppcAssembler_processCROperand(internalInfo, 0, 21, true) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processGPROperand(internalInfo, 1, 16) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processImmediateOperandS16(internalInfo, 2, 0) == false)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\telse if (iDef->instructionForm == OP_FORM_OP3_A_IMM)\n\t{\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 0, 16) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 1, 21) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processImmediateOperandU5(internalInfo, _getOpIndex(iDef, 2), 11) == false)\n\t\t\treturn false;\n\t}\n\telse if (iDef->instructionForm == OP_FORM_X_FP_CMP)\n\t{\n\t\tif (internalInfo.listOperandStr.size() == 2)\n\t\t{\n\t\t\t// implicit cr0\n\t\t\tif (_ppcAssembler_processFPROperand(internalInfo, 0, 16) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processFPROperand(internalInfo, 1, 11) == false)\n\t\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (_ppcAssembler_processCROperand(internalInfo, 0, 21, true) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processFPROperand(internalInfo, 1, 16) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processFPROperand(internalInfo, 2, 11) == false)\n\t\t\t\treturn false;\n\t\t}\n\t}\n\telse if (iDef->instructionForm == OP_FORM_RLWINM)\n\t{\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 0, 16) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 1, 21) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processImmediateOperandU5(internalInfo, 2, 11) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processImmediateOperandU5(internalInfo, 3, 6) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processImmediateOperandU5(internalInfo, 4, 1) == false)\n\t\t\treturn false;\n\t}\n\telse if (iDef->instructionForm == OP_FORM_RLWINM_EXTENDED)\n\t{\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 0, 16) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 1, 21) == false)\n\t\t\treturn false;\n\n\t\tuint8 SH = 0;\n\t\tuint8 MB = 0;\n\t\tuint8 ME = 0;\n\n\t\tif (internalInfo.iDef->ppcAsmOp == PPCASM_OP_EXTLWI || internalInfo.iDef->ppcAsmOp == PPCASM_OP_EXTLWI_)\n\t\t{\n\t\t\tsint8 n, b;\n\t\t\tif (!_ppcAssembler_processImmediateOperandU5Const(internalInfo, 2, n))\n\t\t\t\treturn false;\n\t\t\tif (!_ppcAssembler_processImmediateOperandU5Const(internalInfo, 3, b))\n\t\t\t\treturn false;\n\n\t\t\tSH = b;\n\t\t\tMB = 0;\n\t\t\tME = n - 1;\n\t\t}\n\t\telse if (internalInfo.iDef->ppcAsmOp == PPCASM_OP_EXTRWI || internalInfo.iDef->ppcAsmOp == PPCASM_OP_EXTRWI_)\n\t\t{\n\t\t\tsint8 n, b;\n\t\t\tif (!_ppcAssembler_processImmediateOperandU5Const(internalInfo, 2, n))\n\t\t\t\treturn false;\n\t\t\tif (!_ppcAssembler_processImmediateOperandU5Const(internalInfo, 3, b))\n\t\t\t\treturn false;\n\n\t\t\tSH = b + n;\n\t\t\tMB = 32 - n;\n\t\t\tME = 31;\n\t\t}\n\t\telse if (internalInfo.iDef->ppcAsmOp == PPCASM_OP_SLWI || internalInfo.iDef->ppcAsmOp == PPCASM_OP_SLWI_)\n\t\t{\n\t\t\tsint8 n;\n\t\t\tif (!_ppcAssembler_processImmediateOperandU5Const(internalInfo, 2, n))\n\t\t\t\treturn false;\n\n\t\t\tSH = n;\n\t\t\tMB = 0;\n\t\t\tME = 31 - n;\n\t\t}\n\t\telse if (internalInfo.iDef->ppcAsmOp == PPCASM_OP_SRWI || internalInfo.iDef->ppcAsmOp == PPCASM_OP_SRWI_)\n\t\t{\n\t\t\tsint8 n;\n\t\t\tif (!_ppcAssembler_processImmediateOperandU5Const(internalInfo, 2, n))\n\t\t\t\treturn false;\n\t\t\tSH = 32 - n;\n\t\t\tMB = n;\n\t\t\tME = 31;\n\t\t}\n\t\telse if (internalInfo.iDef->ppcAsmOp == PPCASM_OP_CLRLWI || internalInfo.iDef->ppcAsmOp == PPCASM_OP_CLRLWI_)\n\t\t{\n\t\t\tsint8 n;\n\t\t\tif (!_ppcAssembler_processImmediateOperandU5Const(internalInfo, 2, n))\n\t\t\t\treturn false;\n\t\t\tSH = 0;\n\t\t\tMB = n;\n\t\t\tME = 31;\n\t\t}\n\t\telse if (internalInfo.iDef->ppcAsmOp == PPCASM_OP_CLRRWI || internalInfo.iDef->ppcAsmOp == PPCASM_OP_CLRRWI_)\n\t\t{\n\t\t\tsint8 n;\n\t\t\tif (!_ppcAssembler_processImmediateOperandU5Const(internalInfo, 2, n))\n\t\t\t\treturn false;\n\t\t\tSH = 0;\n\t\t\tMB = 0;\n\t\t\tME = 31 - n;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\n\t\tinternalInfo.opcode |= (SH << 11);\n\t\tinternalInfo.opcode |= (MB << 6);\n\t\tinternalInfo.opcode |= (ME << 1);\n\t}\n\telse if (iDef->instructionForm == OP_FORM_RLWNM)\n\t{\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 0, 16) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 1, 21) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 2, 11) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processImmediateOperandU5(internalInfo, 3, 6) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processImmediateOperandU5(internalInfo, 4, 1) == false)\n\t\t\treturn false;\n\t}\n\telse if (iDef->instructionForm == OP_FORM_RLWNM_EXTENDED)\n\t{\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 0, 16) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 1, 21) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processGPROperand(internalInfo, 2, 11) == false)\n\t\t\treturn false;\n\t\tuint32 MB = 0, ME = 0;\n\t\tif (internalInfo.iDef->ppcAsmOp == PPCASM_OP_ROTLW || internalInfo.iDef->ppcAsmOp == PPCASM_OP_ROTLW_)\n\t\t{\n\t\t\tMB = 0;\n\t\t\tME = 31;\n\t\t}\n\t\tinternalInfo.opcode |= (MB << 6);\n\t\tinternalInfo.opcode |= (ME << 1);\n\t}\n\telse if (iDef->instructionForm == OP_FORM_BRANCH_S16)\n\t{\n\t\tif (iDef->ppcAsmOp == PPCASM_OP_BC)\n\t\t{\n\t\t\t// generic conditional branch\n\t\t\t// BC <BO>, <BI>, <dst>\n\t\t\tsint8 bo;\n\t\t\tif (_ppcAssembler_processImmediateOperandU5Const(internalInfo, 0, bo) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processBIOperand(internalInfo, 1, 16) == false)\n\t\t\t\treturn false;\n\t\t\tif (_ppcAssembler_processBranchOperandS16(internalInfo, 2) == false)\n\t\t\t\treturn false;\n\t\t\tinternalInfo.opcode |= (bo << 21);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// BLE, BGT etc.\n\t\t\tif (internalInfo.listOperandStr.size() == 2)\n\t\t\t{\n\t\t\t\t// explicit CR\n\t\t\t\tif (_ppcAssembler_processCROperand(internalInfo, 0, 16, true) == false)\n\t\t\t\t\treturn false;\n\t\t\t\tif (_ppcAssembler_processBranchOperandS16(internalInfo, 1) == false)\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (_ppcAssembler_processBranchOperandS16(internalInfo, 0) == false)\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (hasBranchHint)\n\t\t\t\tinternalInfo.opcode |= (1 << 21);\n\t\t}\n\t}\n\telse if (iDef->instructionForm == OP_FORM_BRANCH_S24)\n\t{\n\t\tif (_ppcAssembler_processBranchOperandS26(internalInfo, 0) == false)\n\t\t\treturn false;\n\t}\n\telse if (iDef->instructionForm == OP_FORM_XL_CR)\n\t{\n\t\tif (_ppcAssembler_processBIOperand(internalInfo, 0, 21) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processBIOperand(internalInfo, 1, 16) == false)\n\t\t\treturn false;\n\t\tif (_ppcAssembler_processBIOperand(internalInfo, 2, 11) == false)\n\t\t\treturn false;\n\t}\n\telse\n\t{\n\t\tcemu_assert_debug(false); // unsupported instruction form\n\t\treturn false;\n\t}\n\tctx->outputData.resize(4);\n\tctx->outputData[0] = (uint8)((internalInfo.opcode >> 24) & 0xFF);\n\tctx->outputData[1] = (uint8)((internalInfo.opcode >> 16) & 0xFF);\n\tctx->outputData[2] = (uint8)((internalInfo.opcode >>  8) & 0xFF);\n\tctx->outputData[3] = (uint8)((internalInfo.opcode >>  0) & 0xFF);\n\treturn true;\n}\n\nvoid _testAsm(uint32 expected, const char* iText)\n{\n\tPPCAssemblerInOut ctx{};\n\tctx.virtualAddress = 0;\n\tif (!ppcAssembler_assembleSingleInstruction(iText, &ctx))\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\tcemu_assert_debug(ctx.outputData.size() == 4);\n\tuint32 opcode = 0;\n\topcode |= ((uint32)ctx.outputData[0] << 24);\n\topcode |= ((uint32)ctx.outputData[1] << 16);\n\topcode |= ((uint32)ctx.outputData[2] << 8);\n\topcode |= ((uint32)ctx.outputData[3] << 0);\n\tcemu_assert_debug(expected == opcode);\n\n}\n\nvoid _testAsmFail(const char* iText)\n{\n\tPPCAssemblerInOut ctx{};\n\tctx.virtualAddress = 0;\n\tif (!ppcAssembler_assembleSingleInstruction(iText, &ctx))\n\t\treturn;\n\tcemu_assert_debug(false); // should fail\n}\n\nvoid _testAsmArray(std::vector<uint8> expectedArray, const char* iText)\n{\n\tPPCAssemblerInOut ctx{};\n\tctx.virtualAddress = 0;\n\tif (!ppcAssembler_assembleSingleInstruction(iText, &ctx))\n\t{\n\t\tcemu_assert_debug(false);\n\t\treturn;\n\t}\n\tcemu_assert_debug(ctx.outputData.size() == expectedArray.size());\n\tfor (size_t offset = 0; offset < expectedArray.size(); offset++)\n\t{\n\t\tcemu_assert_debug(ctx.outputData[offset] == expectedArray[offset]);\n\t}\n}\n\nvoid ppcAsmTestDisassembler()\n{\n\tcemu_assert_debug(_CanStoreInteger(5, 10, false));\n\tcemu_assert_debug(_CanStoreInteger(1023, 10, false));\n\tcemu_assert_debug(!_CanStoreInteger(1024, 10, false));\n\tcemu_assert_debug(_CanStoreInteger(511, 10, true));\n\tcemu_assert_debug(!_CanStoreInteger(512, 10, true));\n\tcemu_assert_debug(_CanStoreInteger(-511, 10, true));\n\tcemu_assert_debug(_CanStoreInteger(-512, 10, true));\n\tcemu_assert_debug(!_CanStoreInteger(-513, 10, true));\n\n\tPPCDisassembledInstruction disasm;\n\n\tauto disassemble = [&](uint32 opcode, PPCASM_OP ppcAsmCode)\n\t{\n\t\tdisasm = { 0 };\n\t\tppcAssembler_disassemble(0x10000000, opcode, &disasm);\n\t\tcemu_assert_debug(disasm.ppcAsmCode == ppcAsmCode);\n\t};\n\n\tauto checkOperandMask = [&](bool op0 = false, bool op1 = false, bool op2 = false, bool op3 = false)\n\t{\n\t\tbool hasOp0 = (disasm.operandMask & (1 << 0));\n\t\tbool hasOp1 = (disasm.operandMask & (1 << 1));\n\t\tbool hasOp2 = (disasm.operandMask & (1 << 2));\n\t\tbool hasOp3 = (disasm.operandMask & (1 << 3));\n\n\t\tcemu_assert_debug(hasOp0 == op0);\n\t\tcemu_assert_debug(hasOp1 == op1);\n\t\tcemu_assert_debug(hasOp2 == op2);\n\t\tcemu_assert_debug(hasOp3 == op3);\n\t};\n\n\tauto checkOpCR = [&](size_t index, uint8 crIndex)\n\t{\n\t\tcemu_assert_debug(disasm.operand[index].type == PPCASM_OPERAND_TYPE_CR);\n\t\tcemu_assert_debug(disasm.operand[index].registerIndex == crIndex);\n\t};\n\n\tauto checkOpCRBit = [&](size_t index, uint8 crIndex)\n\t{\n\t\tcemu_assert_debug(disasm.operand[index].type == PPCASM_OPERAND_TYPE_CR_BIT);\n\t\tcemu_assert_debug(disasm.operand[index].registerIndex == crIndex);\n\t};\n\n\tauto checkOpFPR = [&](size_t index, uint8 fprIndex)\n\t{\n\t\tcemu_assert_debug(disasm.operand[index].type == PPCASM_OPERAND_TYPE_FPR);\n\t\tcemu_assert_debug(disasm.operand[index].registerIndex == fprIndex);\n\t};\n\n\tauto checkOpGPR = [&](size_t index, uint8 gprIndex)\n\t{\n\t\tcemu_assert_debug(disasm.operand[index].type == PPCASM_OPERAND_TYPE_GPR);\n\t\tcemu_assert_debug(disasm.operand[index].registerIndex == gprIndex);\n\t};\n\n\tauto checkOpImm = [&](size_t index, sint32 imm)\n\t{\n\t\tcemu_assert_debug(disasm.operand[index].type == PPCASM_OPERAND_TYPE_IMM);\n\t\tcemu_assert_debug(disasm.operand[index].immS32 == imm);\n\t};\n\n\tauto checkOpBranchDst = [&](size_t index, sint32 relOffset)\n\t{\n\t\tcemu_assert_debug(disasm.operand[index].type == PPCASM_OPERAND_TYPE_CIMM);\n\t\tcemu_assert_debug(disasm.operand[index].immU32 == 0x10000000 + relOffset);\n\t};\n\n\tauto checkBranchHint = [&](bool isSet)\n\t{\n\t\tcemu_assert_debug(disasm.branchHintBitSet == isSet);\n\t};\n\n\t// addi / subi\n\t_testAsm(0x3863FFFF, \"addi r3, r3, -1\");\n\t_testAsm(0x3863FFFF, \"subi r3, r3, 1\");\n\t_testAsm(0x387E0134, \"addi r3, r30, 0x134\");\n\t_testAsm(0x387E0134, \"subi r3, r30, 0-0x134\");\n\tdisassemble(0x387E0134, PPCASM_OP_ADDI);\n\tcheckOperandMask(true, true, true);\n\tcheckOpGPR(0, 3);\n\tcheckOpGPR(1, 30);\n\tcheckOpImm(2, 0x134);\n\n\t// mulli\n\t_testAsm(0x1D1E0005, \"mulli r8, r30, 5\");\n\tdisassemble(0x1D1E0005, PPCASM_OP_MULLI);\n\tcheckOperandMask(true, true, true);\n\tcheckOpGPR(0, 8);\n\tcheckOpGPR(1, 30);\n\tcheckOpImm(2, 5);\n\n\t// mulli\n\t_testAsm(0x1CFEFFF8, \"mulli r7, r30, 0-(2 + 2 + 2 + 2)\"); // -8\n\tdisassemble(0x1CFEFFF8, PPCASM_OP_MULLI);\n\tcheckOperandMask(true, true, true);\n\tcheckOpGPR(0, 7);\n\tcheckOpGPR(1, 30);\n\tcheckOpImm(2, -8);\n\n\t// subfic\n\t_testAsm(0x2304002F, \"subfic r24, r4, 0x2F\");\n\tdisassemble(0x2304002F, PPCASM_OP_SUBFIC);\n\tcheckOperandMask(true, true, true);\n\tcheckOpGPR(0, 24);\n\tcheckOpGPR(1, 4);\n\tcheckOpImm(2, 0x2F);\n\n\t// fcmpu cr7, f1, f0\n\t_testAsm(0xFF810000, \"fcmpu cr7, f1, f0\");\n\tdisassemble(0xFF810000, PPCASM_OP_FCMPU);\n\tcheckOperandMask(true, true, true);\n\tcheckOpCR(0, 7);\n\tcheckOpFPR(1, 1);\n\tcheckOpFPR(2, 0);\n\n\t// fcmpu cr0, f1, f0\n\t_testAsm(0xFC010000, \"fcmpu cr0, f1, f0\");\n\tdisassemble(0xFC010000, PPCASM_OP_FCMPU);\n\tcheckOperandMask(true, true, true);\n\tcheckOpCR(0, 0);\n\tcheckOpFPR(1, 1);\n\tcheckOpFPR(2, 0);\n\n\t// cmpwi r9, -1\n\t_testAsm(0x2C09FFFF, \"cmpwi r9, -1\");\n\tdisassemble(0x2C09FFFF, PPCASM_OP_CMPWI);\n\tcheckOperandMask(false, true, true);\n\tcheckOpGPR(1, 9);\n\tcheckOpImm(2, -1);\n\t// cmpwi cr7, r9, 0\n\t_testAsm(0x2F890000, \"cmpwi cr7, r9, 0\");\n\tdisassemble(0x2F890000, PPCASM_OP_CMPWI);\n\tcheckOperandMask(true, true, true);\n\tcheckOpCR(0, 7);\n\tcheckOpGPR(1, 9);\n\tcheckOpImm(2, 0);\n\t// cmplwi r3, 0xF\n\t_testAsm(0x2803000F, \"cmplwi r3, 0xF\");\n\tdisassemble(0x2803000F, PPCASM_OP_CMPLWI);\n\tcheckOperandMask(false, true, true);\n\tcheckOpGPR(1, 3);\n\tcheckOpImm(2, 0xF);\n\t// cmpw cr7, r4, r10\n\t_testAsm(0x7F845000, \"cmpw cr7, r4, r10\");\n\tdisassemble(0x7F845000, PPCASM_OP_CMPW);\n\tcheckOperandMask(true, true, true);\n\tcheckOpCR(0, 7);\n\tcheckOpGPR(1, 4);\n\tcheckOpGPR(2, 10);\n\t// cmplw cr7, r31, r9\n\t_testAsm(0x7F9F4840, \"cmplw cr7, r31, r9\");\n\tdisassemble(0x7F9F4840, PPCASM_OP_CMPLW);\n\tcheckOperandMask(true, true, true);\n\tcheckOpCR(0, 7);\n\tcheckOpGPR(1, 31);\n\tcheckOpGPR(2, 9);\n\t// cmplw r24, r28\n\t_testAsm(0x7C18E040, \"cmplw r24, r28\");\n\tdisassemble(0x7C18E040, PPCASM_OP_CMPLW);\n\tcheckOperandMask(false, true, true);\n\tcheckOpGPR(1, 24);\n\tcheckOpGPR(2, 28);\n\n\t// b .+0x18\n\t_testAsm(0x48000018, \"b .+0x18\");\n\t// b 0x10000018\n\t//_testAsm(0x48000018, \"b 0x10000018\");\n\n\t// bgt cr7, .+0x40\n\t_testAsm(0x419D0040, \"bgt cr7, .+0x40\");\n\tdisassemble(0x419D0040, PPCASM_OP_BGT);\n\tcheckOperandMask(true, true);\n\tcheckOpCR(0, 7);\n\tcheckOpBranchDst(1, 0x40);\n\tcheckBranchHint(false);\n\t// bnl cr7, .+0x40 (alias to bgt)\n\t_testAsm(0x419D0040, \"bnl cr7, .+0x40\");\n\t// beq cr7, .+0x14\n\t_testAsm(0x419E0014, \"beq cr7, .+0x14\");\n\tdisassemble(0x419E0014, PPCASM_OP_BEQ);\n\tcheckOperandMask(true, true);\n\tcheckOpCR(0, 7);\n\tcheckOpBranchDst(1, 0x14);\n\tcheckBranchHint(false);\n\t// beq .-0x4C\n\t_testAsm(0x4182FFB4, \"beq .-0x4C\");\n\tdisassemble(0x4182FFB4, PPCASM_OP_BEQ);\n\tcheckOperandMask(true);\n\tcheckOpBranchDst(0, -0x4C);\n\tcheckBranchHint(false);\n\t// beq+ .+8\n\t_testAsm(0x41A20008, \"beq+ .+8\");\n\tdisassemble(0x41A20008, PPCASM_OP_BEQ);\n\tcheckOperandMask(true, false);\n\tcheckOpBranchDst(0, +0x8);\n\tcheckBranchHint(true);\n\n\t// cror\n\t_testAsm(0x4F5DF382, \"cror 4*cr6+eq, 4*cr7+gt, 4*cr7+eq\");\n\t_testAsm(0x4C411B82, \"cror eq, gt, so\");\n\tdisassemble(0x4F5DF382, PPCASM_OP_CROR);\n\tcheckOperandMask(true, true, true);\n\tcheckOpCRBit(0, 6 * 4 + 2);\n\tcheckOpCRBit(1, 7 * 4 + 1);\n\tcheckOpCRBit(2, 7 * 4 + 2);\n\n\t// slw & srw\n\t_testAsm(0x7D202030, \"slw r0, r9, r4\");\n\t_testAsm(0x7D80FC31, \"srw. r0, r12, r31\");\n\tdisassemble(0x7D202030, PPCASM_OP_SLW);\n\tcheckOperandMask(true, true, true);\n\tcheckOpGPR(0, 0);\n\tcheckOpGPR(1, 9);\n\tcheckOpGPR(2, 4);\n\n\t// FADD\n\t_testAsm(0xFC29502A, \"fadd f1, f9, f10\");\n\tdisassemble(0xFC29502A, PPCASM_OP_FADD);\n\tcheckOperandMask(true, true, true);\n\tcheckOpFPR(0, 1);\n\tcheckOpFPR(1, 9);\n\tcheckOpFPR(2, 10);\n\n\t// FSUB\n\t_testAsm(0xFDAB4028, \"fsub f13, f11, f8\");\n\t_testAsm(0xFD0D4828, \"fsub f8, f13, f9\");\n\tdisassemble(0xFD0D4828, PPCASM_OP_FSUB);\n\tcheckOperandMask(true, true, true);\n\tcheckOpFPR(0, 8);\n\tcheckOpFPR(1, 13);\n\tcheckOpFPR(2, 9);\n\n\t// FMUL\n\t_testAsm(0xFD4B0332, \"fmul f10, f11, f12\");\n\tdisassemble(0xFD4B0332, PPCASM_OP_FMUL);\n\tcheckOperandMask(true, true, true);\n\tcheckOpFPR(0, 10);\n\tcheckOpFPR(1, 11);\n\tcheckOpFPR(2, 12);\n\n\t// FDIV\n\t_testAsm(0xFD885824, \"fdiv f12, f8, f11\");\n\tdisassemble(0xFD885824, PPCASM_OP_FDIV);\n\tcheckOperandMask(true, true, true);\n\tcheckOpFPR(0, 12);\n\tcheckOpFPR(1, 8);\n\tcheckOpFPR(2, 11);\n\n\t// FMADD\n\t_testAsm(0xFC2A0A3A, \"fmadd f1, f10, f8, f1\");\n\t_testAsm(0xFC0A0B7A, \"fmadd f0, f10, f13, f1\");\n\t_testAsm(0xFFE0F33A, \"fmadd f31, f0, f12, f30\");\n\tdisassemble(0xFFE0F33A, PPCASM_OP_FMADD);\n\tcheckOperandMask(true, true, true, true);\n\tcheckOpFPR(0, 31);\n\tcheckOpFPR(1, 0);\n\tcheckOpFPR(2, 12);\n\tcheckOpFPR(3, 30);\n\n\t// FNMADDS\n\t_testAsm(0xED8A627E, \"fnmadds f12, f10, f9, f12\");\n\tdisassemble(0xED8A627E, PPCASM_OP_FNMADDS);\n\tcheckOperandMask(true, true, true, true);\n\tcheckOpFPR(0, 12);\n\tcheckOpFPR(1, 10);\n\tcheckOpFPR(2, 9);\n\tcheckOpFPR(3, 12);\n\n\t// still missing test cases: FNMADD, FMADDS\n\n\t// FMSUB\n\t_testAsm(0xFC1C0338, \"fmsub f0, f28, f12, f0\");\n\t_testAsm(0xFD204B38, \"fmsub f9, f0, f12, f9\");\n\tdisassemble(0xFD204B38, PPCASM_OP_FMSUB);\n\tcheckOperandMask(true, true, true, true);\n\tcheckOpFPR(0, 9);\n\tcheckOpFPR(1, 0);\n\tcheckOpFPR(2, 12);\n\tcheckOpFPR(3, 9);\n\n\t// FNMSUB\n\t_testAsm(0xFD7DCB3C, \"fnmsub f11, f29, f12, f25\");\n\tdisassemble(0xFD7DCB3C, PPCASM_OP_FNMSUB);\n\tcheckOperandMask(true, true, true, true);\n\tcheckOpFPR(0, 11);\n\tcheckOpFPR(1, 29);\n\tcheckOpFPR(2, 12);\n\tcheckOpFPR(3, 25);\n\n\t// FMSUBS\n\t_testAsm(0xEE3D5838, \"fmsubs f17, f29, f0, f11\");\n\t_testAsm(0xEDB84AB8, \"fmsubs f13, f24, f10, f9\");\n\tdisassemble(0xEDB84AB8, PPCASM_OP_FMSUBS);\n\tcheckOperandMask(true, true, true, true);\n\tcheckOpFPR(0, 13);\n\tcheckOpFPR(1, 24);\n\tcheckOpFPR(2, 10);\n\tcheckOpFPR(3, 9);\n\n\t// FNMSUBS\n\t_testAsm(0xED4951BC, \"fnmsubs f10, f9, f6, f10\");\n\t_testAsm(0xED253AFC, \"fnmsubs f9, f5, f11, f7\");\n\tdisassemble(0xED253AFC, PPCASM_OP_FNMSUBS);\n\tcheckOperandMask(true, true, true, true);\n\tcheckOpFPR(0, 9);\n\tcheckOpFPR(1, 5);\n\tcheckOpFPR(2, 11);\n\tcheckOpFPR(3, 7);\n\n\t// FRSQRTE\n\t_testAsm(0xFCE06034, \"frsqrte f7, f12\");\n\t_testAsm(0xFCC06834, \"frsqrte f6, f13\");\n\tdisassemble(0xFCC06834, PPCASM_OP_FRSQRTE);\n\tcheckOperandMask(true, true);\n\tcheckOpFPR(0, 6);\n\tcheckOpFPR(1, 13);\n\n\t// FRSP\n\t_testAsm(0xFFA03018, \"frsp f29, f6\");\n\tdisassemble(0xFFA03018, PPCASM_OP_FRSP);\n\tcheckOperandMask(true, true);\n\tcheckOpFPR(0, 29);\n\tcheckOpFPR(1, 6);\n\n\t// FNEG\n\t_testAsm(0xFDA05850, \"fneg f13, f11\");\n\tdisassemble(0xFDA05850, PPCASM_OP_FNEG);\n\tcheckOperandMask(true, true);\n\tcheckOpFPR(0, 13);\n\tcheckOpFPR(1, 11);\n\n\t// FMR\n\t_testAsm(0xFCE06090, \"fmr f7, f12\");\n\tdisassemble(0xFCE06090, PPCASM_OP_FMR);\n\tcheckOperandMask(true, true);\n\tcheckOpFPR(0, 7);\n\tcheckOpFPR(1, 12);\n\n\t// FABS\n\t_testAsm(0xFC200A10, \"fabs f1, f1\");\n\tdisassemble(0xFC200A10, PPCASM_OP_FABS);\n\tcheckOperandMask(true, true);\n\tcheckOpFPR(0, 1);\n\tcheckOpFPR(1, 1);\n\n\t// FCTIWZ\n\t_testAsm(0xFD80401E, \"fctiwz f12, f8\");\n\tdisassemble(0xFD80401E, PPCASM_OP_FCTIWZ);\n\tcheckOperandMask(true, true);\n\tcheckOpFPR(0, 12);\n\tcheckOpFPR(1, 8);\n\n\t// PS_MADD\n\t_testAsm(0x1168637A, \"ps_madd   f11, f8, f13, f12\");\n\tdisassemble(0x1168637A, PPCASM_OP_PS_MADD);\n\tcheckOperandMask(true, true, true, true);\n\tcheckOpFPR(0, 11);\n\tcheckOpFPR(1, 8);\n\tcheckOpFPR(2, 13);\n\tcheckOpFPR(3, 12);\n\n\t// PS_MSUB\n\t_testAsm(0x11A55FF8, \"ps_msub f13, f5, f31, f11\");\n\tdisassemble(0x11A55FF8, PPCASM_OP_PS_MSUB);\n\tcheckOperandMask(true, true, true, true);\n\tcheckOpFPR(0, 13);\n\tcheckOpFPR(1, 5);\n\tcheckOpFPR(2, 31);\n\tcheckOpFPR(3, 11);\n\n\t// PS_NMADD\n\t_testAsm(0x118850FE, \"ps_nmadd f12, f8, f3, f10\");\n\tdisassemble(0x118850FE, PPCASM_OP_PS_NMADD);\n\tcheckOperandMask(true, true, true, true);\n\tcheckOpFPR(0, 12);\n\tcheckOpFPR(1, 8);\n\tcheckOpFPR(2, 3);\n\tcheckOpFPR(3, 10);\n\n\t// PS_NMSUB\n\t_testAsm(0x112832FC, \"ps_nmsub f9, f8, f11, f6\");\n\tdisassemble(0x112832FC, PPCASM_OP_PS_NMSUB);\n\tcheckOperandMask(true, true, true, true);\n\tcheckOpFPR(0, 9);\n\tcheckOpFPR(1, 8);\n\tcheckOpFPR(2, 11);\n\tcheckOpFPR(3, 6);\n\n\t// PS_ADD\n\t_testAsm(0x112A582A, \"ps_add f9, f10, f11\");\n\tdisassemble(0x112A582A, PPCASM_OP_PS_ADD);\n\tcheckOperandMask(true, true, true);\n\tcheckOpFPR(0, 9);\n\tcheckOpFPR(1, 10);\n\tcheckOpFPR(2, 11);\n\n\t// PS_SUB\n\t_testAsm(0x11663828, \"ps_sub f11, f6, f7\");\n\tdisassemble(0x11663828, PPCASM_OP_PS_SUB);\n\tcheckOperandMask(true, true, true);\n\tcheckOpFPR(0, 11);\n\tcheckOpFPR(1, 6);\n\tcheckOpFPR(2, 7);\n\n\t// PS_MUL\n\t_testAsm(0x11680332, \"ps_mul f11, f8, f12\");\n\tdisassemble(0x11680332, PPCASM_OP_PS_MUL);\n\tcheckOperandMask(true, true, true);\n\tcheckOpFPR(0, 11);\n\tcheckOpFPR(1, 8);\n\tcheckOpFPR(2, 12);\n\n\t// PS_DIV\n\t_testAsm(0x10A45824, \"ps_div f5, f4, f11\");\n\tdisassemble(0x10A45824, PPCASM_OP_PS_DIV);\n\tcheckOperandMask(true, true, true);\n\tcheckOpFPR(0, 5);\n\tcheckOpFPR(1, 4);\n\tcheckOpFPR(2, 11);\n\n\t// PS_MERGE10\n\t_testAsm(0x10CC6C20, \"ps_merge00 f6, f12, f13\");\n\tdisassemble(0x10CC6C20, PPCASM_OP_PS_MERGE00);\n\tcheckOperandMask(true, true, true);\n\tcheckOpFPR(0, 6);\n\tcheckOpFPR(1, 12);\n\tcheckOpFPR(2, 13);\n\n\t// random extra tests\n\t_testAsm(0x419D0040, \"bgt cr7, .+0x40\");\n\t_testAsm(0x50AB042E, \"rlwimi r11, r5, 0,16,23\");\n\t_testAsm(0xFF810000, \"fcmpu cr7, f1, f0\");\n\t_testAsm(0xFC010000, \"fcmpu cr0, f1, f0\");\n\t_testAsm(0x7F845000, \"cmpw cr7, r4, r10\");\n\t_testAsm(0x2C090000, \"cmpwi r9, 0\"); // implicit cr0\n\t_testAsm(0x2C090000, \"cmpwi cr0, r9, 0\");\n\t_testAsm(0x2F9E001F, \"cmpwi cr7, r30, 0x1F\");\n\t_testAsm(0x7D573850, \"subf r10, r23, r7\");\n\t_testAsm(0x7D573850, \"sub r10, r7, r23\"); // alias for subf\n\t_testAsm(0x7D862851, \"subf. r12, r6, r5\");\n\t_testAsm(0x7D7C1896, \"mulhw r11, r28, r3\");\n\t_testAsm(0x7D436016, \"mulhwu r10, r3, r12\");\n\t_testAsm(0x7FE318F8, \"nor r3, r31, r3\");\n\t_testAsm(0x7D29F8F8, \"nor r9, r9, r31\");\n\t_testAsm(0x7F26C8F8, \"nor r6, r25, r25\");\n\t_testAsm(0x7F26C8F8, \"not r6, r25\"); // alias for nor where rA == rB\n\t_testAsm(0x7FE4FB78, \"mr r4, r31\"); // alias for or where rA == rB\n\t_testAsm(0x7C7EEAA6, \"mfspr r3, spr958\");\n\t_testAsm(0x7C78E3A6, \"mtspr spr920, r3\");\n\t_testAsm(0x7D6802A6, \"mflr r11\");\n\t_testAsm(0x7E6902A6, \"mfctr r19\");\n\t_testAsm(0x7D430034, \"cntlzw r3, r10\");\n\t_testAsm(0x7C640774, \"extsb r4, r3\");\n\t_testAsm(0x1C8A00B8, \"mulli r4, r10, 0xB8\");\n\t_testAsm(0x1CFEFFF8, \"mulli r7, r30, -8\");\n\t_testAsm(0x1CFE8000, \"mulli r7, r30, -0x8000\");\n\t_testAsm(0x1CFE7FFF, \"mulli r7, r30, 0x7FFF\");\n\t_testAsmFail(\"mulli r7, r30, -0x8001\");\n\t_testAsmFail(\"mulli r7, r30, 0x8000\");\n\t_testAsm(0x38E0FFFF, \"li r7, 0xFFFF\"); // li/lis allows both signed and unsigned 16-bit range\n\t_testAsm(0x38E0FFFF, \"li r7, -1\");\n\t_testAsm(0x38E08000, \"li r7, -0x8000\");\n\t_testAsmFail(\"li r7, -0x8001\");\n\t_testAsmFail(\"li r7, 0xFFFF+1\");\n\n\t// test set 2\n\t_testAsm(0x7c0903a6, \"mtctr     r0\");\n\t_testAsm(0x7c6903a6, \"mtctr     r3\");\n\t_testAsm(0x7d0903a6, \"mtctr     r8\");\n\t_testAsm(0x7d2903a6, \"mtctr     r9\");\n\t_testAsm(0x7c0803a6, \"mtlr      r0\");\n\t_testAsm(0x7c6803a6, \"mtlr      r3\");\n\t_testAsm(0x7c8803a6, \"mtlr      r4\");\n\t_testAsm(0x7c065896, \"mulhw     r0, r6, r11\");\n\t_testAsm(0x7ce85096, \"mulhw     r7, r8, r10\");\n\t_testAsm(0x7d494096, \"mulhw     r10, r9, r8\");\n\t_testAsm(0x7ca4c016, \"mulhwu    r5, r4, r24\");\n\t_testAsm(0x7ce53016, \"mulhwu    r7, r5, r6\");\n\t_testAsm(0x7d373816, \"mulhwu    r9, r23, r7\");\n\t_testAsm(0x7d664816, \"mulhwu    r11, r6, r9\");\n\t_testAsm(0x1d2ae09e, \"mulli     r9, r10, -0x1F62\");\n\t_testAsm(0x1fe900ff, \"mulli     r31, r9, 0xFF\");\n\t_testAsm(0x1ffefffe, \"mulli     r31, r30, -2\");\n\t_testAsm(0x7e4531d6, \"mullw     r18, r5, r6\");\n\t_testAsm(0x7fe429d6, \"mullw     r31, r4, r5\");\n\t_testAsm(0x7d0951d7, \"mullw.    r8, r9, r10\");\n\t_testAsm(0x7f0941d7, \"mullw.    r24, r9, r8\");\n\t_testAsm(0x7c6600d0, \"neg       r3, r6\");\n\t_testAsm(0x7df600d0, \"neg       r15, r22\");\n\t_testAsm(0x7eeb00d0, \"neg       r23, r11\");\n\t_testAsm(0x7ca428f8, \"not       r4, r5\");\n\t_testAsm(0x7df578f8, \"not       r21, r15\");\n\t_testAsm(0x7fe9f8f8, \"not       r9, r31\");\n\t_testAsm(0x7fc83378, \"or        r8, r30, r6\");\n\t_testAsm(0x7de6a379, \"or.       r6, r15, r20\");\n\t_testAsm(0x7f29fb79, \"or.       r9, r25, r31\");\n\t_testAsm(0x7ceafb38, \"orc       r10, r7, r31\");\n\t_testAsm(0x7fbe4338, \"orc       r30, r29, r8\");\n\t_testAsm(0x63a90001, \"ori       r9, r29, 1\");\n\t_testAsm(0x63c3b46e, \"ori       r3, r30, 0xB46E\");\n\t_testAsm(0x63e4ffff, \"ori       r4, r31, 0xFFFF\");\n\t_testAsm(0x650a8000, \"oris      r10, r8, 0x8000\");\n\t_testAsm(0x676c792e, \"oris      r12, r27, 0x792E\");\n\t_testAsm(0x6788ffff, \"oris      r8, r28, 0xFFFF\");\n\t_testAsm(0x67ea3fe0, \"oris      r10, r31, 0x3FE0\");\n\t_testAsm(0x51231fb8, \"rlwimi    r3, r9, 3,30,28\");\n\t_testAsm(0x5249fefe, \"rlwimi    r9, r18, 31,27,31\");\n\t_testAsm(0x52513a20, \"rlwimi    r17, r18, 7,8,16\");\n\t_testAsm(0x53494420, \"rlwimi    r9, r26, 8,16,16\");\n\t_testAsm(0x53657269, \"rlwimi.   r5, r27, 14,9,20\");\n\t_testAsm(0x546906f2, \"rlwinm    r9, r3, 0,27,25\");\n\t_testAsm(0x55284ad6, \"rlwinm    r8, r9, 9,11,11\");\n\t_testAsm(0x57c90428, \"rlwinm    r9, r30, 0,16,20\");\n\t_testAsm(0x57e5d57a, \"rlwinm    r5, r31, 26,21,29\");\n\t_testAsm(0x57ea34b0, \"rlwinm    r10, r31, 6,18,24\");\n\t_testAsm(0x54e1bbb1, \"rlwinm.   r1, r7, 23,14,24\");\n\t_testAsm(0x550707fb, \"rlwinm.   r7, r8, 0,31,29\");\n\t_testAsm(0x552003f1, \"rlwinm.   r0, r9, 0,15,24\");\n\t_testAsm(0x5527022f, \"rlwinm.   r7, r9, 0,8,23\");\n\t_testAsm(0x55270777, \"rlwinm.   r7, r9, 0,29,27\");\n\t_testAsm(0x552a0777, \"rlwinm.   r10, r9, 0,29,27\");\n\t_testAsm(0x552a07b9, \"rlwinm.   r10, r9, 0,30,28\");\n\t_testAsm(0x5d5f583e, \"rotlw     r31, r10, r11\");\n\t_testAsm(0x5eea703e, \"rotlw     r10, r23, r14\");\n\t_testAsm(0x5f0ab03e, \"rotlw     r10, r24, r22\");\n\t_testAsm(0x541a783e, \"rotlwi    r26, r0, 15\");\n\t_testAsm(0x5488383e, \"rotlwi    r8, r4, 7\");\n\t_testAsm(0x5779683e, \"rotlwi    r25, r27, 13\");\n\t_testAsm(0x54e4c83e, \"rotrwi    r4, r7, 7\");\n\t_testAsm(0x7eeaf830, \"slw       r10, r23, r31\");\n\t_testAsm(0x7f68c030, \"slw       r8, r27, r24\");\n\t_testAsm(0x7fe8f030, \"slw       r8, r31, r30\");\n\t_testAsm(0x7f484831, \"slw.      r8, r26, r9\");\n\t_testAsm(0x7f844031, \"slw.      r4, r28, r8\");\n\t_testAsm(0x57e42036, \"slwi      r4, r31, 4\");\n\t_testAsm(0x57e42834, \"slwi      r4, r31, 5\");\n\t_testAsm(0x57f37820, \"slwi      r19, r31, 15\");\n\t_testAsm(0x5488083d, \"slwi.     r8, r4, 1\");\n\t_testAsm(0x552a3033, \"slwi.     r10, r9, 6\");\n\t_testAsm(0x5647083d, \"slwi.     r7, r18, 1\");\n\t_testAsm(0x7c879e30, \"sraw      r7, r4, r19\");\n\t_testAsm(0x7c891e30, \"sraw      r9, r4, r3\");\n\t_testAsm(0x7fca4e30, \"sraw      r10, r30, r9\");\n\t_testAsm(0x7d380e70, \"srawi     r24, r9, 1\");\n\t_testAsm(0x7c79fe71, \"srawi.    r25, r3, 0x1F\");\n\t_testAsm(0x7fb91e71, \"srawi.    r25, r29, 3\");\n\t_testAsm(0x7cc33c30, \"srw       r3, r6, r7\");\n\t_testAsm(0x7d09e430, \"srw       r9, r8, r28\");\n\t_testAsm(0x7d3d4430, \"srw       r29, r9, r8\");\n\t_testAsm(0x5403d97e, \"srwi      r3, r0, 5\");\n\t_testAsm(0x57dc843e, \"srwi      r28, r30, 16\");\n\t_testAsm(0x552a463f, \"srwi.     r10, r9, 24\");\n\t_testAsm(0x5532c9ff, \"srwi.     r18, r9, 7\");\n\t_testAsm(0x57f8f87f, \"srwi.     r24, r31, 1\");\n\t_testAsm(0x9be80201, \"stb       r31, 0x201(r8)\");\n\t_testAsm(0x9bfafffc, \"stb       r31, -4(r26)\");\n\t_testAsm(0x9bfeffff, \"stb       r31, -1(r30)\");\n\t_testAsm(0x9dc3ffff, \"stbu      r14, -1(r3)\");\n\t_testAsm(0x9e55006f, \"stbu      r18, 0x6F(r21)\");\n\t_testAsm(0x9fdc2008, \"stbu      r30, 0x2008(r28)\");\n\t_testAsm(0x7ce521ee, \"stbux     r7, r5, r4\");\n\t_testAsm(0x7d4919ee, \"stbux     r10, r9, r3\");\n\t_testAsm(0x7f6919ee, \"stbux     r27, r9, r3\");\n\t_testAsm(0x7c0531ae, \"stbx      r0, r5, r6\");\n\t_testAsm(0x7d4941ae, \"stbx      r10, r9, r8\");\n\t_testAsm(0x7fdfe9ae, \"stbx      r30, r31, r29\");\n\t_testAsm(0xdb690038, \"stfd      f27, 0x38(r9)\");\n\t_testAsm(0xdb890040, \"stfd      f28, 0x40(r9)\");\n\t_testAsm(0xde230008, \"stfdu     f17, 8(r3)\");\n\t_testAsm(0x7c1235ae, \"stfdx     f0, r18, r6\");\n\t_testAsm(0x7c1f3dae, \"stfdx     f0, r31, r7\");\n\t_testAsm(0x7c1f45ae, \"stfdx     f0, r31, r8\");\n\t_testAsm(0x7c001fae, \"stfiwx    f0, 0, r3\");\n\t_testAsm(0x7c3e4fae, \"stfiwx    f1, r30, r9\");\n\t_testAsm(0x7fa04fae, \"stfiwx    f29, 0, r9\");\n\t_testAsm(0xd008fffc, \"stfs      f0, -4(r8)\");\n\t_testAsm(0xd3ff1604, \"stfs      f31, 0x1604(r31)\");\n\t_testAsm(0xd41e001c, \"stfsu     f0, 0x1C(r30)\");\n\t_testAsm(0x7d87356e, \"stfsux    f12, r7, r6\");\n\t_testAsm(0x7c104d2e, \"stfsx     f0, r16, r9\");\n\t_testAsm(0x7f5d452e, \"stfsx     f26, r29, r8\");\n\t_testAsm(0xb3bf000e, \"sth       r29, 0xE(r31)\");\n\t_testAsm(0xb3f8fffc, \"sth       r31, -4(r24)\");\n\t_testAsm(0xb3fa0000, \"sth       r31, 0(r26)\");\n\t_testAsm(0xb3fd0000, \"sth       r31, 0(r29)\");\n\t_testAsm(0xb528105a, \"sthu      r9, 0x105A(r8)\");\n\t_testAsm(0xb52afffe, \"sthu      r9, -2(r10)\");\n\t_testAsm(0xb53f0002, \"sthu      r9, 2(r31)\");\n\t_testAsm(0x7c69536e, \"sthux     r3, r9, r10\");\n\t_testAsm(0x7c8a3b6e, \"sthux     r4, r10, r7\");\n\t_testAsm(0x7c0ca32e, \"sthx      r0, r12, r20\");\n\t_testAsm(0x7d242b2e, \"sthx      r9, r4, r5\");\n\t_testAsm(0x7fe93b2e, \"sthx      r31, r9, r7\");\n\t_testAsm(0xbdd0b4d0, \"stmw      r14, -0x4B30(r16)\");\n\t_testAsm(0xbed182d1, \"stmw      r22, -0x7D2F(r17)\");\n\t_testAsm(0x7cbb65aa, \"stswi     r5, r27, 0xC\");\n\t_testAsm(0x7cbe05aa, \"stswi     r5, r30, 0\");\n\t_testAsm(0x91348378, \"stw       r9, -0x7C88(r20)\");\n\t_testAsm(0x93e9fddc, \"stw       r31, -0x224(r9)\");\n\t_testAsm(0x93fe45c8, \"stw       r31, 0x45C8(r30)\");\n\t_testAsm(0x7c604d2c, \"stwbrx    r3, 0, r9\");\n\t_testAsm(0x7d20f52c, \"stwbrx    r9, 0, r30\");\n\t_testAsm(0x7fa04d2c, \"stwbrx    r29, 0, r9\");\n\t_testAsm(0x7d20512d, \"stwcx.    r9, 0, r10\");\n\t_testAsm(0x94650208, \"stwu      r3, 0x208(r5)\");\n\t_testAsm(0x953ffffc, \"stwu      r9, -4(r31)\");\n\t_testAsm(0x97fe0208, \"stwu      r31, 0x208(r30)\");\n\t_testAsm(0x7d21196e, \"stwux     r9, r1, r3\");\n\t_testAsm(0x7d23516e, \"stwux     r9, r3, r10\");\n\t_testAsm(0x7d41496e, \"stwux     r10, r1, r9\");\n\t_testAsm(0x7cbc512e, \"stwx      r5, r28, r10\");\n\t_testAsm(0x7d5ce92e, \"stwx      r10, r28, r29\");\n\t_testAsm(0x7ffee92e, \"stwx      r31, r30, r29\");\n\t_testAsm(0x7c1ec050, \"subf      r0, r30, r24\");\n\t_testAsm(0x7fbee050, \"subf      r29, r30, r28\");\n\t_testAsm(0x7fe91850, \"subf      r31, r9, r3\");\n\t_testAsm(0x7c1e5851, \"subf.     r0, r30, r11\");\n\t_testAsm(0x7fc42851, \"subf.     r30, r4, r5\");\n\t_testAsm(0x7fc74851, \"subf.     r30, r7, r9\");\n\t_testAsm(0x7cffd810, \"subfc     r7, r31, r27\");\n\t_testAsm(0x7d053010, \"subfc     r8, r5, r6\");\n\t_testAsm(0x7d093810, \"subfc     r8, r9, r7\");\n\t_testAsm(0x7f884910, \"subfe     r28, r8, r9\");\n\t_testAsm(0x7fe95110, \"subfe     r31, r9, r10\");\n\t_testAsm(0x7fea4910, \"subfe     r31, r10, r9\");\n\t_testAsm(0x20d0b2d1, \"subfic    r6, r16, -0x4D2F\");\n\t_testAsm(0x2109fc02, \"subfic    r8, r9, -0x3FE\");\n\t_testAsm(0x2144001f, \"subfic    r10, r4, 0x1F\");\n\t_testAsm(0x7c04f278, \"xor       r4, r0, r30\");\n\t_testAsm(0x7c08fa78, \"xor       r8, r0, r31\");\n\t_testAsm(0x7c0b4a78, \"xor       r11, r0, r9\");\n\t_testAsm(0x68640008, \"xori      r4, r3, 8\");\n\t_testAsm(0x68652064, \"xori      r5, r3, 0x2064\");\n\t_testAsm(0x692076c3, \"xori      r0, r9, 0x76C3\");\n\t_testAsm(0x6c0a8000, \"xoris     r10, r0, 0x8000\");\n\t_testAsm(0x6c68ffff, \"xoris     r8, r3, 0xFFFF\");\n\t_testAsm(0x6c617267, \"xoris     r1, r3, 0x7267\");\n\t_testAsm(0x6fe98000, \"xoris     r9, r31, 0x8000\");\n\t_testAsm(0x6fe9f000, \"xoris     r9, r31, 0xF000\");\n\t_testAsm(0x6fe9ff00, \"xoris     r9, r31, 0xFF00\");\n\t_testAsm(0x6fe9ffff, \"xoris     r9, r31, 0xFFFF\");\n\n\t// data directives\n\t_testAsmArray({ 0x00, 0x00, 0x00, 0x01 }, \".int 1\");\n\t_testAsmArray({ 0x00, 0x00, 0x00, 0x01, 0x11, 0x22, 0x33, 0x44 }, \".int 1, 0x11223344\");\n\t_testAsmArray({ 0x42, 0xf6, 0x00, 0x00 }, \".float 123.0\");\n\t_testAsmArray({ 0x7f }, \".byte 0x7f\");\n\t_testAsmArray({ 0x74, 0x65, 0x73, 0x74, 0x00 }, \".byte \\\"test\\\"\");\n\t_testAsmArray({ 0x41, 0x42, 0x43, 0x00, 0x74, 0x65, 0x73, 0x74, 0x00 }, \".byte \\\"ABC\\\", \\\"test\\\"\");\n\n}\n\nvoid ppcAsmTest()\n{\n#ifdef CEMU_DEBUG_ASSERT\n\tppcAsmTestDisassembler();\n#endif\n}\n"
  },
  {
    "path": "src/Cemu/PPCAssembler/ppcAssembler.h",
    "content": "#pragma once\n\n#include <boost/container/small_vector.hpp>\n\n#define PPCASM_OPERAND_COUNT\t\t5\n\n#define PPCASM_OPERAND_TYPE_GPR\t\t0 // r0 - r31\n#define PPCASM_OPERAND_TYPE_FPR\t\t1 // f0 - f31\n#define PPCASM_OPERAND_TYPE_SPR\t\t2 // spr0 - spr511\n#define PPCASM_OPERAND_TYPE_IMM\t\t3 // integer constants. E.g. 0x123 \n#define PPCASM_OPERAND_TYPE_MEM\t\t4 // [r0 + 1234]\n#define PPCASM_OPERAND_TYPE_CIMM\t5 // virtual addr of code destination (used for branches)\n#define PPCASM_OPERAND_TYPE_CR\t\t6 // cr0-cr7\n#define PPCASM_OPERAND_TYPE_CR_BIT\t7 // cr bit 0-31. Example display form: '4*cr1+eq'\n#define PPCASM_OPERAND_TYPE_PSQMODE\t8 // single or paired mode control for PSQ_L*/PSQ_ST* instructions\n\nenum PPCASM_OP\n{\n\tPPCASM_OP_UKN,\n\n\tPPCASM_OP_ADDI,\n\tPPCASM_OP_SUBI, // special form of ADDI\n\tPPCASM_OP_ADDIS,\n\tPPCASM_OP_ADDIC,\n\tPPCASM_OP_ADDIC_,\n\n\tPPCASM_OP_ADD,\n\tPPCASM_OP_ADD_,\n\tPPCASM_OP_SUBF,\n\tPPCASM_OP_SUBF_,\n\tPPCASM_OP_SUBFC,\n\tPPCASM_OP_SUBFC_,\n\tPPCASM_OP_SUBFE,\n\tPPCASM_OP_SUBFE_,\n\tPPCASM_OP_SUBFIC,\n\n\tPPCASM_OP_SUB, // alias mnemonic for subf with second and third operand swapped\n\tPPCASM_OP_SUB_,\n\n\tPPCASM_OP_MULLI,\n\tPPCASM_OP_MULLW,\n\tPPCASM_OP_MULLW_,\n\tPPCASM_OP_MULHW,\n\tPPCASM_OP_MULHW_,\n\tPPCASM_OP_MULHWU,\n\tPPCASM_OP_MULHWU_,\n\n\tPPCASM_OP_DIVW,\n\tPPCASM_OP_DIVW_,\n\tPPCASM_OP_DIVWU,\n\tPPCASM_OP_DIVWU_,\n\n\tPPCASM_OP_AND,\n\tPPCASM_OP_AND_,\n\tPPCASM_OP_ANDC,\n\tPPCASM_OP_ANDC_,\n\tPPCASM_OP_OR,\n\tPPCASM_OP_OR_,\n\tPPCASM_OP_ORC,\n\tPPCASM_OP_XOR,\n\tPPCASM_OP_NOR,\n\tPPCASM_OP_NOR_,\n\tPPCASM_OP_NOT, // alias to NOR\n\tPPCASM_OP_NOT_,\n\tPPCASM_OP_NEG,\n\tPPCASM_OP_NEG_,\n\tPPCASM_OP_ANDI_,\n\tPPCASM_OP_ANDIS_,\n\tPPCASM_OP_ORI,\n\tPPCASM_OP_ORIS,\n\tPPCASM_OP_XORI,\n\tPPCASM_OP_XORIS,\n\tPPCASM_OP_CNTLZW,\n\tPPCASM_OP_EXTSB,\n\tPPCASM_OP_EXTSH,\n\tPPCASM_OP_CNTLZW_,\n\tPPCASM_OP_EXTSB_,\n\tPPCASM_OP_EXTSH_,\n\tPPCASM_OP_SRAW,\n\tPPCASM_OP_SRAW_,\n\tPPCASM_OP_SRAWI,\n\tPPCASM_OP_SRAWI_,\n\tPPCASM_OP_SLW,\n\tPPCASM_OP_SLW_,\n\tPPCASM_OP_SRW,\n\tPPCASM_OP_SRW_,\n\tPPCASM_OP_RLWINM,\n\tPPCASM_OP_RLWINM_,\n\tPPCASM_OP_RLWIMI,\n\tPPCASM_OP_RLWIMI_,\n\n\t// rlwinm extended mnemonics\n\tPPCASM_OP_EXTLWI,\n\tPPCASM_OP_EXTLWI_,\n\tPPCASM_OP_EXTRWI,\n\tPPCASM_OP_EXTRWI_,\n\n\tPPCASM_OP_ROTLWI,\n\tPPCASM_OP_ROTLWI_,\n\tPPCASM_OP_ROTRWI,\n\tPPCASM_OP_ROTRWI_,\n\n\tPPCASM_OP_SLWI,\n\tPPCASM_OP_SLWI_,\n\tPPCASM_OP_SRWI,\n\tPPCASM_OP_SRWI_,\n\tPPCASM_OP_CLRLWI,\n\tPPCASM_OP_CLRLWI_,\n\tPPCASM_OP_CLRRWI,\n\tPPCASM_OP_CLRRWI_,\n\n\t// rlwimi extended mnemonics\n\t//PPCASM_OP_INSLWI, rlwimi\n\t//PPCASM_OP_INSLWI_, rlwimi\n\t//PPCASM_OP_INSRWI, rlwimi\n\t//PPCASM_OP_INSRWI_, rlwimi\n\n\t// rlwnm extended mnemonics\n\tPPCASM_OP_RLWNM,\n\tPPCASM_OP_RLWNM_,\n\tPPCASM_OP_ROTLW,\n\tPPCASM_OP_ROTLW_,\n\n\tPPCASM_OP_CMPWI,\n\tPPCASM_OP_CMPLWI,\n\n\tPPCASM_OP_CMPW,\n\tPPCASM_OP_CMPLW,\n\n\tPPCASM_OP_MR,\n\tPPCASM_OP_MR_,\n\n\tPPCASM_OP_MFSPR,\n\tPPCASM_OP_MTSPR,\n\n\tPPCASM_OP_LMW,\n\tPPCASM_OP_LWZ,\n\tPPCASM_OP_LWZU,\n\tPPCASM_OP_LWZX,\n\tPPCASM_OP_LWZUX,\n\tPPCASM_OP_LHZ,\n\tPPCASM_OP_LHZU,\n\tPPCASM_OP_LHZX,\n\tPPCASM_OP_LHZUX,\n\tPPCASM_OP_LHA,\n\tPPCASM_OP_LHAU,\n\tPPCASM_OP_LHAX,\n\tPPCASM_OP_LHAUX,\n\tPPCASM_OP_LBZ,\n\tPPCASM_OP_LBZU,\n\tPPCASM_OP_LBZX,\n\tPPCASM_OP_LBZUX,\n\n\tPPCASM_OP_STMW,\n\tPPCASM_OP_STW,\n\tPPCASM_OP_STWU,\n\tPPCASM_OP_STWX,\n\tPPCASM_OP_STWUX,\n\tPPCASM_OP_STH,\n\tPPCASM_OP_STHU,\n\tPPCASM_OP_STHX,\n\tPPCASM_OP_STHUX,\n\tPPCASM_OP_STB,\n\tPPCASM_OP_STBU,\n\tPPCASM_OP_STBX,\n\tPPCASM_OP_STBUX,\n\tPPCASM_OP_STWBRX,\n\tPPCASM_OP_STHBRX,\n\tPPCASM_OP_STSWI,\n\tPPCASM_OP_LWARX,\n\tPPCASM_OP_STWCX_,\n\n\tPPCASM_OP_B,\n\tPPCASM_OP_BA,\n\tPPCASM_OP_BL,\n\tPPCASM_OP_BLA,\n\n\tPPCASM_OP_BC,\n\tPPCASM_OP_BNE,\n\tPPCASM_OP_BEQ,\n\tPPCASM_OP_BGE,\n\tPPCASM_OP_BGT,\n\tPPCASM_OP_BLT,\n\tPPCASM_OP_BLE,\n\tPPCASM_OP_BDZ,\n\tPPCASM_OP_BDNZ,\n\n\tPPCASM_OP_BLR,\n\tPPCASM_OP_BLTLR, // less\n\tPPCASM_OP_BLELR, // less or equal\n\tPPCASM_OP_BEQLR, // equal\n\tPPCASM_OP_BGELR, // greater or equal\n\tPPCASM_OP_BGTLR, // greater\n\tPPCASM_OP_BNELR, // not equal\n\n\tPPCASM_OP_BCTR,\n\tPPCASM_OP_BCTRL,\n\n\t// CR\n\tPPCASM_OP_CROR,\n\tPPCASM_OP_CRORC,\n\tPPCASM_OP_CRXOR,\n\tPPCASM_OP_CREQV,\n\tPPCASM_OP_CRNOR,\n\tPPCASM_OP_CRAND,\n\tPPCASM_OP_CRNAND,\n\tPPCASM_OP_CRANDC,\n\tPPCASM_OP_CRSET, // simplified mnemonic for CREQV\n\tPPCASM_OP_CRCLR, // simplified mnemonic for CRXOR\n\tPPCASM_OP_CRMOVE, // simplified mnemonic for CROR\n\tPPCASM_OP_CRNOT, // simplified mnemonic for CRNOR\n\n\t// floating point load/store\n\tPPCASM_OP_LFS,\n\tPPCASM_OP_LFSU,\n\tPPCASM_OP_LFSX,\n\tPPCASM_OP_LFSUX,\n\tPPCASM_OP_LFD,\n\tPPCASM_OP_LFDU,\n\tPPCASM_OP_LFDX,\n\tPPCASM_OP_LFDUX,\n\n\tPPCASM_OP_STFS,\n\tPPCASM_OP_STFSU,\n\tPPCASM_OP_STFSX,\n\tPPCASM_OP_STFSUX,\n\tPPCASM_OP_STFD,\n\tPPCASM_OP_STFDU,\n\tPPCASM_OP_STFDX,\n\tPPCASM_OP_STFDUX,\n\n\tPPCASM_OP_STFIWX,\n\n\t// FP\n\tPPCASM_OP_FMR,\n\tPPCASM_OP_FABS,\n\tPPCASM_OP_FNEG,\n\tPPCASM_OP_FRSP,\n\tPPCASM_OP_FRSQRTE,\n\tPPCASM_OP_FADD,\n\tPPCASM_OP_FADDS,\n\tPPCASM_OP_FSUB,\n\tPPCASM_OP_FSUBS,\n\tPPCASM_OP_FMUL,\n\tPPCASM_OP_FMULS,\n\tPPCASM_OP_FDIV,\n\tPPCASM_OP_FDIVS,\n\n\tPPCASM_OP_FMADD,\n\tPPCASM_OP_FMADDS,\n\tPPCASM_OP_FNMADD,\n\tPPCASM_OP_FNMADDS,\n\tPPCASM_OP_FMSUB,\n\tPPCASM_OP_FMSUBS,\n\tPPCASM_OP_FNMSUB,\n\tPPCASM_OP_FNMSUBS,\n\n\tPPCASM_OP_FCTIWZ,\n\n\tPPCASM_OP_FCMPU,\n\tPPCASM_OP_FCMPO,\n\n\t// PS\n\tPPCASM_OP_PS_MERGE00,\n\tPPCASM_OP_PS_MERGE01,\n\tPPCASM_OP_PS_MERGE10,\n\tPPCASM_OP_PS_MERGE11,\n\n\tPPCASM_OP_PS_ADD,\n\tPPCASM_OP_PS_SUB,\n\tPPCASM_OP_PS_DIV,\n\tPPCASM_OP_PS_MUL,\n\n\tPPCASM_OP_PS_MADD,\n\tPPCASM_OP_PS_MSUB,\n\tPPCASM_OP_PS_NMADD,\n\tPPCASM_OP_PS_NMSUB,\n\n\t// cache & misc\n\tPPCASM_OP_ISYNC,\n\n\t// extended mnemonics\n\tPPCASM_OP_NOP, // ORI\n\tPPCASM_OP_LI, // ADDI\n\tPPCASM_OP_LIS, // ADDIS\n\tPPCASM_OP_MFLR, // MFSPR\n\tPPCASM_OP_MTLR, // MTSPR\n\tPPCASM_OP_MFCTR, // MFSPR\n\tPPCASM_OP_MTCTR, // MTSPR\n};\n\nstruct PPCDisassemblerOperand\n{\n\tuint8 type;\n\tuint16 registerIndex;\n\tunion\n\t{\n\t\tsint32 immS32;\n\t\tuint32 immU32;\n\t};\n\tbool isSignedImm;\n\tuint8 immWidth; // in bits. E.g. 16 for ADDI\n};\n\nstruct PPCDisassembledInstruction\n{\n\t// output\n\tuint32 ppcAsmCode;\n\tuint8 operandMask;\n\tPPCDisassemblerOperand operand[PPCASM_OPERAND_COUNT];\n\t// conditional branches\n\tbool branchHintBitSet{false};\n};\n\nconst char* ppcAssembler_getInstructionName(uint32 ppcAsmOp);\n\nvoid ppcAssembler_disassemble(uint32 virtualAddress, uint32 opcode, PPCDisassembledInstruction* disInstr);\n\nenum class PPCASM_RELOC\n{\n\t// code\n\tU32_MASKED_IMM,\n\tBRANCH_S16,\n\tBRANCH_S26,\n\t// data constants\n\tFLOAT, // 4 byte float data\n\tDOUBLE, // 8 byte double precision float data\n\tU32, // 4 byte unsigned integer\n\tU16, // 2 byte unsigned integer\n\tU8, // 1 byte unsigned integer\n\n};\n\nstruct PPCAssemblerReloc\n{\n\tPPCAssemblerReloc(PPCASM_RELOC relocType, std::string expression, uint32 byteOffset, uint8 bitOffset, uint8 bitCount) : m_relocType(relocType), m_expression(expression), m_byteOffset(byteOffset), m_bitOffset(bitOffset), m_bitCount(bitCount) {};\n\tPPCASM_RELOC m_relocType;\n\tstd::string m_expression;\n\tuint32 m_byteOffset;\n\tuint8 m_bitOffset;\n\tuint8 m_bitCount;\n\tbool m_isApplied{};\n\tbool isApplied() { return m_isApplied; };\n\tvoid setApplied() { m_isApplied = true; };\n};\n\nstruct PPCAssemblerInOut\n{\n\t// in\n\tuint32 virtualAddress;\n\tbool forceNoAlignment{}; // if set, alignment will always be set to 1 (even for .align directive!)\n\t// out\n\tboost::container::small_vector<uint8, 16> outputData;\n\tstd::vector<PPCAssemblerReloc> list_relocs;\n\tstd::string errorMsg;\n\tuint32 alignmentRequirement{}; // alignment requirement, 0 if none\n\tuint32 alignmentPaddingSize{}; // number of bytes to fill with alignment padding before instruction\n\tuint32 virtualAddressAligned{}; // effective virtualAddress\n};\n\nbool ppcAssembler_assembleSingleInstruction(char const* text, PPCAssemblerInOut* ctx);\n\nstatic uint32 ppcAssembler_generateMaskRLW(int MB, int ME)\n{\n\tuint32 maskMB = 0xFFFFFFFF >> MB;\n\tuint32 maskME = 0xFFFFFFFF << (31 - ME);\n\tuint32 mask = (MB <= ME) ? maskMB & maskME : maskMB | maskME;\n\treturn mask;\n}"
  },
  {
    "path": "src/Cemu/Tools/DownloadManager/DownloadManager.cpp",
    "content": "#include \"Cemu/Tools/DownloadManager/DownloadManager.h\"\n\n#include \"Cafe/Account/Account.h\"\n#include \"util/crypto/md5.h\"\n#include \"Cafe/TitleList/TitleId.h\"\n#include \"Common/FileStream.h\"\n#include \"Cemu/FileCache/FileCache.h\"\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/ThreadPool/ThreadPool.h\"\n#include \"util/helpers/enum_array.hpp\"\n\n#include \"Cafe/Filesystem/FST/FST.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n\n#include <cinttypes>\n#include <charconv>\n#include <curl/curl.h>\n#include <pugixml.hpp>\n\n#include \"WindowSystem.h\"\n\n#include \"Cemu/napi/napi.h\"\n#include \"util/helpers/Serializer.h\"\n\nFileCache* s_nupFileCache = nullptr;\n\n/* version list */\n\nvoid DownloadManager::downloadTitleVersionList()\n{\n\tif (m_hasTitleVersionList)\n\t\treturn;\n\tNAPI::AuthInfo authInfo = GetAuthInfo(false);\n\tauto versionListVersionResult = NAPI::TAG_GetVersionListVersion(authInfo);\n\tif (!versionListVersionResult.isValid)\n\t\treturn;\n\tauto versionListResult = TAG_GetVersionList(authInfo, versionListVersionResult.fqdnURL, versionListVersionResult.version);\n\tif (!versionListResult.isValid)\n\t\treturn;\n\tm_titleVersionList = versionListResult.titleVersionList;\n\tm_hasTitleVersionList = true;\n}\n\n// grab latest version from TAG version list. Returns false if titleId is not found in the list\nbool DownloadManager::getTitleLatestVersion(TitleId titleId, uint16& version)\n{\n\tauto titleVersionAvailability = m_titleVersionList.find(titleId);\n\tif (titleVersionAvailability == m_titleVersionList.end())\n\t\treturn false;\n\tversion = titleVersionAvailability->second;\n\treturn true;\n}\n\n/* helper method to generate list of owned base titles */\n\nDownloadManager::TitleInstallState::TitleInstallState(DownloadManager* dlMgr, uint64 titleId) : titleId(titleId)\n{\n\tuint16 vers;\t\n\tif (CafeTitleList::HasTitle(titleId, vers))\n\t{\n\t\tisInstalled = true;\n\t\tinstalledTitleVersion = vers;\n\t}\n\telse\n\t{\n\t\tisInstalled = false;\n\t\tinstalledTitleVersion = 0;\n\t}\n\tinstalledTicketVersion = 0;\n\t// for DLC we also retrieve the ticket version from the installed title.tik\n\t// todo - avoid file reads here due to stalling the UI thread\n\tif (TitleIdParser(titleId).GetType() == TitleIdParser::TITLE_TYPE::AOC)\n\t{\n\t\tconst auto ticketPath = ActiveSettings::GetMlcPath(L\"usr/title/{:08x}/{:08x}/code/title.tik\", (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF));\n\t\tuint32 tikFileSize = 0;\n\t\tFileStream* fileStream = FileStream::openFile2(ticketPath);\n\t\tif (fileStream)\n\t\t{\n\t\t\tstd::vector<uint8> tikData;\n\t\t\tfileStream->extract(tikData);\n\t\t\tNCrypto::ETicketParser eTicket;\n\t\t\tif (eTicket.parse(tikData.data(), tikData.size()))\n\t\t\t\tinstalledTicketVersion = eTicket.GetTicketVersion();\n\t\t\tdelete fileStream;\n\t\t}\n\t}\n}\n\nDownloadManager::TitleDownloadAvailableState::TitleDownloadAvailableState(DownloadManager* dlMgr, uint64 titleId) : TitleInstallState(dlMgr, titleId)\n{\n\t// get latest available version of this title (from the TAG version list)\n\tuint16 vers;\n\tif (dlMgr->getTitleLatestVersion(titleId, vers))\n\t{\n\t\tisUpdateAvailable = true;\n\t\tavailableTitleVersion = vers;\n\t}\n\telse\n\t{\n\t\tisUpdateAvailable = false;\n\t\tavailableTitleVersion = 0;\n\t}\n};\n\nstd::set<DownloadManager::TitleInstallState> DownloadManager::getOwnedTitleList()\n{\n\tstd::set<DownloadManager::TitleInstallState> ownedTitleList;\n\t// add installed games and DLC\n\tstd::vector<TitleId> installedTitleIds = CafeTitleList::GetAllTitleIds();\n\tfor (auto& itr : installedTitleIds)\n\t{\n\t\tTitleIdParser titleIdParser(itr);\n\t\tauto titleType = titleIdParser.GetType();\n\t\tif (titleType == TitleIdParser::TITLE_TYPE::BASE_TITLE ||\n\t\t\ttitleType == TitleIdParser::TITLE_TYPE::BASE_TITLE_DEMO ||\n\t\t\ttitleType == TitleIdParser::TITLE_TYPE::SYSTEM_OVERLAY_TITLE)\n\t\t{\n\t\t\townedTitleList.emplace(this, itr);\n\t\t}\n\t}\n\t// add ticket cache\n\tfor (auto& itr : m_ticketCache)\n\t{\n\t\tTitleIdParser titleIdParser(itr.titleId);\n\t\tauto titleType = titleIdParser.GetType();\n\t\tif (titleType == TitleIdParser::TITLE_TYPE::BASE_TITLE ||\n\t\t\ttitleType == TitleIdParser::TITLE_TYPE::BASE_TITLE_DEMO ||\n\t\t\ttitleType == TitleIdParser::TITLE_TYPE::SYSTEM_OVERLAY_TITLE ||\n\t\t\ttitleType == TitleIdParser::TITLE_TYPE::AOC)\n\t\t{\n\t\t\townedTitleList.emplace(this, itr.titleId);\n\t\t}\n\t}\n\n\treturn ownedTitleList;\n}\n\nstd::set<DownloadManager::TitleDownloadAvailableState> DownloadManager::getFullDownloadList()\n{\n\tstd::set<DownloadManager::TitleDownloadAvailableState> fullList;\n\t// get list of owned titles\n\tstd::set<DownloadManager::TitleInstallState> ownedTitleList = getOwnedTitleList();\n\t// add each owned title, but also check for separate updates if available\n\tfor (auto& itr : ownedTitleList)\n\t{\n\t\tTitleIdParser titleIdParser(itr.titleId);\n\t\tfullList.emplace(this, itr.titleId);\n\t\tif (titleIdParser.CanHaveSeparateUpdateTitleId())\n\t\t{\n\t\t\tuint64 updateTitleId = titleIdParser.GetSeparateUpdateTitleId();\n\t\t\tuint16 tempVers;\n\t\t\tif (getTitleLatestVersion(updateTitleId, tempVers))\n\t\t\t\tfullList.emplace(this, updateTitleId);\n\t\t}\n\t}\n\treturn fullList;\n}\n\n/* connect */\n\nstruct StoredTokenInfo : public SerializerHelper\n{\n\tbool serializeImpl(MemStreamWriter& streamWriter)\n\t{\n\t\tstreamWriter.writeBE<uint8>(0);\n\t\tstreamWriter.writeBE<std::string>(accountId);\n\t\tstreamWriter.writeBE<std::string>(deviceToken);\n\t\treturn true;\n\t}\n\n\tbool deserializeImpl(MemStreamReader& streamReader)\n\t{\n\t\tauto version = streamReader.readBE<uint8>();\n\t\tif (version != 0)\n\t\t\treturn false;\n\t\taccountId = streamReader.readBE<std::string>();\n\t\tdeviceToken = streamReader.readBE<std::string>();\n\t\treturn !streamReader.hasError();\n\t}\n\npublic:\n\tstd::string accountId;\n\tstd::string deviceToken;\n};\n\nbool DownloadManager::_connect_refreshIASAccountIdAndDeviceToken()\n{\n\tNAPI::AuthInfo authInfo = GetAuthInfo(false);\n\t// query IAS/ECS account id and device token (if not cached)\n\tauto rChallenge = NAPI::IAS_GetChallenge(authInfo);\n\tif (rChallenge.apiError != NAPI_RESULT::SUCCESS)\n\t\treturn false;\n\tauto rRegistrationInfo = NAPI::IAS_GetRegistrationInfo_QueryInfo(authInfo, rChallenge.challenge);\n\tif (rRegistrationInfo.apiError != NAPI_RESULT::SUCCESS)\n\t\treturn false;\n\tm_iasToken.serviceAccountId = rRegistrationInfo.accountId;\n\tm_iasToken.deviceToken = rRegistrationInfo.deviceToken;\n\t// store to cache\n\tStoredTokenInfo storedTokenInfo;\n\tstoredTokenInfo.accountId = rRegistrationInfo.accountId;\n\tstoredTokenInfo.deviceToken = rRegistrationInfo.deviceToken;\n\tstd::vector<uint8> serializedData;\n\tif (!storedTokenInfo.serialize(serializedData))\n\t\treturn false;\n\ts_nupFileCache->AddFileAsync({ fmt::format(\"{}/token_info\", m_authInfo.cachefileName) }, serializedData.data(), serializedData.size());\n\treturn true;\n}\n\nbool DownloadManager::_connect_queryAccountStatusAndServiceURLs()\n{\n\tNAPI::AuthInfo authInfo = GetAuthInfo(true);\n\tNAPI::NAPI_ECSGetAccountStatus_Result accountStatusResult = NAPI::ECS_GetAccountStatus(authInfo);\n\tif (accountStatusResult.apiError != NAPI_RESULT::SUCCESS)\n\t{\n\t\tcemuLog_log(LogType::Force, \"ECS - Failed to query account status (error: {0} {1})\", accountStatusResult.apiError, accountStatusResult.serviceError);\n\t\treturn false;\n\t}\n\tif (accountStatusResult.accountStatus == NAPI::NAPI_ECSGetAccountStatus_Result::AccountStatus::UNREGISTERED)\n\t{\n\t\tcemuLog_log(LogType::Force, fmt::format(\"ECS - Account is not registered\"));\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// constructor for ticket cache entry\nDownloadManager::ETicketInfo::ETicketInfo(SOURCE source, uint64 ticketId, uint32 ticketVersion, std::vector<uint8>& eTicket)\n\t: source(source), ticketId(ticketId), ticketVersion(ticketVersion), \n\teTicket(eTicket)\n{\n\tNCrypto::ETicketParser eTicketParser;\n\tif (!eTicketParser.parse(eTicket.data(), eTicket.size()))\n\t{\n\t\ttitleId = (uint64)-1;\n\t\treturn;\n\t}\n\n\tcemu_assert_debug(!eTicketParser.IsPersonalized()); // ticket should have been depersonalized already\n\ttitleId = eTicketParser.GetTitleId();\n\tticketVersion = eTicketParser.GetTicketVersion();\n\tcemu_assert_debug(ticketId == eTicketParser.GetTicketId());\n\tcemu_assert_debug(ticketVersion == eTicketParser.GetTicketVersion());\n}\n\nDownloadManager::ETicketInfo::ETicketInfo(SOURCE source, uint64 ticketId, uint32 ticketVersion, std::vector<uint8>& eTicket, std::vector<std::vector<uint8>>& eTicketCerts)\n\t: ETicketInfo(source, ticketId, ticketVersion, eTicket)\n{\n\tthis->eTicketCerts = eTicketCerts;\n}\n\nvoid DownloadManager::ETicketInfo::GetTitleKey(NCrypto::AesKey& key)\n{\n\tNCrypto::ETicketParser eTicketParser;\n\tcemu_assert_debug(eTicketParser.parse(eTicket.data(), eTicket.size()));\n\teTicketParser.GetTitleKey(key);\n}\n\nvoid DownloadManager::loadTicketCache()\n{\n\tm_ticketCache.clear();\n\tcemu_assert_debug(m_ticketCache.empty());\n\tstd::vector<uint8> ticketCacheBlob;\t\n\tif (!s_nupFileCache->GetFile({ fmt::format(\"{}/eticket_cache\", m_authInfo.cachefileName) }, ticketCacheBlob))\n\t\treturn;\n\tMemStreamReader memReader(ticketCacheBlob.data(), ticketCacheBlob.size());\n\tuint8 version = memReader.readBE<uint8>();\n\tif (version != 1)\n\t\treturn; // unsupported version\n\tuint32 numTickets = memReader.readBE<uint32>();\n\tfor (uint32 i = 0; i < numTickets; i++)\n\t{\n\t\tif (memReader.hasError())\n\t\t{\n\t\t\tm_ticketCache.clear();\n\t\t\treturn;\n\t\t}\n\t\tETicketInfo::SOURCE source = (ETicketInfo::SOURCE)memReader.readBE<uint8>();\n\t\tif (source != ETicketInfo::SOURCE::ECS_TICKET && source != ETicketInfo::SOURCE::PUBLIC_TICKET)\n\t\t{\n\t\t\tm_ticketCache.clear();\n\t\t\treturn;\n\t\t}\n\t\tuint64 ticketId = memReader.readBE<uint64>();\n\t\tuint64 ticketVersion = memReader.readBE<uint32>();\n\t\tstd::vector<uint8> eTicketData = memReader.readPODVector<uint8>();\n\t\tstd::vector<std::vector<uint8>> eTicketCerts;\n\t\tuint8 certCount = memReader.readBE<uint8>();\n\t\tfor (uint32 c = 0; c < certCount; c++)\n\t\t\teTicketCerts.emplace_back(memReader.readPODVector<uint8>());\n\t\tif (memReader.hasError())\n\t\t{\n\t\t\tm_ticketCache.clear();\n\t\t\treturn;\n\t\t}\n\t\tm_ticketCache.emplace_back(source, ticketId, ticketVersion, eTicketData, eTicketCerts);\n\t}\n}\n\nvoid DownloadManager::storeTicketCache()\n{\n\tMemStreamWriter memWriter(1024*32);\n\tmemWriter.writeBE<uint8>(1); // version\n\tmemWriter.writeBE<uint32>((uint32)m_ticketCache.size());\n\tfor (auto& eTicket : m_ticketCache)\n\t{\n\t\tmemWriter.writeBE<uint8>((uint8)eTicket.source);\n\t\tmemWriter.writeBE<uint64>(eTicket.ticketId);\n\t\tmemWriter.writeBE<uint32>(eTicket.ticketVersion);\n\t\tmemWriter.writePODVector(eTicket.eTicket);\n\t\tmemWriter.writeBE<uint8>(eTicket.eTicketCerts.size());\n\t\tfor (auto& cert : eTicket.eTicketCerts)\n\t\t\tmemWriter.writePODVector(cert);\n\t}\n\tauto serializedBlob = memWriter.getResult();\n\ts_nupFileCache->AddFileAsync({ fmt::format(\"{}/eticket_cache\", m_authInfo.cachefileName) }, serializedBlob.data(), serializedBlob.size());\n}\n\nbool DownloadManager::syncAccountTickets()\n{\n\tNAPI::AuthInfo authInfo = GetAuthInfo(true);\n\t// query TIV list from server\n\tNAPI::NAPI_ECSAccountListETicketIds_Result resultTicketIds = NAPI::ECS_AccountListETicketIds(authInfo);\n\tif (!resultTicketIds.isValid())\n\t\treturn false;\n\n\t// download uncached tickets\n\tsize_t count = resultTicketIds.tivs.size();\n\tsize_t index = 0;\n\tfor (auto& tiv : resultTicketIds.tivs)\n\t{\n\t\tindex++;\n\t\tstd::string msg = _tr(\"Downloading account ticket\");\n\t\tmsg.append(fmt::format(\" {0}/{1}\", index, count));\n\t\tsetStatusMessage(msg, DLMGR_STATUS_CODE::CONNECTING);\n\t\t// skip if already cached\n\t\tETicketInfo* cachedTicket = findTicketByTicketId(tiv.ticketId);\n\t\tif (cachedTicket)\n\t\t{\n\t\t\tif(cachedTicket->ticketVersion == tiv.ticketVersion)\n\t\t\t\tcontinue;\n\t\t\t// ticket version mismatch, redownload\n\t\t\tdeleteTicketByTicketId(tiv.ticketId);\n\t\t}\n\t\t// get ECS ticket\n\t\tauto resultETickets = NAPI::ECS_AccountGetETickets(authInfo, tiv.ticketId);\n\t\tif (!resultETickets.isValid())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"SyncTicketCache: Account ETicket invalid\");\n\t\t\tcontinue;\n\t\t}\n\t\t// verify ticket integrity\n\t\tNCrypto::ETicketParser eTicketParser;\n\t\tif (!eTicketParser.parse(resultETickets.eTickets.data(), resultETickets.eTickets.size()))\n\t\t\tcontinue;\n\t\tuint64 titleId = eTicketParser.GetTitleId();\n\t\tcemu_assert_debug(eTicketParser.GetTicketId() == tiv.ticketId);\n\t\tcemu_assert_debug(eTicketParser.GetTicketVersion() == tiv.ticketVersion);\n\n\t\t// depersonalize the ticket\n\t\tif (eTicketParser.IsPersonalized())\n\t\t{\n\t\t\tNCrypto::ECCPrivKey privKey = NCrypto::ECCPrivKey::getDeviceCertPrivateKey();\n\t\t\tif (!eTicketParser.Depersonalize(resultETickets.eTickets.data(), resultETickets.eTickets.size(), m_authInfo.deviceId, privKey))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"DownloadManager: Failed to depersonalize ticket\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// reparse\n\t\t\tcemu_assert(eTicketParser.parse(resultETickets.eTickets.data(), resultETickets.eTickets.size()));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"DownloadManager: Unexpected result. ECS ticket not personalized\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tETicketInfo eTicket(ETicketInfo::SOURCE::ECS_TICKET, tiv.ticketId, tiv.ticketVersion, resultETickets.eTickets, resultETickets.certs);\n\t\tm_ticketCache.emplace_back(eTicket);\n\t}\n\treturn true;\n}\n\nbool DownloadManager::syncSystemTitleTickets()\n{\n\tsetStatusMessage(_tr(\"Downloading system tickets...\"), DLMGR_STATUS_CODE::CONNECTING);\n\tNAPI::AuthInfo authInfo = GetAuthInfo(true);\n\tauto querySystemTitleTicket = [&](uint64 titleId) -> void\n\t{\n\t\t// check if cached already\n\t\t// todo - how do we know which version to query? System titles seem to use hashes?\n\t\tif (findFirstTicketByTitleId(titleId))\n\t\t\treturn;\n\t\t// request ticket\n\t\tauto resultCommonETicket = NAPI::NUS_GetSystemCommonETicket(authInfo, titleId);\n\t\tif (!resultCommonETicket.isValid())\n\t\t\treturn;\n\t\t// parse and validate ticket\n\t\tNCrypto::ETicketParser eTicketParser;\n\t\tif (!eTicketParser.parse(resultCommonETicket.eTicket.data(), resultCommonETicket.eTicket.size()))\n\t\t\treturn;\n\t\tif (eTicketParser.GetTitleId() != titleId)\n\t\t\treturn;\n\t\tif (eTicketParser.IsPersonalized())\n\t\t\treturn;\n\t\t// add to eTicket cache\n\t\tETicketInfo eTicket(ETicketInfo::SOURCE::PUBLIC_TICKET, eTicketParser.GetTicketId(), eTicketParser.GetTicketVersion(), resultCommonETicket.eTicket, resultCommonETicket.certs);\n\t\tm_ticketCache.emplace_back(eTicket);\n\t};\n\n\tif (m_authInfo.region == CafeConsoleRegion::EUR)\n\t{\n\t\tquerySystemTitleTicket(0x000500301001420A); // eShop\n\t\tquerySystemTitleTicket(0x000500301001520A); // Friend List\n\t\tquerySystemTitleTicket(0x000500301001220A); // Internet browser\n\t}\n\telse if (m_authInfo.region == CafeConsoleRegion::USA)\n\t{\n\t\tquerySystemTitleTicket(0x000500301001410A); // eShop\n\t\tquerySystemTitleTicket(0x000500301001510A); // Friend List\n\t\tquerySystemTitleTicket(0x000500301001210A); // Internet browser\n\t}\n\telse if (m_authInfo.region == CafeConsoleRegion::JPN)\n\t{\n\t\tquerySystemTitleTicket(0x000500301001400A); // eShop\n\t\tquerySystemTitleTicket(0x000500301001500A); // Friend List\n\t\tquerySystemTitleTicket(0x000500301001200A); // Internet browser\n\t}\n\n\treturn true;\n}\n\n// build list of updates for which either an installed game exists or the base title ticket is cached\nbool DownloadManager::syncUpdateTickets()\n{\n\tsetStatusMessage(_tr(\"Retrieving update information...\"), DLMGR_STATUS_CODE::CONNECTING);\n\t// download update version list\n\tdownloadTitleVersionList();\n\tif (!m_hasTitleVersionList)\n\t\treturn false;\n\tstd::set<DownloadManager::TitleDownloadAvailableState> downloadList = getFullDownloadList();\n\t// count updates\n\tsize_t numUpdates = 0;\n\tfor (auto& itr : downloadList)\n\t{\n\t\tTitleIdParser titleIdParser(itr.titleId);\n\t\tif (titleIdParser.GetType() == TitleIdParser::TITLE_TYPE::BASE_TITLE_UPDATE)\n\t\t\tnumUpdates++;\n\t}\n\t// get tickets for all the updates\n\tsize_t updateIndex = 0;\n\tfor (auto& itr : downloadList)\n\t{\n\t\tTitleIdParser titleIdParser(itr.titleId);\n\t\tif (titleIdParser.GetType() != TitleIdParser::TITLE_TYPE::BASE_TITLE_UPDATE)\n\t\t\tcontinue;\n\n\t\tstd::string msg = _tr(\"Downloading ticket\");\n\t\tmsg.append(fmt::format(\" {0}/{1}\", updateIndex, numUpdates));\n\t\tupdateIndex++;\n\t\tsetStatusMessage(msg, DLMGR_STATUS_CODE::CONNECTING);\n\n\t\tif (!itr.isUpdateAvailable)\n\t\t\tcontinue;\n\n\t\t// skip if already cached\n\t\tif (findTicketByTitleIdAndVersion(itr.titleId, itr.availableTitleVersion))\n\t\t\tcontinue;\n\n\t\tauto cetkResult = NAPI::CCS_GetCETK(GetDownloadMgrNetworkService(), itr.titleId, itr.availableTitleVersion);\n\t\tif (!cetkResult.isValid)\n\t\t\tcontinue;\n\t\tNCrypto::ETicketParser ticketParser;\n\t\tif (!ticketParser.parse(cetkResult.cetkData.data(), cetkResult.cetkData.size()))\n\t\t\tcontinue;\n\t\tuint64 ticketId = ticketParser.GetTicketId();\n\t\tuint64 ticketTitleId = ticketParser.GetTitleId();\n\t\tuint16 ticketTitleVersion = ticketParser.GetTicketVersion();\n\t\tuint16 ticketVersion = ticketTitleVersion;\n\t\tif (ticketTitleId != itr.titleId)\n\t\t\tcontinue;\n\t\tif (ticketTitleVersion != itr.availableTitleVersion)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Ticket for title update has a mismatching version\");\n\t\t\tcontinue;\n\t\t}\n\t\t// add to eTicket cache\n\t\tETicketInfo eTicket(ETicketInfo::SOURCE::PUBLIC_TICKET, ticketId, ticketVersion, cetkResult.cetkData);\n\t\tm_ticketCache.emplace_back(eTicket);\n\t}\n\treturn true;\n}\n\n// synchronize ticket cache with server and request uncached ticket data\nbool DownloadManager::syncTicketCache()\n{\n\tif (!syncAccountTickets())\n\t\treturn false;\n\tsyncSystemTitleTickets();\n\tsyncUpdateTickets();\n\tstoreTicketCache();\n\n\t// make sure IDBE's are loaded into memory for all eTickets (potential downloads)\n\t// this will only download them if they aren't already in the on-disk cache\n\tsize_t count = m_ticketCache.size();\n\tsize_t index = 0;\n\tfor (auto& ticketInfo : m_ticketCache)\n\t{\n\t\tindex++;\n\t\tstd::string msg = _tr(\"Downloading meta data\");\n\t\tmsg.append(fmt::format(\" {0}/{1}\", index, count));\n\t\tsetStatusMessage(msg, DLMGR_STATUS_CODE::CONNECTING);\n\t\tprepareIDBE(ticketInfo.titleId);\n\t}\n\tsetStatusMessage(_tr(\"Connected. Right click entries in the list to start downloading\"), DLMGR_STATUS_CODE::CONNECTED);\n\treturn true;\n}\n\nvoid DownloadManager::searchForIncompleteDownloads()\n{\n\tconst fs::path packagePath = ActiveSettings::GetMlcPath(\"usr/packages/title/\");\n\tif (!fs::exists(packagePath))\n\t\treturn;\n\t\n\tfor (auto& p : fs::directory_iterator(packagePath))\n\t{\n\t\tuint64 titleId;\n\t\tuint32 version;\n\t\tstd::string name = p.path().filename().generic_string();\n\t\tif( sscanf(name.c_str(), \"cemu_%\" PRIx64 \"_v%u\", &titleId, &version) != 2)\n\t\t\tcontinue;\n\t\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\t\tfor (auto& itr : m_ticketCache)\n\t\t\tm_unfinishedDownloads.emplace_back(titleId, version);\n\t}\n}\n\nvoid DownloadManager::reportAvailableTitles()\n{\n\tif (!m_cbAddDownloadableTitle)\n\t\treturn;\n\n\tstd::set<DownloadManager::TitleDownloadAvailableState> downloadList = getFullDownloadList();\n\n\tfor (auto& itr : downloadList)\n\t{\n\t\tTitleIdParser titleIdParser(itr.titleId);\n\t\tTitleIdParser::TITLE_TYPE titleType = titleIdParser.GetType();\n\t\tif (titleType == TitleIdParser::TITLE_TYPE::BASE_TITLE ||\n\t\t\ttitleType == TitleIdParser::TITLE_TYPE::BASE_TITLE_DEMO ||\n\t\t\ttitleType == TitleIdParser::TITLE_TYPE::SYSTEM_OVERLAY_TITLE ||\n\t\t\ttitleType == TitleIdParser::TITLE_TYPE::BASE_TITLE_UPDATE ||\n\t\t\ttitleType == TitleIdParser::TITLE_TYPE::AOC)\n\t\t{\n\t\t\t// show entries only if we were able to retrieve the ticket\n\t\t\tif (itr.isInstalled)\n\t\t\t{\n\t\t\t\tif (!findFirstTicketByTitleId(itr.titleId))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tDlMgrTitleReport::STATUS status = DlMgrTitleReport::STATUS::INSTALLABLE;\n\t\t\tbool aocHasUpdate = false;\n\t\t\tif (itr.isInstalled && titleType == TitleIdParser::TITLE_TYPE::AOC)\n\t\t\t{\n\t\t\t\tETicketInfo* eTicketInfo = findFirstTicketByTitleId(itr.titleId);\n\t\t\t\tif (eTicketInfo && eTicketInfo->ticketVersion > itr.installedTicketVersion)\n\t\t\t\t\taocHasUpdate = true;\n\t\t\t}\n\n\t\t\tif (itr.isInstalled && itr.installedTitleVersion >= itr.availableTitleVersion && aocHasUpdate == false)\n\t\t\t{\n\t\t\t\tstatus = DlMgrTitleReport::STATUS::INSTALLED;\n\t\t\t}\n\t\t\tif (status == DlMgrTitleReport::STATUS::INSTALLABLE)\n\t\t\t{\n\t\t\t\tif (hasPartialDownload(itr.titleId, itr.availableTitleVersion))\n\t\t\t\t\tstatus = DlMgrTitleReport::STATUS::INSTALLABLE_UNFINISHED;\n\t\t\t\tif (aocHasUpdate)\n\t\t\t\t\tstatus = DlMgrTitleReport::STATUS::INSTALLABLE_UPDATE;\n\t\t\t}\n\t\t\tDlMgrTitleReport titleInfo(status, itr.titleId, itr.availableTitleVersion, getNameFromCachedIDBE(itr.titleId), 0, 0, false);\n\t\t\tm_cbAddDownloadableTitle(titleInfo);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false); // unsupported title type\n\t\t}\n\t}\n}\n\n/* connection logic */\n\nvoid DownloadManager::_handle_connect()\n{\n\tm_connectState.store(CONNECT_STATE::PROCESSING);\n\t\n\t// reset login state\n\tm_iasToken.serviceAccountId.clear();\n\tm_iasToken.deviceToken.clear();\n\tsetStatusMessage(_tr(\"Logging in...\"), DLMGR_STATUS_CODE::CONNECTING);\n\t// retrieve ECS AccountId + DeviceToken from cache\n\tif (s_nupFileCache)\n\t{\n\t\tstd::vector<uint8> serializationBlob;\n\t\tif (s_nupFileCache->GetFile({ fmt::format(\"{}/token_info\", m_authInfo.cachefileName) }, serializationBlob))\n\t\t{\n\t\t\tStoredTokenInfo storedTokenInfo;\n\t\t\tif (storedTokenInfo.deserialize(serializationBlob))\n\t\t\t{\n\t\t\t\tm_iasToken.serviceAccountId = storedTokenInfo.accountId;\n\t\t\t\tm_iasToken.deviceToken = storedTokenInfo.deviceToken;\n\t\t\t}\n\t\t}\n\t}\n\t// .. or request AccountId and DeviceToken if not cached\n\tif (m_iasToken.serviceAccountId.empty() || m_iasToken.deviceToken.empty())\n\t{\n\t\tif (!_connect_refreshIASAccountIdAndDeviceToken())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to request IAS token\");\n\t\t\tcemu_assert_debug(false);\n\t\t\tm_connectState.store(CONNECT_STATE::FAILED);\n\t\t\tsetStatusMessage(_tr(\"Login failed. Outdated or incomplete online files?\"), DLMGR_STATUS_CODE::FAILED);\n\t\t\treturn;\n\t\t}\n\t}\n\t// get EC account status and service urls\n\tif (!_connect_queryAccountStatusAndServiceURLs())\n\t{\n\t\tm_connectState.store(CONNECT_STATE::FAILED);\n\t\tsetStatusMessage(_tr(\"Failed to query account status\"), DLMGR_STATUS_CODE::FAILED);\n\t\treturn;\n\t}\n\t// load ticket cache and sync\n\tsetStatusMessage(_tr(\"Updating ticket cache\"), DLMGR_STATUS_CODE::CONNECTING);\n\tloadTicketCache();\n\tif (!syncTicketCache())\n\t{\n\t\tm_connectState.store(CONNECT_STATE::FAILED);\n\t\tsetStatusMessage(_tr(\"Failed to request tickets\"), DLMGR_STATUS_CODE::FAILED);\n\t\treturn;\n\t}\n\tsearchForIncompleteDownloads();\n\n\t// notify about all available downloadable titles\n\treportAvailableTitles();\n\n\t// print ticket info\n\tm_connectState.store(CONNECT_STATE::COMPLETE);\n}\n\nvoid DownloadManager::connect(\n\tstd::string_view nnidAccountName,\n\tconst std::array<uint8, 32>& passwordHash,\n\tCafeConsoleRegion region,\n\tstd::string_view country,\n\tuint32 deviceId,\n\tstd::string_view serial,\n\tstd::string_view deviceCertBase64)\n{\n\trunManager();\n\tm_authInfo.nnidAccountName = nnidAccountName;\n\tm_authInfo.passwordHash = passwordHash;\n\tm_authInfo.cachefileName = nnidAccountName.empty() ? \"DefaultName\" : nnidAccountName;\n\tm_authInfo.region = region;\n\tm_authInfo.country = country;\n\tm_authInfo.deviceCertBase64 = deviceCertBase64;\n\tm_authInfo.deviceId = deviceId;\n\tm_authInfo.serial = serial;\n\tm_connectState.store(CONNECT_STATE::REQUESTED);\n\tnotifyManager();\n\tqueueManagerJob([this]() {_handle_connect(); });\n}\n\nbool DownloadManager::IsConnected() const\n{\n\treturn m_connectState.load() != CONNECT_STATE::UNINITIALIZED;\n}\n\nNetworkService DownloadManager::GetDownloadMgrNetworkService()\n{\n\treturn NetworkService::Nintendo;\n}\n\nNAPI::AuthInfo DownloadManager::GetAuthInfo(bool withIasToken)\n{\n\tNAPI::AuthInfo authInfo;\n\tauthInfo.serviceOverwrite = GetDownloadMgrNetworkService();\n\tauthInfo.accountId = m_authInfo.nnidAccountName;\n\tauthInfo.passwordHash = m_authInfo.passwordHash;\n\tauthInfo.deviceId = m_authInfo.deviceId;\n\tauthInfo.serial = m_authInfo.serial;\n\tauthInfo.country = m_authInfo.country;\n\tauthInfo.region = m_authInfo.region;\n\tauthInfo.deviceCertBase64 = m_authInfo.deviceCertBase64;\n\tif(withIasToken)\n\t{\n\t\tcemu_assert_debug(!m_iasToken.serviceAccountId.empty());\n\t\tauthInfo.IASToken.accountId = m_iasToken.serviceAccountId;\n\t\tauthInfo.IASToken.deviceToken = m_iasToken.deviceToken;\n\t}\n\treturn authInfo;\n}\n\n/* package / downloading */\n\n// start/resume/retry download\nvoid DownloadManager::initiateDownload(uint64 titleId, uint16 version)\n{\n\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\tPackage* package = getPackage(titleId, version);\n\tif (package)\n\t{\n\t\t// remove pause state\n\t\tpackage->state.isPaused = false;\n\t\t// already exists, erase error state\n\t\tif (package->state.hasError)\n\t\t{\n\t\t\tpackage->state.hasError = false;\n\t\t\treportPackageStatus(package);\n\t\t}\n\t\tcheckPackagesState();\n\t\treturn;\n\t}\n\t// find matching eTicket and get key\n\tstd::vector<uint8>* ticketData = nullptr;\n\tfor (auto& ticket : m_ticketCache)\n\t{\n\t\tif (ticket.titleId == titleId )//&& ticket.version == version)\n\t\t{\n\t\t\tticketData = &ticket.eTicket;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!ticketData)\n\t\treturn;\n\n\tpackage = new Package(titleId, version, *ticketData);\n\tm_packageList.emplace_back(package);\n\treportPackageStatus(package);\n\tcheckPackagesState(); // will start downloading this package if none already active\n}\n\nvoid DownloadManager::pauseDownload(uint64 titleId, uint16 version)\n{\n\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\tPackage* package = getPackage(titleId, version);\n\tif (!package || !package->state.isActive)\n\t\treturn;\n\tpackage->state.isPaused = true;\n\tpackage->state.isActive = false;\n\treportPackageStatus(package);\n\tcheckPackagesState();\n}\n\nDownloadManager::Package* DownloadManager::getPackage(uint64 titleId, uint16 version)\n{\n\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\tauto itr = std::find_if(m_packageList.begin(), m_packageList.end(), [titleId, version](const Package* v) { return v->titleId == titleId && v->version == version; });\n\tif (itr == m_packageList.end())\n\t\treturn nullptr;\n\treturn *itr;\n}\n\nfs::path DownloadManager::getPackageDownloadPath(Package* package)\n{\n\treturn ActiveSettings::GetMlcPath(fmt::format(\"usr/packages/title/cemu_{:016x}_v{}/\", package->titleId, package->version));\n}\n\nfs::path DownloadManager::getPackageInstallPath(Package* package)\n{\n\tTitleIdParser tParser(package->titleId);\n\n\tconst char* titleBasePath = \"usr/title/\";\n\tif(tParser.IsSystemTitle())\n\t\ttitleBasePath = \"sys/title/\";\n\treturn ActiveSettings::GetMlcPath(fmt::format(\"{}{:08x}/{:08x}/\", titleBasePath, (uint32)(package->titleId>>32), (uint32)package->titleId));\n}\n\n// called when a package becomes active (queued to downloading) or when any of it's async download operations finishes\n// initiates new async download, decrypt or install tasks\nvoid DownloadManager::updatePackage(Package* package)\n{\n\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\tif (!package->state.isActive || package->state.isPaused || package->state.hasError)\n\t\treturn;\n\t// do we have the TMD downloaded yet?\n\tif (!package->state.tmd)\n\t{\n\t\tif (!package->state.isDownloadingTMD)\n\t\t{\n\t\t\tpackage->state.isDownloadingTMD = true;\n\t\t\tThreadPool::FireAndForget(&DownloadManager::asyncPackageDownloadTMD, this, package);\n\t\t}\n\t\treturn;\n\t}\n\n\tusing ContentState = Package::ContentFile::STATE;\n\t// count state totals\n\tstruct ContentCountInfo\n\t{\n\t\tuint32 total{};\n\t\tuint32 processing{};\n\t};\n\tenum_array<Package::ContentFile::STATE, ContentCountInfo> contentCountTable;\n\tfor (auto& itr : package->state.contentFiles)\n\t{\n\t\tauto state = itr.second.currentState;\n\t\tcontentCountTable[state].total++;\n\t\tif(itr.second.isBeingProcessed)\n\t\t\tcontentCountTable[state].processing++;\n\t}\n\n\t// utility method to grab next inactive content entry with a specific state\n\tauto getFirstInactiveContentByState = [&](ContentState state) -> Package::ContentFile*\n\t{\n\t\tauto itr = std::find_if(package->state.contentFiles.begin(), package->state.contentFiles.end(), [state](const auto& contentFile) {return contentFile.second.currentState == state && !contentFile.second.isBeingProcessed; });\n\t\tif (itr == package->state.contentFiles.end())\n\t\t\treturn nullptr;\n\t\treturn &(itr->second);\n\t};\n\n\t/************* content check phase *************/\n\tif (package->state.currentState == Package::STATE::INITIAL)\n\t{\n\t\tpackage->state.currentState = Package::STATE::CHECKING;\n\t\tpackage->state.progress = 0;\n\t\tpackage->state.progressMax = (uint32)package->state.contentFiles.size();\n\t\treportPackageStatus(package);\n\t}\n\twhile (contentCountTable[ContentState::CHECK].total > 0 && contentCountTable[ContentState::CHECK].processing < 2)\n\t{\n\t\tPackage::ContentFile* contentPtr = getFirstInactiveContentByState(ContentState::CHECK);\n\t\tif (!contentPtr)\n\t\t\tbreak;\n\t\tcontentPtr->isBeingProcessed = true;\n\t\tThreadPool::FireAndForget(&DownloadManager::asyncPackageVerifyFile, this, package, contentPtr->index, true);\n\t\tcontentCountTable[ContentState::CHECK].processing++;\n\t}\n\tif (contentCountTable[ContentState::CHECK].total > 0)\n\t\treturn; // dont proceed to next phase until done\n\n\t/************* content download phase *************/\n\twhile (contentCountTable[ContentState::DOWNLOAD].total > 0 && contentCountTable[ContentState::DOWNLOAD].processing < 2)\n\t{\n\t\tif (package->state.currentState == Package::STATE::CHECKING || package->state.currentState == Package::STATE::VERIFYING)\n\t\t{\n\t\t\tpackage->state.currentState = Package::STATE::DOWNLOADING;\n\t\t\tpackage->state.progress = 0;\n\t\t\tpackage->state.progressMax = 0;\n\t\t\treportPackageStatus(package);\n\t\t}\n\t\t// download next file if there aren't 2 active downloads already\n\t\tPackage::ContentFile* contentPtr = getFirstInactiveContentByState(ContentState::DOWNLOAD);\n\t\tif (!contentPtr)\n\t\t\tbreak;\n\t\tcontentPtr->isBeingProcessed = true;\n\t\tThreadPool::FireAndForget(&DownloadManager::asyncPackageDownloadContentFile, this, package, contentPtr->index);\n\t\tcontentCountTable[ContentState::DOWNLOAD].processing++;\n\t}\n\tif (contentCountTable[ContentState::DOWNLOAD].total > 0)\n\t\treturn;\n\n\t/************* content verification phase *************/\n\tif (package->state.currentState != Package::STATE::VERIFYING)\n\t{\n\t\tpackage->state.currentState = Package::STATE::VERIFYING;\n\t\tpackage->state.progress = 0;\n\t\tpackage->state.progressMax = (uint32)package->state.contentFiles.size();\n\t\treportPackageStatus(package);\n\t}\n\n\twhile (contentCountTable[ContentState::VERIFY].total > 0 && contentCountTable[ContentState::VERIFY].processing < 2)\n\t{\n\t\tPackage::ContentFile* contentPtr = getFirstInactiveContentByState(ContentState::VERIFY);\n\t\tif (!contentPtr)\n\t\t\tbreak;\n\t\tcontentPtr->isBeingProcessed = true;\n\t\tThreadPool::FireAndForget(&DownloadManager::asyncPackageVerifyFile, this, package, contentPtr->index, true);\n\t\tcontentCountTable[ContentState::VERIFY].processing++;\n\t}\n\tif (contentCountTable[ContentState::VERIFY].total > 0)\n\t\treturn;\n\n\t/************* installing phase *************/\n\tif (!package->state.isInstalling)\n\t{\n\t\tif (package->state.currentState != Package::STATE::INSTALLING)\n\t\t{\n\t\t\tpackage->state.currentState = Package::STATE::INSTALLING;\n\t\t\tpackage->state.progress = 0;\n\t\t\tpackage->state.progressMax = 0;\n\t\t\treportPackageStatus(package);\n\t\t}\n\t\tpackage->state.isInstalling = true;\n\t\tThreadPool::FireAndForget(&DownloadManager::asyncPackageInstall, this, package);\n\t}\n}\n\n// checks for new packages to download if none are currently active\nvoid DownloadManager::checkPackagesState()\n{\n\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\tbool hasActive = false;\n\thasActive = std::find_if(m_packageList.begin(), m_packageList.end(),\n\t\t[](const Package* p) { return p->state.isActive; }) != m_packageList.end();\n\tif (!hasActive)\n\t{\n\t\t// start new download\n\t\tauto it = std::find_if(m_packageList.begin(), m_packageList.end(),\n\t\t\t[](const Package* p) { return !p->state.isActive && !p->state.hasError && !p->state.isPaused && p->state.currentState != Package::STATE::INSTALLED; });\n\t\tif (it != m_packageList.end())\n\t\t{\n\t\t\tPackage* startedPackage = *it;\n\t\t\tstartedPackage->state.isActive = true;\n\t\t\tupdatePackage(startedPackage);\n\t\t\treportPackageStatus(startedPackage);\n\t\t}\n\t}\n}\n\nvoid DownloadManager::setPackageError(Package* package, std::string errorMsg)\n{\n\tpackage->state.isActive = false;\n\tif (package->state.hasError)\n\t\treturn; // dont overwrite already set error message\n\tpackage->state.hasError = true;\n\tpackage->state.errorMsg = std::move(errorMsg);\n\treportPackageStatus(package);\n}\n\nvoid DownloadManager::reportPackageStatus(Package* package)\n{\n\tif (!m_cbAddDownloadableTitle)\n\t\treturn;\n\tm_mutex.lock();\n\tDlMgrTitleReport::STATUS status = DlMgrTitleReport::STATUS::INITIALIZING;\n\tif (package->state.hasError)\n\t{\n\t\tstatus = DlMgrTitleReport::STATUS::HAS_ERROR;\n\t}\n\telse if (package->state.currentState == Package::STATE::INSTALLED)\n\t\tstatus = DlMgrTitleReport::STATUS::INSTALLED;\n\telse if (!package->state.isActive)\n\t{\n\t\tif (package->state.tmd)\n\t\t\tstatus = DlMgrTitleReport::STATUS::PAUSED;\n\t\telse\n\t\t\tstatus = DlMgrTitleReport::STATUS::QUEUED;\n\t}\n\telse if (package->state.tmd)\n\t{\n\t\tif (package->state.currentState == Package::STATE::CHECKING)\n\t\t\tstatus = DlMgrTitleReport::STATUS::CHECKING;\n\t\telse if (package->state.currentState == Package::STATE::VERIFYING)\n\t\t\tstatus = DlMgrTitleReport::STATUS::VERIFYING;\n\t\telse if (package->state.currentState == Package::STATE::INSTALLING)\n\t\t\tstatus = DlMgrTitleReport::STATUS::INSTALLING;\n\t\telse if (package->state.currentState == Package::STATE::INSTALLED)\n\t\t\tstatus = DlMgrTitleReport::STATUS::INSTALLED;\n\t\telse\n\t\t\tstatus = DlMgrTitleReport::STATUS::DOWNLOADING;\n\t}\n\n\tDlMgrTitleReport reportInfo(status, package->titleId, package->version, getNameFromCachedIDBE(package->titleId), package->state.progress, package->state.progressMax, package->state.isPaused);\n\tif (package->state.hasError)\n\t\treportInfo.errorMsg = package->state.errorMsg;\n\n\tm_mutex.unlock();\n\tm_cbAddDownloadableTitle(reportInfo);\n}\n\nvoid DownloadManager::reportPackageProgress(Package* package, uint32 currentProgress)\n{\n\t// todo - cooldown timer to avoid spamming too many events\n\n\tpackage->state.progress = currentProgress;\n\treportPackageStatus(package);\n}\n\nvoid DownloadManager::asyncPackageDownloadTMD(Package* package)\n{\n\tNAPI::AuthInfo authInfo = GetAuthInfo(true);\n\tTitleIdParser titleIdParser(package->titleId);\n\tNAPI::NAPI_CCSGetTMD_Result tmdResult;\n\tif (titleIdParser.GetType() == TitleIdParser::TITLE_TYPE::AOC)\n\t{\n\t\t// for AOC we always download the latest TMD\n\t\t// is there a way to get the version beforehand? It doesn't seem to be stored in either the .tik file or the update version list\n\t\ttmdResult = CCS_GetTMD(authInfo, package->titleId);\n\t}\n\telse\n\t{\n\t\ttmdResult = NAPI::CCS_GetTMD(authInfo, package->titleId, package->version);\n\t}\t\n\tif (!tmdResult.isValid)\n\t{\n\t\t// failed, try to get latest TMD instead\n\t\ttmdResult = CCS_GetTMD(authInfo, package->titleId);\n\t}\n\n\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\tif (!tmdResult.isValid)\n\t{\n\t\tsetPackageError(package, _tr(\"TMD download failed\"));\n\t\tpackage->state.isDownloadingTMD = false;\n\t\treturn;\n\t}\n\t_l.unlock();\n\t// parse\n\tNCrypto::TMDParser tmdParser;\n\tif (!tmdParser.parse(tmdResult.tmdData.data(), tmdResult.tmdData.size()))\n\t{\n\t\tsetPackageError(package, _tr(\"Invalid TMD\"));\n\t\tpackage->state.isDownloadingTMD = false;\n\t\treturn;\n\t}\n\t// set TMD\n\t_l.lock();\n\tpackage->state.tmdData = tmdResult.tmdData;\n\tpackage->state.tmd = new NCrypto::TMDParser(tmdParser);\n\tpackage->state.isDownloadingTMD = false;\n\t// prepare list of content files\n\tpackage->state.contentFiles.clear();\n\tfor (auto& itr : package->state.tmd->GetContentList())\n\t{\n\t\tif (package->state.contentFiles.find(itr.index) != package->state.contentFiles.end())\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\tcontinue;\n\t\t}\n\t\tpackage->state.contentFiles.emplace(std::piecewise_construct, std::forward_as_tuple(itr.index), std::forward_as_tuple(itr.index, itr.contentId, itr.size, itr.contentFlags, itr.hash32));\n\t}\n\t// create folder\n\tauto dir = getPackageDownloadPath(package);\n\tfs::create_directories(dir);\n\t// continue with downloading\n\treportPackageStatus(package);\n\tupdatePackage(package);\n}\n\nvoid DownloadManager::calcPackageDownloadProgress(Package* package)\n{\n\tif (package->state.currentState == Package::STATE::DOWNLOADING)\n\t{\n\t\tuint64 totalSize = 0;\n\t\tuint64 totalDownloaded = 0;\n\t\tfor (auto& itr : package->state.contentFiles)\n\t\t{\n\t\t\ttotalSize += itr.second.paddedSize;\n\t\t\tif (itr.second.currentState == Package::ContentFile::STATE::INSTALL || itr.second.currentState == Package::ContentFile::STATE::VERIFY)\n\t\t\t\ttotalDownloaded += itr.second.paddedSize; // already downloaded, add full size\n\t\t\telse\n\t\t\t\ttotalDownloaded += itr.second.amountDownloaded;\n\t\t}\n\n\t\tuint32 pct10 = (uint32)(totalDownloaded * 1000ull / totalSize);\n\t\tif (package->state.progress != pct10)\n\t\t{\n\t\t\tpackage->state.progress = pct10;\n\t\t\tpackage->state.progressMax = 1000;\n\t\t\treportPackageProgress(package, package->state.progress);\n\t\t}\n\t}\n}\n\nvoid DownloadManager::asyncPackageDownloadContentFile(Package* package, uint16 index)\n{\n\t// get titleId, contentId and file path\n\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\tuint64 titleId = package->titleId;\n\tauto contentFileItr = package->state.contentFiles.find(index);\n\tcemu_assert(contentFileItr != package->state.contentFiles.end());\n\tuint32 contentId = contentFileItr->second.contentId;\n\tcontentFileItr->second.amountDownloaded = 0;\n\tauto packageDownloadPath = getPackageDownloadPath(package);\n\t_l.unlock();\n\n\t// download h3 hash file (.h3) if flag 0x0002 is set (-> we are using the TMD to verify the hash of the content files)\n\t//auto h3Result = NAPI::CCS_GetContentH3File(titleId, contentId);\n\t//auto h3Result = NAPI::CCS_GetContentH3File(titleId, contentId);\n\t\n\t//if (!h3Result.isValid)\n\t//{\n\t//\tsetPackageError(package, \"Download failed (h3)\");\n\t//\treturn;\n\t//}\n\t//filePathStr = (packageDownloadPath / fmt::format(\"{:08x}.h3\", index)).generic_u8string();\n\t//auto h3File = FileStream::createFile(filePathStr);\n\t//if (!h3File)\n\t//{\n\t//\tsetPackageError(package, \"Cannot create file\");\n\t//\treturn;\n\t//}\n\t//if (h3File->writeData(h3Result.tmdData.data(), h3Result.tmdData.size()) != h3Result.tmdData.size())\n\t//{\n\t//\tsetPackageError(package, \"Cannot write file (h3). Disk full?\");\n\t//\treturn;\n\t//}\n\t//delete h3File;\n\n\t// streamed download of content file (.app)\n\t// prepare callback parameter struct\n\tstruct CallbackInfo \n\t{\n\t\tDownloadManager* downloadMgr;\n\t\tPackage* package;\n\t\tPackage::ContentFile* contentFile;\n\t\tstd::vector<uint8> receiveBuffer;\n\t\tFileStream* fileOutput;\n\n\t\tstatic bool writeCallback(void* userData, const void* ptr, size_t len, bool isLast)\n\t\t{\n\t\t\tCallbackInfo* callbackInfo = (CallbackInfo*)userData;\n\t\t\t// append bytes to buffer\n\t\t\tcallbackInfo->receiveBuffer.insert(callbackInfo->receiveBuffer.end(), (const uint8*)ptr, (const uint8*)ptr + len);\n\t\t\t// flush cache to file if it exceeds 128KiB or if this is the final callback\n\t\t\tif (callbackInfo->receiveBuffer.size() >= (128 * 1024) || (isLast && !callbackInfo->receiveBuffer.empty()))\n\t\t\t{\n\t\t\t\tsize_t bytesWritten = callbackInfo->receiveBuffer.size();\n\t\t\t\tif (callbackInfo->fileOutput->writeData(callbackInfo->receiveBuffer.data(), callbackInfo->receiveBuffer.size()) != (uint32)callbackInfo->receiveBuffer.size())\n\t\t\t\t{\n\t\t\t\t\tcallbackInfo->downloadMgr->setPackageError(callbackInfo->package, _tr(\"Cannot write file. Disk full?\"));\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tcallbackInfo->receiveBuffer.clear();\n\t\t\t\tif (bytesWritten > 0)\n\t\t\t\t{\n\t\t\t\t\tcallbackInfo->downloadMgr->m_mutex.lock();\n\t\t\t\t\tcallbackInfo->contentFile->amountDownloaded += bytesWritten;\n\t\t\t\t\tcallbackInfo->downloadMgr->calcPackageDownloadProgress(callbackInfo->package);\n\t\t\t\t\tcallbackInfo->downloadMgr->m_mutex.unlock();\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t}callbackInfoData{};\n\tcallbackInfoData.downloadMgr = this;\n\tcallbackInfoData.package = package;\n\tcallbackInfoData.contentFile = &contentFileItr->second;\n\tcallbackInfoData.fileOutput = FileStream::createFile2(packageDownloadPath / fmt::format(\"{:08x}.app\", contentId));\n\tif (!callbackInfoData.fileOutput)\n\t{\n\t\tsetPackageError(package, _tr(\"Cannot create file\"));\n\t\treturn;\n\t}\n\tif (!NAPI::CCS_GetContentFile(GetDownloadMgrNetworkService(), titleId, contentId, CallbackInfo::writeCallback, &callbackInfoData))\n\t{\n\t\tsetPackageError(package, _tr(\"Download failed\"));\n\t\tdelete callbackInfoData.fileOutput;\n\t\treturn;\n\t}\n\tdelete callbackInfoData.fileOutput;\n\tcallbackInfoData.fileOutput = nullptr;\n\n\t// mark file as downloaded by requesting verify state\n\t_l.lock();\n\tcontentFileItr->second.finishProcessing(Package::ContentFile::STATE::VERIFY);\n\t_l.unlock();\n\t// start next task\n\tupdatePackage(package);\n}\n\nvoid DownloadManager::asyncPackageVerifyFile(Package* package, uint16 index, bool isCheckState)\n{\n\tuint8 tmdContentHash[32];\n\t// get titleId, contentId and file path\n\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\tuint64 titleId = package->titleId;\n\tauto contentFileItr = package->state.contentFiles.find(index);\n\tcemu_assert(contentFileItr != package->state.contentFiles.end());\n\tuint16 contentIndex = contentFileItr->second.index;\n\tuint32 contentId = contentFileItr->second.contentId;\n\tuint64 contentSize = contentFileItr->second.size;\n\tuint64 contentPaddedSize = contentFileItr->second.paddedSize;\n\tauto contentFlags = contentFileItr->second.contentFlags;\n\tstd::memcpy(tmdContentHash, contentFileItr->second.contentHash, 32);\n\tauto packageDownloadPath = getPackageDownloadPath(package);\n\t_l.unlock();\n\tNCrypto::AesKey ecsTicketKey = package->ticketKey;\n\n\tPackage::ContentFile::STATE newStateOnError = Package::ContentFile::STATE::DOWNLOAD;\n\tPackage::ContentFile::STATE newStateOnSuccess = Package::ContentFile::STATE::INSTALL;\n\n\t// verify file\n\tstd::unique_ptr<FileStream> fileStream(FileStream::openFile2(packageDownloadPath / fmt::format(\"{:08x}.app\", contentId)));\n\tif (!fileStream)\n\t{\n\t\t_l.lock();\n\t\tcontentFileItr->second.finishProcessing(newStateOnError);\n\t\tif (!isCheckState)\n\t\t\tsetPackageError(package, \"Missing file during verification\");\n\t\t_l.unlock();\n\t\tupdatePackage(package);\n\t\treturn;\n\t}\n\n\tbool isSHA1 = HAS_FLAG(contentFlags, NCrypto::TMDParser::TMDContentFlags::FLAG_SHA1);\n\n\tbool isValid = false;\n\tif (HAS_FLAG(contentFlags, NCrypto::TMDParser::TMDContentFlags::FLAG_HASHED_CONTENT))\n\t\tisValid = FSTVerifier::VerifyHashedContentFile(fileStream.get(), &ecsTicketKey, contentIndex, contentSize, contentPaddedSize, isSHA1, tmdContentHash);\n\telse\n\t\tisValid = FSTVerifier::VerifyContentFile(fileStream.get(), &ecsTicketKey, contentIndex, contentSize, contentPaddedSize, isSHA1, tmdContentHash);\n\n\tif (!isValid)\n\t{\n\t\t_l.lock();\n\t\tcontentFileItr->second.finishProcessing(newStateOnError);\n\t\tif (!isCheckState)\n\t\t\tsetPackageError(package, \"Verification failed\");\n\t\t_l.unlock();\n\t\tupdatePackage(package);\n\t\treturn;\n\t}\n\t// file verified successfully\n\t_l.lock();\n\tcontentFileItr->second.finishProcessing(newStateOnSuccess);\n\treportPackageProgress(package, package->state.progress + 1);\n\t_l.unlock();\n\t// start next task\n\tupdatePackage(package);\n}\n\nbool DownloadManager::asyncPackageInstallRecursiveExtractFiles(Package* package, FSTVolume* fstVolume, const std::string& sourcePath, const fs::path& destinationPath)\n{\n\tstd::error_code ec;\n\tfs::create_directories(destinationPath, ec); // we dont check the error because it is OS/implementation specific (on Windows this returns ec=0 with false when directory already exists)\n\tcemu_assert_debug(sourcePath.back() == '/');\n\tFSTDirectoryIterator dirItr;\n\tif (!fstVolume->OpenDirectoryIterator(sourcePath, dirItr))\n\t{\n\t\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\t\tsetPackageError(package, \"Internal error\");\n\t\treturn false;\n\t}\n\tif (fstVolume->HasLinkFlag(dirItr.GetDirHandle()))\n\t{\n\t\tcemu_assert_suspicious();\n\t\treturn true;\n\t}\n\tFSTFileHandle itr;\n\twhile (fstVolume->Next(dirItr, itr))\n\t{\n\t\tstd::string_view nodeName = fstVolume->GetName(itr);\n\t\tif(nodeName.empty() || boost::equals(nodeName, \".\") || boost::equals(nodeName, \"..\") || boost::contains(nodeName, \"/\") || boost::contains(nodeName, \"\\\\\"))\n\t\t\tcontinue;\n\t\tstd::string sourceFilePath = sourcePath;\n\t\tsourceFilePath.append(nodeName);\n\t\tfs::path nodeDestinationPath = destinationPath;\n\t\tnodeDestinationPath.append(nodeName.data(), nodeName.data() + nodeName.size());\n\t\tif (fstVolume->IsDirectory(itr))\n\t\t{\n\t\t\tif (fstVolume->HasLinkFlag(itr))\n\t\t\t{\n\t\t\t\t// delete link directories\n\t\t\t\tfs::remove_all(nodeDestinationPath, ec);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// iterate\n\t\t\t\tsourceFilePath.push_back('/');\n\t\t\t\tasyncPackageInstallRecursiveExtractFiles(package, fstVolume, sourceFilePath, nodeDestinationPath);\n\t\t\t}\n\t\t}\n\t\telse if (fstVolume->IsFile(itr))\n\t\t{\n\t\t\tif (fstVolume->HasLinkFlag(itr))\n\t\t\t{\n\t\t\t\t// delete link files\n\t\t\t\tfs::remove_all(nodeDestinationPath, ec);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// extract\n\t\t\t\tstd::vector<uint8> buffer(64 * 1024);\n\t\t\t\tFileStream* fileOut = FileStream::createFile2(nodeDestinationPath);\n\t\t\t\tif (!fileOut)\n\t\t\t\t{\n\t\t\t\t\tsetPackageError(package, \"Failed to create file\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tuint32 fileSize = fstVolume->GetFileSize(itr);\n\t\t\t\tuint32 currentPos = 0;\n\t\t\t\twhile (currentPos < fileSize)\n\t\t\t\t{\n\t\t\t\t\tuint32 numBytesToTransfer = std::min(fileSize - currentPos, (uint32)buffer.size());\n\t\t\t\t\tif (fstVolume->ReadFile(itr, currentPos, numBytesToTransfer, buffer.data()) != numBytesToTransfer)\n\t\t\t\t\t{\n\t\t\t\t\t\tsetPackageError(package, \"Failed to extract data\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (fileOut->writeData(buffer.data(), numBytesToTransfer) != numBytesToTransfer)\n\t\t\t\t\t{\n\t\t\t\t\t\tsetPackageError(package, \"Failed to write to file. Disk full?\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tcurrentPos += numBytesToTransfer;\n\t\t\t\t}\n\t\t\t\tdelete fileOut;\n\t\t\t}\n\t\t\t// advance progress\n\t\t\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\t\t\treportPackageProgress(package, package->state.progress + 1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false); // unknown node type\n\t\t}\n\t}\n\treturn true;\n}\n\nvoid DownloadManager::asyncPackageInstall(Package* package)\n{\n\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\tauto packageDownloadPath = getPackageDownloadPath(package);\n\tfs::path installPath = getPackageInstallPath(package);\n\t_l.unlock();\n\t// store title.tmd\n\tstd::unique_ptr<FileStream> fileStream(FileStream::createFile2(packageDownloadPath / \"title.tmd\"));\n\tif (!fileStream || fileStream->writeData(package->state.tmdData.data(), package->state.tmdData.size()) != package->state.tmdData.size())\n\t{\n\t\t_l.lock();\n\t\tsetPackageError(package, \"Failed to write title.tmd\");\n\t\tpackage->state.isInstalling = false;\n\t\treturn;\n\t}\n\tfileStream.reset();\n\t// store title.tik\n\tfileStream.reset(FileStream::createFile2(packageDownloadPath / \"title.tik\"));\n\tif (!fileStream || fileStream->writeData(package->eTicketData.data(), package->eTicketData.size()) != package->eTicketData.size())\n\t{\n\t\t_l.lock();\n\t\tsetPackageError(package, \"Failed to write title.tik\");\n\t\tpackage->state.isInstalling = false;\n\t\treturn;\n\t}\n\tfileStream.reset();\n\t// for AOC titles we also 'install' the ticket by copying it next to the code/content/meta folders\n\t// on an actual Wii U the ticket gets installed to SLC but currently we only emulate MLC\n\tif (TitleIdParser(package->titleId).GetType() == TitleIdParser::TITLE_TYPE::AOC)\n\t{\n\t\tstd::error_code ec;\n\t\tfs::create_directories(installPath, ec);\n\t\tfs::create_directories(installPath / \"code/\", ec);\n\t\tfileStream.reset(FileStream::createFile2(installPath / \"code/title.tik\"));\n\t\tif (!fileStream || fileStream->writeData(package->eTicketData.data(), package->eTicketData.size()) != package->eTicketData.size())\n\t\t{\n\t\t\t_l.lock();\n\t\t\tsetPackageError(package, \"Failed to install title.tik\");\n\t\t\tpackage->state.isInstalling = false;\n\t\t\treturn;\n\t\t}\n\t\tfileStream.reset();\n\t}\n\t// open app FST\n\tFSTVolume* fst = FSTVolume::OpenFromContentFolder(packageDownloadPath);\n\tif (!fst)\n\t{\n\t\t_l.lock();\n\t\tsetPackageError(package, \"Failed to extract content\");\n\t\tpackage->state.isInstalling = false;\n\t\treturn;\n\t}\n\t// count number of files for progress tracking\n\tpackage->state.progressMax = fst->GetFileCount();\n\tpackage->state.progress = 0;\n\t// extract code/content/meta folders into installation directory\n\tif (!asyncPackageInstallRecursiveExtractFiles(package, fst, \"code/\", installPath / \"code\"))\n\t{\n\t\t_l.lock();\n\t\tsetPackageError(package, \"Failed to extract code folder\");\n\t\tpackage->state.isInstalling = false;\n\t\treturn;\n\t}\n\tif (!asyncPackageInstallRecursiveExtractFiles(package, fst, \"content/\", installPath / \"content\"))\n\t{\n\t\t_l.lock();\n\t\tsetPackageError(package, \"Failed to extract content folder\");\n\t\tpackage->state.isInstalling = false;\n\t\treturn;\n\t}\n\tif (!asyncPackageInstallRecursiveExtractFiles(package, fst, \"meta/\", installPath / \"meta\"))\n\t{\n\t\t_l.lock();\n\t\tsetPackageError(package, \"Failed to extract meta folder\");\n\t\tpackage->state.isInstalling = false;\n\t\treturn;\n\t}\n\tdelete fst;\n\t// delete package folder\n\tstd::error_code ec;\n\tfs::remove_all(packageDownloadPath, ec);\n\t// mark as complete\n\t_l.lock();\n\tpackage->state.currentState = Package::STATE::INSTALLED;\n\tpackage->state.isInstalling = false;\n\tpackage->state.isActive = false;\n\tCafeTitleList::AddTitleFromPath(installPath);\n\treportPackageStatus(package);\n\tcheckPackagesState();\n\t// lastly request game list to be refreshed\n\tWindowSystem::RefreshGameList();\n\treturn;\n}\n\n/* IDBE cache */\n\nstd::unordered_map<uint64, NAPI::IDBEIconDataV0*> s_idbeCache;\nstd::mutex s_idbeCacheMutex;\n\n// load IDBE from disk or server into memory cache\n// stalls while reading disk/downloading\nvoid DownloadManager::prepareIDBE(uint64 titleId)\n{\n\tauto hasInCache = [](uint64 titleId) -> bool\n\t{\n\t\ts_idbeCacheMutex.lock();\n\t\tbool hasCached = s_idbeCache.find(titleId) != s_idbeCache.end();\n\t\ts_idbeCacheMutex.unlock();\n\t\treturn hasCached;\n\t};\n\n\tauto addToCache = [](uint64 titleId, NAPI::IDBEIconDataV0* iconData) -> void\n\t{\n\t\tNAPI::IDBEIconDataV0* iconInstance = new NAPI::IDBEIconDataV0();\n\t\t*iconInstance = *iconData;\n\t\ts_idbeCacheMutex.lock();\n\t\tif (!s_idbeCache.try_emplace(titleId, iconInstance).second)\n\t\t\tdelete iconInstance;\n\t\ts_idbeCacheMutex.unlock();\n\t};\n\tif (hasInCache(titleId))\n\t\treturn;\n\t// try to load from disk cache\n\tstd::vector<uint8> idbeFile;\n\tif (s_nupFileCache->GetFile({ fmt::format(\"idbe/{0:016x}\", titleId) }, idbeFile) && idbeFile.size() == sizeof(NAPI::IDBEIconDataV0))\n\t\treturn addToCache(titleId, (NAPI::IDBEIconDataV0*)(idbeFile.data()));\n\t// not cached, query from server\n\tstd::optional<NAPI::IDBEIconDataV0> iconData = NAPI::IDBE_Request(GetDownloadMgrNetworkService(), titleId);\n\tif (!iconData)\n\t\treturn;\n\ts_nupFileCache->AddFileAsync({ fmt::format(\"idbe/{0:016x}\", titleId) }, (uint8*)&(*iconData), sizeof(NAPI::IDBEIconDataV0));\n\taddToCache(titleId, &*iconData);\n}\n\nstd::string DownloadManager::getNameFromCachedIDBE(uint64 titleId)\n{\n\t// workaround for Friend List not having an IDBE\n\tif (titleId == 0x000500301001500A ||\n\t\ttitleId == 0x000500301001510A ||\n\t\ttitleId == 0x000500301001520A)\n\t{\n\t\treturn \"Friend List\";\n\t}\n\n\tstd::unique_lock<std::mutex> _l(s_idbeCacheMutex);\n\tNAPI::IDBEIconDataV0* iconData = getIDBE(titleId);\n\tif (iconData)\n\t\treturn iconData->GetLanguageStrings(GetConfig().console_language).GetGameNameUTF8();\n\treturn fmt::format(\"Title {0:016x}\", titleId);\n}\n\n// returns IDBE by titleId (or nullptr if not in cache)\n// assumes s_idbeCacheMutex is held by caller\nNAPI::IDBEIconDataV0* DownloadManager::getIDBE(uint64 titleId)\n{\n\tauto it = s_idbeCache.find(titleId);\n\tif (it == s_idbeCache.end())\n\t\treturn nullptr;\n\treturn it->second;\n}\n\n/* package manager / downloading */\n\nvoid DownloadManager::threadFunc()\n{\n\twhile (true)\n\t{\n\t\tauto cb = m_jobQueue.pop();\n\t\tcb();\n\t}\n}\n\n// init download manager worker thread and cache\nvoid DownloadManager::runManager()\n{\n\tbool prevBool = false;\n\tif (!m_threadLaunched.compare_exchange_weak(prevBool, true))\n\t\treturn;\n\t// open cache\n\tauto cacheFilePath = ActiveSettings::GetMlcPath(\"usr/save/system/nim/nup/\");\n\tfs::create_directories(cacheFilePath);\n\tcacheFilePath /= \"cemu_cache.dat\";\n\ts_nupFileCache = FileCache::Open(cacheFilePath, true);\n\t// launch worker thread\n\tstd::thread t(&DownloadManager::threadFunc, this);\n\tt.detach();\n}\n\n// let manager known there is a new event that needs processing\nvoid DownloadManager::notifyManager()\n{\n\tm_queuedEvents.increment();\n}\n\nvoid DownloadManager::queueManagerJob(const std::function<void()>& callback)\n{\n\tm_jobQueue.push(callback);\n}\n"
  },
  {
    "path": "src/Cemu/Tools/DownloadManager/DownloadManager.h",
    "content": "#pragma once\n#include \"util/helpers/Semaphore.h\"\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"Cafe/TitleList/TitleId.h\"\n#include \"util/helpers/ConcurrentQueue.h\"\n#include \"config/NetworkSettings.h\"\n\n// forward declarations\nnamespace NAPI\n{\n\tstruct IDBEIconDataV0;\n\tstruct AuthInfo;\n}\n\nnamespace NCrypto\n{\n\tclass TMDParser;\n}\n\nstruct DlMgrTitleReport\n{\n\tenum class STATUS\n\t{\n\t\tINSTALLABLE, // not a package\n\t\tINSTALLABLE_UNFINISHED, // same as INSTALLABLE, but a previous unfinished package was detected\n\t\tINSTALLABLE_UPDATE, // same as INSTALLABLE, but an older version is already installed (used for DLC updates after purchasing more content)\n\t\t// below are packages\n\t\tQUEUED,\n\t\tPAUSED,\n\t\tINITIALIZING, // not active yet, downloading TMD\n\t\tCHECKING, // checking for previously downloaded files\n\t\tDOWNLOADING, // downloading content files\n\t\tVERIFYING, // verifying downloaded files\n\t\tINSTALLING,\n\t\tINSTALLED,\n\t\tHAS_ERROR\n\t};\n\n\tDlMgrTitleReport(STATUS status, uint64 titleId, uint16 version, std::string name, uint32 progress, uint32 progressMax, bool isPaused) : status(status), titleId(titleId), version(version), name(name), progress(progress), progressMax(progressMax), isPaused(isPaused) {}\n\n\tuint64 titleId;\n\tuint16 version;\n\tstd::string name; // utf8\n\tSTATUS status;\n\tuint32 progress;\n\tuint32 progressMax;\n\tbool isPaused;\n\tstd::string errorMsg;\n};\n\nenum class DLMGR_STATUS_CODE\n{\n\tUNINITIALIZED,\n\tCONNECTING,\n\tFAILED,\n\tCONNECTED\n};\n\nclass DownloadManager\n{\npublic:\n\t/* singleton */\n\n\tstatic DownloadManager* GetInstance(bool createIfNotExist = true)\n\t{\n\t\tstatic DownloadManager* s_instance = nullptr;\n\t\tif (s_instance)\n\t\t\treturn s_instance;\n\t\tif (createIfNotExist)\n\t\t\ts_instance = new DownloadManager();\n\t\treturn s_instance;\n\t}\n\n\t// login\n\tvoid connect(\n\t\tstd::string_view nnidAccountName, \n\t\tconst std::array<uint8, 32>& passwordHash, \n\t\tCafeConsoleRegion region,\n\t\tstd::string_view country,\n\t\tuint32 deviceId,\n\t\tstd::string_view serial,\n\t\tstd::string_view deviceCertBase64);\n\n\tbool IsConnected() const;\n\nprivate:\n\t/* connect / login */\n\t\n\tenum class CONNECT_STATE\n\t{\n\t\tUNINITIALIZED = 0, // connect() not called\n\t\tREQUESTED = 1, // connect() requested, but not being processed yet\n\t\tPROCESSING = 2, // processing login request\n\t\tCOMPLETE = 3, // login complete / succeeded\n\t\tFAILED = 4, // failed to login\n\t};\n\n\tstruct \n\t{\n\t\tstd::string cachefileName;\n\t\tstd::string nnidAccountName;\n\t\tstd::array<uint8, 32> passwordHash;\n\t\tstd::string deviceCertBase64;\n\t\tCafeConsoleRegion region;\n\t\tstd::string country;\n\t\tuint32 deviceId; // deviceId without platform (0x5<<32 for WiiU)\n\t\tstd::string serial;\n\t}m_authInfo{};\n\n\tstruct  \n\t{\n\t\t// auth info we have to request from the server\n\t\tstd::string serviceAccountId; // internal account id (integer) provided by server when registering account (GetRegistrationInfo)\n\t\tstd::string deviceToken;\n\t}m_iasToken{};\n\n\tstd::atomic<CONNECT_STATE> m_connectState{ CONNECT_STATE::UNINITIALIZED };\n\n\tvoid _handle_connect();\n\tbool _connect_refreshIASAccountIdAndDeviceToken();\n\tbool _connect_queryAccountStatusAndServiceURLs();\n\n\tNetworkService GetDownloadMgrNetworkService();\n\tNAPI::AuthInfo GetAuthInfo(bool withIasToken);\n\n\t/* idbe cache */\npublic:\n\tvoid prepareIDBE(uint64 titleId);\n\tstd::string getNameFromCachedIDBE(uint64 titleId);\n\nprivate:\n\tNAPI::IDBEIconDataV0* getIDBE(uint64 titleId);\n\n\t/* ticket cache */\npublic:\n\n\tstruct ETicketInfo\n\t{\n\t\tenum class SOURCE : uint8\n\t\t{\n\t\t\tECS_TICKET = 0, // personalized ticket of owned title\n\t\t\tPUBLIC_TICKET = 1, // public ticket file (available as /CETK from NUS server or via SOAP GetSystemCommonETicket. The former is from Wii era while the latter is how Wii U requests public tickets?)\n\t\t\t// note: These ids are baked into the serialized cache format. Do not modify\n\t\t};\n\n\t\tETicketInfo(SOURCE source, uint64 ticketId, uint32 ticketVersion, std::vector<uint8>& eTicket);\n\t\tETicketInfo(SOURCE source, uint64 ticketId, uint32 ticketVersion, std::vector<uint8>& eTicket, std::vector<std::vector<uint8>>& eTicketCerts);\n\t\tvoid GetTitleKey(NCrypto::AesKey& key);\n\n\t\tSOURCE source;\n\t\t// tiv\n\t\tuint64 ticketId;\n\t\tuint32 ticketVersion;\n\t\t// titleInfo\n\t\tuint64 titleId{0}; // parsed from eTicket\n\n\t\tstd::vector<uint8> eTicket;\n\t\tstd::vector<std::vector<uint8>> eTicketCerts;\n\t};\n\n\tstd::vector<ETicketInfo> m_ticketCache;\n\n\tstruct UnfinishedDownload\n\t{\n\t\tUnfinishedDownload(uint64 titleId, uint16 titleVersion) : titleId(titleId), titleVersion(titleVersion) {};\n\n\t\tuint64 titleId;\n\t\tuint16 titleVersion;\n\t};\n\n\tstd::vector<UnfinishedDownload> m_unfinishedDownloads;\n\n\tvoid loadTicketCache();\n\tvoid storeTicketCache();\n\n\tbool syncAccountTickets();\n\tbool syncSystemTitleTickets();\n\tbool syncUpdateTickets();\n\tbool syncTicketCache();\n\tvoid searchForIncompleteDownloads();\n\n\tvoid reportAvailableTitles();\n\nprivate:\n\tETicketInfo* findTicketByTicketId(uint64 ticketId)\n\t{\n\t\tfor (auto& itr : m_ticketCache)\n\t\t{\n\t\t\tif (itr.ticketId == ticketId)\n\t\t\t\treturn &itr;\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tvoid deleteTicketByTicketId(uint64 ticketId)\n\t{\n\t\tauto itr = m_ticketCache.begin();\n\t\twhile (itr != m_ticketCache.end())\n\t\t{\n\t\t\tif (itr->ticketId == ticketId)\n\t\t\t{\n\t\t\t\tm_ticketCache.erase(itr);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\titr++;\n\t\t}\n\t\tcemu_assert_debug(false); // ticketId not found\n\t}\n\n\tETicketInfo* findTicketByTitleIdAndVersion(uint64 titleId, uint16 version)\n\t{\n\t\tfor (auto& itr : m_ticketCache)\n\t\t{\n\t\t\tif (itr.titleId == titleId && itr.ticketVersion == version)\n\t\t\t\treturn &itr;\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tETicketInfo* findFirstTicketByTitleId(uint64 titleId)\n\t{\n\t\tfor (auto& itr : m_ticketCache)\n\t\t{\n\t\t\tif (itr.titleId == titleId)\n\t\t\t\treturn &itr;\n\t\t}\n\t\treturn nullptr;\n\t}\n\n\tbool hasPartialDownload(uint64 titleId, uint16 titleVersion)\n\t{\n\t\tfor (auto& itr : m_unfinishedDownloads)\n\t\t{\n\t\t\tif (itr.titleId == titleId && itr.titleVersion == titleVersion)\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tvoid deleteUnfinishedDownloadRecord(uint64 titleId)\n\t{\n\t\tauto itr = m_unfinishedDownloads.begin();\n\t\twhile (itr != m_unfinishedDownloads.end())\n\t\t{\n\t\t\tif (itr->titleId == titleId)\n\t\t\t{\n\t\t\t\titr = m_unfinishedDownloads.erase(itr);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\titr++;\n\t\t}\n\t}\n\n\t/* packages / downloading */\n\tstruct Package \n\t{\n\t\tPackage(uint64 titleId, uint16 version, std::span<uint8> ticketData) : titleId(titleId), version(version), eTicketData(ticketData.data(), ticketData.data() + ticketData.size()) \n\t\t{\n\t\t\tNCrypto::ETicketParser eTicketParser;\n\t\t\tcemu_assert(eTicketParser.parse(ticketData.data(), ticketData.size()));\n\t\t\teTicketParser.GetTitleKey(ticketKey);\n\t\t};\n\n\t\t~Package()\n\t\t{\n\t\t\tdelete state.tmd;\n\t\t}\n\n\t\tenum class STATE\n\t\t{\n\t\t\tINITIAL,\n\t\t\tCHECKING,\n\t\t\tDOWNLOADING,\n\t\t\tVERIFYING,\n\t\t\tINSTALLING,\n\t\t\tINSTALLED // done\n\t\t};\n\n\t\tuint64 titleId;\n\t\tuint16 version;\n\t\tstd::vector<uint8> eTicketData;\n\t\tNCrypto::AesKey ticketKey;\n\n\t\t// internal\n\t\tstruct ContentFile\n\t\t{\n\t\t\tContentFile(uint16 index, uint32 contentId, uint64 size, NCrypto::TMDParser::TMDContentFlags contentFlags, uint8 hash[32]) : index(index), contentId(contentId), size(size), contentFlags(contentFlags)\n\t\t\t{\n\t\t\t\tstd::memcpy(contentHash, hash, 32);\n\t\t\t\tCalcPaddedSize();\n\t\t\t};\n\t\t\tconst uint16 index;\n\t\t\tconst uint32 contentId;\n\t\t\tconst uint64 size;\n\t\t\tuint64 paddedSize; // includes padding forced by encryption/hashing (e.g. Nintendo Land update has one non-hashed content size of 0x8001, padded to 0x8010)\n\t\t\tconst NCrypto::TMDParser::TMDContentFlags contentFlags;\n\t\t\tuint8 contentHash[32];\n\n\t\t\tenum class STATE\n\t\t\t{\n\t\t\t\tCHECK,\n\t\t\t\tDOWNLOAD,\n\t\t\t\tVERIFY,\n\t\t\t\tINSTALL,\n\n\t\t\t\tENUM_COUNT, // for enum_array\n\t\t\t};\n\n\t\t\tSTATE currentState{STATE::CHECK};\n\t\t\tbool isBeingProcessed{false}; // worked thread assigned and processing current state\n\n\t\t\tvoid finishProcessing(STATE newState)\n\t\t\t{\n\t\t\t\tcurrentState = newState;\n\t\t\t\tisBeingProcessed = false;\n\t\t\t};\n\n\t\t\t// progress tracking\n\t\t\tuint64 amountDownloaded{};\n\n\t\tprivate:\n\t\t\tvoid CalcPaddedSize()\n\t\t\t{\n\t\t\t\tif (HAS_FLAG(contentFlags, NCrypto::TMDParser::TMDContentFlags::FLAG_HASHED_CONTENT))\n\t\t\t\t{\n\t\t\t\t\t// pad to 0x10000 bytes\n\t\t\t\t\tpaddedSize = (size + 0xFFFFull) & ~0xFFFFull;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// pad to 16 bytes\n\t\t\t\t\tpaddedSize = (size + 0xFull) & ~0xFull;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tstruct\n\t\t{\n\t\t\tbool isActive{}; // actively downloading \n\t\t\tbool isPaused{};\n\t\t\tSTATE currentState{ STATE::INITIAL };\n\t\t\t// tmd\n\t\t\tbool isDownloadingTMD{};\n\t\t\tstd::vector<uint8> tmdData;\n\t\t\tNCrypto::TMDParser* tmd{};\n\t\t\t// app/h3 tracking\n\t\t\tstd::unordered_map<uint16, ContentFile> contentFiles;\n\t\t\t// progress of current operation\n\t\t\tuint32 progress{}; // for downloading: in 1/10th of a percent (0-1000), for installing: number of files\n\t\t\tuint32 progressMax{}; // maximum (downloading: unused, installing: total number of files)\n\t\t\t// installing\n\t\t\tbool isInstalling{};\n\t\t\t// error state\n\t\t\tbool hasError{};\n\t\t\tstd::string errorMsg;\n\t\t}state;\n\t};\n\n\tstd::recursive_mutex m_mutex;\n\tstd::vector<Package*> m_packageList;\n\npublic:\n\tvoid initiateDownload(uint64 titleId, uint16 version);\n\tvoid pauseDownload(uint64 titleId, uint16 version);\n\nprivate:\n\tPackage* getPackage(uint64 titleId, uint16 version);\n\tfs::path getPackageDownloadPath(Package* package);\n\tfs::path getPackageInstallPath(Package* package);\n\tvoid updatePackage(Package* package);\n\tvoid checkPackagesState();\n\n\tvoid setPackageError(Package* package, std::string errorMsg);\n\tvoid reportPackageStatus(Package* package);\n\tvoid reportPackageProgress(Package* package, uint32 newProgress);\n\n\tvoid asyncPackageDownloadTMD(Package* package);\n\tvoid calcPackageDownloadProgress(Package* package);\n\tvoid asyncPackageDownloadContentFile(Package* package, uint16 index);\n\tvoid asyncPackageVerifyFile(Package* package, uint16 index, bool isCheckState);\n\tvoid asyncPackageInstall(Package* package);\n\tbool asyncPackageInstallRecursiveExtractFiles(Package* package, class FSTVolume* fstVolume, const std::string& sourcePath, const fs::path& destinationPath);\n\n\t/* callback interface */\npublic:\n\tvoid setUserData(void* ptr)\n\t{\n\t\tm_userData = ptr;\n\t}\n\n\tvoid* getUserData() const\n\t{\n\t\treturn m_userData;\n\t}\n\n\t// register/unregister callbacks\n\t// setting valid callbacks will also trigger transfer of the entire title/package state and the current status message\n\tvoid registerCallbacks(\n\t\tvoid(*cbUpdateConnectStatus)(std::string statusText, DLMGR_STATUS_CODE statusCode),\n\t\tvoid(*cbAddDownloadableTitle)(const DlMgrTitleReport& titleInfo),\n\t\tvoid(*cbRemoveDownloadableTitle)(uint64 titleId, uint16 version)\n\t)\n\t{\n\t\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\t\tm_cbUpdateConnectStatus = cbUpdateConnectStatus;\n\t\tm_cbAddDownloadableTitle = cbAddDownloadableTitle;\n\t\tm_cbRemoveDownloadableTitle = cbRemoveDownloadableTitle;\n\t\t// resend data\n\t\tif (m_cbUpdateConnectStatus || m_cbAddDownloadableTitle)\n\t\t{\n\t\t\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\t\t\tsetStatusMessage(m_statusMessage, m_statusCode);\n\t\t\treportAvailableTitles();\n\t\t\tfor (auto& p : m_packageList)\n\t\t\t\treportPackageStatus(p);\n\t\t}\n\t}\n\n\tvoid setStatusMessage(std::string_view msg, DLMGR_STATUS_CODE statusCode)\n\t{\n\t\tm_statusMessage = msg;\n\t\tm_statusCode = statusCode;\n\t\tif (m_cbUpdateConnectStatus)\n\t\t\tm_cbUpdateConnectStatus(m_statusMessage, statusCode);\n\t}\n\n\tstd::string m_statusMessage{};\n\tDLMGR_STATUS_CODE m_statusCode{ DLMGR_STATUS_CODE::UNINITIALIZED };\n\n\tbool hasActiveDownloads()\n\t{\n\t\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\t\tfor (auto& p : m_packageList)\n\t\t{\n\t\t\tif (p->state.isActive && !p->state.hasError &&\n\t\t\t\t(p->state.currentState != Package::STATE::INSTALLED))\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tvoid reset()\n\t{\n\t\tstd::unique_lock<std::recursive_mutex> _l(m_mutex);\n\t\tm_packageList.clear();\n\t\tm_statusCode = DLMGR_STATUS_CODE::UNINITIALIZED;\n\t\tm_statusMessage.clear();\n\t}\n\nprivate:\n\tvoid(*m_cbUpdateConnectStatus)(std::string statusText, DLMGR_STATUS_CODE statusCode) { nullptr };\n\tvoid(*m_cbAddDownloadableTitle)(const DlMgrTitleReport& titleInfo);\n\tvoid(*m_cbRemoveDownloadableTitle)(uint64 titleId, uint16 version);\n\tvoid* m_userData{};\n\n\t/* title version list */\n\tbool m_hasTitleVersionList{};\n\tstd::unordered_map<uint64, uint16> m_titleVersionList;\n\n\tvoid downloadTitleVersionList();\n\tbool getTitleLatestVersion(TitleId titleId, uint16& version);\n\n\t/* helper for building list of owned titles (is installed or has cached ticket) */\n\tstruct TitleInstallState\n\t{\n\t\tTitleInstallState(DownloadManager* dlMgr, uint64 titleId);\n\n\t\tuint64 titleId;\n\t\tbool isInstalled;\n\t\tuint16 installedTitleVersion;\n\t\tuint16 installedTicketVersion{};\n\n\t\tbool operator<(const TitleInstallState& comp) const\n\t\t{\n\t\t\treturn this->titleId < comp.titleId;\n\t\t}\n\t};\n\n\tstruct TitleDownloadAvailableState : TitleInstallState\n\t{\n\t\tTitleDownloadAvailableState(DownloadManager* dlMgr, uint64 titleId);\n\n\t\tbool isUpdateAvailable; // update available for this specific titleId\n\t\tuint16 availableTitleVersion;\n\t};\n\n\tstd::set<TitleInstallState> getOwnedTitleList();\n\tstd::set<TitleDownloadAvailableState> getFullDownloadList();\n\n\t/* thread */\n\tvoid threadFunc();\n\tvoid runManager();\n\tvoid notifyManager();\n\tvoid queueManagerJob(const std::function<void()>& callback);\n\n\tstd::atomic_bool m_threadLaunched{ false };\n\tCounterSemaphore m_queuedEvents;\n\n\tConcurrentQueue<std::function<void()>> m_jobQueue;\n\n\tstd::mutex m_updateList; // not needed?\n};\n"
  },
  {
    "path": "src/Cemu/napi/napi.h",
    "content": "#pragma once\n#include \"config/CemuConfig.h\" // for ConsoleLanguage\n#include \"config/NetworkSettings.h\" // for NetworkService\n#include \"config/ActiveSettings.h\" // for GetNetworkService()\n\nenum class NAPI_RESULT\n{\n\tSUCCESS = 0,\n\tFAILED = 1, // general failure\n\tXML_ERROR = 2, // XML response unexpected\n\tDATA_ERROR = 3, // incorrect values\n\tSERVICE_ERROR = 4, // server reply indicates error. Extended error code (serviceError) is set\n};\n\nnamespace NAPI\n{\n\t// common auth info structure shared by ACT, ECS and IAS service\n\tstruct AuthInfo\n\t{\n\t\t// nnid\n\t\tstd::string accountId;\n\t\tstd::array<uint8, 32> passwordHash;\n\t\t// console\n\t\tuint32 deviceId;\n\t\tstd::string serial;\n\t\tCafeConsoleRegion region;\n\t\tstd::string country;\n\t\tstd::string deviceCertBase64;\n\n\t\tuint64 getDeviceIdWithPlatform()\n\t\t{\n\t\t\tuint64 deviceType = 5;\n\t\t\treturn (deviceType << 32) | ((uint64)deviceId);\n\t\t}\n\n\t\t// IAS token (for ECS and other SOAP service requests)\n\t\tstruct \n\t\t{\n\t\t\tstd::string accountId; // console account id\n\t\t\tstd::string deviceToken;\n\t\t}IASToken;\n\n\t\t// service selection, if not set fall back to global setting\n\t\tstd::optional<NetworkService> serviceOverwrite;\n\n\t\tNetworkService GetService() const\n\t\t{\n\t\t\treturn serviceOverwrite.value_or(ActiveSettings::GetNetworkService());\n\t\t}\n\t};\n\n\tbool NAPI_MakeAuthInfoFromCurrentAccount(AuthInfo& authInfo); // helper function. Returns false if online credentials/dumped files are not available\n\n\t/* Shared result */\n\n\t// ErrorCodes IAS:\n\t//\t928\t\t-> IAS - Device cert does not verify.\n\t//  954     -> IAS - Invalid Challenge\n\n\tenum class EC_ERROR_CODE\n\t{\n\t\tNONE = 0,\n\t\tECS_INVALID_DEVICE_TOKEN = 903,\n\t\tIAS_DEVICE_CERT_ERROR = 928, // either invalid signature or mismatching incorrect device cert chain\n\t\tIAS_INVALID_CHALLENGE = 954,\n\t\tECS_NO_PERMISSION = 701, // AccountGetETickets\n\t\tNUS_SOAP_INVALID_VERSION = 1301, // seen when accidentally passing wrong SOAP version to GetSystemCommonETicket\n\t};\n\n\tenum class ACT_ERROR_CODE // are these shared with EC_ERROR_CODE?\n\t{\n\t\tNONE = 0,\n\t\tACT_GAME_SERVER_NOT_FOUND = 1021, // seen when passing wrong serverId to nex token request\n\t};\n\n\tstruct _NAPI_CommonResultSOAP\n\t{\n\t\tNAPI_RESULT apiError{ NAPI_RESULT::FAILED };\n\t\tEC_ERROR_CODE serviceError{ EC_ERROR_CODE::NONE };\n\n\t\tbool isValid() const\n\t\t{\n\t\t\treturn apiError == NAPI_RESULT::SUCCESS;\n\t\t}\n\t};\n\n\tstruct _NAPI_CommonResultACT\n\t{\n\t\tNAPI_RESULT apiError{ NAPI_RESULT::FAILED };\n\t\tACT_ERROR_CODE serviceError{ ACT_ERROR_CODE::NONE };\n\n\t\tbool isValid() const\n\t\t{\n\t\t\treturn apiError == NAPI_RESULT::SUCCESS;\n\t\t}\n\t};\n\n\t/* account service (account.nintendo.net) */\n\n\tstruct ACTGetProfileResult \n\t{\n\t\tint todo;\n\t};\n\n\tbool ACT_GetProfile(AuthInfo& authInfo, ACTGetProfileResult& result);\n\n\tstruct ACTNexToken\n\t{\n\t\t/* +0x000 */ char token[0x201];\n\t\t/* +0x201 */ uint8 _padding201[3];\n\t\t/* +0x204 */ char nexPassword[0x41];\n\t\t/* +0x245 */ uint8 _padding245[3];\n\t\t/* +0x248 */ char host[0x10];\n\t\t/* +0x258 */ uint16be port;\n\t\t/* +0x25A */ uint8 _padding25A[2];\n\t};\n\n\tstatic_assert(sizeof(ACTNexToken) == 0x25C);\n\n\tstruct ACTGetNexTokenResult : public _NAPI_CommonResultACT\n\t{\n\t\tACTNexToken nexToken;\n\t};\n\n\tACTGetNexTokenResult ACT_GetNexToken_WithCache(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion, uint32 serverId);\n\n\tstruct ACTGetIndependentTokenResult : public _NAPI_CommonResultACT\n\t{\n\t\tstd::string token;\n\t\tsint64 expiresIn{};\n\t};\n\n\tACTGetIndependentTokenResult ACT_GetIndependentToken_WithCache(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion, std::string_view clientId);\n\n\tstruct ACTConvertNnidToPrincipalIdResult : public _NAPI_CommonResultACT\n\t{\n\t\tbool isFound{false};\n\t\tuint32 principalId{};\n\t};\n\n\tACTConvertNnidToPrincipalIdResult ACT_ACTConvertNnidToPrincipalId(AuthInfo& authInfo, std::string_view nnid);\n\n\t/* NUS */\n\n\tstruct NAPI_NUSGetSystemCommonETicket_Result : public _NAPI_CommonResultSOAP\n\t{\n\t\tstd::vector<uint8> eTicket;\n\t\tstd::vector<std::vector<uint8>> certs;\n\t};\n\n\tNAPI_NUSGetSystemCommonETicket_Result NUS_GetSystemCommonETicket(AuthInfo& authInfo, uint64 titleId);\n\n\t/* IAS/ECS */\n\t\n\tstruct NAPI_IASGetChallenge_Result : public _NAPI_CommonResultSOAP\n\t{\n\t\tstd::string challenge;\n\t};\n\n\tstruct NAPI_IASGetRegistrationInfo_Result : public _NAPI_CommonResultSOAP\n\t{\n\t\tstd::string accountId;\n\t\tstd::string deviceToken;\n\t};\n\n\tstruct NAPI_ECSGetAccountStatus_Result : public _NAPI_CommonResultSOAP\n\t{\n\t\tenum class AccountStatus\n\t\t{\n\t\t\tREGISTERED = 'R',\n\t\t\tTRANSFERRED = 'T',\n\t\t\tUNREGISTERED = 'U',\n\t\t\tUNKNOWN = '\\0',\n\t\t};\n\n\t\tstd::string accountId;\n\t\tAccountStatus accountStatus{ AccountStatus::UNKNOWN };\n\n\t\tstruct \n\t\t{\n\t\t\tstd::string ContentPrefixURL;\n\t\t\tstd::string UncachedContentPrefixURL;\n\t\t\tstd::string SystemContentPrefixURL;\n\t\t\tstd::string SystemUncachedContentPrefixURL;\n\t\t\tstd::string EcsURL;\n\t\t\tstd::string IasURL;\n\t\t\tstd::string CasURL;\n\t\t\tstd::string NusURL;\n\t\t}serviceURLs;\n\t};\n\n\tstruct NAPI_ECSAccountListETicketIds_Result : public _NAPI_CommonResultSOAP\n\t{\n\t\tstruct TIV\n\t\t{\n\t\t\tsint64 ticketId;\n\t\t\tuint32 ticketVersion;\n\t\t};\n\n\t\tstd::vector<TIV> tivs;\n\t};\n\n\tstruct NAPI_ECSAccountGetETickets_Result : public _NAPI_CommonResultSOAP\n\t{\n\t\tstd::vector<uint8> eTickets;\n\t\tstd::vector<std::vector<uint8>> certs;\n\t};\n\n\tNAPI_IASGetChallenge_Result IAS_GetChallenge(AuthInfo& authInfo);\n\tNAPI_IASGetRegistrationInfo_Result IAS_GetRegistrationInfo_QueryInfo(AuthInfo& authInfo, std::string challenge);\n\n\tNAPI_ECSGetAccountStatus_Result ECS_GetAccountStatus(AuthInfo& authInfo);\n\tNAPI_ECSAccountListETicketIds_Result ECS_AccountListETicketIds(AuthInfo& authInfo);\n\tNAPI_ECSAccountGetETickets_Result ECS_AccountGetETickets(AuthInfo& authInfo, sint64 ticketId);\n\n\t/* CCS */\n\n\tstruct NAPI_CCSGetTMD_Result\n\t{\n\t\tbool isValid{ false };\n\t\tstd::vector<uint8> tmdData;\n\t};\n\n\tstruct NAPI_CCSGetETicket_Result\n\t{\n\t\tbool isValid{ false };\n\t\tstd::vector<uint8> cetkData;\n\t};\n\n\tstruct NAPI_CCSGetContentH3_Result\n\t{\n\t\tbool isValid{ false };\n\t\tstd::vector<uint8> tmdData;\n\t};\n\n\tNAPI_CCSGetTMD_Result CCS_GetTMD(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion);\n\tNAPI_CCSGetTMD_Result CCS_GetTMD(AuthInfo& authInfo, uint64 titleId);\n\tNAPI_CCSGetETicket_Result CCS_GetCETK(NetworkService service, uint64 titleId, uint16 titleVersion);\n\tbool CCS_GetContentFile(NetworkService service, uint64 titleId, uint32 contentId, bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData);\n\tNAPI_CCSGetContentH3_Result CCS_GetContentH3File(NetworkService service, uint64 titleId, uint32 contentId);\n\n\t/* IDBE */\n\n\tstruct IDBEIconDataV0\n\t{\n\t\tstruct LanguageInfo\n\t\t{\n\t\t\tstd::string GetGameNameUTF8();\n\t\t\tstd::string GetGameLongNameUTF8();\n\t\t\tstd::string GetPublisherNameUTF8();\n\t\tprivate:\n\t\t\tuint16be gameName[0x40]{};\n\t\t\tuint16be gameLongName[0x80]{};\n\t\t\tuint16be publisherName[0x40]{};\n\t\t};\n\n\t\tLanguageInfo& GetLanguageStrings(CafeConsoleLanguage index)\n\t\t{\n\t\t\tif ((uint32)index >= 16)\n\t\t\t\treturn languageInfo[0];\n\t\t\treturn languageInfo[(uint32)index];\n\t\t}\n\n\tprivate:\n\t\t/* +0x00000 */ uint32be titleIdHigh{};\n\t\t/* +0x00004 */ uint32be titleIdLow{};\n\t\t/* +0x00008 */ uint32 ukn00008;\n\t\t/* +0x0000C */ uint32 ukn0000C;\n\t\t/* +0x00010 */ uint32 ukn00010;\n\t\t/* +0x00014 */ uint32 ukn00014;\n\t\t/* +0x00018 */ uint32 ukn00018;\n\t\t/* +0x0001C */ uint32 ukn0001C;\n\t\t/* +0x00020 */ uint32 ukn00020;\n\t\t/* +0x00024 */ uint32 ukn00024;\n\t\t/* +0x00028 */ uint32 ukn00028;\n\t\t/* +0x0002C */ uint32 ukn0002C;\n\t\t/* +0x00030 */ LanguageInfo languageInfo[16];\n\t\t/* +0x02030 */ uint8 tgaData[0x10030]{};\n\t};\n\n\tstatic_assert(sizeof(IDBEIconDataV0) == 0x12060);\n\n\tstruct IDBEHeader\n\t{\n\t\tuint8 formatVersion;\n\t\tuint8 keyIndex;\n\t\tuint8 hashSHA256[32];\n\t};\n\n\tstatic_assert(sizeof(IDBEHeader) == 2+32);\n\n\tstd::optional<IDBEIconDataV0> IDBE_Request(NetworkService networkService, uint64 titleId);\n\tstd::vector<uint8> IDBE_RequestRawEncrypted(NetworkService networkService, uint64 titleId); // same as IDBE_Request but doesn't strip the header and decrypt the IDBE\n\n\t/* Version list */\n\n\tstruct NAPI_VersionListVersion_Result\n\t{\n\t\tbool isValid{false};\n\t\tuint32 version{0};\n\t\tstd::string fqdnURL;\n\t};\n\n\tNAPI_VersionListVersion_Result TAG_GetVersionListVersion(AuthInfo& authInfo);\n\n\tstruct NAPI_VersionList_Result\n\t{\n\t\tbool isValid{ false };\n\t\tstd::unordered_map<uint64, uint16> titleVersionList; // key = titleId, value = version\n\t};\n\n\tNAPI_VersionList_Result TAG_GetVersionList(AuthInfo& authInfo, std::string_view fqdnURL, uint32 versionListVersion);\n\n}\n\nvoid NAPI_NUS_GetSystemUpdate();\nvoid NAPI_NUS_GetSystemTitleHash();\n"
  },
  {
    "path": "src/Cemu/napi/napi_act.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"napi.h\"\n#include \"napi_helper.h\"\n\n#include \"curl/curl.h\"\n#include \"pugixml.hpp\"\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n\n#include \"config/ActiveSettings.h\"\n#include \"util/helpers/StringHelpers.h\"\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n#include \"config/LaunchSettings.h\"\n\nnamespace NAPI\n{\n\tstd::string _getACTUrl(NetworkService service)\n\t{\n\t\tswitch (service)\n\t\t{\n\t\tcase NetworkService::Nintendo:\n\t\t\treturn NintendoURLs::ACTURL;\n\t\tcase NetworkService::Pretendo:\n\t\t\treturn PretendoURLs::ACTURL;\n\t\tcase NetworkService::Custom:\n\t\t\treturn GetNetworkConfig().urls.ACT.GetValue();\n\t\tdefault:\n\t\t\treturn NintendoURLs::ACTURL;\n\t\t}\n\t}\n\n\tstruct ACTOauthToken : public _NAPI_CommonResultACT\n\t{\n\t\tstd::string token;\n\t\tstd::string refreshToken;\n\t};\n\n\tbool _parseActResponse(CurlRequestHelper& requestHelper, _NAPI_CommonResultACT& result, pugi::xml_document& doc)\n\t{\n\t\tif (!doc.load_buffer(requestHelper.getReceivedData().data(), requestHelper.getReceivedData().size()))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Invalid XML in account service response\"));\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn false;\n\t\t}\n\t\t// check for error codes\n\t\tpugi::xml_node errors = doc.child(\"errors\");\n\t\tif (errors)\n\t\t{\n\t\t\tpugi::xml_node error = errors.child(\"error\");\n\t\t\tif (error)\n\t\t\t{\n\t\t\t\tstd::string_view errorCodeStr = error.child_value(\"code\");\n\t\t\t\tstd::string_view errorCodeMsg = error.child_value(\"message\");\n\t\t\t\tsint32 errorCode = StringHelpers::ToInt(errorCodeStr);\n\t\t\t\tif (errorCode == 0)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Account response with unexpected error code 0\");\n\t\t\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tresult.apiError = NAPI_RESULT::SERVICE_ERROR;\n\t\t\t\t\tresult.serviceError = (ACT_ERROR_CODE)errorCode;\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Account response with error code {}\", errorCode);\n\t\t\t\t\tif(!errorCodeMsg.empty())\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"Message from server: {}\", errorCodeMsg);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid _ACTSetCommonHeaderParameters(CurlRequestHelper& req, AuthInfo& authInfo)\n\t{\n\t\treq.addHeaderField(\"X-Nintendo-Platform-ID\", \"1\");\n\t\treq.addHeaderField(\"X-Nintendo-Device-Type\", \"2\");\n\n\t\treq.addHeaderField(\"X-Nintendo-Client-ID\", \"a2efa818a34fa16b8afbc8a74eba3eda\");\n\t\treq.addHeaderField(\"X-Nintendo-Client-Secret\", \"c91cdb5658bd4954ade78533a339cf9a\");\n\n\t\treq.addHeaderField(\"Accept\", \"*/*\");\n\n\t\tif(authInfo.region == CafeConsoleRegion::USA)\n\t\t\treq.addHeaderField(\"X-Nintendo-System-Version\", \"0270\");\n\t\telse\n\t\t\treq.addHeaderField(\"X-Nintendo-System-Version\", \"0260\");\n\t}\n\n\tvoid _ACTSetDeviceParameters(CurlRequestHelper& req, AuthInfo& authInfo)\n\t{\n\t\treq.addHeaderField(\"X-Nintendo-Device-ID\", fmt::format(\"{}\", authInfo.deviceId)); // deviceId without platform field\n\t\treq.addHeaderField(\"X-Nintendo-Serial-Number\", authInfo.serial);\n\t}\n\n\tvoid _ACTSetRegionAndCountryParameters(CurlRequestHelper& req, AuthInfo& authInfo)\n\t{\n\t\treq.addHeaderField(\"X-Nintendo-Region\", fmt::format(\"{}\", (uint32)authInfo.region));\n\t\treq.addHeaderField(\"X-Nintendo-Country\", authInfo.country);\n\t}\n\n\tstruct OAuthTokenCacheEntry \n\t{\n\t\tOAuthTokenCacheEntry(std::string_view accountId, std::array<uint8, 32>& passwordHash, std::string_view token, std::string_view refreshToken, uint64 expiresIn, NetworkService service) : accountId(accountId), passwordHash(passwordHash), token(token), refreshToken(refreshToken), service(service)\n\t\t{\n\t\t\texpires = HighResolutionTimer::now().getTickInSeconds() + expiresIn;\n\t\t};\n\n\t\tbool CheckIfSameAccount(const AuthInfo& authInfo) const\n\t\t{\n\t\t\treturn authInfo.accountId == accountId && authInfo.passwordHash == passwordHash;\n\t\t}\n\n\t\tbool CheckIfExpired() const\n\t\t{\n\t\t\treturn HighResolutionTimer::now().getTickInSeconds() >= expires;\n\t\t}\n\t\tstd::string accountId;\n\t\tstd::array<uint8, 32> passwordHash;\n\t\tstd::string token;\n\t\tstd::string refreshToken;\n\t\tuint64 expires;\n\t\tNetworkService service;\n\t};\n\n\tstd::vector<OAuthTokenCacheEntry> g_oauthTokenCache;\n\tstd::mutex g_oauthTokenCacheMtx;\n\n\t// look up oauth token in cache, otherwise request from server\n\tACTOauthToken ACT_GetOauthToken_WithCache(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion)\n\t{\n\t\tACTOauthToken result{};\n\t\t\n\t\t// check cache first\n\t\tNetworkService service = authInfo.GetService();\n\t\tg_oauthTokenCacheMtx.lock();\n\t\tauto cacheItr = g_oauthTokenCache.begin();\n\t\twhile (cacheItr != g_oauthTokenCache.end())\n\t\t{\n\t\t\tif (cacheItr->CheckIfSameAccount(authInfo) && cacheItr->service == service)\n\t\t\t{\n\t\t\t\tif (cacheItr->CheckIfExpired())\n\t\t\t\t{\n\t\t\t\t\tcacheItr = g_oauthTokenCache.erase(cacheItr);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tresult.token = cacheItr->token;\n\t\t\t\tresult.refreshToken = cacheItr->refreshToken;\n\t\t\t\tresult.apiError = NAPI_RESULT::SUCCESS;\n\t\t\t\tg_oauthTokenCacheMtx.unlock();\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tcacheItr++;\n\t\t}\n\t\tg_oauthTokenCacheMtx.unlock();\n\t\t// token not cached, request from server via oauth2\n\t\tCurlRequestHelper req;\n\n\t\treq.initate(authInfo.GetService(), fmt::format(\"{}/v1/api/oauth20/access_token/generate\", _getACTUrl(authInfo.GetService())), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);\n\t\t_ACTSetCommonHeaderParameters(req, authInfo);\n\t\t_ACTSetDeviceParameters(req, authInfo);\n\t\t_ACTSetRegionAndCountryParameters(req, authInfo);\n\t\treq.addHeaderField(\"X-Nintendo-Device-Cert\", authInfo.deviceCertBase64);\n\n\t\treq.addHeaderField(\"X-Nintendo-FPD-Version\", \"0000\");\n\t\treq.addHeaderField(\"X-Nintendo-Environment\", \"L1\");\n\t\treq.addHeaderField(\"X-Nintendo-Title-ID\", fmt::format(\"{:016x}\", titleId));\n\t\tuint32 uniqueId = ((titleId >> 8) & 0xFFFFF);\n\t\treq.addHeaderField(\"X-Nintendo-Unique-ID\", fmt::format(\"{:05x}\", uniqueId));\n\t\treq.addHeaderField(\"X-Nintendo-Application-Version\", fmt::format(\"{:04x}\", titleVersion));\n\n\t\t// convert password hash to string\n\t\tchar passwordHashString[128];\n\t\tfor (sint32 i = 0; i < 32; i++)\n\t\t\tsprintf(passwordHashString + i * 2, \"%02x\", authInfo.passwordHash[i]);\n\t\treq.addPostField(\"grant_type\", \"password\");\n\t\treq.addPostField(\"user_id\", authInfo.accountId);\n\t\treq.addPostField(\"password\", passwordHashString);\n\t\treq.addPostField(\"password_type\", \"hash\");\n\n\t\treq.addHeaderField(\"Content-type\", \"application/x-www-form-urlencoded\");\n\n\t\tif (!req.submitRequest(true))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed request /oauth20/access_token/generate\"));\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\t/*\n\t\t Response example:\n\t\t <OAuth20>\n\t\t <access_token>\n\t\t <token>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</token>\n\t\t <refresh_token>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</refresh_token>\n\t\t <expires_in>3600</expires_in>\n\t\t </access_token>\n\t\t </OAuth20>\n\t\t*/\n\n\t\t// parse result\n\t\tpugi::xml_document doc;\n\t\tif (!_parseActResponse(req, result, doc))\n\t\t\treturn result;\n\t\tpugi::xml_node node = doc.child(\"OAuth20\");\n\t\tif (!node)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Response does not contain OAuth20 node\"));\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn result;\n\t\t}\n\t\tnode = node.child(\"access_token\");\n\t\tif (!node)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Response does not contain OAuth20/access_token node\"));\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn result;\n\t\t}\n\n\t\tresult.token = node.child_value(\"token\");\n\t\tresult.refreshToken = node.child_value(\"refresh_token\");\n\t\tstd::string_view expires_in = node.child_value(\"expires_in\");\n\t\tresult.apiError = NAPI_RESULT::SUCCESS;\n\n\t\tif (result.token.empty())\n\t\t\tcemuLog_log(LogType::Force, \"OAuth20/token is empty\");\n\t\tsint64 expiration = StringHelpers::ToInt64(expires_in);\n\t\texpiration = std::max(expiration - 30LL, 0LL); // subtract a few seconds to compensate for the web request delay\n\n\t\t// update cache\n\t\tif (expiration > 0)\n\t\t{\n\t\t\tg_oauthTokenCacheMtx.lock();\n\t\t\tg_oauthTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, result.token, result.refreshToken, expiration, service);\n\t\t\tg_oauthTokenCacheMtx.unlock();\n\t\t}\n\t\treturn result;\n\t}\n\n\tbool ACT_GetProfile(AuthInfo& authInfo, ACTGetProfileResult& result)\n\t{\n\t\tCurlRequestHelper req;\n\n\t\treq.initate(authInfo.GetService(), fmt::format(\"{}/v1/api/people/@me/profile\", _getACTUrl(authInfo.GetService())), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);\n\n\t\t_ACTSetCommonHeaderParameters(req, authInfo);\n\t\t_ACTSetDeviceParameters(req, authInfo);\n\n\t\t// get oauth2 token\n\t\tACTOauthToken oauthToken = ACT_GetOauthToken_WithCache(authInfo, 0x0005001010001C00, 0x0001C);\n\n\t\tcemu_assert_unimplemented();\n\t\treturn true;\n\t}\n\n\tstruct NexTokenCacheEntry\n\t{\n\t\tNexTokenCacheEntry(std::string_view accountId, std::array<uint8, 32>& passwordHash, NetworkService networkService, uint32 gameServerId, ACTNexToken& nexToken) : accountId(accountId), passwordHash(passwordHash), networkService(networkService), nexToken(nexToken), gameServerId(gameServerId) {};\n\n\t\tbool IsMatch(const AuthInfo& authInfo, const uint32 gameServerId) const\n\t\t{\n\t\t\treturn authInfo.accountId == accountId && authInfo.passwordHash == passwordHash && authInfo.GetService() == networkService && this->gameServerId == gameServerId;\n\t\t}\n\n\t\tstd::string accountId;\n\t\tstd::array<uint8, 32> passwordHash;\n\t\tNetworkService networkService;\n\t\tuint32 gameServerId;\n\n\t\tACTNexToken nexToken;\n\t};\n\n\tstd::vector<NexTokenCacheEntry> g_nexTokenCache;\n\tstd::mutex g_nexTokenCacheMtx;\n\n\tACTGetNexTokenResult ACT_GetNexToken_WithCache(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion, uint32 serverId)\n\t{\n\t\tACTGetNexTokenResult result{};\n\t\t// check cache\n\t\tg_nexTokenCacheMtx.lock();\n\t\tfor (auto& itr : g_nexTokenCache)\n\t\t{\n\t\t\tif (itr.IsMatch(authInfo, serverId))\n\t\t\t{\n\t\t\t\tresult.nexToken = itr.nexToken;\n\t\t\t\tresult.apiError = NAPI_RESULT::SUCCESS;\n\t\t\t\tg_nexTokenCacheMtx.unlock();\n\t\t\t\treturn result;\n\n\t\t\t}\n\t\t}\n\t\tg_nexTokenCacheMtx.unlock();\n\t\t// get Nex token\n\t\tACTOauthToken oauthToken = ACT_GetOauthToken_WithCache(authInfo, titleId, titleVersion);\n\t\tif (!oauthToken.isValid())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"ACT_GetNexToken(): Failed to retrieve OAuth token\");\n\t\t\tif (oauthToken.apiError == NAPI_RESULT::SERVICE_ERROR)\n\t\t\t{\n\t\t\t\tresult.apiError = NAPI_RESULT::SERVICE_ERROR;\n\t\t\t\tresult.serviceError = oauthToken.serviceError;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult.apiError = NAPI_RESULT::DATA_ERROR;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\t// do request\n\t\tCurlRequestHelper req;\n\t\treq.initate(authInfo.GetService(), fmt::format(\"{}/v1/api/provider/nex_token/@me?game_server_id={:08X}\", _getACTUrl(authInfo.GetService()), serverId), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);\n\t\t_ACTSetCommonHeaderParameters(req, authInfo);\n\t\t_ACTSetDeviceParameters(req, authInfo);\n\t\t_ACTSetRegionAndCountryParameters(req, authInfo);\n\t\treq.addHeaderField(\"X-Nintendo-FPD-Version\", \"0000\");\n\t\treq.addHeaderField(\"X-Nintendo-Environment\", \"L1\");\n\t\treq.addHeaderField(\"X-Nintendo-Title-ID\", fmt::format(\"{:016x}\", titleId));\n\t\tuint32 uniqueId = ((titleId >> 8) & 0xFFFFF);\n\t\treq.addHeaderField(\"X-Nintendo-Unique-ID\", fmt::format(\"{:05x}\", uniqueId));\n\t\treq.addHeaderField(\"X-Nintendo-Application-Version\", fmt::format(\"{:04x}\", titleVersion));\n\n\t\treq.addHeaderField(\"Authorization\", fmt::format(\"Bearer {}\", oauthToken.token));\n\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed request /provider/nex_token/@me\"));\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\t/*\n\t\tExample response (success):\n\t\t<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n\t\t<nex_token>\n\t\t<host>HOST</host>\n\t\t<nex_password>xxxxxxxxxxxxxxxx</nex_password>\n\t\t<pid>123456</pid>\n\t\t<port>60200</port>\n\t\t<token>xxxxxxxxxxxxxxx</token>\n\t\t</nex_token>\n\n\n\t\tExample response (error case):\n\t\t<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n\t\t<errors>\n\t\t<error>\n\t\t<code>1021</code>\n\t\t<message>The requested game server was not found.</message>\n\t\t</error>\n\t\t</errors>\n\t\t*/\n\n\t\t// code 0124 -> Version lower than useable registered\n\n\t\t// parse result\n\t\tpugi::xml_document doc;\n\t\tif (!_parseActResponse(req, result, doc))\n\t\t\treturn result;\n\t\tpugi::xml_node tokenNode = doc.child(\"nex_token\");\n\t\tif (!tokenNode)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Response does not contain NexToken node\");\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn result;\n\t\t}\n\n\t\tstd::string_view host = tokenNode.child_value(\"host\");\n\t\tstd::string_view nex_password = tokenNode.child_value(\"nex_password\");\n\t\tstd::string_view port = tokenNode.child_value(\"port\");\n\t\tstd::string_view token = tokenNode.child_value(\"token\");\n\n\t\tmemset(&result.nexToken, 0, sizeof(ACTNexToken));\n\t\tif (host.size() > 15)\n\t\t\tcemuLog_log(LogType::Force, \"NexToken response: host field too long\");\n\t\tif (nex_password.size() > 64)\n\t\t\tcemuLog_log(LogType::Force, \"NexToken response: nex_password field too long\");\n\t\tif (token.size() > 512)\n\t\t\tcemuLog_log(LogType::Force, \"NexToken response: token field too long\");\n\t\tfor (size_t i = 0; i < std::min(host.size(), (size_t)15); i++)\n\t\t\tresult.nexToken.host[i] = host[i];\n\t\tfor (size_t i = 0; i < std::min(nex_password.size(), (size_t)64); i++)\n\t\t\tresult.nexToken.nexPassword[i] = nex_password[i];\n\t\tfor (size_t i = 0; i < std::min(token.size(), (size_t)512); i++)\n\t\t\tresult.nexToken.token[i] = token[i];\n\t\tresult.nexToken.port = (uint16)StringHelpers::ToInt(port);\n\t\tresult.apiError = NAPI_RESULT::SUCCESS;\n\t\tg_nexTokenCacheMtx.lock();\n\t\tg_nexTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, authInfo.GetService(), serverId, result.nexToken);\n\t\tg_nexTokenCacheMtx.unlock();\n\t\treturn result;\n\t}\n\n\tstruct IndependentTokenCacheEntry\n\t{\n\t\tIndependentTokenCacheEntry(std::string_view accountId, std::array<uint8, 32>& passwordHash, NetworkService networkService, std::string_view clientId, std::string_view independentToken, sint64 expiresIn) : accountId(accountId), passwordHash(passwordHash), networkService(networkService), clientId(clientId), independentToken(independentToken)\n\t\t{\n\t\t\texpires = HighResolutionTimer::now().getTickInSeconds() + expiresIn;\n\t\t};\n\n\t\tbool IsMatch(const AuthInfo& authInfo, const std::string_view clientId) const\n\t\t{\n\t\t\treturn authInfo.accountId == accountId && authInfo.passwordHash == passwordHash && authInfo.GetService() == networkService && this->clientId == clientId;\n\t\t}\n\n\t\tbool CheckIfExpired() const\n\t\t{\n\t\t\treturn (sint64)HighResolutionTimer::now().getTickInSeconds() >= expires;\n\t\t}\n\n\t\tstd::string accountId;\n\t\tstd::array<uint8, 32> passwordHash;\n\t\tNetworkService networkService;\n\t\tstd::string clientId;\n\t\tsint64 expires;\n\n\t\tstd::string independentToken;\n\t};\n\n\tstd::vector<IndependentTokenCacheEntry> g_IndependentTokenCache;\n\tstd::mutex g_IndependentTokenCacheMtx;\n\n\tACTGetIndependentTokenResult ACT_GetIndependentToken_WithCache(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion, std::string_view clientId)\n\t{\n\t\tACTGetIndependentTokenResult result{};\n\t\t// check cache\n\t\tg_IndependentTokenCacheMtx.lock();\n\t\tauto itr = g_IndependentTokenCache.begin();\n\t\twhile(itr != g_IndependentTokenCache.end())\n\t\t{\n\t\t\tif (itr->CheckIfExpired())\n\t\t\t{\n\t\t\t\titr = g_IndependentTokenCache.erase(itr);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if (itr->IsMatch(authInfo, clientId))\n\t\t\t{\n\t\t\t\tresult.token = itr->independentToken;\n\t\t\t\tresult.expiresIn = std::max(itr->expires - (sint64)HighResolutionTimer::now().getTickInSeconds(), (sint64)0);\n\t\t\t\tresult.apiError = NAPI_RESULT::SUCCESS;\n\t\t\t\tg_IndependentTokenCacheMtx.unlock();\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\titr++;\n\t\t}\n\t\tg_IndependentTokenCacheMtx.unlock();\n\t\t// get Independent token\n\t\tACTOauthToken oauthToken = ACT_GetOauthToken_WithCache(authInfo, titleId, titleVersion);\n\t\tif (!oauthToken.isValid())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"ACT_GetIndependentToken(): Failed to retrieve OAuth token\");\n\t\t\tif (oauthToken.apiError == NAPI_RESULT::SERVICE_ERROR)\n\t\t\t{\n\t\t\t\tresult.apiError = NAPI_RESULT::SERVICE_ERROR;\n\t\t\t\tresult.serviceError = oauthToken.serviceError;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult.apiError = NAPI_RESULT::DATA_ERROR;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\t// do request\n\t\tCurlRequestHelper req;\n\t\treq.initate(authInfo.GetService(), fmt::format(\"{}/v1/api/provider/service_token/@me?client_id={}\", _getACTUrl(authInfo.GetService()), clientId), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);\n\t\t_ACTSetCommonHeaderParameters(req, authInfo);\n\t\t_ACTSetDeviceParameters(req, authInfo);\n\t\t_ACTSetRegionAndCountryParameters(req, authInfo);\n\t\treq.addHeaderField(\"X-Nintendo-FPD-Version\", \"0000\");\n\t\treq.addHeaderField(\"X-Nintendo-Environment\", \"L1\");\n\t\treq.addHeaderField(\"X-Nintendo-Title-ID\", fmt::format(\"{:016x}\", titleId));\n\t\tuint32 uniqueId = ((titleId >> 8) & 0xFFFFF);\n\t\treq.addHeaderField(\"X-Nintendo-Unique-ID\", fmt::format(\"{:05x}\", uniqueId));\n\t\treq.addHeaderField(\"X-Nintendo-Application-Version\", fmt::format(\"{:04x}\", titleVersion));\n\n\t\treq.addHeaderField(\"Authorization\", fmt::format(\"Bearer {}\", oauthToken.token));\n\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed request /provider/service_token/@me\"));\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\t/*\n\t\tExample response (success):\n\t\t<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n\t\t<service_token>\n\t\t<token>xxxxxxxxxxxx</token>\n\t\t</service_token>\n\t\t*/\n\n\t\t// parse result\n\t\tpugi::xml_document doc;\n\t\tif (!_parseActResponse(req, result, doc))\n\t\t\treturn result;\n\t\tpugi::xml_node tokenNode = doc.child(\"service_token\");\n\t\tif (!tokenNode)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Response does not contain service_token node\");\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn result;\n\t\t}\n\n\t\tstd::string_view token = tokenNode.child_value(\"token\");\n\t\tresult.token = token;\n\t\tresult.apiError = NAPI_RESULT::SUCCESS;\n\n\t\tg_IndependentTokenCacheMtx.lock();\n\t\tg_IndependentTokenCache.emplace_back(authInfo.accountId, authInfo.passwordHash, authInfo.GetService(), clientId, result.token, 3600);\n\t\tg_IndependentTokenCacheMtx.unlock();\n\t\treturn result;\n\t}\n\n\tACTConvertNnidToPrincipalIdResult ACT_ACTConvertNnidToPrincipalId(AuthInfo& authInfo, std::string_view nnid)\n\t{\n\t\tACTConvertNnidToPrincipalIdResult result{};\n\t\t// get Independent token\n\t\tACTOauthToken oauthToken = ACT_GetOauthToken_WithCache(authInfo, 0x0005001010001C00, 0);\n\t\tif (!oauthToken.isValid())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"ACT_ACTConvertNnidToPrincipalId(): Failed to retrieve OAuth token\");\n\t\t\tif (oauthToken.apiError == NAPI_RESULT::SERVICE_ERROR)\n\t\t\t{\n\t\t\t\tresult.apiError = NAPI_RESULT::SERVICE_ERROR;\n\t\t\t\tresult.serviceError = oauthToken.serviceError;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult.apiError = NAPI_RESULT::DATA_ERROR;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\t// do request\n\t\tCurlRequestHelper req;\n\t\treq.initate(authInfo.GetService(), fmt::format(\"{}/v1/api/admin/mapped_ids?input_type=user_id&output_type=pid&input={}\", _getACTUrl(authInfo.GetService()), nnid), CurlRequestHelper::SERVER_SSL_CONTEXT::ACT);\n\t\t_ACTSetCommonHeaderParameters(req, authInfo);\n\t\t_ACTSetDeviceParameters(req, authInfo);\n\t\t_ACTSetRegionAndCountryParameters(req, authInfo);\n\t\treq.addHeaderField(\"X-Nintendo-FPD-Version\", \"0000\");\n\t\treq.addHeaderField(\"X-Nintendo-Environment\", \"L1\");\n\t\treq.addHeaderField(\"X-Nintendo-Title-ID\", fmt::format(\"{:016x}\", 0x0005001010001C00));\n\t\tuint32 uniqueId = 0x50010;\n\t\treq.addHeaderField(\"X-Nintendo-Unique-ID\", fmt::format(\"{:05x}\", uniqueId));\n\t\treq.addHeaderField(\"X-Nintendo-Application-Version\", fmt::format(\"{:04x}\", 0));\n\n\t\treq.addHeaderField(\"Authorization\", fmt::format(\"Bearer {}\", oauthToken.token));\n\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed request /admin/mapped_ids\"));\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\t/*\n\t\tExample response (success):\n\t\t<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n\t\t<mapped_ids>\n\t\t<mapped_id>\n\t\t<in_id>input-nnid</in_id>\n\t\t<out_id>12345</out_id>\n\t\t</mapped_id>\n\t\t</mapped_ids>\n\t\t*/\n\n\t\t// parse result\n\t\tpugi::xml_document doc;\n\t\tif (!_parseActResponse(req, result, doc))\n\t\t\treturn result;\n\t\tpugi::xml_node tokenNode = doc.child(\"mapped_ids\");\n\t\tif (!tokenNode)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Response does not contain mapped_ids node\");\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn result;\n\t\t}\n\t\ttokenNode = tokenNode.child(\"mapped_id\");\n\t\tif (!tokenNode)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Response does not contain mapped_id node\");\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn result;\n\t\t}\n\t\tstd::string_view pidString = tokenNode.child_value(\"out_id\");\n\t\tif (!pidString.empty())\n\t\t{\n\t\t\tresult.isFound = true;\n\t\t\tresult.principalId = StringHelpers::ToInt(pidString);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult.isFound = false;\n\t\t\tresult.principalId = 0;\n\t\t}\n\t\tresult.apiError = NAPI_RESULT::SUCCESS;\n\t\treturn result;\n\t}\n\n\tbool NAPI_MakeAuthInfoFromCurrentAccount(AuthInfo& authInfo)\n\t{\n\t\tauthInfo = {};\n\t\tif (!NCrypto::SEEPROM_IsPresent())\n\t\t\treturn false;\n\t\tconst Account& account = Account::GetCurrentAccount();\n\t\tauthInfo.accountId = account.GetAccountId();\n\t\tauto passwordHash = account.GetAccountPasswordCache();\n\t\tauthInfo.passwordHash = passwordHash;\n\t\tif (std::all_of(passwordHash.cbegin(), passwordHash.cend(), [](uint8 v) { return v == 0; }))\n\t\t{\n\t\t\tstatic bool s_showedLoginError = false;\n\t\t\tif (!s_showedLoginError)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Account login is impossible because the cached password hash is not set\");\n\t\t\t\ts_showedLoginError = true;\n\t\t\t}\n\t\t\treturn false; // password hash not set\n\t\t}\n\t\tauthInfo.deviceId = NCrypto::GetDeviceId();\t\t\n\t\tauthInfo.serial = NCrypto::GetSerial();\n\t\tauthInfo.region = NCrypto::SEEPROM_GetRegion();\n\t\tauthInfo.country = NCrypto::GetCountryAsString(account.GetCountry());\n\t\tauthInfo.deviceCertBase64 = NCrypto::CertECC::GetDeviceCertificate().encodeToBase64();\n\n\t\treturn true;\n\t}\n}\n"
  },
  {
    "path": "src/Cemu/napi/napi_ec.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"napi.h\"\n#include \"napi_helper.h\"\n\n#include \"curl/curl.h\"\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"util/crypto/md5.h\"\n#include \"config/LaunchSettings.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/NetworkSettings.h\"\n#include \"pugixml.hpp\"\n#include <charconv>\n\nnamespace NAPI\n{\n\t/* Service URL manager */\n\tstruct CachedServiceUrls\n\t{\n\t\tstd::string s_serviceURL_ContentPrefixURL;\n\t\tstd::string s_serviceURL_UncachedContentPrefixURL;\n\t\tstd::string s_serviceURL_EcsURL;\n\t\tstd::string s_serviceURL_IasURL;\n\t\tstd::string s_serviceURL_CasURL;\n\t\tstd::string s_serviceURL_NusURL;\n\t};\n\n\tstd::unordered_map<NetworkService, CachedServiceUrls> s_cachedServiceUrlsMap;\n\n\tCachedServiceUrls& GetCachedServiceUrls(NetworkService service)\n\t{\n\t\treturn s_cachedServiceUrlsMap[service];\n\t}\n\n\tstd::string _getNUSUrl(NetworkService service)\n\t{\n\t\tauto& cachedServiceUrls = GetCachedServiceUrls(service);\n\t\tif (!cachedServiceUrls.s_serviceURL_NusURL.empty())\n\t\t\treturn cachedServiceUrls.s_serviceURL_NusURL;\n\t\tswitch (service)\n\t\t{\n\t\tcase NetworkService::Nintendo:\n\t\t\treturn NintendoURLs::NUSURL;\n\t\tcase NetworkService::Pretendo:\n\t\t\treturn PretendoURLs::NUSURL;\n\t\tcase NetworkService::Custom:\n\t\t\treturn GetNetworkConfig().urls.NUS;\n\t\tdefault:\n\t\t\treturn NintendoURLs::NUSURL;\n\t\t}\n\t}\n\n\tstd::string _getIASUrl(NetworkService service)\n\t{\n\t\tauto& cachedServiceUrls = GetCachedServiceUrls(service);\n\t\tif (!cachedServiceUrls.s_serviceURL_IasURL.empty())\n\t\t\treturn cachedServiceUrls.s_serviceURL_IasURL;\n\t\tswitch (service)\n\t\t{\n\t\tcase NetworkService::Nintendo:\n\t\t\treturn NintendoURLs::IASURL;\n\t\tcase NetworkService::Pretendo:\n\t\t\treturn PretendoURLs::IASURL;\n\t\tcase NetworkService::Custom:\n\t\t\treturn GetNetworkConfig().urls.IAS;\n\t\tdefault:\n\t\t\treturn NintendoURLs::IASURL;\n\t\t}\n\t}\n\n\tstd::string _getECSUrl(NetworkService service)\n\t{\n\t\t// this is the first url queried (GetAccountStatus). The others are dynamically set if provided by the server but will fallback to hardcoded defaults otherwise\n\t\tauto& cachedServiceUrls = GetCachedServiceUrls(service);\n\t\tif (!cachedServiceUrls.s_serviceURL_EcsURL.empty())\n\t\t\treturn cachedServiceUrls.s_serviceURL_EcsURL;\n\t\tswitch (service)\n\t\t{\n\t\tcase NetworkService::Nintendo:\n\t\t\treturn NintendoURLs::ECSURL;\n\t\tcase NetworkService::Pretendo:\n\t\t\treturn PretendoURLs::ECSURL;\n\t\tcase NetworkService::Custom:\n\t\t\treturn GetNetworkConfig().urls.ECS;\n\t\tdefault:\n\t\t\treturn NintendoURLs::ECSURL;\n\t\t}\n\t}\n\n\tstd::string _getCCSUncachedUrl(NetworkService service) // used for TMD requests\n\t{\n\t\tauto& cachedServiceUrls = GetCachedServiceUrls(service);\n\t\tif (!cachedServiceUrls.s_serviceURL_UncachedContentPrefixURL.empty())\n\t\t\treturn cachedServiceUrls.s_serviceURL_UncachedContentPrefixURL;\n\t\tswitch (service)\n\t\t{\n\t\tcase NetworkService::Nintendo:\n\t\t\treturn NintendoURLs::CCSUURL;\n\t\tcase NetworkService::Pretendo:\n\t\t\treturn PretendoURLs::CCSUURL;\n\t\tcase NetworkService::Custom:\n\t\t\treturn GetNetworkConfig().urls.CCSU;\n\t\tdefault:\n\t\t\treturn NintendoURLs::CCSUURL;\n\t\t}\n\t}\n\n\tstd::string _getCCSUrl(NetworkService service) // used for game data downloads\n\t{\n\t\tauto& cachedServiceUrls = GetCachedServiceUrls(service);\n\t\tif (!cachedServiceUrls.s_serviceURL_ContentPrefixURL.empty())\n\t\t\treturn cachedServiceUrls.s_serviceURL_ContentPrefixURL;\n\t\tswitch (service)\n\t\t{\n\t\tcase NetworkService::Nintendo:\n\t\t\treturn NintendoURLs::CCSURL;\n\t\tcase NetworkService::Pretendo:\n\t\t\treturn PretendoURLs::CCSURL;\n\t\tcase NetworkService::Custom:\n\t\t\treturn GetNetworkConfig().urls.CCS;\n\t\tdefault:\n\t\t\treturn NintendoURLs::CCSURL;\n\t\t}\n\t}\n\n\t/* NUS */\n\n\t// request ticket for titles which have a public eTicket (usually updates and system titles)\n\tNAPI_NUSGetSystemCommonETicket_Result NUS_GetSystemCommonETicket(AuthInfo& authInfo, uint64 titleId)\n\t{\n\t\tNAPI_NUSGetSystemCommonETicket_Result result{};\n\n\t\tCurlSOAPHelper soapHelper(authInfo.GetService());\n\t\tsoapHelper.SOAP_initate(\"nus\", _getNUSUrl(authInfo.GetService()), \"GetSystemCommonETicket\", \"1.0\");\n\n\t\tsoapHelper.SOAP_addRequestField(\"DeviceId\", fmt::format(\"{}\", authInfo.getDeviceIdWithPlatform()));\n\t\tsoapHelper.SOAP_addRequestField(\"RegionId\", NCrypto::GetRegionAsString(authInfo.region));\n\t\tsoapHelper.SOAP_addRequestField(\"CountryCode\", authInfo.country);\n\t\tsoapHelper.SOAP_addRequestField(\"SerialNo\", authInfo.serial);\n\n\t\tsoapHelper.SOAP_addRequestField(\"TitleId\", fmt::format(\"{:016X}\", titleId));\n\n\t\tif (!soapHelper.submitRequest())\n\t\t{\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\t// parse result\n\t\tpugi::xml_document doc;\n\t\tpugi::xml_node responseNode;\n\t\tif (!_parseResponseInit(soapHelper, \"GetSystemCommonETicketResponse\", responseNode, result, doc, responseNode))\n\t\t\treturn result;\n\n\t\tconst char* eTicketsStr = responseNode.child_value(\"CommonETicket\");\n\t\tresult.eTicket = NCrypto::base64Decode(eTicketsStr);\n\t\tif (result.eTicket.empty())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"GetSystemCommonETicketResponse: Invalid eTicket data in response\");\n\t\t\tresult.apiError = NAPI_RESULT::DATA_ERROR;\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (pugi::xml_node certNode : responseNode.children(\"Certs\"))\n\t\t{\n\t\t\tconst char* certStringValue = certNode.child_value();\n\t\t\tauto certData = NCrypto::base64Decode(certStringValue);\n\t\t\tif (certData.empty())\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"GetSystemCommonETicketResponse: Invalid cert data in response\");\n\t\t\t\tresult.apiError = NAPI_RESULT::DATA_ERROR;\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tresult.certs.emplace_back(NCrypto::base64Decode(certStringValue));\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/* IAS */\n\n\tNAPI_IASGetChallenge_Result IAS_GetChallenge(AuthInfo& authInfo)\n\t{\n\t\tNAPI_IASGetChallenge_Result result{};\n\t\t\n\t\tCurlSOAPHelper soapHelper(authInfo.GetService());\n\t\tsoapHelper.SOAP_initate(\"ias\", _getIASUrl(authInfo.GetService()), \"GetChallenge\", \"2.0\");\n\n\t\tsoapHelper.SOAP_addRequestField(\"DeviceId\", fmt::format(\"{}\", authInfo.getDeviceIdWithPlatform())); // not validated but the generated Challenge is bound to this DeviceId\n\t\tsoapHelper.SOAP_addRequestField(\"Region\", NCrypto::GetRegionAsString(authInfo.region));\n\t\tsoapHelper.SOAP_addRequestField(\"Country\", authInfo.country);\n\n\t\tif (!soapHelper.submitRequest())\n\t\t{\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\t/* parse result */\n\t\tpugi::xml_document doc;\n\t\tpugi::xml_node responseNode;\n\t\tif (!_parseResponseInit(soapHelper, \"GetChallengeResponse\", responseNode, result, doc, responseNode))\n\t\t\treturn result;\n\t\tresult.challenge = responseNode.child_value(\"Challenge\");\n\t\treturn result;\n\t}\n\n\tNAPI_IASGetRegistrationInfo_Result IAS_GetRegistrationInfo_QueryInfo(AuthInfo& authInfo, std::string challenge)\n\t{\n\t\tNAPI_IASGetRegistrationInfo_Result result;\n\t\tCurlSOAPHelper soapHelper(authInfo.GetService());\n\t\tsoapHelper.SOAP_initate(\"ias\", _getIASUrl(authInfo.GetService()), \"GetRegistrationInfo\", \"2.0\");\n\n\t\tsoapHelper.SOAP_addRequestField(\"DeviceId\", fmt::format(\"{}\", authInfo.getDeviceIdWithPlatform())); // this must match the DeviceId used to generate Challenge\n\t\tsoapHelper.SOAP_addRequestField(\"Region\", NCrypto::GetRegionAsString(authInfo.region));\n\t\tsoapHelper.SOAP_addRequestField(\"Country\", authInfo.country);\n\n\t\t// string to sign\n\t\t// differs depending on the call mode\n\t\tstd::string signString;\n\t\tsignString.reserve(1024);\n\t\tsignString.append(fmt::format(\"<Challenge>{}</Challenge>\", challenge));\n\n\t\tsoapHelper.SOAP_addRequestField(\"Challenge\", challenge);\n\n\t\tuint32 signerTitleIdHigh = 0x00050010;\n\t\tuint32 signerTitleIdLow = 0x10040300;\n\n\t\tNCrypto::CertECC deviceCert;\n\t\tif (!deviceCert.decodeFromBase64(authInfo.deviceCertBase64))\n\t\t{\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\tNCrypto::CHash256 hash;\n\t\tNCrypto::GenerateHashSHA256(signString.data(), signString.size(), hash);\n\n\t\tNCrypto::CertECC certChain;\n\t\tNCrypto::ECCSig signature = NCrypto::signHash(signerTitleIdHigh, signerTitleIdLow, hash.b, sizeof(hash.b), certChain);\n\n\t\tauto certChainStr = certChain.encodeToBase64();\n\n\t\tsoapHelper.SOAP_addRequestField(\"Signature\", signature.encodeToBase64());\n\t\tsoapHelper.SOAP_addRequestField(\"CertChain\", certChainStr);\n\t\tsoapHelper.SOAP_addRequestField(\"DeviceCert\", deviceCert.encodeToBase64());\n\n\t\tif (!soapHelper.submitRequest())\n\t\t{\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\t// parse result\n\t\tpugi::xml_document doc;\n\t\tpugi::xml_node responseNode;\n\t\tif (!_parseResponseInit(soapHelper, \"GetRegistrationInfoResponse\", responseNode, result, doc, responseNode))\n\t\t\treturn result;\n\n\t\tresult.accountId = responseNode.child_value(\"AccountId\");\n\t\tresult.deviceToken = responseNode.child_value(\"DeviceToken\");\n\n\t\tif (boost::iequals(responseNode.child_value(\"DeviceTokenExpired\"), \"true\"))\n\t\t\tcemuLog_log(LogType::Force, \"Unexpected server response: Device token expired\");\n\n\t\t/*\n\t\t\texample response:\n\n\t\t\t<Version>2.0</Version>\n\t\t\t<DeviceId>1234567</DeviceId>\n\t\t\t<MessageId>EC-1234-1234</MessageId>\n\t\t\t<TimeStamp>123456789</TimeStamp>\n\t\t\t<ErrorCode>0</ErrorCode>\n\t\t\t<ServiceStandbyMode>false/true</ServiceStandbyMode>\n\t\t\t<AccountId>123456</AccountId>\n\t\t\t<DeviceToken>DEVICE_TOKEN_STR</DeviceToken>\n\t\t\t<DeviceTokenExpired>false/true</DeviceTokenExpired>\n\t\t\t<Country>COUNTRYCODE</Country>\n\t\t\t<ExtAccountId></ExtAccountId>\n\t\t\t<DeviceStatus>R</DeviceStatus>\n\t\t\t<Currency>EUR</Currency>\n\t\t*/\n\n\n\t\treturn result;\n\t}\n\n\t/* ECS */\n\n\tstd::string _getDeviceTokenWT(std::string_view deviceToken)\n\t{\n\t\tuint8 wtHash[16];\n\t\tMD5_CTX md5Ctx;\n\t\tMD5_Init(&md5Ctx);\n\t\tMD5_Update(&md5Ctx, deviceToken.data(), (unsigned long)deviceToken.size());\n\t\tMD5_Final(wtHash, &md5Ctx);\n\n\t\tstd::string wtString;\n\t\twtString.reserve(4 + 32);\n\t\twtString.append(\"WT-\");\n\t\tfor (uint8& b : wtHash)\n\t\t{\n\t\t\twtString.append(fmt::format(\"{0:02x}\", b));\n\t\t}\n\t\treturn wtString;\n\t}\n\n\tNAPI_ECSGetAccountStatus_Result ECS_GetAccountStatus(AuthInfo& authInfo)\n\t{\n\t\tNAPI_ECSGetAccountStatus_Result result{};\n\n\t\tCurlSOAPHelper soapHelper(authInfo.GetService());\n\t\tsoapHelper.SOAP_initate(\"ecs\", _getECSUrl(authInfo.GetService()), \"GetAccountStatus\", \"2.0\");\n\n\t\tsoapHelper.SOAP_addRequestField(\"DeviceId\", fmt::format(\"{}\", authInfo.getDeviceIdWithPlatform()));\n\t\tsoapHelper.SOAP_addRequestField(\"Region\", NCrypto::GetRegionAsString(authInfo.region));\n\t\tsoapHelper.SOAP_addRequestField(\"Country\", authInfo.country);\n\n\t\tif(!authInfo.IASToken.accountId.empty())\n\t\t\tsoapHelper.SOAP_addRequestField(\"AccountId\", authInfo.IASToken.accountId);\n\t\tif (!authInfo.IASToken.deviceToken.empty())\n\t\t\tsoapHelper.SOAP_addRequestField(\"DeviceToken\", _getDeviceTokenWT(authInfo.IASToken.deviceToken));\n\n\t\tif (!soapHelper.submitRequest())\n\t\t{\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\tpugi::xml_document doc;\n\t\tpugi::xml_node responseNode;\n\t\tif (!_parseResponseInit(soapHelper, \"GetAccountStatusResponse\", responseNode, result, doc, responseNode))\n\t\t\treturn result;\n\n\t\tresult.accountId = responseNode.child_value(\"AccountId\");\n\t\tconst char* accountStatusStr = responseNode.child_value(\"AccountStatus\");\n\t\tif (accountStatusStr)\n\t\t{\n\t\t\tif (accountStatusStr[0] == 'R')\n\t\t\t\tresult.accountStatus = NAPI_ECSGetAccountStatus_Result::AccountStatus::REGISTERED;\n\t\t\telse if (accountStatusStr[0] == 'T')\n\t\t\t\tresult.accountStatus = NAPI_ECSGetAccountStatus_Result::AccountStatus::TRANSFERRED;\n\t\t\telse if (accountStatusStr[0] == 'U')\n\t\t\t\tresult.accountStatus = NAPI_ECSGetAccountStatus_Result::AccountStatus::UNREGISTERED;\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"ECS_GetAccountStatus: Account has unknown status code {}\", accountStatusStr);\n\t\t\t}\n\t\t}\n\t\t// extract service URLs\n\t\tfor (pugi::xml_node serviceURLNode : responseNode.children(\"ServiceURLs\"))\n\t\t{\n\t\t\tstd::string_view serviceType = serviceURLNode.child_value(\"Name\");\n\t\t\tstd::string_view url = serviceURLNode.child_value(\"URI\");\n\t\t\tif(serviceType.empty() || url.empty())\n\t\t\t\tcontinue;\n\t\t\tif (boost::iequals(serviceType, \"ContentPrefixURL\"))\n\t\t\t\tresult.serviceURLs.ContentPrefixURL = url;\n\t\t\telse if (boost::iequals(serviceType, \"UncachedContentPrefixURL\"))\n\t\t\t\tresult.serviceURLs.UncachedContentPrefixURL = url;\n\t\t\telse if (boost::iequals(serviceType, \"SystemContentPrefixURL\"))\n\t\t\t\tresult.serviceURLs.SystemContentPrefixURL = url;\n\t\t\telse if (boost::iequals(serviceType, \"SystemUncachedContentPrefixURL\"))\n\t\t\t\tresult.serviceURLs.SystemUncachedContentPrefixURL = url;\n\t\t\telse if (boost::iequals(serviceType, \"EcsURL\"))\n\t\t\t\tresult.serviceURLs.EcsURL = url;\n\t\t\telse if (boost::iequals(serviceType, \"IasURL\"))\n\t\t\t\tresult.serviceURLs.IasURL = url;\n\t\t\telse if (boost::iequals(serviceType, \"CasURL\"))\n\t\t\t\tresult.serviceURLs.CasURL = url;\n\t\t\telse if (boost::iequals(serviceType, \"NusURL\"))\n\t\t\t\tresult.serviceURLs.NusURL = url;\n\t\t\telse\n\t\t\t\tcemuLog_log(LogType::Force, \"GetAccountStatus: Unknown service URI type {}\", serviceType);\n\t\t}\n\n\t\t// assign service URLs\n\t\tauto& cachedServiceUrls = GetCachedServiceUrls(authInfo.GetService());\n\t\tif (!result.serviceURLs.ContentPrefixURL.empty())\n\t\t\tcachedServiceUrls.s_serviceURL_ContentPrefixURL = result.serviceURLs.ContentPrefixURL;\n\t\tif (!result.serviceURLs.UncachedContentPrefixURL.empty())\n\t\t\tcachedServiceUrls.s_serviceURL_UncachedContentPrefixURL = result.serviceURLs.UncachedContentPrefixURL;\n\t\tif (!result.serviceURLs.IasURL.empty())\n\t\t\tcachedServiceUrls.s_serviceURL_IasURL = result.serviceURLs.IasURL;\n\t\tif (!result.serviceURLs.CasURL.empty())\n\t\t\tcachedServiceUrls.s_serviceURL_CasURL = result.serviceURLs.CasURL;\n\t\tif (!result.serviceURLs.NusURL.empty())\n\t\t\tcachedServiceUrls.s_serviceURL_NusURL = result.serviceURLs.NusURL;\n\t\tif (!result.serviceURLs.EcsURL.empty())\n\t\t\tcachedServiceUrls.s_serviceURL_EcsURL = result.serviceURLs.EcsURL;\n\t\treturn result;\n\t}\n\n\tNAPI_ECSAccountListETicketIds_Result ECS_AccountListETicketIds(AuthInfo& authInfo)\n\t{\n\t\tNAPI_ECSAccountListETicketIds_Result result{};\n\n\t\tCurlSOAPHelper soapHelper(authInfo.GetService());\n\t\tsoapHelper.SOAP_initate(\"ecs\", _getECSUrl(authInfo.GetService()), \"AccountListETicketIds\", \"2.0\");\n\n\t\tsoapHelper.SOAP_addRequestField(\"DeviceId\", fmt::format(\"{}\", authInfo.getDeviceIdWithPlatform()));\n\t\tsoapHelper.SOAP_addRequestField(\"Region\", NCrypto::GetRegionAsString(authInfo.region));\n\t\tsoapHelper.SOAP_addRequestField(\"Country\", authInfo.country);\n\n\t\tif (!authInfo.IASToken.accountId.empty())\n\t\t\tsoapHelper.SOAP_addRequestField(\"AccountId\", authInfo.IASToken.accountId);\n\t\tif (!authInfo.IASToken.deviceToken.empty())\n\t\t\tsoapHelper.SOAP_addRequestField(\"DeviceToken\", _getDeviceTokenWT(authInfo.IASToken.deviceToken));\n\n\t\tif (!soapHelper.submitRequest())\n\t\t{\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\tpugi::xml_document doc;\n\t\tpugi::xml_node responseNode;\n\t\tif (!_parseResponseInit(soapHelper, \"AccountListETicketIdsResponse\", responseNode, result, doc, responseNode))\n\t\t\treturn result;\n\n\t\t// extract ticket IVs\n\t\tfor (pugi::xml_node tivNode : responseNode.children(\"TIV\"))\n\t\t{\n\t\t\t// TIV is encoded as <ticketId>.<ticketVersion>\n\t\t\t// ticketVersion starts at 0 and increments every time the ticket is updated (e.g. for AOC content, when purchasing additional DLC packages)\n\t\t\tconst char* tivValue = tivNode.child_value();\n\t\t\tconst char* tivValueEnd = tivValue + strlen(tivValue);\n\t\t\tconst char* tivValueSeparator = std::strchr(tivValue, '.');\n\t\t\tif (tivValueSeparator == nullptr)\n\t\t\t\ttivValueSeparator = tivValueEnd;\n\n\t\t\t// parse ticket id\n\t\t\tsint64 ticketId = 0;\n\t\t\tstd::from_chars_result fcr = std::from_chars(tivValue, tivValueSeparator, ticketId);\n\t\t\tif (fcr.ec == std::errc::invalid_argument || fcr.ec == std::errc::result_out_of_range)\n\t\t\t{\n\t\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\t// parse ticket version\n\t\t\tuint32 ticketVersion = 0;\n\t\t\tfcr = std::from_chars(tivValueSeparator+1, tivValueEnd, ticketVersion);\n\t\t\tif (fcr.ec == std::errc::invalid_argument || fcr.ec == std::errc::result_out_of_range)\n\t\t\t{\n\t\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tresult.tivs.push_back({ ticketId , ticketVersion });\n\t\t}\n\t\treturn result;\n\t}\n\n\tNAPI_ECSAccountGetETickets_Result ECS_AccountGetETickets(AuthInfo& authInfo, sint64 ticketId)\n\t{\n\t\tNAPI_ECSAccountGetETickets_Result result{};\n\n\t\tCurlSOAPHelper soapHelper(authInfo.GetService());\n\t\tsoapHelper.SOAP_initate(\"ecs\", _getECSUrl(authInfo.GetService()), \"AccountGetETickets\", \"2.0\");\n\n\t\tsoapHelper.SOAP_addRequestField(\"DeviceId\", fmt::format(\"{}\", authInfo.getDeviceIdWithPlatform()));\n\t\tsoapHelper.SOAP_addRequestField(\"Region\", NCrypto::GetRegionAsString(authInfo.region));\n\t\tsoapHelper.SOAP_addRequestField(\"Country\", authInfo.country);\n\n\t\tif (!authInfo.IASToken.accountId.empty())\n\t\t\tsoapHelper.SOAP_addRequestField(\"AccountId\", authInfo.IASToken.accountId);\n\t\tif (!authInfo.IASToken.deviceToken.empty())\n\t\t\tsoapHelper.SOAP_addRequestField(\"DeviceToken\", _getDeviceTokenWT(authInfo.IASToken.deviceToken));\n\n\t\tsoapHelper.SOAP_addRequestField(\"DeviceCert\", authInfo.deviceCertBase64);\n\n\t\tsoapHelper.SOAP_addRequestField(\"TicketId\", fmt::format(\"{}\", ticketId));\n\n\t\tif (!soapHelper.submitRequest())\n\t\t{\n\t\t\tresult.apiError = NAPI_RESULT::FAILED;\n\t\t\treturn result;\n\t\t}\n\n\t\t// parse result\n\t\tpugi::xml_document doc;\n\t\tpugi::xml_node responseNode;\n\t\tif (!_parseResponseInit(soapHelper, \"AccountGetETicketsResponse\", responseNode, result, doc, responseNode))\n\t\t\treturn result;\n\n\t\tconst char* eTicketsStr = responseNode.child_value(\"ETickets\");\n\t\tresult.eTickets = NCrypto::base64Decode(eTicketsStr);\n\t\tif (result.eTickets.empty())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"AccountGetETickets: Invalid eTickets data in response\");\n\t\t\tresult.apiError = NAPI_RESULT::DATA_ERROR;\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (pugi::xml_node certNode : responseNode.children(\"Certs\"))\n\t\t{\n\t\t\tconst char* certStringValue = certNode.child_value();\n\t\t\tauto certData = NCrypto::base64Decode(certStringValue);\n\t\t\tif (certData.empty())\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"AccountGetETickets: Invalid cert data in response\");\n\t\t\t\tresult.apiError = NAPI_RESULT::DATA_ERROR;\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tresult.certs.emplace_back(NCrypto::base64Decode(certStringValue));\n\t\t}\n\n\t\t/*\n\t\texample response:\n\t\t\t<ETickets>BASE64_TIK?</ETickets>\n\t\t\t<Certs>BASE64_CERT</Certs>\n\t\t\t<Certs>BASE64_CERT</Certs>\n\t\t */\n\n\t\treturn result;\n\t}\n\n\t/* CCS (content server for raw files, does not use SOAP API) */\n\n\tNAPI_CCSGetTMD_Result CCS_GetTMD(AuthInfo& authInfo, uint64 titleId, uint16 titleVersion)\n\t{\n\t\tNAPI_CCSGetTMD_Result result{};\n\t\tCurlRequestHelper req;\n\t\treq.initate(authInfo.GetService(), fmt::format(\"{}/{:016x}/tmd.{}?deviceId={}&accountId={}\", _getCCSUncachedUrl(authInfo.GetService()), titleId, titleVersion, authInfo.getDeviceIdWithPlatform(), authInfo.IASToken.accountId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);\n\t\treq.setTimeout(180);\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed to request TMD for title {0:016X} v{1}\", titleId, titleVersion));\n\t\t\treturn result;\n\t\t}\n\t\tresult.tmdData = req.getReceivedData();\n\t\tresult.isValid = true;\n\t\treturn result;\n\t}\n\n\tNAPI_CCSGetTMD_Result CCS_GetTMD(AuthInfo& authInfo, uint64 titleId)\n\t{\n\t\tNAPI_CCSGetTMD_Result result{};\n\t\tCurlRequestHelper req;\n\t\treq.initate(authInfo.GetService(), fmt::format(\"{}/{:016x}/tmd?deviceId={}&accountId={}\", _getCCSUncachedUrl(authInfo.GetService()), titleId, authInfo.getDeviceIdWithPlatform(), authInfo.IASToken.accountId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);\n\t\treq.setTimeout(180);\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed to request TMD for title {0:016X}\", titleId));\n\t\t\treturn result;\n\t\t}\n\t\tresult.tmdData = req.getReceivedData();\n\t\tresult.isValid = true;\n\t\treturn result;\n\t}\n\n\tNAPI_CCSGetETicket_Result CCS_GetCETK(NetworkService service, uint64 titleId, uint16 titleVersion)\n\t{\n\t\tNAPI_CCSGetETicket_Result result{};\n\t\tCurlRequestHelper req;\n\t\treq.initate(service, fmt::format(\"{}/{:016x}/cetk\", _getCCSUncachedUrl(service), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);\n\t\treq.setTimeout(180);\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed to request eTicket for title {0:016X} v{1}\", titleId, titleVersion));\n\t\t\treturn result;\n\t\t}\n\t\tresult.cetkData = req.getReceivedData();\n\t\tresult.isValid = true;\n\t\treturn result;\n\t}\n\n\tbool CCS_GetContentFile(NetworkService service, uint64 titleId, uint32 contentId, bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData)\n\t{\n\t\tCurlRequestHelper req;\n\t\treq.initate(service, fmt::format(\"{}/{:016x}/{:08x}\", _getCCSUrl(service), titleId, contentId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);\n\t\treq.setWriteCallback(cbWriteCallback, userData);\n\t\treq.setTimeout(0);\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed to request content file {:08x} for title {:016X}\", contentId, titleId));\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tNAPI_CCSGetContentH3_Result CCS_GetContentH3File(NetworkService service, uint64 titleId, uint32 contentId)\n\t{\n\t\tNAPI_CCSGetContentH3_Result result{};\n\t\tCurlRequestHelper req;\n\t\treq.initate(service, fmt::format(\"{}/{:016x}/{:08x}.h3\", _getCCSUrl(service), titleId, contentId), CurlRequestHelper::SERVER_SSL_CONTEXT::CCS);\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed to request content hash file {:08x}.h3 for title {:016X}\", contentId, titleId));\n\t\t\treturn result;\n\t\t}\n\t\tresult.tmdData = req.getReceivedData();\n\t\tresult.isValid = true;\n\t\treturn result;\n\t}\n\n};\n"
  },
  {
    "path": "src/Cemu/napi/napi_helper.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"napi.h\"\n\n#include \"curl/curl.h\"\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"napi_helper.h\"\n#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/NetworkSettings.h\"\n#include \"config/LaunchSettings.h\"\n#include \"pugixml.hpp\"\n#include <charconv>\n\n#include\"openssl/bn.h\"\n#include\"openssl/x509.h\"\n#include\"openssl/ssl.h\"\n\nCURLcode _sslctx_function_NUS(CURL* curl, void* sslctx, void* param)\n{\n\tif (iosuCrypto_addCACertificate(sslctx, 102) == false)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Invalid CA certificate (102)\");\n\t}\n\tif (iosuCrypto_addCACertificate(sslctx, 105) == false)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Invalid CA certificate (105)\");\n\t}\n\n\tif (iosuCrypto_addClientCertificate(sslctx, 3) == false)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Certificate error\");\n\t}\n\tSSL_CTX_set_mode((SSL_CTX*)sslctx, SSL_MODE_AUTO_RETRY);\n\tSSL_CTX_set_verify_depth((SSL_CTX*)sslctx, 2);\n\tSSL_CTX_set_verify((SSL_CTX*)sslctx, SSL_VERIFY_PEER, nullptr);\n\treturn CURLE_OK;\n}\n\nCURLcode _sslctx_function_IDBE(CURL* curl, void* sslctx, void* param)\n{\n\tif (iosuCrypto_addCACertificate(sslctx, 105) == false)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Invalid CA certificate (105)\");\n\t}\n\tSSL_CTX_set_mode((SSL_CTX*)sslctx, SSL_MODE_AUTO_RETRY);\n\tSSL_CTX_set_verify_depth((SSL_CTX*)sslctx, 2);\n\n\treturn CURLE_OK;\n}\n\nCURLcode _sslctx_function_SOAP(CURL* curl, void* sslctx, void* param)\n{\n\tif (iosuCrypto_addCACertificate(sslctx, 102) == false)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Invalid CA certificate (102)\");\n\t\tcemuLog_log(LogType::Force, \"Certificate error\");\n\t}\n\tif (iosuCrypto_addClientCertificate(sslctx, 1) == false)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Certificate error\");\n\t}\n\tSSL_CTX_set_mode((SSL_CTX*)sslctx, SSL_MODE_AUTO_RETRY);\n\tSSL_CTX_set_verify_depth((SSL_CTX*)sslctx, 2);\n\tSSL_CTX_set_verify((SSL_CTX*)sslctx, SSL_VERIFY_PEER, nullptr);\n\treturn CURLE_OK;\n}\n\nCURLcode _sslctx_function_OLIVE(CURL* curl, void* sslctx, void* param)\n{\n\tif (iosuCrypto_addCACertificate(sslctx, 105) == false)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Invalid CA certificate (105)\");\n\t\tcemuLog_log(LogType::Force, \"Certificate error\");\n\t}\n\tif (iosuCrypto_addClientCertificate(sslctx, 7) == false)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Olive client certificate error\");\n\t}\n\n\t{\n\t\tstd::vector<sint16> certGroups = {\n\t\t\t100,  101,  102,   103,  104,  105,\n\t\t\t1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009,\n\t\t\t1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019,\n\t\t\t1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029,\n\t\t\t1030, 1031, 1032, 1033\n\t\t};\n\n\t\tfor (auto& certId : certGroups)\n\t\t\tiosuCrypto_addCACertificate(sslctx, certId);\n\t}\n\n\tSSL_CTX_set_mode((SSL_CTX*)sslctx, SSL_MODE_AUTO_RETRY);\n\tSSL_CTX_set_verify_depth((SSL_CTX*)sslctx, 2);\n\tSSL_CTX_set_verify((SSL_CTX*)sslctx, SSL_VERIFY_PEER, nullptr);\n\treturn CURLE_OK;\n}\n\nCURLcode _sslctx_function_CUSTOM(CURL* curl, void* sslctx, void* param)\n{\n\tCurlRequestHelper* requestHelper = (CurlRequestHelper*)param;\n\tfor (auto& caCertId : requestHelper->GetCaCertIds())\n\t{\n\t\tif (iosuCrypto_addCACertificate(sslctx, caCertId) == false)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Invalid CA certificate ({})\", caCertId);\n\t\t}\n\t}\n\tfor (auto& clientCertId : requestHelper->GetClientCertIds())\n\t{\n\t\tif (iosuCrypto_addCACertificate(sslctx, clientCertId) == false)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Invalid client certificate ({})\", clientCertId);\n\t\t}\n\t}\n\tSSL_CTX_set_mode((SSL_CTX*)sslctx, SSL_MODE_AUTO_RETRY);\n\tSSL_CTX_set_verify_depth((SSL_CTX*)sslctx, 2);\n\tif (requestHelper->GetClientCertIds().empty())\n\t\tSSL_CTX_set_verify((SSL_CTX*)sslctx, SSL_VERIFY_NONE, nullptr);\n\telse\n\t\tSSL_CTX_set_verify((SSL_CTX*)sslctx, SSL_VERIFY_PEER, nullptr);\n\treturn CURLE_OK;\n}\n\nCurlRequestHelper::CurlRequestHelper()\n{\n\tm_curl = curl_easy_init();\n\tcurl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, __curlWriteCallback);\n\tcurl_easy_setopt(m_curl, CURLOPT_WRITEDATA, this);\n\n\tcurl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1);\n\tcurl_easy_setopt(m_curl, CURLOPT_MAXREDIRS, 2);\n\tcurl_easy_setopt(m_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);\n\n\tif(GetConfig().proxy_server.GetValue() != \"\")\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_PROXY, GetConfig().proxy_server.GetValue().c_str());\n\t}\n}\n\nCurlRequestHelper::~CurlRequestHelper()\n{\n\tcurl_easy_cleanup(m_curl);\n}\n\nvoid CurlRequestHelper::initate(NetworkService service, std::string url, SERVER_SSL_CONTEXT sslContext)\n{\n\t// reset parameters\n\tm_headerExtraFields.clear();\n\tm_postData.clear();\n\tm_cbWriteCallback = nullptr;\n\n\tcurl_easy_setopt(m_curl, CURLOPT_URL, url.c_str());\n\tcurl_easy_setopt(m_curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT);\n\tcurl_easy_setopt(m_curl, CURLOPT_TIMEOUT, 60);\n\n\t// SSL\n\tcurl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 1L);\n\tif (IsNetworkServiceSSLDisabled(service))\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L);\n\t}\n\telse if (sslContext == SERVER_SSL_CONTEXT::ACT || sslContext == SERVER_SSL_CONTEXT::TAGAYA)\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_NUS);\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL);\n\t}\n\telse if (sslContext == SERVER_SSL_CONTEXT::IDBE)\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_IDBE);\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL);\n\t}\n\telse if (sslContext == SERVER_SSL_CONTEXT::IAS || sslContext == SERVER_SSL_CONTEXT::ECS)\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_SOAP);\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL);\n\t}\n\telse if (sslContext == SERVER_SSL_CONTEXT::CCS)\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_SOAP);\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL);\n\t}\n\telse if (sslContext == SERVER_SSL_CONTEXT::OLIVE)\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_OLIVE);\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL);\n\t}\n\telse if (sslContext == SERVER_SSL_CONTEXT::CUSTOM)\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_CUSTOM);\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, this);\n\t}\n\telse\n\t{\n\t\tcemu_assert(false);\n\t}\n}\n\nvoid CurlRequestHelper::addHeaderField(const char* fieldName, std::string_view value)\n{\n\tm_headerExtraFields.emplace_back(fieldName, value);\n}\n\nvoid CurlRequestHelper::addPostField(const char* fieldName, std::string_view value)\n{\n\tif (!m_postData.empty())\n\t\tm_postData.emplace_back('&');\n\tm_postData.insert(m_postData.end(), (uint8*)fieldName, (uint8*)fieldName + strlen(fieldName));\n\tm_postData.emplace_back('=');\n\tm_postData.insert(m_postData.end(), (uint8*)value.data(), (uint8*)value.data() + value.size());\n}\n\nvoid CurlRequestHelper::setWriteCallback(bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData)\n{\n\tm_cbWriteCallback = cbWriteCallback;\n\tm_writeCallbackUserData = userData;\n}\n\nvoid CurlRequestHelper::setTimeout(sint32 time)\n{\n\tcurl_easy_setopt(m_curl, CURLOPT_TIMEOUT, time);\n}\n\nsize_t CurlRequestHelper::__curlWriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata)\n{\n\tsize_t writeByteSize = (size_t)(size * nmemb);\n\tCurlRequestHelper* curlHelper = (CurlRequestHelper*)userdata;\n\tif (curlHelper->m_cbWriteCallback)\n\t{\n\t\tif (!curlHelper->m_cbWriteCallback(curlHelper->m_writeCallbackUserData, ptr, writeByteSize, false))\n\t\t\treturn 0;\n\t\treturn writeByteSize;\n\t}\n\tcurlHelper->m_receiveBuffer.insert(curlHelper->m_receiveBuffer.end(), ptr, ptr + writeByteSize);\n\treturn writeByteSize;\n}\n\nbool CurlRequestHelper::submitRequest(bool isPost)\n{\n\t// HTTP headers\n\tstruct curl_slist* headers = nullptr;\n\tfor (auto& itr : m_headerExtraFields)\n\t\theaders = curl_slist_append(headers, itr.data.c_str());\n\tcurl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);\n\n\t// post\n\tif (isPost)\n\t{\n\t\tif (!m_isUsingMultipartFormData)\n\t\t{\n\t\t\tcurl_easy_setopt(m_curl, CURLOPT_POST, 1);\n\t\t\tcurl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_postData.data());\n\t\t\tcurl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, m_postData.size());\n\t\t}\n\t}\n\telse\n\t\tcurl_easy_setopt(m_curl, CURLOPT_POST, 0);\n\n\t// submit\n\tint res = curl_easy_perform(m_curl);\n\tif (res != CURLE_OK)\n\t{\n\t\tcemuLog_log(LogType::Force, \"CURL web request failed with error {}. Retrying...\", res);\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1000));\n\t\t// retry\n\t\tres = curl_easy_perform(m_curl);\n\t\tif (res != CURLE_OK)\n\t\t\treturn false;\n\t}\n\t\n\t// check response code\n\tlong httpCode = 0;\n\tcurl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &httpCode);\n\tm_httpStatusCode = httpCode;\n\tif (httpCode != 200)\n\t{\n\t\tcemuLog_log(LogType::Force, \"HTTP request received response {} but expected 200\", httpCode);\n\t\tchar* effectiveUrl = nullptr;\n\t\tcurl_easy_getinfo(m_curl, CURLINFO_EFFECTIVE_URL, &effectiveUrl);\n\t\tif (effectiveUrl)\n\t\t\tcemuLog_log(LogType::Force, \"Request: {}\", effectiveUrl);\n\t\t// error status codes (4xx or 5xx range) are always considered a failed request, except for code 400 which is usually returned as a response to failed logins etc.\n\t\tif (httpCode >= 400 && httpCode <= 599 && httpCode != 400)\n\t\t\treturn false;\n\t\t// for other status codes we assume success if the message is non-empty\n\t\tif(m_receiveBuffer.empty())\n\t\t\treturn false;\n\t}\n\n\tif (m_cbWriteCallback)\n\t\tm_cbWriteCallback(m_writeCallbackUserData, nullptr, 0, true); // flush write\n\n\treturn true;\n}\n\nCurlSOAPHelper::CurlSOAPHelper(NetworkService service)\n{\n\tm_curl = curl_easy_init();\n\tcurl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, __curlWriteCallback);\n\tcurl_easy_setopt(m_curl, CURLOPT_WRITEDATA, this);\n\tcurl_easy_setopt(m_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);\n\n\t// SSL\n\tif (!IsNetworkServiceSSLDisabled(service))\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_SOAP);\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL);\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 1L);\n\t}\n\telse\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L);\n\t}\n\tif (GetConfig().proxy_server.GetValue() != \"\")\n\t{\n\t\tcurl_easy_setopt(m_curl, CURLOPT_PROXY, GetConfig().proxy_server.GetValue().c_str());\n\t}\n}\n\nCurlSOAPHelper::~CurlSOAPHelper()\n{\n\tcurl_easy_cleanup(m_curl);\n}\n\nvoid CurlSOAPHelper::SOAP_initate(std::string_view serviceType, std::string url, std::string_view requestMethod, std::string_view requestVersion)\n{\n\tcurl_easy_setopt(m_curl, CURLOPT_URL, url.c_str());\n\tm_serviceType = serviceType;\n\tm_requestMethod = requestMethod;\n\tm_requestVersion = requestVersion;\n\n\tm_envelopeExtraParam.reserve(512);\n\tm_envelopeExtraParam.clear();\n}\n\nvoid CurlSOAPHelper::SOAP_addRequestField(const char* fieldName, std::string_view value)\n{\n\tm_envelopeExtraParam.append(fmt::format(\"<{}:{}>{}</{}:{}>\", m_serviceType, fieldName, value, m_serviceType, fieldName));\n}\n\nvoid CurlSOAPHelper::SOAP_generateEnvelope()\n{\n\tm_envelopeStr.reserve(4096);\n\tm_envelopeStr.clear();\n\n\tm_envelopeStr.append(\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\");\n\n\tm_envelopeStr.append(\"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\\\"http://schemas.xmlsoap.org/soap/envelope/\\\"\\n\");\n\tm_envelopeStr.append(\" xmlns:SOAP-ENC=\\\"http://schemas.xmlsoap.org/soap/encoding/\\\"\\n\");\n\tm_envelopeStr.append(\" xmlns:xsi=\\\"http://www.w3.org/2001/XMLSchema-instance\\\"\\n\");\n\tm_envelopeStr.append(\" xmlns:xsd=\\\"http://www.w3.org/2001/XMLSchema\\\"\\n\");\n\tm_envelopeStr.append(fmt::format(\" xmlns:{}=\\\"urn:{}.wsapi.broadon.com\\\">\\n\", m_serviceType, m_serviceType));\n\tm_envelopeStr.append(\"<SOAP-ENV:Body>\\n\");\n\tm_envelopeStr.append(fmt::format(\"<{}:{} xsi:type=\\\"{}:{}RequestType\\\">\\n\", m_serviceType, m_requestMethod, m_serviceType, m_requestMethod));\n\tm_envelopeStr.append(fmt::format(\"<{}:Version>{}</{}:Version>\\n\", m_serviceType, m_requestVersion, m_serviceType));\n\n\t// the server echos the message id\n\tstatic uint64 s_msgHigh = 1 + (uint64)HighResolutionTimer::now().getTick()/7;\n\tuint64 msgId_high = s_msgHigh; // usually this is set to the deviceId\n\tuint64 msgId_low = (uint64)HighResolutionTimer::now().getTick(); // uptime\n\tm_envelopeStr.append(fmt::format(\"<{}:MessageId>EC-{}-{}</{}:MessageId>\", m_serviceType, msgId_high, msgId_low, m_serviceType));\n\n\tm_envelopeStr.append(m_envelopeExtraParam);\n\n\t// some fields are specific to services?\n\t// ECS doesnt seem to like RegionId and CountryCode\n\n\t// following fields are shared:\n\t// >>> Region, Country, Language\n\t// following fields are present when NUS:\n\t// >>> RegionId (instead of Region), CountryCode (instead of Country)\n\t// following fields are present when CAS or ECS:\n\t// >>> ApplicationId, TIN, SerialNo\n\t// following fields are present when CAS:\n\t// >>> Age\n\t// following fields are present when ECS:\n\t// >>> SessionHandle, ServiceTicket, ServiceId\n\t// following fields for anything that isn't BGS:\n\t// >>> DeviceId (the serial)\n\n\t// DeviceId -> All except BGS (deviceId is the console serial)\n\t// DeviceToken -> Everything except BGS and NUS\n\n\t// ECS:\n\t//m_envelopeStr.append(fmt::format(\"<{}:Region>EUR</{}:Region>\", serviceType, serviceType));\n\t//m_envelopeStr.append(fmt::format(\"<{}:Country>AT</{}:Country>\", serviceType, serviceType));\n\n\n\t// device token format:\n\t// <ECS:DeviceToken>WT-<md5hash_in_hex></ECS:DeviceToken>\n\n\t// unknown fields:\n\t// VirtualDeviceType (shared but optional?)\n\n\n\t// device cert not needed for ECS:GetAccountStatus ? (it complains if present)\n\t//char deviceCertStr[1024 * 4];\n\t//iosuCrypto_getDeviceCertificateBase64Encoded(deviceCertStr);\n\t//m_envelopeStr.append(fmt::format(\"<{}:DeviceCert>{}</{}:DeviceCert>\", serviceType, deviceCertStr, serviceType));\n\n\t// only device token needed\n\t// DeviceToken comes from GetRegistrationInfo and is then stored in ec_account_info.exi\n\n\tm_envelopeStr.append(fmt::format(\"</{}:{}>\\n\", m_serviceType, m_requestMethod));\n\n\tm_envelopeStr.append(\"</SOAP-ENV:Body>\\n\");\n\tm_envelopeStr.append(\"</SOAP-ENV:Envelope>\\n\");\n\n\n}\n\nsint32 iosuCrypto_getDeviceCertificateBase64Encoded(char* output);\n\nbool CurlSOAPHelper::submitRequest()\n{\n\t// generate and set envelope\n\tSOAP_generateEnvelope();\n\tcurl_easy_setopt(m_curl, CURLOPT_POST, 1);\n\tcurl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_envelopeStr.c_str());\n\tcurl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, m_envelopeStr.size());\n\t// generate and set headers\n\tstruct curl_slist* headers = NULL;\n\theaders = curl_slist_append(headers, \"Content-Type: text/xml; charset=utf-8\");\n\theaders = curl_slist_append(headers, \"Accept-Charset: UTF-8\");\n\theaders = curl_slist_append(headers, fmt::format(\"SOAPAction: urn:{}.wsapi.broadon.com/{}\", m_serviceType, m_requestMethod).c_str());\n\theaders = curl_slist_append(headers, \"Accept: */*\");\n\tcurl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);\n\tcurl_easy_setopt(m_curl, CURLOPT_USERAGENT, \"EVL NUP 040800 Sep 18 2012 20:20:02\");\n\n\t// send request\n\tauto res = curl_easy_perform(m_curl);\n\treturn res == CURLE_OK;\n}\n\n/* helper functions */\n\nnamespace NAPI\n{\n\tbool _findXmlNode(pugi::xml_node& doc, pugi::xml_node& nodeOut, const char* name)\n\t{\n\t\tfor (auto& itr : doc.children())\n\t\t{\n\t\t\tif (boost::iequals(itr.name(), name))\n\t\t\t{\n\t\t\t\tnodeOut = itr;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (_findXmlNode(itr, nodeOut, name))\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool _parseResponseInit(const CurlSOAPHelper& soapHelper, const char* responseNodeName, pugi::xml_node& node, _NAPI_CommonResultSOAP& result, pugi::xml_document& doc, pugi::xml_node& responseNode)\n\t{\n\t\t// parse XML response\n\t\tif (!doc.load_buffer(soapHelper.getReceivedData().data(), soapHelper.getReceivedData().size()))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to parse GetRegistrationInfo() response\");\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn false;\n\t\t}\n\t\tif (!_findXmlNode(doc, node, responseNodeName))\n\t\t{\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn false;\n\t\t}\n\t\t// parse error code\n\t\tauto errorCodeStr = node.child_value(\"ErrorCode\");\n\t\tif (!errorCodeStr)\n\t\t{\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn false;\n\t\t}\n\t\tint parsedErrorCode = 0;\n\t\tstd::from_chars_result fcr = std::from_chars(errorCodeStr, errorCodeStr + strlen(errorCodeStr), parsedErrorCode);\n\t\tif (fcr.ec == std::errc::invalid_argument || fcr.ec == std::errc::result_out_of_range)\n\t\t{\n\t\t\tresult.apiError = NAPI_RESULT::XML_ERROR;\n\t\t\treturn false;\n\t\t}\n\t\tif (parsedErrorCode != 0)\n\t\t{\n\t\t\tresult.serviceError = (EC_ERROR_CODE)parsedErrorCode;\n\t\t\tresult.apiError = NAPI_RESULT::SERVICE_ERROR;\n\t\t\treturn false;\n\t\t}\n\t\tresult.apiError = NAPI_RESULT::SUCCESS;\n\t\treturn true;\n\t}\n};\n"
  },
  {
    "path": "src/Cemu/napi/napi_helper.h",
    "content": "#pragma once\n#include \"napi.h\"\n#include \"curl/curl.h\"\n#include \"pugixml.hpp\"\n\ntypedef void CURL;\n\nclass CurlRequestHelper\n{\n\tstruct HeaderExtraField\n\t{\n\t\tHeaderExtraField(std::string_view name, std::string_view value)\n\t\t{\n\t\t\tdata.assign(name);\n\t\t\tdata.append(\": \");\n\t\t\tdata.append(value);\n\t\t};\n\n\t\tstd::string data;\n\t};\npublic:\n\tenum class SERVER_SSL_CONTEXT\n\t{\n\t\tACT, // account.nintendo.net\n\t\tECS, // ecs.\n\t\tIAS, // ias.\n\t\tCCS, // ccs.\n\t\tIDBE, // idbe-wup.\n\t\tTAGAYA, // tagaya.wup.shop.nintendo.net\n\t\tOLIVE, // olv.\n\t\tCUSTOM, // use cert parameters\n\t};\n\n\tCurlRequestHelper();\n\t~CurlRequestHelper();\n\n\tCURL* getCURL()\n\t{\n\t\treturn m_curl;\n\t}\n\n\tvoid initate(NetworkService service, std::string url, SERVER_SSL_CONTEXT sslContext);\n\tvoid addHeaderField(const char* fieldName, std::string_view value);\n\tvoid addPostField(const char* fieldName, std::string_view value);\n\tvoid setWriteCallback(bool(*cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast), void* userData);\n\tvoid setTimeout(sint32 timeoutSeconds); // maximum duration of the request after connecting. Set to zero to disable limit\n\n\tbool submitRequest(bool isPost = false);\n\n\tstd::vector<uint8>& getReceivedData()\n\t{\n\t\treturn m_receiveBuffer;\n\t}\n\n\tvoid setUseMultipartFormData(bool isUsingMultipartFormData)\n\t{\n\t\tm_isUsingMultipartFormData = isUsingMultipartFormData;\n\t}\n\n\tvoid ClearCaCertIds()\n\t{\n\t\tm_caCertIds.clear();\n\t}\n\n\tvoid ClearClientCertIds()\n\t{\n\t\tm_clientCertIds.clear();\n\t}\n\n\tvoid AddCaCertId(sint32 caCertId)\n\t{\n\t\tm_caCertIds.emplace_back(caCertId);\n\t}\n\n\tvoid AddClientCertId(sint32 clientCertId)\n\t{\n\t\tm_clientCertIds.emplace_back(clientCertId);\n\t}\n\n\tstd::vector<sint32> GetCaCertIds() const\n\t{\n\t\treturn m_caCertIds;\n\t}\n\n\tstd::vector<sint32> GetClientCertIds() const\n\t{\n\t\treturn m_clientCertIds;\n\t}\n\n\tsint32 GetHTTPStatusCode() const\n\t{\n\t\treturn m_httpStatusCode;\n\t}\n\nprivate:\n\tstatic size_t __curlWriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata);\n\n\tCURL* m_curl;\n\tstd::vector<uint8> m_receiveBuffer;\n\t// input parameters\n\tstd::vector<HeaderExtraField> m_headerExtraFields;\n\tstd::vector<uint8> m_postData;\n\t// write callback redirect\n\tbool (*m_cbWriteCallback)(void* userData, const void* ptr, size_t len, bool isLast);\n\tvoid* m_writeCallbackUserData{};\n\n\tbool m_isUsingMultipartFormData = false;\n\t// cert data\n\tstd::vector<sint32> m_caCertIds;\n\tstd::vector<sint32> m_clientCertIds;\n\t// result\n\tsint32 m_httpStatusCode{ 0 };\n};\n\nclass CurlSOAPHelper // todo - make this use CurlRequestHelper\n{\npublic:\n\tCurlSOAPHelper(NetworkService service);\n\t~CurlSOAPHelper();\n\n\tCURL* getCURL()\n\t{\n\t\treturn m_curl;\n\t}\n\n\tvoid SOAP_initate(std::string_view serviceType, std::string url, std::string_view requestMethod, std::string_view requestVersion);\n\n\tvoid SOAP_addRequestField(const char* fieldName, std::string_view value);\n\n\tbool submitRequest();\n\n\tconst std::vector<uint8>& getReceivedData() const\n\t{\n\t\treturn m_receiveBuffer;\n\t}\n\nprivate:\n\tvoid SOAP_generateEnvelope();\n\n\tstatic size_t __curlWriteCallback(char* ptr, size_t size, size_t nmemb, void* userdata)\n\t{\n\t\tCurlSOAPHelper* curlHelper = (CurlSOAPHelper*)userdata;\n\t\tsint32 writeByteSize = (sint32)(size * nmemb);\n\t\tcurlHelper->m_receiveBuffer.insert(curlHelper->m_receiveBuffer.end(), ptr, ptr + writeByteSize);\n\t\treturn writeByteSize;\n\t}\n\n\tCURL* m_curl;\n\tstd::vector<uint8> m_receiveBuffer;\n\t// input parameters\n\tstd::string m_serviceType;\n\tstd::string m_requestMethod;\n\tstd::string m_requestVersion;\n\t// generated / internal\n\tstd::string m_envelopeStr;\n\tstd::string m_envelopeExtraParam;\n};\n\nnamespace NAPI\n{\n\tbool _findXmlNode(pugi::xml_node& doc, pugi::xml_node& nodeOut, const char* name);\n\tbool _parseResponseInit(const CurlSOAPHelper& soapHelper, const char* responseNodeName, pugi::xml_node& node, _NAPI_CommonResultSOAP& result, pugi::xml_document& doc, pugi::xml_node& responseNode);\n\n};"
  },
  {
    "path": "src/Cemu/napi/napi_idbe.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"napi.h\"\n#include \"napi_helper.h\"\n\n#include \"curl/curl.h\"\n#include \"pugixml.hpp\"\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"openssl/sha.h\"\n#include \"util/crypto/aes128.h\"\n#include \"util/helpers/StringHelpers.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/NetworkSettings.h\"\n\nnamespace NAPI\n{\n\n\tstd::string IDBEIconDataV0::LanguageInfo::GetGameNameUTF8()\n\t{\n\t\treturn StringHelpers::ToUtf8(gameName);\n\t}\n\n\tstd::string IDBEIconDataV0::LanguageInfo::GetGameLongNameUTF8()\n\t{\n\t\treturn StringHelpers::ToUtf8(gameLongName);\n\t}\n\n\tstd::string IDBEIconDataV0::LanguageInfo::GetPublisherNameUTF8()\n\t{\n\t\treturn StringHelpers::ToUtf8(publisherName);\n\t}\n\n\tvoid _decryptIDBEAndHash(IDBEIconDataV0* iconData, uint8* hash, uint8 keyIndex)\n\t{\n\t\tstatic uint8 idbeAesKeys[4 * 16] =\n\t\t{\n\t\t\t0x4A,0xB9,0xA4,0x0E,0x14,0x69,0x75,0xA8,0x4B,0xB1,0xB4,0xF3,0xEC,0xEF,0xC4,0x7B,\n\t\t\t0x90,0xA0,0xBB,0x1E,0x0E,0x86,0x4A,0xE8,0x7D,0x13,0xA6,0xA0,0x3D,0x28,0xC9,0xB8,\n\t\t\t0xFF,0xBB,0x57,0xC1,0x4E,0x98,0xEC,0x69,0x75,0xB3,0x84,0xFC,0xF4,0x07,0x86,0xB5,\n\t\t\t0x80,0x92,0x37,0x99,0xB4,0x1F,0x36,0xA6,0xA7,0x5F,0xB8,0xB4,0x8C,0x95,0xF6,0x6F\n\t\t};\n\n\t\tstatic uint8 idbeAesIv[16] =\n\t\t{\n\t\t\t0xA4,0x69,0x87,0xAE,0x47,0xD8,0x2B,0xB4,0xFA,0x8A,0xBC,0x04,0x50,0x28,0x5F,0xA4\n\t\t};\n\n\t\tconst uint8* aesKey = idbeAesKeys + 16 * keyIndex;\n\n\t\tuint8 iv[16];\n\t\tmemcpy(iv, hash + 16, sizeof(iv));\n\t\tAES128_CBC_decrypt(hash, hash, 32, aesKey, idbeAesIv);\n\t\tAES128_CBC_decrypt((uint8*)iconData, (uint8*)iconData, sizeof(IDBEIconDataV0), aesKey, iv);\n\t}\n\n\tstd::vector<uint8> IDBE_RequestRawEncrypted(NetworkService networkService, uint64 titleId)\n\t{\n\t\tCurlRequestHelper req;\n\t\tstd::string requestUrl;\n\t\tswitch (networkService)\n\t\t{\n\t\tcase NetworkService::Pretendo:\n\t\t\trequestUrl = PretendoURLs::IDBEURL;\n\t\t\tbreak;\n\t\tcase NetworkService::Custom:\n\t\t\trequestUrl = GetNetworkConfig().urls.IDBE.GetValue();\n\t\t\tbreak;\n\t\tcase NetworkService::Nintendo:\n\t\tdefault:\n\t\t\trequestUrl = NintendoURLs::IDBEURL;\n\t\t\tbreak;\n\t\t}\n\t\trequestUrl.append(fmt::format(fmt::runtime(\"/{0:02X}/{1:016X}.idbe\"), (uint32)((titleId >> 8) & 0xFF), titleId));\n\t\treq.initate(networkService, requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE);\n\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed to request IDBE icon for title {0:016X}\", titleId));\n\t\t\treturn {};\n\t\t}\n\t\t/*\n\t\t\tformat:\n\t\t\t+0x00\tuint8\t\tversion (0)\n\t\t\t+0x01\tuint8\t\tkeyIndex\n\t\t\t+0x02\tuint8[32]\thashSHA256\n\t\t\t+0x22\tuint8[]\t\tEncryptedIconData\n\t\t*/\n\t\tauto& receivedData = req.getReceivedData();\n\t\treturn receivedData;\n\t}\n\n\tstd::optional<IDBEIconDataV0> IDBE_Request(NetworkService networkService, uint64 titleId)\n\t{\n\t\tif (titleId == 0x000500301001500A ||\n\t\t\ttitleId == 0x000500301001510A ||\n\t\t\ttitleId == 0x000500301001520A)\n\t\t{\n\t\t\t// friend list has no icon, just fail immediately\n\t\t\tcemuLog_logDebug(LogType::Force, \"Requesting IDBE for Friend List. Return none instead\");\n\t\t\treturn std::nullopt;\n\t\t}\n\n\t\tstd::vector<uint8> idbeData = IDBE_RequestRawEncrypted(networkService, titleId);\n\t\tif (idbeData.size() < 0x22)\n\t\t\treturn std::nullopt;\n\t\tif (idbeData[0] != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IDBE_Request: File has invalid version\");\n\t\t\treturn std::nullopt;\n\t\t}\n\t\tuint8 keyIndex = idbeData[1];\n\t\tif (keyIndex >= 4)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IDBE_Request: Key index out of range\");\n\t\t\treturn std::nullopt;\n\t\t}\n\t\tif (idbeData.size() < (0x22 + sizeof(IDBEIconDataV0)))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IDBE_Request: File size does not match\");\n\t\t\treturn std::nullopt;\n\t\t}\n\t\t// extract hash and encrypted icon data\n\t\tuint8 hash[32];\n\t\tstd::memcpy(hash, idbeData.data() + 0x2, 32);\n\t\tIDBEIconDataV0 iconDataV0;\n\t\tstd::memcpy(&iconDataV0, idbeData.data() + 0x22, sizeof(IDBEIconDataV0));\n\t\t// decrypt icon data and hash\n\t\t_decryptIDBEAndHash(&iconDataV0, hash, keyIndex);\n\t\t// verify hash of decrypted data\n\t\tuint8 calcHash[SHA256_DIGEST_LENGTH];\n\t\tSHA256((const unsigned char*) &iconDataV0, sizeof(IDBEIconDataV0), calcHash);\n\t\tif (std::memcmp(calcHash, hash, SHA256_DIGEST_LENGTH) != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"IDBE_Request: Hash mismatch\");\n\t\t\treturn std::nullopt;\n\t\t}\n\t\treturn std::optional(iconDataV0);\n\t}\n};\n"
  },
  {
    "path": "src/Cemu/napi/napi_version.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"napi.h\"\n#include \"napi_helper.h\"\n\n#include \"curl/curl.h\"\n#include \"pugixml.hpp\"\n\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include <charconv>\n#include \"config/ActiveSettings.h\"\n#include \"config/NetworkSettings.h\"\n\nnamespace NAPI\n{\n\tNAPI_VersionListVersion_Result TAG_GetVersionListVersion(AuthInfo& authInfo)\n\t{\n\t\tNAPI_VersionListVersion_Result result;\n\t\tCurlRequestHelper req;\n\n\t\tstd::string requestUrl;\n\t\tswitch (authInfo.GetService())\n\t\t{\n\t\tcase NetworkService::Pretendo:\n\t\t\trequestUrl = PretendoURLs::TAGAYAURL;\n\t\t\tbreak;\n\t\tcase NetworkService::Custom:\n\t\t\trequestUrl = GetNetworkConfig().urls.TAGAYA.GetValue();\n\t\t\tbreak;\n\t\tcase NetworkService::Nintendo:\n\t\tdefault:\n\t\t\trequestUrl = NintendoURLs::TAGAYAURL;\n\t\t\tbreak;\n\t\t}\n\t\trequestUrl.append(fmt::format(fmt::runtime(\"/{}/{}/latest_version\"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country.empty() ? \"NN\" : authInfo.country));\n\t\treq.initate(authInfo.GetService(), requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA);\n\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed to request version of update list\"));\n\t\t\treturn result;\n\t\t}\n\t\tauto& receivedData = req.getReceivedData();\n\n\t\tpugi::xml_document doc;\n\t\tif (!doc.load_buffer(receivedData.data(), receivedData.size()))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to parse title list XML\");\n\t\t\treturn result;\n\t\t}\n\n\t\tif (!doc.child(\"version_list_info\").child(\"version\") || !doc.child(\"version_list_info\").child(\"fqdn\"))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Title list XML has missing field\");\n\t\t\treturn result;\n\t\t}\n\t\tresult.version = atoi(doc.child(\"version_list_info\").child(\"version\").child_value());\n\t\tresult.fqdnURL = doc.child(\"version_list_info\").child(\"fqdn\").child_value();\n\t\tresult.isValid = true;\n\t\treturn result;\n\t}\n\n\tNAPI_VersionList_Result TAG_GetVersionList(AuthInfo& authInfo, std::string_view fqdnURL, uint32 versionListVersion)\n\t{\n\t\tNAPI_VersionList_Result result;\n\t\tCurlRequestHelper req;\n\t\treq.initate(authInfo.GetService(), fmt::format(\"https://{}/tagaya/versionlist/{}/{}/list/{}.versionlist\", fqdnURL, NCrypto::GetRegionAsString(authInfo.region), authInfo.country.empty() ? \"NN\" : authInfo.country, versionListVersion), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA);\n\t\tif (!req.submitRequest(false))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, fmt::format(\"Failed to request update list\"));\n\t\t\treturn result;\n\t\t}\n\t\tauto& receivedData = req.getReceivedData();\n\n\t\tpugi::xml_document doc;\n\t\tif (!doc.load_buffer(receivedData.data(), receivedData.size()))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to parse update list XML\");\n\t\t\treturn result;\n\t\t}\n\t\t// example:\n\t\t// <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n\t\t// <version_list format_version=\"1.0\"><version>1615</version>\n\t\t// <titles>\n\t\t//    <title><id>0005000E10100600</id><version>16</version></title>\n\t\t//    <title><id>0005000E10101B00</id><version>16</version></title>\n\t\t// ...\n\n\t\tfor (pugi::xml_node title : doc.child(\"version_list\").child(\"titles\").children(\"title\"))\n\t\t{\n\t\t\tuint64 titleId = 0;\n\t\t\tuint32 titleVersion = 0;\n\t\t\tstd::string_view str = title.child_value(\"id\");\n\t\t\tif (const auto res = std::from_chars(str.data(), str.data() + str.size(), titleId, 16); res.ec != std::errc())\n\t\t\t\tcontinue;\n\t\t\tstr = title.child_value(\"version\");\n\t\t\tif (const auto res = std::from_chars(str.data(), str.data() + str.size(), titleVersion, 10); res.ec != std::errc())\n\t\t\t\tcontinue;\n\t\t\tresult.titleVersionList.emplace(titleId, titleVersion);\n\t\t}\n\t\tresult.isValid = true;\n\t\treturn result;\n\t}\n};\n"
  },
  {
    "path": "src/Cemu/ncrypto/ncrypto.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"util/helpers/helpers.h\"\n\n#include \"openssl/bn.h\"\n#include \"openssl/ec.h\"\n#include \"openssl/x509.h\"\n#include \"openssl/ssl.h\"\n#include \"openssl/sha.h\"\n#include \"openssl/ecdsa.h\"\n\n#include \"util/crypto/aes128.h\"\n\nvoid iosuCrypto_getDeviceCertificate(void* certOut, sint32 len);\nvoid iosuCrypto_getDeviceCertPrivateKey(void* privKeyOut, sint32 len);\nbool iosuCrypto_getDeviceId(uint32* deviceId);\nvoid iosuCrypto_getDeviceSerialString(char* serialString);\n\nvoid iosuCrypto_readOtpData(void* output, sint32 wordIndex, sint32 size);\n\nvoid iosuCrypto_readSeepromData(void* output, sint32 wordIndex, sint32 size);\n\nextern bool hasSeepromMem; // remove later (migrate otp/seeprom loading & parsing to this class)\nextern bool hasOtpMem; // remove later\n\nnamespace NCrypto\n{\n\tstd::string base64Encode(const void* inputMem, size_t inputLen)\n\t{\n\t\tconst uint8* input = (const uint8*)inputMem;\n\n\t\tstatic const char* base64_charset =\n\t\t\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\t\t\t\"abcdefghijklmnopqrstuvwxyz\"\n\t\t\t\"0123456789+/\";\n\n\t\tstd::string strBase64;\n\t\tstrBase64.resize((inputLen * 4) / 3 + 16);\n\n\t\tint i = 0;\n\t\tint j = 0;\n\t\tunsigned char charArray_3[3];\n\t\tunsigned char charArray_4[4];\n\t\tsint32 outputLength = 0;\n\t\twhile (inputLen--)\n\t\t{\n\t\t\tcharArray_3[i++] = *(input++);\n\t\t\tif (i == 3)\n\t\t\t{\n\t\t\t\tcharArray_4[0] = (charArray_3[0] & 0xfc) >> 2;\n\t\t\t\tcharArray_4[1] = ((charArray_3[0] & 0x03) << 4) + ((charArray_3[1] & 0xf0) >> 4);\n\t\t\t\tcharArray_4[2] = ((charArray_3[1] & 0x0f) << 2) + ((charArray_3[2] & 0xc0) >> 6);\n\t\t\t\tcharArray_4[3] = charArray_3[2] & 0x3f;\n\t\t\t\tfor (i = 0; (i < 4); i++)\n\t\t\t\t{\n\t\t\t\t\tstrBase64[outputLength] = base64_charset[charArray_4[i]];\n\t\t\t\t\toutputLength++;\n\t\t\t\t}\n\t\t\t\ti = 0;\n\t\t\t}\n\t\t}\n\t\tif (i)\n\t\t{\n\t\t\tfor (j = i; j < 3; j++)\n\t\t\t\tcharArray_3[j] = '\\0';\n\n\t\t\tcharArray_4[0] = (charArray_3[0] & 0xfc) >> 2;\n\t\t\tcharArray_4[1] = ((charArray_3[0] & 0x03) << 4) + ((charArray_3[1] & 0xf0) >> 4);\n\t\t\tcharArray_4[2] = ((charArray_3[1] & 0x0f) << 2) + ((charArray_3[2] & 0xc0) >> 6);\n\t\t\tcharArray_4[3] = charArray_3[2] & 0x3f;\n\n\t\t\tfor (j = 0; j < (i + 1); j++)\n\t\t\t{\n\t\t\t\tstrBase64[outputLength] = base64_charset[charArray_4[j]];\n\t\t\t\toutputLength++;\n\t\t\t}\n\t\t\twhile (i++ < 3)\n\t\t\t{\n\t\t\t\tstrBase64[outputLength] = '=';\n\t\t\t\toutputLength++;\n\t\t\t}\n\t\t}\n\n\t\tcemu_assert(outputLength <= strBase64.size());\n\t\tstrBase64.resize(outputLength);\n\t\treturn strBase64;\n\t}\n\n\tstd::vector<uint8> base64Decode(std::string_view inputStr)\n\t{\n\t\tstatic constexpr unsigned char kDecodingTable[] = {\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,\n\t\t  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,\n\t\t  64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,\n\t\t  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,\n\t\t  64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,\n\t\t  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,\n\t\t  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64\n\t\t};\n\n\t\tsize_t in_len = inputStr.size();\n\t\tif (in_len <= 3 || (in_len & 3) != 0)\n\t\t\treturn std::vector<uint8>(); // invalid length\n\n\t\tstd::vector<uint8> output;\n\n\t\tsize_t out_len = in_len / 4 * 3;\n\t\tif (inputStr[in_len - 1] == '=') out_len--;\n\t\tif (inputStr[in_len - 2] == '=') out_len--;\n\n\t\toutput.resize(out_len);\n\n\t\tfor (size_t i = 0, j = 0; i < in_len;) \n\t\t{\n\t\t\tuint32 a = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(inputStr[i++])];\n\t\t\tuint32 b = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(inputStr[i++])];\n\t\t\tuint32 c = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(inputStr[i++])];\n\t\t\tuint32 d = inputStr[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(inputStr[i++])];\n\n\t\t\tuint32 triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);\n\n\t\t\tif (j < out_len) output[j++] = (triple >> 2 * 8) & 0xFF;\n\t\t\tif (j < out_len) output[j++] = (triple >> 1 * 8) & 0xFF;\n\t\t\tif (j < out_len) output[j++] = (triple >> 0 * 8) & 0xFF;\n\t\t}\n\n\t\treturn output;\n\t}\n\n\tvoid base64Tests()\n\t{\n\t\tstd::vector<uint8> random;\n\t\tfor (sint32 i = 0; i < 100; i++)\n\t\t{\n\t\t\trandom.resize(0 + i);\n\t\t\tfor (size_t x = 0; x < random.size(); x++)\n\t\t\t\trandom[x] = (uint8)(i * 21 + x * 133);\n\n\t\t\tstd::string b64 = base64Encode(random.data(), random.size());\n\t\t\tstd::vector<uint8> dec = base64Decode(b64);\n\n\t\t\tcemu_assert(random == dec);\n\t\t}\n\t}\n\n\t/* Hashing */\n\n\tvoid GenerateHashSHA1(const void* data, size_t len, CHash160& hashOut)\n\t{\n\t\tSHA1((const unsigned char*) data, len, hashOut.b);\n\t}\n\n\tvoid GenerateHashSHA256(const void* data, size_t len, CHash256& hashOut)\n\t{\n\t\tSHA256((const unsigned char*) data, len, hashOut.b);\n\t}\n\n\t/* Ticket */\n\tstruct ETicketFileHeaderWiiU\n\t{\n\t\t/*\n\t\t\tTicket version 0:\n\t\t\t\tSHA1 hash\n\t\t\tTicket version 1:\n\t\t\t\tSHA256 hash + has item rights\n\t\t\n\t\t*/\n\n\t\t/* +0x000 */ uint32be signatureType;\n\t\t/* +0x004 */ uint8 sig[0x100];\n\t\t/* +0x104 */ uint8 _ukn104[0x180 - 0x104];\n\n\t\t/* +0x180 */ ECCPubKey publicKey;\n\t\t/* +0x1BC */ uint8 ticketFormatVersion;\n\t\t/* +0x1BD */ uint8 _ukn1BD;\n\t\t/* +0x1BE */ uint8 _ukn1BE;\n\n\t\t/* +0x1BF */ uint8 encryptedTitleKey[16];\n\t\t/* +0x1CF */ uint8 _ukn1CF; // probably padding\n\n\t\t/* +0x1D0 */ uint32be ticketIdHigh;\n\t\t/* +0x1D4 */ uint32be ticketIdLow;\n\n\t\t/* +0x1D8 */ uint32be deviceId; // ticket personalized to this deviceId. Zero if not personalized\n\n\t\t/* +0x1DC */ uint32be titleIdHigh;\n\t\t/* +0x1E0 */ uint32be titleIdLow;\n\t\t/* +0x1E4 */ uint16be ukn1E4;\n\t\t/* +0x1E6 */ uint16be titleVersion; // also used as ticket version (for AOC content)?\n\n\t\t/* +0x1E8 */ uint8 _ukn1E8[0x21C - 0x1E8];\n\n\t\t/* +0x21C */ uint32be accountId;\n\n\t\t/* V1 extension header starts at +0x2A4 */ \n\t};\n\n\tstruct ETicketFileHeaderExtV1\n\t{\n\t\t/* starts at +0x2A4 */\n\t\t/* +0x000 */ uint16be headerVersion;\n\t\t/* +0x002 */ uint16be headerSize;\n\t\t/* +0x004 */ uint32be ukn008;\n\t\t/* +0x008 */ uint32be sectionTableOffset;\n\t\t/* +0x00C */ uint16be sectionTableNumEntries;\n\t\t/* +0x00E */ uint16be sectionTableEntrySize;\n\t\t/**/\n\t};\n\n\tstruct ETicketFileHeaderExtV1SectionHeader\n\t{\n\t\tenum\n\t\t{\n\t\t\tSECTION_TYPE_CONTENT_RIGHTS = 3, // content rights\n\t\t};\n\n\t\t/* +0x00 */ uint32be sectionOffset;\n\t\t/* +0x04 */ uint32be entryCount;\n\t\t/* +0x08 */ uint32be entrySize;\n\t\t/* +0x0C */ uint32be sectionSize;\n\t\t/* +0x10 */ uint16be type;\n\t\t/* +0x12 */ uint16be ukn00;\n\t};\n\n\tstatic_assert(sizeof(ETicketFileHeaderWiiU) == 0x220);\n\n\tstruct ETicketV1_ContentRights\n\t{\n\t\tuint32be baseIndex; // first index for bitmask?\n\t\tuint8be rightBitmask[0x80];\n\n\t\tuint32 GetRightsCount() const\n\t\t{\n\t\t\treturn sizeof(rightBitmask) * 8;\n\t\t}\n\n\t\tbool GetRight(uint32 index) const\n\t\t{\n\t\t\tcemu_assert_debug(index < GetRightsCount());\n\t\t\tif (index >= GetRightsCount())\n\t\t\t\treturn false;\n\t\t\treturn ((rightBitmask[(index/8)]>>(index & 7)) & 1) != 0;\n\t\t}\n\t};\n\n\tstatic_assert(sizeof(ETicketV1_ContentRights) == 0x84);\n\n\tbool ETicketParser::parse(const uint8* data, size_t size)\n\t{\n\t\tauto readStruct = [&](uint32 offset, uint32 readSize) -> void*\n\t\t{\n\t\t\tif ((offset + readSize) > size)\n\t\t\t\treturn nullptr;\n\t\t\treturn (void*)((const uint8*)data + offset);\n\t\t};\n\n\t\tif (size < sizeof(ETicketFileHeaderWiiU))\n\t\t\treturn false;\n\t\tETicketFileHeaderWiiU* header = (ETicketFileHeaderWiiU*)readStruct(0, sizeof(ETicketFileHeaderWiiU));\n\t\tif (!header)\n\t\t\treturn false;\n\t\tm_titleId = MakeU64(header->titleIdHigh, header->titleIdLow);\n\t\tm_ticketId = MakeU64(header->ticketIdHigh, header->ticketIdLow);\n\t\tm_ticketFormatVersion = header->ticketFormatVersion;\n\t\tm_titleVersion = header->titleVersion;\n\t\tuint32 titleIdHigh = (m_titleId >> 32);\n\t\tif ((titleIdHigh >> 16) != 0x5)\n\t\t\treturn false; // title id should start with 0005... (Wii U platform id?)\n\n\t\tm_isPersonalized = header->deviceId != 0;\n\t\tm_deviceId = header->deviceId;\n\t\tm_publicKey = header->publicKey;\n\n\t\tstd::memcpy(m_encryptedTitleKey, header->encryptedTitleKey, 16);\n\n\t\tcemu_assert_debug(header->ukn1E4 == 0);\n\n\t\t// read V1 extension\n\t\tif (m_ticketFormatVersion >= 1)\n\t\t{\n\t\t\tif ((titleIdHigh) == 0x0005000c)\n\t\t\t{\n\t\t\t\tETicketFileHeaderExtV1* extHeader = (ETicketFileHeaderExtV1*)readStruct(0x2A4, sizeof(ETicketFileHeaderExtV1)); //  (ETicketFileHeaderExtV1*)((uint8*)header + 0x2A4);\n\t\t\t\tif (!extHeader)\n\t\t\t\t\treturn false;\n\t\t\t\tcemu_assert_debug(extHeader->sectionTableEntrySize == 0x14);\n\t\t\t\tfor (uint32 i = 0; i < extHeader->sectionTableNumEntries; i++)\n\t\t\t\t{\n\t\t\t\t\tETicketFileHeaderExtV1SectionHeader* sectHeader = (ETicketFileHeaderExtV1SectionHeader*)readStruct(0x2A4 + extHeader->sectionTableOffset, sizeof(ETicketFileHeaderExtV1SectionHeader));\n\t\t\t\t\tif (!sectHeader)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tif (sectHeader->type == ETicketFileHeaderExtV1SectionHeader::SECTION_TYPE_CONTENT_RIGHTS)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (sectHeader->entrySize != sizeof(ETicketV1_ContentRights))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"ETicket: Failed to parse ticket with invalid rights size\");\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcemu_assert_debug(sectHeader->entryCount == 1);\n\t\t\t\t\t\tfor (uint32 r = 0; r < sectHeader->entryCount; r++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tETicketV1_ContentRights* rights = (ETicketV1_ContentRights*)readStruct(0x2A4 + sectHeader->sectionOffset + r * sectHeader->entrySize, sizeof(ETicketV1_ContentRights));\n\t\t\t\t\t\t\tcemu_assert_debug(rights->baseIndex == 0);\n\t\t\t\t\t\t\tif (rights->baseIndex > 0x1000)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"ETicket: Invalid content rights index ({})\", (uint32)rights->baseIndex);\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsize_t maxRightsCount = rights->baseIndex + rights->GetRightsCount();\n\t\t\t\t\t\t\tif (maxRightsCount > m_contentRights.size())\n\t\t\t\t\t\t\t\tm_contentRights.resize(maxRightsCount);\n\t\t\t\t\t\t\tfor (uint32 x = 0; x < rights->GetRightsCount(); x++)\n\t\t\t\t\t\t\t\tm_contentRights[x + rights->baseIndex] = rights->GetRight(x);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid ETicketParser::GetTitleKey(AesKey& key)\n\t{\n\t\t// the key is encrypted using the titleId as IV + 8 zero bytes\n\t\tuint8 iv[16]{};\n\t\t*(uint64be*)iv = m_titleId;\n\n\t\tuint8 commonKey[16] = { 0xD7,0xB0,0x04,0x02,0x65,0x9B,0xA2,0xAB,0xD2,0xCB,0x0D,0xB2,0x7F,0xA2,0xB6,0x56 };\n\n\t\tAES128_CBC_decrypt(key.b, m_encryptedTitleKey, 16, commonKey, iv);\n\t}\n\n\t// personalized tickets have an extra layer of encryption for the title key\n\tbool ETicketParser::Depersonalize(uint8* ticketData, size_t ticketSize, uint32 deviceId, const ECCPrivKey& devicePrivKey)\n\t{\n\t\tETicketParser ticketParser;\n\t\tif (!ticketParser.parse(ticketData, ticketSize))\n\t\t\treturn false;\n\t\tif (!ticketParser.IsPersonalized())\n\t\t\treturn false;\n\t\tif (ticketParser.m_deviceId != deviceId)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Personalized ticket does not match deviceId\");\n\t\t\treturn false;\n\t\t}\n\n\t\t// decrypt personalized titlekey\n\t\tEC_KEY* ec_privKey = devicePrivKey.getPrivateKey();\n\t\tEC_POINT* ec_publicKey = ticketParser.m_publicKey.getPublicKeyAsPoint();\n\n\t\tuint8 sharedKey[128]{};\n\t\tint sharedKeyLen = ECDH_compute_key(sharedKey, sizeof(sharedKey), ec_publicKey, ec_privKey, nullptr);\n\t\tcemu_assert(sharedKeyLen > 16);\n\t\tEC_KEY_free(ec_privKey);\n\t\tEC_POINT_free(ec_publicKey);\n\n\t\tNCrypto::CHash160 sharedKeySHA1;\n\t\tNCrypto::GenerateHashSHA1(sharedKey, sharedKeyLen, sharedKeySHA1);\n\n\t\tuint8 aesSharedKey[16]{};\n\t\tstd::memcpy(aesSharedKey, sharedKeySHA1.b, 16);\n\n\t\tuint8 iv[16]{};\n\t\t*(uint64be*)iv = ticketParser.m_ticketId;\n\n\t\tuint8 ticketKey[16];\n\t\tAES128_CBC_decrypt(ticketKey, ticketParser.m_encryptedTitleKey, 16, aesSharedKey, iv);\n\n\t\t// store de-personalized key and remove personal data from ticket\n\t\tETicketFileHeaderWiiU* header = (ETicketFileHeaderWiiU*)ticketData;\n\t\tstd::memcpy(header->encryptedTitleKey, ticketKey, 16);\n\t\theader->deviceId = 0;\n\t\theader->accountId = 0;\n\n\t\treturn true;\n\t}\n\n\t/* Title meta data */\n\n\tstruct TMDFileHeaderWiiU\n\t{\n\t\t/* +0x000 */ uint32be signatureType;\n\n\t\t/* +0x004 */ uint8be sig[0x100];\n\t\t/* +0x104 */ uint8be _padding104[0x140 - 0x104];\n\t\t/* +0x140 */ uint8be _ukn140[0x40];\n\n\t\t/* +0x180 */ uint8be tmdVersion;\n\t\t/* +0x181 */ uint8be _ukn181;\n\t\t/* +0x182 */ uint8be _ukn182;\n\t\t/* +0x183 */ uint8be isVWii;\n\t\t/* +0x184 */ uint32be iosTitleIdHigh;\n\t\t/* +0x188 */ uint32be iosTitleIdLow;\n\t\t/* +0x18C */ uint32be titleIdHigh;\n\t\t/* +0x190 */ uint32be titleIdLow;\n\t\t/* +0x194 */ uint32be titleType;\n\t\t/* +0x198 */ uint16be group;\n\t\t/* +0x19A */ uint16be _ukn19A;\n\t\t/* +0x19C */ uint16be region;\n\t\t/* +0x19E */ uint8be ratings[16];\n\t\t/* +0x1AE */ uint8be _ukn1AE[12];\n\t\t/* +0x1BA */ uint8be _ipcMask[12];\n\t\t/* +0x1C6 */ uint8be _ukn1C6[18];\n\t\t/* +0x1D8 */ uint32be accessRightsMask;\n\t\t/* +0x1DC */ uint16be titleVersion;\n\t\t/* +0x1DE */ uint16be numContent;\n\t\t/* +0x1E0 */ uint32be _ukn1E0;\n\t\t/* +0x1E4 */ uint8 uknHash[32]; // hash of array at 0x204\n\n\t\t/* +0x204 */\n\t\tstruct \n\t\t{\n\t\t\t// pointer to cert data and cert hash?\n\t\t\tuint16 ukn00; // index?\n\t\t\tuint16 ukn02;\n\t\t\tuint8 hash[32];\n\t\t}ContentInfo[64];\n\t};\n\n\tstatic_assert(sizeof(TMDFileHeaderWiiU) == 0x204 + 64*36);\n\n\tstruct TMDFileContentEntryWiiU\n\t{\n\t\t/* +0x00 */ uint32be contentId;\n\t\t/* +0x04 */ uint16be index;\n\t\t/* +0x06 */ uint16be type;\n\t\t/* +0x08 */ uint32be sizeHigh;\n\t\t/* +0x0C */ uint32be sizeLow;\n\t\t/* +0x10 */ uint8 hashSHA256[32]; // only the first 20 bytes of the hash seem to be stored?\n\t};\n\n\tstatic_assert(sizeof(TMDFileContentEntryWiiU) == 0x30);\n\n\tbool TMDParser::parse(const uint8* data, size_t size)\n\t{\n\t\tif (size < sizeof(TMDFileHeaderWiiU))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"TMD size {} below minimum size of {}\", size, sizeof(TMDFileHeaderWiiU));\n\t\t\treturn false;\n\t\t}\n\t\tTMDFileHeaderWiiU* header = (TMDFileHeaderWiiU*)data;\n\t\tm_titleId = ((uint64)header->titleIdHigh << 32) | ((uint64)header->titleIdLow);\n\t\tm_titleVersion = header->titleVersion;\n\t\tsize_t expectedSize = sizeof(TMDFileHeaderWiiU) + sizeof(TMDFileContentEntryWiiU) * header->numContent;\n\t\tif (size < expectedSize)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"TMD size {} below expected size of {}. Content count: {}\", size, expectedSize, (uint16)header->numContent);\n\t\t\treturn false;\n\t\t}\n\n\t\t// parse content\n\t\tTMDFileContentEntryWiiU* contentEntry = (TMDFileContentEntryWiiU*)(header + 1);\n\t\tfor (uint32 i = 0; i < header->numContent; i++)\n\t\t{\n\t\t\tContentEntry c{};\n\t\t\tc.contentId = contentEntry->contentId;\n\t\t\tc.index = contentEntry->index;\n\t\t\tc.size = MakeU64(contentEntry->sizeHigh, contentEntry->sizeLow);\n\t\t\tc.contentFlags = static_cast<TMDParser::TMDContentFlags>((uint16)contentEntry->type);\n\t\t\tstd::memcpy(c.hash32, contentEntry->hashSHA256, sizeof(c.hash32));\n\t\t\tm_content.emplace_back(c);\n\t\t\tcontentEntry++;\n\t\t}\n\n\t\t// todo - parse certificates\n\t\treturn true;\n\t}\n\n\t/* ECC PrivateKey helper functions */\n\n\tvoid ECCPrivKey::setPrivateKey(EC_KEY* key)\n\t{\n\t\tconst BIGNUM* bnPrivKey = EC_KEY_get0_private_key(key);\n\t\tmemset(this->keyData, 0, sizeof(this->keyData));\n\t\tBN_bn2binpad(bnPrivKey, this->keyData, sizeof(this->keyData));\n\t}\n\n\tEC_KEY* ECCPrivKey::getPrivateKey() const\n\t{\n\t\tBIGNUM* bn_privKey = BN_new();\n\t\tBN_bin2bn(this->keyData, sizeof(this->keyData), bn_privKey);\n\t\tEC_KEY* ec_privKey = EC_KEY_new_by_curve_name(NID_sect233r1);\n\t\tEC_KEY_set_private_key(ec_privKey, bn_privKey);\n\t\tBN_free(bn_privKey);\n\t\treturn ec_privKey;\n\t}\n\n\tECCPrivKey ECCPrivKey::getDeviceCertPrivateKey()\n\t{\n\t\tECCPrivKey key{};\n\t\tiosuCrypto_getDeviceCertPrivateKey(key.keyData, sizeof(key.keyData));\n\t\treturn key;\n\t}\n\n\t/* ECC PublicKey helper functions */\n\n\tEC_KEY* ECCPubKey::getPublicKey()\n\t{\n\t\tBIGNUM* bn_x = BN_new();\n\t\tBIGNUM* bn_y = BN_new();\n\t\tBN_bin2bn(this->x, sizeof(this->x), bn_x);\n\t\tBN_bin2bn(this->y, sizeof(this->y), bn_y);\n\n\t\tEC_KEY* ec_pubKey = EC_KEY_new_by_curve_name(NID_sect233r1);\n\t\tint r = EC_KEY_set_public_key_affine_coordinates(ec_pubKey, bn_x, bn_y);\n\n\t\tBN_free(bn_x);\n\t\tBN_free(bn_y);\n\n\t\treturn ec_pubKey;\n\t}\n\n\tEC_POINT* ECCPubKey::getPublicKeyAsPoint()\n\t{\n\t\tBN_CTX* ctx = BN_CTX_new();\n\t\tBIGNUM* bn_x = BN_new();\n\t\tBIGNUM* bn_y = BN_new();\n\t\tBN_bin2bn(this->x, sizeof(this->x), bn_x);\n\t\tBN_bin2bn(this->y, sizeof(this->y), bn_y);\n\t\tEC_GROUP* group = EC_GROUP_new_by_curve_name(NID_sect233r1);\n\t\tEC_POINT* pubkey = EC_POINT_new(group);\n\t\tEC_POINT_set_affine_coordinates(group, pubkey, bn_x, bn_y, ctx);\n\t\tEC_GROUP_free(group);\n\t\tBN_CTX_free(ctx);\n\t\tBN_free(bn_x);\n\t\tBN_free(bn_y);\n\t\treturn pubkey;\n\t}\n\n\tECCPubKey ECCPubKey::generateFromPrivateKey(ECCPrivKey& privKey)\n\t{\n\t\tBIGNUM* bn_privKey = BN_new();\n\t\tBN_bin2bn(privKey.keyData, sizeof(privKey.keyData), bn_privKey);\n\n\t\t// gen public key from private key\n\t\tEC_GROUP* group = EC_GROUP_new_by_curve_name(NID_sect233r1);\n\t\tEC_POINT* pubkey = EC_POINT_new(group);\n\t\tEC_POINT_mul(group, pubkey, bn_privKey, NULL, NULL, NULL);\n\t\tBIGNUM* bn_x = BN_new();\n\t\tBIGNUM* bn_y = BN_new();\n\t\tEC_POINT_get_affine_coordinates(group, pubkey, bn_x, bn_y, NULL);\n\n\t\t// store public key\n\t\tECCPubKey genPubKey;\n\t\tBN_bn2binpad(bn_x, genPubKey.x, sizeof(genPubKey.x));\n\t\tBN_bn2binpad(bn_y, genPubKey.y, sizeof(genPubKey.y));\n\t\n\t\t// clean up and return\n\t\tEC_POINT_free(pubkey);\n\t\tBN_free(bn_y);\n\t\tBN_free(bn_x);\n\t\tBN_free(bn_privKey);\n\n\t\treturn genPubKey;\n\t}\n\n\t/* Signature helper functions */\n\n\tECDSA_SIG* ECCSig::getSignature()\n\t{\n\t\tBIGNUM* bn_r = BN_new();\n\t\tBIGNUM* bn_s = BN_new();\n\t\tBN_bin2bn(this->r, 30, bn_r);\n\t\tBN_bin2bn(this->s, 30, bn_s);\n\n\t\tECDSA_SIG* ec_sig = ECDSA_SIG_new();\n\t\tECDSA_SIG_set0(ec_sig, bn_r, bn_s); // ownership of bn_r and bn_s transferred to SIG as well, do not free manually\n\n\t\treturn ec_sig;\n\t}\n\n\tvoid ECCSig::setSignature(ECDSA_SIG* sig)\n\t{\n\t\tconst BIGNUM* sig_r = nullptr, * sig_s = nullptr;\n\t\tECDSA_SIG_get0(sig, &sig_r, &sig_s);\n\n\t\tsint32 lenR = BN_num_bytes(sig_r);\n\t\tsint32 lenS = BN_num_bytes(sig_s);\n\t\tcemu_assert_debug(lenR <= 30);\n\t\tcemu_assert_debug(lenS <= 30);\n\n\t\tmemset(this->r, 0, sizeof(this->r));\n\t\tmemset(this->s, 0, sizeof(this->s));\n\t\tBN_bn2binpad(sig_r, this->r, 30);\n\t\tBN_bn2binpad(sig_s, this->s, 30);\n\t}\n\n\t/* Certificate */\n\n\tbool CertECC::decodeFromBase64(std::string_view input)\n\t{\n\t\tauto v = base64Decode(input);\n\t\tif (v.size() != sizeof(CertECC))\n\t\t\treturn false;\n\t\tmemcpy(this, v.data(), sizeof(CertECC));\n\t\treturn true;\n\t}\n\n\tstd::string CertECC::encodeToBase64()\n\t{\n\t\treturn base64Encode(this, sizeof(CertECC));\n\t}\n\n\tbool CertECC::verifySignatureViaPubKey(ECCPubKey& signerPubKey)\n\t{\n\t\tuint8 hash[SHA256_DIGEST_LENGTH];\n\t\tSHA256((const unsigned char *) this->issuer, 0x100, hash);\n\n\t\tEC_KEY* ecPubKey = signerPubKey.getPublicKey();\n\t\tECDSA_SIG* ecSig = this->signature.getSignature();\n\n\t\tint r = ECDSA_do_verify(hash, sizeof(hash), ecSig, ecPubKey);\n\n\t\tECDSA_SIG_free(ecSig);\n\t\tEC_KEY_free(ecPubKey);\n\n\t\treturn r == 1; // true if valid signature\n\t}\n\n\tvoid CertECC::sign(ECCPrivKey& signerPrivKey)\n\t{\n\t\tuint8 hash[SHA256_DIGEST_LENGTH];\n\t\tSHA256((const unsigned char *) this->issuer, 0x100, hash);\n\n\t\t// generate signature\n\t\tEC_KEY* ec_privKey = signerPrivKey.getPrivateKey();\n\t\tECDSA_SIG* sig = ECDSA_do_sign(hash, sizeof(hash), ec_privKey);\n\t\tEC_KEY_free(ec_privKey);\n\n\t\t// store signature\n\t\tconst BIGNUM* bn_r = nullptr, *bn_s = nullptr;\n\t\tECDSA_SIG_get0(sig, &bn_r, &bn_s);\n\t\tBN_bn2binpad(bn_r, this->signature.r, sizeof(this->signature.r));\n\t\tBN_bn2binpad(bn_s, this->signature.s, sizeof(this->signature.s));\n\n\t\tECDSA_SIG_free(sig);\n\t}\n\n\tCertECC CertECC::GetDeviceCertificate()\n\t{\n\t\tCertECC deviceCert{};\n\t\tiosuCrypto_getDeviceCertificate(&deviceCert, sizeof(CertECC));\n\t\treturn deviceCert;\n\t}\n\n\t// generate a new public key + certificate from privateKey. Certificate is signed with the device key\n\tCertECC CertECC::generateCertificate(uint32 signerTitleIdHigh, uint32 signerTitleIdLow, ECCPrivKey& privKeySigner, ECCPrivKey& privKeyIn, ECCPubKey& pubKeyOut)\n\t{\n\t\tCertECC deviceCert = GetDeviceCertificate();\n\n\t\tCertECC newCert = deviceCert;\n\n\t\tcemu_assert(newCert.signatureType == CertECC::SIGTYPE::ECC_SHA256);\n\t\t// update date\n\t\tnewCert.date = 0;\n\t\t// update issuer\n\t\tstrcat(newCert.issuer, \"-\");\n\t\tstrcat(newCert.issuer, newCert.ngName);\n\n\t\t// update subject\n\t\tmemset(newCert.ngName, 0, sizeof(newCert.ngName));\n\t\tsprintf(newCert.ngName, \"AP%08x%08x\", signerTitleIdHigh, signerTitleIdLow);\n\n\t\t// calculate public key from input private key\n\t\tnewCert.publicKey = ECCPubKey::generateFromPrivateKey(privKeyIn);\n\t\tpubKeyOut = newCert.publicKey;\n\n\t\t// sign certificate\n\t\tnewCert.sign(privKeySigner);\n\n\t\treturn newCert;\n\t}\n\n\tECCSig signHash(uint32 signerTitleIdHigh, uint32 signerTitleIdLow, uint8* hash, sint32 hashLen, CertECC& certChainOut)\n\t{\n\t\t// generate key pair (we only care about the private key)\n\t\tEC_KEY* ec_keyPair = EC_KEY_new_by_curve_name(NID_sect233r1);\n\t\tEC_KEY_generate_key(ec_keyPair);\n\n\t\tECCPrivKey privKey;\n\t\tprivKey.setPrivateKey(ec_keyPair);\n\n\t\tEC_KEY_free(ec_keyPair);\n\n\t\t// get public key and certificate\n\t\tECCPubKey pubKey;\n\t\tECCPrivKey signerPrivKey = ECCPrivKey::getDeviceCertPrivateKey();\n\t\tcertChainOut = CertECC::generateCertificate(signerTitleIdHigh, signerTitleIdLow, signerPrivKey, privKey, pubKey);\n\t\t\n\t\t// generate signature\n\t\tcemu_assert_debug(hashLen == 32);\n\t\tEC_KEY* ec_privKey = privKey.getPrivateKey();\n\t\tECDSA_SIG* sig = ECDSA_do_sign(hash, hashLen, ec_privKey);\n\t\tEC_KEY_free(ec_privKey);\n\n\t\t// verify\n\t\tEC_KEY* ec_pubKey = pubKey.getPublicKey();\n\t\tbool isValid = ECDSA_do_verify(hash, hashLen, sig, ec_pubKey) == 1;\n\t\tEC_KEY_free(ec_pubKey);\n\t\tcemu_assert(isValid);\n\n\t\t// store signature\n\t\tECCSig eccSig;\n\t\tconst BIGNUM* bn_r = nullptr, * bn_s = nullptr;\n\t\tECDSA_SIG_get0(sig, &bn_r, &bn_s);\n\t\tBN_bn2binpad(bn_r, eccSig.r, sizeof(eccSig.r));\n\t\tBN_bn2binpad(bn_s, eccSig.s, sizeof(eccSig.s));\n\n\t\tECDSA_SIG_free(sig);\n\n\t\treturn eccSig;\n\t}\n\n\tbool verifyHashSignature(uint8* hash, sint32 hashLen, ECCPubKey& certChainPubKey, ECCSig& sig)\n\t{\n\t\tEC_KEY* ec_pubKey = certChainPubKey.getPublicKey();\n\n\t\tECDSA_SIG* ecdsa_sig = sig.getSignature();\n\n\t\tbool r = ECDSA_do_verify(hash, hashLen, ecdsa_sig, ec_pubKey) == 1;\n\n\t\tEC_KEY_free(ec_pubKey);\n\t\tECDSA_SIG_free(ecdsa_sig);\n\t\treturn r;\n\t}\n\n\tbool verifyCert(CertECC& cert, NCrypto::ECCPubKey& signerPubKey)\n\t{\n\t\tCertECC::SIGTYPE sigType = cert.signatureType;\n\n\t\tif (sigType == CertECC::SIGTYPE::ECC_SHA256)\n\t\t{\n\t\t\t// used for Wii U certs\n\t\t\tNCrypto::CHash256 hash;\n\t\t\tNCrypto::GenerateHashSHA256(cert.issuer, 0x100, hash);\n\t\t\treturn NCrypto::verifyHashSignature(hash.b, 32, signerPubKey, cert.signature);\n\t\t}\n\t\telse if (sigType == CertECC::SIGTYPE::ECC_SHA1)\n\t\t{\n\t\t\t// from Wii era\n\t\t\tNCrypto::CHash160 hash;\n\t\t\tNCrypto::GenerateHashSHA1(cert.issuer, 0x100, hash);\n\t\t\treturn NCrypto::verifyHashSignature(hash.b, 20, signerPubKey, cert.signature);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t\treturn false;\n\t}\n\n\tuint32 GetDeviceId()\n\t{\n\t\tuint32 deviceId;\n\t\tif (!iosuCrypto_getDeviceId(&deviceId))\n\t\t\treturn 0x11223344;\n\t\treturn deviceId;\n\t}\n\n\tstd::string GetSerial()\n\t{\n\t\tchar serialBuffer[128]{};\n\t\tiosuCrypto_getDeviceSerialString(serialBuffer);\n\t\treturn serialBuffer;\n\t}\n\n\tbool SEEPROM_IsPresent()\n\t{\n\t\treturn hasSeepromMem;\n\t}\n\n\tCafeConsoleRegion SEEPROM_GetRegion()\n\t{\n\t\tuint8 seepromRegionU32[4] = {};\n\t\tiosuCrypto_readSeepromData(seepromRegionU32, 0xA4, 4);\n\t\tif (seepromRegionU32[3] == 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"SEEPROM region is invalid (0)\");\n\t\t}\n\t\treturn (CafeConsoleRegion)seepromRegionU32[3];\n\t}\n\n\tbool OTP_IsPresent()\n\t{\n\t\treturn hasOtpMem;\n\t}\n\n\tbool HasDataForConsoleCert()\n\t{\n\t\treturn SEEPROM_IsPresent() && OTP_IsPresent();\n\t}\n\n\tstd::string GetRegionAsString(CafeConsoleRegion regionCode)\n\t{\n\t\tif (regionCode == CafeConsoleRegion::EUR)\n\t\t\treturn \"EUR\";\n\t\telse if (regionCode == CafeConsoleRegion::USA)\n\t\t\treturn \"USA\";\n\t\telse if (regionCode == CafeConsoleRegion::JPN)\n\t\t\treturn \"JPN\";\n\t\telse if (regionCode == CafeConsoleRegion::CHN)\n\t\t\treturn \"CHN\";\n\t\telse if (regionCode == CafeConsoleRegion::KOR)\n\t\t\treturn \"KOR\";\n\t\telse if (regionCode == CafeConsoleRegion::TWN)\n\t\t\treturn \"TWN\";\n\t\tcemuLog_log(LogType::Force, \"Unknown region code 0x{:x}\", (uint32)regionCode);\n\t\treturn \"UKN\";\n\t}\n\n\tconst std::unordered_map<sint32, const char*> g_countryTable = {\n\t\t{1,\"JP\"},\n\t\t{8,\"AI\"},\n\t\t{9,\"AG\"},\n\t\t{10,\"AR\"},\n\t\t{11,\"AW\"},\n\t\t{12,\"BS\"},\n\t\t{13,\"BB\"},\n\t\t{14,\"BZ\"},\n\t\t{15,\"BO\"},\n\t\t{16,\"BR\"},\n\t\t{17,\"VG\"},\n\t\t{18,\"CA\"},\n\t\t{19,\"KY\"},\n\t\t{20,\"CL\"},\n\t\t{21,\"CO\"},\n\t\t{22,\"CR\"},\n\t\t{23,\"DM\"},\n\t\t{24,\"DO\"},\n\t\t{25,\"EC\"},\n\t\t{26,\"SV\"},\n\t\t{27,\"GF\"},\n\t\t{28,\"GD\"},\n\t\t{29,\"GP\"},\n\t\t{30,\"GT\"},\n\t\t{31,\"GY\"},\n\t\t{32,\"HT\"},\n\t\t{33,\"HN\"},\n\t\t{34,\"JM\"},\n\t\t{35,\"MQ\"},\n\t\t{36,\"MX\"},\n\t\t{37,\"MS\"},\n\t\t{38,\"AN\"},\n\t\t{39,\"NI\"},\n\t\t{40,\"PA\"},\n\t\t{41,\"PY\"},\n\t\t{42,\"PE\"},\n\t\t{43,\"KN\"},\n\t\t{44,\"LC\"},\n\t\t{45,\"VC\"},\n\t\t{46,\"SR\"},\n\t\t{47,\"TT\"},\n\t\t{48,\"TC\"},\n\t\t{49,\"US\"},\n\t\t{50,\"UY\"},\n\t\t{51,\"VI\"},\n\t\t{52,\"VE\"},\n\t\t{64,\"AL\"},\n\t\t{65,\"AU\"},\n\t\t{66,\"AT\"},\n\t\t{67,\"BE\"},\n\t\t{68,\"BA\"},\n\t\t{69,\"BW\"},\n\t\t{70,\"BG\"},\n\t\t{71,\"HR\"},\n\t\t{72,\"CY\"},\n\t\t{73,\"CZ\"},\n\t\t{74,\"DK\"},\n\t\t{75,\"EE\"},\n\t\t{76,\"FI\"},\n\t\t{77,\"FR\"},\n\t\t{78,\"DE\"},\n\t\t{79,\"GR\"},\n\t\t{80,\"HU\"},\n\t\t{81,\"IS\"},\n\t\t{82,\"IE\"},\n\t\t{83,\"IT\"},\n\t\t{84,\"LV\"},\n\t\t{85,\"LS\"},\n\t\t{86,\"LI\"},\n\t\t{87,\"LT\"},\n\t\t{88,\"LU\"},\n\t\t{89,\"MK\"},\n\t\t{90,\"MT\"},\n\t\t{91,\"ME\"},\n\t\t{92,\"MZ\"},\n\t\t{93,\"NA\"},\n\t\t{94,\"NL\"},\n\t\t{95,\"NZ\"},\n\t\t{96,\"NO\"},\n\t\t{97,\"PL\"},\n\t\t{98,\"PT\"},\n\t\t{99,\"RO\"},\n\t\t{100,\"RU\"},\n\t\t{101,\"RS\"},\n\t\t{102,\"SK\"},\n\t\t{103,\"SI\"},\n\t\t{104,\"ZA\"},\n\t\t{105,\"ES\"},\n\t\t{106,\"SZ\"},\n\t\t{107,\"SE\"},\n\t\t{108,\"CH\"},\n\t\t{109,\"TR\"},\n\t\t{110,\"GB\"},\n\t\t{111,\"ZM\"},\n\t\t{112,\"ZW\"},\n\t\t{113,\"AZ\"},\n\t\t{114,\"MR\"},\n\t\t{115,\"ML\"},\n\t\t{116,\"NE\"},\n\t\t{117,\"TD\"},\n\t\t{118,\"SD\"},\n\t\t{119,\"ER\"},\n\t\t{120,\"DJ\"},\n\t\t{121,\"SO\"},\n\t\t{122,\"AD\"},\n\t\t{123,\"GI\"},\n\t\t{124,\"GG\"},\n\t\t{125,\"IM\"},\n\t\t{126,\"JE\"},\n\t\t{127,\"MC\"},\n\t\t{128,\"TW\"},\n\t\t{136,\"KR\"},\n\t\t{144,\"HK\"},\n\t\t{145,\"MO\"},\n\t\t{152,\"ID\"},\n\t\t{153,\"SG\"},\n\t\t{154,\"TH\"},\n\t\t{155,\"PH\"},\n\t\t{156,\"MY\"},\n\t\t{160,\"CN\"},\n\t\t{168,\"AE\"},\n\t\t{170,\"EG\"},\n\t\t{171,\"OM\"},\n\t\t{172,\"QA\"},\n\t\t{173,\"KW\"},\n\t\t{174,\"SA\"},\n\t\t{175,\"SY\"},\n\t\t{176,\"BH\"},\n\t\t{177,\"JO\"},\n\t\t{184,\"SM\"},\n\t\t{185,\"VA\"},\n\t\t{186,\"BM\"},\n\t\t{187,\"IN\"},\n\t\t{192,\"NG\"},\n\t\t{193,\"AO\"},\n\t\t{194,\"GH\"}\n\t};\n\n\tconst char* GetCountryAsString(sint32 index)\n\t{\n\t\tconst auto it = g_countryTable.find(index);\n\t\tif (it == g_countryTable.cend())\n\t\t\treturn \"NN\";\n\t\treturn it->second;\n\t}\n\n\tsize_t GetCountryCount()\n\t{\n\t\treturn g_countryTable.size();\n\t}\n\n\tvoid unitTests()\n\t{\n\t\tbase64Tests();\n\t}\n\n};\n"
  },
  {
    "path": "src/Cemu/ncrypto/ncrypto.h",
    "content": "#pragma once\n#include \"Common/betype.h\"\n#include \"config/CemuConfig.h\" // for ConsoleRegion\n\n/* OpenSSL forward declarations */\ntypedef struct ec_key_st EC_KEY;\ntypedef struct ec_point_st EC_POINT;\ntypedef struct ECDSA_SIG_st ECDSA_SIG;\n\nnamespace NCrypto\n{\n\t/* Base 64 */\n\tstd::string base64Encode(const void* inputMem, size_t inputLen);\n\tstd::vector<uint8> base64Decode(std::string_view inputStr);\n\t\n\t/* key and iv helper struct */\n\tstruct AesKey \n\t{\n\t\tstatic constexpr size_t SIZE = 16;\n\t\tuint8 b[SIZE];\n\t};\n\n\tstruct AesIv\n\t{\n\t\tstatic constexpr size_t SIZE = 16;\n\t\tuint8 iv[SIZE];\n\t};\n\n\t/* ECC Certificate */\n\tstruct ECCPrivKey\n\t{\n\t\tuint8 keyData[30];\n\n\t\tvoid setPrivateKey(EC_KEY* key);\n\t\tEC_KEY* getPrivateKey() const;\n\n\t\tstatic ECCPrivKey getDeviceCertPrivateKey();\n\t};\n\n\tstruct ECCPubKey\n\t{\n\t\tuint8 x[30];\n\t\tuint8 y[30];\n\n\t\tEC_KEY* getPublicKey();\n\t\tEC_POINT* getPublicKeyAsPoint();\n\n\t\t[[nodiscard]] static ECCPubKey generateFromPrivateKey(ECCPrivKey& privKey);\n\t};\n\n\tstruct ECCSig\n\t{\n\t\tuint8 r[30];\n\t\tuint8 s[30];\n\n\t\tECDSA_SIG* getSignature();\n\t\tvoid setSignature(ECDSA_SIG* sig);\n\n\t\tbool doesMatch(ECCSig& otherSig) const\n\t\t{\n\t\t\treturn memcmp(this->r, otherSig.r, sizeof(this->r)) == 0 && memcmp(this->s, otherSig.s, sizeof(this->s)) == 0;\n\t\t}\n\n\t\tstd::string encodeToBase64()\n\t\t{\n\t\t\treturn base64Encode(this, 60);\n\t\t}\n\t};\n\n\tstruct CHash256 // SHA256\n\t{\n\t\tuint8 b[32];\n\t};\n\n\tstruct CHash160 // SHA1\n\t{\n\t\tuint8 b[20];\n\t};\n\n\tstruct CertECC\n\t{\n\t\tenum class SIGTYPE : uint32\n\t\t{\n\t\t\tECC_SHA1   = 0x00010002, // guessed\n\t\t\tECC_SHA256 = 0x00010005\n\t\t};\n\n\t\t/* +0x000 */ betype<SIGTYPE>\tsignatureType; // 01 00 02 00\n\t\t/* +0x004 */ ECCSig\t\t\t\tsignature; //uint8\t\t\t\tsignature[0x3C]; // from OTP 0xA3*4\n\t\t/* +0x040 */ uint8\t\t\t\tukn040[0x40]; // seems to be just padding\n\t\t/* +0x080 */ char\t\t\t\tissuer[0x40]; // \"Root - CA%08x - MS%08x\" \n\t\t/* +0x0C0 */ char\t\t\t\tukn0C0[0x4]; // ??? 00 00 00 02 ?\n\t\t/* +0x0C4 */ char\t\t\t\tngName[0x40]; // \"NG%08X\"\n\t\t/* +0x104 */ uint32\t\t\t\tdate; // big endian? (from OTP 0xA2*4)\n\t\t/* +0x108 */ ECCPubKey\t\t\tpublicKey; //uint8\t\t\t\tpublicKey[0x3C];\n\t\t/* +0x144 */ uint8\t\t\t\tpadding[0x180 - 0x144];\n\n\t\tbool decodeFromBase64(std::string_view input);\n\t\tstd::string encodeToBase64();\n\n\t\tbool verifySignatureViaPubKey(ECCPubKey& signerPubKey);\n\t\tvoid sign(ECCPrivKey& signerPrivKey);\n\n\t\tstatic CertECC GetDeviceCertificate();\n\t\tstatic CertECC generateCertificate(uint32 signerTitleIdHigh, uint32 signerTitleIdLow, ECCPrivKey& privKeySigner, ECCPrivKey& privKeyIn, ECCPubKey& pubKeyOut);\n\t};\n\n\tstatic_assert(sizeof(CertECC) == 0x180);\n\n\n\t/* ETicket */\n\n\tclass ETicketParser  // .tik parser\n\t{\n\tpublic:\n\t\tbool parse(const uint8* data, size_t size);\n\t\tstatic bool Depersonalize(uint8* ticketData, size_t ticketSize, uint32 deviceId, const ECCPrivKey& devicePrivKey);\n\n\t\tuint64 GetTicketId() const\n\t\t{\n\t\t\treturn m_ticketId;\n\t\t}\n\n\t\tuint64 GetTitleId() const\n\t\t{\n\t\t\treturn m_titleId;\n\t\t}\n\n\t\tuint16 GetTicketVersion() const\n\t\t{\n\t\t\treturn m_titleVersion;\n\t\t}\n\n\t\tvoid GetTitleKey(AesKey& key);\n\n\t\tbool IsPersonalized()\n\t\t{\n\t\t\treturn m_isPersonalized;\n\t\t}\n\n\t\tbool CheckRight(size_t index)\n\t\t{\n\t\t\tif (index >= m_contentRights.size())\n\t\t\t\treturn false;\n\t\t\treturn m_contentRights[index];\n\t\t}\n\n\tprivate:\n\t\tuint64 m_titleId;\n\t\tuint16 m_titleVersion;\n\t\tuint64 m_ticketId;\n\t\tuint8 m_ticketFormatVersion;\n\t\tuint8 m_encryptedTitleKey[16];\n\t\t// personalized data\n\t\tbool m_isPersonalized;\n\t\tuint32 m_deviceId;\n\t\tECCPubKey m_publicKey;\n\t\t// rights\n\t\tstd::vector<bool> m_contentRights;\n\t};\n\n\t/* Title meta data */\n\n\tclass TMDParser\n\t{\n\tpublic:\n\t\tenum class TMDContentFlags : uint16\n\t\t{\n\t\t\t// 0x0001 -> Is encrypted?\n\t\t\tFLAG_SHA1 = 0x2000, // if not set, use SHA256\n\t\t\tFLAG_HASHED_CONTENT = 0x0002, // .app uses hashed format\n\t\t};\n\n\t\tstruct ContentEntry\n\t\t{\n\t\t\tuint32 contentId;\n\t\t\tuint16 index;\n\t\t\tTMDContentFlags contentFlags;\n\t\t\tuint64 size;\n\t\t\tuint8 hash32[32];\n\t\t};\n\n\t\tuint64 getTitleId() const\n\t\t{\n\t\t\treturn m_titleId;\n\t\t}\n\n\t\tuint16 getTitleVersion() const\n\t\t{\n\t\t\treturn m_titleVersion;\n\t\t}\n\n\t\tbool parse(const uint8* data, size_t size);\n\t\tstd::vector<ContentEntry>& GetContentList()\n\t\t{\n\t\t\treturn m_content;\n\t\t}\n\n\tprivate:\n\t\tuint64 m_titleId;\n\t\tuint16 m_titleVersion;\n\t\tstd::vector<ContentEntry> m_content;\n\t};\n\n\tDEFINE_ENUM_FLAG_OPERATORS(TMDParser::TMDContentFlags);\n\n\tvoid GenerateHashSHA256(const void* data, size_t len, CHash256& hashOut);\n\tECCSig signHash(uint32 signerTitleIdHigh, uint32 signerTitleIdLow, uint8* hash, sint32 hashLen, CertECC& certChainOut);\n\n\tuint32 GetDeviceId();\n\tstd::string GetSerial();\n\tCafeConsoleRegion SEEPROM_GetRegion();\n\tstd::string GetRegionAsString(CafeConsoleRegion regionCode);\n\tconst char* GetCountryAsString(sint32 index); // returns NN if index is not valid or known\n\tsize_t GetCountryCount();\n\tbool SEEPROM_IsPresent();\n\tbool OTP_IsPresent();\n\n\tbool HasDataForConsoleCert();\n\n\tvoid unitTests();\n}"
  },
  {
    "path": "src/Cemu/nex/nex.cpp",
    "content": "#include \"prudp.h\"\n#include \"nex.h\"\n#include \"nexThread.h\"\n\n#include \"util/crypto/md5.h\"\n\n// for inet_pton:\n#if BOOST_OS_WINDOWS\n#include <WS2tcpip.h>\n#else\n#include <arpa/inet.h>\n#endif\n\nuint32 _currentCallId = 1;\n\nsint32 nexService_parseResponse(uint8* data, sint32 length, nexServiceResponse_t* response)\n{\n\tif (length < 4)\n\t\treturn 0;\n\t// get length field\n\tuint32 responseLength = *(uint32*)(data + 0x0);\n\tlength -= 4;\n\tif (responseLength > (uint32)length)\n\t\treturn 0;\n\tif (responseLength < 6)\n\t\treturn 0;\n\tuint8 protocolId = *(uint8*)(data + 0x04);\n\tbool isRequest = (protocolId & 0x80) != 0;\n\tprotocolId &= 0x7F;\n\tif (isRequest)\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tassert_dbg(); // should never reach since we handle requests before this function is called\n#endif\n\t}\n\tuint8 success = *(uint8*)(data + 0x5);\n\tif (success == 0)\n\t{\n\t\t// error\n\t\tuint32 errorCode;\n\t\tif (length < 0xA)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\t\terrorCode = *(uint32*)(data + 0x6);\n\t\tresponse->errorCode = errorCode;\n\t\tresponse->callId = *(uint32*)(data + 0xA);\n\t\tresponse->isSuccessful = false;\n\t\tresponse->protocolId = protocolId;\n\t\tresponse->methodId = 0xFFFFFFFF;\n\t\treturn responseLength + 4;\n\t}\n\telse\n\t{\n\t\tif (responseLength < 0xA)\n\t\t\treturn 0;\n\t\tresponse->errorCode = 0;\n\t\tresponse->isSuccessful = true;\n\t\tresponse->protocolId = protocolId;\n\t\tresponse->callId = *(uint32*)(data + 0x6);\n\t\tresponse->methodId = (*(uint32*)(data + 0xA)) & 0x7FFF;\n\t\tresponse->data = nexPacketBuffer(data + 0xE, responseLength - (0xE - 4), false);\n\t\treturn responseLength+4;\n\t}\n\treturn 0;\n}\n\nsint32 nexService_parseRequest(uint8* data, sint32 length, nexServiceRequest_t* request)\n{\n\tif (length < 4)\n\t\treturn 0;\n\t// get length field\n\tuint32 requestLength = *(uint32*)(data + 0x0) + 4;\n\tif (requestLength > (uint32)length)\n\t\treturn 0;\n\tif (requestLength < 13)\n\t\treturn 0;\n\tuint8 protocolId = *(uint8*)(data + 0x4);\n\tbool isRequest = (protocolId & 0x80) != 0;\n\tprotocolId &= 0x7F;\n\tif(isRequest == false)\n\t\tassert_dbg();\n\tuint32 callId = *(uint32*)(data + 0x5);\n\tuint32 methodId = *(uint32*)(data + 0x9);\n\n\tuint8* dataPtr = (data + 0xD);\n\tsint32 dataLength = (sint32)(requestLength - 0xD);\n\n\trequest->callId = callId;\n\trequest->methodId = methodId;\n\trequest->protocolId = protocolId;\n\n\trequest->data = nexPacketBuffer(dataPtr, dataLength, false);\n\n\treturn requestLength;\n}\n\nnexService::nexService()\n{\n\tconnectionState = STATE_CONNECTING;\n\tconNexService = nullptr;\n\tisAsync = false;\n\tisDestroyed = false;\n\tisSecureService = false;\n}\n\nnexService::nexService(prudpClient* con) : nexService()\n{\n\tif (con->IsConnected() == false)\n\t\tcemu_assert_suspicious();\n\tthis->conNexService = con;\n\tbufferReceive = std::vector<uint8>(1024 * 4);\n}\n\nnexService::nexService(uint32 ip, uint16 port, const char* accessKey) : nexService()\n{\n\t// unsecured connection\n\tisSecureService = false;\n\tconNexService = new prudpClient(ip, port, accessKey);\n\tbufferReceive = std::vector<uint8>(1024 * 4);\n}\n\nnexService::~nexService()\n{\n\t// call error handlers for unfinished method calls\n\tfor (auto& it : list_activeRequests)\n\t{\n\t\tnexServiceResponse_t response = { 0 };\n\t\tresponse.isSuccessful = false;\n\t\tresponse.errorCode = ERR_TIMEOUT;\n\t\tresponse.custom = it.custom;\n\t\tif (it.nexServiceResponse)\n\t\t\tit.nexServiceResponse(this, &response);\n\t\telse\n\t\t{\n\t\t\tit.cb2(&response);\n\t\t}\n\t}\n\tif (conNexService)\n\t\tdelete conNexService;\n}\n\nvoid nexService::destroy()\n{\n\tif (nexThread_isCurrentThread())\n\t{\n\t\tdelete this;\n\t\treturn;\n\t}\n\tif (this->isAsync)\n\t\tisDestroyed = true;\n\telse\n\t\tdelete this;\n}\n\nbool nexService::isMarkedForDestruction()\n{\n\treturn isDestroyed;\n}\n\nvoid nexService::callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer* parameter, void(*nexServiceResponse)(nexService* nex, nexServiceResponse_t* serviceResponse), void* custom, bool callHandlerIfError)\n{\n\tqueuedRequest_t queueRequest = { 0 };\n\tqueueRequest.protocolId = protocolId;\n\tqueueRequest.methodId = methodId;\n\tqueueRequest.parameterData.assign(parameter->getDataPtr(), parameter->getDataPtr() + parameter->getWriteIndex());\n\tqueueRequest.nexServiceResponse = nexServiceResponse;\n\tqueueRequest.custom = custom;\n\tqueueRequest.callHandlerIfError = callHandlerIfError;\n\tmtx_queuedRequests.lock();\n\tqueuedRequests.push_back(queueRequest);\n\tmtx_queuedRequests.unlock();\n}\n\nvoid nexService::callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer* parameter, std::function<void(nexServiceResponse_t*)> cb, bool callHandlerIfError)\n{\n\tqueuedRequest_t queueRequest = { 0 };\n\tqueueRequest.protocolId = protocolId;\n\tqueueRequest.methodId = methodId;\n\tqueueRequest.parameterData.assign(parameter->getDataPtr(), parameter->getDataPtr() + parameter->getWriteIndex());\n\tqueueRequest.nexServiceResponse = nullptr;\n\tqueueRequest.cb2 = cb;\n\tqueueRequest.callHandlerIfError = callHandlerIfError;\n\tmtx_queuedRequests.lock();\n\tqueuedRequests.push_back(queueRequest);\n\tmtx_queuedRequests.unlock();\n}\n\nvoid nexService::processQueuedRequest(queuedRequest_t* queuedRequest)\n{\n\tuint32 callId = _currentCallId;\n\t_currentCallId++;\n\t// check state of connection\n\tif (conNexService->GetConnectionState() != prudpClient::ConnectionState::Connected)\n\t{\n\t\tnexServiceResponse_t response = { 0 };\n\t\tresponse.isSuccessful = false;\n\t\tresponse.errorCode = ERR_NO_CONNECTION;\n\t\tresponse.custom = queuedRequest->custom;\n\t\tif (queuedRequest->nexServiceResponse)\n\t\t\tqueuedRequest->nexServiceResponse(this, &response);\n\t\telse\n\t\t{\n\t\t\tqueuedRequest->cb2(&response);\n\t\t}\n\t\treturn;\n\t}\n\tuint8 packetBuffer[1024 * 8];\n\t*(uint32*)(packetBuffer + 0x00) = 1 + 4 + 4 + (uint32)queuedRequest->parameterData.size(); // size\n\t*(uint8*)(packetBuffer + 0x04) = queuedRequest->protocolId | PROTOCOL_BIT_REQUEST;\n\t*(uint32*)(packetBuffer + 0x05) = callId;\n\t*(uint32*)(packetBuffer + 0x09) = queuedRequest->methodId;\n\tif (queuedRequest->parameterData.size() >= 1024 * 7)\n\t\tassert_dbg();\n\tmemcpy((packetBuffer + 0x0D), &queuedRequest->parameterData.front(), queuedRequest->parameterData.size());\n\tsint32 length = 0xD + (sint32)queuedRequest->parameterData.size();\n\tconNexService->SendDatagram(packetBuffer, length, true);\n\t// remember request\n\tnexActiveRequestInfo_t requestInfo = { 0 };\n\trequestInfo.callId = callId;\n\trequestInfo.methodId = queuedRequest->methodId;\n\trequestInfo.protocolId = queuedRequest->protocolId;\n\tif (queuedRequest->nexServiceResponse)\n\t{\n\t\trequestInfo.nexServiceResponse = queuedRequest->nexServiceResponse;\n\t\trequestInfo.custom = queuedRequest->custom;\n\t}\n\telse\n\t{\n\t\trequestInfo.cb2 = queuedRequest->cb2;\n\t}\n\trequestInfo.handleError = queuedRequest->callHandlerIfError;\n\trequestInfo.requestTime = prudpGetMSTimestamp();\n\tlist_activeRequests.push_back(requestInfo);\n}\n\nvoid nexService::update()\n{\n\tif (connectionState == STATE_CONNECTED)\n\t{\n\t\tupdateNexServiceConnection();\n\t\t// process any queued requests\n\t\tmtx_queuedRequests.lock();\n\t\tfor (auto& request : queuedRequests)\n\t\t{\n\t\t\tprocessQueuedRequest(&request);\n\t\t}\n\t\tqueuedRequests.clear();\n\t\tmtx_queuedRequests.unlock();\n\t}\n\telse if (connectionState == STATE_CONNECTING)\n\t{\n\t\tupdateTemporaryConnections();\n\t}\n\t// handle request timeouts\n\tuint32 currentTimestamp = prudpGetMSTimestamp();\n\tsint32 idx = 0;\n\twhile (idx < list_activeRequests.size())\n\t{\n\t\tauto& it = list_activeRequests[idx];\n\t\tif ((uint32)(currentTimestamp - it.requestTime) >= 10000)\n\t\t{\n\t\t\t// time out after 10 seconds\n\t\t\tnexServiceResponse_t response = { 0 };\n\t\t\tresponse.isSuccessful = false;\n\t\t\tresponse.errorCode = ERR_TIMEOUT;\n\t\t\tresponse.custom = it.custom;\n\t\t\tif (it.nexServiceResponse)\n\t\t\t\tit.nexServiceResponse(this, &response);\n\t\t\telse\n\t\t\t{\n\t\t\t\tit.cb2(&response);\n\t\t\t}\n\t\t\tlist_activeRequests.erase(list_activeRequests.cbegin()+idx);\n\t\t\tcontinue;\n\t\t}\n\t\tidx++;\n\t}\n}\n\nprudpClient* nexService::getPRUDPConnection()\n{\n\treturn conNexService;\n}\n\nsint32 nexService::getState()\n{\n\treturn connectionState;\n}\n\t\nvoid nexService::registerForAsyncProcessing()\n{\n\tif (isAsync)\n\t\treturn;\n\tnexThread_registerService(this);\n\tisAsync = true;\n}\n\nvoid nexService::updateTemporaryConnections()\n{\n\t// check for connection\n\tconNexService->Update();\n\tif (conNexService->IsConnected())\n\t{\n\t\tif (connectionState == STATE_CONNECTING)\n\t\t\tconnectionState = STATE_CONNECTED;\n\t}\n\tif (conNexService->GetConnectionState() == prudpClient::ConnectionState::Disconnected)\n\t\tconnectionState = STATE_DISCONNECTED;\n}\n\n// returns true if the packet is a nex RPC request, in case of error false is returned\nbool nexIsRequest(uint8* data, sint32 length)\n{\n\tif (length < 5)\n\t\treturn false;\n\tuint8 protocolId = *(uint8*)(data + 0x04);\n\tbool isRequest = (protocolId & 0x80) != 0;\n\treturn isRequest;\n}\n\nvoid nexService::registerProtocolRequestHandler(uint8 protocol, void(*processRequest)(nexServiceRequest_t* request), void* custom)\n{\n\tprotocolHandler_t protocolHandler;\n\tprotocolHandler.protocol = protocol;\n\tprotocolHandler.processRequest = processRequest;\n\tprotocolHandler.custom = custom;\n\tlist_requestHandlers.push_back(protocolHandler);\n}\n\nvoid nexService::sendRequestResponse(nexServiceRequest_t* request, uint32 errorCode, uint8* data, sint32 length)\n{\n\tcemu_assert_debug(length == 0); // non-zero length is todo\n\n\tuint8 packetBuffer[256];\n\tnexPacketBuffer response(packetBuffer, sizeof(packetBuffer), true);\n\n\tbool isSuccess = (errorCode == 0);\n\t// write placeholder for response length\n\tresponse.writeU32(0);\n\t// header fields\n\tresponse.writeU8(request->protocolId&0x7F);\n\tresponse.writeU8(isSuccess);\n\tif (isSuccess)\n\t{\n\t\tresponse.writeU32(request->callId);\n\t\tresponse.writeU32(request->methodId);\n\t\t// write data\n\t\t// todo\n\t}\n\telse\n\t{\n\t\tresponse.writeU32(errorCode);\n\t\tresponse.writeU32(request->callId);\n\t}\n\t// update length field\n\t*(uint32*)response.getDataPtr() = response.getWriteIndex()-4;\n\tif(request->nex->conNexService)\n\t\trequest->nex->conNexService->SendDatagram(response.getDataPtr(), response.getWriteIndex(), true);\n}\n\nvoid nexService::updateNexServiceConnection()\n{\n\tif (conNexService->GetConnectionState() == prudpClient::ConnectionState::Disconnected)\n\t{\n\t\tthis->connectionState = STATE_DISCONNECTED;\n\t\treturn;\n\t}\n\tconNexService->Update();\n\tsint32 datagramLen = conNexService->ReceiveDatagram(bufferReceive);\n\tif (datagramLen > 0)\n\t{\n\t\tif (nexIsRequest(&bufferReceive[0], datagramLen))\n\t\t{\n\t\t\t// request\n\t\t\tnexServiceRequest_t nexServiceRequest;\n\t\t\tsint32 parsedLength = nexService_parseRequest(&bufferReceive[0], datagramLen, &nexServiceRequest);\n\t\t\tif (parsedLength > 0)\n\t\t\t{\n\t\t\t\tnexServiceRequest.nex = this;\n\t\t\t\t// call request handler\n\t\t\t\tfor (auto& it : list_requestHandlers)\n\t\t\t\t{\n\t\t\t\t\tif (it.protocol == nexServiceRequest.protocolId)\n\t\t\t\t\t{\n\t\t\t\t\t\tnexServiceRequest.custom = it.custom;\n\t\t\t\t\t\tit.processRequest(&nexServiceRequest);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcemu_assert_debug(parsedLength == datagramLen);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// response\n\t\t\tnexServiceResponse_t nexServiceResponse;\n\t\t\tsint32 parsedLength = nexService_parseResponse(&bufferReceive[0], datagramLen, &nexServiceResponse);\n\t\t\tif (parsedLength > 0)\n\t\t\t{\n\t\t\t\tnexServiceResponse.nex = this;\n\t\t\t\t// call response handler\n\t\t\t\tfor (sint32 i = 0; i < list_activeRequests.size(); i++)\n\t\t\t\t{\n\t\t\t\t\tif (nexServiceResponse.callId == list_activeRequests[i].callId &&\n\t\t\t\t\t\tnexServiceResponse.protocolId == list_activeRequests[i].protocolId &&\n\t\t\t\t\t\t(nexServiceResponse.methodId == list_activeRequests[i].methodId || nexServiceResponse.methodId == 0xFFFFFFFF))\n\t\t\t\t\t{\n\t\t\t\t\t\tnexServiceResponse.custom = list_activeRequests[i].custom;\n\t\t\t\t\t\tif (nexServiceResponse.isSuccessful || list_activeRequests[i].handleError)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (list_activeRequests[i].nexServiceResponse)\n\t\t\t\t\t\t\t\tlist_activeRequests[i].nexServiceResponse(this, &nexServiceResponse);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlist_activeRequests[i].cb2(&nexServiceResponse);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// remove entry\n\t\t\t\t\t\tlist_activeRequests.erase(list_activeRequests.begin() + i);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcemu_assert_debug(parsedLength == datagramLen);\n\t\t}\n\t}\n}\n\nbool _extractStationUrlParamValue(const char* urlStr, const char* paramName, char* output, sint32 maxLength)\n{\t\n\tsize_t paramNameLen = strlen(paramName);\n\tconst char* optionPtr = strstr(urlStr, paramName);\n\twhile (optionPtr)\n\t{\n\t\tif (optionPtr[paramNameLen] == '=')\n\t\t{\n\t\t\toutput[maxLength - 1] = '\\0';\n\t\t\tfor (sint32 i = 0; i < maxLength - 1; i++)\n\t\t\t{\n\t\t\t\tchar c = optionPtr[paramNameLen + 1 + i];\n\t\t\t\tif (c == ';' || c == '\\0')\n\t\t\t\t{\n\t\t\t\t\toutput[i] = '\\0';\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\toutput[i] = c;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\t// next\n\t\toptionPtr = strstr(optionPtr+1, paramName);\n\t}\n\treturn false;\n}\n\nvoid nexServiceAuthentication_parseStationURL(char* urlStr, prudpStationUrl* stationUrl)\n{\n\t// example:\n\t// prudps:/address=34.210.xxx.xxx;port=60181;CID=1;PID=2;sid=1;stream=10;type=2\n\n\tmemset(stationUrl, 0, sizeof(prudpStationUrl));\n\n\tchar optionValue[128];\n\tif (_extractStationUrlParamValue(urlStr, \"address\", optionValue, sizeof(optionValue)))\n\t{\n\t\tinet_pton(AF_INET, optionValue, &stationUrl->ip);\n\t}\n\tif (_extractStationUrlParamValue(urlStr, \"port\", optionValue, sizeof(optionValue)))\n\t{\n\t\tstationUrl->port = atoi(optionValue);\n\t}\n\tif (_extractStationUrlParamValue(urlStr, \"CID\", optionValue, sizeof(optionValue)))\n\t{\n\t\tstationUrl->cid = atoi(optionValue);\n\t}\n\tif (_extractStationUrlParamValue(urlStr, \"PID\", optionValue, sizeof(optionValue)))\n\t{\n\t\tstationUrl->pid = atoi(optionValue);\n\t}\n\tif (_extractStationUrlParamValue(urlStr, \"sid\", optionValue, sizeof(optionValue)))\n\t{\n\t\tstationUrl->sid = atoi(optionValue);\n\t}\n\tif (_extractStationUrlParamValue(urlStr, \"stream\", optionValue, sizeof(optionValue)))\n\t{\n\t\tstationUrl->stream = atoi(optionValue);\n\t}\n\tif (_extractStationUrlParamValue(urlStr, \"type\", optionValue, sizeof(optionValue)))\n\t{\n\t\tstationUrl->type = atoi(optionValue);\n\t}\n}\n\ntypedef struct  \n{\n\tuint32 userPid;\n\tuint8 kerberosTicket[1024];\n\tsint32 kerberosTicketSize;\n\tuint8 kerberosTicket2[4096];\n\tsint32 kerberosTicket2Size;\n\tprudpStationUrl server;\n\t// progress info\n\tbool hasError;\n\tbool done;\n}authenticationService_t;\n\nvoid nexServiceAuthentication_handleResponse_requestTicket(nexService* nex, nexServiceResponse_t* response)\n{\n\tauthenticationService_t* authService = (authenticationService_t*)response->custom;\n\tif (response->isSuccessful == false)\n\t{\n\t\tcemuLog_log(LogType::Force, \"NEX: RPC error while requesting auth ticket with error code 0x{:08x}\", response->errorCode);\n\t\tauthService->hasError = true;\n\t\treturn;\n\t}\n\tuint32 returnValue = response->data.readU32();\n\tif (returnValue & 0x80000000)\n\t{\n\t\tcemuLog_log(LogType::Force, \"NEX: Failed to request auth ticket with error code 0x{:08x}\", returnValue);\n\t\tauthService->hasError = true;\n\t}\n\tauthService->kerberosTicket2Size = response->data.readBuffer(authService->kerberosTicket2, sizeof(authService->kerberosTicket2));\n\tif (response->data.hasReadOutOfBounds())\n\t{\n\t\tauthService->hasError = true;\n\t\tcemuLog_log(LogType::Force, \"NEX: Out of bounds error while reading auth ticket\");\n\t\treturn;\n\t}\n\tauthService->done = true;\n}\n\nvoid nexServiceAuthentication_handleResponse_login(nexService* nex, nexServiceResponse_t* response)\n{\n\tauthenticationService_t* authService = (authenticationService_t*)response->custom;\n\tif (response->isSuccessful == false)\n\t{\n\t\tauthService->hasError = true;\n\t\tcemuLog_log(LogType::Force, \"NEX: RPC error in login response 0x{:08x}\", response->errorCode);\n\t\treturn;\n\t}\n\n\tuint32 returnValue = response->data.readU32();\n\tif (returnValue & 0x80000000)\n\t{\n\t\tauthService->hasError = true;\n\t\tcemuLog_log(LogType::Force, \"NEX: Error 0x{:08x} in login response (returnCode 0x{:08x})\", response->errorCode, returnValue);\n\t\treturn;\n\t}\n\n\tuint32 userPid = response->data.readU32();\n\t\n\t// kerberos ticket\n\tauthService->kerberosTicketSize = response->data.readBuffer(authService->kerberosTicket, sizeof(authService->kerberosTicket));\n\t// RVConnection data\n\t// server address (regular protocol)\n\tchar serverAddress[1024];\n\tresponse->data.readString(serverAddress, sizeof(serverAddress));\n\tnexServiceAuthentication_parseStationURL(serverAddress, &authService->server);\n\t// special protocols\n\tif (response->data.readU32() != 0)\n\t\tassert_dbg(); // list not empty\n\tchar specialAddress[32];\n\tresponse->data.readString(specialAddress, sizeof(specialAddress));\n\t// V1 has extra info here\n\t// server name\n\tchar serverName[256];\n\tresponse->data.readString(serverName, sizeof(serverName));\n\tif (response->data.hasReadOutOfBounds())\n\t{\n\t\tauthService->hasError = true;\n\t\tcemuLog_log(LogType::Force, \"NEX: Read out of bounds\");\n\t\treturn;\n\t}\n\t// request ticket data\n\tuint8 tempNexBufferArray[1024];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tpacketBuffer.writeU32(authService->userPid);\n\tpacketBuffer.writeU32(authService->server.pid);\n\tnex->callMethod(NEX_PROTOCOL_AUTHENTICATION, 3, &packetBuffer, nexServiceAuthentication_handleResponse_requestTicket, authService);\n}\n\ntypedef struct  \n{\n\tbool isComplete;\n\tbool isSuccessful;\n}nexServiceSecureRegisterExData_t;\n\nvoid nexServiceSecure_handleResponse_RegisterEx(nexService* nex, nexServiceResponse_t* response)\n{\n\tnexServiceSecureRegisterExData_t* info = (nexServiceSecureRegisterExData_t*)response->custom;\n\tinfo->isComplete = true;\n\tuint32 returnCode = response->data.readU32();\n\tif (response->isSuccessful == false || response->data.hasReadOutOfBounds())\n\t{\n\t\tcemuLog_log(LogType::Force, \"NEX: RPC error in secure register\");\n\t\tinfo->isSuccessful = false;\n\t\tinfo->isComplete = true;\n\t\treturn;\n\t}\n\tif (returnCode & 0x80000000)\n\t{\n\t\tcemuLog_log(LogType::Force, \"NEX: Secure register failed with error code 0x{:08x}\", returnCode);\n\t\tinfo->isSuccessful = false;\n\t\tinfo->isComplete = true;\n\t\treturn;\n\t}\n\t// remaining data is skipped\n\tinfo->isSuccessful = true;\n\tinfo->isComplete = true;\n\treturn;\n}\n\nnexService* nex_secureLogin(prudpAuthServerInfo* authServerInfo, const char* accessKey, const char* nexToken)\n{\n\tprudpClient* prudpSecureSock = new prudpClient(authServerInfo->server.ip, authServerInfo->server.port, accessKey, authServerInfo);\n\t// wait until connected\n\twhile (true)\n\t{\n\t\tprudpSecureSock->Update();\n\t\tif (prudpSecureSock->IsConnected())\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tif (prudpSecureSock->GetConnectionState() == prudpClient::ConnectionState::Disconnected)\n\t\t{\n\t\t\t// timeout or disconnected\n\t\t\tcemuLog_log(LogType::Force, \"NEX: Secure login connection time-out\");\n\t\t\tdelete prudpSecureSock;\n\t\t\treturn nullptr;\n\t\t}\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t}\n\t// create nex service layer\n\tnexService* nex = new nexService(prudpSecureSock);\n\t// secureService: RegisterEx\n\tuint8 tempNexBufferArray[4096];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\t\n\tchar clientStationUrl[256];\n\tsprintf(clientStationUrl, \"prudp:/port=%u;natf=0;natm=0;pmp=0;sid=15;type=2;upnp=0\", (uint32)nex->getPRUDPConnection()->GetSourcePort());\n\t// station url list\n\tpacketBuffer.writeU32(1);\n\tpacketBuffer.writeString(clientStationUrl);\n\t// login data\n\tpacketBuffer.writeCustomType(nexNintendoLoginData(nexToken));\n\t\n\tnexServiceSecureRegisterExData_t secureRegisterExData = { 0 };\n\tnex->callMethod(NEX_PROTOCOL_SECURE, 4, &packetBuffer, nexServiceSecure_handleResponse_RegisterEx, &secureRegisterExData);\n\twhile (true)\n\t{\n\t\tnex->update();\n\t\tif (secureRegisterExData.isComplete)\n\t\t\tbreak;\n\t\tif (nex->getState() == nexService::STATE_DISCONNECTED)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"NEX: Connection error while registering\");\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (secureRegisterExData.isSuccessful == false)\n\t{\n\t\tcemuLog_log(LogType::Force, \"NEX: Failed to register to secure server\");\n\t\tnex->destroy();\n\t\treturn nullptr;\n\t}\n\treturn nex;\n}\n\nnexService* nex_establishSecureConnection(uint32 authServerIp, uint16 authServerPort, const char* accessKey, uint32 pid, const char* nexPassword, const char* nexToken)\n{\n\tnexService* authConnection = new nexService(authServerIp, authServerPort, accessKey);\n\t// wait until connected\n\twhile (authConnection->getState() == nexService::STATE_CONNECTING)\n\t{\n\t\tauthConnection->update();\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t}\n\tif (authConnection->getState() != nexService::STATE_CONNECTED)\n\t{\n\t\t// error\n\t\tauthConnection->destroy();\n\t\tcemuLog_log(LogType::Force, \"NEX: Failed to connect to the NEX server\");\n\t\treturn nullptr;\n\t}\n\t// send auth login request\n\tuint8 tempNexBufferArray[1024];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tchar pidStr[32];\n\tsprintf(pidStr, \"%u\", pid);\n\tpacketBuffer.writeString(pidStr);\n\tauthenticationService_t nexAuthService = { 0 };\n\tnexAuthService.userPid = pid;\n\tauthConnection->callMethod(NEX_PROTOCOL_AUTHENTICATION, 1, &packetBuffer, nexServiceAuthentication_handleResponse_login, &nexAuthService);\n\twhile (true)\n\t{\n\t\tif (nexAuthService.hasError || nexAuthService.done || authConnection->getState() != nexService::STATE_CONNECTED)\n\t\t\tbreak;\n\t\tauthConnection->update();\n\t}\n\tif (nexAuthService.hasError || authConnection->getState() != nexService::STATE_CONNECTED)\n\t{\n\t\t// error\n\t\tauthConnection->destroy();\n\t\tcemuLog_log(LogType::Force, \"NEX: Error during authentication\");\n\t\treturn nullptr;\n\t}\n\t// close connection to auth server\n\tauthConnection->destroy();\n\t// calculate kerberos decryption key\n\tuint32 md5LoopCount = 65000 + (pid % 1024);\n\tmd5LoopCount--;\n\tuint8 kerberosKey[16];\n\tMD5_CTX md5Ctx;\n\tMD5_Init(&md5Ctx);\n\tMD5_Update(&md5Ctx, nexPassword, (unsigned long)strlen(nexPassword));\n\tMD5_Final(kerberosKey, &md5Ctx);\n\tfor (uint32 i = 0; i < md5LoopCount; i++)\n\t{\n\t\tMD5_Init(&md5Ctx);\n\t\tMD5_Update(&md5Ctx, kerberosKey, 16);\n\t\tMD5_Final(kerberosKey, &md5Ctx);\n\t}\n\tif (nexAuthService.kerberosTicket2Size < 16)\n\t{\n\t\tnexAuthService.hasError = true;\n\t\tcemuLog_log(LogType::Force, \"NEX: Kerberos ticket too short\");\n\t\treturn nullptr;\n\t}\n\t// check hmac of ticket\n\tuint8 hmacTicket[16];\n\thmacMD5(kerberosKey, 16, nexAuthService.kerberosTicket2, nexAuthService.kerberosTicket2Size - 16, hmacTicket);\n\tif (memcmp(hmacTicket, nexAuthService.kerberosTicket2 + nexAuthService.kerberosTicket2Size - 16, 16) != 0)\n\t{\n\t\tnexAuthService.hasError = true;\n\t\tcemuLog_log(LogType::Force, \"NEX: Kerberos ticket hmac invalid\");\n\t\treturn nullptr;\n\t}\n\t// auth info\n\tauto authServerInfo = std::make_unique<prudpAuthServerInfo>();\n\t// decrypt ticket\n\tRC4Ctx rc4Ticket;\n\tRC4_initCtx(&rc4Ticket, kerberosKey, 16);\n\tRC4_transform(&rc4Ticket, nexAuthService.kerberosTicket2, nexAuthService.kerberosTicket2Size - 16, nexAuthService.kerberosTicket2);\n\tnexPacketBuffer packetKerberosTicket(nexAuthService.kerberosTicket2, nexAuthService.kerberosTicket2Size - 16, false);\n\tuint8 secureKey[16]; // for friends server it's 16 bytes, all others use 32 bytes\n\tpacketKerberosTicket.readData(secureKey, 16);\n\tuint32 ukn = packetKerberosTicket.readU32();\n\tauthServerInfo->secureTicketLength = packetKerberosTicket.readBuffer(authServerInfo->secureTicket, sizeof(authServerInfo->secureTicket));\n\n\tif (packetKerberosTicket.hasReadOutOfBounds())\n\t{\n\t\tcemuLog_log(LogType::Force, \"NEX: Parse error\");\n\t\treturn nullptr;\n\t}\n\n\tmemcpy(authServerInfo->kerberosKey, kerberosKey, 16);\n\tmemcpy(authServerInfo->secureKey, secureKey, 16);\n\tmemcpy(&authServerInfo->server, &nexAuthService.server, sizeof(prudpStationUrl));\n\tauthServerInfo->userPid = pid;\n\n\treturn nex_secureLogin(authServerInfo.get(), accessKey, nexToken);\n}\n"
  },
  {
    "path": "src/Cemu/nex/nex.h",
    "content": "#pragma once\n#include \"nexTypes.h\"\n#include<mutex>\n\nconst int NEX_PROTOCOL_AUTHENTICATION = 0xA;\nconst int NEX_PROTOCOL_SECURE = 0xB;\nconst int NEX_PROTOCOL_FRIENDS_WIIU = 0x66;\n\nclass nexService;\n\ntypedef struct\n{\n\tnexService* nex;\n\tbool isSuccessful;\n\tuint32 errorCode;\n\tuint32 callId;\n\tuint32 methodId;\n\tuint8  protocolId;\n\tnexPacketBuffer data;\n\tvoid* custom;\n}nexServiceResponse_t;\n\ntypedef struct\n{\n\tnexService* nex;\n\tuint32 callId;\n\tuint32 methodId;\n\tuint8  protocolId;\n\tnexPacketBuffer data;\n\tvoid* custom;\n}nexServiceRequest_t;\n\nclass prudpClient;\n\nclass nexService\n{\nprivate:\n\ttypedef struct\n\t{\n\t\tuint8 protocolId;\n\t\tuint32 methodId;\n\t\tuint32 callId;\n\t\tvoid(*nexServiceResponse)(nexService* nex, nexServiceResponse_t* serviceResponse);\n\t\tvoid* custom;\n\t\tbool handleError; // if set to true, call nexServiceResponse with errorCode set (else the callback is skipped when the call is not successful)\n\t\tuint32 requestTime; // timestamp of when the request was sent\n\t\t// alternative callback handler\n\t\tstd::function<void(nexServiceResponse_t*)> cb2;\n\t}nexActiveRequestInfo_t;\n\n\ttypedef struct  \n\t{\n\t\tuint8 protocolId;\n\t\tuint32 methodId;\n\t\tbool callHandlerIfError;\n\t\t//nexPacketBuffer* parameter;\n\t\tstd::vector<uint8> parameterData;\n\t\tvoid(*nexServiceResponse)(nexService* nex, nexServiceResponse_t* serviceResponse);\n\t\tvoid* custom;\n\t\t// alternative callback handler\n\t\tstd::function<void(nexServiceResponse_t*)> cb2;\n\t}queuedRequest_t;\n\n\ttypedef struct\n\t{\n\t\tuint8 protocol;\n\t\tvoid(*processRequest)(nexServiceRequest_t* request);\n\t\tvoid* custom;\n\t}protocolHandler_t;\n\npublic:\n\tstatic const int STATE_CONNECTING = 0;\n\tstatic const int STATE_CONNECTED = 1;\n\tstatic const int STATE_DISCONNECTED = 2;\n\n\tstatic const unsigned int ERR_TIMEOUT = (0xFFFFFFFF);\n\tstatic const unsigned int ERR_NO_CONNECTION = (0xFFFFFFFE);\n\n\tnexService(prudpClient* con);\n\tnexService(uint32 ip, uint16 port, const char* accessKey);\n\n\tconst uint8 PROTOCOL_BIT_REQUEST = 0x80;\n\n\tvoid callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer* parameter, void(*nexServiceResponse)(nexService* nex, nexServiceResponse_t* serviceResponse), void* custom, bool callHandlerIfError = false);\n\tvoid callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer* parameter, std::function<void(nexServiceResponse_t*)> cb, bool callHandlerIfError);\n\tvoid registerProtocolRequestHandler(uint8 protocol, void(*processRequest)(nexServiceRequest_t* request), void* custom);\n\tvoid sendRequestResponse(nexServiceRequest_t* request, uint32 errorCode, uint8* data, sint32 length);\n\tvoid update();\n\tprudpClient* getPRUDPConnection();\n\tsint32 getState();\n\tvoid registerForAsyncProcessing();\n\tvoid destroy();\n\tbool isMarkedForDestruction();\n\nprivate:\n\tnexService();\n\t~nexService();\n\tvoid updateTemporaryConnections();\n\tvoid updateNexServiceConnection();\n\tvoid processQueuedRequest(queuedRequest_t* queuedRequest);\nprivate:\n\t//bool serviceIsConnected;\n\tuint8 connectionState;\n\tprudpClient* conNexService;\n\tbool isAsync;\n\tbool isDestroyed; // if set, delete object asynchronously\n\tstd::vector<nexActiveRequestInfo_t> list_activeRequests;\n\t// protocol request handlers\n\tstd::vector<protocolHandler_t> list_requestHandlers;\n\t// packet buffer\n\tstd::vector<uint8> bufferReceive;\n\t// auth\n\tbool isSecureService;\n\t// request queue\n\tstd::mutex mtx_queuedRequests;\n\tstd::vector<queuedRequest_t> queuedRequests;\n};\n\nnexService* nex_establishSecureConnection(uint32 authServerIp, uint16 authServerPort, const char* accessKey, uint32 pid, const char* nexPassword, const char* nexToken);"
  },
  {
    "path": "src/Cemu/nex/nexFriends.cpp",
    "content": "#include \"prudp.h\"\n#include \"nex.h\"\n#include \"nexFriends.h\"\n#include \"Cafe/CafeSystem.h\"\n\nstatic const int NOTIFICATION_SRV_FRIEND_OFFLINE = 0x0A; // the opposite event (friend online) is notified via _PRESENCE_CHANGE\nstatic const int NOTIFICATION_SRV_FRIEND_PRESENCE_CHANGE = 0x18;\n\nstatic const int NOTIFICATION_SRV_FRIEND_REMOVED = 0x1A; // also used to indicate that an incoming friend request was canceled\nstatic const int NOTIFICATION_SRV_FRIEND_REQUEST_INCOMING = 0x1B; // someone sent a friend request to us\nstatic const int NOTIFICATION_SRV_FRIEND_ADDED = 0x1E; // not sent when friend request is accepted locally\n\nvoid NexFriends::processServerNotification_friendOffline(uint32 pid)\n{\n\tstd::unique_lock listLock(mtx_lists);\n\tfor (auto& it : list_friends)\n\t{\n\t\tif (it.nnaInfo.principalInfo.principalId == pid)\n\t\t{\n\t\t\tit.presence.isOnline = 0;\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_FRIEND_LOGOFF, pid);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nvoid NexFriends::processServerNotification_presenceChange(uint32 pid, nexPresenceV2& presence)\n{\n\tstd::unique_lock listLock(mtx_lists);\n\tfor (auto& it : list_friends)\n\t{\n\t\tif (it.nnaInfo.principalInfo.principalId == pid)\n\t\t{\n\t\t\tbool isOnlineChange = (presence.isOnline != it.presence.isOnline);\n\t\t\tit.presence = presence;\n\t\t\tif (isOnlineChange)\n\t\t\t\tgenerateNotification((presence.isOnline!=0)?NOTIFICATION_TYPE_FRIEND_LOGIN:NOTIFICATION_TYPE_FRIEND_LOGOFF, pid);\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_FRIEND_PRESENCE_CHANGE, pid);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nvoid NexFriends::processServerNotification_removeFriendOrFriendRequest(uint32 pid)\n{\n\tstd::unique_lock listLock(mtx_lists);\n\tfor (auto it = list_friends.begin(); it != list_friends.end();)\n\t{\n\t\tif (it->nnaInfo.principalInfo.principalId == pid)\n\t\t{\n\t\t\tlist_friends.erase(it);\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_REMOVED_FRIEND, pid);\n\t\t\treturn;\n\t\t}\n\t\tit++;\n\t}\n\tfor (auto it = list_friendReqIncoming.begin(); it != list_friendReqIncoming.end();)\n\t{\n\t\tif (it->principalInfo.principalId == pid)\n\t\t{\n\t\t\tlist_friendReqIncoming.erase(it);\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_REMOVED_INCOMING_REQUEST, pid);\n\t\t\treturn;\n\t\t}\n\t\tit++;\n\t}\n}\n\nvoid NexFriends::processServerNotification_incomingFriendRequest(uint32 pid, nexFriendRequest& friendRequest)\n{\n\tstd::unique_lock listLock(mtx_lists);\n\t// check for duplicate\n\tfor (auto& it : list_friendReqIncoming)\n\t{\n\t\tif (it.principalInfo.principalId == pid)\n\t\t\treturn;\n\t}\n\t// add friend request and send notification\n\tlist_friendReqIncoming.push_back(friendRequest);\n\tgenerateNotification(NOTIFICATION_TYPE_ADDED_INCOMING_REQUEST, pid);\n}\n\nvoid NexFriends::processServerNotification_addedFriend(uint32 pid, nexFriend& frd)\n{\n\tstd::unique_lock listLock(mtx_lists);\n\t// remove any related incoming friend request\n\tfor (auto it = list_friendReqIncoming.begin(); it != list_friendReqIncoming.end();)\n\t{\n\t\tif (it->principalInfo.principalId == pid)\n\t\t{\n\t\t\tlist_friendReqIncoming.erase(it);\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_REMOVED_INCOMING_REQUEST, pid);\n\t\t\tbreak;\n\t\t}\n\t\tit++;\n\t}\n\t// remove any related outgoing friend request\n\tfor (auto it = list_friendReqOutgoing.begin(); it != list_friendReqOutgoing.end();)\n\t{\n\t\tif (it->principalInfo.principalId == pid)\n\t\t{\n\t\t\tlist_friendReqOutgoing.erase(it);\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_REMOVED_OUTGOING_REQUEST, pid);\n\t\t\tbreak;\n\t\t}\n\t\tit++;\n\t}\n\t// check for duplicate\n\tfor (auto& it : list_friendReqIncoming)\n\t{\n\t\tif (it.principalInfo.principalId == pid)\n\t\t\treturn;\n\t}\n\t// add friend\n\tlist_friends.push_back(frd);\n\tgenerateNotification(NOTIFICATION_TYPE_ADDED_FRIEND, pid);\n}\n\nvoid NexFriends::processServerNotification(uint32 notificationType, uint32 pid, nexPacketBuffer* notificationData)\n{\n\tnexNotificationEventGeneral notificationGeneral;\n\tif (notificationType == NOTIFICATION_SRV_FRIEND_PRESENCE_CHANGE)\n\t{\n\t\tnexPresenceV2 presence;\n\t\tif (notificationData->readPlaceholderType(presence))\n\t\t{\n\t\t\tthis->processServerNotification_presenceChange(pid, presence);\n\t\t}\n\t}\n\telse if (notificationType == 0x21)\n\t{\n\t\t// change comment text\n\t\tif (notificationData->readPlaceholderType(notificationGeneral))\n\t\t{\n\t\t\t// todo\n\t\t}\n\t}\n\telse if (notificationType == NOTIFICATION_SRV_FRIEND_OFFLINE)\n\t{\n\t\t// friend now offline\n\t\tif (notificationData->readPlaceholderType(notificationGeneral))\n\t\t{\n\t\t\tthis->processServerNotification_friendOffline(pid);\n\t\t}\n\t}\n\telse if (notificationType == NOTIFICATION_SRV_FRIEND_REMOVED)\n\t{\n\t\t// friend removed or friend-request removed\n\t\tif (notificationData->readPlaceholderType(notificationGeneral))\n\t\t{\n\t\t\tthis->processServerNotification_removeFriendOrFriendRequest(pid);\n\t\t}\n\t}\n\telse if (notificationType == NOTIFICATION_SRV_FRIEND_REQUEST_INCOMING)\n\t{\n\t\tnexFriendRequest friendRequest;\n\t\tif (notificationData->readPlaceholderType(friendRequest))\n\t\t{\n\t\t\tthis->processServerNotification_incomingFriendRequest(pid, friendRequest);\n\t\t}\n\t}\n\telse if (notificationType == NOTIFICATION_SRV_FRIEND_ADDED)\n\t{\n\t\tnexFriend frd;\n\t\tif (notificationData->readPlaceholderType(frd))\n\t\t{\n\t\t\tthis->processServerNotification_addedFriend(pid, frd);\n\t\t}\n\t}\n\telse if (true)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"Unsupported friend server notification type 0x{:02x}\", notificationType);\n\t}\n}\n\nvoid nexFriends_protocolNotification_processRequest(nexServiceRequest_t* request)\n{\n\tNexFriends* nexFriends = (NexFriends*)request->custom;\n\tif (request->methodId == 0x1 || request->methodId == 0x2)\n\t{\n\t\t// notification\n\t\tuint32 notificationType = request->data.readU32();\n\t\tuint32 pid = request->data.readU32();\n\t\tif (request->data.hasReadOutOfBounds())\n\t\t{\n\t\t\trequest->nex->sendRequestResponse(request, 0, nullptr, 0);\n\t\t\treturn;\n\t\t}\n\t\tcemuLog_logDebug(LogType::Force, \"NN_NOTIFICATION methodId {} type {:02x} pid {:08x}\", request->methodId, notificationType, pid);\n\t\tnexFriends->processServerNotification(notificationType, pid, &request->data);\n\t\trequest->nex->sendRequestResponse(request, 0, nullptr, 0);\n\t\treturn;\n\t}\n\t// unknown method\n\trequest->nex->sendRequestResponse(request, 0x80000000, nullptr, 0);\n}\n\nNexFriends::NexFriends(uint32 authServerIp, uint16 authServerPort, const char* accessKey, uint32 pid, const char* nexPassword, const char* nexToken, const char* nnid, uint8* miiData, const wchar_t* miiNickname, uint8 countryCode, nexPresenceV2& myPresence)\n\t: nexCon(nullptr)\n{\n\tmemcpy(this->miiData, miiData, FFL_SIZE);\n\tstrcpy(this->nnid, nnid);\n\tthis->pid = pid;\n\tthis->countryCode = countryCode;\n\tthis->myPresence = myPresence;\n\tthis->miiNickname = boost::nowide::narrow(miiNickname);\n\tcemu_assert_debug(this->miiNickname.size() <= 96-1);\n\tauth.serverIp = authServerIp;\n\tauth.port = authServerPort;\n\tauth.accessKey = std::string(accessKey);\n\tauth.nexPassword = std::string(nexPassword);\n\tauth.nexToken = std::string(nexToken);\n\t// login related variables\n\tthis->lastLoginAttemptTime = prudpGetMSTimestamp() - 1000*60*60;\n\tthis->isCurrentlyConnected = false;\n\tthis->hasData = false;\n\tthis->loginInProcess = false;\n\tthis->numFailedLogins = 0;\n\tthis->numSuccessfulLogins = 0;\n}\n\nNexFriends::~NexFriends()\n{\n\tif(nexCon)\n\t\tnexCon->destroy();\n}\n\nvoid NexFriends::doAsyncLogin()\n{\n\tnexCon = nex_establishSecureConnection(auth.serverIp, auth.port, auth.accessKey.c_str(), pid, auth.nexPassword.c_str(), auth.nexToken.c_str());\n\tif (nexCon == nullptr)\n\t{\n\t\tthis->numFailedLogins++;\n\t\tthis->loginInProcess = false;\n\t\treturn;\n\t}\n\n\tnexCon->registerProtocolRequestHandler(0x64, nexFriends_protocolNotification_processRequest, this);\n\tnexCon->registerForAsyncProcessing();\n\tthis->isCurrentlyConnected = true;\n\tthis->firstInformationRequest = true;\n\tthis->loginInProcess = false;\n\tthis->numSuccessfulLogins++;\n\trequestGetAllInformation();\n}\n\nvoid NexFriends::initiateLogin()\n{\n\tif (this->isCurrentlyConnected)\n\t\treturn;\n\tif (this->loginInProcess)\n\t\treturn;\n\tstd::unique_lock loginLock(mtx_login);\n\tthis->loginInProcess = true;\n\t// reset all data\n\tstd::unique_lock listLock(mtx_lists);\n\tlist_friends.resize(0);\n\tlist_friendReqIncoming.resize(0);\n\tlist_friendReqOutgoing.resize(0);\n\tpreviousState.list_friends.resize(0);\n\tpreviousState.list_friendReqIncoming.resize(0);\n\tpreviousState.list_friendReqOutgoing.resize(0);\n\tthis->hasData = false;\n\t// start login attempt\n\tcemuLog_logDebug(LogType::Force, \"Attempt to log into friend server...\");\n\tstd::thread t(&NexFriends::doAsyncLogin, this);\n\tt.detach();\n}\n\nvoid NexFriends::handleResponse_getAllInformation(nexServiceResponse_t* response, NexFriends* nexFriends, std::function<void(uint32)> cb)\n{\n\tif (response->isSuccessful == false)\n\t{\n\t\tif (cb)\n\t\t\tcb(ERR_RPC_FAILED);\n\t\treturn;\n\t}\n\tNexFriends* session = (NexFriends*)nexFriends;\n\tsession->myPreference = nexPrincipalPreference(&response->data);\n\tauto comment = nexComment(&response->data);\n\tsession->myComment = comment;\n\tif (response->data.hasReadOutOfBounds())\n\t\treturn;\n\t// acquire lock on lists\n\tstd::unique_lock listLock(session->mtx_lists);\n\t// remember current state of lists for change tracking\n\tsession->previousState.list_friends = session->list_friends;\n\tsession->previousState.list_friendReqIncoming = session->list_friendReqIncoming;\n\tsession->previousState.list_friendReqOutgoing = session->list_friendReqOutgoing;\n\t// parse response and update lists\n\t// friends\n\tuint32 friendCount = response->data.readU32();\n\tsession->list_friends.resize(friendCount);\n\tfor (uint32 i = 0; i < friendCount; i++)\n\t\tsession->list_friends[i].readData(&response->data);\n\t// friend requests (outgoing)\n\tuint32 friendRequestsOutCount = response->data.readU32();\n\tif (response->data.hasReadOutOfBounds())\n\t\treturn;\n\tsession->list_friendReqOutgoing.resize(friendRequestsOutCount);\n\tfor (uint32 i = 0; i < friendRequestsOutCount; i++)\n\t\tsession->list_friendReqOutgoing[i].readData(&response->data);\n\t// friend requests (incoming)\n\tuint32 friendRequestsInCount = response->data.readU32();\n\tif (response->data.hasReadOutOfBounds())\n\t\treturn;\n\tsession->list_friendReqIncoming.resize(friendRequestsInCount);\n\tfor (uint32 i = 0; i < friendRequestsInCount; i++)\n\t\tsession->list_friendReqIncoming[i].readData(&response->data);\n\tif (response->data.hasReadOutOfBounds())\n\t\treturn;\n\t// blacklist\n\tuint32 blacklistCount = response->data.readU32();\n\tfor (uint32 i = 0; i < blacklistCount; i++)\n\t{\n\t\tnexBlacklisted blacklisted(&response->data);\n\t}\n\t// ukn\n\tuint8 uknSetting = response->data.readU8(); // ? (usually zero)\n\t// persistent notifications\n\tuint32 perstNotificationCount = response->data.readU32();\n\tfor (uint32 i = 0; i < perstNotificationCount; i++)\n\t{\n\t\tnexPersistentNotification notification(&response->data);\n\t\t//printf(\"--- Notification ---\\n\");\n\t\t//printf(\"ID %016llx pid1 %08x pid2 %08x type %08x\\n\", notification.messageId, notification.pid1, notification.pid2, notification.type);\n\t\t//printf(\"Msg %s\\n\", notification.msg.c_str());\n\t}\n\tuint8 isPreferenceInvalid = response->data.readU8(); // if not zero, preferences must be setup\n\tif (isPreferenceInvalid)\n\t{\n\t\tcemuLog_log(LogType::Force, \"NEX: First time login into friend account, setting up default preferences\");\n\t\tsession->updatePreferencesAsync(nexPrincipalPreference(1, 1, 0), [](RpcErrorCode err){});\n\t}\n\n\tif (session->firstInformationRequest == false)\n\t\tsession->trackNotifications();\n\telse\n\t{\n\t\t// first request after login -> send online notification\n\t\tsession->generateNotification(NOTIFICATION_TYPE_ONLINE, session->pid);\n\t}\n\n\tsession->firstInformationRequest = false;\n\n\tsession->hasData = true;\n\n\tif (cb)\n\t\tcb(ERR_NONE);\n}\n\nbool NexFriends::requestGetAllInformation()\n{\n\tuint8 tempNexBufferArray[1024];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tnexNNAInfo(this->countryCode, 0, nexPrincipalBasicInfo(pid, nnid, nexMiiV2(miiNickname.c_str(), miiData))).writeData(&packetBuffer);\n\tmyPresence.writeData(&packetBuffer);\n\tpacketBuffer.writeU64(0x1f18420000); // birthday (set to 1990-1-1)\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 1, &packetBuffer, std::bind(handleResponse_getAllInformation, std::placeholders::_1, this, nullptr), true);\n\treturn true;\n}\n\nbool NexFriends::requestGetAllInformation(std::function<void(uint32)> cb)\n{\n\tuint8 tempNexBufferArray[1024];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tnexNNAInfo(this->countryCode, 0, nexPrincipalBasicInfo(pid, nnid, nexMiiV2(miiNickname.c_str(), miiData))).writeData(&packetBuffer);\n\tnexPresenceV2(0).writeData(&packetBuffer);\n\tpacketBuffer.writeU64(0x1f18420000); // birthday (set to 1990-1-1)\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 1, &packetBuffer, std::bind(handleResponse_getAllInformation, std::placeholders::_1, this, cb), true);\n\treturn true;\n}\n\nbool NexFriends::updatePreferencesAsync(nexPrincipalPreference newPreferences, std::function<void(RpcErrorCode)> cb)\n{\n\tuint8 tempNexBufferArray[1024];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tnewPreferences.writeData(&packetBuffer);\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 16, &packetBuffer, [this, cb, newPreferences](nexServiceResponse_t* response) -> void\n\t\t{\n\t\t\tif (!response->isSuccessful)\n\t\t\t\treturn cb(NexFriends::ERR_RPC_FAILED);\n\t\t\tthis->myPreference = newPreferences;\n\t\t\treturn cb(NexFriends::ERR_NONE);\n\t\t}, true);\n\t// TEST\n\treturn true;\n}\n\nvoid NexFriends::getMyPreference(nexPrincipalPreference& preference)\n{\n\tpreference = myPreference;\n}\n\nbool NexFriends::updateCommentAsync(nexComment newComment, std::function<void(RpcErrorCode)> cb)\n{\n\tuint8 tempNexBufferArray[1024];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tnewComment.writeData(&packetBuffer);\n\tnexCon->callMethod(\n\t\tNEX_PROTOCOL_FRIENDS_WIIU, 15, &packetBuffer, [this, cb, newComment](nexServiceResponse_t* response) -> void {\n\t\t\tif (!response->isSuccessful)\n\t\t\t\treturn cb(NexFriends::ERR_RPC_FAILED);\n\t\t\tthis->myComment = newComment;\n\t\t\treturn cb(NexFriends::ERR_NONE);\n\t\t},\n\t\ttrue);\n\t// TEST\n\treturn true;\n}\n\nvoid NexFriends::getMyComment(nexComment& comment)\n{\n\tcomment = myComment;\n}\n\nbool NexFriends::addProvisionalFriendByPidGuessed(uint32 principalId)\n{\n\tuint8 tempNexBufferArray[512];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tpacketBuffer.writeU32(principalId);\n\tcemu_assert_unimplemented();\n\t//nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 2, &packetBuffer, handleResponse_test, this);\n\treturn true;\n}\n\n// returns true once connection is established and friend list data is available\nbool NexFriends::isOnline()\n{\n\treturn isCurrentlyConnected && hasData;\n}\n\nvoid NexFriends::handleResponse_acceptFriendRequest(nexService* nex, nexServiceResponse_t* response)\n{\n\tNexFriends* session = (NexFriends*)response->custom;\n\t// returns new state of FriendRequest + FriendInfo (if friend request holds no valid data, it means the friend request was successfully accepted?)\n}\n\nvoid NexFriends::setNotificationHandler(void(*notificationHandler)(NOTIFICATION_TYPE notificationType, uint32 pid))\n{\n\tthis->notificationHandler = notificationHandler;\n}\n\nvoid NexFriends::generateNotification(NOTIFICATION_TYPE notificationType, uint32 pid)\n{\n\tif (this->notificationHandler == nullptr)\n\t\treturn;\n\tthis->notificationHandler(notificationType, pid);\n}\n\n// compare previous and current state of friend(-request) lists and generate change-notifications\nvoid NexFriends::trackNotifications()\n{\n\t// search for changed and added friend entries\n\tfor (auto& frNew : list_friends)\n\t{\n\t\tbool entryFound = false;\n\t\tfor (auto& frPrevious : previousState.list_friends)\n\t\t{\n\t\t\tif (frNew.nnaInfo.principalInfo.principalId == frPrevious.nnaInfo.principalInfo.principalId)\n\t\t\t{\n\t\t\t\t// todo - scan for changes\n\t\t\t\tentryFound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (entryFound == false)\n\t\t{\n\t\t\t// friend added\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_ADDED_FRIEND, frNew.nnaInfo.principalInfo.principalId);\n\t\t}\n\t}\n\t// search for removed friends\n\tfor (auto& frPrevious : previousState.list_friends)\n\t{\n\t\tbool entryFound = false;\n\t\tfor (auto& frNew : list_friends)\n\t\t{\n\t\t\tif (frNew.nnaInfo.principalInfo.principalId == frPrevious.nnaInfo.principalInfo.principalId)\n\t\t\t{\n\t\t\t\tentryFound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (entryFound == false)\n\t\t{\n\t\t\t// friend removed\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_REMOVED_FRIEND, frPrevious.nnaInfo.principalInfo.principalId);\n\t\t}\n\t}\n\t// search for added friend requests (incoming)\n\tfor (auto& frqNew : list_friendReqIncoming)\n\t{\n\t\tbool entryFound = false;\n\t\tfor (auto& frqPrevious : previousState.list_friendReqIncoming)\n\t\t{\n\t\t\tif (frqNew.principalInfo.principalId == frqPrevious.principalInfo.principalId)\n\t\t\t{\n\t\t\t\tentryFound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (entryFound == false)\n\t\t{\n\t\t\t// incoming friend request added\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_ADDED_INCOMING_REQUEST, frqNew.principalInfo.principalId);\n\t\t}\n\t}\n\t// search for removed friend requests (incoming)\n\tfor (auto& frqPrevious : previousState.list_friendReqIncoming)\n\t{\n\t\tbool entryFound = false;\n\t\tfor (auto& frqNew : list_friendReqIncoming)\n\t\t{\t\n\t\t\tif (frqNew.principalInfo.principalId == frqPrevious.principalInfo.principalId)\n\t\t\t{\n\t\t\t\tentryFound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (entryFound == false)\n\t\t{\n\t\t\t// incoming friend request removed\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_REMOVED_INCOMING_REQUEST, frqPrevious.principalInfo.principalId);\n\t\t}\n\t}\n\t// search for added friend requests (outgoing)\n\tfor (auto& frqNew : list_friendReqOutgoing)\n\t{\n\t\tbool entryFound = false;\n\t\tfor (auto& frqPrevious : previousState.list_friendReqOutgoing)\n\t\t{\n\t\t\tif (frqNew.principalInfo.principalId == frqPrevious.principalInfo.principalId)\n\t\t\t{\n\t\t\t\tentryFound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (entryFound == false)\n\t\t{\n\t\t\t// outgoing friend request added\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_ADDED_OUTGOING_REQUEST, frqNew.principalInfo.principalId);\n\t\t}\n\t}\n\t// search for removed friend requests (outgoing)\n\tfor (auto& frqPrevious : previousState.list_friendReqOutgoing)\n\t{\n\t\tbool entryFound = false;\n\t\tfor (auto& frqNew : list_friendReqOutgoing)\n\t\t{\n\t\t\tif (frqNew.principalInfo.principalId == frqPrevious.principalInfo.principalId)\n\t\t\t{\n\t\t\t\tentryFound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (entryFound == false)\n\t\t{\n\t\t\t// outgoing friend request removed\n\t\t\tgenerateNotification(NOTIFICATION_TYPE_REMOVED_OUTGOING_REQUEST, frqPrevious.principalInfo.principalId);\n\t\t}\n\t}\n}\n\nvoid addUniquePidToList(std::vector<uint32>& pidList, uint32 pid)\n{\n\tbool alreadyAdded = false;\n\tfor (auto& it2 : pidList)\n\t{\n\t\tif (it2 == pid)\n\t\t{\n\t\t\talreadyAdded = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (alreadyAdded)\n\t\treturn;\n\tpidList.push_back(pid);\n}\n\nvoid NexFriends::getFriendPIDs(uint32* pidList, uint32* pidCount, sint32 offset, sint32 count, bool includeFriendRequests)\n{\n\tif (count < 0)\n\t{\n\t\t*pidCount = 0;\n\t\treturn;\n\t}\n\t// parse response and update lists\n\tstd::vector<uint32> allPids;\n\tstd::unique_lock listLock(this->mtx_lists);\n\tfor (auto& it : this->list_friends)\n\t{\n\t\tuint32 pid = it.nnaInfo.principalInfo.principalId;\n\t\taddUniquePidToList(allPids, pid);\n\t}\n\tif (includeFriendRequests)\n\t{\n\t\t// incoming friend requests are not included\n\t\tfor (auto& it : this->list_friendReqOutgoing)\n\t\t{\n\t\t\tuint32 pid = it.principalInfo.principalId;\n\t\t\taddUniquePidToList(allPids, pid);\n\t\t}\n\t}\n\tsint32 copyCount = std::max((sint32)allPids.size() - offset, 0);\n\tcopyCount = std::min(copyCount, count);\n\tif (pidList)\n\t{\n\t\tfor (sint32 i = 0; i < copyCount; i++)\n\t\t\tpidList[i] = allPids[offset + i];\n\t}\n\t*pidCount = copyCount;\n}\n\nvoid NexFriends::getFriendRequestPIDs(uint32* pidList, uint32* pidCount, sint32 offset, sint32 count, bool includeIncoming, bool includeOutgoing)\n{\n\tif (count < 0)\n\t{\n\t\t*pidCount = 0;\n\t\treturn;\n\t}\n\t// parse response and update lists\n\tstd::vector<uint32> allPids;\n\tstd::unique_lock listLock(this->mtx_lists);\n\tif (includeIncoming)\n\t{\n\t\tfor (auto& it : this->list_friendReqIncoming)\n\t\t{\n\t\t\tuint32 pid = it.principalInfo.principalId;\n\t\t\taddUniquePidToList(allPids, pid);\n\t\t}\n\t}\n\tif (includeOutgoing)\n\t{\n\t\tfor (auto& it : this->list_friendReqOutgoing)\n\t\t{\n\t\t\tuint32 pid = it.principalInfo.principalId;\n\t\t\taddUniquePidToList(allPids, pid);\n\t\t}\n\t}\n\tsint32 copyCount = std::max((sint32)allPids.size() - offset, 0);\n\tcopyCount = std::min(copyCount, count);\n\tif (pidList)\n\t{\n\t\tfor (sint32 i = 0; i < copyCount; i++)\n\t\t\tpidList[i] = allPids[offset + i];\n\t}\n\t*pidCount = copyCount;\n}\n\nstd::string NexFriends::getAccountNameByPid(uint32 principalId)\n{\n\tif (this->pid == principalId)\n\t\treturn this->nnid;\n\n\tnexFriend friendData{};\n\tif(getFriendByPID(friendData, principalId))\n\t\treturn friendData.nnaInfo.principalInfo.nnid;\n\n\tnexFriendRequest requestData{};\n\tif (getFriendRequestByPID(requestData, nullptr, principalId))\n\t\treturn requestData.principalInfo.nnid;\n\n\treturn {};\n}\n\nint NexFriends::getPendingFriendRequestCount()\n{\n\tstd::unique_lock listLock(this->mtx_lists);\n\treturn (int)this->list_friendReqIncoming.size();\n}\n\n\nbool NexFriends::getFriendByPID(nexFriend& friendData, uint32 searchedPid)\n{\n\tstd::unique_lock listLock(this->mtx_lists);\n\tfor (auto& it : this->list_friends)\n\t{\n\t\tuint32 pid = it.nnaInfo.principalInfo.principalId;\n\t\tif (pid == searchedPid)\n\t\t{\n\t\t\tfriendData = it;\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nbool NexFriends::getFriendRequestByPID(nexFriendRequest& friendRequestData, bool* isIncoming, uint32 searchedPid)\n{\n\tstd::unique_lock listLock(this->mtx_lists);\n\tfor (auto& it : this->list_friendReqIncoming)\n\t{\n\t\tuint32 pid = it.principalInfo.principalId;\n\t\tif (pid == searchedPid)\n\t\t{\n\t\t\tfriendRequestData = it;\n\t\t\tif(isIncoming)\n\t\t\t\t*isIncoming = true;\n\t\t\treturn true;\n\t\t}\n\t}\n\tfor (auto& it : this->list_friendReqOutgoing)\n\t{\n\t\tuint32 pid = it.principalInfo.principalId;\n\t\tif (pid == searchedPid)\n\t\t{\n\t\t\tfriendRequestData = it;\n\t\t\tif (isIncoming)\n\t\t\t\t*isIncoming = false;\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nbool NexFriends::getFriendRequestByMessageId(nexFriendRequest& friendRequestData, bool* isIncoming, uint64 messageId)\n{\n\tstd::unique_lock listLock(this->mtx_lists);\n\tfor (auto& it : this->list_friendReqIncoming)\n\t{\n\t\tuint64 mid = it.message.messageId;\n\t\tif(mid == 0)\n\t\t\tcontinue;\n\t\tif (mid == messageId)\n\t\t{\n\t\t\tfriendRequestData = it;\n\t\t\t*isIncoming = true;\n\t\t\treturn true;\n\t\t}\n\t}\n\tfor (auto& it : this->list_friendReqOutgoing)\n\t{\n\t\tuint64 mid = it.message.messageId;\n\t\tif (mid == 0)\n\t\t\tcontinue;\n\t\tif (mid == messageId)\n\t\t{\n\t\t\tfriendRequestData = it;\n\t\t\t*isIncoming = false;\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nvoid addProvisionalFriendHandler(nexServiceResponse_t* nexResponse, std::function<void(uint32)> cb)\n{\n\tif (nexResponse->isSuccessful)\n\t\tcb(0);\n\telse\n\t{\n\t\t// todo: Properly handle returned error code and data\n\t\tcb(NexFriends::ERR_RPC_FAILED);\n\t}\n}\n\nbool NexFriends::addProvisionalFriend(char* name, std::function<void(RpcErrorCode)> cb)\n{\n\tif (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)\n\t{\n\t\t// not connected\n\t\tcb(ERR_NOT_CONNECTED);\n\t\treturn false;\n\t}\n\tuint8 tempNexBufferArray[128];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tpacketBuffer.writeString(name);\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 3, &packetBuffer, std::bind(addProvisionalFriendHandler, std::placeholders::_1, cb), true);\n\treturn true;\n}\n\nvoid addFriendRequestHandler(nexServiceResponse_t* nexResponse, NexFriends* nexFriends, std::function<void(uint32)> cb)\n{\n\tif (nexResponse->isSuccessful)\n\t\tcb(0);\n\telse\n\t{\n\t\t// todo: Properly handle returned error code\n\t\tcb(NexFriends::ERR_RPC_FAILED);\n\t\tnexFriends->requestGetAllInformation(); // refresh friend list and send add/remove notifications\n\t}\n}\n\nvoid NexFriends::addFriendRequest(uint32 pid, const char* comment, std::function<void(RpcErrorCode)> cb)\n{\n\tif (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)\n\t{\n\t\t// not connected\n\t\tcb(ERR_NOT_CONNECTED);\n\t\treturn;\n\t}\n\tuint8 tempNexBufferArray[2048];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tpacketBuffer.writeU32(pid);\n\tpacketBuffer.writeU8(0); // ukn (language of comment?)\n\tpacketBuffer.writeString(comment);\n\tpacketBuffer.writeU8(0); // ukn (language of next string?)\n\tpacketBuffer.writeString(\"\"); // ukn\n\tnexGameKey(0, 0).writeData(&packetBuffer);\n\tpacketBuffer.writeU64(0); // ukn\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 5, &packetBuffer, std::bind(addFriendRequestHandler, std::placeholders::_1, this, cb), true);\n}\n\nvoid NexFriends::requestPrincipleBaseInfoByPID(uint32* pidList, sint32 count, const std::function<void(RpcErrorCode result, std::span<nexPrincipalBasicInfo> basicInfo)>& cb)\n{\n\tif (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)\n\t\treturn cb(ERR_NOT_CONNECTED, {});\n\tuint8 tempNexBufferArray[512];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tpacketBuffer.writeU32(count);\n\tfor(sint32 i=0; i<count; i++)\n\t\tpacketBuffer.writeU32(pidList[i]);\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 17, &packetBuffer, [cb, count](nexServiceResponse_t* response)\n\t\t{\n\t\t\tif (!response->isSuccessful)\n\t\t\t\treturn cb(NexFriends::ERR_RPC_FAILED, {});\n\t\t\t// process result\n\t\t\tuint32 resultCount = response->data.readU32();\n\t\t\tif (resultCount != count)\n\t\t\t\treturn cb(NexFriends::ERR_UNEXPECTED_RESULT, {});\n\t\t\tstd::vector<nexPrincipalBasicInfo> nexBasicInfo;\n\t\t\tnexBasicInfo.resize(count);\n\t\t\tfor (uint32 i = 0; i < resultCount; i++)\n\t\t\t\tnexBasicInfo[i].readData(&response->data);\n\t\t\tif (response->data.hasReadOutOfBounds())\n\t\t\t\treturn cb(NexFriends::ERR_UNEXPECTED_RESULT, {});\n\t\t\treturn cb(NexFriends::ERR_NONE, nexBasicInfo);\n\t\t}, true);\n}\n\nvoid genericFriendServiceNoResponseHandler(nexServiceResponse_t* nexResponse, std::function<void(uint32)> cb)\n{\n\tif (nexResponse->isSuccessful)\n\t\tcb(0);\n\telse\n\t{\n\t\t// todo: Properly handle returned error code\n\t\tcb(NexFriends::ERR_RPC_FAILED);\n\t}\n}\n\nvoid NexFriends::removeFriend(uint32 pid, std::function<void(RpcErrorCode)> cb)\n{\n\tif (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)\n\t{\n\t\t// not connected\n\t\tcb(ERR_NOT_CONNECTED);\n\t\treturn;\n\t}\n\tuint8 tempNexBufferArray[512];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tpacketBuffer.writeU32(pid);\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 4, &packetBuffer, [this, cb](nexServiceResponse_t* response) -> void\n\t\t{\n\t\t\tif (!response->isSuccessful)\n\t\t\t\treturn cb(NexFriends::ERR_RPC_FAILED);\n\t\t\telse\n\t\t\t{\n\t\t\t\tcb(NexFriends::ERR_NONE);\n\t\t\t\tthis->requestGetAllInformation(); // refresh friend list and send add/remove notifications\n\t\t\t\treturn;\n\t\t\t}\n\t\t}, true);\n}\n\nvoid NexFriends::cancelOutgoingProvisionalFriendRequest(uint32 pid, std::function<void(RpcErrorCode)> cb)\n{\n\tif (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)\n\t{\n\t\t// not connected\n\t\tcb(ERR_NOT_CONNECTED);\n\t\treturn;\n\t}\n\tuint8 tempNexBufferArray[512];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tpacketBuffer.writeU32(pid);\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 4, &packetBuffer, [cb](nexServiceResponse_t* response) -> void\n\t{\n\t\tif (!response->isSuccessful)\n\t\t\treturn cb(NexFriends::ERR_RPC_FAILED);\n\t\telse\n\t\t\treturn cb(NexFriends::ERR_NONE);\n\t\t}, true);\n}\n\nvoid NexFriends::acceptFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb)\n{\n\tif (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)\n\t\treturn cb(ERR_NOT_CONNECTED);\n\tuint8 tempNexBufferArray[128];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tpacketBuffer.writeU64(messageId);\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 7, &packetBuffer, [cb](nexServiceResponse_t* response) -> void\n\t\t{\n\t\t\tif (!response->isSuccessful)\n\t\t\t\treturn cb(NexFriends::ERR_RPC_FAILED);\n\t\t\telse\n\t\t\t\treturn cb(NexFriends::ERR_NONE);\n\t\t}, true);\n}\n\nvoid NexFriends::deleteFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb)\n{\n\tif (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)\n\t\treturn cb(ERR_NOT_CONNECTED);\n\tuint8 tempNexBufferArray[128];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tpacketBuffer.writeU64(messageId);\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 8, &packetBuffer, [this, cb](nexServiceResponse_t* response) -> void\n\t\t{\n\t\t\tif (!response->isSuccessful)\n\t\t\t\treturn cb(NexFriends::ERR_RPC_FAILED);\n\t\t\tcb(NexFriends::ERR_NONE);\n\t\t\tthis->requestGetAllInformation(); // refresh friend list and send add/remove notifications\n\t\t}, true);\n}\n\nvoid NexFriends::markFriendRequestsAsReceived(uint64* messageIdList, sint32 count, std::function<void(RpcErrorCode)> cb)\n{\n\tif (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)\n\t\treturn cb(ERR_NOT_CONNECTED);\n\tuint8 tempNexBufferArray[1024];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tpacketBuffer.writeU32(count);\n\tfor(sint32 i=0; i<count; i++)\n\t\tpacketBuffer.writeU64(messageIdList[i]);\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 10, &packetBuffer, [cb](nexServiceResponse_t* response) -> void\n\t\t{\n\t\t\tif (!response->isSuccessful)\n\t\t\t\treturn cb(NexFriends::ERR_RPC_FAILED);\n\t\t\telse\n\t\t\t\treturn cb(NexFriends::ERR_NONE);\n\t\t}, true);\n}\n\nvoid NexFriends::updateMyPresence(nexPresenceV2& myPresence)\n{\n\tthis->myPresence = myPresence;\n\n\tif (GetTitleIdHigh(CafeSystem::GetForegroundTitleId()) == 0x00050000)\n\t{\n\t\tmyPresence.gameKey.titleId = CafeSystem::GetForegroundTitleId();\n\t\tmyPresence.gameKey.ukn = CafeSystem::GetForegroundTitleVersion();\n\t}\n\telse\n\t{\n\t\tmyPresence.gameKey.titleId = 0; // icon will not be ??? or invalid to others\n\t\tmyPresence.gameKey.ukn = 0;\n\t}\n\n\tif (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)\n\t{\n\t\t// not connected\n\t\treturn;\n\t}\n\tuint8 tempNexBufferArray[1024];\n\tnexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);\n\tmyPresence.writeData(&packetBuffer);\n\tnexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 13, &packetBuffer, +[](nexServiceResponse_t* nexResponse){}, false);\n}\n\nvoid NexFriends::update()\n{\n\tstd::unique_lock loginLock(mtx_login);\n\tif (!isCurrentlyConnected)\n\t{\n\t\tif (loginInProcess)\n\t\t{\n\t\t\t// wait for login attempt to finish\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// should we try to reconnect?\n\t\t\tuint32 timeSinceLastLoginAttempt = prudpGetMSTimestamp() - this->lastLoginAttemptTime;\n\t\t\tuint32 delayTime = 30; // 30 seconds by default\n\t\t\tif (this->numFailedLogins < 3)\n\t\t\t\tdelayTime = 30;\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (this->numSuccessfulLogins == 0)\n\t\t\t\t\treturn; // never try again\n\t\t\t\tif (this->numFailedLogins >= 10)\n\t\t\t\t\treturn; // stop after 10 failed attempts\n\t\t\t\tdelayTime = 60 + (this->numFailedLogins - 3) * 60; // add one minute each time it fails\n\t\t\t}\n\t\t\tif (timeSinceLastLoginAttempt < delayTime)\n\t\t\t\treturn;\n\t\t\tcemuLog_log(LogType::Force, \"NEX: Attempt async friend service login\");\n\t\t\tinitiateLogin();\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (this->nexCon == nullptr || this->nexCon->getState() != nexService::STATE_CONNECTED)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"NEX: Lost friend server session\");\n\t\t\tif (this->nexCon)\n\t\t\t{\n\t\t\t\tthis->nexCon->destroy();\n\t\t\t\tthis->nexCon = nullptr;\n\t\t\t}\n\n\t\t\tisCurrentlyConnected = false;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/Cemu/nex/nexFriends.h",
    "content": "#pragma once\n\n#ifndef FFL_SIZE\n#define FFL_SIZE\t0x60\n#endif\n\nclass nexGameKey : public nexType\n{\npublic:\n\tnexGameKey() = default;\n\n\tnexGameKey(uint64 titleId, uint16 ukn)\n\t{\n\t\tthis->titleId = titleId;\n\t\tthis->ukn = ukn;\n\t}\n\n\tnexGameKey(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tpb->writeU64(titleId);\n\t\tpb->writeU16(ukn);\n\t}\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\ttitleId = pb->readU64();\n\t\tukn = pb->readU16();\n\t}\npublic:\n\tuint64 titleId;\n\tuint16 ukn;\n};\n\nclass nexMiiV2 : public nexType\n{\npublic:\n\tnexMiiV2()\n\t{\n\t\tmiiNickname[0] = '\\0';\n\t}\n\n\tnexMiiV2(const char* miiNickname, uint8* miiData)\n\t{\n\t\tstrncpy(this->miiNickname, miiNickname, 127);\n\t\tthis->miiNickname[127] = '\\0';\n\t\tmemcpy(this->miiData, miiData, FFL_SIZE);\n\t}\n\n\tnexMiiV2(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tpb->writeString(this->miiNickname);\n\t\tpb->writeU8(0); // ukn\n\t\tpb->writeU8(0); // ukn\n\t\tpb->writeBuffer(this->miiData, FFL_SIZE);\n\t\tpb->writeU64(0); // ukn\n\t}\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tpb->readString(this->miiNickname, sizeof(this->miiNickname));\n\t\tthis->miiNickname[127] = '\\0';\n\t\tpb->readU8(); // ukn\n\t\tpb->readU8(); // ukn\n\t\tmemset(miiData, 0, sizeof(miiData));\n\t\tpb->readBuffer(this->miiData, FFL_SIZE);\n\t\tpb->readU64(); // ukn\n\t}\npublic:\n\tuint8 miiData[FFL_SIZE];\n\tchar miiNickname[128];\n};\n\nclass nexPresenceV2 : public nexType\n{\npublic:\n\tnexPresenceV2()\n\t{\n\n\t}\n\n\tnexPresenceV2(int ukn)\n\t{\n\t\t// todo\n\t}\n\n\tnexPresenceV2(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tconst char* getMetaName() override\n\t{\n\t\treturn \"NintendoPresenceV2\";\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tpb->writeU32(1); // isValid?\n\t\tpb->writeU8(isOnline ? 1 : 0);\n\t\t// gameKey:\n\t\tpb->writeU64(gameKey.titleId);\n\t\tpb->writeU16(gameKey.ukn);\n\n\t\tpb->writeU8(1); //\tuint8\t\t\tukn3(example value : 1)\n\t\tpb->writeString(\"\");//\tString\t\t\tmsg(current game ? )\n\n\t\tpb->writeU32(joinFlagMask);\n\t\tpb->writeU8(joinAvailability);\n\t\tpb->writeU32(gameId);\n\t\tpb->writeU32(gameMode);\n\t\tpb->writeU32(hostPid);\n\t\tpb->writeU32(groupId);\n\n\t\tpb->writeBuffer(appSpecificData, sizeof(appSpecificData));\n\t\tpb->writeU8(3); // ukn\n\t\tpb->writeU8(1); // ukn\n\t\tpb->writeU8(3); // ukn\n\t}\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tukn0 = pb->readU32();\n\t\tisOnline = pb->readU8();\n\t\tgameKey.readData(pb);\n\t\tukn3 = pb->readU8();\n\t\tchar msgBuffer[1024];\n\t\tpb->readString(msgBuffer, sizeof(msgBuffer));\n\t\tmsgBuffer[1023] = '\\0';\n\t\tthis->msg = std::string(msgBuffer);\n\t\tjoinFlagMask = pb->readU32();\n\t\tjoinAvailability = pb->readU8();\n\t\tgameId = pb->readU32();\n\t\tgameMode = pb->readU32();\n\t\thostPid = pb->readU32();\n\t\tgroupId = pb->readU32();\n\t\tpb->readBuffer(appSpecificData, sizeof(appSpecificData));\n\t\tukn11 = pb->readU8();\n\t\tukn12 = pb->readU8();\n\t\tukn13 = pb->readU8();\n\t}\npublic:\n\tuint32 ukn0; // seen values: 0 -> offline, 1 -> online (menu, but not always), 8 and 0x1E6 -> in Splatoon\n\tuint8 isOnline;\n\tnexGameKey gameKey;\n\tuint8 ukn3; // message language?\n\tstd::string msg;\n\tuint32 joinFlagMask;\n\tuint8 joinAvailability;\n\tuint32 gameId;\n\tuint32 gameMode;\n\tuint32 hostPid;\n\tuint32 groupId;\n\tuint8 appSpecificData[0x14];\n\tuint8 ukn11;\n\tuint8 ukn12;\n\tuint8 ukn13;\n};\n\nclass nexPrincipalBasicInfo : public nexType\n{\npublic:\n\tnexPrincipalBasicInfo()\n\t{\n\t\tthis->nnid[0] = '\\0';\n\t}\n\n\tnexPrincipalBasicInfo(uint32 principalId, char* nnid, const nexMiiV2& mii)\n\t\t: principalId(principalId), mii(mii)\n\t{\n\t\tstrcpy(this->nnid, nnid);\n\t}\n\n\tnexPrincipalBasicInfo(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tpb->writeU32(principalId);\n\t\tpb->writeString(this->nnid);\n\t\tmii.writeData(pb);\n\t\tpb->writeU8(2); // todo\n\t}\n\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tprincipalId = pb->readU32();\n\t\tpb->readString(nnid, sizeof(nnid));\n\t\tmii.readData(pb);\n\t\tregionGuessed = pb->readU8();\n\t}\n\npublic:\n\tuint32 principalId;\n\tchar nnid[32];\n\tnexMiiV2 mii;\n\tuint8 regionGuessed;\n};\n\nclass nexNNAInfo : public nexType\n{\npublic:\n\tnexNNAInfo()\n\t{\n\n\t}\n\n\tnexNNAInfo(uint8 countryCode, uint8 countrySubCode, const nexPrincipalBasicInfo& principalBasicInfo)\n\t\t: countryCode(countryCode), countrySubCode(countrySubCode), principalInfo(principalBasicInfo)\n\t{\n\t}\n\n\tnexNNAInfo(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tprincipalInfo.writeData(pb);\n\t\tpb->writeU8(countryCode);\n\t\tpb->writeU8(countrySubCode);\n\t}\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tprincipalInfo.readData(pb);\n\t\tcountryCode = pb->readU8();\n\t\tcountrySubCode = pb->readU8();\n\t}\npublic:\n\tuint8 countryCode;\n\tuint8 countrySubCode;\n\tnexPrincipalBasicInfo principalInfo;\n};\n\nclass nexPrincipalPreference : public nexType\n{\npublic:\n\tnexPrincipalPreference() = default;\n\n\tnexPrincipalPreference(uint8 ukn0, uint8 ukn1, uint8 ukn2)\n\t{\n\t\tthis->showOnline = ukn0;\n\t\tthis->showGame = ukn1;\n\t\tthis->blockFriendRequests = ukn2;\n\t}\n\n\tnexPrincipalPreference(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tpb->writeU8(showOnline);\n\t\tpb->writeU8(showGame);\n\t\tpb->writeU8(blockFriendRequests);\n\t}\n\t\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tshowOnline = pb->readU8();\n\t\tshowGame = pb->readU8();\n\t\tblockFriendRequests = pb->readU8();\n\t}\npublic:\n\tuint8 showOnline;\n\tuint8 showGame;\n\tuint8 blockFriendRequests;\n};\n\nclass nexComment : public nexType\n{\npublic:\n\tnexComment()\n\t{\n\n\t}\n\n\tnexComment(uint8 todo)\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tnexComment(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tpb->writeU8(ukn0);\n\t\tpb->writeString(commentString.c_str());\n\t\tpb->writeU64(ukn1);\n\t}\n\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tukn0 = pb->readU8();\n\t\tchar stringBuffer[1024];\n\t\tpb->readString(stringBuffer, 1024);\n\t\tstringBuffer[1023] = '\\0';\n\t\tcommentString = std::string(stringBuffer);\n\t\tukn1 = pb->readU64();\n\t}\npublic:\n\tuint8 ukn0;\n\tstd::string commentString;\n\tuint64 ukn1;\n};\n\nclass nexFriendRequestMessage : public nexType\n{\npublic:\n\tnexFriendRequestMessage()\n\t{\n\n\t}\n\n\tnexFriendRequestMessage(uint8 todo)\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tnexFriendRequestMessage(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tmessageId = pb->readU64();\n\t\tisMarkedAsReceived = pb->readU8();\n\t\tukn2 = pb->readU8();\n\t\tchar stringBuffer[1024];\n\t\tpb->readString(stringBuffer, sizeof(stringBuffer));\n\t\tstringBuffer[1023] = '\\0';\n\t\tcommentStr = std::string(stringBuffer);\n\t\tukn4 = pb->readU8();\n\t\tpb->readString(stringBuffer, sizeof(stringBuffer));\n\t\tstringBuffer[1023] = '\\0';\n\t\tukn5Str = std::string(stringBuffer);\n\t\tgameKey.readData(pb);\n\t\tukn7 = pb->readU64();\n\t\texpireTimestamp = pb->readU64();\n\t}\npublic:\n\tuint64 messageId;\n\tuint8 isMarkedAsReceived;\n\tuint8 ukn2;\n\tstd::string commentStr;\n\tuint8 ukn4;\n\tstd::string ukn5Str;\n\tnexGameKey gameKey;\n\tuint64 ukn7;\n\tuint64 expireTimestamp;\n};\n\nclass nexFriendRequest : public nexType\n{\npublic:\n\tnexFriendRequest()\n\t{\n\t}\n\n\tnexFriendRequest(uint64 titleId, uint16 ukn)\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tnexFriendRequest(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tconst char* getMetaName() override\n\t{\n\t\treturn \"FriendRequest\";\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tprincipalInfo.readData(pb);\n\t\tmessage.readData(pb);\n\t\tukn = pb->readU64();\n\t}\npublic:\n\tnexPrincipalBasicInfo\tprincipalInfo;\n\tnexFriendRequestMessage\tmessage;\n\tuint64\t\t\t\t\tukn;\n};\n\nclass nexFriend : public nexType\n{\npublic:\n\tnexFriend()\n\t{\n\t}\n\n\tnexFriend(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tconst char* getMetaName() override\n\t{\n\t\treturn \"FriendInfo\";\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tnnaInfo.readData(pb);\n\t\tpresence.readData(pb);\n\t\tcomment.readData(pb);\n\t\tfriendsSinceTimestamp = pb->readU64();\n\t\tlastOnlineTimestamp = pb->readU64();\n\t\tukn6 = pb->readU64();\n\t}\npublic:\n\tnexNNAInfo\t\tnnaInfo;\n\tnexPresenceV2\tpresence;\n\tnexComment\t\tcomment;\n\tuint64\t\t\tfriendsSinceTimestamp;\n\tuint64\t\t\tlastOnlineTimestamp;\n\tuint64\t\t\tukn6;\n};\n\nclass nexBlacklisted : public nexType\n{\npublic:\n\tnexBlacklisted()\n\t{\n\t}\n\n\tnexBlacklisted(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tbasicInfo.readData(pb);\n\t\tgameKey.readData(pb);\n\t\tukn = pb->readU64();\n\t}\npublic:\n\tnexPrincipalBasicInfo basicInfo;\n\tnexGameKey gameKey;\n\tuint64 ukn;\n};\n\n\nclass nexPersistentNotification : public nexType\n{\npublic:\n\tnexPersistentNotification()\n\t{\n\t}\n\n\tnexPersistentNotification(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tmessageId = pb->readU64();\n\t\tpid1 = pb->readU32();\n\t\tpid2 = pb->readU32();\n\t\ttype = pb->readU32();\n\t\tpb->readStdString(msg);\n\t}\npublic:\n\tuint64\t\tmessageId;\n\tuint32\t\tpid1; // principal id 1 (might differ depending on type)\n\tuint32\t\tpid2; // principal id 2 (might differ depending on type)\n\tuint32\t\ttype;\n\tstd::string\tmsg;\n};\n\nclass NexFriends\n{\npublic:\n  \tusing RpcErrorCode = int; // replace with enum class later\n\n\tstatic const int ERR_NONE = 0;\n\tstatic const int ERR_RPC_FAILED = 1;\n\tstatic const int ERR_UNEXPECTED_RESULT = 2;\n\tstatic const int ERR_NOT_CONNECTED = 3;\n\n\tenum NOTIFICATION_TYPE\n\t{\n\t\tNOTIFICATION_TYPE_ONLINE = 0,\n\n\t\tNOTIFICATION_TYPE_FRIEND_LOGIN = 4,\n\t\tNOTIFICATION_TYPE_FRIEND_LOGOFF = 5,\n\t\tNOTIFICATION_TYPE_FRIEND_PRESENCE_CHANGE = 6,\n\n\t\tNOTIFICATION_TYPE_ADDED_FRIEND = 9,\n\t\tNOTIFICATION_TYPE_REMOVED_FRIEND = 10,\n\t\tNOTIFICATION_TYPE_ADDED_OUTGOING_REQUEST = 11,\n\t\tNOTIFICATION_TYPE_REMOVED_OUTGOING_REQUEST = 12,\n\t\tNOTIFICATION_TYPE_ADDED_INCOMING_REQUEST = 17,\n\t\tNOTIFICATION_TYPE_REMOVED_INCOMING_REQUEST = 18\n\n\n\t};\n\npublic:\n\tNexFriends(uint32 authServerIp, uint16 authServerPort, const char* accessKey, uint32 pid, const char* nexPassword, const char* nexToken, const char* nnid, uint8* miiData, const wchar_t* miiNickname, uint8 countryCode, nexPresenceV2& myPresence);\n\n\t~NexFriends();\n\n\tstd::string getAccountNameByPid(uint32 principalId);\n\tint getPendingFriendRequestCount();\n\n\tbool requestGetAllInformation();\n\tbool addProvisionalFriendByPidGuessed(uint32 principalId);\n\n\t// synchronous API (returns immediately)\n\tbool requestGetAllInformation(std::function<void(uint32)> cb);\n\tvoid getFriendPIDs(uint32* pidList, uint32* pidCount, sint32 offset, sint32 count, bool includeFriendRequests);\n\tvoid getFriendRequestPIDs(uint32* pidList, uint32* pidCount, sint32 offset, sint32 count, bool includeIncoming, bool includeOutgoing);\n\tbool getFriendByPID(nexFriend& friendData, uint32 pid);\n\tbool getFriendRequestByPID(nexFriendRequest& friendRequestData, bool* isIncoming, uint32 searchedPid);\n\tbool getFriendRequestByMessageId(nexFriendRequest& friendRequestData, bool* isIncoming, uint64 messageId);\n\tbool isOnline();\n\tvoid getMyPreference(nexPrincipalPreference& preference);\n\tvoid getMyComment(nexComment& comment);\n\n\t// asynchronous API (data has to be requested)\n\tbool addProvisionalFriend(char* name, std::function<void(RpcErrorCode)> cb);\n\tvoid addFriendRequest(uint32 pid, const char* comment, std::function<void(RpcErrorCode)> cb);\n\tvoid requestPrincipleBaseInfoByPID(uint32* pidList, sint32 count, const std::function<void(RpcErrorCode result, std::span<nexPrincipalBasicInfo> basicInfo)>& cb);\n\tvoid removeFriend(uint32 pid, std::function<void(RpcErrorCode)> cb);\n\tvoid cancelOutgoingProvisionalFriendRequest(uint32 pid, std::function<void(RpcErrorCode)> cb);\n\tvoid markFriendRequestsAsReceived(uint64* messageIdList, sint32 count, std::function<void(RpcErrorCode)> cb);\n\tvoid acceptFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb);\n\tvoid deleteFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb); // rejecting incoming friend request (differs from blocking friend requests)\n\tbool updatePreferencesAsync(const nexPrincipalPreference newPreferences, std::function<void(RpcErrorCode)> cb);\n\tbool updateCommentAsync(const nexComment newComment, std::function<void(RpcErrorCode)> cb);\n\tvoid updateMyPresence(nexPresenceV2& myPresence);\n\n\tvoid setNotificationHandler(void(*notificationHandler)(NOTIFICATION_TYPE notificationType, uint32 pid));\n\n\tvoid update();\n\n\tvoid processServerNotification(uint32 notificationType, uint32 pid, nexPacketBuffer* notificationData);\n\nprivate:\n\tvoid doAsyncLogin();\n\tvoid initiateLogin();\n\n\tstatic void handleResponse_acceptFriendRequest(nexService* nex, nexServiceResponse_t* response);\n\tstatic void handleResponse_getAllInformation(nexServiceResponse_t* response, NexFriends* nexFriends, std::function<void(uint32)> cb);\n\n\tvoid generateNotification(NOTIFICATION_TYPE notificationType, uint32 pid);\n\tvoid trackNotifications();\n\t\n\t// notification-service handlers\n\tvoid processServerNotification_friendOffline(uint32 pid);\n\tvoid processServerNotification_presenceChange(uint32 pid, nexPresenceV2& presence);\n\tvoid processServerNotification_removeFriendOrFriendRequest(uint32 pid);\n\tvoid processServerNotification_incomingFriendRequest(uint32 pid, nexFriendRequest& friendRequest);\n\tvoid processServerNotification_addedFriend(uint32 pid, nexFriend& frd);\n\nprivate:\n\tvoid(*notificationHandler)(NOTIFICATION_TYPE notificationType, uint32 pid);\n\tbool isCurrentlyConnected;\n\tbool hasData; // set after connect when information request response was received\n\tbool firstInformationRequest;\n\tnexService* nexCon;\n\tuint8 miiData[FFL_SIZE];\n\tstd::string miiNickname;\n\tchar nnid[96];\n\tuint32 pid;\n\tuint8 countryCode;\n\t// login tracking\n\tstd::recursive_mutex mtx_login;\n\tbool loginInProcess;\n\tuint32 lastLoginAttemptTime;\n\tuint32 numFailedLogins;\n\tuint32 numSuccessfulLogins;\n\t// auth\n\tstruct  \n\t{\n\t\tuint32 serverIp;\n\t\tuint16 port;\n\t\tstd::string accessKey;\n\t\tstd::string nexPassword;\n\t\tstd::string nexToken;\n\t}auth;\n\t// local friend state\n\tnexPresenceV2 myPresence;\n\tnexPrincipalPreference myPreference;\n\tnexComment myComment;\n\n\tstd::recursive_mutex mtx_lists;\n\tstd::vector<nexFriend> list_friends;\n\tstd::vector<nexFriendRequest> list_friendReqOutgoing;\n\tstd::vector<nexFriendRequest> list_friendReqIncoming;\n\tstruct  \n\t{\n\t\tstd::vector<nexFriend> list_friends;\n\t\tstd::vector<nexFriendRequest> list_friendReqOutgoing;\n\t\tstd::vector<nexFriendRequest> list_friendReqIncoming;\n\t}previousState;\n};\n"
  },
  {
    "path": "src/Cemu/nex/nexThread.cpp",
    "content": "#include \"prudp.h\"\n#include \"nex.h\"\n#include \"nexThread.h\"\n\nstd::mutex mtx_queuedServices;\nstd::vector<nexService*> list_queuedServices;\n\nstd::vector<nexService*> list_activeNexServices;\n\nvoid nexThread_run()\n{\n\twhile (true)\n\t{\n\t\t// check for new services\n\t\tmtx_queuedServices.lock();\n\t\tfor(auto& it : list_queuedServices)\n\t\t\tlist_activeNexServices.push_back(it);\n\t\tlist_queuedServices.clear();\n\t\tmtx_queuedServices.unlock();\n\t\t// if service list is empty then pause\n\t\tif (list_activeNexServices.empty())\n\t\t{\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(200));\n\t\t\tcontinue;\n\t\t}\n\t\t// update\n\t\tfor (auto& it : list_activeNexServices)\n\t\t{\n\t\t\tit->update();\n\t\t}\n\t\t// delete services marked for destruction\n\t\tsint32 idx = 0;\n\t\tsint32 listSize = (sint32)list_activeNexServices.size();\n\t\twhile (idx < listSize)\n\t\t{\n\t\t\tif (list_activeNexServices[idx]->isMarkedForDestruction())\n\t\t\t{\n\t\t\t\tlist_activeNexServices[idx]->destroy();\n\t\t\t\tlistSize--;\n\t\t\t\tlist_activeNexServices[idx] = list_activeNexServices[listSize];\n\t\t\t}\n\t\t\tidx++;\n\t\t}\n\t\tif (listSize != list_activeNexServices.size())\n\t\t{\n\t\t\tlist_activeNexServices.resize(listSize);\n\t\t}\n\t\t// idle for short time\n\t\t// todo - find a better way to handle this with lower latency. Maybe using select() with loopback socket for interrupting the select on service change\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t}\n}\n\nbool _nexThreadLaunched = false;\n\nstd::thread::id nexThreadId;\n\nvoid nexThread_init()\n{\n\tif (_nexThreadLaunched)\n\t\treturn;\n\tstd::thread t(nexThread_run);\n\tnexThreadId = t.get_id();\n\tt.detach();\n\t_nexThreadLaunched = true;\n}\n\nvoid nexThread_registerService(nexService* service)\n{\n\tmtx_queuedServices.lock();\n\tnexThread_init();\n\tlist_queuedServices.push_back(service);\n\tmtx_queuedServices.unlock();\n}\n\nbool nexThread_isCurrentThread()\n{\n\tif (_nexThreadLaunched == false)\n\t\treturn false;\n\treturn std::this_thread::get_id() == nexThreadId;\n}"
  },
  {
    "path": "src/Cemu/nex/nexThread.h",
    "content": "#pragma once\n\nvoid nexThread_registerService(nexService* service);\nbool nexThread_isCurrentThread();"
  },
  {
    "path": "src/Cemu/nex/nexTypes.h",
    "content": "#pragma once\n#include<string>\n\n#ifndef FFL_SIZE\n#define FFL_SIZE\t(0x60)\n#endif\n\nclass nexPacketBuffer;\n\nclass nexMetaType\n{\npublic:\n\tvirtual const char* getMetaName() const = 0;\n\tvirtual void writeData(nexPacketBuffer* pb) const = 0;\n};\n\nclass nexType\n{\n  public:\n\tvirtual ~nexType(){};\n\n\tvirtual const char* getMetaName()\n\t{\n\t\tcemu_assert_unimplemented();\n\t\treturn \"\";\n\t}\n\tvirtual void writeData(nexPacketBuffer* pb) const = 0;\n\tvirtual void readData(nexPacketBuffer* pb) = 0;\n};\n\nclass nexPacketBuffer\n{\npublic:\n\tnexPacketBuffer(uint8* data, sint32 size, bool isWrite)\n\t{\n\t\tthis->buffer = data;\n\t\tthis->size = size;\n\t\tthis->currentIndex = 0;\n\t\tthis->isWrite = isWrite;\n\t\tthis->readOutOfBounds = false;\n\t}\n\n\tnexPacketBuffer()\n\t{\n\t\tthis->buffer = 0;\n\t\tthis->size = 0;\n\t\tthis->currentIndex = 0;\n\t}\n\n\tvoid writeData(const uint8* data, sint32 len)\n\t{\n\t\tif (this->currentIndex + len > this->size)\n\t\t\treturn;\n\t\tmemcpy(this->buffer + this->currentIndex, data, len);\n\t\tthis->currentIndex += len;\n\t}\n\n\tvoid writeU8(uint8 v)\n\t{\n\t\tif (this->currentIndex + sizeof(uint8) > this->size)\n\t\t\treturn;\n\t\t*(uint8*)(this->buffer + this->currentIndex) = v;\n\t\tthis->currentIndex += sizeof(uint8);\n\t}\n\n\tvoid writeU16(uint16 v)\n\t{\n\t\tif (this->currentIndex + sizeof(uint16) > this->size)\n\t\t\treturn;\n\t\t*(uint16*)(this->buffer + this->currentIndex) = v;\n\t\tthis->currentIndex += sizeof(uint16);\n\t}\n\n\tvoid writeU32(uint32 v)\n\t{\n\t\tif (this->currentIndex + sizeof(uint32) > this->size)\n\t\t\treturn;\n\t\t*(uint32*)(this->buffer + this->currentIndex) = v;\n\t\tthis->currentIndex += sizeof(uint32);\n\t}\n\n\tvoid writeU64(uint64 v)\n\t{\n\t\tif (this->currentIndex + sizeof(uint64) > this->size)\n\t\t\treturn;\n\t\t*(uint64*)(this->buffer + this->currentIndex) = v;\n\t\tthis->currentIndex += sizeof(uint64);\n\t}\n\n\tvoid writeString(const char* v)\n\t{\n\t\tsint32 len = (sint32)strlen(v) + 1;\n\t\twriteU16(len);\n\t\twriteData((uint8*)v, len);\n\t}\n\n\tvoid writeBuffer(const uint8* v, sint32 len)\n\t{\n\t\twriteU32(len);\n\t\twriteData(v, len);\n\t}\n\n\tvoid writeCustomType(const nexMetaType& v)\n\t{\n\t\t// write meta name\n\t\twriteString(v.getMetaName());\n\t\t// write length 0 placeholder\n\t\tuint32* lengthPtr0 = (uint32*)(this->buffer + this->currentIndex);\n\t\twriteU32(0);\n\t\t// write length 1 placeholder\n\t\tuint32* lengthPtr1 = (uint32*)(this->buffer + this->currentIndex);\n\t\twriteU32(0);\n\t\t// write data\n\t\tuint32 preWriteIndex = this->currentIndex;\n\t\tv.writeData(this);\n\t\tuint32 writeSize = this->currentIndex - preWriteIndex;\n\t\t// update lengths\n\t\t*lengthPtr1 = writeSize;\n\t\t*lengthPtr0 = writeSize + 4;\n\t}\n\n\tuint64 readU64()\n\t{\n\t\tif (this->currentIndex + sizeof(uint64) > this->size)\n\t\t{\n\t\t\treadOutOfBounds = true;\n\t\t\treturn 0;\n\t\t}\n\t\tuint64 v = *(uint64*)(this->buffer + this->currentIndex);\n\t\tthis->currentIndex += sizeof(uint64);\n\t\treturn v;\n\t}\n\n\tuint32 readU32()\n\t{\n\t\tif (this->currentIndex + sizeof(uint32) > this->size)\n\t\t{\n\t\t\treadOutOfBounds = true;\n\t\t\treturn 0;\n\t\t}\n\t\tuint32 v = *(uint32*)(this->buffer + this->currentIndex);\n\t\tthis->currentIndex += sizeof(uint32);\n\t\treturn v;\n\t}\n\n\tuint16 readU16()\n\t{\n\t\tif (this->currentIndex + sizeof(uint16) > this->size)\n\t\t{\n\t\t\treadOutOfBounds = true;\n\t\t\treturn 0;\n\t\t}\n\t\tuint16 v = *(uint16*)(this->buffer + this->currentIndex);\n\t\tthis->currentIndex += sizeof(uint16);\n\t\treturn v;\n\t}\n\n\tuint8 readU8()\n\t{\n\t\tif (this->currentIndex + sizeof(uint8) > this->size)\n\t\t{\n\t\t\treadOutOfBounds = true;\n\t\t\treturn 0;\n\t\t}\n\t\tuint8 v = *(uint8*)(this->buffer + this->currentIndex);\n\t\tthis->currentIndex += sizeof(uint8);\n\t\treturn v;\n\t}\n\n\tsint32 readData(void* buffer, sint32 length)\n\t{\n\t\tif (this->currentIndex + length > this->size)\n\t\t{\n\t\t\treadOutOfBounds = true;\n\t\t\treturn 0;\n\t\t}\n\t\tmemcpy(buffer, (this->buffer + this->currentIndex), length);\n\t\tthis->currentIndex += length;\n\t\treturn length;\n\t}\n\n\t// reads buffer data from packet and returns amount of bytes copied into buffer\n\t// if buffer is larger than maxLength, the read data is silently truncated\n\tsint32 readBuffer(void* buffer, sint32 maxLength)\n\t{\n\t\tsint32 bufferLength = (sint32)readU32();\n\t\tif (bufferLength < 0 || bufferLength >= 0x10000000)\n\t\t{\n\t\t\treadOutOfBounds = true;\n\t\t\treturn 0;\n\t\t}\n\t\tif (this->currentIndex + bufferLength > this->size)\n\t\t{\n\t\t\treadOutOfBounds = true;\n\t\t\treturn 0;\n\t\t}\n\t\tuint32 copiedLength = std::min(bufferLength, maxLength);\n\n\t\tmemcpy(buffer, (this->buffer + this->currentIndex), copiedLength);\n\t\tthis->currentIndex += bufferLength;\n\t\treturn copiedLength;\n\t}\n\n\tsint32 readString(char* buffer, sint32 maxLength)\n\t{\n\t\tsint32 bufferLength = readU16();\n\t\tif (this->currentIndex + bufferLength > this->size)\n\t\t{\n\t\t\treadOutOfBounds = true;\n\t\t\tbuffer[0] = '\\0';\n\t\t\treturn 0;\n\t\t}\n\t\tuint32 copiedLength = std::min(bufferLength, maxLength - 1);\n\n\t\tmemcpy(buffer, (this->buffer + this->currentIndex), copiedLength);\n\t\tbuffer[copiedLength] = '\\0';\n\t\tthis->currentIndex += bufferLength;\n\t\treturn copiedLength;\n\t}\n\n\tsint32 readStdString(std::string& outputStr)\n\t{\n\t\tsint32 bufferLength = readU16();\n\t\tif (this->currentIndex + bufferLength > this->size)\n\t\t{\n\t\t\treadOutOfBounds = true;\n\t\t\toutputStr.clear();\n\t\t\treturn 0;\n\t\t}\n\t\tsint32 copiedLength = bufferLength;\n\t\tif (bufferLength > 0 && this->buffer[this->currentIndex+bufferLength-1] == '\\0')\n\t\t{\n\t\t\t// cut off trailing '\\0'\n\t\t\tcopiedLength--;\n\t\t}\n\t\toutputStr = std::string((char*)(this->buffer + this->currentIndex), copiedLength);\n\t\tthis->currentIndex += bufferLength;\n\t\treturn copiedLength;\n\t}\n\n\tbool readPlaceholderType(nexType& v)\n\t{\n\t\tchar name[128];\n\t\treadString(name, sizeof(name));\n\t\tname[sizeof(name)-1] = '\\0';\n\t\tif (hasReadOutOfBounds())\n\t\t\treturn false;\n\t\tif (strcmp(name, v.getMetaName()) != 0)\n\t\t\treturn false;\n\t\t// read sizes\n\t\tuint32 len0 = readU32();\n\t\tuint32 len1 = readU32();\n\t\tif (hasReadOutOfBounds())\n\t\t\treturn false;\n\t\tif (len1 != (len0 - 4))\n\t\t\treturn false;\n\t\t// parse type data\n\t\tv.readData(this);\n\t\tif (hasReadOutOfBounds())\n\t\t\treturn false;\n\t\treturn true;\n\t\t//// write meta name\n\t\t//writeString(v.getMetaName());\n\t\t//// write length 0 placeholder\n\t\t//uint32* lengthPtr0 = (uint32*)(this->buffer + this->currentIndex);\n\t\t//writeU32(0);\n\t\t//// write length 1 placeholder\n\t\t//uint32* lengthPtr1 = (uint32*)(this->buffer + this->currentIndex);\n\t\t//writeU32(0);\n\t\t//// write data\n\t\t//uint32 preWriteIndex = this->currentIndex;\n\t\t//v.writeData(this);\n\t\t//uint32 writeSize = this->currentIndex - preWriteIndex;\n\t\t//// update lengths\n\t\t//*lengthPtr1 = writeSize;\n\t\t//*lengthPtr0 = writeSize + 4;\n\t}\n\n\tbool hasReadOutOfBounds()\n\t{\n\t\treturn readOutOfBounds;\n\t}\n\n\tuint8* getDataPtr()\n\t{\n\t\treturn buffer;\n\t}\n\n\tsint32 getWriteIndex()\n\t{\n\t\treturn currentIndex;\n\t}\n\n\tsint32 getSize()\n\t{\n\t\treturn size;\n\t}\n\n\tvoid setSize(sint32 length)\n\t{\n\t\tsize = length;\n\t}\n\nprivate:\n\tuint8* buffer;\n\tsint32 size;\n\tsint32 currentIndex;\n\tbool isWrite;\n\tbool readOutOfBounds; // set if any read operation failed because it exceeded the buffer\n};\n\nclass nexNintendoLoginData : public nexMetaType\n{\npublic:\n\tnexNintendoLoginData(const char* nexToken)\n\t{\n\t\tthis->nexToken = new std::string(nexToken);\n\t}\n\n\tconst char* getMetaName() const override\n\t{\n\t\treturn \"NintendoLoginData\";\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tpb->writeString(nexToken->c_str());\n\t}\nprivate:\n\tstd::string* nexToken;\n};\n\nclass nexNotificationEventGeneral : public nexType\n{\npublic:\n\tnexNotificationEventGeneral()\n\t{\n\n\t}\n\n\tnexNotificationEventGeneral(nexPacketBuffer* pb)\n\t{\n\t\treadData(pb);\n\t}\n\n\tconst char* getMetaName() override\n\t{\n\t\treturn \"NintendoNotificationEventGeneral\";\n\t}\n\n\tvoid writeData(nexPacketBuffer* pb) const override\n\t{\n\t\tcemu_assert_unimplemented();\n\t}\n\n\tvoid readData(nexPacketBuffer* pb) override\n\t{\n\t\tparam1 = pb->readU32();\n\t\tparam2 = pb->readU64();\n\t\tparam3 = pb->readU64();\n\t\tpb->readStdString(paramStr);\n\t}\npublic:\n\tuint32 param1;\n\tuint64 param2;\n\tuint64 param3;\n\tstd::string paramStr;\n};\n"
  },
  {
    "path": "src/Cemu/nex/prudp.cpp",
    "content": "#include \"prudp.h\"\n#include \"util/crypto/md5.h\"\n\n#include <bitset>\n#include <random>\n\n#include <boost/random/uniform_int.hpp>\n\nstatic void KSA(unsigned char* key, int keyLen, unsigned char* S)\n{\n\tfor (int i = 0; i < RC4_N; i++)\n\t\tS[i] = i;\n\tint j = 0;\n\tfor (int i = 0; i < RC4_N; i++)\n\t{\n\t\tj = (j + S[i] + key[i % keyLen]) % RC4_N;\n\t\tstd::swap(S[i], S[j]);\n\t}\n}\n\nstatic void PRGA(unsigned char* S, unsigned char* input, int len, unsigned char* output)\n{\n\tfor (size_t n = 0; n < len; n++)\n\t{\n\t\tint i = (i + 1) % RC4_N;\n\t\tint j = (j + S[i]) % RC4_N;\n\t\tstd::swap(S[i], S[j]);\n\t\tint rnd = S[(S[i] + S[j]) % RC4_N];\n\t\toutput[n] = rnd ^ input[n];\n\t}\n}\n\nstatic void RC4(char* key, unsigned char* input, int len, unsigned char* output)\n{\n\tunsigned char S[RC4_N];\n\tKSA((unsigned char*)key, (int)strlen(key), S);\n\tPRGA(S, input, len, output);\n}\n\nvoid RC4_initCtx(RC4Ctx* rc4Ctx, const char* key)\n{\n\trc4Ctx->i = 0;\n\trc4Ctx->j = 0;\n\tKSA((unsigned char*)key, (int)strlen(key), rc4Ctx->S);\n}\n\nvoid RC4_initCtx(RC4Ctx* rc4Ctx, unsigned char* key, int keyLen)\n{\n\trc4Ctx->i = 0;\n\trc4Ctx->j = 0;\n\tKSA(key, keyLen, rc4Ctx->S);\n}\n\nvoid RC4_transform(RC4Ctx* rc4Ctx, unsigned char* input, int len, unsigned char* output)\n{\n\tint i = rc4Ctx->i;\n\tint j = rc4Ctx->j;\n\n\tfor (size_t n = 0; n < len; n++)\n\t{\n\t\ti = (i + 1) % RC4_N;\n\t\tj = (j + rc4Ctx->S[i]) % RC4_N;\n\t\tstd::swap(rc4Ctx->S[i], rc4Ctx->S[j]);\n\t\tint rnd = rc4Ctx->S[(rc4Ctx->S[i] + rc4Ctx->S[j]) % RC4_N];\n\t\toutput[n] = rnd ^ input[n];\n\t}\n\trc4Ctx->i = i;\n\trc4Ctx->j = j;\n}\n\nuint32 prudpGetMSTimestamp()\n{\n\treturn GetTickCount();\n}\n\nstd::mt19937_64 prudpRG(GetTickCount());\n// workaround for static asserts when using uniform_int_distribution (see https://github.com/cemu-project/Cemu/issues/48)\nboost::random::uniform_int_distribution<int> prudpRandomDistribution8(0, 0xFF);\nboost::random::uniform_int_distribution<int> prudpRandomDistributionPortGen(0, 10000);\n\nuint8 prudp_generateRandomU8()\n{\n\treturn prudpRandomDistribution8(prudpRG);\n}\n\nuint32 prudp_generateRandomU32()\n{\n\tuint32 v = prudp_generateRandomU8();\n\tv <<= 8;\n\tv |= prudp_generateRandomU8();\n\tv <<= 8;\n\tv |= prudp_generateRandomU8();\n\tv <<= 8;\n\tv |= prudp_generateRandomU8();\n\treturn v;\n}\n\nstd::bitset<10000> _portUsageMask;\n\nstatic uint16 AllocateRandomSrcPRUDPPort()\n{\n\twhile (true)\n\t{\n\t\tsint32 p = prudpRandomDistributionPortGen(prudpRG);\n\t\tif (_portUsageMask.test(p))\n\t\t\tcontinue;\n\t\t_portUsageMask.set(p);\n\t\treturn 40000 + p;\n\t}\n}\n\nstatic void ReleasePRUDPSrcPort(uint16 port)\n{\n\tcemu_assert_debug(port >= 40000);\n\tuint32 bitIndex = port - 40000;\n\tcemu_assert_debug(_portUsageMask.test(bitIndex));\n\t_portUsageMask.reset(bitIndex);\n}\n\nstatic uint8 prudp_calculateChecksum(uint8 checksumBase, uint8* data, sint32 length)\n{\n\tuint32 checksum32 = 0;\n\tfor (sint32 i = 0; i < length / 4; i++)\n\t{\n\t\tchecksum32 += *(uint32*)(data + i * 4);\n\t}\n\tuint8 checksum = checksumBase;\n\tfor (sint32 i = length & (~3); i < length; i++)\n\t{\n\t\tchecksum += data[i];\n\t}\n\tchecksum += (uint8)((checksum32 >> 0) & 0xFF);\n\tchecksum += (uint8)((checksum32 >> 8) & 0xFF);\n\tchecksum += (uint8)((checksum32 >> 16) & 0xFF);\n\tchecksum += (uint8)((checksum32 >> 24) & 0xFF);\n\treturn checksum;\n}\n\n// calculate the actual size of the packet from the unprocessed raw data\n// returns 0 on error\nsint32 prudpPacket::calculateSizeFromPacketData(uint8* data, sint32 length)\n{\n\t// check if packet is long enough to hold basic header\n\tif (length < 0xB)\n\t\treturn 0;\n\t// get flags fields\n\tuint16 typeAndFlags = *(uint16*)(data + 0x02);\n\tuint16 type = (typeAndFlags & 0xF);\n\tuint16 flags = (typeAndFlags >> 4);\n\tif ((flags & FLAG_HAS_SIZE) == 0)\n\t\treturn length; // without a size field, we cant calculate the length\n\tsint32 calculatedSize;\n\tif (type == TYPE_SYN)\n\t{\n\t\tif (length < (0xB + 0x4 + 2))\n\t\t\treturn 0;\n\t\tuint16 payloadSize = *(uint16*)(data + 0xB + 0x4);\n\t\tcalculatedSize = 0xB + 0x4 + 2 + (sint32)payloadSize + 1; // base header + connection signature (SYN param) + payloadSize field + checksum after payload\n\t\tif (calculatedSize > length)\n\t\t\treturn 0;\n\t\treturn calculatedSize;\n\t}\n\telse if (type == TYPE_CON)\n\t{\n\t\tif (length < (0xB + 0x4 + 2))\n\t\t\treturn 0;\n\t\tuint16 payloadSize = *(uint16*)(data + 0xB + 0x4);\n\t\tcalculatedSize = 0xB + 0x4 + 2 + (sint32)payloadSize + 1; // base header + connection signature (CON param) + payloadSize field + checksum after payload\n\t\t// note: For secure connections the extra data is part of the payload\n\t\tif (calculatedSize > length)\n\t\t\treturn 0;\n\t\treturn calculatedSize;\n\t}\n\telse if (type == TYPE_DATA)\n\t{\n\t\tif (length < (0xB + 1 + 2))\n\t\t\treturn 0;\n\t\tuint16 payloadSize = *(uint16*)(data + 0xB + 1);\n\t\tcalculatedSize = 0xB + 1 + 2 + (sint32)payloadSize + 1; // base header + fragmentIndex (DATA param) + payloadSize field + checksum after payload\n\t\tif (calculatedSize > length)\n\t\t\treturn 0;\n\t\treturn calculatedSize;\n\t}\n\telse if (type == TYPE_PING)\n\t{\n\t\tif (length < (0xB + 2))\n\t\t\treturn 0;\n\t\tuint16 payloadSize = *(uint16*)(data + 0xB);\n\t\tcalculatedSize = 0xB + 2 + (sint32)payloadSize + 1; // base header + payloadSize field + checksum after payload\n\t\tif (calculatedSize > length)\n\t\t\treturn 0;\n\t\treturn calculatedSize;\n\t}\n\telse\n\t\tassert_dbg(); // unknown packet type (todo - add disconnect and ping packet, then make this function return 0 for all unknown types)\n\treturn length;\n}\n\nprudpPacket::prudpPacket(prudpStreamSettings* streamSettings, uint8 src, uint8 dst, uint8 type, uint16 flags, uint8 sessionId, uint16 sequenceId, uint32 packetSignature)\n{\n\tthis->src = src;\n\tthis->dst = dst;\n\tthis->type = type;\n\tthis->flags = flags;\n\tthis->sessionId = sessionId;\n\tthis->m_sequenceId = sequenceId;\n\tthis->specifiedPacketSignature = packetSignature;\n\tthis->streamSettings = streamSettings;\n\tthis->fragmentIndex = 0;\n\tthis->isEncrypted = false;\n}\n\nbool prudpPacket::requiresAck()\n{\n\treturn (flags & FLAG_NEED_ACK) != 0;\n}\n\nsint32 prudpPacket::buildData(uint8* output, sint32 maxLength)\n{\n\t// PRUDP V0\n\t// encrypt packet data\n\tif (this->type == prudpPacket::TYPE_DATA)\n\t{\n\t\t// dont save new rc4 state if the packet is not reliable or requires no ack?\n\t\tif (packetData.size() > 0)\n\t\t{\n\t\t\tif (isEncrypted == false) // only encrypt once\n\t\t\t{\n\t\t\t\tRC4_transform(&streamSettings->rc4Client, &packetData.front(), (int)packetData.size(), &packetData.front());\n\t\t\t\tisEncrypted = true;\n\t\t\t}\n\t\t}\n\t}\n\t// build packet\n\tuint8* packetBuffer = output;\n\tsint32 writeIndex = 0;\n\t// write constant header\n\t*(uint8*)(packetBuffer + 0x00) = src;\n\t*(uint8*)(packetBuffer + 0x01) = dst;\n\tuint16 typeAndFlags = (this->flags << 4) | (this->type);\n\t*(uint16*)(packetBuffer + 0x02) = typeAndFlags;\n\t*(uint8*)(packetBuffer + 0x04) = sessionId;\n\t*(uint32*)(packetBuffer + 0x05) = packetSignature();\n\t*(uint16*)(packetBuffer + 0x09) = m_sequenceId;\n\twriteIndex = 0xB;\n\t// variable fields\n\tif (this->type == TYPE_SYN)\n\t{\n\t\t*(uint32*)(packetBuffer + writeIndex) = 0; // connection signature (always 0 for SYN packet)\n\t\twriteIndex += 4;\n\t}\n\telse if (this->type == TYPE_CON)\n\t{\n\t\t// connection signature (+ kerberos data if secure connection)\n\t\tmemcpy(packetBuffer + writeIndex, &packetData.front(), packetData.size());\n\t\twriteIndex += (int)packetData.size();\n\t}\n\telse if (this->type == TYPE_DATA)\n\t{\n\t\t*(uint8*)(packetBuffer + writeIndex) = fragmentIndex; // fragment index\n\t\twriteIndex += 1;\n\t\tif (packetData.empty() == false)\n\t\t{\n\t\t\tmemcpy(packetBuffer + writeIndex, &packetData.front(), packetData.size());\n\t\t\twriteIndex += (int)packetData.size();\n\t\t}\n\t}\n\telse if (this->type == TYPE_PING)\n\t{\n\t\t// no data\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n\t// checksum\n\t*(uint8*)(packetBuffer + writeIndex) = calculateChecksum(packetBuffer, writeIndex);\n\twriteIndex++;\n\n\treturn writeIndex;\n}\n\nuint32 prudpPacket::packetSignature()\n{\n\tif (type == TYPE_SYN)\n\t\treturn 0;\n\telse if (type == TYPE_CON || type == TYPE_PING)\n\t\treturn specifiedPacketSignature;\n\telse if (type == TYPE_DATA)\n\t{\n\t\tif (packetData.empty())\n\t\t\treturn 0x12345678;\n\n\t\tHMACMD5Ctx ctx;\n\t\thmacMD5_init_limK_to_64(streamSettings->accessKeyDigest, 16, &ctx);\n\t\thmacMD5_update(&packetData.front(), (int)packetData.size(), &ctx);\n\n\t\tuint8 digest[16];\n\t\thmacMD5_final(digest, &ctx);\n\t\tuint32 pSig = *(uint32*)digest;\n\t\treturn pSig;\n\t}\n\n\tassert_dbg();\n\treturn 0;\n}\n\nvoid prudpPacket::setData(uint8* data, sint32 length)\n{\n\tpacketData.assign(data, data + length);\n}\n\nvoid prudpPacket::setFragmentIndex(uint8 fragmentIndex)\n{\n\tthis->fragmentIndex = fragmentIndex;\n}\n\nuint8 prudpPacket::calculateChecksum(uint8* data, sint32 length)\n{\n\treturn prudp_calculateChecksum(streamSettings->checksumBase, data, length);\n}\n\nprudpIncomingPacket::prudpIncomingPacket()\n{\n\tsrc = 0;\n\tdst = 0;\n\tflags = 0;\n\ttype = 0;\n\tsessionId = 0;\n\tpacketSignature = 0;\n\tsequenceId = 0;\n\tfragmentIndex = 0;\n\thasData = false;\n\tisInvalid = false;\n\tstreamSettings = nullptr;\n}\n\nprudpIncomingPacket::prudpIncomingPacket(prudpStreamSettings* streamSettings, uint8* data, sint32 length)\n\t: prudpIncomingPacket()\n{\n\tif (length < 0xB + 1)\n\t{\n\t\tisInvalid = true;\n\t\treturn;\n\t}\n\tthis->streamSettings = streamSettings;\n\t// verify checksum first\n\tuint8 actualChecksum = calculateChecksum(data, length - 1);\n\tuint8 packetChecksum = *(uint8*)(data + length - 1);\n\tif (actualChecksum != packetChecksum)\n\t{\n\t\tisInvalid = true;\n\t\treturn;\n\t}\n\tlength--; // remove checksum from length\n\t// verify constant header\n\tthis->src = *(uint8*)(data + 0x00);\n\tthis->dst = *(uint8*)(data + 0x01);\n\tuint16 typeAndFlags = *(uint16*)(data + 0x02);\n\tthis->flags = (typeAndFlags >> 4) & 0xFFF;\n\tthis->type = (typeAndFlags & 0xF);\n\tthis->sessionId = *(uint8*)(data + 0x4);\n\tthis->packetSignature = *(uint32*)(data + 0x5);\n\tthis->sequenceId = *(uint16*)(data + 0x9);\n\t// read dynamic fields\n\tsint32 readIndex = 0xB;\n\tif (this->type == prudpPacket::TYPE_SYN)\n\t{\n\t\t// SYN packet\n\t\tif (readIndex < 4)\n\t\t{\n\t\t\tisInvalid = true;\n\t\t\treturn;\n\t\t}\n\t\tpacketData.resize(4);\n\t\t*(uint32*)(&packetData.front()) = *(uint32*)(data + readIndex);\n\t\thasData = true;\n\t\treadIndex += 4;\n\t\t// ignore FLAG_HAS_SIZE (would come here, usually with a value of 0)\n\t\treturn;\n\t}\n\telse if (this->type == prudpPacket::TYPE_CON)\n\t{\n\t\t// CON packet\n\t\tif (readIndex < 4)\n\t\t{\n\t\t\tisInvalid = true;\n\t\t\treturn;\n\t\t}\n\t\t// this packet has another 4 byte signature but it's always zero? (value is ignored for now)\n\t\t// ignore FLAG_HAS_SIZE\n\t}\n\telse if (this->type == prudpPacket::TYPE_PING)\n\t{\n\t\t// PING packet\n\t\t// ignore payload\n\t}\n\telse if (this->type == prudpPacket::TYPE_DATA)\n\t{\n\t\t// can we assume that reliable data packets always need to have a unique sequence id? (Even if it's a multi-fragment frame)\n\t\t// unreliable packets must have a sequence id too or how else would we know when to decrypt it?\n\n\t\tbool hasPayloadSize = (this->flags & prudpPacket::FLAG_HAS_SIZE) != 0;\n\t\t// verify length\n\t\tif ((length - readIndex) < 1 + (hasPayloadSize ? 2 : 0))\n\t\t{\n\t\t\t// too short\n\t\t\tisInvalid = true;\n\t\t\treturn;\n\t\t}\n\t\t// read fragment index\n\t\tthis->fragmentIndex = *(uint8*)(data + readIndex);\n\t\treadIndex += sizeof(uint8);\n\t\t// read payload size (optional)\n\t\tif (hasPayloadSize)\n\t\t{\n\t\t\tuint16 payloadSize = *(uint32*)(data + readIndex);\n\t\t\treadIndex += sizeof(uint16);\n\t\t\t// verify payload size\n\t\t\tif ((length - readIndex) != payloadSize)\n\t\t\t{\n\t\t\t\tassert_dbg(); // mismatch, ignore packet or use specified payload size?\n\t\t\t}\n\t\t}\n\t\t// read payload\n\t\tif (readIndex < length)\n\t\t{\n\t\t\tsint32 dataSize = length - readIndex;\n\t\t\tpacketData.resize(dataSize);\n\t\t\tmemcpy(&packetData.front(), data + readIndex, dataSize);\n\t\t}\n\t\treturn;\n\t}\n\telse if (this->type == prudpPacket::TYPE_DISCONNECT)\n\t{\n\t\t// DISCONNECT packet\n\t\t// ignore payload\n\t}\n\telse\n\t{\n\t\tcemu_assert_suspicious();\n\t}\n}\n\nbool prudpIncomingPacket::hasError()\n{\n\treturn isInvalid;\n}\n\nuint8 prudpIncomingPacket::calculateChecksum(uint8* data, sint32 length)\n{\n\treturn prudp_calculateChecksum(streamSettings->checksumBase, data, length);\n}\n\nvoid prudpIncomingPacket::decrypt()\n{\n\tif (packetData.empty())\n\t\treturn;\n\tRC4_transform(&streamSettings->rc4Server, &packetData.front(), (int)packetData.size(), &packetData.front());\n}\n\n#define PRUDP_VPORT(__streamType, __port) (((__streamType) << 4) | (__port))\n\nprudpClient::prudpClient()\n{\n\tm_currentConnectionState = ConnectionState::Connecting;\n\tm_serverConnectionSignature = 0;\n\tm_clientConnectionSignature = 0;\n\tm_incomingSequenceId = 0;\n\n\tm_clientSessionId = 0;\n\tm_serverSessionId = 0;\n}\n\nprudpClient::prudpClient(uint32 dstIp, uint16 dstPort, const char* key)\n\t: prudpClient()\n{\n\tm_dstIp = dstIp;\n\tm_dstPort = dstPort;\n\t// get unused random source port\n\tfor (sint32 tries = 0; tries < 5; tries++)\n\t{\n\t\tm_srcPort = AllocateRandomSrcPRUDPPort();\n\t\t// create and bind udp socket\n\t\tm_socketUdp = socket(AF_INET, SOCK_DGRAM, 0);\n\t\tstruct sockaddr_in udpServer;\n\t\tudpServer.sin_family = AF_INET;\n\t\tudpServer.sin_addr.s_addr = INADDR_ANY;\n\t\tudpServer.sin_port = htons(m_srcPort);\n\t\tif (bind(m_socketUdp, (struct sockaddr*)&udpServer, sizeof(udpServer)) == SOCKET_ERROR)\n\t\t{\n\t\t\tReleasePRUDPSrcPort(m_srcPort);\n\t\t\tm_srcPort = 0;\n\t\t\tif (tries == 4)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"PRUDP: Failed to bind UDP socket\");\n\t\t\t\tm_currentConnectionState = ConnectionState::Disconnected;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclosesocket(m_socketUdp);\n\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t\tbreak;\n\t}\n\t// set socket to non-blocking mode\n#if BOOST_OS_WINDOWS\n\tu_long nonBlockingMode = 1; // 1 to enable non-blocking socket\n\tioctlsocket(m_socketUdp, FIONBIO, &nonBlockingMode);\n#else\n\tint flags = fcntl(m_socketUdp, F_GETFL);\n\tfcntl(m_socketUdp, F_SETFL, flags | O_NONBLOCK);\n#endif\n\t// generate frequently used parameters\n\tm_srcVPort = PRUDP_VPORT(prudpPacket::STREAM_TYPE_SECURE, 0xF);\n\tm_dstVPort = PRUDP_VPORT(prudpPacket::STREAM_TYPE_SECURE, 0x1);\n\t// set stream settings\n\tuint8 checksumBase = 0;\n\tfor (sint32 i = 0; key[i] != '\\0'; i++)\n\t{\n\t\tchecksumBase += key[i];\n\t}\n\tm_streamSettings.checksumBase = checksumBase;\n\tMD5_CTX md5Ctx;\n\tMD5_Init(&md5Ctx);\n\tMD5_Update(&md5Ctx, key, (int)strlen(key));\n\tMD5_Final(m_streamSettings.accessKeyDigest, &md5Ctx);\n\t// init stream ciphers\n\tRC4_initCtx(&m_streamSettings.rc4Server, \"CD&ML\");\n\tRC4_initCtx(&m_streamSettings.rc4Client, \"CD&ML\");\n\t// send syn packet\n\tSendCurrentHandshakePacket();\n\t// set incoming sequence id to 1\n\tm_incomingSequenceId = 1;\n}\n\nprudpClient::prudpClient(uint32 dstIp, uint16 dstPort, const char* key, prudpAuthServerInfo* authInfo)\n\t: prudpClient(dstIp, dstPort, key)\n{\n\tRC4_initCtx(&m_streamSettings.rc4Server, authInfo->secureKey, 16);\n\tRC4_initCtx(&m_streamSettings.rc4Client, authInfo->secureKey, 16);\n\tm_isSecureConnection = true;\n\tmemcpy(&m_authInfo, authInfo, sizeof(prudpAuthServerInfo));\n}\n\nprudpClient::~prudpClient()\n{\n\tif (m_srcPort != 0)\n\t{\n\t\tReleasePRUDPSrcPort(m_srcPort);\n\t\tclosesocket(m_socketUdp);\n\t}\n}\n\nvoid prudpClient::AcknowledgePacket(uint16 sequenceId)\n{\n\tauto it = std::begin(m_dataPacketsWithAckReq);\n\twhile (it != std::end(m_dataPacketsWithAckReq))\n\t{\n\t\tif (it->packet->GetSequenceId() == sequenceId)\n\t\t{\n\t\t\tdelete it->packet;\n\t\t\tm_dataPacketsWithAckReq.erase(it);\n\t\t\treturn;\n\t\t}\n\t\tit++;\n\t}\n}\n\nvoid prudpClient::SortIncomingDataPacket(std::unique_ptr<prudpIncomingPacket> incomingPacket)\n{\n\tuint16 sequenceIdIncomingPacket = incomingPacket->sequenceId;\n\t// find insert index\n\tsint32 insertIndex = 0;\n\twhile (insertIndex < m_incomingPacketQueue.size())\n\t{\n\t\tuint16 seqDif = sequenceIdIncomingPacket - m_incomingPacketQueue[insertIndex]->sequenceId;\n\t\tif (seqDif & 0x8000)\n\t\t\tbreak; // negative seqDif -> insert before current element\n#ifdef CEMU_DEBUG_ASSERT\n\t\tif (seqDif == 0)\n\t\t\tassert_dbg(); // same sequence id, sort by fragment index?\n#endif\n\t\tinsertIndex++;\n\t}\n\tm_incomingPacketQueue.insert(m_incomingPacketQueue.begin() + insertIndex, std::move(incomingPacket));\n\t// debug check if packets are really ordered by sequence id\n#ifdef CEMU_DEBUG_ASSERT\n\tfor (sint32 i = 1; i < m_incomingPacketQueue.size(); i++)\n\t{\n\t\tuint16 seqDif = m_incomingPacketQueue[i]->sequenceId - m_incomingPacketQueue[i - 1]->sequenceId;\n\t\tif (seqDif & 0x8000)\n\t\t\tseqDif = -seqDif;\n\t\tif (seqDif >= 0x8000)\n\t\t\tassert_dbg();\n\t}\n#endif\n}\n\nsint32 prudpClient::KerberosEncryptData(uint8* input, sint32 length, uint8* output)\n{\n\tRC4Ctx rc4Kerberos;\n\tRC4_initCtx(&rc4Kerberos, m_authInfo.secureKey, 16);\n\tmemcpy(output, input, length);\n\tRC4_transform(&rc4Kerberos, output, length, output);\n\t// calculate and append hmac\n\thmacMD5(this->m_authInfo.secureKey, 16, output, length, output + length);\n\treturn length + 16;\n}\n\n// (re)sends either CON or SYN based on what stage of the login we are at\n// the sequenceId for both is hardcoded for both because we'll never send anything in between\nvoid prudpClient::SendCurrentHandshakePacket()\n{\n\tif (!m_hasSynAck)\n\t{\n\t\t// send syn (with a fixed sequenceId of 0)\n\t\tprudpPacket synPacket(&m_streamSettings, m_srcVPort, m_dstVPort, prudpPacket::TYPE_SYN, prudpPacket::FLAG_NEED_ACK, 0, 0, 0);\n\t\tDirectSendPacket(&synPacket);\n\t}\n\telse\n\t{\n\t\t// send con (with a fixed sequenceId of 1)\n\t\tprudpPacket conPacket(&m_streamSettings, m_srcVPort, m_dstVPort, prudpPacket::TYPE_CON, prudpPacket::FLAG_NEED_ACK | prudpPacket::FLAG_RELIABLE, this->m_clientSessionId, 1, m_serverConnectionSignature);\n\t\tif (this->m_isSecureConnection)\n\t\t{\n\t\t\tuint8 tempBuffer[512];\n\t\t\tnexPacketBuffer conData(tempBuffer, sizeof(tempBuffer), true);\n\t\t\tconData.writeU32(m_clientConnectionSignature);\n\t\t\tconData.writeBuffer(m_authInfo.secureTicket, m_authInfo.secureTicketLength);\n\t\t\t// encrypted request data\n\t\t\tuint8 requestData[4 * 3];\n\t\t\tuint8 requestDataEncrypted[4 * 3 + 0x10];\n\t\t\t*(uint32*)(requestData + 0x0) = m_authInfo.userPid;\n\t\t\t*(uint32*)(requestData + 0x4) = m_authInfo.server.cid;\n\t\t\t*(uint32*)(requestData + 0x8) = prudp_generateRandomU32(); // todo - check value\n\t\t\tsint32 encryptedSize = KerberosEncryptData(requestData, sizeof(requestData), requestDataEncrypted);\n\t\t\tconData.writeBuffer(requestDataEncrypted, encryptedSize);\n\t\t\tconPacket.setData(conData.getDataPtr(), conData.getWriteIndex());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconPacket.setData((uint8*)&m_clientConnectionSignature, sizeof(uint32));\n\t\t}\n\t\tDirectSendPacket(&conPacket);\n\t}\n\tm_lastHandshakeTimestamp = prudpGetMSTimestamp();\n\tm_handshakeRetryCount++;\n}\n\nvoid prudpClient::HandleIncomingPacket(std::unique_ptr<prudpIncomingPacket> incomingPacket)\n{\n\tif (incomingPacket->type == prudpPacket::TYPE_PING)\n\t{\n\t\tif (incomingPacket->flags & prudpPacket::FLAG_ACK)\n\t\t{\n\t\t\t// ack for our ping packet\n\t\t\tif (incomingPacket->flags & prudpPacket::FLAG_NEED_ACK)\n\t\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Received unexpected ping packet with both ACK and NEED_ACK set\");\n\t\t\tif (m_unacknowledgedPingCount > 0)\n\t\t\t{\n\t\t\t\tif (incomingPacket->sequenceId == m_outgoingSequenceId_ping)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Received ping packet ACK (unacknowledged count: {})\", m_unacknowledgedPingCount);\n\t\t\t\t\tm_unacknowledgedPingCount = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Received ping packet ACK with wrong sequenceId (expected: {}, received: {})\", m_outgoingSequenceId_ping, incomingPacket->sequenceId);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Received ping packet ACK which we dont need\");\n\t\t\t}\n\t\t}\n\t\telse if (incomingPacket->flags & prudpPacket::FLAG_NEED_ACK)\n\t\t{\n\t\t\t// other side is asking for ping ack\n\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Received ping packet with NEED_ACK set. Sending ACK back\");\n\t\t\tprudpPacket ackPacket(&m_streamSettings, m_srcVPort, m_dstVPort, prudpPacket::TYPE_PING, prudpPacket::FLAG_ACK, this->m_clientSessionId, incomingPacket->sequenceId, 0);\n\t\t\tif(!incomingPacket->packetData.empty())\n\t\t\t\tackPacket.setData(incomingPacket->packetData.data(), incomingPacket->packetData.size());\n\t\t\tDirectSendPacket(&ackPacket);\n\t\t}\n\t\treturn;\n\t}\n\telse if (incomingPacket->type == prudpPacket::TYPE_SYN)\n\t{\n\t\t// syn packet from server is expected to have ACK set\n\t\tif (!(incomingPacket->flags & prudpPacket::FLAG_ACK))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"[PRUDP] Received SYN packet without ACK flag set\"); // always log this\n\t\t\treturn;\n\t\t}\n\t\tif (m_hasSynAck || !incomingPacket->hasData || incomingPacket->packetData.size() != 4)\n\t\t{\n\t\t\t// syn already acked or not a valid syn packet\n\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Received unexpected SYN packet\");\n\t\t\treturn;\n\t\t}\n\t\tm_hasSynAck = true;\n\t\tthis->m_serverConnectionSignature = *(uint32*)&incomingPacket->packetData.front();\n\t\t// generate client session id and connection signature\n\t\tthis->m_clientSessionId = prudp_generateRandomU8();\n\t\tthis->m_clientConnectionSignature = prudp_generateRandomU32();\n\t\t// send con packet\n\t\tm_handshakeRetryCount = 0;\n\t\tSendCurrentHandshakePacket();\n\t\treturn;\n\t}\n\telse if (incomingPacket->type == prudpPacket::TYPE_CON)\n\t{\n\t\tif (!m_hasSynAck || m_hasConAck)\n\t\t{\n\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Received unexpected CON packet\");\n\t\t\treturn;\n\t\t}\n\t\t// make sure the packet has the ACK flag set\n\t\tif (!(incomingPacket->flags & prudpPacket::FLAG_ACK))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"[PRUDP] Received CON packet without ACK flag set\");\n\t\t\treturn;\n\t\t}\n\t\tm_hasConAck = true;\n\t\tm_handshakeRetryCount = 0;\n\t\tcemu_assert_debug(m_currentConnectionState == ConnectionState::Connecting);\n\t\t// connected!\n\t\tm_lastPingTimestamp = prudpGetMSTimestamp();\n\t\tcemu_assert_debug(m_serverSessionId == 0);\n\t\tm_serverSessionId = incomingPacket->sessionId;\n\t\tm_currentConnectionState = ConnectionState::Connected;\n\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Connection established. ClientSession {:02x} ServerSession {:02x}\", m_clientSessionId, m_serverSessionId);\n\t\treturn;\n\t}\n\telse if (incomingPacket->type == prudpPacket::TYPE_DATA)\n\t{\n\t\t// handle ACK\n\t\tif (incomingPacket->flags & prudpPacket::FLAG_ACK)\n\t\t{\n\t\t\tAcknowledgePacket(incomingPacket->sequenceId);\n\t\t\tif(!incomingPacket->packetData.empty())\n\t\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Received ACK data packet with payload\");\n\t\t\treturn;\n\t\t}\n\t\t// send ack back if requested\n\t\tif (incomingPacket->flags & prudpPacket::FLAG_NEED_ACK)\n\t\t{\n\t\t\tprudpPacket ackPacket(&m_streamSettings, m_srcVPort, m_dstVPort, prudpPacket::TYPE_DATA, prudpPacket::FLAG_ACK, this->m_clientSessionId, incomingPacket->sequenceId, 0);\n\t\t\tDirectSendPacket(&ackPacket);\n\t\t}\n\t\t// skip data packets without payload\n\t\tif (incomingPacket->packetData.empty())\n\t\t\treturn;\n\t\t// verify sequence id\n\t\tuint16 seqDist = incomingPacket->sequenceId - m_incomingSequenceId;\n\t\tif (seqDist >= 0xC000)\n\t\t{\n\t\t\t// outdated\n\t\t\treturn;\n\t\t}\n\t\t// check if packet is already queued\n\t\tfor (auto& it : m_incomingPacketQueue)\n\t\t{\n\t\t\tif (it->sequenceId == incomingPacket->sequenceId)\n\t\t\t{\n\t\t\t\t// already queued (should check other values too, like packet type?)\n\t\t\t\tcemuLog_log(LogType::PRUDP, \"Duplicate PRUDP packet received\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// put into ordered receive queue\n\t\tSortIncomingDataPacket(std::move(incomingPacket));\n\t}\n\telse if (incomingPacket->type == prudpPacket::TYPE_DISCONNECT)\n\t{\n\t\tm_currentConnectionState = ConnectionState::Disconnected;\n\t\treturn;\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Received unknown packet type\");\n\t}\n}\n\nbool prudpClient::Update()\n{\n\tif (m_currentConnectionState == ConnectionState::Disconnected)\n\t\treturn false;\n\tuint32 currentTimestamp = prudpGetMSTimestamp();\n\t// check for incoming packets\n\tuint8 receiveBuffer[4096];\n\twhile (true)\n\t{\n\t\tsockaddr receiveFrom = {0};\n\t\tsocklen_t receiveFromLen = sizeof(receiveFrom);\n\t\tsint32 r = recvfrom(m_socketUdp, (char*)receiveBuffer, sizeof(receiveBuffer), 0, &receiveFrom, &receiveFromLen);\n\t\tif (r >= 0)\n\t\t{\n\t\t\t// todo: Verify sender (receiveFrom)\n\t\t\t// calculate packet size\n\t\t\tsint32 pIdx = 0;\n\t\t\twhile (pIdx < r)\n\t\t\t{\n\t\t\t\tsint32 packetLength = prudpPacket::calculateSizeFromPacketData(receiveBuffer + pIdx, r - pIdx);\n\t\t\t\tif (packetLength <= 0 || (pIdx + packetLength) > r)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"[PRUDP] Invalid packet length\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tauto incomingPacket = std::make_unique<prudpIncomingPacket>(&m_streamSettings, receiveBuffer + pIdx, packetLength);\n\t\t\t\tpIdx += packetLength;\n\t\t\t\tif (incomingPacket->hasError())\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"[PRUDP] Packet error\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (incomingPacket->type != prudpPacket::TYPE_CON && incomingPacket->sessionId != m_serverSessionId)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Invalid session id\");\n\t\t\t\t\tcontinue; // different session\n\t\t\t\t}\n\t\t\t\tHandleIncomingPacket(std::move(incomingPacket));\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tbreak;\n\t}\n\t// check for ack timeouts\n\tfor (auto& it : m_dataPacketsWithAckReq)\n\t{\n\t\tif ((currentTimestamp - it.lastRetryTimestamp) >= 2300)\n\t\t{\n\t\t\tif (it.retryCount >= 7)\n\t\t\t{\n\t\t\t\t// after too many retries consider the connection dead\n\t\t\t\tm_currentConnectionState = ConnectionState::Disconnected;\n\t\t\t}\n\t\t\t// resend\n\t\t\tDirectSendPacket(it.packet);\n\t\t\tit.lastRetryTimestamp = currentTimestamp;\n\t\t\tit.retryCount++;\n\t\t}\n\t}\n\tif (m_currentConnectionState == ConnectionState::Connecting)\n\t{\n\t\t// check if we need to resend SYN or CON\n\t\tuint32 timeSinceLastHandshake = currentTimestamp - m_lastHandshakeTimestamp;\n\t\tif (timeSinceLastHandshake >= 1200)\n\t\t{\n\t\t\tif (m_handshakeRetryCount >= 5)\n\t\t\t{\n\t\t\t\t// too many retries, assume the other side doesn't listen\n\t\t\t\tm_currentConnectionState = ConnectionState::Disconnected;\n\t\t\t\tcemuLog_log(LogType::PRUDP, \"PRUDP: Failed to connect\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tSendCurrentHandshakePacket();\n\t\t}\n\t}\n\telse if (m_currentConnectionState == ConnectionState::Connected)\n\t{\n\t\t// handle pings\n\t\tif (m_unacknowledgedPingCount != 0) // counts how many times we sent a ping packet (for the current sequenceId) without receiving an ack\n\t\t{\n\t\t\t// we are waiting for the ack of the previous ping, but it hasn't arrived yet so send another ping packet\n\t\t\tif ((currentTimestamp - m_lastPingTimestamp) >= 1500)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Resending ping packet (no ack received)\");\n\t\t\t\tif (m_unacknowledgedPingCount >= 10)\n\t\t\t\t{\n\t\t\t\t\t// too many unacknowledged pings, assume the connection is dead\n\t\t\t\t\tm_currentConnectionState = ConnectionState::Disconnected;\n\t\t\t\t\tcemuLog_log(LogType::PRUDP, \"PRUDP: Connection did not receive a ping response in a while. Assuming disconnect\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t// resend the ping packet\n\t\t\t\tprudpPacket pingPacket(&m_streamSettings, m_srcVPort, m_dstVPort, prudpPacket::TYPE_PING, prudpPacket::FLAG_NEED_ACK, this->m_clientSessionId, this->m_outgoingSequenceId_ping, m_serverConnectionSignature);\n\t\t\t\tDirectSendPacket(&pingPacket);\n\t\t\t\tm_unacknowledgedPingCount++;\n\t\t\t\tm_lastPingTimestamp = currentTimestamp;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((currentTimestamp - m_lastPingTimestamp) >= 20000)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::PRUDP, \"[PRUDP] Sending new ping packet with sequenceId {}\", this->m_outgoingSequenceId_ping + 1);\n\t\t\t\t// start a new ping packet with a new sequenceId. Note that ping packets have their own sequenceId and acknowledgement happens by manually comparing the incoming ping ACK against the last sent sequenceId\n\t\t\t\t// only one unacknowledged ping packet can be in flight at a time. We will resend the same ping packet until we receive an ack\n\t\t\t\tm_outgoingSequenceId_ping++; // increment before sending. The first ping has a sequenceId of 1\n\t\t\t\tprudpPacket pingPacket(&m_streamSettings, m_srcVPort, m_dstVPort, prudpPacket::TYPE_PING, prudpPacket::FLAG_NEED_ACK, this->m_clientSessionId, this->m_outgoingSequenceId_ping, m_serverConnectionSignature);\n\t\t\t\tDirectSendPacket(&pingPacket);\n\t\t\t\tm_unacknowledgedPingCount++;\n\t\t\t\tm_lastPingTimestamp = currentTimestamp;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nvoid prudpClient::DirectSendPacket(prudpPacket* packet)\n{\n\tuint8 packetBuffer[prudpPacket::PACKET_RAW_SIZE_MAX];\n\tsint32 len = packet->buildData(packetBuffer, prudpPacket::PACKET_RAW_SIZE_MAX);\n\tsockaddr_in destAddr;\n\tdestAddr.sin_family = AF_INET;\n\tdestAddr.sin_port = htons(m_dstPort);\n\tdestAddr.sin_addr.s_addr = m_dstIp;\n\tsendto(m_socketUdp, (const char*)packetBuffer, len, 0, (const sockaddr*)&destAddr, sizeof(destAddr));\n}\n\nvoid prudpClient::QueuePacket(prudpPacket* packet)\n{\n\tcemu_assert_debug(packet->GetType() == prudpPacket::TYPE_DATA); // only data packets should be queued\n\tif (packet->requiresAck())\n\t{\n\t\t// remember this packet until we receive the ack\n\t\tm_dataPacketsWithAckReq.emplace_back(packet, prudpGetMSTimestamp());\n\t\tDirectSendPacket(packet);\n\t}\n\telse\n\t{\n\t\tDirectSendPacket(packet);\n\t\tdelete packet;\n\t}\n}\n\nvoid prudpClient::SendDatagram(uint8* input, sint32 length, bool reliable)\n{\n\tcemu_assert_debug(reliable); // non-reliable packets require correct sequenceId handling and testing\n\tcemu_assert_debug(m_hasSynAck && m_hasConAck); // cant send data packets before we are connected\n\tif (length >= 0x300)\n\t{\n\t\tcemuLog_logOnce(LogType::Force, \"PRUDP: Datagram too long. Fragmentation not implemented yet\");\n\t}\n\t// single fragment data packet\n\tuint16 flags = prudpPacket::FLAG_NEED_ACK;\n\tif (reliable)\n\t\tflags |= prudpPacket::FLAG_RELIABLE;\n\tprudpPacket* packet = new prudpPacket(&m_streamSettings, m_srcVPort, m_dstVPort, prudpPacket::TYPE_DATA, flags, m_clientSessionId, m_outgoingReliableSequenceId, 0);\n\tif (reliable)\n\t\tm_outgoingReliableSequenceId++;\n\tpacket->setFragmentIndex(0);\n\tpacket->setData(input, length);\n\tQueuePacket(packet);\n}\n\nsint32 prudpClient::ReceiveDatagram(std::vector<uint8>& outputBuffer)\n{\n\toutputBuffer.clear();\n\tif (m_incomingPacketQueue.empty())\n\t\treturn -1;\n\tprudpIncomingPacket* frontPacket = m_incomingPacketQueue[0].get();\n\tif (frontPacket->sequenceId != this->m_incomingSequenceId)\n\t\treturn -1;\n\tif (frontPacket->fragmentIndex == 0)\n\t{\n\t\t// single-fragment packet\n\t\t// decrypt\n\t\tfrontPacket->decrypt();\n\t\t// read data\n\t\tif (!frontPacket->packetData.empty())\n\t\t{\n\t\t\t// to conserve memory we will also shrink the buffer if it was previously extended beyond 32KB\n\t\t\tconstexpr size_t BUFFER_TARGET_SIZE = 1024 * 32;\n\t\t\tif (frontPacket->packetData.size() < BUFFER_TARGET_SIZE && outputBuffer.capacity() > BUFFER_TARGET_SIZE)\n\t\t\t{\n\t\t\t\toutputBuffer.resize(BUFFER_TARGET_SIZE);\n\t\t\t\toutputBuffer.shrink_to_fit();\n\t\t\t\toutputBuffer.clear();\n\t\t\t}\n\t\t\t// write packet data to output buffer\n\t\t\tcemu_assert_debug(outputBuffer.empty());\n\t\t\toutputBuffer.insert(outputBuffer.end(), frontPacket->packetData.begin(), frontPacket->packetData.end());\n\t\t}\n\t\tm_incomingPacketQueue.erase(m_incomingPacketQueue.begin());\n\t\t// advance expected sequence id\n\t\tthis->m_incomingSequenceId++;\n\t\treturn (sint32)outputBuffer.size();\n\t}\n\telse\n\t{\n\t\t// multi-fragment packet\n\t\tif (frontPacket->fragmentIndex != 1)\n\t\t\treturn -1; // first packet of the chain not received yet\n\t\t// verify chain\n\t\tsint32 packetIndex = 1;\n\t\tsint32 chainLength = -1; // if full chain found, set to count of packets\n\t\tfor (sint32 i = 1; i < m_incomingPacketQueue.size(); i++)\n\t\t{\n\t\t\tuint8 itFragmentIndex = m_incomingPacketQueue[packetIndex]->fragmentIndex;\n\t\t\t// sequence id must increase by 1 for every packet\n\t\t\tif (m_incomingPacketQueue[packetIndex]->sequenceId != (m_incomingSequenceId + i))\n\t\t\t\treturn -1; // missing packets\n\t\t\t// last fragment in chain is marked by fragment index 0\n\t\t\tif (itFragmentIndex == 0)\n\t\t\t{\n\t\t\t\tchainLength = i + 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tpacketIndex++;\n\t\t}\n\t\tif (chainLength < 1)\n\t\t\treturn -1; // chain not complete\n\t\t// extract data from packet chain\n\t\tcemu_assert_debug(outputBuffer.empty());\n\t\tfor (sint32 i = 0; i < chainLength; i++)\n\t\t{\n\t\t\tprudpIncomingPacket* incomingPacket = m_incomingPacketQueue[i].get();\n\t\t\tincomingPacket->decrypt();\n\t\t\toutputBuffer.insert(outputBuffer.end(), incomingPacket->packetData.begin(), incomingPacket->packetData.end());\n\t\t}\n\t\t// remove packets from queue\n\t\tm_incomingPacketQueue.erase(m_incomingPacketQueue.begin(), m_incomingPacketQueue.begin() + chainLength);\n\t\tm_incomingSequenceId += chainLength;\n\t\treturn (sint32)outputBuffer.size();\n\t}\n\treturn -1;\n}\n"
  },
  {
    "path": "src/Cemu/nex/prudp.h",
    "content": "#pragma once\n#include \"nexTypes.h\"\n#include \"Common/socket.h\"\n\n#define RC4_N 256\n\nstruct RC4Ctx\n{\n\tunsigned char S[RC4_N];\n\tint i;\n\tint j;\n};\n\nvoid RC4_initCtx(RC4Ctx* rc4Ctx, const char* key);\nvoid RC4_initCtx(RC4Ctx* rc4Ctx, unsigned char* key, int keyLen);\nvoid RC4_transform(RC4Ctx* rc4Ctx, unsigned char* input, int len, unsigned char* output);\n\nstruct prudpStreamSettings\n{\n\tuint8 checksumBase; // calculated from key\n\tuint8 accessKeyDigest[16]; // MD5 hash of key\n\tRC4Ctx rc4Client;\n\tRC4Ctx rc4Server;\n};\n\nstruct prudpStationUrl\n{\n\tuint32 ip;\n\tuint16 port;\n\tsint32 cid;\n\tsint32 pid;\n\tsint32 sid;\n\tsint32 stream;\n\tsint32 type;\n};\n\nstruct prudpAuthServerInfo\n{\n\tuint32 userPid;\n\tuint8 secureKey[16];\n\tuint8 kerberosKey[16];\n\tuint8 secureTicket[1024];\n\tsint32 secureTicketLength;\n\tprudpStationUrl server;\n};\n\nclass prudpPacket\n{\npublic:\n\tstatic const int PACKET_RAW_SIZE_MAX = 500;\n\n\tstatic const int TYPE_SYN = 0;\n\tstatic const int TYPE_CON = 1;\n\tstatic const int TYPE_DATA = 2;\n\tstatic const int TYPE_DISCONNECT = 3;\n\tstatic const int TYPE_PING = 4;\n\n\tstatic const int STREAM_TYPE_SECURE = 0xA;\n\n\tstatic const int FLAG_ACK = 0x1;\n\tstatic const int FLAG_RELIABLE = 0x2; // if this flag is set, increase sequenceId\n\tstatic const int FLAG_NEED_ACK = 0x4;\n\tstatic const int FLAG_HAS_SIZE = 0x8;\n\n\tstatic sint32 calculateSizeFromPacketData(uint8* data, sint32 length);\n\n\tprudpPacket(prudpStreamSettings* streamSettings, uint8 src, uint8 dst, uint8 type, uint16 flags, uint8 sessionId, uint16 sequenceId, uint32 packetSignature);\n\tbool requiresAck();\n\tvoid setData(uint8* data, sint32 length);\n\tvoid setFragmentIndex(uint8 fragmentIndex);\n\tsint32 buildData(uint8* output, sint32 maxLength);\n\tuint8 GetType() const { return type; }\n\tuint16 GetSequenceId() const { return m_sequenceId; }\n\nprivate:\n\tuint32 packetSignature();\n\n\tuint8 calculateChecksum(uint8* data, sint32 length);\n\nprivate:\n\tuint8 src;\n\tuint8 dst;\n\tuint8 type;\n\tuint8 fragmentIndex;\n\tuint16 flags;\n\tuint8 sessionId;\n\tuint32 specifiedPacketSignature;\n\tprudpStreamSettings* streamSettings;\n\tstd::vector<uint8> packetData;\n\tbool isEncrypted;\n\tuint16 m_sequenceId{0};\n\n};\n\nclass prudpIncomingPacket\n{\npublic:\n\tprudpIncomingPacket(prudpStreamSettings* streamSettings, uint8* data, sint32 length);\n\n\tbool hasError();\n\n\tuint8 calculateChecksum(uint8* data, sint32 length);\n\tvoid decrypt();\n\nprivate:\n\tprudpIncomingPacket();\n\npublic:\n\t// prudp header\n\tuint8 src;\n\tuint8 dst;\n\tuint16 flags;\n\tuint8 type;\n\tuint8 sessionId;\n\tuint32 packetSignature;\n\tuint16 sequenceId;\n\tuint8 fragmentIndex;\n\tbool hasData = false;\n\tstd::vector<uint8> packetData;\n\nprivate:\n\tbool isInvalid = false;\n\tprudpStreamSettings* streamSettings = nullptr;\n};\n\nclass prudpClient\n{\n\tstruct PacketWithAckRequired\n\t{\n\t\tPacketWithAckRequired(prudpPacket* packet, uint32 initialSendTimestamp) :\n\t\t\tpacket(packet), initialSendTimestamp(initialSendTimestamp), lastRetryTimestamp(initialSendTimestamp) { }\n\t\tprudpPacket* packet;\n\t\tuint32 initialSendTimestamp;\n\t\tuint32 lastRetryTimestamp;\n\t\tsint32 retryCount{0};\n\t};\npublic:\n\tenum class ConnectionState : uint8\n\t{\n\t  Connecting,\n\t  Connected,\n\t  Disconnected\n  };\n\n\tprudpClient(uint32 dstIp, uint16 dstPort, const char* key);\n\tprudpClient(uint32 dstIp, uint16 dstPort, const char* key, prudpAuthServerInfo* authInfo);\n\t~prudpClient();\n\n\tbool IsConnected() const { return m_currentConnectionState == ConnectionState::Connected; }\n\tConnectionState GetConnectionState() const { return m_currentConnectionState; }\n\tuint16 GetSourcePort() const { return m_srcPort; }\n\n\tbool Update(); // update connection state and check for incoming packets. Returns true if ReceiveDatagram() should be called\n\n\tsint32 ReceiveDatagram(std::vector<uint8>& outputBuffer);\n\tvoid SendDatagram(uint8* input, sint32 length, bool reliable = true);\n\nprivate:\n\tprudpClient();\n\n\tvoid HandleIncomingPacket(std::unique_ptr<prudpIncomingPacket> incomingPacket);\n\tvoid DirectSendPacket(prudpPacket* packet);\n\tsint32 KerberosEncryptData(uint8* input, sint32 length, uint8* output);\n\tvoid QueuePacket(prudpPacket* packet);\n\n\tvoid AcknowledgePacket(uint16 sequenceId);\n\tvoid SortIncomingDataPacket(std::unique_ptr<prudpIncomingPacket> incomingPacket);\n\n\tvoid SendCurrentHandshakePacket();\n\nprivate:\n\tuint16 m_srcPort;\n\tuint32 m_dstIp;\n\tuint16 m_dstPort;\n\tuint8 m_srcVPort;\n\tuint8 m_dstVPort;\n\tprudpStreamSettings m_streamSettings;\n\tstd::vector<PacketWithAckRequired> m_dataPacketsWithAckReq;\n\tstd::vector<std::unique_ptr<prudpIncomingPacket>> m_incomingPacketQueue;\n\n\t// connection handshake state\n\tbool m_hasSynAck{false};\n\tbool m_hasConAck{false};\n\tuint32 m_lastHandshakeTimestamp{0};\n\tuint8 m_handshakeRetryCount{0};\n\n\t// connection\n\tConnectionState m_currentConnectionState;\n\tuint32 m_serverConnectionSignature;\n\tuint32 m_clientConnectionSignature;\n\tuint32 m_lastPingTimestamp;\n\n\tuint16 m_outgoingReliableSequenceId{2}; // 1 is reserved for CON\n\tuint16 m_incomingSequenceId;\n\n\tuint16 m_outgoingSequenceId_ping{0};\n\tuint8 m_unacknowledgedPingCount{0};\n\n\tuint8 m_clientSessionId;\n\tuint8 m_serverSessionId;\n\n\t// secure\n\tbool m_isSecureConnection{false};\n\tprudpAuthServerInfo m_authInfo;\n\n\t// socket\n\tSOCKET m_socketUdp;\n};\n\nuint32 prudpGetMSTimestamp();"
  },
  {
    "path": "src/Common/CMakeLists.txt",
    "content": "add_library(CemuCommon \n  betype.h\n  cpu_features.cpp\n  cpu_features.h\n  enumFlags.h\n  ExceptionHandler/ExceptionHandler.cpp\n  ExceptionHandler/ExceptionHandler.h\n  FileStream.h\n  GLInclude/glext.h\n  GLInclude/glFunctions.h\n  GLInclude/GLInclude.h\n  GLInclude/glxext.h\n  GLInclude/khrplatform.h\n  GLInclude/wglext.h\n  MemPtr.h\n  platform.h\n  precompiled.cpp\n  precompiled.h\n  socket.h\n  StackAllocator.h\n  SysAllocator.cpp\n  SysAllocator.h\n  CafeString.h\n  version.h\n)\n\nset_property(TARGET CemuCommon PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\nif(WIN32)\n\ttarget_sources(CemuCommon PRIVATE\n\t\twindows/platform.cpp\n\t\twindows/platform.h\n\t\twindows/FileStream_win32.cpp\n\t\tExceptionHandler/ExceptionHandler_win32.cpp\n\t)\nelse()\ntarget_sources(CemuCommon\nPRIVATE\n    unix/date.h\n    unix/fast_float.h\n    unix/platform.cpp\n    unix/platform.h\n    unix/FileStream_unix.cpp\n    unix/FileStream_unix.h\n    ExceptionHandler/ExceptionHandler_posix.cpp\n)\nendif()\n\nif(LINUX)\n\ttarget_sources(CemuCommon PRIVATE\n\t\tExceptionHandler/ELFSymbolTable.cpp\n\t\tExceptionHandler/ELFSymbolTable.h\n\t)\nendif()\n\n# All the targets wanting to use the precompiled.h header\n# have to link to CemuCommon\ntarget_precompile_headers(CemuCommon PUBLIC precompiled.h)\ntarget_include_directories(CemuCommon PUBLIC \"../\")\n\ntarget_link_libraries(CemuCommon PRIVATE\n\tBoost::nowide\n\tBoost::filesystem\n\tglm::glm\n)\n\nif (UNIX AND NOT APPLE)\n\ttarget_link_libraries(CemuCommon PRIVATE X11::X11 X11::Xrender X11::Xutil)\nendif()\n\n# PUBLIC because:\n# - boost/predef/os.h is included in platform.h\n# - fmt/core.h is included in precompiled.h\ntarget_link_libraries(CemuCommon PUBLIC Boost::headers fmt::fmt)\n"
  },
  {
    "path": "src/Common/CafeString.h",
    "content": "#pragma once\n#include \"betype.h\"\n#include \"util/helpers/StringHelpers.h\"\n\n/* Helper classes to represent CafeOS strings in emulated memory */\ntemplate <size_t N>\nclass CafeString // fixed buffer size, null-terminated, PPC char\n{\n  public:\n\tconstexpr static size_t Size()\n\t{\n\t\treturn N;\n\t}\n\n\t// checks whether the string and a null terminator can fit into the buffer\n\tbool CanHoldString(std::string_view sv) const\n\t{\n\t\treturn sv.size() < N;\n\t}\n\n\tbool assign(std::string_view sv)\n\t{\n\t\tif (sv.size() >= N)\n\t\t{\n\t\t\tmemcpy(data, sv.data(), N-1);\n\t\t\tdata[N-1] = '\\0';\n\t\t\treturn false;\n\t\t}\n\t\tmemcpy(data, sv.data(), sv.size());\n\t\tdata[sv.size()] = '\\0';\n\t\treturn true;\n\t}\n\n\tvoid Copy(CafeString<N>& other)\n\t{\n\t\tmemcpy(data, other.data, N);\n\t}\n\n\tbool empty() const\n\t{\n\t\treturn data[0] == '\\0';\n\t}\n\n\tconst char* c_str() const\n\t{\n\t\treturn (const char*)data;\n\t}\n\n\tvoid ClearAllBytes()\n\t{\n\t\tmemset(data, 0, N);\n\t}\n\n\tauto operator<=>(const CafeString<N>& other) const\n\t{\n\t\tfor (size_t i = 0; i < N; i++)\n\t\t{\n\t\t\tif (data[i] != other.data[i])\n\t\t\t\treturn data[i] <=> other.data[i];\n\t\t\tif (data[i] == '\\0')\n\t\t\t\treturn std::strong_ordering::equal;\n\t\t}\n\t\treturn std::strong_ordering::equal;\n\t}\n\n\tbool operator==(const CafeString<N>& other) const\n\t{\n\t\tfor (size_t i = 0; i < N; i++)\n\t\t{\n\t\t\tif (data[i] != other.data[i])\n\t\t\t\treturn false;\n\t\t\tif (data[i] == '\\0')\n\t\t\t\treturn true;\n\t\t}\n\t\treturn true;\n\t}\n\n\tuint8be data[N];\n};\n\ntemplate <size_t N>\nclass CafeWideString // fixed buffer size, null-terminated, PPC wchar_t (16bit big-endian)\n{\n  public:\n\tbool assign(const uint16be* input)\n\t{\n\t\tsize_t i = 0;\n\t\twhile(input[i])\n\t\t{\n\t\t\tif(i >= N-1)\n\t\t\t{\n\t\t\t\tdata[N-1] = 0;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdata[i] = input[i];\n\t\t\ti++;\n\t\t}\n\t\tdata[i] = 0;\n\t\treturn true;\n\t}\n\n\tbool assignFromUTF8(std::string_view sv)\n\t{\n\t\tstd::vector<uint16be> beStr = StringHelpers::FromUtf8(sv);\n\t\tif(beStr.size() > N-1)\n\t\t{\n\t\t\tmemcpy(data, beStr.data(), (N-1)*sizeof(uint16be));\n\t\t\tdata[N-1] = 0;\n\t\t\treturn false;\n\t\t}\n\t\tmemcpy(data, beStr.data(), beStr.size()*sizeof(uint16be));\n\t\tdata[beStr.size()] = '\\0';\n\t\treturn true;\n\t}\n\n\tuint16be data[N];\n};\n\nnamespace CafeStringHelpers\n{\n\tstatic uint32 Length(const uint16be* input, uint32 maxLength)\n\t{\n\t\tuint32 i = 0;\n\t\twhile(input[i] && i < maxLength)\n\t\t\ti++;\n\t\treturn i;\n\t}\n};\n"
  },
  {
    "path": "src/Common/ExceptionHandler/ELFSymbolTable.cpp",
    "content": "#include \"Common/ExceptionHandler/ELFSymbolTable.h\"\n#include \"Common/FileStream.h\"\n#include <sys/mman.h>\n#include <fcntl.h>\n\nuint16 ELFSymbolTable::FindSection(int type, const std::string_view& name)\n{\n\tif (!shTable || !shStrTable)\n\t\treturn 0;\n\n\tfor (uint16 i = 0; i < header->e_shnum; ++i)\n\t{\n\t\tauto& entry = shTable[i];\n\t\tif(entry.sh_type == type && std::string_view{&shStrTable[entry.sh_name]} == name)\n\t\t{\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn 0;\n}\n\nvoid* ELFSymbolTable::SectionPointer(uint16 index)\n{\n\treturn SectionPointer(shTable[index]);\n}\n\nvoid* ELFSymbolTable::SectionPointer(const Elf64_Shdr& section)\n{\n\treturn (void*)(mappedExecutable + section.sh_offset);\n}\n\nELFSymbolTable::ELFSymbolTable()\n{\n\t// create file handle\n\tint fd = open(\"/proc/self/exe\", O_RDONLY);\n\tif (!fd)\n\t\treturn;\n\n\t// retrieve file size.\n\tstruct stat filestats;\n\tif (fstat(fd, &filestats))\n\t{\n\t\tclose(fd);\n\t\treturn;\n\t}\n\tmappedExecutableSize = filestats.st_size;\n\n\t// attempt to map the file\n\tmappedExecutable = (uint8*)(mmap(nullptr, mappedExecutableSize, PROT_READ, MAP_PRIVATE, fd, 0));\n\tclose(fd);\n\tif (!mappedExecutable)\n\t\treturn;\n\n\t// verify signature\n\theader = (Elf64_Ehdr*)(mappedExecutable);\n\tconstexpr uint8 signature[] = {0x7f, 0x45, 0x4c, 0x46};\n\tfor (size_t i = 0; i < 4; ++i)\n\t{\n\t\tif (signature[i] != header->e_ident[i])\n\t\t{\n\t\t\treturn;\n\t\t}\n\t}\n\n\tshTable = (Elf64_Shdr*)(mappedExecutable + header->e_shoff);\n\n\tElf64_Shdr& shStrn = shTable[header->e_shstrndx];\n\tshStrTable = (char*)(mappedExecutable + shStrn.sh_offset);\n\n\tstrTable = (char*)SectionPointer(FindSection(SHT_STRTAB, \".strtab\"));\n\n\tElf64_Shdr& symTabShdr = shTable[FindSection(SHT_SYMTAB, \".symtab\")];\n\tif (symTabShdr.sh_entsize == 0)\n\t\treturn;\n\n\tsymTableLen = symTabShdr.sh_size / symTabShdr.sh_entsize;\n\tsymTable = (Elf64_Sym*)(SectionPointer(symTabShdr));\n}\n\nELFSymbolTable::~ELFSymbolTable()\n{\n\tif (mappedExecutable)\n\t\tmunmap(mappedExecutable, mappedExecutableSize);\n}\n\nstd::string_view ELFSymbolTable::OffsetToSymbol(uint64 ptr, uint64& fromStart) const\n{\n\tif(!symTable || !strTable)\n\t{\n\t\tfromStart = -1;\n\t\treturn {};\n\t}\n\n\tfor (auto entry = symTable+1; entry < symTable+symTableLen; ++entry)\n\t{\n\t\tif (ELF64_ST_TYPE(entry->st_info) != STT_FUNC)\n\t\t\tcontinue;\n\t\tauto begin = entry->st_value;\n\t\tauto size = entry->st_size;\n\t\tif(ptr >= begin && ptr < begin+size)\n\t\t{\n\t\t\tfromStart = ptr-begin;\n\t\t\treturn &strTable[entry->st_name];\n\t\t}\n\t}\n\tfromStart = -1;\n\treturn {};\n}\n"
  },
  {
    "path": "src/Common/ExceptionHandler/ELFSymbolTable.h",
    "content": "#pragma once\n#include <memory>\n#include <elf.h>\n\nclass ELFSymbolTable\n{\npublic:\n\tstd::string_view OffsetToSymbol(uint64 ptr, uint64& fromStart) const;\n\n\tELFSymbolTable();\n\t~ELFSymbolTable();\nprivate:\n\tuint8* mappedExecutable = nullptr;\n\tsize_t mappedExecutableSize = 0;\n\n\tElf64_Ehdr* header = nullptr;\n\n\tElf64_Shdr* shTable = nullptr;\n\tchar* shStrTable = nullptr;\n\n\tElf64_Sym* symTable = nullptr;\n\tuint64 symTableLen = 0;\n\tchar* strTable = nullptr;\n\n\tuint16 FindSection(int type, const std::string_view& name);\n\n\tvoid* SectionPointer (uint16 index);\n\tvoid* SectionPointer(const Elf64_Shdr& section);\n\n\t// ownership of mapped memory, cannot copy.\n\tELFSymbolTable(const ELFSymbolTable&) = delete;\n};\n"
  },
  {
    "path": "src/Common/ExceptionHandler/ExceptionHandler.cpp",
    "content": "#include \"config/ActiveSettings.h\"\n#include \"config/CemuConfig.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/HW/Espresso/Debugger/GDBStub.h\"\n#include \"ExceptionHandler.h\"\n\nbool crashLogCreated = false;\n\nbool CrashLog_Create()\n{\n    if (crashLogCreated)\n        return false; // only create one crashlog\n    crashLogCreated = true;\n    cemuLog_createLogFile(true);\n    CrashLog_SetOutputChannels(true, true);\n    return true;\n}\n\nstatic bool s_writeToStdErr{true};\nstatic bool s_writeToLogTxt{true};\n\nvoid CrashLog_SetOutputChannels(bool writeToStdErr, bool writeToLogTxt)\n{\n    s_writeToStdErr = writeToStdErr;\n    s_writeToLogTxt = writeToLogTxt;\n}\n\n// outputs to both stderr and log.txt\nvoid CrashLog_WriteLine(std::string_view text, bool newLine)\n{\n    if(s_writeToLogTxt)\n        cemuLog_writeLineToLog(text, false, newLine);\n    if(s_writeToStdErr)\n    {\n        fwrite(text.data(), sizeof(char), text.size(), stderr);\n        if(newLine)\n            fwrite(\"\\n\", sizeof(char), 1, stderr);\n    }\n}\n\nvoid CrashLog_WriteHeader(const char* header)\n{\n    CrashLog_WriteLine(\"-----------------------------------------\");\n    CrashLog_WriteLine(\"   \", false);\n    CrashLog_WriteLine(header);\n    CrashLog_WriteLine(\"-----------------------------------------\");\n}\n\nvoid ExceptionHandler_LogGeneralInfo()\n{\n    char dumpLine[1024];\n    // info about game\n    CrashLog_WriteLine(\"\");\n    CrashLog_WriteHeader(\"Game info\");\n    if (CafeSystem::IsTitleRunning())\n    {\n        CrashLog_WriteLine(\"Game: \", false);\n        CrashLog_WriteLine(CafeSystem::GetForegroundTitleName());\n        // title id\n        CrashLog_WriteLine(fmt::format(\"TitleId: {:016x}\", CafeSystem::GetForegroundTitleId()));\n        // rpx hash\n        sprintf(dumpLine, \"RPXHash: %08x (Update: %08x)\", CafeSystem::GetRPXHashBase(), CafeSystem::GetRPXHashUpdated());\n        CrashLog_WriteLine(dumpLine);\n    }\n    else\n    {\n        CrashLog_WriteLine(\"Not running\");\n    }\n    // info about active PPC instance:\n    CrashLog_WriteLine(\"\");\n    CrashLog_WriteHeader(\"Active PPC instance\");\n\tPPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();\n    if (hCPU)\n    {\n        OSThread_t* currentThread = coreinit::OSGetCurrentThread();\n        uint32 threadPtr = memory_getVirtualOffsetFromPointer(coreinit::OSGetCurrentThread());\n        sprintf(dumpLine, \"IP 0x%08x LR 0x%08x Thread 0x%08x\", hCPU->instructionPointer, hCPU->spr.LR, threadPtr);\n        CrashLog_WriteLine(dumpLine);\n\n        // GPR info\n        CrashLog_WriteLine(\"\");\n        auto gprs = hCPU->gpr;\n        sprintf(dumpLine, \"r0 =%08x r1 =%08x r2 =%08x r3 =%08x r4 =%08x r5 =%08x r6 =%08x r7 =%08x\", gprs[0], gprs[1], gprs[2], gprs[3], gprs[4], gprs[5], gprs[6], gprs[7]);\n        CrashLog_WriteLine(dumpLine);\n        sprintf(dumpLine, \"r8 =%08x r9 =%08x r10=%08x r11=%08x r12=%08x r13=%08x r14=%08x r15=%08x\", gprs[8], gprs[9], gprs[10], gprs[11], gprs[12], gprs[13], gprs[14], gprs[15]);\n        CrashLog_WriteLine(dumpLine);\n        sprintf(dumpLine, \"r16=%08x r17=%08x r18=%08x r19=%08x r20=%08x r21=%08x r22=%08x r23=%08x\", gprs[16], gprs[17], gprs[18], gprs[19], gprs[20], gprs[21], gprs[22], gprs[23]);\n        CrashLog_WriteLine(dumpLine);\n        sprintf(dumpLine, \"r24=%08x r25=%08x r26=%08x r27=%08x r28=%08x r29=%08x r30=%08x r31=%08x\", gprs[24], gprs[25], gprs[26], gprs[27], gprs[28], gprs[29], gprs[30], gprs[31]);\n        CrashLog_WriteLine(dumpLine);\n\n        // stack trace\n        MPTR currentStackVAddr = hCPU->gpr[1];\n        CrashLog_WriteLine(\"\");\n        CrashLog_WriteHeader(\"PPC stack trace\");\n        DebugLogStackTrace(currentThread, currentStackVAddr, true);\n\n        // stack dump\n        CrashLog_WriteLine(\"\");\n        CrashLog_WriteHeader(\"PPC stack dump\");\n        for (uint32 i = 0; i < 16; i++)\n        {\n            MPTR lineAddr = currentStackVAddr + i * 8 * 4;\n            if (memory_isAddressRangeAccessible(lineAddr, 8 * 4))\n            {\n                sprintf(dumpLine, \"[0x%08x] %08x %08x %08x %08x - %08x %08x %08x %08x\", lineAddr, memory_readU32(lineAddr + 0), memory_readU32(lineAddr + 4), memory_readU32(lineAddr + 8), memory_readU32(lineAddr + 12), memory_readU32(lineAddr + 16), memory_readU32(lineAddr + 20), memory_readU32(lineAddr + 24), memory_readU32(lineAddr + 28));\n                CrashLog_WriteLine(dumpLine);\n            }\n            else\n            {\n                sprintf(dumpLine, \"[0x%08x] ?\", lineAddr);\n                CrashLog_WriteLine(dumpLine);\n            }\n        }\n    }\n    else\n    {\n        CrashLog_WriteLine(\"Not active\");\n    }\n\n    // PPC thread log\n    CrashLog_WriteLine(\"\");\n    CrashLog_WriteHeader(\"PPC threads\");\n    if (activeThreadCount == 0)\n    {\n        CrashLog_WriteLine(\"None active\");\n    }\n    for (sint32 i = 0; i < activeThreadCount; i++)\n    {\n        MPTR threadItrMPTR = activeThread[i];\n        OSThread_t* threadItrBE = (OSThread_t*)memory_getPointerFromVirtualOffset(threadItrMPTR);\n\n        // get thread state\n        OSThread_t::THREAD_STATE threadState = threadItrBE->state;\n        const char* threadStateStr = \"UNDEFINED\";\n        if (threadItrBE->suspendCounter != 0)\n            threadStateStr = \"SUSPENDED\";\n        else if (threadState == OSThread_t::THREAD_STATE::STATE_NONE)\n            threadStateStr = \"NONE\";\n        else if (threadState == OSThread_t::THREAD_STATE::STATE_READY)\n            threadStateStr = \"READY\";\n        else if (threadState == OSThread_t::THREAD_STATE::STATE_RUNNING)\n            threadStateStr = \"RUNNING\";\n        else if (threadState == OSThread_t::THREAD_STATE::STATE_WAITING)\n            threadStateStr = \"WAITING\";\n        else if (threadState == OSThread_t::THREAD_STATE::STATE_MORIBUND)\n            threadStateStr = \"MORIBUND\";\n        // generate log line\n        uint8 affinity = threadItrBE->attr;\n        sint32 effectivePriority = threadItrBE->effectivePriority;\n        const char* threadName = \"NULL\";\n        if (!threadItrBE->threadName.IsNull())\n            threadName = threadItrBE->threadName.GetPtr();\n        sprintf(dumpLine, \"%08x Ent %08x IP %08x LR %08x %-9s Aff %d%d%d Pri %2d Name %s\", threadItrMPTR, threadItrBE->entrypoint.GetMPTR(), threadItrBE->context.srr0, _swapEndianU32(threadItrBE->context.lr), threadStateStr, (affinity >> 0) & 1, (affinity >> 1) & 1, (affinity >> 2) & 1, effectivePriority, threadName);\n        // write line to log\n        CrashLog_WriteLine(dumpLine);\n    }\n}\n"
  },
  {
    "path": "src/Common/ExceptionHandler/ExceptionHandler.h",
    "content": "#pragma once\n\nvoid ExceptionHandler_Init();\n\nbool CrashLog_Create();\nvoid CrashLog_SetOutputChannels(bool writeToStdErr, bool writeToLogTxt);\nvoid CrashLog_WriteLine(std::string_view text, bool newLine = true);\nvoid CrashLog_WriteHeader(const char* header);\n\nvoid ExceptionHandler_LogGeneralInfo();\n"
  },
  {
    "path": "src/Common/ExceptionHandler/ExceptionHandler_posix.cpp",
    "content": "#include <signal.h>\n#include <execinfo.h>\n#include <string.h>\n#include <string>\n#include \"config/CemuConfig.h\"\n#include \"util/helpers/StringHelpers.h\"\n#include \"ExceptionHandler.h\"\n\n#include \"Cafe/HW/Espresso/Debugger/GDBStub.h\"\n#include \"Cafe/HW/Espresso/Debugger/GDBBreakpoints.h\"\n\n#if BOOST_OS_LINUX\n#include \"ELFSymbolTable.h\"\n#endif\n\n#if BOOST_OS_LINUX\nvoid DemangleAndPrintBacktrace(char** backtrace, size_t size)\n{\n\tELFSymbolTable symTable;\n\tfor (char** i = backtrace; i < backtrace + size; i++)\n\t{\n\t\tstd::string_view traceLine{*i};\n\n\t\t// basic check to see if the backtrace line matches expected format\n\t\tsize_t parenthesesOpen = traceLine.find_last_of('(');\n\t\tsize_t parenthesesClose = traceLine.find_last_of(')');\n\t\tsize_t offsetPlus = traceLine.find_last_of('+');\n\t\tif (!parenthesesOpen || !parenthesesClose || !offsetPlus ||\n\t\t\t offsetPlus < parenthesesOpen || offsetPlus > parenthesesClose)\n\t\t{\n\t\t\t// fall back to default string\n            CrashLog_WriteLine(traceLine);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// attempt to resolve symbol from regular symbol table if missing from dynamic symbol table\n\t\tuint64 newOffset = -1;\n\t\tstd::string_view symbolName = traceLine.substr(parenthesesOpen+1, offsetPlus-parenthesesOpen-1);\n\t\tif (symbolName.empty())\n\t\t{\n\t\t\tuint64 symbolOffset = StringHelpers::ToInt64(traceLine.substr(offsetPlus+1,offsetPlus+1-parenthesesClose-1));\n\t\t\tsymbolName = symTable.OffsetToSymbol(symbolOffset, newOffset);\n\t\t}\n\n        CrashLog_WriteLine(traceLine.substr(0, parenthesesOpen+1), false);\n\n        CrashLog_WriteLine(boost::core::demangle(symbolName.empty() ? \"\" : symbolName.data()), false);\n\n\t\t// print relative or existing symbol offset.\n        CrashLog_WriteLine(\"+\", false);\n\t\tif (newOffset != -1)\n\t\t{\n            CrashLog_WriteLine(fmt::format(\"0x{:x}\", newOffset), false);\n            CrashLog_WriteLine(traceLine.substr(parenthesesClose));\n\t\t}\n\t\telse\n\t\t{\n            CrashLog_WriteLine(traceLine.substr(offsetPlus+1));\n\t\t}\n\t}\n}\n#endif\n\n// handle signals that would dump core, print stacktrace and then dump depending on config\nvoid handlerDumpingSignal(int sig, siginfo_t *info, void *context)\n{\n#if defined(ARCH_X86_64) && BOOST_OS_LINUX\n\t// Check for hardware breakpoints\n\tif (info->si_signo == SIGTRAP && info->si_code == TRAP_HWBKPT)\n\t{\n\t\tuint64 dr6 = _ReadDR6();\n\t\tg_gdbstub->HandleAccessException(dr6);\n\t\treturn;\n\t}\n#endif\n\n    if(!CrashLog_Create())\n        return; // give up if crashlog was already created\n\n    char* sigName = strsignal(sig);\n\tif (sigName)\n\t{\n\t\tprintf(\"%s!\\n\", sigName);\n\t}\n\telse\n\t{\n\t\t// should never be the case\n\t\tprintf(\"Unknown core dumping signal!\\n\");\n\t}\n\n\tvoid* backtraceArray[128];\n\tsize_t size;\n\n\t// get void*'s for all entries on the stack\n\tsize = backtrace(backtraceArray, 128);\n    // replace the deepest entry with the actual crash address\n#if defined(ARCH_X86_64) && BOOST_OS_LINUX > 0\n    ucontext_t *uc = (ucontext_t *)context;\n    backtraceArray[0] = (void *)uc->uc_mcontext.gregs[REG_RIP];\n#endif\n\n    CrashLog_WriteLine(fmt::format(\"Error: signal {}:\", sig));\n\n#if BOOST_OS_LINUX\n\tchar** symbol_trace = backtrace_symbols(backtraceArray, size);\n\n\tif (symbol_trace)\n\t{\n        DemangleAndPrintBacktrace(symbol_trace, size);\n\t\tfree(symbol_trace);\n\t}\n\telse\n\t{\n        CrashLog_WriteLine(\"Failed to read backtrace\");\n\t}\n#else\n\tbacktrace_symbols_fd(backtraceArray, size, STDERR_FILENO);\n#endif\n\n    std::cerr << fmt::format(\"\\nStacktrace and additional info written to:\") << std::endl;\n    std::cerr << cemuLog_GetLogFilePath().generic_string() << std::endl;\n\n    CrashLog_SetOutputChannels(false, true);\n    ExceptionHandler_LogGeneralInfo();\n    CrashLog_SetOutputChannels(true, true);\n\n\tif (GetConfig().crash_dump == CrashDump::Enabled)\n\t{\n\t\t// reset signal handler to default and re-raise signal to dump core\n\t\tsignal(sig, SIG_DFL);\n\t\traise(sig);\n\t\treturn;\n\t}\n\t// exit process ignoring all issues\n\t_Exit(1);\n}\n\nvoid handler_SIGINT(int sig)\n{\n\t/*\n\t * Received when pressing CTRL + C in a console\n\t * Ideally should be exiting cleanly after saving settings but currently\n\t * there's no clean exit pathway (at least on linux) and exiting the app\n\t * by any mean ends up with a SIGABRT from the standard library destroying\n\t * threads.\n\t */\n\t_Exit(0);\n}\n\nvoid ExceptionHandler_Init()\n{\n\tstruct sigaction action;\n\taction.sa_flags = 0;\n\tsigfillset(&action.sa_mask); // don't allow signals to be interrupted\n\n\taction.sa_handler = handler_SIGINT;\n\tsigaction(SIGINT, &action, nullptr);\n\tsigaction(SIGTERM, &action, nullptr);\n\n    action.sa_flags = SA_SIGINFO;\n    action.sa_handler = nullptr;\n\taction.sa_sigaction = handlerDumpingSignal;\n\tsigaction(SIGABRT, &action, nullptr);\n\tsigaction(SIGBUS, &action, nullptr);\n\tsigaction(SIGFPE, &action, nullptr);\n\tsigaction(SIGILL, &action, nullptr);\n\tsigaction(SIGIOT, &action, nullptr);\n\tsigaction(SIGQUIT, &action, nullptr);\n\tsigaction(SIGSEGV, &action, nullptr);\n\tsigaction(SIGSYS, &action, nullptr);\n\tsigaction(SIGTRAP, &action, nullptr);\n}\n"
  },
  {
    "path": "src/Common/ExceptionHandler/ExceptionHandler_win32.cpp",
    "content": "#include \"Common/precompiled.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"ExceptionHandler.h\"\n\n#include <Windows.h>\n#include <Dbghelp.h>\n#include <shellapi.h>\n\n#include \"config/ActiveSettings.h\"\n#include \"config/CemuConfig.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/HW/Espresso/Debugger/GDBStub.h\"\n\nLONG handleException_SINGLE_STEP(PEXCEPTION_POINTERS pExceptionInfo)\n{\n\treturn EXCEPTION_CONTINUE_SEARCH;\n}\n\n#include <boost/algorithm/string.hpp>\nBOOL CALLBACK MyMiniDumpCallback(PVOID pParam, const PMINIDUMP_CALLBACK_INPUT pInput, PMINIDUMP_CALLBACK_OUTPUT pOutput)\n{\n\tif (!pInput || !pOutput)\n\t\treturn FALSE;\n\n\tswitch (pInput->CallbackType)\n\t{\n\tcase IncludeModuleCallback:\n\tcase IncludeThreadCallback:\n\tcase ThreadCallback:\n\tcase ThreadExCallback:\n\t\treturn TRUE;\n\n\tcase ModuleCallback:\n\n\t\tif (!(pOutput->ModuleWriteFlags & ModuleReferencedByMemory))\n\t\t\tpOutput->ModuleWriteFlags &= ~ModuleWriteModule;\n\n\t\treturn TRUE;\n\t}\n\n\treturn FALSE;\n\n}\n\nbool CreateMiniDump(CrashDump dump, EXCEPTION_POINTERS* pep)\n{\n\tif (dump == CrashDump::Disabled)\n\t\treturn true;\n\n\tfs::path p = ActiveSettings::GetUserDataPath(\"crashdump\");\n\n\tstd::error_code ec;\n\tfs::create_directories(p, ec);\n\tif (ec)\n\t\treturn false;\n\n\tconst auto now = std::chrono::system_clock::now();\n\tconst auto temp_time = std::chrono::system_clock::to_time_t(now);\n\tconst auto& time = *std::gmtime(&temp_time);\n\n\tp /= fmt::format(\"crash_{:04d}{:02d}{:02d}_{:02d}{:02d}{:02d}.dmp\", 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_year, time.tm_hour, time.tm_min, time.tm_sec);\n\n\tconst auto hFile = CreateFileW(p.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);\n\tif (hFile == INVALID_HANDLE_VALUE)\n\t\treturn false;\n\n\tMINIDUMP_EXCEPTION_INFORMATION mdei;\n\tmdei.ThreadId = GetCurrentThreadId();\n\tmdei.ExceptionPointers = pep;\n\tmdei.ClientPointers = FALSE;\n\n\tMINIDUMP_CALLBACK_INFORMATION mci;\n\tmci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;\n\tmci.CallbackParam = nullptr;\n\n\tMINIDUMP_TYPE mdt;\n\tif (dump == CrashDump::Full)\n\t{\n\t\tmdt = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory |\n\t\t\tMiniDumpWithDataSegs |\n\t\t\tMiniDumpWithHandleData |\n\t\t\tMiniDumpWithFullMemoryInfo |\n\t\t\tMiniDumpWithThreadInfo |\n\t\t\tMiniDumpWithUnloadedModules);\n\t}\n\telse\n\t{\n\t\tmdt = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory);\n\t}\n\n\tconst auto result = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, mdt, &mdei, nullptr, &mci);\n\tCloseHandle(hFile);\n\treturn result != FALSE;\n}\n\nvoid DumpThreadStackTrace()\n{\n\tHANDLE process = GetCurrentProcess();\n\tSymInitialize(process, NULL, TRUE);\n\n\tchar dumpLine[1024 * 4];\n\tvoid* stack[100];\n\n\tconst unsigned short frames = CaptureStackBackTrace(0, 40, stack, NULL);\n\tSYMBOL_INFO* symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);\n\tsymbol->MaxNameLen = 255;\n\tsymbol->SizeOfStruct = sizeof(SYMBOL_INFO);\n\n    CrashLog_WriteHeader(\"Stack trace\");\n\tfor (unsigned int i = 0; i < frames; i++)\n\t{\n\t\tDWORD64 stackTraceOffset = (DWORD64)stack[i];\n\t\tSymFromAddr(process, stackTraceOffset, 0, symbol);\n\t\tsprintf(dumpLine, \"0x%016I64x \", (uint64)(size_t)stack[i]);\n\t\tcemuLog_writePlainToLog(dumpLine);\n\t\t// module name\n\t\tHMODULE stackModule;\n\t\tif (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)stackTraceOffset, &stackModule))\n\t\t{\n\t\t\tchar moduleName[512];\n\t\t\tmoduleName[0] = '\\0';\n\t\t\tGetModuleFileNameA(stackModule, moduleName, 512);\n\t\t\tsint32 moduleNameStartIndex = std::max((sint32)0, (sint32)strlen(moduleName) - 1);\n\t\t\twhile (moduleNameStartIndex > 0)\n\t\t\t{\n\t\t\t\tif (moduleName[moduleNameStartIndex] == '\\\\' || moduleName[moduleNameStartIndex] == '/')\n\t\t\t\t{\n\t\t\t\t\tmoduleNameStartIndex++;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmoduleNameStartIndex--;\n\t\t\t}\n\n\t\t\tDWORD64 moduleAddress = (DWORD64)GetModuleHandleA(moduleName);\n\t\t\tsint32 relativeOffset = 0;\n\t\t\tif (moduleAddress != 0)\n\t\t\t\trelativeOffset = stackTraceOffset - moduleAddress;\n\n\t\t\tsprintf(dumpLine, \"+0x%08x %-16s\", relativeOffset, moduleName + moduleNameStartIndex);\n\t\t\tcemuLog_writePlainToLog(dumpLine);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsprintf(dumpLine, \"+0x00000000 %-16s\", \"NULL\");\n\t\t\tcemuLog_writePlainToLog(dumpLine);\n\t\t}\n\t\t// function name\n\t\tsprintf(dumpLine, \" %s\\n\", symbol->Name);\n\t\tcemuLog_writePlainToLog(dumpLine);\n\t}\n\n\tfree(symbol);\n}\n\nvoid createCrashlog(EXCEPTION_POINTERS* e, PCONTEXT context)\n{\n    if(!CrashLog_Create())\n        return; // give up if crashlog was already created\n\n\tconst auto crash_dump = GetConfig().crash_dump.GetValue();\n\tconst auto dump_written = CreateMiniDump(crash_dump, e);\n\tif (!dump_written)\n\t\tcemuLog_writeLineToLog(fmt::format(\"couldn't write minidump {:#x}\", GetLastError()), false, true);\n\n\tchar dumpLine[1024 * 4];\n\n\t// info about Cemu version\n\tsprintf(dumpLine, \"\\nCrashlog for %s\\n\", BUILD_VERSION_WITH_NAME_STRING);\n\tcemuLog_writePlainToLog(dumpLine);\n\n\tSYSTEMTIME sysTime;\n\tGetSystemTime(&sysTime);\n\tsprintf(dumpLine, \"Date: %02d-%02d-%04d %02d:%02d:%02d\\n\\n\", (sint32)sysTime.wDay, (sint32)sysTime.wMonth, (sint32)sysTime.wYear, (sint32)sysTime.wHour, (sint32)sysTime.wMinute, (sint32)sysTime.wSecond);\n\tcemuLog_writePlainToLog(dumpLine);\n\n\tDumpThreadStackTrace();\n\t// info about exception\n\tif (e->ExceptionRecord)\n\t{\n\t\tHMODULE exceptionModule;\n\t\tif (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)(e->ExceptionRecord->ExceptionAddress), &exceptionModule))\n\t\t{\n\t\t\tchar moduleName[512];\n\t\t\tmoduleName[0] = '\\0';\n\t\t\tGetModuleFileNameA(exceptionModule, moduleName, 512);\n\t\t\tsint32 moduleNameStartIndex = std::max((sint32)0, (sint32)strlen(moduleName) - 1);\n\t\t\twhile (moduleNameStartIndex > 0)\n\t\t\t{\n\t\t\t\tif (moduleName[moduleNameStartIndex] == '\\\\' || moduleName[moduleNameStartIndex] == '/')\n\t\t\t\t{\n\t\t\t\t\tmoduleNameStartIndex++;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmoduleNameStartIndex--;\n\t\t\t}\n\t\t\tsprintf(dumpLine, \"Exception 0x%08x at 0x%I64x(+0x%I64x) in module %s\\n\", (uint32)e->ExceptionRecord->ExceptionCode, (uint64)e->ExceptionRecord->ExceptionAddress, (uint64)e->ExceptionRecord->ExceptionAddress - (uint64)exceptionModule, moduleName + moduleNameStartIndex);\n\t\t\tcemuLog_writePlainToLog(dumpLine);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsprintf(dumpLine, \"Exception 0x%08x at 0x%I64x\\n\", (uint32)e->ExceptionRecord->ExceptionCode, (uint64)e->ExceptionRecord->ExceptionAddress);\n\t\t\tcemuLog_writePlainToLog(dumpLine);\n\t\t}\n\n\t}\n\tsprintf(dumpLine, \"cemu.exe at 0x%I64x\\n\", (uint64)GetModuleHandle(NULL));\n\tcemuLog_writePlainToLog(dumpLine);\n\t// register info\n\tsprintf(dumpLine, \"\\n\");\n\tcemuLog_writePlainToLog(dumpLine);\n\tsprintf(dumpLine, \"RAX=%016I64x RBX=%016I64x RCX=%016I64x RDX=%016I64x\\n\", context->Rax, context->Rbx, context->Rcx, context->Rdx);\n\tcemuLog_writePlainToLog(dumpLine);\n\tsprintf(dumpLine, \"RSP=%016I64x RBP=%016I64x RDI=%016I64x RSI=%016I64x\\n\", context->Rsp, context->Rbp, context->Rdi, context->Rsi);\n\tcemuLog_writePlainToLog(dumpLine);\n\tsprintf(dumpLine, \"R8 =%016I64x R9 =%016I64x R10=%016I64x R11=%016I64x\\n\", context->R8, context->R9, context->R10, context->R11);\n\tcemuLog_writePlainToLog(dumpLine);\n\tsprintf(dumpLine, \"R12=%016I64x R13=%016I64x R14=%016I64x R15=%016I64x\\n\", context->R12, context->R13, context->R14, context->R15);\n\tcemuLog_writePlainToLog(dumpLine);\n\n    CrashLog_SetOutputChannels(false, true);\n    ExceptionHandler_LogGeneralInfo();\n    CrashLog_SetOutputChannels(true, true);\n\n\tcemuLog_waitForFlush();\n\n\t// save log with the dump\n\tif (dump_written && crash_dump != CrashDump::Disabled)\n\t{\n\t\tconst auto now = std::chrono::system_clock::now();\n\t\tconst auto temp_time = std::chrono::system_clock::to_time_t(now);\n\t\tconst auto& time = *std::gmtime(&temp_time);\n\n\t\tfs::path p = ActiveSettings::GetUserDataPath(\"crashdump\");\n\t\tp /= fmt::format(\"log_{:04d}{:02d}{:02d}_{:02d}{:02d}{:02d}.txt\", 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_year, time.tm_hour, time.tm_min, time.tm_sec);\n\n\t\tstd::error_code ec;\n\t\tfs::copy_file(ActiveSettings::GetUserDataPath(\"log.txt\"), p, ec);\n\t}\n\n\texit(0);\n\n\treturn;\n}\n\nbool logCrashlog;\n\nint crashlogThread(void* exceptionInfoRawPtr)\n{\n\tPEXCEPTION_POINTERS pExceptionInfo = (PEXCEPTION_POINTERS)exceptionInfoRawPtr;\n\tcreateCrashlog(pExceptionInfo, pExceptionInfo->ContextRecord);\n\tlogCrashlog = true;\n\treturn 0;\n}\n\nvoid debugger_handleSingleStepException(uint64 dr6);\n\n\nLONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)\n{\n\tif (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)\n\t{\n\t\tLONG r = handleException_SINGLE_STEP(pExceptionInfo);\n\t\tif (r != EXCEPTION_CONTINUE_SEARCH)\n\t\t\treturn r;\n\n\t\tif (GetBits(pExceptionInfo->ContextRecord->Dr6, 0, 1) || GetBits(pExceptionInfo->ContextRecord->Dr6, 1, 1))\n\t\t\tdebugger_handleSingleStepException(pExceptionInfo->ContextRecord->Dr6);\n\t\telse if (GetBits(pExceptionInfo->ContextRecord->Dr6, 2, 1) || GetBits(pExceptionInfo->ContextRecord->Dr6, 3, 1))\n\t\t\tg_gdbstub->HandleAccessException(pExceptionInfo->ContextRecord->Dr6);\n\t\treturn EXCEPTION_CONTINUE_EXECUTION;\n\t}\n\treturn EXCEPTION_CONTINUE_SEARCH;\n}\n\nLONG WINAPI cemu_unhandledExceptionFilter(EXCEPTION_POINTERS* pExceptionInfo)\n{\n\tcreateCrashlog(pExceptionInfo, pExceptionInfo->ContextRecord);\n\treturn EXCEPTION_NONCONTINUABLE_EXCEPTION;\n}\n\nvoid ExceptionHandler_Init()\n{\n\tSetUnhandledExceptionFilter(cemu_unhandledExceptionFilter);\n\tAddVectoredExceptionHandler(1, VectoredExceptionHandler);\n\tSetErrorMode(SEM_FAILCRITICALERRORS);\n}\n"
  },
  {
    "path": "src/Common/FileStream.h",
    "content": "#pragma once\n#include \"Common/precompiled.h\"\n\n#ifdef _WIN32\n#include \"Common/windows/FileStream_win32.h\"\n#else\n#include \"Common/unix/FileStream_unix.h\"\n#endif\n"
  },
  {
    "path": "src/Common/GLInclude/GLInclude.h",
    "content": "#pragma once\n\n#include \"glext.h\"\n\n#if BOOST_OS_WINDOWS > 0\n#include \"wglext.h\"\n#endif\n\n#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) > 0\n\n// from Xlib\n#define Bool int\n#define Status int\n#define True 1\n#define False 0\n\n// from system glx.h\ntypedef XID GLXContextID;\ntypedef XID GLXPixmap;\ntypedef XID GLXDrawable;\ntypedef XID GLXPbuffer;\ntypedef XID GLXWindow;\ntypedef XID GLXFBConfigID;\ntypedef struct __GLXcontextRec *GLXContext;\ntypedef struct __GLXFBConfigRec *GLXFBConfig;\n\n#define EGL_EGL_PROTOTYPES 0\n#include \"egl.h\"\n#undef EGL_EGL_PROTOTYPES\n#include \"glxext.h\"\n\n#undef Bool\n#undef Status\n#undef True\n#undef False\n\n#endif\n\nnamespace CemuGL\n{\n#define GLFUNC(__type, __name)\textern __type __name;\n#define EGLFUNC(__type, __name) extern __type __name;\n#include \"glFunctions.h\"\n#undef GLFUNC\n#undef EGLFUNC\n\n// DSA-style helpers with fallback to legacy API if DSA is not supported\n\n#define DSA_FORCE_DISABLE false // set to true to simulate DSA not being supported\n\nstatic GLenum GetGLBindingFromTextureTarget(GLenum texTarget)\n{\n\tswitch(texTarget)\n\t{\n\tcase GL_TEXTURE_1D: return GL_TEXTURE_BINDING_1D;\n\tcase GL_TEXTURE_2D: return GL_TEXTURE_BINDING_2D;\n\tcase GL_TEXTURE_3D: return GL_TEXTURE_BINDING_3D;\n\tcase GL_TEXTURE_2D_ARRAY: return GL_TEXTURE_BINDING_2D_ARRAY;\n\tcase GL_TEXTURE_CUBE_MAP: return GL_TEXTURE_BINDING_CUBE_MAP;\n\tcase GL_TEXTURE_CUBE_MAP_ARRAY: return GL_TEXTURE_BINDING_CUBE_MAP_ARRAY;\n\tdefault:\n\t\tcemu_assert_unimplemented();\n\t\treturn 0;\n\t}\n}\n\nstatic GLuint glCreateTextureWrapper(GLenum target)\n{\n\tGLuint tex;\n\tif (glCreateTextures && !DSA_FORCE_DISABLE)\n\t{\n\t\tglCreateTextures(target, 1, &tex);\n\t\treturn tex;\n\t}\n\tGLint originalTexture;\n\tglGetIntegerv(GetGLBindingFromTextureTarget(target), &originalTexture);\n\tglGenTextures(1, &tex);\n\tglBindTexture(target, tex);\n\tglBindTexture(target, originalTexture);\n\treturn tex;\n}\n\nstatic void glTextureStorage1DWrapper(GLenum target, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width)\n{\n\tif (glTextureStorage1D && !DSA_FORCE_DISABLE)\n\t{\n\t\tglTextureStorage1D(texture, levels, internalformat, width);\n\t\treturn;\n\t}\n\tGLenum binding = GetGLBindingFromTextureTarget(target);\n\tGLint originalTexture;\n\tglGetIntegerv(binding, &originalTexture);\n\tglBindTexture(target, texture);\n\tglTexStorage1D(target, levels, internalformat, width);\n\tglBindTexture(target, originalTexture);\n}\n\nstatic void glTextureStorage2DWrapper(GLenum target, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)\n{\n\tif (glTextureStorage2D && !DSA_FORCE_DISABLE)\n\t{\n\t\tglTextureStorage2D(texture, levels, internalformat, width, height);\n\t\treturn;\n\t}\n\tGLenum binding = GetGLBindingFromTextureTarget(target);\n\tGLint originalTexture;\n\tglGetIntegerv(binding, &originalTexture);\n\tglBindTexture(target, texture);\n\tglTexStorage2D(target, levels, internalformat, width, height);\n\tglBindTexture(target, originalTexture);\n}\n\nstatic void glTextureStorage3DWrapper(GLenum target, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)\n{\n\tif (glTextureStorage3D && !DSA_FORCE_DISABLE)\n\t{\n\t\tglTextureStorage3D(texture, levels, internalformat, width, height, depth);\n\t\treturn;\n\t}\n\tGLenum binding = GetGLBindingFromTextureTarget(target);\n\tGLint originalTexture;\n\tglGetIntegerv(binding, &originalTexture);\n\tglBindTexture(target, texture);\n\tglTexStorage3D(target, levels, internalformat, width, height, depth);\n\tglBindTexture(target, originalTexture);\n}\n\nstatic void glTextureSubImage1DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels)\n{\n\tif (glTextureSubImage1D && !DSA_FORCE_DISABLE)\n\t{\n\t\tglTextureSubImage1D(texture, level, xoffset, width, format, type, pixels);\n\t\treturn;\n\t}\n\tGLenum binding = GetGLBindingFromTextureTarget(target);\n\tGLint originalTexture;\n\tglGetIntegerv(binding, &originalTexture);\n\tglBindTexture(target, texture);\n\tglTexSubImage1D(target, level, xoffset, width, format, type, pixels);\n\tglBindTexture(target, originalTexture);\n}\n\nstatic void glCompressedTextureSubImage1DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data)\n{\n\tif (glCompressedTextureSubImage1D && !DSA_FORCE_DISABLE)\n\t{\n\t\tglCompressedTextureSubImage1D(texture, level, xoffset, width, format, imageSize, data);\n\t\treturn;\n\t}\n\tGLenum binding = GetGLBindingFromTextureTarget(target);\n\tGLint originalTexture;\n\tglGetIntegerv(binding, &originalTexture);\n\tglBindTexture(target, texture);\n\tglCompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data);\n\tglBindTexture(target, originalTexture);\n}\n\nstatic void glTextureSubImage2DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels)\n{\n\tif (glTextureSubImage2D && !DSA_FORCE_DISABLE)\n\t{\n\t\tglTextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, type, pixels);\n\t\treturn;\n\t}\n\tGLenum binding = GetGLBindingFromTextureTarget(target);\n\tGLint originalTexture;\n\tglGetIntegerv(binding, &originalTexture);\n\tglBindTexture(target, texture);\n\tglTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);\n\tglBindTexture(target, originalTexture);\n}\n\nstatic void glCompressedTextureSubImage2DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)\n{\n\tif (glCompressedTextureSubImage2D && !DSA_FORCE_DISABLE)\n\t{\n\t\tglCompressedTextureSubImage2D(texture, level, xoffset, yoffset, width, height, format, imageSize, data);\n\t\treturn;\n\t}\n\tGLenum binding = GetGLBindingFromTextureTarget(target);\n\tGLint originalTexture;\n\tglGetIntegerv(binding, &originalTexture);\n\tglBindTexture(target, texture);\n\tglCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);\n\tglBindTexture(target, originalTexture);\n}\n\nstatic void glTextureSubImage3DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels)\n{\n\tif(glTextureSubImage3D && !DSA_FORCE_DISABLE)\n\t{\n\t\tglTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);\n\t\treturn;\n\t}\n\tGLenum binding = GetGLBindingFromTextureTarget(target);\n\tGLint originalTexture;\n\tglGetIntegerv(binding, &originalTexture);\n\tglBindTexture(target, texture);\n\tglTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);\n\tglBindTexture(target, originalTexture);\n}\n\nstatic void glCompressedTextureSubImage3DWrapper(GLenum target, GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data)\n{\n\tif(glCompressedTextureSubImage3D && !DSA_FORCE_DISABLE)\n\t{\n\t\tglCompressedTextureSubImage3D(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);\n\t\treturn;\n\t}\n\tGLenum binding = GetGLBindingFromTextureTarget(target);\n\tGLint originalTexture;\n\tglGetIntegerv(binding, &originalTexture);\n\tglBindTexture(target, texture);\n\tglCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);\n\tglBindTexture(target, originalTexture);\n}\n\n}\nusing namespace CemuGL;\n// this prevents Windows GL.h from being included:\n#define __gl_h_\n#define __GL_H__\n"
  },
  {
    "path": "src/Common/GLInclude/egl.h",
    "content": "#ifndef __egl_h_\n#define __egl_h_ 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n** Copyright 2013-2020 The Khronos Group Inc.\n** SPDX-License-Identifier: Apache-2.0\n**\n** This header is generated from the Khronos EGL XML API Registry.\n** The current version of the Registry, generator scripts\n** used to make the header, and the header can be found at\n**   http://www.khronos.org/registry/egl\n**\n** Khronos $Git commit SHA1: 8c62b915dd $ on $Git commit date: 2021-11-05 23:32:01 -0400 $\n*/\n\n#include <EGL/eglplatform.h>\n\n#ifndef EGL_EGL_PROTOTYPES\n#define EGL_EGL_PROTOTYPES 1\n#endif\n\n/* Generated on date 20211116 */\n\n/* Generated C header for:\n * API: egl\n * Versions considered: .*\n * Versions emitted: .*\n * Default extensions included: None\n * Additional extensions included: _nomatch_^\n * Extensions removed: _nomatch_^\n */\n\n#ifndef EGL_VERSION_1_0\n#define EGL_VERSION_1_0 1\ntypedef unsigned int EGLBoolean;\ntypedef void *EGLDisplay;\n#include <KHR/khrplatform.h>\n#include <EGL/eglplatform.h>\ntypedef void *EGLConfig;\ntypedef void *EGLSurface;\ntypedef void *EGLContext;\ntypedef void (*__eglMustCastToProperFunctionPointerType)(void);\n#define EGL_ALPHA_SIZE                    0x3021\n#define EGL_BAD_ACCESS                    0x3002\n#define EGL_BAD_ALLOC                     0x3003\n#define EGL_BAD_ATTRIBUTE                 0x3004\n#define EGL_BAD_CONFIG                    0x3005\n#define EGL_BAD_CONTEXT                   0x3006\n#define EGL_BAD_CURRENT_SURFACE           0x3007\n#define EGL_BAD_DISPLAY                   0x3008\n#define EGL_BAD_MATCH                     0x3009\n#define EGL_BAD_NATIVE_PIXMAP             0x300A\n#define EGL_BAD_NATIVE_WINDOW             0x300B\n#define EGL_BAD_PARAMETER                 0x300C\n#define EGL_BAD_SURFACE                   0x300D\n#define EGL_BLUE_SIZE                     0x3022\n#define EGL_BUFFER_SIZE                   0x3020\n#define EGL_CONFIG_CAVEAT                 0x3027\n#define EGL_CONFIG_ID                     0x3028\n#define EGL_CORE_NATIVE_ENGINE            0x305B\n#define EGL_DEPTH_SIZE                    0x3025\n#define EGL_DONT_CARE                     EGL_CAST(EGLint,-1)\n#define EGL_DRAW                          0x3059\n#define EGL_EXTENSIONS                    0x3055\n#define EGL_FALSE                         0\n#define EGL_GREEN_SIZE                    0x3023\n#define EGL_HEIGHT                        0x3056\n#define EGL_LARGEST_PBUFFER               0x3058\n#define EGL_LEVEL                         0x3029\n#define EGL_MAX_PBUFFER_HEIGHT            0x302A\n#define EGL_MAX_PBUFFER_PIXELS            0x302B\n#define EGL_MAX_PBUFFER_WIDTH             0x302C\n#define EGL_NATIVE_RENDERABLE             0x302D\n#define EGL_NATIVE_VISUAL_ID              0x302E\n#define EGL_NATIVE_VISUAL_TYPE            0x302F\n#define EGL_NONE                          0x3038\n#define EGL_NON_CONFORMANT_CONFIG         0x3051\n#define EGL_NOT_INITIALIZED               0x3001\n#define EGL_NO_CONTEXT                    EGL_CAST(EGLContext,0)\n#define EGL_NO_DISPLAY                    EGL_CAST(EGLDisplay,0)\n#define EGL_NO_SURFACE                    EGL_CAST(EGLSurface,0)\n#define EGL_PBUFFER_BIT                   0x0001\n#define EGL_PIXMAP_BIT                    0x0002\n#define EGL_READ                          0x305A\n#define EGL_RED_SIZE                      0x3024\n#define EGL_SAMPLES                       0x3031\n#define EGL_SAMPLE_BUFFERS                0x3032\n#define EGL_SLOW_CONFIG                   0x3050\n#define EGL_STENCIL_SIZE                  0x3026\n#define EGL_SUCCESS                       0x3000\n#define EGL_SURFACE_TYPE                  0x3033\n#define EGL_TRANSPARENT_BLUE_VALUE        0x3035\n#define EGL_TRANSPARENT_GREEN_VALUE       0x3036\n#define EGL_TRANSPARENT_RED_VALUE         0x3037\n#define EGL_TRANSPARENT_RGB               0x3052\n#define EGL_TRANSPARENT_TYPE              0x3034\n#define EGL_TRUE                          1\n#define EGL_VENDOR                        0x3053\n#define EGL_VERSION                       0x3054\n#define EGL_WIDTH                         0x3057\n#define EGL_WINDOW_BIT                    0x0004\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLCHOOSECONFIGPROC) (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLCOPYBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);\ntypedef EGLContext (EGLAPIENTRYP PFNEGLCREATECONTEXTPROC) (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);\ntypedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPBUFFERSURFACEPROC) (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);\ntypedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);\ntypedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCONFIGATTRIBPROC) (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCONFIGSPROC) (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);\ntypedef EGLDisplay (EGLAPIENTRYP PFNEGLGETCURRENTDISPLAYPROC) (void);\ntypedef EGLSurface (EGLAPIENTRYP PFNEGLGETCURRENTSURFACEPROC) (EGLint readdraw);\ntypedef EGLDisplay (EGLAPIENTRYP PFNEGLGETDISPLAYPROC) (EGLNativeDisplayType display_id);\ntypedef EGLint (EGLAPIENTRYP PFNEGLGETERRORPROC) (void);\ntypedef __eglMustCastToProperFunctionPointerType (EGLAPIENTRYP PFNEGLGETPROCADDRESSPROC) (const char *procname);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLINITIALIZEPROC) (EGLDisplay dpy, EGLint *major, EGLint *minor);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLMAKECURRENTPROC) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);\ntypedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGPROC) (EGLDisplay dpy, EGLint name);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLTERMINATEPROC) (EGLDisplay dpy);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITGLPROC) (void);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITNATIVEPROC) (EGLint engine);\n#if EGL_EGL_PROTOTYPES\nEGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);\nEGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);\nEGLAPI EGLContext EGLAPIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);\nEGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);\nEGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);\nEGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);\nEGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx);\nEGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface);\nEGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);\nEGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);\nEGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay (void);\nEGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface (EGLint readdraw);\nEGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay (EGLNativeDisplayType display_id);\nEGLAPI EGLint EGLAPIENTRY eglGetError (void);\nEGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress (const char *procname);\nEGLAPI EGLBoolean EGLAPIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);\nEGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);\nEGLAPI EGLBoolean EGLAPIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);\nEGLAPI const char *EGLAPIENTRY eglQueryString (EGLDisplay dpy, EGLint name);\nEGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);\nEGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface surface);\nEGLAPI EGLBoolean EGLAPIENTRY eglTerminate (EGLDisplay dpy);\nEGLAPI EGLBoolean EGLAPIENTRY eglWaitGL (void);\nEGLAPI EGLBoolean EGLAPIENTRY eglWaitNative (EGLint engine);\n#endif\n#endif /* EGL_VERSION_1_0 */\n\n#ifndef EGL_VERSION_1_1\n#define EGL_VERSION_1_1 1\n#define EGL_BACK_BUFFER                   0x3084\n#define EGL_BIND_TO_TEXTURE_RGB           0x3039\n#define EGL_BIND_TO_TEXTURE_RGBA          0x303A\n#define EGL_CONTEXT_LOST                  0x300E\n#define EGL_MIN_SWAP_INTERVAL             0x303B\n#define EGL_MAX_SWAP_INTERVAL             0x303C\n#define EGL_MIPMAP_TEXTURE                0x3082\n#define EGL_MIPMAP_LEVEL                  0x3083\n#define EGL_NO_TEXTURE                    0x305C\n#define EGL_TEXTURE_2D                    0x305F\n#define EGL_TEXTURE_FORMAT                0x3080\n#define EGL_TEXTURE_RGB                   0x305D\n#define EGL_TEXTURE_RGBA                  0x305E\n#define EGL_TEXTURE_TARGET                0x3081\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDTEXIMAGEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint buffer);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLRELEASETEXIMAGEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint buffer);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLSURFACEATTRIBPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPINTERVALPROC) (EGLDisplay dpy, EGLint interval);\n#if EGL_EGL_PROTOTYPES\nEGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);\nEGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);\nEGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);\nEGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval (EGLDisplay dpy, EGLint interval);\n#endif\n#endif /* EGL_VERSION_1_1 */\n\n#ifndef EGL_VERSION_1_2\n#define EGL_VERSION_1_2 1\ntypedef unsigned int EGLenum;\ntypedef void *EGLClientBuffer;\n#define EGL_ALPHA_FORMAT                  0x3088\n#define EGL_ALPHA_FORMAT_NONPRE           0x308B\n#define EGL_ALPHA_FORMAT_PRE              0x308C\n#define EGL_ALPHA_MASK_SIZE               0x303E\n#define EGL_BUFFER_PRESERVED              0x3094\n#define EGL_BUFFER_DESTROYED              0x3095\n#define EGL_CLIENT_APIS                   0x308D\n#define EGL_COLORSPACE                    0x3087\n#define EGL_COLORSPACE_sRGB               0x3089\n#define EGL_COLORSPACE_LINEAR             0x308A\n#define EGL_COLOR_BUFFER_TYPE             0x303F\n#define EGL_CONTEXT_CLIENT_TYPE           0x3097\n#define EGL_DISPLAY_SCALING               10000\n#define EGL_HORIZONTAL_RESOLUTION         0x3090\n#define EGL_LUMINANCE_BUFFER              0x308F\n#define EGL_LUMINANCE_SIZE                0x303D\n#define EGL_OPENGL_ES_BIT                 0x0001\n#define EGL_OPENVG_BIT                    0x0002\n#define EGL_OPENGL_ES_API                 0x30A0\n#define EGL_OPENVG_API                    0x30A1\n#define EGL_OPENVG_IMAGE                  0x3096\n#define EGL_PIXEL_ASPECT_RATIO            0x3092\n#define EGL_RENDERABLE_TYPE               0x3040\n#define EGL_RENDER_BUFFER                 0x3086\n#define EGL_RGB_BUFFER                    0x308E\n#define EGL_SINGLE_BUFFER                 0x3085\n#define EGL_SWAP_BEHAVIOR                 0x3093\n#define EGL_UNKNOWN                       EGL_CAST(EGLint,-1)\n#define EGL_VERTICAL_RESOLUTION           0x3091\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDAPIPROC) (EGLenum api);\ntypedef EGLenum (EGLAPIENTRYP PFNEGLQUERYAPIPROC) (void);\ntypedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC) (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLRELEASETHREADPROC) (void);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITCLIENTPROC) (void);\n#if EGL_EGL_PROTOTYPES\nEGLAPI EGLBoolean EGLAPIENTRY eglBindAPI (EGLenum api);\nEGLAPI EGLenum EGLAPIENTRY eglQueryAPI (void);\nEGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);\nEGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread (void);\nEGLAPI EGLBoolean EGLAPIENTRY eglWaitClient (void);\n#endif\n#endif /* EGL_VERSION_1_2 */\n\n#ifndef EGL_VERSION_1_3\n#define EGL_VERSION_1_3 1\n#define EGL_CONFORMANT                    0x3042\n#define EGL_CONTEXT_CLIENT_VERSION        0x3098\n#define EGL_MATCH_NATIVE_PIXMAP           0x3041\n#define EGL_OPENGL_ES2_BIT                0x0004\n#define EGL_VG_ALPHA_FORMAT               0x3088\n#define EGL_VG_ALPHA_FORMAT_NONPRE        0x308B\n#define EGL_VG_ALPHA_FORMAT_PRE           0x308C\n#define EGL_VG_ALPHA_FORMAT_PRE_BIT       0x0040\n#define EGL_VG_COLORSPACE                 0x3087\n#define EGL_VG_COLORSPACE_sRGB            0x3089\n#define EGL_VG_COLORSPACE_LINEAR          0x308A\n#define EGL_VG_COLORSPACE_LINEAR_BIT      0x0020\n#endif /* EGL_VERSION_1_3 */\n\n#ifndef EGL_VERSION_1_4\n#define EGL_VERSION_1_4 1\n#define EGL_DEFAULT_DISPLAY               EGL_CAST(EGLNativeDisplayType,0)\n#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT   0x0200\n#define EGL_MULTISAMPLE_RESOLVE           0x3099\n#define EGL_MULTISAMPLE_RESOLVE_DEFAULT   0x309A\n#define EGL_MULTISAMPLE_RESOLVE_BOX       0x309B\n#define EGL_OPENGL_API                    0x30A2\n#define EGL_OPENGL_BIT                    0x0008\n#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT   0x0400\ntypedef EGLContext (EGLAPIENTRYP PFNEGLGETCURRENTCONTEXTPROC) (void);\n#if EGL_EGL_PROTOTYPES\nEGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void);\n#endif\n#endif /* EGL_VERSION_1_4 */\n\n#ifndef EGL_VERSION_1_5\n#define EGL_VERSION_1_5 1\ntypedef void *EGLSync;\ntypedef intptr_t EGLAttrib;\ntypedef khronos_utime_nanoseconds_t EGLTime;\ntypedef void *EGLImage;\n#define EGL_CONTEXT_MAJOR_VERSION         0x3098\n#define EGL_CONTEXT_MINOR_VERSION         0x30FB\n#define EGL_CONTEXT_OPENGL_PROFILE_MASK   0x30FD\n#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD\n#define EGL_NO_RESET_NOTIFICATION         0x31BE\n#define EGL_LOSE_CONTEXT_ON_RESET         0x31BF\n#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001\n#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002\n#define EGL_CONTEXT_OPENGL_DEBUG          0x31B0\n#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1\n#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS  0x31B2\n#define EGL_OPENGL_ES3_BIT                0x00000040\n#define EGL_CL_EVENT_HANDLE               0x309C\n#define EGL_SYNC_CL_EVENT                 0x30FE\n#define EGL_SYNC_CL_EVENT_COMPLETE        0x30FF\n#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE  0x30F0\n#define EGL_SYNC_TYPE                     0x30F7\n#define EGL_SYNC_STATUS                   0x30F1\n#define EGL_SYNC_CONDITION                0x30F8\n#define EGL_SIGNALED                      0x30F2\n#define EGL_UNSIGNALED                    0x30F3\n#define EGL_SYNC_FLUSH_COMMANDS_BIT       0x0001\n#define EGL_FOREVER                       0xFFFFFFFFFFFFFFFFull\n#define EGL_TIMEOUT_EXPIRED               0x30F5\n#define EGL_CONDITION_SATISFIED           0x30F6\n#define EGL_NO_SYNC                       EGL_CAST(EGLSync,0)\n#define EGL_SYNC_FENCE                    0x30F9\n#define EGL_GL_COLORSPACE                 0x309D\n#define EGL_GL_COLORSPACE_SRGB            0x3089\n#define EGL_GL_COLORSPACE_LINEAR          0x308A\n#define EGL_GL_RENDERBUFFER               0x30B9\n#define EGL_GL_TEXTURE_2D                 0x30B1\n#define EGL_GL_TEXTURE_LEVEL              0x30BC\n#define EGL_GL_TEXTURE_3D                 0x30B2\n#define EGL_GL_TEXTURE_ZOFFSET            0x30BD\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8\n#define EGL_IMAGE_PRESERVED               0x30D2\n#define EGL_NO_IMAGE                      EGL_CAST(EGLImage,0)\ntypedef EGLSync (EGLAPIENTRYP PFNEGLCREATESYNCPROC) (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCPROC) (EGLDisplay dpy, EGLSync sync);\ntypedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCPROC) (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBPROC) (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);\ntypedef EGLImage (EGLAPIENTRYP PFNEGLCREATEIMAGEPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEPROC) (EGLDisplay dpy, EGLImage image);\ntypedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYPROC) (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);\ntypedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);\ntypedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);\ntypedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITSYNCPROC) (EGLDisplay dpy, EGLSync sync, EGLint flags);\n#if EGL_EGL_PROTOTYPES\nEGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);\nEGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync);\nEGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);\nEGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttrib (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);\nEGLAPI EGLImage EGLAPIENTRY eglCreateImage (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);\nEGLAPI EGLBoolean EGLAPIENTRY eglDestroyImage (EGLDisplay dpy, EGLImage image);\nEGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplay (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);\nEGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);\nEGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);\nEGLAPI EGLBoolean EGLAPIENTRY eglWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags);\n#endif\n#endif /* EGL_VERSION_1_5 */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/Common/GLInclude/glFunctions.h",
    "content": "// OpenGL 1.1 - 2.0\nGLFUNC(PFNGLDRAWBUFFERPROC, glDrawBuffer)\nGLFUNC(PFNGLGENTEXTURESPROC, glGenTextures)\nGLFUNC(PFNGLDELETETEXTURESPROC, glDeleteTextures)\nGLFUNC(PFNGLBINDTEXTUREPROC, glBindTexture)\nGLFUNC(PFNGLTEXPARAMETERIPROC, glTexParameteri)\nGLFUNC(PFNGLTEXIMAGE2DPROC, glTexImage2D)\nGLFUNC(PFNGLTEXSUBIMAGE2DPROC, glTexSubImage2D)\nGLFUNC(PFNGLTEXIMAGE1DPROC, glTexImage1D)\nGLFUNC(PFNGLTEXSUBIMAGE1DPROC, glTexSubImage1D)\nGLFUNC(PFNGLGETTEXIMAGEPROC, glGetTexImage)\nGLFUNC(PFNGLENABLEPROC, glEnable)\nGLFUNC(PFNGLDISABLEPROC, glDisable)\nGLFUNC(PFNGLISENABLEDPROC, glIsEnabled)\nGLFUNC(PFNGLCLEARPROC, glClear)\nGLFUNC(PFNGLCLEARCOLORPROC, glClearColor)\nGLFUNC(PFNGLCLEARDEPTHPROC, glClearDepth)\nGLFUNC(PFNGLCLEARSTENCILPROC, glClearStencil)\nGLFUNC(PFNGLFLUSHPROC, glFlush)\nGLFUNC(PFNGLFINISHPROC, glFinish)\nGLFUNC(PFNGLPIXELSTOREIPROC, glPixelStorei)\nGLFUNC(PFNGLGETSTRINGPROC, glGetString)\nGLFUNC(PFNGLGETINTEGERVPROC, glGetIntegerv)\nGLFUNC(PFNGLGETTEXLEVELPARAMETERIVPROC, glGetTexLevelParameteriv)\nGLFUNC(PFNGLTEXPARAMETERFPROC, glTexParameterf)\nGLFUNC(PFNGLTEXPARAMETERFVPROC, glTexParameterfv)\nGLFUNC(PFNGLDEPTHFUNCPROC, glDepthFunc)\nGLFUNC(PFNGLDEPTHMASKPROC, glDepthMask)\nGLFUNC(PFNGLDEPTHRANGEPROC, glDepthRange)\nGLFUNC(PFNGLFRONTFACEPROC, glFrontFace)\nGLFUNC(PFNGLCULLFACEPROC, glCullFace)\nGLFUNC(PFNGLPOLYGONOFFSETPROC, glPolygonOffset)\nGLFUNC(PFNGLPOINTSIZEPROC, glPointSize)\nGLFUNC(PFNGLLOGICOPPROC, glLogicOp)\nGLFUNC(PFNGLPOLYGONMODEPROC, glPolygonMode)\nGLFUNC(PFNGLSCISSORPROC, glScissor)\nGLFUNC(PFNGLVIEWPORTPROC, glViewport)\nGLFUNC(PFNGLGETERRORPROC, glGetError)\nGLFUNC(PFNGLDRAWARRAYSPROC, glDrawArrays)\n\n// everything else\n\nGLFUNC(PFNGLUNIFORM1IPROC, glUniform1i)\nGLFUNC(PFNGLUNIFORM2IPROC, glUniform2i)\nGLFUNC(PFNGLUNIFORM2FPROC, glUniform2f)\nGLFUNC(PFNGLUNIFORM4FVPROC, glUniform4fv)\nGLFUNC(PFNGLUNIFORMMATRIX4FVPROC, glUniformMatrix4fv)\n\n\nGLFUNC(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog)\n\nGLFUNC(PFNGLUSEPROGRAMPROC, glUseProgram)\n\nGLFUNC(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation)\n\nGLFUNC(PFNGLACTIVETEXTUREPROC, glActiveTexture)\nGLFUNC(PFNGLCLIENTACTIVETEXTUREPROC, glClientActiveTexture)\n\nGLFUNC(PFNGLPRIMITIVERESTARTINDEXPROC, glPrimitiveRestartIndex)\n\nGLFUNC(PFNGLDRAWRANGEELEMENTSPROC, glDrawRangeElements)\nGLFUNC(PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC, glDrawRangeElementsBaseVertex)\n\nGLFUNC(PFNGLGENBUFFERSPROC, glGenBuffers)\nGLFUNC(PFNGLBINDBUFFERPROC, glBindBuffer)\nGLFUNC(PFNGLBUFFERDATAPROC, glBufferData)\nGLFUNC(PFNGLBUFFERSUBDATAPROC, glBufferSubData)\nGLFUNC(PFNGLMAPBUFFERPROC, glMapBuffer)\nGLFUNC(PFNGLUNMAPBUFFERPROC, glUnmapBuffer)\nGLFUNC(PFNGLDELETEBUFFERSARBPROC, glDeleteBuffers)\n\nGLFUNC(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray)\nGLFUNC(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray)\nGLFUNC(PFNGLGETATTRIBLOCATIONPROC, glGetAttribLocation)\nGLFUNC(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation)\nGLFUNC(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer)\nGLFUNC(PFNGLVERTEXATTRIBIPOINTERPROC, glVertexAttribIPointer)\n\nGLFUNC(PFNGLBLENDEQUATIONPROC, glBlendEquation)\nGLFUNC(PFNGLBLENDFUNCSEPARATEEXTPROC, glBlendFuncSeparate)\nGLFUNC(PFNGLBLENDEQUATIONSEPARATEEXTPROC, glBlendEquationSeparate)\nGLFUNC(PFNGLBLENDEQUATIONSEPARATEIPROC, glBlendEquationSeparatei)\nGLFUNC(PFNGLBLENDFUNCSEPARATEIPROC, glBlendFuncSeparatei)\nGLFUNC(PFNGLBLENDCOLORPROC, glBlendColor)\n\nGLFUNC(PFNGLDRAWBUFFERSPROC, glDrawBuffers)\nGLFUNC(PFNGLCLAMPCOLORARBPROC, glClampColor)\n\nGLFUNC(PFNGLBINDFRAGDATALOCATIONEXTPROC, glBindFragDataLocation)\n\nGLFUNC(PFNGLSHADERSOURCEPROC, glShaderSource)\nGLFUNC(PFNGLCOMPILESHADERPROC, glCompileShader)\nGLFUNC(PFNGLATTACHSHADERPROC, glAttachShader)\nGLFUNC(PFNGLLINKPROGRAMPROC, glLinkProgram)\nGLFUNC(PFNGLGETSHADERIVPROC, glGetShaderiv)\nGLFUNC(PFNGLGETPROGRAMIVPROC, glGetProgramiv)\nGLFUNC(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog)\nGLFUNC(PFNGLGETPROGRAMBINARYPROC, glGetProgramBinary)\nGLFUNC(PFNGLPROGRAMBINARYPROC, glProgramBinary)\nGLFUNC(PFNGLPROGRAMPARAMETERIPROC, glProgramParameteri)\nGLFUNC(PFNGLCREATEPROGRAMPROC, glCreateProgram)\nGLFUNC(PFNGLCREATESHADERPROC, glCreateShader)\nGLFUNC(PFNGLDELETEPROGRAMPROC, glDeleteProgram)\nGLFUNC(PFNGLDELETESHADERPROC, glDeleteShader)\nGLFUNC(PFNGLDETACHSHADERPROC, glDetachShader)\nGLFUNC(PFNGLGETATTACHEDSHADERSPROC, glGetAttachedShaders)\n\nGLFUNC(PFNGLCREATESHADERPROGRAMVPROC, glCreateShaderProgramv)\nGLFUNC(PFNGLUSEPROGRAMSTAGESPROC, glUseProgramStages)\nGLFUNC(PFNGLBINDPROGRAMPIPELINEPROC, glBindProgramPipeline)\nGLFUNC(PFNGLGENPROGRAMPIPELINESPROC, glGenProgramPipelines)\nGLFUNC(PFNGLACTIVESHADERPROGRAMPROC, glActiveShaderProgram)\nGLFUNC(PFNGLDELETEPROGRAMPIPELINESPROC, glDeleteProgramPipelines)\n\nGLFUNC(PFNGLPROGRAMUNIFORM1IPROC, glProgramUniform1i)\nGLFUNC(PFNGLPROGRAMUNIFORM2IPROC, glProgramUniform2i)\nGLFUNC(PFNGLPROGRAMUNIFORM1IVPROC, glProgramUniform1iv)\nGLFUNC(PFNGLPROGRAMUNIFORM4IVPROC, glProgramUniform4iv)\nGLFUNC(PFNGLPROGRAMUNIFORM1IPROC, glProgramUniform1f)\nGLFUNC(PFNGLPROGRAMUNIFORM1FVPROC, glProgramUniform1fv)\nGLFUNC(PFNGLPROGRAMUNIFORM2FVPROC, glProgramUniform2fv)\n\n// FBO\n\nGLFUNC(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers)\nGLFUNC(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer)\nGLFUNC(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D)\nGLFUNC(PFNGLFRAMEBUFFERTEXTURELAYERPROC, glFramebufferTextureLayer)\nGLFUNC(PFNGLNAMEDFRAMEBUFFERTEXTUREPROC, glNamedFramebufferTexture)\nGLFUNC(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus)\nGLFUNC(PFNGLINVALIDATEFRAMEBUFFERPROC, glInvalidateFramebuffer)\nGLFUNC(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers)\n\n//GLFUNC(PFNGLNAMEDFRAMEBUFFERTEXTUREPROC, glNamedFramebufferTexture)\nGLFUNC(PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC, glNamedFramebufferTexture2DEXT)\nGLFUNC(PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC, glNamedFramebufferTextureLayer)\n\nGLFUNC(PFNGLENABLEIPROC, glEnablei)\nGLFUNC(PFNGLDISABLEIPROC, glDisablei)\n\nGLFUNC(PFNGLBEGINQUERYINDEXEDPROC, glBeginQueryIndexed)\nGLFUNC(PFNGLENDQUERYINDEXEDPROC, glEndQueryIndexed)\nGLFUNC(PFNGLGETQUERYINDEXEDIVPROC, glGetQueryIndexediv)\nGLFUNC(PFNGLGETQUERYOBJECTI64VPROC, glGetQueryObjecti64v)\n\nGLFUNC(PFNGLGENQUERIESPROC, glGenQueries)\nGLFUNC(PFNGLDELETEQUERIESPROC, glDeleteQueries)\nGLFUNC(PFNGLQUERYCOUNTERPROC, glQueryCounter)\nGLFUNC(PFNGLGETQUERYOBJECTIVPROC, glGetQueryObjectiv)\n\n// FBO DSA\n\nGLFUNC(PFNGLCREATEFRAMEBUFFERSPROC, glCreateFramebuffers)\nGLFUNC(PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC, glInvalidateNamedFramebufferData)\n\n\n// misc\n\nGLFUNC(PFNGLCOLORMASKIPROC, glColorMaski)\nGLFUNC(PFNGLTEXTUREBARRIERPROC, glTextureBarrier)\nGLFUNC(PFNGLCLIPCONTROLPROC, glClipControl)\nGLFUNC(PFNGLVIEWPORTINDEXEDFPROC, glViewportIndexedf)\nGLFUNC(PFNGLMAXSHADERCOMPILERTHREADSARBPROC, glMaxShaderCompilerThreadsARB)\nGLFUNC(PFNGLDEPTHRANGEDNVPROC, glDepthRangedNV)\nGLFUNC(PFNGLPOLYGONOFFSETCLAMPEXTPROC, glPolygonOffsetClampEXT)\n\n// texture \n\nGLFUNC(PFNGLTEXTUREVIEWPROC, glTextureView)\nGLFUNC(PFNGLTEXSTORAGE1DPROC, glTexStorage1D)\nGLFUNC(PFNGLTEXSTORAGE2DPROC, glTexStorage2D)\nGLFUNC(PFNGLTEXSTORAGE3DPROC, glTexStorage3D)\nGLFUNC(PFNGLTEXIMAGE3DPROC, glTexImage3D)\nGLFUNC(PFNGLTEXSUBIMAGE3DPROC, glTexSubImage3D)\nGLFUNC(PFNGLCOMPRESSEDTEXIMAGE1DPROC, glCompressedTexImage1D)\nGLFUNC(PFNGLCOMPRESSEDTEXIMAGE2DPROC, glCompressedTexImage2D)\nGLFUNC(PFNGLCOMPRESSEDTEXIMAGE3DPROC, glCompressedTexImage3D)\nGLFUNC(PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC, glCompressedTexSubImage1D)\nGLFUNC(PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC, glCompressedTexSubImage2D)\nGLFUNC(PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC, glCompressedTexSubImage3D)\nGLFUNC(PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC, glCompressedTextureSubImage1D)\nGLFUNC(PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC, glCompressedTextureSubImage2D)\nGLFUNC(PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC, glCompressedTextureSubImage3D)\nGLFUNC(PFNGLCOPYIMAGESUBDATAPROC, glCopyImageSubData)\nGLFUNC(PFNGLCLEARTEXIMAGEPROC, glClearTexImage)\nGLFUNC(PFNGLCLEARTEXSUBIMAGEPROC, glClearTexSubImage)\nGLFUNC(PFNGLINVALIDATETEXIMAGEPROC, glInvalidateTexImage)\n\n// texture DSA\n\nGLFUNC(PFNGLCREATETEXTURESPROC, glCreateTextures)\nGLFUNC(PFNGLBINDTEXTUREUNITPROC, glBindTextureUnit)\nGLFUNC(PFNGLGETTEXTURELEVELPARAMETERIVPROC, glGetTextureLevelParameteriv)\nGLFUNC(PFNGLTEXTUREPARAMETERIPROC, glTextureParameteri)\nGLFUNC(PFNGLGETTEXTURESUBIMAGEPROC, glGetTextureSubImage)\nGLFUNC(PFNGLTEXTURESUBIMAGE1DPROC, glTextureSubImage1D)\nGLFUNC(PFNGLTEXTURESUBIMAGE2DPROC, glTextureSubImage2D);\nGLFUNC(PFNGLTEXTURESUBIMAGE3DPROC, glTextureSubImage3D)\nGLFUNC(PFNGLTEXTURESTORAGE1DPROC, glTextureStorage1D)\nGLFUNC(PFNGLTEXTURESTORAGE2DPROC, glTextureStorage2D)\nGLFUNC(PFNGLTEXTURESTORAGE3DPROC, glTextureStorage3D)\n\n// instancing / draw\n\nGLFUNC(PFNGLDRAWELEMENTSBASEVERTEXPROC, glDrawElementsBaseVertex)\nGLFUNC(PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC, glDrawElementsInstancedBaseVertexBaseInstance)\nGLFUNC(PFNGLDRAWARRAYSINSTANCEDPROC, glDrawArraysInstanced)\n\n// vertex array\n\nGLFUNC(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays)\nGLFUNC(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray)\nGLFUNC(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays)\nGLFUNC(PFNGLBINDVERTEXBUFFERPROC, glBindVertexBuffer)\nGLFUNC(PFNGLVERTEXATTRIBFORMATPROC, glVertexAttribFormat)\nGLFUNC(PFNGLVERTEXATTRIBIFORMATPROC, glVertexAttribIFormat)\nGLFUNC(PFNGLVERTEXATTRIBBINDINGPROC, glVertexAttribBinding)\nGLFUNC(PFNGLVERTEXBINDINGDIVISORPROC, glVertexBindingDivisor)\nGLFUNC(PFNGLVERTEXATTRIBDIVISORPROC, glVertexAttribDivisor)\n\n// vertex array DSA\n\nGLFUNC(PFNGLCREATEVERTEXARRAYSPROC, glCreateVertexArrays)\nGLFUNC(PFNGLDISABLEVERTEXARRAYATTRIBPROC, glDisableVertexArrayAttrib)\nGLFUNC(PFNGLENABLEVERTEXARRAYATTRIBPROC, glEnableVertexArrayAttrib)\nGLFUNC(PFNGLVERTEXARRAYELEMENTBUFFERPROC, glVertexArrayElementBuffer)\nGLFUNC(PFNGLVERTEXARRAYVERTEXBUFFERPROC, glVertexArrayVertexBuffer)\nGLFUNC(PFNGLVERTEXARRAYATTRIBBINDINGPROC, glVertexArrayAttribBinding)\nGLFUNC(PFNGLVERTEXARRAYATTRIBIFORMATPROC, glVertexArrayAttribIFormat)\nGLFUNC(PFNGLVERTEXARRAYBINDINGDIVISORPROC, glVertexArrayBindingDivisor)\n\n// sampler\n\nGLFUNC(PFNGLGENSAMPLERSPROC, glGenSamplers)\nGLFUNC(PFNGLBINDSAMPLERPROC, glBindSampler)\nGLFUNC(PFNGLSAMPLERPARAMETERIPROC, glSamplerParameteri)\nGLFUNC(PFNGLSAMPLERPARAMETERFPROC, glSamplerParameterf)\nGLFUNC(PFNGLSAMPLERPARAMETERIVPROC, glSamplerParameteriv)\nGLFUNC(PFNGLSAMPLERPARAMETERFVPROC, glSamplerParameterfv)\n\n// buffer object\n\nGLFUNC(PFNGLGETUNIFORMBLOCKINDEXPROC, glGetUniformBlockIndex)\nGLFUNC(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding)\nGLFUNC(PFNGLBINDBUFFERBASEPROC, glBindBufferBase)\nGLFUNC(PFNGLBINDBUFFERRANGEPROC, glBindBufferRange)\nGLFUNC(PFNGLGETBUFFERSUBDATAPROC, glGetBufferSubData)\n\n// uniform storage buffer object\n\nGLFUNC(PFNGLGETPROGRAMRESOURCEINDEXPROC, glGetProgramResourceIndex)\nGLFUNC(PFNGLSHADERSTORAGEBLOCKBINDINGPROC, glShaderStorageBlockBinding)\n\n// stencil \n\nGLFUNC(PFNGLSTENCILOPSEPARATEPROC, glStencilOpSeparate)\nGLFUNC(PFNGLSTENCILFUNCSEPARATEPROC, glStencilFuncSeparate)\nGLFUNC(PFNGLSTENCILMASKSEPARATEPROC, glStencilMaskSeparate)\n\n// buffer\n\nGLFUNC(PFNGLCREATEBUFFERSPROC, glCreateBuffers)\nGLFUNC(PFNGLBUFFERSTORAGEPROC, glBufferStorage)\nGLFUNC(PFNGLNAMEDBUFFERSTORAGEPROC, glNamedBufferStorage)\nGLFUNC(PFNGLMAPNAMEDBUFFERPROC, glMapNamedBuffer)\nGLFUNC(PFNGLMAPNAMEDBUFFERRANGEPROC, glMapNamedBufferRange)\nGLFUNC(PFNGLMAPBUFFERRANGEPROC, glMapBufferRange)\nGLFUNC(PFNGLFLUSHMAPPEDBUFFERRANGEPROC, glFlushMappedBufferRange)\nGLFUNC(PFNGLMEMORYBARRIERPROC, glMemoryBarrier)\nGLFUNC(PFNGLCOPYBUFFERSUBDATAPROC, glCopyBufferSubData)\nGLFUNC(PFNGLCOPYNAMEDBUFFERSUBDATAPROC, glCopyNamedBufferSubData)\nGLFUNC(PFNGLNAMEDBUFFERSUBDATAPROC, glNamedBufferSubData)\nGLFUNC(PFNGLGETNAMEDBUFFERSUBDATAPROC, glGetNamedBufferSubData);\n\n// transform feedback\n\nGLFUNC(PFNGLBEGINTRANSFORMFEEDBACKPROC, glBeginTransformFeedback)\nGLFUNC(PFNGLENDTRANSFORMFEEDBACKPROC, glEndTransformFeedback)\nGLFUNC(PFNGLTRANSFORMFEEDBACKVARYINGSPROC, glTransformFeedbackVaryings)\n\n// sync / fence\n\nGLFUNC(PFNGLFENCESYNCPROC, glFenceSync)\nGLFUNC(PFNGLCLIENTWAITSYNCPROC, glClientWaitSync)\nGLFUNC(PFNGLDELETESYNCPROC, glDeleteSync)\n\n// debugging\n\nGLFUNC(PFNGLOBJECTLABELPROC, glObjectLabel)\nGLFUNC(PFNGLDEBUGMESSAGECALLBACKPROC, glDebugMessageCallback)\nGLFUNC(PFNGLDEBUGMESSAGECONTROLPROC, glDebugMessageControl)\n\n// wgl\n\n#if BOOST_OS_WINDOWS\nGLFUNC(PFNWGLSWAPINTERVALEXTPROC, wglSwapIntervalEXT)\n#endif\n\n// x\n\n#if BOOST_OS_LINUX || BOOST_OS_BSD\nEGLFUNC(PFNEGLSWAPINTERVALPROC, eglSwapInterval)\nEGLFUNC(PFNEGLGETCURRENTDISPLAYPROC, eglGetCurrentDisplay)\n#endif\n"
  },
  {
    "path": "src/Common/GLInclude/glext.h",
    "content": "#ifndef __gl_glext_custom_h_\n#define __gl_glext_custom_h_ 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n** Copyright 2013-2020 The Khronos Group Inc.\n** SPDX-License-Identifier: MIT\n**\n** This header is generated from the Khronos OpenGL / OpenGL ES XML\n** API Registry. The current version of the Registry, generator scripts\n** used to make the header, and the header can be found at\n**   https://github.com/KhronosGroup/OpenGL-Registry\n*/\n\n#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN 1\n#endif\n#include <windows.h>\n#endif\n\n#ifndef APIENTRY\n#define APIENTRY\n#endif\n#ifndef APIENTRYP\n#define APIENTRYP APIENTRY *\n#endif\n#ifndef GLAPI\n#define GLAPI extern\n#endif\n\n#define GL_GLEXT_VERSION 20220309\n\n#include \"khrplatform.h\"\n\n/* Generated C header for:\n * API: gl\n * Profile: compatibility\n * Versions considered: .*\n * Versions emitted: .*\n * Default extensions included: gl\n * Additional extensions included: _nomatch_^\n * Extensions removed: _nomatch_^\n */\n\n#ifndef GL_VERSION_1_0\n#define GL_VERSION_1_0 1\ntypedef void GLvoid;\ntypedef unsigned int GLenum;\ntypedef khronos_float_t GLfloat;\ntypedef int GLint;\ntypedef int GLsizei;\ntypedef unsigned int GLbitfield;\ntypedef double GLdouble;\ntypedef unsigned int GLuint;\ntypedef unsigned char GLboolean;\ntypedef khronos_uint8_t GLubyte;\ntypedef khronos_int8_t GLbyte;\ntypedef khronos_int16_t GLshort;\ntypedef khronos_uint16_t GLushort;\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\ntypedef void (APIENTRYP PFNGLCULLFACEPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLFRONTFACEPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLHINTPROC) (GLenum target, GLenum mode);\ntypedef void (APIENTRYP PFNGLLINEWIDTHPROC) (GLfloat width);\ntypedef void (APIENTRYP PFNGLPOINTSIZEPROC) (GLfloat size);\ntypedef void (APIENTRYP PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode);\ntypedef void (APIENTRYP PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLTEXIMAGE1DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLDRAWBUFFERPROC) (GLenum buf);\ntypedef void (APIENTRYP PFNGLCLEARPROC) (GLbitfield mask);\ntypedef void (APIENTRYP PFNGLCLEARCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\ntypedef void (APIENTRYP PFNGLCLEARSTENCILPROC) (GLint s);\ntypedef void (APIENTRYP PFNGLCLEARDEPTHPROC) (GLdouble depth);\ntypedef void (APIENTRYP PFNGLSTENCILMASKPROC) (GLuint mask);\ntypedef void (APIENTRYP PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);\ntypedef void (APIENTRYP PFNGLDEPTHMASKPROC) (GLboolean flag);\ntypedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);\ntypedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);\ntypedef void (APIENTRYP PFNGLFINISHPROC) (void);\ntypedef void (APIENTRYP PFNGLFLUSHPROC) (void);\ntypedef void (APIENTRYP PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor);\ntypedef void (APIENTRYP PFNGLLOGICOPPROC) (GLenum opcode);\ntypedef void (APIENTRYP PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask);\ntypedef void (APIENTRYP PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass);\ntypedef void (APIENTRYP PFNGLDEPTHFUNCPROC) (GLenum func);\ntypedef void (APIENTRYP PFNGLPIXELSTOREFPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLREADBUFFERPROC) (GLenum src);\ntypedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);\ntypedef void (APIENTRYP PFNGLGETBOOLEANVPROC) (GLenum pname, GLboolean *data);\ntypedef void (APIENTRYP PFNGLGETDOUBLEVPROC) (GLenum pname, GLdouble *data);\ntypedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);\ntypedef void (APIENTRYP PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *data);\ntypedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data);\ntypedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);\ntypedef void (APIENTRYP PFNGLGETTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, void *pixels);\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC) (GLenum target, GLint level, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC) (GLenum target, GLint level, GLenum pname, GLint *params);\ntypedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap);\ntypedef void (APIENTRYP PFNGLDEPTHRANGEPROC) (GLdouble n, GLdouble f);\ntypedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLNEWLISTPROC) (GLuint list, GLenum mode);\ntypedef void (APIENTRYP PFNGLENDLISTPROC) (void);\ntypedef void (APIENTRYP PFNGLCALLLISTPROC) (GLuint list);\ntypedef void (APIENTRYP PFNGLCALLLISTSPROC) (GLsizei n, GLenum type, const void *lists);\ntypedef void (APIENTRYP PFNGLDELETELISTSPROC) (GLuint list, GLsizei range);\ntypedef GLuint (APIENTRYP PFNGLGENLISTSPROC) (GLsizei range);\ntypedef void (APIENTRYP PFNGLLISTBASEPROC) (GLuint base);\ntypedef void (APIENTRYP PFNGLBEGINPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLBITMAPPROC) (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);\ntypedef void (APIENTRYP PFNGLCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);\ntypedef void (APIENTRYP PFNGLCOLOR3BVPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);\ntypedef void (APIENTRYP PFNGLCOLOR3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);\ntypedef void (APIENTRYP PFNGLCOLOR3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLCOLOR3IPROC) (GLint red, GLint green, GLint blue);\ntypedef void (APIENTRYP PFNGLCOLOR3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);\ntypedef void (APIENTRYP PFNGLCOLOR3SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);\ntypedef void (APIENTRYP PFNGLCOLOR3UBVPROC) (const GLubyte *v);\ntypedef void (APIENTRYP PFNGLCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);\ntypedef void (APIENTRYP PFNGLCOLOR3UIVPROC) (const GLuint *v);\ntypedef void (APIENTRYP PFNGLCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);\ntypedef void (APIENTRYP PFNGLCOLOR3USVPROC) (const GLushort *v);\ntypedef void (APIENTRYP PFNGLCOLOR4BPROC) (GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);\ntypedef void (APIENTRYP PFNGLCOLOR4BVPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLCOLOR4DPROC) (GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);\ntypedef void (APIENTRYP PFNGLCOLOR4DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLCOLOR4FPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\ntypedef void (APIENTRYP PFNGLCOLOR4FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLCOLOR4IPROC) (GLint red, GLint green, GLint blue, GLint alpha);\ntypedef void (APIENTRYP PFNGLCOLOR4IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLCOLOR4SPROC) (GLshort red, GLshort green, GLshort blue, GLshort alpha);\ntypedef void (APIENTRYP PFNGLCOLOR4SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLCOLOR4UBPROC) (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);\ntypedef void (APIENTRYP PFNGLCOLOR4UBVPROC) (const GLubyte *v);\ntypedef void (APIENTRYP PFNGLCOLOR4UIPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha);\ntypedef void (APIENTRYP PFNGLCOLOR4UIVPROC) (const GLuint *v);\ntypedef void (APIENTRYP PFNGLCOLOR4USPROC) (GLushort red, GLushort green, GLushort blue, GLushort alpha);\ntypedef void (APIENTRYP PFNGLCOLOR4USVPROC) (const GLushort *v);\ntypedef void (APIENTRYP PFNGLEDGEFLAGPROC) (GLboolean flag);\ntypedef void (APIENTRYP PFNGLEDGEFLAGVPROC) (const GLboolean *flag);\ntypedef void (APIENTRYP PFNGLENDPROC) (void);\ntypedef void (APIENTRYP PFNGLINDEXDPROC) (GLdouble c);\ntypedef void (APIENTRYP PFNGLINDEXDVPROC) (const GLdouble *c);\ntypedef void (APIENTRYP PFNGLINDEXFPROC) (GLfloat c);\ntypedef void (APIENTRYP PFNGLINDEXFVPROC) (const GLfloat *c);\ntypedef void (APIENTRYP PFNGLINDEXIPROC) (GLint c);\ntypedef void (APIENTRYP PFNGLINDEXIVPROC) (const GLint *c);\ntypedef void (APIENTRYP PFNGLINDEXSPROC) (GLshort c);\ntypedef void (APIENTRYP PFNGLINDEXSVPROC) (const GLshort *c);\ntypedef void (APIENTRYP PFNGLNORMAL3BPROC) (GLbyte nx, GLbyte ny, GLbyte nz);\ntypedef void (APIENTRYP PFNGLNORMAL3BVPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLNORMAL3DPROC) (GLdouble nx, GLdouble ny, GLdouble nz);\ntypedef void (APIENTRYP PFNGLNORMAL3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLNORMAL3FPROC) (GLfloat nx, GLfloat ny, GLfloat nz);\ntypedef void (APIENTRYP PFNGLNORMAL3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLNORMAL3IPROC) (GLint nx, GLint ny, GLint nz);\ntypedef void (APIENTRYP PFNGLNORMAL3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLNORMAL3SPROC) (GLshort nx, GLshort ny, GLshort nz);\ntypedef void (APIENTRYP PFNGLNORMAL3SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS2DPROC) (GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLRASTERPOS2DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS2FPROC) (GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLRASTERPOS2FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS2IPROC) (GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLRASTERPOS2IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS2SPROC) (GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLRASTERPOS2SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLRASTERPOS3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLRASTERPOS3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS3IPROC) (GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLRASTERPOS3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS3SPROC) (GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLRASTERPOS3SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS4DPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLRASTERPOS4DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS4FPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLRASTERPOS4FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS4IPROC) (GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLRASTERPOS4IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLRASTERPOS4SPROC) (GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLRASTERPOS4SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLRECTDPROC) (GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);\ntypedef void (APIENTRYP PFNGLRECTDVPROC) (const GLdouble *v1, const GLdouble *v2);\ntypedef void (APIENTRYP PFNGLRECTFPROC) (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);\ntypedef void (APIENTRYP PFNGLRECTFVPROC) (const GLfloat *v1, const GLfloat *v2);\ntypedef void (APIENTRYP PFNGLRECTIPROC) (GLint x1, GLint y1, GLint x2, GLint y2);\ntypedef void (APIENTRYP PFNGLRECTIVPROC) (const GLint *v1, const GLint *v2);\ntypedef void (APIENTRYP PFNGLRECTSPROC) (GLshort x1, GLshort y1, GLshort x2, GLshort y2);\ntypedef void (APIENTRYP PFNGLRECTSVPROC) (const GLshort *v1, const GLshort *v2);\ntypedef void (APIENTRYP PFNGLTEXCOORD1DPROC) (GLdouble s);\ntypedef void (APIENTRYP PFNGLTEXCOORD1DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD1FPROC) (GLfloat s);\ntypedef void (APIENTRYP PFNGLTEXCOORD1FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD1IPROC) (GLint s);\ntypedef void (APIENTRYP PFNGLTEXCOORD1IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD1SPROC) (GLshort s);\ntypedef void (APIENTRYP PFNGLTEXCOORD1SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2DPROC) (GLdouble s, GLdouble t);\ntypedef void (APIENTRYP PFNGLTEXCOORD2DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FPROC) (GLfloat s, GLfloat t);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2IPROC) (GLint s, GLint t);\ntypedef void (APIENTRYP PFNGLTEXCOORD2IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2SPROC) (GLshort s, GLshort t);\ntypedef void (APIENTRYP PFNGLTEXCOORD2SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD3DPROC) (GLdouble s, GLdouble t, GLdouble r);\ntypedef void (APIENTRYP PFNGLTEXCOORD3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD3FPROC) (GLfloat s, GLfloat t, GLfloat r);\ntypedef void (APIENTRYP PFNGLTEXCOORD3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD3IPROC) (GLint s, GLint t, GLint r);\ntypedef void (APIENTRYP PFNGLTEXCOORD3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD3SPROC) (GLshort s, GLshort t, GLshort r);\ntypedef void (APIENTRYP PFNGLTEXCOORD3SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD4DPROC) (GLdouble s, GLdouble t, GLdouble r, GLdouble q);\ntypedef void (APIENTRYP PFNGLTEXCOORD4DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD4FPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat q);\ntypedef void (APIENTRYP PFNGLTEXCOORD4FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD4IPROC) (GLint s, GLint t, GLint r, GLint q);\ntypedef void (APIENTRYP PFNGLTEXCOORD4IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD4SPROC) (GLshort s, GLshort t, GLshort r, GLshort q);\ntypedef void (APIENTRYP PFNGLTEXCOORD4SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEX2DPROC) (GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEX2DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEX2FPROC) (GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLVERTEX2FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEX2IPROC) (GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLVERTEX2IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEX2SPROC) (GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLVERTEX2SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEX3DPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEX3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEX3FPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLVERTEX3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEX3IPROC) (GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLVERTEX3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEX3SPROC) (GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLVERTEX3SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEX4DPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEX4DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEX4FPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLVERTEX4FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEX4IPROC) (GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLVERTEX4IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEX4SPROC) (GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLVERTEX4SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLCLIPPLANEPROC) (GLenum plane, const GLdouble *equation);\ntypedef void (APIENTRYP PFNGLCOLORMATERIALPROC) (GLenum face, GLenum mode);\ntypedef void (APIENTRYP PFNGLFOGFPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLFOGFVPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLFOGIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLFOGIVPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLLIGHTFPROC) (GLenum light, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLLIGHTFVPROC) (GLenum light, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLLIGHTIPROC) (GLenum light, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLLIGHTIVPROC) (GLenum light, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLLIGHTMODELFPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLLIGHTMODELFVPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLLIGHTMODELIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLLIGHTMODELIVPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLLINESTIPPLEPROC) (GLint factor, GLushort pattern);\ntypedef void (APIENTRYP PFNGLMATERIALFPROC) (GLenum face, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLMATERIALFVPROC) (GLenum face, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLMATERIALIPROC) (GLenum face, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLMATERIALIVPROC) (GLenum face, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLPOLYGONSTIPPLEPROC) (const GLubyte *mask);\ntypedef void (APIENTRYP PFNGLSHADEMODELPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLTEXENVFPROC) (GLenum target, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLTEXENVFVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLTEXENVIPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLTEXENVIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLTEXGENDPROC) (GLenum coord, GLenum pname, GLdouble param);\ntypedef void (APIENTRYP PFNGLTEXGENDVPROC) (GLenum coord, GLenum pname, const GLdouble *params);\ntypedef void (APIENTRYP PFNGLTEXGENFPROC) (GLenum coord, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLTEXGENFVPROC) (GLenum coord, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLTEXGENIPROC) (GLenum coord, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLTEXGENIVPROC) (GLenum coord, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLFEEDBACKBUFFERPROC) (GLsizei size, GLenum type, GLfloat *buffer);\ntypedef void (APIENTRYP PFNGLSELECTBUFFERPROC) (GLsizei size, GLuint *buffer);\ntypedef GLint (APIENTRYP PFNGLRENDERMODEPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLINITNAMESPROC) (void);\ntypedef void (APIENTRYP PFNGLLOADNAMEPROC) (GLuint name);\ntypedef void (APIENTRYP PFNGLPASSTHROUGHPROC) (GLfloat token);\ntypedef void (APIENTRYP PFNGLPOPNAMEPROC) (void);\ntypedef void (APIENTRYP PFNGLPUSHNAMEPROC) (GLuint name);\ntypedef void (APIENTRYP PFNGLCLEARACCUMPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\ntypedef void (APIENTRYP PFNGLCLEARINDEXPROC) (GLfloat c);\ntypedef void (APIENTRYP PFNGLINDEXMASKPROC) (GLuint mask);\ntypedef void (APIENTRYP PFNGLACCUMPROC) (GLenum op, GLfloat value);\ntypedef void (APIENTRYP PFNGLPOPATTRIBPROC) (void);\ntypedef void (APIENTRYP PFNGLPUSHATTRIBPROC) (GLbitfield mask);\ntypedef void (APIENTRYP PFNGLMAP1DPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);\ntypedef void (APIENTRYP PFNGLMAP1FPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);\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);\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);\ntypedef void (APIENTRYP PFNGLMAPGRID1DPROC) (GLint un, GLdouble u1, GLdouble u2);\ntypedef void (APIENTRYP PFNGLMAPGRID1FPROC) (GLint un, GLfloat u1, GLfloat u2);\ntypedef void (APIENTRYP PFNGLMAPGRID2DPROC) (GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);\ntypedef void (APIENTRYP PFNGLMAPGRID2FPROC) (GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);\ntypedef void (APIENTRYP PFNGLEVALCOORD1DPROC) (GLdouble u);\ntypedef void (APIENTRYP PFNGLEVALCOORD1DVPROC) (const GLdouble *u);\ntypedef void (APIENTRYP PFNGLEVALCOORD1FPROC) (GLfloat u);\ntypedef void (APIENTRYP PFNGLEVALCOORD1FVPROC) (const GLfloat *u);\ntypedef void (APIENTRYP PFNGLEVALCOORD2DPROC) (GLdouble u, GLdouble v);\ntypedef void (APIENTRYP PFNGLEVALCOORD2DVPROC) (const GLdouble *u);\ntypedef void (APIENTRYP PFNGLEVALCOORD2FPROC) (GLfloat u, GLfloat v);\ntypedef void (APIENTRYP PFNGLEVALCOORD2FVPROC) (const GLfloat *u);\ntypedef void (APIENTRYP PFNGLEVALMESH1PROC) (GLenum mode, GLint i1, GLint i2);\ntypedef void (APIENTRYP PFNGLEVALPOINT1PROC) (GLint i);\ntypedef void (APIENTRYP PFNGLEVALMESH2PROC) (GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);\ntypedef void (APIENTRYP PFNGLEVALPOINT2PROC) (GLint i, GLint j);\ntypedef void (APIENTRYP PFNGLALPHAFUNCPROC) (GLenum func, GLfloat ref);\ntypedef void (APIENTRYP PFNGLPIXELZOOMPROC) (GLfloat xfactor, GLfloat yfactor);\ntypedef void (APIENTRYP PFNGLPIXELTRANSFERFPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPIXELTRANSFERIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPIXELMAPFVPROC) (GLenum map, GLsizei mapsize, const GLfloat *values);\ntypedef void (APIENTRYP PFNGLPIXELMAPUIVPROC) (GLenum map, GLsizei mapsize, const GLuint *values);\ntypedef void (APIENTRYP PFNGLPIXELMAPUSVPROC) (GLenum map, GLsizei mapsize, const GLushort *values);\ntypedef void (APIENTRYP PFNGLCOPYPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);\ntypedef void (APIENTRYP PFNGLDRAWPIXELSPROC) (GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLGETCLIPPLANEPROC) (GLenum plane, GLdouble *equation);\ntypedef void (APIENTRYP PFNGLGETLIGHTFVPROC) (GLenum light, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETLIGHTIVPROC) (GLenum light, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMAPDVPROC) (GLenum target, GLenum query, GLdouble *v);\ntypedef void (APIENTRYP PFNGLGETMAPFVPROC) (GLenum target, GLenum query, GLfloat *v);\ntypedef void (APIENTRYP PFNGLGETMAPIVPROC) (GLenum target, GLenum query, GLint *v);\ntypedef void (APIENTRYP PFNGLGETMATERIALFVPROC) (GLenum face, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMATERIALIVPROC) (GLenum face, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPIXELMAPFVPROC) (GLenum map, GLfloat *values);\ntypedef void (APIENTRYP PFNGLGETPIXELMAPUIVPROC) (GLenum map, GLuint *values);\ntypedef void (APIENTRYP PFNGLGETPIXELMAPUSVPROC) (GLenum map, GLushort *values);\ntypedef void (APIENTRYP PFNGLGETPOLYGONSTIPPLEPROC) (GLubyte *mask);\ntypedef void (APIENTRYP PFNGLGETTEXENVFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETTEXENVIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETTEXGENDVPROC) (GLenum coord, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETTEXGENFVPROC) (GLenum coord, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETTEXGENIVPROC) (GLenum coord, GLenum pname, GLint *params);\ntypedef GLboolean (APIENTRYP PFNGLISLISTPROC) (GLuint list);\ntypedef void (APIENTRYP PFNGLFRUSTUMPROC) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\ntypedef void (APIENTRYP PFNGLLOADIDENTITYPROC) (void);\ntypedef void (APIENTRYP PFNGLLOADMATRIXFPROC) (const GLfloat *m);\ntypedef void (APIENTRYP PFNGLLOADMATRIXDPROC) (const GLdouble *m);\ntypedef void (APIENTRYP PFNGLMATRIXMODEPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLMULTMATRIXFPROC) (const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMULTMATRIXDPROC) (const GLdouble *m);\ntypedef void (APIENTRYP PFNGLORTHOPROC) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\ntypedef void (APIENTRYP PFNGLPOPMATRIXPROC) (void);\ntypedef void (APIENTRYP PFNGLPUSHMATRIXPROC) (void);\ntypedef void (APIENTRYP PFNGLROTATEDPROC) (GLdouble angle, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLROTATEFPROC) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLSCALEDPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLSCALEFPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTRANSLATEDPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLTRANSLATEFPROC) (GLfloat x, GLfloat y, GLfloat z);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCullFace (GLenum mode);\nGLAPI void APIENTRY glFrontFace (GLenum mode);\nGLAPI void APIENTRY glHint (GLenum target, GLenum mode);\nGLAPI void APIENTRY glLineWidth (GLfloat width);\nGLAPI void APIENTRY glPointSize (GLfloat size);\nGLAPI void APIENTRY glPolygonMode (GLenum face, GLenum mode);\nGLAPI void APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);\nGLAPI void APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glTexImage1D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glDrawBuffer (GLenum buf);\nGLAPI void APIENTRY glClear (GLbitfield mask);\nGLAPI void APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\nGLAPI void APIENTRY glClearStencil (GLint s);\nGLAPI void APIENTRY glClearDepth (GLdouble depth);\nGLAPI void APIENTRY glStencilMask (GLuint mask);\nGLAPI void APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);\nGLAPI void APIENTRY glDepthMask (GLboolean flag);\nGLAPI void APIENTRY glDisable (GLenum cap);\nGLAPI void APIENTRY glEnable (GLenum cap);\nGLAPI void APIENTRY glFinish (void);\nGLAPI void APIENTRY glFlush (void);\nGLAPI void APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);\nGLAPI void APIENTRY glLogicOp (GLenum opcode);\nGLAPI void APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);\nGLAPI void APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);\nGLAPI void APIENTRY glDepthFunc (GLenum func);\nGLAPI void APIENTRY glPixelStoref (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);\nGLAPI void APIENTRY glReadBuffer (GLenum src);\nGLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);\nGLAPI void APIENTRY glGetBooleanv (GLenum pname, GLboolean *data);\nGLAPI void APIENTRY glGetDoublev (GLenum pname, GLdouble *data);\nGLAPI GLenum APIENTRY glGetError (void);\nGLAPI void APIENTRY glGetFloatv (GLenum pname, GLfloat *data);\nGLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data);\nGLAPI const GLubyte *APIENTRY glGetString (GLenum name);\nGLAPI void APIENTRY glGetTexImage (GLenum target, GLint level, GLenum format, GLenum type, void *pixels);\nGLAPI void APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetTexLevelParameterfv (GLenum target, GLint level, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetTexLevelParameteriv (GLenum target, GLint level, GLenum pname, GLint *params);\nGLAPI GLboolean APIENTRY glIsEnabled (GLenum cap);\nGLAPI void APIENTRY glDepthRange (GLdouble n, GLdouble f);\nGLAPI void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glNewList (GLuint list, GLenum mode);\nGLAPI void APIENTRY glEndList (void);\nGLAPI void APIENTRY glCallList (GLuint list);\nGLAPI void APIENTRY glCallLists (GLsizei n, GLenum type, const void *lists);\nGLAPI void APIENTRY glDeleteLists (GLuint list, GLsizei range);\nGLAPI GLuint APIENTRY glGenLists (GLsizei range);\nGLAPI void APIENTRY glListBase (GLuint base);\nGLAPI void APIENTRY glBegin (GLenum mode);\nGLAPI void APIENTRY glBitmap (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap);\nGLAPI void APIENTRY glColor3b (GLbyte red, GLbyte green, GLbyte blue);\nGLAPI void APIENTRY glColor3bv (const GLbyte *v);\nGLAPI void APIENTRY glColor3d (GLdouble red, GLdouble green, GLdouble blue);\nGLAPI void APIENTRY glColor3dv (const GLdouble *v);\nGLAPI void APIENTRY glColor3f (GLfloat red, GLfloat green, GLfloat blue);\nGLAPI void APIENTRY glColor3fv (const GLfloat *v);\nGLAPI void APIENTRY glColor3i (GLint red, GLint green, GLint blue);\nGLAPI void APIENTRY glColor3iv (const GLint *v);\nGLAPI void APIENTRY glColor3s (GLshort red, GLshort green, GLshort blue);\nGLAPI void APIENTRY glColor3sv (const GLshort *v);\nGLAPI void APIENTRY glColor3ub (GLubyte red, GLubyte green, GLubyte blue);\nGLAPI void APIENTRY glColor3ubv (const GLubyte *v);\nGLAPI void APIENTRY glColor3ui (GLuint red, GLuint green, GLuint blue);\nGLAPI void APIENTRY glColor3uiv (const GLuint *v);\nGLAPI void APIENTRY glColor3us (GLushort red, GLushort green, GLushort blue);\nGLAPI void APIENTRY glColor3usv (const GLushort *v);\nGLAPI void APIENTRY glColor4b (GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);\nGLAPI void APIENTRY glColor4bv (const GLbyte *v);\nGLAPI void APIENTRY glColor4d (GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);\nGLAPI void APIENTRY glColor4dv (const GLdouble *v);\nGLAPI void APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\nGLAPI void APIENTRY glColor4fv (const GLfloat *v);\nGLAPI void APIENTRY glColor4i (GLint red, GLint green, GLint blue, GLint alpha);\nGLAPI void APIENTRY glColor4iv (const GLint *v);\nGLAPI void APIENTRY glColor4s (GLshort red, GLshort green, GLshort blue, GLshort alpha);\nGLAPI void APIENTRY glColor4sv (const GLshort *v);\nGLAPI void APIENTRY glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);\nGLAPI void APIENTRY glColor4ubv (const GLubyte *v);\nGLAPI void APIENTRY glColor4ui (GLuint red, GLuint green, GLuint blue, GLuint alpha);\nGLAPI void APIENTRY glColor4uiv (const GLuint *v);\nGLAPI void APIENTRY glColor4us (GLushort red, GLushort green, GLushort blue, GLushort alpha);\nGLAPI void APIENTRY glColor4usv (const GLushort *v);\nGLAPI void APIENTRY glEdgeFlag (GLboolean flag);\nGLAPI void APIENTRY glEdgeFlagv (const GLboolean *flag);\nGLAPI void APIENTRY glEnd (void);\nGLAPI void APIENTRY glIndexd (GLdouble c);\nGLAPI void APIENTRY glIndexdv (const GLdouble *c);\nGLAPI void APIENTRY glIndexf (GLfloat c);\nGLAPI void APIENTRY glIndexfv (const GLfloat *c);\nGLAPI void APIENTRY glIndexi (GLint c);\nGLAPI void APIENTRY glIndexiv (const GLint *c);\nGLAPI void APIENTRY glIndexs (GLshort c);\nGLAPI void APIENTRY glIndexsv (const GLshort *c);\nGLAPI void APIENTRY glNormal3b (GLbyte nx, GLbyte ny, GLbyte nz);\nGLAPI void APIENTRY glNormal3bv (const GLbyte *v);\nGLAPI void APIENTRY glNormal3d (GLdouble nx, GLdouble ny, GLdouble nz);\nGLAPI void APIENTRY glNormal3dv (const GLdouble *v);\nGLAPI void APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);\nGLAPI void APIENTRY glNormal3fv (const GLfloat *v);\nGLAPI void APIENTRY glNormal3i (GLint nx, GLint ny, GLint nz);\nGLAPI void APIENTRY glNormal3iv (const GLint *v);\nGLAPI void APIENTRY glNormal3s (GLshort nx, GLshort ny, GLshort nz);\nGLAPI void APIENTRY glNormal3sv (const GLshort *v);\nGLAPI void APIENTRY glRasterPos2d (GLdouble x, GLdouble y);\nGLAPI void APIENTRY glRasterPos2dv (const GLdouble *v);\nGLAPI void APIENTRY glRasterPos2f (GLfloat x, GLfloat y);\nGLAPI void APIENTRY glRasterPos2fv (const GLfloat *v);\nGLAPI void APIENTRY glRasterPos2i (GLint x, GLint y);\nGLAPI void APIENTRY glRasterPos2iv (const GLint *v);\nGLAPI void APIENTRY glRasterPos2s (GLshort x, GLshort y);\nGLAPI void APIENTRY glRasterPos2sv (const GLshort *v);\nGLAPI void APIENTRY glRasterPos3d (GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glRasterPos3dv (const GLdouble *v);\nGLAPI void APIENTRY glRasterPos3f (GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glRasterPos3fv (const GLfloat *v);\nGLAPI void APIENTRY glRasterPos3i (GLint x, GLint y, GLint z);\nGLAPI void APIENTRY glRasterPos3iv (const GLint *v);\nGLAPI void APIENTRY glRasterPos3s (GLshort x, GLshort y, GLshort z);\nGLAPI void APIENTRY glRasterPos3sv (const GLshort *v);\nGLAPI void APIENTRY glRasterPos4d (GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glRasterPos4dv (const GLdouble *v);\nGLAPI void APIENTRY glRasterPos4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glRasterPos4fv (const GLfloat *v);\nGLAPI void APIENTRY glRasterPos4i (GLint x, GLint y, GLint z, GLint w);\nGLAPI void APIENTRY glRasterPos4iv (const GLint *v);\nGLAPI void APIENTRY glRasterPos4s (GLshort x, GLshort y, GLshort z, GLshort w);\nGLAPI void APIENTRY glRasterPos4sv (const GLshort *v);\nGLAPI void APIENTRY glRectd (GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);\nGLAPI void APIENTRY glRectdv (const GLdouble *v1, const GLdouble *v2);\nGLAPI void APIENTRY glRectf (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);\nGLAPI void APIENTRY glRectfv (const GLfloat *v1, const GLfloat *v2);\nGLAPI void APIENTRY glRecti (GLint x1, GLint y1, GLint x2, GLint y2);\nGLAPI void APIENTRY glRectiv (const GLint *v1, const GLint *v2);\nGLAPI void APIENTRY glRects (GLshort x1, GLshort y1, GLshort x2, GLshort y2);\nGLAPI void APIENTRY glRectsv (const GLshort *v1, const GLshort *v2);\nGLAPI void APIENTRY glTexCoord1d (GLdouble s);\nGLAPI void APIENTRY glTexCoord1dv (const GLdouble *v);\nGLAPI void APIENTRY glTexCoord1f (GLfloat s);\nGLAPI void APIENTRY glTexCoord1fv (const GLfloat *v);\nGLAPI void APIENTRY glTexCoord1i (GLint s);\nGLAPI void APIENTRY glTexCoord1iv (const GLint *v);\nGLAPI void APIENTRY glTexCoord1s (GLshort s);\nGLAPI void APIENTRY glTexCoord1sv (const GLshort *v);\nGLAPI void APIENTRY glTexCoord2d (GLdouble s, GLdouble t);\nGLAPI void APIENTRY glTexCoord2dv (const GLdouble *v);\nGLAPI void APIENTRY glTexCoord2f (GLfloat s, GLfloat t);\nGLAPI void APIENTRY glTexCoord2fv (const GLfloat *v);\nGLAPI void APIENTRY glTexCoord2i (GLint s, GLint t);\nGLAPI void APIENTRY glTexCoord2iv (const GLint *v);\nGLAPI void APIENTRY glTexCoord2s (GLshort s, GLshort t);\nGLAPI void APIENTRY glTexCoord2sv (const GLshort *v);\nGLAPI void APIENTRY glTexCoord3d (GLdouble s, GLdouble t, GLdouble r);\nGLAPI void APIENTRY glTexCoord3dv (const GLdouble *v);\nGLAPI void APIENTRY glTexCoord3f (GLfloat s, GLfloat t, GLfloat r);\nGLAPI void APIENTRY glTexCoord3fv (const GLfloat *v);\nGLAPI void APIENTRY glTexCoord3i (GLint s, GLint t, GLint r);\nGLAPI void APIENTRY glTexCoord3iv (const GLint *v);\nGLAPI void APIENTRY glTexCoord3s (GLshort s, GLshort t, GLshort r);\nGLAPI void APIENTRY glTexCoord3sv (const GLshort *v);\nGLAPI void APIENTRY glTexCoord4d (GLdouble s, GLdouble t, GLdouble r, GLdouble q);\nGLAPI void APIENTRY glTexCoord4dv (const GLdouble *v);\nGLAPI void APIENTRY glTexCoord4f (GLfloat s, GLfloat t, GLfloat r, GLfloat q);\nGLAPI void APIENTRY glTexCoord4fv (const GLfloat *v);\nGLAPI void APIENTRY glTexCoord4i (GLint s, GLint t, GLint r, GLint q);\nGLAPI void APIENTRY glTexCoord4iv (const GLint *v);\nGLAPI void APIENTRY glTexCoord4s (GLshort s, GLshort t, GLshort r, GLshort q);\nGLAPI void APIENTRY glTexCoord4sv (const GLshort *v);\nGLAPI void APIENTRY glVertex2d (GLdouble x, GLdouble y);\nGLAPI void APIENTRY glVertex2dv (const GLdouble *v);\nGLAPI void APIENTRY glVertex2f (GLfloat x, GLfloat y);\nGLAPI void APIENTRY glVertex2fv (const GLfloat *v);\nGLAPI void APIENTRY glVertex2i (GLint x, GLint y);\nGLAPI void APIENTRY glVertex2iv (const GLint *v);\nGLAPI void APIENTRY glVertex2s (GLshort x, GLshort y);\nGLAPI void APIENTRY glVertex2sv (const GLshort *v);\nGLAPI void APIENTRY glVertex3d (GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glVertex3dv (const GLdouble *v);\nGLAPI void APIENTRY glVertex3f (GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glVertex3fv (const GLfloat *v);\nGLAPI void APIENTRY glVertex3i (GLint x, GLint y, GLint z);\nGLAPI void APIENTRY glVertex3iv (const GLint *v);\nGLAPI void APIENTRY glVertex3s (GLshort x, GLshort y, GLshort z);\nGLAPI void APIENTRY glVertex3sv (const GLshort *v);\nGLAPI void APIENTRY glVertex4d (GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glVertex4dv (const GLdouble *v);\nGLAPI void APIENTRY glVertex4f (GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glVertex4fv (const GLfloat *v);\nGLAPI void APIENTRY glVertex4i (GLint x, GLint y, GLint z, GLint w);\nGLAPI void APIENTRY glVertex4iv (const GLint *v);\nGLAPI void APIENTRY glVertex4s (GLshort x, GLshort y, GLshort z, GLshort w);\nGLAPI void APIENTRY glVertex4sv (const GLshort *v);\nGLAPI void APIENTRY glClipPlane (GLenum plane, const GLdouble *equation);\nGLAPI void APIENTRY glColorMaterial (GLenum face, GLenum mode);\nGLAPI void APIENTRY glFogf (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glFogfv (GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glFogi (GLenum pname, GLint param);\nGLAPI void APIENTRY glFogiv (GLenum pname, const GLint *params);\nGLAPI void APIENTRY glLightf (GLenum light, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glLighti (GLenum light, GLenum pname, GLint param);\nGLAPI void APIENTRY glLightiv (GLenum light, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glLightModelf (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glLightModelfv (GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glLightModeli (GLenum pname, GLint param);\nGLAPI void APIENTRY glLightModeliv (GLenum pname, const GLint *params);\nGLAPI void APIENTRY glLineStipple (GLint factor, GLushort pattern);\nGLAPI void APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glMateriali (GLenum face, GLenum pname, GLint param);\nGLAPI void APIENTRY glMaterialiv (GLenum face, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glPolygonStipple (const GLubyte *mask);\nGLAPI void APIENTRY glShadeModel (GLenum mode);\nGLAPI void APIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glTexEnvi (GLenum target, GLenum pname, GLint param);\nGLAPI void APIENTRY glTexEnviv (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glTexGend (GLenum coord, GLenum pname, GLdouble param);\nGLAPI void APIENTRY glTexGendv (GLenum coord, GLenum pname, const GLdouble *params);\nGLAPI void APIENTRY glTexGenf (GLenum coord, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glTexGenfv (GLenum coord, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glTexGeni (GLenum coord, GLenum pname, GLint param);\nGLAPI void APIENTRY glTexGeniv (GLenum coord, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glFeedbackBuffer (GLsizei size, GLenum type, GLfloat *buffer);\nGLAPI void APIENTRY glSelectBuffer (GLsizei size, GLuint *buffer);\nGLAPI GLint APIENTRY glRenderMode (GLenum mode);\nGLAPI void APIENTRY glInitNames (void);\nGLAPI void APIENTRY glLoadName (GLuint name);\nGLAPI void APIENTRY glPassThrough (GLfloat token);\nGLAPI void APIENTRY glPopName (void);\nGLAPI void APIENTRY glPushName (GLuint name);\nGLAPI void APIENTRY glClearAccum (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\nGLAPI void APIENTRY glClearIndex (GLfloat c);\nGLAPI void APIENTRY glIndexMask (GLuint mask);\nGLAPI void APIENTRY glAccum (GLenum op, GLfloat value);\nGLAPI void APIENTRY glPopAttrib (void);\nGLAPI void APIENTRY glPushAttrib (GLbitfield mask);\nGLAPI void APIENTRY glMap1d (GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);\nGLAPI void APIENTRY glMap1f (GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);\nGLAPI void APIENTRY glMap2d (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);\nGLAPI void APIENTRY glMap2f (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);\nGLAPI void APIENTRY glMapGrid1d (GLint un, GLdouble u1, GLdouble u2);\nGLAPI void APIENTRY glMapGrid1f (GLint un, GLfloat u1, GLfloat u2);\nGLAPI void APIENTRY glMapGrid2d (GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2);\nGLAPI void APIENTRY glMapGrid2f (GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2);\nGLAPI void APIENTRY glEvalCoord1d (GLdouble u);\nGLAPI void APIENTRY glEvalCoord1dv (const GLdouble *u);\nGLAPI void APIENTRY glEvalCoord1f (GLfloat u);\nGLAPI void APIENTRY glEvalCoord1fv (const GLfloat *u);\nGLAPI void APIENTRY glEvalCoord2d (GLdouble u, GLdouble v);\nGLAPI void APIENTRY glEvalCoord2dv (const GLdouble *u);\nGLAPI void APIENTRY glEvalCoord2f (GLfloat u, GLfloat v);\nGLAPI void APIENTRY glEvalCoord2fv (const GLfloat *u);\nGLAPI void APIENTRY glEvalMesh1 (GLenum mode, GLint i1, GLint i2);\nGLAPI void APIENTRY glEvalPoint1 (GLint i);\nGLAPI void APIENTRY glEvalMesh2 (GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2);\nGLAPI void APIENTRY glEvalPoint2 (GLint i, GLint j);\nGLAPI void APIENTRY glAlphaFunc (GLenum func, GLfloat ref);\nGLAPI void APIENTRY glPixelZoom (GLfloat xfactor, GLfloat yfactor);\nGLAPI void APIENTRY glPixelTransferf (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glPixelTransferi (GLenum pname, GLint param);\nGLAPI void APIENTRY glPixelMapfv (GLenum map, GLsizei mapsize, const GLfloat *values);\nGLAPI void APIENTRY glPixelMapuiv (GLenum map, GLsizei mapsize, const GLuint *values);\nGLAPI void APIENTRY glPixelMapusv (GLenum map, GLsizei mapsize, const GLushort *values);\nGLAPI void APIENTRY glCopyPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum type);\nGLAPI void APIENTRY glDrawPixels (GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glGetClipPlane (GLenum plane, GLdouble *equation);\nGLAPI void APIENTRY glGetLightfv (GLenum light, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetLightiv (GLenum light, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetMapdv (GLenum target, GLenum query, GLdouble *v);\nGLAPI void APIENTRY glGetMapfv (GLenum target, GLenum query, GLfloat *v);\nGLAPI void APIENTRY glGetMapiv (GLenum target, GLenum query, GLint *v);\nGLAPI void APIENTRY glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetMaterialiv (GLenum face, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetPixelMapfv (GLenum map, GLfloat *values);\nGLAPI void APIENTRY glGetPixelMapuiv (GLenum map, GLuint *values);\nGLAPI void APIENTRY glGetPixelMapusv (GLenum map, GLushort *values);\nGLAPI void APIENTRY glGetPolygonStipple (GLubyte *mask);\nGLAPI void APIENTRY glGetTexEnvfv (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetTexEnviv (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetTexGendv (GLenum coord, GLenum pname, GLdouble *params);\nGLAPI void APIENTRY glGetTexGenfv (GLenum coord, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetTexGeniv (GLenum coord, GLenum pname, GLint *params);\nGLAPI GLboolean APIENTRY glIsList (GLuint list);\nGLAPI void APIENTRY glFrustum (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\nGLAPI void APIENTRY glLoadIdentity (void);\nGLAPI void APIENTRY glLoadMatrixf (const GLfloat *m);\nGLAPI void APIENTRY glLoadMatrixd (const GLdouble *m);\nGLAPI void APIENTRY glMatrixMode (GLenum mode);\nGLAPI void APIENTRY glMultMatrixf (const GLfloat *m);\nGLAPI void APIENTRY glMultMatrixd (const GLdouble *m);\nGLAPI void APIENTRY glOrtho (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\nGLAPI void APIENTRY glPopMatrix (void);\nGLAPI void APIENTRY glPushMatrix (void);\nGLAPI void APIENTRY glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glScaled (GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glScalef (GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glTranslated (GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z);\n#endif\n#endif /* GL_VERSION_1_0 */\n\n#ifndef GL_VERSION_1_1\n#define GL_VERSION_1_1 1\ntypedef khronos_float_t GLclampf;\ntypedef double GLclampd;\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\ntypedef void (APIENTRYP PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices);\ntypedef void (APIENTRYP PFNGLGETPOINTERVPROC) (GLenum pname, void **params);\ntypedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units);\ntypedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\ntypedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);\ntypedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures);\ntypedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);\ntypedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC) (GLuint texture);\ntypedef void (APIENTRYP PFNGLARRAYELEMENTPROC) (GLint i);\ntypedef void (APIENTRYP PFNGLCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLDISABLECLIENTSTATEPROC) (GLenum array);\ntypedef void (APIENTRYP PFNGLEDGEFLAGPOINTERPROC) (GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLENABLECLIENTSTATEPROC) (GLenum array);\ntypedef void (APIENTRYP PFNGLINDEXPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLINTERLEAVEDARRAYSPROC) (GLenum format, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLNORMALPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLTEXCOORDPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLVERTEXPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences);\ntypedef void (APIENTRYP PFNGLPRIORITIZETEXTURESPROC) (GLsizei n, const GLuint *textures, const GLfloat *priorities);\ntypedef void (APIENTRYP PFNGLINDEXUBPROC) (GLubyte c);\ntypedef void (APIENTRYP PFNGLINDEXUBVPROC) (const GLubyte *c);\ntypedef void (APIENTRYP PFNGLPOPCLIENTATTRIBPROC) (void);\ntypedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBPROC) (GLbitfield mask);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);\nGLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices);\nGLAPI void APIENTRY glGetPointerv (GLenum pname, void **params);\nGLAPI void APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);\nGLAPI void APIENTRY glCopyTexImage1D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\nGLAPI void APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\nGLAPI void APIENTRY glCopyTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\nGLAPI void APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture);\nGLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);\nGLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures);\nGLAPI GLboolean APIENTRY glIsTexture (GLuint texture);\nGLAPI void APIENTRY glArrayElement (GLint i);\nGLAPI void APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glDisableClientState (GLenum array);\nGLAPI void APIENTRY glEdgeFlagPointer (GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glEnableClientState (GLenum array);\nGLAPI void APIENTRY glIndexPointer (GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glInterleavedArrays (GLenum format, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glNormalPointer (GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI GLboolean APIENTRY glAreTexturesResident (GLsizei n, const GLuint *textures, GLboolean *residences);\nGLAPI void APIENTRY glPrioritizeTextures (GLsizei n, const GLuint *textures, const GLfloat *priorities);\nGLAPI void APIENTRY glIndexub (GLubyte c);\nGLAPI void APIENTRY glIndexubv (const GLubyte *c);\nGLAPI void APIENTRY glPopClientAttrib (void);\nGLAPI void APIENTRY glPushClientAttrib (GLbitfield mask);\n#endif\n#endif /* GL_VERSION_1_1 */\n\n#ifndef GL_VERSION_1_2\n#define GL_VERSION_1_2 1\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\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);\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);\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);\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);\nGLAPI void APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\n#endif\n#endif /* GL_VERSION_1_2 */\n\n#ifndef GL_VERSION_1_3\n#define GL_VERSION_1_3 1\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\ntypedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);\ntypedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC) (GLfloat value, GLboolean invert);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);\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);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, void *img);\ntypedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC) (GLenum texture);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC) (GLenum target, GLdouble s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, GLfloat s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC) (GLenum target, GLint s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC) (GLenum target, GLshort s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC) (GLenum target, GLdouble s, GLdouble t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, GLfloat s, GLfloat t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC) (GLenum target, GLint s, GLint t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC) (GLenum target, GLshort s, GLshort t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC) (GLenum target, GLint s, GLint t, GLint r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC) (GLenum target, GLshort s, GLshort t, GLshort r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC) (const GLfloat *m);\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC) (const GLdouble *m);\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC) (const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC) (const GLdouble *m);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glActiveTexture (GLenum texture);\nGLAPI void APIENTRY glSampleCoverage (GLfloat value, GLboolean invert);\nGLAPI void APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glGetCompressedTexImage (GLenum target, GLint level, void *img);\nGLAPI void APIENTRY glClientActiveTexture (GLenum texture);\nGLAPI void APIENTRY glMultiTexCoord1d (GLenum target, GLdouble s);\nGLAPI void APIENTRY glMultiTexCoord1dv (GLenum target, const GLdouble *v);\nGLAPI void APIENTRY glMultiTexCoord1f (GLenum target, GLfloat s);\nGLAPI void APIENTRY glMultiTexCoord1fv (GLenum target, const GLfloat *v);\nGLAPI void APIENTRY glMultiTexCoord1i (GLenum target, GLint s);\nGLAPI void APIENTRY glMultiTexCoord1iv (GLenum target, const GLint *v);\nGLAPI void APIENTRY glMultiTexCoord1s (GLenum target, GLshort s);\nGLAPI void APIENTRY glMultiTexCoord1sv (GLenum target, const GLshort *v);\nGLAPI void APIENTRY glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t);\nGLAPI void APIENTRY glMultiTexCoord2dv (GLenum target, const GLdouble *v);\nGLAPI void APIENTRY glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t);\nGLAPI void APIENTRY glMultiTexCoord2fv (GLenum target, const GLfloat *v);\nGLAPI void APIENTRY glMultiTexCoord2i (GLenum target, GLint s, GLint t);\nGLAPI void APIENTRY glMultiTexCoord2iv (GLenum target, const GLint *v);\nGLAPI void APIENTRY glMultiTexCoord2s (GLenum target, GLshort s, GLshort t);\nGLAPI void APIENTRY glMultiTexCoord2sv (GLenum target, const GLshort *v);\nGLAPI void APIENTRY glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r);\nGLAPI void APIENTRY glMultiTexCoord3dv (GLenum target, const GLdouble *v);\nGLAPI void APIENTRY glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r);\nGLAPI void APIENTRY glMultiTexCoord3fv (GLenum target, const GLfloat *v);\nGLAPI void APIENTRY glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r);\nGLAPI void APIENTRY glMultiTexCoord3iv (GLenum target, const GLint *v);\nGLAPI void APIENTRY glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r);\nGLAPI void APIENTRY glMultiTexCoord3sv (GLenum target, const GLshort *v);\nGLAPI void APIENTRY glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);\nGLAPI void APIENTRY glMultiTexCoord4dv (GLenum target, const GLdouble *v);\nGLAPI void APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);\nGLAPI void APIENTRY glMultiTexCoord4fv (GLenum target, const GLfloat *v);\nGLAPI void APIENTRY glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q);\nGLAPI void APIENTRY glMultiTexCoord4iv (GLenum target, const GLint *v);\nGLAPI void APIENTRY glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);\nGLAPI void APIENTRY glMultiTexCoord4sv (GLenum target, const GLshort *v);\nGLAPI void APIENTRY glLoadTransposeMatrixf (const GLfloat *m);\nGLAPI void APIENTRY glLoadTransposeMatrixd (const GLdouble *m);\nGLAPI void APIENTRY glMultTransposeMatrixf (const GLfloat *m);\nGLAPI void APIENTRY glMultTransposeMatrixd (const GLdouble *m);\n#endif\n#endif /* GL_VERSION_1_3 */\n\n#ifndef GL_VERSION_1_4\n#define GL_VERSION_1_4 1\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\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLFOGCOORDFPROC) (GLfloat coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDFVPROC) (const GLfloat *coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDDPROC) (GLdouble coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDDVPROC) (const GLdouble *coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC) (GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC) (GLint red, GLint green, GLint blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC) (const GLubyte *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC) (const GLuint *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC) (const GLushort *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DPROC) (GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FPROC) (GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IPROC) (GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SPROC) (GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IPROC) (GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SPROC) (GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\nGLAPI void APIENTRY glMultiDrawArrays (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount);\nGLAPI void APIENTRY glMultiDrawElements (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount);\nGLAPI void APIENTRY glPointParameterf (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glPointParameteri (GLenum pname, GLint param);\nGLAPI void APIENTRY glPointParameteriv (GLenum pname, const GLint *params);\nGLAPI void APIENTRY glFogCoordf (GLfloat coord);\nGLAPI void APIENTRY glFogCoordfv (const GLfloat *coord);\nGLAPI void APIENTRY glFogCoordd (GLdouble coord);\nGLAPI void APIENTRY glFogCoorddv (const GLdouble *coord);\nGLAPI void APIENTRY glFogCoordPointer (GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue);\nGLAPI void APIENTRY glSecondaryColor3bv (const GLbyte *v);\nGLAPI void APIENTRY glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue);\nGLAPI void APIENTRY glSecondaryColor3dv (const GLdouble *v);\nGLAPI void APIENTRY glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue);\nGLAPI void APIENTRY glSecondaryColor3fv (const GLfloat *v);\nGLAPI void APIENTRY glSecondaryColor3i (GLint red, GLint green, GLint blue);\nGLAPI void APIENTRY glSecondaryColor3iv (const GLint *v);\nGLAPI void APIENTRY glSecondaryColor3s (GLshort red, GLshort green, GLshort blue);\nGLAPI void APIENTRY glSecondaryColor3sv (const GLshort *v);\nGLAPI void APIENTRY glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue);\nGLAPI void APIENTRY glSecondaryColor3ubv (const GLubyte *v);\nGLAPI void APIENTRY glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue);\nGLAPI void APIENTRY glSecondaryColor3uiv (const GLuint *v);\nGLAPI void APIENTRY glSecondaryColor3us (GLushort red, GLushort green, GLushort blue);\nGLAPI void APIENTRY glSecondaryColor3usv (const GLushort *v);\nGLAPI void APIENTRY glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glWindowPos2d (GLdouble x, GLdouble y);\nGLAPI void APIENTRY glWindowPos2dv (const GLdouble *v);\nGLAPI void APIENTRY glWindowPos2f (GLfloat x, GLfloat y);\nGLAPI void APIENTRY glWindowPos2fv (const GLfloat *v);\nGLAPI void APIENTRY glWindowPos2i (GLint x, GLint y);\nGLAPI void APIENTRY glWindowPos2iv (const GLint *v);\nGLAPI void APIENTRY glWindowPos2s (GLshort x, GLshort y);\nGLAPI void APIENTRY glWindowPos2sv (const GLshort *v);\nGLAPI void APIENTRY glWindowPos3d (GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glWindowPos3dv (const GLdouble *v);\nGLAPI void APIENTRY glWindowPos3f (GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glWindowPos3fv (const GLfloat *v);\nGLAPI void APIENTRY glWindowPos3i (GLint x, GLint y, GLint z);\nGLAPI void APIENTRY glWindowPos3iv (const GLint *v);\nGLAPI void APIENTRY glWindowPos3s (GLshort x, GLshort y, GLshort z);\nGLAPI void APIENTRY glWindowPos3sv (const GLshort *v);\nGLAPI void APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\nGLAPI void APIENTRY glBlendEquation (GLenum mode);\n#endif\n#endif /* GL_VERSION_1_4 */\n\n#ifndef GL_VERSION_1_5\n#define GL_VERSION_1_5 1\ntypedef khronos_ssize_t GLsizeiptr;\ntypedef khronos_intptr_t GLintptr;\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\ntypedef void (APIENTRYP PFNGLGENQUERIESPROC) (GLsizei n, GLuint *ids);\ntypedef void (APIENTRYP PFNGLDELETEQUERIESPROC) (GLsizei n, const GLuint *ids);\ntypedef GLboolean (APIENTRYP PFNGLISQUERYPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLBEGINQUERYPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP PFNGLENDQUERYPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC) (GLuint id, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);\ntypedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);\ntypedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);\ntypedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);\ntypedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);\ntypedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, void *data);\ntypedef void *(APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);\ntypedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, void **params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenQueries (GLsizei n, GLuint *ids);\nGLAPI void APIENTRY glDeleteQueries (GLsizei n, const GLuint *ids);\nGLAPI GLboolean APIENTRY glIsQuery (GLuint id);\nGLAPI void APIENTRY glBeginQuery (GLenum target, GLuint id);\nGLAPI void APIENTRY glEndQuery (GLenum target);\nGLAPI void APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params);\nGLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);\nGLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);\nGLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);\nGLAPI GLboolean APIENTRY glIsBuffer (GLuint buffer);\nGLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);\nGLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);\nGLAPI void APIENTRY glGetBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, void *data);\nGLAPI void *APIENTRY glMapBuffer (GLenum target, GLenum access);\nGLAPI GLboolean APIENTRY glUnmapBuffer (GLenum target);\nGLAPI void APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, void **params);\n#endif\n#endif /* GL_VERSION_1_5 */\n\n#ifndef GL_VERSION_2_0\n#define GL_VERSION_2_0 1\ntypedef char GLchar;\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\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC) (GLenum modeRGB, GLenum modeAlpha);\ntypedef void (APIENTRYP PFNGLDRAWBUFFERSPROC) (GLsizei n, const GLenum *bufs);\ntypedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);\ntypedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC) (GLenum face, GLenum func, GLint ref, GLuint mask);\ntypedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC) (GLenum face, GLuint mask);\ntypedef void (APIENTRYP PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);\ntypedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar *name);\ntypedef void (APIENTRYP PFNGLCOMPILESHADERPROC) (GLuint shader);\ntypedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC) (void);\ntypedef GLuint (APIENTRYP PFNGLCREATESHADERPROC) (GLenum type);\ntypedef void (APIENTRYP PFNGLDELETEPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP PFNGLDELETESHADERPROC) (GLuint shader);\ntypedef void (APIENTRYP PFNGLDETACHSHADERPROC) (GLuint program, GLuint shader);\ntypedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC) (GLuint index);\ntypedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);\ntypedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);\ntypedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);\ntypedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP PFNGLGETPROGRAMIVPROC) (GLuint program, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\ntypedef void (APIENTRYP PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\ntypedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);\ntypedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP PFNGLGETUNIFORMFVPROC) (GLuint program, GLint location, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETUNIFORMIVPROC) (GLuint program, GLint location, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC) (GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC) (GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC) (GLuint index, GLenum pname, void **pointer);\ntypedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC) (GLuint program);\ntypedef GLboolean (APIENTRYP PFNGLISSHADERPROC) (GLuint shader);\ntypedef void (APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);\ntypedef void (APIENTRYP PFNGLUSEPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0);\ntypedef void (APIENTRYP PFNGLUNIFORM2FPROC) (GLint location, GLfloat v0, GLfloat v1);\ntypedef void (APIENTRYP PFNGLUNIFORM3FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (APIENTRYP PFNGLUNIFORM4FPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (APIENTRYP PFNGLUNIFORM1IPROC) (GLint location, GLint v0);\ntypedef void (APIENTRYP PFNGLUNIFORM2IPROC) (GLint location, GLint v0, GLint v1);\ntypedef void (APIENTRYP PFNGLUNIFORM3IPROC) (GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (APIENTRYP PFNGLUNIFORM4IPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (APIENTRYP PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4FVPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM1IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4IVPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC) (GLuint index, GLfloat x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC) (GLuint index, GLshort x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC) (GLuint index, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC) (GLuint index, GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC) (GLuint index, GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);\nGLAPI void APIENTRY glDrawBuffers (GLsizei n, const GLenum *bufs);\nGLAPI void APIENTRY glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);\nGLAPI void APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);\nGLAPI void APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);\nGLAPI void APIENTRY glAttachShader (GLuint program, GLuint shader);\nGLAPI void APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar *name);\nGLAPI void APIENTRY glCompileShader (GLuint shader);\nGLAPI GLuint APIENTRY glCreateProgram (void);\nGLAPI GLuint APIENTRY glCreateShader (GLenum type);\nGLAPI void APIENTRY glDeleteProgram (GLuint program);\nGLAPI void APIENTRY glDeleteShader (GLuint shader);\nGLAPI void APIENTRY glDetachShader (GLuint program, GLuint shader);\nGLAPI void APIENTRY glDisableVertexAttribArray (GLuint index);\nGLAPI void APIENTRY glEnableVertexAttribArray (GLuint index);\nGLAPI void APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);\nGLAPI void APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);\nGLAPI void APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders);\nGLAPI GLint APIENTRY glGetAttribLocation (GLuint program, const GLchar *name);\nGLAPI void APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\nGLAPI void APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\nGLAPI void APIENTRY glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source);\nGLAPI GLint APIENTRY glGetUniformLocation (GLuint program, const GLchar *name);\nGLAPI void APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params);\nGLAPI void APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params);\nGLAPI void APIENTRY glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params);\nGLAPI void APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer);\nGLAPI GLboolean APIENTRY glIsProgram (GLuint program);\nGLAPI GLboolean APIENTRY glIsShader (GLuint shader);\nGLAPI void APIENTRY glLinkProgram (GLuint program);\nGLAPI void APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length);\nGLAPI void APIENTRY glUseProgram (GLuint program);\nGLAPI void APIENTRY glUniform1f (GLint location, GLfloat v0);\nGLAPI void APIENTRY glUniform2f (GLint location, GLfloat v0, GLfloat v1);\nGLAPI void APIENTRY glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\nGLAPI void APIENTRY glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\nGLAPI void APIENTRY glUniform1i (GLint location, GLint v0);\nGLAPI void APIENTRY glUniform2i (GLint location, GLint v0, GLint v1);\nGLAPI void APIENTRY glUniform3i (GLint location, GLint v0, GLint v1, GLint v2);\nGLAPI void APIENTRY glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\nGLAPI void APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glValidateProgram (GLuint program);\nGLAPI void APIENTRY glVertexAttrib1d (GLuint index, GLdouble x);\nGLAPI void APIENTRY glVertexAttrib1dv (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib1f (GLuint index, GLfloat x);\nGLAPI void APIENTRY glVertexAttrib1fv (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib1s (GLuint index, GLshort x);\nGLAPI void APIENTRY glVertexAttrib1sv (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y);\nGLAPI void APIENTRY glVertexAttrib2dv (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y);\nGLAPI void APIENTRY glVertexAttrib2fv (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib2s (GLuint index, GLshort x, GLshort y);\nGLAPI void APIENTRY glVertexAttrib2sv (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glVertexAttrib3dv (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glVertexAttrib3fv (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z);\nGLAPI void APIENTRY glVertexAttrib3sv (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib4Nbv (GLuint index, const GLbyte *v);\nGLAPI void APIENTRY glVertexAttrib4Niv (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttrib4Nsv (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\nGLAPI void APIENTRY glVertexAttrib4Nubv (GLuint index, const GLubyte *v);\nGLAPI void APIENTRY glVertexAttrib4Nuiv (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttrib4Nusv (GLuint index, const GLushort *v);\nGLAPI void APIENTRY glVertexAttrib4bv (GLuint index, const GLbyte *v);\nGLAPI void APIENTRY glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glVertexAttrib4dv (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glVertexAttrib4fv (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib4iv (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\nGLAPI void APIENTRY glVertexAttrib4sv (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib4ubv (GLuint index, const GLubyte *v);\nGLAPI void APIENTRY glVertexAttrib4uiv (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttrib4usv (GLuint index, const GLushort *v);\nGLAPI void APIENTRY glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);\n#endif\n#endif /* GL_VERSION_2_0 */\n\n#ifndef GL_VERSION_2_1\n#define GL_VERSION_2_1 1\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\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\n#endif\n#endif /* GL_VERSION_2_1 */\n\n#ifndef GL_VERSION_3_0\n#define GL_VERSION_3_0 1\ntypedef khronos_uint16_t GLhalf;\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\ntypedef void (APIENTRYP PFNGLCOLORMASKIPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\ntypedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC) (GLenum target, GLuint index, GLboolean *data);\ntypedef void (APIENTRYP PFNGLGETINTEGERI_VPROC) (GLenum target, GLuint index, GLint *data);\ntypedef void (APIENTRYP PFNGLENABLEIPROC) (GLenum target, GLuint index);\ntypedef void (APIENTRYP PFNGLDISABLEIPROC) (GLenum target, GLuint index);\ntypedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC) (GLenum target, GLuint index);\ntypedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC) (GLenum primitiveMode);\ntypedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC) (void);\ntypedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC) (GLenum target, GLuint index, GLuint buffer);\ntypedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);\ntypedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);\ntypedef void (APIENTRYP PFNGLCLAMPCOLORPROC) (GLenum target, GLenum clamp);\ntypedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC) (GLuint id, GLenum mode);\ntypedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC) (void);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC) (GLuint index, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC) (GLuint index, GLint x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC) (GLuint index, GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC) (GLuint index, GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC) (GLuint index, GLuint x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC) (GLuint index, GLuint x, GLuint y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC) (GLuint program, GLint location, GLuint *params);\ntypedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC) (GLuint program, GLuint color, const GLchar *name);\ntypedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP PFNGLUNIFORM1UIPROC) (GLint location, GLuint v0);\ntypedef void (APIENTRYP PFNGLUNIFORM2UIPROC) (GLint location, GLuint v0, GLuint v1);\ntypedef void (APIENTRYP PFNGLUNIFORM3UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);\ntypedef void (APIENTRYP PFNGLUNIFORM4UIPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\ntypedef void (APIENTRYP PFNGLUNIFORM1UIVPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2UIVPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3UIVPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4UIVPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, const GLuint *params);\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC) (GLenum target, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC) (GLenum buffer, GLint drawbuffer, const GLint *value);\ntypedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint *value);\ntypedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC) (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);\ntypedef const GLubyte *(APIENTRYP PFNGLGETSTRINGIPROC) (GLenum name, GLuint index);\ntypedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC) (GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers);\ntypedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers);\ntypedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC) (GLuint framebuffer);\ntypedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer);\ntypedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers);\ntypedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers);\ntypedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\ntypedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);\ntypedef void *(APIENTRYP PFNGLMAPBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);\ntypedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC) (GLenum target, GLintptr offset, GLsizeiptr length);\ntypedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC) (GLuint array);\ntypedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC) (GLsizei n, const GLuint *arrays);\ntypedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);\ntypedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC) (GLuint array);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\nGLAPI void APIENTRY glGetBooleani_v (GLenum target, GLuint index, GLboolean *data);\nGLAPI void APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint *data);\nGLAPI void APIENTRY glEnablei (GLenum target, GLuint index);\nGLAPI void APIENTRY glDisablei (GLenum target, GLuint index);\nGLAPI GLboolean APIENTRY glIsEnabledi (GLenum target, GLuint index);\nGLAPI void APIENTRY glBeginTransformFeedback (GLenum primitiveMode);\nGLAPI void APIENTRY glEndTransformFeedback (void);\nGLAPI void APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI void APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer);\nGLAPI void APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);\nGLAPI void APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);\nGLAPI void APIENTRY glClampColor (GLenum target, GLenum clamp);\nGLAPI void APIENTRY glBeginConditionalRender (GLuint id, GLenum mode);\nGLAPI void APIENTRY glEndConditionalRender (void);\nGLAPI void APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params);\nGLAPI void APIENTRY glVertexAttribI1i (GLuint index, GLint x);\nGLAPI void APIENTRY glVertexAttribI2i (GLuint index, GLint x, GLint y);\nGLAPI void APIENTRY glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z);\nGLAPI void APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w);\nGLAPI void APIENTRY glVertexAttribI1ui (GLuint index, GLuint x);\nGLAPI void APIENTRY glVertexAttribI2ui (GLuint index, GLuint x, GLuint y);\nGLAPI void APIENTRY glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z);\nGLAPI void APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\nGLAPI void APIENTRY glVertexAttribI1iv (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttribI2iv (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttribI3iv (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttribI4iv (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttribI1uiv (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttribI2uiv (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttribI3uiv (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttribI4bv (GLuint index, const GLbyte *v);\nGLAPI void APIENTRY glVertexAttribI4sv (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttribI4ubv (GLuint index, const GLubyte *v);\nGLAPI void APIENTRY glVertexAttribI4usv (GLuint index, const GLushort *v);\nGLAPI void APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint *params);\nGLAPI void APIENTRY glBindFragDataLocation (GLuint program, GLuint color, const GLchar *name);\nGLAPI GLint APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name);\nGLAPI void APIENTRY glUniform1ui (GLint location, GLuint v0);\nGLAPI void APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1);\nGLAPI void APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2);\nGLAPI void APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\nGLAPI void APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glTexParameterIiv (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glTexParameterIuiv (GLenum target, GLenum pname, const GLuint *params);\nGLAPI void APIENTRY glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params);\nGLAPI void APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint *value);\nGLAPI void APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint *value);\nGLAPI void APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat *value);\nGLAPI void APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);\nGLAPI const GLubyte *APIENTRY glGetStringi (GLenum name, GLuint index);\nGLAPI GLboolean APIENTRY glIsRenderbuffer (GLuint renderbuffer);\nGLAPI void APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);\nGLAPI void APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers);\nGLAPI void APIENTRY glGenRenderbuffers (GLsizei n, GLuint *renderbuffers);\nGLAPI void APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params);\nGLAPI GLboolean APIENTRY glIsFramebuffer (GLuint framebuffer);\nGLAPI void APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);\nGLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers);\nGLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers);\nGLAPI GLenum APIENTRY glCheckFramebufferStatus (GLenum target);\nGLAPI void APIENTRY glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\nGLAPI void APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\nGLAPI void APIENTRY glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\nGLAPI void APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\nGLAPI void APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGenerateMipmap (GLenum target);\nGLAPI void APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\nGLAPI void APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);\nGLAPI void *APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);\nGLAPI void APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length);\nGLAPI void APIENTRY glBindVertexArray (GLuint array);\nGLAPI void APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint *arrays);\nGLAPI void APIENTRY glGenVertexArrays (GLsizei n, GLuint *arrays);\nGLAPI GLboolean APIENTRY glIsVertexArray (GLuint array);\n#endif\n#endif /* GL_VERSION_3_0 */\n\n#ifndef GL_VERSION_3_1\n#define GL_VERSION_3_1 1\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                  0xFFFFFFFFu\ntypedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);\ntypedef void (APIENTRYP PFNGLTEXBUFFERPROC) (GLenum target, GLenum internalformat, GLuint buffer);\ntypedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC) (GLuint index);\ntypedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC) (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC) (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC) (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC) (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);\ntypedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC) (GLuint program, const GLchar *uniformBlockName);\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC) (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);\ntypedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC) (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instancecount);\nGLAPI void APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount);\nGLAPI void APIENTRY glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer);\nGLAPI void APIENTRY glPrimitiveRestartIndex (GLuint index);\nGLAPI void APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\nGLAPI void APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices);\nGLAPI void APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);\nGLAPI GLuint APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar *uniformBlockName);\nGLAPI void APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);\nGLAPI void APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);\n#endif\n#endif /* GL_VERSION_3_1 */\n\n#ifndef GL_VERSION_3_2\n#define GL_VERSION_3_2 1\ntypedef struct __GLsync *GLsync;\ntypedef khronos_uint64_t GLuint64;\ntypedef khronos_int64_t GLint64;\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                0xFFFFFFFFFFFFFFFFull\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\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);\ntypedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC) (GLenum mode);\ntypedef GLsync (APIENTRYP PFNGLFENCESYNCPROC) (GLenum condition, GLbitfield flags);\ntypedef GLboolean (APIENTRYP PFNGLISSYNCPROC) (GLsync sync);\ntypedef void (APIENTRYP PFNGLDELETESYNCPROC) (GLsync sync);\ntypedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);\ntypedef void (APIENTRYP PFNGLWAITSYNCPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);\ntypedef void (APIENTRYP PFNGLGETINTEGER64VPROC) (GLenum pname, GLint64 *data);\ntypedef void (APIENTRYP PFNGLGETSYNCIVPROC) (GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values);\ntypedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC) (GLenum target, GLuint index, GLint64 *data);\ntypedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC) (GLenum target, GLenum pname, GLint64 *params);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC) (GLenum pname, GLuint index, GLfloat *val);\ntypedef void (APIENTRYP PFNGLSAMPLEMASKIPROC) (GLuint maskNumber, GLbitfield mask);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);\nGLAPI void APIENTRY glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);\nGLAPI void APIENTRY glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);\nGLAPI void APIENTRY glMultiDrawElementsBaseVertex (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex);\nGLAPI void APIENTRY glProvokingVertex (GLenum mode);\nGLAPI GLsync APIENTRY glFenceSync (GLenum condition, GLbitfield flags);\nGLAPI GLboolean APIENTRY glIsSync (GLsync sync);\nGLAPI void APIENTRY glDeleteSync (GLsync sync);\nGLAPI GLenum APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);\nGLAPI void APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);\nGLAPI void APIENTRY glGetInteger64v (GLenum pname, GLint64 *data);\nGLAPI void APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values);\nGLAPI void APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64 *data);\nGLAPI void APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64 *params);\nGLAPI void APIENTRY glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level);\nGLAPI void APIENTRY glTexImage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\nGLAPI void APIENTRY glTexImage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\nGLAPI void APIENTRY glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val);\nGLAPI void APIENTRY glSampleMaski (GLuint maskNumber, GLbitfield mask);\n#endif\n#endif /* GL_VERSION_3_2 */\n\n#ifndef GL_VERSION_3_3\n#define GL_VERSION_3_3 1\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\ntypedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);\ntypedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);\ntypedef void (APIENTRYP PFNGLDELETESAMPLERSPROC) (GLsizei count, const GLuint *samplers);\ntypedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC) (GLuint sampler);\ntypedef void (APIENTRYP PFNGLBINDSAMPLERPROC) (GLuint unit, GLuint sampler);\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC) (GLuint sampler, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, const GLint *param);\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC) (GLuint sampler, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, const GLfloat *param);\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, const GLint *param);\ntypedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, const GLuint *param);\ntypedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC) (GLuint sampler, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC) (GLuint sampler, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC) (GLuint sampler, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLQUERYCOUNTERPROC) (GLuint id, GLenum target);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC) (GLuint id, GLenum pname, GLuint64 *params);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC) (GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC) (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\ntypedef void (APIENTRYP PFNGLVERTEXP2UIPROC) (GLenum type, GLuint value);\ntypedef void (APIENTRYP PFNGLVERTEXP2UIVPROC) (GLenum type, const GLuint *value);\ntypedef void (APIENTRYP PFNGLVERTEXP3UIPROC) (GLenum type, GLuint value);\ntypedef void (APIENTRYP PFNGLVERTEXP3UIVPROC) (GLenum type, const GLuint *value);\ntypedef void (APIENTRYP PFNGLVERTEXP4UIPROC) (GLenum type, GLuint value);\ntypedef void (APIENTRYP PFNGLVERTEXP4UIVPROC) (GLenum type, const GLuint *value);\ntypedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC) (GLenum type, GLuint coords);\ntypedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC) (GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC) (GLenum type, GLuint coords);\ntypedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC) (GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC) (GLenum type, GLuint coords);\ntypedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC) (GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC) (GLenum type, GLuint coords);\ntypedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC) (GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC) (GLenum texture, GLenum type, GLuint coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC) (GLenum texture, GLenum type, GLuint coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC) (GLenum texture, GLenum type, GLuint coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC) (GLenum texture, GLenum type, GLuint coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC) (GLenum texture, GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP PFNGLNORMALP3UIPROC) (GLenum type, GLuint coords);\ntypedef void (APIENTRYP PFNGLNORMALP3UIVPROC) (GLenum type, const GLuint *coords);\ntypedef void (APIENTRYP PFNGLCOLORP3UIPROC) (GLenum type, GLuint color);\ntypedef void (APIENTRYP PFNGLCOLORP3UIVPROC) (GLenum type, const GLuint *color);\ntypedef void (APIENTRYP PFNGLCOLORP4UIPROC) (GLenum type, GLuint color);\ntypedef void (APIENTRYP PFNGLCOLORP4UIVPROC) (GLenum type, const GLuint *color);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC) (GLenum type, GLuint color);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC) (GLenum type, const GLuint *color);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, const GLchar *name);\nGLAPI GLint APIENTRY glGetFragDataIndex (GLuint program, const GLchar *name);\nGLAPI void APIENTRY glGenSamplers (GLsizei count, GLuint *samplers);\nGLAPI void APIENTRY glDeleteSamplers (GLsizei count, const GLuint *samplers);\nGLAPI GLboolean APIENTRY glIsSampler (GLuint sampler);\nGLAPI void APIENTRY glBindSampler (GLuint unit, GLuint sampler);\nGLAPI void APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param);\nGLAPI void APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint *param);\nGLAPI void APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat *param);\nGLAPI void APIENTRY glSamplerParameterIiv (GLuint sampler, GLenum pname, const GLint *param);\nGLAPI void APIENTRY glSamplerParameterIuiv (GLuint sampler, GLenum pname, const GLuint *param);\nGLAPI void APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params);\nGLAPI void APIENTRY glQueryCounter (GLuint id, GLenum target);\nGLAPI void APIENTRY glGetQueryObjecti64v (GLuint id, GLenum pname, GLint64 *params);\nGLAPI void APIENTRY glGetQueryObjectui64v (GLuint id, GLenum pname, GLuint64 *params);\nGLAPI void APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor);\nGLAPI void APIENTRY glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);\nGLAPI void APIENTRY glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\nGLAPI void APIENTRY glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);\nGLAPI void APIENTRY glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\nGLAPI void APIENTRY glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);\nGLAPI void APIENTRY glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\nGLAPI void APIENTRY glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value);\nGLAPI void APIENTRY glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, const GLuint *value);\nGLAPI void APIENTRY glVertexP2ui (GLenum type, GLuint value);\nGLAPI void APIENTRY glVertexP2uiv (GLenum type, const GLuint *value);\nGLAPI void APIENTRY glVertexP3ui (GLenum type, GLuint value);\nGLAPI void APIENTRY glVertexP3uiv (GLenum type, const GLuint *value);\nGLAPI void APIENTRY glVertexP4ui (GLenum type, GLuint value);\nGLAPI void APIENTRY glVertexP4uiv (GLenum type, const GLuint *value);\nGLAPI void APIENTRY glTexCoordP1ui (GLenum type, GLuint coords);\nGLAPI void APIENTRY glTexCoordP1uiv (GLenum type, const GLuint *coords);\nGLAPI void APIENTRY glTexCoordP2ui (GLenum type, GLuint coords);\nGLAPI void APIENTRY glTexCoordP2uiv (GLenum type, const GLuint *coords);\nGLAPI void APIENTRY glTexCoordP3ui (GLenum type, GLuint coords);\nGLAPI void APIENTRY glTexCoordP3uiv (GLenum type, const GLuint *coords);\nGLAPI void APIENTRY glTexCoordP4ui (GLenum type, GLuint coords);\nGLAPI void APIENTRY glTexCoordP4uiv (GLenum type, const GLuint *coords);\nGLAPI void APIENTRY glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords);\nGLAPI void APIENTRY glMultiTexCoordP1uiv (GLenum texture, GLenum type, const GLuint *coords);\nGLAPI void APIENTRY glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords);\nGLAPI void APIENTRY glMultiTexCoordP2uiv (GLenum texture, GLenum type, const GLuint *coords);\nGLAPI void APIENTRY glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords);\nGLAPI void APIENTRY glMultiTexCoordP3uiv (GLenum texture, GLenum type, const GLuint *coords);\nGLAPI void APIENTRY glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords);\nGLAPI void APIENTRY glMultiTexCoordP4uiv (GLenum texture, GLenum type, const GLuint *coords);\nGLAPI void APIENTRY glNormalP3ui (GLenum type, GLuint coords);\nGLAPI void APIENTRY glNormalP3uiv (GLenum type, const GLuint *coords);\nGLAPI void APIENTRY glColorP3ui (GLenum type, GLuint color);\nGLAPI void APIENTRY glColorP3uiv (GLenum type, const GLuint *color);\nGLAPI void APIENTRY glColorP4ui (GLenum type, GLuint color);\nGLAPI void APIENTRY glColorP4uiv (GLenum type, const GLuint *color);\nGLAPI void APIENTRY glSecondaryColorP3ui (GLenum type, GLuint color);\nGLAPI void APIENTRY glSecondaryColorP3uiv (GLenum type, const GLuint *color);\n#endif\n#endif /* GL_VERSION_3_3 */\n\n#ifndef GL_VERSION_4_0\n#define GL_VERSION_4_0 1\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\ntypedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC) (GLfloat value);\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC) (GLuint buf, GLenum mode);\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\ntypedef void (APIENTRYP PFNGLBLENDFUNCIPROC) (GLuint buf, GLenum src, GLenum dst);\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\ntypedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect);\ntypedef void (APIENTRYP PFNGLUNIFORM1DPROC) (GLint location, GLdouble x);\ntypedef void (APIENTRYP PFNGLUNIFORM2DPROC) (GLint location, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLUNIFORM3DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLUNIFORM4DPROC) (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLUNIFORM1DVPROC) (GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2DVPROC) (GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3DVPROC) (GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4DVPROC) (GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLGETUNIFORMDVPROC) (GLuint program, GLint location, GLdouble *params);\ntypedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) (GLuint program, GLenum shadertype, const GLchar *name);\ntypedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC) (GLuint program, GLenum shadertype, const GLchar *name);\ntypedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);\ntypedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);\ntypedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC) (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);\ntypedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, GLsizei count, const GLuint *indices);\ntypedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC) (GLenum shadertype, GLint location, GLuint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC) (GLuint program, GLenum shadertype, GLenum pname, GLint *values);\ntypedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value);\ntypedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC) (GLenum pname, const GLfloat *values);\ntypedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint *ids);\ntypedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids);\ntypedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC) (void);\ntypedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC) (void);\ntypedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC) (GLenum mode, GLuint id);\ntypedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) (GLenum mode, GLuint id, GLuint stream);\ntypedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC) (GLenum target, GLuint index, GLuint id);\ntypedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC) (GLenum target, GLuint index);\ntypedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMinSampleShading (GLfloat value);\nGLAPI void APIENTRY glBlendEquationi (GLuint buf, GLenum mode);\nGLAPI void APIENTRY glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\nGLAPI void APIENTRY glBlendFunci (GLuint buf, GLenum src, GLenum dst);\nGLAPI void APIENTRY glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\nGLAPI void APIENTRY glDrawArraysIndirect (GLenum mode, const void *indirect);\nGLAPI void APIENTRY glDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect);\nGLAPI void APIENTRY glUniform1d (GLint location, GLdouble x);\nGLAPI void APIENTRY glUniform2d (GLint location, GLdouble x, GLdouble y);\nGLAPI void APIENTRY glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glUniform1dv (GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glUniform2dv (GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glUniform3dv (GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glUniform4dv (GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glGetUniformdv (GLuint program, GLint location, GLdouble *params);\nGLAPI GLint APIENTRY glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, const GLchar *name);\nGLAPI GLuint APIENTRY glGetSubroutineIndex (GLuint program, GLenum shadertype, const GLchar *name);\nGLAPI void APIENTRY glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values);\nGLAPI void APIENTRY glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);\nGLAPI void APIENTRY glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);\nGLAPI void APIENTRY glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, const GLuint *indices);\nGLAPI void APIENTRY glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params);\nGLAPI void APIENTRY glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values);\nGLAPI void APIENTRY glPatchParameteri (GLenum pname, GLint value);\nGLAPI void APIENTRY glPatchParameterfv (GLenum pname, const GLfloat *values);\nGLAPI void APIENTRY glBindTransformFeedback (GLenum target, GLuint id);\nGLAPI void APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint *ids);\nGLAPI void APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint *ids);\nGLAPI GLboolean APIENTRY glIsTransformFeedback (GLuint id);\nGLAPI void APIENTRY glPauseTransformFeedback (void);\nGLAPI void APIENTRY glResumeTransformFeedback (void);\nGLAPI void APIENTRY glDrawTransformFeedback (GLenum mode, GLuint id);\nGLAPI void APIENTRY glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream);\nGLAPI void APIENTRY glBeginQueryIndexed (GLenum target, GLuint index, GLuint id);\nGLAPI void APIENTRY glEndQueryIndexed (GLenum target, GLuint index);\nGLAPI void APIENTRY glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params);\n#endif\n#endif /* GL_VERSION_4_0 */\n\n#ifndef GL_VERSION_4_1\n#define GL_VERSION_4_1 1\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\ntypedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC) (void);\ntypedef void (APIENTRYP PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length);\ntypedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);\ntypedef void (APIENTRYP PFNGLDEPTHRANGEFPROC) (GLfloat n, GLfloat f);\ntypedef void (APIENTRYP PFNGLCLEARDEPTHFPROC) (GLfloat d);\ntypedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);\ntypedef void (APIENTRYP PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value);\ntypedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC) (GLuint pipeline, GLbitfield stages, GLuint program);\ntypedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC) (GLuint pipeline, GLuint program);\ntypedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC) (GLenum type, GLsizei count, const GLchar *const*strings);\ntypedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC) (GLuint pipeline);\ntypedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC) (GLsizei n, const GLuint *pipelines);\ntypedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines);\ntypedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC) (GLuint pipeline);\ntypedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC) (GLuint pipeline, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC) (GLuint program, GLint location, GLint v0);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC) (GLuint program, GLint location, GLfloat v0);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC) (GLuint program, GLint location, GLdouble v0);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC) (GLuint program, GLint location, GLuint v0);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC) (GLuint program, GLint location, GLint v0, GLint v1);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC) (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC) (GLuint pipeline);\ntypedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC) (GLuint first, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);\ntypedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLSCISSORARRAYVPROC) (GLuint first, GLsizei count, const GLint *v);\ntypedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC) (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC) (GLuint first, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC) (GLuint index, GLdouble n, GLdouble f);\ntypedef void (APIENTRYP PFNGLGETFLOATI_VPROC) (GLenum target, GLuint index, GLfloat *data);\ntypedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC) (GLenum target, GLuint index, GLdouble *data);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glReleaseShaderCompiler (void);\nGLAPI void APIENTRY glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length);\nGLAPI void APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision);\nGLAPI void APIENTRY glDepthRangef (GLfloat n, GLfloat f);\nGLAPI void APIENTRY glClearDepthf (GLfloat d);\nGLAPI void APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary);\nGLAPI void APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const void *binary, GLsizei length);\nGLAPI void APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value);\nGLAPI void APIENTRY glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program);\nGLAPI void APIENTRY glActiveShaderProgram (GLuint pipeline, GLuint program);\nGLAPI GLuint APIENTRY glCreateShaderProgramv (GLenum type, GLsizei count, const GLchar *const*strings);\nGLAPI void APIENTRY glBindProgramPipeline (GLuint pipeline);\nGLAPI void APIENTRY glDeleteProgramPipelines (GLsizei n, const GLuint *pipelines);\nGLAPI void APIENTRY glGenProgramPipelines (GLsizei n, GLuint *pipelines);\nGLAPI GLboolean APIENTRY glIsProgramPipeline (GLuint pipeline);\nGLAPI void APIENTRY glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params);\nGLAPI void APIENTRY glProgramUniform1i (GLuint program, GLint location, GLint v0);\nGLAPI void APIENTRY glProgramUniform1iv (GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glProgramUniform1f (GLuint program, GLint location, GLfloat v0);\nGLAPI void APIENTRY glProgramUniform1fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniform1d (GLuint program, GLint location, GLdouble v0);\nGLAPI void APIENTRY glProgramUniform1dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniform1ui (GLuint program, GLint location, GLuint v0);\nGLAPI void APIENTRY glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1);\nGLAPI void APIENTRY glProgramUniform2iv (GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1);\nGLAPI void APIENTRY glProgramUniform2fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1);\nGLAPI void APIENTRY glProgramUniform2dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1);\nGLAPI void APIENTRY glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);\nGLAPI void APIENTRY glProgramUniform3iv (GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\nGLAPI void APIENTRY glProgramUniform3fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);\nGLAPI void APIENTRY glProgramUniform3dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);\nGLAPI void APIENTRY glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\nGLAPI void APIENTRY glProgramUniform4iv (GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\nGLAPI void APIENTRY glProgramUniform4fv (GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);\nGLAPI void APIENTRY glProgramUniform4dv (GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\nGLAPI void APIENTRY glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glValidateProgramPipeline (GLuint pipeline);\nGLAPI void APIENTRY glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);\nGLAPI void APIENTRY glVertexAttribL1d (GLuint index, GLdouble x);\nGLAPI void APIENTRY glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y);\nGLAPI void APIENTRY glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glVertexAttribL1dv (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribL2dv (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribL3dv (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribL4dv (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params);\nGLAPI void APIENTRY glViewportArrayv (GLuint first, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);\nGLAPI void APIENTRY glViewportIndexedfv (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glScissorArrayv (GLuint first, GLsizei count, const GLint *v);\nGLAPI void APIENTRY glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glScissorIndexedv (GLuint index, const GLint *v);\nGLAPI void APIENTRY glDepthRangeArrayv (GLuint first, GLsizei count, const GLdouble *v);\nGLAPI void APIENTRY glDepthRangeIndexed (GLuint index, GLdouble n, GLdouble f);\nGLAPI void APIENTRY glGetFloati_v (GLenum target, GLuint index, GLfloat *data);\nGLAPI void APIENTRY glGetDoublei_v (GLenum target, GLuint index, GLdouble *data);\n#endif\n#endif /* GL_VERSION_4_1 */\n\n#ifndef GL_VERSION_4_2\n#define GL_VERSION_4_2 1\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\ntypedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);\ntypedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params);\ntypedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);\ntypedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);\ntypedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\ntypedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) (GLenum mode, GLuint id, GLsizei instancecount);\ntypedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance);\nGLAPI void APIENTRY glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance);\nGLAPI void APIENTRY glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance);\nGLAPI void APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params);\nGLAPI void APIENTRY glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params);\nGLAPI void APIENTRY glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);\nGLAPI void APIENTRY glMemoryBarrier (GLbitfield barriers);\nGLAPI void APIENTRY glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\nGLAPI void APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\nGLAPI void APIENTRY glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei instancecount);\nGLAPI void APIENTRY glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei instancecount);\n#endif\n#endif /* GL_VERSION_4_2 */\n\n#ifndef GL_VERSION_4_3\n#define GL_VERSION_4_3 1\ntypedef void (APIENTRY  *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);\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\ntypedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC) (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);\ntypedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC) (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);\ntypedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);\ntypedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect);\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);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64 *params);\ntypedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC) (GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);\ntypedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);\ntypedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);\ntypedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC) (GLuint program, GLenum programInterface, GLenum pname, GLint *params);\ntypedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);\ntypedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);\ntypedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params);\ntypedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name);\ntypedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name);\ntypedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC) (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);\ntypedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC) (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP PFNGLTEXTUREVIEWPROC) (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);\ntypedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC) (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC) (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC) (GLuint attribindex, GLuint bindingindex);\ntypedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC) (GLuint bindingindex, GLuint divisor);\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);\ntypedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);\ntypedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);\ntypedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void);\ntypedef void (APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);\ntypedef void (APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);\ntypedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);\ntypedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glClearBufferData (GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data);\nGLAPI void APIENTRY glClearBufferSubData (GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);\nGLAPI void APIENTRY glDispatchCompute (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);\nGLAPI void APIENTRY glDispatchComputeIndirect (GLintptr indirect);\nGLAPI void APIENTRY glCopyImageSubData (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 void APIENTRY glFramebufferParameteri (GLenum target, GLenum pname, GLint param);\nGLAPI void APIENTRY glGetFramebufferParameteriv (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetInternalformati64v (GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64 *params);\nGLAPI void APIENTRY glInvalidateTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);\nGLAPI void APIENTRY glInvalidateTexImage (GLuint texture, GLint level);\nGLAPI void APIENTRY glInvalidateBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr length);\nGLAPI void APIENTRY glInvalidateBufferData (GLuint buffer);\nGLAPI void APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments);\nGLAPI void APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glMultiDrawArraysIndirect (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride);\nGLAPI void APIENTRY glMultiDrawElementsIndirect (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride);\nGLAPI void APIENTRY glGetProgramInterfaceiv (GLuint program, GLenum programInterface, GLenum pname, GLint *params);\nGLAPI GLuint APIENTRY glGetProgramResourceIndex (GLuint program, GLenum programInterface, const GLchar *name);\nGLAPI void APIENTRY glGetProgramResourceName (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);\nGLAPI void APIENTRY glGetProgramResourceiv (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params);\nGLAPI GLint APIENTRY glGetProgramResourceLocation (GLuint program, GLenum programInterface, const GLchar *name);\nGLAPI GLint APIENTRY glGetProgramResourceLocationIndex (GLuint program, GLenum programInterface, const GLchar *name);\nGLAPI void APIENTRY glShaderStorageBlockBinding (GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding);\nGLAPI void APIENTRY glTexBufferRange (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI void APIENTRY glTexStorage2DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\nGLAPI void APIENTRY glTexStorage3DMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\nGLAPI void APIENTRY glTextureView (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers);\nGLAPI void APIENTRY glBindVertexBuffer (GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);\nGLAPI void APIENTRY glVertexAttribFormat (GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);\nGLAPI void APIENTRY glVertexAttribIFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\nGLAPI void APIENTRY glVertexAttribLFormat (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\nGLAPI void APIENTRY glVertexAttribBinding (GLuint attribindex, GLuint bindingindex);\nGLAPI void APIENTRY glVertexBindingDivisor (GLuint bindingindex, GLuint divisor);\nGLAPI void APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\nGLAPI void APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);\nGLAPI void APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam);\nGLAPI GLuint APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);\nGLAPI void APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message);\nGLAPI void APIENTRY glPopDebugGroup (void);\nGLAPI void APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);\nGLAPI void APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);\nGLAPI void APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label);\nGLAPI void APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);\n#endif\n#endif /* GL_VERSION_4_3 */\n\n#ifndef GL_VERSION_4_4\n#define GL_VERSION_4_4 1\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\ntypedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);\ntypedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);\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);\ntypedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);\ntypedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);\ntypedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);\ntypedef void (APIENTRYP PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint *samplers);\ntypedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);\ntypedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBufferStorage (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);\nGLAPI void APIENTRY glClearTexImage (GLuint texture, GLint level, GLenum format, GLenum type, const void *data);\nGLAPI void APIENTRY glClearTexSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data);\nGLAPI void APIENTRY glBindBuffersBase (GLenum target, GLuint first, GLsizei count, const GLuint *buffers);\nGLAPI void APIENTRY glBindBuffersRange (GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes);\nGLAPI void APIENTRY glBindTextures (GLuint first, GLsizei count, const GLuint *textures);\nGLAPI void APIENTRY glBindSamplers (GLuint first, GLsizei count, const GLuint *samplers);\nGLAPI void APIENTRY glBindImageTextures (GLuint first, GLsizei count, const GLuint *textures);\nGLAPI void APIENTRY glBindVertexBuffers (GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);\n#endif\n#endif /* GL_VERSION_4_4 */\n\n#ifndef GL_VERSION_4_5\n#define GL_VERSION_4_5 1\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_COLOR_TABLE                    0x80D0\n#define GL_POST_CONVOLUTION_COLOR_TABLE   0x80D1\n#define GL_POST_COLOR_MATRIX_COLOR_TABLE  0x80D2\n#define GL_PROXY_COLOR_TABLE              0x80D3\n#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE 0x80D4\n#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE 0x80D5\n#define GL_CONVOLUTION_1D                 0x8010\n#define GL_CONVOLUTION_2D                 0x8011\n#define GL_SEPARABLE_2D                   0x8012\n#define GL_HISTOGRAM                      0x8024\n#define GL_PROXY_HISTOGRAM                0x8025\n#define GL_MINMAX                         0x802E\n#define GL_CONTEXT_RELEASE_BEHAVIOR       0x82FB\n#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC\ntypedef void (APIENTRYP PFNGLCLIPCONTROLPROC) (GLenum origin, GLenum depth);\ntypedef void (APIENTRYP PFNGLCREATETRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint *ids);\ntypedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC) (GLuint xfb, GLuint index, GLuint buffer);\ntypedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC) (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKIVPROC) (GLuint xfb, GLenum pname, GLint *param);\ntypedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint *param);\ntypedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC) (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);\ntypedef void (APIENTRYP PFNGLCREATEBUFFERSPROC) (GLsizei n, GLuint *buffers);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERDATAPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);\ntypedef void (APIENTRYP PFNGLCOPYNAMEDBUFFERSUBDATAPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);\ntypedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);\ntypedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERPROC) (GLuint buffer, GLenum access);\ntypedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);\ntypedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFERPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVPROC) (GLuint buffer, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERI64VPROC) (GLuint buffer, GLenum pname, GLint64 *params);\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVPROC) (GLuint buffer, GLenum pname, void **params);\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);\ntypedef void (APIENTRYP PFNGLCREATEFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC) (GLuint framebuffer, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC) (GLuint framebuffer, GLenum buf);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC) (GLuint framebuffer, GLenum src);\ntypedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments);\ntypedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value);\ntypedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value);\ntypedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);\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);\ntypedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) (GLuint framebuffer, GLenum target);\ntypedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) (GLuint framebuffer, GLenum pname, GLint *param);\ntypedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLCREATERENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers);\ntypedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC) (GLuint renderbuffer, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLCREATETEXTURESPROC) (GLenum target, GLsizei n, GLuint *textures);\ntypedef void (APIENTRYP PFNGLTEXTUREBUFFERPROC) (GLuint texture, GLenum internalformat, GLuint buffer);\ntypedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEPROC) (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE1DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE2DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE3DPROC) (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC) (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\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);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);\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);\ntypedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DPROC) (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERFPROC) (GLuint texture, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, const GLfloat *param);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIPROC) (GLuint texture, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, const GLuint *params);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, const GLint *param);\ntypedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPPROC) (GLuint texture);\ntypedef void (APIENTRYP PFNGLBINDTEXTUREUNITPROC) (GLuint unit, GLuint texture);\ntypedef void (APIENTRYP PFNGLGETTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC) (GLuint texture, GLint level, GLsizei bufSize, void *pixels);\ntypedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVPROC) (GLuint texture, GLint level, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVPROC) (GLuint texture, GLint level, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVPROC) (GLuint texture, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVPROC) (GLuint texture, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVPROC) (GLuint texture, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVPROC) (GLuint texture, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLCREATEVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);\ntypedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index);\ntypedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBPROC) (GLuint vaobj, GLuint index);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYELEMENTBUFFERPROC) (GLuint vaobj, GLuint buffer);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERSPROC) (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBBINDINGPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBIFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBLFORMATPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYBINDINGDIVISORPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor);\ntypedef void (APIENTRYP PFNGLGETVERTEXARRAYIVPROC) (GLuint vaobj, GLenum pname, GLint *param);\ntypedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXEDIVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);\ntypedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXED64IVPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param);\ntypedef void (APIENTRYP PFNGLCREATESAMPLERSPROC) (GLsizei n, GLuint *samplers);\ntypedef void (APIENTRYP PFNGLCREATEPROGRAMPIPELINESPROC) (GLsizei n, GLuint *pipelines);\ntypedef void (APIENTRYP PFNGLCREATEQUERIESPROC) (GLenum target, GLsizei n, GLuint *ids);\ntypedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\ntypedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\ntypedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUI64VPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\ntypedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUIVPROC) (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\ntypedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC) (GLbitfield barriers);\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);\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels);\ntypedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC) (void);\ntypedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint lod, GLsizei bufSize, void *pixels);\ntypedef void (APIENTRYP PFNGLGETNTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);\ntypedef void (APIENTRYP PFNGLGETNUNIFORMDVPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);\ntypedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);\ntypedef void (APIENTRYP PFNGLREADNPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);\ntypedef void (APIENTRYP PFNGLGETNMAPDVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);\ntypedef void (APIENTRYP PFNGLGETNMAPFVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);\ntypedef void (APIENTRYP PFNGLGETNMAPIVPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v);\ntypedef void (APIENTRYP PFNGLGETNPIXELMAPFVPROC) (GLenum map, GLsizei bufSize, GLfloat *values);\ntypedef void (APIENTRYP PFNGLGETNPIXELMAPUIVPROC) (GLenum map, GLsizei bufSize, GLuint *values);\ntypedef void (APIENTRYP PFNGLGETNPIXELMAPUSVPROC) (GLenum map, GLsizei bufSize, GLushort *values);\ntypedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEPROC) (GLsizei bufSize, GLubyte *pattern);\ntypedef void (APIENTRYP PFNGLGETNCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);\ntypedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);\ntypedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);\ntypedef void (APIENTRYP PFNGLGETNHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\ntypedef void (APIENTRYP PFNGLGETNMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\ntypedef void (APIENTRYP PFNGLTEXTUREBARRIERPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glClipControl (GLenum origin, GLenum depth);\nGLAPI void APIENTRY glCreateTransformFeedbacks (GLsizei n, GLuint *ids);\nGLAPI void APIENTRY glTransformFeedbackBufferBase (GLuint xfb, GLuint index, GLuint buffer);\nGLAPI void APIENTRY glTransformFeedbackBufferRange (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI void APIENTRY glGetTransformFeedbackiv (GLuint xfb, GLenum pname, GLint *param);\nGLAPI void APIENTRY glGetTransformFeedbacki_v (GLuint xfb, GLenum pname, GLuint index, GLint *param);\nGLAPI void APIENTRY glGetTransformFeedbacki64_v (GLuint xfb, GLenum pname, GLuint index, GLint64 *param);\nGLAPI void APIENTRY glCreateBuffers (GLsizei n, GLuint *buffers);\nGLAPI void APIENTRY glNamedBufferStorage (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);\nGLAPI void APIENTRY glNamedBufferData (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);\nGLAPI void APIENTRY glNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);\nGLAPI void APIENTRY glCopyNamedBufferSubData (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\nGLAPI void APIENTRY glClearNamedBufferData (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);\nGLAPI void APIENTRY glClearNamedBufferSubData (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);\nGLAPI void *APIENTRY glMapNamedBuffer (GLuint buffer, GLenum access);\nGLAPI void *APIENTRY glMapNamedBufferRange (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);\nGLAPI GLboolean APIENTRY glUnmapNamedBuffer (GLuint buffer);\nGLAPI void APIENTRY glFlushMappedNamedBufferRange (GLuint buffer, GLintptr offset, GLsizeiptr length);\nGLAPI void APIENTRY glGetNamedBufferParameteriv (GLuint buffer, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetNamedBufferParameteri64v (GLuint buffer, GLenum pname, GLint64 *params);\nGLAPI void APIENTRY glGetNamedBufferPointerv (GLuint buffer, GLenum pname, void **params);\nGLAPI void APIENTRY glGetNamedBufferSubData (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);\nGLAPI void APIENTRY glCreateFramebuffers (GLsizei n, GLuint *framebuffers);\nGLAPI void APIENTRY glNamedFramebufferRenderbuffer (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\nGLAPI void APIENTRY glNamedFramebufferParameteri (GLuint framebuffer, GLenum pname, GLint param);\nGLAPI void APIENTRY glNamedFramebufferTexture (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);\nGLAPI void APIENTRY glNamedFramebufferTextureLayer (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);\nGLAPI void APIENTRY glNamedFramebufferDrawBuffer (GLuint framebuffer, GLenum buf);\nGLAPI void APIENTRY glNamedFramebufferDrawBuffers (GLuint framebuffer, GLsizei n, const GLenum *bufs);\nGLAPI void APIENTRY glNamedFramebufferReadBuffer (GLuint framebuffer, GLenum src);\nGLAPI void APIENTRY glInvalidateNamedFramebufferData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments);\nGLAPI void APIENTRY glInvalidateNamedFramebufferSubData (GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glClearNamedFramebufferiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value);\nGLAPI void APIENTRY glClearNamedFramebufferuiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value);\nGLAPI void APIENTRY glClearNamedFramebufferfv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value);\nGLAPI void APIENTRY glClearNamedFramebufferfi (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);\nGLAPI void APIENTRY glBlitNamedFramebuffer (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 GLenum APIENTRY glCheckNamedFramebufferStatus (GLuint framebuffer, GLenum target);\nGLAPI void APIENTRY glGetNamedFramebufferParameteriv (GLuint framebuffer, GLenum pname, GLint *param);\nGLAPI void APIENTRY glGetNamedFramebufferAttachmentParameteriv (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);\nGLAPI void APIENTRY glCreateRenderbuffers (GLsizei n, GLuint *renderbuffers);\nGLAPI void APIENTRY glNamedRenderbufferStorage (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glNamedRenderbufferStorageMultisample (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glGetNamedRenderbufferParameteriv (GLuint renderbuffer, GLenum pname, GLint *params);\nGLAPI void APIENTRY glCreateTextures (GLenum target, GLsizei n, GLuint *textures);\nGLAPI void APIENTRY glTextureBuffer (GLuint texture, GLenum internalformat, GLuint buffer);\nGLAPI void APIENTRY glTextureBufferRange (GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI void APIENTRY glTextureStorage1D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width);\nGLAPI void APIENTRY glTextureStorage2D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glTextureStorage3D (GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\nGLAPI void APIENTRY glTextureStorage2DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\nGLAPI void APIENTRY glTextureStorage3DMultisample (GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\nGLAPI void APIENTRY glTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glCompressedTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCopyTextureSubImage1D (GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\nGLAPI void APIENTRY glCopyTextureSubImage2D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glCopyTextureSubImage3D (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glTextureParameterf (GLuint texture, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glTextureParameterfv (GLuint texture, GLenum pname, const GLfloat *param);\nGLAPI void APIENTRY glTextureParameteri (GLuint texture, GLenum pname, GLint param);\nGLAPI void APIENTRY glTextureParameterIiv (GLuint texture, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glTextureParameterIuiv (GLuint texture, GLenum pname, const GLuint *params);\nGLAPI void APIENTRY glTextureParameteriv (GLuint texture, GLenum pname, const GLint *param);\nGLAPI void APIENTRY glGenerateTextureMipmap (GLuint texture);\nGLAPI void APIENTRY glBindTextureUnit (GLuint unit, GLuint texture);\nGLAPI void APIENTRY glGetTextureImage (GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);\nGLAPI void APIENTRY glGetCompressedTextureImage (GLuint texture, GLint level, GLsizei bufSize, void *pixels);\nGLAPI void APIENTRY glGetTextureLevelParameterfv (GLuint texture, GLint level, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetTextureLevelParameteriv (GLuint texture, GLint level, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetTextureParameterfv (GLuint texture, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetTextureParameterIiv (GLuint texture, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetTextureParameterIuiv (GLuint texture, GLenum pname, GLuint *params);\nGLAPI void APIENTRY glGetTextureParameteriv (GLuint texture, GLenum pname, GLint *params);\nGLAPI void APIENTRY glCreateVertexArrays (GLsizei n, GLuint *arrays);\nGLAPI void APIENTRY glDisableVertexArrayAttrib (GLuint vaobj, GLuint index);\nGLAPI void APIENTRY glEnableVertexArrayAttrib (GLuint vaobj, GLuint index);\nGLAPI void APIENTRY glVertexArrayElementBuffer (GLuint vaobj, GLuint buffer);\nGLAPI void APIENTRY glVertexArrayVertexBuffer (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);\nGLAPI void APIENTRY glVertexArrayVertexBuffers (GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides);\nGLAPI void APIENTRY glVertexArrayAttribBinding (GLuint vaobj, GLuint attribindex, GLuint bindingindex);\nGLAPI void APIENTRY glVertexArrayAttribFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);\nGLAPI void APIENTRY glVertexArrayAttribIFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\nGLAPI void APIENTRY glVertexArrayAttribLFormat (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\nGLAPI void APIENTRY glVertexArrayBindingDivisor (GLuint vaobj, GLuint bindingindex, GLuint divisor);\nGLAPI void APIENTRY glGetVertexArrayiv (GLuint vaobj, GLenum pname, GLint *param);\nGLAPI void APIENTRY glGetVertexArrayIndexediv (GLuint vaobj, GLuint index, GLenum pname, GLint *param);\nGLAPI void APIENTRY glGetVertexArrayIndexed64iv (GLuint vaobj, GLuint index, GLenum pname, GLint64 *param);\nGLAPI void APIENTRY glCreateSamplers (GLsizei n, GLuint *samplers);\nGLAPI void APIENTRY glCreateProgramPipelines (GLsizei n, GLuint *pipelines);\nGLAPI void APIENTRY glCreateQueries (GLenum target, GLsizei n, GLuint *ids);\nGLAPI void APIENTRY glGetQueryBufferObjecti64v (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\nGLAPI void APIENTRY glGetQueryBufferObjectiv (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\nGLAPI void APIENTRY glGetQueryBufferObjectui64v (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\nGLAPI void APIENTRY glGetQueryBufferObjectuiv (GLuint id, GLuint buffer, GLenum pname, GLintptr offset);\nGLAPI void APIENTRY glMemoryBarrierByRegion (GLbitfield barriers);\nGLAPI void APIENTRY glGetTextureSubImage (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 void APIENTRY glGetCompressedTextureSubImage (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels);\nGLAPI GLenum APIENTRY glGetGraphicsResetStatus (void);\nGLAPI void APIENTRY glGetnCompressedTexImage (GLenum target, GLint lod, GLsizei bufSize, void *pixels);\nGLAPI void APIENTRY glGetnTexImage (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels);\nGLAPI void APIENTRY glGetnUniformdv (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);\nGLAPI void APIENTRY glGetnUniformfv (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);\nGLAPI void APIENTRY glGetnUniformiv (GLuint program, GLint location, GLsizei bufSize, GLint *params);\nGLAPI void APIENTRY glGetnUniformuiv (GLuint program, GLint location, GLsizei bufSize, GLuint *params);\nGLAPI void APIENTRY glReadnPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);\nGLAPI void APIENTRY glGetnMapdv (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);\nGLAPI void APIENTRY glGetnMapfv (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);\nGLAPI void APIENTRY glGetnMapiv (GLenum target, GLenum query, GLsizei bufSize, GLint *v);\nGLAPI void APIENTRY glGetnPixelMapfv (GLenum map, GLsizei bufSize, GLfloat *values);\nGLAPI void APIENTRY glGetnPixelMapuiv (GLenum map, GLsizei bufSize, GLuint *values);\nGLAPI void APIENTRY glGetnPixelMapusv (GLenum map, GLsizei bufSize, GLushort *values);\nGLAPI void APIENTRY glGetnPolygonStipple (GLsizei bufSize, GLubyte *pattern);\nGLAPI void APIENTRY glGetnColorTable (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);\nGLAPI void APIENTRY glGetnConvolutionFilter (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);\nGLAPI void APIENTRY glGetnSeparableFilter (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);\nGLAPI void APIENTRY glGetnHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\nGLAPI void APIENTRY glGetnMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\nGLAPI void APIENTRY glTextureBarrier (void);\n#endif\n#endif /* GL_VERSION_4_5 */\n\n#ifndef GL_VERSION_4_6\n#define GL_VERSION_4_6 1\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\ntypedef void (APIENTRYP PFNGLSPECIALIZESHADERPROC) (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue);\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC) (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC) (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\ntypedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPPROC) (GLfloat factor, GLfloat units, GLfloat clamp);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSpecializeShader (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue);\nGLAPI void APIENTRY glMultiDrawArraysIndirectCount (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\nGLAPI void APIENTRY glMultiDrawElementsIndirectCount (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\nGLAPI void APIENTRY glPolygonOffsetClamp (GLfloat factor, GLfloat units, GLfloat clamp);\n#endif\n#endif /* GL_VERSION_4_6 */\n\n#ifndef GL_ARB_ES2_compatibility\n#define GL_ARB_ES2_compatibility 1\n#endif /* GL_ARB_ES2_compatibility */\n\n#ifndef GL_ARB_ES3_1_compatibility\n#define GL_ARB_ES3_1_compatibility 1\n#endif /* GL_ARB_ES3_1_compatibility */\n\n#ifndef GL_ARB_ES3_2_compatibility\n#define GL_ARB_ES3_2_compatibility 1\n#define GL_PRIMITIVE_BOUNDING_BOX_ARB     0x92BE\n#define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381\n#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382\ntypedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXARBPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPrimitiveBoundingBoxARB (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);\n#endif\n#endif /* GL_ARB_ES3_2_compatibility */\n\n#ifndef GL_ARB_ES3_compatibility\n#define GL_ARB_ES3_compatibility 1\n#endif /* GL_ARB_ES3_compatibility */\n\n#ifndef GL_ARB_arrays_of_arrays\n#define GL_ARB_arrays_of_arrays 1\n#endif /* GL_ARB_arrays_of_arrays */\n\n#ifndef GL_ARB_base_instance\n#define GL_ARB_base_instance 1\n#endif /* GL_ARB_base_instance */\n\n#ifndef GL_ARB_bindless_texture\n#define GL_ARB_bindless_texture 1\ntypedef khronos_uint64_t GLuint64EXT;\n#define GL_UNSIGNED_INT64_ARB             0x140F\ntypedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture);\ntypedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler);\ntypedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);\ntypedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle);\ntypedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);\ntypedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access);\ntypedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle);\ntypedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value);\ntypedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);\ntypedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle);\ntypedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT *v);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLuint64 APIENTRY glGetTextureHandleARB (GLuint texture);\nGLAPI GLuint64 APIENTRY glGetTextureSamplerHandleARB (GLuint texture, GLuint sampler);\nGLAPI void APIENTRY glMakeTextureHandleResidentARB (GLuint64 handle);\nGLAPI void APIENTRY glMakeTextureHandleNonResidentARB (GLuint64 handle);\nGLAPI GLuint64 APIENTRY glGetImageHandleARB (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);\nGLAPI void APIENTRY glMakeImageHandleResidentARB (GLuint64 handle, GLenum access);\nGLAPI void APIENTRY glMakeImageHandleNonResidentARB (GLuint64 handle);\nGLAPI void APIENTRY glUniformHandleui64ARB (GLint location, GLuint64 value);\nGLAPI void APIENTRY glUniformHandleui64vARB (GLint location, GLsizei count, const GLuint64 *value);\nGLAPI void APIENTRY glProgramUniformHandleui64ARB (GLuint program, GLint location, GLuint64 value);\nGLAPI void APIENTRY glProgramUniformHandleui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *values);\nGLAPI GLboolean APIENTRY glIsTextureHandleResidentARB (GLuint64 handle);\nGLAPI GLboolean APIENTRY glIsImageHandleResidentARB (GLuint64 handle);\nGLAPI void APIENTRY glVertexAttribL1ui64ARB (GLuint index, GLuint64EXT x);\nGLAPI void APIENTRY glVertexAttribL1ui64vARB (GLuint index, const GLuint64EXT *v);\nGLAPI void APIENTRY glGetVertexAttribLui64vARB (GLuint index, GLenum pname, GLuint64EXT *params);\n#endif\n#endif /* GL_ARB_bindless_texture */\n\n#ifndef GL_ARB_blend_func_extended\n#define GL_ARB_blend_func_extended 1\n#endif /* GL_ARB_blend_func_extended */\n\n#ifndef GL_ARB_buffer_storage\n#define GL_ARB_buffer_storage 1\n#endif /* GL_ARB_buffer_storage */\n\n#ifndef GL_ARB_cl_event\n#define GL_ARB_cl_event 1\nstruct _cl_context;\nstruct _cl_event;\n#define GL_SYNC_CL_EVENT_ARB              0x8240\n#define GL_SYNC_CL_EVENT_COMPLETE_ARB     0x8241\ntypedef GLsync (APIENTRYP PFNGLCREATESYNCFROMCLEVENTARBPROC) (struct _cl_context *context, struct _cl_event *event, GLbitfield flags);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLsync APIENTRY glCreateSyncFromCLeventARB (struct _cl_context *context, struct _cl_event *event, GLbitfield flags);\n#endif\n#endif /* GL_ARB_cl_event */\n\n#ifndef GL_ARB_clear_buffer_object\n#define GL_ARB_clear_buffer_object 1\n#endif /* GL_ARB_clear_buffer_object */\n\n#ifndef GL_ARB_clear_texture\n#define GL_ARB_clear_texture 1\n#endif /* GL_ARB_clear_texture */\n\n#ifndef GL_ARB_clip_control\n#define GL_ARB_clip_control 1\n#endif /* GL_ARB_clip_control */\n\n#ifndef GL_ARB_color_buffer_float\n#define GL_ARB_color_buffer_float 1\n#define GL_RGBA_FLOAT_MODE_ARB            0x8820\n#define GL_CLAMP_VERTEX_COLOR_ARB         0x891A\n#define GL_CLAMP_FRAGMENT_COLOR_ARB       0x891B\n#define GL_CLAMP_READ_COLOR_ARB           0x891C\n#define GL_FIXED_ONLY_ARB                 0x891D\ntypedef void (APIENTRYP PFNGLCLAMPCOLORARBPROC) (GLenum target, GLenum clamp);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glClampColorARB (GLenum target, GLenum clamp);\n#endif\n#endif /* GL_ARB_color_buffer_float */\n\n#ifndef GL_ARB_compatibility\n#define GL_ARB_compatibility 1\n#endif /* GL_ARB_compatibility */\n\n#ifndef GL_ARB_compressed_texture_pixel_storage\n#define GL_ARB_compressed_texture_pixel_storage 1\n#endif /* GL_ARB_compressed_texture_pixel_storage */\n\n#ifndef GL_ARB_compute_shader\n#define GL_ARB_compute_shader 1\n#endif /* GL_ARB_compute_shader */\n\n#ifndef GL_ARB_compute_variable_group_size\n#define GL_ARB_compute_variable_group_size 1\n#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344\n#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB\n#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345\n#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF\ntypedef void (APIENTRYP PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDispatchComputeGroupSizeARB (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z);\n#endif\n#endif /* GL_ARB_compute_variable_group_size */\n\n#ifndef GL_ARB_conditional_render_inverted\n#define GL_ARB_conditional_render_inverted 1\n#endif /* GL_ARB_conditional_render_inverted */\n\n#ifndef GL_ARB_conservative_depth\n#define GL_ARB_conservative_depth 1\n#endif /* GL_ARB_conservative_depth */\n\n#ifndef GL_ARB_copy_buffer\n#define GL_ARB_copy_buffer 1\n#endif /* GL_ARB_copy_buffer */\n\n#ifndef GL_ARB_copy_image\n#define GL_ARB_copy_image 1\n#endif /* GL_ARB_copy_image */\n\n#ifndef GL_ARB_cull_distance\n#define GL_ARB_cull_distance 1\n#endif /* GL_ARB_cull_distance */\n\n#ifndef GL_ARB_debug_output\n#define GL_ARB_debug_output 1\ntypedef void (APIENTRY  *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);\n#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB   0x8242\n#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243\n#define GL_DEBUG_CALLBACK_FUNCTION_ARB    0x8244\n#define GL_DEBUG_CALLBACK_USER_PARAM_ARB  0x8245\n#define GL_DEBUG_SOURCE_API_ARB           0x8246\n#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247\n#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248\n#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB   0x8249\n#define GL_DEBUG_SOURCE_APPLICATION_ARB   0x824A\n#define GL_DEBUG_SOURCE_OTHER_ARB         0x824B\n#define GL_DEBUG_TYPE_ERROR_ARB           0x824C\n#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D\n#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E\n#define GL_DEBUG_TYPE_PORTABILITY_ARB     0x824F\n#define GL_DEBUG_TYPE_PERFORMANCE_ARB     0x8250\n#define GL_DEBUG_TYPE_OTHER_ARB           0x8251\n#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB   0x9143\n#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB  0x9144\n#define GL_DEBUG_LOGGED_MESSAGES_ARB      0x9145\n#define GL_DEBUG_SEVERITY_HIGH_ARB        0x9146\n#define GL_DEBUG_SEVERITY_MEDIUM_ARB      0x9147\n#define GL_DEBUG_SEVERITY_LOW_ARB         0x9148\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const void *userParam);\ntypedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDebugMessageControlARB (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\nGLAPI void APIENTRY glDebugMessageInsertARB (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);\nGLAPI void APIENTRY glDebugMessageCallbackARB (GLDEBUGPROCARB callback, const void *userParam);\nGLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);\n#endif\n#endif /* GL_ARB_debug_output */\n\n#ifndef GL_ARB_depth_buffer_float\n#define GL_ARB_depth_buffer_float 1\n#endif /* GL_ARB_depth_buffer_float */\n\n#ifndef GL_ARB_depth_clamp\n#define GL_ARB_depth_clamp 1\n#endif /* GL_ARB_depth_clamp */\n\n#ifndef GL_ARB_depth_texture\n#define GL_ARB_depth_texture 1\n#define GL_DEPTH_COMPONENT16_ARB          0x81A5\n#define GL_DEPTH_COMPONENT24_ARB          0x81A6\n#define GL_DEPTH_COMPONENT32_ARB          0x81A7\n#define GL_TEXTURE_DEPTH_SIZE_ARB         0x884A\n#define GL_DEPTH_TEXTURE_MODE_ARB         0x884B\n#endif /* GL_ARB_depth_texture */\n\n#ifndef GL_ARB_derivative_control\n#define GL_ARB_derivative_control 1\n#endif /* GL_ARB_derivative_control */\n\n#ifndef GL_ARB_direct_state_access\n#define GL_ARB_direct_state_access 1\n#endif /* GL_ARB_direct_state_access */\n\n#ifndef GL_ARB_draw_buffers\n#define GL_ARB_draw_buffers 1\n#define GL_MAX_DRAW_BUFFERS_ARB           0x8824\n#define GL_DRAW_BUFFER0_ARB               0x8825\n#define GL_DRAW_BUFFER1_ARB               0x8826\n#define GL_DRAW_BUFFER2_ARB               0x8827\n#define GL_DRAW_BUFFER3_ARB               0x8828\n#define GL_DRAW_BUFFER4_ARB               0x8829\n#define GL_DRAW_BUFFER5_ARB               0x882A\n#define GL_DRAW_BUFFER6_ARB               0x882B\n#define GL_DRAW_BUFFER7_ARB               0x882C\n#define GL_DRAW_BUFFER8_ARB               0x882D\n#define GL_DRAW_BUFFER9_ARB               0x882E\n#define GL_DRAW_BUFFER10_ARB              0x882F\n#define GL_DRAW_BUFFER11_ARB              0x8830\n#define GL_DRAW_BUFFER12_ARB              0x8831\n#define GL_DRAW_BUFFER13_ARB              0x8832\n#define GL_DRAW_BUFFER14_ARB              0x8833\n#define GL_DRAW_BUFFER15_ARB              0x8834\ntypedef void (APIENTRYP PFNGLDRAWBUFFERSARBPROC) (GLsizei n, const GLenum *bufs);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawBuffersARB (GLsizei n, const GLenum *bufs);\n#endif\n#endif /* GL_ARB_draw_buffers */\n\n#ifndef GL_ARB_draw_buffers_blend\n#define GL_ARB_draw_buffers_blend 1\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONIARBPROC) (GLuint buf, GLenum mode);\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIARBPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\ntypedef void (APIENTRYP PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLenum dst);\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIARBPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendEquationiARB (GLuint buf, GLenum mode);\nGLAPI void APIENTRY glBlendEquationSeparateiARB (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\nGLAPI void APIENTRY glBlendFunciARB (GLuint buf, GLenum src, GLenum dst);\nGLAPI void APIENTRY glBlendFuncSeparateiARB (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\n#endif\n#endif /* GL_ARB_draw_buffers_blend */\n\n#ifndef GL_ARB_draw_elements_base_vertex\n#define GL_ARB_draw_elements_base_vertex 1\n#endif /* GL_ARB_draw_elements_base_vertex */\n\n#ifndef GL_ARB_draw_indirect\n#define GL_ARB_draw_indirect 1\n#endif /* GL_ARB_draw_indirect */\n\n#ifndef GL_ARB_draw_instanced\n#define GL_ARB_draw_instanced 1\ntypedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDARBPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDARBPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawArraysInstancedARB (GLenum mode, GLint first, GLsizei count, GLsizei primcount);\nGLAPI void APIENTRY glDrawElementsInstancedARB (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);\n#endif\n#endif /* GL_ARB_draw_instanced */\n\n#ifndef GL_ARB_enhanced_layouts\n#define GL_ARB_enhanced_layouts 1\n#endif /* GL_ARB_enhanced_layouts */\n\n#ifndef GL_ARB_explicit_attrib_location\n#define GL_ARB_explicit_attrib_location 1\n#endif /* GL_ARB_explicit_attrib_location */\n\n#ifndef GL_ARB_explicit_uniform_location\n#define GL_ARB_explicit_uniform_location 1\n#endif /* GL_ARB_explicit_uniform_location */\n\n#ifndef GL_ARB_fragment_coord_conventions\n#define GL_ARB_fragment_coord_conventions 1\n#endif /* GL_ARB_fragment_coord_conventions */\n\n#ifndef GL_ARB_fragment_layer_viewport\n#define GL_ARB_fragment_layer_viewport 1\n#endif /* GL_ARB_fragment_layer_viewport */\n\n#ifndef GL_ARB_fragment_program\n#define GL_ARB_fragment_program 1\n#define GL_FRAGMENT_PROGRAM_ARB           0x8804\n#define GL_PROGRAM_FORMAT_ASCII_ARB       0x8875\n#define GL_PROGRAM_LENGTH_ARB             0x8627\n#define GL_PROGRAM_FORMAT_ARB             0x8876\n#define GL_PROGRAM_BINDING_ARB            0x8677\n#define GL_PROGRAM_INSTRUCTIONS_ARB       0x88A0\n#define GL_MAX_PROGRAM_INSTRUCTIONS_ARB   0x88A1\n#define GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A2\n#define GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB 0x88A3\n#define GL_PROGRAM_TEMPORARIES_ARB        0x88A4\n#define GL_MAX_PROGRAM_TEMPORARIES_ARB    0x88A5\n#define GL_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A6\n#define GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB 0x88A7\n#define GL_PROGRAM_PARAMETERS_ARB         0x88A8\n#define GL_MAX_PROGRAM_PARAMETERS_ARB     0x88A9\n#define GL_PROGRAM_NATIVE_PARAMETERS_ARB  0x88AA\n#define GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB 0x88AB\n#define GL_PROGRAM_ATTRIBS_ARB            0x88AC\n#define GL_MAX_PROGRAM_ATTRIBS_ARB        0x88AD\n#define GL_PROGRAM_NATIVE_ATTRIBS_ARB     0x88AE\n#define GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB 0x88AF\n#define GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB 0x88B4\n#define GL_MAX_PROGRAM_ENV_PARAMETERS_ARB 0x88B5\n#define GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB 0x88B6\n#define GL_PROGRAM_ALU_INSTRUCTIONS_ARB   0x8805\n#define GL_PROGRAM_TEX_INSTRUCTIONS_ARB   0x8806\n#define GL_PROGRAM_TEX_INDIRECTIONS_ARB   0x8807\n#define GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x8808\n#define GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x8809\n#define GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x880A\n#define GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB 0x880B\n#define GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB 0x880C\n#define GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB 0x880D\n#define GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB 0x880E\n#define GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB 0x880F\n#define GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB 0x8810\n#define GL_PROGRAM_STRING_ARB             0x8628\n#define GL_PROGRAM_ERROR_POSITION_ARB     0x864B\n#define GL_CURRENT_MATRIX_ARB             0x8641\n#define GL_TRANSPOSE_CURRENT_MATRIX_ARB   0x88B7\n#define GL_CURRENT_MATRIX_STACK_DEPTH_ARB 0x8640\n#define GL_MAX_PROGRAM_MATRICES_ARB       0x862F\n#define GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB 0x862E\n#define GL_MAX_TEXTURE_COORDS_ARB         0x8871\n#define GL_MAX_TEXTURE_IMAGE_UNITS_ARB    0x8872\n#define GL_PROGRAM_ERROR_STRING_ARB       0x8874\n#define GL_MATRIX0_ARB                    0x88C0\n#define GL_MATRIX1_ARB                    0x88C1\n#define GL_MATRIX2_ARB                    0x88C2\n#define GL_MATRIX3_ARB                    0x88C3\n#define GL_MATRIX4_ARB                    0x88C4\n#define GL_MATRIX5_ARB                    0x88C5\n#define GL_MATRIX6_ARB                    0x88C6\n#define GL_MATRIX7_ARB                    0x88C7\n#define GL_MATRIX8_ARB                    0x88C8\n#define GL_MATRIX9_ARB                    0x88C9\n#define GL_MATRIX10_ARB                   0x88CA\n#define GL_MATRIX11_ARB                   0x88CB\n#define GL_MATRIX12_ARB                   0x88CC\n#define GL_MATRIX13_ARB                   0x88CD\n#define GL_MATRIX14_ARB                   0x88CE\n#define GL_MATRIX15_ARB                   0x88CF\n#define GL_MATRIX16_ARB                   0x88D0\n#define GL_MATRIX17_ARB                   0x88D1\n#define GL_MATRIX18_ARB                   0x88D2\n#define GL_MATRIX19_ARB                   0x88D3\n#define GL_MATRIX20_ARB                   0x88D4\n#define GL_MATRIX21_ARB                   0x88D5\n#define GL_MATRIX22_ARB                   0x88D6\n#define GL_MATRIX23_ARB                   0x88D7\n#define GL_MATRIX24_ARB                   0x88D8\n#define GL_MATRIX25_ARB                   0x88D9\n#define GL_MATRIX26_ARB                   0x88DA\n#define GL_MATRIX27_ARB                   0x88DB\n#define GL_MATRIX28_ARB                   0x88DC\n#define GL_MATRIX29_ARB                   0x88DD\n#define GL_MATRIX30_ARB                   0x88DE\n#define GL_MATRIX31_ARB                   0x88DF\ntypedef void (APIENTRYP PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void *string);\ntypedef void (APIENTRYP PFNGLBINDPROGRAMARBPROC) (GLenum target, GLuint program);\ntypedef void (APIENTRYP PFNGLDELETEPROGRAMSARBPROC) (GLsizei n, const GLuint *programs);\ntypedef void (APIENTRYP PFNGLGENPROGRAMSARBPROC) (GLsizei n, GLuint *programs);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble *params);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void *string);\ntypedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const void *string);\nGLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program);\nGLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs);\nGLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs);\nGLAPI void APIENTRY glProgramEnvParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glProgramEnvParameter4dvARB (GLenum target, GLuint index, const GLdouble *params);\nGLAPI void APIENTRY glProgramEnvParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glProgramEnvParameter4fvARB (GLenum target, GLuint index, const GLfloat *params);\nGLAPI void APIENTRY glProgramLocalParameter4dARB (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glProgramLocalParameter4dvARB (GLenum target, GLuint index, const GLdouble *params);\nGLAPI void APIENTRY glProgramLocalParameter4fARB (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum target, GLuint index, const GLfloat *params);\nGLAPI void APIENTRY glGetProgramEnvParameterdvARB (GLenum target, GLuint index, GLdouble *params);\nGLAPI void APIENTRY glGetProgramEnvParameterfvARB (GLenum target, GLuint index, GLfloat *params);\nGLAPI void APIENTRY glGetProgramLocalParameterdvARB (GLenum target, GLuint index, GLdouble *params);\nGLAPI void APIENTRY glGetProgramLocalParameterfvARB (GLenum target, GLuint index, GLfloat *params);\nGLAPI void APIENTRY glGetProgramivARB (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetProgramStringARB (GLenum target, GLenum pname, void *string);\nGLAPI GLboolean APIENTRY glIsProgramARB (GLuint program);\n#endif\n#endif /* GL_ARB_fragment_program */\n\n#ifndef GL_ARB_fragment_program_shadow\n#define GL_ARB_fragment_program_shadow 1\n#endif /* GL_ARB_fragment_program_shadow */\n\n#ifndef GL_ARB_fragment_shader\n#define GL_ARB_fragment_shader 1\n#define GL_FRAGMENT_SHADER_ARB            0x8B30\n#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB 0x8B49\n#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B\n#endif /* GL_ARB_fragment_shader */\n\n#ifndef GL_ARB_fragment_shader_interlock\n#define GL_ARB_fragment_shader_interlock 1\n#endif /* GL_ARB_fragment_shader_interlock */\n\n#ifndef GL_ARB_framebuffer_no_attachments\n#define GL_ARB_framebuffer_no_attachments 1\n#endif /* GL_ARB_framebuffer_no_attachments */\n\n#ifndef GL_ARB_framebuffer_object\n#define GL_ARB_framebuffer_object 1\n#endif /* GL_ARB_framebuffer_object */\n\n#ifndef GL_ARB_framebuffer_sRGB\n#define GL_ARB_framebuffer_sRGB 1\n#endif /* GL_ARB_framebuffer_sRGB */\n\n#ifndef GL_ARB_geometry_shader4\n#define GL_ARB_geometry_shader4 1\n#define GL_LINES_ADJACENCY_ARB            0x000A\n#define GL_LINE_STRIP_ADJACENCY_ARB       0x000B\n#define GL_TRIANGLES_ADJACENCY_ARB        0x000C\n#define GL_TRIANGLE_STRIP_ADJACENCY_ARB   0x000D\n#define GL_PROGRAM_POINT_SIZE_ARB         0x8642\n#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29\n#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7\n#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8\n#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9\n#define GL_GEOMETRY_SHADER_ARB            0x8DD9\n#define GL_GEOMETRY_VERTICES_OUT_ARB      0x8DDA\n#define GL_GEOMETRY_INPUT_TYPE_ARB        0x8DDB\n#define GL_GEOMETRY_OUTPUT_TYPE_ARB       0x8DDC\n#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD\n#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE\n#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF\n#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0\n#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenum pname, GLint value);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProgramParameteriARB (GLuint program, GLenum pname, GLint value);\nGLAPI void APIENTRY glFramebufferTextureARB (GLenum target, GLenum attachment, GLuint texture, GLint level);\nGLAPI void APIENTRY glFramebufferTextureLayerARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);\nGLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);\n#endif\n#endif /* GL_ARB_geometry_shader4 */\n\n#ifndef GL_ARB_get_program_binary\n#define GL_ARB_get_program_binary 1\n#endif /* GL_ARB_get_program_binary */\n\n#ifndef GL_ARB_get_texture_sub_image\n#define GL_ARB_get_texture_sub_image 1\n#endif /* GL_ARB_get_texture_sub_image */\n\n#ifndef GL_ARB_gl_spirv\n#define GL_ARB_gl_spirv 1\n#define GL_SHADER_BINARY_FORMAT_SPIR_V_ARB 0x9551\n#define GL_SPIR_V_BINARY_ARB              0x9552\ntypedef void (APIENTRYP PFNGLSPECIALIZESHADERARBPROC) (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSpecializeShaderARB (GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue);\n#endif\n#endif /* GL_ARB_gl_spirv */\n\n#ifndef GL_ARB_gpu_shader5\n#define GL_ARB_gpu_shader5 1\n#endif /* GL_ARB_gpu_shader5 */\n\n#ifndef GL_ARB_gpu_shader_fp64\n#define GL_ARB_gpu_shader_fp64 1\n#endif /* GL_ARB_gpu_shader_fp64 */\n\n#ifndef GL_ARB_gpu_shader_int64\n#define GL_ARB_gpu_shader_int64 1\n#define GL_INT64_ARB                      0x140E\n#define GL_INT64_VEC2_ARB                 0x8FE9\n#define GL_INT64_VEC3_ARB                 0x8FEA\n#define GL_INT64_VEC4_ARB                 0x8FEB\n#define GL_UNSIGNED_INT64_VEC2_ARB        0x8FF5\n#define GL_UNSIGNED_INT64_VEC3_ARB        0x8FF6\n#define GL_UNSIGNED_INT64_VEC4_ARB        0x8FF7\ntypedef void (APIENTRYP PFNGLUNIFORM1I64ARBPROC) (GLint location, GLint64 x);\ntypedef void (APIENTRYP PFNGLUNIFORM2I64ARBPROC) (GLint location, GLint64 x, GLint64 y);\ntypedef void (APIENTRYP PFNGLUNIFORM3I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z);\ntypedef void (APIENTRYP PFNGLUNIFORM4I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);\ntypedef void (APIENTRYP PFNGLUNIFORM1I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);\ntypedef void (APIENTRYP PFNGLUNIFORM1UI64ARBPROC) (GLint location, GLuint64 x);\ntypedef void (APIENTRYP PFNGLUNIFORM2UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y);\ntypedef void (APIENTRYP PFNGLUNIFORM3UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z);\ntypedef void (APIENTRYP PFNGLUNIFORM4UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);\ntypedef void (APIENTRYP PFNGLUNIFORM1UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);\ntypedef void (APIENTRYP PFNGLGETUNIFORMI64VARBPROC) (GLuint program, GLint location, GLint64 *params);\ntypedef void (APIENTRYP PFNGLGETUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLuint64 *params);\ntypedef void (APIENTRYP PFNGLGETNUNIFORMI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint64 *params);\ntypedef void (APIENTRYP PFNGLGETNUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64ARBPROC) (GLuint program, GLint location, GLint64 x);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64ARBPROC) (GLuint program, GLint location, GLuint64 x);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glUniform1i64ARB (GLint location, GLint64 x);\nGLAPI void APIENTRY glUniform2i64ARB (GLint location, GLint64 x, GLint64 y);\nGLAPI void APIENTRY glUniform3i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z);\nGLAPI void APIENTRY glUniform4i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);\nGLAPI void APIENTRY glUniform1i64vARB (GLint location, GLsizei count, const GLint64 *value);\nGLAPI void APIENTRY glUniform2i64vARB (GLint location, GLsizei count, const GLint64 *value);\nGLAPI void APIENTRY glUniform3i64vARB (GLint location, GLsizei count, const GLint64 *value);\nGLAPI void APIENTRY glUniform4i64vARB (GLint location, GLsizei count, const GLint64 *value);\nGLAPI void APIENTRY glUniform1ui64ARB (GLint location, GLuint64 x);\nGLAPI void APIENTRY glUniform2ui64ARB (GLint location, GLuint64 x, GLuint64 y);\nGLAPI void APIENTRY glUniform3ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z);\nGLAPI void APIENTRY glUniform4ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);\nGLAPI void APIENTRY glUniform1ui64vARB (GLint location, GLsizei count, const GLuint64 *value);\nGLAPI void APIENTRY glUniform2ui64vARB (GLint location, GLsizei count, const GLuint64 *value);\nGLAPI void APIENTRY glUniform3ui64vARB (GLint location, GLsizei count, const GLuint64 *value);\nGLAPI void APIENTRY glUniform4ui64vARB (GLint location, GLsizei count, const GLuint64 *value);\nGLAPI void APIENTRY glGetUniformi64vARB (GLuint program, GLint location, GLint64 *params);\nGLAPI void APIENTRY glGetUniformui64vARB (GLuint program, GLint location, GLuint64 *params);\nGLAPI void APIENTRY glGetnUniformi64vARB (GLuint program, GLint location, GLsizei bufSize, GLint64 *params);\nGLAPI void APIENTRY glGetnUniformui64vARB (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params);\nGLAPI void APIENTRY glProgramUniform1i64ARB (GLuint program, GLint location, GLint64 x);\nGLAPI void APIENTRY glProgramUniform2i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y);\nGLAPI void APIENTRY glProgramUniform3i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z);\nGLAPI void APIENTRY glProgramUniform4i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);\nGLAPI void APIENTRY glProgramUniform1i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);\nGLAPI void APIENTRY glProgramUniform2i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);\nGLAPI void APIENTRY glProgramUniform3i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);\nGLAPI void APIENTRY glProgramUniform4i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);\nGLAPI void APIENTRY glProgramUniform1ui64ARB (GLuint program, GLint location, GLuint64 x);\nGLAPI void APIENTRY glProgramUniform2ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y);\nGLAPI void APIENTRY glProgramUniform3ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z);\nGLAPI void APIENTRY glProgramUniform4ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);\nGLAPI void APIENTRY glProgramUniform1ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);\nGLAPI void APIENTRY glProgramUniform2ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);\nGLAPI void APIENTRY glProgramUniform3ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);\nGLAPI void APIENTRY glProgramUniform4ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);\n#endif\n#endif /* GL_ARB_gpu_shader_int64 */\n\n#ifndef GL_ARB_half_float_pixel\n#define GL_ARB_half_float_pixel 1\ntypedef khronos_uint16_t GLhalfARB;\n#define GL_HALF_FLOAT_ARB                 0x140B\n#endif /* GL_ARB_half_float_pixel */\n\n#ifndef GL_ARB_half_float_vertex\n#define GL_ARB_half_float_vertex 1\n#endif /* GL_ARB_half_float_vertex */\n\n#ifndef GL_ARB_imaging\n#define GL_ARB_imaging 1\n#define GL_CONVOLUTION_BORDER_MODE        0x8013\n#define GL_CONVOLUTION_FILTER_SCALE       0x8014\n#define GL_CONVOLUTION_FILTER_BIAS        0x8015\n#define GL_REDUCE                         0x8016\n#define GL_CONVOLUTION_FORMAT             0x8017\n#define GL_CONVOLUTION_WIDTH              0x8018\n#define GL_CONVOLUTION_HEIGHT             0x8019\n#define GL_MAX_CONVOLUTION_WIDTH          0x801A\n#define GL_MAX_CONVOLUTION_HEIGHT         0x801B\n#define GL_POST_CONVOLUTION_RED_SCALE     0x801C\n#define GL_POST_CONVOLUTION_GREEN_SCALE   0x801D\n#define GL_POST_CONVOLUTION_BLUE_SCALE    0x801E\n#define GL_POST_CONVOLUTION_ALPHA_SCALE   0x801F\n#define GL_POST_CONVOLUTION_RED_BIAS      0x8020\n#define GL_POST_CONVOLUTION_GREEN_BIAS    0x8021\n#define GL_POST_CONVOLUTION_BLUE_BIAS     0x8022\n#define GL_POST_CONVOLUTION_ALPHA_BIAS    0x8023\n#define GL_HISTOGRAM_WIDTH                0x8026\n#define GL_HISTOGRAM_FORMAT               0x8027\n#define GL_HISTOGRAM_RED_SIZE             0x8028\n#define GL_HISTOGRAM_GREEN_SIZE           0x8029\n#define GL_HISTOGRAM_BLUE_SIZE            0x802A\n#define GL_HISTOGRAM_ALPHA_SIZE           0x802B\n#define GL_HISTOGRAM_LUMINANCE_SIZE       0x802C\n#define GL_HISTOGRAM_SINK                 0x802D\n#define GL_MINMAX_FORMAT                  0x802F\n#define GL_MINMAX_SINK                    0x8030\n#define GL_TABLE_TOO_LARGE                0x8031\n#define GL_COLOR_MATRIX                   0x80B1\n#define GL_COLOR_MATRIX_STACK_DEPTH       0x80B2\n#define GL_MAX_COLOR_MATRIX_STACK_DEPTH   0x80B3\n#define GL_POST_COLOR_MATRIX_RED_SCALE    0x80B4\n#define GL_POST_COLOR_MATRIX_GREEN_SCALE  0x80B5\n#define GL_POST_COLOR_MATRIX_BLUE_SCALE   0x80B6\n#define GL_POST_COLOR_MATRIX_ALPHA_SCALE  0x80B7\n#define GL_POST_COLOR_MATRIX_RED_BIAS     0x80B8\n#define GL_POST_COLOR_MATRIX_GREEN_BIAS   0x80B9\n#define GL_POST_COLOR_MATRIX_BLUE_BIAS    0x80BA\n#define GL_POST_COLOR_MATRIX_ALPHA_BIAS   0x80BB\n#define GL_COLOR_TABLE_SCALE              0x80D6\n#define GL_COLOR_TABLE_BIAS               0x80D7\n#define GL_COLOR_TABLE_FORMAT             0x80D8\n#define GL_COLOR_TABLE_WIDTH              0x80D9\n#define GL_COLOR_TABLE_RED_SIZE           0x80DA\n#define GL_COLOR_TABLE_GREEN_SIZE         0x80DB\n#define GL_COLOR_TABLE_BLUE_SIZE          0x80DC\n#define GL_COLOR_TABLE_ALPHA_SIZE         0x80DD\n#define GL_COLOR_TABLE_LUMINANCE_SIZE     0x80DE\n#define GL_COLOR_TABLE_INTENSITY_SIZE     0x80DF\n#define GL_CONSTANT_BORDER                0x8151\n#define GL_REPLICATE_BORDER               0x8153\n#define GL_CONVOLUTION_BORDER_COLOR       0x8154\ntypedef void (APIENTRYP PFNGLCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);\ntypedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLCOPYCOLORTABLEPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPROC) (GLenum target, GLenum format, GLenum type, void *table);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);\ntypedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIPROC) (GLenum target, GLenum pname, GLint params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTERPROC) (GLenum target, GLenum format, GLenum type, void *image);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETSEPARABLEFILTERPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);\ntypedef void (APIENTRYP PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMINMAXPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);\ntypedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLHISTOGRAMPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);\ntypedef void (APIENTRYP PFNGLMINMAXPROC) (GLenum target, GLenum internalformat, GLboolean sink);\ntypedef void (APIENTRYP PFNGLRESETHISTOGRAMPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLRESETMINMAXPROC) (GLenum target);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);\nGLAPI void APIENTRY glColorTableParameterfv (GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glColorTableParameteriv (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\nGLAPI void APIENTRY glGetColorTable (GLenum target, GLenum format, GLenum type, void *table);\nGLAPI void APIENTRY glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);\nGLAPI void APIENTRY glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);\nGLAPI void APIENTRY glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);\nGLAPI void APIENTRY glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);\nGLAPI void APIENTRY glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params);\nGLAPI void APIENTRY glConvolutionParameterfv (GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glConvolutionParameteri (GLenum target, GLenum pname, GLint params);\nGLAPI void APIENTRY glConvolutionParameteriv (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\nGLAPI void APIENTRY glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, void *image);\nGLAPI void APIENTRY glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetSeparableFilter (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);\nGLAPI void APIENTRY glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);\nGLAPI void APIENTRY glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);\nGLAPI void APIENTRY glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);\nGLAPI void APIENTRY glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);\nGLAPI void APIENTRY glMinmax (GLenum target, GLenum internalformat, GLboolean sink);\nGLAPI void APIENTRY glResetHistogram (GLenum target);\nGLAPI void APIENTRY glResetMinmax (GLenum target);\n#endif\n#endif /* GL_ARB_imaging */\n\n#ifndef GL_ARB_indirect_parameters\n#define GL_ARB_indirect_parameters 1\n#define GL_PARAMETER_BUFFER_ARB           0x80EE\n#define GL_PARAMETER_BUFFER_BINDING_ARB   0x80EF\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMultiDrawArraysIndirectCountARB (GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\nGLAPI void APIENTRY glMultiDrawElementsIndirectCountARB (GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\n#endif\n#endif /* GL_ARB_indirect_parameters */\n\n#ifndef GL_ARB_instanced_arrays\n#define GL_ARB_instanced_arrays 1\n#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB 0x88FE\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORARBPROC) (GLuint index, GLuint divisor);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexAttribDivisorARB (GLuint index, GLuint divisor);\n#endif\n#endif /* GL_ARB_instanced_arrays */\n\n#ifndef GL_ARB_internalformat_query\n#define GL_ARB_internalformat_query 1\n#endif /* GL_ARB_internalformat_query */\n\n#ifndef GL_ARB_internalformat_query2\n#define GL_ARB_internalformat_query2 1\n#define GL_SRGB_DECODE_ARB                0x8299\n#define GL_VIEW_CLASS_EAC_R11             0x9383\n#define GL_VIEW_CLASS_EAC_RG11            0x9384\n#define GL_VIEW_CLASS_ETC2_RGB            0x9385\n#define GL_VIEW_CLASS_ETC2_RGBA           0x9386\n#define GL_VIEW_CLASS_ETC2_EAC_RGBA       0x9387\n#define GL_VIEW_CLASS_ASTC_4x4_RGBA       0x9388\n#define GL_VIEW_CLASS_ASTC_5x4_RGBA       0x9389\n#define GL_VIEW_CLASS_ASTC_5x5_RGBA       0x938A\n#define GL_VIEW_CLASS_ASTC_6x5_RGBA       0x938B\n#define GL_VIEW_CLASS_ASTC_6x6_RGBA       0x938C\n#define GL_VIEW_CLASS_ASTC_8x5_RGBA       0x938D\n#define GL_VIEW_CLASS_ASTC_8x6_RGBA       0x938E\n#define GL_VIEW_CLASS_ASTC_8x8_RGBA       0x938F\n#define GL_VIEW_CLASS_ASTC_10x5_RGBA      0x9390\n#define GL_VIEW_CLASS_ASTC_10x6_RGBA      0x9391\n#define GL_VIEW_CLASS_ASTC_10x8_RGBA      0x9392\n#define GL_VIEW_CLASS_ASTC_10x10_RGBA     0x9393\n#define GL_VIEW_CLASS_ASTC_12x10_RGBA     0x9394\n#define GL_VIEW_CLASS_ASTC_12x12_RGBA     0x9395\n#endif /* GL_ARB_internalformat_query2 */\n\n#ifndef GL_ARB_invalidate_subdata\n#define GL_ARB_invalidate_subdata 1\n#endif /* GL_ARB_invalidate_subdata */\n\n#ifndef GL_ARB_map_buffer_alignment\n#define GL_ARB_map_buffer_alignment 1\n#endif /* GL_ARB_map_buffer_alignment */\n\n#ifndef GL_ARB_map_buffer_range\n#define GL_ARB_map_buffer_range 1\n#endif /* GL_ARB_map_buffer_range */\n\n#ifndef GL_ARB_matrix_palette\n#define GL_ARB_matrix_palette 1\n#define GL_MATRIX_PALETTE_ARB             0x8840\n#define GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB 0x8841\n#define GL_MAX_PALETTE_MATRICES_ARB       0x8842\n#define GL_CURRENT_PALETTE_MATRIX_ARB     0x8843\n#define GL_MATRIX_INDEX_ARRAY_ARB         0x8844\n#define GL_CURRENT_MATRIX_INDEX_ARB       0x8845\n#define GL_MATRIX_INDEX_ARRAY_SIZE_ARB    0x8846\n#define GL_MATRIX_INDEX_ARRAY_TYPE_ARB    0x8847\n#define GL_MATRIX_INDEX_ARRAY_STRIDE_ARB  0x8848\n#define GL_MATRIX_INDEX_ARRAY_POINTER_ARB 0x8849\ntypedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXARBPROC) (GLint index);\ntypedef void (APIENTRYP PFNGLMATRIXINDEXUBVARBPROC) (GLint size, const GLubyte *indices);\ntypedef void (APIENTRYP PFNGLMATRIXINDEXUSVARBPROC) (GLint size, const GLushort *indices);\ntypedef void (APIENTRYP PFNGLMATRIXINDEXUIVARBPROC) (GLint size, const GLuint *indices);\ntypedef void (APIENTRYP PFNGLMATRIXINDEXPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCurrentPaletteMatrixARB (GLint index);\nGLAPI void APIENTRY glMatrixIndexubvARB (GLint size, const GLubyte *indices);\nGLAPI void APIENTRY glMatrixIndexusvARB (GLint size, const GLushort *indices);\nGLAPI void APIENTRY glMatrixIndexuivARB (GLint size, const GLuint *indices);\nGLAPI void APIENTRY glMatrixIndexPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer);\n#endif\n#endif /* GL_ARB_matrix_palette */\n\n#ifndef GL_ARB_multi_bind\n#define GL_ARB_multi_bind 1\n#endif /* GL_ARB_multi_bind */\n\n#ifndef GL_ARB_multi_draw_indirect\n#define GL_ARB_multi_draw_indirect 1\n#endif /* GL_ARB_multi_draw_indirect */\n\n#ifndef GL_ARB_multisample\n#define GL_ARB_multisample 1\n#define GL_MULTISAMPLE_ARB                0x809D\n#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB   0x809E\n#define GL_SAMPLE_ALPHA_TO_ONE_ARB        0x809F\n#define GL_SAMPLE_COVERAGE_ARB            0x80A0\n#define GL_SAMPLE_BUFFERS_ARB             0x80A8\n#define GL_SAMPLES_ARB                    0x80A9\n#define GL_SAMPLE_COVERAGE_VALUE_ARB      0x80AA\n#define GL_SAMPLE_COVERAGE_INVERT_ARB     0x80AB\n#define GL_MULTISAMPLE_BIT_ARB            0x20000000\ntypedef void (APIENTRYP PFNGLSAMPLECOVERAGEARBPROC) (GLfloat value, GLboolean invert);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSampleCoverageARB (GLfloat value, GLboolean invert);\n#endif\n#endif /* GL_ARB_multisample */\n\n#ifndef GL_ARB_multitexture\n#define GL_ARB_multitexture 1\n#define GL_TEXTURE0_ARB                   0x84C0\n#define GL_TEXTURE1_ARB                   0x84C1\n#define GL_TEXTURE2_ARB                   0x84C2\n#define GL_TEXTURE3_ARB                   0x84C3\n#define GL_TEXTURE4_ARB                   0x84C4\n#define GL_TEXTURE5_ARB                   0x84C5\n#define GL_TEXTURE6_ARB                   0x84C6\n#define GL_TEXTURE7_ARB                   0x84C7\n#define GL_TEXTURE8_ARB                   0x84C8\n#define GL_TEXTURE9_ARB                   0x84C9\n#define GL_TEXTURE10_ARB                  0x84CA\n#define GL_TEXTURE11_ARB                  0x84CB\n#define GL_TEXTURE12_ARB                  0x84CC\n#define GL_TEXTURE13_ARB                  0x84CD\n#define GL_TEXTURE14_ARB                  0x84CE\n#define GL_TEXTURE15_ARB                  0x84CF\n#define GL_TEXTURE16_ARB                  0x84D0\n#define GL_TEXTURE17_ARB                  0x84D1\n#define GL_TEXTURE18_ARB                  0x84D2\n#define GL_TEXTURE19_ARB                  0x84D3\n#define GL_TEXTURE20_ARB                  0x84D4\n#define GL_TEXTURE21_ARB                  0x84D5\n#define GL_TEXTURE22_ARB                  0x84D6\n#define GL_TEXTURE23_ARB                  0x84D7\n#define GL_TEXTURE24_ARB                  0x84D8\n#define GL_TEXTURE25_ARB                  0x84D9\n#define GL_TEXTURE26_ARB                  0x84DA\n#define GL_TEXTURE27_ARB                  0x84DB\n#define GL_TEXTURE28_ARB                  0x84DC\n#define GL_TEXTURE29_ARB                  0x84DD\n#define GL_TEXTURE30_ARB                  0x84DE\n#define GL_TEXTURE31_ARB                  0x84DF\n#define GL_ACTIVE_TEXTURE_ARB             0x84E0\n#define GL_CLIENT_ACTIVE_TEXTURE_ARB      0x84E1\n#define GL_MAX_TEXTURE_UNITS_ARB          0x84E2\ntypedef void (APIENTRYP PFNGLACTIVETEXTUREARBPROC) (GLenum texture);\ntypedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREARBPROC) (GLenum texture);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1DARBPROC) (GLenum target, GLdouble s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1FARBPROC) (GLenum target, GLfloat s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1IARBPROC) (GLenum target, GLint s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1SARBPROC) (GLenum target, GLshort s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2DARBPROC) (GLenum target, GLdouble s, GLdouble t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2IARBPROC) (GLenum target, GLint s, GLint t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2SARBPROC) (GLenum target, GLshort s, GLshort t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3IARBPROC) (GLenum target, GLint s, GLint t, GLint r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3SVARBPROC) (GLenum target, const GLshort *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4DARBPROC) (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4DVARBPROC) (GLenum target, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4FARBPROC) (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4FVARBPROC) (GLenum target, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4IARBPROC) (GLenum target, GLint s, GLint t, GLint r, GLint q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4IVARBPROC) (GLenum target, const GLint *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4SARBPROC) (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4SVARBPROC) (GLenum target, const GLshort *v);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glActiveTextureARB (GLenum texture);\nGLAPI void APIENTRY glClientActiveTextureARB (GLenum texture);\nGLAPI void APIENTRY glMultiTexCoord1dARB (GLenum target, GLdouble s);\nGLAPI void APIENTRY glMultiTexCoord1dvARB (GLenum target, const GLdouble *v);\nGLAPI void APIENTRY glMultiTexCoord1fARB (GLenum target, GLfloat s);\nGLAPI void APIENTRY glMultiTexCoord1fvARB (GLenum target, const GLfloat *v);\nGLAPI void APIENTRY glMultiTexCoord1iARB (GLenum target, GLint s);\nGLAPI void APIENTRY glMultiTexCoord1ivARB (GLenum target, const GLint *v);\nGLAPI void APIENTRY glMultiTexCoord1sARB (GLenum target, GLshort s);\nGLAPI void APIENTRY glMultiTexCoord1svARB (GLenum target, const GLshort *v);\nGLAPI void APIENTRY glMultiTexCoord2dARB (GLenum target, GLdouble s, GLdouble t);\nGLAPI void APIENTRY glMultiTexCoord2dvARB (GLenum target, const GLdouble *v);\nGLAPI void APIENTRY glMultiTexCoord2fARB (GLenum target, GLfloat s, GLfloat t);\nGLAPI void APIENTRY glMultiTexCoord2fvARB (GLenum target, const GLfloat *v);\nGLAPI void APIENTRY glMultiTexCoord2iARB (GLenum target, GLint s, GLint t);\nGLAPI void APIENTRY glMultiTexCoord2ivARB (GLenum target, const GLint *v);\nGLAPI void APIENTRY glMultiTexCoord2sARB (GLenum target, GLshort s, GLshort t);\nGLAPI void APIENTRY glMultiTexCoord2svARB (GLenum target, const GLshort *v);\nGLAPI void APIENTRY glMultiTexCoord3dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r);\nGLAPI void APIENTRY glMultiTexCoord3dvARB (GLenum target, const GLdouble *v);\nGLAPI void APIENTRY glMultiTexCoord3fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r);\nGLAPI void APIENTRY glMultiTexCoord3fvARB (GLenum target, const GLfloat *v);\nGLAPI void APIENTRY glMultiTexCoord3iARB (GLenum target, GLint s, GLint t, GLint r);\nGLAPI void APIENTRY glMultiTexCoord3ivARB (GLenum target, const GLint *v);\nGLAPI void APIENTRY glMultiTexCoord3sARB (GLenum target, GLshort s, GLshort t, GLshort r);\nGLAPI void APIENTRY glMultiTexCoord3svARB (GLenum target, const GLshort *v);\nGLAPI void APIENTRY glMultiTexCoord4dARB (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q);\nGLAPI void APIENTRY glMultiTexCoord4dvARB (GLenum target, const GLdouble *v);\nGLAPI void APIENTRY glMultiTexCoord4fARB (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);\nGLAPI void APIENTRY glMultiTexCoord4fvARB (GLenum target, const GLfloat *v);\nGLAPI void APIENTRY glMultiTexCoord4iARB (GLenum target, GLint s, GLint t, GLint r, GLint q);\nGLAPI void APIENTRY glMultiTexCoord4ivARB (GLenum target, const GLint *v);\nGLAPI void APIENTRY glMultiTexCoord4sARB (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q);\nGLAPI void APIENTRY glMultiTexCoord4svARB (GLenum target, const GLshort *v);\n#endif\n#endif /* GL_ARB_multitexture */\n\n#ifndef GL_ARB_occlusion_query\n#define GL_ARB_occlusion_query 1\n#define GL_QUERY_COUNTER_BITS_ARB         0x8864\n#define GL_CURRENT_QUERY_ARB              0x8865\n#define GL_QUERY_RESULT_ARB               0x8866\n#define GL_QUERY_RESULT_AVAILABLE_ARB     0x8867\n#define GL_SAMPLES_PASSED_ARB             0x8914\ntypedef void (APIENTRYP PFNGLGENQUERIESARBPROC) (GLsizei n, GLuint *ids);\ntypedef void (APIENTRYP PFNGLDELETEQUERIESARBPROC) (GLsizei n, const GLuint *ids);\ntypedef GLboolean (APIENTRYP PFNGLISQUERYARBPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLBEGINQUERYARBPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP PFNGLENDQUERYARBPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLGETQUERYIVARBPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTIVARBPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, GLuint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenQueriesARB (GLsizei n, GLuint *ids);\nGLAPI void APIENTRY glDeleteQueriesARB (GLsizei n, const GLuint *ids);\nGLAPI GLboolean APIENTRY glIsQueryARB (GLuint id);\nGLAPI void APIENTRY glBeginQueryARB (GLenum target, GLuint id);\nGLAPI void APIENTRY glEndQueryARB (GLenum target);\nGLAPI void APIENTRY glGetQueryivARB (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetQueryObjectivARB (GLuint id, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *params);\n#endif\n#endif /* GL_ARB_occlusion_query */\n\n#ifndef GL_ARB_occlusion_query2\n#define GL_ARB_occlusion_query2 1\n#endif /* GL_ARB_occlusion_query2 */\n\n#ifndef GL_ARB_parallel_shader_compile\n#define GL_ARB_parallel_shader_compile 1\n#define GL_MAX_SHADER_COMPILER_THREADS_ARB 0x91B0\n#define GL_COMPLETION_STATUS_ARB          0x91B1\ntypedef void (APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSARBPROC) (GLuint count);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMaxShaderCompilerThreadsARB (GLuint count);\n#endif\n#endif /* GL_ARB_parallel_shader_compile */\n\n#ifndef GL_ARB_pipeline_statistics_query\n#define GL_ARB_pipeline_statistics_query 1\n#define GL_VERTICES_SUBMITTED_ARB         0x82EE\n#define GL_PRIMITIVES_SUBMITTED_ARB       0x82EF\n#define GL_VERTEX_SHADER_INVOCATIONS_ARB  0x82F0\n#define GL_TESS_CONTROL_SHADER_PATCHES_ARB 0x82F1\n#define GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB 0x82F2\n#define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB 0x82F3\n#define GL_FRAGMENT_SHADER_INVOCATIONS_ARB 0x82F4\n#define GL_COMPUTE_SHADER_INVOCATIONS_ARB 0x82F5\n#define GL_CLIPPING_INPUT_PRIMITIVES_ARB  0x82F6\n#define GL_CLIPPING_OUTPUT_PRIMITIVES_ARB 0x82F7\n#endif /* GL_ARB_pipeline_statistics_query */\n\n#ifndef GL_ARB_pixel_buffer_object\n#define GL_ARB_pixel_buffer_object 1\n#define GL_PIXEL_PACK_BUFFER_ARB          0x88EB\n#define GL_PIXEL_UNPACK_BUFFER_ARB        0x88EC\n#define GL_PIXEL_PACK_BUFFER_BINDING_ARB  0x88ED\n#define GL_PIXEL_UNPACK_BUFFER_BINDING_ARB 0x88EF\n#endif /* GL_ARB_pixel_buffer_object */\n\n#ifndef GL_ARB_point_parameters\n#define GL_ARB_point_parameters 1\n#define GL_POINT_SIZE_MIN_ARB             0x8126\n#define GL_POINT_SIZE_MAX_ARB             0x8127\n#define GL_POINT_FADE_THRESHOLD_SIZE_ARB  0x8128\n#define GL_POINT_DISTANCE_ATTENUATION_ARB 0x8129\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFARBPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFVARBPROC) (GLenum pname, const GLfloat *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPointParameterfARB (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params);\n#endif\n#endif /* GL_ARB_point_parameters */\n\n#ifndef GL_ARB_point_sprite\n#define GL_ARB_point_sprite 1\n#define GL_POINT_SPRITE_ARB               0x8861\n#define GL_COORD_REPLACE_ARB              0x8862\n#endif /* GL_ARB_point_sprite */\n\n#ifndef GL_ARB_polygon_offset_clamp\n#define GL_ARB_polygon_offset_clamp 1\n#endif /* GL_ARB_polygon_offset_clamp */\n\n#ifndef GL_ARB_post_depth_coverage\n#define GL_ARB_post_depth_coverage 1\n#endif /* GL_ARB_post_depth_coverage */\n\n#ifndef GL_ARB_program_interface_query\n#define GL_ARB_program_interface_query 1\n#endif /* GL_ARB_program_interface_query */\n\n#ifndef GL_ARB_provoking_vertex\n#define GL_ARB_provoking_vertex 1\n#endif /* GL_ARB_provoking_vertex */\n\n#ifndef GL_ARB_query_buffer_object\n#define GL_ARB_query_buffer_object 1\n#endif /* GL_ARB_query_buffer_object */\n\n#ifndef GL_ARB_robust_buffer_access_behavior\n#define GL_ARB_robust_buffer_access_behavior 1\n#endif /* GL_ARB_robust_buffer_access_behavior */\n\n#ifndef GL_ARB_robustness\n#define GL_ARB_robustness 1\n#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB 0x00000004\n#define GL_LOSE_CONTEXT_ON_RESET_ARB      0x8252\n#define GL_GUILTY_CONTEXT_RESET_ARB       0x8253\n#define GL_INNOCENT_CONTEXT_RESET_ARB     0x8254\n#define GL_UNKNOWN_CONTEXT_RESET_ARB      0x8255\n#define GL_RESET_NOTIFICATION_STRATEGY_ARB 0x8256\n#define GL_NO_RESET_NOTIFICATION_ARB      0x8261\ntypedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSARBPROC) (void);\ntypedef void (APIENTRYP PFNGLGETNTEXIMAGEARBPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img);\ntypedef void (APIENTRYP PFNGLREADNPIXELSARBPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);\ntypedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLsizei bufSize, void *img);\ntypedef void (APIENTRYP PFNGLGETNUNIFORMFVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETNUNIFORMIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);\ntypedef void (APIENTRYP PFNGLGETNUNIFORMUIVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint *params);\ntypedef void (APIENTRYP PFNGLGETNUNIFORMDVARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETNMAPDVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);\ntypedef void (APIENTRYP PFNGLGETNMAPFVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);\ntypedef void (APIENTRYP PFNGLGETNMAPIVARBPROC) (GLenum target, GLenum query, GLsizei bufSize, GLint *v);\ntypedef void (APIENTRYP PFNGLGETNPIXELMAPFVARBPROC) (GLenum map, GLsizei bufSize, GLfloat *values);\ntypedef void (APIENTRYP PFNGLGETNPIXELMAPUIVARBPROC) (GLenum map, GLsizei bufSize, GLuint *values);\ntypedef void (APIENTRYP PFNGLGETNPIXELMAPUSVARBPROC) (GLenum map, GLsizei bufSize, GLushort *values);\ntypedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEARBPROC) (GLsizei bufSize, GLubyte *pattern);\ntypedef void (APIENTRYP PFNGLGETNCOLORTABLEARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);\ntypedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);\ntypedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERARBPROC) (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);\ntypedef void (APIENTRYP PFNGLGETNHISTOGRAMARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\ntypedef void (APIENTRYP PFNGLGETNMINMAXARBPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLenum APIENTRY glGetGraphicsResetStatusARB (void);\nGLAPI void APIENTRY glGetnTexImageARB (GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *img);\nGLAPI void APIENTRY glReadnPixelsARB (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);\nGLAPI void APIENTRY glGetnCompressedTexImageARB (GLenum target, GLint lod, GLsizei bufSize, void *img);\nGLAPI void APIENTRY glGetnUniformfvARB (GLuint program, GLint location, GLsizei bufSize, GLfloat *params);\nGLAPI void APIENTRY glGetnUniformivARB (GLuint program, GLint location, GLsizei bufSize, GLint *params);\nGLAPI void APIENTRY glGetnUniformuivARB (GLuint program, GLint location, GLsizei bufSize, GLuint *params);\nGLAPI void APIENTRY glGetnUniformdvARB (GLuint program, GLint location, GLsizei bufSize, GLdouble *params);\nGLAPI void APIENTRY glGetnMapdvARB (GLenum target, GLenum query, GLsizei bufSize, GLdouble *v);\nGLAPI void APIENTRY glGetnMapfvARB (GLenum target, GLenum query, GLsizei bufSize, GLfloat *v);\nGLAPI void APIENTRY glGetnMapivARB (GLenum target, GLenum query, GLsizei bufSize, GLint *v);\nGLAPI void APIENTRY glGetnPixelMapfvARB (GLenum map, GLsizei bufSize, GLfloat *values);\nGLAPI void APIENTRY glGetnPixelMapuivARB (GLenum map, GLsizei bufSize, GLuint *values);\nGLAPI void APIENTRY glGetnPixelMapusvARB (GLenum map, GLsizei bufSize, GLushort *values);\nGLAPI void APIENTRY glGetnPolygonStippleARB (GLsizei bufSize, GLubyte *pattern);\nGLAPI void APIENTRY glGetnColorTableARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table);\nGLAPI void APIENTRY glGetnConvolutionFilterARB (GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image);\nGLAPI void APIENTRY glGetnSeparableFilterARB (GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span);\nGLAPI void APIENTRY glGetnHistogramARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\nGLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values);\n#endif\n#endif /* GL_ARB_robustness */\n\n#ifndef GL_ARB_robustness_isolation\n#define GL_ARB_robustness_isolation 1\n#endif /* GL_ARB_robustness_isolation */\n\n#ifndef GL_ARB_sample_locations\n#define GL_ARB_sample_locations 1\n#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D\n#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E\n#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F\n#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340\n#define GL_SAMPLE_LOCATION_ARB            0x8E50\n#define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341\n#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342\n#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLEVALUATEDEPTHVALUESARBPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFramebufferSampleLocationsfvARB (GLenum target, GLuint start, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glNamedFramebufferSampleLocationsfvARB (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glEvaluateDepthValuesARB (void);\n#endif\n#endif /* GL_ARB_sample_locations */\n\n#ifndef GL_ARB_sample_shading\n#define GL_ARB_sample_shading 1\n#define GL_SAMPLE_SHADING_ARB             0x8C36\n#define GL_MIN_SAMPLE_SHADING_VALUE_ARB   0x8C37\ntypedef void (APIENTRYP PFNGLMINSAMPLESHADINGARBPROC) (GLfloat value);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMinSampleShadingARB (GLfloat value);\n#endif\n#endif /* GL_ARB_sample_shading */\n\n#ifndef GL_ARB_sampler_objects\n#define GL_ARB_sampler_objects 1\n#endif /* GL_ARB_sampler_objects */\n\n#ifndef GL_ARB_seamless_cube_map\n#define GL_ARB_seamless_cube_map 1\n#endif /* GL_ARB_seamless_cube_map */\n\n#ifndef GL_ARB_seamless_cubemap_per_texture\n#define GL_ARB_seamless_cubemap_per_texture 1\n#endif /* GL_ARB_seamless_cubemap_per_texture */\n\n#ifndef GL_ARB_separate_shader_objects\n#define GL_ARB_separate_shader_objects 1\n#endif /* GL_ARB_separate_shader_objects */\n\n#ifndef GL_ARB_shader_atomic_counter_ops\n#define GL_ARB_shader_atomic_counter_ops 1\n#endif /* GL_ARB_shader_atomic_counter_ops */\n\n#ifndef GL_ARB_shader_atomic_counters\n#define GL_ARB_shader_atomic_counters 1\n#endif /* GL_ARB_shader_atomic_counters */\n\n#ifndef GL_ARB_shader_ballot\n#define GL_ARB_shader_ballot 1\n#endif /* GL_ARB_shader_ballot */\n\n#ifndef GL_ARB_shader_bit_encoding\n#define GL_ARB_shader_bit_encoding 1\n#endif /* GL_ARB_shader_bit_encoding */\n\n#ifndef GL_ARB_shader_clock\n#define GL_ARB_shader_clock 1\n#endif /* GL_ARB_shader_clock */\n\n#ifndef GL_ARB_shader_draw_parameters\n#define GL_ARB_shader_draw_parameters 1\n#endif /* GL_ARB_shader_draw_parameters */\n\n#ifndef GL_ARB_shader_group_vote\n#define GL_ARB_shader_group_vote 1\n#endif /* GL_ARB_shader_group_vote */\n\n#ifndef GL_ARB_shader_image_load_store\n#define GL_ARB_shader_image_load_store 1\n#endif /* GL_ARB_shader_image_load_store */\n\n#ifndef GL_ARB_shader_image_size\n#define GL_ARB_shader_image_size 1\n#endif /* GL_ARB_shader_image_size */\n\n#ifndef GL_ARB_shader_objects\n#define GL_ARB_shader_objects 1\n#ifdef __APPLE__\ntypedef void *GLhandleARB;\n#else\ntypedef unsigned int GLhandleARB;\n#endif\ntypedef char GLcharARB;\n#define GL_PROGRAM_OBJECT_ARB             0x8B40\n#define GL_SHADER_OBJECT_ARB              0x8B48\n#define GL_OBJECT_TYPE_ARB                0x8B4E\n#define GL_OBJECT_SUBTYPE_ARB             0x8B4F\n#define GL_FLOAT_VEC2_ARB                 0x8B50\n#define GL_FLOAT_VEC3_ARB                 0x8B51\n#define GL_FLOAT_VEC4_ARB                 0x8B52\n#define GL_INT_VEC2_ARB                   0x8B53\n#define GL_INT_VEC3_ARB                   0x8B54\n#define GL_INT_VEC4_ARB                   0x8B55\n#define GL_BOOL_ARB                       0x8B56\n#define GL_BOOL_VEC2_ARB                  0x8B57\n#define GL_BOOL_VEC3_ARB                  0x8B58\n#define GL_BOOL_VEC4_ARB                  0x8B59\n#define GL_FLOAT_MAT2_ARB                 0x8B5A\n#define GL_FLOAT_MAT3_ARB                 0x8B5B\n#define GL_FLOAT_MAT4_ARB                 0x8B5C\n#define GL_SAMPLER_1D_ARB                 0x8B5D\n#define GL_SAMPLER_2D_ARB                 0x8B5E\n#define GL_SAMPLER_3D_ARB                 0x8B5F\n#define GL_SAMPLER_CUBE_ARB               0x8B60\n#define GL_SAMPLER_1D_SHADOW_ARB          0x8B61\n#define GL_SAMPLER_2D_SHADOW_ARB          0x8B62\n#define GL_SAMPLER_2D_RECT_ARB            0x8B63\n#define GL_SAMPLER_2D_RECT_SHADOW_ARB     0x8B64\n#define GL_OBJECT_DELETE_STATUS_ARB       0x8B80\n#define GL_OBJECT_COMPILE_STATUS_ARB      0x8B81\n#define GL_OBJECT_LINK_STATUS_ARB         0x8B82\n#define GL_OBJECT_VALIDATE_STATUS_ARB     0x8B83\n#define GL_OBJECT_INFO_LOG_LENGTH_ARB     0x8B84\n#define GL_OBJECT_ATTACHED_OBJECTS_ARB    0x8B85\n#define GL_OBJECT_ACTIVE_UNIFORMS_ARB     0x8B86\n#define GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB 0x8B87\n#define GL_OBJECT_SHADER_SOURCE_LENGTH_ARB 0x8B88\ntypedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj);\ntypedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname);\ntypedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj);\ntypedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType);\ntypedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length);\ntypedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj);\ntypedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void);\ntypedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj);\ntypedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj);\ntypedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj);\ntypedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj);\ntypedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0);\ntypedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1);\ntypedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (APIENTRYP PFNGLUNIFORM4FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (APIENTRYP PFNGLUNIFORM1IARBPROC) (GLint location, GLint v0);\ntypedef void (APIENTRYP PFNGLUNIFORM2IARBPROC) (GLint location, GLint v0, GLint v1);\ntypedef void (APIENTRYP PFNGLUNIFORM3IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (APIENTRYP PFNGLUNIFORM4IARBPROC) (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (APIENTRYP PFNGLUNIFORM1FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4FVARBPROC) (GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORM1IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);\ntypedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);\ntypedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);\ntypedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);\ntypedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params);\ntypedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj);\nGLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname);\nGLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj);\nGLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum shaderType);\nGLAPI void APIENTRY glShaderSourceARB (GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length);\nGLAPI void APIENTRY glCompileShaderARB (GLhandleARB shaderObj);\nGLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void);\nGLAPI void APIENTRY glAttachObjectARB (GLhandleARB containerObj, GLhandleARB obj);\nGLAPI void APIENTRY glLinkProgramARB (GLhandleARB programObj);\nGLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB programObj);\nGLAPI void APIENTRY glValidateProgramARB (GLhandleARB programObj);\nGLAPI void APIENTRY glUniform1fARB (GLint location, GLfloat v0);\nGLAPI void APIENTRY glUniform2fARB (GLint location, GLfloat v0, GLfloat v1);\nGLAPI void APIENTRY glUniform3fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\nGLAPI void APIENTRY glUniform4fARB (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\nGLAPI void APIENTRY glUniform1iARB (GLint location, GLint v0);\nGLAPI void APIENTRY glUniform2iARB (GLint location, GLint v0, GLint v1);\nGLAPI void APIENTRY glUniform3iARB (GLint location, GLint v0, GLint v1, GLint v2);\nGLAPI void APIENTRY glUniform4iARB (GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\nGLAPI void APIENTRY glUniform1fvARB (GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glUniform2fvARB (GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glUniform3fvARB (GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glUniform4fvARB (GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glUniform1ivARB (GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glUniform2ivARB (GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glUniform3ivARB (GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glUniform4ivARB (GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog);\nGLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj);\nGLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name);\nGLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);\nGLAPI void APIENTRY glGetUniformfvARB (GLhandleARB programObj, GLint location, GLfloat *params);\nGLAPI void APIENTRY glGetUniformivARB (GLhandleARB programObj, GLint location, GLint *params);\nGLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source);\n#endif\n#endif /* GL_ARB_shader_objects */\n\n#ifndef GL_ARB_shader_precision\n#define GL_ARB_shader_precision 1\n#endif /* GL_ARB_shader_precision */\n\n#ifndef GL_ARB_shader_stencil_export\n#define GL_ARB_shader_stencil_export 1\n#endif /* GL_ARB_shader_stencil_export */\n\n#ifndef GL_ARB_shader_storage_buffer_object\n#define GL_ARB_shader_storage_buffer_object 1\n#endif /* GL_ARB_shader_storage_buffer_object */\n\n#ifndef GL_ARB_shader_subroutine\n#define GL_ARB_shader_subroutine 1\n#endif /* GL_ARB_shader_subroutine */\n\n#ifndef GL_ARB_shader_texture_image_samples\n#define GL_ARB_shader_texture_image_samples 1\n#endif /* GL_ARB_shader_texture_image_samples */\n\n#ifndef GL_ARB_shader_texture_lod\n#define GL_ARB_shader_texture_lod 1\n#endif /* GL_ARB_shader_texture_lod */\n\n#ifndef GL_ARB_shader_viewport_layer_array\n#define GL_ARB_shader_viewport_layer_array 1\n#endif /* GL_ARB_shader_viewport_layer_array */\n\n#ifndef GL_ARB_shading_language_100\n#define GL_ARB_shading_language_100 1\n#define GL_SHADING_LANGUAGE_VERSION_ARB   0x8B8C\n#endif /* GL_ARB_shading_language_100 */\n\n#ifndef GL_ARB_shading_language_420pack\n#define GL_ARB_shading_language_420pack 1\n#endif /* GL_ARB_shading_language_420pack */\n\n#ifndef GL_ARB_shading_language_include\n#define GL_ARB_shading_language_include 1\n#define GL_SHADER_INCLUDE_ARB             0x8DAE\n#define GL_NAMED_STRING_LENGTH_ARB        0x8DE9\n#define GL_NAMED_STRING_TYPE_ARB          0x8DEA\ntypedef void (APIENTRYP PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string);\ntypedef void (APIENTRYP PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);\ntypedef void (APIENTRYP PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length);\ntypedef GLboolean (APIENTRYP PFNGLISNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name);\ntypedef void (APIENTRYP PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string);\ntypedef void (APIENTRYP PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar *name, GLenum pname, GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glNamedStringARB (GLenum type, GLint namelen, const GLchar *name, GLint stringlen, const GLchar *string);\nGLAPI void APIENTRY glDeleteNamedStringARB (GLint namelen, const GLchar *name);\nGLAPI void APIENTRY glCompileShaderIncludeARB (GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length);\nGLAPI GLboolean APIENTRY glIsNamedStringARB (GLint namelen, const GLchar *name);\nGLAPI void APIENTRY glGetNamedStringARB (GLint namelen, const GLchar *name, GLsizei bufSize, GLint *stringlen, GLchar *string);\nGLAPI void APIENTRY glGetNamedStringivARB (GLint namelen, const GLchar *name, GLenum pname, GLint *params);\n#endif\n#endif /* GL_ARB_shading_language_include */\n\n#ifndef GL_ARB_shading_language_packing\n#define GL_ARB_shading_language_packing 1\n#endif /* GL_ARB_shading_language_packing */\n\n#ifndef GL_ARB_shadow\n#define GL_ARB_shadow 1\n#define GL_TEXTURE_COMPARE_MODE_ARB       0x884C\n#define GL_TEXTURE_COMPARE_FUNC_ARB       0x884D\n#define GL_COMPARE_R_TO_TEXTURE_ARB       0x884E\n#endif /* GL_ARB_shadow */\n\n#ifndef GL_ARB_shadow_ambient\n#define GL_ARB_shadow_ambient 1\n#define GL_TEXTURE_COMPARE_FAIL_VALUE_ARB 0x80BF\n#endif /* GL_ARB_shadow_ambient */\n\n#ifndef GL_ARB_sparse_buffer\n#define GL_ARB_sparse_buffer 1\n#define GL_SPARSE_STORAGE_BIT_ARB         0x0400\n#define GL_SPARSE_BUFFER_PAGE_SIZE_ARB    0x82F8\ntypedef void (APIENTRYP PFNGLBUFFERPAGECOMMITMENTARBPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTARBPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBufferPageCommitmentARB (GLenum target, GLintptr offset, GLsizeiptr size, GLboolean commit);\nGLAPI void APIENTRY glNamedBufferPageCommitmentEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit);\nGLAPI void APIENTRY glNamedBufferPageCommitmentARB (GLuint buffer, GLintptr offset, GLsizeiptr size, GLboolean commit);\n#endif\n#endif /* GL_ARB_sparse_buffer */\n\n#ifndef GL_ARB_sparse_texture\n#define GL_ARB_sparse_texture 1\n#define GL_TEXTURE_SPARSE_ARB             0x91A6\n#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB    0x91A7\n#define GL_NUM_SPARSE_LEVELS_ARB          0x91AA\n#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB     0x91A8\n#define GL_VIRTUAL_PAGE_SIZE_X_ARB        0x9195\n#define GL_VIRTUAL_PAGE_SIZE_Y_ARB        0x9196\n#define GL_VIRTUAL_PAGE_SIZE_Z_ARB        0x9197\n#define GL_MAX_SPARSE_TEXTURE_SIZE_ARB    0x9198\n#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199\n#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A\n#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9\ntypedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);\n#endif\n#endif /* GL_ARB_sparse_texture */\n\n#ifndef GL_ARB_sparse_texture2\n#define GL_ARB_sparse_texture2 1\n#endif /* GL_ARB_sparse_texture2 */\n\n#ifndef GL_ARB_sparse_texture_clamp\n#define GL_ARB_sparse_texture_clamp 1\n#endif /* GL_ARB_sparse_texture_clamp */\n\n#ifndef GL_ARB_spirv_extensions\n#define GL_ARB_spirv_extensions 1\n#endif /* GL_ARB_spirv_extensions */\n\n#ifndef GL_ARB_stencil_texturing\n#define GL_ARB_stencil_texturing 1\n#endif /* GL_ARB_stencil_texturing */\n\n#ifndef GL_ARB_sync\n#define GL_ARB_sync 1\n#endif /* GL_ARB_sync */\n\n#ifndef GL_ARB_tessellation_shader\n#define GL_ARB_tessellation_shader 1\n#endif /* GL_ARB_tessellation_shader */\n\n#ifndef GL_ARB_texture_barrier\n#define GL_ARB_texture_barrier 1\n#endif /* GL_ARB_texture_barrier */\n\n#ifndef GL_ARB_texture_border_clamp\n#define GL_ARB_texture_border_clamp 1\n#define GL_CLAMP_TO_BORDER_ARB            0x812D\n#endif /* GL_ARB_texture_border_clamp */\n\n#ifndef GL_ARB_texture_buffer_object\n#define GL_ARB_texture_buffer_object 1\n#define GL_TEXTURE_BUFFER_ARB             0x8C2A\n#define GL_MAX_TEXTURE_BUFFER_SIZE_ARB    0x8C2B\n#define GL_TEXTURE_BINDING_BUFFER_ARB     0x8C2C\n#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_ARB 0x8C2D\n#define GL_TEXTURE_BUFFER_FORMAT_ARB      0x8C2E\ntypedef void (APIENTRYP PFNGLTEXBUFFERARBPROC) (GLenum target, GLenum internalformat, GLuint buffer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexBufferARB (GLenum target, GLenum internalformat, GLuint buffer);\n#endif\n#endif /* GL_ARB_texture_buffer_object */\n\n#ifndef GL_ARB_texture_buffer_object_rgb32\n#define GL_ARB_texture_buffer_object_rgb32 1\n#endif /* GL_ARB_texture_buffer_object_rgb32 */\n\n#ifndef GL_ARB_texture_buffer_range\n#define GL_ARB_texture_buffer_range 1\n#endif /* GL_ARB_texture_buffer_range */\n\n#ifndef GL_ARB_texture_compression\n#define GL_ARB_texture_compression 1\n#define GL_COMPRESSED_ALPHA_ARB           0x84E9\n#define GL_COMPRESSED_LUMINANCE_ARB       0x84EA\n#define GL_COMPRESSED_LUMINANCE_ALPHA_ARB 0x84EB\n#define GL_COMPRESSED_INTENSITY_ARB       0x84EC\n#define GL_COMPRESSED_RGB_ARB             0x84ED\n#define GL_COMPRESSED_RGBA_ARB            0x84EE\n#define GL_TEXTURE_COMPRESSION_HINT_ARB   0x84EF\n#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB 0x86A0\n#define GL_TEXTURE_COMPRESSED_ARB         0x86A1\n#define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2\n#define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint level, void *img);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCompressedTexImage3DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTexImage2DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTexImage1DARB (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTexSubImage3DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTexSubImage2DARB (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glCompressedTexSubImage1DARB (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data);\nGLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, void *img);\n#endif\n#endif /* GL_ARB_texture_compression */\n\n#ifndef GL_ARB_texture_compression_bptc\n#define GL_ARB_texture_compression_bptc 1\n#define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C\n#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D\n#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E\n#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F\n#endif /* GL_ARB_texture_compression_bptc */\n\n#ifndef GL_ARB_texture_compression_rgtc\n#define GL_ARB_texture_compression_rgtc 1\n#endif /* GL_ARB_texture_compression_rgtc */\n\n#ifndef GL_ARB_texture_cube_map\n#define GL_ARB_texture_cube_map 1\n#define GL_NORMAL_MAP_ARB                 0x8511\n#define GL_REFLECTION_MAP_ARB             0x8512\n#define GL_TEXTURE_CUBE_MAP_ARB           0x8513\n#define GL_TEXTURE_BINDING_CUBE_MAP_ARB   0x8514\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A\n#define GL_PROXY_TEXTURE_CUBE_MAP_ARB     0x851B\n#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB  0x851C\n#endif /* GL_ARB_texture_cube_map */\n\n#ifndef GL_ARB_texture_cube_map_array\n#define GL_ARB_texture_cube_map_array 1\n#define GL_TEXTURE_CUBE_MAP_ARRAY_ARB     0x9009\n#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY_ARB 0x900A\n#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY_ARB 0x900B\n#define GL_SAMPLER_CUBE_MAP_ARRAY_ARB     0x900C\n#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW_ARB 0x900D\n#define GL_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900E\n#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY_ARB 0x900F\n#endif /* GL_ARB_texture_cube_map_array */\n\n#ifndef GL_ARB_texture_env_add\n#define GL_ARB_texture_env_add 1\n#endif /* GL_ARB_texture_env_add */\n\n#ifndef GL_ARB_texture_env_combine\n#define GL_ARB_texture_env_combine 1\n#define GL_COMBINE_ARB                    0x8570\n#define GL_COMBINE_RGB_ARB                0x8571\n#define GL_COMBINE_ALPHA_ARB              0x8572\n#define GL_SOURCE0_RGB_ARB                0x8580\n#define GL_SOURCE1_RGB_ARB                0x8581\n#define GL_SOURCE2_RGB_ARB                0x8582\n#define GL_SOURCE0_ALPHA_ARB              0x8588\n#define GL_SOURCE1_ALPHA_ARB              0x8589\n#define GL_SOURCE2_ALPHA_ARB              0x858A\n#define GL_OPERAND0_RGB_ARB               0x8590\n#define GL_OPERAND1_RGB_ARB               0x8591\n#define GL_OPERAND2_RGB_ARB               0x8592\n#define GL_OPERAND0_ALPHA_ARB             0x8598\n#define GL_OPERAND1_ALPHA_ARB             0x8599\n#define GL_OPERAND2_ALPHA_ARB             0x859A\n#define GL_RGB_SCALE_ARB                  0x8573\n#define GL_ADD_SIGNED_ARB                 0x8574\n#define GL_INTERPOLATE_ARB                0x8575\n#define GL_SUBTRACT_ARB                   0x84E7\n#define GL_CONSTANT_ARB                   0x8576\n#define GL_PRIMARY_COLOR_ARB              0x8577\n#define GL_PREVIOUS_ARB                   0x8578\n#endif /* GL_ARB_texture_env_combine */\n\n#ifndef GL_ARB_texture_env_crossbar\n#define GL_ARB_texture_env_crossbar 1\n#endif /* GL_ARB_texture_env_crossbar */\n\n#ifndef GL_ARB_texture_env_dot3\n#define GL_ARB_texture_env_dot3 1\n#define GL_DOT3_RGB_ARB                   0x86AE\n#define GL_DOT3_RGBA_ARB                  0x86AF\n#endif /* GL_ARB_texture_env_dot3 */\n\n#ifndef GL_ARB_texture_filter_anisotropic\n#define GL_ARB_texture_filter_anisotropic 1\n#endif /* GL_ARB_texture_filter_anisotropic */\n\n#ifndef GL_ARB_texture_filter_minmax\n#define GL_ARB_texture_filter_minmax 1\n#define GL_TEXTURE_REDUCTION_MODE_ARB     0x9366\n#define GL_WEIGHTED_AVERAGE_ARB           0x9367\n#endif /* GL_ARB_texture_filter_minmax */\n\n#ifndef GL_ARB_texture_float\n#define GL_ARB_texture_float 1\n#define GL_TEXTURE_RED_TYPE_ARB           0x8C10\n#define GL_TEXTURE_GREEN_TYPE_ARB         0x8C11\n#define GL_TEXTURE_BLUE_TYPE_ARB          0x8C12\n#define GL_TEXTURE_ALPHA_TYPE_ARB         0x8C13\n#define GL_TEXTURE_LUMINANCE_TYPE_ARB     0x8C14\n#define GL_TEXTURE_INTENSITY_TYPE_ARB     0x8C15\n#define GL_TEXTURE_DEPTH_TYPE_ARB         0x8C16\n#define GL_UNSIGNED_NORMALIZED_ARB        0x8C17\n#define GL_RGBA32F_ARB                    0x8814\n#define GL_RGB32F_ARB                     0x8815\n#define GL_ALPHA32F_ARB                   0x8816\n#define GL_INTENSITY32F_ARB               0x8817\n#define GL_LUMINANCE32F_ARB               0x8818\n#define GL_LUMINANCE_ALPHA32F_ARB         0x8819\n#define GL_RGBA16F_ARB                    0x881A\n#define GL_RGB16F_ARB                     0x881B\n#define GL_ALPHA16F_ARB                   0x881C\n#define GL_INTENSITY16F_ARB               0x881D\n#define GL_LUMINANCE16F_ARB               0x881E\n#define GL_LUMINANCE_ALPHA16F_ARB         0x881F\n#endif /* GL_ARB_texture_float */\n\n#ifndef GL_ARB_texture_gather\n#define GL_ARB_texture_gather 1\n#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5E\n#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_ARB 0x8E5F\n#define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB 0x8F9F\n#endif /* GL_ARB_texture_gather */\n\n#ifndef GL_ARB_texture_mirror_clamp_to_edge\n#define GL_ARB_texture_mirror_clamp_to_edge 1\n#endif /* GL_ARB_texture_mirror_clamp_to_edge */\n\n#ifndef GL_ARB_texture_mirrored_repeat\n#define GL_ARB_texture_mirrored_repeat 1\n#define GL_MIRRORED_REPEAT_ARB            0x8370\n#endif /* GL_ARB_texture_mirrored_repeat */\n\n#ifndef GL_ARB_texture_multisample\n#define GL_ARB_texture_multisample 1\n#endif /* GL_ARB_texture_multisample */\n\n#ifndef GL_ARB_texture_non_power_of_two\n#define GL_ARB_texture_non_power_of_two 1\n#endif /* GL_ARB_texture_non_power_of_two */\n\n#ifndef GL_ARB_texture_query_levels\n#define GL_ARB_texture_query_levels 1\n#endif /* GL_ARB_texture_query_levels */\n\n#ifndef GL_ARB_texture_query_lod\n#define GL_ARB_texture_query_lod 1\n#endif /* GL_ARB_texture_query_lod */\n\n#ifndef GL_ARB_texture_rectangle\n#define GL_ARB_texture_rectangle 1\n#define GL_TEXTURE_RECTANGLE_ARB          0x84F5\n#define GL_TEXTURE_BINDING_RECTANGLE_ARB  0x84F6\n#define GL_PROXY_TEXTURE_RECTANGLE_ARB    0x84F7\n#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8\n#endif /* GL_ARB_texture_rectangle */\n\n#ifndef GL_ARB_texture_rg\n#define GL_ARB_texture_rg 1\n#endif /* GL_ARB_texture_rg */\n\n#ifndef GL_ARB_texture_rgb10_a2ui\n#define GL_ARB_texture_rgb10_a2ui 1\n#endif /* GL_ARB_texture_rgb10_a2ui */\n\n#ifndef GL_ARB_texture_stencil8\n#define GL_ARB_texture_stencil8 1\n#endif /* GL_ARB_texture_stencil8 */\n\n#ifndef GL_ARB_texture_storage\n#define GL_ARB_texture_storage 1\n#endif /* GL_ARB_texture_storage */\n\n#ifndef GL_ARB_texture_storage_multisample\n#define GL_ARB_texture_storage_multisample 1\n#endif /* GL_ARB_texture_storage_multisample */\n\n#ifndef GL_ARB_texture_swizzle\n#define GL_ARB_texture_swizzle 1\n#endif /* GL_ARB_texture_swizzle */\n\n#ifndef GL_ARB_texture_view\n#define GL_ARB_texture_view 1\n#endif /* GL_ARB_texture_view */\n\n#ifndef GL_ARB_timer_query\n#define GL_ARB_timer_query 1\n#endif /* GL_ARB_timer_query */\n\n#ifndef GL_ARB_transform_feedback2\n#define GL_ARB_transform_feedback2 1\n#endif /* GL_ARB_transform_feedback2 */\n\n#ifndef GL_ARB_transform_feedback3\n#define GL_ARB_transform_feedback3 1\n#endif /* GL_ARB_transform_feedback3 */\n\n#ifndef GL_ARB_transform_feedback_instanced\n#define GL_ARB_transform_feedback_instanced 1\n#endif /* GL_ARB_transform_feedback_instanced */\n\n#ifndef GL_ARB_transform_feedback_overflow_query\n#define GL_ARB_transform_feedback_overflow_query 1\n#define GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB 0x82EC\n#define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB 0x82ED\n#endif /* GL_ARB_transform_feedback_overflow_query */\n\n#ifndef GL_ARB_transpose_matrix\n#define GL_ARB_transpose_matrix 1\n#define GL_TRANSPOSE_MODELVIEW_MATRIX_ARB 0x84E3\n#define GL_TRANSPOSE_PROJECTION_MATRIX_ARB 0x84E4\n#define GL_TRANSPOSE_TEXTURE_MATRIX_ARB   0x84E5\n#define GL_TRANSPOSE_COLOR_MATRIX_ARB     0x84E6\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFARBPROC) (const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDARBPROC) (const GLdouble *m);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glLoadTransposeMatrixfARB (const GLfloat *m);\nGLAPI void APIENTRY glLoadTransposeMatrixdARB (const GLdouble *m);\nGLAPI void APIENTRY glMultTransposeMatrixfARB (const GLfloat *m);\nGLAPI void APIENTRY glMultTransposeMatrixdARB (const GLdouble *m);\n#endif\n#endif /* GL_ARB_transpose_matrix */\n\n#ifndef GL_ARB_uniform_buffer_object\n#define GL_ARB_uniform_buffer_object 1\n#endif /* GL_ARB_uniform_buffer_object */\n\n#ifndef GL_ARB_vertex_array_bgra\n#define GL_ARB_vertex_array_bgra 1\n#endif /* GL_ARB_vertex_array_bgra */\n\n#ifndef GL_ARB_vertex_array_object\n#define GL_ARB_vertex_array_object 1\n#endif /* GL_ARB_vertex_array_object */\n\n#ifndef GL_ARB_vertex_attrib_64bit\n#define GL_ARB_vertex_attrib_64bit 1\n#endif /* GL_ARB_vertex_attrib_64bit */\n\n#ifndef GL_ARB_vertex_attrib_binding\n#define GL_ARB_vertex_attrib_binding 1\n#endif /* GL_ARB_vertex_attrib_binding */\n\n#ifndef GL_ARB_vertex_blend\n#define GL_ARB_vertex_blend 1\n#define GL_MAX_VERTEX_UNITS_ARB           0x86A4\n#define GL_ACTIVE_VERTEX_UNITS_ARB        0x86A5\n#define GL_WEIGHT_SUM_UNITY_ARB           0x86A6\n#define GL_VERTEX_BLEND_ARB               0x86A7\n#define GL_CURRENT_WEIGHT_ARB             0x86A8\n#define GL_WEIGHT_ARRAY_TYPE_ARB          0x86A9\n#define GL_WEIGHT_ARRAY_STRIDE_ARB        0x86AA\n#define GL_WEIGHT_ARRAY_SIZE_ARB          0x86AB\n#define GL_WEIGHT_ARRAY_POINTER_ARB       0x86AC\n#define GL_WEIGHT_ARRAY_ARB               0x86AD\n#define GL_MODELVIEW0_ARB                 0x1700\n#define GL_MODELVIEW1_ARB                 0x850A\n#define GL_MODELVIEW2_ARB                 0x8722\n#define GL_MODELVIEW3_ARB                 0x8723\n#define GL_MODELVIEW4_ARB                 0x8724\n#define GL_MODELVIEW5_ARB                 0x8725\n#define GL_MODELVIEW6_ARB                 0x8726\n#define GL_MODELVIEW7_ARB                 0x8727\n#define GL_MODELVIEW8_ARB                 0x8728\n#define GL_MODELVIEW9_ARB                 0x8729\n#define GL_MODELVIEW10_ARB                0x872A\n#define GL_MODELVIEW11_ARB                0x872B\n#define GL_MODELVIEW12_ARB                0x872C\n#define GL_MODELVIEW13_ARB                0x872D\n#define GL_MODELVIEW14_ARB                0x872E\n#define GL_MODELVIEW15_ARB                0x872F\n#define GL_MODELVIEW16_ARB                0x8730\n#define GL_MODELVIEW17_ARB                0x8731\n#define GL_MODELVIEW18_ARB                0x8732\n#define GL_MODELVIEW19_ARB                0x8733\n#define GL_MODELVIEW20_ARB                0x8734\n#define GL_MODELVIEW21_ARB                0x8735\n#define GL_MODELVIEW22_ARB                0x8736\n#define GL_MODELVIEW23_ARB                0x8737\n#define GL_MODELVIEW24_ARB                0x8738\n#define GL_MODELVIEW25_ARB                0x8739\n#define GL_MODELVIEW26_ARB                0x873A\n#define GL_MODELVIEW27_ARB                0x873B\n#define GL_MODELVIEW28_ARB                0x873C\n#define GL_MODELVIEW29_ARB                0x873D\n#define GL_MODELVIEW30_ARB                0x873E\n#define GL_MODELVIEW31_ARB                0x873F\ntypedef void (APIENTRYP PFNGLWEIGHTBVARBPROC) (GLint size, const GLbyte *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTSVARBPROC) (GLint size, const GLshort *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTIVARBPROC) (GLint size, const GLint *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTFVARBPROC) (GLint size, const GLfloat *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTDVARBPROC) (GLint size, const GLdouble *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTUBVARBPROC) (GLint size, const GLubyte *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTUSVARBPROC) (GLint size, const GLushort *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTUIVARBPROC) (GLint size, const GLuint *weights);\ntypedef void (APIENTRYP PFNGLWEIGHTPOINTERARBPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLVERTEXBLENDARBPROC) (GLint count);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glWeightbvARB (GLint size, const GLbyte *weights);\nGLAPI void APIENTRY glWeightsvARB (GLint size, const GLshort *weights);\nGLAPI void APIENTRY glWeightivARB (GLint size, const GLint *weights);\nGLAPI void APIENTRY glWeightfvARB (GLint size, const GLfloat *weights);\nGLAPI void APIENTRY glWeightdvARB (GLint size, const GLdouble *weights);\nGLAPI void APIENTRY glWeightubvARB (GLint size, const GLubyte *weights);\nGLAPI void APIENTRY glWeightusvARB (GLint size, const GLushort *weights);\nGLAPI void APIENTRY glWeightuivARB (GLint size, const GLuint *weights);\nGLAPI void APIENTRY glWeightPointerARB (GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glVertexBlendARB (GLint count);\n#endif\n#endif /* GL_ARB_vertex_blend */\n\n#ifndef GL_ARB_vertex_buffer_object\n#define GL_ARB_vertex_buffer_object 1\ntypedef khronos_ssize_t GLsizeiptrARB;\ntypedef khronos_intptr_t GLintptrARB;\n#define GL_BUFFER_SIZE_ARB                0x8764\n#define GL_BUFFER_USAGE_ARB               0x8765\n#define GL_ARRAY_BUFFER_ARB               0x8892\n#define GL_ELEMENT_ARRAY_BUFFER_ARB       0x8893\n#define GL_ARRAY_BUFFER_BINDING_ARB       0x8894\n#define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895\n#define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896\n#define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897\n#define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898\n#define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899\n#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A\n#define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B\n#define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C\n#define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D\n#define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E\n#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F\n#define GL_READ_ONLY_ARB                  0x88B8\n#define GL_WRITE_ONLY_ARB                 0x88B9\n#define GL_READ_WRITE_ARB                 0x88BA\n#define GL_BUFFER_ACCESS_ARB              0x88BB\n#define GL_BUFFER_MAPPED_ARB              0x88BC\n#define GL_BUFFER_MAP_POINTER_ARB         0x88BD\n#define GL_STREAM_DRAW_ARB                0x88E0\n#define GL_STREAM_READ_ARB                0x88E1\n#define GL_STREAM_COPY_ARB                0x88E2\n#define GL_STATIC_DRAW_ARB                0x88E4\n#define GL_STATIC_READ_ARB                0x88E5\n#define GL_STATIC_COPY_ARB                0x88E6\n#define GL_DYNAMIC_DRAW_ARB               0x88E8\n#define GL_DYNAMIC_READ_ARB               0x88E9\n#define GL_DYNAMIC_COPY_ARB               0x88EA\ntypedef void (APIENTRYP PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer);\ntypedef void (APIENTRYP PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint *buffers);\ntypedef void (APIENTRYP PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint *buffers);\ntypedef GLboolean (APIENTRYP PFNGLISBUFFERARBPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);\ntypedef void (APIENTRYP PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);\ntypedef void (APIENTRYP PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);\ntypedef void *(APIENTRYP PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access);\ntypedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERARBPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, void **params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBindBufferARB (GLenum target, GLuint buffer);\nGLAPI void APIENTRY glDeleteBuffersARB (GLsizei n, const GLuint *buffers);\nGLAPI void APIENTRY glGenBuffersARB (GLsizei n, GLuint *buffers);\nGLAPI GLboolean APIENTRY glIsBufferARB (GLuint buffer);\nGLAPI void APIENTRY glBufferDataARB (GLenum target, GLsizeiptrARB size, const void *data, GLenum usage);\nGLAPI void APIENTRY glBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const void *data);\nGLAPI void APIENTRY glGetBufferSubDataARB (GLenum target, GLintptrARB offset, GLsizeiptrARB size, void *data);\nGLAPI void *APIENTRY glMapBufferARB (GLenum target, GLenum access);\nGLAPI GLboolean APIENTRY glUnmapBufferARB (GLenum target);\nGLAPI void APIENTRY glGetBufferParameterivARB (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetBufferPointervARB (GLenum target, GLenum pname, void **params);\n#endif\n#endif /* GL_ARB_vertex_buffer_object */\n\n#ifndef GL_ARB_vertex_program\n#define GL_ARB_vertex_program 1\n#define GL_COLOR_SUM_ARB                  0x8458\n#define GL_VERTEX_PROGRAM_ARB             0x8620\n#define GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB 0x8622\n#define GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB   0x8623\n#define GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB 0x8624\n#define GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB   0x8625\n#define GL_CURRENT_VERTEX_ATTRIB_ARB      0x8626\n#define GL_VERTEX_PROGRAM_POINT_SIZE_ARB  0x8642\n#define GL_VERTEX_PROGRAM_TWO_SIDE_ARB    0x8643\n#define GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB 0x8645\n#define GL_MAX_VERTEX_ATTRIBS_ARB         0x8869\n#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB 0x886A\n#define GL_PROGRAM_ADDRESS_REGISTERS_ARB  0x88B0\n#define GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB 0x88B1\n#define GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B2\n#define GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB 0x88B3\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SARBPROC) (GLuint index, GLshort x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DARBPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FARBPROC) (GLuint index, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SARBPROC) (GLuint index, GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVARBPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVARBPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBARBPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVARBPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVARBPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVARBPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4BVARBPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DARBPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DVARBPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FARBPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FVARBPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4IVARBPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SARBPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);\ntypedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) (GLuint index);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVARBPROC) (GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVARBPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, void **pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexAttrib1dARB (GLuint index, GLdouble x);\nGLAPI void APIENTRY glVertexAttrib1dvARB (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib1fARB (GLuint index, GLfloat x);\nGLAPI void APIENTRY glVertexAttrib1fvARB (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib1sARB (GLuint index, GLshort x);\nGLAPI void APIENTRY glVertexAttrib1svARB (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib2dARB (GLuint index, GLdouble x, GLdouble y);\nGLAPI void APIENTRY glVertexAttrib2dvARB (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib2fARB (GLuint index, GLfloat x, GLfloat y);\nGLAPI void APIENTRY glVertexAttrib2fvARB (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib2sARB (GLuint index, GLshort x, GLshort y);\nGLAPI void APIENTRY glVertexAttrib2svARB (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib3dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glVertexAttrib3dvARB (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib3fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glVertexAttrib3fvARB (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib3sARB (GLuint index, GLshort x, GLshort y, GLshort z);\nGLAPI void APIENTRY glVertexAttrib3svARB (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib4NbvARB (GLuint index, const GLbyte *v);\nGLAPI void APIENTRY glVertexAttrib4NivARB (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttrib4NsvARB (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib4NubARB (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\nGLAPI void APIENTRY glVertexAttrib4NubvARB (GLuint index, const GLubyte *v);\nGLAPI void APIENTRY glVertexAttrib4NuivARB (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttrib4NusvARB (GLuint index, const GLushort *v);\nGLAPI void APIENTRY glVertexAttrib4bvARB (GLuint index, const GLbyte *v);\nGLAPI void APIENTRY glVertexAttrib4dARB (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glVertexAttrib4dvARB (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib4fARB (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glVertexAttrib4fvARB (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib4ivARB (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttrib4sARB (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\nGLAPI void APIENTRY glVertexAttrib4svARB (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib4ubvARB (GLuint index, const GLubyte *v);\nGLAPI void APIENTRY glVertexAttrib4uivARB (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttrib4usvARB (GLuint index, const GLushort *v);\nGLAPI void APIENTRY glVertexAttribPointerARB (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glEnableVertexAttribArrayARB (GLuint index);\nGLAPI void APIENTRY glDisableVertexAttribArrayARB (GLuint index);\nGLAPI void APIENTRY glGetVertexAttribdvARB (GLuint index, GLenum pname, GLdouble *params);\nGLAPI void APIENTRY glGetVertexAttribfvARB (GLuint index, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetVertexAttribivARB (GLuint index, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetVertexAttribPointervARB (GLuint index, GLenum pname, void **pointer);\n#endif\n#endif /* GL_ARB_vertex_program */\n\n#ifndef GL_ARB_vertex_shader\n#define GL_ARB_vertex_shader 1\n#define GL_VERTEX_SHADER_ARB              0x8B31\n#define GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB 0x8B4A\n#define GL_MAX_VARYING_FLOATS_ARB         0x8B4B\n#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB 0x8B4C\n#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB 0x8B4D\n#define GL_OBJECT_ACTIVE_ATTRIBUTES_ARB   0x8B89\n#define GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB 0x8B8A\ntypedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name);\ntypedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);\ntypedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB programObj, GLuint index, const GLcharARB *name);\nGLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name);\nGLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB programObj, const GLcharARB *name);\n#endif\n#endif /* GL_ARB_vertex_shader */\n\n#ifndef GL_ARB_vertex_type_10f_11f_11f_rev\n#define GL_ARB_vertex_type_10f_11f_11f_rev 1\n#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */\n\n#ifndef GL_ARB_vertex_type_2_10_10_10_rev\n#define GL_ARB_vertex_type_2_10_10_10_rev 1\n#endif /* GL_ARB_vertex_type_2_10_10_10_rev */\n\n#ifndef GL_ARB_viewport_array\n#define GL_ARB_viewport_array 1\ntypedef void (APIENTRYP PFNGLDEPTHRANGEARRAYDVNVPROC) (GLuint first, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDDNVPROC) (GLuint index, GLdouble n, GLdouble f);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDepthRangeArraydvNV (GLuint first, GLsizei count, const GLdouble *v);\nGLAPI void APIENTRY glDepthRangeIndexeddNV (GLuint index, GLdouble n, GLdouble f);\n#endif\n#endif /* GL_ARB_viewport_array */\n\n#ifndef GL_ARB_window_pos\n#define GL_ARB_window_pos 1\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DARBPROC) (GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DVARBPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FARBPROC) (GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FVARBPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IARBPROC) (GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IVARBPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SARBPROC) (GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SVARBPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DARBPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DVARBPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FARBPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FVARBPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IARBPROC) (GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IVARBPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SARBPROC) (GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SVARBPROC) (const GLshort *v);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glWindowPos2dARB (GLdouble x, GLdouble y);\nGLAPI void APIENTRY glWindowPos2dvARB (const GLdouble *v);\nGLAPI void APIENTRY glWindowPos2fARB (GLfloat x, GLfloat y);\nGLAPI void APIENTRY glWindowPos2fvARB (const GLfloat *v);\nGLAPI void APIENTRY glWindowPos2iARB (GLint x, GLint y);\nGLAPI void APIENTRY glWindowPos2ivARB (const GLint *v);\nGLAPI void APIENTRY glWindowPos2sARB (GLshort x, GLshort y);\nGLAPI void APIENTRY glWindowPos2svARB (const GLshort *v);\nGLAPI void APIENTRY glWindowPos3dARB (GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glWindowPos3dvARB (const GLdouble *v);\nGLAPI void APIENTRY glWindowPos3fARB (GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glWindowPos3fvARB (const GLfloat *v);\nGLAPI void APIENTRY glWindowPos3iARB (GLint x, GLint y, GLint z);\nGLAPI void APIENTRY glWindowPos3ivARB (const GLint *v);\nGLAPI void APIENTRY glWindowPos3sARB (GLshort x, GLshort y, GLshort z);\nGLAPI void APIENTRY glWindowPos3svARB (const GLshort *v);\n#endif\n#endif /* GL_ARB_window_pos */\n\n#ifndef GL_KHR_blend_equation_advanced\n#define GL_KHR_blend_equation_advanced 1\n#define GL_MULTIPLY_KHR                   0x9294\n#define GL_SCREEN_KHR                     0x9295\n#define GL_OVERLAY_KHR                    0x9296\n#define GL_DARKEN_KHR                     0x9297\n#define GL_LIGHTEN_KHR                    0x9298\n#define GL_COLORDODGE_KHR                 0x9299\n#define GL_COLORBURN_KHR                  0x929A\n#define GL_HARDLIGHT_KHR                  0x929B\n#define GL_SOFTLIGHT_KHR                  0x929C\n#define GL_DIFFERENCE_KHR                 0x929E\n#define GL_EXCLUSION_KHR                  0x92A0\n#define GL_HSL_HUE_KHR                    0x92AD\n#define GL_HSL_SATURATION_KHR             0x92AE\n#define GL_HSL_COLOR_KHR                  0x92AF\n#define GL_HSL_LUMINOSITY_KHR             0x92B0\ntypedef void (APIENTRYP PFNGLBLENDBARRIERKHRPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendBarrierKHR (void);\n#endif\n#endif /* GL_KHR_blend_equation_advanced */\n\n#ifndef GL_KHR_blend_equation_advanced_coherent\n#define GL_KHR_blend_equation_advanced_coherent 1\n#define GL_BLEND_ADVANCED_COHERENT_KHR    0x9285\n#endif /* GL_KHR_blend_equation_advanced_coherent */\n\n#ifndef GL_KHR_context_flush_control\n#define GL_KHR_context_flush_control 1\n#endif /* GL_KHR_context_flush_control */\n\n#ifndef GL_KHR_debug\n#define GL_KHR_debug 1\n#endif /* GL_KHR_debug */\n\n#ifndef GL_KHR_no_error\n#define GL_KHR_no_error 1\n#define GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR  0x00000008\n#endif /* GL_KHR_no_error */\n\n#ifndef GL_KHR_parallel_shader_compile\n#define GL_KHR_parallel_shader_compile 1\n#define GL_MAX_SHADER_COMPILER_THREADS_KHR 0x91B0\n#define GL_COMPLETION_STATUS_KHR          0x91B1\ntypedef void (APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSKHRPROC) (GLuint count);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMaxShaderCompilerThreadsKHR (GLuint count);\n#endif\n#endif /* GL_KHR_parallel_shader_compile */\n\n#ifndef GL_KHR_robust_buffer_access_behavior\n#define GL_KHR_robust_buffer_access_behavior 1\n#endif /* GL_KHR_robust_buffer_access_behavior */\n\n#ifndef GL_KHR_robustness\n#define GL_KHR_robustness 1\n#define GL_CONTEXT_ROBUST_ACCESS          0x90F3\n#endif /* GL_KHR_robustness */\n\n#ifndef GL_KHR_shader_subgroup\n#define GL_KHR_shader_subgroup 1\n#define GL_SUBGROUP_SIZE_KHR              0x9532\n#define GL_SUBGROUP_SUPPORTED_STAGES_KHR  0x9533\n#define GL_SUBGROUP_SUPPORTED_FEATURES_KHR 0x9534\n#define GL_SUBGROUP_QUAD_ALL_STAGES_KHR   0x9535\n#define GL_SUBGROUP_FEATURE_BASIC_BIT_KHR 0x00000001\n#define GL_SUBGROUP_FEATURE_VOTE_BIT_KHR  0x00000002\n#define GL_SUBGROUP_FEATURE_ARITHMETIC_BIT_KHR 0x00000004\n#define GL_SUBGROUP_FEATURE_BALLOT_BIT_KHR 0x00000008\n#define GL_SUBGROUP_FEATURE_SHUFFLE_BIT_KHR 0x00000010\n#define GL_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT_KHR 0x00000020\n#define GL_SUBGROUP_FEATURE_CLUSTERED_BIT_KHR 0x00000040\n#define GL_SUBGROUP_FEATURE_QUAD_BIT_KHR  0x00000080\n#endif /* GL_KHR_shader_subgroup */\n\n#ifndef GL_KHR_texture_compression_astc_hdr\n#define GL_KHR_texture_compression_astc_hdr 1\n#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR   0x93B0\n#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR   0x93B1\n#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR   0x93B2\n#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR   0x93B3\n#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR   0x93B4\n#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR   0x93B5\n#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR   0x93B6\n#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR   0x93B7\n#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR  0x93B8\n#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR  0x93B9\n#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR  0x93BA\n#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB\n#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC\n#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC\n#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD\n#endif /* GL_KHR_texture_compression_astc_hdr */\n\n#ifndef GL_KHR_texture_compression_astc_ldr\n#define GL_KHR_texture_compression_astc_ldr 1\n#endif /* GL_KHR_texture_compression_astc_ldr */\n\n#ifndef GL_KHR_texture_compression_astc_sliced_3d\n#define GL_KHR_texture_compression_astc_sliced_3d 1\n#endif /* GL_KHR_texture_compression_astc_sliced_3d */\n\n#ifndef GL_OES_byte_coordinates\n#define GL_OES_byte_coordinates 1\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1BVOESPROC) (GLenum texture, const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2BOESPROC) (GLenum texture, GLbyte s, GLbyte t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2BVOESPROC) (GLenum texture, const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3BVOESPROC) (GLenum texture, const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4BOESPROC) (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4BVOESPROC) (GLenum texture, const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLTEXCOORD1BOESPROC) (GLbyte s);\ntypedef void (APIENTRYP PFNGLTEXCOORD1BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLTEXCOORD2BOESPROC) (GLbyte s, GLbyte t);\ntypedef void (APIENTRYP PFNGLTEXCOORD2BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLTEXCOORD3BOESPROC) (GLbyte s, GLbyte t, GLbyte r);\ntypedef void (APIENTRYP PFNGLTEXCOORD3BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLTEXCOORD4BOESPROC) (GLbyte s, GLbyte t, GLbyte r, GLbyte q);\ntypedef void (APIENTRYP PFNGLTEXCOORD4BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLVERTEX2BOESPROC) (GLbyte x, GLbyte y);\ntypedef void (APIENTRYP PFNGLVERTEX2BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLVERTEX3BOESPROC) (GLbyte x, GLbyte y, GLbyte z);\ntypedef void (APIENTRYP PFNGLVERTEX3BVOESPROC) (const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLVERTEX4BOESPROC) (GLbyte x, GLbyte y, GLbyte z, GLbyte w);\ntypedef void (APIENTRYP PFNGLVERTEX4BVOESPROC) (const GLbyte *coords);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMultiTexCoord1bOES (GLenum texture, GLbyte s);\nGLAPI void APIENTRY glMultiTexCoord1bvOES (GLenum texture, const GLbyte *coords);\nGLAPI void APIENTRY glMultiTexCoord2bOES (GLenum texture, GLbyte s, GLbyte t);\nGLAPI void APIENTRY glMultiTexCoord2bvOES (GLenum texture, const GLbyte *coords);\nGLAPI void APIENTRY glMultiTexCoord3bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r);\nGLAPI void APIENTRY glMultiTexCoord3bvOES (GLenum texture, const GLbyte *coords);\nGLAPI void APIENTRY glMultiTexCoord4bOES (GLenum texture, GLbyte s, GLbyte t, GLbyte r, GLbyte q);\nGLAPI void APIENTRY glMultiTexCoord4bvOES (GLenum texture, const GLbyte *coords);\nGLAPI void APIENTRY glTexCoord1bOES (GLbyte s);\nGLAPI void APIENTRY glTexCoord1bvOES (const GLbyte *coords);\nGLAPI void APIENTRY glTexCoord2bOES (GLbyte s, GLbyte t);\nGLAPI void APIENTRY glTexCoord2bvOES (const GLbyte *coords);\nGLAPI void APIENTRY glTexCoord3bOES (GLbyte s, GLbyte t, GLbyte r);\nGLAPI void APIENTRY glTexCoord3bvOES (const GLbyte *coords);\nGLAPI void APIENTRY glTexCoord4bOES (GLbyte s, GLbyte t, GLbyte r, GLbyte q);\nGLAPI void APIENTRY glTexCoord4bvOES (const GLbyte *coords);\nGLAPI void APIENTRY glVertex2bOES (GLbyte x, GLbyte y);\nGLAPI void APIENTRY glVertex2bvOES (const GLbyte *coords);\nGLAPI void APIENTRY glVertex3bOES (GLbyte x, GLbyte y, GLbyte z);\nGLAPI void APIENTRY glVertex3bvOES (const GLbyte *coords);\nGLAPI void APIENTRY glVertex4bOES (GLbyte x, GLbyte y, GLbyte z, GLbyte w);\nGLAPI void APIENTRY glVertex4bvOES (const GLbyte *coords);\n#endif\n#endif /* GL_OES_byte_coordinates */\n\n#ifndef GL_OES_compressed_paletted_texture\n#define GL_OES_compressed_paletted_texture 1\n#define GL_PALETTE4_RGB8_OES              0x8B90\n#define GL_PALETTE4_RGBA8_OES             0x8B91\n#define GL_PALETTE4_R5_G6_B5_OES          0x8B92\n#define GL_PALETTE4_RGBA4_OES             0x8B93\n#define GL_PALETTE4_RGB5_A1_OES           0x8B94\n#define GL_PALETTE8_RGB8_OES              0x8B95\n#define GL_PALETTE8_RGBA8_OES             0x8B96\n#define GL_PALETTE8_R5_G6_B5_OES          0x8B97\n#define GL_PALETTE8_RGBA4_OES             0x8B98\n#define GL_PALETTE8_RGB5_A1_OES           0x8B99\n#endif /* GL_OES_compressed_paletted_texture */\n\n#ifndef GL_OES_fixed_point\n#define GL_OES_fixed_point 1\ntypedef khronos_int32_t GLfixed;\n#define GL_FIXED_OES                      0x140C\ntypedef void (APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLfixed ref);\ntypedef void (APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\ntypedef void (APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLfixed depth);\ntypedef void (APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);\ntypedef void (APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\ntypedef void (APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLfixed n, GLfixed f);\ntypedef void (APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *param);\ntypedef void (APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);\ntypedef void (APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum plane, GLfixed *equation);\ntypedef void (APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *param);\ntypedef void (APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width);\ntypedef void (APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m);\ntypedef void (APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *param);\ntypedef void (APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);\ntypedef void (APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);\ntypedef void (APIENTRYP PFNGLORTHOXOESPROC) (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size);\ntypedef void (APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);\ntypedef void (APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);\ntypedef void (APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);\ntypedef void (APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);\ntypedef void (APIENTRYP PFNGLACCUMXOESPROC) (GLenum op, GLfixed value);\ntypedef void (APIENTRYP PFNGLBITMAPXOESPROC) (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap);\ntypedef void (APIENTRYP PFNGLBLENDCOLORXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\ntypedef void (APIENTRYP PFNGLCLEARACCUMXOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\ntypedef void (APIENTRYP PFNGLCOLOR3XOESPROC) (GLfixed red, GLfixed green, GLfixed blue);\ntypedef void (APIENTRYP PFNGLCOLOR3XVOESPROC) (const GLfixed *components);\ntypedef void (APIENTRYP PFNGLCOLOR4XVOESPROC) (const GLfixed *components);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP PFNGLEVALCOORD1XOESPROC) (GLfixed u);\ntypedef void (APIENTRYP PFNGLEVALCOORD1XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLEVALCOORD2XOESPROC) (GLfixed u, GLfixed v);\ntypedef void (APIENTRYP PFNGLEVALCOORD2XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLFEEDBACKBUFFERXOESPROC) (GLsizei n, GLenum type, const GLfixed *buffer);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP PFNGLGETLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP PFNGLGETMAPXVOESPROC) (GLenum target, GLenum query, GLfixed *v);\ntypedef void (APIENTRYP PFNGLGETMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLGETPIXELMAPXVPROC) (GLenum map, GLint size, GLfixed *values);\ntypedef void (APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERXVOESPROC) (GLenum target, GLint level, GLenum pname, GLfixed *params);\ntypedef void (APIENTRYP PFNGLINDEXXOESPROC) (GLfixed component);\ntypedef void (APIENTRYP PFNGLINDEXXVOESPROC) (const GLfixed *component);\ntypedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);\ntypedef void (APIENTRYP PFNGLMAP1XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points);\ntypedef void (APIENTRYP PFNGLMAP2XOESPROC) (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points);\ntypedef void (APIENTRYP PFNGLMAPGRID1XOESPROC) (GLint n, GLfixed u1, GLfixed u2);\ntypedef void (APIENTRYP PFNGLMAPGRID2XOESPROC) (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2);\ntypedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXXOESPROC) (const GLfixed *m);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1XOESPROC) (GLenum texture, GLfixed s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1XVOESPROC) (GLenum texture, const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2XOESPROC) (GLenum texture, GLfixed s, GLfixed t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2XVOESPROC) (GLenum texture, const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3XOESPROC) (GLenum texture, GLfixed s, GLfixed t, GLfixed r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3XVOESPROC) (GLenum texture, const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4XVOESPROC) (GLenum texture, const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLNORMAL3XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLPASSTHROUGHXOESPROC) (GLfixed token);\ntypedef void (APIENTRYP PFNGLPIXELMAPXPROC) (GLenum map, GLint size, const GLfixed *values);\ntypedef void (APIENTRYP PFNGLPIXELSTOREXPROC) (GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLPIXELTRANSFERXOESPROC) (GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLPIXELZOOMXOESPROC) (GLfixed xfactor, GLfixed yfactor);\ntypedef void (APIENTRYP PFNGLPRIORITIZETEXTURESXOESPROC) (GLsizei n, const GLuint *textures, const GLfixed *priorities);\ntypedef void (APIENTRYP PFNGLRASTERPOS2XOESPROC) (GLfixed x, GLfixed y);\ntypedef void (APIENTRYP PFNGLRASTERPOS2XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLRASTERPOS3XOESPROC) (GLfixed x, GLfixed y, GLfixed z);\ntypedef void (APIENTRYP PFNGLRASTERPOS3XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLRASTERPOS4XOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed w);\ntypedef void (APIENTRYP PFNGLRASTERPOS4XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLRECTXOESPROC) (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2);\ntypedef void (APIENTRYP PFNGLRECTXVOESPROC) (const GLfixed *v1, const GLfixed *v2);\ntypedef void (APIENTRYP PFNGLTEXCOORD1XOESPROC) (GLfixed s);\ntypedef void (APIENTRYP PFNGLTEXCOORD1XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLTEXCOORD2XOESPROC) (GLfixed s, GLfixed t);\ntypedef void (APIENTRYP PFNGLTEXCOORD2XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLTEXCOORD3XOESPROC) (GLfixed s, GLfixed t, GLfixed r);\ntypedef void (APIENTRYP PFNGLTEXCOORD3XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLTEXCOORD4XOESPROC) (GLfixed s, GLfixed t, GLfixed r, GLfixed q);\ntypedef void (APIENTRYP PFNGLTEXCOORD4XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);\ntypedef void (APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);\ntypedef void (APIENTRYP PFNGLVERTEX2XOESPROC) (GLfixed x);\ntypedef void (APIENTRYP PFNGLVERTEX2XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLVERTEX3XOESPROC) (GLfixed x, GLfixed y);\ntypedef void (APIENTRYP PFNGLVERTEX3XVOESPROC) (const GLfixed *coords);\ntypedef void (APIENTRYP PFNGLVERTEX4XOESPROC) (GLfixed x, GLfixed y, GLfixed z);\ntypedef void (APIENTRYP PFNGLVERTEX4XVOESPROC) (const GLfixed *coords);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glAlphaFuncxOES (GLenum func, GLfixed ref);\nGLAPI void APIENTRY glClearColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\nGLAPI void APIENTRY glClearDepthxOES (GLfixed depth);\nGLAPI void APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation);\nGLAPI void APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\nGLAPI void APIENTRY glDepthRangexOES (GLfixed n, GLfixed f);\nGLAPI void APIENTRY glFogxOES (GLenum pname, GLfixed param);\nGLAPI void APIENTRY glFogxvOES (GLenum pname, const GLfixed *param);\nGLAPI void APIENTRY glFrustumxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);\nGLAPI void APIENTRY glGetClipPlanexOES (GLenum plane, GLfixed *equation);\nGLAPI void APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params);\nGLAPI void APIENTRY glGetTexEnvxvOES (GLenum target, GLenum pname, GLfixed *params);\nGLAPI void APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params);\nGLAPI void APIENTRY glLightModelxOES (GLenum pname, GLfixed param);\nGLAPI void APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *param);\nGLAPI void APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param);\nGLAPI void APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params);\nGLAPI void APIENTRY glLineWidthxOES (GLfixed width);\nGLAPI void APIENTRY glLoadMatrixxOES (const GLfixed *m);\nGLAPI void APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param);\nGLAPI void APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *param);\nGLAPI void APIENTRY glMultMatrixxOES (const GLfixed *m);\nGLAPI void APIENTRY glMultiTexCoord4xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q);\nGLAPI void APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz);\nGLAPI void APIENTRY glOrthoxOES (GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f);\nGLAPI void APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params);\nGLAPI void APIENTRY glPointSizexOES (GLfixed size);\nGLAPI void APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units);\nGLAPI void APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);\nGLAPI void APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z);\nGLAPI void APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param);\nGLAPI void APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params);\nGLAPI void APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param);\nGLAPI void APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);\nGLAPI void APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z);\nGLAPI void APIENTRY glAccumxOES (GLenum op, GLfixed value);\nGLAPI void APIENTRY glBitmapxOES (GLsizei width, GLsizei height, GLfixed xorig, GLfixed yorig, GLfixed xmove, GLfixed ymove, const GLubyte *bitmap);\nGLAPI void APIENTRY glBlendColorxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\nGLAPI void APIENTRY glClearAccumxOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);\nGLAPI void APIENTRY glColor3xOES (GLfixed red, GLfixed green, GLfixed blue);\nGLAPI void APIENTRY glColor3xvOES (const GLfixed *components);\nGLAPI void APIENTRY glColor4xvOES (const GLfixed *components);\nGLAPI void APIENTRY glConvolutionParameterxOES (GLenum target, GLenum pname, GLfixed param);\nGLAPI void APIENTRY glConvolutionParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);\nGLAPI void APIENTRY glEvalCoord1xOES (GLfixed u);\nGLAPI void APIENTRY glEvalCoord1xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glEvalCoord2xOES (GLfixed u, GLfixed v);\nGLAPI void APIENTRY glEvalCoord2xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glFeedbackBufferxOES (GLsizei n, GLenum type, const GLfixed *buffer);\nGLAPI void APIENTRY glGetConvolutionParameterxvOES (GLenum target, GLenum pname, GLfixed *params);\nGLAPI void APIENTRY glGetHistogramParameterxvOES (GLenum target, GLenum pname, GLfixed *params);\nGLAPI void APIENTRY glGetLightxOES (GLenum light, GLenum pname, GLfixed *params);\nGLAPI void APIENTRY glGetMapxvOES (GLenum target, GLenum query, GLfixed *v);\nGLAPI void APIENTRY glGetMaterialxOES (GLenum face, GLenum pname, GLfixed param);\nGLAPI void APIENTRY glGetPixelMapxv (GLenum map, GLint size, GLfixed *values);\nGLAPI void APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params);\nGLAPI void APIENTRY glGetTexLevelParameterxvOES (GLenum target, GLint level, GLenum pname, GLfixed *params);\nGLAPI void APIENTRY glIndexxOES (GLfixed component);\nGLAPI void APIENTRY glIndexxvOES (const GLfixed *component);\nGLAPI void APIENTRY glLoadTransposeMatrixxOES (const GLfixed *m);\nGLAPI void APIENTRY glMap1xOES (GLenum target, GLfixed u1, GLfixed u2, GLint stride, GLint order, GLfixed points);\nGLAPI void APIENTRY glMap2xOES (GLenum target, GLfixed u1, GLfixed u2, GLint ustride, GLint uorder, GLfixed v1, GLfixed v2, GLint vstride, GLint vorder, GLfixed points);\nGLAPI void APIENTRY glMapGrid1xOES (GLint n, GLfixed u1, GLfixed u2);\nGLAPI void APIENTRY glMapGrid2xOES (GLint n, GLfixed u1, GLfixed u2, GLfixed v1, GLfixed v2);\nGLAPI void APIENTRY glMultTransposeMatrixxOES (const GLfixed *m);\nGLAPI void APIENTRY glMultiTexCoord1xOES (GLenum texture, GLfixed s);\nGLAPI void APIENTRY glMultiTexCoord1xvOES (GLenum texture, const GLfixed *coords);\nGLAPI void APIENTRY glMultiTexCoord2xOES (GLenum texture, GLfixed s, GLfixed t);\nGLAPI void APIENTRY glMultiTexCoord2xvOES (GLenum texture, const GLfixed *coords);\nGLAPI void APIENTRY glMultiTexCoord3xOES (GLenum texture, GLfixed s, GLfixed t, GLfixed r);\nGLAPI void APIENTRY glMultiTexCoord3xvOES (GLenum texture, const GLfixed *coords);\nGLAPI void APIENTRY glMultiTexCoord4xvOES (GLenum texture, const GLfixed *coords);\nGLAPI void APIENTRY glNormal3xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glPassThroughxOES (GLfixed token);\nGLAPI void APIENTRY glPixelMapx (GLenum map, GLint size, const GLfixed *values);\nGLAPI void APIENTRY glPixelStorex (GLenum pname, GLfixed param);\nGLAPI void APIENTRY glPixelTransferxOES (GLenum pname, GLfixed param);\nGLAPI void APIENTRY glPixelZoomxOES (GLfixed xfactor, GLfixed yfactor);\nGLAPI void APIENTRY glPrioritizeTexturesxOES (GLsizei n, const GLuint *textures, const GLfixed *priorities);\nGLAPI void APIENTRY glRasterPos2xOES (GLfixed x, GLfixed y);\nGLAPI void APIENTRY glRasterPos2xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glRasterPos3xOES (GLfixed x, GLfixed y, GLfixed z);\nGLAPI void APIENTRY glRasterPos3xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glRasterPos4xOES (GLfixed x, GLfixed y, GLfixed z, GLfixed w);\nGLAPI void APIENTRY glRasterPos4xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glRectxOES (GLfixed x1, GLfixed y1, GLfixed x2, GLfixed y2);\nGLAPI void APIENTRY glRectxvOES (const GLfixed *v1, const GLfixed *v2);\nGLAPI void APIENTRY glTexCoord1xOES (GLfixed s);\nGLAPI void APIENTRY glTexCoord1xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glTexCoord2xOES (GLfixed s, GLfixed t);\nGLAPI void APIENTRY glTexCoord2xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glTexCoord3xOES (GLfixed s, GLfixed t, GLfixed r);\nGLAPI void APIENTRY glTexCoord3xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glTexCoord4xOES (GLfixed s, GLfixed t, GLfixed r, GLfixed q);\nGLAPI void APIENTRY glTexCoord4xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param);\nGLAPI void APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params);\nGLAPI void APIENTRY glVertex2xOES (GLfixed x);\nGLAPI void APIENTRY glVertex2xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glVertex3xOES (GLfixed x, GLfixed y);\nGLAPI void APIENTRY glVertex3xvOES (const GLfixed *coords);\nGLAPI void APIENTRY glVertex4xOES (GLfixed x, GLfixed y, GLfixed z);\nGLAPI void APIENTRY glVertex4xvOES (const GLfixed *coords);\n#endif\n#endif /* GL_OES_fixed_point */\n\n#ifndef GL_OES_query_matrix\n#define GL_OES_query_matrix 1\ntypedef GLbitfield (APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed *mantissa, GLint *exponent);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLbitfield APIENTRY glQueryMatrixxOES (GLfixed *mantissa, GLint *exponent);\n#endif\n#endif /* GL_OES_query_matrix */\n\n#ifndef GL_OES_read_format\n#define GL_OES_read_format 1\n#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES 0x8B9A\n#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES 0x8B9B\n#endif /* GL_OES_read_format */\n\n#ifndef GL_OES_single_precision\n#define GL_OES_single_precision 1\ntypedef void (APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth);\ntypedef void (APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);\ntypedef void (APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf n, GLclampf f);\ntypedef void (APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);\ntypedef void (APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum plane, GLfloat *equation);\ntypedef void (APIENTRYP PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glClearDepthfOES (GLclampf depth);\nGLAPI void APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation);\nGLAPI void APIENTRY glDepthRangefOES (GLclampf n, GLclampf f);\nGLAPI void APIENTRY glFrustumfOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);\nGLAPI void APIENTRY glGetClipPlanefOES (GLenum plane, GLfloat *equation);\nGLAPI void APIENTRY glOrthofOES (GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f);\n#endif\n#endif /* GL_OES_single_precision */\n\n#ifndef GL_3DFX_multisample\n#define GL_3DFX_multisample 1\n#define GL_MULTISAMPLE_3DFX               0x86B2\n#define GL_SAMPLE_BUFFERS_3DFX            0x86B3\n#define GL_SAMPLES_3DFX                   0x86B4\n#define GL_MULTISAMPLE_BIT_3DFX           0x20000000\n#endif /* GL_3DFX_multisample */\n\n#ifndef GL_3DFX_tbuffer\n#define GL_3DFX_tbuffer 1\ntypedef void (APIENTRYP PFNGLTBUFFERMASK3DFXPROC) (GLuint mask);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTbufferMask3DFX (GLuint mask);\n#endif\n#endif /* GL_3DFX_tbuffer */\n\n#ifndef GL_3DFX_texture_compression_FXT1\n#define GL_3DFX_texture_compression_FXT1 1\n#define GL_COMPRESSED_RGB_FXT1_3DFX       0x86B0\n#define GL_COMPRESSED_RGBA_FXT1_3DFX      0x86B1\n#endif /* GL_3DFX_texture_compression_FXT1 */\n\n#ifndef GL_AMD_blend_minmax_factor\n#define GL_AMD_blend_minmax_factor 1\n#define GL_FACTOR_MIN_AMD                 0x901C\n#define GL_FACTOR_MAX_AMD                 0x901D\n#endif /* GL_AMD_blend_minmax_factor */\n\n#ifndef GL_AMD_conservative_depth\n#define GL_AMD_conservative_depth 1\n#endif /* GL_AMD_conservative_depth */\n\n#ifndef GL_AMD_debug_output\n#define GL_AMD_debug_output 1\ntypedef void (APIENTRY  *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);\n#define GL_MAX_DEBUG_MESSAGE_LENGTH_AMD   0x9143\n#define GL_MAX_DEBUG_LOGGED_MESSAGES_AMD  0x9144\n#define GL_DEBUG_LOGGED_MESSAGES_AMD      0x9145\n#define GL_DEBUG_SEVERITY_HIGH_AMD        0x9146\n#define GL_DEBUG_SEVERITY_MEDIUM_AMD      0x9147\n#define GL_DEBUG_SEVERITY_LOW_AMD         0x9148\n#define GL_DEBUG_CATEGORY_API_ERROR_AMD   0x9149\n#define GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD 0x914A\n#define GL_DEBUG_CATEGORY_DEPRECATION_AMD 0x914B\n#define GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD 0x914C\n#define GL_DEBUG_CATEGORY_PERFORMANCE_AMD 0x914D\n#define GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD 0x914E\n#define GL_DEBUG_CATEGORY_APPLICATION_AMD 0x914F\n#define GL_DEBUG_CATEGORY_OTHER_AMD       0x9150\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf);\ntypedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void *userParam);\ntypedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufSize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDebugMessageEnableAMD (GLenum category, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);\nGLAPI void APIENTRY glDebugMessageInsertAMD (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar *buf);\nGLAPI void APIENTRY glDebugMessageCallbackAMD (GLDEBUGPROCAMD callback, void *userParam);\nGLAPI GLuint APIENTRY glGetDebugMessageLogAMD (GLuint count, GLsizei bufSize, GLenum *categories, GLuint *severities, GLuint *ids, GLsizei *lengths, GLchar *message);\n#endif\n#endif /* GL_AMD_debug_output */\n\n#ifndef GL_AMD_depth_clamp_separate\n#define GL_AMD_depth_clamp_separate 1\n#define GL_DEPTH_CLAMP_NEAR_AMD           0x901E\n#define GL_DEPTH_CLAMP_FAR_AMD            0x901F\n#endif /* GL_AMD_depth_clamp_separate */\n\n#ifndef GL_AMD_draw_buffers_blend\n#define GL_AMD_draw_buffers_blend 1\ntypedef void (APIENTRYP PFNGLBLENDFUNCINDEXEDAMDPROC) (GLuint buf, GLenum src, GLenum dst);\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONINDEXEDAMDPROC) (GLuint buf, GLenum mode);\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC) (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendFuncIndexedAMD (GLuint buf, GLenum src, GLenum dst);\nGLAPI void APIENTRY glBlendFuncSeparateIndexedAMD (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\nGLAPI void APIENTRY glBlendEquationIndexedAMD (GLuint buf, GLenum mode);\nGLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRGB, GLenum modeAlpha);\n#endif\n#endif /* GL_AMD_draw_buffers_blend */\n\n#ifndef GL_AMD_framebuffer_multisample_advanced\n#define GL_AMD_framebuffer_multisample_advanced 1\n#define GL_RENDERBUFFER_STORAGE_SAMPLES_AMD 0x91B2\n#define GL_MAX_COLOR_FRAMEBUFFER_SAMPLES_AMD 0x91B3\n#define GL_MAX_COLOR_FRAMEBUFFER_STORAGE_SAMPLES_AMD 0x91B4\n#define GL_MAX_DEPTH_STENCIL_FRAMEBUFFER_SAMPLES_AMD 0x91B5\n#define GL_NUM_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B6\n#define GL_SUPPORTED_MULTISAMPLE_MODES_AMD 0x91B7\ntypedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC) (GLenum target, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEADVANCEDAMDPROC) (GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glRenderbufferStorageMultisampleAdvancedAMD (GLenum target, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glNamedRenderbufferStorageMultisampleAdvancedAMD (GLuint renderbuffer, GLsizei samples, GLsizei storageSamples, GLenum internalformat, GLsizei width, GLsizei height);\n#endif\n#endif /* GL_AMD_framebuffer_multisample_advanced */\n\n#ifndef GL_AMD_framebuffer_sample_positions\n#define GL_AMD_framebuffer_sample_positions 1\n#define GL_SUBSAMPLE_DISTANCE_AMD         0x883F\n#define GL_PIXELS_PER_SAMPLE_PATTERN_X_AMD 0x91AE\n#define GL_PIXELS_PER_SAMPLE_PATTERN_Y_AMD 0x91AF\n#define GL_ALL_PIXELS_AMD                 0xFFFFFFFF\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC) (GLenum target, GLuint numsamples, GLuint pixelindex, const GLfloat *values);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLEPOSITIONSFVAMDPROC) (GLuint framebuffer, GLuint numsamples, GLuint pixelindex, const GLfloat *values);\ntypedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERFVAMDPROC) (GLenum target, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values);\ntypedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERFVAMDPROC) (GLuint framebuffer, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFramebufferSamplePositionsfvAMD (GLenum target, GLuint numsamples, GLuint pixelindex, const GLfloat *values);\nGLAPI void APIENTRY glNamedFramebufferSamplePositionsfvAMD (GLuint framebuffer, GLuint numsamples, GLuint pixelindex, const GLfloat *values);\nGLAPI void APIENTRY glGetFramebufferParameterfvAMD (GLenum target, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values);\nGLAPI void APIENTRY glGetNamedFramebufferParameterfvAMD (GLuint framebuffer, GLenum pname, GLuint numsamples, GLuint pixelindex, GLsizei size, GLfloat *values);\n#endif\n#endif /* GL_AMD_framebuffer_sample_positions */\n\n#ifndef GL_AMD_gcn_shader\n#define GL_AMD_gcn_shader 1\n#endif /* GL_AMD_gcn_shader */\n\n#ifndef GL_AMD_gpu_shader_half_float\n#define GL_AMD_gpu_shader_half_float 1\n#define GL_FLOAT16_NV                     0x8FF8\n#define GL_FLOAT16_VEC2_NV                0x8FF9\n#define GL_FLOAT16_VEC3_NV                0x8FFA\n#define GL_FLOAT16_VEC4_NV                0x8FFB\n#define GL_FLOAT16_MAT2_AMD               0x91C5\n#define GL_FLOAT16_MAT3_AMD               0x91C6\n#define GL_FLOAT16_MAT4_AMD               0x91C7\n#define GL_FLOAT16_MAT2x3_AMD             0x91C8\n#define GL_FLOAT16_MAT2x4_AMD             0x91C9\n#define GL_FLOAT16_MAT3x2_AMD             0x91CA\n#define GL_FLOAT16_MAT3x4_AMD             0x91CB\n#define GL_FLOAT16_MAT4x2_AMD             0x91CC\n#define GL_FLOAT16_MAT4x3_AMD             0x91CD\n#endif /* GL_AMD_gpu_shader_half_float */\n\n#ifndef GL_AMD_gpu_shader_int16\n#define GL_AMD_gpu_shader_int16 1\n#endif /* GL_AMD_gpu_shader_int16 */\n\n#ifndef GL_AMD_gpu_shader_int64\n#define GL_AMD_gpu_shader_int64 1\ntypedef khronos_int64_t GLint64EXT;\n#define GL_INT64_NV                       0x140E\n#define GL_UNSIGNED_INT64_NV              0x140F\n#define GL_INT8_NV                        0x8FE0\n#define GL_INT8_VEC2_NV                   0x8FE1\n#define GL_INT8_VEC3_NV                   0x8FE2\n#define GL_INT8_VEC4_NV                   0x8FE3\n#define GL_INT16_NV                       0x8FE4\n#define GL_INT16_VEC2_NV                  0x8FE5\n#define GL_INT16_VEC3_NV                  0x8FE6\n#define GL_INT16_VEC4_NV                  0x8FE7\n#define GL_INT64_VEC2_NV                  0x8FE9\n#define GL_INT64_VEC3_NV                  0x8FEA\n#define GL_INT64_VEC4_NV                  0x8FEB\n#define GL_UNSIGNED_INT8_NV               0x8FEC\n#define GL_UNSIGNED_INT8_VEC2_NV          0x8FED\n#define GL_UNSIGNED_INT8_VEC3_NV          0x8FEE\n#define GL_UNSIGNED_INT8_VEC4_NV          0x8FEF\n#define GL_UNSIGNED_INT16_NV              0x8FF0\n#define GL_UNSIGNED_INT16_VEC2_NV         0x8FF1\n#define GL_UNSIGNED_INT16_VEC3_NV         0x8FF2\n#define GL_UNSIGNED_INT16_VEC4_NV         0x8FF3\n#define GL_UNSIGNED_INT64_VEC2_NV         0x8FF5\n#define GL_UNSIGNED_INT64_VEC3_NV         0x8FF6\n#define GL_UNSIGNED_INT64_VEC4_NV         0x8FF7\ntypedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x);\ntypedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y);\ntypedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);\ntypedef void (APIENTRYP PFNGLUNIFORM4I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);\ntypedef void (APIENTRYP PFNGLUNIFORM1I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4I64VNVPROC) (GLint location, GLsizei count, const GLint64EXT *value);\ntypedef void (APIENTRYP PFNGLUNIFORM1UI64NVPROC) (GLint location, GLuint64EXT x);\ntypedef void (APIENTRYP PFNGLUNIFORM2UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y);\ntypedef void (APIENTRYP PFNGLUNIFORM3UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);\ntypedef void (APIENTRYP PFNGLUNIFORM4UI64NVPROC) (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);\ntypedef void (APIENTRYP PFNGLUNIFORM1UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4UI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);\ntypedef void (APIENTRYP PFNGLGETUNIFORMI64VNVPROC) (GLuint program, GLint location, GLint64EXT *params);\ntypedef void (APIENTRYP PFNGLGETUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLuint64EXT *params);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64NVPROC) (GLuint program, GLint location, GLint64EXT x);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64NVPROC) (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64NVPROC) (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glUniform1i64NV (GLint location, GLint64EXT x);\nGLAPI void APIENTRY glUniform2i64NV (GLint location, GLint64EXT x, GLint64EXT y);\nGLAPI void APIENTRY glUniform3i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);\nGLAPI void APIENTRY glUniform4i64NV (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);\nGLAPI void APIENTRY glUniform1i64vNV (GLint location, GLsizei count, const GLint64EXT *value);\nGLAPI void APIENTRY glUniform2i64vNV (GLint location, GLsizei count, const GLint64EXT *value);\nGLAPI void APIENTRY glUniform3i64vNV (GLint location, GLsizei count, const GLint64EXT *value);\nGLAPI void APIENTRY glUniform4i64vNV (GLint location, GLsizei count, const GLint64EXT *value);\nGLAPI void APIENTRY glUniform1ui64NV (GLint location, GLuint64EXT x);\nGLAPI void APIENTRY glUniform2ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y);\nGLAPI void APIENTRY glUniform3ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);\nGLAPI void APIENTRY glUniform4ui64NV (GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);\nGLAPI void APIENTRY glUniform1ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);\nGLAPI void APIENTRY glUniform2ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);\nGLAPI void APIENTRY glUniform3ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);\nGLAPI void APIENTRY glUniform4ui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);\nGLAPI void APIENTRY glGetUniformi64vNV (GLuint program, GLint location, GLint64EXT *params);\nGLAPI void APIENTRY glGetUniformui64vNV (GLuint program, GLint location, GLuint64EXT *params);\nGLAPI void APIENTRY glProgramUniform1i64NV (GLuint program, GLint location, GLint64EXT x);\nGLAPI void APIENTRY glProgramUniform2i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y);\nGLAPI void APIENTRY glProgramUniform3i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);\nGLAPI void APIENTRY glProgramUniform4i64NV (GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);\nGLAPI void APIENTRY glProgramUniform1i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);\nGLAPI void APIENTRY glProgramUniform2i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);\nGLAPI void APIENTRY glProgramUniform3i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);\nGLAPI void APIENTRY glProgramUniform4i64vNV (GLuint program, GLint location, GLsizei count, const GLint64EXT *value);\nGLAPI void APIENTRY glProgramUniform1ui64NV (GLuint program, GLint location, GLuint64EXT x);\nGLAPI void APIENTRY glProgramUniform2ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y);\nGLAPI void APIENTRY glProgramUniform3ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);\nGLAPI void APIENTRY glProgramUniform4ui64NV (GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);\nGLAPI void APIENTRY glProgramUniform1ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);\nGLAPI void APIENTRY glProgramUniform2ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);\nGLAPI void APIENTRY glProgramUniform3ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);\nGLAPI void APIENTRY glProgramUniform4ui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);\n#endif\n#endif /* GL_AMD_gpu_shader_int64 */\n\n#ifndef GL_AMD_interleaved_elements\n#define GL_AMD_interleaved_elements 1\n#define GL_VERTEX_ELEMENT_SWIZZLE_AMD     0x91A4\n#define GL_VERTEX_ID_SWIZZLE_AMD          0x91A5\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBPARAMETERIAMDPROC) (GLuint index, GLenum pname, GLint param);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexAttribParameteriAMD (GLuint index, GLenum pname, GLint param);\n#endif\n#endif /* GL_AMD_interleaved_elements */\n\n#ifndef GL_AMD_multi_draw_indirect\n#define GL_AMD_multi_draw_indirect 1\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMultiDrawArraysIndirectAMD (GLenum mode, const void *indirect, GLsizei primcount, GLsizei stride);\nGLAPI void APIENTRY glMultiDrawElementsIndirectAMD (GLenum mode, GLenum type, const void *indirect, GLsizei primcount, GLsizei stride);\n#endif\n#endif /* GL_AMD_multi_draw_indirect */\n\n#ifndef GL_AMD_name_gen_delete\n#define GL_AMD_name_gen_delete 1\n#define GL_DATA_BUFFER_AMD                0x9151\n#define GL_PERFORMANCE_MONITOR_AMD        0x9152\n#define GL_QUERY_OBJECT_AMD               0x9153\n#define GL_VERTEX_ARRAY_OBJECT_AMD        0x9154\n#define GL_SAMPLER_OBJECT_AMD             0x9155\ntypedef void (APIENTRYP PFNGLGENNAMESAMDPROC) (GLenum identifier, GLuint num, GLuint *names);\ntypedef void (APIENTRYP PFNGLDELETENAMESAMDPROC) (GLenum identifier, GLuint num, const GLuint *names);\ntypedef GLboolean (APIENTRYP PFNGLISNAMEAMDPROC) (GLenum identifier, GLuint name);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenNamesAMD (GLenum identifier, GLuint num, GLuint *names);\nGLAPI void APIENTRY glDeleteNamesAMD (GLenum identifier, GLuint num, const GLuint *names);\nGLAPI GLboolean APIENTRY glIsNameAMD (GLenum identifier, GLuint name);\n#endif\n#endif /* GL_AMD_name_gen_delete */\n\n#ifndef GL_AMD_occlusion_query_event\n#define GL_AMD_occlusion_query_event 1\n#define GL_OCCLUSION_QUERY_EVENT_MASK_AMD 0x874F\n#define GL_QUERY_DEPTH_PASS_EVENT_BIT_AMD 0x00000001\n#define GL_QUERY_DEPTH_FAIL_EVENT_BIT_AMD 0x00000002\n#define GL_QUERY_STENCIL_FAIL_EVENT_BIT_AMD 0x00000004\n#define GL_QUERY_DEPTH_BOUNDS_FAIL_EVENT_BIT_AMD 0x00000008\n#define GL_QUERY_ALL_EVENT_BITS_AMD       0xFFFFFFFF\ntypedef void (APIENTRYP PFNGLQUERYOBJECTPARAMETERUIAMDPROC) (GLenum target, GLuint id, GLenum pname, GLuint param);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glQueryObjectParameteruiAMD (GLenum target, GLuint id, GLenum pname, GLuint param);\n#endif\n#endif /* GL_AMD_occlusion_query_event */\n\n#ifndef GL_AMD_performance_monitor\n#define GL_AMD_performance_monitor 1\n#define GL_COUNTER_TYPE_AMD               0x8BC0\n#define GL_COUNTER_RANGE_AMD              0x8BC1\n#define GL_UNSIGNED_INT64_AMD             0x8BC2\n#define GL_PERCENTAGE_AMD                 0x8BC3\n#define GL_PERFMON_RESULT_AVAILABLE_AMD   0x8BC4\n#define GL_PERFMON_RESULT_SIZE_AMD        0x8BC5\n#define GL_PERFMON_RESULT_AMD             0x8BC6\ntypedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);\ntypedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);\ntypedef void (APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);\ntypedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);\ntypedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data);\ntypedef void (APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);\ntypedef void (APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);\ntypedef void (APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList);\ntypedef void (APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);\ntypedef void (APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);\ntypedef void (APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);\nGLAPI void APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);\nGLAPI void APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);\nGLAPI void APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);\nGLAPI void APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data);\nGLAPI void APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);\nGLAPI void APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);\nGLAPI void APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *counterList);\nGLAPI void APIENTRY glBeginPerfMonitorAMD (GLuint monitor);\nGLAPI void APIENTRY glEndPerfMonitorAMD (GLuint monitor);\nGLAPI void APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);\n#endif\n#endif /* GL_AMD_performance_monitor */\n\n#ifndef GL_AMD_pinned_memory\n#define GL_AMD_pinned_memory 1\n#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160\n#endif /* GL_AMD_pinned_memory */\n\n#ifndef GL_AMD_query_buffer_object\n#define GL_AMD_query_buffer_object 1\n#define GL_QUERY_BUFFER_AMD               0x9192\n#define GL_QUERY_BUFFER_BINDING_AMD       0x9193\n#define GL_QUERY_RESULT_NO_WAIT_AMD       0x9194\n#endif /* GL_AMD_query_buffer_object */\n\n#ifndef GL_AMD_sample_positions\n#define GL_AMD_sample_positions 1\ntypedef void (APIENTRYP PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint index, const GLfloat *val);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLfloat *val);\n#endif\n#endif /* GL_AMD_sample_positions */\n\n#ifndef GL_AMD_seamless_cubemap_per_texture\n#define GL_AMD_seamless_cubemap_per_texture 1\n#endif /* GL_AMD_seamless_cubemap_per_texture */\n\n#ifndef GL_AMD_shader_atomic_counter_ops\n#define GL_AMD_shader_atomic_counter_ops 1\n#endif /* GL_AMD_shader_atomic_counter_ops */\n\n#ifndef GL_AMD_shader_ballot\n#define GL_AMD_shader_ballot 1\n#endif /* GL_AMD_shader_ballot */\n\n#ifndef GL_AMD_shader_explicit_vertex_parameter\n#define GL_AMD_shader_explicit_vertex_parameter 1\n#endif /* GL_AMD_shader_explicit_vertex_parameter */\n\n#ifndef GL_AMD_shader_gpu_shader_half_float_fetch\n#define GL_AMD_shader_gpu_shader_half_float_fetch 1\n#endif /* GL_AMD_shader_gpu_shader_half_float_fetch */\n\n#ifndef GL_AMD_shader_image_load_store_lod\n#define GL_AMD_shader_image_load_store_lod 1\n#endif /* GL_AMD_shader_image_load_store_lod */\n\n#ifndef GL_AMD_shader_stencil_export\n#define GL_AMD_shader_stencil_export 1\n#endif /* GL_AMD_shader_stencil_export */\n\n#ifndef GL_AMD_shader_trinary_minmax\n#define GL_AMD_shader_trinary_minmax 1\n#endif /* GL_AMD_shader_trinary_minmax */\n\n#ifndef GL_AMD_sparse_texture\n#define GL_AMD_sparse_texture 1\n#define GL_VIRTUAL_PAGE_SIZE_X_AMD        0x9195\n#define GL_VIRTUAL_PAGE_SIZE_Y_AMD        0x9196\n#define GL_VIRTUAL_PAGE_SIZE_Z_AMD        0x9197\n#define GL_MAX_SPARSE_TEXTURE_SIZE_AMD    0x9198\n#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD 0x9199\n#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS 0x919A\n#define GL_MIN_SPARSE_LEVEL_AMD           0x919B\n#define GL_MIN_LOD_WARNING_AMD            0x919C\n#define GL_TEXTURE_STORAGE_SPARSE_BIT_AMD 0x00000001\ntypedef void (APIENTRYP PFNGLTEXSTORAGESPARSEAMDPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGESPARSEAMDPROC) (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexStorageSparseAMD (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);\nGLAPI void APIENTRY glTextureStorageSparseAMD (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags);\n#endif\n#endif /* GL_AMD_sparse_texture */\n\n#ifndef GL_AMD_stencil_operation_extended\n#define GL_AMD_stencil_operation_extended 1\n#define GL_SET_AMD                        0x874A\n#define GL_REPLACE_VALUE_AMD              0x874B\n#define GL_STENCIL_OP_VALUE_AMD           0x874C\n#define GL_STENCIL_BACK_OP_VALUE_AMD      0x874D\ntypedef void (APIENTRYP PFNGLSTENCILOPVALUEAMDPROC) (GLenum face, GLuint value);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glStencilOpValueAMD (GLenum face, GLuint value);\n#endif\n#endif /* GL_AMD_stencil_operation_extended */\n\n#ifndef GL_AMD_texture_gather_bias_lod\n#define GL_AMD_texture_gather_bias_lod 1\n#endif /* GL_AMD_texture_gather_bias_lod */\n\n#ifndef GL_AMD_texture_texture4\n#define GL_AMD_texture_texture4 1\n#endif /* GL_AMD_texture_texture4 */\n\n#ifndef GL_AMD_transform_feedback3_lines_triangles\n#define GL_AMD_transform_feedback3_lines_triangles 1\n#endif /* GL_AMD_transform_feedback3_lines_triangles */\n\n#ifndef GL_AMD_transform_feedback4\n#define GL_AMD_transform_feedback4 1\n#define GL_STREAM_RASTERIZATION_AMD       0x91A0\n#endif /* GL_AMD_transform_feedback4 */\n\n#ifndef GL_AMD_vertex_shader_layer\n#define GL_AMD_vertex_shader_layer 1\n#endif /* GL_AMD_vertex_shader_layer */\n\n#ifndef GL_AMD_vertex_shader_tessellator\n#define GL_AMD_vertex_shader_tessellator 1\n#define GL_SAMPLER_BUFFER_AMD             0x9001\n#define GL_INT_SAMPLER_BUFFER_AMD         0x9002\n#define GL_UNSIGNED_INT_SAMPLER_BUFFER_AMD 0x9003\n#define GL_TESSELLATION_MODE_AMD          0x9004\n#define GL_TESSELLATION_FACTOR_AMD        0x9005\n#define GL_DISCRETE_AMD                   0x9006\n#define GL_CONTINUOUS_AMD                 0x9007\ntypedef void (APIENTRYP PFNGLTESSELLATIONFACTORAMDPROC) (GLfloat factor);\ntypedef void (APIENTRYP PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTessellationFactorAMD (GLfloat factor);\nGLAPI void APIENTRY glTessellationModeAMD (GLenum mode);\n#endif\n#endif /* GL_AMD_vertex_shader_tessellator */\n\n#ifndef GL_AMD_vertex_shader_viewport_index\n#define GL_AMD_vertex_shader_viewport_index 1\n#endif /* GL_AMD_vertex_shader_viewport_index */\n\n#ifndef GL_APPLE_aux_depth_stencil\n#define GL_APPLE_aux_depth_stencil 1\n#define GL_AUX_DEPTH_STENCIL_APPLE        0x8A14\n#endif /* GL_APPLE_aux_depth_stencil */\n\n#ifndef GL_APPLE_client_storage\n#define GL_APPLE_client_storage 1\n#define GL_UNPACK_CLIENT_STORAGE_APPLE    0x85B2\n#endif /* GL_APPLE_client_storage */\n\n#ifndef GL_APPLE_element_array\n#define GL_APPLE_element_array 1\n#define GL_ELEMENT_ARRAY_APPLE            0x8A0C\n#define GL_ELEMENT_ARRAY_TYPE_APPLE       0x8A0D\n#define GL_ELEMENT_ARRAY_POINTER_APPLE    0x8A0E\ntypedef void (APIENTRYP PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const void *pointer);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count);\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);\ntypedef void (APIENTRYP PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glElementPointerAPPLE (GLenum type, const void *pointer);\nGLAPI void APIENTRY glDrawElementArrayAPPLE (GLenum mode, GLint first, GLsizei count);\nGLAPI void APIENTRY glDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count);\nGLAPI void APIENTRY glMultiDrawElementArrayAPPLE (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);\nGLAPI void APIENTRY glMultiDrawRangeElementArrayAPPLE (GLenum mode, GLuint start, GLuint end, const GLint *first, const GLsizei *count, GLsizei primcount);\n#endif\n#endif /* GL_APPLE_element_array */\n\n#ifndef GL_APPLE_fence\n#define GL_APPLE_fence 1\n#define GL_DRAW_PIXELS_APPLE              0x8A0A\n#define GL_FENCE_APPLE                    0x8A0B\ntypedef void (APIENTRYP PFNGLGENFENCESAPPLEPROC) (GLsizei n, GLuint *fences);\ntypedef void (APIENTRYP PFNGLDELETEFENCESAPPLEPROC) (GLsizei n, const GLuint *fences);\ntypedef void (APIENTRYP PFNGLSETFENCEAPPLEPROC) (GLuint fence);\ntypedef GLboolean (APIENTRYP PFNGLISFENCEAPPLEPROC) (GLuint fence);\ntypedef GLboolean (APIENTRYP PFNGLTESTFENCEAPPLEPROC) (GLuint fence);\ntypedef void (APIENTRYP PFNGLFINISHFENCEAPPLEPROC) (GLuint fence);\ntypedef GLboolean (APIENTRYP PFNGLTESTOBJECTAPPLEPROC) (GLenum object, GLuint name);\ntypedef void (APIENTRYP PFNGLFINISHOBJECTAPPLEPROC) (GLenum object, GLint name);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenFencesAPPLE (GLsizei n, GLuint *fences);\nGLAPI void APIENTRY glDeleteFencesAPPLE (GLsizei n, const GLuint *fences);\nGLAPI void APIENTRY glSetFenceAPPLE (GLuint fence);\nGLAPI GLboolean APIENTRY glIsFenceAPPLE (GLuint fence);\nGLAPI GLboolean APIENTRY glTestFenceAPPLE (GLuint fence);\nGLAPI void APIENTRY glFinishFenceAPPLE (GLuint fence);\nGLAPI GLboolean APIENTRY glTestObjectAPPLE (GLenum object, GLuint name);\nGLAPI void APIENTRY glFinishObjectAPPLE (GLenum object, GLint name);\n#endif\n#endif /* GL_APPLE_fence */\n\n#ifndef GL_APPLE_float_pixels\n#define GL_APPLE_float_pixels 1\n#define GL_HALF_APPLE                     0x140B\n#define GL_RGBA_FLOAT32_APPLE             0x8814\n#define GL_RGB_FLOAT32_APPLE              0x8815\n#define GL_ALPHA_FLOAT32_APPLE            0x8816\n#define GL_INTENSITY_FLOAT32_APPLE        0x8817\n#define GL_LUMINANCE_FLOAT32_APPLE        0x8818\n#define GL_LUMINANCE_ALPHA_FLOAT32_APPLE  0x8819\n#define GL_RGBA_FLOAT16_APPLE             0x881A\n#define GL_RGB_FLOAT16_APPLE              0x881B\n#define GL_ALPHA_FLOAT16_APPLE            0x881C\n#define GL_INTENSITY_FLOAT16_APPLE        0x881D\n#define GL_LUMINANCE_FLOAT16_APPLE        0x881E\n#define GL_LUMINANCE_ALPHA_FLOAT16_APPLE  0x881F\n#define GL_COLOR_FLOAT_APPLE              0x8A0F\n#endif /* GL_APPLE_float_pixels */\n\n#ifndef GL_APPLE_flush_buffer_range\n#define GL_APPLE_flush_buffer_range 1\n#define GL_BUFFER_SERIALIZED_MODIFY_APPLE 0x8A12\n#define GL_BUFFER_FLUSHING_UNMAP_APPLE    0x8A13\ntypedef void (APIENTRYP PFNGLBUFFERPARAMETERIAPPLEPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC) (GLenum target, GLintptr offset, GLsizeiptr size);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBufferParameteriAPPLE (GLenum target, GLenum pname, GLint param);\nGLAPI void APIENTRY glFlushMappedBufferRangeAPPLE (GLenum target, GLintptr offset, GLsizeiptr size);\n#endif\n#endif /* GL_APPLE_flush_buffer_range */\n\n#ifndef GL_APPLE_object_purgeable\n#define GL_APPLE_object_purgeable 1\n#define GL_BUFFER_OBJECT_APPLE            0x85B3\n#define GL_RELEASED_APPLE                 0x8A19\n#define GL_VOLATILE_APPLE                 0x8A1A\n#define GL_RETAINED_APPLE                 0x8A1B\n#define GL_UNDEFINED_APPLE                0x8A1C\n#define GL_PURGEABLE_APPLE                0x8A1D\ntypedef GLenum (APIENTRYP PFNGLOBJECTPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option);\ntypedef GLenum (APIENTRYP PFNGLOBJECTUNPURGEABLEAPPLEPROC) (GLenum objectType, GLuint name, GLenum option);\ntypedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVAPPLEPROC) (GLenum objectType, GLuint name, GLenum pname, GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLenum APIENTRY glObjectPurgeableAPPLE (GLenum objectType, GLuint name, GLenum option);\nGLAPI GLenum APIENTRY glObjectUnpurgeableAPPLE (GLenum objectType, GLuint name, GLenum option);\nGLAPI void APIENTRY glGetObjectParameterivAPPLE (GLenum objectType, GLuint name, GLenum pname, GLint *params);\n#endif\n#endif /* GL_APPLE_object_purgeable */\n\n#ifndef GL_APPLE_rgb_422\n#define GL_APPLE_rgb_422 1\n#define GL_RGB_422_APPLE                  0x8A1F\n#define GL_UNSIGNED_SHORT_8_8_APPLE       0x85BA\n#define GL_UNSIGNED_SHORT_8_8_REV_APPLE   0x85BB\n#define GL_RGB_RAW_422_APPLE              0x8A51\n#endif /* GL_APPLE_rgb_422 */\n\n#ifndef GL_APPLE_row_bytes\n#define GL_APPLE_row_bytes 1\n#define GL_PACK_ROW_BYTES_APPLE           0x8A15\n#define GL_UNPACK_ROW_BYTES_APPLE         0x8A16\n#endif /* GL_APPLE_row_bytes */\n\n#ifndef GL_APPLE_specular_vector\n#define GL_APPLE_specular_vector 1\n#define GL_LIGHT_MODEL_SPECULAR_VECTOR_APPLE 0x85B0\n#endif /* GL_APPLE_specular_vector */\n\n#ifndef GL_APPLE_texture_range\n#define GL_APPLE_texture_range 1\n#define GL_TEXTURE_RANGE_LENGTH_APPLE     0x85B7\n#define GL_TEXTURE_RANGE_POINTER_APPLE    0x85B8\n#define GL_TEXTURE_STORAGE_HINT_APPLE     0x85BC\n#define GL_STORAGE_PRIVATE_APPLE          0x85BD\n#define GL_STORAGE_CACHED_APPLE           0x85BE\n#define GL_STORAGE_SHARED_APPLE           0x85BF\ntypedef void (APIENTRYP PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, const void *pointer);\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERPOINTERVAPPLEPROC) (GLenum target, GLenum pname, void **params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTextureRangeAPPLE (GLenum target, GLsizei length, const void *pointer);\nGLAPI void APIENTRY glGetTexParameterPointervAPPLE (GLenum target, GLenum pname, void **params);\n#endif\n#endif /* GL_APPLE_texture_range */\n\n#ifndef GL_APPLE_transform_hint\n#define GL_APPLE_transform_hint 1\n#define GL_TRANSFORM_HINT_APPLE           0x85B1\n#endif /* GL_APPLE_transform_hint */\n\n#ifndef GL_APPLE_vertex_array_object\n#define GL_APPLE_vertex_array_object 1\n#define GL_VERTEX_ARRAY_BINDING_APPLE     0x85B5\ntypedef void (APIENTRYP PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);\ntypedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);\ntypedef void (APIENTRYP PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, GLuint *arrays);\ntypedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBindVertexArrayAPPLE (GLuint array);\nGLAPI void APIENTRY glDeleteVertexArraysAPPLE (GLsizei n, const GLuint *arrays);\nGLAPI void APIENTRY glGenVertexArraysAPPLE (GLsizei n, GLuint *arrays);\nGLAPI GLboolean APIENTRY glIsVertexArrayAPPLE (GLuint array);\n#endif\n#endif /* GL_APPLE_vertex_array_object */\n\n#ifndef GL_APPLE_vertex_array_range\n#define GL_APPLE_vertex_array_range 1\n#define GL_VERTEX_ARRAY_RANGE_APPLE       0x851D\n#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E\n#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F\n#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521\n#define GL_STORAGE_CLIENT_APPLE           0x85B4\ntypedef void (APIENTRYP PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer);\ntypedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void *pointer);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexArrayRangeAPPLE (GLsizei length, void *pointer);\nGLAPI void APIENTRY glFlushVertexArrayRangeAPPLE (GLsizei length, void *pointer);\nGLAPI void APIENTRY glVertexArrayParameteriAPPLE (GLenum pname, GLint param);\n#endif\n#endif /* GL_APPLE_vertex_array_range */\n\n#ifndef GL_APPLE_vertex_program_evaluators\n#define GL_APPLE_vertex_program_evaluators 1\n#define GL_VERTEX_ATTRIB_MAP1_APPLE       0x8A00\n#define GL_VERTEX_ATTRIB_MAP2_APPLE       0x8A01\n#define GL_VERTEX_ATTRIB_MAP1_SIZE_APPLE  0x8A02\n#define GL_VERTEX_ATTRIB_MAP1_COEFF_APPLE 0x8A03\n#define GL_VERTEX_ATTRIB_MAP1_ORDER_APPLE 0x8A04\n#define GL_VERTEX_ATTRIB_MAP1_DOMAIN_APPLE 0x8A05\n#define GL_VERTEX_ATTRIB_MAP2_SIZE_APPLE  0x8A06\n#define GL_VERTEX_ATTRIB_MAP2_COEFF_APPLE 0x8A07\n#define GL_VERTEX_ATTRIB_MAP2_ORDER_APPLE 0x8A08\n#define GL_VERTEX_ATTRIB_MAP2_DOMAIN_APPLE 0x8A09\ntypedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname);\ntypedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBAPPLEPROC) (GLuint index, GLenum pname);\ntypedef GLboolean (APIENTRYP PFNGLISVERTEXATTRIBENABLEDAPPLEPROC) (GLuint index, GLenum pname);\ntypedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);\ntypedef void (APIENTRYP PFNGLMAPVERTEXATTRIB1FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);\ntypedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2DAPPLEPROC) (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);\ntypedef void (APIENTRYP PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glEnableVertexAttribAPPLE (GLuint index, GLenum pname);\nGLAPI void APIENTRY glDisableVertexAttribAPPLE (GLuint index, GLenum pname);\nGLAPI GLboolean APIENTRY glIsVertexAttribEnabledAPPLE (GLuint index, GLenum pname);\nGLAPI void APIENTRY glMapVertexAttrib1dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points);\nGLAPI void APIENTRY glMapVertexAttrib1fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points);\nGLAPI void APIENTRY glMapVertexAttrib2dAPPLE (GLuint index, GLuint size, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points);\nGLAPI void APIENTRY glMapVertexAttrib2fAPPLE (GLuint index, GLuint size, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points);\n#endif\n#endif /* GL_APPLE_vertex_program_evaluators */\n\n#ifndef GL_APPLE_ycbcr_422\n#define GL_APPLE_ycbcr_422 1\n#define GL_YCBCR_422_APPLE                0x85B9\n#endif /* GL_APPLE_ycbcr_422 */\n\n#ifndef GL_ATI_draw_buffers\n#define GL_ATI_draw_buffers 1\n#define GL_MAX_DRAW_BUFFERS_ATI           0x8824\n#define GL_DRAW_BUFFER0_ATI               0x8825\n#define GL_DRAW_BUFFER1_ATI               0x8826\n#define GL_DRAW_BUFFER2_ATI               0x8827\n#define GL_DRAW_BUFFER3_ATI               0x8828\n#define GL_DRAW_BUFFER4_ATI               0x8829\n#define GL_DRAW_BUFFER5_ATI               0x882A\n#define GL_DRAW_BUFFER6_ATI               0x882B\n#define GL_DRAW_BUFFER7_ATI               0x882C\n#define GL_DRAW_BUFFER8_ATI               0x882D\n#define GL_DRAW_BUFFER9_ATI               0x882E\n#define GL_DRAW_BUFFER10_ATI              0x882F\n#define GL_DRAW_BUFFER11_ATI              0x8830\n#define GL_DRAW_BUFFER12_ATI              0x8831\n#define GL_DRAW_BUFFER13_ATI              0x8832\n#define GL_DRAW_BUFFER14_ATI              0x8833\n#define GL_DRAW_BUFFER15_ATI              0x8834\ntypedef void (APIENTRYP PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum *bufs);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawBuffersATI (GLsizei n, const GLenum *bufs);\n#endif\n#endif /* GL_ATI_draw_buffers */\n\n#ifndef GL_ATI_element_array\n#define GL_ATI_element_array 1\n#define GL_ELEMENT_ARRAY_ATI              0x8768\n#define GL_ELEMENT_ARRAY_TYPE_ATI         0x8769\n#define GL_ELEMENT_ARRAY_POINTER_ATI      0x876A\ntypedef void (APIENTRYP PFNGLELEMENTPOINTERATIPROC) (GLenum type, const void *pointer);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count);\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glElementPointerATI (GLenum type, const void *pointer);\nGLAPI void APIENTRY glDrawElementArrayATI (GLenum mode, GLsizei count);\nGLAPI void APIENTRY glDrawRangeElementArrayATI (GLenum mode, GLuint start, GLuint end, GLsizei count);\n#endif\n#endif /* GL_ATI_element_array */\n\n#ifndef GL_ATI_envmap_bumpmap\n#define GL_ATI_envmap_bumpmap 1\n#define GL_BUMP_ROT_MATRIX_ATI            0x8775\n#define GL_BUMP_ROT_MATRIX_SIZE_ATI       0x8776\n#define GL_BUMP_NUM_TEX_UNITS_ATI         0x8777\n#define GL_BUMP_TEX_UNITS_ATI             0x8778\n#define GL_DUDV_ATI                       0x8779\n#define GL_DU8DV8_ATI                     0x877A\n#define GL_BUMP_ENVMAP_ATI                0x877B\n#define GL_BUMP_TARGET_ATI                0x877C\ntypedef void (APIENTRYP PFNGLTEXBUMPPARAMETERIVATIPROC) (GLenum pname, const GLint *param);\ntypedef void (APIENTRYP PFNGLTEXBUMPPARAMETERFVATIPROC) (GLenum pname, const GLfloat *param);\ntypedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERIVATIPROC) (GLenum pname, GLint *param);\ntypedef void (APIENTRYP PFNGLGETTEXBUMPPARAMETERFVATIPROC) (GLenum pname, GLfloat *param);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexBumpParameterivATI (GLenum pname, const GLint *param);\nGLAPI void APIENTRY glTexBumpParameterfvATI (GLenum pname, const GLfloat *param);\nGLAPI void APIENTRY glGetTexBumpParameterivATI (GLenum pname, GLint *param);\nGLAPI void APIENTRY glGetTexBumpParameterfvATI (GLenum pname, GLfloat *param);\n#endif\n#endif /* GL_ATI_envmap_bumpmap */\n\n#ifndef GL_ATI_fragment_shader\n#define GL_ATI_fragment_shader 1\n#define GL_FRAGMENT_SHADER_ATI            0x8920\n#define GL_REG_0_ATI                      0x8921\n#define GL_REG_1_ATI                      0x8922\n#define GL_REG_2_ATI                      0x8923\n#define GL_REG_3_ATI                      0x8924\n#define GL_REG_4_ATI                      0x8925\n#define GL_REG_5_ATI                      0x8926\n#define GL_REG_6_ATI                      0x8927\n#define GL_REG_7_ATI                      0x8928\n#define GL_REG_8_ATI                      0x8929\n#define GL_REG_9_ATI                      0x892A\n#define GL_REG_10_ATI                     0x892B\n#define GL_REG_11_ATI                     0x892C\n#define GL_REG_12_ATI                     0x892D\n#define GL_REG_13_ATI                     0x892E\n#define GL_REG_14_ATI                     0x892F\n#define GL_REG_15_ATI                     0x8930\n#define GL_REG_16_ATI                     0x8931\n#define GL_REG_17_ATI                     0x8932\n#define GL_REG_18_ATI                     0x8933\n#define GL_REG_19_ATI                     0x8934\n#define GL_REG_20_ATI                     0x8935\n#define GL_REG_21_ATI                     0x8936\n#define GL_REG_22_ATI                     0x8937\n#define GL_REG_23_ATI                     0x8938\n#define GL_REG_24_ATI                     0x8939\n#define GL_REG_25_ATI                     0x893A\n#define GL_REG_26_ATI                     0x893B\n#define GL_REG_27_ATI                     0x893C\n#define GL_REG_28_ATI                     0x893D\n#define GL_REG_29_ATI                     0x893E\n#define GL_REG_30_ATI                     0x893F\n#define GL_REG_31_ATI                     0x8940\n#define GL_CON_0_ATI                      0x8941\n#define GL_CON_1_ATI                      0x8942\n#define GL_CON_2_ATI                      0x8943\n#define GL_CON_3_ATI                      0x8944\n#define GL_CON_4_ATI                      0x8945\n#define GL_CON_5_ATI                      0x8946\n#define GL_CON_6_ATI                      0x8947\n#define GL_CON_7_ATI                      0x8948\n#define GL_CON_8_ATI                      0x8949\n#define GL_CON_9_ATI                      0x894A\n#define GL_CON_10_ATI                     0x894B\n#define GL_CON_11_ATI                     0x894C\n#define GL_CON_12_ATI                     0x894D\n#define GL_CON_13_ATI                     0x894E\n#define GL_CON_14_ATI                     0x894F\n#define GL_CON_15_ATI                     0x8950\n#define GL_CON_16_ATI                     0x8951\n#define GL_CON_17_ATI                     0x8952\n#define GL_CON_18_ATI                     0x8953\n#define GL_CON_19_ATI                     0x8954\n#define GL_CON_20_ATI                     0x8955\n#define GL_CON_21_ATI                     0x8956\n#define GL_CON_22_ATI                     0x8957\n#define GL_CON_23_ATI                     0x8958\n#define GL_CON_24_ATI                     0x8959\n#define GL_CON_25_ATI                     0x895A\n#define GL_CON_26_ATI                     0x895B\n#define GL_CON_27_ATI                     0x895C\n#define GL_CON_28_ATI                     0x895D\n#define GL_CON_29_ATI                     0x895E\n#define GL_CON_30_ATI                     0x895F\n#define GL_CON_31_ATI                     0x8960\n#define GL_MOV_ATI                        0x8961\n#define GL_ADD_ATI                        0x8963\n#define GL_MUL_ATI                        0x8964\n#define GL_SUB_ATI                        0x8965\n#define GL_DOT3_ATI                       0x8966\n#define GL_DOT4_ATI                       0x8967\n#define GL_MAD_ATI                        0x8968\n#define GL_LERP_ATI                       0x8969\n#define GL_CND_ATI                        0x896A\n#define GL_CND0_ATI                       0x896B\n#define GL_DOT2_ADD_ATI                   0x896C\n#define GL_SECONDARY_INTERPOLATOR_ATI     0x896D\n#define GL_NUM_FRAGMENT_REGISTERS_ATI     0x896E\n#define GL_NUM_FRAGMENT_CONSTANTS_ATI     0x896F\n#define GL_NUM_PASSES_ATI                 0x8970\n#define GL_NUM_INSTRUCTIONS_PER_PASS_ATI  0x8971\n#define GL_NUM_INSTRUCTIONS_TOTAL_ATI     0x8972\n#define GL_NUM_INPUT_INTERPOLATOR_COMPONENTS_ATI 0x8973\n#define GL_NUM_LOOPBACK_COMPONENTS_ATI    0x8974\n#define GL_COLOR_ALPHA_PAIRING_ATI        0x8975\n#define GL_SWIZZLE_STR_ATI                0x8976\n#define GL_SWIZZLE_STQ_ATI                0x8977\n#define GL_SWIZZLE_STR_DR_ATI             0x8978\n#define GL_SWIZZLE_STQ_DQ_ATI             0x8979\n#define GL_SWIZZLE_STRQ_ATI               0x897A\n#define GL_SWIZZLE_STRQ_DQ_ATI            0x897B\n#define GL_RED_BIT_ATI                    0x00000001\n#define GL_GREEN_BIT_ATI                  0x00000002\n#define GL_BLUE_BIT_ATI                   0x00000004\n#define GL_2X_BIT_ATI                     0x00000001\n#define GL_4X_BIT_ATI                     0x00000002\n#define GL_8X_BIT_ATI                     0x00000004\n#define GL_HALF_BIT_ATI                   0x00000008\n#define GL_QUARTER_BIT_ATI                0x00000010\n#define GL_EIGHTH_BIT_ATI                 0x00000020\n#define GL_SATURATE_BIT_ATI               0x00000040\n#define GL_COMP_BIT_ATI                   0x00000002\n#define GL_NEGATE_BIT_ATI                 0x00000004\n#define GL_BIAS_BIT_ATI                   0x00000008\ntypedef GLuint (APIENTRYP PFNGLGENFRAGMENTSHADERSATIPROC) (GLuint range);\ntypedef void (APIENTRYP PFNGLBINDFRAGMENTSHADERATIPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLDELETEFRAGMENTSHADERATIPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLBEGINFRAGMENTSHADERATIPROC) (void);\ntypedef void (APIENTRYP PFNGLENDFRAGMENTSHADERATIPROC) (void);\ntypedef void (APIENTRYP PFNGLPASSTEXCOORDATIPROC) (GLuint dst, GLuint coord, GLenum swizzle);\ntypedef void (APIENTRYP PFNGLSAMPLEMAPATIPROC) (GLuint dst, GLuint interp, GLenum swizzle);\ntypedef void (APIENTRYP PFNGLCOLORFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);\ntypedef void (APIENTRYP PFNGLCOLORFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);\ntypedef void (APIENTRYP PFNGLCOLORFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);\ntypedef void (APIENTRYP PFNGLALPHAFRAGMENTOP1ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);\ntypedef void (APIENTRYP PFNGLALPHAFRAGMENTOP2ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);\ntypedef void (APIENTRYP PFNGLALPHAFRAGMENTOP3ATIPROC) (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);\ntypedef void (APIENTRYP PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) (GLuint dst, const GLfloat *value);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLuint APIENTRY glGenFragmentShadersATI (GLuint range);\nGLAPI void APIENTRY glBindFragmentShaderATI (GLuint id);\nGLAPI void APIENTRY glDeleteFragmentShaderATI (GLuint id);\nGLAPI void APIENTRY glBeginFragmentShaderATI (void);\nGLAPI void APIENTRY glEndFragmentShaderATI (void);\nGLAPI void APIENTRY glPassTexCoordATI (GLuint dst, GLuint coord, GLenum swizzle);\nGLAPI void APIENTRY glSampleMapATI (GLuint dst, GLuint interp, GLenum swizzle);\nGLAPI void APIENTRY glColorFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);\nGLAPI void APIENTRY glColorFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);\nGLAPI void APIENTRY glColorFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMask, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);\nGLAPI void APIENTRY glAlphaFragmentOp1ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod);\nGLAPI void APIENTRY glAlphaFragmentOp2ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod);\nGLAPI void APIENTRY glAlphaFragmentOp3ATI (GLenum op, GLuint dst, GLuint dstMod, GLuint arg1, GLuint arg1Rep, GLuint arg1Mod, GLuint arg2, GLuint arg2Rep, GLuint arg2Mod, GLuint arg3, GLuint arg3Rep, GLuint arg3Mod);\nGLAPI void APIENTRY glSetFragmentShaderConstantATI (GLuint dst, const GLfloat *value);\n#endif\n#endif /* GL_ATI_fragment_shader */\n\n#ifndef GL_ATI_map_object_buffer\n#define GL_ATI_map_object_buffer 1\ntypedef void *(APIENTRYP PFNGLMAPOBJECTBUFFERATIPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLUNMAPOBJECTBUFFERATIPROC) (GLuint buffer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void *APIENTRY glMapObjectBufferATI (GLuint buffer);\nGLAPI void APIENTRY glUnmapObjectBufferATI (GLuint buffer);\n#endif\n#endif /* GL_ATI_map_object_buffer */\n\n#ifndef GL_ATI_meminfo\n#define GL_ATI_meminfo 1\n#define GL_VBO_FREE_MEMORY_ATI            0x87FB\n#define GL_TEXTURE_FREE_MEMORY_ATI        0x87FC\n#define GL_RENDERBUFFER_FREE_MEMORY_ATI   0x87FD\n#endif /* GL_ATI_meminfo */\n\n#ifndef GL_ATI_pixel_format_float\n#define GL_ATI_pixel_format_float 1\n#define GL_RGBA_FLOAT_MODE_ATI            0x8820\n#define GL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI 0x8835\n#endif /* GL_ATI_pixel_format_float */\n\n#ifndef GL_ATI_pn_triangles\n#define GL_ATI_pn_triangles 1\n#define GL_PN_TRIANGLES_ATI               0x87F0\n#define GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F1\n#define GL_PN_TRIANGLES_POINT_MODE_ATI    0x87F2\n#define GL_PN_TRIANGLES_NORMAL_MODE_ATI   0x87F3\n#define GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI 0x87F4\n#define GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI 0x87F5\n#define GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI 0x87F6\n#define GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI 0x87F7\n#define GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI 0x87F8\ntypedef void (APIENTRYP PFNGLPNTRIANGLESIATIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPNTRIANGLESFATIPROC) (GLenum pname, GLfloat param);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPNTrianglesiATI (GLenum pname, GLint param);\nGLAPI void APIENTRY glPNTrianglesfATI (GLenum pname, GLfloat param);\n#endif\n#endif /* GL_ATI_pn_triangles */\n\n#ifndef GL_ATI_separate_stencil\n#define GL_ATI_separate_stencil 1\n#define GL_STENCIL_BACK_FUNC_ATI          0x8800\n#define GL_STENCIL_BACK_FAIL_ATI          0x8801\n#define GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI 0x8802\n#define GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI 0x8803\ntypedef void (APIENTRYP PFNGLSTENCILOPSEPARATEATIPROC) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);\ntypedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEATIPROC) (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glStencilOpSeparateATI (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);\nGLAPI void APIENTRY glStencilFuncSeparateATI (GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask);\n#endif\n#endif /* GL_ATI_separate_stencil */\n\n#ifndef GL_ATI_text_fragment_shader\n#define GL_ATI_text_fragment_shader 1\n#define GL_TEXT_FRAGMENT_SHADER_ATI       0x8200\n#endif /* GL_ATI_text_fragment_shader */\n\n#ifndef GL_ATI_texture_env_combine3\n#define GL_ATI_texture_env_combine3 1\n#define GL_MODULATE_ADD_ATI               0x8744\n#define GL_MODULATE_SIGNED_ADD_ATI        0x8745\n#define GL_MODULATE_SUBTRACT_ATI          0x8746\n#endif /* GL_ATI_texture_env_combine3 */\n\n#ifndef GL_ATI_texture_float\n#define GL_ATI_texture_float 1\n#define GL_RGBA_FLOAT32_ATI               0x8814\n#define GL_RGB_FLOAT32_ATI                0x8815\n#define GL_ALPHA_FLOAT32_ATI              0x8816\n#define GL_INTENSITY_FLOAT32_ATI          0x8817\n#define GL_LUMINANCE_FLOAT32_ATI          0x8818\n#define GL_LUMINANCE_ALPHA_FLOAT32_ATI    0x8819\n#define GL_RGBA_FLOAT16_ATI               0x881A\n#define GL_RGB_FLOAT16_ATI                0x881B\n#define GL_ALPHA_FLOAT16_ATI              0x881C\n#define GL_INTENSITY_FLOAT16_ATI          0x881D\n#define GL_LUMINANCE_FLOAT16_ATI          0x881E\n#define GL_LUMINANCE_ALPHA_FLOAT16_ATI    0x881F\n#endif /* GL_ATI_texture_float */\n\n#ifndef GL_ATI_texture_mirror_once\n#define GL_ATI_texture_mirror_once 1\n#define GL_MIRROR_CLAMP_ATI               0x8742\n#define GL_MIRROR_CLAMP_TO_EDGE_ATI       0x8743\n#endif /* GL_ATI_texture_mirror_once */\n\n#ifndef GL_ATI_vertex_array_object\n#define GL_ATI_vertex_array_object 1\n#define GL_STATIC_ATI                     0x8760\n#define GL_DYNAMIC_ATI                    0x8761\n#define GL_PRESERVE_ATI                   0x8762\n#define GL_DISCARD_ATI                    0x8763\n#define GL_OBJECT_BUFFER_SIZE_ATI         0x8764\n#define GL_OBJECT_BUFFER_USAGE_ATI        0x8765\n#define GL_ARRAY_OBJECT_BUFFER_ATI        0x8766\n#define GL_ARRAY_OBJECT_OFFSET_ATI        0x8767\ntypedef GLuint (APIENTRYP PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const void *pointer, GLenum usage);\ntypedef GLboolean (APIENTRYP PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve);\ntypedef void (APIENTRYP PFNGLGETOBJECTBUFFERFVATIPROC) (GLuint buffer, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLFREEOBJECTBUFFERATIPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLARRAYOBJECTATIPROC) (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);\ntypedef void (APIENTRYP PFNGLGETARRAYOBJECTFVATIPROC) (GLenum array, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETARRAYOBJECTIVATIPROC) (GLenum array, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);\ntypedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLuint APIENTRY glNewObjectBufferATI (GLsizei size, const void *pointer, GLenum usage);\nGLAPI GLboolean APIENTRY glIsObjectBufferATI (GLuint buffer);\nGLAPI void APIENTRY glUpdateObjectBufferATI (GLuint buffer, GLuint offset, GLsizei size, const void *pointer, GLenum preserve);\nGLAPI void APIENTRY glGetObjectBufferfvATI (GLuint buffer, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetObjectBufferivATI (GLuint buffer, GLenum pname, GLint *params);\nGLAPI void APIENTRY glFreeObjectBufferATI (GLuint buffer);\nGLAPI void APIENTRY glArrayObjectATI (GLenum array, GLint size, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);\nGLAPI void APIENTRY glGetArrayObjectfvATI (GLenum array, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetArrayObjectivATI (GLenum array, GLenum pname, GLint *params);\nGLAPI void APIENTRY glVariantArrayObjectATI (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset);\nGLAPI void APIENTRY glGetVariantArrayObjectfvATI (GLuint id, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetVariantArrayObjectivATI (GLuint id, GLenum pname, GLint *params);\n#endif\n#endif /* GL_ATI_vertex_array_object */\n\n#ifndef GL_ATI_vertex_attrib_array_object\n#define GL_ATI_vertex_attrib_array_object 1\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBARRAYOBJECTATIPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTFVATIPROC) (GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBARRAYOBJECTIVATIPROC) (GLuint index, GLenum pname, GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexAttribArrayObjectATI (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLuint buffer, GLuint offset);\nGLAPI void APIENTRY glGetVertexAttribArrayObjectfvATI (GLuint index, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetVertexAttribArrayObjectivATI (GLuint index, GLenum pname, GLint *params);\n#endif\n#endif /* GL_ATI_vertex_attrib_array_object */\n\n#ifndef GL_ATI_vertex_streams\n#define GL_ATI_vertex_streams 1\n#define GL_MAX_VERTEX_STREAMS_ATI         0x876B\n#define GL_VERTEX_STREAM0_ATI             0x876C\n#define GL_VERTEX_STREAM1_ATI             0x876D\n#define GL_VERTEX_STREAM2_ATI             0x876E\n#define GL_VERTEX_STREAM3_ATI             0x876F\n#define GL_VERTEX_STREAM4_ATI             0x8770\n#define GL_VERTEX_STREAM5_ATI             0x8771\n#define GL_VERTEX_STREAM6_ATI             0x8772\n#define GL_VERTEX_STREAM7_ATI             0x8773\n#define GL_VERTEX_SOURCE_ATI              0x8774\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1SATIPROC) (GLenum stream, GLshort x);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1SVATIPROC) (GLenum stream, const GLshort *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1IATIPROC) (GLenum stream, GLint x);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1IVATIPROC) (GLenum stream, const GLint *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1FATIPROC) (GLenum stream, GLfloat x);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1FVATIPROC) (GLenum stream, const GLfloat *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1DATIPROC) (GLenum stream, GLdouble x);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM1DVATIPROC) (GLenum stream, const GLdouble *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2SATIPROC) (GLenum stream, GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2SVATIPROC) (GLenum stream, const GLshort *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2IATIPROC) (GLenum stream, GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2IVATIPROC) (GLenum stream, const GLint *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2FATIPROC) (GLenum stream, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2FVATIPROC) (GLenum stream, const GLfloat *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2DATIPROC) (GLenum stream, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM2DVATIPROC) (GLenum stream, const GLdouble *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3IATIPROC) (GLenum stream, GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4SATIPROC) (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4SVATIPROC) (GLenum stream, const GLshort *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4IATIPROC) (GLenum stream, GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4IVATIPROC) (GLenum stream, const GLint *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4FATIPROC) (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4FVATIPROC) (GLenum stream, const GLfloat *coords);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4DATIPROC) (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEXSTREAM4DVATIPROC) (GLenum stream, const GLdouble *coords);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3BATIPROC) (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3BVATIPROC) (GLenum stream, const GLbyte *coords);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3SATIPROC) (GLenum stream, GLshort nx, GLshort ny, GLshort nz);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3SVATIPROC) (GLenum stream, const GLshort *coords);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3IATIPROC) (GLenum stream, GLint nx, GLint ny, GLint nz);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3IVATIPROC) (GLenum stream, const GLint *coords);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3FATIPROC) (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3FVATIPROC) (GLenum stream, const GLfloat *coords);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3DATIPROC) (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);\ntypedef void (APIENTRYP PFNGLNORMALSTREAM3DVATIPROC) (GLenum stream, const GLdouble *coords);\ntypedef void (APIENTRYP PFNGLCLIENTACTIVEVERTEXSTREAMATIPROC) (GLenum stream);\ntypedef void (APIENTRYP PFNGLVERTEXBLENDENVIATIPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLVERTEXBLENDENVFATIPROC) (GLenum pname, GLfloat param);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexStream1sATI (GLenum stream, GLshort x);\nGLAPI void APIENTRY glVertexStream1svATI (GLenum stream, const GLshort *coords);\nGLAPI void APIENTRY glVertexStream1iATI (GLenum stream, GLint x);\nGLAPI void APIENTRY glVertexStream1ivATI (GLenum stream, const GLint *coords);\nGLAPI void APIENTRY glVertexStream1fATI (GLenum stream, GLfloat x);\nGLAPI void APIENTRY glVertexStream1fvATI (GLenum stream, const GLfloat *coords);\nGLAPI void APIENTRY glVertexStream1dATI (GLenum stream, GLdouble x);\nGLAPI void APIENTRY glVertexStream1dvATI (GLenum stream, const GLdouble *coords);\nGLAPI void APIENTRY glVertexStream2sATI (GLenum stream, GLshort x, GLshort y);\nGLAPI void APIENTRY glVertexStream2svATI (GLenum stream, const GLshort *coords);\nGLAPI void APIENTRY glVertexStream2iATI (GLenum stream, GLint x, GLint y);\nGLAPI void APIENTRY glVertexStream2ivATI (GLenum stream, const GLint *coords);\nGLAPI void APIENTRY glVertexStream2fATI (GLenum stream, GLfloat x, GLfloat y);\nGLAPI void APIENTRY glVertexStream2fvATI (GLenum stream, const GLfloat *coords);\nGLAPI void APIENTRY glVertexStream2dATI (GLenum stream, GLdouble x, GLdouble y);\nGLAPI void APIENTRY glVertexStream2dvATI (GLenum stream, const GLdouble *coords);\nGLAPI void APIENTRY glVertexStream3sATI (GLenum stream, GLshort x, GLshort y, GLshort z);\nGLAPI void APIENTRY glVertexStream3svATI (GLenum stream, const GLshort *coords);\nGLAPI void APIENTRY glVertexStream3iATI (GLenum stream, GLint x, GLint y, GLint z);\nGLAPI void APIENTRY glVertexStream3ivATI (GLenum stream, const GLint *coords);\nGLAPI void APIENTRY glVertexStream3fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glVertexStream3fvATI (GLenum stream, const GLfloat *coords);\nGLAPI void APIENTRY glVertexStream3dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glVertexStream3dvATI (GLenum stream, const GLdouble *coords);\nGLAPI void APIENTRY glVertexStream4sATI (GLenum stream, GLshort x, GLshort y, GLshort z, GLshort w);\nGLAPI void APIENTRY glVertexStream4svATI (GLenum stream, const GLshort *coords);\nGLAPI void APIENTRY glVertexStream4iATI (GLenum stream, GLint x, GLint y, GLint z, GLint w);\nGLAPI void APIENTRY glVertexStream4ivATI (GLenum stream, const GLint *coords);\nGLAPI void APIENTRY glVertexStream4fATI (GLenum stream, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glVertexStream4fvATI (GLenum stream, const GLfloat *coords);\nGLAPI void APIENTRY glVertexStream4dATI (GLenum stream, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glVertexStream4dvATI (GLenum stream, const GLdouble *coords);\nGLAPI void APIENTRY glNormalStream3bATI (GLenum stream, GLbyte nx, GLbyte ny, GLbyte nz);\nGLAPI void APIENTRY glNormalStream3bvATI (GLenum stream, const GLbyte *coords);\nGLAPI void APIENTRY glNormalStream3sATI (GLenum stream, GLshort nx, GLshort ny, GLshort nz);\nGLAPI void APIENTRY glNormalStream3svATI (GLenum stream, const GLshort *coords);\nGLAPI void APIENTRY glNormalStream3iATI (GLenum stream, GLint nx, GLint ny, GLint nz);\nGLAPI void APIENTRY glNormalStream3ivATI (GLenum stream, const GLint *coords);\nGLAPI void APIENTRY glNormalStream3fATI (GLenum stream, GLfloat nx, GLfloat ny, GLfloat nz);\nGLAPI void APIENTRY glNormalStream3fvATI (GLenum stream, const GLfloat *coords);\nGLAPI void APIENTRY glNormalStream3dATI (GLenum stream, GLdouble nx, GLdouble ny, GLdouble nz);\nGLAPI void APIENTRY glNormalStream3dvATI (GLenum stream, const GLdouble *coords);\nGLAPI void APIENTRY glClientActiveVertexStreamATI (GLenum stream);\nGLAPI void APIENTRY glVertexBlendEnviATI (GLenum pname, GLint param);\nGLAPI void APIENTRY glVertexBlendEnvfATI (GLenum pname, GLfloat param);\n#endif\n#endif /* GL_ATI_vertex_streams */\n\n#ifndef GL_EXT_422_pixels\n#define GL_EXT_422_pixels 1\n#define GL_422_EXT                        0x80CC\n#define GL_422_REV_EXT                    0x80CD\n#define GL_422_AVERAGE_EXT                0x80CE\n#define GL_422_REV_AVERAGE_EXT            0x80CF\n#endif /* GL_EXT_422_pixels */\n\n#ifndef GL_EXT_EGL_image_storage\n#define GL_EXT_EGL_image_storage 1\ntypedef void *GLeglImageOES;\ntypedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXSTORAGEEXTPROC) (GLenum target, GLeglImageOES image, const GLint* attrib_list);\ntypedef void (APIENTRYP PFNGLEGLIMAGETARGETTEXTURESTORAGEEXTPROC) (GLuint texture, GLeglImageOES image, const GLint* attrib_list);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glEGLImageTargetTexStorageEXT (GLenum target, GLeglImageOES image, const GLint* attrib_list);\nGLAPI void APIENTRY glEGLImageTargetTextureStorageEXT (GLuint texture, GLeglImageOES image, const GLint* attrib_list);\n#endif\n#endif /* GL_EXT_EGL_image_storage */\n\n#ifndef GL_EXT_EGL_sync\n#define GL_EXT_EGL_sync 1\n#endif /* GL_EXT_EGL_sync */\n\n#ifndef GL_EXT_abgr\n#define GL_EXT_abgr 1\n#define GL_ABGR_EXT                       0x8000\n#endif /* GL_EXT_abgr */\n\n#ifndef GL_EXT_bgra\n#define GL_EXT_bgra 1\n#define GL_BGR_EXT                        0x80E0\n#define GL_BGRA_EXT                       0x80E1\n#endif /* GL_EXT_bgra */\n\n#ifndef GL_EXT_bindable_uniform\n#define GL_EXT_bindable_uniform 1\n#define GL_MAX_VERTEX_BINDABLE_UNIFORMS_EXT 0x8DE2\n#define GL_MAX_FRAGMENT_BINDABLE_UNIFORMS_EXT 0x8DE3\n#define GL_MAX_GEOMETRY_BINDABLE_UNIFORMS_EXT 0x8DE4\n#define GL_MAX_BINDABLE_UNIFORM_SIZE_EXT  0x8DED\n#define GL_UNIFORM_BUFFER_EXT             0x8DEE\n#define GL_UNIFORM_BUFFER_BINDING_EXT     0x8DEF\ntypedef void (APIENTRYP PFNGLUNIFORMBUFFEREXTPROC) (GLuint program, GLint location, GLuint buffer);\ntypedef GLint (APIENTRYP PFNGLGETUNIFORMBUFFERSIZEEXTPROC) (GLuint program, GLint location);\ntypedef GLintptr (APIENTRYP PFNGLGETUNIFORMOFFSETEXTPROC) (GLuint program, GLint location);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glUniformBufferEXT (GLuint program, GLint location, GLuint buffer);\nGLAPI GLint APIENTRY glGetUniformBufferSizeEXT (GLuint program, GLint location);\nGLAPI GLintptr APIENTRY glGetUniformOffsetEXT (GLuint program, GLint location);\n#endif\n#endif /* GL_EXT_bindable_uniform */\n\n#ifndef GL_EXT_blend_color\n#define GL_EXT_blend_color 1\n#define GL_CONSTANT_COLOR_EXT             0x8001\n#define GL_ONE_MINUS_CONSTANT_COLOR_EXT   0x8002\n#define GL_CONSTANT_ALPHA_EXT             0x8003\n#define GL_ONE_MINUS_CONSTANT_ALPHA_EXT   0x8004\n#define GL_BLEND_COLOR_EXT                0x8005\ntypedef void (APIENTRYP PFNGLBLENDCOLOREXTPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendColorEXT (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\n#endif\n#endif /* GL_EXT_blend_color */\n\n#ifndef GL_EXT_blend_equation_separate\n#define GL_EXT_blend_equation_separate 1\n#define GL_BLEND_EQUATION_RGB_EXT         0x8009\n#define GL_BLEND_EQUATION_ALPHA_EXT       0x883D\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEEXTPROC) (GLenum modeRGB, GLenum modeAlpha);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendEquationSeparateEXT (GLenum modeRGB, GLenum modeAlpha);\n#endif\n#endif /* GL_EXT_blend_equation_separate */\n\n#ifndef GL_EXT_blend_func_separate\n#define GL_EXT_blend_func_separate 1\n#define GL_BLEND_DST_RGB_EXT              0x80C8\n#define GL_BLEND_SRC_RGB_EXT              0x80C9\n#define GL_BLEND_DST_ALPHA_EXT            0x80CA\n#define GL_BLEND_SRC_ALPHA_EXT            0x80CB\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEEXTPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendFuncSeparateEXT (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\n#endif\n#endif /* GL_EXT_blend_func_separate */\n\n#ifndef GL_EXT_blend_logic_op\n#define GL_EXT_blend_logic_op 1\n#endif /* GL_EXT_blend_logic_op */\n\n#ifndef GL_EXT_blend_minmax\n#define GL_EXT_blend_minmax 1\n#define GL_MIN_EXT                        0x8007\n#define GL_MAX_EXT                        0x8008\n#define GL_FUNC_ADD_EXT                   0x8006\n#define GL_BLEND_EQUATION_EXT             0x8009\ntypedef void (APIENTRYP PFNGLBLENDEQUATIONEXTPROC) (GLenum mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendEquationEXT (GLenum mode);\n#endif\n#endif /* GL_EXT_blend_minmax */\n\n#ifndef GL_EXT_blend_subtract\n#define GL_EXT_blend_subtract 1\n#define GL_FUNC_SUBTRACT_EXT              0x800A\n#define GL_FUNC_REVERSE_SUBTRACT_EXT      0x800B\n#endif /* GL_EXT_blend_subtract */\n\n#ifndef GL_EXT_clip_volume_hint\n#define GL_EXT_clip_volume_hint 1\n#define GL_CLIP_VOLUME_CLIPPING_HINT_EXT  0x80F0\n#endif /* GL_EXT_clip_volume_hint */\n\n#ifndef GL_EXT_cmyka\n#define GL_EXT_cmyka 1\n#define GL_CMYK_EXT                       0x800C\n#define GL_CMYKA_EXT                      0x800D\n#define GL_PACK_CMYK_HINT_EXT             0x800E\n#define GL_UNPACK_CMYK_HINT_EXT           0x800F\n#endif /* GL_EXT_cmyka */\n\n#ifndef GL_EXT_color_subtable\n#define GL_EXT_color_subtable 1\ntypedef void (APIENTRYP PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);\ntypedef void (APIENTRYP PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorSubTableEXT (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void *data);\nGLAPI void APIENTRY glCopyColorSubTableEXT (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width);\n#endif\n#endif /* GL_EXT_color_subtable */\n\n#ifndef GL_EXT_compiled_vertex_array\n#define GL_EXT_compiled_vertex_array 1\n#define GL_ARRAY_ELEMENT_LOCK_FIRST_EXT   0x81A8\n#define GL_ARRAY_ELEMENT_LOCK_COUNT_EXT   0x81A9\ntypedef void (APIENTRYP PFNGLLOCKARRAYSEXTPROC) (GLint first, GLsizei count);\ntypedef void (APIENTRYP PFNGLUNLOCKARRAYSEXTPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glLockArraysEXT (GLint first, GLsizei count);\nGLAPI void APIENTRY glUnlockArraysEXT (void);\n#endif\n#endif /* GL_EXT_compiled_vertex_array */\n\n#ifndef GL_EXT_convolution\n#define GL_EXT_convolution 1\n#define GL_CONVOLUTION_1D_EXT             0x8010\n#define GL_CONVOLUTION_2D_EXT             0x8011\n#define GL_SEPARABLE_2D_EXT               0x8012\n#define GL_CONVOLUTION_BORDER_MODE_EXT    0x8013\n#define GL_CONVOLUTION_FILTER_SCALE_EXT   0x8014\n#define GL_CONVOLUTION_FILTER_BIAS_EXT    0x8015\n#define GL_REDUCE_EXT                     0x8016\n#define GL_CONVOLUTION_FORMAT_EXT         0x8017\n#define GL_CONVOLUTION_WIDTH_EXT          0x8018\n#define GL_CONVOLUTION_HEIGHT_EXT         0x8019\n#define GL_MAX_CONVOLUTION_WIDTH_EXT      0x801A\n#define GL_MAX_CONVOLUTION_HEIGHT_EXT     0x801B\n#define GL_POST_CONVOLUTION_RED_SCALE_EXT 0x801C\n#define GL_POST_CONVOLUTION_GREEN_SCALE_EXT 0x801D\n#define GL_POST_CONVOLUTION_BLUE_SCALE_EXT 0x801E\n#define GL_POST_CONVOLUTION_ALPHA_SCALE_EXT 0x801F\n#define GL_POST_CONVOLUTION_RED_BIAS_EXT  0x8020\n#define GL_POST_CONVOLUTION_GREEN_BIAS_EXT 0x8021\n#define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022\n#define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023\ntypedef void (APIENTRYP PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint params);\ntypedef void (APIENTRYP PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *image);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);\ntypedef void (APIENTRYP PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *image);\nGLAPI void APIENTRY glConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *image);\nGLAPI void APIENTRY glConvolutionParameterfEXT (GLenum target, GLenum pname, GLfloat params);\nGLAPI void APIENTRY glConvolutionParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glConvolutionParameteriEXT (GLenum target, GLenum pname, GLint params);\nGLAPI void APIENTRY glConvolutionParameterivEXT (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glCopyConvolutionFilter1DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\nGLAPI void APIENTRY glCopyConvolutionFilter2DEXT (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glGetConvolutionFilterEXT (GLenum target, GLenum format, GLenum type, void *image);\nGLAPI void APIENTRY glGetConvolutionParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetConvolutionParameterivEXT (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetSeparableFilterEXT (GLenum target, GLenum format, GLenum type, void *row, void *column, void *span);\nGLAPI void APIENTRY glSeparableFilter2DEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *row, const void *column);\n#endif\n#endif /* GL_EXT_convolution */\n\n#ifndef GL_EXT_coordinate_frame\n#define GL_EXT_coordinate_frame 1\n#define GL_TANGENT_ARRAY_EXT              0x8439\n#define GL_BINORMAL_ARRAY_EXT             0x843A\n#define GL_CURRENT_TANGENT_EXT            0x843B\n#define GL_CURRENT_BINORMAL_EXT           0x843C\n#define GL_TANGENT_ARRAY_TYPE_EXT         0x843E\n#define GL_TANGENT_ARRAY_STRIDE_EXT       0x843F\n#define GL_BINORMAL_ARRAY_TYPE_EXT        0x8440\n#define GL_BINORMAL_ARRAY_STRIDE_EXT      0x8441\n#define GL_TANGENT_ARRAY_POINTER_EXT      0x8442\n#define GL_BINORMAL_ARRAY_POINTER_EXT     0x8443\n#define GL_MAP1_TANGENT_EXT               0x8444\n#define GL_MAP2_TANGENT_EXT               0x8445\n#define GL_MAP1_BINORMAL_EXT              0x8446\n#define GL_MAP2_BINORMAL_EXT              0x8447\ntypedef void (APIENTRYP PFNGLTANGENT3BEXTPROC) (GLbyte tx, GLbyte ty, GLbyte tz);\ntypedef void (APIENTRYP PFNGLTANGENT3BVEXTPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLTANGENT3DEXTPROC) (GLdouble tx, GLdouble ty, GLdouble tz);\ntypedef void (APIENTRYP PFNGLTANGENT3DVEXTPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLTANGENT3FEXTPROC) (GLfloat tx, GLfloat ty, GLfloat tz);\ntypedef void (APIENTRYP PFNGLTANGENT3FVEXTPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTANGENT3IEXTPROC) (GLint tx, GLint ty, GLint tz);\ntypedef void (APIENTRYP PFNGLTANGENT3IVEXTPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLTANGENT3SEXTPROC) (GLshort tx, GLshort ty, GLshort tz);\ntypedef void (APIENTRYP PFNGLTANGENT3SVEXTPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLBINORMAL3BEXTPROC) (GLbyte bx, GLbyte by, GLbyte bz);\ntypedef void (APIENTRYP PFNGLBINORMAL3BVEXTPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLBINORMAL3DEXTPROC) (GLdouble bx, GLdouble by, GLdouble bz);\ntypedef void (APIENTRYP PFNGLBINORMAL3DVEXTPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLBINORMAL3FEXTPROC) (GLfloat bx, GLfloat by, GLfloat bz);\ntypedef void (APIENTRYP PFNGLBINORMAL3FVEXTPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLBINORMAL3IEXTPROC) (GLint bx, GLint by, GLint bz);\ntypedef void (APIENTRYP PFNGLBINORMAL3IVEXTPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLBINORMAL3SEXTPROC) (GLshort bx, GLshort by, GLshort bz);\ntypedef void (APIENTRYP PFNGLBINORMAL3SVEXTPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTangent3bEXT (GLbyte tx, GLbyte ty, GLbyte tz);\nGLAPI void APIENTRY glTangent3bvEXT (const GLbyte *v);\nGLAPI void APIENTRY glTangent3dEXT (GLdouble tx, GLdouble ty, GLdouble tz);\nGLAPI void APIENTRY glTangent3dvEXT (const GLdouble *v);\nGLAPI void APIENTRY glTangent3fEXT (GLfloat tx, GLfloat ty, GLfloat tz);\nGLAPI void APIENTRY glTangent3fvEXT (const GLfloat *v);\nGLAPI void APIENTRY glTangent3iEXT (GLint tx, GLint ty, GLint tz);\nGLAPI void APIENTRY glTangent3ivEXT (const GLint *v);\nGLAPI void APIENTRY glTangent3sEXT (GLshort tx, GLshort ty, GLshort tz);\nGLAPI void APIENTRY glTangent3svEXT (const GLshort *v);\nGLAPI void APIENTRY glBinormal3bEXT (GLbyte bx, GLbyte by, GLbyte bz);\nGLAPI void APIENTRY glBinormal3bvEXT (const GLbyte *v);\nGLAPI void APIENTRY glBinormal3dEXT (GLdouble bx, GLdouble by, GLdouble bz);\nGLAPI void APIENTRY glBinormal3dvEXT (const GLdouble *v);\nGLAPI void APIENTRY glBinormal3fEXT (GLfloat bx, GLfloat by, GLfloat bz);\nGLAPI void APIENTRY glBinormal3fvEXT (const GLfloat *v);\nGLAPI void APIENTRY glBinormal3iEXT (GLint bx, GLint by, GLint bz);\nGLAPI void APIENTRY glBinormal3ivEXT (const GLint *v);\nGLAPI void APIENTRY glBinormal3sEXT (GLshort bx, GLshort by, GLshort bz);\nGLAPI void APIENTRY glBinormal3svEXT (const GLshort *v);\nGLAPI void APIENTRY glTangentPointerEXT (GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glBinormalPointerEXT (GLenum type, GLsizei stride, const void *pointer);\n#endif\n#endif /* GL_EXT_coordinate_frame */\n\n#ifndef GL_EXT_copy_texture\n#define GL_EXT_copy_texture 1\ntypedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\ntypedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCopyTexImage1DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\nGLAPI void APIENTRY glCopyTexImage2DEXT (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\nGLAPI void APIENTRY glCopyTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\nGLAPI void APIENTRY glCopyTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glCopyTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\n#endif\n#endif /* GL_EXT_copy_texture */\n\n#ifndef GL_EXT_cull_vertex\n#define GL_EXT_cull_vertex 1\n#define GL_CULL_VERTEX_EXT                0x81AA\n#define GL_CULL_VERTEX_EYE_POSITION_EXT   0x81AB\n#define GL_CULL_VERTEX_OBJECT_POSITION_EXT 0x81AC\ntypedef void (APIENTRYP PFNGLCULLPARAMETERDVEXTPROC) (GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLCULLPARAMETERFVEXTPROC) (GLenum pname, GLfloat *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCullParameterdvEXT (GLenum pname, GLdouble *params);\nGLAPI void APIENTRY glCullParameterfvEXT (GLenum pname, GLfloat *params);\n#endif\n#endif /* GL_EXT_cull_vertex */\n\n#ifndef GL_EXT_debug_label\n#define GL_EXT_debug_label 1\n#define GL_PROGRAM_PIPELINE_OBJECT_EXT    0x8A4F\n#define GL_PROGRAM_OBJECT_EXT             0x8B40\n#define GL_SHADER_OBJECT_EXT              0x8B48\n#define GL_BUFFER_OBJECT_EXT              0x9151\n#define GL_QUERY_OBJECT_EXT               0x9153\n#define GL_VERTEX_ARRAY_OBJECT_EXT        0x9154\ntypedef void (APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);\ntypedef void (APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label);\nGLAPI void APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);\n#endif\n#endif /* GL_EXT_debug_label */\n\n#ifndef GL_EXT_debug_marker\n#define GL_EXT_debug_marker 1\ntypedef void (APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);\ntypedef void (APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);\ntypedef void (APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);\nGLAPI void APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);\nGLAPI void APIENTRY glPopGroupMarkerEXT (void);\n#endif\n#endif /* GL_EXT_debug_marker */\n\n#ifndef GL_EXT_depth_bounds_test\n#define GL_EXT_depth_bounds_test 1\n#define GL_DEPTH_BOUNDS_TEST_EXT          0x8890\n#define GL_DEPTH_BOUNDS_EXT               0x8891\ntypedef void (APIENTRYP PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zmax);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDepthBoundsEXT (GLclampd zmin, GLclampd zmax);\n#endif\n#endif /* GL_EXT_depth_bounds_test */\n\n#ifndef GL_EXT_direct_state_access\n#define GL_EXT_direct_state_access 1\n#define GL_PROGRAM_MATRIX_EXT             0x8E2D\n#define GL_TRANSPOSE_PROGRAM_MATRIX_EXT   0x8E2E\n#define GL_PROGRAM_MATRIX_STACK_DEPTH_EXT 0x8E2F\ntypedef void (APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMATRIXLOADDEXTPROC) (GLenum mode, const GLdouble *m);\ntypedef void (APIENTRYP PFNGLMATRIXMULTFEXTPROC) (GLenum mode, const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMATRIXMULTDEXTPROC) (GLenum mode, const GLdouble *m);\ntypedef void (APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLMATRIXROTATEFEXTPROC) (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLMATRIXROTATEDEXTPROC) (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLMATRIXSCALEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLMATRIXSCALEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum mode, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum mode, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLMATRIXFRUSTUMEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\ntypedef void (APIENTRYP PFNGLMATRIXORTHOEXTPROC) (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\ntypedef void (APIENTRYP PFNGLMATRIXPOPEXTPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLMATRIXPUSHEXTPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask);\ntypedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\ntypedef void (APIENTRYP PFNGLCOPYTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\ntypedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLMULTITEXGENDEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble param);\ntypedef void (APIENTRYP PFNGLMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params);\ntypedef void (APIENTRYP PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLGETMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\ntypedef void (APIENTRYP PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\ntypedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);\ntypedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLCOPYMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLENABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index);\ntypedef void (APIENTRYP PFNGLDISABLECLIENTSTATEINDEXEDEXTPROC) (GLenum array, GLuint index);\ntypedef void (APIENTRYP PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat *data);\ntypedef void (APIENTRYP PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble *data);\ntypedef void (APIENTRYP PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, void **data);\ntypedef void (APIENTRYP PFNGLENABLEINDEXEDEXTPROC) (GLenum target, GLuint index);\ntypedef void (APIENTRYP PFNGLDISABLEINDEXEDEXTPROC) (GLenum target, GLuint index);\ntypedef GLboolean (APIENTRYP PFNGLISENABLEDINDEXEDEXTPROC) (GLenum target, GLuint index);\ntypedef void (APIENTRYP PFNGLGETINTEGERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLint *data);\ntypedef void (APIENTRYP PFNGLGETBOOLEANINDEXEDVEXTPROC) (GLenum target, GLuint index, GLboolean *data);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint lod, void *img);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);\ntypedef void (APIENTRYP PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint lod, void *img);\ntypedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m);\ntypedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEFEXTPROC) (GLenum mode, const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSEDEXTPROC) (GLenum mode, const GLdouble *m);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);\ntypedef void *(APIENTRYP PFNGLMAPNAMEDBUFFEREXTPROC) (GLuint buffer, GLenum access);\ntypedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void **params);\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer);\ntypedef void (APIENTRYP PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint *params);\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint *params);\ntypedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IEXTPROC) (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLint *params);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLuint *params);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params);\ntypedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint *params);\ntypedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint *params);\ntypedef void (APIENTRYP PFNGLENABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index);\ntypedef void (APIENTRYP PFNGLDISABLECLIENTSTATEIEXTPROC) (GLenum array, GLuint index);\ntypedef void (APIENTRYP PFNGLGETFLOATI_VEXTPROC) (GLenum pname, GLuint index, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, void **params);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4DVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLdouble *params);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLNAMEDPROGRAMLOCALPARAMETER4FVEXTPROC) (GLuint program, GLenum target, GLuint index, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void *string);\ntypedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE2DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURE3DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target);\ntypedef void (APIENTRYP PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFEREXTPROC) (GLuint framebuffer, GLenum mode);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuffer, GLsizei n, const GLenum *bufs);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode);\ntypedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYEREXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREFACEEXTPROC) (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face);\ntypedef void (APIENTRYP PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYINDEXOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYNORMALOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYTEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYMULTITEXCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYFOGCOORDOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYSECONDARYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLENABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array);\ntypedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYEXTPROC) (GLuint vaobj, GLenum array);\ntypedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index);\ntypedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBEXTPROC) (GLuint vaobj, GLuint index);\ntypedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERVEXTPROC) (GLuint vaobj, GLenum pname, GLint *param);\ntypedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERVEXTPROC) (GLuint vaobj, GLenum pname, void **param);\ntypedef void (APIENTRYP PFNGLGETVERTEXARRAYINTEGERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, GLint *param);\ntypedef void (APIENTRYP PFNGLGETVERTEXARRAYPOINTERI_VEXTPROC) (GLuint vaobj, GLuint index, GLenum pname, void **param);\ntypedef void *(APIENTRYP PFNGLMAPNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);\ntypedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr length);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);\ntypedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);\ntypedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIEXTPROC) (GLuint framebuffer, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\ntypedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEEXTPROC) (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYBINDVERTEXBUFFEREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBIFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLFORMATEXTPROC) (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBBINDINGEXTPROC) (GLuint vaobj, GLuint attribindex, GLuint bindingindex);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBINDINGDIVISOREXTPROC) (GLuint vaobj, GLuint bindingindex, GLuint divisor);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBLOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);\ntypedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXATTRIBDIVISOREXTPROC) (GLuint vaobj, GLuint index, GLuint divisor);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMatrixLoadfEXT (GLenum mode, const GLfloat *m);\nGLAPI void APIENTRY glMatrixLoaddEXT (GLenum mode, const GLdouble *m);\nGLAPI void APIENTRY glMatrixMultfEXT (GLenum mode, const GLfloat *m);\nGLAPI void APIENTRY glMatrixMultdEXT (GLenum mode, const GLdouble *m);\nGLAPI void APIENTRY glMatrixLoadIdentityEXT (GLenum mode);\nGLAPI void APIENTRY glMatrixRotatefEXT (GLenum mode, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glMatrixRotatedEXT (GLenum mode, GLdouble angle, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glMatrixScalefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glMatrixScaledEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glMatrixTranslatefEXT (GLenum mode, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glMatrixTranslatedEXT (GLenum mode, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glMatrixFrustumEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\nGLAPI void APIENTRY glMatrixOrthoEXT (GLenum mode, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar);\nGLAPI void APIENTRY glMatrixPopEXT (GLenum mode);\nGLAPI void APIENTRY glMatrixPushEXT (GLenum mode);\nGLAPI void APIENTRY glClientAttribDefaultEXT (GLbitfield mask);\nGLAPI void APIENTRY glPushClientAttribDefaultEXT (GLbitfield mask);\nGLAPI void APIENTRY glTextureParameterfEXT (GLuint texture, GLenum target, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glTextureParameteriEXT (GLuint texture, GLenum target, GLenum pname, GLint param);\nGLAPI void APIENTRY glTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glCopyTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\nGLAPI void APIENTRY glCopyTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\nGLAPI void APIENTRY glCopyTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\nGLAPI void APIENTRY glCopyTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glGetTextureImageEXT (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);\nGLAPI void APIENTRY glGetTextureParameterfvEXT (GLuint texture, GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetTextureParameterivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetTextureLevelParameterfvEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetTextureLevelParameterivEXT (GLuint texture, GLenum target, GLint level, GLenum pname, GLint *params);\nGLAPI void APIENTRY glTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glCopyTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glBindMultiTextureEXT (GLenum texunit, GLenum target, GLuint texture);\nGLAPI void APIENTRY glMultiTexCoordPointerEXT (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glMultiTexEnvfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glMultiTexEnviEXT (GLenum texunit, GLenum target, GLenum pname, GLint param);\nGLAPI void APIENTRY glMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glMultiTexGendEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble param);\nGLAPI void APIENTRY glMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLdouble *params);\nGLAPI void APIENTRY glMultiTexGenfEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glMultiTexGeniEXT (GLenum texunit, GLenum coord, GLenum pname, GLint param);\nGLAPI void APIENTRY glMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glGetMultiTexEnvfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetMultiTexEnvivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetMultiTexGendvEXT (GLenum texunit, GLenum coord, GLenum pname, GLdouble *params);\nGLAPI void APIENTRY glGetMultiTexGenfvEXT (GLenum texunit, GLenum coord, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetMultiTexGenivEXT (GLenum texunit, GLenum coord, GLenum pname, GLint *params);\nGLAPI void APIENTRY glMultiTexParameteriEXT (GLenum texunit, GLenum target, GLenum pname, GLint param);\nGLAPI void APIENTRY glMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glMultiTexParameterfEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glCopyMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\nGLAPI void APIENTRY glCopyMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\nGLAPI void APIENTRY glCopyMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\nGLAPI void APIENTRY glCopyMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glGetMultiTexImageEXT (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void *pixels);\nGLAPI void APIENTRY glGetMultiTexParameterfvEXT (GLenum texunit, GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetMultiTexParameterivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetMultiTexLevelParameterfvEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetMultiTexLevelParameterivEXT (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint *params);\nGLAPI void APIENTRY glMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glCopyMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glEnableClientStateIndexedEXT (GLenum array, GLuint index);\nGLAPI void APIENTRY glDisableClientStateIndexedEXT (GLenum array, GLuint index);\nGLAPI void APIENTRY glGetFloatIndexedvEXT (GLenum target, GLuint index, GLfloat *data);\nGLAPI void APIENTRY glGetDoubleIndexedvEXT (GLenum target, GLuint index, GLdouble *data);\nGLAPI void APIENTRY glGetPointerIndexedvEXT (GLenum target, GLuint index, void **data);\nGLAPI void APIENTRY glEnableIndexedEXT (GLenum target, GLuint index);\nGLAPI void APIENTRY glDisableIndexedEXT (GLenum target, GLuint index);\nGLAPI GLboolean APIENTRY glIsEnabledIndexedEXT (GLenum target, GLuint index);\nGLAPI void APIENTRY glGetIntegerIndexedvEXT (GLenum target, GLuint index, GLint *data);\nGLAPI void APIENTRY glGetBooleanIndexedvEXT (GLenum target, GLuint index, GLboolean *data);\nGLAPI void APIENTRY glCompressedTextureImage3DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glCompressedTextureImage2DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glCompressedTextureImage1DEXT (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glCompressedTextureSubImage3DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glCompressedTextureSubImage2DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glCompressedTextureSubImage1DEXT (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glGetCompressedTextureImageEXT (GLuint texture, GLenum target, GLint lod, void *img);\nGLAPI void APIENTRY glCompressedMultiTexImage3DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glCompressedMultiTexImage2DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glCompressedMultiTexImage1DEXT (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glCompressedMultiTexSubImage3DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glCompressedMultiTexSubImage2DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glCompressedMultiTexSubImage1DEXT (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *bits);\nGLAPI void APIENTRY glGetCompressedMultiTexImageEXT (GLenum texunit, GLenum target, GLint lod, void *img);\nGLAPI void APIENTRY glMatrixLoadTransposefEXT (GLenum mode, const GLfloat *m);\nGLAPI void APIENTRY glMatrixLoadTransposedEXT (GLenum mode, const GLdouble *m);\nGLAPI void APIENTRY glMatrixMultTransposefEXT (GLenum mode, const GLfloat *m);\nGLAPI void APIENTRY glMatrixMultTransposedEXT (GLenum mode, const GLdouble *m);\nGLAPI void APIENTRY glNamedBufferDataEXT (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);\nGLAPI void APIENTRY glNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);\nGLAPI void *APIENTRY glMapNamedBufferEXT (GLuint buffer, GLenum access);\nGLAPI GLboolean APIENTRY glUnmapNamedBufferEXT (GLuint buffer);\nGLAPI void APIENTRY glGetNamedBufferParameterivEXT (GLuint buffer, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetNamedBufferPointervEXT (GLuint buffer, GLenum pname, void **params);\nGLAPI void APIENTRY glGetNamedBufferSubDataEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);\nGLAPI void APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat v0);\nGLAPI void APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1);\nGLAPI void APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\nGLAPI void APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\nGLAPI void APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint v0);\nGLAPI void APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint v0, GLint v1);\nGLAPI void APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2);\nGLAPI void APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\nGLAPI void APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);\nGLAPI void APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix2x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix3x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix2x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix4x2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix3x4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glProgramUniformMatrix4x3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);\nGLAPI void APIENTRY glTextureBufferEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer);\nGLAPI void APIENTRY glMultiTexBufferEXT (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer);\nGLAPI void APIENTRY glTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, const GLuint *params);\nGLAPI void APIENTRY glGetTextureParameterIivEXT (GLuint texture, GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetTextureParameterIuivEXT (GLuint texture, GLenum target, GLenum pname, GLuint *params);\nGLAPI void APIENTRY glMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, const GLuint *params);\nGLAPI void APIENTRY glGetMultiTexParameterIivEXT (GLenum texunit, GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetMultiTexParameterIuivEXT (GLenum texunit, GLenum target, GLenum pname, GLuint *params);\nGLAPI void APIENTRY glProgramUniform1uiEXT (GLuint program, GLint location, GLuint v0);\nGLAPI void APIENTRY glProgramUniform2uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1);\nGLAPI void APIENTRY glProgramUniform3uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);\nGLAPI void APIENTRY glProgramUniform4uiEXT (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\nGLAPI void APIENTRY glProgramUniform1uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glProgramUniform2uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glProgramUniform3uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glProgramUniform4uivEXT (GLuint program, GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glNamedProgramLocalParameters4fvEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat *params);\nGLAPI void APIENTRY glNamedProgramLocalParameterI4iEXT (GLuint program, GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);\nGLAPI void APIENTRY glNamedProgramLocalParameterI4ivEXT (GLuint program, GLenum target, GLuint index, const GLint *params);\nGLAPI void APIENTRY glNamedProgramLocalParametersI4ivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint *params);\nGLAPI void APIENTRY glNamedProgramLocalParameterI4uiEXT (GLuint program, GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\nGLAPI void APIENTRY glNamedProgramLocalParameterI4uivEXT (GLuint program, GLenum target, GLuint index, const GLuint *params);\nGLAPI void APIENTRY glNamedProgramLocalParametersI4uivEXT (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint *params);\nGLAPI void APIENTRY glGetNamedProgramLocalParameterIivEXT (GLuint program, GLenum target, GLuint index, GLint *params);\nGLAPI void APIENTRY glGetNamedProgramLocalParameterIuivEXT (GLuint program, GLenum target, GLuint index, GLuint *params);\nGLAPI void APIENTRY glEnableClientStateiEXT (GLenum array, GLuint index);\nGLAPI void APIENTRY glDisableClientStateiEXT (GLenum array, GLuint index);\nGLAPI void APIENTRY glGetFloati_vEXT (GLenum pname, GLuint index, GLfloat *params);\nGLAPI void APIENTRY glGetDoublei_vEXT (GLenum pname, GLuint index, GLdouble *params);\nGLAPI void APIENTRY glGetPointeri_vEXT (GLenum pname, GLuint index, void **params);\nGLAPI void APIENTRY glNamedProgramStringEXT (GLuint program, GLenum target, GLenum format, GLsizei len, const void *string);\nGLAPI void APIENTRY glNamedProgramLocalParameter4dEXT (GLuint program, GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glNamedProgramLocalParameter4dvEXT (GLuint program, GLenum target, GLuint index, const GLdouble *params);\nGLAPI void APIENTRY glNamedProgramLocalParameter4fEXT (GLuint program, GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glNamedProgramLocalParameter4fvEXT (GLuint program, GLenum target, GLuint index, const GLfloat *params);\nGLAPI void APIENTRY glGetNamedProgramLocalParameterdvEXT (GLuint program, GLenum target, GLuint index, GLdouble *params);\nGLAPI void APIENTRY glGetNamedProgramLocalParameterfvEXT (GLuint program, GLenum target, GLuint index, GLfloat *params);\nGLAPI void APIENTRY glGetNamedProgramivEXT (GLuint program, GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetNamedProgramStringEXT (GLuint program, GLenum target, GLenum pname, void *string);\nGLAPI void APIENTRY glNamedRenderbufferStorageEXT (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glGetNamedRenderbufferParameterivEXT (GLuint renderbuffer, GLenum pname, GLint *params);\nGLAPI void APIENTRY glNamedRenderbufferStorageMultisampleEXT (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glNamedRenderbufferStorageMultisampleCoverageEXT (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI GLenum APIENTRY glCheckNamedFramebufferStatusEXT (GLuint framebuffer, GLenum target);\nGLAPI void APIENTRY glNamedFramebufferTexture1DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\nGLAPI void APIENTRY glNamedFramebufferTexture2DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\nGLAPI void APIENTRY glNamedFramebufferTexture3DEXT (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\nGLAPI void APIENTRY glNamedFramebufferRenderbufferEXT (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\nGLAPI void APIENTRY glGetNamedFramebufferAttachmentParameterivEXT (GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGenerateTextureMipmapEXT (GLuint texture, GLenum target);\nGLAPI void APIENTRY glGenerateMultiTexMipmapEXT (GLenum texunit, GLenum target);\nGLAPI void APIENTRY glFramebufferDrawBufferEXT (GLuint framebuffer, GLenum mode);\nGLAPI void APIENTRY glFramebufferDrawBuffersEXT (GLuint framebuffer, GLsizei n, const GLenum *bufs);\nGLAPI void APIENTRY glFramebufferReadBufferEXT (GLuint framebuffer, GLenum mode);\nGLAPI void APIENTRY glGetFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params);\nGLAPI void APIENTRY glNamedCopyBufferSubDataEXT (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\nGLAPI void APIENTRY glNamedFramebufferTextureEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level);\nGLAPI void APIENTRY glNamedFramebufferTextureLayerEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer);\nGLAPI void APIENTRY glNamedFramebufferTextureFaceEXT (GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLenum face);\nGLAPI void APIENTRY glTextureRenderbufferEXT (GLuint texture, GLenum target, GLuint renderbuffer);\nGLAPI void APIENTRY glMultiTexRenderbufferEXT (GLenum texunit, GLenum target, GLuint renderbuffer);\nGLAPI void APIENTRY glVertexArrayVertexOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glVertexArrayColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glVertexArrayEdgeFlagOffsetEXT (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glVertexArrayIndexOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glVertexArrayNormalOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glVertexArrayTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glVertexArrayMultiTexCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum texunit, GLint size, GLenum type, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glVertexArrayFogCoordOffsetEXT (GLuint vaobj, GLuint buffer, GLenum type, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glVertexArraySecondaryColorOffsetEXT (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glVertexArrayVertexAttribOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glVertexArrayVertexAttribIOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glEnableVertexArrayEXT (GLuint vaobj, GLenum array);\nGLAPI void APIENTRY glDisableVertexArrayEXT (GLuint vaobj, GLenum array);\nGLAPI void APIENTRY glEnableVertexArrayAttribEXT (GLuint vaobj, GLuint index);\nGLAPI void APIENTRY glDisableVertexArrayAttribEXT (GLuint vaobj, GLuint index);\nGLAPI void APIENTRY glGetVertexArrayIntegervEXT (GLuint vaobj, GLenum pname, GLint *param);\nGLAPI void APIENTRY glGetVertexArrayPointervEXT (GLuint vaobj, GLenum pname, void **param);\nGLAPI void APIENTRY glGetVertexArrayIntegeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, GLint *param);\nGLAPI void APIENTRY glGetVertexArrayPointeri_vEXT (GLuint vaobj, GLuint index, GLenum pname, void **param);\nGLAPI void *APIENTRY glMapNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);\nGLAPI void APIENTRY glFlushMappedNamedBufferRangeEXT (GLuint buffer, GLintptr offset, GLsizeiptr length);\nGLAPI void APIENTRY glNamedBufferStorageEXT (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);\nGLAPI void APIENTRY glClearNamedBufferDataEXT (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);\nGLAPI void APIENTRY glClearNamedBufferSubDataEXT (GLuint buffer, GLenum internalformat, GLsizeiptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);\nGLAPI void APIENTRY glNamedFramebufferParameteriEXT (GLuint framebuffer, GLenum pname, GLint param);\nGLAPI void APIENTRY glGetNamedFramebufferParameterivEXT (GLuint framebuffer, GLenum pname, GLint *params);\nGLAPI void APIENTRY glProgramUniform1dEXT (GLuint program, GLint location, GLdouble x);\nGLAPI void APIENTRY glProgramUniform2dEXT (GLuint program, GLint location, GLdouble x, GLdouble y);\nGLAPI void APIENTRY glProgramUniform3dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glProgramUniform4dEXT (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glProgramUniform1dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniform2dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniform3dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniform4dvEXT (GLuint program, GLint location, GLsizei count, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix2x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix2x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix3x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix3x4dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix4x2dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glProgramUniformMatrix4x3dvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value);\nGLAPI void APIENTRY glTextureBufferRangeEXT (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI void APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\nGLAPI void APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\nGLAPI void APIENTRY glTextureStorage2DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\nGLAPI void APIENTRY glTextureStorage3DMultisampleEXT (GLuint texture, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\nGLAPI void APIENTRY glVertexArrayBindVertexBufferEXT (GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);\nGLAPI void APIENTRY glVertexArrayVertexAttribFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);\nGLAPI void APIENTRY glVertexArrayVertexAttribIFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\nGLAPI void APIENTRY glVertexArrayVertexAttribLFormatEXT (GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);\nGLAPI void APIENTRY glVertexArrayVertexAttribBindingEXT (GLuint vaobj, GLuint attribindex, GLuint bindingindex);\nGLAPI void APIENTRY glVertexArrayVertexBindingDivisorEXT (GLuint vaobj, GLuint bindingindex, GLuint divisor);\nGLAPI void APIENTRY glVertexArrayVertexAttribLOffsetEXT (GLuint vaobj, GLuint buffer, GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);\nGLAPI void APIENTRY glTexturePageCommitmentEXT (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit);\nGLAPI void APIENTRY glVertexArrayVertexAttribDivisorEXT (GLuint vaobj, GLuint index, GLuint divisor);\n#endif\n#endif /* GL_EXT_direct_state_access */\n\n#ifndef GL_EXT_draw_buffers2\n#define GL_EXT_draw_buffers2 1\ntypedef void (APIENTRYP PFNGLCOLORMASKINDEXEDEXTPROC) (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorMaskIndexedEXT (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\n#endif\n#endif /* GL_EXT_draw_buffers2 */\n\n#ifndef GL_EXT_draw_instanced\n#define GL_EXT_draw_instanced 1\ntypedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount);\ntypedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawArraysInstancedEXT (GLenum mode, GLint start, GLsizei count, GLsizei primcount);\nGLAPI void APIENTRY glDrawElementsInstancedEXT (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);\n#endif\n#endif /* GL_EXT_draw_instanced */\n\n#ifndef GL_EXT_draw_range_elements\n#define GL_EXT_draw_range_elements 1\n#define GL_MAX_ELEMENTS_VERTICES_EXT      0x80E8\n#define GL_MAX_ELEMENTS_INDICES_EXT       0x80E9\ntypedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSEXTPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawRangeElementsEXT (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices);\n#endif\n#endif /* GL_EXT_draw_range_elements */\n\n#ifndef GL_EXT_external_buffer\n#define GL_EXT_external_buffer 1\ntypedef void *GLeglClientBufferEXT;\ntypedef void (APIENTRYP PFNGLBUFFERSTORAGEEXTERNALEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEEXTERNALEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBufferStorageExternalEXT (GLenum target, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);\nGLAPI void APIENTRY glNamedBufferStorageExternalEXT (GLuint buffer, GLintptr offset, GLsizeiptr size, GLeglClientBufferEXT clientBuffer, GLbitfield flags);\n#endif\n#endif /* GL_EXT_external_buffer */\n\n#ifndef GL_EXT_fog_coord\n#define GL_EXT_fog_coord 1\n#define GL_FOG_COORDINATE_SOURCE_EXT      0x8450\n#define GL_FOG_COORDINATE_EXT             0x8451\n#define GL_FRAGMENT_DEPTH_EXT             0x8452\n#define GL_CURRENT_FOG_COORDINATE_EXT     0x8453\n#define GL_FOG_COORDINATE_ARRAY_TYPE_EXT  0x8454\n#define GL_FOG_COORDINATE_ARRAY_STRIDE_EXT 0x8455\n#define GL_FOG_COORDINATE_ARRAY_POINTER_EXT 0x8456\n#define GL_FOG_COORDINATE_ARRAY_EXT       0x8457\ntypedef void (APIENTRYP PFNGLFOGCOORDFEXTPROC) (GLfloat coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDFVEXTPROC) (const GLfloat *coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDDEXTPROC) (GLdouble coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDDVEXTPROC) (const GLdouble *coord);\ntypedef void (APIENTRYP PFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, const void *pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFogCoordfEXT (GLfloat coord);\nGLAPI void APIENTRY glFogCoordfvEXT (const GLfloat *coord);\nGLAPI void APIENTRY glFogCoorddEXT (GLdouble coord);\nGLAPI void APIENTRY glFogCoorddvEXT (const GLdouble *coord);\nGLAPI void APIENTRY glFogCoordPointerEXT (GLenum type, GLsizei stride, const void *pointer);\n#endif\n#endif /* GL_EXT_fog_coord */\n\n#ifndef GL_EXT_framebuffer_blit\n#define GL_EXT_framebuffer_blit 1\n#define GL_READ_FRAMEBUFFER_EXT           0x8CA8\n#define GL_DRAW_FRAMEBUFFER_EXT           0x8CA9\n#define GL_DRAW_FRAMEBUFFER_BINDING_EXT   0x8CA6\n#define GL_READ_FRAMEBUFFER_BINDING_EXT   0x8CAA\ntypedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\n#endif\n#endif /* GL_EXT_framebuffer_blit */\n\n#ifndef GL_EXT_framebuffer_multisample\n#define GL_EXT_framebuffer_multisample 1\n#define GL_RENDERBUFFER_SAMPLES_EXT       0x8CAB\n#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56\n#define GL_MAX_SAMPLES_EXT                0x8D57\ntypedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\n#endif\n#endif /* GL_EXT_framebuffer_multisample */\n\n#ifndef GL_EXT_framebuffer_multisample_blit_scaled\n#define GL_EXT_framebuffer_multisample_blit_scaled 1\n#define GL_SCALED_RESOLVE_FASTEST_EXT     0x90BA\n#define GL_SCALED_RESOLVE_NICEST_EXT      0x90BB\n#endif /* GL_EXT_framebuffer_multisample_blit_scaled */\n\n#ifndef GL_EXT_framebuffer_object\n#define GL_EXT_framebuffer_object 1\n#define GL_INVALID_FRAMEBUFFER_OPERATION_EXT 0x0506\n#define GL_MAX_RENDERBUFFER_SIZE_EXT      0x84E8\n#define GL_FRAMEBUFFER_BINDING_EXT        0x8CA6\n#define GL_RENDERBUFFER_BINDING_EXT       0x8CA7\n#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT 0x8CD0\n#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT 0x8CD1\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT 0x8CD2\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT 0x8CD3\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT 0x8CD4\n#define GL_FRAMEBUFFER_COMPLETE_EXT       0x8CD5\n#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6\n#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7\n#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9\n#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA\n#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB\n#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC\n#define GL_FRAMEBUFFER_UNSUPPORTED_EXT    0x8CDD\n#define GL_MAX_COLOR_ATTACHMENTS_EXT      0x8CDF\n#define GL_COLOR_ATTACHMENT0_EXT          0x8CE0\n#define GL_COLOR_ATTACHMENT1_EXT          0x8CE1\n#define GL_COLOR_ATTACHMENT2_EXT          0x8CE2\n#define GL_COLOR_ATTACHMENT3_EXT          0x8CE3\n#define GL_COLOR_ATTACHMENT4_EXT          0x8CE4\n#define GL_COLOR_ATTACHMENT5_EXT          0x8CE5\n#define GL_COLOR_ATTACHMENT6_EXT          0x8CE6\n#define GL_COLOR_ATTACHMENT7_EXT          0x8CE7\n#define GL_COLOR_ATTACHMENT8_EXT          0x8CE8\n#define GL_COLOR_ATTACHMENT9_EXT          0x8CE9\n#define GL_COLOR_ATTACHMENT10_EXT         0x8CEA\n#define GL_COLOR_ATTACHMENT11_EXT         0x8CEB\n#define GL_COLOR_ATTACHMENT12_EXT         0x8CEC\n#define GL_COLOR_ATTACHMENT13_EXT         0x8CED\n#define GL_COLOR_ATTACHMENT14_EXT         0x8CEE\n#define GL_COLOR_ATTACHMENT15_EXT         0x8CEF\n#define GL_DEPTH_ATTACHMENT_EXT           0x8D00\n#define GL_STENCIL_ATTACHMENT_EXT         0x8D20\n#define GL_FRAMEBUFFER_EXT                0x8D40\n#define GL_RENDERBUFFER_EXT               0x8D41\n#define GL_RENDERBUFFER_WIDTH_EXT         0x8D42\n#define GL_RENDERBUFFER_HEIGHT_EXT        0x8D43\n#define GL_RENDERBUFFER_INTERNAL_FORMAT_EXT 0x8D44\n#define GL_STENCIL_INDEX1_EXT             0x8D46\n#define GL_STENCIL_INDEX4_EXT             0x8D47\n#define GL_STENCIL_INDEX8_EXT             0x8D48\n#define GL_STENCIL_INDEX16_EXT            0x8D49\n#define GL_RENDERBUFFER_RED_SIZE_EXT      0x8D50\n#define GL_RENDERBUFFER_GREEN_SIZE_EXT    0x8D51\n#define GL_RENDERBUFFER_BLUE_SIZE_EXT     0x8D52\n#define GL_RENDERBUFFER_ALPHA_SIZE_EXT    0x8D53\n#define GL_RENDERBUFFER_DEPTH_SIZE_EXT    0x8D54\n#define GL_RENDERBUFFER_STENCIL_SIZE_EXT  0x8D55\ntypedef GLboolean (APIENTRYP PFNGLISRENDERBUFFEREXTPROC) (GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);\ntypedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);\ntypedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);\ntypedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);\ntypedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);\ntypedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);\ntypedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\ntypedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLboolean APIENTRY glIsRenderbufferEXT (GLuint renderbuffer);\nGLAPI void APIENTRY glBindRenderbufferEXT (GLenum target, GLuint renderbuffer);\nGLAPI void APIENTRY glDeleteRenderbuffersEXT (GLsizei n, const GLuint *renderbuffers);\nGLAPI void APIENTRY glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers);\nGLAPI void APIENTRY glRenderbufferStorageEXT (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params);\nGLAPI GLboolean APIENTRY glIsFramebufferEXT (GLuint framebuffer);\nGLAPI void APIENTRY glBindFramebufferEXT (GLenum target, GLuint framebuffer);\nGLAPI void APIENTRY glDeleteFramebuffersEXT (GLsizei n, const GLuint *framebuffers);\nGLAPI void APIENTRY glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers);\nGLAPI GLenum APIENTRY glCheckFramebufferStatusEXT (GLenum target);\nGLAPI void APIENTRY glFramebufferTexture1DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\nGLAPI void APIENTRY glFramebufferTexture2DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\nGLAPI void APIENTRY glFramebufferTexture3DEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\nGLAPI void APIENTRY glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\nGLAPI void APIENTRY glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum attachment, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGenerateMipmapEXT (GLenum target);\n#endif\n#endif /* GL_EXT_framebuffer_object */\n\n#ifndef GL_EXT_framebuffer_sRGB\n#define GL_EXT_framebuffer_sRGB 1\n#define GL_FRAMEBUFFER_SRGB_EXT           0x8DB9\n#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT   0x8DBA\n#endif /* GL_EXT_framebuffer_sRGB */\n\n#ifndef GL_EXT_geometry_shader4\n#define GL_EXT_geometry_shader4 1\n#define GL_GEOMETRY_SHADER_EXT            0x8DD9\n#define GL_GEOMETRY_VERTICES_OUT_EXT      0x8DDA\n#define GL_GEOMETRY_INPUT_TYPE_EXT        0x8DDB\n#define GL_GEOMETRY_OUTPUT_TYPE_EXT       0x8DDC\n#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_EXT 0x8C29\n#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_EXT 0x8DDD\n#define GL_MAX_VERTEX_VARYING_COMPONENTS_EXT 0x8DDE\n#define GL_MAX_VARYING_COMPONENTS_EXT     0x8B4B\n#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_EXT 0x8DDF\n#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT 0x8DE0\n#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_EXT 0x8DE1\n#define GL_LINES_ADJACENCY_EXT            0x000A\n#define GL_LINE_STRIP_ADJACENCY_EXT       0x000B\n#define GL_TRIANGLES_ADJACENCY_EXT        0x000C\n#define GL_TRIANGLE_STRIP_ADJACENCY_EXT   0x000D\n#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_EXT 0x8DA8\n#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_EXT 0x8DA9\n#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT 0x8DA7\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT 0x8CD4\n#define GL_PROGRAM_POINT_SIZE_EXT         0x8642\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value);\n#endif\n#endif /* GL_EXT_geometry_shader4 */\n\n#ifndef GL_EXT_gpu_program_parameters\n#define GL_EXT_gpu_program_parameters 1\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProgramEnvParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params);\nGLAPI void APIENTRY glProgramLocalParameters4fvEXT (GLenum target, GLuint index, GLsizei count, const GLfloat *params);\n#endif\n#endif /* GL_EXT_gpu_program_parameters */\n\n#ifndef GL_EXT_gpu_shader4\n#define GL_EXT_gpu_shader4 1\n#define GL_SAMPLER_1D_ARRAY_EXT           0x8DC0\n#define GL_SAMPLER_2D_ARRAY_EXT           0x8DC1\n#define GL_SAMPLER_BUFFER_EXT             0x8DC2\n#define GL_SAMPLER_1D_ARRAY_SHADOW_EXT    0x8DC3\n#define GL_SAMPLER_2D_ARRAY_SHADOW_EXT    0x8DC4\n#define GL_SAMPLER_CUBE_SHADOW_EXT        0x8DC5\n#define GL_UNSIGNED_INT_VEC2_EXT          0x8DC6\n#define GL_UNSIGNED_INT_VEC3_EXT          0x8DC7\n#define GL_UNSIGNED_INT_VEC4_EXT          0x8DC8\n#define GL_INT_SAMPLER_1D_EXT             0x8DC9\n#define GL_INT_SAMPLER_2D_EXT             0x8DCA\n#define GL_INT_SAMPLER_3D_EXT             0x8DCB\n#define GL_INT_SAMPLER_CUBE_EXT           0x8DCC\n#define GL_INT_SAMPLER_2D_RECT_EXT        0x8DCD\n#define GL_INT_SAMPLER_1D_ARRAY_EXT       0x8DCE\n#define GL_INT_SAMPLER_2D_ARRAY_EXT       0x8DCF\n#define GL_INT_SAMPLER_BUFFER_EXT         0x8DD0\n#define GL_UNSIGNED_INT_SAMPLER_1D_EXT    0x8DD1\n#define GL_UNSIGNED_INT_SAMPLER_2D_EXT    0x8DD2\n#define GL_UNSIGNED_INT_SAMPLER_3D_EXT    0x8DD3\n#define GL_UNSIGNED_INT_SAMPLER_CUBE_EXT  0x8DD4\n#define GL_UNSIGNED_INT_SAMPLER_2D_RECT_EXT 0x8DD5\n#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY_EXT 0x8DD6\n#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY_EXT 0x8DD7\n#define GL_UNSIGNED_INT_SAMPLER_BUFFER_EXT 0x8DD8\n#define GL_MIN_PROGRAM_TEXEL_OFFSET_EXT   0x8904\n#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT   0x8905\n#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_EXT 0x88FD\ntypedef void (APIENTRYP PFNGLGETUNIFORMUIVEXTPROC) (GLuint program, GLint location, GLuint *params);\ntypedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONEXTPROC) (GLuint program, GLuint color, const GLchar *name);\ntypedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONEXTPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP PFNGLUNIFORM1UIEXTPROC) (GLint location, GLuint v0);\ntypedef void (APIENTRYP PFNGLUNIFORM2UIEXTPROC) (GLint location, GLuint v0, GLuint v1);\ntypedef void (APIENTRYP PFNGLUNIFORM3UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2);\ntypedef void (APIENTRYP PFNGLUNIFORM4UIEXTPROC) (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\ntypedef void (APIENTRYP PFNGLUNIFORM1UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM2UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM3UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLUNIFORM4UIVEXTPROC) (GLint location, GLsizei count, const GLuint *value);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1IEXTPROC) (GLuint index, GLint x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2IEXTPROC) (GLuint index, GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3IEXTPROC) (GLuint index, GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4IEXTPROC) (GLuint index, GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIEXTPROC) (GLuint index, GLuint x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIEXTPROC) (GLuint index, GLuint x, GLuint y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIEXTPROC) (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVEXTPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVEXTPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVEXTPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVEXTPROC) (GLuint index, const GLint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVEXTPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVEXTPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVEXTPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVEXTPROC) (GLuint index, const GLuint *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVEXTPROC) (GLuint index, const GLbyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVEXTPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVEXTPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVEXTPROC) (GLuint index, const GLushort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVEXTPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVEXTPROC) (GLuint index, GLenum pname, GLuint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetUniformuivEXT (GLuint program, GLint location, GLuint *params);\nGLAPI void APIENTRY glBindFragDataLocationEXT (GLuint program, GLuint color, const GLchar *name);\nGLAPI GLint APIENTRY glGetFragDataLocationEXT (GLuint program, const GLchar *name);\nGLAPI void APIENTRY glUniform1uiEXT (GLint location, GLuint v0);\nGLAPI void APIENTRY glUniform2uiEXT (GLint location, GLuint v0, GLuint v1);\nGLAPI void APIENTRY glUniform3uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2);\nGLAPI void APIENTRY glUniform4uiEXT (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\nGLAPI void APIENTRY glUniform1uivEXT (GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glUniform2uivEXT (GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glUniform3uivEXT (GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glUniform4uivEXT (GLint location, GLsizei count, const GLuint *value);\nGLAPI void APIENTRY glVertexAttribI1iEXT (GLuint index, GLint x);\nGLAPI void APIENTRY glVertexAttribI2iEXT (GLuint index, GLint x, GLint y);\nGLAPI void APIENTRY glVertexAttribI3iEXT (GLuint index, GLint x, GLint y, GLint z);\nGLAPI void APIENTRY glVertexAttribI4iEXT (GLuint index, GLint x, GLint y, GLint z, GLint w);\nGLAPI void APIENTRY glVertexAttribI1uiEXT (GLuint index, GLuint x);\nGLAPI void APIENTRY glVertexAttribI2uiEXT (GLuint index, GLuint x, GLuint y);\nGLAPI void APIENTRY glVertexAttribI3uiEXT (GLuint index, GLuint x, GLuint y, GLuint z);\nGLAPI void APIENTRY glVertexAttribI4uiEXT (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\nGLAPI void APIENTRY glVertexAttribI1ivEXT (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttribI2ivEXT (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttribI3ivEXT (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttribI4ivEXT (GLuint index, const GLint *v);\nGLAPI void APIENTRY glVertexAttribI1uivEXT (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttribI2uivEXT (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttribI3uivEXT (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttribI4uivEXT (GLuint index, const GLuint *v);\nGLAPI void APIENTRY glVertexAttribI4bvEXT (GLuint index, const GLbyte *v);\nGLAPI void APIENTRY glVertexAttribI4svEXT (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttribI4ubvEXT (GLuint index, const GLubyte *v);\nGLAPI void APIENTRY glVertexAttribI4usvEXT (GLuint index, const GLushort *v);\nGLAPI void APIENTRY glVertexAttribIPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glGetVertexAttribIivEXT (GLuint index, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetVertexAttribIuivEXT (GLuint index, GLenum pname, GLuint *params);\n#endif\n#endif /* GL_EXT_gpu_shader4 */\n\n#ifndef GL_EXT_histogram\n#define GL_EXT_histogram 1\n#define GL_HISTOGRAM_EXT                  0x8024\n#define GL_PROXY_HISTOGRAM_EXT            0x8025\n#define GL_HISTOGRAM_WIDTH_EXT            0x8026\n#define GL_HISTOGRAM_FORMAT_EXT           0x8027\n#define GL_HISTOGRAM_RED_SIZE_EXT         0x8028\n#define GL_HISTOGRAM_GREEN_SIZE_EXT       0x8029\n#define GL_HISTOGRAM_BLUE_SIZE_EXT        0x802A\n#define GL_HISTOGRAM_ALPHA_SIZE_EXT       0x802B\n#define GL_HISTOGRAM_LUMINANCE_SIZE_EXT   0x802C\n#define GL_HISTOGRAM_SINK_EXT             0x802D\n#define GL_MINMAX_EXT                     0x802E\n#define GL_MINMAX_FORMAT_EXT              0x802F\n#define GL_MINMAX_SINK_EXT                0x8030\n#define GL_TABLE_TOO_LARGE_EXT            0x8031\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);\ntypedef void (APIENTRYP PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);\ntypedef void (APIENTRYP PFNGLMINMAXEXTPROC) (GLenum target, GLenum internalformat, GLboolean sink);\ntypedef void (APIENTRYP PFNGLRESETHISTOGRAMEXTPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLRESETMINMAXEXTPROC) (GLenum target);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetHistogramEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);\nGLAPI void APIENTRY glGetHistogramParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetHistogramParameterivEXT (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetMinmaxEXT (GLenum target, GLboolean reset, GLenum format, GLenum type, void *values);\nGLAPI void APIENTRY glGetMinmaxParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetMinmaxParameterivEXT (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glHistogramEXT (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink);\nGLAPI void APIENTRY glMinmaxEXT (GLenum target, GLenum internalformat, GLboolean sink);\nGLAPI void APIENTRY glResetHistogramEXT (GLenum target);\nGLAPI void APIENTRY glResetMinmaxEXT (GLenum target);\n#endif\n#endif /* GL_EXT_histogram */\n\n#ifndef GL_EXT_index_array_formats\n#define GL_EXT_index_array_formats 1\n#define GL_IUI_V2F_EXT                    0x81AD\n#define GL_IUI_V3F_EXT                    0x81AE\n#define GL_IUI_N3F_V2F_EXT                0x81AF\n#define GL_IUI_N3F_V3F_EXT                0x81B0\n#define GL_T2F_IUI_V2F_EXT                0x81B1\n#define GL_T2F_IUI_V3F_EXT                0x81B2\n#define GL_T2F_IUI_N3F_V2F_EXT            0x81B3\n#define GL_T2F_IUI_N3F_V3F_EXT            0x81B4\n#endif /* GL_EXT_index_array_formats */\n\n#ifndef GL_EXT_index_func\n#define GL_EXT_index_func 1\n#define GL_INDEX_TEST_EXT                 0x81B5\n#define GL_INDEX_TEST_FUNC_EXT            0x81B6\n#define GL_INDEX_TEST_REF_EXT             0x81B7\ntypedef void (APIENTRYP PFNGLINDEXFUNCEXTPROC) (GLenum func, GLclampf ref);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glIndexFuncEXT (GLenum func, GLclampf ref);\n#endif\n#endif /* GL_EXT_index_func */\n\n#ifndef GL_EXT_index_material\n#define GL_EXT_index_material 1\n#define GL_INDEX_MATERIAL_EXT             0x81B8\n#define GL_INDEX_MATERIAL_PARAMETER_EXT   0x81B9\n#define GL_INDEX_MATERIAL_FACE_EXT        0x81BA\ntypedef void (APIENTRYP PFNGLINDEXMATERIALEXTPROC) (GLenum face, GLenum mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glIndexMaterialEXT (GLenum face, GLenum mode);\n#endif\n#endif /* GL_EXT_index_material */\n\n#ifndef GL_EXT_index_texture\n#define GL_EXT_index_texture 1\n#endif /* GL_EXT_index_texture */\n\n#ifndef GL_EXT_light_texture\n#define GL_EXT_light_texture 1\n#define GL_FRAGMENT_MATERIAL_EXT          0x8349\n#define GL_FRAGMENT_NORMAL_EXT            0x834A\n#define GL_FRAGMENT_COLOR_EXT             0x834C\n#define GL_ATTENUATION_EXT                0x834D\n#define GL_SHADOW_ATTENUATION_EXT         0x834E\n#define GL_TEXTURE_APPLICATION_MODE_EXT   0x834F\n#define GL_TEXTURE_LIGHT_EXT              0x8350\n#define GL_TEXTURE_MATERIAL_FACE_EXT      0x8351\n#define GL_TEXTURE_MATERIAL_PARAMETER_EXT 0x8352\ntypedef void (APIENTRYP PFNGLAPPLYTEXTUREEXTPROC) (GLenum mode);\ntypedef void (APIENTRYP PFNGLTEXTURELIGHTEXTPROC) (GLenum pname);\ntypedef void (APIENTRYP PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glApplyTextureEXT (GLenum mode);\nGLAPI void APIENTRY glTextureLightEXT (GLenum pname);\nGLAPI void APIENTRY glTextureMaterialEXT (GLenum face, GLenum mode);\n#endif\n#endif /* GL_EXT_light_texture */\n\n#ifndef GL_EXT_memory_object\n#define GL_EXT_memory_object 1\n#define GL_TEXTURE_TILING_EXT             0x9580\n#define GL_DEDICATED_MEMORY_OBJECT_EXT    0x9581\n#define GL_PROTECTED_MEMORY_OBJECT_EXT    0x959B\n#define GL_NUM_TILING_TYPES_EXT           0x9582\n#define GL_TILING_TYPES_EXT               0x9583\n#define GL_OPTIMAL_TILING_EXT             0x9584\n#define GL_LINEAR_TILING_EXT              0x9585\n#define GL_NUM_DEVICE_UUIDS_EXT           0x9596\n#define GL_DEVICE_UUID_EXT                0x9597\n#define GL_DRIVER_UUID_EXT                0x9598\n#define GL_UUID_SIZE_EXT                  16\ntypedef void (APIENTRYP PFNGLGETUNSIGNEDBYTEVEXTPROC) (GLenum pname, GLubyte *data);\ntypedef void (APIENTRYP PFNGLGETUNSIGNEDBYTEI_VEXTPROC) (GLenum target, GLuint index, GLubyte *data);\ntypedef void (APIENTRYP PFNGLDELETEMEMORYOBJECTSEXTPROC) (GLsizei n, const GLuint *memoryObjects);\ntypedef GLboolean (APIENTRYP PFNGLISMEMORYOBJECTEXTPROC) (GLuint memoryObject);\ntypedef void (APIENTRYP PFNGLCREATEMEMORYOBJECTSEXTPROC) (GLsizei n, GLuint *memoryObjects);\ntypedef void (APIENTRYP PFNGLMEMORYOBJECTPARAMETERIVEXTPROC) (GLuint memoryObject, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC) (GLuint memoryObject, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLTEXSTORAGEMEM2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLTEXSTORAGEMEM3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLBUFFERSTORAGEMEMEXTPROC) (GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM2DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC) (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM3DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC) (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC) (GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLTEXSTORAGEMEM1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLTEXTURESTORAGEMEM1DEXTPROC) (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetUnsignedBytevEXT (GLenum pname, GLubyte *data);\nGLAPI void APIENTRY glGetUnsignedBytei_vEXT (GLenum target, GLuint index, GLubyte *data);\nGLAPI void APIENTRY glDeleteMemoryObjectsEXT (GLsizei n, const GLuint *memoryObjects);\nGLAPI GLboolean APIENTRY glIsMemoryObjectEXT (GLuint memoryObject);\nGLAPI void APIENTRY glCreateMemoryObjectsEXT (GLsizei n, GLuint *memoryObjects);\nGLAPI void APIENTRY glMemoryObjectParameterivEXT (GLuint memoryObject, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glGetMemoryObjectParameterivEXT (GLuint memoryObject, GLenum pname, GLint *params);\nGLAPI void APIENTRY glTexStorageMem2DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glTexStorageMem2DMultisampleEXT (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glTexStorageMem3DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glTexStorageMem3DMultisampleEXT (GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glBufferStorageMemEXT (GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glTextureStorageMem2DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glTextureStorageMem2DMultisampleEXT (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glTextureStorageMem3DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glTextureStorageMem3DMultisampleEXT (GLuint texture, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glNamedBufferStorageMemEXT (GLuint buffer, GLsizeiptr size, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glTexStorageMem1DEXT (GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glTextureStorageMem1DEXT (GLuint texture, GLsizei levels, GLenum internalFormat, GLsizei width, GLuint memory, GLuint64 offset);\n#endif\n#endif /* GL_EXT_memory_object */\n\n#ifndef GL_EXT_memory_object_fd\n#define GL_EXT_memory_object_fd 1\n#define GL_HANDLE_TYPE_OPAQUE_FD_EXT      0x9586\ntypedef void (APIENTRYP PFNGLIMPORTMEMORYFDEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, GLint fd);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glImportMemoryFdEXT (GLuint memory, GLuint64 size, GLenum handleType, GLint fd);\n#endif\n#endif /* GL_EXT_memory_object_fd */\n\n#ifndef GL_EXT_memory_object_win32\n#define GL_EXT_memory_object_win32 1\n#define GL_HANDLE_TYPE_OPAQUE_WIN32_EXT   0x9587\n#define GL_HANDLE_TYPE_OPAQUE_WIN32_KMT_EXT 0x9588\n#define GL_DEVICE_LUID_EXT                0x9599\n#define GL_DEVICE_NODE_MASK_EXT           0x959A\n#define GL_LUID_SIZE_EXT                  8\n#define GL_HANDLE_TYPE_D3D12_TILEPOOL_EXT 0x9589\n#define GL_HANDLE_TYPE_D3D12_RESOURCE_EXT 0x958A\n#define GL_HANDLE_TYPE_D3D11_IMAGE_EXT    0x958B\n#define GL_HANDLE_TYPE_D3D11_IMAGE_KMT_EXT 0x958C\ntypedef void (APIENTRYP PFNGLIMPORTMEMORYWIN32HANDLEEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, void *handle);\ntypedef void (APIENTRYP PFNGLIMPORTMEMORYWIN32NAMEEXTPROC) (GLuint memory, GLuint64 size, GLenum handleType, const void *name);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glImportMemoryWin32HandleEXT (GLuint memory, GLuint64 size, GLenum handleType, void *handle);\nGLAPI void APIENTRY glImportMemoryWin32NameEXT (GLuint memory, GLuint64 size, GLenum handleType, const void *name);\n#endif\n#endif /* GL_EXT_memory_object_win32 */\n\n#ifndef GL_EXT_misc_attribute\n#define GL_EXT_misc_attribute 1\n#endif /* GL_EXT_misc_attribute */\n\n#ifndef GL_EXT_multi_draw_arrays\n#define GL_EXT_multi_draw_arrays 1\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMultiDrawArraysEXT (GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount);\nGLAPI void APIENTRY glMultiDrawElementsEXT (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount);\n#endif\n#endif /* GL_EXT_multi_draw_arrays */\n\n#ifndef GL_EXT_multisample\n#define GL_EXT_multisample 1\n#define GL_MULTISAMPLE_EXT                0x809D\n#define GL_SAMPLE_ALPHA_TO_MASK_EXT       0x809E\n#define GL_SAMPLE_ALPHA_TO_ONE_EXT        0x809F\n#define GL_SAMPLE_MASK_EXT                0x80A0\n#define GL_1PASS_EXT                      0x80A1\n#define GL_2PASS_0_EXT                    0x80A2\n#define GL_2PASS_1_EXT                    0x80A3\n#define GL_4PASS_0_EXT                    0x80A4\n#define GL_4PASS_1_EXT                    0x80A5\n#define GL_4PASS_2_EXT                    0x80A6\n#define GL_4PASS_3_EXT                    0x80A7\n#define GL_SAMPLE_BUFFERS_EXT             0x80A8\n#define GL_SAMPLES_EXT                    0x80A9\n#define GL_SAMPLE_MASK_VALUE_EXT          0x80AA\n#define GL_SAMPLE_MASK_INVERT_EXT         0x80AB\n#define GL_SAMPLE_PATTERN_EXT             0x80AC\n#define GL_MULTISAMPLE_BIT_EXT            0x20000000\ntypedef void (APIENTRYP PFNGLSAMPLEMASKEXTPROC) (GLclampf value, GLboolean invert);\ntypedef void (APIENTRYP PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSampleMaskEXT (GLclampf value, GLboolean invert);\nGLAPI void APIENTRY glSamplePatternEXT (GLenum pattern);\n#endif\n#endif /* GL_EXT_multisample */\n\n#ifndef GL_EXT_multiview_tessellation_geometry_shader\n#define GL_EXT_multiview_tessellation_geometry_shader 1\n#endif /* GL_EXT_multiview_tessellation_geometry_shader */\n\n#ifndef GL_EXT_multiview_texture_multisample\n#define GL_EXT_multiview_texture_multisample 1\n#endif /* GL_EXT_multiview_texture_multisample */\n\n#ifndef GL_EXT_multiview_timer_query\n#define GL_EXT_multiview_timer_query 1\n#endif /* GL_EXT_multiview_timer_query */\n\n#ifndef GL_EXT_packed_depth_stencil\n#define GL_EXT_packed_depth_stencil 1\n#define GL_DEPTH_STENCIL_EXT              0x84F9\n#define GL_UNSIGNED_INT_24_8_EXT          0x84FA\n#define GL_DEPTH24_STENCIL8_EXT           0x88F0\n#define GL_TEXTURE_STENCIL_SIZE_EXT       0x88F1\n#endif /* GL_EXT_packed_depth_stencil */\n\n#ifndef GL_EXT_packed_float\n#define GL_EXT_packed_float 1\n#define GL_R11F_G11F_B10F_EXT             0x8C3A\n#define GL_UNSIGNED_INT_10F_11F_11F_REV_EXT 0x8C3B\n#define GL_RGBA_SIGNED_COMPONENTS_EXT     0x8C3C\n#endif /* GL_EXT_packed_float */\n\n#ifndef GL_EXT_packed_pixels\n#define GL_EXT_packed_pixels 1\n#define GL_UNSIGNED_BYTE_3_3_2_EXT        0x8032\n#define GL_UNSIGNED_SHORT_4_4_4_4_EXT     0x8033\n#define GL_UNSIGNED_SHORT_5_5_5_1_EXT     0x8034\n#define GL_UNSIGNED_INT_8_8_8_8_EXT       0x8035\n#define GL_UNSIGNED_INT_10_10_10_2_EXT    0x8036\n#endif /* GL_EXT_packed_pixels */\n\n#ifndef GL_EXT_paletted_texture\n#define GL_EXT_paletted_texture 1\n#define GL_COLOR_INDEX1_EXT               0x80E2\n#define GL_COLOR_INDEX2_EXT               0x80E3\n#define GL_COLOR_INDEX4_EXT               0x80E4\n#define GL_COLOR_INDEX8_EXT               0x80E5\n#define GL_COLOR_INDEX12_EXT              0x80E6\n#define GL_COLOR_INDEX16_EXT              0x80E7\n#define GL_TEXTURE_INDEX_SIZE_EXT         0x80ED\ntypedef void (APIENTRYP PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, void *data);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorTableEXT (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void *table);\nGLAPI void APIENTRY glGetColorTableEXT (GLenum target, GLenum format, GLenum type, void *data);\nGLAPI void APIENTRY glGetColorTableParameterivEXT (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetColorTableParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);\n#endif\n#endif /* GL_EXT_paletted_texture */\n\n#ifndef GL_EXT_pixel_buffer_object\n#define GL_EXT_pixel_buffer_object 1\n#define GL_PIXEL_PACK_BUFFER_EXT          0x88EB\n#define GL_PIXEL_UNPACK_BUFFER_EXT        0x88EC\n#define GL_PIXEL_PACK_BUFFER_BINDING_EXT  0x88ED\n#define GL_PIXEL_UNPACK_BUFFER_BINDING_EXT 0x88EF\n#endif /* GL_EXT_pixel_buffer_object */\n\n#ifndef GL_EXT_pixel_transform\n#define GL_EXT_pixel_transform 1\n#define GL_PIXEL_TRANSFORM_2D_EXT         0x8330\n#define GL_PIXEL_MAG_FILTER_EXT           0x8331\n#define GL_PIXEL_MIN_FILTER_EXT           0x8332\n#define GL_PIXEL_CUBIC_WEIGHT_EXT         0x8333\n#define GL_CUBIC_EXT                      0x8334\n#define GL_AVERAGE_EXT                    0x8335\n#define GL_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8336\n#define GL_MAX_PIXEL_TRANSFORM_2D_STACK_DEPTH_EXT 0x8337\n#define GL_PIXEL_TRANSFORM_2D_MATRIX_EXT  0x8338\ntypedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPIXELTRANSFORMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPixelTransformParameteriEXT (GLenum target, GLenum pname, GLint param);\nGLAPI void APIENTRY glPixelTransformParameterfEXT (GLenum target, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glPixelTransformParameterivEXT (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glPixelTransformParameterfvEXT (GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glGetPixelTransformParameterivEXT (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetPixelTransformParameterfvEXT (GLenum target, GLenum pname, GLfloat *params);\n#endif\n#endif /* GL_EXT_pixel_transform */\n\n#ifndef GL_EXT_pixel_transform_color_table\n#define GL_EXT_pixel_transform_color_table 1\n#endif /* GL_EXT_pixel_transform_color_table */\n\n#ifndef GL_EXT_point_parameters\n#define GL_EXT_point_parameters 1\n#define GL_POINT_SIZE_MIN_EXT             0x8126\n#define GL_POINT_SIZE_MAX_EXT             0x8127\n#define GL_POINT_FADE_THRESHOLD_SIZE_EXT  0x8128\n#define GL_DISTANCE_ATTENUATION_EXT       0x8129\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFEXTPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFVEXTPROC) (GLenum pname, const GLfloat *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPointParameterfEXT (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glPointParameterfvEXT (GLenum pname, const GLfloat *params);\n#endif\n#endif /* GL_EXT_point_parameters */\n\n#ifndef GL_EXT_polygon_offset\n#define GL_EXT_polygon_offset 1\n#define GL_POLYGON_OFFSET_EXT             0x8037\n#define GL_POLYGON_OFFSET_FACTOR_EXT      0x8038\n#define GL_POLYGON_OFFSET_BIAS_EXT        0x8039\ntypedef void (APIENTRYP PFNGLPOLYGONOFFSETEXTPROC) (GLfloat factor, GLfloat bias);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPolygonOffsetEXT (GLfloat factor, GLfloat bias);\n#endif\n#endif /* GL_EXT_polygon_offset */\n\n#ifndef GL_EXT_polygon_offset_clamp\n#define GL_EXT_polygon_offset_clamp 1\n#define GL_POLYGON_OFFSET_CLAMP_EXT       0x8E1B\ntypedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPEXTPROC) (GLfloat factor, GLfloat units, GLfloat clamp);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPolygonOffsetClampEXT (GLfloat factor, GLfloat units, GLfloat clamp);\n#endif\n#endif /* GL_EXT_polygon_offset_clamp */\n\n#ifndef GL_EXT_post_depth_coverage\n#define GL_EXT_post_depth_coverage 1\n#endif /* GL_EXT_post_depth_coverage */\n\n#ifndef GL_EXT_provoking_vertex\n#define GL_EXT_provoking_vertex 1\n#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION_EXT 0x8E4C\n#define GL_FIRST_VERTEX_CONVENTION_EXT    0x8E4D\n#define GL_LAST_VERTEX_CONVENTION_EXT     0x8E4E\n#define GL_PROVOKING_VERTEX_EXT           0x8E4F\ntypedef void (APIENTRYP PFNGLPROVOKINGVERTEXEXTPROC) (GLenum mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProvokingVertexEXT (GLenum mode);\n#endif\n#endif /* GL_EXT_provoking_vertex */\n\n#ifndef GL_EXT_raster_multisample\n#define GL_EXT_raster_multisample 1\n#define GL_RASTER_MULTISAMPLE_EXT         0x9327\n#define GL_RASTER_SAMPLES_EXT             0x9328\n#define GL_MAX_RASTER_SAMPLES_EXT         0x9329\n#define GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT 0x932A\n#define GL_MULTISAMPLE_RASTERIZATION_ALLOWED_EXT 0x932B\n#define GL_EFFECTIVE_RASTER_SAMPLES_EXT   0x932C\ntypedef void (APIENTRYP PFNGLRASTERSAMPLESEXTPROC) (GLuint samples, GLboolean fixedsamplelocations);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glRasterSamplesEXT (GLuint samples, GLboolean fixedsamplelocations);\n#endif\n#endif /* GL_EXT_raster_multisample */\n\n#ifndef GL_EXT_rescale_normal\n#define GL_EXT_rescale_normal 1\n#define GL_RESCALE_NORMAL_EXT             0x803A\n#endif /* GL_EXT_rescale_normal */\n\n#ifndef GL_EXT_secondary_color\n#define GL_EXT_secondary_color 1\n#define GL_COLOR_SUM_EXT                  0x8458\n#define GL_CURRENT_SECONDARY_COLOR_EXT    0x8459\n#define GL_SECONDARY_COLOR_ARRAY_SIZE_EXT 0x845A\n#define GL_SECONDARY_COLOR_ARRAY_TYPE_EXT 0x845B\n#define GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT 0x845C\n#define GL_SECONDARY_COLOR_ARRAY_POINTER_EXT 0x845D\n#define GL_SECONDARY_COLOR_ARRAY_EXT      0x845E\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3BEXTPROC) (GLbyte red, GLbyte green, GLbyte blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVEXTPROC) (const GLbyte *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3DEXTPROC) (GLdouble red, GLdouble green, GLdouble blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVEXTPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3FEXTPROC) (GLfloat red, GLfloat green, GLfloat blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVEXTPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3IEXTPROC) (GLint red, GLint green, GLint blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVEXTPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3SEXTPROC) (GLshort red, GLshort green, GLshort blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVEXTPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBEXTPROC) (GLubyte red, GLubyte green, GLubyte blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVEXTPROC) (const GLubyte *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIEXTPROC) (GLuint red, GLuint green, GLuint blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVEXTPROC) (const GLuint *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3USEXTPROC) (GLushort red, GLushort green, GLushort blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVEXTPROC) (const GLushort *v);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSecondaryColor3bEXT (GLbyte red, GLbyte green, GLbyte blue);\nGLAPI void APIENTRY glSecondaryColor3bvEXT (const GLbyte *v);\nGLAPI void APIENTRY glSecondaryColor3dEXT (GLdouble red, GLdouble green, GLdouble blue);\nGLAPI void APIENTRY glSecondaryColor3dvEXT (const GLdouble *v);\nGLAPI void APIENTRY glSecondaryColor3fEXT (GLfloat red, GLfloat green, GLfloat blue);\nGLAPI void APIENTRY glSecondaryColor3fvEXT (const GLfloat *v);\nGLAPI void APIENTRY glSecondaryColor3iEXT (GLint red, GLint green, GLint blue);\nGLAPI void APIENTRY glSecondaryColor3ivEXT (const GLint *v);\nGLAPI void APIENTRY glSecondaryColor3sEXT (GLshort red, GLshort green, GLshort blue);\nGLAPI void APIENTRY glSecondaryColor3svEXT (const GLshort *v);\nGLAPI void APIENTRY glSecondaryColor3ubEXT (GLubyte red, GLubyte green, GLubyte blue);\nGLAPI void APIENTRY glSecondaryColor3ubvEXT (const GLubyte *v);\nGLAPI void APIENTRY glSecondaryColor3uiEXT (GLuint red, GLuint green, GLuint blue);\nGLAPI void APIENTRY glSecondaryColor3uivEXT (const GLuint *v);\nGLAPI void APIENTRY glSecondaryColor3usEXT (GLushort red, GLushort green, GLushort blue);\nGLAPI void APIENTRY glSecondaryColor3usvEXT (const GLushort *v);\nGLAPI void APIENTRY glSecondaryColorPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer);\n#endif\n#endif /* GL_EXT_secondary_color */\n\n#ifndef GL_EXT_semaphore\n#define GL_EXT_semaphore 1\n#define GL_LAYOUT_GENERAL_EXT             0x958D\n#define GL_LAYOUT_COLOR_ATTACHMENT_EXT    0x958E\n#define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT 0x958F\n#define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT 0x9590\n#define GL_LAYOUT_SHADER_READ_ONLY_EXT    0x9591\n#define GL_LAYOUT_TRANSFER_SRC_EXT        0x9592\n#define GL_LAYOUT_TRANSFER_DST_EXT        0x9593\n#define GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT 0x9530\n#define GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT 0x9531\ntypedef void (APIENTRYP PFNGLGENSEMAPHORESEXTPROC) (GLsizei n, GLuint *semaphores);\ntypedef void (APIENTRYP PFNGLDELETESEMAPHORESEXTPROC) (GLsizei n, const GLuint *semaphores);\ntypedef GLboolean (APIENTRYP PFNGLISSEMAPHOREEXTPROC) (GLuint semaphore);\ntypedef void (APIENTRYP PFNGLSEMAPHOREPARAMETERUI64VEXTPROC) (GLuint semaphore, GLenum pname, const GLuint64 *params);\ntypedef void (APIENTRYP PFNGLGETSEMAPHOREPARAMETERUI64VEXTPROC) (GLuint semaphore, GLenum pname, GLuint64 *params);\ntypedef void (APIENTRYP PFNGLWAITSEMAPHOREEXTPROC) (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts);\ntypedef void (APIENTRYP PFNGLSIGNALSEMAPHOREEXTPROC) (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenSemaphoresEXT (GLsizei n, GLuint *semaphores);\nGLAPI void APIENTRY glDeleteSemaphoresEXT (GLsizei n, const GLuint *semaphores);\nGLAPI GLboolean APIENTRY glIsSemaphoreEXT (GLuint semaphore);\nGLAPI void APIENTRY glSemaphoreParameterui64vEXT (GLuint semaphore, GLenum pname, const GLuint64 *params);\nGLAPI void APIENTRY glGetSemaphoreParameterui64vEXT (GLuint semaphore, GLenum pname, GLuint64 *params);\nGLAPI void APIENTRY glWaitSemaphoreEXT (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts);\nGLAPI void APIENTRY glSignalSemaphoreEXT (GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts);\n#endif\n#endif /* GL_EXT_semaphore */\n\n#ifndef GL_EXT_semaphore_fd\n#define GL_EXT_semaphore_fd 1\ntypedef void (APIENTRYP PFNGLIMPORTSEMAPHOREFDEXTPROC) (GLuint semaphore, GLenum handleType, GLint fd);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glImportSemaphoreFdEXT (GLuint semaphore, GLenum handleType, GLint fd);\n#endif\n#endif /* GL_EXT_semaphore_fd */\n\n#ifndef GL_EXT_semaphore_win32\n#define GL_EXT_semaphore_win32 1\n#define GL_HANDLE_TYPE_D3D12_FENCE_EXT    0x9594\n#define GL_D3D12_FENCE_VALUE_EXT          0x9595\ntypedef void (APIENTRYP PFNGLIMPORTSEMAPHOREWIN32HANDLEEXTPROC) (GLuint semaphore, GLenum handleType, void *handle);\ntypedef void (APIENTRYP PFNGLIMPORTSEMAPHOREWIN32NAMEEXTPROC) (GLuint semaphore, GLenum handleType, const void *name);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glImportSemaphoreWin32HandleEXT (GLuint semaphore, GLenum handleType, void *handle);\nGLAPI void APIENTRY glImportSemaphoreWin32NameEXT (GLuint semaphore, GLenum handleType, const void *name);\n#endif\n#endif /* GL_EXT_semaphore_win32 */\n\n#ifndef GL_EXT_separate_shader_objects\n#define GL_EXT_separate_shader_objects 1\n#define GL_ACTIVE_PROGRAM_EXT             0x8B8D\ntypedef void (APIENTRYP PFNGLUSESHADERPROGRAMEXTPROC) (GLenum type, GLuint program);\ntypedef void (APIENTRYP PFNGLACTIVEPROGRAMEXTPROC) (GLuint program);\ntypedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMEXTPROC) (GLenum type, const GLchar *string);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glUseShaderProgramEXT (GLenum type, GLuint program);\nGLAPI void APIENTRY glActiveProgramEXT (GLuint program);\nGLAPI GLuint APIENTRY glCreateShaderProgramEXT (GLenum type, const GLchar *string);\n#endif\n#endif /* GL_EXT_separate_shader_objects */\n\n#ifndef GL_EXT_separate_specular_color\n#define GL_EXT_separate_specular_color 1\n#define GL_LIGHT_MODEL_COLOR_CONTROL_EXT  0x81F8\n#define GL_SINGLE_COLOR_EXT               0x81F9\n#define GL_SEPARATE_SPECULAR_COLOR_EXT    0x81FA\n#endif /* GL_EXT_separate_specular_color */\n\n#ifndef GL_EXT_shader_framebuffer_fetch\n#define GL_EXT_shader_framebuffer_fetch 1\n#define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52\n#endif /* GL_EXT_shader_framebuffer_fetch */\n\n#ifndef GL_EXT_shader_framebuffer_fetch_non_coherent\n#define GL_EXT_shader_framebuffer_fetch_non_coherent 1\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFramebufferFetchBarrierEXT (void);\n#endif\n#endif /* GL_EXT_shader_framebuffer_fetch_non_coherent */\n\n#ifndef GL_EXT_shader_image_load_formatted\n#define GL_EXT_shader_image_load_formatted 1\n#endif /* GL_EXT_shader_image_load_formatted */\n\n#ifndef GL_EXT_shader_image_load_store\n#define GL_EXT_shader_image_load_store 1\n#define GL_MAX_IMAGE_UNITS_EXT            0x8F38\n#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS_EXT 0x8F39\n#define GL_IMAGE_BINDING_NAME_EXT         0x8F3A\n#define GL_IMAGE_BINDING_LEVEL_EXT        0x8F3B\n#define GL_IMAGE_BINDING_LAYERED_EXT      0x8F3C\n#define GL_IMAGE_BINDING_LAYER_EXT        0x8F3D\n#define GL_IMAGE_BINDING_ACCESS_EXT       0x8F3E\n#define GL_IMAGE_1D_EXT                   0x904C\n#define GL_IMAGE_2D_EXT                   0x904D\n#define GL_IMAGE_3D_EXT                   0x904E\n#define GL_IMAGE_2D_RECT_EXT              0x904F\n#define GL_IMAGE_CUBE_EXT                 0x9050\n#define GL_IMAGE_BUFFER_EXT               0x9051\n#define GL_IMAGE_1D_ARRAY_EXT             0x9052\n#define GL_IMAGE_2D_ARRAY_EXT             0x9053\n#define GL_IMAGE_CUBE_MAP_ARRAY_EXT       0x9054\n#define GL_IMAGE_2D_MULTISAMPLE_EXT       0x9055\n#define GL_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9056\n#define GL_INT_IMAGE_1D_EXT               0x9057\n#define GL_INT_IMAGE_2D_EXT               0x9058\n#define GL_INT_IMAGE_3D_EXT               0x9059\n#define GL_INT_IMAGE_2D_RECT_EXT          0x905A\n#define GL_INT_IMAGE_CUBE_EXT             0x905B\n#define GL_INT_IMAGE_BUFFER_EXT           0x905C\n#define GL_INT_IMAGE_1D_ARRAY_EXT         0x905D\n#define GL_INT_IMAGE_2D_ARRAY_EXT         0x905E\n#define GL_INT_IMAGE_CUBE_MAP_ARRAY_EXT   0x905F\n#define GL_INT_IMAGE_2D_MULTISAMPLE_EXT   0x9060\n#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x9061\n#define GL_UNSIGNED_INT_IMAGE_1D_EXT      0x9062\n#define GL_UNSIGNED_INT_IMAGE_2D_EXT      0x9063\n#define GL_UNSIGNED_INT_IMAGE_3D_EXT      0x9064\n#define GL_UNSIGNED_INT_IMAGE_2D_RECT_EXT 0x9065\n#define GL_UNSIGNED_INT_IMAGE_CUBE_EXT    0x9066\n#define GL_UNSIGNED_INT_IMAGE_BUFFER_EXT  0x9067\n#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY_EXT 0x9068\n#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY_EXT 0x9069\n#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY_EXT 0x906A\n#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_EXT 0x906B\n#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY_EXT 0x906C\n#define GL_MAX_IMAGE_SAMPLES_EXT          0x906D\n#define GL_IMAGE_BINDING_FORMAT_EXT       0x906E\n#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT_EXT 0x00000001\n#define GL_ELEMENT_ARRAY_BARRIER_BIT_EXT  0x00000002\n#define GL_UNIFORM_BARRIER_BIT_EXT        0x00000004\n#define GL_TEXTURE_FETCH_BARRIER_BIT_EXT  0x00000008\n#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT_EXT 0x00000020\n#define GL_COMMAND_BARRIER_BIT_EXT        0x00000040\n#define GL_PIXEL_BUFFER_BARRIER_BIT_EXT   0x00000080\n#define GL_TEXTURE_UPDATE_BARRIER_BIT_EXT 0x00000100\n#define GL_BUFFER_UPDATE_BARRIER_BIT_EXT  0x00000200\n#define GL_FRAMEBUFFER_BARRIER_BIT_EXT    0x00000400\n#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT_EXT 0x00000800\n#define GL_ATOMIC_COUNTER_BARRIER_BIT_EXT 0x00001000\n#define GL_ALL_BARRIER_BITS_EXT           0xFFFFFFFF\ntypedef void (APIENTRYP PFNGLBINDIMAGETEXTUREEXTPROC) (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format);\ntypedef void (APIENTRYP PFNGLMEMORYBARRIEREXTPROC) (GLbitfield barriers);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBindImageTextureEXT (GLuint index, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLint format);\nGLAPI void APIENTRY glMemoryBarrierEXT (GLbitfield barriers);\n#endif\n#endif /* GL_EXT_shader_image_load_store */\n\n#ifndef GL_EXT_shader_integer_mix\n#define GL_EXT_shader_integer_mix 1\n#endif /* GL_EXT_shader_integer_mix */\n\n#ifndef GL_EXT_shadow_funcs\n#define GL_EXT_shadow_funcs 1\n#endif /* GL_EXT_shadow_funcs */\n\n#ifndef GL_EXT_shared_texture_palette\n#define GL_EXT_shared_texture_palette 1\n#define GL_SHARED_TEXTURE_PALETTE_EXT     0x81FB\n#endif /* GL_EXT_shared_texture_palette */\n\n#ifndef GL_EXT_sparse_texture2\n#define GL_EXT_sparse_texture2 1\n#endif /* GL_EXT_sparse_texture2 */\n\n#ifndef GL_EXT_stencil_clear_tag\n#define GL_EXT_stencil_clear_tag 1\n#define GL_STENCIL_TAG_BITS_EXT           0x88F2\n#define GL_STENCIL_CLEAR_TAG_VALUE_EXT    0x88F3\ntypedef void (APIENTRYP PFNGLSTENCILCLEARTAGEXTPROC) (GLsizei stencilTagBits, GLuint stencilClearTag);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glStencilClearTagEXT (GLsizei stencilTagBits, GLuint stencilClearTag);\n#endif\n#endif /* GL_EXT_stencil_clear_tag */\n\n#ifndef GL_EXT_stencil_two_side\n#define GL_EXT_stencil_two_side 1\n#define GL_STENCIL_TEST_TWO_SIDE_EXT      0x8910\n#define GL_ACTIVE_STENCIL_FACE_EXT        0x8911\ntypedef void (APIENTRYP PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glActiveStencilFaceEXT (GLenum face);\n#endif\n#endif /* GL_EXT_stencil_two_side */\n\n#ifndef GL_EXT_stencil_wrap\n#define GL_EXT_stencil_wrap 1\n#define GL_INCR_WRAP_EXT                  0x8507\n#define GL_DECR_WRAP_EXT                  0x8508\n#endif /* GL_EXT_stencil_wrap */\n\n#ifndef GL_EXT_subtexture\n#define GL_EXT_subtexture 1\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexSubImage1DEXT (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTexSubImage2DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels);\n#endif\n#endif /* GL_EXT_subtexture */\n\n#ifndef GL_EXT_texture\n#define GL_EXT_texture 1\n#define GL_ALPHA4_EXT                     0x803B\n#define GL_ALPHA8_EXT                     0x803C\n#define GL_ALPHA12_EXT                    0x803D\n#define GL_ALPHA16_EXT                    0x803E\n#define GL_LUMINANCE4_EXT                 0x803F\n#define GL_LUMINANCE8_EXT                 0x8040\n#define GL_LUMINANCE12_EXT                0x8041\n#define GL_LUMINANCE16_EXT                0x8042\n#define GL_LUMINANCE4_ALPHA4_EXT          0x8043\n#define GL_LUMINANCE6_ALPHA2_EXT          0x8044\n#define GL_LUMINANCE8_ALPHA8_EXT          0x8045\n#define GL_LUMINANCE12_ALPHA4_EXT         0x8046\n#define GL_LUMINANCE12_ALPHA12_EXT        0x8047\n#define GL_LUMINANCE16_ALPHA16_EXT        0x8048\n#define GL_INTENSITY_EXT                  0x8049\n#define GL_INTENSITY4_EXT                 0x804A\n#define GL_INTENSITY8_EXT                 0x804B\n#define GL_INTENSITY12_EXT                0x804C\n#define GL_INTENSITY16_EXT                0x804D\n#define GL_RGB2_EXT                       0x804E\n#define GL_RGB4_EXT                       0x804F\n#define GL_RGB5_EXT                       0x8050\n#define GL_RGB8_EXT                       0x8051\n#define GL_RGB10_EXT                      0x8052\n#define GL_RGB12_EXT                      0x8053\n#define GL_RGB16_EXT                      0x8054\n#define GL_RGBA2_EXT                      0x8055\n#define GL_RGBA4_EXT                      0x8056\n#define GL_RGB5_A1_EXT                    0x8057\n#define GL_RGBA8_EXT                      0x8058\n#define GL_RGB10_A2_EXT                   0x8059\n#define GL_RGBA12_EXT                     0x805A\n#define GL_RGBA16_EXT                     0x805B\n#define GL_TEXTURE_RED_SIZE_EXT           0x805C\n#define GL_TEXTURE_GREEN_SIZE_EXT         0x805D\n#define GL_TEXTURE_BLUE_SIZE_EXT          0x805E\n#define GL_TEXTURE_ALPHA_SIZE_EXT         0x805F\n#define GL_TEXTURE_LUMINANCE_SIZE_EXT     0x8060\n#define GL_TEXTURE_INTENSITY_SIZE_EXT     0x8061\n#define GL_REPLACE_EXT                    0x8062\n#define GL_PROXY_TEXTURE_1D_EXT           0x8063\n#define GL_PROXY_TEXTURE_2D_EXT           0x8064\n#define GL_TEXTURE_TOO_LARGE_EXT          0x8065\n#endif /* GL_EXT_texture */\n\n#ifndef GL_EXT_texture3D\n#define GL_EXT_texture3D 1\n#define GL_PACK_SKIP_IMAGES_EXT           0x806B\n#define GL_PACK_IMAGE_HEIGHT_EXT          0x806C\n#define GL_UNPACK_SKIP_IMAGES_EXT         0x806D\n#define GL_UNPACK_IMAGE_HEIGHT_EXT        0x806E\n#define GL_TEXTURE_3D_EXT                 0x806F\n#define GL_PROXY_TEXTURE_3D_EXT           0x8070\n#define GL_TEXTURE_DEPTH_EXT              0x8071\n#define GL_TEXTURE_WRAP_R_EXT             0x8072\n#define GL_MAX_3D_TEXTURE_SIZE_EXT        0x8073\ntypedef void (APIENTRYP PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexImage3DEXT (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTexSubImage3DEXT (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels);\n#endif\n#endif /* GL_EXT_texture3D */\n\n#ifndef GL_EXT_texture_array\n#define GL_EXT_texture_array 1\n#define GL_TEXTURE_1D_ARRAY_EXT           0x8C18\n#define GL_PROXY_TEXTURE_1D_ARRAY_EXT     0x8C19\n#define GL_TEXTURE_2D_ARRAY_EXT           0x8C1A\n#define GL_PROXY_TEXTURE_2D_ARRAY_EXT     0x8C1B\n#define GL_TEXTURE_BINDING_1D_ARRAY_EXT   0x8C1C\n#define GL_TEXTURE_BINDING_2D_ARRAY_EXT   0x8C1D\n#define GL_MAX_ARRAY_TEXTURE_LAYERS_EXT   0x88FF\n#define GL_COMPARE_REF_DEPTH_TO_TEXTURE_EXT 0x884E\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYEREXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFramebufferTextureLayerEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);\n#endif\n#endif /* GL_EXT_texture_array */\n\n#ifndef GL_EXT_texture_buffer_object\n#define GL_EXT_texture_buffer_object 1\n#define GL_TEXTURE_BUFFER_EXT             0x8C2A\n#define GL_MAX_TEXTURE_BUFFER_SIZE_EXT    0x8C2B\n#define GL_TEXTURE_BINDING_BUFFER_EXT     0x8C2C\n#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING_EXT 0x8C2D\n#define GL_TEXTURE_BUFFER_FORMAT_EXT      0x8C2E\ntypedef void (APIENTRYP PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum internalformat, GLuint buffer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexBufferEXT (GLenum target, GLenum internalformat, GLuint buffer);\n#endif\n#endif /* GL_EXT_texture_buffer_object */\n\n#ifndef GL_EXT_texture_compression_latc\n#define GL_EXT_texture_compression_latc 1\n#define GL_COMPRESSED_LUMINANCE_LATC1_EXT 0x8C70\n#define GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT 0x8C71\n#define GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT 0x8C72\n#define GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT 0x8C73\n#endif /* GL_EXT_texture_compression_latc */\n\n#ifndef GL_EXT_texture_compression_rgtc\n#define GL_EXT_texture_compression_rgtc 1\n#define GL_COMPRESSED_RED_RGTC1_EXT       0x8DBB\n#define GL_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC\n#define GL_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD\n#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE\n#endif /* GL_EXT_texture_compression_rgtc */\n\n#ifndef GL_EXT_texture_compression_s3tc\n#define GL_EXT_texture_compression_s3tc 1\n#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT   0x83F0\n#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  0x83F1\n#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  0x83F2\n#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  0x83F3\n#endif /* GL_EXT_texture_compression_s3tc */\n\n#ifndef GL_EXT_texture_cube_map\n#define GL_EXT_texture_cube_map 1\n#define GL_NORMAL_MAP_EXT                 0x8511\n#define GL_REFLECTION_MAP_EXT             0x8512\n#define GL_TEXTURE_CUBE_MAP_EXT           0x8513\n#define GL_TEXTURE_BINDING_CUBE_MAP_EXT   0x8514\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A\n#define GL_PROXY_TEXTURE_CUBE_MAP_EXT     0x851B\n#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT  0x851C\n#endif /* GL_EXT_texture_cube_map */\n\n#ifndef GL_EXT_texture_env_add\n#define GL_EXT_texture_env_add 1\n#endif /* GL_EXT_texture_env_add */\n\n#ifndef GL_EXT_texture_env_combine\n#define GL_EXT_texture_env_combine 1\n#define GL_COMBINE_EXT                    0x8570\n#define GL_COMBINE_RGB_EXT                0x8571\n#define GL_COMBINE_ALPHA_EXT              0x8572\n#define GL_RGB_SCALE_EXT                  0x8573\n#define GL_ADD_SIGNED_EXT                 0x8574\n#define GL_INTERPOLATE_EXT                0x8575\n#define GL_CONSTANT_EXT                   0x8576\n#define GL_PRIMARY_COLOR_EXT              0x8577\n#define GL_PREVIOUS_EXT                   0x8578\n#define GL_SOURCE0_RGB_EXT                0x8580\n#define GL_SOURCE1_RGB_EXT                0x8581\n#define GL_SOURCE2_RGB_EXT                0x8582\n#define GL_SOURCE0_ALPHA_EXT              0x8588\n#define GL_SOURCE1_ALPHA_EXT              0x8589\n#define GL_SOURCE2_ALPHA_EXT              0x858A\n#define GL_OPERAND0_RGB_EXT               0x8590\n#define GL_OPERAND1_RGB_EXT               0x8591\n#define GL_OPERAND2_RGB_EXT               0x8592\n#define GL_OPERAND0_ALPHA_EXT             0x8598\n#define GL_OPERAND1_ALPHA_EXT             0x8599\n#define GL_OPERAND2_ALPHA_EXT             0x859A\n#endif /* GL_EXT_texture_env_combine */\n\n#ifndef GL_EXT_texture_env_dot3\n#define GL_EXT_texture_env_dot3 1\n#define GL_DOT3_RGB_EXT                   0x8740\n#define GL_DOT3_RGBA_EXT                  0x8741\n#endif /* GL_EXT_texture_env_dot3 */\n\n#ifndef GL_EXT_texture_filter_anisotropic\n#define GL_EXT_texture_filter_anisotropic 1\n#define GL_TEXTURE_MAX_ANISOTROPY_EXT     0x84FE\n#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF\n#endif /* GL_EXT_texture_filter_anisotropic */\n\n#ifndef GL_EXT_texture_filter_minmax\n#define GL_EXT_texture_filter_minmax 1\n#define GL_TEXTURE_REDUCTION_MODE_EXT     0x9366\n#define GL_WEIGHTED_AVERAGE_EXT           0x9367\n#endif /* GL_EXT_texture_filter_minmax */\n\n#ifndef GL_EXT_texture_integer\n#define GL_EXT_texture_integer 1\n#define GL_RGBA32UI_EXT                   0x8D70\n#define GL_RGB32UI_EXT                    0x8D71\n#define GL_ALPHA32UI_EXT                  0x8D72\n#define GL_INTENSITY32UI_EXT              0x8D73\n#define GL_LUMINANCE32UI_EXT              0x8D74\n#define GL_LUMINANCE_ALPHA32UI_EXT        0x8D75\n#define GL_RGBA16UI_EXT                   0x8D76\n#define GL_RGB16UI_EXT                    0x8D77\n#define GL_ALPHA16UI_EXT                  0x8D78\n#define GL_INTENSITY16UI_EXT              0x8D79\n#define GL_LUMINANCE16UI_EXT              0x8D7A\n#define GL_LUMINANCE_ALPHA16UI_EXT        0x8D7B\n#define GL_RGBA8UI_EXT                    0x8D7C\n#define GL_RGB8UI_EXT                     0x8D7D\n#define GL_ALPHA8UI_EXT                   0x8D7E\n#define GL_INTENSITY8UI_EXT               0x8D7F\n#define GL_LUMINANCE8UI_EXT               0x8D80\n#define GL_LUMINANCE_ALPHA8UI_EXT         0x8D81\n#define GL_RGBA32I_EXT                    0x8D82\n#define GL_RGB32I_EXT                     0x8D83\n#define GL_ALPHA32I_EXT                   0x8D84\n#define GL_INTENSITY32I_EXT               0x8D85\n#define GL_LUMINANCE32I_EXT               0x8D86\n#define GL_LUMINANCE_ALPHA32I_EXT         0x8D87\n#define GL_RGBA16I_EXT                    0x8D88\n#define GL_RGB16I_EXT                     0x8D89\n#define GL_ALPHA16I_EXT                   0x8D8A\n#define GL_INTENSITY16I_EXT               0x8D8B\n#define GL_LUMINANCE16I_EXT               0x8D8C\n#define GL_LUMINANCE_ALPHA16I_EXT         0x8D8D\n#define GL_RGBA8I_EXT                     0x8D8E\n#define GL_RGB8I_EXT                      0x8D8F\n#define GL_ALPHA8I_EXT                    0x8D90\n#define GL_INTENSITY8I_EXT                0x8D91\n#define GL_LUMINANCE8I_EXT                0x8D92\n#define GL_LUMINANCE_ALPHA8I_EXT          0x8D93\n#define GL_RED_INTEGER_EXT                0x8D94\n#define GL_GREEN_INTEGER_EXT              0x8D95\n#define GL_BLUE_INTEGER_EXT               0x8D96\n#define GL_ALPHA_INTEGER_EXT              0x8D97\n#define GL_RGB_INTEGER_EXT                0x8D98\n#define GL_RGBA_INTEGER_EXT               0x8D99\n#define GL_BGR_INTEGER_EXT                0x8D9A\n#define GL_BGRA_INTEGER_EXT               0x8D9B\n#define GL_LUMINANCE_INTEGER_EXT          0x8D9C\n#define GL_LUMINANCE_ALPHA_INTEGER_EXT    0x8D9D\n#define GL_RGBA_INTEGER_MODE_EXT          0x8D9E\ntypedef void (APIENTRYP PFNGLTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, const GLuint *params);\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVEXTPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVEXTPROC) (GLenum target, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLCLEARCOLORIIEXTPROC) (GLint red, GLint green, GLint blue, GLint alpha);\ntypedef void (APIENTRYP PFNGLCLEARCOLORIUIEXTPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexParameterIivEXT (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glTexParameterIuivEXT (GLenum target, GLenum pname, const GLuint *params);\nGLAPI void APIENTRY glGetTexParameterIivEXT (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetTexParameterIuivEXT (GLenum target, GLenum pname, GLuint *params);\nGLAPI void APIENTRY glClearColorIiEXT (GLint red, GLint green, GLint blue, GLint alpha);\nGLAPI void APIENTRY glClearColorIuiEXT (GLuint red, GLuint green, GLuint blue, GLuint alpha);\n#endif\n#endif /* GL_EXT_texture_integer */\n\n#ifndef GL_EXT_texture_lod_bias\n#define GL_EXT_texture_lod_bias 1\n#define GL_MAX_TEXTURE_LOD_BIAS_EXT       0x84FD\n#define GL_TEXTURE_FILTER_CONTROL_EXT     0x8500\n#define GL_TEXTURE_LOD_BIAS_EXT           0x8501\n#endif /* GL_EXT_texture_lod_bias */\n\n#ifndef GL_EXT_texture_mirror_clamp\n#define GL_EXT_texture_mirror_clamp 1\n#define GL_MIRROR_CLAMP_EXT               0x8742\n#define GL_MIRROR_CLAMP_TO_EDGE_EXT       0x8743\n#define GL_MIRROR_CLAMP_TO_BORDER_EXT     0x8912\n#endif /* GL_EXT_texture_mirror_clamp */\n\n#ifndef GL_EXT_texture_object\n#define GL_EXT_texture_object 1\n#define GL_TEXTURE_PRIORITY_EXT           0x8066\n#define GL_TEXTURE_RESIDENT_EXT           0x8067\n#define GL_TEXTURE_1D_BINDING_EXT         0x8068\n#define GL_TEXTURE_2D_BINDING_EXT         0x8069\n#define GL_TEXTURE_3D_BINDING_EXT         0x806A\ntypedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTEXTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences);\ntypedef void (APIENTRYP PFNGLBINDTEXTUREEXTPROC) (GLenum target, GLuint texture);\ntypedef void (APIENTRYP PFNGLDELETETEXTURESEXTPROC) (GLsizei n, const GLuint *textures);\ntypedef void (APIENTRYP PFNGLGENTEXTURESEXTPROC) (GLsizei n, GLuint *textures);\ntypedef GLboolean (APIENTRYP PFNGLISTEXTUREEXTPROC) (GLuint texture);\ntypedef void (APIENTRYP PFNGLPRIORITIZETEXTURESEXTPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLboolean APIENTRY glAreTexturesResidentEXT (GLsizei n, const GLuint *textures, GLboolean *residences);\nGLAPI void APIENTRY glBindTextureEXT (GLenum target, GLuint texture);\nGLAPI void APIENTRY glDeleteTexturesEXT (GLsizei n, const GLuint *textures);\nGLAPI void APIENTRY glGenTexturesEXT (GLsizei n, GLuint *textures);\nGLAPI GLboolean APIENTRY glIsTextureEXT (GLuint texture);\nGLAPI void APIENTRY glPrioritizeTexturesEXT (GLsizei n, const GLuint *textures, const GLclampf *priorities);\n#endif\n#endif /* GL_EXT_texture_object */\n\n#ifndef GL_EXT_texture_perturb_normal\n#define GL_EXT_texture_perturb_normal 1\n#define GL_PERTURB_EXT                    0x85AE\n#define GL_TEXTURE_NORMAL_EXT             0x85AF\ntypedef void (APIENTRYP PFNGLTEXTURENORMALEXTPROC) (GLenum mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTextureNormalEXT (GLenum mode);\n#endif\n#endif /* GL_EXT_texture_perturb_normal */\n\n#ifndef GL_EXT_texture_sRGB\n#define GL_EXT_texture_sRGB 1\n#define GL_SRGB_EXT                       0x8C40\n#define GL_SRGB8_EXT                      0x8C41\n#define GL_SRGB_ALPHA_EXT                 0x8C42\n#define GL_SRGB8_ALPHA8_EXT               0x8C43\n#define GL_SLUMINANCE_ALPHA_EXT           0x8C44\n#define GL_SLUMINANCE8_ALPHA8_EXT         0x8C45\n#define GL_SLUMINANCE_EXT                 0x8C46\n#define GL_SLUMINANCE8_EXT                0x8C47\n#define GL_COMPRESSED_SRGB_EXT            0x8C48\n#define GL_COMPRESSED_SRGB_ALPHA_EXT      0x8C49\n#define GL_COMPRESSED_SLUMINANCE_EXT      0x8C4A\n#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B\n#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT  0x8C4C\n#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D\n#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E\n#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F\n#endif /* GL_EXT_texture_sRGB */\n\n#ifndef GL_EXT_texture_sRGB_R8\n#define GL_EXT_texture_sRGB_R8 1\n#define GL_SR8_EXT                        0x8FBD\n#endif /* GL_EXT_texture_sRGB_R8 */\n\n#ifndef GL_EXT_texture_sRGB_RG8\n#define GL_EXT_texture_sRGB_RG8 1\n#define GL_SRG8_EXT                       0x8FBE\n#endif /* GL_EXT_texture_sRGB_RG8 */\n\n#ifndef GL_EXT_texture_sRGB_decode\n#define GL_EXT_texture_sRGB_decode 1\n#define GL_TEXTURE_SRGB_DECODE_EXT        0x8A48\n#define GL_DECODE_EXT                     0x8A49\n#define GL_SKIP_DECODE_EXT                0x8A4A\n#endif /* GL_EXT_texture_sRGB_decode */\n\n#ifndef GL_EXT_texture_shadow_lod\n#define GL_EXT_texture_shadow_lod 1\n#endif /* GL_EXT_texture_shadow_lod */\n\n#ifndef GL_EXT_texture_shared_exponent\n#define GL_EXT_texture_shared_exponent 1\n#define GL_RGB9_E5_EXT                    0x8C3D\n#define GL_UNSIGNED_INT_5_9_9_9_REV_EXT   0x8C3E\n#define GL_TEXTURE_SHARED_SIZE_EXT        0x8C3F\n#endif /* GL_EXT_texture_shared_exponent */\n\n#ifndef GL_EXT_texture_snorm\n#define GL_EXT_texture_snorm 1\n#define GL_ALPHA_SNORM                    0x9010\n#define GL_LUMINANCE_SNORM                0x9011\n#define GL_LUMINANCE_ALPHA_SNORM          0x9012\n#define GL_INTENSITY_SNORM                0x9013\n#define GL_ALPHA8_SNORM                   0x9014\n#define GL_LUMINANCE8_SNORM               0x9015\n#define GL_LUMINANCE8_ALPHA8_SNORM        0x9016\n#define GL_INTENSITY8_SNORM               0x9017\n#define GL_ALPHA16_SNORM                  0x9018\n#define GL_LUMINANCE16_SNORM              0x9019\n#define GL_LUMINANCE16_ALPHA16_SNORM      0x901A\n#define GL_INTENSITY16_SNORM              0x901B\n#define GL_RED_SNORM                      0x8F90\n#define GL_RG_SNORM                       0x8F91\n#define GL_RGB_SNORM                      0x8F92\n#define GL_RGBA_SNORM                     0x8F93\n#endif /* GL_EXT_texture_snorm */\n\n#ifndef GL_EXT_texture_storage\n#define GL_EXT_texture_storage 1\n#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT   0x912F\n#define GL_RGBA32F_EXT                    0x8814\n#define GL_RGB32F_EXT                     0x8815\n#define GL_ALPHA32F_EXT                   0x8816\n#define GL_LUMINANCE32F_EXT               0x8818\n#define GL_LUMINANCE_ALPHA32F_EXT         0x8819\n#define GL_RGBA16F_EXT                    0x881A\n#define GL_RGB16F_EXT                     0x881B\n#define GL_ALPHA16F_EXT                   0x881C\n#define GL_LUMINANCE16F_EXT               0x881E\n#define GL_LUMINANCE_ALPHA16F_EXT         0x881F\n#define GL_BGRA8_EXT                      0x93A1\n#define GL_R8_EXT                         0x8229\n#define GL_RG8_EXT                        0x822B\n#define GL_R32F_EXT                       0x822E\n#define GL_RG32F_EXT                      0x8230\n#define GL_R16F_EXT                       0x822D\n#define GL_RG16F_EXT                      0x822F\ntypedef void (APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\ntypedef void (APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);\nGLAPI void APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);\n#endif\n#endif /* GL_EXT_texture_storage */\n\n#ifndef GL_EXT_texture_swizzle\n#define GL_EXT_texture_swizzle 1\n#define GL_TEXTURE_SWIZZLE_R_EXT          0x8E42\n#define GL_TEXTURE_SWIZZLE_G_EXT          0x8E43\n#define GL_TEXTURE_SWIZZLE_B_EXT          0x8E44\n#define GL_TEXTURE_SWIZZLE_A_EXT          0x8E45\n#define GL_TEXTURE_SWIZZLE_RGBA_EXT       0x8E46\n#endif /* GL_EXT_texture_swizzle */\n\n#ifndef GL_EXT_timer_query\n#define GL_EXT_timer_query 1\n#define GL_TIME_ELAPSED_EXT               0x88BF\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VEXTPROC) (GLuint id, GLenum pname, GLint64 *params);\ntypedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VEXTPROC) (GLuint id, GLenum pname, GLuint64 *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetQueryObjecti64vEXT (GLuint id, GLenum pname, GLint64 *params);\nGLAPI void APIENTRY glGetQueryObjectui64vEXT (GLuint id, GLenum pname, GLuint64 *params);\n#endif\n#endif /* GL_EXT_timer_query */\n\n#ifndef GL_EXT_transform_feedback\n#define GL_EXT_transform_feedback 1\n#define GL_TRANSFORM_FEEDBACK_BUFFER_EXT  0x8C8E\n#define GL_TRANSFORM_FEEDBACK_BUFFER_START_EXT 0x8C84\n#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_EXT 0x8C85\n#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_EXT 0x8C8F\n#define GL_INTERLEAVED_ATTRIBS_EXT        0x8C8C\n#define GL_SEPARATE_ATTRIBS_EXT           0x8C8D\n#define GL_PRIMITIVES_GENERATED_EXT       0x8C87\n#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_EXT 0x8C88\n#define GL_RASTERIZER_DISCARD_EXT         0x8C89\n#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_EXT 0x8C8A\n#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_EXT 0x8C8B\n#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_EXT 0x8C80\n#define GL_TRANSFORM_FEEDBACK_VARYINGS_EXT 0x8C83\n#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_EXT 0x8C7F\n#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH_EXT 0x8C76\ntypedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKEXTPROC) (GLenum primitiveMode);\ntypedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void);\ntypedef void (APIENTRYP PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset);\ntypedef void (APIENTRYP PFNGLBINDBUFFERBASEEXTPROC) (GLenum target, GLuint index, GLuint buffer);\ntypedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);\ntypedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBeginTransformFeedbackEXT (GLenum primitiveMode);\nGLAPI void APIENTRY glEndTransformFeedbackEXT (void);\nGLAPI void APIENTRY glBindBufferRangeEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI void APIENTRY glBindBufferOffsetEXT (GLenum target, GLuint index, GLuint buffer, GLintptr offset);\nGLAPI void APIENTRY glBindBufferBaseEXT (GLenum target, GLuint index, GLuint buffer);\nGLAPI void APIENTRY glTransformFeedbackVaryingsEXT (GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode);\nGLAPI void APIENTRY glGetTransformFeedbackVaryingEXT (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);\n#endif\n#endif /* GL_EXT_transform_feedback */\n\n#ifndef GL_EXT_vertex_array\n#define GL_EXT_vertex_array 1\n#define GL_VERTEX_ARRAY_EXT               0x8074\n#define GL_NORMAL_ARRAY_EXT               0x8075\n#define GL_COLOR_ARRAY_EXT                0x8076\n#define GL_INDEX_ARRAY_EXT                0x8077\n#define GL_TEXTURE_COORD_ARRAY_EXT        0x8078\n#define GL_EDGE_FLAG_ARRAY_EXT            0x8079\n#define GL_VERTEX_ARRAY_SIZE_EXT          0x807A\n#define GL_VERTEX_ARRAY_TYPE_EXT          0x807B\n#define GL_VERTEX_ARRAY_STRIDE_EXT        0x807C\n#define GL_VERTEX_ARRAY_COUNT_EXT         0x807D\n#define GL_NORMAL_ARRAY_TYPE_EXT          0x807E\n#define GL_NORMAL_ARRAY_STRIDE_EXT        0x807F\n#define GL_NORMAL_ARRAY_COUNT_EXT         0x8080\n#define GL_COLOR_ARRAY_SIZE_EXT           0x8081\n#define GL_COLOR_ARRAY_TYPE_EXT           0x8082\n#define GL_COLOR_ARRAY_STRIDE_EXT         0x8083\n#define GL_COLOR_ARRAY_COUNT_EXT          0x8084\n#define GL_INDEX_ARRAY_TYPE_EXT           0x8085\n#define GL_INDEX_ARRAY_STRIDE_EXT         0x8086\n#define GL_INDEX_ARRAY_COUNT_EXT          0x8087\n#define GL_TEXTURE_COORD_ARRAY_SIZE_EXT   0x8088\n#define GL_TEXTURE_COORD_ARRAY_TYPE_EXT   0x8089\n#define GL_TEXTURE_COORD_ARRAY_STRIDE_EXT 0x808A\n#define GL_TEXTURE_COORD_ARRAY_COUNT_EXT  0x808B\n#define GL_EDGE_FLAG_ARRAY_STRIDE_EXT     0x808C\n#define GL_EDGE_FLAG_ARRAY_COUNT_EXT      0x808D\n#define GL_VERTEX_ARRAY_POINTER_EXT       0x808E\n#define GL_NORMAL_ARRAY_POINTER_EXT       0x808F\n#define GL_COLOR_ARRAY_POINTER_EXT        0x8090\n#define GL_INDEX_ARRAY_POINTER_EXT        0x8091\n#define GL_TEXTURE_COORD_ARRAY_POINTER_EXT 0x8092\n#define GL_EDGE_FLAG_ARRAY_POINTER_EXT    0x8093\ntypedef void (APIENTRYP PFNGLARRAYELEMENTEXTPROC) (GLint i);\ntypedef void (APIENTRYP PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);\ntypedef void (APIENTRYP PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count);\ntypedef void (APIENTRYP PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean *pointer);\ntypedef void (APIENTRYP PFNGLGETPOINTERVEXTPROC) (GLenum pname, void **params);\ntypedef void (APIENTRYP PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer);\ntypedef void (APIENTRYP PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void *pointer);\ntypedef void (APIENTRYP PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);\ntypedef void (APIENTRYP PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glArrayElementEXT (GLint i);\nGLAPI void APIENTRY glColorPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);\nGLAPI void APIENTRY glDrawArraysEXT (GLenum mode, GLint first, GLsizei count);\nGLAPI void APIENTRY glEdgeFlagPointerEXT (GLsizei stride, GLsizei count, const GLboolean *pointer);\nGLAPI void APIENTRY glGetPointervEXT (GLenum pname, void **params);\nGLAPI void APIENTRY glIndexPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer);\nGLAPI void APIENTRY glNormalPointerEXT (GLenum type, GLsizei stride, GLsizei count, const void *pointer);\nGLAPI void APIENTRY glTexCoordPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);\nGLAPI void APIENTRY glVertexPointerEXT (GLint size, GLenum type, GLsizei stride, GLsizei count, const void *pointer);\n#endif\n#endif /* GL_EXT_vertex_array */\n\n#ifndef GL_EXT_vertex_array_bgra\n#define GL_EXT_vertex_array_bgra 1\n#endif /* GL_EXT_vertex_array_bgra */\n\n#ifndef GL_EXT_vertex_attrib_64bit\n#define GL_EXT_vertex_attrib_64bit 1\n#define GL_DOUBLE_VEC2_EXT                0x8FFC\n#define GL_DOUBLE_VEC3_EXT                0x8FFD\n#define GL_DOUBLE_VEC4_EXT                0x8FFE\n#define GL_DOUBLE_MAT2_EXT                0x8F46\n#define GL_DOUBLE_MAT3_EXT                0x8F47\n#define GL_DOUBLE_MAT4_EXT                0x8F48\n#define GL_DOUBLE_MAT2x3_EXT              0x8F49\n#define GL_DOUBLE_MAT2x4_EXT              0x8F4A\n#define GL_DOUBLE_MAT3x2_EXT              0x8F4B\n#define GL_DOUBLE_MAT3x4_EXT              0x8F4C\n#define GL_DOUBLE_MAT4x2_EXT              0x8F4D\n#define GL_DOUBLE_MAT4x3_EXT              0x8F4E\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1DEXTPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL2DEXTPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVEXTPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVEXTPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVEXTPROC) (GLuint index, GLenum pname, GLdouble *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexAttribL1dEXT (GLuint index, GLdouble x);\nGLAPI void APIENTRY glVertexAttribL2dEXT (GLuint index, GLdouble x, GLdouble y);\nGLAPI void APIENTRY glVertexAttribL3dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glVertexAttribL4dEXT (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glVertexAttribL1dvEXT (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribL2dvEXT (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribL3dvEXT (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribL4dvEXT (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribLPointerEXT (GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glGetVertexAttribLdvEXT (GLuint index, GLenum pname, GLdouble *params);\n#endif\n#endif /* GL_EXT_vertex_attrib_64bit */\n\n#ifndef GL_EXT_vertex_shader\n#define GL_EXT_vertex_shader 1\n#define GL_VERTEX_SHADER_EXT              0x8780\n#define GL_VERTEX_SHADER_BINDING_EXT      0x8781\n#define GL_OP_INDEX_EXT                   0x8782\n#define GL_OP_NEGATE_EXT                  0x8783\n#define GL_OP_DOT3_EXT                    0x8784\n#define GL_OP_DOT4_EXT                    0x8785\n#define GL_OP_MUL_EXT                     0x8786\n#define GL_OP_ADD_EXT                     0x8787\n#define GL_OP_MADD_EXT                    0x8788\n#define GL_OP_FRAC_EXT                    0x8789\n#define GL_OP_MAX_EXT                     0x878A\n#define GL_OP_MIN_EXT                     0x878B\n#define GL_OP_SET_GE_EXT                  0x878C\n#define GL_OP_SET_LT_EXT                  0x878D\n#define GL_OP_CLAMP_EXT                   0x878E\n#define GL_OP_FLOOR_EXT                   0x878F\n#define GL_OP_ROUND_EXT                   0x8790\n#define GL_OP_EXP_BASE_2_EXT              0x8791\n#define GL_OP_LOG_BASE_2_EXT              0x8792\n#define GL_OP_POWER_EXT                   0x8793\n#define GL_OP_RECIP_EXT                   0x8794\n#define GL_OP_RECIP_SQRT_EXT              0x8795\n#define GL_OP_SUB_EXT                     0x8796\n#define GL_OP_CROSS_PRODUCT_EXT           0x8797\n#define GL_OP_MULTIPLY_MATRIX_EXT         0x8798\n#define GL_OP_MOV_EXT                     0x8799\n#define GL_OUTPUT_VERTEX_EXT              0x879A\n#define GL_OUTPUT_COLOR0_EXT              0x879B\n#define GL_OUTPUT_COLOR1_EXT              0x879C\n#define GL_OUTPUT_TEXTURE_COORD0_EXT      0x879D\n#define GL_OUTPUT_TEXTURE_COORD1_EXT      0x879E\n#define GL_OUTPUT_TEXTURE_COORD2_EXT      0x879F\n#define GL_OUTPUT_TEXTURE_COORD3_EXT      0x87A0\n#define GL_OUTPUT_TEXTURE_COORD4_EXT      0x87A1\n#define GL_OUTPUT_TEXTURE_COORD5_EXT      0x87A2\n#define GL_OUTPUT_TEXTURE_COORD6_EXT      0x87A3\n#define GL_OUTPUT_TEXTURE_COORD7_EXT      0x87A4\n#define GL_OUTPUT_TEXTURE_COORD8_EXT      0x87A5\n#define GL_OUTPUT_TEXTURE_COORD9_EXT      0x87A6\n#define GL_OUTPUT_TEXTURE_COORD10_EXT     0x87A7\n#define GL_OUTPUT_TEXTURE_COORD11_EXT     0x87A8\n#define GL_OUTPUT_TEXTURE_COORD12_EXT     0x87A9\n#define GL_OUTPUT_TEXTURE_COORD13_EXT     0x87AA\n#define GL_OUTPUT_TEXTURE_COORD14_EXT     0x87AB\n#define GL_OUTPUT_TEXTURE_COORD15_EXT     0x87AC\n#define GL_OUTPUT_TEXTURE_COORD16_EXT     0x87AD\n#define GL_OUTPUT_TEXTURE_COORD17_EXT     0x87AE\n#define GL_OUTPUT_TEXTURE_COORD18_EXT     0x87AF\n#define GL_OUTPUT_TEXTURE_COORD19_EXT     0x87B0\n#define GL_OUTPUT_TEXTURE_COORD20_EXT     0x87B1\n#define GL_OUTPUT_TEXTURE_COORD21_EXT     0x87B2\n#define GL_OUTPUT_TEXTURE_COORD22_EXT     0x87B3\n#define GL_OUTPUT_TEXTURE_COORD23_EXT     0x87B4\n#define GL_OUTPUT_TEXTURE_COORD24_EXT     0x87B5\n#define GL_OUTPUT_TEXTURE_COORD25_EXT     0x87B6\n#define GL_OUTPUT_TEXTURE_COORD26_EXT     0x87B7\n#define GL_OUTPUT_TEXTURE_COORD27_EXT     0x87B8\n#define GL_OUTPUT_TEXTURE_COORD28_EXT     0x87B9\n#define GL_OUTPUT_TEXTURE_COORD29_EXT     0x87BA\n#define GL_OUTPUT_TEXTURE_COORD30_EXT     0x87BB\n#define GL_OUTPUT_TEXTURE_COORD31_EXT     0x87BC\n#define GL_OUTPUT_FOG_EXT                 0x87BD\n#define GL_SCALAR_EXT                     0x87BE\n#define GL_VECTOR_EXT                     0x87BF\n#define GL_MATRIX_EXT                     0x87C0\n#define GL_VARIANT_EXT                    0x87C1\n#define GL_INVARIANT_EXT                  0x87C2\n#define GL_LOCAL_CONSTANT_EXT             0x87C3\n#define GL_LOCAL_EXT                      0x87C4\n#define GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87C5\n#define GL_MAX_VERTEX_SHADER_VARIANTS_EXT 0x87C6\n#define GL_MAX_VERTEX_SHADER_INVARIANTS_EXT 0x87C7\n#define GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87C8\n#define GL_MAX_VERTEX_SHADER_LOCALS_EXT   0x87C9\n#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CA\n#define GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT 0x87CB\n#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87CC\n#define GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT 0x87CD\n#define GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT 0x87CE\n#define GL_VERTEX_SHADER_INSTRUCTIONS_EXT 0x87CF\n#define GL_VERTEX_SHADER_VARIANTS_EXT     0x87D0\n#define GL_VERTEX_SHADER_INVARIANTS_EXT   0x87D1\n#define GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT 0x87D2\n#define GL_VERTEX_SHADER_LOCALS_EXT       0x87D3\n#define GL_VERTEX_SHADER_OPTIMIZED_EXT    0x87D4\n#define GL_X_EXT                          0x87D5\n#define GL_Y_EXT                          0x87D6\n#define GL_Z_EXT                          0x87D7\n#define GL_W_EXT                          0x87D8\n#define GL_NEGATIVE_X_EXT                 0x87D9\n#define GL_NEGATIVE_Y_EXT                 0x87DA\n#define GL_NEGATIVE_Z_EXT                 0x87DB\n#define GL_NEGATIVE_W_EXT                 0x87DC\n#define GL_ZERO_EXT                       0x87DD\n#define GL_ONE_EXT                        0x87DE\n#define GL_NEGATIVE_ONE_EXT               0x87DF\n#define GL_NORMALIZED_RANGE_EXT           0x87E0\n#define GL_FULL_RANGE_EXT                 0x87E1\n#define GL_CURRENT_VERTEX_EXT             0x87E2\n#define GL_MVP_MATRIX_EXT                 0x87E3\n#define GL_VARIANT_VALUE_EXT              0x87E4\n#define GL_VARIANT_DATATYPE_EXT           0x87E5\n#define GL_VARIANT_ARRAY_STRIDE_EXT       0x87E6\n#define GL_VARIANT_ARRAY_TYPE_EXT         0x87E7\n#define GL_VARIANT_ARRAY_EXT              0x87E8\n#define GL_VARIANT_ARRAY_POINTER_EXT      0x87E9\n#define GL_INVARIANT_VALUE_EXT            0x87EA\n#define GL_INVARIANT_DATATYPE_EXT         0x87EB\n#define GL_LOCAL_CONSTANT_VALUE_EXT       0x87EC\n#define GL_LOCAL_CONSTANT_DATATYPE_EXT    0x87ED\ntypedef void (APIENTRYP PFNGLBEGINVERTEXSHADEREXTPROC) (void);\ntypedef void (APIENTRYP PFNGLENDVERTEXSHADEREXTPROC) (void);\ntypedef void (APIENTRYP PFNGLBINDVERTEXSHADEREXTPROC) (GLuint id);\ntypedef GLuint (APIENTRYP PFNGLGENVERTEXSHADERSEXTPROC) (GLuint range);\ntypedef void (APIENTRYP PFNGLDELETEVERTEXSHADEREXTPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLSHADEROP1EXTPROC) (GLenum op, GLuint res, GLuint arg1);\ntypedef void (APIENTRYP PFNGLSHADEROP2EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2);\ntypedef void (APIENTRYP PFNGLSHADEROP3EXTPROC) (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);\ntypedef void (APIENTRYP PFNGLSWIZZLEEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);\ntypedef void (APIENTRYP PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);\ntypedef void (APIENTRYP PFNGLINSERTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);\ntypedef void (APIENTRYP PFNGLEXTRACTCOMPONENTEXTPROC) (GLuint res, GLuint src, GLuint num);\ntypedef GLuint (APIENTRYP PFNGLGENSYMBOLSEXTPROC) (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);\ntypedef void (APIENTRYP PFNGLSETINVARIANTEXTPROC) (GLuint id, GLenum type, const void *addr);\ntypedef void (APIENTRYP PFNGLSETLOCALCONSTANTEXTPROC) (GLuint id, GLenum type, const void *addr);\ntypedef void (APIENTRYP PFNGLVARIANTBVEXTPROC) (GLuint id, const GLbyte *addr);\ntypedef void (APIENTRYP PFNGLVARIANTSVEXTPROC) (GLuint id, const GLshort *addr);\ntypedef void (APIENTRYP PFNGLVARIANTIVEXTPROC) (GLuint id, const GLint *addr);\ntypedef void (APIENTRYP PFNGLVARIANTFVEXTPROC) (GLuint id, const GLfloat *addr);\ntypedef void (APIENTRYP PFNGLVARIANTDVEXTPROC) (GLuint id, const GLdouble *addr);\ntypedef void (APIENTRYP PFNGLVARIANTUBVEXTPROC) (GLuint id, const GLubyte *addr);\ntypedef void (APIENTRYP PFNGLVARIANTUSVEXTPROC) (GLuint id, const GLushort *addr);\ntypedef void (APIENTRYP PFNGLVARIANTUIVEXTPROC) (GLuint id, const GLuint *addr);\ntypedef void (APIENTRYP PFNGLVARIANTPOINTEREXTPROC) (GLuint id, GLenum type, GLuint stride, const void *addr);\ntypedef void (APIENTRYP PFNGLENABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLDISABLEVARIANTCLIENTSTATEEXTPROC) (GLuint id);\ntypedef GLuint (APIENTRYP PFNGLBINDLIGHTPARAMETEREXTPROC) (GLenum light, GLenum value);\ntypedef GLuint (APIENTRYP PFNGLBINDMATERIALPARAMETEREXTPROC) (GLenum face, GLenum value);\ntypedef GLuint (APIENTRYP PFNGLBINDTEXGENPARAMETEREXTPROC) (GLenum unit, GLenum coord, GLenum value);\ntypedef GLuint (APIENTRYP PFNGLBINDTEXTUREUNITPARAMETEREXTPROC) (GLenum unit, GLenum value);\ntypedef GLuint (APIENTRYP PFNGLBINDPARAMETEREXTPROC) (GLenum value);\ntypedef GLboolean (APIENTRYP PFNGLISVARIANTENABLEDEXTPROC) (GLuint id, GLenum cap);\ntypedef void (APIENTRYP PFNGLGETVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);\ntypedef void (APIENTRYP PFNGLGETVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);\ntypedef void (APIENTRYP PFNGLGETVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);\ntypedef void (APIENTRYP PFNGLGETVARIANTPOINTERVEXTPROC) (GLuint id, GLenum value, void **data);\ntypedef void (APIENTRYP PFNGLGETINVARIANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);\ntypedef void (APIENTRYP PFNGLGETINVARIANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);\ntypedef void (APIENTRYP PFNGLGETINVARIANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);\ntypedef void (APIENTRYP PFNGLGETLOCALCONSTANTBOOLEANVEXTPROC) (GLuint id, GLenum value, GLboolean *data);\ntypedef void (APIENTRYP PFNGLGETLOCALCONSTANTINTEGERVEXTPROC) (GLuint id, GLenum value, GLint *data);\ntypedef void (APIENTRYP PFNGLGETLOCALCONSTANTFLOATVEXTPROC) (GLuint id, GLenum value, GLfloat *data);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBeginVertexShaderEXT (void);\nGLAPI void APIENTRY glEndVertexShaderEXT (void);\nGLAPI void APIENTRY glBindVertexShaderEXT (GLuint id);\nGLAPI GLuint APIENTRY glGenVertexShadersEXT (GLuint range);\nGLAPI void APIENTRY glDeleteVertexShaderEXT (GLuint id);\nGLAPI void APIENTRY glShaderOp1EXT (GLenum op, GLuint res, GLuint arg1);\nGLAPI void APIENTRY glShaderOp2EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2);\nGLAPI void APIENTRY glShaderOp3EXT (GLenum op, GLuint res, GLuint arg1, GLuint arg2, GLuint arg3);\nGLAPI void APIENTRY glSwizzleEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);\nGLAPI void APIENTRY glWriteMaskEXT (GLuint res, GLuint in, GLenum outX, GLenum outY, GLenum outZ, GLenum outW);\nGLAPI void APIENTRY glInsertComponentEXT (GLuint res, GLuint src, GLuint num);\nGLAPI void APIENTRY glExtractComponentEXT (GLuint res, GLuint src, GLuint num);\nGLAPI GLuint APIENTRY glGenSymbolsEXT (GLenum datatype, GLenum storagetype, GLenum range, GLuint components);\nGLAPI void APIENTRY glSetInvariantEXT (GLuint id, GLenum type, const void *addr);\nGLAPI void APIENTRY glSetLocalConstantEXT (GLuint id, GLenum type, const void *addr);\nGLAPI void APIENTRY glVariantbvEXT (GLuint id, const GLbyte *addr);\nGLAPI void APIENTRY glVariantsvEXT (GLuint id, const GLshort *addr);\nGLAPI void APIENTRY glVariantivEXT (GLuint id, const GLint *addr);\nGLAPI void APIENTRY glVariantfvEXT (GLuint id, const GLfloat *addr);\nGLAPI void APIENTRY glVariantdvEXT (GLuint id, const GLdouble *addr);\nGLAPI void APIENTRY glVariantubvEXT (GLuint id, const GLubyte *addr);\nGLAPI void APIENTRY glVariantusvEXT (GLuint id, const GLushort *addr);\nGLAPI void APIENTRY glVariantuivEXT (GLuint id, const GLuint *addr);\nGLAPI void APIENTRY glVariantPointerEXT (GLuint id, GLenum type, GLuint stride, const void *addr);\nGLAPI void APIENTRY glEnableVariantClientStateEXT (GLuint id);\nGLAPI void APIENTRY glDisableVariantClientStateEXT (GLuint id);\nGLAPI GLuint APIENTRY glBindLightParameterEXT (GLenum light, GLenum value);\nGLAPI GLuint APIENTRY glBindMaterialParameterEXT (GLenum face, GLenum value);\nGLAPI GLuint APIENTRY glBindTexGenParameterEXT (GLenum unit, GLenum coord, GLenum value);\nGLAPI GLuint APIENTRY glBindTextureUnitParameterEXT (GLenum unit, GLenum value);\nGLAPI GLuint APIENTRY glBindParameterEXT (GLenum value);\nGLAPI GLboolean APIENTRY glIsVariantEnabledEXT (GLuint id, GLenum cap);\nGLAPI void APIENTRY glGetVariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data);\nGLAPI void APIENTRY glGetVariantIntegervEXT (GLuint id, GLenum value, GLint *data);\nGLAPI void APIENTRY glGetVariantFloatvEXT (GLuint id, GLenum value, GLfloat *data);\nGLAPI void APIENTRY glGetVariantPointervEXT (GLuint id, GLenum value, void **data);\nGLAPI void APIENTRY glGetInvariantBooleanvEXT (GLuint id, GLenum value, GLboolean *data);\nGLAPI void APIENTRY glGetInvariantIntegervEXT (GLuint id, GLenum value, GLint *data);\nGLAPI void APIENTRY glGetInvariantFloatvEXT (GLuint id, GLenum value, GLfloat *data);\nGLAPI void APIENTRY glGetLocalConstantBooleanvEXT (GLuint id, GLenum value, GLboolean *data);\nGLAPI void APIENTRY glGetLocalConstantIntegervEXT (GLuint id, GLenum value, GLint *data);\nGLAPI void APIENTRY glGetLocalConstantFloatvEXT (GLuint id, GLenum value, GLfloat *data);\n#endif\n#endif /* GL_EXT_vertex_shader */\n\n#ifndef GL_EXT_vertex_weighting\n#define GL_EXT_vertex_weighting 1\n#define GL_MODELVIEW0_STACK_DEPTH_EXT     0x0BA3\n#define GL_MODELVIEW1_STACK_DEPTH_EXT     0x8502\n#define GL_MODELVIEW0_MATRIX_EXT          0x0BA6\n#define GL_MODELVIEW1_MATRIX_EXT          0x8506\n#define GL_VERTEX_WEIGHTING_EXT           0x8509\n#define GL_MODELVIEW0_EXT                 0x1700\n#define GL_MODELVIEW1_EXT                 0x850A\n#define GL_CURRENT_VERTEX_WEIGHT_EXT      0x850B\n#define GL_VERTEX_WEIGHT_ARRAY_EXT        0x850C\n#define GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT   0x850D\n#define GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT   0x850E\n#define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F\n#define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510\ntypedef void (APIENTRYP PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight);\ntypedef void (APIENTRYP PFNGLVERTEXWEIGHTFVEXTPROC) (const GLfloat *weight);\ntypedef void (APIENTRYP PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, const void *pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexWeightfEXT (GLfloat weight);\nGLAPI void APIENTRY glVertexWeightfvEXT (const GLfloat *weight);\nGLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei stride, const void *pointer);\n#endif\n#endif /* GL_EXT_vertex_weighting */\n\n#ifndef GL_EXT_win32_keyed_mutex\n#define GL_EXT_win32_keyed_mutex 1\ntypedef GLboolean (APIENTRYP PFNGLACQUIREKEYEDMUTEXWIN32EXTPROC) (GLuint memory, GLuint64 key, GLuint timeout);\ntypedef GLboolean (APIENTRYP PFNGLRELEASEKEYEDMUTEXWIN32EXTPROC) (GLuint memory, GLuint64 key);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLboolean APIENTRY glAcquireKeyedMutexWin32EXT (GLuint memory, GLuint64 key, GLuint timeout);\nGLAPI GLboolean APIENTRY glReleaseKeyedMutexWin32EXT (GLuint memory, GLuint64 key);\n#endif\n#endif /* GL_EXT_win32_keyed_mutex */\n\n#ifndef GL_EXT_window_rectangles\n#define GL_EXT_window_rectangles 1\n#define GL_INCLUSIVE_EXT                  0x8F10\n#define GL_EXCLUSIVE_EXT                  0x8F11\n#define GL_WINDOW_RECTANGLE_EXT           0x8F12\n#define GL_WINDOW_RECTANGLE_MODE_EXT      0x8F13\n#define GL_MAX_WINDOW_RECTANGLES_EXT      0x8F14\n#define GL_NUM_WINDOW_RECTANGLES_EXT      0x8F15\ntypedef void (APIENTRYP PFNGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glWindowRectanglesEXT (GLenum mode, GLsizei count, const GLint *box);\n#endif\n#endif /* GL_EXT_window_rectangles */\n\n#ifndef GL_EXT_x11_sync_object\n#define GL_EXT_x11_sync_object 1\n#define GL_SYNC_X11_FENCE_EXT             0x90E1\ntypedef GLsync (APIENTRYP PFNGLIMPORTSYNCEXTPROC) (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLsync APIENTRY glImportSyncEXT (GLenum external_sync_type, GLintptr external_sync, GLbitfield flags);\n#endif\n#endif /* GL_EXT_x11_sync_object */\n\n#ifndef GL_GREMEDY_frame_terminator\n#define GL_GREMEDY_frame_terminator 1\ntypedef void (APIENTRYP PFNGLFRAMETERMINATORGREMEDYPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFrameTerminatorGREMEDY (void);\n#endif\n#endif /* GL_GREMEDY_frame_terminator */\n\n#ifndef GL_GREMEDY_string_marker\n#define GL_GREMEDY_string_marker 1\ntypedef void (APIENTRYP PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const void *string);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glStringMarkerGREMEDY (GLsizei len, const void *string);\n#endif\n#endif /* GL_GREMEDY_string_marker */\n\n#ifndef GL_HP_convolution_border_modes\n#define GL_HP_convolution_border_modes 1\n#define GL_IGNORE_BORDER_HP               0x8150\n#define GL_CONSTANT_BORDER_HP             0x8151\n#define GL_REPLICATE_BORDER_HP            0x8153\n#define GL_CONVOLUTION_BORDER_COLOR_HP    0x8154\n#endif /* GL_HP_convolution_border_modes */\n\n#ifndef GL_HP_image_transform\n#define GL_HP_image_transform 1\n#define GL_IMAGE_SCALE_X_HP               0x8155\n#define GL_IMAGE_SCALE_Y_HP               0x8156\n#define GL_IMAGE_TRANSLATE_X_HP           0x8157\n#define GL_IMAGE_TRANSLATE_Y_HP           0x8158\n#define GL_IMAGE_ROTATE_ANGLE_HP          0x8159\n#define GL_IMAGE_ROTATE_ORIGIN_X_HP       0x815A\n#define GL_IMAGE_ROTATE_ORIGIN_Y_HP       0x815B\n#define GL_IMAGE_MAG_FILTER_HP            0x815C\n#define GL_IMAGE_MIN_FILTER_HP            0x815D\n#define GL_IMAGE_CUBIC_WEIGHT_HP          0x815E\n#define GL_CUBIC_HP                       0x815F\n#define GL_AVERAGE_HP                     0x8160\n#define GL_IMAGE_TRANSFORM_2D_HP          0x8161\n#define GL_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8162\n#define GL_PROXY_POST_IMAGE_TRANSFORM_COLOR_TABLE_HP 0x8163\ntypedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIHPPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFHPPROC) (GLenum target, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETIMAGETRANSFORMPARAMETERFVHPPROC) (GLenum target, GLenum pname, GLfloat *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glImageTransformParameteriHP (GLenum target, GLenum pname, GLint param);\nGLAPI void APIENTRY glImageTransformParameterfHP (GLenum target, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glImageTransformParameterivHP (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glImageTransformParameterfvHP (GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glGetImageTransformParameterivHP (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetImageTransformParameterfvHP (GLenum target, GLenum pname, GLfloat *params);\n#endif\n#endif /* GL_HP_image_transform */\n\n#ifndef GL_HP_occlusion_test\n#define GL_HP_occlusion_test 1\n#define GL_OCCLUSION_TEST_HP              0x8165\n#define GL_OCCLUSION_TEST_RESULT_HP       0x8166\n#endif /* GL_HP_occlusion_test */\n\n#ifndef GL_HP_texture_lighting\n#define GL_HP_texture_lighting 1\n#define GL_TEXTURE_LIGHTING_MODE_HP       0x8167\n#define GL_TEXTURE_POST_SPECULAR_HP       0x8168\n#define GL_TEXTURE_PRE_SPECULAR_HP        0x8169\n#endif /* GL_HP_texture_lighting */\n\n#ifndef GL_IBM_cull_vertex\n#define GL_IBM_cull_vertex 1\n#define GL_CULL_VERTEX_IBM                103050\n#endif /* GL_IBM_cull_vertex */\n\n#ifndef GL_IBM_multimode_draw_arrays\n#define GL_IBM_multimode_draw_arrays 1\ntypedef void (APIENTRYP PFNGLMULTIMODEDRAWARRAYSIBMPROC) (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);\ntypedef void (APIENTRYP PFNGLMULTIMODEDRAWELEMENTSIBMPROC) (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMultiModeDrawArraysIBM (const GLenum *mode, const GLint *first, const GLsizei *count, GLsizei primcount, GLint modestride);\nGLAPI void APIENTRY glMultiModeDrawElementsIBM (const GLenum *mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, GLint modestride);\n#endif\n#endif /* GL_IBM_multimode_draw_arrays */\n\n#ifndef GL_IBM_rasterpos_clip\n#define GL_IBM_rasterpos_clip 1\n#define GL_RASTER_POSITION_UNCLIPPED_IBM  0x19262\n#endif /* GL_IBM_rasterpos_clip */\n\n#ifndef GL_IBM_static_data\n#define GL_IBM_static_data 1\n#define GL_ALL_STATIC_DATA_IBM            103060\n#define GL_STATIC_VERTEX_ARRAY_IBM        103061\ntypedef void (APIENTRYP PFNGLFLUSHSTATICDATAIBMPROC) (GLenum target);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFlushStaticDataIBM (GLenum target);\n#endif\n#endif /* GL_IBM_static_data */\n\n#ifndef GL_IBM_texture_mirrored_repeat\n#define GL_IBM_texture_mirrored_repeat 1\n#define GL_MIRRORED_REPEAT_IBM            0x8370\n#endif /* GL_IBM_texture_mirrored_repeat */\n\n#ifndef GL_IBM_vertex_array_lists\n#define GL_IBM_vertex_array_lists 1\n#define GL_VERTEX_ARRAY_LIST_IBM          103070\n#define GL_NORMAL_ARRAY_LIST_IBM          103071\n#define GL_COLOR_ARRAY_LIST_IBM           103072\n#define GL_INDEX_ARRAY_LIST_IBM           103073\n#define GL_TEXTURE_COORD_ARRAY_LIST_IBM   103074\n#define GL_EDGE_FLAG_ARRAY_LIST_IBM       103075\n#define GL_FOG_COORDINATE_ARRAY_LIST_IBM  103076\n#define GL_SECONDARY_COLOR_ARRAY_LIST_IBM 103077\n#define GL_VERTEX_ARRAY_LIST_STRIDE_IBM   103080\n#define GL_NORMAL_ARRAY_LIST_STRIDE_IBM   103081\n#define GL_COLOR_ARRAY_LIST_STRIDE_IBM    103082\n#define GL_INDEX_ARRAY_LIST_STRIDE_IBM    103083\n#define GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM 103084\n#define GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM 103085\n#define GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM 103086\n#define GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM 103087\ntypedef void (APIENTRYP PFNGLCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLEDGEFLAGPOINTERLISTIBMPROC) (GLint stride, const GLboolean **pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLFOGCOORDPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLINDEXPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLNORMALPOINTERLISTIBMPROC) (GLenum type, GLint stride, const void **pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLTEXCOORDPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);\ntypedef void (APIENTRYP PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);\nGLAPI void APIENTRY glSecondaryColorPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);\nGLAPI void APIENTRY glEdgeFlagPointerListIBM (GLint stride, const GLboolean **pointer, GLint ptrstride);\nGLAPI void APIENTRY glFogCoordPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride);\nGLAPI void APIENTRY glIndexPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride);\nGLAPI void APIENTRY glNormalPointerListIBM (GLenum type, GLint stride, const void **pointer, GLint ptrstride);\nGLAPI void APIENTRY glTexCoordPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);\nGLAPI void APIENTRY glVertexPointerListIBM (GLint size, GLenum type, GLint stride, const void **pointer, GLint ptrstride);\n#endif\n#endif /* GL_IBM_vertex_array_lists */\n\n#ifndef GL_INGR_blend_func_separate\n#define GL_INGR_blend_func_separate 1\ntypedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEINGRPROC) (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\n#endif\n#endif /* GL_INGR_blend_func_separate */\n\n#ifndef GL_INGR_color_clamp\n#define GL_INGR_color_clamp 1\n#define GL_RED_MIN_CLAMP_INGR             0x8560\n#define GL_GREEN_MIN_CLAMP_INGR           0x8561\n#define GL_BLUE_MIN_CLAMP_INGR            0x8562\n#define GL_ALPHA_MIN_CLAMP_INGR           0x8563\n#define GL_RED_MAX_CLAMP_INGR             0x8564\n#define GL_GREEN_MAX_CLAMP_INGR           0x8565\n#define GL_BLUE_MAX_CLAMP_INGR            0x8566\n#define GL_ALPHA_MAX_CLAMP_INGR           0x8567\n#endif /* GL_INGR_color_clamp */\n\n#ifndef GL_INGR_interlace_read\n#define GL_INGR_interlace_read 1\n#define GL_INTERLACE_READ_INGR            0x8568\n#endif /* GL_INGR_interlace_read */\n\n#ifndef GL_INTEL_blackhole_render\n#define GL_INTEL_blackhole_render 1\n#define GL_BLACKHOLE_RENDER_INTEL         0x83FC\n#endif /* GL_INTEL_blackhole_render */\n\n#ifndef GL_INTEL_conservative_rasterization\n#define GL_INTEL_conservative_rasterization 1\n#define GL_CONSERVATIVE_RASTERIZATION_INTEL 0x83FE\n#endif /* GL_INTEL_conservative_rasterization */\n\n#ifndef GL_INTEL_fragment_shader_ordering\n#define GL_INTEL_fragment_shader_ordering 1\n#endif /* GL_INTEL_fragment_shader_ordering */\n\n#ifndef GL_INTEL_framebuffer_CMAA\n#define GL_INTEL_framebuffer_CMAA 1\ntypedef void (APIENTRYP PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glApplyFramebufferAttachmentCMAAINTEL (void);\n#endif\n#endif /* GL_INTEL_framebuffer_CMAA */\n\n#ifndef GL_INTEL_map_texture\n#define GL_INTEL_map_texture 1\n#define GL_TEXTURE_MEMORY_LAYOUT_INTEL    0x83FF\n#define GL_LAYOUT_DEFAULT_INTEL           0\n#define GL_LAYOUT_LINEAR_INTEL            1\n#define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2\ntypedef void (APIENTRYP PFNGLSYNCTEXTUREINTELPROC) (GLuint texture);\ntypedef void (APIENTRYP PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level);\ntypedef void *(APIENTRYP PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSyncTextureINTEL (GLuint texture);\nGLAPI void APIENTRY glUnmapTexture2DINTEL (GLuint texture, GLint level);\nGLAPI void *APIENTRY glMapTexture2DINTEL (GLuint texture, GLint level, GLbitfield access, GLint *stride, GLenum *layout);\n#endif\n#endif /* GL_INTEL_map_texture */\n\n#ifndef GL_INTEL_parallel_arrays\n#define GL_INTEL_parallel_arrays 1\n#define GL_PARALLEL_ARRAYS_INTEL          0x83F4\n#define GL_VERTEX_ARRAY_PARALLEL_POINTERS_INTEL 0x83F5\n#define GL_NORMAL_ARRAY_PARALLEL_POINTERS_INTEL 0x83F6\n#define GL_COLOR_ARRAY_PARALLEL_POINTERS_INTEL 0x83F7\n#define GL_TEXTURE_COORD_ARRAY_PARALLEL_POINTERS_INTEL 0x83F8\ntypedef void (APIENTRYP PFNGLVERTEXPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer);\ntypedef void (APIENTRYP PFNGLNORMALPOINTERVINTELPROC) (GLenum type, const void **pointer);\ntypedef void (APIENTRYP PFNGLCOLORPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer);\ntypedef void (APIENTRYP PFNGLTEXCOORDPOINTERVINTELPROC) (GLint size, GLenum type, const void **pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexPointervINTEL (GLint size, GLenum type, const void **pointer);\nGLAPI void APIENTRY glNormalPointervINTEL (GLenum type, const void **pointer);\nGLAPI void APIENTRY glColorPointervINTEL (GLint size, GLenum type, const void **pointer);\nGLAPI void APIENTRY glTexCoordPointervINTEL (GLint size, GLenum type, const void **pointer);\n#endif\n#endif /* GL_INTEL_parallel_arrays */\n\n#ifndef GL_INTEL_performance_query\n#define GL_INTEL_performance_query 1\n#define GL_PERFQUERY_SINGLE_CONTEXT_INTEL 0x00000000\n#define GL_PERFQUERY_GLOBAL_CONTEXT_INTEL 0x00000001\n#define GL_PERFQUERY_WAIT_INTEL           0x83FB\n#define GL_PERFQUERY_FLUSH_INTEL          0x83FA\n#define GL_PERFQUERY_DONOT_FLUSH_INTEL    0x83F9\n#define GL_PERFQUERY_COUNTER_EVENT_INTEL  0x94F0\n#define GL_PERFQUERY_COUNTER_DURATION_NORM_INTEL 0x94F1\n#define GL_PERFQUERY_COUNTER_DURATION_RAW_INTEL 0x94F2\n#define GL_PERFQUERY_COUNTER_THROUGHPUT_INTEL 0x94F3\n#define GL_PERFQUERY_COUNTER_RAW_INTEL    0x94F4\n#define GL_PERFQUERY_COUNTER_TIMESTAMP_INTEL 0x94F5\n#define GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL 0x94F8\n#define GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL 0x94F9\n#define GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL 0x94FA\n#define GL_PERFQUERY_COUNTER_DATA_DOUBLE_INTEL 0x94FB\n#define GL_PERFQUERY_COUNTER_DATA_BOOL32_INTEL 0x94FC\n#define GL_PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL 0x94FD\n#define GL_PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL 0x94FE\n#define GL_PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL 0x94FF\n#define GL_PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL 0x9500\ntypedef void (APIENTRYP PFNGLBEGINPERFQUERYINTELPROC) (GLuint queryHandle);\ntypedef void (APIENTRYP PFNGLCREATEPERFQUERYINTELPROC) (GLuint queryId, GLuint *queryHandle);\ntypedef void (APIENTRYP PFNGLDELETEPERFQUERYINTELPROC) (GLuint queryHandle);\ntypedef void (APIENTRYP PFNGLENDPERFQUERYINTELPROC) (GLuint queryHandle);\ntypedef void (APIENTRYP PFNGLGETFIRSTPERFQUERYIDINTELPROC) (GLuint *queryId);\ntypedef void (APIENTRYP PFNGLGETNEXTPERFQUERYIDINTELPROC) (GLuint queryId, GLuint *nextQueryId);\ntypedef void (APIENTRYP PFNGLGETPERFCOUNTERINFOINTELPROC) (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);\ntypedef void (APIENTRYP PFNGLGETPERFQUERYDATAINTELPROC) (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten);\ntypedef void (APIENTRYP PFNGLGETPERFQUERYIDBYNAMEINTELPROC) (GLchar *queryName, GLuint *queryId);\ntypedef void (APIENTRYP PFNGLGETPERFQUERYINFOINTELPROC) (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBeginPerfQueryINTEL (GLuint queryHandle);\nGLAPI void APIENTRY glCreatePerfQueryINTEL (GLuint queryId, GLuint *queryHandle);\nGLAPI void APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle);\nGLAPI void APIENTRY glEndPerfQueryINTEL (GLuint queryHandle);\nGLAPI void APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId);\nGLAPI void APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId);\nGLAPI void APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);\nGLAPI void APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, void *data, GLuint *bytesWritten);\nGLAPI void APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId);\nGLAPI void APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask);\n#endif\n#endif /* GL_INTEL_performance_query */\n\n#ifndef GL_MESAX_texture_stack\n#define GL_MESAX_texture_stack 1\n#define GL_TEXTURE_1D_STACK_MESAX         0x8759\n#define GL_TEXTURE_2D_STACK_MESAX         0x875A\n#define GL_PROXY_TEXTURE_1D_STACK_MESAX   0x875B\n#define GL_PROXY_TEXTURE_2D_STACK_MESAX   0x875C\n#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D\n#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E\n#endif /* GL_MESAX_texture_stack */\n\n#ifndef GL_MESA_framebuffer_flip_x\n#define GL_MESA_framebuffer_flip_x 1\n#define GL_FRAMEBUFFER_FLIP_X_MESA        0x8BBC\n#endif /* GL_MESA_framebuffer_flip_x */\n\n#ifndef GL_MESA_framebuffer_flip_y\n#define GL_MESA_framebuffer_flip_y 1\n#define GL_FRAMEBUFFER_FLIP_Y_MESA        0x8BBB\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIMESAPROC) (GLenum target, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVMESAPROC) (GLenum target, GLenum pname, GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFramebufferParameteriMESA (GLenum target, GLenum pname, GLint param);\nGLAPI void APIENTRY glGetFramebufferParameterivMESA (GLenum target, GLenum pname, GLint *params);\n#endif\n#endif /* GL_MESA_framebuffer_flip_y */\n\n#ifndef GL_MESA_framebuffer_swap_xy\n#define GL_MESA_framebuffer_swap_xy 1\n#define GL_FRAMEBUFFER_SWAP_XY_MESA       0x8BBD\n#endif /* GL_MESA_framebuffer_swap_xy */\n\n#ifndef GL_MESA_pack_invert\n#define GL_MESA_pack_invert 1\n#define GL_PACK_INVERT_MESA               0x8758\n#endif /* GL_MESA_pack_invert */\n\n#ifndef GL_MESA_program_binary_formats\n#define GL_MESA_program_binary_formats 1\n#define GL_PROGRAM_BINARY_FORMAT_MESA     0x875F\n#endif /* GL_MESA_program_binary_formats */\n\n#ifndef GL_MESA_resize_buffers\n#define GL_MESA_resize_buffers 1\ntypedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glResizeBuffersMESA (void);\n#endif\n#endif /* GL_MESA_resize_buffers */\n\n#ifndef GL_MESA_shader_integer_functions\n#define GL_MESA_shader_integer_functions 1\n#endif /* GL_MESA_shader_integer_functions */\n\n#ifndef GL_MESA_tile_raster_order\n#define GL_MESA_tile_raster_order 1\n#define GL_TILE_RASTER_ORDER_FIXED_MESA   0x8BB8\n#define GL_TILE_RASTER_ORDER_INCREASING_X_MESA 0x8BB9\n#define GL_TILE_RASTER_ORDER_INCREASING_Y_MESA 0x8BBA\n#endif /* GL_MESA_tile_raster_order */\n\n#ifndef GL_MESA_window_pos\n#define GL_MESA_window_pos 1\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DMESAPROC) (GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2DVMESAPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FMESAPROC) (GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2FVMESAPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IMESAPROC) (GLint x, GLint y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2IVMESAPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SMESAPROC) (GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLWINDOWPOS2SVMESAPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DMESAPROC) (GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3DVMESAPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FMESAPROC) (GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3FVMESAPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IMESAPROC) (GLint x, GLint y, GLint z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3IVMESAPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SMESAPROC) (GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLWINDOWPOS3SVMESAPROC) (const GLshort *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4DMESAPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4DVMESAPROC) (const GLdouble *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4FMESAPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4FVMESAPROC) (const GLfloat *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4IMESAPROC) (GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4IVMESAPROC) (const GLint *v);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4SMESAPROC) (GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLWINDOWPOS4SVMESAPROC) (const GLshort *v);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glWindowPos2dMESA (GLdouble x, GLdouble y);\nGLAPI void APIENTRY glWindowPos2dvMESA (const GLdouble *v);\nGLAPI void APIENTRY glWindowPos2fMESA (GLfloat x, GLfloat y);\nGLAPI void APIENTRY glWindowPos2fvMESA (const GLfloat *v);\nGLAPI void APIENTRY glWindowPos2iMESA (GLint x, GLint y);\nGLAPI void APIENTRY glWindowPos2ivMESA (const GLint *v);\nGLAPI void APIENTRY glWindowPos2sMESA (GLshort x, GLshort y);\nGLAPI void APIENTRY glWindowPos2svMESA (const GLshort *v);\nGLAPI void APIENTRY glWindowPos3dMESA (GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glWindowPos3dvMESA (const GLdouble *v);\nGLAPI void APIENTRY glWindowPos3fMESA (GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glWindowPos3fvMESA (const GLfloat *v);\nGLAPI void APIENTRY glWindowPos3iMESA (GLint x, GLint y, GLint z);\nGLAPI void APIENTRY glWindowPos3ivMESA (const GLint *v);\nGLAPI void APIENTRY glWindowPos3sMESA (GLshort x, GLshort y, GLshort z);\nGLAPI void APIENTRY glWindowPos3svMESA (const GLshort *v);\nGLAPI void APIENTRY glWindowPos4dMESA (GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glWindowPos4dvMESA (const GLdouble *v);\nGLAPI void APIENTRY glWindowPos4fMESA (GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glWindowPos4fvMESA (const GLfloat *v);\nGLAPI void APIENTRY glWindowPos4iMESA (GLint x, GLint y, GLint z, GLint w);\nGLAPI void APIENTRY glWindowPos4ivMESA (const GLint *v);\nGLAPI void APIENTRY glWindowPos4sMESA (GLshort x, GLshort y, GLshort z, GLshort w);\nGLAPI void APIENTRY glWindowPos4svMESA (const GLshort *v);\n#endif\n#endif /* GL_MESA_window_pos */\n\n#ifndef GL_MESA_ycbcr_texture\n#define GL_MESA_ycbcr_texture 1\n#define GL_UNSIGNED_SHORT_8_8_MESA        0x85BA\n#define GL_UNSIGNED_SHORT_8_8_REV_MESA    0x85BB\n#define GL_YCBCR_MESA                     0x8757\n#endif /* GL_MESA_ycbcr_texture */\n\n#ifndef GL_NVX_blend_equation_advanced_multi_draw_buffers\n#define GL_NVX_blend_equation_advanced_multi_draw_buffers 1\n#endif /* GL_NVX_blend_equation_advanced_multi_draw_buffers */\n\n#ifndef GL_NVX_conditional_render\n#define GL_NVX_conditional_render 1\ntypedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVXPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVXPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBeginConditionalRenderNVX (GLuint id);\nGLAPI void APIENTRY glEndConditionalRenderNVX (void);\n#endif\n#endif /* GL_NVX_conditional_render */\n\n#ifndef GL_NVX_gpu_memory_info\n#define GL_NVX_gpu_memory_info 1\n#define GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX 0x9047\n#define GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX 0x9048\n#define GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049\n#define GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX 0x904A\n#define GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX 0x904B\n#endif /* GL_NVX_gpu_memory_info */\n\n#ifndef GL_NVX_gpu_multicast2\n#define GL_NVX_gpu_multicast2 1\n#define GL_UPLOAD_GPU_MASK_NVX            0x954A\ntypedef void (APIENTRYP PFNGLUPLOADGPUMASKNVXPROC) (GLbitfield mask);\ntypedef void (APIENTRYP PFNGLMULTICASTVIEWPORTARRAYVNVXPROC) (GLuint gpu, GLuint first, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTICASTVIEWPORTPOSITIONWSCALENVXPROC) (GLuint gpu, GLuint index, GLfloat xcoeff, GLfloat ycoeff);\ntypedef void (APIENTRYP PFNGLMULTICASTSCISSORARRAYVNVXPROC) (GLuint gpu, GLuint first, GLsizei count, const GLint *v);\ntypedef GLuint (APIENTRYP PFNGLASYNCCOPYBUFFERSUBDATANVXPROC) (GLsizei waitSemaphoreCount, const GLuint *waitSemaphoreArray, const GLuint64 *fenceValueArray, GLuint readGpu, GLbitfield writeGpuMask, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size, GLsizei signalSemaphoreCount, const GLuint *signalSemaphoreArray, const GLuint64 *signalValueArray);\ntypedef GLuint (APIENTRYP PFNGLASYNCCOPYIMAGESUBDATANVXPROC) (GLsizei waitSemaphoreCount, const GLuint *waitSemaphoreArray, const GLuint64 *waitValueArray, GLuint srcGpu, GLbitfield dstGpuMask, 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, GLsizei signalSemaphoreCount, const GLuint *signalSemaphoreArray, const GLuint64 *signalValueArray);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glUploadGpuMaskNVX (GLbitfield mask);\nGLAPI void APIENTRY glMulticastViewportArrayvNVX (GLuint gpu, GLuint first, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glMulticastViewportPositionWScaleNVX (GLuint gpu, GLuint index, GLfloat xcoeff, GLfloat ycoeff);\nGLAPI void APIENTRY glMulticastScissorArrayvNVX (GLuint gpu, GLuint first, GLsizei count, const GLint *v);\nGLAPI GLuint APIENTRY glAsyncCopyBufferSubDataNVX (GLsizei waitSemaphoreCount, const GLuint *waitSemaphoreArray, const GLuint64 *fenceValueArray, GLuint readGpu, GLbitfield writeGpuMask, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size, GLsizei signalSemaphoreCount, const GLuint *signalSemaphoreArray, const GLuint64 *signalValueArray);\nGLAPI GLuint APIENTRY glAsyncCopyImageSubDataNVX (GLsizei waitSemaphoreCount, const GLuint *waitSemaphoreArray, const GLuint64 *waitValueArray, GLuint srcGpu, GLbitfield dstGpuMask, 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, GLsizei signalSemaphoreCount, const GLuint *signalSemaphoreArray, const GLuint64 *signalValueArray);\n#endif\n#endif /* GL_NVX_gpu_multicast2 */\n\n#ifndef GL_NVX_linked_gpu_multicast\n#define GL_NVX_linked_gpu_multicast 1\n#define GL_LGPU_SEPARATE_STORAGE_BIT_NVX  0x0800\n#define GL_MAX_LGPU_GPUS_NVX              0x92BA\ntypedef void (APIENTRYP PFNGLLGPUNAMEDBUFFERSUBDATANVXPROC) (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);\ntypedef void (APIENTRYP PFNGLLGPUCOPYIMAGESUBDATANVXPROC) (GLuint sourceGpu, GLbitfield destinationGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srxY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);\ntypedef void (APIENTRYP PFNGLLGPUINTERLOCKNVXPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glLGPUNamedBufferSubDataNVX (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);\nGLAPI void APIENTRY glLGPUCopyImageSubDataNVX (GLuint sourceGpu, GLbitfield destinationGpuMask, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srxY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);\nGLAPI void APIENTRY glLGPUInterlockNVX (void);\n#endif\n#endif /* GL_NVX_linked_gpu_multicast */\n\n#ifndef GL_NVX_progress_fence\n#define GL_NVX_progress_fence 1\ntypedef GLuint (APIENTRYP PFNGLCREATEPROGRESSFENCENVXPROC) (void);\ntypedef void (APIENTRYP PFNGLSIGNALSEMAPHOREUI64NVXPROC) (GLuint signalGpu, GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray);\ntypedef void (APIENTRYP PFNGLWAITSEMAPHOREUI64NVXPROC) (GLuint waitGpu, GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray);\ntypedef void (APIENTRYP PFNGLCLIENTWAITSEMAPHOREUI64NVXPROC) (GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLuint APIENTRY glCreateProgressFenceNVX (void);\nGLAPI void APIENTRY glSignalSemaphoreui64NVX (GLuint signalGpu, GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray);\nGLAPI void APIENTRY glWaitSemaphoreui64NVX (GLuint waitGpu, GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray);\nGLAPI void APIENTRY glClientWaitSemaphoreui64NVX (GLsizei fenceObjectCount, const GLuint *semaphoreArray, const GLuint64 *fenceValueArray);\n#endif\n#endif /* GL_NVX_progress_fence */\n\n#ifndef GL_NV_alpha_to_coverage_dither_control\n#define GL_NV_alpha_to_coverage_dither_control 1\n#define GL_ALPHA_TO_COVERAGE_DITHER_DEFAULT_NV 0x934D\n#define GL_ALPHA_TO_COVERAGE_DITHER_ENABLE_NV 0x934E\n#define GL_ALPHA_TO_COVERAGE_DITHER_DISABLE_NV 0x934F\n#define GL_ALPHA_TO_COVERAGE_DITHER_MODE_NV 0x92BF\ntypedef void (APIENTRYP PFNGLALPHATOCOVERAGEDITHERCONTROLNVPROC) (GLenum mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glAlphaToCoverageDitherControlNV (GLenum mode);\n#endif\n#endif /* GL_NV_alpha_to_coverage_dither_control */\n\n#ifndef GL_NV_bindless_multi_draw_indirect\n#define GL_NV_bindless_multi_draw_indirect 1\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMultiDrawArraysIndirectBindlessNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);\nGLAPI void APIENTRY glMultiDrawElementsIndirectBindlessNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount);\n#endif\n#endif /* GL_NV_bindless_multi_draw_indirect */\n\n#ifndef GL_NV_bindless_multi_draw_indirect_count\n#define GL_NV_bindless_multi_draw_indirect_count 1\ntypedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount);\ntypedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSCOUNTNVPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMultiDrawArraysIndirectBindlessCountNV (GLenum mode, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount);\nGLAPI void APIENTRY glMultiDrawElementsIndirectBindlessCountNV (GLenum mode, GLenum type, const void *indirect, GLsizei drawCount, GLsizei maxDrawCount, GLsizei stride, GLint vertexBufferCount);\n#endif\n#endif /* GL_NV_bindless_multi_draw_indirect_count */\n\n#ifndef GL_NV_bindless_texture\n#define GL_NV_bindless_texture 1\ntypedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLENVPROC) (GLuint texture);\ntypedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLENVPROC) (GLuint texture, GLuint sampler);\ntypedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle);\ntypedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTNVPROC) (GLuint64 handle);\ntypedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLENVPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);\ntypedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle, GLenum access);\ntypedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTNVPROC) (GLuint64 handle);\ntypedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64NVPROC) (GLint location, GLuint64 value);\ntypedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsizei count, const GLuint64 *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64NVPROC) (GLuint program, GLint location, GLuint64 value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);\ntypedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTNVPROC) (GLuint64 handle);\ntypedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTNVPROC) (GLuint64 handle);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLuint64 APIENTRY glGetTextureHandleNV (GLuint texture);\nGLAPI GLuint64 APIENTRY glGetTextureSamplerHandleNV (GLuint texture, GLuint sampler);\nGLAPI void APIENTRY glMakeTextureHandleResidentNV (GLuint64 handle);\nGLAPI void APIENTRY glMakeTextureHandleNonResidentNV (GLuint64 handle);\nGLAPI GLuint64 APIENTRY glGetImageHandleNV (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);\nGLAPI void APIENTRY glMakeImageHandleResidentNV (GLuint64 handle, GLenum access);\nGLAPI void APIENTRY glMakeImageHandleNonResidentNV (GLuint64 handle);\nGLAPI void APIENTRY glUniformHandleui64NV (GLint location, GLuint64 value);\nGLAPI void APIENTRY glUniformHandleui64vNV (GLint location, GLsizei count, const GLuint64 *value);\nGLAPI void APIENTRY glProgramUniformHandleui64NV (GLuint program, GLint location, GLuint64 value);\nGLAPI void APIENTRY glProgramUniformHandleui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64 *values);\nGLAPI GLboolean APIENTRY glIsTextureHandleResidentNV (GLuint64 handle);\nGLAPI GLboolean APIENTRY glIsImageHandleResidentNV (GLuint64 handle);\n#endif\n#endif /* GL_NV_bindless_texture */\n\n#ifndef GL_NV_blend_equation_advanced\n#define GL_NV_blend_equation_advanced 1\n#define GL_BLEND_OVERLAP_NV               0x9281\n#define GL_BLEND_PREMULTIPLIED_SRC_NV     0x9280\n#define GL_BLUE_NV                        0x1905\n#define GL_COLORBURN_NV                   0x929A\n#define GL_COLORDODGE_NV                  0x9299\n#define GL_CONJOINT_NV                    0x9284\n#define GL_CONTRAST_NV                    0x92A1\n#define GL_DARKEN_NV                      0x9297\n#define GL_DIFFERENCE_NV                  0x929E\n#define GL_DISJOINT_NV                    0x9283\n#define GL_DST_ATOP_NV                    0x928F\n#define GL_DST_IN_NV                      0x928B\n#define GL_DST_NV                         0x9287\n#define GL_DST_OUT_NV                     0x928D\n#define GL_DST_OVER_NV                    0x9289\n#define GL_EXCLUSION_NV                   0x92A0\n#define GL_GREEN_NV                       0x1904\n#define GL_HARDLIGHT_NV                   0x929B\n#define GL_HARDMIX_NV                     0x92A9\n#define GL_HSL_COLOR_NV                   0x92AF\n#define GL_HSL_HUE_NV                     0x92AD\n#define GL_HSL_LUMINOSITY_NV              0x92B0\n#define GL_HSL_SATURATION_NV              0x92AE\n#define GL_INVERT_OVG_NV                  0x92B4\n#define GL_INVERT_RGB_NV                  0x92A3\n#define GL_LIGHTEN_NV                     0x9298\n#define GL_LINEARBURN_NV                  0x92A5\n#define GL_LINEARDODGE_NV                 0x92A4\n#define GL_LINEARLIGHT_NV                 0x92A7\n#define GL_MINUS_CLAMPED_NV               0x92B3\n#define GL_MINUS_NV                       0x929F\n#define GL_MULTIPLY_NV                    0x9294\n#define GL_OVERLAY_NV                     0x9296\n#define GL_PINLIGHT_NV                    0x92A8\n#define GL_PLUS_CLAMPED_ALPHA_NV          0x92B2\n#define GL_PLUS_CLAMPED_NV                0x92B1\n#define GL_PLUS_DARKER_NV                 0x9292\n#define GL_PLUS_NV                        0x9291\n#define GL_RED_NV                         0x1903\n#define GL_SCREEN_NV                      0x9295\n#define GL_SOFTLIGHT_NV                   0x929C\n#define GL_SRC_ATOP_NV                    0x928E\n#define GL_SRC_IN_NV                      0x928A\n#define GL_SRC_NV                         0x9286\n#define GL_SRC_OUT_NV                     0x928C\n#define GL_SRC_OVER_NV                    0x9288\n#define GL_UNCORRELATED_NV                0x9282\n#define GL_VIVIDLIGHT_NV                  0x92A6\n#define GL_XOR_NV                         0x1506\ntypedef void (APIENTRYP PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value);\ntypedef void (APIENTRYP PFNGLBLENDBARRIERNVPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBlendParameteriNV (GLenum pname, GLint value);\nGLAPI void APIENTRY glBlendBarrierNV (void);\n#endif\n#endif /* GL_NV_blend_equation_advanced */\n\n#ifndef GL_NV_blend_equation_advanced_coherent\n#define GL_NV_blend_equation_advanced_coherent 1\n#define GL_BLEND_ADVANCED_COHERENT_NV     0x9285\n#endif /* GL_NV_blend_equation_advanced_coherent */\n\n#ifndef GL_NV_blend_minmax_factor\n#define GL_NV_blend_minmax_factor 1\n#endif /* GL_NV_blend_minmax_factor */\n\n#ifndef GL_NV_blend_square\n#define GL_NV_blend_square 1\n#endif /* GL_NV_blend_square */\n\n#ifndef GL_NV_clip_space_w_scaling\n#define GL_NV_clip_space_w_scaling 1\n#define GL_VIEWPORT_POSITION_W_SCALE_NV   0x937C\n#define GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV 0x937D\n#define GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV 0x937E\ntypedef void (APIENTRYP PFNGLVIEWPORTPOSITIONWSCALENVPROC) (GLuint index, GLfloat xcoeff, GLfloat ycoeff);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glViewportPositionWScaleNV (GLuint index, GLfloat xcoeff, GLfloat ycoeff);\n#endif\n#endif /* GL_NV_clip_space_w_scaling */\n\n#ifndef GL_NV_command_list\n#define GL_NV_command_list 1\n#define GL_TERMINATE_SEQUENCE_COMMAND_NV  0x0000\n#define GL_NOP_COMMAND_NV                 0x0001\n#define GL_DRAW_ELEMENTS_COMMAND_NV       0x0002\n#define GL_DRAW_ARRAYS_COMMAND_NV         0x0003\n#define GL_DRAW_ELEMENTS_STRIP_COMMAND_NV 0x0004\n#define GL_DRAW_ARRAYS_STRIP_COMMAND_NV   0x0005\n#define GL_DRAW_ELEMENTS_INSTANCED_COMMAND_NV 0x0006\n#define GL_DRAW_ARRAYS_INSTANCED_COMMAND_NV 0x0007\n#define GL_ELEMENT_ADDRESS_COMMAND_NV     0x0008\n#define GL_ATTRIBUTE_ADDRESS_COMMAND_NV   0x0009\n#define GL_UNIFORM_ADDRESS_COMMAND_NV     0x000A\n#define GL_BLEND_COLOR_COMMAND_NV         0x000B\n#define GL_STENCIL_REF_COMMAND_NV         0x000C\n#define GL_LINE_WIDTH_COMMAND_NV          0x000D\n#define GL_POLYGON_OFFSET_COMMAND_NV      0x000E\n#define GL_ALPHA_REF_COMMAND_NV           0x000F\n#define GL_VIEWPORT_COMMAND_NV            0x0010\n#define GL_SCISSOR_COMMAND_NV             0x0011\n#define GL_FRONT_FACE_COMMAND_NV          0x0012\ntypedef void (APIENTRYP PFNGLCREATESTATESNVPROC) (GLsizei n, GLuint *states);\ntypedef void (APIENTRYP PFNGLDELETESTATESNVPROC) (GLsizei n, const GLuint *states);\ntypedef GLboolean (APIENTRYP PFNGLISSTATENVPROC) (GLuint state);\ntypedef void (APIENTRYP PFNGLSTATECAPTURENVPROC) (GLuint state, GLenum mode);\ntypedef GLuint (APIENTRYP PFNGLGETCOMMANDHEADERNVPROC) (GLenum tokenID, GLuint size);\ntypedef GLushort (APIENTRYP PFNGLGETSTAGEINDEXNVPROC) (GLenum shadertype);\ntypedef void (APIENTRYP PFNGLDRAWCOMMANDSNVPROC) (GLenum primitiveMode, GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, GLuint count);\ntypedef void (APIENTRYP PFNGLDRAWCOMMANDSADDRESSNVPROC) (GLenum primitiveMode, const GLuint64 *indirects, const GLsizei *sizes, GLuint count);\ntypedef void (APIENTRYP PFNGLDRAWCOMMANDSSTATESNVPROC) (GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);\ntypedef void (APIENTRYP PFNGLDRAWCOMMANDSSTATESADDRESSNVPROC) (const GLuint64 *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);\ntypedef void (APIENTRYP PFNGLCREATECOMMANDLISTSNVPROC) (GLsizei n, GLuint *lists);\ntypedef void (APIENTRYP PFNGLDELETECOMMANDLISTSNVPROC) (GLsizei n, const GLuint *lists);\ntypedef GLboolean (APIENTRYP PFNGLISCOMMANDLISTNVPROC) (GLuint list);\ntypedef void (APIENTRYP PFNGLLISTDRAWCOMMANDSSTATESCLIENTNVPROC) (GLuint list, GLuint segment, const void **indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);\ntypedef void (APIENTRYP PFNGLCOMMANDLISTSEGMENTSNVPROC) (GLuint list, GLuint segments);\ntypedef void (APIENTRYP PFNGLCOMPILECOMMANDLISTNVPROC) (GLuint list);\ntypedef void (APIENTRYP PFNGLCALLCOMMANDLISTNVPROC) (GLuint list);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCreateStatesNV (GLsizei n, GLuint *states);\nGLAPI void APIENTRY glDeleteStatesNV (GLsizei n, const GLuint *states);\nGLAPI GLboolean APIENTRY glIsStateNV (GLuint state);\nGLAPI void APIENTRY glStateCaptureNV (GLuint state, GLenum mode);\nGLAPI GLuint APIENTRY glGetCommandHeaderNV (GLenum tokenID, GLuint size);\nGLAPI GLushort APIENTRY glGetStageIndexNV (GLenum shadertype);\nGLAPI void APIENTRY glDrawCommandsNV (GLenum primitiveMode, GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, GLuint count);\nGLAPI void APIENTRY glDrawCommandsAddressNV (GLenum primitiveMode, const GLuint64 *indirects, const GLsizei *sizes, GLuint count);\nGLAPI void APIENTRY glDrawCommandsStatesNV (GLuint buffer, const GLintptr *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);\nGLAPI void APIENTRY glDrawCommandsStatesAddressNV (const GLuint64 *indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);\nGLAPI void APIENTRY glCreateCommandListsNV (GLsizei n, GLuint *lists);\nGLAPI void APIENTRY glDeleteCommandListsNV (GLsizei n, const GLuint *lists);\nGLAPI GLboolean APIENTRY glIsCommandListNV (GLuint list);\nGLAPI void APIENTRY glListDrawCommandsStatesClientNV (GLuint list, GLuint segment, const void **indirects, const GLsizei *sizes, const GLuint *states, const GLuint *fbos, GLuint count);\nGLAPI void APIENTRY glCommandListSegmentsNV (GLuint list, GLuint segments);\nGLAPI void APIENTRY glCompileCommandListNV (GLuint list);\nGLAPI void APIENTRY glCallCommandListNV (GLuint list);\n#endif\n#endif /* GL_NV_command_list */\n\n#ifndef GL_NV_compute_program5\n#define GL_NV_compute_program5 1\n#define GL_COMPUTE_PROGRAM_NV             0x90FB\n#define GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV 0x90FC\n#endif /* GL_NV_compute_program5 */\n\n#ifndef GL_NV_compute_shader_derivatives\n#define GL_NV_compute_shader_derivatives 1\n#endif /* GL_NV_compute_shader_derivatives */\n\n#ifndef GL_NV_conditional_render\n#define GL_NV_conditional_render 1\n#define GL_QUERY_WAIT_NV                  0x8E13\n#define GL_QUERY_NO_WAIT_NV               0x8E14\n#define GL_QUERY_BY_REGION_WAIT_NV        0x8E15\n#define GL_QUERY_BY_REGION_NO_WAIT_NV     0x8E16\ntypedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERNVPROC) (GLuint id, GLenum mode);\ntypedef void (APIENTRYP PFNGLENDCONDITIONALRENDERNVPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBeginConditionalRenderNV (GLuint id, GLenum mode);\nGLAPI void APIENTRY glEndConditionalRenderNV (void);\n#endif\n#endif /* GL_NV_conditional_render */\n\n#ifndef GL_NV_conservative_raster\n#define GL_NV_conservative_raster 1\n#define GL_CONSERVATIVE_RASTERIZATION_NV  0x9346\n#define GL_SUBPIXEL_PRECISION_BIAS_X_BITS_NV 0x9347\n#define GL_SUBPIXEL_PRECISION_BIAS_Y_BITS_NV 0x9348\n#define GL_MAX_SUBPIXEL_PRECISION_BIAS_BITS_NV 0x9349\ntypedef void (APIENTRYP PFNGLSUBPIXELPRECISIONBIASNVPROC) (GLuint xbits, GLuint ybits);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSubpixelPrecisionBiasNV (GLuint xbits, GLuint ybits);\n#endif\n#endif /* GL_NV_conservative_raster */\n\n#ifndef GL_NV_conservative_raster_dilate\n#define GL_NV_conservative_raster_dilate 1\n#define GL_CONSERVATIVE_RASTER_DILATE_NV  0x9379\n#define GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV 0x937A\n#define GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV 0x937B\ntypedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERFNVPROC) (GLenum pname, GLfloat value);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glConservativeRasterParameterfNV (GLenum pname, GLfloat value);\n#endif\n#endif /* GL_NV_conservative_raster_dilate */\n\n#ifndef GL_NV_conservative_raster_pre_snap\n#define GL_NV_conservative_raster_pre_snap 1\n#define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_NV 0x9550\n#endif /* GL_NV_conservative_raster_pre_snap */\n\n#ifndef GL_NV_conservative_raster_pre_snap_triangles\n#define GL_NV_conservative_raster_pre_snap_triangles 1\n#define GL_CONSERVATIVE_RASTER_MODE_NV    0x954D\n#define GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV 0x954E\n#define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV 0x954F\ntypedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERINVPROC) (GLenum pname, GLint param);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glConservativeRasterParameteriNV (GLenum pname, GLint param);\n#endif\n#endif /* GL_NV_conservative_raster_pre_snap_triangles */\n\n#ifndef GL_NV_conservative_raster_underestimation\n#define GL_NV_conservative_raster_underestimation 1\n#endif /* GL_NV_conservative_raster_underestimation */\n\n#ifndef GL_NV_copy_depth_to_color\n#define GL_NV_copy_depth_to_color 1\n#define GL_DEPTH_STENCIL_TO_RGBA_NV       0x886E\n#define GL_DEPTH_STENCIL_TO_BGRA_NV       0x886F\n#endif /* GL_NV_copy_depth_to_color */\n\n#ifndef GL_NV_copy_image\n#define GL_NV_copy_image 1\ntypedef void (APIENTRYP PFNGLCOPYIMAGESUBDATANVPROC) (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 width, GLsizei height, GLsizei depth);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCopyImageSubDataNV (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 width, GLsizei height, GLsizei depth);\n#endif\n#endif /* GL_NV_copy_image */\n\n#ifndef GL_NV_deep_texture3D\n#define GL_NV_deep_texture3D 1\n#define GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV 0x90D0\n#define GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV   0x90D1\n#endif /* GL_NV_deep_texture3D */\n\n#ifndef GL_NV_depth_buffer_float\n#define GL_NV_depth_buffer_float 1\n#define GL_DEPTH_COMPONENT32F_NV          0x8DAB\n#define GL_DEPTH32F_STENCIL8_NV           0x8DAC\n#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV_NV 0x8DAD\n#define GL_DEPTH_BUFFER_FLOAT_MODE_NV     0x8DAF\ntypedef void (APIENTRYP PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFar);\ntypedef void (APIENTRYP PFNGLCLEARDEPTHDNVPROC) (GLdouble depth);\ntypedef void (APIENTRYP PFNGLDEPTHBOUNDSDNVPROC) (GLdouble zmin, GLdouble zmax);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDepthRangedNV (GLdouble zNear, GLdouble zFar);\nGLAPI void APIENTRY glClearDepthdNV (GLdouble depth);\nGLAPI void APIENTRY glDepthBoundsdNV (GLdouble zmin, GLdouble zmax);\n#endif\n#endif /* GL_NV_depth_buffer_float */\n\n#ifndef GL_NV_depth_clamp\n#define GL_NV_depth_clamp 1\n#define GL_DEPTH_CLAMP_NV                 0x864F\n#endif /* GL_NV_depth_clamp */\n\n#ifndef GL_NV_draw_texture\n#define GL_NV_draw_texture 1\ntypedef void (APIENTRYP PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawTextureNV (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);\n#endif\n#endif /* GL_NV_draw_texture */\n\n#ifndef GL_NV_draw_vulkan_image\n#define GL_NV_draw_vulkan_image 1\ntypedef void (APIENTRY  *GLVULKANPROCNV)(void);\ntypedef void (APIENTRYP PFNGLDRAWVKIMAGENVPROC) (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);\ntypedef GLVULKANPROCNV (APIENTRYP PFNGLGETVKPROCADDRNVPROC) (const GLchar *name);\ntypedef void (APIENTRYP PFNGLWAITVKSEMAPHORENVPROC) (GLuint64 vkSemaphore);\ntypedef void (APIENTRYP PFNGLSIGNALVKSEMAPHORENVPROC) (GLuint64 vkSemaphore);\ntypedef void (APIENTRYP PFNGLSIGNALVKFENCENVPROC) (GLuint64 vkFence);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawVkImageNV (GLuint64 vkImage, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1);\nGLAPI GLVULKANPROCNV APIENTRY glGetVkProcAddrNV (const GLchar *name);\nGLAPI void APIENTRY glWaitVkSemaphoreNV (GLuint64 vkSemaphore);\nGLAPI void APIENTRY glSignalVkSemaphoreNV (GLuint64 vkSemaphore);\nGLAPI void APIENTRY glSignalVkFenceNV (GLuint64 vkFence);\n#endif\n#endif /* GL_NV_draw_vulkan_image */\n\n#ifndef GL_NV_evaluators\n#define GL_NV_evaluators 1\n#define GL_EVAL_2D_NV                     0x86C0\n#define GL_EVAL_TRIANGULAR_2D_NV          0x86C1\n#define GL_MAP_TESSELLATION_NV            0x86C2\n#define GL_MAP_ATTRIB_U_ORDER_NV          0x86C3\n#define GL_MAP_ATTRIB_V_ORDER_NV          0x86C4\n#define GL_EVAL_FRACTIONAL_TESSELLATION_NV 0x86C5\n#define GL_EVAL_VERTEX_ATTRIB0_NV         0x86C6\n#define GL_EVAL_VERTEX_ATTRIB1_NV         0x86C7\n#define GL_EVAL_VERTEX_ATTRIB2_NV         0x86C8\n#define GL_EVAL_VERTEX_ATTRIB3_NV         0x86C9\n#define GL_EVAL_VERTEX_ATTRIB4_NV         0x86CA\n#define GL_EVAL_VERTEX_ATTRIB5_NV         0x86CB\n#define GL_EVAL_VERTEX_ATTRIB6_NV         0x86CC\n#define GL_EVAL_VERTEX_ATTRIB7_NV         0x86CD\n#define GL_EVAL_VERTEX_ATTRIB8_NV         0x86CE\n#define GL_EVAL_VERTEX_ATTRIB9_NV         0x86CF\n#define GL_EVAL_VERTEX_ATTRIB10_NV        0x86D0\n#define GL_EVAL_VERTEX_ATTRIB11_NV        0x86D1\n#define GL_EVAL_VERTEX_ATTRIB12_NV        0x86D2\n#define GL_EVAL_VERTEX_ATTRIB13_NV        0x86D3\n#define GL_EVAL_VERTEX_ATTRIB14_NV        0x86D4\n#define GL_EVAL_VERTEX_ATTRIB15_NV        0x86D5\n#define GL_MAX_MAP_TESSELLATION_NV        0x86D6\n#define GL_MAX_RATIONAL_EVAL_ORDER_NV     0x86D7\ntypedef void (APIENTRYP PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points);\ntypedef void (APIENTRYP PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points);\ntypedef void (APIENTRYP PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void *points);\nGLAPI void APIENTRY glMapParameterivNV (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glMapParameterfvNV (GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glGetMapControlPointsNV (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void *points);\nGLAPI void APIENTRY glGetMapParameterivNV (GLenum target, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetMapParameterfvNV (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetMapAttribParameterivNV (GLenum target, GLuint index, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetMapAttribParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glEvalMapsNV (GLenum target, GLenum mode);\n#endif\n#endif /* GL_NV_evaluators */\n\n#ifndef GL_NV_explicit_multisample\n#define GL_NV_explicit_multisample 1\n#define GL_SAMPLE_POSITION_NV             0x8E50\n#define GL_SAMPLE_MASK_NV                 0x8E51\n#define GL_SAMPLE_MASK_VALUE_NV           0x8E52\n#define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53\n#define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54\n#define GL_TEXTURE_RENDERBUFFER_NV        0x8E55\n#define GL_SAMPLER_RENDERBUFFER_NV        0x8E56\n#define GL_INT_SAMPLER_RENDERBUFFER_NV    0x8E57\n#define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58\n#define GL_MAX_SAMPLE_MASK_WORDS_NV       0x8E59\ntypedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val);\ntypedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask);\ntypedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetMultisamplefvNV (GLenum pname, GLuint index, GLfloat *val);\nGLAPI void APIENTRY glSampleMaskIndexedNV (GLuint index, GLbitfield mask);\nGLAPI void APIENTRY glTexRenderbufferNV (GLenum target, GLuint renderbuffer);\n#endif\n#endif /* GL_NV_explicit_multisample */\n\n#ifndef GL_NV_fence\n#define GL_NV_fence 1\n#define GL_ALL_COMPLETED_NV               0x84F2\n#define GL_FENCE_STATUS_NV                0x84F3\n#define GL_FENCE_CONDITION_NV             0x84F4\ntypedef void (APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);\ntypedef void (APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);\ntypedef GLboolean (APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);\ntypedef GLboolean (APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);\ntypedef void (APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);\ntypedef void (APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDeleteFencesNV (GLsizei n, const GLuint *fences);\nGLAPI void APIENTRY glGenFencesNV (GLsizei n, GLuint *fences);\nGLAPI GLboolean APIENTRY glIsFenceNV (GLuint fence);\nGLAPI GLboolean APIENTRY glTestFenceNV (GLuint fence);\nGLAPI void APIENTRY glGetFenceivNV (GLuint fence, GLenum pname, GLint *params);\nGLAPI void APIENTRY glFinishFenceNV (GLuint fence);\nGLAPI void APIENTRY glSetFenceNV (GLuint fence, GLenum condition);\n#endif\n#endif /* GL_NV_fence */\n\n#ifndef GL_NV_fill_rectangle\n#define GL_NV_fill_rectangle 1\n#define GL_FILL_RECTANGLE_NV              0x933C\n#endif /* GL_NV_fill_rectangle */\n\n#ifndef GL_NV_float_buffer\n#define GL_NV_float_buffer 1\n#define GL_FLOAT_R_NV                     0x8880\n#define GL_FLOAT_RG_NV                    0x8881\n#define GL_FLOAT_RGB_NV                   0x8882\n#define GL_FLOAT_RGBA_NV                  0x8883\n#define GL_FLOAT_R16_NV                   0x8884\n#define GL_FLOAT_R32_NV                   0x8885\n#define GL_FLOAT_RG16_NV                  0x8886\n#define GL_FLOAT_RG32_NV                  0x8887\n#define GL_FLOAT_RGB16_NV                 0x8888\n#define GL_FLOAT_RGB32_NV                 0x8889\n#define GL_FLOAT_RGBA16_NV                0x888A\n#define GL_FLOAT_RGBA32_NV                0x888B\n#define GL_TEXTURE_FLOAT_COMPONENTS_NV    0x888C\n#define GL_FLOAT_CLEAR_COLOR_VALUE_NV     0x888D\n#define GL_FLOAT_RGBA_MODE_NV             0x888E\n#endif /* GL_NV_float_buffer */\n\n#ifndef GL_NV_fog_distance\n#define GL_NV_fog_distance 1\n#define GL_FOG_DISTANCE_MODE_NV           0x855A\n#define GL_EYE_RADIAL_NV                  0x855B\n#define GL_EYE_PLANE_ABSOLUTE_NV          0x855C\n#endif /* GL_NV_fog_distance */\n\n#ifndef GL_NV_fragment_coverage_to_color\n#define GL_NV_fragment_coverage_to_color 1\n#define GL_FRAGMENT_COVERAGE_TO_COLOR_NV  0x92DD\n#define GL_FRAGMENT_COVERAGE_COLOR_NV     0x92DE\ntypedef void (APIENTRYP PFNGLFRAGMENTCOVERAGECOLORNVPROC) (GLuint color);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFragmentCoverageColorNV (GLuint color);\n#endif\n#endif /* GL_NV_fragment_coverage_to_color */\n\n#ifndef GL_NV_fragment_program\n#define GL_NV_fragment_program 1\n#define GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV 0x8868\n#define GL_FRAGMENT_PROGRAM_NV            0x8870\n#define GL_MAX_TEXTURE_COORDS_NV          0x8871\n#define GL_MAX_TEXTURE_IMAGE_UNITS_NV     0x8872\n#define GL_FRAGMENT_PROGRAM_BINDING_NV    0x8873\n#define GL_PROGRAM_ERROR_STRING_NV        0x8874\ntypedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4FVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLPROGRAMNAMEDPARAMETER4DVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERFVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMNAMEDPARAMETERDVNVPROC) (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProgramNamedParameter4fNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glProgramNamedParameter4fvNV (GLuint id, GLsizei len, const GLubyte *name, const GLfloat *v);\nGLAPI void APIENTRY glProgramNamedParameter4dNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glProgramNamedParameter4dvNV (GLuint id, GLsizei len, const GLubyte *name, const GLdouble *v);\nGLAPI void APIENTRY glGetProgramNamedParameterfvNV (GLuint id, GLsizei len, const GLubyte *name, GLfloat *params);\nGLAPI void APIENTRY glGetProgramNamedParameterdvNV (GLuint id, GLsizei len, const GLubyte *name, GLdouble *params);\n#endif\n#endif /* GL_NV_fragment_program */\n\n#ifndef GL_NV_fragment_program2\n#define GL_NV_fragment_program2 1\n#define GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV 0x88F4\n#define GL_MAX_PROGRAM_CALL_DEPTH_NV      0x88F5\n#define GL_MAX_PROGRAM_IF_DEPTH_NV        0x88F6\n#define GL_MAX_PROGRAM_LOOP_DEPTH_NV      0x88F7\n#define GL_MAX_PROGRAM_LOOP_COUNT_NV      0x88F8\n#endif /* GL_NV_fragment_program2 */\n\n#ifndef GL_NV_fragment_program4\n#define GL_NV_fragment_program4 1\n#endif /* GL_NV_fragment_program4 */\n\n#ifndef GL_NV_fragment_program_option\n#define GL_NV_fragment_program_option 1\n#endif /* GL_NV_fragment_program_option */\n\n#ifndef GL_NV_fragment_shader_barycentric\n#define GL_NV_fragment_shader_barycentric 1\n#endif /* GL_NV_fragment_shader_barycentric */\n\n#ifndef GL_NV_fragment_shader_interlock\n#define GL_NV_fragment_shader_interlock 1\n#endif /* GL_NV_fragment_shader_interlock */\n\n#ifndef GL_NV_framebuffer_mixed_samples\n#define GL_NV_framebuffer_mixed_samples 1\n#define GL_COVERAGE_MODULATION_TABLE_NV   0x9331\n#define GL_COLOR_SAMPLES_NV               0x8E20\n#define GL_DEPTH_SAMPLES_NV               0x932D\n#define GL_STENCIL_SAMPLES_NV             0x932E\n#define GL_MIXED_DEPTH_SAMPLES_SUPPORTED_NV 0x932F\n#define GL_MIXED_STENCIL_SAMPLES_SUPPORTED_NV 0x9330\n#define GL_COVERAGE_MODULATION_NV         0x9332\n#define GL_COVERAGE_MODULATION_TABLE_SIZE_NV 0x9333\ntypedef void (APIENTRYP PFNGLCOVERAGEMODULATIONTABLENVPROC) (GLsizei n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLGETCOVERAGEMODULATIONTABLENVPROC) (GLsizei bufSize, GLfloat *v);\ntypedef void (APIENTRYP PFNGLCOVERAGEMODULATIONNVPROC) (GLenum components);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCoverageModulationTableNV (GLsizei n, const GLfloat *v);\nGLAPI void APIENTRY glGetCoverageModulationTableNV (GLsizei bufSize, GLfloat *v);\nGLAPI void APIENTRY glCoverageModulationNV (GLenum components);\n#endif\n#endif /* GL_NV_framebuffer_mixed_samples */\n\n#ifndef GL_NV_framebuffer_multisample_coverage\n#define GL_NV_framebuffer_multisample_coverage 1\n#define GL_RENDERBUFFER_COVERAGE_SAMPLES_NV 0x8CAB\n#define GL_RENDERBUFFER_COLOR_SAMPLES_NV  0x8E10\n#define GL_MAX_MULTISAMPLE_COVERAGE_MODES_NV 0x8E11\n#define GL_MULTISAMPLE_COVERAGE_MODES_NV  0x8E12\ntypedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glRenderbufferStorageMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height);\n#endif\n#endif /* GL_NV_framebuffer_multisample_coverage */\n\n#ifndef GL_NV_geometry_program4\n#define GL_NV_geometry_program4 1\n#define GL_GEOMETRY_PROGRAM_NV            0x8C26\n#define GL_MAX_PROGRAM_OUTPUT_VERTICES_NV 0x8C27\n#define GL_MAX_PROGRAM_TOTAL_OUTPUT_COMPONENTS_NV 0x8C28\ntypedef void (APIENTRYP PFNGLPROGRAMVERTEXLIMITNVPROC) (GLenum target, GLint limit);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level);\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREFACEEXTPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProgramVertexLimitNV (GLenum target, GLint limit);\nGLAPI void APIENTRY glFramebufferTextureEXT (GLenum target, GLenum attachment, GLuint texture, GLint level);\nGLAPI void APIENTRY glFramebufferTextureFaceEXT (GLenum target, GLenum attachment, GLuint texture, GLint level, GLenum face);\n#endif\n#endif /* GL_NV_geometry_program4 */\n\n#ifndef GL_NV_geometry_shader4\n#define GL_NV_geometry_shader4 1\n#endif /* GL_NV_geometry_shader4 */\n\n#ifndef GL_NV_geometry_shader_passthrough\n#define GL_NV_geometry_shader_passthrough 1\n#endif /* GL_NV_geometry_shader_passthrough */\n\n#ifndef GL_NV_gpu_multicast\n#define GL_NV_gpu_multicast 1\n#define GL_PER_GPU_STORAGE_BIT_NV         0x0800\n#define GL_MULTICAST_GPUS_NV              0x92BA\n#define GL_RENDER_GPU_MASK_NV             0x9558\n#define GL_PER_GPU_STORAGE_NV             0x9548\n#define GL_MULTICAST_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9549\ntypedef void (APIENTRYP PFNGLRENDERGPUMASKNVPROC) (GLbitfield mask);\ntypedef void (APIENTRYP PFNGLMULTICASTBUFFERSUBDATANVPROC) (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);\ntypedef void (APIENTRYP PFNGLMULTICASTCOPYBUFFERSUBDATANVPROC) (GLuint readGpu, GLbitfield writeGpuMask, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLMULTICASTCOPYIMAGESUBDATANVPROC) (GLuint srcGpu, GLbitfield dstGpuMask, 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);\ntypedef void (APIENTRYP PFNGLMULTICASTBLITFRAMEBUFFERNVPROC) (GLuint srcGpu, GLuint dstGpu, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\ntypedef void (APIENTRYP PFNGLMULTICASTFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLuint gpu, GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLMULTICASTBARRIERNVPROC) (void);\ntypedef void (APIENTRYP PFNGLMULTICASTWAITSYNCNVPROC) (GLuint signalGpu, GLbitfield waitGpuMask);\ntypedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTIVNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTUIVNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTI64VNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLint64 *params);\ntypedef void (APIENTRYP PFNGLMULTICASTGETQUERYOBJECTUI64VNVPROC) (GLuint gpu, GLuint id, GLenum pname, GLuint64 *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glRenderGpuMaskNV (GLbitfield mask);\nGLAPI void APIENTRY glMulticastBufferSubDataNV (GLbitfield gpuMask, GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);\nGLAPI void APIENTRY glMulticastCopyBufferSubDataNV (GLuint readGpu, GLbitfield writeGpuMask, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\nGLAPI void APIENTRY glMulticastCopyImageSubDataNV (GLuint srcGpu, GLbitfield dstGpuMask, 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 void APIENTRY glMulticastBlitFramebufferNV (GLuint srcGpu, GLuint dstGpu, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\nGLAPI void APIENTRY glMulticastFramebufferSampleLocationsfvNV (GLuint gpu, GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glMulticastBarrierNV (void);\nGLAPI void APIENTRY glMulticastWaitSyncNV (GLuint signalGpu, GLbitfield waitGpuMask);\nGLAPI void APIENTRY glMulticastGetQueryObjectivNV (GLuint gpu, GLuint id, GLenum pname, GLint *params);\nGLAPI void APIENTRY glMulticastGetQueryObjectuivNV (GLuint gpu, GLuint id, GLenum pname, GLuint *params);\nGLAPI void APIENTRY glMulticastGetQueryObjecti64vNV (GLuint gpu, GLuint id, GLenum pname, GLint64 *params);\nGLAPI void APIENTRY glMulticastGetQueryObjectui64vNV (GLuint gpu, GLuint id, GLenum pname, GLuint64 *params);\n#endif\n#endif /* GL_NV_gpu_multicast */\n\n#ifndef GL_NV_gpu_program4\n#define GL_NV_gpu_program4 1\n#define GL_MIN_PROGRAM_TEXEL_OFFSET_NV    0x8904\n#define GL_MAX_PROGRAM_TEXEL_OFFSET_NV    0x8905\n#define GL_PROGRAM_ATTRIB_COMPONENTS_NV   0x8906\n#define GL_PROGRAM_RESULT_COMPONENTS_NV   0x8907\n#define GL_MAX_PROGRAM_ATTRIB_COMPONENTS_NV 0x8908\n#define GL_MAX_PROGRAM_RESULT_COMPONENTS_NV 0x8909\n#define GL_MAX_PROGRAM_GENERIC_ATTRIBS_NV 0x8DA5\n#define GL_MAX_PROGRAM_GENERIC_RESULTS_NV 0x8DA6\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4INVPROC) (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4IVNVPROC) (GLenum target, GLuint index, const GLint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4IVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UINVPROC) (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERI4UIVNVPROC) (GLenum target, GLuint index, const GLuint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMENVPARAMETERSI4UIVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLuint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMLOCALPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIIVNVPROC) (GLenum target, GLuint index, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMENVPARAMETERIUIVNVPROC) (GLenum target, GLuint index, GLuint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProgramLocalParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);\nGLAPI void APIENTRY glProgramLocalParameterI4ivNV (GLenum target, GLuint index, const GLint *params);\nGLAPI void APIENTRY glProgramLocalParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params);\nGLAPI void APIENTRY glProgramLocalParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\nGLAPI void APIENTRY glProgramLocalParameterI4uivNV (GLenum target, GLuint index, const GLuint *params);\nGLAPI void APIENTRY glProgramLocalParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params);\nGLAPI void APIENTRY glProgramEnvParameterI4iNV (GLenum target, GLuint index, GLint x, GLint y, GLint z, GLint w);\nGLAPI void APIENTRY glProgramEnvParameterI4ivNV (GLenum target, GLuint index, const GLint *params);\nGLAPI void APIENTRY glProgramEnvParametersI4ivNV (GLenum target, GLuint index, GLsizei count, const GLint *params);\nGLAPI void APIENTRY glProgramEnvParameterI4uiNV (GLenum target, GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\nGLAPI void APIENTRY glProgramEnvParameterI4uivNV (GLenum target, GLuint index, const GLuint *params);\nGLAPI void APIENTRY glProgramEnvParametersI4uivNV (GLenum target, GLuint index, GLsizei count, const GLuint *params);\nGLAPI void APIENTRY glGetProgramLocalParameterIivNV (GLenum target, GLuint index, GLint *params);\nGLAPI void APIENTRY glGetProgramLocalParameterIuivNV (GLenum target, GLuint index, GLuint *params);\nGLAPI void APIENTRY glGetProgramEnvParameterIivNV (GLenum target, GLuint index, GLint *params);\nGLAPI void APIENTRY glGetProgramEnvParameterIuivNV (GLenum target, GLuint index, GLuint *params);\n#endif\n#endif /* GL_NV_gpu_program4 */\n\n#ifndef GL_NV_gpu_program5\n#define GL_NV_gpu_program5 1\n#define GL_MAX_GEOMETRY_PROGRAM_INVOCATIONS_NV 0x8E5A\n#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5B\n#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET_NV 0x8E5C\n#define GL_FRAGMENT_PROGRAM_INTERPOLATION_OFFSET_BITS_NV 0x8E5D\n#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5E\n#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET_NV 0x8E5F\n#define GL_MAX_PROGRAM_SUBROUTINE_PARAMETERS_NV 0x8F44\n#define GL_MAX_PROGRAM_SUBROUTINE_NUM_NV  0x8F45\ntypedef void (APIENTRYP PFNGLPROGRAMSUBROUTINEPARAMETERSUIVNVPROC) (GLenum target, GLsizei count, const GLuint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMSUBROUTINEPARAMETERUIVNVPROC) (GLenum target, GLuint index, GLuint *param);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProgramSubroutineParametersuivNV (GLenum target, GLsizei count, const GLuint *params);\nGLAPI void APIENTRY glGetProgramSubroutineParameteruivNV (GLenum target, GLuint index, GLuint *param);\n#endif\n#endif /* GL_NV_gpu_program5 */\n\n#ifndef GL_NV_gpu_program5_mem_extended\n#define GL_NV_gpu_program5_mem_extended 1\n#endif /* GL_NV_gpu_program5_mem_extended */\n\n#ifndef GL_NV_gpu_shader5\n#define GL_NV_gpu_shader5 1\n#endif /* GL_NV_gpu_shader5 */\n\n#ifndef GL_NV_half_float\n#define GL_NV_half_float 1\ntypedef unsigned short GLhalfNV;\n#define GL_HALF_FLOAT_NV                  0x140B\ntypedef void (APIENTRYP PFNGLVERTEX2HNVPROC) (GLhalfNV x, GLhalfNV y);\ntypedef void (APIENTRYP PFNGLVERTEX2HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEX3HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z);\ntypedef void (APIENTRYP PFNGLVERTEX3HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEX4HNVPROC) (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);\ntypedef void (APIENTRYP PFNGLVERTEX4HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLNORMAL3HNVPROC) (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);\ntypedef void (APIENTRYP PFNGLNORMAL3HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);\ntypedef void (APIENTRYP PFNGLCOLOR3HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLCOLOR4HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);\ntypedef void (APIENTRYP PFNGLCOLOR4HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD1HNVPROC) (GLhalfNV s);\ntypedef void (APIENTRYP PFNGLTEXCOORD1HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2HNVPROC) (GLhalfNV s, GLhalfNV t);\ntypedef void (APIENTRYP PFNGLTEXCOORD2HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD3HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r);\ntypedef void (APIENTRYP PFNGLTEXCOORD3HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD4HNVPROC) (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);\ntypedef void (APIENTRYP PFNGLTEXCOORD4HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1HNVPROC) (GLenum target, GLhalfNV s);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD1HVNVPROC) (GLenum target, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD2HVNVPROC) (GLenum target, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD3HVNVPROC) (GLenum target, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4HNVPROC) (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);\ntypedef void (APIENTRYP PFNGLMULTITEXCOORD4HVNVPROC) (GLenum target, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLFOGCOORDHNVPROC) (GLhalfNV fog);\ntypedef void (APIENTRYP PFNGLFOGCOORDHVNVPROC) (const GLhalfNV *fog);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3HNVPROC) (GLhalfNV red, GLhalfNV green, GLhalfNV blue);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLOR3HVNVPROC) (const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXWEIGHTHNVPROC) (GLhalfNV weight);\ntypedef void (APIENTRYP PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalfNV *weight);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1HNVPROC) (GLuint index, GLhalfNV x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1HVNVPROC) (GLuint index, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2HVNVPROC) (GLuint index, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3HVNVPROC) (GLuint index, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4HNVPROC) (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4HVNVPROC) (GLuint index, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS1HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS2HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS3HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS4HVNVPROC) (GLuint index, GLsizei n, const GLhalfNV *v);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertex2hNV (GLhalfNV x, GLhalfNV y);\nGLAPI void APIENTRY glVertex2hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glVertex3hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z);\nGLAPI void APIENTRY glVertex3hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glVertex4hNV (GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);\nGLAPI void APIENTRY glVertex4hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glNormal3hNV (GLhalfNV nx, GLhalfNV ny, GLhalfNV nz);\nGLAPI void APIENTRY glNormal3hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue);\nGLAPI void APIENTRY glColor3hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glColor4hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue, GLhalfNV alpha);\nGLAPI void APIENTRY glColor4hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glTexCoord1hNV (GLhalfNV s);\nGLAPI void APIENTRY glTexCoord1hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glTexCoord2hNV (GLhalfNV s, GLhalfNV t);\nGLAPI void APIENTRY glTexCoord2hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glTexCoord3hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r);\nGLAPI void APIENTRY glTexCoord3hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glTexCoord4hNV (GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);\nGLAPI void APIENTRY glTexCoord4hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glMultiTexCoord1hNV (GLenum target, GLhalfNV s);\nGLAPI void APIENTRY glMultiTexCoord1hvNV (GLenum target, const GLhalfNV *v);\nGLAPI void APIENTRY glMultiTexCoord2hNV (GLenum target, GLhalfNV s, GLhalfNV t);\nGLAPI void APIENTRY glMultiTexCoord2hvNV (GLenum target, const GLhalfNV *v);\nGLAPI void APIENTRY glMultiTexCoord3hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r);\nGLAPI void APIENTRY glMultiTexCoord3hvNV (GLenum target, const GLhalfNV *v);\nGLAPI void APIENTRY glMultiTexCoord4hNV (GLenum target, GLhalfNV s, GLhalfNV t, GLhalfNV r, GLhalfNV q);\nGLAPI void APIENTRY glMultiTexCoord4hvNV (GLenum target, const GLhalfNV *v);\nGLAPI void APIENTRY glFogCoordhNV (GLhalfNV fog);\nGLAPI void APIENTRY glFogCoordhvNV (const GLhalfNV *fog);\nGLAPI void APIENTRY glSecondaryColor3hNV (GLhalfNV red, GLhalfNV green, GLhalfNV blue);\nGLAPI void APIENTRY glSecondaryColor3hvNV (const GLhalfNV *v);\nGLAPI void APIENTRY glVertexWeighthNV (GLhalfNV weight);\nGLAPI void APIENTRY glVertexWeighthvNV (const GLhalfNV *weight);\nGLAPI void APIENTRY glVertexAttrib1hNV (GLuint index, GLhalfNV x);\nGLAPI void APIENTRY glVertexAttrib1hvNV (GLuint index, const GLhalfNV *v);\nGLAPI void APIENTRY glVertexAttrib2hNV (GLuint index, GLhalfNV x, GLhalfNV y);\nGLAPI void APIENTRY glVertexAttrib2hvNV (GLuint index, const GLhalfNV *v);\nGLAPI void APIENTRY glVertexAttrib3hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z);\nGLAPI void APIENTRY glVertexAttrib3hvNV (GLuint index, const GLhalfNV *v);\nGLAPI void APIENTRY glVertexAttrib4hNV (GLuint index, GLhalfNV x, GLhalfNV y, GLhalfNV z, GLhalfNV w);\nGLAPI void APIENTRY glVertexAttrib4hvNV (GLuint index, const GLhalfNV *v);\nGLAPI void APIENTRY glVertexAttribs1hvNV (GLuint index, GLsizei n, const GLhalfNV *v);\nGLAPI void APIENTRY glVertexAttribs2hvNV (GLuint index, GLsizei n, const GLhalfNV *v);\nGLAPI void APIENTRY glVertexAttribs3hvNV (GLuint index, GLsizei n, const GLhalfNV *v);\nGLAPI void APIENTRY glVertexAttribs4hvNV (GLuint index, GLsizei n, const GLhalfNV *v);\n#endif\n#endif /* GL_NV_half_float */\n\n#ifndef GL_NV_internalformat_sample_query\n#define GL_NV_internalformat_sample_query 1\n#define GL_MULTISAMPLES_NV                0x9371\n#define GL_SUPERSAMPLE_SCALE_X_NV         0x9372\n#define GL_SUPERSAMPLE_SCALE_Y_NV         0x9373\n#define GL_CONFORMANT_NV                  0x9374\ntypedef void (APIENTRYP PFNGLGETINTERNALFORMATSAMPLEIVNVPROC) (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei count, GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetInternalformatSampleivNV (GLenum target, GLenum internalformat, GLsizei samples, GLenum pname, GLsizei count, GLint *params);\n#endif\n#endif /* GL_NV_internalformat_sample_query */\n\n#ifndef GL_NV_light_max_exponent\n#define GL_NV_light_max_exponent 1\n#define GL_MAX_SHININESS_NV               0x8504\n#define GL_MAX_SPOT_EXPONENT_NV           0x8505\n#endif /* GL_NV_light_max_exponent */\n\n#ifndef GL_NV_memory_attachment\n#define GL_NV_memory_attachment 1\n#define GL_ATTACHED_MEMORY_OBJECT_NV      0x95A4\n#define GL_ATTACHED_MEMORY_OFFSET_NV      0x95A5\n#define GL_MEMORY_ATTACHABLE_ALIGNMENT_NV 0x95A6\n#define GL_MEMORY_ATTACHABLE_SIZE_NV      0x95A7\n#define GL_MEMORY_ATTACHABLE_NV           0x95A8\n#define GL_DETACHED_MEMORY_INCARNATION_NV 0x95A9\n#define GL_DETACHED_TEXTURES_NV           0x95AA\n#define GL_DETACHED_BUFFERS_NV            0x95AB\n#define GL_MAX_DETACHED_TEXTURES_NV       0x95AC\n#define GL_MAX_DETACHED_BUFFERS_NV        0x95AD\ntypedef void (APIENTRYP PFNGLGETMEMORYOBJECTDETACHEDRESOURCESUIVNVPROC) (GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint *params);\ntypedef void (APIENTRYP PFNGLRESETMEMORYOBJECTPARAMETERNVPROC) (GLuint memory, GLenum pname);\ntypedef void (APIENTRYP PFNGLTEXATTACHMEMORYNVPROC) (GLenum target, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLBUFFERATTACHMEMORYNVPROC) (GLenum target, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLTEXTUREATTACHMEMORYNVPROC) (GLuint texture, GLuint memory, GLuint64 offset);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERATTACHMEMORYNVPROC) (GLuint buffer, GLuint memory, GLuint64 offset);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetMemoryObjectDetachedResourcesuivNV (GLuint memory, GLenum pname, GLint first, GLsizei count, GLuint *params);\nGLAPI void APIENTRY glResetMemoryObjectParameterNV (GLuint memory, GLenum pname);\nGLAPI void APIENTRY glTexAttachMemoryNV (GLenum target, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glBufferAttachMemoryNV (GLenum target, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glTextureAttachMemoryNV (GLuint texture, GLuint memory, GLuint64 offset);\nGLAPI void APIENTRY glNamedBufferAttachMemoryNV (GLuint buffer, GLuint memory, GLuint64 offset);\n#endif\n#endif /* GL_NV_memory_attachment */\n\n#ifndef GL_NV_memory_object_sparse\n#define GL_NV_memory_object_sparse 1\ntypedef void (APIENTRYP PFNGLBUFFERPAGECOMMITMENTMEMNVPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLuint memory, GLuint64 memOffset, GLboolean commit);\ntypedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTMEMNVPROC) (GLenum target, GLint layer, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset, GLboolean commit);\ntypedef void (APIENTRYP PFNGLNAMEDBUFFERPAGECOMMITMENTMEMNVPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLuint memory, GLuint64 memOffset, GLboolean commit);\ntypedef void (APIENTRYP PFNGLTEXTUREPAGECOMMITMENTMEMNVPROC) (GLuint texture, GLint layer, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset, GLboolean commit);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBufferPageCommitmentMemNV (GLenum target, GLintptr offset, GLsizeiptr size, GLuint memory, GLuint64 memOffset, GLboolean commit);\nGLAPI void APIENTRY glTexPageCommitmentMemNV (GLenum target, GLint layer, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset, GLboolean commit);\nGLAPI void APIENTRY glNamedBufferPageCommitmentMemNV (GLuint buffer, GLintptr offset, GLsizeiptr size, GLuint memory, GLuint64 memOffset, GLboolean commit);\nGLAPI void APIENTRY glTexturePageCommitmentMemNV (GLuint texture, GLint layer, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset, GLboolean commit);\n#endif\n#endif /* GL_NV_memory_object_sparse */\n\n#ifndef GL_NV_mesh_shader\n#define GL_NV_mesh_shader 1\n#define GL_MESH_SHADER_NV                 0x9559\n#define GL_TASK_SHADER_NV                 0x955A\n#define GL_MAX_MESH_UNIFORM_BLOCKS_NV     0x8E60\n#define GL_MAX_MESH_TEXTURE_IMAGE_UNITS_NV 0x8E61\n#define GL_MAX_MESH_IMAGE_UNIFORMS_NV     0x8E62\n#define GL_MAX_MESH_UNIFORM_COMPONENTS_NV 0x8E63\n#define GL_MAX_MESH_ATOMIC_COUNTER_BUFFERS_NV 0x8E64\n#define GL_MAX_MESH_ATOMIC_COUNTERS_NV    0x8E65\n#define GL_MAX_MESH_SHADER_STORAGE_BLOCKS_NV 0x8E66\n#define GL_MAX_COMBINED_MESH_UNIFORM_COMPONENTS_NV 0x8E67\n#define GL_MAX_TASK_UNIFORM_BLOCKS_NV     0x8E68\n#define GL_MAX_TASK_TEXTURE_IMAGE_UNITS_NV 0x8E69\n#define GL_MAX_TASK_IMAGE_UNIFORMS_NV     0x8E6A\n#define GL_MAX_TASK_UNIFORM_COMPONENTS_NV 0x8E6B\n#define GL_MAX_TASK_ATOMIC_COUNTER_BUFFERS_NV 0x8E6C\n#define GL_MAX_TASK_ATOMIC_COUNTERS_NV    0x8E6D\n#define GL_MAX_TASK_SHADER_STORAGE_BLOCKS_NV 0x8E6E\n#define GL_MAX_COMBINED_TASK_UNIFORM_COMPONENTS_NV 0x8E6F\n#define GL_MAX_MESH_WORK_GROUP_INVOCATIONS_NV 0x95A2\n#define GL_MAX_TASK_WORK_GROUP_INVOCATIONS_NV 0x95A3\n#define GL_MAX_MESH_TOTAL_MEMORY_SIZE_NV  0x9536\n#define GL_MAX_TASK_TOTAL_MEMORY_SIZE_NV  0x9537\n#define GL_MAX_MESH_OUTPUT_VERTICES_NV    0x9538\n#define GL_MAX_MESH_OUTPUT_PRIMITIVES_NV  0x9539\n#define GL_MAX_TASK_OUTPUT_COUNT_NV       0x953A\n#define GL_MAX_DRAW_MESH_TASKS_COUNT_NV   0x953D\n#define GL_MAX_MESH_VIEWS_NV              0x9557\n#define GL_MESH_OUTPUT_PER_VERTEX_GRANULARITY_NV 0x92DF\n#define GL_MESH_OUTPUT_PER_PRIMITIVE_GRANULARITY_NV 0x9543\n#define GL_MAX_MESH_WORK_GROUP_SIZE_NV    0x953B\n#define GL_MAX_TASK_WORK_GROUP_SIZE_NV    0x953C\n#define GL_MESH_WORK_GROUP_SIZE_NV        0x953E\n#define GL_TASK_WORK_GROUP_SIZE_NV        0x953F\n#define GL_MESH_VERTICES_OUT_NV           0x9579\n#define GL_MESH_PRIMITIVES_OUT_NV         0x957A\n#define GL_MESH_OUTPUT_TYPE_NV            0x957B\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_MESH_SHADER_NV 0x959C\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_TASK_SHADER_NV 0x959D\n#define GL_REFERENCED_BY_MESH_SHADER_NV   0x95A0\n#define GL_REFERENCED_BY_TASK_SHADER_NV   0x95A1\n#define GL_MESH_SHADER_BIT_NV             0x00000040\n#define GL_TASK_SHADER_BIT_NV             0x00000080\n#define GL_MESH_SUBROUTINE_NV             0x957C\n#define GL_TASK_SUBROUTINE_NV             0x957D\n#define GL_MESH_SUBROUTINE_UNIFORM_NV     0x957E\n#define GL_TASK_SUBROUTINE_UNIFORM_NV     0x957F\n#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_MESH_SHADER_NV 0x959E\n#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TASK_SHADER_NV 0x959F\ntypedef void (APIENTRYP PFNGLDRAWMESHTASKSNVPROC) (GLuint first, GLuint count);\ntypedef void (APIENTRYP PFNGLDRAWMESHTASKSINDIRECTNVPROC) (GLintptr indirect);\ntypedef void (APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTNVPROC) (GLintptr indirect, GLsizei drawcount, GLsizei stride);\ntypedef void (APIENTRYP PFNGLMULTIDRAWMESHTASKSINDIRECTCOUNTNVPROC) (GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawMeshTasksNV (GLuint first, GLuint count);\nGLAPI void APIENTRY glDrawMeshTasksIndirectNV (GLintptr indirect);\nGLAPI void APIENTRY glMultiDrawMeshTasksIndirectNV (GLintptr indirect, GLsizei drawcount, GLsizei stride);\nGLAPI void APIENTRY glMultiDrawMeshTasksIndirectCountNV (GLintptr indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride);\n#endif\n#endif /* GL_NV_mesh_shader */\n\n#ifndef GL_NV_multisample_coverage\n#define GL_NV_multisample_coverage 1\n#endif /* GL_NV_multisample_coverage */\n\n#ifndef GL_NV_multisample_filter_hint\n#define GL_NV_multisample_filter_hint 1\n#define GL_MULTISAMPLE_FILTER_HINT_NV     0x8534\n#endif /* GL_NV_multisample_filter_hint */\n\n#ifndef GL_NV_occlusion_query\n#define GL_NV_occlusion_query 1\n#define GL_PIXEL_COUNTER_BITS_NV          0x8864\n#define GL_CURRENT_OCCLUSION_QUERY_ID_NV  0x8865\n#define GL_PIXEL_COUNT_NV                 0x8866\n#define GL_PIXEL_COUNT_AVAILABLE_NV       0x8867\ntypedef void (APIENTRYP PFNGLGENOCCLUSIONQUERIESNVPROC) (GLsizei n, GLuint *ids);\ntypedef void (APIENTRYP PFNGLDELETEOCCLUSIONQUERIESNVPROC) (GLsizei n, const GLuint *ids);\ntypedef GLboolean (APIENTRYP PFNGLISOCCLUSIONQUERYNVPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLBEGINOCCLUSIONQUERYNVPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLENDOCCLUSIONQUERYNVPROC) (void);\ntypedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYIVNVPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETOCCLUSIONQUERYUIVNVPROC) (GLuint id, GLenum pname, GLuint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenOcclusionQueriesNV (GLsizei n, GLuint *ids);\nGLAPI void APIENTRY glDeleteOcclusionQueriesNV (GLsizei n, const GLuint *ids);\nGLAPI GLboolean APIENTRY glIsOcclusionQueryNV (GLuint id);\nGLAPI void APIENTRY glBeginOcclusionQueryNV (GLuint id);\nGLAPI void APIENTRY glEndOcclusionQueryNV (void);\nGLAPI void APIENTRY glGetOcclusionQueryivNV (GLuint id, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetOcclusionQueryuivNV (GLuint id, GLenum pname, GLuint *params);\n#endif\n#endif /* GL_NV_occlusion_query */\n\n#ifndef GL_NV_packed_depth_stencil\n#define GL_NV_packed_depth_stencil 1\n#define GL_DEPTH_STENCIL_NV               0x84F9\n#define GL_UNSIGNED_INT_24_8_NV           0x84FA\n#endif /* GL_NV_packed_depth_stencil */\n\n#ifndef GL_NV_parameter_buffer_object\n#define GL_NV_parameter_buffer_object 1\n#define GL_MAX_PROGRAM_PARAMETER_BUFFER_BINDINGS_NV 0x8DA0\n#define GL_MAX_PROGRAM_PARAMETER_BUFFER_SIZE_NV 0x8DA1\n#define GL_VERTEX_PROGRAM_PARAMETER_BUFFER_NV 0x8DA2\n#define GL_GEOMETRY_PROGRAM_PARAMETER_BUFFER_NV 0x8DA3\n#define GL_FRAGMENT_PROGRAM_PARAMETER_BUFFER_NV 0x8DA4\ntypedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params);\ntypedef void (APIENTRYP PFNGLPROGRAMBUFFERPARAMETERSIUIVNVPROC) (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glProgramBufferParametersfvNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLfloat *params);\nGLAPI void APIENTRY glProgramBufferParametersIivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLint *params);\nGLAPI void APIENTRY glProgramBufferParametersIuivNV (GLenum target, GLuint bindingIndex, GLuint wordIndex, GLsizei count, const GLuint *params);\n#endif\n#endif /* GL_NV_parameter_buffer_object */\n\n#ifndef GL_NV_parameter_buffer_object2\n#define GL_NV_parameter_buffer_object2 1\n#endif /* GL_NV_parameter_buffer_object2 */\n\n#ifndef GL_NV_path_rendering\n#define GL_NV_path_rendering 1\n#define GL_PATH_FORMAT_SVG_NV             0x9070\n#define GL_PATH_FORMAT_PS_NV              0x9071\n#define GL_STANDARD_FONT_NAME_NV          0x9072\n#define GL_SYSTEM_FONT_NAME_NV            0x9073\n#define GL_FILE_NAME_NV                   0x9074\n#define GL_PATH_STROKE_WIDTH_NV           0x9075\n#define GL_PATH_END_CAPS_NV               0x9076\n#define GL_PATH_INITIAL_END_CAP_NV        0x9077\n#define GL_PATH_TERMINAL_END_CAP_NV       0x9078\n#define GL_PATH_JOIN_STYLE_NV             0x9079\n#define GL_PATH_MITER_LIMIT_NV            0x907A\n#define GL_PATH_DASH_CAPS_NV              0x907B\n#define GL_PATH_INITIAL_DASH_CAP_NV       0x907C\n#define GL_PATH_TERMINAL_DASH_CAP_NV      0x907D\n#define GL_PATH_DASH_OFFSET_NV            0x907E\n#define GL_PATH_CLIENT_LENGTH_NV          0x907F\n#define GL_PATH_FILL_MODE_NV              0x9080\n#define GL_PATH_FILL_MASK_NV              0x9081\n#define GL_PATH_FILL_COVER_MODE_NV        0x9082\n#define GL_PATH_STROKE_COVER_MODE_NV      0x9083\n#define GL_PATH_STROKE_MASK_NV            0x9084\n#define GL_COUNT_UP_NV                    0x9088\n#define GL_COUNT_DOWN_NV                  0x9089\n#define GL_PATH_OBJECT_BOUNDING_BOX_NV    0x908A\n#define GL_CONVEX_HULL_NV                 0x908B\n#define GL_BOUNDING_BOX_NV                0x908D\n#define GL_TRANSLATE_X_NV                 0x908E\n#define GL_TRANSLATE_Y_NV                 0x908F\n#define GL_TRANSLATE_2D_NV                0x9090\n#define GL_TRANSLATE_3D_NV                0x9091\n#define GL_AFFINE_2D_NV                   0x9092\n#define GL_AFFINE_3D_NV                   0x9094\n#define GL_TRANSPOSE_AFFINE_2D_NV         0x9096\n#define GL_TRANSPOSE_AFFINE_3D_NV         0x9098\n#define GL_UTF8_NV                        0x909A\n#define GL_UTF16_NV                       0x909B\n#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C\n#define GL_PATH_COMMAND_COUNT_NV          0x909D\n#define GL_PATH_COORD_COUNT_NV            0x909E\n#define GL_PATH_DASH_ARRAY_COUNT_NV       0x909F\n#define GL_PATH_COMPUTED_LENGTH_NV        0x90A0\n#define GL_PATH_FILL_BOUNDING_BOX_NV      0x90A1\n#define GL_PATH_STROKE_BOUNDING_BOX_NV    0x90A2\n#define GL_SQUARE_NV                      0x90A3\n#define GL_ROUND_NV                       0x90A4\n#define GL_TRIANGULAR_NV                  0x90A5\n#define GL_BEVEL_NV                       0x90A6\n#define GL_MITER_REVERT_NV                0x90A7\n#define GL_MITER_TRUNCATE_NV              0x90A8\n#define GL_SKIP_MISSING_GLYPH_NV          0x90A9\n#define GL_USE_MISSING_GLYPH_NV           0x90AA\n#define GL_PATH_ERROR_POSITION_NV         0x90AB\n#define GL_ACCUM_ADJACENT_PAIRS_NV        0x90AD\n#define GL_ADJACENT_PAIRS_NV              0x90AE\n#define GL_FIRST_TO_REST_NV               0x90AF\n#define GL_PATH_GEN_MODE_NV               0x90B0\n#define GL_PATH_GEN_COEFF_NV              0x90B1\n#define GL_PATH_GEN_COMPONENTS_NV         0x90B3\n#define GL_PATH_STENCIL_FUNC_NV           0x90B7\n#define GL_PATH_STENCIL_REF_NV            0x90B8\n#define GL_PATH_STENCIL_VALUE_MASK_NV     0x90B9\n#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD\n#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE\n#define GL_PATH_COVER_DEPTH_FUNC_NV       0x90BF\n#define GL_PATH_DASH_OFFSET_RESET_NV      0x90B4\n#define GL_MOVE_TO_RESETS_NV              0x90B5\n#define GL_MOVE_TO_CONTINUES_NV           0x90B6\n#define GL_CLOSE_PATH_NV                  0x00\n#define GL_MOVE_TO_NV                     0x02\n#define GL_RELATIVE_MOVE_TO_NV            0x03\n#define GL_LINE_TO_NV                     0x04\n#define GL_RELATIVE_LINE_TO_NV            0x05\n#define GL_HORIZONTAL_LINE_TO_NV          0x06\n#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07\n#define GL_VERTICAL_LINE_TO_NV            0x08\n#define GL_RELATIVE_VERTICAL_LINE_TO_NV   0x09\n#define GL_QUADRATIC_CURVE_TO_NV          0x0A\n#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B\n#define GL_CUBIC_CURVE_TO_NV              0x0C\n#define GL_RELATIVE_CUBIC_CURVE_TO_NV     0x0D\n#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV   0x0E\n#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F\n#define GL_SMOOTH_CUBIC_CURVE_TO_NV       0x10\n#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11\n#define GL_SMALL_CCW_ARC_TO_NV            0x12\n#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV   0x13\n#define GL_SMALL_CW_ARC_TO_NV             0x14\n#define GL_RELATIVE_SMALL_CW_ARC_TO_NV    0x15\n#define GL_LARGE_CCW_ARC_TO_NV            0x16\n#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV   0x17\n#define GL_LARGE_CW_ARC_TO_NV             0x18\n#define GL_RELATIVE_LARGE_CW_ARC_TO_NV    0x19\n#define GL_RESTART_PATH_NV                0xF0\n#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV    0xF2\n#define GL_DUP_LAST_CUBIC_CURVE_TO_NV     0xF4\n#define GL_RECT_NV                        0xF6\n#define GL_CIRCULAR_CCW_ARC_TO_NV         0xF8\n#define GL_CIRCULAR_CW_ARC_TO_NV          0xFA\n#define GL_CIRCULAR_TANGENT_ARC_TO_NV     0xFC\n#define GL_ARC_TO_NV                      0xFE\n#define GL_RELATIVE_ARC_TO_NV             0xFF\n#define GL_BOLD_BIT_NV                    0x01\n#define GL_ITALIC_BIT_NV                  0x02\n#define GL_GLYPH_WIDTH_BIT_NV             0x01\n#define GL_GLYPH_HEIGHT_BIT_NV            0x02\n#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04\n#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08\n#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10\n#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20\n#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40\n#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80\n#define GL_GLYPH_HAS_KERNING_BIT_NV       0x100\n#define GL_FONT_X_MIN_BOUNDS_BIT_NV       0x00010000\n#define GL_FONT_Y_MIN_BOUNDS_BIT_NV       0x00020000\n#define GL_FONT_X_MAX_BOUNDS_BIT_NV       0x00040000\n#define GL_FONT_Y_MAX_BOUNDS_BIT_NV       0x00080000\n#define GL_FONT_UNITS_PER_EM_BIT_NV       0x00100000\n#define GL_FONT_ASCENDER_BIT_NV           0x00200000\n#define GL_FONT_DESCENDER_BIT_NV          0x00400000\n#define GL_FONT_HEIGHT_BIT_NV             0x00800000\n#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV  0x01000000\n#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000\n#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000\n#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000\n#define GL_FONT_HAS_KERNING_BIT_NV        0x10000000\n#define GL_ROUNDED_RECT_NV                0xE8\n#define GL_RELATIVE_ROUNDED_RECT_NV       0xE9\n#define GL_ROUNDED_RECT2_NV               0xEA\n#define GL_RELATIVE_ROUNDED_RECT2_NV      0xEB\n#define GL_ROUNDED_RECT4_NV               0xEC\n#define GL_RELATIVE_ROUNDED_RECT4_NV      0xED\n#define GL_ROUNDED_RECT8_NV               0xEE\n#define GL_RELATIVE_ROUNDED_RECT8_NV      0xEF\n#define GL_RELATIVE_RECT_NV               0xF7\n#define GL_FONT_GLYPHS_AVAILABLE_NV       0x9368\n#define GL_FONT_TARGET_UNAVAILABLE_NV     0x9369\n#define GL_FONT_UNAVAILABLE_NV            0x936A\n#define GL_FONT_UNINTELLIGIBLE_NV         0x936B\n#define GL_CONIC_CURVE_TO_NV              0x1A\n#define GL_RELATIVE_CONIC_CURVE_TO_NV     0x1B\n#define GL_FONT_NUM_GLYPH_INDICES_BIT_NV  0x20000000\n#define GL_STANDARD_FONT_FORMAT_NV        0x936C\n#define GL_2_BYTES_NV                     0x1407\n#define GL_3_BYTES_NV                     0x1408\n#define GL_4_BYTES_NV                     0x1409\n#define GL_EYE_LINEAR_NV                  0x2400\n#define GL_OBJECT_LINEAR_NV               0x2401\n#define GL_CONSTANT_NV                    0x8576\n#define GL_PATH_FOG_GEN_MODE_NV           0x90AC\n#define GL_PRIMARY_COLOR_NV               0x852C\n#define GL_SECONDARY_COLOR_NV             0x852D\n#define GL_PATH_GEN_COLOR_FORMAT_NV       0x90B2\n#define GL_PATH_PROJECTION_NV             0x1701\n#define GL_PATH_MODELVIEW_NV              0x1700\n#define GL_PATH_MODELVIEW_STACK_DEPTH_NV  0x0BA3\n#define GL_PATH_MODELVIEW_MATRIX_NV       0x0BA6\n#define GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36\n#define GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3\n#define GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4\n#define GL_PATH_PROJECTION_MATRIX_NV      0x0BA7\n#define GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38\n#define GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4\n#define GL_FRAGMENT_INPUT_NV              0x936D\ntypedef GLuint (APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range);\ntypedef void (APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range);\ntypedef GLboolean (APIENTRYP PFNGLISPATHNVPROC) (GLuint path);\ntypedef void (APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);\ntypedef void (APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords);\ntypedef void (APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);\ntypedef void (APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords);\ntypedef void (APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString);\ntypedef void (APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);\ntypedef void (APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);\ntypedef void (APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights);\ntypedef void (APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath);\ntypedef void (APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight);\ntypedef void (APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues);\ntypedef void (APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value);\ntypedef void (APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value);\ntypedef void (APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value);\ntypedef void (APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value);\ntypedef void (APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray);\ntypedef void (APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask);\ntypedef void (APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units);\ntypedef void (APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask);\ntypedef void (APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask);\ntypedef void (APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues);\ntypedef void (APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues);\ntypedef void (APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func);\ntypedef void (APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode);\ntypedef void (APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode);\ntypedef void (APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);\ntypedef void (APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);\ntypedef void (APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value);\ntypedef void (APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value);\ntypedef void (APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands);\ntypedef void (APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords);\ntypedef void (APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray);\ntypedef void (APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics);\ntypedef void (APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics);\ntypedef void (APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing);\ntypedef GLboolean (APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y);\ntypedef GLboolean (APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y);\ntypedef GLfloat (APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments);\ntypedef GLboolean (APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY);\ntypedef void (APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);\ntypedef void (APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m);\ntypedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode);\ntypedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode);\ntypedef void (APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);\ntypedef void (APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);\ntypedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint *baseAndCount);\ntypedef GLenum (APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);\ntypedef GLenum (APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);\ntypedef void (APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs);\ntypedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLfloat *params);\ntypedef void (APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs);\ntypedef void (APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs);\ntypedef void (APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode);\ntypedef void (APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value);\ntypedef void (APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value);\ntypedef void (APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value);\ntypedef void (APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLuint APIENTRY glGenPathsNV (GLsizei range);\nGLAPI void APIENTRY glDeletePathsNV (GLuint path, GLsizei range);\nGLAPI GLboolean APIENTRY glIsPathNV (GLuint path);\nGLAPI void APIENTRY glPathCommandsNV (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);\nGLAPI void APIENTRY glPathCoordsNV (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords);\nGLAPI void APIENTRY glPathSubCommandsNV (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords);\nGLAPI void APIENTRY glPathSubCoordsNV (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords);\nGLAPI void APIENTRY glPathStringNV (GLuint path, GLenum format, GLsizei length, const void *pathString);\nGLAPI void APIENTRY glPathGlyphsNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);\nGLAPI void APIENTRY glPathGlyphRangeNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale);\nGLAPI void APIENTRY glWeightPathsNV (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights);\nGLAPI void APIENTRY glCopyPathNV (GLuint resultPath, GLuint srcPath);\nGLAPI void APIENTRY glInterpolatePathsNV (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight);\nGLAPI void APIENTRY glTransformPathNV (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues);\nGLAPI void APIENTRY glPathParameterivNV (GLuint path, GLenum pname, const GLint *value);\nGLAPI void APIENTRY glPathParameteriNV (GLuint path, GLenum pname, GLint value);\nGLAPI void APIENTRY glPathParameterfvNV (GLuint path, GLenum pname, const GLfloat *value);\nGLAPI void APIENTRY glPathParameterfNV (GLuint path, GLenum pname, GLfloat value);\nGLAPI void APIENTRY glPathDashArrayNV (GLuint path, GLsizei dashCount, const GLfloat *dashArray);\nGLAPI void APIENTRY glPathStencilFuncNV (GLenum func, GLint ref, GLuint mask);\nGLAPI void APIENTRY glPathStencilDepthOffsetNV (GLfloat factor, GLfloat units);\nGLAPI void APIENTRY glStencilFillPathNV (GLuint path, GLenum fillMode, GLuint mask);\nGLAPI void APIENTRY glStencilStrokePathNV (GLuint path, GLint reference, GLuint mask);\nGLAPI void APIENTRY glStencilFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues);\nGLAPI void APIENTRY glStencilStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues);\nGLAPI void APIENTRY glPathCoverDepthFuncNV (GLenum func);\nGLAPI void APIENTRY glCoverFillPathNV (GLuint path, GLenum coverMode);\nGLAPI void APIENTRY glCoverStrokePathNV (GLuint path, GLenum coverMode);\nGLAPI void APIENTRY glCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);\nGLAPI void APIENTRY glCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);\nGLAPI void APIENTRY glGetPathParameterivNV (GLuint path, GLenum pname, GLint *value);\nGLAPI void APIENTRY glGetPathParameterfvNV (GLuint path, GLenum pname, GLfloat *value);\nGLAPI void APIENTRY glGetPathCommandsNV (GLuint path, GLubyte *commands);\nGLAPI void APIENTRY glGetPathCoordsNV (GLuint path, GLfloat *coords);\nGLAPI void APIENTRY glGetPathDashArrayNV (GLuint path, GLfloat *dashArray);\nGLAPI void APIENTRY glGetPathMetricsNV (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics);\nGLAPI void APIENTRY glGetPathMetricRangeNV (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics);\nGLAPI void APIENTRY glGetPathSpacingNV (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing);\nGLAPI GLboolean APIENTRY glIsPointInFillPathNV (GLuint path, GLuint mask, GLfloat x, GLfloat y);\nGLAPI GLboolean APIENTRY glIsPointInStrokePathNV (GLuint path, GLfloat x, GLfloat y);\nGLAPI GLfloat APIENTRY glGetPathLengthNV (GLuint path, GLsizei startSegment, GLsizei numSegments);\nGLAPI GLboolean APIENTRY glPointAlongPathNV (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY);\nGLAPI void APIENTRY glMatrixLoad3x2fNV (GLenum matrixMode, const GLfloat *m);\nGLAPI void APIENTRY glMatrixLoad3x3fNV (GLenum matrixMode, const GLfloat *m);\nGLAPI void APIENTRY glMatrixLoadTranspose3x3fNV (GLenum matrixMode, const GLfloat *m);\nGLAPI void APIENTRY glMatrixMult3x2fNV (GLenum matrixMode, const GLfloat *m);\nGLAPI void APIENTRY glMatrixMult3x3fNV (GLenum matrixMode, const GLfloat *m);\nGLAPI void APIENTRY glMatrixMultTranspose3x3fNV (GLenum matrixMode, const GLfloat *m);\nGLAPI void APIENTRY glStencilThenCoverFillPathNV (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode);\nGLAPI void APIENTRY glStencilThenCoverStrokePathNV (GLuint path, GLint reference, GLuint mask, GLenum coverMode);\nGLAPI void APIENTRY glStencilThenCoverFillPathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);\nGLAPI void APIENTRY glStencilThenCoverStrokePathInstancedNV (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues);\nGLAPI GLenum APIENTRY glPathGlyphIndexRangeNV (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint *baseAndCount);\nGLAPI GLenum APIENTRY glPathGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);\nGLAPI GLenum APIENTRY glPathMemoryGlyphIndexArrayNV (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale);\nGLAPI void APIENTRY glProgramPathFragmentInputGenNV (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs);\nGLAPI void APIENTRY glGetProgramResourcefvNV (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLfloat *params);\nGLAPI void APIENTRY glPathColorGenNV (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs);\nGLAPI void APIENTRY glPathTexGenNV (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs);\nGLAPI void APIENTRY glPathFogGenNV (GLenum genMode);\nGLAPI void APIENTRY glGetPathColorGenivNV (GLenum color, GLenum pname, GLint *value);\nGLAPI void APIENTRY glGetPathColorGenfvNV (GLenum color, GLenum pname, GLfloat *value);\nGLAPI void APIENTRY glGetPathTexGenivNV (GLenum texCoordSet, GLenum pname, GLint *value);\nGLAPI void APIENTRY glGetPathTexGenfvNV (GLenum texCoordSet, GLenum pname, GLfloat *value);\n#endif\n#endif /* GL_NV_path_rendering */\n\n#ifndef GL_NV_path_rendering_shared_edge\n#define GL_NV_path_rendering_shared_edge 1\n#define GL_SHARED_EDGE_NV                 0xC0\n#endif /* GL_NV_path_rendering_shared_edge */\n\n#ifndef GL_NV_pixel_data_range\n#define GL_NV_pixel_data_range 1\n#define GL_WRITE_PIXEL_DATA_RANGE_NV      0x8878\n#define GL_READ_PIXEL_DATA_RANGE_NV       0x8879\n#define GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV 0x887A\n#define GL_READ_PIXEL_DATA_RANGE_LENGTH_NV 0x887B\n#define GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV 0x887C\n#define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D\ntypedef void (APIENTRYP PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, const void *pointer);\ntypedef void (APIENTRYP PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPixelDataRangeNV (GLenum target, GLsizei length, const void *pointer);\nGLAPI void APIENTRY glFlushPixelDataRangeNV (GLenum target);\n#endif\n#endif /* GL_NV_pixel_data_range */\n\n#ifndef GL_NV_point_sprite\n#define GL_NV_point_sprite 1\n#define GL_POINT_SPRITE_NV                0x8861\n#define GL_COORD_REPLACE_NV               0x8862\n#define GL_POINT_SPRITE_R_MODE_NV         0x8863\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERINVPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERIVNVPROC) (GLenum pname, const GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPointParameteriNV (GLenum pname, GLint param);\nGLAPI void APIENTRY glPointParameterivNV (GLenum pname, const GLint *params);\n#endif\n#endif /* GL_NV_point_sprite */\n\n#ifndef GL_NV_present_video\n#define GL_NV_present_video 1\n#define GL_FRAME_NV                       0x8E26\n#define GL_FIELDS_NV                      0x8E27\n#define GL_CURRENT_TIME_NV                0x8E28\n#define GL_NUM_FILL_STREAMS_NV            0x8E29\n#define GL_PRESENT_TIME_NV                0x8E2A\n#define GL_PRESENT_DURATION_NV            0x8E2B\ntypedef void (APIENTRYP PFNGLPRESENTFRAMEKEYEDNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1);\ntypedef void (APIENTRYP PFNGLPRESENTFRAMEDUALFILLNVPROC) (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3);\ntypedef void (APIENTRYP PFNGLGETVIDEOIVNVPROC) (GLuint video_slot, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVIDEOUIVNVPROC) (GLuint video_slot, GLenum pname, GLuint *params);\ntypedef void (APIENTRYP PFNGLGETVIDEOI64VNVPROC) (GLuint video_slot, GLenum pname, GLint64EXT *params);\ntypedef void (APIENTRYP PFNGLGETVIDEOUI64VNVPROC) (GLuint video_slot, GLenum pname, GLuint64EXT *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPresentFrameKeyedNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLuint key0, GLenum target1, GLuint fill1, GLuint key1);\nGLAPI void APIENTRY glPresentFrameDualFillNV (GLuint video_slot, GLuint64EXT minPresentTime, GLuint beginPresentTimeId, GLuint presentDurationId, GLenum type, GLenum target0, GLuint fill0, GLenum target1, GLuint fill1, GLenum target2, GLuint fill2, GLenum target3, GLuint fill3);\nGLAPI void APIENTRY glGetVideoivNV (GLuint video_slot, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetVideouivNV (GLuint video_slot, GLenum pname, GLuint *params);\nGLAPI void APIENTRY glGetVideoi64vNV (GLuint video_slot, GLenum pname, GLint64EXT *params);\nGLAPI void APIENTRY glGetVideoui64vNV (GLuint video_slot, GLenum pname, GLuint64EXT *params);\n#endif\n#endif /* GL_NV_present_video */\n\n#ifndef GL_NV_primitive_restart\n#define GL_NV_primitive_restart 1\n#define GL_PRIMITIVE_RESTART_NV           0x8558\n#define GL_PRIMITIVE_RESTART_INDEX_NV     0x8559\ntypedef void (APIENTRYP PFNGLPRIMITIVERESTARTNVPROC) (void);\ntypedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXNVPROC) (GLuint index);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPrimitiveRestartNV (void);\nGLAPI void APIENTRY glPrimitiveRestartIndexNV (GLuint index);\n#endif\n#endif /* GL_NV_primitive_restart */\n\n#ifndef GL_NV_primitive_shading_rate\n#define GL_NV_primitive_shading_rate 1\n#define GL_SHADING_RATE_IMAGE_PER_PRIMITIVE_NV 0x95B1\n#define GL_SHADING_RATE_IMAGE_PALETTE_COUNT_NV 0x95B2\n#endif /* GL_NV_primitive_shading_rate */\n\n#ifndef GL_NV_query_resource\n#define GL_NV_query_resource 1\n#define GL_QUERY_RESOURCE_TYPE_VIDMEM_ALLOC_NV 0x9540\n#define GL_QUERY_RESOURCE_MEMTYPE_VIDMEM_NV 0x9542\n#define GL_QUERY_RESOURCE_SYS_RESERVED_NV 0x9544\n#define GL_QUERY_RESOURCE_TEXTURE_NV      0x9545\n#define GL_QUERY_RESOURCE_RENDERBUFFER_NV 0x9546\n#define GL_QUERY_RESOURCE_BUFFEROBJECT_NV 0x9547\ntypedef GLint (APIENTRYP PFNGLQUERYRESOURCENVPROC) (GLenum queryType, GLint tagId, GLuint count, GLint *buffer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLint APIENTRY glQueryResourceNV (GLenum queryType, GLint tagId, GLuint count, GLint *buffer);\n#endif\n#endif /* GL_NV_query_resource */\n\n#ifndef GL_NV_query_resource_tag\n#define GL_NV_query_resource_tag 1\ntypedef void (APIENTRYP PFNGLGENQUERYRESOURCETAGNVPROC) (GLsizei n, GLint *tagIds);\ntypedef void (APIENTRYP PFNGLDELETEQUERYRESOURCETAGNVPROC) (GLsizei n, const GLint *tagIds);\ntypedef void (APIENTRYP PFNGLQUERYRESOURCETAGNVPROC) (GLint tagId, const GLchar *tagString);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGenQueryResourceTagNV (GLsizei n, GLint *tagIds);\nGLAPI void APIENTRY glDeleteQueryResourceTagNV (GLsizei n, const GLint *tagIds);\nGLAPI void APIENTRY glQueryResourceTagNV (GLint tagId, const GLchar *tagString);\n#endif\n#endif /* GL_NV_query_resource_tag */\n\n#ifndef GL_NV_register_combiners\n#define GL_NV_register_combiners 1\n#define GL_REGISTER_COMBINERS_NV          0x8522\n#define GL_VARIABLE_A_NV                  0x8523\n#define GL_VARIABLE_B_NV                  0x8524\n#define GL_VARIABLE_C_NV                  0x8525\n#define GL_VARIABLE_D_NV                  0x8526\n#define GL_VARIABLE_E_NV                  0x8527\n#define GL_VARIABLE_F_NV                  0x8528\n#define GL_VARIABLE_G_NV                  0x8529\n#define GL_CONSTANT_COLOR0_NV             0x852A\n#define GL_CONSTANT_COLOR1_NV             0x852B\n#define GL_SPARE0_NV                      0x852E\n#define GL_SPARE1_NV                      0x852F\n#define GL_DISCARD_NV                     0x8530\n#define GL_E_TIMES_F_NV                   0x8531\n#define GL_SPARE0_PLUS_SECONDARY_COLOR_NV 0x8532\n#define GL_UNSIGNED_IDENTITY_NV           0x8536\n#define GL_UNSIGNED_INVERT_NV             0x8537\n#define GL_EXPAND_NORMAL_NV               0x8538\n#define GL_EXPAND_NEGATE_NV               0x8539\n#define GL_HALF_BIAS_NORMAL_NV            0x853A\n#define GL_HALF_BIAS_NEGATE_NV            0x853B\n#define GL_SIGNED_IDENTITY_NV             0x853C\n#define GL_SIGNED_NEGATE_NV               0x853D\n#define GL_SCALE_BY_TWO_NV                0x853E\n#define GL_SCALE_BY_FOUR_NV               0x853F\n#define GL_SCALE_BY_ONE_HALF_NV           0x8540\n#define GL_BIAS_BY_NEGATIVE_ONE_HALF_NV   0x8541\n#define GL_COMBINER_INPUT_NV              0x8542\n#define GL_COMBINER_MAPPING_NV            0x8543\n#define GL_COMBINER_COMPONENT_USAGE_NV    0x8544\n#define GL_COMBINER_AB_DOT_PRODUCT_NV     0x8545\n#define GL_COMBINER_CD_DOT_PRODUCT_NV     0x8546\n#define GL_COMBINER_MUX_SUM_NV            0x8547\n#define GL_COMBINER_SCALE_NV              0x8548\n#define GL_COMBINER_BIAS_NV               0x8549\n#define GL_COMBINER_AB_OUTPUT_NV          0x854A\n#define GL_COMBINER_CD_OUTPUT_NV          0x854B\n#define GL_COMBINER_SUM_OUTPUT_NV         0x854C\n#define GL_MAX_GENERAL_COMBINERS_NV       0x854D\n#define GL_NUM_GENERAL_COMBINERS_NV       0x854E\n#define GL_COLOR_SUM_CLAMP_NV             0x854F\n#define GL_COMBINER0_NV                   0x8550\n#define GL_COMBINER1_NV                   0x8551\n#define GL_COMBINER2_NV                   0x8552\n#define GL_COMBINER3_NV                   0x8553\n#define GL_COMBINER4_NV                   0x8554\n#define GL_COMBINER5_NV                   0x8555\n#define GL_COMBINER6_NV                   0x8556\n#define GL_COMBINER7_NV                   0x8557\ntypedef void (APIENTRYP PFNGLCOMBINERPARAMETERFVNVPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLCOMBINERPARAMETERFNVPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLCOMBINERPARAMETERIVNVPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLCOMBINERPARAMETERINVPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLCOMBINERINPUTNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);\ntypedef void (APIENTRYP PFNGLCOMBINEROUTPUTNVPROC) (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);\ntypedef void (APIENTRYP PFNGLFINALCOMBINERINPUTNVPROC) (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);\ntypedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC) (GLenum stage, GLenum portion, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC) (GLenum variable, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC) (GLenum variable, GLenum pname, GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCombinerParameterfvNV (GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glCombinerParameterfNV (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glCombinerParameterivNV (GLenum pname, const GLint *params);\nGLAPI void APIENTRY glCombinerParameteriNV (GLenum pname, GLint param);\nGLAPI void APIENTRY glCombinerInputNV (GLenum stage, GLenum portion, GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);\nGLAPI void APIENTRY glCombinerOutputNV (GLenum stage, GLenum portion, GLenum abOutput, GLenum cdOutput, GLenum sumOutput, GLenum scale, GLenum bias, GLboolean abDotProduct, GLboolean cdDotProduct, GLboolean muxSum);\nGLAPI void APIENTRY glFinalCombinerInputNV (GLenum variable, GLenum input, GLenum mapping, GLenum componentUsage);\nGLAPI void APIENTRY glGetCombinerInputParameterfvNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetCombinerInputParameterivNV (GLenum stage, GLenum portion, GLenum variable, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetCombinerOutputParameterfvNV (GLenum stage, GLenum portion, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetCombinerOutputParameterivNV (GLenum stage, GLenum portion, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetFinalCombinerInputParameterfvNV (GLenum variable, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetFinalCombinerInputParameterivNV (GLenum variable, GLenum pname, GLint *params);\n#endif\n#endif /* GL_NV_register_combiners */\n\n#ifndef GL_NV_register_combiners2\n#define GL_NV_register_combiners2 1\n#define GL_PER_STAGE_CONSTANTS_NV         0x8535\ntypedef void (APIENTRYP PFNGLCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage, GLenum pname, GLfloat *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCombinerStageParameterfvNV (GLenum stage, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname, GLfloat *params);\n#endif\n#endif /* GL_NV_register_combiners2 */\n\n#ifndef GL_NV_representative_fragment_test\n#define GL_NV_representative_fragment_test 1\n#define GL_REPRESENTATIVE_FRAGMENT_TEST_NV 0x937F\n#endif /* GL_NV_representative_fragment_test */\n\n#ifndef GL_NV_robustness_video_memory_purge\n#define GL_NV_robustness_video_memory_purge 1\n#define GL_PURGED_CONTEXT_RESET_NV        0x92BB\n#endif /* GL_NV_robustness_video_memory_purge */\n\n#ifndef GL_NV_sample_locations\n#define GL_NV_sample_locations 1\n#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV 0x933D\n#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_NV 0x933E\n#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_NV 0x933F\n#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_NV 0x9340\n#define GL_SAMPLE_LOCATION_NV             0x8E50\n#define GL_PROGRAMMABLE_SAMPLE_LOCATION_NV 0x9341\n#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_NV 0x9342\n#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_NV 0x9343\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVNVPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLRESOLVEDEPTHVALUESNVPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFramebufferSampleLocationsfvNV (GLenum target, GLuint start, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glNamedFramebufferSampleLocationsfvNV (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glResolveDepthValuesNV (void);\n#endif\n#endif /* GL_NV_sample_locations */\n\n#ifndef GL_NV_sample_mask_override_coverage\n#define GL_NV_sample_mask_override_coverage 1\n#endif /* GL_NV_sample_mask_override_coverage */\n\n#ifndef GL_NV_scissor_exclusive\n#define GL_NV_scissor_exclusive 1\n#define GL_SCISSOR_TEST_EXCLUSIVE_NV      0x9555\n#define GL_SCISSOR_BOX_EXCLUSIVE_NV       0x9556\ntypedef void (APIENTRYP PFNGLSCISSOREXCLUSIVENVPROC) (GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (APIENTRYP PFNGLSCISSOREXCLUSIVEARRAYVNVPROC) (GLuint first, GLsizei count, const GLint *v);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glScissorExclusiveNV (GLint x, GLint y, GLsizei width, GLsizei height);\nGLAPI void APIENTRY glScissorExclusiveArrayvNV (GLuint first, GLsizei count, const GLint *v);\n#endif\n#endif /* GL_NV_scissor_exclusive */\n\n#ifndef GL_NV_shader_atomic_counters\n#define GL_NV_shader_atomic_counters 1\n#endif /* GL_NV_shader_atomic_counters */\n\n#ifndef GL_NV_shader_atomic_float\n#define GL_NV_shader_atomic_float 1\n#endif /* GL_NV_shader_atomic_float */\n\n#ifndef GL_NV_shader_atomic_float64\n#define GL_NV_shader_atomic_float64 1\n#endif /* GL_NV_shader_atomic_float64 */\n\n#ifndef GL_NV_shader_atomic_fp16_vector\n#define GL_NV_shader_atomic_fp16_vector 1\n#endif /* GL_NV_shader_atomic_fp16_vector */\n\n#ifndef GL_NV_shader_atomic_int64\n#define GL_NV_shader_atomic_int64 1\n#endif /* GL_NV_shader_atomic_int64 */\n\n#ifndef GL_NV_shader_buffer_load\n#define GL_NV_shader_buffer_load 1\n#define GL_BUFFER_GPU_ADDRESS_NV          0x8F1D\n#define GL_GPU_ADDRESS_NV                 0x8F34\n#define GL_MAX_SHADER_BUFFER_ADDRESS_NV   0x8F35\ntypedef void (APIENTRYP PFNGLMAKEBUFFERRESIDENTNVPROC) (GLenum target, GLenum access);\ntypedef void (APIENTRYP PFNGLMAKEBUFFERNONRESIDENTNVPROC) (GLenum target);\ntypedef GLboolean (APIENTRYP PFNGLISBUFFERRESIDENTNVPROC) (GLenum target);\ntypedef void (APIENTRYP PFNGLMAKENAMEDBUFFERRESIDENTNVPROC) (GLuint buffer, GLenum access);\ntypedef void (APIENTRYP PFNGLMAKENAMEDBUFFERNONRESIDENTNVPROC) (GLuint buffer);\ntypedef GLboolean (APIENTRYP PFNGLISNAMEDBUFFERRESIDENTNVPROC) (GLuint buffer);\ntypedef void (APIENTRYP PFNGLGETBUFFERPARAMETERUI64VNVPROC) (GLenum target, GLenum pname, GLuint64EXT *params);\ntypedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERUI64VNVPROC) (GLuint buffer, GLenum pname, GLuint64EXT *params);\ntypedef void (APIENTRYP PFNGLGETINTEGERUI64VNVPROC) (GLenum value, GLuint64EXT *result);\ntypedef void (APIENTRYP PFNGLUNIFORMUI64NVPROC) (GLint location, GLuint64EXT value);\ntypedef void (APIENTRYP PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei count, const GLuint64EXT *value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64NVPROC) (GLuint program, GLint location, GLuint64EXT value);\ntypedef void (APIENTRYP PFNGLPROGRAMUNIFORMUI64VNVPROC) (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glMakeBufferResidentNV (GLenum target, GLenum access);\nGLAPI void APIENTRY glMakeBufferNonResidentNV (GLenum target);\nGLAPI GLboolean APIENTRY glIsBufferResidentNV (GLenum target);\nGLAPI void APIENTRY glMakeNamedBufferResidentNV (GLuint buffer, GLenum access);\nGLAPI void APIENTRY glMakeNamedBufferNonResidentNV (GLuint buffer);\nGLAPI GLboolean APIENTRY glIsNamedBufferResidentNV (GLuint buffer);\nGLAPI void APIENTRY glGetBufferParameterui64vNV (GLenum target, GLenum pname, GLuint64EXT *params);\nGLAPI void APIENTRY glGetNamedBufferParameterui64vNV (GLuint buffer, GLenum pname, GLuint64EXT *params);\nGLAPI void APIENTRY glGetIntegerui64vNV (GLenum value, GLuint64EXT *result);\nGLAPI void APIENTRY glUniformui64NV (GLint location, GLuint64EXT value);\nGLAPI void APIENTRY glUniformui64vNV (GLint location, GLsizei count, const GLuint64EXT *value);\nGLAPI void APIENTRY glProgramUniformui64NV (GLuint program, GLint location, GLuint64EXT value);\nGLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLsizei count, const GLuint64EXT *value);\n#endif\n#endif /* GL_NV_shader_buffer_load */\n\n#ifndef GL_NV_shader_buffer_store\n#define GL_NV_shader_buffer_store 1\n#define GL_SHADER_GLOBAL_ACCESS_BARRIER_BIT_NV 0x00000010\n#endif /* GL_NV_shader_buffer_store */\n\n#ifndef GL_NV_shader_storage_buffer_object\n#define GL_NV_shader_storage_buffer_object 1\n#endif /* GL_NV_shader_storage_buffer_object */\n\n#ifndef GL_NV_shader_subgroup_partitioned\n#define GL_NV_shader_subgroup_partitioned 1\n#define GL_SUBGROUP_FEATURE_PARTITIONED_BIT_NV 0x00000100\n#endif /* GL_NV_shader_subgroup_partitioned */\n\n#ifndef GL_NV_shader_texture_footprint\n#define GL_NV_shader_texture_footprint 1\n#endif /* GL_NV_shader_texture_footprint */\n\n#ifndef GL_NV_shader_thread_group\n#define GL_NV_shader_thread_group 1\n#define GL_WARP_SIZE_NV                   0x9339\n#define GL_WARPS_PER_SM_NV                0x933A\n#define GL_SM_COUNT_NV                    0x933B\n#endif /* GL_NV_shader_thread_group */\n\n#ifndef GL_NV_shader_thread_shuffle\n#define GL_NV_shader_thread_shuffle 1\n#endif /* GL_NV_shader_thread_shuffle */\n\n#ifndef GL_NV_shading_rate_image\n#define GL_NV_shading_rate_image 1\n#define GL_SHADING_RATE_IMAGE_NV          0x9563\n#define GL_SHADING_RATE_NO_INVOCATIONS_NV 0x9564\n#define GL_SHADING_RATE_1_INVOCATION_PER_PIXEL_NV 0x9565\n#define GL_SHADING_RATE_1_INVOCATION_PER_1X2_PIXELS_NV 0x9566\n#define GL_SHADING_RATE_1_INVOCATION_PER_2X1_PIXELS_NV 0x9567\n#define GL_SHADING_RATE_1_INVOCATION_PER_2X2_PIXELS_NV 0x9568\n#define GL_SHADING_RATE_1_INVOCATION_PER_2X4_PIXELS_NV 0x9569\n#define GL_SHADING_RATE_1_INVOCATION_PER_4X2_PIXELS_NV 0x956A\n#define GL_SHADING_RATE_1_INVOCATION_PER_4X4_PIXELS_NV 0x956B\n#define GL_SHADING_RATE_2_INVOCATIONS_PER_PIXEL_NV 0x956C\n#define GL_SHADING_RATE_4_INVOCATIONS_PER_PIXEL_NV 0x956D\n#define GL_SHADING_RATE_8_INVOCATIONS_PER_PIXEL_NV 0x956E\n#define GL_SHADING_RATE_16_INVOCATIONS_PER_PIXEL_NV 0x956F\n#define GL_SHADING_RATE_IMAGE_BINDING_NV  0x955B\n#define GL_SHADING_RATE_IMAGE_TEXEL_WIDTH_NV 0x955C\n#define GL_SHADING_RATE_IMAGE_TEXEL_HEIGHT_NV 0x955D\n#define GL_SHADING_RATE_IMAGE_PALETTE_SIZE_NV 0x955E\n#define GL_MAX_COARSE_FRAGMENT_SAMPLES_NV 0x955F\n#define GL_SHADING_RATE_SAMPLE_ORDER_DEFAULT_NV 0x95AE\n#define GL_SHADING_RATE_SAMPLE_ORDER_PIXEL_MAJOR_NV 0x95AF\n#define GL_SHADING_RATE_SAMPLE_ORDER_SAMPLE_MAJOR_NV 0x95B0\ntypedef void (APIENTRYP PFNGLBINDSHADINGRATEIMAGENVPROC) (GLuint texture);\ntypedef void (APIENTRYP PFNGLGETSHADINGRATEIMAGEPALETTENVPROC) (GLuint viewport, GLuint entry, GLenum *rate);\ntypedef void (APIENTRYP PFNGLGETSHADINGRATESAMPLELOCATIONIVNVPROC) (GLenum rate, GLuint samples, GLuint index, GLint *location);\ntypedef void (APIENTRYP PFNGLSHADINGRATEIMAGEBARRIERNVPROC) (GLboolean synchronize);\ntypedef void (APIENTRYP PFNGLSHADINGRATEIMAGEPALETTENVPROC) (GLuint viewport, GLuint first, GLsizei count, const GLenum *rates);\ntypedef void (APIENTRYP PFNGLSHADINGRATESAMPLEORDERNVPROC) (GLenum order);\ntypedef void (APIENTRYP PFNGLSHADINGRATESAMPLEORDERCUSTOMNVPROC) (GLenum rate, GLuint samples, const GLint *locations);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBindShadingRateImageNV (GLuint texture);\nGLAPI void APIENTRY glGetShadingRateImagePaletteNV (GLuint viewport, GLuint entry, GLenum *rate);\nGLAPI void APIENTRY glGetShadingRateSampleLocationivNV (GLenum rate, GLuint samples, GLuint index, GLint *location);\nGLAPI void APIENTRY glShadingRateImageBarrierNV (GLboolean synchronize);\nGLAPI void APIENTRY glShadingRateImagePaletteNV (GLuint viewport, GLuint first, GLsizei count, const GLenum *rates);\nGLAPI void APIENTRY glShadingRateSampleOrderNV (GLenum order);\nGLAPI void APIENTRY glShadingRateSampleOrderCustomNV (GLenum rate, GLuint samples, const GLint *locations);\n#endif\n#endif /* GL_NV_shading_rate_image */\n\n#ifndef GL_NV_stereo_view_rendering\n#define GL_NV_stereo_view_rendering 1\n#endif /* GL_NV_stereo_view_rendering */\n\n#ifndef GL_NV_tessellation_program5\n#define GL_NV_tessellation_program5 1\n#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV   0x86D8\n#define GL_TESS_CONTROL_PROGRAM_NV        0x891E\n#define GL_TESS_EVALUATION_PROGRAM_NV     0x891F\n#define GL_TESS_CONTROL_PROGRAM_PARAMETER_BUFFER_NV 0x8C74\n#define GL_TESS_EVALUATION_PROGRAM_PARAMETER_BUFFER_NV 0x8C75\n#endif /* GL_NV_tessellation_program5 */\n\n#ifndef GL_NV_texgen_emboss\n#define GL_NV_texgen_emboss 1\n#define GL_EMBOSS_LIGHT_NV                0x855D\n#define GL_EMBOSS_CONSTANT_NV             0x855E\n#define GL_EMBOSS_MAP_NV                  0x855F\n#endif /* GL_NV_texgen_emboss */\n\n#ifndef GL_NV_texgen_reflection\n#define GL_NV_texgen_reflection 1\n#define GL_NORMAL_MAP_NV                  0x8511\n#define GL_REFLECTION_MAP_NV              0x8512\n#endif /* GL_NV_texgen_reflection */\n\n#ifndef GL_NV_texture_barrier\n#define GL_NV_texture_barrier 1\ntypedef void (APIENTRYP PFNGLTEXTUREBARRIERNVPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTextureBarrierNV (void);\n#endif\n#endif /* GL_NV_texture_barrier */\n\n#ifndef GL_NV_texture_compression_vtc\n#define GL_NV_texture_compression_vtc 1\n#endif /* GL_NV_texture_compression_vtc */\n\n#ifndef GL_NV_texture_env_combine4\n#define GL_NV_texture_env_combine4 1\n#define GL_COMBINE4_NV                    0x8503\n#define GL_SOURCE3_RGB_NV                 0x8583\n#define GL_SOURCE3_ALPHA_NV               0x858B\n#define GL_OPERAND3_RGB_NV                0x8593\n#define GL_OPERAND3_ALPHA_NV              0x859B\n#endif /* GL_NV_texture_env_combine4 */\n\n#ifndef GL_NV_texture_expand_normal\n#define GL_NV_texture_expand_normal 1\n#define GL_TEXTURE_UNSIGNED_REMAP_MODE_NV 0x888F\n#endif /* GL_NV_texture_expand_normal */\n\n#ifndef GL_NV_texture_multisample\n#define GL_NV_texture_multisample 1\n#define GL_TEXTURE_COVERAGE_SAMPLES_NV    0x9045\n#define GL_TEXTURE_COLOR_SAMPLES_NV       0x9046\ntypedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);\ntypedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);\ntypedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);\ntypedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLENVPROC) (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);\ntypedef void (APIENTRYP PFNGLTEXTUREIMAGE2DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);\ntypedef void (APIENTRYP PFNGLTEXTUREIMAGE3DMULTISAMPLECOVERAGENVPROC) (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexImage2DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);\nGLAPI void APIENTRY glTexImage3DMultisampleCoverageNV (GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);\nGLAPI void APIENTRY glTextureImage2DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);\nGLAPI void APIENTRY glTextureImage3DMultisampleNV (GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);\nGLAPI void APIENTRY glTextureImage2DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations);\nGLAPI void APIENTRY glTextureImage3DMultisampleCoverageNV (GLuint texture, GLenum target, GLsizei coverageSamples, GLsizei colorSamples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations);\n#endif\n#endif /* GL_NV_texture_multisample */\n\n#ifndef GL_NV_texture_rectangle\n#define GL_NV_texture_rectangle 1\n#define GL_TEXTURE_RECTANGLE_NV           0x84F5\n#define GL_TEXTURE_BINDING_RECTANGLE_NV   0x84F6\n#define GL_PROXY_TEXTURE_RECTANGLE_NV     0x84F7\n#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV  0x84F8\n#endif /* GL_NV_texture_rectangle */\n\n#ifndef GL_NV_texture_rectangle_compressed\n#define GL_NV_texture_rectangle_compressed 1\n#endif /* GL_NV_texture_rectangle_compressed */\n\n#ifndef GL_NV_texture_shader\n#define GL_NV_texture_shader 1\n#define GL_OFFSET_TEXTURE_RECTANGLE_NV    0x864C\n#define GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV 0x864D\n#define GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV 0x864E\n#define GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV 0x86D9\n#define GL_UNSIGNED_INT_S8_S8_8_8_NV      0x86DA\n#define GL_UNSIGNED_INT_8_8_S8_S8_REV_NV  0x86DB\n#define GL_DSDT_MAG_INTENSITY_NV          0x86DC\n#define GL_SHADER_CONSISTENT_NV           0x86DD\n#define GL_TEXTURE_SHADER_NV              0x86DE\n#define GL_SHADER_OPERATION_NV            0x86DF\n#define GL_CULL_MODES_NV                  0x86E0\n#define GL_OFFSET_TEXTURE_MATRIX_NV       0x86E1\n#define GL_OFFSET_TEXTURE_SCALE_NV        0x86E2\n#define GL_OFFSET_TEXTURE_BIAS_NV         0x86E3\n#define GL_OFFSET_TEXTURE_2D_MATRIX_NV    0x86E1\n#define GL_OFFSET_TEXTURE_2D_SCALE_NV     0x86E2\n#define GL_OFFSET_TEXTURE_2D_BIAS_NV      0x86E3\n#define GL_PREVIOUS_TEXTURE_INPUT_NV      0x86E4\n#define GL_CONST_EYE_NV                   0x86E5\n#define GL_PASS_THROUGH_NV                0x86E6\n#define GL_CULL_FRAGMENT_NV               0x86E7\n#define GL_OFFSET_TEXTURE_2D_NV           0x86E8\n#define GL_DEPENDENT_AR_TEXTURE_2D_NV     0x86E9\n#define GL_DEPENDENT_GB_TEXTURE_2D_NV     0x86EA\n#define GL_DOT_PRODUCT_NV                 0x86EC\n#define GL_DOT_PRODUCT_DEPTH_REPLACE_NV   0x86ED\n#define GL_DOT_PRODUCT_TEXTURE_2D_NV      0x86EE\n#define GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV 0x86F0\n#define GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV 0x86F1\n#define GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV 0x86F2\n#define GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV 0x86F3\n#define GL_HILO_NV                        0x86F4\n#define GL_DSDT_NV                        0x86F5\n#define GL_DSDT_MAG_NV                    0x86F6\n#define GL_DSDT_MAG_VIB_NV                0x86F7\n#define GL_HILO16_NV                      0x86F8\n#define GL_SIGNED_HILO_NV                 0x86F9\n#define GL_SIGNED_HILO16_NV               0x86FA\n#define GL_SIGNED_RGBA_NV                 0x86FB\n#define GL_SIGNED_RGBA8_NV                0x86FC\n#define GL_SIGNED_RGB_NV                  0x86FE\n#define GL_SIGNED_RGB8_NV                 0x86FF\n#define GL_SIGNED_LUMINANCE_NV            0x8701\n#define GL_SIGNED_LUMINANCE8_NV           0x8702\n#define GL_SIGNED_LUMINANCE_ALPHA_NV      0x8703\n#define GL_SIGNED_LUMINANCE8_ALPHA8_NV    0x8704\n#define GL_SIGNED_ALPHA_NV                0x8705\n#define GL_SIGNED_ALPHA8_NV               0x8706\n#define GL_SIGNED_INTENSITY_NV            0x8707\n#define GL_SIGNED_INTENSITY8_NV           0x8708\n#define GL_DSDT8_NV                       0x8709\n#define GL_DSDT8_MAG8_NV                  0x870A\n#define GL_DSDT8_MAG8_INTENSITY8_NV       0x870B\n#define GL_SIGNED_RGB_UNSIGNED_ALPHA_NV   0x870C\n#define GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV 0x870D\n#define GL_HI_SCALE_NV                    0x870E\n#define GL_LO_SCALE_NV                    0x870F\n#define GL_DS_SCALE_NV                    0x8710\n#define GL_DT_SCALE_NV                    0x8711\n#define GL_MAGNITUDE_SCALE_NV             0x8712\n#define GL_VIBRANCE_SCALE_NV              0x8713\n#define GL_HI_BIAS_NV                     0x8714\n#define GL_LO_BIAS_NV                     0x8715\n#define GL_DS_BIAS_NV                     0x8716\n#define GL_DT_BIAS_NV                     0x8717\n#define GL_MAGNITUDE_BIAS_NV              0x8718\n#define GL_VIBRANCE_BIAS_NV               0x8719\n#define GL_TEXTURE_BORDER_VALUES_NV       0x871A\n#define GL_TEXTURE_HI_SIZE_NV             0x871B\n#define GL_TEXTURE_LO_SIZE_NV             0x871C\n#define GL_TEXTURE_DS_SIZE_NV             0x871D\n#define GL_TEXTURE_DT_SIZE_NV             0x871E\n#define GL_TEXTURE_MAG_SIZE_NV            0x871F\n#endif /* GL_NV_texture_shader */\n\n#ifndef GL_NV_texture_shader2\n#define GL_NV_texture_shader2 1\n#define GL_DOT_PRODUCT_TEXTURE_3D_NV      0x86EF\n#endif /* GL_NV_texture_shader2 */\n\n#ifndef GL_NV_texture_shader3\n#define GL_NV_texture_shader3 1\n#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV 0x8850\n#define GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV 0x8851\n#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8852\n#define GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV 0x8853\n#define GL_OFFSET_HILO_TEXTURE_2D_NV      0x8854\n#define GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV 0x8855\n#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV 0x8856\n#define GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV 0x8857\n#define GL_DEPENDENT_HILO_TEXTURE_2D_NV   0x8858\n#define GL_DEPENDENT_RGB_TEXTURE_3D_NV    0x8859\n#define GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV 0x885A\n#define GL_DOT_PRODUCT_PASS_THROUGH_NV    0x885B\n#define GL_DOT_PRODUCT_TEXTURE_1D_NV      0x885C\n#define GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV 0x885D\n#define GL_HILO8_NV                       0x885E\n#define GL_SIGNED_HILO8_NV                0x885F\n#define GL_FORCE_BLUE_TO_ONE_NV           0x8860\n#endif /* GL_NV_texture_shader3 */\n\n#ifndef GL_NV_timeline_semaphore\n#define GL_NV_timeline_semaphore 1\n#define GL_TIMELINE_SEMAPHORE_VALUE_NV    0x9595\n#define GL_SEMAPHORE_TYPE_NV              0x95B3\n#define GL_SEMAPHORE_TYPE_BINARY_NV       0x95B4\n#define GL_SEMAPHORE_TYPE_TIMELINE_NV     0x95B5\n#define GL_MAX_TIMELINE_SEMAPHORE_VALUE_DIFFERENCE_NV 0x95B6\ntypedef void (APIENTRYP PFNGLCREATESEMAPHORESNVPROC) (GLsizei n, GLuint *semaphores);\ntypedef void (APIENTRYP PFNGLSEMAPHOREPARAMETERIVNVPROC) (GLuint semaphore, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLGETSEMAPHOREPARAMETERIVNVPROC) (GLuint semaphore, GLenum pname, GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glCreateSemaphoresNV (GLsizei n, GLuint *semaphores);\nGLAPI void APIENTRY glSemaphoreParameterivNV (GLuint semaphore, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glGetSemaphoreParameterivNV (GLuint semaphore, GLenum pname, GLint *params);\n#endif\n#endif /* GL_NV_timeline_semaphore */\n\n#ifndef GL_NV_transform_feedback\n#define GL_NV_transform_feedback 1\n#define GL_BACK_PRIMARY_COLOR_NV          0x8C77\n#define GL_BACK_SECONDARY_COLOR_NV        0x8C78\n#define GL_TEXTURE_COORD_NV               0x8C79\n#define GL_CLIP_DISTANCE_NV               0x8C7A\n#define GL_VERTEX_ID_NV                   0x8C7B\n#define GL_PRIMITIVE_ID_NV                0x8C7C\n#define GL_GENERIC_ATTRIB_NV              0x8C7D\n#define GL_TRANSFORM_FEEDBACK_ATTRIBS_NV  0x8C7E\n#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE_NV 0x8C7F\n#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS_NV 0x8C80\n#define GL_ACTIVE_VARYINGS_NV             0x8C81\n#define GL_ACTIVE_VARYING_MAX_LENGTH_NV   0x8C82\n#define GL_TRANSFORM_FEEDBACK_VARYINGS_NV 0x8C83\n#define GL_TRANSFORM_FEEDBACK_BUFFER_START_NV 0x8C84\n#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE_NV 0x8C85\n#define GL_TRANSFORM_FEEDBACK_RECORD_NV   0x8C86\n#define GL_PRIMITIVES_GENERATED_NV        0x8C87\n#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN_NV 0x8C88\n#define GL_RASTERIZER_DISCARD_NV          0x8C89\n#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS_NV 0x8C8A\n#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS_NV 0x8C8B\n#define GL_INTERLEAVED_ATTRIBS_NV         0x8C8C\n#define GL_SEPARATE_ATTRIBS_NV            0x8C8D\n#define GL_TRANSFORM_FEEDBACK_BUFFER_NV   0x8C8E\n#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING_NV 0x8C8F\n#define GL_LAYER_NV                       0x8DAA\n#define GL_NEXT_BUFFER_NV                 -2\n#define GL_SKIP_COMPONENTS4_NV            -3\n#define GL_SKIP_COMPONENTS3_NV            -4\n#define GL_SKIP_COMPONENTS2_NV            -5\n#define GL_SKIP_COMPONENTS1_NV            -6\ntypedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKNVPROC) (GLenum primitiveMode);\ntypedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKNVPROC) (void);\ntypedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLenum bufferMode);\ntypedef void (APIENTRYP PFNGLBINDBUFFERRANGENVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (APIENTRYP PFNGLBINDBUFFEROFFSETNVPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset);\ntypedef void (APIENTRYP PFNGLBINDBUFFERBASENVPROC) (GLenum target, GLuint index, GLuint buffer);\ntypedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSNVPROC) (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode);\ntypedef void (APIENTRYP PFNGLACTIVEVARYINGNVPROC) (GLuint program, const GLchar *name);\ntypedef GLint (APIENTRYP PFNGLGETVARYINGLOCATIONNVPROC) (GLuint program, const GLchar *name);\ntypedef void (APIENTRYP PFNGLGETACTIVEVARYINGNVPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);\ntypedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGNVPROC) (GLuint program, GLuint index, GLint *location);\ntypedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKSTREAMATTRIBSNVPROC) (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBeginTransformFeedbackNV (GLenum primitiveMode);\nGLAPI void APIENTRY glEndTransformFeedbackNV (void);\nGLAPI void APIENTRY glTransformFeedbackAttribsNV (GLsizei count, const GLint *attribs, GLenum bufferMode);\nGLAPI void APIENTRY glBindBufferRangeNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\nGLAPI void APIENTRY glBindBufferOffsetNV (GLenum target, GLuint index, GLuint buffer, GLintptr offset);\nGLAPI void APIENTRY glBindBufferBaseNV (GLenum target, GLuint index, GLuint buffer);\nGLAPI void APIENTRY glTransformFeedbackVaryingsNV (GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode);\nGLAPI void APIENTRY glActiveVaryingNV (GLuint program, const GLchar *name);\nGLAPI GLint APIENTRY glGetVaryingLocationNV (GLuint program, const GLchar *name);\nGLAPI void APIENTRY glGetActiveVaryingNV (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name);\nGLAPI void APIENTRY glGetTransformFeedbackVaryingNV (GLuint program, GLuint index, GLint *location);\nGLAPI void APIENTRY glTransformFeedbackStreamAttribsNV (GLsizei count, const GLint *attribs, GLsizei nbuffers, const GLint *bufstreams, GLenum bufferMode);\n#endif\n#endif /* GL_NV_transform_feedback */\n\n#ifndef GL_NV_transform_feedback2\n#define GL_NV_transform_feedback2 1\n#define GL_TRANSFORM_FEEDBACK_NV          0x8E22\n#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23\n#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24\n#define GL_TRANSFORM_FEEDBACK_BINDING_NV  0x8E25\ntypedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids);\ntypedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids);\ntypedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void);\ntypedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void);\ntypedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBindTransformFeedbackNV (GLenum target, GLuint id);\nGLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei n, const GLuint *ids);\nGLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei n, GLuint *ids);\nGLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint id);\nGLAPI void APIENTRY glPauseTransformFeedbackNV (void);\nGLAPI void APIENTRY glResumeTransformFeedbackNV (void);\nGLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum mode, GLuint id);\n#endif\n#endif /* GL_NV_transform_feedback2 */\n\n#ifndef GL_NV_uniform_buffer_unified_memory\n#define GL_NV_uniform_buffer_unified_memory 1\n#define GL_UNIFORM_BUFFER_UNIFIED_NV      0x936E\n#define GL_UNIFORM_BUFFER_ADDRESS_NV      0x936F\n#define GL_UNIFORM_BUFFER_LENGTH_NV       0x9370\n#endif /* GL_NV_uniform_buffer_unified_memory */\n\n#ifndef GL_NV_vdpau_interop\n#define GL_NV_vdpau_interop 1\ntypedef GLintptr GLvdpauSurfaceNV;\n#define GL_SURFACE_STATE_NV               0x86EB\n#define GL_SURFACE_REGISTERED_NV          0x86FD\n#define GL_SURFACE_MAPPED_NV              0x8700\n#define GL_WRITE_DISCARD_NV               0x88BE\ntypedef void (APIENTRYP PFNGLVDPAUINITNVPROC) (const void *vdpDevice, const void *getProcAddress);\ntypedef void (APIENTRYP PFNGLVDPAUFININVPROC) (void);\ntypedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);\ntypedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);\ntypedef GLboolean (APIENTRYP PFNGLVDPAUISSURFACENVPROC) (GLvdpauSurfaceNV surface);\ntypedef void (APIENTRYP PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV surface);\ntypedef void (APIENTRYP PFNGLVDPAUGETSURFACEIVNVPROC) (GLvdpauSurfaceNV surface, GLenum pname, GLsizei count, GLsizei *length, GLint *values);\ntypedef void (APIENTRYP PFNGLVDPAUSURFACEACCESSNVPROC) (GLvdpauSurfaceNV surface, GLenum access);\ntypedef void (APIENTRYP PFNGLVDPAUMAPSURFACESNVPROC) (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces);\ntypedef void (APIENTRYP PFNGLVDPAUUNMAPSURFACESNVPROC) (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVDPAUInitNV (const void *vdpDevice, const void *getProcAddress);\nGLAPI void APIENTRY glVDPAUFiniNV (void);\nGLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);\nGLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterOutputSurfaceNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames);\nGLAPI GLboolean APIENTRY glVDPAUIsSurfaceNV (GLvdpauSurfaceNV surface);\nGLAPI void APIENTRY glVDPAUUnregisterSurfaceNV (GLvdpauSurfaceNV surface);\nGLAPI void APIENTRY glVDPAUGetSurfaceivNV (GLvdpauSurfaceNV surface, GLenum pname, GLsizei count, GLsizei *length, GLint *values);\nGLAPI void APIENTRY glVDPAUSurfaceAccessNV (GLvdpauSurfaceNV surface, GLenum access);\nGLAPI void APIENTRY glVDPAUMapSurfacesNV (GLsizei numSurfaces, const GLvdpauSurfaceNV *surfaces);\nGLAPI void APIENTRY glVDPAUUnmapSurfacesNV (GLsizei numSurface, const GLvdpauSurfaceNV *surfaces);\n#endif\n#endif /* GL_NV_vdpau_interop */\n\n#ifndef GL_NV_vdpau_interop2\n#define GL_NV_vdpau_interop2 1\ntypedef GLvdpauSurfaceNV (APIENTRYP PFNGLVDPAUREGISTERVIDEOSURFACEWITHPICTURESTRUCTURENVPROC) (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames, GLboolean isFrameStructure);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLvdpauSurfaceNV APIENTRY glVDPAURegisterVideoSurfaceWithPictureStructureNV (const void *vdpSurface, GLenum target, GLsizei numTextureNames, const GLuint *textureNames, GLboolean isFrameStructure);\n#endif\n#endif /* GL_NV_vdpau_interop2 */\n\n#ifndef GL_NV_vertex_array_range\n#define GL_NV_vertex_array_range 1\n#define GL_VERTEX_ARRAY_RANGE_NV          0x851D\n#define GL_VERTEX_ARRAY_RANGE_LENGTH_NV   0x851E\n#define GL_VERTEX_ARRAY_RANGE_VALID_NV    0x851F\n#define GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV 0x8520\n#define GL_VERTEX_ARRAY_RANGE_POINTER_NV  0x8521\ntypedef void (APIENTRYP PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void);\ntypedef void (APIENTRYP PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, const void *pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFlushVertexArrayRangeNV (void);\nGLAPI void APIENTRY glVertexArrayRangeNV (GLsizei length, const void *pointer);\n#endif\n#endif /* GL_NV_vertex_array_range */\n\n#ifndef GL_NV_vertex_array_range2\n#define GL_NV_vertex_array_range2 1\n#define GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV 0x8533\n#endif /* GL_NV_vertex_array_range2 */\n\n#ifndef GL_NV_vertex_attrib_integer_64bit\n#define GL_NV_vertex_attrib_integer_64bit 1\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64NVPROC) (GLuint index, GLint64EXT x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64NVPROC) (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1I64VNVPROC) (GLuint index, const GLint64EXT *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL2I64VNVPROC) (GLuint index, const GLint64EXT *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL3I64VNVPROC) (GLuint index, const GLint64EXT *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL4I64VNVPROC) (GLuint index, const GLint64EXT *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64NVPROC) (GLuint index, GLuint64EXT x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64NVPROC) (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VNVPROC) (GLuint index, const GLuint64EXT *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL2UI64VNVPROC) (GLuint index, const GLuint64EXT *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL3UI64VNVPROC) (GLuint index, const GLuint64EXT *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBL4UI64VNVPROC) (GLuint index, const GLuint64EXT *v);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBLI64VNVPROC) (GLuint index, GLenum pname, GLint64EXT *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VNVPROC) (GLuint index, GLenum pname, GLuint64EXT *params);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glVertexAttribL1i64NV (GLuint index, GLint64EXT x);\nGLAPI void APIENTRY glVertexAttribL2i64NV (GLuint index, GLint64EXT x, GLint64EXT y);\nGLAPI void APIENTRY glVertexAttribL3i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z);\nGLAPI void APIENTRY glVertexAttribL4i64NV (GLuint index, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w);\nGLAPI void APIENTRY glVertexAttribL1i64vNV (GLuint index, const GLint64EXT *v);\nGLAPI void APIENTRY glVertexAttribL2i64vNV (GLuint index, const GLint64EXT *v);\nGLAPI void APIENTRY glVertexAttribL3i64vNV (GLuint index, const GLint64EXT *v);\nGLAPI void APIENTRY glVertexAttribL4i64vNV (GLuint index, const GLint64EXT *v);\nGLAPI void APIENTRY glVertexAttribL1ui64NV (GLuint index, GLuint64EXT x);\nGLAPI void APIENTRY glVertexAttribL2ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y);\nGLAPI void APIENTRY glVertexAttribL3ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z);\nGLAPI void APIENTRY glVertexAttribL4ui64NV (GLuint index, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w);\nGLAPI void APIENTRY glVertexAttribL1ui64vNV (GLuint index, const GLuint64EXT *v);\nGLAPI void APIENTRY glVertexAttribL2ui64vNV (GLuint index, const GLuint64EXT *v);\nGLAPI void APIENTRY glVertexAttribL3ui64vNV (GLuint index, const GLuint64EXT *v);\nGLAPI void APIENTRY glVertexAttribL4ui64vNV (GLuint index, const GLuint64EXT *v);\nGLAPI void APIENTRY glGetVertexAttribLi64vNV (GLuint index, GLenum pname, GLint64EXT *params);\nGLAPI void APIENTRY glGetVertexAttribLui64vNV (GLuint index, GLenum pname, GLuint64EXT *params);\nGLAPI void APIENTRY glVertexAttribLFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride);\n#endif\n#endif /* GL_NV_vertex_attrib_integer_64bit */\n\n#ifndef GL_NV_vertex_buffer_unified_memory\n#define GL_NV_vertex_buffer_unified_memory 1\n#define GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV 0x8F1E\n#define GL_ELEMENT_ARRAY_UNIFIED_NV       0x8F1F\n#define GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV 0x8F20\n#define GL_VERTEX_ARRAY_ADDRESS_NV        0x8F21\n#define GL_NORMAL_ARRAY_ADDRESS_NV        0x8F22\n#define GL_COLOR_ARRAY_ADDRESS_NV         0x8F23\n#define GL_INDEX_ARRAY_ADDRESS_NV         0x8F24\n#define GL_TEXTURE_COORD_ARRAY_ADDRESS_NV 0x8F25\n#define GL_EDGE_FLAG_ARRAY_ADDRESS_NV     0x8F26\n#define GL_SECONDARY_COLOR_ARRAY_ADDRESS_NV 0x8F27\n#define GL_FOG_COORD_ARRAY_ADDRESS_NV     0x8F28\n#define GL_ELEMENT_ARRAY_ADDRESS_NV       0x8F29\n#define GL_VERTEX_ATTRIB_ARRAY_LENGTH_NV  0x8F2A\n#define GL_VERTEX_ARRAY_LENGTH_NV         0x8F2B\n#define GL_NORMAL_ARRAY_LENGTH_NV         0x8F2C\n#define GL_COLOR_ARRAY_LENGTH_NV          0x8F2D\n#define GL_INDEX_ARRAY_LENGTH_NV          0x8F2E\n#define GL_TEXTURE_COORD_ARRAY_LENGTH_NV  0x8F2F\n#define GL_EDGE_FLAG_ARRAY_LENGTH_NV      0x8F30\n#define GL_SECONDARY_COLOR_ARRAY_LENGTH_NV 0x8F31\n#define GL_FOG_COORD_ARRAY_LENGTH_NV      0x8F32\n#define GL_ELEMENT_ARRAY_LENGTH_NV        0x8F33\n#define GL_DRAW_INDIRECT_UNIFIED_NV       0x8F40\n#define GL_DRAW_INDIRECT_ADDRESS_NV       0x8F41\n#define GL_DRAW_INDIRECT_LENGTH_NV        0x8F42\ntypedef void (APIENTRYP PFNGLBUFFERADDRESSRANGENVPROC) (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length);\ntypedef void (APIENTRYP PFNGLVERTEXFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);\ntypedef void (APIENTRYP PFNGLNORMALFORMATNVPROC) (GLenum type, GLsizei stride);\ntypedef void (APIENTRYP PFNGLCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);\ntypedef void (APIENTRYP PFNGLINDEXFORMATNVPROC) (GLenum type, GLsizei stride);\ntypedef void (APIENTRYP PFNGLTEXCOORDFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);\ntypedef void (APIENTRYP PFNGLEDGEFLAGFORMATNVPROC) (GLsizei stride);\ntypedef void (APIENTRYP PFNGLSECONDARYCOLORFORMATNVPROC) (GLint size, GLenum type, GLsizei stride);\ntypedef void (APIENTRYP PFNGLFOGCOORDFORMATNVPROC) (GLenum type, GLsizei stride);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride);\ntypedef void (APIENTRYP PFNGLGETINTEGERUI64I_VNVPROC) (GLenum value, GLuint index, GLuint64EXT *result);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBufferAddressRangeNV (GLenum pname, GLuint index, GLuint64EXT address, GLsizeiptr length);\nGLAPI void APIENTRY glVertexFormatNV (GLint size, GLenum type, GLsizei stride);\nGLAPI void APIENTRY glNormalFormatNV (GLenum type, GLsizei stride);\nGLAPI void APIENTRY glColorFormatNV (GLint size, GLenum type, GLsizei stride);\nGLAPI void APIENTRY glIndexFormatNV (GLenum type, GLsizei stride);\nGLAPI void APIENTRY glTexCoordFormatNV (GLint size, GLenum type, GLsizei stride);\nGLAPI void APIENTRY glEdgeFlagFormatNV (GLsizei stride);\nGLAPI void APIENTRY glSecondaryColorFormatNV (GLint size, GLenum type, GLsizei stride);\nGLAPI void APIENTRY glFogCoordFormatNV (GLenum type, GLsizei stride);\nGLAPI void APIENTRY glVertexAttribFormatNV (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride);\nGLAPI void APIENTRY glVertexAttribIFormatNV (GLuint index, GLint size, GLenum type, GLsizei stride);\nGLAPI void APIENTRY glGetIntegerui64i_vNV (GLenum value, GLuint index, GLuint64EXT *result);\n#endif\n#endif /* GL_NV_vertex_buffer_unified_memory */\n\n#ifndef GL_NV_vertex_program\n#define GL_NV_vertex_program 1\n#define GL_VERTEX_PROGRAM_NV              0x8620\n#define GL_VERTEX_STATE_PROGRAM_NV        0x8621\n#define GL_ATTRIB_ARRAY_SIZE_NV           0x8623\n#define GL_ATTRIB_ARRAY_STRIDE_NV         0x8624\n#define GL_ATTRIB_ARRAY_TYPE_NV           0x8625\n#define GL_CURRENT_ATTRIB_NV              0x8626\n#define GL_PROGRAM_LENGTH_NV              0x8627\n#define GL_PROGRAM_STRING_NV              0x8628\n#define GL_MODELVIEW_PROJECTION_NV        0x8629\n#define GL_IDENTITY_NV                    0x862A\n#define GL_INVERSE_NV                     0x862B\n#define GL_TRANSPOSE_NV                   0x862C\n#define GL_INVERSE_TRANSPOSE_NV           0x862D\n#define GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV 0x862E\n#define GL_MAX_TRACK_MATRICES_NV          0x862F\n#define GL_MATRIX0_NV                     0x8630\n#define GL_MATRIX1_NV                     0x8631\n#define GL_MATRIX2_NV                     0x8632\n#define GL_MATRIX3_NV                     0x8633\n#define GL_MATRIX4_NV                     0x8634\n#define GL_MATRIX5_NV                     0x8635\n#define GL_MATRIX6_NV                     0x8636\n#define GL_MATRIX7_NV                     0x8637\n#define GL_CURRENT_MATRIX_STACK_DEPTH_NV  0x8640\n#define GL_CURRENT_MATRIX_NV              0x8641\n#define GL_VERTEX_PROGRAM_POINT_SIZE_NV   0x8642\n#define GL_VERTEX_PROGRAM_TWO_SIDE_NV     0x8643\n#define GL_PROGRAM_PARAMETER_NV           0x8644\n#define GL_ATTRIB_ARRAY_POINTER_NV        0x8645\n#define GL_PROGRAM_TARGET_NV              0x8646\n#define GL_PROGRAM_RESIDENT_NV            0x8647\n#define GL_TRACK_MATRIX_NV                0x8648\n#define GL_TRACK_MATRIX_TRANSFORM_NV      0x8649\n#define GL_VERTEX_PROGRAM_BINDING_NV      0x864A\n#define GL_PROGRAM_ERROR_POSITION_NV      0x864B\n#define GL_VERTEX_ATTRIB_ARRAY0_NV        0x8650\n#define GL_VERTEX_ATTRIB_ARRAY1_NV        0x8651\n#define GL_VERTEX_ATTRIB_ARRAY2_NV        0x8652\n#define GL_VERTEX_ATTRIB_ARRAY3_NV        0x8653\n#define GL_VERTEX_ATTRIB_ARRAY4_NV        0x8654\n#define GL_VERTEX_ATTRIB_ARRAY5_NV        0x8655\n#define GL_VERTEX_ATTRIB_ARRAY6_NV        0x8656\n#define GL_VERTEX_ATTRIB_ARRAY7_NV        0x8657\n#define GL_VERTEX_ATTRIB_ARRAY8_NV        0x8658\n#define GL_VERTEX_ATTRIB_ARRAY9_NV        0x8659\n#define GL_VERTEX_ATTRIB_ARRAY10_NV       0x865A\n#define GL_VERTEX_ATTRIB_ARRAY11_NV       0x865B\n#define GL_VERTEX_ATTRIB_ARRAY12_NV       0x865C\n#define GL_VERTEX_ATTRIB_ARRAY13_NV       0x865D\n#define GL_VERTEX_ATTRIB_ARRAY14_NV       0x865E\n#define GL_VERTEX_ATTRIB_ARRAY15_NV       0x865F\n#define GL_MAP1_VERTEX_ATTRIB0_4_NV       0x8660\n#define GL_MAP1_VERTEX_ATTRIB1_4_NV       0x8661\n#define GL_MAP1_VERTEX_ATTRIB2_4_NV       0x8662\n#define GL_MAP1_VERTEX_ATTRIB3_4_NV       0x8663\n#define GL_MAP1_VERTEX_ATTRIB4_4_NV       0x8664\n#define GL_MAP1_VERTEX_ATTRIB5_4_NV       0x8665\n#define GL_MAP1_VERTEX_ATTRIB6_4_NV       0x8666\n#define GL_MAP1_VERTEX_ATTRIB7_4_NV       0x8667\n#define GL_MAP1_VERTEX_ATTRIB8_4_NV       0x8668\n#define GL_MAP1_VERTEX_ATTRIB9_4_NV       0x8669\n#define GL_MAP1_VERTEX_ATTRIB10_4_NV      0x866A\n#define GL_MAP1_VERTEX_ATTRIB11_4_NV      0x866B\n#define GL_MAP1_VERTEX_ATTRIB12_4_NV      0x866C\n#define GL_MAP1_VERTEX_ATTRIB13_4_NV      0x866D\n#define GL_MAP1_VERTEX_ATTRIB14_4_NV      0x866E\n#define GL_MAP1_VERTEX_ATTRIB15_4_NV      0x866F\n#define GL_MAP2_VERTEX_ATTRIB0_4_NV       0x8670\n#define GL_MAP2_VERTEX_ATTRIB1_4_NV       0x8671\n#define GL_MAP2_VERTEX_ATTRIB2_4_NV       0x8672\n#define GL_MAP2_VERTEX_ATTRIB3_4_NV       0x8673\n#define GL_MAP2_VERTEX_ATTRIB4_4_NV       0x8674\n#define GL_MAP2_VERTEX_ATTRIB5_4_NV       0x8675\n#define GL_MAP2_VERTEX_ATTRIB6_4_NV       0x8676\n#define GL_MAP2_VERTEX_ATTRIB7_4_NV       0x8677\n#define GL_MAP2_VERTEX_ATTRIB8_4_NV       0x8678\n#define GL_MAP2_VERTEX_ATTRIB9_4_NV       0x8679\n#define GL_MAP2_VERTEX_ATTRIB10_4_NV      0x867A\n#define GL_MAP2_VERTEX_ATTRIB11_4_NV      0x867B\n#define GL_MAP2_VERTEX_ATTRIB12_4_NV      0x867C\n#define GL_MAP2_VERTEX_ATTRIB13_4_NV      0x867D\n#define GL_MAP2_VERTEX_ATTRIB14_4_NV      0x867E\n#define GL_MAP2_VERTEX_ATTRIB15_4_NV      0x867F\ntypedef GLboolean (APIENTRYP PFNGLAREPROGRAMSRESIDENTNVPROC) (GLsizei n, const GLuint *programs, GLboolean *residences);\ntypedef void (APIENTRYP PFNGLBINDPROGRAMNVPROC) (GLenum target, GLuint id);\ntypedef void (APIENTRYP PFNGLDELETEPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);\ntypedef void (APIENTRYP PFNGLEXECUTEPROGRAMNVPROC) (GLenum target, GLuint id, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGENPROGRAMSNVPROC) (GLsizei n, GLuint *programs);\ntypedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERDVNVPROC) (GLenum target, GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMIVNVPROC) (GLuint id, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPROGRAMSTRINGNVPROC) (GLuint id, GLenum pname, GLubyte *program);\ntypedef void (APIENTRYP PFNGLGETTRACKMATRIXIVNVPROC) (GLenum target, GLuint address, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVNVPROC) (GLuint index, GLenum pname, GLdouble *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVNVPROC) (GLuint index, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVNVPROC) (GLuint index, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVNVPROC) (GLuint index, GLenum pname, void **pointer);\ntypedef GLboolean (APIENTRYP PFNGLISPROGRAMNVPROC) (GLuint id);\ntypedef void (APIENTRYP PFNGLLOADPROGRAMNVPROC) (GLenum target, GLuint id, GLsizei len, const GLubyte *program);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DNVPROC) (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETER4DVNVPROC) (GLenum target, GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FNVPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETER4FVNVPROC) (GLenum target, GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4DVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLPROGRAMPARAMETERS4FVNVPROC) (GLenum target, GLuint index, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREQUESTRESIDENTPROGRAMSNVPROC) (GLsizei n, const GLuint *programs);\ntypedef void (APIENTRYP PFNGLTRACKMATRIXNVPROC) (GLenum target, GLuint address, GLenum matrix, GLenum transform);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DNVPROC) (GLuint index, GLdouble x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1DVNVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FNVPROC) (GLuint index, GLfloat x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1FVNVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SNVPROC) (GLuint index, GLshort x);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB1SVNVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DNVPROC) (GLuint index, GLdouble x, GLdouble y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2DVNVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FNVPROC) (GLuint index, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2FVNVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SNVPROC) (GLuint index, GLshort x, GLshort y);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB2SVNVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3DVNVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3FVNVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB3SVNVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DNVPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4DVNVPROC) (GLuint index, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FNVPROC) (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4FVNVPROC) (GLuint index, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS2DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS2FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS2SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS3DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS3FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS3SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS4DVNVPROC) (GLuint index, GLsizei count, const GLdouble *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS4FVNVPROC) (GLuint index, GLsizei count, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS4SVNVPROC) (GLuint index, GLsizei count, const GLshort *v);\ntypedef void (APIENTRYP PFNGLVERTEXATTRIBS4UBVNVPROC) (GLuint index, GLsizei count, const GLubyte *v);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLboolean APIENTRY glAreProgramsResidentNV (GLsizei n, const GLuint *programs, GLboolean *residences);\nGLAPI void APIENTRY glBindProgramNV (GLenum target, GLuint id);\nGLAPI void APIENTRY glDeleteProgramsNV (GLsizei n, const GLuint *programs);\nGLAPI void APIENTRY glExecuteProgramNV (GLenum target, GLuint id, const GLfloat *params);\nGLAPI void APIENTRY glGenProgramsNV (GLsizei n, GLuint *programs);\nGLAPI void APIENTRY glGetProgramParameterdvNV (GLenum target, GLuint index, GLenum pname, GLdouble *params);\nGLAPI void APIENTRY glGetProgramParameterfvNV (GLenum target, GLuint index, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetProgramivNV (GLuint id, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetProgramStringNV (GLuint id, GLenum pname, GLubyte *program);\nGLAPI void APIENTRY glGetTrackMatrixivNV (GLenum target, GLuint address, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetVertexAttribdvNV (GLuint index, GLenum pname, GLdouble *params);\nGLAPI void APIENTRY glGetVertexAttribfvNV (GLuint index, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetVertexAttribivNV (GLuint index, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetVertexAttribPointervNV (GLuint index, GLenum pname, void **pointer);\nGLAPI GLboolean APIENTRY glIsProgramNV (GLuint id);\nGLAPI void APIENTRY glLoadProgramNV (GLenum target, GLuint id, GLsizei len, const GLubyte *program);\nGLAPI void APIENTRY glProgramParameter4dNV (GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glProgramParameter4dvNV (GLenum target, GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glProgramParameter4fNV (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glProgramParameter4fvNV (GLenum target, GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glProgramParameters4dvNV (GLenum target, GLuint index, GLsizei count, const GLdouble *v);\nGLAPI void APIENTRY glProgramParameters4fvNV (GLenum target, GLuint index, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glRequestResidentProgramsNV (GLsizei n, const GLuint *programs);\nGLAPI void APIENTRY glTrackMatrixNV (GLenum target, GLuint address, GLenum matrix, GLenum transform);\nGLAPI void APIENTRY glVertexAttribPointerNV (GLuint index, GLint fsize, GLenum type, GLsizei stride, const void *pointer);\nGLAPI void APIENTRY glVertexAttrib1dNV (GLuint index, GLdouble x);\nGLAPI void APIENTRY glVertexAttrib1dvNV (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib1fNV (GLuint index, GLfloat x);\nGLAPI void APIENTRY glVertexAttrib1fvNV (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib1sNV (GLuint index, GLshort x);\nGLAPI void APIENTRY glVertexAttrib1svNV (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib2dNV (GLuint index, GLdouble x, GLdouble y);\nGLAPI void APIENTRY glVertexAttrib2dvNV (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib2fNV (GLuint index, GLfloat x, GLfloat y);\nGLAPI void APIENTRY glVertexAttrib2fvNV (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib2sNV (GLuint index, GLshort x, GLshort y);\nGLAPI void APIENTRY glVertexAttrib2svNV (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib3dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z);\nGLAPI void APIENTRY glVertexAttrib3dvNV (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib3fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glVertexAttrib3fvNV (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib3sNV (GLuint index, GLshort x, GLshort y, GLshort z);\nGLAPI void APIENTRY glVertexAttrib3svNV (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib4dNV (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\nGLAPI void APIENTRY glVertexAttrib4dvNV (GLuint index, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttrib4fNV (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glVertexAttrib4fvNV (GLuint index, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttrib4sNV (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\nGLAPI void APIENTRY glVertexAttrib4svNV (GLuint index, const GLshort *v);\nGLAPI void APIENTRY glVertexAttrib4ubNV (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\nGLAPI void APIENTRY glVertexAttrib4ubvNV (GLuint index, const GLubyte *v);\nGLAPI void APIENTRY glVertexAttribs1dvNV (GLuint index, GLsizei count, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribs1fvNV (GLuint index, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttribs1svNV (GLuint index, GLsizei count, const GLshort *v);\nGLAPI void APIENTRY glVertexAttribs2dvNV (GLuint index, GLsizei count, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribs2fvNV (GLuint index, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttribs2svNV (GLuint index, GLsizei count, const GLshort *v);\nGLAPI void APIENTRY glVertexAttribs3dvNV (GLuint index, GLsizei count, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribs3fvNV (GLuint index, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttribs3svNV (GLuint index, GLsizei count, const GLshort *v);\nGLAPI void APIENTRY glVertexAttribs4dvNV (GLuint index, GLsizei count, const GLdouble *v);\nGLAPI void APIENTRY glVertexAttribs4fvNV (GLuint index, GLsizei count, const GLfloat *v);\nGLAPI void APIENTRY glVertexAttribs4svNV (GLuint index, GLsizei count, const GLshort *v);\nGLAPI void APIENTRY glVertexAttribs4ubvNV (GLuint index, GLsizei count, const GLubyte *v);\n#endif\n#endif /* GL_NV_vertex_program */\n\n#ifndef GL_NV_vertex_program1_1\n#define GL_NV_vertex_program1_1 1\n#endif /* GL_NV_vertex_program1_1 */\n\n#ifndef GL_NV_vertex_program2\n#define GL_NV_vertex_program2 1\n#endif /* GL_NV_vertex_program2 */\n\n#ifndef GL_NV_vertex_program2_option\n#define GL_NV_vertex_program2_option 1\n#endif /* GL_NV_vertex_program2_option */\n\n#ifndef GL_NV_vertex_program3\n#define GL_NV_vertex_program3 1\n#endif /* GL_NV_vertex_program3 */\n\n#ifndef GL_NV_vertex_program4\n#define GL_NV_vertex_program4 1\n#define GL_VERTEX_ATTRIB_ARRAY_INTEGER_NV 0x88FD\n#endif /* GL_NV_vertex_program4 */\n\n#ifndef GL_NV_video_capture\n#define GL_NV_video_capture 1\n#define GL_VIDEO_BUFFER_NV                0x9020\n#define GL_VIDEO_BUFFER_BINDING_NV        0x9021\n#define GL_FIELD_UPPER_NV                 0x9022\n#define GL_FIELD_LOWER_NV                 0x9023\n#define GL_NUM_VIDEO_CAPTURE_STREAMS_NV   0x9024\n#define GL_NEXT_VIDEO_CAPTURE_BUFFER_STATUS_NV 0x9025\n#define GL_VIDEO_CAPTURE_TO_422_SUPPORTED_NV 0x9026\n#define GL_LAST_VIDEO_CAPTURE_STATUS_NV   0x9027\n#define GL_VIDEO_BUFFER_PITCH_NV          0x9028\n#define GL_VIDEO_COLOR_CONVERSION_MATRIX_NV 0x9029\n#define GL_VIDEO_COLOR_CONVERSION_MAX_NV  0x902A\n#define GL_VIDEO_COLOR_CONVERSION_MIN_NV  0x902B\n#define GL_VIDEO_COLOR_CONVERSION_OFFSET_NV 0x902C\n#define GL_VIDEO_BUFFER_INTERNAL_FORMAT_NV 0x902D\n#define GL_PARTIAL_SUCCESS_NV             0x902E\n#define GL_SUCCESS_NV                     0x902F\n#define GL_FAILURE_NV                     0x9030\n#define GL_YCBYCR8_422_NV                 0x9031\n#define GL_YCBAYCR8A_4224_NV              0x9032\n#define GL_Z6Y10Z6CB10Z6Y10Z6CR10_422_NV  0x9033\n#define GL_Z6Y10Z6CB10Z6A10Z6Y10Z6CR10Z6A10_4224_NV 0x9034\n#define GL_Z4Y12Z4CB12Z4Y12Z4CR12_422_NV  0x9035\n#define GL_Z4Y12Z4CB12Z4A12Z4Y12Z4CR12Z4A12_4224_NV 0x9036\n#define GL_Z4Y12Z4CB12Z4CR12_444_NV       0x9037\n#define GL_VIDEO_CAPTURE_FRAME_WIDTH_NV   0x9038\n#define GL_VIDEO_CAPTURE_FRAME_HEIGHT_NV  0x9039\n#define GL_VIDEO_CAPTURE_FIELD_UPPER_HEIGHT_NV 0x903A\n#define GL_VIDEO_CAPTURE_FIELD_LOWER_HEIGHT_NV 0x903B\n#define GL_VIDEO_CAPTURE_SURFACE_ORIGIN_NV 0x903C\ntypedef void (APIENTRYP PFNGLBEGINVIDEOCAPTURENVPROC) (GLuint video_capture_slot);\ntypedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMBUFFERNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset);\ntypedef void (APIENTRYP PFNGLBINDVIDEOCAPTURESTREAMTEXTURENVPROC) (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture);\ntypedef void (APIENTRYP PFNGLENDVIDEOCAPTURENVPROC) (GLuint video_capture_slot);\ntypedef void (APIENTRYP PFNGLGETVIDEOCAPTUREIVNVPROC) (GLuint video_capture_slot, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETVIDEOCAPTURESTREAMDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params);\ntypedef GLenum (APIENTRYP PFNGLVIDEOCAPTURENVPROC) (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time);\ntypedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERFVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLVIDEOCAPTURESTREAMPARAMETERDVNVPROC) (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glBeginVideoCaptureNV (GLuint video_capture_slot);\nGLAPI void APIENTRY glBindVideoCaptureStreamBufferNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLintptrARB offset);\nGLAPI void APIENTRY glBindVideoCaptureStreamTextureNV (GLuint video_capture_slot, GLuint stream, GLenum frame_region, GLenum target, GLuint texture);\nGLAPI void APIENTRY glEndVideoCaptureNV (GLuint video_capture_slot);\nGLAPI void APIENTRY glGetVideoCaptureivNV (GLuint video_capture_slot, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetVideoCaptureStreamivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetVideoCaptureStreamfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetVideoCaptureStreamdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, GLdouble *params);\nGLAPI GLenum APIENTRY glVideoCaptureNV (GLuint video_capture_slot, GLuint *sequence_num, GLuint64EXT *capture_time);\nGLAPI void APIENTRY glVideoCaptureStreamParameterivNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glVideoCaptureStreamParameterfvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot, GLuint stream, GLenum pname, const GLdouble *params);\n#endif\n#endif /* GL_NV_video_capture */\n\n#ifndef GL_NV_viewport_array2\n#define GL_NV_viewport_array2 1\n#endif /* GL_NV_viewport_array2 */\n\n#ifndef GL_NV_viewport_swizzle\n#define GL_NV_viewport_swizzle 1\n#define GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV 0x9350\n#define GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV 0x9351\n#define GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV 0x9352\n#define GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV 0x9353\n#define GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV 0x9354\n#define GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV 0x9355\n#define GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV 0x9356\n#define GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV 0x9357\n#define GL_VIEWPORT_SWIZZLE_X_NV          0x9358\n#define GL_VIEWPORT_SWIZZLE_Y_NV          0x9359\n#define GL_VIEWPORT_SWIZZLE_Z_NV          0x935A\n#define GL_VIEWPORT_SWIZZLE_W_NV          0x935B\ntypedef void (APIENTRYP PFNGLVIEWPORTSWIZZLENVPROC) (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glViewportSwizzleNV (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew);\n#endif\n#endif /* GL_NV_viewport_swizzle */\n\n#ifndef GL_OML_interlace\n#define GL_OML_interlace 1\n#define GL_INTERLACE_OML                  0x8980\n#define GL_INTERLACE_READ_OML             0x8981\n#endif /* GL_OML_interlace */\n\n#ifndef GL_OML_resample\n#define GL_OML_resample 1\n#define GL_PACK_RESAMPLE_OML              0x8984\n#define GL_UNPACK_RESAMPLE_OML            0x8985\n#define GL_RESAMPLE_REPLICATE_OML         0x8986\n#define GL_RESAMPLE_ZERO_FILL_OML         0x8987\n#define GL_RESAMPLE_AVERAGE_OML           0x8988\n#define GL_RESAMPLE_DECIMATE_OML          0x8989\n#endif /* GL_OML_resample */\n\n#ifndef GL_OML_subsample\n#define GL_OML_subsample 1\n#define GL_FORMAT_SUBSAMPLE_24_24_OML     0x8982\n#define GL_FORMAT_SUBSAMPLE_244_244_OML   0x8983\n#endif /* GL_OML_subsample */\n\n#ifndef GL_OVR_multiview\n#define GL_OVR_multiview 1\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632\n#define GL_MAX_VIEWS_OVR                  0x9631\n#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633\ntypedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);\n#endif\n#endif /* GL_OVR_multiview */\n\n#ifndef GL_OVR_multiview2\n#define GL_OVR_multiview2 1\n#endif /* GL_OVR_multiview2 */\n\n#ifndef GL_PGI_misc_hints\n#define GL_PGI_misc_hints 1\n#define GL_PREFER_DOUBLEBUFFER_HINT_PGI   0x1A1F8\n#define GL_CONSERVE_MEMORY_HINT_PGI       0x1A1FD\n#define GL_RECLAIM_MEMORY_HINT_PGI        0x1A1FE\n#define GL_NATIVE_GRAPHICS_HANDLE_PGI     0x1A202\n#define GL_NATIVE_GRAPHICS_BEGIN_HINT_PGI 0x1A203\n#define GL_NATIVE_GRAPHICS_END_HINT_PGI   0x1A204\n#define GL_ALWAYS_FAST_HINT_PGI           0x1A20C\n#define GL_ALWAYS_SOFT_HINT_PGI           0x1A20D\n#define GL_ALLOW_DRAW_OBJ_HINT_PGI        0x1A20E\n#define GL_ALLOW_DRAW_WIN_HINT_PGI        0x1A20F\n#define GL_ALLOW_DRAW_FRG_HINT_PGI        0x1A210\n#define GL_ALLOW_DRAW_MEM_HINT_PGI        0x1A211\n#define GL_STRICT_DEPTHFUNC_HINT_PGI      0x1A216\n#define GL_STRICT_LIGHTING_HINT_PGI       0x1A217\n#define GL_STRICT_SCISSOR_HINT_PGI        0x1A218\n#define GL_FULL_STIPPLE_HINT_PGI          0x1A219\n#define GL_CLIP_NEAR_HINT_PGI             0x1A220\n#define GL_CLIP_FAR_HINT_PGI              0x1A221\n#define GL_WIDE_LINE_HINT_PGI             0x1A222\n#define GL_BACK_NORMALS_HINT_PGI          0x1A223\ntypedef void (APIENTRYP PFNGLHINTPGIPROC) (GLenum target, GLint mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glHintPGI (GLenum target, GLint mode);\n#endif\n#endif /* GL_PGI_misc_hints */\n\n#ifndef GL_PGI_vertex_hints\n#define GL_PGI_vertex_hints 1\n#define GL_VERTEX_DATA_HINT_PGI           0x1A22A\n#define GL_VERTEX_CONSISTENT_HINT_PGI     0x1A22B\n#define GL_MATERIAL_SIDE_HINT_PGI         0x1A22C\n#define GL_MAX_VERTEX_HINT_PGI            0x1A22D\n#define GL_COLOR3_BIT_PGI                 0x00010000\n#define GL_COLOR4_BIT_PGI                 0x00020000\n#define GL_EDGEFLAG_BIT_PGI               0x00040000\n#define GL_INDEX_BIT_PGI                  0x00080000\n#define GL_MAT_AMBIENT_BIT_PGI            0x00100000\n#define GL_MAT_AMBIENT_AND_DIFFUSE_BIT_PGI 0x00200000\n#define GL_MAT_DIFFUSE_BIT_PGI            0x00400000\n#define GL_MAT_EMISSION_BIT_PGI           0x00800000\n#define GL_MAT_COLOR_INDEXES_BIT_PGI      0x01000000\n#define GL_MAT_SHININESS_BIT_PGI          0x02000000\n#define GL_MAT_SPECULAR_BIT_PGI           0x04000000\n#define GL_NORMAL_BIT_PGI                 0x08000000\n#define GL_TEXCOORD1_BIT_PGI              0x10000000\n#define GL_TEXCOORD2_BIT_PGI              0x20000000\n#define GL_TEXCOORD3_BIT_PGI              0x40000000\n#define GL_TEXCOORD4_BIT_PGI              0x80000000\n#define GL_VERTEX23_BIT_PGI               0x00000004\n#define GL_VERTEX4_BIT_PGI                0x00000008\n#endif /* GL_PGI_vertex_hints */\n\n#ifndef GL_REND_screen_coordinates\n#define GL_REND_screen_coordinates 1\n#define GL_SCREEN_COORDINATES_REND        0x8490\n#define GL_INVERTED_SCREEN_W_REND         0x8491\n#endif /* GL_REND_screen_coordinates */\n\n#ifndef GL_S3_s3tc\n#define GL_S3_s3tc 1\n#define GL_RGB_S3TC                       0x83A0\n#define GL_RGB4_S3TC                      0x83A1\n#define GL_RGBA_S3TC                      0x83A2\n#define GL_RGBA4_S3TC                     0x83A3\n#define GL_RGBA_DXT5_S3TC                 0x83A4\n#define GL_RGBA4_DXT5_S3TC                0x83A5\n#endif /* GL_S3_s3tc */\n\n#ifndef GL_SGIS_detail_texture\n#define GL_SGIS_detail_texture 1\n#define GL_DETAIL_TEXTURE_2D_SGIS         0x8095\n#define GL_DETAIL_TEXTURE_2D_BINDING_SGIS 0x8096\n#define GL_LINEAR_DETAIL_SGIS             0x8097\n#define GL_LINEAR_DETAIL_ALPHA_SGIS       0x8098\n#define GL_LINEAR_DETAIL_COLOR_SGIS       0x8099\n#define GL_DETAIL_TEXTURE_LEVEL_SGIS      0x809A\n#define GL_DETAIL_TEXTURE_MODE_SGIS       0x809B\n#define GL_DETAIL_TEXTURE_FUNC_POINTS_SGIS 0x809C\ntypedef void (APIENTRYP PFNGLDETAILTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);\ntypedef void (APIENTRYP PFNGLGETDETAILTEXFUNCSGISPROC) (GLenum target, GLfloat *points);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDetailTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points);\nGLAPI void APIENTRY glGetDetailTexFuncSGIS (GLenum target, GLfloat *points);\n#endif\n#endif /* GL_SGIS_detail_texture */\n\n#ifndef GL_SGIS_fog_function\n#define GL_SGIS_fog_function 1\n#define GL_FOG_FUNC_SGIS                  0x812A\n#define GL_FOG_FUNC_POINTS_SGIS           0x812B\n#define GL_MAX_FOG_FUNC_POINTS_SGIS       0x812C\ntypedef void (APIENTRYP PFNGLFOGFUNCSGISPROC) (GLsizei n, const GLfloat *points);\ntypedef void (APIENTRYP PFNGLGETFOGFUNCSGISPROC) (GLfloat *points);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFogFuncSGIS (GLsizei n, const GLfloat *points);\nGLAPI void APIENTRY glGetFogFuncSGIS (GLfloat *points);\n#endif\n#endif /* GL_SGIS_fog_function */\n\n#ifndef GL_SGIS_generate_mipmap\n#define GL_SGIS_generate_mipmap 1\n#define GL_GENERATE_MIPMAP_SGIS           0x8191\n#define GL_GENERATE_MIPMAP_HINT_SGIS      0x8192\n#endif /* GL_SGIS_generate_mipmap */\n\n#ifndef GL_SGIS_multisample\n#define GL_SGIS_multisample 1\n#define GL_MULTISAMPLE_SGIS               0x809D\n#define GL_SAMPLE_ALPHA_TO_MASK_SGIS      0x809E\n#define GL_SAMPLE_ALPHA_TO_ONE_SGIS       0x809F\n#define GL_SAMPLE_MASK_SGIS               0x80A0\n#define GL_1PASS_SGIS                     0x80A1\n#define GL_2PASS_0_SGIS                   0x80A2\n#define GL_2PASS_1_SGIS                   0x80A3\n#define GL_4PASS_0_SGIS                   0x80A4\n#define GL_4PASS_1_SGIS                   0x80A5\n#define GL_4PASS_2_SGIS                   0x80A6\n#define GL_4PASS_3_SGIS                   0x80A7\n#define GL_SAMPLE_BUFFERS_SGIS            0x80A8\n#define GL_SAMPLES_SGIS                   0x80A9\n#define GL_SAMPLE_MASK_VALUE_SGIS         0x80AA\n#define GL_SAMPLE_MASK_INVERT_SGIS        0x80AB\n#define GL_SAMPLE_PATTERN_SGIS            0x80AC\ntypedef void (APIENTRYP PFNGLSAMPLEMASKSGISPROC) (GLclampf value, GLboolean invert);\ntypedef void (APIENTRYP PFNGLSAMPLEPATTERNSGISPROC) (GLenum pattern);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSampleMaskSGIS (GLclampf value, GLboolean invert);\nGLAPI void APIENTRY glSamplePatternSGIS (GLenum pattern);\n#endif\n#endif /* GL_SGIS_multisample */\n\n#ifndef GL_SGIS_pixel_texture\n#define GL_SGIS_pixel_texture 1\n#define GL_PIXEL_TEXTURE_SGIS             0x8353\n#define GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS 0x8354\n#define GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS 0x8355\n#define GL_PIXEL_GROUP_COLOR_SGIS         0x8356\ntypedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERISGISPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFSGISPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERIVSGISPROC) (GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETPIXELTEXGENPARAMETERFVSGISPROC) (GLenum pname, GLfloat *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPixelTexGenParameteriSGIS (GLenum pname, GLint param);\nGLAPI void APIENTRY glPixelTexGenParameterivSGIS (GLenum pname, const GLint *params);\nGLAPI void APIENTRY glPixelTexGenParameterfSGIS (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glPixelTexGenParameterfvSGIS (GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glGetPixelTexGenParameterivSGIS (GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetPixelTexGenParameterfvSGIS (GLenum pname, GLfloat *params);\n#endif\n#endif /* GL_SGIS_pixel_texture */\n\n#ifndef GL_SGIS_point_line_texgen\n#define GL_SGIS_point_line_texgen 1\n#define GL_EYE_DISTANCE_TO_POINT_SGIS     0x81F0\n#define GL_OBJECT_DISTANCE_TO_POINT_SGIS  0x81F1\n#define GL_EYE_DISTANCE_TO_LINE_SGIS      0x81F2\n#define GL_OBJECT_DISTANCE_TO_LINE_SGIS   0x81F3\n#define GL_EYE_POINT_SGIS                 0x81F4\n#define GL_OBJECT_POINT_SGIS              0x81F5\n#define GL_EYE_LINE_SGIS                  0x81F6\n#define GL_OBJECT_LINE_SGIS               0x81F7\n#endif /* GL_SGIS_point_line_texgen */\n\n#ifndef GL_SGIS_point_parameters\n#define GL_SGIS_point_parameters 1\n#define GL_POINT_SIZE_MIN_SGIS            0x8126\n#define GL_POINT_SIZE_MAX_SGIS            0x8127\n#define GL_POINT_FADE_THRESHOLD_SIZE_SGIS 0x8128\n#define GL_DISTANCE_ATTENUATION_SGIS      0x8129\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFSGISPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLPOINTPARAMETERFVSGISPROC) (GLenum pname, const GLfloat *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPointParameterfSGIS (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glPointParameterfvSGIS (GLenum pname, const GLfloat *params);\n#endif\n#endif /* GL_SGIS_point_parameters */\n\n#ifndef GL_SGIS_sharpen_texture\n#define GL_SGIS_sharpen_texture 1\n#define GL_LINEAR_SHARPEN_SGIS            0x80AD\n#define GL_LINEAR_SHARPEN_ALPHA_SGIS      0x80AE\n#define GL_LINEAR_SHARPEN_COLOR_SGIS      0x80AF\n#define GL_SHARPEN_TEXTURE_FUNC_POINTS_SGIS 0x80B0\ntypedef void (APIENTRYP PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei n, const GLfloat *points);\ntypedef void (APIENTRYP PFNGLGETSHARPENTEXFUNCSGISPROC) (GLenum target, GLfloat *points);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSharpenTexFuncSGIS (GLenum target, GLsizei n, const GLfloat *points);\nGLAPI void APIENTRY glGetSharpenTexFuncSGIS (GLenum target, GLfloat *points);\n#endif\n#endif /* GL_SGIS_sharpen_texture */\n\n#ifndef GL_SGIS_texture4D\n#define GL_SGIS_texture4D 1\n#define GL_PACK_SKIP_VOLUMES_SGIS         0x8130\n#define GL_PACK_IMAGE_DEPTH_SGIS          0x8131\n#define GL_UNPACK_SKIP_VOLUMES_SGIS       0x8132\n#define GL_UNPACK_IMAGE_DEPTH_SGIS        0x8133\n#define GL_TEXTURE_4D_SGIS                0x8134\n#define GL_PROXY_TEXTURE_4D_SGIS          0x8135\n#define GL_TEXTURE_4DSIZE_SGIS            0x8136\n#define GL_TEXTURE_WRAP_Q_SGIS            0x8137\n#define GL_MAX_4D_TEXTURE_SIZE_SGIS       0x8138\n#define GL_TEXTURE_4D_BINDING_SGIS        0x814F\ntypedef void (APIENTRYP PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels);\ntypedef void (APIENTRYP PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTexImage4DSGIS (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLint border, GLenum format, GLenum type, const void *pixels);\nGLAPI void APIENTRY glTexSubImage4DSGIS (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei size4d, GLenum format, GLenum type, const void *pixels);\n#endif\n#endif /* GL_SGIS_texture4D */\n\n#ifndef GL_SGIS_texture_border_clamp\n#define GL_SGIS_texture_border_clamp 1\n#define GL_CLAMP_TO_BORDER_SGIS           0x812D\n#endif /* GL_SGIS_texture_border_clamp */\n\n#ifndef GL_SGIS_texture_color_mask\n#define GL_SGIS_texture_color_mask 1\n#define GL_TEXTURE_COLOR_WRITEMASK_SGIS   0x81EF\ntypedef void (APIENTRYP PFNGLTEXTURECOLORMASKSGISPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTextureColorMaskSGIS (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);\n#endif\n#endif /* GL_SGIS_texture_color_mask */\n\n#ifndef GL_SGIS_texture_edge_clamp\n#define GL_SGIS_texture_edge_clamp 1\n#define GL_CLAMP_TO_EDGE_SGIS             0x812F\n#endif /* GL_SGIS_texture_edge_clamp */\n\n#ifndef GL_SGIS_texture_filter4\n#define GL_SGIS_texture_filter4 1\n#define GL_FILTER4_SGIS                   0x8146\n#define GL_TEXTURE_FILTER4_SIZE_SGIS      0x8147\ntypedef void (APIENTRYP PFNGLGETTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLfloat *weights);\ntypedef void (APIENTRYP PFNGLTEXFILTERFUNCSGISPROC) (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetTexFilterFuncSGIS (GLenum target, GLenum filter, GLfloat *weights);\nGLAPI void APIENTRY glTexFilterFuncSGIS (GLenum target, GLenum filter, GLsizei n, const GLfloat *weights);\n#endif\n#endif /* GL_SGIS_texture_filter4 */\n\n#ifndef GL_SGIS_texture_lod\n#define GL_SGIS_texture_lod 1\n#define GL_TEXTURE_MIN_LOD_SGIS           0x813A\n#define GL_TEXTURE_MAX_LOD_SGIS           0x813B\n#define GL_TEXTURE_BASE_LEVEL_SGIS        0x813C\n#define GL_TEXTURE_MAX_LEVEL_SGIS         0x813D\n#endif /* GL_SGIS_texture_lod */\n\n#ifndef GL_SGIS_texture_select\n#define GL_SGIS_texture_select 1\n#define GL_DUAL_ALPHA4_SGIS               0x8110\n#define GL_DUAL_ALPHA8_SGIS               0x8111\n#define GL_DUAL_ALPHA12_SGIS              0x8112\n#define GL_DUAL_ALPHA16_SGIS              0x8113\n#define GL_DUAL_LUMINANCE4_SGIS           0x8114\n#define GL_DUAL_LUMINANCE8_SGIS           0x8115\n#define GL_DUAL_LUMINANCE12_SGIS          0x8116\n#define GL_DUAL_LUMINANCE16_SGIS          0x8117\n#define GL_DUAL_INTENSITY4_SGIS           0x8118\n#define GL_DUAL_INTENSITY8_SGIS           0x8119\n#define GL_DUAL_INTENSITY12_SGIS          0x811A\n#define GL_DUAL_INTENSITY16_SGIS          0x811B\n#define GL_DUAL_LUMINANCE_ALPHA4_SGIS     0x811C\n#define GL_DUAL_LUMINANCE_ALPHA8_SGIS     0x811D\n#define GL_QUAD_ALPHA4_SGIS               0x811E\n#define GL_QUAD_ALPHA8_SGIS               0x811F\n#define GL_QUAD_LUMINANCE4_SGIS           0x8120\n#define GL_QUAD_LUMINANCE8_SGIS           0x8121\n#define GL_QUAD_INTENSITY4_SGIS           0x8122\n#define GL_QUAD_INTENSITY8_SGIS           0x8123\n#define GL_DUAL_TEXTURE_SELECT_SGIS       0x8124\n#define GL_QUAD_TEXTURE_SELECT_SGIS       0x8125\n#endif /* GL_SGIS_texture_select */\n\n#ifndef GL_SGIX_async\n#define GL_SGIX_async 1\n#define GL_ASYNC_MARKER_SGIX              0x8329\ntypedef void (APIENTRYP PFNGLASYNCMARKERSGIXPROC) (GLuint marker);\ntypedef GLint (APIENTRYP PFNGLFINISHASYNCSGIXPROC) (GLuint *markerp);\ntypedef GLint (APIENTRYP PFNGLPOLLASYNCSGIXPROC) (GLuint *markerp);\ntypedef GLuint (APIENTRYP PFNGLGENASYNCMARKERSSGIXPROC) (GLsizei range);\ntypedef void (APIENTRYP PFNGLDELETEASYNCMARKERSSGIXPROC) (GLuint marker, GLsizei range);\ntypedef GLboolean (APIENTRYP PFNGLISASYNCMARKERSGIXPROC) (GLuint marker);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glAsyncMarkerSGIX (GLuint marker);\nGLAPI GLint APIENTRY glFinishAsyncSGIX (GLuint *markerp);\nGLAPI GLint APIENTRY glPollAsyncSGIX (GLuint *markerp);\nGLAPI GLuint APIENTRY glGenAsyncMarkersSGIX (GLsizei range);\nGLAPI void APIENTRY glDeleteAsyncMarkersSGIX (GLuint marker, GLsizei range);\nGLAPI GLboolean APIENTRY glIsAsyncMarkerSGIX (GLuint marker);\n#endif\n#endif /* GL_SGIX_async */\n\n#ifndef GL_SGIX_async_histogram\n#define GL_SGIX_async_histogram 1\n#define GL_ASYNC_HISTOGRAM_SGIX           0x832C\n#define GL_MAX_ASYNC_HISTOGRAM_SGIX       0x832D\n#endif /* GL_SGIX_async_histogram */\n\n#ifndef GL_SGIX_async_pixel\n#define GL_SGIX_async_pixel 1\n#define GL_ASYNC_TEX_IMAGE_SGIX           0x835C\n#define GL_ASYNC_DRAW_PIXELS_SGIX         0x835D\n#define GL_ASYNC_READ_PIXELS_SGIX         0x835E\n#define GL_MAX_ASYNC_TEX_IMAGE_SGIX       0x835F\n#define GL_MAX_ASYNC_DRAW_PIXELS_SGIX     0x8360\n#define GL_MAX_ASYNC_READ_PIXELS_SGIX     0x8361\n#endif /* GL_SGIX_async_pixel */\n\n#ifndef GL_SGIX_blend_alpha_minmax\n#define GL_SGIX_blend_alpha_minmax 1\n#define GL_ALPHA_MIN_SGIX                 0x8320\n#define GL_ALPHA_MAX_SGIX                 0x8321\n#endif /* GL_SGIX_blend_alpha_minmax */\n\n#ifndef GL_SGIX_calligraphic_fragment\n#define GL_SGIX_calligraphic_fragment 1\n#define GL_CALLIGRAPHIC_FRAGMENT_SGIX     0x8183\n#endif /* GL_SGIX_calligraphic_fragment */\n\n#ifndef GL_SGIX_clipmap\n#define GL_SGIX_clipmap 1\n#define GL_LINEAR_CLIPMAP_LINEAR_SGIX     0x8170\n#define GL_TEXTURE_CLIPMAP_CENTER_SGIX    0x8171\n#define GL_TEXTURE_CLIPMAP_FRAME_SGIX     0x8172\n#define GL_TEXTURE_CLIPMAP_OFFSET_SGIX    0x8173\n#define GL_TEXTURE_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8174\n#define GL_TEXTURE_CLIPMAP_LOD_OFFSET_SGIX 0x8175\n#define GL_TEXTURE_CLIPMAP_DEPTH_SGIX     0x8176\n#define GL_MAX_CLIPMAP_DEPTH_SGIX         0x8177\n#define GL_MAX_CLIPMAP_VIRTUAL_DEPTH_SGIX 0x8178\n#define GL_NEAREST_CLIPMAP_NEAREST_SGIX   0x844D\n#define GL_NEAREST_CLIPMAP_LINEAR_SGIX    0x844E\n#define GL_LINEAR_CLIPMAP_NEAREST_SGIX    0x844F\n#endif /* GL_SGIX_clipmap */\n\n#ifndef GL_SGIX_convolution_accuracy\n#define GL_SGIX_convolution_accuracy 1\n#define GL_CONVOLUTION_HINT_SGIX          0x8316\n#endif /* GL_SGIX_convolution_accuracy */\n\n#ifndef GL_SGIX_depth_pass_instrument\n#define GL_SGIX_depth_pass_instrument 1\n#endif /* GL_SGIX_depth_pass_instrument */\n\n#ifndef GL_SGIX_depth_texture\n#define GL_SGIX_depth_texture 1\n#define GL_DEPTH_COMPONENT16_SGIX         0x81A5\n#define GL_DEPTH_COMPONENT24_SGIX         0x81A6\n#define GL_DEPTH_COMPONENT32_SGIX         0x81A7\n#endif /* GL_SGIX_depth_texture */\n\n#ifndef GL_SGIX_flush_raster\n#define GL_SGIX_flush_raster 1\ntypedef void (APIENTRYP PFNGLFLUSHRASTERSGIXPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFlushRasterSGIX (void);\n#endif\n#endif /* GL_SGIX_flush_raster */\n\n#ifndef GL_SGIX_fog_offset\n#define GL_SGIX_fog_offset 1\n#define GL_FOG_OFFSET_SGIX                0x8198\n#define GL_FOG_OFFSET_VALUE_SGIX          0x8199\n#endif /* GL_SGIX_fog_offset */\n\n#ifndef GL_SGIX_fragment_lighting\n#define GL_SGIX_fragment_lighting 1\n#define GL_FRAGMENT_LIGHTING_SGIX         0x8400\n#define GL_FRAGMENT_COLOR_MATERIAL_SGIX   0x8401\n#define GL_FRAGMENT_COLOR_MATERIAL_FACE_SGIX 0x8402\n#define GL_FRAGMENT_COLOR_MATERIAL_PARAMETER_SGIX 0x8403\n#define GL_MAX_FRAGMENT_LIGHTS_SGIX       0x8404\n#define GL_MAX_ACTIVE_LIGHTS_SGIX         0x8405\n#define GL_CURRENT_RASTER_NORMAL_SGIX     0x8406\n#define GL_LIGHT_ENV_MODE_SGIX            0x8407\n#define GL_FRAGMENT_LIGHT_MODEL_LOCAL_VIEWER_SGIX 0x8408\n#define GL_FRAGMENT_LIGHT_MODEL_TWO_SIDE_SGIX 0x8409\n#define GL_FRAGMENT_LIGHT_MODEL_AMBIENT_SGIX 0x840A\n#define GL_FRAGMENT_LIGHT_MODEL_NORMAL_INTERPOLATION_SGIX 0x840B\n#define GL_FRAGMENT_LIGHT0_SGIX           0x840C\n#define GL_FRAGMENT_LIGHT1_SGIX           0x840D\n#define GL_FRAGMENT_LIGHT2_SGIX           0x840E\n#define GL_FRAGMENT_LIGHT3_SGIX           0x840F\n#define GL_FRAGMENT_LIGHT4_SGIX           0x8410\n#define GL_FRAGMENT_LIGHT5_SGIX           0x8411\n#define GL_FRAGMENT_LIGHT6_SGIX           0x8412\n#define GL_FRAGMENT_LIGHT7_SGIX           0x8413\ntypedef void (APIENTRYP PFNGLFRAGMENTCOLORMATERIALSGIXPROC) (GLenum face, GLenum mode);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTFSGIXPROC) (GLenum light, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTISGIXPROC) (GLenum light, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFSGIXPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELFVSGIXPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELISGIXPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLFRAGMENTLIGHTMODELIVSGIXPROC) (GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLFRAGMENTMATERIALFSGIXPROC) (GLenum face, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLFRAGMENTMATERIALISGIXPROC) (GLenum face, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTFVSGIXPROC) (GLenum light, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETFRAGMENTLIGHTIVSGIXPROC) (GLenum light, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALFVSGIXPROC) (GLenum face, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETFRAGMENTMATERIALIVSGIXPROC) (GLenum face, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLLIGHTENVISGIXPROC) (GLenum pname, GLint param);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFragmentColorMaterialSGIX (GLenum face, GLenum mode);\nGLAPI void APIENTRY glFragmentLightfSGIX (GLenum light, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glFragmentLightfvSGIX (GLenum light, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glFragmentLightiSGIX (GLenum light, GLenum pname, GLint param);\nGLAPI void APIENTRY glFragmentLightivSGIX (GLenum light, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glFragmentLightModelfSGIX (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glFragmentLightModelfvSGIX (GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glFragmentLightModeliSGIX (GLenum pname, GLint param);\nGLAPI void APIENTRY glFragmentLightModelivSGIX (GLenum pname, const GLint *params);\nGLAPI void APIENTRY glFragmentMaterialfSGIX (GLenum face, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glFragmentMaterialfvSGIX (GLenum face, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glFragmentMaterialiSGIX (GLenum face, GLenum pname, GLint param);\nGLAPI void APIENTRY glFragmentMaterialivSGIX (GLenum face, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glGetFragmentLightfvSGIX (GLenum light, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetFragmentLightivSGIX (GLenum light, GLenum pname, GLint *params);\nGLAPI void APIENTRY glGetFragmentMaterialfvSGIX (GLenum face, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetFragmentMaterialivSGIX (GLenum face, GLenum pname, GLint *params);\nGLAPI void APIENTRY glLightEnviSGIX (GLenum pname, GLint param);\n#endif\n#endif /* GL_SGIX_fragment_lighting */\n\n#ifndef GL_SGIX_framezoom\n#define GL_SGIX_framezoom 1\n#define GL_FRAMEZOOM_SGIX                 0x818B\n#define GL_FRAMEZOOM_FACTOR_SGIX          0x818C\n#define GL_MAX_FRAMEZOOM_FACTOR_SGIX      0x818D\ntypedef void (APIENTRYP PFNGLFRAMEZOOMSGIXPROC) (GLint factor);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFrameZoomSGIX (GLint factor);\n#endif\n#endif /* GL_SGIX_framezoom */\n\n#ifndef GL_SGIX_igloo_interface\n#define GL_SGIX_igloo_interface 1\ntypedef void (APIENTRYP PFNGLIGLOOINTERFACESGIXPROC) (GLenum pname, const void *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glIglooInterfaceSGIX (GLenum pname, const void *params);\n#endif\n#endif /* GL_SGIX_igloo_interface */\n\n#ifndef GL_SGIX_instruments\n#define GL_SGIX_instruments 1\n#define GL_INSTRUMENT_BUFFER_POINTER_SGIX 0x8180\n#define GL_INSTRUMENT_MEASUREMENTS_SGIX   0x8181\ntypedef GLint (APIENTRYP PFNGLGETINSTRUMENTSSGIXPROC) (void);\ntypedef void (APIENTRYP PFNGLINSTRUMENTSBUFFERSGIXPROC) (GLsizei size, GLint *buffer);\ntypedef GLint (APIENTRYP PFNGLPOLLINSTRUMENTSSGIXPROC) (GLint *marker_p);\ntypedef void (APIENTRYP PFNGLREADINSTRUMENTSSGIXPROC) (GLint marker);\ntypedef void (APIENTRYP PFNGLSTARTINSTRUMENTSSGIXPROC) (void);\ntypedef void (APIENTRYP PFNGLSTOPINSTRUMENTSSGIXPROC) (GLint marker);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI GLint APIENTRY glGetInstrumentsSGIX (void);\nGLAPI void APIENTRY glInstrumentsBufferSGIX (GLsizei size, GLint *buffer);\nGLAPI GLint APIENTRY glPollInstrumentsSGIX (GLint *marker_p);\nGLAPI void APIENTRY glReadInstrumentsSGIX (GLint marker);\nGLAPI void APIENTRY glStartInstrumentsSGIX (void);\nGLAPI void APIENTRY glStopInstrumentsSGIX (GLint marker);\n#endif\n#endif /* GL_SGIX_instruments */\n\n#ifndef GL_SGIX_interlace\n#define GL_SGIX_interlace 1\n#define GL_INTERLACE_SGIX                 0x8094\n#endif /* GL_SGIX_interlace */\n\n#ifndef GL_SGIX_ir_instrument1\n#define GL_SGIX_ir_instrument1 1\n#define GL_IR_INSTRUMENT1_SGIX            0x817F\n#endif /* GL_SGIX_ir_instrument1 */\n\n#ifndef GL_SGIX_list_priority\n#define GL_SGIX_list_priority 1\n#define GL_LIST_PRIORITY_SGIX             0x8182\ntypedef void (APIENTRYP PFNGLGETLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, GLint *params);\ntypedef void (APIENTRYP PFNGLLISTPARAMETERFSGIXPROC) (GLuint list, GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLLISTPARAMETERFVSGIXPROC) (GLuint list, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLLISTPARAMETERISGIXPROC) (GLuint list, GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLLISTPARAMETERIVSGIXPROC) (GLuint list, GLenum pname, const GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGetListParameterfvSGIX (GLuint list, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetListParameterivSGIX (GLuint list, GLenum pname, GLint *params);\nGLAPI void APIENTRY glListParameterfSGIX (GLuint list, GLenum pname, GLfloat param);\nGLAPI void APIENTRY glListParameterfvSGIX (GLuint list, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glListParameteriSGIX (GLuint list, GLenum pname, GLint param);\nGLAPI void APIENTRY glListParameterivSGIX (GLuint list, GLenum pname, const GLint *params);\n#endif\n#endif /* GL_SGIX_list_priority */\n\n#ifndef GL_SGIX_pixel_texture\n#define GL_SGIX_pixel_texture 1\n#define GL_PIXEL_TEX_GEN_SGIX             0x8139\n#define GL_PIXEL_TEX_GEN_MODE_SGIX        0x832B\ntypedef void (APIENTRYP PFNGLPIXELTEXGENSGIXPROC) (GLenum mode);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glPixelTexGenSGIX (GLenum mode);\n#endif\n#endif /* GL_SGIX_pixel_texture */\n\n#ifndef GL_SGIX_pixel_tiles\n#define GL_SGIX_pixel_tiles 1\n#define GL_PIXEL_TILE_BEST_ALIGNMENT_SGIX 0x813E\n#define GL_PIXEL_TILE_CACHE_INCREMENT_SGIX 0x813F\n#define GL_PIXEL_TILE_WIDTH_SGIX          0x8140\n#define GL_PIXEL_TILE_HEIGHT_SGIX         0x8141\n#define GL_PIXEL_TILE_GRID_WIDTH_SGIX     0x8142\n#define GL_PIXEL_TILE_GRID_HEIGHT_SGIX    0x8143\n#define GL_PIXEL_TILE_GRID_DEPTH_SGIX     0x8144\n#define GL_PIXEL_TILE_CACHE_SIZE_SGIX     0x8145\n#endif /* GL_SGIX_pixel_tiles */\n\n#ifndef GL_SGIX_polynomial_ffd\n#define GL_SGIX_polynomial_ffd 1\n#define GL_TEXTURE_DEFORMATION_BIT_SGIX   0x00000001\n#define GL_GEOMETRY_DEFORMATION_BIT_SGIX  0x00000002\n#define GL_GEOMETRY_DEFORMATION_SGIX      0x8194\n#define GL_TEXTURE_DEFORMATION_SGIX       0x8195\n#define GL_DEFORMATIONS_MASK_SGIX         0x8196\n#define GL_MAX_DEFORMATION_ORDER_SGIX     0x8197\ntypedef void (APIENTRYP PFNGLDEFORMATIONMAP3DSGIXPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);\ntypedef void (APIENTRYP PFNGLDEFORMATIONMAP3FSGIXPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);\ntypedef void (APIENTRYP PFNGLDEFORMSGIXPROC) (GLbitfield mask);\ntypedef void (APIENTRYP PFNGLLOADIDENTITYDEFORMATIONMAPSGIXPROC) (GLbitfield mask);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDeformationMap3dSGIX (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, GLdouble w1, GLdouble w2, GLint wstride, GLint worder, const GLdouble *points);\nGLAPI void APIENTRY glDeformationMap3fSGIX (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, GLfloat w1, GLfloat w2, GLint wstride, GLint worder, const GLfloat *points);\nGLAPI void APIENTRY glDeformSGIX (GLbitfield mask);\nGLAPI void APIENTRY glLoadIdentityDeformationMapSGIX (GLbitfield mask);\n#endif\n#endif /* GL_SGIX_polynomial_ffd */\n\n#ifndef GL_SGIX_reference_plane\n#define GL_SGIX_reference_plane 1\n#define GL_REFERENCE_PLANE_SGIX           0x817D\n#define GL_REFERENCE_PLANE_EQUATION_SGIX  0x817E\ntypedef void (APIENTRYP PFNGLREFERENCEPLANESGIXPROC) (const GLdouble *equation);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glReferencePlaneSGIX (const GLdouble *equation);\n#endif\n#endif /* GL_SGIX_reference_plane */\n\n#ifndef GL_SGIX_resample\n#define GL_SGIX_resample 1\n#define GL_PACK_RESAMPLE_SGIX             0x842E\n#define GL_UNPACK_RESAMPLE_SGIX           0x842F\n#define GL_RESAMPLE_REPLICATE_SGIX        0x8433\n#define GL_RESAMPLE_ZERO_FILL_SGIX        0x8434\n#define GL_RESAMPLE_DECIMATE_SGIX         0x8430\n#endif /* GL_SGIX_resample */\n\n#ifndef GL_SGIX_scalebias_hint\n#define GL_SGIX_scalebias_hint 1\n#define GL_SCALEBIAS_HINT_SGIX            0x8322\n#endif /* GL_SGIX_scalebias_hint */\n\n#ifndef GL_SGIX_shadow\n#define GL_SGIX_shadow 1\n#define GL_TEXTURE_COMPARE_SGIX           0x819A\n#define GL_TEXTURE_COMPARE_OPERATOR_SGIX  0x819B\n#define GL_TEXTURE_LEQUAL_R_SGIX          0x819C\n#define GL_TEXTURE_GEQUAL_R_SGIX          0x819D\n#endif /* GL_SGIX_shadow */\n\n#ifndef GL_SGIX_shadow_ambient\n#define GL_SGIX_shadow_ambient 1\n#define GL_SHADOW_AMBIENT_SGIX            0x80BF\n#endif /* GL_SGIX_shadow_ambient */\n\n#ifndef GL_SGIX_sprite\n#define GL_SGIX_sprite 1\n#define GL_SPRITE_SGIX                    0x8148\n#define GL_SPRITE_MODE_SGIX               0x8149\n#define GL_SPRITE_AXIS_SGIX               0x814A\n#define GL_SPRITE_TRANSLATION_SGIX        0x814B\n#define GL_SPRITE_AXIAL_SGIX              0x814C\n#define GL_SPRITE_OBJECT_ALIGNED_SGIX     0x814D\n#define GL_SPRITE_EYE_ALIGNED_SGIX        0x814E\ntypedef void (APIENTRYP PFNGLSPRITEPARAMETERFSGIXPROC) (GLenum pname, GLfloat param);\ntypedef void (APIENTRYP PFNGLSPRITEPARAMETERFVSGIXPROC) (GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLSPRITEPARAMETERISGIXPROC) (GLenum pname, GLint param);\ntypedef void (APIENTRYP PFNGLSPRITEPARAMETERIVSGIXPROC) (GLenum pname, const GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glSpriteParameterfSGIX (GLenum pname, GLfloat param);\nGLAPI void APIENTRY glSpriteParameterfvSGIX (GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glSpriteParameteriSGIX (GLenum pname, GLint param);\nGLAPI void APIENTRY glSpriteParameterivSGIX (GLenum pname, const GLint *params);\n#endif\n#endif /* GL_SGIX_sprite */\n\n#ifndef GL_SGIX_subsample\n#define GL_SGIX_subsample 1\n#define GL_PACK_SUBSAMPLE_RATE_SGIX       0x85A0\n#define GL_UNPACK_SUBSAMPLE_RATE_SGIX     0x85A1\n#define GL_PIXEL_SUBSAMPLE_4444_SGIX      0x85A2\n#define GL_PIXEL_SUBSAMPLE_2424_SGIX      0x85A3\n#define GL_PIXEL_SUBSAMPLE_4242_SGIX      0x85A4\n#endif /* GL_SGIX_subsample */\n\n#ifndef GL_SGIX_tag_sample_buffer\n#define GL_SGIX_tag_sample_buffer 1\ntypedef void (APIENTRYP PFNGLTAGSAMPLEBUFFERSGIXPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glTagSampleBufferSGIX (void);\n#endif\n#endif /* GL_SGIX_tag_sample_buffer */\n\n#ifndef GL_SGIX_texture_add_env\n#define GL_SGIX_texture_add_env 1\n#define GL_TEXTURE_ENV_BIAS_SGIX          0x80BE\n#endif /* GL_SGIX_texture_add_env */\n\n#ifndef GL_SGIX_texture_coordinate_clamp\n#define GL_SGIX_texture_coordinate_clamp 1\n#define GL_TEXTURE_MAX_CLAMP_S_SGIX       0x8369\n#define GL_TEXTURE_MAX_CLAMP_T_SGIX       0x836A\n#define GL_TEXTURE_MAX_CLAMP_R_SGIX       0x836B\n#endif /* GL_SGIX_texture_coordinate_clamp */\n\n#ifndef GL_SGIX_texture_lod_bias\n#define GL_SGIX_texture_lod_bias 1\n#define GL_TEXTURE_LOD_BIAS_S_SGIX        0x818E\n#define GL_TEXTURE_LOD_BIAS_T_SGIX        0x818F\n#define GL_TEXTURE_LOD_BIAS_R_SGIX        0x8190\n#endif /* GL_SGIX_texture_lod_bias */\n\n#ifndef GL_SGIX_texture_multi_buffer\n#define GL_SGIX_texture_multi_buffer 1\n#define GL_TEXTURE_MULTI_BUFFER_HINT_SGIX 0x812E\n#endif /* GL_SGIX_texture_multi_buffer */\n\n#ifndef GL_SGIX_texture_scale_bias\n#define GL_SGIX_texture_scale_bias 1\n#define GL_POST_TEXTURE_FILTER_BIAS_SGIX  0x8179\n#define GL_POST_TEXTURE_FILTER_SCALE_SGIX 0x817A\n#define GL_POST_TEXTURE_FILTER_BIAS_RANGE_SGIX 0x817B\n#define GL_POST_TEXTURE_FILTER_SCALE_RANGE_SGIX 0x817C\n#endif /* GL_SGIX_texture_scale_bias */\n\n#ifndef GL_SGIX_vertex_preclip\n#define GL_SGIX_vertex_preclip 1\n#define GL_VERTEX_PRECLIP_SGIX            0x83EE\n#define GL_VERTEX_PRECLIP_HINT_SGIX       0x83EF\n#endif /* GL_SGIX_vertex_preclip */\n\n#ifndef GL_SGIX_ycrcb\n#define GL_SGIX_ycrcb 1\n#define GL_YCRCB_422_SGIX                 0x81BB\n#define GL_YCRCB_444_SGIX                 0x81BC\n#endif /* GL_SGIX_ycrcb */\n\n#ifndef GL_SGIX_ycrcb_subsample\n#define GL_SGIX_ycrcb_subsample 1\n#endif /* GL_SGIX_ycrcb_subsample */\n\n#ifndef GL_SGIX_ycrcba\n#define GL_SGIX_ycrcba 1\n#define GL_YCRCB_SGIX                     0x8318\n#define GL_YCRCBA_SGIX                    0x8319\n#endif /* GL_SGIX_ycrcba */\n\n#ifndef GL_SGI_color_matrix\n#define GL_SGI_color_matrix 1\n#define GL_COLOR_MATRIX_SGI               0x80B1\n#define GL_COLOR_MATRIX_STACK_DEPTH_SGI   0x80B2\n#define GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI 0x80B3\n#define GL_POST_COLOR_MATRIX_RED_SCALE_SGI 0x80B4\n#define GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI 0x80B5\n#define GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI 0x80B6\n#define GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI 0x80B7\n#define GL_POST_COLOR_MATRIX_RED_BIAS_SGI 0x80B8\n#define GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI 0x80B9\n#define GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI 0x80BA\n#define GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI 0x80BB\n#endif /* GL_SGI_color_matrix */\n\n#ifndef GL_SGI_color_table\n#define GL_SGI_color_table 1\n#define GL_COLOR_TABLE_SGI                0x80D0\n#define GL_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D1\n#define GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D2\n#define GL_PROXY_COLOR_TABLE_SGI          0x80D3\n#define GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI 0x80D4\n#define GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI 0x80D5\n#define GL_COLOR_TABLE_SCALE_SGI          0x80D6\n#define GL_COLOR_TABLE_BIAS_SGI           0x80D7\n#define GL_COLOR_TABLE_FORMAT_SGI         0x80D8\n#define GL_COLOR_TABLE_WIDTH_SGI          0x80D9\n#define GL_COLOR_TABLE_RED_SIZE_SGI       0x80DA\n#define GL_COLOR_TABLE_GREEN_SIZE_SGI     0x80DB\n#define GL_COLOR_TABLE_BLUE_SIZE_SGI      0x80DC\n#define GL_COLOR_TABLE_ALPHA_SIZE_SGI     0x80DD\n#define GL_COLOR_TABLE_LUMINANCE_SIZE_SGI 0x80DE\n#define GL_COLOR_TABLE_INTENSITY_SIZE_SGI 0x80DF\ntypedef void (APIENTRYP PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);\ntypedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat *params);\ntypedef void (APIENTRYP PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint *params);\ntypedef void (APIENTRYP PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, void *table);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat *params);\ntypedef void (APIENTRYP PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint *params);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColorTableSGI (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void *table);\nGLAPI void APIENTRY glColorTableParameterfvSGI (GLenum target, GLenum pname, const GLfloat *params);\nGLAPI void APIENTRY glColorTableParameterivSGI (GLenum target, GLenum pname, const GLint *params);\nGLAPI void APIENTRY glCopyColorTableSGI (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width);\nGLAPI void APIENTRY glGetColorTableSGI (GLenum target, GLenum format, GLenum type, void *table);\nGLAPI void APIENTRY glGetColorTableParameterfvSGI (GLenum target, GLenum pname, GLfloat *params);\nGLAPI void APIENTRY glGetColorTableParameterivSGI (GLenum target, GLenum pname, GLint *params);\n#endif\n#endif /* GL_SGI_color_table */\n\n#ifndef GL_SGI_texture_color_table\n#define GL_SGI_texture_color_table 1\n#define GL_TEXTURE_COLOR_TABLE_SGI        0x80BC\n#define GL_PROXY_TEXTURE_COLOR_TABLE_SGI  0x80BD\n#endif /* GL_SGI_texture_color_table */\n\n#ifndef GL_SUNX_constant_data\n#define GL_SUNX_constant_data 1\n#define GL_UNPACK_CONSTANT_DATA_SUNX      0x81D5\n#define GL_TEXTURE_CONSTANT_DATA_SUNX     0x81D6\ntypedef void (APIENTRYP PFNGLFINISHTEXTURESUNXPROC) (void);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glFinishTextureSUNX (void);\n#endif\n#endif /* GL_SUNX_constant_data */\n\n#ifndef GL_SUN_convolution_border_modes\n#define GL_SUN_convolution_border_modes 1\n#define GL_WRAP_BORDER_SUN                0x81D4\n#endif /* GL_SUN_convolution_border_modes */\n\n#ifndef GL_SUN_global_alpha\n#define GL_SUN_global_alpha 1\n#define GL_GLOBAL_ALPHA_SUN               0x81D9\n#define GL_GLOBAL_ALPHA_FACTOR_SUN        0x81DA\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORBSUNPROC) (GLbyte factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORSSUNPROC) (GLshort factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORISUNPROC) (GLint factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORFSUNPROC) (GLfloat factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORDSUNPROC) (GLdouble factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUBSUNPROC) (GLubyte factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUSSUNPROC) (GLushort factor);\ntypedef void (APIENTRYP PFNGLGLOBALALPHAFACTORUISUNPROC) (GLuint factor);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glGlobalAlphaFactorbSUN (GLbyte factor);\nGLAPI void APIENTRY glGlobalAlphaFactorsSUN (GLshort factor);\nGLAPI void APIENTRY glGlobalAlphaFactoriSUN (GLint factor);\nGLAPI void APIENTRY glGlobalAlphaFactorfSUN (GLfloat factor);\nGLAPI void APIENTRY glGlobalAlphaFactordSUN (GLdouble factor);\nGLAPI void APIENTRY glGlobalAlphaFactorubSUN (GLubyte factor);\nGLAPI void APIENTRY glGlobalAlphaFactorusSUN (GLushort factor);\nGLAPI void APIENTRY glGlobalAlphaFactoruiSUN (GLuint factor);\n#endif\n#endif /* GL_SUN_global_alpha */\n\n#ifndef GL_SUN_mesh_array\n#define GL_SUN_mesh_array 1\n#define GL_QUAD_MESH_SUN                  0x8614\n#define GL_TRIANGLE_MESH_SUN              0x8615\ntypedef void (APIENTRYP PFNGLDRAWMESHARRAYSSUNPROC) (GLenum mode, GLint first, GLsizei count, GLsizei width);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glDrawMeshArraysSUN (GLenum mode, GLint first, GLsizei count, GLsizei width);\n#endif\n#endif /* GL_SUN_mesh_array */\n\n#ifndef GL_SUN_slice_accum\n#define GL_SUN_slice_accum 1\n#define GL_SLICE_ACCUM_SUN                0x85CC\n#endif /* GL_SUN_slice_accum */\n\n#ifndef GL_SUN_triangle_list\n#define GL_SUN_triangle_list 1\n#define GL_RESTART_SUN                    0x0001\n#define GL_REPLACE_MIDDLE_SUN             0x0002\n#define GL_REPLACE_OLDEST_SUN             0x0003\n#define GL_TRIANGLE_LIST_SUN              0x81D7\n#define GL_REPLACEMENT_CODE_SUN           0x81D8\n#define GL_REPLACEMENT_CODE_ARRAY_SUN     0x85C0\n#define GL_REPLACEMENT_CODE_ARRAY_TYPE_SUN 0x85C1\n#define GL_REPLACEMENT_CODE_ARRAY_STRIDE_SUN 0x85C2\n#define GL_REPLACEMENT_CODE_ARRAY_POINTER_SUN 0x85C3\n#define GL_R1UI_V3F_SUN                   0x85C4\n#define GL_R1UI_C4UB_V3F_SUN              0x85C5\n#define GL_R1UI_C3F_V3F_SUN               0x85C6\n#define GL_R1UI_N3F_V3F_SUN               0x85C7\n#define GL_R1UI_C4F_N3F_V3F_SUN           0x85C8\n#define GL_R1UI_T2F_V3F_SUN               0x85C9\n#define GL_R1UI_T2F_N3F_V3F_SUN           0x85CA\n#define GL_R1UI_T2F_C4F_N3F_V3F_SUN       0x85CB\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUSSUNPROC) (GLushort code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVSUNPROC) (const GLuint *code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUSVSUNPROC) (const GLushort *code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte *code);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const void **pointer);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glReplacementCodeuiSUN (GLuint code);\nGLAPI void APIENTRY glReplacementCodeusSUN (GLushort code);\nGLAPI void APIENTRY glReplacementCodeubSUN (GLubyte code);\nGLAPI void APIENTRY glReplacementCodeuivSUN (const GLuint *code);\nGLAPI void APIENTRY glReplacementCodeusvSUN (const GLushort *code);\nGLAPI void APIENTRY glReplacementCodeubvSUN (const GLubyte *code);\nGLAPI void APIENTRY glReplacementCodePointerSUN (GLenum type, GLsizei stride, const void **pointer);\n#endif\n#endif /* GL_SUN_triangle_list */\n\n#ifndef GL_SUN_vertex\n#define GL_SUN_vertex 1\ntypedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);\ntypedef void (APIENTRYP PFNGLCOLOR4UBVERTEX2FVSUNPROC) (const GLubyte *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FSUNPROC) (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLCOLOR4UBVERTEX3FVSUNPROC) (const GLubyte *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FSUNPROC) (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *c, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLTEXCOORD4FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4UBVERTEX3FVSUNPROC) (const GLfloat *tc, const GLubyte *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLTEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FSUNPROC) (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (APIENTRYP PFNGLTEXCOORD4FCOLOR4FNORMAL3FVERTEX4FVSUNPROC) (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FSUNPROC) (GLuint rc, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUIVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FSUNPROC) (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4UBVERTEX3FVSUNPROC) (const GLuint *rc, const GLubyte *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUINORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUICOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FSUNPROC) (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (APIENTRYP PFNGLREPLACEMENTCODEUITEXCOORD2FCOLOR4FNORMAL3FVERTEX3FVSUNPROC) (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\n#ifdef GL_GLEXT_PROTOTYPES\nGLAPI void APIENTRY glColor4ubVertex2fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y);\nGLAPI void APIENTRY glColor4ubVertex2fvSUN (const GLubyte *c, const GLfloat *v);\nGLAPI void APIENTRY glColor4ubVertex3fSUN (GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glColor4ubVertex3fvSUN (const GLubyte *c, const GLfloat *v);\nGLAPI void APIENTRY glColor3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glColor3fVertex3fvSUN (const GLfloat *c, const GLfloat *v);\nGLAPI void APIENTRY glNormal3fVertex3fSUN (GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glNormal3fVertex3fvSUN (const GLfloat *n, const GLfloat *v);\nGLAPI void APIENTRY glColor4fNormal3fVertex3fSUN (GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glColor4fNormal3fVertex3fvSUN (const GLfloat *c, const GLfloat *n, const GLfloat *v);\nGLAPI void APIENTRY glTexCoord2fVertex3fSUN (GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glTexCoord2fVertex3fvSUN (const GLfloat *tc, const GLfloat *v);\nGLAPI void APIENTRY glTexCoord4fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glTexCoord4fVertex4fvSUN (const GLfloat *tc, const GLfloat *v);\nGLAPI void APIENTRY glTexCoord2fColor4ubVertex3fSUN (GLfloat s, GLfloat t, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glTexCoord2fColor4ubVertex3fvSUN (const GLfloat *tc, const GLubyte *c, const GLfloat *v);\nGLAPI void APIENTRY glTexCoord2fColor3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glTexCoord2fColor3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *v);\nGLAPI void APIENTRY glTexCoord2fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glTexCoord2fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *n, const GLfloat *v);\nGLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fSUN (GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glTexCoord2fColor4fNormal3fVertex3fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\nGLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fSUN (GLfloat s, GLfloat t, GLfloat p, GLfloat q, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\nGLAPI void APIENTRY glTexCoord4fColor4fNormal3fVertex4fvSUN (const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\nGLAPI void APIENTRY glReplacementCodeuiVertex3fSUN (GLuint rc, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glReplacementCodeuiVertex3fvSUN (const GLuint *rc, const GLfloat *v);\nGLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fSUN (GLuint rc, GLubyte r, GLubyte g, GLubyte b, GLubyte a, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glReplacementCodeuiColor4ubVertex3fvSUN (const GLuint *rc, const GLubyte *c, const GLfloat *v);\nGLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glReplacementCodeuiColor3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *v);\nGLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fSUN (GLuint rc, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glReplacementCodeuiNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *n, const GLfloat *v);\nGLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glReplacementCodeuiColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *v);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *n, const GLfloat *v);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN (GLuint rc, GLfloat s, GLfloat t, GLfloat r, GLfloat g, GLfloat b, GLfloat a, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat x, GLfloat y, GLfloat z);\nGLAPI void APIENTRY glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN (const GLuint *rc, const GLfloat *tc, const GLfloat *c, const GLfloat *n, const GLfloat *v);\n#endif\n#endif /* GL_SUN_vertex */\n\n#ifndef GL_WIN_phong_shading\n#define GL_WIN_phong_shading 1\n#define GL_PHONG_WIN                      0x80EA\n#define GL_PHONG_HINT_WIN                 0x80EB\n#endif /* GL_WIN_phong_shading */\n\n#ifndef GL_WIN_specular_fog\n#define GL_WIN_specular_fog 1\n#define GL_FOG_SPECULAR_TEXTURE_WIN       0x80EC\n#endif /* GL_WIN_specular_fog */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/Common/GLInclude/glxext.h",
    "content": "#ifndef __glx_glxext_h_\n#define __glx_glxext_h_ 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n** Copyright 2013-2020 The Khronos Group Inc.\n** SPDX-License-Identifier: MIT\n**\n** This header is generated from the Khronos OpenGL / OpenGL ES XML\n** API Registry. The current version of the Registry, generator scripts\n** used to make the header, and the header can be found at\n**   https://github.com/KhronosGroup/OpenGL-Registry\n*/\n\n#define GLX_GLXEXT_VERSION 20211115\n\n/* Generated C header for:\n * API: glx\n * Versions considered: .*\n * Versions emitted: 1\\.[3-9]\n * Default extensions included: glx\n * Additional extensions included: _nomatch_^\n * Extensions removed: _nomatch_^\n */\n\n#ifndef GLX_VERSION_1_3\n#define GLX_VERSION_1_3 1\ntypedef XID GLXContextID;\ntypedef struct __GLXFBConfigRec *GLXFBConfig;\ntypedef XID GLXWindow;\ntypedef XID GLXPbuffer;\n#define GLX_WINDOW_BIT                    0x00000001\n#define GLX_PIXMAP_BIT                    0x00000002\n#define GLX_PBUFFER_BIT                   0x00000004\n#define GLX_RGBA_BIT                      0x00000001\n#define GLX_COLOR_INDEX_BIT               0x00000002\n#define GLX_PBUFFER_CLOBBER_MASK          0x08000000\n#define GLX_FRONT_LEFT_BUFFER_BIT         0x00000001\n#define GLX_FRONT_RIGHT_BUFFER_BIT        0x00000002\n#define GLX_BACK_LEFT_BUFFER_BIT          0x00000004\n#define GLX_BACK_RIGHT_BUFFER_BIT         0x00000008\n#define GLX_AUX_BUFFERS_BIT               0x00000010\n#define GLX_DEPTH_BUFFER_BIT              0x00000020\n#define GLX_STENCIL_BUFFER_BIT            0x00000040\n#define GLX_ACCUM_BUFFER_BIT              0x00000080\n#define GLX_CONFIG_CAVEAT                 0x20\n#define GLX_X_VISUAL_TYPE                 0x22\n#define GLX_TRANSPARENT_TYPE              0x23\n#define GLX_TRANSPARENT_INDEX_VALUE       0x24\n#define GLX_TRANSPARENT_RED_VALUE         0x25\n#define GLX_TRANSPARENT_GREEN_VALUE       0x26\n#define GLX_TRANSPARENT_BLUE_VALUE        0x27\n#define GLX_TRANSPARENT_ALPHA_VALUE       0x28\n#define GLX_DONT_CARE                     0xFFFFFFFF\n#define GLX_NONE                          0x8000\n#define GLX_SLOW_CONFIG                   0x8001\n#define GLX_TRUE_COLOR                    0x8002\n#define GLX_DIRECT_COLOR                  0x8003\n#define GLX_PSEUDO_COLOR                  0x8004\n#define GLX_STATIC_COLOR                  0x8005\n#define GLX_GRAY_SCALE                    0x8006\n#define GLX_STATIC_GRAY                   0x8007\n#define GLX_TRANSPARENT_RGB               0x8008\n#define GLX_TRANSPARENT_INDEX             0x8009\n#define GLX_VISUAL_ID                     0x800B\n#define GLX_SCREEN                        0x800C\n#define GLX_NON_CONFORMANT_CONFIG         0x800D\n#define GLX_DRAWABLE_TYPE                 0x8010\n#define GLX_RENDER_TYPE                   0x8011\n#define GLX_X_RENDERABLE                  0x8012\n#define GLX_FBCONFIG_ID                   0x8013\n#define GLX_RGBA_TYPE                     0x8014\n#define GLX_COLOR_INDEX_TYPE              0x8015\n#define GLX_MAX_PBUFFER_WIDTH             0x8016\n#define GLX_MAX_PBUFFER_HEIGHT            0x8017\n#define GLX_MAX_PBUFFER_PIXELS            0x8018\n#define GLX_PRESERVED_CONTENTS            0x801B\n#define GLX_LARGEST_PBUFFER               0x801C\n#define GLX_WIDTH                         0x801D\n#define GLX_HEIGHT                        0x801E\n#define GLX_EVENT_MASK                    0x801F\n#define GLX_DAMAGED                       0x8020\n#define GLX_SAVED                         0x8021\n#define GLX_WINDOW                        0x8022\n#define GLX_PBUFFER                       0x8023\n#define GLX_PBUFFER_HEIGHT                0x8040\n#define GLX_PBUFFER_WIDTH                 0x8041\ntypedef GLXFBConfig *( *PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements);\ntypedef GLXFBConfig *( *PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);\ntypedef int ( *PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value);\ntypedef XVisualInfo *( *PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config);\ntypedef GLXWindow ( *PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);\ntypedef void ( *PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win);\ntypedef GLXPixmap ( *PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);\ntypedef void ( *PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap);\ntypedef GLXPbuffer ( *PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list);\ntypedef void ( *PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf);\ntypedef void ( *PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);\ntypedef GLXContext ( *PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);\ntypedef Bool ( *PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);\ntypedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLEPROC) (void);\ntypedef int ( *PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value);\ntypedef void ( *PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask);\ntypedef void ( *PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask);\n#ifdef GLX_GLXEXT_PROTOTYPES\nGLXFBConfig *glXGetFBConfigs (Display *dpy, int screen, int *nelements);\nGLXFBConfig *glXChooseFBConfig (Display *dpy, int screen, const int *attrib_list, int *nelements);\nint glXGetFBConfigAttrib (Display *dpy, GLXFBConfig config, int attribute, int *value);\nXVisualInfo *glXGetVisualFromFBConfig (Display *dpy, GLXFBConfig config);\nGLXWindow glXCreateWindow (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list);\nvoid glXDestroyWindow (Display *dpy, GLXWindow win);\nGLXPixmap glXCreatePixmap (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list);\nvoid glXDestroyPixmap (Display *dpy, GLXPixmap pixmap);\nGLXPbuffer glXCreatePbuffer (Display *dpy, GLXFBConfig config, const int *attrib_list);\nvoid glXDestroyPbuffer (Display *dpy, GLXPbuffer pbuf);\nvoid glXQueryDrawable (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value);\nGLXContext glXCreateNewContext (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct);\nBool glXMakeContextCurrent (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);\nGLXDrawable glXGetCurrentReadDrawable (void);\nint glXQueryContext (Display *dpy, GLXContext ctx, int attribute, int *value);\nvoid glXSelectEvent (Display *dpy, GLXDrawable draw, unsigned long event_mask);\nvoid glXGetSelectedEvent (Display *dpy, GLXDrawable draw, unsigned long *event_mask);\n#endif\n#endif /* GLX_VERSION_1_3 */\n\n#ifndef GLX_VERSION_1_4\n#define GLX_VERSION_1_4 1\ntypedef void ( *__GLXextFuncPtr)(void);\n#define GLX_SAMPLE_BUFFERS                100000\n#define GLX_SAMPLES                       100001\ntypedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName);\n#ifdef GLX_GLXEXT_PROTOTYPES\n__GLXextFuncPtr glXGetProcAddress (const GLubyte *procName);\n#endif\n#endif /* GLX_VERSION_1_4 */\n\n#ifndef GLX_ARB_context_flush_control\n#define GLX_ARB_context_flush_control 1\n#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB  0x2097\n#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0\n#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098\n#endif /* GLX_ARB_context_flush_control */\n\n#ifndef GLX_ARB_create_context\n#define GLX_ARB_create_context 1\n#define GLX_CONTEXT_DEBUG_BIT_ARB         0x00000001\n#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002\n#define GLX_CONTEXT_MAJOR_VERSION_ARB     0x2091\n#define GLX_CONTEXT_MINOR_VERSION_ARB     0x2092\n#define GLX_CONTEXT_FLAGS_ARB             0x2094\ntypedef GLXContext ( *PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);\n#ifdef GLX_GLXEXT_PROTOTYPES\nGLXContext glXCreateContextAttribsARB (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);\n#endif\n#endif /* GLX_ARB_create_context */\n\n#ifndef GLX_ARB_create_context_no_error\n#define GLX_ARB_create_context_no_error 1\n#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB   0x31B3\n#endif /* GLX_ARB_create_context_no_error */\n\n#ifndef GLX_ARB_create_context_profile\n#define GLX_ARB_create_context_profile 1\n#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB  0x00000001\n#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002\n#define GLX_CONTEXT_PROFILE_MASK_ARB      0x9126\n#endif /* GLX_ARB_create_context_profile */\n\n#ifndef GLX_ARB_create_context_robustness\n#define GLX_ARB_create_context_robustness 1\n#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004\n#define GLX_LOSE_CONTEXT_ON_RESET_ARB     0x8252\n#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256\n#define GLX_NO_RESET_NOTIFICATION_ARB     0x8261\n#endif /* GLX_ARB_create_context_robustness */\n\n#ifndef GLX_ARB_fbconfig_float\n#define GLX_ARB_fbconfig_float 1\n#define GLX_RGBA_FLOAT_TYPE_ARB           0x20B9\n#define GLX_RGBA_FLOAT_BIT_ARB            0x00000004\n#endif /* GLX_ARB_fbconfig_float */\n\n#ifndef GLX_ARB_framebuffer_sRGB\n#define GLX_ARB_framebuffer_sRGB 1\n#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB  0x20B2\n#endif /* GLX_ARB_framebuffer_sRGB */\n\n#ifndef GLX_ARB_get_proc_address\n#define GLX_ARB_get_proc_address 1\ntypedef __GLXextFuncPtr ( *PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName);\n#ifdef GLX_GLXEXT_PROTOTYPES\n__GLXextFuncPtr glXGetProcAddressARB (const GLubyte *procName);\n#endif\n#endif /* GLX_ARB_get_proc_address */\n\n#ifndef GLX_ARB_multisample\n#define GLX_ARB_multisample 1\n#define GLX_SAMPLE_BUFFERS_ARB            100000\n#define GLX_SAMPLES_ARB                   100001\n#endif /* GLX_ARB_multisample */\n\n#ifndef GLX_ARB_robustness_application_isolation\n#define GLX_ARB_robustness_application_isolation 1\n#define GLX_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008\n#endif /* GLX_ARB_robustness_application_isolation */\n\n#ifndef GLX_ARB_robustness_share_group_isolation\n#define GLX_ARB_robustness_share_group_isolation 1\n#endif /* GLX_ARB_robustness_share_group_isolation */\n\n#ifndef GLX_ARB_vertex_buffer_object\n#define GLX_ARB_vertex_buffer_object 1\n#define GLX_CONTEXT_ALLOW_BUFFER_BYTE_ORDER_MISMATCH_ARB 0x2095\n#endif /* GLX_ARB_vertex_buffer_object */\n\n#ifndef GLX_3DFX_multisample\n#define GLX_3DFX_multisample 1\n#define GLX_SAMPLE_BUFFERS_3DFX           0x8050\n#define GLX_SAMPLES_3DFX                  0x8051\n#endif /* GLX_3DFX_multisample */\n\n#ifndef GLX_AMD_gpu_association\n#define GLX_AMD_gpu_association 1\n#define GLX_GPU_VENDOR_AMD                0x1F00\n#define GLX_GPU_RENDERER_STRING_AMD       0x1F01\n#define GLX_GPU_OPENGL_VERSION_STRING_AMD 0x1F02\n#define GLX_GPU_FASTEST_TARGET_GPUS_AMD   0x21A2\n#define GLX_GPU_RAM_AMD                   0x21A3\n#define GLX_GPU_CLOCK_AMD                 0x21A4\n#define GLX_GPU_NUM_PIPES_AMD             0x21A5\n#define GLX_GPU_NUM_SIMD_AMD              0x21A6\n#define GLX_GPU_NUM_RB_AMD                0x21A7\n#define GLX_GPU_NUM_SPI_AMD               0x21A8\ntypedef unsigned int ( *PFNGLXGETGPUIDSAMDPROC) (unsigned int maxCount, unsigned int *ids);\ntypedef int ( *PFNGLXGETGPUINFOAMDPROC) (unsigned int id, int property, GLenum dataType, unsigned int size, void *data);\ntypedef unsigned int ( *PFNGLXGETCONTEXTGPUIDAMDPROC) (GLXContext ctx);\ntypedef GLXContext ( *PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC) (unsigned int id, GLXContext share_list);\ntypedef GLXContext ( *PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (unsigned int id, GLXContext share_context, const int *attribList);\ntypedef Bool ( *PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC) (GLXContext ctx);\ntypedef Bool ( *PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (GLXContext ctx);\ntypedef GLXContext ( *PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void);\ntypedef void ( *PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC) (GLXContext dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\n#ifdef GLX_GLXEXT_PROTOTYPES\nunsigned int glXGetGPUIDsAMD (unsigned int maxCount, unsigned int *ids);\nint glXGetGPUInfoAMD (unsigned int id, int property, GLenum dataType, unsigned int size, void *data);\nunsigned int glXGetContextGPUIDAMD (GLXContext ctx);\nGLXContext glXCreateAssociatedContextAMD (unsigned int id, GLXContext share_list);\nGLXContext glXCreateAssociatedContextAttribsAMD (unsigned int id, GLXContext share_context, const int *attribList);\nBool glXDeleteAssociatedContextAMD (GLXContext ctx);\nBool glXMakeAssociatedContextCurrentAMD (GLXContext ctx);\nGLXContext glXGetCurrentAssociatedContextAMD (void);\nvoid glXBlitContextFramebufferAMD (GLXContext dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\n#endif\n#endif /* GLX_AMD_gpu_association */\n\n#ifndef GLX_EXT_buffer_age\n#define GLX_EXT_buffer_age 1\n#define GLX_BACK_BUFFER_AGE_EXT           0x20F4\n#endif /* GLX_EXT_buffer_age */\n\n#ifndef GLX_EXT_context_priority\n#define GLX_EXT_context_priority 1\n#define GLX_CONTEXT_PRIORITY_LEVEL_EXT    0x3100\n#define GLX_CONTEXT_PRIORITY_HIGH_EXT     0x3101\n#define GLX_CONTEXT_PRIORITY_MEDIUM_EXT   0x3102\n#define GLX_CONTEXT_PRIORITY_LOW_EXT      0x3103\n#endif /* GLX_EXT_context_priority */\n\n#ifndef GLX_EXT_create_context_es2_profile\n#define GLX_EXT_create_context_es2_profile 1\n#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT   0x00000004\n#endif /* GLX_EXT_create_context_es2_profile */\n\n#ifndef GLX_EXT_create_context_es_profile\n#define GLX_EXT_create_context_es_profile 1\n#define GLX_CONTEXT_ES_PROFILE_BIT_EXT    0x00000004\n#endif /* GLX_EXT_create_context_es_profile */\n\n#ifndef GLX_EXT_fbconfig_packed_float\n#define GLX_EXT_fbconfig_packed_float 1\n#define GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT  0x20B1\n#define GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT   0x00000008\n#endif /* GLX_EXT_fbconfig_packed_float */\n\n#ifndef GLX_EXT_framebuffer_sRGB\n#define GLX_EXT_framebuffer_sRGB 1\n#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT  0x20B2\n#endif /* GLX_EXT_framebuffer_sRGB */\n\n#ifndef GLX_EXT_get_drawable_type\n#define GLX_EXT_get_drawable_type 1\n#endif /* GLX_EXT_get_drawable_type */\n\n#ifndef GLX_EXT_import_context\n#define GLX_EXT_import_context 1\n#define GLX_SHARE_CONTEXT_EXT             0x800A\n#define GLX_VISUAL_ID_EXT                 0x800B\n#define GLX_SCREEN_EXT                    0x800C\ntypedef Display *( *PFNGLXGETCURRENTDISPLAYEXTPROC) (void);\ntypedef int ( *PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value);\ntypedef GLXContextID ( *PFNGLXGETCONTEXTIDEXTPROC) (const GLXContext context);\ntypedef GLXContext ( *PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID);\ntypedef void ( *PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context);\n#ifdef GLX_GLXEXT_PROTOTYPES\nDisplay *glXGetCurrentDisplayEXT (void);\nint glXQueryContextInfoEXT (Display *dpy, GLXContext context, int attribute, int *value);\nGLXContextID glXGetContextIDEXT (const GLXContext context);\nGLXContext glXImportContextEXT (Display *dpy, GLXContextID contextID);\nvoid glXFreeContextEXT (Display *dpy, GLXContext context);\n#endif\n#endif /* GLX_EXT_import_context */\n\n#ifndef GLX_EXT_libglvnd\n#define GLX_EXT_libglvnd 1\n#define GLX_VENDOR_NAMES_EXT              0x20F6\n#endif /* GLX_EXT_libglvnd */\n\n#ifndef GLX_EXT_no_config_context\n#define GLX_EXT_no_config_context 1\n#endif /* GLX_EXT_no_config_context */\n\n#ifndef GLX_EXT_stereo_tree\n#define GLX_EXT_stereo_tree 1\ntypedef struct {\n    int type;\n    unsigned long serial;\n    Bool send_event;\n    Display *display;\n    int extension;\n    int evtype;\n    GLXDrawable window;\n    Bool stereo_tree;\n} GLXStereoNotifyEventEXT;\n#define GLX_STEREO_TREE_EXT               0x20F5\n#define GLX_STEREO_NOTIFY_MASK_EXT        0x00000001\n#define GLX_STEREO_NOTIFY_EXT             0x00000000\n#endif /* GLX_EXT_stereo_tree */\n\n#ifndef GLX_EXT_swap_control\n#define GLX_EXT_swap_control 1\n#define GLX_SWAP_INTERVAL_EXT             0x20F1\n#define GLX_MAX_SWAP_INTERVAL_EXT         0x20F2\ntypedef void ( *PFNGLXSWAPINTERVALEXTPROC) (Display *dpy, GLXDrawable drawable, int interval);\n#ifdef GLX_GLXEXT_PROTOTYPES\nvoid glXSwapIntervalEXT (Display *dpy, GLXDrawable drawable, int interval);\n#endif\n#endif /* GLX_EXT_swap_control */\n\n#ifndef GLX_EXT_swap_control_tear\n#define GLX_EXT_swap_control_tear 1\n#define GLX_LATE_SWAPS_TEAR_EXT           0x20F3\n#endif /* GLX_EXT_swap_control_tear */\n\n#ifndef GLX_EXT_texture_from_pixmap\n#define GLX_EXT_texture_from_pixmap 1\n#define GLX_TEXTURE_1D_BIT_EXT            0x00000001\n#define GLX_TEXTURE_2D_BIT_EXT            0x00000002\n#define GLX_TEXTURE_RECTANGLE_BIT_EXT     0x00000004\n#define GLX_BIND_TO_TEXTURE_RGB_EXT       0x20D0\n#define GLX_BIND_TO_TEXTURE_RGBA_EXT      0x20D1\n#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT    0x20D2\n#define GLX_BIND_TO_TEXTURE_TARGETS_EXT   0x20D3\n#define GLX_Y_INVERTED_EXT                0x20D4\n#define GLX_TEXTURE_FORMAT_EXT            0x20D5\n#define GLX_TEXTURE_TARGET_EXT            0x20D6\n#define GLX_MIPMAP_TEXTURE_EXT            0x20D7\n#define GLX_TEXTURE_FORMAT_NONE_EXT       0x20D8\n#define GLX_TEXTURE_FORMAT_RGB_EXT        0x20D9\n#define GLX_TEXTURE_FORMAT_RGBA_EXT       0x20DA\n#define GLX_TEXTURE_1D_EXT                0x20DB\n#define GLX_TEXTURE_2D_EXT                0x20DC\n#define GLX_TEXTURE_RECTANGLE_EXT         0x20DD\n#define GLX_FRONT_LEFT_EXT                0x20DE\n#define GLX_FRONT_RIGHT_EXT               0x20DF\n#define GLX_BACK_LEFT_EXT                 0x20E0\n#define GLX_BACK_RIGHT_EXT                0x20E1\n#define GLX_FRONT_EXT                     0x20DE\n#define GLX_BACK_EXT                      0x20E0\n#define GLX_AUX0_EXT                      0x20E2\n#define GLX_AUX1_EXT                      0x20E3\n#define GLX_AUX2_EXT                      0x20E4\n#define GLX_AUX3_EXT                      0x20E5\n#define GLX_AUX4_EXT                      0x20E6\n#define GLX_AUX5_EXT                      0x20E7\n#define GLX_AUX6_EXT                      0x20E8\n#define GLX_AUX7_EXT                      0x20E9\n#define GLX_AUX8_EXT                      0x20EA\n#define GLX_AUX9_EXT                      0x20EB\ntypedef void ( *PFNGLXBINDTEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);\ntypedef void ( *PFNGLXRELEASETEXIMAGEEXTPROC) (Display *dpy, GLXDrawable drawable, int buffer);\n#ifdef GLX_GLXEXT_PROTOTYPES\nvoid glXBindTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list);\nvoid glXReleaseTexImageEXT (Display *dpy, GLXDrawable drawable, int buffer);\n#endif\n#endif /* GLX_EXT_texture_from_pixmap */\n\n#ifndef GLX_EXT_visual_info\n#define GLX_EXT_visual_info 1\n#define GLX_X_VISUAL_TYPE_EXT             0x22\n#define GLX_TRANSPARENT_TYPE_EXT          0x23\n#define GLX_TRANSPARENT_INDEX_VALUE_EXT   0x24\n#define GLX_TRANSPARENT_RED_VALUE_EXT     0x25\n#define GLX_TRANSPARENT_GREEN_VALUE_EXT   0x26\n#define GLX_TRANSPARENT_BLUE_VALUE_EXT    0x27\n#define GLX_TRANSPARENT_ALPHA_VALUE_EXT   0x28\n#define GLX_NONE_EXT                      0x8000\n#define GLX_TRUE_COLOR_EXT                0x8002\n#define GLX_DIRECT_COLOR_EXT              0x8003\n#define GLX_PSEUDO_COLOR_EXT              0x8004\n#define GLX_STATIC_COLOR_EXT              0x8005\n#define GLX_GRAY_SCALE_EXT                0x8006\n#define GLX_STATIC_GRAY_EXT               0x8007\n#define GLX_TRANSPARENT_RGB_EXT           0x8008\n#define GLX_TRANSPARENT_INDEX_EXT         0x8009\n#endif /* GLX_EXT_visual_info */\n\n#ifndef GLX_EXT_visual_rating\n#define GLX_EXT_visual_rating 1\n#define GLX_VISUAL_CAVEAT_EXT             0x20\n#define GLX_SLOW_VISUAL_EXT               0x8001\n#define GLX_NON_CONFORMANT_VISUAL_EXT     0x800D\n#endif /* GLX_EXT_visual_rating */\n\n#ifndef GLX_INTEL_swap_event\n#define GLX_INTEL_swap_event 1\n#define GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK 0x04000000\n#define GLX_EXCHANGE_COMPLETE_INTEL       0x8180\n#define GLX_COPY_COMPLETE_INTEL           0x8181\n#define GLX_FLIP_COMPLETE_INTEL           0x8182\n#endif /* GLX_INTEL_swap_event */\n\n#ifndef GLX_MESA_agp_offset\n#define GLX_MESA_agp_offset 1\ntypedef unsigned int ( *PFNGLXGETAGPOFFSETMESAPROC) (const void *pointer);\n#ifdef GLX_GLXEXT_PROTOTYPES\nunsigned int glXGetAGPOffsetMESA (const void *pointer);\n#endif\n#endif /* GLX_MESA_agp_offset */\n\n#ifndef GLX_MESA_copy_sub_buffer\n#define GLX_MESA_copy_sub_buffer 1\ntypedef void ( *PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);\n#ifdef GLX_GLXEXT_PROTOTYPES\nvoid glXCopySubBufferMESA (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);\n#endif\n#endif /* GLX_MESA_copy_sub_buffer */\n\n#ifndef GLX_MESA_pixmap_colormap\n#define GLX_MESA_pixmap_colormap 1\ntypedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap);\n#ifdef GLX_GLXEXT_PROTOTYPES\nGLXPixmap glXCreateGLXPixmapMESA (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap);\n#endif\n#endif /* GLX_MESA_pixmap_colormap */\n\n#ifndef GLX_MESA_query_renderer\n#define GLX_MESA_query_renderer 1\n#define GLX_RENDERER_VENDOR_ID_MESA       0x8183\n#define GLX_RENDERER_DEVICE_ID_MESA       0x8184\n#define GLX_RENDERER_VERSION_MESA         0x8185\n#define GLX_RENDERER_ACCELERATED_MESA     0x8186\n#define GLX_RENDERER_VIDEO_MEMORY_MESA    0x8187\n#define GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA 0x8188\n#define GLX_RENDERER_PREFERRED_PROFILE_MESA 0x8189\n#define GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA 0x818A\n#define GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA 0x818B\n#define GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA 0x818C\n#define GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA 0x818D\ntypedef Bool ( *PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) (int attribute, unsigned int *value);\ntypedef const char *( *PFNGLXQUERYCURRENTRENDERERSTRINGMESAPROC) (int attribute);\ntypedef Bool ( *PFNGLXQUERYRENDERERINTEGERMESAPROC) (Display *dpy, int screen, int renderer, int attribute, unsigned int *value);\ntypedef const char *( *PFNGLXQUERYRENDERERSTRINGMESAPROC) (Display *dpy, int screen, int renderer, int attribute);\n#ifdef GLX_GLXEXT_PROTOTYPES\nBool glXQueryCurrentRendererIntegerMESA (int attribute, unsigned int *value);\nconst char *glXQueryCurrentRendererStringMESA (int attribute);\nBool glXQueryRendererIntegerMESA (Display *dpy, int screen, int renderer, int attribute, unsigned int *value);\nconst char *glXQueryRendererStringMESA (Display *dpy, int screen, int renderer, int attribute);\n#endif\n#endif /* GLX_MESA_query_renderer */\n\n#ifndef GLX_MESA_release_buffers\n#define GLX_MESA_release_buffers 1\ntypedef Bool ( *PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable);\n#ifdef GLX_GLXEXT_PROTOTYPES\nBool glXReleaseBuffersMESA (Display *dpy, GLXDrawable drawable);\n#endif\n#endif /* GLX_MESA_release_buffers */\n\n#ifndef GLX_MESA_set_3dfx_mode\n#define GLX_MESA_set_3dfx_mode 1\n#define GLX_3DFX_WINDOW_MODE_MESA         0x1\n#define GLX_3DFX_FULLSCREEN_MODE_MESA     0x2\ntypedef GLboolean ( *PFNGLXSET3DFXMODEMESAPROC) (GLint mode);\n#ifdef GLX_GLXEXT_PROTOTYPES\nGLboolean glXSet3DfxModeMESA (GLint mode);\n#endif\n#endif /* GLX_MESA_set_3dfx_mode */\n\n#ifndef GLX_MESA_swap_control\n#define GLX_MESA_swap_control 1\ntypedef int ( *PFNGLXGETSWAPINTERVALMESAPROC) (void);\ntypedef int ( *PFNGLXSWAPINTERVALMESAPROC) (unsigned int interval);\n#ifdef GLX_GLXEXT_PROTOTYPES\nint glXGetSwapIntervalMESA (void);\nint glXSwapIntervalMESA (unsigned int interval);\n#endif\n#endif /* GLX_MESA_swap_control */\n\n#ifndef GLX_NV_copy_buffer\n#define GLX_NV_copy_buffer 1\ntypedef void ( *PFNGLXCOPYBUFFERSUBDATANVPROC) (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\ntypedef void ( *PFNGLXNAMEDCOPYBUFFERSUBDATANVPROC) (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\n#ifdef GLX_GLXEXT_PROTOTYPES\nvoid glXCopyBufferSubDataNV (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\nvoid glXNamedCopyBufferSubDataNV (Display *dpy, GLXContext readCtx, GLXContext writeCtx, GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\n#endif\n#endif /* GLX_NV_copy_buffer */\n\n#ifndef GLX_NV_copy_image\n#define GLX_NV_copy_image 1\ntypedef void ( *PFNGLXCOPYIMAGESUBDATANVPROC) (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);\n#ifdef GLX_GLXEXT_PROTOTYPES\nvoid glXCopyImageSubDataNV (Display *dpy, GLXContext srcCtx, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLXContext dstCtx, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);\n#endif\n#endif /* GLX_NV_copy_image */\n\n#ifndef GLX_NV_delay_before_swap\n#define GLX_NV_delay_before_swap 1\ntypedef Bool ( *PFNGLXDELAYBEFORESWAPNVPROC) (Display *dpy, GLXDrawable drawable, GLfloat seconds);\n#ifdef GLX_GLXEXT_PROTOTYPES\nBool glXDelayBeforeSwapNV (Display *dpy, GLXDrawable drawable, GLfloat seconds);\n#endif\n#endif /* GLX_NV_delay_before_swap */\n\n#ifndef GLX_NV_float_buffer\n#define GLX_NV_float_buffer 1\n#define GLX_FLOAT_COMPONENTS_NV           0x20B0\n#endif /* GLX_NV_float_buffer */\n\n#ifndef GLX_NV_multigpu_context\n#define GLX_NV_multigpu_context 1\n#define GLX_CONTEXT_MULTIGPU_ATTRIB_NV    0x20AA\n#define GLX_CONTEXT_MULTIGPU_ATTRIB_SINGLE_NV 0x20AB\n#define GLX_CONTEXT_MULTIGPU_ATTRIB_AFR_NV 0x20AC\n#define GLX_CONTEXT_MULTIGPU_ATTRIB_MULTICAST_NV 0x20AD\n#define GLX_CONTEXT_MULTIGPU_ATTRIB_MULTI_DISPLAY_MULTICAST_NV 0x20AE\n#endif /* GLX_NV_multigpu_context */\n\n#ifndef GLX_NV_multisample_coverage\n#define GLX_NV_multisample_coverage 1\n#define GLX_COVERAGE_SAMPLES_NV           100001\n#define GLX_COLOR_SAMPLES_NV              0x20B3\n#endif /* GLX_NV_multisample_coverage */\n\n#ifndef GLX_NV_present_video\n#define GLX_NV_present_video 1\n#define GLX_NUM_VIDEO_SLOTS_NV            0x20F0\ntypedef unsigned int *( *PFNGLXENUMERATEVIDEODEVICESNVPROC) (Display *dpy, int screen, int *nelements);\ntypedef int ( *PFNGLXBINDVIDEODEVICENVPROC) (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list);\n#ifdef GLX_GLXEXT_PROTOTYPES\nunsigned int *glXEnumerateVideoDevicesNV (Display *dpy, int screen, int *nelements);\nint glXBindVideoDeviceNV (Display *dpy, unsigned int video_slot, unsigned int video_device, const int *attrib_list);\n#endif\n#endif /* GLX_NV_present_video */\n\n#ifndef GLX_NV_robustness_video_memory_purge\n#define GLX_NV_robustness_video_memory_purge 1\n#define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7\n#endif /* GLX_NV_robustness_video_memory_purge */\n\n#ifndef GLX_NV_swap_group\n#define GLX_NV_swap_group 1\ntypedef Bool ( *PFNGLXJOINSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint group);\ntypedef Bool ( *PFNGLXBINDSWAPBARRIERNVPROC) (Display *dpy, GLuint group, GLuint barrier);\ntypedef Bool ( *PFNGLXQUERYSWAPGROUPNVPROC) (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);\ntypedef Bool ( *PFNGLXQUERYMAXSWAPGROUPSNVPROC) (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);\ntypedef Bool ( *PFNGLXQUERYFRAMECOUNTNVPROC) (Display *dpy, int screen, GLuint *count);\ntypedef Bool ( *PFNGLXRESETFRAMECOUNTNVPROC) (Display *dpy, int screen);\n#ifdef GLX_GLXEXT_PROTOTYPES\nBool glXJoinSwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint group);\nBool glXBindSwapBarrierNV (Display *dpy, GLuint group, GLuint barrier);\nBool glXQuerySwapGroupNV (Display *dpy, GLXDrawable drawable, GLuint *group, GLuint *barrier);\nBool glXQueryMaxSwapGroupsNV (Display *dpy, int screen, GLuint *maxGroups, GLuint *maxBarriers);\nBool glXQueryFrameCountNV (Display *dpy, int screen, GLuint *count);\nBool glXResetFrameCountNV (Display *dpy, int screen);\n#endif\n#endif /* GLX_NV_swap_group */\n\n#ifndef GLX_NV_video_capture\n#define GLX_NV_video_capture 1\ntypedef XID GLXVideoCaptureDeviceNV;\n#define GLX_DEVICE_ID_NV                  0x20CD\n#define GLX_UNIQUE_ID_NV                  0x20CE\n#define GLX_NUM_VIDEO_CAPTURE_SLOTS_NV    0x20CF\ntypedef int ( *PFNGLXBINDVIDEOCAPTUREDEVICENVPROC) (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device);\ntypedef GLXVideoCaptureDeviceNV *( *PFNGLXENUMERATEVIDEOCAPTUREDEVICESNVPROC) (Display *dpy, int screen, int *nelements);\ntypedef void ( *PFNGLXLOCKVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device);\ntypedef int ( *PFNGLXQUERYVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value);\ntypedef void ( *PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display *dpy, GLXVideoCaptureDeviceNV device);\n#ifdef GLX_GLXEXT_PROTOTYPES\nint glXBindVideoCaptureDeviceNV (Display *dpy, unsigned int video_capture_slot, GLXVideoCaptureDeviceNV device);\nGLXVideoCaptureDeviceNV *glXEnumerateVideoCaptureDevicesNV (Display *dpy, int screen, int *nelements);\nvoid glXLockVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device);\nint glXQueryVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device, int attribute, int *value);\nvoid glXReleaseVideoCaptureDeviceNV (Display *dpy, GLXVideoCaptureDeviceNV device);\n#endif\n#endif /* GLX_NV_video_capture */\n\n#ifndef GLX_NV_video_out\n#define GLX_NV_video_out 1\ntypedef unsigned int GLXVideoDeviceNV;\n#define GLX_VIDEO_OUT_COLOR_NV            0x20C3\n#define GLX_VIDEO_OUT_ALPHA_NV            0x20C4\n#define GLX_VIDEO_OUT_DEPTH_NV            0x20C5\n#define GLX_VIDEO_OUT_COLOR_AND_ALPHA_NV  0x20C6\n#define GLX_VIDEO_OUT_COLOR_AND_DEPTH_NV  0x20C7\n#define GLX_VIDEO_OUT_FRAME_NV            0x20C8\n#define GLX_VIDEO_OUT_FIELD_1_NV          0x20C9\n#define GLX_VIDEO_OUT_FIELD_2_NV          0x20CA\n#define GLX_VIDEO_OUT_STACKED_FIELDS_1_2_NV 0x20CB\n#define GLX_VIDEO_OUT_STACKED_FIELDS_2_1_NV 0x20CC\ntypedef int ( *PFNGLXGETVIDEODEVICENVPROC) (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice);\ntypedef int ( *PFNGLXRELEASEVIDEODEVICENVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice);\ntypedef int ( *PFNGLXBINDVIDEOIMAGENVPROC) (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer);\ntypedef int ( *PFNGLXRELEASEVIDEOIMAGENVPROC) (Display *dpy, GLXPbuffer pbuf);\ntypedef int ( *PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock);\ntypedef int ( *PFNGLXGETVIDEOINFONVPROC) (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);\n#ifdef GLX_GLXEXT_PROTOTYPES\nint glXGetVideoDeviceNV (Display *dpy, int screen, int numVideoDevices, GLXVideoDeviceNV *pVideoDevice);\nint glXReleaseVideoDeviceNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice);\nint glXBindVideoImageNV (Display *dpy, GLXVideoDeviceNV VideoDevice, GLXPbuffer pbuf, int iVideoBuffer);\nint glXReleaseVideoImageNV (Display *dpy, GLXPbuffer pbuf);\nint glXSendPbufferToVideoNV (Display *dpy, GLXPbuffer pbuf, int iBufferType, unsigned long *pulCounterPbuffer, GLboolean bBlock);\nint glXGetVideoInfoNV (Display *dpy, int screen, GLXVideoDeviceNV VideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);\n#endif\n#endif /* GLX_NV_video_out */\n\n#ifndef GLX_OML_swap_method\n#define GLX_OML_swap_method 1\n#define GLX_SWAP_METHOD_OML               0x8060\n#define GLX_SWAP_EXCHANGE_OML             0x8061\n#define GLX_SWAP_COPY_OML                 0x8062\n#define GLX_SWAP_UNDEFINED_OML            0x8063\n#endif /* GLX_OML_swap_method */\n\n#ifndef GLX_OML_sync_control\n#define GLX_OML_sync_control 1\n#ifndef GLEXT_64_TYPES_DEFINED\n/* This code block is duplicated in glext.h, so must be protected */\n#define GLEXT_64_TYPES_DEFINED\n/* Define int32_t, int64_t, and uint64_t types for UST/MSC */\n/* (as used in the GLX_OML_sync_control extension). */\n#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L\n#include <inttypes.h>\n#elif defined(__sun__) || defined(__digital__)\n#include <inttypes.h>\n#if defined(__STDC__)\n#if defined(__arch64__) || defined(_LP64)\ntypedef long int int64_t;\ntypedef unsigned long int uint64_t;\n#else\ntypedef long long int int64_t;\ntypedef unsigned long long int uint64_t;\n#endif /* __arch64__ */\n#endif /* __STDC__ */\n#elif defined( __VMS ) || defined(__sgi)\n#include <inttypes.h>\n#elif defined(__SCO__) || defined(__USLC__)\n#include <stdint.h>\n#elif defined(__UNIXOS2__) || defined(__SOL64__)\ntypedef long int int32_t;\ntypedef long long int int64_t;\ntypedef unsigned long long int uint64_t;\n#elif defined(_WIN32) && defined(__GNUC__)\n#include <stdint.h>\n#elif defined(_WIN32)\ntypedef __int32 int32_t;\ntypedef __int64 int64_t;\ntypedef unsigned __int64 uint64_t;\n#else\n/* Fallback if nothing above works */\n#include <inttypes.h>\n#endif\n#endif\ntypedef Bool ( *PFNGLXGETSYNCVALUESOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);\ntypedef Bool ( *PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);\ntypedef int64_t ( *PFNGLXSWAPBUFFERSMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder);\ntypedef Bool ( *PFNGLXWAITFORMSCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);\ntypedef Bool ( *PFNGLXWAITFORSBCOMLPROC) (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);\n#ifdef GLX_GLXEXT_PROTOTYPES\nBool glXGetSyncValuesOML (Display *dpy, GLXDrawable drawable, int64_t *ust, int64_t *msc, int64_t *sbc);\nBool glXGetMscRateOML (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);\nint64_t glXSwapBuffersMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder);\nBool glXWaitForMscOML (Display *dpy, GLXDrawable drawable, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);\nBool glXWaitForSbcOML (Display *dpy, GLXDrawable drawable, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc);\n#endif\n#endif /* GLX_OML_sync_control */\n\n#ifndef GLX_SGIS_blended_overlay\n#define GLX_SGIS_blended_overlay 1\n#define GLX_BLENDED_RGBA_SGIS             0x8025\n#endif /* GLX_SGIS_blended_overlay */\n\n#ifndef GLX_SGIS_multisample\n#define GLX_SGIS_multisample 1\n#define GLX_SAMPLE_BUFFERS_SGIS           100000\n#define GLX_SAMPLES_SGIS                  100001\n#endif /* GLX_SGIS_multisample */\n\n#ifndef GLX_SGIS_shared_multisample\n#define GLX_SGIS_shared_multisample 1\n#define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026\n#define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027\n#endif /* GLX_SGIS_shared_multisample */\n\n#ifndef GLX_SGIX_dmbuffer\n#define GLX_SGIX_dmbuffer 1\ntypedef XID GLXPbufferSGIX;\n#ifdef _DM_BUFFER_H_\n#define GLX_DIGITAL_MEDIA_PBUFFER_SGIX    0x8024\ntypedef Bool ( *PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer);\n#ifdef GLX_GLXEXT_PROTOTYPES\nBool glXAssociateDMPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer);\n#endif\n#endif /* _DM_BUFFER_H_ */\n#endif /* GLX_SGIX_dmbuffer */\n\n#ifndef GLX_SGIX_fbconfig\n#define GLX_SGIX_fbconfig 1\ntypedef struct __GLXFBConfigRec *GLXFBConfigSGIX;\n#define GLX_WINDOW_BIT_SGIX               0x00000001\n#define GLX_PIXMAP_BIT_SGIX               0x00000002\n#define GLX_RGBA_BIT_SGIX                 0x00000001\n#define GLX_COLOR_INDEX_BIT_SGIX          0x00000002\n#define GLX_DRAWABLE_TYPE_SGIX            0x8010\n#define GLX_RENDER_TYPE_SGIX              0x8011\n#define GLX_X_RENDERABLE_SGIX             0x8012\n#define GLX_FBCONFIG_ID_SGIX              0x8013\n#define GLX_RGBA_TYPE_SGIX                0x8014\n#define GLX_COLOR_INDEX_TYPE_SGIX         0x8015\ntypedef int ( *PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value);\ntypedef GLXFBConfigSGIX *( *PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements);\ntypedef GLXPixmap ( *PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap);\ntypedef GLXContext ( *PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct);\ntypedef XVisualInfo *( *PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config);\ntypedef GLXFBConfigSGIX ( *PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) (Display *dpy, XVisualInfo *vis);\n#ifdef GLX_GLXEXT_PROTOTYPES\nint glXGetFBConfigAttribSGIX (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value);\nGLXFBConfigSGIX *glXChooseFBConfigSGIX (Display *dpy, int screen, int *attrib_list, int *nelements);\nGLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap);\nGLXContext glXCreateContextWithConfigSGIX (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct);\nXVisualInfo *glXGetVisualFromFBConfigSGIX (Display *dpy, GLXFBConfigSGIX config);\nGLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *dpy, XVisualInfo *vis);\n#endif\n#endif /* GLX_SGIX_fbconfig */\n\n#ifndef GLX_SGIX_hyperpipe\n#define GLX_SGIX_hyperpipe 1\ntypedef struct {\n    char    pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */\n    int     networkId;\n} GLXHyperpipeNetworkSGIX;\ntypedef struct {\n    char    pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */\n    int     channel;\n    unsigned int participationType;\n    int     timeSlice;\n} GLXHyperpipeConfigSGIX;\ntypedef struct {\n    char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */\n    int srcXOrigin, srcYOrigin, srcWidth, srcHeight;\n    int destXOrigin, destYOrigin, destWidth, destHeight;\n} GLXPipeRect;\ntypedef struct {\n    char pipeName[80]; /* Should be [GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX] */\n    int XOrigin, YOrigin, maxHeight, maxWidth;\n} GLXPipeRectLimits;\n#define GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX 80\n#define GLX_BAD_HYPERPIPE_CONFIG_SGIX     91\n#define GLX_BAD_HYPERPIPE_SGIX            92\n#define GLX_HYPERPIPE_DISPLAY_PIPE_SGIX   0x00000001\n#define GLX_HYPERPIPE_RENDER_PIPE_SGIX    0x00000002\n#define GLX_PIPE_RECT_SGIX                0x00000001\n#define GLX_PIPE_RECT_LIMITS_SGIX         0x00000002\n#define GLX_HYPERPIPE_STEREO_SGIX         0x00000003\n#define GLX_HYPERPIPE_PIXEL_AVERAGE_SGIX  0x00000004\n#define GLX_HYPERPIPE_ID_SGIX             0x8030\ntypedef GLXHyperpipeNetworkSGIX *( *PFNGLXQUERYHYPERPIPENETWORKSGIXPROC) (Display *dpy, int *npipes);\ntypedef int ( *PFNGLXHYPERPIPECONFIGSGIXPROC) (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId);\ntypedef GLXHyperpipeConfigSGIX *( *PFNGLXQUERYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId, int *npipes);\ntypedef int ( *PFNGLXDESTROYHYPERPIPECONFIGSGIXPROC) (Display *dpy, int hpId);\ntypedef int ( *PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId);\ntypedef int ( *PFNGLXQUERYHYPERPIPEBESTATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList);\ntypedef int ( *PFNGLXHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *attribList);\ntypedef int ( *PFNGLXQUERYHYPERPIPEATTRIBSGIXPROC) (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList);\n#ifdef GLX_GLXEXT_PROTOTYPES\nGLXHyperpipeNetworkSGIX *glXQueryHyperpipeNetworkSGIX (Display *dpy, int *npipes);\nint glXHyperpipeConfigSGIX (Display *dpy, int networkId, int npipes, GLXHyperpipeConfigSGIX *cfg, int *hpId);\nGLXHyperpipeConfigSGIX *glXQueryHyperpipeConfigSGIX (Display *dpy, int hpId, int *npipes);\nint glXDestroyHyperpipeConfigSGIX (Display *dpy, int hpId);\nint glXBindHyperpipeSGIX (Display *dpy, int hpId);\nint glXQueryHyperpipeBestAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList, void *returnAttribList);\nint glXHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *attribList);\nint glXQueryHyperpipeAttribSGIX (Display *dpy, int timeSlice, int attrib, int size, void *returnAttribList);\n#endif\n#endif /* GLX_SGIX_hyperpipe */\n\n#ifndef GLX_SGIX_pbuffer\n#define GLX_SGIX_pbuffer 1\n#define GLX_PBUFFER_BIT_SGIX              0x00000004\n#define GLX_BUFFER_CLOBBER_MASK_SGIX      0x08000000\n#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX    0x00000001\n#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX   0x00000002\n#define GLX_BACK_LEFT_BUFFER_BIT_SGIX     0x00000004\n#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX    0x00000008\n#define GLX_AUX_BUFFERS_BIT_SGIX          0x00000010\n#define GLX_DEPTH_BUFFER_BIT_SGIX         0x00000020\n#define GLX_STENCIL_BUFFER_BIT_SGIX       0x00000040\n#define GLX_ACCUM_BUFFER_BIT_SGIX         0x00000080\n#define GLX_SAMPLE_BUFFERS_BIT_SGIX       0x00000100\n#define GLX_MAX_PBUFFER_WIDTH_SGIX        0x8016\n#define GLX_MAX_PBUFFER_HEIGHT_SGIX       0x8017\n#define GLX_MAX_PBUFFER_PIXELS_SGIX       0x8018\n#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX    0x8019\n#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX   0x801A\n#define GLX_PRESERVED_CONTENTS_SGIX       0x801B\n#define GLX_LARGEST_PBUFFER_SGIX          0x801C\n#define GLX_WIDTH_SGIX                    0x801D\n#define GLX_HEIGHT_SGIX                   0x801E\n#define GLX_EVENT_MASK_SGIX               0x801F\n#define GLX_DAMAGED_SGIX                  0x8020\n#define GLX_SAVED_SGIX                    0x8021\n#define GLX_WINDOW_SGIX                   0x8022\n#define GLX_PBUFFER_SGIX                  0x8023\ntypedef GLXPbufferSGIX ( *PFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list);\ntypedef void ( *PFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf);\ntypedef void ( *PFNGLXQUERYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value);\ntypedef void ( *PFNGLXSELECTEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long mask);\ntypedef void ( *PFNGLXGETSELECTEDEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long *mask);\n#ifdef GLX_GLXEXT_PROTOTYPES\nGLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list);\nvoid glXDestroyGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf);\nvoid glXQueryGLXPbufferSGIX (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value);\nvoid glXSelectEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long mask);\nvoid glXGetSelectedEventSGIX (Display *dpy, GLXDrawable drawable, unsigned long *mask);\n#endif\n#endif /* GLX_SGIX_pbuffer */\n\n#ifndef GLX_SGIX_swap_barrier\n#define GLX_SGIX_swap_barrier 1\ntypedef void ( *PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier);\ntypedef Bool ( *PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max);\n#ifdef GLX_GLXEXT_PROTOTYPES\nvoid glXBindSwapBarrierSGIX (Display *dpy, GLXDrawable drawable, int barrier);\nBool glXQueryMaxSwapBarriersSGIX (Display *dpy, int screen, int *max);\n#endif\n#endif /* GLX_SGIX_swap_barrier */\n\n#ifndef GLX_SGIX_swap_group\n#define GLX_SGIX_swap_group 1\ntypedef void ( *PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member);\n#ifdef GLX_GLXEXT_PROTOTYPES\nvoid glXJoinSwapGroupSGIX (Display *dpy, GLXDrawable drawable, GLXDrawable member);\n#endif\n#endif /* GLX_SGIX_swap_group */\n\n#ifndef GLX_SGIX_video_resize\n#define GLX_SGIX_video_resize 1\n#define GLX_SYNC_FRAME_SGIX               0x00000000\n#define GLX_SYNC_SWAP_SGIX                0x00000001\ntypedef int ( *PFNGLXBINDCHANNELTOWINDOWSGIXPROC) (Display *display, int screen, int channel, Window window);\ntypedef int ( *PFNGLXCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int x, int y, int w, int h);\ntypedef int ( *PFNGLXQUERYCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh);\ntypedef int ( *PFNGLXQUERYCHANNELDELTASSGIXPROC) (Display *display, int screen, int channel, int *x, int *y, int *w, int *h);\ntypedef int ( *PFNGLXCHANNELRECTSYNCSGIXPROC) (Display *display, int screen, int channel, GLenum synctype);\n#ifdef GLX_GLXEXT_PROTOTYPES\nint glXBindChannelToWindowSGIX (Display *display, int screen, int channel, Window window);\nint glXChannelRectSGIX (Display *display, int screen, int channel, int x, int y, int w, int h);\nint glXQueryChannelRectSGIX (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh);\nint glXQueryChannelDeltasSGIX (Display *display, int screen, int channel, int *x, int *y, int *w, int *h);\nint glXChannelRectSyncSGIX (Display *display, int screen, int channel, GLenum synctype);\n#endif\n#endif /* GLX_SGIX_video_resize */\n\n#ifndef GLX_SGIX_video_source\n#define GLX_SGIX_video_source 1\ntypedef XID GLXVideoSourceSGIX;\n#ifdef _VL_H\ntypedef GLXVideoSourceSGIX ( *PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode);\ntypedef void ( *PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource);\n#ifdef GLX_GLXEXT_PROTOTYPES\nGLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode);\nvoid glXDestroyGLXVideoSourceSGIX (Display *dpy, GLXVideoSourceSGIX glxvideosource);\n#endif\n#endif /* _VL_H */\n#endif /* GLX_SGIX_video_source */\n\n#ifndef GLX_SGIX_visual_select_group\n#define GLX_SGIX_visual_select_group 1\n#define GLX_VISUAL_SELECT_GROUP_SGIX      0x8028\n#endif /* GLX_SGIX_visual_select_group */\n\n#ifndef GLX_SGI_cushion\n#define GLX_SGI_cushion 1\ntypedef void ( *PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion);\n#ifdef GLX_GLXEXT_PROTOTYPES\nvoid glXCushionSGI (Display *dpy, Window window, float cushion);\n#endif\n#endif /* GLX_SGI_cushion */\n\n#ifndef GLX_SGI_make_current_read\n#define GLX_SGI_make_current_read 1\ntypedef Bool ( *PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);\ntypedef GLXDrawable ( *PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void);\n#ifdef GLX_GLXEXT_PROTOTYPES\nBool glXMakeCurrentReadSGI (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx);\nGLXDrawable glXGetCurrentReadDrawableSGI (void);\n#endif\n#endif /* GLX_SGI_make_current_read */\n\n#ifndef GLX_SGI_swap_control\n#define GLX_SGI_swap_control 1\ntypedef int ( *PFNGLXSWAPINTERVALSGIPROC) (int interval);\n#ifdef GLX_GLXEXT_PROTOTYPES\nint glXSwapIntervalSGI (int interval);\n#endif\n#endif /* GLX_SGI_swap_control */\n\n#ifndef GLX_SGI_video_sync\n#define GLX_SGI_video_sync 1\ntypedef int ( *PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count);\ntypedef int ( *PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count);\n#ifdef GLX_GLXEXT_PROTOTYPES\nint glXGetVideoSyncSGI (unsigned int *count);\nint glXWaitVideoSyncSGI (int divisor, int remainder, unsigned int *count);\n#endif\n#endif /* GLX_SGI_video_sync */\n\n#ifndef GLX_SUN_get_transparent_index\n#define GLX_SUN_get_transparent_index 1\ntypedef Status ( *PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, unsigned long *pTransparentIndex);\n#ifdef GLX_GLXEXT_PROTOTYPES\nStatus glXGetTransparentIndexSUN (Display *dpy, Window overlay, Window underlay, unsigned long *pTransparentIndex);\n#endif\n#endif /* GLX_SUN_get_transparent_index */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/Common/GLInclude/khrplatform.h",
    "content": "#ifndef __khrplatform_h_\n#define __khrplatform_h_\n\n/*\n** Copyright (c) 2008-2018 The Khronos Group Inc.\n**\n** Permission is hereby granted, free of charge, to any person obtaining a\n** copy of this software and/or associated documentation files (the\n** \"Materials\"), to deal in the Materials without restriction, including\n** without limitation the rights to use, copy, modify, merge, publish,\n** distribute, sublicense, and/or sell copies of the Materials, and to\n** permit persons to whom the Materials are furnished to do so, subject to\n** the following conditions:\n**\n** The above copyright notice and this permission notice shall be included\n** in all copies or substantial portions of the Materials.\n**\n** THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.\n*/\n\n/* Khronos platform-specific types and definitions.\n *\n * The master copy of khrplatform.h is maintained in the Khronos EGL\n * Registry repository at https://github.com/KhronosGroup/EGL-Registry\n * The last semantic modification to khrplatform.h was at commit ID:\n *      67a3e0864c2d75ea5287b9f3d2eb74a745936692\n *\n * Adopters may modify this file to suit their platform. Adopters are\n * encouraged to submit platform specific modifications to the Khronos\n * group so that they can be included in future versions of this file.\n * Please submit changes by filing pull requests or issues on\n * the EGL Registry repository linked above.\n *\n *\n * See the Implementer's Guidelines for information about where this file\n * should be located on your system and for more details of its use:\n *    http://www.khronos.org/registry/implementers_guide.pdf\n *\n * This file should be included as\n *        #include <KHR/khrplatform.h>\n * by Khronos client API header files that use its types and defines.\n *\n * The types in khrplatform.h should only be used to define API-specific types.\n *\n * Types defined in khrplatform.h:\n *    khronos_int8_t              signed   8  bit\n *    khronos_uint8_t             unsigned 8  bit\n *    khronos_int16_t             signed   16 bit\n *    khronos_uint16_t            unsigned 16 bit\n *    khronos_int32_t             signed   32 bit\n *    khronos_uint32_t            unsigned 32 bit\n *    khronos_int64_t             signed   64 bit\n *    khronos_uint64_t            unsigned 64 bit\n *    khronos_intptr_t            signed   same number of bits as a pointer\n *    khronos_uintptr_t           unsigned same number of bits as a pointer\n *    khronos_ssize_t             signed   size\n *    khronos_usize_t             unsigned size\n *    khronos_float_t             signed   32 bit floating point\n *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds\n *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in\n *                                         nanoseconds\n *    khronos_stime_nanoseconds_t signed time interval in nanoseconds\n *    khronos_boolean_enum_t      enumerated boolean type. This should\n *      only be used as a base type when a client API's boolean type is\n *      an enum. Client APIs which use an integer or other type for\n *      booleans cannot use this as the base type for their boolean.\n *\n * Tokens defined in khrplatform.h:\n *\n *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.\n *\n *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.\n *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.\n *\n * Calling convention macros defined in this file:\n *    KHRONOS_APICALL\n *    KHRONOS_APIENTRY\n *    KHRONOS_APIATTRIBUTES\n *\n * These may be used in function prototypes as:\n *\n *      KHRONOS_APICALL void KHRONOS_APIENTRY funcname(\n *                                  int arg1,\n *                                  int arg2) KHRONOS_APIATTRIBUTES;\n */\n\n#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)\n#   define KHRONOS_STATIC 1\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APICALL\n *-------------------------------------------------------------------------\n * This precedes the return type of the function in the function prototype.\n */\n#if defined(KHRONOS_STATIC)\n    /* If the preprocessor constant KHRONOS_STATIC is defined, make the\n     * header compatible with static linking. */\n#   define KHRONOS_APICALL\n#elif defined(_WIN32)\n#   define KHRONOS_APICALL __declspec(dllimport)\n#elif defined (__SYMBIAN32__)\n#   define KHRONOS_APICALL IMPORT_C\n#elif defined(__ANDROID__)\n#   define KHRONOS_APICALL __attribute__((visibility(\"default\")))\n#else\n#   define KHRONOS_APICALL\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APIENTRY\n *-------------------------------------------------------------------------\n * This follows the return type of the function  and precedes the function\n * name in the function prototype.\n */\n#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)\n    /* Win32 but not WinCE */\n#   define KHRONOS_APIENTRY __stdcall\n#else\n#   define KHRONOS_APIENTRY\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APIATTRIBUTES\n *-------------------------------------------------------------------------\n * This follows the closing parenthesis of the function prototype arguments.\n */\n#if defined (__ARMCC_2__)\n#define KHRONOS_APIATTRIBUTES __softfp\n#else\n#define KHRONOS_APIATTRIBUTES\n#endif\n\n/*-------------------------------------------------------------------------\n * basic type definitions\n *-----------------------------------------------------------------------*/\n#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)\n\n\n/*\n * Using <stdint.h>\n */\n#include <stdint.h>\ntypedef int32_t                 khronos_int32_t;\ntypedef uint32_t                khronos_uint32_t;\ntypedef int64_t                 khronos_int64_t;\ntypedef uint64_t                khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n/*\n * To support platform where unsigned long cannot be used interchangeably with\n * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.\n * Ideally, we could just use (u)intptr_t everywhere, but this could result in\n * ABI breakage if khronos_uintptr_t is changed from unsigned long to\n * unsigned long long or similar (this results in different C++ name mangling).\n * To avoid changes for existing platforms, we restrict usage of intptr_t to\n * platforms where the size of a pointer is larger than the size of long.\n */\n#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)\n#if __SIZEOF_POINTER__ > __SIZEOF_LONG__\n#define KHRONOS_USE_INTPTR_T\n#endif\n#endif\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 KHRONOS_USE_INTPTR_T\ntypedef intptr_t               khronos_intptr_t;\ntypedef uintptr_t              khronos_uintptr_t;\n#elif defined(_WIN64)\ntypedef signed   long long int khronos_intptr_t;\ntypedef unsigned long long int khronos_uintptr_t;\n#else\ntypedef signed   long  int     khronos_intptr_t;\ntypedef unsigned long  int     khronos_uintptr_t;\n#endif\n\n#if defined(_WIN64)\ntypedef signed   long long int khronos_ssize_t;\ntypedef unsigned long long int khronos_usize_t;\n#else\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": "src/Common/GLInclude/wglext.h",
    "content": "#ifndef __wgl_wglext_h_\n#define __wgl_wglext_h_ 1\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*\n** Copyright 2013-2020 The Khronos Group Inc.\n** SPDX-License-Identifier: MIT\n**\n** This header is generated from the Khronos OpenGL / OpenGL ES XML\n** API Registry. The current version of the Registry, generator scripts\n** used to make the header, and the header can be found at\n**   https://github.com/KhronosGroup/OpenGL-Registry\n*/\n\n#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)\n#define WIN32_LEAN_AND_MEAN 1\n#include <windows.h>\n#endif\n\n#define WGL_WGLEXT_VERSION 20211115\n\n/* Generated C header for:\n * API: wgl\n * Versions considered: .*\n * Versions emitted: _nomatch_^\n * Default extensions included: wgl\n * Additional extensions included: _nomatch_^\n * Extensions removed: _nomatch_^\n */\n\n#ifndef WGL_ARB_buffer_region\n#define WGL_ARB_buffer_region 1\n#define WGL_FRONT_COLOR_BUFFER_BIT_ARB    0x00000001\n#define WGL_BACK_COLOR_BUFFER_BIT_ARB     0x00000002\n#define WGL_DEPTH_BUFFER_BIT_ARB          0x00000004\n#define WGL_STENCIL_BUFFER_BIT_ARB        0x00000008\ntypedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType);\ntypedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion);\ntypedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height);\ntypedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc);\n#ifdef WGL_WGLEXT_PROTOTYPES\nHANDLE WINAPI wglCreateBufferRegionARB (HDC hDC, int iLayerPlane, UINT uType);\nVOID WINAPI wglDeleteBufferRegionARB (HANDLE hRegion);\nBOOL WINAPI wglSaveBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height);\nBOOL WINAPI wglRestoreBufferRegionARB (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc);\n#endif\n#endif /* WGL_ARB_buffer_region */\n\n#ifndef WGL_ARB_context_flush_control\n#define WGL_ARB_context_flush_control 1\n#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB  0x2097\n#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0\n#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098\n#endif /* WGL_ARB_context_flush_control */\n\n#ifndef WGL_ARB_create_context\n#define WGL_ARB_create_context 1\n#define WGL_CONTEXT_DEBUG_BIT_ARB         0x00000001\n#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002\n#define WGL_CONTEXT_MAJOR_VERSION_ARB     0x2091\n#define WGL_CONTEXT_MINOR_VERSION_ARB     0x2092\n#define WGL_CONTEXT_LAYER_PLANE_ARB       0x2093\n#define WGL_CONTEXT_FLAGS_ARB             0x2094\n#define ERROR_INVALID_VERSION_ARB         0x2095\ntypedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);\n#ifdef WGL_WGLEXT_PROTOTYPES\nHGLRC WINAPI wglCreateContextAttribsARB (HDC hDC, HGLRC hShareContext, const int *attribList);\n#endif\n#endif /* WGL_ARB_create_context */\n\n#ifndef WGL_ARB_create_context_no_error\n#define WGL_ARB_create_context_no_error 1\n#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB   0x31B3\n#endif /* WGL_ARB_create_context_no_error */\n\n#ifndef WGL_ARB_create_context_profile\n#define WGL_ARB_create_context_profile 1\n#define WGL_CONTEXT_PROFILE_MASK_ARB      0x9126\n#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB  0x00000001\n#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002\n#define ERROR_INVALID_PROFILE_ARB         0x2096\n#endif /* WGL_ARB_create_context_profile */\n\n#ifndef WGL_ARB_create_context_robustness\n#define WGL_ARB_create_context_robustness 1\n#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004\n#define WGL_LOSE_CONTEXT_ON_RESET_ARB     0x8252\n#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256\n#define WGL_NO_RESET_NOTIFICATION_ARB     0x8261\n#endif /* WGL_ARB_create_context_robustness */\n\n#ifndef WGL_ARB_extensions_string\n#define WGL_ARB_extensions_string 1\ntypedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc);\n#ifdef WGL_WGLEXT_PROTOTYPES\nconst char *WINAPI wglGetExtensionsStringARB (HDC hdc);\n#endif\n#endif /* WGL_ARB_extensions_string */\n\n#ifndef WGL_ARB_framebuffer_sRGB\n#define WGL_ARB_framebuffer_sRGB 1\n#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB  0x20A9\n#endif /* WGL_ARB_framebuffer_sRGB */\n\n#ifndef WGL_ARB_make_current_read\n#define WGL_ARB_make_current_read 1\n#define ERROR_INVALID_PIXEL_TYPE_ARB      0x2043\n#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054\ntypedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);\ntypedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglMakeContextCurrentARB (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);\nHDC WINAPI wglGetCurrentReadDCARB (void);\n#endif\n#endif /* WGL_ARB_make_current_read */\n\n#ifndef WGL_ARB_multisample\n#define WGL_ARB_multisample 1\n#define WGL_SAMPLE_BUFFERS_ARB            0x2041\n#define WGL_SAMPLES_ARB                   0x2042\n#endif /* WGL_ARB_multisample */\n\n#ifndef WGL_ARB_pbuffer\n#define WGL_ARB_pbuffer 1\nDECLARE_HANDLE(HPBUFFERARB);\n#define WGL_DRAW_TO_PBUFFER_ARB           0x202D\n#define WGL_MAX_PBUFFER_PIXELS_ARB        0x202E\n#define WGL_MAX_PBUFFER_WIDTH_ARB         0x202F\n#define WGL_MAX_PBUFFER_HEIGHT_ARB        0x2030\n#define WGL_PBUFFER_LARGEST_ARB           0x2033\n#define WGL_PBUFFER_WIDTH_ARB             0x2034\n#define WGL_PBUFFER_HEIGHT_ARB            0x2035\n#define WGL_PBUFFER_LOST_ARB              0x2036\ntypedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);\ntypedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer);\ntypedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC);\ntypedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer);\ntypedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue);\n#ifdef WGL_WGLEXT_PROTOTYPES\nHPBUFFERARB WINAPI wglCreatePbufferARB (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);\nHDC WINAPI wglGetPbufferDCARB (HPBUFFERARB hPbuffer);\nint WINAPI wglReleasePbufferDCARB (HPBUFFERARB hPbuffer, HDC hDC);\nBOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB hPbuffer);\nBOOL WINAPI wglQueryPbufferARB (HPBUFFERARB hPbuffer, int iAttribute, int *piValue);\n#endif\n#endif /* WGL_ARB_pbuffer */\n\n#ifndef WGL_ARB_pixel_format\n#define WGL_ARB_pixel_format 1\n#define WGL_NUMBER_PIXEL_FORMATS_ARB      0x2000\n#define WGL_DRAW_TO_WINDOW_ARB            0x2001\n#define WGL_DRAW_TO_BITMAP_ARB            0x2002\n#define WGL_ACCELERATION_ARB              0x2003\n#define WGL_NEED_PALETTE_ARB              0x2004\n#define WGL_NEED_SYSTEM_PALETTE_ARB       0x2005\n#define WGL_SWAP_LAYER_BUFFERS_ARB        0x2006\n#define WGL_SWAP_METHOD_ARB               0x2007\n#define WGL_NUMBER_OVERLAYS_ARB           0x2008\n#define WGL_NUMBER_UNDERLAYS_ARB          0x2009\n#define WGL_TRANSPARENT_ARB               0x200A\n#define WGL_TRANSPARENT_RED_VALUE_ARB     0x2037\n#define WGL_TRANSPARENT_GREEN_VALUE_ARB   0x2038\n#define WGL_TRANSPARENT_BLUE_VALUE_ARB    0x2039\n#define WGL_TRANSPARENT_ALPHA_VALUE_ARB   0x203A\n#define WGL_TRANSPARENT_INDEX_VALUE_ARB   0x203B\n#define WGL_SHARE_DEPTH_ARB               0x200C\n#define WGL_SHARE_STENCIL_ARB             0x200D\n#define WGL_SHARE_ACCUM_ARB               0x200E\n#define WGL_SUPPORT_GDI_ARB               0x200F\n#define WGL_SUPPORT_OPENGL_ARB            0x2010\n#define WGL_DOUBLE_BUFFER_ARB             0x2011\n#define WGL_STEREO_ARB                    0x2012\n#define WGL_PIXEL_TYPE_ARB                0x2013\n#define WGL_COLOR_BITS_ARB                0x2014\n#define WGL_RED_BITS_ARB                  0x2015\n#define WGL_RED_SHIFT_ARB                 0x2016\n#define WGL_GREEN_BITS_ARB                0x2017\n#define WGL_GREEN_SHIFT_ARB               0x2018\n#define WGL_BLUE_BITS_ARB                 0x2019\n#define WGL_BLUE_SHIFT_ARB                0x201A\n#define WGL_ALPHA_BITS_ARB                0x201B\n#define WGL_ALPHA_SHIFT_ARB               0x201C\n#define WGL_ACCUM_BITS_ARB                0x201D\n#define WGL_ACCUM_RED_BITS_ARB            0x201E\n#define WGL_ACCUM_GREEN_BITS_ARB          0x201F\n#define WGL_ACCUM_BLUE_BITS_ARB           0x2020\n#define WGL_ACCUM_ALPHA_BITS_ARB          0x2021\n#define WGL_DEPTH_BITS_ARB                0x2022\n#define WGL_STENCIL_BITS_ARB              0x2023\n#define WGL_AUX_BUFFERS_ARB               0x2024\n#define WGL_NO_ACCELERATION_ARB           0x2025\n#define WGL_GENERIC_ACCELERATION_ARB      0x2026\n#define WGL_FULL_ACCELERATION_ARB         0x2027\n#define WGL_SWAP_EXCHANGE_ARB             0x2028\n#define WGL_SWAP_COPY_ARB                 0x2029\n#define WGL_SWAP_UNDEFINED_ARB            0x202A\n#define WGL_TYPE_RGBA_ARB                 0x202B\n#define WGL_TYPE_COLORINDEX_ARB           0x202C\ntypedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);\ntypedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);\ntypedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglGetPixelFormatAttribivARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);\nBOOL WINAPI wglGetPixelFormatAttribfvARB (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);\nBOOL WINAPI wglChoosePixelFormatARB (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);\n#endif\n#endif /* WGL_ARB_pixel_format */\n\n#ifndef WGL_ARB_pixel_format_float\n#define WGL_ARB_pixel_format_float 1\n#define WGL_TYPE_RGBA_FLOAT_ARB           0x21A0\n#endif /* WGL_ARB_pixel_format_float */\n\n#ifndef WGL_ARB_render_texture\n#define WGL_ARB_render_texture 1\n#define WGL_BIND_TO_TEXTURE_RGB_ARB       0x2070\n#define WGL_BIND_TO_TEXTURE_RGBA_ARB      0x2071\n#define WGL_TEXTURE_FORMAT_ARB            0x2072\n#define WGL_TEXTURE_TARGET_ARB            0x2073\n#define WGL_MIPMAP_TEXTURE_ARB            0x2074\n#define WGL_TEXTURE_RGB_ARB               0x2075\n#define WGL_TEXTURE_RGBA_ARB              0x2076\n#define WGL_NO_TEXTURE_ARB                0x2077\n#define WGL_TEXTURE_CUBE_MAP_ARB          0x2078\n#define WGL_TEXTURE_1D_ARB                0x2079\n#define WGL_TEXTURE_2D_ARB                0x207A\n#define WGL_MIPMAP_LEVEL_ARB              0x207B\n#define WGL_CUBE_MAP_FACE_ARB             0x207C\n#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D\n#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E\n#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F\n#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080\n#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081\n#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082\n#define WGL_FRONT_LEFT_ARB                0x2083\n#define WGL_FRONT_RIGHT_ARB               0x2084\n#define WGL_BACK_LEFT_ARB                 0x2085\n#define WGL_BACK_RIGHT_ARB                0x2086\n#define WGL_AUX0_ARB                      0x2087\n#define WGL_AUX1_ARB                      0x2088\n#define WGL_AUX2_ARB                      0x2089\n#define WGL_AUX3_ARB                      0x208A\n#define WGL_AUX4_ARB                      0x208B\n#define WGL_AUX5_ARB                      0x208C\n#define WGL_AUX6_ARB                      0x208D\n#define WGL_AUX7_ARB                      0x208E\n#define WGL_AUX8_ARB                      0x208F\n#define WGL_AUX9_ARB                      0x2090\ntypedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);\ntypedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer);\ntypedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int *piAttribList);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglBindTexImageARB (HPBUFFERARB hPbuffer, int iBuffer);\nBOOL WINAPI wglReleaseTexImageARB (HPBUFFERARB hPbuffer, int iBuffer);\nBOOL WINAPI wglSetPbufferAttribARB (HPBUFFERARB hPbuffer, const int *piAttribList);\n#endif\n#endif /* WGL_ARB_render_texture */\n\n#ifndef WGL_ARB_robustness_application_isolation\n#define WGL_ARB_robustness_application_isolation 1\n#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008\n#endif /* WGL_ARB_robustness_application_isolation */\n\n#ifndef WGL_ARB_robustness_share_group_isolation\n#define WGL_ARB_robustness_share_group_isolation 1\n#endif /* WGL_ARB_robustness_share_group_isolation */\n\n#ifndef WGL_3DFX_multisample\n#define WGL_3DFX_multisample 1\n#define WGL_SAMPLE_BUFFERS_3DFX           0x2060\n#define WGL_SAMPLES_3DFX                  0x2061\n#endif /* WGL_3DFX_multisample */\n\n#ifndef WGL_3DL_stereo_control\n#define WGL_3DL_stereo_control 1\n#define WGL_STEREO_EMITTER_ENABLE_3DL     0x2055\n#define WGL_STEREO_EMITTER_DISABLE_3DL    0x2056\n#define WGL_STEREO_POLARITY_NORMAL_3DL    0x2057\n#define WGL_STEREO_POLARITY_INVERT_3DL    0x2058\ntypedef BOOL (WINAPI * PFNWGLSETSTEREOEMITTERSTATE3DLPROC) (HDC hDC, UINT uState);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglSetStereoEmitterState3DL (HDC hDC, UINT uState);\n#endif\n#endif /* WGL_3DL_stereo_control */\n\n#ifndef WGL_AMD_gpu_association\n#define WGL_AMD_gpu_association 1\n#define WGL_GPU_VENDOR_AMD                0x1F00\n#define WGL_GPU_RENDERER_STRING_AMD       0x1F01\n#define WGL_GPU_OPENGL_VERSION_STRING_AMD 0x1F02\n#define WGL_GPU_FASTEST_TARGET_GPUS_AMD   0x21A2\n#define WGL_GPU_RAM_AMD                   0x21A3\n#define WGL_GPU_CLOCK_AMD                 0x21A4\n#define WGL_GPU_NUM_PIPES_AMD             0x21A5\n#define WGL_GPU_NUM_SIMD_AMD              0x21A6\n#define WGL_GPU_NUM_RB_AMD                0x21A7\n#define WGL_GPU_NUM_SPI_AMD               0x21A8\ntypedef UINT (WINAPI * PFNWGLGETGPUIDSAMDPROC) (UINT maxCount, UINT *ids);\ntypedef INT (WINAPI * PFNWGLGETGPUINFOAMDPROC) (UINT id, INT property, GLenum dataType, UINT size, void *data);\ntypedef UINT (WINAPI * PFNWGLGETCONTEXTGPUIDAMDPROC) (HGLRC hglrc);\ntypedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTAMDPROC) (UINT id);\ntypedef HGLRC (WINAPI * PFNWGLCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (UINT id, HGLRC hShareContext, const int *attribList);\ntypedef BOOL (WINAPI * PFNWGLDELETEASSOCIATEDCONTEXTAMDPROC) (HGLRC hglrc);\ntypedef BOOL (WINAPI * PFNWGLMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (HGLRC hglrc);\ntypedef HGLRC (WINAPI * PFNWGLGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void);\ntypedef VOID (WINAPI * PFNWGLBLITCONTEXTFRAMEBUFFERAMDPROC) (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\n#ifdef WGL_WGLEXT_PROTOTYPES\nUINT WINAPI wglGetGPUIDsAMD (UINT maxCount, UINT *ids);\nINT WINAPI wglGetGPUInfoAMD (UINT id, INT property, GLenum dataType, UINT size, void *data);\nUINT WINAPI wglGetContextGPUIDAMD (HGLRC hglrc);\nHGLRC WINAPI wglCreateAssociatedContextAMD (UINT id);\nHGLRC WINAPI wglCreateAssociatedContextAttribsAMD (UINT id, HGLRC hShareContext, const int *attribList);\nBOOL WINAPI wglDeleteAssociatedContextAMD (HGLRC hglrc);\nBOOL WINAPI wglMakeAssociatedContextCurrentAMD (HGLRC hglrc);\nHGLRC WINAPI wglGetCurrentAssociatedContextAMD (void);\nVOID WINAPI wglBlitContextFramebufferAMD (HGLRC dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\n#endif\n#endif /* WGL_AMD_gpu_association */\n\n#ifndef WGL_ATI_pixel_format_float\n#define WGL_ATI_pixel_format_float 1\n#define WGL_TYPE_RGBA_FLOAT_ATI           0x21A0\n#endif /* WGL_ATI_pixel_format_float */\n\n#ifndef WGL_ATI_render_texture_rectangle\n#define WGL_ATI_render_texture_rectangle 1\n#define WGL_TEXTURE_RECTANGLE_ATI         0x21A5\n#endif /* WGL_ATI_render_texture_rectangle */\n\n#ifndef WGL_EXT_colorspace\n#define WGL_EXT_colorspace 1\n#define WGL_COLORSPACE_EXT                0x309D\n#define WGL_COLORSPACE_SRGB_EXT           0x3089\n#define WGL_COLORSPACE_LINEAR_EXT         0x308A\n#endif /* WGL_EXT_colorspace */\n\n#ifndef WGL_EXT_create_context_es2_profile\n#define WGL_EXT_create_context_es2_profile 1\n#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT   0x00000004\n#endif /* WGL_EXT_create_context_es2_profile */\n\n#ifndef WGL_EXT_create_context_es_profile\n#define WGL_EXT_create_context_es_profile 1\n#define WGL_CONTEXT_ES_PROFILE_BIT_EXT    0x00000004\n#endif /* WGL_EXT_create_context_es_profile */\n\n#ifndef WGL_EXT_depth_float\n#define WGL_EXT_depth_float 1\n#define WGL_DEPTH_FLOAT_EXT               0x2040\n#endif /* WGL_EXT_depth_float */\n\n#ifndef WGL_EXT_display_color_table\n#define WGL_EXT_display_color_table 1\ntypedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id);\ntypedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length);\ntypedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id);\ntypedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id);\n#ifdef WGL_WGLEXT_PROTOTYPES\nGLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort id);\nGLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *table, GLuint length);\nGLboolean WINAPI wglBindDisplayColorTableEXT (GLushort id);\nVOID WINAPI wglDestroyDisplayColorTableEXT (GLushort id);\n#endif\n#endif /* WGL_EXT_display_color_table */\n\n#ifndef WGL_EXT_extensions_string\n#define WGL_EXT_extensions_string 1\ntypedef const char *(WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void);\n#ifdef WGL_WGLEXT_PROTOTYPES\nconst char *WINAPI wglGetExtensionsStringEXT (void);\n#endif\n#endif /* WGL_EXT_extensions_string */\n\n#ifndef WGL_EXT_framebuffer_sRGB\n#define WGL_EXT_framebuffer_sRGB 1\n#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT  0x20A9\n#endif /* WGL_EXT_framebuffer_sRGB */\n\n#ifndef WGL_EXT_make_current_read\n#define WGL_EXT_make_current_read 1\n#define ERROR_INVALID_PIXEL_TYPE_EXT      0x2043\ntypedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);\ntypedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglMakeContextCurrentEXT (HDC hDrawDC, HDC hReadDC, HGLRC hglrc);\nHDC WINAPI wglGetCurrentReadDCEXT (void);\n#endif\n#endif /* WGL_EXT_make_current_read */\n\n#ifndef WGL_EXT_multisample\n#define WGL_EXT_multisample 1\n#define WGL_SAMPLE_BUFFERS_EXT            0x2041\n#define WGL_SAMPLES_EXT                   0x2042\n#endif /* WGL_EXT_multisample */\n\n#ifndef WGL_EXT_pbuffer\n#define WGL_EXT_pbuffer 1\nDECLARE_HANDLE(HPBUFFEREXT);\n#define WGL_DRAW_TO_PBUFFER_EXT           0x202D\n#define WGL_MAX_PBUFFER_PIXELS_EXT        0x202E\n#define WGL_MAX_PBUFFER_WIDTH_EXT         0x202F\n#define WGL_MAX_PBUFFER_HEIGHT_EXT        0x2030\n#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT     0x2031\n#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT    0x2032\n#define WGL_PBUFFER_LARGEST_EXT           0x2033\n#define WGL_PBUFFER_WIDTH_EXT             0x2034\n#define WGL_PBUFFER_HEIGHT_EXT            0x2035\ntypedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);\ntypedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer);\ntypedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC);\ntypedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer);\ntypedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue);\n#ifdef WGL_WGLEXT_PROTOTYPES\nHPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList);\nHDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT hPbuffer);\nint WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT hPbuffer, HDC hDC);\nBOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT hPbuffer);\nBOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue);\n#endif\n#endif /* WGL_EXT_pbuffer */\n\n#ifndef WGL_EXT_pixel_format\n#define WGL_EXT_pixel_format 1\n#define WGL_NUMBER_PIXEL_FORMATS_EXT      0x2000\n#define WGL_DRAW_TO_WINDOW_EXT            0x2001\n#define WGL_DRAW_TO_BITMAP_EXT            0x2002\n#define WGL_ACCELERATION_EXT              0x2003\n#define WGL_NEED_PALETTE_EXT              0x2004\n#define WGL_NEED_SYSTEM_PALETTE_EXT       0x2005\n#define WGL_SWAP_LAYER_BUFFERS_EXT        0x2006\n#define WGL_SWAP_METHOD_EXT               0x2007\n#define WGL_NUMBER_OVERLAYS_EXT           0x2008\n#define WGL_NUMBER_UNDERLAYS_EXT          0x2009\n#define WGL_TRANSPARENT_EXT               0x200A\n#define WGL_TRANSPARENT_VALUE_EXT         0x200B\n#define WGL_SHARE_DEPTH_EXT               0x200C\n#define WGL_SHARE_STENCIL_EXT             0x200D\n#define WGL_SHARE_ACCUM_EXT               0x200E\n#define WGL_SUPPORT_GDI_EXT               0x200F\n#define WGL_SUPPORT_OPENGL_EXT            0x2010\n#define WGL_DOUBLE_BUFFER_EXT             0x2011\n#define WGL_STEREO_EXT                    0x2012\n#define WGL_PIXEL_TYPE_EXT                0x2013\n#define WGL_COLOR_BITS_EXT                0x2014\n#define WGL_RED_BITS_EXT                  0x2015\n#define WGL_RED_SHIFT_EXT                 0x2016\n#define WGL_GREEN_BITS_EXT                0x2017\n#define WGL_GREEN_SHIFT_EXT               0x2018\n#define WGL_BLUE_BITS_EXT                 0x2019\n#define WGL_BLUE_SHIFT_EXT                0x201A\n#define WGL_ALPHA_BITS_EXT                0x201B\n#define WGL_ALPHA_SHIFT_EXT               0x201C\n#define WGL_ACCUM_BITS_EXT                0x201D\n#define WGL_ACCUM_RED_BITS_EXT            0x201E\n#define WGL_ACCUM_GREEN_BITS_EXT          0x201F\n#define WGL_ACCUM_BLUE_BITS_EXT           0x2020\n#define WGL_ACCUM_ALPHA_BITS_EXT          0x2021\n#define WGL_DEPTH_BITS_EXT                0x2022\n#define WGL_STENCIL_BITS_EXT              0x2023\n#define WGL_AUX_BUFFERS_EXT               0x2024\n#define WGL_NO_ACCELERATION_EXT           0x2025\n#define WGL_GENERIC_ACCELERATION_EXT      0x2026\n#define WGL_FULL_ACCELERATION_EXT         0x2027\n#define WGL_SWAP_EXCHANGE_EXT             0x2028\n#define WGL_SWAP_COPY_EXT                 0x2029\n#define WGL_SWAP_UNDEFINED_EXT            0x202A\n#define WGL_TYPE_RGBA_EXT                 0x202B\n#define WGL_TYPE_COLORINDEX_EXT           0x202C\ntypedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues);\ntypedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues);\ntypedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglGetPixelFormatAttribivEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues);\nBOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues);\nBOOL WINAPI wglChoosePixelFormatEXT (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);\n#endif\n#endif /* WGL_EXT_pixel_format */\n\n#ifndef WGL_EXT_pixel_format_packed_float\n#define WGL_EXT_pixel_format_packed_float 1\n#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT  0x20A8\n#endif /* WGL_EXT_pixel_format_packed_float */\n\n#ifndef WGL_EXT_swap_control\n#define WGL_EXT_swap_control 1\ntypedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);\ntypedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglSwapIntervalEXT (int interval);\nint WINAPI wglGetSwapIntervalEXT (void);\n#endif\n#endif /* WGL_EXT_swap_control */\n\n#ifndef WGL_EXT_swap_control_tear\n#define WGL_EXT_swap_control_tear 1\n#endif /* WGL_EXT_swap_control_tear */\n\n#ifndef WGL_I3D_digital_video_control\n#define WGL_I3D_digital_video_control 1\n#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050\n#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051\n#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052\n#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053\ntypedef BOOL (WINAPI * PFNWGLGETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue);\ntypedef BOOL (WINAPI * PFNWGLSETDIGITALVIDEOPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglGetDigitalVideoParametersI3D (HDC hDC, int iAttribute, int *piValue);\nBOOL WINAPI wglSetDigitalVideoParametersI3D (HDC hDC, int iAttribute, const int *piValue);\n#endif\n#endif /* WGL_I3D_digital_video_control */\n\n#ifndef WGL_I3D_gamma\n#define WGL_I3D_gamma 1\n#define WGL_GAMMA_TABLE_SIZE_I3D          0x204E\n#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D     0x204F\ntypedef BOOL (WINAPI * PFNWGLGETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, int *piValue);\ntypedef BOOL (WINAPI * PFNWGLSETGAMMATABLEPARAMETERSI3DPROC) (HDC hDC, int iAttribute, const int *piValue);\ntypedef BOOL (WINAPI * PFNWGLGETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue);\ntypedef BOOL (WINAPI * PFNWGLSETGAMMATABLEI3DPROC) (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglGetGammaTableParametersI3D (HDC hDC, int iAttribute, int *piValue);\nBOOL WINAPI wglSetGammaTableParametersI3D (HDC hDC, int iAttribute, const int *piValue);\nBOOL WINAPI wglGetGammaTableI3D (HDC hDC, int iEntries, USHORT *puRed, USHORT *puGreen, USHORT *puBlue);\nBOOL WINAPI wglSetGammaTableI3D (HDC hDC, int iEntries, const USHORT *puRed, const USHORT *puGreen, const USHORT *puBlue);\n#endif\n#endif /* WGL_I3D_gamma */\n\n#ifndef WGL_I3D_genlock\n#define WGL_I3D_genlock 1\n#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D  0x2044\n#define WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D 0x2045\n#define WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D 0x2046\n#define WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D 0x2047\n#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048\n#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049\n#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A\n#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B\n#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D  0x204C\ntypedef BOOL (WINAPI * PFNWGLENABLEGENLOCKI3DPROC) (HDC hDC);\ntypedef BOOL (WINAPI * PFNWGLDISABLEGENLOCKI3DPROC) (HDC hDC);\ntypedef BOOL (WINAPI * PFNWGLISENABLEDGENLOCKI3DPROC) (HDC hDC, BOOL *pFlag);\ntypedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEI3DPROC) (HDC hDC, UINT uSource);\ntypedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEI3DPROC) (HDC hDC, UINT *uSource);\ntypedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT uEdge);\ntypedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEEDGEI3DPROC) (HDC hDC, UINT *uEdge);\ntypedef BOOL (WINAPI * PFNWGLGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT uRate);\ntypedef BOOL (WINAPI * PFNWGLGETGENLOCKSAMPLERATEI3DPROC) (HDC hDC, UINT *uRate);\ntypedef BOOL (WINAPI * PFNWGLGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT uDelay);\ntypedef BOOL (WINAPI * PFNWGLGETGENLOCKSOURCEDELAYI3DPROC) (HDC hDC, UINT *uDelay);\ntypedef BOOL (WINAPI * PFNWGLQUERYGENLOCKMAXSOURCEDELAYI3DPROC) (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglEnableGenlockI3D (HDC hDC);\nBOOL WINAPI wglDisableGenlockI3D (HDC hDC);\nBOOL WINAPI wglIsEnabledGenlockI3D (HDC hDC, BOOL *pFlag);\nBOOL WINAPI wglGenlockSourceI3D (HDC hDC, UINT uSource);\nBOOL WINAPI wglGetGenlockSourceI3D (HDC hDC, UINT *uSource);\nBOOL WINAPI wglGenlockSourceEdgeI3D (HDC hDC, UINT uEdge);\nBOOL WINAPI wglGetGenlockSourceEdgeI3D (HDC hDC, UINT *uEdge);\nBOOL WINAPI wglGenlockSampleRateI3D (HDC hDC, UINT uRate);\nBOOL WINAPI wglGetGenlockSampleRateI3D (HDC hDC, UINT *uRate);\nBOOL WINAPI wglGenlockSourceDelayI3D (HDC hDC, UINT uDelay);\nBOOL WINAPI wglGetGenlockSourceDelayI3D (HDC hDC, UINT *uDelay);\nBOOL WINAPI wglQueryGenlockMaxSourceDelayI3D (HDC hDC, UINT *uMaxLineDelay, UINT *uMaxPixelDelay);\n#endif\n#endif /* WGL_I3D_genlock */\n\n#ifndef WGL_I3D_image_buffer\n#define WGL_I3D_image_buffer 1\n#define WGL_IMAGE_BUFFER_MIN_ACCESS_I3D   0x00000001\n#define WGL_IMAGE_BUFFER_LOCK_I3D         0x00000002\ntypedef LPVOID (WINAPI * PFNWGLCREATEIMAGEBUFFERI3DPROC) (HDC hDC, DWORD dwSize, UINT uFlags);\ntypedef BOOL (WINAPI * PFNWGLDESTROYIMAGEBUFFERI3DPROC) (HDC hDC, LPVOID pAddress);\ntypedef BOOL (WINAPI * PFNWGLASSOCIATEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count);\ntypedef BOOL (WINAPI * PFNWGLRELEASEIMAGEBUFFEREVENTSI3DPROC) (HDC hDC, const LPVOID *pAddress, UINT count);\n#ifdef WGL_WGLEXT_PROTOTYPES\nLPVOID WINAPI wglCreateImageBufferI3D (HDC hDC, DWORD dwSize, UINT uFlags);\nBOOL WINAPI wglDestroyImageBufferI3D (HDC hDC, LPVOID pAddress);\nBOOL WINAPI wglAssociateImageBufferEventsI3D (HDC hDC, const HANDLE *pEvent, const LPVOID *pAddress, const DWORD *pSize, UINT count);\nBOOL WINAPI wglReleaseImageBufferEventsI3D (HDC hDC, const LPVOID *pAddress, UINT count);\n#endif\n#endif /* WGL_I3D_image_buffer */\n\n#ifndef WGL_I3D_swap_frame_lock\n#define WGL_I3D_swap_frame_lock 1\ntypedef BOOL (WINAPI * PFNWGLENABLEFRAMELOCKI3DPROC) (void);\ntypedef BOOL (WINAPI * PFNWGLDISABLEFRAMELOCKI3DPROC) (void);\ntypedef BOOL (WINAPI * PFNWGLISENABLEDFRAMELOCKI3DPROC) (BOOL *pFlag);\ntypedef BOOL (WINAPI * PFNWGLQUERYFRAMELOCKMASTERI3DPROC) (BOOL *pFlag);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglEnableFrameLockI3D (void);\nBOOL WINAPI wglDisableFrameLockI3D (void);\nBOOL WINAPI wglIsEnabledFrameLockI3D (BOOL *pFlag);\nBOOL WINAPI wglQueryFrameLockMasterI3D (BOOL *pFlag);\n#endif\n#endif /* WGL_I3D_swap_frame_lock */\n\n#ifndef WGL_I3D_swap_frame_usage\n#define WGL_I3D_swap_frame_usage 1\ntypedef BOOL (WINAPI * PFNWGLGETFRAMEUSAGEI3DPROC) (float *pUsage);\ntypedef BOOL (WINAPI * PFNWGLBEGINFRAMETRACKINGI3DPROC) (void);\ntypedef BOOL (WINAPI * PFNWGLENDFRAMETRACKINGI3DPROC) (void);\ntypedef BOOL (WINAPI * PFNWGLQUERYFRAMETRACKINGI3DPROC) (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglGetFrameUsageI3D (float *pUsage);\nBOOL WINAPI wglBeginFrameTrackingI3D (void);\nBOOL WINAPI wglEndFrameTrackingI3D (void);\nBOOL WINAPI wglQueryFrameTrackingI3D (DWORD *pFrameCount, DWORD *pMissedFrames, float *pLastMissedUsage);\n#endif\n#endif /* WGL_I3D_swap_frame_usage */\n\n#ifndef WGL_NV_DX_interop\n#define WGL_NV_DX_interop 1\n#define WGL_ACCESS_READ_ONLY_NV           0x00000000\n#define WGL_ACCESS_READ_WRITE_NV          0x00000001\n#define WGL_ACCESS_WRITE_DISCARD_NV       0x00000002\ntypedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLENVPROC) (void *dxObject, HANDLE shareHandle);\ntypedef HANDLE (WINAPI * PFNWGLDXOPENDEVICENVPROC) (void *dxDevice);\ntypedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICENVPROC) (HANDLE hDevice);\ntypedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTNVPROC) (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access);\ntypedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECTNVPROC) (HANDLE hDevice, HANDLE hObject);\ntypedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSNVPROC) (HANDLE hObject, GLenum access);\ntypedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects);\ntypedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSNVPROC) (HANDLE hDevice, GLint count, HANDLE *hObjects);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglDXSetResourceShareHandleNV (void *dxObject, HANDLE shareHandle);\nHANDLE WINAPI wglDXOpenDeviceNV (void *dxDevice);\nBOOL WINAPI wglDXCloseDeviceNV (HANDLE hDevice);\nHANDLE WINAPI wglDXRegisterObjectNV (HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access);\nBOOL WINAPI wglDXUnregisterObjectNV (HANDLE hDevice, HANDLE hObject);\nBOOL WINAPI wglDXObjectAccessNV (HANDLE hObject, GLenum access);\nBOOL WINAPI wglDXLockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects);\nBOOL WINAPI wglDXUnlockObjectsNV (HANDLE hDevice, GLint count, HANDLE *hObjects);\n#endif\n#endif /* WGL_NV_DX_interop */\n\n#ifndef WGL_NV_DX_interop2\n#define WGL_NV_DX_interop2 1\n#endif /* WGL_NV_DX_interop2 */\n\n#ifndef WGL_NV_copy_image\n#define WGL_NV_copy_image 1\ntypedef BOOL (WINAPI * PFNWGLCOPYIMAGESUBDATANVPROC) (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglCopyImageSubDataNV (HGLRC hSrcRC, GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, HGLRC hDstRC, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei width, GLsizei height, GLsizei depth);\n#endif\n#endif /* WGL_NV_copy_image */\n\n#ifndef WGL_NV_delay_before_swap\n#define WGL_NV_delay_before_swap 1\ntypedef BOOL (WINAPI * PFNWGLDELAYBEFORESWAPNVPROC) (HDC hDC, GLfloat seconds);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglDelayBeforeSwapNV (HDC hDC, GLfloat seconds);\n#endif\n#endif /* WGL_NV_delay_before_swap */\n\n#ifndef WGL_NV_float_buffer\n#define WGL_NV_float_buffer 1\n#define WGL_FLOAT_COMPONENTS_NV           0x20B0\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV 0x20B1\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV 0x20B2\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV 0x20B3\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV 0x20B4\n#define WGL_TEXTURE_FLOAT_R_NV            0x20B5\n#define WGL_TEXTURE_FLOAT_RG_NV           0x20B6\n#define WGL_TEXTURE_FLOAT_RGB_NV          0x20B7\n#define WGL_TEXTURE_FLOAT_RGBA_NV         0x20B8\n#endif /* WGL_NV_float_buffer */\n\n#ifndef WGL_NV_gpu_affinity\n#define WGL_NV_gpu_affinity 1\nDECLARE_HANDLE(HGPUNV);\nstruct _GPU_DEVICE {\n    DWORD  cb;\n    CHAR   DeviceName[32];\n    CHAR   DeviceString[128];\n    DWORD  Flags;\n    RECT   rcVirtualScreen;\n};\ntypedef struct _GPU_DEVICE *PGPU_DEVICE;\n#define ERROR_INCOMPATIBLE_AFFINITY_MASKS_NV 0x20D0\n#define ERROR_MISSING_AFFINITY_MASK_NV    0x20D1\ntypedef BOOL (WINAPI * PFNWGLENUMGPUSNVPROC) (UINT iGpuIndex, HGPUNV *phGpu);\ntypedef BOOL (WINAPI * PFNWGLENUMGPUDEVICESNVPROC) (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice);\ntypedef HDC (WINAPI * PFNWGLCREATEAFFINITYDCNVPROC) (const HGPUNV *phGpuList);\ntypedef BOOL (WINAPI * PFNWGLENUMGPUSFROMAFFINITYDCNVPROC) (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu);\ntypedef BOOL (WINAPI * PFNWGLDELETEDCNVPROC) (HDC hdc);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglEnumGpusNV (UINT iGpuIndex, HGPUNV *phGpu);\nBOOL WINAPI wglEnumGpuDevicesNV (HGPUNV hGpu, UINT iDeviceIndex, PGPU_DEVICE lpGpuDevice);\nHDC WINAPI wglCreateAffinityDCNV (const HGPUNV *phGpuList);\nBOOL WINAPI wglEnumGpusFromAffinityDCNV (HDC hAffinityDC, UINT iGpuIndex, HGPUNV *hGpu);\nBOOL WINAPI wglDeleteDCNV (HDC hdc);\n#endif\n#endif /* WGL_NV_gpu_affinity */\n\n#ifndef WGL_NV_multigpu_context\n#define WGL_NV_multigpu_context 1\n#define WGL_CONTEXT_MULTIGPU_ATTRIB_NV    0x20AA\n#define WGL_CONTEXT_MULTIGPU_ATTRIB_SINGLE_NV 0x20AB\n#define WGL_CONTEXT_MULTIGPU_ATTRIB_AFR_NV 0x20AC\n#define WGL_CONTEXT_MULTIGPU_ATTRIB_MULTICAST_NV 0x20AD\n#define WGL_CONTEXT_MULTIGPU_ATTRIB_MULTI_DISPLAY_MULTICAST_NV 0x20AE\n#endif /* WGL_NV_multigpu_context */\n\n#ifndef WGL_NV_multisample_coverage\n#define WGL_NV_multisample_coverage 1\n#define WGL_COVERAGE_SAMPLES_NV           0x2042\n#define WGL_COLOR_SAMPLES_NV              0x20B9\n#endif /* WGL_NV_multisample_coverage */\n\n#ifndef WGL_NV_present_video\n#define WGL_NV_present_video 1\nDECLARE_HANDLE(HVIDEOOUTPUTDEVICENV);\n#define WGL_NUM_VIDEO_SLOTS_NV            0x20F0\ntypedef int (WINAPI * PFNWGLENUMERATEVIDEODEVICESNVPROC) (HDC hDc, HVIDEOOUTPUTDEVICENV *phDeviceList);\ntypedef BOOL (WINAPI * PFNWGLBINDVIDEODEVICENVPROC) (HDC hDc, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);\ntypedef BOOL (WINAPI * PFNWGLQUERYCURRENTCONTEXTNVPROC) (int iAttribute, int *piValue);\n#ifdef WGL_WGLEXT_PROTOTYPES\nint WINAPI wglEnumerateVideoDevicesNV (HDC hDc, HVIDEOOUTPUTDEVICENV *phDeviceList);\nBOOL WINAPI wglBindVideoDeviceNV (HDC hDc, unsigned int uVideoSlot, HVIDEOOUTPUTDEVICENV hVideoDevice, const int *piAttribList);\nBOOL WINAPI wglQueryCurrentContextNV (int iAttribute, int *piValue);\n#endif\n#endif /* WGL_NV_present_video */\n\n#ifndef WGL_NV_render_depth_texture\n#define WGL_NV_render_depth_texture 1\n#define WGL_BIND_TO_TEXTURE_DEPTH_NV      0x20A3\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4\n#define WGL_DEPTH_TEXTURE_FORMAT_NV       0x20A5\n#define WGL_TEXTURE_DEPTH_COMPONENT_NV    0x20A6\n#define WGL_DEPTH_COMPONENT_NV            0x20A7\n#endif /* WGL_NV_render_depth_texture */\n\n#ifndef WGL_NV_render_texture_rectangle\n#define WGL_NV_render_texture_rectangle 1\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0\n#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1\n#define WGL_TEXTURE_RECTANGLE_NV          0x20A2\n#endif /* WGL_NV_render_texture_rectangle */\n\n#ifndef WGL_NV_swap_group\n#define WGL_NV_swap_group 1\ntypedef BOOL (WINAPI * PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group);\ntypedef BOOL (WINAPI * PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier);\ntypedef BOOL (WINAPI * PFNWGLQUERYSWAPGROUPNVPROC) (HDC hDC, GLuint *group, GLuint *barrier);\ntypedef BOOL (WINAPI * PFNWGLQUERYMAXSWAPGROUPSNVPROC) (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers);\ntypedef BOOL (WINAPI * PFNWGLQUERYFRAMECOUNTNVPROC) (HDC hDC, GLuint *count);\ntypedef BOOL (WINAPI * PFNWGLRESETFRAMECOUNTNVPROC) (HDC hDC);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglJoinSwapGroupNV (HDC hDC, GLuint group);\nBOOL WINAPI wglBindSwapBarrierNV (GLuint group, GLuint barrier);\nBOOL WINAPI wglQuerySwapGroupNV (HDC hDC, GLuint *group, GLuint *barrier);\nBOOL WINAPI wglQueryMaxSwapGroupsNV (HDC hDC, GLuint *maxGroups, GLuint *maxBarriers);\nBOOL WINAPI wglQueryFrameCountNV (HDC hDC, GLuint *count);\nBOOL WINAPI wglResetFrameCountNV (HDC hDC);\n#endif\n#endif /* WGL_NV_swap_group */\n\n#ifndef WGL_NV_vertex_array_range\n#define WGL_NV_vertex_array_range 1\ntypedef void *(WINAPI * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);\ntypedef void (WINAPI * PFNWGLFREEMEMORYNVPROC) (void *pointer);\n#ifdef WGL_WGLEXT_PROTOTYPES\nvoid *WINAPI wglAllocateMemoryNV (GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority);\nvoid WINAPI wglFreeMemoryNV (void *pointer);\n#endif\n#endif /* WGL_NV_vertex_array_range */\n\n#ifndef WGL_NV_video_capture\n#define WGL_NV_video_capture 1\nDECLARE_HANDLE(HVIDEOINPUTDEVICENV);\n#define WGL_UNIQUE_ID_NV                  0x20CE\n#define WGL_NUM_VIDEO_CAPTURE_SLOTS_NV    0x20CF\ntypedef BOOL (WINAPI * PFNWGLBINDVIDEOCAPTUREDEVICENVPROC) (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice);\ntypedef UINT (WINAPI * PFNWGLENUMERATEVIDEOCAPTUREDEVICESNVPROC) (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList);\ntypedef BOOL (WINAPI * PFNWGLLOCKVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice);\ntypedef BOOL (WINAPI * PFNWGLQUERYVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue);\ntypedef BOOL (WINAPI * PFNWGLRELEASEVIDEOCAPTUREDEVICENVPROC) (HDC hDc, HVIDEOINPUTDEVICENV hDevice);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglBindVideoCaptureDeviceNV (UINT uVideoSlot, HVIDEOINPUTDEVICENV hDevice);\nUINT WINAPI wglEnumerateVideoCaptureDevicesNV (HDC hDc, HVIDEOINPUTDEVICENV *phDeviceList);\nBOOL WINAPI wglLockVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice);\nBOOL WINAPI wglQueryVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice, int iAttribute, int *piValue);\nBOOL WINAPI wglReleaseVideoCaptureDeviceNV (HDC hDc, HVIDEOINPUTDEVICENV hDevice);\n#endif\n#endif /* WGL_NV_video_capture */\n\n#ifndef WGL_NV_video_output\n#define WGL_NV_video_output 1\nDECLARE_HANDLE(HPVIDEODEV);\n#define WGL_BIND_TO_VIDEO_RGB_NV          0x20C0\n#define WGL_BIND_TO_VIDEO_RGBA_NV         0x20C1\n#define WGL_BIND_TO_VIDEO_RGB_AND_DEPTH_NV 0x20C2\n#define WGL_VIDEO_OUT_COLOR_NV            0x20C3\n#define WGL_VIDEO_OUT_ALPHA_NV            0x20C4\n#define WGL_VIDEO_OUT_DEPTH_NV            0x20C5\n#define WGL_VIDEO_OUT_COLOR_AND_ALPHA_NV  0x20C6\n#define WGL_VIDEO_OUT_COLOR_AND_DEPTH_NV  0x20C7\n#define WGL_VIDEO_OUT_FRAME               0x20C8\n#define WGL_VIDEO_OUT_FIELD_1             0x20C9\n#define WGL_VIDEO_OUT_FIELD_2             0x20CA\n#define WGL_VIDEO_OUT_STACKED_FIELDS_1_2  0x20CB\n#define WGL_VIDEO_OUT_STACKED_FIELDS_2_1  0x20CC\ntypedef BOOL (WINAPI * PFNWGLGETVIDEODEVICENVPROC) (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice);\ntypedef BOOL (WINAPI * PFNWGLRELEASEVIDEODEVICENVPROC) (HPVIDEODEV hVideoDevice);\ntypedef BOOL (WINAPI * PFNWGLBINDVIDEOIMAGENVPROC) (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer);\ntypedef BOOL (WINAPI * PFNWGLRELEASEVIDEOIMAGENVPROC) (HPBUFFERARB hPbuffer, int iVideoBuffer);\ntypedef BOOL (WINAPI * PFNWGLSENDPBUFFERTOVIDEONVPROC) (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock);\ntypedef BOOL (WINAPI * PFNWGLGETVIDEOINFONVPROC) (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglGetVideoDeviceNV (HDC hDC, int numDevices, HPVIDEODEV *hVideoDevice);\nBOOL WINAPI wglReleaseVideoDeviceNV (HPVIDEODEV hVideoDevice);\nBOOL WINAPI wglBindVideoImageNV (HPVIDEODEV hVideoDevice, HPBUFFERARB hPbuffer, int iVideoBuffer);\nBOOL WINAPI wglReleaseVideoImageNV (HPBUFFERARB hPbuffer, int iVideoBuffer);\nBOOL WINAPI wglSendPbufferToVideoNV (HPBUFFERARB hPbuffer, int iBufferType, unsigned long *pulCounterPbuffer, BOOL bBlock);\nBOOL WINAPI wglGetVideoInfoNV (HPVIDEODEV hpVideoDevice, unsigned long *pulCounterOutputPbuffer, unsigned long *pulCounterOutputVideo);\n#endif\n#endif /* WGL_NV_video_output */\n\n#ifndef WGL_OML_sync_control\n#define WGL_OML_sync_control 1\ntypedef BOOL (WINAPI * PFNWGLGETSYNCVALUESOMLPROC) (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);\ntypedef BOOL (WINAPI * PFNWGLGETMSCRATEOMLPROC) (HDC hdc, INT32 *numerator, INT32 *denominator);\ntypedef INT64 (WINAPI * PFNWGLSWAPBUFFERSMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);\ntypedef INT64 (WINAPI * PFNWGLSWAPLAYERBUFFERSMSCOMLPROC) (HDC hdc, INT fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);\ntypedef BOOL (WINAPI * PFNWGLWAITFORMSCOMLPROC) (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);\ntypedef BOOL (WINAPI * PFNWGLWAITFORSBCOMLPROC) (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);\n#ifdef WGL_WGLEXT_PROTOTYPES\nBOOL WINAPI wglGetSyncValuesOML (HDC hdc, INT64 *ust, INT64 *msc, INT64 *sbc);\nBOOL WINAPI wglGetMscRateOML (HDC hdc, INT32 *numerator, INT32 *denominator);\nINT64 WINAPI wglSwapBuffersMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder);\nINT64 WINAPI wglSwapLayerBuffersMscOML (HDC hdc, INT fuPlanes, INT64 target_msc, INT64 divisor, INT64 remainder);\nBOOL WINAPI wglWaitForMscOML (HDC hdc, INT64 target_msc, INT64 divisor, INT64 remainder, INT64 *ust, INT64 *msc, INT64 *sbc);\nBOOL WINAPI wglWaitForSbcOML (HDC hdc, INT64 target_sbc, INT64 *ust, INT64 *msc, INT64 *sbc);\n#endif\n#endif /* WGL_OML_sync_control */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "src/Common/MemPtr.h",
    "content": "#pragma once\n#include <type_traits>\n#include \"betype.h\"\n\nusing MPTR = uint32; // generic address in PowerPC memory space\n\n#define MPTR_NULL (0)\n\nusing VAddr = uint32; // virtual address\nusing PAddr = uint32; // physical address\n\nextern uint8* memory_base;\nextern uint8* PPCInterpreterGetStackPointer();\nextern uint8* PPCInterpreter_PushAndReturnStackPointer(sint32 offset);\nextern void PPCInterpreterModifyStackPointer(sint32 offset);\n\nclass MEMPTRBase\n{\n};\n\ntemplate<typename T>\nclass MEMPTR : MEMPTRBase\n{\n  public:\n\tconstexpr MEMPTR() noexcept\n\t\t: m_value(0) {}\n\n\texplicit constexpr MEMPTR(uint32 offset) noexcept\n\t\t: m_value(offset) {}\n\n\texplicit constexpr MEMPTR(const uint32be& offset) noexcept\n\t\t: m_value(offset) {}\n\n\tconstexpr MEMPTR(std::nullptr_t) noexcept\n\t\t: m_value(0) {}\n\n\tMEMPTR(T* ptr) noexcept\n\t{\n\t\tif (ptr == nullptr)\n\t\t\tm_value = 0;\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000);\n\t\t\tm_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base);\n\t\t}\n\t}\n\n\tconstexpr MEMPTR(const MEMPTR&) noexcept = default;\n\n\tconstexpr MEMPTR& operator=(const MEMPTR&) noexcept = default;\n\n\tconstexpr MEMPTR& operator=(const uint32& offset) noexcept\n\t{\n\t\tm_value = offset;\n\t\treturn *this;\n\t}\n\n\tconstexpr MEMPTR& operator=(std::nullptr_t) noexcept\n\t{\n\t\tm_value = 0;\n\t\treturn *this;\n\t}\n\n\tMEMPTR& operator=(T* ptr) noexcept\n\t{\n\t\tif (ptr == nullptr)\n\t\t\tm_value = 0;\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug((uint8*)ptr >= memory_base && (uint8*)ptr <= memory_base + 0x100000000);\n\t\t\tm_value = (uint32)((uintptr_t)ptr - (uintptr_t)memory_base);\n\t\t}\n\t\treturn *this;\n\t}\n\n\tbool atomic_compare_exchange(T* comparePtr, T* newPtr) noexcept\n\t{\n\t\tMEMPTR<T> mp_compare = comparePtr;\n\t\tMEMPTR<T> mp_new = newPtr;\n\t\tauto* thisValueAtomic = reinterpret_cast<std::atomic<uint32be>*>(&m_value);\n\t\treturn thisValueAtomic->compare_exchange_strong(mp_compare.m_value, mp_new.m_value);\n\t}\n\n\texplicit constexpr operator bool() const noexcept\n\t{\n\t\treturn m_value != 0;\n\t}\n\n\t// allow implicit cast to wrapped pointer type\n\tconstexpr operator T*() const noexcept\n\t{\n\t\treturn GetPtr();\n\t}\n\n\ttemplate<typename X>\n\texplicit operator MEMPTR<X>() const noexcept\n\t{\n\t\treturn MEMPTR<X>(this->m_value);\n\t}\n\n\tsint32 operator-(const MEMPTR& ptr) noexcept\n\t\trequires(!std::is_void_v<T>)\n\t{\n\t\treturn static_cast<sint32>(this->GetMPTR() - ptr.GetMPTR());\n\t}\n\n\tMEMPTR operator+(sint32 v) noexcept\n\t\trequires(!std::is_void_v<T>)\n\t{\n\t\t// pointer arithmetic\n\t\treturn MEMPTR(this->GetMPTR() + v * sizeof(T));\n\t}\n\n\tMEMPTR operator-(sint32 v) noexcept\n\t\trequires(!std::is_void_v<T>)\n\t{\n\t\t// pointer arithmetic\n\t\treturn MEMPTR(this->GetMPTR() - v * sizeof(T));\n\t}\n\n\tMEMPTR& operator+=(sint32 v) noexcept\n\t\trequires(!std::is_void_v<T>)\n\t{\n\t\tm_value += v * sizeof(T);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename Q = T>\n\t\trequires(!std::is_void_v<Q>)\n\tQ& operator*() const noexcept\n\t{\n\t\treturn *GetPtr();\n\t}\n\n\tconstexpr T* operator->() const noexcept\n\t{\n\t\treturn GetPtr();\n\t}\n\n\ttemplate<typename Q = T>\n\t\trequires(!std::is_void_v<Q>)\n\tQ& operator[](int index) noexcept\n\t{\n\t\treturn GetPtr()[index];\n\t}\n\n\tT* GetPtr() const noexcept\n\t{\n\t\treturn (T*)(m_value == 0 ? nullptr : memory_base + (uint32)m_value);\n\t}\n\n\ttemplate<typename C>\n\tC* GetPtr() const noexcept\n\t{\n\t\treturn static_cast<C*>(GetPtr());\n\t}\n\n\t[[nodiscard]] constexpr uint32 GetMPTR() const noexcept\n\t{\n\t\treturn m_value.value();\n\t}\n\t[[nodiscard]] constexpr const uint32be& GetBEValue() const noexcept\n\t{\n\t\treturn m_value;\n\t}\n\n\t[[nodiscard]] constexpr bool IsNull() const noexcept\n\t{\n\t\treturn m_value == 0;\n\t}\n\n  private:\n\tuint32be m_value;\n};\n\nstatic_assert(sizeof(MEMPTR<void*>) == sizeof(uint32be));\nstatic_assert(std::is_trivially_copyable_v<MEMPTR<void*>>);\n\n#include \"StackAllocator.h\"\n#include \"SysAllocator.h\"\n\ntemplate<typename T>\nstruct fmt::formatter<MEMPTR<T>> : formatter<string_view>\n{\n\ttemplate<typename FormatContext>\n\tauto format(const MEMPTR<T>& v, FormatContext& ctx) const -> format_context::iterator\n\t{\n\t\treturn fmt::format_to(ctx.out(), \"{:#x}\", v.GetMPTR());\n\t}\n};\n"
  },
  {
    "path": "src/Common/StackAllocator.h",
    "content": "#pragma once\n\ntemplate<typename T, int count = 1>\nclass StackAllocator\n{\npublic:\n\tStackAllocator()\n\t\t: StackAllocator(1)\n\t{}\n\n\texplicit StackAllocator(const uint32 items)\n\t{\n\t\tm_items = items;\n\t\tm_modified_size = count * sizeof(T) * items + kStaticMemOffset * 2;\n\t\tm_modified_size = (m_modified_size/8+7) * 8; // pad to 8 bytes\n\t\tm_ptr = new(PPCInterpreter_PushAndReturnStackPointer(m_modified_size) + kStaticMemOffset) T[count * items]();\n\t}\n\n\t~StackAllocator()\n\t{\n\t\tfor (size_t i = 0; i < count * m_items; ++i)\n\t\t\tm_ptr[i].~T();\n\t\tPPCInterpreterModifyStackPointer(-m_modified_size);\n\t}\n\n\tT* operator->() const\n\t{\n\t\treturn GetPointer();\n\t}\n\n\tT* GetPointer() const { return m_ptr; }\n\tuint32 GetMPTR() const { return MEMPTR<T>(m_ptr).GetMPTR(); }\n\n\tT* operator&() { return GetPointer(); }\n\texplicit operator T*() const { return GetPointer(); }\n\texplicit operator uint32() const { return GetMPTR(); }\n\texplicit operator bool() const { return *m_ptr != 0; }\n\n\t// for arrays (count > 1) allow direct access via [] operator\n\ttemplate<int c = count>\n\trequires (c > 1)\n\tT& operator[](const uint32 index)\n\t{\n\t\treturn m_ptr[index];\n\t}\n\n\t// if count is 1, then allow direct value assignment via = operator\n\ttemplate<int c = count>\n\trequires (c == 1)\n\tT& operator=(const T& rhs)\n\t{\n\t\t*m_ptr = rhs;\n\t\treturn *m_ptr;\n\t}\n\n\t// if count is 1, then allow == and != operators\n\ttemplate<int c = count>\n\trequires (c == 1)\n\tbool operator==(const T& rhs) const\n\t{\n\t\treturn *m_ptr == rhs;\n\t}\n\nprivate:\n\tstatic const uint32 kStaticMemOffset = 64;\n\n\tT* m_ptr;\n\tsint32 m_modified_size;\n\tuint32 m_items;\n};"
  },
  {
    "path": "src/Common/SysAllocator.cpp",
    "content": "#include \"SysAllocator.h\"\n\nvoid SysAllocatorContainer::Initialize()\n{\n\tfor (SysAllocatorBase* sysAlloc : m_sysAllocList)\n\t{\n\t\tsysAlloc->Initialize();\n\t}\n}\n\nvoid SysAllocatorContainer::PushSysAllocator(SysAllocatorBase* base)\n{\n\tm_sysAllocList.push_back(base);\n}\n\nSysAllocatorContainer& SysAllocatorContainer::GetInstance()\n{\n\tstatic SysAllocatorContainer s_instance;\n\treturn s_instance;\n}\n\nSysAllocatorBase::SysAllocatorBase()\n{\n\tSysAllocatorContainer::GetInstance().PushSysAllocator(this);\n}"
  },
  {
    "path": "src/Common/SysAllocator.h",
    "content": "#pragma once\n\n#include <type_traits>\n#include <cstddef>\n#include <vector>\n\nuint32 coreinit_allocFromSysArea(uint32 size, uint32 alignment);\nclass SysAllocatorBase;\n\n#define SYSALLOCATOR_GUARDS\t\t0\t// if 1, create a magic constant at the top of each memory allocation which is used to check for memory corruption\n\nclass SysAllocatorContainer\n{\npublic:\n\tvoid Initialize();\n\tvoid PushSysAllocator(SysAllocatorBase* base);\n\n\tstatic SysAllocatorContainer& GetInstance();\n\nprivate:\n\tstd::vector<SysAllocatorBase*> m_sysAllocList;\n};\n\n\nclass SysAllocatorBase\n{\n\tfriend class SysAllocatorContainer;\npublic:\n\tSysAllocatorBase();\n\tvirtual ~SysAllocatorBase() = default;\n\nprivate:\n\tvirtual void Initialize() = 0;\n};\n\ntemplate<typename T, size_t count = 1, size_t alignment = 32>\nclass SysAllocator : public SysAllocatorBase\n{\npublic:\n\tSysAllocator()\n\t{\n\t\tm_tempData.resize(count);\n\t}\n\n\tSysAllocator(std::initializer_list<T> l)\n\t{\n\t\tm_tempData.reserve(count);\n\n\t\tm_tempData.insert(m_tempData.begin(), l);\n\t\tif (count > l.size())\n\t\t\tm_tempData.insert(m_tempData.end(), count - l.size(), T());\n\t}\n\n\ttemplate <size_t N>\n\tSysAllocator(const char(&str)[N])\n\t{\n\t\tm_tempData.reserve(count);\n\t\tm_tempData.insert(m_tempData.begin(), str, str + N);\n\t}\n\n\tconstexpr uint32 GetCount() const\n\t{\n\t\treturn count;\n\t}\n\n\tconstexpr size_t GetByteSize() const\n\t{\n\t\treturn count * sizeof(T);\n\t}\n\n\tT* GetPtr() const\n\t{\n#if SYSALLOCATOR_GUARDS\n\t\tcemu_assert(*(uint32*)((uint8*)m_sysMem.GetPtr()+(sizeof(T) * count)) == 0x112A33C4);\n#endif\n\t\treturn m_sysMem.GetPtr();\n\t}\n\n\tuint32 GetMPTR() const\n\t{\n#if SYSALLOCATOR_GUARDS\n\t\tcemu_assert(*(uint32*)((uint8*)m_sysMem.GetPtr()+(sizeof(T) * count)) == 0x112A33C4);\n#endif\n\t\treturn m_sysMem.GetMPTR();\n\t}\n\n\tT& operator*()\n\t{\n\t\treturn *GetPtr();\n\t}\n\n\toperator T*()\n\t{\n\t\treturn GetPtr();\n\t}\n\n\tSysAllocator operator+(const SysAllocator& ptr)\n\t{\n\t\treturn SysAllocator(this->GetMPTR() + ptr.GetMPTR());\n\t}\n\n\tSysAllocator operator-(const SysAllocator& ptr)\n\t{\n\t\treturn SysAllocator(this->GetMPTR() - ptr.GetMPTR());\n\t}\n\n\tT* operator+(sint32 v)\n\t{\n\t\treturn this->GetPtr() + v;\n\t}\n\n\tT* operator-(sint32 v)\n\t{\n\t\treturn this->GetPtr() - v;\n\t}\n\n\toperator void*() { return m_sysMem->GetPtr(); }\n\n\t// for all arrays except bool\n\tT& operator[](int index)\n\t\trequires(count != 1) && (!std::is_same_v<T, bool>)\n\t{\n\t\t// return tmp data until we allocated in sys mem\n\t\tif (m_sysMem.GetMPTR() == 0)\n\t\t{\n\t\t\treturn m_tempData[index];\n\t\t}\n\n\t\treturn m_sysMem[index];\n\t}\n  private:\n\tSysAllocator(uint32 memptr)\n\t\t: m_sysMem(memptr)\n\t{}\n\n\tvoid Initialize() override\n\t{\n\t\tif (m_sysMem.GetMPTR() != 0)\n\t\t\treturn;\n\t\t// alloc mem\n\t\tuint32 guardSize = 0;\n#if SYSALLOCATOR_GUARDS\n\t\tguardSize = 4;\n#endif\n\t\tm_sysMem = { coreinit_allocFromSysArea(sizeof(T) * count + guardSize, alignment) };\n\t\t// copy temp buffer to mem and clear it\n\t\tmemcpy(m_sysMem.GetPtr(), m_tempData.data(), sizeof(T)*count);\n#if SYSALLOCATOR_GUARDS\n\t\t*(uint32*)((uint8*)m_sysMem.GetPtr()+(sizeof(T) * count)) = 0x112A33C4;\n#endif\n\t\tm_tempData.clear();\n\t}\n\n\tMEMPTR<T> m_sysMem;\n\tstd::vector<T> m_tempData;\n};\n\ntemplate <size_t N>\nSysAllocator(const char(&str)[N]) -> SysAllocator<char, N>;\n\ntemplate<typename T>\nclass SysAllocator<T, 1> : public SysAllocatorBase\n{\npublic:\n\tSysAllocator()\n\t{\n\t\tm_tempData = {};\n\t}\n\n\tSysAllocator(const T& value)\n\t{\n\t\tm_tempData = value;\n\t}\n\n\tSysAllocator& operator=(const T& value)\n\t{\n\t\t*m_sysMem = value;\n\t\treturn *this;\n\t}\n\n\toperator T()\n\t{\n\t\treturn *GetPtr();\n\t}\n\n\toperator T*()\n\t{\n\t\treturn GetPtr();\n\t}\n\n\tT* GetPtr() const\n\t{\n\t\treturn m_sysMem.GetPtr();\n\t}\n\n\tuint32 GetMPTR() const\n\t{\n\t\treturn m_sysMem.GetMPTR();\n\t}\n\n\tT* operator&() { return (T*)m_sysMem.GetPtr(); }\n\n\tT* operator->() const\n\t{\n\t\treturn this->GetPtr();\n\t}\n\nprivate:\n\tvoid Initialize() override\n\t{\n\t\tif (m_sysMem.GetMPTR() != 0)\n\t\t\treturn;\n\t\t// alloc mem\n\t\tm_sysMem = { coreinit_allocFromSysArea(sizeof(T), 32) };\n\t\t// copy temp buffer to mem and clear it\n\t\t*m_sysMem = m_tempData;\n\t}\n\n\tMEMPTR<T> m_sysMem;\n\tT m_tempData;\n};\n"
  },
  {
    "path": "src/Common/betype.h",
    "content": "#pragma once\n\n#include <type_traits>\n\nnamespace Latte\n{\n\tclass LATTEREG;\n};\n\ntemplate<class T, std::size_t... N>\nconstexpr T bswap_impl(T i, std::index_sequence<N...>)\n{\n\treturn ((((i >> (N * CHAR_BIT)) & (T)(uint8_t)(-1)) << ((sizeof(T) - 1 - N) * CHAR_BIT)) | ...);\n}\n\ntemplate<class T, class U = std::make_unsigned_t<T>>\nconstexpr T bswap(T i)\n{\n\treturn (T)bswap_impl<U>((U)i, std::make_index_sequence<sizeof(T)>{});\n}\n\ntemplate <typename T>\nconstexpr T SwapEndian(T value)\n{\n\tif constexpr (std::is_integral_v<T>)\n\t{\n#ifdef _MSC_VER\n\t\tif constexpr (sizeof(T) == sizeof(uint32_t))\n\t\t{\n\t\t\treturn (T)_byteswap_ulong(value);\n\t\t}\n#endif\n\n\t\treturn (T)bswap((std::make_unsigned_t<T>)value);\n\t}\n\telse if constexpr (std::is_floating_point_v<T>)\n\t{\n\t\tif constexpr (sizeof(T) == sizeof(uint32_t))\n\t\t{\n\t\t\tconst auto tmp = bswap<uint32_t>(*(uint32_t*)&value);\n\t\t\treturn *(T*)&tmp;\n\t\t}\n\t\tif constexpr (sizeof(T) == sizeof(uint64_t))\n\t\t{\n\t\t\tconst auto tmp = bswap<uint64_t>(*(uint64_t*)&value);\n\t\t\treturn *(T*)&tmp;\n\t\t}\n\t}\n\telse if constexpr (std::is_enum_v<T>)\n\t{\n\t\treturn (T)SwapEndian((std::underlying_type_t<T>)value);\n\t}\n\telse if constexpr (std::is_base_of_v<Latte::LATTEREG, T>)\n\t{\n\t\tconst auto tmp = bswap<uint32_t>(*(uint32_t*)&value);\n\t\treturn *(T*)&tmp;\n\t}\n    else\n    {\n        static_assert(std::is_integral_v<T>, \"unsupported betype specialization!\");\n    }\n\n\treturn value;\n}\n\n#ifndef WIN32\n//static_assert(false, \"_BE and _LE need to be adjusted\");\n#endif\n\n// swap if native isn't big endian\ntemplate <typename T>\nconstexpr T _BE(T value)\n{\n\treturn SwapEndian(value);\n}\n\n// swap if native isn't little endian\ntemplate <typename T>\nconstexpr T _LE(T value)\n{\n\treturn value;\n}\n\ntemplate <typename T>\nclass betype\n{\npublic:\n\tconstexpr betype() = default;\n\n\t// copy\n\tconstexpr betype(T value)\n\t\t: m_value(SwapEndian(value)) {}\n\n\tconstexpr betype(const betype& value) = default; // required for trivially_copyable\n\t//constexpr betype(const betype& value)\n\t//\t: m_value(value.m_value) {}\n\n\ttemplate <typename U>\n\tconstexpr betype(const betype<U>& value)\n\t\t: betype((T)value.value()) {}\n\n\t// assigns\n\tstatic betype from_bevalue(T value)\n\t{\n\t\tbetype result;\n\t\tresult.m_value = value;\n\t\treturn result;\n\t}\n\n\t// returns LE value\n\tconstexpr T value() const { return SwapEndian<T>(m_value); }\n\n\t// returns BE value\n\tconstexpr T bevalue() const { return m_value; }\n\n\tconstexpr operator T() const { return value(); }\n\n\tbetype<T>& operator+=(const betype<T>& v)\n\t{\n\t\tm_value = SwapEndian(T(value() + v.value()));\n\t\treturn *this;\n\t}\n\n\tbetype<T>& operator+=(const T& v) requires std::integral<T>\n\t{\n\t\tm_value = SwapEndian(T(value() + v));\n\t\treturn *this;\n\t}\n\n\tbetype<T>& operator-=(const betype<T>& v)\n\t{\n\t\tm_value = SwapEndian(T(value() - v.value()));\n\t\treturn *this;\n\t}\n\n\tbetype<T>& operator*=(const betype<T>& v)\n\t{\n\t\tm_value = SwapEndian(T(value() * v.value()));\n\t\treturn *this;\n\t}\n\n\tbetype<T>& operator/=(const betype<T>& v)\n\t{\n\t\tm_value = SwapEndian(T(value() / v.value()));\n\t\treturn *this;\n\t}\n\n\tbetype<T>& operator&=(const betype<T>& v) requires (requires (T& x, const T& y) { x &= y; })\n\t{\n\t\tm_value &= v.m_value;\n\t\treturn *this;\n\t}\n\n\tbetype<T>& operator|=(const betype<T>& v) requires (requires (T& x, const T& y) { x |= y; })\n\t{\n\t\tm_value |= v.m_value;\n\t\treturn *this;\n\t}\n\n\tbetype<T>& operator|(const betype<T>& v) const requires (requires (T& x, const T& y) { x | y; })\n\t{\n\t\tbetype<T> tmp(*this);\n\t\ttmp.m_value = tmp.m_value | v.m_value;\n\t\treturn tmp;\n\t}\n\n\tbetype<T> operator|(const T& v) const requires (requires (T& x, const T& y) { x | y; })\n\t{\n\t\tbetype<T> tmp(*this);\n\t\ttmp.m_value = tmp.m_value | SwapEndian(v);\n\t\treturn tmp;\n\t}\n\n\tbetype<T>& operator^=(const betype<T>& v) requires std::integral<T>\n\t{\n\t\tm_value ^= v.m_value;\n\t\treturn *this;\n\t}\n\n\tbetype<T>& operator>>=(std::size_t idx) requires std::integral<T>\n\t{\n\t\tm_value = SwapEndian(T(value() >> idx));\n\t\treturn *this;\n\t}\n\n\tbetype<T>& operator<<=(std::size_t idx) requires std::integral<T>\n\t{\n\t\tm_value = SwapEndian(T(value() << idx));\n\t\treturn *this;\n\t}\n\n\tbetype<T> operator~() const requires std::integral<T>\n\t{\n\t\treturn from_bevalue(T(~m_value));\n\t}\n\n\t// pre-increment\n\tbetype<T>& operator++() requires std::integral<T>\n\t{\n\t\tm_value = SwapEndian(T(value() + 1));\n\t\treturn *this;\n\t}\n\n\t// post-increment\n\tbetype<T> operator++(int) requires std::integral<T>\n\t{\n\t\tbetype<T> tmp(*this);\n\t\tm_value = SwapEndian(T(value() + 1));\n\t\treturn tmp;\n\t}\n\n\t// pre-decrement\n\tbetype<T>& operator--() requires std::integral<T>\n\t{\n\t\tm_value = SwapEndian(T(value() - 1));\n\t\treturn *this;\n\t}\n\n\t// post-decrement\n\tbetype<T> operator--(int) requires std::integral<T>\n\t{\n\t\tbetype<T> tmp(*this);\n\t\tm_value = SwapEndian(T(value() - 1));\n\t\treturn tmp;\n\t}\n\nprivate:\n\t//T m_value{}; // before 1.26.2\n\tT m_value;\n};\n\nusing uint64be = betype<uint64>;\nusing uint32be = betype<uint32>;\nusing uint16be = betype<uint16>;\nusing uint8be = betype<uint8>;\n\nusing sint64be = betype<sint64>;\nusing sint32be = betype<sint32>;\nusing sint16be = betype<sint16>;\nusing sint8be = betype<sint8>;\n\nusing float32be = betype<float>;\nusing float64be = betype<double>;\n\nstatic_assert(sizeof(betype<uint64>) == sizeof(uint64));\nstatic_assert(sizeof(betype<uint32>) == sizeof(uint32));\nstatic_assert(sizeof(betype<uint16>) == sizeof(uint16));\nstatic_assert(sizeof(betype<uint8>) == sizeof(uint8));\nstatic_assert(sizeof(betype<float>) == sizeof(float));\nstatic_assert(sizeof(betype<double>) == sizeof(double));\n\nstatic_assert(std::is_trivially_copyable_v<uint32be>);\nstatic_assert(std::is_trivially_constructible_v<uint32be>);\nstatic_assert(std::is_copy_constructible_v<uint32be>);\nstatic_assert(std::is_move_constructible_v<uint32be>);\nstatic_assert(std::is_copy_assignable_v<uint32be>);\nstatic_assert(std::is_move_assignable_v<uint32be>);\n"
  },
  {
    "path": "src/Common/cpu_features.cpp",
    "content": "#include \"cpu_features.h\"\n\n// wrappers with uniform prototype for implementation-specific x86 CPU id\n#if defined(ARCH_X86_64)\n#ifdef __GNUC__\n#include <cpuid.h>\n#endif\n\ninline void cpuid(int cpuInfo[4], int functionId) {\n#if defined(_MSC_VER)\n\t__cpuid(cpuInfo, functionId);\n#elif defined(__GNUC__)\n\t__cpuid(functionId, cpuInfo[0], cpuInfo[1], cpuInfo[2], cpuInfo[3]);\n#else\n#error No definition for cpuid\n#endif\n}\n\ninline void cpuidex(int cpuInfo[4], int functionId, int subFunctionId) {\n#if defined(_MSC_VER)\n\t__cpuidex(cpuInfo, functionId, subFunctionId);\n#elif defined(__GNUC__)\n\t__cpuid_count(functionId, subFunctionId, cpuInfo[0], cpuInfo[1], cpuInfo[2], cpuInfo[3]);\n#else\n#error No definition for cpuidex\n#endif\n}\n#endif\n\n\nCPUFeaturesImpl::CPUFeaturesImpl()\n{\n#if defined(ARCH_X86_64)\n\tint cpuInfo[4];\n\tcpuid(cpuInfo, 0x80000001);\n\tx86.lzcnt = ((cpuInfo[2] >> 5) & 1) != 0;\n\tcpuid(cpuInfo, 0x1);\n\tx86.movbe = ((cpuInfo[2] >> 22) & 1) != 0;\n\tx86.avx = ((cpuInfo[2] >> 28) & 1) != 0;\n\tx86.aesni = ((cpuInfo[2] >> 25) & 1) != 0;\n\tx86.ssse3 = ((cpuInfo[2] >> 9) & 1) != 0;\n\tx86.sse4_1 = ((cpuInfo[2] >> 19) & 1) != 0;\n\tcpuidex(cpuInfo, 0x7, 0);\n\tx86.avx2 = ((cpuInfo[1] >> 5) & 1) != 0;\n\tx86.bmi2 = ((cpuInfo[1] >> 8) & 1) != 0;\n\tcpuid(cpuInfo, 0x80000007);\n\tx86.invariant_tsc = ((cpuInfo[3] >> 8) & 1);\n\t// get CPU brand name\n\tuint32_t nExIds, i = 0;\n\tmemset(m_cpuBrandName, 0, sizeof(m_cpuBrandName));\n\tcpuid(cpuInfo, 0x80000000);\n\tnExIds = (uint32_t)cpuInfo[0];\n\tfor (uint32_t i = 0x80000000; i <= nExIds; ++i)\n\t{\n\t\tcpuid(cpuInfo, i);\n\t\tif (i == 0x80000002)\n\t\t\tmemcpy(m_cpuBrandName, cpuInfo, sizeof(cpuInfo));\n\t\telse if (i == 0x80000003)\n\t\t\tmemcpy(m_cpuBrandName + 16, cpuInfo, sizeof(cpuInfo));\n\t\telse if (i == 0x80000004)\n\t\t\tmemcpy(m_cpuBrandName + 32, cpuInfo, sizeof(cpuInfo));\n\t}\n#endif\n}\n\nstd::string CPUFeaturesImpl::GetCPUName()\n{\n\treturn { m_cpuBrandName };\n}\n\nstd::string CPUFeaturesImpl::GetCommaSeparatedExtensionList()\n{\n\tstd::string tmp;\n\tauto appendExt = [&tmp](const char* str)\n\t{\n\t\tif (!tmp.empty())\n\t\t\ttmp.append(\", \");\n\t\ttmp.append(str);\n\t};\n\tif (x86.ssse3)\n\t\tappendExt(\"SSSE3\");\n\tif (x86.sse4_1)\n\t\tappendExt(\"SSE4.1\");\n\tif (x86.avx)\n\t\tappendExt(\"AVX\");\n\tif (x86.avx2)\n\t\tappendExt(\"AVX2\");\n\tif (x86.lzcnt)\n\t\tappendExt(\"LZCNT\");\n\tif (x86.movbe)\n\t\tappendExt(\"MOVBE\");\n\tif (x86.bmi2)\n\t\tappendExt(\"BMI2\");\n\tif (x86.aesni)\n\t\tappendExt(\"AES-NI\");\n\tif(x86.invariant_tsc)\n\t\tappendExt(\"INVARIANT-TSC\");\n\treturn tmp;\n}\n\nCPUFeaturesImpl g_CPUFeatures;\n"
  },
  {
    "path": "src/Common/cpu_features.h",
    "content": "#ifdef __GNUC__\n#define ATTRIBUTE_AVX2 __attribute__((target(\"avx2\")))\n#define ATTRIBUTE_SSE41 __attribute__((target(\"sse4.1\")))\n#define ATTRIBUTE_AESNI __attribute__((target(\"aes\")))\n#else\n#define ATTRIBUTE_AVX2\n#define ATTRIBUTE_SSE41\n#define ATTRIBUTE_AESNI\n#endif\n\n#include <string>\n\nclass CPUFeaturesImpl\n{\npublic:\n\tCPUFeaturesImpl();\n\n\tstd::string GetCPUName(); // empty if not available\n\tstd::string GetCommaSeparatedExtensionList();\n\n\tstruct\n\t{\n\t\tbool ssse3{ false };\n\t\tbool sse4_1{ false };\n\t\tbool avx{ false };\n\t\tbool avx2{ false };\n\t\tbool lzcnt{ false };\n\t\tbool movbe{ false };\n\t\tbool bmi2{ false };\n\t\tbool aesni{ false };\n\t\tbool invariant_tsc{ false };\n\t}x86;\nprivate:\n\tchar m_cpuBrandName[0x40]{ 0 };\n};\n\nextern CPUFeaturesImpl g_CPUFeatures;\n"
  },
  {
    "path": "src/Common/enumFlags.h",
    "content": "#pragma once\n\n#include <type_traits>\n\n// enum flag helpers\ntemplate<typename TEnum>\nstruct EnableBitMaskOperators\n{\n\tstatic const bool enable = false;\n};\n\ntemplate<typename TEnum>\n\trequires EnableBitMaskOperators<TEnum>::enable\nTEnum operator &(TEnum lhs, TEnum rhs)\n{\n\treturn static_cast<TEnum> (static_cast<typename std::underlying_type<TEnum>::type>(lhs) & static_cast<typename std::underlying_type<TEnum>::type>(rhs));\n}\n\ntemplate<typename TEnum>\n\trequires EnableBitMaskOperators<TEnum>::enable\nTEnum operator |(TEnum lhs, TEnum rhs)\n{\n\treturn static_cast<TEnum> (static_cast<typename std::underlying_type<TEnum>::type>(lhs) | static_cast<typename std::underlying_type<TEnum>::type>(rhs));\n}\n\ntemplate<typename TEnum>\n\trequires EnableBitMaskOperators<TEnum>::enable\nTEnum operator ^(TEnum lhs, TEnum rhs)\n{\n\treturn static_cast<TEnum> (static_cast<typename std::underlying_type<TEnum>::type>(lhs) ^ static_cast<typename std::underlying_type<TEnum>::type>(rhs));\n}\n\ntemplate<typename TEnum>\n\trequires EnableBitMaskOperators<TEnum>::enable\nTEnum operator ~(TEnum rhs)\n{\n\treturn static_cast<TEnum> (~static_cast<typename std::underlying_type<TEnum>::type>(rhs));\n}\n\ntemplate<typename TEnum>\n\trequires EnableBitMaskOperators<TEnum>::enable\nTEnum& operator &=(TEnum& lhs, TEnum rhs)\n{\n\tlhs = static_cast<TEnum> (static_cast<typename std::underlying_type<TEnum>::type>(lhs) & static_cast<typename std::underlying_type<TEnum>::type>(rhs));\n\treturn lhs;\n}\n\ntemplate<typename TEnum>\n\trequires EnableBitMaskOperators<TEnum>::enable\nTEnum& operator |=(TEnum& lhs, TEnum rhs)\n{\n\tlhs = static_cast<TEnum> (static_cast<typename std::underlying_type<TEnum>::type>(lhs) | static_cast<typename std::underlying_type<TEnum>::type>(rhs));\n\treturn lhs;\n}\n\ntemplate<typename TEnum>\n\trequires EnableBitMaskOperators<TEnum>::enable\nTEnum& operator ^=(TEnum& lhs, TEnum rhs)\n{\n\tlhs = static_cast<TEnum> (static_cast<typename std::underlying_type<TEnum>::type>(lhs) ^ static_cast<typename std::underlying_type<TEnum>::type>(rhs));\n\treturn lhs;\n}\n\ntemplate<typename TEnum>\n\trequires EnableBitMaskOperators<TEnum>::enable\nconstexpr bool operator==(TEnum lhs, std::underlying_type_t<TEnum> rhs)\n{\n\treturn static_cast<std::underlying_type_t<TEnum>>(lhs) == rhs;\n}\ntemplate<typename TEnum>\n\trequires EnableBitMaskOperators<TEnum>::enable\nconstexpr bool operator!=(TEnum lhs, std::underlying_type_t<TEnum> rhs)\n{\n\treturn static_cast<std::underlying_type_t<TEnum>>(lhs) != rhs;\n}\n\n#define ENABLE_BITMASK_OPERATORS(x) template<> struct EnableBitMaskOperators<x> { static const bool enable = true; };\n\n\ntemplate<typename TEnum>\nstruct EnableEnumIterators\n{\n\tstatic const bool enable = false;\n};\n\ntemplate<typename TEnum>\n\trequires EnableEnumIterators<TEnum>::enable\nTEnum& operator++(TEnum& lhs) \n{\n\tlhs = static_cast<TEnum>(static_cast<typename std::underlying_type<TEnum>::type>(lhs) + 1);\n\treturn lhs;\n}\n\ntemplate<typename TEnum>\n\trequires EnableEnumIterators<TEnum>::enable\nTEnum operator*(TEnum rhs) \n{\n\treturn rhs;\n}\n\ntemplate<typename TEnum>\n\trequires EnableEnumIterators<TEnum>::enable\nTEnum begin(TEnum value) \n{\n\treturn EnableEnumIterators<TEnum>::begin;\n}\n\ntemplate<typename TEnum>\n\trequires EnableEnumIterators<TEnum>::enable\nTEnum rbegin(TEnum value) \n{\n\treturn EnableEnumIterators<TEnum>::rbegin;\n}\n\ntemplate<typename TEnum>\n\trequires EnableEnumIterators<TEnum>::enable\nTEnum end(TEnum r) {\n\treturn EnableEnumIterators<TEnum>::end;\n}\n\ntemplate<typename TEnum>\n\trequires EnableEnumIterators<TEnum>::enable\nTEnum rend(TEnum r) {\n\treturn EnableEnumIterators<TEnum>::rend;\n}\n\n#define ENABLE_ENUM_ITERATORS(x, first_value, last_value) template<> struct EnableEnumIterators<x> {\\\n\tstatic const bool enable = true;\\\n\tstatic const x begin = first_value;\\\n\tstatic const x rbegin = last_value;\\\n\tstatic const x end = static_cast<x>(static_cast<typename std::underlying_type<x>::type>(last_value) + 1);\\\n\tstatic const x rend = static_cast<x>(static_cast<typename std::underlying_type<x>::type>(first_value) - 1);\\\n};\n// todo: rend type must be signed?\n"
  },
  {
    "path": "src/Common/platform.h",
    "content": "#pragma once\n\n#include <boost/predef/os.h>\n#include <cstdint>\n\n#if BOOST_OS_WINDOWS\n#include \"Common/windows/platform.h\"\n#elif BOOST_OS_LINUX || BOOST_OS_BSD\n#if BOOST_OS_LINUX\n#include <byteswap.h>\n#elif BOOST_OS_BSD\n#include <endian.h>\n#endif\n#include <X11/Xlib.h>\n#include <X11/extensions/Xrender.h>\n#include <X11/Xutil.h>\n#include \"Common/unix/platform.h\"\n#elif BOOST_OS_MACOS\n#include <libkern/OSByteOrder.h>\n#include \"Common/unix/platform.h\"\n#endif\n"
  },
  {
    "path": "src/Common/precompiled.cpp",
    "content": "#include \"precompiled.h\""
  },
  {
    "path": "src/Common/precompiled.h",
    "content": "#pragma once\n\n#include <stdlib.h> // for size_t\n\n#include \"version.h\"\n#include \"platform.h\"\n\n#define FMT_HEADER_ONLY\n#define FMT_USE_GRISU 1\n#include <fmt/core.h>\n#include <fmt/format.h>\n#include <fmt/ranges.h>\n#if FMT_VERSION > 80000\n#include <fmt/xchar.h> // needed for wchar_t support\n#endif\n\n#define SDL_MAIN_HANDLED\n\n// #if FMT_VERSION > 80102\n// // restore generic formatter for enum (class) to underlying. We currently utilize this for HLE call logging\n// template <typename Enum, std::enable_if_t<std::is_enum<Enum>::value, int> = 0>\n// constexpr auto format_as(Enum e) noexcept -> std::underlying_type<Enum> {\n//   return static_cast<std::underlying_type<Enum>>(e);\n// }\n// #endif\n\n// arch defines\n\n#if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64)\n#define ARCH_X86_64\n#endif\n\n// c includes\n#include <cstdint>\n#include <cstdlib>\n#include <cmath>\n#include <ctime>\n#include <cassert>\n\n#if defined(ARCH_X86_64)\n#include <immintrin.h>\n#endif\n\n// c++ includes\n#include <string>\n#include <string_view>\n#include <fstream>\n#include <iostream>\n#include <sstream>\n#include <algorithm>\n\n#include <mutex>\n#include <shared_mutex>\n#include <thread>\n#include <future>\n#include <atomic>\n\n#include <vector>\n#include <unordered_map>\n#include <unordered_set>\n#include <map>\n#include <set>\n#include <queue>\n#include <stack>\n#include <array>\n#include <bitset>\n#include <bit>\n\n#include <filesystem>\n#include <memory>\n#include <chrono>\n#include <ctime>\n#include <regex>\n#include <type_traits>\n#include <optional>\n#include <span>\n#include <ranges>\n\n#include <boost/predef.h>\n#include <boost/nowide/convert.hpp>\n#include <boost/algorithm/string.hpp>\n#include <boost/asio.hpp>\n#include <glm/glm.hpp>\n#include <glm/gtc/quaternion.hpp>\n\nnamespace fs = std::filesystem;\n\n#include \"enumFlags.h\"\n\n// base types\nusing uint64 = uint64_t;\nusing uint32 = uint32_t;\nusing uint16 = uint16_t;\nusing uint8 = uint8_t;\n\nusing sint64 = int64_t;\nusing sint32 = int32_t;\nusing sint16 = int16_t;\nusing sint8 = int8_t;\n\n#if _MSC_VER\n#ifndef _SSIZE_T_DEFINED\n#define _SSIZE_T_DEFINED\n#include <basetsd.h>\ntypedef SSIZE_T ssize_t;\n#endif\n#endif\n\n// types with explicit big endian order\n#include \"betype.h\"\n\n// types with explicit little endian order (on a big-endian system these would be implemented like betype.h)\nusing uint64le = uint64_t;\nusing uint32le = uint32_t;\nusing uint16le = uint16_t;\nusing uint8le = uint8_t;\n\n// logging\n#include \"Cemu/Logging/CemuDebugLogging.h\"\n#include \"Cemu/Logging/CemuLogging.h\"\n\n// localization\nnamespace\n{\n\tstd::function<std::string(std::string_view)> g_translate;\n}\n\ninline void SetTranslationCallback(std::function<std::string(std::string_view)> translate)\n{\n\tg_translate = translate;\n}\n\n#define TR_NOOP(str) str\n\ninline std::string _tr(std::string_view text)\n{\n\tif (g_translate)\n\t\treturn g_translate(text);\n\n\treturn std::string{text};\n}\n\ntemplate<typename... TArgs>\ninline std::string _tr(fmt::format_string<TArgs...> text, TArgs... args)\n{\n\tif (g_translate)\n\t{\n\t\tstd::string_view textSV{text.get().data(), text.get().size()};\n\t\treturn fmt::format(fmt::runtime(g_translate(textSV)), std::forward<TArgs>(args)...);\n\t}\n\n\treturn fmt::format(text, std::forward<TArgs>(args)...);\n}\n\n// manual endian-swapping\n\n#if _MSC_VER\ninline uint64 _swapEndianU64(uint64 v)\n{\n\treturn _byteswap_uint64(v);\n}\n\ninline uint32 _swapEndianU32(uint32 v)\n{\n\treturn _byteswap_ulong(v);\n}\n\ninline sint32 _swapEndianS32(sint32 v)\n{\n\treturn (sint32)_byteswap_ulong((uint32)v);\n}\n\ninline uint16 _swapEndianU16(uint16 v)\n{\n\treturn (v >> 8) | (v << 8);\n}\n\ninline sint16 _swapEndianS16(sint16 v)\n{\n\treturn (sint16)(((uint16)v >> 8) | ((uint16)v << 8));\n}\n#else\ninline uint64 _swapEndianU64(uint64 v)\n{\n#if BOOST_OS_MACOS\n    return OSSwapInt64(v);\n#elif BOOST_OS_BSD\n#ifdef __OpenBSD__\n    return swap64(v);\n#else // FreeBSD and NetBSD\n    return bswap64(v);\n#endif\n#else\n    return bswap_64(v);\n#endif\n}\n\ninline uint32 _swapEndianU32(uint32 v)\n{\n#if BOOST_OS_MACOS\n    return OSSwapInt32(v);\n#elif BOOST_OS_BSD\n#ifdef __OpenBSD__\n    return swap32(v);\n#else // FreeBSD and NetBSD\n    return bswap32(v);\n#endif\n#else\n    return bswap_32(v);\n#endif\n}\n\ninline sint32 _swapEndianS32(sint32 v)\n{\n#if BOOST_OS_MACOS\n    return (sint32)OSSwapInt32((uint32)v);\n#elif BOOST_OS_BSD\n#ifdef __OpenBSD__\n    return (sint32)swap32((uint32)v);\n#else // FreeBSD and NetBSD\n    return (sint32)bswap32((uint32)v);\n#endif\n#else\n    return (sint32)bswap_32((uint32)v);\n#endif\n}\n\ninline uint16 _swapEndianU16(uint16 v)\n{\n    return (v >> 8) | (v << 8);\n}\n\ninline sint16 _swapEndianS16(sint16 v)\n{\n    return (sint16)(((uint16)v >> 8) | ((uint16)v << 8));\n}\n\ninline uint64 _umul128(uint64 multiplier, uint64 multiplicand, uint64 *highProduct) {\n    unsigned __int128 x = (unsigned __int128)multiplier * (unsigned __int128)multiplicand;\n    *highProduct = (x >> 64);\n    return x & 0xFFFFFFFFFFFFFFFF;\n}\n\ntypedef uint8_t BYTE;\ntypedef uint32_t DWORD;\ntypedef int32_t LONG;\ntypedef int64_t LONGLONG;\n\ntypedef union _LARGE_INTEGER {\n    struct {\n        DWORD LowPart;\n        LONG  HighPart;\n    };\n    struct {\n        DWORD LowPart;\n        LONG  HighPart;\n    } u;\n    LONGLONG QuadPart;\n} LARGE_INTEGER, *PLARGE_INTEGER;\n\n#define DEFINE_ENUM_FLAG_OPERATORS(T)                                                                                                                                            \\\n    inline T operator~ (T a) { return static_cast<T>( ~static_cast<std::underlying_type<T>::type>(a) ); }                                                                       \\\n    inline T operator| (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) | static_cast<std::underlying_type<T>::type>(b) ); }                   \\\n    inline T operator& (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) & static_cast<std::underlying_type<T>::type>(b) ); }                   \\\n    inline T operator^ (T a, T b) { return static_cast<T>( static_cast<std::underlying_type<T>::type>(a) ^ static_cast<std::underlying_type<T>::type>(b) ); }                   \\\n    inline T& operator|= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) |= static_cast<std::underlying_type<T>::type>(b) ); }   \\\n    inline T& operator&= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) &= static_cast<std::underlying_type<T>::type>(b) ); }   \\\n    inline T& operator^= (T& a, T b) { return reinterpret_cast<T&>( reinterpret_cast<std::underlying_type<T>::type&>(a) ^= static_cast<std::underlying_type<T>::type>(b) ); }\n#endif\n\ntemplate<typename T>\ninline T GetBits(T value, uint32 index, uint32 numBits)\n{\n\tT mask = (1<<numBits)-1;\n\treturn (value>>index) & mask;\n}\n\ntemplate<typename T>\ninline void SetBits(T& value, uint32 index, uint32 numBits, uint32 bitValue)\n{\n\tT mask = (1<<numBits)-1;\n\tvalue &= ~(mask << index);\n\tvalue |= (bitValue << index);\n}\n\n#if !defined(_MSC_VER) || defined(__clang__) // clang-cl does not have built-in _udiv128\ninline uint64 _udiv128(uint64 highDividend, uint64 lowDividend, uint64 divisor, uint64 *remainder)\n{\n    unsigned __int128 dividend = (((unsigned __int128)highDividend) << 64) | ((unsigned __int128)lowDividend);\n    *remainder = (uint64)((dividend % divisor) & 0xFFFFFFFFFFFFFFFF);\n    return       (uint64)((dividend / divisor) & 0xFFFFFFFFFFFFFFFF);\n}\n#endif\n\n#if defined(_MSC_VER)\n    #define UNREACHABLE __assume(false)\n\t#define ASSUME(__cond) __assume(__cond)\n\t#define TLS_WORKAROUND_NOINLINE // no-op for MSVC as it has a flag for fiber-safe TLS optimizations\n#elif defined(__GNUC__) && !defined(__llvm__)\n    #define UNREACHABLE __builtin_unreachable()\n\t#define ASSUME(__cond) __attribute__((assume(__cond)))\n\t#define TLS_WORKAROUND_NOINLINE __attribute__((noinline))\n#elif defined(__clang__)\n\t#define UNREACHABLE __builtin_unreachable()\n\t#define ASSUME(__cond) __builtin_assume(__cond)\n\t#define TLS_WORKAROUND_NOINLINE __attribute__((noinline))\n#else\n    #error Unknown compiler\n#endif\n\n#if defined(_MSC_VER)\n    #define DEBUG_BREAK __debugbreak()\n#else\n    #include <csignal>\n    #define DEBUG_BREAK raise(SIGTRAP) \n#endif\n\n#if defined(_MSC_VER)\n    #define DLLEXPORT __declspec(dllexport)\n#elif defined(__GNUC__)\n    #if BOOST_OS_WINDOWS\n        #define DLLEXPORT __attribute__((dllexport))\n    #else\n        #define DLLEXPORT\n    #endif\n#else\n    #error No definition for DLLEXPORT\n#endif\n\n#if BOOST_OS_WINDOWS\n\t#define NOEXPORT\n#elif defined(__GNUC__)\n\t#define NOEXPORT __attribute__ ((visibility (\"hidden\")))\n#endif\n\n#if defined(_MSC_VER)\n#define FORCE_INLINE __forceinline\n#elif defined(__GNUC__) || defined(__clang__)\n#define FORCE_INLINE inline __attribute__((always_inline))\n#else\n#define FORCE_INLINE inline\n#endif\n\nFORCE_INLINE int BSF(uint32 v) // returns index of first bit set, counting from LSB. If v is 0 then result is undefined\n{\n#if defined(_MSC_VER)\n\treturn _tzcnt_u32(v); // TZCNT requires BMI1. But if not supported it will execute as BSF\n#elif defined(__GNUC__) || defined(__clang__)\n\treturn __builtin_ctz(v);\n#else\n\treturn std::countr_zero(v);\n#endif\n}\n\n// On aarch64 we handle some of the x86 intrinsics by implementing them as wrappers\n#if defined(__aarch64__)\n\ninline void _mm_pause()\n{\n    asm volatile(\"yield\");\n}\n\ninline uint64 __rdtsc()\n{\n    uint64 t;\n    asm volatile(\"mrs %0, cntvct_el0\" : \"=r\" (t));\n    return t;\n}\n\ninline void _mm_mfence()\n{\n\tasm volatile(\"\" ::: \"memory\");\n\tstd::atomic_thread_fence(std::memory_order_seq_cst);\n}\n\ninline unsigned char _addcarry_u64(unsigned char carry, unsigned long long a, unsigned long long b, unsigned long long *result)\n{\n    *result = a + b + (unsigned long long)carry;\n    if (*result < a)\n        return 1;\n    return 0;\n}\n\n#endif\n\n// asserts\n\n\ninline void cemu_assert(bool _condition)\n{\n    if ((_condition) == false)\n    {\n        DEBUG_BREAK;\n    }\n}\n\n#ifndef CEMU_DEBUG_ASSERT\n//#define cemu_assert_debug(__cond) -> Forcing __cond not to be evaluated currently has unexpected side-effects\n\ninline void cemu_assert_debug(bool _condition)\n{\n}\n\ninline void cemu_assert_unimplemented()\n{\n}\n\ninline void cemu_assert_suspicious()\n{\n}\n\ninline void cemu_assert_error()\n{\n\tDEBUG_BREAK;\n}\n#else\ninline void cemu_assert_debug(bool _condition)\n{\n    if ((_condition) == false)\n        DEBUG_BREAK;\n}\n\ninline void cemu_assert_unimplemented()\n{\n    DEBUG_BREAK;\n}\n\ninline void cemu_assert_suspicious()\n{\n    DEBUG_BREAK;\n}\n\ninline void cemu_assert_error()\n{\n    DEBUG_BREAK;\n}\n#endif\n\n#define assert_dbg() DEBUG_BREAK // old style unconditional generic assert\n\n// MEMPTR\n#include \"Common/MemPtr.h\"\n\ntemplate <typename T1, typename T2>\nconstexpr bool HAS_FLAG(T1 flags, T2 test_flag) { return (flags & (T1)test_flag) == (T1)test_flag; }\ntemplate <typename T1, typename T2>\nconstexpr bool HAS_BIT(T1 value, T2 index) { return (value & ((T1)1 << index)) != 0; }\n\ntemplate <typename T>\nconstexpr uint32_t ppcsizeof() { return (uint32_t) sizeof(T); }\n\n// common utility functions\n\ntemplate <typename T>\nvoid vectorAppendUnique(std::vector<T>& vec, const T& val) // for cases where a small vector is more efficient than a set\n{\n    if (std::find(vec.begin(), vec.end(), val) != vec.end())\n        return;\n    vec.emplace_back(val);\n}\n\ntemplate <typename T>\nvoid vectorRemoveByValue(std::vector<T>& vec, const T& val)\n{\n    vec.erase(std::remove(vec.begin(), vec.end(), val), vec.end());\n}\n\ntemplate <typename T>\nvoid vectorRemoveByIndex(std::vector<T>& vec, const size_t index)\n{\n    vec.erase(vec.begin() + index);\n}\n\ntemplate<typename T1, typename... Types>\nbool match_any_of(T1&& value, Types&&... others)\n{\n    return ((value == others) || ...);\n}\n\n// we cache the frequency in a static variable\n[[nodiscard]] static std::chrono::high_resolution_clock::time_point now_cached() noexcept\n{\n#ifdef _WIN32\n    // get current time\n\tstatic const long long _Freq = _Query_perf_frequency();\t// doesn't change after system boot\n\tconst long long _Ctr = _Query_perf_counter();\n\tstatic_assert(std::nano::num == 1, \"This assumes period::num == 1.\");\n\tconst long long _Whole = (_Ctr / _Freq) * std::nano::den;\n\tconst long long _Part = (_Ctr % _Freq) * std::nano::den / _Freq;\n\treturn (std::chrono::high_resolution_clock::time_point(std::chrono::nanoseconds(_Whole + _Part)));\n#else\n    return std::chrono::high_resolution_clock::now();\n#endif\n}\n\n[[nodiscard]] static std::chrono::steady_clock::time_point tick_cached() noexcept\n{\n#if BOOST_OS_WINDOWS\n    // get current time\n\tstatic const long long _Freq = _Query_perf_frequency();\t// doesn't change after system boot\n\tconst long long _Ctr = _Query_perf_counter();\n\tstatic_assert(std::nano::num == 1, \"This assumes period::num == 1.\");\n\tconst long long _Whole = (_Ctr / _Freq) * std::nano::den;\n\tconst long long _Part = (_Ctr % _Freq) * std::nano::den / _Freq;\n\treturn (std::chrono::steady_clock::time_point(std::chrono::nanoseconds(_Whole + _Part)));\n#elif BOOST_OS_LINUX\n\tstruct timespec tp;\n\tclock_gettime(CLOCK_MONOTONIC_RAW, &tp);\n\treturn std::chrono::steady_clock::time_point(\n\t\tstd::chrono::seconds(tp.tv_sec) + std::chrono::nanoseconds(tp.tv_nsec));\n#elif BOOST_OS_MACOS\n\treturn std::chrono::steady_clock::time_point(\n\t\tstd::chrono::nanoseconds(clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW)));\n#elif BOOST_OS_BSD\n\tstruct timespec tp;\n\tclock_gettime(CLOCK_MONOTONIC, &tp);\n\treturn std::chrono::steady_clock::time_point(\n\t\tstd::chrono::seconds(tp.tv_sec) + std::chrono::nanoseconds(tp.tv_nsec));\n#endif\n}\n\n// Some string conversion helpers because C++20 std::u8string is too cumbersome to use in practice\n// mixing string types generally causes loads of issues and many of the libraries we use dont expose interfaces for u8string\n\ninline const char* _utf8WrapperPtr(const char8_t* input)\n{\n    // use with care\n    return (const char*)input;\n}\n\ninline std::string_view _utf8Wrapper(std::u8string_view input)\n{\n    std::basic_string_view<char> v((char*)input.data(), input.size());\n    return v;\n}\n\n// convert fs::path to utf8 encoded string\ninline std::string _pathToUtf8(const fs::path& path)\n{\n    std::u8string strU8 = path.generic_u8string();\n    std::string v((const char*)strU8.data(), strU8.size());\n    return v;\n}\n\n// convert utf8 encoded string to fs::path\ninline fs::path _utf8ToPath(std::string_view input)\n{\n    std::basic_string_view<char8_t> v((char8_t*)input.data(), input.size());\n    return fs::path(v);\n}\n\n// locale-independent variant of tolower() which also matches Wii U behavior\ninline char _ansiToLower(char c)\n{\n\tif (c >= 'A' && c <= 'Z')\n\t\tc -= ('A' - 'a');\n\treturn c;\n}\n\nclass RunAtCemuBoot // -> replaces this with direct function calls. Linkers other than MSVC may optimize way object files entirely if they are not referenced from outside. So a source file self-registering using this would be causing issues\n{\npublic:\n    RunAtCemuBoot(void(*f)())\n    {\n        f();\n    }\n};\n\n// temporary wrapper until Concurrency TS gives us std::future .is_ready()\ntemplate<typename T>\nbool future_is_ready(std::future<T>& f)\n{\n#if defined(__GNUC__)\n    return f.wait_for(std::chrono::nanoseconds(0)) == std::future_status::ready;\n#else\n\treturn f._Is_ready();\n#endif\n}\n\n\n// helper function to cast raw pointers to std::atomic\n// this is technically not legal but works on most platforms as long as alignment restrictions are met and the implementation of atomic doesnt come with additional members\n\ntemplate<typename T>\nstd::atomic<T>* _rawPtrToAtomic(T* ptr)\n{\n\tstatic_assert(sizeof(T) == sizeof(std::atomic<T>));\n\tcemu_assert_debug((reinterpret_cast<std::uintptr_t>(ptr) % alignof(std::atomic<T>)) == 0);\n    return reinterpret_cast<std::atomic<T>*>(ptr);\n}\n\n#if defined(__GNUC__)\n#define ATTR_MS_ABI __attribute__((ms_abi))\n#else\n#define ATTR_MS_ABI\n#endif\n\n#if !defined(TRUE) or !defined(FALSE)\n#define TRUE (1)\n#define FALSE (0)\n#endif\n\ninline uint32 GetTitleIdHigh(uint64 titleId)\n{\n\treturn titleId >> 32;\n}\n\ninline uint32 GetTitleIdLow(uint64 titleId)\n{\n\treturn titleId & 0xFFFFFFFF;\n}\n\n#if defined(__GNUC__)\n#define memcpy_dwords(__dest, __src, __numDwords) memcpy((__dest), (__src), (__numDwords) * sizeof(uint32))\n#define memcpy_qwords(__dest, __src, __numQwords) memcpy((__dest), (__src), (__numQwords) * sizeof(uint64))\n#else\n#define memcpy_dwords(__dest, __src, __numDwords) __movsd((unsigned long*)(__dest), (const unsigned long*)(__src), __numDwords)\n#define memcpy_qwords(__dest, __src, __numQwords) __movsq((unsigned long long*)(__dest), (const unsigned long long*)(__src), __numQwords)\n#endif\n\n// PPC context and memory functions\n#include \"Cafe/HW/MMU/MMU.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"Cafe/HW/Espresso/PPCCallback.h\"\n\n// PPC stack trace printer\nvoid DebugLogStackTrace(struct OSThread_t* thread, MPTR sp, bool printSymbols = false);\n\n// generic formatter for enums (to underlying)\ntemplate <typename Enum>\n\trequires std::is_enum_v<Enum>\nstruct fmt::formatter<Enum> : fmt::formatter<underlying_t<Enum>>\n{\n\tauto format(const Enum& e, format_context& ctx) const\n\t{\n\t\t//return fmt::format_to(ctx.out(), \"{}\", fmt::underlying(e));\n\n\t\treturn formatter<underlying_t<Enum>>::format(fmt::underlying(e), ctx);\n\t}\n};\n\n// formatter for betype<T>\ntemplate <typename T>\nstruct fmt::formatter<betype<T>> : fmt::formatter<T>\n{\n\tauto format(const betype<T>& e, format_context& ctx) const\n\t{\n\t\treturn formatter<T>::format(static_cast<T>(e), ctx);\n\t}\n};\n\n// useful future C++ stuff\nnamespace stdx\n{\n\t// std::to_underlying\n    template <typename EnumT>\n\t\trequires (std::is_enum_v<EnumT>)\n        constexpr std::underlying_type_t<EnumT> to_underlying(EnumT e) noexcept {\n        return static_cast<std::underlying_type_t<EnumT>>(e);\n    };\n\n\t// std::scope_exit\n\ttemplate <typename Fn>\n\tclass scope_exit\n\t{\n\t\tFn m_func;\n\t\tbool m_released = false;\n\tpublic:\n\t\texplicit scope_exit(Fn&& f) noexcept\n\t\t\t: m_func(std::forward<Fn>(f))\n\t\t{}\n\t\t~scope_exit()\n\t\t{\n\t\t\tif (!m_released) m_func();\n\t\t}\n\t\tscope_exit(scope_exit&& other) noexcept\n\t\t\t: m_func(std::move(other.m_func)), m_released(std::exchange(other.m_released, true))\n\t\t{}\n\t\tscope_exit(const scope_exit&) = delete;\n\t\tscope_exit& operator=(scope_exit) = delete;\n\t\tvoid release() { m_released = true;}\n\t};\n\n\t// Xcode 16 doesn't have std::atomic_ref support and we provide a minimalist reimplementation as fallback\n#ifdef __cpp_lib_atomic_ref\n\t#include <atomic>\n\ttemplate<typename T>\n\tusing atomic_ref = std::atomic_ref<T>;\n#else\n\ttemplate<typename T>\n\tclass atomic_ref\n\t{\n\t\tstatic_assert(std::is_trivially_copyable_v<T>, \"atomic_ref requires trivially copyable types\");\n\tpublic:\n\t\tusing value_type = T;\n\n\t\texplicit atomic_ref(T& obj) noexcept : ptr_(std::addressof(obj)) {}\n\n\t\tT load(std::memory_order order = std::memory_order_seq_cst) const noexcept\n\t\t{\n\t\t\tauto aptr = reinterpret_cast<std::atomic<T>*>(ptr_);\n\t\t\treturn aptr->load(order);\n\t\t}\n\n\t\tvoid store(T desired, std::memory_order order = std::memory_order_seq_cst) const noexcept\n\t\t{\n\t\t\tauto aptr = reinterpret_cast<std::atomic<T>*>(ptr_);\n\t\t\taptr->store(desired, order);\n\t\t}\n\n\tprivate:\n\t\tT* ptr_;\n\t};\n#endif\n}\n"
  },
  {
    "path": "src/Common/socket.h",
    "content": "#pragma once\n\n#if BOOST_OS_WINDOWS\n\n#include <WinSock2.h>\ntypedef int socklen_t;\n\n#else\n\n#include <sys/socket.h>\n#define SOCKET int\n#define closesocket close\n#define SOCKET_ERROR -1\n#define INVALID_SOCKET -1\n\n#endif\n"
  },
  {
    "path": "src/Common/unix/FileStream_unix.cpp",
    "content": "#include \"Common/unix/FileStream_unix.h\"\n#include <cstdarg>\n\nfs::path findPathCI(const fs::path& path)\n{\n\tif (fs::exists(path)) return path;\n\n\tfs::path fName = path.filename();\n\tfs::path parentPath = path.parent_path();\n\tif (!fs::exists(parentPath))\n\t{\n\t\tauto CIParent = findPathCI(parentPath);\n\t\tif (fs::exists(CIParent))\n\t\t\treturn findPathCI(CIParent / fName);\n\t}\n\n\tstd::error_code listErr;\n\tfor (auto&& dirEntry : fs::directory_iterator(parentPath, listErr))\n\t\tif (boost::iequals(dirEntry.path().filename().string(), fName.string()))\n\t\t\treturn dirEntry;\n\n\treturn parentPath / fName;\n}\n\nFileStream* FileStream::openFile(std::string_view path)\n{\n\treturn openFile2(path, false);\n}\n\nFileStream* FileStream::openFile(const wchar_t* path, bool allowWrite)\n{\n\treturn openFile2(path, allowWrite);\n}\n\nFileStream* FileStream::openFile2(const fs::path& path, bool allowWrite)\n{\n\tFileStream* fs = new FileStream(path, true, allowWrite);\n\tif (fs->m_isValid)\n\t\treturn fs;\n\tdelete fs;\n\treturn nullptr;\n}\n\nFileStream* FileStream::createFile(const wchar_t* path)\n{\n\treturn createFile2(path);\n}\n\nFileStream* FileStream::createFile(std::string_view path)\n{\n\treturn createFile2(path);\n}\n\nFileStream* FileStream::createFile2(const fs::path& path)\n{\n\tFileStream* fs = new FileStream(path, false, false);\n\tif (fs->m_isValid)\n\t\treturn fs;\n\tdelete fs;\n\treturn nullptr;\n}\n\nstd::optional<std::vector<uint8>> FileStream::LoadIntoMemory(const fs::path& path)\n{\n\tFileStream* fs = openFile2(path);\n\tif (!fs)\n\t\treturn std::nullopt;\n\tuint64 fileSize = fs->GetSize();\n\tif (fileSize > 0xFFFFFFFFull)\n\t{\n\t\tdelete fs;\n\t\treturn std::nullopt;\n\t}\n\tstd::optional<std::vector<uint8>> v(fileSize);\n\tif (fs->readData(v->data(), (uint32)fileSize) != (uint32)fileSize)\n\t{\n\t\tdelete fs;\n\t\treturn std::nullopt;\n\t}\n\tdelete fs;\n\treturn v;\n}\n\nvoid FileStream::SetPosition(uint64 pos)\n{\n\tcemu_assert(m_isValid);\n\tif (m_prevOperationWasWrite)\n\t\tm_fileStream.seekp((std::streampos)pos);\n\telse\n\t\tm_fileStream.seekg((std::streampos)pos);\n}\n\nuint64 FileStream::GetSize()\n{\n\tcemu_assert(m_isValid);\n\tauto currentPos = m_fileStream.tellg();\n\tm_fileStream.seekg(0, std::ios::end);\n\tauto fileSize = m_fileStream.tellg();\n\tm_fileStream.seekg(currentPos, std::ios::beg);\n\tuint64 fs = (uint64)fileSize;\n\treturn fs;\n}\n\nbool FileStream::SetEndOfFile()\n{\n\tassert_dbg();\n\treturn true;\n\t//return ::SetEndOfFile(m_hFile) != 0;\n}\n\nvoid FileStream::extract(std::vector<uint8>& data)\n{\n\tuint64 fileSize = GetSize();\n\tSetPosition(0);\n\tdata.resize(fileSize);\n\treadData(data.data(), fileSize);\n}\n\nvoid FileStream::Flush()\n{\n    m_fileStream.flush();\n}\n\nuint32 FileStream::readData(void* data, uint32 length)\n{\n\tSyncReadWriteSeek(false);\n\tm_fileStream.read((char*)data, length);\n\tsize_t bytesRead = m_fileStream.gcount();\n\treturn (uint32)bytesRead;\n}\n\nbool FileStream::readU64(uint64& v)\n{\n\treturn readData(&v, sizeof(uint64)) == sizeof(uint64);\n}\n\nbool FileStream::readU32(uint32& v)\n{\n\treturn readData(&v, sizeof(uint32)) == sizeof(uint32);\n}\n\nbool FileStream::readU8(uint8& v)\n{\n\treturn readData(&v, sizeof(uint8)) == sizeof(uint8);\n}\n\nbool FileStream::readLine(std::string& line)\n{\n\tline.clear();\n\tuint8 c;\n\tbool isEOF = true;\n\twhile (readU8(c))\n\t{\n\t\tisEOF = false;\n\t\tif (c == '\\r')\n\t\t\tcontinue;\n\t\tif (c == '\\n')\n\t\t\tbreak;\n\t\tline.push_back((char)c);\n\t}\n\treturn !isEOF;\n}\n\nsint32 FileStream::writeData(const void* data, sint32 length)\n{\n\tSyncReadWriteSeek(true);\n\tm_fileStream.write((const char*)data, length);\n\treturn length;\n}\n\nvoid FileStream::writeU64(uint64 v)\n{\n\twriteData(&v, sizeof(uint64));\n}\n\nvoid FileStream::writeU32(uint32 v)\n{\n\twriteData(&v, sizeof(uint32));\n}\n\nvoid FileStream::writeU8(uint8 v)\n{\n\twriteData(&v, sizeof(uint8));\n}\n\nvoid FileStream::writeStringFmt(const char* format, ...)\n{\n\tchar buffer[2048];\n\tva_list args;\n\tva_start(args, format);\n\tvsnprintf(buffer, sizeof(buffer), format, args);\n\twriteData(buffer, (sint32)strlen(buffer));\n}\n\nvoid FileStream::writeString(const char* str)\n{\n\twriteData(str, (sint32)strlen(str));\n}\n\nvoid FileStream::writeLine(const char* str)\n{\n\twriteData(str, (sint32)strlen(str));\n\twriteData(\"\\r\\n\", 2);\n}\n\nFileStream::~FileStream()\n{\n\tif (m_isValid)\n\t{\n\t\tm_fileStream.close();\n\t}\n\t//\tCloseHandle(m_hFile);\n}\n\nFileStream::FileStream(const fs::path& path, bool isOpen, bool isWriteable)\n{\n\tfs::path CIPath = findPathCI(path);\n\tif (isOpen)\n\t{\n\t\tm_fileStream.open(CIPath, isWriteable ? (std::ios_base::in | std::ios_base::out | std::ios_base::binary) : (std::ios_base::in | std::ios_base::binary));\n\t\tm_isValid = m_fileStream.is_open();\n\t}\n\telse\n\t{\n\t\tm_fileStream.open(CIPath, std::ios_base::in | std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);\n\t\tm_isValid = m_fileStream.is_open();\n\t}\n\tif(m_isValid && fs::is_directory(path))\n\t{\n\t\tm_isValid = false;\n\t\tm_fileStream.close();\n\t}\n}\n\nvoid FileStream::SyncReadWriteSeek(bool nextOpIsWrite)\n{\n\t// nextOpIsWrite == false -> read. Otherwise write\n\tif (nextOpIsWrite == m_prevOperationWasWrite)\n\t\treturn;\n\tif (nextOpIsWrite)\n\t\tm_fileStream.seekp(m_fileStream.tellg(), std::ios::beg);\n\telse\n\t\tm_fileStream.seekg(m_fileStream.tellp(), std::ios::beg);\n\n\tm_prevOperationWasWrite = nextOpIsWrite;\n}\n"
  },
  {
    "path": "src/Common/unix/FileStream_unix.h",
    "content": "#pragma once\n#include \"Common/precompiled.h\"\n\nclass FileStream\n{\n public:\n\tstatic FileStream* openFile(std::string_view path);\n\tstatic FileStream* openFile(const wchar_t* path, bool allowWrite = false);\n\tstatic FileStream* openFile2(const fs::path& path, bool allowWrite = false);\n\n\tstatic FileStream* createFile(const wchar_t* path);\n\tstatic FileStream* createFile(std::string_view path);\n\tstatic FileStream* createFile2(const fs::path& path);\n\n\t// helper function to load a file into memory\n\tstatic std::optional<std::vector<uint8>> LoadIntoMemory(const fs::path& path);\n\n\t// size and seek\n\tvoid SetPosition(uint64 pos);\n\n\tuint64 GetSize();\n\tbool SetEndOfFile();\n\tvoid extract(std::vector<uint8>& data);\n\n\tvoid Flush();\n\n\t// reading\n\tuint32 readData(void* data, uint32 length);\n\tbool readU64(uint64& v);\n\tbool readU32(uint32& v);\n\tbool readU16(uint16& v);\n\tbool readU8(uint8& v);\n\tbool readLine(std::string& line);\n\n\t// writing (binary)\n\tsint32 writeData(const void* data, sint32 length);\n\tvoid writeU64(uint64 v);\n\tvoid writeU32(uint32 v);\n\tvoid writeU16(uint16 v);\n\tvoid writeU8(uint8 v);\n\n\t// writing (strings)\n\tvoid writeStringFmt(const char* format, ...);\n\tvoid writeString(const char* str);\n\tvoid writeLine(const char* str);\n\n\t~FileStream();\n\tFileStream() {};\n\n private:\n\tvoid SyncReadWriteSeek(bool nextOpIsWrite);\n\tFileStream(const fs::path& path, bool isOpen, bool isWriteable);\n\n\tbool m_isValid{};\n\tstd::fstream m_fileStream;\n\tbool m_prevOperationWasWrite{false};\n\n};\n"
  },
  {
    "path": "src/Common/unix/date.h",
    "content": "#ifndef DATE_H\n#define DATE_H\n\n// The MIT License (MIT)\n//\n// Copyright (c) 2015, 2016, 2017 Howard Hinnant\n// Copyright (c) 2016 Adrian Colomitchi\n// Copyright (c) 2017 Florian Dang\n// Copyright (c) 2017 Paul Thompson\n// Copyright (c) 2018, 2019 Tomasz Kamiński\n// Copyright (c) 2019 Jiangang Zhuang\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// Our apologies.  When the previous paragraph was written, lowercase had not yet\n// been invented (that would involve another several millennia of evolution).\n// We did not mean to shout.\n\n#ifndef HAS_STRING_VIEW\n#  if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)\n#    define HAS_STRING_VIEW 1\n#  else\n#    define HAS_STRING_VIEW 0\n#  endif\n#endif  // HAS_STRING_VIEW\n\n#include <cassert>\n#include <algorithm>\n#include <cctype>\n#include <chrono>\n#include <climits>\n#include <cmath>\n#include <cstddef>\n#include <cstdint>\n#include <cstdlib>\n#include <ctime>\n#include <ios>\n#include <istream>\n#include <iterator>\n#include <limits>\n#include <locale>\n#include <memory>\n#include <ostream>\n#include <ratio>\n#include <sstream>\n#include <stdexcept>\n#include <string>\n#if HAS_STRING_VIEW\n# include <string_view>\n#endif\n#include <utility>\n#include <type_traits>\n\n#ifdef __GNUC__\n# pragma GCC diagnostic push\n# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7)\n#  pragma GCC diagnostic ignored \"-Wpedantic\"\n# endif\n# if __GNUC__ < 5\n   // GCC 4.9 Bug 61489 Wrong warning with -Wmissing-field-initializers\n#  pragma GCC diagnostic ignored \"-Wmissing-field-initializers\"\n# endif\n#endif\n\n#ifdef _MSC_VER\n#   pragma warning(push)\n// warning C4127: conditional expression is constant\n#   pragma warning(disable : 4127)\n#endif\n\nnamespace date\n{\n\n//---------------+\n// Configuration |\n//---------------+\n\n#ifndef ONLY_C_LOCALE\n#  define ONLY_C_LOCALE 0\n#endif\n\n#if defined(_MSC_VER) && (!defined(__clang__) || (_MSC_VER < 1910))\n// MSVC\n#  ifndef _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING\n#    define _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING\n#  endif\n#  if _MSC_VER < 1910\n//   before VS2017\n#    define CONSTDATA const\n#    define CONSTCD11\n#    define CONSTCD14\n#    define NOEXCEPT _NOEXCEPT\n#  else\n//   VS2017 and later\n#    define CONSTDATA constexpr const\n#    define CONSTCD11 constexpr\n#    define CONSTCD14 constexpr\n#    define NOEXCEPT noexcept\n#  endif\n\n#elif defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x5150\n// Oracle Developer Studio 12.6 and earlier\n#  define CONSTDATA constexpr const\n#  define CONSTCD11 constexpr\n#  define CONSTCD14\n#  define NOEXCEPT noexcept\n\n#elif __cplusplus >= 201402\n// C++14\n#  define CONSTDATA constexpr const\n#  define CONSTCD11 constexpr\n#  define CONSTCD14 constexpr\n#  define NOEXCEPT noexcept\n#else\n// C++11\n#  define CONSTDATA constexpr const\n#  define CONSTCD11 constexpr\n#  define CONSTCD14\n#  define NOEXCEPT noexcept\n#endif\n\n#ifndef HAS_UNCAUGHT_EXCEPTIONS\n#  if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)\n#    define HAS_UNCAUGHT_EXCEPTIONS 1\n#  else\n#    define HAS_UNCAUGHT_EXCEPTIONS 0\n#  endif\n#endif  // HAS_UNCAUGHT_EXCEPTIONS\n\n#ifndef HAS_VOID_T\n#  if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)\n#    define HAS_VOID_T 1\n#  else\n#    define HAS_VOID_T 0\n#  endif\n#endif  // HAS_VOID_T\n\n// Protect from Oracle sun macro\n#ifdef sun\n#  undef sun\n#endif\n\n// Work around for a NVCC compiler bug which causes it to fail\n// to compile std::ratio_{multiply,divide} when used directly\n// in the std::chrono::duration template instantiations below\nnamespace detail {\ntemplate <typename R1, typename R2>\nusing ratio_multiply = decltype(std::ratio_multiply<R1, R2>{});\n\ntemplate <typename R1, typename R2>\nusing ratio_divide = decltype(std::ratio_divide<R1, R2>{});\n}  // namespace detail\n\n//-----------+\n// Interface |\n//-----------+\n\n// durations\n\nusing days = std::chrono::duration\n    <int, detail::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;\n\nusing weeks = std::chrono::duration\n    <int, detail::ratio_multiply<std::ratio<7>, days::period>>;\n\nusing years = std::chrono::duration\n    <int, detail::ratio_multiply<std::ratio<146097, 400>, days::period>>;\n\nusing months = std::chrono::duration\n    <int, detail::ratio_divide<years::period, std::ratio<12>>>;\n\n// time_point\n\ntemplate <class Duration>\n    using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;\n\nusing sys_days    = sys_time<days>;\nusing sys_seconds = sys_time<std::chrono::seconds>;\n\nstruct local_t {};\n\ntemplate <class Duration>\n    using local_time = std::chrono::time_point<local_t, Duration>;\n\nusing local_seconds = local_time<std::chrono::seconds>;\nusing local_days    = local_time<days>;\n\n// types\n\nstruct last_spec\n{\n    explicit last_spec() = default;\n};\n\nclass day;\nclass month;\nclass year;\n\nclass weekday;\nclass weekday_indexed;\nclass weekday_last;\n\nclass month_day;\nclass month_day_last;\nclass month_weekday;\nclass month_weekday_last;\n\nclass year_month;\n\nclass year_month_day;\nclass year_month_day_last;\nclass year_month_weekday;\nclass year_month_weekday_last;\n\n// date composition operators\n\nCONSTCD11 year_month operator/(const year& y, const month& m) NOEXCEPT;\nCONSTCD11 year_month operator/(const year& y, int          m) NOEXCEPT;\n\nCONSTCD11 month_day operator/(const day& d, const month& m) NOEXCEPT;\nCONSTCD11 month_day operator/(const day& d, int          m) NOEXCEPT;\nCONSTCD11 month_day operator/(const month& m, const day& d) NOEXCEPT;\nCONSTCD11 month_day operator/(const month& m, int        d) NOEXCEPT;\nCONSTCD11 month_day operator/(int          m, const day& d) NOEXCEPT;\n\nCONSTCD11 month_day_last operator/(const month& m, last_spec) NOEXCEPT;\nCONSTCD11 month_day_last operator/(int          m, last_spec) NOEXCEPT;\nCONSTCD11 month_day_last operator/(last_spec, const month& m) NOEXCEPT;\nCONSTCD11 month_day_last operator/(last_spec, int          m) NOEXCEPT;\n\nCONSTCD11 month_weekday operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT;\nCONSTCD11 month_weekday operator/(int          m, const weekday_indexed& wdi) NOEXCEPT;\nCONSTCD11 month_weekday operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT;\nCONSTCD11 month_weekday operator/(const weekday_indexed& wdi, int          m) NOEXCEPT;\n\nCONSTCD11 month_weekday_last operator/(const month& m, const weekday_last& wdl) NOEXCEPT;\nCONSTCD11 month_weekday_last operator/(int          m, const weekday_last& wdl) NOEXCEPT;\nCONSTCD11 month_weekday_last operator/(const weekday_last& wdl, const month& m) NOEXCEPT;\nCONSTCD11 month_weekday_last operator/(const weekday_last& wdl, int          m) NOEXCEPT;\n\nCONSTCD11 year_month_day operator/(const year_month& ym, const day& d) NOEXCEPT;\nCONSTCD11 year_month_day operator/(const year_month& ym, int        d) NOEXCEPT;\nCONSTCD11 year_month_day operator/(const year& y, const month_day& md) NOEXCEPT;\nCONSTCD11 year_month_day operator/(int         y, const month_day& md) NOEXCEPT;\nCONSTCD11 year_month_day operator/(const month_day& md, const year& y) NOEXCEPT;\nCONSTCD11 year_month_day operator/(const month_day& md, int         y) NOEXCEPT;\n\nCONSTCD11\n    year_month_day_last operator/(const year_month& ym,   last_spec) NOEXCEPT;\nCONSTCD11\n    year_month_day_last operator/(const year& y, const month_day_last& mdl) NOEXCEPT;\nCONSTCD11\n    year_month_day_last operator/(int         y, const month_day_last& mdl) NOEXCEPT;\nCONSTCD11\n    year_month_day_last operator/(const month_day_last& mdl, const year& y) NOEXCEPT;\nCONSTCD11\n    year_month_day_last operator/(const month_day_last& mdl, int         y) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday\noperator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday\noperator/(const year&        y, const month_weekday&   mwd) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday\noperator/(int                y, const month_weekday&   mwd) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday\noperator/(const month_weekday& mwd, const year&          y) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday\noperator/(const month_weekday& mwd, int                  y) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday_last\noperator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday_last\noperator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday_last\noperator/(int         y, const month_weekday_last& mwdl) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday_last\noperator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday_last\noperator/(const month_weekday_last& mwdl, int         y) NOEXCEPT;\n\n// Detailed interface\n\n// day\n\nclass day\n{\n    unsigned char d_;\n\npublic:\n    day() = default;\n    explicit CONSTCD11 day(unsigned d) NOEXCEPT;\n\n    CONSTCD14 day& operator++()    NOEXCEPT;\n    CONSTCD14 day  operator++(int) NOEXCEPT;\n    CONSTCD14 day& operator--()    NOEXCEPT;\n    CONSTCD14 day  operator--(int) NOEXCEPT;\n\n    CONSTCD14 day& operator+=(const days& d) NOEXCEPT;\n    CONSTCD14 day& operator-=(const days& d) NOEXCEPT;\n\n    CONSTCD11 explicit operator unsigned() const NOEXCEPT;\n    CONSTCD11 bool ok() const NOEXCEPT;\n};\n\nCONSTCD11 bool operator==(const day& x, const day& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const day& x, const day& y) NOEXCEPT;\nCONSTCD11 bool operator< (const day& x, const day& y) NOEXCEPT;\nCONSTCD11 bool operator> (const day& x, const day& y) NOEXCEPT;\nCONSTCD11 bool operator<=(const day& x, const day& y) NOEXCEPT;\nCONSTCD11 bool operator>=(const day& x, const day& y) NOEXCEPT;\n\nCONSTCD11 day  operator+(const day&  x, const days& y) NOEXCEPT;\nCONSTCD11 day  operator+(const days& x, const day&  y) NOEXCEPT;\nCONSTCD11 day  operator-(const day&  x, const days& y) NOEXCEPT;\nCONSTCD11 days operator-(const day&  x, const day&  y) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const day& d);\n\n// month\n\nclass month\n{\n    unsigned char m_;\n\npublic:\n    month() = default;\n    explicit CONSTCD11 month(unsigned m) NOEXCEPT;\n\n    CONSTCD14 month& operator++()    NOEXCEPT;\n    CONSTCD14 month  operator++(int) NOEXCEPT;\n    CONSTCD14 month& operator--()    NOEXCEPT;\n    CONSTCD14 month  operator--(int) NOEXCEPT;\n\n    CONSTCD14 month& operator+=(const months& m) NOEXCEPT;\n    CONSTCD14 month& operator-=(const months& m) NOEXCEPT;\n\n    CONSTCD11 explicit operator unsigned() const NOEXCEPT;\n    CONSTCD11 bool ok() const NOEXCEPT;\n};\n\nCONSTCD11 bool operator==(const month& x, const month& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const month& x, const month& y) NOEXCEPT;\nCONSTCD11 bool operator< (const month& x, const month& y) NOEXCEPT;\nCONSTCD11 bool operator> (const month& x, const month& y) NOEXCEPT;\nCONSTCD11 bool operator<=(const month& x, const month& y) NOEXCEPT;\nCONSTCD11 bool operator>=(const month& x, const month& y) NOEXCEPT;\n\nCONSTCD14 month  operator+(const month&  x, const months& y) NOEXCEPT;\nCONSTCD14 month  operator+(const months& x,  const month& y) NOEXCEPT;\nCONSTCD14 month  operator-(const month&  x, const months& y) NOEXCEPT;\nCONSTCD14 months operator-(const month&  x,  const month& y) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const month& m);\n\n// year\n\nclass year\n{\n    short y_;\n\npublic:\n    year() = default;\n    explicit CONSTCD11 year(int y) NOEXCEPT;\n\n    CONSTCD14 year& operator++()    NOEXCEPT;\n    CONSTCD14 year  operator++(int) NOEXCEPT;\n    CONSTCD14 year& operator--()    NOEXCEPT;\n    CONSTCD14 year  operator--(int) NOEXCEPT;\n\n    CONSTCD14 year& operator+=(const years& y) NOEXCEPT;\n    CONSTCD14 year& operator-=(const years& y) NOEXCEPT;\n\n    CONSTCD11 year operator-() const NOEXCEPT;\n    CONSTCD11 year operator+() const NOEXCEPT;\n\n    CONSTCD11 bool is_leap() const NOEXCEPT;\n\n    CONSTCD11 explicit operator int() const NOEXCEPT;\n    CONSTCD11 bool ok() const NOEXCEPT;\n\n    static CONSTCD11 year min() NOEXCEPT { return year{-32767}; }\n    static CONSTCD11 year max() NOEXCEPT { return year{32767}; }\n};\n\nCONSTCD11 bool operator==(const year& x, const year& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const year& x, const year& y) NOEXCEPT;\nCONSTCD11 bool operator< (const year& x, const year& y) NOEXCEPT;\nCONSTCD11 bool operator> (const year& x, const year& y) NOEXCEPT;\nCONSTCD11 bool operator<=(const year& x, const year& y) NOEXCEPT;\nCONSTCD11 bool operator>=(const year& x, const year& y) NOEXCEPT;\n\nCONSTCD11 year  operator+(const year&  x, const years& y) NOEXCEPT;\nCONSTCD11 year  operator+(const years& x, const year&  y) NOEXCEPT;\nCONSTCD11 year  operator-(const year&  x, const years& y) NOEXCEPT;\nCONSTCD11 years operator-(const year&  x, const year&  y) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year& y);\n\n// weekday\n\nclass weekday\n{\n    unsigned char wd_;\npublic:\n    weekday() = default;\n    explicit CONSTCD11 weekday(unsigned wd) NOEXCEPT;\n    CONSTCD14 weekday(const sys_days& dp) NOEXCEPT;\n    CONSTCD14 explicit weekday(const local_days& dp) NOEXCEPT;\n\n    CONSTCD14 weekday& operator++()    NOEXCEPT;\n    CONSTCD14 weekday  operator++(int) NOEXCEPT;\n    CONSTCD14 weekday& operator--()    NOEXCEPT;\n    CONSTCD14 weekday  operator--(int) NOEXCEPT;\n\n    CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT;\n    CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT;\n\n    CONSTCD11 bool ok() const NOEXCEPT;\n\n    CONSTCD11 unsigned c_encoding() const NOEXCEPT;\n    CONSTCD11 unsigned iso_encoding() const NOEXCEPT;\n\n    CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT;\n    CONSTCD11 weekday_last    operator[](last_spec)      const NOEXCEPT;\n\nprivate:\n    static CONSTCD14 unsigned char weekday_from_days(int z) NOEXCEPT;\n\n    friend CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT;\n    friend CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT;\n    friend CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT;\n    template<class CharT, class Traits>\n        friend std::basic_ostream<CharT, Traits>&\n            operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd);\n    friend class weekday_indexed;\n};\n\nCONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const weekday& x, const weekday& y) NOEXCEPT;\n\nCONSTCD14 weekday operator+(const weekday& x, const days&    y) NOEXCEPT;\nCONSTCD14 weekday operator+(const days&    x, const weekday& y) NOEXCEPT;\nCONSTCD14 weekday operator-(const weekday& x, const days&    y) NOEXCEPT;\nCONSTCD14 days    operator-(const weekday& x, const weekday& y) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd);\n\n// weekday_indexed\n\nclass weekday_indexed\n{\n    unsigned char wd_    : 4;\n    unsigned char index_ : 4;\n\npublic:\n    weekday_indexed() = default;\n    CONSTCD11 weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT;\n\n    CONSTCD11 date::weekday weekday() const NOEXCEPT;\n    CONSTCD11 unsigned index() const NOEXCEPT;\n    CONSTCD11 bool ok() const NOEXCEPT;\n};\n\nCONSTCD11 bool operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi);\n\n// weekday_last\n\nclass weekday_last\n{\n    date::weekday wd_;\n\npublic:\n    explicit CONSTCD11 weekday_last(const date::weekday& wd) NOEXCEPT;\n\n    CONSTCD11 date::weekday weekday() const NOEXCEPT;\n    CONSTCD11 bool ok() const NOEXCEPT;\n};\n\nCONSTCD11 bool operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl);\n\nnamespace detail\n{\n\nstruct unspecified_month_disambiguator {};\n\n}  // namespace detail\n\n// year_month\n\nclass year_month\n{\n    date::year  y_;\n    date::month m_;\n\npublic:\n    year_month() = default;\n    CONSTCD11 year_month(const date::year& y, const date::month& m) NOEXCEPT;\n\n    CONSTCD11 date::year  year()  const NOEXCEPT;\n    CONSTCD11 date::month month() const NOEXCEPT;\n\n    template<class = detail::unspecified_month_disambiguator>\n    CONSTCD14 year_month& operator+=(const months& dm) NOEXCEPT;\n    template<class = detail::unspecified_month_disambiguator>\n    CONSTCD14 year_month& operator-=(const months& dm) NOEXCEPT;\n    CONSTCD14 year_month& operator+=(const years& dy) NOEXCEPT;\n    CONSTCD14 year_month& operator-=(const years& dy) NOEXCEPT;\n\n    CONSTCD11 bool ok() const NOEXCEPT;\n};\n\nCONSTCD11 bool operator==(const year_month& x, const year_month& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const year_month& x, const year_month& y) NOEXCEPT;\nCONSTCD11 bool operator< (const year_month& x, const year_month& y) NOEXCEPT;\nCONSTCD11 bool operator> (const year_month& x, const year_month& y) NOEXCEPT;\nCONSTCD11 bool operator<=(const year_month& x, const year_month& y) NOEXCEPT;\nCONSTCD11 bool operator>=(const year_month& x, const year_month& y) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14 year_month operator+(const year_month& ym, const months& dm) NOEXCEPT;\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14 year_month operator+(const months& dm, const year_month& ym) NOEXCEPT;\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14 year_month operator-(const year_month& ym, const months& dm) NOEXCEPT;\n\nCONSTCD11 months operator-(const year_month& x, const year_month& y) NOEXCEPT;\nCONSTCD11 year_month operator+(const year_month& ym, const years& dy) NOEXCEPT;\nCONSTCD11 year_month operator+(const years& dy, const year_month& ym) NOEXCEPT;\nCONSTCD11 year_month operator-(const year_month& ym, const years& dy) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year_month& ym);\n\n// month_day\n\nclass month_day\n{\n    date::month m_;\n    date::day   d_;\n\npublic:\n    month_day() = default;\n    CONSTCD11 month_day(const date::month& m, const date::day& d) NOEXCEPT;\n\n    CONSTCD11 date::month month() const NOEXCEPT;\n    CONSTCD11 date::day   day() const NOEXCEPT;\n\n    CONSTCD14 bool ok() const NOEXCEPT;\n};\n\nCONSTCD11 bool operator==(const month_day& x, const month_day& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const month_day& x, const month_day& y) NOEXCEPT;\nCONSTCD11 bool operator< (const month_day& x, const month_day& y) NOEXCEPT;\nCONSTCD11 bool operator> (const month_day& x, const month_day& y) NOEXCEPT;\nCONSTCD11 bool operator<=(const month_day& x, const month_day& y) NOEXCEPT;\nCONSTCD11 bool operator>=(const month_day& x, const month_day& y) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const month_day& md);\n\n// month_day_last\n\nclass month_day_last\n{\n    date::month m_;\n\npublic:\n    CONSTCD11 explicit month_day_last(const date::month& m) NOEXCEPT;\n\n    CONSTCD11 date::month month() const NOEXCEPT;\n    CONSTCD11 bool ok() const NOEXCEPT;\n};\n\nCONSTCD11 bool operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT;\nCONSTCD11 bool operator< (const month_day_last& x, const month_day_last& y) NOEXCEPT;\nCONSTCD11 bool operator> (const month_day_last& x, const month_day_last& y) NOEXCEPT;\nCONSTCD11 bool operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT;\nCONSTCD11 bool operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl);\n\n// month_weekday\n\nclass month_weekday\n{\n    date::month           m_;\n    date::weekday_indexed wdi_;\npublic:\n    CONSTCD11 month_weekday(const date::month& m,\n                            const date::weekday_indexed& wdi) NOEXCEPT;\n\n    CONSTCD11 date::month           month()           const NOEXCEPT;\n    CONSTCD11 date::weekday_indexed weekday_indexed() const NOEXCEPT;\n\n    CONSTCD11 bool ok() const NOEXCEPT;\n};\n\nCONSTCD11 bool operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd);\n\n// month_weekday_last\n\nclass month_weekday_last\n{\n    date::month        m_;\n    date::weekday_last wdl_;\n\npublic:\n    CONSTCD11 month_weekday_last(const date::month& m,\n                                 const date::weekday_last& wd) NOEXCEPT;\n\n    CONSTCD11 date::month        month()        const NOEXCEPT;\n    CONSTCD11 date::weekday_last weekday_last() const NOEXCEPT;\n\n    CONSTCD11 bool ok() const NOEXCEPT;\n};\n\nCONSTCD11\n    bool operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT;\nCONSTCD11\n    bool operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl);\n\n// class year_month_day\n\nclass year_month_day\n{\n    date::year  y_;\n    date::month m_;\n    date::day   d_;\n\npublic:\n    year_month_day() = default;\n    CONSTCD11 year_month_day(const date::year& y, const date::month& m,\n                             const date::day& d) NOEXCEPT;\n    CONSTCD14 year_month_day(const year_month_day_last& ymdl) NOEXCEPT;\n\n    CONSTCD14 year_month_day(sys_days dp) NOEXCEPT;\n    CONSTCD14 explicit year_month_day(local_days dp) NOEXCEPT;\n\n    template<class = detail::unspecified_month_disambiguator>\n    CONSTCD14 year_month_day& operator+=(const months& m) NOEXCEPT;\n    template<class = detail::unspecified_month_disambiguator>\n    CONSTCD14 year_month_day& operator-=(const months& m) NOEXCEPT;\n    CONSTCD14 year_month_day& operator+=(const years& y)  NOEXCEPT;\n    CONSTCD14 year_month_day& operator-=(const years& y)  NOEXCEPT;\n\n    CONSTCD11 date::year  year()  const NOEXCEPT;\n    CONSTCD11 date::month month() const NOEXCEPT;\n    CONSTCD11 date::day   day()   const NOEXCEPT;\n\n    CONSTCD14 operator sys_days() const NOEXCEPT;\n    CONSTCD14 explicit operator local_days() const NOEXCEPT;\n    CONSTCD14 bool ok() const NOEXCEPT;\n\nprivate:\n    static CONSTCD14 year_month_day from_days(days dp) NOEXCEPT;\n    CONSTCD14 days to_days() const NOEXCEPT;\n};\n\nCONSTCD11 bool operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT;\nCONSTCD11 bool operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT;\nCONSTCD11 bool operator< (const year_month_day& x, const year_month_day& y) NOEXCEPT;\nCONSTCD11 bool operator> (const year_month_day& x, const year_month_day& y) NOEXCEPT;\nCONSTCD11 bool operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT;\nCONSTCD11 bool operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14 year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT;\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14 year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT;\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14 year_month_day operator-(const year_month_day& ymd, const months& dm) NOEXCEPT;\nCONSTCD11 year_month_day operator+(const year_month_day& ymd, const years& dy)  NOEXCEPT;\nCONSTCD11 year_month_day operator+(const years& dy, const year_month_day& ymd)  NOEXCEPT;\nCONSTCD11 year_month_day operator-(const year_month_day& ymd, const years& dy)  NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd);\n\n// year_month_day_last\n\nclass year_month_day_last\n{\n    date::year           y_;\n    date::month_day_last mdl_;\n\npublic:\n    CONSTCD11 year_month_day_last(const date::year& y,\n                                  const date::month_day_last& mdl) NOEXCEPT;\n\n    template<class = detail::unspecified_month_disambiguator>\n    CONSTCD14 year_month_day_last& operator+=(const months& m) NOEXCEPT;\n    template<class = detail::unspecified_month_disambiguator>\n    CONSTCD14 year_month_day_last& operator-=(const months& m) NOEXCEPT;\n    CONSTCD14 year_month_day_last& operator+=(const years& y)  NOEXCEPT;\n    CONSTCD14 year_month_day_last& operator-=(const years& y)  NOEXCEPT;\n\n    CONSTCD11 date::year           year()           const NOEXCEPT;\n    CONSTCD11 date::month          month()          const NOEXCEPT;\n    CONSTCD11 date::month_day_last month_day_last() const NOEXCEPT;\n    CONSTCD14 date::day            day()            const NOEXCEPT;\n\n    CONSTCD14 operator sys_days() const NOEXCEPT;\n    CONSTCD14 explicit operator local_days() const NOEXCEPT;\n    CONSTCD11 bool ok() const NOEXCEPT;\n};\n\nCONSTCD11\n    bool operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;\nCONSTCD11\n    bool operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;\nCONSTCD11\n    bool operator< (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;\nCONSTCD11\n    bool operator> (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;\nCONSTCD11\n    bool operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;\nCONSTCD11\n    bool operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14\nyear_month_day_last\noperator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14\nyear_month_day_last\noperator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT;\n\nCONSTCD11\nyear_month_day_last\noperator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT;\n\nCONSTCD11\nyear_month_day_last\noperator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14\nyear_month_day_last\noperator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT;\n\nCONSTCD11\nyear_month_day_last\noperator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl);\n\n// year_month_weekday\n\nclass year_month_weekday\n{\n    date::year            y_;\n    date::month           m_;\n    date::weekday_indexed wdi_;\n\npublic:\n    year_month_weekday() = default;\n    CONSTCD11 year_month_weekday(const date::year& y, const date::month& m,\n                                   const date::weekday_indexed& wdi) NOEXCEPT;\n    CONSTCD14 year_month_weekday(const sys_days& dp) NOEXCEPT;\n    CONSTCD14 explicit year_month_weekday(const local_days& dp) NOEXCEPT;\n\n    template<class = detail::unspecified_month_disambiguator>\n    CONSTCD14 year_month_weekday& operator+=(const months& m) NOEXCEPT;\n    template<class = detail::unspecified_month_disambiguator>\n    CONSTCD14 year_month_weekday& operator-=(const months& m) NOEXCEPT;\n    CONSTCD14 year_month_weekday& operator+=(const years& y)  NOEXCEPT;\n    CONSTCD14 year_month_weekday& operator-=(const years& y)  NOEXCEPT;\n\n    CONSTCD11 date::year year() const NOEXCEPT;\n    CONSTCD11 date::month month() const NOEXCEPT;\n    CONSTCD11 date::weekday weekday() const NOEXCEPT;\n    CONSTCD11 unsigned index() const NOEXCEPT;\n    CONSTCD11 date::weekday_indexed weekday_indexed() const NOEXCEPT;\n\n    CONSTCD14 operator sys_days() const NOEXCEPT;\n    CONSTCD14 explicit operator local_days() const NOEXCEPT;\n    CONSTCD14 bool ok() const NOEXCEPT;\n\nprivate:\n    static CONSTCD14 year_month_weekday from_days(days dp) NOEXCEPT;\n    CONSTCD14 days to_days() const NOEXCEPT;\n};\n\nCONSTCD11\n    bool operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT;\nCONSTCD11\n    bool operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14\nyear_month_weekday\noperator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14\nyear_month_weekday\noperator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday\noperator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday\noperator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14\nyear_month_weekday\noperator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday\noperator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday& ymwdi);\n\n// year_month_weekday_last\n\nclass year_month_weekday_last\n{\n    date::year y_;\n    date::month m_;\n    date::weekday_last wdl_;\n\npublic:\n    CONSTCD11 year_month_weekday_last(const date::year& y, const date::month& m,\n                                      const date::weekday_last& wdl) NOEXCEPT;\n\n    template<class = detail::unspecified_month_disambiguator>\n    CONSTCD14 year_month_weekday_last& operator+=(const months& m) NOEXCEPT;\n    template<class = detail::unspecified_month_disambiguator>\n    CONSTCD14 year_month_weekday_last& operator-=(const months& m) NOEXCEPT;\n    CONSTCD14 year_month_weekday_last& operator+=(const years& y) NOEXCEPT;\n    CONSTCD14 year_month_weekday_last& operator-=(const years& y) NOEXCEPT;\n\n    CONSTCD11 date::year year() const NOEXCEPT;\n    CONSTCD11 date::month month() const NOEXCEPT;\n    CONSTCD11 date::weekday weekday() const NOEXCEPT;\n    CONSTCD11 date::weekday_last weekday_last() const NOEXCEPT;\n\n    CONSTCD14 operator sys_days() const NOEXCEPT;\n    CONSTCD14 explicit operator local_days() const NOEXCEPT;\n    CONSTCD11 bool ok() const NOEXCEPT;\n\nprivate:\n    CONSTCD14 days to_days() const NOEXCEPT;\n};\n\nCONSTCD11\nbool\noperator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT;\n\nCONSTCD11\nbool\noperator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14\nyear_month_weekday_last\noperator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14\nyear_month_weekday_last\noperator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday_last\noperator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday_last\noperator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT;\n\ntemplate<class = detail::unspecified_month_disambiguator>\nCONSTCD14\nyear_month_weekday_last\noperator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT;\n\nCONSTCD11\nyear_month_weekday_last\noperator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT;\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday_last& ymwdl);\n\n#if !defined(_MSC_VER) || (_MSC_VER >= 1900)\ninline namespace literals\n{\n\nCONSTCD11 date::day  operator \"\" _d(unsigned long long d) NOEXCEPT;\nCONSTCD11 date::year operator \"\" _y(unsigned long long y) NOEXCEPT;\n\n}  // inline namespace literals\n#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900)\n\n// CONSTDATA date::month January{1};\n// CONSTDATA date::month February{2};\n// CONSTDATA date::month March{3};\n// CONSTDATA date::month April{4};\n// CONSTDATA date::month May{5};\n// CONSTDATA date::month June{6};\n// CONSTDATA date::month July{7};\n// CONSTDATA date::month August{8};\n// CONSTDATA date::month September{9};\n// CONSTDATA date::month October{10};\n// CONSTDATA date::month November{11};\n// CONSTDATA date::month December{12};\n//\n// CONSTDATA date::weekday Sunday{0u};\n// CONSTDATA date::weekday Monday{1u};\n// CONSTDATA date::weekday Tuesday{2u};\n// CONSTDATA date::weekday Wednesday{3u};\n// CONSTDATA date::weekday Thursday{4u};\n// CONSTDATA date::weekday Friday{5u};\n// CONSTDATA date::weekday Saturday{6u};\n\n#if HAS_VOID_T\n\ntemplate <class T, class = std::void_t<>>\nstruct is_clock\n    : std::false_type\n{};\n\ntemplate <class T>\nstruct is_clock<T, std::void_t<decltype(T::now()), typename T::rep, typename T::period,\n                               typename T::duration, typename T::time_point,\n                               decltype(T::is_steady)>>\n    : std::true_type\n{};\n\ntemplate<class T> inline constexpr bool is_clock_v = is_clock<T>::value;\n\n#endif  // HAS_VOID_T\n\n//----------------+\n// Implementation |\n//----------------+\n\n// utilities\nnamespace detail {\n\ntemplate<class CharT, class Traits = std::char_traits<CharT>>\nclass save_istream\n{\nprotected:\n    std::basic_ios<CharT, Traits>& is_;\n    CharT fill_;\n    std::ios::fmtflags flags_;\n    std::streamsize precision_;\n    std::streamsize width_;\n    std::basic_ostream<CharT, Traits>* tie_;\n    std::locale loc_;\n\npublic:\n    ~save_istream()\n    {\n        is_.fill(fill_);\n        is_.flags(flags_);\n        is_.precision(precision_);\n        is_.width(width_);\n        is_.imbue(loc_);\n        is_.tie(tie_);\n    }\n\n    save_istream(const save_istream&) = delete;\n    save_istream& operator=(const save_istream&) = delete;\n\n    explicit save_istream(std::basic_ios<CharT, Traits>& is)\n        : is_(is)\n        , fill_(is.fill())\n        , flags_(is.flags())\n        , precision_(is.precision())\n        , width_(is.width(0))\n        , tie_(is.tie(nullptr))\n        , loc_(is.getloc())\n        {\n            if (tie_ != nullptr)\n                tie_->flush();\n        }\n};\n\ntemplate<class CharT, class Traits = std::char_traits<CharT>>\nclass save_ostream\n    : private save_istream<CharT, Traits>\n{\npublic:\n    ~save_ostream()\n    {\n        if ((this->flags_ & std::ios::unitbuf) &&\n#if HAS_UNCAUGHT_EXCEPTIONS\n                std::uncaught_exceptions() == 0 &&\n#else\n                !std::uncaught_exception() &&\n#endif\n                this->is_.good())\n            this->is_.rdbuf()->pubsync();\n    }\n\n    save_ostream(const save_ostream&) = delete;\n    save_ostream& operator=(const save_ostream&) = delete;\n\n    explicit save_ostream(std::basic_ios<CharT, Traits>& os)\n        : save_istream<CharT, Traits>(os)\n        {\n        }\n};\n\ntemplate <class T>\nstruct choose_trunc_type\n{\n    static const int digits = std::numeric_limits<T>::digits;\n    using type = typename std::conditional\n                 <\n                     digits < 32,\n                     std::int32_t,\n                     typename std::conditional\n                     <\n                         digits < 64,\n                         std::int64_t,\n#ifdef __SIZEOF_INT128__\n                         __int128\n#else\n                         std::int64_t\n#endif\n                     >::type\n                 >::type;\n};\n\ntemplate <class T>\nCONSTCD11\ninline\ntypename std::enable_if\n<\n    !std::chrono::treat_as_floating_point<T>::value,\n    T\n>::type\ntrunc(T t) NOEXCEPT\n{\n    return t;\n}\n\ntemplate <class T>\nCONSTCD14\ninline\ntypename std::enable_if\n<\n    std::chrono::treat_as_floating_point<T>::value,\n    T\n>::type\ntrunc(T t) NOEXCEPT\n{\n    using std::numeric_limits;\n    using I = typename choose_trunc_type<T>::type;\n    CONSTDATA auto digits = numeric_limits<T>::digits;\n    static_assert(digits < numeric_limits<I>::digits, \"\");\n    CONSTDATA auto max = I{1} << (digits-1);\n    CONSTDATA auto min = -max;\n    const auto negative = t < T{0};\n    if (min <= t && t <= max && t != 0 && t == t)\n    {\n        t = static_cast<T>(static_cast<I>(t));\n        if (t == 0 && negative)\n            t = -t;\n    }\n    return t;\n}\n\ntemplate <std::intmax_t Xp, std::intmax_t Yp>\nstruct static_gcd\n{\n    static const std::intmax_t value = static_gcd<Yp, Xp % Yp>::value;\n};\n\ntemplate <std::intmax_t Xp>\nstruct static_gcd<Xp, 0>\n{\n    static const std::intmax_t value = Xp;\n};\n\ntemplate <>\nstruct static_gcd<0, 0>\n{\n    static const std::intmax_t value = 1;\n};\n\ntemplate <class R1, class R2>\nstruct no_overflow\n{\nprivate:\n    static const std::intmax_t gcd_n1_n2 = static_gcd<R1::num, R2::num>::value;\n    static const std::intmax_t gcd_d1_d2 = static_gcd<R1::den, R2::den>::value;\n    static const std::intmax_t n1 = R1::num / gcd_n1_n2;\n    static const std::intmax_t d1 = R1::den / gcd_d1_d2;\n    static const std::intmax_t n2 = R2::num / gcd_n1_n2;\n    static const std::intmax_t d2 = R2::den / gcd_d1_d2;\n#ifdef __cpp_constexpr\n    static const std::intmax_t max = std::numeric_limits<std::intmax_t>::max();\n#else\n    static const std::intmax_t max = LLONG_MAX;\n#endif\n\n    template <std::intmax_t Xp, std::intmax_t Yp, bool overflow>\n    struct mul    // overflow == false\n    {\n        static const std::intmax_t value = Xp * Yp;\n    };\n\n    template <std::intmax_t Xp, std::intmax_t Yp>\n    struct mul<Xp, Yp, true>\n    {\n        static const std::intmax_t value = 1;\n    };\n\npublic:\n    static const bool value = (n1 <= max / d2) && (n2 <= max / d1);\n    typedef std::ratio<mul<n1, d2, !value>::value,\n                       mul<n2, d1, !value>::value> type;\n};\n\n}  // detail\n\n// trunc towards zero\ntemplate <class To, class Rep, class Period>\nCONSTCD11\ninline\ntypename std::enable_if\n<\n    detail::no_overflow<Period, typename To::period>::value,\n    To\n>::type\ntrunc(const std::chrono::duration<Rep, Period>& d)\n{\n    return To{detail::trunc(std::chrono::duration_cast<To>(d).count())};\n}\n\ntemplate <class To, class Rep, class Period>\nCONSTCD11\ninline\ntypename std::enable_if\n<\n    !detail::no_overflow<Period, typename To::period>::value,\n    To\n>::type\ntrunc(const std::chrono::duration<Rep, Period>& d)\n{\n    using std::chrono::duration_cast;\n    using std::chrono::duration;\n    using rep = typename std::common_type<Rep, typename To::rep>::type;\n    return To{detail::trunc(duration_cast<To>(duration_cast<duration<rep>>(d)).count())};\n}\n\n#ifndef HAS_CHRONO_ROUNDING\n#  if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023918 || (_MSC_FULL_VER >= 190000000 && defined (__clang__)))\n#    define HAS_CHRONO_ROUNDING 1\n#  elif defined(__cpp_lib_chrono) && __cplusplus > 201402 && __cpp_lib_chrono >= 201510\n#    define HAS_CHRONO_ROUNDING 1\n#  elif defined(_LIBCPP_VERSION) && __cplusplus > 201402 && _LIBCPP_VERSION >= 3800\n#    define HAS_CHRONO_ROUNDING 1\n#  else\n#    define HAS_CHRONO_ROUNDING 0\n#  endif\n#endif  // HAS_CHRONO_ROUNDING\n\n#if HAS_CHRONO_ROUNDING == 0\n\n// round down\ntemplate <class To, class Rep, class Period>\nCONSTCD14\ninline\ntypename std::enable_if\n<\n    detail::no_overflow<Period, typename To::period>::value,\n    To\n>::type\nfloor(const std::chrono::duration<Rep, Period>& d)\n{\n    auto t = trunc<To>(d);\n    if (t > d)\n        return t - To{1};\n    return t;\n}\n\ntemplate <class To, class Rep, class Period>\nCONSTCD14\ninline\ntypename std::enable_if\n<\n    !detail::no_overflow<Period, typename To::period>::value,\n    To\n>::type\nfloor(const std::chrono::duration<Rep, Period>& d)\n{\n    using rep = typename std::common_type<Rep, typename To::rep>::type;\n    return floor<To>(floor<std::chrono::duration<rep>>(d));\n}\n\n// round to nearest, to even on tie\ntemplate <class To, class Rep, class Period>\nCONSTCD14\ninline\nTo\nround(const std::chrono::duration<Rep, Period>& d)\n{\n    auto t0 = floor<To>(d);\n    auto t1 = t0 + To{1};\n    if (t1 == To{0} && t0 < To{0})\n        t1 = -t1;\n    auto diff0 = d - t0;\n    auto diff1 = t1 - d;\n    if (diff0 == diff1)\n    {\n        if (t0 - trunc<To>(t0/2)*2 == To{0})\n            return t0;\n        return t1;\n    }\n    if (diff0 < diff1)\n        return t0;\n    return t1;\n}\n\n// round up\ntemplate <class To, class Rep, class Period>\nCONSTCD14\ninline\nTo\nceil(const std::chrono::duration<Rep, Period>& d)\n{\n    auto t = trunc<To>(d);\n    if (t < d)\n        return t + To{1};\n    return t;\n}\n\ntemplate <class Rep, class Period,\n          class = typename std::enable_if\n          <\n              std::numeric_limits<Rep>::is_signed\n          >::type>\nCONSTCD11\nstd::chrono::duration<Rep, Period>\nabs(std::chrono::duration<Rep, Period> d)\n{\n    return d >= d.zero() ? d : static_cast<decltype(d)>(-d);\n}\n\n// round down\ntemplate <class To, class Clock, class FromDuration>\nCONSTCD11\ninline\nstd::chrono::time_point<Clock, To>\nfloor(const std::chrono::time_point<Clock, FromDuration>& tp)\n{\n    using std::chrono::time_point;\n    return time_point<Clock, To>{date::floor<To>(tp.time_since_epoch())};\n}\n\n// round to nearest, to even on tie\ntemplate <class To, class Clock, class FromDuration>\nCONSTCD11\ninline\nstd::chrono::time_point<Clock, To>\nround(const std::chrono::time_point<Clock, FromDuration>& tp)\n{\n    using std::chrono::time_point;\n    return time_point<Clock, To>{round<To>(tp.time_since_epoch())};\n}\n\n// round up\ntemplate <class To, class Clock, class FromDuration>\nCONSTCD11\ninline\nstd::chrono::time_point<Clock, To>\nceil(const std::chrono::time_point<Clock, FromDuration>& tp)\n{\n    using std::chrono::time_point;\n    return time_point<Clock, To>{ceil<To>(tp.time_since_epoch())};\n}\n\n#else  // HAS_CHRONO_ROUNDING == 1\n\nusing std::chrono::floor;\nusing std::chrono::ceil;\nusing std::chrono::round;\nusing std::chrono::abs;\n\n#endif  // HAS_CHRONO_ROUNDING\n\nnamespace detail\n{\n\ntemplate <class To, class Rep, class Period>\nCONSTCD14\ninline\ntypename std::enable_if\n<\n    !std::chrono::treat_as_floating_point<typename To::rep>::value,\n    To\n>::type\nround_i(const std::chrono::duration<Rep, Period>& d)\n{\n    return round<To>(d);\n}\n\ntemplate <class To, class Rep, class Period>\nCONSTCD14\ninline\ntypename std::enable_if\n<\n    std::chrono::treat_as_floating_point<typename To::rep>::value,\n    To\n>::type\nround_i(const std::chrono::duration<Rep, Period>& d)\n{\n    return d;\n}\n\ntemplate <class To, class Clock, class FromDuration>\nCONSTCD11\ninline\nstd::chrono::time_point<Clock, To>\nround_i(const std::chrono::time_point<Clock, FromDuration>& tp)\n{\n    using std::chrono::time_point;\n    return time_point<Clock, To>{round_i<To>(tp.time_since_epoch())};\n}\n\n}  // detail\n\n// trunc towards zero\ntemplate <class To, class Clock, class FromDuration>\nCONSTCD11\ninline\nstd::chrono::time_point<Clock, To>\ntrunc(const std::chrono::time_point<Clock, FromDuration>& tp)\n{\n    using std::chrono::time_point;\n    return time_point<Clock, To>{trunc<To>(tp.time_since_epoch())};\n}\n\n// day\n\nCONSTCD11 inline day::day(unsigned d) NOEXCEPT : d_(static_cast<decltype(d_)>(d)) {}\nCONSTCD14 inline day& day::operator++() NOEXCEPT {++d_; return *this;}\nCONSTCD14 inline day day::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;}\nCONSTCD14 inline day& day::operator--() NOEXCEPT {--d_; return *this;}\nCONSTCD14 inline day day::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;}\nCONSTCD14 inline day& day::operator+=(const days& d) NOEXCEPT {*this = *this + d; return *this;}\nCONSTCD14 inline day& day::operator-=(const days& d) NOEXCEPT {*this = *this - d; return *this;}\nCONSTCD11 inline day::operator unsigned() const NOEXCEPT {return d_;}\nCONSTCD11 inline bool day::ok() const NOEXCEPT {return 1 <= d_ && d_ <= 31;}\n\nCONSTCD11\ninline\nbool\noperator==(const day& x, const day& y) NOEXCEPT\n{\n    return static_cast<unsigned>(x) == static_cast<unsigned>(y);\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const day& x, const day& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nCONSTCD11\ninline\nbool\noperator<(const day& x, const day& y) NOEXCEPT\n{\n    return static_cast<unsigned>(x) < static_cast<unsigned>(y);\n}\n\nCONSTCD11\ninline\nbool\noperator>(const day& x, const day& y) NOEXCEPT\n{\n    return y < x;\n}\n\nCONSTCD11\ninline\nbool\noperator<=(const day& x, const day& y) NOEXCEPT\n{\n    return !(y < x);\n}\n\nCONSTCD11\ninline\nbool\noperator>=(const day& x, const day& y) NOEXCEPT\n{\n    return !(x < y);\n}\n\nCONSTCD11\ninline\ndays\noperator-(const day& x, const day& y) NOEXCEPT\n{\n    return days{static_cast<days::rep>(static_cast<unsigned>(x)\n                                     - static_cast<unsigned>(y))};\n}\n\nCONSTCD11\ninline\nday\noperator+(const day& x, const days& y) NOEXCEPT\n{\n    return day{static_cast<unsigned>(x) + static_cast<unsigned>(y.count())};\n}\n\nCONSTCD11\ninline\nday\noperator+(const days& x, const day& y) NOEXCEPT\n{\n    return y + x;\n}\n\nCONSTCD11\ninline\nday\noperator-(const day& x, const days& y) NOEXCEPT\n{\n    return x + -y;\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const day& d)\n{\n    detail::save_ostream<CharT, Traits> _(os);\n    os.fill('0');\n    os.flags(std::ios::dec | std::ios::right);\n    os.width(2);\n    os << static_cast<unsigned>(d);\n    return os;\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const day& d)\n{\n    detail::low_level_fmt(os, d);\n    if (!d.ok())\n        os << \" is not a valid day\";\n    return os;\n}\n\n// month\n\nCONSTCD11 inline month::month(unsigned m) NOEXCEPT : m_(static_cast<decltype(m_)>(m)) {}\nCONSTCD14 inline month& month::operator++() NOEXCEPT {*this += months{1}; return *this;}\nCONSTCD14 inline month month::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;}\nCONSTCD14 inline month& month::operator--() NOEXCEPT {*this -= months{1}; return *this;}\nCONSTCD14 inline month month::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;}\n\nCONSTCD14\ninline\nmonth&\nmonth::operator+=(const months& m) NOEXCEPT\n{\n    *this = *this + m;\n    return *this;\n}\n\nCONSTCD14\ninline\nmonth&\nmonth::operator-=(const months& m) NOEXCEPT\n{\n    *this = *this - m;\n    return *this;\n}\n\nCONSTCD11 inline month::operator unsigned() const NOEXCEPT {return m_;}\nCONSTCD11 inline bool month::ok() const NOEXCEPT {return 1 <= m_ && m_ <= 12;}\n\nCONSTCD11\ninline\nbool\noperator==(const month& x, const month& y) NOEXCEPT\n{\n    return static_cast<unsigned>(x) == static_cast<unsigned>(y);\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const month& x, const month& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nCONSTCD11\ninline\nbool\noperator<(const month& x, const month& y) NOEXCEPT\n{\n    return static_cast<unsigned>(x) < static_cast<unsigned>(y);\n}\n\nCONSTCD11\ninline\nbool\noperator>(const month& x, const month& y) NOEXCEPT\n{\n    return y < x;\n}\n\nCONSTCD11\ninline\nbool\noperator<=(const month& x, const month& y) NOEXCEPT\n{\n    return !(y < x);\n}\n\nCONSTCD11\ninline\nbool\noperator>=(const month& x, const month& y) NOEXCEPT\n{\n    return !(x < y);\n}\n\nCONSTCD14\ninline\nmonths\noperator-(const month& x, const month& y) NOEXCEPT\n{\n    auto const d = static_cast<unsigned>(x) - static_cast<unsigned>(y);\n    return months(d <= 11 ? d : d + 12);\n}\n\nCONSTCD14\ninline\nmonth\noperator+(const month& x, const months& y) NOEXCEPT\n{\n    auto const mu = static_cast<long long>(static_cast<unsigned>(x)) + y.count() - 1;\n    auto const yr = (mu >= 0 ? mu : mu-11) / 12;\n    return month{static_cast<unsigned>(mu - yr * 12 + 1)};\n}\n\nCONSTCD14\ninline\nmonth\noperator+(const months& x, const month& y) NOEXCEPT\n{\n    return y + x;\n}\n\nCONSTCD14\ninline\nmonth\noperator-(const month& x, const months& y) NOEXCEPT\n{\n    return x + -y;\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const month& m)\n{\n    if (m.ok())\n    {\n        CharT fmt[] = {'%', 'b', 0};\n        os << format(os.getloc(), fmt, m);\n    }\n    else\n        os << static_cast<unsigned>(m);\n    return os;\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const month& m)\n{\n    detail::low_level_fmt(os, m);\n    if (!m.ok())\n        os << \" is not a valid month\";\n    return os;\n}\n\n// year\n\nCONSTCD11 inline year::year(int y) NOEXCEPT : y_(static_cast<decltype(y_)>(y)) {}\nCONSTCD14 inline year& year::operator++() NOEXCEPT {++y_; return *this;}\nCONSTCD14 inline year year::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;}\nCONSTCD14 inline year& year::operator--() NOEXCEPT {--y_; return *this;}\nCONSTCD14 inline year year::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;}\nCONSTCD14 inline year& year::operator+=(const years& y) NOEXCEPT {*this = *this + y; return *this;}\nCONSTCD14 inline year& year::operator-=(const years& y) NOEXCEPT {*this = *this - y; return *this;}\nCONSTCD11 inline year year::operator-() const NOEXCEPT {return year{-y_};}\nCONSTCD11 inline year year::operator+() const NOEXCEPT {return *this;}\n\nCONSTCD11\ninline\nbool\nyear::is_leap() const NOEXCEPT\n{\n    return y_ % 4 == 0 && (y_ % 100 != 0 || y_ % 400 == 0);\n}\n\nCONSTCD11 inline year::operator int() const NOEXCEPT {return y_;}\n\nCONSTCD11\ninline\nbool\nyear::ok() const NOEXCEPT\n{\n    return y_ != std::numeric_limits<short>::min();\n}\n\nCONSTCD11\ninline\nbool\noperator==(const year& x, const year& y) NOEXCEPT\n{\n    return static_cast<int>(x) == static_cast<int>(y);\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const year& x, const year& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nCONSTCD11\ninline\nbool\noperator<(const year& x, const year& y) NOEXCEPT\n{\n    return static_cast<int>(x) < static_cast<int>(y);\n}\n\nCONSTCD11\ninline\nbool\noperator>(const year& x, const year& y) NOEXCEPT\n{\n    return y < x;\n}\n\nCONSTCD11\ninline\nbool\noperator<=(const year& x, const year& y) NOEXCEPT\n{\n    return !(y < x);\n}\n\nCONSTCD11\ninline\nbool\noperator>=(const year& x, const year& y) NOEXCEPT\n{\n    return !(x < y);\n}\n\nCONSTCD11\ninline\nyears\noperator-(const year& x, const year& y) NOEXCEPT\n{\n    return years{static_cast<int>(x) - static_cast<int>(y)};\n}\n\nCONSTCD11\ninline\nyear\noperator+(const year& x, const years& y) NOEXCEPT\n{\n    return year{static_cast<int>(x) + y.count()};\n}\n\nCONSTCD11\ninline\nyear\noperator+(const years& x, const year& y) NOEXCEPT\n{\n    return y + x;\n}\n\nCONSTCD11\ninline\nyear\noperator-(const year& x, const years& y) NOEXCEPT\n{\n    return year{static_cast<int>(x) - y.count()};\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const year& y)\n{\n    detail::save_ostream<CharT, Traits> _(os);\n    os.fill('0');\n    os.flags(std::ios::dec | std::ios::internal);\n    os.width(4 + (y < year{0}));\n    os.imbue(std::locale::classic());\n    os << static_cast<int>(y);\n    return os;\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year& y)\n{\n    detail::low_level_fmt(os, y);\n    if (!y.ok())\n        os << \" is not a valid year\";\n    return os;\n}\n\n// weekday\n\nCONSTCD14\ninline\nunsigned char\nweekday::weekday_from_days(int z) NOEXCEPT\n{\n    auto u = static_cast<unsigned>(z);\n    return static_cast<unsigned char>(z >= -4 ? (u+4) % 7 : u % 7);\n}\n\nCONSTCD11\ninline\nweekday::weekday(unsigned wd) NOEXCEPT\n    : wd_(static_cast<decltype(wd_)>(wd != 7 ? wd : 0))\n    {}\n\nCONSTCD14\ninline\nweekday::weekday(const sys_days& dp) NOEXCEPT\n    : wd_(weekday_from_days(dp.time_since_epoch().count()))\n    {}\n\nCONSTCD14\ninline\nweekday::weekday(const local_days& dp) NOEXCEPT\n    : wd_(weekday_from_days(dp.time_since_epoch().count()))\n    {}\n\nCONSTCD14 inline weekday& weekday::operator++() NOEXCEPT {*this += days{1}; return *this;}\nCONSTCD14 inline weekday weekday::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;}\nCONSTCD14 inline weekday& weekday::operator--() NOEXCEPT {*this -= days{1}; return *this;}\nCONSTCD14 inline weekday weekday::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;}\n\nCONSTCD14\ninline\nweekday&\nweekday::operator+=(const days& d) NOEXCEPT\n{\n    *this = *this + d;\n    return *this;\n}\n\nCONSTCD14\ninline\nweekday&\nweekday::operator-=(const days& d) NOEXCEPT\n{\n    *this = *this - d;\n    return *this;\n}\n\nCONSTCD11 inline bool weekday::ok() const NOEXCEPT {return wd_ <= 6;}\n\nCONSTCD11\ninline\nunsigned weekday::c_encoding() const NOEXCEPT\n{\n    return unsigned{wd_};\n}\n\nCONSTCD11\ninline\nunsigned weekday::iso_encoding() const NOEXCEPT\n{\n    return unsigned{((wd_ == 0u) ? 7u : wd_)};\n}\n\nCONSTCD11\ninline\nbool\noperator==(const weekday& x, const weekday& y) NOEXCEPT\n{\n    return x.wd_ == y.wd_;\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const weekday& x, const weekday& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nCONSTCD14\ninline\ndays\noperator-(const weekday& x, const weekday& y) NOEXCEPT\n{\n    auto const wdu = x.wd_ - y.wd_;\n    auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7;\n    return days{wdu - wk * 7};\n}\n\nCONSTCD14\ninline\nweekday\noperator+(const weekday& x, const days& y) NOEXCEPT\n{\n    auto const wdu = static_cast<long long>(static_cast<unsigned>(x.wd_)) + y.count();\n    auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7;\n    return weekday{static_cast<unsigned>(wdu - wk * 7)};\n}\n\nCONSTCD14\ninline\nweekday\noperator+(const days& x, const weekday& y) NOEXCEPT\n{\n    return y + x;\n}\n\nCONSTCD14\ninline\nweekday\noperator-(const weekday& x, const days& y) NOEXCEPT\n{\n    return x + -y;\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday& wd)\n{\n    if (wd.ok())\n    {\n        CharT fmt[] = {'%', 'a', 0};\n        os << format(fmt, wd);\n    }\n    else\n        os << wd.c_encoding();\n    return os;\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd)\n{\n    detail::low_level_fmt(os, wd);\n    if (!wd.ok())\n        os << \" is not a valid weekday\";\n    return os;\n}\n\n#if !defined(_MSC_VER) || (_MSC_VER >= 1900)\ninline namespace literals\n{\n\nCONSTCD11\ninline\ndate::day\noperator \"\" _d(unsigned long long d) NOEXCEPT\n{\n    return date::day{static_cast<unsigned>(d)};\n}\n\nCONSTCD11\ninline\ndate::year\noperator \"\" _y(unsigned long long y) NOEXCEPT\n{\n    return date::year(static_cast<int>(y));\n}\n#endif  // !defined(_MSC_VER) || (_MSC_VER >= 1900)\n\nCONSTDATA date::last_spec last{};\n\nCONSTDATA date::month jan{1};\nCONSTDATA date::month feb{2};\nCONSTDATA date::month mar{3};\nCONSTDATA date::month apr{4};\nCONSTDATA date::month may{5};\nCONSTDATA date::month jun{6};\nCONSTDATA date::month jul{7};\nCONSTDATA date::month aug{8};\nCONSTDATA date::month sep{9};\nCONSTDATA date::month oct{10};\nCONSTDATA date::month nov{11};\nCONSTDATA date::month dec{12};\n\nCONSTDATA date::weekday sun{0u};\nCONSTDATA date::weekday mon{1u};\nCONSTDATA date::weekday tue{2u};\nCONSTDATA date::weekday wed{3u};\nCONSTDATA date::weekday thu{4u};\nCONSTDATA date::weekday fri{5u};\nCONSTDATA date::weekday sat{6u};\n\n#if !defined(_MSC_VER) || (_MSC_VER >= 1900)\n}  // inline namespace literals\n#endif\n\nCONSTDATA date::month January{1};\nCONSTDATA date::month February{2};\nCONSTDATA date::month March{3};\nCONSTDATA date::month April{4};\nCONSTDATA date::month May{5};\nCONSTDATA date::month June{6};\nCONSTDATA date::month July{7};\nCONSTDATA date::month August{8};\nCONSTDATA date::month September{9};\nCONSTDATA date::month October{10};\nCONSTDATA date::month November{11};\nCONSTDATA date::month December{12};\n\nCONSTDATA date::weekday Monday{1};\nCONSTDATA date::weekday Tuesday{2};\nCONSTDATA date::weekday Wednesday{3};\nCONSTDATA date::weekday Thursday{4};\nCONSTDATA date::weekday Friday{5};\nCONSTDATA date::weekday Saturday{6};\nCONSTDATA date::weekday Sunday{7};\n\n// weekday_indexed\n\nCONSTCD11\ninline\nweekday\nweekday_indexed::weekday() const NOEXCEPT\n{\n    return date::weekday{static_cast<unsigned>(wd_)};\n}\n\nCONSTCD11 inline unsigned weekday_indexed::index() const NOEXCEPT {return index_;}\n\nCONSTCD11\ninline\nbool\nweekday_indexed::ok() const NOEXCEPT\n{\n    return weekday().ok() && 1 <= index_ && index_ <= 5;\n}\n\n#ifdef __GNUC__\n#  pragma GCC diagnostic push\n#  pragma GCC diagnostic ignored \"-Wconversion\"\n#endif  // __GNUC__\n\nCONSTCD11\ninline\nweekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT\n    : wd_(static_cast<decltype(wd_)>(static_cast<unsigned>(wd.wd_)))\n    , index_(static_cast<decltype(index_)>(index))\n    {}\n\n#ifdef __GNUC__\n#  pragma GCC diagnostic pop\n#endif  // __GNUC__\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi)\n{\n    return low_level_fmt(os, wdi.weekday()) << '[' << wdi.index() << ']';\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi)\n{\n    detail::low_level_fmt(os, wdi);\n    if (!wdi.ok())\n        os << \" is not a valid weekday_indexed\";\n    return os;\n}\n\nCONSTCD11\ninline\nweekday_indexed\nweekday::operator[](unsigned index) const NOEXCEPT\n{\n    return {*this, index};\n}\n\nCONSTCD11\ninline\nbool\noperator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT\n{\n    return x.weekday() == y.weekday() && x.index() == y.index();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\n// weekday_last\n\nCONSTCD11 inline date::weekday weekday_last::weekday() const NOEXCEPT {return wd_;}\nCONSTCD11 inline bool weekday_last::ok() const NOEXCEPT {return wd_.ok();}\nCONSTCD11 inline weekday_last::weekday_last(const date::weekday& wd) NOEXCEPT : wd_(wd) {}\n\nCONSTCD11\ninline\nbool\noperator==(const weekday_last& x, const weekday_last& y) NOEXCEPT\n{\n    return x.weekday() == y.weekday();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl)\n{\n    return low_level_fmt(os, wdl.weekday()) << \"[last]\";\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl)\n{\n    detail::low_level_fmt(os, wdl);\n    if (!wdl.ok())\n        os << \" is not a valid weekday_last\";\n    return os;\n}\n\nCONSTCD11\ninline\nweekday_last\nweekday::operator[](last_spec) const NOEXCEPT\n{\n    return weekday_last{*this};\n}\n\n// year_month\n\nCONSTCD11\ninline\nyear_month::year_month(const date::year& y, const date::month& m) NOEXCEPT\n    : y_(y)\n    , m_(m)\n    {}\n\nCONSTCD11 inline year year_month::year() const NOEXCEPT {return y_;}\nCONSTCD11 inline month year_month::month() const NOEXCEPT {return m_;}\nCONSTCD11 inline bool year_month::ok() const NOEXCEPT {return y_.ok() && m_.ok();}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month&\nyear_month::operator+=(const months& dm) NOEXCEPT\n{\n    *this = *this + dm;\n    return *this;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month&\nyear_month::operator-=(const months& dm) NOEXCEPT\n{\n    *this = *this - dm;\n    return *this;\n}\n\nCONSTCD14\ninline\nyear_month&\nyear_month::operator+=(const years& dy) NOEXCEPT\n{\n    *this = *this + dy;\n    return *this;\n}\n\nCONSTCD14\ninline\nyear_month&\nyear_month::operator-=(const years& dy) NOEXCEPT\n{\n    *this = *this - dy;\n    return *this;\n}\n\nCONSTCD11\ninline\nbool\noperator==(const year_month& x, const year_month& y) NOEXCEPT\n{\n    return x.year() == y.year() && x.month() == y.month();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const year_month& x, const year_month& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nCONSTCD11\ninline\nbool\noperator<(const year_month& x, const year_month& y) NOEXCEPT\n{\n    return x.year() < y.year() ? true\n        : (x.year() > y.year() ? false\n        : (x.month() < y.month()));\n}\n\nCONSTCD11\ninline\nbool\noperator>(const year_month& x, const year_month& y) NOEXCEPT\n{\n    return y < x;\n}\n\nCONSTCD11\ninline\nbool\noperator<=(const year_month& x, const year_month& y) NOEXCEPT\n{\n    return !(y < x);\n}\n\nCONSTCD11\ninline\nbool\noperator>=(const year_month& x, const year_month& y) NOEXCEPT\n{\n    return !(x < y);\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month\noperator+(const year_month& ym, const months& dm) NOEXCEPT\n{\n    auto dmi = static_cast<int>(static_cast<unsigned>(ym.month())) - 1 + dm.count();\n    auto dy = (dmi >= 0 ? dmi : dmi-11) / 12;\n    dmi = dmi - dy * 12 + 1;\n    return (ym.year() + years(dy)) / month(static_cast<unsigned>(dmi));\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month\noperator+(const months& dm, const year_month& ym) NOEXCEPT\n{\n    return ym + dm;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month\noperator-(const year_month& ym, const months& dm) NOEXCEPT\n{\n    return ym + -dm;\n}\n\nCONSTCD11\ninline\nmonths\noperator-(const year_month& x, const year_month& y) NOEXCEPT\n{\n    return (x.year() - y.year()) +\n            months(static_cast<unsigned>(x.month()) - static_cast<unsigned>(y.month()));\n}\n\nCONSTCD11\ninline\nyear_month\noperator+(const year_month& ym, const years& dy) NOEXCEPT\n{\n    return (ym.year() + dy) / ym.month();\n}\n\nCONSTCD11\ninline\nyear_month\noperator+(const years& dy, const year_month& ym) NOEXCEPT\n{\n    return ym + dy;\n}\n\nCONSTCD11\ninline\nyear_month\noperator-(const year_month& ym, const years& dy) NOEXCEPT\n{\n    return ym + -dy;\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const year_month& ym)\n{\n    low_level_fmt(os, ym.year()) << '/';\n    return low_level_fmt(os, ym.month());\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year_month& ym)\n{\n    detail::low_level_fmt(os, ym);\n    if (!ym.ok())\n        os << \" is not a valid year_month\";\n    return os;\n}\n\n// month_day\n\nCONSTCD11\ninline\nmonth_day::month_day(const date::month& m, const date::day& d) NOEXCEPT\n    : m_(m)\n    , d_(d)\n    {}\n\nCONSTCD11 inline date::month month_day::month() const NOEXCEPT {return m_;}\nCONSTCD11 inline date::day month_day::day() const NOEXCEPT {return d_;}\n\nCONSTCD14\ninline\nbool\nmonth_day::ok() const NOEXCEPT\n{\n    CONSTDATA date::day d[] =\n    {\n        date::day(31), date::day(29), date::day(31),\n        date::day(30), date::day(31), date::day(30),\n        date::day(31), date::day(31), date::day(30),\n        date::day(31), date::day(30), date::day(31)\n    };\n    return m_.ok() && date::day{1} <= d_ && d_ <= d[static_cast<unsigned>(m_)-1];\n}\n\nCONSTCD11\ninline\nbool\noperator==(const month_day& x, const month_day& y) NOEXCEPT\n{\n    return x.month() == y.month() && x.day() == y.day();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const month_day& x, const month_day& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nCONSTCD11\ninline\nbool\noperator<(const month_day& x, const month_day& y) NOEXCEPT\n{\n    return x.month() < y.month() ? true\n        : (x.month() > y.month() ? false\n        : (x.day() < y.day()));\n}\n\nCONSTCD11\ninline\nbool\noperator>(const month_day& x, const month_day& y) NOEXCEPT\n{\n    return y < x;\n}\n\nCONSTCD11\ninline\nbool\noperator<=(const month_day& x, const month_day& y) NOEXCEPT\n{\n    return !(y < x);\n}\n\nCONSTCD11\ninline\nbool\noperator>=(const month_day& x, const month_day& y) NOEXCEPT\n{\n    return !(x < y);\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_day& md)\n{\n    low_level_fmt(os, md.month()) << '/';\n    return low_level_fmt(os, md.day());\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const month_day& md)\n{\n    detail::low_level_fmt(os, md);\n    if (!md.ok())\n        os << \" is not a valid month_day\";\n    return os;\n}\n\n// month_day_last\n\nCONSTCD11 inline month month_day_last::month() const NOEXCEPT {return m_;}\nCONSTCD11 inline bool month_day_last::ok() const NOEXCEPT {return m_.ok();}\nCONSTCD11 inline month_day_last::month_day_last(const date::month& m) NOEXCEPT : m_(m) {}\n\nCONSTCD11\ninline\nbool\noperator==(const month_day_last& x, const month_day_last& y) NOEXCEPT\n{\n    return x.month() == y.month();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nCONSTCD11\ninline\nbool\noperator<(const month_day_last& x, const month_day_last& y) NOEXCEPT\n{\n    return x.month() < y.month();\n}\n\nCONSTCD11\ninline\nbool\noperator>(const month_day_last& x, const month_day_last& y) NOEXCEPT\n{\n    return y < x;\n}\n\nCONSTCD11\ninline\nbool\noperator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT\n{\n    return !(y < x);\n}\n\nCONSTCD11\ninline\nbool\noperator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT\n{\n    return !(x < y);\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl)\n{\n    return low_level_fmt(os, mdl.month()) << \"/last\";\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl)\n{\n    detail::low_level_fmt(os, mdl);\n    if (!mdl.ok())\n        os << \" is not a valid month_day_last\";\n    return os;\n}\n\n// month_weekday\n\nCONSTCD11\ninline\nmonth_weekday::month_weekday(const date::month& m,\n                             const date::weekday_indexed& wdi) NOEXCEPT\n    : m_(m)\n    , wdi_(wdi)\n    {}\n\nCONSTCD11 inline month month_weekday::month() const NOEXCEPT {return m_;}\n\nCONSTCD11\ninline\nweekday_indexed\nmonth_weekday::weekday_indexed() const NOEXCEPT\n{\n    return wdi_;\n}\n\nCONSTCD11\ninline\nbool\nmonth_weekday::ok() const NOEXCEPT\n{\n    return m_.ok() && wdi_.ok();\n}\n\nCONSTCD11\ninline\nbool\noperator==(const month_weekday& x, const month_weekday& y) NOEXCEPT\n{\n    return x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd)\n{\n    low_level_fmt(os, mwd.month()) << '/';\n    return low_level_fmt(os, mwd.weekday_indexed());\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd)\n{\n    detail::low_level_fmt(os, mwd);\n    if (!mwd.ok())\n        os << \" is not a valid month_weekday\";\n    return os;\n}\n\n// month_weekday_last\n\nCONSTCD11\ninline\nmonth_weekday_last::month_weekday_last(const date::month& m,\n                                       const date::weekday_last& wdl) NOEXCEPT\n    : m_(m)\n    , wdl_(wdl)\n    {}\n\nCONSTCD11 inline month month_weekday_last::month() const NOEXCEPT {return m_;}\n\nCONSTCD11\ninline\nweekday_last\nmonth_weekday_last::weekday_last() const NOEXCEPT\n{\n    return wdl_;\n}\n\nCONSTCD11\ninline\nbool\nmonth_weekday_last::ok() const NOEXCEPT\n{\n    return m_.ok() && wdl_.ok();\n}\n\nCONSTCD11\ninline\nbool\noperator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT\n{\n    return x.month() == y.month() && x.weekday_last() == y.weekday_last();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl)\n{\n    low_level_fmt(os, mwdl.month()) << '/';\n    return low_level_fmt(os, mwdl.weekday_last());\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl)\n{\n    detail::low_level_fmt(os, mwdl);\n    if (!mwdl.ok())\n        os << \" is not a valid month_weekday_last\";\n    return os;\n}\n\n// year_month_day_last\n\nCONSTCD11\ninline\nyear_month_day_last::year_month_day_last(const date::year& y,\n                                         const date::month_day_last& mdl) NOEXCEPT\n    : y_(y)\n    , mdl_(mdl)\n    {}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_day_last&\nyear_month_day_last::operator+=(const months& m) NOEXCEPT\n{\n    *this = *this + m;\n    return *this;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_day_last&\nyear_month_day_last::operator-=(const months& m) NOEXCEPT\n{\n    *this = *this - m;\n    return *this;\n}\n\nCONSTCD14\ninline\nyear_month_day_last&\nyear_month_day_last::operator+=(const years& y) NOEXCEPT\n{\n    *this = *this + y;\n    return *this;\n}\n\nCONSTCD14\ninline\nyear_month_day_last&\nyear_month_day_last::operator-=(const years& y) NOEXCEPT\n{\n    *this = *this - y;\n    return *this;\n}\n\nCONSTCD11 inline year year_month_day_last::year() const NOEXCEPT {return y_;}\nCONSTCD11 inline month year_month_day_last::month() const NOEXCEPT {return mdl_.month();}\n\nCONSTCD11\ninline\nmonth_day_last\nyear_month_day_last::month_day_last() const NOEXCEPT\n{\n    return mdl_;\n}\n\nCONSTCD14\ninline\nday\nyear_month_day_last::day() const NOEXCEPT\n{\n    CONSTDATA date::day d[] =\n    {\n        date::day(31), date::day(28), date::day(31),\n        date::day(30), date::day(31), date::day(30),\n        date::day(31), date::day(31), date::day(30),\n        date::day(31), date::day(30), date::day(31)\n    };\n    return (month() != February || !y_.is_leap()) && mdl_.ok() ?\n        d[static_cast<unsigned>(month()) - 1] : date::day{29};\n}\n\nCONSTCD14\ninline\nyear_month_day_last::operator sys_days() const NOEXCEPT\n{\n    return sys_days(year()/month()/day());\n}\n\nCONSTCD14\ninline\nyear_month_day_last::operator local_days() const NOEXCEPT\n{\n    return local_days(year()/month()/day());\n}\n\nCONSTCD11\ninline\nbool\nyear_month_day_last::ok() const NOEXCEPT\n{\n    return y_.ok() && mdl_.ok();\n}\n\nCONSTCD11\ninline\nbool\noperator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT\n{\n    return x.year() == y.year() && x.month_day_last() == y.month_day_last();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nCONSTCD11\ninline\nbool\noperator<(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT\n{\n    return x.year() < y.year() ? true\n        : (x.year() > y.year() ? false\n        : (x.month_day_last() < y.month_day_last()));\n}\n\nCONSTCD11\ninline\nbool\noperator>(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT\n{\n    return y < x;\n}\n\nCONSTCD11\ninline\nbool\noperator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT\n{\n    return !(y < x);\n}\n\nCONSTCD11\ninline\nbool\noperator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT\n{\n    return !(x < y);\n}\n\nnamespace detail\n{\n\ntemplate<class CharT, class Traits>\nstd::basic_ostream<CharT, Traits>&\nlow_level_fmt(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl)\n{\n    low_level_fmt(os, ymdl.year()) << '/';\n    return low_level_fmt(os, ymdl.month_day_last());\n}\n\n}  // namespace detail\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl)\n{\n    detail::low_level_fmt(os, ymdl);\n    if (!ymdl.ok())\n        os << \" is not a valid year_month_day_last\";\n    return os;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_day_last\noperator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT\n{\n    return (ymdl.year() / ymdl.month() + dm) / last;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_day_last\noperator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT\n{\n    return ymdl + dm;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_day_last\noperator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT\n{\n    return ymdl + (-dm);\n}\n\nCONSTCD11\ninline\nyear_month_day_last\noperator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT\n{\n    return {ymdl.year()+dy, ymdl.month_day_last()};\n}\n\nCONSTCD11\ninline\nyear_month_day_last\noperator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT\n{\n    return ymdl + dy;\n}\n\nCONSTCD11\ninline\nyear_month_day_last\noperator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT\n{\n    return ymdl + (-dy);\n}\n\n// year_month_day\n\nCONSTCD11\ninline\nyear_month_day::year_month_day(const date::year& y, const date::month& m,\n                               const date::day& d) NOEXCEPT\n    : y_(y)\n    , m_(m)\n    , d_(d)\n    {}\n\nCONSTCD14\ninline\nyear_month_day::year_month_day(const year_month_day_last& ymdl) NOEXCEPT\n    : y_(ymdl.year())\n    , m_(ymdl.month())\n    , d_(ymdl.day())\n    {}\n\nCONSTCD14\ninline\nyear_month_day::year_month_day(sys_days dp) NOEXCEPT\n    : year_month_day(from_days(dp.time_since_epoch()))\n    {}\n\nCONSTCD14\ninline\nyear_month_day::year_month_day(local_days dp) NOEXCEPT\n    : year_month_day(from_days(dp.time_since_epoch()))\n    {}\n\nCONSTCD11 inline year year_month_day::year() const NOEXCEPT {return y_;}\nCONSTCD11 inline month year_month_day::month() const NOEXCEPT {return m_;}\nCONSTCD11 inline day year_month_day::day() const NOEXCEPT {return d_;}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_day&\nyear_month_day::operator+=(const months& m) NOEXCEPT\n{\n    *this = *this + m;\n    return *this;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_day&\nyear_month_day::operator-=(const months& m) NOEXCEPT\n{\n    *this = *this - m;\n    return *this;\n}\n\nCONSTCD14\ninline\nyear_month_day&\nyear_month_day::operator+=(const years& y) NOEXCEPT\n{\n    *this = *this + y;\n    return *this;\n}\n\nCONSTCD14\ninline\nyear_month_day&\nyear_month_day::operator-=(const years& y) NOEXCEPT\n{\n    *this = *this - y;\n    return *this;\n}\n\nCONSTCD14\ninline\ndays\nyear_month_day::to_days() const NOEXCEPT\n{\n    static_assert(std::numeric_limits<unsigned>::digits >= 18,\n             \"This algorithm has not been ported to a 16 bit unsigned integer\");\n    static_assert(std::numeric_limits<int>::digits >= 20,\n             \"This algorithm has not been ported to a 16 bit signed integer\");\n    auto const y = static_cast<int>(y_) - (m_ <= February);\n    auto const m = static_cast<unsigned>(m_);\n    auto const d = static_cast<unsigned>(d_);\n    auto const era = (y >= 0 ? y : y-399) / 400;\n    auto const yoe = static_cast<unsigned>(y - era * 400);       // [0, 399]\n    auto const doy = (153*(m > 2 ? m-3 : m+9) + 2)/5 + d-1;      // [0, 365]\n    auto const doe = yoe * 365 + yoe/4 - yoe/100 + doy;          // [0, 146096]\n    return days{era * 146097 + static_cast<int>(doe) - 719468};\n}\n\nCONSTCD14\ninline\nyear_month_day::operator sys_days() const NOEXCEPT\n{\n    return sys_days{to_days()};\n}\n\nCONSTCD14\ninline\nyear_month_day::operator local_days() const NOEXCEPT\n{\n    return local_days{to_days()};\n}\n\nCONSTCD14\ninline\nbool\nyear_month_day::ok() const NOEXCEPT\n{\n    if (!(y_.ok() && m_.ok()))\n        return false;\n    return date::day{1} <= d_ && d_ <= (y_ / m_ / last).day();\n}\n\nCONSTCD11\ninline\nbool\noperator==(const year_month_day& x, const year_month_day& y) NOEXCEPT\n{\n    return x.year() == y.year() && x.month() == y.month() && x.day() == y.day();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\nCONSTCD11\ninline\nbool\noperator<(const year_month_day& x, const year_month_day& y) NOEXCEPT\n{\n    return x.year() < y.year() ? true\n        : (x.year() > y.year() ? false\n        : (x.month() < y.month() ? true\n        : (x.month() > y.month() ? false\n        : (x.day() < y.day()))));\n}\n\nCONSTCD11\ninline\nbool\noperator>(const year_month_day& x, const year_month_day& y) NOEXCEPT\n{\n    return y < x;\n}\n\nCONSTCD11\ninline\nbool\noperator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT\n{\n    return !(y < x);\n}\n\nCONSTCD11\ninline\nbool\noperator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT\n{\n    return !(x < y);\n}\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd)\n{\n    detail::save_ostream<CharT, Traits> _(os);\n    os.fill('0');\n    os.flags(std::ios::dec | std::ios::right);\n    os.imbue(std::locale::classic());\n    os << static_cast<int>(ymd.year()) << '-';\n    os.width(2);\n    os << static_cast<unsigned>(ymd.month()) << '-';\n    os.width(2);\n    os << static_cast<unsigned>(ymd.day());\n    if (!ymd.ok())\n        os << \" is not a valid year_month_day\";\n    return os;\n}\n\nCONSTCD14\ninline\nyear_month_day\nyear_month_day::from_days(days dp) NOEXCEPT\n{\n    static_assert(std::numeric_limits<unsigned>::digits >= 18,\n             \"This algorithm has not been ported to a 16 bit unsigned integer\");\n    static_assert(std::numeric_limits<int>::digits >= 20,\n             \"This algorithm has not been ported to a 16 bit signed integer\");\n    auto const z = dp.count() + 719468;\n    auto const era = (z >= 0 ? z : z - 146096) / 146097;\n    auto const doe = static_cast<unsigned>(z - era * 146097);          // [0, 146096]\n    auto const yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365;  // [0, 399]\n    auto const y = static_cast<days::rep>(yoe) + era * 400;\n    auto const doy = doe - (365*yoe + yoe/4 - yoe/100);                // [0, 365]\n    auto const mp = (5*doy + 2)/153;                                   // [0, 11]\n    auto const d = doy - (153*mp+2)/5 + 1;                             // [1, 31]\n    auto const m = mp < 10 ? mp+3 : mp-9;                              // [1, 12]\n    return year_month_day{date::year{y + (m <= 2)}, date::month(m), date::day(d)};\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_day\noperator+(const year_month_day& ymd, const months& dm) NOEXCEPT\n{\n    return (ymd.year() / ymd.month() + dm) / ymd.day();\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_day\noperator+(const months& dm, const year_month_day& ymd) NOEXCEPT\n{\n    return ymd + dm;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_day\noperator-(const year_month_day& ymd, const months& dm) NOEXCEPT\n{\n    return ymd + (-dm);\n}\n\nCONSTCD11\ninline\nyear_month_day\noperator+(const year_month_day& ymd, const years& dy) NOEXCEPT\n{\n    return (ymd.year() + dy) / ymd.month() / ymd.day();\n}\n\nCONSTCD11\ninline\nyear_month_day\noperator+(const years& dy, const year_month_day& ymd) NOEXCEPT\n{\n    return ymd + dy;\n}\n\nCONSTCD11\ninline\nyear_month_day\noperator-(const year_month_day& ymd, const years& dy) NOEXCEPT\n{\n    return ymd + (-dy);\n}\n\n// year_month_weekday\n\nCONSTCD11\ninline\nyear_month_weekday::year_month_weekday(const date::year& y, const date::month& m,\n                                       const date::weekday_indexed& wdi)\n        NOEXCEPT\n    : y_(y)\n    , m_(m)\n    , wdi_(wdi)\n    {}\n\nCONSTCD14\ninline\nyear_month_weekday::year_month_weekday(const sys_days& dp) NOEXCEPT\n    : year_month_weekday(from_days(dp.time_since_epoch()))\n    {}\n\nCONSTCD14\ninline\nyear_month_weekday::year_month_weekday(const local_days& dp) NOEXCEPT\n    : year_month_weekday(from_days(dp.time_since_epoch()))\n    {}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_weekday&\nyear_month_weekday::operator+=(const months& m) NOEXCEPT\n{\n    *this = *this + m;\n    return *this;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_weekday&\nyear_month_weekday::operator-=(const months& m) NOEXCEPT\n{\n    *this = *this - m;\n    return *this;\n}\n\nCONSTCD14\ninline\nyear_month_weekday&\nyear_month_weekday::operator+=(const years& y) NOEXCEPT\n{\n    *this = *this + y;\n    return *this;\n}\n\nCONSTCD14\ninline\nyear_month_weekday&\nyear_month_weekday::operator-=(const years& y) NOEXCEPT\n{\n    *this = *this - y;\n    return *this;\n}\n\nCONSTCD11 inline year year_month_weekday::year() const NOEXCEPT {return y_;}\nCONSTCD11 inline month year_month_weekday::month() const NOEXCEPT {return m_;}\n\nCONSTCD11\ninline\nweekday\nyear_month_weekday::weekday() const NOEXCEPT\n{\n    return wdi_.weekday();\n}\n\nCONSTCD11\ninline\nunsigned\nyear_month_weekday::index() const NOEXCEPT\n{\n    return wdi_.index();\n}\n\nCONSTCD11\ninline\nweekday_indexed\nyear_month_weekday::weekday_indexed() const NOEXCEPT\n{\n    return wdi_;\n}\n\nCONSTCD14\ninline\nyear_month_weekday::operator sys_days() const NOEXCEPT\n{\n    return sys_days{to_days()};\n}\n\nCONSTCD14\ninline\nyear_month_weekday::operator local_days() const NOEXCEPT\n{\n    return local_days{to_days()};\n}\n\nCONSTCD14\ninline\nbool\nyear_month_weekday::ok() const NOEXCEPT\n{\n    if (!y_.ok() || !m_.ok() || !wdi_.weekday().ok() || wdi_.index() < 1)\n        return false;\n    if (wdi_.index() <= 4)\n        return true;\n    auto d2 = wdi_.weekday() - date::weekday(static_cast<sys_days>(y_/m_/1)) +\n                  days((wdi_.index()-1)*7 + 1);\n    return static_cast<unsigned>(d2.count()) <= static_cast<unsigned>((y_/m_/last).day());\n}\n\nCONSTCD14\ninline\nyear_month_weekday\nyear_month_weekday::from_days(days d) NOEXCEPT\n{\n    sys_days dp{d};\n    auto const wd = date::weekday(dp);\n    auto const ymd = year_month_day(dp);\n    return {ymd.year(), ymd.month(), wd[(static_cast<unsigned>(ymd.day())-1)/7+1]};\n}\n\nCONSTCD14\ninline\ndays\nyear_month_weekday::to_days() const NOEXCEPT\n{\n    auto d = sys_days(y_/m_/1);\n    return (d + (wdi_.weekday() - date::weekday(d) + days{(wdi_.index()-1)*7})\n           ).time_since_epoch();\n}\n\nCONSTCD11\ninline\nbool\noperator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT\n{\n    return x.year() == y.year() && x.month() == y.month() &&\n           x.weekday_indexed() == y.weekday_indexed();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday& ymwdi)\n{\n    detail::low_level_fmt(os, ymwdi.year()) << '/';\n    detail::low_level_fmt(os, ymwdi.month()) << '/';\n    detail::low_level_fmt(os, ymwdi.weekday_indexed());\n    if (!ymwdi.ok())\n        os << \" is not a valid year_month_weekday\";\n    return os;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_weekday\noperator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT\n{\n    return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed();\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_weekday\noperator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT\n{\n    return ymwd + dm;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_weekday\noperator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT\n{\n    return ymwd + (-dm);\n}\n\nCONSTCD11\ninline\nyear_month_weekday\noperator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT\n{\n    return {ymwd.year()+dy, ymwd.month(), ymwd.weekday_indexed()};\n}\n\nCONSTCD11\ninline\nyear_month_weekday\noperator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT\n{\n    return ymwd + dy;\n}\n\nCONSTCD11\ninline\nyear_month_weekday\noperator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT\n{\n    return ymwd + (-dy);\n}\n\n// year_month_weekday_last\n\nCONSTCD11\ninline\nyear_month_weekday_last::year_month_weekday_last(const date::year& y,\n                                                 const date::month& m,\n                                                 const date::weekday_last& wdl) NOEXCEPT\n    : y_(y)\n    , m_(m)\n    , wdl_(wdl)\n    {}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_weekday_last&\nyear_month_weekday_last::operator+=(const months& m) NOEXCEPT\n{\n    *this = *this + m;\n    return *this;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_weekday_last&\nyear_month_weekday_last::operator-=(const months& m) NOEXCEPT\n{\n    *this = *this - m;\n    return *this;\n}\n\nCONSTCD14\ninline\nyear_month_weekday_last&\nyear_month_weekday_last::operator+=(const years& y) NOEXCEPT\n{\n    *this = *this + y;\n    return *this;\n}\n\nCONSTCD14\ninline\nyear_month_weekday_last&\nyear_month_weekday_last::operator-=(const years& y) NOEXCEPT\n{\n    *this = *this - y;\n    return *this;\n}\n\nCONSTCD11 inline year year_month_weekday_last::year() const NOEXCEPT {return y_;}\nCONSTCD11 inline month year_month_weekday_last::month() const NOEXCEPT {return m_;}\n\nCONSTCD11\ninline\nweekday\nyear_month_weekday_last::weekday() const NOEXCEPT\n{\n    return wdl_.weekday();\n}\n\nCONSTCD11\ninline\nweekday_last\nyear_month_weekday_last::weekday_last() const NOEXCEPT\n{\n    return wdl_;\n}\n\nCONSTCD14\ninline\nyear_month_weekday_last::operator sys_days() const NOEXCEPT\n{\n    return sys_days{to_days()};\n}\n\nCONSTCD14\ninline\nyear_month_weekday_last::operator local_days() const NOEXCEPT\n{\n    return local_days{to_days()};\n}\n\nCONSTCD11\ninline\nbool\nyear_month_weekday_last::ok() const NOEXCEPT\n{\n    return y_.ok() && m_.ok() && wdl_.ok();\n}\n\nCONSTCD14\ninline\ndays\nyear_month_weekday_last::to_days() const NOEXCEPT\n{\n    auto const d = sys_days(y_/m_/last);\n    return (d - (date::weekday{d} - wdl_.weekday())).time_since_epoch();\n}\n\nCONSTCD11\ninline\nbool\noperator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT\n{\n    return x.year() == y.year() && x.month() == y.month() &&\n           x.weekday_last() == y.weekday_last();\n}\n\nCONSTCD11\ninline\nbool\noperator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT\n{\n    return !(x == y);\n}\n\ntemplate<class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday_last& ymwdl)\n{\n    detail::low_level_fmt(os, ymwdl.year()) << '/';\n    detail::low_level_fmt(os, ymwdl.month()) << '/';\n    detail::low_level_fmt(os, ymwdl.weekday_last());\n    if (!ymwdl.ok())\n        os << \" is not a valid year_month_weekday_last\";\n    return os;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_weekday_last\noperator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT\n{\n    return (ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last();\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_weekday_last\noperator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT\n{\n    return ymwdl + dm;\n}\n\ntemplate<class>\nCONSTCD14\ninline\nyear_month_weekday_last\noperator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT\n{\n    return ymwdl + (-dm);\n}\n\nCONSTCD11\ninline\nyear_month_weekday_last\noperator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT\n{\n    return {ymwdl.year()+dy, ymwdl.month(), ymwdl.weekday_last()};\n}\n\nCONSTCD11\ninline\nyear_month_weekday_last\noperator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT\n{\n    return ymwdl + dy;\n}\n\nCONSTCD11\ninline\nyear_month_weekday_last\noperator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT\n{\n    return ymwdl + (-dy);\n}\n\n// year_month from operator/()\n\nCONSTCD11\ninline\nyear_month\noperator/(const year& y, const month& m) NOEXCEPT\n{\n    return {y, m};\n}\n\nCONSTCD11\ninline\nyear_month\noperator/(const year& y, int   m) NOEXCEPT\n{\n    return y / month(static_cast<unsigned>(m));\n}\n\n// month_day from operator/()\n\nCONSTCD11\ninline\nmonth_day\noperator/(const month& m, const day& d) NOEXCEPT\n{\n    return {m, d};\n}\n\nCONSTCD11\ninline\nmonth_day\noperator/(const day& d, const month& m) NOEXCEPT\n{\n    return m / d;\n}\n\nCONSTCD11\ninline\nmonth_day\noperator/(const month& m, int d) NOEXCEPT\n{\n    return m / day(static_cast<unsigned>(d));\n}\n\nCONSTCD11\ninline\nmonth_day\noperator/(int m, const day& d) NOEXCEPT\n{\n    return month(static_cast<unsigned>(m)) / d;\n}\n\nCONSTCD11 inline month_day operator/(const day& d, int m) NOEXCEPT {return m / d;}\n\n// month_day_last from operator/()\n\nCONSTCD11\ninline\nmonth_day_last\noperator/(const month& m, last_spec) NOEXCEPT\n{\n    return month_day_last{m};\n}\n\nCONSTCD11\ninline\nmonth_day_last\noperator/(last_spec, const month& m) NOEXCEPT\n{\n    return m/last;\n}\n\nCONSTCD11\ninline\nmonth_day_last\noperator/(int m, last_spec) NOEXCEPT\n{\n    return month(static_cast<unsigned>(m))/last;\n}\n\nCONSTCD11\ninline\nmonth_day_last\noperator/(last_spec, int m) NOEXCEPT\n{\n    return m/last;\n}\n\n// month_weekday from operator/()\n\nCONSTCD11\ninline\nmonth_weekday\noperator/(const month& m, const weekday_indexed& wdi) NOEXCEPT\n{\n    return {m, wdi};\n}\n\nCONSTCD11\ninline\nmonth_weekday\noperator/(const weekday_indexed& wdi, const month& m) NOEXCEPT\n{\n    return m / wdi;\n}\n\nCONSTCD11\ninline\nmonth_weekday\noperator/(int m, const weekday_indexed& wdi) NOEXCEPT\n{\n    return month(static_cast<unsigned>(m)) / wdi;\n}\n\nCONSTCD11\ninline\nmonth_weekday\noperator/(const weekday_indexed& wdi, int m) NOEXCEPT\n{\n    return m / wdi;\n}\n\n// month_weekday_last from operator/()\n\nCONSTCD11\ninline\nmonth_weekday_last\noperator/(const month& m, const weekday_last& wdl) NOEXCEPT\n{\n    return {m, wdl};\n}\n\nCONSTCD11\ninline\nmonth_weekday_last\noperator/(const weekday_last& wdl, const month& m) NOEXCEPT\n{\n    return m / wdl;\n}\n\nCONSTCD11\ninline\nmonth_weekday_last\noperator/(int m, const weekday_last& wdl) NOEXCEPT\n{\n    return month(static_cast<unsigned>(m)) / wdl;\n}\n\nCONSTCD11\ninline\nmonth_weekday_last\noperator/(const weekday_last& wdl, int m) NOEXCEPT\n{\n    return m / wdl;\n}\n\n// year_month_day from operator/()\n\nCONSTCD11\ninline\nyear_month_day\noperator/(const year_month& ym, const day& d) NOEXCEPT\n{\n    return {ym.year(), ym.month(), d};\n}\n\nCONSTCD11\ninline\nyear_month_day\noperator/(const year_month& ym, int d)  NOEXCEPT\n{\n    return ym / day(static_cast<unsigned>(d));\n}\n\nCONSTCD11\ninline\nyear_month_day\noperator/(const year& y, const month_day& md) NOEXCEPT\n{\n    return y / md.month() / md.day();\n}\n\nCONSTCD11\ninline\nyear_month_day\noperator/(int y, const month_day& md) NOEXCEPT\n{\n    return year(y) / md;\n}\n\nCONSTCD11\ninline\nyear_month_day\noperator/(const month_day& md, const year& y)  NOEXCEPT\n{\n    return y / md;\n}\n\nCONSTCD11\ninline\nyear_month_day\noperator/(const month_day& md, int y) NOEXCEPT\n{\n    return year(y) / md;\n}\n\n// year_month_day_last from operator/()\n\nCONSTCD11\ninline\nyear_month_day_last\noperator/(const year_month& ym, last_spec) NOEXCEPT\n{\n    return {ym.year(), month_day_last{ym.month()}};\n}\n\nCONSTCD11\ninline\nyear_month_day_last\noperator/(const year& y, const month_day_last& mdl) NOEXCEPT\n{\n    return {y, mdl};\n}\n\nCONSTCD11\ninline\nyear_month_day_last\noperator/(int y, const month_day_last& mdl) NOEXCEPT\n{\n    return year(y) / mdl;\n}\n\nCONSTCD11\ninline\nyear_month_day_last\noperator/(const month_day_last& mdl, const year& y) NOEXCEPT\n{\n    return y / mdl;\n}\n\nCONSTCD11\ninline\nyear_month_day_last\noperator/(const month_day_last& mdl, int y) NOEXCEPT\n{\n    return year(y) / mdl;\n}\n\n// year_month_weekday from operator/()\n\nCONSTCD11\ninline\nyear_month_weekday\noperator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT\n{\n    return {ym.year(), ym.month(), wdi};\n}\n\nCONSTCD11\ninline\nyear_month_weekday\noperator/(const year& y, const month_weekday& mwd) NOEXCEPT\n{\n    return {y, mwd.month(), mwd.weekday_indexed()};\n}\n\nCONSTCD11\ninline\nyear_month_weekday\noperator/(int y, const month_weekday& mwd) NOEXCEPT\n{\n    return year(y) / mwd;\n}\n\nCONSTCD11\ninline\nyear_month_weekday\noperator/(const month_weekday& mwd, const year& y) NOEXCEPT\n{\n    return y / mwd;\n}\n\nCONSTCD11\ninline\nyear_month_weekday\noperator/(const month_weekday& mwd, int y) NOEXCEPT\n{\n    return year(y) / mwd;\n}\n\n// year_month_weekday_last from operator/()\n\nCONSTCD11\ninline\nyear_month_weekday_last\noperator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT\n{\n    return {ym.year(), ym.month(), wdl};\n}\n\nCONSTCD11\ninline\nyear_month_weekday_last\noperator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT\n{\n    return {y, mwdl.month(), mwdl.weekday_last()};\n}\n\nCONSTCD11\ninline\nyear_month_weekday_last\noperator/(int y, const month_weekday_last& mwdl) NOEXCEPT\n{\n    return year(y) / mwdl;\n}\n\nCONSTCD11\ninline\nyear_month_weekday_last\noperator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT\n{\n    return y / mwdl;\n}\n\nCONSTCD11\ninline\nyear_month_weekday_last\noperator/(const month_weekday_last& mwdl, int y) NOEXCEPT\n{\n    return year(y) / mwdl;\n}\n\ntemplate <class Duration>\nstruct fields;\n\ntemplate <class CharT, class Traits, class Duration>\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,\n          const fields<Duration>& fds, const std::string* abbrev = nullptr,\n          const std::chrono::seconds* offset_sec = nullptr);\n\ntemplate <class CharT, class Traits, class Duration, class Alloc>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,\n            fields<Duration>& fds, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr);\n\n// hh_mm_ss\n\nnamespace detail\n{\n\nstruct undocumented {explicit undocumented() = default;};\n\n// width<n>::value is the number of fractional decimal digits in 1/n\n// width<0>::value and width<1>::value are defined to be 0\n// If 1/n takes more than 18 fractional decimal digits,\n//   the result is truncated to 19.\n// Example:  width<2>::value    ==  1\n// Example:  width<3>::value    == 19\n// Example:  width<4>::value    ==  2\n// Example:  width<10>::value   ==  1\n// Example:  width<1000>::value ==  3\ntemplate <std::uint64_t n, std::uint64_t d, unsigned w = 0,\n          bool should_continue = n%d != 0 && (w < 19)>\nstruct width\n{\n    static_assert(d > 0, \"width called with zero denominator\");\n    static CONSTDATA unsigned value = 1 + width<n%d*10, d, w+1>::value;\n};\n\ntemplate <std::uint64_t n, std::uint64_t d, unsigned w>\nstruct width<n, d, w, false>\n{\n    static CONSTDATA unsigned value = 0;\n};\n\ntemplate <unsigned exp>\nstruct static_pow10\n{\nprivate:\n    static CONSTDATA std::uint64_t h = static_pow10<exp/2>::value;\npublic:\n    static CONSTDATA std::uint64_t value = h * h * (exp % 2 ? 10 : 1);\n};\n\ntemplate <>\nstruct static_pow10<0>\n{\n    static CONSTDATA std::uint64_t value = 1;\n};\n\ntemplate <class Duration>\nclass decimal_format_seconds\n{\n    using CT = typename std::common_type<Duration, std::chrono::seconds>::type;\n    using rep = typename CT::rep;\n    static unsigned CONSTDATA trial_width =\n        detail::width<CT::period::num, CT::period::den>::value;\npublic:\n    static unsigned CONSTDATA width = trial_width < 19 ? trial_width : 6u;\n    using precision = std::chrono::duration<rep,\n                                            std::ratio<1, static_pow10<width>::value>>;\n\nprivate:\n    std::chrono::seconds s_;\n    precision            sub_s_;\n\npublic:\n    CONSTCD11 decimal_format_seconds()\n        : s_()\n        , sub_s_()\n        {}\n\n    CONSTCD11 explicit decimal_format_seconds(const Duration& d) NOEXCEPT\n        : s_(std::chrono::duration_cast<std::chrono::seconds>(d))\n        , sub_s_(std::chrono::duration_cast<precision>(d - s_))\n        {}\n\n    CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_;}\n    CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_;}\n    CONSTCD11 precision subseconds() const NOEXCEPT {return sub_s_;}\n\n    CONSTCD14 precision to_duration() const NOEXCEPT\n    {\n        return s_ + sub_s_;\n    }\n\n    CONSTCD11 bool in_conventional_range() const NOEXCEPT\n    {\n        return sub_s_ < std::chrono::seconds{1} && s_ < std::chrono::minutes{1};\n    }\n\n    template <class CharT, class Traits>\n    friend\n    std::basic_ostream<CharT, Traits>&\n    operator<<(std::basic_ostream<CharT, Traits>& os, const decimal_format_seconds& x)\n    {\n        return x.print(os, std::chrono::treat_as_floating_point<rep>{});\n    }\n\n    template <class CharT, class Traits>\n    std::basic_ostream<CharT, Traits>&\n    print(std::basic_ostream<CharT, Traits>& os, std::true_type) const\n    {\n        date::detail::save_ostream<CharT, Traits> _(os);\n        std::chrono::duration<rep> d = s_ + sub_s_;\n        if (d < std::chrono::seconds{10})\n            os << '0';\n        os.precision(width+6);\n        os << std::fixed << d.count();\n        return os;\n    }\n\n    template <class CharT, class Traits>\n    std::basic_ostream<CharT, Traits>&\n    print(std::basic_ostream<CharT, Traits>& os, std::false_type) const\n    {\n        date::detail::save_ostream<CharT, Traits> _(os);\n        os.fill('0');\n        os.flags(std::ios::dec | std::ios::right);\n        os.width(2);\n        os << s_.count();\n        if (width > 0)\n        {\n#if !ONLY_C_LOCALE\n            os << std::use_facet<std::numpunct<CharT>>(os.getloc()).decimal_point();\n#else\n            os << '.';\n#endif\n            date::detail::save_ostream<CharT, Traits> _s(os);\n            os.imbue(std::locale::classic());\n            os.width(width);\n            os << sub_s_.count();\n        }\n        return os;\n    }\n};\n\ntemplate <class Rep, class Period>\ninline\nCONSTCD11\ntypename std::enable_if\n         <\n            std::numeric_limits<Rep>::is_signed,\n            std::chrono::duration<Rep, Period>\n         >::type\nabs(std::chrono::duration<Rep, Period> d)\n{\n    return d >= d.zero() ? +d : -d;\n}\n\ntemplate <class Rep, class Period>\ninline\nCONSTCD11\ntypename std::enable_if\n         <\n            !std::numeric_limits<Rep>::is_signed,\n            std::chrono::duration<Rep, Period>\n         >::type\nabs(std::chrono::duration<Rep, Period> d)\n{\n    return d;\n}\n\n}  // namespace detail\n\ntemplate <class Duration>\nclass hh_mm_ss\n{\n    using dfs = detail::decimal_format_seconds<typename std::common_type<Duration,\n                                               std::chrono::seconds>::type>;\n\n    std::chrono::hours h_;\n    std::chrono::minutes m_;\n    dfs s_;\n    bool neg_;\n\npublic:\n    static unsigned CONSTDATA fractional_width = dfs::width;\n    using precision = typename dfs::precision;\n\n    CONSTCD11 hh_mm_ss() NOEXCEPT\n        : hh_mm_ss(Duration::zero())\n        {}\n\n    CONSTCD11 explicit hh_mm_ss(Duration d) NOEXCEPT\n        : h_(std::chrono::duration_cast<std::chrono::hours>(detail::abs(d)))\n        , m_(std::chrono::duration_cast<std::chrono::minutes>(detail::abs(d)) - h_)\n        , s_(detail::abs(d) - h_ - m_)\n        , neg_(d < Duration::zero())\n        {}\n\n    CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;}\n    CONSTCD11 std::chrono::minutes minutes() const NOEXCEPT {return m_;}\n    CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_.seconds();}\n    CONSTCD14 std::chrono::seconds&\n        seconds(detail::undocumented) NOEXCEPT {return s_.seconds();}\n    CONSTCD11 precision subseconds() const NOEXCEPT {return s_.subseconds();}\n    CONSTCD11 bool is_negative() const NOEXCEPT {return neg_;}\n\n    CONSTCD11 explicit operator  precision()   const NOEXCEPT {return to_duration();}\n    CONSTCD11          precision to_duration() const NOEXCEPT\n        {return (s_.to_duration() + m_ + h_) * (1-2*neg_);}\n\n    CONSTCD11 bool in_conventional_range() const NOEXCEPT\n    {\n        return !neg_ && h_ < days{1} && m_ < std::chrono::hours{1} &&\n               s_.in_conventional_range();\n    }\n\nprivate:\n\n    template <class charT, class traits>\n    friend\n    std::basic_ostream<charT, traits>&\n    operator<<(std::basic_ostream<charT, traits>& os, hh_mm_ss const& tod)\n    {\n        if (tod.is_negative())\n            os << '-';\n        if (tod.h_ < std::chrono::hours{10})\n            os << '0';\n        os << tod.h_.count() << ':';\n        if (tod.m_ < std::chrono::minutes{10})\n            os << '0';\n        os << tod.m_.count() << ':' << tod.s_;\n        return os;\n    }\n\n    template <class CharT, class Traits, class Duration2>\n    friend\n    std::basic_ostream<CharT, Traits>&\n    date::to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,\n          const fields<Duration2>& fds, const std::string* abbrev,\n          const std::chrono::seconds* offset_sec);\n\n    template <class CharT, class Traits, class Duration2, class Alloc>\n    friend\n    std::basic_istream<CharT, Traits>&\n    date::from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,\n          fields<Duration2>& fds,\n          std::basic_string<CharT, Traits, Alloc>* abbrev, std::chrono::minutes* offset);\n};\n\ninline\nCONSTCD14\nbool\nis_am(std::chrono::hours const& h) NOEXCEPT\n{\n    using std::chrono::hours;\n    return hours{0} <= h && h < hours{12};\n}\n\ninline\nCONSTCD14\nbool\nis_pm(std::chrono::hours const& h) NOEXCEPT\n{\n    using std::chrono::hours;\n    return hours{12} <= h && h < hours{24};\n}\n\ninline\nCONSTCD14\nstd::chrono::hours\nmake12(std::chrono::hours h) NOEXCEPT\n{\n    using std::chrono::hours;\n    if (h < hours{12})\n    {\n        if (h == hours{0})\n            h = hours{12};\n    }\n    else\n    {\n        if (h != hours{12})\n            h = h - hours{12};\n    }\n    return h;\n}\n\ninline\nCONSTCD14\nstd::chrono::hours\nmake24(std::chrono::hours h, bool is_pm) NOEXCEPT\n{\n    using std::chrono::hours;\n    if (is_pm)\n    {\n        if (h != hours{12})\n            h = h + hours{12};\n    }\n    else if (h == hours{12})\n        h = hours{0};\n    return h;\n}\n\ntemplate <class Duration>\nusing time_of_day = hh_mm_ss<Duration>;\n\ntemplate <class Rep, class Period>\nCONSTCD11\ninline\nhh_mm_ss<std::chrono::duration<Rep, Period>>\nmake_time(const std::chrono::duration<Rep, Period>& d)\n{\n    return hh_mm_ss<std::chrono::duration<Rep, Period>>(d);\n}\n\ntemplate <class CharT, class Traits, class Duration>\ninline\ntypename std::enable_if\n<\n    !std::is_convertible<Duration, days>::value,\n    std::basic_ostream<CharT, Traits>&\n>::type\noperator<<(std::basic_ostream<CharT, Traits>& os, const sys_time<Duration>& tp)\n{\n    auto const dp = date::floor<days>(tp);\n    return os << year_month_day(dp) << ' ' << make_time(tp-dp);\n}\n\ntemplate <class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const sys_days& dp)\n{\n    return os << year_month_day(dp);\n}\n\ntemplate <class CharT, class Traits, class Duration>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os, const local_time<Duration>& ut)\n{\n    return (os << sys_time<Duration>{ut.time_since_epoch()});\n}\n\nnamespace detail\n{\n\ntemplate <class CharT, std::size_t N>\nclass string_literal;\n\ntemplate <class CharT1, class CharT2, std::size_t N1, std::size_t N2>\ninline\nCONSTCD14\nstring_literal<typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type,\n               N1 + N2 - 1>\noperator+(const string_literal<CharT1, N1>& x, const string_literal<CharT2, N2>& y) NOEXCEPT;\n\ntemplate <class CharT, std::size_t N>\nclass string_literal\n{\n    CharT p_[N];\n\n    CONSTCD11 string_literal() NOEXCEPT\n      : p_{}\n    {}\n\npublic:\n    using const_iterator = const CharT*;\n\n    string_literal(string_literal const&) = default;\n    string_literal& operator=(string_literal const&) = delete;\n\n    template <std::size_t N1 = 2,\n              class = typename std::enable_if<N1 == N>::type>\n    CONSTCD11 string_literal(CharT c) NOEXCEPT\n        : p_{c}\n    {\n    }\n\n    template <std::size_t N1 = 3,\n              class = typename std::enable_if<N1 == N>::type>\n    CONSTCD11 string_literal(CharT c1, CharT c2) NOEXCEPT\n        : p_{c1, c2}\n    {\n    }\n\n    template <std::size_t N1 = 4,\n              class = typename std::enable_if<N1 == N>::type>\n    CONSTCD11 string_literal(CharT c1, CharT c2, CharT c3) NOEXCEPT\n        : p_{c1, c2, c3}\n    {\n    }\n\n    CONSTCD14 string_literal(const CharT(&a)[N]) NOEXCEPT\n        : p_{}\n    {\n        for (std::size_t i = 0; i < N; ++i)\n            p_[i] = a[i];\n    }\n\n    template <class U = CharT,\n              class = typename std::enable_if<(1 < sizeof(U))>::type>\n    CONSTCD14 string_literal(const char(&a)[N]) NOEXCEPT\n        : p_{}\n    {\n        for (std::size_t i = 0; i < N; ++i)\n            p_[i] = a[i];\n    }\n\n    template <class CharT2,\n              class = typename std::enable_if<!std::is_same<CharT2, CharT>::value>::type>\n    CONSTCD14 string_literal(string_literal<CharT2, N> const& a) NOEXCEPT\n        : p_{}\n    {\n        for (std::size_t i = 0; i < N; ++i)\n            p_[i] = a[i];\n    }\n\n    CONSTCD11 const CharT* data() const NOEXCEPT {return p_;}\n    CONSTCD11 std::size_t size() const NOEXCEPT {return N-1;}\n\n    CONSTCD11 const_iterator begin() const NOEXCEPT {return p_;}\n    CONSTCD11 const_iterator end()   const NOEXCEPT {return p_ + N-1;}\n\n    CONSTCD11 CharT const& operator[](std::size_t n) const NOEXCEPT\n    {\n        return p_[n];\n    }\n\n    template <class Traits>\n    friend\n    std::basic_ostream<CharT, Traits>&\n    operator<<(std::basic_ostream<CharT, Traits>& os, const string_literal& s)\n    {\n        return os << s.p_;\n    }\n\n    template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>\n    friend\n    CONSTCD14\n    string_literal<typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type,\n                   N1 + N2 - 1>\n    operator+(const string_literal<CharT1, N1>& x, const string_literal<CharT2, N2>& y) NOEXCEPT;\n};\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 3>\noperator+(const string_literal<CharT, 2>& x, const string_literal<CharT, 2>& y) NOEXCEPT\n{\n  return string_literal<CharT, 3>(x[0], y[0]);\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 4>\noperator+(const string_literal<CharT, 3>& x, const string_literal<CharT, 2>& y) NOEXCEPT\n{\n  return string_literal<CharT, 4>(x[0], x[1], y[0]);\n}\n\ntemplate <class CharT1, class CharT2, std::size_t N1, std::size_t N2>\nCONSTCD14\ninline\nstring_literal<typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type,\n               N1 + N2 - 1>\noperator+(const string_literal<CharT1, N1>& x, const string_literal<CharT2, N2>& y) NOEXCEPT\n{\n    using CT = typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type;\n\n    string_literal<CT, N1 + N2 - 1> r;\n    std::size_t i = 0;\n    for (; i < N1-1; ++i)\n       r.p_[i] = CT(x.p_[i]);\n    for (std::size_t j = 0; j < N2; ++j, ++i)\n       r.p_[i] = CT(y.p_[j]);\n\n    return r;\n}\n\n\ntemplate <class CharT, class Traits, class Alloc, std::size_t N>\ninline\nstd::basic_string<CharT, Traits, Alloc>\noperator+(std::basic_string<CharT, Traits, Alloc> x, const string_literal<CharT, N>& y)\n{\n    x.append(y.data(), y.size());\n    return x;\n}\n\n#if __cplusplus >= 201402  && (!defined(__EDG_VERSION__) || __EDG_VERSION__ > 411) \\\n                           && (!defined(__SUNPRO_CC) || __SUNPRO_CC > 0x5150)\n\ntemplate <class CharT,\n          class = std::enable_if_t<std::is_same<CharT, char>::value ||\n                                   std::is_same<CharT, wchar_t>::value ||\n                                   std::is_same<CharT, char16_t>::value ||\n                                   std::is_same<CharT, char32_t>::value>>\nCONSTCD14\ninline\nstring_literal<CharT, 2>\nmsl(CharT c) NOEXCEPT\n{\n    return string_literal<CharT, 2>{c};\n}\n\nCONSTCD14\ninline\nstd::size_t\nto_string_len(std::intmax_t i)\n{\n    std::size_t r = 0;\n    do\n    {\n        i /= 10;\n        ++r;\n    } while (i > 0);\n    return r;\n}\n\ntemplate <std::intmax_t N>\nCONSTCD14\ninline\nstd::enable_if_t\n<\n    N < 10,\n    string_literal<char, to_string_len(N)+1>\n>\nmsl() NOEXCEPT\n{\n    return msl(char(N % 10 + '0'));\n}\n\ntemplate <std::intmax_t N>\nCONSTCD14\ninline\nstd::enable_if_t\n<\n    10 <= N,\n    string_literal<char, to_string_len(N)+1>\n>\nmsl() NOEXCEPT\n{\n    return msl<N/10>() + msl(char(N % 10 + '0'));\n}\n\ntemplate <class CharT, std::intmax_t N, std::intmax_t D>\nCONSTCD14\ninline\nstd::enable_if_t\n<\n    std::ratio<N, D>::type::den != 1,\n    string_literal<CharT, to_string_len(std::ratio<N, D>::type::num) +\n                          to_string_len(std::ratio<N, D>::type::den) + 4>\n>\nmsl(std::ratio<N, D>) NOEXCEPT\n{\n    using R = typename std::ratio<N, D>::type;\n    return msl(CharT{'['}) + msl<R::num>() + msl(CharT{'/'}) +\n                             msl<R::den>() + msl(CharT{']'});\n}\n\ntemplate <class CharT, std::intmax_t N, std::intmax_t D>\nCONSTCD14\ninline\nstd::enable_if_t\n<\n    std::ratio<N, D>::type::den == 1,\n    string_literal<CharT, to_string_len(std::ratio<N, D>::type::num) + 3>\n>\nmsl(std::ratio<N, D>) NOEXCEPT\n{\n    using R = typename std::ratio<N, D>::type;\n    return msl(CharT{'['}) + msl<R::num>() + msl(CharT{']'});\n}\n\n\n#else  // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411)\n\ninline\nstd::string\nto_string(std::uint64_t x)\n{\n    return std::to_string(x);\n}\n\ntemplate <class CharT>\ninline\nstd::basic_string<CharT>\nto_string(std::uint64_t x)\n{\n    auto y = std::to_string(x);\n    return std::basic_string<CharT>(y.begin(), y.end());\n}\n\ntemplate <class CharT, std::intmax_t N, std::intmax_t D>\ninline\ntypename std::enable_if\n<\n    std::ratio<N, D>::type::den != 1,\n    std::basic_string<CharT>\n>::type\nmsl(std::ratio<N, D>)\n{\n    using R = typename std::ratio<N, D>::type;\n    return std::basic_string<CharT>(1, '[') + to_string<CharT>(R::num) + CharT{'/'} +\n                                              to_string<CharT>(R::den) + CharT{']'};\n}\n\ntemplate <class CharT, std::intmax_t N, std::intmax_t D>\ninline\ntypename std::enable_if\n<\n    std::ratio<N, D>::type::den == 1,\n    std::basic_string<CharT>\n>::type\nmsl(std::ratio<N, D>)\n{\n    using R = typename std::ratio<N, D>::type;\n    return std::basic_string<CharT>(1, '[') + to_string<CharT>(R::num) + CharT{']'};\n}\n\n#endif  // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411)\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::atto) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'a'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::femto) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'f'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::pico) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'p'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::nano) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'n'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\ntypename std::enable_if\n<\n    std::is_same<CharT, char>::value,\n    string_literal<char, 3>\n>::type\nmsl(std::micro) NOEXCEPT\n{\n    return string_literal<char, 3>{'\\xC2', '\\xB5'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\ntypename std::enable_if\n<\n    !std::is_same<CharT, char>::value,\n    string_literal<CharT, 2>\n>::type\nmsl(std::micro) NOEXCEPT\n{\n    return string_literal<CharT, 2>{CharT{static_cast<unsigned char>('\\xB5')}};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::milli) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'m'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::centi) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'c'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 3>\nmsl(std::deca) NOEXCEPT\n{\n    return string_literal<CharT, 3>{'d', 'a'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::deci) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'d'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::hecto) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'h'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::kilo) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'k'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::mega) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'M'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::giga) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'G'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::tera) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'T'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::peta) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'P'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nmsl(std::exa) NOEXCEPT\n{\n    return string_literal<CharT, 2>{'E'};\n}\n\ntemplate <class CharT, class Period>\nCONSTCD11\ninline\nauto\nget_units(Period p)\n -> decltype(msl<CharT>(p) + string_literal<CharT, 2>{'s'})\n{\n    return msl<CharT>(p) + string_literal<CharT, 2>{'s'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nget_units(std::ratio<1>)\n{\n    return string_literal<CharT, 2>{'s'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nget_units(std::ratio<3600>)\n{\n    return string_literal<CharT, 2>{'h'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 4>\nget_units(std::ratio<60>)\n{\n    return string_literal<CharT, 4>{'m', 'i', 'n'};\n}\n\ntemplate <class CharT>\nCONSTCD11\ninline\nstring_literal<CharT, 2>\nget_units(std::ratio<86400>)\n{\n    return string_literal<CharT, 2>{'d'};\n}\n\ntemplate <class CharT, class Traits = std::char_traits<CharT>>\nstruct make_string;\n\ntemplate <>\nstruct make_string<char>\n{\n    template <class Rep>\n    static\n    std::string\n    from(Rep n)\n    {\n        return std::to_string(n);\n    }\n};\n\ntemplate <class Traits>\nstruct make_string<char, Traits>\n{\n    template <class Rep>\n    static\n    std::basic_string<char, Traits>\n    from(Rep n)\n    {\n        auto s = std::to_string(n);\n        return std::basic_string<char, Traits>(s.begin(), s.end());\n    }\n};\n\ntemplate <>\nstruct make_string<wchar_t>\n{\n    template <class Rep>\n    static\n    std::wstring\n    from(Rep n)\n    {\n        return std::to_wstring(n);\n    }\n};\n\ntemplate <class Traits>\nstruct make_string<wchar_t, Traits>\n{\n    template <class Rep>\n    static\n    std::basic_string<wchar_t, Traits>\n    from(Rep n)\n    {\n        auto s = std::to_wstring(n);\n        return std::basic_string<wchar_t, Traits>(s.begin(), s.end());\n    }\n};\n\n}  // namespace detail\n\n// to_stream\n\nCONSTDATA year nanyear{-32768};\n\ntemplate <class Duration>\nstruct fields\n{\n    year_month_day        ymd{nanyear/0/0};\n    weekday               wd{8u};\n    hh_mm_ss<Duration>    tod{};\n    bool                  has_tod = false;\n\n#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ <= 409)\n    fields() : ymd{nanyear/0/0}, wd{8u}, tod{}, has_tod{false} {}\n#else\n    fields() = default;\n#endif\n\n    fields(year_month_day ymd_) : ymd(ymd_) {}\n    fields(weekday wd_) : wd(wd_) {}\n    fields(hh_mm_ss<Duration> tod_) : tod(tod_), has_tod(true) {}\n\n    fields(year_month_day ymd_, weekday wd_) : ymd(ymd_), wd(wd_) {}\n    fields(year_month_day ymd_, hh_mm_ss<Duration> tod_) : ymd(ymd_), tod(tod_),\n                                                           has_tod(true) {}\n\n    fields(weekday wd_, hh_mm_ss<Duration> tod_) : wd(wd_), tod(tod_), has_tod(true) {}\n\n    fields(year_month_day ymd_, weekday wd_, hh_mm_ss<Duration> tod_)\n        : ymd(ymd_)\n        , wd(wd_)\n        , tod(tod_)\n        , has_tod(true)\n        {}\n};\n\nnamespace detail\n{\n\ntemplate <class CharT, class Traits, class Duration>\nunsigned\nextract_weekday(std::basic_ostream<CharT, Traits>& os, const fields<Duration>& fds)\n{\n    if (!fds.ymd.ok() && !fds.wd.ok())\n    {\n        // fds does not contain a valid weekday\n        os.setstate(std::ios::failbit);\n        return 8;\n    }\n    weekday wd;\n    if (fds.ymd.ok())\n    {\n        wd = weekday{sys_days(fds.ymd)};\n        if (fds.wd.ok() && wd != fds.wd)\n        {\n            // fds.ymd and fds.wd are inconsistent\n            os.setstate(std::ios::failbit);\n            return 8;\n        }\n    }\n    else\n        wd = fds.wd;\n    return static_cast<unsigned>((wd - Sunday).count());\n}\n\ntemplate <class CharT, class Traits, class Duration>\nunsigned\nextract_month(std::basic_ostream<CharT, Traits>& os, const fields<Duration>& fds)\n{\n    if (!fds.ymd.month().ok())\n    {\n        // fds does not contain a valid month\n        os.setstate(std::ios::failbit);\n        return 0;\n    }\n    return static_cast<unsigned>(fds.ymd.month());\n}\n\n}  // namespace detail\n\n#if ONLY_C_LOCALE\n\nnamespace detail\n{\n\ninline\nstd::pair<const std::string*, const std::string*>\nweekday_names()\n{\n    static const std::string nm[] =\n    {\n        \"Sunday\",\n        \"Monday\",\n        \"Tuesday\",\n        \"Wednesday\",\n        \"Thursday\",\n        \"Friday\",\n        \"Saturday\",\n        \"Sun\",\n        \"Mon\",\n        \"Tue\",\n        \"Wed\",\n        \"Thu\",\n        \"Fri\",\n        \"Sat\"\n    };\n    return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0]));\n}\n\ninline\nstd::pair<const std::string*, const std::string*>\nmonth_names()\n{\n    static const std::string nm[] =\n    {\n        \"January\",\n        \"February\",\n        \"March\",\n        \"April\",\n        \"May\",\n        \"June\",\n        \"July\",\n        \"August\",\n        \"September\",\n        \"October\",\n        \"November\",\n        \"December\",\n        \"Jan\",\n        \"Feb\",\n        \"Mar\",\n        \"Apr\",\n        \"May\",\n        \"Jun\",\n        \"Jul\",\n        \"Aug\",\n        \"Sep\",\n        \"Oct\",\n        \"Nov\",\n        \"Dec\"\n    };\n    return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0]));\n}\n\ninline\nstd::pair<const std::string*, const std::string*>\nampm_names()\n{\n    static const std::string nm[] =\n    {\n        \"AM\",\n        \"PM\"\n    };\n    return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0]));\n}\n\ntemplate <class CharT, class Traits, class FwdIter>\nFwdIter\nscan_keyword(std::basic_istream<CharT, Traits>& is, FwdIter kb, FwdIter ke)\n{\n    size_t nkw = static_cast<size_t>(std::distance(kb, ke));\n    const unsigned char doesnt_match = '\\0';\n    const unsigned char might_match = '\\1';\n    const unsigned char does_match = '\\2';\n    unsigned char statbuf[100];\n    unsigned char* status = statbuf;\n    std::unique_ptr<unsigned char, void(*)(void*)> stat_hold(0, free);\n    if (nkw > sizeof(statbuf))\n    {\n        status = (unsigned char*)std::malloc(nkw);\n        if (status == nullptr)\n            throw std::bad_alloc();\n        stat_hold.reset(status);\n    }\n    size_t n_might_match = nkw;  // At this point, any keyword might match\n    size_t n_does_match = 0;     // but none of them definitely do\n    // Initialize all statuses to might_match, except for \"\" keywords are does_match\n    unsigned char* st = status;\n    for (auto ky = kb; ky != ke; ++ky, ++st)\n    {\n        if (!ky->empty())\n            *st = might_match;\n        else\n        {\n            *st = does_match;\n            --n_might_match;\n            ++n_does_match;\n        }\n    }\n    // While there might be a match, test keywords against the next CharT\n    for (size_t indx = 0; is && n_might_match > 0; ++indx)\n    {\n        // Peek at the next CharT but don't consume it\n        auto ic = is.peek();\n        if (ic == EOF)\n        {\n            is.setstate(std::ios::eofbit);\n            break;\n        }\n        auto c = static_cast<char>(toupper(static_cast<unsigned char>(ic)));\n        bool consume = false;\n        // For each keyword which might match, see if the indx character is c\n        // If a match if found, consume c\n        // If a match is found, and that is the last character in the keyword,\n        //    then that keyword matches.\n        // If the keyword doesn't match this character, then change the keyword\n        //    to doesn't match\n        st = status;\n        for (auto ky = kb; ky != ke; ++ky, ++st)\n        {\n            if (*st == might_match)\n            {\n                if (c == static_cast<char>(toupper(static_cast<unsigned char>((*ky)[indx]))))\n                {\n                    consume = true;\n                    if (ky->size() == indx+1)\n                    {\n                        *st = does_match;\n                        --n_might_match;\n                        ++n_does_match;\n                    }\n                }\n                else\n                {\n                    *st = doesnt_match;\n                    --n_might_match;\n                }\n            }\n        }\n        // consume if we matched a character\n        if (consume)\n        {\n            (void)is.get();\n            // If we consumed a character and there might be a matched keyword that\n            //   was marked matched on a previous iteration, then such keywords\n            //   are now marked as not matching.\n            if (n_might_match + n_does_match > 1)\n            {\n                st = status;\n                for (auto ky = kb; ky != ke; ++ky, ++st)\n                {\n                    if (*st == does_match && ky->size() != indx+1)\n                    {\n                        *st = doesnt_match;\n                        --n_does_match;\n                    }\n                }\n            }\n        }\n    }\n    // We've exited the loop because we hit eof and/or we have no more \"might matches\".\n    // Return the first matching result\n    for (st = status; kb != ke; ++kb, ++st)\n        if (*st == does_match)\n            break;\n    if (kb == ke)\n        is.setstate(std::ios::failbit);\n    return kb;\n}\n\n}  // namespace detail\n\n#endif  // ONLY_C_LOCALE\n\ntemplate <class CharT, class Traits, class Duration>\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,\n          const fields<Duration>& fds, const std::string* abbrev,\n          const std::chrono::seconds* offset_sec)\n{\n#if ONLY_C_LOCALE\n    using detail::weekday_names;\n    using detail::month_names;\n    using detail::ampm_names;\n#endif\n    using detail::save_ostream;\n    using detail::get_units;\n    using detail::extract_weekday;\n    using detail::extract_month;\n    using std::ios;\n    using std::chrono::duration_cast;\n    using std::chrono::seconds;\n    using std::chrono::minutes;\n    using std::chrono::hours;\n    date::detail::save_ostream<CharT, Traits> ss(os);\n    os.fill(' ');\n    os.flags(std::ios::skipws | std::ios::dec);\n    os.width(0);\n    tm tm{};\n    bool insert_negative = fds.has_tod && fds.tod.to_duration() < Duration::zero();\n#if !ONLY_C_LOCALE\n    auto& facet = std::use_facet<std::time_put<CharT>>(os.getloc());\n#endif\n    const CharT* command = nullptr;\n    CharT modified = CharT{};\n    for (; *fmt; ++fmt)\n    {\n        switch (*fmt)\n        {\n        case 'a':\n        case 'A':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    tm.tm_wday = static_cast<int>(extract_weekday(os, fds));\n                    if (os.fail())\n                        return os;\n#if !ONLY_C_LOCALE\n                    const CharT f[] = {'%', *fmt};\n                    facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n#else  // ONLY_C_LOCALE\n                    os << weekday_names().first[tm.tm_wday+7*(*fmt == 'a')];\n#endif  // ONLY_C_LOCALE\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'b':\n        case 'B':\n        case 'h':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    tm.tm_mon = static_cast<int>(extract_month(os, fds)) - 1;\n#if !ONLY_C_LOCALE\n                    const CharT f[] = {'%', *fmt};\n                    facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n#else  // ONLY_C_LOCALE\n                    os << month_names().first[tm.tm_mon+12*(*fmt != 'B')];\n#endif  // ONLY_C_LOCALE\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'c':\n        case 'x':\n            if (command)\n            {\n                if (modified == CharT{'O'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    if (!fds.ymd.ok())\n                        os.setstate(std::ios::failbit);\n                    if (*fmt == 'c' && !fds.has_tod)\n                        os.setstate(std::ios::failbit);\n#if !ONLY_C_LOCALE\n                    tm = std::tm{};\n                    auto const& ymd = fds.ymd;\n                    auto ld = local_days(ymd);\n                    if (*fmt == 'c')\n                    {\n                        tm.tm_sec = static_cast<int>(fds.tod.seconds().count());\n                        tm.tm_min = static_cast<int>(fds.tod.minutes().count());\n                        tm.tm_hour = static_cast<int>(fds.tod.hours().count());\n                    }\n                    tm.tm_mday = static_cast<int>(static_cast<unsigned>(ymd.day()));\n                    tm.tm_mon = static_cast<int>(extract_month(os, fds) - 1);\n                    tm.tm_year = static_cast<int>(ymd.year()) - 1900;\n                    tm.tm_wday = static_cast<int>(extract_weekday(os, fds));\n                    if (os.fail())\n                        return os;\n                    tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());\n                    CharT f[3] = {'%'};\n                    auto fe = std::begin(f) + 1;\n                    if (modified == CharT{'E'})\n                        *fe++ = modified;\n                    *fe++ = *fmt;\n                    facet.put(os, os, os.fill(), &tm, std::begin(f), fe);\n#else  // ONLY_C_LOCALE\n                    if (*fmt == 'c')\n                    {\n                        auto wd = static_cast<int>(extract_weekday(os, fds));\n                        os << weekday_names().first[static_cast<unsigned>(wd)+7]\n                           << ' ';\n                        os << month_names().first[extract_month(os, fds)-1+12] << ' ';\n                        auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day()));\n                        if (d < 10)\n                            os << ' ';\n                        os << d << ' '\n                           << make_time(duration_cast<seconds>(fds.tod.to_duration()))\n                           << ' ' << fds.ymd.year();\n\n                    }\n                    else  // *fmt == 'x'\n                    {\n                        auto const& ymd = fds.ymd;\n                        save_ostream<CharT, Traits> _(os);\n                        os.fill('0');\n                        os.flags(std::ios::dec | std::ios::right);\n                        os.width(2);\n                        os << static_cast<unsigned>(ymd.month()) << CharT{'/'};\n                        os.width(2);\n                        os << static_cast<unsigned>(ymd.day()) << CharT{'/'};\n                        os.width(2);\n                        os << static_cast<int>(ymd.year()) % 100;\n                    }\n#endif  // ONLY_C_LOCALE\n                }\n                command = nullptr;\n                modified = CharT{};\n            }\n            else\n                os << *fmt;\n            break;\n        case 'C':\n            if (command)\n            {\n                if (modified == CharT{'O'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    if (!fds.ymd.year().ok())\n                        os.setstate(std::ios::failbit);\n                    auto y = static_cast<int>(fds.ymd.year());\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        save_ostream<CharT, Traits> _(os);\n                        os.fill('0');\n                        os.flags(std::ios::dec | std::ios::right);\n                        if (y >= 0)\n                        {\n                            os.width(2);\n                            os << y/100;\n                        }\n                        else\n                        {\n                            os << CharT{'-'};\n                            os.width(2);\n                            os << -(y-99)/100;\n                        }\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'E'})\n                    {\n                        tm.tm_year = y - 1900;\n                        CharT f[3] = {'%', 'E', 'C'};\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                command = nullptr;\n                modified = CharT{};\n            }\n            else\n                os << *fmt;\n            break;\n        case 'd':\n        case 'e':\n            if (command)\n            {\n                if (modified == CharT{'E'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    if (!fds.ymd.day().ok())\n                        os.setstate(std::ios::failbit);\n                    auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day()));\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        save_ostream<CharT, Traits> _(os);\n                        if (*fmt == CharT{'d'})\n                            os.fill('0');\n                        else\n                            os.fill(' ');\n                        os.flags(std::ios::dec | std::ios::right);\n                        os.width(2);\n                        os << d;\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        tm.tm_mday = d;\n                        CharT f[3] = {'%', 'O', *fmt};\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                command = nullptr;\n                modified = CharT{};\n            }\n            else\n                os << *fmt;\n            break;\n        case 'D':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    if (!fds.ymd.ok())\n                        os.setstate(std::ios::failbit);\n                    auto const& ymd = fds.ymd;\n                    save_ostream<CharT, Traits> _(os);\n                    os.fill('0');\n                    os.flags(std::ios::dec | std::ios::right);\n                    os.width(2);\n                    os << static_cast<unsigned>(ymd.month()) << CharT{'/'};\n                    os.width(2);\n                    os << static_cast<unsigned>(ymd.day()) << CharT{'/'};\n                    os.width(2);\n                    os << static_cast<int>(ymd.year()) % 100;\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'F':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    if (!fds.ymd.ok())\n                        os.setstate(std::ios::failbit);\n                    auto const& ymd = fds.ymd;\n                    save_ostream<CharT, Traits> _(os);\n                    os.imbue(std::locale::classic());\n                    os.fill('0');\n                    os.flags(std::ios::dec | std::ios::right);\n                    os.width(4);\n                    os << static_cast<int>(ymd.year()) << CharT{'-'};\n                    os.width(2);\n                    os << static_cast<unsigned>(ymd.month()) << CharT{'-'};\n                    os.width(2);\n                    os << static_cast<unsigned>(ymd.day());\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'g':\n        case 'G':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    if (!fds.ymd.ok())\n                        os.setstate(std::ios::failbit);\n                    auto ld = local_days(fds.ymd);\n                    auto y = year_month_day{ld + days{3}}.year();\n                    auto start = local_days((y-years{1})/December/Thursday[last]) +\n                                 (Monday-Thursday);\n                    if (ld < start)\n                        --y;\n                    if (*fmt == CharT{'G'})\n                        os << y;\n                    else\n                    {\n                        save_ostream<CharT, Traits> _(os);\n                        os.fill('0');\n                        os.flags(std::ios::dec | std::ios::right);\n                        os.width(2);\n                        os << std::abs(static_cast<int>(y)) % 100;\n                    }\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'H':\n        case 'I':\n            if (command)\n            {\n                if (modified == CharT{'E'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    if (!fds.has_tod)\n                        os.setstate(std::ios::failbit);\n                    if (insert_negative)\n                    {\n                        os << '-';\n                        insert_negative = false;\n                    }\n                    auto hms = fds.tod;\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        auto h = *fmt == CharT{'I'} ? date::make12(hms.hours()) : hms.hours();\n                        if (h < hours{10})\n                            os << CharT{'0'};\n                        os << h.count();\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        const CharT f[] = {'%', modified, *fmt};\n                        tm.tm_hour = static_cast<int>(hms.hours().count());\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'j':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    if (fds.ymd.ok() || fds.has_tod)\n                    {\n                        days doy;\n                        if (fds.ymd.ok())\n                        {\n                            auto ld = local_days(fds.ymd);\n                            auto y = fds.ymd.year();\n                            doy = ld - local_days(y/January/1) + days{1};\n                        }\n                        else\n                        {\n                            doy = duration_cast<days>(fds.tod.to_duration());\n                        }\n                        save_ostream<CharT, Traits> _(os);\n                        os.fill('0');\n                        os.flags(std::ios::dec | std::ios::right);\n                        os.width(3);\n                        os << doy.count();\n                    }\n                    else\n                    {\n                        os.setstate(std::ios::failbit);\n                    }\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'm':\n            if (command)\n            {\n                if (modified == CharT{'E'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    if (!fds.ymd.month().ok())\n                        os.setstate(std::ios::failbit);\n                    auto m = static_cast<unsigned>(fds.ymd.month());\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        if (m < 10)\n                            os << CharT{'0'};\n                        os << m;\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        const CharT f[] = {'%', modified, *fmt};\n                        tm.tm_mon = static_cast<int>(m-1);\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'M':\n            if (command)\n            {\n                if (modified == CharT{'E'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    if (!fds.has_tod)\n                        os.setstate(std::ios::failbit);\n                    if (insert_negative)\n                    {\n                        os << '-';\n                        insert_negative = false;\n                    }\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        if (fds.tod.minutes() < minutes{10})\n                            os << CharT{'0'};\n                        os << fds.tod.minutes().count();\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        const CharT f[] = {'%', modified, *fmt};\n                        tm.tm_min = static_cast<int>(fds.tod.minutes().count());\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'n':\n            if (command)\n            {\n                if (modified == CharT{})\n                    os << CharT{'\\n'};\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'p':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    if (!fds.has_tod)\n                        os.setstate(std::ios::failbit);\n#if !ONLY_C_LOCALE\n                    const CharT f[] = {'%', *fmt};\n                    tm.tm_hour = static_cast<int>(fds.tod.hours().count());\n                    facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n#else\n                    if (date::is_am(fds.tod.hours()))\n                        os << ampm_names().first[0];\n                    else\n                        os << ampm_names().first[1];\n#endif\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'Q':\n        case 'q':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    if (!fds.has_tod)\n                        os.setstate(std::ios::failbit);\n                    auto d = fds.tod.to_duration();\n                    if (*fmt == 'q')\n                        os << get_units<CharT>(typename decltype(d)::period::type{});\n                    else\n                        os << d.count();\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'r':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    if (!fds.has_tod)\n                        os.setstate(std::ios::failbit);\n#if !ONLY_C_LOCALE\n                    const CharT f[] = {'%', *fmt};\n                    tm.tm_hour = static_cast<int>(fds.tod.hours().count());\n                    tm.tm_min = static_cast<int>(fds.tod.minutes().count());\n                    tm.tm_sec = static_cast<int>(fds.tod.seconds().count());\n                    facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n#else\n                    hh_mm_ss<seconds> tod(duration_cast<seconds>(fds.tod.to_duration()));\n                    save_ostream<CharT, Traits> _(os);\n                    os.fill('0');\n                    os.width(2);\n                    os << date::make12(tod.hours()).count() << CharT{':'};\n                    os.width(2);\n                    os << tod.minutes().count() << CharT{':'};\n                    os.width(2);\n                    os << tod.seconds().count() << CharT{' '};\n                    if (date::is_am(tod.hours()))\n                        os << ampm_names().first[0];\n                    else\n                        os << ampm_names().first[1];\n#endif\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'R':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    if (!fds.has_tod)\n                        os.setstate(std::ios::failbit);\n                    if (fds.tod.hours() < hours{10})\n                        os << CharT{'0'};\n                    os << fds.tod.hours().count() << CharT{':'};\n                    if (fds.tod.minutes() < minutes{10})\n                        os << CharT{'0'};\n                    os << fds.tod.minutes().count();\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'S':\n            if (command)\n            {\n                if (modified == CharT{'E'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    if (!fds.has_tod)\n                        os.setstate(std::ios::failbit);\n                    if (insert_negative)\n                    {\n                        os << '-';\n                        insert_negative = false;\n                    }\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        os << fds.tod.s_;\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        const CharT f[] = {'%', modified, *fmt};\n                        tm.tm_sec = static_cast<int>(fds.tod.s_.seconds().count());\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 't':\n            if (command)\n            {\n                if (modified == CharT{})\n                    os << CharT{'\\t'};\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'T':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    if (!fds.has_tod)\n                        os.setstate(std::ios::failbit);\n                    os << fds.tod;\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'u':\n            if (command)\n            {\n                if (modified == CharT{'E'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    auto wd = extract_weekday(os, fds);\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        os << (wd != 0 ? wd : 7u);\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        const CharT f[] = {'%', modified, *fmt};\n                        tm.tm_wday = static_cast<int>(wd);\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'U':\n            if (command)\n            {\n                if (modified == CharT{'E'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    auto const& ymd = fds.ymd;\n                    if (!ymd.ok())\n                        os.setstate(std::ios::failbit);\n                    auto ld = local_days(ymd);\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        auto st = local_days(Sunday[1]/January/ymd.year());\n                        if (ld < st)\n                            os << CharT{'0'} << CharT{'0'};\n                        else\n                        {\n                            auto wn = duration_cast<weeks>(ld - st).count() + 1;\n                            if (wn < 10)\n                                os << CharT{'0'};\n                            os << wn;\n                        }\n                   }\n #if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        const CharT f[] = {'%', modified, *fmt};\n                        tm.tm_year = static_cast<int>(ymd.year()) - 1900;\n                        tm.tm_wday = static_cast<int>(extract_weekday(os, fds));\n                        if (os.fail())\n                            return os;\n                        tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'V':\n            if (command)\n            {\n                if (modified == CharT{'E'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    if (!fds.ymd.ok())\n                        os.setstate(std::ios::failbit);\n                    auto ld = local_days(fds.ymd);\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        auto y = year_month_day{ld + days{3}}.year();\n                        auto st = local_days((y-years{1})/12/Thursday[last]) +\n                                  (Monday-Thursday);\n                        if (ld < st)\n                        {\n                            --y;\n                            st = local_days((y - years{1})/12/Thursday[last]) +\n                                 (Monday-Thursday);\n                        }\n                        auto wn = duration_cast<weeks>(ld - st).count() + 1;\n                        if (wn < 10)\n                            os << CharT{'0'};\n                        os << wn;\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        const CharT f[] = {'%', modified, *fmt};\n                        auto const& ymd = fds.ymd;\n                        tm.tm_year = static_cast<int>(ymd.year()) - 1900;\n                        tm.tm_wday = static_cast<int>(extract_weekday(os, fds));\n                        if (os.fail())\n                            return os;\n                        tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'w':\n            if (command)\n            {\n                auto wd = extract_weekday(os, fds);\n                if (os.fail())\n                    return os;\n#if !ONLY_C_LOCALE\n                if (modified == CharT{})\n#else\n                if (modified != CharT{'E'})\n#endif\n                {\n                    os << wd;\n                }\n#if !ONLY_C_LOCALE\n                else if (modified == CharT{'O'})\n                {\n                    const CharT f[] = {'%', modified, *fmt};\n                    tm.tm_wday = static_cast<int>(wd);\n                    facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                }\n#endif\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'W':\n            if (command)\n            {\n                if (modified == CharT{'E'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    auto const& ymd = fds.ymd;\n                    if (!ymd.ok())\n                        os.setstate(std::ios::failbit);\n                    auto ld = local_days(ymd);\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        auto st = local_days(Monday[1]/January/ymd.year());\n                        if (ld < st)\n                            os << CharT{'0'} << CharT{'0'};\n                        else\n                        {\n                            auto wn = duration_cast<weeks>(ld - st).count() + 1;\n                            if (wn < 10)\n                                os << CharT{'0'};\n                            os << wn;\n                        }\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        const CharT f[] = {'%', modified, *fmt};\n                        tm.tm_year = static_cast<int>(ymd.year()) - 1900;\n                        tm.tm_wday = static_cast<int>(extract_weekday(os, fds));\n                        if (os.fail())\n                            return os;\n                        tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'X':\n            if (command)\n            {\n                if (modified == CharT{'O'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    if (!fds.has_tod)\n                        os.setstate(std::ios::failbit);\n#if !ONLY_C_LOCALE\n                    tm = std::tm{};\n                    tm.tm_sec = static_cast<int>(fds.tod.seconds().count());\n                    tm.tm_min = static_cast<int>(fds.tod.minutes().count());\n                    tm.tm_hour = static_cast<int>(fds.tod.hours().count());\n                    CharT f[3] = {'%'};\n                    auto fe = std::begin(f) + 1;\n                    if (modified == CharT{'E'})\n                        *fe++ = modified;\n                    *fe++ = *fmt;\n                    facet.put(os, os, os.fill(), &tm, std::begin(f), fe);\n#else\n                    os << fds.tod;\n#endif\n                }\n                command = nullptr;\n                modified = CharT{};\n            }\n            else\n                os << *fmt;\n            break;\n        case 'y':\n            if (command)\n            {\n                if (!fds.ymd.year().ok())\n                    os.setstate(std::ios::failbit);\n                auto y = static_cast<int>(fds.ymd.year());\n#if !ONLY_C_LOCALE\n                if (modified == CharT{})\n                {\n#endif\n                    y = std::abs(y) % 100;\n                    if (y < 10)\n                        os << CharT{'0'};\n                    os << y;\n#if !ONLY_C_LOCALE\n                }\n                else\n                {\n                    const CharT f[] = {'%', modified, *fmt};\n                    tm.tm_year = y - 1900;\n                    facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                }\n#endif\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'Y':\n            if (command)\n            {\n                if (modified == CharT{'O'})\n                    os << CharT{'%'} << modified << *fmt;\n                else\n                {\n                    if (!fds.ymd.year().ok())\n                        os.setstate(std::ios::failbit);\n                    auto y = fds.ymd.year();\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        save_ostream<CharT, Traits> _(os);\n                        os.imbue(std::locale::classic());\n                        os << y;\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'E'})\n                    {\n                        const CharT f[] = {'%', modified, *fmt};\n                        tm.tm_year = static_cast<int>(y) - 1900;\n                        facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));\n                    }\n#endif\n                }\n                modified = CharT{};\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'z':\n            if (command)\n            {\n                if (offset_sec == nullptr)\n                {\n                    // Can not format %z with unknown offset\n                    os.setstate(ios::failbit);\n                    return os;\n                }\n                auto m = duration_cast<minutes>(*offset_sec);\n                auto neg = m < minutes{0};\n                m = date::abs(m);\n                auto h = duration_cast<hours>(m);\n                m -= h;\n                if (neg)\n                    os << CharT{'-'};\n                else\n                    os << CharT{'+'};\n                if (h < hours{10})\n                    os << CharT{'0'};\n                os << h.count();\n                if (modified != CharT{})\n                    os << CharT{':'};\n                if (m < minutes{10})\n                    os << CharT{'0'};\n                os << m.count();\n                command = nullptr;\n                modified = CharT{};\n            }\n            else\n                os << *fmt;\n            break;\n        case 'Z':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    if (abbrev == nullptr)\n                    {\n                        // Can not format %Z with unknown time_zone\n                        os.setstate(ios::failbit);\n                        return os;\n                    }\n                    for (auto c : *abbrev)\n                        os << CharT(c);\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    modified = CharT{};\n                }\n                command = nullptr;\n            }\n            else\n                os << *fmt;\n            break;\n        case 'E':\n        case 'O':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    modified = *fmt;\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << *fmt;\n                    command = nullptr;\n                    modified = CharT{};\n                }\n            }\n            else\n                os << *fmt;\n            break;\n        case '%':\n            if (command)\n            {\n                if (modified == CharT{})\n                {\n                    os << CharT{'%'};\n                    command = nullptr;\n                }\n                else\n                {\n                    os << CharT{'%'} << modified << CharT{'%'};\n                    command = nullptr;\n                    modified = CharT{};\n                }\n            }\n            else\n                command = fmt;\n            break;\n        default:\n            if (command)\n            {\n                os << CharT{'%'};\n                command = nullptr;\n            }\n            if (modified != CharT{})\n            {\n                os << modified;\n                modified = CharT{};\n            }\n            os << *fmt;\n            break;\n        }\n    }\n    if (command)\n        os << CharT{'%'};\n    if (modified != CharT{})\n        os << modified;\n    return os;\n}\n\ntemplate <class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const year& y)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{y/0/0};\n    return to_stream(os, fmt, fds);\n}\n\ntemplate <class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const month& m)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{m/0/nanyear};\n    return to_stream(os, fmt, fds);\n}\n\ntemplate <class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const day& d)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{d/0/nanyear};\n    return to_stream(os, fmt, fds);\n}\n\ntemplate <class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const weekday& wd)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{wd};\n    return to_stream(os, fmt, fds);\n}\n\ntemplate <class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const year_month& ym)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{ym/0};\n    return to_stream(os, fmt, fds);\n}\n\ntemplate <class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const month_day& md)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{md/nanyear};\n    return to_stream(os, fmt, fds);\n}\n\ntemplate <class CharT, class Traits>\ninline\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,\n          const year_month_day& ymd)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{ymd};\n    return to_stream(os, fmt, fds);\n}\n\ntemplate <class CharT, class Traits, class Rep, class Period>\ninline\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,\n          const std::chrono::duration<Rep, Period>& d)\n{\n    using Duration = std::chrono::duration<Rep, Period>;\n    using CT = typename std::common_type<Duration, std::chrono::seconds>::type;\n    fields<CT> fds{hh_mm_ss<CT>{d}};\n    return to_stream(os, fmt, fds);\n}\n\ntemplate <class CharT, class Traits, class Duration>\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,\n          const local_time<Duration>& tp, const std::string* abbrev = nullptr,\n          const std::chrono::seconds* offset_sec = nullptr)\n{\n    using CT = typename std::common_type<Duration, std::chrono::seconds>::type;\n    auto ld = std::chrono::time_point_cast<days>(tp);\n    fields<CT> fds;\n    if (ld <= tp)\n        fds = fields<CT>{year_month_day{ld}, hh_mm_ss<CT>{tp-local_seconds{ld}}};\n    else\n        fds = fields<CT>{year_month_day{ld - days{1}},\n                         hh_mm_ss<CT>{days{1} - (local_seconds{ld} - tp)}};\n    return to_stream(os, fmt, fds, abbrev, offset_sec);\n}\n\ntemplate <class CharT, class Traits, class Duration>\nstd::basic_ostream<CharT, Traits>&\nto_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,\n          const sys_time<Duration>& tp)\n{\n    using std::chrono::seconds;\n    using CT = typename std::common_type<Duration, seconds>::type;\n    const std::string abbrev(\"UTC\");\n    CONSTDATA seconds offset{0};\n    auto sd = std::chrono::time_point_cast<days>(tp);\n    fields<CT> fds;\n    if (sd <= tp)\n        fds = fields<CT>{year_month_day{sd}, hh_mm_ss<CT>{tp-sys_seconds{sd}}};\n    else\n        fds = fields<CT>{year_month_day{sd - days{1}},\n                         hh_mm_ss<CT>{days{1} - (sys_seconds{sd} - tp)}};\n    return to_stream(os, fmt, fds, &abbrev, &offset);\n}\n\n// format\n\ntemplate <class CharT, class Streamable>\nauto\nformat(const std::locale& loc, const CharT* fmt, const Streamable& tp)\n    -> decltype(to_stream(std::declval<std::basic_ostream<CharT>&>(), fmt, tp),\n                std::basic_string<CharT>{})\n{\n    std::basic_ostringstream<CharT> os;\n    os.exceptions(std::ios::failbit | std::ios::badbit);\n    os.imbue(loc);\n    to_stream(os, fmt, tp);\n    return os.str();\n}\n\ntemplate <class CharT, class Streamable>\nauto\nformat(const CharT* fmt, const Streamable& tp)\n    -> decltype(to_stream(std::declval<std::basic_ostream<CharT>&>(), fmt, tp),\n                std::basic_string<CharT>{})\n{\n    std::basic_ostringstream<CharT> os;\n    os.exceptions(std::ios::failbit | std::ios::badbit);\n    to_stream(os, fmt, tp);\n    return os.str();\n}\n\ntemplate <class CharT, class Traits, class Alloc, class Streamable>\nauto\nformat(const std::locale& loc, const std::basic_string<CharT, Traits, Alloc>& fmt,\n       const Streamable& tp)\n    -> decltype(to_stream(std::declval<std::basic_ostream<CharT, Traits>&>(), fmt.c_str(), tp),\n                std::basic_string<CharT, Traits, Alloc>{})\n{\n    std::basic_ostringstream<CharT, Traits, Alloc> os;\n    os.exceptions(std::ios::failbit | std::ios::badbit);\n    os.imbue(loc);\n    to_stream(os, fmt.c_str(), tp);\n    return os.str();\n}\n\ntemplate <class CharT, class Traits, class Alloc, class Streamable>\nauto\nformat(const std::basic_string<CharT, Traits, Alloc>& fmt, const Streamable& tp)\n    -> decltype(to_stream(std::declval<std::basic_ostream<CharT, Traits>&>(), fmt.c_str(), tp),\n                std::basic_string<CharT, Traits, Alloc>{})\n{\n    std::basic_ostringstream<CharT, Traits, Alloc> os;\n    os.exceptions(std::ios::failbit | std::ios::badbit);\n    to_stream(os, fmt.c_str(), tp);\n    return os.str();\n}\n\n// parse\n\nnamespace detail\n{\n\ntemplate <class CharT, class Traits>\nbool\nread_char(std::basic_istream<CharT, Traits>& is, CharT fmt, std::ios::iostate& err)\n{\n    auto ic = is.get();\n    if (Traits::eq_int_type(ic, Traits::eof()) ||\n       !Traits::eq(Traits::to_char_type(ic), fmt))\n    {\n        err |= std::ios::failbit;\n        is.setstate(std::ios::failbit);\n        return false;\n    }\n    return true;\n}\n\ntemplate <class CharT, class Traits>\nunsigned\nread_unsigned(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10)\n{\n    unsigned x = 0;\n    unsigned count = 0;\n    while (true)\n    {\n        auto ic = is.peek();\n        if (Traits::eq_int_type(ic, Traits::eof()))\n            break;\n        auto c = static_cast<char>(Traits::to_char_type(ic));\n        if (!('0' <= c && c <= '9'))\n            break;\n        (void)is.get();\n        ++count;\n        x = 10*x + static_cast<unsigned>(c - '0');\n        if (count == M)\n            break;\n    }\n    if (count < m)\n        is.setstate(std::ios::failbit);\n    return x;\n}\n\ntemplate <class CharT, class Traits>\nint\nread_signed(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10)\n{\n    auto ic = is.peek();\n    if (!Traits::eq_int_type(ic, Traits::eof()))\n    {\n        auto c = static_cast<char>(Traits::to_char_type(ic));\n        if (('0' <= c && c <= '9') || c == '-' || c == '+')\n        {\n            if (c == '-' || c == '+')\n                (void)is.get();\n            auto x = static_cast<int>(read_unsigned(is, std::max(m, 1u), M));\n            if (!is.fail())\n            {\n                if (c == '-')\n                    x = -x;\n                return x;\n            }\n        }\n    }\n    if (m > 0)\n        is.setstate(std::ios::failbit);\n    return 0;\n}\n\ntemplate <class CharT, class Traits>\nlong double\nread_long_double(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10)\n{\n    unsigned count = 0;\n    unsigned fcount = 0;\n    unsigned long long i = 0;\n    unsigned long long f = 0;\n    bool parsing_fraction = false;\n#if ONLY_C_LOCALE\n    typename Traits::int_type decimal_point = '.';\n#else\n    auto decimal_point = Traits::to_int_type(\n        std::use_facet<std::numpunct<CharT>>(is.getloc()).decimal_point());\n#endif\n    while (true)\n    {\n        auto ic = is.peek();\n        if (Traits::eq_int_type(ic, Traits::eof()))\n            break;\n        if (Traits::eq_int_type(ic, decimal_point))\n        {\n            decimal_point = Traits::eof();\n            parsing_fraction = true;\n        }\n        else\n        {\n            auto c = static_cast<char>(Traits::to_char_type(ic));\n            if (!('0' <= c && c <= '9'))\n                break;\n            if (!parsing_fraction)\n            {\n                i = 10*i + static_cast<unsigned>(c - '0');\n            }\n            else\n            {\n                f = 10*f + static_cast<unsigned>(c - '0');\n                ++fcount;\n            }\n        }\n        (void)is.get();\n        if (++count == M)\n            break;\n    }\n    if (count < m)\n    {\n        is.setstate(std::ios::failbit);\n        return 0;\n    }\n    return static_cast<long double>(i) + static_cast<long double>(f)/std::pow(10.L, fcount);\n}\n\nstruct rs\n{\n    int& i;\n    unsigned m;\n    unsigned M;\n};\n\nstruct ru\n{\n    int& i;\n    unsigned m;\n    unsigned M;\n};\n\nstruct rld\n{\n    long double& i;\n    unsigned m;\n    unsigned M;\n};\n\ntemplate <class CharT, class Traits>\nvoid\nread(std::basic_istream<CharT, Traits>&)\n{\n}\n\ntemplate <class CharT, class Traits, class ...Args>\nvoid\nread(std::basic_istream<CharT, Traits>& is, CharT a0, Args&& ...args);\n\ntemplate <class CharT, class Traits, class ...Args>\nvoid\nread(std::basic_istream<CharT, Traits>& is, rs a0, Args&& ...args);\n\ntemplate <class CharT, class Traits, class ...Args>\nvoid\nread(std::basic_istream<CharT, Traits>& is, ru a0, Args&& ...args);\n\ntemplate <class CharT, class Traits, class ...Args>\nvoid\nread(std::basic_istream<CharT, Traits>& is, int a0, Args&& ...args);\n\ntemplate <class CharT, class Traits, class ...Args>\nvoid\nread(std::basic_istream<CharT, Traits>& is, rld a0, Args&& ...args);\n\ntemplate <class CharT, class Traits, class ...Args>\nvoid\nread(std::basic_istream<CharT, Traits>& is, CharT a0, Args&& ...args)\n{\n    // No-op if a0 == CharT{}\n    if (a0 != CharT{})\n    {\n        auto ic = is.peek();\n        if (Traits::eq_int_type(ic, Traits::eof()))\n        {\n            is.setstate(std::ios::failbit | std::ios::eofbit);\n            return;\n        }\n        if (!Traits::eq(Traits::to_char_type(ic), a0))\n        {\n            is.setstate(std::ios::failbit);\n            return;\n        }\n        (void)is.get();\n    }\n    read(is, std::forward<Args>(args)...);\n}\n\ntemplate <class CharT, class Traits, class ...Args>\nvoid\nread(std::basic_istream<CharT, Traits>& is, rs a0, Args&& ...args)\n{\n    auto x = read_signed(is, a0.m, a0.M);\n    if (is.fail())\n        return;\n    a0.i = x;\n    read(is, std::forward<Args>(args)...);\n}\n\ntemplate <class CharT, class Traits, class ...Args>\nvoid\nread(std::basic_istream<CharT, Traits>& is, ru a0, Args&& ...args)\n{\n    auto x = read_unsigned(is, a0.m, a0.M);\n    if (is.fail())\n        return;\n    a0.i = static_cast<int>(x);\n    read(is, std::forward<Args>(args)...);\n}\n\ntemplate <class CharT, class Traits, class ...Args>\nvoid\nread(std::basic_istream<CharT, Traits>& is, int a0, Args&& ...args)\n{\n    if (a0 != -1)\n    {\n        auto u = static_cast<unsigned>(a0);\n        CharT buf[std::numeric_limits<unsigned>::digits10+2u] = {};\n        auto e = buf;\n        do\n        {\n            *e++ = static_cast<CharT>(CharT(u % 10) + CharT{'0'});\n            u /= 10;\n        } while (u > 0);\n        std::reverse(buf, e);\n        for (auto p = buf; p != e && is.rdstate() == std::ios::goodbit; ++p)\n            read(is, *p);\n    }\n    if (is.rdstate() == std::ios::goodbit)\n        read(is, std::forward<Args>(args)...);\n}\n\ntemplate <class CharT, class Traits, class ...Args>\nvoid\nread(std::basic_istream<CharT, Traits>& is, rld a0, Args&& ...args)\n{\n    auto x = read_long_double(is, a0.m, a0.M);\n    if (is.fail())\n        return;\n    a0.i = x;\n    read(is, std::forward<Args>(args)...);\n}\n\ntemplate <class T, class CharT, class Traits>\ninline\nvoid\nchecked_set(T& value, T from, T not_a_value, std::basic_ios<CharT, Traits>& is)\n{\n    if (!is.fail())\n    {\n        if (value == not_a_value)\n            value = std::move(from);\n        else if (value != from)\n            is.setstate(std::ios::failbit);\n    }\n}\n\n}  // namespace detail;\n\ntemplate <class CharT, class Traits, class Duration, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,\n            fields<Duration>& fds, std::basic_string<CharT, Traits, Alloc>* abbrev,\n            std::chrono::minutes* offset)\n{\n    using std::numeric_limits;\n    using std::ios;\n    using std::chrono::duration;\n    using std::chrono::duration_cast;\n    using std::chrono::seconds;\n    using std::chrono::minutes;\n    using std::chrono::hours;\n    using detail::round_i;\n    typename std::basic_istream<CharT, Traits>::sentry ok{is, true};\n    if (ok)\n    {\n        date::detail::save_istream<CharT, Traits> ss(is);\n        is.fill(' ');\n        is.flags(std::ios::skipws | std::ios::dec);\n        is.width(0);\n#if !ONLY_C_LOCALE\n        auto& f = std::use_facet<std::time_get<CharT>>(is.getloc());\n        std::tm tm{};\n#endif\n        const CharT* command = nullptr;\n        auto modified = CharT{};\n        auto width = -1;\n\n        CONSTDATA int not_a_year = numeric_limits<short>::min();\n        CONSTDATA int not_a_2digit_year = 100;\n        CONSTDATA int not_a_century = not_a_year / 100;\n        CONSTDATA int not_a_month = 0;\n        CONSTDATA int not_a_day = 0;\n        CONSTDATA int not_a_hour = numeric_limits<int>::min();\n        CONSTDATA int not_a_hour_12_value = 0;\n        CONSTDATA int not_a_minute = not_a_hour;\n        CONSTDATA Duration not_a_second = Duration::min();\n        CONSTDATA int not_a_doy = -1;\n        CONSTDATA int not_a_weekday = 8;\n        CONSTDATA int not_a_week_num = 100;\n        CONSTDATA int not_a_ampm = -1;\n        CONSTDATA minutes not_a_offset = minutes::min();\n\n        int Y = not_a_year;             // c, F, Y                   *\n        int y = not_a_2digit_year;      // D, x, y                   *\n        int g = not_a_2digit_year;      // g                         *\n        int G = not_a_year;             // G                         *\n        int C = not_a_century;          // C                         *\n        int m = not_a_month;            // b, B, h, m, c, D, F, x    *\n        int d = not_a_day;              // c, d, D, e, F, x          *\n        int j = not_a_doy;              // j                         *\n        int wd = not_a_weekday;         // a, A, u, w                *\n        int H = not_a_hour;             // c, H, R, T, X             *\n        int I = not_a_hour_12_value;    // I, r                      *\n        int p = not_a_ampm;             // p, r                      *\n        int M = not_a_minute;           // c, M, r, R, T, X          *\n        Duration s = not_a_second;      // c, r, S, T, X             *\n        int U = not_a_week_num;         // U                         *\n        int V = not_a_week_num;         // V                         *\n        int W = not_a_week_num;         // W                         *\n        std::basic_string<CharT, Traits, Alloc> temp_abbrev;  // Z   *\n        minutes temp_offset = not_a_offset;  // z                    *\n\n        using detail::read;\n        using detail::rs;\n        using detail::ru;\n        using detail::rld;\n        using detail::checked_set;\n        for (; *fmt != CharT{} && !is.fail(); ++fmt)\n        {\n            switch (*fmt)\n            {\n            case 'a':\n            case 'A':\n            case 'u':\n            case 'w':  // wd:  a, A, u, w\n                if (command)\n                {\n                    int trial_wd = not_a_weekday;\n                    if (*fmt == 'a' || *fmt == 'A')\n                    {\n                        if (modified == CharT{})\n                        {\n#if !ONLY_C_LOCALE\n                            ios::iostate err = ios::goodbit;\n                            f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                            is.setstate(err);\n                            if (!is.fail())\n                                trial_wd = tm.tm_wday;\n#else\n                            auto nm = detail::weekday_names();\n                            auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;\n                            if (!is.fail())\n                                trial_wd = i % 7;\n#endif\n                        }\n                        else\n                            read(is, CharT{'%'}, width, modified, *fmt);\n                    }\n                    else  // *fmt == 'u' || *fmt == 'w'\n                    {\n#if !ONLY_C_LOCALE\n                        if (modified == CharT{})\n#else\n                        if (modified != CharT{'E'})\n#endif\n                        {\n                            read(is, ru{trial_wd, 1, width == -1 ?\n                                                      1u : static_cast<unsigned>(width)});\n                            if (!is.fail())\n                            {\n                                if (*fmt == 'u')\n                                {\n                                    if (!(1 <= trial_wd && trial_wd <= 7))\n                                    {\n                                        trial_wd = not_a_weekday;\n                                        is.setstate(ios::failbit);\n                                    }\n                                    else if (trial_wd == 7)\n                                        trial_wd = 0;\n                                }\n                                else  // *fmt == 'w'\n                                {\n                                    if (!(0 <= trial_wd && trial_wd <= 6))\n                                    {\n                                        trial_wd = not_a_weekday;\n                                        is.setstate(ios::failbit);\n                                    }\n                                }\n                            }\n                        }\n#if !ONLY_C_LOCALE\n                        else if (modified == CharT{'O'})\n                        {\n                            ios::iostate err = ios::goodbit;\n                            f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                            is.setstate(err);\n                            if (!is.fail())\n                                trial_wd = tm.tm_wday;\n                        }\n#endif\n                        else\n                            read(is, CharT{'%'}, width, modified, *fmt);\n                    }\n                    if (trial_wd != not_a_weekday)\n                        checked_set(wd, trial_wd, not_a_weekday, is);\n                }\n                else  // !command\n                    read(is, *fmt);\n                command = nullptr;\n                width = -1;\n                modified = CharT{};\n                break;\n            case 'b':\n            case 'B':\n            case 'h':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int ttm = not_a_month;\n#if !ONLY_C_LOCALE\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                            ttm = tm.tm_mon + 1;\n                        is.setstate(err);\n#else\n                        auto nm = detail::month_names();\n                        auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;\n                        if (!is.fail())\n                            ttm = i % 12 + 1;\n#endif\n                        checked_set(m, ttm, not_a_month, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'c':\n                if (command)\n                {\n                    if (modified != CharT{'O'})\n                    {\n#if !ONLY_C_LOCALE\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                        {\n                            checked_set(Y, tm.tm_year + 1900, not_a_year, is);\n                            checked_set(m, tm.tm_mon + 1, not_a_month, is);\n                            checked_set(d, tm.tm_mday, not_a_day, is);\n                            checked_set(H, tm.tm_hour, not_a_hour, is);\n                            checked_set(M, tm.tm_min, not_a_minute, is);\n                            checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),\n                                        not_a_second, is);\n                        }\n                        is.setstate(err);\n#else\n                        // \"%a %b %e %T %Y\"\n                        auto nm = detail::weekday_names();\n                        auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;\n                        checked_set(wd, static_cast<int>(i % 7), not_a_weekday, is);\n                        ws(is);\n                        nm = detail::month_names();\n                        i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;\n                        checked_set(m, static_cast<int>(i % 12 + 1), not_a_month, is);\n                        ws(is);\n                        int td = not_a_day;\n                        read(is, rs{td, 1, 2});\n                        checked_set(d, td, not_a_day, is);\n                        ws(is);\n                        using dfs = detail::decimal_format_seconds<Duration>;\n                        CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;\n                        int tH;\n                        int tM;\n                        long double S{};\n                        read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2},\n                                               CharT{':'}, rld{S, 1, w});\n                        checked_set(H, tH, not_a_hour, is);\n                        checked_set(M, tM, not_a_minute, is);\n                        checked_set(s, round_i<Duration>(duration<long double>{S}),\n                                    not_a_second, is);\n                        ws(is);\n                        int tY = not_a_year;\n                        read(is, rs{tY, 1, 4u});\n                        checked_set(Y, tY, not_a_year, is);\n#endif\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'x':\n                if (command)\n                {\n                    if (modified != CharT{'O'})\n                    {\n#if !ONLY_C_LOCALE\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                        {\n                            checked_set(Y, tm.tm_year + 1900, not_a_year, is);\n                            checked_set(m, tm.tm_mon + 1, not_a_month, is);\n                            checked_set(d, tm.tm_mday, not_a_day, is);\n                        }\n                        is.setstate(err);\n#else\n                        // \"%m/%d/%y\"\n                        int ty = not_a_2digit_year;\n                        int tm = not_a_month;\n                        int td = not_a_day;\n                        read(is, ru{tm, 1, 2}, CharT{'/'}, ru{td, 1, 2}, CharT{'/'},\n                                 rs{ty, 1, 2});\n                        checked_set(y, ty, not_a_2digit_year, is);\n                        checked_set(m, tm, not_a_month, is);\n                        checked_set(d, td, not_a_day, is);\n#endif\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'X':\n                if (command)\n                {\n                    if (modified != CharT{'O'})\n                    {\n#if !ONLY_C_LOCALE\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                        {\n                            checked_set(H, tm.tm_hour, not_a_hour, is);\n                            checked_set(M, tm.tm_min, not_a_minute, is);\n                            checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),\n                                        not_a_second, is);\n                        }\n                        is.setstate(err);\n#else\n                        // \"%T\"\n                        using dfs = detail::decimal_format_seconds<Duration>;\n                        CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;\n                        int tH = not_a_hour;\n                        int tM = not_a_minute;\n                        long double S{};\n                        read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2},\n                                               CharT{':'}, rld{S, 1, w});\n                        checked_set(H, tH, not_a_hour, is);\n                        checked_set(M, tM, not_a_minute, is);\n                        checked_set(s, round_i<Duration>(duration<long double>{S}),\n                                    not_a_second, is);\n#endif\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'C':\n                if (command)\n                {\n                    int tC = not_a_century;\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n                    {\n#endif\n                        read(is, rs{tC, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n#if !ONLY_C_LOCALE\n                    }\n                    else\n                    {\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                        {\n                            auto tY = tm.tm_year + 1900;\n                            tC = (tY >= 0 ? tY : tY-99) / 100;\n                        }\n                        is.setstate(err);\n                    }\n#endif\n                    checked_set(C, tC, not_a_century, is);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'D':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tn = not_a_month;\n                        int td = not_a_day;\n                        int ty = not_a_2digit_year;\n                        read(is, ru{tn, 1, 2}, CharT{'\\0'}, CharT{'/'}, CharT{'\\0'},\n                                 ru{td, 1, 2}, CharT{'\\0'}, CharT{'/'}, CharT{'\\0'},\n                                 rs{ty, 1, 2});\n                        checked_set(y, ty, not_a_2digit_year, is);\n                        checked_set(m, tn, not_a_month, is);\n                        checked_set(d, td, not_a_day, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'F':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tY = not_a_year;\n                        int tn = not_a_month;\n                        int td = not_a_day;\n                        read(is, rs{tY, 1, width == -1 ? 4u : static_cast<unsigned>(width)},\n                                 CharT{'-'}, ru{tn, 1, 2}, CharT{'-'}, ru{td, 1, 2});\n                        checked_set(Y, tY, not_a_year, is);\n                        checked_set(m, tn, not_a_month, is);\n                        checked_set(d, td, not_a_day, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'd':\n            case 'e':\n                if (command)\n                {\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#else\n                    if (modified != CharT{'E'})\n#endif\n                    {\n                        int td = not_a_day;\n                        read(is, rs{td, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n                        checked_set(d, td, not_a_day, is);\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        command = nullptr;\n                        width = -1;\n                        modified = CharT{};\n                        if ((err & ios::failbit) == 0)\n                            checked_set(d, tm.tm_mday, not_a_day, is);\n                        is.setstate(err);\n                    }\n#endif\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'H':\n                if (command)\n                {\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#else\n                    if (modified != CharT{'E'})\n#endif\n                    {\n                        int tH = not_a_hour;\n                        read(is, ru{tH, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n                        checked_set(H, tH, not_a_hour, is);\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                            checked_set(H, tm.tm_hour, not_a_hour, is);\n                        is.setstate(err);\n                    }\n#endif\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'I':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tI = not_a_hour_12_value;\n                        // reads in an hour into I, but most be in [1, 12]\n                        read(is, rs{tI, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n                        if (!(1 <= tI && tI <= 12))\n                            is.setstate(ios::failbit);\n                        checked_set(I, tI, not_a_hour_12_value, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n               break;\n            case 'j':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tj = not_a_doy;\n                        read(is, ru{tj, 1, width == -1 ? 3u : static_cast<unsigned>(width)});\n                        checked_set(j, tj, not_a_doy, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'M':\n                if (command)\n                {\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#else\n                    if (modified != CharT{'E'})\n#endif\n                    {\n                        int tM = not_a_minute;\n                        read(is, ru{tM, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n                        checked_set(M, tM, not_a_minute, is);\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                            checked_set(M, tm.tm_min, not_a_minute, is);\n                        is.setstate(err);\n                    }\n#endif\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'm':\n                if (command)\n                {\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#else\n                    if (modified != CharT{'E'})\n#endif\n                    {\n                        int tn = not_a_month;\n                        read(is, rs{tn, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n                        checked_set(m, tn, not_a_month, is);\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                            checked_set(m, tm.tm_mon + 1, not_a_month, is);\n                        is.setstate(err);\n                    }\n#endif\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'n':\n            case 't':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        // %n matches a single white space character\n                        // %t matches 0 or 1 white space characters\n                        auto ic = is.peek();\n                        if (Traits::eq_int_type(ic, Traits::eof()))\n                        {\n                            ios::iostate err = ios::eofbit;\n                            if (*fmt == 'n')\n                                err |= ios::failbit;\n                            is.setstate(err);\n                            break;\n                        }\n                        if (isspace(ic))\n                        {\n                            (void)is.get();\n                        }\n                        else if (*fmt == 'n')\n                            is.setstate(ios::failbit);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'p':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tp = not_a_ampm;\n#if !ONLY_C_LOCALE\n                        tm = std::tm{};\n                        tm.tm_hour = 1;\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        is.setstate(err);\n                        if (tm.tm_hour == 1)\n                            tp = 0;\n                        else if (tm.tm_hour == 13)\n                            tp = 1;\n                        else\n                            is.setstate(err);\n#else\n                        auto nm = detail::ampm_names();\n                        auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;\n                        tp = static_cast<decltype(tp)>(i);\n#endif\n                        checked_set(p, tp, not_a_ampm, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n\n               break;\n            case 'r':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n#if !ONLY_C_LOCALE\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                        {\n                            checked_set(H, tm.tm_hour, not_a_hour, is);\n                            checked_set(M, tm.tm_min, not_a_hour, is);\n                            checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),\n                                        not_a_second, is);\n                        }\n                        is.setstate(err);\n#else\n                        // \"%I:%M:%S %p\"\n                        using dfs = detail::decimal_format_seconds<Duration>;\n                        CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;\n                        long double S{};\n                        int tI = not_a_hour_12_value;\n                        int tM = not_a_minute;\n                        read(is, ru{tI, 1, 2}, CharT{':'}, ru{tM, 1, 2},\n                                               CharT{':'}, rld{S, 1, w});\n                        checked_set(I, tI, not_a_hour_12_value, is);\n                        checked_set(M, tM, not_a_minute, is);\n                        checked_set(s, round_i<Duration>(duration<long double>{S}),\n                                    not_a_second, is);\n                        ws(is);\n                        auto nm = detail::ampm_names();\n                        auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;\n                        checked_set(p, static_cast<int>(i), not_a_ampm, is);\n#endif\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'R':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tH = not_a_hour;\n                        int tM = not_a_minute;\n                        read(is, ru{tH, 1, 2}, CharT{'\\0'}, CharT{':'}, CharT{'\\0'},\n                                 ru{tM, 1, 2}, CharT{'\\0'});\n                        checked_set(H, tH, not_a_hour, is);\n                        checked_set(M, tM, not_a_minute, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'S':\n                if (command)\n                {\n #if !ONLY_C_LOCALE\n                   if (modified == CharT{})\n#else\n                   if (modified != CharT{'E'})\n#endif\n                    {\n                        using dfs = detail::decimal_format_seconds<Duration>;\n                        CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;\n                        long double S{};\n                        read(is, rld{S, 1, width == -1 ? w : static_cast<unsigned>(width)});\n                        checked_set(s, round_i<Duration>(duration<long double>{S}),\n                                    not_a_second, is);\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'O'})\n                    {\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                            checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),\n                                        not_a_second, is);\n                        is.setstate(err);\n                    }\n#endif\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'T':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        using dfs = detail::decimal_format_seconds<Duration>;\n                        CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;\n                        int tH = not_a_hour;\n                        int tM = not_a_minute;\n                        long double S{};\n                        read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2},\n                                               CharT{':'}, rld{S, 1, w});\n                        checked_set(H, tH, not_a_hour, is);\n                        checked_set(M, tM, not_a_minute, is);\n                        checked_set(s, round_i<Duration>(duration<long double>{S}),\n                                    not_a_second, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'Y':\n                if (command)\n                {\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#else\n                    if (modified != CharT{'O'})\n#endif\n                    {\n                        int tY = not_a_year;\n                        read(is, rs{tY, 1, width == -1 ? 4u : static_cast<unsigned>(width)});\n                        checked_set(Y, tY, not_a_year, is);\n                    }\n#if !ONLY_C_LOCALE\n                    else if (modified == CharT{'E'})\n                    {\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                            checked_set(Y, tm.tm_year + 1900, not_a_year, is);\n                        is.setstate(err);\n                    }\n#endif\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'y':\n                if (command)\n                {\n#if !ONLY_C_LOCALE\n                    if (modified == CharT{})\n#endif\n                    {\n                        int ty = not_a_2digit_year;\n                        read(is, ru{ty, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n                        checked_set(y, ty, not_a_2digit_year, is);\n                    }\n#if !ONLY_C_LOCALE\n                    else\n                    {\n                        ios::iostate err = ios::goodbit;\n                        f.get(is, nullptr, is, err, &tm, command, fmt+1);\n                        if ((err & ios::failbit) == 0)\n                            checked_set(Y, tm.tm_year + 1900, not_a_year, is);\n                        is.setstate(err);\n                    }\n#endif\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'g':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tg = not_a_2digit_year;\n                        read(is, ru{tg, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n                        checked_set(g, tg, not_a_2digit_year, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'G':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tG = not_a_year;\n                        read(is, rs{tG, 1, width == -1 ? 4u : static_cast<unsigned>(width)});\n                        checked_set(G, tG, not_a_year, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'U':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tU = not_a_week_num;\n                        read(is, ru{tU, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n                        checked_set(U, tU, not_a_week_num, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'V':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tV = not_a_week_num;\n                        read(is, ru{tV, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n                        checked_set(V, tV, not_a_week_num, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'W':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        int tW = not_a_week_num;\n                        read(is, ru{tW, 1, width == -1 ? 2u : static_cast<unsigned>(width)});\n                        checked_set(W, tW, not_a_week_num, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'E':\n            case 'O':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        modified = *fmt;\n                    }\n                    else\n                    {\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                        command = nullptr;\n                        width = -1;\n                        modified = CharT{};\n                    }\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case '%':\n                if (command)\n                {\n                    if (modified == CharT{})\n                        read(is, *fmt);\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    command = fmt;\n                break;\n            case 'z':\n                if (command)\n                {\n                    int tH, tM;\n                    minutes toff = not_a_offset;\n                    bool neg = false;\n                    auto ic = is.peek();\n                    if (!Traits::eq_int_type(ic, Traits::eof()))\n                    {\n                        auto c = static_cast<char>(Traits::to_char_type(ic));\n                        if (c == '-')\n                            neg = true;\n                    }\n                    if (modified == CharT{})\n                    {\n                        read(is, rs{tH, 2, 2});\n                        if (!is.fail())\n                            toff = hours{std::abs(tH)};\n                        if (is.good())\n                        {\n                            ic = is.peek();\n                            if (!Traits::eq_int_type(ic, Traits::eof()))\n                            {\n                                auto c = static_cast<char>(Traits::to_char_type(ic));\n                                if ('0' <= c && c <= '9')\n                                {\n                                    read(is, ru{tM, 2, 2});\n                                    if (!is.fail())\n                                        toff += minutes{tM};\n                                }\n                            }\n                        }\n                    }\n                    else\n                    {\n                        read(is, rs{tH, 1, 2});\n                        if (!is.fail())\n                            toff = hours{std::abs(tH)};\n                        if (is.good())\n                        {\n                            ic = is.peek();\n                            if (!Traits::eq_int_type(ic, Traits::eof()))\n                            {\n                                auto c = static_cast<char>(Traits::to_char_type(ic));\n                                if (c == ':')\n                                {\n                                    (void)is.get();\n                                    read(is, ru{tM, 2, 2});\n                                    if (!is.fail())\n                                        toff += minutes{tM};\n                                }\n                            }\n                        }\n                    }\n                    if (neg)\n                        toff = -toff;\n                    checked_set(temp_offset, toff, not_a_offset, is);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            case 'Z':\n                if (command)\n                {\n                    if (modified == CharT{})\n                    {\n                        std::basic_string<CharT, Traits, Alloc> buf;\n                        while (is.rdstate() == std::ios::goodbit)\n                        {\n                            auto i = is.rdbuf()->sgetc();\n                            if (Traits::eq_int_type(i, Traits::eof()))\n                            {\n                                is.setstate(ios::eofbit);\n                                break;\n                            }\n                            auto wc = Traits::to_char_type(i);\n                            auto c = static_cast<char>(wc);\n                            // is c a valid time zone name or abbreviation character?\n                            if (!(CharT{1} < wc && wc < CharT{127}) || !(isalnum(c) ||\n                                    c == '_' || c == '/' || c == '-' || c == '+'))\n                                break;\n                            buf.push_back(c);\n                            is.rdbuf()->sbumpc();\n                        }\n                        if (buf.empty())\n                            is.setstate(ios::failbit);\n                        checked_set(temp_abbrev, buf, {}, is);\n                    }\n                    else\n                        read(is, CharT{'%'}, width, modified, *fmt);\n                    command = nullptr;\n                    width = -1;\n                    modified = CharT{};\n                }\n                else\n                    read(is, *fmt);\n                break;\n            default:\n                if (command)\n                {\n                    if (width == -1 && modified == CharT{} && '0' <= *fmt && *fmt <= '9')\n                    {\n                        width = static_cast<char>(*fmt) - '0';\n                        while ('0' <= fmt[1] && fmt[1] <= '9')\n                            width = 10*width + static_cast<char>(*++fmt) - '0';\n                    }\n                    else\n                    {\n                        if (modified == CharT{})\n                            read(is, CharT{'%'}, width, *fmt);\n                        else\n                            read(is, CharT{'%'}, width, modified, *fmt);\n                        command = nullptr;\n                        width = -1;\n                        modified = CharT{};\n                    }\n                }\n                else  // !command\n                {\n                    if (isspace(static_cast<unsigned char>(*fmt)))\n                    {\n                        // space matches 0 or more white space characters\n                        if (is.good())\n                           ws(is);\n                    }\n                    else\n                        read(is, *fmt);\n                }\n                break;\n            }\n        }\n        // is.fail() || *fmt == CharT{}\n        if (is.rdstate() == ios::goodbit && command)\n        {\n            if (modified == CharT{})\n                read(is, CharT{'%'}, width);\n            else\n                read(is, CharT{'%'}, width, modified);\n        }\n        if (!is.fail())\n        {\n            if (y != not_a_2digit_year)\n            {\n                // Convert y and an optional C to Y\n                if (!(0 <= y && y <= 99))\n                    goto broken;\n                if (C == not_a_century)\n                {\n                    if (Y == not_a_year)\n                    {\n                        if (y >= 69)\n                            C = 19;\n                        else\n                            C = 20;\n                    }\n                    else\n                    {\n                        C = (Y >= 0 ? Y : Y-100) / 100;\n                    }\n                }\n                int tY;\n                if (C >= 0)\n                    tY = 100*C + y;\n                else\n                    tY = 100*(C+1) - (y == 0 ? 100 : y);\n                if (Y != not_a_year && Y != tY)\n                    goto broken;\n                Y = tY;\n            }\n            if (g != not_a_2digit_year)\n            {\n                // Convert g and an optional C to G\n                if (!(0 <= g && g <= 99))\n                    goto broken;\n                if (C == not_a_century)\n                {\n                    if (G == not_a_year)\n                    {\n                        if (g >= 69)\n                            C = 19;\n                        else\n                            C = 20;\n                    }\n                    else\n                    {\n                        C = (G >= 0 ? G : G-100) / 100;\n                    }\n                }\n                int tG;\n                if (C >= 0)\n                    tG = 100*C + g;\n                else\n                    tG = 100*(C+1) - (g == 0 ? 100 : g);\n                if (G != not_a_year && G != tG)\n                    goto broken;\n                G = tG;\n            }\n            if (Y < static_cast<int>(year::min()) || Y > static_cast<int>(year::max()))\n                Y = not_a_year;\n            bool computed = false;\n            if (G != not_a_year && V != not_a_week_num && wd != not_a_weekday)\n            {\n                year_month_day ymd_trial = sys_days(year{G-1}/December/Thursday[last]) +\n                                           (Monday-Thursday) + weeks{V-1} +\n                                           (weekday{static_cast<unsigned>(wd)}-Monday);\n                if (Y == not_a_year)\n                    Y = static_cast<int>(ymd_trial.year());\n                else if (year{Y} != ymd_trial.year())\n                    goto broken;\n                if (m == not_a_month)\n                    m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));\n                else if (month(static_cast<unsigned>(m)) != ymd_trial.month())\n                    goto broken;\n                if (d == not_a_day)\n                    d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));\n                else if (day(static_cast<unsigned>(d)) != ymd_trial.day())\n                    goto broken;\n                computed = true;\n            }\n            if (Y != not_a_year && U != not_a_week_num && wd != not_a_weekday)\n            {\n                year_month_day ymd_trial = sys_days(year{Y}/January/Sunday[1]) +\n                                           weeks{U-1} +\n                                           (weekday{static_cast<unsigned>(wd)} - Sunday);\n                if (Y == not_a_year)\n                    Y = static_cast<int>(ymd_trial.year());\n                else if (year{Y} != ymd_trial.year())\n                    goto broken;\n                if (m == not_a_month)\n                    m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));\n                else if (month(static_cast<unsigned>(m)) != ymd_trial.month())\n                    goto broken;\n                if (d == not_a_day)\n                    d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));\n                else if (day(static_cast<unsigned>(d)) != ymd_trial.day())\n                    goto broken;\n                computed = true;\n            }\n            if (Y != not_a_year && W != not_a_week_num && wd != not_a_weekday)\n            {\n                year_month_day ymd_trial = sys_days(year{Y}/January/Monday[1]) +\n                                           weeks{W-1} +\n                                           (weekday{static_cast<unsigned>(wd)} - Monday);\n                if (Y == not_a_year)\n                    Y = static_cast<int>(ymd_trial.year());\n                else if (year{Y} != ymd_trial.year())\n                    goto broken;\n                if (m == not_a_month)\n                    m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));\n                else if (month(static_cast<unsigned>(m)) != ymd_trial.month())\n                    goto broken;\n                if (d == not_a_day)\n                    d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));\n                else if (day(static_cast<unsigned>(d)) != ymd_trial.day())\n                    goto broken;\n                computed = true;\n            }\n            if (j != not_a_doy && Y != not_a_year)\n            {\n                auto ymd_trial = year_month_day{local_days(year{Y}/1/1) + days{j-1}};\n                if (m == not_a_month)\n                    m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));\n                else if (month(static_cast<unsigned>(m)) != ymd_trial.month())\n                    goto broken;\n                if (d == not_a_day)\n                    d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));\n                else if (day(static_cast<unsigned>(d)) != ymd_trial.day())\n                    goto broken;\n                j = not_a_doy;\n            }\n            auto ymd = year{Y}/m/d;\n            if (ymd.ok())\n            {\n                if (wd == not_a_weekday)\n                    wd = static_cast<int>((weekday(sys_days(ymd)) - Sunday).count());\n                else if (wd != static_cast<int>((weekday(sys_days(ymd)) - Sunday).count()))\n                    goto broken;\n                if (!computed)\n                {\n                    if (G != not_a_year || V != not_a_week_num)\n                    {\n                        sys_days sd = ymd;\n                        auto G_trial = year_month_day{sd + days{3}}.year();\n                        auto start = sys_days((G_trial - years{1})/December/Thursday[last]) +\n                                     (Monday - Thursday);\n                        if (sd < start)\n                        {\n                            --G_trial;\n                            if (V != not_a_week_num)\n                                start = sys_days((G_trial - years{1})/December/Thursday[last])\n                                        + (Monday - Thursday);\n                        }\n                        if (G != not_a_year && G != static_cast<int>(G_trial))\n                            goto broken;\n                        if (V != not_a_week_num)\n                        {\n                            auto V_trial = duration_cast<weeks>(sd - start).count() + 1;\n                            if (V != V_trial)\n                                goto broken;\n                        }\n                    }\n                    if (U != not_a_week_num)\n                    {\n                        auto start = sys_days(Sunday[1]/January/ymd.year());\n                        auto U_trial = floor<weeks>(sys_days(ymd) - start).count() + 1;\n                        if (U != U_trial)\n                            goto broken;\n                    }\n                    if (W != not_a_week_num)\n                    {\n                        auto start = sys_days(Monday[1]/January/ymd.year());\n                        auto W_trial = floor<weeks>(sys_days(ymd) - start).count() + 1;\n                        if (W != W_trial)\n                            goto broken;\n                    }\n                }\n            }\n            fds.ymd = ymd;\n            if (I != not_a_hour_12_value)\n            {\n                if (!(1 <= I && I <= 12))\n                    goto broken;\n                if (p != not_a_ampm)\n                {\n                    // p is in [0, 1] == [AM, PM]\n                    // Store trial H in I\n                    if (I == 12)\n                        --p;\n                    I += p*12;\n                    // Either set H from I or make sure H and I are consistent\n                    if (H == not_a_hour)\n                        H = I;\n                    else if (I != H)\n                        goto broken;\n                }\n                else  // p == not_a_ampm\n                {\n                    // if H, make sure H and I could be consistent\n                    if (H != not_a_hour)\n                    {\n                        if (I == 12)\n                        {\n                            if (H != 0 && H != 12)\n                                goto broken;\n                        }\n                        else if (!(I == H || I == H+12))\n                        {\n                            goto broken;\n                        }\n                    }\n                    else  // I is ambiguous, AM or PM?\n                        goto broken;\n                }\n            }\n            if (H != not_a_hour)\n            {\n                fds.has_tod = true;\n                fds.tod = hh_mm_ss<Duration>{hours{H}};\n            }\n            if (M != not_a_minute)\n            {\n                fds.has_tod = true;\n                fds.tod.m_ = minutes{M};\n            }\n            if (s != not_a_second)\n            {\n                fds.has_tod = true;\n                fds.tod.s_ = detail::decimal_format_seconds<Duration>{s};\n            }\n            if (j != not_a_doy)\n            {\n                fds.has_tod = true;\n                fds.tod.h_ += hours{days{j}};\n            }\n            if (wd != not_a_weekday)\n                fds.wd = weekday{static_cast<unsigned>(wd)};\n            if (abbrev != nullptr)\n                *abbrev = std::move(temp_abbrev);\n            if (offset != nullptr && temp_offset != not_a_offset)\n              *offset = temp_offset;\n        }\n       return is;\n    }\nbroken:\n    is.setstate(ios::failbit);\n    return is;\n}\n\ntemplate <class CharT, class Traits, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, year& y,\n            std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{};\n    date::from_stream(is, fmt, fds, abbrev, offset);\n    if (!fds.ymd.year().ok())\n        is.setstate(std::ios::failbit);\n    if (!is.fail())\n        y = fds.ymd.year();\n    return is;\n}\n\ntemplate <class CharT, class Traits, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, month& m,\n            std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{};\n    date::from_stream(is, fmt, fds, abbrev, offset);\n    if (!fds.ymd.month().ok())\n        is.setstate(std::ios::failbit);\n    if (!is.fail())\n        m = fds.ymd.month();\n    return is;\n}\n\ntemplate <class CharT, class Traits, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, day& d,\n            std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{};\n    date::from_stream(is, fmt, fds, abbrev, offset);\n    if (!fds.ymd.day().ok())\n        is.setstate(std::ios::failbit);\n    if (!is.fail())\n        d = fds.ymd.day();\n    return is;\n}\n\ntemplate <class CharT, class Traits, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, weekday& wd,\n            std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{};\n    date::from_stream(is, fmt, fds, abbrev, offset);\n    if (!fds.wd.ok())\n        is.setstate(std::ios::failbit);\n    if (!is.fail())\n        wd = fds.wd;\n    return is;\n}\n\ntemplate <class CharT, class Traits, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, year_month& ym,\n            std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{};\n    date::from_stream(is, fmt, fds, abbrev, offset);\n    if (!fds.ymd.month().ok())\n        is.setstate(std::ios::failbit);\n    if (!is.fail())\n        ym = fds.ymd.year()/fds.ymd.month();\n    return is;\n}\n\ntemplate <class CharT, class Traits, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, month_day& md,\n            std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{};\n    date::from_stream(is, fmt, fds, abbrev, offset);\n    if (!fds.ymd.month().ok() || !fds.ymd.day().ok())\n        is.setstate(std::ios::failbit);\n    if (!is.fail())\n        md = fds.ymd.month()/fds.ymd.day();\n    return is;\n}\n\ntemplate <class CharT, class Traits, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,\n            year_month_day& ymd, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr)\n{\n    using CT = std::chrono::seconds;\n    fields<CT> fds{};\n    date::from_stream(is, fmt, fds, abbrev, offset);\n    if (!fds.ymd.ok())\n        is.setstate(std::ios::failbit);\n    if (!is.fail())\n        ymd = fds.ymd;\n    return is;\n}\n\ntemplate <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,\n            sys_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr)\n{\n    using CT = typename std::common_type<Duration, std::chrono::seconds>::type;\n    using detail::round_i;\n    std::chrono::minutes offset_local{};\n    auto offptr = offset ? offset : &offset_local;\n    fields<CT> fds{};\n    fds.has_tod = true;\n    date::from_stream(is, fmt, fds, abbrev, offptr);\n    if (!fds.ymd.ok() || !fds.tod.in_conventional_range())\n        is.setstate(std::ios::failbit);\n    if (!is.fail())\n        tp = round_i<Duration>(sys_days(fds.ymd) - *offptr + fds.tod.to_duration());\n    return is;\n}\n\ntemplate <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,\n            local_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr)\n{\n    using CT = typename std::common_type<Duration, std::chrono::seconds>::type;\n    using detail::round_i;\n    fields<CT> fds{};\n    fds.has_tod = true;\n    date::from_stream(is, fmt, fds, abbrev, offset);\n    if (!fds.ymd.ok() || !fds.tod.in_conventional_range())\n        is.setstate(std::ios::failbit);\n    if (!is.fail())\n        tp = round_i<Duration>(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration());\n    return is;\n}\n\ntemplate <class Rep, class Period, class CharT, class Traits, class Alloc = std::allocator<CharT>>\nstd::basic_istream<CharT, Traits>&\nfrom_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,\n            std::chrono::duration<Rep, Period>& d,\n            std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n            std::chrono::minutes* offset = nullptr)\n{\n    using Duration = std::chrono::duration<Rep, Period>;\n    using CT = typename std::common_type<Duration, std::chrono::seconds>::type;\n    using detail::round_i;\n    fields<CT> fds{};\n    date::from_stream(is, fmt, fds, abbrev, offset);\n    if (!fds.has_tod)\n        is.setstate(std::ios::failbit);\n    if (!is.fail())\n        d = round_i<Duration>(fds.tod.to_duration());\n    return is;\n}\n\ntemplate <class Parsable, class CharT, class Traits = std::char_traits<CharT>,\n          class Alloc = std::allocator<CharT>>\nstruct parse_manip\n{\n    const std::basic_string<CharT, Traits, Alloc> format_;\n    Parsable&                                     tp_;\n    std::basic_string<CharT, Traits, Alloc>*      abbrev_;\n    std::chrono::minutes*                         offset_;\n\npublic:\n    parse_manip(std::basic_string<CharT, Traits, Alloc> format, Parsable& tp,\n                std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n                std::chrono::minutes* offset = nullptr)\n        : format_(std::move(format))\n        , tp_(tp)\n        , abbrev_(abbrev)\n        , offset_(offset)\n        {}\n\n#if HAS_STRING_VIEW\n    parse_manip(const CharT* format, Parsable& tp,\n                std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n                std::chrono::minutes* offset = nullptr)\n        : format_(format)\n        , tp_(tp)\n        , abbrev_(abbrev)\n        , offset_(offset)\n        {}\n\n    parse_manip(std::basic_string_view<CharT, Traits> format, Parsable& tp,\n                std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,\n                std::chrono::minutes* offset = nullptr)\n        : format_(format)\n        , tp_(tp)\n        , abbrev_(abbrev)\n        , offset_(offset)\n        {}\n#endif  // HAS_STRING_VIEW\n};\n\ntemplate <class Parsable, class CharT, class Traits, class Alloc>\nstd::basic_istream<CharT, Traits>&\noperator>>(std::basic_istream<CharT, Traits>& is,\n           const parse_manip<Parsable, CharT, Traits, Alloc>& x)\n{\n    return date::from_stream(is, x.format_.c_str(), x.tp_, x.abbrev_, x.offset_);\n}\n\ntemplate <class Parsable, class CharT, class Traits, class Alloc>\ninline\nauto\nparse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp)\n    -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),\n                            format.c_str(), tp),\n                parse_manip<Parsable, CharT, Traits, Alloc>{format, tp})\n{\n    return {format, tp};\n}\n\ntemplate <class Parsable, class CharT, class Traits, class Alloc>\ninline\nauto\nparse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp,\n      std::basic_string<CharT, Traits, Alloc>& abbrev)\n    -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),\n                            format.c_str(), tp, &abbrev),\n                parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev})\n{\n    return {format, tp, &abbrev};\n}\n\ntemplate <class Parsable, class CharT, class Traits, class Alloc>\ninline\nauto\nparse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp,\n      std::chrono::minutes& offset)\n    -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),\n                            format.c_str(), tp,\n                            std::declval<std::basic_string<CharT, Traits, Alloc>*>(),\n                            &offset),\n                parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, nullptr, &offset})\n{\n    return {format, tp, nullptr, &offset};\n}\n\ntemplate <class Parsable, class CharT, class Traits, class Alloc>\ninline\nauto\nparse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp,\n      std::basic_string<CharT, Traits, Alloc>& abbrev, std::chrono::minutes& offset)\n    -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),\n                            format.c_str(), tp, &abbrev, &offset),\n                parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev, &offset})\n{\n    return {format, tp, &abbrev, &offset};\n}\n\n// const CharT* formats\n\ntemplate <class Parsable, class CharT>\ninline\nauto\nparse(const CharT* format, Parsable& tp)\n    -> decltype(date::from_stream(std::declval<std::basic_istream<CharT>&>(), format, tp),\n                parse_manip<Parsable, CharT>{format, tp})\n{\n    return {format, tp};\n}\n\ntemplate <class Parsable, class CharT, class Traits, class Alloc>\ninline\nauto\nparse(const CharT* format, Parsable& tp, std::basic_string<CharT, Traits, Alloc>& abbrev)\n    -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(), format,\n                            tp, &abbrev),\n                parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev})\n{\n    return {format, tp, &abbrev};\n}\n\ntemplate <class Parsable, class CharT>\ninline\nauto\nparse(const CharT* format, Parsable& tp, std::chrono::minutes& offset)\n    -> decltype(date::from_stream(std::declval<std::basic_istream<CharT>&>(), format,\n                            tp, std::declval<std::basic_string<CharT>*>(), &offset),\n                parse_manip<Parsable, CharT>{format, tp, nullptr, &offset})\n{\n    return {format, tp, nullptr, &offset};\n}\n\ntemplate <class Parsable, class CharT, class Traits, class Alloc>\ninline\nauto\nparse(const CharT* format, Parsable& tp,\n      std::basic_string<CharT, Traits, Alloc>& abbrev, std::chrono::minutes& offset)\n    -> decltype(date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(), format,\n                            tp, &abbrev, &offset),\n                parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev, &offset})\n{\n    return {format, tp, &abbrev, &offset};\n}\n\n// duration streaming\n\ntemplate <class CharT, class Traits, class Rep, class Period>\ninline\nstd::basic_ostream<CharT, Traits>&\noperator<<(std::basic_ostream<CharT, Traits>& os,\n           const std::chrono::duration<Rep, Period>& d)\n{\n    return os << detail::make_string<CharT, Traits>::from(d.count()) +\n                 detail::get_units<CharT>(typename Period::type{});\n}\n\n}  // namespace date\n\n#ifdef _MSC_VER\n#   pragma warning(pop)\n#endif\n\n#ifdef __GNUC__\n# pragma GCC diagnostic pop\n#endif\n\n#endif  // DATE_H\n"
  },
  {
    "path": "src/Common/unix/fast_float.h",
    "content": "// fast_float by Daniel Lemire\n// fast_float by João Paulo Magalhaes\n//\n// with contributions from Eugene Golushkov\n// with contributions from Maksim Kita\n// with contributions from Marcin Wojdyr\n// with contributions from Neal Richardson\n// with contributions from Tim Paine\n// with contributions from Fabio Pellacini\n//\n// Licensed under the Apache License, Version 2.0, or the\n// MIT License at your option. This file may not be copied,\n// modified, or distributed except according to those terms.\n//\n// MIT License Notice\n//\n//    MIT License\n//    \n//    Copyright (c) 2021 The fast_float authors\n//    \n//    Permission is hereby granted, free of charge, to any\n//    person obtaining a copy of this software and associated\n//    documentation files (the \"Software\"), to deal in the\n//    Software without restriction, including without\n//    limitation the rights to use, copy, modify, merge,\n//    publish, distribute, sublicense, and/or sell copies of\n//    the Software, and to permit persons to whom the Software\n//    is furnished to do so, subject to the following\n//    conditions:\n//    \n//    The above copyright notice and this permission notice\n//    shall be included in all copies or substantial portions\n//    of the Software.\n//    \n//    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\n//    ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\n//    TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\n//    PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\n//    SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n//    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n//    OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n//    IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n//    DEALINGS IN THE SOFTWARE.\n//\n// Apache License (Version 2.0) Notice\n//\n//    Copyright 2021 The fast_float authors\n//    Licensed under the Apache License, Version 2.0 (the \"License\");\n//    you may not use this file except in compliance with the License.\n//    You may obtain a copy of the License at\n//    \n//    http://www.apache.org/licenses/LICENSE-2.0\n//    \n//    Unless required by applicable law or agreed to in writing, software\n//    distributed under the License is distributed on an \"AS IS\" BASIS,\n//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n//    See the License for the specific language governing permissions and\n//\n\n#ifndef FASTFLOAT_FAST_FLOAT_H\n#define FASTFLOAT_FAST_FLOAT_H\n\n#include <system_error>\n\nnamespace fast_float {\nenum chars_format {\n    scientific = 1<<0,\n    fixed = 1<<2,\n    hex = 1<<3,\n    general = fixed | scientific\n};\n\n\nstruct from_chars_result {\n  const char *ptr;\n  std::errc ec;\n};\n\nstruct parse_options {\n  constexpr explicit parse_options(chars_format fmt = chars_format::general,\n                         char dot = '.')\n    : format(fmt), decimal_point(dot) {}\n\n  /** Which number formats are accepted */\n  chars_format format;\n  /** The character used as decimal point */\n  char decimal_point;\n};\n\n/**\n * This function parses the character sequence [first,last) for a number. It parses floating-point numbers expecting\n * a locale-indepent format equivalent to what is used by std::strtod in the default (\"C\") locale.\n * The resulting floating-point value is the closest floating-point values (using either float or double),\n * using the \"round to even\" convention for values that would otherwise fall right in-between two values.\n * That is, we provide exact parsing according to the IEEE standard.\n *\n * Given a successful parse, the pointer (`ptr`) in the returned value is set to point right after the\n * parsed number, and the `value` referenced is set to the parsed value. In case of error, the returned\n * `ec` contains a representative error, otherwise the default (`std::errc()`) value is stored.\n *\n * The implementation does not throw and does not allocate memory (e.g., with `new` or `malloc`).\n *\n * Like the C++17 standard, the `fast_float::from_chars` functions take an optional last argument of\n * the type `fast_float::chars_format`. It is a bitset value: we check whether\n * `fmt & fast_float::chars_format::fixed` and `fmt & fast_float::chars_format::scientific` are set\n * to determine whether we allowe the fixed point and scientific notation respectively.\n * The default is  `fast_float::chars_format::general` which allows both `fixed` and `scientific`.\n */\ntemplate<typename T>\nfrom_chars_result from_chars(const char *first, const char *last,\n                             T &value, chars_format fmt = chars_format::general)  noexcept;\n\n/**\n * Like from_chars, but accepts an `options` argument to govern number parsing.\n */\ntemplate<typename T>\nfrom_chars_result from_chars_advanced(const char *first, const char *last,\n                                      T &value, parse_options options)  noexcept;\n\n}\n#endif // FASTFLOAT_FAST_FLOAT_H\n\n#ifndef FASTFLOAT_FLOAT_COMMON_H\n#define FASTFLOAT_FLOAT_COMMON_H\n\n#include <cfloat>\n#include <cstdint>\n#include <cassert>\n#include <cstring>\n#include <type_traits>\n\n#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)   \\\n       || defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \\\n       || defined(__MINGW64__)                                          \\\n       || defined(__s390x__)                                            \\\n       || (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || defined(__PPC64LE__)) \\\n       || defined(__EMSCRIPTEN__))\n#define FASTFLOAT_64BIT\n#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86)   \\\n     || defined(__arm__) || defined(_M_ARM)                   \\\n     || defined(__MINGW32__))\n#define FASTFLOAT_32BIT\n#else\n  // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow.\n  // We can never tell the register width, but the SIZE_MAX is a good approximation.\n  // UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max portability.\n  #if SIZE_MAX == 0xffff\n    #error Unknown platform (16-bit, unsupported)\n  #elif SIZE_MAX == 0xffffffff\n    #define FASTFLOAT_32BIT\n  #elif SIZE_MAX == 0xffffffffffffffff\n    #define FASTFLOAT_64BIT\n  #else\n    #error Unknown platform (not 32-bit, not 64-bit?)\n  #endif\n#endif\n\n#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__))\n#include <intrin.h>\n#endif\n\n#if defined(_MSC_VER) && !defined(__clang__)\n#define FASTFLOAT_VISUAL_STUDIO 1\n#endif\n\n#ifdef _WIN32\n#define FASTFLOAT_IS_BIG_ENDIAN 0\n#else\n#if defined(__APPLE__) || defined(__FreeBSD__)\n#include <machine/endian.h>\n#elif defined(sun) || defined(__sun)\n#include <sys/byteorder.h>\n#else\n#include <endian.h>\n#endif\n#\n#ifndef __BYTE_ORDER__\n// safe choice\n#define FASTFLOAT_IS_BIG_ENDIAN 0\n#endif\n#\n#ifndef __ORDER_LITTLE_ENDIAN__\n// safe choice\n#define FASTFLOAT_IS_BIG_ENDIAN 0\n#endif\n#\n#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n#define FASTFLOAT_IS_BIG_ENDIAN 0\n#else\n#define FASTFLOAT_IS_BIG_ENDIAN 1\n#endif\n#endif\n\n#ifdef FASTFLOAT_VISUAL_STUDIO\n#define fastfloat_really_inline __forceinline\n#else\n#define fastfloat_really_inline inline __attribute__((always_inline))\n#endif\n\n#ifndef FASTFLOAT_ASSERT\n#define FASTFLOAT_ASSERT(x)  { if (!(x)) abort(); }\n#endif\n\n#ifndef FASTFLOAT_DEBUG_ASSERT\n#include <cassert>\n#define FASTFLOAT_DEBUG_ASSERT(x) assert(x)\n#endif\n\n// rust style `try!()` macro, or `?` operator\n#define FASTFLOAT_TRY(x) { if (!(x)) return false; }\n\nnamespace fast_float {\n\n// Compares two ASCII strings in a case insensitive manner.\ninline bool fastfloat_strncasecmp(const char *input1, const char *input2,\n                                  size_t length) {\n  char running_diff{0};\n  for (size_t i = 0; i < length; i++) {\n    running_diff |= (input1[i] ^ input2[i]);\n  }\n  return (running_diff == 0) || (running_diff == 32);\n}\n\n#ifndef FLT_EVAL_METHOD\n#error \"FLT_EVAL_METHOD should be defined, please include cfloat.\"\n#endif\n\n// a pointer and a length to a contiguous block of memory\ntemplate <typename T>\nstruct span {\n  const T* ptr;\n  size_t length;\n  span(const T* _ptr, size_t _length) : ptr(_ptr), length(_length) {}\n  span() : ptr(nullptr), length(0) {}\n\n  constexpr size_t len() const noexcept {\n    return length;\n  }\n\n  const T& operator[](size_t index) const noexcept {\n    FASTFLOAT_DEBUG_ASSERT(index < length);\n    return ptr[index];\n  }\n};\n\nstruct value128 {\n  uint64_t low;\n  uint64_t high;\n  value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {}\n  value128() : low(0), high(0) {}\n};\n\n/* result might be undefined when input_num is zero */\nfastfloat_really_inline int leading_zeroes(uint64_t input_num) {\n  assert(input_num > 0);\n#ifdef FASTFLOAT_VISUAL_STUDIO\n  #if defined(_M_X64) || defined(_M_ARM64)\n  unsigned long leading_zero = 0;\n  // Search the mask data from most significant bit (MSB)\n  // to least significant bit (LSB) for a set bit (1).\n  _BitScanReverse64(&leading_zero, input_num);\n  return (int)(63 - leading_zero);\n  #else\n  int last_bit = 0;\n  if(input_num & uint64_t(0xffffffff00000000)) input_num >>= 32, last_bit |= 32;\n  if(input_num & uint64_t(        0xffff0000)) input_num >>= 16, last_bit |= 16;\n  if(input_num & uint64_t(            0xff00)) input_num >>=  8, last_bit |=  8;\n  if(input_num & uint64_t(              0xf0)) input_num >>=  4, last_bit |=  4;\n  if(input_num & uint64_t(               0xc)) input_num >>=  2, last_bit |=  2;\n  if(input_num & uint64_t(               0x2)) input_num >>=  1, last_bit |=  1;\n  return 63 - last_bit;\n  #endif\n#else\n  return __builtin_clzll(input_num);\n#endif\n}\n\n#ifdef FASTFLOAT_32BIT\n\n// slow emulation routine for 32-bit\nfastfloat_really_inline uint64_t emulu(uint32_t x, uint32_t y) {\n    return x * (uint64_t)y;\n}\n\n// slow emulation routine for 32-bit\n#if !defined(__MINGW64__)\nfastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd,\n                                          uint64_t *hi) {\n  uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd);\n  uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd);\n  uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32));\n  uint64_t adbc_carry = !!(adbc < ad);\n  uint64_t lo = bd + (adbc << 32);\n  *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) +\n        (adbc_carry << 32) + !!(lo < bd);\n  return lo;\n}\n#endif // !__MINGW64__\n\n#endif // FASTFLOAT_32BIT\n\n\n// compute 64-bit a*b\nfastfloat_really_inline value128 full_multiplication(uint64_t a,\n                                                     uint64_t b) {\n  value128 answer;\n#ifdef _M_ARM64\n  // ARM64 has native support for 64-bit multiplications, no need to emulate\n  answer.high = __umulh(a, b);\n  answer.low = a * b;\n#elif defined(FASTFLOAT_32BIT) || (defined(_WIN64) && !defined(__clang__))\n  answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64\n#elif defined(FASTFLOAT_64BIT)\n  __uint128_t r = ((__uint128_t)a) * b;\n  answer.low = uint64_t(r);\n  answer.high = uint64_t(r >> 64);\n#else\n  #error Not implemented\n#endif\n  return answer;\n}\n\nstruct adjusted_mantissa {\n  uint64_t mantissa{0};\n  int32_t power2{0}; // a negative value indicates an invalid result\n  adjusted_mantissa() = default;\n  bool operator==(const adjusted_mantissa &o) const {\n    return mantissa == o.mantissa && power2 == o.power2;\n  }\n  bool operator!=(const adjusted_mantissa &o) const {\n    return mantissa != o.mantissa || power2 != o.power2;\n  }\n};\n\n// Bias so we can get the real exponent with an invalid adjusted_mantissa.\nconstexpr static int32_t invalid_am_bias = -0x8000;\n\nconstexpr static double powers_of_ten_double[] = {\n    1e0,  1e1,  1e2,  1e3,  1e4,  1e5,  1e6,  1e7,  1e8,  1e9,  1e10, 1e11,\n    1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};\nconstexpr static float powers_of_ten_float[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5,\n                                                1e6, 1e7, 1e8, 1e9, 1e10};\n\ntemplate <typename T> struct binary_format {\n  using equiv_uint = typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type;\n\n  static inline constexpr int mantissa_explicit_bits();\n  static inline constexpr int minimum_exponent();\n  static inline constexpr int infinite_power();\n  static inline constexpr int sign_index();\n  static inline constexpr int min_exponent_fast_path();\n  static inline constexpr int max_exponent_fast_path();\n  static inline constexpr int max_exponent_round_to_even();\n  static inline constexpr int min_exponent_round_to_even();\n  static inline constexpr uint64_t max_mantissa_fast_path();\n  static inline constexpr int largest_power_of_ten();\n  static inline constexpr int smallest_power_of_ten();\n  static inline constexpr T exact_power_of_ten(int64_t power);\n  static inline constexpr size_t max_digits();\n  static inline constexpr equiv_uint exponent_mask();\n  static inline constexpr equiv_uint mantissa_mask();\n  static inline constexpr equiv_uint hidden_bit_mask();\n};\n\ntemplate <> inline constexpr int binary_format<double>::mantissa_explicit_bits() {\n  return 52;\n}\ntemplate <> inline constexpr int binary_format<float>::mantissa_explicit_bits() {\n  return 23;\n}\n\ntemplate <> inline constexpr int binary_format<double>::max_exponent_round_to_even() {\n  return 23;\n}\n\ntemplate <> inline constexpr int binary_format<float>::max_exponent_round_to_even() {\n  return 10;\n}\n\ntemplate <> inline constexpr int binary_format<double>::min_exponent_round_to_even() {\n  return -4;\n}\n\ntemplate <> inline constexpr int binary_format<float>::min_exponent_round_to_even() {\n  return -17;\n}\n\ntemplate <> inline constexpr int binary_format<double>::minimum_exponent() {\n  return -1023;\n}\ntemplate <> inline constexpr int binary_format<float>::minimum_exponent() {\n  return -127;\n}\n\ntemplate <> inline constexpr int binary_format<double>::infinite_power() {\n  return 0x7FF;\n}\ntemplate <> inline constexpr int binary_format<float>::infinite_power() {\n  return 0xFF;\n}\n\ntemplate <> inline constexpr int binary_format<double>::sign_index() { return 63; }\ntemplate <> inline constexpr int binary_format<float>::sign_index() { return 31; }\n\ntemplate <> inline constexpr int binary_format<double>::min_exponent_fast_path() {\n#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)\n  return 0;\n#else\n  return -22;\n#endif\n}\ntemplate <> inline constexpr int binary_format<float>::min_exponent_fast_path() {\n#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)\n  return 0;\n#else\n  return -10;\n#endif\n}\n\ntemplate <> inline constexpr int binary_format<double>::max_exponent_fast_path() {\n  return 22;\n}\ntemplate <> inline constexpr int binary_format<float>::max_exponent_fast_path() {\n  return 10;\n}\n\ntemplate <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {\n  return uint64_t(2) << mantissa_explicit_bits();\n}\ntemplate <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {\n  return uint64_t(2) << mantissa_explicit_bits();\n}\n\ntemplate <>\ninline constexpr double binary_format<double>::exact_power_of_ten(int64_t power) {\n  return powers_of_ten_double[power];\n}\ntemplate <>\ninline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {\n\n  return powers_of_ten_float[power];\n}\n\n\ntemplate <>\ninline constexpr int binary_format<double>::largest_power_of_ten() {\n  return 308;\n}\ntemplate <>\ninline constexpr int binary_format<float>::largest_power_of_ten() {\n  return 38;\n}\n\ntemplate <>\ninline constexpr int binary_format<double>::smallest_power_of_ten() {\n  return -342;\n}\ntemplate <>\ninline constexpr int binary_format<float>::smallest_power_of_ten() {\n  return -65;\n}\n\ntemplate <> inline constexpr size_t binary_format<double>::max_digits() {\n  return 769;\n}\ntemplate <> inline constexpr size_t binary_format<float>::max_digits() {\n  return 114;\n}\n\ntemplate <> inline constexpr binary_format<float>::equiv_uint\n    binary_format<float>::exponent_mask() {\n  return 0x7F800000;\n}\ntemplate <> inline constexpr binary_format<double>::equiv_uint\n    binary_format<double>::exponent_mask() {\n  return 0x7FF0000000000000;\n}\n\ntemplate <> inline constexpr binary_format<float>::equiv_uint\n    binary_format<float>::mantissa_mask() {\n  return 0x007FFFFF;\n}\ntemplate <> inline constexpr binary_format<double>::equiv_uint\n    binary_format<double>::mantissa_mask() {\n  return 0x000FFFFFFFFFFFFF;\n}\n\ntemplate <> inline constexpr binary_format<float>::equiv_uint\n    binary_format<float>::hidden_bit_mask() {\n  return 0x00800000;\n}\ntemplate <> inline constexpr binary_format<double>::equiv_uint\n    binary_format<double>::hidden_bit_mask() {\n  return 0x0010000000000000;\n}\n\ntemplate<typename T>\nfastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &value) {\n  uint64_t word = am.mantissa;\n  word |= uint64_t(am.power2) << binary_format<T>::mantissa_explicit_bits();\n  word = negative\n  ? word | (uint64_t(1) << binary_format<T>::sign_index()) : word;\n#if FASTFLOAT_IS_BIG_ENDIAN == 1\n   if (std::is_same<T, float>::value) {\n     ::memcpy(&value, (char *)&word + 4, sizeof(T)); // extract value at offset 4-7 if float on big-endian\n   } else {\n     ::memcpy(&value, &word, sizeof(T));\n   }\n#else\n   // For little-endian systems:\n   ::memcpy(&value, &word, sizeof(T));\n#endif\n}\n\n} // namespace fast_float\n\n#endif\n\n#ifndef FASTFLOAT_ASCII_NUMBER_H\n#define FASTFLOAT_ASCII_NUMBER_H\n\n#include <cctype>\n#include <cstdint>\n#include <cstring>\n#include <iterator>\n\n\nnamespace fast_float {\n\n// Next function can be micro-optimized, but compilers are entirely\n// able to optimize it well.\nfastfloat_really_inline bool is_integer(char c)  noexcept  { return c >= '0' && c <= '9'; }\n\nfastfloat_really_inline uint64_t byteswap(uint64_t val) {\n  return (val & 0xFF00000000000000) >> 56\n    | (val & 0x00FF000000000000) >> 40\n    | (val & 0x0000FF0000000000) >> 24\n    | (val & 0x000000FF00000000) >> 8\n    | (val & 0x00000000FF000000) << 8\n    | (val & 0x0000000000FF0000) << 24\n    | (val & 0x000000000000FF00) << 40\n    | (val & 0x00000000000000FF) << 56;\n}\n\nfastfloat_really_inline uint64_t read_u64(const char *chars) {\n  uint64_t val;\n  ::memcpy(&val, chars, sizeof(uint64_t));\n#if FASTFLOAT_IS_BIG_ENDIAN == 1\n  // Need to read as-if the number was in little-endian order.\n  val = byteswap(val);\n#endif\n  return val;\n}\n\nfastfloat_really_inline void write_u64(uint8_t *chars, uint64_t val) {\n#if FASTFLOAT_IS_BIG_ENDIAN == 1\n  // Need to read as-if the number was in little-endian order.\n  val = byteswap(val);\n#endif\n  ::memcpy(chars, &val, sizeof(uint64_t));\n}\n\n// credit  @aqrit\nfastfloat_really_inline uint32_t  parse_eight_digits_unrolled(uint64_t val) {\n  const uint64_t mask = 0x000000FF000000FF;\n  const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)\n  const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)\n  val -= 0x3030303030303030;\n  val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;\n  val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;\n  return uint32_t(val);\n}\n\nfastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars)  noexcept  {\n  return parse_eight_digits_unrolled(read_u64(chars));\n}\n\n// credit @aqrit\nfastfloat_really_inline bool is_made_of_eight_digits_fast(uint64_t val)  noexcept  {\n  return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &\n     0x8080808080808080));\n}\n\nfastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars)  noexcept  {\n  return is_made_of_eight_digits_fast(read_u64(chars));\n}\n\ntypedef span<const char> byte_span;\n\nstruct parsed_number_string {\n  int64_t exponent{0};\n  uint64_t mantissa{0};\n  const char *lastmatch{nullptr};\n  bool negative{false};\n  bool valid{false};\n  bool too_many_digits{false};\n  // contains the range of the significant digits\n  byte_span integer{};  // non-nullable\n  byte_span fraction{}; // nullable\n};\n\n// Assuming that you use no more than 19 digits, this will\n// parse an ASCII string.\nfastfloat_really_inline\nparsed_number_string parse_number_string(const char *p, const char *pend, parse_options options) noexcept {\n  const chars_format fmt = options.format;\n  const char decimal_point = options.decimal_point;\n\n  parsed_number_string answer;\n  answer.valid = false;\n  answer.too_many_digits = false;\n  answer.negative = (*p == '-');\n  if (*p == '-') { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here\n    ++p;\n    if (p == pend) {\n      return answer;\n    }\n    if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot\n      return answer;\n    }\n  }\n  const char *const start_digits = p;\n\n  uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)\n\n  while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) {\n    i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok\n    p += 8;\n  }\n  while ((p != pend) && is_integer(*p)) {\n    // a multiplication by 10 is cheaper than an arbitrary integer\n    // multiplication\n    i = 10 * i +\n        uint64_t(*p - '0'); // might overflow, we will handle the overflow later\n    ++p;\n  }\n  const char *const end_of_integer_part = p;\n  int64_t digit_count = int64_t(end_of_integer_part - start_digits);\n  answer.integer = byte_span(start_digits, size_t(digit_count));\n  int64_t exponent = 0;\n  if ((p != pend) && (*p == decimal_point)) {\n    ++p;\n    const char* before = p;\n    // can occur at most twice without overflowing, but let it occur more, since\n    // for integers with many digits, digit parsing is the primary bottleneck.\n    while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) {\n      i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok\n      p += 8;\n    }\n    while ((p != pend) && is_integer(*p)) {\n      uint8_t digit = uint8_t(*p - '0');\n      ++p;\n      i = i * 10 + digit; // in rare cases, this will overflow, but that's ok\n    }\n    exponent = before - p;\n    answer.fraction = byte_span(before, size_t(p - before));\n    digit_count -= exponent;\n  }\n  // we must have encountered at least one integer!\n  if (digit_count == 0) {\n    return answer;\n  }\n  int64_t exp_number = 0;            // explicit exponential part\n  if ((fmt & chars_format::scientific) && (p != pend) && (('e' == *p) || ('E' == *p))) {\n    const char * location_of_e = p;\n    ++p;\n    bool neg_exp = false;\n    if ((p != pend) && ('-' == *p)) {\n      neg_exp = true;\n      ++p;\n    } else if ((p != pend) && ('+' == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)\n      ++p;\n    }\n    if ((p == pend) || !is_integer(*p)) {\n      if(!(fmt & chars_format::fixed)) {\n        // We are in error.\n        return answer;\n      }\n      // Otherwise, we will be ignoring the 'e'.\n      p = location_of_e;\n    } else {\n      while ((p != pend) && is_integer(*p)) {\n        uint8_t digit = uint8_t(*p - '0');\n        if (exp_number < 0x10000000) {\n          exp_number = 10 * exp_number + digit;\n        }\n        ++p;\n      }\n      if(neg_exp) { exp_number = - exp_number; }\n      exponent += exp_number;\n    }\n  } else {\n    // If it scientific and not fixed, we have to bail out.\n    if((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) { return answer; }\n  }\n  answer.lastmatch = p;\n  answer.valid = true;\n\n  // If we frequently had to deal with long strings of digits,\n  // we could extend our code by using a 128-bit integer instead\n  // of a 64-bit integer. However, this is uncommon.\n  //\n  // We can deal with up to 19 digits.\n  if (digit_count > 19) { // this is uncommon\n    // It is possible that the integer had an overflow.\n    // We have to handle the case where we have 0.0000somenumber.\n    // We need to be mindful of the case where we only have zeroes...\n    // E.g., 0.000000000...000.\n    const char *start = start_digits;\n    while ((start != pend) && (*start == '0' || *start == decimal_point)) {\n      if(*start == '0') { digit_count --; }\n      start++;\n    }\n    if (digit_count > 19) {\n      answer.too_many_digits = true;\n      // Let us start again, this time, avoiding overflows.\n      // We don't need to check if is_integer, since we use the\n      // pre-tokenized spans from above.\n      i = 0;\n      p = answer.integer.ptr;\n      const char* int_end = p + answer.integer.len();\n      const uint64_t minimal_nineteen_digit_integer{1000000000000000000};\n      while((i < minimal_nineteen_digit_integer) && (p != int_end)) {\n        i = i * 10 + uint64_t(*p - '0');\n        ++p;\n      }\n      if (i >= minimal_nineteen_digit_integer) { // We have a big integers\n        exponent = end_of_integer_part - p + exp_number;\n      } else { // We have a value with a fractional component.\n          p = answer.fraction.ptr;\n          const char* frac_end = p + answer.fraction.len();\n          while((i < minimal_nineteen_digit_integer) && (p != frac_end)) {\n            i = i * 10 + uint64_t(*p - '0');\n            ++p;\n          }\n          exponent = answer.fraction.ptr - p + exp_number;\n      }\n      // We have now corrected both exponent and i, to a truncated value\n    }\n  }\n  answer.exponent = exponent;\n  answer.mantissa = i;\n  return answer;\n}\n\n} // namespace fast_float\n\n#endif\n\n#ifndef FASTFLOAT_FAST_TABLE_H\n#define FASTFLOAT_FAST_TABLE_H\n\n#include <cstdint>\n\nnamespace fast_float {\n\n/**\n * When mapping numbers from decimal to binary,\n * we go from w * 10^q to m * 2^p but we have\n * 10^q = 5^q * 2^q, so effectively\n * we are trying to match\n * w * 2^q * 5^q to m * 2^p. Thus the powers of two\n * are not a concern since they can be represented\n * exactly using the binary notation, only the powers of five\n * affect the binary significand.\n */\n\n/**\n * The smallest non-zero float (binary64) is 2^−1074.\n * We take as input numbers of the form w x 10^q where w < 2^64.\n * We have that w * 10^-343  <  2^(64-344) 5^-343 < 2^-1076.\n * However, we have that\n * (2^64-1) * 10^-342 =  (2^64-1) * 2^-342 * 5^-342 > 2^−1074.\n * Thus it is possible for a number of the form w * 10^-342 where\n * w is a 64-bit value to be a non-zero floating-point number.\n *********\n * Any number of form w * 10^309 where w>= 1 is going to be\n * infinite in binary64 so we never need to worry about powers\n * of 5 greater than 308.\n */\ntemplate <class unused = void>\nstruct powers_template {\n\nconstexpr static int smallest_power_of_five = binary_format<double>::smallest_power_of_ten();\nconstexpr static int largest_power_of_five = binary_format<double>::largest_power_of_ten();\nconstexpr static int number_of_entries = 2 * (largest_power_of_five - smallest_power_of_five + 1);\n// Powers of five from 5^-342 all the way to 5^308 rounded toward one.\nstatic const uint64_t power_of_five_128[number_of_entries];\n};\n\ntemplate <class unused>\nconst uint64_t powers_template<unused>::power_of_five_128[number_of_entries] = {\n        0xeef453d6923bd65a,0x113faa2906a13b3f,\n        0x9558b4661b6565f8,0x4ac7ca59a424c507,\n        0xbaaee17fa23ebf76,0x5d79bcf00d2df649,\n        0xe95a99df8ace6f53,0xf4d82c2c107973dc,\n        0x91d8a02bb6c10594,0x79071b9b8a4be869,\n        0xb64ec836a47146f9,0x9748e2826cdee284,\n        0xe3e27a444d8d98b7,0xfd1b1b2308169b25,\n        0x8e6d8c6ab0787f72,0xfe30f0f5e50e20f7,\n        0xb208ef855c969f4f,0xbdbd2d335e51a935,\n        0xde8b2b66b3bc4723,0xad2c788035e61382,\n        0x8b16fb203055ac76,0x4c3bcb5021afcc31,\n        0xaddcb9e83c6b1793,0xdf4abe242a1bbf3d,\n        0xd953e8624b85dd78,0xd71d6dad34a2af0d,\n        0x87d4713d6f33aa6b,0x8672648c40e5ad68,\n        0xa9c98d8ccb009506,0x680efdaf511f18c2,\n        0xd43bf0effdc0ba48,0x212bd1b2566def2,\n        0x84a57695fe98746d,0x14bb630f7604b57,\n        0xa5ced43b7e3e9188,0x419ea3bd35385e2d,\n        0xcf42894a5dce35ea,0x52064cac828675b9,\n        0x818995ce7aa0e1b2,0x7343efebd1940993,\n        0xa1ebfb4219491a1f,0x1014ebe6c5f90bf8,\n        0xca66fa129f9b60a6,0xd41a26e077774ef6,\n        0xfd00b897478238d0,0x8920b098955522b4,\n        0x9e20735e8cb16382,0x55b46e5f5d5535b0,\n        0xc5a890362fddbc62,0xeb2189f734aa831d,\n        0xf712b443bbd52b7b,0xa5e9ec7501d523e4,\n        0x9a6bb0aa55653b2d,0x47b233c92125366e,\n        0xc1069cd4eabe89f8,0x999ec0bb696e840a,\n        0xf148440a256e2c76,0xc00670ea43ca250d,\n        0x96cd2a865764dbca,0x380406926a5e5728,\n        0xbc807527ed3e12bc,0xc605083704f5ecf2,\n        0xeba09271e88d976b,0xf7864a44c633682e,\n        0x93445b8731587ea3,0x7ab3ee6afbe0211d,\n        0xb8157268fdae9e4c,0x5960ea05bad82964,\n        0xe61acf033d1a45df,0x6fb92487298e33bd,\n        0x8fd0c16206306bab,0xa5d3b6d479f8e056,\n        0xb3c4f1ba87bc8696,0x8f48a4899877186c,\n        0xe0b62e2929aba83c,0x331acdabfe94de87,\n        0x8c71dcd9ba0b4925,0x9ff0c08b7f1d0b14,\n        0xaf8e5410288e1b6f,0x7ecf0ae5ee44dd9,\n        0xdb71e91432b1a24a,0xc9e82cd9f69d6150,\n        0x892731ac9faf056e,0xbe311c083a225cd2,\n        0xab70fe17c79ac6ca,0x6dbd630a48aaf406,\n        0xd64d3d9db981787d,0x92cbbccdad5b108,\n        0x85f0468293f0eb4e,0x25bbf56008c58ea5,\n        0xa76c582338ed2621,0xaf2af2b80af6f24e,\n        0xd1476e2c07286faa,0x1af5af660db4aee1,\n        0x82cca4db847945ca,0x50d98d9fc890ed4d,\n        0xa37fce126597973c,0xe50ff107bab528a0,\n        0xcc5fc196fefd7d0c,0x1e53ed49a96272c8,\n        0xff77b1fcbebcdc4f,0x25e8e89c13bb0f7a,\n        0x9faacf3df73609b1,0x77b191618c54e9ac,\n        0xc795830d75038c1d,0xd59df5b9ef6a2417,\n        0xf97ae3d0d2446f25,0x4b0573286b44ad1d,\n        0x9becce62836ac577,0x4ee367f9430aec32,\n        0xc2e801fb244576d5,0x229c41f793cda73f,\n        0xf3a20279ed56d48a,0x6b43527578c1110f,\n        0x9845418c345644d6,0x830a13896b78aaa9,\n        0xbe5691ef416bd60c,0x23cc986bc656d553,\n        0xedec366b11c6cb8f,0x2cbfbe86b7ec8aa8,\n        0x94b3a202eb1c3f39,0x7bf7d71432f3d6a9,\n        0xb9e08a83a5e34f07,0xdaf5ccd93fb0cc53,\n        0xe858ad248f5c22c9,0xd1b3400f8f9cff68,\n        0x91376c36d99995be,0x23100809b9c21fa1,\n        0xb58547448ffffb2d,0xabd40a0c2832a78a,\n        0xe2e69915b3fff9f9,0x16c90c8f323f516c,\n        0x8dd01fad907ffc3b,0xae3da7d97f6792e3,\n        0xb1442798f49ffb4a,0x99cd11cfdf41779c,\n        0xdd95317f31c7fa1d,0x40405643d711d583,\n        0x8a7d3eef7f1cfc52,0x482835ea666b2572,\n        0xad1c8eab5ee43b66,0xda3243650005eecf,\n        0xd863b256369d4a40,0x90bed43e40076a82,\n        0x873e4f75e2224e68,0x5a7744a6e804a291,\n        0xa90de3535aaae202,0x711515d0a205cb36,\n        0xd3515c2831559a83,0xd5a5b44ca873e03,\n        0x8412d9991ed58091,0xe858790afe9486c2,\n        0xa5178fff668ae0b6,0x626e974dbe39a872,\n        0xce5d73ff402d98e3,0xfb0a3d212dc8128f,\n        0x80fa687f881c7f8e,0x7ce66634bc9d0b99,\n        0xa139029f6a239f72,0x1c1fffc1ebc44e80,\n        0xc987434744ac874e,0xa327ffb266b56220,\n        0xfbe9141915d7a922,0x4bf1ff9f0062baa8,\n        0x9d71ac8fada6c9b5,0x6f773fc3603db4a9,\n        0xc4ce17b399107c22,0xcb550fb4384d21d3,\n        0xf6019da07f549b2b,0x7e2a53a146606a48,\n        0x99c102844f94e0fb,0x2eda7444cbfc426d,\n        0xc0314325637a1939,0xfa911155fefb5308,\n        0xf03d93eebc589f88,0x793555ab7eba27ca,\n        0x96267c7535b763b5,0x4bc1558b2f3458de,\n        0xbbb01b9283253ca2,0x9eb1aaedfb016f16,\n        0xea9c227723ee8bcb,0x465e15a979c1cadc,\n        0x92a1958a7675175f,0xbfacd89ec191ec9,\n        0xb749faed14125d36,0xcef980ec671f667b,\n        0xe51c79a85916f484,0x82b7e12780e7401a,\n        0x8f31cc0937ae58d2,0xd1b2ecb8b0908810,\n        0xb2fe3f0b8599ef07,0x861fa7e6dcb4aa15,\n        0xdfbdcece67006ac9,0x67a791e093e1d49a,\n        0x8bd6a141006042bd,0xe0c8bb2c5c6d24e0,\n        0xaecc49914078536d,0x58fae9f773886e18,\n        0xda7f5bf590966848,0xaf39a475506a899e,\n        0x888f99797a5e012d,0x6d8406c952429603,\n        0xaab37fd7d8f58178,0xc8e5087ba6d33b83,\n        0xd5605fcdcf32e1d6,0xfb1e4a9a90880a64,\n        0x855c3be0a17fcd26,0x5cf2eea09a55067f,\n        0xa6b34ad8c9dfc06f,0xf42faa48c0ea481e,\n        0xd0601d8efc57b08b,0xf13b94daf124da26,\n        0x823c12795db6ce57,0x76c53d08d6b70858,\n        0xa2cb1717b52481ed,0x54768c4b0c64ca6e,\n        0xcb7ddcdda26da268,0xa9942f5dcf7dfd09,\n        0xfe5d54150b090b02,0xd3f93b35435d7c4c,\n        0x9efa548d26e5a6e1,0xc47bc5014a1a6daf,\n        0xc6b8e9b0709f109a,0x359ab6419ca1091b,\n        0xf867241c8cc6d4c0,0xc30163d203c94b62,\n        0x9b407691d7fc44f8,0x79e0de63425dcf1d,\n        0xc21094364dfb5636,0x985915fc12f542e4,\n        0xf294b943e17a2bc4,0x3e6f5b7b17b2939d,\n        0x979cf3ca6cec5b5a,0xa705992ceecf9c42,\n        0xbd8430bd08277231,0x50c6ff782a838353,\n        0xece53cec4a314ebd,0xa4f8bf5635246428,\n        0x940f4613ae5ed136,0x871b7795e136be99,\n        0xb913179899f68584,0x28e2557b59846e3f,\n        0xe757dd7ec07426e5,0x331aeada2fe589cf,\n        0x9096ea6f3848984f,0x3ff0d2c85def7621,\n        0xb4bca50b065abe63,0xfed077a756b53a9,\n        0xe1ebce4dc7f16dfb,0xd3e8495912c62894,\n        0x8d3360f09cf6e4bd,0x64712dd7abbbd95c,\n        0xb080392cc4349dec,0xbd8d794d96aacfb3,\n        0xdca04777f541c567,0xecf0d7a0fc5583a0,\n        0x89e42caaf9491b60,0xf41686c49db57244,\n        0xac5d37d5b79b6239,0x311c2875c522ced5,\n        0xd77485cb25823ac7,0x7d633293366b828b,\n        0x86a8d39ef77164bc,0xae5dff9c02033197,\n        0xa8530886b54dbdeb,0xd9f57f830283fdfc,\n        0xd267caa862a12d66,0xd072df63c324fd7b,\n        0x8380dea93da4bc60,0x4247cb9e59f71e6d,\n        0xa46116538d0deb78,0x52d9be85f074e608,\n        0xcd795be870516656,0x67902e276c921f8b,\n        0x806bd9714632dff6,0xba1cd8a3db53b6,\n        0xa086cfcd97bf97f3,0x80e8a40eccd228a4,\n        0xc8a883c0fdaf7df0,0x6122cd128006b2cd,\n        0xfad2a4b13d1b5d6c,0x796b805720085f81,\n        0x9cc3a6eec6311a63,0xcbe3303674053bb0,\n        0xc3f490aa77bd60fc,0xbedbfc4411068a9c,\n        0xf4f1b4d515acb93b,0xee92fb5515482d44,\n        0x991711052d8bf3c5,0x751bdd152d4d1c4a,\n        0xbf5cd54678eef0b6,0xd262d45a78a0635d,\n        0xef340a98172aace4,0x86fb897116c87c34,\n        0x9580869f0e7aac0e,0xd45d35e6ae3d4da0,\n        0xbae0a846d2195712,0x8974836059cca109,\n        0xe998d258869facd7,0x2bd1a438703fc94b,\n        0x91ff83775423cc06,0x7b6306a34627ddcf,\n        0xb67f6455292cbf08,0x1a3bc84c17b1d542,\n        0xe41f3d6a7377eeca,0x20caba5f1d9e4a93,\n        0x8e938662882af53e,0x547eb47b7282ee9c,\n        0xb23867fb2a35b28d,0xe99e619a4f23aa43,\n        0xdec681f9f4c31f31,0x6405fa00e2ec94d4,\n        0x8b3c113c38f9f37e,0xde83bc408dd3dd04,\n        0xae0b158b4738705e,0x9624ab50b148d445,\n        0xd98ddaee19068c76,0x3badd624dd9b0957,\n        0x87f8a8d4cfa417c9,0xe54ca5d70a80e5d6,\n        0xa9f6d30a038d1dbc,0x5e9fcf4ccd211f4c,\n        0xd47487cc8470652b,0x7647c3200069671f,\n        0x84c8d4dfd2c63f3b,0x29ecd9f40041e073,\n        0xa5fb0a17c777cf09,0xf468107100525890,\n        0xcf79cc9db955c2cc,0x7182148d4066eeb4,\n        0x81ac1fe293d599bf,0xc6f14cd848405530,\n        0xa21727db38cb002f,0xb8ada00e5a506a7c,\n        0xca9cf1d206fdc03b,0xa6d90811f0e4851c,\n        0xfd442e4688bd304a,0x908f4a166d1da663,\n        0x9e4a9cec15763e2e,0x9a598e4e043287fe,\n        0xc5dd44271ad3cdba,0x40eff1e1853f29fd,\n        0xf7549530e188c128,0xd12bee59e68ef47c,\n        0x9a94dd3e8cf578b9,0x82bb74f8301958ce,\n        0xc13a148e3032d6e7,0xe36a52363c1faf01,\n        0xf18899b1bc3f8ca1,0xdc44e6c3cb279ac1,\n        0x96f5600f15a7b7e5,0x29ab103a5ef8c0b9,\n        0xbcb2b812db11a5de,0x7415d448f6b6f0e7,\n        0xebdf661791d60f56,0x111b495b3464ad21,\n        0x936b9fcebb25c995,0xcab10dd900beec34,\n        0xb84687c269ef3bfb,0x3d5d514f40eea742,\n        0xe65829b3046b0afa,0xcb4a5a3112a5112,\n        0x8ff71a0fe2c2e6dc,0x47f0e785eaba72ab,\n        0xb3f4e093db73a093,0x59ed216765690f56,\n        0xe0f218b8d25088b8,0x306869c13ec3532c,\n        0x8c974f7383725573,0x1e414218c73a13fb,\n        0xafbd2350644eeacf,0xe5d1929ef90898fa,\n        0xdbac6c247d62a583,0xdf45f746b74abf39,\n        0x894bc396ce5da772,0x6b8bba8c328eb783,\n        0xab9eb47c81f5114f,0x66ea92f3f326564,\n        0xd686619ba27255a2,0xc80a537b0efefebd,\n        0x8613fd0145877585,0xbd06742ce95f5f36,\n        0xa798fc4196e952e7,0x2c48113823b73704,\n        0xd17f3b51fca3a7a0,0xf75a15862ca504c5,\n        0x82ef85133de648c4,0x9a984d73dbe722fb,\n        0xa3ab66580d5fdaf5,0xc13e60d0d2e0ebba,\n        0xcc963fee10b7d1b3,0x318df905079926a8,\n        0xffbbcfe994e5c61f,0xfdf17746497f7052,\n        0x9fd561f1fd0f9bd3,0xfeb6ea8bedefa633,\n        0xc7caba6e7c5382c8,0xfe64a52ee96b8fc0,\n        0xf9bd690a1b68637b,0x3dfdce7aa3c673b0,\n        0x9c1661a651213e2d,0x6bea10ca65c084e,\n        0xc31bfa0fe5698db8,0x486e494fcff30a62,\n        0xf3e2f893dec3f126,0x5a89dba3c3efccfa,\n        0x986ddb5c6b3a76b7,0xf89629465a75e01c,\n        0xbe89523386091465,0xf6bbb397f1135823,\n        0xee2ba6c0678b597f,0x746aa07ded582e2c,\n        0x94db483840b717ef,0xa8c2a44eb4571cdc,\n        0xba121a4650e4ddeb,0x92f34d62616ce413,\n        0xe896a0d7e51e1566,0x77b020baf9c81d17,\n        0x915e2486ef32cd60,0xace1474dc1d122e,\n        0xb5b5ada8aaff80b8,0xd819992132456ba,\n        0xe3231912d5bf60e6,0x10e1fff697ed6c69,\n        0x8df5efabc5979c8f,0xca8d3ffa1ef463c1,\n        0xb1736b96b6fd83b3,0xbd308ff8a6b17cb2,\n        0xddd0467c64bce4a0,0xac7cb3f6d05ddbde,\n        0x8aa22c0dbef60ee4,0x6bcdf07a423aa96b,\n        0xad4ab7112eb3929d,0x86c16c98d2c953c6,\n        0xd89d64d57a607744,0xe871c7bf077ba8b7,\n        0x87625f056c7c4a8b,0x11471cd764ad4972,\n        0xa93af6c6c79b5d2d,0xd598e40d3dd89bcf,\n        0xd389b47879823479,0x4aff1d108d4ec2c3,\n        0x843610cb4bf160cb,0xcedf722a585139ba,\n        0xa54394fe1eedb8fe,0xc2974eb4ee658828,\n        0xce947a3da6a9273e,0x733d226229feea32,\n        0x811ccc668829b887,0x806357d5a3f525f,\n        0xa163ff802a3426a8,0xca07c2dcb0cf26f7,\n        0xc9bcff6034c13052,0xfc89b393dd02f0b5,\n        0xfc2c3f3841f17c67,0xbbac2078d443ace2,\n        0x9d9ba7832936edc0,0xd54b944b84aa4c0d,\n        0xc5029163f384a931,0xa9e795e65d4df11,\n        0xf64335bcf065d37d,0x4d4617b5ff4a16d5,\n        0x99ea0196163fa42e,0x504bced1bf8e4e45,\n        0xc06481fb9bcf8d39,0xe45ec2862f71e1d6,\n        0xf07da27a82c37088,0x5d767327bb4e5a4c,\n        0x964e858c91ba2655,0x3a6a07f8d510f86f,\n        0xbbe226efb628afea,0x890489f70a55368b,\n        0xeadab0aba3b2dbe5,0x2b45ac74ccea842e,\n        0x92c8ae6b464fc96f,0x3b0b8bc90012929d,\n        0xb77ada0617e3bbcb,0x9ce6ebb40173744,\n        0xe55990879ddcaabd,0xcc420a6a101d0515,\n        0x8f57fa54c2a9eab6,0x9fa946824a12232d,\n        0xb32df8e9f3546564,0x47939822dc96abf9,\n        0xdff9772470297ebd,0x59787e2b93bc56f7,\n        0x8bfbea76c619ef36,0x57eb4edb3c55b65a,\n        0xaefae51477a06b03,0xede622920b6b23f1,\n        0xdab99e59958885c4,0xe95fab368e45eced,\n        0x88b402f7fd75539b,0x11dbcb0218ebb414,\n        0xaae103b5fcd2a881,0xd652bdc29f26a119,\n        0xd59944a37c0752a2,0x4be76d3346f0495f,\n        0x857fcae62d8493a5,0x6f70a4400c562ddb,\n        0xa6dfbd9fb8e5b88e,0xcb4ccd500f6bb952,\n        0xd097ad07a71f26b2,0x7e2000a41346a7a7,\n        0x825ecc24c873782f,0x8ed400668c0c28c8,\n        0xa2f67f2dfa90563b,0x728900802f0f32fa,\n        0xcbb41ef979346bca,0x4f2b40a03ad2ffb9,\n        0xfea126b7d78186bc,0xe2f610c84987bfa8,\n        0x9f24b832e6b0f436,0xdd9ca7d2df4d7c9,\n        0xc6ede63fa05d3143,0x91503d1c79720dbb,\n        0xf8a95fcf88747d94,0x75a44c6397ce912a,\n        0x9b69dbe1b548ce7c,0xc986afbe3ee11aba,\n        0xc24452da229b021b,0xfbe85badce996168,\n        0xf2d56790ab41c2a2,0xfae27299423fb9c3,\n        0x97c560ba6b0919a5,0xdccd879fc967d41a,\n        0xbdb6b8e905cb600f,0x5400e987bbc1c920,\n        0xed246723473e3813,0x290123e9aab23b68,\n        0x9436c0760c86e30b,0xf9a0b6720aaf6521,\n        0xb94470938fa89bce,0xf808e40e8d5b3e69,\n        0xe7958cb87392c2c2,0xb60b1d1230b20e04,\n        0x90bd77f3483bb9b9,0xb1c6f22b5e6f48c2,\n        0xb4ecd5f01a4aa828,0x1e38aeb6360b1af3,\n        0xe2280b6c20dd5232,0x25c6da63c38de1b0,\n        0x8d590723948a535f,0x579c487e5a38ad0e,\n        0xb0af48ec79ace837,0x2d835a9df0c6d851,\n        0xdcdb1b2798182244,0xf8e431456cf88e65,\n        0x8a08f0f8bf0f156b,0x1b8e9ecb641b58ff,\n        0xac8b2d36eed2dac5,0xe272467e3d222f3f,\n        0xd7adf884aa879177,0x5b0ed81dcc6abb0f,\n        0x86ccbb52ea94baea,0x98e947129fc2b4e9,\n        0xa87fea27a539e9a5,0x3f2398d747b36224,\n        0xd29fe4b18e88640e,0x8eec7f0d19a03aad,\n        0x83a3eeeef9153e89,0x1953cf68300424ac,\n        0xa48ceaaab75a8e2b,0x5fa8c3423c052dd7,\n        0xcdb02555653131b6,0x3792f412cb06794d,\n        0x808e17555f3ebf11,0xe2bbd88bbee40bd0,\n        0xa0b19d2ab70e6ed6,0x5b6aceaeae9d0ec4,\n        0xc8de047564d20a8b,0xf245825a5a445275,\n        0xfb158592be068d2e,0xeed6e2f0f0d56712,\n        0x9ced737bb6c4183d,0x55464dd69685606b,\n        0xc428d05aa4751e4c,0xaa97e14c3c26b886,\n        0xf53304714d9265df,0xd53dd99f4b3066a8,\n        0x993fe2c6d07b7fab,0xe546a8038efe4029,\n        0xbf8fdb78849a5f96,0xde98520472bdd033,\n        0xef73d256a5c0f77c,0x963e66858f6d4440,\n        0x95a8637627989aad,0xdde7001379a44aa8,\n        0xbb127c53b17ec159,0x5560c018580d5d52,\n        0xe9d71b689dde71af,0xaab8f01e6e10b4a6,\n        0x9226712162ab070d,0xcab3961304ca70e8,\n        0xb6b00d69bb55c8d1,0x3d607b97c5fd0d22,\n        0xe45c10c42a2b3b05,0x8cb89a7db77c506a,\n        0x8eb98a7a9a5b04e3,0x77f3608e92adb242,\n        0xb267ed1940f1c61c,0x55f038b237591ed3,\n        0xdf01e85f912e37a3,0x6b6c46dec52f6688,\n        0x8b61313bbabce2c6,0x2323ac4b3b3da015,\n        0xae397d8aa96c1b77,0xabec975e0a0d081a,\n        0xd9c7dced53c72255,0x96e7bd358c904a21,\n        0x881cea14545c7575,0x7e50d64177da2e54,\n        0xaa242499697392d2,0xdde50bd1d5d0b9e9,\n        0xd4ad2dbfc3d07787,0x955e4ec64b44e864,\n        0x84ec3c97da624ab4,0xbd5af13bef0b113e,\n        0xa6274bbdd0fadd61,0xecb1ad8aeacdd58e,\n        0xcfb11ead453994ba,0x67de18eda5814af2,\n        0x81ceb32c4b43fcf4,0x80eacf948770ced7,\n        0xa2425ff75e14fc31,0xa1258379a94d028d,\n        0xcad2f7f5359a3b3e,0x96ee45813a04330,\n        0xfd87b5f28300ca0d,0x8bca9d6e188853fc,\n        0x9e74d1b791e07e48,0x775ea264cf55347e,\n        0xc612062576589dda,0x95364afe032a819e,\n        0xf79687aed3eec551,0x3a83ddbd83f52205,\n        0x9abe14cd44753b52,0xc4926a9672793543,\n        0xc16d9a0095928a27,0x75b7053c0f178294,\n        0xf1c90080baf72cb1,0x5324c68b12dd6339,\n        0x971da05074da7bee,0xd3f6fc16ebca5e04,\n        0xbce5086492111aea,0x88f4bb1ca6bcf585,\n        0xec1e4a7db69561a5,0x2b31e9e3d06c32e6,\n        0x9392ee8e921d5d07,0x3aff322e62439fd0,\n        0xb877aa3236a4b449,0x9befeb9fad487c3,\n        0xe69594bec44de15b,0x4c2ebe687989a9b4,\n        0x901d7cf73ab0acd9,0xf9d37014bf60a11,\n        0xb424dc35095cd80f,0x538484c19ef38c95,\n        0xe12e13424bb40e13,0x2865a5f206b06fba,\n        0x8cbccc096f5088cb,0xf93f87b7442e45d4,\n        0xafebff0bcb24aafe,0xf78f69a51539d749,\n        0xdbe6fecebdedd5be,0xb573440e5a884d1c,\n        0x89705f4136b4a597,0x31680a88f8953031,\n        0xabcc77118461cefc,0xfdc20d2b36ba7c3e,\n        0xd6bf94d5e57a42bc,0x3d32907604691b4d,\n        0x8637bd05af6c69b5,0xa63f9a49c2c1b110,\n        0xa7c5ac471b478423,0xfcf80dc33721d54,\n        0xd1b71758e219652b,0xd3c36113404ea4a9,\n        0x83126e978d4fdf3b,0x645a1cac083126ea,\n        0xa3d70a3d70a3d70a,0x3d70a3d70a3d70a4,\n        0xcccccccccccccccc,0xcccccccccccccccd,\n        0x8000000000000000,0x0,\n        0xa000000000000000,0x0,\n        0xc800000000000000,0x0,\n        0xfa00000000000000,0x0,\n        0x9c40000000000000,0x0,\n        0xc350000000000000,0x0,\n        0xf424000000000000,0x0,\n        0x9896800000000000,0x0,\n        0xbebc200000000000,0x0,\n        0xee6b280000000000,0x0,\n        0x9502f90000000000,0x0,\n        0xba43b74000000000,0x0,\n        0xe8d4a51000000000,0x0,\n        0x9184e72a00000000,0x0,\n        0xb5e620f480000000,0x0,\n        0xe35fa931a0000000,0x0,\n        0x8e1bc9bf04000000,0x0,\n        0xb1a2bc2ec5000000,0x0,\n        0xde0b6b3a76400000,0x0,\n        0x8ac7230489e80000,0x0,\n        0xad78ebc5ac620000,0x0,\n        0xd8d726b7177a8000,0x0,\n        0x878678326eac9000,0x0,\n        0xa968163f0a57b400,0x0,\n        0xd3c21bcecceda100,0x0,\n        0x84595161401484a0,0x0,\n        0xa56fa5b99019a5c8,0x0,\n        0xcecb8f27f4200f3a,0x0,\n        0x813f3978f8940984,0x4000000000000000,\n        0xa18f07d736b90be5,0x5000000000000000,\n        0xc9f2c9cd04674ede,0xa400000000000000,\n        0xfc6f7c4045812296,0x4d00000000000000,\n        0x9dc5ada82b70b59d,0xf020000000000000,\n        0xc5371912364ce305,0x6c28000000000000,\n        0xf684df56c3e01bc6,0xc732000000000000,\n        0x9a130b963a6c115c,0x3c7f400000000000,\n        0xc097ce7bc90715b3,0x4b9f100000000000,\n        0xf0bdc21abb48db20,0x1e86d40000000000,\n        0x96769950b50d88f4,0x1314448000000000,\n        0xbc143fa4e250eb31,0x17d955a000000000,\n        0xeb194f8e1ae525fd,0x5dcfab0800000000,\n        0x92efd1b8d0cf37be,0x5aa1cae500000000,\n        0xb7abc627050305ad,0xf14a3d9e40000000,\n        0xe596b7b0c643c719,0x6d9ccd05d0000000,\n        0x8f7e32ce7bea5c6f,0xe4820023a2000000,\n        0xb35dbf821ae4f38b,0xdda2802c8a800000,\n        0xe0352f62a19e306e,0xd50b2037ad200000,\n        0x8c213d9da502de45,0x4526f422cc340000,\n        0xaf298d050e4395d6,0x9670b12b7f410000,\n        0xdaf3f04651d47b4c,0x3c0cdd765f114000,\n        0x88d8762bf324cd0f,0xa5880a69fb6ac800,\n        0xab0e93b6efee0053,0x8eea0d047a457a00,\n        0xd5d238a4abe98068,0x72a4904598d6d880,\n        0x85a36366eb71f041,0x47a6da2b7f864750,\n        0xa70c3c40a64e6c51,0x999090b65f67d924,\n        0xd0cf4b50cfe20765,0xfff4b4e3f741cf6d,\n        0x82818f1281ed449f,0xbff8f10e7a8921a4,\n        0xa321f2d7226895c7,0xaff72d52192b6a0d,\n        0xcbea6f8ceb02bb39,0x9bf4f8a69f764490,\n        0xfee50b7025c36a08,0x2f236d04753d5b4,\n        0x9f4f2726179a2245,0x1d762422c946590,\n        0xc722f0ef9d80aad6,0x424d3ad2b7b97ef5,\n        0xf8ebad2b84e0d58b,0xd2e0898765a7deb2,\n        0x9b934c3b330c8577,0x63cc55f49f88eb2f,\n        0xc2781f49ffcfa6d5,0x3cbf6b71c76b25fb,\n        0xf316271c7fc3908a,0x8bef464e3945ef7a,\n        0x97edd871cfda3a56,0x97758bf0e3cbb5ac,\n        0xbde94e8e43d0c8ec,0x3d52eeed1cbea317,\n        0xed63a231d4c4fb27,0x4ca7aaa863ee4bdd,\n        0x945e455f24fb1cf8,0x8fe8caa93e74ef6a,\n        0xb975d6b6ee39e436,0xb3e2fd538e122b44,\n        0xe7d34c64a9c85d44,0x60dbbca87196b616,\n        0x90e40fbeea1d3a4a,0xbc8955e946fe31cd,\n        0xb51d13aea4a488dd,0x6babab6398bdbe41,\n        0xe264589a4dcdab14,0xc696963c7eed2dd1,\n        0x8d7eb76070a08aec,0xfc1e1de5cf543ca2,\n        0xb0de65388cc8ada8,0x3b25a55f43294bcb,\n        0xdd15fe86affad912,0x49ef0eb713f39ebe,\n        0x8a2dbf142dfcc7ab,0x6e3569326c784337,\n        0xacb92ed9397bf996,0x49c2c37f07965404,\n        0xd7e77a8f87daf7fb,0xdc33745ec97be906,\n        0x86f0ac99b4e8dafd,0x69a028bb3ded71a3,\n        0xa8acd7c0222311bc,0xc40832ea0d68ce0c,\n        0xd2d80db02aabd62b,0xf50a3fa490c30190,\n        0x83c7088e1aab65db,0x792667c6da79e0fa,\n        0xa4b8cab1a1563f52,0x577001b891185938,\n        0xcde6fd5e09abcf26,0xed4c0226b55e6f86,\n        0x80b05e5ac60b6178,0x544f8158315b05b4,\n        0xa0dc75f1778e39d6,0x696361ae3db1c721,\n        0xc913936dd571c84c,0x3bc3a19cd1e38e9,\n        0xfb5878494ace3a5f,0x4ab48a04065c723,\n        0x9d174b2dcec0e47b,0x62eb0d64283f9c76,\n        0xc45d1df942711d9a,0x3ba5d0bd324f8394,\n        0xf5746577930d6500,0xca8f44ec7ee36479,\n        0x9968bf6abbe85f20,0x7e998b13cf4e1ecb,\n        0xbfc2ef456ae276e8,0x9e3fedd8c321a67e,\n        0xefb3ab16c59b14a2,0xc5cfe94ef3ea101e,\n        0x95d04aee3b80ece5,0xbba1f1d158724a12,\n        0xbb445da9ca61281f,0x2a8a6e45ae8edc97,\n        0xea1575143cf97226,0xf52d09d71a3293bd,\n        0x924d692ca61be758,0x593c2626705f9c56,\n        0xb6e0c377cfa2e12e,0x6f8b2fb00c77836c,\n        0xe498f455c38b997a,0xb6dfb9c0f956447,\n        0x8edf98b59a373fec,0x4724bd4189bd5eac,\n        0xb2977ee300c50fe7,0x58edec91ec2cb657,\n        0xdf3d5e9bc0f653e1,0x2f2967b66737e3ed,\n        0x8b865b215899f46c,0xbd79e0d20082ee74,\n        0xae67f1e9aec07187,0xecd8590680a3aa11,\n        0xda01ee641a708de9,0xe80e6f4820cc9495,\n        0x884134fe908658b2,0x3109058d147fdcdd,\n        0xaa51823e34a7eede,0xbd4b46f0599fd415,\n        0xd4e5e2cdc1d1ea96,0x6c9e18ac7007c91a,\n        0x850fadc09923329e,0x3e2cf6bc604ddb0,\n        0xa6539930bf6bff45,0x84db8346b786151c,\n        0xcfe87f7cef46ff16,0xe612641865679a63,\n        0x81f14fae158c5f6e,0x4fcb7e8f3f60c07e,\n        0xa26da3999aef7749,0xe3be5e330f38f09d,\n        0xcb090c8001ab551c,0x5cadf5bfd3072cc5,\n        0xfdcb4fa002162a63,0x73d9732fc7c8f7f6,\n        0x9e9f11c4014dda7e,0x2867e7fddcdd9afa,\n        0xc646d63501a1511d,0xb281e1fd541501b8,\n        0xf7d88bc24209a565,0x1f225a7ca91a4226,\n        0x9ae757596946075f,0x3375788de9b06958,\n        0xc1a12d2fc3978937,0x52d6b1641c83ae,\n        0xf209787bb47d6b84,0xc0678c5dbd23a49a,\n        0x9745eb4d50ce6332,0xf840b7ba963646e0,\n        0xbd176620a501fbff,0xb650e5a93bc3d898,\n        0xec5d3fa8ce427aff,0xa3e51f138ab4cebe,\n        0x93ba47c980e98cdf,0xc66f336c36b10137,\n        0xb8a8d9bbe123f017,0xb80b0047445d4184,\n        0xe6d3102ad96cec1d,0xa60dc059157491e5,\n        0x9043ea1ac7e41392,0x87c89837ad68db2f,\n        0xb454e4a179dd1877,0x29babe4598c311fb,\n        0xe16a1dc9d8545e94,0xf4296dd6fef3d67a,\n        0x8ce2529e2734bb1d,0x1899e4a65f58660c,\n        0xb01ae745b101e9e4,0x5ec05dcff72e7f8f,\n        0xdc21a1171d42645d,0x76707543f4fa1f73,\n        0x899504ae72497eba,0x6a06494a791c53a8,\n        0xabfa45da0edbde69,0x487db9d17636892,\n        0xd6f8d7509292d603,0x45a9d2845d3c42b6,\n        0x865b86925b9bc5c2,0xb8a2392ba45a9b2,\n        0xa7f26836f282b732,0x8e6cac7768d7141e,\n        0xd1ef0244af2364ff,0x3207d795430cd926,\n        0x8335616aed761f1f,0x7f44e6bd49e807b8,\n        0xa402b9c5a8d3a6e7,0x5f16206c9c6209a6,\n        0xcd036837130890a1,0x36dba887c37a8c0f,\n        0x802221226be55a64,0xc2494954da2c9789,\n        0xa02aa96b06deb0fd,0xf2db9baa10b7bd6c,\n        0xc83553c5c8965d3d,0x6f92829494e5acc7,\n        0xfa42a8b73abbf48c,0xcb772339ba1f17f9,\n        0x9c69a97284b578d7,0xff2a760414536efb,\n        0xc38413cf25e2d70d,0xfef5138519684aba,\n        0xf46518c2ef5b8cd1,0x7eb258665fc25d69,\n        0x98bf2f79d5993802,0xef2f773ffbd97a61,\n        0xbeeefb584aff8603,0xaafb550ffacfd8fa,\n        0xeeaaba2e5dbf6784,0x95ba2a53f983cf38,\n        0x952ab45cfa97a0b2,0xdd945a747bf26183,\n        0xba756174393d88df,0x94f971119aeef9e4,\n        0xe912b9d1478ceb17,0x7a37cd5601aab85d,\n        0x91abb422ccb812ee,0xac62e055c10ab33a,\n        0xb616a12b7fe617aa,0x577b986b314d6009,\n        0xe39c49765fdf9d94,0xed5a7e85fda0b80b,\n        0x8e41ade9fbebc27d,0x14588f13be847307,\n        0xb1d219647ae6b31c,0x596eb2d8ae258fc8,\n        0xde469fbd99a05fe3,0x6fca5f8ed9aef3bb,\n        0x8aec23d680043bee,0x25de7bb9480d5854,\n        0xada72ccc20054ae9,0xaf561aa79a10ae6a,\n        0xd910f7ff28069da4,0x1b2ba1518094da04,\n        0x87aa9aff79042286,0x90fb44d2f05d0842,\n        0xa99541bf57452b28,0x353a1607ac744a53,\n        0xd3fa922f2d1675f2,0x42889b8997915ce8,\n        0x847c9b5d7c2e09b7,0x69956135febada11,\n        0xa59bc234db398c25,0x43fab9837e699095,\n        0xcf02b2c21207ef2e,0x94f967e45e03f4bb,\n        0x8161afb94b44f57d,0x1d1be0eebac278f5,\n        0xa1ba1ba79e1632dc,0x6462d92a69731732,\n        0xca28a291859bbf93,0x7d7b8f7503cfdcfe,\n        0xfcb2cb35e702af78,0x5cda735244c3d43e,\n        0x9defbf01b061adab,0x3a0888136afa64a7,\n        0xc56baec21c7a1916,0x88aaa1845b8fdd0,\n        0xf6c69a72a3989f5b,0x8aad549e57273d45,\n        0x9a3c2087a63f6399,0x36ac54e2f678864b,\n        0xc0cb28a98fcf3c7f,0x84576a1bb416a7dd,\n        0xf0fdf2d3f3c30b9f,0x656d44a2a11c51d5,\n        0x969eb7c47859e743,0x9f644ae5a4b1b325,\n        0xbc4665b596706114,0x873d5d9f0dde1fee,\n        0xeb57ff22fc0c7959,0xa90cb506d155a7ea,\n        0x9316ff75dd87cbd8,0x9a7f12442d588f2,\n        0xb7dcbf5354e9bece,0xc11ed6d538aeb2f,\n        0xe5d3ef282a242e81,0x8f1668c8a86da5fa,\n        0x8fa475791a569d10,0xf96e017d694487bc,\n        0xb38d92d760ec4455,0x37c981dcc395a9ac,\n        0xe070f78d3927556a,0x85bbe253f47b1417,\n        0x8c469ab843b89562,0x93956d7478ccec8e,\n        0xaf58416654a6babb,0x387ac8d1970027b2,\n        0xdb2e51bfe9d0696a,0x6997b05fcc0319e,\n        0x88fcf317f22241e2,0x441fece3bdf81f03,\n        0xab3c2fddeeaad25a,0xd527e81cad7626c3,\n        0xd60b3bd56a5586f1,0x8a71e223d8d3b074,\n        0x85c7056562757456,0xf6872d5667844e49,\n        0xa738c6bebb12d16c,0xb428f8ac016561db,\n        0xd106f86e69d785c7,0xe13336d701beba52,\n        0x82a45b450226b39c,0xecc0024661173473,\n        0xa34d721642b06084,0x27f002d7f95d0190,\n        0xcc20ce9bd35c78a5,0x31ec038df7b441f4,\n        0xff290242c83396ce,0x7e67047175a15271,\n        0x9f79a169bd203e41,0xf0062c6e984d386,\n        0xc75809c42c684dd1,0x52c07b78a3e60868,\n        0xf92e0c3537826145,0xa7709a56ccdf8a82,\n        0x9bbcc7a142b17ccb,0x88a66076400bb691,\n        0xc2abf989935ddbfe,0x6acff893d00ea435,\n        0xf356f7ebf83552fe,0x583f6b8c4124d43,\n        0x98165af37b2153de,0xc3727a337a8b704a,\n        0xbe1bf1b059e9a8d6,0x744f18c0592e4c5c,\n        0xeda2ee1c7064130c,0x1162def06f79df73,\n        0x9485d4d1c63e8be7,0x8addcb5645ac2ba8,\n        0xb9a74a0637ce2ee1,0x6d953e2bd7173692,\n        0xe8111c87c5c1ba99,0xc8fa8db6ccdd0437,\n        0x910ab1d4db9914a0,0x1d9c9892400a22a2,\n        0xb54d5e4a127f59c8,0x2503beb6d00cab4b,\n        0xe2a0b5dc971f303a,0x2e44ae64840fd61d,\n        0x8da471a9de737e24,0x5ceaecfed289e5d2,\n        0xb10d8e1456105dad,0x7425a83e872c5f47,\n        0xdd50f1996b947518,0xd12f124e28f77719,\n        0x8a5296ffe33cc92f,0x82bd6b70d99aaa6f,\n        0xace73cbfdc0bfb7b,0x636cc64d1001550b,\n        0xd8210befd30efa5a,0x3c47f7e05401aa4e,\n        0x8714a775e3e95c78,0x65acfaec34810a71,\n        0xa8d9d1535ce3b396,0x7f1839a741a14d0d,\n        0xd31045a8341ca07c,0x1ede48111209a050,\n        0x83ea2b892091e44d,0x934aed0aab460432,\n        0xa4e4b66b68b65d60,0xf81da84d5617853f,\n        0xce1de40642e3f4b9,0x36251260ab9d668e,\n        0x80d2ae83e9ce78f3,0xc1d72b7c6b426019,\n        0xa1075a24e4421730,0xb24cf65b8612f81f,\n        0xc94930ae1d529cfc,0xdee033f26797b627,\n        0xfb9b7cd9a4a7443c,0x169840ef017da3b1,\n        0x9d412e0806e88aa5,0x8e1f289560ee864e,\n        0xc491798a08a2ad4e,0xf1a6f2bab92a27e2,\n        0xf5b5d7ec8acb58a2,0xae10af696774b1db,\n        0x9991a6f3d6bf1765,0xacca6da1e0a8ef29,\n        0xbff610b0cc6edd3f,0x17fd090a58d32af3,\n        0xeff394dcff8a948e,0xddfc4b4cef07f5b0,\n        0x95f83d0a1fb69cd9,0x4abdaf101564f98e,\n        0xbb764c4ca7a4440f,0x9d6d1ad41abe37f1,\n        0xea53df5fd18d5513,0x84c86189216dc5ed,\n        0x92746b9be2f8552c,0x32fd3cf5b4e49bb4,\n        0xb7118682dbb66a77,0x3fbc8c33221dc2a1,\n        0xe4d5e82392a40515,0xfabaf3feaa5334a,\n        0x8f05b1163ba6832d,0x29cb4d87f2a7400e,\n        0xb2c71d5bca9023f8,0x743e20e9ef511012,\n        0xdf78e4b2bd342cf6,0x914da9246b255416,\n        0x8bab8eefb6409c1a,0x1ad089b6c2f7548e,\n        0xae9672aba3d0c320,0xa184ac2473b529b1,\n        0xda3c0f568cc4f3e8,0xc9e5d72d90a2741e,\n        0x8865899617fb1871,0x7e2fa67c7a658892,\n        0xaa7eebfb9df9de8d,0xddbb901b98feeab7,\n        0xd51ea6fa85785631,0x552a74227f3ea565,\n        0x8533285c936b35de,0xd53a88958f87275f,\n        0xa67ff273b8460356,0x8a892abaf368f137,\n        0xd01fef10a657842c,0x2d2b7569b0432d85,\n        0x8213f56a67f6b29b,0x9c3b29620e29fc73,\n        0xa298f2c501f45f42,0x8349f3ba91b47b8f,\n        0xcb3f2f7642717713,0x241c70a936219a73,\n        0xfe0efb53d30dd4d7,0xed238cd383aa0110,\n        0x9ec95d1463e8a506,0xf4363804324a40aa,\n        0xc67bb4597ce2ce48,0xb143c6053edcd0d5,\n        0xf81aa16fdc1b81da,0xdd94b7868e94050a,\n        0x9b10a4e5e9913128,0xca7cf2b4191c8326,\n        0xc1d4ce1f63f57d72,0xfd1c2f611f63a3f0,\n        0xf24a01a73cf2dccf,0xbc633b39673c8cec,\n        0x976e41088617ca01,0xd5be0503e085d813,\n        0xbd49d14aa79dbc82,0x4b2d8644d8a74e18,\n        0xec9c459d51852ba2,0xddf8e7d60ed1219e,\n        0x93e1ab8252f33b45,0xcabb90e5c942b503,\n        0xb8da1662e7b00a17,0x3d6a751f3b936243,\n        0xe7109bfba19c0c9d,0xcc512670a783ad4,\n        0x906a617d450187e2,0x27fb2b80668b24c5,\n        0xb484f9dc9641e9da,0xb1f9f660802dedf6,\n        0xe1a63853bbd26451,0x5e7873f8a0396973,\n        0x8d07e33455637eb2,0xdb0b487b6423e1e8,\n        0xb049dc016abc5e5f,0x91ce1a9a3d2cda62,\n        0xdc5c5301c56b75f7,0x7641a140cc7810fb,\n        0x89b9b3e11b6329ba,0xa9e904c87fcb0a9d,\n        0xac2820d9623bf429,0x546345fa9fbdcd44,\n        0xd732290fbacaf133,0xa97c177947ad4095,\n        0x867f59a9d4bed6c0,0x49ed8eabcccc485d,\n        0xa81f301449ee8c70,0x5c68f256bfff5a74,\n        0xd226fc195c6a2f8c,0x73832eec6fff3111,\n        0x83585d8fd9c25db7,0xc831fd53c5ff7eab,\n        0xa42e74f3d032f525,0xba3e7ca8b77f5e55,\n        0xcd3a1230c43fb26f,0x28ce1bd2e55f35eb,\n        0x80444b5e7aa7cf85,0x7980d163cf5b81b3,\n        0xa0555e361951c366,0xd7e105bcc332621f,\n        0xc86ab5c39fa63440,0x8dd9472bf3fefaa7,\n        0xfa856334878fc150,0xb14f98f6f0feb951,\n        0x9c935e00d4b9d8d2,0x6ed1bf9a569f33d3,\n        0xc3b8358109e84f07,0xa862f80ec4700c8,\n        0xf4a642e14c6262c8,0xcd27bb612758c0fa,\n        0x98e7e9cccfbd7dbd,0x8038d51cb897789c,\n        0xbf21e44003acdd2c,0xe0470a63e6bd56c3,\n        0xeeea5d5004981478,0x1858ccfce06cac74,\n        0x95527a5202df0ccb,0xf37801e0c43ebc8,\n        0xbaa718e68396cffd,0xd30560258f54e6ba,\n        0xe950df20247c83fd,0x47c6b82ef32a2069,\n        0x91d28b7416cdd27e,0x4cdc331d57fa5441,\n        0xb6472e511c81471d,0xe0133fe4adf8e952,\n        0xe3d8f9e563a198e5,0x58180fddd97723a6,\n        0x8e679c2f5e44ff8f,0x570f09eaa7ea7648,};\nusing powers = powers_template<>;\n\n}\n\n#endif\n\n#ifndef FASTFLOAT_DECIMAL_TO_BINARY_H\n#define FASTFLOAT_DECIMAL_TO_BINARY_H\n\n#include <cfloat>\n#include <cinttypes>\n#include <cmath>\n#include <cstdint>\n#include <cstdlib>\n#include <cstring>\n\nnamespace fast_float {\n\n// This will compute or rather approximate w * 5**q and return a pair of 64-bit words approximating\n// the result, with the \"high\" part corresponding to the most significant bits and the\n// low part corresponding to the least significant bits.\n//\ntemplate <int bit_precision>\nfastfloat_really_inline\nvalue128 compute_product_approximation(int64_t q, uint64_t w) {\n  const int index = 2 * int(q - powers::smallest_power_of_five);\n  // For small values of q, e.g., q in [0,27], the answer is always exact because\n  // The line value128 firstproduct = full_multiplication(w, power_of_five_128[index]);\n  // gives the exact answer.\n  value128 firstproduct = full_multiplication(w, powers::power_of_five_128[index]);\n  static_assert((bit_precision >= 0) && (bit_precision <= 64), \" precision should  be in (0,64]\");\n  constexpr uint64_t precision_mask = (bit_precision < 64) ?\n               (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision)\n               : uint64_t(0xFFFFFFFFFFFFFFFF);\n  if((firstproduct.high & precision_mask) == precision_mask) { // could further guard with  (lower + w < lower)\n    // regarding the second product, we only need secondproduct.high, but our expectation is that the compiler will optimize this extra work away if needed.\n    value128 secondproduct = full_multiplication(w, powers::power_of_five_128[index + 1]);\n    firstproduct.low += secondproduct.high;\n    if(secondproduct.high > firstproduct.low) {\n      firstproduct.high++;\n    }\n  }\n  return firstproduct;\n}\n\nnamespace detail {\n/**\n * For q in (0,350), we have that\n *  f = (((152170 + 65536) * q ) >> 16);\n * is equal to\n *   floor(p) + q\n * where\n *   p = log(5**q)/log(2) = q * log(5)/log(2)\n *\n * For negative values of q in (-400,0), we have that \n *  f = (((152170 + 65536) * q ) >> 16);\n * is equal to \n *   -ceil(p) + q\n * where\n *   p = log(5**-q)/log(2) = -q * log(5)/log(2)\n */\n  constexpr fastfloat_really_inline int32_t power(int32_t q)  noexcept  {\n    return (((152170 + 65536) * q) >> 16) + 63;\n  }\n} // namespace detail\n\n// create an adjusted mantissa, biased by the invalid power2\n// for significant digits already multiplied by 10 ** q.\ntemplate <typename binary>\nfastfloat_really_inline\nadjusted_mantissa compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept  {\n  int hilz = int(w >> 63) ^ 1;\n  adjusted_mantissa answer;\n  answer.mantissa = w << hilz;\n  int bias = binary::mantissa_explicit_bits() - binary::minimum_exponent();\n  answer.power2 = int32_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + invalid_am_bias);\n  return answer;\n}\n\n// w * 10 ** q, without rounding the representation up.\n// the power2 in the exponent will be adjusted by invalid_am_bias.\ntemplate <typename binary>\nfastfloat_really_inline\nadjusted_mantissa compute_error(int64_t q, uint64_t w)  noexcept  {\n  int lz = leading_zeroes(w);\n  w <<= lz;\n  value128 product = compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);\n  return compute_error_scaled<binary>(q, product.high, lz);\n}\n\n// w * 10 ** q\n// The returned value should be a valid ieee64 number that simply need to be packed.\n// However, in some very rare cases, the computation will fail. In such cases, we\n// return an adjusted_mantissa with a negative power of 2: the caller should recompute\n// in such cases.\ntemplate <typename binary>\nfastfloat_really_inline\nadjusted_mantissa compute_float(int64_t q, uint64_t w)  noexcept  {\n  adjusted_mantissa answer;\n  if ((w == 0) || (q < binary::smallest_power_of_ten())) {\n    answer.power2 = 0;\n    answer.mantissa = 0;\n    // result should be zero\n    return answer;\n  }\n  if (q > binary::largest_power_of_ten()) {\n    // we want to get infinity:\n    answer.power2 = binary::infinite_power();\n    answer.mantissa = 0;\n    return answer;\n  }\n  // At this point in time q is in [powers::smallest_power_of_five, powers::largest_power_of_five].\n\n  // We want the most significant bit of i to be 1. Shift if needed.\n  int lz = leading_zeroes(w);\n  w <<= lz;\n\n  // The required precision is binary::mantissa_explicit_bits() + 3 because\n  // 1. We need the implicit bit\n  // 2. We need an extra bit for rounding purposes\n  // 3. We might lose a bit due to the \"upperbit\" routine (result too small, requiring a shift)\n\n  value128 product = compute_product_approximation<binary::mantissa_explicit_bits() + 3>(q, w);\n  if(product.low == 0xFFFFFFFFFFFFFFFF) { //  could guard it further\n    // In some very rare cases, this could happen, in which case we might need a more accurate\n    // computation that what we can provide cheaply. This is very, very unlikely.\n    //\n    const bool inside_safe_exponent = (q >= -27) && (q <= 55); // always good because 5**q <2**128 when q>=0, \n    // and otherwise, for q<0, we have 5**-q<2**64 and the 128-bit reciprocal allows for exact computation.\n    if(!inside_safe_exponent) {\n      return compute_error_scaled<binary>(q, product.high, lz);\n    }\n  }\n  // The \"compute_product_approximation\" function can be slightly slower than a branchless approach:\n  // value128 product = compute_product(q, w);\n  // but in practice, we can win big with the compute_product_approximation if its additional branch\n  // is easily predicted. Which is best is data specific.\n  int upperbit = int(product.high >> 63);\n\n  answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);\n\n  answer.power2 = int32_t(detail::power(int32_t(q)) + upperbit - lz - binary::minimum_exponent());\n  if (answer.power2 <= 0) { // we have a subnormal?\n    // Here have that answer.power2 <= 0 so -answer.power2 >= 0\n    if(-answer.power2 + 1 >= 64) { // if we have more than 64 bits below the minimum exponent, you have a zero for sure.\n      answer.power2 = 0;\n      answer.mantissa = 0;\n      // result should be zero\n      return answer;\n    }\n    // next line is safe because -answer.power2 + 1 < 64\n    answer.mantissa >>= -answer.power2 + 1;\n    // Thankfully, we can't have both \"round-to-even\" and subnormals because\n    // \"round-to-even\" only occurs for powers close to 0.\n    answer.mantissa += (answer.mantissa & 1); // round up\n    answer.mantissa >>= 1;\n    // There is a weird scenario where we don't have a subnormal but just.\n    // Suppose we start with 2.2250738585072013e-308, we end up\n    // with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal\n    // whereas 0x40000000000000 x 2^-1023-53  is normal. Now, we need to round\n    // up 0x3fffffffffffff x 2^-1023-53  and once we do, we are no longer\n    // subnormal, but we can only know this after rounding.\n    // So we only declare a subnormal if we are smaller than the threshold.\n    answer.power2 = (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) ? 0 : 1;\n    return answer;\n  }\n\n  // usually, we round *up*, but if we fall right in between and and we have an\n  // even basis, we need to round down\n  // We are only concerned with the cases where 5**q fits in single 64-bit word.\n  if ((product.low <= 1) &&  (q >= binary::min_exponent_round_to_even()) && (q <= binary::max_exponent_round_to_even()) &&\n      ((answer.mantissa & 3) == 1) ) { // we may fall between two floats!\n    // To be in-between two floats we need that in doing\n    //   answer.mantissa = product.high >> (upperbit + 64 - binary::mantissa_explicit_bits() - 3);\n    // ... we dropped out only zeroes. But if this happened, then we can go back!!!\n    if((answer.mantissa  << (upperbit + 64 - binary::mantissa_explicit_bits() - 3)) ==  product.high) {\n      answer.mantissa &= ~uint64_t(1);          // flip it so that we do not round up\n    }\n  }\n\n  answer.mantissa += (answer.mantissa & 1); // round up\n  answer.mantissa >>= 1;\n  if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) {\n    answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits());\n    answer.power2++; // undo previous addition\n  }\n\n  answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits());\n  if (answer.power2 >= binary::infinite_power()) { // infinity\n    answer.power2 = binary::infinite_power();\n    answer.mantissa = 0;\n  }\n  return answer;\n}\n\n} // namespace fast_float\n\n#endif\n\n#ifndef FASTFLOAT_BIGINT_H\n#define FASTFLOAT_BIGINT_H\n\n#include <algorithm>\n#include <cstdint>\n#include <climits>\n#include <cstring>\n\n\nnamespace fast_float {\n\n// the limb width: we want efficient multiplication of double the bits in\n// limb, or for 64-bit limbs, at least 64-bit multiplication where we can\n// extract the high and low parts efficiently. this is every 64-bit\n// architecture except for sparc, which emulates 128-bit multiplication.\n// we might have platforms where `CHAR_BIT` is not 8, so let's avoid\n// doing `8 * sizeof(limb)`.\n#if defined(FASTFLOAT_64BIT) && !defined(__sparc)\n#define FASTFLOAT_64BIT_LIMB\ntypedef uint64_t limb;\nconstexpr size_t limb_bits = 64;\n#else\n#define FASTFLOAT_32BIT_LIMB\ntypedef uint32_t limb;\nconstexpr size_t limb_bits = 32;\n#endif\n\ntypedef span<limb> limb_span;\n\n// number of bits in a bigint. this needs to be at least the number\n// of bits required to store the largest bigint, which is\n// `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or\n// ~3600 bits, so we round to 4000.\nconstexpr size_t bigint_bits = 4000;\nconstexpr size_t bigint_limbs = bigint_bits / limb_bits;\n\n// vector-like type that is allocated on the stack. the entire\n// buffer is pre-allocated, and only the length changes.\ntemplate <uint16_t size>\nstruct stackvec {\n  limb data[size];\n  // we never need more than 150 limbs\n  uint16_t length{0};\n\n  stackvec() = default;\n  stackvec(const stackvec &) = delete;\n  stackvec &operator=(const stackvec &) = delete;\n  stackvec(stackvec &&) = delete;\n  stackvec &operator=(stackvec &&other) = delete;\n\n  // create stack vector from existing limb span.\n  stackvec(limb_span s) {\n    FASTFLOAT_ASSERT(try_extend(s));\n  }\n\n  limb& operator[](size_t index) noexcept {\n    FASTFLOAT_DEBUG_ASSERT(index < length);\n    return data[index];\n  }\n  const limb& operator[](size_t index) const noexcept {\n    FASTFLOAT_DEBUG_ASSERT(index < length);\n    return data[index];\n  }\n  // index from the end of the container\n  const limb& rindex(size_t index) const noexcept {\n    FASTFLOAT_DEBUG_ASSERT(index < length);\n    size_t rindex = length - index - 1;\n    return data[rindex];\n  }\n\n  // set the length, without bounds checking.\n  void set_len(size_t len) noexcept {\n    length = uint16_t(len);\n  }\n  constexpr size_t len() const noexcept {\n    return length;\n  }\n  constexpr bool is_empty() const noexcept {\n    return length == 0;\n  }\n  constexpr size_t capacity() const noexcept {\n    return size;\n  }\n  // append item to vector, without bounds checking\n  void push_unchecked(limb value) noexcept {\n    data[length] = value;\n    length++;\n  }\n  // append item to vector, returning if item was added\n  bool try_push(limb value) noexcept {\n    if (len() < capacity()) {\n      push_unchecked(value);\n      return true;\n    } else {\n      return false;\n    }\n  }\n  // add items to the vector, from a span, without bounds checking\n  void extend_unchecked(limb_span s) noexcept {\n    limb* ptr = data + length;\n    ::memcpy((void*)ptr, (const void*)s.ptr, sizeof(limb) * s.len());\n    set_len(len() + s.len());\n  }\n  // try to add items to the vector, returning if items were added\n  bool try_extend(limb_span s) noexcept {\n    if (len() + s.len() <= capacity()) {\n      extend_unchecked(s);\n      return true;\n    } else {\n      return false;\n    }\n  }\n  // resize the vector, without bounds checking\n  // if the new size is longer than the vector, assign value to each\n  // appended item.\n  void resize_unchecked(size_t new_len, limb value) noexcept {\n    if (new_len > len()) {\n      size_t count = new_len - len();\n      limb* first = data + len();\n      limb* last = first + count;\n      ::std::fill(first, last, value);\n      set_len(new_len);\n    } else {\n      set_len(new_len);\n    }\n  }\n  // try to resize the vector, returning if the vector was resized.\n  bool try_resize(size_t new_len, limb value) noexcept {\n    if (new_len > capacity()) {\n      return false;\n    } else {\n      resize_unchecked(new_len, value);\n      return true;\n    }\n  }\n  // check if any limbs are non-zero after the given index.\n  // this needs to be done in reverse order, since the index\n  // is relative to the most significant limbs.\n  bool nonzero(size_t index) const noexcept {\n    while (index < len()) {\n      if (rindex(index) != 0) {\n        return true;\n      }\n      index++;\n    }\n    return false;\n  }\n  // normalize the big integer, so most-significant zero limbs are removed.\n  void normalize() noexcept {\n    while (len() > 0 && rindex(0) == 0) {\n      length--;\n    }\n  }\n};\n\nfastfloat_really_inline\nuint64_t empty_hi64(bool& truncated) noexcept {\n  truncated = false;\n  return 0;\n}\n\nfastfloat_really_inline\nuint64_t uint64_hi64(uint64_t r0, bool& truncated) noexcept {\n  truncated = false;\n  int shl = leading_zeroes(r0);\n  return r0 << shl;\n}\n\nfastfloat_really_inline\nuint64_t uint64_hi64(uint64_t r0, uint64_t r1, bool& truncated) noexcept {\n  int shl = leading_zeroes(r0);\n  if (shl == 0) {\n    truncated = r1 != 0;\n    return r0;\n  } else {\n    int shr = 64 - shl;\n    truncated = (r1 << shl) != 0;\n    return (r0 << shl) | (r1 >> shr);\n  }\n}\n\nfastfloat_really_inline\nuint64_t uint32_hi64(uint32_t r0, bool& truncated) noexcept {\n  return uint64_hi64(r0, truncated);\n}\n\nfastfloat_really_inline\nuint64_t uint32_hi64(uint32_t r0, uint32_t r1, bool& truncated) noexcept {\n  uint64_t x0 = r0;\n  uint64_t x1 = r1;\n  return uint64_hi64((x0 << 32) | x1, truncated);\n}\n\nfastfloat_really_inline\nuint64_t uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool& truncated) noexcept {\n  uint64_t x0 = r0;\n  uint64_t x1 = r1;\n  uint64_t x2 = r2;\n  return uint64_hi64(x0, (x1 << 32) | x2, truncated);\n}\n\n// add two small integers, checking for overflow.\n// we want an efficient operation. for msvc, where\n// we don't have built-in intrinsics, this is still\n// pretty fast.\nfastfloat_really_inline\nlimb scalar_add(limb x, limb y, bool& overflow) noexcept {\n  limb z;\n\n// gcc and clang\n#if defined(__has_builtin)\n  #if __has_builtin(__builtin_add_overflow)\n    overflow = __builtin_add_overflow(x, y, &z);\n    return z;\n  #endif\n#endif\n\n  // generic, this still optimizes correctly on MSVC.\n  z = x + y;\n  overflow = z < x;\n  return z;\n}\n\n// multiply two small integers, getting both the high and low bits.\nfastfloat_really_inline\nlimb scalar_mul(limb x, limb y, limb& carry) noexcept {\n#ifdef FASTFLOAT_64BIT_LIMB\n  #if defined(__SIZEOF_INT128__)\n  // GCC and clang both define it as an extension.\n  __uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry);\n  carry = limb(z >> limb_bits);\n  return limb(z);\n  #else\n  // fallback, no native 128-bit integer multiplication with carry.\n  // on msvc, this optimizes identically, somehow.\n  value128 z = full_multiplication(x, y);\n  bool overflow;\n  z.low = scalar_add(z.low, carry, overflow);\n  z.high += uint64_t(overflow);  // cannot overflow\n  carry = z.high;\n  return z.low;\n  #endif\n#else\n  uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry);\n  carry = limb(z >> limb_bits);\n  return limb(z);\n#endif\n}\n\n// add scalar value to bigint starting from offset.\n// used in grade school multiplication\ntemplate <uint16_t size>\ninline bool small_add_from(stackvec<size>& vec, limb y, size_t start) noexcept {\n  size_t index = start;\n  limb carry = y;\n  bool overflow;\n  while (carry != 0 && index < vec.len()) {\n    vec[index] = scalar_add(vec[index], carry, overflow);\n    carry = limb(overflow);\n    index += 1;\n  }\n  if (carry != 0) {\n    FASTFLOAT_TRY(vec.try_push(carry));\n  }\n  return true;\n}\n\n// add scalar value to bigint.\ntemplate <uint16_t size>\nfastfloat_really_inline bool small_add(stackvec<size>& vec, limb y) noexcept {\n  return small_add_from(vec, y, 0);\n}\n\n// multiply bigint by scalar value.\ntemplate <uint16_t size>\ninline bool small_mul(stackvec<size>& vec, limb y) noexcept {\n  limb carry = 0;\n  for (size_t index = 0; index < vec.len(); index++) {\n    vec[index] = scalar_mul(vec[index], y, carry);\n  }\n  if (carry != 0) {\n    FASTFLOAT_TRY(vec.try_push(carry));\n  }\n  return true;\n}\n\n// add bigint to bigint starting from index.\n// used in grade school multiplication\ntemplate <uint16_t size>\nbool large_add_from(stackvec<size>& x, limb_span y, size_t start) noexcept {\n  // the effective x buffer is from `xstart..x.len()`, so exit early\n  // if we can't get that current range.\n  if (x.len() < start || y.len() > x.len() - start) {\n      FASTFLOAT_TRY(x.try_resize(y.len() + start, 0));\n  }\n\n  bool carry = false;\n  for (size_t index = 0; index < y.len(); index++) {\n    limb xi = x[index + start];\n    limb yi = y[index];\n    bool c1 = false;\n    bool c2 = false;\n    xi = scalar_add(xi, yi, c1);\n    if (carry) {\n      xi = scalar_add(xi, 1, c2);\n    }\n    x[index + start] = xi;\n    carry = c1 | c2;\n  }\n\n  // handle overflow\n  if (carry) {\n    FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start));\n  }\n  return true;\n}\n\n// add bigint to bigint.\ntemplate <uint16_t size>\nfastfloat_really_inline bool large_add_from(stackvec<size>& x, limb_span y) noexcept {\n  return large_add_from(x, y, 0);\n}\n\n// grade-school multiplication algorithm\ntemplate <uint16_t size>\nbool long_mul(stackvec<size>& x, limb_span y) noexcept {\n  limb_span xs = limb_span(x.data, x.len());\n  stackvec<size> z(xs);\n  limb_span zs = limb_span(z.data, z.len());\n\n  if (y.len() != 0) {\n    limb y0 = y[0];\n    FASTFLOAT_TRY(small_mul(x, y0));\n    for (size_t index = 1; index < y.len(); index++) {\n      limb yi = y[index];\n      stackvec<size> zi;\n      if (yi != 0) {\n        // re-use the same buffer throughout\n        zi.set_len(0);\n        FASTFLOAT_TRY(zi.try_extend(zs));\n        FASTFLOAT_TRY(small_mul(zi, yi));\n        limb_span zis = limb_span(zi.data, zi.len());\n        FASTFLOAT_TRY(large_add_from(x, zis, index));\n      }\n    }\n  }\n\n  x.normalize();\n  return true;\n}\n\n// grade-school multiplication algorithm\ntemplate <uint16_t size>\nbool large_mul(stackvec<size>& x, limb_span y) noexcept {\n  if (y.len() == 1) {\n    FASTFLOAT_TRY(small_mul(x, y[0]));\n  } else {\n    FASTFLOAT_TRY(long_mul(x, y));\n  }\n  return true;\n}\n\n// big integer type. implements a small subset of big integer\n// arithmetic, using simple algorithms since asymptotically\n// faster algorithms are slower for a small number of limbs.\n// all operations assume the big-integer is normalized.\nstruct bigint {\n  // storage of the limbs, in little-endian order.\n  stackvec<bigint_limbs> vec;\n\n  bigint(): vec() {}\n  bigint(const bigint &) = delete;\n  bigint &operator=(const bigint &) = delete;\n  bigint(bigint &&) = delete;\n  bigint &operator=(bigint &&other) = delete;\n\n  bigint(uint64_t value): vec() {\n#ifdef FASTFLOAT_64BIT_LIMB\n    vec.push_unchecked(value);\n#else\n    vec.push_unchecked(uint32_t(value));\n    vec.push_unchecked(uint32_t(value >> 32));\n#endif\n    vec.normalize();\n  }\n\n  // get the high 64 bits from the vector, and if bits were truncated.\n  // this is to get the significant digits for the float.\n  uint64_t hi64(bool& truncated) const noexcept {\n#ifdef FASTFLOAT_64BIT_LIMB\n    if (vec.len() == 0) {\n      return empty_hi64(truncated);\n    } else if (vec.len() == 1) {\n      return uint64_hi64(vec.rindex(0), truncated);\n    } else {\n      uint64_t result = uint64_hi64(vec.rindex(0), vec.rindex(1), truncated);\n      truncated |= vec.nonzero(2);\n      return result;\n    }\n#else\n    if (vec.len() == 0) {\n      return empty_hi64(truncated);\n    } else if (vec.len() == 1) {\n      return uint32_hi64(vec.rindex(0), truncated);\n    } else if (vec.len() == 2) {\n      return uint32_hi64(vec.rindex(0), vec.rindex(1), truncated);\n    } else {\n      uint64_t result = uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated);\n      truncated |= vec.nonzero(3);\n      return result;\n    }\n#endif\n  }\n\n  // compare two big integers, returning the large value.\n  // assumes both are normalized. if the return value is\n  // negative, other is larger, if the return value is\n  // positive, this is larger, otherwise they are equal.\n  // the limbs are stored in little-endian order, so we\n  // must compare the limbs in ever order.\n  int compare(const bigint& other) const noexcept {\n    if (vec.len() > other.vec.len()) {\n      return 1;\n    } else if (vec.len() < other.vec.len()) {\n      return -1;\n    } else {\n      for (size_t index = vec.len(); index > 0; index--) {\n        limb xi = vec[index - 1];\n        limb yi = other.vec[index - 1];\n        if (xi > yi) {\n          return 1;\n        } else if (xi < yi) {\n          return -1;\n        }\n      }\n      return 0;\n    }\n  }\n\n  // shift left each limb n bits, carrying over to the new limb\n  // returns true if we were able to shift all the digits.\n  bool shl_bits(size_t n) noexcept {\n    // Internally, for each item, we shift left by n, and add the previous\n    // right shifted limb-bits.\n    // For example, we transform (for u8) shifted left 2, to:\n    //      b10100100 b01000010\n    //      b10 b10010001 b00001000\n    FASTFLOAT_DEBUG_ASSERT(n != 0);\n    FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8);\n\n    size_t shl = n;\n    size_t shr = limb_bits - shl;\n    limb prev = 0;\n    for (size_t index = 0; index < vec.len(); index++) {\n      limb xi = vec[index];\n      vec[index] = (xi << shl) | (prev >> shr);\n      prev = xi;\n    }\n\n    limb carry = prev >> shr;\n    if (carry != 0) {\n      return vec.try_push(carry);\n    }\n    return true;\n  }\n\n  // move the limbs left by `n` limbs.\n  bool shl_limbs(size_t n) noexcept {\n    FASTFLOAT_DEBUG_ASSERT(n != 0);\n    if (n + vec.len() > vec.capacity()) {\n      return false;\n    } else if (!vec.is_empty()) {\n      // move limbs\n      limb* dst = vec.data + n;\n      const limb* src = vec.data;\n      ::memmove(dst, src, sizeof(limb) * vec.len());\n      // fill in empty limbs\n      limb* first = vec.data;\n      limb* last = first + n;\n      ::std::fill(first, last, 0);\n      vec.set_len(n + vec.len());\n      return true;\n    } else {\n      return true;\n    }\n  }\n\n  // move the limbs left by `n` bits.\n  bool shl(size_t n) noexcept {\n    size_t rem = n % limb_bits;\n    size_t div = n / limb_bits;\n    if (rem != 0) {\n      FASTFLOAT_TRY(shl_bits(rem));\n    }\n    if (div != 0) {\n      FASTFLOAT_TRY(shl_limbs(div));\n    }\n    return true;\n  }\n\n  // get the number of leading zeros in the bigint.\n  int ctlz() const noexcept {\n    if (vec.is_empty()) {\n      return 0;\n    } else {\n#ifdef FASTFLOAT_64BIT_LIMB\n      return leading_zeroes(vec.rindex(0));\n#else\n      // no use defining a specialized leading_zeroes for a 32-bit type.\n      uint64_t r0 = vec.rindex(0);\n      return leading_zeroes(r0 << 32);\n#endif\n    }\n  }\n\n  // get the number of bits in the bigint.\n  int bit_length() const noexcept {\n    int lz = ctlz();\n    return int(limb_bits * vec.len()) - lz;\n  }\n\n  bool mul(limb y) noexcept {\n    return small_mul(vec, y);\n  }\n\n  bool add(limb y) noexcept {\n    return small_add(vec, y);\n  }\n\n  // multiply as if by 2 raised to a power.\n  bool pow2(uint32_t exp) noexcept {\n    return shl(exp);\n  }\n\n  // multiply as if by 5 raised to a power.\n  bool pow5(uint32_t exp) noexcept {\n    // multiply by a power of 5\n    static constexpr uint32_t large_step = 135;\n    static constexpr uint64_t small_power_of_5[] = {\n      1UL, 5UL, 25UL, 125UL, 625UL, 3125UL, 15625UL, 78125UL, 390625UL,\n      1953125UL, 9765625UL, 48828125UL, 244140625UL, 1220703125UL,\n      6103515625UL, 30517578125UL, 152587890625UL, 762939453125UL,\n      3814697265625UL, 19073486328125UL, 95367431640625UL, 476837158203125UL,\n      2384185791015625UL, 11920928955078125UL, 59604644775390625UL,\n      298023223876953125UL, 1490116119384765625UL, 7450580596923828125UL,\n    };\n#ifdef FASTFLOAT_64BIT_LIMB\n    constexpr static limb large_power_of_5[] = {\n      1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL,\n      10482974169319127550UL, 198276706040285095UL};\n#else\n    constexpr static limb large_power_of_5[] = {\n      4279965485U, 329373468U, 4020270615U, 2137533757U, 4287402176U,\n      1057042919U, 1071430142U, 2440757623U, 381945767U, 46164893U};\n#endif\n    size_t large_length = sizeof(large_power_of_5) / sizeof(limb);\n    limb_span large = limb_span(large_power_of_5, large_length);\n    while (exp >= large_step) {\n      FASTFLOAT_TRY(large_mul(vec, large));\n      exp -= large_step;\n    }\n#ifdef FASTFLOAT_64BIT_LIMB\n    uint32_t small_step = 27;\n    limb max_native = 7450580596923828125UL;\n#else\n    uint32_t small_step = 13;\n    limb max_native = 1220703125U;\n#endif\n    while (exp >= small_step) {\n      FASTFLOAT_TRY(small_mul(vec, max_native));\n      exp -= small_step;\n    }\n    if (exp != 0) {\n      FASTFLOAT_TRY(small_mul(vec, limb(small_power_of_5[exp])));\n    }\n\n    return true;\n  }\n\n  // multiply as if by 10 raised to a power.\n  bool pow10(uint32_t exp) noexcept {\n    FASTFLOAT_TRY(pow5(exp));\n    return pow2(exp);\n  }\n};\n\n} // namespace fast_float\n\n#endif\n\n#ifndef FASTFLOAT_ASCII_NUMBER_H\n#define FASTFLOAT_ASCII_NUMBER_H\n\n#include <cctype>\n#include <cstdint>\n#include <cstring>\n#include <iterator>\n\n\nnamespace fast_float {\n\n// Next function can be micro-optimized, but compilers are entirely\n// able to optimize it well.\nfastfloat_really_inline bool is_integer(char c)  noexcept  { return c >= '0' && c <= '9'; }\n\nfastfloat_really_inline uint64_t byteswap(uint64_t val) {\n  return (val & 0xFF00000000000000) >> 56\n    | (val & 0x00FF000000000000) >> 40\n    | (val & 0x0000FF0000000000) >> 24\n    | (val & 0x000000FF00000000) >> 8\n    | (val & 0x00000000FF000000) << 8\n    | (val & 0x0000000000FF0000) << 24\n    | (val & 0x000000000000FF00) << 40\n    | (val & 0x00000000000000FF) << 56;\n}\n\nfastfloat_really_inline uint64_t read_u64(const char *chars) {\n  uint64_t val;\n  ::memcpy(&val, chars, sizeof(uint64_t));\n#if FASTFLOAT_IS_BIG_ENDIAN == 1\n  // Need to read as-if the number was in little-endian order.\n  val = byteswap(val);\n#endif\n  return val;\n}\n\nfastfloat_really_inline void write_u64(uint8_t *chars, uint64_t val) {\n#if FASTFLOAT_IS_BIG_ENDIAN == 1\n  // Need to read as-if the number was in little-endian order.\n  val = byteswap(val);\n#endif\n  ::memcpy(chars, &val, sizeof(uint64_t));\n}\n\n// credit  @aqrit\nfastfloat_really_inline uint32_t  parse_eight_digits_unrolled(uint64_t val) {\n  const uint64_t mask = 0x000000FF000000FF;\n  const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)\n  const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)\n  val -= 0x3030303030303030;\n  val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;\n  val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;\n  return uint32_t(val);\n}\n\nfastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars)  noexcept  {\n  return parse_eight_digits_unrolled(read_u64(chars));\n}\n\n// credit @aqrit\nfastfloat_really_inline bool is_made_of_eight_digits_fast(uint64_t val)  noexcept  {\n  return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &\n     0x8080808080808080));\n}\n\nfastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars)  noexcept  {\n  return is_made_of_eight_digits_fast(read_u64(chars));\n}\n\ntypedef span<const char> byte_span;\n\nstruct parsed_number_string {\n  int64_t exponent{0};\n  uint64_t mantissa{0};\n  const char *lastmatch{nullptr};\n  bool negative{false};\n  bool valid{false};\n  bool too_many_digits{false};\n  // contains the range of the significant digits\n  byte_span integer{};  // non-nullable\n  byte_span fraction{}; // nullable\n};\n\n// Assuming that you use no more than 19 digits, this will\n// parse an ASCII string.\nfastfloat_really_inline\nparsed_number_string parse_number_string(const char *p, const char *pend, parse_options options) noexcept {\n  const chars_format fmt = options.format;\n  const char decimal_point = options.decimal_point;\n\n  parsed_number_string answer;\n  answer.valid = false;\n  answer.too_many_digits = false;\n  answer.negative = (*p == '-');\n  if (*p == '-') { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here\n    ++p;\n    if (p == pend) {\n      return answer;\n    }\n    if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot\n      return answer;\n    }\n  }\n  const char *const start_digits = p;\n\n  uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)\n\n  while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) {\n    i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok\n    p += 8;\n  }\n  while ((p != pend) && is_integer(*p)) {\n    // a multiplication by 10 is cheaper than an arbitrary integer\n    // multiplication\n    i = 10 * i +\n        uint64_t(*p - '0'); // might overflow, we will handle the overflow later\n    ++p;\n  }\n  const char *const end_of_integer_part = p;\n  int64_t digit_count = int64_t(end_of_integer_part - start_digits);\n  answer.integer = byte_span(start_digits, size_t(digit_count));\n  int64_t exponent = 0;\n  if ((p != pend) && (*p == decimal_point)) {\n    ++p;\n    const char* before = p;\n    // can occur at most twice without overflowing, but let it occur more, since\n    // for integers with many digits, digit parsing is the primary bottleneck.\n    while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) {\n      i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok\n      p += 8;\n    }\n    while ((p != pend) && is_integer(*p)) {\n      uint8_t digit = uint8_t(*p - '0');\n      ++p;\n      i = i * 10 + digit; // in rare cases, this will overflow, but that's ok\n    }\n    exponent = before - p;\n    answer.fraction = byte_span(before, size_t(p - before));\n    digit_count -= exponent;\n  }\n  // we must have encountered at least one integer!\n  if (digit_count == 0) {\n    return answer;\n  }\n  int64_t exp_number = 0;            // explicit exponential part\n  if ((fmt & chars_format::scientific) && (p != pend) && (('e' == *p) || ('E' == *p))) {\n    const char * location_of_e = p;\n    ++p;\n    bool neg_exp = false;\n    if ((p != pend) && ('-' == *p)) {\n      neg_exp = true;\n      ++p;\n    } else if ((p != pend) && ('+' == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)\n      ++p;\n    }\n    if ((p == pend) || !is_integer(*p)) {\n      if(!(fmt & chars_format::fixed)) {\n        // We are in error.\n        return answer;\n      }\n      // Otherwise, we will be ignoring the 'e'.\n      p = location_of_e;\n    } else {\n      while ((p != pend) && is_integer(*p)) {\n        uint8_t digit = uint8_t(*p - '0');\n        if (exp_number < 0x10000000) {\n          exp_number = 10 * exp_number + digit;\n        }\n        ++p;\n      }\n      if(neg_exp) { exp_number = - exp_number; }\n      exponent += exp_number;\n    }\n  } else {\n    // If it scientific and not fixed, we have to bail out.\n    if((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) { return answer; }\n  }\n  answer.lastmatch = p;\n  answer.valid = true;\n\n  // If we frequently had to deal with long strings of digits,\n  // we could extend our code by using a 128-bit integer instead\n  // of a 64-bit integer. However, this is uncommon.\n  //\n  // We can deal with up to 19 digits.\n  if (digit_count > 19) { // this is uncommon\n    // It is possible that the integer had an overflow.\n    // We have to handle the case where we have 0.0000somenumber.\n    // We need to be mindful of the case where we only have zeroes...\n    // E.g., 0.000000000...000.\n    const char *start = start_digits;\n    while ((start != pend) && (*start == '0' || *start == decimal_point)) {\n      if(*start == '0') { digit_count --; }\n      start++;\n    }\n    if (digit_count > 19) {\n      answer.too_many_digits = true;\n      // Let us start again, this time, avoiding overflows.\n      // We don't need to check if is_integer, since we use the\n      // pre-tokenized spans from above.\n      i = 0;\n      p = answer.integer.ptr;\n      const char* int_end = p + answer.integer.len();\n      const uint64_t minimal_nineteen_digit_integer{1000000000000000000};\n      while((i < minimal_nineteen_digit_integer) && (p != int_end)) {\n        i = i * 10 + uint64_t(*p - '0');\n        ++p;\n      }\n      if (i >= minimal_nineteen_digit_integer) { // We have a big integers\n        exponent = end_of_integer_part - p + exp_number;\n      } else { // We have a value with a fractional component.\n          p = answer.fraction.ptr;\n          const char* frac_end = p + answer.fraction.len();\n          while((i < minimal_nineteen_digit_integer) && (p != frac_end)) {\n            i = i * 10 + uint64_t(*p - '0');\n            ++p;\n          }\n          exponent = answer.fraction.ptr - p + exp_number;\n      }\n      // We have now corrected both exponent and i, to a truncated value\n    }\n  }\n  answer.exponent = exponent;\n  answer.mantissa = i;\n  return answer;\n}\n\n} // namespace fast_float\n\n#endif\n\n#ifndef FASTFLOAT_DIGIT_COMPARISON_H\n#define FASTFLOAT_DIGIT_COMPARISON_H\n\n#include <algorithm>\n#include <cstdint>\n#include <cstring>\n#include <iterator>\n\n\nnamespace fast_float {\n\n// 1e0 to 1e19\nconstexpr static uint64_t powers_of_ten_uint64[] = {\n    1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL,\n    1000000000UL, 10000000000UL, 100000000000UL, 1000000000000UL, 10000000000000UL,\n    100000000000000UL, 1000000000000000UL, 10000000000000000UL, 100000000000000000UL,\n    1000000000000000000UL, 10000000000000000000UL};\n\n// calculate the exponent, in scientific notation, of the number.\n// this algorithm is not even close to optimized, but it has no practical\n// effect on performance: in order to have a faster algorithm, we'd need\n// to slow down performance for faster algorithms, and this is still fast.\nfastfloat_really_inline int32_t scientific_exponent(parsed_number_string& num) noexcept {\n  uint64_t mantissa = num.mantissa;\n  int32_t exponent = int32_t(num.exponent);\n  while (mantissa >= 10000) {\n    mantissa /= 10000;\n    exponent += 4;\n  }\n  while (mantissa >= 100) {\n    mantissa /= 100;\n    exponent += 2;\n  }\n  while (mantissa >= 10) {\n    mantissa /= 10;\n    exponent += 1;\n  }\n  return exponent;\n}\n\n// this converts a native floating-point number to an extended-precision float.\ntemplate <typename T>\nfastfloat_really_inline adjusted_mantissa to_extended(T value) noexcept {\n  using equiv_uint = typename binary_format<T>::equiv_uint;\n  constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();\n  constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask();\n  constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask();\n\n  adjusted_mantissa am;\n  int32_t bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();\n  equiv_uint bits;\n  ::memcpy(&bits, &value, sizeof(T));\n  if ((bits & exponent_mask) == 0) {\n    // denormal\n    am.power2 = 1 - bias;\n    am.mantissa = bits & mantissa_mask;\n  } else {\n    // normal\n    am.power2 = int32_t((bits & exponent_mask) >> binary_format<T>::mantissa_explicit_bits());\n    am.power2 -= bias;\n    am.mantissa = (bits & mantissa_mask) | hidden_bit_mask;\n  }\n\n  return am;\n}\n\n// get the extended precision value of the halfway point between b and b+u.\n// we are given a native float that represents b, so we need to adjust it\n// halfway between b and b+u.\ntemplate <typename T>\nfastfloat_really_inline adjusted_mantissa to_extended_halfway(T value) noexcept {\n  adjusted_mantissa am = to_extended(value);\n  am.mantissa <<= 1;\n  am.mantissa += 1;\n  am.power2 -= 1;\n  return am;\n}\n\n// round an extended-precision float to the nearest machine float.\ntemplate <typename T, typename callback>\nfastfloat_really_inline void round(adjusted_mantissa& am, callback cb) noexcept {\n  int32_t mantissa_shift = 64 - binary_format<T>::mantissa_explicit_bits() - 1;\n  if (-am.power2 >= mantissa_shift) {\n    // have a denormal float\n    int32_t shift = -am.power2 + 1;\n    cb(am, std::min(shift, 64));\n    // check for round-up: if rounding-nearest carried us to the hidden bit.\n    am.power2 = (am.mantissa < (uint64_t(1) << binary_format<T>::mantissa_explicit_bits())) ? 0 : 1;\n    return;\n  }\n\n  // have a normal float, use the default shift.\n  cb(am, mantissa_shift);\n\n  // check for carry\n  if (am.mantissa >= (uint64_t(2) << binary_format<T>::mantissa_explicit_bits())) {\n    am.mantissa = (uint64_t(1) << binary_format<T>::mantissa_explicit_bits());\n    am.power2++;\n  }\n\n  // check for infinite: we could have carried to an infinite power\n  am.mantissa &= ~(uint64_t(1) << binary_format<T>::mantissa_explicit_bits());\n  if (am.power2 >= binary_format<T>::infinite_power()) {\n    am.power2 = binary_format<T>::infinite_power();\n    am.mantissa = 0;\n  }\n}\n\ntemplate <typename callback>\nfastfloat_really_inline\nvoid round_nearest_tie_even(adjusted_mantissa& am, int32_t shift, callback cb) noexcept {\n  uint64_t mask;\n  uint64_t halfway;\n  if (shift == 64) {\n    mask = UINT64_MAX;\n  } else {\n    mask = (uint64_t(1) << shift) - 1;\n  }\n  if (shift == 0) {\n    halfway = 0;\n  } else {\n    halfway = uint64_t(1) << (shift - 1);\n  }\n  uint64_t truncated_bits = am.mantissa & mask;\n  uint64_t is_above = truncated_bits > halfway;\n  uint64_t is_halfway = truncated_bits == halfway;\n\n  // shift digits into position\n  if (shift == 64) {\n    am.mantissa = 0;\n  } else {\n    am.mantissa >>= shift;\n  }\n  am.power2 += shift;\n\n  bool is_odd = (am.mantissa & 1) == 1;\n  am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above));\n}\n\nfastfloat_really_inline void round_down(adjusted_mantissa& am, int32_t shift) noexcept {\n  if (shift == 64) {\n    am.mantissa = 0;\n  } else {\n    am.mantissa >>= shift;\n  }\n  am.power2 += shift;\n}\n\nfastfloat_really_inline void skip_zeros(const char*& first, const char* last) noexcept {\n  uint64_t val;\n  while (std::distance(first, last) >= 8) {\n    ::memcpy(&val, first, sizeof(uint64_t));\n    if (val != 0x3030303030303030) {\n      break;\n    }\n    first += 8;\n  }\n  while (first != last) {\n    if (*first != '0') {\n      break;\n    }\n    first++;\n  }\n}\n\n// determine if any non-zero digits were truncated.\n// all characters must be valid digits.\nfastfloat_really_inline bool is_truncated(const char* first, const char* last) noexcept {\n  // do 8-bit optimizations, can just compare to 8 literal 0s.\n  uint64_t val;\n  while (std::distance(first, last) >= 8) {\n    ::memcpy(&val, first, sizeof(uint64_t));\n    if (val != 0x3030303030303030) {\n      return true;\n    }\n    first += 8;\n  }\n  while (first != last) {\n    if (*first != '0') {\n      return true;\n    }\n    first++;\n  }\n  return false;\n}\n\nfastfloat_really_inline bool is_truncated(byte_span s) noexcept {\n  return is_truncated(s.ptr, s.ptr + s.len());\n}\n\nfastfloat_really_inline\nvoid parse_eight_digits(const char*& p, limb& value, size_t& counter, size_t& count) noexcept {\n  value = value * 100000000 + parse_eight_digits_unrolled(p);\n  p += 8;\n  counter += 8;\n  count += 8;\n}\n\nfastfloat_really_inline\nvoid parse_one_digit(const char*& p, limb& value, size_t& counter, size_t& count) noexcept {\n  value = value * 10 + limb(*p - '0');\n  p++;\n  counter++;\n  count++;\n}\n\nfastfloat_really_inline\nvoid add_native(bigint& big, limb power, limb value) noexcept {\n  big.mul(power);\n  big.add(value);\n}\n\nfastfloat_really_inline void round_up_bigint(bigint& big, size_t& count) noexcept {\n  // need to round-up the digits, but need to avoid rounding\n  // ....9999 to ...10000, which could cause a false halfway point.\n  add_native(big, 10, 1);\n  count++;\n}\n\n// parse the significant digits into a big integer\ninline void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits, size_t& digits) noexcept {\n  // try to minimize the number of big integer and scalar multiplication.\n  // therefore, try to parse 8 digits at a time, and multiply by the largest\n  // scalar value (9 or 19 digits) for each step.\n  size_t counter = 0;\n  digits = 0;\n  limb value = 0;\n#ifdef FASTFLOAT_64BIT_LIMB\n  size_t step = 19;\n#else\n  size_t step = 9;\n#endif\n\n  // process all integer digits.\n  const char* p = num.integer.ptr;\n  const char* pend = p + num.integer.len();\n  skip_zeros(p, pend);\n  // process all digits, in increments of step per loop\n  while (p != pend) {\n    while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {\n      parse_eight_digits(p, value, counter, digits);\n    }\n    while (counter < step && p != pend && digits < max_digits) {\n      parse_one_digit(p, value, counter, digits);\n    }\n    if (digits == max_digits) {\n      // add the temporary value, then check if we've truncated any digits\n      add_native(result, limb(powers_of_ten_uint64[counter]), value);\n      bool truncated = is_truncated(p, pend);\n      if (num.fraction.ptr != nullptr) {\n        truncated |= is_truncated(num.fraction);\n      }\n      if (truncated) {\n        round_up_bigint(result, digits);\n      }\n      return;\n    } else {\n      add_native(result, limb(powers_of_ten_uint64[counter]), value);\n      counter = 0;\n      value = 0;\n    }\n  }\n\n  // add our fraction digits, if they're available.\n  if (num.fraction.ptr != nullptr) {\n    p = num.fraction.ptr;\n    pend = p + num.fraction.len();\n    if (digits == 0) {\n      skip_zeros(p, pend);\n    }\n    // process all digits, in increments of step per loop\n    while (p != pend) {\n      while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {\n        parse_eight_digits(p, value, counter, digits);\n      }\n      while (counter < step && p != pend && digits < max_digits) {\n        parse_one_digit(p, value, counter, digits);\n      }\n      if (digits == max_digits) {\n        // add the temporary value, then check if we've truncated any digits\n        add_native(result, limb(powers_of_ten_uint64[counter]), value);\n        bool truncated = is_truncated(p, pend);\n        if (truncated) {\n          round_up_bigint(result, digits);\n        }\n        return;\n      } else {\n        add_native(result, limb(powers_of_ten_uint64[counter]), value);\n        counter = 0;\n        value = 0;\n      }\n    }\n  }\n\n  if (counter != 0) {\n    add_native(result, limb(powers_of_ten_uint64[counter]), value);\n  }\n}\n\ntemplate <typename T>\ninline adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcept {\n  FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent)));\n  adjusted_mantissa answer;\n  bool truncated;\n  answer.mantissa = bigmant.hi64(truncated);\n  int bias = binary_format<T>::mantissa_explicit_bits() - binary_format<T>::minimum_exponent();\n  answer.power2 = bigmant.bit_length() - 64 + bias;\n\n  round<T>(answer, [truncated](adjusted_mantissa& a, int32_t shift) {\n    round_nearest_tie_even(a, shift, [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool {\n      return is_above || (is_halfway && truncated) || (is_odd && is_halfway);\n    });\n  });\n\n  return answer;\n}\n\n// the scaling here is quite simple: we have, for the real digits `m * 10^e`,\n// and for the theoretical digits `n * 2^f`. Since `e` is always negative,\n// to scale them identically, we do `n * 2^f * 5^-f`, so we now have `m * 2^e`.\n// we then need to scale by `2^(f- e)`, and then the two significant digits\n// are of the same magnitude.\ntemplate <typename T>\ninline adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int32_t exponent) noexcept {\n  bigint& real_digits = bigmant;\n  int32_t real_exp = exponent;\n\n  // get the value of `b`, rounded down, and get a bigint representation of b+h\n  adjusted_mantissa am_b = am;\n  // gcc7 buf: use a lambda to remove the noexcept qualifier bug with -Wnoexcept-type.\n  round<T>(am_b, [](adjusted_mantissa&a, int32_t shift) { round_down(a, shift); });\n  T b;\n  to_float(false, am_b, b);\n  adjusted_mantissa theor = to_extended_halfway(b);\n  bigint theor_digits(theor.mantissa);\n  int32_t theor_exp = theor.power2;\n\n  // scale real digits and theor digits to be same power.\n  int32_t pow2_exp = theor_exp - real_exp;\n  uint32_t pow5_exp = uint32_t(-real_exp);\n  if (pow5_exp != 0) {\n    FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp));\n  }\n  if (pow2_exp > 0) {\n    FASTFLOAT_ASSERT(theor_digits.pow2(uint32_t(pow2_exp)));\n  } else if (pow2_exp < 0) {\n    FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp)));\n  }\n\n  // compare digits, and use it to director rounding\n  int ord = real_digits.compare(theor_digits);\n  adjusted_mantissa answer = am;\n  round<T>(answer, [ord](adjusted_mantissa& a, int32_t shift) {\n    round_nearest_tie_even(a, shift, [ord](bool is_odd, bool _, bool __) -> bool {\n      (void)_;  // not needed, since we've done our comparison\n      (void)__; // not needed, since we've done our comparison\n      if (ord > 0) {\n        return true;\n      } else if (ord < 0) {\n        return false;\n      } else {\n        return is_odd;\n      }\n    });\n  });\n\n  return answer;\n}\n\n// parse the significant digits as a big integer to unambiguously round the\n// the significant digits. here, we are trying to determine how to round\n// an extended float representation close to `b+h`, halfway between `b`\n// (the float rounded-down) and `b+u`, the next positive float. this\n// algorithm is always correct, and uses one of two approaches. when\n// the exponent is positive relative to the significant digits (such as\n// 1234), we create a big-integer representation, get the high 64-bits,\n// determine if any lower bits are truncated, and use that to direct\n// rounding. in case of a negative exponent relative to the significant\n// digits (such as 1.2345), we create a theoretical representation of\n// `b` as a big-integer type, scaled to the same binary exponent as\n// the actual digits. we then compare the big integer representations\n// of both, and use that to direct rounding.\ntemplate <typename T>\ninline adjusted_mantissa digit_comp(parsed_number_string& num, adjusted_mantissa am) noexcept {\n  // remove the invalid exponent bias\n  am.power2 -= invalid_am_bias;\n\n  int32_t sci_exp = scientific_exponent(num);\n  size_t max_digits = binary_format<T>::max_digits();\n  size_t digits = 0;\n  bigint bigmant;\n  parse_mantissa(bigmant, num, max_digits, digits);\n  // can't underflow, since digits is at most max_digits.\n  int32_t exponent = sci_exp + 1 - int32_t(digits);\n  if (exponent >= 0) {\n    return positive_digit_comp<T>(bigmant, exponent);\n  } else {\n    return negative_digit_comp<T>(bigmant, am, exponent);\n  }\n}\n\n} // namespace fast_float\n\n#endif\n\n#ifndef FASTFLOAT_PARSE_NUMBER_H\n#define FASTFLOAT_PARSE_NUMBER_H\n\n\n#include <cmath>\n#include <cstring>\n#include <limits>\n#include <system_error>\n\nnamespace fast_float {\n\n\nnamespace detail {\n/**\n * Special case +inf, -inf, nan, infinity, -infinity.\n * The case comparisons could be made much faster given that we know that the\n * strings a null-free and fixed.\n **/\ntemplate <typename T>\nfrom_chars_result parse_infnan(const char *first, const char *last, T &value)  noexcept  {\n  from_chars_result answer;\n  answer.ptr = first;\n  answer.ec = std::errc(); // be optimistic\n  bool minusSign = false;\n  if (*first == '-') { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here\n      minusSign = true;\n      ++first;\n  }\n  if (last - first >= 3) {\n    if (fastfloat_strncasecmp(first, \"nan\", 3)) {\n      answer.ptr = (first += 3);\n      value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::quiet_NaN();\n      // Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).\n      if(first != last && *first == '(') {\n        for(const char* ptr = first + 1; ptr != last; ++ptr) {\n          if (*ptr == ')') {\n            answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)\n            break;\n          }\n          else if(!(('a' <= *ptr && *ptr <= 'z') || ('A' <= *ptr && *ptr <= 'Z') || ('0' <= *ptr && *ptr <= '9') || *ptr == '_'))\n            break; // forbidden char, not nan(n-char-seq-opt)\n        }\n      }\n      return answer;\n    }\n    if (fastfloat_strncasecmp(first, \"inf\", 3)) {\n      if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, \"inity\", 5)) {\n        answer.ptr = first + 8;\n      } else {\n        answer.ptr = first + 3;\n      }\n      value = minusSign ? -std::numeric_limits<T>::infinity() : std::numeric_limits<T>::infinity();\n      return answer;\n    }\n  }\n  answer.ec = std::errc::invalid_argument;\n  return answer;\n}\n\n} // namespace detail\n\ntemplate<typename T>\nfrom_chars_result from_chars(const char *first, const char *last,\n                             T &value, chars_format fmt /*= chars_format::general*/)  noexcept  {\n  return from_chars_advanced(first, last, value, parse_options{fmt});\n}\n\ntemplate<typename T>\nfrom_chars_result from_chars_advanced(const char *first, const char *last,\n                                      T &value, parse_options options)  noexcept  {\n\n  static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, \"only float and double are supported\");\n\n\n  from_chars_result answer;\n  if (first == last) {\n    answer.ec = std::errc::invalid_argument;\n    answer.ptr = first;\n    return answer;\n  }\n  parsed_number_string pns = parse_number_string(first, last, options);\n  if (!pns.valid) {\n    return detail::parse_infnan(first, last, value);\n  }\n  answer.ec = std::errc(); // be optimistic\n  answer.ptr = pns.lastmatch;\n  // Next is Clinger's fast path.\n  if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && pns.mantissa <=binary_format<T>::max_mantissa_fast_path() && !pns.too_many_digits) {\n    value = T(pns.mantissa);\n    if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); }\n    else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); }\n    if (pns.negative) { value = -value; }\n    return answer;\n  }\n  adjusted_mantissa am = compute_float<binary_format<T>>(pns.exponent, pns.mantissa);\n  if(pns.too_many_digits && am.power2 >= 0) {\n    if(am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {\n      am = compute_error<binary_format<T>>(pns.exponent, pns.mantissa);\n    }\n  }\n  // If we called compute_float<binary_format<T>>(pns.exponent, pns.mantissa) and we have an invalid power (am.power2 < 0),\n  // then we need to go the long way around again. This is very uncommon.\n  if(am.power2 < 0) { am = digit_comp<T>(pns, am); }\n  to_float(pns.negative, am, value);\n  return answer;\n}\n\n} // namespace fast_float\n\n#endif\n\n\n"
  },
  {
    "path": "src/Common/unix/platform.cpp",
    "content": "#include <cstdint>\n#include <ctime>\n\nuint32_t GetTickCount()\n{\n#if BOOST_OS_LINUX\n\tstruct timespec ts;\n\tclock_gettime(CLOCK_MONOTONIC_RAW, &ts);\n\treturn (1000 * ts.tv_sec + ts.tv_nsec / 1000000);\n#elif BOOST_OS_MACOS\n\treturn clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW) / 1000000;\n#elif BOOST_OS_BSD\n\tstruct timespec ts;\n\tclock_gettime(CLOCK_MONOTONIC, &ts);\n\treturn (1000 * ts.tv_sec + ts.tv_nsec / 1000000);\n#endif\n\n}\n"
  },
  {
    "path": "src/Common/unix/platform.h",
    "content": "#include <shared_mutex>\n\nclass SlimRWLock\n{\npublic:\n\tvoid LockRead()\n\t{\n\t\tm_sm.lock_shared();\n\t}\n\n\tvoid UnlockRead()\n\t{\n\t\tm_sm.unlock_shared();\n\t}\n\n\tvoid LockWrite()\n\t{\n\t\tm_sm.lock();\n\t}\n\n\tvoid UnlockWrite()\n\t{\n\t\tm_sm.unlock();\n\t}\n\nprivate:\n\tstd::shared_mutex m_sm;\n};\n\ninline uint32_t GetExceptionError() \n{\n    return errno;\n}\n\n#undef False\n#undef True\n#undef None\n#undef Bool\n#undef Status\n#undef Success\n#undef ClientMessage\n\n// placeholder\nuint32_t GetTickCount();\n\n// strcpy_s and strcat_s implementations\ntemplate<size_t N> \nvoid strcpy_s(char (&dst)[N], const char* src)  \n{\n\tif(N == 0)\n\t\treturn;\n\tchar* dstP = dst;\n\tconst char* end = src + N - 1;\n\twhile(src < end)\n\t{\n\t\tchar c = *src;\n\t\t*dstP = c;\n\t\tif(c == '\\0')\n\t\t\treturn;\n\t\tdstP++;\n\t\tsrc++;\n\t\tc++;\n\t}\n\t*dstP = '\\0';\n\treturn;\n}\n\ntemplate<size_t N> \nvoid strcat_s(char (&dst)[N], const char* src)  \n{\n\tif(N == 0)\n\t\treturn;\n\tchar* dstP = dst;\n\tconst char* end = dstP + N - 1;\n\twhile(dstP < end && *dstP != '\\0')\n\t\tdstP++;\n\twhile(dstP < end)\n\t{\n\t\tchar c = *src;\n\t\t*dstP = c;\n\t\tif(c == '\\0')\n\t\t\treturn;\n\t\tdstP++;\n\t\tsrc++;\n\t\tc++;\n\t}\n\t*dstP = '\\0';\n\treturn;\n}\n"
  },
  {
    "path": "src/Common/version.h",
    "content": "#ifndef EMULATOR_NAME\n\n#define EMULATOR_NAME\t\t\t\t\t\"Cemu\"\n\n#define EMULATOR_VERSION_SUFFIX\t\t\t\"\"\n\n#define _XSTRINGFY(s) _STRINGFY(s)\n#define _STRINGFY(s) #s\n\n#if EMULATOR_VERSION_MAJOR != 0\n#define BUILD_VERSION_WITH_NAME_STRING (EMULATOR_NAME \" \" _XSTRINGFY(EMULATOR_VERSION_MAJOR) \".\" _XSTRINGFY(EMULATOR_VERSION_MINOR) EMULATOR_VERSION_SUFFIX)\n#define BUILD_VERSION_STRING (_XSTRINGFY(EMULATOR_VERSION_MAJOR) \".\" _XSTRINGFY(EMULATOR_VERSION_MINOR) EMULATOR_VERSION_SUFFIX)\n#else\n// no version provided. Only show commit hash\n#define BUILD_VERSION_STRING (_XSTRINGFY(EMULATOR_HASH) EMULATOR_VERSION_SUFFIX)\n#define BUILD_VERSION_WITH_NAME_STRING (EMULATOR_NAME \" \" _XSTRINGFY(EMULATOR_HASH) EMULATOR_VERSION_SUFFIX)\n#endif\n\n#endif\n"
  },
  {
    "path": "src/Common/windows/FileStream_win32.cpp",
    "content": "#include \"Common/windows/FileStream_win32.h\"\n\nFileStream* FileStream::openFile(std::string_view path)\n{\n\tHANDLE hFile = CreateFileW(boost::nowide::widen(path.data(), path.size()).c_str(), FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);\n\tif (hFile == INVALID_HANDLE_VALUE)\n\t\treturn nullptr;\n\treturn new FileStream(hFile);\n}\n\nFileStream* FileStream::openFile(const wchar_t* path, bool allowWrite)\n{\n\tHANDLE hFile = CreateFileW(path, allowWrite ? (FILE_GENERIC_READ | FILE_GENERIC_WRITE) : FILE_GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);\n\tif (hFile == INVALID_HANDLE_VALUE)\n\t\treturn nullptr;\n\treturn new FileStream(hFile);\n}\n\nFileStream* FileStream::openFile2(const fs::path& path, bool allowWrite)\n{\n\treturn openFile(path.generic_wstring().c_str(), allowWrite);\n}\n\nFileStream* FileStream::createFile(const wchar_t* path)\n{\n\tHANDLE hFile = CreateFileW(path, FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0);\n\tif (hFile == INVALID_HANDLE_VALUE)\n\t\treturn nullptr;\n\treturn new FileStream(hFile);\n}\n\nFileStream* FileStream::createFile(std::string_view path)\n{\n\tauto w = boost::nowide::widen(path.data(), path.size());\n\tHANDLE hFile = CreateFileW(w.c_str(), FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, 0);\n\tif (hFile == INVALID_HANDLE_VALUE)\n\t\treturn nullptr;\n\treturn new FileStream(hFile);\n}\n\nFileStream* FileStream::createFile2(const fs::path& path)\n{\n\treturn createFile(path.generic_wstring().c_str());\n}\n\nstd::optional<std::vector<uint8>> FileStream::LoadIntoMemory(const fs::path& path)\n{\n\tFileStream* fs = openFile2(path);\n\tif (!fs)\n\t\treturn std::nullopt;\n\tuint64 fileSize = fs->GetSize();\n\tif(fileSize > 0xFFFFFFFFull)\n\t{\n\t\tdelete fs;\n\t\treturn std::nullopt;\n\t}\n\tstd::optional<std::vector<uint8>> v(fileSize);\n\tif (fs->readData(v->data(), (uint32)fileSize) != (uint32)fileSize)\n\t{\n\t\tdelete fs;\n\t\treturn std::nullopt;\n\t}\n\tdelete fs;\n\treturn v;\n}\n\nvoid FileStream::SetPosition(uint64 pos)\n{\n\tLONG posHigh = (LONG)(pos >> 32);\n\tLONG posLow = (LONG)(pos);\n\tSetFilePointer(m_hFile, posLow, &posHigh, FILE_BEGIN);\n}\n\nuint64 FileStream::GetSize()\n{\n\tDWORD fileSizeHigh = 0;\n\tDWORD fileSizeLow = 0;\n\tfileSizeLow = GetFileSize(m_hFile, &fileSizeHigh);\n\treturn ((uint64)fileSizeHigh << 32) | (uint64)fileSizeLow;\n}\n\nbool FileStream::SetEndOfFile()\n{\n\treturn ::SetEndOfFile(m_hFile) != 0;\n}\n\nvoid FileStream::extract(std::vector<uint8>& data)\n{\n\tDWORD fileSize = GetFileSize(m_hFile, nullptr);\n\tdata.resize(fileSize);\n\tSetFilePointer(m_hFile, 0, 0, FILE_BEGIN);\n\tDWORD bt;\n\tReadFile(m_hFile, data.data(), fileSize, &bt, nullptr);\n}\n\nuint32 FileStream::readData(void* data, uint32 length)\n{\n\tDWORD bytesRead = 0;\n\tReadFile(m_hFile, data, length, &bytesRead, NULL);\n\treturn bytesRead;\n}\n\nbool FileStream::readU64(uint64& v)\n{\n\treturn readData(&v, sizeof(uint64)) == sizeof(uint64);\n}\n\nbool FileStream::readU32(uint32& v)\n{\n\treturn readData(&v, sizeof(uint32)) == sizeof(uint32);\n}\n\nbool FileStream::readU8(uint8& v)\n{\n\treturn readData(&v, sizeof(uint8)) == sizeof(uint8);\n}\n\nbool FileStream::readLine(std::string& line)\n{\n\tline.clear();\n\tuint8 c;\n\tbool isEOF = true;\n\twhile (readU8(c))\n\t{\n\t\tisEOF = false;\n\t\tif(c == '\\r')\n\t\t\tcontinue;\n\t\tif (c == '\\n')\n\t\t\tbreak;\n\t\tline.push_back((char)c);\n\t}\n\treturn !isEOF;\n}\n\nsint32 FileStream::writeData(const void* data, sint32 length)\n{\n\tDWORD bytesWritten = 0;\n\tWriteFile(m_hFile, data, length, &bytesWritten, NULL);\n\treturn bytesWritten;\n}\n\nvoid FileStream::writeU64(uint64 v)\n{\n\twriteData(&v, sizeof(uint64));\n}\n\nvoid FileStream::writeU32(uint32 v)\n{\n\twriteData(&v, sizeof(uint32));\n}\n\nvoid FileStream::writeU8(uint8 v)\n{\n\twriteData(&v, sizeof(uint8));\n}\n\nvoid FileStream::writeStringFmt(const char* format, ...)\n{\n\tchar buffer[2048];\n\tva_list args;\n\tva_start(args, format);\n\tvsnprintf(buffer, sizeof(buffer), format, args);\n\twriteData(buffer, (sint32)strlen(buffer));\n}\n\nvoid FileStream::writeString(const char* str)\n{\n\twriteData(str, (sint32)strlen(str));\n}\n\nvoid FileStream::writeLine(const char* str)\n{\n\twriteData(str, (sint32)strlen(str));\n\twriteData(\"\\r\\n\", 2);\n}\n\nFileStream::~FileStream()\n{\n\tif(m_isValid)\n\t\tCloseHandle(m_hFile);\n}\n\nFileStream::FileStream(HANDLE hFile)\n{\n\tm_hFile = hFile;\n\tm_isValid = true;\n}\n"
  },
  {
    "path": "src/Common/windows/FileStream_win32.h",
    "content": "#pragma once\n#include \"Common/precompiled.h\"\n\nclass FileStream\n{\n public:\n\tstatic FileStream* openFile(std::string_view path);\n\tstatic FileStream* openFile(const wchar_t* path, bool allowWrite = false);\n\tstatic FileStream* openFile2(const fs::path& path, bool allowWrite = false);\n\n\tstatic FileStream* createFile(const wchar_t* path);\n\tstatic FileStream* createFile(std::string_view path);\n\tstatic FileStream* createFile2(const fs::path& path);\n\n\t// helper function to load a file into memory\n\tstatic std::optional<std::vector<uint8>> LoadIntoMemory(const fs::path& path);\n\n\t// size and seek\n\tvoid SetPosition(uint64 pos);\n\n\tuint64 GetSize();\n\tbool SetEndOfFile();\n\tvoid extract(std::vector<uint8>& data);\n\n\t// reading\n\tuint32 readData(void* data, uint32 length);\n\tbool readU64(uint64& v);\n\tbool readU32(uint32& v);\n\tbool readU16(uint16& v);\n\tbool readU8(uint8& v);\n\tbool readLine(std::string& line);\n\n\t// writing (binary)\n\tsint32 writeData(const void* data, sint32 length);\n\tvoid writeU64(uint64 v);\n\tvoid writeU32(uint32 v);\n\tvoid writeU16(uint16 v);\n\tvoid writeU8(uint8 v);\n\n\t// writing (strings)\n\tvoid writeStringFmt(const char* format, ...);\n\tvoid writeString(const char* str);\n\tvoid writeLine(const char* str);\n\n\t~FileStream();\n\tFileStream() = default;\n\n private:\n\tFileStream(HANDLE hFile);\n\n\tbool m_isValid{};\n\tHANDLE m_hFile;\n};\n"
  },
  {
    "path": "src/Common/windows/platform.cpp",
    "content": "#include <Windows.h>\n\nSlimRWLock::SlimRWLock()\n{\n\tstatic_assert(sizeof(m_lock) == sizeof(SRWLOCK));\n\tRTL_SRWLOCK* srwLock = (RTL_SRWLOCK*)&m_lock;\n\t*srwLock = SRWLOCK_INIT;\n\t//m_lock = { SRWLOCK_INIT };\n}\n\nvoid SlimRWLock::LockRead()\n{\n\tAcquireSRWLockShared((SRWLOCK*)&m_lock);\n}\n\nvoid SlimRWLock::UnlockRead()\n{\n\tReleaseSRWLockShared((SRWLOCK*)&m_lock);\n}\n\nvoid SlimRWLock::LockWrite()\n{\n\tAcquireSRWLockExclusive((SRWLOCK*)&m_lock);\n}\n\nvoid SlimRWLock::UnlockWrite()\n{\n\tReleaseSRWLockExclusive((SRWLOCK*)&m_lock);\n}\n\nuint32_t GetExceptionError()\n{\n\treturn (uint32_t)GetLastError();\n}"
  },
  {
    "path": "src/Common/windows/platform.h",
    "content": "#pragma once\n\n#ifndef NOMINMAX\n#define NOMINMAX\n#endif\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#include <Windows.h>\n\n#define AF_BLUETOOTH AF_BTH\n#define BTPROTO_RFCOMM BT_PORT_ANY\n\nclass SlimRWLock\n{\npublic:\n\tSlimRWLock();\n\n\tvoid LockRead();\n\tvoid UnlockRead();\n\tvoid LockWrite();\n\tvoid UnlockWrite();\n\nprivate:\n\t/*SRWLOCK*/ void* m_lock;\n};\n\nuint32_t GetExceptionError();"
  },
  {
    "path": "src/audio/CMakeLists.txt",
    "content": "add_library(CemuAudio\n\tIAudioAPI.cpp\n\tIAudioAPI.h\n\tIAudioInputAPI.cpp\n\tIAudioInputAPI.h\n)\n\nset_property(TARGET CemuAudio PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\nif(WIN32)\n\ttarget_sources(CemuAudio PRIVATE\n\t\tDirectSoundAPI.cpp\n\t\tDirectSoundAPI.h\n\t\tXAudio2API.cpp\n\t\tXAudio2API.h\n\t\tXAudio27API.cpp\n\t\tXAudio27API.h\n\t)\nendif()\n\nif(ENABLE_CUBEB)\n\ttarget_sources(CemuAudio PRIVATE\n\t\tCubebAPI.cpp\n\t\tCubebAPI.h\n\t\tCubebInputAPI.cpp\n\t\tCubebInputAPI.h\n\t)\n\t#add_compile_definitions(HAS_CUBEB)\nendif()\n\ntarget_include_directories(CemuAudio PUBLIC \"../\")\n\ntarget_link_libraries(CemuAudio PRIVATE\n\tCemuCommon\n\tCemuGui\n)\n\nif(ENABLE_CUBEB)\n\t# PUBLIC because cubeb.h/cubeb.h is included in CubebAPI.h\n\ttarget_link_libraries(CemuAudio PUBLIC cubeb::cubeb)\nendif()\n"
  },
  {
    "path": "src/audio/CubebAPI.cpp",
    "content": "#include \"CubebAPI.h\"\n\n#if BOOST_OS_WINDOWS\n#include <combaseapi.h>\n#include <mmreg.h>\n#include <mmsystem.h>\n#pragma comment(lib, \"Avrt.lib\")\n#pragma comment(lib, \"ksuser.lib\")\n#endif\n\n\nstatic void state_cb(cubeb_stream* stream, void* user, cubeb_state state)\n{\n\tif (!stream)\n\t\treturn;\n\n\t/*switch (state)\n\t{\n\tcase CUBEB_STATE_STARTED:\n\t\tfprintf(stderr, \"stream started\\n\");\n\t\tbreak;\n\tcase CUBEB_STATE_STOPPED:\n\t\tfprintf(stderr, \"stream stopped\\n\");\n\t\tbreak;\n\tcase CUBEB_STATE_DRAINED:\n\t\tfprintf(stderr, \"stream drained\\n\");\n\t\tbreak;\n\tdefault:\n\t\tfprintf(stderr, \"unknown stream state %d\\n\", state);\n\t}*/\n}\n\nlong CubebAPI::data_cb(cubeb_stream* stream, void* user, const void* inputbuffer, void* outputbuffer, long nframes)\n{\n\tauto* thisptr = (CubebAPI*)user;\n\t//const auto size = (size_t)thisptr->m_bytesPerBlock; // (size_t)nframes* thisptr->m_channels;\n\n\t// m_bytesPerBlock = samples_per_block * channels * (bits_per_sample / 8);\n\tconst auto size = (size_t)nframes * thisptr->m_channels * (thisptr->m_bitsPerSample/8);\n\n\tstd::unique_lock lock(thisptr->m_mutex);\n\tif (thisptr->m_buffer.empty())\n\t{\n\t\t// we got no data, just write silence\n\t\tmemset(outputbuffer, 0x00, size);\n\t}\n\telse\n\t{\n\t\tconst auto copied = std::min(thisptr->m_buffer.size(), size);\n\t\tmemcpy(outputbuffer, thisptr->m_buffer.data(), copied);\n\t\tthisptr->m_buffer.erase(thisptr->m_buffer.begin(), std::next(thisptr->m_buffer.begin(), copied));\n\t\tlock.unlock();\n\t\t// fill rest with silence\n\t\tif (copied != size)\n\t\t\tmemset((uint8*)outputbuffer + copied, 0x00, size - copied);\n\t}\n\n\treturn nframes;\n}\n\nCubebAPI::CubebAPI(cubeb_devid devid, uint32 samplerate, uint32 channels, uint32 samples_per_block,\n                   uint32 bits_per_sample)\n\t: IAudioAPI(samplerate, channels, samples_per_block, bits_per_sample)\n{\n\tcubeb_stream_params output_params;\n\n\toutput_params.format = CUBEB_SAMPLE_S16LE;\n\toutput_params.rate = samplerate;\n\toutput_params.channels = channels;\n\toutput_params.prefs = CUBEB_STREAM_PREF_NONE;\n\n\tswitch (channels)\n\t{\n\tcase 8:\n\t\toutput_params.layout = CUBEB_LAYOUT_3F4_LFE;\n\t\tbreak;\n\tcase 6:\n\t\toutput_params.layout = CUBEB_LAYOUT_3F2_LFE_BACK;\n\t\tbreak;\n\tcase 4:\n\t\toutput_params.layout = CUBEB_LAYOUT_QUAD;\n\t\tbreak;\n\tcase 2:\n\t\toutput_params.layout = CUBEB_LAYOUT_STEREO;\n\t\tbreak;\n\tdefault:\n\t\toutput_params.layout = CUBEB_LAYOUT_MONO;\n\t\tbreak;\n\t}\n\n\tuint32 latency = 1;\n\tcubeb_get_min_latency(s_context, &output_params, &latency);\n\n\tm_buffer.reserve((size_t)m_bytesPerBlock * kBlockCount);\n\n\tif (cubeb_stream_init(s_context, &m_stream, \"Cemu Cubeb output\",\n\t                      nullptr, nullptr,\n\t                      devid, &output_params,\n\t                      latency, data_cb, state_cb, this) != CUBEB_OK)\n\t{\n\t\tthrow std::runtime_error(\"can't initialize cubeb device\");\n\t}\n}\n\nCubebAPI::~CubebAPI()\n{\n\tif (m_stream)\n\t{\n\t\tStop();\n\t\tcubeb_stream_destroy(m_stream);\n\t}\n}\n\nbool CubebAPI::NeedAdditionalBlocks() const\n{\n\tstd::shared_lock lock(m_mutex);\n\treturn m_buffer.size() < GetAudioDelay() * m_bytesPerBlock;\n}\n\nbool CubebAPI::FeedBlock(sint16* data)\n{\n\tstd::unique_lock lock(m_mutex);\n\tif (m_buffer.capacity() <= m_buffer.size() + m_bytesPerBlock)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"dropped direct sound block since too many buffers are queued\");\n\t\treturn false;\n\t}\n\n\tm_buffer.insert(m_buffer.end(), (uint8*)data, (uint8*)data + m_bytesPerBlock);\n\treturn true;\n}\n\nbool CubebAPI::Play()\n{\n\tif (m_is_playing)\n\t\treturn true;\n\n\tif (cubeb_stream_start(m_stream) == CUBEB_OK)\n\t{\n\t\tm_is_playing = true;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nbool CubebAPI::Stop()\n{\n\tif (!m_is_playing)\n\t\treturn true;\n\n\tif (cubeb_stream_stop(m_stream) == CUBEB_OK)\n\t{\n\t\tm_is_playing = false;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvoid CubebAPI::SetVolume(sint32 volume)\n{\n\tIAudioAPI::SetVolume(volume);\n\tcubeb_stream_set_volume(m_stream, (float)volume / 100.0f);\n}\n\n\nbool CubebAPI::InitializeStatic()\n{\n\tif (cubeb_init(&s_context, \"Cemu Cubeb\", nullptr))\n\t{\n\t\tcemuLog_log(LogType::Force, \"can't create cubeb audio api\");\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nvoid CubebAPI::Destroy()\n{\n\tif (s_context)\n\t\tcubeb_destroy(s_context);\n}\n\nstd::vector<IAudioAPI::DeviceDescriptionPtr> CubebAPI::GetDevices()\n{\n\tstd::vector<DeviceDescriptionPtr> result;\n\t// Add the default device to the list\n\tauto defaultDevice = std::make_shared<CubebDeviceDescription>(nullptr, \"default\", L\"Default Device\");\n\tresult.emplace_back(defaultDevice);\n\n\tcubeb_device_collection devices;\n\tif (cubeb_enumerate_devices(s_context, CUBEB_DEVICE_TYPE_OUTPUT, &devices) != CUBEB_OK)\n\t\treturn result;\n\n\tresult.reserve(devices.count + 1); // The default device already occupies one element\n\n\tfor (size_t i = 0; i < devices.count; ++i)\n\t{\n\t\t// const auto& device = devices.device[i];\n\t\tif (devices.device[i].state == CUBEB_DEVICE_STATE_ENABLED)\n\t\t{\n\t\t\tauto device = std::make_shared<CubebDeviceDescription>(devices.device[i].devid, devices.device[i].device_id,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   boost::nowide::widen(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   devices.device[i].friendly_name));\n\t\t\tresult.emplace_back(device);\n\t\t}\n\t}\n\n\tcubeb_device_collection_destroy(s_context, &devices);\n\n\treturn result;\n}\n"
  },
  {
    "path": "src/audio/CubebAPI.h",
    "content": "#pragma once\n\n#include \"IAudioAPI.h\"\n\n#include <cubeb/cubeb.h>\n\n#include <memory>\n\nclass CubebAPI : public IAudioAPI\n{\npublic:\n\tclass CubebDeviceDescription : public DeviceDescription\n\t{\n\tpublic:\n\t\tCubebDeviceDescription(cubeb_devid devid, std::string device_id, const std::wstring& name)\n\t\t\t: DeviceDescription(name), m_devid(devid), m_device_id(std::move(device_id)) { }\n\n\t\tstd::wstring GetIdentifier() const override { return  boost::nowide::widen(m_device_id); }\n\t\tcubeb_devid GetDeviceId() const { return m_devid; }\n\n\tprivate:\n\t\tcubeb_devid m_devid;\n\t\tstd::string m_device_id;\n\t};\n\n\tusing CubebDeviceDescriptionPtr = std::shared_ptr<CubebDeviceDescription>;\n\n\tCubebAPI(cubeb_devid devid, uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample);\n\t~CubebAPI();\n\n\tAudioAPI GetType() const override { return Cubeb; }\n\tbool NeedAdditionalBlocks() const override;\n\tbool FeedBlock(sint16* data) override;\n\tbool Play() override;\n\tbool Stop() override;\n\tvoid SetVolume(sint32 volume) override;\n\n\tstatic std::vector<DeviceDescriptionPtr> GetDevices();\n\n\tstatic bool InitializeStatic();\n\tstatic void Destroy();\n\nprivate:\n\tinline static cubeb* s_context = nullptr;\n\n\tcubeb_stream* m_stream = nullptr;\n\tbool m_is_playing = false;\n\n\tmutable std::shared_mutex m_mutex;\n\tstd::vector<uint8> m_buffer;\n\tstatic long data_cb(cubeb_stream* stream, void* user, const void* inputbuffer, void* outputbuffer, long nframes);\n};\n"
  },
  {
    "path": "src/audio/CubebInputAPI.cpp",
    "content": "#include \"CubebInputAPI.h\"\n\n#if BOOST_OS_WINDOWS\n#include <combaseapi.h>\n#include <mmreg.h>\n#include <mmsystem.h>\n#pragma comment(lib, \"Avrt.lib\")\n#pragma comment(lib, \"ksuser.lib\")\n#endif\n\nstatic void state_cb(cubeb_stream* stream, void* user, cubeb_state state)\n{\n\tif (!stream)\n\t\treturn;\n\n\t/*switch (state)\n\t{\n\tcase CUBEB_STATE_STARTED:\n\t\tfprintf(stderr, \"stream started\\n\");\n\t\tbreak;\n\tcase CUBEB_STATE_STOPPED:\n\t\tfprintf(stderr, \"stream stopped\\n\");\n\t\tbreak;\n\tcase CUBEB_STATE_DRAINED:\n\t\tfprintf(stderr, \"stream drained\\n\");\n\t\tbreak;\n\tdefault:\n\t\tfprintf(stderr, \"unknown stream state %d\\n\", state);\n\t}*/\n}\n\nlong CubebInputAPI::data_cb(cubeb_stream* stream, void* user, const void* inputbuffer, void* outputbuffer, long nframes)\n{\n\tauto* thisptr = (CubebInputAPI*)user;\n\n\tconst auto size = (size_t)nframes * thisptr->m_channels * (thisptr->m_bitsPerSample / 8);\n\n\tstd::unique_lock lock(thisptr->m_mutex);\n\tif (thisptr->m_buffer.capacity() <= thisptr->m_buffer.size() + size)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"dropped input sound block since too many buffers are queued\");\n\t\treturn nframes;\n\t}\n\n\tthisptr->m_buffer.insert(thisptr->m_buffer.end(), (uint8*)inputbuffer, (uint8*)inputbuffer + size);\n\n\treturn nframes;\n}\n\nCubebInputAPI::CubebInputAPI(cubeb_devid devid, uint32 samplerate, uint32 channels, uint32 samples_per_block,\n                   uint32 bits_per_sample)\n\t: IAudioInputAPI(samplerate, channels, samples_per_block, bits_per_sample)\n{\n\tcubeb_stream_params input_params;\n\n\tinput_params.format = CUBEB_SAMPLE_S16LE;\n\tinput_params.rate = samplerate;\n\tinput_params.channels = channels;\n\tinput_params.prefs = CUBEB_STREAM_PREF_NONE;\n\n\tswitch (channels)\n\t{\n\tcase 8:\n\t\tinput_params.layout = CUBEB_LAYOUT_3F4_LFE;\n\t\tbreak;\n\tcase 6:\n\t\tinput_params.layout = CUBEB_LAYOUT_QUAD_LFE | CHANNEL_FRONT_CENTER;\n\t\tbreak;\n\tcase 4:\n\t\tinput_params.layout = CUBEB_LAYOUT_QUAD;\n\t\tbreak;\n\tcase 2:\n\t\tinput_params.layout = CUBEB_LAYOUT_STEREO;\n\t\tbreak;\n\tdefault:\n\t\tinput_params.layout = CUBEB_LAYOUT_MONO;\n\t\tbreak;\n\t}\n\n\tuint32 latency = 1;\n\tcubeb_get_min_latency(s_context, &input_params, &latency);\n\n\tm_buffer.reserve((size_t)m_bytesPerBlock * kBlockCount);\n\n\tif (cubeb_stream_init(s_context, &m_stream, \"Cemu Cubeb input\",\n\t                      devid, &input_params,\n                          nullptr, nullptr,\n\t                      latency, data_cb, state_cb, this) != CUBEB_OK)\n\t{\n\t\tthrow std::runtime_error(\"can't initialize cubeb device\");\n\t}\n}\n\nCubebInputAPI::~CubebInputAPI()\n{\n\tif (m_stream)\n\t{\n\t\tStop();\n\t\tcubeb_stream_destroy(m_stream);\n\t}\n}\n\nbool CubebInputAPI::ConsumeBlock(sint16* data)\n{\n\tstd::unique_lock lock(m_mutex);\n\tif (m_buffer.empty())\n\t{\n\t\t// we got no data, just write silence\n\t\tmemset(data, 0x00, m_bytesPerBlock);\n\t}\n\telse\n\t{\n\t\tconst auto copied = std::min(m_buffer.size(), (size_t)m_bytesPerBlock);\n\t\tmemcpy(data, m_buffer.data(), copied);\n\t\tm_buffer.erase(m_buffer.begin(), std::next(m_buffer.begin(), copied));\n\t\tlock.unlock();\n\t\t// fill rest with silence\n\t\tif (copied != m_bytesPerBlock)\n\t\t\tmemset((uint8*)data + copied, 0x00, m_bytesPerBlock - copied);\n\t}\n\n\treturn true;\n}\n\nbool CubebInputAPI::Play()\n{\n\tif (m_is_playing)\n\t\treturn true;\n\n\tif (cubeb_stream_start(m_stream) == CUBEB_OK)\n\t{\n\t\tm_is_playing = true;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nbool CubebInputAPI::Stop()\n{\n\tif (!m_is_playing)\n\t\treturn true;\n\n\tif (cubeb_stream_stop(m_stream) == CUBEB_OK)\n\t{\n\t\tm_is_playing = false;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvoid CubebInputAPI::SetVolume(sint32 volume)\n{\n\tIAudioInputAPI::SetVolume(volume);\n\tcubeb_stream_set_volume(m_stream, (float)volume / 100.0f);\n}\n\nbool CubebInputAPI::InitializeStatic()\n{\n\tif (cubeb_init(&s_context, \"Cemu Input Cubeb\", nullptr))\n\t{\n\t\tcemuLog_log(LogType::Force, \"can't create cubeb audio api\");\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nvoid CubebInputAPI::Destroy()\n{\n\tif (s_context)\n\t\tcubeb_destroy(s_context);\n}\n\nstd::vector<IAudioInputAPI::DeviceDescriptionPtr> CubebInputAPI::GetDevices()\n{\n\tstd::vector<DeviceDescriptionPtr> result;\n\t// Add the default device to the list\n\tauto defaultDevice = std::make_shared<CubebDeviceDescription>(nullptr, \"default\", L\"Default Device\");\n\tresult.emplace_back(defaultDevice);\n\n\tcubeb_device_collection devices;\n\tif (cubeb_enumerate_devices(s_context, CUBEB_DEVICE_TYPE_INPUT, &devices) != CUBEB_OK)\n\t\treturn result;\n\n\tresult.reserve(devices.count + 1); // The default device already occupies one element\n\n\tfor (size_t i = 0; i < devices.count; ++i)\n\t{\n\t\t// const auto& device = devices.device[i];\n\t\tif (devices.device[i].state == CUBEB_DEVICE_STATE_ENABLED)\n\t\t{\n\t\t\tauto device = std::make_shared<CubebDeviceDescription>(devices.device[i].devid, devices.device[i].device_id,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   boost::nowide::widen(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   devices.device[i].friendly_name));\n\t\t\tresult.emplace_back(device);\n\t\t}\n\t}\n\n\tcubeb_device_collection_destroy(s_context, &devices);\n\n\treturn result;\n}\n"
  },
  {
    "path": "src/audio/CubebInputAPI.h",
    "content": "#pragma once\n\n#include \"IAudioInputAPI.h\"\n\n#include <cubeb/cubeb.h>\n\nclass CubebInputAPI : public IAudioInputAPI\n{\npublic:\n\tclass CubebDeviceDescription : public DeviceDescription\n\t{\n\tpublic:\n\t\tCubebDeviceDescription(cubeb_devid devid, std::string device_id, const std::wstring& name)\n\t\t\t: DeviceDescription(name), m_devid(devid), m_device_id(std::move(device_id)) { }\n\n\t\tstd::wstring GetIdentifier() const override { return  boost::nowide::widen(m_device_id); }\n\t\tcubeb_devid GetDeviceId() const { return m_devid; }\n\n\tprivate:\n\t\tcubeb_devid m_devid;\n\t\tstd::string m_device_id;\n\t};\n\n\tusing CubebDeviceDescriptionPtr = std::shared_ptr<CubebDeviceDescription>;\n\n\tCubebInputAPI(cubeb_devid devid, uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample);\n\t~CubebInputAPI();\n\n\tAudioInputAPI GetType() const override { return Cubeb; }\n\n\tbool ConsumeBlock(sint16* data) override;\n\tbool Play() override;\n\tbool Stop() override;\n\tbool IsPlaying() const override { return m_is_playing;  };\n\tvoid SetVolume(sint32 volume) override;\n\n\tstatic std::vector<DeviceDescriptionPtr> GetDevices();\n\n\tstatic bool InitializeStatic();\n\tstatic void Destroy();\n\nprivate:\n\tinline static cubeb* s_context = nullptr;\n\n\tcubeb_stream* m_stream = nullptr;\n\tbool m_is_playing = false;\n\n\tmutable std::shared_mutex m_mutex;\n\tstd::vector<uint8> m_buffer;\n\tstatic long data_cb(cubeb_stream* stream, void* user, const void* inputbuffer, void* outputbuffer, long nframes);\n};\n"
  },
  {
    "path": "src/audio/DirectSoundAPI.cpp",
    "content": "#include \"DirectSoundAPI.h\"\n\n#include \"util/helpers/helpers.h\"\n#include \"WindowSystem.h\"\n#include <wrl/client.h>\n\n#pragma comment(lib, \"Dsound.lib\")\n\nstd::wstring DirectSoundAPI::DirectSoundDeviceDescription::GetIdentifier() const\n{\n\treturn m_guid ? WStringFromGUID(*m_guid) : L\"default\";\n}\n\nDirectSoundAPI::DirectSoundAPI(GUID* guid, sint32 samplerate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample)\n\t: IAudioAPI(samplerate, channels, samples_per_block, bits_per_sample)\n{\n\tif (DirectSoundCreate8(guid, &m_direct_sound, nullptr) != DS_OK)\n\t\tthrow std::runtime_error(\"can't create directsound device\");\n\n\tif (FAILED(m_direct_sound->SetCooperativeLevel(static_cast<HWND>(WindowSystem::GetWindowInfo().window_main.surface), DSSCL_PRIORITY)))\n\t\tthrow std::runtime_error(\"can't set directsound priority\");\n\n\tDSBUFFERDESC bd{};\n\tbd.dwSize = sizeof(DSBUFFERDESC);\n\tbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY;\n\tbd.dwBufferBytes = kBufferCount * m_bytesPerBlock; // kBlockCount * (samples_per_block * channels * (bits_per_sample / 8));\n\tbd.lpwfxFormat = (LPWAVEFORMATEX)&m_wfx;\n\n\tMicrosoft::WRL::ComPtr<IDirectSoundBuffer> sound_buffer;\n\tif (FAILED(m_direct_sound->CreateSoundBuffer(&bd, &sound_buffer, nullptr)))\n\t\tthrow std::runtime_error(\"can't create directsound soundbuffer\");\n\n\tDSBCAPS caps{};\n\tcaps.dwSize = sizeof(DSBCAPS);\n\tif (FAILED(sound_buffer->GetCaps(&caps)))\n\t\tthrow std::runtime_error(\"can't get directsound soundbuffer size\");\n\n\tm_sound_buffer_size = caps.dwBufferBytes;\n\n\tMicrosoft::WRL::ComPtr<IDirectSoundNotify8> notify8;\n\n\tif (FAILED(sound_buffer->QueryInterface(IID_IDirectSoundBuffer8, &m_sound_buffer)))\n\t{\n\t\tthrow std::runtime_error(\"can't get directsound buffer interface\");\n\t}\n\n\tif (FAILED(sound_buffer->QueryInterface(IID_IDirectSoundNotify8, &m_notify)))\n\t{\n\t\tthrow std::runtime_error(\"can't get directsound notify interface\");\n\t}\n\n\t{ // initialize sound buffer\n\t\tvoid *ptr1, *ptr2;\n\t\tDWORD bytes1, bytes2;\n\t\tm_sound_buffer->Lock(0, m_sound_buffer_size, &ptr1, &bytes1, &ptr2, &bytes2, 0);\n\t\tmemset(ptr1, 0x00, bytes1);\n\t\tif (ptr2 && bytes2 > 0)\n\t\t\tmemset(ptr2, 0x00, bytes2);\n\t\tm_sound_buffer->Unlock(ptr1, bytes1, ptr2, bytes2);\n\t}\n\n\tm_sound_buffer->SetCurrentPosition(0);\n\n\tDSBPOSITIONNOTIFY notify[kBufferCount]{};\n\tfor (size_t i = 0; i < kBufferCount; ++i)\n\t{\n\t\tm_notify_event[i] = CreateEvent(nullptr, FALSE, FALSE, nullptr);\n\n\t\tnotify[i].hEventNotify = m_notify_event[i];\n\t\t//notify[i].dwOffset = ((i*2) + 1) * (m_bytes_per_block / 2);\n\t\tnotify[i].dwOffset = (i * m_bytesPerBlock);\n\t}\n\n\tif (FAILED(m_notify->SetNotificationPositions(kBufferCount, notify)))\n\t\tthrow std::runtime_error(\"can't set directsound notify positions\");\n\n\tm_running = true;\n\tm_thread = std::thread(&DirectSoundAPI::AudioThread, this);\n#if BOOST_OS_WINDOWS\n\tSetThreadPriority(m_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL);\n#endif\n}\n\nvoid DirectSoundAPI::AudioThread()\n{\n\twhile (m_running)\n\t{\n\t\tHRESULT hr = WaitForMultipleObjects(m_notify_event.size(), m_notify_event.data(), FALSE, 10);\n\t\tif (WAIT_OBJECT_0 <= hr && hr <= WAIT_OBJECT_0 + kBufferCount)\n\t\t{\n\t\t\t// write to the following buffer\n\t\t\tconst sint32 position = (hr - WAIT_OBJECT_0 + 1) % kBufferCount;\n\n\t\t\tvoid *ptr1, *ptr2;\n\t\t\tDWORD bytes1, bytes2;\n\t\t\thr = m_sound_buffer->Lock(position * m_bytesPerBlock, m_bytesPerBlock, &ptr1, &bytes1, &ptr2, &bytes2, 0);\n\t\t\tif (hr == DSERR_BUFFERLOST)\n\t\t\t{\n\t\t\t\tm_sound_buffer->Restore();\n\t\t\t\thr = m_sound_buffer->Lock(position * m_bytesPerBlock, m_bytesPerBlock, &ptr1, &bytes1, &ptr2, &bytes2, 0);\n\t\t\t}\n\n\t\t\tif (FAILED(hr))\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"DirectSound: Dropped audio block due to locking failure\");\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t{\n\t\t\t\tstd::unique_lock lock(m_mutex);\n\t\t\t\tif (m_buffer.empty())\n\t\t\t\t{\n\t\t\t\t\t//cemuLog_logDebug(LogType::Force, \"DirectSound: writing silence\");\n\n\t\t\t\t\t// we got no data, just write silence\n\t\t\t\t\tmemset(ptr1, 0x00, bytes1);\n\t\t\t\t\tif (ptr2)\n\t\t\t\t\t\tmemset(ptr2, 0x00, bytes2);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tconst auto& buffer = m_buffer.front();\n\t\t\t\t\tmemcpy(ptr1, buffer.get(), bytes1);\n\t\t\t\t\tif (ptr2)\n\t\t\t\t\t\tmemcpy(ptr2, buffer.get() + bytes1, bytes2);\n\n\t\t\t\t\tm_buffer.pop();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tm_sound_buffer->Unlock(ptr1, bytes1, ptr2, bytes2);\n\t\t}\n\t}\n}\n\nDirectSoundAPI::~DirectSoundAPI()\n{\n\tm_running = false;\n\tDirectSoundAPI::Stop();\n\t\n\tif(m_thread.joinable())\n\t\tm_thread.join();\n\n\tfor(auto entry : m_notify_event)\n\t{\n\t\tif (entry)\n\t\t\tCloseHandle(entry);\n\t}\n}\n\nbool DirectSoundAPI::Play()\n{\n\tif (m_playing)\n\t\treturn true;\n\n\tm_playing = SUCCEEDED(m_sound_buffer->Play(0, 0, DSBPLAY_LOOPING));\n\treturn m_playing;\n}\n\nbool DirectSoundAPI::Stop()\n{\n\tif (!m_playing)\n\t\treturn true;\n\n\tm_playing = FAILED(m_sound_buffer->Stop());\n\treturn m_playing;\n}\n\nbool DirectSoundAPI::FeedBlock(sint16* data)\n{\n\tstd::lock_guard lock(m_mutex);\n\tif (m_buffer.size() > kBlockCount)\n\t{\n\t\tcemuLog_logDebug(LogType::Force, \"dropped direct sound block since too many buffers are queued\");\n\t\treturn false;\n\t}\n\n\tauto tmp = std::make_unique<uint8[]>(m_bytesPerBlock);\n\tmemcpy(tmp.get(), data, m_bytesPerBlock);\n\tm_buffer.emplace(std::move(tmp));\n\treturn true;\n}\n\nvoid DirectSoundAPI::SetVolume(sint32 volume)\n{\n\tIAudioAPI::SetVolume(volume);\n\n\tconst LONG value = pow((float)volume / 100.0f, 0.20f) * (DSBVOLUME_MAX - DSBVOLUME_MIN) + DSBVOLUME_MIN;\n\tm_sound_buffer->SetVolume(value);\n}\n\nbool DirectSoundAPI::NeedAdditionalBlocks() const\n{\n\tstd::shared_lock lock(m_mutex);\n\treturn m_buffer.size() < GetAudioDelay();\n}\n\nstd::vector<DirectSoundAPI::DeviceDescriptionPtr> DirectSoundAPI::GetDevices()\n{\n\tstd::vector<DeviceDescriptionPtr> result;\n\n\tDirectSoundEnumerateW(\n\t\t[](LPGUID lpGuid, LPCWSTR lpcstrDescription, LPCWSTR lpcstrModule, LPVOID lpContext) -> BOOL\n\t\t{\n\t\t\tauto results = (std::vector<DeviceDescriptionPtr>*)lpContext;\n\t\t\tauto obj = std::make_shared<DirectSoundDeviceDescription>(lpcstrDescription, lpGuid);\n\t\t\tresults->emplace_back(obj);\n\t\t\treturn TRUE;\n\t\t}, &result);\n\n\t//Exclude default primary sound device if no other sound devices are available\n\tif (result.size() == 1 && result.at(0).get()->GetIdentifier() == L\"default\") {\n\t\tresult.clear();\n\t}\n\t\n\treturn result;\n}\n\nstd::vector<DirectSoundAPI::DeviceDescriptionPtr> DirectSoundAPI::GetInputDevices()\n{\n\tstd::vector<DeviceDescriptionPtr> result;\n\n\tDirectSoundCaptureEnumerateW(\n\t\t[](LPGUID lpGuid, LPCWSTR lpcstrDescription, LPCWSTR lpcstrModule, LPVOID lpContext) -> BOOL\n\t{\n\t\tauto results = (std::vector<DirectSoundDeviceDescriptionPtr>*)lpContext;\n\t\tauto obj = std::make_shared<DirectSoundDeviceDescription>(lpcstrDescription, lpGuid);\n\t\tresults->emplace_back(obj);\n\t\treturn TRUE;\n\t}, &result);\n\n\treturn result;\n}\n"
  },
  {
    "path": "src/audio/DirectSoundAPI.h",
    "content": "#pragma once\n\n#define DIRECTSOUND_VERSION 0x0800\n#include <mmsystem.h>\n#include <dsound.h>\n#include <wrl/client.h>\n\n#include \"IAudioAPI.h\"\n\nclass DirectSoundAPI : public IAudioAPI\n{\npublic:\n\tclass DirectSoundDeviceDescription : public DeviceDescription\n\t{\n\tpublic:\n\t\tDirectSoundDeviceDescription(const std::wstring& name, GUID* guid)\n\t\t\t: DeviceDescription(name), m_guid(guid) { }\n\n\t\tstd::wstring GetIdentifier() const override;\n\t\tGUID* GetGUID() const { return m_guid; }\n\n\tprivate:\n\t\tGUID* m_guid;\n\t};\n\n\tusing DirectSoundDeviceDescriptionPtr = std::shared_ptr<DirectSoundDeviceDescription>;\n\n\t// output\n\tDirectSoundAPI(GUID* guid, sint32 samplerate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample);\n\t~DirectSoundAPI();\n\n\tAudioAPI GetType() const override { return DirectSound; }\n\n\tbool Play() override;\n\tbool Stop() override;\n\tbool FeedBlock(sint16* data) override;\n\tvoid SetVolume(sint32 volume) override;\n\tbool NeedAdditionalBlocks() const override;\n\n\tstatic std::vector<DeviceDescriptionPtr> GetDevices();\n\tstatic std::vector<DeviceDescriptionPtr> GetInputDevices();\n\nprivate:\n\tMicrosoft::WRL::ComPtr<IDirectSound8> m_direct_sound;\n\t//Microsoft::WRL::ComPtr<IDirectSoundCapture8> m_direct_sound_capture;\n\tMicrosoft::WRL::ComPtr<IDirectSoundBuffer8> m_sound_buffer;\n\tMicrosoft::WRL::ComPtr<IDirectSoundNotify8> m_notify;\n\n\tDWORD m_sound_buffer_size = 0;\n\tuint32_t m_offset = 0;\n\tbool m_data_written = false;\n\n\tstatic const uint32 kBufferCount = 4;\n\tstd::array<HANDLE, kBufferCount> m_notify_event{};\n\tmutable std::shared_mutex m_mutex;\n\n\tstd::queue<std::unique_ptr<uint8[]>> m_buffer;\n\tstd::thread m_thread;\n\tstd::atomic_bool m_running = false;\n\tvoid AudioThread();\n};\n"
  },
  {
    "path": "src/audio/IAudioAPI.cpp",
    "content": "#include \"IAudioAPI.h\"\n\n#if BOOST_OS_WINDOWS\n#include \"XAudio2API.h\"\n#include \"XAudio27API.h\"\n#include \"DirectSoundAPI.h\"\n#endif\n#include \"config/CemuConfig.h\"\n#if HAS_CUBEB\n#include \"CubebAPI.h\"\n#endif\n\nstd::shared_mutex g_audioMutex;\nAudioAPIPtr g_tvAudio;\nAudioAPIPtr g_padAudio;\nAudioAPIPtr g_portalAudio;\nstd::atomic_int32_t g_padVolume = 0;\n\nuint32 IAudioAPI::s_audioDelay = 2;\nstd::array<bool, IAudioAPI::AudioAPIEnd> IAudioAPI::s_availableApis{};\n\nIAudioAPI::IAudioAPI(uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample)\n\t: m_samplerate(samplerate), m_channels(channels), m_samplesPerBlock(samples_per_block), m_bitsPerSample(bits_per_sample)\n{\n\tm_bytesPerBlock = samples_per_block * channels * (bits_per_sample / 8);\n\tInitWFX(m_samplerate, m_channels, m_bitsPerSample);\n}\n\nvoid IAudioAPI::PrintLogging()\n{\n\tcemuLog_log(LogType::Force, \"------- Init Audio backend -------\");\n\tcemuLog_log(LogType::Force, \"DirectSound: {}\", s_availableApis[DirectSound] ? \"available\" : \"not supported\");\n\tcemuLog_log(LogType::Force, \"XAudio 2.8: {}\", s_availableApis[XAudio2] ? \"available\" : \"not supported\");\n\tif (!s_availableApis[XAudio2])\n\t{\n\t\tcemuLog_log(LogType::Force, \"XAudio 2.7: {}\", s_availableApis[XAudio27] ? \"available\" : \"not supported\");\n\t}\n\n\tcemuLog_log(LogType::Force, \"Cubeb: {}\", s_availableApis[Cubeb] ? \"available\" : \"not supported\");\n}\n\nvoid IAudioAPI::InitWFX(sint32 samplerate, sint32 channels, sint32 bits_per_sample)\n{\n#if BOOST_OS_WINDOWS\n\t// move this to Windows-specific audio API implementations and use a cross-platform format here\n\tm_wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;\n\tm_wfx.Format.nChannels = channels;\n\tm_wfx.Format.nSamplesPerSec = samplerate;\n\tm_wfx.Format.wBitsPerSample = bits_per_sample;\n\tm_wfx.Format.nBlockAlign = (m_wfx.Format.nChannels * m_wfx.Format.wBitsPerSample) / 8; // must equal (nChannels � wBitsPerSample) / 8\n\tm_wfx.Format.nAvgBytesPerSec = m_wfx.Format.nSamplesPerSec * m_wfx.Format.nBlockAlign; // must equal nSamplesPerSec � nBlockAlign.\n\tm_wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);\n\n\tm_wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;\n\tm_wfx.Samples.wValidBitsPerSample = bits_per_sample;\n\tswitch (channels)\n\t{\n\tcase 8:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER);\n\t\tbreak;\n\tcase 6:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT);\n\t\tbreak;\n\tcase 4:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT);\n\t\tbreak;\n\tcase 2:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT);\n\t\tbreak;\n\tdefault:\n\t\tm_wfx.dwChannelMask = 0;\n\t\tbreak;\n\t}\n#endif\n}\n\nvoid IAudioAPI::InitializeStatic()\n{\n\ts_audioDelay = GetConfig().audio_delay;\n\n#if BOOST_OS_WINDOWS\n\ts_availableApis[DirectSound] = true;\n\ts_availableApis[XAudio2] = XAudio2API::InitializeStatic();\n\tif (!s_availableApis[XAudio2]) // don't try to initialize the older lib if the newer version is available\n\t\ts_availableApis[XAudio27] = XAudio27API::InitializeStatic();\n#endif\n#if HAS_CUBEB\n\ts_availableApis[Cubeb] = CubebAPI::InitializeStatic();\n#endif\n}\n\nbool IAudioAPI::IsAudioAPIAvailable(AudioAPI api)\n{\n\tif ((size_t)api < s_availableApis.size())\n\t\treturn s_availableApis[api];\n\n\tcemu_assert_debug(false);\n\treturn false;\n}\n\nAudioAPIPtr IAudioAPI::CreateDeviceFromConfig(AudioType type, sint32 rate, sint32 samples_per_block, sint32 bits_per_sample)\n{\n\tsint32 channels = CemuConfig::AudioChannelsToNChannels(AudioTypeToChannels(type));\n\treturn CreateDeviceFromConfig(type, rate, channels, samples_per_block, bits_per_sample);\n}\n\nAudioAPIPtr IAudioAPI::CreateDeviceFromConfig(AudioType type, sint32 rate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample)\n{\n\tAudioAPIPtr audioAPIDev;\n\n\tauto& config = GetConfig();\n\n\tconst auto audio_api = (IAudioAPI::AudioAPI)config.audio_api;\n\tauto selectedDevice = GetDeviceFromType(type);\n\n\tif (selectedDevice.empty())\n\t\treturn {};\n\n\tIAudioAPI::DeviceDescriptionPtr device_description;\n\tif (IAudioAPI::IsAudioAPIAvailable(audio_api))\n\t{\n\t\tauto devices = IAudioAPI::GetDevices(audio_api);\n\t\tconst auto it = std::find_if(devices.begin(), devices.end(), [&selectedDevice](const auto& d) { return d->GetIdentifier() == selectedDevice; });\n\t\tif (it != devices.end())\n\t\t\tdevice_description = *it;\n\t}\n\tif (!device_description)\n\t\tthrow std::runtime_error(\"failed to find selected device while trying to create audio device\");\n\n\taudioAPIDev = CreateDevice(audio_api, device_description, rate, channels, samples_per_block, bits_per_sample);\n\taudioAPIDev->SetVolume(GetVolumeFromType(type));\n\n\treturn audioAPIDev;\n}\n\nAudioAPIPtr IAudioAPI::CreateDevice(AudioAPI api, const DeviceDescriptionPtr& device, sint32 samplerate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample)\n{\n\tif (!IsAudioAPIAvailable(api))\n\t\treturn {};\n\n\tswitch (api)\n\t{\n#if BOOST_OS_WINDOWS\n\tcase DirectSound:\n\t{\n\t\tconst auto tmp = std::dynamic_pointer_cast<DirectSoundAPI::DirectSoundDeviceDescription>(device);\n\t\treturn std::make_unique<DirectSoundAPI>(tmp->GetGUID(), samplerate, channels, samples_per_block, bits_per_sample);\n\t}\n\tcase XAudio27:\n\t{\n\t\tconst auto tmp = std::dynamic_pointer_cast<XAudio27API::XAudio27DeviceDescription>(device);\n\t\treturn std::make_unique<XAudio27API>(tmp->GetDeviceId(), samplerate, channels, samples_per_block, bits_per_sample);\n\t}\n\tcase XAudio2:\n\t{\n\t\tconst auto tmp = std::dynamic_pointer_cast<XAudio2API::XAudio2DeviceDescription>(device);\n\t\treturn std::make_unique<XAudio2API>(tmp->GetDeviceId(), samplerate, channels, samples_per_block, bits_per_sample);\n\t}\n#endif\n#if HAS_CUBEB\n\tcase Cubeb:\n\t{\n\t\tconst auto tmp = std::dynamic_pointer_cast<CubebAPI::CubebDeviceDescription>(device);\n\t\treturn std::make_unique<CubebAPI>(tmp->GetDeviceId(), samplerate, channels, samples_per_block, bits_per_sample);\n\t}\n#endif\n\tdefault:\n\t\tthrow std::runtime_error(fmt::format(\"invalid audio api: {}\", api));\n\t}\n}\n\nstd::vector<IAudioAPI::DeviceDescriptionPtr> IAudioAPI::GetDevices(AudioAPI api)\n{\n\tif (!IsAudioAPIAvailable(api))\n\t\treturn {};\n\n\tswitch (api)\n\t{\n#if BOOST_OS_WINDOWS\n\tcase DirectSound:\n\t{\n\t\treturn DirectSoundAPI::GetDevices();\n\t}\n\tcase XAudio27:\n\t{\n\t\treturn XAudio27API::GetDevices();\n\t}\n\tcase XAudio2:\n\t{\n\t\treturn XAudio2API::GetDevices();\n\t}\n#endif\n#if HAS_CUBEB\n\tcase Cubeb:\n\t{\n\t\treturn CubebAPI::GetDevices();\n\t}\n#endif\n\tdefault:\n\t\tthrow std::runtime_error(fmt::format(\"invalid audio api: {}\", api));\n\t}\n}\n\nvoid IAudioAPI::SetAudioDelayOverride(uint32 delay)\n{\n\tm_audioDelayOverride = delay;\n}\n\nuint32 IAudioAPI::GetAudioDelay() const\n{\n\treturn m_audioDelayOverride > 0 ? m_audioDelayOverride : s_audioDelay;\n}\n\nAudioChannels IAudioAPI::AudioTypeToChannels(AudioType type)\n{\n\tauto& config = GetConfig();\n\tswitch (type)\n\t{\n\tcase TV:\n\t\treturn config.tv_channels;\n\tcase Gamepad:\n\t\treturn config.pad_channels;\n\tcase Portal:\n\t\treturn kMono;\n\tdefault:\n\t\treturn kMono;\n\t}\n}\n\nstd::wstring IAudioAPI::GetDeviceFromType(AudioType type)\n{\n\tauto& config = GetConfig();\n\tswitch (type)\n\t{\n\tcase TV:\n\t\treturn config.tv_device;\n\tcase Gamepad:\n\t\treturn config.pad_device;\n\tcase Portal:\n\t\treturn config.portal_device;\n\tdefault:\n\t\treturn L\"\";\n\t}\n}\n\nsint32 IAudioAPI::GetVolumeFromType(AudioType type)\n{\n\tauto& config = GetConfig();\n\tswitch (type)\n\t{\n\tcase TV:\n\t\treturn config.tv_volume;\n\tcase Gamepad:\n\t\treturn config.pad_volume;\n\tcase Portal:\n\t\treturn config.portal_volume;\n\tdefault:\n\t\treturn 0;\n\t}\n}\n"
  },
  {
    "path": "src/audio/IAudioAPI.h",
    "content": "#pragma once\n\n#if BOOST_OS_WINDOWS\n#include <mmreg.h>\n#endif\n\n#include \"config/CemuConfig.h\"\n\nclass IAudioAPI\n{\n\tfriend class GeneralSettings2;\n\npublic:\n\tclass DeviceDescription\n\t{\n\tpublic:\n\t\texplicit DeviceDescription(std::wstring name)\n\t\t\t: m_name(std::move(name)) { }\n\n\t\tvirtual ~DeviceDescription() = default;\n\t\tvirtual std::wstring GetIdentifier() const = 0;\n\t\tconst std::wstring& GetName() const { return m_name; }\n\n\t\tbool operator==(const DeviceDescription& o) const\n\t\t{\n\t\t\treturn GetIdentifier() == o.GetIdentifier();\n\t\t}\n\n\tprivate:\n\t\tstd::wstring m_name;\n\t};\n\n\tusing DeviceDescriptionPtr = std::shared_ptr<DeviceDescription>;\n\n\tenum AudioType\n\t{\n\t\tTV = 0,\n\t\tGamepad,\n\t\tPortal\n\t};\n\n\tenum AudioAPI\n\t{\n\t\tDirectSound = 0,\n\t\tXAudio27,\n\t\tXAudio2,\n\t\tCubeb,\n\n\t\tAudioAPIEnd,\n\t};\n\tstatic constexpr uint32 kBlockCount = 24;\n\t\n\tIAudioAPI(uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample);\n\tvirtual ~IAudioAPI() = default;\n\tvirtual AudioAPI GetType() const = 0;\n\n\tsint32 GetChannels() const { return m_channels; }\n\n\tvirtual sint32 GetVolume() const { return m_volume; }\n\tvirtual void SetVolume(sint32 volume) { m_volume = volume; }\n\tvirtual void SetInputVolume(sint32 volume) { m_inputVolume = volume; }\n\n\tvirtual bool NeedAdditionalBlocks() const = 0;\n\tvirtual bool FeedBlock(sint16* data) = 0;\n\tvirtual bool Play() = 0;\n\tvirtual bool Stop() = 0;\n\tvoid SetAudioDelayOverride(uint32 delay);\n\tuint32 GetAudioDelay() const;\n\n\tstatic void PrintLogging();\n\tstatic void InitializeStatic();\n\tstatic bool IsAudioAPIAvailable(AudioAPI api);\n\n\tstatic std::unique_ptr<IAudioAPI> CreateDeviceFromConfig(AudioType type, sint32 rate, sint32 samples_per_block, sint32 bits_per_sample);\n\tstatic std::unique_ptr<IAudioAPI> CreateDeviceFromConfig(AudioType type, sint32 rate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample);\n\tstatic std::unique_ptr<IAudioAPI> CreateDevice(AudioAPI api, const DeviceDescriptionPtr& device, sint32 samplerate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample);\n\tstatic std::vector<DeviceDescriptionPtr> GetDevices(AudioAPI api);\n\nprotected:\n#if BOOST_OS_WINDOWS\n\tWAVEFORMATEXTENSIBLE m_wfx{};\n#endif\n\t\n\tuint32 m_samplerate, m_channels, m_samplesPerBlock, m_bitsPerSample;\n\tuint32 m_bytesPerBlock;\n\n\tsint32 m_volume = 0, m_inputVolume = 0;\n\tbool m_playing = false;\n\n\tstatic std::array<bool, AudioAPIEnd> s_availableApis;\n\tuint32 m_audioDelayOverride = 0;\n\nprivate:\n\tstatic uint32 s_audioDelay;\n\tvoid InitWFX(sint32 samplerate, sint32 channels, sint32 bits_per_sample);\n\tstatic AudioChannels AudioTypeToChannels(AudioType type);\n\tstatic std::wstring GetDeviceFromType(AudioType type);\n\tstatic sint32 GetVolumeFromType(AudioType type);\n\t\n};\n\nusing AudioAPIPtr = std::unique_ptr<IAudioAPI>;\nextern std::shared_mutex g_audioMutex;\nextern AudioAPIPtr g_tvAudio;\n\nextern AudioAPIPtr g_padAudio;\nextern std::atomic_int32_t g_padVolume;\n\nextern AudioAPIPtr g_portalAudio;\n"
  },
  {
    "path": "src/audio/IAudioInputAPI.cpp",
    "content": "#include \"IAudioInputAPI.h\"\n#if HAS_CUBEB\n#include \"CubebInputAPI.h\"\n#endif\n\nstd::shared_mutex g_audioInputMutex;\nAudioInputAPIPtr g_inputAudio;\n\nstd::array<bool, IAudioInputAPI::AudioInputAPIEnd> IAudioInputAPI::s_availableApis{};\n\nIAudioInputAPI::IAudioInputAPI(uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample)\n\t: m_samplerate(samplerate), m_channels(channels), m_samplesPerBlock(samples_per_block), m_bitsPerSample(bits_per_sample) \n{\n\tm_bytesPerBlock = samples_per_block * channels * (bits_per_sample / 8);\n}\n\nvoid IAudioInputAPI::PrintLogging()\n{\n\tcemuLog_log(LogType::Force, \"------- Init Audio input backend -------\");\n\tcemuLog_log(LogType::Force, \"Cubeb: {}\", s_availableApis[Cubeb] ? \"available\" : \"not supported\");\n}\n\nvoid IAudioInputAPI::InitializeStatic()\n{\n#if HAS_CUBEB\n\ts_availableApis[Cubeb] = CubebInputAPI::InitializeStatic();\n#endif\n}\n\nbool IAudioInputAPI::IsAudioInputAPIAvailable(AudioInputAPI api)\n{\n\tif ((size_t)api < s_availableApis.size())\n\t\treturn s_availableApis[api];\n\n\tcemu_assert_debug(false);\n\treturn false;\n}\n\nAudioInputAPIPtr IAudioInputAPI::CreateDevice(AudioInputAPI api, const DeviceDescriptionPtr& device, sint32 samplerate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample)\n{\n\tif (!IsAudioInputAPIAvailable(api))\n\t\treturn {};\n\n\tswitch(api)\n\t{\n#if HAS_CUBEB\n\tcase Cubeb:\n\t{\n\t\tconst auto tmp = std::dynamic_pointer_cast<CubebInputAPI::CubebDeviceDescription>(device);\n\t\treturn std::make_unique<CubebInputAPI>(tmp->GetDeviceId(), samplerate, channels, samples_per_block, bits_per_sample);\n\t}\n#endif\n\tdefault:\n\t\tthrow std::runtime_error(fmt::format(\"invalid audio api: {}\", api));\n\t}\n}\n\nstd::vector<IAudioInputAPI::DeviceDescriptionPtr> IAudioInputAPI::GetDevices(AudioInputAPI api)\n{\n\tif (!IsAudioInputAPIAvailable(api))\n\t\treturn {};\n\t\n\tswitch(api)\n\t{\n#if HAS_CUBEB\n\tcase Cubeb:\n\t{\n\t\treturn CubebInputAPI::GetDevices();\n\t}\n#endif\n\tdefault:\n\t\tthrow std::runtime_error(fmt::format(\"invalid audio api: {}\", api));\n\t}\n}\n"
  },
  {
    "path": "src/audio/IAudioInputAPI.h",
    "content": "#pragma once\n\nclass IAudioInputAPI\n{\n\tfriend class GeneralSettings2;\n\npublic:\n\tclass DeviceDescription\n\t{\n\tpublic:\n\t\texplicit DeviceDescription(std::wstring name)\n\t\t\t: m_name(std::move(name)) { }\n\n\t\tvirtual ~DeviceDescription() = default;\n\t\tvirtual std::wstring GetIdentifier() const = 0;\n\t\tconst std::wstring& GetName() const { return m_name; }\n\n\t\tbool operator==(const DeviceDescription& o) const\n\t\t{\n\t\t\treturn GetIdentifier() == o.GetIdentifier();\n\t\t}\n\n\tprivate:\n\t\tstd::wstring m_name;\n\t};\n\n\tusing DeviceDescriptionPtr = std::shared_ptr<DeviceDescription>;\n\n\tenum AudioInputAPI\n\t{\n\t\tCubeb,\n\n\t\tAudioInputAPIEnd,\n\t};\n\tstatic constexpr uint32 kBlockCount = 24;\n\n\tIAudioInputAPI(uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample);\n\tvirtual ~IAudioInputAPI() = default;\n\tvirtual AudioInputAPI GetType() const = 0;\n\n\tsint32 GetChannels() const { return m_channels; }\n\n\tvirtual sint32 GetVolume() const { return m_volume; }\n\tvirtual void SetVolume(sint32 volume) { m_volume = volume; }\n\n\tvirtual bool ConsumeBlock(sint16* data) = 0;\n\tvirtual bool Play() = 0;\n\tvirtual bool Stop() = 0;\n\tvirtual bool IsPlaying() const = 0;\n\n\tstatic void PrintLogging();\n\tstatic void InitializeStatic();\n\tstatic bool IsAudioInputAPIAvailable(AudioInputAPI api);\n\n\tstatic std::unique_ptr<IAudioInputAPI> CreateDevice(AudioInputAPI api, const DeviceDescriptionPtr& device, sint32 samplerate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample);\n\tstatic std::vector<DeviceDescriptionPtr> GetDevices(AudioInputAPI api);\n\nprotected:\n\tuint32 m_samplerate, m_channels, m_samplesPerBlock, m_bitsPerSample;\n\tuint32 m_bytesPerBlock;\n\n\tsint32 m_volume = 0;\n\n\tstatic std::array<bool, AudioInputAPIEnd> s_availableApis;\n\nprivate:\n};\n\nusing AudioInputAPIPtr = std::unique_ptr<IAudioInputAPI>;\nextern std::shared_mutex g_audioInputMutex;\nextern AudioInputAPIPtr g_inputAudio;\n"
  },
  {
    "path": "src/audio/XAudio27API.cpp",
    "content": "#include \"XAudio27API.h\"\n\n#include \"../dependencies/DirectX_2010/XAudio2.h\"\n\nstatic_assert(IAudioAPI::kBlockCount < XAUDIO2_MAX_QUEUED_BUFFERS, \"too many xaudio2 buffers\");\n\nHMODULE XAudio27API::s_xaudio_dll = nullptr;\nstd::unique_ptr<IXAudio2, XAudio27API::XAudioDeleter> XAudio27API::s_xaudio;\n\nXAudio27API::XAudio27API(uint32 device_id, uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample)\n\t: IAudioAPI(samplerate, channels, samples_per_block, bits_per_sample)\n{\n\tif (!s_xaudio)\n\t\tthrow std::runtime_error(\"xaudio 2.7 not initialized!\");\n\n\t// we use -1 for always selecting the primary device, which is the first one\n\tif (device_id == -1)\n\t\tdevice_id = 0;\n\n\tHRESULT hres;\n\tIXAudio2* xaudio;\n\tif (FAILED((hres = XAudio2Create(&xaudio, 0, XAUDIO2_DEFAULT_PROCESSOR))))\n\t\tthrow std::runtime_error(fmt::format(\"can't create xaudio device (hres: {:#x})\", hres));\n\tm_xaudio = decltype(m_xaudio)(xaudio);\n\n\tIXAudio2MasteringVoice* mastering_voice;\n\tif (FAILED((hres = m_xaudio->CreateMasteringVoice(&mastering_voice, channels, samplerate, 0, device_id))))\n\t\tthrow std::runtime_error(fmt::format(\"can't create xaudio mastering voice (hres: {:#x})\", hres));\n\n\tm_mastering_voice = decltype(m_mastering_voice)(mastering_voice);\n\n\tm_wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;\n\tm_wfx.Format.nChannels = channels;\n\tm_wfx.Format.nSamplesPerSec = samplerate;\n\tm_wfx.Format.wBitsPerSample = bits_per_sample;\n\tm_wfx.Format.nBlockAlign = (m_wfx.Format.nChannels * m_wfx.Format.wBitsPerSample) / 8; // must equal (nChannels × wBitsPerSample) / 8\n\tm_wfx.Format.nAvgBytesPerSec = m_wfx.Format.nSamplesPerSec * m_wfx.Format.nBlockAlign; // must equal nSamplesPerSec × nBlockAlign.\n\tm_wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);\n\n\tm_wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;\n\tm_wfx.Samples.wValidBitsPerSample = bits_per_sample;\n\tswitch (channels)\n\t{\n\tcase 8:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER);\n\t\tbreak;\n\tcase 6:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT);\n\t\tbreak;\n\tcase 4:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT);\n\t\tbreak;\n\tcase 2:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT);\n\t\tbreak;\n\tdefault:\n\t\tm_wfx.dwChannelMask = 0;\n\t\tbreak;\n\t}\n\n\tIXAudio2SourceVoice* source_voice;\n\tif (FAILED((hres = m_xaudio->CreateSourceVoice(&source_voice, &m_wfx.Format, 0, 1.0f))))\n\t\tthrow std::runtime_error(fmt::format(\"can't create xaudio source voice (hres: {:#x})\", hres));\n\tm_source_voice = decltype(m_source_voice)(source_voice);\n\n\tm_sound_buffer_size = kBlockCount * (samples_per_block * channels * (bits_per_sample / 8));\n\n\tfor (uint32 i = 0; i < kBlockCount; ++i)\n\t\tm_audio_buffer[i] = std::make_unique<uint8[]>(m_bytesPerBlock);\n\n\tm_xaudio->StartEngine();\n}\n\nXAudio27API::~XAudio27API()\n{\n\tif(m_xaudio)\n\t\tm_xaudio->StopEngine();\n\n\tXAudio27API::Stop();\n\n\tm_source_voice.reset();\n\tm_mastering_voice.reset();\n\tm_xaudio.reset();\n}\n\nvoid XAudio27API::SetVolume(sint32 volume)\n{\n\tIAudioAPI::SetVolume(volume);\n\tm_mastering_voice->SetVolume((float)volume / 100.0f);\n}\n\nbool XAudio27API::Play()\n{\n\tif (m_playing)\n\t\treturn true;\n\n\tm_playing = SUCCEEDED(m_source_voice->Start());\n\treturn m_playing;\n}\n\nbool XAudio27API::Stop()\n{\n\tif (!m_playing)\n\t\treturn true;\n\n\tm_playing = FAILED(m_source_voice->Stop());\n\tm_source_voice->FlushSourceBuffers();\n\n\treturn m_playing;\n}\n\nbool XAudio27API::InitializeStatic()\n{\n\tif (s_xaudio)\n\t\treturn true;\n\n#ifdef _DEBUG\n\ts_xaudio_dll = LoadLibraryExW(L\"XAudioD2_7.DLL\", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);\n\tif(!s_xaudio_dll)\n\t\ts_xaudio_dll = LoadLibraryExW(L\"XAudio2_7.DLL\", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);\n#else\n\ts_xaudio_dll = LoadLibraryExW(L\"XAudio2_7.DLL\", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);\n#endif\n\n\ttry\n\t{\n\t\tif (!s_xaudio_dll)\n\t\t\tthrow std::exception();\n\n\t\tIXAudio2* xaudio;\n\t\tif (FAILED(XAudio2Create(&xaudio, 0, XAUDIO2_DEFAULT_PROCESSOR)))\n\t\t\tthrow std::exception();\n\n\t\ts_xaudio = decltype(s_xaudio)(xaudio);\n\t\treturn true;\n\t}\n\tcatch (const std::exception&)\n\t{\n\t\tif (s_xaudio_dll)\n\t\t\tFreeLibrary(s_xaudio_dll);\n\n\t\treturn false;\n\t}\n}\n\nvoid XAudio27API::Destroy()\n{\n\ts_xaudio.reset();\n\n\tif (s_xaudio_dll)\n\t\tFreeLibrary(s_xaudio_dll);\n}\n\nstd::vector<XAudio27API::DeviceDescriptionPtr> XAudio27API::GetDevices()\n{\n\tstd::vector<DeviceDescriptionPtr> result;\n\n\t// always add the default device\n\tauto default_device = std::make_shared<XAudio27DeviceDescription>(L\"Primary Sound Driver\", L\"\", -1);\n\tresult.emplace_back(default_device);\n\n\tuint32 count = 0;\n\tif (FAILED(s_xaudio->GetDeviceCount(&count)))\n\t\treturn result;\n\n\tif (!count)\n\t\treturn result;\n\n\tresult.reserve(count + 1);\n\n\t// first device is always the primary device\n\tfor (uint32 id = 0; id < count; ++id)\n\t{\n\t\tXAUDIO2_DEVICE_DETAILS details;\n\t\tif (SUCCEEDED(s_xaudio->GetDeviceDetails(id, &details)))\n\t\t{\n\t\t\tauto device = std::make_shared<XAudio27DeviceDescription>(details.DisplayName, details.DeviceID, id);\n\t\t\tresult.emplace_back(device);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nvoid XAudio27API::XAudioDeleter::operator()(IXAudio2* ptr) const\n{\n\tif (ptr) \n\t\tptr->Release();\n}\n\nvoid XAudio27API::VoiceDeleter::operator()(IXAudio2Voice* ptr) const\n{\n\tif (ptr) \n\t\tptr->DestroyVoice();\n}\n\nbool XAudio27API::FeedBlock(sint16* data)\n{\n\t// check if we queued too many blocks\n\tif(m_blocks_queued >= kBlockCount)\n\t{\n\t\tm_blocks_queued = GetQueuedBuffers();\n\n\t\tif (m_blocks_queued >= kBlockCount)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"dropped xaudio2 block since too many buffers are queued\");\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tmemcpy(m_audio_buffer[m_offset].get(), data, m_bytesPerBlock);\n\n\tXAUDIO2_BUFFER buffer{};\n\tbuffer.AudioBytes = m_bytesPerBlock;\n\tbuffer.pAudioData = m_audio_buffer[m_offset].get();\n\tm_source_voice->SubmitSourceBuffer(&buffer);\n\n\tm_offset = (m_offset + 1) % kBlockCount;\n\tm_blocks_queued++;\n\treturn true;\n}\n\nuint32 XAudio27API::GetQueuedBuffers() const\n{\n\tXAUDIO2_VOICE_STATE state{};\n\tm_source_voice->GetState(&state);\n\treturn state.BuffersQueued;\n}\n\nbool XAudio27API::NeedAdditionalBlocks() const\n{\n\treturn GetQueuedBuffers() < GetAudioDelay();\n}\n"
  },
  {
    "path": "src/audio/XAudio27API.h",
    "content": "#pragma once\n\n#define DIRECTSOUND_VERSION 0x0800\n#include <mmsystem.h>\n#include <mmreg.h>\n#include <dsound.h>\n\n#include \"IAudioAPI.h\"\n\nstruct IXAudio2;\nstruct IXAudio2Voice;\nstruct IXAudio2MasteringVoice;\nstruct IXAudio2SourceVoice;\n\nclass XAudio27API : public IAudioAPI\n{\npublic:\n\tclass XAudio27DeviceDescription : public DeviceDescription\n\t{\n\tpublic:\n\t\tXAudio27DeviceDescription(const std::wstring& name, std::wstring device_id, uint32 id)\n\t\t\t: DeviceDescription(name), m_device_id(std::move(device_id)), m_id(id) { }\n\n\t\tstd::wstring GetIdentifier() const override { return m_device_id.empty() ? L\"default\" : m_device_id; }\n\t\tuint32 GetDeviceId() const { return m_id; }\n\n\tprivate:\n\t\tstd::wstring m_device_id;\n\t\tconst uint32 m_id;\n\t};\n\n\tusing XAudio2DeviceDescriptionPtr = std::shared_ptr<XAudio27DeviceDescription>;\n\n\tAudioAPI GetType() const override { return XAudio27; }\n\n\tXAudio27API(uint32 device_id, uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample);\n\t~XAudio27API();\n\tvoid SetVolume(sint32 volume) override;\n\n\tbool Play() override;\n\tbool Stop() override;\n\tbool FeedBlock(sint16* data) override;\n\tbool NeedAdditionalBlocks() const override;\n\n\tstatic bool InitializeStatic();\n\tstatic void Destroy();\n\tstatic std::vector<DeviceDescriptionPtr> GetDevices();\n\nprivate:\n\tuint32 GetQueuedBuffers() const;\n\n\tstruct XAudioDeleter\n\t{\n\t\tvoid operator()(IXAudio2* ptr) const;\n\t};\n\n\tstruct VoiceDeleter\n\t{\n\t\tvoid operator()(IXAudio2Voice* ptr) const;\n\t};\n\n\tstatic HMODULE s_xaudio_dll;\n\tstatic std::unique_ptr<IXAudio2, XAudioDeleter> s_xaudio;\n\n\tstd::unique_ptr<IXAudio2, XAudioDeleter> m_xaudio;\n\tstd::wstring m_device_id;\n\tstd::unique_ptr<IXAudio2MasteringVoice, VoiceDeleter> m_mastering_voice;\n\tstd::unique_ptr<IXAudio2SourceVoice, VoiceDeleter> m_source_voice;\n\t\n\tstd::unique_ptr<uint8[]> m_audio_buffer[kBlockCount];\n\tDWORD m_sound_buffer_size = 0;\n\tuint32_t m_offset = 0;\n\tuint32_t m_blocks_queued = 0;\n};\n"
  },
  {
    "path": "src/audio/XAudio2API.cpp",
    "content": "\n\n//#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)\n\n#include <wrl/client.h>\n#include <xaudio2.h>\n\n#ifndef XAUDIO2_DLL\n#error wrong <xaudio2.h> included!\n#endif\n\n#include \"XAudio2API.h\"\n#include \"util/helpers/helpers.h\"\n\n#include <WbemCli.h>\n#include <OleAuto.h>\n#include <system_error>\n\n// guid from mmdeviceapi.h\nstatic const GUID DEVINTERFACE_AUDIO_RENDER_GUID = { 0xe6327cad, 0xdcec, 0x4949, 0xae, 0x8a, 0x99, 0x1e, 0x97, 0x6a, 0x79, 0xd2 };\n\n#pragma comment(lib, \"wbemuuid.lib\")\n\nstatic_assert(IAudioAPI::kBlockCount < XAUDIO2_MAX_QUEUED_BUFFERS, \"too many xaudio2 buffers\");\n\nHMODULE XAudio2API::s_xaudio_dll = nullptr;\nstd::vector<XAudio2API::DeviceDescriptionPtr> XAudio2API::s_devices;\n\nXAudio2API::XAudio2API(std::wstring device_id, uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample)\n\t: IAudioAPI(samplerate, channels, samples_per_block, bits_per_sample), m_device_id(std::move(device_id))\n{\n\tconst auto _XAudio2Create = (decltype(&XAudio2Create))GetProcAddress(s_xaudio_dll, \"XAudio2Create\");\n\tif (!_XAudio2Create)\n\t\tthrow std::runtime_error(\"can't find XAudio2Create import\");\n\n\tHRESULT hres;\n\tif (FAILED((hres = _XAudio2Create(&m_xaudio, 0, XAUDIO2_DEFAULT_PROCESSOR))))\n\t\tthrow std::runtime_error(fmt::format(\"can't create xaudio device (hres: {:#x})\", hres));\n\n\n\tIXAudio2MasteringVoice* mastering_voice;\n\tif (FAILED((hres = m_xaudio->CreateMasteringVoice(&mastering_voice, channels, samplerate, 0, m_device_id.empty() ? nullptr : m_device_id.c_str()))))\n\t\tthrow std::runtime_error(fmt::format(\"can't create xaudio mastering voice (hres: {:#x})\", hres));\n\n\tm_mastering_voice.reset(mastering_voice);\n\n\tm_wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;\n\tm_wfx.Format.nChannels = channels;\n\tm_wfx.Format.nSamplesPerSec = samplerate;\n\tm_wfx.Format.wBitsPerSample = bits_per_sample;\n\tm_wfx.Format.nBlockAlign = (m_wfx.Format.nChannels * m_wfx.Format.wBitsPerSample) / 8; // must equal (nChannels × wBitsPerSample) / 8\n\tm_wfx.Format.nAvgBytesPerSec = m_wfx.Format.nSamplesPerSec * m_wfx.Format.nBlockAlign; // must equal nSamplesPerSec × nBlockAlign.\n\tm_wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);\n\n\tm_wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;\n\tm_wfx.Samples.wValidBitsPerSample = bits_per_sample;\n\tswitch(channels)\n\t{\n\tcase 8:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER);\n\t\tbreak;\n\tcase 6:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT);\n\t\tbreak;\n\tcase 4:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT);\n\t\tbreak;\n\tcase 2:\n\t\tm_wfx.dwChannelMask |= (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT);\n\t\tbreak;\n\tdefault:\n\t\tm_wfx.dwChannelMask = 0;\n\t\tbreak;\n\t}\n\t\n\tIXAudio2SourceVoice* source_voice;\n\tif (FAILED((hres = m_xaudio->CreateSourceVoice(&source_voice, &m_wfx.Format, 0, 1.0f))))\n\t\tthrow std::runtime_error(fmt::format(\"can't create xaudio source voice (hres: {:#x})\", hres));\n\n\tm_source_voice = decltype(m_source_voice)(source_voice);\n\n\tm_sound_buffer_size = kBlockCount * (samples_per_block * channels * (bits_per_sample / 8));\n\n\tfor (uint32 i = 0; i < kBlockCount; ++i)\n\t\tm_audio_buffer[i] = std::make_unique<uint8[]>(m_bytesPerBlock);\n\n\tm_xaudio->StartEngine();\n}\n\nvoid XAudio2API::VoiceDeleter::operator()(IXAudio2Voice* ptr) const\n{\n\tif (ptr)\n\t\tptr->DestroyVoice();\n}\n\nXAudio2API::~XAudio2API()\n{\n\tif(m_xaudio)\n\t\tm_xaudio->StopEngine();\n\n\tXAudio2API::Stop();\n}\n\nvoid XAudio2API::SetVolume(sint32 volume)\n{\n\tIAudioAPI::SetVolume(volume);\n\tm_mastering_voice->SetVolume((float)volume / 100.0f);\n}\n\nbool XAudio2API::Play()\n{\n\tif (m_playing)\n\t\treturn true;\n\n\tm_playing = SUCCEEDED(m_source_voice->Start());\n\treturn m_playing;\n}\n\nbool XAudio2API::Stop()\n{\n\tif (!m_playing)\n\t\treturn true;\n\n\tm_playing = FAILED(m_source_voice->Stop());\n\tm_source_voice->FlushSourceBuffers();\n\n\treturn m_playing;\n}\n\nbool XAudio2API::InitializeStatic()\n{\n\tif (s_xaudio_dll)\n\t\treturn true;\n\n\t// win 10\n\ts_xaudio_dll = LoadLibraryEx(XAUDIO2_DLL, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);\n\n\ttry\n\t{\n\t\tif (!s_xaudio_dll)\n\t\t\tthrow std::exception();\n\n\t\tconst auto _XAudio2Create = (decltype(&XAudio2Create))GetProcAddress(s_xaudio_dll, \"XAudio2Create\");\n\t\tif (!_XAudio2Create)\n\t\t\tthrow std::exception();\n\n\t\tRefreshDevices();\n\t\treturn true;\n\t}\n\tcatch (const std::exception&)\n\t{\n\t\tif (s_xaudio_dll)\n\t\t\tFreeLibrary(s_xaudio_dll);\n\n\t\treturn false;\n\t}\n}\n\nvoid XAudio2API::Destroy()\n{\n\tif (s_xaudio_dll)\n\t\tFreeLibrary(s_xaudio_dll);\n}\n\nconst std::vector<XAudio2API::DeviceDescriptionPtr>& XAudio2API::RefreshDevices()\n{\n\ts_devices.clear();\n\n\ttry\n\t{\n\t\tMicrosoft::WRL::ComPtr<IWbemLocator> wbem_locator;\n\n\t\tHRESULT hres = CoCreateInstance(__uuidof(WbemLocator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&wbem_locator));\n\t\tif (FAILED(hres))\n\t\t\tthrow std::system_error(hres, std::system_category());\n\n\t\tstd::shared_ptr<OLECHAR> path(SysAllocString(LR\"(\\\\.\\root\\cimv2)\"), SysFreeString);\n\t\tstd::shared_ptr<OLECHAR> language(SysAllocString(L\"WQL\"), SysFreeString);\n\t\tstd::shared_ptr<OLECHAR> query(SysAllocString(LR\"(SELECT Name,DeviceID FROM Win32_PNPEntity WHERE PNPClass = \"AudioEndpoint\")\"), SysFreeString);\n\t\tstd::shared_ptr<OLECHAR> name_row(SysAllocString(L\"Name\"), SysFreeString);\n\t\tstd::shared_ptr<OLECHAR> device_id_row(SysAllocString(L\"DeviceID\"), SysFreeString);\n\n\t\tMicrosoft::WRL::ComPtr<IWbemServices> wbem_services;\n\t\thres = wbem_locator->ConnectServer(path.get(), nullptr, nullptr, nullptr, 0, nullptr, nullptr, &wbem_services);\n\n\t\tif (FAILED(hres))\n\t\t\tthrow std::system_error(hres, std::system_category());\n\n\t\thres = CoSetProxyBlanket(wbem_services.Get(), RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);\n\t\tif (FAILED(hres))\n\t\t\tthrow std::system_error(hres, std::system_category());\n\n\t\tMicrosoft::WRL::ComPtr<IEnumWbemClassObject> wbem_enum;\n\t\thres = wbem_services->ExecQuery(language.get(), query.get(), WBEM_FLAG_RETURN_WBEM_COMPLETE | WBEM_FLAG_FORWARD_ONLY, nullptr, &wbem_enum);\n\t\tif (FAILED(hres))\n\t\t\tthrow std::system_error(hres, std::system_category());\n\n\t\tULONG returned;\n\t\tIWbemClassObject* object[20];\n\t\t// WBEM_S_TIMEDOUT\n\t\twhile (SUCCEEDED(hres = wbem_enum->Next(100, 20, object, &returned)) && returned > 0)\n\t\t{\n\t\t\tfor (ULONG i = 0; i < returned; ++i)\n\t\t\t{\n\t\t\t\tstd::wstring name, device_id;\n\n\t\t\t\tVARIANT var;\n\t\t\t\tif (SUCCEEDED(object[i]->Get(name_row.get(), 0L, &var, NULL, NULL)) && var.vt == VT_BSTR && var.bstrVal)\n\t\t\t\t{\n\t\t\t\t\tname = var.bstrVal;\n\t\t\t\t\tif (SUCCEEDED(object[i]->Get(device_id_row.get(), 0L, &var, NULL, NULL)) && var.vt == VT_BSTR && var.bstrVal)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::wstring id = var.bstrVal;\n\n\t\t\t\t\t\tif(id.find(L\"{0.0.0.00000000}\") == std::wstring::npos)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tobject[i]->Release();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstd::replace(id.begin(), id.end(), L'\\\\', L'#'); // xaudio devices have \"#\" instead of backslashes\n\t\t\t\t\t\t\n\t\t\t\t\t\tstd::wstringstream tmp;\n\t\t\t\t\t\ttmp << L\"\\\\\\\\?\\\\\" << id << L\"#{\" << WStringFromGUID(DEVINTERFACE_AUDIO_RENDER_GUID) << L\"}\";\n\t\t\t\t\t\tdevice_id = tmp.str();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\tauto device = std::make_shared<XAudio2DeviceDescription>(name,device_id);\n\t\t\t\ts_devices.emplace_back(device);\n\n\t\t\t\tobject[i]->Release();\n\t\t\t}\n\t\t}\n\n\t\t// Only add default device if audio devices exist\n\t\tif (s_devices.size() > 0) {\n\t\t\tauto default_device = std::make_shared<XAudio2DeviceDescription>(L\"Primary Sound Driver\", L\"\");\n\t\t\ts_devices.insert(s_devices.begin(), default_device);\n\t\t}\n\t}\n\tcatch (const std::system_error& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"XAudio2API::RefreshDevices: error while refreshing device list ({} - code: 0x{:08x})\", ex.what(), ex.code().value());\n\t}\n\n\tCoUninitialize();\n\treturn s_devices;\n}\n\nbool XAudio2API::FeedBlock(sint16* data)\n{\n\t// check if we queued too many blocks\n\tif (m_blocks_queued >= kBlockCount)\n\t{\n\t\tm_blocks_queued = GetQueuedBuffers();\n\n\t\tif (m_blocks_queued >= kBlockCount)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"dropped xaudio2 block since too many buffers are queued\");\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tmemcpy(m_audio_buffer[m_offset].get(), data, m_bytesPerBlock);\n\n\tXAUDIO2_BUFFER buffer{};\n\tbuffer.AudioBytes = m_bytesPerBlock;\n\tbuffer.pAudioData = m_audio_buffer[m_offset].get();\n\tm_source_voice->SubmitSourceBuffer(&buffer);\n\n\tm_offset = (m_offset + 1) % kBlockCount;\n\tm_blocks_queued++;\n\treturn true;\n}\n\nuint32 XAudio2API::GetQueuedBuffers() const\n{\n\tXAUDIO2_VOICE_STATE state{};\n\tm_source_voice->GetState(&state);\n\treturn state.BuffersQueued;\n}\n\nbool XAudio2API::NeedAdditionalBlocks() const\n{\n\treturn GetQueuedBuffers() < GetAudioDelay();\n}\n"
  },
  {
    "path": "src/audio/XAudio2API.h",
    "content": "#pragma once\n\n#define DIRECTSOUND_VERSION 0x0800\n#include <mmsystem.h>\n#include <mmreg.h>\n#include <dsound.h>\n#include <wrl/client.h>\n\n#include \"IAudioAPI.h\"\n\nstruct IXAudio2;\nstruct IXAudio2Voice;\nstruct IXAudio2MasteringVoice;\nstruct IXAudio2SourceVoice;\n\nclass XAudio2API : public IAudioAPI\n{\npublic:\n\tclass XAudio2DeviceDescription : public DeviceDescription\n\t{\n\tpublic:\n\t\tXAudio2DeviceDescription(const std::wstring& name, std::wstring device_id)\n\t\t\t: DeviceDescription(name), m_device_id(std::move(device_id)) { }\n\n\t\tstd::wstring GetIdentifier() const override { return m_device_id.empty() ? L\"default\" : m_device_id; }\n\t\tconst std::wstring& GetDeviceId() const { return m_device_id; }\n\n\tprivate:\n\t\tstd::wstring m_device_id;\n\t};\n\n\tusing XAudio2DeviceDescriptionPtr = std::shared_ptr<XAudio2DeviceDescription>;\n\n\tAudioAPI GetType() const override { return XAudio27; }\n\n\tXAudio2API(std::wstring device_id, uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample);\n\t~XAudio2API();\n\tvoid SetVolume(sint32 volume) override;\n\n\tbool Play() override;\n\tbool Stop() override;\n\tbool FeedBlock(sint16* data) override;\n\tbool NeedAdditionalBlocks() const override;\n\n\tstatic bool InitializeStatic();\n\tstatic void Destroy();\n\tstatic const std::vector<DeviceDescriptionPtr>& GetDevices() { return s_devices;\t}\n\nprivate:\n\tuint32 GetQueuedBuffers() const;\n\n\tstatic const std::vector<DeviceDescriptionPtr>& RefreshDevices();\n\n\tstruct VoiceDeleter\n\t{\n\t\tvoid operator()(IXAudio2Voice* ptr) const;\n\t};\n\n\tstatic HMODULE s_xaudio_dll;\n\tstatic std::vector<DeviceDescriptionPtr> s_devices;\n\n\tMicrosoft::WRL::ComPtr<IXAudio2> m_xaudio;\n\tstd::wstring m_device_id;\n\tstd::unique_ptr<IXAudio2MasteringVoice, VoiceDeleter> m_mastering_voice;\n\tstd::unique_ptr<IXAudio2SourceVoice, VoiceDeleter> m_source_voice;\n\n\tstd::unique_ptr<uint8[]> m_audio_buffer[kBlockCount];\n\tDWORD m_sound_buffer_size = 0;\n\tuint32_t m_offset = 0;\n\tuint32_t m_blocks_queued = 0;\n};\n"
  },
  {
    "path": "src/audio/xaudio2_7/audiodefs.h",
    "content": "/***************************************************************************\n *\n *  Copyright (c) Microsoft Corporation.  All rights reserved.\n *\n *  File:     audiodefs.h\n *  Content:  Basic constants and data types for audio work.\n *\n *  Remarks:  This header file defines all of the audio format constants and\n *            structures required for XAudio2 and XACT work.  Providing these\n *            in a single location avoids certain dependency problems in the\n *            legacy audio headers (mmreg.h, mmsystem.h, ksmedia.h).\n *\n *            NOTE: Including the legacy headers after this one may cause a\n *            compilation error, because they define some of the same types\n *            defined here without preprocessor guards to avoid multiple\n *            definitions.  If a source file needs one of the old headers,\n *            it must include it before including audiodefs.h.\n *\n ***************************************************************************/\n\n#ifndef __AUDIODEFS_INCLUDED__\n#define __AUDIODEFS_INCLUDED__\n\n#include <windef.h>  // For WORD, DWORD, etc.\n\n#pragma pack(push, 1)  // Pack structures to 1-byte boundaries\n\n\n/**************************************************************************\n *\n *  WAVEFORMATEX: Base structure for many audio formats.  Format-specific\n *  extensions can be defined for particular formats by using a non-zero\n *  cbSize value and adding extra fields to the end of this structure.\n *\n ***************************************************************************/\n\n#ifndef _WAVEFORMATEX_\n\n    #define _WAVEFORMATEX_\n    typedef struct tWAVEFORMATEX\n    {\n        WORD wFormatTag;        // Integer identifier of the format\n        WORD nChannels;         // Number of audio channels\n        DWORD nSamplesPerSec;   // Audio sample rate\n        DWORD nAvgBytesPerSec;  // Bytes per second (possibly approximate)\n        WORD nBlockAlign;       // Size in bytes of a sample block (all channels)\n        WORD wBitsPerSample;    // Size in bits of a single per-channel sample\n        WORD cbSize;            // Bytes of extra data appended to this struct\n    } WAVEFORMATEX;\n\n#endif\n\n// Defining pointer types outside of the #if block to make sure they are\n// defined even if mmreg.h or mmsystem.h is #included before this file\n\ntypedef WAVEFORMATEX *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;\ntypedef const WAVEFORMATEX *PCWAVEFORMATEX, *LPCWAVEFORMATEX;\n\n\n/**************************************************************************\n *\n *  WAVEFORMATEXTENSIBLE: Extended version of WAVEFORMATEX that should be\n *  used as a basis for all new audio formats.  The format tag is replaced\n *  with a GUID, allowing new formats to be defined without registering a\n *  format tag with Microsoft.  There are also new fields that can be used\n *  to specify the spatial positions for each channel and the bit packing\n *  used for wide samples (e.g. 24-bit PCM samples in 32-bit containers).\n *\n ***************************************************************************/\n\n#ifndef _WAVEFORMATEXTENSIBLE_\n\n    #define _WAVEFORMATEXTENSIBLE_\n    typedef struct\n    {\n        WAVEFORMATEX Format;          // Base WAVEFORMATEX data\n        union\n        {\n            WORD wValidBitsPerSample; // Valid bits in each sample container\n            WORD wSamplesPerBlock;    // Samples per block of audio data; valid\n                                      // if wBitsPerSample=0 (but rarely used).\n            WORD wReserved;           // Zero if neither case above applies.\n        } Samples;\n        DWORD dwChannelMask;          // Positions of the audio channels\n        GUID SubFormat;               // Format identifier GUID\n    } WAVEFORMATEXTENSIBLE;\n\n#endif\n\ntypedef WAVEFORMATEXTENSIBLE *PWAVEFORMATEXTENSIBLE, *LPWAVEFORMATEXTENSIBLE;\ntypedef const WAVEFORMATEXTENSIBLE *PCWAVEFORMATEXTENSIBLE, *LPCWAVEFORMATEXTENSIBLE;\n\n\n\n/**************************************************************************\n *\n *  Define the most common wave format tags used in WAVEFORMATEX formats.\n *\n ***************************************************************************/\n\n#ifndef WAVE_FORMAT_PCM  // Pulse Code Modulation\n\n    // If WAVE_FORMAT_PCM is not defined, we need to define some legacy types\n    // for compatibility with the Windows mmreg.h / mmsystem.h header files.\n\n    // Old general format structure (information common to all formats)\n    typedef struct waveformat_tag\n    {\n        WORD wFormatTag;\n        WORD nChannels;\n        DWORD nSamplesPerSec;\n        DWORD nAvgBytesPerSec;\n        WORD nBlockAlign;\n    } WAVEFORMAT, *PWAVEFORMAT, NEAR *NPWAVEFORMAT, FAR *LPWAVEFORMAT;\n\n    // Specific format structure for PCM data\n    typedef struct pcmwaveformat_tag\n    {\n        WAVEFORMAT wf;\n        WORD wBitsPerSample;\n    } PCMWAVEFORMAT, *PPCMWAVEFORMAT, NEAR *NPPCMWAVEFORMAT, FAR *LPPCMWAVEFORMAT;\n\n    #define WAVE_FORMAT_PCM 0x0001\n\n#endif\n\n#ifndef WAVE_FORMAT_ADPCM  // Microsoft Adaptive Differental PCM\n\n    // Replicate the Microsoft ADPCM type definitions from mmreg.h.\n\n    typedef struct adpcmcoef_tag\n    {\n        short iCoef1;\n        short iCoef2;\n    } ADPCMCOEFSET;\n\n    #pragma warning(push)\n    #pragma warning(disable:4200)  // Disable zero-sized array warnings\n\n    typedef struct adpcmwaveformat_tag {\n        WAVEFORMATEX wfx;\n        WORD wSamplesPerBlock;\n        WORD wNumCoef;\n        ADPCMCOEFSET aCoef[];  // Always 7 coefficient pairs for MS ADPCM\n    } ADPCMWAVEFORMAT;\n\n    #pragma warning(pop)\n\n    #define WAVE_FORMAT_ADPCM 0x0002\n\n#endif\n\n// Other frequently used format tags\n\n#ifndef WAVE_FORMAT_UNKNOWN\n    #define WAVE_FORMAT_UNKNOWN         0x0000 // Unknown or invalid format tag\n#endif\n\n#ifndef WAVE_FORMAT_IEEE_FLOAT\n    #define WAVE_FORMAT_IEEE_FLOAT      0x0003 // 32-bit floating-point\n#endif\n\n#ifndef WAVE_FORMAT_MPEGLAYER3\n    #define WAVE_FORMAT_MPEGLAYER3      0x0055 // ISO/MPEG Layer3\n#endif\n\n#ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF\n    #define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 // Dolby Audio Codec 3 over S/PDIF\n#endif\n\n#ifndef WAVE_FORMAT_WMAUDIO2\n    #define WAVE_FORMAT_WMAUDIO2        0x0161 // Windows Media Audio\n#endif\n\n#ifndef WAVE_FORMAT_WMAUDIO3\n    #define WAVE_FORMAT_WMAUDIO3        0x0162 // Windows Media Audio Pro\n#endif\n\n#ifndef WAVE_FORMAT_WMASPDIF\n    #define WAVE_FORMAT_WMASPDIF        0x0164 // Windows Media Audio over S/PDIF\n#endif\n\n#ifndef WAVE_FORMAT_EXTENSIBLE\n    #define WAVE_FORMAT_EXTENSIBLE      0xFFFE // All WAVEFORMATEXTENSIBLE formats\n#endif\n\n\n/**************************************************************************\n *\n *  Define the most common wave format GUIDs used in WAVEFORMATEXTENSIBLE\n *  formats.  Note that including the Windows ksmedia.h header after this\n *  one will cause build problems; this cannot be avoided, since ksmedia.h\n *  defines these macros without preprocessor guards.\n *\n ***************************************************************************/\n\n#ifdef __cplusplus // uuid() and __uuidof() are only available in C++\n\n    #ifndef KSDATAFORMAT_SUBTYPE_PCM\n        struct __declspec(uuid(\"00000001-0000-0010-8000-00aa00389b71\")) KSDATAFORMAT_SUBTYPE_PCM_STRUCT;\n        #define KSDATAFORMAT_SUBTYPE_PCM __uuidof(KSDATAFORMAT_SUBTYPE_PCM_STRUCT)\n    #endif\n\n    #ifndef KSDATAFORMAT_SUBTYPE_ADPCM\n        struct __declspec(uuid(\"00000002-0000-0010-8000-00aa00389b71\")) KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT;\n        #define KSDATAFORMAT_SUBTYPE_ADPCM __uuidof(KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT)\n    #endif\n\n    #ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n        struct __declspec(uuid(\"00000003-0000-0010-8000-00aa00389b71\")) KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT;\n        #define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT __uuidof(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT)\n    #endif\n\n#endif\n\n\n/**************************************************************************\n *\n *  Speaker positions used in the WAVEFORMATEXTENSIBLE dwChannelMask field.\n *\n ***************************************************************************/\n\n#ifndef SPEAKER_FRONT_LEFT\n    #define SPEAKER_FRONT_LEFT            0x00000001\n    #define SPEAKER_FRONT_RIGHT           0x00000002\n    #define SPEAKER_FRONT_CENTER          0x00000004\n    #define SPEAKER_LOW_FREQUENCY         0x00000008\n    #define SPEAKER_BACK_LEFT             0x00000010\n    #define SPEAKER_BACK_RIGHT            0x00000020\n    #define SPEAKER_FRONT_LEFT_OF_CENTER  0x00000040\n    #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080\n    #define SPEAKER_BACK_CENTER           0x00000100\n    #define SPEAKER_SIDE_LEFT             0x00000200\n    #define SPEAKER_SIDE_RIGHT            0x00000400\n    #define SPEAKER_TOP_CENTER            0x00000800\n    #define SPEAKER_TOP_FRONT_LEFT        0x00001000\n    #define SPEAKER_TOP_FRONT_CENTER      0x00002000\n    #define SPEAKER_TOP_FRONT_RIGHT       0x00004000\n    #define SPEAKER_TOP_BACK_LEFT         0x00008000\n    #define SPEAKER_TOP_BACK_CENTER       0x00010000\n    #define SPEAKER_TOP_BACK_RIGHT        0x00020000\n    #define SPEAKER_RESERVED              0x7FFC0000\n    #define SPEAKER_ALL                   0x80000000\n    #define _SPEAKER_POSITIONS_\n#endif\n\n#ifndef SPEAKER_STEREO\n    #define SPEAKER_MONO             (SPEAKER_FRONT_CENTER)\n    #define SPEAKER_STEREO           (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)\n    #define SPEAKER_2POINT1          (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY)\n    #define SPEAKER_SURROUND         (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER)\n    #define SPEAKER_QUAD             (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)\n    #define SPEAKER_4POINT1          (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)\n    #define SPEAKER_5POINT1          (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)\n    #define SPEAKER_7POINT1          (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER)\n    #define SPEAKER_5POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)\n    #define SPEAKER_7POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT  | SPEAKER_SIDE_RIGHT)\n#endif\n\n\n#pragma pack(pop)\n\n#endif // #ifndef __AUDIODEFS_INCLUDED__\n"
  },
  {
    "path": "src/audio/xaudio2_7/comdecl.h",
    "content": "// comdecl.h: Macros to facilitate COM interface and GUID declarations.\n// Copyright (c) Microsoft Corporation.  All rights reserved.\n\n#ifndef _COMDECL_H_\n#define _COMDECL_H_\n\n#ifndef _XBOX\n    #include <basetyps.h>   // For standard COM interface macros\n#else\n    #pragma warning(push)\n    #pragma warning(disable:4061)\n    #include <xtl.h>        // Required by xobjbase.h\n    #include <xobjbase.h>   // Special definitions for Xbox build\n    #pragma warning(pop)\n#endif\n\n// The DEFINE_CLSID() and DEFINE_IID() macros defined below allow COM GUIDs to\n// be declared and defined in such a way that clients can obtain the GUIDs using\n// either the __uuidof() extension or the old-style CLSID_Foo / IID_IFoo names.\n// If using the latter approach, the client can also choose whether to get the\n// GUID definitions by defining the INITGUID preprocessor constant or by linking\n// to a GUID library.  This works in either C or C++.\n\n#ifdef __cplusplus\n\n    #define DECLSPEC_UUID_WRAPPER(x) __declspec(uuid(#x))\n    #ifdef INITGUID\n\n        #define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n            class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \\\n            EXTERN_C const GUID DECLSPEC_SELECTANY CLSID_##className = __uuidof(className)\n\n        #define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n            interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \\\n            EXTERN_C const GUID DECLSPEC_SELECTANY IID_##interfaceName = __uuidof(interfaceName)\n\n    #else // INITGUID\n\n        #define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n            class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \\\n            EXTERN_C const GUID CLSID_##className\n\n        #define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n            interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \\\n            EXTERN_C const GUID IID_##interfaceName\n\n    #endif // INITGUID\n\n#else // __cplusplus\n\n    #define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n        DEFINE_GUID(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)\n\n    #define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \\\n        DEFINE_GUID(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)\n\n#endif // __cplusplus\n\n#endif // #ifndef _COMDECL_H_\n"
  },
  {
    "path": "src/audio/xaudio2_7/dxsdkver.h",
    "content": "/*==========================================================================;\n *\n *\n *  File:   dxsdkver.h\n *  Content:    DirectX SDK Version Include File\n *\n ****************************************************************************/\n\n#ifndef _DXSDKVER_H_\n#define _DXSDKVER_H_\n\n#define _DXSDK_PRODUCT_MAJOR  9     \n#define _DXSDK_PRODUCT_MINOR  29        \n#define _DXSDK_BUILD_MAJOR    1962        \n#define _DXSDK_BUILD_MINOR    0        \n\n#endif // _DXSDKVER_H_\n\n"
  },
  {
    "path": "src/audio/xaudio2_7/xma2defs.h",
    "content": "/***************************************************************************\n *\n * Copyright (c) Microsoft Corporation.  All rights reserved.\n *\n * File:     xma2defs.h\n * Content:  Constants, data types and functions for XMA2 compressed audio.\n *\n ***************************************************************************/\n\n#ifndef __XMA2DEFS_INCLUDED__\n#define __XMA2DEFS_INCLUDED__\n\n#include <sal.h>        // Markers for documenting API semantics\n#include <winerror.h>   // For S_OK, E_FAIL\n#include \"audiodefs.h\"  // Basic data types and constants for audio work\n\n\n/***************************************************************************\n *  Overview\n ***************************************************************************/\n\n// A typical XMA2 file contains these RIFF chunks:\n//\n// 'fmt' or 'XMA2' chunk (or both): A description of the XMA data's structure\n// and characteristics (length, channels, sample rate, loops, block size, etc).\n//\n// 'seek' chunk: A seek table to help navigate the XMA data.\n//\n// 'data' chunk: The encoded XMA2 data.\n//\n// The encoded XMA2 data is structured as a set of BLOCKS, which contain PACKETS,\n// which contain FRAMES, which contain SUBFRAMES (roughly speaking).  The frames\n// in a file may also be divided into several subsets, called STREAMS.\n//\n// FRAME: A variable-sized segment of XMA data that decodes to exactly 512 mono\n//      or stereo PCM samples.  This is the smallest unit of XMA data that can\n//      be decoded in isolation.  Frames are an arbitrary number of bits in\n//      length, and need not be byte-aligned.  See \"XMA frame structure\" below.\n//\n// SUBFRAME: A region of bits in an XMA frame that decodes to 128 mono or stereo\n//      samples.  The XMA decoder cannot decode a subframe in isolation; it needs\n//      a whole frame to work with.  However, it can begin emitting the frame's\n//      decoded samples at any one of the four subframe boundaries.  Subframes\n//      can be addressed for seeking and looping purposes.\n//\n// PACKET: A 2Kb region containing a 32-bit header and some XMA frames.  Frames\n//      can (and usually do) span packets.  A packet's header includes the offset\n//      in bits of the first frame that begins within that packet.  All of the\n//      frames that begin in a given packet belong to the same \"stream\" (see the\n//      Multichannel Audio section below).\n//\n// STREAM: A set of packets within an XMA file that all contain data for the\n//      same mono or stereo component of a PCM file with more than two channels.\n//      The packets comprising a given stream may be interleaved with each other\n//      more or less arbitrarily; see Multichannel Audio.\n//\n// BLOCK: An array of XMA packets; or, to break it down differently, a series of\n//      consecutive XMA frames, padded at the end with reserved data.  A block\n//      must contain at least one 2Kb packet per stream, and it can hold up to\n//      4095 packets (8190Kb), but its size is typically in the 32Kb-128Kb range.\n//      (The size chosen involves a trade-off between memory use and efficiency\n//      of reading from permanent storage.)\n//\n//      XMA frames do not span blocks, so a block is guaranteed to begin with a\n//      set of complete frames, one per stream.  Also, a block in a multi-stream\n//      XMA2 file always contains the same number of samples for each stream;\n//      see Multichannel Audio.\n//\n// The 'data' chunk in an XMA2 file is an array of XMA2WAVEFORMAT.BlockCount XMA\n// blocks, all the same size (as specified in XMA2WAVEFORMAT.BlockSizeInBytes)\n// except for the last one, which may be shorter.\n\n\n// MULTICHANNEL AUDIO: the XMA decoder can only decode raw XMA data into either\n// mono or stereo PCM data.  In order to encode a 6-channel file (say), the file\n// must be deinterleaved into 3 stereo streams that are encoded independently,\n// producing 3 encoded XMA data streams.  Then the packets in these 3 streams\n// are interleaved to produce a single XMA2 file, and some information is added\n// to the file so that the original 6-channel audio can be reconstructed at\n// decode time.  This works using the concept of an XMA stream (see above).\n//\n// The frames for all the streams in an XMA file are interleaved in an arbitrary\n// order.  To locate a frame that belongs to a given stream in a given XMA block,\n// you must examine the first few packets in the block.  Here (and only here) the\n// packets are guaranteed to be presented in stream order, so that all frames\n// beginning in packet 0 belong to stream 0 (the first stereo pair), etc.\n//\n// (This means that when decoding multi-stream XMA files, only entire XMA blocks\n// should be submitted to the decoder; otherwise it cannot know which frames\n// belong to which stream.)\n//\n// Once you have one frame that belongs to a given stream, you can find the next\n// one by looking at the frame's 'NextFrameOffsetBits' value (which is stored in\n// its first 15 bits; see XMAFRAME below).  The GetXmaFrameBitPosition function\n// uses this technique.\n\n\n// SEEKING IN XMA2 FILES: Here is some pseudocode to find the byte position and\n// subframe in an XMA2 file which will contain sample S when decoded.\n//\n// 1. Traverse the seek table to find the XMA2 block containing sample S. The\n//    seek table is an array of big-endian DWORDs, one per block in the file.\n//    The Nth DWORD is the total number of PCM samples that would be obtained\n//    by decoding the entire XMA file up to the end of block N.  Hence, the\n//    block we want is the first one whose seek table entry is greater than S.\n//    (See the GetXmaBlockContainingSample helper function.)\n//\n// 2. Calculate which frame F within the block found above contains sample S.\n//    Since each frame decodes to 512 samples, this is straightforward.  The\n//    first frame in the block produces samples X to X + 512, where X is the\n//    seek table entry for the prior block.  So F is (S - X) / 512.\n//\n// 3. Find the bit offset within the block where frame F starts.  Since frames\n//    are variable-sized, this can only be done by traversing all the frames in\n//    the block until we reach frame F.  (See GetXmaFrameBitPosition.)\n//\n// 4. Frame F has four 128-sample subframes.  To find the subframe containing S,\n//    we can use the formula (S % 512) / 128.\n//\n// In the case of multi-stream XMA files, sample S is a multichannel sample with\n// parts coming from several frames, one per stream.  To find all these frames,\n// steps 2-4 need to be repeated for each stream N, using the knowledge that the\n// first packets in a block are presented in stream order.  The frame traversal\n// in step 3 must be started at the first frame in the Nth packet of the block,\n// which will be the first frame for stream N.  (And the packet header will tell\n// you the first frame's start position within the packet.)\n//\n// Step 1 can be performed using the GetXmaBlockContainingSample function below,\n// and steps 2-4 by calling GetXmaDecodePositionForSample once for each stream.\n\n\n\n/***************************************************************************\n *  XMA constants\n ***************************************************************************/\n\n// Size of the PCM samples produced by the XMA decoder\n#define XMA_OUTPUT_SAMPLE_BYTES         2u\n#define XMA_OUTPUT_SAMPLE_BITS          (XMA_OUTPUT_SAMPLE_BYTES * 8u)\n\n// Size of an XMA packet\n#define XMA_BYTES_PER_PACKET            2048u\n#define XMA_BITS_PER_PACKET             (XMA_BYTES_PER_PACKET * 8u)\n\n// Size of an XMA packet header\n#define XMA_PACKET_HEADER_BYTES         4u\n#define XMA_PACKET_HEADER_BITS          (XMA_PACKET_HEADER_BYTES * 8u)\n\n// Sample blocks in a decoded XMA frame\n#define XMA_SAMPLES_PER_FRAME           512u\n\n// Sample blocks in a decoded XMA subframe\n#define XMA_SAMPLES_PER_SUBFRAME        128u\n\n// Maximum encoded data that can be submitted to the XMA decoder at a time\n#define XMA_READBUFFER_MAX_PACKETS      4095u\n#define XMA_READBUFFER_MAX_BYTES        (XMA_READBUFFER_MAX_PACKETS * XMA_BYTES_PER_PACKET)\n\n// Maximum size allowed for the XMA decoder's output buffers\n#define XMA_WRITEBUFFER_MAX_BYTES       (31u * 256u)\n\n// Required byte alignment of the XMA decoder's output buffers\n#define XMA_WRITEBUFFER_BYTE_ALIGNMENT  256u\n\n// Decode chunk sizes for the XMA_PLAYBACK_INIT.subframesToDecode field\n#define XMA_MIN_SUBFRAMES_TO_DECODE     1u\n#define XMA_MAX_SUBFRAMES_TO_DECODE     8u\n#define XMA_OPTIMAL_SUBFRAMES_TO_DECODE 4u\n\n// LoopCount<255 means finite repetitions; LoopCount=255 means infinite looping\n#define XMA_MAX_LOOPCOUNT               254u\n#define XMA_INFINITE_LOOP               255u\n\n\n\n/***************************************************************************\n *  XMA format structures\n ***************************************************************************/\n\n// The currently recommended way to express format information for XMA2 files\n// is the XMA2WAVEFORMATEX structure.  This structure is fully compliant with\n// the WAVEFORMATEX standard and contains all the information needed to parse\n// and manage XMA2 files in a compact way.\n\n#define WAVE_FORMAT_XMA2 0x166\n\ntypedef struct XMA2WAVEFORMATEX\n{\n    WAVEFORMATEX wfx;\n    // Meaning of the WAVEFORMATEX fields here:\n    //    wFormatTag;        // Audio format type; always WAVE_FORMAT_XMA2\n    //    nChannels;         // Channel count of the decoded audio\n    //    nSamplesPerSec;    // Sample rate of the decoded audio\n    //    nAvgBytesPerSec;   // Used internally by the XMA encoder\n    //    nBlockAlign;       // Decoded sample size; channels * wBitsPerSample / 8\n    //    wBitsPerSample;    // Bits per decoded mono sample; always 16 for XMA\n    //    cbSize;            // Size in bytes of the rest of this structure (34)\n\n    WORD  NumStreams;        // Number of audio streams (1 or 2 channels each)\n    DWORD ChannelMask;       // Spatial positions of the channels in this file,\n                             // stored as SPEAKER_xxx values (see audiodefs.h)\n    DWORD SamplesEncoded;    // Total number of PCM samples the file decodes to\n    DWORD BytesPerBlock;     // XMA block size (but the last one may be shorter)\n    DWORD PlayBegin;         // First valid sample in the decoded audio\n    DWORD PlayLength;        // Length of the valid part of the decoded audio\n    DWORD LoopBegin;         // Beginning of the loop region in decoded sample terms\n    DWORD LoopLength;        // Length of the loop region in decoded sample terms\n    BYTE  LoopCount;         // Number of loop repetitions; 255 = infinite\n    BYTE  EncoderVersion;    // Version of XMA encoder that generated the file\n    WORD  BlockCount;        // XMA blocks in file (and entries in its seek table)\n} XMA2WAVEFORMATEX, *PXMA2WAVEFORMATEX;\n\n\n// The legacy XMA format structures are described here for reference, but they\n// should not be used in new content.  XMAWAVEFORMAT was the structure used in\n// XMA version 1 files.  XMA2WAVEFORMAT was used in early XMA2 files; it is not\n// placed in the usual 'fmt' RIFF chunk but in its own 'XMA2' chunk.\n\n#ifndef WAVE_FORMAT_XMA\n#define WAVE_FORMAT_XMA 0x0165\n\n// Values used in the ChannelMask fields below.  Similar to the SPEAKER_xxx\n// values defined in audiodefs.h, but modified to fit in a single byte.\n#ifndef XMA_SPEAKER_LEFT\n    #define XMA_SPEAKER_LEFT            0x01\n    #define XMA_SPEAKER_RIGHT           0x02\n    #define XMA_SPEAKER_CENTER          0x04\n    #define XMA_SPEAKER_LFE             0x08\n    #define XMA_SPEAKER_LEFT_SURROUND   0x10\n    #define XMA_SPEAKER_RIGHT_SURROUND  0x20\n    #define XMA_SPEAKER_LEFT_BACK       0x40\n    #define XMA_SPEAKER_RIGHT_BACK      0x80\n#endif\n\n\n// Used in XMAWAVEFORMAT for per-stream data\ntypedef struct XMASTREAMFORMAT\n{\n    DWORD PsuedoBytesPerSec; // Used by the XMA encoder (typo preserved for legacy reasons)\n    DWORD SampleRate;        // The stream's decoded sample rate (in XMA2 files,\n                             // this is the same for all streams in the file).\n    DWORD LoopStart;         // Bit offset of the frame containing the loop start\n                             // point, relative to the beginning of the stream.\n    DWORD LoopEnd;           // Bit offset of the frame containing the loop end.\n    BYTE  SubframeData;      // Two 4-bit numbers specifying the exact location of\n                             // the loop points within the frames that contain them.\n                             //   SubframeEnd: Subframe of the loop end frame where\n                             //                the loop ends.  Ranges from 0 to 3.\n                             //   SubframeSkip: Subframes to skip in the start frame to\n                             //                 reach the loop.  Ranges from 0 to 4.\n    BYTE  Channels;          // Number of channels in the stream (1 or 2)\n    WORD  ChannelMask;       // Spatial positions of the channels in the stream\n} XMASTREAMFORMAT;\n\n// Legacy XMA1 format structure\ntypedef struct XMAWAVEFORMAT\n{\n    WORD FormatTag;          // Audio format type (always WAVE_FORMAT_XMA)\n    WORD BitsPerSample;      // Bit depth (currently required to be 16)\n    WORD EncodeOptions;      // Options for XMA encoder/decoder\n    WORD LargestSkip;        // Largest skip used in interleaving streams\n    WORD NumStreams;         // Number of interleaved audio streams\n    BYTE LoopCount;          // Number of loop repetitions; 255 = infinite\n    BYTE Version;            // XMA encoder version that generated the file.\n                             // Always 3 or higher for XMA2 files.\n    XMASTREAMFORMAT XmaStreams[1]; // Per-stream format information; the actual\n                                   // array length is in the NumStreams field.\n} XMAWAVEFORMAT;\n\n\n// Used in XMA2WAVEFORMAT for per-stream data\ntypedef struct XMA2STREAMFORMAT\n{\n    BYTE Channels;           // Number of channels in the stream (1 or 2)\n    BYTE RESERVED;           // Reserved for future use\n    WORD ChannelMask;        // Spatial positions of the channels in the stream\n} XMA2STREAMFORMAT;\n\n// Legacy XMA2 format structure (big-endian byte ordering)\ntypedef struct XMA2WAVEFORMAT\n{\n    BYTE  Version;           // XMA encoder version that generated the file.\n                             // Always 3 or higher for XMA2 files.\n    BYTE  NumStreams;        // Number of interleaved audio streams\n    BYTE  RESERVED;          // Reserved for future use\n    BYTE  LoopCount;         // Number of loop repetitions; 255 = infinite\n    DWORD LoopBegin;         // Loop begin point, in samples\n    DWORD LoopEnd;           // Loop end point, in samples\n    DWORD SampleRate;        // The file's decoded sample rate\n    DWORD EncodeOptions;     // Options for the XMA encoder/decoder\n    DWORD PsuedoBytesPerSec; // Used internally by the XMA encoder\n    DWORD BlockSizeInBytes;  // Size in bytes of this file's XMA blocks (except\n                             // possibly the last one).  Always a multiple of\n                             // 2Kb, since XMA blocks are arrays of 2Kb packets.\n    DWORD SamplesEncoded;    // Total number of PCM samples encoded in this file\n    DWORD SamplesInSource;   // Actual number of PCM samples in the source\n                             // material used to generate this file\n    DWORD BlockCount;        // Number of XMA blocks in this file (and hence\n                             // also the number of entries in its seek table)\n    XMA2STREAMFORMAT Streams[1]; // Per-stream format information; the actual\n                                 // array length is in the NumStreams field.\n} XMA2WAVEFORMAT;\n\n#endif // #ifndef WAVE_FORMAT_XMA\n\n\n\n/***************************************************************************\n *  XMA packet structure (in big-endian form)\n ***************************************************************************/\n\ntypedef struct XMA2PACKET\n{\n    int FrameCount        :  6;  // Number of XMA frames that begin in this packet\n    int FrameOffsetInBits : 15;  // Bit of XmaData where the first complete frame begins\n    int PacketMetaData    :  3;  // Metadata stored in the packet (always 1 for XMA2)\n    int PacketSkipCount   :  8;  // How many packets belonging to other streams must be\n                                 // skipped to find the next packet belonging to this one\n    BYTE XmaData[XMA_BYTES_PER_PACKET - sizeof(DWORD)];  // XMA encoded data\n} XMA2PACKET;\n\n// E.g. if the first DWORD of a packet is 0x30107902:\n//\n// 001100 000001000001111 001 00000010\n//    |          |         |      |____ Skip 2 packets to find the next one for this stream\n//    |          |         |___________ XMA2 signature (always 001)\n//    |          |_____________________ First frame starts 527 bits into packet\n//    |________________________________ Packet contains 12 frames\n\n\n// Helper functions to extract the fields above from an XMA packet.  (Note that\n// the bitfields cannot be read directly on little-endian architectures such as\n// the Intel x86, as they are laid out in big-endian form.)\n\n__inline DWORD GetXmaPacketFrameCount(__in_bcount(1) const BYTE* pPacket)\n{\n    return (DWORD)(pPacket[0] >> 2);\n}\n\n__inline DWORD GetXmaPacketFirstFrameOffsetInBits(__in_bcount(3) const BYTE* pPacket)\n{\n    return ((DWORD)(pPacket[0] & 0x3) << 13) |\n           ((DWORD)(pPacket[1]) << 5) |\n           ((DWORD)(pPacket[2]) >> 3);\n}\n\n__inline DWORD GetXmaPacketMetadata(__in_bcount(3) const BYTE* pPacket)\n{\n    return (DWORD)(pPacket[2] & 0x7);\n}\n\n__inline DWORD GetXmaPacketSkipCount(__in_bcount(4) const BYTE* pPacket)\n{\n    return (DWORD)(pPacket[3]);\n}\n\n\n\n/***************************************************************************\n *  XMA frame structure\n ***************************************************************************/\n\n// There is no way to represent the XMA frame as a C struct, since it is a\n// variable-sized string of bits that need not be stored at a byte-aligned\n// position in memory.  This is the layout:\n//\n// XMAFRAME\n// {\n//    LengthInBits: A 15-bit number representing the length of this frame.\n//    XmaData: Encoded XMA data; its size in bits is (LengthInBits - 15).\n// }\n\n// Size in bits of the frame's initial LengthInBits field\n#define XMA_BITS_IN_FRAME_LENGTH_FIELD 15\n\n// Special LengthInBits value that marks an invalid final frame\n#define XMA_FINAL_FRAME_MARKER 0x7FFF\n\n\n\n/***************************************************************************\n *  XMA helper functions\n ***************************************************************************/\n\n// We define a local ASSERT macro to equal the global one if it exists.\n// You can define XMA2DEFS_ASSERT in advance to override this default.\n#ifndef XMA2DEFS_ASSERT\n    #ifdef ASSERT\n        #define XMA2DEFS_ASSERT ASSERT\n    #else\n        #define XMA2DEFS_ASSERT(a) /* No-op by default */\n    #endif\n#endif\n\n\n// GetXmaBlockContainingSample: Use a given seek table to find the XMA block\n// containing a given decoded sample.  Note that the seek table entries in an\n// XMA file are stored in big-endian form and may need to be converted prior\n// to calling this function.\n\n__inline HRESULT GetXmaBlockContainingSample\n(\n    DWORD nBlockCount,                      // Blocks in the file (= seek table entries)\n    __in_ecount(nBlockCount) const DWORD* pSeekTable,  // Pointer to the seek table data\n    DWORD nDesiredSample,                   // Decoded sample to locate\n    __out DWORD* pnBlockContainingSample,   // Index of the block containing the sample\n    __out DWORD* pnSampleOffsetWithinBlock  // Position of the sample in this block\n)\n{\n    DWORD nPreviousTotalSamples = 0;\n    DWORD nBlock;\n    DWORD nTotalSamplesSoFar;\n\n    XMA2DEFS_ASSERT(pSeekTable);\n    XMA2DEFS_ASSERT(pnBlockContainingSample);\n    XMA2DEFS_ASSERT(pnSampleOffsetWithinBlock);\n\n    for (nBlock = 0; nBlock < nBlockCount; ++nBlock)\n    {\n        nTotalSamplesSoFar = pSeekTable[nBlock];\n        if (nTotalSamplesSoFar > nDesiredSample)\n        {\n            *pnBlockContainingSample = nBlock;\n            *pnSampleOffsetWithinBlock = nDesiredSample - nPreviousTotalSamples;\n            return S_OK;\n        }\n        nPreviousTotalSamples = nTotalSamplesSoFar;\n    }\n\n    return E_FAIL;\n}\n\n\n// GetXmaFrameLengthInBits: Reads a given frame's LengthInBits field.\n\n__inline DWORD GetXmaFrameLengthInBits\n(\n    __in_bcount(nBitPosition / 8 + 3)\n    __in const BYTE* pPacket,  // Pointer to XMA packet[s] containing the frame\n    DWORD nBitPosition         // Bit offset of the frame within this packet\n)\n{\n    DWORD nRegion;\n    DWORD nBytePosition = nBitPosition / 8;\n    DWORD nBitOffset = nBitPosition % 8;\n\n    if (nBitOffset < 2) // Only need to read 2 bytes (and might not be safe to read more)\n    {\n        nRegion = (DWORD)(pPacket[nBytePosition+0]) << 8 |\n                  (DWORD)(pPacket[nBytePosition+1]);\n        return (nRegion >> (1 - nBitOffset)) & 0x7FFF;  // Last 15 bits\n    }\n    else // Need to read 3 bytes\n    {\n        nRegion = (DWORD)(pPacket[nBytePosition+0]) << 16 |\n                  (DWORD)(pPacket[nBytePosition+1]) << 8 |\n                  (DWORD)(pPacket[nBytePosition+2]);\n        return (nRegion >> (9 - nBitOffset)) & 0x7FFF;  // Last 15 bits\n    }\n}\n\n\n// GetXmaFrameBitPosition: Calculates the bit offset of a given frame within\n// an XMA block or set of blocks.  Returns 0 on failure.\n\n__inline DWORD GetXmaFrameBitPosition\n(\n    __in_bcount(nXmaDataBytes) const BYTE* pXmaData,  // Pointer to XMA block[s]\n    DWORD nXmaDataBytes,                              // Size of pXmaData in bytes\n    DWORD nStreamIndex,                               // Stream within which to seek\n    DWORD nDesiredFrame                               // Frame sought\n)\n{\n    const BYTE* pCurrentPacket;\n    DWORD nPacketsExamined = 0;\n    DWORD nFrameCountSoFar = 0;\n    DWORD nFramesToSkip;\n    DWORD nFrameBitOffset;\n\n    XMA2DEFS_ASSERT(pXmaData);\n    XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);\n\n    // Get the first XMA packet belonging to the desired stream, relying on the\n    // fact that the first packets for each stream are in consecutive order at\n    // the beginning of an XMA block.\n\n    pCurrentPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;\n    for (;;)\n    {\n        // If we have exceeded the size of the XMA data, return failure\n        if (pCurrentPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)\n        {\n            return 0;\n        }\n\n        // If the current packet contains the frame we are looking for...\n        if (nFrameCountSoFar + GetXmaPacketFrameCount(pCurrentPacket) > nDesiredFrame)\n        {\n            // See how many frames in this packet we need to skip to get to it\n            XMA2DEFS_ASSERT(nDesiredFrame >= nFrameCountSoFar);\n            nFramesToSkip = nDesiredFrame - nFrameCountSoFar;\n\n            // Get the bit offset of the first frame in this packet\n            nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pCurrentPacket);\n\n            // Advance nFrameBitOffset to the frame of interest\n            while (nFramesToSkip--)\n            {\n                nFrameBitOffset += GetXmaFrameLengthInBits(pCurrentPacket, nFrameBitOffset);\n            }\n\n            // The bit offset to return is the number of bits from pXmaData to\n            // pCurrentPacket plus the bit offset of the frame of interest\n            return (DWORD)(pCurrentPacket - pXmaData) * 8 + nFrameBitOffset;\n        }\n\n        // If we haven't found the right packet yet, advance our counters\n        ++nPacketsExamined;\n        nFrameCountSoFar += GetXmaPacketFrameCount(pCurrentPacket);\n\n        // And skip to the next packet belonging to the same stream\n        pCurrentPacket += XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pCurrentPacket) + 1);\n    }\n}\n\n\n// GetLastXmaFrameBitPosition: Calculates the bit offset of the last complete\n// frame in an XMA block or set of blocks.\n\n__inline DWORD GetLastXmaFrameBitPosition\n(\n    __in_bcount(nXmaDataBytes) const BYTE* pXmaData,  // Pointer to XMA block[s]\n    DWORD nXmaDataBytes,                              // Size of pXmaData in bytes\n    DWORD nStreamIndex                                // Stream within which to seek\n)\n{\n    const BYTE* pLastPacket;\n    DWORD nBytesToNextPacket;\n    DWORD nFrameBitOffset;\n    DWORD nFramesInLastPacket;\n\n    XMA2DEFS_ASSERT(pXmaData);\n    XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);\n    XMA2DEFS_ASSERT(nXmaDataBytes >= XMA_BYTES_PER_PACKET * (nStreamIndex + 1));\n\n    // Get the first XMA packet belonging to the desired stream, relying on the\n    // fact that the first packets for each stream are in consecutive order at\n    // the beginning of an XMA block.\n    pLastPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;\n\n    // Search for the last packet belonging to the desired stream\n    for (;;)\n    {\n        nBytesToNextPacket = XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pLastPacket) + 1);\n        XMA2DEFS_ASSERT(nBytesToNextPacket);\n        if (pLastPacket + nBytesToNextPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)\n        {\n            break;  // The next packet would extend beyond the end of pXmaData\n        }\n        pLastPacket += nBytesToNextPacket;\n    }\n\n    // The last packet can sometimes have no seekable frames, in which case we\n    // have to use the previous one\n    if (GetXmaPacketFrameCount(pLastPacket) == 0)\n    {\n        pLastPacket -= nBytesToNextPacket;\n    }\n\n    // Found the last packet.  Get the bit offset of its first frame.\n    nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pLastPacket);\n\n    // Traverse frames until we reach the last one\n    nFramesInLastPacket = GetXmaPacketFrameCount(pLastPacket);\n    while (--nFramesInLastPacket)\n    {\n        nFrameBitOffset += GetXmaFrameLengthInBits(pLastPacket, nFrameBitOffset);\n    }\n\n    // The bit offset to return is the number of bits from pXmaData to\n    // pLastPacket plus the offset of the last frame in this packet.\n    return (DWORD)(pLastPacket - pXmaData) * 8 + nFrameBitOffset;\n}\n\n\n// GetXmaDecodePositionForSample: Obtains the information needed to make the\n// decoder generate audio starting at a given sample position relative to the\n// beginning of the given XMA block: the bit offset of the appropriate frame,\n// and the right subframe within that frame.  This data can be passed directly\n// to the XMAPlaybackSetDecodePosition function.\n\n__inline HRESULT GetXmaDecodePositionForSample\n(\n    __in_bcount(nXmaDataBytes) const BYTE* pXmaData,  // Pointer to XMA block[s]\n    DWORD nXmaDataBytes,                              // Size of pXmaData in bytes\n    DWORD nStreamIndex,                               // Stream within which to seek\n    DWORD nDesiredSample,                             // Sample sought\n    __out DWORD* pnBitOffset,                         // Returns the bit offset within pXmaData of\n                                                      // the frame containing the sample sought\n    __out DWORD* pnSubFrame                           // Returns the subframe containing the sample\n)\n{\n    DWORD nDesiredFrame = nDesiredSample / XMA_SAMPLES_PER_FRAME;\n    DWORD nSubFrame = (nDesiredSample % XMA_SAMPLES_PER_FRAME) / XMA_SAMPLES_PER_SUBFRAME;\n    DWORD nBitOffset = GetXmaFrameBitPosition(pXmaData, nXmaDataBytes, nStreamIndex, nDesiredFrame);\n\n    XMA2DEFS_ASSERT(pnBitOffset);\n    XMA2DEFS_ASSERT(pnSubFrame);\n\n    if (nBitOffset)\n    {\n        *pnBitOffset = nBitOffset;\n        *pnSubFrame = nSubFrame;\n        return S_OK;\n    }\n    else\n    {\n        return E_FAIL;\n    }\n}\n\n\n// GetXmaSampleRate: Obtains the legal XMA sample rate (24, 32, 44.1 or 48Khz)\n// corresponding to a generic sample rate.\n\n__inline DWORD GetXmaSampleRate(DWORD dwGeneralRate)\n{\n    DWORD dwXmaRate = 48000; // Default XMA rate for all rates above 44100Hz\n\n    if (dwGeneralRate <= 24000)      dwXmaRate = 24000;\n    else if (dwGeneralRate <= 32000) dwXmaRate = 32000;\n    else if (dwGeneralRate <= 44100) dwXmaRate = 44100;\n\n    return dwXmaRate;\n}\n\n\n// Functions to convert between WAVEFORMATEXTENSIBLE channel masks (combinations\n// of the SPEAKER_xxx flags defined in audiodefs.h) and XMA channel masks (which\n// are limited to eight possible speaker positions: left, right, center, low\n// frequency, side left, side right, back left and back right).\n\n__inline DWORD GetStandardChannelMaskFromXmaMask(BYTE bXmaMask)\n{\n    DWORD dwStandardMask = 0;\n\n    if (bXmaMask & XMA_SPEAKER_LEFT)           dwStandardMask |= SPEAKER_FRONT_LEFT;\n    if (bXmaMask & XMA_SPEAKER_RIGHT)          dwStandardMask |= SPEAKER_FRONT_RIGHT;\n    if (bXmaMask & XMA_SPEAKER_CENTER)         dwStandardMask |= SPEAKER_FRONT_CENTER;\n    if (bXmaMask & XMA_SPEAKER_LFE)            dwStandardMask |= SPEAKER_LOW_FREQUENCY;\n    if (bXmaMask & XMA_SPEAKER_LEFT_SURROUND)  dwStandardMask |= SPEAKER_SIDE_LEFT;\n    if (bXmaMask & XMA_SPEAKER_RIGHT_SURROUND) dwStandardMask |= SPEAKER_SIDE_RIGHT;\n    if (bXmaMask & XMA_SPEAKER_LEFT_BACK)      dwStandardMask |= SPEAKER_BACK_LEFT;\n    if (bXmaMask & XMA_SPEAKER_RIGHT_BACK)     dwStandardMask |= SPEAKER_BACK_RIGHT;\n\n    return dwStandardMask;\n}\n\n__inline BYTE GetXmaChannelMaskFromStandardMask(DWORD dwStandardMask)\n{\n    BYTE bXmaMask = 0;\n\n    if (dwStandardMask & SPEAKER_FRONT_LEFT)    bXmaMask |= XMA_SPEAKER_LEFT;\n    if (dwStandardMask & SPEAKER_FRONT_RIGHT)   bXmaMask |= XMA_SPEAKER_RIGHT;\n    if (dwStandardMask & SPEAKER_FRONT_CENTER)  bXmaMask |= XMA_SPEAKER_CENTER;\n    if (dwStandardMask & SPEAKER_LOW_FREQUENCY) bXmaMask |= XMA_SPEAKER_LFE;\n    if (dwStandardMask & SPEAKER_SIDE_LEFT)     bXmaMask |= XMA_SPEAKER_LEFT_SURROUND;\n    if (dwStandardMask & SPEAKER_SIDE_RIGHT)    bXmaMask |= XMA_SPEAKER_RIGHT_SURROUND;\n    if (dwStandardMask & SPEAKER_BACK_LEFT)     bXmaMask |= XMA_SPEAKER_LEFT_BACK;\n    if (dwStandardMask & SPEAKER_BACK_RIGHT)    bXmaMask |= XMA_SPEAKER_RIGHT_BACK;\n\n    return bXmaMask;\n}\n\n\n// LocalizeXma2Format: Modifies a XMA2WAVEFORMATEX structure in place to comply\n// with the current platform's byte-ordering rules (little- or big-endian).\n\n__inline HRESULT LocalizeXma2Format(__inout XMA2WAVEFORMATEX* pXma2Format)\n{\n    #define XMASWAP2BYTES(n) ((WORD)(((n) >> 8) | (((n) & 0xff) << 8)))\n    #define XMASWAP4BYTES(n) ((DWORD)((n) >> 24 | (n) << 24 | ((n) & 0xff00) << 8 | ((n) & 0xff0000) >> 8))\n\n    if (pXma2Format->wfx.wFormatTag == WAVE_FORMAT_XMA2)\n    {\n        return S_OK;\n    }\n    else if (XMASWAP2BYTES(pXma2Format->wfx.wFormatTag) == WAVE_FORMAT_XMA2)\n    {\n        pXma2Format->wfx.wFormatTag      = XMASWAP2BYTES(pXma2Format->wfx.wFormatTag);\n        pXma2Format->wfx.nChannels       = XMASWAP2BYTES(pXma2Format->wfx.nChannels);\n        pXma2Format->wfx.nSamplesPerSec  = XMASWAP4BYTES(pXma2Format->wfx.nSamplesPerSec);\n        pXma2Format->wfx.nAvgBytesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nAvgBytesPerSec);\n        pXma2Format->wfx.nBlockAlign     = XMASWAP2BYTES(pXma2Format->wfx.nBlockAlign);\n        pXma2Format->wfx.wBitsPerSample  = XMASWAP2BYTES(pXma2Format->wfx.wBitsPerSample);\n        pXma2Format->wfx.cbSize          = XMASWAP2BYTES(pXma2Format->wfx.cbSize);\n        pXma2Format->NumStreams          = XMASWAP2BYTES(pXma2Format->NumStreams);\n        pXma2Format->ChannelMask         = XMASWAP4BYTES(pXma2Format->ChannelMask);\n        pXma2Format->SamplesEncoded      = XMASWAP4BYTES(pXma2Format->SamplesEncoded);\n        pXma2Format->BytesPerBlock       = XMASWAP4BYTES(pXma2Format->BytesPerBlock);\n        pXma2Format->PlayBegin           = XMASWAP4BYTES(pXma2Format->PlayBegin);\n        pXma2Format->PlayLength          = XMASWAP4BYTES(pXma2Format->PlayLength);\n        pXma2Format->LoopBegin           = XMASWAP4BYTES(pXma2Format->LoopBegin);\n        pXma2Format->LoopLength          = XMASWAP4BYTES(pXma2Format->LoopLength);\n        pXma2Format->BlockCount          = XMASWAP2BYTES(pXma2Format->BlockCount);\n        return S_OK;\n    }\n    else\n    {\n        return E_FAIL; // Not a recognizable XMA2 format\n    }\n\n    #undef XMASWAP2BYTES\n    #undef XMASWAP4BYTES\n}\n\n\n#endif // #ifndef __XMA2DEFS_INCLUDED__\n"
  },
  {
    "path": "src/config/ActiveSettings.cpp",
    "content": "#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/CafeSystem.h\"\n#include \"Cemu/Logging/CemuLogging.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/LaunchSettings.h\"\n#include \"util/helpers/helpers.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n\nvoid ActiveSettings::SetPaths(bool isPortableMode,\n\t\tconst fs::path& executablePath,\n\t\tconst fs::path& userDataPath,\n\t\tconst fs::path& configPath,\n\t\tconst fs::path& cachePath,\n\t\tconst fs::path& dataPath,\n\t\tstd::set<fs::path>& failedWriteAccess)\n{\n\tcemu_assert_debug(!s_setPathsCalled); // can only change paths before loading\n\ts_isPortableMode = isPortableMode;\n\ts_executable_path = executablePath;\n\ts_user_data_path = userDataPath;\n\ts_config_path = configPath;\n\ts_cache_path = cachePath;\n\ts_data_path = dataPath;\n\tfailedWriteAccess.clear();\n\tfor (auto&& path : {userDataPath, configPath, cachePath})\n\t{\n\t\tstd::error_code ec;\n\t\tif (!fs::exists(path, ec))\n\t\t\tfs::create_directories(path, ec);\n\t\tif (!TestWriteAccess(path))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to write to {}\", _pathToUtf8(path));\n\t\t\tfailedWriteAccess.insert(path);\n\t\t}\n\t}\n\ts_executable_filename = s_executable_path.filename();\n\ts_setPathsCalled = true;\n}\n\n[[nodiscard]] bool ActiveSettings::IsPortableMode()\n{\n\treturn s_isPortableMode;\n}\n\nvoid ActiveSettings::Init()\n{\n\tcemu_assert_debug(s_setPathsCalled);\n\tstd::string additionalErrorInfo;\n\ts_has_required_online_files = iosuCrypt_checkRequirementsForOnlineMode(additionalErrorInfo) == IOS_CRYPTO_ONLINE_REQ_OK;\n}\n\nbool ActiveSettings::LoadSharedLibrariesEnabled()\n{\n\treturn g_current_game_profile->ShouldLoadSharedLibraries().value_or(true);\n}\n\nbool ActiveSettings::DisplayDRCEnabled()\n{\n\treturn g_current_game_profile->StartWithGamepadView();\n}\n\nCPUMode ActiveSettings::GetCPUMode()\n{\n\tauto mode = g_current_game_profile->GetCPUMode().value_or(CPUMode::Auto);\n\n\tif (mode == CPUMode::Auto)\n\t{\n\t\tif (GetPhysicalCoreCount() >= 4)\n\t\t\tmode = CPUMode::MulticoreRecompiler;\n\t\telse\n\t\t\tmode = CPUMode::SinglecoreRecompiler;\n\t}\n\telse if (mode == CPUMode::DualcoreRecompiler) // dualcore is disabled now\n\t\tmode = CPUMode::MulticoreRecompiler;\n\n\treturn mode;\n}\n\nuint8 ActiveSettings::GetTimerShiftFactor()\n{\n\treturn s_timer_shift;\n}\n\nvoid ActiveSettings::SetTimerShiftFactor(uint8 shiftFactor)\n{\n\ts_timer_shift = shiftFactor;\n}\n\nPrecompiledShaderOption ActiveSettings::GetPrecompiledShadersOption()\n{\n\treturn PrecompiledShaderOption::Auto; // g_current_game_profile->GetPrecompiledShadersState().value_or(GetConfig().precompiled_shaders);\n}\n\nbool ActiveSettings::RenderUpsideDownEnabled()\n{\n\treturn LaunchSettings::RenderUpsideDownEnabled().value_or(GetConfig().render_upside_down);\n}\n\nbool ActiveSettings::WaitForGX2DrawDoneEnabled()\n{\n\treturn GetConfig().gx2drawdone_sync;\n}\n\nGraphicAPI ActiveSettings::GetGraphicsAPI()\n{\n\tGraphicAPI api = g_current_game_profile->GetGraphicsAPI().value_or(GetConfig().graphic_api);\n\t// check if vulkan even available\n\tif (api == kVulkan && !g_vulkan_available)\n\t\tapi = kOpenGL;\n\t\n\treturn api;\n}\n\nfloat ActiveSettings::GetTVGamma()\n{\n\tconst auto& config = GetConfig();\n\treturn config.overrideGammaValue.GetValue() + LatteGPUState.tvGamma * !config.overrideAppGammaPreference.GetValue();\n}\n\nfloat ActiveSettings::GetDRCGamma()\n{\n\tconst auto& config = GetConfig();\n\treturn config.overrideGammaValue.GetValue() + LatteGPUState.drcGamma * !config.overrideAppGammaPreference.GetValue();\n}\n\nbool ActiveSettings::AudioOutputOnlyAux()\n{\n\treturn s_audio_aux_only;\n}\n\nvoid ActiveSettings::EnableAudioOnlyAux(bool state)\n{\n\ts_audio_aux_only = state;\n}\n\nuint32 ActiveSettings::GetPersistentId()\n{\n\treturn LaunchSettings::GetPersistentId().value_or(GetConfig().account.m_persistent_id);\n}\n\nbool ActiveSettings::IsOnlineEnabled()\n{\n\tif(!Account::GetAccount(GetPersistentId()).IsValidOnlineAccount())\n\t\treturn false;\n\tif(!HasRequiredOnlineFiles())\n\t\treturn false;\n\tNetworkService networkService = static_cast<NetworkService>(GetConfig().GetAccountNetworkService(GetPersistentId()));\n\treturn networkService == NetworkService::Nintendo || networkService == NetworkService::Pretendo || networkService == NetworkService::Custom;\n}\n\nbool ActiveSettings::HasRequiredOnlineFiles()\n{\n\treturn s_has_required_online_files;\n}\n\nNetworkService ActiveSettings::GetNetworkService()\n{\n\treturn GetConfig().GetAccountNetworkService(GetPersistentId());\n}\n\nbool ActiveSettings::DumpShadersEnabled()\n{\n\treturn s_dump_shaders;\n}\n\nbool ActiveSettings::DumpTexturesEnabled()\n{\n\treturn s_dump_textures;\n}\n\nbool ActiveSettings::DumpRecompilerFunctionsEnabled()\n{\n\treturn s_dump_recompiler_functions;\n}\n\nbool ActiveSettings::DumpLibcurlRequestsEnabled()\n{\n\treturn s_dump_libcurl_requests;\n}\n\nvoid ActiveSettings::EnableDumpShaders(bool state)\n{\n\ts_dump_shaders = state;\n}\n\nvoid ActiveSettings::EnableDumpTextures(bool state)\n{\n\ts_dump_textures = state;\n}\n\nvoid ActiveSettings::EnableDumpRecompilerFunctions(bool state)\n{\n\ts_dump_recompiler_functions = state;\n}\n\nvoid ActiveSettings::EnableDumpLibcurlRequests(bool state)\n{\n\ts_dump_libcurl_requests = state;\n}\n\nbool ActiveSettings::VPADDelayEnabled()\n{\n\tconst uint64 titleId = CafeSystem::GetForegroundTitleId();\n\t// workaround for Art Academy spamming VPADRead\n\treturn /* Art Academy: Home Studio (US) */ titleId == 0x000500001017BF00 ||\n\t\t/* Art Academy: Home Studio (JP) */ titleId == 0x000500001017BE00 ||\n\t\t/* Art Academy: Atelier (EU) */ titleId == 0x000500001017B500;\n}\n\nbool ActiveSettings::ShaderPreventInfiniteLoopsEnabled()\n{\n\tconst uint64 titleId = CafeSystem::GetForegroundTitleId();\n\t// workaround for NSMBU (and variants) having a bug where shaders can get stuck in infinite loops\n\t// Fatal Frame has an actual infinite loop in shader 0xb6a67c19f6472e00 encountered during a cutscene for the second drop (eShop version only?)\n\t// update: As of Cemu 1.20.0 this should no longer be required for NSMBU/NSLU due to fixes with uniform handling. But we leave it here for good measure\n\t// todo - Once we add support for loop config registers this workaround should become unnecessary\n\treturn /* NSMBU JP */ titleId == 0x0005000010101C00 ||\n\t\t/* NSMBU US */ titleId == 0x0005000010101D00 ||\n\t\t/* NSMBU EU */ titleId == 0x0005000010101E00 ||\n\t\t/* NSMBU+L US */ titleId == 0x000500001014B700 ||\n\t\t/* NSMBU+L EU */ titleId == 0x000500001014B800 ||\n\t\t/* NSLU US */ titleId == 0x0005000010142300 ||\n\t\t/* NSLU EU */ titleId == 0x0005000010142400 ||\n\t   /* Project Zero: Maiden of Black Water (EU) */ titleId == 0x00050000101D0300 ||\n\t   /* Fatal Frame: Maiden of Black Water (US) */ titleId == 0x00050000101D0600 ||\n\t   /* Project Zero: Maiden of Black Water (JP) */ titleId == 0x000500001014D200 ||\n\t   /* Project Zero: Maiden of Black Water (Trial, EU) */ titleId == 0x00050000101D3F00;\n}\n\nbool ActiveSettings::FlushGPUCacheOnSwap()\n{\n\tconst uint64 titleId = CafeSystem::GetForegroundTitleId();\n\t// games that require flushing the cache between frames\n\treturn\n\t\t/* PAC-MAN and the Ghostly Adventures (EU) */ titleId == 0x0005000010147900 ||\n\t\t/* PAC-MAN and the Ghostly Adventures (US) */ titleId == 0x0005000010146300 ||\n\t\t/* PAC-MAN and the Ghostly Adventures 2 (EU) */ titleId == 0x000500001017E500 ||\n\t\t/* PAC-MAN and the Ghostly Adventures 2 (US) */ titleId == 0x000500001017E600;\n}\n\nbool ActiveSettings::ForceSamplerRoundToPrecision()\n{\n\t// some Wayforward games (Duck Tales, Adventure Time Explore The Dungeon) sample textures exactly on the texel edge. On Wii U this is fine because the rounding mode can be controlled\n\t// on OpenGL/Vulkan when uv coordinates are converted from (un)normalized to integer the implementation always truncates which causes an off-by-one error in edge cases\n\t// In the future we should look into optionally correctly emulating sampler behavior (its quite complex, Latte supports flexible precision levels)\n\tconst uint64 titleId = CafeSystem::GetForegroundTitleId();\n\treturn\n\t\t/* Adventure Time ETDBIDK (EU) */ titleId == 0x000500001014E100 ||\n\t\t/* Adventure Time ETDBIDK (US) */ titleId == 0x0005000010144000 ||\n\t\t/* DuckTales Remastered (EU) */ titleId == 0x0005000010129200 ||\n\t\t/* DuckTales Remastered (US) */ titleId == 0x0005000010129000;\n\treturn false;\n}\n\nfs::path ActiveSettings::GetMlcPath()\n{\n\tcemu_assert_debug(s_setPathsCalled);\n\tif(const auto launch_mlc = LaunchSettings::GetMLCPath(); launch_mlc.has_value())\n\t\treturn launch_mlc.value();\n\n\tif(const auto config_mlc = GetConfig().mlc_path.GetValue(); !config_mlc.empty())\n\t\treturn _utf8ToPath(config_mlc);\n\n\treturn GetDefaultMLCPath();\n}\n\nbool ActiveSettings::IsCustomMlcPath()\n{\n\tcemu_assert_debug(s_setPathsCalled);\n\treturn !GetConfig().mlc_path.GetValue().empty();\n}\n\nbool ActiveSettings::IsCommandLineMlcPath()\n{\n\treturn LaunchSettings::GetMLCPath().has_value();\n}\n\nfs::path ActiveSettings::GetDefaultMLCPath()\n{\n\treturn GetUserDataPath(\"mlc01\");\n}\n\n"
  },
  {
    "path": "src/config/ActiveSettings.h",
    "content": "#pragma once\n\n#include <utility>\n#include \"config/CemuConfig.h\"\n#include \"config/NetworkSettings.h\"\n\n// global active settings for fast access (reflects settings from command line and game profile)\nclass ActiveSettings\n{\nprivate:\n\ttemplate <typename ...TArgs>\n\tstatic fs::path GetPath(const fs::path& path, std::string_view format, TArgs&&... args)\n\t{\n\t\tcemu_assert_debug(format.empty() || (format[0] != '/' && format[0] != '\\\\'));\n\t\tstd::string tmpPathStr = fmt::format(fmt::runtime(format), std::forward<TArgs>(args)...);\n\t\treturn path / _utf8ToPath(tmpPathStr);\n\t}\n\n\ttemplate <typename ...TArgs>\n\tstatic fs::path GetPath(const fs::path& path, std::wstring_view format, TArgs&&... args)\n\t{\n\t\tcemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\\\'));\n\t\treturn path / fmt::format(fmt::runtime(format), std::forward<TArgs>(args)...);\n\t}\n\tstatic fs::path GetPath(const fs::path& path, std::string_view p) \n\t{\n\t\tstd::basic_string_view<char8_t> s((const char8_t*)p.data(), p.size());\n\t\treturn path / fs::path(s);\n\t}\n\tstatic fs::path GetPath(const fs::path& path)\n\t{\n\t\treturn path;\n\t}\n\npublic:\n\t// Set directories and return all directories that failed write access test\n\tstatic void\n\tSetPaths(bool isPortableMode,\n\t\t   const fs::path& executablePath,\n\t\t   const fs::path& userDataPath,\n\t\t   const fs::path& configPath,\n\t\t   const fs::path& cachePath,\n\t\t   const fs::path& dataPath,\n\t\t   std::set<fs::path>& failedWriteAccess);\n\n\tstatic void Init();\n\n\t[[nodiscard]] static fs::path GetExecutablePath() { return s_executable_path; }\n\t[[nodiscard]] static fs::path GetExecutableFilename() { return s_executable_filename; }\n\ttemplate <typename ...TArgs>\n\t[[nodiscard]] static fs::path GetUserDataPath(TArgs&&... args){ return GetPath(s_user_data_path, std::forward<TArgs>(args)...); };\n\ttemplate <typename ...TArgs>\n\t[[nodiscard]] static fs::path GetConfigPath(TArgs&&... args){ return GetPath(s_config_path, std::forward<TArgs>(args)...); };\n\ttemplate <typename ...TArgs>\n\t[[nodiscard]] static fs::path GetCachePath(TArgs&&... args){ return GetPath(s_cache_path, std::forward<TArgs>(args)...); };\n\ttemplate <typename ...TArgs>\n\t[[nodiscard]] static fs::path GetDataPath(TArgs&&... args){ return GetPath(s_data_path, std::forward<TArgs>(args)...); };\n\n\t[[nodiscard]] static fs::path GetMlcPath();\n\n\ttemplate <typename ...TArgs>\n\t[[nodiscard]] static fs::path GetMlcPath(TArgs&&... args){ return GetPath(GetMlcPath(), std::forward<TArgs>(args)...); };\n\tstatic bool IsCustomMlcPath();\n\tstatic bool IsCommandLineMlcPath();\n\n\t// get mlc path to default cemu root dir/mlc01\n\t[[nodiscard]] static fs::path GetDefaultMLCPath();\n\nprivate:\n\tinline static bool s_isPortableMode{false};\n\tinline static fs::path s_executable_path;\n\tinline static fs::path s_user_data_path;\n\tinline static fs::path s_config_path;\n\tinline static fs::path s_cache_path;\n\tinline static fs::path s_data_path;\n\tinline static fs::path s_executable_filename; // cemu.exe\n\tinline static fs::path s_mlc_path;\n\npublic:\n\t// can be called before Init\n\t[[nodiscard]] static bool IsPortableMode();\n\n\t// general\n\t[[nodiscard]] static bool LoadSharedLibrariesEnabled();\n\t[[nodiscard]] static bool DisplayDRCEnabled();\n\n\t// cpu\n\t[[nodiscard]] static CPUMode GetCPUMode();\n\t[[nodiscard]] static uint8 GetTimerShiftFactor();\n\n\tstatic void SetTimerShiftFactor(uint8 shiftFactor);\n\t\n\t// gpu\n\t[[nodiscard]] static PrecompiledShaderOption GetPrecompiledShadersOption();\n\t[[nodiscard]] static bool RenderUpsideDownEnabled();\n\t[[nodiscard]] static bool WaitForGX2DrawDoneEnabled();\n\t[[nodiscard]] static GraphicAPI GetGraphicsAPI();\n\n\t// gamma\n\t[[nodiscard]] static float GetTVGamma();\n\t[[nodiscard]] static float GetDRCGamma();\n\n\t// audio\n\t[[nodiscard]] static bool AudioOutputOnlyAux();\n\tstatic void EnableAudioOnlyAux(bool state);\n\n\t// account\n\t[[nodiscard]] static uint32 GetPersistentId();\n\t[[nodiscard]] static bool IsOnlineEnabled();\n\t[[nodiscard]] static bool HasRequiredOnlineFiles();\n\t[[nodiscard]] static NetworkService GetNetworkService();\n\t// dump options\n\t[[nodiscard]] static bool DumpShadersEnabled();\n\t[[nodiscard]] static bool DumpTexturesEnabled();\n\t[[nodiscard]] static bool DumpRecompilerFunctionsEnabled();\n\t[[nodiscard]] static bool DumpLibcurlRequestsEnabled();\n\tstatic void EnableDumpShaders(bool state);\n\tstatic void EnableDumpTextures(bool state);\n\tstatic void EnableDumpRecompilerFunctions(bool state);\n\tstatic void EnableDumpLibcurlRequests(bool state);\n\n\t// hacks\n\t[[nodiscard]] static bool VPADDelayEnabled();\n\t[[nodiscard]] static bool ShaderPreventInfiniteLoopsEnabled();\n\t[[nodiscard]] static bool FlushGPUCacheOnSwap();\n\t[[nodiscard]] static bool ForceSamplerRoundToPrecision();\n\nprivate:\n\tinline static bool s_setPathsCalled = false;\n\t// dump options\n\tinline static bool s_dump_shaders = false;\n\tinline static bool s_dump_textures = false;\n\tinline static bool s_dump_recompiler_functions = false;\n\tinline static bool s_dump_libcurl_requests = false;\n\n\t// timer speed\n\tinline static uint8 s_timer_shift = 3; // right shift factor, 0 -> 8x, 3 -> 1x, 4 -> 0.5x\n\n\t// debug\n\tinline static bool s_audio_aux_only = false;\n\n\tinline static bool s_has_required_online_files = false;\n};\n\n"
  },
  {
    "path": "src/config/CMakeLists.txt",
    "content": "add_library(CemuConfig\n    ActiveSettings.cpp\n    ActiveSettings.h\n    CemuConfig.cpp\n    CemuConfig.h\n    ConfigValue.h\n    LaunchSettings.cpp\n    LaunchSettings.h\n    NetworkSettings.cpp\n    NetworkSettings.h\n    XMLConfig.h\n)\n\nset_property(TARGET CemuConfig PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\ntarget_include_directories(CemuConfig PUBLIC \"../\")\n\ntarget_link_libraries(CemuConfig PRIVATE\n\tCemuCommon\n    CemuGui\n    Boost::program_options\n)\n"
  },
  {
    "path": "src/config/CemuConfig.cpp",
    "content": "#include \"config/CemuConfig.h\"\n#include \"WindowSystem.h\"\n\n#include \"util/helpers/helpers.h\"\n#include \"config/ActiveSettings.h\"\n\n#include \"ActiveSettings.h\"\n\nvoid CemuConfig::SetMLCPath(fs::path path, bool save)\n{\n\tmlc_path.SetValue(_pathToUtf8(path));\n\tif(save)\n\t\tGetConfigHandle().Save();\n\tAccount::RefreshAccounts();\n}\n\nXMLConfigParser CemuConfig::Load(XMLConfigParser& parser)\n{\n\tauto new_parser = parser.get(\"content\");\n\tif (new_parser.valid())\n\t\tparser = new_parser;\n\n\t// general settings\n\tlog_flag = parser.get(\"logflag\", log_flag.GetInitValue());\n\tcemuLog_setActiveLoggingFlags(GetConfig().log_flag.GetValue());\n\tadvanced_ppc_logging = parser.get(\"advanced_ppc_logging\", advanced_ppc_logging.GetInitValue());\n\n\tconst char* mlc = parser.get(\"mlc_path\", \"\");\n\tmlc_path = mlc;\n\n\tpermanent_storage = parser.get(\"permanent_storage\", permanent_storage);\n\n\tproxy_server = parser.get(\"proxy_server\", \"\");\n\tdisable_screensaver = parser.get(\"disable_screensaver\", disable_screensaver);\n\tplay_boot_sound = parser.get(\"play_boot_sound\", play_boot_sound);\n\tconsole_language = parser.get(\"console_language\", console_language.GetInitValue());\n\n\tgame_paths.clear();\n\tauto game_path_parser = parser.get(\"GamePaths\");\n\tfor (auto element = game_path_parser.get(\"Entry\"); element.valid(); element = game_path_parser.get(\"Entry\", element))\n\t{\n\t\tconst std::string path = element.value(\"\");\n\t\tif (path.empty())\n\t\t\tcontinue;\n\t\ttry\n\t\t{\n\t\t\tgame_paths.emplace_back(path);\n\t\t}\n\t\tcatch (const std::exception&)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"config load error: can't load game path: {}\", path);\n\t\t}\n\t}\n\n\tstd::unique_lock _lock(game_cache_entries_mutex);\n\tgame_cache_entries.clear();\n\tauto game_cache_parser = parser.get(\"GameCache\");\n\tfor (auto element = game_cache_parser.get(\"Entry\"); element.valid(); element = game_cache_parser.get(\"Entry\", element))\n\t{\n\t\tconst char* rpx = element.get(\"path\", \"\");\n\t\ttry\n\t\t{\n\t\t\tGameEntry entry{};\n\t\t\tentry.rpx_file = boost::nowide::widen(rpx);\n\t\t\tentry.title_id = element.get<decltype(entry.title_id)>(\"title_id\");\n\t\t\tentry.legacy_name = boost::nowide::widen(element.get(\"name\", \"\"));\n\t\t\tentry.custom_name = element.get(\"custom_name\", \"\");\n\t\t\tentry.legacy_region = element.get(\"region\", 0);\n\t\t\tentry.legacy_version = element.get(\"version\", 0);\n\t\t\tentry.legacy_update_version = element.get(\"version\", 0);\n\t\t\tentry.legacy_dlc_version = element.get(\"dlc_version\", 0);\n\t\t\tentry.legacy_time_played = element.get<decltype(entry.legacy_time_played)>(\"time_played\");\n\t\t\tentry.legacy_last_played = element.get<decltype(entry.legacy_last_played)>(\"last_played\");\n\t\t\tentry.favorite = element.get(\"favorite\", false);\n\t\t\tgame_cache_entries.emplace_back(entry);\n\n\t\t\tif (entry.title_id != 0)\n\t\t\t{\n\t\t\t\tif (entry.favorite)\n\t\t\t\t\tgame_cache_favorites.emplace(entry.title_id);\n\t\t\t\telse\n\t\t\t\t\tgame_cache_favorites.erase(entry.title_id);\n\t\t\t}\n\t\t}\n\t\tcatch (const std::exception&)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"config load error: can't load game cache entry: {}\", rpx);\n\t\t}\n\t}\n\t_lock.unlock();\n\n\tgraphic_pack_entries.clear();\n\tauto graphic_pack_parser = parser.get(\"GraphicPack\");\n\tfor (auto element = graphic_pack_parser.get(\"Entry\"); element.valid(); element = graphic_pack_parser.get(\"Entry\", element))\n\t{\n\t\tstd::string filename = element.get_attribute(\"filename\", \"\");\n\t\tif(filename.empty()) // legacy loading\n\t\t{\n\t\t\tfilename = element.get(\"filename\", \"\");\n\t\t\tfs::path path = fs::path(filename).lexically_normal();\n\t\t\tgraphic_pack_entries.try_emplace(path);\n\t\t\tconst std::string category = element.get(\"category\", \"\");\n\t\t\tconst std::string preset = element.get(\"preset\", \"\");\n\t\t\tgraphic_pack_entries[filename].try_emplace(category, preset);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfs::path path = fs::path(filename).lexically_normal();\n\t\t\tgraphic_pack_entries.try_emplace(path);\n\n\t\t\tconst bool disabled = element.get_attribute(\"disabled\", false);\n\t\t\tif (disabled)\n\t\t\t{\n\t\t\t\tgraphic_pack_entries[path].try_emplace(\"_disabled\", \"true\");\n\t\t\t}\n\n\t\t\tfor (auto preset = element.get(\"Preset\"); preset.valid(); preset = element.get(\"Preset\", preset))\n\t\t\t{\n\t\t\t\tconst std::string category = preset.get(\"category\", \"\");\n\t\t\t\tconst std::string active_preset = preset.get(\"preset\", \"\");\n\t\t\t\tgraphic_pack_entries[path].try_emplace(category, active_preset);\n\t\t\t}\n\t\t}\n\n\t}\n\n\t// graphics\n\tauto graphic = parser.get(\"Graphic\");\n\tgraphic_api = graphic.get(\"api\", kOpenGL);\n\tgraphic.get(\"device\", legacy_graphic_device_uuid);\n\tif (graphic.get(\"vkDevice\").valid())\n\t\tgraphic.get(\"vkDevice\", vk_graphic_device_uuid);\n\telse\n\t\tvk_graphic_device_uuid = legacy_graphic_device_uuid;\n\tmtl_graphic_device_uuid = graphic.get(\"mtlDevice\", 0);\n\tvsync = graphic.get(\"VSync\", 0);\n\toverrideAppGammaPreference = graphic.get(\"OverrideAppGammaPreference\", false);\n\toverrideGammaValue = graphic.get(\"OverrideGammaValue\", 2.2f);\n\tif(overrideGammaValue < 0)\n\t\toverrideGammaValue = 2.2f;\n\tuserDisplayGamma = graphic.get(\"UserDisplayGamma\", 2.2f);\n\tif(userDisplayGamma < 0)\n\t\tuserDisplayGamma = 2.2f;\n\tgx2drawdone_sync = graphic.get(\"GX2DrawdoneSync\", true);\n\tupscale_filter = graphic.get(\"UpscaleFilter\", kBicubicHermiteFilter);\n\tdownscale_filter = graphic.get(\"DownscaleFilter\", kLinearFilter);\n\tfullscreen_scaling = graphic.get(\"FullscreenScaling\", kKeepAspectRatio);\n\tasync_compile = graphic.get(\"AsyncCompile\", async_compile);\n\tvk_accurate_barriers = graphic.get(\"vkAccurateBarriers\", true); // this used to be \"VulkanAccurateBarriers\" but because we changed the default to true in 1.27.1 the option name had to be changed\n#if ENABLE_METAL\n\tforce_mesh_shaders = graphic.get(\"ForceMeshShaders\", false);\n#endif\n\n\tauto overlay_node = graphic.get(\"Overlay\");\n\tif(overlay_node.valid())\n\t{\n\t\toverlay.position = overlay_node.get(\"Position\", ScreenPosition::kDisabled);\n\t\toverlay.text_color = overlay_node.get(\"TextColor\", 0xFFFFFFFF);\n\t\toverlay.text_scale = overlay_node.get(\"TextScale\", 100);\n\t\toverlay.fps = overlay_node.get(\"FPS\", true);\n\t\toverlay.drawcalls = overlay_node.get(\"DrawCalls\", false);\n\t\toverlay.cpu_usage = overlay_node.get(\"CPUUsage\", false);\n\t\toverlay.cpu_per_core_usage = overlay_node.get(\"CPUPerCoreUsage\", false);\n\t\toverlay.ram_usage = overlay_node.get(\"RAMUsage\", false);\n\t\toverlay.vram_usage = overlay_node.get(\"VRAMUsage\", false);\n\t\toverlay.debug = overlay_node.get(\"Debug\", false);\n\n\t\tnotification.controller_profiles = overlay_node.get(\"ControllerProfiles\", true);\n\t\tnotification.controller_battery = overlay_node.get(\"ControllerBattery\", true);\n\t\tnotification.shader_compiling = overlay_node.get(\"ShaderCompiling\", true);\n\t}\n\telse\n\t{\n\t\t// legacy support\n\t\toverlay.position = graphic.get(\"OverlayPosition\", ScreenPosition::kDisabled);\n\t\toverlay.text_color = graphic.get(\"OverlayTextColor\", 0xFFFFFFFF);\n\t\toverlay.fps = graphic.get(\"OverlayFPS\", true);\n\t\toverlay.drawcalls = graphic.get(\"OverlayDrawCalls\", false);\n\t\toverlay.cpu_usage = graphic.get(\"OverlayCPUUsage\", false);\n\t\toverlay.cpu_per_core_usage = graphic.get(\"OverlayCPUPerCoreUsage\", false);\n\t\toverlay.ram_usage = graphic.get(\"OverlayRAMUsage\", false);\n\n\t\tnotification.controller_profiles = graphic.get(\"OverlayControllerProfiles\", true);\n\t\tnotification.controller_battery = graphic.get(\"OverlayControllerBattery\", true);\n\t\tnotification.shader_compiling = graphic.get(\"ShaderCompiling\", true);\n\t}\n\n\tauto notification_node = graphic.get(\"Notification\");\n\tif (notification_node.valid())\n\t{\n\t\tnotification.position = notification_node.get(\"Position\", ScreenPosition::kTopLeft);\n\t\tnotification.text_color = notification_node.get(\"TextColor\", 0xFFFFFFFF);\n\t\tnotification.text_scale = notification_node.get(\"TextScale\", 100);\n\t\tnotification.controller_profiles = notification_node.get(\"ControllerProfiles\", true);\n\t\tnotification.controller_battery = notification_node.get(\"ControllerBattery\", false);\n\t\tnotification.shader_compiling = notification_node.get(\"ShaderCompiling\", true);\n\t\tnotification.friends = notification_node.get(\"FriendService\", true);\n\t}\n\n\t// audio\n\tauto audio = parser.get(\"Audio\");\n\taudio_api = audio.get(\"api\", 0);\n\taudio_delay = audio.get(\"delay\", 2);\n\ttv_channels = audio.get(\"TVChannels\", kStereo);\n\tpad_channels = audio.get(\"PadChannels\", kStereo);\n\tinput_channels = audio.get(\"InputChannels\", kMono);\n\ttv_volume = audio.get(\"TVVolume\", 20);\n\tpad_volume = audio.get(\"PadVolume\", 0);\n\tinput_volume = audio.get(\"InputVolume\", 20);\n\tportal_volume = audio.get(\"PortalVolume\", 20);\n\n\tconst auto tv = audio.get(\"TVDevice\", \"\");\n\ttry\n\t{\n\t\ttv_device = boost::nowide::widen(tv);\n\t}\n\tcatch (const std::exception&)\n\t{\n\t\tcemuLog_log(LogType::Force, \"config load error: can't load tv device: {}\", tv);\n\t}\n\n\tconst auto pad = audio.get(\"PadDevice\", \"\");\n\ttry\n\t{\n\t\tpad_device = boost::nowide::widen(pad);\n\t}\n\tcatch (const std::exception&)\n\t{\n\t\tcemuLog_log(LogType::Force, \"config load error: can't load pad device: {}\", pad);\n\t}\n\n\tconst auto input_device_name = audio.get(\"InputDevice\", \"\");\n\ttry\n\t{\n\t\tinput_device = boost::nowide::widen(input_device_name);\n\t}\n\tcatch (const std::exception&)\n\t{\n\t\tcemuLog_log(LogType::Force, \"config load error: can't load input device: {}\", input_device_name);\n\t}\n\n\tconst auto portal_device_name = audio.get(\"PortalDevice\", \"\");\n\ttry\n\t{\n\t\tportal_device = boost::nowide::widen(portal_device_name);\n\t}\n\tcatch (const std::exception&)\n\t{\n\t\tcemuLog_log(LogType::Force, \"config load error: can't load input device: {}\", portal_device_name);\n\t}\n\n\t// account\n\tauto acc = parser.get(\"Account\");\n\taccount.m_persistent_id = acc.get(\"PersistentId\", account.m_persistent_id);\n\t// legacy online settings, we only parse these for upgrading purposes\n\taccount.legacy_online_enabled = acc.get(\"OnlineEnabled\", account.legacy_online_enabled);\n\taccount.legacy_active_service = acc.get(\"ActiveService\",account.legacy_active_service);\n\t// per-account online setting\n\tauto accService = parser.get(\"AccountService\");\n\taccount.service_select.clear();\n\tfor (auto element = accService.get(\"SelectedService\"); element.valid(); element = accService.get(\"SelectedService\", element))\n\t{\n\t\tuint32 persistentId = element.get_attribute<uint32>(\"PersistentId\", 0);\n\t\tsint32 serviceIndex = element.get_attribute<sint32>(\"Service\", 0);\n\t\tNetworkService networkService = static_cast<NetworkService>(serviceIndex);\n\t\tif (persistentId < Account::kMinPersistendId)\n\t\t\tcontinue;\n\t\tif(networkService == NetworkService::Offline || networkService == NetworkService::Nintendo || networkService == NetworkService::Pretendo || networkService == NetworkService::Custom)\n\t\t\taccount.service_select.emplace(persistentId, networkService);\n\t}\n\t// debug\n\tauto debug = parser.get(\"Debug\");\n#if BOOST_OS_WINDOWS\n\tcrash_dump = debug.get(\"CrashDumpWindows\", crash_dump);\n#elif BOOST_OS_UNIX\n\tcrash_dump = debug.get(\"CrashDumpUnix\", crash_dump);\n#endif\n\tgdb_port = debug.get(\"GDBPort\", 1337);\n#if ENABLE_METAL\n\tgpu_capture_dir = debug.get(\"GPUCaptureDir\", \"\");\n\tframebuffer_fetch = debug.get(\"FramebufferFetch\", true);\n#endif\n\n\t// input\n\tauto input = parser.get(\"Input\");\n\tauto dsuc = input.get(\"DSUC\");\n\tdsu_client.host = dsuc.get_attribute(\"host\", dsu_client.host);\n\tdsu_client.port = dsuc.get_attribute(\"port\", dsu_client.port);\n\n\t// emulatedusbdevices\n\tauto usbdevices = parser.get(\"EmulatedUsbDevices\");\n\temulated_usb_devices.emulate_skylander_portal = usbdevices.get(\"EmulateSkylanderPortal\", emulated_usb_devices.emulate_skylander_portal);\n\temulated_usb_devices.emulate_infinity_base = usbdevices.get(\"EmulateInfinityBase\", emulated_usb_devices.emulate_infinity_base);\n\temulated_usb_devices.emulate_dimensions_toypad = usbdevices.get(\"EmulateDimensionsToypad\", emulated_usb_devices.emulate_dimensions_toypad);\n\n\treturn parser;\n}\n\nXMLConfigParser CemuConfig::Save(XMLConfigParser& parser)\n{\n\tauto config = parser.set(\"content\");\n\t// general settings\n\tconfig.set(\"logflag\", log_flag.GetValue());\n\tconfig.set(\"advanced_ppc_logging\", advanced_ppc_logging.GetValue());\n\tconfig.set(\"mlc_path\", mlc_path.GetValue().c_str());\n\tconfig.set<bool>(\"permanent_storage\", permanent_storage);\n\tconfig.set(\"proxy_server\", proxy_server.GetValue().c_str());\n\tconfig.set<bool>(\"play_boot_sound\", play_boot_sound);\n\n\t// config.set(\"cpu_mode\", cpu_mode.GetValue());\n\t//config.set(\"console_region\", console_region.GetValue());\n\tconfig.set(\"console_language\", console_language.GetValue());\n\n\t// game paths\n\tauto game_path_parser = config.set(\"GamePaths\");\n\tfor (const auto& entry : game_paths)\n\t{\n\t\tgame_path_parser.set(\"Entry\", entry.c_str());\n\t}\n\n\t// game list cache\n\tstd::unique_lock _lock(game_cache_entries_mutex);\n\tauto game_cache_parser = config.set(\"GameCache\");\n\tfor (const auto& game : game_cache_entries)\n\t{\n\t\tauto entry = game_cache_parser.set(\"Entry\");\n\n\t\tentry.set(\"title_id\", (sint64)game.title_id);\n\t\tentry.set(\"name\", boost::nowide::narrow(game.legacy_name).c_str());\n\t\tentry.set(\"custom_name\", game.custom_name.c_str());\n\t\tentry.set(\"region\", (sint32)game.legacy_region);\n\t\tentry.set(\"version\", (sint32)game.legacy_update_version);\n\t\tentry.set(\"dlc_version\", (sint32)game.legacy_dlc_version);\n\t\tentry.set(\"path\", boost::nowide::narrow(game.rpx_file).c_str());\n\t\tentry.set(\"time_played\", game.legacy_time_played);\n\t\tentry.set(\"last_played\", game.legacy_last_played);\n\t\tentry.set(\"favorite\", game.favorite);\n\t}\n\t_lock.unlock();\n\n\tauto graphic_pack_parser = config.set(\"GraphicPack\");\n\tfor (const auto& game : graphic_pack_entries)\n\t{\n\t\tauto entry = graphic_pack_parser.set(\"Entry\");\n\t\tentry.set_attribute(\"filename\",_pathToUtf8(game.first).c_str());\n\t\tfor(const auto& kv : game.second)\n\t\t{\n\t\t\t// TODO: less hacky pls\n\t\t\tif(boost::iequals(kv.first, \"_disabled\"))\n\t\t\t{\n\t\t\t\tentry.set_attribute(\"disabled\", true);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tauto preset = entry.set(\"Preset\");\n\t\t\tif(!kv.first.empty())\n\t\t\t\tpreset.set(\"category\", kv.first.c_str());\n\n\t\t\tpreset.set(\"preset\", kv.second.c_str());\n\t\t}\n\t}\n\n\t// graphics\n\tauto graphic = config.set(\"Graphic\");\n\tgraphic.set(\"api\", graphic_api);\n\tgraphic.set(\"device\", legacy_graphic_device_uuid);\n\tgraphic.set(\"vkDevice\", vk_graphic_device_uuid);\n\tgraphic.set(\"mtlDevice\", mtl_graphic_device_uuid);\n\tgraphic.set(\"VSync\", vsync);\n\tgraphic.set(\"OverrideAppGammaPreference\", overrideAppGammaPreference);\n\tgraphic.set(\"OverrideGammaValue\", overrideGammaValue);\n\tgraphic.set(\"UserDisplayGamma\", userDisplayGamma);\n\tgraphic.set(\"GX2DrawdoneSync\", gx2drawdone_sync);\n#if ENABLE_METAL\n\tgraphic.set(\"ForceMeshShaders\", force_mesh_shaders);\n#endif\n\t//graphic.set(\"PrecompiledShaders\", precompiled_shaders.GetValue());\n\tgraphic.set(\"UpscaleFilter\", upscale_filter);\n\tgraphic.set(\"DownscaleFilter\", downscale_filter);\n\tgraphic.set(\"FullscreenScaling\", fullscreen_scaling);\n\tgraphic.set(\"AsyncCompile\", async_compile.GetValue());\n\tgraphic.set(\"vkAccurateBarriers\", vk_accurate_barriers);\n\n\tauto overlay_node = graphic.set(\"Overlay\");\n\toverlay_node.set(\"Position\", overlay.position);\n\toverlay_node.set(\"TextColor\", overlay.text_color);\n\toverlay_node.set(\"TextScale\", overlay.text_scale);\n\toverlay_node.set(\"FPS\", overlay.fps);\n\toverlay_node.set(\"DrawCalls\", overlay.drawcalls);\n\toverlay_node.set(\"CPUUsage\", overlay.cpu_usage);\n\toverlay_node.set(\"CPUPerCoreUsage\", overlay.cpu_per_core_usage);\n\toverlay_node.set(\"RAMUsage\", overlay.ram_usage);\n\toverlay_node.set(\"VRAMUsage\", overlay.vram_usage);\n\toverlay_node.set(\"Debug\", overlay.debug);\n\n\tauto notification_node = graphic.set(\"Notification\");\n\tnotification_node.set(\"Position\", notification.position);\n\tnotification_node.set(\"TextColor\", notification.text_color);\n\tnotification_node.set(\"TextScale\", notification.text_scale);\n\tnotification_node.set(\"ControllerProfiles\", notification.controller_profiles);\n\tnotification_node.set(\"ControllerBattery\", notification.controller_battery);\n\tnotification_node.set(\"ShaderCompiling\", notification.shader_compiling);\n\tnotification_node.set(\"FriendService\", notification.friends);\n\n\t// audio\n\tauto audio = config.set(\"Audio\");\n\taudio.set(\"api\", audio_api);\n\taudio.set(\"delay\", audio_delay);\n\taudio.set(\"TVChannels\", tv_channels);\n\taudio.set(\"PadChannels\", pad_channels);\n\taudio.set(\"InputChannels\", input_channels);\n\taudio.set(\"TVVolume\", tv_volume);\n\taudio.set(\"PadVolume\", pad_volume);\n\taudio.set(\"InputVolume\", input_volume);\n\taudio.set(\"PortalVolume\", portal_volume);\n\taudio.set(\"TVDevice\", boost::nowide::narrow(tv_device).c_str());\n\taudio.set(\"PadDevice\", boost::nowide::narrow(pad_device).c_str());\n\taudio.set(\"InputDevice\", boost::nowide::narrow(input_device).c_str());\n\taudio.set(\"PortalDevice\", boost::nowide::narrow(portal_device).c_str());\n\n\t// account\n\tauto acc = config.set(\"Account\");\n\tacc.set(\"PersistentId\", account.m_persistent_id.GetValue());\n\t// legacy online mode setting\n\tacc.set(\"OnlineEnabled\", account.legacy_online_enabled.GetValue());\n\tacc.set(\"ActiveService\",account.legacy_active_service.GetValue());\n\t// per-account online setting\n\tauto accService = config.set(\"AccountService\");\n\tfor(auto& it : account.service_select)\n\t{\n\t\tauto entry = accService.set(\"SelectedService\");\n\t\tentry.set_attribute(\"PersistentId\", it.first);\n\t\tentry.set_attribute(\"Service\", static_cast<sint32>(it.second));\n\t}\n\t// debug\n\tauto debug = config.set(\"Debug\");\n#if BOOST_OS_WINDOWS\n\tdebug.set(\"CrashDumpWindows\", crash_dump.GetValue());\n#elif BOOST_OS_UNIX\n\tdebug.set(\"CrashDumpUnix\", crash_dump.GetValue());\n#endif\n\tdebug.set(\"GDBPort\", gdb_port);\n#if ENABLE_METAL\n\tdebug.set(\"GPUCaptureDir\", gpu_capture_dir);\n\tdebug.set(\"FramebufferFetch\", framebuffer_fetch);\n#endif\n\n\t// input\n\tauto input = config.set(\"Input\");\n\tauto dsuc = input.set(\"DSUC\");\n\tdsuc.set_attribute(\"host\", dsu_client.host);\n\tdsuc.set_attribute(\"port\", dsu_client.port);\n\n\t// emulated usb devices\n\tauto usbdevices = config.set(\"EmulatedUsbDevices\");\n\tusbdevices.set(\"EmulateSkylanderPortal\", emulated_usb_devices.emulate_skylander_portal.GetValue());\n\tusbdevices.set(\"EmulateInfinityBase\", emulated_usb_devices.emulate_infinity_base.GetValue());\n\tusbdevices.set(\"EmulateDimensionsToypad\", emulated_usb_devices.emulate_dimensions_toypad.GetValue());\n\n\treturn config;\n}\n\nGameEntry* CemuConfig::GetGameEntryByTitleId(uint64 titleId)\n{\n\t// assumes game_cache_entries_mutex is already held\n\tfor (auto& it : game_cache_entries)\n\t{\n\t\tif (it.title_id == titleId)\n\t\t\treturn &it;\n\t}\n\treturn nullptr;\n}\n\nGameEntry* CemuConfig::CreateGameEntry(uint64 titleId)\n{\n\t// assumes game_cache_entries_mutex is already held\n\tGameEntry gameEntry;\n\tgameEntry.title_id = titleId;\n\tgame_cache_entries.emplace_back(gameEntry);\n\treturn &game_cache_entries.back();\n}\n\nbool CemuConfig::IsGameListFavorite(uint64 titleId)\n{\n\tstd::unique_lock _lock(game_cache_entries_mutex);\n\treturn game_cache_favorites.find(titleId) != game_cache_favorites.end();\n}\n\nvoid CemuConfig::SetGameListFavorite(uint64 titleId, bool isFavorite)\n{\n\tstd::unique_lock _lock(game_cache_entries_mutex);\n\tGameEntry* gameEntry = GetGameEntryByTitleId(titleId);\n\tif (!gameEntry)\n\t\tgameEntry = CreateGameEntry(titleId);\n\tgameEntry->favorite = isFavorite;\n\tif (isFavorite)\n\t\tgame_cache_favorites.emplace(titleId);\n\telse\n\t\tgame_cache_favorites.erase(titleId);\n}\n\nbool CemuConfig::GetGameListCustomName(uint64 titleId, std::string& customName)\n{\n\tstd::unique_lock _lock(game_cache_entries_mutex);\n\tGameEntry* gameEntry = GetGameEntryByTitleId(titleId);\n\tif (gameEntry && !gameEntry->custom_name.empty())\n\t{\n\t\tcustomName = gameEntry->custom_name;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nvoid CemuConfig::SetGameListCustomName(uint64 titleId, std::string customName)\n{\n\tstd::unique_lock _lock(game_cache_entries_mutex);\n\tGameEntry* gameEntry = GetGameEntryByTitleId(titleId);\n\tif (!gameEntry)\n\t{\n\t\tif (customName.empty())\n\t\t\treturn;\n\t\tgameEntry = CreateGameEntry(titleId);\n\t}\n\tgameEntry->custom_name = std::move(customName);\n}\n\nNetworkService CemuConfig::GetAccountNetworkService(uint32 persistentId)\n{\n\tauto it = account.service_select.find(persistentId);\n\tif (it != account.service_select.end())\n\t{\n\t\tNetworkService serviceIndex = it->second;\n\t\t// make sure the returned service is valid\n\t\tif (serviceIndex != NetworkService::Offline &&\n\t\t\tserviceIndex != NetworkService::Nintendo &&\n\t\t\tserviceIndex != NetworkService::Pretendo &&\n\t\t\tserviceIndex != NetworkService::Custom)\n\t\t\treturn NetworkService::Offline;\n\t\tif( static_cast<NetworkService>(serviceIndex) == NetworkService::Custom && !NetworkConfig::XMLExists() )\n\t\t\treturn NetworkService::Offline; // custom is selected but no custom config exists\n\t\treturn serviceIndex;\n\t}\n\t// if not found, return the legacy value\n\tif(!account.legacy_online_enabled)\n\t\treturn NetworkService::Offline;\n\treturn static_cast<NetworkService>(account.legacy_active_service.GetValue() + 1); // +1 because \"Offline\" now takes index 0\n}\n\nvoid CemuConfig::SetAccountSelectedService(uint32 persistentId, NetworkService serviceIndex)\n{\n\taccount.service_select[persistentId] = serviceIndex;\n}\n"
  },
  {
    "path": "src/config/CemuConfig.h",
    "content": "#pragma once\n\n#include \"ConfigValue.h\"\n#include \"XMLConfig.h\"\n#include \"util/math/vector2.h\"\n#include \"Cafe/Account/Account.h\"\n\nenum class NetworkService;\n\nstruct GameEntry\n{\n\tGameEntry() = default;\n\n\tstd::wstring rpx_file;\n\tstd::wstring legacy_name;\n\tstd::string product_code;\n\tstd::string company_code;\n\n\tstd::string custom_name;\n\n\tsint32 icon = -1;\n\tsint32 icon_small = -1;\n\tsint32 legacy_version = 0;\n\tsint32 legacy_update_version = -1;\n\tsint32 legacy_dlc_version = -1;\n\tuint64 title_id = 0;\n\tuint32 legacy_region = 0;\n\n\tstd::wstring save_folder;\n\tstd::wstring update_folder;\n\tstd::wstring dlc_folder;\n\n\tuint64 legacy_time_played = 0;\n\tuint64 legacy_last_played = 0;\n\n\tbool favorite = false;\n\n\tbool is_update = false;\n};\n\nstruct GraphicPackEntry\n{\n\tGraphicPackEntry(std::wstring_view filename,std::string_view category, std::string_view preset)\n\t\t: filename(filename)\n\t{\n\t\tpresets[std::string{category}] = preset;\n\t}\n\n\tGraphicPackEntry(std::wstring_view filename, std::string_view preset)\n\t\t: filename(filename)\n\t{\n\t\tpresets[\"\"] = preset;\n\t}\n\n\tGraphicPackEntry(std::wstring filename)\n\t\t: filename(std::move(filename))\n\t{}\n\n\tstruct Preset\n\t{\n\t\tstd::string name;\n\t\tstd::string category;\n\t};\n\tstd::unordered_map<std::string, std::string> presets; // category, active_preset\n\n\tstd::wstring filename;\n\tbool enabled = true;\n};\n\nenum GraphicAPI\n{\n\tkOpenGL = 0,\n\tkVulkan,\n\tkMetal,\n};\n\nenum AudioChannels\n{\n\tkMono = 0,\n\tkStereo,\n\tkSurround,\n};\n\nenum UpscalingFilter\n{\n\tkLinearFilter,\n\tkBicubicFilter,\n\tkBicubicHermiteFilter,\n\tkNearestNeighborFilter,\n};\n\nenum FullscreenScaling\n{\n\tkKeepAspectRatio,\n\tkStretch,\n};\n\nenum class ScreenPosition\n{\n\tkDisabled = 0,\n\tkTopLeft,\n\tkTopCenter,\n\tkTopRight,\n\tkBottomLeft,\n\tkBottomCenter,\n\tkBottomRight,\n};\n\nenum class PrecompiledShaderOption\n{\n\tAuto,\n\tEnable,\n\tDisable,\n};\nENABLE_ENUM_ITERATORS(PrecompiledShaderOption, PrecompiledShaderOption::Auto, PrecompiledShaderOption::Disable);\n\nenum class AccurateShaderMulOption\n{\n\tFalse = 0, // always use standard multiplication\n\tTrue = 1 // fully emulate non-ieee MUL special cases (0*anything = 0)\n};\nENABLE_ENUM_ITERATORS(AccurateShaderMulOption, AccurateShaderMulOption::False, AccurateShaderMulOption::True);\n\nenum class MetalBufferCacheMode\n{\n    Auto,\n    DevicePrivate,\n    DeviceShared,\n    Host,\n};\nENABLE_ENUM_ITERATORS(MetalBufferCacheMode, MetalBufferCacheMode::Auto, MetalBufferCacheMode::Host);\n\nenum class PositionInvariance\n{\n    Auto,\n    False,\n    True,\n};\nENABLE_ENUM_ITERATORS(PositionInvariance, PositionInvariance::False, PositionInvariance::True);\n\nenum class CPUMode\n{\n\tSinglecoreInterpreter = 0,\n\tSinglecoreRecompiler = 1,\n\tDualcoreRecompiler = 2, // deprecated and not used anymore\n\tMulticoreRecompiler = 3,\n\tAuto = 4,\n};\nENABLE_ENUM_ITERATORS(CPUMode, CPUMode::SinglecoreInterpreter, CPUMode::Auto);\n\n\nenum class CPUModeLegacy\n{\n\tSinglecoreInterpreter = 0,\n\tSinglecoreRecompiler = 1,\n\tDualcoreRecompiler = 2,\n\tTriplecoreRecompiler = 3,\n\tAuto = 4\n};\nENABLE_ENUM_ITERATORS(CPUModeLegacy, CPUModeLegacy::SinglecoreInterpreter, CPUModeLegacy::Auto);\n\nenum class CafeConsoleRegion\n{\n\tJPN = 0x1,\n\tUSA = 0x2,\n\tEUR = 0x4,\n\tAUS_DEPR = 0x8,\n\tCHN = 0x10,\n\tKOR = 0x20,\n\tTWN = 0x40,\n\tAuto = 0xFF,\n};\nENABLE_BITMASK_OPERATORS(CafeConsoleRegion);\n\nenum class CafeConsoleLanguage\n{\n\tJA = 0,\n\tEN = 1,\n\tFR = 2,\n\tDE = 3,\n\tIT = 4,\n\tES = 5,\n\tZH = 6,\n\tKO = 7,\n\tNL = 8,\n\tPT = 9,\n\tRU = 10,\n\tTW = 11,\n};\nENABLE_ENUM_ITERATORS(CafeConsoleLanguage, CafeConsoleLanguage::JA, CafeConsoleLanguage::TW);\n\n#if BOOST_OS_WINDOWS\nenum class CrashDump\n{\n\tDisabled,\n\tLite,\n\tFull\n};\nENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Full);\n#elif BOOST_OS_UNIX\nenum class CrashDump\n{\n\tDisabled,\n\tEnabled\n};\nENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Enabled);\n#endif\n\ntemplate <>\nstruct fmt::formatter<PrecompiledShaderOption> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(const PrecompiledShaderOption c, FormatContext &ctx) const {\n\t\tstring_view name;\n\t\tswitch (c)\n\t\t{\n\t\tcase PrecompiledShaderOption::Auto: name = \"auto\"; break;\n\t\tcase PrecompiledShaderOption::Enable: name = \"true\"; break;\n\t\tcase PrecompiledShaderOption::Disable: name = \"false\"; break;\n\t\tdefault: name = \"unknown\"; break;\n\t\t}\n\t\treturn formatter<string_view>::format(name, ctx);\n\t}\n};\ntemplate <>\nstruct fmt::formatter<AccurateShaderMulOption> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(const AccurateShaderMulOption c, FormatContext &ctx) const {\n\t\tstring_view name;\n\t\tswitch (c)\n\t\t{\n\t\tcase AccurateShaderMulOption::True: name = \"true\"; break;\n\t\tcase AccurateShaderMulOption::False: name = \"false\"; break;\n\t\tdefault: name = \"unknown\"; break;\n\t\t}\n\t\treturn formatter<string_view>::format(name, ctx);\n\t}\n};\ntemplate <>\nstruct fmt::formatter<MetalBufferCacheMode> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(const MetalBufferCacheMode c, FormatContext &ctx) const {\n\t\tstring_view name;\n\t\tswitch (c)\n\t\t{\n\t\tcase MetalBufferCacheMode::Auto: name = \"auto\"; break;\n\t\tcase MetalBufferCacheMode::DevicePrivate: name = \"device private\"; break;\n\t\tcase MetalBufferCacheMode::DeviceShared: name = \"device shared\"; break;\n\t\tcase MetalBufferCacheMode::Host: name = \"host\"; break;\n\t\tdefault: name = \"unknown\"; break;\n\t\t}\n\t\treturn formatter<string_view>::format(name, ctx);\n\t}\n};\ntemplate <>\nstruct fmt::formatter<PositionInvariance> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(const PositionInvariance c, FormatContext &ctx) const {\n\t\tstring_view name;\n\t\tswitch (c)\n\t\t{\n\t\tcase PositionInvariance::Auto: name = \"auto\"; break;\n\t\tcase PositionInvariance::False: name = \"false\"; break;\n\t\tcase PositionInvariance::True: name = \"true\"; break;\n\t\tdefault: name = \"unknown\"; break;\n\t\t}\n\t\treturn formatter<string_view>::format(name, ctx);\n\t}\n};\ntemplate <>\nstruct fmt::formatter<CPUMode> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(const CPUMode c, FormatContext &ctx) const {\n\t\tstring_view name;\n\t\tswitch (c)\n\t\t{\n\t\tcase CPUMode::SinglecoreInterpreter: name = \"Single-core interpreter\"; break;\n\t\tcase CPUMode::SinglecoreRecompiler: name = \"Single-core recompiler\"; break;\n\t\tcase CPUMode::DualcoreRecompiler: name = \"Dual-core recompiler\"; break;\n\t\tcase CPUMode::MulticoreRecompiler: name = \"Multi-core recompiler\"; break;\n\t\tcase CPUMode::Auto: name = \"Auto\"; break;\n\t\tdefault: name = \"unknown\"; break;\n\t\t}\n\t\treturn formatter<string_view>::format(name, ctx);\n\t}\n};\ntemplate <>\nstruct fmt::formatter<CPUModeLegacy> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(const CPUModeLegacy c, FormatContext &ctx) const {\n\t\tstring_view name;\n\t\tswitch (c)\n\t\t{\n\t\tcase CPUModeLegacy::SinglecoreInterpreter: name = \"Singlecore-Interpreter\"; break;\n\t\tcase CPUModeLegacy::SinglecoreRecompiler: name = \"Singlecore-Recompiler\"; break;\n\t\tcase CPUModeLegacy::DualcoreRecompiler: name = \"Dualcore-Recompiler\"; break;\n\t\tcase CPUModeLegacy::TriplecoreRecompiler: name = \"Triplecore-Recompiler\"; break;\n\t\tcase CPUModeLegacy::Auto: name = \"Auto\"; break;\n\t\tdefault: name = \"unknown\"; break;\n\t\t}\n\t\treturn formatter<string_view>::format(name, ctx);\n\t}\n};\ntemplate <>\nstruct fmt::formatter<CafeConsoleRegion> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(const CafeConsoleRegion v, FormatContext &ctx) const {\n\t\tstring_view name;\n\t\tswitch (v)\n\t\t{\n\t\tcase CafeConsoleRegion::JPN: name = TR_NOOP(\"Japan\"); break;\n\t\tcase CafeConsoleRegion::USA: name = TR_NOOP(\"USA\"); break;\n\t\tcase CafeConsoleRegion::EUR: name = TR_NOOP(\"Europe\"); break;\n\t\tcase CafeConsoleRegion::AUS_DEPR: name = TR_NOOP(\"Australia\"); break;\n\t\tcase CafeConsoleRegion::CHN: name = TR_NOOP(\"China\"); break;\n\t\tcase CafeConsoleRegion::KOR: name = TR_NOOP(\"Korea\"); break;\n\t\tcase CafeConsoleRegion::TWN: name = TR_NOOP(\"Taiwan\"); break;\n\t\tcase CafeConsoleRegion::Auto: name = TR_NOOP(\"Auto\"); break;\n\t\tdefault: name = TR_NOOP(\"many\"); break;\n\n\t\t}\n\t\treturn formatter<string_view>::format(name, ctx);\n\t}\n};\ntemplate <>\nstruct fmt::formatter<CafeConsoleLanguage> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(const CafeConsoleLanguage v, FormatContext &ctx) {\n\t\tstring_view name;\n\t\tswitch (v)\n\t\t{\n\t\tcase CafeConsoleLanguage::JA: name = \"Japanese\"; break;\n\t\tcase CafeConsoleLanguage::EN: name = \"English\"; break;\n\t\tcase CafeConsoleLanguage::FR: name = \"French\"; break;\n\t\tcase CafeConsoleLanguage::DE: name = \"German\"; break;\n\t\tcase CafeConsoleLanguage::IT: name = \"Italian\"; break;\n\t\tcase CafeConsoleLanguage::ES: name = \"Spanish\"; break;\n\t\tcase CafeConsoleLanguage::ZH: name = \"Chinese\"; break;\n\t\tcase CafeConsoleLanguage::KO: name = \"Korean\"; break;\n\t\tcase CafeConsoleLanguage::NL: name = \"Dutch\"; break;\n\t\tcase CafeConsoleLanguage::PT: name = \"Portugese\"; break;\n\t\tcase CafeConsoleLanguage::RU: name = \"Russian\"; break;\n\t\tcase CafeConsoleLanguage::TW: name = \"Taiwanese\"; break;\n\t\tdefault: name = \"unknown\"; break;\n\t\t}\n\t\treturn formatter<string_view>::format(name, ctx);\n\t}\n};\n\n#if BOOST_OS_WINDOWS\ntemplate <>\nstruct fmt::formatter<CrashDump> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(const CrashDump v, FormatContext &ctx) {\n\t\tstring_view name;\n\t\tswitch (v)\n\t\t{\n\t\tcase CrashDump::Disabled: name = \"Disabled\"; break;\n\t\tcase CrashDump::Lite: name = \"Lite\"; break;\n\t\tcase CrashDump::Full: name = \"Full\"; break;\n\t\tdefault: name = \"unknown\"; break;\n\n\t\t}\n\t\treturn formatter<string_view>::format(name, ctx);\n\t}\n};\n#elif BOOST_OS_UNIX\ntemplate <>\nstruct fmt::formatter<CrashDump> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(const CrashDump v, FormatContext &ctx) {\n\t\tstring_view name;\n\t\tswitch (v)\n\t\t{\n\t\tcase CrashDump::Disabled: name = \"Disabled\"; break;\n\t\tcase CrashDump::Enabled: name = \"Enabled\"; break;\n\t\tdefault: name = \"unknown\"; break;\n\n\t\t}\n\t\treturn formatter<string_view>::format(name, ctx);\n\t}\n};\n#endif\n\n\nstruct CemuConfig\n{\n\tCemuConfig()\n\t{\n\n\t};\n\n\tCemuConfig(const CemuConfig&) = delete;\n\n\t// sets mlc path, updates permanent config value, saves config\n\tvoid SetMLCPath(fs::path path, bool save = true);\n\n\tConfigValue<uint64> log_flag{ 0 };\n\tConfigValue<bool> advanced_ppc_logging{ false };\n\n\tConfigValue<bool> permanent_storage{ true };\n\n\tConfigValue<std::string> mlc_path{};\n\tConfigValue<std::string> proxy_server{};\n\n\t// temporary workaround because feature crashes on macOS\n#if BOOST_OS_MACOS\n#define DISABLE_SCREENSAVER_DEFAULT false\n#else\n#define DISABLE_SCREENSAVER_DEFAULT true\n#endif\n\tConfigValue<bool> disable_screensaver{DISABLE_SCREENSAVER_DEFAULT};\n#undef DISABLE_SCREENSAVER_DEFAULT\n\tConfigValue<bool> play_boot_sound{false};\n\n\tstd::vector<std::string> game_paths;\n\tstd::mutex game_cache_entries_mutex;\n\tstd::vector<GameEntry> game_cache_entries;\n\n\t// optimized access\n\tstd::set<uint64> game_cache_favorites; // per titleId\n\n\tstruct _path_hash {\n\t\tstd::size_t operator()(const fs::path& path) const {\n\t\t\treturn fs::hash_value(path);\n\t\t}\n\t};\n\t// <filename, <category, preset>>\n\tstd::unordered_map<fs::path, std::unordered_map<std::string, std::string>, _path_hash> graphic_pack_entries;\n\n\tConfigValueBounds<CPUMode> cpu_mode{ CPUMode::Auto };\n\tConfigValueBounds<CafeConsoleLanguage> console_language{ CafeConsoleLanguage::EN };\n\n\t// graphics\n\tConfigValue<GraphicAPI> graphic_api{ kVulkan };\n\tstd::array<uint8, 16> legacy_graphic_device_uuid{}; // placeholder option for backwards compatibility with settings from 2.6 and before (renamed to \"vkDevice\")\n\tstd::array<uint8, 16> vk_graphic_device_uuid;\n\tuint64 mtl_graphic_device_uuid{ 0 };\n\tConfigValue<int> vsync{ 0 }; // 0 = off, 1+ = depending on render backend\n\tConfigValue<bool> gx2drawdone_sync { true };\n\tConfigValue<bool> render_upside_down{ false };\n\tConfigValue<bool> async_compile{ true };\n#if ENABLE_METAL\n\tConfigValue<bool> force_mesh_shaders{ false };\n#endif\n\n\t// Gamma\n\tConfigValue<bool> overrideAppGammaPreference{ false };\n\tConfigValue<float> overrideGammaValue{ 2.2f };\n\tConfigValue<float> userDisplayGamma { 2.2f }; // 0 = sRGB, >0 gamma\n\n\tConfigValue<bool> vk_accurate_barriers{ true };\n\n\tstruct\n\t{\n\t\tScreenPosition position = ScreenPosition::kDisabled;\n\t\tuint32 text_color = 0xFFFFFFFF;\n\t\tsint32 text_scale = 100;\n\t\tbool fps = true;\n\t\tbool drawcalls = false;\n\t\tbool cpu_usage = false;\n\t\tbool cpu_per_core_usage = false;\n\t\tbool ram_usage = false;\n\t\tbool vram_usage = false;\n\t\tbool debug = false;\n\t} overlay{};\n\n\tstruct\n\t{\n\t\tScreenPosition position = ScreenPosition::kTopLeft;\n\t\tuint32 text_color = 0xFFFFFFFF;\n\t\tsint32 text_scale = 100;\n\t\tbool controller_profiles = true;\n\t\tbool controller_battery = false;\n\t\tbool shader_compiling = true;\n\t\tbool friends = true;\n\t} notification{};\n\n\tConfigValue<sint32> upscale_filter{kBicubicFilter};\n\tConfigValue<sint32> downscale_filter{kLinearFilter};\n\tConfigValue<sint32> fullscreen_scaling{kKeepAspectRatio};\n\n\t// audio\n\tsint32 audio_api = 0;\n\tsint32 audio_delay = 2;\n\tAudioChannels tv_channels = kStereo, pad_channels = kStereo, input_channels = kMono;\n\tsint32 tv_volume = 50, pad_volume = 0, input_volume = 50, portal_volume = 50;\n\tstd::wstring tv_device{ L\"default\" }, pad_device, input_device, portal_device;\n\n\t// account\n\tstruct\n\t{\n\t\tConfigValueBounds<uint32> m_persistent_id{ Account::kMinPersistendId, Account::kMinPersistendId, 0xFFFFFFFF };\n\t\tConfigValue<bool> legacy_online_enabled{false};\n\t\tConfigValue<int> legacy_active_service{0};\n\t\tstd::unordered_map<uint32, NetworkService> service_select; // per-account service index. Key is persistentId\n\t}account{};\n\n\t// input\n\tstruct\n\t{\n\t\tConfigValue<std::string> host{\"127.0.0.1\"};\n\t\tConfigValue<uint16> port{ 26760 };\n\t}dsu_client{};\n\n\t// debug\n\tConfigValueBounds<CrashDump> crash_dump{ CrashDump::Disabled };\n\tConfigValue<uint16> gdb_port{ 1337 };\n#if ENABLE_METAL\n\tConfigValue<std::string> gpu_capture_dir{ \"\" };\n\tConfigValue<bool> framebuffer_fetch{ true };\n#endif\n\n\tXMLConfigParser Load(XMLConfigParser& parser);\n\tXMLConfigParser Save(XMLConfigParser& parser);\n\n\tbool IsGameListFavorite(uint64 titleId);\n\tvoid SetGameListFavorite(uint64 titleId, bool isFavorite);\n\tbool GetGameListCustomName(uint64 titleId, std::string& customName);\n\tvoid SetGameListCustomName(uint64 titleId, std::string customName);\n\n\tNetworkService GetAccountNetworkService(uint32 persistentId);\n\tvoid SetAccountSelectedService(uint32 persistentId, NetworkService serviceIndex);\n\n\t// emulated usb devices\n\tstruct\n\t{\n\t\tConfigValue<bool> emulate_skylander_portal{false};\n\t\tConfigValue<bool> emulate_infinity_base{false};\n\t\tConfigValue<bool> emulate_dimensions_toypad{false};\n\t}emulated_usb_devices{};\n\n\tstatic int AudioChannelsToNChannels(AudioChannels kStereo)\n\t{\n\t\tswitch (kStereo)\n\t\t{\n\t\tcase 0:\n\t\t\treturn 1; // will mix mono sound on both output channels\n\t\tcase 2:\n\t\t\treturn 6;\n\t\tdefault: // stereo\n\t\t\treturn 2;\n\t\t}\n\t}\n\n  private:\n\tGameEntry* GetGameEntryByTitleId(uint64 titleId);\n\tGameEntry* CreateGameEntry(uint64 titleId);\n};\n\ntypedef XMLDataConfig<CemuConfig> XMLCemuConfig_t;\n\ninline XMLCemuConfig_t& GetConfigHandle()\n{\n\tstatic XMLCemuConfig_t config;\n\treturn config;\n}\n\ninline CemuConfig& GetConfig()\n{\n\treturn GetConfigHandle().data();\n}\n"
  },
  {
    "path": "src/config/ConfigValue.h",
    "content": "#pragma once\n\n#include \"Common/enumFlags.h\"\n\n#include <mutex>\n#include <atomic>\n#include <shared_mutex>\n#include <cassert>\n#include <string>\n\ntemplate<typename TType>\nclass ConfigValueAtomic\n{\npublic:\n\tconstexpr ConfigValueAtomic()\n\t\t: m_value(TType()), m_init_value(TType()) {}\n\n\tconstexpr ConfigValueAtomic(const TType& init_value)\n\t\t: m_value(init_value), m_init_value(init_value) {}\n\n\tconstexpr ConfigValueAtomic(TType&& init_value)\n\t\t: m_value(init_value), m_init_value(init_value) {}\n\n\tConfigValueAtomic(const ConfigValueAtomic& v)\n\t\t: m_value(v.GetValue()), m_init_value(v.m_init_value) {}\n\n\tConfigValueAtomic& operator=(const ConfigValueAtomic& v)\n\t{\n\t\tSetValue(v.GetValue());\n\t\treturn *this;\n\t}\n\n\tConfigValueAtomic& operator=(const TType& v)\n\t{\n\t\tSetValue(v);\n\t\treturn *this;\n\t}\n\n\tConfigValueAtomic& operator=(TType&& v)\n\t{\n\t\tSetValue(v);\n\t\treturn *this;\n\t}\n\n\t[[nodiscard]] inline TType GetValue() const { return m_value.load(); }\n\tvoid SetValue(const TType& v) { m_value = v; }\n\n\t[[nodiscard]] const TType& GetInitValue() const { return m_init_value; }\n\toperator TType() const { return m_value.load(); }\n\nprivate:\n\tstd::atomic<TType> m_value;\n\tconst TType m_init_value;\n};\n\ntemplate<typename TType>\nclass ConfigValueNoneAtomic\n{\npublic:\n\tconstexpr ConfigValueNoneAtomic()\n\t\t: m_value({}), m_init_value({}) {}\n\n\tconstexpr ConfigValueNoneAtomic(const TType& init_value)\n\t\t: m_value(init_value), m_init_value(init_value) {}\n\n\tconstexpr ConfigValueNoneAtomic(TType&& init_value)\n\t\t: m_value(init_value), m_init_value(init_value) {}\n\n\tConfigValueNoneAtomic(const ConfigValueNoneAtomic& v)\n\t\t: m_value(v.GetValue()), m_init_value(v.GetInitValue()) {}\n\n\tConfigValueNoneAtomic& operator=(const ConfigValueNoneAtomic& v)\n\t{\n\t\tSetValue(v.GetValue());\n\t\treturn *this;\n\t}\n\n\tConfigValueNoneAtomic& operator=(const TType& v)\n\t{\n\t\tSetValue(v);\n\t\treturn *this;\n\t}\n\n\tConfigValueNoneAtomic& operator=(TType&& v)\n\t{\n\t\tSetValue(v);\n\t\treturn *this;\n\t}\n\n\t[[nodiscard]] TType GetValue() const\n\t{\n\t\tstd::shared_lock lock(m_mutex);\n\t\treturn m_value;\n\t}\n\n\tvoid SetValue(const TType& v)\n\t{\n\t\tstd::lock_guard lock(m_mutex);\n\t\tm_value = v;\n\t}\n\n\tvoid SetValue(std::string_view v)\n\t\trequires std::is_same_v<TType, std::string>\n\t{\n\t\tstd::lock_guard lock(m_mutex);\n\t\tm_value = v;\n\t}\n\n\tvoid SetValue(std::wstring_view v)\n\t\trequires std::is_same_v<TType, std::string>\n\t{\n\t\tstd::lock_guard lock(m_mutex);\n\t\tm_value = v;\n\t}\n\n\t[[nodiscard]] const TType& GetInitValue() const { return m_init_value; }\n\n\t[[nodiscard]] operator TType() const\n\t{\n\t\treturn GetValue();\n\t}\n\nprotected:\n\tmutable std::shared_mutex m_mutex;\n\tTType m_value;\n\tconst TType m_init_value;\n};\n\ntemplate<typename TType>\nconstexpr bool is_atomic_type_v = std::is_trivially_copyable_v<TType> && std::is_copy_constructible_v<TType> && std::is_move_constructible_v<TType> && std::is_copy_assignable_v<TType> && std::is_move_assignable_v<TType>;\n\ntemplate<typename TType>\nclass ConfigValue : public std::conditional<is_atomic_type_v<TType>, ConfigValueAtomic<TType>, ConfigValueNoneAtomic<TType>>::type\n{\npublic:\n\tusing base_type = typename std::conditional<is_atomic_type_v<TType>, ConfigValueAtomic<TType>, ConfigValueNoneAtomic<TType>>::type;\n\tusing base_type::base_type;\n\n\tConfigValue& operator=(const ConfigValue& v)\n\t{\n\t\tbase_type::operator=(v.GetValue());\n\t\treturn *this;\n\t}\n\n\tConfigValue& operator=(const TType& v)\n\t{\n\t\tbase_type::operator=(v);\n\t\treturn *this;\n\t}\n\n\tConfigValue& operator=(TType&& v)\n\t{\n\t\tbase_type::operator=(v);\n\t\treturn *this;\n\t}\n};\n\ntemplate<typename TType>\nclass ConfigValueBounds : public ConfigValue<TType>\n{\npublic:\n\tusing base_type = ConfigValue<TType>;\n\n\tconstexpr ConfigValueBounds(const TType& min, const TType& init_value, const TType& max)\n\t\t:base_type(init_value), m_min_value(min), m_max_value(max)\n\t{\n\t\tassert(m_min_value <= init_value && init_value <= m_max_value);\n\t}\n\n\tconstexpr ConfigValueBounds(TType&& min, TType&& init_value, TType&& max)\n\t\t: base_type(std::forward<TType>(init_value)), m_min_value(min), m_max_value(max)\n\t{\n\t\tassert(m_min_value <= init_value && init_value <= m_max_value);\n\t}\n\n\t// init from enum with iterators\n\tconstexpr ConfigValueBounds()\n\t\trequires std::is_enum_v<TType> && EnableEnumIterators<TType>::enable\n\t\t: base_type(), m_min_value(begin(TType{})), m_max_value(rbegin(TType{}))\n\t{\n\t\tassert(m_min_value <= this->GetInitValue() && this->GetInitValue() <= m_max_value);\n\t}\n\n\tconstexpr ConfigValueBounds(const TType& init_value)\n\t\trequires std::is_enum_v<TType> && EnableEnumIterators<TType>::enable\n\t\t: base_type(std::forward<TType>(init_value)), m_min_value(begin(init_value)), m_max_value(rbegin(init_value))\n\t{\n\t\tassert(m_min_value <= init_value && init_value <= m_max_value);\n\t}\n\n\tconstexpr ConfigValueBounds(TType&& init_value)\n\t\trequires std::is_enum_v<TType> && EnableEnumIterators<TType>::enable\n\t\t: base_type(std::forward<TType>(init_value)), m_min_value(begin(init_value)), m_max_value(rbegin(init_value))\n\t{\n\t\tassert(m_min_value <= init_value && init_value <= m_max_value);\n\t}\n\n\tConfigValueBounds& operator=(const ConfigValueBounds& v)\n\t{\n\t\tbase_type::operator=(v.GetValue());\n\n\t\tconst auto& value = this->GetValue();\n\t\tif (value < GetMin() || value > GetMax())\n\t\t\tbase_type::SetValue(this->GetInitValue());\n\n\t\treturn *this;\n\t};\n\n\tConfigValueBounds& operator=(const TType& v)\n\t{\n\t\tbase_type::operator=(v);\n\n\t\tconst auto& value = this->GetValue();\n\t\tif (value < GetMin() || value > GetMax())\n\t\t\tbase_type::SetValue(this->GetInitValue());\n\n\t\treturn *this;\n\t};\n\n\tConfigValueBounds& operator=(TType&& v)\n\t{\n\t\tbase_type::operator=(v);\n\n\t\tconst auto& value = this->GetValue();\n\t\tif (value < GetMin() || value > GetMax())\n\t\t\tbase_type::SetValue(this->GetInitValue());\n\n\t\treturn *this;\n\t};\n\n\t[[nodiscard]] const TType& GetMax() const { return m_max_value; }\n\t[[nodiscard]] const TType& GetMin() const { return m_min_value; }\n\nprivate:\n\tconst TType m_min_value;\n\tconst TType m_max_value;\n};\n"
  },
  {
    "path": "src/config/LaunchSettings.cpp",
    "content": "#include \"LaunchSettings.h\"\n\n#include \"util/helpers/helpers.h\"\n#include \"Cafe/Account/Account.h\"\n\n#include \"Cafe/OS/libs/coreinit/coreinit.h\"\n\n#include \"boost/program_options.hpp\"\n\n#include \"config/ActiveSettings.h\"\n#include \"config/NetworkSettings.h\"\n#include \"util/crypto/aes128.h\"\n\n#include \"Cafe/Filesystem/FST/FST.h\"\n#include \"util/helpers/StringHelpers.h\"\n\nvoid requireConsole();\n\nbool LaunchSettings::HandleCommandline(const wchar_t* lpCmdLine)\n{\n\t#if BOOST_OS_WINDOWS\n\tconst std::vector<std::wstring> args = boost::program_options::split_winmain(lpCmdLine);\n\treturn HandleCommandline(args);\n\t#else\n\tcemu_assert_unimplemented();\n\treturn false;\n\t#endif\n}\n\nbool LaunchSettings::HandleCommandline(int argc, wchar_t* argv[])\n{\n\tstd::vector<std::wstring> args;\n\targs.reserve(argc);\n\tfor(int i = 0; i < argc; ++i)\n\t{\n\t\targs.emplace_back(argv[i]);\n\t}\n\t\n\treturn HandleCommandline(args);\n}\n\nbool LaunchSettings::HandleCommandline(int argc, char* argv[])\n{\n\tstd::vector<std::wstring> args;\n\targs.reserve(argc);\n\tfor(int i = 0; i < argc; ++i)\n\t{\n\t\targs.emplace_back(boost::nowide::widen(argv[i]));\n\t}\n\t\n\treturn HandleCommandline(args);\n}\n\nbool LaunchSettings::HandleCommandline(const std::vector<std::wstring>& args)\n{\n\tnamespace po = boost::program_options;\n\tpo::options_description desc{ \"Launch options\" };\n\tdesc.add_options()\n\t\t(\"help,h\", \"This help screen\")\n\t\t(\"version,v\", \"Displays the version of Cemu\")\n#if !BOOST_OS_WINDOWS\n\t\t(\"verbose\", \"Log to stdout\")\n#endif\n\n\t\t(\"game,g\", po::wvalue<std::wstring>(), \"Path of game to launch\")\n        (\"title-id,t\", po::value<std::string>(), \"Title ID of the title to be launched (overridden by --game)\")\n\t\t(\"mlc,m\", po::wvalue<std::wstring>(), \"Custom mlc folder location\")\n\n\t\t(\"fullscreen,f\", po::value<bool>()->implicit_value(true), \"Launch games in fullscreen mode\")\n\t\t(\"ud,u\", po::value<bool>()->implicit_value(true), \"Render output upside-down\")\n\n\t\t(\"account,a\", po::value<std::string>(), \"Persistent id of account\")\n\n\t\t(\"force-interpreter\", po::value<bool>()->implicit_value(true), \"Force interpreter CPU emulation, disables recompiler. Useful for debugging purposes where you want to get accurate memory accesses and stack traces.\")\n\t\t(\"force-multicore-interpreter\", po::value<bool>()->implicit_value(true), \"Force multi-core interpreter CPU emulation, disables recompiler. Only useful for getting stack traces, but slightly faster than the single-core interpreter mode.\")\n\t\t(\"enable-gdbstub\", po::value<bool>()->implicit_value(true), \"Enable GDB stub to debug executables inside Cemu using an external debugger\");\n\n\tpo::options_description hidden{ \"Hidden options\" };\n\thidden.add_options()\n\t\t(\"nsight\", po::value<bool>()->implicit_value(true), \"NSight debugging options\")\n\t\t(\"legacy\", po::value<bool>()->implicit_value(true), \"Intel legacy graphic mode\")\n\t\t(\"ppcrec-lower-addr\", po::value<std::string>(), \"For debugging: Lower address allowed for PPC recompilation\")\n\t\t(\"ppcrec-upper-addr\", po::value<std::string>(), \"For debugging: Upper address allowed for PPC recompilation\");\n\n\tpo::options_description extractor{ \"Extractor tool\" };\n\textractor.add_options()\n\t\t(\"extract,e\", po::wvalue<std::wstring>(), \"Path to WUD or WUX file for extraction\")\n\t\t(\"path,p\", po::value<std::string>(), \"Path of file to extract (for example meta/meta.xml)\")\n\t\t(\"output,o\", po::wvalue<std::wstring>(), \"Output path for extracted file.\");\n\t\n\tpo::options_description all;\n\tall.add(desc).add(hidden).add(extractor);\n\n\tpo::options_description visible;\n\tvisible.add(desc).add(extractor);\n\n\ttry\n\t{\n\t\tpo::wcommand_line_parser parser{ args };\n\t\tparser.allow_unregistered().options(all).style(po::command_line_style::allow_long | po::command_line_style::allow_short | po::command_line_style::allow_dash_for_short | po::command_line_style::case_insensitive |\n\t\t\tpo::command_line_style::long_allow_next |\n\t\t\tpo::command_line_style::short_allow_next |\n\t\t\tpo::command_line_style::allow_long_disguise);\n\n\t\tconst auto parsed_options = parser.run();\n\n\t\tpo::variables_map vm;\n\t\tpo::store(parsed_options, vm);\n\t\tnotify(vm);\n\n\t\tif (vm.count(\"help\"))\n\t\t{\n\t\t\trequireConsole();\n\t\t\tstd::cout << visible << std::endl;\n\t\t\treturn false; // exit in main\n\t\t}\n\t\tif (vm.count(\"version\"))\n\t\t{\n\t\t\trequireConsole();\n\t\t\tstd::string versionStr;\n#if EMULATOR_VERSION_PATCH == 0\n\t\t\tversionStr = fmt::format(\"{}.{}{}\", EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_SUFFIX);\n#else\n\t\t\tversionStr = fmt::format(\"{}.{}-{}{}\", EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH, EMULATOR_VERSION_SUFFIX);\n#endif\n\t\t\tstd::cout << versionStr << std::endl;\n\t\t\treturn false; // exit in main\n\t\t}\n\n\t\tif (vm.count(\"verbose\"))\n\t\t\ts_verbose = true;\n\n\t\tif (vm.count(\"game\"))\n\t\t{\n\t\t\tstd::wstring tmp = vm[\"game\"].as<std::wstring>();\n\t\t\t// workaround for boost command_line_parser not trimming token for short name parameters despite short_allow_adjacent\n\t\t\tif (tmp.size() > 0 && tmp.front() == '=')\n\t\t\t\ttmp.erase(tmp.begin()+0);\n\t\t\t\n\t\t\ts_load_game_file = tmp;\n\t\t}\n        if (vm.count(\"title-id\"))\n        {\n            auto title_param = vm[\"title-id\"].as<std::string>();\n            try {\n\n                if (title_param.starts_with('=')){\n                    title_param.erase(title_param.begin());\n                }\n                s_load_title_id = std::stoull(title_param, nullptr, 16);\n            }\n            catch (std::invalid_argument const& e)\n            {\n                std::cerr << \"Expected title_param ID as an unsigned 64-bit hexadecimal string\\n\";\n            }\n        }\n\t\t\t\n\t\tif (vm.count(\"mlc\"))\n\t\t{\n\t\t\tstd::wstring tmp = vm[\"mlc\"].as<std::wstring>();\n\t\t\t// workaround for boost command_line_parser not trimming token for short name parameters despite short_allow_adjacent\n\t\t\tif (tmp.size() > 0 && tmp.front() == '=')\n\t\t\t\ttmp.erase(tmp.begin() + 0);\n\n\t\t\ts_mlc_path = tmp;\n\t\t}\n\n\t\tif (vm.count(\"account\"))\n\t\t{\n\t\t\tconst auto id = ConvertString<uint32>(vm[\"account\"].as<std::string>(), 16);\n\t\t\tif (id >= Account::kMinPersistendId)\n\t\t\t\ts_persistent_id = id;\n\t\t}\n\t\t\n\t\tif (vm.count(\"fullscreen\"))\n\t\t\ts_fullscreen = vm[\"fullscreen\"].as<bool>();\n\t\tif (vm.count(\"ud\"))\n\t\t\ts_render_upside_down = vm[\"ud\"].as<bool>();\n\t\t\n\t\tif (vm.count(\"nsight\"))\n\t\t\ts_nsight_mode = vm[\"nsight\"].as<bool>();\n\n\t\tif(vm.count(\"force-interpreter\"))\n\t\t\ts_force_interpreter = vm[\"force-interpreter\"].as<bool>();\n\n\t\tif(vm.count(\"force-multicore-interpreter\"))\n\t\t\ts_force_multicore_interpreter = vm[\"force-multicore-interpreter\"].as<bool>();\n\t\t\n\t\tif (vm.count(\"enable-gdbstub\"))\n\t\t\ts_enable_gdbstub = vm[\"enable-gdbstub\"].as<bool>();\n\n\t\tstd::wstring extract_path, log_path;\n\t\tstd::string output_path;\n\t\tif (vm.count(\"extract\"))\n\t\t\textract_path = vm[\"extract\"].as<std::wstring>();\n\t\tif (vm.count(\"path\"))\n\t\t\toutput_path = vm[\"path\"].as<std::string>();\n\t\tif (vm.count(\"output\"))\n\t\t\tlog_path = vm[\"output\"].as<std::wstring>();\n\n\t\t// recompiler range limit for debugging\n\t\tif (vm.count(\"ppcrec-lower-addr\"))\n\t\t{\n\t\t\tuint32 addr = (uint32)StringHelpers::ToInt64(vm[\"ppcrec-lower-addr\"].as<std::string>());\n\t\t\tppcRec_limitLowerAddr = addr;\n\t\t}\n\t\tif (vm.count(\"ppcrec-upper-addr\"))\n\t\t{\n\t\t\tuint32 addr = (uint32)StringHelpers::ToInt64(vm[\"ppcrec-upper-addr\"].as<std::string>());\n\t\t\tppcRec_limitUpperAddr = addr;\n\t\t}\n\t\tif(ppcRec_limitLowerAddr != 0 && ppcRec_limitUpperAddr != 0)\n\t\t\tcemuLog_log(LogType::Force, \"PPCRec range limited to 0x{:08x}-0x{:08x}\", ppcRec_limitLowerAddr, ppcRec_limitUpperAddr);\n\n\t\tif(!extract_path.empty())\n\t\t{\n\t\t\tExtractorTool(extract_path, output_path, log_path);\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tstd::string errorMsg;\n\t\terrorMsg.append(\"Error while trying to parse command line parameter:\\n\");\n\t\terrorMsg.append(ex.what());\n\t\tstd::cout << errorMsg << std::endl;\n\t\treturn false;\n\t}\n\t\n}\n\nbool LaunchSettings::ExtractorTool(std::wstring_view wud_path, std::string_view output_path, std::wstring_view log_path)\n{\n\t// extracting requires path of file\n\tif (output_path.empty())\n\t{\n\t\trequireConsole();\n\t\tputs(\"Cannot extract files because no source path was specified (-p)\\n\");\n\t\treturn false;\n\t}\n\t// mount wud\n\tAES128_init();\n\tFSTVolume* srcVolume = FSTVolume::OpenFromDiscImage(fs::path(wud_path));\n\tif (!srcVolume)\n\t{\n\t\trequireConsole();\n\t\tputs(fmt::format(\"Unable to open \\\"%s\\\"\\n\", fs::path(wud_path).generic_string()).c_str());\n\t\treturn false;\n\t}\n\tbool fileFound = false;\n\tstd::vector<uint8> fileData = srcVolume->ExtractFile(output_path, &fileFound);\n\tdelete srcVolume;\n\tif (!fileFound)\n\t{\n\t\trequireConsole();\n\t\tputs(fmt::format(\"Unable to read file \\\"%s\\\"\\n\", output_path).c_str());\n\t\treturn false;\n\t}\n\t// output on console (if no output path was specified)\n\tif (!log_path.empty())\n\t{\n\t\ttry\n\t\t{\n\t\t\tfs::path filename(std::wstring{ log_path });\n\n\t\t\tfilename /= boost::nowide::widen(std::string(output_path));\n\t\t\t\n\t\t\tfs::path p = filename;\n\t\t\tp.remove_filename();\n\t\t\t\n\t\t\tfs::create_directories(p);\n\t\t\tstd::ofstream file(filename, std::ios::out | std::ios::binary);\n\t\t\tfile.write((const char*)fileData.data(), fileData.size());\n\t\t\tfile.flush();\n\t\t\tfile.close();\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"can't write file: {}\", ex.what());\n\t\t\tputs(fmt::format(\"can't write file: %s\\n\", ex.what()).c_str());\n\t\t}\n\t}\n\telse\n\t{\n\t\t// output to console\n\t\trequireConsole();\n\t\tprintf(\"%.*s\", (int)fileData.size(), fileData.data());\n\t\tfflush(stdout);\n\t}\n\t\n\treturn true;\n}\n"
  },
  {
    "path": "src/config/LaunchSettings.h",
    "content": "#pragma once\n\n#include <optional>\n#include <string>\n\nclass LaunchSettings\n{\npublic:\n\t// winmain\n\tstatic bool HandleCommandline(const wchar_t* lpCmdLine);\n\t// wmain\n\tstatic bool HandleCommandline(int argc, wchar_t* argv[]);\n\t// main (unix)\n\tstatic bool HandleCommandline(int argc, char* argv[]);\n\n\tstatic bool HandleCommandline(const std::vector<std::wstring>& args);\n\n\tstatic std::optional<fs::path> GetLoadFile() { return s_load_game_file; }\n    static std::optional<uint64> GetLoadTitleID() {return s_load_title_id;}\n\tstatic std::optional<fs::path> GetMLCPath() { return s_mlc_path; }\n\n\tstatic std::optional<bool> RenderUpsideDownEnabled() { return s_render_upside_down; }\n\tstatic std::optional<bool> FullscreenEnabled() { return s_fullscreen; }\n\n\tstatic bool Verbose() { return s_verbose; }\n\n\tstatic bool GDBStubEnabled() { return s_enable_gdbstub; }\n\tstatic bool NSightModeEnabled() { return s_nsight_mode; }\n\n\tstatic bool ForceInterpreter() { return s_force_interpreter; };\n\tstatic bool ForceMultiCoreInterpreter() { return s_force_multicore_interpreter; }\n\n\tstatic std::optional<uint32> GetPersistentId() { return s_persistent_id; }\n\n\tstatic uint32 GetPPCRecLowerAddr() { return ppcRec_limitLowerAddr; };\n\tstatic uint32 GetPPCRecUpperAddr() { return ppcRec_limitUpperAddr; };\n\nprivate:\n\tinline static std::optional<fs::path> s_load_game_file{};\n    inline static std::optional<uint64> s_load_title_id{};\n\tinline static std::optional<fs::path> s_mlc_path{};\n\n\tinline static std::optional<bool> s_render_upside_down{};\n\tinline static std::optional<bool> s_fullscreen{};\n\n\tinline static bool s_verbose = false;\n\t\n\tinline static bool s_enable_gdbstub = false;\n\tinline static bool s_nsight_mode = false;\n\n\tinline static bool s_force_interpreter = false;\n\tinline static bool s_force_multicore_interpreter = false;\n\t\n\tinline static std::optional<uint32> s_persistent_id{};\n\n\t// for recompiler debugging\n\tinline static uint32 ppcRec_limitLowerAddr{};\n\tinline static uint32 ppcRec_limitUpperAddr{};\n\n\tstatic bool ExtractorTool(std::wstring_view wud_path, std::string_view output_path, std::wstring_view log_path);\n};\n\n\n"
  },
  {
    "path": "src/config/NetworkSettings.cpp",
    "content": "#include \"NetworkSettings.h\"\n#include \"ActiveSettings.h\"\n#include \"LaunchSettings.h\"\n#include \"CemuConfig.h\"\n#include \"Common/FileStream.h\"\n\nXMLNetworkConfig_t n_config(L\"network_services.xml\");\n\n\nvoid NetworkConfig::LoadOnce() \n{\n\tn_config.SetFilename(ActiveSettings::GetConfigPath(\"network_services.xml\").generic_wstring());\n\tif (XMLExists())\n\t\tn_config.Load();\n}\n\nvoid NetworkConfig::Load(XMLConfigParser& parser) \n{\n\tauto config = parser.get(\"content\");\n\tnetworkname = config.get(\"networkname\", \"Custom\");\n\tdisablesslver = config.get(\"disablesslverification\", disablesslver);\n\tauto u = config.get(\"urls\");\n\turls.ACT = u.get(\"act\", NintendoURLs::ACTURL);\n\turls.ECS = u.get(\"ecs\", NintendoURLs::ECSURL);\n\turls.NUS = u.get(\"nus\", NintendoURLs::NUSURL);\n\turls.IAS = u.get(\"ias\", NintendoURLs::IASURL);\n\turls.CCSU = u.get(\"ccsu\", NintendoURLs::CCSUURL);\n\turls.CCS = u.get(\"ccs\", NintendoURLs::CCSURL);\n\turls.IDBE = u.get(\"idbe\", NintendoURLs::IDBEURL);\n\turls.BOSS = u.get(\"boss\", NintendoURLs::BOSSURL);\n\turls.TAGAYA = u.get(\"tagaya\", NintendoURLs::TAGAYAURL);\n\turls.OLV = u.get(\"olv\", NintendoURLs::OLVURL);\n}\n\nbool NetworkConfig::XMLExists() \n{\n\tstatic std::optional<bool> s_exists; // caches result of fs::exists\n\tif(s_exists.has_value())\n\t\treturn *s_exists;\n\tstd::error_code ec;\n\tif (!fs::exists(ActiveSettings::GetConfigPath(\"network_services.xml\"), ec))\n\t{\n\t\ts_exists = false;\n\t\treturn false;\n\t}\n\ts_exists = true;\n\treturn true;\n}"
  },
  {
    "path": "src/config/NetworkSettings.h",
    "content": "#pragma once\n\n#include \"ConfigValue.h\"\n#include \"XMLConfig.h\"\n\nenum class NetworkService\n{\n\tOffline,\n\tNintendo,\n\tPretendo,\n\tCustom,\n\tCOUNT = Custom\n};\n\nstruct NetworkConfig\n{\n    NetworkConfig()\n\t{\n\n\t};\n\n\tNetworkConfig(const NetworkConfig&) = delete;\n\n    ConfigValue<std::string> networkname;\n    ConfigValue<bool> disablesslver = false;\n    struct\n\t{\n\t\t ConfigValue<std::string> ACT;\n\t\t ConfigValue<std::string> ECS;\n\t\t ConfigValue<std::string> NUS;\n\t\t ConfigValue<std::string> IAS;\n\t\t ConfigValue<std::string> CCSU;\n\t\t ConfigValue<std::string> CCS;\n\t\t ConfigValue<std::string> IDBE;\n\t\t ConfigValue<std::string> BOSS;\n\t\t ConfigValue<std::string> TAGAYA;\n\t\t ConfigValue<std::string> OLV;\n\t}urls{};\n\n    public:\n    static void LoadOnce();\n    void Load(XMLConfigParser& parser);\n    void Save(XMLConfigParser& parser);\n    \n    static bool XMLExists();\n};\n\nstruct NintendoURLs {\n   inline static std::string ACTURL = \"https://account.nintendo.net\";\n   inline static std::string ECSURL = \"https://ecs.wup.shop.nintendo.net/ecs/services/ECommerceSOAP\";\n   inline static std::string NUSURL = \"https://nus.wup.shop.nintendo.net/nus/services/NetUpdateSOAP\";\n   inline static std::string IASURL = \"https://ias.wup.shop.nintendo.net/ias/services/IdentityAuthenticationSOAP\";\n   inline static std::string CCSUURL = \"https://ccs.wup.shop.nintendo.net/ccs/download\";\n   inline static std::string CCSURL = \"http://ccs.cdn.wup.shop.nintendo.net/ccs/download\";\n   inline static std::string IDBEURL = \"https://idbe-wup.cdn.nintendo.net/icondata\";\n   inline static std::string BOSSURL = \"https://npts.app.nintendo.net/p01/tasksheet\";\n   inline static std::string TAGAYAURL = \"https://tagaya.wup.shop.nintendo.net/tagaya/versionlist\";\n   inline static std::string OLVURL = \"https://discovery.olv.nintendo.net/v1/endpoint\";\n};\n\nstruct PretendoURLs {\n   inline static std::string ACTURL =  \"https://account.pretendo.cc\";\n   inline static std::string ECSURL = \"https://ecs.wup.shop.pretendo.cc/ecs/services/ECommerceSOAP\";\n   inline static std::string NUSURL = \"https://nus.c.shop.pretendo.cc/nus/services/NetUpdateSOAP\";\n   inline static std::string IASURL = \"https://ias.c.shop.pretendo.cc/ias/services/IdentityAuthenticationSOAP\";\n   inline static std::string CCSUURL = \"https://ccs.c.shop.pretendo.cc/ccs/download\";\n   inline static std::string CCSURL = \"http://ccs.cdn.c.shop.pretendo.cc/ccs/download\";\n   inline static std::string IDBEURL = \"https://idbe-wup.cdn.pretendo.cc/icondata\";\n   inline static std::string BOSSURL = \"https://npts.app.pretendo.cc/p01/tasksheet\";\n   inline static std::string TAGAYAURL = \"https://tagaya.wup.shop.pretendo.cc/tagaya/versionlist\";\n   inline static std::string OLVURL = \"https://discovery.olv.pretendo.cc/v1/endpoint\";\n};\n\ntypedef XMLDataConfig<NetworkConfig> XMLNetworkConfig_t;\nextern XMLNetworkConfig_t n_config;\ninline NetworkConfig& GetNetworkConfig() { return n_config.data();};\n\ninline bool IsNetworkServiceSSLDisabled(NetworkService service)\n{\n\tif(service == NetworkService::Nintendo)\n\t\treturn false;\n\telse if(service == NetworkService::Pretendo)\n\t\treturn true;\n\telse if(service == NetworkService::Custom)\n\t\treturn GetNetworkConfig().disablesslver.GetValue();\n\treturn false;\n}"
  },
  {
    "path": "src/config/XMLConfig.h",
    "content": "#pragma once\n\n#include \"util/tinyxml2/tinyxml2.h\"\n#include \"Common/FileStream.h\"\n#include \"config/ConfigValue.h\"\n\n#include <string>\n#include <mutex>\n\ntemplate <typename T>\nconcept HasConstCharConstructor = requires { T(std::declval<const char*>()); };\n\nclass XMLConfigParser\n{\npublic:\n\tXMLConfigParser(tinyxml2::XMLDocument* document)\n\t\t: m_document(document), m_current_element(nullptr), m_is_root(true) {}\n\nprivate:\n\tXMLConfigParser(tinyxml2::XMLDocument* document, tinyxml2::XMLElement* element)\n\t\t: m_document(document), m_current_element(element), m_is_root(false) {}\n\npublic:\n\ttemplate <typename T>\n\tauto get(const char* name, T default_value = {})\n\t{\n\t\tif constexpr(std::is_enum_v<T>)\n\t\t\treturn static_cast<T>(get(name, static_cast<std::underlying_type_t<T>>(default_value)));\n\n\t\tconst auto* element = m_current_element\n\t\t\t? m_current_element->FirstChildElement(name)\n\t\t\t: m_document->FirstChildElement(name);\n\t\t\n\t\tif (element == nullptr)\n\t\t\treturn default_value;\n\n\t\tif constexpr (std::is_same_v<T, bool>)\n\t\t\treturn element->BoolText(default_value);\n\t\telse if constexpr (std::is_same_v<T, float>)\n\t\t\treturn element->FloatText(default_value);\n\t\telse if constexpr (std::is_same_v<T, sint32>)\n\t\t\treturn element->IntText(default_value);\n\t\telse if constexpr (std::is_same_v<T, uint32>)\n\t\t\treturn element->UnsignedText(default_value);\n\t\telse if constexpr (std::is_same_v<T, sint64>)\n\t\t\treturn element->Int64Text(default_value);\n\t\telse if constexpr (std::is_same_v<T, uint64>) // doesnt support real uint64...\n\t\t\treturn (uint64)element->Int64Text((sint64)default_value);\n\t\telse if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, std::string> || HasConstCharConstructor<T>)\n\t\t{\n\t\t\tconst char* text = element->GetText();\n\t\t\treturn text ? text : default_value;\n\t\t}\n\t\t\n\t\treturn default_value;\n\t}\n\t\n\ttemplate <typename T>\n\tT get(const char* name, const ConfigValue<T>& default_value)\n\t{\n\t\treturn get(name, default_value.GetInitValue());\n\t}\n\t\n\ttemplate <typename T>\n\tT get(const char* name, const ConfigValueBounds<T>& default_value)\n\t{\n\t\treturn get(name, default_value.GetInitValue());\n\t}\n\n\ttemplate <typename T>\n\tauto get_attribute(const char* name, T default_value = {})\n\t{\n\t\tif constexpr (std::is_enum_v<T>)\n\t\t\treturn static_cast<T>(get_attribute(name, static_cast<std::underlying_type_t<T>>(default_value)));\n\n\t\tif (m_current_element == nullptr)\n\t\t\treturn default_value;\n\n\t\tif constexpr (std::is_same_v<T, bool>)\n\t\t\treturn m_current_element->BoolAttribute(name, default_value);\n\t\telse if constexpr (std::is_same_v<T, float>)\n\t\t\treturn m_current_element->FloatAttribute(name, default_value);\n\t\telse if constexpr (std::is_same_v<T, sint32>)\n\t\t\treturn m_current_element->IntAttribute(name, default_value);\n\t\telse if constexpr (std::is_same_v<T, uint32>)\n\t\t\treturn m_current_element->UnsignedAttribute(name, default_value);\n\t\telse if constexpr (std::is_same_v<T, sint64>)\n\t\t\treturn m_current_element->Int64Attribute(name, default_value);\n\t\telse if constexpr (std::is_same_v<T, uint64>) // doesnt support real uint64...\n\t\t\treturn (uint64)m_current_element->Int64Attribute(name, (sint64)default_value);\n\t\telse if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, std::string>)\n\t\t{\n\t\t\tconst char* text = m_current_element->Attribute(name);\n\t\t\treturn text ? text : default_value;\n\t\t}\n\n\t\treturn default_value;\n\t}\n\n\ttemplate <typename T>\n\tT get_attribute(const char* name, const ConfigValue<T>& default_value)\n\t{\n\t\treturn get_attribute(name, default_value.GetInitValue());\n\t}\n\n\ttemplate <typename T>\n\tT get_attribute(const char* name, const ConfigValueBounds<T>& default_value)\n\t{\n\t\treturn get_attribute(name, default_value.GetInitValue());\n\t}\n\n\tint char2int(char input)\n\t{\n\t  if(input >= '0' && input <= '9')\n\t    return input - '0';\n\t  if(input >= 'A' && input <= 'F')\n\t    return input - 'A' + 10;\n\t  if(input >= 'a' && input <= 'f')\n\t    return input - 'a' + 10;\n\t  throw std::invalid_argument(\"Invalid input string\");\n\t}\n\n\ttemplate <typename TType, size_t TSize>\n\tstd::array<TType, TSize>& get(const char* name, std::array<TType, TSize>& arr)\n\t{\n\t\tarr = {};\n\t\tconst auto element = m_current_element\n\t\t\t                     ? m_current_element->FirstChildElement(name)\n\t\t\t                     : m_document->FirstChildElement(name);\n\t\tif (element == nullptr)\n\t\t\treturn arr;\n\n\t\tconst char* text = element->GetText();\n\t\tif(text)\n\t\t{\n\t\t\tassert(strlen(text) == (arr.size() * 2));\n\t\t\tstd::istringstream iss(text);\n\t\t\tfor(int i = 0; i < arr.size(); ++i)\n\t\t\t{\n\t\t\t\tarr[i] = (char2int(text[i*2]) << 4) + char2int(text[i * 2 + 1]);\n\t\t\t}\n\t\t}\n\n\t\treturn arr;\n\t}\n\t\n\ttemplate <typename T>\n\tT value(T default_value = T())\n\t{\n\t\t//peterBreak();\n\t\treturn default_value;\n\t}\n\n\tbool value(bool default_value)\n\t{\n\t\treturn m_current_element ? m_current_element->BoolText(default_value) : default_value;\n\t}\n\n\tfloat value(float default_value)\n\t{\n\t\treturn m_current_element ? m_current_element->FloatText(default_value) : default_value;\n\t}\n\n\tdouble value(double default_value)\n\t{\n\t\treturn m_current_element ? m_current_element->DoubleText(default_value) : default_value;\n\t}\n\n\tuint32 value(uint32 default_value)\n\t{\n\t\treturn m_current_element ? m_current_element->UnsignedText(default_value) : default_value;\n\t}\n\n\tsint32 value(sint32 default_value)\n\t{\n\t\treturn m_current_element ? m_current_element->IntText(default_value) : default_value;\n\t}\n\n\tuint64 value(uint64 default_value)\n\t{\n\t\treturn m_current_element ? (uint64)m_current_element->Int64Text(default_value) : default_value;\n\t}\n\n\tsint64 value(sint64 default_value)\n\t{\n\t\treturn m_current_element ? m_current_element->Int64Text(default_value) : default_value;\n\t}\n\n\tconst char* value(const char* default_value)\n\t{\n\t\tif (m_current_element)\n\t\t{\n\t\t\tif (m_current_element->GetText())\n\t\t\t\treturn m_current_element->GetText();\n\t\t}\n\n\t\treturn default_value;\n\t}\n\n\ttemplate <typename TType, size_t TSize>\n\tvoid set(const char* name, const std::array<TType, TSize>& value)\n\t{\n\t\tauto element = m_document->NewElement(name);\n\n\t\tstd::stringstream str;\n\t\tfor(const auto& v : value)\n\t\t{\n\t\t\tstr << fmt::format(\"{:02x}\", v);\n\t\t}\n\n\t\telement->SetText(str.str().c_str());\n\n\t\tif (m_current_element)\n\t\t\tm_current_element->InsertEndChild(element);\n\t\telse\n\t\t\tm_document->InsertEndChild(element);\n\t}\n\n\ttemplate <typename T>\n\tvoid set(const char* name, T value)\n\t{\n\t\tauto* element = m_document->NewElement(name);\n\n\t\tif constexpr (std::is_enum_v<T>)\n\t\t\telement->SetText(fmt::format(\"{}\", static_cast<typename std::underlying_type<T>::type>(value)).c_str());\n\t\telse\n\t\t\telement->SetText(fmt::format(\"{}\", value).c_str());\n\n\t\tif (m_current_element)\n\t\t\tm_current_element->InsertEndChild(element);\n\t\telse\n\t\t\tm_document->InsertEndChild(element);\n\t}\n\n\ttemplate <typename T>\n\tvoid set(const char* name, const std::atomic<T>& value)\n\t{\n\t\tset(name, value.load());\n\t}\n\n\ttemplate <typename T>\n\tvoid set(const char* name, const ConfigValue<T>& value)\n\t{\n\t\tset(name, value.GetValue());\n\t}\n\n\tvoid set(const char* name, uint64 value)\n\t{\n\t\tset(name, (sint64)value);\n\t}\n\n\ttinyxml2::XMLElement* GetCurrentElement() const { return m_current_element; }\n\n\tXMLConfigParser get(const char* name) const\n\t{\n\t\tconst auto element = m_current_element\n\t\t\t                     ? m_current_element->FirstChildElement(name)\n\t\t\t                     : m_document->FirstChildElement(name);\n\t\treturn {m_document, element};\n\t}\n\n\tXMLConfigParser get(const char* name, const XMLConfigParser& parser)\n\t{\n\t\tconst auto element = parser.m_current_element\n\t\t\t? parser.m_current_element->NextSiblingElement(name)\n\t\t\t: parser.m_document->NextSiblingElement(name);\n\t\treturn { m_document, element };\n\t}\n\n\tXMLConfigParser set(const char* name) const\n\t{\n\t\tconst auto element = m_document->NewElement(name);\n\t\tif (m_current_element)\n\t\t\tm_current_element->InsertEndChild(element);\n\t\telse\n\t\t\tm_document->InsertEndChild(element);\n\n\t\treturn {m_document, element};\n\t}\n\n\ttemplate <typename T>\n\tXMLConfigParser& set_attribute(const char* name, const T& value)\n\t{\n\t\tcemu_assert_debug(m_current_element != nullptr);\n\t\tif (m_current_element)\n\t\t\tm_current_element->SetAttribute(name, value);\n\t\t\n\t\treturn *this;\n\t}\n\n\ttemplate <typename T>\n\tXMLConfigParser& set_attribute(const char* name, const ConfigValue<T>& value)\n\t{\n\t\treturn set_attribute(name, value.GetValue());\n\t}\n\n\ttemplate <typename T>\n\tXMLConfigParser& set_attribute(const char* name, const ConfigValueBounds<T>& value)\n\t{\n\t\treturn set_attribute(name, value.GetValue());\n\t}\n\t\n\tXMLConfigParser& set_attribute(const char* name, const std::string& value)\n\t{\n\t\treturn set_attribute(name, value.c_str());\n\t}\n\n\n\tbool valid() const\n\t{\n\t\tif (m_is_root)\n\t\t\treturn m_document != nullptr;\n\n\t\treturn m_document != nullptr && m_current_element != nullptr;\n\t}\n\nprivate:\n\ttinyxml2::XMLDocument* m_document;\n\ttinyxml2::XMLElement* m_current_element;\n\tbool m_is_root;\n};\n\nusing ChildXMLConfigParser = std::pair<std::function<void(XMLConfigParser&)>, std::function<void(XMLConfigParser&)>>;\n\ntemplate<typename T>\nconcept XMLConfigurable = requires(T t, XMLConfigParser& configParser) {\n\t{ t.Save(configParser) } -> std::same_as<XMLConfigParser>;\n\t{ t.Load(configParser) } -> std::same_as<XMLConfigParser>;\n};\n\ntemplate <XMLConfigurable T>\nclass XMLConfig\n{\npublic:\n\tXMLConfig() = delete;\n\n\tXMLConfig(T& instance)\n\t\t: m_instance(instance)\n\t{}\n\n\tXMLConfig(T& instance, std::wstring_view filename)\n\t\t: m_instance(instance), m_filename(filename) {}\n\n\tXMLConfig(const XMLConfig&) = delete;\n\n\tvirtual ~XMLConfig() = default;\n\n\tbool Load()\n\t{\n\t\tif (m_filename.empty())\n\t\t\treturn false;\n\n\t\treturn Load(m_filename);\n\t}\n\n\tbool Load(const std::wstring& filename)\n\t{\n\t\tFileStream* fs = FileStream::openFile(filename.c_str());\n\t\tif (!fs)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"XMLConfig::Load > failed \\\"{}\\\" with error {}\", boost::nowide::narrow(filename), errno);\n\t\t\treturn false;\n\t\t}\n\t\tstd::vector<uint8> xmlData;\n\t\txmlData.resize(fs->GetSize());\n\t\tfs->readData(xmlData.data(), xmlData.size());\n\t\tdelete fs;\n\n\t\ttinyxml2::XMLDocument doc;\t\t\n\t\tconst tinyxml2::XMLError error = doc.Parse((const char*)xmlData.data(), xmlData.size());\n\t\tconst bool success = error == tinyxml2::XML_SUCCESS;\n\t\tif (error != 0)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"XMLConfig::Load > LoadFile {}\", error);\n\t\t}\n\n\t\tif (!success)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tauto parser = XMLConfigParser(&doc);\n\t\tauto parentParser = m_instance.Load(parser);\n\n\t\tfor (auto [save, load] : m_childConfigParsers)\n\t\t\tload(parentParser);\n\n\t\treturn true;\n\t}\n\n\tbool Save()\n\t{\n\t\tif (m_filename.empty())\n\t\t\treturn false;\n\n\t\treturn Save(m_filename);\n\t}\n\n\tbool Save(const std::wstring& filename)\n\t{\n\t\tstd::wstring tmp_name = fmt::format(L\"{}_{}.tmp\", filename,rand() % 1000);\n\t\tstd::error_code err;\n\t\tfs::create_directories(fs::path(filename).parent_path(), err);\n\t\tif (err)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"can't create parent path for save file: {}\", err.message());\n\t\t\treturn false;\n\t\t}\n\n\t\tFILE* file = nullptr;\n#if BOOST_OS_WINDOWS\n        file = _wfopen(tmp_name.c_str(), L\"wb\");\n#else\n\t\tfile = fopen(boost::nowide::narrow(tmp_name).c_str(), \"wb\");\n#endif\n        if (!file)\n        {\n\t\t\tcemuLog_logDebug(LogType::Force, \"XMLConfig::Save > failed \\\"{}\\\" with error {}\", boost::nowide::narrow(filename), errno);\n            return false;\n        }\n\n\t\ttinyxml2::XMLDocument doc;\n\t\tconst auto declaration = doc.NewDeclaration();\n\t\tdoc.InsertFirstChild(declaration);\n\n\t\tauto parser = XMLConfigParser(&doc);\n\t\tauto parentParser = m_instance.Save(parser);\n\n\t\tfor (auto [save, load] : m_childConfigParsers)\n\t\t\tsave(parentParser);\n\n\t\tconst tinyxml2::XMLError error = doc.SaveFile(file);\n\t\tconst bool success = error == tinyxml2::XML_SUCCESS;\n\t\tif(error != 0)\n\t\t\tcemuLog_logDebug(LogType::Force, \"XMLConfig::Save > SaveFile {}\", error);\n\n\t\tfflush(file);\n\t\tfclose(file);\n\n\t\tfs::rename(tmp_name, filename, err);\n\t\tif(err)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Unable to save settings to file: {}\", err.message().c_str());\n\t\t\tfs::remove(tmp_name, err);\n\t\t}\n\n\t\treturn success;\n\t}\n\n\t[[nodiscard]] const std::wstring& GetFilename() const { return m_filename; }\n\tvoid SetFilename(const std::wstring& filename) { m_filename = filename; }\n\n\tstd::unique_lock<std::mutex> Lock() { return std::unique_lock(m_mutex); }\n\n\tvoid AddChildConfig(ChildXMLConfigParser childConfigParser)\n\t{\n\t\tm_childConfigParsers.push_back(childConfigParser);\n\t}\n\n  private:\n\tstd::vector<ChildXMLConfigParser> m_childConfigParsers;\n\tT& m_instance;\n\tstd::wstring m_filename;\n\tstd::mutex m_mutex;\n};\n\ntemplate<typename T>\nconcept XMLConfigProvider = requires(T t, ChildXMLConfigParser& configParser) {\n\t{ t().Save() } -> std::same_as<bool>;\n\t{ t().Load() } -> std::same_as<bool>;\n\t{ t().Lock() } -> std::same_as<std::unique_lock<std::mutex>>;\n\t{ t().AddChildConfig(configParser) } -> std::same_as<void>;\n};\n\ntemplate<typename T, void (T::*L)(XMLConfigParser&), void (T::*S)(XMLConfigParser&)>\nclass XMLChildConfig\n{\n  public:\n\tXMLChildConfig(XMLConfigProvider auto getParentConfig)\n\t{\n\t\tm_parentConfig = {\n\t\t\t.lock = [getParentConfig]() { return getParentConfig().Lock(); },\n\t\t\t.save = [getParentConfig]() { return getParentConfig().Save(); },\n\t\t\t.load = [getParentConfig]() { return getParentConfig().Load(); },\n\t\t};\n\n\t\tauto configParser = std::make_pair(\n\t\t\t[this](XMLConfigParser& parser) {\n\t\t\t\t(m_data.*S)(parser);\n\t\t\t},\n\t\t\t[this](XMLConfigParser& parser) {\n\t\t\t\t(m_data.*L)(parser);\n\t\t\t});\n\n\t\tgetParentConfig().AddChildConfig(configParser);\n\t}\n\n\tbool Save()\n\t{\n\t\treturn m_parentConfig.save();\n\t}\n\n\tbool Load()\n\t{\n\t\treturn m_parentConfig.load();\n\t}\n\n\tT& Data()\n\t{\n\t\treturn m_data;\n\t}\n\n\tstd::unique_lock<std::mutex> Lock()\n\t{\n\t\treturn m_parentConfig.lock();\n\t}\n\n\tvirtual ~XMLChildConfig() = default;\n\n  private:\n\tT m_data;\n\tstruct\n\t{\n\t\tstd::function<std::unique_lock<std::mutex>()> lock;\n\t\tstd::function<bool()> save;\n\t\tstd::function<bool()> load;\n\t} m_parentConfig;\n};\n\ntemplate<typename T>\nstruct XMLDataConfig {};\n\ntemplate <XMLConfigurable T>\nclass XMLDataConfig<T> : public XMLConfig<T>\n{\npublic:\n\tXMLDataConfig()\n\t\t: XMLConfig<T>::XMLConfig(m_data), m_data() {}\n\n\tXMLDataConfig(std::wstring_view filename)\n\t\t: XMLConfig<T>::XMLConfig(m_data, filename), m_data() {}\n\n\tXMLDataConfig(std::wstring_view filename, T init_data)\n\t\t: XMLConfig<T>::XMLConfig(m_data, filename), m_data(std::move(init_data)) {}\n\n\tXMLDataConfig(const XMLDataConfig& o) = delete;\n\n\tT& data() { return m_data; }\n\nprivate:\n\tT m_data;\n};\n\ntemplate<typename T>\nconcept XMLStandaloneConfigurable = requires(T t, XMLConfigParser& configParser) {\n\t{ t.Save(configParser) } -> std::same_as<void>;\n\t{ t.Load(configParser) } -> std::same_as<void>;\n};\n\ntemplate<XMLStandaloneConfigurable T>\nstruct XMLConfigWrapper\n{\n\tXMLConfigParser Save(XMLConfigParser& configParser)\n\t{\n\t\tdata.Save(configParser);\n\t\treturn configParser;\n\t}\n\n\tXMLConfigParser Load(XMLConfigParser& configParser)\n\t{\n\t\tdata.Load(configParser);\n\t\treturn configParser;\n\t}\n\n\tT data;\n};\n\ntemplate<XMLStandaloneConfigurable T>\nclass XMLDataConfig<T> : public XMLConfig<XMLConfigWrapper<T>>\n{\n  public:\n\tXMLDataConfig()\n\t\t: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper), m_configWrapper() {}\n\n\tXMLDataConfig(std::wstring_view filename)\n\t\t: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper, filename), m_configWrapper() {}\n\n\tXMLDataConfig(std::wstring_view filename, T init_data)\n\t\t: XMLConfig<XMLConfigWrapper<T>>::XMLConfig(m_configWrapper, filename), m_configWrapper{.data = std::move(init_data)} {}\n\n\tXMLDataConfig(const XMLDataConfig& o) = delete;\n\n\tT& data()\n\t{\n\t\treturn m_configWrapper.data;\n\t}\n\n  private:\n\tXMLConfigWrapper<T> m_configWrapper;\n};\n"
  },
  {
    "path": "src/gui/CMakeLists.txt",
    "content": "add_library(CemuGui INTERFACE)\ntarget_include_directories(CemuGui INTERFACE \"interface\")\n\nif(ENABLE_WXWIDGETS)\n    add_subdirectory(wxgui)\n    target_link_libraries(CemuGui INTERFACE CemuWxGui)\nendif()\n"
  },
  {
    "path": "src/gui/interface/WindowSystem.h",
    "content": "#pragma once\n\n#include \"config/CemuConfig.h\"\n#include \"input/api/ControllerState.h\"\n\nnamespace WindowSystem\n{\n\tstruct WindowHandleInfo\n\t{\n\t\tenum class Backend\n\t\t{\n\t\t\tX11,\n\t\t\tWayland,\n\t\t\tCocoa,\n\t\t\tWindows,\n\t\t} backend;\n\t\tvoid* display = nullptr;\n\t\tvoid* surface = nullptr;\n\t};\n\n\tenum struct PlatformKeyCodes : uint32\n\t{\n\t\tLCONTROL,\n\t\tRCONTROL,\n\t\tTAB,\n\t\tESCAPE,\n\t};\n\n\tstruct WindowInfo\n\t{\n\t\tstd::atomic_bool app_active; // our app is active/has focus\n\n\t\tstd::atomic_int32_t width, height;\t\t\t // client size of main window\n\t\tstd::atomic_int32_t phys_width, phys_height; // client size of main window in physical pixels\n\t\tstd::atomic<double> dpi_scale;\n\n\t\tstd::atomic_bool pad_open;\t\t\t\t\t\t\t // if separate pad view is open\n\t\tstd::atomic_int32_t pad_width, pad_height;\t\t\t // client size of pad window\n\t\tstd::atomic_int32_t phys_pad_width, phys_pad_height; // client size of pad window in physical pixels\n\t\tstd::atomic<double> pad_dpi_scale;\n\n\t\tstd::atomic_bool pad_maximized = false;\n\t\tstd::atomic_int32_t restored_pad_x = -1, restored_pad_y = -1;\n\t\tstd::atomic_int32_t restored_pad_width = -1, restored_pad_height = -1;\n\n\t\tstd::atomic_bool is_fullscreen;\n\t\tstd::atomic_bool debugger_focused;\n\n\t\tvoid set_keystate(uint32 keycode, bool state)\n\t\t{\n\t\t\tconst std::lock_guard<std::mutex> lock(keycode_mutex);\n\t\t\tm_keydown[keycode] = state;\n\t\t}\n\n\t\tbool get_keystate(uint32 keycode)\n\t\t{\n\t\t\tconst std::lock_guard<std::mutex> lock(keycode_mutex);\n\t\t\tauto result = m_keydown.find(keycode);\n\t\t\tif (result == m_keydown.end())\n\t\t\t\treturn false;\n\t\t\treturn result->second;\n\t\t}\n\n\t\tvoid set_keystatesup()\n\t\t{\n\t\t\tconst std::lock_guard<std::mutex> lock(keycode_mutex);\n\t\t\tstd::for_each(m_keydown.begin(), m_keydown.end(), [](std::pair<const uint32, bool>& el) { el.second = false; });\n\t\t}\n\n\t\ttemplate<typename fn>\n\t\tvoid iter_keystates(fn f)\n\t\t{\n\t\t\tconst std::lock_guard<std::mutex> lock(keycode_mutex);\n\t\t\tstd::for_each(m_keydown.cbegin(), m_keydown.cend(), f);\n\t\t}\n\n\t\tWindowHandleInfo window_main;\n\t\tWindowHandleInfo window_pad;\n\n\t\t// canvas\n\t\tWindowHandleInfo canvas_main;\n\t\tWindowHandleInfo canvas_pad;\n\n\t  private:\n\t\tstd::mutex keycode_mutex;\n\t\tstd::unordered_map<uint32, bool> m_keydown;\n\t};\n\n\tenum class ErrorCategory\n\t{\n\t\tKEYS_TXT_CREATION = 0,\n\t\tGRAPHIC_PACKS = 1,\n\t};\n\n\tvoid ShowErrorDialog(std::string_view message, std::string_view title, std::optional<ErrorCategory> errorCategory = {});\n\tinline void ShowErrorDialog(std::string_view message, std::optional<ErrorCategory> errorCategory = {})\n\t{\n\t\tShowErrorDialog(message, \"\", errorCategory);\n\t}\n\n\tvoid Create();\n\n\tWindowInfo& GetWindowInfo();\n\n\tvoid UpdateWindowTitles(bool isIdle, bool isLoading, double fps);\n\tvoid GetWindowSize(int& w, int& h);\n\tvoid GetPadWindowSize(int& w, int& h);\n\tvoid GetWindowPhysSize(int& w, int& h);\n\tvoid GetPadWindowPhysSize(int& w, int& h);\n\tdouble GetWindowDPIScale();\n\tdouble GetPadDPIScale();\n\tbool IsPadWindowOpen();\n\tbool IsKeyDown(uint32 key);\n\tbool IsKeyDown(PlatformKeyCodes key);\n\tstd::string GetKeyCodeName(uint32 key);\n\n\tbool InputConfigWindowHasFocus();\n\n\tvoid NotifyGameLoaded();\n\tvoid NotifyGameExited();\n\n\tvoid RefreshGameList();\n\n\tbool IsFullScreen();\n\n\tvoid CaptureInput(const ControllerState& currentState, const ControllerState& lastState);\n}; // namespace WindowSystem\n"
  },
  {
    "path": "src/gui/wxgui/AudioDebuggerWindow.cpp",
    "content": "#include \"wxgui.h\"\n#include \"AudioDebuggerWindow.h\"\n\n#include \"Cafe/OS/libs/snd_core/ax.h\"\n#include \"Cafe/OS/libs/snd_core/ax_internal.h\"\n\nenum\n{\n\t// options\n\tREFRESH_ID,\n\tCLOSE_ID,\n\tVOICELIST_ID,\n\tREFRESH_TIMER_ID,\n};\n\nwxBEGIN_EVENT_TABLE(AudioDebuggerWindow, wxFrame)\nEVT_BUTTON(CLOSE_ID, AudioDebuggerWindow::OnCloseButton)\nEVT_BUTTON(REFRESH_ID, AudioDebuggerWindow::OnRefreshButton)\nEVT_TIMER(REFRESH_TIMER_ID, AudioDebuggerWindow::OnRefreshTimer)\n\nEVT_CLOSE(AudioDebuggerWindow::OnClose)\nwxEND_EVENT_TABLE()\n\nAudioDebuggerWindow::AudioDebuggerWindow(wxFrame& parent)\n\t: wxFrame(&parent, wxID_ANY, _(\"AX voice viewer\"), wxDefaultPosition, wxSize(1126, 580), wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER)\n{\n\twxPanel* mainPane = new wxPanel(this);\n\twxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);\n\t\n\tvoiceListbox = new wxListCtrl(mainPane, VOICELIST_ID, wxPoint(0, 0), wxSize(1126, 570), wxLC_REPORT);\n\tvoiceListbox->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, \"Courier New\"));\n\t// add columns\n\twxListItem col0;\n\tcol0.SetId(0);\n\tcol0.SetText(\"idx\");\n\tcol0.SetWidth(40);\n\tvoiceListbox->InsertColumn(0, col0);\n\twxListItem col1;\n\tcol1.SetId(1);\n\tcol1.SetText(\"state\");\n\tcol1.SetWidth(48);\n\tvoiceListbox->InsertColumn(1, col1);\n\t//wxListItem col2;\n\t// format\n\tcol1.SetId(2);\n\tcol1.SetText(\"fmt\");\n\tcol1.SetWidth(52);\n\tvoiceListbox->InsertColumn(2, col1);\n\t// sample base addr\n\tcol1.SetId(3);\n\tcol1.SetText(\"base\");\n\tcol1.SetWidth(70);\n\tvoiceListbox->InsertColumn(3, col1);\n\t// current offset\n\tcol1.SetId(4);\n\tcol1.SetText(\"current\");\n\tcol1.SetWidth(70);\n\tvoiceListbox->InsertColumn(4, col1);\n\t// loop offset\n\tcol1.SetId(5);\n\tcol1.SetText(\"loop\");\n\tcol1.SetWidth(70);\n\tvoiceListbox->InsertColumn(5, col1);\n\t// end offset\n\tcol1.SetId(6);\n\tcol1.SetText(\"end\");\n\tcol1.SetWidth(70);\n\tvoiceListbox->InsertColumn(6, col1);\n\t// volume\n\tcol1.SetId(7);\n\tcol1.SetText(\"vol\");\n\tcol1.SetWidth(46);\n\tvoiceListbox->InsertColumn(7, col1);\n\t// volume delta\n\tcol1.SetId(8);\n\tcol1.SetText(\"volD\");\n\tcol1.SetWidth(46);\n\tvoiceListbox->InsertColumn(8, col1);\n\t// src\n\tcol1.SetId(9);\n\tcol1.SetText(\"src\");\n\tcol1.SetWidth(70);\n\tvoiceListbox->InsertColumn(9, col1);\n\t// low-pass filter coef a0\n\tcol1.SetId(10);\n\tcol1.SetText(\"lpa0\");\n\tcol1.SetWidth(46);\n\tvoiceListbox->InsertColumn(10, col1);\n\t// low-pass filter coef b0\n\tcol1.SetId(11);\n\tcol1.SetText(\"lpb0\");\n\tcol1.SetWidth(46);\n\tvoiceListbox->InsertColumn(11, col1);\n\t// biquad filter coef b0\n\tcol1.SetId(12);\n\tcol1.SetText(\"bqb0\");\n\tcol1.SetWidth(46);\n\tvoiceListbox->InsertColumn(12, col1);\n\t// biquad filter coef b0\n\tcol1.SetId(13);\n\tcol1.SetText(\"bqb1\");\n\tcol1.SetWidth(46);\n\tvoiceListbox->InsertColumn(13, col1);\n\t// biquad filter coef b0\n\tcol1.SetId(14);\n\tcol1.SetText(\"bqb2\");\n\tcol1.SetWidth(46);\n\tvoiceListbox->InsertColumn(14, col1);\n\t// biquad filter coef a0\n\tcol1.SetId(15);\n\tcol1.SetText(\"bqa1\");\n\tcol1.SetWidth(46);\n\tvoiceListbox->InsertColumn(15, col1);\n\t// biquad filter coef a1\n\tcol1.SetId(16);\n\tcol1.SetText(\"bqa2\");\n\tcol1.SetWidth(46);\n\tvoiceListbox->InsertColumn(16, col1);\n\t// device mix\n\tcol1.SetId(17);\n\tcol1.SetText(\"deviceMix\");\n\tcol1.SetWidth(186);\n\tvoiceListbox->InsertColumn(17, col1);\n\n\tsizer->Add(voiceListbox, 1, wxEXPAND | wxBOTTOM, 0);\n\n\tvoiceListbox->Bind(wxEVT_RIGHT_DOWN, &AudioDebuggerWindow::OnVoiceListRightClick, this);\n\n\tmainPane->SetSizer(sizer);\n\n\t// add empty entries\n\tfor (sint32 i = 0; i < snd_core::AX_MAX_VOICES; i++)\n\t{\n\t\twxListItem item;\n\t\titem.SetId(i);\n\t\titem.SetText(wxString::Format(\"%d\", snd_core::AX_MAX_VOICES-i-1));\n\t\tvoiceListbox->InsertItem(item);\n\t}\n\tRefreshVoiceList();\n\n\t// start refresh timer\n\tstatic const int INTERVAL = 100; // milliseconds\n\trefreshTimer = new wxTimer(this, REFRESH_TIMER_ID);\n\trefreshTimer->Start(INTERVAL);\n}\n\nvoid AudioDebuggerWindow::OnRefreshTimer(wxTimerEvent& event)\n{\n\tRefreshVoiceList();\n}\n\nvoid AudioDebuggerWindow::OnCloseButton(wxCommandEvent& event)\n{\n\tClose();\n}\n\nvoid AudioDebuggerWindow::OnRefreshButton(wxCommandEvent& event)\n{\n\tRefreshVoiceList();\n}\n\nvoid AudioDebuggerWindow::OnClose(wxCloseEvent& event)\n{\n\tClose();\n}\n\n#define _r(__idx) _swapEndianU32(threadItrBE->context.gpr[__idx])\n\nvoid AudioDebuggerWindow::RefreshVoiceList_sndgeneric()\n{\n\tif (snd_core::__AXVPBInternalVoiceArray == nullptr || snd_core::__AXVPBArrayPtr == nullptr)\n\t\treturn;\n\n\tsnd_core::AXVPB tempVoiceArray[snd_core::AX_MAX_VOICES];\n\tmemcpy(tempVoiceArray, snd_core::__AXVPBArrayPtr, sizeof(snd_core::AXVPB)*snd_core::AX_MAX_VOICES);\n\n\tvoiceListbox->Freeze();\n\n\tfor (sint32 i = 0; i < snd_core::AX_MAX_VOICES; i++)\n\t{\n\t\tsint32 voiceIndex = snd_core::AX_MAX_VOICES - 1 - i;\n\t\tsnd_core::AXVPBInternal_t* internal = snd_core::__AXVPBInternalVoiceArray + voiceIndex;\n\t\t// index\n\t\tvoiceListbox->SetItem(i, 0, wxString::Format(\"%d\", (sint32)tempVoiceArray[voiceIndex].index));\n\t\t// state\n\t\tuint16 playbackState = _swapEndianU16(internal->playbackState);\n\t\tvoiceListbox->SetItem(i, 1, playbackState ? \"on\" : \"off\");\n\t\t// if voice index is invalid then stop updating here to prevent crashes\n\t\tif (voiceIndex < 0 || playbackState == 0)\n\t\t{\n\t\t\tvoiceListbox->SetItem(i, 0, \"\");\n\t\t\tvoiceListbox->SetItem(i, 1, \"\");\n\t\t\tvoiceListbox->SetItem(i, 2, \"\");\n\t\t\tvoiceListbox->SetItem(i, 3, \"\");\n\t\t\tvoiceListbox->SetItem(i, 4, \"\");\n\t\t\tvoiceListbox->SetItem(i, 5, \"\");\n\t\t\tvoiceListbox->SetItem(i, 6, \"\");\n\t\t\tvoiceListbox->SetItem(i, 7, \"\");\n\t\t\tvoiceListbox->SetItem(i, 8, \"\");\n\t\t\tvoiceListbox->SetItem(i, 9, \"\");\n\t\t\tvoiceListbox->SetItem(i, 10, \"\");\n\t\t\tvoiceListbox->SetItem(i, 11, \"\");\n\t\t\tvoiceListbox->SetItem(i, 12, \"\");\n\t\t\tvoiceListbox->SetItem(i, 13, \"\");\n\t\t\tvoiceListbox->SetItem(i, 14, \"\");\n\t\t\tvoiceListbox->SetItem(i, 15, \"\");\n\t\t\tvoiceListbox->SetItem(i, 16, \"\");\n\t\t\tvoiceListbox->SetItem(i, 17, \"\");\n\t\t\tcontinue;\n\t\t}\n\t\t// format\n\t\twxString formatLabel;\n\t\tif (tempVoiceArray[voiceIndex].offsets.format == _swapEndianU16(snd_core::AX_FORMAT_ADPCM))\n\t\t\tformatLabel = \"adpcm\";\n\t\telse if (tempVoiceArray[voiceIndex].offsets.format == _swapEndianU16(snd_core::AX_FORMAT_PCM16))\n\t\t\tformatLabel = \"pcm16\";\n\t\telse if (tempVoiceArray[voiceIndex].offsets.format == _swapEndianU16(snd_core::AX_FORMAT_PCM8))\n\t\t\tformatLabel = \"pcm8\";\n\t\telse\n\t\t\tformatLabel = \"ukn\";\n\t\tvoiceListbox->SetItem(i, 2, formatLabel);\n\t\t// update offsets\n\t\tsnd_core::AXPBOFFSET_t tempOffsets;\n\t\tsnd_core::AXGetVoiceOffsets(tempVoiceArray + voiceIndex, &tempOffsets);\n\t\t// sample base\n\t\tvoiceListbox->SetItem(i, 3, wxString::Format(\"%08x\", _swapEndianU32(tempOffsets.samples)));\n\t\t// current offset\n\t\tvoiceListbox->SetItem(i, 4, wxString::Format(\"%08x\", _swapEndianU32(tempOffsets.currentOffset)));\n\t\t// loop offset\n\t\tvoiceListbox->SetItem(i, 5, tempOffsets.loopFlag ? wxString::Format(\"%08x\", _swapEndianU32(tempOffsets.loopOffset)) : \"\");\n\t\t// end offset\n\t\tvoiceListbox->SetItem(i, 6, wxString::Format(\"%08x\", _swapEndianU32(tempOffsets.endOffset)));\n\t\t// volume\n\t\tvoiceListbox->SetItem(i, 7, wxString::Format(\"%04x\", (uint16)internal->veVolume));\n\t\t// volume delta\n\t\tvoiceListbox->SetItem(i, 8, wxString::Format(\"%04x\", (uint16)internal->veDelta));\n\t\t// src\n\t\tvoiceListbox->SetItem(i, 9, wxString::Format(\"%04x%04x\", _swapEndianU16(internal->src.ratioHigh), _swapEndianU16(internal->src.ratioLow)));\n\t\t// lpf\n\t\tif (internal->lpf.on)\n\t\t{\n\t\t\tvoiceListbox->SetItem(i, 10, wxString::Format(\"%04x\", _swapEndianU16(internal->lpf.a0)));\n\t\t\tvoiceListbox->SetItem(i, 11, wxString::Format(\"%04x\", _swapEndianU16(internal->lpf.b0)));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvoiceListbox->SetItem(i, 10, \"\");\n\t\t\tvoiceListbox->SetItem(i, 11, \"\");\n\t\t}\n\t\t// biquad\n\t\tif (internal->biquad.on)\n\t\t{\n\t\t\tvoiceListbox->SetItem(i, 12, wxString::Format(\"%04x\", _swapEndianU16(internal->biquad.b0)));\n\t\t\tvoiceListbox->SetItem(i, 13, wxString::Format(\"%04x\", _swapEndianU16(internal->biquad.b1)));\n\t\t\tvoiceListbox->SetItem(i, 14, wxString::Format(\"%04x\", _swapEndianU16(internal->biquad.b2)));\n\t\t\tvoiceListbox->SetItem(i, 15, wxString::Format(\"%04x\", _swapEndianU16(internal->biquad.a1)));\n\t\t\tvoiceListbox->SetItem(i, 16, wxString::Format(\"%04x\", _swapEndianU16(internal->biquad.a2)));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvoiceListbox->SetItem(i, 12, \"\");\n\t\t\tvoiceListbox->SetItem(i, 13, \"\");\n\t\t\tvoiceListbox->SetItem(i, 14, \"\");\n\t\t\tvoiceListbox->SetItem(i, 15, \"\");\n\t\t\tvoiceListbox->SetItem(i, 16, \"\");\n\t\t}\n\t\twxString label;\n\t\t// device mix\n\t\tfor (uint32 f = 0; f < snd_core::AX_TV_CHANNEL_COUNT*snd_core::AX_MAX_NUM_BUS; f++)\n\t\t{\n\t\t\tsint32 busIndex = f% snd_core::AX_MAX_NUM_BUS;\n\t\t\tsint32 channelIndex = f / snd_core::AX_MAX_NUM_BUS;\n\n\t\t\t//debug_printf(\"DeviceMix TV Voice %08x b%02d/c%02d vol %04x delta %04x\\n\", hCPU->gpr[3], busIndex, channelIndex, _swapEndianU16(mixArrayBE[f].vol), _swapEndianU16(mixArrayBE[f].volDelta));\n\t\t\tuint32 mixVol = internal->deviceMixTV[channelIndex * 4 + busIndex].vol;\n\t\t\tmixVol = (mixVol + 0x0FFF) >> (12);\n\t\t\tlabel += wxString::Format(\"%x\", mixVol);\n\t\t\t//ax.voiceInternal[voiceIndex].deviceMixTVChannel[channelIndex].bus[busIndex].vol = _swapEndianU16(mixArrayBE[f].vol);\n\t\t}\n\t\tvoiceListbox->SetItem(i, 17, label);\n\t}\n\tvoiceListbox->Thaw();\n}\n\nvoid AudioDebuggerWindow::RefreshVoiceList()\n{\n\tRefreshVoiceList_sndgeneric();\n}\n\nvoid AudioDebuggerWindow::OnVoiceListPopupClick(wxCommandEvent &evt)\n{\n\n}\n\nvoid AudioDebuggerWindow::OnVoiceListRightClick(wxMouseEvent& event)\n{\n\n}\n\nvoid AudioDebuggerWindow::Close()\n{\n\t// this->MakeModal(false);\n\trefreshTimer->Stop();\n\tthis->Destroy();\n}\n"
  },
  {
    "path": "src/gui/wxgui/AudioDebuggerWindow.h",
    "content": "#pragma once\n\n#include <wx/wx.h>\n\nclass wxListCtrl;\n\nclass AudioDebuggerWindow : public wxFrame\n{\npublic:\n\tAudioDebuggerWindow(wxFrame& parent);\n\n\tvoid OnCloseButton(wxCommandEvent& event);\n\tvoid OnRefreshButton(wxCommandEvent& event);\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid RefreshVoiceList_sndgeneric();\n\tvoid RefreshVoiceList();\n\tvoid OnRefreshTimer(wxTimerEvent& event);\n\tvoid OnVoiceListPopupClick(wxCommandEvent &evt);\n\tvoid OnVoiceListRightClick(wxMouseEvent& event);\n\t\n\tvoid Close();\n\nprivate:\n\twxListCtrl* voiceListbox;\n\twxTimer* refreshTimer;\n\n\twxDECLARE_EVENT_TABLE();\n\n\n};\n"
  },
  {
    "path": "src/gui/wxgui/CMakeLists.txt",
    "content": "add_library(CemuWxGui STATIC\n  canvas/IRenderCanvas.h\n  canvas/OpenGLCanvas.cpp\n  canvas/OpenGLCanvas.h\n  canvas/VulkanCanvas.cpp\n  canvas/VulkanCanvas.h\n  CemuApp.cpp\n  CemuApp.h\n  CemuUpdateWindow.cpp\n  CemuUpdateWindow.h\n  ChecksumTool.cpp\n  ChecksumTool.h\n  components/TextList.cpp\n  components/TextList.h\n  components/wxDownloadManagerList.cpp\n  components/wxDownloadManagerList.h\n  components/wxGameList.cpp\n  components/wxGameList.h\n  components/wxInputDraw.cpp\n  components/wxInputDraw.h\n  components/wxLogCtrl.cpp\n  components/wxLogCtrl.h\n  components/wxTitleManagerList.cpp\n  components/wxTitleManagerList.h\n  debugger/BreakpointWindow.cpp\n  debugger/BreakpointWindow.h\n  debugger/DebuggerWindow2.cpp\n  debugger/DebuggerWindow2.h\n  debugger/DisasmCtrl.cpp\n  debugger/DisasmCtrl.h\n  debugger/DumpCtrl.cpp\n  debugger/DumpCtrl.h\n  debugger/DumpWindow.cpp\n  debugger/DumpWindow.h\n  debugger/ModuleWindow.cpp\n  debugger/ModuleWindow.h\n  debugger/RegisterWindow.cpp\n  debugger/RegisterWindow.h\n  debugger/SymbolCtrl.cpp\n  debugger/SymbolCtrl.h\n  debugger/SymbolWindow.cpp\n  debugger/SymbolWindow.h\n  dialogs/CreateAccount/wxCreateAccountDialog.cpp\n  dialogs/CreateAccount/wxCreateAccountDialog.h\n  dialogs/SaveImport/SaveImportWindow.cpp\n  dialogs/SaveImport/SaveImportWindow.h\n  dialogs/SaveImport/SaveTransfer.cpp\n  dialogs/SaveImport/SaveTransfer.h\n  AudioDebuggerWindow.cpp\n  AudioDebuggerWindow.h\n  DownloadGraphicPacksWindow.cpp\n  DownloadGraphicPacksWindow.h\n  GameProfileWindow.cpp\n  GameProfileWindow.h\n  GameUpdateWindow.cpp\n  GameUpdateWindow.h\n  GeneralSettings2.cpp\n  GeneralSettings2.h\n  GettingStartedDialog.cpp\n  GettingStartedDialog.h\n  GraphicPacksWindow2.cpp\n  GraphicPacksWindow2.h\n  wxWindowSystem.cpp\n  helpers/wxControlObject.h\n  helpers/wxCustomData.h\n  helpers/wxCustomEvents.cpp\n  helpers/wxCustomEvents.h\n  helpers/wxHelpers.cpp\n  helpers/wxHelpers.h\n  helpers/wxLogEvent.h\n  helpers/wxWayland.cpp\n  helpers/wxWayland.h\n  input/HotkeySettings.cpp\n  input/HotkeySettings.h\n  input/InputAPIAddWindow.cpp\n  input/InputAPIAddWindow.h\n  input/InputSettings2.cpp\n  input/InputSettings2.h\n  input/panels/ClassicControllerInputPanel.cpp\n  input/panels/ClassicControllerInputPanel.h\n  input/panels/InputPanel.cpp\n  input/panels/InputPanel.h\n  input/panels/ProControllerInputPanel.cpp\n  input/panels/ProControllerInputPanel.h\n  input/panels/VPADInputPanel.cpp\n  input/panels/VPADInputPanel.h\n  input/panels/WiimoteInputPanel.cpp\n  input/panels/WiimoteInputPanel.h\n  input/settings/DefaultControllerSettings.cpp\n  input/settings/DefaultControllerSettings.h\n  input/settings/WiimoteControllerSettings.cpp\n  input/settings/WiimoteControllerSettings.h\n  LoggingWindow.cpp\n  LoggingWindow.h\n  MainWindow.cpp\n  MainWindow.h\n  MemorySearcherTool.cpp\n  MemorySearcherTool.h\n  PadViewFrame.cpp\n  PadViewFrame.h\n  TitleManager.cpp\n  TitleManager.h\n  wxCemuConfig.cpp\n  wxCemuConfig.h\n  EmulatedUSBDevices/EmulatedUSBDeviceFrame.cpp\n  EmulatedUSBDevices/EmulatedUSBDeviceFrame.h\n  windows/PPCThreadsViewer\n  windows/PPCThreadsViewer/DebugPPCThreadsWindow.cpp\n  windows/PPCThreadsViewer/DebugPPCThreadsWindow.h\n  windows/TextureRelationViewer\n  windows/TextureRelationViewer/TextureRelationWindow.cpp\n  windows/TextureRelationViewer/TextureRelationWindow.h\n  wxcomponents/checktree.cpp\n  wxcomponents/checktree.h\n  wxgui.h\n  wxHelper.h\n)\n\nif (ENABLE_METAL)\n  target_sources(CemuWxGui PRIVATE\n    canvas/MetalCanvas.cpp\n    canvas/MetalCanvas.h\n  )\nendif()\n\nif (ENABLE_BLUEZ)\n  target_sources(CemuWxGui PRIVATE\n    input/PairingDialog.cpp\n    input/PairingDialog.h\n  )\nendif()\n\nset_property(TARGET CemuWxGui PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\n\ntarget_include_directories(CemuWxGui PUBLIC \"../\")\n# PUBLIC because rapidjson/document.h is included in ChecksumTool.h\ntarget_include_directories(CemuWxGui PUBLIC ${RAPIDJSON_INCLUDE_DIRS})\n\ntarget_link_libraries(CemuWxGui PRIVATE\n  CemuCommon\n  CemuResource\n  libzip::zip\n  ZArchive::zarchive\n  CemuComponents\n  SDL2::SDL2\n  pugixml::pugixml\n  CemuCafe\n  PUBLIC\n  CURL::libcurl\n)\n\nif(ENABLE_WXWIDGETS AND UNIX AND NOT APPLE)\n\t# PUBLIC because gdk/gdkkeysyms.h is included in guiWrapper.h\n\ttarget_link_libraries(CemuWxGui PUBLIC GTK3::gtk)\n  if (ENABLE_WAYLAND)\n    target_link_libraries(CemuWxGui PRIVATE Wayland::Client CemuWaylandProtocols)\n  endif()\nendif()\n\nif(ENABLE_CUBEB)\n\ttarget_link_libraries(CemuWxGui PRIVATE cubeb::cubeb)\nendif()\n\nif(UNIX AND NOT APPLE)\n\tif(ENABLE_FERAL_GAMEMODE)\n\t\ttarget_link_libraries(CemuWxGui PRIVATE gamemode)\n\tendif()\nendif()\nif (ENABLE_WXWIDGETS)\n\t# PUBLIC because wx/app.h is included in CemuApp.h\n\ttarget_link_libraries(CemuWxGui PUBLIC wxWidgets::wxWidgets)\nendif()\n\nif(WIN32)\n\ttarget_link_libraries(CemuWxGui PRIVATE bthprops)\nendif()\n\nif(ALLOW_PORTABLE)\n\ttarget_compile_definitions(CemuWxGui PRIVATE CEMU_ALLOW_PORTABLE)\nendif ()\n"
  },
  {
    "path": "src/gui/wxgui/CemuApp.cpp",
    "content": "#include \"wxgui/CemuApp.h\"\n#include \"wxCemuConfig.h\"\n#include \"wxgui/MainWindow.h\"\n#include \"wxgui/wxgui.h\"\n#include \"config/CemuConfig.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Core/LatteOverlay.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/LaunchSettings.h\"\n#include \"wxgui/GettingStartedDialog.h\"\n#include \"input/InputManager.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"wxgui/input/HotkeySettings.h\"\n#include \"wxgui/debugger/DebuggerWindow2.h\"\n#include <wx/language.h>\n\n#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND\n#include \"wxgui/helpers/wxWayland.h\"\n#endif\n#if __WXGTK__\n#include <glib.h>\n#endif\n\n#include <wx/image.h>\n#include <wx/filename.h>\n#include <wx/stdpaths.h>\n#include <wx/clipbrd.h>\n#include \"wxHelper.h\"\n\n#include \"Cafe/TitleList/TitleList.h\"\n#include \"Cafe/TitleList/SaveList.h\"\n\nwxIMPLEMENT_APP_NO_MAIN(CemuApp);\n\n// defined in wxWindowSystem.cpp\nextern WindowSystem::WindowInfo g_window_info;\nextern std::shared_mutex g_mutex;\n\n// forward declarations from main.cpp\nvoid UnitTests();\nvoid CemuCommonInit();\n\nvoid HandlePostUpdate();\n// Translation strings to extract for gettext:\nvoid unused_translation_dummy()\n{\n\tvoid(_(\"Browse\"));\n\tvoid(_(\"Select a file\"));\n\tvoid(_(\"Select a directory\"));\n\n\tvoid(_(\"Japanese\"));\n\tvoid(_(\"English\"));\n\tvoid(_(\"French\"));\n\tvoid(_(\"German\"));\n\tvoid(_(\"Italian\"));\n\tvoid(_(\"Spanish\"));\n\tvoid(_(\"Chinese\"));\n\tvoid(_(\"Korean\"));\n\tvoid(_(\"Dutch\"));\n\tvoid(_(\"Portugese\"));\n\tvoid(_(\"Russian\"));\n\tvoid(_(\"Taiwanese\"));\n\tvoid(_(\"unknown\"));\n}\n\n#if BOOST_OS_WINDOWS\n#include <shlobj.h>\nfs::path GetAppDataRoamingPath()\n{\n\tPWSTR path = nullptr;\n\tHRESULT result = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &path);\n\tif (FAILED(result))\n\t{\n\t\tCoTaskMemFree(path);\n\t\treturn {};\n\t}\n\tstd::string appDataPath = boost::nowide::narrow(path);\n\tCoTaskMemFree(path);\n\treturn _utf8ToPath(appDataPath);\n}\n#endif\n\n#if BOOST_OS_WINDOWS\nvoid CemuApp::DeterminePaths(std::set<fs::path>& failedWriteAccess) // for Windows\n{\n\tstd::error_code ec;\n\tbool isPortable = false;\n\tfs::path user_data_path, config_path, cache_path, data_path;\n\tauto standardPaths = wxStandardPaths::Get();\n\tfs::path exePath(wxHelper::MakeFSPath(standardPaths.GetExecutablePath()));\n\tfs::path portablePath = exePath.parent_path() / \"portable\";\n\tdata_path = exePath.parent_path(); // the data path is always the same as the exe path\n#ifdef CEMU_ALLOW_PORTABLE\n\tif (fs::is_directory(portablePath, ec))\n\t{\n\t\tisPortable = true;\n\t\tuser_data_path = config_path = cache_path = portablePath;\n\t}\n\telse\n#endif\n\t{\n\t\tfs::path roamingPath = GetAppDataRoamingPath() / \"Cemu\";\n\t\tuser_data_path = config_path = cache_path = roamingPath;\n\t}\n\t// on Windows Cemu used to be portable by default prior to 2.0-89\n\t// to remain backwards compatible with old installations we check for settings.xml in the Cemu directory\n\t// if it exists, we use the exe path as the portable directory\n\tif(!isPortable) // lower priority than portable directory\n\t{\n\t\tif (fs::exists(exePath.parent_path() / \"settings.xml\", ec))\n\t\t{\n\t\t\tisPortable = true;\n\t\t\tuser_data_path = config_path = cache_path = exePath.parent_path();\n\t\t}\n\t}\n\tActiveSettings::SetPaths(isPortable, exePath, user_data_path, config_path, cache_path, data_path, failedWriteAccess);\n}\n#endif\n\n#if BOOST_OS_LINUX || BOOST_OS_BSD\nvoid CemuApp::DeterminePaths(std::set<fs::path>& failedWriteAccess) // for Linux\n{\n\tstd::error_code ec;\n\tbool isPortable = false;\n\tfs::path user_data_path, config_path, cache_path, data_path;\n\tauto standardPaths = wxStandardPaths::Get();\n\tfs::path exePath(wxHelper::MakeFSPath(standardPaths.GetExecutablePath()));\n\tfs::path portablePath = exePath.parent_path() / \"portable\";\n\t// GetExecutablePath returns the AppImage's temporary mount location\n\twxString appImagePath;\n\tif (wxGetEnv(\"APPIMAGE\", &appImagePath))\n\t{\n\t\texePath = wxHelper::MakeFSPath(appImagePath);\n\t\tportablePath = exePath.parent_path() / \"portable\";\n\t}\n#ifdef CEMU_ALLOW_PORTABLE\n\tif (fs::is_directory(portablePath, ec))\n\t{\n\t\tisPortable = true;\n\t\tuser_data_path = config_path = cache_path = portablePath;\n\t\t// in portable mode assume the data directories (resources, gameProfiles/default/) are next to the executable\n\t\tdata_path = exePath.parent_path();\n\t}\n\telse\n#endif\n\t{\n\t\tSetAppName(\"Cemu\");\n\t\twxString appName = GetAppName();\n\t\tstandardPaths.SetFileLayout(wxStandardPaths::FileLayout::FileLayout_XDG);\n\t\tauto getEnvDir = [&](const wxString& varName, const wxString& defaultValue)\n\t\t{\n\t\t\twxString dir;\n\t\t\tif (!wxGetEnv(varName, &dir) || dir.empty())\n\t\t\t\treturn defaultValue;\n\t\t\treturn dir;\n\t\t};\n\t\twxString homeDir = wxFileName::GetHomeDir();\n\t\tuser_data_path = (getEnvDir(wxS(\"XDG_DATA_HOME\"), homeDir + wxS(\"/.local/share\")) + \"/\" + appName).ToStdString();\n\t\tconfig_path = (getEnvDir(wxS(\"XDG_CONFIG_HOME\"), homeDir + wxS(\"/.config\")) + \"/\" + appName).ToStdString();\n\t\tdata_path = standardPaths.GetDataDir().ToStdString();\n\t\tcache_path = standardPaths.GetUserDir(wxStandardPaths::Dir::Dir_Cache).ToStdString();\n\t\tcache_path /= appName.ToStdString();\n\t}\n\tActiveSettings::SetPaths(isPortable, exePath, user_data_path, config_path, cache_path, data_path, failedWriteAccess);\n}\n#endif\n\n#if BOOST_OS_MACOS\nvoid CemuApp::DeterminePaths(std::set<fs::path>& failedWriteAccess) // for MacOS\n{\n\tstd::error_code ec;\n\tbool isPortable = false;\n\tfs::path user_data_path, config_path, cache_path, data_path;\n\tauto standardPaths = wxStandardPaths::Get();\n\tfs::path exePath(wxHelper::MakeFSPath(standardPaths.GetExecutablePath()));\n    // If run from an app bundle, use its parent directory\n\tfs::path appPath = exePath.parent_path().parent_path().parent_path();\n\tfs::path portablePath = appPath.extension() == \".app\" ? appPath.parent_path() / \"portable\" : exePath.parent_path() / \"portable\";\n#ifdef CEMU_ALLOW_PORTABLE\n\tif (fs::is_directory(portablePath, ec))\n\t{\n\t\tisPortable = true;\n\t\tuser_data_path = config_path = cache_path = portablePath;\n\t\tdata_path = exePath.parent_path();\n\t}\n\telse\n#endif\n\t{\n\t\tSetAppName(\"Cemu\");\n\t\twxString appName = GetAppName();\n\t\tuser_data_path = config_path = standardPaths.GetUserDataDir().ToStdString();\n\t\tdata_path = standardPaths.GetDataDir().ToStdString();\n\t\tcache_path = standardPaths.GetUserDir(wxStandardPaths::Dir::Dir_Cache).ToStdString();\n\t\tcache_path /= appName.ToStdString();\n\t}\n\tActiveSettings::SetPaths(isPortable, exePath, user_data_path, config_path, cache_path, data_path, failedWriteAccess);\n}\n#endif\n\n// create default MLC files or quit if it fails\nvoid CemuApp::InitializeNewMLCOrFail(fs::path mlc)\n{\n\tif( CemuApp::CreateDefaultMLCFiles(mlc) )\n\t\treturn; // all good\n\tcemu_assert_debug(!ActiveSettings::IsCustomMlcPath()); // should not be possible?\n\n\tif(ActiveSettings::IsCommandLineMlcPath() || ActiveSettings::IsCustomMlcPath())\n\t{\n\t\t// tell user that the custom path is not writable\n\t\twxMessageBox(formatWxString(_(\"Cemu failed to write to the custom mlc directory.\\nThe path is:\\n{}\"), wxHelper::FromPath(mlc)), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\texit(0);\n\t}\n\twxMessageBox(formatWxString(_(\"Cemu failed to write to the mlc directory.\\nThe path is:\\n{}\"), wxHelper::FromPath(mlc)), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\texit(0);\n}\n\nvoid CemuApp::InitializeExistingMLCOrFail(fs::path mlc)\n{\n\tif(CreateDefaultMLCFiles(mlc))\n\t\treturn; // all good\n\t// failed to write mlc files\n\tif(ActiveSettings::IsCommandLineMlcPath() || ActiveSettings::IsCustomMlcPath())\n\t{\n\t\t// tell user that the custom path is not writable\n\t\t// if it's a command line path then just quit. Otherwise ask if user wants to reset the path\n\t\tif(ActiveSettings::IsCommandLineMlcPath())\n\t\t{\n\t\t\twxMessageBox(formatWxString(_(\"Cemu failed to write to the custom mlc directory.\\nThe path is:\\n{}\"), wxHelper::FromPath(mlc)), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\t\texit(0);\n\t\t}\n\t\t// ask user if they want to reset the path\n\t\tconst wxString message = formatWxString(_(\"Cemu failed to write to the custom mlc directory.\\n\\nThe path is:\\n{}\\n\\nCemu cannot start without a valid mlc path. Do you want to reset the path? You can later change it again in the General Settings.\"),\n\t\t\t\t\t\t\t\t\t\t\t\t_pathToUtf8(mlc));\n\t\twxMessageDialog dialog(nullptr, message, _(\"Error\"), wxCENTRE | wxYES_NO | wxICON_WARNING);\n\t\tdialog.SetYesNoLabels(_(\"Reset path\"), _(\"Exit\"));\n\t\tconst auto dialogResult = dialog.ShowModal();\n\t\tif (dialogResult == wxID_NO)\n\t\t\texit(0);\n\t\telse // reset path\n\t\t{\n\t\t\tGetConfig().mlc_path = \"\";\n\t\t\tGetConfigHandle().Save();\n\t\t}\n\t}\n\telse\n\t{\n\t\t// default path is not writeable. Just let the user know and quit. Unsure if it would be a good idea to ask the user to choose an alternative path instead\n\t\twxMessageBox(formatWxString(_(\"Cemu failed to write to the default mlc directory.\\nThe path is:\\n{}\"), wxHelper::FromPath(mlc)), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\texit(0);\n\t}\n}\n\nstd::string TranslationCallback(std::string_view msgId)\n{\n\treturn wxGetTranslation(wxString::FromUTF8(msgId)).utf8_string();\n}\n\nbool CemuApp::OnInit()\n{\n#if __WXGTK__\n\tGTKSuppressDiagnostics(G_LOG_LEVEL_MASK & ~G_LOG_FLAG_FATAL);\n#endif\n\tstd::set<fs::path> failedWriteAccess;\n\tDeterminePaths(failedWriteAccess);\n\t// make sure default cemu directories exist\n\tCreateDefaultCemuFiles();\n\n\tGetConfigHandle().SetFilename(ActiveSettings::GetConfigPath(\"settings.xml\").generic_wstring());\n\n\tauto& config = GetWxGUIConfig();\n\n\tstd::error_code ec;\n\tbool isFirstStart = !fs::exists(ActiveSettings::GetConfigPath(\"settings.xml\"), ec);\n\n\tNetworkConfig::LoadOnce();\n\tif (!isFirstStart)\n\t{\n\t\tGetConfigHandle().Load();\n\t\tsint32 language = config.language.GetValue();\n\t\tLocalizeUI(static_cast<wxLanguage>(language == wxLANGUAGE_DEFAULT ? wxLocale::GetSystemLanguage() : language));\n\t}\n\telse\n\t{\n\t\tLocalizeUI(static_cast<wxLanguage>(wxLocale::GetSystemLanguage()));\n\t}\n\n\tSetTranslationCallback(TranslationCallback);\n#if __WXMSW__\n\tauto& wxGuiConfig = GetWxGUIConfig();\n\tif (wxGuiConfig.msw_theme.GetValue() == static_cast<int>(MSWThemeOption::kAuto))\n\t{\n\t\tMSWEnableDarkMode(DarkMode_Auto);\n\t}\n\telse if (wxGuiConfig.msw_theme.GetValue() == static_cast<int>(MSWThemeOption::kDark))\n\t{\n\t\tMSWEnableDarkMode(DarkMode_Always);\n\t}\n\n\t// extend tooltip duration to the maximum possible value\n\twxToolTip::SetDelay(-1);\n\twxToolTip::SetAutoPop(MAKELPARAM(std::numeric_limits<short>::max(),0));\n#endif\n\n\tfor (auto&& path : failedWriteAccess)\n\t{\n\t\twxMessageBox(formatWxString(_(\"Cemu can't write to {}!\"), wxHelper::FromPath(path)),\n\t\t\t\t\t _(\"Warning\"), wxOK | wxCENTRE | wxICON_EXCLAMATION, nullptr);\n\t}\n\n\tif (isFirstStart)\n\t{\n\t\t// show the getting started dialog\n\t\tGettingStartedDialog dia(nullptr);\n\t\tdia.ShowModal();\n\t\t// make sure config is created. Gfx pack UI and input UI may create it earlier already, but we still want to update it\n\t\tGetConfigHandle().Save();\n\t\t// create mlc, on failure the user can quit here. So do this after the Getting Started dialog\n\t\tInitializeNewMLCOrFail(ActiveSettings::GetMlcPath());\n\t}\n\telse\n\t{\n\t\t// check if mlc is valid and recreate default files\n\t\tInitializeExistingMLCOrFail(ActiveSettings::GetMlcPath());\n\t}\n\n\tActiveSettings::Init(); // this is a bit of a misnomer, right now this call only loads certs for online play. In the future we should move the logic to a more appropriate place\n\tHandlePostUpdate();\n\n\tLatteOverlay_init();\n\t// run a couple of tests if in non-release mode\n#ifdef CEMU_DEBUG_ASSERT\n\tUnitTests();\n#endif\n\tCemuCommonInit();\n\n\twxInitAllImageHandlers();\n\n\t// fill colour db\n\twxTheColourDatabase->AddColour(\"ERROR\", wxColour(0xCC, 0, 0));\n\twxTheColourDatabase->AddColour(\"SUCCESS\", wxColour(0, 0xbb, 0));\n\n#if BOOST_OS_WINDOWS\n\tconst auto parent_path = GetParentProcess();\n\tif(parent_path.has_filename())\n\t{\n\t\tconst auto filename = parent_path.filename().generic_string();\n\t\tif (boost::icontains(filename, \"WiiU_USB_Helper\"))\n\t\t\t__fastfail(0);\n\t}\n#endif\n\tInitializeGlobalVulkan();\n\n\tBind(wxEVT_ACTIVATE_APP, &CemuApp::ActivateApp, this);\n\n\tm_mainFrame = new MainWindow();\n\n\tstd::unique_lock lock(g_mutex);\n\tg_window_info.app_active = true;\n\n\tHotkeySettings::Init(m_mainFrame);\n\n\tSetTopWindow(m_mainFrame);\n\tm_mainFrame->Show();\n\n#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND\n\tif (wxWlIsWaylandWindow(m_mainFrame))\n\t\twxWlSetAppId(m_mainFrame, \"info.cemu.Cemu\");\n#endif\n\n\t// show warning on macOS about state of builds\n#if BOOST_OS_MACOS\n\tif (!config.did_show_macos_disclaimer)\n\t{\n\t\tconst auto message = _(\n\t\t\t\"Thank you for testing the in-development build of Cemu for macOS.\\n \\n\"\n\t\t\t\"The macOS port is currently purely experimental and should not be considered stable or ready for issue-free gameplay. \"\n\t\t\t\"There are also known issues with degraded performance due to the use of MoltenVk and Rosetta for ARM Macs. We appreciate your patience while we improve Cemu for macOS.\");\n\t\twxMessageDialog dialog(nullptr, message, _(\"Preview version\"), wxCENTRE | wxOK | wxICON_WARNING);\n\t\tdialog.SetOKLabel(_(\"I understand\"));\n\t\tdialog.ShowModal();\n\t\tconfig.did_show_macos_disclaimer = true;\n\t\tGetConfigHandle().Save();\n\t}\n#endif\n\n\treturn true;\n}\n\nint CemuApp::OnExit()\n{\n\twxApp::OnExit();\n\twxTheClipboard->Flush();\n#if BOOST_OS_WINDOWS\n\tExitProcess(0);\n#else\n\t_Exit(0);\n#endif\n}\n\n#if BOOST_OS_WINDOWS\nvoid DumpThreadStackTrace();\n#endif\n\nvoid CemuApp::OnAssertFailure(const wxChar* file, int line, const wxChar* func, const wxChar* cond, const wxChar* msg)\n{\n\tcemuLog_createLogFile(false);\n\tcemuLog_log(LogType::Force, \"Encountered wxWidgets assert!\");\n\tcemuLog_log(LogType::Force, \"File: {0} Line: {1}\", wxString(file).utf8_string(), line);\n\tcemuLog_log(LogType::Force, \"Func: {0} Cond: {1}\", wxString(func).utf8_string(), wxString(cond).utf8_string());\n\tcemuLog_log(LogType::Force, \"Message: {}\", wxString(msg).utf8_string());\n\n#if BOOST_OS_WINDOWS\n\tDumpThreadStackTrace();\n#endif\n\tcemu_assert_debug(false);\n}\n\nint CemuApp::FilterEvent(wxEvent& event)\n{\n\tif(event.GetEventType() == wxEVT_KEY_DOWN)\n\t{\n\t\tconst auto& key_event = (wxKeyEvent&)event;\n\t\tg_window_info.set_keystate(fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()), true);\n\t}\n\telse if(event.GetEventType() == wxEVT_KEY_UP)\n\t{\n\t\tconst auto& key_event = (wxKeyEvent&)event;\n\t\tg_window_info.set_keystate(fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()), false);\n\t}\n\telse if(event.GetEventType() == wxEVT_ACTIVATE_APP)\n\t{\n\t\tconst auto& activate_event = (wxActivateEvent&)event;\n\t\tif(!activate_event.GetActive())\n\t\t\tg_window_info.set_keystatesup();\n\t}\n\n\t// track if debugger window or its child windows are focused\n\tif (g_debugger_window && (event.GetEventType() == wxEVT_SET_FOCUS || event.GetEventType() == wxEVT_ACTIVATE))\n\t{\n\t\twxWindow* target_window = wxDynamicCast(event.GetEventObject(), wxWindow);\n\n\t\tif (target_window && event.GetEventType() == wxEVT_ACTIVATE && !((wxActivateEvent&)event).GetActive())\n\t\t\ttarget_window = nullptr;\n\n\t\tif (target_window)\n\t\t{\n\t\t\tg_window_info.debugger_focused = false;\n\t\t\twxWindow* window_it = target_window;\n\t\t\twhile (window_it)\n\t\t\t{\n\t\t\t\tif (window_it == g_debugger_window) g_window_info.debugger_focused = true;\n\t\t\t\twindow_it = window_it->GetParent();\n\t\t\t}\n\t\t}\n\t}\n\telse if (!g_debugger_window)\n\t{\n\t\tg_window_info.debugger_focused = false;\n\t}\n\n\treturn wxApp::FilterEvent(event);\n}\n\nstd::vector<const wxLanguageInfo *> CemuApp::GetLanguages() const {\n\tstd::vector availableLanguages(m_availableTranslations);\n\tavailableLanguages.insert(availableLanguages.begin(), wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH));\n\treturn availableLanguages;\n}\n\nvoid CemuApp::LocalizeUI(wxLanguage languageToUse)\n{\n\tstd::unique_ptr<wxTranslations> translationsMgr(new wxTranslations());\n\tm_availableTranslations = GetAvailableTranslationLanguages(translationsMgr.get());\n\n\tbool isTranslationAvailable = std::any_of(m_availableTranslations.begin(), m_availableTranslations.end(),\n\t\t\t\t\t\t\t\t\t\t\t  [languageToUse](const wxLanguageInfo* info) { return info->Language == languageToUse; });\n\tif (languageToUse == wxLANGUAGE_DEFAULT || isTranslationAvailable)\n\t{\n\t\ttranslationsMgr->SetLanguage(static_cast<wxLanguage>(languageToUse));\n\t\ttranslationsMgr->AddCatalog(\"cemu\");\n\n\t\tif (translationsMgr->IsLoaded(\"cemu\") && wxLocale::IsAvailable(languageToUse))\n\t\t{\n\t\t\tm_locale.Init(languageToUse);\n\t\t}\n\t\t// This must be run after wxLocale::Init, as the latter sets up its own wxTranslations instance which we want to override\n\t\twxTranslations::Set(translationsMgr.release());\n\t}\n}\n\nstd::vector<const wxLanguageInfo*> CemuApp::GetAvailableTranslationLanguages(wxTranslations* translationsMgr)\n{\n\twxFileTranslationsLoader::AddCatalogLookupPathPrefix(wxHelper::FromPath(ActiveSettings::GetDataPath(\"resources\")));\n\tstd::vector<const wxLanguageInfo*> languages;\n\tfor (const auto& langName : translationsMgr->GetAvailableTranslations(\"cemu\"))\n\t{\n\t\tconst auto* langInfo = wxLocale::FindLanguageInfo(langName);\n\t\tif (langInfo)\n\t\t\tlanguages.emplace_back(langInfo);\n\t}\n\treturn languages;\n}\n\nbool CemuApp::CheckMLCPath(const fs::path& mlc)\n{\n\tstd::error_code ec;\n\tif (!fs::exists(mlc, ec))\n\t\treturn false;\n\tif (!fs::exists(mlc / \"usr\", ec) || !fs::exists(mlc / \"sys\", ec))\n\t\treturn false;\n\treturn true;\n}\n\nbool CemuApp::CreateDefaultMLCFiles(const fs::path& mlc)\n{\n\tauto CreateDirectoriesIfNotExist = [](const fs::path& path)\n\t{\n\t\tstd::error_code ec;\n\t\tif (!fs::exists(path, ec))\n\t\t\treturn fs::create_directories(path, ec);\n\t\treturn true;\n\t};\n\t// list of directories to create\n\tconst fs::path directories[] = {\n\t\tmlc,\n\t\tmlc / \"sys\",\n\t\tmlc / \"usr\",\n\t\tmlc / \"usr/title/00050000\", // base\n\t\tmlc / \"usr/title/0005000c\", // dlc\n\t\tmlc / \"usr/title/0005000e\", // update\n\t\tmlc / \"usr/save/00050010/1004a000/user/common/db\", // Mii Maker save folders {0x500101004A000, 0x500101004A100, 0x500101004A200}\n\t\tmlc / \"usr/save/00050010/1004a100/user/common/db\",\n\t\tmlc / \"usr/save/00050010/1004a200/user/common/db\",\n\t\tmlc / \"sys/title/0005001b/1005c000/content\" // lang files\n\t};\n\tfor(auto& path : directories)\n\t{\n\t\tif(!CreateDirectoriesIfNotExist(path))\n\t\t\treturn false;\n\t}\n\t// create sys/usr folder in mlc01\n\ttry\n\t{\n\t\tconst auto langDir = fs::path(mlc).append(\"sys/title/0005001b/1005c000/content\");\n\t\tauto langFile = fs::path(langDir).append(\"language.txt\");\n\t\tif (!fs::exists(langFile))\n\t\t{\n\t\t\tstd::ofstream file(langFile);\n\t\t\tif (file.is_open())\n\t\t\t{\n\t\t\t\tconst char* langStrings[] = { \"ja\",\"en\",\"fr\",\"de\",\"it\",\"es\",\"zh\",\"ko\",\"nl\",\"pt\",\"ru\",\"zh\" };\n\t\t\t\tfor (const char* lang : langStrings)\n\t\t\t\t\tfile << fmt::format(R\"(\"{}\",)\", lang) << std::endl;\n\n\t\t\t\tfile.flush();\n\t\t\t\tfile.close();\n\t\t\t}\n\t\t}\n\n\t\tauto countryFile = fs::path(langDir).append(\"country.txt\");\n\t\tif (!fs::exists(countryFile))\n\t\t{\n\t\t\tstd::ofstream file(countryFile);\n\t\t\tfor (sint32 i = 0; i < NCrypto::GetCountryCount(); i++)\n\t\t\t{\n\t\t\t\tconst char* countryCode = NCrypto::GetCountryAsString(i);\n\t\t\t\tif (boost::iequals(countryCode, \"NN\"))\n\t\t\t\t\tfile << \"NULL,\" << std::endl;\n\t\t\t\telse\n\t\t\t\t\tfile << fmt::format(R\"(\"{}\",)\", countryCode) << std::endl;\n\t\t\t}\n\t\t\tfile.flush();\n\t\t\tfile.close();\n\t\t}\n\t\t// create a dummy file in the mlc folder to check if it's writable\n\t\tconst auto dummyFile = fs::path(mlc).append(\"writetestdummy\");\n\t\tstd::ofstream file(dummyFile);\n\t\tif (!file.is_open())\n\t\t\treturn false;\n\t\tfile.close();\n\t\tfs::remove(dummyFile);\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nvoid CemuApp::CreateDefaultCemuFiles()\n{\n\t// cemu directories\n\ttry\n\t{\n\t\tconst auto controllerProfileFolder = ActiveSettings::GetConfigPath(\"controllerProfiles\");\n\t\tif (!fs::exists(controllerProfileFolder))\n\t\t\tfs::create_directories(controllerProfileFolder);\n\n\t\tconst auto memorySearcherFolder = ActiveSettings::GetUserDataPath(\"memorySearcher\");\n\t\tif (!fs::exists(memorySearcherFolder))\n\t\t\tfs::create_directories(memorySearcherFolder);\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\twxString errorMsg = formatWxString(_(\"Couldn't create a required cemu directory or file!\\n\\nError: {0}\"), ex.what());\n\n#if BOOST_OS_WINDOWS\n\t\tconst DWORD lastError = GetLastError();\n\t\tif (lastError != ERROR_SUCCESS)\n\t\t\terrorMsg << fmt::format(\"\\n\\n{}\", GetSystemErrorMessage(lastError));\n#endif\n\n\t\twxMessageBox(errorMsg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\texit(0);\n\t}\n}\n\nvoid CemuApp::ActivateApp(wxActivateEvent& event)\n{\n\tg_window_info.app_active = event.GetActive();\n\tevent.Skip();\n}\n"
  },
  {
    "path": "src/gui/wxgui/CemuApp.h",
    "content": "#pragma once\n\n#include <wx/app.h>\n\nclass MainWindow;\n\nclass CemuApp : public wxApp\n{\npublic:\n\tbool OnInit() override;\n\tint OnExit() override;\n\n\tvoid OnAssertFailure(const wxChar* file, int line, const wxChar* func, const wxChar* cond, const wxChar* msg) override;\n\tint FilterEvent(wxEvent& event) override;\n\n\tstd::vector<const wxLanguageInfo*> GetLanguages() const;\n\n\tstatic bool CheckMLCPath(const fs::path& mlc);\n\tstatic bool CreateDefaultMLCFiles(const fs::path& mlc);\n\tstatic void CreateDefaultCemuFiles();\n\n\tstatic void InitializeNewMLCOrFail(fs::path mlc);\n\tstatic void InitializeExistingMLCOrFail(fs::path mlc);\nprivate:\n\tvoid LocalizeUI(wxLanguage languageToUse);\n\n\tvoid DeterminePaths(std::set<fs::path>& failedWriteAccess);\n\n\tvoid ActivateApp(wxActivateEvent& event);\n\tstatic std::vector<const wxLanguageInfo*> GetAvailableTranslationLanguages(wxTranslations* translationsMgr);\n\n\tMainWindow* m_mainFrame = nullptr;\n\n\twxLocale m_locale;\n\tstd::vector<const wxLanguageInfo*> m_availableTranslations;\n};\n\nwxDECLARE_APP(CemuApp);\n"
  },
  {
    "path": "src/gui/wxgui/CemuUpdateWindow.cpp",
    "content": "#include \"wxgui/CemuUpdateWindow.h\"\n\n#include \"Common/version.h\"\n#include \"util/helpers/helpers.h\"\n#include \"util/helpers/SystemException.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Common/FileStream.h\"\n#include \"wxCemuConfig.h\"\n\n#include <wx/sizer.h>\n#include <wx/gauge.h>\n#include <wx/button.h>\n#include <wx/msgdlg.h>\n#include <wx/stdpaths.h>\n\n#ifndef BOOST_OS_WINDOWS\n#include <unistd.h>\n#include <sys/stat.h>\n#endif\n\n#include <curl/curl.h>\n#include <zip.h>\n#include <boost/tokenizer.hpp>\n\n\nwxDECLARE_EVENT(wxEVT_RESULT, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_RESULT, wxCommandEvent);\n\nwxDECLARE_EVENT(wxEVT_PROGRESS, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_PROGRESS, wxCommandEvent);\n\nCemuUpdateWindow::CemuUpdateWindow(wxWindow* parent)\n\t: wxDialog(parent, wxID_ANY, _(\"Cemu update\"), wxDefaultPosition, wxDefaultSize,\n\t\twxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX)\n{\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\tm_gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(500, 20), wxGA_HORIZONTAL);\n\tm_gauge->SetValue(0);\n\tsizer->Add(m_gauge, 0, wxALL | wxEXPAND, 5);\n\n\tauto* rows = new wxFlexGridSizer(0, 2, 0, 0);\n\trows->AddGrowableCol(1);\n\n\tm_text = new wxStaticText(this, wxID_ANY, _(\"Checking for latest version...\"));\n\trows->Add(m_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t{\n\t\tauto* right_side = new wxBoxSizer(wxHORIZONTAL);\n\n\t\tm_updateButton = new wxButton(this, wxID_ANY, _(\"Update\"));\n\t\tm_updateButton->Bind(wxEVT_BUTTON, &CemuUpdateWindow::OnUpdateButton, this);\n\t\tright_side->Add(m_updateButton, 0, wxALL, 5);\n\n\t\tm_cancelButton = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\t\tm_cancelButton->Bind(wxEVT_BUTTON, &CemuUpdateWindow::OnCancelButton, this);\n\t\tright_side->Add(m_cancelButton, 0, wxALL, 5);\n\n\t\trows->Add(right_side, 1, wxALIGN_RIGHT, 5);\n\t}\n\n\tm_changelog = new wxHyperlinkCtrl(this, wxID_ANY, _(\"Changelog\"), wxEmptyString);\n\trows->Add(m_changelog, 0, wxLEFT | wxBOTTOM | wxRIGHT | wxEXPAND, 5);\n\n\tsizer->Add(rows, 0, wxALL | wxEXPAND, 5);\n\n\tSetSizerAndFit(sizer);\n\tCentre(wxBOTH);\n\n\tBind(wxEVT_CLOSE_WINDOW, &CemuUpdateWindow::OnClose, this);\n\tBind(wxEVT_RESULT, &CemuUpdateWindow::OnResult, this);\n\tBind(wxEVT_PROGRESS, &CemuUpdateWindow::OnGaugeUpdate, this);\n\tm_thread = std::thread(&CemuUpdateWindow::WorkerThread, this);\n\n\tm_updateButton->Hide();\n\tm_changelog->Hide();\n}\n\nCemuUpdateWindow::~CemuUpdateWindow()\n{\n\tm_order = WorkerOrder::Exit;\n\tif (m_thread.joinable())\n\t\tm_thread.join();\n}\n\nsize_t CemuUpdateWindow::WriteStringCallback(char* ptr, size_t size, size_t nmemb, void* userdata)\n{\n\t((std::string*)userdata)->append(ptr, size * nmemb);\n\treturn size * nmemb;\n};\n\nstd::string _curlUrlEscape(CURL* curl, const std::string& input)\n{\n\tchar* escapedStr = curl_easy_escape(curl, input.c_str(), input.size());\n\tstd::string r(escapedStr);\n\tcurl_free(escapedStr);\n\treturn r;\n}\n\nstd::string _curlUrlUnescape(CURL* curl, std::string_view input)\n{\n\tint decodedLen = 0;\n\tconst char* decoded = curl_easy_unescape(curl, input.data(), input.size(), &decodedLen);\n\treturn std::string(decoded, decodedLen);\n}\n\n// returns true if update is available and sets output parameters\nbool CemuUpdateWindow::QueryUpdateInfo(std::string& downloadUrlOut, std::string& changelogUrlOut)\n{\n\tstd::string buffer;\n\tstd::string urlStr(\"https://cemu.info/api2/version.php?v=\");\n\tauto* curl = curl_easy_init();\n\turlStr.append(_curlUrlEscape(curl, BUILD_VERSION_STRING));\n#if BOOST_OS_LINUX || BOOST_OS_BSD // dummy placeholder on BSD for now\n\turlStr.append(\"&platform=linux_appimage\");\n#elif BOOST_OS_WINDOWS\n\turlStr.append(\"&platform=windows\");\n#elif BOOST_OS_MACOS\n\turlStr.append(\"&platform=macos_bundle\");\n#else\n#error Name for current platform is missing\n#endif\n#if defined(__aarch64__)\n\turlStr.append(\"_aarch64\");\n#elif defined(ARCH_X86_64)\n\turlStr.append(\"_x86_64\");\n#else\n\turlStr.append(\"_unknown\");\n#endif\n#if BOOST_OS_BSD\n\treturn false; // BSD users must update from source; no binary available\n#endif\n\n\tconst auto& config = GetWxGUIConfig();\n\tif(config.receive_untested_updates)\n\t\turlStr.append(\"&allowNewUpdates=1\");\n\n\tcurl_easy_setopt(curl, CURLOPT_URL, urlStr.c_str());\n\tcurl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);\n\tcurl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);\n\tcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteStringCallback);\n\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);\n\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);\n\n\tbool result = false;\n\tCURLcode cr = curl_easy_perform(curl);\n\tif (cr == CURLE_OK)\n\t{\n\t\tlong http_code = 0;\n\t\tcurl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);\n\t\tif (http_code != 0 && http_code != 200)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Update check failed (http code: {})\", http_code);\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn false;\n\t\t}\n\n\t\tstd::vector<std::string> tokens;\n\t\tconst boost::char_separator<char> sep{ \"|\" };\n\t\tfor (const auto& token : boost::tokenizer(buffer, sep))\n\t\t\ttokens.emplace_back(token);\n\n\t\tif (tokens.size() >= 3 && tokens[0] == \"UPDATE\")\n\t\t{\n\t\t\t// first token: \"UPDATE\"\n\t\t\t// second token: Download URL\n\t\t\t// third token: Changelog URL\n\t\t\t// we allow more tokens in case we ever want to add extra information for future releases\n\t\t\tdownloadUrlOut = _curlUrlUnescape(curl, tokens[1]);\n\t\t\tchangelogUrlOut = _curlUrlUnescape(curl, tokens[2]);\n\t\t\tif (!downloadUrlOut.empty() && !changelogUrlOut.empty())\n\t\t\t\tresult = true;\n\t\t}\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"Update check failed with CURL error {}\", (int)cr);\n\t\tcemu_assert_debug(false);\n\t}\n\n\tcurl_easy_cleanup(curl);\n\treturn result;\n}\n\nstd::future<bool> CemuUpdateWindow::IsUpdateAvailableAsync()\n{\n\treturn std::async(std::launch::async, CheckVersion);\n}\n\nbool CemuUpdateWindow::CheckVersion()\n{\n\tstd::string downloadUrl, changelogUrl;\n\treturn QueryUpdateInfo(downloadUrl, changelogUrl);\n}\n\n\nint CemuUpdateWindow::ProgressCallback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal,\n\tcurl_off_t ulnow)\n{\n\tauto* thisptr = (CemuUpdateWindow*)clientp;\n\tauto* event = new wxCommandEvent(wxEVT_PROGRESS);\n\tevent->SetInt((int)dlnow);\n\twxQueueEvent(thisptr, event);\n\treturn 0;\n}\n\nbool CemuUpdateWindow::DownloadCemuZip(const std::string& url, const fs::path& filename)\n{\n\tFileStream* fsUpdateFile = FileStream::createFile2(filename);\n\tif (!fsUpdateFile)\n\t\treturn false;\n\n\tbool result = false;\n\tauto* curl = curl_easy_init();\n\tcurl_easy_setopt(curl, CURLOPT_URL, url.c_str());\n\tcurl_easy_setopt(curl, CURLOPT_NOBODY, 1);\n\tcurl_easy_setopt(curl, CURLOPT_USERAGENT, BUILD_VERSION_WITH_NAME_STRING);\n\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);\n\tcurl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);\n\tauto r = curl_easy_perform(curl);\n\tif (r == CURLE_OK)\n\t{\n\t\tlong http_code = 0;\n\t\tcurl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);\n\t\tif (http_code != 0 && http_code != 200)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Unable to download cemu update zip file from {} (http error: {})\", url, http_code);\n\t\t\tcurl_easy_cleanup(curl);\n\t\t\treturn false;\n\t\t}\n\n\t\tcurl_off_t update_size;\n\t\tif (curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &update_size) == CURLE_OK)\n\t\t\tm_gaugeMaxValue = (int)update_size;\n\n\n\t\tauto _curlWriteData = +[](void* ptr, size_t size, size_t nmemb, void* ctx) -> size_t\n\t\t{\n\t\t\tFileStream* fs = (FileStream*)ctx;\n\t\t\tconst size_t writeSize = size * nmemb;\n\t\t\tfs->writeData(ptr, writeSize);\n\t\t\treturn writeSize;\n\t\t};\n\n\t\tcurl_easy_setopt(curl, CURLOPT_NOBODY, 0);\n\t\tcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _curlWriteData);\n\t\tcurl_easy_setopt(curl, CURLOPT_WRITEDATA, fsUpdateFile);\n\t\tcurl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);\n\t\tcurl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, ProgressCallback);\n\t\tcurl_easy_setopt(curl, CURLOPT_XFERINFODATA, this);\n\n\t\tauto curl_result = std::async(std::launch::async, [](CURL* curl, long* http_code)\n\t\t\t{\n\t\t\t\tconst auto r = curl_easy_perform(curl);\n\t\t\t\tcurl_easy_cleanup(curl);\n\t\t\t\treturn r;\n\t\t\t}, curl, &http_code);\n\t\twhile (!curl_result.valid())\n\t\t{\n\t\t\tif (m_order == WorkerOrder::Exit)\n\t\t\t\treturn false;\n\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\t}\n\n\t\tresult = curl_result.get() == CURLE_OK;\n\n\t\tdelete fsUpdateFile;\n\t}\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"Cemu zip download failed with error {}\", r);\n\t\tcurl_easy_cleanup(curl);\n\t}\n\n\tif (!result && fs::exists(filename))\n\t{\n\t\ttry\n\t\t{\n\t\t\tfs::remove(filename);\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"can't remove update.zip on error: {}\", ex.what());\n\t\t}\n\t}\n\treturn result;\n}\n\nbool CemuUpdateWindow::ExtractUpdate(const fs::path& zipname, const fs::path& targetpath, std::string& cemuFolderName)\n{\n\tcemuFolderName.clear();\n\t// open downloaded zip\n\tint err;\n\tauto* za = zip_open(zipname.string().c_str(), ZIP_RDONLY, &err);\n\tif (za == nullptr)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Cannot open zip file: {}\", zipname.string());\n\t\treturn false;\n\t}\n\n\tconst auto count = zip_get_num_entries(za, 0);\n\tm_gaugeMaxValue = count;\n\tfor (auto i = 0; i < count; i++)\n\t{\n\t\tif (m_order == WorkerOrder::Exit)\n\t\t\treturn false;\n\n\t\tzip_stat_t sb{};\n\t\tif (zip_stat_index(za, i, 0, &sb) == 0)\n\t\t{\n\t\t\tfs::path fname = targetpath;\n\t\t\tfname /= sb.name;\n\n\t\t\tconst auto len = strlen(sb.name);\n\t\t\tif (strcmp(sb.name, \".\") == 0 || strcmp(sb.name, \"..\") == 0)\n\t\t\t{\n\t\t\t\t// protection\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (sb.name[len - 1] == '/' || sb.name[len - 1] == '\\\\')\n\t\t\t{\n\t\t\t\t// directory\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tif (!exists(fname))\n\t\t\t\t\t\tcreate_directory(fname);\n\t\t\t\t}\n\t\t\t\tcatch (const std::exception& ex)\n\t\t\t\t{\n\t\t\t\t\tSystemException sys(ex);\n\t\t\t\t\tcemuLog_log(LogType::Force, \"can't create folder \\\"{}\\\" for update: {}\", sb.name, sys.what());\n\t\t\t\t}\n\t\t\t\t// the root should have only one Cemu_... directory, we track it here\n\t\t\t\tif ((std::count(sb.name, sb.name + len, '/') + std::count(sb.name, sb.name + len, '\\\\')) == 1)\n\t\t\t\t{\n\t\t\t\t\tif (!cemuFolderName.empty())\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"update zip has multiple folders in root\");\n\t\t\t\t\tcemuFolderName.assign(sb.name, len - 1);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// file\n\t\t\tauto* zf = zip_fopen_index(za, i, 0);\n\t\t\tif (!zf)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"can't open zip file \\\"{}\\\"\", sb.name);\n\t\t\t\tzip_close(za);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tstd::vector<char> buffer(sb.size);\n\t\t\tconst auto read = zip_fread(zf, buffer.data(), sb.size);\n\t\t\tif (read != (sint64)sb.size)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"could only read 0x{:x} of 0x{:x} bytes from zip file \\\"{}\\\"\", read, sb.size, sb.name);\n\t\t\t\tzip_close(za);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tauto* file = fopen(fname.string().c_str(), \"wb\");\n\t\t\tif (file == nullptr)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"can't create update file \\\"{}\\\"\", sb.name);\n\t\t\t\tzip_close(za);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfwrite(buffer.data(), 1, buffer.size(), file);\n\t\t\tfflush(file);\n\t\t\tfclose(file);\n\n\t\t\tzip_fclose(zf);\n\n\t\t\tif ((i / 10) * 10 == i)\n\t\t\t{\n\t\t\t\tauto* event = new wxCommandEvent(wxEVT_PROGRESS);\n\t\t\t\tevent->SetInt(i);\n\t\t\t\twxQueueEvent(this, event);\n\t\t\t}\n\t\t}\n\t}\n\n\tauto* event = new wxCommandEvent(wxEVT_PROGRESS);\n\tevent->SetInt(m_gaugeMaxValue);\n\twxQueueEvent(this, event);\n\n\tzip_close(za);\n\n\treturn true;\n}\n\nvoid CemuUpdateWindow::WorkerThread()\n{\n\tconst auto tmppath = fs::temp_directory_path() / L\"cemu_update\";\n\tstd::error_code ec;\n\t// clean leftovers\n\tif (exists(tmppath))\n\t\tremove_all(tmppath, ec);\n\n\twhile (true)\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\twhile (m_order == WorkerOrder::Idle)\n\t\t\tm_condition.wait_for(lock, std::chrono::milliseconds(125));\n\n\t\tif (m_order == WorkerOrder::Exit)\n\t\t\tbreak;\n\n\t\ttry\n\t\t{\n\t\t\tif (m_order == WorkerOrder::CheckVersion)\n\t\t\t{\n\t\t\t\tauto* event = new wxCommandEvent(wxEVT_RESULT);\n\t\t\t\tif (QueryUpdateInfo(m_downloadUrl, m_changelogUrl))\n\t\t\t\t\tevent->SetInt((int)Result::UpdateAvailable);\n\t\t\t\telse\n\t\t\t\t\tevent->SetInt((int)Result::NoUpdateAvailable);\n\n\t\t\t\twxQueueEvent(this, event);\n\t\t\t}\n\t\t\telse if (m_order == WorkerOrder::UpdateVersion)\n\t\t\t{\n\t\t\t\t// download update\n\t\t\t\tconst std::string url = m_downloadUrl;\n\t\t\t\tif (!exists(tmppath))\n\t\t\t\t\tcreate_directory(tmppath);\n\n#if BOOST_OS_WINDOWS\n\t\t\t\tconst auto update_file = tmppath / L\"update.zip\";\n#elif BOOST_OS_LINUX || BOOST_OS_BSD // dummy placeholder on BSD for now\n\t\t\t\tconst auto update_file = tmppath / L\"Cemu.AppImage\";\n#elif BOOST_OS_MACOS\n\t\t\t\tconst auto update_file = tmppath / L\"cemu.dmg\";\n#endif\t\n\t\t\t\tif (DownloadCemuZip(url, update_file))\n\t\t\t\t{\n\t\t\t\t\tauto* event = new wxCommandEvent(wxEVT_RESULT);\n\t\t\t\t\tevent->SetInt((int)Result::UpdateDownloaded);\n\t\t\t\t\twxQueueEvent(this, event);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto* event = new wxCommandEvent(wxEVT_RESULT);\n\t\t\t\t\tevent->SetInt((int)Result::UpdateDownloadError);\n\t\t\t\t\twxQueueEvent(this, event);\n\t\t\t\t\tm_order = WorkerOrder::Idle;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (m_order == WorkerOrder::Exit)\n\t\t\t\t\tbreak;\n\n\t\t\t\t// extract\n\t\t\t\tstd::string cemuFolderName;\n#if BOOST_OS_WINDOWS\n\t\t\t\tif (!ExtractUpdate(update_file, tmppath, cemuFolderName))\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Extracting Cemu zip failed\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (cemuFolderName.empty())\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Cemu folder not found in zip\");\n\t\t\t\t\tbreak;\n\t\t\t\t}\n#endif\n\t\t\t\tconst auto expected_path = tmppath / cemuFolderName;\n\t\t\t\tif (exists(expected_path))\n\t\t\t\t{\n\t\t\t\t\tauto* event = new wxCommandEvent(wxEVT_RESULT);\n\t\t\t\t\tevent->SetInt((int)Result::ExtractSuccess);\n\t\t\t\t\twxQueueEvent(this, event);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tauto* event = new wxCommandEvent(wxEVT_RESULT);\n\t\t\t\t\tevent->SetInt((int)Result::ExtractError);\n\t\t\t\t\twxQueueEvent(this, event);\n\n\t\t\t\t\tif (exists(tmppath))\n\t\t\t\t\t{\n\t\t\t\t\t\ttry\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfs::remove(tmppath);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch (const std::exception& ex)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSystemException sys(ex);\n\t\t\t\t\t\t\tcemuLog_log(LogType::Force, \"can't remove extracted tmp files: {}\", sys.what());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (m_order == WorkerOrder::Exit)\n\t\t\t\t\tbreak;\n\n\t\t\t\t// apply update\n\t\t\t\tfs::path exePath = ActiveSettings::GetExecutablePath();\n#if BOOST_OS_WINDOWS\n\t\t\t\tstd::wstring target_directory = exePath.parent_path().generic_wstring();\n\t\t\t\tif (target_directory[target_directory.size() - 1] == '/')\n\t\t\t\t\ttarget_directory = target_directory.substr(0, target_directory.size() - 1); // remove trailing /\n\n\t\t\t\t// get exe name\n\t\t\t\tconst auto exec = ActiveSettings::GetExecutablePath();\n\t\t\t\tconst auto target_exe = fs::path(exec).replace_extension(\"exe.backup\");\n\t\t\t\tfs::rename(exec, target_exe);\n\t\t\t\tm_restartFile = exec;\t\t\t\t\n#elif BOOST_OS_LINUX\n\t\t\t\tconst char* appimage_path = std::getenv(\"APPIMAGE\");\n\t\t\t\tconst auto target_exe = fs::path(appimage_path).replace_extension(\"AppImage.backup\");\n\t\t\t\tconst char* filePath = update_file.c_str();\n\t\t\t\tmode_t permissions = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;\n\t\t\t\tfs::rename(appimage_path, target_exe);\n\t\t\t\tm_restartFile = appimage_path;\n\t\t\t\tchmod(filePath, permissions);\n\t\t\t\twxString wxAppPath = wxString::FromUTF8(appimage_path);\n\t\t\t\twxCopyFile (wxT(\"/tmp/cemu_update/Cemu.AppImage\"), wxAppPath);\n#endif\n#if BOOST_OS_WINDOWS\n\t\t\t\tconst auto index = expected_path.wstring().size();\n\t\t\t\tint counter = 0;\n\t\t\t\tfor (const auto& it : fs::recursive_directory_iterator(expected_path))\n\t\t\t\t{\n\t\t\t\t\tconst auto filename = it.path().wstring().substr(index);\n\t\t\t\t\tauto target_file = target_directory + filename;\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tif (is_directory(it))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!fs::exists(target_file))\n\t\t\t\t\t\t\t\tfs::create_directory(target_file);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (it.path().filename() == L\"Cemu.exe\")\n\t\t\t\t\t\t\t\tfs::rename(it.path(), fs::path(target_file).replace_filename(exec.filename()));\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tfs::rename(it.path(), target_file);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch (const std::exception& ex)\n\t\t\t\t\t{\n\t\t\t\t\t\tSystemException sys(ex);\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"applying update error: {}\", sys.what());\n\t\t\t\t\t}\n\n\t\t\t\t\tif ((counter++ % 10) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tauto* event = new wxCommandEvent(wxEVT_PROGRESS);\n\t\t\t\t\t\tevent->SetInt(counter);\n\t\t\t\t\t\twxQueueEvent(this, event);\n\t\t\t\t\t}\n\t\t\t\t}\n#endif\n\t\t\t\tauto* event = new wxCommandEvent(wxEVT_PROGRESS);\n\t\t\t\tevent->SetInt(m_gaugeMaxValue);\n\t\t\t\twxQueueEvent(this, event);\n\n\t\t\t\tauto* result_event = new wxCommandEvent(wxEVT_RESULT);\n\t\t\t\tresult_event->SetInt((int)Result::Success);\n\t\t\t\twxQueueEvent(this, result_event);\n\t\t\t}\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tSystemException sys(ex);\n\t\t\tcemuLog_log(LogType::Force, \"update error: {}\", sys.what());\n\n\t\t\t// clean leftovers\n\t\t\tif (exists(tmppath))\n\t\t\t\tremove_all(tmppath, ec);\n\n\t\t\tauto* result_event = new wxCommandEvent(wxEVT_RESULT);\n\t\t\tresult_event->SetInt((int)Result::Error);\n\t\t\twxQueueEvent(this, result_event);\n\t\t}\n\n\t\tm_order = WorkerOrder::Idle;\n\t}\n}\n\nvoid CemuUpdateWindow::OnClose(wxCloseEvent& event)\n{\n\tevent.Skip();\n\n#if BOOST_OS_WINDOWS\n\tif (m_restartRequired && !m_restartFile.empty() && fs::exists(m_restartFile))\n\t{\n\t\tPROCESS_INFORMATION pi{};\n\t\tSTARTUPINFOW si{};\n\t\tsi.cb = sizeof(si);\n\n\t\tstd::wstring cmdline = GetCommandLineW();\n\t\tconst auto index = cmdline.find('\"', 1);\n\t\tcemu_assert_debug(index != std::wstring::npos);\n\t\tcmdline = L\"\\\"\" + boost::nowide::widen(_pathToUtf8(m_restartFile)) + L\"\\\"\" + cmdline.substr(index + 1);\n\n\t\tHANDLE lock = CreateMutexW(nullptr, TRUE, L\"Global\\\\cemu_update_lock\");\n\t\tCreateProcessW(nullptr, (wchar_t*)cmdline.c_str(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);\n\n\t\texit(0);\n\t}\n#elif BOOST_OS_LINUX\n\tif (m_restartRequired && !m_restartFile.empty() && fs::exists(m_restartFile))\n\t{\n\t\tconst char* appimage_path = std::getenv(\"APPIMAGE\");\n\t\texeclp(appimage_path, appimage_path, (char *)NULL);\n\n\t\texit(0);\n\t}\n#elif BOOST_OS_MACOS\n\tif (m_restartRequired)\n\t{\n\t    const auto tmppath = fs::temp_directory_path() / L\"cemu_update/Cemu.dmg\";\n\t    fs::path exePath = ActiveSettings::GetExecutablePath().parent_path();\n\t    const auto apppath = exePath / L\"update.sh\";\n\t    execlp(\"sh\", \"sh\", apppath.c_str(), NULL);\n        \n        exit(0);\n\t}\t\n#endif\n}\n\n\nvoid CemuUpdateWindow::OnResult(wxCommandEvent& event)\n{\n\tswitch ((Result)event.GetInt())\n\t{\n\tcase Result::NoUpdateAvailable:\n\t\tm_cancelButton->SetLabel(_(\"Exit\"));\n\t\tm_text->SetLabel(_(\"No update available!\"));\n\t\tm_gauge->SetValue(100);\n\t\tbreak;\n\tcase Result::UpdateAvailable:\n\t{\n\t\tif (!m_changelogUrl.empty())\n\t\t{\n\t\t\tm_changelog->SetURL(m_changelogUrl);\n\t\t\tm_changelog->Show();\n\t\t}\n\t\telse\n\t\t\tm_changelog->Hide();\n\n\t\tm_updateButton->Show();\n\n\t\tm_text->SetLabel(_(\"Update available!\"));\n\t\tm_cancelButton->SetLabel(_(\"Exit\"));\n\t\tbreak;\n\t}\n\tcase Result::UpdateDownloaded:\n\t\tm_text->SetLabel(_(\"Extracting update...\"));\n\t\tm_gauge->SetValue(0);\n\t\tbreak;\n\tcase Result::UpdateDownloadError:\n\t\tm_updateButton->Enable();\n\t\tm_text->SetLabel(_(\"Couldn't download the update!\"));\n\t\tbreak;\n\tcase Result::ExtractSuccess:\n\t\tm_text->SetLabel(_(\"Applying update...\"));\n\t\tm_gauge->SetValue(0);\n\t\tm_cancelButton->Disable();\n\t\tbreak;\n\tcase Result::ExtractError:\n\t\tm_updateButton->Enable();\n\t\tm_cancelButton->Enable();\n\t\tm_text->SetLabel(_(\"Extracting failed!\"));\n\t\tbreak;\n\tcase Result::Success:\n\t\tm_cancelButton->Enable();\n\t\tm_updateButton->Hide();\n\n\t\tm_text->SetLabel(_(\"Success\"));\n\t\tm_cancelButton->SetLabel(_(\"Restart\"));\n\t\tm_restartRequired = true;\n\t\tbreak;\n\tdefault:;\n\t}\n}\n\nvoid CemuUpdateWindow::OnGaugeUpdate(wxCommandEvent& event)\n{\n\tconst int total_size = m_gaugeMaxValue > 0 ? m_gaugeMaxValue : 10000000;\n\tm_gauge->SetValue((event.GetInt() * 100) / total_size);\n}\n\nvoid CemuUpdateWindow::OnUpdateButton(const wxCommandEvent& event)\n{\n\tstd::unique_lock lock(m_mutex);\n\tm_order = WorkerOrder::UpdateVersion;\n\n\tm_condition.notify_all();\n\n\tm_updateButton->Disable();\n\n\tm_text->SetLabel(_(\"Downloading update...\"));\n}\n\nvoid CemuUpdateWindow::OnCancelButton(const wxCommandEvent& event)\n{\n\tClose();\n}\n"
  },
  {
    "path": "src/gui/wxgui/CemuUpdateWindow.h",
    "content": "#pragma once\n\n#include <wx/dialog.h>\n#include <wx/stattext.h>\n#include <wx/gauge.h>\n#include <wx/timer.h>\n#include <wx/hyperlink.h>\n#include <wx/checkbox.h>\n\n#include <curl/system.h>\n\nclass CemuUpdateWindow : public wxDialog\n{\npublic:\n\tCemuUpdateWindow(wxWindow* parent);\n\t~CemuUpdateWindow();\n\n\tstatic std::future<bool> IsUpdateAvailableAsync();\n\nprivate:\n\twxStaticText* m_text;\n\twxGauge* m_gauge;\n\twxButton* m_cancelButton, *m_updateButton;\n\twxHyperlinkCtrl* m_changelog;\n\n\tvoid OnUpdateButton(const wxCommandEvent& event);\n\tvoid OnCancelButton(const wxCommandEvent& event);\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid OnResult(wxCommandEvent& event);\n\tvoid OnGaugeUpdate(wxCommandEvent& event);\n\n\tstatic size_t WriteStringCallback(char* ptr, size_t size, size_t nmemb, void* userdata);\n\tstatic bool QueryUpdateInfo(std::string& downloadUrlOut, std::string& changelogUrlOut);\n\tstatic bool CheckVersion();\n\n\tstatic int ProgressCallback(void* clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);\n\tbool DownloadCemuZip(const std::string& url, const fs::path& filename);\n\tbool ExtractUpdate(const fs::path& zipname, const fs::path& targetpath, std::string& cemuFolderName);\n\n\tenum class WorkerOrder\n\t{\n\t\tIdle,\n\t\tExit,\n\t\tCheckVersion,\n\t\tUpdateVersion,\n\t};\n\tenum class Result\n\t{\n\t\tNoUpdateAvailable,\n\t\tUpdateAvailable,\n\t\tUpdateDownloaded,\n\t\tUpdateDownloadError,\n\t\tExtractSuccess,\n\t\tExtractError,\n\t\tSuccess,\n\t\tError\n\t};\n\tstd::mutex m_mutex;\n\tstd::condition_variable m_condition;\n\tWorkerOrder m_order = WorkerOrder::CheckVersion;\n\tvoid WorkerThread();\n\n\tstd::string m_downloadUrl, m_changelogUrl;\n\tint m_gaugeMaxValue = 0;\n\n\tstd::thread m_thread;\n\tfs::path m_restartFile;\n\tbool m_restartRequired = false;\n};\n"
  },
  {
    "path": "src/gui/wxgui/ChecksumTool.cpp",
    "content": "#include \"wxgui/ChecksumTool.h\"\n\n#include \"Cafe/TitleList/GameInfo.h\"\n#include \"wxgui/helpers/wxCustomEvents.h\"\n#include \"util/helpers/helpers.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/wxHelper.h\"\n#include \"Cafe/Filesystem/WUD/wud.h\"\n\n#include <zip.h>\n#include <curl/curl.h>\n\n#include <openssl/evp.h> /* EVP_Digest */\n#include <openssl/sha.h> /* SHA256_DIGEST_LENGTH */\n#include <rapidjson/document.h>\n#include <rapidjson/istreamwrapper.h>\n#include <rapidjson/ostreamwrapper.h>\n#include <rapidjson/prettywriter.h>\n#include <rapidjson/schema.h>\n\n#include <wx/frame.h>\n#include <wx/translation.h>\n#include <wx/xrc/xmlres.h>\n#include <wx/gauge.h>\n#include <wx/gdicmn.h>\n#include <wx/string.h>\n#include <wx/sizer.h>\n#include <wx/statbox.h>\n#include <wx/stattext.h>\n#include <wx/button.h>\n#include <wx/filedlg.h>\n#include <wx/dirdlg.h>\n#include <wx/msgdlg.h>\n\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n\nconst char kSchema[] = R\"(\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"title_id\": {\n      \"type\": \"string\"\n    },\n    \"region\": {\n      \"type\": \"integer\"\n    },\n    \"version\": {\n      \"type\": \"integer\"\n    },\n\t\"wud_hash\": {\n      \"type\": \"string\"\n    },\n    \"files\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"file\": {\n            \"type\": \"string\"\n          },\n          \"hash\": {\n            \"type\": \"string\"\n          }\n        },\n        \"required\": [\n          \"file\",\n          \"hash\"\n        ]\n      }\n    }\n  },\n  \"required\": [\n    \"title_id\",\n    \"region\",\n    \"version\",\n    \"files\"\n  ]\n})\";\n\n\nChecksumTool::ChecksumTool(wxWindow* parent, wxTitleManagerList::TitleEntry& entry)\n\t: wxDialog(parent, wxID_ANY,\n\t\tformatWxString(_(\"Title checksum of {:08x}-{:08x}\"), (uint32) (entry.title_id >> 32), (uint32) (entry.title_id & 0xFFFFFFFF)),\n\t\twxDefaultPosition, wxDefaultSize, wxCAPTION | wxFRAME_TOOL_WINDOW | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX), m_entry(entry)\n{\n\n\tm_info = CafeTitleList::GetTitleInfoByUID(m_entry.location_uid);\n\tif (!m_info.IsValid())\n\t\tthrow std::runtime_error(\"Invalid title\");\n\n\t// only request online update once\n\tstatic bool s_once = false;\n\tif (!s_once)\n\t{\n\t\ts_once = true;\n\t\tm_online_ready = std::async(std::launch::async, &ChecksumTool::LoadOnlineData, this);\n\t}\n\telse\n\t\tm_enable_verify_button = 1;\n\t\t\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\t{\n\t\tauto* box_sizer = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _(\"Verifying integrity of game files...\")), wxVERTICAL);\n\t\tauto* box = box_sizer->GetStaticBox();\n\t\t\n\t\tm_progress = new wxGauge(box, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL | wxGA_SMOOTH);\n\t\tm_progress->SetMinSize({ 400, -1 });\n\t\tm_progress->SetValue(0);\n\t\tbox_sizer->Add(m_progress, 0, wxALL | wxEXPAND, 5);\n\n\t\tm_status = new wxStaticText(box, wxID_ANY, wxEmptyString);\n\t\tm_status->Wrap(-1);\n\t\tbox_sizer->Add(m_status, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);\n\n\t\tsizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\t{\n\t\tauto* box_sizer = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _(\"Control\")), wxHORIZONTAL);\n\t\tauto* box = box_sizer->GetStaticBox();\n\t\t\n\t\tm_verify_online = new wxButton(box, wxID_ANY, _(\"Verify online\"));\n\t\tm_verify_online->SetToolTip(_(\"Verifies the checksum online\"));\n\t\tm_verify_online->Disable();\n\t\tm_verify_online->Bind(wxEVT_BUTTON, &ChecksumTool::OnVerifyOnline, this);\n\t\tm_verify_online->Bind(wxEVT_ENABLE, [this](wxCommandEvent&)\n\t\t{\n\t\t\t++m_enable_verify_button;\n\t\t\tif (m_enable_verify_button >= 2)\n\t\t\t{\n\t\t\t\t// only enable if we have a file for it\n\t\t\t\tconst auto title_id_str = fmt::format(\"{:016x}\", m_json_entry.title_id);\n\t\t\t\tconst auto default_file = fmt::format(\"{}_v{}.json\", title_id_str, m_info.GetAppTitleVersion());\n\n\t\t\t\tconst auto checksum_path = ActiveSettings::GetUserDataPath(\"resources/checksums/{}\", default_file);\n\t\t\t\tif (exists(checksum_path))\n\t\t\t\t\tm_verify_online->Enable();\n\t\t\t}\n\t\t});\n\t\tbox_sizer->Add(m_verify_online, 0, wxALL | wxEXPAND, 5);\n\t\t\n\t\tm_verify_local = new wxButton(box, wxID_ANY, _(\"Verify with local file\"));\n\t\tm_verify_online->SetToolTip(_(\"Verifies the checksum with a local JSON file you can select\"));\n\t\tm_verify_local->Disable();\n\t\tm_verify_local->Bind(wxEVT_BUTTON, &ChecksumTool::OnVerifyLocal, this);\n\t\tbox_sizer->Add(m_verify_local, 0, wxALL | wxEXPAND, 5);\n\t\t\n\t\tm_export_button = new wxButton(box, wxID_ANY, _(\"Export\"));\n\t\tm_verify_online->SetToolTip(_(\"Export the title checksum data to a local JSON file\"));\n\t\tm_export_button->Disable();\n\t\tm_export_button->Bind(wxEVT_BUTTON, &ChecksumTool::OnExportChecksums, this);\n\t\tbox_sizer->Add(m_export_button, 0, wxALL | wxEXPAND, 5);\n\n\t\tsizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\tthis->Bind(wxEVT_SET_GAUGE_VALUE, &ChecksumTool::OnSetGaugevalue, this);\n\n\tm_worker = std::thread(&ChecksumTool::DoWork, this);\n\n\tthis->SetSizerAndFit(sizer);\n\tthis->Centre(wxBOTH);\n}\n\nChecksumTool::~ChecksumTool()\n{\n\tm_running = false;\n\tif (m_worker.joinable())\n\t\tm_worker.join();\n}\n\nstd::size_t WriteCallback(const char* in, std::size_t size, std::size_t num, std::string* out)\n{\n\tconst std::size_t totalBytes(size * num);\n\tout->append(in, totalBytes);\n\treturn totalBytes;\n}\n\nvoid ChecksumTool::LoadOnlineData() const\n{\n\ttry\n\t{\n\t\tbool updated_required = true;\n\n\t\tstd::string latest_commit;\n\n\t\tconst auto checksum_path = ActiveSettings::GetUserDataPath(\"resources/checksums\");\n\t\tif (exists(checksum_path))\n\t\t{\n\t\t\tstd::string current_commit;\n\t\t\t// check for current version\n\t\t\tstd::ifstream file(checksum_path / \"commit.txt\");\n\t\t\tif (file.is_open())\n\t\t\t{\n\t\t\t\tstd::getline(file, current_commit);\n\t\t\t\tfile.close();\n\t\t\t}\n\n\t\t\t// check latest version\n\t\t\t/*\n\t\t\t\thttps://api.github.com/repos/teamcemu/title-checksums/branches/master\n\t\t\t\thttps://api.github.com/repos/teamcemu/title-checksums/commits?per_page=1\n\t\t\t*/\n\t\t\tstd::string data;\n\t\t\tauto* curl = curl_easy_init();\n\t\t\tcurl_easy_setopt(curl, CURLOPT_URL, \"https://api.github.com/repos/teamcemu/title-checksums/commits/master\");\n\t\t\tcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);\n\t\t\tcurl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);\n\t\t\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);\n\t\t\tcurl_easy_setopt(curl, CURLOPT_USERAGENT, BUILD_VERSION_WITH_NAME_STRING);\n\n\t\t\tcurl_easy_perform(curl);\n\n\t\t\tlong http_code = 0;\n\t\t\tcurl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);\n\t\t\tcurl_easy_cleanup(curl);\n\t\t\tif (http_code == 200 && !data.empty())\n\t\t\t{\n\t\t\t\trapidjson::Document doc;\n\t\t\t\tdoc.Parse(data.c_str(), data.size());\n\t\t\t\tif (!doc.HasParseError() && doc.HasMember(\"sha\"))\n\t\t\t\t{\n\t\t\t\t\tlatest_commit = doc[\"sha\"].GetString();\n\t\t\t\t\tif (boost::iequals(current_commit, latest_commit))\n\t\t\t\t\t{\n\t\t\t\t\t\tupdated_required = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// create directory since not available yet\n\t\t\tfs::create_directories(checksum_path);\n\t\t}\n\n\t\tif (updated_required)\n\t\t{\n\t\t\tstd::string data;\n\t\t\tauto* curl = curl_easy_init();\n\t\t\tcurl_easy_setopt(curl, CURLOPT_URL, \"https://github.com/TeamCemu/title-checksums/archive/master.zip\");\n\t\t\tcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);\n\t\t\tcurl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);\n\t\t\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);\n\t\t\tcurl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);\n\t\t\tcurl_easy_setopt(curl, CURLOPT_USERAGENT, BUILD_VERSION_WITH_NAME_STRING);\n\n\t\t\tcurl_easy_perform(curl);\n\n\t\t\tlong http_code = 0;\n\t\t\tcurl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);\n\t\t\tcurl_easy_cleanup(curl);\n\t\t\tif (http_code == 200 && !data.empty())\n\t\t\t{\n\t\t\t\t// init zip source\n\t\t\t\tzip_error_t error;\n\t\t\t\tzip_error_init(&error);\n\t\t\t\tzip_source_t* src;\n\t\t\t\tif ((src = zip_source_buffer_create(data.data(), data.size(), 1, &error)) == nullptr)\n\t\t\t\t{\n\t\t\t\t\tzip_error_fini(&error);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tauto* za = zip_open_from_source(src, ZIP_RDONLY, &error);\n\t\t\t\tif (!za)\n\t\t\t\t{\n\t\t\t\t\twxQueueEvent(m_verify_online, new wxCommandEvent(wxEVT_ENABLE));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst auto numEntries = zip_get_num_entries(za, 0);\n\t\t\t\tfor (sint64 i = 0; i < numEntries; i++)\n\t\t\t\t{\n\t\t\t\t\tzip_stat_t sb = { 0 };\n\t\t\t\t\tif (zip_stat_index(za, i, 0, &sb) != 0)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tif (std::strstr(sb.name, \"../\") != nullptr ||\n\t\t\t\t\t\tstd::strstr(sb.name, \"..\\\\\") != nullptr)\n\t\t\t\t\t\tcontinue; // bad path\n\n\t\t\t\t\tif (boost::equals(sb.name, \"title-checksums-master/\"))\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t// title-checksums-master/\n\t\t\t\t\tconst auto path = checksum_path / &sb.name[sizeof(\"title-checksums-master\")];\n\n\t\t\t\t\tsize_t sbNameLen = strlen(sb.name);\n\t\t\t\t\tif (sbNameLen == 0)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tif (sb.name[sbNameLen - 1] == '/')\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::error_code ec;\n\t\t\t\t\t\tfs::create_directories(path, ec);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (sb.size == 0)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tif (sb.size > (1024 * 1024 * 128))\n\t\t\t\t\t\tcontinue; // skip unusually huge files\n\n\t\t\t\t\tzip_file_t* zipFile = zip_fopen_index(za, i, 0);\n\t\t\t\t\tif (zipFile == nullptr)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tstd::vector<char> buffer(sb.size);\n\t\t\t\t\tif (zip_fread(zipFile, buffer.data(), sb.size) == sb.size)\n\t\t\t\t\t{\n\t\t\t\t\t\tstd::ofstream file(path);\n\t\t\t\t\t\tif (file.is_open())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfile.write(buffer.data(), sb.size);\n\t\t\t\t\t\t\tfile.flush();\n\t\t\t\t\t\t\tfile.close();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tzip_fclose(zipFile);\n\t\t\t\t}\n\n\t\t\t\tstd::ofstream file(checksum_path / \"commit.txt\");\n\t\t\t\tif (file.is_open())\n\t\t\t\t{\n\t\t\t\t\tfile << latest_commit;\n\t\t\t\t\tfile.close();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tcatch(const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"error on updating json checksum data: {}\", ex.what());\n\t}\n\t\n\twxQueueEvent(m_verify_online, new wxCommandEvent(wxEVT_ENABLE));\n}\n\nvoid ChecksumTool::OnSetGaugevalue(wxSetGaugeValue& event)\n{\n\tevent.GetGauge()->SetValue(event.GetValue());\n\tevent.GetTextCtrl()->SetLabelText(event.GetText());\n\n\t// no error\n\tif(event.GetInt() == 0 && event.GetValue() == 100)\n\t{\n\t\tm_export_button->Enable();\n\t\tm_verify_local->Enable();\n\t\twxPostEvent(m_verify_online, wxCommandEvent(wxEVT_ENABLE));\n\t}\n}\n\nvoid ChecksumTool::OnExportChecksums(wxCommandEvent& event)\n{\n\t// TODO: merge if json already exists\n\twxDirDialog dialog(this, _(\"Export checksum entry\"), \"\", wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);\n\tif (dialog.ShowModal() != wxID_OK || dialog.GetPath().IsEmpty())\n\t\treturn;\n\t\n\trapidjson::Document doc;\n\tdoc.SetObject();\n\tauto& a = doc.GetAllocator();\n\t/*\n\t\ttitle_id\n\t\tregion\n\t\tversion\n\t\twud_hash\n\t\tfiles:\n\t\t[\n\t\t\t{file, hash}\n\t\t]\n\t */\n\n\tauto title_id_str = fmt::format(\"{:016x}\", m_json_entry.title_id);\n\tdoc.AddMember(\"title_id\", rapidjson::StringRef(title_id_str.c_str(), title_id_str.size()), a);\n\tdoc.AddMember(\"region\", (int)m_info.GetMetaRegion(), a);\n\tdoc.AddMember(\"version\", m_info.GetAppTitleVersion(), a);\n\tif (!m_json_entry.wud_hash.empty())\n\t\tdoc.AddMember(\"wud_hash\", rapidjson::StringRef(m_json_entry.wud_hash.c_str(), m_json_entry.wud_hash.size()), a);\n\t\n\trapidjson::Value entry_array(rapidjson::kArrayType);\n\n\trapidjson::Value file_array(rapidjson::kArrayType);\n\tfor(const auto& file : m_json_entry.file_hashes)\n\t{\n\t\trapidjson::Value file_entry;\n\t\tfile_entry.SetObject();\n\t\t\n\t\tfile_entry.AddMember(\"file\", rapidjson::StringRef(file.first.c_str(), file.first.size()), a);\n\t\tfile_entry.AddMember(\"hash\", rapidjson::StringRef(file.second.c_str(), file.second.size()), a);\n\n\t\tfile_array.PushBack(file_entry, a);\n\t}\n\n\tdoc.AddMember(\"files\", file_array, a);\n\n\tstd::filesystem::path target_file{ dialog.GetPath().c_str().AsInternal() };\n\ttarget_file /= fmt::format(\"{}_v{}.json\", title_id_str, m_info.GetAppTitleVersion());\n\t\n\tstd::ofstream file(target_file);\n\tif(file.is_open())\n\t{\n\t\trapidjson::OStreamWrapper osw(file);\n\t\trapidjson::PrettyWriter<rapidjson::OStreamWrapper> writer(osw);\n\t\t//rapidjson::GenericSchemaValidator<rapidjson::SchemaDocument, rapidjson::Writer<rapidjson::StringBuffer> > validator(schema, writer);\n\t\tdoc.Accept(writer);\n\t\twxMessageBox(_(\"Export successful\"), wxMessageBoxCaptionStr, wxOK | wxCENTRE, this);\n\t}\n\telse\n\t{\n\t\twxMessageBox(formatWxString(_(\"Can't write to file: {}\"), target_file.string()), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t}\n}\n\nvoid ChecksumTool::VerifyJsonEntry(const rapidjson::Document& doc)\n{\n\trapidjson::Document sdoc;\n\tsdoc.Parse(kSchema, std::size(kSchema));\n\twxASSERT(!sdoc.HasParseError());\n\trapidjson::SchemaDocument schema(sdoc);\n\trapidjson::SchemaValidator validator(schema);\n\tif (!doc.Accept(validator))\n\t{\n\t\t//// validation error:\n\t\t//rapidjson::StringBuffer sb;\n\t\t//validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);\n\t\t//printf(\"Invalid schema: %s\\n\", sb.GetString());\n\t\t//printf(\"Invalid keyword: %s\\n\", validator.GetInvalidSchemaKeyword());\n\t\t//sb.Clear();\n\t\t//validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);\n\t\t//printf(\"Invalid document: %s\\n\", sb.GetString());\n\t\t///*\n\t\t//Invalid schema: #\n\t\t//Invalid keyword: required\n\t\t//Invalid document: #\n\t\t// */\n\n\t\twxMessageBox(_(\"JSON file doesn't satisfy needed schema\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\ttry\n\t{\n\t\tJsonEntry test_entry{};\n\t\ttest_entry.title_id = ConvertString<uint64>(doc[\"title_id\"].GetString(), 16);\n\t\ttest_entry.region = (CafeConsoleRegion)doc[\"region\"].GetInt();\n\t\ttest_entry.version = doc[\"version\"].GetInt();\n\t\tif (doc.HasMember(\"wud_hash\"))\n\t\t\ttest_entry.wud_hash = doc[\"wud_hash\"].GetString();\n\n\t\tfor (const auto& v : doc[\"files\"].GetArray())\n\t\t{\n\t\t\tstd::filesystem::path genericFilePath(v[\"file\"].GetString(), std::filesystem::path::generic_format); // convert path to generic form (forward slashes)\n\t\t\ttest_entry.file_hashes[genericFilePath.generic_string()] = v[\"hash\"].GetString();\n\t\t}\n\n\t\tif (m_json_entry.title_id != test_entry.title_id)\n\t\t{\n\t\t\twxMessageBox(formatWxString(_(\"The file you are comparing with is for a different title.\")), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\treturn;\n\t\t}\n\t\tif (m_json_entry.version != test_entry.version)\n\t\t{\n\t\t\twxMessageBox(formatWxString(_(\"Wrong version: {}\"), test_entry.version), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\treturn;\n\t\t}\n\t\tif (m_json_entry.region != test_entry.region)\n\t\t{\n\t\t\twxMessageBox(formatWxString(_(\"Wrong region: {}\"), test_entry.region), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\treturn;\n\t\t}\n\t\tif (!m_json_entry.wud_hash.empty())\n\t\t{\n\t\t\tif (test_entry.wud_hash.empty())\n\t\t\t{\n\t\t\t\twxMessageBox(_(\"The verification data doesn't include a WUD hash!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_WARNING, this);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif(!boost::iequals(test_entry.wud_hash, m_json_entry.wud_hash))\n\t\t\t{\n\t\t\t\twxMessageBox(formatWxString(_(\"Your game image is invalid!\\n\\nYour hash:\\n{}\\n\\nExpected hash:\\n{}\"), m_json_entry.wud_hash, test_entry.wud_hash), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::map<std::string_view, std::pair<std::string, std::string>> invalid_hashes;\n\t\t\tstd::vector<std::string_view> missing_files;\n\t\t\tconst auto writeMismatchInfoToLog = [this, &missing_files, &invalid_hashes]()\n\t\t\t{\n\t\t\t\twxFileDialog dialog(this, _(\"Select a file to export the errors\"), wxEmptyString, wxEmptyString, \"Error list (*.txt)|*.txt\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\n\t\t\t\tif (dialog.ShowModal() != wxID_OK || dialog.GetPath().IsEmpty())\n\t\t\t\t\treturn;\n\n\t\t\t\tconst std::string path = dialog.GetPath().utf8_string();\n\t\t\t\tstd::ofstream file(path);\n\t\t\t\tif (file.is_open())\n\t\t\t\t{\n\t\t\t\t\tif (!missing_files.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tfile << \"The following files are missing:\\n\";\n\t\t\t\t\t\tfor (const auto& f : missing_files)\n\t\t\t\t\t\t\tfile << \"\\t\" << f << \"\\n\";\n\n\t\t\t\t\t\tfile << \"\\n\";\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!invalid_hashes.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tfile << \"The following files have an invalid hash (name | current hash | expected hash):\\n\";\n\t\t\t\t\t\tfor (const auto& f : invalid_hashes)\n\t\t\t\t\t\t\tfile << \"\\t\" << f.first << \" | \" << f.second.first << \" | \" << f.second.second << \"\\n\";\n\t\t\t\t\t}\n\t\t\t\t\tfile.flush();\n\t\t\t\t\tfile.close();\n\n\t\t\t\t\twxLaunchDefaultBrowser(formatWxString(\"file:{}\", path));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\twxMessageBox(_(\"Can't open file to write!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\t};\n\n\t\t\tfor (const auto& f : test_entry.file_hashes)\n\t\t\t{\n\t\t\t\tconst auto it = m_json_entry.file_hashes.find(f.first);\n\t\t\t\tif (it == m_json_entry.file_hashes.cend())\n\t\t\t\t{\n\t\t\t\t\tmissing_files.emplace_back(f.first);\n\t\t\t\t}\n\t\t\t\telse if (!boost::iequals(f.second, it->second))\n\t\t\t\t{\n\t\t\t\t\tinvalid_hashes[f.first] = std::make_pair(it->second, f.second);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// files are missing but rest is okay\n\t\t\tif ((!missing_files.empty() || !invalid_hashes.empty()) && (missing_files.size() + invalid_hashes.size()) < 30)\n\t\t\t{\n\t\t\t\t// the list of missing + invalid hashes is short enough that we can print it to the message box\n\t\t\t\tstd::stringstream str;\n\t\t\t\tif (missing_files.size() > 0)\n\t\t\t\t{\n\t\t\t\t\tstr << _(\"The following files are missing:\").ToUTF8().data() << \"\\n\";\n\t\t\t\t\tfor (const auto& v : missing_files)\n\t\t\t\t\t\tstr << v << \"\\n\";\n\t\t\t\t\tif(invalid_hashes.size() > 0)\n\t\t\t\t\t\tstr << \"\\n\";\n\t\t\t\t}\n\t\t\t\tif (invalid_hashes.size() > 0)\n\t\t\t\t{\n\t\t\t\t\tstr << _(\"The following files are damaged:\").ToUTF8().data() << \"\\n\";\n\t\t\t\t\tfor (const auto& v : invalid_hashes)\n\t\t\t\t\t\tstr << v.first << \"\\n\";\n\t\t\t\t}\n\n\t\t\t\twxMessageBox(str.str(), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (missing_files.empty() && !invalid_hashes.empty())\n\t\t\t{\n\t\t\t\tconst int result = wxMessageBox(formatWxString(\n\t\t\t\t\t\t_(\"{} files have an invalid hash!\\nDo you want to export a list of them to a file?\"),\n\t\t\t\t\t\tinvalid_hashes.size()), _(\"Error\"), wxYES_NO | wxCENTRE | wxICON_ERROR, this);\n\t\t\t\tif (result == wxYES)\n\t\t\t\t{\n\t\t\t\t\twriteMismatchInfoToLog();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (!missing_files.empty() && !invalid_hashes.empty())\n\t\t\t{\n\t\t\t\tconst int result = wxMessageBox(formatWxString(\n\t\t\t\t\t\t_(\"Multiple issues with your game files have been found!\\nDo you want to export them to a file?\"),\n\t\t\t\t\t\tinvalid_hashes.size()), _(\"Error\"), wxYES_NO | wxCENTRE | wxICON_ERROR, this);\n\t\t\t\tif (result == wxYES)\n\t\t\t\t{\n\t\t\t\t\twriteMismatchInfoToLog();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\t\n\t\t}\n\t\twxMessageBox(_(\"Your game files are valid\"), _(\"Success\"), wxOK | wxCENTRE, this);\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\twxMessageBox(formatWxString(_(\"JSON parse error: {}\"), ex.what()), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t}\n\n}\n\nvoid ChecksumTool::OnVerifyOnline(wxCommandEvent& event)\n{\n\tconst auto title_id_str = fmt::format(\"{:016x}\", m_json_entry.title_id);\n\tconst auto default_file = fmt::format(\"{}_v{}.json\", title_id_str, m_info.GetAppTitleVersion());\n\t\n\tconst auto checksum_path = ActiveSettings::GetUserDataPath(\"resources/checksums/{}\", default_file);\n\tif(!exists(checksum_path))\n\t\treturn;\n\t\n\tstd::ifstream file(checksum_path);\n\tif (!file.is_open())\n\t{\n\t\twxMessageBox(_(\"Can't open file!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\trapidjson::IStreamWrapper str(file);\n\trapidjson::Document d;\n\td.ParseStream(str);\n\tif (d.HasParseError())\n\t{\n\t\twxMessageBox(_(\"Can't parse JSON file!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\tVerifyJsonEntry(d);\n}\n\nvoid ChecksumTool::OnVerifyLocal(wxCommandEvent& event)\n{\n\tconst auto title_id_str = fmt::format(\"{:016x}\", m_json_entry.title_id);\n\tconst auto default_file = fmt::format(\"{}_v{}.json\", title_id_str, m_info.GetAppTitleVersion());\n\twxFileDialog file_dialog(this, _(\"Open checksum entry\"), \"\", default_file.c_str(),\"JSON files (*.json)|*.json\", wxFD_OPEN | wxFD_FILE_MUST_EXIST);\n\tif (file_dialog.ShowModal() != wxID_OK || file_dialog.GetPath().IsEmpty())\n\t\treturn;\n\n\tstd::filesystem::path filename{ file_dialog.GetPath().c_str().AsInternal() };\n\tstd::ifstream file(filename);\n\tif(!file.is_open())\n\t{\n\t\twxMessageBox(_(\"Can't open file!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\t\n\t}\n\t\n\trapidjson::IStreamWrapper str(file);\n\trapidjson::Document d;\n\td.ParseStream(str);\n\tif (d.HasParseError())\n\t{\n\t\twxMessageBox(_(\"Can't parse JSON file!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\tVerifyJsonEntry(d);\n}\n\nstatic void _fscGetAllFiles(std::set<std::string>& allFilesOut, const std::string& fscBasePath, const std::string& relativePath)\n{\n\tsint32 fscStatus;\n\tFSCVirtualFile* fsc = fsc_openDirIterator((fscBasePath + relativePath).c_str(), &fscStatus);\n\tcemu_assert(fsc);\n\tFSCDirEntry dirEntry;\n\twhile (fsc_nextDir(fsc, &dirEntry))\n\t{\n\t\tif (dirEntry.isDirectory)\n\t\t{\n\t\t\t_fscGetAllFiles(allFilesOut, fscBasePath, std::string(relativePath).append(dirEntry.GetPath()).append(\"/\"));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tallFilesOut.emplace(std::string(relativePath).append(dirEntry.GetPath()));\n\t\t}\n\t}\n\tdelete fsc;\n}\n\nvoid ChecksumTool::DoWork()\n{\n\tm_json_entry.title_id = m_info.GetAppTitleId();\n\tm_json_entry.region = m_info.GetMetaRegion();\n\tm_json_entry.version = m_info.GetAppTitleVersion();\n\t\t\n\tstatic_assert(SHA256_DIGEST_LENGTH == 32);\n\n\tstd::array<uint8, SHA256_DIGEST_LENGTH> checksum{};\n\n\tswitch (m_info.GetFormat())\n\t{\n\tcase TitleInfo::TitleDataFormat::WUD:\n\t{\n\t\tconst auto path = m_entry.path.string();\n\t\twxQueueEvent(this, new wxSetGaugeValue(1, m_progress, m_status, formatWxString(_(\"Reading game image: {}\"), path)));\n\n\t\twud_t* wud = wud_open(m_info.GetPath());\n\t\tif (!wud)\n\t\t\tthrow std::runtime_error(\"can't open game image\");\n\n\t\tconst auto wud_size = wud_getWUDSize(wud);\n\t\tstd::vector<uint8> buffer(1024 * 1024 * 8);\n\n\t\tEVP_MD_CTX *sha256 = EVP_MD_CTX_new();\n\t\tEVP_DigestInit(sha256, EVP_sha256());\n\n\t\tuint32 read = 0;\n\t\tsize_t offset = 0;\n\t\tauto size = wud_size;\n\t\tdo\n\t\t{\n\t\t\tif (!m_running.load(std::memory_order_relaxed))\n\t\t\t{\n\t\t\t\twud_close(wud);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tread = wud_readData(wud, buffer.data(), std::min(buffer.size(), (size_t)wud_size - offset), offset);\n\t\t\toffset += read;\n\t\t\tsize -= read;\n\n\t\t\tEVP_DigestUpdate(sha256, buffer.data(), read);\n\n\t\t\twxQueueEvent(this, new wxSetGaugeValue((int)((offset * 90) / wud_size), m_progress, m_status, formatWxString(_(\"Reading game image: {0}/{1} kB\"), offset / 1024, wud_size / 1024)));\n\t\t} while (read != 0 && size > 0);\n\t\twud_close(wud);\n\n\t\twxQueueEvent(this, new wxSetGaugeValue(90, m_progress, m_status, formatWxString(_(\"Generating checksum of game image: {}\"), path)));\n\n\t\tif (!m_running.load(std::memory_order_relaxed))\n\t\t\treturn;\n\n\t\tEVP_DigestFinal_ex(sha256, checksum.data(), NULL);\n\t\tEVP_MD_CTX_free(sha256);\n\n\t\tstd::stringstream str;\n\t\tfor (const auto& b : checksum)\n\t\t{\n\t\t\tstr << fmt::format(\"{:02X}\", b);\n\t\t}\n\n\t\tm_json_entry.wud_hash = str.str();\n\n\t\twxQueueEvent(this, new wxSetGaugeValue(100, m_progress, m_status, formatWxString(_(\"Generated checksum of game image: {}\"), path)));\n\t\tbreak;\n\t}\n\tdefault:\n\t\t// we hash the individual files for all formats except WUD/WUX\n\t\tstd::string temporaryMountPath = TitleInfo::GetUniqueTempMountingPath();\n\t\tm_info.Mount(temporaryMountPath.c_str(), \"\", FSC_PRIORITY_BASE);\n\t\twxQueueEvent(this, new wxSetGaugeValue(1, m_progress, m_status, _(\"Grabbing game files\")));\n\n\t\t// get list of all files\n\t\tstd::set<std::string> files;\n\t\t_fscGetAllFiles(files, temporaryMountPath, \"\");\n\n\t\tconst size_t file_count = files.size();\n\t\tsize_t counter = 0;\n\t\tfor (const auto& filename : files)\n\t\t{\t\t\t\t\n\t\t\tauto fileData = fsc_extractFile((temporaryMountPath + \"/\" + filename).c_str());\n\t\t\tif (!fileData)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"Failed to open {}\", filename);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tSHA256(fileData->data(), fileData->size(), checksum.data());\n\n\t\t\tstd::stringstream str;\n\t\t\tfor (const auto& b : checksum)\n\t\t\t{\n\t\t\t\tstr << fmt::format(\"{:02X}\", b);\n\t\t\t}\n\n\t\t\t// store relative path and hash\n\t\t\tm_json_entry.file_hashes[filename] = str.str();\n\n\t\t\t++counter;\n\t\t\twxQueueEvent(this, new wxSetGaugeValue((int)((counter * 100) / file_count), m_progress, m_status, formatWxString(_(\"Hashing game file: {}/{}\"), counter, file_count)));\n\n\t\t\tif (!m_running.load(std::memory_order_relaxed))\n\t\t\t{\n\t\t\t\tm_info.Unmount(temporaryMountPath.c_str());\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tm_info.Unmount(temporaryMountPath.c_str());\n\n\t\twxQueueEvent(this, new wxSetGaugeValue(100, m_progress, m_status, formatWxString(_(\"Generated checksum of {} game files\"), file_count)));\n\t\tbreak;\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/ChecksumTool.h",
    "content": "#pragma once\n#include <wx/dialog.h>\n#include \"wxgui/components/wxTitleManagerList.h\"\n#include \"Cafe/TitleList/TitleInfo.h\"\n#include <rapidjson/document.h>\n\nclass wxSetGaugeValue;\n\nclass ChecksumTool : public wxDialog\n{\npublic:\n\tChecksumTool(wxWindow* parent, wxTitleManagerList::TitleEntry& entry);\n\t~ChecksumTool();\n\t\nprivate:\n\tstd::future<void> m_online_ready;\n\tvoid LoadOnlineData() const;\n\tvoid VerifyJsonEntry(const rapidjson::Document& doc);\n\n\tvoid OnSetGaugevalue(wxSetGaugeValue& event);\n\tvoid OnExportChecksums(wxCommandEvent& event);\n\tvoid OnVerifyOnline(wxCommandEvent& event);\n\tvoid OnVerifyLocal(wxCommandEvent& event);\n\t\n\tvoid DoWork();\n\tstd::atomic_bool m_running = true;\n\tstd::thread m_worker;\n\t\n\tclass wxGauge* m_progress;\n\tclass wxStaticText* m_status;\n\tclass wxButton *m_verify_online, *m_verify_local, *m_export_button;\n\tint m_enable_verify_button = 0;\n\n\tTitleInfo m_info;\n\twxTitleManagerList::TitleEntry m_entry;\n\twxColour m_default_color;\n\t\n\tstruct JsonEntry\n\t{\n\t\tuint64 title_id;\n\t\tuint32 version;\n\t\tCafeConsoleRegion region;\n\n\t\tstd::string wud_hash;\n\t\tstd::map<std::string, std::string> file_hashes;\n\t};\n\tJsonEntry m_json_entry;\n\tinline static std::mutex s_mutex{};\n\tinline static std::vector<JsonEntry> s_entries{};\n\n};\n"
  },
  {
    "path": "src/gui/wxgui/DownloadGraphicPacksWindow.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxgui/DownloadGraphicPacksWindow.h\"\n\n#include <filesystem>\n#include <curl/curl.h>\n#include <zip.h>\n#include <rapidjson/document.h>\n#include <boost/algorithm/string.hpp>\n\n#include \"config/ActiveSettings.h\"\n#include \"Common/FileStream.h\"\n\n#include \"Cafe/CafeSystem.h\"\n\nstruct DownloadGraphicPacksWindow::curlDownloadFileState_t\n{\n\tstd::vector<uint8> fileData;\n\tdouble progress;\n};\n\nsize_t DownloadGraphicPacksWindow::curlDownloadFile_writeData(void *ptr, size_t size, size_t nmemb, curlDownloadFileState_t* downloadState)\n{\n\tconst size_t writeSize = size * nmemb;\n\tconst size_t currentSize = downloadState->fileData.size();\n\tconst size_t newSize = currentSize + writeSize;\n\tdownloadState->fileData.resize(newSize);\n\tmemcpy(downloadState->fileData.data() + currentSize, ptr, writeSize);\n\treturn writeSize;\n}\n\nint DownloadGraphicPacksWindow::progress_callback(curlDownloadFileState_t* downloadState, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)\n{\n\tif (dltotal > 1.0)\n\t\tdownloadState->progress = dlnow / dltotal;\n\telse\n\t\tdownloadState->progress = 0.0;\n\treturn 0;\n}\n\nbool DownloadGraphicPacksWindow::curlDownloadFile(const char *url, curlDownloadFileState_t* downloadState)\n{\n\tCURL* curl = curl_easy_init();\n\tif (curl == nullptr)\n\t\treturn false;\n\t\n\tdownloadState->progress = 0.0;\n\tcurl_easy_setopt(curl, CURLOPT_URL, url);\n\tcurl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlDownloadFile_writeData);\n\tcurl_easy_setopt(curl, CURLOPT_WRITEDATA, downloadState);\n\tcurl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);\n\tcurl_easy_setopt(curl, CURLOPT_PROGRESSDATA, downloadState);\n\tcurl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);\n\tcurl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, true);\n\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);\n\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);\n\n\tcurl_easy_setopt(curl, CURLOPT_USERAGENT, BUILD_VERSION_WITH_NAME_STRING);\n\tdownloadState->fileData.resize(0);\n\tconst CURLcode res = curl_easy_perform(curl);\n\tcurl_easy_cleanup(curl);\n\treturn res == CURLE_OK;\n}\n\n// returns true if the version matches\nbool checkGraphicPackDownloadedVersion(const char* nameVersion, bool& hasVersionFile)\n{\n\thasVersionFile = false;\n\tconst auto path = ActiveSettings::GetUserDataPath(\"graphicPacks/downloadedGraphicPacks/version.txt\");\n\tstd::unique_ptr<FileStream> file(FileStream::openFile2(path));\n\n\tstd::string versionInFile;\n\tif (file && file->readLine(versionInFile))\n\t{\n\t\treturn boost::iequals(versionInFile, nameVersion);\n\t}\n\treturn false;\n}\n\nvoid createGraphicPackDownloadedVersionFile(const char* nameVersion)\n{\n\tconst auto path = ActiveSettings::GetUserDataPath(\"graphicPacks/downloadedGraphicPacks/version.txt\");\n\tstd::unique_ptr<FileStream> file(FileStream::createFile2(path));\n\tif (file)\n\t\tfile->writeString(nameVersion);\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to write graphic pack version.txt\");\n\t}\n}\n\nvoid deleteDownloadedGraphicPacks()\n{\n\tconst auto path = ActiveSettings::GetUserDataPath(\"graphicPacks/downloadedGraphicPacks\");\n\tstd::error_code er;\n\tif (!fs::exists(path, er))\n\t\treturn;\n\ttry\n\t{\n\t\tfor (auto& p : fs::directory_iterator(path))\n\t\t{\n\t\t\tfs::remove_all(p.path(), er);\n\t\t}\n\t}\n\tcatch (std::filesystem::filesystem_error& e)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error in deleteDownloadedGraphicPacks():\");\n\t\tcemuLog_log(LogType::Force, e.what());\n\t}\n}\n\nvoid DownloadGraphicPacksWindow::UpdateThread()\n{\n\t// get github url\n\tstd::string githubAPIUrl;\n\tcurlDownloadFileState_t tempDownloadState;\n\tstd::string queryUrl(\"https://cemu.info/api2/query_graphicpack_url.php?\");\n\tchar temp[64];\n\tsprintf(temp, \"version=%d.%d.%d\", EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH);\n\tqueryUrl.append(temp);\n\tqueryUrl.append(\"&\");\n\tsprintf(temp, \"t=%u\", (uint32)std::chrono::seconds(std::time(NULL)).count()); // add a dynamic part to the url to bypass overly aggressive caching (like some proxies do)\n\tqueryUrl.append(temp);\n\tif (curlDownloadFile(queryUrl.c_str(), &tempDownloadState) && boost::starts_with((const char*)tempDownloadState.fileData.data(), \"http\"))\n\t{\n\t\t// convert downloaded data to url string\n\t\tgithubAPIUrl.assign(tempDownloadState.fileData.cbegin(), tempDownloadState.fileData.cend());\n\t}\n\telse\n\t{\n\t\t// cemu api request failed, use hardcoded github url\n\t\tcemuLog_log(LogType::Force, \"Graphic pack update request failed or returned invalid URL. Using default repository URL instead\");\n\t\tgithubAPIUrl = \"https://api.github.com/repos/cemu-project/cemu_graphic_packs/releases/latest\";\n\t}\n\t// github API request\n\tif (curlDownloadFile(githubAPIUrl.c_str(), &tempDownloadState) == false)\n\t{\n\t\twxMessageBox( _(\"Error\"), _(L\"Failed to connect to server\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\tm_threadState = ThreadError;\n\t\treturn;\n\t}\n\t// parse json result\n\trapidjson::Document d;\n\td.Parse((const char*)tempDownloadState.fileData.data(), tempDownloadState.fileData.size());\n\tif (d.HasParseError())\n\t{\n\t\tm_threadState = ThreadError;\n\t\treturn;\n\t}\n\tauto& jsonName = d[\"name\"];\n\tif (jsonName.IsString() == false)\n\t{\n\t\tm_threadState = ThreadError;\n\t\treturn;\n\t}\n\tconst char* assetName = jsonName.GetString(); // name includes version\n\tif( d.IsObject() == false)\n\t{\n\t\tm_threadState = ThreadError;\n\t\treturn;\n\t}\n\tauto& jsonAssets = d[\"assets\"];\n\tif (jsonAssets.IsArray() == false || jsonAssets.GetArray().Size() == 0)\n\t{\n\t\tm_threadState = ThreadError;\n\t\treturn;\n\t}\n\tauto& jsonAsset0 = jsonAssets.GetArray()[0];\n\tif (jsonAsset0.IsObject() == false)\n\t{\n\t\tm_threadState = ThreadError;\n\t\treturn;\n\t}\n\tauto& jsonDownloadUrl = jsonAsset0[\"browser_download_url\"];\n\tif (jsonDownloadUrl.IsString() == false)\n\t{\n\t\tm_threadState = ThreadError;\n\t\treturn;\n\t}\n\tconst char* browserDownloadUrl = jsonDownloadUrl.GetString();\n\t// check version\n\tbool hasVersionFile = false;\n\tif (checkGraphicPackDownloadedVersion(assetName, hasVersionFile))\n\t{\n\t\t// already up to date\n\t\twxMessageBox(_(\"No updates available.\"), _(\"Graphic packs\"), wxOK | wxCENTRE, this);\n\t\tm_threadState = ThreadFinished;\n\t\treturn;\n\t}\n\tif (hasVersionFile)\n\t{\n\t\t// if a version file already exists (and graphic packs are installed) ask the user if he really wants to update\n\t\tif (wxMessageBox(_(\"Updated graphic packs are available. Do you want to download and install them?\"), _(\"Graphic packs\"), wxYES_NO, this) != wxYES)\n\t\t{\n\t\t\t// cancel update\n\t\t\tm_threadState = ThreadFinished;\n\t\t\treturn;\n\t\t}\n\t}\n\t// download zip\n\tm_stage = StageDownloading;\n\tif (curlDownloadFile(browserDownloadUrl, m_downloadState.get()) == false)\n\t{\n\t\twxMessageBox(_(\"Error\"), _(L\"Failed to connect to server\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\tm_threadState = ThreadError;\n\t\treturn;\n\t}\n\n\tm_extractionProgress = 0.0;\n\tm_stage = StageExtracting;\n\n\tzip_source_t *src;\n\tzip_t *za;\n\tzip_error_t error;\n\n\t// init zip source\n\tzip_error_init(&error);\n\tif ((src = zip_source_buffer_create(m_downloadState->fileData.data(), m_downloadState->fileData.size(), 1, &error)) == NULL)\n\t{\n\t\tzip_error_fini(&error);\n\t\tm_threadState = ThreadError;\n\t\treturn;\n\t}\n\n\t// open zip from source\n\tif ((za = zip_open_from_source(src, 0, &error)) == NULL)\n\t{\n\t\tzip_source_free(src);\n\t\tzip_error_fini(&error);\n\t\tm_threadState = ThreadError;\n\t\treturn;\n\t}\n\n\tauto path = ActiveSettings::GetUserDataPath(\"graphicPacks/downloadedGraphicPacks\");\n\tstd::error_code er;\n\t//fs::remove_all(path, er); -> Don't delete the whole folder and recreate it immediately afterwards because sometimes it just fails\n\tdeleteDownloadedGraphicPacks();\n\tfs::create_directories(path, er); // make sure downloadedGraphicPacks folder exists\n\n\tsint32 numEntries = zip_get_num_entries(za, 0);\n\tfor (sint32 i = 0; i < numEntries; i++)\n\t{\n\t\tm_extractionProgress = (double)i / (double)numEntries;\n\t\tzip_stat_t sb = { 0 };\n\t\tif (zip_stat_index(za, i, 0, &sb) != 0)\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\n\t\tif(std::strstr(sb.name, \"../\") != nullptr ||\n\t\t\tstd::strstr(sb.name, \"..\\\\\") != nullptr)\n\t\t\tcontinue; // bad path\n\n\t\tpath = ActiveSettings::GetUserDataPath(\"graphicPacks/downloadedGraphicPacks/{}\", sb.name);\n\n\t\tsize_t sbNameLen = strlen(sb.name);\n\t\tif(sbNameLen == 0)\n\t\t\tcontinue;\n\t\tif (sb.name[sbNameLen - 1] == '/')\n\t\t{\n\t\t\tfs::create_directories(path, er);\n\t\t\tcontinue;\n\t\t}\n\t\tif(sb.size == 0)\n\t\t\tcontinue;\n\t\tif (sb.size > (1024 * 1024 * 128))\n\t\t\tcontinue; // skip unusually huge files\n\n\t\tzip_file_t* zipFile = zip_fopen_index(za, i, 0);\n\t\tif (zipFile == nullptr)\n\t\t\tcontinue;\n\n\t\tuint8* fileBuffer = new uint8[sb.size];\n\n\t\tif (zip_fread(zipFile, fileBuffer, sb.size) == sb.size)\n\t\t{\n\t\t\tFileStream* fs = FileStream::createFile2(path);\n\t\t\tif (fs)\n\t\t\t{\n\t\t\t\tfs->writeData(fileBuffer, sb.size);\n\t\t\t\tdelete fs;\n\t\t\t}\n\t\t}\n\n\t\tdelete [] fileBuffer;\n\t\tzip_fclose(zipFile);\n\t}\n\t\n\tzip_error_fini(&error);\n\tcreateGraphicPackDownloadedVersionFile(assetName);\n\tm_threadState = ThreadFinished;\n}\n\nDownloadGraphicPacksWindow::DownloadGraphicPacksWindow(wxWindow* parent)\n\t: wxDialog(parent, wxID_ANY, _(\"Checking version...\"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX),\n\tm_threadState(ThreadRunning), m_stage(StageCheckVersion), m_currentStage(StageCheckVersion)\n{\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tm_processBar = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(500, 20), wxGA_HORIZONTAL);\n\tm_processBar->SetValue(0);\n\tm_processBar->SetRange(100);\n\tsizer->Add(m_processBar, 0, wxALL | wxEXPAND, 5);\n\n\tauto* m_cancelButton = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\tm_cancelButton->Bind(wxEVT_BUTTON, &DownloadGraphicPacksWindow::OnCancelButton, this);\n\tsizer->Add(m_cancelButton, 0, wxALIGN_RIGHT | wxALL, 5);\n\n\tthis->SetSizer(sizer);\n\tthis->Centre(wxBOTH);\n\n\twxWindowBase::Layout();\n\twxWindowBase::Fit();\n\n\tm_timer = new wxTimer(this);\n\tthis->Bind(wxEVT_TIMER, &DownloadGraphicPacksWindow::OnUpdate, this);\n\tthis->Bind(wxEVT_CLOSE_WINDOW, &DownloadGraphicPacksWindow::OnClose, this);\n\tm_timer->Start(250);\n\n\n\tm_downloadState = std::make_unique<curlDownloadFileState_t>();\n}\n\nDownloadGraphicPacksWindow::~DownloadGraphicPacksWindow()\n{\n\tm_timer->Stop();\n\tif (m_thread.joinable())\n\t\tm_thread.join();\n}\n\nconst std::string& DownloadGraphicPacksWindow::GetException() const\n{\n\treturn m_threadException;\n}\n\nint DownloadGraphicPacksWindow::ShowModal()\n{\n\tif(CafeSystem::IsTitleRunning())\n\t{\n\t\twxMessageBox(_(\"Graphic packs cannot be updated while a game is running.\"), _(\"Graphic packs\"), 5, this);\n\t\treturn wxID_CANCEL;\n\t}\n\tm_thread = std::thread(&DownloadGraphicPacksWindow::UpdateThread, this);\n\twxDialog::ShowModal();\n\treturn m_threadState == ThreadCanceled ? wxID_CANCEL : wxID_OK;\n}\n\nvoid DownloadGraphicPacksWindow::OnClose(wxCloseEvent& event)\n{\n\tif (m_threadState == ThreadRunning)\n\t{\n\t\t//wxMessageDialog dialog(this, _(\"Do you really want to cancel the update process?\\n\\nCanceling the process will delete the applied update.\"), _(\"Info\"), wxCENTRE | wxYES_NO);\n\t\t//if (dialog.ShowModal() != wxID_YES)\n\t\t//\treturn;\n\n\t\tm_threadState = ThreadCanceled;\n\t}\n\n\tm_timer->Stop();\n\tif (m_thread.joinable())\n\t\tm_thread.join();\n\n\tevent.Skip();\n}\n\nvoid DownloadGraphicPacksWindow::OnUpdate(const wxTimerEvent& event)\n{\n\tif (m_threadState != ThreadRunning)\n\t{\n\t\tClose();\n\t\treturn;\n\t}\n\tif (m_currentStage != m_stage)\n\t{\n\t\tif (m_stage == StageDownloading)\n\t\t{\n\t\t\tthis->SetTitle(_(\"Downloading graphic packs...\"));\n\t\t}\n\t\telse if (m_stage == StageExtracting)\n\t\t{\n\t\t\tthis->SetTitle(_(\"Extracting...\"));\n\t\t}\n\t\tm_currentStage = m_stage;\n\t}\n\n\tif (m_currentStage == StageDownloading)\n\t{\n\t\tconst sint32 processedSize = (sint32)(m_downloadState->progress * 100.0f);\n\t\tif (m_processBar->GetValue() != processedSize)\n\t\t\tm_processBar->SetValue(processedSize);\n\t}\n\telse if (m_currentStage == StageExtracting)\n\t{\n\t\tconst sint32 processedSize = (sint32)(m_extractionProgress * 100.0f);\n\t\tif (m_processBar->GetValue() != processedSize)\n\t\t\tm_processBar->SetValue(processedSize);\n\t}\n}\n\nvoid DownloadGraphicPacksWindow::OnCancelButton(const wxCommandEvent& event)\n{\n\tClose();\n}\n"
  },
  {
    "path": "src/gui/wxgui/DownloadGraphicPacksWindow.h",
    "content": "#pragma once\n\n#include <atomic>\n#include <curl/system.h>\n#include <thread>\n#include <string>\n#include <memory>\n\n#include <wx/dialog.h>\n#include <wx/timer.h>\n#include <wx/gauge.h>\n\n\nclass DownloadGraphicPacksWindow : public wxDialog\n{\npublic:\n\tDownloadGraphicPacksWindow(wxWindow* parent);\n\t~DownloadGraphicPacksWindow();\n\n\tconst std::string& GetException() const;\n\n\tint ShowModal() override;\n\tvoid OnClose(wxCloseEvent& event);\n\n\tvoid OnUpdate(const wxTimerEvent& event);\n\tvoid OnCancelButton(const wxCommandEvent& event);\n\nprivate:\n\tvoid UpdateThread();\n\n\tenum ThreadState_t\n\t{\n\t\tThreadRunning,\n\t\tThreadCanceled,\n\t\tThreadError,\n\t\tThreadFinished,\n\t};\n\n\tenum DownloadStage_t\n\t{\n\t\tStageCheckVersion,\n\t\tStageDownloading,\n\t\tStageExtracting\n\t};\n\n\tstd::atomic<ThreadState_t> m_threadState;\n\tstd::atomic<DownloadStage_t> m_stage;\n\tstd::atomic<double> m_extractionProgress;\n\tstd::string m_threadException;\n\tstd::thread m_thread;\n\n\tDownloadStage_t m_currentStage;\n\twxGauge* m_processBar;\n\twxTimer* m_timer;\n\n\tstruct curlDownloadFileState_t;\n\tstd::unique_ptr<curlDownloadFileState_t> m_downloadState;\n\n\tstatic size_t curlDownloadFile_writeData(void* ptr, size_t size, size_t nmemb, curlDownloadFileState_t* downloadState);\n\tstatic int progress_callback(curlDownloadFileState_t* downloadState, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);\n\tstatic bool curlDownloadFile(const char* url, curlDownloadFileState_t* downloadState);\n};\n"
  },
  {
    "path": "src/gui/wxgui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.cpp",
    "content": "#include \"EmulatedUSBDeviceFrame.h\"\n\n#include <algorithm>\n\n#include \"config/CemuConfig.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/wxHelper.h\"\n#include \"util/helpers/helpers.h\"\n\n#include \"Cafe/OS/libs/nsyshid/nsyshid.h\"\n#include \"Cafe/OS/libs/nsyshid/Dimensions.h\"\n\n#include \"Common/FileStream.h\"\n\n#include <wx/arrstr.h>\n#include <wx/button.h>\n#include <wx/combobox.h>\n#include <wx/checkbox.h>\n#include <wx/combobox.h>\n#include <wx/filedlg.h>\n#include <wx/log.h>\n#include <wx/msgdlg.h>\n#include <wx/notebook.h>\n#include <wx/panel.h>\n#include <wx/sizer.h>\n#include <wx/statbox.h>\n#include <wx/stattext.h>\n#include <wx/stream.h>\n#include <wx/textctrl.h>\n#include <wx/textentry.h>\n#include <wx/valnum.h>\n#include <wx/wfstream.h>\n\n#include \"resource/embedded/resources.h\"\n\nEmulatedUSBDeviceFrame::EmulatedUSBDeviceFrame(wxWindow* parent)\n\t: wxFrame(parent, wxID_ANY, _(\"Emulated USB Devices\"), wxDefaultPosition,\n\t\t\t  wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL)\n{\n\tSetIcon(wxICON(X_BOX));\n\n\tauto& config = GetConfig();\n\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\tauto* notebook = new wxNotebook(this, wxID_ANY);\n\n\tnotebook->AddPage(AddSkylanderPage(notebook), _(\"Skylanders Portal\"));\n\tnotebook->AddPage(AddInfinityPage(notebook), _(\"Infinity Base\"));\n\tnotebook->AddPage(AddDimensionsPage(notebook), _(\"Dimensions Toypad\"));\n\n\tsizer->Add(notebook, 1, wxEXPAND | wxALL, 2);\n\n\tSetSizerAndFit(sizer);\n\tLayout();\n\tCentre(wxBOTH);\n}\n\nEmulatedUSBDeviceFrame::~EmulatedUSBDeviceFrame() {}\n\nwxPanel* EmulatedUSBDeviceFrame::AddSkylanderPage(wxNotebook* notebook)\n{\n\tauto* panel = new wxPanel(notebook);\n\tauto* panelSizer = new wxBoxSizer(wxVERTICAL);\n\tauto* box = new wxStaticBox(panel, wxID_ANY, _(\"Skylanders Manager\"));\n\tauto* boxSizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\tauto* row = new wxBoxSizer(wxHORIZONTAL);\n\n\tm_emulatePortal =\n\t\tnew wxCheckBox(box, wxID_ANY, _(\"Emulate Skylander Portal\"));\n\tm_emulatePortal->SetValue(\n\t\tGetConfig().emulated_usb_devices.emulate_skylander_portal);\n\tm_emulatePortal->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {\n\t\tGetConfig().emulated_usb_devices.emulate_skylander_portal =\n\t\t\tm_emulatePortal->IsChecked();\n\t\tGetConfigHandle().Save();\n\t});\n\trow->Add(m_emulatePortal, 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(row, 1, wxEXPAND | wxALL, 2);\n\tfor (int i = 0; i < nsyshid::MAX_SKYLANDERS; i++)\n\t{\n\t\tboxSizer->Add(AddSkylanderRow(i, box), 1, wxEXPAND | wxALL, 2);\n\t}\n\tpanelSizer->Add(boxSizer, 1, wxEXPAND | wxALL, 2);\n\tpanel->SetSizerAndFit(panelSizer);\n\n\treturn panel;\n}\n\nwxPanel* EmulatedUSBDeviceFrame::AddInfinityPage(wxNotebook* notebook)\n{\n\tauto* panel = new wxPanel(notebook);\n\tauto* panelSizer = new wxBoxSizer(wxVERTICAL);\n\tauto* box = new wxStaticBox(panel, wxID_ANY, _(\"Infinity Manager\"));\n\tauto* boxSizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\tauto* row = new wxBoxSizer(wxHORIZONTAL);\n\n\tm_emulateBase =\n\t\tnew wxCheckBox(box, wxID_ANY, _(\"Emulate Infinity Base\"));\n\tm_emulateBase->SetValue(\n\t\tGetConfig().emulated_usb_devices.emulate_infinity_base);\n\tm_emulateBase->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {\n\t\tGetConfig().emulated_usb_devices.emulate_infinity_base =\n\t\t\tm_emulateBase->IsChecked();\n\t\tGetConfigHandle().Save();\n\t});\n\trow->Add(m_emulateBase, 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(row, 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(AddInfinityRow(\"Play Set/Power Disc\", 0, box), 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(AddInfinityRow(\"Power Disc Two\", 1, box), 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(AddInfinityRow(\"Power Disc Three\", 2, box), 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(AddInfinityRow(\"Player One\", 3, box), 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(AddInfinityRow(\"Player One Ability One\", 4, box), 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(AddInfinityRow(\"Player One Ability Two\", 5, box), 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(AddInfinityRow(\"Player Two\", 6, box), 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(AddInfinityRow(\"Player Two Ability One\", 7, box), 1, wxEXPAND | wxALL, 2);\n\tboxSizer->Add(AddInfinityRow(\"Player Two Ability Two\", 8, box), 1, wxEXPAND | wxALL, 2);\n\n\tpanelSizer->Add(boxSizer, 1, wxEXPAND | wxALL, 2);\n\tpanel->SetSizerAndFit(panelSizer);\n\n\treturn panel;\n}\n\nwxPanel* EmulatedUSBDeviceFrame::AddDimensionsPage(wxNotebook* notebook)\n{\n\tauto* panel = new wxPanel(notebook);\n\tauto* panel_sizer = new wxBoxSizer(wxVERTICAL);\n\tauto* box = new wxStaticBox(panel, wxID_ANY, _(\"Dimensions Manager\"));\n\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\tauto* row = new wxBoxSizer(wxHORIZONTAL);\n\n\tm_emulateToypad =\n\t\tnew wxCheckBox(box, wxID_ANY, _(\"Emulate Dimensions Toypad\"));\n\tm_emulateToypad->SetValue(\n\t\tGetConfig().emulated_usb_devices.emulate_dimensions_toypad);\n\tm_emulateToypad->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {\n\t\tGetConfig().emulated_usb_devices.emulate_dimensions_toypad =\n\t\t\tm_emulateToypad->IsChecked();\n\t\tGetConfigHandle().Save();\n\t});\n\trow->Add(m_emulateToypad, 1, wxEXPAND | wxALL, 2);\n\tbox_sizer->Add(row, 1, wxEXPAND | wxALL, 2);\n\tauto* top_row = new wxBoxSizer(wxHORIZONTAL);\n\tauto* bottom_row = new wxBoxSizer(wxHORIZONTAL);\n\n\ttop_row->Add(AddDimensionPanel(2, 0, box), 1, wxEXPAND | wxALL, 2);\n\ttop_row->Add(0, 0, 1, wxEXPAND | wxLEFT | wxRIGHT, 2);\n\ttop_row->Add(AddDimensionPanel(1, 1, box), 1, wxEXPAND | wxALL, 2);\n\ttop_row->Add(0, 0, 1, wxEXPAND | wxLEFT | wxRIGHT, 2);\n\ttop_row->Add(AddDimensionPanel(3, 2, box), 1, wxEXPAND | wxALL, 2);\n\n\tbottom_row->Add(AddDimensionPanel(2, 3, box), 1, wxEXPAND | wxALL, 2);\n\tbottom_row->Add(AddDimensionPanel(2, 4, box), 1, wxEXPAND | wxALL, 2);\n\tbottom_row->Add(0, 0, 1, wxEXPAND | wxLEFT | wxRIGHT, 0);\n\tbottom_row->Add(AddDimensionPanel(3, 5, box), 1, wxEXPAND | wxALL, 2);\n\tbottom_row->Add(AddDimensionPanel(3, 6, box), 1, wxEXPAND | wxALL, 2);\n\n\tbox_sizer->Add(top_row, 1, wxEXPAND | wxALL, 2);\n\tbox_sizer->Add(bottom_row, 1, wxEXPAND | wxALL, 2);\n\tpanel_sizer->Add(box_sizer, 1, wxEXPAND | wxALL, 2);\n\tpanel->SetSizerAndFit(panel_sizer);\n\n\treturn panel;\n}\n\nwxBoxSizer* EmulatedUSBDeviceFrame::AddSkylanderRow(uint8 rowNumber, wxStaticBox* box)\n{\n\tauto* row = new wxBoxSizer(wxHORIZONTAL);\n\n\trow->Add(new wxStaticText(box, wxID_ANY,\n\t\t\t\t\t\t\t  fmt::format(\"{} {}\", _(\"Skylander\").ToStdString(),\n\t\t\t\t\t\t\t\t\t\t  rowNumber + 1)),\n\t\t\t 1, wxEXPAND | wxALL, 2);\n\tm_skylanderSlots[rowNumber] =\n\t\tnew wxTextCtrl(box, wxID_ANY, _(\"None\"), wxDefaultPosition, wxDefaultSize,\n\t\t\t\t\t   wxTE_READONLY);\n\tm_skylanderSlots[rowNumber]->SetMinSize(wxSize(150, -1));\n\tm_skylanderSlots[rowNumber]->Disable();\n\trow->Add(m_skylanderSlots[rowNumber], 1, wxEXPAND | wxALL, 2);\n\tauto* loadButton = new wxButton(box, wxID_ANY, _(\"Load\"));\n\tloadButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {\n\t\tLoadSkylander(rowNumber);\n\t});\n\tauto* createButton = new wxButton(box, wxID_ANY, _(\"Create\"));\n\tcreateButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {\n\t\tCreateSkylander(rowNumber);\n\t});\n\tauto* clearButton = new wxButton(box, wxID_ANY, _(\"Clear\"));\n\tclearButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {\n\t\tClearSkylander(rowNumber);\n\t});\n\trow->Add(loadButton, 1, wxEXPAND | wxALL, 2);\n\trow->Add(createButton, 1, wxEXPAND | wxALL, 2);\n\trow->Add(clearButton, 1, wxEXPAND | wxALL, 2);\n\n\treturn row;\n}\n\nwxBoxSizer* EmulatedUSBDeviceFrame::AddInfinityRow(wxString name, uint8 rowNumber, wxStaticBox* box)\n{\n\tauto* row = new wxBoxSizer(wxHORIZONTAL);\n\n\trow->Add(new wxStaticText(box, wxID_ANY, name), 1, wxEXPAND | wxALL, 2);\n\tm_infinitySlots[rowNumber] =\n\t\tnew wxTextCtrl(box, wxID_ANY, _(\"None\"), wxDefaultPosition, wxDefaultSize,\n\t\t\t\t\t   wxTE_READONLY);\n\tm_infinitySlots[rowNumber]->SetMinSize(wxSize(150, -1));\n\tm_infinitySlots[rowNumber]->Disable();\n\trow->Add(m_infinitySlots[rowNumber], 1, wxALL | wxEXPAND, 5);\n\tauto* loadButton = new wxButton(box, wxID_ANY, _(\"Load\"));\n\tloadButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {\n\t\tLoadFigure(rowNumber);\n\t});\n\tauto* createButton = new wxButton(box, wxID_ANY, _(\"Create\"));\n\tcreateButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {\n\t\tCreateFigure(rowNumber);\n\t});\n\tauto* clearButton = new wxButton(box, wxID_ANY, _(\"Clear\"));\n\tclearButton->Bind(wxEVT_BUTTON, [rowNumber, this](wxCommandEvent&) {\n\t\tClearFigure(rowNumber);\n\t});\n\trow->Add(loadButton, 1, wxEXPAND | wxALL, 2);\n\trow->Add(createButton, 1, wxEXPAND | wxALL, 2);\n\trow->Add(clearButton, 1, wxEXPAND | wxALL, 2);\n\n\treturn row;\n}\n\nwxBoxSizer* EmulatedUSBDeviceFrame::AddDimensionPanel(uint8 pad, uint8 index, wxStaticBox* box)\n{\n\tauto* panel = new wxBoxSizer(wxVERTICAL);\n\n\tauto* combo_row = new wxBoxSizer(wxHORIZONTAL);\n\tm_dimensionSlots[index] = new wxTextCtrl(box, wxID_ANY, _(\"None\"), wxDefaultPosition, wxDefaultSize,\n\t\t\t\t\t\t\t\t\t\t\t wxTE_READONLY);\n\tcombo_row->Add(m_dimensionSlots[index], 1, wxEXPAND | wxALL, 2);\n\tauto* move_button = new wxButton(box, wxID_ANY, _(\"Move\"));\n\tmove_button->Bind(wxEVT_BUTTON, [pad, index, this](wxCommandEvent&) {\n\t\tMoveMinifig(pad, index);\n\t});\n\n\tcombo_row->Add(move_button, 1, wxEXPAND | wxALL, 2);\n\n\tauto* button_row = new wxBoxSizer(wxHORIZONTAL);\n\tauto* load_button = new wxButton(box, wxID_ANY, _(\"Load\"));\n\tload_button->Bind(wxEVT_BUTTON, [pad, index, this](wxCommandEvent&) {\n\t\tLoadMinifig(pad, index);\n\t});\n\tauto* clear_button = new wxButton(box, wxID_ANY, _(\"Clear\"));\n\tclear_button->Bind(wxEVT_BUTTON, [pad, index, this](wxCommandEvent&) {\n\t\tClearMinifig(pad, index);\n\t});\n\tauto* create_button = new wxButton(box, wxID_ANY, _(\"Create\"));\n\tcreate_button->Bind(wxEVT_BUTTON, [pad, index, this](wxCommandEvent&) {\n\t\tCreateMinifig(pad, index);\n\t});\n\tbutton_row->Add(clear_button, 1, wxEXPAND | wxALL, 2);\n\tbutton_row->Add(create_button, 1, wxEXPAND | wxALL, 2);\n\tbutton_row->Add(load_button, 1, wxEXPAND | wxALL, 2);\n\n\tpanel->Add(combo_row, 1, wxEXPAND | wxALL, 2);\n\tpanel->Add(button_row, 1, wxEXPAND | wxALL, 2);\n\n\treturn panel;\n}\n\nvoid EmulatedUSBDeviceFrame::LoadSkylander(uint8 slot)\n{\n\twxFileDialog openFileDialog(this, _(\"Open Skylander dump\"), \"\", \"\",\n\t\t\t\t\t\t\t\t\"Skylander files (*.sky;*.bin;*.dump;*.dmp)|*.sky;*.bin;*.dump;*.dmp\",\n\t\t\t\t\t\t\t\twxFD_OPEN | wxFD_FILE_MUST_EXIST);\n\tif (openFileDialog.ShowModal() != wxID_OK || openFileDialog.GetPath().empty())\n\t\treturn;\n\n\tLoadSkylanderPath(slot, openFileDialog.GetPath());\n}\n\nvoid EmulatedUSBDeviceFrame::LoadSkylanderPath(uint8 slot, wxString path)\n{\n\tstd::unique_ptr<FileStream> skyFile(FileStream::openFile2(_utf8ToPath(path.utf8_string()), true));\n\tif (!skyFile)\n\t{\n\t\twxMessageDialog open_error(this, \"Error Opening File: \" + path);\n\t\topen_error.ShowModal();\n\t\treturn;\n\t}\n\n\tstd::array<uint8, nsyshid::SKY_FIGURE_SIZE> fileData;\n\tif (skyFile->readData(fileData.data(), fileData.size()) != fileData.size())\n\t{\n\t\twxMessageDialog open_error(this, \"Failed to read file! File was too small\");\n\t\topen_error.ShowModal();\n\t\treturn;\n\t}\n\tClearSkylander(slot);\n\n\tuint16 skyId = uint16(fileData[0x11]) << 8 | uint16(fileData[0x10]);\n\tuint16 skyVar = uint16(fileData[0x1D]) << 8 | uint16(fileData[0x1C]);\n\n\tuint8 portalSlot = nsyshid::g_skyportal.LoadSkylander(fileData.data(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  std::move(skyFile));\n\tm_skySlots[slot] = std::tuple(portalSlot, skyId, skyVar);\n\tUpdateSkylanderEdits();\n}\n\nvoid EmulatedUSBDeviceFrame::CreateSkylander(uint8 slot)\n{\n\tCreateSkylanderDialog create_dlg(this, slot);\n\tcreate_dlg.ShowModal();\n\tif (create_dlg.GetReturnCode() == 1)\n\t{\n\t\tLoadSkylanderPath(slot, create_dlg.GetFilePath());\n\t}\n}\n\nvoid EmulatedUSBDeviceFrame::ClearSkylander(uint8 slot)\n{\n\tif (auto slotInfos = m_skySlots[slot])\n\t{\n\t\tauto [curSlot, id, var] = slotInfos.value();\n\t\tnsyshid::g_skyportal.RemoveSkylander(curSlot);\n\t\tm_skySlots[slot] = {};\n\t\tUpdateSkylanderEdits();\n\t}\n}\n\nCreateSkylanderDialog::CreateSkylanderDialog(wxWindow* parent, uint8 slot)\n\t: wxDialog(parent, wxID_ANY, _(\"Skylander Figure Creator\"), wxDefaultPosition, wxSize(500, 150))\n{\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tauto* comboRow = new wxBoxSizer(wxHORIZONTAL);\n\n\tauto* comboBox = new wxComboBox(this, wxID_ANY);\n\tcomboBox->Append(\"---Select---\", reinterpret_cast<void*>(0xFFFFFFFF));\n\twxArrayString filterlist;\n\tfor (const auto& it : nsyshid::g_skyportal.GetListSkylanders())\n\t{\n\t\tconst uint32 variant = uint32(uint32(it.first.first) << 16) | uint32(it.first.second);\n\t\tcomboBox->Append(it.second, reinterpret_cast<void*>(variant));\n\t\tfilterlist.Add(it.second);\n\t}\n\tcomboBox->SetSelection(0);\n\tbool enabled = comboBox->AutoComplete(filterlist);\n\tcomboRow->Add(comboBox, 1, wxEXPAND | wxALL, 2);\n\n\tauto* idVarRow = new wxBoxSizer(wxHORIZONTAL);\n\n\twxIntegerValidator<uint32> validator;\n\n\tauto* labelId = new wxStaticText(this, wxID_ANY, \"ID:\");\n\tauto* labelVar = new wxStaticText(this, wxID_ANY, \"Variant:\");\n\tauto* editId = new wxTextCtrl(this, wxID_ANY, _(\"0\"), wxDefaultPosition, wxDefaultSize, 0, validator);\n\tauto* editVar = new wxTextCtrl(this, wxID_ANY, _(\"0\"), wxDefaultPosition, wxDefaultSize, 0, validator);\n\n\tidVarRow->Add(labelId, 1, wxALL, 5);\n\tidVarRow->Add(editId, 1, wxALL, 5);\n\tidVarRow->Add(labelVar, 1, wxALL, 5);\n\tidVarRow->Add(editVar, 1, wxALL, 5);\n\n\tauto* buttonRow = new wxBoxSizer(wxHORIZONTAL);\n\n\tauto* createButton = new wxButton(this, wxID_ANY, _(\"Create\"));\n\tcreateButton->Bind(wxEVT_BUTTON, [editId, editVar, this](wxCommandEvent&) {\n\t\tlong longSkyId;\n\t\tif (!editId->GetValue().ToLong(&longSkyId) || longSkyId > 0xFFFF)\n\t\t{\n\t\t\twxMessageDialog idError(this, \"Error Converting ID!\", \"ID Entered is Invalid\");\n\t\t\tidError.ShowModal();\n\t\t\treturn;\n\t\t}\n\t\tlong longSkyVar;\n\t\tif (!editVar->GetValue().ToLong(&longSkyVar) || longSkyVar > 0xFFFF)\n\t\t{\n\t\t\twxMessageDialog idError(this, \"Error Converting Variant!\", \"Variant Entered is Invalid\");\n\t\t\tidError.ShowModal();\n\t\t\treturn;\n\t\t}\n\t\tuint16 skyId = longSkyId & 0xFFFF;\n\t\tuint16 skyVar = longSkyVar & 0xFFFF;\n\t\twxString predefName = nsyshid::g_skyportal.FindSkylander(skyId, skyVar) + \".sky\";\n\t\twxFileDialog\n\t\t\tsaveFileDialog(this, _(\"Create Skylander file\"), \"\", predefName,\n\t\t\t\t\t\t   \"SKY files (*.sky)|*.sky\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\n\n\t\tif (saveFileDialog.ShowModal() == wxID_CANCEL)\n\t\t\treturn;\n\n\t\tm_filePath = saveFileDialog.GetPath();\n\n\t\tif (!nsyshid::g_skyportal.CreateSkylander(_utf8ToPath(m_filePath.utf8_string()), skyId, skyVar))\n\t\t{\n\t\t\twxMessageDialog errorMessage(this, \"Failed to create file\");\n\t\t\terrorMessage.ShowModal();\n\t\t\tthis->EndModal(0);\n\t\t\treturn;\n\t\t}\n\n\t\tthis->EndModal(1);\n\t});\n\tauto* cancelButton = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\tcancelButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {\n\t\tthis->EndModal(0);\n\t});\n\n\tcomboBox->Bind(wxEVT_COMBOBOX, [comboBox, editId, editVar, this](wxCommandEvent&) {\n\t\tconst uint64 sky_info = reinterpret_cast<uint64>(comboBox->GetClientData(comboBox->GetSelection()));\n\t\tif (sky_info != 0xFFFFFFFF)\n\t\t{\n\t\t\tconst uint16 skyId = sky_info >> 16;\n\t\t\tconst uint16 skyVar = sky_info & 0xFFFF;\n\n\t\t\teditId->SetValue(wxString::Format(wxT(\"%i\"), skyId));\n\t\t\teditVar->SetValue(wxString::Format(wxT(\"%i\"), skyVar));\n\t\t}\n\t});\n\n\tbuttonRow->Add(createButton, 1, wxALL, 5);\n\tbuttonRow->Add(cancelButton, 1, wxALL, 5);\n\n\tsizer->Add(comboRow, 1, wxEXPAND | wxALL, 2);\n\tsizer->Add(idVarRow, 1, wxEXPAND | wxALL, 2);\n\tsizer->Add(buttonRow, 1, wxEXPAND | wxALL, 2);\n\n\tthis->SetSizer(sizer);\n\tthis->Centre(wxBOTH);\n}\n\nwxString CreateSkylanderDialog::GetFilePath() const\n{\n\treturn m_filePath;\n}\n\nvoid EmulatedUSBDeviceFrame::UpdateSkylanderEdits()\n{\n\tfor (auto i = 0; i < nsyshid::MAX_SKYLANDERS; i++)\n\t{\n\t\tstd::string displayString;\n\t\tif (auto sd = m_skySlots[i])\n\t\t{\n\t\t\tauto [portalSlot, skyId, skyVar] = sd.value();\n\t\t\tdisplayString = nsyshid::g_skyportal.FindSkylander(skyId, skyVar);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdisplayString = \"None\";\n\t\t}\n\n\t\tm_skylanderSlots[i]->ChangeValue(displayString);\n\t}\n}\n\nvoid EmulatedUSBDeviceFrame::LoadFigure(uint8 slot)\n{\n\twxFileDialog openFileDialog(this, _(\"Open Infinity Figure dump\"), \"\", \"\",\n\t\t\t\t\t\t\t\t\"BIN files (*.bin)|*.bin\",\n\t\t\t\t\t\t\t\twxFD_OPEN | wxFD_FILE_MUST_EXIST);\n\tif (openFileDialog.ShowModal() != wxID_OK || openFileDialog.GetPath().empty())\n\t{\n\t\twxMessageDialog errorMessage(this, \"File Okay Error\");\n\t\terrorMessage.ShowModal();\n\t\treturn;\n\t}\n\n\tLoadFigurePath(slot, openFileDialog.GetPath());\n}\n\nvoid EmulatedUSBDeviceFrame::LoadFigurePath(uint8 slot, wxString path)\n{\n\tstd::unique_ptr<FileStream> infFile(FileStream::openFile2(_utf8ToPath(path.utf8_string()), true));\n\tif (!infFile)\n\t{\n\t\twxMessageDialog errorMessage(this, \"File Open Error\");\n\t\terrorMessage.ShowModal();\n\t\treturn;\n\t}\n\n\tstd::array<uint8, nsyshid::INF_FIGURE_SIZE> fileData;\n\tif (infFile->readData(fileData.data(), fileData.size()) != fileData.size())\n\t{\n\t\twxMessageDialog open_error(this, \"Failed to read file! File was too small\");\n\t\topen_error.ShowModal();\n\t\treturn;\n\t}\n\tClearFigure(slot);\n\n\tuint32 number = nsyshid::g_infinitybase.LoadFigure(fileData, std::move(infFile), slot);\n\tm_infinitySlots[slot]->ChangeValue(nsyshid::g_infinitybase.FindFigure(number).second);\n}\n\nvoid EmulatedUSBDeviceFrame::CreateFigure(uint8 slot)\n{\n\tcemuLog_log(LogType::Force, \"Create Figure: {}\", slot);\n\tCreateInfinityFigureDialog create_dlg(this, slot);\n\tcreate_dlg.ShowModal();\n\tif (create_dlg.GetReturnCode() == 1)\n\t{\n\t\tLoadFigurePath(slot, create_dlg.GetFilePath());\n\t}\n}\n\nvoid EmulatedUSBDeviceFrame::ClearFigure(uint8 slot)\n{\n\tm_infinitySlots[slot]->ChangeValue(\"None\");\n\tnsyshid::g_infinitybase.RemoveFigure(slot);\n}\n\nCreateInfinityFigureDialog::CreateInfinityFigureDialog(wxWindow* parent, uint8 slot)\n\t: wxDialog(parent, wxID_ANY, _(\"Infinity Figure Creator\"), wxDefaultPosition, wxSize(500, 150))\n{\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tauto* comboRow = new wxBoxSizer(wxHORIZONTAL);\n\n\tauto* comboBox = new wxComboBox(this, wxID_ANY);\n\tcomboBox->Append(\"---Select---\", reinterpret_cast<void*>(0xFFFFFF));\n\twxArrayString filterlist;\n\tfor (const auto& it : nsyshid::g_infinitybase.GetFigureList())\n\t{\n\t\tconst uint32 figure = it.first;\n\t\tif ((slot == 0 &&\n\t\t\t ((figure > 0x1E8480 && figure < 0x2DC6BF) || (figure > 0x3D0900 && figure < 0x4C4B3F))) ||\n\t\t\t((slot == 1 || slot == 2) && (figure > 0x3D0900 && figure < 0x4C4B3F)) ||\n\t\t\t((slot == 3 || slot == 6) && figure < 0x1E847F) ||\n\t\t\t((slot == 4 || slot == 5 || slot == 7 || slot == 8) &&\n\t\t\t (figure > 0x2DC6C0 && figure < 0x3D08FF)))\n\t\t{\n\t\t\tcomboBox->Append(it.second.second, reinterpret_cast<void*>(figure));\n\t\t\tfilterlist.Add(it.second.second);\n\t\t}\n\t}\n\tcomboBox->SetSelection(0);\n\tbool enabled = comboBox->AutoComplete(filterlist);\n\tcomboRow->Add(comboBox, 1, wxEXPAND | wxALL, 2);\n\n\tauto* figNumRow = new wxBoxSizer(wxHORIZONTAL);\n\n\twxIntegerValidator<uint32> validator;\n\n\tauto* labelFigNum = new wxStaticText(this, wxID_ANY, \"Figure Number:\");\n\tauto* editFigNum = new wxTextCtrl(this, wxID_ANY, _(\"0\"), wxDefaultPosition, wxDefaultSize, 0, validator);\n\n\tfigNumRow->Add(labelFigNum, 1, wxALL, 5);\n\tfigNumRow->Add(editFigNum, 1, wxALL, 5);\n\n\tauto* buttonRow = new wxBoxSizer(wxHORIZONTAL);\n\n\tauto* createButton = new wxButton(this, wxID_ANY, _(\"Create\"));\n\tcreateButton->Bind(wxEVT_BUTTON, [editFigNum, this](wxCommandEvent&) {\n\t\tlong longFigNum;\n\t\tif (!editFigNum->GetValue().ToLong(&longFigNum))\n\t\t{\n\t\t\twxMessageDialog idError(this, \"Error Converting Figure Number!\", \"Number Entered is Invalid\");\n\t\t\tidError.ShowModal();\n\t\t\tthis->EndModal(0);\n\t\t}\n\t\tuint32 figNum = longFigNum & 0xFFFFFFFF;\n\t\tauto figure = nsyshid::g_infinitybase.FindFigure(figNum);\n\t\twxString predefName = figure.second + \".bin\";\n\t\twxFileDialog\n\t\t\tsaveFileDialog(this, _(\"Create Infinity Figure file\"), \"\", predefName,\n\t\t\t\t\t\t   \"BIN files (*.bin)|*.bin\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\n\n\t\tif (saveFileDialog.ShowModal() == wxID_CANCEL)\n\t\t\tthis->EndModal(0);\n\n\t\tm_filePath = saveFileDialog.GetPath();\n\n\t\tnsyshid::g_infinitybase.CreateFigure(_utf8ToPath(m_filePath.utf8_string()), figNum, figure.first);\n\n\t\tthis->EndModal(1);\n\t});\n\tauto* cancelButton = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\tcancelButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {\n\t\tthis->EndModal(0);\n\t});\n\n\tcomboBox->Bind(wxEVT_COMBOBOX, [comboBox, editFigNum, this](wxCommandEvent&) {\n\t\tconst uint64 fig_info = reinterpret_cast<uint64>(comboBox->GetClientData(comboBox->GetSelection()));\n\t\tif (fig_info != 0xFFFFFF)\n\t\t{\n\t\t\tconst uint32 figNum = fig_info & 0xFFFFFFFF;\n\n\t\t\teditFigNum->SetValue(wxString::Format(wxT(\"%i\"), figNum));\n\t\t}\n\t});\n\n\tbuttonRow->Add(createButton, 1, wxALL, 5);\n\tbuttonRow->Add(cancelButton, 1, wxALL, 5);\n\n\tsizer->Add(comboRow, 1, wxEXPAND | wxALL, 2);\n\tsizer->Add(figNumRow, 1, wxEXPAND | wxALL, 2);\n\tsizer->Add(buttonRow, 1, wxEXPAND | wxALL, 2);\n\n\tthis->SetSizer(sizer);\n\tthis->Centre(wxBOTH);\n}\n\nwxString CreateInfinityFigureDialog::GetFilePath() const\n{\n\treturn m_filePath;\n}\n\nvoid EmulatedUSBDeviceFrame::LoadMinifig(uint8 pad, uint8 index)\n{\n\twxFileDialog openFileDialog(this, _(\"Load Dimensions Figure\"), \"\", \"\",\n\t\t\t\t\t\t\t\t\"Dimensions files (*.bin)|*.bin\",\n\t\t\t\t\t\t\t\twxFD_OPEN | wxFD_FILE_MUST_EXIST);\n\tif (openFileDialog.ShowModal() != wxID_OK || openFileDialog.GetPath().empty())\n\t\treturn;\n\n\tLoadMinifigPath(openFileDialog.GetPath(), pad, index);\n}\n\nvoid EmulatedUSBDeviceFrame::LoadMinifigPath(wxString path_name, uint8 pad, uint8 index)\n{\n\tstd::unique_ptr<FileStream> dim_file(FileStream::openFile2(_utf8ToPath(path_name.utf8_string()), true));\n\tif (!dim_file)\n\t{\n\t\twxMessageDialog errorMessage(this, \"Failed to open minifig file\");\n\t\terrorMessage.ShowModal();\n\t\treturn;\n\t}\n\n\tstd::array<uint8, 0x2D * 0x04> file_data;\n\n\tif (dim_file->readData(file_data.data(), file_data.size()) != file_data.size())\n\t{\n\t\twxMessageDialog errorMessage(this, \"Failed to read minifig file data\");\n\t\terrorMessage.ShowModal();\n\t\treturn;\n\t}\n\n\tClearMinifig(pad, index);\n\n\tuint32 id = nsyshid::g_dimensionstoypad.LoadFigure(file_data, std::move(dim_file), pad, index);\n\tm_dimensionSlots[index]->ChangeValue(nsyshid::g_dimensionstoypad.FindFigure(id));\n\tm_dimSlots[index] = id;\n}\n\nvoid EmulatedUSBDeviceFrame::ClearMinifig(uint8 pad, uint8 index)\n{\n\tnsyshid::g_dimensionstoypad.RemoveFigure(pad, index, true);\n\tm_dimensionSlots[index]->ChangeValue(\"None\");\n\tm_dimSlots[index] = std::nullopt;\n}\n\nvoid EmulatedUSBDeviceFrame::CreateMinifig(uint8 pad, uint8 index)\n{\n\tCreateDimensionFigureDialog create_dlg(this);\n\tcreate_dlg.ShowModal();\n\tif (create_dlg.GetReturnCode() == 1)\n\t{\n\t\tLoadMinifigPath(create_dlg.GetFilePath(), pad, index);\n\t}\n}\n\nvoid EmulatedUSBDeviceFrame::MoveMinifig(uint8 pad, uint8 index)\n{\n\tif (!m_dimSlots[index])\n\t\treturn;\n\n\tMoveDimensionFigureDialog move_dlg(this, index);\n\tnsyshid::g_dimensionstoypad.TempRemove(index);\n\tmove_dlg.ShowModal();\n\tif (move_dlg.GetReturnCode() == 1)\n\t{\n\t\tnsyshid::g_dimensionstoypad.MoveFigure(move_dlg.GetNewPad(), move_dlg.GetNewIndex(), pad, index);\n\t\tif (index != move_dlg.GetNewIndex())\n\t\t{\n\t\t\tm_dimSlots[move_dlg.GetNewIndex()] = m_dimSlots[index];\n\t\t\tm_dimensionSlots[move_dlg.GetNewIndex()]->ChangeValue(m_dimensionSlots[index]->GetValue());\n\t\t\tm_dimSlots[index] = std::nullopt;\n\t\t\tm_dimensionSlots[index]->ChangeValue(\"None\");\n\t\t}\n\t}\n\telse\n\t{\n\t\tnsyshid::g_dimensionstoypad.CancelRemove(index);\n\t}\n}\n\nCreateDimensionFigureDialog::CreateDimensionFigureDialog(wxWindow* parent)\n\t: wxDialog(parent, wxID_ANY, _(\"Dimensions Figure Creator\"), wxDefaultPosition, wxSize(500, 200))\n{\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tauto* comboRow = new wxBoxSizer(wxHORIZONTAL);\n\n\tauto* comboBox = new wxComboBox(this, wxID_ANY);\n\tcomboBox->Append(\"---Select---\", reinterpret_cast<void*>(0xFFFFFFFF));\n\twxArrayString filterlist;\n\tfor (const auto& it : nsyshid::g_dimensionstoypad.GetListMinifigs())\n\t{\n\t\tconst uint32 figure = it.first;\n\t\tcomboBox->Append(it.second, reinterpret_cast<void*>(figure));\n\t\tfilterlist.Add(it.second);\n\t}\n\tcomboBox->SetSelection(0);\n\tbool enabled = comboBox->AutoComplete(filterlist);\n\tcomboRow->Add(comboBox, 1, wxEXPAND | wxALL, 2);\n\n\tauto* figNumRow = new wxBoxSizer(wxHORIZONTAL);\n\n\twxIntegerValidator<uint32> validator;\n\n\tauto* labelFigNum = new wxStaticText(this, wxID_ANY, \"Figure Number:\");\n\tauto* editFigNum = new wxTextCtrl(this, wxID_ANY, _(\"0\"), wxDefaultPosition, wxDefaultSize, 0, validator);\n\n\tfigNumRow->Add(labelFigNum, 1, wxALL, 5);\n\tfigNumRow->Add(editFigNum, 1, wxALL, 5);\n\n\tauto* buttonRow = new wxBoxSizer(wxHORIZONTAL);\n\n\tauto* createButton = new wxButton(this, wxID_ANY, _(\"Create\"));\n\tcreateButton->Bind(wxEVT_BUTTON, [editFigNum, this](wxCommandEvent&) {\n\t\tlong longFigNum;\n\t\tif (!editFigNum->GetValue().ToLong(&longFigNum) || longFigNum > 0xFFFF)\n\t\t{\n\t\t\twxMessageDialog idError(this, \"Error Converting Figure Number!\", \"Number Entered is Invalid\");\n\t\t\tidError.ShowModal();\n\t\t\tthis->EndModal(0);\n\t\t}\n\t\tuint16 figNum = longFigNum & 0xFFFF;\n\t\tauto figure = nsyshid::g_dimensionstoypad.FindFigure(figNum);\n\t\twxString predefName = figure + \".bin\";\n\t\twxFileDialog\n\t\t\tsaveFileDialog(this, _(\"Create Dimensions Figure file\"), \"\", predefName,\n\t\t\t\t\t\t   \"BIN files (*.bin)|*.bin\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\n\n\t\tif (saveFileDialog.ShowModal() == wxID_CANCEL)\n\t\t\tthis->EndModal(0);\n\n\t\tm_filePath = saveFileDialog.GetPath();\n\n\t\tnsyshid::g_dimensionstoypad.CreateFigure(_utf8ToPath(m_filePath.utf8_string()), figNum);\n\n\t\tthis->EndModal(1);\n\t});\n\tauto* cancelButton = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\tcancelButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {\n\t\tthis->EndModal(0);\n\t});\n\n\tcomboBox->Bind(wxEVT_COMBOBOX, [comboBox, editFigNum, this](wxCommandEvent&) {\n\t\tconst uint64 fig_info = reinterpret_cast<uint64>(comboBox->GetClientData(comboBox->GetSelection()));\n\t\tif (fig_info != 0xFFFF)\n\t\t{\n\t\t\tconst uint16 figNum = fig_info & 0xFFFF;\n\n\t\t\teditFigNum->SetValue(wxString::Format(wxT(\"%i\"), figNum));\n\t\t}\n\t});\n\n\tbuttonRow->Add(createButton, 1, wxALL, 5);\n\tbuttonRow->Add(cancelButton, 1, wxALL, 5);\n\n\tsizer->Add(comboRow, 1, wxEXPAND | wxALL, 2);\n\tsizer->Add(figNumRow, 1, wxEXPAND | wxALL, 2);\n\tsizer->Add(buttonRow, 1, wxEXPAND | wxALL, 2);\n\n\tthis->SetSizer(sizer);\n\tthis->Centre(wxBOTH);\n}\n\nwxString CreateDimensionFigureDialog::GetFilePath() const\n{\n\treturn m_filePath;\n}\n\nMoveDimensionFigureDialog::MoveDimensionFigureDialog(EmulatedUSBDeviceFrame* parent, uint8 currentIndex)\n\t: wxDialog(parent, wxID_ANY, _(\"Dimensions Figure Mover\"), wxDefaultPosition, wxSize(700, 300))\n{\n\tauto* sizer = new wxGridSizer(2, 5, 10, 10);\n\n\tstd::array<std::optional<uint32>, 7> ids = parent->GetCurrentMinifigs();\n\n\tsizer->Add(AddMinifigSlot(2, 0, currentIndex, ids[0]), 1, wxALL, 5);\n\tsizer->Add(new wxStaticText(this, wxID_ANY, \"\"), 1, wxALL, 5);\n\tsizer->Add(AddMinifigSlot(1, 1, currentIndex, ids[1]), 1, wxALL, 5);\n\tsizer->Add(new wxStaticText(this, wxID_ANY, \"\"), 1, wxALL, 5);\n\tsizer->Add(AddMinifigSlot(3, 2, currentIndex, ids[2]), 1, wxALL, 5);\n\n\tsizer->Add(AddMinifigSlot(2, 3, currentIndex, ids[3]), 1, wxALL, 5);\n\tsizer->Add(AddMinifigSlot(2, 4, currentIndex, ids[4]), 1, wxALL, 5);\n\tsizer->Add(new wxStaticText(this, wxID_ANY, \"\"), 1, wxALL, 5);\n\tsizer->Add(AddMinifigSlot(3, 5, currentIndex, ids[5]), 1, wxALL, 5);\n\tsizer->Add(AddMinifigSlot(3, 6, currentIndex, ids[6]), 1, wxALL, 5);\n\n\tthis->SetSizer(sizer);\n\tthis->Centre(wxBOTH);\n}\n\nwxBoxSizer* MoveDimensionFigureDialog::AddMinifigSlot(uint8 pad, uint8 index, uint8 currentIndex, std::optional<uint32> currentId)\n{\n\tauto* panel = new wxBoxSizer(wxVERTICAL);\n\n\tauto* label = new wxStaticText(this, wxID_ANY, \"None\");\n\tif (currentId)\n\t\tlabel->SetLabel(nsyshid::g_dimensionstoypad.FindFigure(currentId.value()));\n\n\tauto* moveButton = new wxButton(this, wxID_ANY, _(\"Move Here\"));\n\tif (index == currentIndex)\n\t\tmoveButton->SetLabelText(\"Pick up and Place\");\n\n\tmoveButton->Bind(wxEVT_BUTTON, [pad, index, this](wxCommandEvent&) {\n\t\tm_newPad = pad;\n\t\tm_newIndex = index;\n\t\tthis->EndModal(1);\n\t});\n\n\tpanel->Add(label, 1, wxALL, 5);\n\tpanel->Add(moveButton, 1, wxALL, 5);\n\n\treturn panel;\n}\n\nuint8 MoveDimensionFigureDialog::GetNewPad() const\n{\n\treturn m_newPad;\n}\n\nuint8 MoveDimensionFigureDialog::GetNewIndex() const\n{\n\treturn m_newIndex;\n}\n\nstd::array<std::optional<uint32>, 7> EmulatedUSBDeviceFrame::GetCurrentMinifigs()\n{\n\treturn m_dimSlots;\n}\n"
  },
  {
    "path": "src/gui/wxgui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.h",
    "content": "#pragma once\n\n#include <array>\n\n#include <wx/dialog.h>\n#include <wx/frame.h>\n\n#include \"Cafe/OS/libs/nsyshid/Infinity.h\"\n#include \"Cafe/OS/libs/nsyshid/Skylander.h\"\n\nclass wxBoxSizer;\nclass wxCheckBox;\nclass wxFlexGridSizer;\nclass wxNotebook;\nclass wxPanel;\nclass wxStaticBox;\nclass wxString;\nclass wxTextCtrl;\n\nclass EmulatedUSBDeviceFrame : public wxFrame\n{\n  public:\n\tEmulatedUSBDeviceFrame(wxWindow* parent);\n\t~EmulatedUSBDeviceFrame();\n\tstd::array<std::optional<uint32>, 7> GetCurrentMinifigs();\n\n  private:\n\twxCheckBox* m_emulatePortal;\n\twxCheckBox* m_emulateBase;\n\twxCheckBox* m_emulateToypad;\n\tstd::array<wxTextCtrl*, nsyshid::MAX_SKYLANDERS> m_skylanderSlots;\n\tstd::array<wxTextCtrl*, nsyshid::MAX_FIGURES> m_infinitySlots;\n\tstd::array<wxTextCtrl*, 7> m_dimensionSlots;\n\tstd::array<std::optional<std::tuple<uint8, uint16, uint16>>, nsyshid::MAX_SKYLANDERS> m_skySlots;\n\tstd::array<std::optional<uint32>, 7> m_dimSlots;\n\n\twxPanel* AddSkylanderPage(wxNotebook* notebook);\n\twxPanel* AddInfinityPage(wxNotebook* notebook);\n\twxPanel* AddDimensionsPage(wxNotebook* notebook);\n\twxBoxSizer* AddSkylanderRow(uint8 row_number, wxStaticBox* box);\n\twxBoxSizer* AddInfinityRow(wxString name, uint8 row_number, wxStaticBox* box);\n\twxBoxSizer* AddDimensionPanel(uint8 pad, uint8 index, wxStaticBox* box);\n\tvoid LoadSkylander(uint8 slot);\n\tvoid LoadSkylanderPath(uint8 slot, wxString path);\n\tvoid CreateSkylander(uint8 slot);\n\tvoid ClearSkylander(uint8 slot);\n\tvoid UpdateSkylanderEdits();\n\tvoid LoadFigure(uint8 slot);\n\tvoid LoadFigurePath(uint8 slot, wxString path);\n\tvoid CreateFigure(uint8 slot);\n\tvoid ClearFigure(uint8 slot);\n\tvoid LoadMinifig(uint8 pad, uint8 index);\n\tvoid LoadMinifigPath(wxString path_name, uint8 pad, uint8 index);\n\tvoid CreateMinifig(uint8 pad, uint8 index);\n\tvoid ClearMinifig(uint8 pad, uint8 index);\n\tvoid MoveMinifig(uint8 pad, uint8 index);\n};\n\nclass CreateSkylanderDialog : public wxDialog\n{\n  public:\n\texplicit CreateSkylanderDialog(wxWindow* parent, uint8 slot);\n\twxString GetFilePath() const;\n\n  protected:\n\twxString m_filePath;\n};\n\nclass CreateInfinityFigureDialog : public wxDialog\n{\n  public:\n\texplicit CreateInfinityFigureDialog(wxWindow* parent, uint8 slot);\n\twxString GetFilePath() const;\n\n  protected:\n\twxString m_filePath;\n};\n\nclass CreateDimensionFigureDialog : public wxDialog\n{\n  public:\n\texplicit CreateDimensionFigureDialog(wxWindow* parent);\n\twxString GetFilePath() const;\n\n  protected:\n\twxString m_filePath;\n};\n\nclass MoveDimensionFigureDialog : public wxDialog\n{\n  public:\n\texplicit MoveDimensionFigureDialog(EmulatedUSBDeviceFrame* parent, uint8 currentIndex);\n\tuint8 GetNewPad() const;\n\tuint8 GetNewIndex() const;\n\n  protected:\n\tuint8 m_newIndex = 0;\n\tuint8 m_newPad = 0;\n\n  private:\n\twxBoxSizer* AddMinifigSlot(uint8 pad, uint8 index, uint8 oldIndex, std::optional<uint32> currentId);\n};"
  },
  {
    "path": "src/gui/wxgui/GameProfileWindow.cpp",
    "content": "#include \"wxgui/GameProfileWindow.h\"\n\n#include <wx/statbox.h>\n#include <wx/sizer.h>\n#include <wx/panel.h>\n#include <wx/notebook.h>\n#include <wx/stattext.h>\n#include <wx/wupdlock.h>\n#include <wx/slider.h>\n\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"input/InputManager.h\"\n\n#if BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_BSD\n#include \"resource/embedded/resources.h\"\n#endif\n\nGameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id)\n\t: wxFrame(parent, wxID_ANY, _(\"Edit game profile\"), wxDefaultPosition, wxSize{ 390, 350 }, wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER | wxTAB_TRAVERSAL | wxSYSTEM_MENU), m_title_id(title_id)\n{\n\tSetIcon(wxICON(X_GAME_PROFILE));\n\n\tm_game_profile.Reset();\n\tm_game_profile.Load(title_id);\n\n\tthis->SetSizeHints(wxDefaultSize, wxDefaultSize);\n\n\tauto* main_sizer = new wxBoxSizer(wxVERTICAL);\n\n\tauto* m_notebook = new wxNotebook(this, wxID_ANY);\n\t// general\n\t{\n\t\tauto* panel = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\t\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\t\t{\n\t\t\tauto* box_sizer = new wxStaticBoxSizer(new wxStaticBox(panel, wxID_ANY, _(\"General\")), wxVERTICAL);\n\t\t\tauto* box = box_sizer->GetStaticBox();\n\n\t\t\tm_load_libs = new wxCheckBox(box, wxID_ANY, _(\"Load shared libraries\"));\n\t\t\tm_load_libs->SetToolTip(_(\"EXPERT OPTION\\nThis option will load libraries from the cafeLibs directory\"));\n\t\t\tbox_sizer->Add(m_load_libs, 0, wxALL, 5);\n\n\t\t\tm_start_with_padview = new wxCheckBox(box, wxID_ANY, _(\"Launch with gamepad view\"));\n\t\t\tm_start_with_padview->SetToolTip(_(\"Games will be launched with gamepad view toggled as default. The view can be toggled with CTRL + TAB\"));\n\t\t\tbox_sizer->Add(m_start_with_padview, 0, wxALL, 5);\n\n\t\t\tsizer->Add(box_sizer, 0, wxEXPAND, 5);\n\t\t}\n\t\t// cpu\n\t\t{\n\t\t\tauto* box_sizer = new wxStaticBoxSizer(new wxStaticBox(panel, wxID_ANY, _(\"CPU\")), wxVERTICAL);\n\t\t\tauto* box = box_sizer->GetStaticBox();\n\n\t\t\tauto* first_row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\t\tfirst_row->SetFlexibleDirection(wxBOTH);\n\t\t\tfirst_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\t\tfirst_row->Add(new wxStaticText(box, wxID_ANY, _(\"Mode\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\twxString cpu_modes[] = { _(\"Single-core interpreter\"), _(\"Single-core recompiler\"), _(\"Multi-core recompiler\"), _(\"Auto (recommended)\") };\n\t\t\tconst sint32 m_cpu_modeNChoices = std::size(cpu_modes);\n\t\t\tm_cpu_mode = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_cpu_modeNChoices, cpu_modes, 0);\n\t\t\tm_cpu_mode->SetToolTip(_(\"Set the CPU emulation mode\"));\n\t\t\tfirst_row->Add(m_cpu_mode, 0, wxALL, 5);\n\n\t\t\tfirst_row->Add(new wxStaticText(box, wxID_ANY, _(\"Thread quantum\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\tauto* quantum_sizer = new wxFlexGridSizer(0, 2, 0, 0);\n\t\t\tquantum_sizer->SetFlexibleDirection(wxBOTH);\n\t\t\tquantum_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\t\twxString quantum_values[] = { \"20000\", \"45000\", \"60000\", \"80000\" ,\"100000\" };\n\t\t\tm_thread_quantum = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(quantum_values), quantum_values);\n\t\t\tm_thread_quantum->SetMinSize(wxSize(85, -1));\n\t\t\tm_thread_quantum->SetToolTip(_(\"EXPERT OPTION\\nSet the maximum thread slice runtime (in virtual cycles)\"));\n\t\t\tquantum_sizer->Add(m_thread_quantum, 0, wxALL, 5);\n\n\t\t\tquantum_sizer->Add(new wxStaticText(box, wxID_ANY, _(\"cycles\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\tfirst_row->Add(quantum_sizer, 0, wxEXPAND, 5);\n\n\t\t\tbox_sizer->Add(first_row, 0, wxEXPAND, 5);\n\n\n\t\t\tsizer->Add(box_sizer, 0, wxEXPAND, 5);\n\t\t}\n\n\t\tpanel->SetSizer(sizer);\n\t\tpanel->Layout();\n\t\tsizer->Fit(panel);\n\t\tm_notebook->AddPage(panel, _(\"General\"), true);\n\t}\n\n\t// graphic\n\t{\n\t\tauto* panel = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\t\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\t\t//m_extended_texture_readback = new wxCheckBox(panel, wxID_ANY, _(\"Extended texture readback\"));\n\t\t//m_extended_texture_readback->SetToolTip(_(\"Improves emulation accuracy of CPU to GPU memory access at the cost of performance. Required for some games.\"));\n\t\t//sizer->Add(m_extended_texture_readback, 0, wxALL, 5);\n\n\t\tauto* first_row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\tfirst_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\t/*first_row->Add(new wxStaticText(panel, wxID_ANY, _(\"Precompiled shaders\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\twxString precompiled_modes[] = { _(\"auto\"), _(\"enable\"), _(\"disable\") };\n\t\tconst sint32 precompiled_count = std::size(precompiled_modes);\n\t\tm_precompiled = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, precompiled_count, precompiled_modes, 0);\n\t\tm_precompiled->SetToolTip(_(\"Precompiled shaders can speed up the load time on the shader loading screen.\\nAuto will enable it for AMD/Intel but disable it for NVIDIA GPUs as a workaround for a driver bug.\\n\\nRecommended: Auto\"));\n\t\tfirst_row->Add(m_precompiled, 0, wxALL, 5);*/\n\n\t\tfirst_row->Add(new wxStaticText(panel, wxID_ANY, _(\"Graphics API\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\twxString gapi_values[] = { \"\", \"OpenGL\", \"Vulkan\",\n#if ENABLE_METAL\n            \"Metal\"\n#endif\n\t\t};\n\t\tm_graphic_api = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(gapi_values), gapi_values);\n\t\tfirst_row->Add(m_graphic_api, 0, wxALL, 5);\n\n\t\tfirst_row->Add(new wxStaticText(panel, wxID_ANY, _(\"Shader multiplication accuracy\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\twxString mul_values[] = { _(\"false\"), _(\"true\")};\n\t\tm_shader_mul_accuracy = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(mul_values), mul_values);\n\t\tm_shader_mul_accuracy->SetToolTip(_(\"EXPERT OPTION\\nControls the accuracy of floating point multiplication in shaders.\\n\\nRecommended: true\"));\n\t\tfirst_row->Add(m_shader_mul_accuracy, 0, wxALL, 5);\n\n#if ENABLE_METAL\n\t\tfirst_row->Add(new wxStaticText(panel, wxID_ANY, _(\"Shader fast math\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\twxString math_values[] = { _(\"false\"), _(\"true\") };\n\t\tm_shader_fast_math = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(math_values), math_values);\n\t\tm_shader_fast_math->SetToolTip(_(\"EXPERT OPTION\\nEnables fast math for all shaders. May (rarely) cause graphical bugs.\\n\\nMetal only\\n\\nRecommended: true\"));\n\t\tfirst_row->Add(m_shader_fast_math, 0, wxALL, 5);\n\n\t\tfirst_row->Add(new wxStaticText(panel, wxID_ANY, _(\"Metal buffer cache mode\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\twxString cache_values[] = { _(\"auto\"), _(\"device private\"), _(\"device shared\"), _(\"host\") };\n\t\tm_metal_buffer_cache_mode = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(cache_values), cache_values);\n\t\tm_metal_buffer_cache_mode->SetToolTip(_(\"EXPERT OPTION\\nDecides how the buffer cache memory will be managed.\\n\\nMetal only\\n\\nRecommended: auto\"));\n\t\tfirst_row->Add(m_metal_buffer_cache_mode, 0, wxALL, 5);\n\n\t\tfirst_row->Add(new wxStaticText(panel, wxID_ANY, _(\"Position invariance\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\twxString pos_values[] = { _(\"auto\"), _(\"false\"), _(\"true\") };\n\t\tm_position_invariance = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(pos_values), pos_values);\n\t\tm_position_invariance->SetToolTip(_(\"EXPERT OPTION\\nDisables most optimizations for vertex positions. May fix polygon cutouts or flickering in some games.\\n\\nMetal only\\n\\nRecommended: auto\"));\n\t\tfirst_row->Add(m_position_invariance, 0, wxALL, 5);\n#endif\n\n\t\t/*first_row->Add(new wxStaticText(panel, wxID_ANY, _(\"GPU buffer cache accuracy\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\twxString accuarcy_values[] = { _(\"high\"), _(\"medium\"), _(\"low\") };\n\t\tm_cache_accuracy = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(accuarcy_values), accuarcy_values);\n\t\tm_cache_accuracy->SetToolTip(_(\"Lower value results in higher performance, but may cause graphical issues\"));\n\t\tfirst_row->Add(m_cache_accuracy, 0, wxALL, 5);*/\n\n\t\tsizer->Add(first_row, 0, wxEXPAND, 5);\n\n\n\t\tpanel->SetSizer(sizer);\n\t\tpanel->Layout();\n\t\tsizer->Fit(panel);\n\t\tm_notebook->AddPage(panel, _(\"Graphic\"), false);\n\t}\n\n\t//// audio\n\t//{\n\t//\tauto panel = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\t//\twxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);\n\n\t//\tm_disable_audio = new wxCheckBox(panel, wxID_ANY, _(\"Disable Audio\"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER);\n\t//\tsizer->Add(m_disable_audio, 0, wxALL, 5);\n\n\n\t//\tpanel->SetSizer(sizer);\n\t//\tpanel->Layout();\n\t//\tsizer->Fit(panel);\n\t//\tm_notebook->AddPage(panel, _(\"Audio\"), false);\n\t//}\n\n\t// controller\n\t{\n\t\tauto panel = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\t\twxBoxSizer* sizer;\n\t\tsizer = new wxBoxSizer(wxVERTICAL);\n\n\t\twxFlexGridSizer* profile_sizer;\n\t\tprofile_sizer = new wxFlexGridSizer(0, 2, 0, 0);\n\t\tprofile_sizer->SetFlexibleDirection(wxBOTH);\n\t\tprofile_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tfor (int i = 0; i < 8; ++i)\n\t\t{\n\t\t\tprofile_sizer->Add(new wxStaticText(panel, wxID_ANY, formatWxString(_(\"Controller {}\"), i + 1)), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\tm_controller_profile[i] = new wxComboBox(panel, wxID_ANY,\"\", wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_DROPDOWN| wxCB_READONLY);\n\t\t\tm_controller_profile[i]->SetMinSize(wxSize(250, -1));\n\t\t\tm_controller_profile[i]->Bind(wxEVT_COMBOBOX_DROPDOWN, &GameProfileWindow::OnControllerProfileDropdown, this);\n\t\t\tm_controller_profile[i]->SetToolTip(_(\"Forces a given controller profile\"));\n\t\t\tprofile_sizer->Add(m_controller_profile[i], 0, wxALL, 5);\n\t\t}\n\n\t\tsizer->Add(profile_sizer, 0, wxEXPAND, 5);\n\n\t\tpanel->SetSizer(sizer);\n\t\tpanel->Layout();\n\t\tsizer->Fit(panel);\n\t\tm_notebook->AddPage(panel, _(\"Controller\"), false);\n\t}\n\n\tmain_sizer->Add(m_notebook, 1, wxEXPAND | wxALL, 5);\n\n\n\tthis->SetSizer(main_sizer);\n\tthis->Layout();\n\n\tthis->Centre(wxBOTH);\n\n\tApplyProfile();\n}\n\nGameProfileWindow::~GameProfileWindow()\n{\n\tSaveProfile();\n}\n\nvoid GameProfileWindow::OnStreamoutSizeChange(wxCommandEvent& event)\n{\n\twxSlider* slider = wxDynamicCast(event.GetEventObject(), wxSlider);\n\twxASSERT(slider);\n\twxStaticText* text = wxDynamicCast(slider->GetClientData(), wxStaticText);\n\twxASSERT(text);\n\ttext->SetLabelText(fmt::format(\"{} MB\", slider->GetValue()));\n\tevent.Skip();\n}\n\nvoid GameProfileWindow::OnControllerProfileDropdown(wxCommandEvent& event)\n{\n\twxComboBox* cb = wxDynamicCast(event.GetEventObject(), wxComboBox);\n\twxASSERT(cb);\n\n\twxWindowUpdateLocker lock(cb);\n\n\tconst auto selected_value = cb->GetStringSelection();\n\tcb->Clear();\n\tcb->Append(wxEmptyString);\n\n\tauto profiles = InputManager::get_profiles();\n\tfor (const auto& profile : profiles)\n\t{\n\t\tcb->Append(wxString::FromUTF8(profile));\n\t}\n\n\tcb->SetStringSelection(selected_value);\n}\n\nvoid GameProfileWindow::SetProfileInt(gameProfileIntegerOption_t& option, wxCheckBox* checkbox, sint32 value) const\n{\n\tconst auto state = checkbox->GetValue();\n\tif (state)\n\t{\n\t\toption.isPresent = true;\n\t\toption.value = value;\n\t}\n\telse\n\t\toption.isPresent = false;\n}\n\nvoid GameProfileWindow::ApplyProfile()\n{\n\tif(m_game_profile.m_gameName)\n\t\tthis->SetTitle(_(\"Edit game profile\") + \" - \" + m_game_profile.m_gameName.value());\n\n\t// general\n\tm_load_libs->SetValue(m_game_profile.m_loadSharedLibraries.value());\n\tm_start_with_padview->SetValue(m_game_profile.m_startWithPadView);\n\n\t// cpu\n\t// wxString cpu_modes[] = { _(\"Singlecore-Interpreter\"), _(\"Singlecore-Recompiler\"), _(\"Triplecore-Recompiler\"), _(\"Auto (recommended)\") };\n\tswitch(m_game_profile.m_cpuMode.value())\n\t{\n\tcase CPUMode::SinglecoreInterpreter: m_cpu_mode->SetSelection(0); break;\n\tcase CPUMode::SinglecoreRecompiler: m_cpu_mode->SetSelection(1); break;\n\tcase CPUMode::DualcoreRecompiler: m_cpu_mode->SetSelection(2); break;\n\tcase CPUMode::MulticoreRecompiler: m_cpu_mode->SetSelection(2); break;\n\tdefault: m_cpu_mode->SetSelection(3);\n\t}\n\n\tm_thread_quantum->SetStringSelection(fmt::format(\"{}\", m_game_profile.m_threadQuantum));\n\n\t// gpu\n\tif (!m_game_profile.m_graphics_api.has_value())\n\t\tm_graphic_api->SetSelection(0); // selecting \"\"\n\telse\n\t\tm_graphic_api->SetSelection(1 + m_game_profile.m_graphics_api.value()); // \"\", OpenGL, Vulkan, Metal\n\tm_shader_mul_accuracy->SetSelection((int)m_game_profile.m_accurateShaderMul);\n#if ENABLE_METAL\n\tm_shader_fast_math->SetSelection((int)m_game_profile.m_shaderFastMath);\n\tm_metal_buffer_cache_mode->SetSelection((int)m_game_profile.m_metalBufferCacheMode);\n\tm_position_invariance->SetSelection((int)m_game_profile.m_positionInvariance);\n#endif\n\n\t//// audio\n\t//m_disable_audio->Set3StateValue(GetCheckboxState(m_game_profile.disableAudio));\n\n\t// controller\n\tauto profiles = InputManager::get_profiles();\n\n\tfor (const auto& cb : m_controller_profile)\n\t{\n\t\tcb->Clear();\n\t\tfor (const auto& profile : profiles)\n\t\t{\n\t\t\tcb->Append(wxString::FromUTF8(profile));\n\t\t}\n\t}\n\n\tfor (int i = 0; i < InputManager::kMaxController; ++i)\n\t{\n\t\tconst bool has_value = m_game_profile.m_controllerProfile[i].has_value();\n\t\tif (has_value)\n\t\t{\n\t\t\tconst auto& v = m_game_profile.m_controllerProfile[i].value();\n\t\t\tm_controller_profile[i]->SetStringSelection(wxString::FromUTF8(v));\n\t\t}\n\n\t\telse\n\t\t\tm_controller_profile[i]->SetSelection(wxNOT_FOUND);\n\t}\n}\n\nvoid GameProfileWindow::SaveProfile()\n{\n\t// update game profile struct\n\tm_game_profile.Reset();\n\t// general\n\tm_game_profile.m_loadSharedLibraries = m_load_libs->GetValue();\n\tm_game_profile.m_startWithPadView = m_start_with_padview->GetValue();\n\n\t// cpu\n\tswitch(m_cpu_mode->GetSelection())\n\t{\n\tcase 0: m_game_profile.m_cpuMode = CPUMode::SinglecoreInterpreter; break;\n\tcase 1: m_game_profile.m_cpuMode = CPUMode::SinglecoreRecompiler; break;\n\tcase 2: m_game_profile.m_cpuMode = CPUMode::MulticoreRecompiler; break;\n\tdefault:\n\t\tm_game_profile.m_cpuMode = CPUMode::Auto;\n\t}\n\n\n\tconst wxString thread_quantum = m_thread_quantum->GetStringSelection();\n\tif (!thread_quantum.empty())\n\t{\n\t\tm_game_profile.m_threadQuantum = ConvertString<uint32>(thread_quantum.ToStdString());\n\t\tm_game_profile.m_threadQuantum = std::min<uint32>(m_game_profile.m_threadQuantum, 536870912);\n\t\tm_game_profile.m_threadQuantum = std::max<uint32>(m_game_profile.m_threadQuantum, 5000);\n\t}\n\n\t// gpu\n\tm_game_profile.m_accurateShaderMul = (AccurateShaderMulOption)m_shader_mul_accuracy->GetSelection();\n\tif (m_game_profile.m_accurateShaderMul != AccurateShaderMulOption::False && m_game_profile.m_accurateShaderMul != AccurateShaderMulOption::True)\n\t\tm_game_profile.m_accurateShaderMul = AccurateShaderMulOption::True; // force a legal value\n#if ENABLE_METAL\n\tm_game_profile.m_shaderFastMath = (bool)m_shader_fast_math->GetSelection();\n\tm_game_profile.m_metalBufferCacheMode = (MetalBufferCacheMode)m_metal_buffer_cache_mode->GetSelection();\n\tm_game_profile.m_positionInvariance = (PositionInvariance)m_position_invariance->GetSelection();\n#endif\n\n\tif (m_graphic_api->GetSelection() == 0)\n\t\tm_game_profile.m_graphics_api = {};\n\telse\n\t\tm_game_profile.m_graphics_api = (GraphicAPI)(m_graphic_api->GetSelection() - 1);  // \"\", OpenGL, Vulkan, Metal\n\n\t// controller\n\tfor (int i = 0; i < 8; ++i)\n\t{\n\t\tif(m_controller_profile[i]->GetSelection() == wxNOT_FOUND)\n\t\t{\n\t\t\tm_game_profile.m_controllerProfile[i].reset();\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst wxString profile_name = m_controller_profile[i]->GetStringSelection();\n\t\tif (profile_name.empty())\n\t\t\tm_game_profile.m_controllerProfile[i].reset();\n\t\telse\n\t\t\tm_game_profile.m_controllerProfile[i] = profile_name.ToUTF8();\n\t}\n\n\t// update game profile file\n\tm_game_profile.Save(m_title_id);\n}\n\nvoid GameProfileWindow::SetSliderValue(wxSlider* slider, sint32 new_value) const\n{\n\twxASSERT(slider);\n\tslider->SetValue(new_value);\n\n\twxCommandEvent slider_event(wxEVT_SLIDER, slider->GetId());\n\tslider_event.SetEventObject(slider);\n\tslider_event.SetClientData((void*)IsFrozen());\n\twxPostEvent(slider->GetEventHandler(), slider_event);\n}\n"
  },
  {
    "path": "src/gui/wxgui/GameProfileWindow.h",
    "content": "#pragma once\n\n#include <wx/frame.h>\n#include <wx/checkbox.h>\n#include <wx/choice.h>\n#include <wx/combobox.h>\n#include <wx/slider.h>\n\n#include \"Cafe/GameProfile/GameProfile.h\"\n\nclass GameProfileWindow : public wxFrame\n{\npublic:\n\tGameProfileWindow(wxWindow* parent, uint64_t title_id);\n\t~GameProfileWindow();\n\nprivate:\n\tuint64_t m_title_id;\n\tGameProfile m_game_profile;\n\n\tvoid OnStreamoutSizeChange(wxCommandEvent& event);\n\tvoid OnControllerProfileDropdown(wxCommandEvent& event);\n\n\tvoid SetSliderValue(wxSlider* slider, sint32 new_value) const;\n\tvoid SetProfileInt(gameProfileIntegerOption_t& option, wxCheckBox* checkbox, sint32 value) const;\n\n\tvoid ApplyProfile();\n\tvoid SaveProfile();\n\n\t// general\n\twxCheckBox* m_load_libs, *m_start_with_padview;\n\n\t// cpu\n\twxChoice *m_cpu_mode;\n\twxChoice* m_thread_quantum;\n\n\t// gpu\n\t//wxCheckBox* m_extended_texture_readback;\n\t//wxChoice* m_precompiled;\n\twxChoice* m_graphic_api;\n\n\twxChoice* m_shader_mul_accuracy;\n#if ENABLE_METAL\n\twxChoice* m_shader_fast_math;\n\twxChoice* m_metal_buffer_cache_mode;\n\twxChoice* m_position_invariance;\n#endif\n\t//wxChoice* m_cache_accuracy;\n\n\t// audio\n\t//wxCheckBox* m_disable_audio;\n\n\t// controller\n\twxComboBox* m_controller_profile[8];\n};\n"
  },
  {
    "path": "src/gui/wxgui/GameUpdateWindow.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxgui/GameUpdateWindow.h\"\n#include \"util/helpers/helpers.h\"\n\n#include <filesystem>\n#include <sstream>\n#include \"util/helpers/SystemException.h\"\n#include \"wxgui/CemuApp.h\"\n#include \"Cafe/TitleList/GameInfo.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxHelper.h\"\n\nwxString _GetTitleIdTypeStr(TitleId titleId)\n{\n\tTitleIdParser tip(titleId);\n\tswitch (tip.GetType())\n\t{\n\tcase TitleIdParser::TITLE_TYPE::AOC:\n\t\treturn _(\"DLC\");\n\tcase TitleIdParser::TITLE_TYPE::BASE_TITLE:\n\t\treturn _(\"Base game\");\n\tcase TitleIdParser::TITLE_TYPE::BASE_TITLE_DEMO:\n\t\treturn _(\"Demo\");\n\tcase TitleIdParser::TITLE_TYPE::SYSTEM_TITLE:\n\tcase TitleIdParser::TITLE_TYPE::SYSTEM_OVERLAY_TITLE:\n\t\treturn _(\"System title\");\n\tcase TitleIdParser::TITLE_TYPE::SYSTEM_DATA:\n\t\treturn _(\"System data title\");\n\tcase TitleIdParser::TITLE_TYPE::BASE_TITLE_UPDATE:\n\t\treturn _(\"Update\");\n\tdefault:\n\t\tbreak;\n\t}\n\treturn \"Unknown\";\n}\n\nbool GameUpdateWindow::ParseUpdate(const fs::path& metaPath)\n{\n\tm_title_info = TitleInfo(metaPath);\n\tif (!m_title_info.IsValid())\n\t\treturn false;\n\tfs::path target_location = ActiveSettings::GetMlcPath(m_title_info.GetInstallPath());\n\tstd::error_code ec;\n\tif (fs::exists(target_location, ec))\n\t{\n\t\ttry\n\t\t{\n\t\t\tconst TitleInfo tmp(target_location);\n\t\t\tif (!tmp.IsValid())\n\t\t\t{\n\t\t\t\t// does not exist / is not valid. We allow to overwrite it\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tTitleIdParser tip(m_title_info.GetAppTitleId());\n\t\t\t\tTitleIdParser tipOther(tmp.GetAppTitleId());\n\n\t\t\t\tif (tip.GetType() != tipOther.GetType())\n\t\t\t\t{\n\t\t\t\t\tauto typeStrToInstall = _GetTitleIdTypeStr(m_title_info.GetAppTitleId());\n\t\t\t\t\tauto typeStrCurrentlyInstalled = _GetTitleIdTypeStr(tmp.GetAppTitleId());\n\n\t\t\t\t\tauto wxMsg = _(\"It seems that there is already a title installed at the target location but it has a different type.\\nCurrently installed: \\'{}\\' Installing: \\'{}\\'\\n\\nThis can happen for titles which were installed with very old Cemu versions.\\nDo you still want to continue with the installation? It will replace the currently installed title.\");\n\t\t\t\t\twxMessageDialog dialog(this, formatWxString(wxMsg, typeStrCurrentlyInstalled, typeStrToInstall), _(\"Warning\"), wxCENTRE | wxYES_NO | wxICON_EXCLAMATION);\n\t\t\t\t\tif (dialog.ShowModal() != wxID_YES)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse if (tmp.GetAppTitleVersion() == m_title_info.GetAppTitleVersion())\n\t\t\t\t{\n\t\t\t\t\twxMessageDialog dialog(this, _(\"It seems that the selected title is already installed, do you want to reinstall it?\"), _(\"Warning\"), wxCENTRE | wxYES_NO);\n\t\t\t\t\tif (dialog.ShowModal() != wxID_YES)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse if (tmp.GetAppTitleVersion() > m_title_info.GetAppTitleVersion())\n\t\t\t\t{\n\t\t\t\t\twxMessageDialog dialog(this, _(\"It seems that a newer version is already installed, do you still want to install the older version?\"), _(\"Warning\"), wxCENTRE | wxYES_NO);\n\t\t\t\t\tif (dialog.ShowModal() != wxID_YES)\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// temp rename until done\n\t\t\tm_backup_folder = target_location;\n\t\t\tm_backup_folder.replace_extension(\".backup\");\n\n\t\t\tstd::error_code ec;\n\t\t\twhile (fs::exists(m_backup_folder, ec) || ec)\n\t\t\t{\n\t\t\t\tfs::remove_all(m_backup_folder, ec);\n\n\t\t\t\tif (ec)\n\t\t\t\t{\n\t\t\t\t\tconst auto error_msg = formatWxString(_(\"Error when trying to move former title installation:\\n{}\"), GetSystemErrorMessage(ec));\n\t\t\t\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE, this);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\t// wait so filesystem doesnt \n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t\t\t}\n\n\t\t\tfs::rename(target_location, m_backup_folder);\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"GameUpdateWindow::ParseUpdate exist-error: {} at {}\", ex.what(), _pathToUtf8(target_location));\n\t\t}\n\t}\n\n\tm_target_path = target_location;\n\n\tfs::path source(metaPath);\n\n\tm_source_paths =\n\t{\n\t\tfs::path(source).append(\"content\"),\n\t\tfs::path(source).append(\"code\"),\n\t\tfs::path(source).append(\"meta\")\n\t};\n\n\tm_required_size = 0;\n\tfor (auto& path : m_source_paths)\n\t{\n\t\tfor (const fs::directory_entry& f : fs::recursive_directory_iterator(path))\n\t\t{\n\t\t\tif (is_regular_file(f.path()))\n\t\t\t\tm_required_size += file_size(f.path());\n\t\t}\n\t}\n\n\tconst fs::space_info targetSpace = fs::space(ActiveSettings::GetMlcPath());\n\tif (targetSpace.free <= m_required_size)\n\t{\n\t\tauto string = formatWxString(_(\"Not enough space available.\\nRequired: {0} MB\\nAvailable: {1} MB\"), (m_required_size / 1024 / 1024), (targetSpace.free / 1024 / 1024));\n\t\tthrow std::runtime_error(string.utf8_string());\n\t}\n\n\treturn true;\n}\n\nGameUpdateWindow::GameUpdateWindow(wxWindow& parent, const fs::path& filePath)\n\t: wxDialog(&parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX),\n\t  m_thread_state(ThreadRunning)\n{\n\ttry\n\t{\n\t\t#if BOOST_OS_WINDOWS\n\t\tSetLastError(0);\n\t\t#endif\n\t\tif(!ParseUpdate(filePath))\n\t\t\tthrow AbortException();\n\t}\n\tcatch (const std::runtime_error& ex)\n\t{\n\t\tthrow SystemException(ex);\n\t}\n\t\n\tauto sizer = new wxBoxSizer(wxVERTICAL);\n\n\tTitleIdParser tip(GetTitleId());\n\n\tif (tip.GetType() == TitleIdParser::TITLE_TYPE::AOC)\n\t\tSetTitle(_(\"Installing DLC...\"));\n\telse if (tip.GetType() == TitleIdParser::TITLE_TYPE::BASE_TITLE_UPDATE)\n\t\tSetTitle(_(\"Installing update...\"));\n\telse if (tip.IsSystemTitle())\n\t\tSetTitle(_(\"Installing system title...\"));\n\telse\n\t\tSetTitle(_(\"Installing title...\"));\n\n\tm_processBar = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(500, 20), wxGA_HORIZONTAL);\n\tm_processBar->SetValue(0);\n\tm_processBar->SetRange((sint32)(m_required_size / 1000));\n\tsizer->Add(m_processBar, 0, wxALL | wxEXPAND, 5);\n\n\twxButton* m_cancelButton = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\tm_cancelButton->Bind(wxEVT_BUTTON, &GameUpdateWindow::OnCancelButton, this);\n\tsizer->Add(m_cancelButton, 0, wxALIGN_RIGHT | wxALL, 5);\n\n\tthis->SetSizer(sizer);\n\tthis->Centre(wxBOTH);\n\n\twxWindowBase::Layout();\n\twxWindowBase::Fit();\n\n\tm_timer = new wxTimer(this);\n\tthis->Bind(wxEVT_TIMER, &GameUpdateWindow::OnUpdate, this);\n\tthis->Bind(wxEVT_CLOSE_WINDOW, &GameUpdateWindow::OnClose, this);\n\tm_timer->Start(250);\n\n\tm_thread_state = ThreadRunning;\n\tm_thread = std::thread(&GameUpdateWindow::ThreadWork, this);\n}\n\nvoid GameUpdateWindow::ThreadWork()\n{\n\tfs::directory_entry currentDirEntry;\n\ttry\n\t{\n\t\t// create base directories\n\t\tfor (auto& path : m_source_paths)\n\t\t{\n\t\t\tif (!path.has_stem())\n\t\t\t\tcontinue;\n\n\t\t\tfs::path targetDir = fs::path(m_target_path) / path.stem();\n\t\t\tcreate_directories(targetDir);\n\t\t}\n\n\t\tfor (auto& path : m_source_paths)\n\t\t{\n\t\t\tif (m_thread_state == ThreadCanceled)\n\t\t\t\tbreak;\n\n\t\t\tif (!path.has_parent_path())\n\t\t\t\tcontinue;\n\n\t\t\tconst auto len = path.parent_path().string().size() + 1;\n\t\t\tfor (const fs::directory_entry& f : fs::recursive_directory_iterator {path})\n\t\t\t{\n\t\t\t\tif (m_thread_state == ThreadCanceled)\n\t\t\t\t\tbreak;\n\n\t\t\t\tcurrentDirEntry = f;\n\t\t\t\tfs::path relative(f.path().string().substr(len));\n\t\t\t\tfs::path target = fs::path(m_target_path) / relative;\n\t\t\t\tif (is_directory(f))\n\t\t\t\t{\n\t\t\t\t\tcreate_directories(target);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tcopy(f, target, fs::copy_options::overwrite_existing);\n\t\t\t\tif (is_regular_file(f.path()))\n\t\t\t\t{\n\t\t\t\t\tm_processed_size += file_size(f.path());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tstd::stringstream error_msg;\n\t\terror_msg << GetSystemErrorMessage(ex);\n\n\t\tif(currentDirEntry != fs::directory_entry{})\n\t\t\terror_msg << fmt::format(\"\\n{}\\n{}\",_(\"Current file:\").utf8_string(), _pathToUtf8(currentDirEntry.path()));\n\n\t\tm_thread_exception = error_msg.str();\n\t\tm_thread_state = ThreadCanceled;\n\t}\n\n\tif (m_thread_state == ThreadCanceled)\n\t{\n\t\tif(fs::exists(m_target_path))\n\t\t\tfs::remove_all(m_target_path);\n\t}\n\telse\n\t\tm_thread_state = ThreadFinished;\n}\n\nGameUpdateWindow::~GameUpdateWindow()\n{\n\tm_timer->Stop();\n\tif (m_thread.joinable())\n\t\tm_thread.join();\n}\n\nint GameUpdateWindow::ShowModal()\n{\n\twxDialog::ShowModal();\n\treturn m_thread_state == ThreadCanceled ? wxID_CANCEL : wxID_OK;\n}\n\nvoid GameUpdateWindow::OnClose(wxCloseEvent& event)\n{\n\tif (m_thread_state == ThreadRunning)\n\t{\n\t\twxMessageDialog dialog(this, _(\"Do you really want to cancel the installation process?\\n\\nCanceling the process will delete the applied files.\"), _(\"Info\"), wxCENTRE | wxYES_NO);\n\t\tif (dialog.ShowModal() != wxID_YES)\n\t\t\treturn;\n\n\t\tm_thread_state = ThreadCanceled;\n\t}\n\n\tm_timer->Stop();\n\tif (m_thread.joinable())\n\t\tm_thread.join();\n\n\tif(!m_backup_folder.empty())\n\t{\n\t\tif(m_thread_state == ThreadCanceled)\n\t\t{\n\t\t\t// restore backup\n\t\t\ttry\n\t\t\t{\n\t\t\t\tif(fs::exists(m_target_path))\n\t\t\t\t\tfs::remove_all(m_target_path);\n\n\t\t\t\tfs::rename(m_backup_folder, m_target_path);\n\t\t\t}\n\t\t\tcatch (const std::exception& ex)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"can't restore update backup: {}\",ex.what());\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// delete backup\n\t\t\ttry\n\t\t\t{\n\t\t\t\tif(fs::exists(m_backup_folder))\n\t\t\t\t\tfs::remove_all(m_backup_folder);\n\t\t\t}\n\t\t\tcatch (const std::exception& ex)\n\t\t\t{\n\t\t\t\tcemuLog_logDebug(LogType::Force, \"can't delete update backup: {}\",ex.what());\n\t\t\t}\n\t\t}\n\t\t\n\t\tm_backup_folder.clear();\n\t}\n\n\tevent.Skip();\n}\n\nvoid GameUpdateWindow::OnUpdate(const wxTimerEvent& event)\n{\n\tif (m_thread_state != ThreadRunning)\n\t{\n\t\tClose();\n\t\treturn;\n\t}\n\n\tconst auto processedSize = (sint32)(m_processed_size / 1000);\n\tif (m_processBar->GetValue() != processedSize)\n\t\tm_processBar->SetValue(processedSize);\n}\n\nvoid GameUpdateWindow::OnCancelButton(const wxCommandEvent& event)\n{\n\tClose();\n}\n"
  },
  {
    "path": "src/gui/wxgui/GameUpdateWindow.h",
    "content": "#pragma once\n\n#include \"Cafe/TitleList/GameInfo.h\"\n\n#include <wx/dialog.h>\n#include <wx/timer.h>\n#include <wx/gauge.h>\n\n#include <atomic>\n#include <string>\n#include <array>\n#include <memory>\n\n// thrown if users doesn't wish to reinstall update/dlc\nclass AbortException : public std::exception {};\n\nclass GameUpdateWindow : public wxDialog\n{\npublic:\n\n\tGameUpdateWindow(wxWindow& parent, const fs::path& metaPath);\n\t~GameUpdateWindow();\n\n\tuint64 GetTitleId() const { return m_title_info.GetAppTitleId(); }\n\tbool HasException() const { return !m_thread_exception.empty(); }\n\t//bool IsDLC() const { return m_game_info->IsDLC(); }\n\t//bool IsUpdate() const { return m_game_info->IsUpdate(); }\n\tconst std::string& GetExceptionMessage() const { return m_thread_exception; }\n\tconst std::string GetGameName() const { return m_title_info.GetMetaTitleName(); }\n\tuint32 GetTargetVersion() const { return m_title_info.GetAppTitleVersion(); }\n\tfs::path GetTargetPath() const { return fs::path(m_target_path); }\n\n\tint ShowModal() override;\n\tvoid OnClose(wxCloseEvent& event);\n\n\tvoid OnUpdate(const wxTimerEvent& event);\n\tvoid OnCancelButton(const wxCommandEvent& event);\n\n\t//uint64 GetUpdateTitleId() const { return m_title_info->GetUpdateTitleId(); }\n\t//uint64 GetDLCTitleId() const { return m_game_info->GetDLCTitleId(); }\n\t\nprivate:\n\t//std::unique_ptr<GameInfoDEPRECATED> m_game_info;\n\tTitleInfo m_title_info;\n\tenum ThreadState_t\n\t{\n\t\tThreadRunning,\n\t\tThreadCanceled,\n\t\tThreadFinished,\n\t};\n\n\tuint64_t m_required_size;\n\tfs::path m_target_path;\n\tstd::array<fs::path, 3> m_source_paths;\n\tbool ParseUpdate(const fs::path& metaPath);\n\n\tstd::atomic<uint64> m_processed_size = 0;\n\tstd::atomic<ThreadState_t> m_thread_state;\n\tstd::string m_thread_exception;\n\tstd::thread m_thread;\n\tvoid ThreadWork();\n\n\tfs::path m_backup_folder; // for prev update data\n\n\twxGauge* m_processBar;\n\twxTimer* m_timer;\n};\n"
  },
  {
    "path": "src/gui/wxgui/GeneralSettings2.cpp",
    "content": "#include \"wxCemuConfig.h\"\n#include \"wxgui/wxgui.h\"\n#include \"wxgui/GeneralSettings2.h\"\n#include \"wxgui/CemuApp.h\"\n#include \"wxgui/helpers/wxControlObject.h\"\n\n#include \"util/helpers/helpers.h\"\n\n#include \"Cafe/OS/libs/snd_core/ax.h\"\n\n#include <wx/collpane.h>\n#include <wx/clrpicker.h>\n#include <wx/cshelp.h>\n#include <wx/textctrl.h>\n#include <wx/textdlg.h>\n#include <wx/hyperlink.h>\n\n#include \"config/CemuConfig.h\"\n#include \"config/NetworkSettings.h\"\n\n#include \"audio/IAudioAPI.h\"\n#if BOOST_OS_WINDOWS\n#include \"audio/DirectSoundAPI.h\"\n#include \"audio/XAudio27API.h\"\n#endif\n#include \"audio/CubebAPI.h\"\n\n#include \"audio/IAudioInputAPI.h\"\n\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n#if ENABLE_METAL\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#endif\n#include \"Cafe/Account/Account.h\"\n\n#include <boost/tokenizer.hpp>\n#include \"util/helpers/SystemException.h\"\n#include \"wxgui/dialogs/CreateAccount/wxCreateAccountDialog.h\"\n\n#if BOOST_OS_WINDOWS\n#include <VersionHelpers.h>\n#endif\n\n#include \"config/LaunchSettings.h\"\n#include \"config/ActiveSettings.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n\n#include \"resource/embedded/resources.h\"\n\n#include \"Cafe/CafeSystem.h\"\n#include \"Cemu/ncrypto/ncrypto.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n#include \"wxHelper.h\"\n\n#include \"util/ScreenSaver/ScreenSaver.h\"\n\nconst wxString kDirectSound(\"DirectSound\");\nconst wxString kXAudio27(\"XAudio2.7\");\nconst wxString kXAudio2(\"XAudio2\");\nconst wxString kCubeb(\"Cubeb\");\n\nconst wxString kPropertyPersistentId(\"PersistentId\");\nconst wxString kPropertyMiiName(\"MiiName\");\nconst wxString kPropertyBirthday(\"Birthday\");\nconst wxString kPropertyGender(\"Gender\");\nconst wxString kPropertyEmail(\"Email\");\nconst wxString kPropertyCountry(\"Country\");\n\nwxDEFINE_EVENT(wxEVT_ACCOUNTLIST_REFRESH, wxCommandEvent);\n\nclass wxDeviceDescription : public wxClientData\n{\npublic:\n\twxDeviceDescription(const IAudioAPI::DeviceDescriptionPtr& description) : m_description(description) {}\n\tconst IAudioAPI::DeviceDescriptionPtr& GetDescription() const { return m_description; }\nprivate:\n\tIAudioAPI::DeviceDescriptionPtr m_description;\n};\n\nclass wxInputDeviceDescription : public wxClientData\n{\npublic:\n\twxInputDeviceDescription(const IAudioInputAPI::DeviceDescriptionPtr& description) : m_description(description) {}\n\tconst IAudioInputAPI::DeviceDescriptionPtr& GetDescription() const { return m_description; }\nprivate:\n\tIAudioInputAPI::DeviceDescriptionPtr m_description;\n};\n\nclass wxVulkanUUID : public wxClientData\n{\npublic:\n\twxVulkanUUID(const VulkanRenderer::DeviceInfo& info)\n\t\t: m_device_info(info) {}\n\tconst VulkanRenderer::DeviceInfo& GetDeviceInfo() const { return m_device_info; }\n\nprivate:\n\tVulkanRenderer::DeviceInfo m_device_info;\n};\n\n#if ENABLE_METAL\nclass wxMetalUUID : public wxClientData\n{\npublic:\n\twxMetalUUID(const MetalRenderer::DeviceInfo& info)\n\t\t: m_device_info(info) {}\n\tconst MetalRenderer::DeviceInfo& GetDeviceInfo() const { return m_device_info; }\n\nprivate:\n\tMetalRenderer::DeviceInfo m_device_info;\n};\n#endif\n\nclass wxAccountData : public wxClientData\n{\npublic:\n\twxAccountData(const Account& account)\n\t\t: m_account(account) {}\n\n\tAccount& GetAccount() { return m_account; }\n\tconst Account& GetAccount() const { return m_account; }\n\nprivate:\n\tAccount m_account;\n};\n\nwxPanel* GeneralSettings2::AddGeneralPage(wxNotebook* notebook)\n{\n\tauto* panel = new wxPanel(notebook);\n\tauto* general_panel_sizer = new wxBoxSizer(wxVERTICAL);\n\n\t{\n\t\tauto* box = new wxStaticBox(panel, wxID_ANY, _(\"Interface\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\t{\n\t\t\tauto* first_row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\t\tfirst_row->SetFlexibleDirection(wxBOTH);\n\t\t\tfirst_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\t\tfirst_row->Add(new wxStaticText(box, wxID_ANY, _(\"Language\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\twxString language_choices[] = { _(\"Default\") };\n\t\t\tm_language = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(language_choices), language_choices);\n\t\t\tm_language->SetSelection(0);\n\t\t\tm_language->SetToolTip(_(\"Changes the interface language of Cemu\\nAvailable languages are stored in the translation directory\\nA restart will be required after changing the language\"));\n\t\t\tfor (const auto& language : wxGetApp().GetLanguages())\n\t\t\t{\n\t\t\t\tm_language->Append(language->DescriptionNative);\n\t\t\t}\n\n\t\t\tfirst_row->Add(m_language, 0, wxALL | wxEXPAND, 5);\n\n\t\t\tbox_sizer->Add(first_row, 1, wxEXPAND, 5);\n\t\t}\n\n#if BOOST_OS_WINDOWS\n\t\t{\n\t\t\tauto* second_row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\t\tsecond_row->SetFlexibleDirection(wxBOTH);\n\t\t\tsecond_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\t\tsecond_row->Add(new wxStaticText(box, wxID_ANY, _(\"Theme\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\tm_msw_theme = new wxChoice(box, wxID_ANY);\n\t\t\tm_msw_theme->SetToolTip(_(\"Changes the Windows theme used by Cemu\\nThis only works on Windows 10 and later\\nA restart will be required for any changes to take effect\"));\n\n\t\t\tm_msw_theme->AppendString(_(\"Follow Windows theme\"));\n\t\t\tm_msw_theme->AppendString(_(\"Light Theme\"));\n\t\t\tm_msw_theme->AppendString(_(\"Dark Theme\"));\n\t\t\tm_msw_theme->SetSelection(0);\n\n\t\t\tsecond_row->Add(m_msw_theme, 0, wxALL, 5);\n\n\t\t\tbox_sizer->Add(second_row, 0, wxEXPAND, 5);\n\t\t}\n#endif\n\n\t\t{\n\t\t\tauto* third_row = new wxFlexGridSizer(0, 3, 0, 0);\n\t\t\tthird_row->SetFlexibleDirection(wxBOTH);\n\t\t\tthird_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\t\tsint32 checkboxCount = 0;\n\t\t\tauto CountRowElement = [&]()\n\t\t\t{\n\t\t\t\tcheckboxCount++;\n\t\t\t\tif(checkboxCount != 2)\n\t\t\t\t\treturn;\n\t\t\t\tthird_row->AddSpacer(10);\n\t\t\t\tcheckboxCount = 0;\n\t\t\t};\n\n\t\t\tauto InsertEmptyRow = [&]()\n\t\t\t{\n\t\t\t\twhile(checkboxCount != 0)\n\t\t\t\t\tCountRowElement();\n\t\t\t\tthird_row->AddSpacer(10);\n\t\t\t\tthird_row->AddSpacer(10);\n\t\t\t\tthird_row->AddSpacer(10);\n\t\t\t};\n\n\t\t\tconst int topflag = wxALIGN_CENTER_VERTICAL | wxALL;\n\t\t\tm_save_window_position_size = new wxCheckBox(box, wxID_ANY, _(\"Remember main window position\"));\n\t\t\tm_save_window_position_size->SetToolTip(_(\"Restores the last known window position and size when starting Cemu\"));\n\t\t\tthird_row->Add(m_save_window_position_size, 0, topflag, 5);\n\t\t\tCountRowElement();\n\t\t\t//third_row->AddSpacer(10);\n\t\t\tm_save_padwindow_position_size = new wxCheckBox(box, wxID_ANY, _(\"Remember pad window position\"));\n\t\t\tm_save_padwindow_position_size->SetToolTip(_(\"Restores the last known pad window position and size when opening it\"));\n\t\t\tthird_row->Add(m_save_padwindow_position_size, 0, topflag, 5);\n\t\t\tCountRowElement();\n\n\t\t\tconst int botflag = wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM;\n\t\t\tm_discord_presence = new wxCheckBox(box, wxID_ANY, _(\"Discord Presence\"));\n\t\t\tm_discord_presence->SetToolTip(_(\"Enables the Discord Rich Presence feature\\nYou will also need to enable it in the Discord settings itself!\"));\n\t\t\tthird_row->Add(m_discord_presence, 0, botflag, 5);\n\t\t\tCountRowElement();\n#ifndef ENABLE_DISCORD_RPC\n\t\t\tm_discord_presence->Disable();\n#endif\n\t\t\t// third_row->AddSpacer(10);\n\t\t\tm_fullscreen_menubar = new wxCheckBox(box, wxID_ANY, _(\"Fullscreen menu bar\"));\n\t\t\tm_fullscreen_menubar->SetToolTip(_(\"Displays the menu bar when Cemu is running in fullscreen mode and the mouse cursor is moved to the top\"));\n\t\t\tthird_row->Add(m_fullscreen_menubar, 0, botflag, 5);\n\t\t\tCountRowElement();\n\n\t\t\tm_save_screenshot = new wxCheckBox(box, wxID_ANY, _(\"Save screenshot\"));\n\t\t\tm_save_screenshot->SetToolTip(_(\"Pressing the screenshot key will save a screenshot directly to the screenshots folder instead of to the clipboard\"));\n\t\t\tthird_row->Add(m_save_screenshot, 0, botflag, 5);\n\t\t\tCountRowElement();\n\n\t\t\tm_disable_screensaver = new wxCheckBox(box, wxID_ANY, _(\"Disable screen saver\"));\n\t\t\tm_disable_screensaver->SetToolTip(_(\"Prevents the system from activating the screen saver or going to sleep while running a game.\"));\n\t\t\tthird_row->Add(m_disable_screensaver, 0, botflag, 5);\n\t\t\tCountRowElement();\n\n\t\t\t// enable/disable feral interactive gamemode\n#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)\n\t\t\tm_feral_gamemode = new wxCheckBox(box, wxID_ANY, _(\"Enable Feral GameMode\"));\n\t\t\tm_feral_gamemode->SetToolTip(_(\"Use FeralInteractive GameMode if installed.\"));\n\t\t\tthird_row->Add(m_feral_gamemode, 0, botflag, 5);\n\t\t\tCountRowElement();\n#endif\n\n\t\t\t// temporary workaround because feature crashes on macOS\n#if BOOST_OS_MACOS\n\t\t\tm_disable_screensaver->Enable(false);\n#endif\n\t\t\tm_play_boot_sound = new wxCheckBox(box, wxID_ANY, _(\"Enable intro sound\"));\n\t\t\tm_play_boot_sound->SetToolTip(_(\"Play bootSound file while compiling shaders/pipelines.\"));\n\t\t\tthird_row->Add(m_play_boot_sound, 0, botflag, 5);\n\t\t\tCountRowElement();\n\n\t\t\tm_auto_update = new wxCheckBox(box, wxID_ANY, _(\"Automatically check for updates\"));\n\t\t\tm_auto_update->SetToolTip(_(\"Automatically checks for new cemu versions on startup\"));\n\t\t\tthird_row->Add(m_auto_update, 0, botflag, 5);\n\t\t\tCountRowElement();\n\n\t\t\tm_receive_untested_releases = new wxCheckBox(box, wxID_ANY, _(\"Receive untested updates\"));\n\t\t\tm_receive_untested_releases->SetToolTip(_(\"When checking for updates, include brand new and untested releases. These may contain bugs!\"));\n\t\t\tthird_row->Add(m_receive_untested_releases, 0, botflag, 5);\n#if BOOST_OS_LINUX\n\t\t\tif (!std::getenv(\"APPIMAGE\")) {\n\t\t\t\tm_auto_update->Disable();\n\t\t\t}\n#elif BOOST_OS_BSD // BSD users must update from source so disable auto updates\n\t\t\tm_auto_update->Disable();\n#endif\n\n\t\t\tbox_sizer->Add(third_row, 0, wxEXPAND, 5);\n\t\t}\n\n\t\tgeneral_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\t{\n\t\tauto* outerMlcBox = new wxStaticBox(panel, wxID_ANY, _(\"Custom MLC path\"));\n\n\t\tauto* box_sizer_mlc = new wxStaticBoxSizer(outerMlcBox, wxVERTICAL);\n\t\tbox_sizer_mlc->Add(new wxStaticText(box_sizer_mlc->GetStaticBox(), wxID_ANY, _(\"You can configure a custom path for the emulated internal Wii U storage (MLC).\\nThis is where Cemu stores saves, accounts and other Wii U system files.\")), 0, wxALL, 5);\n\n\t\tauto* mlcPathLineSizer = new wxBoxSizer(wxHORIZONTAL);\n\n\t\tm_mlc_path = new wxTextCtrl(outerMlcBox, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY);\n\t\tm_mlc_path->SetMinSize(wxSize(150, -1));\n\t\tm_mlc_path->SetToolTip(_(\"The mlc directory contains your save games and installed game update/dlc data\"));\n\n\t\tmlcPathLineSizer->Add(m_mlc_path, 1, wxALL | wxEXPAND, 5);\n\n\t\tauto* changePath = new wxButton(outerMlcBox, wxID_ANY, \"Change\");\n\t\tchangePath->Bind(wxEVT_BUTTON, &GeneralSettings2::OnMLCPathSelect, this);\n\t\tmlcPathLineSizer->Add(changePath, 0, wxALL, 5);\n\t\tif (LaunchSettings::GetMLCPath().has_value())\n\t\t\tchangePath->Disable();\n\n\t\tauto* clearPath = new wxButton(outerMlcBox, wxID_ANY, \"Clear custom path\");\n\t\tclearPath->Bind(wxEVT_BUTTON, &GeneralSettings2::OnMLCPathClear, this);\n\t\tmlcPathLineSizer->Add(clearPath, 0, wxALL, 5);\n\t\tif (LaunchSettings::GetMLCPath().has_value() || !ActiveSettings::IsCustomMlcPath())\n\t\t\tclearPath->Disable();\n\n\t\tbox_sizer_mlc->Add(mlcPathLineSizer, 0, wxEXPAND, 5);\n\t\tgeneral_panel_sizer->Add(box_sizer_mlc, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\t{\n\t\tauto* general_gamepath_box = new wxStaticBox(panel, wxID_ANY, _(\"Game Paths\"));\n\t\tauto* general_gamepath_sizer = new wxStaticBoxSizer(general_gamepath_box, wxVERTICAL);\n\n\t\tm_game_paths = new wxListBox(general_gamepath_box, wxID_ANY);\n\t\tm_game_paths->SetMinSize(wxSize(150, 70));\n\t\tm_game_paths->SetToolTip(_(\"Add the root directory of your game(s). It will scan all directories in it for games\"));\n\t\tgeneral_gamepath_sizer->Add(m_game_paths, 1, wxALL | wxEXPAND, 5);\n\n\t\tauto* general_gamepath_buttons = new wxFlexGridSizer(0, 2, 0, 0);\n\t\tgeneral_gamepath_buttons->SetFlexibleDirection(wxBOTH);\n\t\tgeneral_gamepath_buttons->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tauto* general_gamepath_add_button = new wxButton(general_gamepath_box, wxID_ANY, _(\"Add\"));\n\t\tgeneral_gamepath_add_button->Bind(wxEVT_BUTTON, &GeneralSettings2::OnAddPathClicked, this);\n\t\tgeneral_gamepath_add_button->SetToolTip(_(\"Adds a game path to scan for games displayed in the game list\\nIf you have unpacked games, make sure to select the root folder of a game\"));\n\t\tgeneral_gamepath_buttons->Add(general_gamepath_add_button, 0, wxALL, 5);\n\n\t\tauto* general_gamepath_remove_button = new wxButton(general_gamepath_box, wxID_ANY, _(\"Remove\"));\n\t\tgeneral_gamepath_remove_button->Bind(wxEVT_BUTTON, &GeneralSettings2::OnRemovePathClicked, this);\n\t\tgeneral_gamepath_remove_button->SetToolTip(_(\"Removes the currently selected game path from the game list\"));\n\t\tgeneral_gamepath_buttons->Add(general_gamepath_remove_button, 0, wxALL, 5);\n\n\t\tgeneral_gamepath_sizer->Add(general_gamepath_buttons, 0, wxEXPAND, 5);\n\t\tgeneral_panel_sizer->Add(general_gamepath_sizer, 1, wxEXPAND | wxALL, 5);\n\t}\n\n\tpanel->SetSizerAndFit(general_panel_sizer);\n\n\treturn panel;\n}\n\nwxPanel* GeneralSettings2::AddGraphicsPage(wxNotebook* notebook)\n{\n\t// Graphics page\n\tauto graphics_panel = new wxPanel(notebook);\n\tauto graphics_panel_sizer = new wxBoxSizer(wxVERTICAL);\n\n\t{\n\t\tauto box = new wxStaticBox(graphics_panel, wxID_ANY, _(\"General\"));\n\t\tauto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\trow->SetFlexibleDirection(wxBOTH);\n\t\trow->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\trow->Add(new wxStaticText(box, wxID_ANY, _(\"Graphics API\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tsint32 api_size = 1;\n\t\twxString choices[3] = { \"OpenGL\" };\n\t\tif (g_vulkan_available)\n\t\t{\n\t\t\tchoices[api_size++] = \"Vulkan\";\n\t\t}\n#if ENABLE_METAL\n\t\tchoices[api_size++] = \"Metal\";\n#endif\n\n\t\tm_graphic_api = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, api_size, choices);\n\t\tm_graphic_api->SetSelection(0);\n\t\tif (api_size > 1)\n\t\t\tm_graphic_api->SetToolTip(_(\"Select one of the available graphic back ends\"));\n\t\tif (CafeSystem::IsTitleRunning())\n\t\t{\n\t\t\tm_graphic_api->Disable();\n\t\t\tm_graphic_api->SetToolTip(_(\"Graphics API cannot be changed while a title is running\"));\n\t\t}\n\t\trow->Add(m_graphic_api, 0, wxALL, 5);\n\t\tm_graphic_api->Bind(wxEVT_CHOICE, &GeneralSettings2::OnGraphicAPISelected, this);\n\n\t\trow->Add(new wxStaticText(box, wxID_ANY, _(\"Graphics Device\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_graphic_device = new wxChoice(box, wxID_ANY, wxDefaultPosition, { 230, -1 }, api_size, choices);\n\t\tm_graphic_device->SetSelection(0);\n\t\tm_graphic_device->SetToolTip(_(\"Select the used graphic device\"));\n\t\trow->Add(m_graphic_device, 0, wxALL, 5);\n\n\t\trow->Add(new wxStaticText(box, wxID_ANY, _(\"VSync\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_vsync = new wxChoice(box, wxID_ANY, wxDefaultPosition, { 230, -1 });\n\t\tm_vsync->SetToolTip(_(\"Controls the vsync state\"));\n\t\tm_vsync->Bind(wxEVT_CHOICE, [](wxCommandEvent& event) {\n\t\t\tGetConfig().vsync = event.GetSelection();\n\t\t});\n\t\trow->Add(m_vsync, 0, wxALL, 5);\n\n\t\tbox_sizer->Add(row, 0, wxEXPAND, 5);\n\n\t\tauto* graphic_misc_row = new wxFlexGridSizer(0, 2, 0, 0);\n\n\t\tm_async_compile = new wxCheckBox(box, wxID_ANY, _(\"Async shader compile\"));\n\t\tm_async_compile->SetToolTip(_(\"Enables async shader and pipeline compilation. Reduces stutter at the cost of objects not rendering for a short time.\\nVulkan only\"));\n\t\tgraphic_misc_row->Add(m_async_compile, 0, wxALL, 5);\n\n\t\tm_gx2drawdone_sync = new wxCheckBox(box, wxID_ANY, _(\"Full sync at GX2DrawDone()\"));\n\t\tm_gx2drawdone_sync->SetToolTip(_(\"If synchronization is requested by the game, the emulated CPU will wait for the GPU to finish all operations.\\nThis is more accurate behavior, but may cause lower performance\"));\n\t\tgraphic_misc_row->Add(m_gx2drawdone_sync, 0, wxALL, 5);\n\n#if ENABLE_METAL\n\t\tm_force_mesh_shaders = new wxCheckBox(box, wxID_ANY, _(\"Force mesh shaders\"));\n\t\tm_force_mesh_shaders->SetToolTip(_(\"Force mesh shaders on all GPUs that support them. Mesh shaders are disabled by default on Intel GPUs due to potential stability issues.\\nMetal only\"));\n\t\tgraphic_misc_row->Add(m_force_mesh_shaders, 0, wxALL, 5);\n#endif\n\n\t\tbox_sizer->Add(graphic_misc_row, 1, wxEXPAND, 5);\n\t\tgraphics_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\t{\n\t\tauto box = new wxStaticBox(graphics_panel, wxID_ANY, _(\"Gamma settings\"));\n\t\tauto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\t\tauto row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\trow->SetFlexibleDirection(wxBOTH);\n\t\trow->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tauto targetGammaLabel = new wxStaticText(box, wxID_ANY, _(\"Target Gamma\"));\n\t\trow->Add(targetGammaLabel, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_overrideGammaValue = new wxSpinCtrlDouble(box, wxID_ANY, \"2.2f\", wxDefaultPosition, {230, -1}, wxSP_ARROW_KEYS, 0.1f, 4.0f, 2.2f, 0.1f);\n\t\trow->Add(m_overrideGammaValue, 0, wxALL, 5);\n\t\tauto targetGammaTooltip = _(\"The display gamma to reproduce\\nIf you are unsure, set this to 2.2\");\n\t\ttargetGammaLabel->SetToolTip(targetGammaTooltip);\n\t\tm_overrideGammaValue->SetToolTip(targetGammaTooltip);\n\t\tm_overrideGammaValue->Bind(wxEVT_SPINCTRLDOUBLE, [](wxSpinDoubleEvent& event) {\n\t\t\t GetConfig().overrideGammaValue = event.GetValue();\n\t\t});\n\n\n\t\tauto displayGammaLabel = new wxStaticText(box, wxID_ANY, _(\"Display Gamma\"));\n\t\trow->Add(displayGammaLabel, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\twxBoxSizer* srgbCheckBoxSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\trow->Add(srgbCheckBoxSizer);\n\t\tm_userDisplayGamma = new wxSpinCtrlDouble(box, wxID_ANY, \"2.2f\", wxDefaultPosition, {230, -1}, wxSP_ARROW_KEYS, 0.1f, 4.0f, 2.2f, 0.1f);\n\n\t\tauto displayGammaTooltip = _(\"The gamma of your monitor\\nIf you are unsure, set this to 2.2\");\n\t\tm_userDisplayGamma->SetToolTip(displayGammaTooltip);\n\t\tdisplayGammaLabel->SetToolTip(displayGammaTooltip);\n\t\tm_userDisplayGamma->Bind(wxEVT_SPINCTRLDOUBLE, [](wxSpinDoubleEvent& event) {\n\t\t\t GetConfig().userDisplayGamma = event.GetValue();\n\t\t});\n\n\t\tm_userDisplayisSRGB = new wxCheckBox(box, wxID_ANY, \"sRGB\");\n\t\tm_userDisplayisSRGB->SetToolTip(_(\"Select this if Cemu is being displayed using a piecewise sRGB gamma curve.\\n\"\n\t\t\t\t\t\t\t\t\t\t  \"This is typically not the case so you can probably leave this unchecked.\\n\"\n\t\t\t\t\t\t\t\t\t\t  \"Exceptions include HDR displays (with HDR enabled), calibrated SDR displays with Windows 11's Auto Color Management enabled, \"\n\t\t\t\t\t\t\t\t\t\t  \"or when using a display profile with a VCGT tag that targets piecewise sRGB.\\n\"\n\t\t\t\t\t\t\t\t\t\t  \"When this box is selected Cemu will compensate for the piecewise curve to approximate the pure gamma curve of a TV.\\n\"\n\t\t\t\t\t\t\t\t\t\t  \"Colors will be more accurate, especially in dark scenes, but this may result in banding or crushed shadows, \"\n\t\t\t\t\t\t\t\t\t\t  \"so it is best if you display Cemu with pure gamma and do not use this setting.\"));\n\t\tm_userDisplayisSRGB->Bind(wxEVT_CHECKBOX, &GeneralSettings2::OnUserDisplaySRGBSelected, this);\n\n\t\tsrgbCheckBoxSizer->Add(m_userDisplayGamma, 0, wxALL, 5);\n\t\tsrgbCheckBoxSizer->Add(m_userDisplayisSRGB, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\trow->Add(new wxStaticText(box, wxID_ANY, _(\"Override Gamma\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_overrideGamma = new wxCheckBox(box, wxID_ANY, \"\", wxDefaultPosition, {230, -1});\n\t\tm_overrideGamma->SetToolTip(_(\"Ignore title's gamma preference\"));\n\t\tm_overrideGamma->Bind(wxEVT_CHECKBOX, [](wxCommandEvent& event) {\n\t\t\tGetConfig().overrideAppGammaPreference = event.IsChecked();\n\t\t});\n\t\trow->Add(m_overrideGamma, 0, wxALL, 5);\n\n\t\tbox_sizer->Add(row, 0, wxEXPAND, 5);\n\t\tgraphics_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\t{\n\t\twxString choices[] = { _(\"Bilinear\"), _(\"Bicubic\"), _(\"Hermite\"), _(\"Nearest Neighbor\") };\n\t\tm_upscale_filter = new wxRadioBox(graphics_panel, wxID_ANY, _(\"Upscale filter\"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 5, wxRA_SPECIFY_COLS);\n\t\tm_upscale_filter->SetToolTip(_(\"Upscaling filters are used when the game resolution is smaller than the window size\"));\n\t\tm_upscale_filter->Bind(wxEVT_RADIOBOX, [](wxCommandEvent& event) {\n\t\t\tGetConfig().upscale_filter = event.GetSelection();\n\t\t});\n\t\tgraphics_panel_sizer->Add(m_upscale_filter, 0, wxALL | wxEXPAND, 5);\n\n\t\tm_downscale_filter = new wxRadioBox(graphics_panel, wxID_ANY, _(\"Downscale filter\"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 5, wxRA_SPECIFY_COLS);\n\t\tm_downscale_filter->SetToolTip(_(\"Downscaling filters are used when the game resolution is bigger than the window size\"));\n\t\tm_downscale_filter->Bind(wxEVT_RADIOBOX, [](wxCommandEvent& event) {\n\t\t\tGetConfig().downscale_filter = event.GetSelection();\n\t\t});\n\t\tgraphics_panel_sizer->Add(m_downscale_filter, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t{\n\t\twxString choices[] = { _(\"Keep aspect ratio\"), _(\"Stretch\") };\n\t\tm_fullscreen_scaling = new wxRadioBox(graphics_panel, wxID_ANY, _(\"Fullscreen scaling\"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 5, wxRA_SPECIFY_COLS);\n\t\tm_fullscreen_scaling->SetToolTip(_(\"Controls the output aspect ratio when it doesn't match the ratio of the game\"));\n\t\tm_fullscreen_scaling->Bind(wxEVT_RADIOBOX, [](wxCommandEvent& event) {\n\t\t\tGetConfig().fullscreen_scaling = event.GetSelection();\n\t\t});\n\t\tgraphics_panel_sizer->Add(m_fullscreen_scaling, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\tgraphics_panel->SetSizerAndFit(graphics_panel_sizer);\n\treturn graphics_panel;\n}\n\nwxPanel* GeneralSettings2::AddAudioPage(wxNotebook* notebook)\n{\n\tauto audio_panel = new wxPanel(notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\tauto audio_panel_sizer = new wxBoxSizer(wxVERTICAL);\n\n\t{\n\t\tauto box = new wxStaticBox(audio_panel, wxID_ANY, _(\"General\"));\n\t\tauto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto audio_general_row = new wxFlexGridSizer(0, 3, 0, 0);\n\t\taudio_general_row->SetFlexibleDirection(wxBOTH);\n\t\taudio_general_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\taudio_general_row->Add(new wxStaticText(box, wxID_ANY, _(\"API\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tm_audio_api = new wxChoice(box, wxID_ANY);\n\t\tif (IAudioAPI::IsAudioAPIAvailable(IAudioAPI::DirectSound))\n\t\t\tm_audio_api->Append(kDirectSound);\n\t\tif (IAudioAPI::IsAudioAPIAvailable(IAudioAPI::XAudio27))\n\t\t\tm_audio_api->Append(kXAudio27);\n\t\tif (IAudioAPI::IsAudioAPIAvailable(IAudioAPI::XAudio2))\n\t\t\tm_audio_api->Append(kXAudio2);\n\t\tif (IAudioAPI::IsAudioAPIAvailable(IAudioAPI::Cubeb))\n\t\t\tm_audio_api->Append(kCubeb);\n\n\t\tm_audio_api->SetSelection(0);\n\t\tm_audio_api->SetToolTip(_(\"Select one of the available audio back ends\"));\n\t\taudio_general_row->Add(m_audio_api, 0, wxALL, 5);\n\n\t\tm_audio_api->Bind(wxEVT_CHOICE, &GeneralSettings2::OnAudioAPISelected, this);\n\n\t\taudio_general_row->AddSpacer(0);\n\n\t\taudio_general_row->Add(new wxStaticText(box, wxID_ANY, _(\"Latency\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_audio_latency = new wxSlider(box, wxID_ANY, 2, 0, IAudioAPI::kBlockCount - 1, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL);\n\t\tm_audio_latency->SetToolTip(_(\"Controls the amount of buffered audio data\\nHigher values will create a delay in audio playback, but may avoid audio problems when emulation is too slow\"));\n\t\taudio_general_row->Add(m_audio_latency, 0, wxEXPAND | wxALL, 5);\n\t\tauto latency_text = new wxStaticText(box, wxID_ANY, \"24ms\");\n\t\taudio_general_row->Add(latency_text, 0, wxALIGN_CENTER_VERTICAL | wxALL | wxALIGN_RIGHT, 5);\n\t\tm_audio_latency->Bind(wxEVT_SLIDER, &GeneralSettings2::OnLatencySliderChanged, this, wxID_ANY, wxID_ANY, new wxControlObject(latency_text));\n\t\tm_audio_latency->Bind(wxEVT_SLIDER, &GeneralSettings2::OnAudioLatencyChanged, this);\n\n\t\tbox_sizer->Add(audio_general_row, 1, wxEXPAND, 5);\n\t\taudio_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\tconst wxString audio_channel_choices[] = { _(\"Mono\"), _(\"Stereo\") , _(\"Surround\") };\n\t{\n\t\tauto box = new wxStaticBox(audio_panel, wxID_ANY, _(\"TV\"));\n\t\tauto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto audio_tv_row = new wxFlexGridSizer(0, 3, 0, 0);\n\t\taudio_tv_row->SetFlexibleDirection(wxBOTH);\n\t\taudio_tv_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\taudio_tv_row->Add(new wxStaticText(box, wxID_ANY, _(\"Device\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_tv_device = new wxChoice(box, wxID_ANY);\n\t\tm_tv_device->SetMinSize(wxSize(300, -1));\n\t\tm_tv_device->SetToolTip(_(\"Select the active audio output device for Wii U TV\"));\n\t\taudio_tv_row->Add(m_tv_device, 0, wxEXPAND | wxALL, 5);\n\t\taudio_tv_row->AddSpacer(0);\n\n\t\tm_tv_device->Bind(wxEVT_CHOICE, &GeneralSettings2::OnAudioDeviceSelected, this);\n\n\t\taudio_tv_row->Add(new wxStaticText(box, wxID_ANY, _(\"Channels\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tm_tv_channels = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(audio_channel_choices), audio_channel_choices);\n\n\t\tm_tv_channels->SetSelection(1); // set default to stereo\n\t\tm_tv_channels->Bind(wxEVT_CHOICE, &GeneralSettings2::OnAudioChannelsSelected, this);\n\t\taudio_tv_row->Add(m_tv_channels, 0, wxEXPAND | wxALL, 5);\n\t\taudio_tv_row->AddSpacer(0);\n\n\t\taudio_tv_row->Add(new wxStaticText(box, wxID_ANY, _(\"Volume\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_tv_volume = new wxSlider(box, wxID_ANY, 100, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL);\n\t\taudio_tv_row->Add(m_tv_volume, 0, wxEXPAND | wxALL, 5);\n\t\tauto audio_tv_volume_text = new wxStaticText(box, wxID_ANY, \"100%\");\n\t\taudio_tv_row->Add(audio_tv_volume_text, 0, wxALIGN_CENTER_VERTICAL | wxALL | wxALIGN_RIGHT, 5);\n\n\t\tm_tv_volume->Bind(wxEVT_SLIDER, &GeneralSettings2::OnSliderChangedPercent, this, wxID_ANY, wxID_ANY, new wxControlObject(audio_tv_volume_text));\n\t\tm_tv_volume->Bind(wxEVT_SLIDER, &GeneralSettings2::OnVolumeChanged, this);\n\n\t\tbox_sizer->Add(audio_tv_row, 1, wxEXPAND, 5);\n\t\taudio_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\t{\n\t\tauto box = new wxStaticBox(audio_panel, wxID_ANY, _(\"Gamepad\"));\n\t\tauto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto audio_pad_row = new wxFlexGridSizer(0, 3, 0, 0);\n\t\taudio_pad_row->SetFlexibleDirection(wxBOTH);\n\t\taudio_pad_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\taudio_pad_row->Add(new wxStaticText(box, wxID_ANY, _(\"Device\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_pad_device = new wxChoice(box, wxID_ANY);\n\t\tm_pad_device->SetMinSize(wxSize(300, -1));\n\t\tm_pad_device->SetToolTip(_(\"Select the active audio output device for Wii U GamePad\"));\n\t\taudio_pad_row->Add(m_pad_device, 0, wxEXPAND | wxALL, 5);\n\t\taudio_pad_row->AddSpacer(0);\n\n\t\tm_pad_device->Bind(wxEVT_CHOICE, &GeneralSettings2::OnAudioDeviceSelected, this);\n\n\t\tconst wxString audio_channel_drc_choices[] = { _(\"Stereo\") }; // stereo for now only\n\n\t\taudio_pad_row->Add(new wxStaticText(box, wxID_ANY, _(\"Channels\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_pad_channels = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(audio_channel_drc_choices), audio_channel_drc_choices);\n\n\t\tm_pad_channels->SetSelection(0); // set default to stereo\n\n\t\tm_pad_channels->Bind(wxEVT_CHOICE, &GeneralSettings2::OnAudioChannelsSelected, this);\n\t\taudio_pad_row->Add(m_pad_channels, 0, wxEXPAND | wxALL, 5);\n\t\taudio_pad_row->AddSpacer(0);\n\n\t\taudio_pad_row->Add(new wxStaticText(box, wxID_ANY, _(\"Volume\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_pad_volume = new wxSlider(box, wxID_ANY, 100, 0, 100);\n\t\taudio_pad_row->Add(m_pad_volume, 0, wxEXPAND | wxALL, 5);\n\t\tauto audio_pad_volume_text = new wxStaticText(box, wxID_ANY, \"100%\");\n\t\taudio_pad_row->Add(audio_pad_volume_text, 0, wxALIGN_CENTER_VERTICAL | wxALL | wxALIGN_RIGHT, 5);\n\n\t\tm_pad_volume->Bind(wxEVT_SLIDER, &GeneralSettings2::OnSliderChangedPercent, this, wxID_ANY, wxID_ANY, new wxControlObject(audio_pad_volume_text));\n\t\tm_pad_volume->Bind(wxEVT_SLIDER, &GeneralSettings2::OnVolumeChanged, this);\n\n\t\tbox_sizer->Add(audio_pad_row, 1, wxEXPAND, 5);\n\t\taudio_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\t{\n\t\tauto box = new wxStaticBox(audio_panel, wxID_ANY, _(\"Microphone (Experimental)\"));\n\t\tauto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto audio_input_row = new wxFlexGridSizer(0, 3, 0, 0);\n\t\taudio_input_row->SetFlexibleDirection(wxBOTH);\n\t\taudio_input_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\taudio_input_row->Add(new wxStaticText(box, wxID_ANY, _(\"Device\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_input_device = new wxChoice(box, wxID_ANY);\n\t\tm_input_device->SetMinSize(wxSize(300, -1));\n\t\tm_input_device->SetToolTip(_(\"Select the active audio input device for Wii U GamePad\"));\n\t\taudio_input_row->Add(m_input_device, 0, wxEXPAND | wxALL, 5);\n\t\taudio_input_row->AddSpacer(0);\n\n\t\tm_input_device->Bind(wxEVT_CHOICE, &GeneralSettings2::OnAudioDeviceSelected, this);\n\n\t\tconst wxString audio_channel_drc_choices[] = { _(\"Mono\") }; // mono for now only\n\n\t\taudio_input_row->Add(new wxStaticText(box, wxID_ANY, _(\"Channels\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_input_channels = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(audio_channel_drc_choices), audio_channel_drc_choices);\n\n\t\tm_input_channels->SetSelection(0); // set default to stereo\n\n\t\tm_input_channels->Bind(wxEVT_CHOICE, &GeneralSettings2::OnAudioChannelsSelected, this);\n\t\taudio_input_row->Add(m_input_channels, 0, wxEXPAND | wxALL, 5);\n\t\taudio_input_row->AddSpacer(0);\n\n\t\taudio_input_row->Add(new wxStaticText(box, wxID_ANY, _(\"Volume\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_input_volume = new wxSlider(box, wxID_ANY, 100, 0, 100);\n\t\taudio_input_row->Add(m_input_volume, 0, wxEXPAND | wxALL, 5);\n\t\tauto audio_input_volume_text = new wxStaticText(box, wxID_ANY, \"100%\");\n\t\taudio_input_row->Add(audio_input_volume_text, 0, wxALIGN_CENTER_VERTICAL | wxALL | wxALIGN_RIGHT, 5);\n\n\t\tm_input_volume->Bind(wxEVT_SLIDER, &GeneralSettings2::OnSliderChangedPercent, this, wxID_ANY, wxID_ANY, new wxControlObject(audio_input_volume_text));\n\t\tm_input_volume->Bind(wxEVT_SLIDER, &GeneralSettings2::OnVolumeChanged, this);\n\n\t\tbox_sizer->Add(audio_input_row, 1, wxEXPAND, 5);\n\t\taudio_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\t{\n\t\tauto box = new wxStaticBox(audio_panel, wxID_ANY, _(\"Trap Team Portal\"));\n\t\tauto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto portal_audio_row = new wxFlexGridSizer(0, 3, 0, 0);\n\t\tportal_audio_row->SetFlexibleDirection(wxBOTH);\n\t\tportal_audio_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tportal_audio_row->Add(new wxStaticText(box, wxID_ANY, _(\"Device\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_portal_device = new wxChoice(box, wxID_ANY, wxDefaultPosition);\n\t\tm_portal_device->SetMinSize(wxSize(300, -1));\n\t\tm_portal_device->SetToolTip(_(\"Select the active audio output device for Wii U GamePad\"));\n\t\tportal_audio_row->Add(m_portal_device, 0, wxEXPAND | wxALL, 5);\n\t\tportal_audio_row->AddSpacer(0);\n\n\t\tm_portal_device->Bind(wxEVT_CHOICE, &GeneralSettings2::OnAudioDeviceSelected, this);\n\n\t\tportal_audio_row->Add(new wxStaticText(box, wxID_ANY, _(\"Volume\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_portal_volume = new wxSlider(box, wxID_ANY, 100, 0, 100);\n\t\tportal_audio_row->Add(m_portal_volume, 0, wxEXPAND | wxALL, 5);\n\t\tauto audio_pad_volume_text = new wxStaticText(box, wxID_ANY, \"100%\");\n\t\tportal_audio_row->Add(audio_pad_volume_text, 0, wxALIGN_CENTER_VERTICAL | wxALL | wxALIGN_RIGHT, 5);\n\n\t\tm_portal_volume->Bind(wxEVT_SLIDER, &GeneralSettings2::OnSliderChangedPercent, this, wxID_ANY, wxID_ANY, new wxControlObject(audio_pad_volume_text));\n\t\tm_portal_volume->Bind(wxEVT_SLIDER, &GeneralSettings2::OnVolumeChanged, this);\n\n\t\tbox_sizer->Add(portal_audio_row, 1, wxEXPAND, 5);\n\t\taudio_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\taudio_panel->SetSizerAndFit(audio_panel_sizer);\n\treturn audio_panel;\n}\n\nwxPanel* GeneralSettings2::AddOverlayPage(wxNotebook* notebook)\n{\n\tauto* panel = new wxPanel(notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\tauto* panel_sizer = new wxBoxSizer(wxVERTICAL);\n\n\tconst wxString positions[]{ _(\"Disabled\"), _(\"Top left\"), _(\"Top center\"), _(\"Top right\"), _(\"Bottom left\"), _(\"Bottom center\"), _(\"Bottom right\") };\n\tconst wxString text_scale[]{ \"50%\", \"75%\", \"100%\", \"125%\", \"150%\", \"175%\", \"200%\", \"225%\", \"250%\", \"275%\", \"300%\" };\n\t{\n\t\tauto box = new wxStaticBox(panel, wxID_ANY, _(\"Overlay\"));\n\t\tauto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto position_row = new wxFlexGridSizer(1, 0, 0, 0);\n\t\tposition_row->SetFlexibleDirection(wxBOTH);\n\t\tposition_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\t\t{\n\t\t\tposition_row->Add(new wxStaticText(box, wxID_ANY, _(\"Position\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\tm_overlay_position = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(positions), positions);\n\t\t\tm_overlay_position->SetSelection(0);\n\t\t\tm_overlay_position->SetToolTip(_(\"Controls the overlay which displays technical information while playing\"));\n\t\t\tposition_row->Add(m_overlay_position, 0, wxALL, 5);\n\n\t\t\tposition_row->AddSpacer(25);\n\n\t\t\tposition_row->Add(new wxStaticText(box, wxID_ANY, _(\"Text Color\")), 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5);\n\t\t\tm_overlay_font_color = new wxColourPickerCtrl(box, wxID_ANY, *wxWHITE, wxDefaultPosition, wxDefaultSize, wxCLRP_SHOW_ALPHA);\n\t\t\tm_overlay_font_color->SetToolTip(_(\"Sets the text color of the overlay\"));\n\t\t\tposition_row->Add(m_overlay_font_color, 0, wxEXPAND | wxALL, 5);\n\n\t\t\tposition_row->AddSpacer(25);\n\n\t\t\tposition_row->Add(new wxStaticText(box, wxID_ANY, _(\"Scale\")), 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5);\n\t\t\tm_overlay_scale = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(text_scale), text_scale);\n\t\t\tm_overlay_scale->SetToolTip(_(\"Sets the scale of the overlay text\"));\n\t\t\tposition_row->Add(m_overlay_scale, 0, wxEXPAND | wxALL, 5);\n\t\t}\n\t\tbox_sizer->Add(position_row, 0, wxEXPAND, 5);\n\n\t\tauto settings2_row = new wxFlexGridSizer(0, 4, 2, 0);\n\t\t{\n\t\t\tm_overlay_fps = new wxCheckBox(box, wxID_ANY, _(\"FPS\"));\n\t\t\tm_overlay_fps->SetToolTip(_(\"The number of frames per second. Average over last 5 seconds\"));\n\t\t\tsettings2_row->Add(m_overlay_fps, 0, wxALL, 5);\n\n\t\t\tm_overlay_drawcalls = new wxCheckBox(box, wxID_ANY, _(\"Draw calls per frame\"));\n\t\t\tm_overlay_drawcalls->SetToolTip(_(\"The number of draw calls per frame. Average over last 5 seconds\"));\n\t\t\tsettings2_row->Add(m_overlay_drawcalls, 0, wxALL, 5);\n\n\t\t\tm_overlay_cpu = new wxCheckBox(box, wxID_ANY, _(\"CPU usage\"));\n\t\t\tm_overlay_cpu->SetToolTip(_(\"CPU usage of Cemu in percent\"));\n\t\t\tsettings2_row->Add(m_overlay_cpu, 0, wxALL, 5);\n\n\t\t\tm_overlay_cpu_per_core = new wxCheckBox(box, wxID_ANY, _(\"CPU per core usage\"));\n\t\t\tm_overlay_cpu_per_core->SetToolTip(_(\"Total cpu usage in percent for each core\"));\n\t\t\tsettings2_row->Add(m_overlay_cpu_per_core, 0, wxALL, 5);\n\n\t\t\tm_overlay_ram = new wxCheckBox(box, wxID_ANY, _(\"RAM usage\"));\n\t\t\tm_overlay_ram->SetToolTip(_(\"Cemu RAM usage in MB\"));\n\t\t\tsettings2_row->Add(m_overlay_ram, 0, wxALL, 5);\n\n\t\t\tm_overlay_vram = new wxCheckBox(box, wxID_ANY, _(\"VRAM usage\"));\n#if BOOST_OS_WINDOWS\n\t\t\tusing RtlGetVersion_t = LONG(WINAPI*)(PRTL_OSVERSIONINFOW lpVersionInformation);\n\t\t\tconst auto pRtlGetVersion = (RtlGetVersion_t)GetProcAddress(GetModuleHandleA(\"ntdll.dll\"), \"RtlGetVersion\");\n\t\t\t//if(IsWindows8Point1OrGreater()) requires manifest\n\t\t\tRTL_OSVERSIONINFOW info{};\n\t\t\t// Windows 8.1 \t6.3*\n\t\t\tif (pRtlGetVersion && pRtlGetVersion(&info) == 0 && ((info.dwMajorVersion == 6 && info.dwMinorVersion >= 3) || info.dwMajorVersion > 6))\n\t\t\t\tm_overlay_vram->SetToolTip(_(\"The VRAM usage of Cemu in MB\"));\n\t\t\telse\n\t\t\t{\n\t\t\t\tm_overlay_vram->SetToolTip(_(\"This option requires Win8.1+\"));\n\t\t\t\tm_overlay_vram->Disable();\n\t\t\t}\n#else\n\t\t\tm_overlay_vram->SetToolTip(_(\"The VRAM usage of Cemu in MB\"));\n#endif\n\n\t\t\tsettings2_row->Add(m_overlay_vram, 0, wxALL, 5);\n\n\t\t\tm_overlay_debug = new wxCheckBox(box, wxID_ANY, _(\"Debug\"));\n\t\t\tm_overlay_debug->SetToolTip(_(\"Displays internal debug information (Vulkan only)\"));\n\t\t\tsettings2_row->Add(m_overlay_debug, 0, wxALL, 5);\n\t\t}\n\t\tbox_sizer->Add(settings2_row, 0, wxEXPAND, 5);\n\n\t\tpanel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\t{\n\t\tauto box = new wxStaticBox(panel, wxID_ANY, _(\"Notifications\"));\n\t\tauto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto position_row = new wxFlexGridSizer(1, 0, 0, 0);\n\t\tposition_row->SetFlexibleDirection(wxBOTH);\n\t\tposition_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\t\t{\n\t\t\tposition_row->Add(new wxStaticText(box, wxID_ANY, _(\"Position\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\tm_notification_position = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(positions), positions);\n\t\t\tm_notification_position->SetSelection(0);\n\t\t\tm_notification_position->SetToolTip(_(\"Controls the notification position while playing\"));\n\t\t\tposition_row->Add(m_notification_position, 0, wxALL, 5);\n\n\t\t\tposition_row->AddSpacer(25);\n\n\t\t\tposition_row->Add(new wxStaticText(box, wxID_ANY, _(\"Text Color\")), 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5);\n\t\t\tm_notification_font_color = new wxColourPickerCtrl(box, wxID_ANY, *wxWHITE, wxDefaultPosition, wxDefaultSize, wxCLRP_SHOW_ALPHA);\n\t\t\tm_notification_font_color->SetToolTip(_(\"Sets the text color of notifications\"));\n\t\t\tposition_row->Add(m_notification_font_color, 0, wxEXPAND | wxALL, 5);\n\n\t\t\tposition_row->Add(new wxStaticText(box, wxID_ANY, _(\"Scale\")), 0, wxALL | wxALIGN_CENTRE_VERTICAL, 5);\n\t\t\tm_notification_scale = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(text_scale), text_scale);\n\t\t\tm_notification_scale->SetToolTip(_(\"Sets the scale of the notification text\"));\n\t\t\tposition_row->Add(m_notification_scale, 0, wxEXPAND | wxALL, 5);\n\t\t}\n\t\tbox_sizer->Add(position_row, 0, wxEXPAND, 5);\n\n\t\tauto settings1_row = new wxFlexGridSizer(1, 0, 2, 0);\n\t\t{\n\t\t\tm_controller_profile_name = new wxCheckBox(box, wxID_ANY, _(\"Controller profiles\"));\n\t\t\tm_controller_profile_name->SetToolTip(_(\"Displays the active controller profile when starting a game\"));\n\t\t\tsettings1_row->Add(m_controller_profile_name, 0, wxALL, 5);\n\n\t\t\tm_controller_low_battery = new wxCheckBox(box, wxID_ANY, _(\"Low battery\"));\n\t\t\tm_controller_low_battery->SetToolTip(_(\"Shows a notification when a low controller battery has been detected\"));\n\t\t\tsettings1_row->Add(m_controller_low_battery, 0, wxALL, 5);\n\n\t\t\tm_shader_compiling = new wxCheckBox(box, wxID_ANY, _(\"Shader compiler\"));\n\t\t\tm_shader_compiling->SetToolTip(_(\"Shows a notification after shaders have been compiled\"));\n\t\t\tsettings1_row->Add(m_shader_compiling, 0, wxALL, 5);\n\n\t\t\tm_friends_data = new wxCheckBox(box, wxID_ANY, _(\"Friend list\"));\n\t\t\tm_friends_data->SetToolTip(_(\"Shows friend list related data if online\"));\n\t\t\tsettings1_row->Add(m_friends_data, 0, wxALL, 5);\n\t\t}\n\t\tbox_sizer->Add(settings1_row, 0, wxEXPAND, 5);\n\n\n\t\tpanel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\tpanel->SetSizerAndFit(panel_sizer);\n\n\treturn panel;\n}\n\nwxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook)\n{\n\tauto* online_panel = new wxPanel(notebook);\n\tauto* online_panel_sizer = new wxBoxSizer(wxVERTICAL);\n\n\t{\n\t\tauto* box = new wxStaticBox(online_panel, wxID_ANY, _(\"Account settings\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto* content = new wxFlexGridSizer(0, 4, 0, 0);\n\t\tcontent->SetFlexibleDirection(wxBOTH);\n\t\tcontent->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\t\tcontent->AddGrowableCol(1, 1);\n\t\tcontent->AddGrowableCol(2, 0);\n\t\tcontent->AddGrowableCol(3, 0);\n\n\t\tcontent->Add(new wxStaticText(box, wxID_ANY, _(\"Active account\")), 1, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tm_active_account = new wxChoice(box, wxID_ANY);\n\t\tm_active_account->SetMinSize({ 250, -1 });\n\t\tcontent->Add(m_active_account, 0, wxEXPAND | wxALL, 5);\n\t\tm_active_account->Bind(wxEVT_CHOICE, &GeneralSettings2::OnActiveAccountChanged, this);\n\n\t\tm_create_account = new wxButton(box, wxID_ANY, _(\"Create\"));\n\t\tcontent->Add(m_create_account, 0, wxEXPAND | wxALL | wxALIGN_RIGHT, 5);\n\t\tm_create_account->Bind(wxEVT_BUTTON, &GeneralSettings2::OnAccountCreate, this);\n\n\t\tm_delete_account = new wxButton(box, wxID_ANY, _(\"Delete\"));\n\t\tcontent->Add(m_delete_account, 0, wxEXPAND | wxALL | wxALIGN_RIGHT, 5);\n\t\tm_delete_account->Bind(wxEVT_BUTTON, &GeneralSettings2::OnAccountDelete, this);\n\n\t\tbox_sizer->Add(content, 1, wxEXPAND, 5);\n\n\t\tonline_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\n\t\tif (CafeSystem::IsTitleRunning())\n\t\t{\n\t\t\tm_active_account->Enable(false);\n\t\t\tm_create_account->Enable(false);\n\t\t\tm_delete_account->Enable(false);\n\t\t}\n\t}\n\n\n\t{\n\t\twxString choices[] = { _(\"Offline\"),  _(\"Nintendo\"), _(\"Pretendo\"), _(\"Custom\") };\n\t\tm_active_service = new wxRadioBox(online_panel, wxID_ANY, _(\"Network Service\"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 4, wxRA_SPECIFY_COLS);\n\t\tif (!NetworkConfig::XMLExists())\n\t\t\tm_active_service->Enable(3, false);\n\n\t\tm_active_service->SetItemToolTip(0, _(\"Online functionality disabled for this account\"));\n\t\tm_active_service->SetItemToolTip(1, _(\"Connect to the official Nintendo Network Service\"));\n\t\tm_active_service->SetItemToolTip(2, _(\"Connect to the Pretendo Network Service\"));\n\t\tm_active_service->SetItemToolTip(3, _(\"Connect to a custom Network Service (configured via network_services.xml)\"));\n\n\t\tm_active_service->Bind(wxEVT_RADIOBOX, &GeneralSettings2::OnAccountServiceChanged,this);\n\t\tonline_panel_sizer->Add(m_active_service, 0, wxEXPAND | wxALL, 5);\n\n\t\tif (CafeSystem::IsTitleRunning())\n\t\t{\n\t\t\tm_active_service->Enable(false);\n\t\t}\n\t}\n\n\t{\n\t\tauto* box = new wxStaticBox(online_panel, wxID_ANY, _(\"Online play requirements\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto* row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\trow->SetFlexibleDirection(wxBOTH);\n\t\trow->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tconst wxImage tmp = wxBITMAP_PNG_FROM_DATA(PNG_ERROR).ConvertToImage();\n\t\tm_validate_online = new wxBitmapButton(box, wxID_ANY, tmp.Scale(16, 16));\n\t\tm_validate_online->Bind(wxEVT_BUTTON, &GeneralSettings2::OnShowOnlineValidator, this);\n\t\trow->Add(m_validate_online, 0, wxEXPAND | wxALL, 5);\n\n\t\tm_online_status = new wxStaticText(box, wxID_ANY, _(\"No account selected\"));\n\t\trow->Add(m_online_status, 1, wxALL | wxALIGN_CENTRE_VERTICAL, 5);\n\n\t\tbox_sizer->Add(row, 1, wxEXPAND, 5);\n\n\t\tauto* tutorial_link = new wxHyperlinkCtrl(box, wxID_ANY, _(\"Online play tutorial\"), \"https://cemu.info/online-guide\");\n\t\tbox_sizer->Add(tutorial_link, 0, wxALL, 5);\n\n\n\t\tonline_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\t{\n\t\tm_account_information = new wxCollapsiblePane(online_panel, wxID_ANY, _(\"Account information\"));\n\t\tauto win = m_account_information->GetPane();\n\n\t\tauto content = new wxBoxSizer(wxVERTICAL);\n\n\t\tm_account_grid = new wxPropertyGrid(win, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_HIDE_MARGIN | wxPG_STATIC_SPLITTER);\n\t\tm_account_grid->SetExtraStyle(wxPG_EX_HELP_AS_TOOLTIPS);\n\t\tm_account_grid->SetMinSize({ 300, -1 });\n\t\t//m_account_grid->Append(new wxPropertyCategory(\"Main\"));\n\n\t\tauto* persistent_id_gprop = m_account_grid->Append(new wxStringProperty(\"PersistentId\", kPropertyPersistentId));\n\t\tpersistent_id_gprop->SetHelpString(_(\"The persistent id is the internal folder name used for your saves\"));\n\t\tm_account_grid->SetPropertyReadOnly(persistent_id_gprop);\n\n\t\tm_account_grid->Append(new wxStringProperty(_(\"Mii name\"), kPropertyMiiName))->SetHelpString(_(\"The mii name is the profile name\"));\n\t\tm_account_grid->Append(new wxStringProperty(_(\"Birthday\"), kPropertyBirthday));\n\n\t\twxPGChoices gender;\n\t\tgender.Add(_(\"Female\"), 0);\n\t\tgender.Add(_(\"Male\"), 1);\n\t\tm_account_grid->Append(new wxEnumProperty(_(\"Gender\"), kPropertyGender, gender));\n\n\t\tm_account_grid->Append(new wxStringProperty(_(\"Email\"), kPropertyEmail));\n\n\t\twxPGChoices countries;\n\t\tfor (int i = 0; i < NCrypto::GetCountryCount(); ++i)\n\t\t{\n\t\t\tconst auto country = NCrypto::GetCountryAsString(i);\n\t\t\tif (country && (i == 0 || !boost::equals(country, \"NN\")))\n\t\t\t{\n\t\t\t\tcountries.Add(country, i);\n\t\t\t}\n\t\t}\n\t\tm_account_grid->Append(new wxEnumProperty(_(\"Country\"), kPropertyCountry, countries));\n\n\t\tm_account_grid->Bind(wxEVT_PG_CHANGED, &GeneralSettings2::OnAccountSettingsChanged, this);\n\n\t\tcontent->Add(m_account_grid, 1, wxEXPAND | wxALL, 5);\n\n\t\twin->SetSizer(content);\n\t\tcontent->SetSizeHints(win);\n\n\t\tonline_panel_sizer->Add(m_account_information, 0, wxEXPAND | wxALL, 5);\n\t}\n\n\tonline_panel->SetSizerAndFit(online_panel_sizer);\n\treturn online_panel;\n}\n\nwxPanel* GeneralSettings2::AddDebugPage(wxNotebook* notebook)\n{\n\tauto* panel = new wxPanel(notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\tauto* debug_panel_sizer = new wxBoxSizer(wxVERTICAL);\n\n\t{\n\t\tauto* debug_row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\tdebug_row->SetFlexibleDirection(wxBOTH);\n\t\tdebug_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tdebug_row->Add(new wxStaticText(panel, wxID_ANY, _(\"Crash dump\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n#if BOOST_OS_WINDOWS\n\t\twxString dump_choices[] = {_(\"Disabled\"), _(\"Lite\"), _(\"Full\")};\n#elif BOOST_OS_UNIX\n\t\twxString dump_choices[] = {_(\"Disabled\"), _(\"Enabled\")};\n#endif\n\t\tm_crash_dump = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(dump_choices), dump_choices);\n\t\tm_crash_dump->SetSelection(0);\n#if BOOST_OS_WINDOWS\n\t\tm_crash_dump->SetToolTip(_(\"Creates a dump when Cemu crashes\\nOnly enable when requested by a developer!\\nThe Full option will create a very large dump file (includes a full RAM dump of the Cemu process)\"));\n#elif BOOST_OS_UNIX\n\t\tm_crash_dump->SetToolTip(_(\"Creates a core dump when Cemu crashes\\nOnly enable when requested by a developer!\"));\n#endif\n\t\tdebug_row->Add(m_crash_dump, 0, wxALL | wxEXPAND, 5);\n\t\tdebug_panel_sizer->Add(debug_row, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t{\n\t\tauto* debug_row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\tdebug_row->SetFlexibleDirection(wxBOTH);\n\t\tdebug_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tdebug_row->Add(new wxStaticText(panel, wxID_ANY, _(\"GDB Stub port\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tm_gdb_port = new wxSpinCtrl(panel, wxID_ANY, \"1337\", wxDefaultPosition, wxDefaultSize, 0, 1000, 65535);\n\t\tm_gdb_port->SetToolTip(_(\"Changes the port that the GDB stub will use, which you can use by either starting Cemu with the --enable-gdbstub option or by enabling it the Debug tab.\"));\n\n\t\tdebug_row->Add(m_gdb_port, 0, wxALL | wxEXPAND, 5);\n\t\tdebug_panel_sizer->Add(debug_row, 0, wxALL | wxEXPAND, 5);\n\t}\n\n#if ENABLE_METAL\n\t{\n\t\tauto* debug_row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\tdebug_row->SetFlexibleDirection(wxBOTH);\n\t\tdebug_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tdebug_row->Add(new wxStaticText(panel, wxID_ANY, _(\"GPU capture save directory\"), wxDefaultPosition, wxDefaultSize, 0), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tm_gpu_capture_dir = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_DONTWRAP);\n\t\tm_gpu_capture_dir->SetMinSize(wxSize(150, -1));\n\t\tm_gpu_capture_dir->SetToolTip(_(\"Cemu will save the GPU captures done by selecting Debug -> GPU capture (Metal) in the menu bar in this directory. If a debugger with support for GPU captures (like Xcode) is attached, the capture will be opened in that debugger instead. If such debugger is not attached, METAL_CAPTURE_ENABLED must be set to 1 as an environment variable.\"));\n\n\t\tdebug_row->Add(m_gpu_capture_dir, 0, wxALL | wxEXPAND, 5);\n\t\tdebug_panel_sizer->Add(debug_row, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t{\n\t\tauto* debug_row = new wxFlexGridSizer(0, 2, 0, 0);\n\t\tdebug_row->SetFlexibleDirection(wxBOTH);\n\t\tdebug_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tm_framebuffer_fetch = new wxCheckBox(panel, wxID_ANY, _(\"Framebuffer fetch\"));\n\t\tm_framebuffer_fetch->SetToolTip(_(\"Enable framebuffer fetch for eligible textures on supported devices.\\nMetal only\"));\n\n\t\tdebug_row->Add(m_framebuffer_fetch, 0, wxALL | wxEXPAND, 5);\n\t\tdebug_panel_sizer->Add(debug_row, 0, wxALL | wxEXPAND, 5);\n\t}\n#endif\n\n\tpanel->SetSizerAndFit(debug_panel_sizer);\n\n\treturn panel;\n}\n\nGeneralSettings2::GeneralSettings2(wxWindow* parent, bool game_launched)\n\t: wxDialog(parent, wxID_ANY, _(\"General settings\"), wxDefaultPosition, wxDefaultSize, wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER), m_game_launched(game_launched)\n{\n\tSetIcon(wxICON(X_SETTINGS));\n\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\tauto* notebook = new wxNotebook(this, wxID_ANY);\n\n\tnotebook->AddPage(AddGeneralPage(notebook), _(\"General\"));\n\tnotebook->AddPage(AddGraphicsPage(notebook), _(\"Graphics\"));\n\tnotebook->AddPage(AddAudioPage(notebook), _(\"Audio\"));\n\tnotebook->AddPage(AddOverlayPage(notebook), _(\"Overlay\"));\n\tnotebook->AddPage(AddAccountPage(notebook), _(\"Account\"));\n\tnotebook->AddPage(AddDebugPage(notebook), _(\"Debug\"));\n\n\tBind(wxEVT_CLOSE_WINDOW, &GeneralSettings2::OnClose, this);\n\n\t//\n\n\tsizer->Add(notebook, 1, wxEXPAND | wxALL, 5);\n\n\tSetSizerAndFit(sizer);\n\tLayout();\n\tCentre(wxBOTH);\n\n\t//\n\n\tUpdateOnlineAccounts();\n\tUpdateAudioDeviceList();\n\n\tApplyConfig();\n\tHandleGraphicsApiSelection();\n\n\tDisableSettings(game_launched);\n}\n\nuint32 GeneralSettings2::GetSelectedAccountPersistentId()\n{\n\tconst auto active_account = m_active_account->GetSelection();\n\tif (active_account == wxNOT_FOUND)\n\t\treturn GetConfig().account.m_persistent_id.GetInitValue();\n\treturn dynamic_cast<wxAccountData*>(m_active_account->GetClientObject(active_account))->GetAccount().GetPersistentId();\n}\n\nvoid GeneralSettings2::StoreConfig()\n{\n\tauto& app = wxGetApp();\n\tauto& config = GetConfig();\n\tauto& wxGuiConfig = GetWxGUIConfig();\n\n\twxGuiConfig.use_discord_presence = m_discord_presence->IsChecked();\n\twxGuiConfig.fullscreen_menubar = m_fullscreen_menubar->IsChecked();\n\twxGuiConfig.check_update = m_auto_update->IsChecked();\n\twxGuiConfig.save_screenshot = m_save_screenshot->IsChecked();\n\twxGuiConfig.receive_untested_updates = m_receive_untested_releases->IsChecked();\n#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)\n    wxGuiConfig.feral_gamemode = m_feral_gamemode->IsChecked();\n#endif\n#if BOOST_OS_WINDOWS\n\twxGuiConfig.msw_theme = m_msw_theme->GetSelection();\n#endif\n\tconfig.play_boot_sound = m_play_boot_sound->IsChecked();\n\tconfig.disable_screensaver = m_disable_screensaver->IsChecked();\n\t// toggle while a game is running\n\tif (CafeSystem::IsTitleRunning())\n\t{\n\t\tScreenSaver::SetInhibit(config.disable_screensaver);\n\t}\n\n\t// -1 is default wx widget value -> set to dummy 0 so mainwindow and padwindow will update it\n\twxGuiConfig.window_position = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};\n\twxGuiConfig.window_size = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};\n\twxGuiConfig.pad_position = m_save_padwindow_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};\n\twxGuiConfig.pad_size = m_save_padwindow_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};\n\n\tconfig.game_paths.clear();\n\tfor (auto& path : m_game_paths->GetStrings())\n\t\tconfig.game_paths.emplace_back(path.utf8_string());\n\n\tauto selection = m_language->GetSelection();\n\tif (selection == 0)\n\t\twxGuiConfig.language = wxLANGUAGE_DEFAULT;\n\telse\n\t{\n\t\tconst auto language = m_language->GetStringSelection();\n\t\tfor (const auto& lang : app.GetLanguages())\n\t\t{\n\t\t\tif (lang->DescriptionNative == language)\n\t\t\t{\n\t\t\t\twxGuiConfig.language = lang->Language;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// audio\n\tif (m_audio_api->GetStringSelection() == kDirectSound)\n\t\tconfig.audio_api = IAudioAPI::DirectSound;\n\telse if (m_audio_api->GetStringSelection() == kXAudio27)\n\t\tconfig.audio_api = IAudioAPI::XAudio27;\n\telse if (m_audio_api->GetStringSelection() == kXAudio2)\n\t\tconfig.audio_api = IAudioAPI::XAudio2;\n\telse if (m_audio_api->GetStringSelection() == kCubeb)\n\t\tconfig.audio_api = IAudioAPI::Cubeb;\n\n\tconfig.audio_delay = m_audio_latency->GetValue();\n\tconfig.tv_channels = (AudioChannels)m_tv_channels->GetSelection();\n\t//config.pad_channels =  (AudioChannels)m_pad_channels->GetSelection();\n\tconfig.pad_channels = kStereo; // (AudioChannels)m_pad_channels->GetSelection();\n\t//config.input_channels =  (AudioChannels)m_input_channels->GetSelection();\n\tconfig.input_channels = kMono; // (AudioChannels)m_input_channels->GetSelection();\n\n\tconfig.tv_volume = m_tv_volume->GetValue();\n\tconfig.pad_volume = m_pad_volume->GetValue();\n\tconfig.input_volume = m_input_volume->GetValue();\n\tconfig.portal_volume = m_portal_volume->GetValue();\n\n\tconfig.tv_device.clear();\n\tconst auto tv_device = m_tv_device->GetSelection();\n\tif (tv_device != wxNOT_FOUND && tv_device != 0 && m_tv_device->HasClientObjectData())\n\t{\n\t\tconst auto* device_description = (wxDeviceDescription*)m_tv_device->GetClientObject(tv_device);\n\t\tif(device_description)\n\t\t\tconfig.tv_device = device_description->GetDescription()->GetIdentifier();\n\t}\n\n\tconfig.pad_device.clear();\n\tconst auto pad_device = m_pad_device->GetSelection();\n\tif (pad_device != wxNOT_FOUND && pad_device != 0 && m_pad_device->HasClientObjectData())\n\t{\n\t\tconst auto* device_description = (wxDeviceDescription*)m_pad_device->GetClientObject(pad_device);\n\t\tif (device_description)\n\t\t\tconfig.pad_device = device_description->GetDescription()->GetIdentifier();\n\t}\n\n\tconfig.input_device = L\"\";\n\tconst auto input_device = m_input_device->GetSelection();\n\tif (input_device != wxNOT_FOUND && input_device != 0 && m_input_device->HasClientObjectData())\n\t{\n\t\tconst auto* device_description = (wxDeviceDescription*)m_input_device->GetClientObject(input_device);\n\t\tif (device_description)\n\t\t\tconfig.input_device = device_description->GetDescription()->GetIdentifier();\n\t}\n\n\tconfig.portal_device.clear();\n\tconst auto portal_device = m_portal_device->GetSelection();\n\tif (portal_device != wxNOT_FOUND && portal_device != 0 && m_portal_device->HasClientObjectData())\n\t{\n\t\tconst auto* device_description = (wxDeviceDescription*)m_portal_device->GetClientObject(portal_device);\n\t\tif (device_description)\n\t\t\tconfig.portal_device = device_description->GetDescription()->GetIdentifier();\n\t}\n\n\t// graphics\n\tconfig.graphic_api = (GraphicAPI)m_graphic_api->GetSelection();\n\n\tselection = m_graphic_device->GetSelection();\n\tif (config.graphic_api == GraphicAPI::kVulkan)\n\t{\n    \tif (selection != wxNOT_FOUND)\n    \t{\n    \t\tconst auto* info = (wxVulkanUUID*)m_graphic_device->GetClientObject(selection);\n    \t\tif (info)\n    \t\t\tconfig.vk_graphic_device_uuid = info->GetDeviceInfo().uuid;\n    \t\telse\n    \t\t\tconfig.vk_graphic_device_uuid = {};\n    \t}\n    \telse\n    \t\tconfig.vk_graphic_device_uuid = {};\n\t}\n#if ENABLE_METAL\n\telse if (config.graphic_api == GraphicAPI::kMetal)\n\t{\n        if (selection != wxNOT_FOUND)\n    \t{\n    \t\tconst auto* info = (wxMetalUUID*)m_graphic_device->GetClientObject(selection);\n    \t\tif (info)\n    \t\t\tconfig.mtl_graphic_device_uuid = info->GetDeviceInfo().uuid;\n    \t\telse\n    \t\t\tconfig.mtl_graphic_device_uuid = {};\n    \t}\n    \telse\n    \t\tconfig.mtl_graphic_device_uuid = {};\n\t}\n#endif\n\n\n\tconfig.gx2drawdone_sync = m_gx2drawdone_sync->IsChecked();\n#if ENABLE_METAL\n\tconfig.force_mesh_shaders = m_force_mesh_shaders->IsChecked();\n#endif\n\tconfig.async_compile = m_async_compile->IsChecked();\n\n\tconfig.overlay.position = (ScreenPosition)m_overlay_position->GetSelection(); wxASSERT((int)config.overlay.position <= (int)ScreenPosition::kBottomRight);\n\tconfig.overlay.text_color = m_overlay_font_color->GetColour().GetRGBA();\n\tconfig.overlay.text_scale = m_overlay_scale->GetSelection() * 25 + 50;\n\n\tconfig.overlay.fps = m_overlay_fps->GetValue();\n\tconfig.overlay.drawcalls = m_overlay_drawcalls->GetValue();\n\tconfig.overlay.cpu_usage = m_overlay_cpu->GetValue();\n\tconfig.overlay.cpu_per_core_usage = m_overlay_cpu_per_core->GetValue();\n\tconfig.overlay.ram_usage = m_overlay_ram->GetValue();\n\tconfig.overlay.vram_usage = m_overlay_vram->GetValue();\n\tconfig.overlay.debug = m_overlay_debug->GetValue();\n\n\tconfig.notification.position = (ScreenPosition)m_notification_position->GetSelection(); wxASSERT((int)config.notification.position <= (int)ScreenPosition::kBottomRight);\n\tconfig.notification.text_color = m_notification_font_color->GetColour().GetRGBA();\n\tconfig.notification.text_scale = m_notification_scale->GetSelection() * 25 + 50;\n\tconfig.notification.controller_profiles = m_controller_profile_name->GetValue();\n\tconfig.notification.controller_battery = m_controller_low_battery->GetValue();\n\tconfig.notification.shader_compiling = m_shader_compiling->GetValue();\n\tconfig.notification.friends = m_friends_data->GetValue();\n\n\t// account\n\tconfig.account.m_persistent_id = GetSelectedAccountPersistentId();\n\n\t// debug\n\tconfig.crash_dump = (CrashDump)m_crash_dump->GetSelection();\n\tconfig.gdb_port = m_gdb_port->GetValue();\n#if ENABLE_METAL\n\tconfig.gpu_capture_dir = m_gpu_capture_dir->GetValue().utf8_string();\n\tconfig.framebuffer_fetch = m_framebuffer_fetch->IsChecked();\n#endif\n\n\tGetConfigHandle().Save();\n}\n\nGeneralSettings2::~GeneralSettings2()\n{\n\tUnbind(wxEVT_CLOSE_WINDOW, &GeneralSettings2::OnClose, this);\n}\n\nvoid GeneralSettings2::OnClose(wxCloseEvent& event)\n{\n\tStoreConfig();\n\tif (m_has_account_change)\n\t{\n\t\twxCommandEvent refresh_event(wxEVT_ACCOUNTLIST_REFRESH);\n\t\tGetParent()->ProcessWindowEvent(refresh_event);\n\t}\n\tevent.Skip();\n}\n\nvoid GeneralSettings2::ValidateConfig()\n{\n\tGetConfigHandle().Load();\n\n\tauto& data = GetConfigHandle().data();\n\t// todo\n\t//data.fullscreen_scaling = min(max(data.fullscreen_scaling,))\n}\n\nvoid GeneralSettings2::DisableSettings(bool game_launched)\n{\n}\n\nvoid GeneralSettings2::OnAudioLatencyChanged(wxCommandEvent& event)\n{\n\tIAudioAPI::s_audioDelay = event.GetInt();\n\tevent.Skip();\n}\n\nvoid GeneralSettings2::OnVolumeChanged(wxCommandEvent& event)\n{\n\n\tif(event.GetEventObject() == m_input_volume)\n\t{\n\t\tstd::shared_lock lock(g_audioInputMutex);\n\t\tif (g_inputAudio)\n\t\t\tg_inputAudio->SetVolume(event.GetInt());\n\t}\n\telse\n\t{\n\t\tstd::shared_lock lock(g_audioMutex);\n\t\tif(event.GetEventObject() == m_pad_volume)\n\t\t{\n\t\t\tif (g_padAudio)\n\t\t\t\tg_padAudio->SetVolume(event.GetInt());\n\n\t\t\tg_padVolume = event.GetInt();\n\t\t}\n\t\telse if (event.GetEventObject() == m_tv_volume)\n\t\t{\n\t\t\tif (g_tvAudio)\n\t\t\t\tg_tvAudio->SetVolume(event.GetInt());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(g_portalAudio)\n\t\t\t\tg_portalAudio->SetVolume(event.GetInt());\n\t\t}\n\t}\n\n\n\tevent.Skip();\n}\n\nvoid GeneralSettings2::OnInputVolumeChanged(wxCommandEvent& event)\n{\n\tstd::shared_lock lock(g_audioMutex);\n\tif (g_padAudio)\n\t\tg_padAudio->SetInputVolume(event.GetInt());\n\n\tevent.Skip();\n}\n\nvoid GeneralSettings2::OnSliderChangedPercent(wxCommandEvent& event)\n{\n\tconst auto slider = dynamic_cast<wxSlider*>(event.GetEventObject());\n\twxASSERT(slider);\n\n\tconst auto control = dynamic_cast<wxControlObject*>(event.GetEventUserData());\n\twxASSERT(control);\n\n\tauto slider_text = control->GetControl<wxStaticText>();\n\twxASSERT(slider_text);\n\n\tconst auto value = event.GetInt();\n\tslider->SetValue(value);\n\tslider_text->SetLabel(wxString::Format(\"%d%%\", value));\n\n\tevent.Skip();\n}\n\nvoid GeneralSettings2::OnLatencySliderChanged(wxCommandEvent& event)\n{\n\tconst auto slider = dynamic_cast<wxSlider*>(event.GetEventObject());\n\twxASSERT(slider);\n\n\tconst auto control = dynamic_cast<wxControlObject*>(event.GetEventUserData());\n\twxASSERT(control);\n\n\tauto slider_text = control->GetControl<wxStaticText>();\n\twxASSERT(slider_text);\n\n\tconst auto value = event.GetInt();\n\tslider->SetValue(value);\n\tslider_text->SetLabel(wxString::Format(\"%dms\", value * 12));\n\n\tevent.Skip();\n}\n\nvoid GeneralSettings2::UpdateAudioDeviceList()\n{\n\tm_tv_device->Clear();\n\tm_pad_device->Clear();\n\tm_input_device->Clear();\n\tm_portal_device->Clear();\n\n\tm_tv_device->Append(_(\"Disabled\"));\n\tm_pad_device->Append(_(\"Disabled\"));\n\tm_input_device->Append(_(\"Disabled\"));\n\tm_portal_device->Append(_(\"Disabled\"));\n\n\tconst auto audio_api = (IAudioAPI::AudioAPI)GetConfig().audio_api;\n\tconst auto devices = IAudioAPI::GetDevices(audio_api);\n\tfor (auto& device : devices)\n\t{\n\t\tm_tv_device->Append(device->GetName(), new wxDeviceDescription(device));\n\t\tm_pad_device->Append(device->GetName(), new wxDeviceDescription(device));\n\t\tm_portal_device->Append(device->GetName(), new wxDeviceDescription(device));\n\t}\n\n\tconst auto input_audio_api = IAudioInputAPI::Cubeb; //(IAudioAPI::AudioAPI)GetConfig().input_audio_api;\n\tconst auto input_devices = IAudioInputAPI::GetDevices(input_audio_api);\n\n\tfor (auto& device : input_devices)\n\t{\n\t\tm_input_device->Append(device->GetName(), new wxInputDeviceDescription(device));\n\t}\n\n\tif(m_tv_device->GetCount() > 1)\n\t\tm_tv_device->SetSelection(1);\n\telse\n\t\tm_tv_device->SetSelection(0);\n\n\tm_pad_device->SetSelection(0);\n\n\tm_input_device->SetSelection(0);\n\n\tm_portal_device->SetSelection(0);\n\n\t// todo reset global instance of audio device\n}\n\nvoid GeneralSettings2::ResetAccountInformation()\n{\n\tm_account_grid->SetSplitterPosition(100);\n\tm_active_account->SetSelection(0);\n\n\tfor(auto it = m_account_grid->GetIterator(); !it.AtEnd(); ++it)\n\t{\n\t\t(*it)->SetValueToUnspecified();\n\t}\n\n\t// refresh pane size\n\tm_account_information->InvalidateBestSize();\n\t#if BOOST_OS_WINDOWS\n\tm_account_information->OnStateChange(GetBestSize());\n\t#endif\n}\n\nvoid GeneralSettings2::OnAccountCreate(wxCommandEvent& event)\n{\n\twxASSERT(Account::HasFreeAccountSlots());\n\n\twxCreateAccountDialog dialog(this);\n\tif (dialog.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\tAccount account(dialog.GetPersistentId(), dialog.GetMiiName().ToStdWstring());\n\taccount.Save();\n\tAccount::RefreshAccounts();\n\n\tconst int index = m_active_account->Append(account.ToString(), new wxAccountData(account));\n\n\t// update ui\n\tm_active_account->SetSelection(index);\n\tUpdateAccountInformation();\n\n\tm_create_account->Enable(m_active_account->GetCount() < 0xC);\n\tm_delete_account->Enable(m_active_account->GetCount() > 1);\n\n\t// send main window event\n\twxASSERT(GetParent());\n\twxCommandEvent refresh_event(wxEVT_ACCOUNTLIST_REFRESH);\n\tGetParent()->ProcessWindowEvent(refresh_event);\n}\n\nvoid GeneralSettings2::OnAccountDelete(wxCommandEvent& event)\n{\n\tif(m_active_account->GetCount() == 1)\n\t{\n\t\twxMessageBox(_(\"Can't delete the only account!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\tconst auto selection = m_active_account->GetSelection();\n\twxASSERT(selection != wxNOT_FOUND);\n\tauto* obj = dynamic_cast<wxAccountData*>(m_active_account->GetClientObject(selection));\n\twxASSERT(obj);\n\tauto& account = obj->GetAccount();\n\n\tconst std::wstring format_str = _(\"Are you sure you want to delete the account {} with id {:x}?\").ToStdWstring();\n\tconst std::wstring msg = fmt::format(fmt::runtime(format_str),\n\t                                     std::wstring{ account.GetMiiName() }, account.GetPersistentId());\n\n\tconst int answer = wxMessageBox(msg, _(\"Confirmation\"), wxYES_NO | wxCENTRE | wxICON_QUESTION, this);\n\tif (answer == wxNO)\n\t\treturn;\n\n\t// todo: ask if saves should be deleted too?\n\n\tconst fs::path path = account.GetFileName();\n\ttry\n\t{\n\t\tfs::remove_all(path.parent_path());\n\t\tm_active_account->Delete(selection);\n\t\tm_active_account->SetSelection(0);\n\t\tAccount::RefreshAccounts();\n\t\tUpdateAccountInformation();\n\n\t\tm_create_account->Enable(m_active_account->GetCount() < 0xC);\n\t\tm_delete_account->Enable(m_active_account->GetCount() > 1);\n\t}\n\tcatch(const std::exception& ex)\n\t{\n\t\tSystemException sys(ex);\n\t\tcemuLog_log(LogType::Force, sys.what());\n\t}\n\n}\n\nvoid GeneralSettings2::OnAccountSettingsChanged(wxPropertyGridEvent& event)\n{\n\twxPGProperty* property = event.GetProperty();\n\tif (!property)\n\t\treturn;\n\n\tconst wxAny value = property->GetValue();\n\tif (value.IsNull())\n\t\treturn;\n\n\tconst auto selection = m_active_account->GetSelection();\n\twxASSERT(selection != wxNOT_FOUND);\n\tauto* obj = dynamic_cast<wxAccountData*>(m_active_account->GetClientObject(selection));\n\twxASSERT(obj);\n\tauto& account = obj->GetAccount();\n\n\t// TODO make id changeable to free ids + current it?\n\tbool refresh_accounts = false;\n\tif (property->GetName() == kPropertyMiiName)\n\t{\n\t\tstd::wstring new_name = value.As<wxString>().ToStdWstring();\n\t\tif (new_name.empty())\n\t\t\tnew_name = L\"default\";\n\n\t\taccount.SetMiiName(new_name);\n\t\trefresh_accounts = true;\n\t}\n\telse if (property->GetName() == kPropertyBirthday)\n\t{\n\t\tconst std::string birthday = value.As<wxString>().ToStdString();\n\t\tconst boost::char_separator<char> sep{ \"-\" };\n\n\t\tstd::vector<std::string> tokens;\n\t\tfor (const auto& token : boost::tokenizer(birthday, sep))\n\t\t{\n\t\t\ttokens.emplace_back(token);\n\t\t}\n\n\t\tif (tokens.size() == 3)\n\t\t{\n\t\t\taccount.SetBirthYear(ConvertString<uint16>(tokens[0]));\n\t\t\taccount.SetBirthMonth(ConvertString<uint8>(tokens[1]));\n\t\t\taccount.SetBirthDay(ConvertString<uint8>(tokens[2]));\n\t\t}\n\t}\n\telse if (property->GetName() == kPropertyGender)\n\t{\n\t\taccount.SetGender(value.As<int>());\n\t}\n\telse if (property->GetName() == kPropertyEmail)\n\t{\n\t\taccount.SetEmail(value.As<wxString>().ToStdString());\n\n\t}\n\telse if (property->GetName() == kPropertyCountry)\n\t{\n\t\taccount.SetCountry(value.As<int>());\n\t}\n\telse\n\t\tcemu_assert_debug(false);\n\n\taccount.Save();\n\tAccount::RefreshAccounts(); // refresh internal account list\n\tUpdateAccountInformation(); // refresh on invalid values\n\n\tif(refresh_accounts)\n\t{\n\t\twxCommandEvent refresh_event(wxEVT_ACCOUNTLIST_REFRESH);\n\t\tGetParent()->ProcessWindowEvent(refresh_event);\n\t}\n}\n\nvoid GeneralSettings2::UpdateAccountInformation()\n{\n\tm_account_grid->SetSplitterPosition(100);\n\n\tconst auto selection = m_active_account->GetSelection();\n\tif(selection == wxNOT_FOUND)\n\t{\n\t\tm_validate_online->SetBitmap(wxBITMAP_PNG_FROM_DATA(PNG_ERROR).ConvertToImage().Scale(16, 16));\n\t\tm_validate_online->SetWindowStyleFlag(m_validate_online->GetWindowStyleFlag() & ~wxBORDER_NONE);\n\t\tResetAccountInformation();\n\t\tm_online_status->SetLabel(_(\"No account selected\"));\n\t\treturn;\n\t}\n\n\tconst auto* obj = dynamic_cast<wxAccountData*>(m_active_account->GetClientObject(selection));\n\twxASSERT(obj);\n\tconst auto& account = obj->GetAccount();\n\n\tm_active_account->SetString(selection, account.ToString());\n\n\tm_account_grid->GetProperty(kPropertyPersistentId)->SetValueFromString(fmt::format(\"{:x}\", account.GetPersistentId()));\n\tm_account_grid->GetProperty(kPropertyMiiName)->SetValueFromString(std::wstring{ account.GetMiiName() });\n\tm_account_grid->GetProperty(kPropertyBirthday)->SetValueFromString(fmt::format(\"{:04d}-{:02d}-{:02d}\", account.GetBirthYear(), account.GetBirthMonth(), account.GetBirthDay()));\n\n\tconst auto gender_property = m_account_grid->GetProperty(kPropertyGender); // gender 2 can be also female?\n\tgender_property->SetChoiceSelection(std::min(gender_property->GetChoices().GetCount() - 1, (uint32)account.GetGender()));\n\n\tm_account_grid->GetProperty(kPropertyEmail)->SetValueFromString(std::string{ account.GetEmail() });\n\n\tauto* country_property = dynamic_cast<wxEnumProperty*>(m_account_grid->GetProperty(kPropertyCountry));\n\twxASSERT(country_property);\n\tint index = (country_property)->GetIndexForValue(account.GetCountry());\n\tif (index == wxNOT_FOUND)\n\t\tindex = 0;\n\tcountry_property->SetChoiceSelection(index);\n\n\tconst bool online_fully_valid = account.IsValidOnlineAccount() && ActiveSettings::HasRequiredOnlineFiles();\n\tif (ActiveSettings::HasRequiredOnlineFiles())\n\t{\n\t\tif(account.IsValidOnlineAccount())\n\t\t\tm_online_status->SetLabel(_(\"Selected account is a valid online account\"));\n\t\telse\n\t\t\tm_online_status->SetLabel(_(\"Selected account is not linked to a NNID or PNID\"));\n\t}\n\telse\n\t{\n\t\tif(NCrypto::OTP_IsPresent() != NCrypto::SEEPROM_IsPresent())\n\t\t\tm_online_status->SetLabel(_(\"OTP.bin or SEEPROM.bin is missing\"));\n\t\telse if(NCrypto::OTP_IsPresent() && NCrypto::SEEPROM_IsPresent())\n\t\t\tm_online_status->SetLabel(_(\"OTP and SEEPROM present but no certificate files were found\"));\n\t\telse\n\t\t\tm_online_status->SetLabel(_(\"Online play is not set up. Follow the guide below to get started\"));\n\t}\n\n\tif(online_fully_valid)\n\t{\n\t\tm_validate_online->SetBitmap(wxBITMAP_PNG_FROM_DATA(PNG_CHECK_YES).ConvertToImage().Scale(16, 16));\n\t\tm_validate_online->SetWindowStyleFlag(m_validate_online->GetWindowStyleFlag() | wxBORDER_NONE);\n\t}\n\telse\n\t{\n\t\tm_validate_online->SetBitmap(wxBITMAP_PNG_FROM_DATA(PNG_ERROR).ConvertToImage().Scale(16, 16));\n\t\tm_validate_online->SetWindowStyleFlag(m_validate_online->GetWindowStyleFlag() & ~wxBORDER_NONE);\n\t}\n\n\t// enable/disable network service field depending on online requirements\n\tm_active_service->Enable(online_fully_valid && !CafeSystem::IsTitleRunning());\n\tif(online_fully_valid)\n\t{\n\t\tNetworkService service = GetConfig().GetAccountNetworkService(account.GetPersistentId());\n\t\tm_active_service->SetSelection(static_cast<int>(service));\n\t\t// set the config option here for the selected service\n\t\t// this will guarantee that it's actually written to settings.xml\n\t\t// allowing us to eventually get rid of the legacy option in the (far) future\n\t\tGetConfig().SetAccountSelectedService(account.GetPersistentId(), service);\n\t}\n\telse\n\t{\n\t\tm_active_service->SetSelection(0); // force offline\n\t}\n\twxString tmp = _(\"Network service\");\n\ttmp.append(\" (\");\n\ttmp.append(wxString::FromUTF8(boost::nowide::narrow(account.GetMiiName())));\n\ttmp.append(\")\");\n\tm_active_service->SetLabel(tmp);\n\n\t// refresh pane size\n\tm_account_grid->InvalidateBestSize();\n\t//m_account_grid->GetParent()->FitInside();\n\t//m_account_information->OnStateChange(GetBestSize()); idk..\n}\n\nvoid GeneralSettings2::UpdateOnlineAccounts()\n{\n\tm_active_account->Clear();\n\tfor(const auto& account : Account::GetAccounts())\n\t{\n\t\tm_active_account->Append(fmt::format(L\"{} ({:x})\", std::wstring{ account.GetMiiName() }, account.GetPersistentId()),\n\t\t\tnew wxAccountData(account));\n\t}\n\n\tm_active_account->SetSelection(0);\n\tm_create_account->Enable(m_active_account->GetCount() < 0xC);\n\tm_delete_account->Enable(m_active_account->GetCount() > 1);\n\tUpdateAccountInformation();\n}\n\nvoid GeneralSettings2::HandleGraphicsApiSelection()\n{\n\tint selection = m_vsync->GetSelection();\n\tif(selection == wxNOT_FOUND)\n\t\tselection = GetConfig().vsync;\n\n\tm_vsync->Clear();\n\tif (m_graphic_api->GetSelection() == 0)\n\t{\n\t\t// OpenGL\n\t\tm_vsync->AppendString(_(\"Off\"));\n\t\tm_vsync->AppendString(_(\"On\"));\n\t\tif (selection == 0)\n\t\t\tm_vsync->Select(0);\n\t\telse\n\t\t\tm_vsync->Select(1);\n\n\t\tm_graphic_device->Clear();\n\t\tm_graphic_device->Disable();\n\n\t\tm_gx2drawdone_sync->Enable();\n\t\tm_async_compile->Disable();\n#if ENABLE_METAL\n\t\tm_force_mesh_shaders->Disable();\n#endif\n\t}\n\telse if (m_graphic_api->GetSelection() == 1)\n\t{\n\t\t// Vulkan\n\t\tm_gx2drawdone_sync->Disable();\n\t\tm_async_compile->Enable();\n#if ENABLE_METAL\n\t\tm_force_mesh_shaders->Disable();\n#endif\n\n\t\tm_vsync->AppendString(_(\"Off\"));\n\t\tm_vsync->AppendString(_(\"Double buffering\"));\n\t\tm_vsync->AppendString(_(\"Triple buffering\"));\n#if BOOST_OS_WINDOWS\n\t\tm_vsync->AppendString(_(\"Match emulated display (Experimental)\"));\n#endif\n\n\t\tm_vsync->Select(selection);\n\n\t\tm_graphic_device->Enable();\n\t\tauto devices = VulkanRenderer::GetDevices();\n\t\tm_graphic_device->Clear();\n\t\tif(!devices.empty())\n\t\t{\n\t\t\tfor(const auto& device : devices)\n\t\t\t{\n\t\t\t\tm_graphic_device->Append(device.name, new wxVulkanUUID(device));\n\t\t\t}\n\t\t\tm_graphic_device->SetSelection(0);\n\n\t\t\tconst auto& config = GetConfig();\n\t\t\tfor(size_t i = 0; i < devices.size(); ++i)\n\t\t\t{\n\t\t\t\tif(config.vk_graphic_device_uuid == devices[i].uuid)\n\t\t\t\t{\n\t\t\t\t\tm_graphic_device->SetSelection(i);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#if ENABLE_METAL\n\telse\n\t{\n\t\t// Metal\n\t\tm_gx2drawdone_sync->Disable();\n\t\tm_async_compile->Enable();\n\t\tm_force_mesh_shaders->Enable();\n\n\t\tm_vsync->AppendString(_(\"Off\"));\n\t\tm_vsync->AppendString(_(\"On\"));\n\n\t\tm_vsync->Select(selection);\n\n\t\tm_graphic_device->Enable();\n\t\tm_graphic_device->Clear();\n\n\t\tauto devices = MetalRenderer::GetDevices();\n\t\tif(!devices.empty())\n\t\t{\n\t\t\tfor (const auto& device : devices)\n\t\t\t{\n\t\t\t\tm_graphic_device->Append(device.name, new wxMetalUUID(device));\n\t\t\t}\n\t\t\tm_graphic_device->SetSelection(0);\n\n\t\t\tconst auto& config = GetConfig();\n\t\t\tfor (size_t i = 0; i < devices.size(); ++i)\n\t\t\t{\n\t\t\t\tif (config.mtl_graphic_device_uuid == devices[i].uuid)\n\t\t\t\t{\n\t\t\t\t\tm_graphic_device->SetSelection(i);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n\nvoid GeneralSettings2::ApplyConfig()\n{\n\tValidateConfig();\n\tauto& wxGUIconfig = GetWxGUIConfig();\n\tauto& config = GetConfig();\n\n\tif (LaunchSettings::GetMLCPath().has_value())\n\t\tm_mlc_path->SetValue(wxHelper::FromPath(LaunchSettings::GetMLCPath().value()));\n\telse\n\t\tm_mlc_path->SetValue(wxString::FromUTF8(config.mlc_path.GetValue()));\n\n\tm_save_window_position_size->SetValue(wxGUIconfig.window_position != Vector2i{-1,-1});\n\tm_save_padwindow_position_size->SetValue(wxGUIconfig.pad_position != Vector2i{-1,-1});\n\n\tm_discord_presence->SetValue(wxGUIconfig.use_discord_presence);\n\tm_fullscreen_menubar->SetValue(wxGUIconfig.fullscreen_menubar);\n\n\tm_auto_update->SetValue(wxGUIconfig.check_update);\n\tm_receive_untested_releases->SetValue(wxGUIconfig.receive_untested_updates);\n\tm_save_screenshot->SetValue(wxGUIconfig.save_screenshot);\n\n\tm_disable_screensaver->SetValue(config.disable_screensaver);\n\tm_play_boot_sound->SetValue(config.play_boot_sound);\n#if BOOST_OS_WINDOWS\n\tm_msw_theme->SetSelection(wxGUIconfig.msw_theme);\n#endif\n#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)\n    \tm_feral_gamemode->SetValue(wxGUIconfig.feral_gamemode);\n#endif\n\t// temporary workaround because feature crashes on macOS\n#if BOOST_OS_MACOS\n\tm_disable_screensaver->SetValue(false);\n#endif\n\n\tm_game_paths->Clear();\n\tfor (auto& path : config.game_paths)\n\t{\n\t\tm_game_paths->Append(wxString::FromUTF8(path));\n\t}\n\n\tconst auto& app = wxGetApp();\n\tfor (const auto& language : app.GetLanguages())\n\t{\n\t\tif (wxGUIconfig.language == language->Language)\n\t\t{\n\t\t\tm_language->SetStringSelection(language->DescriptionNative);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// graphics\n\tm_graphic_api->SetSelection(config.graphic_api);\n\tm_vsync->SetSelection(config.vsync);\n\tm_overrideGamma->SetValue(config.overrideAppGammaPreference);\n\tm_overrideGammaValue->SetValue(config.overrideGammaValue);\n\tm_userDisplayisSRGB->SetValue(config.userDisplayGamma == 0.0f);\n\tm_userDisplayGamma->SetValue(config.userDisplayGamma);\n\tif(m_userDisplayisSRGB->GetValue())\n\t{\n\t\tm_userDisplayGamma->Disable();\n\t\tm_userDisplayGamma->SetValue(2.2f);\n\t}\n\tm_async_compile->SetValue(config.async_compile);\n\tm_gx2drawdone_sync->SetValue(config.gx2drawdone_sync);\n#if ENABLE_METAL\n\tm_force_mesh_shaders->SetValue(config.force_mesh_shaders);\n#endif\n\tm_upscale_filter->SetSelection(config.upscale_filter);\n\tm_downscale_filter->SetSelection(config.downscale_filter);\n\tm_fullscreen_scaling->SetSelection(config.fullscreen_scaling);\n\n\twxASSERT((uint32)config.overlay.position < m_overlay_position->GetCount());\n\tm_overlay_position->SetSelection((int)config.overlay.position);\n\tm_overlay_font_color->SetColour(wxColour((unsigned long)config.overlay.text_color));\n\n\tuint32 selection = (config.overlay.text_scale - 50) / 25;\n\twxASSERT(selection < m_overlay_scale->GetCount());\n\tm_overlay_scale->SetSelection(selection);\n\n\tm_overlay_fps->SetValue(config.overlay.fps);\n\tm_overlay_drawcalls->SetValue(config.overlay.drawcalls);\n\tm_overlay_cpu->SetValue(config.overlay.cpu_usage);\n\tm_overlay_cpu_per_core->SetValue(config.overlay.cpu_per_core_usage);\n\tm_overlay_ram->SetValue(config.overlay.ram_usage);\n\tm_overlay_vram->SetValue(config.overlay.vram_usage);\n\tm_overlay_debug->SetValue(config.overlay.debug);\n\n\twxASSERT((uint32)config.notification.position < m_notification_position->GetCount());\n\tm_notification_position->SetSelection((int)config.notification.position);\n\tm_notification_font_color->SetColour(wxColour((unsigned long)config.notification.text_color));\n\n\tselection = (config.notification.text_scale - 50) / 25;\n\twxASSERT(selection < m_notification_scale->GetCount());\n\tm_notification_scale->SetSelection(selection);\n\n\tm_controller_profile_name->SetValue(config.notification.controller_profiles);\n\tm_controller_low_battery->SetValue(config.notification.controller_battery);\n\tm_shader_compiling->SetValue(config.notification.shader_compiling);\n\tm_friends_data->SetValue(config.notification.friends);\n\n\t// audio\n\tif(config.audio_api == IAudioAPI::DirectSound)\n\t\tm_audio_api->SetStringSelection(kDirectSound);\n\telse if(config.audio_api == IAudioAPI::XAudio27)\n\t\tm_audio_api->SetStringSelection(kXAudio27);\n\telse if(config.audio_api == IAudioAPI::XAudio2)\n\t\tm_audio_api->SetStringSelection(kXAudio2);\n\telse if(config.audio_api == IAudioAPI::Cubeb)\n\t\tm_audio_api->SetStringSelection(kCubeb);\n\n\tSendSliderEvent(m_audio_latency, config.audio_delay);\n\n\tm_tv_channels->SetSelection(config.tv_channels);\n\t//m_pad_channels->SetSelection(config.pad_channels);\n\tm_pad_channels->SetSelection(0);\n\t//m_input_channels->SetSelection(config.pad_channels);\n\tm_input_channels->SetSelection(0);\n\n\tSendSliderEvent(m_tv_volume, config.tv_volume);\n\n\tif (!config.tv_device.empty() && m_tv_device->HasClientObjectData())\n\t{\n\t\tfor(uint32 i = 0; i < m_tv_device->GetCount(); ++i)\n\t\t{\n\t\t\tconst auto device_description = (wxDeviceDescription*)m_tv_device->GetClientObject(i);\n\t\t\tif (device_description && config.tv_device == device_description->GetDescription()->GetIdentifier())\n\t\t\t{\n\t\t\t\tm_tv_device->SetSelection(i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t\tm_tv_device->SetSelection(0);\n\n\tSendSliderEvent(m_pad_volume, config.pad_volume);\n\tif (!config.pad_device.empty() && m_pad_device->HasClientObjectData())\n\t{\n\t\tfor (uint32 i = 0; i < m_pad_device->GetCount(); ++i)\n\t\t{\n\t\t\tconst auto device_description = (wxDeviceDescription*)m_pad_device->GetClientObject(i);\n\t\t\tif (device_description && config.pad_device == device_description->GetDescription()->GetIdentifier())\n\t\t\t{\n\t\t\t\tm_pad_device->SetSelection(i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t\tm_pad_device->SetSelection(0);\n\n\tSendSliderEvent(m_input_volume, config.input_volume);\n\tif (!config.input_device.empty() && m_input_device->HasClientObjectData())\n\t{\n\t\tfor (uint32 i = 0; i < m_input_device->GetCount(); ++i)\n\t\t{\n\t\t\tconst auto device_description = (wxInputDeviceDescription*)m_input_device->GetClientObject(i);\n\t\t\tif (device_description && config.input_device == device_description->GetDescription()->GetIdentifier())\n\t\t\t{\n\t\t\t\tm_input_device->SetSelection(i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t\tm_input_device->SetSelection(0);\n\n\tSendSliderEvent(m_portal_volume, config.portal_volume);\n\tif (!config.portal_device.empty() && m_portal_device->HasClientObjectData())\n\t{\n\t\tfor (uint32 i = 0; i < m_portal_device->GetCount(); ++i)\n\t\t{\n\t\t\tconst auto device_description = (wxDeviceDescription*)m_portal_device->GetClientObject(i);\n\t\t\tif (device_description && config.portal_device == device_description->GetDescription()->GetIdentifier())\n\t\t\t{\n\t\t\t\tm_portal_device->SetSelection(i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t\tm_portal_device->SetSelection(0);\n\n\t// account\n\tUpdateOnlineAccounts();\n\tm_active_account->SetSelection(0);\n\tfor(uint32 i = 0; i < m_active_account->GetCount(); ++i)\n\t{\n\t\tconst auto* obj = dynamic_cast<wxAccountData*>(m_active_account->GetClientObject(i));\n\t\twxASSERT(obj);\n\t\tif(obj->GetAccount().GetPersistentId() == ActiveSettings::GetPersistentId())\n\t\t{\n\t\t\tm_active_account->SetSelection(i);\n\t\t\tbreak;\n\t\t}\n\t}\n\tm_active_service->SetSelection((int)config.GetAccountNetworkService(ActiveSettings::GetPersistentId()));\n\n\tUpdateAccountInformation();\n\n\t// debug\n\tm_crash_dump->SetSelection((int)config.crash_dump.GetValue());\n\tm_gdb_port->SetValue(config.gdb_port.GetValue());\n#if ENABLE_METAL\n\tm_gpu_capture_dir->SetValue(wxString::FromUTF8(config.gpu_capture_dir.GetValue()));\n\tm_framebuffer_fetch->SetValue(config.framebuffer_fetch);\n#endif\n}\n\nvoid GeneralSettings2::OnAudioAPISelected(wxCommandEvent& event)\n{\n\tIAudioAPI::AudioAPI api;\n\tif (m_audio_api->GetStringSelection() == kDirectSound)\n\t\tapi = IAudioAPI::DirectSound;\n\telse if (m_audio_api->GetStringSelection() == kXAudio27)\n\t\tapi = IAudioAPI::XAudio27;\n\telse if (m_audio_api->GetStringSelection() == kXAudio2)\n\t\tapi = IAudioAPI::XAudio2;\n\telse if (m_audio_api->GetStringSelection() == kCubeb)\n\t\tapi = IAudioAPI::Cubeb;\n\telse\n\t{\n\t\twxFAIL_MSG(\"invalid audio api selected!\");\n\t\treturn;\n\t}\n\n\tGetConfig().audio_api = api;\n\tUpdateAudioDeviceList();\n\tOnAudioDeviceSelected(event);\n}\n\n#define AX_FRAMES_PER_GROUP 4\n\nvoid GeneralSettings2::UpdateAudioDevice()\n{\n\tauto& config = GetConfig();\n\n\tstd::unique_lock lock(g_audioMutex);\n\tstd::unique_lock inputLock(g_audioInputMutex);\n\n\t// tv audio device\n\t{\n\t\tconst auto selection = m_tv_device->GetSelection();\n\t\tif (selection == wxNOT_FOUND)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn;\n\t\t}\n\n\t\tg_tvAudio.reset();\n\n\t\tif (m_tv_device->HasClientObjectData())\n\t\t{\n\t\t\tconst auto description = (wxDeviceDescription*)m_tv_device->GetClientObject(selection);\n\t\t\tif (description)\n\t\t\t{\n\t\t\t\tsint32 channels;\n\t\t\t\tif (m_game_launched && g_tvAudio)\n\t\t\t\t\tchannels = g_tvAudio->GetChannels();\n\t\t\t\telse\n\t\t\t\t\tchannels = CemuConfig::AudioChannelsToNChannels(config.tv_channels);\n\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tg_tvAudio = IAudioAPI::CreateDevice((IAudioAPI::AudioAPI)config.audio_api, description->GetDescription(), 48000, channels, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16);\n\t\t\t\t\tg_tvAudio->SetVolume(m_tv_volume->GetValue());\n\t\t\t\t}\n\t\t\t\tcatch (std::runtime_error& ex)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"can't initialize tv audio: {}\", ex.what());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// pad audio device\n\t{\n\t\tconst auto selection = m_pad_device->GetSelection();\n\t\tif (selection == wxNOT_FOUND)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn;\n\t\t}\n\n\t\tg_padAudio.reset();\n\n\t\tif (m_pad_device->HasClientObjectData())\n\t\t{\n\t\t\tconst auto description = (wxDeviceDescription*)m_pad_device->GetClientObject(selection);\n\t\t\tif (description)\n\t\t\t{\n\t\t\t\tsint32 channels;\n\t\t\t\tif (m_game_launched && g_padAudio)\n\t\t\t\t\tchannels = g_padAudio->GetChannels();\n\t\t\t\telse\n\t\t\t\t\tchannels = CemuConfig::AudioChannelsToNChannels(config.pad_channels);\n\n\t\t\t\tg_padVolume = m_pad_volume->GetValue();\n\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tg_padAudio = IAudioAPI::CreateDevice((IAudioAPI::AudioAPI)config.audio_api, description->GetDescription(), 48000, channels, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16);\n\t\t\t\t\tg_padAudio->SetVolume(m_pad_volume->GetValue());\n\t\t\t\t}\n\t\t\t\tcatch (std::runtime_error& ex)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"can't initialize pad audio: {}\", ex.what());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// input audio device\n\t{\n\t\tconst auto selection = m_input_device->GetSelection();\n\t\tif (selection == wxNOT_FOUND)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn;\n\t\t}\n\n\t\tg_inputAudio.reset();\n\n\t\tif (m_input_device->HasClientObjectData())\n\t\t{\n\t\t\tconst auto description = (wxInputDeviceDescription*)m_input_device->GetClientObject(selection);\n\t\t\tif (description)\n\t\t\t{\n\t\t\t\tsint32 channels;\n\t\t\t\tif (m_game_launched && g_inputAudio)\n\t\t\t\t\tchannels = g_inputAudio->GetChannels();\n\t\t\t\telse\n\t\t\t\t\tchannels = CemuConfig::AudioChannelsToNChannels(config.input_channels);\n\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tg_inputAudio = IAudioInputAPI::CreateDevice(IAudioInputAPI::AudioInputAPI::Cubeb, description->GetDescription(), 32000, channels, snd_core::AX_SAMPLES_PER_3MS_32KHZ, 16);\n\t\t\t\t\tg_inputAudio->SetVolume(m_input_volume->GetValue());\n\t\t\t\t}\n\t\t\t\tcatch (std::runtime_error& ex)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"can't initialize pad audio: {}\", ex.what());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// skylander portal audio device\n\t{\n\t\tconst auto selection = m_portal_device->GetSelection();\n\t\tif (selection == wxNOT_FOUND)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn;\n\t\t}\n\n\t\tg_portalAudio.reset();\n\n\t\tif (m_portal_device->HasClientObjectData())\n\t\t{\n\t\t\tconst auto description = (wxDeviceDescription*)m_portal_device->GetClientObject(selection);\n\t\t\tif (description)\n\t\t\t{\n\t\t\t\tsint32 channels;\n\t\t\t\tif (m_game_launched && g_portalAudio)\n\t\t\t\t\tchannels = g_portalAudio->GetChannels();\n\t\t\t\telse\n\t\t\t\t\tchannels = 1;\n\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tg_portalAudio = IAudioAPI::CreateDevice((IAudioAPI::AudioAPI)config.audio_api, description->GetDescription(), 8000, 1, 32, 16);\n\t\t\t\t\tg_portalAudio->SetVolume(m_portal_volume->GetValue());\n\t\t\t\t}\n\t\t\t\tcatch (std::runtime_error& ex)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"can't initialize portal audio: {}\", ex.what());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n}\n\nvoid GeneralSettings2::OnAudioDeviceSelected(wxCommandEvent& event)\n{\n\tUpdateAudioDevice();\n}\n\nvoid GeneralSettings2::OnAudioChannelsSelected(wxCommandEvent& event)\n{\n\tconst auto obj = wxDynamicCast(event.GetEventObject(), wxChoice);\n\twxASSERT(obj);\n\tif (obj->GetSelection() == wxNOT_FOUND)\n\t\treturn;\n\n\tauto& config = GetConfig();\n\tif (obj == m_tv_channels)\n\t{\n\t\tif (config.tv_channels == (AudioChannels)obj->GetSelection())\n\t\t\treturn;\n\n\t\tconfig.tv_channels = (AudioChannels)obj->GetSelection();\n\t}\n\telse if (obj == m_pad_channels)\n\t{\n\t\tif (config.pad_channels == (AudioChannels)obj->GetSelection())\n\t\t\treturn;\n\n\t\tconfig.pad_channels = (AudioChannels)obj->GetSelection();\n\t}\n\telse\n\t\tcemu_assert_debug(false);\n\n\tif(m_game_launched)\n\t\twxMessageBox(_(\"You have to restart the game in order to apply the new settings.\"), _(\"Information\"), wxOK | wxCENTRE, this);\n\telse\n\t\tUpdateAudioDevice();\n}\n\nvoid GeneralSettings2::OnGraphicAPISelected(wxCommandEvent& event)\n{\n\tHandleGraphicsApiSelection();\n}\n\nvoid GeneralSettings2::OnUserDisplaySRGBSelected(wxCommandEvent& event)\n{\n\tm_userDisplayGamma->SetValue(2.2f);\n\tif(event.IsChecked())\n\t\tm_userDisplayGamma->Disable();\n\telse\n\t\tm_userDisplayGamma->Enable();\n\tauto& config = GetConfig();\n\tconfig.userDisplayGamma = m_userDisplayGamma->GetValue() * !event.IsChecked();\n}\n\nvoid GeneralSettings2::OnAddPathClicked(wxCommandEvent& event)\n{\n\twxDirDialog path_dialog(this, _(\"Select a directory containing games.\"), wxEmptyString, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);\n\tif (path_dialog.ShowModal() != wxID_OK || path_dialog.GetPath().empty())\n\t\treturn;\n\n\tconst auto path = path_dialog.GetPath();\n\t// test if already included\n\tfor (auto& s : m_game_paths->GetStrings())\n\t{\n\t\tif (s == path)\n\t\t\treturn;\n\t}\n\n\tm_game_paths->Append(path);\n\tm_reload_gamelist = true;\n\n\t// trigger title list rescan with new path configuration\n\tCafeTitleList::ClearScanPaths();\n\tfor (auto& it : m_game_paths->GetStrings())\n\t\tCafeTitleList::AddScanPath(wxHelper::MakeFSPath(it));\n\tCafeTitleList::Refresh();\n}\n\nvoid GeneralSettings2::OnRemovePathClicked(wxCommandEvent& event)\n{\n\tconst auto selection = m_game_paths->GetSelection();\n\tif (selection == wxNOT_FOUND)\n\t\treturn;\n\n\tm_game_paths->Delete(selection);\n\tm_reload_gamelist = true;\n\t// trigger title list rescan with new path configuration\n\tCafeTitleList::ClearScanPaths();\n\tfor (auto& it : m_game_paths->GetStrings())\n\t\tCafeTitleList::AddScanPath(wxHelper::MakeFSPath(it));\n\tCafeTitleList::Refresh();\n}\n\nvoid GeneralSettings2::OnActiveAccountChanged(wxCommandEvent& event)\n{\n\tUpdateAccountInformation();\n\tm_has_account_change = true;\n}\n\nvoid GeneralSettings2::OnAccountServiceChanged(wxCommandEvent& event)\n{\n\tauto& config = GetConfig();\n\tuint32 peristentId = GetSelectedAccountPersistentId();\n\tconfig.SetAccountSelectedService(peristentId, static_cast<NetworkService>(m_active_service->GetSelection()));\n\tUpdateAccountInformation();\n}\n\nvoid GeneralSettings2::OnMLCPathSelect(wxCommandEvent& event)\n{\n\tif(CafeSystem::IsTitleRunning())\n\t{\n\t\twxMessageBox(_(\"Can't change MLC path while a game is running!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\t// show directory dialog\n\twxDirDialog path_dialog(this, _(\"Select MLC directory\"), wxEmptyString, wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);\n\tif (path_dialog.ShowModal() != wxID_OK || path_dialog.GetPath().empty())\n\t\treturn;\n\t// check if the choosen MLC path is an already initialized MLC location\n\tfs::path newMlc = wxHelper::MakeFSPath(path_dialog.GetPath());\n\tif(CemuApp::CheckMLCPath(newMlc))\n\t{\n\t\t// ask user if they are sure they want to use this folder and let them know that accounts and saves wont transfer\n\t\twxString message = _(\"Note that changing the MLC location will not transfer any accounts or save files. Are you sure you want to change the path?\");\n\t\twxMessageDialog dialog(this, message, _(\"Warning\"), wxYES_NO | wxCENTRE | wxICON_WARNING);\n\t\tif(dialog.ShowModal() == wxID_NO)\n\t\t\treturn;\n\t\tif( !CemuApp::CreateDefaultMLCFiles(newMlc) ) // creating also acts as a check for read+write access\n\t\t{\n\t\t\twxMessageBox(_(\"Failed to create default MLC files in the selected directory. The MLC path has not been changed\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\treturn;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// ask user if they want to create a new mlc structure at the choosen location\n\t\twxString message = _(\"The selected directory does not contain the expected MLC structure. Do you want to create a new MLC structure in this directory?\\nNote that changing the MLC location will not transfer any accounts or save files.\");\n\t\twxMessageDialog dialog(this, message, _(\"Warning\"), wxYES_NO | wxCENTRE | wxICON_WARNING);\n\t\tif( !CemuApp::CreateDefaultMLCFiles(newMlc) )\n\t\t{\n\t\t\twxMessageBox(_(\"Failed to create default MLC files in the selected directory. The MLC path has not been changed\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\treturn;\n\t\t}\n\t}\n\t// update MLC path and store any other modified settings\n\tGetConfig().SetMLCPath(newMlc);\n\tStoreConfig();\n\twxMessageBox(_(\"Cemu needs to be restarted for the changes to take effect.\"), _(\"Information\"), wxOK | wxCENTRE | wxICON_INFORMATION, this);\n\t// close settings and then cemu\n\twxCloseEvent closeEvent(wxEVT_CLOSE_WINDOW);\n\twxPostEvent(this, closeEvent);\n\twxPostEvent(GetParent(), closeEvent);\n}\n\nvoid GeneralSettings2::OnMLCPathClear(wxCommandEvent& event)\n{\n\tif(CafeSystem::IsTitleRunning())\n\t{\n\t\twxMessageBox(_(\"Can't change MLC path while a game is running!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\twxString message = _(\"Note that changing the MLC location will not transfer any accounts or save files. Are you sure you want to change the path?\");\n\twxMessageDialog dialog(this, message, _(\"Warning\"), wxYES_NO | wxCENTRE | wxICON_WARNING);\n\tif(dialog.ShowModal() == wxID_NO)\n\t\treturn;\n\tGetConfig().SetMLCPath(\"\");\n\tStoreConfig();\n\tGetConfigHandle().Save();\n\twxMessageBox(_(\"Cemu needs to be restarted for the changes to take effect.\"), _(\"Information\"), wxOK | wxCENTRE | wxICON_INFORMATION, this);\n\t// close settings and then cemu\n\twxCloseEvent closeEvent(wxEVT_CLOSE_WINDOW);\n\twxPostEvent(this, closeEvent);\n\twxPostEvent(GetParent(), closeEvent);\n}\n\nvoid GeneralSettings2::OnShowOnlineValidator(wxCommandEvent& event)\n{\n\tconst auto selection = m_active_account->GetSelection();\n\tif (selection == wxNOT_FOUND)\n\t\treturn;\n\n\tconst auto* obj = dynamic_cast<wxAccountData*>(m_active_account->GetClientObject(selection));\n\twxASSERT(obj);\n\tconst auto& account = obj->GetAccount();\n\n\tconst auto validator = account.ValidateOnlineFiles();\n\tif (validator) // everything valid? shouldn't happen\n\t\treturn;\n\n\twxString err;\n\terr << _(\"The following error(s) have been found:\") << '\\n';\n\n\tif (validator.otp == OnlineValidator::FileState::Missing)\n\t\terr << _(\"otp.bin missing in Cemu directory\") << '\\n';\n\telse if(validator.otp == OnlineValidator::FileState::Corrupted)\n\t\terr << _(\"otp.bin is invalid\") << '\\n';\n\n\tif (validator.seeprom == OnlineValidator::FileState::Missing)\n\t\terr << _(\"seeprom.bin missing in Cemu directory\") << '\\n';\n\telse if(validator.seeprom == OnlineValidator::FileState::Corrupted)\n\t\terr << _(\"seeprom.bin is invalid\") << '\\n';\n\n\tif(!validator.missing_files.empty())\n\t{\n\t\terr << _(\"Missing certificate and key files:\") << '\\n';\n\n\t\tint counter = 0;\n\t\tfor (const auto& f : validator.missing_files)\n\t\t{\n\t\t\terr << f << '\\n';\n\n\t\t\t++counter;\n\t\t\tif(counter > 10)\n\t\t\t{\n\t\t\t\terr << \"...\" << '\\n';\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\terr << '\\n';\n\t}\n\n\tif (!validator.valid_account)\n\t{\n\t\terr << _(\"The currently selected account is not a valid or dumped online account:\") << '\\n';\n\t\terr << GetOnlineAccountErrorMessage(validator.account_error);\n\t}\n\n\twxMessageBox(err, _(\"Online Status\"), wxOK | wxCENTRE | wxICON_INFORMATION);\n}\n\nwxString GeneralSettings2::GetOnlineAccountErrorMessage(OnlineAccountError error)\n{\n\tswitch (error)\n\t{\n\t\tcase OnlineAccountError::kNoAccountId:\n\t\t\treturn _(\"AccountId missing (The account is not connected to a NNID/PNID)\");\n\t\tcase OnlineAccountError::kNoPasswordCached:\n\t\t\treturn _(\"IsPasswordCacheEnabled is set to false (The remember password option on your Wii U must be enabled for this account before dumping it)\");\n\t\tcase OnlineAccountError::kPasswordCacheEmpty:\n\t\t\treturn _(\"AccountPasswordCache is empty (The remember password option on your Wii U must be enabled for this account before dumping it)\");\n\t\tcase OnlineAccountError::kNoPrincipalId:\n\t\t\treturn _(\"PrincipalId missing\");\n\t\tdefault:\n\t\t\treturn \"no error\";\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/GeneralSettings2.h",
    "content": "#pragma once\n#include <wx/collpane.h>\n#include <wx/propgrid/propgrid.h>\n#include <Cafe/Account/Account.h>\n\nclass wxCheckBox;\nclass wxChoice;\nclass wxColourPickerCtrl;\nclass wxListBox;\nclass wxNotebook;\nclass wxRadioBox;\nclass wxSlider;\nclass wxSpinCtrl;\nclass wxSpinCtrlDouble;\nclass wxStaticText;\n\nwxDECLARE_EVENT(wxEVT_ACCOUNTLIST_REFRESH, wxCommandEvent);\n\nclass GeneralSettings2 : public wxDialog\n{\npublic:\n\tGeneralSettings2(wxWindow* parent, bool game_launched);\n\t~GeneralSettings2();\n\n\t[[nodiscard]] bool ShouldReloadGamelist() const  { return m_reload_gamelist; }\n\t[[nodiscard]] bool MLCModified() const  { return m_mlc_modified; }\n\tvoid OnClose(wxCloseEvent& event);\n\nprivate:\n\tvoid ValidateConfig();\n\tvoid StoreConfig();\n\tvoid DisableSettings(bool game_launched);\n\n\tbool m_reload_gamelist = false;\n\tbool m_mlc_modified = false;\n\tbool m_game_launched;\n\n\tbool m_has_account_change = false; // keep track of dirty state of accounts\n\n\n\twxPanel* AddGeneralPage(wxNotebook* notebook);\n\twxPanel* AddGraphicsPage(wxNotebook* notebook);\n\twxPanel* AddAudioPage(wxNotebook* notebook);\n\twxPanel* AddOverlayPage(wxNotebook* notebook);\n\twxPanel* AddAccountPage(wxNotebook* notebook);\n\twxPanel* AddDebugPage(wxNotebook* notebook);\n\n\t// General\n\twxChoice * m_language;\n\twxCheckBox* m_save_window_position_size;\n\twxCheckBox* m_save_padwindow_position_size;\n\twxCheckBox* m_discord_presence, *m_fullscreen_menubar;\n\twxCheckBox* m_auto_update, *m_receive_untested_releases, *m_save_screenshot;\n\twxCheckBox* m_disable_screensaver;\n\twxCheckBox* m_play_boot_sound;\n#if BOOST_OS_WINDOWS\n\twxChoice* m_msw_theme;\n#endif\n#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)\n   \twxCheckBox* m_feral_gamemode;\n#endif\n\twxListBox* m_game_paths;\n\twxTextCtrl* m_mlc_path;\n\n\t// Graphics\n\twxChoice* m_graphic_api, * m_graphic_device;\n\twxChoice* m_vsync;\n\twxCheckBox* m_overrideGamma;\n\twxSpinCtrlDouble* m_overrideGammaValue;\n\twxSpinCtrlDouble* m_userDisplayGamma;\n\twxCheckBox* m_userDisplayisSRGB;\n\n\twxCheckBox *m_async_compile, *m_gx2drawdone_sync;\n#if ENABLE_METAL\n\twxCheckBox *m_force_mesh_shaders;\n#endif\n\twxRadioBox* m_upscale_filter, *m_downscale_filter, *m_fullscreen_scaling;\n\twxChoice* m_overlay_position, *m_notification_position, *m_overlay_scale, *m_notification_scale;\n\twxCheckBox* m_controller_profile_name, *m_controller_low_battery, *m_shader_compiling, *m_friends_data;\n\twxCheckBox *m_overlay_fps, *m_overlay_drawcalls, *m_overlay_cpu, *m_overlay_cpu_per_core,*m_overlay_ram, *m_overlay_vram, *m_overlay_debug;\n\twxColourPickerCtrl *m_overlay_font_color, *m_notification_font_color;\n\n\t// Audio\n\twxChoice* m_audio_api;\n\twxSlider *m_audio_latency;\n\twxSlider *m_tv_volume, *m_pad_volume, *m_input_volume, *m_portal_volume;\n\twxChoice *m_tv_channels, *m_pad_channels, *m_input_channels;\n\twxChoice *m_tv_device, *m_pad_device, *m_input_device, *m_portal_device;\n\n\t// Account\n\twxButton* m_create_account, * m_delete_account;\n\twxChoice* m_active_account;\n\twxRadioBox* m_active_service;\n\twxCollapsiblePane* m_account_information;\n\twxPropertyGrid* m_account_grid;\n\twxBitmapButton* m_validate_online;\n\twxStaticText* m_online_status;\n\n\t// Debug\n\twxChoice* m_crash_dump;\n\twxSpinCtrl* m_gdb_port;\n#if ENABLE_METAL\n\twxTextCtrl* m_gpu_capture_dir;\n\twxCheckBox* m_framebuffer_fetch;\n#endif\n\n\tvoid OnAccountCreate(wxCommandEvent& event);\n\tvoid OnAccountDelete(wxCommandEvent& event);\n\tvoid OnAccountSettingsChanged(wxPropertyGridEvent& event);\n\tvoid OnAudioLatencyChanged(wxCommandEvent& event);\n\tvoid OnVolumeChanged(wxCommandEvent& event);\n\tvoid OnInputVolumeChanged(wxCommandEvent& event);\n\tvoid OnSliderChangedPercent(wxCommandEvent& event);\n\tvoid OnLatencySliderChanged(wxCommandEvent& event);\n\tvoid OnAudioAPISelected(wxCommandEvent& event);\n\tvoid OnAudioDeviceSelected(wxCommandEvent& event);\n\tvoid OnAudioChannelsSelected(wxCommandEvent& event);\n\tvoid OnGraphicAPISelected(wxCommandEvent& event);\n\tvoid OnUserDisplaySRGBSelected(wxCommandEvent& event);\n\tvoid OnAddPathClicked(wxCommandEvent& event);\n\tvoid OnRemovePathClicked(wxCommandEvent& event);\n\tvoid OnActiveAccountChanged(wxCommandEvent& event);\n\tvoid OnMLCPathSelect(wxCommandEvent& event);\n\tvoid OnMLCPathClear(wxCommandEvent& event);\n\tvoid OnShowOnlineValidator(wxCommandEvent& event);\n\tvoid OnAccountServiceChanged(wxCommandEvent& event);\n\tstatic wxString GetOnlineAccountErrorMessage(OnlineAccountError error);\n\n\tuint32 GetSelectedAccountPersistentId();\n\n\t// updates cemu audio devices\n\tvoid UpdateAudioDevice();\n\t// refreshes audio device list for dropdown\n\tvoid UpdateAudioDeviceList();\n\n\tvoid ResetAccountInformation();\n\tvoid UpdateAccountInformation();\n\tvoid UpdateOnlineAccounts();\n\tvoid HandleGraphicsApiSelection();\n\tvoid ApplyConfig();\n};\n"
  },
  {
    "path": "src/gui/wxgui/GettingStartedDialog.cpp",
    "content": "#include \"wxgui/GettingStartedDialog.h\"\n\n#include <wx/sizer.h>\n#include <wx/filepicker.h>\n#include <wx/statbox.h>\n#include <wx/msgdlg.h>\n#include <wx/radiobox.h>\n#include <wx/button.h>\n\n#include \"config/ActiveSettings.h\"\n#include \"wxCemuConfig.h\"\n#include \"wxgui/CemuApp.h\"\n#include \"wxgui/DownloadGraphicPacksWindow.h\"\n#include \"wxgui/GraphicPacksWindow2.h\"\n#include \"wxgui/input/InputSettings2.h\"\n#include \"config/CemuConfig.h\"\n\n#include \"Cafe/TitleList/TitleList.h\"\n\n#if BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_BSD\n#include \"resource/embedded/resources.h\"\n#endif\n\n#include \"wxHelper.h\"\n\nwxDEFINE_EVENT(EVT_REFRESH_FIRST_PAGE, wxCommandEvent); // used to refresh the first page after the language change\n\nwxPanel* GettingStartedDialog::CreatePage1()\n{\n\tauto* mainPanel = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\tauto* page1_sizer = new wxBoxSizer(wxVERTICAL);\n\t{\n\t\tauto* sizer = new wxBoxSizer(wxHORIZONTAL);\n\t\tsizer->Add(new wxStaticBitmap(mainPanel, wxID_ANY, wxICON(M_WND_ICON128)), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_page1.staticText11 = new wxStaticText(mainPanel, wxID_ANY, _(\"It looks like you're starting Cemu for the first time.\\nThis quick setup assistant will help you get the best experience\"));\n\t\tm_page1.staticText11->Wrap(-1);\n\t\tsizer->Add(m_page1.staticText11, 0, wxALL, 5);\n\t\tpage1_sizer->Add(sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\tif(ActiveSettings::IsPortableMode())\n\t{\n\t\tm_page1.portableModeInfoText = new wxStaticText(mainPanel, wxID_ANY, _(\"Cemu is running in portable mode\"));\n\t\tm_page1.portableModeInfoText->Show(true);\n\t\tpage1_sizer->Add(m_page1.portableModeInfoText, 0, wxALL, 5);\n\n\t}\n\n\t// language selection\n#if 0\n\t{\n\t\tm_page1.languageBoxSizer = new wxStaticBoxSizer(wxVERTICAL, mainPanel, _(\"Language\"));\n\t\tm_page1.languageText = new wxStaticText(m_page1.languageBoxSizer->GetStaticBox(), wxID_ANY, _(\"Select the language you want to use in Cemu\"));\n\t\tm_page1.languageBoxSizer->Add(m_page1.languageText, 0, wxALL, 5);\n\n\t\twxString language_choices[] = { _(\"Default\") };\n\t\twxChoice* m_language = new wxChoice(m_page1.languageBoxSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(language_choices), language_choices);\n\t\tm_language->SetSelection(0);\n\n\t\tfor (const auto& language : wxGetApp().GetLanguages())\n\t\t{\n\t\t\tm_language->Append(language->DescriptionNative);\n\t\t}\n\n\t\tm_language->SetSelection(0);\n\t\tm_page1.languageBoxSizer->Add(m_language, 0, wxALL | wxEXPAND, 5);\n\n\t\tpage1_sizer->Add(m_page1.languageBoxSizer, 0, wxALL | wxEXPAND, 5);\n\n\t\tm_language->Bind(wxEVT_CHOICE, [this, m_language](const auto&)\n\t\t{\n\t\t\tconst auto language = m_language->GetStringSelection();\n\t\t\tauto selection = m_language->GetSelection();\n\t\t\tif (selection == 0)\n\t\t\t\tGetConfig().language = wxLANGUAGE_DEFAULT;\n\t\t\telse\n\t\t\t{\n\t\t\t\tauto& app = wxGetApp();\n\t\t\t\tconst auto language = m_language->GetStringSelection();\n\t\t\t\tfor (const auto& lang : app.GetLanguages())\n\t\t\t\t{\n\t\t\t\t\tif (lang->DescriptionNative == language)\n\t\t\t\t\t{\n\t\t\t\t\t\tapp.LocalizeUI(static_cast<wxLanguage>(lang->Language));\n\t\t\t\t\t\twxCommandEvent event(EVT_REFRESH_FIRST_PAGE);\n\t\t\t\t\t\twxPostEvent(this, event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n#endif\n\n\t{\n\t\tm_page1.gamePathBoxSizer = new wxStaticBoxSizer(wxVERTICAL, mainPanel, _(\"Game paths\"));\n\t\tm_page1.gamePathText = new wxStaticText(m_page1.gamePathBoxSizer->GetStaticBox(), wxID_ANY, _(\"The game path is scanned by Cemu to automatically locate your games, game updates and DLCs. We recommend creating a dedicated directory in which\\nyou place all your Wii U game files. Additional paths can be set later in Cemu's general settings. All common Wii U game formats are supported by Cemu.\"));\n\t\tm_page1.gamePathBoxSizer->Add(m_page1.gamePathText, 0, wxALL, 5);\n\n\t\tauto* game_path_sizer = new wxBoxSizer(wxHORIZONTAL);\n\n\t\tm_page1.gamePathText2 = new wxStaticText(m_page1.gamePathBoxSizer->GetStaticBox(), wxID_ANY, _(\"Game path\"));\n\t\tgame_path_sizer->Add(m_page1.gamePathText2, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tm_page1.gamePathPicker = new wxDirPickerCtrl(m_page1.gamePathBoxSizer->GetStaticBox(), wxID_ANY, wxEmptyString, _(\"Select a folder\"));\n\t\tgame_path_sizer->Add(m_page1.gamePathPicker, 1, wxALL, 5);\n\n\t\tm_page1.gamePathBoxSizer->Add(game_path_sizer, 0, wxEXPAND, 5);\n\n\t\tpage1_sizer->Add(m_page1.gamePathBoxSizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t{\n\t\tauto* sizer = new wxStaticBoxSizer(wxVERTICAL, mainPanel, _(\"Graphic packs && mods\"));\n\n\t\tsizer->Add(new wxStaticText(sizer->GetStaticBox(), wxID_ANY, _(\"Graphic packs improve games by offering the ability to change resolution, increase FPS, tweak visuals or add gameplay modifications.\\nGet started by opening the graphic packs configuration window.\\n\")), 0, wxALL, 5);\n\n\t\tauto* download_gp = new wxButton(sizer->GetStaticBox(), wxID_ANY, _(\"Download and configure graphic packs\"));\n\t\tdownload_gp->Bind(wxEVT_BUTTON, &GettingStartedDialog::OnConfigureGPs, this);\n\t\tsizer->Add(download_gp, 0, wxALIGN_CENTER | wxALL, 5);\n\n\t\tpage1_sizer->Add(sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t{\n\t\tauto* sizer = new wxFlexGridSizer(0, 1, 0, 0);\n\t\tsizer->AddGrowableCol(0);\n\t\tsizer->AddGrowableRow(0);\n\t\tsizer->SetFlexibleDirection(wxBOTH);\n\t\tsizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL);\n\n\t\tauto* next = new wxButton(mainPanel, wxID_ANY, _(\"Next\"));\n\t\tnext->Bind(wxEVT_BUTTON, [this](const auto&){m_notebook->SetSelection(1); });\n\t\tsizer->Add(next, 0, wxALIGN_BOTTOM | wxALIGN_RIGHT | wxALL, 5);\n\n\t\tpage1_sizer->Add(sizer, 1, wxEXPAND, 5);\n\t}\n\n\tmainPanel->SetSizer(page1_sizer);\n\treturn mainPanel;\n}\n\nwxPanel* GettingStartedDialog::CreatePage2()\n{\n\tauto* result = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\tauto* page2_sizer = new wxBoxSizer(wxVERTICAL);\n\n\t{\n\t\tauto* sizer = new wxStaticBoxSizer(new wxStaticBox(result, wxID_ANY, _(\"Input settings\")), wxVERTICAL);\n\n\t\tsizer->Add(new wxStaticText(sizer->GetStaticBox(), wxID_ANY, _(\"You can configure one controller for each player.\\nWe advise you to always use GamePad as emulated input for the first player, since many games expect the GamePad to be present.\\nIt is also required for touch functionality.\\nThe default global hotkeys are:\\nCTRL - show pad screen\\nCTRL + TAB - toggle pad screen\\nALT + ENTER - toggle fullscreen\\nESC - leave fullscreen\\n\\nIf you're having trouble configuring your controller, make sure to have it in idle state and press calibrate.\\nAlso don't set the axis deadzone too low.\")), 0, wxALL, 5);\n\n\t\tauto* input_button = new wxButton(sizer->GetStaticBox(), wxID_ANY, _(\"Configure input\"));\n\t\tinput_button->Bind(wxEVT_BUTTON, &GettingStartedDialog::OnInputSettings, this);\n\t\tsizer->Add(input_button, 0, wxALIGN_CENTER | wxALL, 5);\n\n\t\tpage2_sizer->Add(sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t{\n\t\tauto* sizer = new wxStaticBoxSizer(new wxStaticBox(result, wxID_ANY, _(\"Additional options\")), wxVERTICAL);\n\n\t\tauto* option_sizer = new wxFlexGridSizer(0, 2, 0, 0);\n\t\toption_sizer->SetFlexibleDirection(wxBOTH);\n\t\toption_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tm_page2.fullscreenCheckbox = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _(\"Start games with fullscreen\"));\n\t\toption_sizer->Add(m_page2.fullscreenCheckbox, 0, wxALL, 5);\n\n\t\tm_page2.separateCheckbox = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _(\"Open separate pad screen\"));\n\t\toption_sizer->Add(m_page2.separateCheckbox, 0, wxALL, 5);\n\n\t\tm_page2.updateCheckbox = new wxCheckBox(sizer->GetStaticBox(), wxID_ANY, _(\"Automatically check for updates\"));\n\t\toption_sizer->Add(m_page2.updateCheckbox, 0, wxALL, 5);\n#if BOOST_OS_LINUX \n\t\tif (!std::getenv(\"APPIMAGE\")) {\n\t\t\tm_page2.updateCheckbox->Disable();\n\t\t} \n#endif\n\t\tsizer->Add(option_sizer, 1, wxEXPAND, 5);\n\t\tpage2_sizer->Add(sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t{\n\t\tauto* sizer = new wxFlexGridSizer(0, 3, 0, 0);\n\t\tsizer->AddGrowableCol(1);\n\t\tsizer->AddGrowableRow(0);\n\t\tsizer->SetFlexibleDirection(wxBOTH);\n\t\tsizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL);\n\n\t\tauto* previous = new wxButton(result, wxID_ANY, _(\"Previous\"));\n\t\tprevious->Bind(wxEVT_BUTTON, [this](const auto&) {m_notebook->SetSelection(0); });\n\t\tsizer->Add(previous, 0, wxALIGN_BOTTOM | wxALIGN_RIGHT | wxALL, 5);\n\n\t\tauto* close = new wxButton(result, wxID_ANY, _(\"Close\"));\n\t\tclose->Bind(wxEVT_BUTTON, [this](const auto&){ Close(); });\n\t\tsizer->Add(close, 1, wxALIGN_BOTTOM | wxALIGN_RIGHT | wxALL, 5);\n\n\t\tpage2_sizer->Add(sizer, 1, wxEXPAND | wxLEFT, 5);\n\t}\n\t\n\tresult->SetSizer(page2_sizer);\n\treturn result;\n}\n\nvoid GettingStartedDialog::ApplySettings()\n{\n\tauto& config = GetWxGUIConfig();\n\tm_page2.fullscreenCheckbox->SetValue(config.fullscreen.GetValue());\n\tm_page2.updateCheckbox->SetValue(config.check_update.GetValue());\n\tm_page2.separateCheckbox->SetValue(config.pad_open.GetValue());\n}\n\nvoid GettingStartedDialog::UpdateWindowSize()\n{\n\tfor (auto it = m_notebook->GetChildren().GetFirst(); it; it = it->GetNext())\n\t{\n\t\tit->GetData()->Layout();\n\t}\n\tm_notebook->Layout();\n\tLayout();\n\tFit();\n}\n\nvoid GettingStartedDialog::OnClose(wxCloseEvent& event)\n{\n\tevent.Skip();\n\n\tauto& wxGUIConfig = GetWxGUIConfig();\n\twxGUIConfig.fullscreen = m_page2.fullscreenCheckbox->GetValue();\n\twxGUIConfig.check_update = m_page2.updateCheckbox->GetValue();\n\twxGUIConfig.pad_open = m_page2.separateCheckbox->GetValue();\n\n\tauto& config = GetConfig();\n\tconst fs::path gamePath = wxHelper::MakeFSPath(m_page1.gamePathPicker->GetPath());\n\tstd::error_code ec;\n\tif (!gamePath.empty() && fs::exists(gamePath, ec))\n\t{\n\t\tconst auto it = std::find(config.game_paths.cbegin(), config.game_paths.cend(), gamePath);\n\t\tif (it == config.game_paths.cend())\n\t\t{\n\t\t\tconfig.game_paths.emplace_back(_pathToUtf8(gamePath));\n\t\t}\n\t}\n}\n\nGettingStartedDialog::GettingStartedDialog(wxWindow* parent)\n\t: wxDialog(parent, wxID_ANY, _(\"Getting started\"), wxDefaultPosition, { 740,530 }, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)\n{\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tm_notebook = new wxSimplebook(this, wxID_ANY);\n\n\tauto* m_page1 = CreatePage1();\n\tm_notebook->AddPage(m_page1, wxEmptyString);\n\n\tauto* m_page2 = CreatePage2();\n\tm_notebook->AddPage(m_page2, wxEmptyString);\n\n\tsizer->Add(m_notebook, 1, wxEXPAND | wxALL, 5);\n\n\tthis->SetSizer(sizer);\n\tthis->Centre(wxBOTH);\n\tthis->Bind(wxEVT_CLOSE_WINDOW, &GettingStartedDialog::OnClose, this);\n\n\tApplySettings();\n\tUpdateWindowSize();\n}\n\nvoid GettingStartedDialog::OnConfigureGPs(wxCommandEvent& event)\n{\n\tDownloadGraphicPacksWindow dialog(this);\n\tdialog.ShowModal();\n\tGraphicPacksWindow2::RefreshGraphicPacks();\n\tGraphicPacksWindow2 window(this, 0);\n\twindow.ShowModal();\n}\n\nvoid GettingStartedDialog::OnInputSettings(wxCommandEvent& event)\n{\n\tInputSettings2 dialog(this);\n\tdialog.ShowModal();\n}\n"
  },
  {
    "path": "src/gui/wxgui/GettingStartedDialog.h",
    "content": "#pragma once\n\n#include <wx/dialog.h>\n#include <wx/checkbox.h>\n#include <wx/filepicker.h>\n#include <wx/statbmp.h>\n#include <wx/simplebook.h>\n#include <wx/stattext.h>\n#include <wx/panel.h>\n\nclass GettingStartedDialog : public wxDialog\n{\npublic:\n\tGettingStartedDialog(wxWindow* parent = nullptr);\n\nprivate:\n\twxPanel* CreatePage1();\n\twxPanel* CreatePage2();\n\tvoid ApplySettings();\n\tvoid UpdateWindowSize();\n\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid OnConfigureGPs(wxCommandEvent& event);\n\tvoid OnInputSettings(wxCommandEvent& event);\n\n\twxSimplebook* m_notebook;\n\n\tstruct\n\t{\n\t\t// header\n\t\twxStaticText* staticText11{};\n\t\twxStaticText* portableModeInfoText{};\n\n\t\t// game path box\n\t\twxStaticBoxSizer* gamePathBoxSizer{};\n\t\twxStaticText* gamePathText{};\n\t\twxStaticText* gamePathText2{};\n\t\twxDirPickerCtrl* gamePathPicker{};\n\t}m_page1;\n\n\tstruct\n\t{\n\t\twxCheckBox* fullscreenCheckbox;\n\t\twxCheckBox* separateCheckbox;\n\t\twxCheckBox* updateCheckbox;\n\t}m_page2;\n};\n\n"
  },
  {
    "path": "src/gui/wxgui/GraphicPacksWindow2.cpp",
    "content": "#include \"helpers/wxHelpers.h\"\n#include \"wxgui/wxgui.h\"\n#include \"wxgui/GraphicPacksWindow2.h\"\n#include \"wxgui/DownloadGraphicPacksWindow.h\"\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"config/CemuConfig.h\"\n#include \"config/ActiveSettings.h\"\n\n#include \"Cafe/HW/Latte/Core/LatteAsyncCommands.h\"\n\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n\n#include \"wxHelper.h\"\n\n#if BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_BSD\n#include \"resource/embedded/resources.h\"\n#endif\n\n// main.cpp\nclass wxGraphicPackData : public wxTreeItemData\n{\npublic:\n\twxGraphicPackData(GraphicPackPtr pack)\n\t : m_pack(std::move(pack)) {  }\n\n\tconst GraphicPackPtr& GetGraphicPack() const { return m_pack; }\n\nprivate:\n\tGraphicPackPtr m_pack;\n};\n\nvoid GraphicPacksWindow2::FillGraphicPackList() const\n{\n\twxWindowUpdateLocker lock(m_graphic_pack_tree);\n\n\tm_graphic_pack_tree->DeleteAllItems();\n\tauto graphic_packs = GraphicPack2::GetGraphicPacks();\n\n\tconst auto root = m_graphic_pack_tree->AddRoot(\"Root\");\n\n\tconst bool has_filter = !m_filter.empty();\n\n\tfor(auto& p : graphic_packs)\n\t{\n\t\tif (!p->IsUniversal())\n\t\t{\n\t\t\t// filter graphic packs by given title id\n\t\t\tif (m_filter_installed_games && !m_installed_games.empty())\n\t\t\t{\n\t\t\t\tbool found = false;\n\t\t\t\tfor (uint64 titleId : p->GetTitleIds())\n\t\t\t\t{\n\t\t\t\t\tif (std::find(m_installed_games.cbegin(), m_installed_games.cend(), titleId) != m_installed_games.cend())\n\t\t\t\t\t{\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\tif (!found)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\n\t\t\t// filter graphic packs by given title id\n\t\t\tif(has_filter)\n\t\t\t{\n\t\t\t\tbool found = false;\n\t\n\t\t\t\tif (boost::icontains(p->GetVirtualPath(), m_filter))\n\t\t\t\t\tfound = true;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor (uint64 titleId : p->GetTitleIds())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (boost::icontains(fmt::format(\"{:x}\", titleId), m_filter))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\n\t\t\t\tif (!found)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tconst auto& path = p->GetVirtualPath();\n\t\tauto tokens = TokenizeView(path, '/');\n\t\tauto node = root;\n\t\tfor(size_t i=0; i<tokens.size(); i++)\n\t\t{\n\t\t\tauto& token = tokens[i];\n\t\t\tconst auto parent_node = node;\n\t\t\tif (i < (tokens.size() - 1))\n\t\t\t{\n\t\t\t\tnode = FindTreeItem(parent_node, wxString::FromUTF8(token));\n\t\t\t\tif (!node.IsOk())\n\t\t\t\t{\n\t\t\t\t\tnode = m_graphic_pack_tree->AppendItem(parent_node, wxString::FromUTF8(token));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// last token\n\t\t\t\t// if a node with same name already exists, add a number suffix\n\t\t\t\tfor (sint32 s = 0; s < 999; s++)\n\t\t\t\t{\n\t\t\t\t\twxString nodeName = wxString::FromUTF8(token);\n\t\t\t\t\tif (s > 0)\n\t\t\t\t\t\tnodeName.append(formatWxString(\" #{}\", s + 1));\n\n\t\t\t\t\tnode = FindTreeItem(parent_node, nodeName);\n\t\t\t\t\tif (!node.IsOk())\n\t\t\t\t\t{\n\t\t\t\t\t\tnode = m_graphic_pack_tree->AppendItem(parent_node, nodeName);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(node.IsOk() && node != root)\n\t\t{\n\t\t\tm_graphic_pack_tree->SetItemData(node, new wxGraphicPackData(p));\n\t\t\tbool canEnable = true;\n\n\t\t\tif (p->GetVersion() == 3)\n\t\t\t{\n\t\t\t\tauto tmp_text = m_graphic_pack_tree->GetItemText(node);\n\t\t\t\tm_graphic_pack_tree->SetItemText(node, tmp_text + \" (may not be compatible with Vulkan)\");\n\t\t\t}\n\t\t\telse if (p->GetVersion() != 3 && p->GetVersion() != 4 && p->GetVersion() != 5 && p->GetVersion() != 6 && p->GetVersion() != GraphicPack2::GFXPACK_VERSION_7)\n\t\t\t{\n\t\t\t\tauto tmp_text = m_graphic_pack_tree->GetItemText(node);\n\t\t\t\tm_graphic_pack_tree->SetItemText(node, tmp_text + \" (Unsupported version)\");\n\t\t\t\tm_graphic_pack_tree->SetItemTextColour(node, m_incompatible_colour);\n\t\t\t\tcanEnable = false;\n\t\t\t}\n\t\t\telse if (p->IsActivated())\n\t\t\t\tm_graphic_pack_tree->SetItemTextColour(node, m_activated_colour);\n\n\t\t\tm_graphic_pack_tree->MakeCheckable(node, p->IsEnabled());\n\t\t\tif (!canEnable)\n\t\t\t\tm_graphic_pack_tree->DisableCheckBox(node);\n\t\t}\n\t}\n\n\tm_graphic_pack_tree->Sort(root, true);\n\n\tif (!m_filter.empty())\n\t{\n\t\tsize_t counter = 0;\n\t\tExpandChildren({ root }, counter);\n\t}\n}\n\n\nvoid GraphicPacksWindow2::GetChildren(const wxTreeItemId& id, std::vector<wxTreeItemId>& children) const\n{\n\twxTreeItemIdValue cookie;\n\twxTreeItemId child = m_graphic_pack_tree->GetFirstChild(id, cookie);\n\twhile (child.IsOk())\n\t{\n\t\tchildren.emplace_back(child);\n\t\tchild = m_graphic_pack_tree->GetNextChild(child, cookie);\n\t}\n}\n\nvoid GraphicPacksWindow2::ExpandChildren(const std::vector<wxTreeItemId>& ids, size_t& counter) const\n{\n\tstd::vector<wxTreeItemId> children;\n\tfor (const auto& id : ids)\n\t\tGetChildren(id, children);\n\n\tcounter += children.size();\n\tif (counter >= 30 || children.empty())\n\t\treturn;\n\n\tfor (const auto& id : ids)\n\t{\n\t\tif(id != m_graphic_pack_tree->GetRootItem() && m_graphic_pack_tree->HasChildren(id))\n\t\t\tm_graphic_pack_tree->Expand(id);\n\t}\n\n\tExpandChildren(children, counter);\n}\n\nvoid GraphicPacksWindow2::RefreshGraphicPacks()\n{\n\tGraphicPack2::ClearGraphicPacks();\n\tGraphicPack2::LoadAll();\n}\n\nGraphicPacksWindow2::GraphicPacksWindow2(wxWindow* parent, uint64_t title_id_filter)\n\t: wxDialog(parent, wxID_ANY, _(\"Graphic packs\"), wxDefaultPosition, wxSize(1000,670), wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER),\n\t\tm_installed_games(CafeTitleList::GetAllTitleIds())\n{\n\tif (title_id_filter != 0)\n\t\tm_filter = fmt::format(\"{:x}\", title_id_filter);\n\n\tm_filter_installed_games = !m_installed_games.empty();\n\n\tSetIcon(wxICON(X_BOX));\n\tSetMinSize(wxSize(500, 400));\n\tauto main_sizer = new wxBoxSizer(wxVERTICAL);\n\n\tm_splitter_window = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3D);\n\tm_splitter_window->Bind(wxEVT_SIZE, &GraphicPacksWindow2::OnSizeChanged, this);\n\tm_splitter_window->Bind(wxEVT_SPLITTER_SASH_POS_CHANGED, &GraphicPacksWindow2::SashPositionChanged, this);\n\t\n\t// left side\n\tauto left_panel = new wxPanel(m_splitter_window);\n\t{\n\t\tauto sizer = new wxBoxSizer(wxVERTICAL);\n\n\t\twxFlexGridSizer* filter_row = new wxFlexGridSizer(0, 3, 0, 0);\n\t\tfilter_row->AddGrowableCol(1);\n\t\tfilter_row->SetFlexibleDirection(wxBOTH);\n\t\tfilter_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tconst auto text = new wxStaticText(left_panel, wxID_ANY, _(\"Filter\"));\n\t\ttext->Wrap(-1);\n\t\tfilter_row->Add(text, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tm_filter_text = new wxTextCtrl(left_panel, wxID_ANY, wxString::FromUTF8(m_filter));\n\t\tfilter_row->Add(m_filter_text, 0, wxALL | wxEXPAND, 5);\n\t\tm_filter_text->Bind(wxEVT_COMMAND_TEXT_UPDATED, &GraphicPacksWindow2::OnFilterUpdate, this);\n\n\t\tm_installed_games_only = new wxCheckBox(left_panel, wxID_ANY, _(\"Installed games\"));\n\t\tm_installed_games_only->SetValue(m_filter_installed_games);\n\t\tfilter_row->Add(m_installed_games_only, 0, wxALL | wxEXPAND, 5);\n\t\tm_installed_games_only->Bind(wxEVT_CHECKBOX, &GraphicPacksWindow2::OnInstalledGamesChanged, this);\n\t\tif (m_installed_games.empty())\n\t\t\tm_installed_games_only->Disable();\n\n\t\tsizer->Add(filter_row, 0, wxEXPAND, 5);\n\n\t\tm_graphic_pack_tree = new wxCheckTree(left_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT);\n\t\tm_graphic_pack_tree->Bind(wxEVT_TREE_SEL_CHANGED, &GraphicPacksWindow2::OnTreeSelectionChanged, this);\n\t\tm_graphic_pack_tree->Bind(wxEVT_CHECKTREE_CHOICE, &GraphicPacksWindow2::OnTreeChoiceChanged, this);\n\t\t//m_graphic_pack_tree->SetMinSize(wxSize(600, 400));\n\t\tsizer->Add(m_graphic_pack_tree, 1, wxEXPAND | wxALL, 5);\n\n\t\tleft_panel->SetSizerAndFit(sizer);\n\t}\n\n\t// right side\n\tm_right_panel = new wxPanel(m_splitter_window, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxFULL_REPAINT_ON_RESIZE);\n\t{\n\t\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\t\t{\n\t\t\tm_gp_options = new wxScrolled<wxPanel>(m_right_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxVSCROLL);\n\t\t\tm_gp_options->SetScrollRate(-1, 10);\n\n\t\t\tauto* inner_sizer = new wxBoxSizer(wxVERTICAL);\n\t\t\t{\n\t\t\t\tauto* box = new wxStaticBox(m_gp_options, wxID_ANY, _(\"Graphic pack\"));\n\t\t\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\t\t\tm_graphic_pack_name = new wxStaticText(box, wxID_ANY, wxEmptyString);\n\t\t\t\tbox_sizer->Add(m_graphic_pack_name, 1, wxEXPAND | wxALL, 5);\n\n\t\t\t\tinner_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t\t\t}\n\n\t\t\t{\n\t\t\t\tauto* box = new wxStaticBox(m_gp_options, wxID_ANY, _(\"Description\"));\n\t\t\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\t\t\tm_graphic_pack_description = new wxStaticText(box, wxID_ANY, wxEmptyString);\n\t\t\t\tbox_sizer->Add(m_graphic_pack_description, 1, wxEXPAND | wxALL, 5);\n\n\t\t\t\tinner_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t\t\t}\n\n\t\t\tm_preset_sizer = new wxBoxSizer(wxVERTICAL);\n\t\t\tinner_sizer->Add(m_preset_sizer, 0, wxEXPAND, 0);\n\n\t\t\t{\n\t\t\t\tauto* box = new wxStaticBox(m_gp_options, wxID_ANY, _(\"Control\"));\n\t\t\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxHORIZONTAL);\n\n\t\t\t\tm_reload_shaders = new wxButton(box, wxID_ANY, _(\"Reload edited shaders\"));\n\t\t\t\tm_reload_shaders->Bind(wxEVT_BUTTON, &GraphicPacksWindow2::OnReloadShaders, this);\n\t\t\t\tm_reload_shaders->Disable();\n\t\t\t\tbox_sizer->Add(m_reload_shaders, 0, wxEXPAND | wxALL, 5);\n\n\t\t\t\tinner_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t\t\t}\n\n\t\t\tinner_sizer->Add(new wxStaticText(m_gp_options, wxID_ANY, wxEmptyString), 1, wxALL | wxEXPAND, 5);\n\n\t\t\tm_gp_options->SetSizerAndFit(inner_sizer);\n\t\t\tm_gp_options->Hide();\n\n\t\t\tsizer->Add(m_gp_options, 1, wxEXPAND | wxRESERVE_SPACE_EVEN_IF_HIDDEN);\n\t\t}\n\n\t\t\n\t\tsizer->Add(new wxStaticLine(m_right_panel, wxID_ANY), 0, wxLEFT|wxRIGHT | wxEXPAND, 3);\n\n\t\tauto* row = new wxBoxSizer(wxHORIZONTAL);\n\t\tm_update_graphicPacks = new wxButton(m_right_panel, wxID_ANY, _(\"Download latest community graphic packs\"));\n\t\tm_update_graphicPacks->Bind(wxEVT_BUTTON, &GraphicPacksWindow2::OnCheckForUpdates, this);\n\t\trow->Add(m_update_graphicPacks, 0, wxALL, 5);\n\n\t\tsizer->Add(row, 0, wxALL | wxEXPAND, 5);\n\n\t\tm_right_panel->SetSizerAndFit(sizer);\n\t}\n\n\tm_splitter_window->SetMinimumPaneSize(50);\n\tm_splitter_window->SplitVertically(left_panel, m_right_panel, (sint32)(m_ratio * m_splitter_window->GetParent()->GetSize().GetWidth()));\n\tmain_sizer->Add(m_splitter_window, 1, wxEXPAND, 5);\n\n\n\tm_info_bar = new wxInfoBar(this);\n\tm_info_bar->SetShowHideEffects(wxSHOW_EFFECT_BLEND, wxSHOW_EFFECT_BLEND);\n\tm_info_bar->SetEffectDuration(500);\n\tmain_sizer->Add(m_info_bar, 0, wxALL | wxEXPAND, 5);\n\n\tSetSizer(main_sizer);\n\n\tUpdateTitleRunning(CafeSystem::IsTitleRunning());\n\tFillGraphicPackList();\n}\n\nvoid GraphicPacksWindow2::SaveStateToConfig()\n{\n\tauto& data = GetConfigHandle().data();\n\tdata.graphic_pack_entries.clear();\n\n\tfor (const auto& gp : GraphicPack2::GetGraphicPacks())\n\t{\n\t\tauto filename = _utf8ToPath(gp->GetNormalizedPathString());\n\t\tif (gp->IsEnabled())\n\t\t{\n\t\t\tdata.graphic_pack_entries.try_emplace(filename);\n\t\t\tauto& it = data.graphic_pack_entries[filename];\n\t\t\t// otherwise store all selected presets\n\t\t\tfor (const auto& preset : gp->GetActivePresets())\n\t\t\t\tit.try_emplace(preset->category, preset->name);\n\t\t}\n\t\telse if(gp->IsDefaultEnabled())\n\t\t{\n\t\t\t// save that its disabled\n\t\t\tdata.graphic_pack_entries.try_emplace(filename);\n\t\t\tauto& it = data.graphic_pack_entries[filename];\n\t\t\tit.try_emplace(\"_disabled\", \"false\");\n\t\t}\n\t}\n\n\tGetConfigHandle().Save();\n}\n\nGraphicPacksWindow2::~GraphicPacksWindow2()\n{\n\tm_graphic_pack_tree->Unbind(wxEVT_CHECKTREE_CHOICE, &GraphicPacksWindow2::OnTreeSelectionChanged, this);\n\tm_graphic_pack_tree->Unbind(wxEVT_CHECKTREE_CHOICE, &GraphicPacksWindow2::OnTreeChoiceChanged, this);\n\t// m_active_preset->Unbind(wxEVT_CHOICE, &GraphicPacksWindow2::OnActivePresetChanged, this);\n\tm_reload_shaders->Unbind(wxEVT_BUTTON, &GraphicPacksWindow2::OnReloadShaders, this);\n\n\tSaveStateToConfig();\n}\n\nwxTreeItemId GraphicPacksWindow2::FindTreeItem(const wxTreeItemId& root, const wxString& text) const\n{\n\twxTreeItemIdValue cookie;\n\tfor(auto item = m_graphic_pack_tree->GetFirstChild(root, cookie); item.IsOk(); item = m_graphic_pack_tree->GetNextSibling(item))\n\t{\n\t\tif (m_graphic_pack_tree->GetItemText(item) == text)\n\t\t\treturn item;\n\t}\n\n\treturn {};\n}\n\nvoid GraphicPacksWindow2::LoadPresetSelections(const GraphicPackPtr& gp)\n{\n\tstd::vector<std::string> order;\n\tauto presets = gp->GetCategorizedPresets(order);\n\tfor(const auto& category : order)\n\t{\n\t\tconst auto& entry = presets[category];\n\t\t\n\t\t// test if any preset is visible and update its status\n\t\tif (std::none_of(entry.cbegin(), entry.cend(), [gp](const auto& p)\n\t\t{\n\t\t\treturn p->visible;\n\t\t}))\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\twxString categoryWxStr = wxString::FromUTF8(category);\n\t\twxString label(category.empty() ? _(\"Active preset\") : categoryWxStr);\n\t\tauto* box = new wxStaticBox(m_preset_sizer->GetContainingWindow(), wxID_ANY, label);\n\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tauto* preset = new wxChoice(box, wxID_ANY);\n\t\tpreset->SetClientObject(new wxStringClientData(categoryWxStr));\n\t\tpreset->Bind(wxEVT_CHOICE, &GraphicPacksWindow2::OnActivePresetChanged, this);\n\n\t\tstd::optional<std::string> active_preset;\n\t\tfor (auto& pentry : entry)\n\t\t{\n\t\t\tif (!pentry->visible)\n\t\t\t\tcontinue;\n\n\t\t\tpreset->AppendString(wxString::FromUTF8(pentry->name));\n\t\t\tif (pentry->active)\n\t\t\t\tactive_preset = pentry->name;\n\t\t}\n\n\t\tif (active_preset)\n\t\t\tpreset->SetStringSelection(wxString::FromUTF8(active_preset.value()));\n\t\telse if (preset->GetCount() > 0)\n\t\t\tpreset->SetSelection(0);\n\t\t\t\t\t\n\t\tbox_sizer->Add(preset, 1, wxEXPAND | wxALL, 5);\n\n\t\tm_preset_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);\n\t}\n}\n\nvoid GraphicPacksWindow2::OnTreeSelectionChanged(wxTreeEvent& event)\n{\n\twxWindowUpdateLocker lock(this);\n\t\n\tbool item_deselected = m_graphic_pack_tree->GetSelection() == m_graphic_pack_tree->GetRootItem(); \n\tif (item_deselected)\n\t\treturn;\n\n\tconst auto selection = m_graphic_pack_tree->GetSelection();\n\tif (selection.IsOk())\n\t{\n\t\tconst auto data = dynamic_cast<wxGraphicPackData*>(m_graphic_pack_tree->GetItemData(selection));\n\t\tif (data)\n\t\t{\n\t\t\tif(!m_gp_options->IsShown())\n\t\t\t\tm_gp_options->Show();\n\t\t\t\n\t\t\tconst auto& gp = data->GetGraphicPack();\n\t\t\tif (gp != m_shown_graphic_pack)\n\t\t\t{\n\t\t\t\tm_preset_sizer->Clear(true);\n\t\t\t\tm_gp_name = gp->GetName();\n\t\t\t\tm_graphic_pack_name->SetLabel(wxString::FromUTF8(m_gp_name));\n\n\t\t\t\tif (gp->GetDescription().empty())\n\t\t\t\t\tm_gp_description = _(\"This graphic pack has no description\").utf8_string();\n\t\t\t\telse\n\t\t\t\t\tm_gp_description = gp->GetDescription();\n\n\t\t\t\tm_graphic_pack_description->SetLabel(wxString::FromUTF8(m_gp_description));\n\n\t\t\t\tLoadPresetSelections(gp);\n\t\t\t\t\n\t\t\t\tm_reload_shaders->Enable(gp->HasShaders());\n\n\t\t\t\tm_shown_graphic_pack = gp;\n\n\t\t\t\tm_graphic_pack_name->Wrap(m_graphic_pack_name->GetParent()->GetClientSize().GetWidth() - 20);\n\t\t\t\tm_graphic_pack_name->GetGrandParent()->Layout();\n\n\t\t\t\tm_graphic_pack_description->Wrap(m_graphic_pack_description->GetParent()->GetClientSize().GetWidth() - 20);\n\t\t\t\tm_graphic_pack_description->GetGrandParent()->Layout();\n\n\t\t\t\tm_right_panel->FitInside();\n\t\t\t\tm_right_panel->Layout();\t\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\n\tm_preset_sizer->Clear(true);\n\tm_graphic_pack_name->SetLabel(wxEmptyString);\n\tm_graphic_pack_description->SetLabel(wxEmptyString);\n\n\tm_reload_shaders->Disable();\n\n\tm_shown_graphic_pack.reset();\n\n\tm_gp_options->Hide();\n\tm_right_panel->FitInside();\n\tm_right_panel->Layout();\n}\n\nvoid GraphicPacksWindow2::OnTreeChoiceChanged(wxTreeEvent& event)\n{\n\tauto item = event.GetItem();\n\tif (!item.IsOk())\n\t\treturn;\n\n\tconst bool state = event.GetExtraLong() != 0;\n\n\tconst auto data = dynamic_cast<wxGraphicPackData*>(m_graphic_pack_tree->GetItemData(item));\n\tif (!data)\n\t\treturn;\n\n\tauto& graphic_pack = data->GetGraphicPack();\n\tgraphic_pack->SetEnabled(state);\n\n\tbool requiresRestart = graphic_pack->RequiresRestart(true, false);\n\tbool isRunning = CafeSystem::IsTitleRunning() && graphic_pack->ContainsTitleId(CafeSystem::GetForegroundTitleId());\n\tif (isRunning)\n\t{\n\t\tif (state)\n\t\t{\n\t\t\tGraphicPack2::ActivateGraphicPack(graphic_pack);\n\t\t\tif (!requiresRestart)\n\t\t\t{\n\t\t\t\tReloadPack(graphic_pack);\n\t\t\t\tm_graphic_pack_tree->SetItemTextColour(item, m_activated_colour);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!requiresRestart)\n\t\t\t{\n\t\t\t\tDeleteShadersFromRuntimeCache(graphic_pack);\n\t\t\t\tm_graphic_pack_tree->SetItemTextColour(item, m_default_colour);\n\t\t\t}\n\t\t\tGraphicPack2::DeactivateGraphicPack(graphic_pack);\n\t\t}\n\t}\n\n\tif (!m_info_bar->IsShown() && (isRunning && requiresRestart))\n\t\tm_info_bar->ShowMessage(_(\"Restart of Cemu required for changes to take effect\"));\n\n\t// also change selection to activated gp\n\tm_graphic_pack_tree->SelectItem(item);\n}\n\n// In some environments with GTK (e.g. a flatpak app with org.freedesktop.Platform 22.08 runtime),\n// destroying the event source inside the handler crashes the app.\n// As a workaround to that, the wxWindow that needs to be destroyed is hidden and then \n// destroyed at a later time, outside the handler.\nvoid GraphicPacksWindow2::ClearPresets()\n{\n\tsize_t item_count = m_preset_sizer->GetItemCount();\n\tstd::vector<wxSizer*> sizers;\n\tsizers.reserve(item_count);\n\tfor (size_t i = 0; i < item_count; i++)\n\t\tsizers.push_back(m_preset_sizer->GetItem(i)->GetSizer());\n\n\tfor (auto&& sizer : sizers)\n\t{\n\t\tauto static_box_sizer = dynamic_cast<wxStaticBoxSizer*>(sizer);\n\t\tif (static_box_sizer)\n\t\t{\n\t\t\twxStaticBox* parent_window = static_box_sizer->GetStaticBox();\n\t\t\tif (parent_window)\n\t\t\t{\n\t\t\t\tm_preset_sizer->Detach(sizer);\n\t\t\t\tparent_window->Hide();\n\t\t\t\tCallAfter([=]()\n\t\t\t\t{\n\t\t\t\t\tparent_window->DestroyChildren();\n\t\t\t\t\tdelete static_box_sizer;\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid GraphicPacksWindow2::OnActivePresetChanged(wxCommandEvent& event)\n{\n\tif (!m_shown_graphic_pack)\n\t\treturn;\n\n\tconst auto obj = wxDynamicCast(event.GetEventObject(), wxChoice);\n\twxASSERT(obj);\n\tconst auto string_data = dynamic_cast<wxStringClientData*>(obj->GetClientObject());\n\twxASSERT(string_data);\n\tconst auto preset = obj->GetStringSelection().utf8_string();\n\tif(m_shown_graphic_pack->SetActivePreset(string_data->GetData().utf8_string(), preset))\n\t{\n\t\twxWindowUpdateLocker lock(this);\n\t\tClearPresets();\n\t\tLoadPresetSelections(m_shown_graphic_pack);\n\t\t//m_preset_sizer->GetContainingWindow()->Layout();\n\t\t//m_right_panel->FitInside();\n\t\tm_right_panel->FitInside();\n\t\tm_right_panel->Layout();\n\t}\n\n\tif (!m_shown_graphic_pack->RequiresRestart(false, true))\n\t\tReloadPack(m_shown_graphic_pack);\n\telse if (!m_info_bar->IsShown())\n\t\tm_info_bar->ShowMessage(_(\"Restart of Cemu required for changes to take effect\"));\t\t\n}\n\nvoid GraphicPacksWindow2::OnReloadShaders(wxCommandEvent& event)\n{\n\tif (m_shown_graphic_pack)\n\t\tReloadPack(m_shown_graphic_pack);\n}\n\nvoid GraphicPacksWindow2::OnCheckForUpdates(wxCommandEvent& event)\n{\n\tDownloadGraphicPacksWindow frame(this);\n\tSaveStateToConfig();\n\tconst int updateResult = frame.ShowModal();\n\tif (updateResult == wxID_OK)\n\t{\n\t\tif (!CafeSystem::IsTitleRunning())\n\t\t{\n\t\t\t// remember virtual paths of all the enabled packs\n\t\t\tstd::map<std::string, std::string> previouslyEnabledPacks;\n\t\t\tfor(auto& it : GraphicPack2::GetGraphicPacks())\n\t\t\t{\n\t\t\t\tif(it->IsEnabled())\n\t\t\t\t\tpreviouslyEnabledPacks.emplace(it->GetNormalizedPathString(), it->GetVirtualPath());\n\t\t\t}\n\t\t\t// reload graphic packs\n\t\t\tRefreshGraphicPacks();\n\t\t\tFillGraphicPackList();\n\t\t\t// remove packs which are still present\n\t\t\tfor(auto& it : GraphicPack2::GetGraphicPacks())\n\t\t\t\tpreviouslyEnabledPacks.erase(it->GetNormalizedPathString());\n\t\t\tif(!previouslyEnabledPacks.empty())\n\t\t\t{\n\t\t\t\tstd::string lost_packs;\n\t\t\t\tfor(auto& it : previouslyEnabledPacks)\n\t\t\t\t{\n\t\t\t\t\tlost_packs.append(it.second);\n\t\t\t\t\tlost_packs.push_back('\\n');\n\t\t\t\t}\n\t\t\t\twxString message = _(\"This update removed or renamed the following graphic packs:\");\n\t\t\t\tmessage << \"\\n \\n\" << wxString::FromUTF8(lost_packs) << \" \\n\" << _(\"You may need to set them up again.\");\n\t\t\t\twxMessageBox(message, _(\"Warning\"), wxOK | wxCENTRE | wxICON_INFORMATION, this);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid GraphicPacksWindow2::OnSizeChanged(wxSizeEvent& event)\n{\n\tconst auto obj = (wxSplitterWindow*)event.GetEventObject();\n\twxASSERT(obj);\n\n\tconst auto width = std::max(obj->GetMinimumPaneSize(), obj->GetParent()->GetClientSize().GetWidth());\n\tobj->SetSashPosition((sint32)(m_ratio * width));\n\n\tif (!m_gp_name.empty())\n\t\tm_graphic_pack_name->SetLabel(wxString::FromUTF8(m_gp_name));\n\n\tif (!m_gp_description.empty())\n\t\tm_graphic_pack_description->SetLabel(wxString::FromUTF8(m_gp_description));\n\n\tm_graphic_pack_name->Wrap(m_graphic_pack_name->GetParent()->GetClientSize().GetWidth() - 10);\n\tm_graphic_pack_description->Wrap(m_graphic_pack_description->GetParent()->GetClientSize().GetWidth() - 10);\n\n\tevent.Skip();\n}\n\nvoid GraphicPacksWindow2::SashPositionChanged(wxEvent& event)\n{\n\tconst auto obj = (wxSplitterWindow*)event.GetEventObject();\n\twxASSERT(obj);\n\n\tconst auto width = std::max(obj->GetMinimumPaneSize(), obj->GetParent()->GetClientSize().GetWidth());\n\tm_ratio = (float)obj->GetSashPosition() / width;\n\tevent.Skip();\n}\n\nvoid GraphicPacksWindow2::OnFilterUpdate(wxEvent& event)\n{\n\tm_filter = m_filter_text->GetValue().utf8_string();\n\tFillGraphicPackList();\n\tevent.Skip();\n}\n\nvoid GraphicPacksWindow2::OnInstalledGamesChanged(wxCommandEvent& event)\n{\n\tm_filter_installed_games = m_installed_games_only->GetValue();\n\tFillGraphicPackList();\n\tevent.Skip();\n}\n\nvoid GraphicPacksWindow2::UpdateTitleRunning(bool running)\n{\n\tm_update_graphicPacks->Enable(!running);\n\tif(running)\n\t\tm_update_graphicPacks->SetToolTip(_(\"Graphic packs cannot be updated while a game is running.\"));\n\telse\n\t\tm_update_graphicPacks->SetToolTip(nullptr);\n}\n\nvoid GraphicPacksWindow2::ReloadPack(const GraphicPackPtr& graphic_pack) const\n{\n\tif (graphic_pack->HasShaders() || graphic_pack->HasPatches() || graphic_pack->HasCustomVSyncFrequency())\n\t{\n\t\tif (graphic_pack->Reload())\n\t\t{\n\t\t\tDeleteShadersFromRuntimeCache(graphic_pack);\n\t\t}\n\t}\n}\n\nvoid GraphicPacksWindow2::DeleteShadersFromRuntimeCache(const GraphicPackPtr& graphic_pack) const\n{\n\tfor (const auto& shader : graphic_pack->GetCustomShaders())\n\t{\n\t\tLatteConst::ShaderType shaderType;\n\t\tif (shader.type == GraphicPack2::GP_SHADER_TYPE::VERTEX)\n\t\t\tshaderType = LatteConst::ShaderType::Vertex;\n\t\telse if (shader.type == GraphicPack2::GP_SHADER_TYPE::GEOMETRY)\n\t\t\tshaderType = LatteConst::ShaderType::Geometry;\n\t\telse if (shader.type == GraphicPack2::GP_SHADER_TYPE::PIXEL)\n\t\t\tshaderType = LatteConst::ShaderType::Pixel;\n\t\tLatteAsyncCommands_queueDeleteShader(shader.shader_base_hash, shader.shader_aux_hash, shaderType);\n\t}\n}\n\n"
  },
  {
    "path": "src/gui/wxgui/GraphicPacksWindow2.h",
    "content": "#pragma once\n\n#include <wx/frame.h>\n#include <wx/dialog.h>\n#include <wx/scrolwin.h>\n#include <wx/infobar.h>\n\n#include \"wxcomponents/checktree.h\"\n\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n\nclass wxSplitterWindow;\nclass wxPanel;\nclass wxButton;\nclass wxChoice;\n\nclass GraphicPacksWindow2 : public wxDialog\n{\npublic:\n\tGraphicPacksWindow2(wxWindow* parent, uint64_t title_id_filter);\n\t~GraphicPacksWindow2();\n\n\tstatic void RefreshGraphicPacks();\n\tvoid UpdateTitleRunning(bool running);\n\nprivate:\n\tstd::string m_filter;\n\tbool m_filter_installed_games;\n\tstd::vector<uint64_t> m_installed_games;\n\n\tvoid ClearPresets();\n\tvoid FillGraphicPackList() const;\n\tvoid GetChildren(const wxTreeItemId& id, std::vector<wxTreeItemId>& children) const;\n\tvoid ExpandChildren(const std::vector<wxTreeItemId>& ids, size_t& counter) const;\n\t\n\twxSplitterWindow * m_splitter_window;\n\n\twxPanel* m_right_panel;\n\twxScrolled<wxPanel>* m_gp_options;\n\t\n\twxCheckTree * m_graphic_pack_tree;\n\twxTextCtrl* m_filter_text;\n\twxCheckBox* m_installed_games_only;\n\n\twxStaticText* m_graphic_pack_name, *m_graphic_pack_description;\n\twxBoxSizer* m_preset_sizer;\n\tstd::vector<wxChoice*> m_active_preset;\n\twxButton* m_reload_shaders;\n\twxButton* m_update_graphicPacks;\n\twxInfoBar* m_info_bar;\n\n\tGraphicPackPtr m_shown_graphic_pack;\n\tstd::string m_gp_name, m_gp_description;\n\n\tfloat m_ratio = 0.55f;\n\twxColour m_default_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);\n\twxColour m_activated_colour = wxSystemSettings::SelectLightDark(wxColour(0x00, 0xCC, 0x00), wxColour(0x42, 0xB3, 0x42));\n\twxColour m_incompatible_colour = wxSystemSettings::SelectLightDark(wxColour(0xCC, 0x00, 0x00), wxColour(0xDE, 0x49, 0x49));\n\n\twxTreeItemId FindTreeItem(const wxTreeItemId& root, const wxString& text) const;\n\tvoid LoadPresetSelections(const GraphicPackPtr& gp);\n\n\tvoid OnTreeSelectionChanged(wxTreeEvent& event);\n\tvoid OnTreeChoiceChanged(wxTreeEvent& event);\n\tvoid OnActivePresetChanged(wxCommandEvent& event);\n\tvoid OnReloadShaders(wxCommandEvent& event);\n\tvoid OnCheckForUpdates(wxCommandEvent& event);\n\tvoid OnSizeChanged(wxSizeEvent& event);\n\tvoid SashPositionChanged(wxEvent& event);\n\tvoid OnFilterUpdate(wxEvent& event);\n\tvoid OnInstalledGamesChanged(wxCommandEvent& event);\n\n\tvoid SaveStateToConfig();\n\n\tvoid ReloadPack(const GraphicPackPtr& graphic_pack) const;\n\tvoid DeleteShadersFromRuntimeCache(const GraphicPackPtr& graphic_pack) const;\n\n};"
  },
  {
    "path": "src/gui/wxgui/LoggingWindow.cpp",
    "content": "#include \"wxgui/LoggingWindow.h\"\n\n#include \"Cemu/Logging/CemuLogging.h\"\n#include \"wxgui/helpers/wxLogEvent.h\"\n\n#include <wx/sizer.h>\n#include <wx/stattext.h>\n#include <wx/wupdlock.h>\n\nwxDEFINE_EVENT(EVT_LOG, wxLogEvent);\n\nLoggingWindow::LoggingWindow(wxFrame* parent)\n\t: wxFrame(parent, wxID_ANY, _(\"Logging window\"), wxDefaultPosition, wxSize(800, 600), wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL)\n{\n\tauto* sizer = new wxBoxSizer( wxVERTICAL );\n\t{\n\t\tauto filter_row = new wxBoxSizer( wxHORIZONTAL );\n\n\t\tfilter_row->Add(new wxStaticText( this, wxID_ANY, _(\"Filter\")), 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );\n\n\t\twxString choices[] = {\"Unsupported APIs calls\", \"Coreinit Logging\", \"Coreinit File-Access\", \"Coreinit Thread-Synchronization\", \"Coreinit Memory\", \"Coreinit MP\", \"Coreinit Thread\", \"nn::nfp\", \"GX2\", \"Audio\", \"Input\", \"Socket\", \"Save\", \"H264\", \"Graphic pack patches\", \"Texture cache\", \"Texture readback\", \"OpenGL debug output\", \"Vulkan validation layer\", \"Metal debug output\"};\n\t\tm_filter = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, std::size(choices), choices);\n\t\tm_filter->Bind(wxEVT_COMBOBOX, &LoggingWindow::OnFilterChange, this);\n\t\tm_filter->Bind(wxEVT_TEXT, &LoggingWindow::OnFilterChange, this);\n\t\tfilter_row->Add(m_filter, 1, wxALL, 5 );\n\n\t\tm_filter_message = new wxCheckBox(this, wxID_ANY, _(\"Filter messages\"));\n\t\tm_filter_message->Bind(wxEVT_CHECKBOX, &LoggingWindow::OnFilterMessageChange, this);\n\t\tfilter_row->Add(m_filter_message, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );\n\n\t\tsizer->Add( filter_row, 0, wxEXPAND, 5 );\n\t}\n\n\tm_log_list = new wxLogCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxScrolledWindowStyle, true);\n\tsizer->Add( m_log_list, 1, wxALL | wxEXPAND, 5 );\n\n\tthis->SetSizer( sizer );\n\tthis->Layout();\n\n\tthis->Bind(EVT_LOG, &LoggingWindow::OnLogMessage, this);\n\n\tcemuLog_setCallbacks(this);\n}\n\nLoggingWindow::~LoggingWindow()\n{\n\tthis->Unbind(EVT_LOG, &LoggingWindow::OnLogMessage, this);\n\n\tcemuLog_clearCallbacks();\n}\n\nvoid LoggingWindow::Log(std::string_view filter, std::string_view message)\n{\n\twxLogEvent event(std::string {filter}, std::string{ message });\n\tOnLogMessage(event);\n\n\t//const auto log_event = new wxLogEvent(filter, message);\n\t//wxQueueEvent(s_instance, log_event);\n}\n\nvoid LoggingWindow::Log(std::string_view filter, std::wstring_view message)\n{\n\twxLogEvent event(std::string {filter}, std::wstring{ message });\n\tOnLogMessage(event);\n\n\t//const auto log_event = new wxLogEvent(filter, message);\n\t//wxQueueEvent(s_instance, log_event);\n}\n\nvoid LoggingWindow::OnLogMessage(wxLogEvent& event)\n{\n\tm_log_list->PushEntry(event.GetFilter(), event.GetMessage());\n}\n\nvoid LoggingWindow::OnFilterChange(wxCommandEvent& event)\n{\n\tm_log_list->SetActiveFilter(m_filter->GetValue().utf8_string());\n\tevent.Skip();\n}\n\nvoid LoggingWindow::OnFilterMessageChange(wxCommandEvent& event)\n{\n\tm_log_list->SetFilterMessage(m_filter_message->GetValue());\n\tevent.Skip();\n}\n"
  },
  {
    "path": "src/gui/wxgui/LoggingWindow.h",
    "content": "#pragma once\n\n#include \"Cemu/Logging/CemuLogging.h\"\n\n#include <wx/frame.h>\n#include <wx/listbox.h>\n#include <wx/combobox.h>\n#include \"wxgui/components/wxLogCtrl.h\"\n\nclass wxLogEvent;\n\nclass LoggingWindow : public wxFrame, public LoggingCallbacks\n{\n  public:\n\tLoggingWindow(wxFrame* parent);\n\t~LoggingWindow();\n\n\tvoid Log(std::string_view filter, std::string_view message) override;\n\tvoid Log(std::string_view filter, std::wstring_view message) override;\n\n  private:\n\tvoid OnLogMessage(wxLogEvent& event);\n\tvoid OnFilterChange(wxCommandEvent& event);\n\tvoid OnFilterMessageChange(wxCommandEvent& event);\n\n\twxComboBox* m_filter;\n\twxLogCtrl* m_log_list;\n\twxCheckBox* m_filter_message;\n};\n"
  },
  {
    "path": "src/gui/wxgui/MainWindow.cpp",
    "content": "#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"interface/WindowSystem.h\"\n#include \"wxCemuConfig.h\"\n#include \"wxgui/wxgui.h\"\n#include \"wxgui/MainWindow.h\"\n\n#include <wx/mstream.h>\n\n#include \"wxgui/GameUpdateWindow.h\"\n#include \"wxgui/PadViewFrame.h\"\n#include \"wxgui/windows/TextureRelationViewer/TextureRelationWindow.h\"\n#include \"wxgui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.h\"\n#include \"AudioDebuggerWindow.h\"\n#include \"wxgui/canvas/OpenGLCanvas.h\"\n#include \"wxgui/canvas/VulkanCanvas.h\"\n#if ENABLE_METAL\n#include \"wxgui/canvas/MetalCanvas.h\"\n#endif\n#include \"Cafe/OS/libs/nfc/nfc.h\"\n#include \"Cafe/OS/libs/swkbd/swkbd.h\"\n#include \"wxgui/debugger/DebuggerWindow2.h\"\n#include \"util/helpers/helpers.h\"\n#include \"config/CemuConfig.h\"\n#include \"Cemu/DiscordPresence/DiscordPresence.h\"\n#include \"util/ScreenSaver/ScreenSaver.h\"\n#include \"wxgui/GeneralSettings2.h\"\n#include \"wxgui/GraphicPacksWindow2.h\"\n#include \"wxgui/CemuApp.h\"\n#include \"wxgui/CemuUpdateWindow.h\"\n#include \"wxgui/LoggingWindow.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/LaunchSettings.h\"\n\n#include \"Cafe/Filesystem/FST/FST.h\"\n\n#include \"wxgui/TitleManager.h\"\n#include \"wxgui/EmulatedUSBDevices/EmulatedUSBDeviceFrame.h\"\n\n#include \"Cafe/CafeSystem.h\"\n\n#include \"util/helpers/SystemException.h\"\n#include \"wxgui/DownloadGraphicPacksWindow.h\"\n#include \"wxgui/GettingStartedDialog.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.h\"\n#include \"wxgui/input/InputSettings2.h\"\n#include \"wxgui/input/HotkeySettings.h\"\n#include \"input/InputManager.h\"\n\n#if BOOST_OS_WINDOWS\n#define exit(__c) ExitProcess(__c)\n#else\n#define exit(__c) _Exit(__c)\n#endif\n\n#if BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_BSD\n#include \"resource/embedded/resources.h\"\n#endif\n\n#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND\n#include \"wxgui/helpers/wxWayland.h\"\n#endif\n\n//GameMode support\n#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)\n#include \"gamemode_client.h\"\n#endif\n\n#if ENABLE_METAL\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n#endif\n\n#include \"Cafe/TitleList/TitleInfo.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n#include \"wxHelper.h\"\n\nextern WindowSystem::WindowInfo g_window_info;\nextern std::shared_mutex g_mutex;\n\nenum\n{\n\t// ui elements\n\tMAINFRAME_GAMELIST_ID = 20000, //wxID_HIGHEST + 1,\n\t// file\n\tMAINFRAME_MENU_ID_FILE_LOAD = 20100,\n\tMAINFRAME_MENU_ID_FILE_INSTALL_UPDATE,\n\tMAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER,\n\tMAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER,\n\tMAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER,\n\tMAINFRAME_MENU_ID_FILE_CLEAR_SPOTPASS_CACHE,\n\tMAINFRAME_MENU_ID_FILE_EXIT,\n\tMAINFRAME_MENU_ID_FILE_END_EMULATION,\n\tMAINFRAME_MENU_ID_FILE_RECENT_0,\n\tMAINFRAME_MENU_ID_FILE_RECENT_LAST = MAINFRAME_MENU_ID_FILE_RECENT_0 + 15,\n\t// options\n\tMAINFRAME_MENU_ID_OPTIONS_FULLSCREEN = 20200,\n\tMAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW,\n\tMAINFRAME_MENU_ID_OPTIONS_GRAPHIC,\n\tMAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2,\n\tMAINFRAME_MENU_ID_OPTIONS_GENERAL,\n\tMAINFRAME_MENU_ID_OPTIONS_GENERAL2,\n\tMAINFRAME_MENU_ID_OPTIONS_AUDIO,\n\tMAINFRAME_MENU_ID_OPTIONS_INPUT,\n\tMAINFRAME_MENU_ID_OPTIONS_HOTKEY,\n\tMAINFRAME_MENU_ID_OPTIONS_MAC_SETTINGS,\n\t// options -> account\n\tMAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1 = 20350,\n\tMAINFRAME_MENU_ID_OPTIONS_ACCOUNT_12 = 20350 + 11,\n\n\t// options -> system language\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_JAPANESE = 20500,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ENGLISH,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_FRENCH,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_GERMAN,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ITALIAN,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_SPANISH,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_CHINESE,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_KOREAN,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_DUTCH,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_PORTUGUESE,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_RUSSIAN,\n\tMAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE,\n\t// tools\n\tMAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER = 20600,\n\tMAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER,\n\tMAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER,\n\tMAINFRAME_MENU_ID_TOOLS_EMULATED_USB_DEVICES,\n\t// cpu\n\t// cpu->timer speed\n\tMAINFRAME_MENU_ID_TIMER_SPEED_1X = 20700,\n\tMAINFRAME_MENU_ID_TIMER_SPEED_2X = 20701,\n\tMAINFRAME_MENU_ID_TIMER_SPEED_4X = 20702,\n\tMAINFRAME_MENU_ID_TIMER_SPEED_8X = 20703,\n\tMAINFRAME_MENU_ID_TIMER_SPEED_05X = 20704,\n\tMAINFRAME_MENU_ID_TIMER_SPEED_025X = 20705,\n\tMAINFRAME_MENU_ID_TIMER_SPEED_0125X = 20706,\n\n\t// nfc->Touch NFC file\n\tMAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE = 21000,\n\tMAINFRAME_MENU_ID_NFC_RECENT_0,\n\tMAINFRAME_MENU_ID_NFC_RECENT_LAST = MAINFRAME_MENU_ID_NFC_RECENT_0 + 15,\n\t// debug\n\tMAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN = 21100,\n\tMAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW,\n\tMAINFRAME_MENU_ID_DEBUG_TOGGLE_GDB_STUB,\n\tMAINFRAME_MENU_ID_DEBUG_VIEW_PPC_THREADS,\n\tMAINFRAME_MENU_ID_DEBUG_VIEW_PPC_DEBUGGER,\n\tMAINFRAME_MENU_ID_DEBUG_VIEW_AUDIO_DEBUGGER,\n\tMAINFRAME_MENU_ID_DEBUG_VIEW_TEXTURE_RELATIONS,\n\tMAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY,\n\tMAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS,\n\tMAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE,\n\n\t// debug->logging\n\tMAINFRAME_MENU_ID_DEBUG_LOGGING_MESSAGE = 21499,\n\tMAINFRAME_MENU_ID_DEBUG_LOGGING0 = 21500,\n\tMAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO = 21599,\n\t// debug->dump\n\tMAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES = 21600,\n\tMAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS,\n\tMAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS,\n\tMAINFRAME_MENU_ID_DEBUG_DUMP_RAM,\n\tMAINFRAME_MENU_ID_DEBUG_DUMP_FST,\n\tMAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS,\n\t// help\n\tMAINFRAME_MENU_ID_HELP_ABOUT = 21700,\n\tMAINFRAME_MENU_ID_HELP_UPDATE,\n\t// custom\n\tMAINFRAME_ID_TIMER1 = 21800,\n};\n\nwxDEFINE_EVENT(wxEVT_SET_WINDOW_TITLE, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_REQUEST_GAMELIST_REFRESH, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_LAUNCH_GAME, wxLaunchGameEvent);\nwxDEFINE_EVENT(wxEVT_REQUEST_RECREATE_CANVAS, wxCommandEvent);\n\nwxBEGIN_EVENT_TABLE(MainWindow, wxFrame)\nEVT_TIMER(MAINFRAME_ID_TIMER1, MainWindow::OnTimer)\nEVT_CLOSE(MainWindow::OnClose)\nEVT_SIZE(MainWindow::OnSizeEvent)\nEVT_DPI_CHANGED(MainWindow::OnDPIChangedEvent)\nEVT_MOVE(MainWindow::OnMove)\n// file menu\nEVT_MENU(MAINFRAME_MENU_ID_FILE_LOAD, MainWindow::OnFileMenu)\nEVT_MENU(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, MainWindow::OnInstallUpdate)\nEVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, MainWindow::OnOpenFolder)\nEVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, MainWindow::OnOpenFolder)\nEVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER, MainWindow::OnOpenFolder)\nEVT_MENU(MAINFRAME_MENU_ID_FILE_CLEAR_SPOTPASS_CACHE, MainWindow::OnClearSpotPassCache)\nEVT_MENU(MAINFRAME_MENU_ID_FILE_EXIT, MainWindow::OnFileExit)\nEVT_MENU(MAINFRAME_MENU_ID_FILE_END_EMULATION, MainWindow::OnFileMenu)\nEVT_MENU_RANGE(MAINFRAME_MENU_ID_FILE_RECENT_0 + 0, MAINFRAME_MENU_ID_FILE_RECENT_LAST, MainWindow::OnFileMenu)\n// options -> region menu\nEVT_MENU_RANGE(MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1, MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_12, MainWindow::OnAccountSelect)\nEVT_MENU_RANGE(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_JAPANESE, MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE, MainWindow::OnConsoleLanguage)\n// options menu\nEVT_MENU(MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN, MainWindow::OnOptionsInput)\nEVT_MENU(MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW, MainWindow::OnOptionsInput)\nEVT_MENU(MAINFRAME_MENU_ID_OPTIONS_GRAPHIC, MainWindow::OnOptionsInput)\nEVT_MENU(MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2, MainWindow::OnOptionsInput)\nEVT_MENU(MAINFRAME_MENU_ID_OPTIONS_GENERAL, MainWindow::OnOptionsInput)\nEVT_MENU(MAINFRAME_MENU_ID_OPTIONS_GENERAL2, MainWindow::OnOptionsInput)\nEVT_MENU(MAINFRAME_MENU_ID_OPTIONS_AUDIO, MainWindow::OnOptionsInput)\nEVT_MENU(MAINFRAME_MENU_ID_OPTIONS_INPUT, MainWindow::OnOptionsInput)\nEVT_MENU(MAINFRAME_MENU_ID_OPTIONS_HOTKEY, MainWindow::OnOptionsInput)\nEVT_MENU(MAINFRAME_MENU_ID_OPTIONS_MAC_SETTINGS, MainWindow::OnOptionsInput)\n// tools menu\nEVT_MENU(MAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER, MainWindow::OnToolsInput)\nEVT_MENU(MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER, MainWindow::OnToolsInput)\nEVT_MENU(MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER, MainWindow::OnToolsInput)\nEVT_MENU(MAINFRAME_MENU_ID_TOOLS_EMULATED_USB_DEVICES, MainWindow::OnToolsInput)\n// cpu menu\nEVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_8X, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_4X, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_2X, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_1X, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_05X, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_025X, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_0125X, MainWindow::OnDebugSetting)\n// nfc menu\nEVT_MENU(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, MainWindow::OnNFCMenu)\nEVT_MENU_RANGE(MAINFRAME_MENU_ID_NFC_RECENT_0 + 0, MAINFRAME_MENU_ID_NFC_RECENT_LAST, MainWindow::OnNFCMenu)\n// debug -> logging menu\nEVT_MENU_RANGE(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 0, MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 98, MainWindow::OnDebugLoggingToggleFlagGeneric)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, MainWindow::OnPPCInfoToggle)\n// debug -> dump menu\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES, MainWindow::OnDebugDumpGeneric)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS, MainWindow::OnDebugDumpGeneric)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS, MainWindow::OnDebugDumpGeneric)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, MainWindow::OnDebugSetting)\n// debug -> Other options\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_RAM, MainWindow::OnDebugSetting)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_FST, MainWindow::OnDebugSetting)\n// debug -> View ...\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW, MainWindow::OnLoggingWindow)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_TOGGLE_GDB_STUB, MainWindow::OnGDBStubToggle)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_THREADS, MainWindow::OnDebugViewPPCThreads)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_DEBUGGER, MainWindow::OnDebugViewPPCDebugger)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_AUDIO_DEBUGGER, MainWindow::OnDebugViewAudioDebugger)\nEVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_TEXTURE_RELATIONS, MainWindow::OnDebugViewTextureRelations)\n// help menu\nEVT_MENU(MAINFRAME_MENU_ID_HELP_ABOUT, MainWindow::OnHelpAbout)\nEVT_MENU(MAINFRAME_MENU_ID_HELP_UPDATE, MainWindow::OnHelpUpdate)\n// misc\nEVT_COMMAND(wxID_ANY, wxEVT_REQUEST_GAMELIST_REFRESH, MainWindow::OnRequestGameListRefresh)\n\nEVT_COMMAND(wxID_ANY, wxEVT_GAMELIST_BEGIN_UPDATE, MainWindow::OnGameListBeginUpdate)\nEVT_COMMAND(wxID_ANY, wxEVT_GAMELIST_END_UPDATE, MainWindow::OnGameListEndUpdate)\nEVT_COMMAND(wxID_ANY, wxEVT_ACCOUNTLIST_REFRESH, MainWindow::OnAccountListRefresh)\nEVT_COMMAND(wxID_ANY, wxEVT_SET_WINDOW_TITLE, MainWindow::OnSetWindowTitle)\n\nEVT_COMMAND(wxID_ANY, wxEVT_REQUEST_RECREATE_CANVAS, MainWindow::OnRequestRecreateCanvas)\n\nwxEND_EVENT_TABLE()\n\nclass wxGameDropTarget : public wxFileDropTarget\n{\npublic:\n\twxGameDropTarget(MainWindow* window) : m_window(window) {}\n\tbool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) override\n\t{\n\t\tif(!m_window->IsGameLaunched() && filenames.GetCount() == 1)\n\t\t\treturn m_window->FileLoad(_utf8ToPath(filenames[0].utf8_string()), wxLaunchGameEvent::INITIATED_BY::DRAG_AND_DROP);\n\n\t\treturn false;\n\t}\n\nprivate:\n\tMainWindow* m_window;\n};\n\nclass wxAmiiboDropTarget : public wxFileDropTarget\n{\npublic:\n\twxAmiiboDropTarget(MainWindow* window) : m_window(window) {}\n\tbool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) override\n\t{\n\t\tif (!m_window->IsGameLaunched() || filenames.GetCount() != 1)\n\t\t\treturn false;\n\t\tuint32 nfcError;\n\t\tstd::string path = filenames[0].utf8_string();\n\t\tif (nfc::TouchTagFromFile(_utf8ToPath(path), &nfcError))\n\t\t{\n\t\t\tGetWxGUIConfig().AddRecentNfcFile(path);\n\t\t\tm_window->UpdateNFCMenu();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (nfcError == NFC_TOUCH_TAG_ERROR_NO_ACCESS)\n\t\t\t\twxMessageBox(_(\"Cannot open file\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\t\telse if (nfcError == NFC_TOUCH_TAG_ERROR_INVALID_FILE_FORMAT)\n\t\t\t\twxMessageBox(_(\"Not a valid NFC file\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\t\treturn false;\n\t\t}\n\t}\n\nprivate:\n\tMainWindow* m_window;\n};\n\nMainWindow::MainWindow()\n\t: wxFrame(nullptr, wxID_ANY, GetInitialWindowTitle(), wxDefaultPosition, wxSize(1280, 720), wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN | wxRESIZE_BORDER)\n{\n#ifdef __WXMAC__\n\t// Not necessary to set wxApp::s_macExitMenuItemId as automatically handled\n\twxApp::s_macAboutMenuItemId = MAINFRAME_MENU_ID_HELP_ABOUT;\n\twxApp::s_macPreferencesMenuItemId = MAINFRAME_MENU_ID_OPTIONS_MAC_SETTINGS;\n#endif\n\tg_window_info.window_main = initHandleContextFromWxWidgetsWindow(this);\n\tg_mainFrame = this;\n\tCafeSystem::SetImplementation(this);\n\n\tRecreateMenu();\n\tSetClientSize(1280, 720);\n\tSetIcon(wxICON(M_WND_ICON128));\n\n#if BOOST_OS_MACOS\n\tthis->EnableFullScreenView(true);\n#endif\n\n#if BOOST_OS_WINDOWS\n\tHICON hWindowIcon = (HICON)LoadImageA(NULL, \"M_WND_ICON16\", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);\n\tSendMessage(this->GetHWND(), WM_SETICON, ICON_SMALL, (LPARAM)hWindowIcon);\n#endif\n\n\tauto* main_sizer = new wxBoxSizer(wxVERTICAL);\n    auto load_file = LaunchSettings::GetLoadFile();\n    auto load_title_id = LaunchSettings::GetLoadTitleID();\n    bool quick_launch = false;\n\n\tif (load_file)\n\t{\n\t\tMainWindow::RequestLaunchGame(load_file.value(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE);\n\t\tquick_launch = true;\n\t}\n\telse if (load_title_id)\n\t{\n\t\tTitleInfo info;\n\t\tTitleId baseId;\n\t\tif (CafeTitleList::FindBaseTitleId(load_title_id.value(), baseId) && CafeTitleList::GetFirstByTitleId(baseId, info))\n\t\t{\n\t\t\tMainWindow::RequestLaunchGame(info.GetPath(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE);\n\t\t\tquick_launch = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\twxString errorMsg = fmt::format(\"Title ID {:016x} not found\", load_title_id.value());\n\t\t\twxMessageBox(errorMsg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\n\t\t}\n\t}\n\tSetSizer(main_sizer);\n\tif (!quick_launch)\n\t{\n\t\tCreateGameListAndStatusBar();\n\t}\n\telse\n\t{\n\t\t// launching game via -g or -t option. Don't set up or load game list\n\t\tm_game_list = nullptr;\n\t\tm_info_bar = nullptr;\n\t}\n\tSetSizer(main_sizer);\n\n\tm_last_mouse_move_time = std::chrono::steady_clock::now();\n\n\tm_timer = new wxTimer(this, MAINFRAME_ID_TIMER1);\n\tm_timer->Start(500);\n\n\tLoadSettings();\n\n\t#ifdef ENABLE_DISCORD_RPC\n\tif (GetWxGUIConfig().use_discord_presence)\n\t\t\tm_discord = std::make_unique<DiscordPresence>();\n\t#endif\n\n\tBind(wxEVT_OPEN_GRAPHIC_PACK, &MainWindow::OnGraphicWindowOpen, this);\n\tBind(wxEVT_LAUNCH_GAME, &MainWindow::OnLaunchFromFile, this);\n\n\tif (LaunchSettings::GDBStubEnabled())\n\t{\n\t\t\tg_gdbstub = std::make_unique<GDBServer>(GetConfig().gdb_port);\n\t}\n}\n\nMainWindow::~MainWindow()\n{\n\tif (m_padView)\n\t{\n\t\tm_padView->Destroy();\n\t\tm_padView = nullptr;\n\t}\n\n\tm_timer->Stop();\n\n\tstd::unique_lock lock(g_mutex);\n\tg_mainFrame = nullptr;\n}\n\nvoid MainWindow::CreateGameListAndStatusBar()\n{\n    if(m_main_panel)\n        return; // already displayed\n    m_main_panel = new wxPanel(this);\n    auto* sizer = new wxBoxSizer(wxVERTICAL);\n    // game list\n    m_game_list = new wxGameList(m_main_panel, MAINFRAME_GAMELIST_ID);\n    m_game_list->Bind(wxEVT_OPEN_SETTINGS, [this](auto&) {OpenSettings(); });\n    m_game_list->SetDropTarget(new wxGameDropTarget(this));\n    sizer->Add(m_game_list, 1, wxEXPAND);\n\n    // info, warning bar\n    m_info_bar = new wxInfoBar(m_main_panel);\n    m_info_bar->SetShowHideEffects(wxSHOW_EFFECT_BLEND, wxSHOW_EFFECT_BLEND);\n    m_info_bar->SetEffectDuration(500);\n    sizer->Add(m_info_bar, 0, wxALL | wxEXPAND, 5);\n\n    m_main_panel->SetSizer(sizer);\n\n    auto* main_sizer = this->GetSizer();\n    main_sizer->Add(m_main_panel, 1, wxEXPAND, 0, nullptr);\n}\n\nvoid MainWindow::DestroyGameListAndStatusBar()\n{\n    if(!m_main_panel)\n        return;\n    m_main_panel->Destroy();\n    m_main_panel = nullptr;\n    m_game_list = nullptr;\n    m_info_bar = nullptr;\n}\n\nwxString MainWindow::GetInitialWindowTitle()\n{\n\treturn BUILD_VERSION_WITH_NAME_STRING;\n}\n\nvoid MainWindow::OnClose(wxCloseEvent& event)\n{\n\n\tif(m_game_list)\n\t\tm_game_list->OnClose(event);\n\n\tif (!IsMaximized() && !WindowSystem::IsFullScreen())\n\t\tm_restored_size = GetSize();\n\n\tSaveSettings();\n\tm_timer->Stop();\n\n\tevent.Skip();\n\n    CafeSystem::Shutdown();\n\tDestroyCanvas();\n}\n\nbool MainWindow::InstallUpdate(const fs::path& metaFilePath)\n{\n\ttry\n\t{\n\t\tGameUpdateWindow frame(*this, metaFilePath);\n\t\tconst int updateResult = frame.ShowModal();\n\n\t\tif (updateResult == wxID_OK)\n\t\t{\n\t\t\tCafeTitleList::AddTitleFromPath(frame.GetTargetPath()); // this will also send a notification to the game list which will update the entry\n\t\t\twxMessageBox(_(\"Title installed!\"), _(\"Success\"));\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (frame.GetExceptionMessage().empty())\n\t\t\t\twxMessageBox(_(\"Title installation has been canceled!\"));\n\t\t\telse\n\t\t\t{\n\t\t\t\tthrow std::runtime_error(frame.GetExceptionMessage());\n\t\t\t}\n\t\t}\n\t}\n\tcatch(const AbortException&)\n\t{\n\t\t// ignored\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\twxMessageBox(ex.what(), _(\"Update error\"));\n\t}\n\treturn false;\n}\n\nbool MainWindow::FileLoad(const fs::path launchPath, wxLaunchGameEvent::INITIATED_BY initiatedBy)\n{\n\tTitleInfo launchTitle{ launchPath };\n\tif (launchTitle.IsValid())\n\t{\n\t\t// the title might not be in the TitleList, so we add it as a temporary entry\n\t\tCafeTitleList::AddTitleFromPath(launchPath);\n\t\t// title is valid, launch from TitleId\n\t\tTitleId baseTitleId;\n\t\tif (!CafeTitleList::FindBaseTitleId(launchTitle.GetAppTitleId(), baseTitleId))\n\t\t{\n\t\t\twxString t = _(\"Unable to launch game because the base files were not found.\");\n\t\t\twxMessageBox(t, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\t\treturn false;\n\t\t}\n\t\tCafeSystem::PREPARE_STATUS_CODE r = CafeSystem::PrepareForegroundTitle(baseTitleId);\n\t\tif (r == CafeSystem::PREPARE_STATUS_CODE::INVALID_RPX)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn false;\n\t\t}\n\t\telse if (r == CafeSystem::PREPARE_STATUS_CODE::UNABLE_TO_MOUNT)\n\t\t{\n\t\t\twxString t = _(\"Unable to mount title.\\nMake sure the configured game paths are still valid and refresh the game list.\\n\\nFile which failed to load:\\n\");\n\t\t\tt.append(_pathToUtf8(launchPath));\n\t\t\twxMessageBox(t, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\t\treturn false;\n\t\t}\n\t\telse if (r != CafeSystem::PREPARE_STATUS_CODE::SUCCESS)\n\t\t{\n\t\t\twxString t = _(\"Failed to launch game.\");\n\t\t\tt.append(_pathToUtf8(launchPath));\n\t\t\twxMessageBox(t, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\t\treturn false;\n\t\t}\n\t}\n\telse //if (launchTitle.GetFormat() == TitleInfo::TitleDataFormat::INVALID_STRUCTURE )\n\t{\n\t\t// title is invalid, if it's an RPX/ELF we can launch it directly\n\t\t// otherwise it's an error\n\t\tCafeTitleFileType fileType = DetermineCafeSystemFileType(launchPath);\n\t\tif (fileType == CafeTitleFileType::RPX || fileType == CafeTitleFileType::ELF)\n\t\t{\n\t\t\tCafeSystem::PREPARE_STATUS_CODE r = CafeSystem::PrepareForegroundTitleFromStandaloneRPX(launchPath);\n\t\t\tif (r != CafeSystem::PREPARE_STATUS_CODE::SUCCESS)\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false); // todo\n\t\t\t\twxString t = _(\"Failed to launch executable. Path: \");\n\t\t\t\tt.append(_pathToUtf8(launchPath));\n\t\t\t\twxMessageBox(t, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse if (initiatedBy == wxLaunchGameEvent::INITIATED_BY::GAME_LIST)\n\t\t{\n\t\t\twxString t = _(\"Unable to launch title.\\nMake sure the configured game paths are still valid and refresh the game list.\\n\\nPath which failed to load:\\n\");\n\t\t\tt.append(_pathToUtf8(launchPath));\n\t\t\twxMessageBox(t, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\t\treturn false;\n\t\t}\n\t\telse if (initiatedBy == wxLaunchGameEvent::INITIATED_BY::MENU ||\n\t\t\tinitiatedBy == wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE)\n\t\t{\n\t\t\twxString t = _(\"Unable to launch game\\nPath:\\n\");\n\t\t\tt.append(_pathToUtf8(launchPath));\n\t\t\tif(launchTitle.GetInvalidReason() == TitleInfo::InvalidReason::NO_DISC_KEY)\n\t\t\t{\n\t\t\t\tt.append(\"\\n\\n\");\n\t\t\t\tt.append(_(\"Could not decrypt title. Make sure that keys.txt contains the correct disc key for this title.\"));\n\t\t\t}\n\t\t\tif(launchTitle.GetInvalidReason() == TitleInfo::InvalidReason::NO_TITLE_TIK)\n\t\t\t{\n\t\t\t\tt.append(\"\\n\\n\");\n\t\t\t\tt.append(_(\"Could not decrypt title because title.tik is missing.\"));\n\t\t\t}\n\t\t\twxMessageBox(t, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\twxString t = _(\"Unable to launch game\\nPath:\\n\");\n\t\t\tt.append(_pathToUtf8(launchPath));\n\t\t\twxMessageBox(t, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif(launchTitle.IsValid())\n\t\tGetWxGUIConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchTitle.GetPath()));\n\telse\n\t\tGetWxGUIConfig().AddRecentlyLaunchedFile(_pathToUtf8(launchPath));\n\n\twxWindowUpdateLocker lock(this);\n\n    DestroyGameListAndStatusBar();\n\n\tm_game_launched = true;\n\tm_loadMenuItem->Enable(false);\n\tm_installUpdateMenuItem->Enable(false);\n\tm_memorySearcherMenuItem->Enable(true);\n\n\tm_launched_game_name = CafeSystem::GetForegroundTitleName();\n\t#ifdef ENABLE_DISCORD_RPC\n\tif (m_discord)\n\t\tm_discord->UpdatePresence(DiscordPresence::Playing, m_launched_game_name);\n\t#endif\n\n\tif (GetConfig().disable_screensaver)\n\t\tScreenSaver::SetInhibit(true);\n\n\tif (FullscreenEnabled())\n\t\tSetFullScreen(true);\n\n    //GameMode support\n#if BOOST_OS_LINUX && defined(ENABLE_FERAL_GAMEMODE)\n    if(GetWxGUIConfig().feral_gamemode)\n    {\n        // attempt to start gamemode\n        if(gamemode_request_start() < 0)\n        {\n            // GameMode failed to start\n            cemuLog_log(LogType::Force, \"Could not start GameMode\");\n        }\n        else\n        {\n            cemuLog_log(LogType::Force, \"GameMode has been started.\");\n        }\n    }\n#endif\n\n\tCreateCanvas();\n\tCafeSystem::LaunchForegroundTitle();\n\tRecreateMenu();\n\tUpdateChildWindowTitleRunningState();\n\n\treturn true;\n}\n\nvoid MainWindow::OnLaunchFromFile(wxLaunchGameEvent& event)\n{\n\tif (event.GetPath().empty())\n\t\treturn;\n\tFileLoad(event.GetPath(), event.GetInitiatedBy());\n}\n\nvoid MainWindow::OnFileMenu(wxCommandEvent& event)\n{\n\tconst auto menuId = event.GetId();\n\tif (menuId == MAINFRAME_MENU_ID_FILE_LOAD)\n\t{\n\t\tconst auto wildcard = formatWxString(\n\t\t\t\"{}|*.wud;*.wux;*.wua;*.wuhb;*.iso;*.rpx;*.elf;title.tmd\"\n\t\t\t\"|{}|*.wud;*.wux;*.iso\"\n\t\t\t\"|{}|title.tmd\"\n\t\t\t\"|{}|*.wua\"\n\t\t\t\"|{}|*.wuhb\"\n\t\t\t\"|{}|*.rpx;*.elf\"\n\t\t\t\"|{}|*\",\n\t\t\t_(\"All Wii U files (*.wud, *.wux, *.wua, *.wuhb, *.iso, *.rpx, *.elf)\"),\n\t\t\t_(\"Wii U image (*.wud, *.wux, *.iso, *.wad)\"),\n\t\t\t_(\"Wii U NUS content\"),\n\t\t\t_(\"Wii U archive (*.wua)\"),\n\t\t\t_(\"Wii U homebrew bundle (*.wuhb)\"),\n\t\t\t_(\"Wii U executable (*.rpx, *.elf)\"),\n\t\t\t_(\"All files (*.*)\")\n\t\t);\n\n\t\twxFileDialog openFileDialog(this, _(\"Open file to launch\"), wxEmptyString, wxEmptyString, wildcard, wxFD_OPEN | wxFD_FILE_MUST_EXIST);\n\n\t\tif (openFileDialog.ShowModal() == wxID_CANCEL || openFileDialog.GetPath().IsEmpty())\n\t\t\treturn;\n\n\t\tconst wxString wxStrFilePath = openFileDialog.GetPath();\n\t\tFileLoad(_utf8ToPath(wxStrFilePath.utf8_string()), wxLaunchGameEvent::INITIATED_BY::MENU);\n\t}\n\telse if (menuId >= MAINFRAME_MENU_ID_FILE_RECENT_0 && menuId <= MAINFRAME_MENU_ID_FILE_RECENT_LAST)\n\t{\n\t\tconst auto& config = GetWxGUIConfig();\n\t\tconst size_t index = menuId - MAINFRAME_MENU_ID_FILE_RECENT_0;\n\t\tif (index < config.recent_launch_files.size())\n\t\t{\n\t\t\tfs::path path = _utf8ToPath(config.recent_launch_files[index]);\n\t\t\tif (!path.empty())\n\t\t\t\tFileLoad(path, wxLaunchGameEvent::INITIATED_BY::MENU);\n\t\t}\n\t}\n\telse if (menuId == MAINFRAME_MENU_ID_FILE_END_EMULATION)\n\t{\n\t\tEndEmulation();\n\t}\n}\n\nvoid MainWindow::OnOpenFolder(wxCommandEvent& event)\n{\n\tconst auto id = event.GetId();\n\tif(id == MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER)\n\t\twxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetUserDataPath()));\n\telse if(id == MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER)\n\t\twxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetMlcPath()));\n\telse if (id == MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER)\n\t\twxLaunchDefaultApplication(wxHelper::FromPath(ActiveSettings::GetCachePath(\"shaderCache\")));\n}\n\nvoid MainWindow::OnClearSpotPassCache(wxCommandEvent& event)\n{\n\tfs::path bossPath = ActiveSettings::GetMlcPath(\"usr/boss\");\n\tfs::remove_all(bossPath);\n\t// recreate usr/boss/\n\tfs::create_directory(bossPath);\n\twxMessageBox(_(\"SpotPass cache cleared\"));\n}\n\nvoid MainWindow::OnInstallUpdate(wxCommandEvent& event)\n{\n\twhile (true)\n\t{\n\t\twxDirDialog openDirDialog(nullptr, _(\"Select folder of title to install\"), \"\", wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST, wxDefaultPosition, wxDefaultSize, _(\"Select the folder that stores your update, DLC or base game files\"));\n\t\tint modalChoice = openDirDialog.ShowModal();\n\t\tif (modalChoice == wxID_CANCEL || openDirDialog.GetPath().IsEmpty())\n\t\t\tbreak;\n\t\tif (modalChoice == wxID_OK)\n\t\t{\n\t\t\t#if BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_BSD\n\t\t\tfs::path dirPath((const char*)(openDirDialog.GetPath().fn_str()));\n\t\t\t#else\n\t\t\tfs::path dirPath(openDirDialog.GetPath().fn_str());\n\t\t\t#endif\n\n\t\t\tif ((dirPath.filename() == \"code\" || dirPath.filename() == \"content\" || dirPath.filename() == \"meta\") && dirPath.has_parent_path())\n\t\t\t{\n\t\t\t\tif (!fs::exists(dirPath.parent_path() / \"code\") || !fs::exists(dirPath.parent_path() / \"content\") || !fs::exists(dirPath.parent_path() / \"meta\"))\n\t\t\t\t{\n\t\t\t\t\twxMessageBox(formatWxString(_(\"The (parent) folder of the title you selected is missing at least one of the required subfolders (\\\"code\\\", \\\"content\\\" and \\\"meta\\\")\\nMake sure that the files are complete.\"), dirPath.filename().string()));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tdirPath = dirPath.parent_path();\n\t\t\t}\n\n\t\t\tif (!fs::exists(dirPath))\n\t\t\t\twxMessageBox(_(\"The folder you have selected cannot be found on your system.\"));\n\t\t\telse if (!fs::exists(dirPath / \"meta\" / \"meta.xml\"))\n\t\t\t\twxMessageBox(_(\"Unable to find the /meta/meta.xml file inside the selected folder.\"));\n\t\t\telse\n\t\t\t{\n\t\t\t\tInstallUpdate(dirPath);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid MainWindow::OnNFCMenu(wxCommandEvent& event)\n{\n\tif (event.GetId() == MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE)\n\t{\n\t\twxFileDialog\n\t\t\topenFileDialog(this, _(\"Open file to load\"), \"\", \"\",\n\t\t\t\t\"All NFC files (bin, dat, nfc)|*.bin;*.dat;*.nfc|All files (*.*)|*\", wxFD_OPEN | wxFD_FILE_MUST_EXIST); // TRANSLATE\n\t\tif (openFileDialog.ShowModal() == wxID_CANCEL || openFileDialog.GetPath().IsEmpty())\n\t\t\treturn;\n\t\twxString wxStrFilePath = openFileDialog.GetPath();\n\t\tuint32 nfcError;\n\t\tif (nfc::TouchTagFromFile(_utf8ToPath(wxStrFilePath.utf8_string()), &nfcError) == false)\n\t\t{\n\t\t\tif (nfcError == NFC_TOUCH_TAG_ERROR_NO_ACCESS)\n\t\t\t\twxMessageBox(_(\"Cannot open file\"));\n\t\t\telse if (nfcError == NFC_TOUCH_TAG_ERROR_INVALID_FILE_FORMAT)\n\t\t\t\twxMessageBox(_(\"Not a valid NFC file\"));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tGetWxGUIConfig().AddRecentNfcFile(wxStrFilePath.utf8_string());\n\t\t\tUpdateNFCMenu();\n\t\t}\n\t}\n\telse if (event.GetId() >= MAINFRAME_MENU_ID_NFC_RECENT_0 && event.GetId() <= MAINFRAME_MENU_ID_NFC_RECENT_LAST)\n\t{\n\t\tconst size_t index = event.GetId() - MAINFRAME_MENU_ID_NFC_RECENT_0;\n\t\tauto& config = GetWxGUIConfig();\n\t\tif (index < config.recent_nfc_files.size())\n\t\t{\n\t\t\tconst auto& path = config.recent_nfc_files[index];\n\t\t\tif (!path.empty())\n\t\t\t{\n\t\t\t\tuint32 nfcError = 0;\n\t\t\t\tif (nfc::TouchTagFromFile(_utf8ToPath(path), &nfcError) == false)\n\t\t\t\t{\n\t\t\t\t\tif (nfcError == NFC_TOUCH_TAG_ERROR_NO_ACCESS)\n\t\t\t\t\t\twxMessageBox(_(\"Cannot open file\"));\n\t\t\t\t\telse if (nfcError == NFC_TOUCH_TAG_ERROR_INVALID_FILE_FORMAT)\n\t\t\t\t\t\twxMessageBox(_(\"Not a valid NFC file\"));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tconfig.AddRecentNfcFile(path);\n\t\t\t\t\tUpdateNFCMenu();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid MainWindow::OnFileExit(wxCommandEvent& event)\n{\n\tClose();\n}\n\nvoid MainWindow::TogglePadView()\n{\n\tconst auto& config = GetWxGUIConfig();\n\tif (config.pad_open)\n\t{\n\t\tif (m_padView)\n\t\t\treturn;\n\n\t\tm_padView = new PadViewFrame(this);\n\n\t\tm_padView->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnPadClose, this);\n\n\t\tm_padView->Show(true);\n\n#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND\n\t\tif (wxWlIsWaylandWindow(m_padView))\n\t\t\twxWlSetAppId(m_padView, \"info.cemu.Cemu\");\n#endif\n\n\t\tm_padView->Initialize();\n\t\tif (m_game_launched)\n\t\t\tm_padView->InitializeRenderCanvas();\n\t}\n\telse if (m_padView)\n\t{\n\t\tm_padView->Destroy();\n\t\tm_padView = nullptr;\n\t}\n}\n\n#if BOOST_OS_WINDOWS\n\n#ifndef DBT_DEVNODES_CHANGED\n#define DBT_DEVNODES_CHANGED (0x0007)\n#endif\nWXLRESULT MainWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)\n{\n\tif (nMsg == WM_DEVICECHANGE)\n\t{\n\t\tif (wParam == DBT_DEVNODES_CHANGED)\n\t\t{\n\t\t\tInputManager::instance().on_device_changed();\n\t\t}\n\t}\n\n\treturn wxFrame::MSWWindowProc(nMsg, wParam, lParam);\n}\n#endif\n\nvoid MainWindow::OpenSettings()\n{\n\tauto& config = GetWxGUIConfig();\n\tconst auto language = config.language;\n\n\tGeneralSettings2 frame(this, m_game_launched);\n\tframe.ShowModal();\n\tconst bool paths_modified = frame.ShouldReloadGamelist();\n\tconst bool mlc_modified = frame.MLCModified();\n\n\tif (paths_modified)\n\t\tm_game_list->ReloadGameEntries();\n\telse\n\t\tSaveSettings();\n\n\t#ifdef ENABLE_DISCORD_RPC\n\tif (config.use_discord_presence)\n\t{\n\t\tif (!m_discord)\n\t\t{\n\t\t\tm_discord = std::make_unique<DiscordPresence>();\n\t\t\tif (!m_launched_game_name.empty())\n\t\t\t\tm_discord->UpdatePresence(DiscordPresence::Playing, m_launched_game_name);\n\t\t}\n\t}\n\telse\n\t\tm_discord.reset();\n\t#endif\n\n\tif(config.check_update && !m_game_launched)\n\t\tm_update_available = CemuUpdateWindow::IsUpdateAvailableAsync();\n\n\tif (mlc_modified)\n\t\tRecreateMenu();\n\n\tif (!config.fullscreen_menubar && IsFullScreen())\n\t\tSetMenuVisible(false);\n\n\tif (language != config.language)\n\t\twxMessageBox(_(\"Cemu must be restarted to apply the selected UI language.\"), _(\"Information\"), wxOK | wxCENTRE, this); // TODO: change language to newly selected one\n}\n\nvoid MainWindow::OnOptionsInput(wxCommandEvent& event)\n{\n\tswitch (event.GetId())\n\t{\n\tcase MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN:\n\t{\n\t\tconst bool state = m_fullscreenMenuItem->IsChecked();\n\t\tSetFullScreen(state);\n\t\tbreak;\n\t}\n\tcase MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW:\n\t{\n\t\tGetWxGUIConfig().pad_open = !GetWxGUIConfig().pad_open;\n\t\tg_wxConfig.Save();\n\n\t\tTogglePadView();\n\t\tbreak;\n\t}\n\tcase MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2:\n\t{\n\t\tif (m_graphic_pack_window)\n\t\t\treturn;\n\n\t\tuint64 titleId = 0;\n\t\tif (CafeSystem::IsTitleRunning())\n\t\t\ttitleId = CafeSystem::GetForegroundTitleId();\n\n\t\tm_graphic_pack_window = new GraphicPacksWindow2(this, titleId);\n\t\tm_graphic_pack_window->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnGraphicWindowClose, this);\n\t\tm_graphic_pack_window->Show(true);\n\n\t\tbreak;\n\t}\n\n\tcase MAINFRAME_MENU_ID_OPTIONS_MAC_SETTINGS:\n\tcase MAINFRAME_MENU_ID_OPTIONS_GENERAL2:\n\t{\n\t\tOpenSettings();\n\t\tbreak;\n\t}\n\tcase MAINFRAME_MENU_ID_OPTIONS_INPUT:\n\t{\n\t\tauto* frame = new InputSettings2(this);\n\t\tframe->ShowModal();\n\t\tframe->Destroy();\n\t\tbreak;\n\t}\n\n\tcase MAINFRAME_MENU_ID_OPTIONS_HOTKEY:\n\t{\n\t\tauto* frame = new HotkeySettings(this);\n\t\tframe->Show();\n\t\tbreak;\n\t}\n\t}\n}\n\nvoid MainWindow::OnAccountSelect(wxCommandEvent& event)\n{\n\tconst int index = event.GetId() - MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1;\n\tconst auto& accounts = Account::GetAccounts();\n\twxASSERT(index >= 0 && index < (int)accounts.size());\n\tauto& config = GetConfig();\n\tconfig.account.m_persistent_id = accounts[index].GetPersistentId();\n\t// config.account.online_enabled.value = false; // reset online for safety\n\tGetConfigHandle().Save();\n}\n\nvoid MainWindow::OnConsoleLanguage(wxCommandEvent& event)\n{\n\tswitch (event.GetId())\n\t{\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_JAPANESE:\n\t\tGetConfig().console_language = CafeConsoleLanguage::JA;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ENGLISH:\n\t\tGetConfig().console_language = CafeConsoleLanguage::EN;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_FRENCH:\n\t\tGetConfig().console_language = CafeConsoleLanguage::FR;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_GERMAN:\n\t\tGetConfig().console_language = CafeConsoleLanguage::DE;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ITALIAN:\n\t\tGetConfig().console_language = CafeConsoleLanguage::IT;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_SPANISH:\n\t\tGetConfig().console_language = CafeConsoleLanguage::ES;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_CHINESE:\n\t\tGetConfig().console_language = CafeConsoleLanguage::ZH;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_KOREAN:\n\t\tGetConfig().console_language = CafeConsoleLanguage::KO;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_DUTCH:\n\t\tGetConfig().console_language = CafeConsoleLanguage::NL;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_PORTUGUESE:\n\t\tGetConfig().console_language = CafeConsoleLanguage::PT;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_RUSSIAN:\n\t\tGetConfig().console_language = CafeConsoleLanguage::RU;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE:\n\t\tGetConfig().console_language = CafeConsoleLanguage::TW;\n\t\tbreak;\n\tdefault:\n\t\tcemu_assert_debug(false);\n\t}\n\tif (m_game_list)\n\t{\n\t\tm_game_list->DeleteCachedStrings();\n\t\tm_game_list->ReloadGameEntries();\n\t}\n\tGetConfigHandle().Save();\n}\n\n//void MainWindow::OnCPUMode(wxCommandEvent& event)\n//{\n//\tif (event.GetId() == MAINFRAME_MENU_ID_CPU_MODE_SINGLECORE_INTERPRETER)\n//\t\tGetConfig().cpu_mode = CPUMode::SinglecoreInterpreter;\n//\telse if (event.GetId() == MAINFRAME_MENU_ID_CPU_MODE_SINGLECORE_RECOMPILER)\n//\t\tGetConfig().cpu_mode = CPUMode::SinglecoreRecompiler;\n//\telse if (event.GetId() == MAINFRAME_MENU_ID_CPU_MODE_DUALCORE_RECOMPILER)\n//\t\tGetConfig().cpu_mode = CPUMode::DualcoreRecompiler;\n//\telse if (event.GetId() == MAINFRAME_MENU_ID_CPU_MODE_TRIPLECORE_RECOMPILER)\n//\t\tGetConfig().cpu_mode = CPUMode::TriplecoreRecompiler;\n//\telse\n//\t\tcemu_assert_debug(false);\n//\n//\tGetConfigHandle().Save();\n//}\n\nvoid MainWindow::OnDebugSetting(wxCommandEvent& event)\n{\n\tif (event.GetId() == MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN)\n\t\tGetConfig().render_upside_down = event.IsChecked();\n\telse if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS)\n\t{\n\t\tGetConfig().vk_accurate_barriers = event.IsChecked();\n\t\tif(!GetConfig().vk_accurate_barriers)\n\t\t\twxMessageBox(_(\"Warning: Disabling the accurate barriers option will lead to flickering graphics but may improve performance. It is highly recommended to leave it turned on.\"), _(\"Accurate barriers are off\"), wxOK);\n\t}\n#if ENABLE_METAL\n\telse if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE)\n\t{\n\t\tcemu_assert_debug(g_renderer->GetType() == RendererAPI::Metal);\n\t\tstatic_cast<MetalRenderer*>(g_renderer.get())->CaptureFrame();\n\t}\n#endif\n\telse if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY)\n\t\tActiveSettings::EnableAudioOnlyAux(event.IsChecked());\n\telse if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_DUMP_RAM)\n\t\tmemory_createDump();\n\telse if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_DUMP_FST)\n\t{\n\t\t/*\tint msgBoxAnswer = wxMessageBox(_(\"All files from the currently running game will be dumped to /dump/<gamefolder>. This process can take a few minutes.\"),\n\t\t\t\t_(\"Dump WUD\"), wxOK | wxCANCEL | wxICON_WARNING);\n\t\t\tif (msgBoxAnswer == wxOK)\n\t\t\t{\n\t\t\t\tvolumeFST_dump(bootGame_getMountedWUD());\n\t\t\t\twxMessageBox(_(\"Dump complete\"));\n\t\t\t}*/\n\t}\n\telse if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS)\n\t{\n\t\t// toggle debug -> dump -> curl requests\n\t\tconst bool state = event.IsChecked();\n\t\tActiveSettings::EnableDumpLibcurlRequests(state);\n\t\tif (state)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tconst fs::path path(ActiveSettings::GetUserDataPath());\n\t\t\t\tfs::create_directories(path / \"dump\" / \"curl\");\n\t\t\t}\n\t\t\tcatch (const std::exception& ex)\n\t\t\t{\n\t\t\t\tSystemException sys(ex);\n\t\t\t\tcemuLog_log(LogType::Force, \"error when creating dump curl folder: {}\", sys.what());\n\t\t\t\tActiveSettings::EnableDumpLibcurlRequests(false);\n\t\t\t}\n\t\t}\n\t}\n\telse if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_8X)\n\t\tActiveSettings::SetTimerShiftFactor(0);\n\telse if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_4X)\n\t\tActiveSettings::SetTimerShiftFactor(1);\n\telse if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_2X)\n\t\tActiveSettings::SetTimerShiftFactor(2);\n\telse if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_1X)\n\t\tActiveSettings::SetTimerShiftFactor(3);\n\telse if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_05X)\n\t\tActiveSettings::SetTimerShiftFactor(4);\n\telse if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_025X)\n\t\tActiveSettings::SetTimerShiftFactor(5);\n\telse if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_0125X)\n\t\tActiveSettings::SetTimerShiftFactor(6);\n\telse\n\t\tcemu_assert_debug(false);\n\n\tGetConfigHandle().Save();\n}\n\nvoid MainWindow::OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event)\n{\n\tsint32 loggingIdBase = MAINFRAME_MENU_ID_DEBUG_LOGGING0;\n\n\tsint32 id = event.GetId();\n\tif (id >= loggingIdBase && id < (MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 64))\n\t{\n\t\tbool isEnable = event.IsChecked();\n\t\tLogType loggingType = static_cast<LogType>(id - loggingIdBase);\n\t\tif (isEnable)\n\t\t\tGetConfig().log_flag = GetConfig().log_flag.GetValue() | cemuLog_getFlag(loggingType);\n\t\telse\n\t\t\tGetConfig().log_flag = GetConfig().log_flag.GetValue() & ~cemuLog_getFlag(loggingType);\n\t\tcemuLog_setActiveLoggingFlags(GetConfig().log_flag.GetValue());\n\t\tGetConfigHandle().Save();\n\t}\n}\n\nvoid MainWindow::OnPPCInfoToggle(wxCommandEvent& event)\n{\n\tGetConfig().advanced_ppc_logging = !GetConfig().advanced_ppc_logging.GetValue();\n\tGetConfigHandle().Save();\n}\n\nvoid MainWindow::OnDebugDumpGeneric(wxCommandEvent& event)\n{\n\tstd::string dumpSubpath;\n\tstd::function<void(bool)> setDumpState;\n\tswitch(event.GetId())\n\t{\n\tcase MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES:\n\t\tdumpSubpath = \"dump/textures\";\n\t\tsetDumpState = ActiveSettings::EnableDumpTextures;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS:\n\t\tdumpSubpath = \"dump/shaders\";\n\t\tsetDumpState = ActiveSettings::EnableDumpShaders;\n\t\tbreak;\n\tcase MAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS:\n\t\tdumpSubpath = \"dump/recompiler\";\n\t\tsetDumpState = ActiveSettings::EnableDumpRecompilerFunctions;\n\t\tbreak;\n\tdefault:\n\t\tUNREACHABLE;\n\t}\n\tconst bool value = event.IsChecked();\n\tsetDumpState(value);\n\tif (value)\n\t{\n\t\ttry\n\t\t{\n\t\t\tfs::create_directories(ActiveSettings::GetUserDataPath(dumpSubpath));\n\t\t}\n\t\tcatch (const std::exception & ex)\n\t\t{\n\t\t\tSystemException sys(ex);\n\t\t\tcemuLog_log(LogType::Force, \"can't create folder {} in user data folder: {}\", dumpSubpath, ex.what());\n\t\t\tsetDumpState(false);\n\t\t}\n\t}\n}\n\nvoid MainWindow::OnLoggingWindow(wxCommandEvent& event)\n{\n\tif(m_logging_window)\n\t\treturn;\n\n\tm_logging_window = new LoggingWindow(this);\n\tm_logging_window->Bind(wxEVT_CLOSE_WINDOW,\n\t\t[this](wxCloseEvent& event) {\n\t\tm_logging_window = nullptr;\n\t\tevent.Skip();\n\t});\n\tm_logging_window->Show(true);\n}\n\nvoid MainWindow::OnGDBStubToggle(wxCommandEvent& event)\n{\n\tif (g_gdbstub)\n\t{\n\t\tg_gdbstub.release();\n\t\treturn;\n\t}\n\n\tconst auto& config = GetConfig();\n\tg_gdbstub = std::make_unique<GDBServer>(config.gdb_port);\n}\n\nvoid MainWindow::OnDebugViewPPCThreads(wxCommandEvent& event)\n{\n\tauto frame = new DebugPPCThreadsWindow(*this);\n\tframe->Show(true);\n}\n\nvoid MainWindow::OnDebugViewPPCDebugger(wxCommandEvent& event)\n{\n\tif (m_debugger_window && m_debugger_window->IsShown())\n\t{\n\t\tm_debugger_window->Close();\n\t\tm_debugger_window = nullptr;\n\t\treturn;\n\t}\n\n\tauto rect = GetDesktopRect();\n\t/*\n\tsint32 new_width = max(rect.GetWidth() * 0.70, rect.GetWidth() - 850);\n\tthis->SetSize(new_width, 480);*/\n\n\tthis->SetSize(800, 450 + 50);\n\tthis->CenterOnScreen();\n\n\tauto pos = this->GetPosition();\n\tpos.y = std::min(pos.y + 200, rect.GetHeight() - 400);\n\tthis->SetPosition(pos);\n\n\tm_debugger_window = new DebuggerWindow2(*this, rect);\n\tm_debugger_window->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnDebuggerClose, this);\n\tm_debugger_window->Show(true);\n}\n\nvoid MainWindow::OnDebugViewAudioDebugger(wxCommandEvent& event)\n{\n\tauto frame = new AudioDebuggerWindow(*this);\n\tframe->Show(true);\n}\n\nvoid MainWindow::OnDebugViewTextureRelations(wxCommandEvent& event)\n{\n\topenTextureViewer(*this);\n}\n\nvoid MainWindow::ShowCursor(bool state)\n{\n\t#if BOOST_OS_WINDOWS\n\tCURSORINFO info{};\n\tinfo.cbSize = sizeof(CURSORINFO);\n\tGetCursorInfo(&info);\n\tconst bool visible = info.flags == CURSOR_SHOWING;\n\n\tif (state == visible)\n\t\treturn;\n\n\tint counter = 0;\n\tif(state)\n\t{\n\t\tdo\n\t\t{\n\t\t\tcounter = ::ShowCursor(TRUE);\n\t\t} while (counter < 0);\n\t}\n\telse\n\t{\n\t\tdo\n\t\t{\n\t\t\tcounter = ::ShowCursor(FALSE);\n\t\t} while (counter >= 0);\n\t}\n\t#else\n\tif (state)\n\t{\n\t\twxSetCursor(wxNullCursor); // restore system default cursor\n\t}\n\telse\n\t{\n\t\twxSetCursor(wxCursor(wxCURSOR_BLANK));\n\t}\n\t#endif\n}\n\nuintptr_t MainWindow::GetRenderCanvasHWND()\n{\n\t// deprecated. We can use the global cross-platform window info structs now\n\t#if BOOST_OS_WINDOWS\n\tif (!m_render_canvas)\n\t\treturn 0;\n\treturn (uintptr_t)m_render_canvas->GetHWND();\n\t#else\n\treturn 0;\n\t#endif\n}\n\nwxRect MainWindow::GetDesktopRect()\n{\n\tconst auto pos = GetPosition();\n\tconst auto middle = pos.x + GetSize().GetWidth() / 2;\n\n\tconst auto displayCount = wxDisplay::GetCount();\n\tfor (uint32 i = 0; i < displayCount; ++i)\n\t{\n\t\twxDisplay display(i);\n\t\tif (!display.IsOk())\n\t\t\tcontinue;\n\n\t\tconst auto geo = display.GetGeometry();\n\t\tif (geo.x <= middle && middle <= geo.x + geo.width)\n\t\t\treturn geo;\n\t}\n\treturn { 0,0,800,600 };\n}\n\nvoid MainWindow::LoadSettings()\n{\n\tGetConfigHandle().Load();\n\tconst auto& config = GetWxGUIConfig();\n\n\tif(config.check_update)\n\t\tm_update_available = CemuUpdateWindow::IsUpdateAvailableAsync();\n\n\tif (config.window_position != Vector2i{ -1,-1 })\n\t\tthis->SetPosition({ config.window_position.x, config.window_position.y });\n\n\tif (config.window_size.x > 0 && config.window_size.y > 0)\n\t{\n\t\tthis->SetSize({ config.window_size.x, config.window_size.y });\n\n\t\tif (config.window_maximized)\n\t\t\tthis->Maximize();\n\t}\n\n\tif (config.pad_position != Vector2i{ -1,-1 })\n\t{\n\t\tg_window_info.restored_pad_x = config.pad_position.x;\n\t\tg_window_info.restored_pad_y = config.pad_position.y;\n\t}\n\n\tif (config.pad_size != Vector2i{ -1,-1 })\n\t{\n\t\tg_window_info.restored_pad_width = config.pad_size.x;\n\t\tg_window_info.restored_pad_height = config.pad_size.y;\n\n\t\tg_window_info.pad_maximized = config.pad_maximized;\n\t}\n\n\tthis->TogglePadView();\n\n\tif(m_game_list)\n\t\tm_game_list->LoadConfig();\n}\n\nvoid MainWindow::SaveSettings()\n{\n\tauto lock = GetConfigHandle().Lock();\n\tauto& config = GetWxGUIConfig();\n\n\tif (config.window_position != Vector2i{ -1,-1 })\n\t{\n\t\tconfig.window_position.x = m_restored_position.x;\n\t\tconfig.window_position.y = m_restored_position.y;\n\t}\n\tif (config.window_size != Vector2i{ -1,-1 })\n\t{\n\t\tconfig.window_size.x = m_restored_size.x;\n\t\tconfig.window_size.y = m_restored_size.y;\n\t\tconfig.window_maximized = IsMaximized();\n\t}\n\telse\n\t{\n\t\tconfig.window_maximized = false;\n\t}\n\n\tconfig.pad_open = m_padView != nullptr;\n\n\tif (config.pad_position != Vector2i{ -1,-1 } && g_window_info.restored_pad_x != -1)\n\t{\n\t\tconfig.pad_position.x = g_window_info.restored_pad_x;\n\t\tconfig.pad_position.y = g_window_info.restored_pad_y;\n\t}\n\tif (config.pad_size != Vector2i{ -1,-1 } && g_window_info.restored_pad_width != -1)\n\t{\n\t\tconfig.pad_size.x = g_window_info.restored_pad_width;\n\t\tconfig.pad_size.y = g_window_info.restored_pad_height;\n\t\tconfig.pad_maximized = g_window_info.pad_maximized;\n\t}\n\telse\n\t{\n\t\tconfig.pad_maximized = false;\n\t}\n\n\tif(m_game_list)\n\t\tm_game_list->SaveConfig();\n\n\tg_wxConfig.Save();\n}\n\nvoid MainWindow::OnMouseMove(wxMouseEvent& event)\n{\n\tevent.Skip();\n\n\tm_last_mouse_move_time = std::chrono::steady_clock::now();\n\tm_mouse_position = wxGetMousePosition();\n\tShowCursor(true);\n\n\tauto& instance = InputManager::instance();\n\tstd::unique_lock lock(instance.m_main_mouse.m_mutex);\n\tauto physPos = ToPhys(event.GetPosition());\n\tinstance.m_main_mouse.position = { physPos.x, physPos.y };\n\tlock.unlock();\n\n\tif (!IsFullScreen())\n\t\treturn;\n\n\tconst auto& config = GetWxGUIConfig();\n\t// if mouse goes to upper screen then show our menu in fullscreen mode\n\tif (config.fullscreen_menubar)\n\t\tSetMenuVisible(event.GetPosition().y < 50);\n}\n\nvoid MainWindow::OnMouseLeft(wxMouseEvent& event)\n{\n\tauto& instance = InputManager::instance();\n\n\tstd::scoped_lock lock(instance.m_main_mouse.m_mutex);\n\tinstance.m_main_mouse.left_down = event.ButtonDown(wxMOUSE_BTN_LEFT);\n\tauto physPos = ToPhys(event.GetPosition());\n\tinstance.m_main_mouse.position = { physPos.x, physPos.y };\n\tif (event.ButtonDown(wxMOUSE_BTN_LEFT))\n\t\tinstance.m_main_mouse.left_down_toggle = true;\n\n\tevent.Skip();\n}\n\nvoid MainWindow::OnMouseRight(wxMouseEvent& event)\n{\n\tauto& instance = InputManager::instance();\n\n\tstd::scoped_lock lock(instance.m_main_mouse.m_mutex);\n\tinstance.m_main_mouse.right_down = event.ButtonDown(wxMOUSE_BTN_RIGHT);\n\tauto physPos = ToPhys(event.GetPosition());\n\tinstance.m_main_mouse.position = { physPos.x, physPos.y };\n\tif(event.ButtonDown(wxMOUSE_BTN_RIGHT))\n\t\tinstance.m_main_mouse.right_down_toggle = true;\n\n\tevent.Skip();\n}\n\nvoid MainWindow::OnGameListBeginUpdate(wxCommandEvent& event)\n{\n\tif (m_game_list->IsShown())\n\t\tm_info_bar->ShowMessage(_(\"Updating game list...\"));\n}\n\nvoid MainWindow::OnGameListEndUpdate(wxCommandEvent& event)\n{\n\tm_info_bar->Dismiss();\n}\n\nvoid MainWindow::OnAccountListRefresh(wxCommandEvent& event)\n{\n\tRecreateMenu();\n}\n\nvoid MainWindow::OnRequestGameListRefresh(wxCommandEvent& event)\n{\n\tm_game_list->ReloadGameEntries();\n}\n\nvoid MainWindow::OnSetWindowTitle(wxCommandEvent& event)\n{\n\tthis->SetTitle(event.GetString());\n}\n\nvoid MainWindow::OnKeyUp(wxKeyEvent& event)\n{\n\tevent.Skip();\n\n\tif (swkbd_hasKeyboardInputHook())\n\t\treturn;\n\n\tHotkeySettings::CaptureInput(event);\n}\n\nvoid MainWindow::OnKeyDown(wxKeyEvent& event)\n{\n#if defined(__APPLE__)\n       // On macOS, allow Cmd+Q to quit the application\n    if (event.CmdDown() && event.GetKeyCode() == 'Q')\n    {\n        Close(true);\n    }\n#else\n     // On Windows/Linux, only Alt+F4 is allowed for quitting\n    if (event.AltDown() && event.GetKeyCode() == WXK_F4)\n    {\n        Close(true);\n    }\n#endif\n    else\n    {\n        event.Skip();\n    }\n}\n\nvoid MainWindow::OnChar(wxKeyEvent& event)\n{\n\tif (swkbd_hasKeyboardInputHook())\n\t\tswkbd_keyInput(event.GetUnicodeKey());\n\n\t// event.Skip();\n}\n\nvoid MainWindow::OnToolsInput(wxCommandEvent& event)\n{\n\tconst auto id = event.GetId();\n\tswitch (id)\n\t{\n\tcase MAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER:\n\t{\n\t\tif (m_toolWindow)\n\t\t\tm_toolWindow->SetFocus();\n\t\telse\n\t\t{\n\t\t\tm_toolWindow = new MemorySearcherTool(this);\n\t\t\tm_toolWindow->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnMemorySearcherClose, this);\n\t\t\tm_toolWindow->Show(true);\n\t\t}\n\t\tbreak;\n\t}\n\tcase MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER:\n\tcase MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER:\n\t{\n\t\tconst auto default_tab = id == MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER ? TitleManagerPage::TitleManager : TitleManagerPage::DownloadManager;\n\n\t\tif (m_title_manager)\n\t\t\tm_title_manager->SetFocusAndTab(default_tab);\n\t\telse\n\t\t{\n\t\t\tm_title_manager = new TitleManager(this, default_tab);\n\t\t\tm_title_manager->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event)\n\t\t\t\t{\n\t\t\t\t\tm_title_manager = nullptr;\n\t\t\t\t\tevent.Skip();\n\t\t\t\t});\n\t\t\tm_title_manager->Show();\n\t\t}\n\t\tbreak;\n\t}\n\tcase MAINFRAME_MENU_ID_TOOLS_EMULATED_USB_DEVICES:\n\t{\n\t\tif (m_usb_devices)\n\t\t{\n\t\t\tm_usb_devices->Show(true);\n\t\t\tm_usb_devices->Raise();\n\t\t\tm_usb_devices->SetFocus();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_usb_devices = new EmulatedUSBDeviceFrame(this);\n\t\t\tm_usb_devices->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event)\n\t\t\t\t{\n\t\t\t\t\tif (event.CanVeto()) {\n\t\t\t\t\t\tm_usb_devices->Show(false);\n\t\t\t\t\t\tevent.Veto();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\tm_usb_devices->Show(true);\n\t\t}\n\t\tbreak;\n\t}\n\tbreak;\n\t}\n}\n\nvoid MainWindow::OnGesturePan(wxPanGestureEvent& event)\n{\n\tauto& instance = InputManager::instance();\n\tstd::scoped_lock lock(instance.m_main_touch.m_mutex);\n\tauto physPos = ToPhys(event.GetPosition());\n\tinstance.m_main_touch.position = { physPos.x, physPos.y };\n\tinstance.m_main_touch.left_down = event.IsGestureStart() || !event.IsGestureEnd();\n\tif (event.IsGestureStart() || !event.IsGestureEnd())\n\t\tinstance.m_main_touch.left_down_toggle = true;\n\n\n\tevent.Skip();\n}\n\nvoid MainWindow::OnGameLoaded()\n{\n\tif (m_debugger_window)\n\t\tm_debugger_window->OnGameLoaded();\n}\n\nvoid MainWindow::AsyncSetTitle(std::string_view windowTitle)\n{\n\twxCommandEvent set_title_event(wxEVT_SET_WINDOW_TITLE);\n\tset_title_event.SetString(wxString::FromUTF8(windowTitle));\n\tg_mainFrame->QueueEvent(set_title_event.Clone());\n}\n\nvoid MainWindow::CreateCanvas()\n{\n    // create panel for canvas\n    m_game_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxWANTS_CHARS);\n    auto* sizer = new wxBoxSizer(wxVERTICAL);\n\n    // shouldn't be needed, but who knows\n    m_game_panel->Bind(wxEVT_KEY_UP, &MainWindow::OnKeyUp, this);\n    m_game_panel->Bind(wxEVT_CHAR, &MainWindow::OnChar, this);\n\n    m_game_panel->SetSizer(sizer);\n    this->GetSizer()->Add(m_game_panel, 1, wxEXPAND);\n\n    // create canvas\n    if (ActiveSettings::GetGraphicsAPI() == kVulkan)\n\t\tm_render_canvas = new VulkanCanvas(m_game_panel, wxSize(1280, 720), true);\n\telse if (ActiveSettings::GetGraphicsAPI() == kOpenGL)\n\t\tm_render_canvas = GLCanvas_Create(m_game_panel, wxSize(1280, 720), true);\n#if ENABLE_METAL\n\telse\n\t    m_render_canvas = new MetalCanvas(m_game_panel, wxSize(1280, 720), true);\n#endif\n\n\t// mouse events\n\tm_render_canvas->Bind(wxEVT_MOTION, &MainWindow::OnMouseMove, this);\n\tm_render_canvas->Bind(wxEVT_MOUSEWHEEL, &MainWindow::OnMouseWheel, this);\n\tm_render_canvas->Bind(wxEVT_LEFT_DOWN, &MainWindow::OnMouseLeft, this);\n\tm_render_canvas->Bind(wxEVT_LEFT_UP, &MainWindow::OnMouseLeft, this);\n\tm_render_canvas->Bind(wxEVT_RIGHT_DOWN, &MainWindow::OnMouseRight, this);\n\tm_render_canvas->Bind(wxEVT_RIGHT_UP, &MainWindow::OnMouseRight, this);\n\n\tm_render_canvas->Bind(wxEVT_GESTURE_PAN, &MainWindow::OnGesturePan, this);\n\n\t// key events\n\tm_render_canvas->Bind(wxEVT_KEY_UP, &MainWindow::OnKeyUp, this);\n\tm_render_canvas->Bind(wxEVT_KEY_DOWN, &MainWindow::OnKeyDown, this);\n\tm_render_canvas->Bind(wxEVT_CHAR, &MainWindow::OnChar, this);\n\n\tm_render_canvas->SetDropTarget(new wxAmiiboDropTarget(this));\n\tm_game_panel->GetSizer()->Add(m_render_canvas, 1, wxEXPAND, 0, nullptr);\n\n\tGetSizer()->Layout();\n\tm_render_canvas->SetFocus();\n\n\tif (m_padView)\n\t\tm_padView->InitializeRenderCanvas();\n}\n\nvoid MainWindow::DestroyCanvas()\n{\n\tif (m_padView)\n\t{\n\t\tm_padView->DestroyCanvas();\n\t}\n\tif (m_render_canvas)\n\t{\n\t\tm_render_canvas->Destroy();\n\t\tm_render_canvas = nullptr;\n\t}\n    if(m_game_panel)\n    {\n        m_game_panel->Destroy();\n        m_game_panel = nullptr;\n    }\n}\n\nvoid MainWindow::OnSizeEvent(wxSizeEvent& event)\n{\n\tif (!IsMaximized() && !WindowSystem::IsFullScreen())\n\t\tm_restored_size = GetSize();\n\n\tconst wxSize client_size = GetClientSize();\n\tg_window_info.width = client_size.GetWidth();\n\tg_window_info.height = client_size.GetHeight();\n\tg_window_info.phys_width = ToPhys(client_size.GetWidth());\n\tg_window_info.phys_height = ToPhys(client_size.GetHeight());\n\tg_window_info.dpi_scale = GetDPIScaleFactor();\n\n\tif (m_debugger_window && m_debugger_window->IsShown())\n\t\tm_debugger_window->OnParentMove(GetPosition(), event.GetSize());\n\n\tevent.Skip();\n\n\tVsyncDriver_notifyWindowPosChanged();\n}\n\nvoid MainWindow::OnDPIChangedEvent(wxDPIChangedEvent& event)\n{\n\tevent.Skip();\n\tconst wxSize client_size = GetClientSize();\n\tg_window_info.width = client_size.GetWidth();\n\tg_window_info.height = client_size.GetHeight();\n\tg_window_info.phys_width = ToPhys(client_size.GetWidth());\n\tg_window_info.phys_height = ToPhys(client_size.GetHeight());\n\tg_window_info.dpi_scale = GetDPIScaleFactor();\n}\n\nvoid MainWindow::OnMove(wxMoveEvent& event)\n{\n\tif (!IsMaximized() && !WindowSystem::IsFullScreen())\n\t\tm_restored_position = GetPosition();\n\n\tif (m_debugger_window && m_debugger_window->IsShown())\n\t\tm_debugger_window->OnParentMove(GetPosition(), GetSize());\n\tVsyncDriver_notifyWindowPosChanged();\n}\n\nvoid MainWindow::OnDebuggerClose(wxCloseEvent& event)\n{\n\tm_debugger_window = nullptr;\n\tevent.Skip();\n}\n\nvoid MainWindow::OnPadClose(wxCloseEvent& event)\n{\n\tauto& config = GetWxGUIConfig();\n\tconfig.pad_open = false;\n\tif (config.pad_position != Vector2i{ -1,-1 })\n\t\tm_padView->GetPosition(&config.pad_position.x, &config.pad_position.y);\n\n\tif (config.pad_size != Vector2i{ -1,-1 })\n\t\tm_padView->GetSize(&config.pad_size.x, &config.pad_size.y);\n\n\tg_wxConfig.Save();\n\n\t// already deleted by wxwidget\n\tm_padView = nullptr;\n\n\tif (m_padViewMenuItem)\n\t\tm_padViewMenuItem->Check(false);\n\n\tevent.Skip();\n}\n\nvoid MainWindow::OnMemorySearcherClose(wxCloseEvent& event)\n{\n\tm_toolWindow = nullptr;\n\tevent.Skip();\n}\n\nvoid MainWindow::OnMouseWheel(wxMouseEvent& event)\n{\n\tconst float delta = event.GetWheelRotation(); // in 120 steps -> max reached ~480 (?)\n\tauto& instance = InputManager::instance();\n\tinstance.m_mouse_wheel = (delta / 120.0f);\n\n\tevent.Skip();\n}\n\nvoid MainWindow::SetFullScreen(bool state)\n{\n\t// only update config entry if we dont't have launch parameters\n\tif (!LaunchSettings::FullscreenEnabled().has_value())\n\t{\n\t\tGetWxGUIConfig().fullscreen = state;\n\t\tg_wxConfig.Save();\n\t}\n\tif (state && !m_game_launched)\n\t\treturn;\n\tg_window_info.is_fullscreen = state;\n\tm_fullscreenMenuItem->Check(state);\n\n\tthis->ShowFullScreen(state);\n\n\tif (state)\n\t\tm_menu_visible = false; // menu gets always disabled by wxFULLSCREEN_NOMENUBAR\n\telse\n\t\tSetMenuVisible(true);\n}\n\nvoid MainWindow::EndEmulation() // unfinished - memory leaks and crashes after repeated use (after 3x usually)\n{\n\tCafeSystem::ShutdownTitle();\n\tDestroyCanvas();\n\tm_game_launched = false;\n\tm_launched_game_name.clear();\n\t#ifdef ENABLE_DISCORD_RPC\n\tif (m_discord)\n\t\tm_discord->UpdatePresence(DiscordPresence::Idling, \"\");\n\t#endif\n\n\tif (GetConfig().disable_screensaver)\n\t\tScreenSaver::SetInhibit(false);\n\n\t// close memory searcher if created\n\tif (m_toolWindow)\n\t{\n\t\tm_toolWindow->Close();\n\t\tm_toolWindow = nullptr;\n\t\tm_memorySearcherMenuItem->Enable(false);\n\t}\n\n\tRecreateMenu();\n\tCreateGameListAndStatusBar();\n\tDoLayout();\n\tUpdateChildWindowTitleRunningState();\n}\n\nvoid MainWindow::SetMenuVisible(bool state)\n{\n\tif (m_menu_visible == state)\n\t\treturn;\n\n\tSetMenuBar(state ? m_menuBar : nullptr);\n\tm_menu_visible = state;\n}\n\nvoid MainWindow::UpdateNFCMenu()\n{\n\tif (m_nfcMenuSeparator0)\n\t{\n\t\tm_nfcMenu->Remove(m_nfcMenuSeparator0->GetId());\n\t\tm_nfcMenuSeparator0 = nullptr;\n\t}\n\t// remove recent files list\n\tfor (sint32 i = 0; i < wxCemuConfig::kMaxRecentEntries; i++)\n\t{\n\t\tif (m_nfcMenu->FindChildItem(MAINFRAME_MENU_ID_NFC_RECENT_0 + i) == nullptr)\n\t\t\tcontinue;\n\t\tm_nfcMenu->Remove(MAINFRAME_MENU_ID_NFC_RECENT_0 + i);\n\t}\n\t// add entries\n\tconst auto& config = GetWxGUIConfig();\n\tsint32 recentFileIndex = 0;\n\tfor (size_t i = 0; i < config.recent_nfc_files.size(); i++)\n\t{\n\t\tconst auto& entry = config.recent_nfc_files[i];\n\t\tif (entry.empty())\n\t\t\tcontinue;\n\n\t\tif (!fs::exists(_utf8ToPath(entry)))\n\t\t\tcontinue;\n\n\t\tif (recentFileIndex == 0)\n\t\t\tm_nfcMenuSeparator0 = m_nfcMenu->AppendSeparator();\n\n\t\tm_nfcMenu->Append(MAINFRAME_MENU_ID_NFC_RECENT_0 + i, formatWxString(\"{}. {}\", recentFileIndex, entry));\n\n\t\trecentFileIndex++;\n\t\tif (recentFileIndex >= 12)\n\t\t\tbreak;\n\t}\n}\n\nbool MainWindow::IsMenuHidden() const\n{\n\treturn m_menu_visible;\n}\n\nvoid MainWindow::OnTimer(wxTimerEvent& event)\n{\n\tif(m_update_available.valid() && future_is_ready(m_update_available))\n\t{\n\t\tif(m_update_available.get())\n\t\t{\n\t\t\twxMessageDialog dialog(this, _(\"There's a new update available.\\nDo you want to update?\"), _(\"Update notification\"), wxCENTRE | wxYES_NO);\n\t\t\tif(dialog.ShowModal() == wxID_YES)\n\t\t\t{\n\t\t\t\tCemuUpdateWindow update_window(this);\n\t\t\t\tupdate_window.ShowModal();\n\t\t\t}\n\t\t}\n\n\t\tm_update_available = {};\n\t}\n\n\tif (!IsFullScreen() || m_menu_visible)\n\t\treturn;\n\n\tconst auto mouse_position = wxGetMousePosition();\n\tif(m_mouse_position != mouse_position)\n\t{\n\t\tm_last_mouse_move_time = std::chrono::steady_clock::now();\n\t\tm_mouse_position = mouse_position;\n\t\tShowCursor(true);\n\t\treturn;\n\t}\n\n\tauto diff = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_last_mouse_move_time);\n\tif (diff.count() > 3000)\n\t{\n\t\tShowCursor(false);\n\t}\n\n}\n\n#define BUILD_DATE __DATE__ \" \" __TIME__\n\nclass CemuAboutDialog : public wxDialog\n{\npublic:\n\tCemuAboutDialog(wxWindow* parent = NULL)\n\t\t: wxDialog(NULL, wxID_ANY, _(\"About Cemu\"), wxDefaultPosition, wxSize(500, 700))\n\t{\n\t\tCreate(parent);\n\t}\n\n\tvoid Create(wxWindow* parent = NULL)\n\t{\n\t\tSetIcon(wxICON(M_WND_ICON128));\n\n\t\twxScrolledWindow* scrolledWindow = new wxScrolledWindow(this);\n\n\t\twxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);\n\n\t\tm_scrolledSizer = new wxBoxSizer(wxVERTICAL);\n\n\t\tAddHeaderInfo(scrolledWindow, m_scrolledSizer);\n\t\tm_scrolledSizer->AddSpacer(5);\n\t\tAddLibInfo(scrolledWindow, m_scrolledSizer);\n\t\tm_scrolledSizer->AddSpacer(5);\n\t\tAddThanks(scrolledWindow, m_scrolledSizer);\n\n\t\tscrolledWindow->SetSizer(m_scrolledSizer);\n\t\tscrolledWindow->FitInside();\n\t\tscrolledWindow->SetScrollRate(25, 25);\n\t\tmainSizer->Add(scrolledWindow, wxSizerFlags(1).Expand().Border(wxLEFT, 10));\n\n\t\tSetSizer(mainSizer);\n\t\tCentreOnParent();\n\t}\n\n\tvoid AddHeaderInfo(wxWindow* parent, wxSizer* sizer)\n\t{\n\t\tauto versionString = formatWxString(_(\"Cemu\\nVersion {0}\\nCompiled on {1}\\nOriginal authors: {2}\"), BUILD_VERSION_STRING, BUILD_DATE, \"Exzap, Petergov\");\n\n\t\tsizer->Add(new wxStaticText(parent, wxID_ANY, versionString), wxSizerFlags().Border(wxALL, 3).Border(wxTOP, 10));\n\t\tsizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://cemu.info\", \"https://cemu.info\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)), wxSizerFlags().Expand().Border(wxTOP | wxBOTTOM, 3));\n\n\t\tsizer->AddSpacer(3);\n\t\tsizer->Add(new wxStaticLine(parent), wxSizerFlags().Expand().Border(wxRIGHT, 4));\n\t\tsizer->AddSpacer(5);\n\n\t\twxString extraInfo(_(\"Cemu is a Wii U emulator.\\n\\nWii and Wii U are trademarks of Nintendo.\\nCemu is not affiliated with Nintendo.\"));\n\t\tsizer->Add(new wxStaticText(parent, wxID_ANY, extraInfo), wxSizerFlags());\n\t}\n\n\tvoid AddLibInfo(wxWindow* parent, wxSizer* sizer)\n\t{\n\t\tsizer->AddSpacer(3);\n\t\tsizer->Add(new wxStaticLine(parent), wxSizerFlags().Expand().Border(wxRIGHT, 4));\n\t\tsizer->AddSpacer(3);\n\n\t\tsizer->Add(new wxStaticText(parent, wxID_ANY, _(\"Used libraries and utilities:\")), wxSizerFlags().Expand().Border(wxTOP | wxBOTTOM, 2));\n\t\t// zLib\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"zLib (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://www.zlib.net\", \"https://www.zlib.net\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t\t// wxWidgets\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"wxWidgets (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://www.wxwidgets.org/\", \"https://www.wxwidgets.org/\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t\t// OpenSSL\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"OpenSSL (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://www.openssl.org/\", \"https://www.openssl.org/\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t\t// libcurl\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"libcurl (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://curl.haxx.se/libcurl/\", \"https://curl.haxx.se/libcurl/\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t\t// imgui\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"imgui (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://github.com/ocornut/imgui\", \"https://github.com/ocornut/imgui\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t\t// fontawesome\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"fontawesome (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://github.com/FortAwesome/Font-Awesome\", \"https://github.com/FortAwesome/Font-Awesome\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t\t// boost\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"boost (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://www.boost.org\", \"https://www.boost.org\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t\t// libusb\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"libusb (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://libusb.info\", \"https://libusb.info\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n#if BOOST_OS_MACOS\n\t\t// MoltenVK\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, -1, \"MoltenVK (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, -1, \"https://github.com/KhronosGroup/MoltenVK\", \"https://github.com/KhronosGroup/MoltenVK\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, -1, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n#endif\n\t\t// icons\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"icons from \"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://icons8.com\", \"https://icons8.com\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t\t// Lato font (are we still using it?)\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"\\\"Lato\\\" font by tyPoland Lukasz Dziedzic (OFL, V1.1)\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t\t// SDL\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"SDL (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"https://github.com/libsdl-org/SDL\", \"https://github.com/libsdl-org/SDL\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t\t// IH264\n\t\t{\n\t\t\twxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \"Modified ih264 from Android project (\"));\n\t\t\tlineSizer->Add(new wxHyperlinkCtrl(parent, wxID_ANY, \"Source\", \"https://cemu.info/oss/ih264d.zip\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT)));\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \" \"));\n\t\t\twxHyperlinkCtrl* noticeLink = new wxHyperlinkCtrl(parent, wxID_ANY, \"NOTICE\", \"\", wxDefaultPosition, wxDefaultSize, (wxHL_CONTEXTMENU|wxNO_BORDER|wxHL_ALIGN_LEFT));\n\t\t\tnoticeLink->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent& event)\n\t\t\t\t{\n\t\t\t\t\tfs::path tempPath = fs::temp_directory_path();\n\t\t\t\t\ttempPath.append(\"NOTICE_IH264.txt\");\n\t\t\t\t\tFileStream* fs = FileStream::createFile2(tempPath);\n\t\t\t\t\tif (!fs)\n\t\t\t\t\t\treturn;\n\t\t\t\t\tfs->writeString(\n\t\t\t\t\t\t\"/******************************************************************************\\r\\n\"\n\t\t\t\t\t\t\" *\\r\\n\"\n\t\t\t\t\t\t\" * Copyright (C) 2015 The Android Open Source Project\\r\\n\"\n\t\t\t\t\t\t\" *\\r\\n\"\n\t\t\t\t\t\t\" * Licensed under the Apache License, Version 2.0 (the \\\"License\\\");\\r\\n\"\n\t\t\t\t\t\t\" * you may not use this file except in compliance with the License.\\r\\n\"\n\t\t\t\t\t\t\" * You may obtain a copy of the License at:\"\n\t\t\t\t\t\t\" *\\r\\n\"\n\t\t\t\t\t\t\" * http://www.apache.org/licenses/LICENSE-2.0\\r\\n\"\n\t\t\t\t\t\t\" *\\r\\n\"\n\t\t\t\t\t\t\" * Unless required by applicable law or agreed to in writing, software\\r\\n\"\n\t\t\t\t\t\t\" * distributed under the License is distributed on an \\\"AS IS\\\" BASIS,\\r\\n\"\n\t\t\t\t\t\t\" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\\r\\n\"\n\t\t\t\t\t\t\" * See the License for the specific language governing permissions and\\r\\n\"\n\t\t\t\t\t\t\" * limitations under the License.\\r\\n\"\n\t\t\t\t\t\t\" *\\r\\n\"\n\t\t\t\t\t\t\" *****************************************************************************\\r\\n\"\n\t\t\t\t\t\t\" * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\\r\\n\"\n\t\t\t\t\t\t\"*/\\r\\n\"\n\t\t\t\t\t\t\"/*****************************************************************************/\\r\\n\"\n\t\t\t\t\t);\n\t\t\t\t\tdelete fs;\n\t\t\t\t\twxLaunchDefaultBrowser(formatWxString(\"file:{}\", _pathToUtf8(tempPath)));\n\t\t\t\t});\n\t\t\tlineSizer->Add(noticeLink);\n\t\t\tlineSizer->Add(new wxStaticText(parent, wxID_ANY, \")\"));\n\t\t\tsizer->Add(lineSizer);\n\t\t}\n\t}\n\n\tvoid AddThanks(wxWindow* parent, wxSizer* sizer)\n\t{\n\t\tsizer->AddSpacer(3);\n\t\tsizer->Add(new wxStaticLine(parent), wxSizerFlags().Expand().Border(wxRIGHT, 4));\n\t\tsizer->AddSpacer(3);\n\n\t\twxGridSizer* gridSizer = new wxGridSizer(1, 2, 0, 0);\n\n\t\tsizer->AddSpacer(2);\n\n\t\tsizer->Add(new wxStaticText(parent, wxID_ANY, _(\"Thanks to our Patreon supporters:\")), wxSizerFlags().Expand().Border(wxTOP | wxBOTTOM, 2));\n\n\t\tstd::vector<const char*> patreonSupporterNames{ \"Maufeat\", \"lvlv\", \"F34R\", \"John Godgames\", \"Jameel Lewis\", \"skooks\", \"Cheesy\", \"Barrowsx\", \"Mored1984\", \"madmat007\"\n\t\t\t, \"Kuhnnl\", \"Owen M\", \"lucianobugalu\", \"KimoMaka\", \"nick palma aka renaissance18\", \"TheGiantBros\", \"SpiGAndromeda\"\n\t\t\t, \"Chimech0\", \"Nicolás Pino\", \"Pezzatti\", \"Barry Wallace\", \"REGNR8 Productions\", \"Lagia\", \"Freestyler316\", \"Dentora\"\n\t\t\t, \"tactics\", \"Merola.C\", \"Ceigyx\", \"Mata\", \"BobSchneeder45\", \"fenixDG\", \"jjalapeno55\", \"FissionMetroid101\", \"Jetta88\"\n\t\t\t, \"nesxdie\", \"Mikah\", \"PornfoxVR.com\", \"Hunter4everosa\", \"Bbzx\", \"Salim Sanehi\", \"FalloutpunkX\", \"NashOH-CL\", \"RaheemWala\"\n\t\t\t, \"Faris Leonhart\", \"MahvZero\", \"PlaguedGuardian\", \"Stuffie\", \"CaptainLester\", \"Qtech\", \"Zaurexus\", \"Leonidas\", \"Artifesto\"\n\t\t\t, \"Alca259\", \"SirWestofAsh\", \"Loli Co.\", \"The Technical Revolutionary\", \"MegaYama\", \"mitori\", \"Seymordius\", \"Adrian Josh Cruz\", \"Manuel Hoenings\", \"Just A Jabb\"\n\t\t\t, \"pgantonio\", \"CannonXIII\", \"Lonewolf00708\", \"AlexsDesign.com\", \"NoskLo\", \"MrSirHaku\", \"xElite_V AKA William H. Johnson\", \"Zalnor\", \"Pig\", \"James \\\"SE4LS\\\"\", \"DairyOrange\", \"Horoko Lawrence\", \"bloodmc\", \"Officer Jenny\", \"Quasar\", \"Postposterous\", \"Jake Jackson\", \"Kaydax\", \"CthePredatorG\"\n\t\t\t, \"Hengi\", \"Pyrochaser\", \"luma.x3\"};\n\n\t\twxString nameListLeft, nameListRight;\n\t\tfor (size_t i = 0; i < patreonSupporterNames.size(); i++)\n\t\t{\n\t\t\tconst char* name = patreonSupporterNames[i];\n\t\t\twxString& nameList = ((i % 2) == 0) ? nameListLeft : nameListRight;\n\t\t\tif (i >= 2)\n\t\t\t\tnameList.append(\"\\n\");\n\t\t\tnameList.append(wxString::FromUTF8(name));\n\t\t}\n\n\t\tgridSizer->Add(new wxStaticText(parent, wxID_ANY, nameListLeft), wxSizerFlags());\n\t\tgridSizer->Add(new wxStaticText(parent, wxID_ANY, nameListRight), wxSizerFlags());\n\n\t\tsizer->AddSpacer(4);\n\n\t\tsizer->Add(gridSizer, 1, wxEXPAND);\n\n\t\tsizer->AddSpacer(2);\n\t\tsizer->Add(new wxStaticText(parent, wxID_ANY, _(\"Special thanks:\")), wxSizerFlags().Expand().Border(wxTOP, 2));\n\t\tsizer->Add(new wxStaticText(parent, wxID_ANY, \"espes - Also try XQEMU!\\nWaltzz92\"), wxSizerFlags().Expand().Border(wxTOP, 1));\n\t}\n\nprotected:\n\twxSizer* m_scrolledSizer;\n};\n\nvoid MainWindow::OnHelpAbout(wxCommandEvent& event)\n{\n\tCemuAboutDialog dlgAbout(this);\n\tdlgAbout.ShowModal();\n}\n\nvoid MainWindow::OnHelpUpdate(wxCommandEvent& event)\n{\n\tCemuUpdateWindow test(this);\n\ttest.ShowModal();\n}\n\nvoid MainWindow::RecreateMenu()\n{\n\tif (m_menuBar)\n\t{\n\t\tSetMenuBar(nullptr);\n\t\tm_menuBar->Destroy();\n\t\tm_menuBar = nullptr;\n\t}\n\n\tauto& guiConfig = GetWxGUIConfig();\n\n\tm_menuBar = new wxMenuBar();\n\t// file submenu\n\tm_fileMenu = new wxMenu();\n\n\tif (!m_game_launched)\n\t{\n\t\tm_loadMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_LOAD, _(\"&Load...\"));\n\t\tm_installUpdateMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, _(\"&Install game title, update or DLC...\"));\n\n\t\twxMenu* recentMenu = new wxMenu();\n\t\tsint32 recentFileIndex = 1;\n\t\tm_fileMenuSeparator0 = nullptr;\n\t\tm_fileMenuSeparator1 = nullptr;\n\t\tfor (size_t i = 0; i < guiConfig.recent_launch_files.size(); i++)\n\t\t{\n\t\t\tconst std::string& pathStr = guiConfig.recent_launch_files[i];\n\t\t\tif (pathStr.empty())\n\t\t\t\tcontinue;\n\t\t\trecentMenu->Append(MAINFRAME_MENU_ID_FILE_RECENT_0 + i, formatWxString(\"{}. {}\", recentFileIndex, pathStr));\n\t\t\trecentFileIndex++;\n\n\t\t\tif (recentFileIndex >= 10)\n\t\t\t\tbreak;\n\t\t}\n\t\tif (recentFileIndex == 0)\n\t\t{\n\t\t\twxMenuItem* placeholder = recentMenu->Append(wxID_NONE, _(\"(No recent files)\"));\n\t\t\tplaceholder->Enable(false);\n\t\t}\n\n\t\tm_fileMenu->AppendSeparator();\n\t\tm_fileMenu->AppendSubMenu(recentMenu, _(\"Recent files\"));\n\t\tm_fileMenu->AppendSeparator();\n\t}\n\telse\n\t{\n#ifdef CEMU_DEBUG_ASSERT\n\t\tm_fileMenu->Append(MAINFRAME_MENU_ID_FILE_END_EMULATION, _(\"Close game\"));\n\t\tm_fileMenuSeparator1 = m_fileMenu->AppendSeparator();\n#endif\n\t}\n\n\tm_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, _(\"Open Cemu folder\"));\n\tm_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_MLC_FOLDER, _(\"Open MLC folder\"));\n\tm_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_SHADERCACHE_FOLDER, _(\"Open &shader cache folder\"));\n\tm_fileMenu->AppendSeparator();\n\tm_fileMenu->Append(MAINFRAME_MENU_ID_FILE_CLEAR_SPOTPASS_CACHE, _(\"Clear Spot&Pass cache\"));\n\tif (m_game_launched)\n\t\tm_fileMenu->Enable(MAINFRAME_MENU_ID_FILE_CLEAR_SPOTPASS_CACHE, false);\n\tm_fileMenu->AppendSeparator();\n\tm_exitMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_EXIT, _(\"&Exit\"));\n\tm_menuBar->Append(m_fileMenu, _(\"&File\"));\n\t// options->account submenu\n\tm_optionsAccountMenu = new wxMenu();\n\tconst auto account_id = ActiveSettings::GetPersistentId();\n\tint index = 0;\n\tfor(const auto& account : Account::GetAccounts())\n\t{\n\t\twxMenuItem* item = m_optionsAccountMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1 + index, account.ToString());\n\t\titem->Check(account_id == account.GetPersistentId());\n\t\tif (m_game_launched || LaunchSettings::GetPersistentId().has_value())\n\t\t\titem->Enable(false);\n\n\t\t++index;\n\t}\n\n\tauto& config = GetConfig();\n\tauto& wxConfig = GetWxGUIConfig();\n\t// options->console language submenu\n\twxMenu* optionsConsoleLanguageMenu = new wxMenu();\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ENGLISH, _(\"&English\"))->Check(config.console_language == CafeConsoleLanguage::EN);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_JAPANESE, _(\"&Japanese\"))->Check(config.console_language == CafeConsoleLanguage::JA);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_FRENCH, _(\"&French\"))->Check(config.console_language == CafeConsoleLanguage::FR);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_GERMAN, _(\"&German\"))->Check(config.console_language == CafeConsoleLanguage::DE);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ITALIAN, _(\"&Italian\"))->Check(config.console_language == CafeConsoleLanguage::IT);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_SPANISH, _(\"&Spanish\"))->Check(config.console_language == CafeConsoleLanguage::ES);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_CHINESE, _(\"&Chinese\"))->Check(config.console_language == CafeConsoleLanguage::ZH);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_KOREAN, _(\"&Korean\"))->Check(config.console_language == CafeConsoleLanguage::KO);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_DUTCH, _(\"&Dutch\"))->Check(config.console_language == CafeConsoleLanguage::NL);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_PORTUGUESE, _(\"&Portuguese\"))->Check(config.console_language == CafeConsoleLanguage::PT);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_RUSSIAN, _(\"&Russian\"))->Check(config.console_language == CafeConsoleLanguage::RU);\n\toptionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE, _(\"&Taiwanese\"))->Check(config.console_language == CafeConsoleLanguage::TW);\n\tif(IsGameLaunched())\n\t{\n\t\tauto items = optionsConsoleLanguageMenu->GetMenuItems();\n\t\tfor (auto& item : items)\n\t\t{\n\t\t\titem->Enable(false);\n\t\t}\n\t}\n\n\t// options submenu\n\twxMenu* optionsMenu = new wxMenu();\n\tm_fullscreenMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN, _(\"&Fullscreen\"));\n\tm_fullscreenMenuItem->Check(FullscreenEnabled());\n\n\toptionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2, _(\"&Graphic packs\"));\n\tm_padViewMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW, _(\"&Separate GamePad view\"));\n\tm_padViewMenuItem->Check(wxConfig.pad_open);\n\toptionsMenu->AppendSeparator();\n\t#if BOOST_OS_MACOS\n\toptionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_MAC_SETTINGS, _(\"&Settings...\" \"\\tCtrl-,\"));\n\t#endif\n\toptionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_GENERAL2, _(\"&General settings\"));\n\toptionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_INPUT, _(\"&Input settings\"));\n\toptionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_HOTKEY, _(\"&Hotkey settings\"));\n\n\toptionsMenu->AppendSeparator();\n\toptionsMenu->AppendSubMenu(m_optionsAccountMenu, _(\"&Active account\"));\n\toptionsMenu->AppendSubMenu(optionsConsoleLanguageMenu, _(\"&Console language\"));\n\tm_menuBar->Append(optionsMenu, _(\"&Options\"));\n\n\t// tools submenu\n\twxMenu* toolsMenu = new wxMenu();\n\tm_memorySearcherMenuItem = toolsMenu->Append(MAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER, _(\"&Memory searcher\"));\n\tm_memorySearcherMenuItem->Enable(false);\n\ttoolsMenu->Append(MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER, _(\"&Title Manager\"));\n\ttoolsMenu->Append(MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER, _(\"&Download Manager\"));\n\ttoolsMenu->Append(MAINFRAME_MENU_ID_TOOLS_EMULATED_USB_DEVICES, _(\"&Emulated USB Devices\"));\n\n\tm_menuBar->Append(toolsMenu, _(\"&Tools\"));\n\n\t// cpu timer speed menu\n\twxMenu* timerSpeedMenu = new wxMenu();\n\ttimerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_1X, _(\"&1x speed\"))->Check(ActiveSettings::GetTimerShiftFactor() == 3);\n\ttimerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_2X, _(\"&2x speed\"))->Check(ActiveSettings::GetTimerShiftFactor() == 2);\n\ttimerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_4X, _(\"&4x speed\"))->Check(ActiveSettings::GetTimerShiftFactor() == 1);\n\ttimerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_8X, _(\"&8x speed\"))->Check(ActiveSettings::GetTimerShiftFactor() == 0);\n\ttimerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_05X, _(\"&0.5x speed\"))->Check(ActiveSettings::GetTimerShiftFactor() == 4);\n\ttimerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_025X, _(\"&0.25x speed\"))->Check(ActiveSettings::GetTimerShiftFactor() == 5);\n\ttimerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_0125X, _(\"&0.125x speed\"))->Check(ActiveSettings::GetTimerShiftFactor() == 6);\n\n\t// cpu submenu\n\twxMenu* cpuMenu = new wxMenu();\n\tcpuMenu->AppendSubMenu(timerSpeedMenu, _(\"&Timer speed\"));\n\tm_menuBar->Append(cpuMenu, _(\"&CPU\"));\n\n\t// nfc submenu\n\twxMenu* nfcMenu = new wxMenu();\n\tm_nfcMenu = nfcMenu;\n\tnfcMenu->Append(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, _(\"&Scan NFC tag/amiibo from file\"))->Enable(false);\n\tm_menuBar->Append(nfcMenu, _(\"&NFC\"));\n\tm_nfcMenuSeparator0 = nullptr;\n\t// debug->logging submenu\n\twxMenu* debugLoggingMenu = new wxMenu();\n\n\tdebugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::UnsupportedAPI), _(\"&Unsupported API calls\"))->Check(cemuLog_isLoggingEnabled(LogType::UnsupportedAPI));\n\tdebugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::APIErrors), _(\"&Invalid API usage\"))->Check(cemuLog_isLoggingEnabled(LogType::APIErrors));\n\tdebugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitLogging), _(\"&Coreinit Logging (OSReport/OSConsole)\"))->Check(cemuLog_isLoggingEnabled(LogType::CoreinitLogging));\n\tdebugLoggingMenu->AppendSeparator();\n\n\twxMenu* logCosModulesMenu = new wxMenu();\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING_MESSAGE, _(\"&Options below are for experts. Leave off if unsure\"))->Enable(false);\n\tlogCosModulesMenu->AppendSeparator();\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitFile), _(\"coreinit File-Access API\"))->Check(cemuLog_isLoggingEnabled(LogType::CoreinitFile));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitThreadSync), _(\"coreinit Thread-Synchronization API\"))->Check(cemuLog_isLoggingEnabled(LogType::CoreinitThreadSync));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMem), _(\"coreinit Memory API\"))->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMem));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMP), _(\"coreinit MP API\"))->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMP));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitThread), _(\"coreinit Thread API\"))->Check(cemuLog_isLoggingEnabled(LogType::CoreinitThread));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Save), _(\"nn_save API\"))->Check(cemuLog_isLoggingEnabled(LogType::Save));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_NFP), _(\"nn_nfp API\"))->Check(cemuLog_isLoggingEnabled(LogType::NN_NFP));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_FP), _(\"nn_fp API\"))->Check(cemuLog_isLoggingEnabled(LogType::NN_FP));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::PRUDP), _(\"nn_fp PRUDP\"))->Check(cemuLog_isLoggingEnabled(LogType::PRUDP));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_BOSS), _(\"nn_boss API\"))->Check(cemuLog_isLoggingEnabled(LogType::NN_BOSS));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NFC), _(\"nfc API\"))->Check(cemuLog_isLoggingEnabled(LogType::NFC));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NTAG), _(\"ntag API\"))->Check(cemuLog_isLoggingEnabled(LogType::NTAG));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Socket), _(\"nsysnet API\"))->Check(cemuLog_isLoggingEnabled(LogType::Socket));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::H264), _(\"h264 API\"))->Check(cemuLog_isLoggingEnabled(LogType::H264));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::GX2), _(\"gx2 API\"))->Check(cemuLog_isLoggingEnabled(LogType::GX2));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::SoundAPI), _(\"Audio API\"))->Check(cemuLog_isLoggingEnabled(LogType::SoundAPI));\n\tlogCosModulesMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::InputAPI), _(\"Input API\"))->Check(cemuLog_isLoggingEnabled(LogType::InputAPI));\n\n\tdebugLoggingMenu->AppendSubMenu(logCosModulesMenu, _(\"&CafeOS modules logging\"));\n\tdebugLoggingMenu->AppendSeparator();\n\tdebugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Patches), _(\"&Graphic pack patches\"))->Check(cemuLog_isLoggingEnabled(LogType::Patches));\n\tdebugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::TextureCache), _(\"&Texture cache warnings\"))->Check(cemuLog_isLoggingEnabled(LogType::TextureCache));\n\tdebugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::TextureReadback), _(\"&Texture readback\"))->Check(cemuLog_isLoggingEnabled(LogType::TextureReadback));\n\tdebugLoggingMenu->AppendSeparator();\n\tdebugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::OpenGLLogging), _(\"&OpenGL debug output\"))->Check(cemuLog_isLoggingEnabled(LogType::OpenGLLogging));\n\tdebugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::VulkanValidation), _(\"&Vulkan validation layer (slow)\"))->Check(cemuLog_isLoggingEnabled(LogType::VulkanValidation));\n\tdebugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, _(\"&Log PPC context for API\"))->Check(cemuLog_advancedPPCLoggingEnabled());\n\tm_loggingSubmenu = debugLoggingMenu;\n\t// debug->dump submenu\n\twxMenu* debugDumpMenu = new wxMenu;\n\tdebugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES, _(\"&Textures\"))->Check(ActiveSettings::DumpTexturesEnabled());\n\tdebugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS, _(\"&Shaders\"))->Check(ActiveSettings::DumpShadersEnabled());\n\tdebugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_RECOMPILER_FUNCTIONS, _(\"&Recompiled functions\"))->Check(ActiveSettings::DumpRecompilerFunctionsEnabled());\n\tdebugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, _(\"&nlibcurl HTTP/HTTPS requests\"));\n\t// debug submenu\n\twxMenu* debugMenu = new wxMenu();\n\tm_debugMenu = debugMenu;\n\tdebugMenu->AppendSubMenu(debugLoggingMenu, _(\"&Logging\"));\n\tdebugMenu->AppendSubMenu(debugDumpMenu, _(\"&Dump\"));\n\tdebugMenu->AppendSeparator();\n\n\tauto upsidedownItem = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, _(\"&Render upside-down\"));\n\tupsidedownItem->Check(ActiveSettings::RenderUpsideDownEnabled());\n\tif(LaunchSettings::RenderUpsideDownEnabled().has_value())\n\t\tupsidedownItem->Enable(false);\n\n\tauto accurateBarriers = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS, _(\"&Accurate barriers (Vulkan)\"));\n\taccurateBarriers->Check(GetConfig().vk_accurate_barriers);\n\n#if ENABLE_METAL\n\tauto gpuCapture = debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE, _(\"&GPU capture (Metal)\"));\n\tgpuCapture->Enable(m_game_launched && g_renderer->GetType() == RendererAPI::Metal);\n#endif\n\n\tdebugMenu->AppendSeparator();\n\n#ifdef CEMU_DEBUG_ASSERT\n\tauto audioAuxOnly = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY, _(\"&Audio AUX only\"));\n\taudioAuxOnly->Check(ActiveSettings::AudioOutputOnlyAux());\n#endif\n\n\tdebugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW, _(\"&Open logging window\"));\n\tm_gdbstub_toggle = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_TOGGLE_GDB_STUB, _(\"&Launch with GDB stub\"));\n\tm_gdbstub_toggle->Check(g_gdbstub != nullptr);\n\tm_gdbstub_toggle->Enable(!m_game_launched);\n\n\tdebugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_THREADS, _(\"&View PPC threads\"));\n\tdebugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_DEBUGGER, _(\"&View PPC debugger\"));\n\tdebugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_AUDIO_DEBUGGER, _(\"&View audio debugger\"));\n\tdebugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_TEXTURE_RELATIONS, _(\"&View texture cache info\"));\n\tdebugMenu->Append(MAINFRAME_MENU_ID_DEBUG_DUMP_RAM, _(\"&Dump current RAM\"));\n\t// debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_DUMP_FST, _(\"&Dump WUD filesystem\"))->Enable(false);\n\n\tm_menuBar->Append(debugMenu, _(\"&Debug\"));\n\t// help menu\n\twxMenu* helpMenu = new wxMenu();\n\tm_check_update_menu = helpMenu->Append(MAINFRAME_MENU_ID_HELP_UPDATE, _(\"&Check for updates\"));\n#if BOOST_OS_LINUX\n\tif (!std::getenv(\"APPIMAGE\")) {\n\t\tm_check_update_menu->Enable(false);\n\t}\n#elif BOOST_OS_BSD // BSD users must update from source so disable update checks\n\tm_check_update_menu->Enable(false);\n#endif\n\thelpMenu->AppendSeparator();\n\thelpMenu->Append(MAINFRAME_MENU_ID_HELP_ABOUT, _(\"&About Cemu\"));\n\n\tm_menuBar->Append(helpMenu, _(\"&Help\"));\n\n\tSetMenuBar(m_menuBar);\n\tm_menu_visible = true;\n\n\tif (m_game_launched)\n\t{\n\t\tif (m_check_update_menu)\n\t\t\tm_check_update_menu->Enable(false);\n\n\t\tm_memorySearcherMenuItem->Enable(true);\n\t\tm_nfcMenu->Enable(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, true);\n\n\t\t// these options cant be toggled after the renderer backend is initialized:\n\t\tm_loggingSubmenu->Enable(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::OpenGLLogging), false);\n\t\tm_loggingSubmenu->Enable(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::VulkanValidation), false);\n\n\t\tUpdateNFCMenu();\n\t}\n\n\t// hide new menu in fullscreen\n\tif (IsFullScreen())\n\t\tSetMenuVisible(false);\n}\n\nvoid MainWindow::UpdateChildWindowTitleRunningState()\n{\n\tconst bool running = CafeSystem::IsTitleRunning();\n\n\tif(m_graphic_pack_window)\n\t\tm_graphic_pack_window->UpdateTitleRunning(running);\n}\n\nvoid MainWindow::RestoreSettingsAfterGameExited()\n{\n\tRecreateMenu();\n}\n\nvoid MainWindow::UpdateSettingsAfterGameLaunch()\n{\n\tm_update_available = {};\n\tRecreateMenu();\n}\n\nvoid MainWindow::OnGraphicWindowClose(wxCloseEvent& event)\n{\n\tm_graphic_pack_window->Destroy();\n\tm_graphic_pack_window = nullptr;\n}\n\nvoid MainWindow::OnGraphicWindowOpen(wxTitleIdEvent& event)\n{\n\tif (m_graphic_pack_window)\n\t\treturn;\n\tm_graphic_pack_window = new GraphicPacksWindow2(this, event.GetTitleId());\n\tm_graphic_pack_window->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnGraphicWindowClose, this);\n\tm_graphic_pack_window->Show(true);\n}\n\nvoid MainWindow::RequestGameListRefresh()\n{\n\tauto* evt = new wxCommandEvent(wxEVT_REQUEST_GAMELIST_REFRESH);\n\twxQueueEvent(g_mainFrame, evt);\n}\n\nvoid MainWindow::RequestLaunchGame(fs::path filePath, wxLaunchGameEvent::INITIATED_BY initiatedBy)\n{\n\twxLaunchGameEvent evt(filePath, initiatedBy);\n\twxPostEvent(g_mainFrame, evt);\n}\n\nvoid MainWindow::OnRequestRecreateCanvas(wxCommandEvent& event)\n{\n\tCounterSemaphore* sem = (CounterSemaphore*)event.GetClientData();\n\tDestroyCanvas();\n\tCreateCanvas();\n\tsem->increment();\n}\n\nvoid MainWindow::CafeRecreateCanvas()\n{\n\tCounterSemaphore sem;\n\tauto* evt = new wxCommandEvent(wxEVT_REQUEST_RECREATE_CANVAS);\n\tevt->SetClientData((void*)&sem);\n\twxQueueEvent(g_mainFrame, evt);\n\tsem.decrementWithWait();\n}\n\nbool MainWindow::FullscreenEnabled() const\n{\n\treturn LaunchSettings::FullscreenEnabled().value_or(GetWxGUIConfig().fullscreen);\n}\n"
  },
  {
    "path": "src/gui/wxgui/MainWindow.h",
    "content": "#pragma once\n\n#include <wx/wx.h>\n#include <wx/dataview.h>\n#include <wx/infobar.h>\n\n#include \"wxgui/PadViewFrame.h\"\n#include \"wxgui/MemorySearcherTool.h\"\n\n#include \"config/XMLConfig.h\"\n\n#include \"wxgui/LoggingWindow.h\"\n#include \"wxgui/components/wxGameList.h\"\n\n#include <future>\n#include \"Cafe/HW/Espresso/Debugger/GDBStub.h\"\n#include \"Cafe/CafeSystem.h\"\n\nclass DebuggerWindow2;\nstruct GameEntry;\nclass DiscordPresence;\nclass TitleManager;\nclass GraphicPacksWindow2;\nclass EmulatedUSBDeviceFrame;\nclass wxLaunchGameEvent;\n\nwxDECLARE_EVENT(wxEVT_LAUNCH_GAME, wxLaunchGameEvent);\nwxDECLARE_EVENT(wxEVT_SET_WINDOW_TITLE, wxCommandEvent);\n\nclass wxLaunchGameEvent : public wxCommandEvent\n{\npublic:\n\tenum class INITIATED_BY\n\t{\n\t\tMENU, // via file menu\n\t\tDRAG_AND_DROP,\n\t\tGAME_LIST,\n\t\tTITLE_MANAGER,\n\t\tCOMMAND_LINE, // -g parameter\n\t};\n\n\twxLaunchGameEvent(fs::path path, INITIATED_BY initiatedBy)\n\t\t: wxCommandEvent(wxEVT_LAUNCH_GAME), m_launchPath(path), m_initiatedBy(initiatedBy) {}\n\n\t[[nodiscard]] fs::path GetPath() const { return m_launchPath; }\n\t[[nodiscard]] INITIATED_BY GetInitiatedBy() const { return m_initiatedBy; }\n\n\twxEvent* Clone() const { return new wxLaunchGameEvent(*this); }\n\nprivate:\n\tfs::path m_launchPath;\n\tINITIATED_BY m_initiatedBy;\n};\n\nclass MainWindow : public wxFrame, public CafeSystem::SystemImplementation\n{\n\tfriend class CemuApp;\n\npublic:\n\tMainWindow();\n\t~MainWindow();\n\n    void CreateGameListAndStatusBar();\n    void DestroyGameListAndStatusBar();\n\n\tvoid UpdateSettingsAfterGameLaunch();\n\tvoid RestoreSettingsAfterGameExited();\n\n\tbool FileLoad(const fs::path launchPath, wxLaunchGameEvent::INITIATED_BY initiatedBy);\n\n\t[[nodiscard]] bool IsGameLaunched() const { return m_game_launched; }\n\n\tvoid SetFullScreen(bool state);\n\tvoid EndEmulation();\n\tvoid SetMenuVisible(bool state);\n\tvoid UpdateNFCMenu();\n\tbool IsMenuHidden() const;\n\tvoid TogglePadView();\n\n#if BOOST_OS_WINDOWS\n\tWXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;\n#endif\n\tvoid OpenSettings();\n\n\tPadViewFrame* GetPadView() const { return m_padView; }\n\n\tvoid OnSizeEvent(wxSizeEvent& event);\n\tvoid OnDPIChangedEvent(wxDPIChangedEvent& event);\n\tvoid OnMove(wxMoveEvent& event);\n\n\tvoid OnDebuggerClose(wxCloseEvent& event);\n\tvoid OnPadClose(wxCloseEvent& event);\n\tvoid OnMemorySearcherClose(wxCloseEvent& event);\n\tvoid OnMouseWheel(wxMouseEvent& event);\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid OnFileMenu(wxCommandEvent& event);\n\tvoid OnOpenFolder(wxCommandEvent& event);\n\tvoid OnClearSpotPassCache(wxCommandEvent& event);\n\tvoid OnLaunchFromFile(wxLaunchGameEvent& event);\n\tvoid OnInstallUpdate(wxCommandEvent& event);\n\tvoid OnFileExit(wxCommandEvent& event);\n\tvoid OnNFCMenu(wxCommandEvent& event);\n\tvoid OnOptionsInput(wxCommandEvent& event);\n\tvoid OnAccountSelect(wxCommandEvent& event);\n\tvoid OnConsoleLanguage(wxCommandEvent& event);\n\tvoid OnHelpAbout(wxCommandEvent& event);\n\tvoid OnHelpUpdate(wxCommandEvent& event);\n\tvoid OnDebugSetting(wxCommandEvent& event);\n\tvoid OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event);\n\tvoid OnPPCInfoToggle(wxCommandEvent& event);\n\tvoid OnDebugDumpGeneric(wxCommandEvent& event);\n\tvoid OnLoggingWindow(wxCommandEvent& event);\n\tvoid OnGDBStubToggle(wxCommandEvent& event);\n\tvoid OnDebugViewPPCThreads(wxCommandEvent& event);\n\tvoid OnDebugViewPPCDebugger(wxCommandEvent& event);\n\tvoid OnDebugViewAudioDebugger(wxCommandEvent& event);\n\tvoid OnDebugViewTextureRelations(wxCommandEvent& event);\n\tvoid OnMouseMove(wxMouseEvent& event);\n\tvoid OnMouseLeft(wxMouseEvent& event);\n\tvoid OnMouseRight(wxMouseEvent& event);\n\tvoid OnGameListBeginUpdate(wxCommandEvent& event);\n\tvoid OnGameListEndUpdate(wxCommandEvent& event);\n\tvoid OnAccountListRefresh(wxCommandEvent& event);\n\tvoid OnRequestGameListRefresh(wxCommandEvent& event);\n\tvoid OnSetWindowTitle(wxCommandEvent& event);\n\n\tvoid OnKeyUp(wxKeyEvent& event);\n\tvoid OnKeyDown(wxKeyEvent& event);\n\tvoid OnChar(wxKeyEvent& event);\n\n\tvoid OnToolsInput(wxCommandEvent& event);\n\tvoid OnGesturePan(wxPanGestureEvent& event);\n\n\tvoid OnGameLoaded();\n\n\tvoid AsyncSetTitle(std::string_view windowTitle);\n\n\tvoid CreateCanvas();\n\tvoid DestroyCanvas();\n\n\tstatic void ShowCursor(bool state);\n\n\tuintptr_t GetRenderCanvasHWND();\n\n\tstatic void RequestGameListRefresh();\n\tstatic void RequestLaunchGame(fs::path filePath, wxLaunchGameEvent::INITIATED_BY initiatedBy);\n\nprivate:\n\tbool FullscreenEnabled() const;\n\tvoid RecreateMenu();\n\tvoid UpdateChildWindowTitleRunningState();\n\tstatic wxString GetInitialWindowTitle();\n\n\tbool InstallUpdate(const fs::path& metaFilePath);\n\n\tvoid OnTimer(wxTimerEvent& event);\n\n\t// CafeSystem implementation\n\tvoid CafeRecreateCanvas() override;\n\n\tvoid OnRequestRecreateCanvas(wxCommandEvent& event);\n\n\twxRect GetDesktopRect();\n\n\tMemorySearcherTool* m_toolWindow = nullptr;\n\tTitleManager* m_title_manager = nullptr;\n\tEmulatedUSBDeviceFrame* m_usb_devices = nullptr;\n\tPadViewFrame* m_padView = nullptr;\n\tGraphicPacksWindow2* m_graphic_pack_window = nullptr;\n\n\twxTimer* m_timer;\n\twxPoint m_mouse_position{};\n\tstd::chrono::steady_clock::time_point m_last_mouse_move_time;\n\twxSize m_restored_size;\n\twxPoint m_restored_position;\n\n\tbool m_menu_visible = false;\n\tbool m_game_launched = false;\n\n\t#ifdef ENABLE_DISCORD_RPC\n\tstd::unique_ptr<DiscordPresence> m_discord;\n\t#endif\n\n\tstd::string m_launched_game_name;\n\n\twxMenuItem* m_gdbstub_toggle{};\n\tDebuggerWindow2* m_debugger_window = nullptr;\n\tLoggingWindow* m_logging_window = nullptr;\n\n\tstd::future<bool> m_update_available;\n\n\twxMenuItem* m_check_update_menu{};\n\tvoid LoadSettings();\n\tvoid SaveSettings();\n\n\tvoid OnGraphicWindowClose(wxCloseEvent& event);\n\tvoid OnGraphicWindowOpen(wxTitleIdEvent& event);\n\n\t// panels\n\twxPanel* m_main_panel{}, * m_game_panel{};\n\n\t// rendering\n\twxWindow* m_render_canvas{};\n\n\t// gamelist\n\twxGameList* m_game_list{};\n\twxInfoBar* m_info_bar{};\n\n\t// menu\n\twxMenuBar* m_menuBar{};\n\n\t// file\n\twxMenu* m_fileMenu{};\n\twxMenuItem* m_fileMenuSeparator0{};\n\twxMenuItem* m_fileMenuSeparator1{};\n\twxMenuItem* m_loadMenuItem{};\n\twxMenuItem* m_installUpdateMenuItem{};\n\twxMenuItem* m_exitMenuItem{};\n\n\t// options\n\twxMenu* m_optionsAccountMenu{};\n\n\twxMenuItem* m_fullscreenMenuItem{};\n\twxMenuItem* m_padViewMenuItem{};\n\n\t// tools\n\twxMenuItem* m_memorySearcherMenuItem{};\n\n\t// cpu\n\twxMenu* m_cpuTimerSubmenu{};\n\n\t// nfc\n\twxMenu* m_nfcMenu{};\n\twxMenuItem* m_nfcMenuSeparator0{};\n\n\t// debug\n\twxMenu* m_debugMenu{};\n\twxMenu* m_loggingSubmenu{};\n\twxMenuItem* m_asyncCompile{};\n\nwxDECLARE_EVENT_TABLE();\n};\n\nextern MainWindow* g_mainFrame;\n"
  },
  {
    "path": "src/gui/wxgui/MemorySearcherTool.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n\n#include \"wxgui/MemorySearcherTool.h\"\n\n#include <vector>\n#include <sstream>\n#include <thread>\n#include <wx/listctrl.h>\n\n#include \"config/ActiveSettings.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"Common/FileStream.h\"\n#include \"util/IniParser/IniParser.h\"\n#include \"util/helpers/StringHelpers.h\"\n#include \"Cafe/CafeSystem.h\"\n\nenum\n{\n\tCOMBOBOX_DATATYPE = wxID_HIGHEST + 1,\n\tTEXT_VALUE,\n\tBUTTON_START,\n\tBUTTON_FILTER,\n\tLIST_RESULTS,\n\tLIST_ENTRYTABLE,\n\tTIMER_REFRESH,\n\tLIST_ENTRY_ADD,\n\tLIST_ENTRY_REMOVE,\n};\n\nwxDEFINE_EVENT(wxEVT_SEARCH_FINISHED, wxCommandEvent);\n\nwxBEGIN_EVENT_TABLE(MemorySearcherTool, wxFrame)\nEVT_CLOSE(MemorySearcherTool::OnClose)\nEVT_BUTTON(BUTTON_START, MemorySearcherTool::OnSearch)\nEVT_BUTTON(BUTTON_FILTER, MemorySearcherTool::OnFilter)\nEVT_TIMER(TIMER_REFRESH, MemorySearcherTool::OnTimerTick)\nwxEND_EVENT_TABLE()\n\nconstexpr auto kMaxResultCount = 5000;\n\nconst wxString kDatatypeFloat = \"float\";\nconst wxString kDatatypeDouble = \"double\";\nconst wxString kDatatypeString = \"string\";\nconst wxString kDatatypeInt8 = \"int8\";\nconst wxString kDatatypeInt16 = \"int16\";\nconst wxString kDatatypeInt32 = \"int32\";\nconst wxString kDatatypeInt64 = \"int64\";\nconst wxString kDataTypeNames[] = {kDatatypeFloat,kDatatypeDouble,/*DATATYPE_STRING,*/kDatatypeInt8,kDatatypeInt16,kDatatypeInt32,kDatatypeInt64};\n\nMemorySearcherTool::MemorySearcherTool(wxFrame* parent)\n\t: wxFrame(parent, wxID_ANY, _(\"Memory Searcher\"), wxDefaultPosition, wxSize(600, 540), wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL)\n{\n\tthis->SetSizeHints(wxDefaultSize, wxDefaultSize);\n\tthis->wxTopLevelWindowBase::SetMinSize(wxSize(600, 540));\n\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tauto* row1 = new wxFlexGridSizer(0, 4, 0, 0);\n\trow1->AddGrowableCol(1);\n\n\tm_cbDataType = new wxComboBox(this, COMBOBOX_DATATYPE, kDatatypeFloat, wxDefaultPosition, wxDefaultSize, std::size(kDataTypeNames), kDataTypeNames, wxCB_READONLY);\n\tm_textValue = new wxTextCtrl(this, TEXT_VALUE);\n\tm_buttonStart = new wxButton(this, BUTTON_START, _(\"Search\"));\n\tm_buttonFilter = new wxButton(this, BUTTON_FILTER, _(\"Filter\"));\n\tm_buttonFilter->Disable();\n\n\trow1->Add(m_cbDataType, 0, wxALL, 5);\n\trow1->Add(m_textValue, 0, wxALL | wxEXPAND, 5);\n\trow1->Add(m_buttonStart, 0, wxALL, 5);\n\trow1->Add(m_buttonFilter, 0, wxALL, 5);\n\n\tsizer->Add(row1, 0, wxEXPAND, 5);\n\n\tauto* row2 = new wxFlexGridSizer(0, 1, 0, 0);\n\trow2->AddGrowableCol(0);\n\n\tm_gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL);\n\tm_gauge->SetValue(0);\n\tm_gauge->Enable(false);\n\n\tm_textEntryTable = new wxStaticText(this, wxID_ANY, _(\"Results\"));\n\tm_listResults = new wxListView(this, LIST_RESULTS, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SORT_ASCENDING);\n\tm_listResults->Bind(wxEVT_LEFT_DCLICK, &MemorySearcherTool::OnResultListClick, this);\n\t{\n\t\twxListItem col0;\n\t\tcol0.SetId(0);\n\t\tcol0.SetText(_(\"Address\"));\n\t\tcol0.SetWidth(100);\n\t\tm_listResults->InsertColumn(0, col0);\n\t\twxListItem col1;\n\t\tcol1.SetId(1);\n\t\tcol1.SetText(_(\"Value\"));\n\t\tcol1.SetWidth(250);\n\t\tm_listResults->InsertColumn(1, col1);\n\t}\n\n\tauto textEntryTable = new wxStaticText(this, wxID_ANY, _(\"Stored Entries\"));\n\tm_listEntryTable = new wxDataViewListCtrl(this, LIST_ENTRYTABLE, wxDefaultPosition, wxSize(420, 200), wxDV_HORIZ_RULES);\n\tm_listEntryTable->Bind(wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, &MemorySearcherTool::OnEntryListRightClick, this);\n\tm_listEntryTable->Bind(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE, &MemorySearcherTool::OnItemEdited, this);\n\t{\n\t\tm_listEntryTable->AppendTextColumn(_(\"Description\"), wxDATAVIEW_CELL_EDITABLE, 150, wxALIGN_LEFT, wxDATAVIEW_COL_SORTABLE);\n\t\tm_listEntryTable->AppendTextColumn(_(\"Address\"), wxDATAVIEW_CELL_INERT, 100, wxALIGN_LEFT, wxDATAVIEW_COL_SORTABLE);\n\t\tm_listEntryTable->AppendTextColumn(_(\"Type\"));\n\t\tm_listEntryTable->AppendTextColumn(_(\"Value\"), wxDATAVIEW_CELL_EDITABLE);\n\t\tm_listEntryTable->AppendToggleColumn(_(\"Freeze\"), wxDATAVIEW_CELL_ACTIVATABLE, 50, wxALIGN_LEFT, 0);\n\t}\n\n\trow2->AddGrowableRow(3);\n\trow2->AddGrowableRow(5);\n\n\trow2->Add(m_gauge, 0, wxALL | wxEXPAND, 5);\n\trow2->Add(0, 10, 1, wxEXPAND, 5);\n\trow2->Add(m_textEntryTable, 0, wxALL, 5);\n\trow2->Add(m_listResults, 1, wxALL | wxEXPAND, 5);\n\trow2->Add(textEntryTable, 0, wxALL, 5);\n\trow2->Add(m_listEntryTable, 1, wxALL | wxEXPAND, 5);\n\n\tsizer->Add(row2, 1, wxEXPAND, 5);\n\n\t// load stored entries\n\tLoad();\n\n\tthis->Bind(wxEVT_SEARCH_FINISHED, &MemorySearcherTool::OnSearchFinished, this);\n\tthis->Bind(wxEVT_SET_GAUGE_VALUE, &MemorySearcherTool::OnUpdateGauge, this);\n\n\tm_refresh_timer = new wxTimer(this, TIMER_REFRESH);\n\tm_refresh_timer->Start(250);\n\t\n\tthis->SetSizer(sizer);\n\tthis->wxWindowBase::Layout();\n\n\tthis->Centre(wxBOTH);\n}\n\nMemorySearcherTool::~MemorySearcherTool()\n{\n\tm_refresh_timer->Stop();\n\t\n\tm_running = false;\n\tif (m_worker.joinable())\n\t\tm_worker.join();\n}\n\nvoid MemorySearcherTool::OnTimerTick(wxTimerEvent& event)\n{\n\tRefreshResultList();\n\tRefreshStashList();\n}\n\nvoid MemorySearcherTool::OnClose(wxCloseEvent& event)\n{\n\tSave();\n\tevent.Skip();\n}\n\nvoid MemorySearcherTool::OnSearchFinished(wxCommandEvent&)\n{\n\tFillResultList();\n\tm_search_running = false;\n\tm_buttonStart->Enable();\n\tm_buttonFilter->Enable();\n}\n\nvoid MemorySearcherTool::OnUpdateGauge(wxSetGaugeValue& event)\n{\n\tauto* gauge = event.GetGauge();\n\tconst auto value = event.GetValue();\n\tif (event.GetRange() != 0)\n\t{\n\t\tgauge->SetRange(event.GetRange());\n\t\tgauge->SetValue(value);\n\t\treturn;\n\t}\n\t\n\tdebug_printf(\"update gauge: %d + %d = %d (/%d)\\n\", gauge->GetValue(), value, gauge->GetValue() + value, gauge->GetRange());\n\tgauge->SetValue(gauge->GetValue() + value);\n}\n\nvoid MemorySearcherTool::OnSearch(wxCommandEvent&)\n{\n\tif (m_clear_state)\n\t{\n\t\tReset();\n\t\treturn;\n\t}\n\n\tif (m_search_running)\n\t\treturn;\n\n\tif (m_textValue->IsEmpty())\n\t\treturn;\n\n\tSetSearchDataType();\n\n\tif (!VerifySearchValue())\n\t{\n\t\twxMessageBox(_(\"Your entered value is not valid for the selected datatype.\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\tm_buttonStart->Disable();\n\tm_buttonFilter->Disable();\n\tm_cbDataType->Disable();\n\tm_buttonStart->SetLabelText(_(\"Clear\"));\n\tm_clear_state = true;\n\n\tif (m_worker.joinable())\n\t\tm_worker.join();\n\n\tm_worker = std::thread([this]()\n\t\t{\n\t\t\tm_search_jobs.clear();\n\t\t\tuint32 total_size = 0;\n\t\t\tfor (const auto& itr : memory_getMMURanges())\n\t\t\t{\n\t\t\t\tif (!m_running)\n\t\t\t\t\treturn;\n\n\t\t\t\tif (!itr->isMapped())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tvoid* ptr = itr->getPtr();\n\t\t\t\tconst uint32 size = itr->getSize();\n\n\t\t\t\ttotal_size += (size / kGaugeStep);\n\t\t\t\tm_search_jobs.emplace_back(std::async(std::launch::async, [this, ptr, size]() { return SearchValues(m_searchDataType, ptr, size); }));\n\t\t\t}\n\n\t\t\twxQueueEvent(this, new wxSetGaugeValue(0, total_size, m_gauge));\n\t\t\t\n\t\t\tListType_t tmp;\n\t\t\tfor (auto& it : m_search_jobs)\n\t\t\t{\n\t\t\t\tconst auto result = it.get();\n\t\t\t\ttmp.insert(tmp.end(), result.cbegin(), result.cend());\n\t\t\t}\n\t\t\n\t\t\tstd::unique_lock lock(m_mutex);\n\t\t\tm_searchBuffer.swap(tmp);\n\t\t\tlock.unlock();\n\t\t\t\n\t\t\twxQueueEvent(this, new wxCommandEvent(wxEVT_SEARCH_FINISHED));\n\t\t});\n}\n\nvoid MemorySearcherTool::OnFilter(wxCommandEvent& event)\n{\n\tm_buttonStart->Disable();\n\tm_buttonFilter->Disable();\n\n\tif (m_worker.joinable())\n\t\tm_worker.join();\n\n\tm_worker = std::thread([this]()\n\t\t{\n\t\t\tconst auto count = (uint32)m_searchBuffer.size();\n\t\t\twxQueueEvent(this, new wxSetGaugeValue(0, count, m_gauge));\n\t\t\n\t\t\tauto tmp = FilterValues(m_searchDataType);\n\n\t\t\tstd::unique_lock lock(m_mutex);\n\t\t\tm_searchBuffer.swap(tmp);\n\t\t\tlock.unlock();\n\n\t\t\twxQueueEvent(this, new wxCommandEvent(wxEVT_SEARCH_FINISHED));\n\t\t});\n\n\tm_gauge->SetValue(0);\n}\n\nvoid MemorySearcherTool::Load()\n{\n\tconst auto memorySearcherPath = ActiveSettings::GetUserDataPath(\"memorySearcher/{:016x}.ini\", CafeSystem::GetForegroundTitleId());\n\tauto memSearcherIniContents = FileStream::LoadIntoMemory(memorySearcherPath);\n\tif (!memSearcherIniContents)\n\t\treturn;\n\n\tIniParser iniParser(*memSearcherIniContents, _pathToUtf8(memorySearcherPath));\n\twhile (iniParser.NextSection())\n\t{\n\t\tauto option_description = iniParser.FindOption(\"description\");\n\t\tauto option_address = iniParser.FindOption(\"address\");\n\t\tauto option_type = iniParser.FindOption(\"type\");\n\t\tauto option_value = iniParser.FindOption(\"value\");\n\n\t\tif (!option_description || !option_address || !option_type || !option_value)\n\t\t\tcontinue;\n\n\t\ttry\n\t\t{\n\t\t\tconst auto addr = StringHelpers::ToInt64(*option_address);\n\t\t\tif (!IsAddressValid(addr))\n\t\t\t\tcontinue;\n\t\t}\n\t\tcatch (const std::invalid_argument&)\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\tbool found = false;\n\t\tfor (const auto& entry : kDataTypeNames)\n\t\t{\n\t\t\tif (boost::iequals(entry.ToStdString(), *option_type))\n\t\t\t{\n\t\t\t\tfound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!found && !boost::iequals(kDatatypeString.ToStdString(), *option_type))\n\t\t\tcontinue;\n\n\t\twxVector<wxVariant> data;\n\t\tdata.push_back(std::string(*option_description).c_str());\n\t\tdata.push_back(std::string(*option_address).c_str());\n\t\tdata.push_back(std::string(*option_type).c_str());\n\t\tdata.push_back(std::string(*option_value).c_str());\n\t\tdata.push_back(!option_value->empty());\n\t\tm_listEntryTable->AppendItem(data);\n\t}\n}\n\nvoid MemorySearcherTool::Save()\n{\n\tconst auto memorySearcherPath = ActiveSettings::GetUserDataPath(\"memorySearcher/{:016x}.ini\", CafeSystem::GetForegroundTitleId());\n\tFileStream* fs = FileStream::createFile2(memorySearcherPath);\n\tif (fs)\n\t{\n\t\tfor (int i = 0; i < m_listEntryTable->GetItemCount(); ++i)\n\t\t{\n\t\t\tfs->writeLine(\"[Entry]\");\n\n\t\t\tstd::string tmp = \"description=\" + m_listEntryTable->GetTextValue(i, 0).ToStdString();\n\t\t\tfs->writeLine(tmp.c_str());\n\n\t\t\ttmp = \"address=\" + m_listEntryTable->GetTextValue(i, 1).ToStdString();\n\t\t\tfs->writeLine(tmp.c_str());\n\n\t\t\ttmp = \"type=\" + m_listEntryTable->GetTextValue(i, 2).ToStdString();\n\t\t\tfs->writeLine(tmp.c_str());\n\n\t\t\t// only save value when FREEZE is active\n\t\t\tif (m_listEntryTable->GetToggleValue(i, 4))\n\t\t\t{\n\t\t\t\ttmp = \"value=\" + m_listEntryTable->GetTextValue(i, 3).ToStdString();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttmp = \"value=\";\n\t\t\t}\n\t\t\tfs->writeLine(tmp.c_str());\n\n\t\t\tfs->writeLine(\"\");\n\t\t}\n\t\tdelete fs;\n\t}\n}\n\nbool MemorySearcherTool::IsAddressValid(uint32 addr)\n{\n\tfor (const auto& itr : memory_getMMURanges())\n\t{\n\t\tif (!itr->isMapped())\n\t\t\tcontinue;\n\n\t\tvoid* ptr = itr->getPtr();\n\t\tconst uint32 size = itr->getSize();\n\n\t\tMEMPTR start((uint8*)ptr);\n\t\tMEMPTR end((uint8*)ptr + size);\n\t\tif (start.GetMPTR() <= addr && addr < end.GetMPTR())\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvoid MemorySearcherTool::OnEntryListRightClick(wxDataViewEvent& event)\n{\n\t//void *data = reinterpret_cast<void *>(event.GetItem().GetData());\n\twxMenu mnu;\n\t//mnu.SetClientData(data);\n\tmnu.Append(LIST_ENTRY_ADD, _(\"&Add new entry\"))->Enable(false);\n\tmnu.Append(LIST_ENTRY_REMOVE, _(\"&Remove entry\"));\n\tmnu.Bind(wxEVT_COMMAND_MENU_SELECTED, &MemorySearcherTool::OnPopupClick, this);\n\tPopupMenu(&mnu);\n}\n\nvoid MemorySearcherTool::OnResultListClick(wxMouseEvent& event)\n{\n\tfor (long selectedIndex = m_listResults->GetFirstSelected(); selectedIndex != wxNOT_FOUND; selectedIndex = m_listResults->GetNextSelected(selectedIndex))\n\t{\n\t\tlong address = m_listResults->GetItemData(selectedIndex);\n\t\tauto currValue = m_listResults->GetItemText(selectedIndex, 1);\n\n\t\twxString addressString = wxString::Format(\"0x%08lx\", address);\n\n\t\t// description, address, type, value, freeze\n\t\twxVector<wxVariant> data;\n\t\tdata.push_back(\"\");\n\t\tdata.push_back(addressString);\n\t\tdata.push_back(m_cbDataType->GetValue());\n\t\tdata.push_back(currValue);\n\t\tdata.push_back(false);\n\t\tm_listEntryTable->AppendItem(data);\n\t}\n}\n\nvoid MemorySearcherTool::Reset()\n{\n\tm_searchBuffer.clear();\n\tm_buttonStart->SetLabelText(_(\"Search\"));\n\tm_textEntryTable->SetLabelText(_(\"Results\"));\n\tm_buttonFilter->Disable();\n\tm_cbDataType->Enable();\n\tm_textValue->SetValue(\"\");\n\tm_listResults->DeleteAllItems();\n\tm_clear_state = false;\n}\n\nbool MemorySearcherTool::VerifySearchValue() const\n{\n\tconst auto inputString = m_textValue->GetValue().ToStdString();\n\n\tswitch (m_searchDataType)\n\t{\n\tcase SearchDataType_String:\n\t\treturn true;\n\tcase SearchDataType_Float:\n\t\t{\n\t\t\tfloat value;\n\t\t\treturn ConvertStringToType(inputString, value);\n\t\t}\n\tcase SearchDataType_Double:\n\t\t{\n\t\t\tdouble value;\n\t\t\treturn ConvertStringToType(inputString, value);\n\t\t}\n\tcase SearchDataType_Int8:\n\t\t{\n\t\t\tsint8 value;\n\t\t\treturn ConvertStringToType(inputString, value);\n\t\t}\n\tcase SearchDataType_Int16:\n\t\t{\n\t\t\tsint16 value;\n\t\t\treturn ConvertStringToType(inputString, value);\n\t\t}\n\tcase SearchDataType_Int32:\n\t\t{\n\t\t\tsint32 value;\n\t\t\treturn ConvertStringToType(inputString, value);\n\t\t}\n\tcase SearchDataType_Int64:\n\t\t{\n\t\t\tsint64 value;\n\t\t\treturn ConvertStringToType(inputString, value);\n\t\t}\n\tdefault:\n\t\treturn false;\n\t}\n}\n\nvoid MemorySearcherTool::FillResultList()\n{\n\tauto text = formatWxString(_(\"Results ({0})\"), m_searchBuffer.size());\n\tm_textEntryTable->SetLabelText(text);\n\n\tm_listResults->DeleteAllItems();\n\n\tif (m_searchBuffer.empty() || m_searchBuffer.size() > kMaxResultCount)\n\t\treturn;\n\n\tfor (const auto& address : m_searchBuffer)\n\t{\n\t\tconst auto index = m_listResults->InsertItem(0, fmt::format(\"{:#08x}\", address.GetMPTR()));\n\t\tm_listResults->SetItemData(index, address.GetMPTR());\n\t\tm_listResults->SetItem(index, 1, m_textValue->GetValue());\n\t}\n}\n\nvoid MemorySearcherTool::RefreshResultList()\n{\n\tstd::unique_lock lock(m_mutex);\n\tif (m_searchBuffer.empty() || m_searchBuffer.size() > kMaxResultCount)\n\t\treturn;\n\n\tfor (int i = 0; i < m_listResults->GetItemCount(); ++i)\n\t{\n\t\tconst auto addr = m_listResults->GetItemData(i);\n\t\tswitch (m_searchDataType)\n\t\t{\n\t\tcase SearchDataType_String:\n\t\t\t{\n\t\t\t\t// TODO Peter\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase SearchDataType_Float:\n\t\t\t{\n\t\t\tconst auto value = memory_read<float>(addr);\n\t\t\t\tm_listResults->SetItem(i, 1, fmt::format(\"{}\", value));\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase SearchDataType_Double:\n\t\t\t{\n\t\t\tconst auto value = memory_read<double>(addr);\n\t\t\t\tm_listResults->SetItem(i, 1, fmt::format(\"{}\", value));\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase SearchDataType_Int8:\n\t\t\t{\n\t\t\tconst auto value = memory_read<sint8>(addr);\n\t\t\t\tm_listResults->SetItem(i, 1, fmt::format(\"{}\", value));\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase SearchDataType_Int16:\n\t\t\t{\n\t\t\tconst auto value = memory_read<sint16>(addr);\n\t\t\t\tm_listResults->SetItem(i, 1, fmt::format(\"{}\", value));\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase SearchDataType_Int32:\n\t\t\t{\n\t\t\t\tconst auto value = memory_read<sint32>(addr);\n\t\t\t\tm_listResults->SetItem(i, 1, fmt::format(\"{}\", value));\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase SearchDataType_Int64:\n\t\t\t{\n\t\t\tconst auto value = memory_read<sint64>(addr);\n\t\t\t\tm_listResults->SetItem(i, 1, fmt::format(\"{}\", value));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid MemorySearcherTool::RefreshStashList()\n{\n\tfor (int i = 0; i < m_listEntryTable->GetItemCount(); ++i)\n\t{\n\t\tauto freeze = m_listEntryTable->GetToggleValue(i, 4);\n\n\t\tauto addressText = m_listEntryTable->GetTextValue(i, 1).ToStdString();\n\t\tauto type = m_listEntryTable->GetTextValue(i, 2);\n\n\t\tauto address = std::stol(addressText, nullptr, 16);\n\n\t\t// if freeze is activated, set the value instead of refreshing it\n\t\tif (freeze)\n\t\t{\n\t\t\twxVariant var;\n\t\t\tm_listEntryTable->GetValue(var, i, 3);\n\t\t\tif (type == kDatatypeFloat)\n\t\t\t{\n\t\t\t\tauto value = (float)var.GetDouble();\n\t\t\t\tmemory_writeFloat(address, value);\n\t\t\t}\n\t\t\telse if (type == kDatatypeDouble)\n\t\t\t{\n\t\t\t\tauto value = var.GetDouble();\n\t\t\t\tmemory_writeDouble(address, value);\n\t\t\t}\n\t\t\telse if (type == kDatatypeInt8)\n\t\t\t{\n\t\t\t\tauto value = var.GetInteger();\n\t\t\t\tmemory_writeU8(address, value);\n\t\t\t}\n\t\t\telse if (type == kDatatypeInt16)\n\t\t\t{\n\t\t\t\tauto value = var.GetInteger();\n\t\t\t\tmemory_writeU16(address, value);\n\t\t\t}\n\t\t\telse if (type == kDatatypeInt32)\n\t\t\t{\n\t\t\t\tauto value = var.GetInteger();\n\t\t\t\tmemory_writeU32(address, value);\n\t\t\t}\n\t\t\telse if (type == kDatatypeInt64)\n\t\t\t{\n\t\t\t\tauto valueText = var.GetString().ToStdString();\n\t\t\t\tauto value = std::stoull(valueText);\n\t\t\t\tmemory_writeU64(address, value);\n\t\t\t}\n\t\t\telse if (type == kDatatypeString)\n\t\t\t{\n\t\t\t\tauto valueText = var.GetString().ToStdString();\n\t\t\t\tfor (int i = 0; i < valueText.size(); ++i)\n\t\t\t\t{\n\t\t\t\t\tmemory_writeU8(address + i, valueText[i]);\n\t\t\t\t}\n\t\t\t\tmemory_writeU8(address + valueText.size(), 0x00);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (type == kDatatypeFloat)\n\t\t\t{\n\t\t\t\tauto value = memory_readFloat(address);\n\t\t\t\tm_listEntryTable->SetValue(fmt::format(\"{}\", value), i, 3);\n\t\t\t}\n\t\t\telse if (type == kDatatypeDouble)\n\t\t\t{\n\t\t\t\tauto value = memory_readDouble(address);\n\t\t\t\tm_listEntryTable->SetValue(fmt::format(\"{}\", value), i, 3);\n\t\t\t}\n\t\t\telse if (type == kDatatypeInt8)\n\t\t\t{\n\t\t\t\tauto value = (sint8)memory_readU8(address);\n\t\t\t\tm_listEntryTable->SetValue(fmt::format(\"{}\", (int)value), i, 3);\n\t\t\t}\n\t\t\telse if (type == kDatatypeInt16)\n\t\t\t{\n\t\t\t\tauto value = (sint16)memory_readU16(address);\n\t\t\t\tm_listEntryTable->SetValue(fmt::format(\"{}\", value), i, 3);\n\t\t\t}\n\t\t\telse if (type == kDatatypeInt32)\n\t\t\t{\n\t\t\t\tauto value = (sint32)memory_readU32(address);\n\t\t\t\tm_listEntryTable->SetValue(fmt::format(\"{}\", value), i, 3);\n\t\t\t}\n\t\t\telse if (type == kDatatypeInt64)\n\t\t\t{\n\t\t\t\tauto value = (sint64)memory_readU64(address);\n\t\t\t\tm_listEntryTable->SetValue(fmt::format(\"{}\", value), i, 3);\n\t\t\t}\n\t\t\telse if (type == kDatatypeString)\n\t\t\t{\n\t\t\t\t// TODO Peter\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid MemorySearcherTool::SetSearchDataType()\n{\n\tconst auto type = m_cbDataType->GetStringSelection();\n\tif (type == kDatatypeFloat)\n\t\tm_searchDataType = SearchDataType_Float;\n\telse if (type == kDatatypeDouble)\n\t\tm_searchDataType = SearchDataType_Double;\n\telse if (type == kDatatypeInt8)\n\t\tm_searchDataType = SearchDataType_Int8;\n\telse if (type == kDatatypeInt16)\n\t\tm_searchDataType = SearchDataType_Int16;\n\telse if (type == kDatatypeInt32)\n\t\tm_searchDataType = SearchDataType_Int32;\n\telse if (type == kDatatypeInt64)\n\t\tm_searchDataType = SearchDataType_Int64;\n\telse if (type == kDatatypeString)\n\t\tm_searchDataType = SearchDataType_String;\n\telse\n\t\tm_searchDataType = SearchDataType_None;\n}\n\ntemplate<>\nbool MemorySearcherTool::ConvertStringToType<signed char>(const std::string& inValue, sint8& outValue) const\n{\n\tsint16 tmp;\n\tstd::istringstream iss(inValue);\n\tiss >> std::noskipws >> tmp;\n\tif (iss && iss.eof())\n\t{\n\t\tif (SCHAR_MIN <= tmp && tmp <= SCHAR_MAX)\n\t\t{\n\t\t\toutValue = tmp;\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nvoid MemorySearcherTool::OnPopupClick(wxCommandEvent& event)\n{\n\tif (event.GetId() == LIST_ENTRY_REMOVE)\n\t{\n\t\tconst int row = m_listEntryTable->GetSelectedRow();\n\t\tif (row == wxNOT_FOUND)\n\t\t\treturn;\n\t\t\n\t\tm_listEntryTable->DeleteItem(row);\n\t}\n}\n\nvoid MemorySearcherTool::OnItemEdited(wxDataViewEvent& event)\n{\n\tauto column = event.GetColumn();\n\t// Edit description\n\tif (column == 0) { }\n\t\t// Edit value\n\telse if (column == 3)\n\t{\n\t\tauto row = m_listEntryTable->GetSelectedRow();\n\t\tif (row == wxNOT_FOUND)\n\t\t\treturn;\n\n\t\tauto addressText = m_listEntryTable->GetTextValue(row, 1).ToStdString();\n\t\tuint32 address = std::stoul(addressText, nullptr, 16);\n\n\t\tauto type = m_listEntryTable->GetTextValue(row, 2);\n\t\tif (type == kDatatypeFloat)\n\t\t{\n\t\t\tauto value = (float)event.GetValue().GetDouble();\n\t\t\tmemory_writeFloat(address, value);\n\t\t}\n\t\telse if (type == kDatatypeDouble)\n\t\t{\n\t\t\tauto value = event.GetValue().GetDouble();\n\t\t\tmemory_writeDouble(address, value);\n\t\t}\n\t\telse if (type == kDatatypeInt8)\n\t\t{\n\t\t\tauto value = event.GetValue().GetInteger();\n\t\t\tmemory_writeU8(address, value);\n\t\t}\n\t\telse if (type == kDatatypeInt16)\n\t\t{\n\t\t\tauto value = event.GetValue().GetInteger();\n\t\t\tmemory_writeU16(address, value);\n\t\t}\n\t\telse if (type == kDatatypeInt32)\n\t\t{\n\t\t\tauto value = event.GetValue().GetInteger();\n\t\t\tmemory_writeU32(address, value);\n\t\t}\n\t\telse if (type == kDatatypeInt64)\n\t\t{\n\t\t\tauto valueText = event.GetValue().GetString().ToStdString();\n\t\t\tauto value = std::stoull(valueText);\n\t\t\tmemory_writeU64(address, value);\n\t\t}\n\t\telse if (type == kDatatypeString)\n\t\t{\n\t\t\tauto valueText = event.GetValue().GetString().ToStdString();\n\t\t\tfor (int i = 0; i < valueText.size(); ++i)\n\t\t\t{\n\t\t\t\tmemory_writeU8(address + i, valueText[i]);\n\t\t\t}\n\t\t\tmemory_writeU8(address + valueText.size(), 0x00);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/MemorySearcherTool.h",
    "content": "#pragma once\n\n#include <mutex>\n#include <thread>\n#include <atomic>\n#include <future>\n\n#include <wx/listctrl.h>\n#include <wx/frame.h>\n\n#include \"Cafe/HW/MMU/MMU.h\"\n#include \"util/helpers/helpers.h\"\n#include \"wxgui/helpers/wxCustomEvents.h\"\n\nclass wxComboBox;\nclass wxDataViewEvent;\nclass wxDataViewListCtrl;\nclass wxStaticText;\nclass wxTimer;\nclass wxTimerEvent;\n\nenum SearchDataType\n{\n\tSearchDataType_None,\n\tSearchDataType_String,\n\tSearchDataType_Float,\n\tSearchDataType_Double,\n\tSearchDataType_Int8,\n\tSearchDataType_Int16,\n\tSearchDataType_Int32,\n\tSearchDataType_Int64,\n};\n\nstruct TableEntry_t\n{\n\tuint32 address;\n\tconst char description[32];\n\tSearchDataType type;\n\tbool freeze;\n\tuint16 dataLen;\n\tuint8* data;\n};\n\nclass MemorySearcherTool : public wxFrame\n{\npublic:\n\tMemorySearcherTool(wxFrame* parent);\n\tvirtual ~MemorySearcherTool();\n\n\tvoid OnTimerTick(wxTimerEvent& event);\n\tvoid OnClose(wxCloseEvent&);\n\tvoid OnSearch(wxCommandEvent&);\n\tvoid OnSearchFinished(wxCommandEvent& event);\n\tvoid OnUpdateGauge(wxSetGaugeValue& event);\n\tvoid OnFilter(wxCommandEvent& event);\n\tvoid OnResultListClick(wxMouseEvent& event);\n\tvoid OnEntryListRightClick(wxDataViewEvent& event);\n\t//void OnEntryListRightClick2(wxContextMenuEvent& event);\n\tvoid OnPopupClick(wxCommandEvent& event);\n\n\tvoid OnItemEdited(wxDataViewEvent& event);\n\nprivate:\n\tvoid Reset();\n\tbool VerifySearchValue() const;\n\tvoid FillResultList();\n\tvoid RefreshResultList();\n\tvoid RefreshStashList();\n\tvoid SetSearchDataType();\n\n\tvoid Load();\n\tvoid Save();\n\n\tstatic bool IsAddressValid(uint32 addr);\n\n\ttemplate<typename T>\n\tbool ConvertStringToType(const std::string& inValue, T& outValue) const\n\t{\n\t\tstd::istringstream iss(inValue);\n\t\tiss >> std::noskipws >> outValue;\n\t\treturn iss && iss.eof();\n\t}\n\t\n\tusing ListType_t = std::vector<MEMPTR<void>>;\n\tListType_t SearchValues(SearchDataType type, void* ptr, uint32 size)\n\t{\n\t\t/*if (type == SearchDataType_String)\n\t\t\treturn SearchValues((const char* )ptr, size);\n\t\telse */if (type == SearchDataType_Float)\n\t\t\treturn SearchValues((float*)ptr, size);\n\t\telse if (type == SearchDataType_Double)\n\t\t\treturn SearchValues((double*)ptr, size);\n\t\telse if (type == SearchDataType_Int8)\n\t\t\treturn SearchValues((sint8*)ptr, size);\n\t\telse if (type == SearchDataType_Int16)\n\t\t\treturn SearchValues((sint16*)ptr, size);\n\t\telse if (type == SearchDataType_Int32)\n\t\t\treturn SearchValues((sint32*)ptr, size);\n\t\telse if (type == SearchDataType_Int64)\n\t\t\treturn SearchValues((sint64*)ptr, size);\n\t\treturn {};\n\t}\n\t\n\tListType_t FilterValues(SearchDataType type)\n\t{\n\t\t/*if (type == SearchDataType_String)\n\t\t\treturn FilterValues<const char*>();\n\t\telse */if (type == SearchDataType_Float)\n\t\t\treturn FilterValues<float>();\n\t\telse if (type == SearchDataType_Double)\n\t\t\treturn FilterValues<double>();\n\t\telse if (type == SearchDataType_Int8)\n\t\t\treturn FilterValues<sint8>();\n\t\telse if (type == SearchDataType_Int16)\n\t\t\treturn FilterValues<sint16>();\n\t\telse if (type == SearchDataType_Int32)\n\t\t\treturn FilterValues<sint32>();\n\t\telse if (type == SearchDataType_Int64)\n\t\t\treturn FilterValues<sint64>();\n\t\treturn {};\n\t}\n\n\tconstexpr static int kGaugeStep = 0x10000;\n\n\ttemplate <typename T>\n\tListType_t SearchValues(T* ptr, uint32 size)\n\t{\n\t\tconst auto search_value = ConvertString<T>(m_textValue->GetValue().ToStdString());\n\n\t\tconst auto* end = (T*)((uint8*)ptr + size - sizeof(T));\n\n\t\tuint32 counter = 0;\n\t\tstd::vector<MEMPTR<void>> result;\n\t\tfor (; ptr < end; ++ptr)\n\t\t{\n\t\t\tif (!m_running)\n\t\t\t\treturn result;\n\n\t\t\tconst auto tmp = (betype<T>*)ptr;\n\t\t\tif (equals(search_value, tmp->value()))\n\t\t\t\tresult.emplace_back(ptr);\n\n\t\t\tcounter += sizeof(T);\n\t\t\tif(counter >= kGaugeStep)\n\t\t\t{\n\t\t\t\twxQueueEvent(this, new wxSetGaugeValue(1, m_gauge));\n\t\t\t\tcounter -= kGaugeStep;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\ttemplate <typename T>\n\tListType_t FilterValues()\n\t{\n\t\tconst auto search_value = ConvertString<T>(m_textValue->GetValue().ToStdString());\n\n\t\tListType_t newSearchBuffer;\n\t\tnewSearchBuffer.reserve(m_searchBuffer.size());\n\n\t\tfor (const auto& it : m_searchBuffer)\n\t\t{\n\t\t\tif (!m_running)\n\t\t\t\treturn newSearchBuffer;\n\n\t\t\tconst auto tmp = (betype<T>*)it.GetPtr();\n\t\t\tif (equals(search_value , tmp->value()))\n\t\t\t\tnewSearchBuffer.emplace_back(it);\n\t\t\t\n\t\t\twxQueueEvent(this, new wxSetGaugeValue(1, m_gauge));\n\t\t}\n\n\t\treturn newSearchBuffer;\n\t}\n\nwxDECLARE_EVENT_TABLE();\n\n\tSearchDataType m_searchDataType = SearchDataType_None;\n\twxComboBox* m_cbDataType;\n\twxTextCtrl* m_textValue;\n\twxButton *m_buttonStart, *m_buttonFilter;\n\twxListView* m_listResults;\n\twxDataViewListCtrl* m_listEntryTable;\n\twxStaticText* m_textEntryTable;\n\twxGauge* m_gauge;\n\twxTimer* m_refresh_timer;\n\n\tListType_t m_searchBuffer;\n\tstd::vector<TableEntry_t> m_tableEntries;\n\t\n\tstd::mutex m_mutex;\n\tstd::thread m_worker;\n\n\tstd::atomic_bool m_running = true;\n\tstd::atomic_bool m_search_running = false;\n\tstd::vector<std::future<ListType_t>> m_search_jobs;\n\n\tbool m_clear_state = false;\n};\n\ntemplate<>\nbool MemorySearcherTool::ConvertStringToType(const std::string& inValue, sint8& outValue) const;\n\n//\n//template <typename T>\n//void MemorySearcherTool::FilterValues()\n//{\n//\tauto s1 = m_textValue->GetValue();\n//\tauto s2 = s1.c_str();\n//\tauto stringValue = s2.AsChar();\n//\n//\tT filterValue;\n//\tConvertStringToType(stringValue, filterValue);\n//\n//\tstd::vector<uint32> newSearchBuffer;\n//\tnewSearchBuffer.reserve(m_searchBuffer.size());\n//\n//\tuint32 gaugeValue = 0;\n//\tuint32 count = m_searchBuffer.size();\n//\tuint32 counter = 0;\n//\n//\tfor (auto it = m_searchBuffer.begin(); it != m_searchBuffer.end(); ++it)\n//\t{\n//\t\tif (m_running)\n//\t\t\treturn;\n//\n//\t\tT value = memory_read<T>(*it);\n//\t\tif constexpr (std::is_same<T, float>::value)\n//\t\t{\n//\t\t\t//float value1 = filterValue * 0.95f;\n//\t\t\tfloat diff = filterValue - value;\n//\t\t\tdiff = fabs(diff);\n//\t\t\tif(diff < value*0.05f)\n//\t\t\t{\n//\t\t\t\tnewSearchBuffer.push_back(*it);\n//\t\t\t}\n//\n//\t\t}\n//\t\telse\n//\t\t{\n//\t\t\tif (value == filterValue)\n//\t\t\t{\n//\t\t\t\tnewSearchBuffer.push_back(*it);\n//\t\t\t}\n//\t\t}\n//\n//\t\t++counter;\n//\t\tuint32 newValue = counter * 100 / count;\n//\t\tif (newValue > gaugeValue + GAUGE_STEP_SIZE)\n//\t\t{\n//\t\t\tgaugeValue = newValue;\n//\t\t\tm_gaugeValue = newValue;\n//\t\t}\n//\t}\n//\n//\tm_mutex.lock();\n//\tm_searchBuffer = newSearchBuffer;\n//\tm_gaugeValue = 100;\n//\tm_mutex.unlock();\n//\tm_isSearchFinished = true;\n//}\n//\n\n"
  },
  {
    "path": "src/gui/wxgui/PadViewFrame.cpp",
    "content": "#include \"interface/WindowSystem.h\"\n#include \"wxgui/wxgui.h\"\n#include \"wxgui/PadViewFrame.h\"\n\n#include <wx/display.h>\n\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/OS/libs/swkbd/swkbd.h\"\n#include \"wxgui/canvas/OpenGLCanvas.h\"\n#include \"wxgui/canvas/VulkanCanvas.h\"\n#if ENABLE_METAL\n#include \"wxgui/canvas/MetalCanvas.h\"\n#endif\n#include \"config/CemuConfig.h\"\n#include \"wxgui/MainWindow.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"input/InputManager.h\"\n\n#if BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_BSD\n#include \"resource/embedded/resources.h\"\n#endif\n#include \"wxHelper.h\"\n\nextern WindowSystem::WindowInfo g_window_info;\n\n#define PAD_MIN_WIDTH  320\n#define PAD_MIN_HEIGHT 180\n\nPadViewFrame::PadViewFrame(wxFrame* parent)\n\t: wxFrame(nullptr, wxID_ANY, _(\"GamePad View\"), wxDefaultPosition, wxDefaultSize, wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxCLOSE_BOX | wxWANTS_CHARS)\n{\n\tg_window_info.window_pad = initHandleContextFromWxWidgetsWindow(this);\n\n\tSetIcon(wxICON(M_WND_ICON128));\n\twxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES);\n\n\tSetMinClientSize({ PAD_MIN_WIDTH, PAD_MIN_HEIGHT });\n\n\tSetPosition({ g_window_info.restored_pad_x, g_window_info.restored_pad_y });\n\tif (g_window_info.restored_pad_width >= PAD_MIN_WIDTH && g_window_info.restored_pad_height >= PAD_MIN_HEIGHT)\n\t\tSetClientSize({ g_window_info.restored_pad_width, g_window_info.restored_pad_height });\n\telse\n\t\tSetClientSize(wxSize(854, 480));\n\n\tif (g_window_info.pad_maximized)\n\t\tMaximize();\n\n\tBind(wxEVT_SIZE, &PadViewFrame::OnSizeEvent, this);\n\tBind(wxEVT_DPI_CHANGED, &PadViewFrame::OnDPIChangedEvent, this);\n\tBind(wxEVT_MOVE, &PadViewFrame::OnMoveEvent, this);\n\tBind(wxEVT_MOTION, &PadViewFrame::OnMouseMove, this);\n\n\tBind(wxEVT_SET_WINDOW_TITLE, &PadViewFrame::OnSetWindowTitle, this);\n\n\tg_window_info.pad_open = true;\n}\n\nPadViewFrame::~PadViewFrame()\n{\n\tg_window_info.pad_open = false;\n}\n\nbool PadViewFrame::Initialize()\n{\n\tconst wxSize client_size = GetClientSize();\n\tg_window_info.pad_width = client_size.GetWidth();\n\tg_window_info.pad_height = client_size.GetHeight();\n\tg_window_info.phys_pad_width = ToPhys(client_size.GetWidth());\n\tg_window_info.phys_pad_height = ToPhys(client_size.GetHeight());\n\n\treturn true;\n}\n\nvoid PadViewFrame::InitializeRenderCanvas()\n{\n\tauto sizer = new wxBoxSizer(wxVERTICAL);\n\t{\n\t\tif (ActiveSettings::GetGraphicsAPI() == kVulkan)\n\t\t\tm_render_canvas = new VulkanCanvas(this, wxSize(854, 480), false);\n\t\telse if (ActiveSettings::GetGraphicsAPI() == kOpenGL)\n\t\t\tm_render_canvas = GLCanvas_Create(this, wxSize(854, 480), false);\n#if ENABLE_METAL\n\t\telse\n\t\t    m_render_canvas = new MetalCanvas(this, wxSize(854, 480), false);\n#endif\n\t\tsizer->Add(m_render_canvas, 1, wxEXPAND, 0, nullptr);\n\t}\n\tSetSizer(sizer);\n\tLayout();\n\n\tm_render_canvas->Bind(wxEVT_KEY_UP, &PadViewFrame::OnKeyUp, this);\n\tm_render_canvas->Bind(wxEVT_CHAR, &PadViewFrame::OnChar, this);\n\n\tm_render_canvas->Bind(wxEVT_MOTION, &PadViewFrame::OnMouseMove, this);\n\tm_render_canvas->Bind(wxEVT_LEFT_DOWN, &PadViewFrame::OnMouseLeft, this);\n\tm_render_canvas->Bind(wxEVT_LEFT_UP, &PadViewFrame::OnMouseLeft, this);\n\tm_render_canvas->Bind(wxEVT_RIGHT_DOWN, &PadViewFrame::OnMouseRight, this);\n\tm_render_canvas->Bind(wxEVT_RIGHT_UP, &PadViewFrame::OnMouseRight, this);\n\n\tm_render_canvas->Bind(wxEVT_GESTURE_PAN, &PadViewFrame::OnGesturePan, this);\n\n\tm_render_canvas->SetFocus();\n\tSendSizeEvent();\n}\n\nvoid PadViewFrame::DestroyCanvas()\n{\n\tif(!m_render_canvas)\n\t\treturn;\n\tm_render_canvas->Destroy();\n\tm_render_canvas = nullptr;\n}\n\nvoid PadViewFrame::OnSizeEvent(wxSizeEvent& event)\n{\n\tif (!IsMaximized() && !IsFullScreen())\n\t{\n\t\tg_window_info.restored_pad_width = GetSize().x;\n\t\tg_window_info.restored_pad_height = GetSize().y;\n\t}\n\tg_window_info.pad_maximized = IsMaximized() && !IsFullScreen();\n\n\tconst wxSize client_size = GetClientSize();\n\tg_window_info.pad_width = client_size.GetWidth();\n\tg_window_info.pad_height = client_size.GetHeight();\n\tg_window_info.phys_pad_width = ToPhys(client_size.GetWidth());\n\tg_window_info.phys_pad_height = ToPhys(client_size.GetHeight());\n\tg_window_info.pad_dpi_scale = GetDPIScaleFactor();\n\n\tevent.Skip();\n}\n\nvoid PadViewFrame::OnDPIChangedEvent(wxDPIChangedEvent& event)\n{\n\tevent.Skip();\n\tconst wxSize client_size = GetClientSize();\n\tg_window_info.pad_width = client_size.GetWidth();\n\tg_window_info.pad_height = client_size.GetHeight();\n\tg_window_info.phys_pad_width = ToPhys(client_size.GetWidth());\n\tg_window_info.phys_pad_height = ToPhys(client_size.GetHeight());\n\tg_window_info.pad_dpi_scale = GetDPIScaleFactor();\n}\n\nvoid PadViewFrame::OnMoveEvent(wxMoveEvent& event)\n{\n\tif (!IsMaximized() && !IsFullScreen())\n\t{\n\t\tg_window_info.restored_pad_x = GetPosition().x;\n\t\tg_window_info.restored_pad_y = GetPosition().y;\n\t}\n}\n\nvoid PadViewFrame::OnKeyUp(wxKeyEvent& event)\n{\n\tevent.Skip();\n\n\tif (swkbd_hasKeyboardInputHook())\n\t\treturn;\n\n\tconst auto code = event.GetKeyCode();\n\tif (code == WXK_ESCAPE)\n\t\tShowFullScreen(false);\n\telse if (code == WXK_RETURN && event.AltDown() || code == WXK_F11)\n\t\tShowFullScreen(!IsFullScreen());\n}\n\nvoid PadViewFrame::OnGesturePan(wxPanGestureEvent& event)\n{\n\tauto& instance = InputManager::instance();\n\n\tstd::scoped_lock lock(instance.m_pad_touch.m_mutex);\n\tauto physPos = ToPhys(event.GetPosition());\n\tinstance.m_pad_touch.position = { physPos.x, physPos.y };\n\tinstance.m_pad_touch.left_down = event.IsGestureStart() || !event.IsGestureEnd();\n\tif (event.IsGestureStart() || !event.IsGestureEnd())\n\t\tinstance.m_pad_touch.left_down_toggle = true;\n}\n\nvoid PadViewFrame::OnChar(wxKeyEvent& event)\n{\n\tif (swkbd_hasKeyboardInputHook())\n\t\tswkbd_keyInput(event.GetUnicodeKey());\n\n\tevent.Skip();\n}\n\nvoid PadViewFrame::OnMouseMove(wxMouseEvent& event)\n{\n\tauto& instance = InputManager::instance();\n\n\tstd::scoped_lock lock(instance.m_pad_touch.m_mutex);\n\tauto physPos = ToPhys(event.GetPosition());\n\tinstance.m_pad_mouse.position = { physPos.x, physPos.y };\n\n\tevent.Skip();\n}\n\nvoid PadViewFrame::OnMouseLeft(wxMouseEvent& event)\n{\n\tauto& instance = InputManager::instance();\n\n\tstd::scoped_lock lock(instance.m_pad_mouse.m_mutex);\n\tinstance.m_pad_mouse.left_down = event.ButtonDown(wxMOUSE_BTN_LEFT);\n\tauto physPos = ToPhys(event.GetPosition());\n\tinstance.m_pad_mouse.position = { physPos.x, physPos.y };\n\tif (event.ButtonDown(wxMOUSE_BTN_LEFT))\n\t\tinstance.m_pad_mouse.left_down_toggle = true;\n\n}\n\nvoid PadViewFrame::OnMouseRight(wxMouseEvent& event)\n{\n\tauto& instance = InputManager::instance();\n\n\tstd::scoped_lock lock(instance.m_pad_mouse.m_mutex);\n\tinstance.m_pad_mouse.right_down = event.ButtonDown(wxMOUSE_BTN_LEFT);\n\tauto physPos = ToPhys(event.GetPosition());\n\tinstance.m_pad_mouse.position = { physPos.x, physPos.y };\n\tif (event.ButtonDown(wxMOUSE_BTN_RIGHT))\n\t\tinstance.m_pad_mouse.right_down_toggle = true;\n}\n\nvoid PadViewFrame::OnSetWindowTitle(wxCommandEvent& event)\n{\n\tthis->SetTitle(event.GetString());\n}\n\nvoid PadViewFrame::AsyncSetTitle(std::string_view windowTitle)\n{\n\twxCommandEvent set_title_event(wxEVT_SET_WINDOW_TITLE);\n\tset_title_event.SetString(wxString::FromUTF8(windowTitle));\n\tQueueEvent(set_title_event.Clone());\n}\n"
  },
  {
    "path": "src/gui/wxgui/PadViewFrame.h",
    "content": "#pragma once\n\n#include <wx/frame.h>\n\n#define WM_CREATE_PAD\t(WM_USER+1)\n#define WM_DESTROY_PAD\t(WM_USER+2)\n\nwxDECLARE_EVENT(EVT_PAD_CLOSE, wxCommandEvent);\nwxDECLARE_EVENT(EVT_SET_WINDOW_TITLE, wxCommandEvent);\n\nclass PadViewFrame : public wxFrame\n{\npublic:\n\tPadViewFrame(wxFrame* parent);\n\t~PadViewFrame();\n\n\tbool Initialize();\n\tvoid InitializeRenderCanvas();\n\tvoid DestroyCanvas();\n\n\tvoid OnKeyUp(wxKeyEvent& event);\n\tvoid OnChar(wxKeyEvent& event);\n\t\n\tvoid AsyncSetTitle(std::string_view windowTitle);\n\nprivate:\n\n\tvoid OnMouseMove(wxMouseEvent& event);\n\tvoid OnMouseLeft(wxMouseEvent& event);\n\tvoid OnMouseRight(wxMouseEvent& event);\n\tvoid OnSizeEvent(wxSizeEvent& event);\n\tvoid OnDPIChangedEvent(wxDPIChangedEvent& event);\n\tvoid OnMoveEvent(wxMoveEvent& event);\n\tvoid OnGesturePan(wxPanGestureEvent& event);\n\tvoid OnSetWindowTitle(wxCommandEvent& event);\n\n\twxWindow* m_render_canvas = nullptr;\n};\n"
  },
  {
    "path": "src/gui/wxgui/TitleManager.cpp",
    "content": "#include \"wxgui/TitleManager.h\"\n\n#include \"wxgui/helpers/wxCustomEvents.h\"\n#include \"wxgui/helpers/wxCustomData.h\"\n#include \"Cafe/TitleList/GameInfo.h\"\n#include \"util/helpers/helpers.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/wxHelper.h\"\n#include \"wxgui/components/wxTitleManagerList.h\"\n#include \"wxgui/components/wxDownloadManagerList.h\"\n#include \"wxgui/GameUpdateWindow.h\"\n#include \"wxgui/dialogs/SaveImport/SaveTransfer.h\"\n\n#include <wx/listbase.h>\n#include <wx/sizer.h>\n#include <wx/listctrl.h>\n#include <wx/statline.h>\n#include <wx/stattext.h>\n#include <wx/textctrl.h>\n#include <wx/statbmp.h>\n#include <wx/panel.h>\n#include <wx/bmpbuttn.h>\n#include <wx/choice.h>\n#include <wx/msgdlg.h>\n#include <wx/filedlg.h>\n#include <wx/combobox.h>\n#include <wx/checkbox.h>\n\n#include <pugixml.hpp>\n#include <zip.h>\n#include <wx/dirdlg.h>\n#include <wx/notebook.h>\n#include <wx/settings.h>\n\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n#include \"config/ActiveSettings.h\"\n#include \"wxgui/dialogs/SaveImport/SaveImportWindow.h\"\n#include \"Cafe/Account/Account.h\"\n#include \"Cemu/Tools/DownloadManager/DownloadManager.h\"\n#include \"wxgui/CemuApp.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n#include \"Cafe/TitleList/SaveList.h\"\n#include \"resource/embedded/resources.h\"\n\nwxDEFINE_EVENT(wxEVT_TITLE_FOUND, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_TITLE_SEARCH_COMPLETE, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_DL_TITLE_UPDATE, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_DL_DISCONNECT_COMPLETE, wxCommandEvent);\n\nwxPanel* TitleManager::CreateTitleManagerPage()\n{\n\tauto* panel = new wxPanel(m_notebook);\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\t{\n\t\tauto* row = new wxFlexGridSizer(0, 4, 0, 0);\n\t\trow->AddGrowableCol(1);\n\n\t\trow->Add(new wxStaticText(panel, wxID_ANY, _(\"Filter\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tm_filter = new wxTextCtrl(panel, wxID_ANY);\n\t\tm_filter->Bind(wxEVT_TEXT, &TitleManager::OnFilterChanged, this);\n\t\trow->Add(m_filter, 1, wxALL | wxEXPAND, 5);\n\n\t\tconst wxImage refresh = wxHelper::LoadThemedBitmapFromPNG(PNG_REFRESH_png, sizeof(PNG_REFRESH_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)).ConvertToImage();\n\t\tm_refresh_button = new wxBitmapButton(panel, wxID_ANY, refresh.Scale(16, 16));\n\t\tm_refresh_button->Disable();\n\t\tm_refresh_button->Bind(wxEVT_BUTTON, &TitleManager::OnRefreshButton, this);\n\t\tm_refresh_button->SetToolTip(_(\"Refresh\"));\n\t\trow->Add(m_refresh_button, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tconst wxBitmap help_bitmap = wxHelper::LoadThemedBitmapFromPNG(PNG_HELP_png, sizeof(PNG_HELP_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\tauto* help_button = new wxStaticBitmap(panel, wxID_ANY, help_bitmap);\n\t\thelp_button->SetToolTip(formatWxString(_(\"The following prefixes are supported:\\n{0}\\n{1}\\n{2}\\n{3}\\n{4}\"),\n\t\t\t\"titleid:\", \"name:\", \"type:\", \"version:\", \"region:\"));\n\t\trow->Add(help_button, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tsizer->Add(row, 0, wxEXPAND, 5);\n\t}\n\n\tsizer->Add(new wxStaticLine(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL), 0, wxEXPAND | wxALL, 5);\n\n\tm_title_list = new wxTitleManagerList(panel);\n\tm_title_list->SetSizeHints(800, 600);\n\tm_title_list->Bind(wxEVT_LIST_ITEM_SELECTED, &TitleManager::OnTitleSelected, this);\n\tsizer->Add(m_title_list, 1, wxALL | wxEXPAND, 5);\n\n\tsizer->Add(new wxStaticLine(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL), 0, wxEXPAND | wxALL, 5);\n\n\t{\n\t\tauto* row = new wxFlexGridSizer(0, 3, 0, 0);\n\t\trow->AddGrowableCol(2);\n\n\t\tauto* install_button = new wxButton(panel, wxID_ANY, _(\"Install title\"));\n\t\tinstall_button->Bind(wxEVT_BUTTON, &TitleManager::OnInstallTitle, this);\n\t\trow->Add(install_button, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\trow->Add(new wxStaticLine(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL), 0, wxEXPAND | wxALL, 5);\n\n\t\t{\n\t\t\tm_save_panel = new wxPanel(panel);\n\t\t\tauto* save_sizer = new wxFlexGridSizer(0, 7, 0, 0);\n\n\t\t\tsave_sizer->Add(new wxStaticText(m_save_panel, wxID_ANY, _(\"Account\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\tm_save_account_list = new wxChoice(m_save_panel, wxID_ANY);\n\t\t\tm_save_account_list->SetMinSize({ 170, -1 });\n\t\t\tm_save_account_list->Bind(wxEVT_CHOICE, &TitleManager::OnSaveAccountSelected, this);\n\t\t\tsave_sizer->Add(m_save_account_list, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\tauto* save_open = new wxButton(m_save_panel, wxID_ANY, _(\"Open directory\"));\n\t\t\tsave_open->Bind(wxEVT_BUTTON, &TitleManager::OnSaveOpenDirectory, this);\n\t\t\tsave_open->SetToolTip(_(\"Open the directory of the save entry\"));\n\t\t\tsave_open->Disable();\n\t\t\tsave_sizer->Add(save_open, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\tauto* save_transfer = new wxButton(m_save_panel, wxID_ANY, _(\"Transfer\"));\n\t\t\tsave_transfer->Bind(wxEVT_BUTTON, &TitleManager::OnSaveTransfer, this);\n\t\t\tsave_transfer->SetToolTip(_(\"Transfers the save entry to another persistent account id\"));\n\t\t\tsave_transfer->Disable();\n\t\t\tsave_sizer->Add(save_transfer, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\tauto* save_delete = new wxButton(m_save_panel, wxID_ANY, _(\"Delete\"));\n\t\t\tsave_delete->Bind(wxEVT_BUTTON, &TitleManager::OnSaveDelete, this);\n\t\t\tsave_delete->SetToolTip(_(\"Permanently delete the save entry\"));\n\t\t\tsave_delete->Disable();\n\t\t\tsave_sizer->Add(save_delete, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\t\tm_save_import = new wxButton(m_save_panel, wxID_ANY, _(\"Import\"));\n\t\t\tm_save_import->Bind(wxEVT_BUTTON, &TitleManager::OnSaveImport, this);\n\t\t\tm_save_import->SetToolTip(_(\"Imports a zipped save entry\"));\n\t\t\tsave_sizer->Add(m_save_import, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxTOP | wxBOTTOM, 5);\n\n\t\t\tauto* export_bttn = new wxButton(m_save_panel, wxID_ANY, _(\"Export\"));\n\t\t\texport_bttn->Bind(wxEVT_BUTTON, &TitleManager::OnSaveExport, this);\n\t\t\texport_bttn->SetToolTip(_(\"Exports the selected save entry as zip file\"));\n\t\t\texport_bttn->Disable();\n\t\t\tsave_sizer->Add(export_bttn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT | wxTOP | wxBOTTOM, 5);\n\n\t\t\tm_save_panel->SetSizerAndFit(save_sizer);\n\t\t\trow->Add(m_save_panel, 1, wxRESERVE_SPACE_EVEN_IF_HIDDEN | wxALIGN_CENTER_VERTICAL, 0);\n\t\t\tm_save_panel->Hide(); // hide by default\n\t\t}\n\n\t\tsizer->Add(row, 0, wxEXPAND, 5);\n\t}\n\n\tpanel->SetSizerAndFit(sizer);\n\treturn panel;\n}\n\nwxPanel* TitleManager::CreateDownloadManagerPage()\n{\n\tauto* panel = new wxPanel(m_notebook);\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\t{\n\t\tauto* row = new wxBoxSizer(wxHORIZONTAL);\n\n#if DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN\n\t\tm_account = new wxChoice(panel, wxID_ANY);\n\t\tm_account->SetMinSize({ 250,-1 });\n\t\tauto accounts = Account::GetAccounts();\n\t\tif (!accounts.empty())\n\t\t{\n\t\t\tconst auto id = GetConfig().account.m_persistent_id.GetValue();\n\t\t\tfor (const auto& a : accounts)\n\t\t\t{\n\t\t\t\tm_account->Append(a.ToString(), (void*)static_cast<uintptr_t>(a.GetPersistentId()));\n\t\t\t\tif(a.GetPersistentId() == id)\n\t\t\t\t{\n\t\t\t\t\tm_account->SetSelection(m_account->GetCount() - 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\n\t\trow->Add(m_account, 0, wxALL, 5);\n#endif\n\n\t\tm_connect = new wxButton(panel, wxID_ANY, _(\"Connect\"));\n\t\tm_connect->Bind(wxEVT_BUTTON, &TitleManager::OnConnect, this);\n\t\trow->Add(m_connect, 0, wxALL, 5);\n\n\t\tsizer->Add(row, 0, wxEXPAND, 5);\n\t}\n\n#if DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN\n\tm_status_text = new wxStaticText(panel, wxID_ANY, _(\"Select an account and press Connect\"));\n#else\n\tif(!NCrypto::HasDataForConsoleCert())\n\t{\n\t\tm_status_text = new wxStaticText(panel, wxID_ANY, _(\"Valid online files are required to download eShop titles. For more information, go to the Account tab in the General Settings.\"));\n\t\tm_connect->Enable(false);\n\t}\n\telse\n\t\tm_status_text = new wxStaticText(panel, wxID_ANY, _(\"Click on Connect to load the list of downloadable titles\"));\n#endif\n\tthis->Bind(wxEVT_SET_TEXT, &TitleManager::OnSetStatusText, this);\n\tsizer->Add(m_status_text, 0, wxALL, 5);\n\t\n\tsizer->Add(new wxStaticLine(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL), 0, wxEXPAND | wxALL, 5);\n\n\t{\n\t\tauto* row = new wxFlexGridSizer(0, 3, 0, 0);\n\t\tm_show_titles = new wxCheckBox(panel, wxID_ANY, _(\"Show available titles\"));\n\t\tm_show_titles->SetValue(true);\n\t\tm_show_titles->Enable(false);\n\t\trow->Add(m_show_titles, 0, wxALL, 5);\n\t\tm_show_titles->Bind(wxEVT_CHECKBOX, &TitleManager::OnDlFilterCheckbox, this);\n\n\t\tm_show_updates = new wxCheckBox(panel, wxID_ANY, _(\"Show available updates\"));\n\t\tm_show_updates->SetValue(true);\n\t\tm_show_updates->Enable(false);\n\t\trow->Add(m_show_updates, 0, wxALL, 5);\n\t\tm_show_updates->Bind(wxEVT_CHECKBOX, &TitleManager::OnDlFilterCheckbox, this);\n\n\t\tm_show_installed = new wxCheckBox(panel, wxID_ANY, _(\"Show installed\"));\n\t\tm_show_installed->SetValue(true);\n\t\tm_show_installed->Enable(false);\n\t\trow->Add(m_show_installed, 0, wxALL, 5);\n\t\tm_show_installed->Bind(wxEVT_CHECKBOX, &TitleManager::OnDlFilterCheckbox, this);\n\n\t\tsizer->Add(row, 0, wxEXPAND, 5);\n\t}\n\t\n\tm_download_list = new wxDownloadManagerList(panel);\n\tm_download_list->SetSizeHints(800, 600);\n\tm_download_list->Bind(wxEVT_LIST_ITEM_SELECTED, &TitleManager::OnTitleSelected, this);\n\tsizer->Add(m_download_list, 1, wxALL | wxEXPAND, 5);\n\n\tpanel->SetSizerAndFit(sizer);\n\treturn panel;\n}\n\nTitleManager::TitleManager(wxWindow* parent, TitleManagerPage default_page)\n\t: wxFrame(parent, wxID_ANY, _(\"Title Manager\"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL)\n{\n\tSetIcon(wxICON(X_BOX));\n\t\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\tm_notebook = new wxNotebook(this, wxID_ANY);\n\n\tm_notebook->AddPage(CreateTitleManagerPage(), _(\"Title Manager\"), default_page == TitleManagerPage::TitleManager);\n\tm_notebook->AddPage(CreateDownloadManagerPage(), _(\"Download Manager\"), default_page == TitleManagerPage::DownloadManager);\n\n\tsizer->Add(m_notebook, 1, wxEXPAND);\n\n\tm_status_bar = CreateStatusBar(2, wxSTB_SIZEGRIP);\n\tm_status_bar->SetStatusText(_(\"Searching for titles...\"));\n\n\tthis->SetSizerAndFit(sizer);\n\tthis->Centre(wxBOTH);\n\n\tthis->Bind(wxEVT_SET_STATUS_BAR_TEXT, &TitleManager::OnSetStatusBarText, this);\n\tthis->Bind(wxEVT_TITLE_FOUND, &TitleManager::OnTitleFound, this);\n\tthis->Bind(wxEVT_TITLE_SEARCH_COMPLETE, &TitleManager::OnTitleSearchComplete, this);\n\tthis->Bind(wxEVT_DL_TITLE_UPDATE, &TitleManager::OnDownloadableTitleUpdate, this);\n\tthis->Bind(wxEVT_DL_DISCONNECT_COMPLETE, &TitleManager::OnDisconnect, this);\n\t\n\t// TODO typing on title list should change filter text and filter!\n\n\t// if download manager is already active then restore state\n\tDownloadManager* dlMgr = DownloadManager::GetInstance(false);\n\tif (dlMgr && dlMgr->IsConnected())\n\t{\n\t\tdlMgr->setUserData(this);\n\t\tdlMgr->registerCallbacks(\n\t\t\tTitleManager::Callback_ConnectStatusUpdate,\n\t\t\tTitleManager::Callback_AddDownloadableTitle,\n\t\t\tTitleManager::Callback_RemoveDownloadableTitle);\n\t\tSetConnected(true);\n\t}\n\n\tm_callbackId = CafeTitleList::RegisterCallback([](CafeTitleListCallbackEvent* evt, void* ctx) { ((TitleManager*)ctx)->HandleTitleListCallback(evt); }, this);\n}\n\nTitleManager::~TitleManager()\n{\n\tCafeTitleList::UnregisterCallback(m_callbackId);\n\n\t// unregister callbacks for download manager\n\tDownloadManager* dlMgr = DownloadManager::GetInstance(false);\n\tif (dlMgr)\n\t{\n\t\tdlMgr->setUserData(nullptr);\n\t\tdlMgr->registerCallbacks(\n\t\t\tnullptr,\n\t\t\tnullptr,\n\t\t\tnullptr);\n\t\t// if download manager is still downloading / installing then show a warning\n\t\tif (dlMgr->hasActiveDownloads())\n\t\t{\n\t\t\tstatic bool s_showedBGDownloadWarning = false;\n\t\t\tif (!s_showedBGDownloadWarning)\n\t\t\t{\n\t\t\t\twxMessageBox(_(\"Currently active downloads will continue in the background.\"), _(\"Information\"), wxOK | wxCENTRE, this);\n\t\t\t\ts_showedBGDownloadWarning = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tm_running = false;\n}\n\nvoid TitleManager::SetFocusAndTab(TitleManagerPage page)\n{\n\tm_notebook->SetSelection((int)page);\n\tthis->SetFocus();\n}\n\nvoid TitleManager::SetDownloadStatusText(const wxString& text)\n{\n\tauto* evt = new wxCommandEvent(wxEVT_SET_TEXT);\n\tevt->SetEventObject(m_status_text);\n\tevt->SetString(text);\n\twxQueueEvent(this, evt);\n}\n\nvoid TitleManager::HandleTitleListCallback(CafeTitleListCallbackEvent* evt)\n{\n\tif (evt->eventType == CafeTitleListCallbackEvent::TYPE::SCAN_FINISHED)\n\t{\n\t\tauto* evt = new wxCommandEvent(wxEVT_TITLE_SEARCH_COMPLETE);\n\t\twxQueueEvent(this, evt);\n\t}\n}\n\nvoid TitleManager::OnTitleFound(wxCommandEvent& event)\n{\n\tauto* obj = dynamic_cast<wxTitleManagerList::TitleEntryData_t*>(event.GetClientObject());\n\twxASSERT(obj);\n\tm_title_list->AddTitle(obj);\n}\n\nvoid TitleManager::OnTitleSearchComplete(wxCommandEvent& event)\n{\n\tm_isScanning = false;\n\tif (m_connectRequested)\n\t{\n\t\tInitiateConnect();\n\t\tm_connectRequested = false;\n\t}\n\t// update status bar text\n\tm_title_list->SortEntries(-1);\n\tm_status_bar->SetStatusText(formatWxString(_(\"Found {0} games, {1} updates, {2} DLCs and {3} save entries\"),\n\t\tm_title_list->GetCountByType(wxTitleManagerList::EntryType::Base) + m_title_list->GetCountByType(wxTitleManagerList::EntryType::System),\n\t\tm_title_list->GetCountByType(wxTitleManagerList::EntryType::Update),\n\t\tm_title_list->GetCountByType(wxTitleManagerList::EntryType::Dlc),\n\t\tm_title_list->GetCountByType(wxTitleManagerList::EntryType::Save)\n\t));\n\n\t// re-filter if any filter is set\n\tconst auto filter = m_filter->GetValue();\n\tif (!filter.IsEmpty())\n\t\tm_title_list->Filter(m_filter->GetValue());\n\n\tm_title_list->AutosizeColumns();\n\tm_refresh_button->Enable();\n}\n\nvoid TitleManager::OnSetStatusBarText(wxSetStatusBarTextEvent& event)\n{\n\tm_status_bar->SetStatusText(event.GetText(), event.GetNumber());\n}\n\nvoid TitleManager::OnFilterChanged(wxCommandEvent& event)\n{\n\tevent.Skip();\n\tm_title_list->Filter(m_filter->GetValue());\n}\n\nvoid TitleManager::OnRefreshButton(wxCommandEvent& event)\n{\n\tm_refresh_button->Disable();\n\tm_isScanning = true;\n\t// m_title_list->ClearItems(); -> Dont clear. Refresh() triggers incremental updates via notifications\n\tm_status_bar->SetStatusText(_(\"Searching for titles...\"));\n\tCafeTitleList::Refresh();\n}\n\nvoid TitleManager::OnInstallTitle(wxCommandEvent& event)\n{\n\twxFileDialog openFileDialog(this, _(\"Select title to install\"), \"\", \"\", \"meta.xml|meta.xml\", wxFD_OPEN | wxFD_FILE_MUST_EXIST);\n\tif (openFileDialog.ShowModal() == wxID_CANCEL || openFileDialog.GetPath().IsEmpty())\n\t\treturn;\n\n\tfs::path filePath(openFileDialog.GetPath().wc_string());\n\ttry\n\t{\n\t\tfilePath = filePath.parent_path();\n\t\tfilePath = filePath.parent_path();\n\t\tGameUpdateWindow frame(*this, filePath);\n\t\tconst int updateResult = frame.ShowModal();\n\n\t\tif (updateResult == wxID_OK)\n\t\t{\n\t\t\tCafeTitleList::AddTitleFromPath(frame.GetTargetPath());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (frame.GetExceptionMessage().empty())\n\t\t\t\twxMessageBox(_(\"Update installation has been canceled!\"));\n\t\t\telse\n\t\t\t{\n\t\t\t\tthrow std::runtime_error(frame.GetExceptionMessage());\n\t\t\t}\n\t\t}\n\t}\n\tcatch (const AbortException&)\n\t{\n\t\t// ignored\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\twxMessageBox(ex.what(), _(\"Update error\"));\n\t}\n}\n\nstatic void PopulateSavePersistentIds(wxTitleManagerList::TitleEntry& entry)\n{\n\tif (!entry.persistent_ids.empty())\n\t\treturn;\n\tcemu_assert(entry.type == wxTitleManagerList::EntryType::Save);\n\tSaveInfo saveInfo = CafeSaveList::GetSaveByTitleId(entry.title_id);\n\tif (!saveInfo.IsValid())\n\t\treturn;\n\tfs::path savePath = saveInfo.GetPath();\n\tsavePath /= \"user\";\n\tstd::error_code ec;\n\tfor (auto it : fs::directory_iterator(savePath, ec))\n\t{\n\t\tif(!it.is_directory(ec))\n\t\t\tcontinue;\n\t\tif(fs::is_empty(it.path()))\n\t\t\tcontinue;\n\t\tstd::string dirName = it.path().filename().string();\n\t\tif(!std::regex_match(dirName, std::regex(\"[0-9a-fA-F]{8}\")))\n\t\t\tcontinue;\n\t\tentry.persistent_ids.emplace_back(ConvertString<uint32>(dirName, 16));\n\t}\n}\n\nvoid TitleManager::OnTitleSelected(wxListEvent& event)\n{\n\tevent.Skip();\n\n\tconst auto entry = m_title_list->GetSelectedTitleEntry();\n\tif(entry.has_value() && entry->type == wxTitleManagerList::EntryType::Save)\n\t{\n\t\tm_save_panel->Show();\n\t\tm_save_account_list->Clear();\n\n\t\tPopulateSavePersistentIds(*entry);\n\n\t\t// an account must be selected before any of the control buttons can be used\n\t\tfor(auto&& v : m_save_panel->GetChildren())\n\t\t{\n\t\t\tif (dynamic_cast<wxButton*>(v) && v->GetId() != m_save_import->GetId()) // import is always enabled\n\t\t\t\tv->Disable();\n\t\t}\n\n\t\tconst auto& accounts = Account::GetAccounts();\n\t\tfor (const auto& id : entry->persistent_ids)\n\t\t{\n\t\t\tconst auto it = std::find_if(accounts.cbegin(), accounts.cend(), [id](const auto& acc) { return acc.GetPersistentId() == id; });\n\t\t\tif(it != accounts.cend())\n\t\t\t{\n\t\t\t\tm_save_account_list->Append(fmt::format(\"{:x} ({})\", id, \n\t\t\t\t\tboost::nowide::narrow(it->GetMiiName().data(), it->GetMiiName().size())), \n\t\t\t\t\t(void*)(uintptr_t)id);\n\t\t\t}\n\t\t\telse\n\t\t\t\tm_save_account_list->Append(fmt::format(\"{:x}\", id), (void*)(uintptr_t)id);\n\t\t}\n\t}\n\telse\n\t{\n\t\tm_save_panel->Hide();\n\t}\n}\n\nvoid TitleManager::OnSaveOpenDirectory(wxCommandEvent& event)\n{\n\tconst auto selection=  m_save_account_list->GetSelection();\n\tif (selection == wxNOT_FOUND)\n\t\treturn;\n\n\tconst auto entry = m_title_list->GetSelectedTitleEntry();\n\tif (!entry.has_value())\n\t\treturn;\n\n\tconst auto persistent_id = (uint32)(uintptr_t)m_save_account_list->GetClientData(selection);\n\n\tconst fs::path target = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/user/{:08x}\", (uint32)(entry->title_id >> 32), (uint32)(entry->title_id & 0xFFFFFFFF), persistent_id);\n\tif (!fs::exists(target) || !fs::is_directory(target))\n\t\treturn;\n\n\twxLaunchDefaultApplication(wxHelper::FromPath(target));\n}\n\nvoid TitleManager::OnSaveDelete(wxCommandEvent& event)\n{\n\tconst auto selection_index = m_save_account_list->GetSelection();\n\tif (selection_index == wxNOT_FOUND)\n\t\treturn;\n\t\n\tconst auto selection = m_save_account_list->GetStringSelection();\n\tif (selection.IsEmpty())\n\t\treturn;\n\t\n\tconst auto msg = formatWxString(_(\"Are you really sure that you want to delete the save entry for {}\"), selection);\n\tconst auto result = wxMessageBox(msg, _(\"Warning\"), wxYES_NO | wxCENTRE | wxICON_EXCLAMATION, this);\n\tif (result == wxNO)\n\t\treturn;\n\n\tauto entry = m_title_list->GetSelectedTitleEntry();\n\tif (!entry.has_value())\n\t\treturn;\n\n\tconst auto persistent_id = (uint32)(uintptr_t)m_save_account_list->GetClientData(selection_index);\n\n\tconst fs::path target = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/user/{:08x}\", (uint32)(entry->title_id >> 32), (uint32)(entry->title_id & 0xFFFFFFFF), persistent_id);\n\tif (!fs::exists(target) || !fs::is_directory(target))\n\t\treturn;\n\n\t// edit meta saveinfo.xml\n\tbool meta_file_edited = false;\n\tconst fs::path saveinfo = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/meta/saveinfo.xml\", (uint32)(entry->title_id >> 32), (uint32)(entry->title_id & 0xFFFFFFFF));\n\tif (fs::exists(saveinfo) || fs::is_regular_file(saveinfo))\n\t{\n\t\tpugi::xml_document doc;\n\t\tif (doc.load_file(saveinfo.c_str()))\n\t\t{\n\t\t\tauto info_node = doc.child(\"info\");\n\t\t\tif(info_node)\n\t\t\t{\n\t\t\t\tauto persistend_id_string = fmt::format(L\"{:08x}\", persistent_id);\n\t\t\t\tconst auto delete_entry = info_node.find_child([&persistend_id_string](const pugi::xml_node& node)\n\t\t\t\t{\n\t\t\t\t\t\treturn boost::iequals(node.attribute(\"persistentId\").as_string(), persistend_id_string);\n\t\t\t\t});\n\t\t\t\tif (delete_entry)\n\t\t\t\t{\n\t\t\t\t\tinfo_node.remove_child(delete_entry);\n\t\t\t\t\tmeta_file_edited = doc.save_file(saveinfo.c_str());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!meta_file_edited)\n\t\tcemuLog_log(LogType::Force, \"TitleManager::OnSaveDelete: couldn't delete save entry in saveinfo.xml: {}\", _pathToUtf8(saveinfo));\n\n\t// remove from title entry\n\tauto& persistent_ids = entry->persistent_ids;\n\tpersistent_ids.erase(std::remove(persistent_ids.begin(), persistent_ids.end(), persistent_id), persistent_ids.end());\n\n\tstd::error_code ec;\n\tfs::remove_all(target, ec);\n\tif (ec)\n\t{\n\t\tconst auto error_msg = formatWxString(_(\"Error when trying to delete the save directory:\\n{}\"), GetSystemErrorMessage(ec));\n\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE, this);\n\t\treturn;\n\t}\n\n\tm_save_account_list->Delete(selection_index);\n}\n\n\nvoid TitleManager::OnSaveTransfer(wxCommandEvent& event)\n{\n\tconst auto selection_index = m_save_account_list->GetSelection();\n\tif (selection_index == wxNOT_FOUND)\n\t\treturn;\n\t\n\tconst auto selection = m_save_account_list->GetStringSelection();\n\tif (selection.IsEmpty())\n\t\treturn;\n\n\tauto entry = m_title_list->GetSelectedTitleEntry();\n\tif (!entry.has_value())\n\t\treturn;\n\n\tconst auto persistent_id = (uint32)(uintptr_t)m_save_account_list->GetClientData(selection_index);\n\t\n\tSaveTransfer transfer(this, entry->title_id, selection, persistent_id);\n\tif (transfer.ShowModal() == wxCANCEL)\n\t\treturn;\n\n\t// remove old id entry\n\tauto& persistent_ids = entry->persistent_ids;\n\tpersistent_ids.erase(std::remove(persistent_ids.begin(), persistent_ids.end(), persistent_id), persistent_ids.end());\n\n\t// add new id if not added yet\n\tconst auto new_id = transfer.GetTargetPersistentId();\n\tif (new_id != 0 && std::find(persistent_ids.cbegin(), persistent_ids.cend(), new_id) == persistent_ids.cend())\n\t{\n\t\tpersistent_ids.emplace_back(new_id);\n\n\t\tconst auto& account = Account::GetAccount(new_id);\n\t\tif(account.GetPersistentId() == new_id)\n\t\t\tm_save_account_list->Append(fmt::format(\"{:x} ({})\", new_id,\n\t\t\t\tboost::nowide::narrow(account.GetMiiName().data(), account.GetMiiName().size())),\n\t\t\t\t(void*)(uintptr_t)new_id);\n\t\telse\n\t\t\tm_save_account_list->Append(fmt::format(\"{:x}\", new_id), (void*)(uintptr_t)new_id);\n\t}\n\n\tm_save_account_list->Delete(selection_index);\n}\n\nvoid TitleManager::OnSaveAccountSelected(wxCommandEvent& event)\n{\n\tevent.Skip();\n\tfor (auto&& v : m_save_panel->GetChildren())\n\t{\n\t\tif (!v->IsEnabled())\n\t\t\tv->Enable();\n\t}\n}\n\nvoid TitleManager::OnSaveExport(wxCommandEvent& event)\n{\n\tconst auto selection_index = m_save_account_list->GetSelection();\n\tif (selection_index == wxNOT_FOUND)\n\t\treturn;\n\n\tconst auto selection = m_save_account_list->GetStringSelection();\n\tif (selection.IsEmpty())\n\t\treturn;\n\n\tconst auto entry = m_title_list->GetSelectedTitleEntry();\n\tif (!entry.has_value())\n\t\treturn;\n\n\tconst auto persistent_id = (uint32)(uintptr_t)m_save_account_list->GetClientData(selection_index);\n\n\twxFileDialog path_dialog(this, _(\"Select a target file to export the save entry\"), wxHelper::FromPath(entry->path), wxEmptyString,\n\t\tfmt::format(\"{}|*.zip\", _(\"Exported save entry (*.zip)\")), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\n\tif (path_dialog.ShowModal() != wxID_OK || path_dialog.GetPath().IsEmpty())\n\t\treturn;\n\n\tconst auto path = path_dialog.GetPath();\n\tint ze;\n\tauto* zip = zip_open(path.ToUTF8().data(), ZIP_CREATE | ZIP_TRUNCATE, &ze);\n\tif (!zip)\n\t{\n\t\tzip_error_t ziperror;\n\t\tzip_error_init_with_code(&ziperror, ze);\n\t\tconst auto error_msg = formatWxString(_(\"Error when creating the zip for the save entry:\\n{}\"), zip_error_strerror(&ziperror));\n\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\t// grab all files to zip\n\tconst auto savedir = fs::path(entry->path).append(fmt::format(\"user/{:08x}\", persistent_id));\n\tconst auto savedir_str = savedir.generic_u8string();\n\tfor(const auto& it : fs::recursive_directory_iterator(savedir))\n\t{\n\t\tif (it.path() == \".\" || it.path() == \"..\")\n\t\t\tcontinue;\n\n\t\tconst auto entryname = it.path().generic_u8string();\n\t\tif(fs::is_directory(it.path()))\n\t\t{\n\t\t\tif(zip_dir_add(zip, (const char*)entryname.substr(savedir_str.size() + 1).c_str(), ZIP_FL_ENC_UTF_8) < 0 )\n\t\t\t{\n\t\t\t\tconst auto error_msg = formatWxString(_(\"Error when trying to add a directory to the zip:\\n{}\"), zip_strerror(zip));\n\t\t\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto* source = zip_source_file(zip, (const char*)entryname.c_str(), 0, 0);\n\t\t\tif(!source)\n\t\t\t{\n\t\t\t\tconst auto error_msg = formatWxString(_(\"Error when trying to add a file to the zip:\\n{}\"), zip_strerror(zip));\n\t\t\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\t}\n\n\t\t\tif (zip_file_add(zip, (const char*)entryname.substr(savedir_str.size() + 1).c_str(), source, ZIP_FL_ENC_UTF_8) < 0)\n\t\t\t{\n\t\t\t\tconst auto error_msg = formatWxString(_(\"Error when trying to add a file to the zip:\\n{}\"), zip_strerror(zip));\n\t\t\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\t\t\n\t\t\t\tzip_source_free(source);\n\t\t\t}\n\t\t}\n\t}\n\n\t// add own metainfo like file and store title id for verification later\n\tstd::string metacontent = fmt::format(\"titleId = {:#016x}\", entry->title_id);\n\tauto* metabuff = zip_source_buffer(zip, metacontent.data(), metacontent.size(), 0);\n\tif(zip_file_add(zip, \"cemu_meta\", metabuff, ZIP_FL_ENC_UTF_8) < 0)\n\t{\n\t\tconst auto error_msg = formatWxString(_(\"Error when trying to add cemu_meta file to the zip:\\n{}\"), zip_strerror(zip));\n\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\n\t\tzip_source_free(metabuff);\n\t}\n\n\tzip_close(zip);\n}\n\nvoid TitleManager::OnSaveImport(wxCommandEvent& event)\n{\n\tauto entry = m_title_list->GetSelectedTitleEntry();\n\tif (!entry.has_value())\n\t\treturn;\n\t\n\tSaveImportWindow save_import(this, entry->title_id);\n\tif (save_import.ShowModal() == wxCANCEL)\n\t\treturn;\n\n\t// add new id if not added yet\n\tauto& persistent_ids = entry->persistent_ids;\n\tconst auto new_id = save_import.GetTargetPersistentId();\n\tif (new_id != 0 && std::find(persistent_ids.cbegin(), persistent_ids.cend(), new_id) == persistent_ids.cend())\n\t{\n\t\tpersistent_ids.emplace_back(new_id);\n\n\t\tconst auto& account = Account::GetAccount(new_id);\n\t\tif (account.GetPersistentId() == new_id)\n\t\t\tm_save_account_list->Append(fmt::format(\"{:x} ({})\", new_id,\n\t\t\t\tboost::nowide::narrow(account.GetMiiName().data(), account.GetMiiName().size())),\n\t\t\t\t(void*)(uintptr_t)new_id);\n\t\telse\n\t\t\tm_save_account_list->Append(fmt::format(\"{:x}\", new_id), (void*)(uintptr_t)new_id);\n\t}\n\t\n}\n\nvoid TitleManager::InitiateConnect()\n{\n\t// init connection to download manager if queued\n#if DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN\n\tuint32 persistentId = (uint32)(uintptr_t)m_account->GetClientData(m_account->GetSelection());\n\tauto& account = Account::GetAccount(persistentId);\n#endif\n\tDownloadManager* dlMgr = DownloadManager::GetInstance();\n\tdlMgr->reset();\n\tm_download_list->SetCurrentDownloadMgr(dlMgr);\n\n\tstd::string deviceCertBase64 = NCrypto::CertECC::GetDeviceCertificate().encodeToBase64();\n\n\tif (!NCrypto::SEEPROM_IsPresent())\n\t{\n\t\tSetDownloadStatusText(_(\"Dumped online files not found\"));\n\t\treturn;\n\t}\n\n\tSetDownloadStatusText(_(\"Connecting...\"));\n\t// begin async connect\n\tdlMgr->setUserData(this);\n\tdlMgr->registerCallbacks(\n\t\tTitleManager::Callback_ConnectStatusUpdate,\n\t\tTitleManager::Callback_AddDownloadableTitle,\n\t\tTitleManager::Callback_RemoveDownloadableTitle);\n\tstd::string accountName;\n\tstd::array<uint8, 32> accountPassword;\n\tstd::string accountCountry;\n#if DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN\n\taccountName = account.GetAccountId();\n\taccountPassword = account.GetAccountPasswordCache();\n\taccountCountry.assign(NCrypto::GetCountryAsString(account.GetCountry()));\n#endif\n\tdlMgr->connect(accountName, accountPassword, NCrypto::SEEPROM_GetRegion(), accountCountry, NCrypto::GetDeviceId(), NCrypto::GetSerial(), deviceCertBase64);\n}\n\nvoid TitleManager::OnConnect(wxCommandEvent& event)\n{\n\tif (!m_isScanning)\n\t{\n\t\tInitiateConnect();\n\t\tSetConnected(true);\n\t}\n\telse\n\t{\n\t\tSetDownloadStatusText(_(\"Getting installed title information...\"));\n\t\tSetConnected(true);\n\t\tm_connectRequested = true;\n\t}\n}\n\nvoid TitleManager::OnDlFilterCheckbox(wxCommandEvent& event)\n{\n\tm_download_list->Filter2(m_show_titles->GetValue(), m_show_updates->GetValue(), m_show_installed->GetValue());\n\tm_download_list->SortEntries();\n}\n\nvoid TitleManager::OnSetStatusText(wxCommandEvent& event)\n{\n\tauto* text = wxDynamicCast(event.GetEventObject(), wxControl);\n\twxASSERT(text);\n\ttext->SetLabel(event.GetString());\n}\n\nvoid TitleManager::OnDownloadableTitleUpdate(wxCommandEvent& event)\n{\n\tauto* obj = dynamic_cast<wxDownloadManagerList::TitleEntryData_t*>(event.GetClientObject());\n\tauto entry = obj->GetData();\n\tm_download_list->AddOrUpdateTitle(obj);\n}\n\nvoid TitleManager::OnDisconnect(wxCommandEvent& event)\n{\n\tSetConnected(false);\n}\n\nvoid TitleManager::SetConnected(bool state)\n{\n#if DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN\n\tm_account->Enable(!state);\n#endif\n\tm_connect->Enable(!state);\n\n\tm_show_titles->Enable(state);\n\tm_show_updates->Enable(state);\n\tm_show_installed->Enable(state);\n\tm_download_list->Enable(state);\n}\n\nvoid TitleManager::Callback_ConnectStatusUpdate(std::string statusText, DLMGR_STATUS_CODE statusCode)\n{\n\tTitleManager* titleManager = static_cast<TitleManager*>(DownloadManager::GetInstance()->getUserData());\n\ttitleManager->SetDownloadStatusText(wxString::FromUTF8(statusText));\n\tif (statusCode == DLMGR_STATUS_CODE::FAILED)\n\t{\n\t\tauto* evt = new wxCommandEvent(wxEVT_DL_DISCONNECT_COMPLETE);\n\t\twxQueueEvent(titleManager, evt); // this will set SetConnected() to false\n\t\treturn;\n\t}\n}\n\nvoid TitleManager::Callback_AddDownloadableTitle(const DlMgrTitleReport& titleInfo)\n{\n\tTitleManager* titleManager = static_cast<TitleManager*>(DownloadManager::GetInstance()->getUserData());\n\twxDownloadManagerList::EntryType type = wxDownloadManagerList::EntryType::Base;\n\tif (((titleInfo.titleId >> 32) & 0xF) == 0xE)\n\t\ttype = wxDownloadManagerList::EntryType::Update;\n\telse if (((titleInfo.titleId >> 32) & 0xF) == 0xC)\n\t\ttype = wxDownloadManagerList::EntryType::DLC;\n\tif (titleInfo.status == DlMgrTitleReport::STATUS::INSTALLABLE || titleInfo.status == DlMgrTitleReport::STATUS::INSTALLABLE_UNFINISHED || titleInfo.status == DlMgrTitleReport::STATUS::INSTALLABLE_UPDATE)\n\t{\n\t\t// installable title\n\t\twxDownloadManagerList::TitleEntry titleEntry(type, false, titleInfo.titleId, titleInfo.version, titleInfo.isPaused);\n\t\ttitleEntry.name = wxString::FromUTF8(titleInfo.name);\n\t\ttitleEntry.status = wxDownloadManagerList::TitleDownloadStatus::Available;\n\t\ttitleEntry.progress = 0;\n\t\tif (titleInfo.status == DlMgrTitleReport::STATUS::INSTALLABLE_UNFINISHED)\n\t\t\ttitleEntry.progress = 1;\n\t\tif (titleInfo.status == DlMgrTitleReport::STATUS::INSTALLABLE_UPDATE)\n\t\t\ttitleEntry.progress = 2;\n\t\tauto* evt = new wxCommandEvent(wxEVT_DL_TITLE_UPDATE);\n\t\tevt->SetClientObject(new wxCustomData(titleEntry));\n\t\twxQueueEvent(titleManager, evt);\n\t}\n\telse\n\t{\n\t\t// package\n\t\twxDownloadManagerList::TitleEntry titleEntry(type, true, titleInfo.titleId, titleInfo.version, titleInfo.isPaused);\n\t\ttitleEntry.name = wxString::FromUTF8(titleInfo.name);\n\t\ttitleEntry.progress = titleInfo.progress;\n\t\ttitleEntry.progressMax = titleInfo.progressMax;\n\t\tswitch (titleInfo.status)\n\t\t{\n\t\tcase DlMgrTitleReport::STATUS::INITIALIZING:\n\t\t\ttitleEntry.status = wxDownloadManagerList::TitleDownloadStatus::Initializing;\n\t\t\tbreak;\n\t\tcase DlMgrTitleReport::STATUS::QUEUED:\n\t\t\ttitleEntry.status = wxDownloadManagerList::TitleDownloadStatus::Queued;\n\t\t\tbreak;\n\t\tcase DlMgrTitleReport::STATUS::CHECKING:\n\t\t\ttitleEntry.status = wxDownloadManagerList::TitleDownloadStatus::Checking;\n\t\t\tbreak;\n\t\tcase DlMgrTitleReport::STATUS::DOWNLOADING:\n\t\t\ttitleEntry.status = wxDownloadManagerList::TitleDownloadStatus::Downloading;\n\t\t\ttitleEntry.progress = titleInfo.progress;\n\t\t\tbreak;\n\t\tcase DlMgrTitleReport::STATUS::VERIFYING:\n\t\t\ttitleEntry.status = wxDownloadManagerList::TitleDownloadStatus::Verifying;\n\t\t\tbreak;\n\t\tcase DlMgrTitleReport::STATUS::INSTALLING:\n\t\t\ttitleEntry.status = wxDownloadManagerList::TitleDownloadStatus::Installing;\n\t\t\tbreak;\n\t\tcase DlMgrTitleReport::STATUS::INSTALLED:\n\t\t\ttitleEntry.status = wxDownloadManagerList::TitleDownloadStatus::Installed;\n\t\t\tbreak;\n\t\tcase DlMgrTitleReport::STATUS::HAS_ERROR:\n\t\t\ttitleEntry.status = wxDownloadManagerList::TitleDownloadStatus::Error;\n\t\t\ttitleEntry.errorMsg = titleInfo.errorMsg;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ttitleEntry.status = wxDownloadManagerList::TitleDownloadStatus::None;\n\t\t\tbreak;\n\t\t}\n\n\t\tauto* evt = new wxCommandEvent(wxEVT_DL_TITLE_UPDATE);\n\t\tevt->SetClientObject(new wxCustomData(titleEntry));\n\t\twxQueueEvent(titleManager, evt);\n\t}\n}\n\nvoid TitleManager::Callback_RemoveDownloadableTitle(uint64 titleId, uint16 version)\n{\n\tTitleManager* titleManager = static_cast<TitleManager*>(DownloadManager::GetInstance()->getUserData());\n\tassert_dbg();\n}\n"
  },
  {
    "path": "src/gui/wxgui/TitleManager.h",
    "content": "#pragma once\n\n#include <thread>\n#include <atomic>\n\n#include <wx/frame.h>\n#include <wx/button.h>\n\n#include \"Cemu/Tools/DownloadManager/DownloadManager.h\"\n\n#define DOWNLOADMGR_HAS_ACCOUNT_DROPDOWN 0\n\nclass wxCheckBox;\nclass wxStaticText;\nclass wxListEvent;\nclass wxSetStatusBarTextEvent;\nclass wxTitleManagerList;\nclass wxDownloadManagerList;\nclass wxTextCtrl;\nclass wxStatusBar;\nclass wxImageList;\nclass wxBitmapButton;\nclass wxPanel;\nclass wxChoice;\nclass wxNotebook;\n\nenum class TitleManagerPage\n{\n\tTitleManager = 0,\n\tDownloadManager = 1\n};\n\nenum class DLMGR_STATUS_CODE;\n\nclass TitleManager : public wxFrame\n{\npublic:\n\tTitleManager(wxWindow* parent, TitleManagerPage default_page = TitleManagerPage::TitleManager);\n\t~TitleManager();\n\n\tvoid SetFocusAndTab(TitleManagerPage page);\n\n\tvoid SetDownloadStatusText(const wxString& text);\n\t\nprivate:\n\twxPanel* CreateTitleManagerPage();\n\twxPanel* CreateDownloadManagerPage();\n\t\n\t// title manager\n\tvoid OnTitleFound(wxCommandEvent& event);\n\tvoid OnTitleSearchComplete(wxCommandEvent& event);\n\tvoid OnSetStatusBarText(wxSetStatusBarTextEvent& event);\n\tvoid OnFilterChanged(wxCommandEvent& event);\n\tvoid OnRefreshButton(wxCommandEvent& event);\n\tvoid OnInstallTitle(wxCommandEvent& event);\n\tvoid OnTitleSelected(wxListEvent& event);\n\tvoid OnSaveOpenDirectory(wxCommandEvent& event);\n\tvoid OnSaveDelete(wxCommandEvent& event);\n\tvoid OnSaveTransfer(wxCommandEvent& event);\n\tvoid OnSaveAccountSelected(wxCommandEvent& event);\n\tvoid OnSaveExport(wxCommandEvent& event);\n\tvoid OnSaveImport(wxCommandEvent& event);\n\n\tvoid HandleTitleListCallback(struct CafeTitleListCallbackEvent* evt);\n\n\twxNotebook* m_notebook;\n\t\n\tuint32 m_callbackId;\n\n\t// title manager\n\twxTextCtrl* m_filter;\n\twxTitleManagerList* m_title_list;\n\twxStatusBar* m_status_bar;\n\twxBitmapButton* m_refresh_button;\n\twxPanel* m_save_panel;\n\twxChoice* m_save_account_list;\n\twxButton* m_save_import;\n\n\tbool m_isScanning{ true }; // set when CafeTitleList is scanning\n\n\tstd::atomic_bool m_running = true;\n\n\t// download manager\n\tvoid InitiateConnect();\n\tvoid OnConnect(wxCommandEvent& event);\n\tvoid OnSetStatusText(wxCommandEvent& event);\n\tvoid OnDownloadableTitleUpdate(wxCommandEvent& event);\n\tvoid OnDisconnect(wxCommandEvent& event);\n\n\tvoid OnDlFilterCheckbox(wxCommandEvent& event);\n\n\tvoid SetConnected(bool state);\n\n\tstatic void Callback_ConnectStatusUpdate(std::string statusText, DLMGR_STATUS_CODE statusCode);\n\tstatic void Callback_AddDownloadableTitle(const struct DlMgrTitleReport& titleInfo);\n\tstatic void Callback_RemoveDownloadableTitle(uint64 titleId, uint16 version);\n\n\twxChoice* m_account;\n\twxButton* m_connect;\n\twxStaticText* m_status_text;\n\twxCheckBox *m_show_titles, *m_show_updates, *m_show_installed;\n\twxDownloadManagerList* m_download_list;\n\tbool m_connectRequested{false}; // connect was clicked before m_foundTitles was available\n};\n"
  },
  {
    "path": "src/gui/wxgui/canvas/IRenderCanvas.h",
    "content": "#pragma once\n\n#include <wx/wxprec.h>\n\n// base class for all render interfaces\nclass IRenderCanvas\n{\npublic:\n\tIRenderCanvas(bool is_main_window)\n\t\t: m_is_main_window(is_main_window) {}\n\nprotected:\n\tbool m_is_main_window;\n};"
  },
  {
    "path": "src/gui/wxgui/canvas/MetalCanvas.cpp",
    "content": "#include \"wxgui/canvas/MetalCanvas.h\"\n#include \"Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h\"\n\n#include <wx/msgdlg.h>\n#include <helpers/wxHelpers.h>\n\nMetalCanvas::MetalCanvas(wxWindow* parent, const wxSize& size, bool is_main_window)\n\t: IRenderCanvas(is_main_window), wxWindow(parent, wxID_ANY, wxDefaultPosition, size, wxNO_FULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)\n{\n\tBind(wxEVT_PAINT, &MetalCanvas::OnPaint, this);\n\tBind(wxEVT_SIZE, &MetalCanvas::OnResize, this);\n\n\tauto& canvas = is_main_window ? WindowSystem::GetWindowInfo().canvas_main : WindowSystem::GetWindowInfo().canvas_pad;\n\tcanvas = initHandleContextFromWxWidgetsWindow(this);\n\n\ttry\n\t{\n\t\tif (is_main_window)\n\t\t\tg_renderer = std::make_unique<MetalRenderer>();\n\n\t\tauto metal_renderer = MetalRenderer::GetInstance();\n\t\tmetal_renderer->InitializeLayer({size.x, size.y}, is_main_window);\n\t}\n\tcatch(const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error when initializing Metal renderer: {}\", ex.what());\n\t\tauto msg = formatWxString(_(\"Error when initializing Metal renderer:\\n{}\"), ex.what());\n\t\twxMessageDialog dialog(this, msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\tdialog.ShowModal();\n\t\texit(0);\n\t}\n\n\twxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES);\n}\n\nMetalCanvas::~MetalCanvas()\n{\n\tUnbind(wxEVT_PAINT, &MetalCanvas::OnPaint, this);\n\tUnbind(wxEVT_SIZE, &MetalCanvas::OnResize, this);\n\n\tMetalRenderer* mtlr = (MetalRenderer*)g_renderer.get();\n\tif (mtlr)\n\t\tmtlr->ShutdownLayer(m_is_main_window);\n}\n\nvoid MetalCanvas::OnPaint(wxPaintEvent& event)\n{\n}\n\nvoid MetalCanvas::OnResize(wxSizeEvent& event)\n{\n\tconst wxSize size = GetSize();\n\tif (size.GetWidth() == 0 || size.GetHeight() == 0)\n\t\treturn;\n\n\tconst wxRect refreshRect(size);\n\tRefreshRect(refreshRect, false);\n\n\tauto metal_renderer = MetalRenderer::GetInstance();\n\tmetal_renderer->ResizeLayer({size.x, size.y}, m_is_main_window);\n}\n"
  },
  {
    "path": "src/gui/wxgui/canvas/MetalCanvas.h",
    "content": "#pragma once\n\n#include \"wxgui/canvas/IRenderCanvas.h\"\n\n#include <wx/frame.h>\n\n#include <set>\n\nclass MetalCanvas : public IRenderCanvas, public wxWindow\n{\npublic:\n\tMetalCanvas(wxWindow* parent, const wxSize& size, bool is_main_window);\n\t~MetalCanvas();\n\nprivate:\n\n\tvoid OnPaint(wxPaintEvent& event);\n\tvoid OnResize(wxSizeEvent& event);\n};\n"
  },
  {
    "path": "src/gui/wxgui/canvas/OpenGLCanvas.cpp",
    "content": "#include \"wxgui/canvas/OpenGLCanvas.h\"\n\n#include \"wxgui/canvas/IRenderCanvas.h\"\n\n#include \"Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h\"\n\n#include \"config/CemuConfig.h\"\n\n#include \"Common/GLInclude/GLInclude.h\"\n#include <wx/glcanvas.h> // this includes GL/gl.h, avoid using this in a header because it would contaminate our own OpenGL definitions (GLInclude)\n\nstatic const int g_gl_attribute_list[] =\n{\n\tWX_GL_RGBA,\n\tWX_GL_DOUBLEBUFFER,\n\tWX_GL_DEPTH_SIZE, 16,\n\n\tWX_GL_MIN_RED, 8,\n\tWX_GL_MIN_GREEN, 8,\n\tWX_GL_MIN_BLUE, 8,\n\tWX_GL_MIN_ALPHA, 8,\n\n\tWX_GL_STENCIL_SIZE, 8,\n\n\t//WX_GL_MAJOR_VERSION, 4,\n\t//WX_GL_MINOR_VERSION, 1,\n\t//wx_GL_COMPAT_PROFILE,\n\n\t0, // end of list\n};\n\nclass OpenGLCanvas;\n\nclass GLCanvasManager : public OpenGLCanvasCallbacks\n{\n  public:\n\tGLCanvasManager()\n\t{\n\t\tSetOpenGLCanvasCallbacks(this);\n\t}\n\n\t~GLCanvasManager()\n\t{\n\t\tClearOpenGLCanvasCallbacks();\n\t}\n\n\tvoid SetTVView(OpenGLCanvas* canvas)\n\t{\n\t\tm_tvView = canvas;\n\t}\n\n\tvoid SetPadView(OpenGLCanvas* canvas)\n\t{\n\t\tm_padView = canvas;\n\t}\n\n\tvoid SetGLContext(wxGLContext* context)\n\t{\n\t\tm_glContext = context;\n\t}\n\n\tvoid DeleteGLContext()\n\t{\n\t\tif (m_tvView == nullptr && m_padView == nullptr && m_glContext)\n\t\t{\n\t\t\tdelete m_glContext;\n\t\t\tm_glContext = nullptr;\n\t\t}\n\t}\n\n\tbool HasPadViewOpen() const\n\t{\n\t\treturn m_padView != nullptr;\n\t}\n\n\tbool MakeCurrent(bool padView);\n\n\tvoid SwapBuffers(bool swapTV, bool swapDRC);\n\n  private:\n\twxGLContext* m_glContext = nullptr;\n\tOpenGLCanvas* m_tvView = nullptr;\n\tOpenGLCanvas* m_padView = nullptr;\n} s_glCanvasManager;\n\nclass OpenGLCanvas : public IRenderCanvas, public wxGLCanvas\n{\npublic:\n\tOpenGLCanvas(wxWindow* parent, const wxSize& size, bool is_main_window)\n\t\t: IRenderCanvas(is_main_window), wxGLCanvas(parent, wxID_ANY, g_gl_attribute_list, wxDefaultPosition, size, wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)\n\t{\n\t\tif (m_is_main_window)\n\t\t{\n\t\t\ts_glCanvasManager.SetTVView(this);\n\t\t\ts_glCanvasManager.SetGLContext(new wxGLContext(this));\n\n\t\t\tg_renderer = std::make_unique<OpenGLRenderer>();\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts_glCanvasManager.SetPadView(this);\n\t\t}\n\n\t\twxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES);\n\t}\n\n\t~OpenGLCanvas() override\n\t{\n\t\t// todo - if this is the main window, make sure the renderer has been shut down\n\n\t\tif (m_is_main_window)\n\t\t\ts_glCanvasManager.SetTVView(nullptr);\n\t\telse\n\t\t\ts_glCanvasManager.SetPadView(nullptr);\n\n\t\ts_glCanvasManager.DeleteGLContext();\n\t}\n\n\tvoid UpdateVSyncState()\n\t{\n\t\tint configValue = GetConfig().vsync.GetValue();\n\t\tif(m_activeVSyncState != configValue)\n\t\t{\n#if BOOST_OS_WINDOWS\n\t\t\tif(wglSwapIntervalEXT)\n\t\t\t\twglSwapIntervalEXT(configValue); // 1 = enabled, 0 = disabled\n#elif BOOST_OS_LINUX || BOOST_OS_BSD\n\t\t\tif (eglSwapInterval)\n\t\t\t{\n\t\t\t\tif (eglSwapInterval(eglGetCurrentDisplay(), configValue) == EGL_FALSE)\n\t\t\t\t{\n\t\t\t\t\tcemuLog_log(LogType::Force, \"Failed to set vsync using EGL\");\n\t\t\t\t}\n\t\t\t}\n#else\n\t\t\tcemuLog_log(LogType::Force, \"OpenGL vsync not implemented\");\n#endif\n\t\t\tm_activeVSyncState = configValue;\n\t\t}\n\t}\n\nprivate:\n\tint m_activeVSyncState = -1;\n\t//wxGLContext* m_context = nullptr;\n};\n\nwxWindow* GLCanvas_Create(wxWindow* parent, const wxSize& size, bool is_main_window)\n{\n\treturn new OpenGLCanvas(parent, size, is_main_window);\n}\n\nvoid GLCanvasManager::SwapBuffers(bool swapTV, bool swapDRC)\n{\n\tif (swapTV && m_tvView)\n\t{\n\t\tMakeCurrent(false);\n\t\tm_tvView->SwapBuffers();\n\t\tm_tvView->UpdateVSyncState();\n\t}\n\n\tif (swapDRC && m_padView)\n\t{\n\t\tMakeCurrent(true);\n\t\tm_padView->SwapBuffers();\n\t\tm_padView->UpdateVSyncState();\n\t}\n\n\tMakeCurrent(false);\n}\n\nbool GLCanvasManager::MakeCurrent(bool padView)\n{\n\tOpenGLCanvas* canvas = padView ? m_padView : m_tvView;\n\tif (!canvas)\n\t\treturn false;\n\tm_glContext->SetCurrent(*canvas);\n\treturn true;\n}"
  },
  {
    "path": "src/gui/wxgui/canvas/OpenGLCanvas.h",
    "content": "#pragma once\n#include <wx/window.h>\n\nwxWindow* GLCanvas_Create(wxWindow* parent, const wxSize& size, bool is_main_window);"
  },
  {
    "path": "src/gui/wxgui/canvas/VulkanCanvas.cpp",
    "content": "#include \"wxgui/canvas/VulkanCanvas.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n\n#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND\n#include \"wxgui/helpers/wxWayland.h\"\n#endif\n\n#include <wx/msgdlg.h>\n#include <helpers/wxHelpers.h>\n\nVulkanCanvas::VulkanCanvas(wxWindow* parent, const wxSize& size, bool is_main_window)\n\t: IRenderCanvas(is_main_window), wxWindow(parent, wxID_ANY, wxDefaultPosition, size, wxNO_FULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)\n{\n\tBind(wxEVT_PAINT, &VulkanCanvas::OnPaint, this);\n\tBind(wxEVT_SIZE, &VulkanCanvas::OnResize, this);\n#if __WXMSW__\n\tMSWDisableComposited();\n#endif\n\n\tauto& canvas = is_main_window ? WindowSystem::GetWindowInfo().canvas_main : WindowSystem::GetWindowInfo().canvas_pad;\n\tcanvas = initHandleContextFromWxWidgetsWindow(this);\n\t#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND\n\tif (canvas.backend == WindowSystem::WindowHandleInfo::Backend::Wayland)\n\t{\n\t\tm_subsurface = std::make_unique<wxWlSubsurface>(this);\n\t\tcanvas.surface = m_subsurface->getSurface();\n\t}\n\t#endif\n\n\tcemu_assert(g_vulkan_available);\n\n\ttry\n\t{\n\t\tif (is_main_window)\n\t\t\tg_renderer = std::make_unique<VulkanRenderer>();\n\n\t\tauto vulkan_renderer = VulkanRenderer::GetInstance();\n\t\tvulkan_renderer->InitializeSurface({size.x, size.y}, is_main_window);\n\t}\n\tcatch(const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Error when initializing Vulkan renderer: {}\", ex.what());\n\t\tauto msg = formatWxString(_(\"Error when initializing Vulkan renderer:\\n{}\"), ex.what());\n\t\twxMessageDialog dialog(this, msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\tdialog.ShowModal();\n\t\texit(0);\n\t}\n\n\twxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES);\n}\n\nVulkanCanvas::~VulkanCanvas()\n{\n\tUnbind(wxEVT_PAINT, &VulkanCanvas::OnPaint, this);\n\tUnbind(wxEVT_SIZE, &VulkanCanvas::OnResize, this);\n\n\tif(!m_is_main_window)\n\t{\n\t\tVulkanRenderer* vkr = (VulkanRenderer*)g_renderer.get();\n\t\tif(vkr)\n\t\t\tvkr->StopUsingPadAndWait();\n\t}\n}\n\nvoid VulkanCanvas::OnPaint(wxPaintEvent& event)\n{\n}\n\nvoid VulkanCanvas::OnResize(wxSizeEvent& event)\n{\n\tconst wxSize size = GetSize();\n\tif (size.GetWidth() == 0 || size.GetHeight() == 0)\n\t\treturn;\n\n#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND\n\tif(m_subsurface)\n\t{\n\t\tauto sRect = GetScreenRect();\n\t\tm_subsurface->setSize(sRect.GetX(), sRect.GetY(), sRect.GetWidth(), sRect.GetHeight());\n\t}\n#endif\n\n\tconst wxRect refreshRect(size);\n\tRefreshRect(refreshRect, false);\n}\n"
  },
  {
    "path": "src/gui/wxgui/canvas/VulkanCanvas.h",
    "content": "#pragma once\n\n#include \"wxgui/canvas/IRenderCanvas.h\"\n\n#include <wx/frame.h>\n\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include <set>\n\nclass VulkanCanvas : public IRenderCanvas, public wxWindow\n{\n#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND\n\tstd::unique_ptr<class wxWlSubsurface> m_subsurface;\n#endif\npublic:\n\tVulkanCanvas(wxWindow* parent, const wxSize& size, bool is_main_window);\n\t~VulkanCanvas();\n\nprivate:\n\n\tvoid OnPaint(wxPaintEvent& event);\n\tvoid OnResize(wxSizeEvent& event);\n};\n"
  },
  {
    "path": "src/gui/wxgui/components/TextList.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"TextList.h\"\n\n#include \"debugger/DisasmCtrl.h\"\n\n#include <wx/setup.h>\n#include <wx/tooltip.h>\n\nTextList::~TextList()\n{\n\tm_tooltip_timer->Stop();\n\n\tthis->Unbind(wxEVT_MOTION, &TextList::OnMouseMoveEvent, this);\n\tthis->Unbind(wxEVT_KEY_DOWN, &TextList::OnKeyDownEvent, this);\n\tthis->Unbind(wxEVT_KEY_UP, &TextList::OnKeyUpEvent, this);\n\tthis->Unbind(wxEVT_PAINT, &TextList::OnPaintEvent, this);\n\tthis->Unbind(wxEVT_LEFT_DOWN, &TextList::OnMouseDownEvent, this);\n\tthis->Unbind(wxEVT_LEFT_UP, &TextList::OnMouseUpEvent, this);\n\tthis->Unbind(wxEVT_LEFT_DCLICK, &TextList::OnMouseDClickEvent, this);\n\tthis->Unbind(wxEVT_CONTEXT_MENU, &TextList::OnContextMenu, this);\n\tthis->Unbind(wxEVT_ERASE_BACKGROUND, &TextList::OnEraseBackground, this);\n}\n\nTextList::TextList(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style)\n\t: wxControl(parent, id, pos, size, style), wxScrollHelper(this)\n{\n\tm_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);\n\tthis->wxWindowBase::SetBackgroundStyle(wxBG_STYLE_PAINT);\n\n\twxInfoDC dc(this);\n\tthis->DoPrepareReadOnlyDC(dc);\n\tdc.SetFont(m_font);\n\tm_line_height = dc.GetCharHeight();\n\tm_char_width = dc.GetCharWidth();\n\n\tm_yScrollPixelsPerLine = m_line_height;\n\n\tthis->ShowScrollbars(wxSHOW_SB_DEFAULT, wxSHOW_SB_DEFAULT);\n\n\tm_tooltip = new wxToolTip(wxEmptyString);\n\n\tthis->Bind(wxEVT_MOTION, &TextList::OnMouseMoveEvent, this);\n\tthis->Bind(wxEVT_KEY_DOWN, &TextList::OnKeyDownEvent, this);\n\tthis->Bind(wxEVT_KEY_UP, &TextList::OnKeyUpEvent, this);\n\tthis->Bind(wxEVT_PAINT, &TextList::OnPaintEvent, this);\n\tthis->Bind(wxEVT_LEFT_DOWN, &TextList::OnMouseDownEvent, this);\n\tthis->Bind(wxEVT_LEFT_UP, &TextList::OnMouseUpEvent, this);\n\tthis->Bind(wxEVT_LEFT_DCLICK, &TextList::OnMouseDClickEvent, this);\n\tthis->Bind(wxEVT_CONTEXT_MENU, &TextList::OnContextMenu, this);\n\tthis->Bind(wxEVT_ERASE_BACKGROUND, &TextList::OnEraseBackground, this);\n\n\tm_tooltip_window = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);\n\tm_tooltip_window->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));\n\tm_tooltip_window->Hide();\n\n\tm_tooltip_timer = new wxTimer(this);\n\tthis->Bind(wxEVT_TIMER, &TextList::OnTooltipTimer, this);\n}\n\nvoid TextList::RefreshControl(const wxRect* update_region)\n{\n\tif(update_region)\n\t\tRefresh(true, update_region);\n\telse\n\t{\n\t\twxRect region = GetClientRect();\n\t\tupdate_region = &region;\n\t\tRefresh(true, update_region);\n\t}\n}\n\nvoid TextList::RefreshLine(uint32 line)\n{\n\twxRect update_region = GetClientRect();\n\tupdate_region.y = (sint32)line * m_line_height;\n\tupdate_region.height = m_line_height;\n\tCalcScrolledPosition(0, update_region.y, nullptr, &update_region.y);\n\t// debug_printf(\"update: <%x, %x>\\n\", update_region.y, update_region.height);\n\tRefresh(true, &update_region);\n}\n\nwxSize TextList::DoGetVirtualSize() const\n{\n\treturn {wxDefaultCoord, (int)m_element_count * m_line_height};\n}\n\nvoid TextList::DoSetSize(int x, int y, int width, int height, int sizeFlags)\n{\n\twxControl::DoSetSize(x, y, width, height, sizeFlags);\n\n\tm_elements_visible = (height + m_line_height - 1) / m_line_height;\n\tRefresh();\n}\n\nvoid TextList::SetScrollPos(int orient, int pos, bool refresh)\n{\n\twxControl::SetScrollPos(orient, pos, refresh);\n}\n\nvoid TextList::DrawLineBackground(wxDC& dc, uint32 line, const wxColour& colour, uint32 lines) const\n{\n\twxRect rect;\n\trect.x = GetPosition().x;\n\trect.y = line * m_line_height;\n\trect.width = GetSize().x;\n\trect.height = m_line_height * lines;\n\n\tdc.SetBrush(colour);\n\tdc.DrawRectangle(rect);\n}\n\nvoid TextList::DrawLineBackground(wxDC& dc, const wxPoint& position, const wxColour& colour, uint32 lines) const\n{\n\twxRect rect;\n\trect.x = position.x;\n\trect.y = position.y;\n\trect.width = this->GetSize().x;\n\trect.height = m_line_height * lines;\n\n\tdc.SetBrush(colour);\n\tdc.DrawRectangle(rect);\n}\n\nbool TextList::SetElementCount(size_t element_count)\n{\n\tif (m_element_count == element_count)\n\t\treturn false;\n\n\tif (element_count > 0x7FFFFFFF)\n\t\telement_count = 0x7FFFFFFF;\n\n\tm_element_count = element_count;\n\tthis->AdjustScrollbars();\n\treturn true;\n}\n\nuint32 TextList::GetElementCount() const\n{\n\treturn m_element_count;\n}\n\nbool TextList::IsKeyDown(sint32 keycode)\n{\n\treturn m_key_states[keycode];\n}\n\nvoid TextList::WriteText(wxDC& dc, const wxString& text, wxPoint& position) const\n{\n\tdc.ResetBoundingBox();\n\tdc.DrawText(text, position);\n\tposition.x += dc.MaxX() - dc.MinX();\n}\n\nvoid TextList::WriteText(wxDC& dc, const wxString& text, wxPoint& position, const wxColour& color) const\n{\n\tdc.SetTextForeground(color);\n\tWriteText(dc, text, position);\n}\n\nvoid TextList::NextLine(wxPoint& position, const wxPoint* start_position) const\n{\n\tposition.y += m_line_height;\n\n\tif (start_position)\n\t\tposition.x = start_position->x;\n}\n\nvoid TextList::OnMouseDown() {}\nvoid TextList::OnMouseUp() {}\n\nbool TextList::OnShowTooltip(const wxPoint& position, uint32 line)\n{\n\treturn false;\n}\n\nvoid TextList::OnMouseMoveEvent(wxMouseEvent& event)\n{\n\tm_tooltip_timer->Stop();\n\tm_tooltip_timer->StartOnce(250);\n\t\n\twxPoint position = event.GetPosition();\n\tCalcUnscrolledPosition(position.x, position.y, &position.x, &position.y);\n\n\tm_mouse_position = position;\n\n\tif(m_mouse_down)\n\t\tm_selection.SetBottomRight(position);\n\n\tconst sint32 line = position.y / m_line_height;\n\tOnMouseMove(position, line);\n}\n\nvoid TextList::OnKeyDownEvent(wxKeyEvent& event)\n{\n\tconst auto key_code = event.GetKeyCode();\n\tconst auto it = m_key_states.find(key_code);\n\tif(it == m_key_states.end() || !it->second)\n\t{\n\t\tm_key_states[key_code] = true;\n\t\tOnKeyPressed(key_code, event.GetPosition());\n\t}\n\n\tevent.Skip();\n}\n\nvoid TextList::OnKeyUpEvent(wxKeyEvent& event)\n{\n\tm_key_states[event.GetKeyCode()] = false;\n}\n\nvoid TextList::OnMouseDownEvent(wxMouseEvent& event)\n{\n\tm_mouse_down = true;\n\n\twxPoint position = event.GetPosition();\n\tCalcUnscrolledPosition(position.x, position.y, &position.x, &position.y);\n\tm_selection.SetPosition(position);\n\tm_selection.SetBottomRight(position);\n\n\tOnMouseDown();\n\n\tevent.Skip();\n}\n\nvoid TextList::OnMouseUpEvent(wxMouseEvent& event)\n{\n\tm_mouse_down = false;\n\tOnMouseUp();\n\n\tevent.Skip();\n}\n\nvoid TextList::OnMouseDClickEvent(wxMouseEvent& event)\n{\n\twxPoint position = event.GetPosition();\n\tCalcUnscrolledPosition(position.x, position.y, &position.x, &position.y);\n\tm_selection.SetPosition(position);\n\tm_selection.SetBottomRight(position);\n\n\tconst uint32 line = position.y / m_line_height;\n\tOnMouseDClick(position, line);\n}\n\nvoid TextList::OnContextMenu(wxContextMenuEvent& event)\n{\n\twxPoint position = event.GetPosition();\n\tif (position == wxDefaultPosition)\n\t\treturn;\n\n\twxPoint clientPosition = ScreenToClient(position);\n\n\tCalcUnscrolledPosition(clientPosition.x, clientPosition.y, &clientPosition.x, &clientPosition.y);\n\tm_selection.SetPosition(clientPosition);\n\tm_selection.SetBottomRight(clientPosition);\n\n\tconst uint32 line = clientPosition.y / m_line_height;\n\tOnContextMenu(clientPosition, line);\n}\n\nvoid TextList::OnTooltipTimer(wxTimerEvent& event)\n{\n\tm_tooltip_window->Hide();\n\n\tconst auto cursor_position = wxGetMousePosition();\n\n\tconst auto position = GetScreenPosition();\n\tif (cursor_position.x < position.x || cursor_position.y < position.y)\n\t\treturn;\n\n\tconst auto size = GetSize();\n\tif (position.x + size.x < cursor_position.x || position.y + size.y < cursor_position.y)\n\t\treturn;\n\n\tconst sint32 line = position.y / m_line_height;\n\tif(OnShowTooltip(m_mouse_position, line))\n\t{\n\t\tm_tooltip_window->SetPosition(wxPoint(m_mouse_position.x + 15, m_mouse_position.y + 15));\n\t\tm_tooltip_window->SendSizeEvent();\n\t\tm_tooltip_window->Show();\n\t}\n}\n\nvoid TextList::OnPaintEvent(wxPaintEvent& event)\n{\n\twxAutoBufferedPaintDC dc(m_targetWindow);\n\n\t// get window position\n\tauto position = GetPosition();\n\n\t// get current real position\n\twxRect rect_update = GetUpdateRegion().GetBox();\n\tconst auto count = (uint32)std::ceil((float)rect_update.GetHeight() / m_line_height);\n\n\tposition.y = (rect_update.y / m_line_height) * m_line_height;\n\n\t// paint background\n\tdc.SetFont(m_font);\n\tconst wxColour window_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);\n\tdc.SetBrush(GetBackgroundColour());\n\tdc.SetPen(*wxTRANSPARENT_PEN);\n\tdc.DrawRectangle(rect_update);\n\n\t//// paint selection\n\t//if (!m_selected_text.eof())\n\t//{\n\t//\tdc.SetBrush(*wxBLUE_BRUSH);\n\t//\tdc.SetPen(*wxBLUE_PEN);\n\t//\tdc.DrawRectangle(m_selection);\n\t//}\n\n\tsint32 start;\n\tCalcUnscrolledPosition(rect_update.x, rect_update.y, nullptr, &start);\n\n\tstart /= m_line_height;\n\tm_scrolled_to_end = (start + count) >= m_element_count;\n\n\tOnDraw(dc, start, count, position);\n\n\t// removed Update() here since all text is white\n}"
  },
  {
    "path": "src/gui/wxgui/components/TextList.h",
    "content": "#pragma once\n\n#include <wx/wx.h>\n\n#include <unordered_map>\n#include <sstream>\n\n\nclass TextList : public wxControl, public wxScrollHelper\n{\npublic:\n\tvirtual ~TextList();\n\tTextList(wxWindow* parent, wxWindowID id,\n\t\tconst wxPoint& pos = wxDefaultPosition,\n\t\tconst wxSize& size = wxDefaultSize, long style = 0);\n\n\tvoid RefreshControl(const wxRect* update_region = nullptr);\n\tvoid RefreshLine(uint32 line);\n\n\twxSize DoGetVirtualSize() const override;\n\tvoid DoSetSize(int x, int y, int width, int height, int sizeFlags) override;\n\tvoid SetScrollPos(int orient, int pos, bool refresh) override;\n\tvoid DrawLineBackground(wxDC& dc, uint32 line, const wxColour& colour, uint32 lines = 1) const;\n\tvoid DrawLineBackground(wxDC& dc, const wxPoint& position, const wxColour& colour, uint32 lines = 1) const;\n\n\tbool SetElementCount(size_t element_count);\n\tuint32 GetElementCount() const;\n\tbool IsKeyDown(sint32 keycode);\n\t\nprotected:\n\tvoid WriteText(wxDC& dc, const wxString& text, wxPoint& position) const;\n\tvoid WriteText(wxDC& dc, const wxString& text, wxPoint& position, const wxColour& color) const;\n\tvoid NextLine(wxPoint& position, const wxPoint* start_position = nullptr) const;\n\n\tvirtual void OnDraw(wxDC& dc, sint32 start, sint32 count, const wxPoint& start_position) {};\n\tvirtual void OnMouseMove(const wxPoint& position, uint32 line) {}\n\tvirtual void OnKeyPressed(sint32 key_code, const wxPoint& position) {}\n\tvirtual void OnMouseDown();\n\tvirtual void OnMouseUp();\n\tvirtual void OnMouseDClick(const wxPoint& position, uint32 line) {}\n\tvirtual void OnContextMenu(const wxPoint& position, uint32 line) {}\n\tvirtual bool OnShowTooltip(const wxPoint& position, uint32 line);\n\tvoid OnEraseBackground(wxEraseEvent&) {}\n\n\tsint32 m_line_height;\n\tsint32 m_char_width;\n\tsize_t m_elements_visible = 0;\n\tsize_t m_element_count = 0;\n\tbool m_scrolled_to_end = true;\n\n\tstd::wstringstream m_selected_text;\n\tbool m_mouse_down = false;\n\twxRect m_selection;\n\twxPanel* m_tooltip_window;\n\nprivate:\n\tvoid OnPaintEvent(wxPaintEvent& event);\n\tvoid OnMouseMoveEvent(wxMouseEvent& event);\n\tvoid OnKeyDownEvent(wxKeyEvent& event);\n\tvoid OnKeyUpEvent(wxKeyEvent& event);\n\tvoid OnMouseDownEvent(wxMouseEvent& event);\n\tvoid OnMouseUpEvent(wxMouseEvent& event);\n\tvoid OnMouseDClickEvent(wxMouseEvent& event);\n\tvoid OnContextMenu(wxContextMenuEvent& event);\n\tvoid OnTooltipTimer(wxTimerEvent& event);\n\n\tstd::unordered_map<sint32, bool> m_key_states;\n\n\twxFont m_font;\n\t\n\twxTimer* m_tooltip_timer;\n\twxPoint m_mouse_position;\n};\n"
  },
  {
    "path": "src/gui/wxgui/components/wxDownloadManagerList.cpp",
    "content": "#include \"wxgui/components/wxDownloadManagerList.h\"\n\n#include \"wxHelper.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"util/helpers/SystemException.h\"\n#include \"Cafe/TitleList/GameInfo.h\"\n#include \"wxgui/components/wxGameList.h\"\n#include \"wxgui/helpers/wxCustomEvents.h\"\n\n#include <wx/wupdlock.h>\n#include <wx/menu.h>\n#include <wx/msgdlg.h>\n#include <wx/stattext.h>\n#include <wx/sizer.h>\n#include <wx/timer.h>\n#include <wx/panel.h>\n\n#include <functional>\n\n#include \"config/ActiveSettings.h\"\n#include \"wxgui/ChecksumTool.h\"\n#include \"Cemu/Tools/DownloadManager/DownloadManager.h\"\n#include \"Cafe/TitleList/TitleId.h\"\n#include \"wxgui/MainWindow.h\"\n\nwxDEFINE_EVENT(wxEVT_REMOVE_ENTRY, wxCommandEvent);\n\nwxDownloadManagerList::wxDownloadManagerList(wxWindow* parent, wxWindowID id)\n\t: wxListView(parent, id, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_VIRTUAL)\n{\n\tAddColumns();\n\n\t// tooltip TODO: extract class mb wxPanelTooltip\n\tm_tooltip_window = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);\n\tauto* tooltip_sizer = new wxBoxSizer(wxVERTICAL);\n\tm_tooltip_text = new wxStaticText(m_tooltip_window, wxID_ANY, wxEmptyString);\n\ttooltip_sizer->Add(m_tooltip_text , 0, wxALL, 5);\n\tm_tooltip_window->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));\n\tm_tooltip_window->SetSizerAndFit(tooltip_sizer);\n\tm_tooltip_window->Hide();\n\tm_tooltip_timer = new wxTimer(this);\n\n\tBind(wxEVT_LIST_COL_CLICK, &wxDownloadManagerList::OnColumnClick, this);\n\tBind(wxEVT_CONTEXT_MENU, &wxDownloadManagerList::OnContextMenu, this);\n\tBind(wxEVT_LIST_ITEM_SELECTED, &wxDownloadManagerList::OnItemSelected, this);\n\tBind(wxEVT_TIMER, &wxDownloadManagerList::OnTimer, this);\n\tBind(wxEVT_REMOVE_ITEM, &wxDownloadManagerList::OnRemoveItem, this);\n\tBind(wxEVT_REMOVE_ENTRY, &wxDownloadManagerList::OnRemoveEntry, this);\n\tBind(wxEVT_CLOSE_WINDOW, &wxDownloadManagerList::OnClose, this);\n\n\tShowSortIndicator(ColumnName);\n}\n\nboost::optional<const wxDownloadManagerList::TitleEntry&> wxDownloadManagerList::GetSelectedTitleEntry() const\n{\n\tconst auto selection = GetFirstSelected();\n\tif (selection != wxNOT_FOUND)\n\t{\n\t\tconst auto tmp = GetTitleEntry(selection);\n\t\tif (tmp.has_value())\n\t\t\treturn tmp.value();\n\t}\n\n\treturn {};\n}\n\nboost::optional<wxDownloadManagerList::TitleEntry&> wxDownloadManagerList::GetSelectedTitleEntry()\n{\n\tconst auto selection = GetFirstSelected();\n\tif (selection != wxNOT_FOUND)\n\t{\n\t\tconst auto tmp = GetTitleEntry(selection);\n\t\tif (tmp.has_value())\n\t\t\treturn tmp.value();\n\t}\n\n\treturn {};\n}\n\nboost::optional<wxDownloadManagerList::TitleEntry&> wxDownloadManagerList::GetTitleEntry(uint64 titleId, uint16 titleVersion)\n{\n\tfor(const auto& v : m_data)\n\t{\n\t\tif (v->entry.titleId == titleId && v->entry.version == titleVersion)\n\t\t\treturn v->entry;\n\t}\n\n\treturn {};\n}\n\nvoid wxDownloadManagerList::AddColumns()\n{\n\twxListItem col0;\n\tcol0.SetId(ColumnTitleId);\n\tcol0.SetText(_(\"Title ID\"));\n\tcol0.SetWidth(120);\n\tInsertColumn(ColumnTitleId, col0);\n\n\twxListItem col1;\n\tcol1.SetId(ColumnName);\n\tcol1.SetText(_(\"Name\"));\n\tcol1.SetWidth(260);\n\tInsertColumn(ColumnName, col1);\n\n\twxListItem col2;\n\tcol2.SetId(ColumnVersion);\n\tcol2.SetText(_(\"Version\"));\n\tcol2.SetWidth(55);\n\tInsertColumn(ColumnVersion, col2);\n\n\twxListItem col3;\n\tcol3.SetId(ColumnType);\n\tcol3.SetText(_(\"Type\"));\n\tcol3.SetWidth(60);\n\tInsertColumn(ColumnType, col3);\n\n\twxListItem col4;\n\tcol4.SetId(ColumnProgress);\n\tcol4.SetText(_(\"Progress\"));\n\tcol4.SetWidth(wxLIST_AUTOSIZE_USEHEADER);\n\tInsertColumn(ColumnProgress, col4);\n\t\n\twxListItem col5;\n\tcol5.SetId(ColumnStatus);\n\tcol5.SetText(_(\"Status\"));\n\tcol5.SetWidth(240);\n\tInsertColumn(ColumnStatus, col5);\n}\n\nwxString wxDownloadManagerList::OnGetItemText(long item, long column) const\n{\n\tif (item >= GetItemCount())\n\t\treturn wxEmptyString;\n\n\tconst auto entry = GetTitleEntry(item);\n\tif (entry.has_value())\n\t\treturn GetTitleEntryText(entry.value(), (ItemColumn)column);\n\n\treturn wxEmptyString;\n}\n\nwxItemAttr* wxDownloadManagerList::OnGetItemAttr(long item) const\n{\n\tconst auto entry = GetTitleEntry(item);\n\n\tconst wxColour bgColour = GetBackgroundColour();\n\tconst bool isDarkTheme = wxSystemSettings::GetAppearance().IsDark();\n\n\tif (entry.has_value())\n\t{\n\t\tauto& entryData = entry.value();\n\t\tif (entryData.status == TitleDownloadStatus::Downloading ||\n\t\t\tentryData.status == TitleDownloadStatus::Verifying ||\n\t\t\tentryData.status == TitleDownloadStatus::Installing)\n\t\t{\n\t\t\tconst wxColour kActiveColor = isDarkTheme ? wxColour(80, 40, 40) : wxColour(0xFFE0E0);\n\t\t\tstatic wxListItemAttr s_active_attr;\n\t\t\ts_active_attr.SetBackgroundColour(kActiveColor);\n\t\t\ts_active_attr.SetTextColour(GetTextColour());\n\t\t\ts_active_attr.SetFont(GetFont());\n\t\t\treturn &s_active_attr;\n\t\t}\n\t\telse if (entryData.status == TitleDownloadStatus::Installed && entryData.isPackage)\n\t\t{\n\t\t\tconst wxColour kActiveColor = isDarkTheme ? wxColour(40, 80, 40) : wxColour(0xE0FFE0);\n\t\t\tstatic wxListItemAttr s_installed_attr;\n\t\t\ts_installed_attr.SetBackgroundColour(kActiveColor);\n\t\t\ts_installed_attr.SetTextColour(GetTextColour());\n\t\t\ts_installed_attr.SetFont(GetFont());\n\t\t\treturn &s_installed_attr;\n\t\t}\n\t\telse if (entryData.status == TitleDownloadStatus::Error)\n\t\t{\n\t\t\tconst wxColour kActiveColor = isDarkTheme ? wxColour(40, 40, 80) : wxColour(0xCCCCF2);\n\t\t\tstatic wxListItemAttr s_error_attr;\n\t\t\ts_error_attr.SetBackgroundColour(kActiveColor);\n\t\t\ts_error_attr.SetTextColour(GetTextColour());\n\t\t\ts_error_attr.SetFont(GetFont());\n\t\t\treturn &s_error_attr;\n\t\t}\n\t}\n\n\twxColour bgColourSecondary = wxHelper::CalculateAccentColour(bgColour);\n\tstatic wxListItemAttr s_coloured_attr;\n\ts_coloured_attr.SetBackgroundColour(bgColourSecondary);\n\ts_coloured_attr.SetTextColour(GetTextColour());\n\ts_coloured_attr.SetFont(GetFont());\n\treturn item % 2 == 0 ? nullptr : &s_coloured_attr;\n}\n\nboost::optional<wxDownloadManagerList::TitleEntry&> wxDownloadManagerList::GetTitleEntry(long item)\n{\n\tlong counter = 0;\n\tfor (const auto& data : m_sorted_data)\n\t{\n\t\tif (!data.get().visible)\n\t\t\tcontinue;\n\n\t\tif (item != counter++)\n\t\t\tcontinue;\n\n\t\treturn data.get().entry;\n\t}\n\t\n\treturn {};\n}\n\nboost::optional<const wxDownloadManagerList::TitleEntry&> wxDownloadManagerList::GetTitleEntry(long item) const\n{\n\tlong counter = 0;\n\tfor (const auto& data : m_sorted_data)\n\t{\n\t\tif (!data.get().visible)\n\t\t\tcontinue;\n\n\t\tif (item != counter++)\n\t\t\tcontinue;\n\n\t\treturn data.get().entry;\n\t}\n\n\treturn {};\n}\n\nvoid wxDownloadManagerList::OnClose(wxCloseEvent& event)\n{\n\tevent.Skip();\n\t// wait until all tasks are complete\n\tif (m_context_worker.valid())\n\t\tm_context_worker.get();\n\tg_mainFrame->RequestGameListRefresh(); // todo: add games instead of fully refreshing game list if a game is downloaded\n}\n\nvoid wxDownloadManagerList::OnColumnClick(wxListEvent& event)\n{\n\tconst int column = event.GetColumn();\n\n\tSortEntries(column);\n\tevent.Skip();\n}\n\nvoid wxDownloadManagerList::RemoveItem(long item)\n{\n\tconst int item_count = GetItemCount();\n\n\tconst ItemData* ref = nullptr;\n\tlong counter = 0;\n\tfor(auto it = m_sorted_data.begin(); it != m_sorted_data.end(); ++it)\n\t{\n\t\tif (!it->get().visible)\n\t\t\tcontinue;\n\n\t\tif (item != counter++)\n\t\t\tcontinue;\n\n\t\tref = &(it->get());\n\t\tm_sorted_data.erase(it);\n\t\tbreak;\n\t}\n\n\t// shouldn't happen\n\tif (ref == nullptr)\n\t\treturn;\n\t\n\tfor(auto it = m_data.begin(); it != m_data.end(); ++it)\n\t{\n\t\tif (ref != (*it).get())\n\t\t\tcontinue;\n\t\t\n\t\tm_data.erase(it);\n\t\tbreak;\n\t}\n\n\tSetItemCount(std::max(0, item_count - 1));\n\tRefreshPage();\n}\n\nvoid wxDownloadManagerList::RemoveItem(const TitleEntry& entry)\n{\n\tconst int item_count = GetItemCount();\n\n\tconst TitleEntry* ref = &entry;\n\tfor (auto it = m_sorted_data.begin(); it != m_sorted_data.end(); ++it)\n\t{\n\t\tif (ref != &it->get().entry)\n\t\t\tcontinue;\n\n\t\tm_sorted_data.erase(it);\n\t\tbreak;\n\t}\n\n\tfor (auto it = m_data.begin(); it != m_data.end(); ++it)\n\t{\n\t\tif (ref != &(*it).get()->entry)\n\t\t\tcontinue;\n\n\t\tm_data.erase(it);\n\t\tbreak;\n\t}\n\n\tSetItemCount(std::max(0, item_count - 1));\n\tRefreshPage();\n}\n\nvoid wxDownloadManagerList::OnItemSelected(wxListEvent& event)\n{\n\tevent.Skip();\n\tm_tooltip_timer->Stop();\n\tconst auto selection = event.GetIndex();\n\n\tif (selection == wxNOT_FOUND)\n\t{\n\t\tm_tooltip_window->Hide();\n\t\treturn;\n\t}\n\n}\n\nenum ContextMenuEntries\n{\n\tkContextMenuRetry = wxID_HIGHEST + 1,\n\tkContextMenuDownload,\n\tkContextMenuPause,\n\tkContextMenuResume,\n};\nvoid wxDownloadManagerList::OnContextMenu(wxContextMenuEvent& event)\n{\n\t// still doing work\n\tif (m_context_worker.valid() && !future_is_ready(m_context_worker))\n\t\treturn;\n\t\n\twxMenu menu;\n\tmenu.Bind(wxEVT_COMMAND_MENU_SELECTED, &wxDownloadManagerList::OnContextMenuSelected, this);\n\n\tconst auto selection = GetFirstSelected();\n\tif (selection == wxNOT_FOUND)\n\t\treturn;\n\n\tconst auto entry = GetTitleEntry(selection);\n\tif (!entry.has_value())\n\t\treturn;\n\n\tif (entry->isPaused)\n\t\tmenu.Append(kContextMenuResume, _(\"&Resume\"));\n\telse if (entry->status == TitleDownloadStatus::Error)\n\t\tmenu.Append(kContextMenuRetry, _(\"&Retry\"));\n\telse if(entry->status == TitleDownloadStatus::Available)\n\t\tmenu.Append(kContextMenuDownload, _(\"&Download\"));\n\t//else if(entry->status == TitleDownloadStatus::Downloading || entry->status == TitleDownloadStatus::Initializing)\n\t//\tmenu.Append(kContextMenuPause, _(\"&Pause\")); buggy!\n\n\tPopupMenu(&menu);\n\t\n\t// TODO: fix tooltip position\n}\n\nvoid wxDownloadManagerList::SetCurrentDownloadMgr(DownloadManager* dlMgr)\n{\n\tstd::unique_lock<std::mutex> _l(m_dlMgrMutex);\n\tm_dlMgr = dlMgr;\n}\n\nbool wxDownloadManagerList::StartDownloadEntry(const TitleEntry& entry)\n{\n\tstd::unique_lock<std::mutex> _l(m_dlMgrMutex);\n\tif (m_dlMgr)\n\t\tm_dlMgr->initiateDownload(entry.titleId, entry.version);\n\treturn true;\n}\n\nbool wxDownloadManagerList::RetryDownloadEntry(const TitleEntry& entry)\n{\n\tStartDownloadEntry(entry);\n\treturn true;\n}\n\nbool wxDownloadManagerList::PauseDownloadEntry(const TitleEntry& entry)\n{\n\tstd::unique_lock<std::mutex> _l(m_dlMgrMutex);\n\tif (m_dlMgr)\n\t\tm_dlMgr->pauseDownload(entry.titleId, entry.version);\n\treturn true;\n}\n\nvoid wxDownloadManagerList::OnContextMenuSelected(wxCommandEvent& event)\n{\n\t// still doing work\n\tif (m_context_worker.valid() && !future_is_ready(m_context_worker))\n\t\treturn;\n\n\tconst auto selection = GetFirstSelected();\n\tif (selection == wxNOT_FOUND)\n\t\treturn;\n\n\tconst auto entry = GetTitleEntry(selection);\n\tif (!entry.has_value())\n\t\treturn;\n\t\n\tswitch (event.GetId())\n\t{\n\tcase kContextMenuDownload:\n\t\tStartDownloadEntry(entry.value());\n\t\tbreak;\n\tcase kContextMenuRetry:\n\t\tRetryDownloadEntry(entry.value());\n\t\tbreak;\n\tcase kContextMenuResume:\n\t\tStartDownloadEntry(entry.value());\n\t\tbreak;\n\tcase kContextMenuPause:\n\t\tPauseDownloadEntry(entry.value());\n\t\tbreak;\n\t}\n}\n\nvoid wxDownloadManagerList::OnTimer(wxTimerEvent& event)\n{\n\tif(event.GetTimer().GetId() != m_tooltip_timer->GetId())\n\t{\n\t\tevent.Skip();\n\t\treturn;\n\t}\n\n\tm_tooltip_window->Show();\n}\n\nvoid wxDownloadManagerList::OnRemoveItem(wxCommandEvent& event)\n{\n\tRemoveItem(event.GetInt());\n}\n\nvoid wxDownloadManagerList::OnRemoveEntry(wxCommandEvent& event)\n{\n\twxASSERT(event.GetClientData() != nullptr);\n\tRemoveItem(*(TitleEntry*)event.GetClientData());\n}\n\nwxString wxDownloadManagerList::GetTitleEntryText(const TitleEntry& entry, ItemColumn column)\n{\n\tswitch (column)\n\t{\n\tcase ColumnTitleId:\n\t\treturn formatWxString(\"{:08x}-{:08x}\", (uint32) (entry.titleId >> 32), (uint32) (entry.titleId & 0xFFFFFFFF));\n\tcase ColumnName:\n\t\treturn entry.name;\n\tcase ColumnType:\n\t\treturn GetTranslatedTitleEntryType(entry.type);\n\tcase ColumnVersion:\n\t{\n\t\t// dont show version for base game unless it is not v0\n\t\tif (entry.type == EntryType::Base && entry.version == 0)\n\t\t\treturn \"\";\n\t\tif (entry.type == EntryType::DLC && entry.version == 0)\n\t\t\treturn \"\";\n\t\treturn formatWxString(\"v{}\", entry.version);\n\t}\n\tcase ColumnProgress:\n\t{\n\t\tif (entry.status == TitleDownloadStatus::Downloading)\n\t\t{\n\t\t\tif (entry.progress >= 1000)\n\t\t\t\treturn \"100%\";\n\t\t\treturn formatWxString(\"{:.1f}%\", (float) entry.progress / 10.0f); // one decimal\n\t\t}\n\t\telse if (entry.status == TitleDownloadStatus::Installing || entry.status == TitleDownloadStatus::Checking || entry.status == TitleDownloadStatus::Verifying)\n\t\t{\n\t\t\treturn formatWxString(\"{0}/{1}\", entry.progress, entry.progressMax); // number of processed files/content files\n\t\t}\n\t\treturn \"\";\n\t}\n\tcase ColumnStatus:\n\t{\n\t\tif (entry.isPaused)\n\t\t\treturn _(\"Paused\");\n\t\telse if (entry.status == TitleDownloadStatus::Available)\n\t\t{\n\t\t\tif (entry.progress == 1)\n\t\t\t\treturn _(\"Not installed (Partially downloaded)\");\n\t\t\tif (entry.progress == 2)\n\t\t\t\treturn _(\"Update available\");\n\t\t\treturn _(\"Not installed\");\n\t\t}\n\t\telse if (entry.status == TitleDownloadStatus::Initializing)\n\t\t\treturn _(\"Initializing\");\n\t\telse if (entry.status == TitleDownloadStatus::Checking)\n\t\t\treturn _(\"Checking\");\n\t\telse if (entry.status == TitleDownloadStatus::Queued)\n\t\t\treturn _(\"Queued\");\n\t\telse if (entry.status == TitleDownloadStatus::Downloading)\n\t\t\treturn _(\"Downloading\");\n\t\telse if (entry.status == TitleDownloadStatus::Verifying)\n\t\t\treturn _(\"Verifying\");\n\t\telse if (entry.status == TitleDownloadStatus::Installing)\n\t\t\treturn _(\"Installing\");\n\t\telse if (entry.status == TitleDownloadStatus::Installed)\n\t\t\treturn _(\"Installed\");\n\t\telse if (entry.status == TitleDownloadStatus::Error)\n\t\t{\n\t\t\twxString errorStatusMsg = _(\"Error:\");\n\t\t\terrorStatusMsg.append(\" \");\n\t\t\terrorStatusMsg.append(entry.errorMsg);\n\t\t\treturn errorStatusMsg;\n\t\t}\n\t\telse\n\t\t\treturn \"Unknown status\";\n\t}\n\t}\n\t\n\treturn wxEmptyString;\n}\n\nwxString wxDownloadManagerList::GetTranslatedTitleEntryType(EntryType type)\n{\n\tswitch (type)\n\t{\n\t\tcase EntryType::Base:\n\t\t\treturn _(\"base\");\n\t\tcase EntryType::Update:\n\t\t\treturn _(\"update\");\n\t\tcase EntryType::DLC:\n\t\t\treturn _(\"DLC\");\n\t\tdefault:\n\t\t\treturn std::to_string(static_cast<std::underlying_type_t<EntryType>>(type));\n\t}\n}\n\nvoid wxDownloadManagerList::AddOrUpdateTitle(TitleEntryData_t* obj)\n{\n\tconst auto& data = obj->GetData();\n\t// if already in list only update\n\tauto entry = GetTitleEntry(data.titleId, data.version);\n\tif (entry.has_value())\n\t{\n\t\t// update item\n\t\tentry.value() = data;\n\t\tRefreshPage(); // more efficient way to do this?\n\t\treturn;\n\t}\n\n\tm_data.emplace_back(std::make_unique<ItemData>(true, data));\n\tm_sorted_data.emplace_back(*m_data[m_data.size() - 1]);\n\tSetItemCount(m_data.size());\n\n\t// reapply sort\n\tFilter2(m_filterShowTitles, m_filterShowUpdates, m_filterShowInstalled);\n\tSortEntries();\n}\n\nvoid wxDownloadManagerList::UpdateTitleStatusDepr(TitleEntryData_t* obj, const wxString& text)\n{\n\tconst auto& data = obj->GetData();\n\tconst auto entry = GetTitleEntry(data.titleId, data.version);\n\t// check if already added to list\n\tif (!entry.has_value())\n\t\treturn;\n\n\t// update gamelist text\n\tfor(size_t i = 0; i < m_sorted_data.size(); ++i)\n\t{\n\t\tif (m_sorted_data[i].get().entry == data)\n\t\t{\n\t\t\tSetItem(i, ColumnStatus, text);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tcemuLog_logDebug(LogType::Force, \"cant update title status of {:x}\", data.titleId);\n}\n\nint wxDownloadManagerList::AddImage(const wxImage& image) const\n{\n\treturn -1; // m_image_list->Add(image.Scale(kListIconWidth, kListIconWidth, wxIMAGE_QUALITY_BICUBIC));\n}\n\n// return <\nbool wxDownloadManagerList::SortFunc(std::span<int> sortColumnOrder, const Type_t& v1, const Type_t& v2)\n{\n\tcemu_assert_debug(sortColumnOrder.size() == 5);\n\n\t// visible have always priority\n\tif (!v1.get().visible && v2.get().visible)\n\t\treturn false;\n\telse if (v1.get().visible && !v2.get().visible)\n\t\treturn true;\n\n\tconst auto& entry1 = v1.get().entry;\n\tconst auto& entry2 = v2.get().entry;\n\t\n\tfor (size_t i = 0; i < sortColumnOrder.size(); i++)\n\t{\n\t\tint sortByColumn = sortColumnOrder[i];\n\t\tif (sortByColumn == ColumnTitleId)\n\t\t{\n\t\t\t// ensure strong ordering -> use type since only one entry should be now (should be changed if every save for every user is displayed spearately?)\n\t\t\tif (entry1.titleId != entry2.titleId)\n\t\t\t\treturn entry1.titleId < entry2.titleId;\n\t\t}\n\t\telse if (sortByColumn == ColumnName)\n\t\t{\n\t\t\tconst int tmp = entry1.name.CmpNoCase(entry2.name);\n\t\t\tif (tmp != 0)\n\t\t\t\treturn tmp < 0;\n\t\t}\n\t\telse if (sortByColumn == ColumnType)\n\t\t{\n\t\t\tif (std::underlying_type_t<EntryType>(entry1.type) != std::underlying_type_t<EntryType>(entry2.type))\n\t\t\t\treturn std::underlying_type_t<EntryType>(entry1.type) < std::underlying_type_t<EntryType>(entry2.type);\n\t\t}\n\t\telse if (sortByColumn == ColumnVersion)\n\t\t{\n\t\t\tif (entry1.version != entry2.version)\n\t\t\t\treturn entry1.version < entry2.version;\n\t\t}\n\t\telse if (sortByColumn == ColumnProgress)\n\t\t{\n\t\t\tif (entry1.progress != entry2.progress)\n\t\t\treturn entry1.progress < entry2.progress;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn (uintptr_t)&entry1 < (uintptr_t)&entry2;\n\t\t}\n\n\t}\n\n\treturn false;\n}\n\n#include <boost/container/small_vector.hpp>\n\nvoid wxDownloadManagerList::SortEntries(int column)\n{\n\tboost::container::small_vector<int, 12> s_SortColumnOrder{ ColumnName, ColumnType, ColumnVersion, ColumnTitleId, ColumnProgress };\n\n\tbool ascending;\n\tif (column == -1)\n\t{\n\t\tcolumn = GetSortIndicator();\n\t\tif (column == -1)\n\t\t\tcolumn = ColumnName;\n\t\tascending = IsAscendingSortIndicator();\n\t}\n\telse\n\t\tascending = GetUpdatedAscendingSortIndicator(column);\n\n\t// prioritize column by moving it to first position in the column sort order list\n\ts_SortColumnOrder.erase(std::remove(s_SortColumnOrder.begin(), s_SortColumnOrder.end(), column), s_SortColumnOrder.end());\n\ts_SortColumnOrder.insert(s_SortColumnOrder.begin(), column);\n\n\tstd::sort(m_sorted_data.begin(), m_sorted_data.end(),\n\t\t\t  [this, &s_SortColumnOrder, ascending](const Type_t& v1, const Type_t& v2) -> bool {\n\t\t\t\t  return ascending ? SortFunc(s_SortColumnOrder, v1, v2) : SortFunc(s_SortColumnOrder, v2, v1);\n\t\t\t  });\n\n\tShowSortIndicator(column, ascending);\n\tRefreshPage();\n}\n\nvoid wxDownloadManagerList::RefreshPage()\n{\n\tlong item_count = GetItemCount();\n\n\tif (item_count > 0)\n\t\tRefreshItems(GetTopItem(), std::min(item_count - 1, GetTopItem() + GetCountPerPage() + 1));\n}\n\nint wxDownloadManagerList::Filter(const wxString& filter, const wxString& prefix, ItemColumn column)\n{\n\tif (prefix.empty())\n\t\treturn -1;\n\t\n\tif (!filter.StartsWith(prefix))\n\t\treturn -1;\n\n\tint counter = 0;\n\tconst auto tmp_filter = filter.substr(prefix.size() - 1).Trim(false);\n\tfor (auto&& data : m_data)\n\t{\n\t\tif (GetTitleEntryText(data->entry, column).Upper().Contains(tmp_filter))\n\t\t{\n\t\t\tdata->visible = true;\n\t\t\t++counter;\n\t\t}\n\t\telse\n\t\t\tdata->visible = false;\n\t}\n\treturn counter;\n}\n\nvoid wxDownloadManagerList::Filter(const wxString& filter)\n{\n\tif(filter.empty())\n\t{\n\t\tstd::for_each(m_data.begin(), m_data.end(), [](ItemDataPtr& data) { data->visible = true; });\n\t\tSetItemCount(m_data.size());\n\t\tRefreshPage();\n\t\treturn;\n\t}\n\n\tconst auto filter_upper = filter.Upper().Trim(false).Trim(true);\n\tint counter = 0;\n\t\n\tif (const auto result = Filter(filter_upper, \"TITLEID:\", ColumnTitleId) != -1)\n\t\tcounter = result;\n\telse if (const auto result = Filter(filter_upper, \"NAME:\", ColumnName) != -1)\n\t\tcounter = result;\n\telse if (const auto result = Filter(filter_upper, \"TYPE:\", ColumnType) != -1)\n\t\tcounter = result;\n\t//else if (const auto result = Filter(filter_upper, \"REGION:\", ColumnRegion) != -1)\n\t//\tcounter = result;\n\telse if (const auto result = Filter(filter_upper, \"VERSION:\", ColumnVersion) != -1)\n\t\tcounter = result;\n\telse if(filter_upper == \"ERROR\")\n\t{\n\t\tfor (auto&& data : m_data)\n\t\t{\n\t\t\tbool visible = false;\n\t\t\t//if (data->entry.error != TitleError::None)\n\t\t\t//\tvisible = true;\n\n\t\t\tdata->visible = visible;\n\t\t\tif (visible)\n\t\t\t\t++counter;\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (auto&& data : m_data)\n\t\t{\n\t\t\tbool visible = false;\n\t\t\tif (data->entry.name.Upper().Contains(filter_upper))\n\t\t\t\tvisible = true;\n\t\t\telse if (GetTitleEntryText(data->entry, ColumnTitleId).Upper().Contains(filter_upper))\n\t\t\t\tvisible = true;\n\t\t\telse if (GetTitleEntryText(data->entry, ColumnType).Upper().Contains(filter_upper))\n\t\t\t\tvisible = true;\n\n\t\t\tdata->visible = visible;\n\t\t\tif (visible)\n\t\t\t\t++counter;\n\t\t}\n\t}\n\t\n\tSetItemCount(counter);\n\tRefreshPage();\n}\n\nvoid wxDownloadManagerList::Filter2(bool showTitles, bool showUpdates, bool showInstalled)\n{\n\tm_filterShowTitles = showTitles;\n\tm_filterShowUpdates = showUpdates;\n\tm_filterShowInstalled = showInstalled;\n\tif (showTitles && showUpdates && showInstalled)\n\t{\n\t\tstd::for_each(m_data.begin(), m_data.end(), [](ItemDataPtr& data) { data->visible = true; });\n\t\tSetItemCount(m_data.size());\n\t\tRefreshPage();\n\t\treturn;\n\t}\n\n\tsize_t counter = 0;\n\n\tfor (auto&& data : m_data)\n\t{\n\t\tbool visible = false;\n\n\t\tTitleIdParser tParser(data->entry.titleId);\n\t\tbool isInstalled = data->entry.status == TitleDownloadStatus::Installed;\n\t\tif (tParser.IsBaseTitleUpdate())\n\t\t{\n\t\t\tif (showUpdates && (showInstalled || !isInstalled))\n\t\t\t\tvisible = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (showTitles && (showInstalled || !isInstalled))\n\t\t\t\tvisible = true;\n\t\t}\n\t\n\t\tdata->visible = visible;\n\t\tif (visible)\n\t\t\t++counter;\n\t}\n\n\tSetItemCount(counter);\n\tRefreshPage();\n}\n\nsize_t wxDownloadManagerList::GetCountByType(EntryType type) const\n{\n\tsize_t result = 0;\n\tfor(const auto& data : m_data)\n\t{\n\t\tif (data->entry.type == type)\n\t\t\t++result;\n\t}\n\treturn result;\n}\n\nvoid wxDownloadManagerList::ClearItems()\n{\n\tm_sorted_data.clear();\n\tm_data.clear();\n\tSetItemCount(0);\n\tRefreshPage();\n}\n\nvoid wxDownloadManagerList::AutosizeColumns()\n{\n\twxAutosizeColumns(this, ColumnTitleId, ColumnMAX - 1);\n}\n\n"
  },
  {
    "path": "src/gui/wxgui/components/wxDownloadManagerList.h",
    "content": "#pragma once\n\n#include \"wxgui/helpers/wxCustomData.h\"\n#include \"config/CemuConfig.h\"\n\n#include <wx/listctrl.h>\n\n#include <boost/optional.hpp> // std::optional doesn't support optional reference inner types yet\n#include <utility>\n#include <vector>\n\nclass wxDownloadManagerList : public wxListView\n{\n\tfriend class TitleManager;\npublic:\n\twxDownloadManagerList(wxWindow* parent, wxWindowID id = wxID_ANY);\n\t\n\tenum ItemColumn\n\t{\n\t\tColumnTitleId = 0,\n\t\tColumnName,\n\t\tColumnVersion,\n\t\tColumnType,\n\t\tColumnProgress,\n\t\tColumnStatus,\n\n\t\tColumnMAX,\n\t};\n\n\tenum class EntryType\n\t{\n\t\tBase,\n\t\tUpdate,\n\t\tDLC,\n\t};\n\n\tenum class TitleDownloadStatus\n\t{\n\t\tNone,\n\t\tAvailable, // available for download\n\t\tError, // error state\n\t\tQueued, // queued for download\n\t\tInitializing, // downloading/parsing TMD\n\t\tChecking, // checking for previously downloaded files\n\t\tDownloading,\n\t\tVerifying, // verifying downloaded files\n\t\tInstalling,\n\t\tInstalled,\n\t\t// error state?\n\t};\n\n\tvoid SortEntries(int column = -1);\n\tvoid RefreshPage();\n\tvoid Filter(const wxString& filter);\n\tvoid Filter2(bool showTitles, bool showUpdates, bool showInstalled);\n\t[[nodiscard]] size_t GetCountByType(EntryType type) const;\n\tvoid ClearItems();\n\tvoid AutosizeColumns();\n\n\tstruct TitleEntry\n\t{\n\t\tTitleEntry(const EntryType& type, bool isPackage, uint64 titleId, uint16 version, bool isPaused)\n\t\t\t: type(type), isPackage(isPackage), titleId(titleId), version(version), isPaused(isPaused) {}\n\n\t\tEntryType type;\n\n\t\tbool isPaused{};\n\t\tint icon = -1;\n\t\tbool isPackage;\n\t\tuint64 titleId;\n\t\twxString name;\n\t\tuint32_t version{ 0 };\n\t\tuint32 progress; // downloading: in 1/10th of a percent, installing: number of files\n\t\tuint32 progressMax{ 0 };\n\t\tCafeConsoleRegion region;\n\n\t\tTitleDownloadStatus status = TitleDownloadStatus::None;\n\t\tstd::string errorMsg;\n\n\t\tbool operator==(const TitleEntry& e) const\n\t\t{\n\t\t\treturn type == e.type && titleId == e.titleId && version == e.version;\n\t\t}\n\t\tbool operator!=(const TitleEntry& e) const { return !(*this == e); }\n\t};\n\tboost::optional<const TitleEntry&> GetSelectedTitleEntry() const;\n\nprivate:\n\tvoid AddColumns();\n\tint Filter(const wxString& filter, const wxString& prefix, ItemColumn column);\n\tboost::optional<TitleEntry&> GetSelectedTitleEntry();\n\tboost::optional<TitleEntry&> GetTitleEntry(uint64 titleId, uint16 titleVersion);\n\t\n\tclass wxPanel* m_tooltip_window;\n\tclass wxStaticText* m_tooltip_text;\n\tclass wxTimer* m_tooltip_timer;\n\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid OnColumnClick(wxListEvent& event);\n\tvoid OnContextMenu(wxContextMenuEvent& event);\n\tvoid OnItemSelected(wxListEvent& event);\n\tvoid OnContextMenuSelected(wxCommandEvent& event);\n\tvoid OnTimer(class wxTimerEvent& event);\n\tvoid OnRemoveItem(wxCommandEvent& event);\n\tvoid OnRemoveEntry(wxCommandEvent& event);\n\n\tusing TitleEntryData_t = wxCustomData<TitleEntry>;\n\tvoid AddOrUpdateTitle(TitleEntryData_t* obj);\n\tvoid UpdateTitleStatusDepr(TitleEntryData_t* obj, const wxString& text);\n\tint AddImage(const wxImage& image) const;\n\twxString OnGetItemText(long item, long column) const override;\n\twxItemAttr* OnGetItemAttr(long item) const override;\n\t[[nodiscard]] boost::optional<const TitleEntry&> GetTitleEntry(long item) const;\n\t[[nodiscard]] boost::optional<TitleEntry&> GetTitleEntry(long item);\n\t//[[nodiscard]] boost::optional<const TitleEntry&> GetTitleEntry(const fs::path& path) const;\n\t//[[nodiscard]] boost::optional<TitleEntry&> GetTitleEntry(const fs::path& path);\n\t\n\tvoid SetCurrentDownloadMgr(class DownloadManager* dlMgr);\n\n\t//bool FixEntry(TitleEntry& entry);\n\t//bool VerifyEntryFiles(TitleEntry& entry);\n\tbool StartDownloadEntry(const TitleEntry& entry);\n\tbool RetryDownloadEntry(const TitleEntry& entry);\n\tbool PauseDownloadEntry(const TitleEntry& entry);\n\n\tvoid RemoveItem(long item);\n\tvoid RemoveItem(const TitleEntry& entry);\n\t\n\tstruct ItemData\n\t{\n\t\tItemData(bool visible, const TitleEntry& entry)\n\t\t\t: visible(visible), entry(entry) {}\n\t\t\n\t\tbool visible;\n\t\tTitleEntry entry;\n\t};\n\tusing ItemDataPtr = std::unique_ptr<ItemData>;\n\tstd::vector<ItemDataPtr> m_data;\n\tstd::vector<std::reference_wrapper<ItemData>> m_sorted_data;\n\n\tbool m_filterShowTitles = true;\n\tbool m_filterShowUpdates = true;\n\tbool m_filterShowInstalled = true;\n\tDownloadManager* m_dlMgr{};\n\tstd::mutex m_dlMgrMutex;\n\tusing Type_t = std::reference_wrapper<const ItemData>;\n\tbool SortFunc(std::span<int> sortColumnOrder, const Type_t& v1, const Type_t& v2);\n\n\tstatic wxString GetTitleEntryText(const TitleEntry& entry, ItemColumn column);\n\tstatic wxString GetTranslatedTitleEntryType(EntryType entryType);\n\tstd::future<bool> m_context_worker;\n};\n"
  },
  {
    "path": "src/gui/wxgui/components/wxGameList.cpp",
    "content": "#include \"wxgui/components/wxGameList.h\"\n\n#include \"wxgui/helpers/wxCustomData.h\"\n#include \"wxCemuConfig.h\"\n#include \"util/helpers/helpers.h\"\n#include \"wxgui/GameProfileWindow.h\"\n\n#include <numeric>\n\n#include <wx/listctrl.h>\n#include <wx/wupdlock.h>\n#include <wx/menu.h>\n#include <wx/mstream.h>\n#include <wx/imaglist.h>\n#include <wx/textdlg.h>\n#include <wx/stattext.h>\n#include <wx/sizer.h>\n#include <wx/wfstream.h>\n#include <wx/imagpng.h>\n#include <wx/string.h>\n#include <wx/utils.h>\n#include <wx/clipbrd.h>\n\n#include <boost/algorithm/string.hpp>\n#include <boost/tokenizer.hpp>\n\n#include \"config/ActiveSettings.h\"\n#include \"config/LaunchSettings.h\"\n#include \"Cafe/TitleList/GameInfo.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n\n#include \"wxgui/CemuApp.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/MainWindow.h\"\n\n#include \"../wxHelper.h\"\n\n#include \"Cafe/IOSU/PDM/iosu_pdm.h\" // for last played and play time\n\n#if BOOST_OS_WINDOWS\n// for shortcut creation\n#include <windows.h>\n#include <winnls.h>\n#include <shobjidl.h>\n#include <objbase.h>\n#include <objidl.h>\n#include <shlguid.h>\n#include <shlobj.h>\n#include <wrl/client.h>\n#endif\n\n// public events\nwxDEFINE_EVENT(wxEVT_OPEN_SETTINGS, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_GAMELIST_BEGIN_UPDATE, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_GAMELIST_END_UPDATE, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_OPEN_GRAPHIC_PACK, wxTitleIdEvent);\n\n// internal events\nwxDEFINE_EVENT(wxEVT_GAME_ENTRY_ADDED_OR_REMOVED, wxTitleIdEvent);\n\nconstexpr uint64 kDefaultEntryData = 0x1337;\n\nvoid _stripPathFilename(fs::path& path)\n{\n\tif (path.has_extension())\n\t\tpath = path.parent_path();\n}\n\nstd::vector<fs::path> _getCachesPaths(const TitleId& titleId)\n{\n\tstd::vector<fs::path> cachePaths{\n\t\tActiveSettings::GetCachePath(L\"shaderCache/driver/vk/{:016x}.bin\", titleId),\n\t\tActiveSettings::GetCachePath(L\"shaderCache/precompiled/{:016x}_spirv.bin\", titleId),\n\t\tActiveSettings::GetCachePath(L\"shaderCache/precompiled/{:016x}_gl.bin\", titleId),\n\t\tActiveSettings::GetCachePath(L\"shaderCache/precompiled/{:016x}_air.bin\", titleId),\n\t\tActiveSettings::GetCachePath(L\"shaderCache/transferable/{:016x}_shaders.bin\", titleId),\n\t\tActiveSettings::GetCachePath(L\"shaderCache/transferable/{:016x}_mtlshaders.bin\", titleId),\n\t\tActiveSettings::GetCachePath(L\"shaderCache/transferable/{:016x}_vkpipeline.bin\", titleId),\n\t\tActiveSettings::GetCachePath(L\"shaderCache/transferable/{:016x}_mtlpipeline.bin\", titleId)};\n\n\tcachePaths.erase(std::remove_if(cachePaths.begin(), cachePaths.end(),\n\t\t\t\t\t\t\t\t\t[](const fs::path& cachePath) {\n\t\t\t\t\t\t\t\t\t\tstd::error_code ec;\n\t\t\t\t\t\t\t\t\t\treturn !fs::exists(cachePath, ec);\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t cachePaths.end());\n\n\treturn cachePaths;\n}\n\n// Convert PNG to Apple icon image format\nbool writeICNS(const fs::path& pngPath, const fs::path& icnsPath) {\n\t// Read PNG file\n\tstd::ifstream pngFile(pngPath, std::ios::binary);\n\tif (!pngFile)\n\t\treturn false;\n\n\t// Get PNG size\n\tpngFile.seekg(0, std::ios::end);\n\tuint32 pngSize = static_cast<uint32>(pngFile.tellg());\n\tpngFile.seekg(0, std::ios::beg);\n\n\t// Calculate total file size (header + size + type + data)\n\tuint32 totalSize = 8 + 8 + pngSize;\n\n\t// Create output file\n\tstd::ofstream icnsFile(icnsPath, std::ios::binary);\n\tif (!icnsFile)\n\t\treturn false;\n\n\t// Write ICNS header\n\ticnsFile.put(0x69); // 'i'\n\ticnsFile.put(0x63); // 'c'\n\ticnsFile.put(0x6e); // 'n'\n\ticnsFile.put(0x73); // 's'\n\n\t// Write total file size (big endian)\n\ticnsFile.put((totalSize >> 24) & 0xFF);\n\ticnsFile.put((totalSize >> 16) & 0xFF);\n\ticnsFile.put((totalSize >> 8) & 0xFF);\n\ticnsFile.put(totalSize & 0xFF);\n\n\t// Write icon type (ic07 = 128x128 PNG)\n\ticnsFile.put(0x69); // 'i'\n\ticnsFile.put(0x63); // 'c'\n\ticnsFile.put(0x30); // '0'\n\ticnsFile.put(0x37); // '7'\n\n\t// Write PNG size (big endian)\n\ticnsFile.put((pngSize >> 24) & 0xFF);\n\ticnsFile.put((pngSize >> 16) & 0xFF);\n\ticnsFile.put((pngSize >> 8) & 0xFF);\n\ticnsFile.put(pngSize & 0xFF);\n\n\t// Copy PNG data\n\ticnsFile << pngFile.rdbuf();\n\n\treturn true;\n}\n\nwxGameList::wxGameList(wxWindow* parent, wxWindowID id)\n\t: wxListView(parent, id, wxDefaultPosition, wxDefaultSize, GetStyleFlags(Style::kList)), m_style(Style::kList)\n{\n\tconst auto& config = GetWxGUIConfig();\n\n\tchar transparent_bitmap[kIconWidth * kIconWidth * 4] = {};\n\tmemset(transparent_bitmap, wxSystemSettings::GetAppearance().IsDark() ? 0xFF : 0x00, sizeof(transparent_bitmap));\n\twxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth);\n\n\tm_image_list_data.Add(blank);\n\twxListCtrl::SetImageList(&m_image_list_data, wxIMAGE_LIST_NORMAL);\n\n\twxBitmap::Rescale(blank, {kListIconWidth, kListIconWidth});\n\tm_image_list_small_data.Add(blank);\n\twxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_SMALL);\n\n\tInsertColumn(ColumnHiddenName, \"\", wxLIST_FORMAT_LEFT, 0);\n\tif(config.show_icon_column)\n\t\tInsertColumn(ColumnIcon, _(\"Icon\"), wxLIST_FORMAT_LEFT, GetColumnDefaultWidth(ColumnIcon));\n\telse\n\t\tInsertColumn(ColumnIcon, _(\"Icon\"), wxLIST_FORMAT_LEFT, 0);\n\tInsertColumn(ColumnName, _(\"Game\"), wxLIST_FORMAT_LEFT, config.column_width.name);\n\tInsertColumn(ColumnVersion, _(\"Version\"), wxLIST_FORMAT_LEFT, config.column_width.version);\n\tInsertColumn(ColumnDLC, _(\"DLC\"), wxLIST_FORMAT_LEFT, config.column_width.dlc);\n\tInsertColumn(ColumnGameTime, _(\"You've played\"), wxLIST_FORMAT_LEFT, config.column_width.game_time);\n\tInsertColumn(ColumnGameStarted, _(\"Last played\"), wxLIST_FORMAT_LEFT, config.column_width.game_started);\n\tInsertColumn(ColumnRegion, _(\"Region\"), wxLIST_FORMAT_LEFT, config.column_width.region);\n    InsertColumn(ColumnTitleID, _(\"Title ID\"), wxLIST_FORMAT_LEFT, config.column_width.title_id);\n\n\tm_tooltip_window = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);\n\tauto* tooltip_sizer = new wxBoxSizer(wxVERTICAL);\n\ttooltip_sizer->Add(new wxStaticText(m_tooltip_window, wxID_ANY, _(\"This game entry seems to be either an update or the base game was merged with update data\\nBroken game dumps cause various problems during emulation and may even stop working at all in future Cemu versions\\nPlease make sure the base game is intact and install updates only with the File->Install Update/DLC option\")), 0, wxALL, 5);\n\tm_tooltip_window->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));\n\tm_tooltip_window->SetSizerAndFit(tooltip_sizer);\n\tm_tooltip_window->Hide();\n\n\tm_tooltip_timer = new wxTimer(this);\n\n\tBind(wxEVT_CLOSE_WINDOW, &wxGameList::OnClose, this);\n\tBind(wxEVT_MOTION, &wxGameList::OnMouseMove, this);\n\tBind(wxEVT_LIST_KEY_DOWN, &wxGameList::OnKeyDown, this);\n\tBind(wxEVT_CONTEXT_MENU, &wxGameList::OnContextMenu, this);\n\tBind(wxEVT_LIST_ITEM_ACTIVATED, &wxGameList::OnItemActivated, this);\n\tBind(wxEVT_GAME_ENTRY_ADDED_OR_REMOVED, &wxGameList::OnGameEntryUpdatedByTitleId, this);\n\tBind(wxEVT_TIMER, &wxGameList::OnTimer, this);\n\tBind(wxEVT_LEAVE_WINDOW, &wxGameList::OnLeaveWindow, this);\n\n\tBind(wxEVT_LIST_COL_CLICK, &wxGameList::OnColumnClick, this);\n\tBind(wxEVT_LIST_COL_BEGIN_DRAG, &wxGameList::OnColumnBeginResize, this);\n\tBind(wxEVT_LIST_COL_END_DRAG, &wxGameList::OnColumnResize, this);\n\tBind(wxEVT_LIST_COL_RIGHT_CLICK, &wxGameList::OnColumnRightClick, this);\n\tBind(wxEVT_SIZE, &wxGameList::OnGameListSize, this);\n\tm_bulkUpdateTimer.Bind(wxEVT_TIMER, &wxGameList::OnTimerBulkAddEntriesToGameList, this);\n\n\tm_callbackIdTitleList = CafeTitleList::RegisterCallback([](CafeTitleListCallbackEvent* evt, void* ctx) { ((wxGameList*)ctx)->HandleTitleListCallback(evt); }, this);\n\n\t// start async worker (for icon loading)\n\tm_async_worker_active = true;\n\tm_async_worker_thread = std::thread(&wxGameList::AsyncWorkerThread, this);\n\n\tShowSortIndicator(ColumnName);\n}\n\nwxGameList::~wxGameList()\n{\n\tCafeTitleList::UnregisterCallback(m_callbackIdTitleList);\n\n\tm_tooltip_timer->Stop();\n\n\t// shut down async worker\n\tm_async_worker_active.store(false);\n\tm_async_task_count.increment();\n\tm_async_worker_thread.join();\n\n\t// clear image cache\n\tm_icon_cache_mtx.lock();\n\tm_icon_cache.clear();\n\tm_icon_cache_mtx.unlock();\n}\n\nvoid wxGameList::LoadConfig()\n{\n\tconst auto& config = GetWxGUIConfig();\n\tSetStyle((Style)config.game_list_style, false);\n\n\tif (!config.game_list_column_order.empty())\n\t{\n\t\twxArrayInt order;\n\t\torder.reserve(ColumnCounts);\n\n\t\tconst auto order_string = std::string_view(config.game_list_column_order).substr(1);\n\n\t\tconst boost::char_separator<char> sep(\",\");\n\t\tboost::tokenizer tokens(order_string.begin(), order_string.end(), sep);\n\t\tfor(const auto& token : tokens)\n\t\t{\n\t\t\torder.push_back(ConvertString<int>(token, 10));\n\t\t}\n\n#ifdef wxHAS_LISTCTRL_COLUMN_ORDER\n\t\tif(order.GetCount() == ColumnCounts)\n\t\t\tSetColumnsOrder(order);\n#endif\n\t}\n}\n\nvoid wxGameList::OnGameListSize(wxSizeEvent &event)\n{\n\tevent.Skip();\n\n\t// when using a sizer-based layout, do not change the size of the wxComponent in its own wxSizeEvent handler to avoid some UI issues.\n\tint last_col_index = 0;\n\tfor(int i = GetColumnCount() - 1; i > 0; i--)\n\t{\n#ifdef wxHAS_LISTCTRL_COLUMN_ORDER\n\t\tif(GetColumnWidth(GetColumnIndexFromOrder(i)) > 0)\n\t\t{\n\t\t\tlast_col_index = GetColumnIndexFromOrder(i);\n\t\t\tbreak;\n\t\t}\n#else\n\t\tif(GetColumnWidth(i) > 0)\n\t\t{\n\t\t\tlast_col_index = i;\n\t\t\tbreak;\n\t\t}\n#endif\n\t}\n\twxListEvent column_resize_event(wxEVT_LIST_COL_END_DRAG);\n\tcolumn_resize_event.SetColumn(last_col_index);\n\twxPostEvent(this, column_resize_event);\n}\n\nvoid wxGameList::AdjustLastColumnWidth()\n{\n\twxWindowUpdateLocker windowlock(this);\n\tint last_col_index = 0;\n\tint last_col_width = GetClientSize().GetWidth();\n\tfor (int i = 1; i < GetColumnCount(); i++)\n\t{\n#ifdef wxHAS_LISTCTRL_COLUMN_ORDER\n\t\tif (GetColumnWidth(GetColumnIndexFromOrder(i)) > 0)\n\t\t{\n\t\t\tlast_col_index = GetColumnIndexFromOrder(i);\n\t\t\tlast_col_width -= GetColumnWidth(last_col_index);\n\t\t}\n#else\n\t\tif (GetColumnWidth(i) > 0)\n\t\t{\n\t\t\tlast_col_index = i;\n\t\t\tlast_col_width -= GetColumnWidth(i);\n\t\t}\n#endif\n\t}\n\tlast_col_width += GetColumnWidth(last_col_index);\n\tif (last_col_width < GetColumnDefaultWidth(last_col_index)) // keep a minimum width\n\t\tlast_col_width = GetColumnDefaultWidth(last_col_index);\n\tSetColumnWidth(last_col_index, last_col_width);\n}\n\n// todo: scale all columns using a ratio instead of hardcoding exact widths\nint wxGameList::GetColumnDefaultWidth(int column)\n{\n\tswitch (column)\n\t{\n\tcase ColumnIcon:\n\t\treturn kListIconWidth+2;\n\tcase ColumnName:\n\t\treturn DefaultColumnSize::name;\n\tcase ColumnVersion:\n\t\treturn DefaultColumnSize::version;\n\tcase ColumnDLC:\n\t\treturn DefaultColumnSize::dlc;\n\tcase ColumnGameTime:\n\t\treturn DefaultColumnSize::game_time;\n\tcase ColumnGameStarted:\n\t\treturn DefaultColumnSize::game_started;\n\tcase ColumnRegion:\n\t\treturn DefaultColumnSize::region;\n    case ColumnTitleID:\n        return DefaultColumnSize::title_id;\n\tdefault:\n\t\treturn 80;\n\t}\n}\n\nvoid wxGameList::SaveConfig(bool flush)\n{\n\tauto& config = GetWxGUIConfig();\n\n\tconfig.game_list_style = (int)m_style;\n\t#ifdef wxHAS_LISTCTRL_COLUMN_ORDER\n\tconfig.game_list_column_order = fmt::format(\"{}\", GetColumnsOrder());\n\t#endif\n\n\tif (flush)\n\t\tGetConfigHandle().Save();\n}\n\nbool wxGameList::IsVisible(long item) const\n{\n\twxRect itemRect;\n\tGetItemRect(item, itemRect);\n\tconst wxRect clientRect = GetClientRect();\n\tbool visible = clientRect.Intersects(itemRect);\n\treturn visible;\n}\n\nvoid wxGameList::ReloadGameEntries()\n{\n\twxWindowUpdateLocker windowlock(this);\n\tDeleteAllItems();\n\t// tell the game list to rescan\n\tCafeTitleList::Refresh();\n\t// resend notifications for all known titles by re-registering the callback\n\tCafeTitleList::UnregisterCallback(m_callbackIdTitleList);\n\tm_callbackIdTitleList = CafeTitleList::RegisterCallback([](CafeTitleListCallbackEvent* evt, void* ctx) { ((wxGameList*)ctx)->HandleTitleListCallback(evt); }, this);\n}\n\nlong wxGameList::FindListItemByTitleId(uint64 title_id) const\n{\n\tfor (int i = 0; i < GetItemCount(); ++i)\n\t{\n\t\tconst auto id = (uint64)GetItemData(i);\n\t\tif (id == title_id)\n\t\t\treturn i;\n\t}\n\n\treturn wxNOT_FOUND;\n}\n\n// get title name with cache\nstd::string wxGameList::GetNameByTitleId(uint64 titleId)\n{\n\tauto it = m_name_cache.find(titleId);\n\tif (it != m_name_cache.end())\n\t\treturn it->second;\n\tTitleInfo titleInfo;\n\tif (!CafeTitleList::GetFirstByTitleId(titleId, titleInfo))\n\t\treturn \"Unknown title\";\n\tstd::string name;\n\tif (!GetConfig().GetGameListCustomName(titleId, name))\n\t\tname = titleInfo.GetMetaTitleName();\n\tm_name_cache.emplace(titleId, name);\n\treturn name;\n}\n\nvoid wxGameList::SetStyle(Style style, bool save)\n{\n\tif (m_style == style)\n\t\treturn;\n\n\twxWindowUpdateLocker updatelock(this);\n\n\tm_style = style;\n\tSetWindowStyleFlag(GetStyleFlags(m_style));\n\n\tuint64 selected_title_id = 0;\n\tauto selection = GetFirstSelected();\n\tif (selection != wxNOT_FOUND)\n\t{\n\t\tselected_title_id = (uint64)GetItemData(selection);\n\t\tselection = wxNOT_FOUND;\n\t}\n\n\tswitch(style)\n\t{\n\tcase Style::kIcons:\n\t\twxListCtrl::SetImageList(&m_image_list_data, wxIMAGE_LIST_NORMAL);\n\t\tbreak;\n\tcase Style::kSmallIcons:\n\t\twxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_NORMAL);\n\t\tbreak;\n\tcase Style::kList:\n\t\twxListCtrl::SetImageList(&m_image_list_small_data, wxIMAGE_LIST_SMALL);\n\t\tbreak;\n\t}\n\n\tReloadGameEntries();\n\tSortEntries();\n\tUpdateItemColors();\n\n\tif(selection != wxNOT_FOUND)\n\t{\n\t\tSelect(selection);\n\t\tFocus(selection);\n\t}\n\n\tif(save)\n\t{\n\t\tGetWxGUIConfig().game_list_style = (int)m_style;\n\t\tGetConfigHandle().Save();\n\t}\n\n\tif (style == Style::kList)\n\t\tApplyGameListColumnWidths();\n}\n\nlong wxGameList::GetStyleFlags(Style style) const\n{\n\tswitch (style)\n\t{\n\tcase Style::kList:\n\t\treturn (wxLC_SINGLE_SEL | wxLC_VRULES | wxLC_REPORT);\n\tcase Style::kIcons:\n\t\treturn (wxLC_SINGLE_SEL | wxLC_ICON);\n\tcase Style::kSmallIcons:\n\t\treturn (wxLC_SINGLE_SEL | wxLC_ICON);\n\tdefault:\n\t\twxASSERT(false);\n\t\treturn (wxLC_SINGLE_SEL | wxLC_REPORT);\n\t}\n}\n\nvoid wxGameList::UpdateItemColors(sint32 startIndex)\n{\n    wxWindowUpdateLocker lock(this);\n\n    for (int i = startIndex; i < GetItemCount(); ++i)\n    {\n        const uint64 titleId = GetItemData(i);\n\t\tif (GetConfig().IsGameListFavorite(titleId))\n\t\t{\n\t\t\tSetItemBackgroundColour(i, kFavoriteColor);\n\t\t\tSetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\t}\n\t\telse if ((i % 2) != 0)\n\t\t{\n            SetItemBackgroundColour(i, kPrimaryColor);\n            SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\t}\n\t\telse\n\t\t{\n            SetItemBackgroundColour(i, kAlternateColor);\n            SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\t}\n\t}\n}\n\nstatic inline int order_to_int(const std::weak_ordering &wo)\n{\n\t// no easy conversion seems to exist in C++20\n\tif (wo == std::weak_ordering::less)\n\t\treturn -1;\n\telse if (wo == std::weak_ordering::greater)\n\t\treturn 1;\n\treturn 0;\n}\n\nstd::weak_ordering wxGameList::SortComparator(uint64 titleId1, uint64 titleId2, SortData* sortData)\n{\n\tauto titleLastPlayed = [](uint64_t id)\n\t{\n\t\tiosu::pdm::GameListStat playTimeStat{};\n\t\tiosu::pdm::GetStatForGamelist(id, playTimeStat);\n\t\treturn playTimeStat;\n\t};\n\n\tauto titlePlayMinutes = [](uint64_t id)\n\t{\n\t\tiosu::pdm::GameListStat playTimeStat;\n\t\tif (!iosu::pdm::GetStatForGamelist(id, playTimeStat))\n\t\t\treturn 0u;\n\t\treturn playTimeStat.numMinutesPlayed;\n\t};\n\n\tauto titleRegion = [](uint64_t id)\n\t{\n\t\treturn CafeTitleList::GetGameInfo(id).GetRegion();\n\t};\n\n\tswitch(sortData->column)\n\t{\n\tdefault:\n\tcase ColumnName:\n\t{\n\t\tconst auto isFavoriteA = GetConfig().IsGameListFavorite(titleId1);\n\t\tconst auto isFavoriteB = GetConfig().IsGameListFavorite(titleId2);\n\t\tconst auto nameA = GetNameByTitleId(titleId1);\n\t\tconst auto nameB = GetNameByTitleId(titleId2);\n\t\treturn std::tie(isFavoriteB, nameA) <=> std::tie(isFavoriteA, nameB);\n\t}\n\tcase ColumnGameStarted:\n\t\treturn titleLastPlayed(titleId1).last_played <=> titleLastPlayed(titleId2).last_played;\n\tcase ColumnGameTime:\n\t\treturn titlePlayMinutes(titleId1) <=> titlePlayMinutes(titleId2);\n\tcase ColumnRegion:\n\t\treturn titleRegion(titleId1) <=> titleRegion(titleId2);\n\tcase ColumnTitleID:\n\t\treturn titleId1 <=> titleId2;\n\t}\n\t// unreachable\n\tcemu_assert_debug(false);\n\treturn std::weak_ordering::less;\n}\n\nint wxGameList::SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)\n{\n\tconst auto sort_data = (SortData*)sortData;\n\treturn sort_data->dir * order_to_int(sort_data->thisptr->SortComparator((uint64)item1, (uint64)item2, sort_data));\n}\n\nvoid wxGameList::SortEntries(int column)\n{\n\tbool ascending;\n\tif (column == -1)\n\t{\n\t\tcolumn = GetSortIndicator();\n\t\tif (column == -1)\n\t\t\tcolumn = ColumnName;\n\t\tascending = IsAscendingSortIndicator();\n\t}\n\telse\n\t\tascending = GetUpdatedAscendingSortIndicator(column);\n\n\tswitch (column)\n\t{\n\tcase ColumnName:\n\tcase ColumnGameTime:\n\tcase ColumnGameStarted:\n\tcase ColumnRegion:\n\tcase ColumnTitleID:\n\t{\n\t\tSortData data{this, ItemColumns{column}, ascending ? 1 : -1};\n\t\tSortItems(SortFunction, (wxIntPtr)&data);\n\t\tShowSortIndicator(column, ascending);\n\t\tbreak;\n\t}\n\t}\n}\n\nvoid wxGameList::OnKeyDown(wxListEvent& event)\n{\n\tevent.Skip();\n\tif (m_style != Style::kList)\n\t\treturn;\n\n\tconst auto keycode = event.GetKeyCode();\n\tif (keycode == WXK_LEFT)\n\t{\n\t\tconst auto item_count = GetItemCount();\n\t\tif (item_count > 0)\n\t\t{\n\t\t\tauto selection = (int)GetFirstSelected();\n\t\t\tif (selection == wxNOT_FOUND)\n\t\t\t\tselection = 0;\n\t\t\telse\n\t\t\t\tselection = std::max(0, selection - GetCountPerPage());\n\n\t\t\tSelect(selection);\n\t\t\tFocus(selection);\n\t\t}\n\t}\n\telse if (keycode == WXK_RIGHT)\n\t{\n\t\tconst auto item_count = GetItemCount();\n\t\tif (item_count > 0)\n\t\t{\n\t\t\tauto selection = (int)GetFirstSelected();\n\t\t\tif (selection == wxNOT_FOUND)\n\t\t\t\tselection = 0;\n\n\t\t\tselection = std::min(item_count - 1, selection + GetCountPerPage());\n\n\t\t\tSelect(selection);\n\t\t\tFocus(selection);\n\t\t}\n\t}\n}\n\nenum ContextMenuEntries\n{\n\tkContextMenuRefreshGames = wxID_HIGHEST + 1,\n\n\tkContextMenuStart,\n\tkWikiPage,\n\tkContextMenuFavorite,\n\tkContextMenuEditName,\n\n\tkContextMenuGameFolder,\n\tkContextMenuSaveFolder,\n\tkContextMenuUpdateFolder,\n\tkContextMenuDLCFolder,\n\tkContextMenuEditGraphicPacks,\n\tkContextMenuEditGameProfile,\n\n\tkContextMenuRemoveCache,\n\n\tkContextMenuStyleList,\n\tkContextMenuStyleIcon,\n\tkContextMenuStyleIconSmall,\n\n    kContextMenuCreateShortcut,\n\n    kContextMenuCopyTitleName,\n    kContextMenuCopyTitleId,\n    kContextMenuCopyTitleImage\n};\n\nvoid wxGameList::OnContextMenu(wxContextMenuEvent& event)\n{\n\tauto& config = GetConfig();\n\n\twxMenu menu;\n\tmenu.Bind(wxEVT_COMMAND_MENU_SELECTED, &wxGameList::OnContextMenuSelected, this);\n\n\tconst auto selection = GetFirstSelected();\n\tif (selection != wxNOT_FOUND)\n\t{\n\t\tconst auto title_id = (uint64)GetItemData(selection);\n\t\tGameInfo2 gameInfo = CafeTitleList::GetGameInfo(title_id);\n\t\tif (gameInfo.IsValid())\n\t\t{\n\t\t\tmenu.SetClientData((void*)title_id);\n\n\t\t\tmenu.Append(kContextMenuStart, _(\"&Start\"));\n\n\t\t\tbool isFavorite = GetConfig().IsGameListFavorite(title_id);\n\t\t\tstd::error_code ec;\n\n\t\t\tmenu.AppendSeparator();\n\t\t\tmenu.AppendCheckItem(kContextMenuFavorite, _(\"&Favorite\"))->Check(isFavorite);\n\t\t\tmenu.Append(kContextMenuEditName, _(\"&Edit name\"));\n\n\t\t\tmenu.AppendSeparator();\n\t\t\tmenu.Append(kWikiPage, _(\"&Wiki page\"));\n\t\t\tmenu.Append(kContextMenuGameFolder, _(\"&Game directory\"));\n\t\t\tmenu.Append(kContextMenuSaveFolder, _(\"&Save directory\"))->Enable(fs::is_directory(gameInfo.GetSaveFolder(), ec));\n\t\t\tmenu.Append(kContextMenuUpdateFolder, _(\"&Update directory\"))->Enable(gameInfo.HasUpdate());\n\t\t\tmenu.Append(kContextMenuDLCFolder, _(\"&DLC directory\"))->Enable(gameInfo.HasAOC());\n\n\t\t\tmenu.AppendSeparator();\n\t\t\tmenu.Append(kContextMenuRemoveCache, _(\"&Remove shader caches\"))->Enable(!_getCachesPaths(gameInfo.GetBaseTitleId()).empty());\n\n\t\t\tmenu.AppendSeparator();\n\t\t\tmenu.Append(kContextMenuEditGraphicPacks, _(\"&Edit graphic packs\"));\n\t\t\tmenu.Append(kContextMenuEditGameProfile, _(\"&Edit game profile\"));\n\n            menu.AppendSeparator();\n            menu.Append(kContextMenuCreateShortcut, _(\"&Create shortcut\"));\n            menu.AppendSeparator();\n            menu.Append(kContextMenuCopyTitleName, _(\"&Copy Title Name\"));\n            menu.Append(kContextMenuCopyTitleId, _(\"&Copy Title ID\"));\n            menu.Append(kContextMenuCopyTitleImage, _(\"&Copy Title Image\"));\n\t\t\tmenu.AppendSeparator();\n\t\t}\n\t}\n\n\tmenu.Append(kContextMenuRefreshGames, _(\"&Refresh game list\"))->Enable(!CafeTitleList::IsScanning());\n\tmenu.AppendSeparator();\n\tmenu.AppendRadioItem(kContextMenuStyleList, _(\"Style: &List\"))->Check(m_style == Style::kList);\n\tmenu.AppendRadioItem(kContextMenuStyleIcon, _(\"Style: &Icons\"))->Check(m_style == Style::kIcons);\n\tmenu.AppendRadioItem(kContextMenuStyleIconSmall, _(\"Style: &Small Icons\"))->Check(m_style == Style::kSmallIcons);\n\tPopupMenu(&menu);\n}\n\nvoid wxGameList::OnContextMenuSelected(wxCommandEvent& event)\n{\n\tconst auto title_id = (uint64)((wxMenu*)event.GetEventObject())->GetClientData();\n\tif (title_id)\n\t{\n\t\tGameInfo2 gameInfo = CafeTitleList::GetGameInfo(title_id);\n\t\tif (gameInfo.IsValid())\n\t\t{\n\t\t\tswitch (event.GetId())\n\t\t\t{\n\t\t\tcase kContextMenuStart:\n\t\t\t{\n\t\t\t\tMainWindow::RequestLaunchGame(gameInfo.GetBase().GetPath(), wxLaunchGameEvent::INITIATED_BY::GAME_LIST);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase kContextMenuFavorite:\n\t\t\t\tGetConfig().SetGameListFavorite(title_id, !GetConfig().IsGameListFavorite(title_id));\n\t\t\t\tSortEntries();\n\t\t\t\tUpdateItemColors();\n\t\t\t\tSaveConfig(true);\n\t\t\t\tbreak;\n\t\t\tcase kContextMenuEditName:\n\t\t\t{\n\t\t\t\tstd::string customName = \"\";\n\t\t\t\tif (!GetConfig().GetGameListCustomName(title_id, customName))\n\t\t\t\t\tcustomName.clear();\n\t\t\t\twxTextEntryDialog dialog(this, wxEmptyString, _(\"Enter a custom game title\"), wxString::FromUTF8(customName));\n\t\t\t\tif(dialog.ShowModal() == wxID_OK)\n\t\t\t\t{\n\t\t\t\t\tconst auto custom_name = dialog.GetValue();\n\t\t\t\t\tGetConfig().SetGameListCustomName(title_id, custom_name.utf8_string());\n\t\t\t\t\tm_name_cache.clear();\n\t\t\t\t\tGetConfigHandle().Save();\n\t\t\t\t\t// update list entry\n\t\t\t\t\tfor (int i = 0; i < GetItemCount(); ++i)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst auto id = (uint64)GetItemData(i);\n\t\t\t\t\t\tif (id == title_id)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (m_style == Style::kList)\n\t\t\t\t\t\t\t\tSetItem(i, ColumnName, wxString::FromUTF8(GetNameByTitleId(title_id)));\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tSortEntries();\n\t\t\t\t\tUpdateItemColors();\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase kContextMenuGameFolder:\n\t\t\t\t{\n\t\t\t\tfs::path path(gameInfo.GetBase().GetPath());\n\t\t\t\t_stripPathFilename(path);\n\t\t\t\twxLaunchDefaultApplication(wxHelper::FromPath(path));\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase kWikiPage:\n\t\t\t\t{\n\t\t\t\t\t// https://wiki.cemu.info/wiki/GameIDs\n\t\t\t\t\t// WUP-P-ALZP\n\t\t\t\tif (gameInfo.GetBase().ParseXmlInfo())\n\t\t\t\t{\n\t\t\t\t\tstd::string productCode = gameInfo.GetBase().GetMetaInfo()->GetProductCode();\n\t\t\t\t\tconst auto tokens = TokenizeView(productCode, '-');\n\t\t\t\t\twxASSERT(!tokens.empty());\n\t\t\t\t\tconst std::string company_code = gameInfo.GetBase().GetMetaInfo()->GetCompanyCode();\n\t\t\t\t\twxASSERT(company_code.size() >= 2);\n\t\t\t\t\twxLaunchDefaultBrowser(formatWxString(\"https://wiki.cemu.info/wiki/{}{}\", *tokens.rbegin(), company_code.substr(company_code.size() - 2)));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\tcase kContextMenuSaveFolder:\n\t\t\t{\n\t\t\t\twxLaunchDefaultApplication(wxHelper::FromPath(gameInfo.GetSaveFolder()));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase kContextMenuUpdateFolder:\n\t\t\t{\n\t\t\t\tfs::path path(gameInfo.GetUpdate().GetPath());\n\t\t\t\t_stripPathFilename(path);\n\t\t\t\twxLaunchDefaultApplication(wxHelper::FromPath(path));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase kContextMenuDLCFolder:\n\t\t\t{\n\t\t\t\tfs::path path(gameInfo.GetAOC().front().GetPath());\n\t\t\t\t_stripPathFilename(path);\n\t\t\t\twxLaunchDefaultApplication(wxHelper::FromPath(path));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase kContextMenuRemoveCache:\n\t\t\t{\n\t\t\t\tRemoveCache(_getCachesPaths(gameInfo.GetBaseTitleId()), gameInfo.GetTitleName());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase kContextMenuEditGraphicPacks:\n\t\t\t{\n\t\t\t\twxTitleIdEvent open_event(wxEVT_OPEN_GRAPHIC_PACK, title_id);\n\t\t\t\tProcessWindowEvent(open_event);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase kContextMenuEditGameProfile:\n\t\t\t{\n\t\t\t\t(new GameProfileWindow(GetParent(), title_id))->Show();\n\t\t\t\tbreak;\n\t\t\t}\n            case kContextMenuCreateShortcut:\n            {\n                CreateShortcut(gameInfo);\n                break;\n            }\n            case kContextMenuCopyTitleName:\n            {\n                if (wxClipboard::Get()->Open())\n                {\n                    wxClipboard::Get()->SetData(new wxTextDataObject(wxString::FromUTF8(gameInfo.GetTitleName())));\n                    wxClipboard::Get()->Close();\n                }\n                break;\n            }\n            case kContextMenuCopyTitleId:\n            {\n                if (wxClipboard::Get()->Open())\n                {\n                    wxClipboard::Get()->SetData(new wxTextDataObject(fmt::format(\"{:016x}\", gameInfo.GetBaseTitleId())));\n                    wxClipboard::Get()->Close();\n                }\n                break;\n            }\n            case kContextMenuCopyTitleImage:\n            {\n                if (wxClipboard::Get()->Open())\n                {\n                    int icon_large;\n                    int icon_small;\n                    if (!QueryIconForTitle(title_id, icon_large, icon_small))\n                        break;\n                    auto icon = m_image_list_data.GetIcon(icon_large);\n                \tauto newClipboardData = wxBitmapDataObject(icon);\n                    wxClipboard::Get()->SetData(&newClipboardData);\n                    wxClipboard::Get()->Close();\n                }\n                break;\n            }\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch (event.GetId())\n\t{\n\tcase kContextMenuRefreshGames:\n\t\tReloadGameEntries();\n\t\tbreak;\n\tcase kContextMenuStyleList:\n\t\tSetStyle(Style::kList);\n\t\tbreak;\n\tcase kContextMenuStyleIcon:\n\t\tSetStyle(Style::kIcons);\n\t\tbreak;\n\tcase kContextMenuStyleIconSmall:\n\t\tSetStyle(Style::kSmallIcons);\n\t\tbreak;\n\t}\n}\n\nvoid wxGameList::OnColumnClick(wxListEvent& event)\n{\n\tconst int column = event.GetColumn();\n\tSortEntries(column);\n\tUpdateItemColors();\n\tevent.Skip();\n}\n\nvoid wxGameList::OnColumnRightClick(wxListEvent& event)\n{\n\tenum ItemIds\n\t{\n\t\tResetWidth = wxID_HIGHEST + 1,\n\t\tResetOrder,\n\n\t\tShowIcon,\n\t\tShowName,\n\t\tShowVersion,\n\t\tShowDlc,\n\t\tShowGameTime,\n\t\tShowLastPlayed,\n\t\tShowRegion,\n        ShowTitleId\n\t};\n\tconst int column = event.GetColumn();\n\twxMenu menu;\n\tmenu.SetClientObject(new wxCustomData(column));\n\n\tmenu.Append(ResetWidth, _(\"Reset &width\"));\n\tmenu.Append(ResetOrder, _(\"Reset &order\"))\t;\n\n\tmenu.AppendSeparator();\n\tmenu.AppendCheckItem(ShowIcon, _(\"Show &icon\"))->Check(GetColumnWidth(ColumnIcon) > 0);\n\tmenu.AppendCheckItem(ShowName, _(\"Show &name\"))->Check(GetColumnWidth(ColumnName) > 0);\n\tmenu.AppendCheckItem(ShowVersion, _(\"Show &version\"))->Check(GetColumnWidth(ColumnVersion) > 0);\n\tmenu.AppendCheckItem(ShowDlc, _(\"Show &dlc\"))->Check(GetColumnWidth(ColumnDLC) > 0);\n\tmenu.AppendCheckItem(ShowGameTime, _(\"Show &game time\"))->Check(GetColumnWidth(ColumnGameTime) > 0);\n\tmenu.AppendCheckItem(ShowLastPlayed, _(\"Show &last played\"))->Check(GetColumnWidth(ColumnGameStarted) > 0);\n\tmenu.AppendCheckItem(ShowRegion, _(\"Show &region\"))->Check(GetColumnWidth(ColumnRegion) > 0);\n    menu.AppendCheckItem(ShowTitleId, _(\"Show &title ID\"))->Check(GetColumnWidth(ColumnTitleID) > 0);\n\n\tmenu.Bind(wxEVT_COMMAND_MENU_SELECTED,\n\t\t[this](wxCommandEvent& event) {\n\t\t\tevent.Skip();\n\n\t\t\tconst auto menu = dynamic_cast<wxMenu*>(event.GetEventObject());\n\t\t\tconst int column = dynamic_cast<wxCustomData<int>*>(menu->GetClientObject())->GetData();\n\t\t\tauto& config = GetWxGUIConfig();\n\n\t\t\tswitch (event.GetId())\n\t\t\t{\n\t\t\tcase ShowIcon:\n\t\t\t\tconfig.show_icon_column = menu->IsChecked(ShowIcon);\n\t\t\t\tbreak;\n\t\t\tcase ShowName:\n\t\t\t\tconfig.column_width.name = menu->IsChecked(ShowName) ? DefaultColumnSize::name : 0;\n\t\t\t\tbreak;\n\t\t\tcase ShowVersion:\n\t\t\t\tconfig.column_width.version = menu->IsChecked(ShowVersion) ? DefaultColumnSize::version : 0;\n\t\t\t\tbreak;\n\t\t\tcase ShowDlc:\n\t\t\t\tconfig.column_width.dlc = menu->IsChecked(ShowDlc) ? DefaultColumnSize::dlc : 0;\n\t\t\t\tbreak;\n\t\t\tcase ShowGameTime:\n\t\t\t\tconfig.column_width.game_time = menu->IsChecked(ShowGameTime) ? DefaultColumnSize::game_time : 0;\n\t\t\t\tbreak;\n\t\t\tcase ShowLastPlayed:\n\t\t\t\tconfig.column_width.game_started = menu->IsChecked(ShowLastPlayed) ? DefaultColumnSize::game_started : 0;\n\t\t\t\tbreak;\n\t\t\tcase ShowRegion:\n\t\t\t\tconfig.column_width.region = menu->IsChecked(ShowRegion) ? DefaultColumnSize::region : 0;\n\t\t\t\tbreak;\n            case ShowTitleId:\n                config.column_width.title_id = menu->IsChecked(ShowTitleId) ? DefaultColumnSize::title_id : 0;\n                break;\n\t\t\tcase ResetWidth:\n\t\t\t{\n\t\t\t\tswitch (column)\n\t\t\t\t{\n\t\t\t\tcase ColumnIcon:\n\t\t\t\t\tbreak;\n\t\t\t\tcase ColumnName:\n\t\t\t\t\tconfig.column_width.name = DefaultColumnSize::name;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ColumnVersion:\n\t\t\t\t\tconfig.column_width.version = DefaultColumnSize::version;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ColumnDLC:\n\t\t\t\t\tconfig.column_width.dlc = DefaultColumnSize::dlc;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ColumnGameTime:\n\t\t\t\t\tconfig.column_width.game_time = DefaultColumnSize::game_time;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ColumnGameStarted:\n\t\t\t\t\tconfig.column_width.game_started = DefaultColumnSize::game_started;\n\t\t\t\t\tbreak;\n\t\t\t\tcase ColumnRegion:\n\t\t\t\t\tconfig.column_width.region = DefaultColumnSize::region;\n\t\t\t\t\tbreak;\n                case ColumnTitleID:\n                    config.column_width.title_id = DefaultColumnSize::title_id;\n\t\t\t\tdefault:\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase ResetOrder:\n\t\t\t{\n\t\t\t\tconfig.game_list_column_order.clear();\n\t\t\t\twxArrayInt order(ColumnCounts);\n\t\t\t\tstd::iota(order.begin(), order.end(), 0);\n\t\t\t\t#ifdef wxHAS_LISTCTRL_COLUMN_ORDER\n\t\t\t\tSetColumnsOrder(order);\n\t\t\t\t#endif\n\t\t\t\t//ApplyGameListColumnWidths();\n\t\t\t\t//Refresh();\n\t\t\t\t//return;\n\t\t\t}\n\t\t\t}\n\n\t\t\tGetConfigHandle().Save();\n\t\t\tApplyGameListColumnWidths();\n\t\t});\n\n\tPopupMenu(&menu);\n\tevent.Skip();\n}\n\nvoid wxGameList::ApplyGameListColumnWidths()\n{\n\tconst auto& config = GetWxGUIConfig();\n\twxWindowUpdateLocker lock(this);\n\tif(config.show_icon_column)\n\t\tSetColumnWidth(ColumnIcon, kListIconWidth+2);\n\telse\n\t\tSetColumnWidth(ColumnIcon, 0);\n\tSetColumnWidth(ColumnName, config.column_width.name);\n\tSetColumnWidth(ColumnVersion, config.column_width.version);\n\tSetColumnWidth(ColumnDLC, config.column_width.dlc);\n\tSetColumnWidth(ColumnGameTime, config.column_width.game_time);\n\tSetColumnWidth(ColumnGameStarted, config.column_width.game_started);\n\tSetColumnWidth(ColumnRegion, config.column_width.region);\n    SetColumnWidth(ColumnTitleID, config.column_width.title_id);\n\n\tAdjustLastColumnWidth();\n}\n\nvoid wxGameList::OnColumnBeginResize(wxListEvent& event)\n{\n\tconst int column = event.GetColumn();\n\tconst int width = GetColumnWidth(column);\n\tint last_col_index = 0;\n\tfor(int i = GetColumnCount() - 1; i > 0; i--)\n\t{\n#ifdef wxHAS_LISTCTRL_COLUMN_ORDER\n\t\tif(GetColumnWidth(GetColumnIndexFromOrder(i)) > 0)\n\t\t{\n\t\t\tlast_col_index = GetColumnIndexFromOrder(i);\n\t\t\tbreak;\n\t\t}\n#else\n\t\tif(GetColumnWidth(i) > 0)\n\t\t{\n\t\t\tlast_col_index = i;\n\t\t\tbreak;\n\t\t}\n#endif\n\t}\n\tif (width == 0 || column == ColumnIcon || column == last_col_index) // dont resize hidden name, icon, and last column\n\t\tevent.Veto();\n\telse\n\t\tevent.Skip();\n}\n\nvoid wxGameList::OnColumnResize(wxListEvent& event)\n{\n\tevent.Skip();\n\n\tif(m_style != Style::kList)\n\t\treturn;\n\n\tconst int column = event.GetColumn();\n\tconst int width = GetColumnWidth(column);\n\n\tauto& config = GetWxGUIConfig();\n\tswitch (column)\n\t{\n\tcase ColumnName:\n\t\tconfig.column_width.name = width;\n\t\tbreak;\n\tcase ColumnVersion:\n\t\tconfig.column_width.version = width;\n\t\tbreak;\n\tcase ColumnDLC:\n\t\tconfig.column_width.dlc = width;\n\t\tbreak;\n\tcase ColumnGameTime:\n\t\tconfig.column_width.game_time = width;\n\t\tbreak;\n\tcase ColumnGameStarted:\n\t\tconfig.column_width.game_started = width;\n\t\tbreak;\n\tcase ColumnRegion:\n\t\tconfig.column_width.region = width;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tGetConfigHandle().Save();\n\tAdjustLastColumnWidth();\n}\n\nvoid wxGameList::OnClose(wxCloseEvent& event)\n{\n\tevent.Skip();\n\tm_exit = true;\n}\n\nint wxGameList::FindInsertPosition(TitleId titleId, bool& entryAlreadyExists)\n{\n\tentryAlreadyExists = false;\n\tSortData data{this, ItemColumns(GetSortIndicator()), IsAscendingSortIndicator()};\n\tconst auto itemCount = GetItemCount();\n\n\tif (itemCount == 0)\n\t\treturn 0;\n\tsint32 low = 0;\n\tsint32 high = itemCount;\n\twhile (low < high)\n\t{\n\t\tsint32 mid = low + (high - low) / 2;\n\t\tauto cmp = SortComparator(titleId, (uint64)GetItemData(mid), &data);\n\t\tif (cmp <= 0)\n\t\t{\n\t\t\tif (cmp == 0)\n\t\t\t{\n\t\t\t\tentryAlreadyExists = true;\n\t\t\t\treturn mid;\n\t\t\t}\n\t\t\thigh = mid;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlow = mid + 1;\n\t\t}\n\t}\n\treturn low;\n}\n\nvoid wxGameList::OnTimerBulkAddEntriesToGameList(wxTimerEvent& event)\n{\n\tstd::vector<TitleId> titleIdsToUpdate;\n\tstd::swap(titleIdsToUpdate, m_bulkTitlesToAdd);\n\n\twxWindowUpdateLocker lock(this);\n\tbool hasAnyNewEntry = false;\n\tfor (auto& titleId : titleIdsToUpdate)\n\t{\n\t\tGameInfo2 gameInfo = CafeTitleList::GetGameInfo(titleId);\n\t\tif (!gameInfo.IsValid() || gameInfo.IsSystemDataTitle())\n\t\t{\n\t\t\t// entry no longer exists or is not a valid game\n\t\t\t// we dont need to remove list entries here because all delete operations should trigger a full list refresh\n\t\t\tcontinue;\n\t\t}\n\t\tTitleId baseTitleId = gameInfo.GetBaseTitleId();\n\t\tbool isNewEntry = false;\n\n\t\tint icon = -1; /* 0 is the default empty icon */\n\t\tint icon_small = -1; /* 0 is the default empty icon */\n\t\tQueryIconForTitle(baseTitleId, icon, icon_small);\n\n\t\tbool entryAlreadyExists = false;\n\t\tauto index = FindInsertPosition(baseTitleId, entryAlreadyExists);\n\t\tif(!entryAlreadyExists)\n\t\t{\n\t\t\t// entry doesn't exist\n\t\t\tindex = InsertItem(index, wxString::FromUTF8(GetNameByTitleId(baseTitleId)));\n\t\t\tSetItemPtrData(index, baseTitleId);\n\t\t\tisNewEntry = true;\n\t\t\thasAnyNewEntry = true;\n\t\t}\n\n\t\tif (m_style == Style::kList)\n\t\t{\n\t\t\tSetItemColumnImage(index, ColumnIcon, icon_small);\n\n\t\t\tSetItem(index, ColumnName, wxString::FromUTF8(GetNameByTitleId(baseTitleId)));\n\n\t\t\tSetItem(index, ColumnVersion, fmt::format(\"{}\", gameInfo.GetVersion()));\n\n\t\t\tif(gameInfo.HasAOC())\n\t\t\t\tSetItem(index, ColumnDLC, fmt::format(\"{}\", gameInfo.GetAOCVersion()));\n\t\t\telse\n\t\t\t\tSetItem(index, ColumnDLC, wxString());\n\n\t\t\tif (isNewEntry)\n\t\t\t{\n\t\t\t\tiosu::pdm::GameListStat playTimeStat;\n\t\t\t\tif (iosu::pdm::GetStatForGamelist(baseTitleId, playTimeStat))\n\t\t\t\t{\n\t\t\t\t\t// time played\n\t\t\t\t\tuint32 minutesPlayed = playTimeStat.numMinutesPlayed;\n\t\t\t\t\tif (minutesPlayed == 0)\n\t\t\t\t\t\tSetItem(index, ColumnGameTime, wxEmptyString);\n\t\t\t\t\telse if (minutesPlayed < 60)\n\t\t\t\t\t\tSetItem(index, ColumnGameTime, formatWxString(wxPLURAL(\"{} minute\", \"{} minutes\", minutesPlayed), minutesPlayed));\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tuint32 hours = minutesPlayed / 60;\n\t\t\t\t\t\tuint32 minutes = minutesPlayed % 60;\n\t\t\t\t\t\twxString hoursText = formatWxString(wxPLURAL(\"{} hour\", \"{} hours\", hours), hours);\n\t\t\t\t\t\twxString minutesText = formatWxString(wxPLURAL(\"{} minute\", \"{} minutes\", minutes), minutes);\n\t\t\t\t\t\tSetItem(index, ColumnGameTime, hoursText + \" \" + minutesText);\n\t\t\t\t\t}\n\n\t\t\t\t\t// last played\n\t\t\t\t\tif (playTimeStat.last_played.year != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst wxDateTime tmp((wxDateTime::wxDateTime_t)playTimeStat.last_played.day, (wxDateTime::Month)playTimeStat.last_played.month, (wxDateTime::wxDateTime_t)playTimeStat.last_played.year, 0, 0, 0, 0);\n\t\t\t\t\t\tSetItem(index, ColumnGameStarted, tmp.FormatDate());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tSetItem(index, ColumnGameStarted, _(\"never\"));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tSetItem(index, ColumnGameTime, wxEmptyString);\n\t\t\t\t\tSetItem(index, ColumnGameStarted, _(\"never\"));\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst auto region_text = fmt::format(\"{}\", gameInfo.GetRegion());\n\t\t\tSetItem(index, ColumnRegion, wxGetTranslation(region_text));\n\t        SetItem(index, ColumnTitleID, fmt::format(\"{:016x}\", baseTitleId));\n\t\t}\n\t\telse if (m_style == Style::kIcons)\n\t\t{\n\t\t\tSetItemImage(index, icon);\n\t\t}\n\t\telse if (m_style == Style::kSmallIcons)\n\t\t{\n\t\t\tSetItemImage(index, icon_small);\n\t\t}\n\t}\n\tif (hasAnyNewEntry)\n\t\tUpdateItemColors();\n}\n\nvoid wxGameList::OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event)\n{\n\tif (m_bulkTitlesToAdd.size() < 100)\n\t\tm_bulkUpdateTimer.StartOnce(100); // if timer is started already this will delay it\n\tconst auto titleId = event.GetTitleId();\n\tm_bulkTitlesToAdd.emplace_back(titleId);\n}\n\nvoid wxGameList::OnItemActivated(wxListEvent& event)\n{\n\tevent.Skip();\n\n\tconst auto selection = event.GetIndex();\n\tif (selection == wxNOT_FOUND)\n\t\treturn;\n\n\tconst auto item_data = (uint64)GetItemData(selection);\n\tif(item_data == kDefaultEntryData)\n\t{\n\t\tconst wxCommandEvent open_settings_event(wxEVT_OPEN_SETTINGS);\n\t\twxPostEvent(this, open_settings_event);\n\t\treturn;\n\t}\n\n\tTitleInfo titleInfo;\n\tif (!CafeTitleList::GetFirstByTitleId(item_data, titleInfo))\n\t\treturn;\n\tif (!titleInfo.IsValid())\n\t\treturn;\n\n\tMainWindow::RequestLaunchGame(titleInfo.GetPath(), wxLaunchGameEvent::INITIATED_BY::GAME_LIST);\n}\n\nvoid wxGameList::OnTimer(wxTimerEvent& event)\n{\n\tconst auto& obj = event.GetTimer().GetId();\n\tif(obj == m_tooltip_timer->GetId())\n\t{\n\t\tm_tooltip_window->Hide();\n\n\t\tauto flag = wxLIST_HITTEST_ONITEM;\n\t\tconst auto item = this->HitTest(m_mouse_position, flag);\n\t\tif(item != wxNOT_FOUND )\n\t\t{\n\t\t\t//const auto title_id = (uint64_t)GetItemData(item);\n\t\t\t//auto entry = GetGameEntry(title_id);\n\t\t\t//if (entry && entry->is_update)\n\t\t\t//{\n\t\t\t//\tm_tooltip_window->SetPosition(wxPoint(m_mouse_position.x + 15, m_mouse_position.y + 15));\n\t\t\t//\tm_tooltip_window->SendSizeEvent();\n\t\t\t//\tm_tooltip_window->Show();\n\t\t\t//}\n\t\t}\n\t}\n\n}\n\nvoid wxGameList::OnMouseMove(wxMouseEvent& event)\n{\n\tm_tooltip_timer->Stop();\n\tm_tooltip_timer->StartOnce(250);\n\tm_mouse_position = event.GetPosition();\n}\n\nvoid wxGameList::OnLeaveWindow(wxMouseEvent& event)\n{\n\tm_tooltip_timer->Stop();\n\tm_tooltip_window->Hide();\n}\n\nvoid wxGameList::HandleTitleListCallback(CafeTitleListCallbackEvent* evt)\n{\n\tif (evt->eventType == CafeTitleListCallbackEvent::TYPE::TITLE_DISCOVERED ||\n\t\tevt->eventType == CafeTitleListCallbackEvent::TYPE::TITLE_REMOVED)\n\t{\n\t\twxQueueEvent(this, new wxTitleIdEvent(wxEVT_GAME_ENTRY_ADDED_OR_REMOVED, evt->titleInfo->GetAppTitleId()));\n\t}\n}\n\nvoid wxGameList::RemoveCache(const std::vector<fs::path>& cachePaths, const std::string& titleName)\n{\n\twxMessageDialog dialog(this, formatWxString(_(\"Remove the shader caches for {}?\"), titleName), _(\"Remove shader caches\"), wxCENTRE | wxYES_NO | wxICON_EXCLAMATION);\n\tdialog.SetYesNoLabels(_(\"Yes\"), _(\"No\"));\n\n\tconst auto dialogResult = dialog.ShowModal();\n\tif (dialogResult != wxID_YES)\n\t\treturn;\n\tstd::vector<std::string> errs;\n\tfor (const fs::path& cachePath : cachePaths)\n\t{\n\t\tif (std::error_code ec; !fs::remove(cachePath, ec))\n\t\t\terrs.emplace_back(fmt::format(\"{} : {}\", cachePath.string(), ec.message()));\n\t}\n\tif (errs.empty())\n\t\twxMessageDialog(this, _(\"The shader caches were removed!\"), _(\"Shader caches removed\"), wxCENTRE | wxOK | wxICON_INFORMATION).ShowModal();\n\telse\n\t\twxMessageDialog(this, formatWxString(_(\"Failed to remove the shader caches:\\n{}\"), fmt::join(errs, \"\\n\")), _(\"Error\"), wxCENTRE | wxOK | wxICON_ERROR).ShowModal();\n}\n\nvoid wxGameList::AsyncWorkerThread()\n{\n\tSetThreadName(\"GameListWorker\");\n\twhile (m_async_worker_active)\n\t{\n\t\tm_async_task_count.decrementWithWait();\n\t\t// get next titleId to load (if any)\n\t\tm_async_worker_mutex.lock();\n\t\tbool hasJob = !m_icon_load_queue.empty();\n\t\tTitleId titleId = 0;\n\t\tif (hasJob)\n\t\t{\n\t\t\ttitleId = m_icon_load_queue.front();\n\t\t\tm_icon_load_queue.erase(m_icon_load_queue.begin());\n\t\t}\n\t\tm_async_worker_mutex.unlock();\n\t\tif (!hasJob)\n\t\t\tcontinue;\n\t\tif(m_icon_loaded.find(titleId) != m_icon_loaded.end())\n\t\t\tcontinue;\n\t\tm_icon_loaded.emplace(titleId);\n\t\t// load and process icon\n\t\tTitleInfo titleInfo;\n\t\tif( !CafeTitleList::GetFirstByTitleId(titleId, titleInfo) )\n\t\t\tcontinue;\n\t\tstd::string tempMountPath = TitleInfo::GetUniqueTempMountingPath();\n\t\tif(!titleInfo.Mount(tempMountPath, \"\", FSC_PRIORITY_BASE))\n\t\t\tcontinue;\n\t\tauto tgaData = fsc_extractFile((tempMountPath + \"/meta/iconTex.tga\").c_str());\n\t\t// try iconTex.tga.gz\n\t\tif (!tgaData)\n\t\t{\n\t\t\ttgaData = fsc_extractFile((tempMountPath + \"/meta/iconTex.tga.gz\").c_str());\n\t\t\tif (tgaData)\n\t\t\t{\n\t\t\t\tauto decompressed = zlibDecompress(*tgaData, 70*1024);\n\t\t\t\tstd::swap(tgaData, decompressed);\n\t\t\t}\n\t\t}\n\t\tbool iconSuccessfullyLoaded = false;\n\t\tif (tgaData && tgaData->size() > 16)\n\t\t{\n\t\t\twxMemoryInputStream tmp_stream(tgaData->data(), tgaData->size());\n\t\t\tconst wxImage image(tmp_stream);\n\t\t\t// todo - is wxImageList thread safe?\n\t\t\tint icon = m_image_list_data.Add(image.Scale(kIconWidth, kIconWidth, wxIMAGE_QUALITY_BICUBIC));\n\t\t\tint icon_small = m_image_list_small_data.Add(image.Scale(kListIconWidth, kListIconWidth, wxIMAGE_QUALITY_BICUBIC));\n\t\t\t// store in cache\n\t\t\tm_icon_cache_mtx.lock();\n\t\t\tm_icon_cache.try_emplace(titleId, icon, icon_small);\n\t\t\tm_icon_cache_mtx.unlock();\n\t\t\ticonSuccessfullyLoaded = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to load icon for title {:016x}\", titleId);\n\t\t}\n\t\ttitleInfo.Unmount(tempMountPath);\n\t\t// notify UI about loaded icon\n\t\tif(iconSuccessfullyLoaded)\n\t\t\twxQueueEvent(this, new wxTitleIdEvent(wxEVT_GAME_ENTRY_ADDED_OR_REMOVED, titleId));\n\t}\n}\n\nvoid wxGameList::RequestLoadIconAsync(TitleId titleId)\n{\n\tm_async_worker_mutex.lock();\n\tm_icon_load_queue.push_back(titleId);\n\tm_async_worker_mutex.unlock();\n\tm_async_task_count.increment();\n}\n\n// returns icons if cached, otherwise an async request to load them is made\nbool wxGameList::QueryIconForTitle(TitleId titleId, int& icon, int& iconSmall)\n{\n\tm_icon_cache_mtx.lock();\n\tauto it = m_icon_cache.find(titleId);\n\tif (it == m_icon_cache.end())\n\t{\n\t\tm_icon_cache_mtx.unlock();\n\t\tRequestLoadIconAsync(titleId);\n\t\treturn false;\n\t}\n\ticon = it->second.first;\n\ticonSmall = it->second.second;\n\tm_icon_cache_mtx.unlock();\n\treturn true;\n}\n\nvoid wxGameList::DeleteCachedStrings()\n{\n\tm_name_cache.clear();\n}\n\n#if BOOST_OS_LINUX || BOOST_OS_BSD\nvoid wxGameList::CreateShortcut(GameInfo2& gameInfo)\n{\n\tconst auto titleId = gameInfo.GetBaseTitleId();\n\tconst auto titleName = wxString::FromUTF8(gameInfo.GetTitleName());\n\tauto exePath = ActiveSettings::GetExecutablePath();\n\tconst char* flatpakId = getenv(\"FLATPAK_ID\");\n\n\tconst wxString desktopEntryName = wxString::Format(\"%s.desktop\", titleName);\n\twxFileDialog entryDialog(this, _(\"Choose desktop entry location\"), \"~/.local/share/applications\", desktopEntryName,\n\t\t\t\t\t\t\t \"Desktop file (*.desktop)|*.desktop\", wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT);\n\tconst auto result = entryDialog.ShowModal();\n\tif (result == wxID_CANCEL)\n\t\treturn;\n\tconst auto output_path = entryDialog.GetPath();\n\n\tstd::optional<fs::path> iconPath;\n\t// Obtain and convert icon\n\t[&]()\n\t{\n\t\tint iconIdx, smallIconIdx;\n\n\t\tif (!QueryIconForTitle(titleId, iconIdx, smallIconIdx))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Icon hasn't loaded\");\n\t\t\treturn;\n\t\t}\n\t\tconst fs::path outIconDir = ActiveSettings::GetUserDataPath(\"icons\");\n\n\t\tif (!fs::exists(outIconDir) && !fs::create_directories(outIconDir))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to create icon directory\");\n\t\t\treturn;\n\t\t}\n\n\t\ticonPath = outIconDir / fmt::format(\"{:016x}.png\", gameInfo.GetBaseTitleId());\n\t\twxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));\n\n\t\tconst auto icon = m_image_list_data.GetIcon(iconIdx);\n\t\twxBitmap bitmap{icon};\n\t\twxImage image = bitmap.ConvertToImage();\n\t\twxPNGHandler pngHandler;\n\t\tif (!pngHandler.SaveFile(&image, pngFileStream, false))\n\t\t{\n\t\t\ticonPath = std::nullopt;\n\t\t\tcemuLog_log(LogType::Force, \"Icon failed to save\");\n\t\t}\n\t}();\n\n\tstd::string desktopExecEntry = flatpakId ? fmt::format(\"/usr/bin/flatpak run {0} --title-id {1:016x}\", flatpakId, titleId)\n\t\t\t\t\t\t\t\t\t\t\t : fmt::format(\"{0:?} --title-id {1:016x}\", _pathToUtf8(exePath), titleId);\n\n\t// 'Icon' accepts spaces in file name, does not accept quoted file paths\n\t// 'Exec' does not accept non-escaped spaces, and can accept quoted file paths\n\tauto desktopEntryString = fmt::format(\n\t\t\"[Desktop Entry]\\n\"\n\t\t\"Name={0}\\n\"\n\t\t\"Comment=Play {0} on Cemu\\n\"\n\t\t\"Exec={1}\\n\"\n\t\t\"Icon={2}\\n\"\n\t\t\"Terminal=false\\n\"\n\t\t\"Type=Application\\n\"\n\t\t\"Categories=Game;\\n\",\n\t\ttitleName.utf8_string(),\n\t\tdesktopExecEntry,\n\t\t_pathToUtf8(iconPath.value_or(\"\")));\n\n\tif (flatpakId)\n\t\tdesktopEntryString += fmt::format(\"X-Flatpak={}\\n\", flatpakId);\n\n\tstd::ofstream outputStream(output_path.utf8_string());\n\tif (!outputStream.good())\n\t{\n\t\tauto errorMsg = formatWxString(_(\"Failed to save desktop entry to {}\"), output_path.utf8_string());\n\t\twxMessageBox(errorMsg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\treturn;\n\t}\n\toutputStream << desktopEntryString;\n}\n#elif BOOST_OS_MACOS\nvoid wxGameList::CreateShortcut(GameInfo2& gameInfo)\n{\n\tconst auto titleId = gameInfo.GetBaseTitleId();\n\tconst auto titleName = wxString::FromUTF8(gameInfo.GetTitleName());\n\tauto exePath = ActiveSettings::GetExecutablePath();\n\n\tconst wxString appName = wxString::Format(\"%s.app\", titleName);\n\twxFileDialog entryDialog(this, _(\"Choose shortcut location\"), \"~/Applications\", appName,\n\t\t\t\t\t\t\t \"Application (*.app)|*.app\", wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT);\n\tconst auto result = entryDialog.ShowModal();\n\tif (result == wxID_CANCEL)\n\t\treturn;\n\tconst auto output_path = entryDialog.GetPath();\n\t// Create .app folder\n\tconst fs::path appPath = output_path.utf8_string();\n\tif (!fs::create_directories(appPath))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to create app directory\");\n\t\treturn;\n\t}\n\tconst fs::path infoPath = appPath / \"Contents/Info.plist\";\n\tconst fs::path scriptPath = appPath / \"Contents/MacOS/run.sh\";\n\tconst fs::path icnsPath = appPath / \"Contents/Resources/shortcut.icns\";\n\tif (!(fs::create_directories(scriptPath.parent_path()) && fs::create_directories(icnsPath.parent_path())))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to create app shortcut directories\");\n\t\treturn;\n\t}\n\n\tstd::optional<fs::path> iconPath;\n\t// Obtain and convert icon\n\t[&]()\n\t{\n\t\tint iconIdx, smallIconIdx;\n\n\t\tif (!QueryIconForTitle(titleId, iconIdx, smallIconIdx))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Icon hasn't loaded\");\n\t\t\treturn;\n\t\t}\n\t\tconst fs::path outIconDir = fs::temp_directory_path();\n\n\t\tif (!fs::exists(outIconDir) && !fs::create_directories(outIconDir))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to create icon directory\");\n\t\t\treturn;\n\t\t}\n\n\t\ticonPath = outIconDir / fmt::format(\"{:016x}.png\", gameInfo.GetBaseTitleId());\n\t\twxFileOutputStream pngFileStream(_pathToUtf8(iconPath.value()));\n\n\t\tconst auto icon = m_image_list_data.GetIcon(iconIdx);\n\t\twxBitmap bitmap{icon};\n\t\twxImage image = bitmap.ConvertToImage();\n\t\twxPNGHandler pngHandler;\n\t\tif (!pngHandler.SaveFile(&image, pngFileStream, false))\n\t\t{\n\t\t\ticonPath = std::nullopt;\n\t\t\tcemuLog_log(LogType::Force, \"Icon failed to save\");\n\t\t}\n\t}();\n\n\tstd::string runCommand = fmt::format(\"#!/bin/zsh\\n\\n{0:?} --title-id {1:016x}\", _pathToUtf8(exePath), titleId);\n\tconst std::string infoPlist = fmt::format(\n\t\"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n\"\n\t\"<!DOCTYPE plist PUBLIC \\\"-//Apple//DTD PLIST 1.0//EN\\\" \\\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\\">\\n\"\n\t\"<plist version=\\\"1.0\\\">\\n\"\n\t\"<dict>\\n\"\n\t\"\t<key>CFBundleDisplayName</key>\\n\"\n\t\"\t<string>{0}</string>\\n\"\n\t\"\t<key>CFBundleExecutable</key>\\n\"\n\t\"\t<string>run.sh</string>\\n\"\n\t\"\t<key>CFBundleIconFile</key>\\n\"\n\t\"\t<string>shortcut.icns</string>\\n\"\n\t\"\t<key>CFBundleName</key>\\n\"\n\t\"\t<string>{0}</string>\\n\"\n\t\"\t<key>CFBundlePackageType</key>\\n\"\n\t\"\t<string>APPL</string>\\n\"\n\t\"\t<key>CFBundleSignature</key>\\n\"\n\t\"\t<string>\\?\\?\\?\\?</string>\\n\"\n\t\"\t<key>LSApplicationCategoryType</key>\\n\"\n\t\"\t<string>public.app-category.games</string>\\n\"\n\t\"\t<key>CFBundleShortVersionString</key>\\n\"\n\t\"\t<string>{1}</string>\\n\"\n\t\"\t<key>CFBundleVersion</key>\\n\"\n\t\"\t<string>{1}</string>\\n\"\n\t\"</dict>\\n\"\n\t\"</plist>\\n\",\n\tgameInfo.GetTitleName(),\n\tstd::to_string(gameInfo.GetVersion())\n\t);\n\t// write Info.plist to infoPath\n\tstd::ofstream infoStream(infoPath);\n\tstd::ofstream scriptStream(scriptPath);\n\tif (!infoStream.good() || !scriptStream.good())\n\t{\n\t\tauto errorMsg = formatWxString(_(\"Failed to save app shortcut to {}\"), output_path.utf8_string());\n\t\twxMessageBox(errorMsg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t\treturn;\n\t}\n\tinfoStream << infoPlist;\n\tscriptStream << runCommand;\n\tscriptStream.close();\n\n\t// Set execute permissions for script\n\tfs::permissions(\n\t\tscriptPath,\n\t\tfs::perms::owner_exec | fs::perms::group_exec | fs::perms::others_exec,\n\t\tfs::perm_options::add\n\t);\n\n\t// Return if iconPath is empty\n\tif (!iconPath)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Icon not found\");\n\t\treturn;\n\t}\n\n\t// Convert icon to icns, only works for 128x128 PNG\n\t// Alternatively, can run the command \"sips -s format icns {iconPath} --out '{icnsPath}'\"\n\t// using std::system() to handle images of any size\n\tif (!writeICNS(*iconPath, icnsPath))\n\t{\n\t\tcemuLog_log(LogType::Force, \"Failed to convert icon to icns\");\n\t\treturn;\n\t}\n\n\t// Remove temp file\n\tfs::remove(*iconPath);\n}\n#elif BOOST_OS_WINDOWS\nvoid wxGameList::CreateShortcut(GameInfo2& gameInfo)\n{\n\tconst auto titleId = gameInfo.GetBaseTitleId();\n\tconst auto titleName = wxString::FromUTF8(gameInfo.GetTitleName());\n\tauto exePath = ActiveSettings::GetExecutablePath();\n\n\t// Get '%APPDATA%\\Microsoft\\Windows\\Start Menu\\Programs' path\n\tPWSTR userShortcutFolder;\n\tSHGetKnownFolderPath(FOLDERID_Programs, 0, NULL, &userShortcutFolder);\n\tconst wxString shortcutName = wxString::Format(\"%s.lnk\", titleName);\n\twxFileDialog shortcutDialog(this, _(\"Choose shortcut location\"), userShortcutFolder, shortcutName,\n\t\t\t\t\t\t\t\t\"Shortcut (*.lnk)|*.lnk\", wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT);\n\n\tCoTaskMemFree(userShortcutFolder);\n\n\tconst auto result = shortcutDialog.ShowModal();\n\tif (result == wxID_CANCEL)\n\t\treturn;\n\tconst auto outputPath = shortcutDialog.GetPath();\n\n\tstd::optional<fs::path> icon_path = std::nullopt;\n\t{\n\t\tint iconIdx;\n\t\tint smallIconIdx;\n\t\tif (!QueryIconForTitle(titleId, iconIdx, smallIconIdx))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Icon hasn't loaded\");\n\t\t\treturn;\n\t\t}\n\t\tconst auto icon = m_image_list_data.GetIcon(iconIdx);\n\t\tconst auto folder = ActiveSettings::GetUserDataPath(\"icons\");\n\t\tif (!fs::exists(folder) && !fs::create_directories(folder))\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Failed to create icon directory\");\n\t\t\treturn;\n\t\t}\n\t\twxBitmap bitmap{icon};\n\n\t\ticon_path = folder / fmt::format(\"{:016x}.ico\", titleId);\n\t\tauto stream = wxFileOutputStream(icon_path->wstring());\n\t\tauto image = bitmap.ConvertToImage();\n\t\twxICOHandler icohandler{};\n\t\tif (!icohandler.SaveFile(&image, stream, false))\n\t\t{\n\t\t\ticon_path = std::nullopt;\n\t\t\tcemuLog_log(LogType::Force, \"Icon failed to save\");\n\t\t}\n\t}\n\n\tMicrosoft::WRL::ComPtr<IShellLinkW> shellLink;\n\tHRESULT hres = CoCreateInstance(__uuidof(ShellLink), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shellLink));\n\tif (SUCCEEDED(hres))\n\t{\n\t\tconst auto description = wxString::Format(\"Play %s on Cemu\", titleName);\n\t\tconst auto args = wxString::Format(\"-t %016llx\", titleId);\n\n\t\tshellLink->SetPath(exePath.wstring().c_str());\n\t\tshellLink->SetDescription(description.wc_str());\n\t\tshellLink->SetArguments(args.wc_str());\n\t\tshellLink->SetWorkingDirectory(exePath.parent_path().wstring().c_str());\n\n\t\tif (icon_path)\n\t\t\tshellLink->SetIconLocation(icon_path->wstring().c_str(), 0);\n\t\telse\n\t\t\tshellLink->SetIconLocation(exePath.wstring().c_str(), 0);\n\n\t\tMicrosoft::WRL::ComPtr<IPersistFile> shellLinkFile;\n\t\t// save the shortcut\n\t\thres = shellLink.As(&shellLinkFile);\n\t\tif (SUCCEEDED(hres))\n\t\t{\n\t\t\thres = shellLinkFile->Save(outputPath.wc_str(), TRUE);\n\t\t}\n\t}\n\tif (FAILED(hres))\n\t{\n\t\tauto errorMsg = formatWxString(_(\"Failed to save shortcut to {}\"), outputPath);\n\t\twxMessageBox(errorMsg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR);\n\t}\n}\n#endif\n"
  },
  {
    "path": "src/gui/wxgui/components/wxGameList.h",
    "content": "#pragma once\n\n#include \"config/CemuConfig.h\"\n#include \"Cafe/TitleList/TitleId.h\"\n\n#include <wx/listctrl.h>\n#include <wx/timer.h>\n#include <wx/panel.h>\n#include <wx/settings.h>\n#include <Cafe/TitleList/GameInfo.h>\n\n#include \"wxHelper.h\"\n#include \"util/helpers/Semaphore.h\"\n\nclass wxTitleIdEvent : public wxCommandEvent\n{\npublic:\n\twxTitleIdEvent(int type, uint64 title_id)\n\t\t: wxCommandEvent(type), m_title_id(title_id) {}\n\n\t[[nodiscard]] uint64 GetTitleId() const { return m_title_id; }\n\nprivate:\n\tuint64 m_title_id;\n};\n\nwxDECLARE_EVENT(wxEVT_OPEN_SETTINGS, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_OPEN_GRAPHIC_PACK, wxTitleIdEvent);\nwxDECLARE_EVENT(wxEVT_GAMELIST_BEGIN_UPDATE, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_GAMELIST_END_UPDATE, wxCommandEvent);\n\nclass wxGameList : public wxListView\n{\n\tfriend class MainWindow;\npublic:\n\tenum class Style\n\t{\n\t\tkList,\n\t\tkIcons,\n\t\tkSmallIcons\n\t};\n\n\twxGameList(wxWindow* parent, wxWindowID id = wxID_ANY);\n\t~wxGameList();\n\n\tvoid SetStyle(Style style, bool save = true);\n\n\tvoid LoadConfig();\n\tvoid SaveConfig(bool flush = false);\n\tbool IsVisible(long item) const; // only available in wxwidgets 3.1.3\n\n\tvoid ReloadGameEntries();\n\tvoid DeleteCachedStrings();\n\n    void CreateShortcut(GameInfo2& gameInfo);\n\n\tlong FindListItemByTitleId(uint64 title_id) const;\n\n\tvoid OnClose(wxCloseEvent& event);\n\nprivate:\n\tstd::atomic_bool m_exit = false;\n\tStyle m_style;\n\tlong GetStyleFlags(Style style) const;\n\n\tconst wxColour kUpdateColor{ wxSystemSettings::SelectLightDark(wxColour(195, 57, 57), wxColour(84, 29, 29)) };\n\tconst wxColour kFavoriteColor{ wxSystemSettings::SelectLightDark(wxColour(253, 246, 211), wxColour(82, 84, 48)) };\n\tconst wxColour kPrimaryColor = GetBackgroundColour();\n\tconst wxColour kAlternateColor = wxHelper::CalculateAccentColour(kPrimaryColor);\n\tvoid UpdateItemColors(sint32 startIndex = 0);\n\n\tenum ItemColumns : int\n\t{\n\t\tColumnHiddenName = 0,\n\t\tColumnIcon,\n\t\tColumnName,\n\t\tColumnVersion,\n\t\tColumnDLC,\n\t\tColumnGameTime,\n\t\tColumnGameStarted,\n\t\tColumnRegion,\n        ColumnTitleID,\n        //ColumnFavorite,\n\t\tColumnCounts,\n\t};\n\n\tvoid SortEntries(int column = -1);\n\tstruct SortData\n\t{\n\t\twxGameList* thisptr;\n\t\tItemColumns column;\n\t\tint dir;\n\t};\n\n\tint FindInsertPosition(TitleId titleId, bool& entryAlreadyExists);\n\tstd::weak_ordering SortComparator(uint64 titleId1, uint64 titleId2, SortData* sortData);\n\tstatic int SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData);\n\n\twxTimer* m_tooltip_timer;\n\twxToolTip* m_tool_tip;\n\twxPanel* m_tooltip_window;\n\twxPoint m_mouse_position;\n\n\tstd::mutex m_async_worker_mutex;\n\tstd::thread m_async_worker_thread;\n\tCounterSemaphore m_async_task_count;\n\tstd::atomic_bool m_async_worker_active{false};\n\n\tstd::vector<TitleId> m_icon_load_queue;\n\n\tuint64 m_callbackIdTitleList;\n\n\tstd::string GetNameByTitleId(uint64 titleId);\n\n\tvoid HandleTitleListCallback(struct CafeTitleListCallbackEvent* evt);\n\n\tvoid RemoveCache(const std::vector<fs::path>& cachePath, const std::string& titleName);\n\n\tvoid AsyncWorkerThread();\n\tvoid RequestLoadIconAsync(TitleId titleId);\n\tbool QueryIconForTitle(TitleId titleId, int& icon, int& iconSmall);\n\n\tinline static constexpr int kListIconWidth = 64;\n\tinline static constexpr int kIconWidth = 128;\n\twxImageList m_image_list_data = wxImageList(kIconWidth, kIconWidth, false, 1);\n\twxImageList m_image_list_small_data = wxImageList(kListIconWidth, kListIconWidth, false, 1);\n\n\tstd::mutex m_icon_cache_mtx;\n\tstd::set<TitleId> m_icon_loaded;\n\tstd::map<TitleId, std::pair<int, int>> m_icon_cache; // pair contains icon and small icon\n\n\tstd::map<TitleId, std::string> m_name_cache;\n\n\t// bulk update handling\n\tstd::vector<TitleId> m_bulkTitlesToAdd;\n\twxTimer m_bulkUpdateTimer;\n\n\t// list mode\n\tvoid CreateListColumns();\n\n\tvoid OnColumnClick(wxListEvent& event);\n\tvoid OnColumnRightClick(wxListEvent& event);\n\tvoid ApplyGameListColumnWidths();\n\tvoid OnColumnBeginResize(wxListEvent& event);\n\tvoid OnColumnResize(wxListEvent& event);\n\tvoid OnColumnDrag(wxListEvent& event);\n\t\n\t// generic events\n\tvoid OnKeyDown(wxListEvent& event);\n\tvoid OnContextMenu(wxContextMenuEvent& event);\n\tvoid OnContextMenuSelected(wxCommandEvent& event);\n\tvoid OnGameEntryUpdatedByTitleId(wxTitleIdEvent& event);\n\tvoid OnItemActivated(wxListEvent& event);\n\tvoid OnTimer(wxTimerEvent& event);\n\tvoid OnMouseMove(wxMouseEvent& event);\n\tvoid OnLeaveWindow(wxMouseEvent& event);\n\n\tvoid OnGameListSize(wxSizeEvent& event);\n\tvoid AdjustLastColumnWidth();\n\tint GetColumnDefaultWidth(int column);\n\n\tvoid OnTimerBulkAddEntriesToGameList(wxTimerEvent& event);\n\n\tstatic inline std::once_flag s_launch_file_once;\n};\n\n"
  },
  {
    "path": "src/gui/wxgui/components/wxInputDraw.cpp",
    "content": "#include \"wxgui/components/wxInputDraw.h\"\n\n#include <wx/dcbuffer.h>\n#include <wx/settings.h>\n\nwxInputDraw::wxInputDraw(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size)\n\t: wxWindow(parent, id, pos, size, 0, wxPanelNameStr)\n{\n\tSetBackgroundStyle(wxBG_STYLE_PAINT);\n\tBind(wxEVT_PAINT, &wxInputDraw::OnPaintEvent, this);\n}\n\nwxInputDraw::~wxInputDraw() { Unbind(wxEVT_PAINT, &wxInputDraw::OnPaintEvent, this); }\n\nvoid wxInputDraw::OnPaintEvent(wxPaintEvent& event)\n{\n\twxAutoBufferedPaintDC dc(this);\n\tOnRender(dc);\n}\n\nvoid wxInputDraw::OnRender(wxDC& dc)\n{\n\tdc.Clear();\n\n\tglm::vec2 position = m_position;\n\n\twxPen black = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\twxPen red = *wxRED_PEN;\n\twxPen grey = wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));\n\twxPen green = wxSystemSettings::SelectLightDark(0x336600, 0x99FF99);\n\n\twxBrush black_brush = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);\n\twxBrush red_brush = *wxRED_BRUSH;\n\twxBrush grey_brush = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);\n\twxBrush green_brush = wxSystemSettings::SelectLightDark(0x336600, 0x99FF99);\n\n\tif(!IsEnabled())\n\t{\n\t\tposition = {};\n\t\tblack.SetColour(black.GetColour());\n\t\tred.SetColour(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));\n\t\tgrey.SetColour(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT).MakeDisabled());\n\n\t\tblack_brush = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);\n\t\tred_brush = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT).MakeDisabled();\n\t\tgrey_brush = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT).MakeDisabled();\n\t}\n\n\tdc.SetBackgroundMode(wxSOLID);\n\tdc.SetBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\tdc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\tdc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\tdc.Clear();\n\n\tconst auto size = GetSize();\n\tconst auto min_size = (float)std::min(size.GetWidth(), size.GetHeight()) - 1.0f;\n\tconst Vector2f middle{min_size / 2.0f, min_size / 2.0f};\n\n\t// border\n\tconst wxRect border{0, 0, (int)min_size, (int)min_size};\n\tdc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));\n\tdc.DrawRectangle(border);\n\n\tdc.SetPen(IsEnabled() ? green.GetColour() : grey.GetColour());\n\tdc.DrawCircle((int)middle.x, (int)middle.y, (int)middle.x);\n\n\tif (m_deadzone > 0)\n\t{\n\t\tdc.SetPen(grey);\n\t\tdc.SetBrush(grey_brush);\n\t\tconst auto deadzone_size = m_deadzone * min_size / 2.0f;\n\t\tdc.DrawCircle(\n\t\t\tstatic_cast<int>(middle.x),\n\t\t\tstatic_cast<int>(middle.x),\n\t\t\t(int)deadzone_size);\n\n\t\tif (length(position) >= m_deadzone)\n\t\t{\n\t\t\tdc.SetPen(red);\n\t\t\tdc.SetBrush(red_brush);\n\n\t\t\tif (std::abs(1.0f - length(position)) < 0.05f)\n\t\t\t{\n\t\t\t\tdc.SetPen(green);\n\t\t\t\tdc.SetBrush(green_brush);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdc.SetPen(black);\n\t\t\tdc.SetBrush(black_brush);\n\t\t}\n\t}\n\telse\n\t{\n\t\tdc.SetPen(red);\n\t\tdc.SetBrush(red_brush);\n\t}\n\n\t// draw axis\n\tconst wxPoint pos\n\t{\n\t\tstatic_cast<int>(middle.x + position.x * middle.x),\n\t\tstatic_cast<int>(middle.y - position.y * middle.y)\n\t};\n\tdc.DrawCircle(pos.x, pos.y, 2);\n\n\tdc.SetBrush(*wxTRANSPARENT_BRUSH);\n}\n\nvoid wxInputDraw::SetAxisValue(const glm::vec2& position)\n{\n\tm_position = position;\n\tRefresh();\n}\n\nvoid wxInputDraw::SetDeadzone(float deadzone)\n{\n\tm_deadzone = deadzone;\n\tRefresh();\n}\n"
  },
  {
    "path": "src/gui/wxgui/components/wxInputDraw.h",
    "content": "#pragma once\n\n#include \"input/api/ControllerState.h\"\n#include \"util/math/vector2.h\"\n\n#include <wx/window.h>\n\n\nclass wxInputDraw : public wxWindow\n{\npublic:\n\twxInputDraw(wxWindow *parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize);\n\t~wxInputDraw();\n\n\tvirtual void OnRender(wxDC& dc);\n\tvoid SetAxisValue(const glm::vec2& position);\n\tvoid SetDeadzone(float deadzone);\n\nprivate:\n\tvoid OnPaintEvent(wxPaintEvent& event);\n\n\tglm::vec2 m_position{};\n\tfloat m_deadzone{0};\n};\n"
  },
  {
    "path": "src/gui/wxgui/components/wxLogCtrl.cpp",
    "content": "#include \"wxgui/components/wxLogCtrl.h\"\n\n#include <boost/algorithm/string.hpp>\n\nwxDEFINE_EVENT(EVT_ON_LIST_UPDATED, wxEvent);\n\nwxLogCtrl::wxLogCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, bool alternateRowColours)\n\t: TextList(parent, id, pos, size, style)\n{\n\tm_timer = new wxTimer(this);\n\tthis->Bind(wxEVT_TIMER, &wxLogCtrl::OnTimer, this);\n\tthis->Bind(EVT_ON_LIST_UPDATED, &wxLogCtrl::OnActiveListUpdated, this);\n\tm_timer->Start(250);\n\n\tm_alternateRowColoursEnabled = alternateRowColours;\n}\n\nwxLogCtrl::~wxLogCtrl()\n{\n\tthis->Unbind(wxEVT_TIMER, &wxLogCtrl::OnTimer, this);\n\tthis->Unbind(EVT_ON_LIST_UPDATED, &wxLogCtrl::OnActiveListUpdated, this);\n\n\tif(m_timer)\n\t\tm_timer->Stop();\n\n\tif(m_update_worker.joinable())\n\t\tm_update_worker.join();\n}\n\nvoid wxLogCtrl::SetActiveFilter(const std::string& active_filter)\n{\n\tif(m_active_filter == active_filter)\n\t\treturn;\n\n\tm_active_filter = active_filter;\n\n\tif(m_update_worker.joinable())\n\t\tm_update_worker.join();\n\n\tm_update_worker = std::thread(&wxLogCtrl::UpdateActiveEntries, this);\n}\n\nconst std::string& wxLogCtrl::GetActiveFilter() const\n{\n\treturn m_active_filter;\n}\n\nvoid wxLogCtrl::SetFilterMessage(bool state)\n{\n\tif(m_filter_messages == state)\n\t\treturn;\n\n\tm_filter_messages = state;\n\n\tif(m_update_worker.joinable())\n\t\tm_update_worker.join();\n\n\tm_update_worker = std::thread(&wxLogCtrl::UpdateActiveEntries, this);\n}\n\nbool wxLogCtrl::GetFilterMessage() const\n{\n\treturn m_filter_messages;\n}\n\nvoid wxLogCtrl::PushEntry(const wxString& filter, const wxString& message)\n{\n\tstd::unique_lock lock(m_mutex);\n\tm_log_entries.emplace_back(filter, message);\n\tListIt_t it = m_log_entries.back();\n\tlock.unlock();\n\n\tif(m_active_filter.empty() || filter == m_active_filter || (m_filter_messages && boost::icontains(message.ToStdString(), m_active_filter)))\n\t{\n\t\tstd::unique_lock active_lock(m_active_mutex);\n\t\tm_active_entries.emplace_back(std::cref(it));\n\t\tconst auto entry_count = m_active_entries.size();\n\t\tactive_lock.unlock();\n\t\t\n\t\tif(entry_count <= m_elements_visible)\n\t\t{\n\t\t\tRefreshLine(entry_count - 1);\n\t\t}\n\t}\n}\n\nvoid wxLogCtrl::OnDraw(wxDC& dc, sint32 start, sint32 count, const wxPoint& start_position)\n{\n\twxPoint position = start_position;\n\n\tstd::scoped_lock lock(m_active_mutex);\n\tauto it = std::next(m_active_entries.cbegin(), start);\n\tif(it == m_active_entries.cend())\n\t\treturn;\n\n\tfor (sint32 i = 0; i <= count && it != m_active_entries.cend(); ++i, ++it)\n\t{\n\t\twxColour background_colour = GetBackgroundColour();\n\t\tif((start + i) % 2 != 0 && m_alternateRowColoursEnabled)\n\t\t\tbackground_colour = GetAlternateRowColour();\n\n\t\tDrawLineBackground(dc, position, background_colour);\n\n\t\tdc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\tdc.DrawText(it->get().second, position);\n\n\t\tNextLine(position, &start_position);\n\t}\n}\n\nvoid wxLogCtrl::OnTimer(wxTimerEvent& event)\n{\n\tstd::unique_lock lock(m_active_mutex);\n\tconst auto count = m_active_entries.size();\n\tif(count == m_element_count)\n\t\treturn;\n\n\tlock.unlock();\n\tSetElementCount(count);\n\n\tif(m_scrolled_to_end)\n\t{\n\t\tScroll(0, count);\n\t\tRefreshControl();\n\t}\n}\n\nvoid wxLogCtrl::OnActiveListUpdated(wxEvent& event)\n{\n\tstd::unique_lock lock(m_active_mutex);\n\tconst auto count = m_active_entries.size();\n\tlock.unlock();\n\n\tSetElementCount(count);\n\tRefreshControl();\n}\n\nvoid wxLogCtrl::UpdateActiveEntries()\n{\n\t{\n\t\tstd::scoped_lock lock(m_mutex, m_active_mutex);\n\t\tm_active_entries.clear();\n\t\tif(m_active_filter.empty())\n\t\t{\n\t\t\tfor (const auto& it : m_log_entries)\n\t\t\t\tm_active_entries.emplace_back(it);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor (const auto& it : m_log_entries)\n\t\t\t{\n\t\t\t\tif(it.first == m_active_filter ||\n                              (m_filter_messages && boost::icontains(it.second.ToStdString(), m_active_filter)) )\n\t\t\t\t\tm_active_entries.emplace_back(it);\n\t\t\t}\n\t\t}\n\t}\n\n\twxQueueEvent(this, new wxCommandEvent(EVT_ON_LIST_UPDATED));\n}\n\n"
  },
  {
    "path": "src/gui/wxgui/components/wxLogCtrl.h",
    "content": "#pragma once\n#include \"TextList.h\"\n\nclass wxLogCtrl : public TextList\n{\npublic:\n\twxLogCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, bool alternateRowColours = false);\n\t~wxLogCtrl();\n\n\tvoid SetActiveFilter(const std::string& active_filter);\n\t[[nodiscard]] const std::string& GetActiveFilter() const;\n\tvoid SetFilterMessage(bool state);\n\t[[nodiscard]] bool GetFilterMessage() const;\n\n\tvoid PushEntry(const wxString& filter, const wxString& message);\n\t\nprotected:\n\tvoid OnDraw(wxDC& dc, sint32 start, sint32 count, const wxPoint& start_position);\n\nprivate:\n\tvoid OnTimer(wxTimerEvent& event);\n\tvoid OnActiveListUpdated(wxEvent& event);\n\n\twxTimer* m_timer;\n\n\tbool m_alternateRowColoursEnabled = false;\n\twxColour m_alternateRowColour;\n\n\twxColour GetAlternateRowColour()\n\t{\n\t\tif (m_alternateRowColour.IsOk())\n\t\t\treturn m_alternateRowColour;\n\n\t\t// Depending on the background, alternate row colour should be a bit\n\t\t// darker or brighter.\n\t\tconst wxColour bgColour = GetBackgroundColour();\n\t\tint alpha = bgColour.GetRGB() > 0x808080 ? 97 : 110;\n\t\tm_alternateRowColour = bgColour.ChangeLightness(alpha);\n\t\treturn m_alternateRowColour;\n\t}\n\n\tstd::string m_active_filter;\n\tstd::thread m_update_worker;\n\tbool m_filter_messages = false;\n\n\tstd::mutex m_mutex, m_active_mutex;\n\tusing ListEntry_t = std::pair<wxString, wxString>;\n\tusing ListIt_t = std::list<ListEntry_t>::const_reference;\n\tstd::list<ListEntry_t> m_log_entries;\n\tstd::list<std::reference_wrapper<const ListEntry_t>> m_active_entries;\n\tvoid UpdateActiveEntries();\n};"
  },
  {
    "path": "src/gui/wxgui/components/wxProgressDialogManager.h",
    "content": "#pragma once\n\n#include <wx/event.h>\n#include <wx/progdlg.h>\n#include <wx/thread.h>\n#include \"util/helpers/Semaphore.h\"\n\nwxDEFINE_EVENT(wxEVT_CREATE_PROGRESS_DIALOG, wxThreadEvent);\nwxDEFINE_EVENT(wxEVT_DESTROY_PROGRESS_DIALOG, wxThreadEvent);\nwxDEFINE_EVENT(wxEVT_UPDATE_PROGRESS_DIALOG, wxThreadEvent);\n\n// wrapper for wxGenericProgressDialog which can be used from any thread\nclass wxProgressDialogManager : public wxEvtHandler\n{\npublic:\n    wxProgressDialogManager(wxWindow* parent) : m_parent(parent), m_dialog(nullptr)\n    {\n        Bind(wxEVT_CREATE_PROGRESS_DIALOG, &wxProgressDialogManager::OnCreateProgressDialog, this);\n        Bind(wxEVT_DESTROY_PROGRESS_DIALOG, &wxProgressDialogManager::OnDestroyProgressDialog, this);\n        Bind(wxEVT_UPDATE_PROGRESS_DIALOG, &wxProgressDialogManager::OnUpdateProgressDialog, this);\n    }\n\n    ~wxProgressDialogManager()\n    {\n        if (m_dialog)\n            Destroy();\n    }\n\n    void Create(const wxString& title, const wxString& message, int maximum, int style = wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME)\n    {\n        m_instanceSemaphore.increment();\n        m_isCancelled = false;\n        m_isSkipped = false;\n        wxThreadEvent event(wxEVT_CREATE_PROGRESS_DIALOG);\n        event.SetString(title);\n        event.SetInt(maximum);\n        event.SetExtraLong(style);\n        wxQueueEvent(this, event.Clone());\n    }\n\n    void Destroy()\n    {\n        wxThreadEvent event(wxEVT_DESTROY_PROGRESS_DIALOG);\n        wxQueueEvent(this, event.Clone());\n        m_instanceSemaphore.waitUntilZero(); // wait until destruction is complete\n    }\n\n    // this also updates the cancel and skip state\n    void Update(int value, const wxString& newmsg = wxEmptyString)\n    {\n        wxThreadEvent event(wxEVT_UPDATE_PROGRESS_DIALOG);\n        event.SetInt(value);\n        event.SetString(newmsg);\n        wxQueueEvent(this, event.Clone());\n    }\n\n    bool IsCancelled() const\n    {\n        return m_isCancelled;\n    }\n\n    bool IsSkipped() const\n    {\n        return m_isSkipped;\n    }\n\n    bool IsCancelledOrSkipped() const\n    {\n        return m_isCancelled || m_isSkipped;\n    }\n\nprivate:\n    void OnCreateProgressDialog(wxThreadEvent& event)\n    {\n        if (m_dialog)\n        {\n            m_dialog->Destroy();\n            m_instanceSemaphore.waitUntilZero();\n        }\n        m_maximum = event.GetInt();\n        m_dialog = new wxGenericProgressDialog(event.GetString(), \"Please wait...\", m_maximum, m_parent, event.GetExtraLong());\n    }\n\n    void OnDestroyProgressDialog(wxThreadEvent& event)\n    {\n        if (m_dialog)\n        {\n            m_dialog->Destroy();\n            m_dialog = nullptr;\n            m_instanceSemaphore.decrement();\n        }\n    }\n\n    void OnUpdateProgressDialog(wxThreadEvent& event)\n    {\n        if (m_dialog)\n        {\n            // make sure that progress is never >= maximum\n            // because wxGenericProgressDialog seems to become crashy on destruction otherwise\n            int progress = event.GetInt();\n            if(progress >= m_maximum)\n                progress = m_maximum - 1;\n            bool wasSkipped = false;\n            bool r = m_dialog->Update(progress, event.GetString(), &wasSkipped);\n            if(!r)\n                m_isCancelled = true;\n            if(wasSkipped)\n                m_isSkipped = true;\n        }\n    }\n\n    wxWindow* m_parent;\n    wxGenericProgressDialog* m_dialog;\n    bool m_isCancelled{false};\n    bool m_isSkipped{false};\n    int m_maximum{0};\n    CounterSemaphore m_instanceSemaphore; // used to synchronize destruction of the dialog\n};"
  },
  {
    "path": "src/gui/wxgui/components/wxTitleManagerList.cpp",
    "content": "#include \"wxgui/components/wxTitleManagerList.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"util/helpers/SystemException.h\"\n#include \"Cafe/TitleList/GameInfo.h\"\n#include \"Cafe/TitleList/TitleInfo.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n#include \"wxgui/components/wxGameList.h\"\n#include \"wxgui/helpers/wxCustomEvents.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n\n#include <wx/imaglist.h>\n#include <wx/wupdlock.h>\n#include <wx/menu.h>\n#include <wx/msgdlg.h>\n#include <wx/stattext.h>\n#include <wx/sizer.h>\n#include <wx/timer.h>\n#include <wx/panel.h>\n#include <wx/progdlg.h>\n#include \"../wxHelper.h\"\n\n#include <functional>\n\n#include \"config/ActiveSettings.h\"\n#include \"wxgui/ChecksumTool.h\"\n#include \"wxgui/MainWindow.h\"\n#include \"Cafe/TitleList/TitleId.h\"\n#include \"Cafe/TitleList/SaveList.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n\n#include <zarchive/zarchivewriter.h>\n#include <zarchive/zarchivereader.h>\n\n#include \"Common/FileStream.h\"\n\nwxDEFINE_EVENT(wxEVT_TITLE_FOUND, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_TITLE_REMOVED, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_REMOVE_ENTRY, wxCommandEvent);\n\nwxTitleManagerList::wxTitleManagerList(wxWindow* parent, wxWindowID id)\n\t: wxListView(parent, id, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_VIRTUAL)\n{\n\tAddColumns();\n\n\t// tooltip TODO: extract class mb wxPanelTooltip\n\tm_tooltip_window = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);\n\tauto* tooltip_sizer = new wxBoxSizer(wxVERTICAL);\n\tm_tooltip_text = new wxStaticText(m_tooltip_window, wxID_ANY, wxEmptyString);\n\ttooltip_sizer->Add(m_tooltip_text , 0, wxALL, 5);\n\tm_tooltip_window->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));\n\tm_tooltip_window->SetSizerAndFit(tooltip_sizer);\n\tm_tooltip_window->Hide();\n\tm_tooltip_timer = new wxTimer(this);\n\n\tBind(wxEVT_LIST_COL_CLICK, &wxTitleManagerList::OnColumnClick, this);\n\tBind(wxEVT_CONTEXT_MENU, &wxTitleManagerList::OnContextMenu, this);\n\tBind(wxEVT_LIST_ITEM_SELECTED, &wxTitleManagerList::OnItemSelected, this);\n\tBind(wxEVT_TIMER, &wxTitleManagerList::OnTimer, this);\n\tBind(wxEVT_REMOVE_ITEM, &wxTitleManagerList::OnRemoveItem, this);\n\tBind(wxEVT_REMOVE_ENTRY, &wxTitleManagerList::OnRemoveEntry, this);\n\tBind(wxEVT_TITLE_FOUND, &wxTitleManagerList::OnTitleDiscovered, this);\n\tBind(wxEVT_TITLE_REMOVED, &wxTitleManagerList::OnTitleRemoved, this);\n\tBind(wxEVT_CLOSE_WINDOW, &wxTitleManagerList::OnClose, this);\n\n\tm_callbackIdTitleList = CafeTitleList::RegisterCallback([](CafeTitleListCallbackEvent* evt, void* ctx) { ((wxTitleManagerList*)ctx)->HandleTitleListCallback(evt); }, this);\n\tm_callbackIdSaveList = CafeSaveList::RegisterCallback([](CafeSaveListCallbackEvent* evt, void* ctx) { ((wxTitleManagerList*)ctx)->HandleSaveListCallback(evt); }, this);\n\n\tShowSortIndicator(ColumnTitleId);\n}\n\nwxTitleManagerList::~wxTitleManagerList()\n{\n\tCafeSaveList::UnregisterCallback(m_callbackIdSaveList);\n\tCafeTitleList::UnregisterCallback(m_callbackIdTitleList);\n}\n\nboost::optional<const wxTitleManagerList::TitleEntry&> wxTitleManagerList::GetSelectedTitleEntry() const\n{\n\tconst auto selection = GetFirstSelected();\n\tif (selection != wxNOT_FOUND)\n\t{\n\t\tconst auto tmp = GetTitleEntry(selection);\n\t\tif (tmp.has_value())\n\t\t\treturn tmp.value();\n\t}\n\n\treturn {};\n}\n\nboost::optional<wxTitleManagerList::TitleEntry&> wxTitleManagerList::GetSelectedTitleEntry()\n{\n\tconst auto selection = GetFirstSelected();\n\tif (selection != wxNOT_FOUND)\n\t{\n\t\tconst auto tmp = GetTitleEntry(selection);\n\t\tif (tmp.has_value())\n\t\t\treturn tmp.value();\n\t}\n\n\treturn {};\n}\n\n//boost::optional<wxTitleManagerList::TitleEntry&> wxTitleManagerList::GetTitleEntry(EntryType type, uint64 titleid)\n//{\n//\tfor(const auto& v : m_data)\n//\t{\n//\t\tif (v->entry.title_id == titleid && v->entry.type == type)\n//\t\t\treturn v->entry;\n//\t}\n//\n//\treturn {};\n//}\n\nboost::optional<wxTitleManagerList::TitleEntry&> wxTitleManagerList::GetTitleEntryByUID(uint64 uid)\n{\n\tfor (const auto& v : m_data)\n\t{\n\t\tif (v->entry.location_uid == uid)\n\t\t\treturn v->entry;\n\t}\n\treturn {};\n}\n\nvoid wxTitleManagerList::AddColumns()\n{\n\twxListItem col0;\n\tcol0.SetId(ColumnTitleId);\n\tcol0.SetText(_(\"Title ID\"));\n\tcol0.SetWidth(120);\n\tInsertColumn(ColumnTitleId, col0);\n\n\twxListItem col1;\n\tcol1.SetId(ColumnName);\n\tcol1.SetText(_(\"Name\"));\n\tcol1.SetWidth(435);\n\tInsertColumn(ColumnName, col1);\n\n\twxListItem col2;\n\tcol2.SetId(ColumnType);\n\tcol2.SetText(_(\"Type\"));\n\tcol2.SetWidth(65);\n\tInsertColumn(ColumnType, col2);\n\n\twxListItem col3;\n\tcol3.SetId(ColumnVersion);\n\tcol3.SetText(_(\"Version\"));\n\tcol3.SetWidth(40);\n\tInsertColumn(ColumnVersion, col3);\n\n\twxListItem col4;\n\tcol4.SetId(ColumnRegion);\n\tcol4.SetText(_(\"Region\"));\n\tcol4.SetWidth(60);\n\tInsertColumn(ColumnRegion, col4);\n\n\twxListItem col5;\n\tcol5.SetId(ColumnFormat);\n\tcol5.SetText(_(\"Format\"));\n\tcol5.SetWidth(63);\n\tInsertColumn(ColumnFormat, col5);\n\n\twxListItem col6;\n\tcol6.SetId(ColumnLocation);\n\tcol6.SetText(_(\"Location\"));\n\tcol6.SetWidth(63);\n\tInsertColumn(ColumnLocation, col6);\n}\n\nwxString wxTitleManagerList::OnGetItemText(long item, long column) const\n{\n\tif (item >= GetItemCount())\n\t\treturn wxEmptyString;\n\n\tconst auto entry = GetTitleEntry(item);\n\tif (entry.has_value())\n\t\treturn GetTitleEntryText(entry.value(), (ItemColumn)column);\n\n\treturn wxEmptyString;\n}\n\nwxItemAttr* wxTitleManagerList::OnGetItemAttr(long item) const\n{\n\tstatic wxColour bgColourPrimary = GetBackgroundColour();\n\tstatic wxColour bgColourSecondary = wxHelper::CalculateAccentColour(bgColourPrimary);\n\tstatic wxListItemAttr s_primary_attr(GetTextColour(), bgColourPrimary, GetFont());\n\tstatic wxListItemAttr s_secondary_attr(GetTextColour(), bgColourSecondary, GetFont());\n\treturn item % 2 == 0 ? &s_primary_attr : &s_secondary_attr;\n}\n\nboost::optional<wxTitleManagerList::TitleEntry&> wxTitleManagerList::GetTitleEntry(long item)\n{\n\tlong counter = 0;\n\tfor (const auto& data : m_sorted_data)\n\t{\n\t\tif (!data.get().visible)\n\t\t\tcontinue;\n\n\t\tif (item != counter++)\n\t\t\tcontinue;\n\n\t\treturn data.get().entry;\n\t}\n\t\n\treturn {};\n}\n\nboost::optional<const wxTitleManagerList::TitleEntry&> wxTitleManagerList::GetTitleEntry(const fs::path& path) const\n{\n\tconst auto tmp = _pathToUtf8(path);\n\tfor (const auto& data : m_data)\n\t{\n\t\tif (boost::iequals(_pathToUtf8(data->entry.path), tmp))\n\t\t\treturn data->entry;\n\t}\n\n\treturn {};\n}\nboost::optional<wxTitleManagerList::TitleEntry&> wxTitleManagerList::GetTitleEntry(const fs::path& path)\n{\n\tconst auto tmp = _pathToUtf8(path);\n\tfor (const auto& data : m_data)\n\t{\n\t\tif (boost::iequals(_pathToUtf8(data->entry.path), tmp))\n\t\t\treturn data->entry;\n\t}\n\n\treturn {};\n}\n\nboost::optional<const wxTitleManagerList::TitleEntry&> wxTitleManagerList::GetTitleEntry(long item) const\n{\n\tlong counter = 0;\n\tfor (const auto& data : m_sorted_data)\n\t{\n\t\tif (!data.get().visible)\n\t\t\tcontinue;\n\n\t\tif (item != counter++)\n\t\t\tcontinue;\n\n\t\treturn data.get().entry;\n\t}\n\n\treturn {};\n}\n\nvoid wxTitleManagerList::OnConvertToCompressedFormat(uint64 titleId, uint64 rightClickedUID)\n{\n\tTitleInfo titleInfo_base;\n\tTitleInfo titleInfo_update;\n\tTitleInfo titleInfo_aoc;\n\n\ttitleId = TitleIdParser::MakeBaseTitleId(titleId); // if the titleId of a separate update is selected, this converts it back to the base titleId\n\tTitleIdParser titleIdParser(titleId);\n\tbool hasBaseTitleId = titleIdParser.GetType() != TitleIdParser::TITLE_TYPE::AOC;\n\tbool hasUpdateTitleId = titleIdParser.CanHaveSeparateUpdateTitleId();\n\tTitleId updateTitleId = hasUpdateTitleId ? titleIdParser.GetSeparateUpdateTitleId() : 0;\n\n\t// todo - AOC titleIds might differ from the base/update game in other bits than the type. We have to use the meta data from the base/update to match aoc to the base title id\n\t// for now we just assume they match\n\tTitleId aocTitleId;\n\tif (hasBaseTitleId)\n\t\taocTitleId = (titleId & (uint64)~0xFF00000000) | (uint64)0xC00000000;\n\telse\n\t\taocTitleId = titleId;\n\n\t// find base and update\n\tfor (const auto& data : m_data)\n\t{\n\t\tif (hasBaseTitleId && data->entry.title_id == titleId)\n\t\t{\n\t\t\tif (!titleInfo_base.IsValid())\n\t\t\t{\n\t\t\t\ttitleInfo_base = CafeTitleList::GetTitleInfoByUID(data->entry.location_uid);\n\t\t\t\tif(data->entry.location_uid == rightClickedUID)\n\t\t\t\t\tbreak; // prefer the users selection\n\t\t\t}\n\t\t}\n\t}\n\tfor (const auto& data : m_data)\n\t{\n\t\tif (hasUpdateTitleId && data->entry.title_id == updateTitleId)\n\t\t{\n\t\t\tif (!titleInfo_update.IsValid())\n\t\t\t{\n\t\t\t\ttitleInfo_update = CafeTitleList::GetTitleInfoByUID(data->entry.location_uid);\n\t\t\t\tif(data->entry.location_uid == rightClickedUID)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// if multiple updates are present use the newest one\n\t\t\t\tif (titleInfo_update.GetAppTitleVersion() < data->entry.version)\n\t\t\t\t\ttitleInfo_update = CafeTitleList::GetTitleInfoByUID(data->entry.location_uid);\n\t\t\t\tif(data->entry.location_uid == rightClickedUID)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t// find AOC\n\tfor (const auto& data : m_data)\n\t{\n\t\tif (data->entry.title_id == aocTitleId)\n\t\t{\n\t\t\ttitleInfo_aoc = CafeTitleList::GetTitleInfoByUID(data->entry.location_uid);\n\t\t\tif(data->entry.location_uid == rightClickedUID)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\twxString msg = _(\"The following content will be converted to a compressed Wii U archive file (.wua):\");\n\tmsg.append(\"\\n \\n\");\n\t\n\tif (titleInfo_base.IsValid())\n\t\tmsg.append(formatWxString(_(\"Base game:\\n{}\"), titleInfo_base.GetPrintPath()));\n\telse\n\t\tmsg.append(_(\"Base game:\\nNot installed\"));\n\n\tmsg.append(\"\\n\\n\");\n\n\tif (titleInfo_update.IsValid())\n\t\tmsg.append(formatWxString(_(\"Update:\\n{}\"), titleInfo_update.GetPrintPath()));\n\telse\n\t\tmsg.append(_(\"Update:\\nNot installed\"));\n\n\tmsg.append(\"\\n\\n\");\n\n\tif (titleInfo_aoc.IsValid())\n\t\tmsg.append(formatWxString(_(\"DLC:\\n{}\"), titleInfo_aoc.GetPrintPath()));\n\telse\n\t\tmsg.append(_(\"DLC:\\nNot installed\"));\n\n\tconst int answer = wxMessageBox(msg, _(\"Confirmation\"), wxOK | wxCANCEL | wxCENTRE | wxICON_QUESTION, this);\n\tif (answer != wxOK)\n\t\treturn;\n\tstd::vector<TitleInfo*> titlesToConvert;\n\tif (titleInfo_base.IsValid())\n\t\ttitlesToConvert.emplace_back(&titleInfo_base);\n\tif (titleInfo_update.IsValid())\n\t\ttitlesToConvert.emplace_back(&titleInfo_update);\n\tif (titleInfo_aoc.IsValid())\n\t\ttitlesToConvert.emplace_back(&titleInfo_aoc);\n\tif (titlesToConvert.empty())\n\t\treturn;\n\t// get short name\n\tCafeConsoleLanguage languageId = CafeConsoleLanguage::EN; // todo - use user's locale\n\tstd::string shortName;\n\tif (titleInfo_base.IsValid())\n\t\tshortName = titleInfo_base.GetMetaInfo()->GetShortName(languageId);\n\telse if (titleInfo_update.IsValid())\n\t\tshortName = titleInfo_update.GetMetaInfo()->GetShortName(languageId);\n\telse if (titleInfo_aoc.IsValid())\n\t\tshortName = titleInfo_aoc.GetMetaInfo()->GetShortName(languageId);\n\n\tif (!shortName.empty())\n\t{\n\t\tboost::replace_all(shortName, \":\", \"\");\n\t}\n\t// for the default output directory we use the first game path configured by the user\n\tstd::string defaultDir = \"\";\n\tif (!GetConfig().game_paths.empty())\n\t\tdefaultDir = GetConfig().game_paths.front();\n\t// get the short name, which we will use as a suggested default file name\n\tstd::string defaultFileName = std::move(shortName);\n\tboost::replace_all(defaultFileName, \"/\", \"\");\n\tboost::replace_all(defaultFileName, \"\\\\\", \"\");\n\n\tCafeConsoleRegion region = CafeConsoleRegion::Auto;\n\tif (titleInfo_base.IsValid() && titleInfo_base.HasValidXmlInfo())\n\t\tregion = titleInfo_base.GetMetaInfo()->GetRegion();\n\telse if (titleInfo_update.IsValid() && titleInfo_update.HasValidXmlInfo())\n\t\tregion = titleInfo_update.GetMetaInfo()->GetRegion();\n\n\tif (region == CafeConsoleRegion::JPN)\n\t\tdefaultFileName.append(\" (JP)\");\n\telse if (region == CafeConsoleRegion::EUR)\n\t\tdefaultFileName.append(\" (EU)\");\n\telse if (region == CafeConsoleRegion::USA)\n\t\tdefaultFileName.append(\" (US)\");\n\tif (titleInfo_update.IsValid())\n\t{\n\t\tdefaultFileName.append(fmt::format(\" (v{})\", titleInfo_update.GetAppTitleVersion()));\n\t}\n\tdefaultFileName.append(\".wua\");\n\n\t// ask the user to provide a path for the output file\n\twxFileDialog saveFileDialog(this, _(\"Save Wii U game archive file\"), defaultDir, wxString::FromUTF8(defaultFileName),\n\t\t\t\t\t\t\t\t\"WUA files (*.wua)|*.wua\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\n\tif (saveFileDialog.ShowModal() == wxID_CANCEL || saveFileDialog.GetPath().IsEmpty())\n\t\treturn;\n\tfs::path outputPath(wxHelper::MakeFSPath(saveFileDialog.GetPath()));\n\tfs::path outputPathTmp(wxHelper::MakeFSPath(saveFileDialog.GetPath().append(\"__tmp\")));\n\tstruct ZArchiveWriterContext\n\t{\n\t\tstatic void NewOutputFile(const int32_t partIndex, void* _ctx)\n\t\t{\n\t\t\tZArchiveWriterContext* ctx = (ZArchiveWriterContext*)_ctx;\n\t\t\tctx->fs = FileStream::createFile2(ctx->outputPath);\n\t\t\tif (!ctx->fs)\n\t\t\t\tctx->isValid = false;\n\t\t}\n\n\t\tstatic void WriteOutputData(const void* data, size_t length, void* _ctx)\n\t\t{\n\t\t\tZArchiveWriterContext* ctx = (ZArchiveWriterContext*)_ctx;\n\t\t\tif (ctx->fs)\n\t\t\t\tctx->fs->writeData(data, length);\n\t\t}\n\n\t\tbool RecursivelyCountFiles(const std::string& fscPath)\n\t\t{\n\t\t\tsint32 fscStatus;\n\t\t\tstd::unique_ptr<FSCVirtualFile> vfDir(fsc_openDirIterator(fscPath.c_str(), &fscStatus));\n\t\t\tif (!vfDir)\n\t\t\t\treturn false;\n\t\t\tif (cancelled)\n\t\t\t\treturn false;\n\t\t\tFSCDirEntry dirEntry;\n\t\t\twhile (fsc_nextDir(vfDir.get(), &dirEntry))\n\t\t\t{\n\t\t\t\tif (dirEntry.isFile)\n\t\t\t\t{\n\t\t\t\t\ttotalInputFileSize += (uint64)dirEntry.fileSize;\n\t\t\t\t\ttotalFileCount++;\n\t\t\t\t}\n\t\t\t\telse if (dirEntry.isDirectory)\n\t\t\t\t{\n\t\t\t\t\tif (!RecursivelyCountFiles(fmt::format(\"{}{}/\", fscPath, dirEntry.path)))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tbool RecursivelyAddFiles(std::string archivePath, std::string fscPath)\n\t\t{\n\t\t\tsint32 fscStatus;\n\t\t\tstd::unique_ptr<FSCVirtualFile> vfDir(fsc_openDirIterator(fscPath.c_str(), &fscStatus));\n\t\t\tif (!vfDir)\n\t\t\t\treturn false;\n\t\t\tif (cancelled)\n\t\t\t\treturn false;\n\t\t\tzaWriter->MakeDir(archivePath.c_str(), false);\n\t\t\tFSCDirEntry dirEntry;\n\t\t\twhile (fsc_nextDir(vfDir.get(), &dirEntry))\n\t\t\t{\n\t\t\t\tif (dirEntry.isFile)\n\t\t\t\t{\n\t\t\t\t\tzaWriter->StartNewFile((archivePath + dirEntry.path).c_str());\n\t\t\t\t\tstd::unique_ptr<FSCVirtualFile> vFile(fsc_open((fscPath + dirEntry.path).c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus));\n\t\t\t\t\tif (!vFile)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\ttransferBuffer.resize(32 * 1024); // 32KB\n\t\t\t\t\tuint32 readBytes;\n\t\t\t\t\twhile (true)\n\t\t\t\t\t{\n                        readBytes = vFile->fscReadData(transferBuffer.data(), transferBuffer.size());\n                        if(readBytes == 0)\n                            break;\n\t\t\t\t\t\tzaWriter->AppendData(transferBuffer.data(), readBytes);\n\t\t\t\t\t\tif (cancelled)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\ttransferredInputBytes += readBytes;\n\t\t\t\t\t}\n\t\t\t\t\tcurrentFileIndex++;\n\t\t\t\t}\n\t\t\t\telse if (dirEntry.isDirectory)\n\t\t\t\t{\n\t\t\t\t\tif (!RecursivelyAddFiles(fmt::format(\"{}{}/\", archivePath, dirEntry.path), fmt::format(\"{}{}/\", fscPath, dirEntry.path)))\n\t\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tbool LoadTitleMetaAndCountFiles(TitleInfo* titleInfo)\n\t\t{\n\t\t\tstd::string temporaryMountPath = TitleInfo::GetUniqueTempMountingPath();\n\t\t\ttitleInfo->Mount(temporaryMountPath.c_str(), \"\", FSC_PRIORITY_BASE);\n\t\t\tbool r = RecursivelyCountFiles(temporaryMountPath);\n\t\t\ttitleInfo->Unmount(temporaryMountPath.c_str());\n\t\t\treturn r;\n\t\t}\n\n\t\tbool StoreTitle(TitleInfo* titleInfo)\n\t\t{\n\t\t\tstd::string temporaryMountPath = TitleInfo::GetUniqueTempMountingPath();\n\t\t\ttitleInfo->Mount(temporaryMountPath.c_str(), \"\", FSC_PRIORITY_BASE);\n\t\t\tbool r = RecursivelyAddFiles(fmt::format(\"{:016x}_v{}/\", titleInfo->GetAppTitleId(), titleInfo->GetAppTitleVersion()), temporaryMountPath);\n\t\t\ttitleInfo->Unmount(temporaryMountPath.c_str());\n\t\t\treturn r;\n\t\t}\n\n\t\tbool AddTitles(TitleInfo** titles, size_t count)\n\t\t{\n\t\t\tcurrentFileIndex = 0;\n\t\t\ttotalFileCount = 0;\n\t\t\t// count files\n\t\t\tfor (size_t i = 0; i < count; i++)\n\t\t\t{\n\t\t\t\tif (!LoadTitleMetaAndCountFiles(titles[i]))\n\t\t\t\t\treturn false;\n\t\t\t\tif (cancelled)\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// store files\n\t\t\tfor (size_t i = 0; i < count; i++)\n\t\t\t{\n\t\t\t\tif (!StoreTitle(titles[i]))\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\t~ZArchiveWriterContext()\n\t\t{\n\t\t\tdelete fs;\n\t\t\tdelete zaWriter;\n\t\t};\n\n\t\tfs::path outputPath;\n\t\tFileStream* fs;\n\t\tZArchiveWriter* zaWriter{};\n\t\tbool isValid{false};\n\t\tstd::vector<uint8> transferBuffer;\n\t\tstd::atomic_bool cancelled{false};\n\t\t// progress\n\t\tstd::atomic_uint32_t totalFileCount{};\n\t\tstd::atomic_uint32_t currentFileIndex{};\n\t\tstd::atomic_uint64_t totalInputFileSize{};\n\t\tstd::atomic_uint64_t transferredInputBytes{};\n\t}writerContext;\n\n\t// mount and store\n\twriterContext.isValid = true;\n\twriterContext.outputPath = outputPathTmp;\n\twriterContext.zaWriter = new ZArchiveWriter(&ZArchiveWriterContext::NewOutputFile, &ZArchiveWriterContext::WriteOutputData, &writerContext);\n\tif (!writerContext.isValid)\n\t{\n\t\t// failed to create file\n\t\twxMessageBox(_(\"Unable to create file\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\t// open progress dialog\n\twxGenericProgressDialog progressDialog(\"Converting to .wua\",\n\t\t_(\"Counting files...\"),\n\t\t100,    // range\n\t\tthis,   // parent\n\t\twxPD_CAN_ABORT\n\t);\n\tprogressDialog.Show();\n\n\tauto asyncWorker = std::async(std::launch::async, &ZArchiveWriterContext::AddTitles, &writerContext, titlesToConvert.data(), titlesToConvert.size());\n\twhile (!future_is_ready(asyncWorker))\n\t{\n\t\tif (writerContext.cancelled)\n\t\t{\n\t\t\tprogressDialog.Update(0, _(\"Stopping...\"));\n\t\t}\n\t\telse if (writerContext.currentFileIndex != 0)\n\t\t{\n\t\t\tuint64 numSizeCompleted = writerContext.transferredInputBytes;\n\t\t\tuint64 numSizeTotal = writerContext.totalInputFileSize;\n\t\t\tuint32 pct = (uint32)(numSizeCompleted * (uint64)100 / numSizeTotal);\n\t\t\tpct = std::min(pct, (uint32)100);\n\t\t\tif (pct >= 100)\n\t\t\t\tpct = 99; // never set it to 100 as progress == total will make .Update() call ShowModal() and lock up this loop\n\t\t\tstd::string textSuffix = fmt::format(\" ({}MiB/{}MiB)\", numSizeCompleted / 1024 / 1024, numSizeTotal / 1024 / 1024);\n\t\t\tprogressDialog.Update(pct, _(\"Converting files...\") + textSuffix);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tprogressDialog.Update(0, _(\"Collecting list of files...\") + fmt::format(\" ({})\", writerContext.totalFileCount.load()));\n\t\t}\n\t\tif (progressDialog.WasCancelled())\n\t\t\twriterContext.cancelled.store(true);\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t}\n\tprogressDialog.Update(100-1, _(\"Finalizing...\"));\n\tbool r = asyncWorker.get();\n\tif (!r)\n\t{\n\t\tdelete writerContext.fs;\n\t\twriterContext.fs = nullptr;\n\t\tstd::error_code ec;\n\t\tfs::remove(outputPathTmp, ec);\n\t\treturn;\n\t}\n\twriterContext.zaWriter->Finalize();\n\tdelete writerContext.fs;\n\twriterContext.fs = nullptr;\n\t// verify the created WUA file\n\tZArchiveReader* zreader = ZArchiveReader::OpenFromFile(outputPathTmp);\n\tif (!zreader)\n\t{\n\t\twxMessageBox(_(\"Conversion failed\\n\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\tstd::error_code ec;\n\t\tfs::remove(outputPathTmp, ec);\n\t\treturn;\n\t}\n\t// todo - do a quick verification here\n\tdelete zreader;\n\t// finish\n\tprogressDialog.Hide();\n\tfs::rename(outputPathTmp, outputPath);\n\n\t// ask user if they want to delete the original titles\n\t// todo\n\n\n\tCafeTitleList::Refresh();\n\twxMessageBox(_(\"Conversion finished\\n\"), _(\"Complete\"), wxOK | wxCENTRE | wxICON_INFORMATION, this);\n}\n\nvoid wxTitleManagerList::OnClose(wxCloseEvent& event)\n{\n\tevent.Skip();\n\t// wait until all tasks are complete\n\tif (m_context_worker.valid())\n\t\tm_context_worker.get();\n}\n\nvoid wxTitleManagerList::OnColumnClick(wxListEvent& event)\n{\n\tconst int column = event.GetColumn();\n\tSortEntries(column);\n\tevent.Skip();\n}\n\nvoid wxTitleManagerList::RemoveItem(long item)\n{\n\tconst int item_count = GetItemCount();\n\n\tconst ItemData* ref = nullptr;\n\tlong counter = 0;\n\tfor(auto it = m_sorted_data.begin(); it != m_sorted_data.end(); ++it)\n\t{\n\t\tif (!it->get().visible)\n\t\t\tcontinue;\n\n\t\tif (item != counter++)\n\t\t\tcontinue;\n\n\t\tref = &(it->get());\n\t\tm_sorted_data.erase(it);\n\t\tbreak;\n\t}\n\n\t// shouldn't happen\n\tif (ref == nullptr)\n\t\treturn;\n\t\n\tfor(auto it = m_data.begin(); it != m_data.end(); ++it)\n\t{\n\t\tif (ref != (*it).get())\n\t\t\tcontinue;\n\t\t\n\t\tm_data.erase(it);\n\t\tbreak;\n\t}\n\n\tSetItemCount(std::max(0, item_count - 1));\n\tRefreshPage();\n}\n\nvoid wxTitleManagerList::RemoveItem(const TitleEntry& entry)\n{\n\tconst int item_count = GetItemCount();\n\n\tconst TitleEntry* ref = &entry;\n\tfor (auto it = m_sorted_data.begin(); it != m_sorted_data.end(); ++it)\n\t{\n\t\tif (ref != &it->get().entry)\n\t\t\tcontinue;\n\n\t\tm_sorted_data.erase(it);\n\t\tbreak;\n\t}\n\n\tfor (auto it = m_data.begin(); it != m_data.end(); ++it)\n\t{\n\t\tif (ref != &(*it).get()->entry)\n\t\t\tcontinue;\n\n\t\tm_data.erase(it);\n\t\tbreak;\n\t}\n\n\tSetItemCount(std::max(0, item_count - 1));\n\tRefreshPage();\n}\n\nvoid wxTitleManagerList::OnItemSelected(wxListEvent& event)\n{\n\tevent.Skip();\n\tm_tooltip_timer->Stop();\n\tconst auto selection = event.GetIndex();\n\n\tif (selection == wxNOT_FOUND)\n\t{\n\t\tm_tooltip_window->Hide();\n\t\treturn;\n\t}\n\n\tconst auto entry = GetTitleEntry(selection);\n\tif (!entry.has_value())\n\t{\n\t\tm_tooltip_window->Hide();\n\t\treturn;\n\t}\n\n\tm_tooltip_window->Hide();\n\treturn;\n\n\t//const auto mouse_position = wxGetMousePosition() - GetScreenPosition();\n\t//m_tooltip_window->SetPosition(wxPoint(mouse_position.x + 15, mouse_position.y + 15));\n\n\t//wxString msg;\n\t//switch(entry->error)\n\t//{\n\t//case TitleError::WrongBaseLocation:\n\t//\tmsg = _(\"This base game is installed at the wrong location.\");\n\t//\tbreak;\n\t//case TitleError::WrongUpdateLocation:\n\t//\tmsg = _(\"This update is installed at the wrong location.\");\n\t//\tbreak;\n\t//case TitleError::WrongDlcLocation:\n\t//\tmsg = _(\"This DLC is installed at the wrong location.\");\n\t//\tbreak;\n\t//default:\n\t//\treturn;;\n\t//}\n\n\t//m_tooltip_text->SetLabel(formatWxString(\"{}\\n{}\", msg, _(\"You can use the context menu to fix it.\")));\n\t//m_tooltip_window->Fit();\n\t//m_tooltip_timer->StartOnce(250);\n}\n\nenum ContextMenuEntries\n{\n\tkContextMenuOpenDirectory = wxID_HIGHEST + 1,\n\tkContextMenuDelete,\n\tkContextMenuLaunch,\n\tkContextMenuVerifyGameFiles,\n\tkContextMenuConvertToWUA,\n};\nvoid wxTitleManagerList::OnContextMenu(wxContextMenuEvent& event)\n{\n\t// still doing work\n\tif (m_context_worker.valid() && !future_is_ready(m_context_worker))\n\t\treturn;\n\t\n\twxMenu menu;\n\tmenu.Bind(wxEVT_COMMAND_MENU_SELECTED, &wxTitleManagerList::OnContextMenuSelected, this);\n\n\tconst auto selection = GetFirstSelected();\n\tif (selection == wxNOT_FOUND)\n\t\treturn;\n\n\tconst auto entry = GetTitleEntry(selection);\n\tif (!entry.has_value())\n\t\treturn;\n\n\tif(entry->type == EntryType::Base)\n\t\tmenu.Append(kContextMenuLaunch, _(\"&Launch title\"));\n\t\n\tmenu.Append(kContextMenuOpenDirectory, _(\"&Open directory\"));\n\tif (entry->type != EntryType::Save)\n\t\tmenu.Append(kContextMenuVerifyGameFiles, _(\"&Verify integrity of game files\"));\n\n\tmenu.AppendSeparator();\n\n\tif (entry->type != EntryType::Save && entry->format != EntryFormat::WUA)\n\t{\n\t\tmenu.Append(kContextMenuConvertToWUA, _(\"Convert to compressed Wii U archive (.wua)\"));\n\n\t\tmenu.AppendSeparator();\n\t}\n\tmenu.Append(kContextMenuDelete, _(\"&Delete\"));\t\n\n\tPopupMenu(&menu);\n\t\n\t// TODO: fix tooltip position\n}\n\nbool wxTitleManagerList::DeleteEntry(long index, const TitleEntry& entry)\n{\n\twxDTorFunc reset_text(wxQueueEvent, this, new wxSetStatusBarTextEvent(wxEmptyString, 1));\n\twxQueueEvent(this, new wxSetStatusBarTextEvent(\"Deleting entry...\", 1));\n\t\n\twxString msg;\n\tconst bool is_directory = fs::is_directory(entry.path);\n\tif(is_directory)\n\t\tmsg = formatWxString(_(\"Are you really sure that you want to delete the following folder:\\n{}\"), _pathToUtf8(entry.path));\n\telse\n\t\tmsg = formatWxString(_(\"Are you really sure that you want to delete the following file:\\n{}\"), _pathToUtf8(entry.path));\n\t\n\tconst auto result = wxMessageBox(msg, _(\"Warning\"), wxYES_NO | wxCENTRE | wxICON_EXCLAMATION, this);\n\tif (result == wxNO)\n\t\treturn false;\n\t\t\t\t\n\tstd::error_code ec;\n\tif (is_directory)\n\t{\n\t\tif (entry.type != EntryType::Save)\n\t\t{\n\t\t\t// delete content, meta, code folders first\n\t\t\tconst auto content = entry.path / \"content\";\n\t\t\tfs::remove_all(content, ec);\n\n\t\t\tconst auto meta = entry.path / \"meta\";\n\t\t\tfs::remove_all(meta, ec);\n\n\t\t\tconst auto code = entry.path / \"code\";\n\t\t\tfs::remove_all(code, ec);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// delete meta, user folders first\n\t\t\tconst auto meta = entry.path / \"meta\";\n\t\t\tfs::remove_all(meta, ec);\n\t\t\t\n\t\t\tconst auto user = entry.path / \"user\";\n\t\t\tfs::remove_all(user, ec);\n\t\t}\n\t\t\n\n\t\t// check if folder is empty\n\t\tif(fs::is_empty(entry.path, ec))\n\t\t\tfs::remove_all(entry.path, ec);\n\t}\t\n\telse // simply remove file\n\t\tfs::remove(entry.path, ec);\n\t\n\tif(ec)\n\t{\n\t\tconst auto error_msg = formatWxString(_(\"Error when trying to delete the entry:\\n{}\"), GetSystemErrorMessage(ec));\n\t\twxMessageBox(error_msg, _(\"Error\"), wxOK|wxCENTRE, this);\n\t\treturn false;\n\t}\n\n\t// thread safe request to delete entry\n\tconst auto evt = new wxCommandEvent(wxEVT_REMOVE_ITEM);\n\tevt->SetInt(index);\n\twxQueueEvent(this, evt);\n\treturn true;\n}\n\nvoid wxTitleManagerList::OnContextMenuSelected(wxCommandEvent& event)\n{\n\t// still doing work\n\tif (m_context_worker.valid() && !future_is_ready(m_context_worker))\n\t\treturn;\n\n\tconst auto selection = GetFirstSelected();\n\tif (selection == wxNOT_FOUND)\n\t\treturn;\n\n\tconst auto entry = GetTitleEntry(selection);\n\tif (!entry.has_value())\n\t\treturn;\n\t\n\tswitch (event.GetId())\n\t{\n\tcase kContextMenuOpenDirectory:\n\t\t{\n\t\t\tconst auto path = fs::is_directory(entry->path) ? entry->path : entry->path.parent_path();\n\t\t\twxLaunchDefaultApplication(wxHelper::FromPath(path));\n\t\t}\n\t\tbreak;\n\tcase kContextMenuDelete:\n\t\tm_context_worker = std::async(std::launch::async, &wxTitleManagerList::DeleteEntry, this, selection, entry.value());\n\t\tbreak;\n\tcase kContextMenuLaunch:\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tMainWindow::RequestLaunchGame(entry->path, wxLaunchGameEvent::INITIATED_BY::TITLE_MANAGER);\n\t\t\t\tClose();\n\t\t\t}\n\t\t\tcatch (const std::exception& ex)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"wxTitleManagerList::OnContextMenuSelected: can't launch title: {}\", ex.what());\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tcase kContextMenuVerifyGameFiles:\n\t\t(new ChecksumTool(this, entry.value()))->Show();\n\t\tbreak;\n\tcase kContextMenuConvertToWUA:\n\t\t\n\t\tOnConvertToCompressedFormat(entry.value().title_id, entry.value().location_uid);\n\t\tbreak;\n\t}\n}\n\nvoid wxTitleManagerList::OnTimer(wxTimerEvent& event)\n{\n\tif(event.GetTimer().GetId() != m_tooltip_timer->GetId())\n\t{\n\t\tevent.Skip();\n\t\treturn;\n\t}\n\n\tm_tooltip_window->Show();\n}\n\nvoid wxTitleManagerList::OnRemoveItem(wxCommandEvent& event)\n{\n\tRemoveItem(event.GetInt());\n}\n\nvoid wxTitleManagerList::OnRemoveEntry(wxCommandEvent& event)\n{\n\twxASSERT(event.GetClientData() != nullptr);\n\tRemoveItem(*(TitleEntry*)event.GetClientData());\n}\n\nwxString wxTitleManagerList::GetTitleEntryText(const TitleEntry& entry, ItemColumn column)\n{\n\tswitch (column)\n\t{\n\tcase ColumnTitleId:\n\t\treturn formatWxString(\"{:08x}-{:08x}\", (uint32) (entry.title_id >> 32), (uint32) (entry.title_id & 0xFFFFFFFF));\n\tcase ColumnName:\n\t\treturn entry.name;\n\tcase ColumnType:\n\t\treturn GetTranslatedTitleEntryType(entry.type);\n\tcase ColumnVersion:\n\t\treturn formatWxString(\"{}\", entry.version);\n\tcase ColumnRegion:\n\t\treturn wxGetTranslation(fmt::format(\"{}\", entry.region));\n\tcase ColumnFormat:\n\t{\n\t\tif (entry.type == EntryType::Save)\n\t\t\treturn _(\"Save folder\");\n\t\tswitch (entry.format)\n\t\t{\n\t\tcase wxTitleManagerList::EntryFormat::Folder:\n\t\t\treturn _(\"Folder\");\n\t\tcase wxTitleManagerList::EntryFormat::WUD:\n\t\t\treturn _(\"WUD\");\n\t\tcase wxTitleManagerList::EntryFormat::NUS:\n\t\t\treturn _(\"NUS\");\n\t\tcase wxTitleManagerList::EntryFormat::WUA:\n\t\t\treturn _(\"WUA\");\n\t\tcase wxTitleManagerList::EntryFormat::WUHB:\n\t\t\treturn _(\"WUHB\");\n\t\t}\n\t\treturn \"\";\n\t}\n\tcase ColumnLocation:\n\t{\n\t\tconst auto relative_mlc_path = _pathToUtf8(entry.path.lexically_relative(ActiveSettings::GetMlcPath()));\n\t\tif (relative_mlc_path.starts_with(\"usr\") || relative_mlc_path.starts_with(\"sys\"))\n\t\t\treturn _(\"MLC\");\n\t\telse\n\t\t\treturn _(\"Game Paths\");\n\t}\n\tdefault:\n\t\tUNREACHABLE;\n\t}\n\t\n\treturn wxEmptyString;\n}\n\nwxString wxTitleManagerList::GetTranslatedTitleEntryType(EntryType type)\n{\n\tswitch (type)\n\t{\n\t\tcase EntryType::Base:\n\t\t\treturn _(\"base\");\n\t\tcase EntryType::Update:\n\t\t\treturn _(\"update\");\n\t\tcase EntryType::Dlc:\n\t\t\treturn _(\"DLC\");\n\t\tcase EntryType::Save:\n\t\t\treturn _(\"save\");\n\t\tcase EntryType::System:\n\t\t\treturn _(\"system\");\n\t\tdefault:\n\t\t\treturn std::to_string(static_cast<std::underlying_type_t<EntryType>>(type));\n\t}\n}\n\nvoid wxTitleManagerList::HandleTitleListCallback(CafeTitleListCallbackEvent* evt)\n{\n\tif (evt->eventType != CafeTitleListCallbackEvent::TYPE::TITLE_DISCOVERED &&\n\t\tevt->eventType != CafeTitleListCallbackEvent::TYPE::TITLE_REMOVED)\n\t\treturn;\n\n\tauto& titleInfo = *evt->titleInfo;\n\twxTitleManagerList::EntryType entryType;\n\tswitch (titleInfo.GetTitleType())\n\t{\n\tcase TitleIdParser::TITLE_TYPE::BASE_TITLE_UPDATE:\n\t\tentryType = EntryType::Update;\n\t\tbreak;\n\tcase TitleIdParser::TITLE_TYPE::AOC:\n\t\tentryType = EntryType::Dlc;\n\t\tbreak;\n\tcase TitleIdParser::TITLE_TYPE::SYSTEM_DATA:\n\tcase TitleIdParser::TITLE_TYPE::SYSTEM_OVERLAY_TITLE:\n\tcase TitleIdParser::TITLE_TYPE::SYSTEM_TITLE:\n\t\tentryType = EntryType::System;\n\t\tbreak;\n\tdefault:\n\t\tentryType = EntryType::Base;\n\t}\n\n\twxTitleManagerList::EntryFormat entryFormat;\n\tswitch (titleInfo.GetFormat())\n\t{\n\tcase TitleInfo::TitleDataFormat::WUD:\n\t\tentryFormat = EntryFormat::WUD;\n\t\tbreak;\n\tcase TitleInfo::TitleDataFormat::NUS:\n\t\tentryFormat = EntryFormat::NUS;\n\t\tbreak;\n\tcase TitleInfo::TitleDataFormat::WIIU_ARCHIVE:\n\t\tentryFormat = EntryFormat::WUA;\n\t\tbreak;\n\tcase TitleInfo::TitleDataFormat::WUHB:\n\t\tentryFormat = EntryFormat::WUHB;\n\t\tbreak;\n\tcase TitleInfo::TitleDataFormat::HOST_FS:\n\tdefault:\n\t\tentryFormat = EntryFormat::Folder;\n\t\tbreak;\n\t}\n\n\tif (evt->eventType == CafeTitleListCallbackEvent::TYPE::TITLE_DISCOVERED)\n\t{\n\t\tif (titleInfo.IsCached())\n\t\t\treturn; // the title list only displays non-cached entries\n\t\twxTitleManagerList::TitleEntry entry(entryType, entryFormat, titleInfo.GetPath());\n\n\t\tParsedMetaXml* metaInfo = titleInfo.GetMetaInfo();\n\t\tif(titleInfo.IsSystemDataTitle())\n\t\t\treturn; // dont show system data titles for now\n\t\tentry.location_uid = titleInfo.GetUID();\n\t\tentry.title_id = titleInfo.GetAppTitleId();\n\t\tstd::string name = metaInfo->GetLongName(GetConfig().console_language.GetValue());\n\t\tconst auto nl = name.find(L'\\n');\n\t\tif (nl != std::string::npos)\n\t\t\tname.replace(nl, 1, \" - \");\n\t\tentry.name = wxString::FromUTF8(name);\n\t\tentry.version = titleInfo.GetAppTitleVersion();\n\t\tentry.region = metaInfo->GetRegion();\n\n\t\tauto* cmdEvt = new wxCommandEvent(wxEVT_TITLE_FOUND);\n\t\tcmdEvt->SetClientObject(new wxCustomData(entry));\n\t\twxQueueEvent(this, cmdEvt);\n\t}\n\telse if (evt->eventType == CafeTitleListCallbackEvent::TYPE::TITLE_REMOVED)\n\t{\n\t\twxTitleManagerList::TitleEntry entry(entryType, entryFormat, titleInfo.GetPath());\n\t\tentry.location_uid = titleInfo.GetUID();\n\t\tentry.title_id = titleInfo.GetAppTitleId();\n\n\t\tauto* cmdEvt = new wxCommandEvent(wxEVT_TITLE_REMOVED);\n\t\tcmdEvt->SetClientObject(new wxCustomData(entry));\n\t\twxQueueEvent(this, cmdEvt);\n\t}\n}\n\nvoid wxTitleManagerList::HandleSaveListCallback(struct CafeSaveListCallbackEvent* evt)\n{\n\tif (evt->eventType == CafeSaveListCallbackEvent::TYPE::SAVE_DISCOVERED)\n\t{\n\t\tParsedMetaXml* metaInfo = evt->saveInfo->GetMetaInfo();\n\t\tif (!metaInfo)\n\t\t\treturn;\n\t\tauto& saveInfo = *evt->saveInfo;\n\t\twxTitleManagerList::TitleEntry entry(EntryType::Save, EntryFormat::Folder, saveInfo.GetPath());\n\t\tentry.location_uid = std::hash<uint64>() ( metaInfo->GetTitleId() );\n\t\tentry.title_id = metaInfo->GetTitleId();\n\t\tstd::string name = metaInfo->GetLongName(GetConfig().console_language.GetValue());\n\t\tconst auto nl = name.find(L'\\n');\n\t\tif (nl != std::string::npos)\n\t\t\tname.replace(nl, 1, \" - \");\n\t\tentry.name = wxString::FromUTF8(name);\n\t\tentry.version = metaInfo->GetTitleVersion();\n\t\tentry.region = metaInfo->GetRegion();\n\n\t\tauto* cmdEvt = new wxCommandEvent(wxEVT_TITLE_FOUND);\n\t\tcmdEvt->SetClientObject(new wxCustomData(entry));\n\t\twxQueueEvent(this, cmdEvt);\n\t}\n}\n\nvoid wxTitleManagerList::OnTitleDiscovered(wxCommandEvent& event)\n{\n\tauto* obj = dynamic_cast<wxTitleManagerList::TitleEntryData_t*>(event.GetClientObject());\n\twxASSERT(obj);\n\tAddTitle(obj);\n}\n\nvoid wxTitleManagerList::OnTitleRemoved(wxCommandEvent& event)\n{\n\tauto* obj = dynamic_cast<wxTitleManagerList::TitleEntryData_t*>(event.GetClientObject());\n\twxASSERT(obj);\n\tfor (auto& itr : m_data)\n\t{\n\t\tif (itr.get()->entry.location_uid == obj->get().location_uid)\n\t\t{\n\t\t\tRemoveItem(itr.get()->entry);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid wxTitleManagerList::AddTitle(TitleEntryData_t* obj)\n{\n\tconst auto& data = obj->GetData();\n\tif (GetTitleEntryByUID(data.location_uid).has_value())\n\t\treturn; // already in list\n\tm_data.emplace_back(std::make_unique<ItemData>(true, data));\n\tm_sorted_data.emplace_back(*m_data[m_data.size() - 1]);\n\tSetItemCount(m_data.size());\n}\n\nint wxTitleManagerList::AddImage(const wxImage& image) const\n{\n\treturn -1; // m_image_list->Add(image.Scale(kListIconWidth, kListIconWidth, wxIMAGE_QUALITY_BICUBIC));\n}\n\n// return <\nbool wxTitleManagerList::SortFunc(int column, const Type_t& v1, const Type_t& v2)\n{\n\t// last sort option\n\tif (column == -1)\n\t\treturn v1.get().entry.path.compare(v2.get().entry.path) < 0;\n\n\t// visible have always priority\n\tif (!v1.get().visible && v2.get().visible)\n\t\treturn false;\n\telse if (v1.get().visible && !v2.get().visible)\n\t\treturn true;\n\n\tconst auto& entry1 = v1.get().entry;\n\tconst auto& entry2 = v2.get().entry;\n\t\n\t// check column: title id -> type -> path\n\tif (column == ColumnTitleId)\n\t{\n\t\t// ensure strong ordering -> use type since only one entry should be now (should be changed if every save for every user is displayed separately?)\n\t\tif (entry1.title_id == entry2.title_id)\n\t\t\treturn SortFunc(ColumnType, v1, v2);\n\t\t\n\t\treturn entry1.title_id < entry2.title_id;\n\t}\n\telse if (column == ColumnName)\n\t{\n\t\tconst int tmp = entry1.name.CmpNoCase(entry2.name);\n\t\tif(tmp == 0)\n\t\t\treturn SortFunc(ColumnTitleId, v1, v2);\n\t\t\t\n\t\treturn tmp < 0;\n\t}\n\telse if (column == ColumnType)\n\t{\n\t\tif(entry1.type == entry2.type)\n\t\t\treturn SortFunc(-1, v1, v2);\n\t\t\n\t\treturn std::underlying_type_t<EntryType>(entry1.type) < std::underlying_type_t<EntryType>(entry2.type);\n\t}\n\telse if (column == ColumnVersion)\n\t{\n\t\tif(entry1.version == entry2.version)\n\t\t\treturn SortFunc(ColumnTitleId, v1, v2);\n\n\t\treturn entry1.version < entry2.version;\n\t}\n\telse if (column == ColumnRegion)\n\t{\n\t\tif(entry1.region == entry2.region)\n\t\t\treturn SortFunc(ColumnTitleId, v1, v2);\n\n\t\treturn std::underlying_type_t<CafeConsoleRegion>(entry1.region) < std::underlying_type_t<CafeConsoleRegion>(entry2.region);\n\t}\n\telse if (column == ColumnFormat)\n\t{\n\t\tif(entry1.format == entry2.format)\n\t\t\treturn SortFunc(ColumnType, v1, v2);\n\n\t\treturn std::underlying_type_t<EntryFormat>(entry1.format) < std::underlying_type_t<EntryFormat>(entry2.format);\n\t}\n\t\t\n\treturn false;\n}\nvoid wxTitleManagerList::SortEntries(int column)\n{\n\tbool ascending;\n\tif (column == -1)\n\t{\n\t\tcolumn = GetSortIndicator();\n\t\tif (column == -1)\n\t\t\tcolumn = ColumnTitleId;\n\t\tascending = IsAscendingSortIndicator();\n\t}\n\telse\n\t\tascending = GetUpdatedAscendingSortIndicator(column);\n\n\tif (column != ColumnTitleId && column != ColumnName && column != ColumnType && column != ColumnVersion && column != ColumnRegion && column != ColumnFormat)\n\t\treturn;\n\n\tstd::sort(m_sorted_data.begin(), m_sorted_data.end(),\n\t\t\t  [this, column, ascending](const Type_t& v1, const Type_t& v2) -> bool {\n\t\t\t\t  return ascending ? SortFunc(column, v1, v2) : SortFunc(column, v2, v1);\n\t\t\t  });\n\n\tShowSortIndicator(column, ascending);\n\tRefreshPage();\n}\n\nvoid wxTitleManagerList::RefreshPage()\n{\n\tlong item_count = GetItemCount();\n\n\tif (item_count > 0)\n\t\tRefreshItems(GetTopItem(), std::min(item_count - 1, GetTopItem() + GetCountPerPage() + 1));\n}\n\nint wxTitleManagerList::Filter(const wxString& filter, const wxString& prefix, ItemColumn column)\n{\n\tif (prefix.empty())\n\t\treturn -1;\n\t\n\tif (!filter.StartsWith(prefix))\n\t\treturn -1;\n\n\tint counter = 0;\n\tconst auto tmp_filter = filter.substr(prefix.size() - 1).Trim(false);\n\tfor (auto&& data : m_data)\n\t{\n\t\tif (GetTitleEntryText(data->entry, column).Upper().Contains(tmp_filter))\n\t\t{\n\t\t\tdata->visible = true;\n\t\t\t++counter;\n\t\t}\n\t\telse\n\t\t\tdata->visible = false;\n\t}\n\treturn counter;\n}\n\nvoid wxTitleManagerList::Filter(const wxString& filter)\n{\n\tif(filter.empty())\n\t{\n\t\tstd::for_each(m_data.begin(), m_data.end(), [](ItemDataPtr& data) { data->visible = true; });\n\t\tSetItemCount(m_data.size());\n\t\tRefreshPage();\n\t\treturn;\n\t}\n\n\tconst auto filter_upper = filter.Upper().Trim(false).Trim(true);\n\tint counter = 0;\n\t\n\tif (const auto result = Filter(filter_upper, \"TITLEID:\", ColumnTitleId) != -1)\n\t\tcounter = result;\n\telse if (const auto result = Filter(filter_upper, \"NAME:\", ColumnName) != -1)\n\t\tcounter = result;\n\telse if (const auto result = Filter(filter_upper, \"TYPE:\", ColumnType) != -1)\n\t\tcounter = result;\n\telse if (const auto result = Filter(filter_upper, \"REGION:\", ColumnRegion) != -1)\n\t\tcounter = result;\n\telse if (const auto result = Filter(filter_upper, \"VERSION:\", ColumnVersion) != -1)\n\t\tcounter = result;\n\telse if (const auto result = Filter(filter_upper, \"FORMAT:\", ColumnFormat) != -1)\n\t\tcounter = result;\n\telse if(filter_upper == \"ERROR\")\n\t{\n\t\tfor (auto&& data : m_data)\n\t\t{\n\t\t\tbool visible = true;\n\t\t\tdata->visible = visible;\n\t\t\tif (visible)\n\t\t\t\t++counter;\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (auto&& data : m_data)\n\t\t{\n\t\t\tbool visible = false;\n\t\t\tif (data->entry.name.Upper().Contains(filter_upper))\n\t\t\t\tvisible = true;\n\t\t\telse if (GetTitleEntryText(data->entry, ColumnTitleId).Upper().Contains(filter_upper))\n\t\t\t\tvisible = true;\n\t\t\telse if (GetTitleEntryText(data->entry, ColumnType).Upper().Contains(filter_upper))\n\t\t\t\tvisible = true;\n\n\t\t\tdata->visible = visible;\n\t\t\tif (visible)\n\t\t\t\t++counter;\n\t\t}\n\t}\n\t\n\tSetItemCount(counter);\n\tRefreshPage();\n}\n\nsize_t wxTitleManagerList::GetCountByType(EntryType type) const\n{\n\tsize_t result = 0;\n\tfor(const auto& data : m_data)\n\t{\n\t\tif (data->entry.type == type)\n\t\t\t++result;\n\t}\n\treturn result;\n}\n\nvoid wxTitleManagerList::ClearItems()\n{\n\tm_sorted_data.clear();\n\tm_data.clear();\n\tSetItemCount(0);\n\tRefreshPage();\n}\n\nvoid wxTitleManagerList::AutosizeColumns()\n{\n\twxAutosizeColumns(this, ColumnTitleId, ColumnMAX - 1);\n}\n"
  },
  {
    "path": "src/gui/wxgui/components/wxTitleManagerList.h",
    "content": "#pragma once\n\n#include \"wxgui/helpers/wxCustomData.h\"\n#include \"config/CemuConfig.h\"\n\n#include <wx/listctrl.h>\n\n#include <boost/optional.hpp> // std::optional doesn't support optional reference inner types yet\n#include <utility>\n#include <vector>\n\nclass wxTitleManagerList : public wxListView\n{\n\tfriend class TitleManager;\npublic:\n\twxTitleManagerList(wxWindow* parent, wxWindowID id = wxID_ANY);\n\t~wxTitleManagerList();\n\n\tenum ItemColumn\n\t{\n\t\tColumnTitleId = 0,\n\t\tColumnName,\n\t\tColumnType,\n\t\tColumnVersion,\n\t\tColumnRegion,\n\t\tColumnFormat,\n\t\tColumnLocation,\n\n\t\tColumnMAX,\n\t};\n\n\tenum class EntryType\n\t{\n\t\tBase,\n\t\tUpdate,\n\t\tDlc,\n\t\tSave,\n\t\tSystem,\n\t};\n\n\tenum class EntryFormat\n\t{\n\t\tFolder,\n\t\tWUD,\n\t\tNUS,\n\t\tWUA,\n\t\tWUHB,\n\t};\n\n\t// sort by column, if -1 will sort by last column or default (=titleid)\n\tvoid SortEntries(int column);\n\tvoid RefreshPage();\n\tvoid Filter(const wxString& filter);\n\t[[nodiscard]] size_t GetCountByType(EntryType type) const;\n\tvoid ClearItems();\n\tvoid AutosizeColumns();\n\n\tstruct TitleEntry\n\t{\n\t\tTitleEntry(const EntryType& type, const EntryFormat& format, fs::path path)\n\t\t\t: type(type), format(format), path(std::move(path)) {}\n\n\t\tEntryType type;\n\t\tEntryFormat format;\n\t\tfs::path path;\n\n\t\tint icon = -1;\n\t\tuint64 location_uid;\n\t\tuint64 title_id;\n\t\twxString name;\n\t\tuint32_t version = 0;\n\t\tCafeConsoleRegion region;\n\n\t\tstd::vector<uint32> persistent_ids; // only used for save\n\t};\n\tboost::optional<const TitleEntry&> GetSelectedTitleEntry() const;\n\nprivate:\n\tvoid AddColumns();\n\tint Filter(const wxString& filter, const wxString& prefix, ItemColumn column);\n\tboost::optional<TitleEntry&> GetSelectedTitleEntry();\n\tboost::optional<TitleEntry&> GetTitleEntryByUID(uint64 uid);\n\n\tclass wxPanel* m_tooltip_window;\n\tclass wxStaticText* m_tooltip_text;\n\tclass wxTimer* m_tooltip_timer;\n\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid OnColumnClick(wxListEvent& event);\n\tvoid OnContextMenu(wxContextMenuEvent& event);\n\tvoid OnItemSelected(wxListEvent& event);\n\tvoid OnContextMenuSelected(wxCommandEvent& event);\n\tvoid OnTimer(class wxTimerEvent& event);\n\tvoid OnRemoveItem(wxCommandEvent& event);\n\tvoid OnRemoveEntry(wxCommandEvent& event);\n\n\tvoid OnTitleDiscovered(wxCommandEvent& event);\n\tvoid OnTitleRemoved(wxCommandEvent& event);\n\tvoid HandleTitleListCallback(struct CafeTitleListCallbackEvent* evt);\n\tvoid HandleSaveListCallback(struct CafeSaveListCallbackEvent* evt);\n\n\tusing TitleEntryData_t = wxCustomData<TitleEntry>;\n\tvoid AddTitle(TitleEntryData_t* obj);\n\tint AddImage(const wxImage& image) const;\n\twxString OnGetItemText(long item, long column) const override;\n\twxItemAttr* OnGetItemAttr(long item) const override;\n\t[[nodiscard]] boost::optional<const TitleEntry&> GetTitleEntry(long item) const;\n\t[[nodiscard]] boost::optional<TitleEntry&> GetTitleEntry(long item);\n\t[[nodiscard]] boost::optional<const TitleEntry&> GetTitleEntry(const fs::path& path) const;\n\t[[nodiscard]] boost::optional<TitleEntry&> GetTitleEntry(const fs::path& path);\n\n\tvoid OnConvertToCompressedFormat(uint64 titleId, uint64 rightClickedUID);\n\tbool DeleteEntry(long index, const TitleEntry& entry);\n\n\tvoid RemoveItem(long item);\n\tvoid RemoveItem(const TitleEntry& entry);\n\t\n\tstruct ItemData\n\t{\n\t\tItemData(bool visible, const TitleEntry& entry)\n\t\t\t: visible(visible), entry(entry) {}\n\t\t\n\t\tbool visible;\n\t\tTitleEntry entry;\n\t};\n\tusing ItemDataPtr = std::unique_ptr<ItemData>;\n\tstd::vector<ItemDataPtr> m_data;\n\tstd::vector<std::reference_wrapper<ItemData>> m_sorted_data;\n\n\tusing Type_t = std::reference_wrapper<const ItemData>;\n\tbool SortFunc(int column, const Type_t& v1, const Type_t& v2);\n\n\tstatic wxString GetTitleEntryText(const TitleEntry& entry, ItemColumn column);\n\tstatic wxString GetTranslatedTitleEntryType(EntryType entryType);\n\tstd::future<bool> m_context_worker;\n\n\tuint64 m_callbackIdTitleList;\n\tuint64 m_callbackIdSaveList;\n};\n"
  },
  {
    "path": "src/gui/wxgui/debugger/BreakpointWindow.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxgui/debugger/BreakpointWindow.h\"\n\n#include <sstream>\n\n#include \"wxgui/debugger/DebuggerWindow2.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n\n#include \"Cemu/ExpressionParser/ExpressionParser.h\"\n\nenum\n{\n\tMENU_ID_CREATE_CODE_BP_EXECUTION = 1,\n\tMENU_ID_CREATE_CODE_BP_LOGGING,\n\tMENU_ID_CREATE_MEM_BP_READ,\n\tMENU_ID_CREATE_MEM_BP_WRITE,\n\tMENU_ID_DELETE_BP,\n};\n\nenum ItemColumns\n{\n\tColumnEnabled = 0,\n\tColumnAddress,\n\tColumnType,\n\tColumnComment,\n};\n\nBreakpointWindow::BreakpointWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size)\n\t: wxFrame(&parent, wxID_ANY, _(\"Breakpoints\"), wxDefaultPosition, wxSize(420, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT)\n{\n\tthis->SetSizeHints(wxDefaultSize, wxDefaultSize);\n\t\n\twxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);\n\n\tm_breakpoints = new wxListView(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL);\n\tm_breakpoints->EnableCheckBoxes(true);\n\t\n\twxListItem col0;\n\tcol0.SetId(ColumnEnabled);\n\tcol0.SetText(_(\"On\"));\n\tcol0.SetWidth(32);\n\tm_breakpoints->InsertColumn(ColumnEnabled, col0);\n\n\twxListItem col1;\n\tcol1.SetId(ColumnAddress);\n\tcol1.SetText(_(\"Address\"));\n\tcol1.SetWidth(75);\n\tm_breakpoints->InsertColumn(ColumnAddress, col1);\n\n\twxListItem col2;\n\tcol2.SetId(ColumnType);\n\tcol2.SetText(_(\"Type\"));\n\tcol2.SetWidth(42);\n\tm_breakpoints->InsertColumn(ColumnType, col2);\n\n\twxListItem col3;\n\tcol3.SetId(ColumnComment);\n\tcol3.SetText(_(\"Comment\"));\n\tcol3.SetWidth(250);\n\tm_breakpoints->InsertColumn(ColumnComment, col3);\n\n\tmain_sizer->Add(m_breakpoints, 1, wxEXPAND);\n\n\tthis->SetSizer(main_sizer);\n\tthis->wxWindowBase::Layout();\n\n\tthis->Centre(wxBOTH);\n\n\tif (parent.GetConfig().data().pin_to_main)\n\t\tOnMainMove(main_position, main_size);\n\n\tm_breakpoints->Bind(wxEVT_LIST_ITEM_CHECKED, &BreakpointWindow::OnBreakpointToggled, this);\n\tm_breakpoints->Bind(wxEVT_LIST_ITEM_UNCHECKED, &BreakpointWindow::OnBreakpointToggled, this);\n\tm_breakpoints->Bind(wxEVT_LEFT_DCLICK, &BreakpointWindow::OnLeftDClick, this);\n\tm_breakpoints->Bind(wxEVT_RIGHT_DOWN, &BreakpointWindow::OnRightDown, this);\n\n\tOnUpdateView();\n}\n\nBreakpointWindow::~BreakpointWindow()\n{\n\tm_breakpoints->Unbind(wxEVT_LIST_ITEM_CHECKED, &BreakpointWindow::OnBreakpointToggled, this);\n\tm_breakpoints->Unbind(wxEVT_LIST_ITEM_UNCHECKED, &BreakpointWindow::OnBreakpointToggled, this);\n\tm_breakpoints->Unbind(wxEVT_LEFT_DCLICK, &BreakpointWindow::OnLeftDClick, this);\n\tm_breakpoints->Unbind(wxEVT_RIGHT_DOWN, &BreakpointWindow::OnRightDown, this);\n}\n\nvoid BreakpointWindow::OnMainMove(const wxPoint& main_position, const wxSize& main_size)\n{\n\twxSize size(420, 250);\n\tthis->SetSize(size);\n\n\twxPoint position = main_position;\n\tposition.x -= 420;\n\tposition.y += main_size.y - 250;\n\tthis->SetPosition(position);\n}\n\nvoid BreakpointWindow::OnUpdateView()\n{\n\tFreeze();\n\n\tm_breakpoints->DeleteAllItems();\n\n\tif (!debuggerState.breakpoints.empty())\n\t{\n\t\tuint32_t i = 0;\n\t\tfor (const auto bpBase : debuggerState.breakpoints)\n\t\t{\n\t\t\tDebuggerBreakpoint* bp = bpBase;\n\t\t\twhile (bp)\n\t\t\t{\n\t\t\t\twxListItem item = {};\n\t\t\t\titem.SetId(i++);\n\n\t\t\t\tconst auto index = m_breakpoints->InsertItem(item);\n\t\t\t\tm_breakpoints->SetItem(index, ColumnAddress, wxString::Format(\"%08x\", bp->address));\n\t\t\t\tconst char* typeName = \"UKN\";\n\t\t\t\tif (bp->bpType == DEBUGGER_BP_T_NORMAL)\n\t\t\t\t\ttypeName = \"X\";\n\t\t\t\telse if (bp->bpType == DEBUGGER_BP_T_LOGGING)\n\t\t\t\t\ttypeName = \"LOG\";\n\t\t\t\telse if (bp->bpType == DEBUGGER_BP_T_ONE_SHOT)\n\t\t\t\t\ttypeName = \"XS\";\n\t\t\t\telse if (bp->bpType == DEBUGGER_BP_T_MEMORY_READ)\n\t\t\t\t\ttypeName = \"R\";\n\t\t\t\telse if (bp->bpType == DEBUGGER_BP_T_MEMORY_WRITE)\n\t\t\t\t\ttypeName = \"W\";\n\n\t\t\t\tm_breakpoints->SetItem(index, ColumnType, typeName);\n\t\t\t\tm_breakpoints->SetItem(index, ColumnComment, bp->comment);\n\t\t\t\tm_breakpoints->CheckItem(index, bp->enabled);\n\t\t\t\tm_breakpoints->SetItemPtrData(index, (wxUIntPtr)bp);\n\n\t\t\t\tbp = bp->next;\n\t\t\t}\n\t\t}\n\t}\n\t\n\tThaw();\n}\n\nvoid BreakpointWindow::OnGameLoaded()\n{\n\tOnUpdateView();\n}\n\nvoid BreakpointWindow::OnBreakpointToggled(wxListEvent& event)\n{\n\tconst int32_t index = event.GetIndex();\n\tif (0 <= index && index < m_breakpoints->GetItemCount())\n\t{\n\t\tconst bool state = m_breakpoints->IsItemChecked(index);\n\t\twxString line = m_breakpoints->GetItemText(index, ColumnAddress);\n\t\tDebuggerBreakpoint* bp = (DebuggerBreakpoint*)m_breakpoints->GetItemData(index);\n\t\tconst uint32 address = std::stoul(line.ToStdString(), nullptr, 16);\n\t\tdebugger_toggleBreakpoint(address, state, bp);\n\t\tm_breakpoints->CheckItem(index, state);\n\t}\n}\n\nvoid BreakpointWindow::OnLeftDClick(wxMouseEvent& event)\n{\n\tconst auto position = event.GetPosition();\n\tint flags = 0;\n\tconst long index = m_breakpoints->HitTest(position, flags);\n\n\tif (index == wxNOT_FOUND)\n\t\treturn;\n\n\tsint32 x = position.x;\n\tconst auto enabled_width = m_breakpoints->GetColumnWidth(ColumnEnabled);\n\tif (x <= enabled_width)\n\t\treturn;\n\n\tx -= enabled_width;\n\tconst auto address_width = m_breakpoints->GetColumnWidth(ColumnAddress);\n\tif (x <= address_width)\n\t{\n\t\tconst auto item = m_breakpoints->GetItemText(index, ColumnAddress);\n\t\tconst auto address = std::stoul(item.ToStdString(), nullptr, 16);\n\t\tdebuggerState.debugSession.instructionPointer = address;\n\t\tg_debuggerDispatcher.MoveIP();\n\t\treturn;\n\t}\n\n\tx -= address_width;\n\tconst auto type_width = m_breakpoints->GetColumnWidth(ColumnType);\n\tif (x <= type_width)\n\t\treturn;\n\n\tx -= type_width;\n\tconst auto comment_width = m_breakpoints->GetColumnWidth(ColumnComment);\n\tif (x <= comment_width)\n\t{\n\t\tif (index >= debuggerState.breakpoints.size())\n\t\t\treturn;\n\n\t\tconst auto item = m_breakpoints->GetItemText(index, ColumnAddress);\n\t\tconst auto address = std::stoul(item.ToStdString(), nullptr, 16);\n\t\t\n\t\tauto it = debuggerState.breakpoints.begin();\n\t\tstd::advance(it, index);\n\n\t\tconst wxString dialogTitle = (*it)->bpType == DEBUGGER_BP_T_LOGGING ? _(\"Enter a new logging message\") : _(\"Enter a new comment\");\n\t\tconst wxString dialogMessage = (*it)->bpType == DEBUGGER_BP_T_LOGGING ? _(\"Set logging message when code at address %08x is ran.\\nUse placeholders like {r3} or {f3} to log register values\") : _(\"Set comment for breakpoint at address %08x\");\n\t\twxTextEntryDialog set_comment_dialog(this, dialogMessage, dialogTitle, (*it)->comment);\n\t\tif (set_comment_dialog.ShowModal() == wxID_OK)\n\t\t{\n\t\t\t(*it)->comment = set_comment_dialog.GetValue().ToStdWstring();\n\t\t\tm_breakpoints->SetItem(index, ColumnComment, set_comment_dialog.GetValue());\n\t\t}\n\t}\n}\n\nvoid BreakpointWindow::OnRightDown(wxMouseEvent& event)\n{\n\tint flags = 0;\n\tconst long index = m_breakpoints->HitTest(event.GetPosition(), flags);\n\tif (index == wxNOT_FOUND || index < 0 || index >= m_breakpoints->GetItemCount())\n\t{\n\t\twxMenu menu;\n\t\tmenu.Append(MENU_ID_CREATE_CODE_BP_EXECUTION, _(\"Create execution breakpoint\"));\n\t\tmenu.Append(MENU_ID_CREATE_CODE_BP_LOGGING, _(\"Create logging breakpoint\"));\n\t\tmenu.Append(MENU_ID_CREATE_MEM_BP_READ, _(\"Create memory breakpoint (read)\"));\n\t\tmenu.Append(MENU_ID_CREATE_MEM_BP_WRITE, _(\"Create memory breakpoint (write)\"));\n\n\t\tmenu.Bind(wxEVT_COMMAND_MENU_SELECTED, &BreakpointWindow::OnContextMenuClick, this);\n\t\tPopupMenu(&menu);\n\t}\n\telse\n\t{\n\t\tm_breakpoints->Focus(index);\n\t\tm_breakpoints->Select(index);\n\n\t\twxMenu menu;\n\t\tmenu.Append(MENU_ID_DELETE_BP, _(\"Delete breakpoint\"));\n\n\t\tmenu.Bind(wxEVT_COMMAND_MENU_SELECTED, &BreakpointWindow::OnContextMenuClickSelected, this);\n\t\tPopupMenu(&menu);\n\t}\n}\n\nvoid BreakpointWindow::OnContextMenuClickSelected(wxCommandEvent& evt)\n{\n\tif (evt.GetId() == MENU_ID_DELETE_BP)\n\t{\n\t\tlong sel = m_breakpoints->GetFirstSelected();\n\t\tif (sel == wxNOT_FOUND || sel < 0 || sel >= m_breakpoints->GetItemCount())\n\t\t\treturn;\n\n\t\tauto it = debuggerState.breakpoints.begin();\n\t\tstd::advance(it, sel);\n\n\t\tdebugger_deleteBreakpoint(*it);\n\n\t\twxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE);\n\t\twxPostEvent(this->m_parent, evt);\n\t}\n}\n\nvoid BreakpointWindow::OnContextMenuClick(wxCommandEvent& evt)\n{\n\twxTextEntryDialog goto_dialog(this, _(\"Enter a memory address\"), _(\"Set breakpoint\"), wxEmptyString);\n\tif (goto_dialog.ShowModal() == wxID_OK)\n\t{\n\t\tExpressionParser parser;\n\n\t\tauto value = goto_dialog.GetValue().ToStdString();\n\t\tstd::transform(value.begin(), value.end(), value.begin(), tolower);\n\n\t\tuint32_t newBreakpointAddress = 0;\n\t\ttry\n\t\t{\n\t\t\tdebugger_addParserSymbols(parser);\n\t\t\tnewBreakpointAddress = parser.IsConstantExpression(\"0x\"+value) ? (uint32)parser.Evaluate(\"0x\"+value) : (uint32)parser.Evaluate(value);\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\twxMessageBox(ex.what(), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\treturn;\n\t\t}\n\n\t\tswitch (evt.GetId())\n\t\t{\n\t\tcase MENU_ID_CREATE_CODE_BP_EXECUTION:\n\t\t\tdebugger_createCodeBreakpoint(newBreakpointAddress, DEBUGGER_BP_T_NORMAL);\n\t\t\tbreak;\n\t\tcase MENU_ID_CREATE_CODE_BP_LOGGING:\n\t\t\tdebugger_createCodeBreakpoint(newBreakpointAddress, DEBUGGER_BP_T_LOGGING);\n\t\t\tbreak;\n\t\tcase MENU_ID_CREATE_MEM_BP_READ:\n\t\t\tdebugger_createMemoryBreakpoint(newBreakpointAddress, true, false);\n\t\t\tbreak;\n\t\tcase MENU_ID_CREATE_MEM_BP_WRITE:\n\t\t\tdebugger_createMemoryBreakpoint(newBreakpointAddress, false, true);\n\t\t\tbreak;\n\t\t}\n\n\t\tthis->OnUpdateView();\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/debugger/BreakpointWindow.h",
    "content": "#pragma once\n\n#include <wx/frame.h>\n\nclass DebuggerWindow2;\nclass wxListEvent;\nclass wxListView;\n\nclass BreakpointWindow : public wxFrame\n{\npublic:\n\tBreakpointWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size);\n\tvirtual ~BreakpointWindow();\n\n\tvoid OnMainMove(const wxPoint& position, const wxSize& main_size);\n\tvoid OnUpdateView();\n\tvoid OnGameLoaded();\n\nprivate:\n\tvoid OnBreakpointToggled(wxListEvent& event);\n\tvoid OnLeftDClick(wxMouseEvent& event);\n\tvoid OnRightDown(wxMouseEvent& event);\n\n\tvoid OnContextMenuClick(wxCommandEvent& evt);\n\tvoid OnContextMenuClickSelected(wxCommandEvent& evt);\n\n\twxListView* m_breakpoints;\n};\n"
  },
  {
    "path": "src/gui/wxgui/debugger/DebuggerWindow2.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxgui/debugger/DebuggerWindow2.h\"\n\n#include \"wxHelper.h\"\n\n#include <filesystem>\n\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n#include \"Cafe/OS/RPL/rpl_debug_symbols.h\"\n\n#include \"wxgui/debugger/RegisterWindow.h\"\n#include \"wxgui/debugger/DumpWindow.h\"\n\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"wxgui/debugger/DisasmCtrl.h\"\n#include \"wxgui/debugger/SymbolWindow.h\"\n#include \"wxgui/debugger/BreakpointWindow.h\"\n#include \"wxgui/debugger/ModuleWindow.h\"\n#include \"util/helpers/helpers.h\"\n#include \"Cafe/HW/Espresso/Recompiler/PPCRecompiler.h\"\n#include \"Cemu/Logging/CemuLogging.h\"\n\n#include \"resource/embedded/resources.h\"\n\nenum\n{\n\t// file\n\tMENU_ID_FILE_EXIT = wxID_HIGHEST + 8000,\n\t// settings\n\tMENU_ID_OPTIONS_PIN_TO_MAINWINDOW,\n\tMENU_ID_OPTIONS_BREAK_ON_START,\n\tMENU_ID_OPTIONS_LOG_MEMORY_BREAKPOINTS,\n\tMENU_ID_OPTIONS_SWITCH_CPU_MODE,\n\t// window\n\tMENU_ID_WINDOW_REGISTERS,\n\tMENU_ID_WINDOW_DUMP,\n\tMENU_ID_WINDOW_STACK,\n\tMENU_ID_WINDOW_BREAKPOINTS,\n\tMENU_ID_WINDOW_MODULE,\n\tMENU_ID_WINDOW_SYMBOL,\n\n\t// tool\n\tTOOL_ID_GOTO,\n\tTOOL_ID_BP,\n\tTOOL_ID_PAUSE,\n\tTOOL_ID_STEP_OVER,\n\tTOOL_ID_STEP_INTO,\n};\n\nwxDEFINE_EVENT(wxEVT_DEBUGGER_CLOSE, wxCloseEvent);\nwxDEFINE_EVENT(wxEVT_UPDATE_VIEW, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_BREAKPOINT_CHANGE, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_BREAKPOINT_HIT, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_MOVE_IP, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_RUN, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_NOTIFY_MODULE_LOADED, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_NOTIFY_MODULE_UNLOADED, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_NOTIFY_GRAPHIC_PACKS_MODIFIED, wxCommandEvent);\n\nwxBEGIN_EVENT_TABLE(DebuggerWindow2, wxFrame)\n\tEVT_SHOW(DebuggerWindow2::OnShow)\n\tEVT_CLOSE(DebuggerWindow2::OnClose)\n\tEVT_COMMAND(wxID_ANY, wxEVT_UPDATE_VIEW, DebuggerWindow2::OnUpdateView)\n\tEVT_COMMAND(wxID_ANY, wxEVT_BREAKPOINT_CHANGE, DebuggerWindow2::OnBreakpointChange)\n\tEVT_COMMAND(wxID_ANY, wxEVT_MOVE_IP, DebuggerWindow2::OnMoveIP)\n\tEVT_COMMAND(wxID_ANY, wxEVT_COMMAND_TOOL_CLICKED, DebuggerWindow2::OnToolClicked)\n\tEVT_COMMAND(wxID_ANY, wxEVT_BREAKPOINT_HIT, DebuggerWindow2::OnBreakpointHit)\n\tEVT_COMMAND(wxID_ANY, wxEVT_RUN, DebuggerWindow2::OnRunProgram)\n\tEVT_COMMAND(wxID_ANY, wxEVT_NOTIFY_MODULE_LOADED, DebuggerWindow2::OnNotifyModuleLoaded)\n\tEVT_COMMAND(wxID_ANY, wxEVT_NOTIFY_MODULE_UNLOADED, DebuggerWindow2::OnNotifyModuleUnloaded)\n\tEVT_COMMAND(wxID_ANY, wxEVT_NOTIFY_GRAPHIC_PACKS_MODIFIED, DebuggerWindow2::OnNotifyGraphicPacksModified)\n\tEVT_COMMAND(wxID_ANY, wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, DebuggerWindow2::OnDisasmCtrlGotoAddress)\n\t// file menu\n\tEVT_MENU(MENU_ID_FILE_EXIT, DebuggerWindow2::OnExit)\n\t// window\n\tEVT_MENU_RANGE(MENU_ID_WINDOW_REGISTERS, MENU_ID_WINDOW_MODULE, DebuggerWindow2::OnWindowMenu)\nwxEND_EVENT_TABLE()\n\n\nDebuggerWindow2* g_debugger_window;\n\nvoid DebuggerConfig::Load(XMLConfigParser& parser)\n{\n\tpin_to_main = parser.get(\"PinToMainWindow\", true);\n\tbreak_on_start = parser.get(\"break_on_start\", true);\n\tlog_memory_breakpoints = parser.get(\"log_memory_breakpoints\", false);\n\n\tauto window_parser = parser.get(\"Windows\");\n\tshow_register = window_parser.get(\"Registers\", true);\n\tshow_dump = window_parser.get(\"MemoryDump\", true);\n\tshow_stack = window_parser.get(\"Stack\", true);\n\tshow_breakpoints = window_parser.get(\"Breakpoints\", true);\n\tshow_modules = window_parser.get(\"Modules\", true);\n\tshow_symbols = window_parser.get(\"Symbols\", true);\n}\n\nvoid DebuggerConfig::Save(XMLConfigParser& parser)\n{\n\tparser.set(\"PinToMainWindow\", pin_to_main);\n\tparser.set(\"break_on_start\", break_on_start);\n\tparser.set(\"log_memory_breakpoints\", log_memory_breakpoints);\n\n\tauto window_parser = parser.set(\"Windows\");\n\twindow_parser.set(\"Registers\", show_register);\n\twindow_parser.set(\"MemoryDump\", show_dump);\n\twindow_parser.set(\"Stack\", show_stack);\n\twindow_parser.set(\"Breakpoints\", show_breakpoints);\n\twindow_parser.set(\"Modules\", show_modules);\n\twindow_parser.set(\"Symbols\", show_symbols);\n}\n\nvoid DebuggerModuleStorage::Load(XMLConfigParser& parser)\n{\n\tauto breakpoints_parser = parser.get(\"Breakpoints\");\n\tfor (auto element = breakpoints_parser.get(\"Entry\"); element.valid(); element = breakpoints_parser.get(\"Entry\", element))\n\t{\n\t\tconst auto address_string = element.get(\"Address\", \"\");\n\t\tif (*address_string == '\\0')\n\t\t\tcontinue;\n\n\t\tuint32 relative_address = std::strtoul(address_string, nullptr, 16);\n\t\tif (relative_address == 0)\n\t\t\tcontinue;\n\n\t\tauto type = element.get(\"Type\", 0);\n\t\tauto enabled = element.get(\"Enabled\", true);\n\t\tconst auto comment = element.get(\"Comment\", \"\");\n\n\t\t// calculate absolute address\n\t\tuint32 module_base_address = (type == DEBUGGER_BP_T_NORMAL || type == DEBUGGER_BP_T_LOGGING) ? this->rpl_module->regionMappingBase_text.GetMPTR() : this->rpl_module->regionMappingBase_data;\n\t\tuint32 address = module_base_address + relative_address;\n\n\t\t// don't change anything if there's already a breakpoint\n\t\tif (debugger_getFirstBP(address) != nullptr)\n\t\t\tcontinue;\n\n\t\t// register breakpoints in debugger\n\t\tif (type == DEBUGGER_BP_T_NORMAL)\n\t\t\tdebugger_createCodeBreakpoint(address, DEBUGGER_BP_T_NORMAL);\n\t\telse if (type == DEBUGGER_BP_T_LOGGING)\n\t\t\tdebugger_createCodeBreakpoint(address, DEBUGGER_BP_T_LOGGING);\n\t\telse if (type == DEBUGGER_BP_T_MEMORY_READ)\n\t\t\tdebugger_createMemoryBreakpoint(address, true, false);\n\t\telse if (type == DEBUGGER_BP_T_MEMORY_WRITE)\n\t\t\tdebugger_createMemoryBreakpoint(address, false, true);\n\t\telse\n\t\t\tcontinue;\n\n\t\tDebuggerBreakpoint* debugBreakpoint = debugger_getFirstBP(address);\n\n\t\tif (!enabled)\n\t\t\tdebugger_toggleBreakpoint(address, false, debugBreakpoint);\n\n\t\tdebugBreakpoint->comment = boost::nowide::widen(comment);\n\t}\n\n\tauto comments_parser = parser.get(\"Comments\");\n\tfor (XMLConfigParser element = comments_parser.get(\"Entry\"); element.valid(); element = comments_parser.get(\"Entry\", element))\n\t{\n\t\tconst auto address_string = element.get(\"Address\", \"\");\n\t\tif (*address_string == '\\0')\n\t\t\tcontinue;\n\n\t\tuint32 address = std::strtoul(address_string, nullptr, 16);\n\t\tif (address == 0)\n\t\t\tcontinue;\n\n\t\tconst auto comment = element.get(\"Comment\", \"\");\n\t\tif (*comment == '\\0')\n\t\t\tcontinue;\n\n\t\trplDebugSymbol_createComment(address, boost::nowide::widen(comment).c_str());\n\t}\n}\n\nvoid DebuggerModuleStorage::Save(XMLConfigParser& parser)\n{\n\tauto breakpoints_parser = parser.set(\"Breakpoints\");\n\tfor (const auto& bp : debuggerState.breakpoints)\n\t{\n\t\t// check breakpoint type\n\t\tif (bp->dbType != DEBUGGER_BP_T_DEBUGGER)\n\t\t\tcontinue;\n\n\t\t// check whether the breakpoint is part of the current module being saved\n\t\tRPLModule* address_module;\n\t\tif (bp->bpType == DEBUGGER_BP_T_NORMAL || bp->bpType == DEBUGGER_BP_T_LOGGING) address_module = RPLLoader_FindModuleByCodeAddr(bp->address);\n\t\telse if (bp->isMemBP()) address_module = RPLLoader_FindModuleByDataAddr(bp->address);\n\t\telse continue;\n\n\t\tif (!address_module || !(address_module->moduleName2 == this->module_name && address_module->patchCRC == this->crc_hash))\n\t\t\tcontinue;\n\n\t\tuint32_t relative_address = bp->address - (bp->isMemBP() ? address_module->regionMappingBase_data : address_module->regionMappingBase_text.GetMPTR());\n\t\tauto entry = breakpoints_parser.set(\"Entry\");\n\t\tentry.set(\"Address\", fmt::format(\"{:#10x}\", relative_address));\n\t\tentry.set(\"Comment\", boost::nowide::narrow(bp->comment).c_str());\n\t\tentry.set(\"Type\", bp->bpType);\n\t\tentry.set(\"Enabled\", bp->enabled);\n\n\t\tif (this->delete_breakpoints_after_saving) debugger_deleteBreakpoint(bp);\n\t\tthis->delete_breakpoints_after_saving = false;\n\t}\n\n\tauto comments_parser = parser.set(\"Comments\");\n\tfor (const auto& comment_entry : rplDebugSymbol_getSymbols())\n\t{\n\t\t// check comment type\n\t\tconst auto comment_address = comment_entry.first;\n\t\tconst auto comment = static_cast<rplDebugSymbolComment*>(comment_entry.second);\n\t\tif (!comment || comment->type != RplDebugSymbolComment)\n\t\t\tcontinue;\n\n\t\t// check whether it's part of the current module being saved\n\t\tRPLModule* address_module = RPLLoader_FindModuleByCodeAddr(comment_entry.first);\n\t\tif (!address_module || !(address_module->moduleName2 == module_name && address_module->patchCRC == this->crc_hash))\n\t\t\tcontinue;\n\n\t\tuint32_t relative_address = comment_address - address_module->regionMappingBase_text.GetMPTR();\n\t\tauto entry = comments_parser.set(\"Entry\");\n\t\tentry.set(\"Address\", fmt::format(\"{:#10x}\", relative_address));\n\t\tentry.set(\"Comment\", boost::nowide::narrow(comment->comment).c_str());\n\t}\n}\n\nvoid DebuggerWindow2::CreateToolBar() \n{\n\tm_toolbar = wxFrame::CreateToolBar(wxTB_HORIZONTAL, wxID_ANY);\n\tm_toolbar->SetToolBitmapSize(wxSize(16, 16));\n\n\twxBitmap goto_bitmap = wxHelper::LoadThemedBitmapFromPNG(DEBUGGER_GOTO_png, sizeof(DEBUGGER_GOTO_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\tm_toolbar->AddTool(TOOL_ID_GOTO, wxEmptyString, goto_bitmap, wxNullBitmap, wxITEM_NORMAL, _(\"GoTo (CTRL + G)\"), \"test\", NULL);\n\tm_toolbar->AddSeparator();\n\n\twxBitmap bp_bitmap = wxHelper::LoadThemedBitmapFromPNG(DEBUGGER_BP_RED_png, sizeof(DEBUGGER_BP_RED_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\tm_toolbar->AddTool(TOOL_ID_BP, wxEmptyString, bp_bitmap, wxNullBitmap, wxITEM_NORMAL, _(\"Toggle Breakpoint (F9)\"), wxEmptyString, NULL);\n\tm_toolbar->AddSeparator();\n\n\tm_pause = wxHelper::LoadThemedBitmapFromPNG(DEBUGGER_PAUSE_png, sizeof(DEBUGGER_PAUSE_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\tm_run = wxHelper::LoadThemedBitmapFromPNG(DEBUGGER_PLAY_png, sizeof(DEBUGGER_PLAY_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\tm_toolbar->AddTool(TOOL_ID_PAUSE, wxEmptyString, m_pause, wxNullBitmap, wxITEM_NORMAL, _(\"Break (F5)\"), wxEmptyString, NULL);\n\n\twxBitmap step_into_bitmap = wxHelper::LoadThemedBitmapFromPNG(DEBUGGER_STEP_INTO_png, sizeof(DEBUGGER_STEP_INTO_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\twxBitmap step_over_bitmap = wxHelper::LoadThemedBitmapFromPNG(DEBUGGER_STEP_OVER_png, sizeof(DEBUGGER_STEP_OVER_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\tm_toolbar->AddTool(TOOL_ID_STEP_INTO, wxEmptyString, step_into_bitmap, wxNullBitmap, wxITEM_NORMAL, _(\"Step Into (F11)\"), wxEmptyString, NULL);\n\tm_toolbar->AddTool(TOOL_ID_STEP_OVER, wxEmptyString, step_over_bitmap, wxNullBitmap, wxITEM_NORMAL, _(\"Step Over (F10)\"), wxEmptyString, NULL);\n\tm_toolbar->AddSeparator();\n\n\tm_toolbar->Realize();\n\n\tm_toolbar->EnableTool(TOOL_ID_STEP_INTO, false);\n\tm_toolbar->EnableTool(TOOL_ID_STEP_OVER, false);\n\n}\n\nvoid DebuggerWindow2::SaveModuleStorage(const RPLModule* module, bool delete_breakpoints)\n{\n\tauto path = GetModuleStoragePath(module->moduleName2, module->patchCRC);\n\tfor (auto& module_storage : m_modules_storage)\n\t{\n\t\tif (module_storage->data().module_name == module->moduleName2 && module_storage->data().crc_hash == module->patchCRC)\n\t\t{\n\t\t\tmodule_storage->data().delete_breakpoints_after_saving = delete_breakpoints;\n\t\t\tmodule_storage->Save(path);\n\t\t\tif (delete_breakpoints) m_modules_storage.erase(std::find(m_modules_storage.begin(), m_modules_storage.end(), module_storage));\n\t\t}\n\t}\n\n}\n\nvoid DebuggerWindow2::LoadModuleStorage(const RPLModule* module)\n{\n\tauto path = GetModuleStoragePath(module->moduleName2, module->patchCRC);\n\tbool already_loaded = std::any_of(m_modules_storage.begin(), m_modules_storage.end(), [path](const std::unique_ptr<XMLDebuggerModuleConfig>& debug) { return debug->GetFilename() == path; });\n\tif (!path.empty() && !already_loaded)\n\t{\n\t\tm_modules_storage.emplace_back(new XMLDebuggerModuleConfig(path, { module->moduleName2, module->patchCRC, module, false }))->Load();\n\t}\n}\n\nDebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size)\n\t: wxFrame(&parent, wxID_ANY, _(\"PPC Debugger\"), wxDefaultPosition, wxSize(1280, 300), wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT),\n\t\tm_module_address(0)\n{\n\tg_debuggerDispatcher.SetDebuggerCallbacks(this);\n\n\tconst auto file = ActiveSettings::GetConfigPath(\"debugger/config.xml\");\n\tm_config.SetFilename(file.generic_wstring());\n\tm_config.Load();\n\n\tdebuggerState.breakOnEntry = m_config.data().break_on_start;\n\tdebuggerState.logOnlyMemoryBreakpoints = m_config.data().log_memory_breakpoints;\n\n\tm_main_position = parent.GetPosition();\n\tm_main_size = parent.GetSize();\n\n\tauto y = std::max<uint32>(300, (display_size.GetHeight() - 500 - 300) * 0.8);\n\tthis->SetSize(1280, y);\n\n\tCreateMenuBar();\n\tCreateToolBar();\n\n\twxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);\n\n\t// load configs for already loaded modules\n\tconst auto module_count = RPLLoader_GetModuleCount();\n\tconst auto module_list = RPLLoader_GetModuleList();\n\tfor (sint32 i = 0; i < module_count; i++)\n\t{\n\t\tconst auto module = module_list[i];\n\t\tLoadModuleStorage(module);\n\t}\n\n\twxString label_text = _(\"> no modules loaded\");\n\tif (module_count != 0)\n\t{\n\t\tRPLModule* current_rpl_module = RPLLoader_FindModuleByCodeAddr(MEMORY_CODEAREA_ADDR);\n\t\tif (current_rpl_module)\n\t\t\tlabel_text = wxString::Format(\"> %s\", current_rpl_module->moduleName2.c_str());\n\t\telse\n\t\t\tlabel_text = _(\"> unknown module\");\n\t}\n\n\tm_module_label = new wxStaticText(this, wxID_ANY, label_text);\n\tm_module_label->SetForegroundColour(wxColour(0xFFbf52fe));\n\tmain_sizer->Add(m_module_label, 0, wxEXPAND | wxALL, 5);\n\n\tm_disasm_ctrl = new DisasmCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxScrolledWindowStyle);\n\tmain_sizer->Add(m_disasm_ctrl, 1, wxEXPAND);\n\n\tthis->SetSizer(main_sizer);\n\tthis->wxWindowBase::Layout();\n\n\tm_register_window = new RegisterWindow(*this, m_main_position, m_main_size);\n\tm_dump_window = new DumpWindow(*this, m_main_position, m_main_size);\n\tm_breakpoint_window = new BreakpointWindow(*this, m_main_position, m_main_size);\n\tm_module_window = new ModuleWindow(*this, m_main_position, m_main_size);\n\tm_symbol_window = new SymbolWindow(*this, m_main_position, m_main_size);\n\n\tconst bool value = m_config.data().pin_to_main;\n\tm_config.data().pin_to_main = true;\n\tOnParentMove(m_main_position, m_main_size);\n\tm_config.data().pin_to_main = value;\n\n\tg_debugger_window = this;\n}\n\nDebuggerWindow2::~DebuggerWindow2()\n{\n\tg_debuggerDispatcher.ClearDebuggerCallbacks();\n\n\tdebuggerState.breakOnEntry = false;\n\tg_debugger_window = nullptr;\n\n\t// save configs for all modules that are still loaded\n\t// doesn't delete breakpoints since that should (in the future) be done by unloading the rpl modules when exiting the current game\n\tconst auto module_count = RPLLoader_GetModuleCount();\n\tconst auto module_list = RPLLoader_GetModuleList();\n\tfor (sint32 i = 0; i < module_count; i++)\n\t{\n\t\tconst auto module = module_list[i];\n\t\tif (module)\n\t\t\tSaveModuleStorage(module, false);\n\t}\n\n\tif (m_register_window && m_register_window->IsShown())\n\t\tm_register_window->Close(true);\n\n\tif (m_dump_window && m_dump_window->IsShown())\n\t\tm_dump_window->Close(true);\n\n\tif (m_breakpoint_window && m_breakpoint_window->IsShown())\n\t\tm_breakpoint_window->Close(true);\n\n\tif (m_module_window && m_module_window->IsShown())\n\t\tm_module_window->Close(true);\n\n\tif (m_symbol_window && m_symbol_window->IsShown())\n\t\tm_symbol_window->Close(true);\n\n\tm_config.Save();\n}\n\nvoid DebuggerWindow2::OnClose(wxCloseEvent& event)\n{\n\tdebuggerState.breakOnEntry = false;\n\t\n\tconst wxCloseEvent parentEvent(wxEVT_DEBUGGER_CLOSE);\n\twxPostEvent(m_parent, parentEvent);\n\n\tevent.Skip();\n}\n\nvoid DebuggerWindow2::OnMoveIP(wxCommandEvent& event)\n{\n\tconst auto ip = debuggerState.debugSession.instructionPointer;\n\tUpdateModuleLabel(ip);\n\tm_disasm_ctrl->CenterOffset(ip);\n}\n\nvoid DebuggerWindow2::OnDisasmCtrlGotoAddress(wxCommandEvent& event)\n{\n\tuint32 address = static_cast<uint32>(event.GetExtraLong());\n\tUpdateModuleLabel(address);\n}\n\nvoid DebuggerWindow2::OnParentMove(const wxPoint& main_position, const wxSize& main_size)\n{\n\tm_main_position = main_position;\n\tm_main_size = main_size;\n\n\tif (!m_config.data().pin_to_main)\n\t\treturn;\n\n\twxSize size(m_main_size.x, GetSize().GetHeight());\n\tSetSize(size);\n\n\twxPoint position = m_main_position;\n\tposition.y -= size.y;\n\tSetPosition(position);\n\n\tm_register_window->OnMainMove(main_position, main_size);\n\tm_dump_window->OnMainMove(main_position, main_size);\n\tm_breakpoint_window->OnMainMove(main_position, main_size);\n\tm_module_window->OnMainMove(main_position, main_size);\n\tm_symbol_window->OnMainMove(main_position, main_size);\n}\n\nvoid DebuggerWindow2::OnNotifyModuleLoaded(wxCommandEvent& event)\n{\n\tRPLModule* module = (RPLModule*)event.GetClientData();\n\tLoadModuleStorage(module);\n\tm_module_window->OnGameLoaded();\n\tm_symbol_window->OnGameLoaded();\n\tm_disasm_ctrl->Init();\n}\n\nvoid DebuggerWindow2::OnNotifyModuleUnloaded(wxCommandEvent& event)\n{\n\tRPLModule* module = (RPLModule*)event.GetClientData(); // todo - the RPL module is already unloaded at this point. Find a better way to handle this\n\tSaveModuleStorage(module, true);\n\tm_module_window->OnGameLoaded();\n\tm_symbol_window->OnGameLoaded();\n\tm_disasm_ctrl->Init();\n}\n\nvoid DebuggerWindow2::OnNotifyGraphicPacksModified(wxCommandEvent& event)\n{\n\tm_module_window->OnGameLoaded();\n\tm_symbol_window->OnGameLoaded();\n\tm_disasm_ctrl->Init();\n}\n\nvoid DebuggerWindow2::OnGameLoaded()\n{\n\tm_disasm_ctrl->Init();\n\n\tm_dump_window->OnGameLoaded();\n\tm_module_window->OnGameLoaded();\n\tm_breakpoint_window->OnGameLoaded();\n\tm_symbol_window->OnGameLoaded();\n\n\tRPLModule* current_rpl_module = RPLLoader_FindModuleByCodeAddr(MEMORY_CODEAREA_ADDR);\n\tif(current_rpl_module)\n\t\tm_module_label->SetLabel(wxString::Format(\"> %s\", current_rpl_module->moduleName2.c_str()));\t\n\n\tthis->SendSizeEvent();\n}\n\nXMLDebuggerConfig& DebuggerWindow2::GetConfig()\n{\n\treturn m_config;\n}\n\nbool DebuggerWindow2::Show(bool show)\n{\n\tconst bool result = wxFrame::Show(show);\n\n\tif (show)\n\t{\n\t\tm_register_window->Show(m_config.data().show_register);\n\t\tm_dump_window->Show(m_config.data().show_dump);\n\t\tm_breakpoint_window->Show(m_config.data().show_breakpoints);\n\t\tm_module_window->Show(m_config.data().show_modules);\n\t\tm_symbol_window->Show(m_config.data().show_symbols);\n\t}\n\telse\n\t{\n\t\tm_register_window->Show(false);\n\t\tm_dump_window->Show(false);\n\t\tm_breakpoint_window->Show(false);\n\t\tm_module_window->Show(false);\n\t\tm_symbol_window->Show(false);\n\t}\n\n\treturn result;\n}\n\nstd::wstring DebuggerWindow2::GetModuleStoragePath(std::string module_name, uint32_t crc_hash) const\n{\n\tif (module_name.empty() || crc_hash == 0) return {};\n\treturn ActiveSettings::GetConfigPath(\"debugger/{}_{:#10x}.xml\", module_name, crc_hash).generic_wstring();\n}\n\nvoid DebuggerWindow2::OnBreakpointHit(wxCommandEvent& event)\n{\n\tconst auto ip = debuggerState.debugSession.instructionPointer;\n\tUpdateModuleLabel(ip);\n\n\tm_toolbar->SetToolShortHelp(TOOL_ID_PAUSE, _(\"Run (F5)\"));\n\tm_toolbar->SetToolNormalBitmap(TOOL_ID_PAUSE, m_run);\n\n\tm_toolbar->EnableTool(TOOL_ID_STEP_INTO, true);\n\tm_toolbar->EnableTool(TOOL_ID_STEP_OVER, true);\n\n\tm_disasm_ctrl->CenterOffset(ip);\n}\n\nvoid DebuggerWindow2::OnRunProgram(wxCommandEvent& event)\n{\n\tm_toolbar->SetToolShortHelp(TOOL_ID_PAUSE, _(\"Break (F5)\"));\n\tm_toolbar->SetToolNormalBitmap(TOOL_ID_PAUSE, m_pause);\n\n\tm_toolbar->EnableTool(TOOL_ID_STEP_INTO, false);\n\tm_toolbar->EnableTool(TOOL_ID_STEP_OVER, false);\n}\n\nvoid DebuggerWindow2::OnToolClicked(wxCommandEvent& event)\n{\n\tswitch(event.GetId())\n\t{\n\tcase TOOL_ID_GOTO:\n\t\tm_disasm_ctrl->GoToAddressDialog();\n\t\tbreak;\n\tcase TOOL_ID_PAUSE:\n\t\tif (debugger_isTrapped())\n\t\t\tdebugger_resume();\n\t\telse\n\t\t\tdebugger_forceBreak();\n\t\tbreak;\n\tcase TOOL_ID_STEP_INTO:\n\t\tif (debugger_isTrapped())\n\t\t\tdebuggerState.debugSession.stepInto = true;\n\t\tbreak;\n\tcase TOOL_ID_STEP_OVER:\n\t\tif (debugger_isTrapped())\n\t\t\tdebuggerState.debugSession.stepOver = true;\n\t\tbreak;\n\t}\n}\n\nvoid DebuggerWindow2::OnBreakpointChange(wxCommandEvent& event)\n{\n\tm_breakpoint_window->OnUpdateView();\n\tm_disasm_ctrl->RefreshControl();\n\tUpdateModuleLabel();\n}\n\nvoid DebuggerWindow2::OnOptionsInput(wxCommandEvent& event)\n{\n\tswitch (event.GetId())\n\t{\n\tcase MENU_ID_OPTIONS_PIN_TO_MAINWINDOW:\n\t{\n\t\tconst bool value = !m_config.data().pin_to_main;\n\t\tm_config.data().pin_to_main = value;\n\t\tif (value)\n\t\t\tOnParentMove(m_main_position, m_main_size);\n\n\t\tbreak;\n\t}\n\tcase MENU_ID_OPTIONS_BREAK_ON_START:\n\t{\n\t\tconst bool value = !m_config.data().break_on_start;\n\t\tm_config.data().break_on_start = value;\n\t\tdebuggerState.breakOnEntry = value;\n\t\tbreak;\n\t}\n\tcase MENU_ID_OPTIONS_LOG_MEMORY_BREAKPOINTS:\n\t{\n\t\tconst bool value = !m_config.data().log_memory_breakpoints;\n\t\tm_config.data().log_memory_breakpoints = value;\n\t\tdebuggerState.logOnlyMemoryBreakpoints = value;\n\t\tbreak;\n\t}\n\tcase MENU_ID_OPTIONS_SWITCH_CPU_MODE:\n\t{\n\t\tif (ppcRecompilerEnabled)\n\t\t{\n\t\t\tppcRecompilerEnabled = false;\n\t\t\tcemuLog_log(LogType::Force, \"Debugger: Switched CPU mode to interpreter\");\n\t\t}\n\t\telse {\n\t\t\tppcRecompilerEnabled = true;\n\t\t\tcemuLog_log(LogType::Force, \"Debugger: Switched CPU mode to recompiler\");\n\t\t}\n\t\tbreak;\n\t}\n\tdefault:\n\t\treturn;\n\t}\n\n\tm_config.Save();\n}\n\nvoid DebuggerWindow2::OnWindowMenu(wxCommandEvent& event)\n{\n\tswitch (event.GetId())\n\t{\n\tcase MENU_ID_WINDOW_REGISTERS:\n\t{\n\t\tconst bool value = !m_config.data().show_register;\n\t\tm_config.data().show_register = value;\n\t\tm_register_window->Show(value);\n\t\tbreak;\n\t}\n\tcase MENU_ID_WINDOW_DUMP:\n\t{\n\t\tconst bool value = !m_config.data().show_dump;\n\t\tm_config.data().show_dump = value;\n\t\tm_dump_window->Show(value);\n\t\tbreak;\n\t}\n\tcase MENU_ID_WINDOW_BREAKPOINTS:\n\t{\n\t\tconst bool value = !m_config.data().show_breakpoints;\n\t\tm_config.data().show_breakpoints = value;\n\t\tm_breakpoint_window->Show(value);\n\t\tbreak;\n\t}\n\tcase MENU_ID_WINDOW_MODULE:\n\t{\n\t\tconst bool value = !m_config.data().show_modules;\n\t\tm_config.data().show_modules = value;\n\t\tm_module_window->Show(value);\n\t\tbreak;\n\t}\n\tcase MENU_ID_WINDOW_SYMBOL:\n\t{\n\t\tconst bool value = !m_config.data().show_symbols;\n\t\tm_config.data().show_symbols = value;\n\t\tm_symbol_window->Show(value);\n\t\tbreak;\n\t}\n\tdefault:\n\t\treturn;\n\t}\n\n\tm_config.Save();\n}\n\nvoid DebuggerWindow2::OnUpdateView(wxCommandEvent& event)\n{\n\tUpdateModuleLabel();\n\tm_disasm_ctrl->OnUpdateView();\n\tm_register_window->OnUpdateView();\n\tm_breakpoint_window->OnUpdateView();\n}\n\nvoid DebuggerWindow2::OnExit(wxCommandEvent& event)\n{\n\tthis->Close();\n}\n\nvoid DebuggerWindow2::OnShow(wxShowEvent& event)\n{\n\tm_register_window->Show();\n\tm_dump_window->Show();\n\tm_breakpoint_window->Show();\n\tm_module_window->Show();\n\tm_symbol_window->Show();\n\tevent.Skip();\n}\n\nvoid DebuggerWindow2::CreateMenuBar()\n{\n\tauto menu_bar = new wxMenuBar;\n\t\n\t// file\n\twxMenu* file_menu = new wxMenu;\n\tfile_menu->Append(MENU_ID_FILE_EXIT, _(\"&Exit\"));\n\tfile_menu->Bind(wxEVT_MENU, &DebuggerWindow2::OnExit, this);\n\n\tmenu_bar->Append(file_menu, _(\"&File\"));\n\n\t// options\n\twxMenu* options_menu = new wxMenu;\n\toptions_menu->Append(MENU_ID_OPTIONS_PIN_TO_MAINWINDOW, _(\"&Pin to main window\"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().pin_to_main);\n\toptions_menu->Append(MENU_ID_OPTIONS_BREAK_ON_START, _(\"Break on &entry point\"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().break_on_start);\n\toptions_menu->Append(MENU_ID_OPTIONS_LOG_MEMORY_BREAKPOINTS, _(\"Log only memory breakpoints\"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().log_memory_breakpoints);\n\toptions_menu->Append(MENU_ID_OPTIONS_SWITCH_CPU_MODE, _(\"Switch to &interpreter CPU mode\"), wxEmptyString, wxITEM_CHECK);\n\tmenu_bar->Append(options_menu, _(\"&Options\"));\n\n\t// window\n\twxMenu* window_menu = new wxMenu;\n\twindow_menu->Append(MENU_ID_WINDOW_REGISTERS, _(\"&Registers\"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().show_register);\n\twindow_menu->Append(MENU_ID_WINDOW_DUMP, _(\"&Memory Dump\"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().show_dump);\n\twindow_menu->Append(MENU_ID_WINDOW_BREAKPOINTS, _(\"&Breakpoints\"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().show_breakpoints);\n\twindow_menu->Append(MENU_ID_WINDOW_MODULE, _(\"Module&list\"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().show_modules);\n\twindow_menu->Append(MENU_ID_WINDOW_SYMBOL, _(\"&Symbols\"), wxEmptyString, wxITEM_CHECK)->Check(m_config.data().show_symbols);\n\t\n\tmenu_bar->Append(window_menu, _(\"&Window\"));\n\n\tSetMenuBar(menu_bar);\n\n\toptions_menu->Bind(wxEVT_MENU, &DebuggerWindow2::OnOptionsInput, this);\n\twindow_menu->Bind(wxEVT_MENU, &DebuggerWindow2::OnWindowMenu, this);\n}\n\nvoid DebuggerWindow2::UpdateModuleLabel(uint32 address)\n{\n\tif (address == 0)\n\t\taddress = m_disasm_ctrl->GetViewBaseAddress();\n\n\tRPLModule* module = RPLLoader_FindModuleByCodeAddr(address);\n\tif (module && m_module_address != module->regionMappingBase_text.GetMPTR())\n\t{\n\t\tm_module_label->SetLabel(wxString::Format(\"> %s\", module->moduleName2.c_str()));\n\t\tm_module_address = module->regionMappingBase_text.GetMPTR();\n\t}\n\telse if (address >= mmuRange_CODECAVE.getBase() && address < mmuRange_CODECAVE.getEnd())\n\t{\n\t\tm_module_label->SetLabel(wxString::Format(\"> %s\", \"Cemu codecave\"));\n\t\tm_module_address = mmuRange_CODECAVE.getBase();\n\t}\n}\n\nvoid DebuggerWindow2::UpdateViewThreadsafe()\n{\n\tauto* evt = new wxCommandEvent(wxEVT_UPDATE_VIEW);\n\twxQueueEvent(this, evt);\n}\n\nvoid DebuggerWindow2::NotifyDebugBreakpointHit()\n{\n\tauto* evt = new wxCommandEvent(wxEVT_BREAKPOINT_HIT);\n\twxQueueEvent(this, evt);\n}\n\nvoid DebuggerWindow2::NotifyRun()\n{\n\tauto* evt = new wxCommandEvent(wxEVT_RUN);\n\twxQueueEvent(this, evt);\n}\n\nvoid DebuggerWindow2::MoveIP()\n{\n\tauto* evt = new wxCommandEvent(wxEVT_MOVE_IP);\n\twxQueueEvent(this, evt);\n}\n\nvoid DebuggerWindow2::NotifyModuleLoaded(void* module)\n{\n\tauto* evt = new wxCommandEvent(wxEVT_NOTIFY_MODULE_LOADED);\n\tevt->SetClientData(module);\n\twxQueueEvent(this, evt);\n}\n\nvoid DebuggerWindow2::NotifyGraphicPacksModified()\n{\n\tauto* evt = new wxCommandEvent(wxEVT_NOTIFY_GRAPHIC_PACKS_MODIFIED);\n\twxQueueEvent(this, evt);\n}\n\nvoid DebuggerWindow2::NotifyModuleUnloaded(void* module)\n{\n\tauto* evt = new wxCommandEvent(wxEVT_NOTIFY_MODULE_UNLOADED);\n\tevt->SetClientData(module);\n\twxQueueEvent(this, evt);\n}\n"
  },
  {
    "path": "src/gui/wxgui/debugger/DebuggerWindow2.h",
    "content": "#pragma once\n\n#include \"wxgui/debugger/DisasmCtrl.h\"\n#include \"config/XMLConfig.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/HW/Espresso/Debugger/GDBStub.h\"\n\n#include <wx/bitmap.h>\n#include <wx/frame.h>\n#include <wx/mstream.h>\n\nclass BreakpointWindow;\nclass RegisterWindow;\nclass DumpWindow;\nclass ModuleWindow;\nclass SymbolWindow;\nclass wxStaticText;\n\nwxDECLARE_EVENT(wxEVT_UPDATE_VIEW, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_BREAKPOINT_HIT, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_RUN, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_BREAKPOINT_CHANGE, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_MOVE_IP, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_NOTIFY_MODULE_LOADED, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_NOTIFY_MODULE_UNLOADED, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_NOTIFY_GRAPHIC_PACKS_MODIFIED, wxCommandEvent);\n\nextern class DebuggerWindow2* g_debugger_window;\n\nstruct DebuggerConfig\n{\n\tDebuggerConfig()\n\t: pin_to_main(true), break_on_start(true), log_memory_breakpoints(false), show_register(true), show_dump(true), show_stack(true), show_breakpoints(true), show_modules(true), show_symbols(true) {}\n\n\tbool pin_to_main;\n\tbool break_on_start;\n\tbool log_memory_breakpoints;\n\n\tbool show_register;\n\tbool show_dump;\n\tbool show_stack;\n\tbool show_breakpoints;\n\tbool show_modules;\n\tbool show_symbols;\n\n\tvoid Load(XMLConfigParser& parser);\n\tvoid Save(XMLConfigParser& parser);\n};\ntypedef XMLDataConfig<DebuggerConfig> XMLDebuggerConfig;\n\nstruct DebuggerModuleStorage\n{\n\tstd::string module_name;\n\tuint32_t crc_hash;\n\tconst RPLModule* rpl_module;\n\tbool delete_breakpoints_after_saving;\n\n\tvoid Load(XMLConfigParser& parser);\n\tvoid Save(XMLConfigParser& parser);\n};\ntypedef XMLDataConfig<DebuggerModuleStorage> XMLDebuggerModuleConfig;\n\nstatic wxBitmap LoadThemedBitmapFromPNG(const uint8* data, size_t size, const wxColour& tint)\n{\n\twxMemoryInputStream strm(data, size);\n\twxImage img(strm, wxBITMAP_TYPE_PNG);\n\timg.Replace(0x00, 0x00, 0x00, tint.Red(), tint.Green(), tint.Blue());\n\treturn wxBitmap(img);\n}\n\nclass DebuggerWindow2 : public wxFrame, public DebuggerCallbacks\n{\npublic:\n\tvoid CreateToolBar();\n\tvoid LoadModuleStorage(const RPLModule* module);\n\tvoid SaveModuleStorage(const RPLModule* module, bool delete_breakpoints);\n\tDebuggerWindow2(wxFrame& parent, const wxRect& display_size);\n\t~DebuggerWindow2();\n\n\tvoid OnParentMove(const wxPoint& position, const wxSize& size);\n\tvoid OnGameLoaded();\n\n\tXMLDebuggerConfig& GetConfig();\n\n\tbool Show(bool show = true) override;\n\tstd::wstring GetModuleStoragePath(std::string module_name, uint32_t crc_hash) const;\n\nprivate:\n\tvoid OnBreakpointHit(wxCommandEvent& event);\n\tvoid OnRunProgram(wxCommandEvent& event);\n\tvoid OnToolClicked(wxCommandEvent& event);\n\tvoid OnBreakpointChange(wxCommandEvent& event);\n\tvoid OnOptionsInput(wxCommandEvent& event);\n\tvoid OnWindowMenu(wxCommandEvent& event);\n\tvoid OnUpdateView(wxCommandEvent& event);\n\tvoid OnExit(wxCommandEvent& event);\n\tvoid OnShow(wxShowEvent& event);\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid OnMoveIP(wxCommandEvent& event);\n\tvoid OnNotifyModuleLoaded(wxCommandEvent& event);\n\tvoid OnNotifyModuleUnloaded(wxCommandEvent& event);\n\tvoid OnNotifyGraphicPacksModified(wxCommandEvent& event);\n\t// events from DisasmCtrl\n\tvoid OnDisasmCtrlGotoAddress(wxCommandEvent& event);\n\n\tvoid CreateMenuBar();\n\tvoid UpdateModuleLabel(uint32 address = 0);\n\n\tvoid UpdateViewThreadsafe() override;\n\tvoid NotifyDebugBreakpointHit() override;\n\tvoid NotifyRun() override;\n\tvoid MoveIP() override;\n\tvoid NotifyModuleLoaded(void* module) override;\n\tvoid NotifyGraphicPacksModified() override;\n\tvoid NotifyModuleUnloaded(void* module) override;\n\n\tXMLDebuggerConfig m_config;\n\tstd::vector<std::unique_ptr<XMLDebuggerModuleConfig>> m_modules_storage;\n\n\twxPoint m_main_position;\n\twxSize m_main_size;\n\t\n\tRegisterWindow* m_register_window;\n\tDumpWindow* m_dump_window;\n\tBreakpointWindow* m_breakpoint_window;\n\tModuleWindow* m_module_window;\n\tSymbolWindow* m_symbol_window;\n\n\tDisasmCtrl* m_disasm_ctrl;\n\n\twxToolBar* m_toolbar;\n\twxBitmap m_run, m_pause;\n\n\tuint32 m_module_address;\n\twxStaticText* m_module_label;\n\n\nwxDECLARE_EVENT_TABLE();\n};\n\n"
  },
  {
    "path": "src/gui/wxgui/debugger/DisasmCtrl.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxgui/debugger/DisasmCtrl.h\"\n\n#include \"wxHelper.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/RPL/rpl_symbol_storage.h\"\n#include \"Cafe/OS/RPL/rpl_debug_symbols.h\"\n#include \"Cemu/PPCAssembler/ppcAssembler.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include \"wxgui/debugger/DebuggerWindow2.h\"\n#include \"util/helpers/helpers.h\"\n\n#include \"Cemu/ExpressionParser/ExpressionParser.h\"\n#include \"Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h\"\n\nwxDEFINE_EVENT(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, wxCommandEvent);\n\n#define MAX_SYMBOL_LEN\t\t\t(120)\n\n\nconstexpr uint8 arrowRightPNG[] =\n{\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0B,\n\t0x08, 0x03, 0x00, 0x00, 0x00, 0x41, 0x3C, 0xFD, 0x0B, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x06, 0x50, 0x4C, 0x54, 0x45, 0x00, 0x00,\n\t0x00, 0x00, 0x00, 0x00, 0xA5, 0x67, 0xB9, 0xCF, 0x00, 0x00, 0x00, 0x02,\n\t0x74, 0x52, 0x4E, 0x53, 0xFF, 0x00, 0xE5, 0xB7, 0x30, 0x4A, 0x00, 0x00,\n\t0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00,\n\t0x0E, 0xC3, 0x01, 0xC7, 0x6F, 0xA8, 0x64, 0x00, 0x00, 0x00, 0x2C, 0x49,\n\t0x44, 0x41, 0x54, 0x18, 0x57, 0x63, 0x60, 0x84, 0x03, 0x08, 0x13, 0x59,\n\t0x00, 0xCC, 0x46, 0x11, 0x00, 0x71, 0x80, 0x24, 0x32, 0xC0, 0x10, 0x60,\n\t0xC0, 0x10, 0xC0, 0x00, 0x58, 0xCC, 0x80, 0xD8, 0x00, 0x02, 0x60, 0x3E,\n\t0x7E, 0x77, 0x00, 0x31, 0x23, 0x23, 0x00, 0x21, 0x95, 0x00, 0x5B, 0x20,\n\t0x73, 0x8D, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,\n\t0x42, 0x60, 0x82\n};\nstd::optional<wxBitmap> g_ipArrowBitmap;\n\n\nstatic wxColour theme_textForeground;\nstatic wxColour theme_textForegroundMuted;\nstatic wxColour theme_background;\n\n// background colors for lines in the disassembly view\nstatic wxColour theme_lineBreakpointAndCurrentInstruction;\nstatic wxColour theme_lineCurrentInstruction;\nstatic wxColour theme_lineBreakpointSet;\nstatic wxColour theme_lineLoggingBreakpointSet;\nstatic wxColour theme_lineLastGotoAddress;\n\n// text colors for addresses in the disassembly view\nstatic wxColour theme_syntaxGPR;\nstatic wxColour theme_syntaxFPR;\nstatic wxColour theme_syntaxSPR;\nstatic wxColour theme_syntaxCR;\nstatic wxColour theme_syntaxIMM;\nstatic wxColour theme_syntaxIMMOffset;\nstatic wxColour theme_syntaxCallIMM;\nstatic wxColour theme_syntaxPseudoOrUnknown;\nstatic wxColour theme_syntaxSymbol;\n\nstatic wxColour theme_opCode;\nstatic wxColour theme_typeData;\nstatic wxColour theme_patchedOpCode;\nstatic wxColour theme_patchedData;\n\n\nstatic void InitSyntaxColors()\n{\n\ttheme_textForeground = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);\n\ttheme_textForegroundMuted = wxSystemSettings::SelectLightDark(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT), wxColour(140, 142, 145));\n\ttheme_background = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);\n\n\t// line background highlights\n\ttheme_lineBreakpointSet = wxSystemSettings::SelectLightDark(wxColour(0xFF,0x80,0x80), wxColour(0x84,0x21,0x21)); // red for a non-current breakpoint\n\ttheme_lineBreakpointAndCurrentInstruction = wxSystemSettings::SelectLightDark(wxColour(0xD2,0x7E,0xD2), wxColour(0x91,0x44,0xA4)); // pink for a current breakpoint\n\ttheme_lineCurrentInstruction = wxSystemSettings::SelectLightDark(wxColour(0xFF,0xA0,0x80), wxColour(0x87,0x53,0x1A)); // light orange\n\ttheme_lineLoggingBreakpointSet = wxSystemSettings::SelectLightDark(wxColour(0xAB,0xED,0xEE), wxColour(0x25,0x5D,0x6D)); // light blue\n\ttheme_lineLastGotoAddress = wxSystemSettings::SelectLightDark(wxColour(0xE0,0xE0,0xE0), wxColour(0x40,0x40,0x40)); // very light gray to indicate the line that was last jumped to\n\n\t// disassembly syntax colors\n\ttheme_syntaxGPR = wxSystemSettings::SelectLightDark(wxColour(0x66,0x00,0x00), wxColour(0xE0,0x6C,0x75));\n\ttheme_syntaxFPR = wxSystemSettings::SelectLightDark(wxColour(0x66,0x66,0x00), wxColour(0xD1,0x9A,0x66));\n\ttheme_syntaxSPR = wxSystemSettings::SelectLightDark(wxColour(0x00,0x66,0x66), wxColour(0x56,0xB6,0xC2));\n\ttheme_syntaxCR = wxSystemSettings::SelectLightDark(wxColour(0x00,0x66,0x66), wxColour(0x56,0xB6,0xC2));\n\ttheme_syntaxIMM = wxSystemSettings::SelectLightDark(wxColour(0x00,0x66,0x00), wxColour(0x9D,0xDE,0x6F));\n\ttheme_syntaxIMMOffset = wxSystemSettings::SelectLightDark(wxColour(0x00,0x66,0x00), wxColour(0x9D,0xDE,0x6F));\n\ttheme_syntaxCallIMM = wxSystemSettings::SelectLightDark(wxColour(0x00,0x00,0x88), wxColour(0x61,0xAF,0xEF));\n\ttheme_syntaxPseudoOrUnknown = wxSystemSettings::SelectLightDark(wxColour(0xA0,0xA0,0xA0), wxColour(0x5C,0x63,0x70));\n\ttheme_syntaxSymbol = wxSystemSettings::SelectLightDark(wxColour(0xA0,0x00,0x00), wxColour(0xE0,0x6C,0x75));\n\n\t// opcode & data highlighting\n\ttheme_opCode = wxSystemSettings::SelectLightDark(wxColour(0xFF,0x00,0x40), wxColour(0xFF,0x70,0x7B));\n\ttheme_patchedOpCode = wxSystemSettings::SelectLightDark(wxColour(0xFF,0x20,0x20), wxColour(0xCC,0x52,0xF5));\n\ttheme_typeData = wxSystemSettings::SelectLightDark(wxColour(0xFF,0x20,0x20), wxColour(0xCE,0x91,0x78));\n\ttheme_patchedData = wxSystemSettings::SelectLightDark(wxColour(0xFF,0x20,0x20), wxColour(0xF4,0x43,0x36));\n\n\t// theme the current instruction pointer arrow\n\tg_ipArrowBitmap = wxHelper::LoadThemedBitmapFromPNG(arrowRightPNG, sizeof(arrowRightPNG), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n}\n\n\n#define OFFSET_ADDRESS (60)\n#define OFFSET_ADDRESS_RELATIVE (90)\n#define OFFSET_DISASSEMBLY (300)\n\n#define OFFSET_DISASSEMBLY_OPERAND (80)\n\nDisasmCtrl::DisasmCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size, long style)\n\t: TextList(parent, id, pos, size, style), m_mouse_line(-1), m_mouse_line_drawn(-1), m_active_line(-1)\n{\n\tInit();\n\n\tif (!g_ipArrowBitmap.has_value())\n\t{\n\t\tInitSyntaxColors();\n\t}\n\n\tauto tooltip_sizer = new wxBoxSizer(wxVERTICAL);\n\ttooltip_sizer->Add(new wxStaticText(m_tooltip_window, wxID_ANY, wxEmptyString), 0, wxALL, 5);\n\tm_tooltip_window->SetSizer(tooltip_sizer);\n\n\tBind(wxEVT_MENU, &DisasmCtrl::OnContextMenuEntryClicked, this, IDContextMenu_ToggleBreakpoint, IDContextMenu_Last);\n}\n\nvoid DisasmCtrl::Init()\n{\n\tSelectCodeRegion(mmuRange_TEXT_AREA.getBase());\n}\n\nvoid DisasmCtrl::SelectCodeRegion(uint32 newAddress)\n{\n\tif (newAddress >= mmuRange_TEXT_AREA.getBase() && newAddress < mmuRange_TEXT_AREA.getEnd())\n\t{\n\t\tcurrentCodeRegionStart = MEMORY_CODEAREA_ADDR;\n\t\tcurrentCodeRegionEnd = RPLLoader_GetMaxCodeOffset();\n\t\tcurrentCodeRegionEnd = std::max(currentCodeRegionEnd, currentCodeRegionStart + 0x1000);\n\t}\n\tMMURange* mmuRange = memory_getMMURangeByAddress(newAddress);\n\tif (mmuRange)\n\t{\n\t\tcurrentCodeRegionStart = mmuRange->getBase();\n\t\tcurrentCodeRegionEnd = mmuRange->getEnd();\n\t}\n\telse\n\t{\n\t\tcurrentCodeRegionStart = 0;\n\t\tcurrentCodeRegionEnd = 0;\n\t}\n\n\t// update line tracking\n\tsint32 element_count = currentCodeRegionEnd - currentCodeRegionStart;\n\t// if (element_count <= 0x00010000)\n\t// \telement_count = 0x00010000;\n\n\tif (this->SetElementCount(element_count / 4))\n\t{\n\t\tScroll(0, 0);\n\t\tRefreshControl();\n\t}\n}\n\nvoid DisasmCtrl::DrawDisassemblyLine(wxDC& dc, const wxPoint& linePosition, MPTR virtualAddress, RPLModule* rplModule)\n{\n\twxPoint position = linePosition;\n\n\tbool hasPatch = debugger_hasPatch(virtualAddress);\n\n\tPPCDisassembledInstruction disasmInstr;\n\n\tconst DebuggerBreakpoint* bp = debugger_getFirstBP(virtualAddress);\n\twhile (bp)\n\t{\n\t\tif (bp->isExecuteBP() && bp->enabled)\n\t\t\tbreak;\n\t\tbp = bp->next;\n\t}\n\n\tuint32 opcode;\n\n\tif (bp)\n\t\topcode = bp->originalOpcodeValue;\n\telse\n\t\topcode = memory_readU32(virtualAddress);\n\n\tppcAssembler_disassemble(virtualAddress, opcode, &disasmInstr);\n\n\tconst bool is_active_bp = debuggerState.debugSession.isTrapped && debuggerState.debugSession.instructionPointer == virtualAddress;\n\n\t// write virtual address\n\twxColour background_colour;\n\tif (is_active_bp && bp != nullptr)\n\t\tbackground_colour = theme_lineBreakpointAndCurrentInstruction;\n\telse if (is_active_bp)\n\t\tbackground_colour = theme_lineCurrentInstruction;\n\telse if (bp != nullptr)\n\t\tbackground_colour = bp->bpType == DEBUGGER_BP_T_NORMAL ? theme_lineBreakpointSet : theme_lineLoggingBreakpointSet;\n\telse if(virtualAddress == m_lastGotoTarget)\n\t\tbackground_colour = theme_lineLastGotoAddress;\n\telse\n\t\tbackground_colour = theme_background;\n\n\tDrawLineBackground(dc, position, background_colour);\n\n\tdc.SetTextForeground(theme_textForeground);\n\tdc.DrawText(wxString::Format(\"%08x\", virtualAddress), position);\n\tposition.x += OFFSET_ADDRESS;\n\n\tdc.SetTextForeground(theme_textForegroundMuted);\n\tif (rplModule)\n\t\tdc.DrawText(wxString::Format(\"+0x%-8x\", virtualAddress - rplModule->regionMappingBase_text.GetMPTR()), position);\n\telse\n\t\tdc.DrawText(\"???\", position);\n\n\tposition.x += OFFSET_ADDRESS_RELATIVE;\n\n\t// draw arrow to clearly indicate instruction pointer\n\tif(is_active_bp)\n\t\tdc.DrawBitmap(*g_ipArrowBitmap, wxPoint(position.x - 24, position.y + 2), false);\n\n\t// handle data symbols\n\tauto debugSymbolDataType = DebugSymbolStorage::GetDataType(virtualAddress);\n\tif (debugSymbolDataType == DEBUG_SYMBOL_TYPE::FLOAT)\n\t{\n\t\tdc.SetTextForeground(hasPatch ? theme_patchedData : theme_typeData);\n\t\tdc.DrawText(fmt::format(\".float\"), position);\n\n\t\tposition.x += OFFSET_DISASSEMBLY_OPERAND;\n\t\tdc.SetTextForeground(hasPatch ? theme_patchedData : theme_syntaxIMM);\n\t\tdc.DrawText(fmt::format(\"{}\", memory_readFloat(virtualAddress)), position);\n\n\t\treturn;\n\t}\n\telse if (debugSymbolDataType == DEBUG_SYMBOL_TYPE::U32)\n\t{\n\t\tdc.SetTextForeground(hasPatch ? theme_patchedData : theme_typeData);\n\t\tdc.DrawText(fmt::format(\".uint\"), position);\n\n\t\tposition.x += OFFSET_DISASSEMBLY_OPERAND;\n\t\tdc.SetTextForeground(hasPatch ? theme_patchedData : theme_syntaxIMM);\n\t\tdc.DrawText(fmt::format(\"{}\", memory_readU32(virtualAddress)), position);\n\n\t\treturn;\n\t}\n\n\tsint32 start_width = position.x;\n\tdc.SetTextForeground(hasPatch ? theme_patchedOpCode : theme_opCode);\n\tstd::string opName = ppcAssembler_getInstructionName(disasmInstr.ppcAsmCode);\n\tstd::transform(opName.begin(), opName.end(), opName.begin(), tolower);\n\tdc.DrawText(wxString::Format(\"%-12s\", opName.c_str()), position);\n\tposition.x += OFFSET_DISASSEMBLY_OPERAND;\n\n\tbool isRLWINM = disasmInstr.ppcAsmCode == PPCASM_OP_RLWINM || disasmInstr.ppcAsmCode == PPCASM_OP_RLWINM_ ||\n\t\tdisasmInstr.ppcAsmCode == PPCASM_OP_CLRLWI || disasmInstr.ppcAsmCode == PPCASM_OP_CLRLWI_ ||\n\t\tdisasmInstr.ppcAsmCode == PPCASM_OP_CLRRWI || disasmInstr.ppcAsmCode == PPCASM_OP_CLRRWI_ ||\n\t\tdisasmInstr.ppcAsmCode == PPCASM_OP_EXTLWI || disasmInstr.ppcAsmCode == PPCASM_OP_EXTLWI_ ||\n\t\tdisasmInstr.ppcAsmCode == PPCASM_OP_EXTRWI || disasmInstr.ppcAsmCode == PPCASM_OP_EXTRWI_ ||\n\t\tdisasmInstr.ppcAsmCode == PPCASM_OP_SLWI || disasmInstr.ppcAsmCode == PPCASM_OP_SLWI_ ||\n\t\tdisasmInstr.ppcAsmCode == PPCASM_OP_SRWI || disasmInstr.ppcAsmCode == PPCASM_OP_SRWI_ ||\n\t\tdisasmInstr.ppcAsmCode == PPCASM_OP_ROTRWI || disasmInstr.ppcAsmCode == PPCASM_OP_ROTRWI_ ||\n\t\tdisasmInstr.ppcAsmCode == PPCASM_OP_ROTLWI || disasmInstr.ppcAsmCode == PPCASM_OP_ROTLWI_;\n\tbool forceDecDisplay = isRLWINM;\n\n\tif (disasmInstr.ppcAsmCode == PPCASM_OP_UKN)\n\t{\n\t\t// show raw bytes\n\t\tWriteText(dc, wxString::Format(\"%02x %02x %02x %02x\", (opcode >> 24) & 0xFF, (opcode >> 16) & 0xFF, (opcode >> 8) & 0xFF, (opcode >> 0) & 0xFF), position, theme_syntaxPseudoOrUnknown);\n\t}\n\n\tbool is_first_operand = true;\n\tfor (sint32 o = 0; o < PPCASM_OPERAND_COUNT; o++)\n\t{\n\t\tif (((disasmInstr.operandMask >> o) & 1) == 0)\n\t\t\tcontinue;\n\n\t\tif (!is_first_operand)\n\t\t\tWriteText(dc, \", \", position, theme_textForeground);\n\n\t\tis_first_operand = false;\n\t\tswitch (disasmInstr.operand[o].type)\n\t\t{\n\t\tcase PPCASM_OPERAND_TYPE_GPR:\n\t\t\tWriteText(dc, wxString::Format(\"r%d\", disasmInstr.operand[o].registerIndex), position, theme_syntaxGPR);\n\t\t\tbreak;\n\n\t\tcase PPCASM_OPERAND_TYPE_FPR:\n\t\t\tWriteText(dc, wxString::Format(\"f%d\", disasmInstr.operand[o].registerIndex), position, theme_syntaxFPR);\n\t\t\tbreak;\n\n\t\tcase PPCASM_OPERAND_TYPE_SPR:\n\t\t\tWriteText(dc, wxString::Format(\"spr%d\", disasmInstr.operand[o].registerIndex), position, theme_syntaxSPR);\n\t\t\tbreak;\n\n\t\tcase PPCASM_OPERAND_TYPE_CR:\n\t\t\tWriteText(dc, wxString::Format(\"cr%d\", disasmInstr.operand[o].registerIndex), position, theme_syntaxCR);\n\t\t\tbreak;\n\n\t\tcase PPCASM_OPERAND_TYPE_IMM:\n\t\t{\n\t\t\twxString string;\n\t\t\tif (disasmInstr.operand[o].isSignedImm)\n\t\t\t{\n\t\t\t\tsint32 sImm = disasmInstr.operand[o].immS32;\n\t\t\t\tif (disasmInstr.operand[o].immWidth == 16 && (sImm & 0x8000))\n\t\t\t\t\tsImm |= (sint32)0xFFFF0000;\n\n\t\t\t\tif ((sImm > -10 && sImm < 10) || forceDecDisplay)\n\t\t\t\t\tstring = wxString::Format(\"%d\", sImm);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (sImm < 0)\n\t\t\t\t\t\tstring = wxString::Format(\"-0x%x\", -sImm);\n\t\t\t\t\telse\n\t\t\t\t\t\tstring = wxString::Format(\"0x%x\", sImm);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint32 uImm = disasmInstr.operand[o].immS32;\n\t\t\t\tif ((uImm >= 0 && uImm < 10) || forceDecDisplay)\n\t\t\t\t\tstring = wxString::Format(\"%u\", uImm);\n\t\t\t\telse\n\t\t\t\t\tstring = wxString::Format(\"0x%x\", uImm);\n\t\t\t}\n\n\t\t\tWriteText(dc, string, position, theme_syntaxIMM);\n\t\t\tbreak;\n\t\t}\n\t\tcase PPCASM_OPERAND_TYPE_PSQMODE:\n\t\t{\n\t\t\tif (disasmInstr.operand[o].immS32)\n\t\t\t\tWriteText(dc, \"single\", position, theme_syntaxIMM);\n\t\t\telse\n\t\t\t\tWriteText(dc, \"paired\", position, theme_syntaxIMM);\n\t\t\tbreak;\n\t\t}\n\t\tcase PPCASM_OPERAND_TYPE_CIMM:\n\t\t{\n\t\t\twxString string;\n\t\t\t// use symbol for function calls if available \n\t\t\tuint32 callDest = disasmInstr.operand[o].immU32;\n\t\t\tRPLStoredSymbol* storedSymbol = nullptr;\n\t\t\tif (disasmInstr.ppcAsmCode == PPCASM_OP_BL || disasmInstr.ppcAsmCode == PPCASM_OP_BLA)\n\t\t\t\tstoredSymbol = rplSymbolStorage_getByAddress(callDest);\n\n\t\t\tif (storedSymbol)\n\t\t\t{\n\t\t\t\t// if symbol is within same module then don't display libname prefix\n\t\t\t\tRPLModule* rplModuleCurrent = RPLLoader_FindModuleByCodeAddr(virtualAddress); // cache this\n\t\t\t\tif (rplModuleCurrent && callDest >= rplModuleCurrent->regionMappingBase_text.GetMPTR() && callDest < (rplModuleCurrent->regionMappingBase_text.GetMPTR() + rplModuleCurrent->regionSize_text))\n\t\t\t\t\tstring = wxString((char*)storedSymbol->symbolName);\n\t\t\t\telse\n\t\t\t\t\tstring = wxString::Format(\"%s.%s\", (char*)storedSymbol->libName, (char*)storedSymbol->symbolName);\n\n\t\t\t\t// truncate name after 36 characters\n\t\t\t\tif (string.Length() >= 36)\n\t\t\t\t{\n\t\t\t\t\tstring.Truncate(34);\n\t\t\t\t\tstring.Append(\"..\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstring = wxString::Format(\"0x%08x\", disasmInstr.operand[o].immU32);\n\t\t\t}\n\n\t\t\tWriteText(dc, string, position, theme_syntaxCallIMM);\n\n\t\t\tif (disasmInstr.ppcAsmCode != PPCASM_OP_BL)\n\t\t\t{\n\t\t\t\twxString x = wxString(\" \");\n\t\t\t\tif (callDest <= virtualAddress)\n\t\t\t\t\tx.Append(wxUniChar(0x2191)); // arrow up\n\t\t\t\telse\n\t\t\t\t\tx.Append(wxUniChar(0x2193)); // arrow down\n\n\t\t\t\tWriteText(dc, x, position, theme_textForeground);\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase PPCASM_OPERAND_TYPE_MEM:\n\t\t{\n\t\t\t// offset\n\t\t\twxString string;\n\t\t\tif (disasmInstr.operand[o].isSignedImm && disasmInstr.operand[o].immS32 >= 0)\n\t\t\t\tstring = wxString::Format(\"+0x%x\", disasmInstr.operand[o].immS32);\n\t\t\telse\n\t\t\t\tstring = wxString::Format(\"-0x%x\", -disasmInstr.operand[o].immS32);\n\n\t\t\tWriteText(dc, string, position, theme_syntaxIMMOffset);\n\t\t\tWriteText(dc, \"(\", position, theme_textForeground);\n\n\t\t\t// register\n\t\t\tWriteText(dc, wxString::Format(\"r%d\", disasmInstr.operand[o].registerIndex), position, theme_syntaxGPR);\n\t\t\tWriteText(dc, \")\", position, theme_textForeground);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\t// TODO\n\t\t\tWriteText(dc, \"<TODO>\", position, wxColour(0xFF444444));\n\t\t}\n\t}\n\n\tposition.x = start_width + OFFSET_DISASSEMBLY;\n\tconst auto comment = static_cast<rplDebugSymbolComment*>(rplDebugSymbol_getForAddress(virtualAddress));\n\tif (comment && comment->type == RplDebugSymbolComment)\n\t\tWriteText(dc, comment->comment, position, theme_textForeground);\n\telse if (isRLWINM)\n\t{\n\t\tsint32 rS, rA, SH, MB, ME;\n\t\trS = (opcode >> 21) & 0x1f;\n\t\trA = (opcode >> 16) & 0x1f;\n\t\tSH = (opcode >> 11) & 0x1f;\n\t\tMB = (opcode >> 6) & 0x1f;\n\t\tME = (opcode >> 1) & 0x1f;\n\n\t\tuint32 mask = ppcAssembler_generateMaskRLW(MB, ME);\n\n\t\twxString string;\n\t\tif (SH == 0)\n\t\t\tstring = wxString::Format(\"r%d=r%d&0x%x\", rA, rS, mask);\n\t\telse if ((0xFFFFFFFF << (uint32)disasmInstr.operand[2].immS32) == mask)\n\t\t\tstring = wxString::Format(\"r%d=r%d<<%d\", rA, rS, SH);\n\t\telse if ((0xFFFFFFFF >> (32 - SH) == mask))\n\t\t\tstring = wxString::Format(\"r%d=r%d>>%d\", rA, rS, 32 - SH);\n\t\telse\n\t\t\tstring = wxString::Format(\"r%d=(r%d<<<%d)&0x%x\", rA, rS, SH, mask);\n\t\tWriteText(dc, string, position, theme_textForegroundMuted);\n\t}\n\telse if (disasmInstr.ppcAsmCode == PPCASM_OP_SUBF || disasmInstr.ppcAsmCode == PPCASM_OP_SUBF_)\n\t{\n\t\tsint32 rD, rA, rB;\n\t\trD = (opcode >> 21) & 0x1f;\n\t\trA = (opcode >> 16) & 0x1f;\n\t\trB = (opcode >> 11) & 0x1f;\n\n\t\twxString string;\n\t\tstring = wxString::Format(\"r%d=r%d-r%d\", rD, rB, rA);\n\t\tWriteText(dc, string, position, theme_textForegroundMuted);\n\t}\n}\n\nvoid DisasmCtrl::DrawLabelName(wxDC& dc, const wxPoint& linePosition, MPTR virtualAddress, RPLStoredSymbol* storedSymbol)\n{\n\twxString symbol_string = wxString::Format(\"%s:\", (char*)storedSymbol->symbolName);\n\tif (symbol_string.Length() > MAX_SYMBOL_LEN)\n\t{\n\t\tsymbol_string.Truncate(MAX_SYMBOL_LEN - 3);\n\t\tsymbol_string.Append(\"..:\");\n\t}\n\twxPoint tmpPos(linePosition);\n\tWriteText(dc, symbol_string, tmpPos, theme_syntaxSymbol);\n}\n\nvoid DisasmCtrl::OnDraw(wxDC& dc, sint32 start, sint32 count, const wxPoint& start_position)\n{\n\twxPoint position(0, 0);\n\n\tRPLModule* current_rpl_module = RPLLoader_FindModuleByCodeAddr(GetViewBaseAddress());\n\t\n\tif (currentCodeRegionStart == currentCodeRegionEnd)\n\t\treturn;\n\n\tsint32 viewFirstLine = GetViewStart().y;\n\tsint32 lineOffset = start - viewFirstLine;\n\n\tcemu_assert_debug(lineOffset >= 0);\n\n\tsint32 instructionIndex = 0;\n\tsint32 numLinesToUpdate = lineOffset + count;\n\tnumLinesToUpdate = std::min(numLinesToUpdate, (sint32)m_elements_visible);\n\n\tif(m_lineToAddress.size() != m_elements_visible)\n\t\tm_lineToAddress.resize(m_elements_visible);\n\n\tsint32 lineIndex = 0;\n\twhile(lineIndex < numLinesToUpdate)\n\t{\n\t\tconst uint32 virtualAddress = GetViewBaseAddress() + instructionIndex * 4;\n\t\tinstructionIndex++;\n\n\t\tif (virtualAddress < currentCodeRegionStart ||\n\t\t\tvirtualAddress >= currentCodeRegionEnd)\n\t\t{\n\t\t\tNextLine(position, &start_position);\n\t\t\tm_lineToAddress[lineIndex] = std::nullopt;\n\t\t\tlineIndex++;\n\t\t\tcontinue;\t\n\t\t}\n\n\t\t// check if valid memory address\n\t\tif (!memory_isAddressRangeAccessible(virtualAddress, 4))\n\t\t{\n\t\t\tNextLine(position, &start_position);\n\t\t\tm_lineToAddress[lineIndex] = std::nullopt;\n\t\t\tlineIndex++;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// draw symbol as label\n\t\tRPLStoredSymbol* storedSymbol = rplSymbolStorage_getByAddress(virtualAddress);\n\t\tif (storedSymbol)\n\t\t{\n\t\t\tif(lineIndex >= lineOffset)\n\t\t\t\tDrawLabelName(dc, position, virtualAddress, storedSymbol);\n\t\t\tm_lineToAddress[lineIndex] = virtualAddress;\n\t\t\tlineIndex++;\n\t\t\tif (lineIndex >= numLinesToUpdate)\n\t\t\t\tbreak;\n\t\t\tNextLine(position, &start_position);\n\t\t}\n\t\tm_lineToAddress[lineIndex] = virtualAddress;\n\t\tif (lineIndex >= lineOffset)\n\t\t\tDrawDisassemblyLine(dc, position, virtualAddress, current_rpl_module);\n\t\tNextLine(position, &start_position);\n\t\tlineIndex++;\n\t}\n\n\t// draw vertical separator lines: offset | disassembly | comment\n\tdc.SetPen(*wxLIGHT_GREY_PEN);\n\n\twxPoint line_from = start_position;\n\tline_from.x = OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE - 5;\n\twxPoint line_to = line_from;\n\tline_to.y += (count + 1) * m_line_height;\n\tdc.DrawLine(line_from, line_to);\n\n\tline_from.x += OFFSET_DISASSEMBLY;\n\tline_to.x += OFFSET_DISASSEMBLY;\n\tdc.DrawLine(line_from, line_to);\n}\n\nvoid DisasmCtrl::OnMouseMove(const wxPoint& start_position, uint32 line)\n{\n\t/*m_mouse_line = line;\n\tif (m_mouse_line_drawn != -1)\n\t\tRefreshLine(m_mouse_line_drawn);\n\tif (m_mouse_line != -1)\n\t\tRefreshLine(m_mouse_line);*/\n\n\twxPoint position = start_position;\n\n\t// address\n\tif (position.x <= OFFSET_ADDRESS)\n\t{\n\t\treturn;\n\t}\n\n\tposition.x -= OFFSET_ADDRESS;\n\n\t// relative offset\n\tif (position.x <= OFFSET_ADDRESS_RELATIVE)\n\t{\n\t\treturn;\n\t}\n\n\tposition.x -= OFFSET_ADDRESS_RELATIVE;\n\n\t// disassembly code\n\tif (position.x <= OFFSET_DISASSEMBLY)\n\t{\n\t\tif(m_mouse_down)\n\t\t{\n\t\t\t\n\t\t}\n\n\t\tif (position.x <= OFFSET_DISASSEMBLY_OPERAND)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tposition.x -= OFFSET_DISASSEMBLY_OPERAND;\n\t}\n}\n\nvoid DisasmCtrl::OnKeyPressed(sint32 key_code, const wxPoint& position)\n{\n\tauto optVirtualAddress = LinePixelPosToAddress(position.y);\n\tswitch (key_code)\n\t{\n\t\tcase WXK_F9:\n\t\t{\n\t\t\tif (optVirtualAddress)\n\t\t\t{\n\t\t\t\tdebugger_toggleExecuteBreakpoint(*optVirtualAddress);\n\n\t\t\t\twxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE);\n\t\t\t\twxPostEvent(this->m_parent, evt);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tcase 'G':\n\t\t{\n\t\t\tif(IsKeyDown(WXK_CONTROL))\n\t\t\t{\n\t\t\t\tGoToAddressDialog();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t// debugger currently in break state\n\tif (debuggerState.debugSession.isTrapped)\n\t{\n\t\tswitch (key_code)\n\t\t{\n\t\tcase WXK_F5:\n\t\t\t{\n\t\t\t\tdebuggerState.debugSession.run = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\tcase WXK_F10:\n\t\t\t{\n\t\t\t\tdebuggerState.debugSession.stepOver = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\tcase WXK_F11:\n\t\t\t{\n\t\t\t\tdebuggerState.debugSession.stepInto = true;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tswitch (key_code)\n\t\t{\n\t\tcase WXK_F5:\n\t\t\t{\n\t\t\t\tdebuggerState.debugSession.shouldBreak = true;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid DisasmCtrl::OnMouseDClick(const wxPoint& position, uint32 line)\n{\n\twxPoint pos = position;\n\tauto optVirtualAddress = LinePixelPosToAddress(position.y - GetViewStart().y * m_line_height);\n\tif (!optVirtualAddress)\n\t\treturn;\n\tMPTR virtualAddress = *optVirtualAddress;\n\n\t// address\n\tif (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE)\n\t{\n\t\t// address + address relative\n\t\tdebugger_toggleExecuteBreakpoint(virtualAddress);\n\t\tRefreshLine(line);\n\t\twxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE);\n\t\twxPostEvent(this->m_parent, evt);\n\t\treturn;\n\t}\n\telse if (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE + OFFSET_DISASSEMBLY)\n\t{\n\t\t// double-clicked on disassembly (operation and operand data)\n\t\twxString currentInstruction = wxEmptyString;\n\t\twxTextEntryDialog set_value_dialog(this, _(\"Enter a new instruction.\"), wxString::Format(_(\"Overwrite instruction at address %08x\"), virtualAddress), currentInstruction);\n\t\tif (set_value_dialog.ShowModal() == wxID_OK)\n\t\t{\n\t\t\tPPCAssemblerInOut ctx = { 0 };\n\t\t\tctx.virtualAddress = virtualAddress;\n\t\t\tif (ppcAssembler_assembleSingleInstruction(set_value_dialog.GetValue().c_str(), &ctx))\n\t\t\t{\n\t\t\t\tdebugger_createPatch(virtualAddress, { ctx.outputData.data(), ctx.outputData.size() });\n\t\t\t\tRefreshLine(line);\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\telse\n\t{\n\t\t// comment\n\t\tconst auto comment = static_cast<rplDebugSymbolComment*>(rplDebugSymbol_getForAddress(virtualAddress));\n\n\t\twxString old_comment = wxEmptyString;\n\t\tif (comment && comment->type == RplDebugSymbolComment)\n\t\t\told_comment = comment->comment;\n\n\t\twxTextEntryDialog set_value_dialog(this, _(\"Enter a new comment.\"), wxString::Format(_(\"Create comment at address %08x\"), virtualAddress), old_comment);\n\t\tif (set_value_dialog.ShowModal() == wxID_OK)\n\t\t{\n\t\t\trplDebugSymbol_createComment(virtualAddress, set_value_dialog.GetValue().wc_str());\n\t\t\tRefreshLine(line);\n\t\t}\n\t\treturn;\n\t}\n}\n\nvoid DisasmCtrl::CopyToClipboard(std::string text)\n{\n#if BOOST_OS_WINDOWS\n\tif (OpenClipboard(nullptr))\n\t{\n\t\tEmptyClipboard();\n\t\tconst HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, text.size() + 1);\n\t\tif (hGlobal)\n\t\t{\n\t\t\tmemcpy(GlobalLock(hGlobal), text.c_str(), text.size() + 1);\n\t\t\tGlobalUnlock(hGlobal);\n\t\t\tSetClipboardData(CF_TEXT, hGlobal);\n\t\t}\n\t\tCloseClipboard();\n\t}\n#endif\n}\n\nstatic uint32 GetUnrelocatedAddress(MPTR address)\n{\n\tRPLModule* rplModule = RPLLoader_FindModuleByCodeAddr(address);\n\tif (!rplModule)\n\t\treturn 0;\n\tif (address >= rplModule->regionMappingBase_text.GetMPTR() && address < (rplModule->regionMappingBase_text.GetMPTR() + rplModule->regionSize_text))\n\t\treturn 0x02000000 + (address - rplModule->regionMappingBase_text.GetMPTR());\n\treturn 0;\n}\n\nvoid DisasmCtrl::OnContextMenu(const wxPoint& position, uint32 line)\n{\n\tauto optVirtualAddress = LinePixelPosToAddress(position.y - GetViewStart().y * m_line_height);\n\tif (!optVirtualAddress)\n\t\treturn;\n\tMPTR virtualAddress = *optVirtualAddress;\n\tm_contextMenuAddress = virtualAddress;\n\t// show dialog\n\twxMenu menu;\n\tmenu.Append(IDContextMenu_ToggleBreakpoint, _(\"Toggle breakpoint\"));\n\tmenu.Append(IDContextMenu_ToggleLoggingBreakpoint, _(\"Toggle logging point\"));\n\tif(debugger_hasPatch(virtualAddress))\n\t\tmenu.Append(IDContextMenu_RestoreOriginalInstructions, _(\"Restore original instructions\"));\n\tmenu.AppendSeparator();\n\tmenu.Append(IDContextMenu_CopyAddress, _(\"Copy address\"));\n\tuint32 unrelocatedAddress = GetUnrelocatedAddress(virtualAddress);\n\tif (unrelocatedAddress && unrelocatedAddress != virtualAddress)\n\t\tmenu.Append(IDContextMenu_CopyUnrelocatedAddress, _(\"Copy virtual address (for IDA/Ghidra)\"));\n\tPopupMenu(&menu);\n}\n\nvoid DisasmCtrl::OnContextMenuEntryClicked(wxCommandEvent& event)\n{\n\tswitch(event.GetId())\n\t{\n\t\tcase IDContextMenu_ToggleBreakpoint:\n\t\t{\n\t\t\tdebugger_toggleExecuteBreakpoint(m_contextMenuAddress);\n\t\t\twxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE);\n\t\t\twxPostEvent(this->m_parent, evt);\n\t\t\tbreak;\n\t\t}\n\t\tcase IDContextMenu_ToggleLoggingBreakpoint:\n\t\t{\n\t\t\tdebugger_toggleLoggingBreakpoint(m_contextMenuAddress);\n\t\t\twxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE);\n\t\t\twxPostEvent(this->m_parent, evt);\n\t\t\tbreak;\n\t\t}\n\t\tcase IDContextMenu_RestoreOriginalInstructions:\n\t\t{\n\t\t\tdebugger_removePatch(m_contextMenuAddress);\n\t\t\twxCommandEvent evt(wxEVT_BREAKPOINT_CHANGE); // This also refreshes the disassembly view\n\t\t\twxPostEvent(this->m_parent, evt);\n\t\t\tbreak;\n\t\t}\n\t\tcase IDContextMenu_CopyAddress:\n\t\t{\n\t\t\tCopyToClipboard(fmt::format(\"{:#10x}\", m_contextMenuAddress));\n\t\t\tbreak;\n\t\t}\n\t\tcase IDContextMenu_CopyUnrelocatedAddress:\n\t\t{\n\t\t\tuint32 unrelocatedAddress = GetUnrelocatedAddress(m_contextMenuAddress);\n\t\t\tCopyToClipboard(fmt::format(\"{:#10x}\", unrelocatedAddress));\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tUNREACHABLE;\n\t}\n}\n\nbool DisasmCtrl::OnShowTooltip(const wxPoint& position, uint32 line)\n{\n\treturn false;\n}\n\nvoid DisasmCtrl::ScrollWindow(int dx, int dy, const wxRect* prect)\n{\n\t// scroll and repaint everything\n\tRefreshControl(nullptr);\n\tTextList::ScrollWindow(dx, dy, nullptr);\n}\n\nwxSize DisasmCtrl::DoGetBestSize() const\n{\n\treturn TextList::DoGetBestSize();\n}\n\nvoid DisasmCtrl::OnUpdateView()\n{\n\tRefreshControl();\n}\n\nuint32 DisasmCtrl::GetViewBaseAddress() const\n{\n\tif (GetViewStart().y < 0)\n\t\treturn MPTR_NULL;\n\treturn currentCodeRegionStart + GetViewStart().y * 4;\n}\n\nstd::optional<MPTR> DisasmCtrl::LinePixelPosToAddress(sint32 posY)\n{\n\tif (posY < 0)\n\t\treturn std::nullopt;\n\n\tsint32 lineIndex = posY / m_line_height;\n\tif (lineIndex >= m_lineToAddress.size())\n\t\treturn std::nullopt;\n\n\treturn m_lineToAddress[lineIndex];\n}\n\nuint32 DisasmCtrl::AddressToScrollPos(uint32 offset) const\n{\n\treturn (offset - currentCodeRegionStart) / 4;\n}\n\nvoid DisasmCtrl::CenterOffset(uint32 offset)\n{\n\tif (offset < currentCodeRegionStart || offset >= currentCodeRegionEnd)\n\t\tSelectCodeRegion(offset);\n\n\tconst sint32 line = AddressToScrollPos(offset);\n\tif (line < 0 || line >= (sint32)m_element_count)\n\t\treturn;\n\n\tif (m_active_line != -1)\n\t\tRefreshLine(m_active_line);\n\n\tDoScroll(0, std::max(0, line - (sint32)(m_elements_visible / 2)));\n\n\tm_active_line = line;\n\tRefreshLine(m_active_line);\n}\n\nvoid DisasmCtrl::GoToAddressDialog()\n{\n\twxTextEntryDialog goto_dialog(this, _(\"Enter a target address.\"), _(\"GoTo address\"), wxEmptyString);\n\tif (goto_dialog.ShowModal() == wxID_OK)\n\t{\n\t\tExpressionParser parser;\n\n\t\tauto value = goto_dialog.GetValue().ToStdString();\n\t\tstd::transform(value.begin(), value.end(), value.begin(), tolower);\n\n\t\t// trim any leading spaces\n\t\twhile(!value.empty() && value[0] == ' ')\n\t\t\tvalue.erase(value.begin());\n\n\t\tdebugger_addParserSymbols(parser);\n\n\t\t// try to parse expression as hex value first (it should interpret 1234 as 0x1234, not 1234)\n\t\tif (parser.IsConstantExpression(\"0x\"+value))\n\t\t{\n\t\t\tconst auto result = (uint32)parser.Evaluate(\"0x\"+value);\n\t\t\tm_lastGotoTarget = result;\n\t\t\tCenterOffset(result);\n\t\t\twxCommandEvent evt(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS);\n\t\t\tevt.SetExtraLong(static_cast<long>(result));\n\t\t\twxPostEvent(GetParent(), evt);\n\t\t}\n\t\telse if (parser.IsConstantExpression(value))\n\t\t{\n\t\t\tconst auto result = (uint32)parser.Evaluate(value);\n\t\t\tm_lastGotoTarget = result;\n\t\t\tCenterOffset(result);\n\t\t\twxCommandEvent evt(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS);\n\t\t\tevt.SetExtraLong(static_cast<long>(result));\n\t\t\twxPostEvent(GetParent(), evt);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// if not a constant expression (i.e. relying on unknown variables), then evaluating will throw an exception with a detailed error message\n\t\t\t\tconst auto _ = (uint32)parser.Evaluate(value);\n\t\t\t}\n\t\t\tcatch (const std::exception& ex)\n\t\t\t{\n\t\t\t\twxMessageBox(ex.what(), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/debugger/DisasmCtrl.h",
    "content": "#pragma once\n#include \"wxgui/components/TextList.h\"\n\nwxDECLARE_EVENT(wxEVT_DISASMCTRL_NOTIFY_GOTO_ADDRESS, wxCommandEvent); // Notify parent that goto address operation completed. Event contains the address that was jumped to.\n\nclass DisasmCtrl : public TextList\n{\n\tenum\n\t{\n\t\tIDContextMenu_ToggleBreakpoint = wxID_HIGHEST + 1,\n\t\tIDContextMenu_ToggleLoggingBreakpoint,\n\t\tIDContextMenu_RestoreOriginalInstructions,\n\t\tIDContextMenu_CopyAddress,\n\t\tIDContextMenu_CopyUnrelocatedAddress,\n\t\tIDContextMenu_Last\n\t};\npublic:\n\n\tDisasmCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size, long style);\n\n\tvoid Init();\n\twxSize DoGetBestSize() const override;\n\n\tvoid OnUpdateView();\n\n\tuint32 GetViewBaseAddress() const;\n\tstd::optional<MPTR> LinePixelPosToAddress(sint32 posY);\n\n\tuint32 AddressToScrollPos(uint32 offset) const;\n\tvoid CenterOffset(uint32 offset);\n\tvoid GoToAddressDialog();\n\nprotected:\n\tvoid OnDraw(wxDC& dc, sint32 start, sint32 count, const wxPoint& start_position) override;\n\tvoid OnMouseMove(const wxPoint& position, uint32 line) override;\n\tvoid OnKeyPressed(sint32 key_code, const wxPoint& position) override;\n\tvoid OnMouseDClick(const wxPoint& position, uint32 line) override;\n\tvoid OnContextMenu(const wxPoint& position, uint32 line) override;\n\tvoid OnContextMenuEntryClicked(wxCommandEvent& event);\n\tbool OnShowTooltip(const wxPoint& position, uint32 line) override;\n\tvoid ScrollWindow(int dx, int dy, const wxRect* prect) override;\n\n\tvoid DrawDisassemblyLine(wxDC& dc, const wxPoint& linePosition, MPTR virtualAddress, struct RPLModule* rplModule);\n\tvoid DrawLabelName(wxDC& dc, const wxPoint& linePosition, MPTR virtualAddress, struct RPLStoredSymbol* storedSymbol);\n\n\tvoid SelectCodeRegion(uint32 newAddress);\n\nprivate:\n\tvoid CopyToClipboard(std::string text);\n\n\tsint32 m_mouse_line, m_mouse_line_drawn;\n\tsint32 m_active_line;\n\tuint32 m_lastGotoTarget{};\n\tuint32 m_contextMenuAddress{};\n\t// code region info\n\tuint32 currentCodeRegionStart;\n\tuint32 currentCodeRegionEnd;\n\t// line to address mapping\n\tstd::vector<std::optional<MPTR>> m_lineToAddress;\n};\n"
  },
  {
    "path": "src/gui/wxgui/debugger/DumpCtrl.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxgui/debugger/DumpCtrl.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include \"util/helpers/helpers.h\"\n\n#include \"Cemu/ExpressionParser/ExpressionParser.h\"\n\n\n#define OFFSET_ADDRESS (60)\n#define OFFSET_ADDRESS_RELATIVE (90)\n#define OFFSET_MEMORY (450)\n\nDumpCtrl::DumpCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size, long style)\n\t: TextList(parent, id, pos, size, style)\n{\n\tMMURange* range = memory_getMMURangeByAddress(0x10000000);\n\tif (range)\n\t{\n\t\tm_memoryRegion.baseAddress = range->getBase();\n\t\tm_memoryRegion.size = range->getSize();\n\t\tInit();\n\t}\n\telse\n\t{\n\t\tm_memoryRegion.baseAddress = 0x10000000;\n\t\tm_memoryRegion.size = 0x1000;\n\t\tInit();\n\t}\n}\n\nvoid DumpCtrl::Init()\n{\n\tuint32 element_count = m_memoryRegion.size;\n\tthis->SetElementCount(element_count / 0x10);\n\tScroll(0, 0);\n\tRefreshControl();\n}\n\nvoid DumpCtrl::OnDraw(wxDC& dc, sint32 start, sint32 count, const wxPoint& start_position)\n{\n\twxPoint position = start_position;\n\tuint32 endAddr = m_memoryRegion.baseAddress + m_memoryRegion.size;\n\tRPLModule* currentCodeRPL = RPLLoader_FindModuleByCodeAddr(LineToOffset(start));\n\tRPLModule* currentDataRPL = RPLLoader_FindModuleByDataAddr(LineToOffset(start));\n\tfor (sint32 i = 0; i <= count; i++)\n\t{\n\t\tconst uint32 virtual_address = LineToOffset(start + i);\n\n\t\tdc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\tdc.DrawText(wxString::Format(\"%08x\", virtual_address), position);\n\t\tposition.x += OFFSET_ADDRESS;\n\n\t\tdc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));\n\t\tif (currentCodeRPL)\n\t\t{\n\t\t\tdc.DrawText(wxString::Format(\"+0x%-8x\", virtual_address - currentCodeRPL->regionMappingBase_text.GetMPTR()), position);\n\t\t}\n\t\telse if (currentDataRPL)\n\t\t{\n\t\t\tdc.DrawText(wxString::Format(\"+0x%-8x\", virtual_address - currentDataRPL->regionMappingBase_data), position);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdc.DrawText(\"???\", position);\n\t\t}\n\n\t\tposition.x += OFFSET_ADDRESS_RELATIVE;\n\n\t\tsint32 start_width = position.x;\n\t\t\n\t\tif (!memory_isAddressRangeAccessible(virtual_address, 0x10))\n\t\t{\n\t\t\tfor (sint32 f=0; f<0x10; f++)\n\t\t\t{\n\t\t\t\twxPoint p(position);\n\t\t\t\tWriteText(dc, wxString::Format(\"?? \"), p);\n\t\t\t\tposition.x += (m_char_width * 3);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::array<uint8, 0x10> data;\n\t\t\tmemory_readBytes(virtual_address, data);\n\t\t\tfor (auto b : data)\n\t\t\t{\n\t\t\t\twxPoint p(position);\n\t\t\t\tWriteText(dc, wxString::Format(\"%02x \", b), p);\n\t\t\t\tposition.x += (m_char_width * 3);\n\t\t\t}\n\t\t\tposition.x = start_width = OFFSET_MEMORY;\n\t\t\tdc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\t\tfor (auto b : data)\n\t\t\t{\n\t\t\t\tif (isprint(b))\n\t\t\t\t\tdc.DrawText(wxString::Format(\"%c \", b), position);\n\t\t\t\telse\n\t\t\t\t\tdc.DrawText(\".\", position);\n\n\t\t\t\tposition.x += m_char_width;\n\t\t\t}\n\t\t}\n\n\t\t// display goto indicator\n\t\tif (m_lastGotoOffset >= virtual_address && m_lastGotoOffset < (virtual_address + 16))\n\t\t{\n\t\t\tsint32 indicatorX = start_position.x + OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE + (m_lastGotoOffset - virtual_address) * m_char_width * 3;\n\t\t\twxPoint line1(start_position.x + indicatorX - 2, position.y);\n\t\t\twxPoint line2(line1.x, line1.y + m_line_height);\n\t\t\tdc.SetPen(*wxRED_PEN);\n\t\t\tdc.DrawLine(line1, line2);\n\t\t\tdc.DrawLine(line1, wxPoint(line1.x + 3, line1.y));\n\t\t\tdc.DrawLine(line2, wxPoint(line2.x + 3, line2.y));\n\t\t}\n\n\t\tNextLine(position, &start_position);\n\t}\n\n\t// draw vertical separator lines for 4 byte blocks\n\tsint32 cursorOffsetHexBytes = start_position.x + OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE;\n\twxPoint line_from(\n\t\tcursorOffsetHexBytes + m_char_width * (3 * 4 - 1) + m_char_width / 2,\n\t\tstart_position.y\n\t);\n\twxPoint line_to(line_from.x, line_from.y + m_line_height * (count + 1));\n\tdc.SetPen(wxSystemSettings::GetColour(wxSYS_COLOUR_INACTIVECAPTIONTEXT));\n\tfor (sint32 i = 0; i < 3; i++)\n\t{\n\t\tdc.DrawLine(line_from, line_to);\n\t\tline_from.x += m_char_width * (3 * 4);\n\t\tline_to.x += m_char_width * (3 * 4);\n\t}\n}\n\nvoid DumpCtrl::OnMouseMove(const wxPoint& start_position, uint32 line)\n{\n\twxPoint position = start_position;\n\n\t// address\n\tif (position.x <= OFFSET_ADDRESS)\n\t{\n\t\treturn;\n\t}\n\n\tposition.x -= OFFSET_ADDRESS;\n\n\t// relative offset\n\tif (position.x <= OFFSET_ADDRESS_RELATIVE)\n\t{\n\t\treturn;\n\t}\n\n\tposition.x -= OFFSET_ADDRESS_RELATIVE;\n\n\t// byte code\n\tif (position.x <= OFFSET_MEMORY)\n\t{\n\t\t\n\t}\n\n\t// string view\n\tposition.x -= OFFSET_MEMORY;\n}\n\nvoid DumpCtrl::OnMouseDClick(const wxPoint& position, uint32 line)\n{\n\twxPoint pos = position;\n\tif (pos.x <= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE)\n\t\treturn;\n\t \n\tpos.x -= OFFSET_ADDRESS + OFFSET_ADDRESS_RELATIVE;\n\tif(pos.x <= OFFSET_MEMORY)\n\t{\n\t\tconst uint32 byte_index = (pos.x / m_char_width) / 3;\n\t\tconst uint32 offset = LineToOffset(line) + byte_index;\n\t\tif (!memory_isAddressRangeAccessible(offset, 1))\n\t\t\treturn;\n\t\tconst uint8 value = memory_readU8(offset);\n\n\t\twxTextEntryDialog set_value_dialog(this, _(\"Enter a new value.\"), wxString::Format(_(\"Set byte at address %08x\"), offset), wxString::Format(\"%02x\", value));\n\t\tif (set_value_dialog.ShowModal() == wxID_OK)\n\t\t{\n\t\t\tconst uint8 new_value = std::stoul(set_value_dialog.GetValue().ToStdString(), nullptr, 16);\n\t\t\tmemory_writeU8(offset, new_value);\n\t\t\twxRect update_rect(0, line * m_line_height, GetSize().x, m_line_height);\n\t\t\tRefreshControl(&update_rect);\n\t\t}\n\n\t\treturn;\n\t}\n}\n\nvoid DumpCtrl::GoToAddressDialog()\n{\n\twxTextEntryDialog goto_dialog(this, _(\"Enter a target address.\"), _(\"GoTo address\"), wxEmptyString);\n\tif (goto_dialog.ShowModal() == wxID_OK)\n\t{\n\t\tExpressionParser parser;\n\n\t\tauto value = goto_dialog.GetValue().ToStdString();\n\t\tstd::transform(value.begin(), value.end(), value.begin(), tolower);\n\n\t\tdebugger_addParserSymbols(parser);\n\n\t\t// try to parse expression as hex value first (it should interpret 1234 as 0x1234, not 1234)\n\t\tif (parser.IsConstantExpression(\"0x\"+value))\n\t\t{\n\t\t\tconst auto result = (uint32)parser.Evaluate(\"0x\"+value);\n\t\t\tm_lastGotoOffset = result;\n\t\t\tCenterOffset(result);\n\t\t}\n\t\telse if (parser.IsConstantExpression(value))\n\t\t{\n\t\t\tconst auto result = (uint32)parser.Evaluate(value);\n\t\t\tm_lastGotoOffset = result;\n\t\t\tCenterOffset(result);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tconst auto _ = (uint32)parser.Evaluate(value);\n\t\t\t}\n\t\t\tcatch (const std::exception& ex)\n\t\t\t{\n\t\t\t\twxMessageBox(ex.what(), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid DumpCtrl::CenterOffset(uint32 offset)\n{\n\t// check if the offset is valid\n\tif (!memory_isAddressRangeAccessible(offset, 1))\n\t\treturn;\n\t// set region and line\n\tMMURange* range = memory_getMMURangeByAddress(offset);\n\tif (m_memoryRegion.baseAddress != range->getBase() || m_memoryRegion.size != range->getSize())\n\t{\n\t\tm_memoryRegion.baseAddress = range->getBase();\n\t\tm_memoryRegion.size = range->getSize();\n\t\tInit();\n\t}\n\t\n\tconst sint32 line = OffsetToLine(offset);\n\tif (line < 0 || line >= (sint32)m_element_count)\n\t\treturn;\n\n\tDoScroll(0, std::max(0, line - ((sint32)m_elements_visible / 2)));\n\n\tRefreshControl();\n\t//RefreshLine(line);\n\n\tdebug_printf(\"scroll to %x\\n\", debuggerState.debugSession.instructionPointer);\n}\n\nuint32 DumpCtrl::LineToOffset(uint32 line)\n{\n\treturn m_memoryRegion.baseAddress + line * 0x10;\n}\n\nuint32 DumpCtrl::OffsetToLine(uint32 offset)\n{\n\treturn (offset - m_memoryRegion.baseAddress) / 0x10;\n}\n\n\nvoid DumpCtrl::OnKeyPressed(sint32 key_code, const wxPoint& position)\n{\n\tswitch (key_code)\n\t{\n\tcase 'G':\n\t{\n\t\tif (IsKeyDown(WXK_CONTROL))\n\t\t{\n\t\t\tGoToAddressDialog();\n\t\t\treturn;\n\t\t}\n\t}\n\t}\n}\n\nwxSize DumpCtrl::DoGetBestSize() const\n{\n\treturn TextList::DoGetBestSize();\n}\n"
  },
  {
    "path": "src/gui/wxgui/debugger/DumpCtrl.h",
    "content": "#pragma once\n#include \"wxgui/components/TextList.h\"\n\n\nclass DumpCtrl : public TextList\n{\npublic:\n\tDumpCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size, long style);\n\n\tvoid Init();\n\twxSize DoGetBestSize() const override;\n\nprotected:\n\tvoid GoToAddressDialog();\n\tvoid CenterOffset(uint32 offset);\n\tuint32 LineToOffset(uint32 line);\n\tuint32 OffsetToLine(uint32 offset);\n\n\tvoid OnDraw(wxDC& dc, sint32 start, sint32 count, const wxPoint& start_position) override;\n\tvoid OnMouseMove(const wxPoint& position, uint32 line) override;\n\tvoid OnMouseDClick(const wxPoint& position, uint32 line) override;\n\tvoid OnKeyPressed(sint32 key_code, const wxPoint& position) override;\nprivate:\n\tstruct  \n\t{\n\t\tuint32 baseAddress;\n\t\tuint32 size;\n\t}m_memoryRegion;\n\tuint32 m_lastGotoOffset{0};\n};\n"
  },
  {
    "path": "src/gui/wxgui/debugger/DumpWindow.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxgui/debugger/DumpWindow.h\"\n\n#include \"wxgui/debugger/DebuggerWindow2.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include \"wxgui/debugger/DumpCtrl.h\"\n\nenum\n{\n\t// REGISTER\n\tREGISTER_ADDRESS_R0 = wxID_HIGHEST + 8200,\n\tREGISTER_LABEL_R0 = REGISTER_ADDRESS_R0 + 32,\n\tREGISTER_LABEL_FPR0_0 = REGISTER_LABEL_R0 + 32,\n\tREGISTER_LABEL_FPR1_0 = REGISTER_LABEL_R0 + 32,\n};\n\nDumpWindow::DumpWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size)\n\t: wxFrame(&parent, wxID_ANY, _(\"Memory Dump\"), wxDefaultPosition, wxSize(600, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT)\n{\n\twxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);\n\tm_dump_ctrl = new DumpCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxScrolledWindowStyle);\n\tmain_sizer->Add(m_dump_ctrl, 1, wxEXPAND);\n\n\tthis->SetSizer(main_sizer);\n\tthis->wxWindowBase::Layout();\n\n\tthis->Centre(wxBOTH);\n\n\tif (parent.GetConfig().data().pin_to_main)\n\t\tOnMainMove(main_position, main_size);\n}\n\nvoid DumpWindow::OnMainMove(const wxPoint& main_position, const wxSize& main_size)\n{\n\twxSize size(600, 250);\n\tthis->SetSize(size);\n\n\twxPoint position = main_position;\n\tposition.y += main_size.GetHeight();\n\tthis->SetPosition(position);\n}\n\nvoid DumpWindow::OnGameLoaded()\n{\n\tm_dump_ctrl->Init();\n}\n"
  },
  {
    "path": "src/gui/wxgui/debugger/DumpWindow.h",
    "content": "#pragma once\n\n#include \"wxgui/debugger/DumpCtrl.h\"\n\nclass DebuggerWindow2;\n\nclass DumpWindow : public wxFrame\n{\npublic:\n\tDumpWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size);\n\n\tvoid OnMainMove(const wxPoint& position, const wxSize& main_size);\n\tvoid OnGameLoaded();\n\nprivate:\n\twxScrolledWindow* m_scrolled_window;\n\tDumpCtrl* m_dump_ctrl;\n};"
  },
  {
    "path": "src/gui/wxgui/debugger/ModuleWindow.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxgui/debugger/ModuleWindow.h\"\n\n#include <sstream>\n\n#include \"wxgui/debugger/DebuggerWindow2.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n\nenum ItemColumns\n{\n\tColumnName = 0,\n\tColumnAddress,\n\tColumnSize,\n};\n\nModuleWindow::ModuleWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size)\n\t: wxFrame(&parent, wxID_ANY, _(\"Modules\"), wxDefaultPosition, wxSize(420, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT)\n{\n\tthis->SetSizeHints(wxDefaultSize, wxDefaultSize);\n\n\twxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);\n\n\tm_modules = new wxListView(this, wxID_ANY);\n\n\twxListItem col0;\n\tcol0.SetId(ColumnName);\n\tcol0.SetText(_(\"Name\"));\n\tcol0.SetWidth(125);\n\tm_modules->InsertColumn(ColumnName, col0);\n\n\twxListItem col1;\n\tcol1.SetId(ColumnAddress);\n\tcol1.SetText(_(\"Address\"));\n\tcol1.SetWidth(75);\n\tcol1.SetAlign(wxLIST_FORMAT_RIGHT);\n\tm_modules->InsertColumn(ColumnAddress, col1);\n\n\twxListItem col2;\n\tcol2.SetId(ColumnSize);\n\tcol2.SetText(_(\"Size\"));\n\tcol2.SetWidth(75);\n\tcol2.SetAlign(wxLIST_FORMAT_RIGHT);\n\tm_modules->InsertColumn(ColumnSize, col2);\n\n\tmain_sizer->Add(m_modules, 1, wxEXPAND);\n\n\tthis->SetSizer(main_sizer);\n\tthis->wxWindowBase::Layout();\n\n\tthis->Centre(wxBOTH);\n\n\tif (parent.GetConfig().data().pin_to_main)\n\t\tOnMainMove(main_position, main_size);\n\n\tm_modules->Bind(wxEVT_LEFT_DCLICK, &ModuleWindow::OnLeftDClick, this);\n\n\tOnGameLoaded();\n}\n\nvoid ModuleWindow::OnMainMove(const wxPoint& main_position, const wxSize& main_size)\n{\n\twxSize size(420, 250);\n\tthis->SetSize(size);\n\n\twxPoint position = main_position;\n\tposition.x -= 420;\n\tposition.y += main_size.y;\n\tthis->SetPosition(position);\n}\n\n\nvoid ModuleWindow::OnGameLoaded()\n{\n\tFreeze();\n\n\tm_modules->DeleteAllItems();\n\n\tconst auto module_count = RPLLoader_GetModuleCount();\n\tconst auto module_list = RPLLoader_GetModuleList();\n\tfor (int i = 0; i < module_count; i++)\n\t{\n\t\tconst auto module = module_list[i];\n\t\tif (module)\n\t\t{\n\t\t\twxListItem item;\n\t\t\titem.SetId(i);\n\t\t\titem.SetText(module->moduleName2);\n\n\t\t\tconst auto index = m_modules->InsertItem(item);\n\t\t\tm_modules->SetItem(index, ColumnAddress, wxString::Format(\"%08x\", module->regionMappingBase_text.GetMPTR()));\n\t\t\tm_modules->SetItem(index, ColumnSize, wxString::Format(\"%x\", module->regionSize_text));\n\t\t}\n\t}\n\n\tsint32 patch_count = 0;\n\tfor (auto& gfx_pack : GraphicPack2::GetGraphicPacks())\n\t{\n\t\tfor (auto& patch_group : gfx_pack->GetPatchGroups())\n\t\t{\n\t\t\tif (patch_group->isApplied())\n\t\t\t{\n\t\t\t\twxListItem item;\n\t\t\t\titem.SetId(module_count + patch_count);\n\t\t\t\titem.SetText(std::string(patch_group->getName()));\n\n\t\t\t\tconst auto index = m_modules->InsertItem(item);\n\t\t\t\tm_modules->SetItem(index, ColumnAddress, wxString::Format(\"%08x\", patch_group->getCodeCaveBase()));\n\t\t\t\tm_modules->SetItem(index, ColumnSize, wxString::Format(\"%x\", patch_group->getCodeCaveSize()));\n\t\t\t\tpatch_count++;\n\t\t\t}\n\t\t}\n\t}\n\n\tThaw();\n}\n\n\nvoid ModuleWindow::OnLeftDClick(wxMouseEvent& event)\n{\n\tlong selected = m_modules->GetFirstSelected();\n\tif (selected == wxNOT_FOUND)\n\t\treturn;\n\tconst auto text = m_modules->GetItemText(selected, ColumnAddress);\n\tconst auto address = std::stoul(text.ToStdString(), nullptr, 16);\n\tif (address == 0)\n\t\treturn;\n\tdebuggerState.debugSession.instructionPointer = address;\n\tg_debuggerDispatcher.MoveIP();\n}\n"
  },
  {
    "path": "src/gui/wxgui/debugger/ModuleWindow.h",
    "content": "#pragma once\n\n#include <wx/frame.h>\n\nclass DebuggerWindow2;\nclass wxListView;\n\nclass ModuleWindow : public wxFrame\n{\npublic:\n\tModuleWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size);\n\n\tvoid OnMainMove(const wxPoint& position, const wxSize& main_size);\n\tvoid OnGameLoaded();\n\nprivate:\n\tvoid OnLeftDClick(wxMouseEvent& event);\n\n\twxListView* m_modules;\n};\n"
  },
  {
    "path": "src/gui/wxgui/debugger/RegisterWindow.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxgui/debugger/RegisterWindow.h\"\n\n#include <sstream>\n\n#include \"wxgui/debugger/DebuggerWindow2.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/RPL/rpl_structs.h\"\n#include \"Cafe/HW/Espresso/EspressoISA.h\"\n\nenum\n{\n\t// REGISTER\n\tkRegisterValueR0 = wxID_HIGHEST + 8400,\n\tkRegisterLabelR0 = kRegisterValueR0 + 32,\n\tkRegisterLabelLR = kRegisterLabelR0 + 32,\n\tkRegisterValueLR = kRegisterLabelLR + 1,\n\tkRegisterValueFPR0_0 = kRegisterValueLR + 32,\n\tkRegisterValueFPR1_0 = kRegisterValueFPR0_0 + 32,\n\tkRegisterValueCR0 = kRegisterValueFPR1_0 + 32,\n\tkContextMenuZero,\n\tkContextMenuInc,\n\tkContextMenuDec,\n\tkContextMenuCopy,\n\tkContextMenuGotoDisasm,\n\tkContextMenuGotoDump,\n};\n\nRegisterWindow::RegisterWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size)\n\t: wxFrame(&parent, wxID_ANY, _(\"Registers\"), wxDefaultPosition, wxSize(400, 975), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT),\n\tm_prev_snapshot({}), m_show_double_values(true), m_context_ctrl(nullptr)\n{\n\tSetSizeHints(wxDefaultSize, wxDefaultSize);\n\tSetMaxSize({ 400, 975 });\n\tthis->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\n\twxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);\n\n\tauto scrolled_win = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL);\n\twxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tauto gpr_sizer = new wxFlexGridSizer(0, 3, 0, 0);\n\t\n\t// GPRs\n\tfor(sint32 i = 0; i < 32; ++i)\n\t{\n\t\tgpr_sizer->Add(new wxStaticText(scrolled_win, wxID_ANY, wxString::Format(\"R%d\", i)), 0, wxLEFT, 5);\n\n\t\tauto value = new wxTextCtrl(scrolled_win, kRegisterValueR0 + i, wxString::Format(\"%08x\", 0), wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER | wxTE_RICH2);\n\t\tvalue->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\t\tvalue->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\tvalue->Bind(wxEVT_LEFT_DCLICK, &RegisterWindow::OnMouseDClickEvent, this);\n\t\t//value->Bind(wxEVT_CONTEXT_MENU, &RegisterWindow::OnValueContextMenu, this);\n\t\tgpr_sizer->Add(value, 0, wxLEFT|wxRIGHT, 5);\n\n\t\tauto label = new wxTextCtrl(scrolled_win, kRegisterLabelR0 + i, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER | wxTE_RICH2);\n\t\tlabel->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\t\tlabel->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\tlabel->SetMinSize(wxSize(500, -1));\n\t\tgpr_sizer->Add(label, 0, wxEXPAND);\n\t}\n\n\t{\n\t\t// LR\n\t\tgpr_sizer->Add(new wxStaticText(scrolled_win, wxID_ANY, wxString::Format(\"LR\")), 0, wxLEFT, 5);\n\t\tauto value = new wxTextCtrl(scrolled_win, kRegisterValueLR, wxString::Format(\"%08x\", 0), wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER | wxTE_RICH2);\n\t\tvalue->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\t\tvalue->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\tvalue->Bind(wxEVT_LEFT_DCLICK, &RegisterWindow::OnMouseDClickEvent, this);\n\t\t//value->Bind(wxEVT_CONTEXT_MENU, &RegisterWindow::OnValueContextMenu, this);\n\t\tgpr_sizer->Add(value, 0, wxLEFT | wxRIGHT, 5);\n\t\tauto label = new wxTextCtrl(scrolled_win, kRegisterLabelLR, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER | wxTE_RICH2);\n\t\tlabel->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\t\tlabel->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\tlabel->SetMinSize(wxSize(500, -1));\n\t\tgpr_sizer->Add(label, 0, wxEXPAND);\n\t}\n\n\tsizer->Add(gpr_sizer, 1, wxEXPAND);\n\n\tauto button = new wxButton(scrolled_win, wxID_ANY, _(\"FP view mode\"));\n\tbutton->Bind(wxEVT_BUTTON, &RegisterWindow::OnFPViewModePress, this);\n\tsizer->Add(button, 0, wxALL, 5);\n\n\tauto fp_sizer = new wxFlexGridSizer(0, 3, 0, 0);\n\tfor (sint32 i = 0; i < 32; ++i)\n\t{\n\t\tfp_sizer->Add(new wxStaticText(scrolled_win, wxID_ANY, wxString::Format(\"FP%d\", i)), 0, wxLEFT, 5);\n\n\t\tauto value0 = new wxTextCtrl(scrolled_win, kRegisterValueFPR0_0 + i, wxString::Format(\"%lf\", 0.0), wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER | wxTE_RICH2);\n\t\tvalue0->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\t\tvalue0->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\tvalue0->Bind(wxEVT_LEFT_DCLICK, &RegisterWindow::OnMouseDClickEvent, this);\n\t\tfp_sizer->Add(value0, 0, wxLEFT | wxRIGHT, 5);\n\n\t\tauto value1 = new wxTextCtrl(scrolled_win, kRegisterValueFPR1_0 + i, wxString::Format(\"%lf\", 0.0), wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER | wxTE_RICH2);\n\t\tvalue1->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\t\tvalue1->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\tvalue1->Bind(wxEVT_LEFT_DCLICK, &RegisterWindow::OnMouseDClickEvent, this);\n\t\tfp_sizer->Add(value1, 0, wxLEFT | wxRIGHT, 5);\n\t}\n\n\tsizer->Add(fp_sizer, 0, wxEXPAND);\n\tauto cr_sizer = new wxFlexGridSizer(0, 2, 0, 0);\n\n\t// CRs\n\tfor (sint32 i = 0; i < 8; ++i)\n\t{\n\t\tcr_sizer->Add(new wxStaticText(scrolled_win, wxID_ANY, wxString::Format(\"CR%d\", i)), 0, wxLEFT, 5);\n\t\tauto value = new wxTextCtrl(scrolled_win, kRegisterValueCR0 + i, \"-\", wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER | wxTE_RICH2);\n\t\tvalue->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\t\tvalue->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\t//value->Bind(wxEVT_CONTEXT_MENU, &RegisterWindow::OnValueContextMenu, this);\n\t\tcr_sizer->Add(value, 0, wxRIGHT, 5);\n\t}\n\n\tsizer->Add(cr_sizer, 0, wxEXPAND);\n\tscrolled_win->SetSizerAndFit(sizer);\n\tscrolled_win->SetScrollRate(-1, 10);\n\n\tmain_sizer->Add(scrolled_win, 1, wxEXPAND);\n\tSetSizer(main_sizer);\n\tLayout();\n\n\tif (parent.GetConfig().data().pin_to_main)\n\t\tOnMainMove(main_position, main_size);\n\n\t//Bind(wxEVT_COMMAND_MENU_SELECTED, &RegisterWindow::OnValueContextMenuSelected, this, kContextMenuZero, kContextMenuGotoDump);\n}\n\n\nvoid RegisterWindow::OnMainMove(const wxPoint& main_position, const wxSize& main_size)\n{\n\twxSize size(400, 255 + main_size.y + 250);\n\tthis->SetSize(size);\n\n\twxPoint position = main_position;\n\tposition.x += main_size.x;\n\tposition.y -= 255;\n\tthis->SetPosition(position);\n}\n\nvoid RegisterWindow::UpdateIntegerRegister(wxTextCtrl* label, wxTextCtrl* value, uint32 registerValue, bool hasChanged)\n{\n\t//const auto value = dynamic_cast<wxTextCtrl*>(GetWindowChild(kRegisterValueR0 + i));\n\t//wxASSERT(value);\n\n\t//const bool has_changed = register_value != m_prev_snapshot.gpr[i];\n\tif (hasChanged)\n\t\tvalue->SetForegroundColour(m_changed_color);\n\telse if (value->GetForegroundColour() != wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT))\n\t\tvalue->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\n\tvalue->ChangeValue(wxString::Format(\"%08x\", registerValue));\n\n\t//const auto label = dynamic_cast<wxTextCtrl*>(GetWindowChild(kRegisterLabelR0 + i));\n\t//wxASSERT(label);\n\tlabel->SetForegroundColour(hasChanged ? m_changed_color : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\n\t// check if address is a string\n\tif (registerValue >= MEMORY_DATA_AREA_ADDR && registerValue < (MEMORY_DATA_AREA_ADDR + MEMORY_DATA_AREA_SIZE))\n\t{\n\t\tbool is_valid_string = true;\n\t\tstd::stringstream buffer;\n\n\t\tuint32 string_offset = registerValue;\n\t\twhile (string_offset < (MEMORY_DATA_AREA_ADDR + MEMORY_DATA_AREA_SIZE))\n\t\t{\n\t\t\tconst uint8 c = memory_readU8(string_offset++);\n\t\t\tif (isprint(c))\n\t\t\t\tbuffer << c;\n\t\t\telse if (c == '\\0')\n\t\t\t{\n\t\t\t\tbuffer << c;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tis_valid_string = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (is_valid_string && buffer.tellp() > 1)\n\t\t{\n\t\t\tlabel->ChangeValue(wxString::Format(\"\\\"%s\\\"\", buffer.str().c_str()));\n\t\t\treturn;\n\t\t}\n\n\t\t// check for widestring\n\t\tis_valid_string = true;\n\t\tstring_offset = registerValue;\n\t\tstd::wstringstream wbuffer;\n\t\twhile (string_offset < (MEMORY_DATA_AREA_ADDR + MEMORY_DATA_AREA_SIZE - 1))\n\t\t{\n\t\t\tconst uint16 c = memory_readU16(string_offset);\n\t\t\tstring_offset += 2;\n\n\t\t\tif (iswprint(c))\n\t\t\t\twbuffer << c;\n\t\t\telse if (c == L'\\0')\n\t\t\t{\n\t\t\t\twbuffer << c;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tis_valid_string = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (is_valid_string && buffer.tellp() > 1)\n\t\t{\n\t\t\tlabel->ChangeValue(wxString::Format(L\"ws\\\"%s\\\"\", wbuffer.str().c_str()));\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// check if address is a code offset\n\tRPLModule* code_module = RPLLoader_FindModuleByCodeAddr(registerValue);\n\tif (code_module)\n\t{\n\t\tlabel->ChangeValue(wxString::Format(\"<%s> + %x\", code_module->moduleName2.c_str(), registerValue - code_module->regionMappingBase_text.GetMPTR()));\n\t\treturn;\n\t}\n\n\tlabel->ChangeValue(wxEmptyString);\n}\n\nvoid RegisterWindow::OnUpdateView()\n{\n\t// m_register_ctrl->RefreshControl();\n\tfor (int i = 0; i < 32; ++i)\n\t{\n\t\tconst uint32 registerValue = debuggerState.debugSession.ppcSnapshot.gpr[i];\n\t\tconst bool hasChanged = registerValue != m_prev_snapshot.gpr[i];\n\t\tconst auto value = dynamic_cast<wxTextCtrl*>(FindWindow(kRegisterValueR0 + i));\n\t\twxASSERT(value);\n\t\tconst auto label = dynamic_cast<wxTextCtrl*>(FindWindow(kRegisterLabelR0 + i));\n\t\twxASSERT(label);\n\n\t\tUpdateIntegerRegister(label, value, registerValue, hasChanged);\n\t}\n\n\t// update LR\n\t{\n\t\tconst uint32 registerValue = debuggerState.debugSession.ppcSnapshot.spr_lr;\n\t\tconst bool hasChanged = registerValue != m_prev_snapshot.spr_lr;\n\t\tconst auto value = dynamic_cast<wxTextCtrl*>(FindWindow(kRegisterValueLR));\n\t\twxASSERT(value);\n\t\tconst auto label = dynamic_cast<wxTextCtrl*>(FindWindow(kRegisterLabelLR));\n\t\twxASSERT(label);\n\t\tUpdateIntegerRegister(label, value, registerValue, hasChanged);\n\t}\n\n\tfor (int i = 0; i < 32; ++i)\n\t{\n\t\tconst uint64_t register_value = debuggerState.debugSession.ppcSnapshot.fpr[i].fp0int;\n\n\t\tconst auto value = dynamic_cast<wxTextCtrl*>(FindWindow(kRegisterValueFPR0_0 + i));\n\t\twxASSERT(value);\n\n\t\tconst bool has_changed = register_value != m_prev_snapshot.fpr[i].fp0int;\n\t\tif (has_changed)\n\t\t\tvalue->SetForegroundColour(m_changed_color);\n\t\telse if (value->GetForegroundColour() != wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT))\n\t\t\tvalue->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\telse\n\t\t\tcontinue;\n\n\t\tif(m_show_double_values)\n\t\t\tvalue->ChangeValue(wxString::Format(\"%lf\", debuggerState.debugSession.ppcSnapshot.fpr[i].fp0));\n\t\telse\n\t\t\tvalue->ChangeValue(wxString::Format(\"%016llx\", register_value));\n\t}\n\n\tfor (int i = 0; i < 32; ++i)\n\t{\n\t\tconst uint64_t register_value = debuggerState.debugSession.ppcSnapshot.fpr[i].fp1int;\n\n\t\tconst auto value = dynamic_cast<wxTextCtrl*>(FindWindow(kRegisterValueFPR1_0 + i));\n\t\twxASSERT(value);\n\n\t\tconst bool has_changed = register_value != m_prev_snapshot.fpr[i].fp1int;\n\t\tif (has_changed)\n\t\t\tvalue->SetForegroundColour(m_changed_color);\n\t\telse if (value->GetForegroundColour() != wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT))\n\t\t\tvalue->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\telse\n\t\t\tcontinue;\n\n\t\tif (m_show_double_values)\n\t\t\tvalue->ChangeValue(wxString::Format(\"%lf\", debuggerState.debugSession.ppcSnapshot.fpr[i].fp1));\n\t\telse\n\t\t\tvalue->ChangeValue(wxString::Format(\"%016llx\", register_value));\n\t}\n\n\t// update CRs\n\tfor (int i = 0; i < 8; ++i)\n\t{\n\t\tconst auto value = dynamic_cast<wxTextCtrl*>(FindWindow(kRegisterValueCR0 + i));\n\t\twxASSERT(value);\n\t\t\n\t\tauto cr_bits_ptr = debuggerState.debugSession.ppcSnapshot.cr + i * 4;\n\t\tauto cr_bits_ptr_cmp = m_prev_snapshot.cr + i * 4;\n\n\t\tconst bool has_changed = !std::equal(cr_bits_ptr, cr_bits_ptr + 4, cr_bits_ptr_cmp);\n\t\tif (has_changed)\n\t\t\tvalue->SetForegroundColour(m_changed_color);\n\t\telse if (value->GetForegroundColour() != wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT))\n\t\t\tvalue->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\t\telse\n\t\t\tcontinue;\n\n\t\tstd::vector<std::string> joinArray = {};\n\t\tif (cr_bits_ptr[Espresso::CR_BIT_INDEX_LT] != 0)\n\t\t\tjoinArray.emplace_back(\"LT\");\n\t\tif (cr_bits_ptr[Espresso::CR_BIT_INDEX_GT] != 0)\n\t\t\tjoinArray.emplace_back(\"GT\");\n\t\tif (cr_bits_ptr[Espresso::CR_BIT_INDEX_EQ] != 0)\n\t\t\tjoinArray.emplace_back(\"EQ\");\n\t\tif (cr_bits_ptr[Espresso::CR_BIT_INDEX_SO] != 0)\n\t\t\tjoinArray.emplace_back(\"SO\");\n\n\t\tif (joinArray.empty())\n\t\t\tvalue->ChangeValue(\"-\");\n\t\telse\n\t\t\tvalue->ChangeValue(fmt::format(\"{}\", fmt::join(joinArray, \", \")));\n\t}\n\n\tmemcpy(&m_prev_snapshot, &debuggerState.debugSession.ppcSnapshot, sizeof(m_prev_snapshot));\n}\n\nvoid RegisterWindow::OnMouseDClickEvent(wxMouseEvent& event)\n{\n\tif (!debuggerState.debugSession.isTrapped)\n\t{\n\t\tevent.Skip();\n\t\treturn;\n\t}\n\n\tconst auto id = event.GetId();\n\tif(kRegisterValueR0 <= id && id < kRegisterValueR0 + 32)\n\t{\n\t\tconst uint32 register_index = id - kRegisterValueR0;\n\t\tconst uint32 register_value = debuggerState.debugSession.ppcSnapshot.gpr[register_index];\n\t\twxTextEntryDialog set_value_dialog(this, _(\"Enter a new value.\"), wxString::Format(_(\"Set R%d value\"), register_index), wxString::Format(\"%08x\", register_value));\n\t\tif (set_value_dialog.ShowModal() == wxID_OK)\n\t\t{\n\t\t\tconst uint32 new_value = std::stoul(set_value_dialog.GetValue().ToStdString(), nullptr, 16);\n\t\t\tdebuggerState.debugSession.hCPU->gpr[register_index] = new_value;\n\t\t\tdebuggerState.debugSession.ppcSnapshot.gpr[register_index] = new_value;\n\t\t\tOnUpdateView();\n\t\t}\n\t\t\t\t\n\t\treturn;\n\t}\n\n\tif (kRegisterValueFPR0_0 <= id && id < kRegisterValueFPR0_0 + 32)\n\t{\n\t\tconst uint32 register_index = id - kRegisterValueFPR0_0;\n\t\tconst double register_value = debuggerState.debugSession.ppcSnapshot.fpr[register_index].fp0;\n\t\twxTextEntryDialog set_value_dialog(this, _(\"Enter a new value.\"), wxString::Format(_(\"Set FP0_%d value\"), register_index), wxString::Format(\"%lf\", register_value));\n\t\tif (set_value_dialog.ShowModal() == wxID_OK)\n\t\t{\n\t\t\tconst double new_value = std::stod(set_value_dialog.GetValue().ToStdString());\n\t\t\tdebuggerState.debugSession.hCPU->fpr[register_index].fp0 = new_value;\n\t\t\tdebuggerState.debugSession.ppcSnapshot.fpr[register_index].fp0 = new_value;\n\t\t\tOnUpdateView();\n\t\t}\n\n\t\treturn;\n\t}\n\n\tif (kRegisterValueFPR1_0 <= id && id < kRegisterValueFPR1_0 + 32)\n\t{\n\t\tconst uint32 register_index = id - kRegisterValueFPR1_0;\n\t\tconst double register_value = debuggerState.debugSession.ppcSnapshot.fpr[register_index].fp1;\n\t\twxTextEntryDialog set_value_dialog(this, _(\"Enter a new value.\"), wxString::Format(_(\"Set FP1_%d value\"), register_index), wxString::Format(\"%lf\", register_value));\n\t\tif (set_value_dialog.ShowModal() == wxID_OK)\n\t\t{\n\t\t\tconst double new_value = std::stod(set_value_dialog.GetValue().ToStdString());\n\t\t\tdebuggerState.debugSession.hCPU->fpr[register_index].fp1 = new_value;\n\t\t\tdebuggerState.debugSession.ppcSnapshot.fpr[register_index].fp1 = new_value;\n\t\t\tOnUpdateView();\n\t\t}\n\n\t\treturn;\n\t}\n\n\tevent.Skip();\n}\n\nvoid RegisterWindow::OnFPViewModePress(wxCommandEvent& event)\n{\n\tm_show_double_values = !m_show_double_values;\n\t\n\tfor (int i = 0; i < 32; ++i)\n\t{\n\t\tconst auto value0 = dynamic_cast<wxTextCtrl*>(FindWindow(kRegisterValueFPR0_0 + i));\n\t\tconst auto value1 = dynamic_cast<wxTextCtrl*>(FindWindow(kRegisterValueFPR1_0 + i));\n\t\twxASSERT(value0);\n\t\twxASSERT(value1);\n\n\t\tif (m_show_double_values)\n\t\t{\n\t\t\tvalue0->ChangeValue(wxString::Format(\"%lf\", debuggerState.debugSession.ppcSnapshot.fpr[i].fp0));\n\t\t\tvalue1->ChangeValue(wxString::Format(\"%lf\", debuggerState.debugSession.ppcSnapshot.fpr[i].fp1));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvalue0->ChangeValue(wxString::Format(\"%016llx\", debuggerState.debugSession.ppcSnapshot.fpr[i].fp0int));\n\t\t\tvalue1->ChangeValue(wxString::Format(\"%016llx\", debuggerState.debugSession.ppcSnapshot.fpr[i].fp1int));\n\t\t}\n\t}\n}\n\nvoid RegisterWindow::OnValueContextMenu(wxContextMenuEvent& event)\n{\n\twxMenu menu;\n\n\tmenu.Append(kContextMenuZero, _(\"&Zero\"));\n\tmenu.Append(kContextMenuInc, _(\"&Increment\"));\n\tmenu.Append(kContextMenuDec, _(\"&Decrement\"));\n\tmenu.AppendSeparator();\n\tmenu.Append(kContextMenuCopy, _(\"&Copy\"));\n\tmenu.AppendSeparator();\n\tmenu.Append(kContextMenuGotoDisasm, _(\"&Goto Disasm\"));\n\tmenu.Append(kContextMenuGotoDump, _(\"G&oto Dump\"));\n\n\tm_context_ctrl = dynamic_cast<wxTextCtrl*>(event.GetEventObject());\n\n\tPopupMenu(&menu);\n}\n\nvoid RegisterWindow::OnValueContextMenuSelected(wxCommandEvent& event)\n{\n\twxASSERT(m_context_ctrl);\n\n\tswitch (event.GetId()) \n\t{\n\tcase kContextMenuZero:\n\t\tbreak;\n\tcase kContextMenuInc:\n\t\tbreak;\n\tcase kContextMenuDec:\n\t\tbreak;\n\tcase kContextMenuCopy:\n\t\tbreak;\n\tcase kContextMenuGotoDisasm:\n\t\tbreak;\n\tcase kContextMenuGotoDump:\n\t\tbreak;\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/debugger/RegisterWindow.h",
    "content": "#pragma once\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include <wx/frame.h>\n\nclass DebuggerWindow2;\nclass wxTextCtrl;\n\nclass RegisterWindow : public wxFrame\n{\npublic:\n\tRegisterWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size);\n\n\tvoid OnMainMove(const wxPoint& position, const wxSize& main_size);\n\tvoid OnUpdateView();\n\nprivate:\n\tvoid OnMouseDClickEvent(wxMouseEvent& event);\n\tvoid OnFPViewModePress(wxCommandEvent& event);\n\tvoid OnValueContextMenu(wxContextMenuEvent& event);\n\tvoid OnValueContextMenuSelected(wxCommandEvent& event);\n\n\tvoid UpdateIntegerRegister(wxTextCtrl* label, wxTextCtrl* value, uint32 registerValue, bool hasChanged);\n\n\tPPCSnapshot m_prev_snapshot;\n\tbool m_show_double_values;\n\twxColour m_changed_color = {0xFF0000FF};\n\n\twxTextCtrl* m_context_ctrl;\n};\n"
  },
  {
    "path": "src/gui/wxgui/debugger/SymbolCtrl.cpp",
    "content": "#include \"wxgui/debugger/SymbolCtrl.h\"\n#include \"Cafe/OS/RPL/rpl_symbol_storage.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include <wx/listctrl.h>\n\nenum ItemColumns\n{\n\tColumnName = 0,\n\tColumnAddress,\n\tColumnModule,\n};\n\nSymbolListCtrl::SymbolListCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size) : wxListView(parent, id, pos, size, wxLC_REPORT | wxLC_VIRTUAL)\n{    \n\twxListItem col0;\n\tcol0.SetId(ColumnName);\n\tcol0.SetText(_(\"Name\"));\n\tcol0.SetWidth(200);\n\tInsertColumn(ColumnName, col0);\n\n\twxListItem col1;\n\tcol1.SetId(ColumnAddress);\n\tcol1.SetText(_(\"Address\"));\n\tcol1.SetWidth(75);\n\tcol1.SetAlign(wxLIST_FORMAT_RIGHT);\n\tInsertColumn(ColumnAddress, col1);\n\n\twxListItem col2;\n\tcol2.SetId(ColumnModule);\n\tcol2.SetText(_(\"Module\"));\n\tcol2.SetWidth(75);\n\tcol2.SetAlign(wxLIST_FORMAT_RIGHT);\n\tInsertColumn(ColumnModule, col2);\n\n\tBind(wxEVT_LIST_ITEM_ACTIVATED, &SymbolListCtrl::OnLeftDClick, this);\n\tBind(wxEVT_LIST_ITEM_RIGHT_CLICK, &SymbolListCtrl::OnRightClick, this);\n\n\tm_list_filter.Clear();\n\n\tOnGameLoaded();\n\n\tSetItemCount(m_data.size());\n}\n\nvoid SymbolListCtrl::OnGameLoaded()\n{\n\tm_data.clear();\n\tconst auto symbol_map = rplSymbolStorage_lockSymbolMap();\n\tfor (auto const& [address, symbol_info] : symbol_map)\n\t{\n\t\tif (symbol_info == nullptr || symbol_info->symbolName == nullptr)\n\t\t\tcontinue;\n\n\t\twxString libNameWX = wxString::FromAscii((const char*)symbol_info->libName);\n\t\twxString symbolNameWX = wxString::FromAscii((const char*)symbol_info->symbolName);\n\t\twxString searchNameWX = libNameWX + symbolNameWX;\n\t\tsearchNameWX.MakeLower();\n\n\t\tauto new_entry = m_data.try_emplace(\n\t\t\tsymbol_info->address,\n            symbolNameWX,\n\t\t\tlibNameWX,\n            searchNameWX,\n\t\t\tfalse\n\t\t);\n\n\t\tif (m_list_filter.IsEmpty())\n\t\t\tnew_entry.first->second.visible = true;\n\t\telse if (new_entry.first->second.searchName.Contains(m_list_filter))\n\t\t\tnew_entry.first->second.visible = true;\n\t}\n\trplSymbolStorage_unlockSymbolMap();\n\n\tSetItemCount(m_data.size());\n\tif (m_data.size() > 0)\n\t\tRefreshItems(GetTopItem(), std::min<long>(m_data.size() - 1, GetTopItem() + GetCountPerPage() + 1));\n}\n\nwxString SymbolListCtrl::OnGetItemText(long item, long column) const\n{\n\tif (item >= GetItemCount())\n\t\treturn wxEmptyString;\n\n\tlong visible_idx = 0;\n\tfor (const auto& [address, symbol] : m_data)\n\t{\n\t\tif (!symbol.visible)\n\t\t\tcontinue;\n\n\t\tif (item == visible_idx)\n\t\t{\n\t\t\tif (column == ColumnName)\n\t\t\t\treturn wxString(symbol.name);\n\t\t\tif (column == ColumnAddress)\n\t\t\t\treturn wxString::Format(\"%08x\", address);\n\t\t\tif (column == ColumnModule)\n\t\t\t\treturn wxString(symbol.libName);\n\t\t}\n\t\tvisible_idx++;\n\t}\n\n\treturn wxEmptyString;\n}\n\n\nvoid SymbolListCtrl::OnLeftDClick(wxListEvent& event)\n{\n\tlong selected = GetFirstSelected();\n\tif (selected == wxNOT_FOUND)\n\t\treturn;\n\tconst auto text = GetItemText(selected, ColumnAddress);\n\tconst auto address = std::stoul(text.ToStdString(), nullptr, 16);\n\tif (address == 0)\n\t\treturn;\n\tdebuggerState.debugSession.instructionPointer = address;\n\tg_debuggerDispatcher.MoveIP();\n}\n\nvoid SymbolListCtrl::OnRightClick(wxListEvent& event)\n{\n\tlong selected = GetFirstSelected();\n\tif (selected == wxNOT_FOUND)\n\t\treturn;\n\tauto text = GetItemText(selected, ColumnAddress);\n\ttext = \"0x\" + text;\n#if BOOST_OS_WINDOWS\n\tif (OpenClipboard(nullptr))\n\t{\n\t\tEmptyClipboard();\n\t\tconst HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, text.size()+1);\n\t\tif (hGlobal)\n\t\t{\n\t\t\tmemcpy(GlobalLock(hGlobal), text.c_str(), text.size() + 1);\n\t\t\tGlobalUnlock(hGlobal);\n\n\t\t\tSetClipboardData(CF_TEXT, hGlobal);\n\t\t\tGlobalFree(hGlobal);\n\t\t}\n\t\tCloseClipboard();\n\t}\n#endif\n}\n\nvoid SymbolListCtrl::ChangeListFilter(wxString filter)\n{\n\tm_list_filter = filter.MakeLower();\n\n\tsize_t visible_entries = m_data.size();\n\tfor (auto& [address, symbol] : m_data)\n\t{\n\t\tif (m_list_filter.IsEmpty())\n\t\t\tsymbol.visible = true;\n\t\telse if (symbol.searchName.Contains(m_list_filter))\n\t\t\tsymbol.visible = true;\n\t\telse\n\t\t{\n\t\t\tvisible_entries--;\n\t\t\tsymbol.visible = false;\n\t\t}\n\t}\n\tSetItemCount(visible_entries);\n\tif (visible_entries > 0)\n\t\tRefreshItems(GetTopItem(), std::min<long>(visible_entries - 1, GetTopItem() + GetCountPerPage() + 1));\n}\n"
  },
  {
    "path": "src/gui/wxgui/debugger/SymbolCtrl.h",
    "content": "#pragma once\n\n#include <wx/listctrl.h>\n\nclass SymbolListCtrl : public wxListView\n{\npublic:\n\tSymbolListCtrl(wxWindow* parent, const wxWindowID& id, const wxPoint& pos, const wxSize& size);\n\tvoid OnGameLoaded();\n\n\tvoid ChangeListFilter(wxString filter);\n\n  private:\n\tstruct SymbolItem {\n        SymbolItem() = default;\n        SymbolItem(wxString name, wxString libName, wxString searchName, bool visible) : name(name), libName(libName), searchName(searchName), visible(visible) {}\n\n\n\t\twxString name;\n\t\twxString libName;\n\t\twxString searchName;\n\t\tbool visible;\n\t};\n\n\tstd::map<MPTR, SymbolItem> m_data;\n\twxString m_list_filter;\n\n\twxString OnGetItemText(long item, long column) const;\n\tvoid OnLeftDClick(wxListEvent& event);\n\tvoid OnRightClick(wxListEvent& event);\n};\n"
  },
  {
    "path": "src/gui/wxgui/debugger/SymbolWindow.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxgui/debugger/SymbolWindow.h\"\n#include \"wxgui/debugger/DebuggerWindow2.h\"\n#include \"Cafe/HW/Espresso/Debugger/Debugger.h\"\n#include \"Cafe/OS/RPL/rpl_symbol_storage.h\"\n\nenum ItemColumns\n{\n\tColumnName = 0,\n\tColumnAddress,\n\tColumnModule,\n};\n\nSymbolWindow::SymbolWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size)\n\t: wxFrame(&parent, wxID_ANY, _(\"Symbols\"), wxDefaultPosition, wxSize(600, 250), wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT)\n{\n\twxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);\n\tm_symbol_ctrl = new SymbolListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);\n\tmain_sizer->Add(m_symbol_ctrl, 1, wxEXPAND);\n\n\tm_filter = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_NO_VSCROLL);\n\tm_filter->Bind(wxEVT_TEXT, &SymbolWindow::OnFilterChanged, this);\n\tmain_sizer->Add(m_filter, 0, wxALL | wxEXPAND, 5);\n\n\tthis->SetSizer(main_sizer);\n\tthis->wxWindowBase::Layout();\n\n\tthis->Centre(wxHORIZONTAL);\n\n\tif (parent.GetConfig().data().pin_to_main)\n\t\tOnMainMove(main_position, main_size);\n}\n\nvoid SymbolWindow::OnMainMove(const wxPoint& main_position, const wxSize& main_size)\n{\n\twxSize size(420, 250);\n\tthis->SetSize(size);\n\n\twxPoint position = main_position;\n\tposition.x -= 420;\n\tthis->SetPosition(position);\n}\n\nvoid SymbolWindow::OnGameLoaded()\n{\n\tm_symbol_ctrl->OnGameLoaded();\n}\n\nvoid SymbolWindow::OnFilterChanged(wxCommandEvent& event)\n{\n\tm_symbol_ctrl->ChangeListFilter(m_filter->GetValue());\n}\n"
  },
  {
    "path": "src/gui/wxgui/debugger/SymbolWindow.h",
    "content": "#pragma once\n\n#include \"wxgui/debugger/SymbolCtrl.h\"\n#include <wx/frame.h>\n\nclass DebuggerWindow2;\n\nclass SymbolWindow : public wxFrame\n{\npublic:\n\tSymbolWindow(DebuggerWindow2& parent, const wxPoint& main_position, const wxSize& main_size);\n\n\tvoid OnMainMove(const wxPoint& position, const wxSize& main_size);\n\tvoid OnGameLoaded();\n\n\tvoid OnLeftDClick(wxListEvent& event);\n\nprivate:\n\twxTextCtrl* m_filter;\n\tSymbolListCtrl* m_symbol_ctrl;\n\n\tvoid OnFilterChanged(wxCommandEvent& event);\n};\n"
  },
  {
    "path": "src/gui/wxgui/dialogs/CreateAccount/wxCreateAccountDialog.cpp",
    "content": "#include \"wxgui/dialogs/CreateAccount/wxCreateAccountDialog.h\"\n#include \"Cafe/Account/Account.h\"\n\n#include <wx/sizer.h>\n#include <wx/stattext.h>\n#include <wx/choice.h>\n#include <wx/button.h>\n#include <wx/textctrl.h>\n#include <wx/msgdlg.h>\n#include <helpers/wxHelpers.h>\n#include \"util/helpers/helpers.h\"\n\nwxCreateAccountDialog::wxCreateAccountDialog(wxWindow* parent)\n\t: wxDialog(parent, wxID_ANY, _(\"Create new account\"))\n{\n\tauto* main_sizer = new wxFlexGridSizer(0, 2, 0, 0);\n\tmain_sizer->AddGrowableCol(1);\n\tmain_sizer->SetFlexibleDirection(wxBOTH);\n\tmain_sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\tmain_sizer->Add(new wxStaticText(this, wxID_ANY, \"PersistentId\"), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\n\tm_persistent_id = new wxTextCtrl(this, wxID_ANY, fmt::format(\"{:x}\", Account::GetNextPersistentId()));\n\tm_persistent_id->SetToolTip(_(\"The persistent id is the internal folder name used for your saves. Only change this if you are importing saves from a Wii U with a specific id\"));\n\tmain_sizer->Add(m_persistent_id, 1, wxALL | wxEXPAND, 5);\n\n\tmain_sizer->Add(new wxStaticText(this, wxID_ANY, _(\"Mii name\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\tm_mii_name = new wxTextCtrl(this, wxID_ANY);\n\tm_mii_name->SetFocus();\n\tm_mii_name->SetMaxLength(10);\n\tmain_sizer->Add(m_mii_name, 1, wxALL | wxEXPAND, 5);\n\n\tmain_sizer->Add(0, 0, 1, wxEXPAND, 5);\n\t{\n\t\tauto* button_sizer = new wxBoxSizer(wxHORIZONTAL);\n\n\t\tm_ok_button = new wxButton(this, wxID_ANY, _(\"OK\"));\n\t\tm_ok_button->Bind(wxEVT_BUTTON, &wxCreateAccountDialog::OnOK, this);\n\t\tbutton_sizer->Add(m_ok_button, 0, wxALL, 5);\n\n\t\tm_cancel_buton = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\t\tm_cancel_buton->Bind(wxEVT_BUTTON, &wxCreateAccountDialog::OnCancel, this);\n\t\tbutton_sizer->Add(m_cancel_buton, 0, wxALL, 5);\n\n\t\tmain_sizer->Add(button_sizer, 1, wxALIGN_RIGHT, 5);\n\t}\n\n\tthis->SetSizerAndFit(main_sizer);\n\tthis->wxWindowBase::Layout();\n}\n\nuint32 wxCreateAccountDialog::GetPersistentId() const\n{\n\tconst std::string id_string = m_persistent_id->GetValue().ToStdString();\n\treturn ConvertString<uint32>(id_string, 16);\n}\n\nwxString wxCreateAccountDialog::GetMiiName() const\n{\n\treturn m_mii_name->GetValue();\n}\n\nvoid wxCreateAccountDialog::OnOK(wxCommandEvent& event)\n{\n\tif(m_persistent_id->IsEmpty())\n\t{\n\t\twxMessageBox(_(\"No persistent id entered!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\tconst auto id = GetPersistentId();\n\tif(id < Account::kMinPersistendId)\n\t{\n\t\twxMessageBox(formatWxString(_(\"The persistent id must be greater than {:x}!\"), Account::kMinPersistendId),\n\t\t\t_(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\t\n\tconst auto& account = Account::GetAccount(id);\n\tif(account.GetPersistentId() == id)\n\t{\n\t\tconst std::wstring msg = fmt::format(fmt::runtime(_(\"The persistent id {:x} is already in use by account {}!\").ToStdWstring()), \n\t\t\taccount.GetPersistentId(), std::wstring{ account.GetMiiName() });\n\t\twxMessageBox(msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\t\n\tif(m_mii_name->IsEmpty())\n\t{\n\t\twxMessageBox(_(\"Account name may not be empty!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\t\n\tEndModal(wxID_OK);\n}\n\nvoid wxCreateAccountDialog::OnCancel(wxCommandEvent& event)\n{\n\tEndModal(wxID_CANCEL);\n}\n"
  },
  {
    "path": "src/gui/wxgui/dialogs/CreateAccount/wxCreateAccountDialog.h",
    "content": "#pragma once\n#include <wx/dialog.h>\n\nclass wxCreateAccountDialog : public wxDialog\n{\npublic:\n\twxCreateAccountDialog(wxWindow* parent);\n\n\t[[nodiscard]] uint32 GetPersistentId() const;\n\t[[nodiscard]] wxString GetMiiName() const;\nprivate:\n\tclass wxTextCtrl* m_persistent_id;\n\tclass wxTextCtrl* m_mii_name;\n\tclass wxButton* m_ok_button, * m_cancel_buton;\n\n\tvoid OnOK(wxCommandEvent& event);\n\tvoid OnCancel(wxCommandEvent& event);\n};"
  },
  {
    "path": "src/gui/wxgui/dialogs/SaveImport/SaveImportWindow.cpp",
    "content": "#include \"SaveImportWindow.h\"\n\n#include \"pugixml.hpp\"\n#include <wx/sizer.h>\n#include <wx/choice.h>\n#include <wx/combobox.h>\n#include <wx/stattext.h>\n#include <wx/button.h>\n#include <wx/frame.h>\n#include <wx/filepicker.h>\n#include <wx/msgdlg.h>\n#include \"zip.h\"\n\n#include \"Cafe/Account/Account.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Time.h\"\n#include \"util/helpers/helpers.h\"\n#include \"Cafe/HW/Espresso/PPCState.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n\nSaveImportWindow::SaveImportWindow(wxWindow* parent, uint64 title_id)\n\t: wxDialog(parent, wxID_ANY, _(\"Import save entry\"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxFRAME_TOOL_WINDOW | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX),\n\tm_title_id(title_id)\n{\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\t{\n\t\tauto* row1 = new wxFlexGridSizer(0, 2, 0, 0);\n\t\trow1->AddGrowableCol(1);\n\n\t\trow1->Add(new wxStaticText(this, wxID_ANY, _(\"Source\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tm_source_selection = new wxFilePickerCtrl(this, wxID_ANY, wxEmptyString,\n\t\t\t_(\"Select a zipped save file\"),\n\t\t\tformatWxString(\"{}|*.zip\", _(\"Save entry (*.zip)\")));\n\t\tm_source_selection->SetMinSize({ 270, -1 });\n\t\trow1->Add(m_source_selection, 1, wxALL | wxEXPAND, 5);\n\n\t\trow1->Add(new wxStaticText(this, wxID_ANY, _(\"Target\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tconst auto& accounts = Account::GetAccounts();\n\t\tm_target_selection = new wxComboBox(this, wxID_ANY);\n\t\tfor (const auto& account : accounts)\n\t\t{\n\t\t\tm_target_selection->Append(fmt::format(\"{:x} ({})\", account.GetPersistentId(),\n\t\t\t\tboost::nowide::narrow(account.GetMiiName().data(), account.GetMiiName().size())),\n\t\t\t\t(void*)(uintptr_t)account.GetPersistentId());\n\t\t}\n\t\trow1->Add(m_target_selection, 1, wxALL | wxEXPAND, 5);\n\n\t\tsizer->Add(row1, 0, wxEXPAND, 5);\n\t}\n\n\t{\n\t\tauto* row2 = new wxFlexGridSizer(0, 2, 0, 0);\n\t\trow2->AddGrowableCol(1);\n\t\trow2->SetFlexibleDirection(wxBOTH);\n\t\trow2->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tauto* ok_button = new wxButton(this, wxID_ANY, _(\"OK\"));\n\t\tok_button->Bind(wxEVT_BUTTON, &SaveImportWindow::OnImport, this);\n\t\trow2->Add(ok_button, 0, wxALL, 5);\n\n\t\tauto* cancel_button = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\t\tcancel_button->Bind(wxEVT_BUTTON, [this](auto&)\n\t\t\t{\n\t\t\t\tm_return_code = wxCANCEL;\n\t\t\t\tClose();\n\t\t\t});\n\t\trow2->Add(cancel_button, 0, wxALIGN_RIGHT | wxALL, 5);\n\n\t\tsizer->Add(row2, 1, wxEXPAND, 5);\n\t}\n\n\tthis->SetSizerAndFit(sizer);\n\tthis->Centre(wxBOTH);\n}\n\nvoid SaveImportWindow::EndModal(int retCode)\n{\n\twxDialog::EndModal(retCode);\n\tSetReturnCode(m_return_code);\n}\n\nvoid SaveImportWindow::OnImport(wxCommandEvent& event)\n{\n\tconst auto source_path = m_source_selection->GetPath();\n\tif (source_path.empty())\n\t\treturn;\n\n\t// try to find cemu_meta file to verify targetid\n\tconst std::string zipfile = source_path.ToUTF8().data();\n\t\n\tint ziperr;\n\tauto* zip = zip_open(zipfile.c_str(), ZIP_RDONLY, &ziperr);\n\tif (zip)\n\t{\n\t\tconst sint32 numEntries = zip_get_num_entries(zip, 0);\n\t\tfor (sint32 i = 0; i < numEntries; i++)\n\t\t{\n\t\t\tzip_stat_t sb{};\n\t\t\tif (zip_stat_index(zip, i, 0, &sb) != 0)\n\t\t\t\tcontinue;\n\n\t\t\tif (!boost::equals(sb.name, \"cemu_meta\"))\n\t\t\t\tcontinue;\n\n\t\t\tauto* zip_file = zip_fopen_index(zip, i, 0);\n\t\t\tif (zip_file == nullptr)\n\t\t\t\tcontinue;\n\n\t\t\tauto buffer = std::make_unique<char[]>(sb.size);\n\t\t\tif (zip_fread(zip_file, buffer.get(), sb.size) == sb.size)\n\t\t\t{\n\t\t\t\tstd::string_view str{ buffer.get(), sb.size };\n\t\t\t\t// titleId = {:#016x}\n\t\t\t\tif(boost::starts_with(str, \"titleId = \"))\n\t\t\t\t{\n\t\t\t\t\tconst uint64_t titleId = ConvertString<uint64>(str.substr(sizeof(\"titleId = \") + 1), 16);\n\t\t\t\t\tif(titleId != 0 && titleId != m_title_id)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst auto msg = formatWxString(_(\"You are trying to import a savegame for a different title than your currently selected one: {:016x} vs {:016x}\\nAre you sure that you want to continue?\"), titleId, m_title_id);\n\t\t\t\t\t\tconst auto res = wxMessageBox(msg, _(\"Error\"), wxYES_NO | wxCENTRE | wxICON_WARNING, this);\n\t\t\t\t\t\tif(res == wxNO)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tm_return_code = wxCANCEL;\n\t\t\t\t\t\t\tClose();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tzip_fclose(zip_file);\n\n\t\t\tbreak;\n\t\t}\n\n\t\tzip_close(zip);\n\t}\n\n\t// unzip to tmp folder -> using target path directly now\n\tstd::error_code ec;\n\t//auto tmp_source = fs::temp_directory_path(ec);\n\t//if(ec)\n\t//{\n\t//\tconst auto error_msg = formatWxString(_(\"Error when getting the temp directory path:\\n{}\"), GetSystemErrorMessage(ec));\n\t//\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t//\treturn;\n\t//}\n\t\n\tuint32 target_id = 0;\n\tconst auto selection = m_target_selection->GetCurrentSelection();\n\tif (selection != wxNOT_FOUND)\n\t\ttarget_id = (uint32)(uintptr_t)m_target_selection->GetClientData(selection);\n\n\tif (target_id == 0)\n\t{\n\t\ttarget_id = ConvertString<uint32>(m_target_selection->GetValue().ToStdString(), 16);\n\t\tif (target_id < Account::kMinPersistendId)\n\t\t{\n\t\t\tconst auto msg = formatWxString(_(\"The given account id is not valid!\\nIt must be a hex number bigger or equal than {:08x}\"), Account::kMinPersistendId);\n\t\t\twxMessageBox(msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\treturn;\n\t\t}\n\n\t}\n\n\tfs::path target_path = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/user/{:08x}\", (uint32)(m_title_id >> 32), (uint32)(m_title_id & 0xFFFFFFFF), target_id);\n\tif (fs::exists(target_path))\n\t{\n\t\tif (!fs::is_directory(target_path))\n\t\t{\n\t\t\tconst auto msg = formatWxString(_(\"There's already a file at the target directory:\\n{}\"), _pathToUtf8(target_path));\n\t\t\twxMessageBox(msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\tm_return_code = wxCANCEL;\n\t\t\tClose();\n\t\t\treturn;\n\t\t}\n\n\t\tconst auto msg = _(\"There's already a save game available for the target account, do you want to overwrite it?\\nThis will delete the existing save files for the account and replace them.\");\n\t\tconst auto result = wxMessageBox(msg, _(\"Error\"), wxYES_NO | wxCENTRE | wxICON_WARNING, this);\n\t\tif (result == wxNO)\n\t\t{\n\t\t\tm_return_code = wxCANCEL;\n\t\t\tClose();\n\t\t\treturn;\n\t\t}\n\n\t\tstd::error_code ec;\n\t\twhile (fs::exists(target_path, ec) || ec)\n\t\t{\n\t\t\tfs::remove_all(target_path, ec);\n\n\t\t\tif (ec)\n\t\t\t{\n\t\t\t\tconst auto error_msg = formatWxString(_(\"Error when trying to delete the former save game:\\n{}\"), GetSystemErrorMessage(ec));\n\t\t\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE, this);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t\t}\n\t}\n\n\t// extract zip file\n\n\t//tmp_source.append(\"Cemu\").append(fmt::format(\"{}\", rand()));\n\n\t//tmp_source = getMlcPath(L\"usr/save\");\n\t//tmp_source /= fmt::format(\"{:08x}/{:08x}/user/{:08x}_tmp\", (uint32)(m_title_id >> 32), (uint32)(m_title_id & 0xFFFFFFFF), target_id);\n\tauto tmp_source = target_path;\n\t\n\tfs::create_directories(tmp_source, ec);\n\tif (ec)\n\t{\n\t\tconst auto error_msg = formatWxString(_(\"Error when creating the extraction path:\\n{}\"), GetSystemErrorMessage(ec));\n\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\tzip = zip_open(zipfile.c_str(), ZIP_RDONLY, &ziperr);\n\tif (!zip)\n\t{\n\t\tconst auto error_msg = formatWxString(_(\"Error when opening the import zip file:\\n{}\"), GetSystemErrorMessage(ec));\n\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\tsint32 numEntries = zip_get_num_entries(zip, 0);\n\tfor (sint32 i = 0; i < numEntries; i++)\n\t{\n\t\tzip_stat_t sb{};\n\t\tif (zip_stat_index(zip, i, 0, &sb) != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"zip stat index failed on {} entry\", i);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (boost::starts_with(sb.name, \"../\") || boost::starts_with(sb.name, \"..\\\\\"))\n\t\t\tcontinue; // bad path\n\n\t\tif (boost::equals(sb.name, \"cemu_meta\"))\n\t\t\tcontinue;\n\n\t\tsize_t sb_name_len = strlen(sb.name);\n\t\tif (sb_name_len == 0)\n\t\t\tcontinue;\n\n\t\tconst auto path = fs::path(tmp_source).append(sb.name);\n\t\tif (sb.name[sb_name_len - 1] == '/')\n\t\t{\n\t\t\tfs::create_directories(path, ec);\n\t\t\tif (ec)\n\t\t\t\tcemuLog_log(LogType::Force, \"can't create directory {}: {}\", sb.name, ec.message());\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (sb.size == 0)\n\t\t\tcontinue;\n\n\t\tif (sb.size > (1024 * 1024 * 128))\n\t\t\tcontinue; // skip unusually huge files\n\n\t\tauto* zip_file = zip_fopen_index(zip, i, 0);\n\t\tif (zip_file == nullptr)\n\t\t\tcontinue;\n\n\t\tauto buffer = std::make_unique<char[]>(sb.size);\n\t\tif (zip_fread(zip_file, buffer.get(), sb.size) == sb.size)\n\t\t{\n\t\t\tstd::ofstream file(path, std::ios::out | std::ios::binary);\n\t\t\tif (file.is_open())\n\t\t\t\tfile.write(buffer.get(), sb.size);\n\t\t}\n\n\t\tzip_fclose(zip_file);\n\t}\n\n\tzip_close(zip);\n\t// extracted all files to tmp_source\n\n\t// edit meta saveinfo.xml\n\tfs::path saveinfo = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/meta/saveinfo.xml\", (uint32)(m_title_id >> 32), (uint32)(m_title_id & 0xFFFFFFFF));\n\tif (fs::exists(saveinfo) || fs::is_regular_file(saveinfo))\n\t{\n\t\tpugi::xml_document doc;\n\t\tif (doc.load_file(saveinfo.c_str()))\n\t\t{\n\t\t\tauto info_node = doc.child(\"info\");\n\t\t\tif (info_node)\n\t\t\t{\n\t\t\t\t// delete old node if available\n\t\t\t\tauto old_persistend_id_string = fmt::format(\"{:08x}\", target_id);\n\t\t\t\tconst auto node_entry = info_node.find_child([&old_persistend_id_string](const pugi::xml_node& node)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn boost::iequals(node.attribute(\"persistentId\").as_string(), old_persistend_id_string);\n\t\t\t\t\t});\n\t\t\t\t// add save-entry node if not available yet\n\t\t\t\tif (!node_entry)\n\t\t\t\t{\n\t\t\t\t\t// add new node \n\t\t\t\t\tauto new_persistend_id_string = fmt::format(\"{:08x}\", target_id);\n\t\t\t\t\tauto new_node = info_node.append_child(\"account\");\n\t\t\t\t\tnew_node.append_attribute(\"persistentId\").set_value(new_persistend_id_string.c_str());\n\t\t\t\t\tauto timestamp = new_node.append_child(\"timestamp\");\n\t\t\t\t\ttimestamp.text().set(fmt::format(\"{:016x}\", coreinit::OSGetTime() / ESPRESSO_TIMER_CLOCK).c_str()); // TODO time not initialized yet?\n\t\t\t\t\t\n\t\t\t\t\tif(!doc.save_file(saveinfo.c_str()))\n\t\t\t\t\t\tcemuLog_log(LogType::Force, \"couldn't insert save entry in saveinfo.xml: {}\", _pathToUtf8(saveinfo));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} // todo create saveinfo if doesnt exist\n\n\t\n\t/*wxMessageBox(fmt::format(\"{}\\n{}\", tmp_source.generic_u8string(), target_path.generic_u8string()), _(\"Error\"), wxOK | wxCENTRE, this);\n\n\tfs::rename(tmp_source, target_path, ec);\n\tif (ec)\n\t{\n\t\tconst auto error_msg = formatWxString(_(\"Error when trying to move the extracted save game:\\n{}\"), GetSystemErrorMessage(ec));\n\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE, this);\n\t\treturn;\n\t}*/\n\n\tm_target_id = target_id;\n\tm_return_code = wxOK;\n\tClose();\n}\n"
  },
  {
    "path": "src/gui/wxgui/dialogs/SaveImport/SaveImportWindow.h",
    "content": "#pragma once\n\n#include <wx/dialog.h>\n\nclass SaveImportWindow : public wxDialog\n{\npublic:\n\tSaveImportWindow(wxWindow* parent, uint64 title_id);\n\n\tvoid EndModal(int retCode) override;\n\n\tuint32 GetTargetPersistentId() const { return m_target_id; }\nprivate:\n\tvoid OnImport(wxCommandEvent& event);\n\n\tclass wxFilePickerCtrl* m_source_selection;\n\tclass wxComboBox* m_target_selection;\n\n\tuint32 m_target_id = 0;\n\tconst uint64 m_title_id;\n\tconst fs::path m_source_file;\n\tint m_return_code = wxCANCEL;\n};\n\n\n"
  },
  {
    "path": "src/gui/wxgui/dialogs/SaveImport/SaveTransfer.cpp",
    "content": "#include \"SaveTransfer.h\"\n\n#include \"pugixml.hpp\"\n#include <wx/sizer.h>\n#include <wx/choice.h>\n#include <wx/combobox.h>\n#include <wx/stattext.h>\n#include <wx/button.h>\n#include <wx/frame.h>\n#include <wx/msgdlg.h>\n\n#include \"Cafe/Account/Account.h\"\n#include \"config/ActiveSettings.h\"\n#include \"util/helpers/helpers.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n\nSaveTransfer::SaveTransfer(wxWindow* parent, uint64 title_id, const wxString& source_account, uint32 source_id)\n: wxDialog(parent, wxID_ANY, _(\"Save transfer\"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxFRAME_TOOL_WINDOW | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX),\n\tm_title_id(title_id), m_source_id(source_id)\n{\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\t{\n\t\tauto* row1 = new wxFlexGridSizer(0, 2, 0, 0);\n\t\trow1->AddGrowableCol(1);\n\n\t\trow1->Add(new wxStaticText(this, wxID_ANY, _(\"Source\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tauto* source_choice = new wxChoice(this, wxID_ANY);\n\t\tsource_choice->SetMinSize({170, -1});\n\t\tsource_choice->Append(source_account);\n\t\tsource_choice->SetSelection(0);\n\t\trow1->Add(source_choice, 1, wxALL | wxEXPAND, 5);\n\n\t\trow1->Add(new wxStaticText(this, wxID_ANY, _(\"Target\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tconst auto& accounts = Account::GetAccounts();\n\t\tm_target_selection = new wxComboBox(this, wxID_ANY);\n\t\tfor (const auto& account : accounts)\n\t\t{\n\t\t\tif (account.GetPersistentId() == m_source_id)\n\t\t\t\tcontinue;\n\n\t\t\tm_target_selection->Append(fmt::format(\"{:x} ({})\", account.GetPersistentId(),\n\t\t\t                           boost::nowide::narrow(account.GetMiiName().data(), account.GetMiiName().size())),\n\t\t\t               (void*)(uintptr_t)account.GetPersistentId());\n\t\t}\n\t\trow1->Add(m_target_selection, 1, wxALL | wxEXPAND, 5);\n\n\t\tsizer->Add(row1, 0, wxEXPAND, 5);\n\t}\n\n\t{\n\t\tauto* row2 = new wxFlexGridSizer(0, 2, 0, 0);\n\t\trow2->AddGrowableCol(1);\n\t\trow2->SetFlexibleDirection(wxBOTH);\n\t\trow2->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);\n\n\t\tauto* ok_button = new wxButton(this, wxID_ANY, _(\"OK\"));\n\t\tok_button->Bind(wxEVT_BUTTON, &SaveTransfer::OnTransfer, this);\n\t\trow2->Add(ok_button, 0, wxALL, 5);\n\n\t\tauto* cancel_button = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\t\tcancel_button->Bind(wxEVT_BUTTON, [this](auto&)\n\t\t{\n\t\t\tm_return_code = wxCANCEL;\n\t\t\tClose();\n\t\t});\n\t\trow2->Add(cancel_button, 0, wxALIGN_RIGHT | wxALL, 5);\n\n\t\tsizer->Add(row2, 1, wxEXPAND, 5);\n\t}\n\n\tthis->SetSizerAndFit(sizer);\n\tthis->Centre(wxBOTH);\n}\n\nvoid SaveTransfer::EndModal(int retCode)\n{\n\twxDialog::EndModal(retCode);\n\tSetReturnCode(m_return_code);\n}\n\nvoid SaveTransfer::OnTransfer(wxCommandEvent& event)\n{\n\tuint32 target_id = 0;\n\tconst auto selection = m_target_selection->GetCurrentSelection();\n\tif(selection != wxNOT_FOUND)\n\t\ttarget_id = (uint32)(uintptr_t)m_target_selection->GetClientData(selection);\n\t\t\n\tif (target_id == 0)\n\t{\n\t\ttarget_id = ConvertString<uint32>(m_target_selection->GetValue().ToStdString(), 16);\n\t\tif(target_id < Account::kMinPersistendId)\n\t\t{\n\t\t\tconst auto msg = formatWxString(_(\"The given account id is not valid!\\nIt must be a hex number bigger or equal than {:08x}\"), Account::kMinPersistendId);\n\t\t\twxMessageBox(msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\treturn;\n\t\t}\n\t\t\t\n\t}\n\t\n\tconst fs::path source_path = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/user/{:08x}\", (uint32)(m_title_id >> 32), (uint32)(m_title_id & 0xFFFFFFFF), m_source_id);\n\tif (!fs::exists(source_path) || !fs::is_directory(source_path))\n\t\treturn;\n\t\n\tconst fs::path target_path = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/user/{:08x}\", (uint32)(m_title_id >> 32), (uint32)(m_title_id & 0xFFFFFFFF), target_id);\n\tif (fs::exists(target_path))\n\t{\n\t\tif(!fs::is_directory(target_path))\n\t\t{\n\t\t\tconst auto msg = formatWxString(_(\"There's already a file at the target directory:\\n{}\"), _pathToUtf8(target_path));\n\t\t\twxMessageBox(msg, _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\tm_return_code = wxCANCEL;\n\t\t\tClose();\n\t\t\treturn;\n\t\t}\n\n\t\tconst auto msg = _(\"There's already a save game available for the target account, do you want to overwrite it?\\nThis will delete the existing save files for the account and replace them.\");\n\t\tconst auto result = wxMessageBox(msg, _(\"Error\"), wxYES_NO | wxCENTRE | wxICON_WARNING, this);\n\t\tif(result == wxNO)\n\t\t{\n\t\t\tm_return_code = wxCANCEL;\n\t\t\tClose();\n\t\t\treturn;\n\t\t}\n\n\t\tstd::error_code ec;\n\t\twhile (fs::exists(target_path, ec) || ec)\n\t\t{\n\t\t\tfs::remove_all(target_path, ec);\n\n\t\t\tif (ec)\n\t\t\t{\n\t\t\t\tconst auto error_msg = formatWxString(_(\"Error when trying to delete the former save game:\\n{}\"), GetSystemErrorMessage(ec));\n\t\t\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE, this);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// wait so filesystem doesnt \n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(100));\n\t\t}\n\t}\n\n\t// edit meta saveinfo.xml\n\tbool meta_file_edited = false;\n\tconst fs::path saveinfo = ActiveSettings::GetMlcPath(\"usr/save/{:08x}/{:08x}/meta/saveinfo.xml\", (uint32)(m_title_id >> 32), (uint32)(m_title_id & 0xFFFFFFFF));\n\tif (fs::exists(saveinfo) || fs::is_regular_file(saveinfo))\n\t{\n\t\tpugi::xml_document doc;\n\t\tif (doc.load_file(saveinfo.c_str()))\n\t\t{\n\t\t\tauto info_node = doc.child(\"info\");\n\t\t\tif (info_node)\n\t\t\t{\n\t\t\t\t// delete old node if available\n\t\t\t\tauto old_persistend_id_string = fmt::format(\"{:08x}\", target_id);\n\t\t\t\tconst auto delete_entry = info_node.find_child([&old_persistend_id_string](const pugi::xml_node& node)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn boost::iequals(node.attribute(\"persistentId\").as_string(), old_persistend_id_string);\n\t\t\t\t\t});\n\t\t\t\tif (delete_entry)\n\t\t\t\t\tinfo_node.remove_child(delete_entry);\n\t\t\t\t\t\n\n\t\t\t\t// move new node \n\t\t\t\tauto new_persistend_id_string = fmt::format(\"{:08x}\", m_source_id);\n\t\t\t\tauto move_entry = info_node.find_child([&new_persistend_id_string](const pugi::xml_node& node)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn boost::iequals(node.attribute(\"persistentId\").as_string(), new_persistend_id_string);\n\t\t\t\t\t});\n\t\t\t\tif(move_entry)\n\t\t\t\t\tmove_entry.attribute(\"persistentId\").set_value(old_persistend_id_string.c_str());\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// TODO: create if not found! (shouldnt happen though)\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tmeta_file_edited = doc.save_file(saveinfo.c_str());\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!meta_file_edited)\n\t\tcemuLog_log(LogType::Force, \"SaveTransfer::OnTransfer: couldn't update save entry in saveinfo.xml: {}\", _pathToUtf8(saveinfo));\n\n\tstd::error_code ec;\n\tfs::rename(source_path, target_path, ec);\n\tif (ec)\n\t{\n\t\tconst auto error_msg = formatWxString(_(\"Error when trying to move the save game:\\n{}\"), GetSystemErrorMessage(ec));\n\t\twxMessageBox(error_msg, _(\"Error\"), wxOK | wxCENTRE, this);\n\t\treturn;\n\t}\n\n\tm_target_id = target_id;\n\tm_return_code = wxOK;\n\tClose();\n}\n"
  },
  {
    "path": "src/gui/wxgui/dialogs/SaveImport/SaveTransfer.h",
    "content": "#pragma once\n\n#include <wx/dialog.h>\n\nclass wxComboBox;\n\nclass SaveTransfer : public wxDialog\n{\npublic:\n\tSaveTransfer(wxWindow* parent, uint64 title_id, const wxString& source_account, uint32 source_id);\n\n\tvoid EndModal(int retCode) override;\n\n\tuint32 GetTargetPersistentId() const { return m_target_id; }\nprivate:\n\tvoid OnTransfer(wxCommandEvent& event);\n\n\twxComboBox* m_target_selection;\n\n\tuint32 m_target_id = 0;\n\tconst uint64 m_title_id;\n\tconst uint32 m_source_id;\n\tint m_return_code = wxCANCEL;\n};\n"
  },
  {
    "path": "src/gui/wxgui/helpers/wxControlObject.h",
    "content": "#pragma once\n\n#include <wx/control.h>\n\nclass wxControlObject : public wxObject\n{\npublic:\n\twxControlObject(wxControl* control)\n\t\t: m_control(control) {}\n\n\ttemplate<typename T>\n\tT* GetControl() const\n\t{\n\t\tstatic_assert(std::is_base_of_v<wxControl, T>, \"T must inherit from wxControl\");\n\t\treturn dynamic_cast<T*>(m_control);\n\t}\n\n\twxControl* GetControl() const { return m_control; }\n\nprivate:\n\twxControl* m_control;\n};\n\nclass wxControlObjects : public wxObject\n{\npublic:\n\twxControlObjects(std::vector<wxControl*> controls)\n\t\t: m_controls(std::move(controls)) {}\n\n\ttemplate<typename T = wxControl>\n\tT* GetControl(int index) const\n\t{\n\t\tstatic_assert(std::is_base_of_v<wxControl, T>, \"T must inherit from wxControl\");\n\t\tif (index < 0 || index >= m_controls.size())\n\t\t\treturn nullptr;\n\t\t\n\t\treturn dynamic_cast<T*>(m_controls[index]);\n\t}\n\n\tconst std::vector<wxControl*>& GetControls() const { return m_controls; }\n\nprivate:\n\tstd::vector<wxControl*> m_controls;\n};\n"
  },
  {
    "path": "src/gui/wxgui/helpers/wxCustomData.h",
    "content": "#pragma once\n\n#include <wx/clntdata.h>\n\ntemplate <typename T>\nclass wxCustomData : public wxClientData\n{\npublic:\n\twxCustomData()\n\t\t:  m_data({}) {}\n\n\twxCustomData(T data)\n\t\t:  m_data(std::move(data)) { }\n\t\n\tconst T& GetData() const { return m_data; }\n\n\t/// <summary>\n\t/// obtains ownership of the data\n\t/// </summary>\n\t/// <returns>returns the stored data</returns>\n\tT get() { return std::move(m_data); }\n\n\t/// <summary>\n\t/// access to the data without obtaining ownership\n\t/// </summary>\n\t/// <returns>returns a reference to the stored data</returns>\n\tT& ref() { return m_data; }\n\n\tbool operator==(const T& o) const { return m_data == o.m_data; }\n\tbool operator!=(const T& o) const { return !(*this == o); }\n\nprivate:\n\tT m_data;\n};\n\n//template <typename T>\n//class wxCustomObject : public wxObject\n//{\n//public:\n//\twxCustomObject(T data)\n//\t\t:  m_data(std::move(data)) { }\n//\n//\tconst T& GetData() const { return m_data; }\n//\n//\tbool operator==(const T& o) const { return m_data == o.m_data; }\n//\tbool operator!=(const T& o) const { return !(*this == o); }\n//private:\n//\tT m_data;\n//};\n"
  },
  {
    "path": "src/gui/wxgui/helpers/wxCustomEvents.cpp",
    "content": "#include \"wxgui/helpers/wxCustomEvents.h\"\n\nwxDEFINE_EVENT(wxEVT_SET_STATUS_BAR_TEXT, wxSetStatusBarTextEvent);\nwxDEFINE_EVENT(wxEVT_SET_GAUGE_VALUE, wxSetGaugeValue);\nwxDEFINE_EVENT(wxEVT_REMOVE_ITEM, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_SET_TEXT, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_ENABLE, wxCommandEvent);"
  },
  {
    "path": "src/gui/wxgui/helpers/wxCustomEvents.h",
    "content": "#pragma once\n\n#include <wx/event.h>\n#include <wx/gauge.h>\n\nclass wxStatusBar;\nclass wxControl;\n\nwxDECLARE_EVENT(wxEVT_REMOVE_ITEM, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_SET_TEXT, wxCommandEvent);\nwxDECLARE_EVENT(wxEVT_ENABLE, wxCommandEvent);\n\nclass wxSetStatusBarTextEvent;\nwxDECLARE_EVENT(wxEVT_SET_STATUS_BAR_TEXT, wxSetStatusBarTextEvent);\nclass wxSetStatusBarTextEvent : public wxCommandEvent\n{\npublic:\n\twxSetStatusBarTextEvent(const wxString& text, int number = 0, wxEventType type = wxEVT_SET_STATUS_BAR_TEXT, int id = 0)\n\t\t: wxCommandEvent(type, id), m_text(text), m_number(number) {}\n\n\twxSetStatusBarTextEvent(const wxSetStatusBarTextEvent& event)\n\t\t: wxCommandEvent(event), m_text(event.GetText()), m_number(event.GetNumber()) {}\n\n\n\t[[nodiscard]] const wxString& GetText() const { return m_text; }\n\t[[nodiscard]] int GetNumber() const { return m_number; }\n\n\twxEvent* Clone() const override\n\t{\n\t\treturn new wxSetStatusBarTextEvent(*this);\n\t}\n\nprivate:\n\tconst wxString m_text;\n\tconst int m_number;\n};\nclass wxSetGaugeValue;\nwxDECLARE_EVENT(wxEVT_SET_GAUGE_VALUE, wxSetGaugeValue);\nclass wxSetGaugeValue : public wxCommandEvent\n{\npublic:\n\twxSetGaugeValue(int value, wxGauge* gauge, wxControl* text_ctrl = nullptr, const wxString& text = wxEmptyString, wxEventType type = wxEVT_SET_GAUGE_VALUE, int id = 0)\n\t\t: wxCommandEvent(type, id), m_gauge_value(value), m_gauge_range(0), m_text_ctrl(text_ctrl), m_text(text)\n\t{\n\t\tSetEventObject(gauge);\n\t}\n\t\n\twxSetGaugeValue(int value, int range, wxGauge* gauge, wxControl* text_ctrl = nullptr, const wxString& text = wxEmptyString, wxEventType type = wxEVT_SET_GAUGE_VALUE, int id = 0)\n\t\t: wxCommandEvent(type, id), m_gauge_value(value), m_gauge_range(range), m_text_ctrl(text_ctrl), m_text(text)\n\t{\n\t\tSetEventObject(gauge);\n\t}\n\n\twxSetGaugeValue(const wxSetGaugeValue& event)\n\t\t: wxCommandEvent(event), m_gauge_value(event.GetValue()), m_gauge_range(event.GetRange()), m_text_ctrl(event.GetTextCtrl()), m_text(event.GetText())\n\t{}\n\n\t[[nodiscard]] int GetValue() const { return m_gauge_value; }\n\t[[nodiscard]] int GetRange() const { return m_gauge_range; }\n\t[[nodiscard]] wxGauge* GetGauge() const { return (wxGauge*)GetEventObject(); }\n\t[[nodiscard]] const wxString& GetText() const { return m_text; }\n\t[[nodiscard]] wxControl* GetTextCtrl() const { return m_text_ctrl; }\n\n\twxEvent* Clone() const override\n\t{\n\t\treturn new wxSetGaugeValue(*this);\n\t}\n\nprivate:\n\tconst int m_gauge_value, m_gauge_range;\n\twxControl* m_text_ctrl;\n\tconst wxString m_text;\n};\n\n"
  },
  {
    "path": "src/gui/wxgui/helpers/wxHelpers.cpp",
    "content": "#include \"wxgui/helpers/wxHelpers.h\"\n\n#include <wx/wupdlock.h>\n#include <wx/stattext.h>\n#include <wx/slider.h>\n#include <wx/dirdlg.h>\n\n#if BOOST_OS_LINUX || BOOST_OS_BSD\n#include <gtk/gtk.h>\n#include <gdk/gdk.h>\n#include <gdk/gdkwindow.h>\n#include <gdk/gdkx.h>\n#ifdef HAS_WAYLAND\n#include <gdk/gdkwayland.h>\n#endif\n#endif\n\n#include \"wxgui/helpers/wxControlObject.h\"\n\nvoid wxAutosizeColumn(wxListCtrlBase* ctrl, int col)\n{\n\tctrl->SetColumnWidth(col, wxLIST_AUTOSIZE_USEHEADER);\n\tint wh = ctrl->GetColumnWidth(col);\n\tctrl->SetColumnWidth(col, wxLIST_AUTOSIZE);\n\tint wc = ctrl->GetColumnWidth(col);\n\tif (wh > wc)\n\tctrl->SetColumnWidth(col, wxLIST_AUTOSIZE_USEHEADER);\n}\n\nvoid wxAutosizeColumns(wxListCtrlBase* ctrl, int col_start, int col_end)\n{\n\twxWindowUpdateLocker lock(ctrl);\n\tfor (int i = col_start; i <= col_end; ++i)\n\t\twxAutosizeColumn(ctrl, i);\n}\n\nvoid update_slider_text(wxCommandEvent& event, const wxFormatString& format /*= \"%d%%\"*/)\n{\n\tconst auto slider = dynamic_cast<wxSlider*>(event.GetEventObject());\n\twxASSERT(slider);\n\n\tauto slider_text = dynamic_cast<wxControlObject*>(event.GetEventUserData())->GetControl<wxStaticText>();\n\twxASSERT(slider_text);\n\n\tslider_text->SetLabel(wxString::Format(format, slider->GetValue()));\n}\n\nuint32 fix_raw_keycode(uint32 keycode, uint32 raw_flags)\n{\n#if BOOST_OS_WINDOWS\n\tconst auto flags = (HIWORD(raw_flags) & 0xFFF);\n\tif(keycode == VK_SHIFT)\n\t{\n\t\tif(flags == 0x2A)\n\t\t\treturn 160;\n\t\telse if (flags == 0x36)\n\t\t\treturn 161;\n\t}\n\telse if (keycode == VK_CONTROL)\n\t{\n\t\tif (flags == 0x1d)\n\t\t\treturn 162;\n\t\telse if (flags == 0x11d)\n\t\t\treturn 163;\n\t}\n\telse if (keycode == VK_MENU)\n\t{\n\t\tif ((flags & 0xFF) == 0x38)\n\t\t\treturn 164;\n\t\telse if ((flags & 0xFF) == 0x38)\n\t\t\treturn 165;\n\t}\n#endif\n\n\treturn keycode;\n}\n\nWindowSystem::WindowHandleInfo initHandleContextFromWxWidgetsWindow(wxWindow* wxw)\n{\n\tWindowSystem::WindowHandleInfo handleInfo;\n#if BOOST_OS_WINDOWS\n\thandleInfo.backend = WindowSystem::WindowHandleInfo::Backend::Windows;\n\thandleInfo.surface = reinterpret_cast<void*>(wxw->GetHWND());\n#elif BOOST_OS_LINUX || BOOST_OS_BSD\n\tGtkWidget* gtkWidget = (GtkWidget*)wxw->GetHandle(); // returns GtkWidget\n\tgtk_widget_realize(gtkWidget);\n\tGdkWindow* gdkWindow = gtk_widget_get_window(gtkWidget);\n\tGdkDisplay* gdkDisplay = gdk_window_get_display(gdkWindow);\n\tif (GDK_IS_X11_WINDOW(gdkWindow))\n\t{\n\t\thandleInfo.backend = WindowSystem::WindowHandleInfo::Backend::X11;\n\t\thandleInfo.surface = reinterpret_cast<void*>(gdk_x11_window_get_xid(gdkWindow));\n\t\thandleInfo.display = gdk_x11_display_get_xdisplay(gdkDisplay);\n\t\tif (!handleInfo.display)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Unable to get xlib display\");\n\t\t}\n\t}\n#ifdef HAS_WAYLAND\n\telse if (GDK_IS_WAYLAND_WINDOW(gdkWindow))\n\t{\n\t\thandleInfo.backend = WindowSystem::WindowHandleInfo::Backend::Wayland;\n\t\thandleInfo.surface = gdk_wayland_window_get_wl_surface(gdkWindow);\n\t\thandleInfo.display = gdk_wayland_display_get_wl_display(gdkDisplay);\n\t}\n#endif\n\telse\n\t{\n\t\tcemuLog_log(LogType::Force, \"Unsuported GTK backend\");\n\t}\n#elif BOOST_OS_MACOS\n\thandleInfo.backend = WindowSystem::WindowHandleInfo::Backend::Cocoa;\n\thandleInfo.surface = reinterpret_cast<void*>(wxw->GetHandle());\n#endif\n\treturn handleInfo;\n}\n"
  },
  {
    "path": "src/gui/wxgui/helpers/wxHelpers.h",
    "content": "#pragma once\n\n#include \"interface/WindowSystem.h\"\n#include <wx/control.h>\n#include <wx/listbase.h>\n#include <wx/string.h>\n\ntemplate <>\nstruct fmt::formatter<wxString> : formatter<string_view>\n{\n\ttemplate <typename FormatContext>\n\tauto format(const wxString& str, FormatContext& ctx) const\n\t{\n\t\treturn formatter<string_view>::format(str.ToStdString(), ctx);\n\t}\n};\n\nclass wxTempEnable\n{\npublic:\n\twxTempEnable(wxControl* control, bool state = true)\n\t\t: m_control(control), m_state(state)\n\t{\n\t\tm_control->Enable(m_state);\n\t}\n\n\twxTempEnable(const wxTempEnable&) = delete;\n\twxTempEnable(wxTempEnable&&) noexcept = default;\n\n\t~wxTempEnable()\n\t{\n\t\tif(m_control)\n\t\t\tm_control->Enable(!m_state);\n\t}\n\nprivate:\n\twxControl* m_control;\n\tconst bool m_state;\n};\n\nclass wxTempDisable : wxTempEnable\n{\npublic:\n\twxTempDisable(wxControl* control)\n\t\t: wxTempEnable(control, false) {}\n};\n\ntemplate<typename ...TArgs>\nwxString formatWxString(const wxString& format, TArgs&&...args)\n{\n\treturn wxString::FromUTF8(fmt::format(fmt::runtime(format.utf8_string()), std::forward<TArgs>(args)...));\n}\n\n// executes a function when destroying the obj\ntemplate<typename TFunction, typename ...TArgs>\nclass wxDTorFunc\n{\npublic:\n\twxDTorFunc(TFunction&& func, TArgs&&... args)\n\t{\n\t\tauto bound = std::bind(std::forward<TFunction>(func), std::forward<TArgs>(args)...);\n\t\t// m_function = [bound] { bound(); };\n\t\tm_function = [bound{ std::move(bound) }]{ bound(); };\n\t\t\n\t}\n\t~wxDTorFunc()\n\t{\n\t\tm_function();\n\t}\nprivate:\n\tstd::function<void()> m_function;\n};\n\nvoid wxAutosizeColumn(wxListCtrlBase* ctrl, int col);\nvoid wxAutosizeColumns(wxListCtrlBase* ctrl, int col_start, int col_end);\n\ntemplate <typename T>\nT get_next_sibling(const T element)\n{\n\tstatic_assert(std::is_pointer_v<T> && std::is_base_of_v<wxControl, std::remove_pointer_t<T>>, \"element must be a pointer and inherit from wxControl\");\n\tfor (auto sibling = element->GetNextSibling(); sibling; sibling = sibling->GetNextSibling())\n\t{\n\t\tif (auto result = dynamic_cast<T>(sibling))\n\t\t\treturn result;\n\t}\n\n\treturn nullptr;\n}\n\ntemplate <typename T>\nT get_prev_sibling(const T element)\n{\n\tstatic_assert(std::is_pointer_v<T> && std::is_base_of_v<wxControl, std::remove_pointer_t<T>>, \"element must be a pointer and inherit from wxControl\");\n\tfor (auto sibling = element->GetPrevSibling(); sibling; sibling = sibling->GetPrevSibling())\n\t{\n\t\tauto result = dynamic_cast<T>(sibling);\n\t\tif (result)\n\t\t\treturn result;\n\t}\n\n\treturn nullptr;\n}\n\nvoid update_slider_text(wxCommandEvent& event, const wxFormatString& format = \"%d%%\");\n\nuint32 fix_raw_keycode(uint32 keycode, uint32 raw_flags);\n\nWindowSystem::WindowHandleInfo initHandleContextFromWxWidgetsWindow(wxWindow* wxw);\n"
  },
  {
    "path": "src/gui/wxgui/helpers/wxLogEvent.h",
    "content": "#pragma once\n\n#include <wx/event.h>\n\nclass wxLogEvent;\nwxDECLARE_EVENT(EVT_LOG, wxLogEvent);\n\nclass wxLogEvent : public wxCommandEvent\n{\npublic:\n\twxLogEvent(const wxString& filter, const wxString& message) \n\t\t: wxCommandEvent(EVT_LOG), m_filter(filter), m_message(message) { }\n\n\twxLogEvent(const wxLogEvent& event)\n\t\t:  wxCommandEvent(event), m_filter(event.GetFilter()), m_message(event.GetMessage()) { }\n\n\twxEvent* Clone() const { return new wxLogEvent(*this); }\n\n\t[[nodiscard]] const wxString& GetFilter() const\n\t{\n\t\treturn m_filter;\n\t}\n\n\t[[nodiscard]] const wxString& GetMessage() const\n\t{\n\t\treturn m_message;\n\t}\n\nprivate:\n\twxString m_filter;\n\twxString m_message;\n};\n"
  },
  {
    "path": "src/gui/wxgui/helpers/wxWayland.cpp",
    "content": "#include \"wxgui/helpers/wxWayland.h\"\n\n#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND\n\n#include <dlfcn.h>\n\nbool wxWlIsWaylandWindow(wxWindow* window)\n{\n\tGtkWidget* gtkWindow = static_cast<GtkWidget*>(window->GetHandle());\n\tGdkWindow* gdkWindow = gtk_widget_get_window(gtkWindow);\n\treturn GDK_IS_WAYLAND_WINDOW(gdkWindow);\n}\n\nvoid wxWlSetAppId(wxFrame* frame, const char* applicationId)\n{\n\tGtkWidget* gtkWindow = static_cast<GtkWidget*>(frame->GetHandle());\n\tgtk_widget_realize(gtkWindow);\n\tGdkWindow* gdkWindow = gtk_widget_get_window(gtkWindow);\n\tstatic auto gdk_wl_set_app_id = reinterpret_cast<void (*) (GdkWindow*, const char*)>(dlsym(nullptr, \"gdk_wayland_window_set_application_id\"));\n\tif (gdk_wl_set_app_id)\n\t\tgdk_wl_set_app_id(gdkWindow, applicationId);\n}\n\n#endif\t// BOOST_OS_LINUX && HAS_WAYLAND\n"
  },
  {
    "path": "src/gui/wxgui/helpers/wxWayland.h",
    "content": "#pragma once\n\n#if ( BOOST_OS_LINUX || BOOST_OS_BSD ) && HAS_WAYLAND\n\n#include <gdk/gdk.h>\n#include <gdk/gdkwayland.h>\n#include <gtk/gtk.h>\n#include <wayland-client.h>\n#include <wx/wx.h>\n#include \"wayland-viewporter-client-protocol.h\"\n\nclass wxWlSubsurface\n{\n\tstatic void registry_add_object(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)\n\t{\n\t\tauto wlSubsurface = static_cast<wxWlSubsurface*>(data);\n\n\t\tif (!strcmp(interface, wl_subcompositor_interface.name))\n\t\t{\n\t\t\twlSubsurface->m_subcompositor = static_cast<wl_subcompositor*>(wl_registry_bind(registry, name, &wl_subcompositor_interface, 1));\n\t\t}\n\t\telse if (!strcmp(interface, wp_viewporter_interface.name))\n\t\t{\n\t\t\twlSubsurface->m_viewporter = static_cast<wp_viewporter*>(wl_registry_bind(registry, name, &wp_viewporter_interface, 1));\n\t\t}\n\t}\n\tstatic void registry_remove_object(void* /*data*/, struct wl_registry* /*registry*/, uint32_t /*name*/) {}\n\n\twl_registry_listener m_registry_listener = {&registry_add_object, &registry_remove_object};\n\twl_subcompositor* m_subcompositor;\n\twl_surface* m_surface;\n\twl_subsurface* m_subsurface;\n\twp_viewporter* m_viewporter = NULL;\n\twp_viewport* m_viewport = NULL;\n\tint32_t m_xPos = 0;\n\tint32_t m_yPos = 0;\n\tint32_t m_width = 0;\n\tint32_t m_height = 0;\n\npublic:\n\twxWlSubsurface(wxWindow* window)\n\t{\n\t\tGtkWidget* widget = static_cast<GtkWidget*>(window->GetHandle());\n\t\tgtk_widget_realize(widget);\n\t\tGdkWindow* gdkWindow = gtk_widget_get_window(widget);\n\t\tGdkDisplay* gdkDisplay = gdk_window_get_display(gdkWindow);\n\t\twl_display* display = gdk_wayland_display_get_wl_display(gdkDisplay);\n\t\twl_surface* surface = gdk_wayland_window_get_wl_surface(gdkWindow);\n\t\twl_compositor* compositor = gdk_wayland_display_get_wl_compositor(gdkDisplay);\n\t\twl_registry* registry = wl_display_get_registry(display);\n\t\twl_registry_add_listener(registry, &m_registry_listener, this);\n\t\twl_display_roundtrip(display);\n\t\tm_surface = wl_compositor_create_surface(compositor);\n\t\tif (m_viewporter)\n\t\t\tm_viewport = wp_viewporter_get_viewport(m_viewporter, m_surface);\n\t\twl_region* region = wl_compositor_create_region(compositor);\n\t\twl_surface_set_input_region(m_surface, region);\n\t\tm_subsurface = wl_subcompositor_get_subsurface(m_subcompositor, m_surface, surface);\n\t\twl_subsurface_set_desync(m_subsurface);\n\t\tauto sRect = window->GetScreenRect();\n\t\tsetSize(sRect.x, sRect.y, sRect.width, sRect.height);\n\t\twl_region_destroy(region);\n\t}\n\n\twl_surface* getSurface() const { return m_surface; }\n\n\tvoid setSize(int32_t xPos, int32_t yPos, int32_t width, int32_t height)\n\t{\n\t\tif (xPos != m_xPos || m_yPos != yPos || m_width != width || m_height != height)\n\t\t{\n\t\t\tm_xPos = xPos;\n\t\t\tm_yPos = yPos;\n\t\t\tm_height = height;\n\t\t\tm_width = width;\n\t\t\twl_subsurface_set_position(m_subsurface, m_xPos, m_yPos);\n\t\t\tif (m_viewport)\n\t\t\t\twp_viewport_set_destination(m_viewport, m_width, m_height);\n\t\t\twl_surface_commit(m_surface);\n\t\t}\n\t}\n\n\t~wxWlSubsurface()\n\t{\n\t\twl_subsurface_destroy(m_subsurface);\n\t\twl_surface_destroy(m_surface);\n\t\twl_subcompositor_destroy(m_subcompositor);\n\t}\n};\n\nbool wxWlIsWaylandWindow(wxWindow* window);\nvoid wxWlSetAppId(wxFrame* frame, const char* application_id);\n\n#endif\t// BOOST_OS_LINUX && HAS_WAYLAND\n"
  },
  {
    "path": "src/gui/wxgui/input/HotkeySettings.cpp",
    "content": "#include \"wxgui/input/HotkeySettings.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"interface/WindowSystem.h\"\n#include <config/ActiveSettings.h>\n#include \"input/InputManager.h\"\n#include \"HotkeySettings.h\"\n#include \"MainWindow.h\"\n\n#include <wx/app.h>\n#include <wx/clipbrd.h>\n\n#if BOOST_OS_WINDOWS\n#include <ole2.h>\n#endif\n\n#if BOOST_OS_LINUX || BOOST_OS_MACOS || BOOST_OS_BSD\n#include \"resource/embedded/resources.h\"\n#endif\n\nstd::optional<fs::path> GenerateScreenshotFilename(bool isDRC)\n{\n\tfs::path screendir = ActiveSettings::GetUserDataPath(\"screenshots\");\n\t// build screenshot name with format Screenshot_YYYY-MM-DD_HH-MM-SS[_GamePad].png\n\t// if the file already exists add a suffix counter (_2.png, _3.png etc)\n\tstd::time_t time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());\n\tstd::tm* tm = std::localtime(&time_t);\n\n\tstd::string screenshotFileName = fmt::format(\"Screenshot_{:04}-{:02}-{:02}_{:02}-{:02}-{:02}\", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);\n\tif (isDRC)\n\t\tscreenshotFileName.append(\"_GamePad\");\n\n\tfs::path screenshotPath;\n\tfor (sint32 i = 0; i < 999; i++)\n\t{\n\t\tscreenshotPath = screendir;\n\t\tif (i == 0)\n\t\t\tscreenshotPath.append(fmt::format(\"{}.png\", screenshotFileName));\n\t\telse\n\t\t\tscreenshotPath.append(fmt::format(\"{}_{}.png\", screenshotFileName, i + 1));\n\n\t\tstd::error_code ec;\n\t\tbool exists = fs::exists(screenshotPath, ec);\n\n\t\tif (!ec && !exists)\n\t\t\treturn screenshotPath;\n\t}\n\treturn std::nullopt;\n}\n\nbool SaveScreenshotToFile(const fs::path& imagePath, const wxImage& image)\n{\n\tstd::error_code ec;\n\tfs::create_directories(imagePath.parent_path(), ec);\n\tif (ec)\n\t\treturn false;\n\n\t// suspend wxWidgets logging for the lifetime this object, to prevent a message box if wxImage::SaveFile fails\n\twxLogNull _logNo;\n\treturn image.SaveFile(imagePath.wstring());\n}\n\nbool SaveScreenshotToClipboard(const wxImage& image)\n{\n\tstatic std::mutex s_clipboardMutex;\n\tbool success = false;\n\n\ts_clipboardMutex.lock();\n\tif (wxTheClipboard->Open())\n\t{\n\t\twxTheClipboard->SetData(new wxImageDataObject(image));\n\t\twxTheClipboard->Close();\n\t\tsuccess = true;\n\t}\n\ts_clipboardMutex.unlock();\n\n\treturn success;\n}\n\nstd::optional<std::string> SaveScreenshot(std::vector<uint8> data, int width, int height, bool mainWindow)\n{\n#if BOOST_OS_WINDOWS\n\t// on Windows wxWidgets uses OLE API for the clipboard\n\t// to make this work we need to call OleInitialize() on the same thread\n\tOleInitialize(nullptr);\n#endif\n\tbool save_screenshot = GetWxGUIConfig().save_screenshot;\n\twxImage image(width, height, data.data(), true);\n\tif (mainWindow)\n\t{\n\t\tif (SaveScreenshotToClipboard(image))\n\t\t{\n\t\t\tif (!save_screenshot)\n\t\t\t\treturn _tr(\"Screenshot saved to clipboard\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn _tr(\"Failed to open clipboard\");\n\t\t}\n\t}\n\tif (save_screenshot)\n\t{\n\t\tauto imagePath = GenerateScreenshotFilename(mainWindow);\n\t\tif (imagePath.has_value() && SaveScreenshotToFile(imagePath.value(), image))\n\t\t{\n\t\t\tif (mainWindow)\n\t\t\t\treturn _tr(\"Screenshot saved\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn _tr(\"Failed to save screenshot to file\");\n\t\t}\n\t}\n\treturn std::nullopt;\n}\n\nextern WindowSystem::WindowInfo g_window_info;\n\nstd::unordered_map<sHotkeyCfg*, std::function<void(void)>> HotkeySettings::s_cfgHotkeyToFuncMap;\n\nstruct HotkeyEntry\n{\n\tstd::unique_ptr<wxStaticText> name;\n\tstd::unique_ptr<wxButton> keyInput;\n\tstd::unique_ptr<wxButton> controllerInput;\n\tsHotkeyCfg& hotkey;\n\n\tHotkeyEntry(wxStaticText* name, wxButton* keyInput, wxButton* controllerInput, sHotkeyCfg& hotkey)\n\t\t: name(name), keyInput(keyInput), controllerInput(controllerInput), hotkey(hotkey)\n\t{\n\t\tkeyInput->SetClientData(&hotkey);\n\t\tcontrollerInput->SetClientData(&hotkey);\n\t}\n};\n\nHotkeySettings::HotkeySettings(wxWindow* parent)\n\t: wxFrame(parent, wxID_ANY, _(\"Hotkey Settings\"))\n{\n\tSetIcon(wxICON(X_HOTKEY_SETTINGS));\n\n\tm_sizer = new wxFlexGridSizer(0, 3, 5, 5);\n\tm_sizer->AddGrowableCol(1);\n\tm_sizer->AddGrowableCol(2);\n\n\tm_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_THEME);\n\tm_panel->SetSizer(m_sizer);\n\n\tCenter();\n\n\tSetActiveController();\n\n\tCreateColumnHeaders();\n\n\t/* global modifier */\n\tCreateHotkeyRow(_tr(\"Hotkey modifier\"), s_cfgHotkeys.modifiers);\n\tm_hotkeys.at(0).keyInput->Hide();\n\n\t/* hotkeys */\n\tCreateHotkeyRow(_tr(\"Toggle fullscreen\"), s_cfgHotkeys.toggleFullscreen);\n\tCreateHotkeyRow(_tr(\"Take screenshot\"), s_cfgHotkeys.takeScreenshot);\n\tCreateHotkeyRow(_tr(\"Toggle fast-forward\"), s_cfgHotkeys.toggleFastForward);\n#ifdef CEMU_DEBUG_ASSERT\n\tCreateHotkeyRow(_tr(\"End emulation\"), s_cfgHotkeys.endEmulation);\n#endif\n\tCreateHotkeyRow(_tr(\"Exit application\"), s_cfgHotkeys.exitApplication);\n\n\tm_controllerTimer = new wxTimer(this);\n\tBind(wxEVT_TIMER, &HotkeySettings::OnControllerTimer, this);\n\n\tm_sizer->SetSizeHints(this);\n}\n\nHotkeySettings::~HotkeySettings()\n{\n\tm_controllerTimer->Stop();\n\tif (m_needToSave)\n\t{\n\t\tGetConfigHandle().Save();\n\t}\n}\n\nvoid HotkeySettings::Init(MainWindow* mainWindowFrame)\n{\n\ts_cfgHotkeyToFuncMap.insert({\n\t\t{&s_cfgHotkeys.toggleFullscreen, [](void) {\n\t\t\t s_mainWindow->SetFullScreen(!s_mainWindow->IsFullScreen());\n\t\t }},\n\t\t{&s_cfgHotkeys.toggleFullscreenAlt, [](void) {\n\t\t\t s_mainWindow->SetFullScreen(!s_mainWindow->IsFullScreen());\n\t\t }},\n\t\t{&s_cfgHotkeys.exitFullscreen, [](void) {\n\t\t\t s_mainWindow->SetFullScreen(false);\n\t\t }},\n\t\t{&s_cfgHotkeys.takeScreenshot, [](void) {\n\t\t\t if (g_renderer)\n\t\t\t\t g_renderer->RequestScreenshot(SaveScreenshot);\n\t\t }},\n\t\t{&s_cfgHotkeys.toggleFastForward, [](void) {\n\t\t\t ActiveSettings::SetTimerShiftFactor((ActiveSettings::GetTimerShiftFactor() < 3) ? 3 : 1);\n\t\t }},\n\t\t{&s_cfgHotkeys.exitApplication, [](void) {\n\t\t\tauto closeEvent = new wxCloseEvent{wxEVT_CLOSE_WINDOW, s_mainWindow->GetId()};\n\t\t\tcloseEvent->SetCanVeto(false);\n\t\t\twxQueueEvent(s_mainWindow, closeEvent);\n\t\t }},\n#ifdef CEMU_DEBUG_ASSERT\n\t\t{&s_cfgHotkeys.endEmulation, [](void) {\n\t\t\t wxTheApp->CallAfter([]() {\n\t\t\t\ts_mainWindow->EndEmulation();\n\t\t\t });\n\t\t }},\n#endif\n\t});\n\n\ts_keyboardHotkeyToFuncMap.reserve(s_cfgHotkeyToFuncMap.size());\n\tfor (const auto& [cfgHotkey, func] : s_cfgHotkeyToFuncMap)\n\t{\n\t\tauto keyboardHotkey = cfgHotkey->keyboard.raw;\n\t\tif (keyboardHotkey > sHotkeyCfg::keyboardNone)\n\t\t{\n\t\t\ts_keyboardHotkeyToFuncMap[keyboardHotkey] = func;\n\t\t}\n\t\tauto controllerHotkey = cfgHotkey->controller;\n\t\tif (controllerHotkey > sHotkeyCfg::controllerNone)\n\t\t{\n\t\t\ts_controllerHotkeyToFuncMap[controllerHotkey] = func;\n\t\t}\n\t}\n\ts_mainWindow = mainWindowFrame;\n}\n\nvoid HotkeySettings::CreateColumnHeaders(void)\n{\n\tauto* emptySpace = new wxStaticText(m_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);\n\tauto* keyboard = new wxStaticText(m_panel, wxID_ANY, _tr(\"Keyboard\"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);\n\tauto* controller = new wxStaticText(m_panel, wxID_ANY, _tr(\"Controller\"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);\n\tkeyboard->SetFont(keyboard->GetFont().Bold().Larger());\n\tcontroller->SetFont(controller->GetFont().Bold().Larger());\n\n\tkeyboard->SetMinSize(m_minButtonSize);\n\tcontroller->SetMinSize(m_minButtonSize);\n\n\tauto flags = wxSizerFlags().Expand().Border(wxTOP, 10);\n\tm_sizer->Add(emptySpace, flags);\n\tm_sizer->Add(keyboard, flags);\n\tm_sizer->Add(controller, flags);\n}\n\nvoid HotkeySettings::CreateHotkeyRow(const wxString& label, sHotkeyCfg& cfgHotkey)\n{\n\tauto* name = new wxStaticText(m_panel, wxID_ANY, label);\n\tauto* keyInput = new wxButton(m_panel, wxID_ANY, To_wxString(cfgHotkey.keyboard), wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxBU_EXACTFIT);\n\tauto* controllerInput = new wxButton(m_panel, wxID_ANY, To_wxString(cfgHotkey.controller), wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxBU_EXACTFIT);\n\n\t/* for starting input */\n\tkeyInput->Bind(wxEVT_BUTTON, &HotkeySettings::OnKeyboardHotkeyInputLeftClick, this);\n\tcontrollerInput->Bind(wxEVT_BUTTON, &HotkeySettings::OnControllerHotkeyInputLeftClick, this);\n\n\t/* for cancelling and clearing input */\n\tkeyInput->Bind(wxEVT_RIGHT_UP, &HotkeySettings::OnKeyboardHotkeyInputRightClick, this);\n\tcontrollerInput->Bind(wxEVT_RIGHT_UP, &HotkeySettings::OnControllerHotkeyInputRightClick, this);\n\n\tkeyInput->SetMinSize(m_minButtonSize);\n\tcontrollerInput->SetMinSize(m_minButtonSize);\n\n\tconst wxColour inputButtonColor = GetBackgroundColour();\n\tkeyInput->SetBackgroundColour(inputButtonColor);\n\tcontrollerInput->SetBackgroundColour(inputButtonColor);\n\n\tauto flags = wxSizerFlags(1).Expand().Border(wxALL, 5).CenterVertical();\n\tm_sizer->Add(name, flags);\n\tm_sizer->Add(keyInput, flags);\n\tm_sizer->Add(controllerInput, flags);\n\n\tm_hotkeys.emplace_back(name, keyInput, controllerInput, cfgHotkey);\n}\n\nvoid HotkeySettings::OnControllerTimer(wxTimerEvent& event)\n{\n\tif (m_activeController.expired())\n\t{\n\t\tm_controllerTimer->Stop();\n\t\treturn;\n\t}\n\tauto& controller = *m_activeController.lock();\n\tauto buttons = controller.update_state().buttons;\n\tif (!buttons.IsIdle())\n\t{\n\t\tfor (const auto& newHotkey : buttons.GetButtonList())\n\t\t{\n\t\t\tm_controllerTimer->Stop();\n\t\t\tauto* inputButton = static_cast<wxButton*>(m_controllerTimer->GetClientData());\n\t\t\tauto& cfgHotkey = *static_cast<sHotkeyCfg*>(inputButton->GetClientData());\n\t\t\tconst auto oldHotkey = cfgHotkey.controller;\n\t\t\tconst bool isModifier = (&cfgHotkey == &s_cfgHotkeys.modifiers);\n\t\t\t/* ignore same hotkeys and block duplicate hotkeys */\n\t\t\tif ((newHotkey != oldHotkey) && (isModifier || (newHotkey != s_cfgHotkeys.modifiers.controller)) &&\n\t\t\t\t(s_controllerHotkeyToFuncMap.find(newHotkey) == s_controllerHotkeyToFuncMap.end()))\n\t\t\t{\n\t\t\t\tm_needToSave |= true;\n\t\t\t\tcfgHotkey.controller = newHotkey;\n\t\t\t\t/* don't bind modifier to map */\n\t\t\t\tif (!isModifier)\n\t\t\t\t{\n\t\t\t\t\ts_controllerHotkeyToFuncMap.erase(oldHotkey);\n\t\t\t\t\ts_controllerHotkeyToFuncMap[newHotkey] = s_cfgHotkeyToFuncMap.at(&cfgHotkey);\n\t\t\t\t}\n\t\t\t}\n\t\t\tFinalizeInput<ControllerHotkey_t>(inputButton);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nvoid HotkeySettings::OnKeyboardHotkeyInputLeftClick(wxCommandEvent& event)\n{\n\tauto* inputButton = static_cast<wxButton*>(event.GetEventObject());\n\tif (m_activeInputButton)\n\t{\n\t\t/* ignore multiple clicks of the same button */\n\t\tif (inputButton == m_activeInputButton) return;\n\t\tRestoreInputButton<uKeyboardHotkey>();\n\t}\n\tinputButton->Bind(wxEVT_KEY_UP, &HotkeySettings::OnKeyUp, this);\n\tinputButton->SetLabelText(m_editModeHotkeyText);\n\tm_activeInputButton = inputButton;\n}\n\nvoid HotkeySettings::OnControllerHotkeyInputLeftClick(wxCommandEvent& event)\n{\n\tauto* inputButton = static_cast<wxButton*>(event.GetEventObject());\n\tif (m_activeInputButton)\n\t{\n\t\t/* ignore multiple clicks of the same button */\n\t\tif (inputButton == m_activeInputButton) return;\n\t\tRestoreInputButton<ControllerHotkey_t>();\n\t}\n\tm_controllerTimer->Stop();\n\tif (!SetActiveController())\n\t{\n\t\treturn;\n\t}\n\tinputButton->SetLabelText(m_editModeHotkeyText);\n\tm_controllerTimer->SetClientData(inputButton);\n\tm_controllerTimer->Start(25);\n\tm_activeInputButton = inputButton;\n}\n\nvoid HotkeySettings::OnKeyboardHotkeyInputRightClick(wxMouseEvent& event)\n{\n\tif (m_activeInputButton)\n\t{\n\t\tRestoreInputButton<uKeyboardHotkey>();\n\t\treturn;\n\t}\n\tauto* inputButton = static_cast<wxButton*>(event.GetEventObject());\n\tauto& cfgHotkey = *static_cast<sHotkeyCfg*>(inputButton->GetClientData());\n\tuKeyboardHotkey newHotkey{sHotkeyCfg::keyboardNone};\n\tif (cfgHotkey.keyboard.raw != newHotkey.raw)\n\t{\n\t\tm_needToSave |= true;\n\t\ts_keyboardHotkeyToFuncMap.erase(cfgHotkey.keyboard.raw);\n\t\tcfgHotkey.keyboard = newHotkey;\n\t\tFinalizeInput<uKeyboardHotkey>(inputButton);\n\t}\n}\n\nvoid HotkeySettings::OnControllerHotkeyInputRightClick(wxMouseEvent& event)\n{\n\tif (m_activeInputButton)\n\t{\n\t\tRestoreInputButton<ControllerHotkey_t>();\n\t\treturn;\n\t}\n\tauto* inputButton = static_cast<wxButton*>(event.GetEventObject());\n\tauto& cfgHotkey = *static_cast<sHotkeyCfg*>(inputButton->GetClientData());\n\tControllerHotkey_t newHotkey{sHotkeyCfg::controllerNone};\n\tif (cfgHotkey.controller != newHotkey)\n\t{\n\t\tm_needToSave |= true;\n\t\ts_controllerHotkeyToFuncMap.erase(cfgHotkey.controller);\n\t\tcfgHotkey.controller = newHotkey;\n\t\tFinalizeInput<ControllerHotkey_t>(inputButton);\n\t}\n}\n\nbool HotkeySettings::SetActiveController(void)\n{\n\tauto emulatedController = InputManager::instance().get_controller(0);\n\tif (emulatedController.use_count() <= 1)\n\t{\n\t\treturn false;\n\t}\n\tconst auto& controllers = emulatedController->get_controllers();\n\tif (controllers.empty())\n\t{\n\t\treturn false;\n\t}\n\tm_activeController = controllers.at(0);\n\treturn true;\n}\n\nvoid HotkeySettings::OnKeyUp(wxKeyEvent& event)\n{\n\tauto* inputButton = static_cast<wxButton*>(event.GetEventObject());\n\tauto& cfgHotkey = *static_cast<sHotkeyCfg*>(inputButton->GetClientData());\n\tif (auto keycode = event.GetKeyCode(); IsValidKeycodeUp(keycode))\n\t{\n\t\tauto oldHotkey = cfgHotkey.keyboard;\n\t\tuKeyboardHotkey newHotkey{};\n\t\tnewHotkey.key = keycode;\n\t\tnewHotkey.alt = event.AltDown();\n\t\tnewHotkey.ctrl = event.ControlDown();\n\t\tnewHotkey.shift = event.ShiftDown();\n\t\tif ((newHotkey.raw != oldHotkey.raw) &&\n\t\t\t(s_keyboardHotkeyToFuncMap.find(newHotkey.raw) == s_keyboardHotkeyToFuncMap.end()))\n\t\t{\n\t\t\tm_needToSave |= true;\n\t\t\tcfgHotkey.keyboard = newHotkey;\n\t\t\ts_keyboardHotkeyToFuncMap.erase(oldHotkey.raw);\n\t\t\ts_keyboardHotkeyToFuncMap[newHotkey.raw] = s_cfgHotkeyToFuncMap.at(&cfgHotkey);\n\t\t}\n\t}\n\tFinalizeInput<uKeyboardHotkey>(inputButton);\n}\n\ntemplate<typename T>\nvoid HotkeySettings::FinalizeInput(wxButton* inputButton)\n{\n\tauto& cfgHotkey = *static_cast<sHotkeyCfg*>(inputButton->GetClientData());\n\tif constexpr (std::is_same_v<T, uKeyboardHotkey>)\n\t{\n\t\tinputButton->Unbind(wxEVT_KEY_UP, &HotkeySettings::OnKeyUp, this);\n\t\tinputButton->SetLabelText(To_wxString(cfgHotkey.keyboard));\n\t}\n\telse if constexpr (std::is_same_v<T, ControllerHotkey_t>)\n\t{\n\t\tinputButton->SetLabelText(To_wxString(cfgHotkey.controller));\n\t}\n\tm_activeInputButton = nullptr;\n}\n\ntemplate<typename T>\nvoid HotkeySettings::RestoreInputButton(void)\n{\n\tFinalizeInput<T>(m_activeInputButton);\n}\n\nbool HotkeySettings::IsValidKeycodeUp(int keycode)\n{\n\tswitch (keycode)\n\t{\n\tcase WXK_NONE:\n\tcase WXK_ESCAPE:\n\tcase WXK_ALT:\n\tcase WXK_CONTROL:\n\tcase WXK_SHIFT:\n\t\treturn false;\n\tdefault:\n\t\treturn true;\n\t}\n}\n\nwxString HotkeySettings::To_wxString(uKeyboardHotkey hotkey)\n{\n\tif (hotkey.raw == sHotkeyCfg::keyboardNone) {\n\t\treturn m_disabledHotkeyText;\n\t}\n\twxString ret{};\n\tif (hotkey.alt)\n\t{\n\t\tret.append(_(\"Alt + \"));\n\t}\n\tif (hotkey.ctrl)\n\t{\n\t\tret.append(_(\"Ctrl + \"));\n\t}\n\tif (hotkey.shift)\n\t{\n\t\tret.append(_(\"Shift + \"));\n\t}\n\tret.append(wxAcceleratorEntry(0, hotkey.key).ToString());\n\treturn ret;\n}\n\nwxString HotkeySettings::To_wxString(ControllerHotkey_t hotkey)\n{\n\tif ((hotkey == sHotkeyCfg::controllerNone) || m_activeController.expired()) {\n\t\treturn m_disabledHotkeyText;\n\t}\n\treturn m_activeController.lock()->get_button_name(hotkey);\n}\n\nvoid HotkeySettings::CaptureInput(wxKeyEvent& event)\n{\n\tuKeyboardHotkey hotkey{};\n\thotkey.key = event.GetKeyCode();\n\thotkey.alt = event.AltDown();\n\thotkey.ctrl = event.ControlDown();\n\thotkey.shift = event.ShiftDown();\n\tconst auto it = s_keyboardHotkeyToFuncMap.find(hotkey.raw);\n\tif (it != s_keyboardHotkeyToFuncMap.end())\n\t\tit->second();\n}\n\nvoid HotkeySettings::CaptureInput(const ControllerState& currentState, const ControllerState& lastState)\n{\n\tconst auto& modifier = s_cfgHotkeys.modifiers.controller;\n\tif ((modifier >= 0) && currentState.buttons.GetButtonState(modifier))\n\t{\n\t\tfor (const auto& buttonId : currentState.buttons.GetButtonList())\n\t\t{\n\t\t\tconst auto it = s_controllerHotkeyToFuncMap.find(buttonId);\n\t\t\tif (it == s_controllerHotkeyToFuncMap.end())\n\t\t\t\tcontinue;\n\t\t\t/* only capture clicks */\n\t\t\tif (lastState.buttons.GetButtonState(buttonId))\n\t\t\t\tbreak;\n\t\t\tit->second();\n\t\t\tbreak;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/input/HotkeySettings.h",
    "content": "#pragma once\n\n#include <wx/wx.h>\n#include \"wxCemuConfig.h\"\n#include \"input/api/Controller.h\"\n\nclass HotkeyEntry;\n\nclass HotkeySettings : public wxFrame\n{\npublic:\n\tstatic void Init(class MainWindow* mainWindow);\n\n\tstatic void CaptureInput(wxKeyEvent& event);\n\tstatic void CaptureInput(const ControllerState& currentState, const ControllerState& lastState);\n\n\tHotkeySettings(wxWindow* parent);\n\t~HotkeySettings();\n\nprivate:\n\tinline static class MainWindow* s_mainWindow = nullptr;\n\tstatic std::unordered_map<sHotkeyCfg*, std::function<void(void)>> s_cfgHotkeyToFuncMap;\n\tinline static std::unordered_map<uint16, std::function<void(void)>> s_keyboardHotkeyToFuncMap{};\n\tinline static std::unordered_map<uint16, std::function<void(void)>> s_controllerHotkeyToFuncMap{};\n\tinline static auto& s_cfgHotkeys = GetWxGUIConfig().hotkeys;\n\n\twxPanel* m_panel;\n\twxFlexGridSizer* m_sizer;\n\twxButton* m_activeInputButton{ nullptr };\n\twxTimer* m_controllerTimer{ nullptr };\n\tconst wxSize m_minButtonSize{ 250, 45 };\n\tconst wxString m_disabledHotkeyText{ _(\"----\") };\n\tconst wxString m_editModeHotkeyText{ \"\" };\n\n\tstd::vector<HotkeyEntry> m_hotkeys;\n\tstd::weak_ptr<ControllerBase> m_activeController{};\n\tbool m_needToSave = false;\n\n\t/* helpers */\n\tvoid CreateColumnHeaders(void);\n\tvoid CreateHotkeyRow(const wxString& label, sHotkeyCfg& cfgHotkey);\n\twxString To_wxString(uKeyboardHotkey hotkey);\n\twxString To_wxString(ControllerHotkey_t hotkey);\n\tbool IsValidKeycodeUp(int keycode);\n\tbool SetActiveController(void);\n\n\ttemplate<typename T>\n\tvoid FinalizeInput(wxButton* inputButton);\n\n\ttemplate <typename T>\n\tvoid RestoreInputButton(void);\n\n\t/* events */\n\tvoid OnKeyboardHotkeyInputLeftClick(wxCommandEvent& event);\n\tvoid OnControllerHotkeyInputLeftClick(wxCommandEvent& event);\n\tvoid OnKeyboardHotkeyInputRightClick(wxMouseEvent& event);\n\tvoid OnControllerHotkeyInputRightClick(wxMouseEvent& event);\n\tvoid OnKeyUp(wxKeyEvent& event);\n\tvoid OnControllerTimer(wxTimerEvent& event);\n};\n"
  },
  {
    "path": "src/gui/wxgui/input/InputAPIAddWindow.cpp",
    "content": "#include \"wxgui/input/InputAPIAddWindow.h\"\n\n#include \"input/InputManager.h\"\n#include \"wxgui/helpers/wxCustomData.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"input/api/Controller.h\"\n\n#include <wx/sizer.h>\n#include <wx/stattext.h>\n#include <wx/choice.h>\n#include <wx/statline.h>\n#include <wx/button.h>\n#include <wx/combobox.h>\n#include <wx/msgdlg.h>\n#include <wx/wupdlock.h>\n\n#include \"input/ControllerFactory.h\"\n\nwxDEFINE_EVENT(wxControllersRefreshed, wxCommandEvent);\n\nusing wxTypeData = wxCustomData<InputAPI::Type>;\nusing wxControllerData = wxCustomData<ControllerPtr>;\n\nInputAPIAddWindow::InputAPIAddWindow(wxWindow* parent, const wxPoint& position,\n                                     const std::vector<ControllerPtr>& controllers)\n\t: wxDialog(parent, wxID_ANY, \"Add input API\", position, wxDefaultSize, wxCAPTION), m_controllers(controllers)\n{\n\tthis->SetSizeHints(wxDefaultSize, wxDefaultSize);\n\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\t{\n\t\tauto* api_row = new wxFlexGridSizer(2);\n\n\t\t// API\n\t\tapi_row->Add(new wxStaticText(this, wxID_ANY, _(\"API\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tm_input_api = new wxChoice(this, wxID_ANY);\n\t\tauto& providers = InputManager::instance().get_api_providers();\n\t\tfor (const auto& p : providers)\n\t\t{\n\t\t\tif (p.empty())\n\t\t\t\tcontinue;\n\n\t\t\tconst auto provider = *p.begin();\n\t\t\tm_input_api->Append(wxString::FromUTF8(provider->api_name()), new wxTypeData(provider->api()));\n\t\t}\n\n\t\tm_input_api->Bind(wxEVT_CHOICE, &InputAPIAddWindow::on_api_selected, this);\n\t\tapi_row->Add(m_input_api, 1, wxALL | wxEXPAND, 5);\n\n\t\t// Controller\n\t\tapi_row->Add(new wxStaticText(this, wxID_ANY, _(\"Controller\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tm_controller_list = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr,\n\t\t                                   wxCB_READONLY);\n\t\tm_controller_list->Bind(wxEVT_COMBOBOX_DROPDOWN, &InputAPIAddWindow::on_controller_dropdown, this);\n\t\tm_controller_list->Bind(wxEVT_COMBOBOX, &InputAPIAddWindow::on_controller_selected, this);\n\t\tm_controller_list->SetMinSize(wxSize(240, -1));\n\t\tm_controller_list->Disable();\n\t\tapi_row->Add(m_controller_list, 1, wxALL | wxEXPAND, 5);\n\n\t\tsizer->Add(api_row, 0, wxEXPAND, 5);\n\t}\n\n\tsizer->Add(new wxStaticLine(this), 0, wxEXPAND);\n\n\t{\n\t\tauto* end_row = new wxBoxSizer(wxHORIZONTAL);\n\n\t\tm_ok_button = new wxButton(this, wxID_ANY, _(\"Add\"));\n\t\tm_ok_button->Bind(wxEVT_BUTTON, &InputAPIAddWindow::on_add_button, this);\n\t\tm_ok_button->Disable();\n\t\tend_row->Add(m_ok_button, 0, wxALL, 5);\n\n\t\tauto* cancel_button = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\t\tcancel_button->Bind(wxEVT_BUTTON, &InputAPIAddWindow::on_close_button, this);\n\t\tend_row->Add(cancel_button, 0, wxALL, 5);\n\n\t\tsizer->Add(end_row, 0, wxEXPAND, 5);\n\t}\n\n\t{\n\t\t// optional settings\n\t\tm_settings_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\t\tauto* panel_sizer = new wxBoxSizer(wxVERTICAL);\n\t\tpanel_sizer->Add(new wxStaticLine(m_settings_panel), 0, wxEXPAND, 0);\n\n\t\t{\n\t\t\tauto* row = new wxBoxSizer(wxHORIZONTAL);\n\t\t\t// we only have dsu settings atm, so add elements now\n\t\t\trow->Add(new wxStaticText(m_settings_panel, wxID_ANY, _(\"IP\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\t\tm_ip = new wxTextCtrl(m_settings_panel, wxID_ANY, \"127.0.0.1\");\n\t\t\trow->Add(m_ip, 0, wxALL, 5);\n\n\t\t\trow->Add(new wxStaticText(m_settings_panel, wxID_ANY, _(\"Port\")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\t\tm_port = new wxTextCtrl(m_settings_panel, wxID_ANY, \"26760\");\n\t\t\trow->Add(m_port, 0, wxALL, 5);\n\n\t\t\tpanel_sizer->Add(row, 0, wxEXPAND);\n\t\t}\n\n\t\tm_settings_panel->SetSizer(panel_sizer);\n\t\tm_settings_panel->Layout();\n\t\tm_settings_panel->Hide();\n\n\t\tsizer->Add(m_settings_panel, 1, wxEXPAND);\n\t}\n\n\tthis->SetSizer(sizer);\n\tthis->Layout();\n\tsizer->Fit(this);\n\n\tthis->Bind(wxControllersRefreshed, &InputAPIAddWindow::on_controllers_refreshed, this);\n}\n\nInputAPIAddWindow::~InputAPIAddWindow()\n{\n\tdiscard_thread_result();\n}\n\nvoid InputAPIAddWindow::on_add_button(wxCommandEvent& event)\n{\n\tconst auto selection = m_input_api->GetSelection();\n\tif (selection == wxNOT_FOUND)\n\t{\n\t\tcemu_assert_debug(false);\n\t\tEndModal(wxID_CANCEL);\n\t\treturn;\n\t}\n\n\tfor (const auto& c : m_controllers)\n\t{\n\t\tif (*c == *m_controller)\n\t\t{\n\t\t\twxMessageBox(_(\"The controller is already added!\"), _(\"Error\"), wxOK | wxCENTRE | wxICON_ERROR, this);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tm_type = static_cast<wxTypeData*>(m_input_api->GetClientObject(selection))->get();\n\tEndModal(wxID_OK);\n}\n\nvoid InputAPIAddWindow::on_close_button(wxCommandEvent& event)\n{\n\tEndModal(wxID_CANCEL);\n}\n\nbool InputAPIAddWindow::has_custom_settings() const\n{\n\tconst auto selection = m_input_api->GetStringSelection();\n\treturn selection == wxString::FromUTF8(to_string(InputAPI::DSUClient));\n}\n\nstd::unique_ptr<ControllerProviderSettings> InputAPIAddWindow::get_settings() const\n{\n\tif (!has_custom_settings())\n\t\treturn {};\n\n\treturn std::make_unique<DSUProviderSettings>(m_ip->GetValue().ToStdString(),\n\t                                             ConvertString<uint16>(m_port->GetValue().ToStdString()));\n}\n\nvoid InputAPIAddWindow::on_api_selected(wxCommandEvent& event)\n{\n\tdiscard_thread_result();\n\n\tif (m_input_api->GetSelection() == wxNOT_FOUND)\n\t\treturn;\n\n\tm_controller_list->Enable();\n\tm_controller_list->SetSelection(wxNOT_FOUND);\n\n    const auto selection = m_input_api->GetStringSelection();\n\t// keyboard is a special case, as theres only one device supported atm\n\tif (selection == wxString::FromUTF8(to_string(InputAPI::Keyboard)))\n\t{\n\t\tconst auto controllers = InputManager::instance().get_api_provider(InputAPI::Keyboard)->get_controllers();\n\t\tif (!controllers.empty())\n\t\t{\n\t\t\tm_controller = controllers[0];\n\t\t\tm_ok_button->Enable();\n\n\t\t\tm_controller_list->Clear();\n\t\t\tconst auto display_name = controllers[0]->display_name();\n\t\t\tconst auto index = m_controller_list->Append(display_name, new wxCustomData(controllers[0]));\n\t\t\tm_controller_list->SetSelection(index);\n\t\t}\n\t}\n    else\n    {\n#if BOOST_OS_LINUX || BOOST_OS_BSD\n        // We rely on the wxEVT_COMBOBOX_DROPDOWN event to trigger filling the controller list,\n        // but on wxGTK the dropdown button cannot be clicked if the list is empty\n        // so as a quick and dirty workaround we fill the list here\n        wxCommandEvent tmpCmdEvt;\n        on_controller_dropdown(tmpCmdEvt);\n#endif\n    }\n\n\tconst auto show_settings = has_custom_settings();\n\t// dsu has special settings for ip/port\n\tif (show_settings != m_settings_panel->IsShown())\n\t{\n\t\twxWindowUpdateLocker locker(this);\n\t\tm_settings_panel->Show(show_settings);\n\t\tLayout();\n\t\tFit();\n\t}\n}\n\nvoid InputAPIAddWindow::on_controller_dropdown(wxCommandEvent& event)\n{\n\tif (m_search_running)\n\t\treturn;\n\n\tint selection = m_input_api->GetSelection();\n\tif (selection == wxNOT_FOUND)\n\t\treturn;\n\n\tconst auto type = static_cast<wxAPIType*>(m_input_api->GetClientObject(selection))->get();\n\tauto settings = get_settings();\n\n\tControllerProviderPtr provider;\n\tif (settings)\n\t\tprovider = InputManager::instance().get_api_provider(type, *settings);\n\telse\n\t\tprovider = InputManager::instance().get_api_provider(type);\n\n\tif (!provider)\n\t\treturn;\n\n\tstd::string selected_uuid;\n\tselection = m_controller_list->GetSelection();\n\tif (selection != wxNOT_FOUND)\n\t{\n\t\t// TODO selected_uuid\n\t}\n\n\tm_search_running = true;\n\n\twxWindowUpdateLocker lock(m_controller_list);\n\tm_controller_list->Clear();\n\n\tm_controller_list->Append(_(\"Searching for controllers...\"), (wxClientData*)nullptr);\n\tm_controller_list->SetSelection(wxNOT_FOUND);\n\n\tm_search_thread_data = std::make_unique<AsyncThreadData>();\n\tstd::thread([this, provider, selected_uuid](std::shared_ptr<AsyncThreadData> data)\n\t{\n\t\tauto available_controllers = provider->get_controllers();\n\n\t\t{\n\t\t\tstd::lock_guard lock{data->mutex};\n\t\t\tif(!data->discardResult)\n\t\t\t{\n\t\t\t\twxCommandEvent event(wxControllersRefreshed);\n\t\t\t\tevent.SetEventObject(m_controller_list);\n\t\t\t\tevent.SetClientObject(new wxCustomData(std::move(available_controllers)));\n\t\t\t\tevent.SetInt(provider->api());\n\t\t\t\tevent.SetString(selected_uuid);\n\t\t\t\twxPostEvent(this, event);\n\t\t\t\tm_search_running = false;\n\t\t\t}\n\t\t}\n\t}, m_search_thread_data).detach();\n}\n\nvoid InputAPIAddWindow::on_controller_selected(wxCommandEvent& event)\n{\n\tif (m_search_running)\n\t{\n\t\treturn;\n\t}\n\n\tconst auto selection = m_controller_list->GetSelection();\n\tif (selection == wxNOT_FOUND)\n\t{\n\t\treturn;\n\t}\n\n\tif (auto* controller = (wxControllerData*)m_controller_list->GetClientObject(selection))\n\t{\n\t\tm_controller = controller->ref();\n\t\tm_ok_button->Enable();\n\t}\n}\n\nvoid InputAPIAddWindow::on_controllers_refreshed(wxCommandEvent& event)\n{\n\tconst auto type = event.GetInt();\n\twxASSERT(0 <= type && type < InputAPI::MAX);\n\n\tauto* controllers = dynamic_cast<wxComboBox*>(event.GetEventObject());\n\twxASSERT(controllers);\n\n\tconst auto available_controllers = static_cast<wxCustomData<std::vector<std::shared_ptr<ControllerBase>>>*>(event.\n\t\tGetClientObject())->get();\n\tconst auto selected_uuid = event.GetString().ToStdString();\n\tbool item_selected = false;\n\n\twxWindowUpdateLocker lock(controllers);\n\tcontrollers->Clear();\n\tfor (const auto& c : available_controllers)\n\t{\n\t\tconst auto display_name = c->display_name();\n\t\tconst auto uuid = c->uuid();\n\t\tconst auto index = controllers->Append(display_name, new wxCustomData(c));\n\t\tif (!item_selected && selected_uuid == uuid)\n\t\t{\n\t\t\tcontrollers->SetSelection(index);\n\t\t\titem_selected = true;\n\t\t}\n\t}\n}\n\nvoid InputAPIAddWindow::discard_thread_result()\n{\n\tm_search_running = false;\n\tif(m_search_thread_data)\n\t{\n\t\tstd::lock_guard lock{m_search_thread_data->mutex};\n\t\tm_search_thread_data->discardResult = true;\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/input/InputAPIAddWindow.h",
    "content": "#pragma once\n\n#include \"input/api/InputAPI.h\"\n\n#include <optional>\n#include <wx/dialog.h>\n#include <wx/panel.h>\n\n#include \"wxgui/helpers/wxCustomData.h\"\n#include \"input/api/Controller.h\"\n\nclass wxComboBox;\nclass wxChoice;\nclass wxTextCtrl;\n\nusing wxAPIType = wxCustomData<InputAPI::Type>;\n\nclass InputAPIAddWindow : public wxDialog\n{\npublic:\n\tInputAPIAddWindow(wxWindow* parent, const wxPoint& position, const std::vector<ControllerPtr>& controllers);\n\t~InputAPIAddWindow();\n\n\tbool is_valid() const { return m_type.has_value() && m_controller != nullptr; }\n\tInputAPI::Type get_type() const { return m_type.value(); }\n\tstd::shared_ptr<ControllerBase> get_controller() const { return m_controller; }\n\n\tbool has_custom_settings() const;\n\tstd::unique_ptr<ControllerProviderSettings> get_settings() const;\n\nprivate:\n\tvoid on_add_button(wxCommandEvent& event);\n\tvoid on_close_button(wxCommandEvent& event);\n\t\n\n\tvoid on_api_selected(wxCommandEvent& event);\n\n\tvoid on_controller_dropdown(wxCommandEvent& event);\n\tvoid on_controller_selected(wxCommandEvent& event);\n\tvoid on_controllers_refreshed(wxCommandEvent& event);\n\n\tvoid discard_thread_result();\n\n\twxChoice* m_input_api;\n\twxComboBox* m_controller_list;\n\twxButton* m_ok_button;\n\n\twxPanel* m_settings_panel;\n\twxTextCtrl* m_ip, * m_port;\n\n\tstd::optional<InputAPI::Type> m_type;\n\tstd::shared_ptr<ControllerBase> m_controller;\n\n\tstd::vector<ControllerPtr> m_controllers;\n\tstd::atomic_bool m_search_running = false;\n\tstruct AsyncThreadData\n\t{\n\t\tstd::atomic_bool discardResult = false;\n\t\tstd::mutex mutex;\n\t};\n\tstd::shared_ptr<AsyncThreadData> m_search_thread_data;\n};\n"
  },
  {
    "path": "src/gui/wxgui/input/InputSettings2.cpp",
    "content": "#include \"wxgui/input/InputSettings2.h\"\n\n#include <wx/gbsizer.h>\n\n#include \"input/InputManager.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/helpers/wxControlObject.h\"\n#include \"wxgui/helpers/wxCustomData.h\"\n\n#include <wx/sizer.h>\n#include <wx/notebook.h>\n#include <wx/wupdlock.h>\n#include <wx/stattext.h>\n#include <wx/combobox.h>\n#include <wx/button.h>\n#include <wx/statline.h>\n#include <wx/bmpbuttn.h>\n#include <wx/settings.h>\n\n#include \"config/ActiveSettings.h\"\n#include \"wxgui/input/InputAPIAddWindow.h\"\n#include \"input/ControllerFactory.h\"\n\n#ifdef HAS_BLUEZ\n#include \"wxgui/input/PairingDialog.h\"\n#endif\n\n#include \"wxgui/input/panels/VPADInputPanel.h\"\n#include \"wxgui/input/panels/ProControllerInputPanel.h\"\n\n#include \"wxgui/input/settings/DefaultControllerSettings.h\"\n#include \"wxgui/input/panels/ClassicControllerInputPanel.h\"\n#include \"wxgui/input/panels/WiimoteInputPanel.h\"\n#include \"wxgui/input/settings/WiimoteControllerSettings.h\"\n#include \"util/EventService.h\"\n\n#include \"resource/embedded/resources.h\"\n\nbool g_inputConfigWindowHasFocus = false;\n\nusing wxTypeData = wxCustomData<EmulatedController::Type>;\nusing wxControllerData = wxCustomData<ControllerPtr>;\n\nstruct ControllerPage\n{\n\tEmulatedControllerPtr m_controller;\n\n\t// profiles\n\twxComboBox* m_profiles;\n\twxButton* m_profile_load, * m_profile_save, * m_profile_delete;\n\twxStaticText* m_profile_status;\n\n\t// emulated controller\n\twxComboBox* m_emulated_controller;\n\n\t// controller api\n\twxComboBox* m_controllers;\n\twxButton* m_controller_api_add, *m_controller_api_remove;\n\n\twxButton* m_controller_settings, * m_controller_calibrate, *m_controller_clear;\n\twxBitmapButton* m_controller_connected;\n\n\t// panel\n\tstd::array<InputPanel*, EmulatedController::Type::MAX> m_panels{};\n};\nusing wxControllerPageData = wxCustomData<ControllerPage>;\n\n\nInputSettings2::InputSettings2(wxWindow* parent)\n\t: wxDialog(parent, wxID_ANY, _(\"Input settings\"))\n{\n\tthis->SetSizeHints(wxDefaultSize, wxDefaultSize);\n\n\tg_inputConfigWindowHasFocus = true;\n\n\tm_connected = wxHelper::LoadThemedBitmapFromPNG(INPUT_CONNECTED_png, sizeof(INPUT_CONNECTED_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\tm_disconnected = wxHelper::LoadThemedBitmapFromPNG(INPUT_DISCONNECTED_png, sizeof(INPUT_DISCONNECTED_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\tm_low_battery = wxHelper::LoadThemedBitmapFromPNG(INPUT_LOW_BATTERY_png, sizeof(INPUT_LOW_BATTERY_png), wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));\n\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tm_notebook = new wxNotebook(this, wxID_ANY);\n\tfor(size_t i = 0; i < InputManager::kMaxController; ++i)\n\t{\n\t\tauto* page = new wxPanel(m_notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\t\tpage->SetClientObject(nullptr); // force internal type to client object\n\t\tm_notebook->AddPage(page, formatWxString(_(\"Controller {}\"), i + 1));\n\t}\n\n\tm_notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &InputSettings2::on_controller_page_changed, this);\n\tsizer->Add(m_notebook, 1, wxEXPAND);\n\n\tm_notebook->SetSelection(0);\n\tauto* first_page = initialize_page(0);\n\n\t// init first/default page for fitting size\n\tauto* page_data = (wxControllerPageData*)first_page->GetClientObject();\n\tauto* panel = new VPADInputPanel(first_page);\n\tpage_data->ref().m_panels[EmulatedController::Type::VPAD] = panel;\n\n\tauto* first_page_sizer = dynamic_cast<wxGridBagSizer*>(first_page->GetSizer());\n\tauto* panel_sizer = first_page_sizer->FindItemAtPosition(wxGBPosition(7, 0))->GetSizer();\n\tpanel_sizer->Add(panel, 0, wxEXPAND);\n\n\tpanel->Show();\n\tfirst_page->Layout();\n\n\tSetSizer(sizer);\n\tLayout();\n\tFit();\n\n    panel->Hide();\n\n\tupdate_state();\n\n\tBind(wxEVT_TIMER, &InputSettings2::on_timer, this);\n\n\tm_timer = new wxTimer(this);\n\tm_timer->Start(25);\n\n\tm_controller_changed = EventService::instance().connect<Events::ControllerChanged>(&InputSettings2::on_controller_changed, this);\n}\n\nInputSettings2::~InputSettings2()\n{\n\tm_controller_changed.disconnect();\n\n\tg_inputConfigWindowHasFocus = false;\n\tm_timer->Stop();\n\tInputManager::instance().save();\n}\n\n\nwxWindow* InputSettings2::initialize_page(size_t index)\n{\n\tauto* page = m_notebook->GetPage(index);\n\tif (page->GetClientObject()) // already initialized\n\t\treturn page;\n\n\tpage->Bind(wxEVT_LEFT_UP, &InputSettings2::on_left_click, this);\n\n\tControllerPage page_data{};\n\tconst auto emulated_controller = InputManager::instance().get_controller(index);\n\tpage_data.m_controller = emulated_controller;\n\n\twxWindowUpdateLocker lock(page);\n\tauto* sizer = new wxGridBagSizer();\n\n\t{\n\t\t// profile\n\t\tsizer->Add(new wxStaticText(page, wxID_ANY, _(\"Profile\")), wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\t\tauto* profiles = new wxComboBox(page, wxID_ANY, kDefaultProfileName);\n\t\tsizer->Add(profiles, wxGBPosition(0, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5);\n\n#if BOOST_OS_LINUX || BOOST_OS_BSD\n\t\t// We rely on the wxEVT_COMBOBOX_DROPDOWN event to trigger filling the profile list,\n\t\t// but on wxGTK the dropdown button cannot be clicked if the list is empty\n\t\t// so as a quick and dirty workaround we fill the list here\n\t\twxCommandEvent tmpCmdEvt;\n\t\ttmpCmdEvt.SetEventObject(profiles);\n\t\ton_profile_dropdown(tmpCmdEvt);\n#endif\n\n\t\tif (emulated_controller && emulated_controller->has_profile_name())\n\t\t{\n\t\t\tprofiles->SetValue(emulated_controller->get_profile_name());\n\t\t}\n\n\t\tauto* load_bttn = new wxButton(page, wxID_ANY, _(\"Load\"));\n\t\tload_bttn->Disable();\n\t\tsizer->Add(load_bttn, wxGBPosition(0, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tauto* save_bttn = new wxButton(page, wxID_ANY, _(\"Save\"));\n\t\tsave_bttn->Disable();\n\t\tsizer->Add(save_bttn, wxGBPosition(0, 3), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tauto* delete_bttn = new wxButton(page, wxID_ANY, _(\"Delete\"));\n\t\tdelete_bttn->Disable();\n\t\tsizer->Add(delete_bttn, wxGBPosition(0, 4), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tauto* profile_status = new wxStaticText(page, wxID_ANY, _(\"controller set by gameprofile. changes won't be saved permanently!\"));\n\t\tprofile_status->SetMinSize(wxSize(200, -1));\n\t\tprofile_status->Wrap(200);\n\t\tsizer->Add(profile_status, wxGBPosition(0, 5), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL | wxRESERVE_SPACE_EVEN_IF_HIDDEN, 5);\n\n\t\tif(InputManager::instance().is_gameprofile_set(index))\n\t\t{\n\t\t\tprofile_status->SetForegroundColour(wxTheColourDatabase->Find(\"ERROR\"));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tprofile_status->Hide();\n\t\t}\n\n\t\tload_bttn->Bind(wxEVT_BUTTON, &InputSettings2::on_profile_load, this);\n\t\tsave_bttn->Bind(wxEVT_BUTTON, &InputSettings2::on_profile_save, this);\n\t\tdelete_bttn->Bind(wxEVT_BUTTON, &InputSettings2::on_profile_delete, this);\n\n\t\tprofiles->Bind(wxEVT_COMBOBOX_DROPDOWN, &InputSettings2::on_profile_dropdown, this);\n\t\tprofiles->Bind(wxEVT_TEXT, &InputSettings2::on_profile_text_changed, this);\n\n\t\tpage_data.m_profiles = profiles;\n\t\tpage_data.m_profile_load = load_bttn;\n\t\tpage_data.m_profile_save = save_bttn;\n\t\tpage_data.m_profile_delete = delete_bttn;\n\t\tpage_data.m_profile_status = profile_status;\n\t}\n\n\tsizer->Add(new wxStaticLine(page), wxGBPosition(1, 0), wxGBSpan(1, 6), wxEXPAND);\n\n\t{\n\t\t// emulated controller\n\t\tsizer->Add(new wxStaticText(page, wxID_ANY, _(\"Emulated controller\")), wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tauto* econtroller_box = new wxComboBox(page, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY);\n\t\tecontroller_box->SetMinSize(wxSize(200, -1));\n\t\tecontroller_box->Bind(wxEVT_COMBOBOX_DROPDOWN, &InputSettings2::on_emulated_controller_dropdown, this);\n\t\tecontroller_box->Bind(wxEVT_COMBOBOX, &InputSettings2::on_emulated_controller_selected, this);\n\n\t\tecontroller_box->AppendString(_(\"Disabled\"));\n\t\tecontroller_box->SetSelection(0);\n\n\t\tsizer->Add(econtroller_box, wxGBPosition(2, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5);\n\t\tpage_data.m_emulated_controller = econtroller_box;\n\t}\n\n\tsizer->Add(new wxStaticLine(page), wxGBPosition(3, 0), wxGBSpan(1, 6), wxEXPAND);\n\n\t{\n\t\t// controller api\n\t\tsizer->Add(new wxStaticText(page, wxID_ANY, _(\"Controller\")), wxGBPosition(4, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\t\tauto* controllers = new wxComboBox(page, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY);\n\t\tcontrollers->Bind(wxEVT_COMBOBOX, &InputSettings2::on_controller_selected, this);\n\t\tcontrollers->Bind(wxEVT_COMBOBOX_DROPDOWN, &InputSettings2::on_controller_dropdown, this);\n\t\tcontrollers->SetMinSize(wxSize(300, -1));\n\n\t\tpage_data.m_controllers = controllers;\n\n\t\tsizer->Add(controllers, wxGBPosition(4, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5);\n\n\t\t{\n\t\t\t// add/remove buttons\n\t\t\tauto* bttn_sizer = new wxBoxSizer(wxHORIZONTAL);\n\n\t\t\tauto* add_api = new wxButton(page, wxID_ANY, \" + \", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);\n\t\t\tadd_api->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_add, this);\n\t\t\tbttn_sizer->Add(add_api, 0, wxALL, 5);\n\n\t\t\tauto* remove_api = new wxButton(page, wxID_ANY, \"  -  \", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);\n\t\t\tremove_api->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_remove, this);\n\t\t\tbttn_sizer->Add(remove_api, 0, wxALL, 5);\n\n\t\t\tsizer->Add(bttn_sizer, wxGBPosition(4, 2), wxDefaultSpan, wxEXPAND, 5);\n\n\t\t\tpage_data.m_controller_api_add = add_api;\n\t\t\tpage_data.m_controller_api_remove = remove_api;\n\t\t}\n\n#ifdef HAS_BLUEZ\n\t\tauto* pairingDialog = new wxButton(page, wxID_ANY, _(\"Pair Wii/Wii U Controller\"));\n\t\tpairingDialog->Bind(wxEVT_BUTTON, [this](wxEvent&) {\n\t\t\tPairingDialog pairing_dialog(this);\n\t\t\tpairing_dialog.ShowModal();\n\t\t});\n\t\tsizer->Add(pairingDialog, wxGBPosition(5, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n#endif\n\n\t\t// controller\n\t\tauto* controller_bttns = new wxBoxSizer(wxHORIZONTAL);\n\t\tauto* settings = new wxButton(page, wxID_ANY, _(\"Settings\"));\n\t\tsettings->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_settings, this);\n\t\tsettings->Disable();\n\t\tcontroller_bttns->Add(settings, 0, wxALL, 5);\n\n\t\tauto* calibrate = new wxButton(page, wxID_ANY, _(\"Calibrate\"));\n\t\tcalibrate->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_calibrate, this);\n\t\tcalibrate->Disable();\n\t\tcontroller_bttns->Add(calibrate, 0, wxALL, 5);\n\n\t\tauto* clear = new wxButton(page, wxID_ANY, _(\"Clear\"));\n\t\tclear->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_clear, this);\n\t\tcontroller_bttns->Add(clear, 0, wxALL, 5);\n\n\t\tsizer->Add(controller_bttns, wxGBPosition(5, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);\n\n\t\tauto* connected_button = new wxBitmapButton(page, wxID_ANY, m_disconnected);\n\t\tconnected_button->Bind(wxEVT_BUTTON, &InputSettings2::on_controller_connect, this);\n\t\tconnected_button->SetToolTip(_(\"Test if the controller is connected\"));\n\t\tsizer->Add(connected_button, wxGBPosition(5, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5); // TODO replace with icon\n\n\t\tpage_data.m_controller_settings = settings;\n\t\tpage_data.m_controller_calibrate = calibrate;\n\t\tpage_data.m_controller_clear = clear;\n\t\tpage_data.m_controller_connected = connected_button;\n\n\t}\n\n\tsizer->Add(new wxStaticLine(page), wxGBPosition(6, 0), wxGBSpan(1, 6), wxEXPAND);\n\n\tauto* panel_sizer = new wxBoxSizer(wxVERTICAL);\n\tsizer->Add(panel_sizer, wxGBPosition(7, 0), wxGBSpan(1, 6), wxEXPAND | wxALL, 5);\n\n\tpage->SetSizer(sizer);\n\tpage->Layout();\n\n\tpage->SetClientObject(new wxCustomData(page_data));\n\n\treturn page;\n}\n\nstd::shared_ptr<ControllerBase> InputSettings2::get_active_controller() const\n{\n\tauto& page_data = get_current_page_data();\n\n\tconst auto selection = page_data.m_controllers->GetSelection();\n\tif(selection != wxNOT_FOUND)\n\t{\n\t\tif(auto* controller = (wxControllerData*)page_data.m_controllers->GetClientObject(selection))\n\t\t\treturn controller->ref();\n\t}\n\n\treturn {};\n}\n\nbool InputSettings2::has_settings(InputAPI::Type type)\n{\n\tswitch(type)\n\t{\n\tcase InputAPI::Keyboard:\n\t\treturn false;\n\tdefault:\n\t\treturn true;\n\t}\n}\n\nvoid InputSettings2::update_state()\n{\n\tauto* page = m_notebook->GetCurrentPage();\n\twxWindowUpdateLocker lock(page);\n\n\tauto* page_data_ptr = (wxControllerPageData*)page->GetClientObject();\n\twxASSERT(page_data_ptr);\n\tauto& page_data = page_data_ptr->ref();\n\n\tpage_data.m_profile_status->Hide();\n\n\tEmulatedControllerPtr emulated_controller = page_data.m_controller;\n\tauto has_controllers = false;\n\n\t// update emulated\n\tif(emulated_controller)\n\t{\n\t\thas_controllers = !emulated_controller->get_controllers().empty();\n\n\t\tconst auto emulated_type = emulated_controller->type();\n\t\tint index = page_data.m_emulated_controller->Append(wxString::FromUTF8(emulated_controller->type_to_string(emulated_type)));\n\t\tpage_data.m_emulated_controller->SetSelection(index);\n\n\t\tconst auto controller_selection = page_data.m_controllers->GetStringSelection();\n\t\tpage_data.m_controllers->Clear();\n\t\tif (has_controllers)\n\t\t{\n\t\t\tfor (const auto& c : emulated_controller->get_controllers())\n\t\t\t{\n\t\t\t\tpage_data.m_controllers->Append(fmt::format(\"{} [{}]\", c->display_name(), c->api_name()), new wxCustomData(c));\n\t\t\t}\n\n\t\t\tif (page_data.m_controllers->GetCount() > 0)\n\t\t\t{\n\t\t\t\tpage_data.m_controllers->SetSelection(0);\n\t\t\t\tif (!controller_selection.empty())\n\t\t\t\t\tpage_data.m_controllers->SetStringSelection(controller_selection);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tpage_data.m_emulated_controller->SetValue(_(\"Disabled\"));\n\t}\n\n\tControllerPtr controller;\n\tif (page_data.m_controllers->GetSelection() != wxNOT_FOUND)\n\t{\n\t\tif (const auto data = (wxControllerData*)page_data.m_controllers->GetClientObject(page_data.m_controllers->GetSelection()))\n\t\t\tcontroller = data->ref();\n\t}\n\n\tif (controller && controller->is_connected())\n\t\tpage_data.m_controller_connected->SetBitmap(m_connected);\n\telse\n\t\tpage_data.m_controller_connected->SetBitmap(m_disconnected);\n\n\t// update controller\n\tpage_data.m_controller_calibrate->Enable(has_controllers);\n\tpage_data.m_controller_api_remove->Enable(has_controllers);\n\tpage_data.m_controller_settings->Enable(controller && has_settings(controller->api()));\n\n\t// update settings\n\t// update panel\n\t// test if we need to update to correct panel\n\tstd::optional<EmulatedController::Type> active_api{};\n\tfor(auto i = 0; i < EmulatedController::Type::MAX; ++i)\n\t{\n\t\tif(page_data.m_panels[i] && page_data.m_panels[i]->IsShown())\n\t\t{\n\t\t\tactive_api = (EmulatedController::Type)i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// disabled and no emulated controller\n\tif (!active_api && !emulated_controller)\n\t\treturn;\n\n\t// enabled correct panel for active controller\n\tif (active_api && emulated_controller && emulated_controller->type() == active_api.value())\n\t{\n\t\t// same controller type panel already shown, refresh content of panels\n\t\tfor (auto* panel : page_data.m_panels)\n\t\t{\n\t\t\tif (panel)\n\t\t\t\tpanel->load_controller(page_data.m_controller);\n\t\t}\n\t\treturn;\n\t}\n\n\t// hide all panels\n\tfor (auto* panel : page_data.m_panels)\n\t{\n\t\tif (panel)\n\t\t\tpanel->Hide();\n\t}\n\n\t// show required panel\n\tif (emulated_controller)\n\t{\n\t\tauto* sizer = dynamic_cast<wxGridBagSizer*>(page->GetSizer());\n\t\twxASSERT(sizer);\n\n\t\tconst auto type = page_data.m_controller->type();\n\t\tInputPanel* panel = page_data.m_panels[type];\n\t\tif (!panel)\n\t\t{\n\t\t\tswitch (type)\n\t\t\t{\n\t\t\tcase EmulatedController::Type::VPAD:\n\t\t\t\tpanel = new VPADInputPanel(page);\n\t\t\t\tbreak;\n\t\t\tcase EmulatedController::Pro:\n\t\t\t\tpanel = new ProControllerInputPanel(page);\n\t\t\t\tbreak;\n\t\t\tcase EmulatedController::Classic:\n\t\t\t\tpanel = new ClassicControllerInputPanel(page);\n\t\t\t\tbreak;\n\t\t\tcase EmulatedController::Wiimote:\n\t\t\t\tpanel = new WiimoteInputPanel(page);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tpage_data.m_panels[type] = panel;\n\n\t\t\tauto* panel_sizer = sizer->FindItemAtPosition(wxGBPosition(7, 0))->GetSizer();\n\t\t\twxASSERT(panel_sizer);\n\t\t\tpanel_sizer->Add(panel, 0, wxEXPAND);\n\t\t}\n\n\t\tpanel->load_controller(page_data.m_controller);\n\t\tif (has_controllers)\n\t\t\tpanel->set_selected_controller(emulated_controller, emulated_controller->get_controllers()[0]);\n\n\t\tpanel->Show();\n\t\tpage->wxWindowBase::Layout();\n\t\tpage->wxWindow::Update();\n\t}\n}\n\nvoid InputSettings2::on_controller_changed()\n{\n\tfor(auto i = 0 ; i < m_notebook->GetPageCount(); ++i)\n\t{\n\t\tauto* page = m_notebook->GetPage(i);\n\t\tif (!page)\n\t\t\tcontinue;\n\n\t\tauto* page_data_ptr = (wxControllerPageData*)page->GetClientObject();\n\t\tif (!page_data_ptr)\n\t\t\tcontinue;\n\n\t\tconst auto& page_data = page_data_ptr->ref();\n\t\tif (page_data.m_controllers->GetSelection() != wxNOT_FOUND)\n\t\t{\n\t\t\tif (const auto data = (wxControllerData*)page_data.m_controllers->GetClientObject(page_data.m_controllers->GetSelection()))\n\t\t\t{\n\t\t\t\tif (const auto controller = data->ref())\n\t\t\t\t{\n\t\t\t\t\tif (controller->connect())\n\t\t\t\t\t\tpage_data.m_controller_connected->SetBitmap(m_connected);\n\t\t\t\t\telse\n\t\t\t\t\t\tpage_data.m_controller_connected->SetBitmap(m_disconnected);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid InputSettings2::on_notebook_page_changed(wxBookCtrlEvent& event)\n{\n\tinitialize_page(event.GetSelection());\n\tupdate_state();\n\tevent.Skip();\n}\n\nvoid InputSettings2::on_timer(wxTimerEvent&)\n{\n\tauto& page_data = get_current_page_data();\n\tif (!page_data.m_controller) {\n\t\treturn;\n\t}\n\n\tauto* panel = page_data.m_panels[page_data.m_controller->type()];\n\tif (!panel)\n\t\treturn;\n\n\tauto controller = get_active_controller();\n\tif (controller) {\n\t\tpanel->on_timer(page_data.m_controller, controller);\n\t}\n}\n\nvoid InputSettings2::on_left_click(wxMouseEvent& event)\n{\n\tevent.Skip();\n\n\tauto& page_data = get_current_page_data();\n\tif (!page_data.m_controller) {\n\t\treturn;\n\t}\n\n\tauto* panel = page_data.m_panels[page_data.m_controller->type()];\n\tif (!panel)\n\t\treturn;\n\n\tpanel->on_left_click(event);\n}\n\nvoid InputSettings2::on_profile_dropdown(wxCommandEvent& event)\n{\n\tauto* profile_names = dynamic_cast<wxComboBox*>(event.GetEventObject());\n\twxASSERT(profile_names);\n\twxWindowUpdateLocker lock(profile_names);\n\t\n\tconst auto selected_value = profile_names->GetStringSelection();\n\tprofile_names->Clear();\n\n\tfor(const auto& profile : InputManager::get_profiles())\n\t{\n\t\tprofile_names->Append(wxString::FromUTF8(profile));\n\t}\n\n\tprofile_names->SetStringSelection(selected_value);\n}\n\nvoid InputSettings2::on_profile_text_changed(wxCommandEvent& event)\n{\n\tauto* profile_names = dynamic_cast<wxComboBox*>(event.GetEventObject());\n\twxASSERT(profile_names);\n\n\tauto& page_data = get_current_page_data();\n\n\t// load_bttn, save_bttn, delete_bttn, profile_status\n\tconst auto text = event.GetString();\n\tconst bool valid_name = InputManager::is_valid_profilename(text.utf8_string());\n\tconst bool name_exists = profile_names->FindString(text) != wxNOT_FOUND;\n\n\tpage_data.m_profile_load->Enable(name_exists);\n\tpage_data.m_profile_save->Enable(valid_name);\n\tpage_data.m_profile_delete->Enable(name_exists);\n\tpage_data.m_profile_status->Hide();\n}\n\nvoid InputSettings2::on_profile_load(wxCommandEvent& event)\n{\n\tauto& page_data = get_current_page_data();\n\n\tauto* profile_names = page_data.m_profiles;\n\tauto* text = page_data.m_profile_status;\n\n\tconst auto selection = profile_names->GetValue().utf8_string();\n\ttext->Show();\n\tif (selection.empty() || !InputManager::is_valid_profilename(selection))\n\t{\n\t\ttext->SetLabelText(_(\"invalid profile name\"));\n\t\ttext->SetForegroundColour(wxTheColourDatabase->Find(\"ERROR\"));\n\t\ttext->Refresh();\n\t\treturn;\n\t}\n\n\tconst auto page_index = m_notebook->GetSelection();\n\tif (InputManager::instance().load(page_index, selection))\n\t{\n\t\ttext->SetLabelText(_(\"profile loaded\"));\n\t\ttext->SetForegroundColour(wxTheColourDatabase->Find(\"SUCCESS\"));\n\t}\n\telse\n\t{\n\t\ttext->SetLabelText(_(\"couldn't load profile\"));\n\t\ttext->SetForegroundColour(wxTheColourDatabase->Find(\"ERROR\"));\n\t}\n\n\ttext->Refresh();\n\n\t// update controller info\n\tpage_data.m_controller = InputManager::instance().get_controller(page_index);\n\tupdate_state();\n}\n\nvoid InputSettings2::on_profile_save(wxCommandEvent& event)\n{\n\tauto& page_data = get_current_page_data();\n\n\tauto* profile_names = page_data.m_profiles;\n\tauto* text = page_data.m_profile_status;\n\n\tconst auto selection = profile_names->GetValue().utf8_string();\n\ttext->Show();\n\tif (selection.empty() || !InputManager::is_valid_profilename(selection))\n\t{\n\t\ttext->SetLabelText(_(\"invalid profile name\"));\n\t\ttext->SetForegroundColour(wxTheColourDatabase->Find(\"ERROR\"));\n\t\ttext->Refresh();\n\t\treturn;\n\t}\n\n\tif(InputManager::instance().save(m_notebook->GetSelection(), selection))\n\t{\n\t\ttext->SetLabelText(_(\"profile saved\"));\n\t\ttext->SetForegroundColour(wxTheColourDatabase->Find(\"SUCCESS\"));\n\t}\n\telse\n\t{\n\t\ttext->SetLabelText(_(\"couldn't save profile\"));\n\t\ttext->SetForegroundColour(wxTheColourDatabase->Find(\"ERROR\"));\n\t}\n\n\ttext->Refresh();\n}\n\nvoid InputSettings2::on_profile_delete(wxCommandEvent& event)\n{\n\tauto& page_data = get_current_page_data();\n\n\tauto* profile_names = page_data.m_profiles;\n\tauto* text = page_data.m_profile_status;\n\n\tconst auto selection = profile_names->GetStringSelection().utf8_string();\n\n\ttext->Show();\n\tif (selection.empty() || !InputManager::is_valid_profilename(selection))\n\t{\n\t\ttext->SetLabelText(_(\"invalid profile name\"));\n\t\ttext->SetForegroundColour(wxTheColourDatabase->Find(\"ERROR\"));\n\t\ttext->Refresh();\n\t\treturn;\n\t}\n\ttry\n\t{\n\t\tconst fs::path old_path = ActiveSettings::GetConfigPath(\"controllerProfiles/{}.txt\", selection);\n\t\tfs::remove(old_path);\n\n\t\tconst fs::path path = ActiveSettings::GetConfigPath(\"controllerProfiles/{}.xml\", selection);\n\t\tfs::remove(path);\n\n\t\tprofile_names->ChangeValue(kDefaultProfileName);\n\t\ttext->SetLabelText(_(\"profile deleted\"));\n\t\ttext->SetForegroundColour(wxTheColourDatabase->Find(\"SUCCESS\"));\n\n\t\tpage_data.m_profile_load->Disable();\n\t\tpage_data.m_profile_save->Disable();\n\t\tpage_data.m_profile_delete->Disable();\n\t}\n\tcatch (const std::exception&)\n\t{\n\t\ttext->SetLabelText(_(\"can't delete profile\"));\n\t\ttext->SetForegroundColour(wxTheColourDatabase->Find(\"ERROR\"));\n\t}\n\ttext->Refresh();\n}\n\n\nvoid InputSettings2::on_controller_page_changed(wxBookCtrlEvent& event)\n{\n\tinitialize_page(event.GetSelection());\n\tupdate_state();\n\tevent.Skip();\n}\n\nvoid InputSettings2::on_emulated_controller_selected(wxCommandEvent& event)\n{\n\tconst auto page_index = m_notebook->GetSelection();\n\tauto& page_data = get_current_page_data();\n\n\tconst auto selection = event.GetSelection();\n\tif(selection == 0) // disabled selected\n\t{\n\t\tpage_data.m_controller = {};\n\t\tInputManager::instance().delete_controller(page_index, true);\n\t}\n\telse\n\t{\n\t\ttry\n\t\t{\n\t\t\tconst auto type = EmulatedController::type_from_string(event.GetString().utf8_string());\n\t\t\t// same has already been selected\n\t\t\tif (page_data.m_controller && page_data.m_controller->type() == type)\n\t\t\t\treturn;\n\n\t\t\t// set new controller\n\t\t\tconst auto new_controller = InputManager::instance().set_controller(page_index, type);\n\t\t\tpage_data.m_controller = new_controller;\n\n\t\t\t// append controllers if some were already added before\n\t\t\tif (new_controller->get_controllers().empty())\n\t\t\t{\n\t\t\t\t// test if we had no emulated controller before but still assigned controllers we want to transfer now\n\t\t\t\tfor (uint32 i = 0; i < page_data.m_controllers->GetCount(); ++i)\n\t\t\t\t{\n\t\t\t\t\tif (auto* controller = (wxControllerData*)page_data.m_controllers->GetClientObject(i))\n\t\t\t\t\t{\n\t\t\t\t\t\tnew_controller->add_controller(controller->ref());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// set default mappings if any controllers available\n\t\t\tfor(const auto& c: new_controller->get_controllers())\n\t\t\t{\n\t\t\t\tnew_controller->set_default_mapping(c);\n\t\t\t}\n\t\t}\n\t\tcatch (const std::exception&)\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t\t\n\t}\n\n\tupdate_state();\n}\n\nvoid InputSettings2::on_emulated_controller_dropdown(wxCommandEvent& event)\n{\n\tauto* emulated_controllers = dynamic_cast<wxComboBox*>(event.GetEventObject());\n\twxASSERT(emulated_controllers);\n\n\twxWindowUpdateLocker lock(emulated_controllers);\n\n\tbool is_gamepad_selected = false;\n\tbool is_wpad_selected = false;\n\tconst auto selected = emulated_controllers->GetSelection();\n\tconst auto selected_value = emulated_controllers->GetStringSelection();\n\tif(selected != wxNOT_FOUND)\n\t{\n\t\tis_gamepad_selected = selected_value == wxString::FromUTF8(EmulatedController::type_to_string(EmulatedController::Type::VPAD));\n\t\tis_wpad_selected = !is_gamepad_selected && selected != 0;\n\t}\n\n\tconst auto [vpad_count, wpad_count] = InputManager::instance().get_controller_count();\n\n\temulated_controllers->Clear();\n\temulated_controllers->AppendString(_(\"Disabled\"));\n\n\tif (vpad_count < InputManager::kMaxVPADControllers || is_gamepad_selected)\n\t\temulated_controllers->Append(wxString::FromUTF8(EmulatedController::type_to_string(EmulatedController::Type::VPAD)));\n\n\tif (wpad_count < InputManager::kMaxWPADControllers || is_wpad_selected)\n\t{\n\t\temulated_controllers->AppendString(wxString::FromUTF8(EmulatedController::type_to_string(EmulatedController::Type::Pro)));\n\t\temulated_controllers->AppendString(wxString::FromUTF8(EmulatedController::type_to_string(EmulatedController::Type::Classic)));\n\t\temulated_controllers->AppendString(wxString::FromUTF8(EmulatedController::type_to_string(EmulatedController::Type::Wiimote)));\n\t}\n\n\temulated_controllers->SetStringSelection(selected_value);\n}\n\nvoid InputSettings2::on_controller_selected(wxCommandEvent& event)\n{\n\tauto& page_data = get_current_page_data();\n\n\tconst auto enabled = event.GetSelection() != wxNOT_FOUND;\n\tpage_data.m_controller_api_remove->Enable(enabled);\n\t// page_data->ref().m_controller_list->Clear();\n\tif(enabled)\n\t{\n\t\t// get selected controller if any todo\n\t\tif (auto* controller = (wxControllerData*)page_data.m_controllers->GetClientObject(event.GetSelection()))\n\t\t{\n\t\t\tpage_data.m_controller_settings->Enable(has_settings(controller->ref()->api()));\n\n\t\t\tif(page_data.m_controller)\n\t\t\t{\n\t\t\t\tpage_data.m_panels[page_data.m_controller->type()]->set_selected_controller(page_data.m_controller, controller->ref());\n\t\t\t}\n\t\t}\n\t\t\n\t}\n}\n\nvoid InputSettings2::on_controller_dropdown(wxCommandEvent& event)\n{\n\tif(auto* controllers = dynamic_cast<wxComboBox*>(event.GetEventObject()))\n\t{\n\t\tif(controllers->GetCount()== 0)\n\t\t{\n\t\t\ton_controller_add(event);\n\t\t\tcontrollers->SetSelection(0);\n\t\t}\n\t}\n}\n\nControllerPage& InputSettings2::get_current_page_data() const\n{\n\tauto* page = m_notebook->GetCurrentPage();\n\tauto* page_data_ptr = (wxControllerPageData*)page->GetClientObject();\n\twxASSERT(page_data_ptr);\n\treturn page_data_ptr->ref();\n}\n\nvoid InputSettings2::on_controller_connect(wxCommandEvent& event)\n{\n\tauto& page_data = get_current_page_data();\n\n\tif (page_data.m_controllers->GetSelection() != wxNOT_FOUND)\n\t{\n\t\tif (const auto data = (wxControllerData*)page_data.m_controllers->GetClientObject(page_data.m_controllers->GetSelection()))\n\t\t{\n\t\t\tif(const auto controller = data->ref())\n\t\t\t{\n\t\t\t\tif(controller->connect())\n\t\t\t\t\tpage_data.m_controller_connected->SetBitmap(m_connected);\n\t\t\t\telse\n\t\t\t\t\tpage_data.m_controller_connected->SetBitmap(m_disconnected);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid InputSettings2::on_controller_add(wxCommandEvent& event)\n{\n\tauto& page_data = get_current_page_data();\n\n\tstd::vector<ControllerPtr> controllers;\n\tcontrollers.reserve(page_data.m_controllers->GetCount());\n\tfor(uint32 i = 0; i < page_data.m_controllers->GetCount(); ++i)\n\t{\n\t\tif (auto* controller = (wxControllerData*)page_data.m_controllers->GetClientObject(i))\n\t\t\tcontrollers.emplace_back(controller->ref());\n\t}\n\n\tInputAPIAddWindow wnd(this, wxGetMousePosition() + wxSize(5, 5), controllers);\n\tif (wnd.ShowModal() != wxID_OK)\n\t\treturn;\n\n\twxASSERT(wnd.is_valid());\n\n\tconst auto controller = wnd.get_controller();\n\n\tconst auto api_type = wnd.get_type();\n\tcontroller->connect();\n\tconst int index = page_data.m_controllers->Append(fmt::format(\"{} [{}]\", controller->display_name(), to_string(api_type)), new wxCustomData(controller));\n\n\tpage_data.m_controllers->Select(index);\n\t\n\tif(page_data.m_controller)\n\t{\n\t\tpage_data.m_controller->add_controller(controller);\n\n\t\tconst auto type = page_data.m_controller->type();\n\t\t// if first controller and we got no mappings, add default mappings\n\t\tif(page_data.m_controller->set_default_mapping(controller))\n\t\t\tpage_data.m_panels[type]->load_controller(page_data.m_controller);\n\t\t\n\t\tpage_data.m_panels[type]->set_selected_controller(page_data.m_controller, controller);\n\t}\n\n\tupdate_state();\n}\n\nvoid InputSettings2::on_controller_remove(wxCommandEvent& event)\n{\n\tauto& page_data = get_current_page_data();\n\n\tauto* api_box = page_data.m_controllers;\n\tint selection = api_box->GetSelection();\n\tif (selection == wxNOT_FOUND)\n\t\treturn;\n\n\tif (page_data.m_controller) {\n\t\tif (auto* controller = (wxControllerData*)page_data.m_controllers->GetClientObject(selection))\n\t\t{\n\t\t\tpage_data.m_controller->remove_controller(controller->ref());\n\t\t\tpage_data.m_panels[page_data.m_controller->type()]->load_controller(page_data.m_controller);\n\t\t}\n\t}\n\n\tpage_data.m_panels[page_data.m_controller->type()]->reset_colours();\n\n\tapi_box->Delete(selection);\n\tapi_box->Refresh();\n\n\tupdate_state();\n\n\tif (api_box->GetCount() > 0)\n\t{\n\t\tselection = selection > 0 ? (selection - 1) : 0;\n\t\tapi_box->SetSelection(selection);\n\t}\n\n\tupdate_state();\n}\n\nvoid InputSettings2::on_controller_calibrate(wxCommandEvent& event)\n{\n\tif(const auto controller = get_active_controller())\n\t\tcontroller->calibrate();\n}\n\nvoid InputSettings2::on_controller_clear(wxCommandEvent& event)\n{\n\tauto& page_data = get_current_page_data();\n\tif (page_data.m_controller) {\n\t\tconst auto type = page_data.m_controller->type();\n\n\t\tpage_data.m_panels[type]->reset_configuration();\n\t\tpage_data.m_controller->clear_mappings();\n\t}\n}\n\nvoid InputSettings2::on_controller_settings(wxCommandEvent& event)\n{\n\tauto controller = get_active_controller();\n\tif (!controller)\n\t\treturn;\n\n\tswitch(controller->api())\n\t{\n\t\n\tcase InputAPI::DirectInput:\n\tcase InputAPI::XInput:\n\tcase InputAPI::GameCube:\n\tcase InputAPI::WGIGamepad:\n\tcase InputAPI::WGIRawController:\n\tcase InputAPI::SDLController:\n\tcase InputAPI::DSUClient:\n\t{\n\t\tDefaultControllerSettings wnd(this, wxGetMousePosition() + wxSize(5, 5), controller);\n\t\twnd.ShowModal();\n\t\tbreak;\n\t}\n\n\tcase InputAPI::Keyboard: break;\n\n\t#ifdef SUPPORTS_WIIMOTE\n\tcase InputAPI::Wiimote: {\n\t\tconst auto wiimote = std::dynamic_pointer_cast<NativeWiimoteController>(controller);\n\t\twxASSERT(wiimote);\n\t\tWiimoteControllerSettings wnd(this, wxGetMousePosition() + wxSize(5, 5), wiimote);\n\t\twnd.ShowModal();\n\t\tbreak;\n\t}\n\t#endif\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/input/InputSettings2.h",
    "content": "#pragma once\n\n#include <wx/dialog.h>\n#include <wx/notebook.h>\n#include <wx/timer.h>\n\n#include \"input/api/InputAPI.h\"\n\n#include <boost/signals2/connection.hpp>\n\nstruct ControllerPage;\nclass ControllerBase;\n\nclass InputSettings2 : public wxDialog\n{\npublic:\n\tInputSettings2(wxWindow* parent);\n\t~InputSettings2();\n\nprivate:\n\tconst wxString kDefaultProfileName = _(\"<profile name>\");\n\n\twxNotebook* m_notebook;\n\twxTimer* m_timer;\n\n\twxBitmap m_connected, m_disconnected, m_low_battery;\n\n\twxWindow* initialize_page(size_t index);\n\n\t// currently selected controller from active tab\n\tstd::shared_ptr<ControllerBase> get_active_controller() const;\n\n\tbool has_settings(InputAPI::Type type);\n\tControllerPage& get_current_page_data() const;\n\tvoid update_state();\n\n\tboost::signals2::connection m_controller_changed;\n\tvoid on_controller_changed();\n\n\t// events\n\tvoid on_notebook_page_changed(wxBookCtrlEvent& event);\n\tvoid on_timer(wxTimerEvent& event);\n\n\tvoid on_left_click(wxMouseEvent& event);\n\n\tvoid on_controller_page_changed(wxBookCtrlEvent& event);\n\n\tvoid on_profile_dropdown(wxCommandEvent& event);\n\tvoid on_profile_text_changed(wxCommandEvent& event);\n\n\tvoid on_profile_load(wxCommandEvent& event);\n\tvoid on_profile_save(wxCommandEvent& event);\n\tvoid on_profile_delete(wxCommandEvent& event);\n\n\tvoid on_emulated_controller_selected(wxCommandEvent& event);\n\tvoid on_emulated_controller_dropdown(wxCommandEvent& event);\n\n\tvoid on_controller_selected(wxCommandEvent& event);\n\tvoid on_controller_dropdown(wxCommandEvent& event);\n\tvoid on_controller_connect(wxCommandEvent& event);\n\n\tvoid on_controller_add(wxCommandEvent& event);\n\tvoid on_controller_remove(wxCommandEvent& event);\n\n\tvoid on_controller_calibrate(wxCommandEvent& event);\n\tvoid on_controller_clear(wxCommandEvent& event);\n\tvoid on_controller_settings(wxCommandEvent& event);\n\n\t// void on_controller_dropdown(wxCommandEvent& event);\n\t// void on_controllers_refreshed(wxCommandEvent& event);\n\n};\n\n"
  },
  {
    "path": "src/gui/wxgui/input/PairingDialog.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"PairingDialog.h\"\n\n#if BOOST_OS_WINDOWS\n#include <bluetoothapis.h>\n#endif\n#if BOOST_OS_LINUX\n#include <bluetooth/bluetooth.h>\n#include <bluetooth/hci.h>\n#include <bluetooth/hci_lib.h>\n#include <input/api/Wiimote/l2cap/L2CapWiimote.h>\n#endif\n\nwxDECLARE_EVENT(wxEVT_PROGRESS_PAIR, wxCommandEvent);\nwxDEFINE_EVENT(wxEVT_PROGRESS_PAIR, wxCommandEvent);\n\nPairingDialog::PairingDialog(wxWindow* parent)\n\t: wxDialog(parent, wxID_ANY, _(\"Pairing...\"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX)\n{\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\tm_gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(350, 20), wxGA_HORIZONTAL);\n\tm_gauge->SetValue(0);\n\tsizer->Add(m_gauge, 0, wxALL | wxEXPAND, 5);\n\n\tauto* rows = new wxFlexGridSizer(0, 2, 0, 0);\n\trows->AddGrowableCol(1);\n\n\tm_text = new wxStaticText(this, wxID_ANY, _(\"Searching for controllers...\"));\n\trows->Add(m_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t{\n\t\tauto* right_side = new wxBoxSizer(wxHORIZONTAL);\n\n\t\tm_cancelButton = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\t\tm_cancelButton->Bind(wxEVT_BUTTON, &PairingDialog::OnCancelButton, this);\n\t\tright_side->Add(m_cancelButton, 0, wxALL, 5);\n\n\t\trows->Add(right_side, 1, wxALIGN_RIGHT, 5);\n\t}\n\n\tsizer->Add(rows, 0, wxALL | wxEXPAND, 5);\n\n\tSetSizerAndFit(sizer);\n\tCentre(wxBOTH);\n\n\tBind(wxEVT_CLOSE_WINDOW, &PairingDialog::OnClose, this);\n\tBind(wxEVT_PROGRESS_PAIR, &PairingDialog::OnGaugeUpdate, this);\n\n\tm_thread = std::thread(&PairingDialog::WorkerThread, this);\n}\n\nPairingDialog::~PairingDialog()\n{\n\tUnbind(wxEVT_CLOSE_WINDOW, &PairingDialog::OnClose, this);\n}\n\nvoid PairingDialog::OnClose(wxCloseEvent& event)\n{\n\tevent.Skip();\n\n\tm_threadShouldQuit = true;\n\tif (m_thread.joinable())\n\t\tm_thread.join();\n}\n\nvoid PairingDialog::OnCancelButton(const wxCommandEvent& event)\n{\n\tClose();\n}\n\nvoid PairingDialog::OnGaugeUpdate(wxCommandEvent& event)\n{\n\tPairingState state = (PairingState)event.GetInt();\n\n\tswitch (state)\n\t{\n\tcase PairingState::Pairing:\n\t{\n\t\tm_text->SetLabel(_(\"Found controller. Pairing...\"));\n\t\tm_gauge->SetValue(50);\n\t\tbreak;\n\t}\n\n\tcase PairingState::Finished:\n\t{\n\t\tm_text->SetLabel(_(\"Successfully paired the controller.\"));\n\t\tm_gauge->SetValue(100);\n\t\tm_cancelButton->SetLabel(_(\"Close\"));\n\t\tbreak;\n\t}\n\n\tcase PairingState::NoBluetoothAvailable:\n\t{\n\t\tm_text->SetLabel(_(\"Failed to find a suitable Bluetooth radio.\"));\n\t\tm_gauge->SetValue(0);\n\t\tm_cancelButton->SetLabel(_(\"Close\"));\n\t\tbreak;\n\t}\n\n\tcase PairingState::SearchFailed:\n\t{\n\t\tm_text->SetLabel(_(\"Failed to find controllers.\"));\n\t\tm_gauge->SetValue(0);\n\t\tm_cancelButton->SetLabel(_(\"Close\"));\n\t\tbreak;\n\t}\n\n\tcase PairingState::PairingFailed:\n\t{\n\t\tm_text->SetLabel(_(\"Failed to pair with the found controller.\"));\n\t\tm_gauge->SetValue(0);\n\t\tm_cancelButton->SetLabel(_(\"Close\"));\n\t\tbreak;\n\t}\n\n\tcase PairingState::BluetoothUnusable:\n\t{\n\t\tm_text->SetLabel(_(\"Please use your system's Bluetooth manager instead.\"));\n\t\tm_gauge->SetValue(0);\n\t\tm_cancelButton->SetLabel(_(\"Close\"));\n\t\tbreak;\n\t}\n\n\tdefault:\n\t{\n\t\tbreak;\n\t}\n\t}\n}\n\n#if BOOST_OS_WINDOWS\nvoid PairingDialog::WorkerThread()\n{\n\tconst std::wstring wiimoteName = L\"Nintendo RVL-CNT-01\";\n\tconst std::wstring wiiUProControllerName = L\"Nintendo RVL-CNT-01-UC\";\n\n\tconst GUID bthHidGuid = {0x00001124, 0x0000, 0x1000, {0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}};\n\n\tconst BLUETOOTH_FIND_RADIO_PARAMS radioFindParams =\n\t\t{\n\t\t\t.dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS)};\n\n\tHANDLE radio = INVALID_HANDLE_VALUE;\n\tHBLUETOOTH_RADIO_FIND radioFind = BluetoothFindFirstRadio(&radioFindParams, &radio);\n\tif (radioFind == nullptr)\n\t{\n\t\tUpdateCallback(PairingState::NoBluetoothAvailable);\n\t\treturn;\n\t}\n\n\tBluetoothFindRadioClose(radioFind);\n\n\tBLUETOOTH_RADIO_INFO radioInfo =\n\t\t{\n\t\t\t.dwSize = sizeof(BLUETOOTH_RADIO_INFO)};\n\n\tDWORD result = BluetoothGetRadioInfo(radio, &radioInfo);\n\tif (result != ERROR_SUCCESS)\n\t{\n\t\tUpdateCallback(PairingState::NoBluetoothAvailable);\n\t\treturn;\n\t}\n\n\tconst BLUETOOTH_DEVICE_SEARCH_PARAMS searchParams =\n\t\t{\n\t\t\t.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS),\n\n\t\t\t.fReturnAuthenticated = FALSE,\n\t\t\t.fReturnRemembered = FALSE,\n\t\t\t.fReturnUnknown = TRUE,\n\t\t\t.fReturnConnected = FALSE,\n\n\t\t\t.fIssueInquiry = TRUE,\n\t\t\t.cTimeoutMultiplier = 5,\n\n\t\t\t.hRadio = radio};\n\n\tBLUETOOTH_DEVICE_INFO info =\n\t\t{\n\t\t\t.dwSize = sizeof(BLUETOOTH_DEVICE_INFO)};\n\n\twhile (!m_threadShouldQuit)\n\t{\n\t\tHBLUETOOTH_DEVICE_FIND deviceFind = BluetoothFindFirstDevice(&searchParams, &info);\n\t\tif (deviceFind == nullptr)\n\t\t{\n\t\t\tUpdateCallback(PairingState::SearchFailed);\n\t\t\treturn;\n\t\t}\n\n\t\twhile (!m_threadShouldQuit)\n\t\t{\n\t\t\tif (info.szName == wiimoteName || info.szName == wiiUProControllerName)\n\t\t\t{\n\t\t\t\tBluetoothFindDeviceClose(deviceFind);\n\n\t\t\t\tUpdateCallback(PairingState::Pairing);\n\n\t\t\t\twchar_t passwd[6] = {radioInfo.address.rgBytes[0], radioInfo.address.rgBytes[1], radioInfo.address.rgBytes[2], radioInfo.address.rgBytes[3], radioInfo.address.rgBytes[4], radioInfo.address.rgBytes[5]};\n\t\t\t\tDWORD bthResult = BluetoothAuthenticateDevice(nullptr, radio, &info, passwd, 6);\n\t\t\t\tif (bthResult != ERROR_SUCCESS)\n\t\t\t\t{\n\t\t\t\t\tUpdateCallback(PairingState::PairingFailed);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tbthResult = BluetoothSetServiceState(radio, &info, &bthHidGuid, BLUETOOTH_SERVICE_ENABLE);\n\t\t\t\tif (bthResult != ERROR_SUCCESS)\n\t\t\t\t{\n\t\t\t\t\tUpdateCallback(PairingState::PairingFailed);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tUpdateCallback(PairingState::Finished);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tBOOL nextDevResult = BluetoothFindNextDevice(deviceFind, &info);\n\t\t\tif (nextDevResult == FALSE)\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tBluetoothFindDeviceClose(deviceFind);\n\t}\n}\n#elif defined(HAS_BLUEZ)\nvoid PairingDialog::WorkerThread()\n{\n\tconstexpr static uint8_t LIAC_LAP[] = {0x00, 0x8b, 0x9e};\n\n\tconstexpr static auto isWiimoteName = [](std::string_view name) {\n\t\treturn name == \"Nintendo RVL-CNT-01\" || name == \"Nintendo RVL-CNT-01-TR\";\n\t};\n\n\t// Get default BT device\n\tconst auto hostId = hci_get_route(nullptr);\n\tif (hostId < 0)\n\t{\n\t\tUpdateCallback(PairingState::NoBluetoothAvailable);\n\t\treturn;\n\t}\n\n\t// Search for device\n\tinquiry_info* infos = nullptr;\n\tm_cancelButton->Disable();\n\tconst auto respCount = hci_inquiry(hostId, 7, 4, LIAC_LAP, &infos, IREQ_CACHE_FLUSH);\n\tm_cancelButton->Enable();\n\tif (respCount <= 0)\n\t{\n\t\tUpdateCallback(PairingState::SearchFailed);\n\t\treturn;\n\t}\n\tstdx::scope_exit infoFree([&]() { bt_free(infos);});\n\n\tif (m_threadShouldQuit)\n\t\treturn;\n\n\t// Open dev to read name\n\tconst auto hostDev = hci_open_dev(hostId);\n\tstdx::scope_exit devClose([&]() { hci_close_dev(hostDev);});\n\n\tchar nameBuffer[HCI_MAX_NAME_LENGTH] = {};\n\n\tbool foundADevice = false;\n\t// Get device name and compare. Would use product and vendor id from SDP, but many third-party Wiimotes don't store them\n\tfor (const auto& devInfo : std::span(infos, respCount))\n\t{\n\t\tconst auto& addr = devInfo.bdaddr;\n\t\tconst auto err =  hci_read_remote_name(hostDev, &addr, HCI_MAX_NAME_LENGTH, nameBuffer,\n\t\t\t\t\t\t\t\t 2000);\n\t\tif (m_threadShouldQuit)\n\t\t\treturn;\n\t\tif (err || !isWiimoteName(nameBuffer))\n\t\t\tcontinue;\n\n\t\tL2CapWiimote::AddCandidateAddress(addr);\n\t\tfoundADevice = true;\n\t\tconst auto& b = addr.b;\n\t\tcemuLog_log(LogType::Force, \"Pairing Dialog: Found '{}' with address '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'\",\n\t\t\t\t\tnameBuffer, b[5], b[4], b[3], b[2], b[1], b[0]);\n\t}\n\tif (foundADevice)\n\t\tUpdateCallback(PairingState::Finished);\n\telse\n\t\tUpdateCallback(PairingState::SearchFailed);\n}\n#else\nvoid PairingDialog::WorkerThread()\n{\n\tUpdateCallback(PairingState::BluetoothUnusable);\n}\n#endif\nvoid PairingDialog::UpdateCallback(PairingState state)\n{\n\tauto* event = new wxCommandEvent(wxEVT_PROGRESS_PAIR);\n\tevent->SetInt((int)state);\n\twxQueueEvent(this, event);\n}"
  },
  {
    "path": "src/gui/wxgui/input/PairingDialog.h",
    "content": "#pragma once\n\n#include <wx/button.h>\n#include <wx/dialog.h>\n#include <wx/gauge.h>\n#include <wx/stattext.h>\n\nclass PairingDialog : public wxDialog\n{\npublic:\n\tPairingDialog(wxWindow* parent);\n\t~PairingDialog();\n\nprivate:\n    enum class PairingState\n    {\n        Pairing,\n        Finished,\n        NoBluetoothAvailable,\n\t  \tSearchFailed,\n        PairingFailed,\n        BluetoothUnusable\n    };\n\n    void OnClose(wxCloseEvent& event);\n    void OnCancelButton(const wxCommandEvent& event);\n    void OnGaugeUpdate(wxCommandEvent& event);\n\n    void WorkerThread();\n    void UpdateCallback(PairingState state);\n\n    wxStaticText* m_text;\n    wxGauge* m_gauge;\n    wxButton* m_cancelButton;\n\n    std::thread m_thread;\n    bool m_threadShouldQuit = false;\n};\n"
  },
  {
    "path": "src/gui/wxgui/input/panels/ClassicControllerInputPanel.cpp",
    "content": "#include \"wxgui/input/panels/ClassicControllerInputPanel.h\"\n\n#include <wx/gbsizer.h>\n#include <wx/stattext.h>\n#include <wx/statline.h>\n#include <wx/textctrl.h>\n#include <wx/slider.h>\n\n#include \"wxgui/helpers/wxControlObject.h\"\n#include \"input/emulated/ClassicController.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/components/wxInputDraw.h\"\n\nconstexpr ClassicController::ButtonId g_kFirstColumnItems[] = { ClassicController::kButtonId_A, ClassicController::kButtonId_B, ClassicController::kButtonId_X, ClassicController::kButtonId_Y, ClassicController::kButtonId_L, ClassicController::kButtonId_R, ClassicController::kButtonId_ZL, ClassicController::kButtonId_ZR, ClassicController::kButtonId_Plus, ClassicController::kButtonId_Minus };\nconstexpr ClassicController::ButtonId g_kSecondColumnItems[] = { ClassicController::kButtonId_StickL_Up, ClassicController::kButtonId_StickL_Down, ClassicController::kButtonId_StickL_Left, ClassicController::kButtonId_StickL_Right };\nconstexpr ClassicController::ButtonId g_kThirdColumnItems[] = { ClassicController::kButtonId_StickR_Up, ClassicController::kButtonId_StickR_Down, ClassicController::kButtonId_StickR_Left, ClassicController::kButtonId_StickR_Right };\nconstexpr ClassicController::ButtonId g_kFourthRowItems[] = { ClassicController::kButtonId_Up, ClassicController::kButtonId_Down, ClassicController::kButtonId_Left, ClassicController::kButtonId_Right };\n\n\nClassicControllerInputPanel::ClassicControllerInputPanel(wxWindow* parent)\n\t: InputPanel(parent)\n{\n\tauto bold_font = GetFont();\n\tbold_font.MakeBold();\n\n\tauto* main_sizer = new wxGridBagSizer();\n\tsint32 row = 0;\n\tsint32 column = 0;\n\tfor (const auto& id : g_kFirstColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\t//////////////////////////////////////////////////////////////////\n\n\tmain_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 2), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);\n\n\trow = 0;\n\tcolumn += 3;\n\n\tauto text = new wxStaticText(this, wxID_ANY, _(\"Left Axis\"));\n\ttext->SetFont(bold_font);\n\tmain_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (const auto& id : g_kSecondColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\trow++;\n\t\n\t// input drawer\n\tm_left_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\tmain_sizer->Add(m_left_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);\n\n\tmain_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);\n\n\t//////////////////////////////////////////////////////////////////\n\n\trow = 0;\n\tcolumn += 4;\n\n\ttext = new wxStaticText(this, wxID_ANY, _(\"Right Axis\"));\n\ttext->SetFont(bold_font);\n\tmain_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (const auto& id : g_kThirdColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\trow++;\n\n\t// input drawer\n\tm_right_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\tmain_sizer->Add(m_right_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);\n\n\tmain_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);\n\n\t//////////////////////////////////////////////////////////////////\n\n\trow = 0;\n\tcolumn += 4;\n\n\ttext = new wxStaticText(this, wxID_ANY, _(\"D-pad\"));\n\ttext->SetFont(bold_font);\n\tmain_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (auto id : g_kFourthRowItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\t//////////////////////////////////////////////////////////////////\n\n\tSetSizer(main_sizer);\n\tLayout();\n}\n\nvoid ClassicControllerInputPanel::add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const ClassicController::ButtonId &button_id) {\n\tsizer->Add(\n\t\tnew wxStaticText(this, wxID_ANY, wxGetTranslation(wxString::FromUTF8(ClassicController::get_button_name(button_id)))),\n\t\twxGBPosition(row, column),\n\t\twxDefaultSpan,\n\t\twxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\tauto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);\n\ttext_ctrl->SetClientData(reinterpret_cast<void*>(button_id));\n\ttext_ctrl->SetMinSize(wxSize(150, -1));\n\ttext_ctrl->SetEditable(false);\n\ttext_ctrl->SetBackgroundColour(kKeyColourNormalMode);\n\tbind_hotkey_events(text_ctrl);\n\tsizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);\n}\n"
  },
  {
    "path": "src/gui/wxgui/input/panels/ClassicControllerInputPanel.h",
    "content": "#pragma once\n\n#include <wx/gbsizer.h>\n#include \"input/emulated/ClassicController.h\"\n#include \"wxgui/input/panels/InputPanel.h\"\n\nclass wxInputDraw;\n\nclass ClassicControllerInputPanel : public InputPanel\n{\npublic:\n\tClassicControllerInputPanel(wxWindow* parent);\n\nprivate:\n\twxInputDraw* m_left_draw, * m_right_draw;\n\n\tvoid add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const ClassicController::ButtonId &button_id);\n};\n\n"
  },
  {
    "path": "src/gui/wxgui/input/panels/InputPanel.cpp",
    "content": "#include \"wxgui/input/panels/InputPanel.h\"\n\n#include <wx/textctrl.h>\n#include <wx/wupdlock.h>\n\n#include \"wxgui/helpers/wxHelpers.h\"\n\nInputPanel::InputPanel(wxWindow* parent)\n\t: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxWANTS_CHARS)\n{\n\tBind(wxEVT_LEFT_UP, &InputPanel::on_left_click, this);\n}\n\nvoid InputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller)\n{\n\tconst auto& state = controller->update_state();\n\n\tif(m_focused_element == wxID_NONE)\n\t{\n\t\treturn;\n\t}\n\n\tconst auto element = dynamic_cast<wxTextCtrl*>(FindWindow(m_focused_element));\n\twxASSERT(element);\n\n\tconst auto mapping = reinterpret_cast<uint64>(element->GetClientData());\n\n\t// reset mapping\n\tif(std::exchange(m_right_down, false) || WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::ESCAPE))\n\t{\n\t\telement->SetBackgroundColour(kKeyColourNormalMode);\n\t\tm_color_backup[element->GetId()] = kKeyColourNormalMode;\n\n\t\temulated_controller->delete_mapping(mapping);\n\t\tif(element->IsEmpty())\n\t\t\treset_focused_element();\n\t\telse\n\t\t\telement->SetValue(wxEmptyString);\n\n\t\treturn;\n\t}\n\n\tstatic bool s_was_idle = true;\n\tif (state.buttons.IsIdle()) \n\t{\n\t\ts_was_idle = true;\n\t\treturn;\n\t}\n\n\tif (!s_was_idle) \n\t{\n\t\treturn;\n\t}\n\ts_was_idle = false;\n\tfor(const auto& id : state.buttons.GetButtonList())\n\t{\n\t\tif (controller->has_axis())\n\t\t{\n\t\t\t// test if one axis direction is pressed more than the other\n\t\t\tif ((id == kAxisXP || id == kAxisXN) && (state.buttons.GetButtonState(kAxisYP) || state.buttons.GetButtonState(kAxisYN)))\n\t\t\t{\n\t\t\t\tif (std::abs(state.axis.y) > std::abs(state.axis.x))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if ((id == kAxisYP || id == kAxisYN) && (state.buttons.GetButtonState(kAxisXP) || state.buttons.GetButtonState(kAxisXN)))\n\t\t\t{\n\t\t\t\tif (std::abs(state.axis.x) > std::abs(state.axis.y))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if ((id == kRotationXP || id == kRotationXN) && (state.buttons.GetButtonState(kRotationYP) || state.buttons.GetButtonState(kRotationYN)))\n\t\t\t{\n\t\t\t\tif (std::abs(state.rotation.y) > std::abs(state.rotation.x))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if ((id == kRotationYP || id == kRotationYN) && (state.buttons.GetButtonState(kRotationXP) || state.buttons.GetButtonState(kRotationXN)))\n\t\t\t{\n\t\t\t\tif (std::abs(state.rotation.x) > std::abs(state.rotation.y))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if ((id == kTriggerXP || id == kTriggerXN) && (state.buttons.GetButtonState(kTriggerYP) || state.buttons.GetButtonState(kTriggerYN)))\n\t\t\t{\n\t\t\t\tif (std::abs(state.trigger.y) > std::abs(state.trigger.x))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse if ((id == kTriggerYP || id == kTriggerYN) && (state.buttons.GetButtonState(kTriggerXP) || state.buttons.GetButtonState(kTriggerXN)))\n\t\t\t{\n\t\t\t\tif (std::abs(state.trigger.x) > std::abs(state.trigger.y))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// ignore too low button values on configuration\n\t\t\tif (id >= kButtonAxisStart)\n\t\t\t{\n\t\t\t\tif (controller->get_axis_value(id) < 0.33f) {\n\t\t\t\t\tcemuLog_logDebug(LogType::Force, \"skipping since value too low {}\", controller->get_axis_value(id));\n\t\t\t\t\ts_was_idle = true;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\temulated_controller->set_mapping(mapping, controller, id);\n\t\telement->SetValue(controller->get_button_name(id));\n\t\telement->SetBackgroundColour(kKeyColourNormalMode);\n\t\tm_color_backup[element->GetId()] = kKeyColourNormalMode;\n\t\tbreak;\n\t}\n\n\tif (const auto sibling = get_next_sibling(element))\n\t\tsibling->SetFocus();\n\telse // last element reached \n\t{\n\t\treset_focused_element();\n\t\tthis->SetFocusIgnoringChildren();\n\t}\n}\n\nvoid InputPanel::reset_configuration()\n{\n\tm_color_backup.clear();\n\n\twxWindowUpdateLocker lock(this);\n\tfor (const auto& c : GetChildren())\n\t{\n\t\tif (auto* text = dynamic_cast<wxTextCtrl*>(c))\n\t\t{\n\t\t\ttext->SetValue(wxEmptyString);\n\t\t\ttext->SetBackgroundColour(kKeyColourNormalMode);\n\t\t\ttext->Refresh();\n\t\t}\n\t}\n}\n\nvoid InputPanel::reset_colours()\n{\n\tm_color_backup.clear();\n\n\twxWindowUpdateLocker lock(this);\n\tfor (const auto& c : GetChildren())\n\t{\n\t\tif (auto* text = dynamic_cast<wxTextCtrl*>(c))\n\t\t{\n\t\t\ttext->SetBackgroundColour(kKeyColourNormalMode);\n\t\t\ttext->Refresh();\n\t\t}\n\t}\n}\n\n\nvoid InputPanel::load_controller(const EmulatedControllerPtr& controller)\n{\n\treset_configuration();\n\tif(!controller)\n\t{\n\t\treturn;\n\t}\n\n\tif(controller->get_controllers().empty())\n\t{\n\t\treturn;\n\t}\n\n\twxWindowUpdateLocker lock(this);\n\tfor (auto* child : this->GetChildren())\n\t{\n\t\tconst auto text = dynamic_cast<wxTextCtrl*>(child);\n\t\tif (text == nullptr)\n\t\t\tcontinue;\n\n\n\t\tconst auto mapping = reinterpret_cast<sint64>(text->GetClientData());\n\t\tif (mapping <= 0)\n\t\t\tcontinue;\n\n\t\tauto button_name = controller->get_mapping_name(mapping);\n\t\ttext->ChangeValue(button_name);\n\t}\n}\n\nvoid InputPanel::set_selected_controller(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller)\n{\n\twxWindowUpdateLocker lock(this);\n\tfor (auto* child : this->GetChildren())\n\t{\n\t\tconst auto text = dynamic_cast<wxTextCtrl*>(child);\n\t\tif (text == nullptr)\n\t\t\tcontinue;\n\n\t\tif (text->GetId() == m_focused_element)\n\t\t\tcontinue;\n\n\t\tconst auto mapping = reinterpret_cast<sint64>(text->GetClientData());\n\t\tif (mapping <= 0)\n\t\t\tcontinue;\n\n\t\tconst auto mapping_controller = emulated_controller->get_mapping_controller(mapping);\n\t\tif (!mapping_controller)\n\t\t\tcontinue;\n\n\t\ttext->SetBackgroundColour(*mapping_controller == *controller ? kKeyColourNormalMode : kKeyColourActiveMode);\n\t\ttext->Refresh();\n\t}\n}\n\nvoid InputPanel::bind_hotkey_events(wxTextCtrl* text_ctrl)\n{\n\ttext_ctrl->Bind(wxEVT_SET_FOCUS, &InputPanel::on_edit_key_focus, this);\n\ttext_ctrl->Bind(wxEVT_KILL_FOCUS, &InputPanel::on_edit_key_kill_focus, this);\n\ttext_ctrl->Bind(wxEVT_RIGHT_DOWN, &InputPanel::on_right_click, this);\n#if BOOST_OS_LINUX\n\t// Bind to a no-op lambda to disable arrow keys navigation\n\ttext_ctrl->Bind(wxEVT_KEY_DOWN, [](wxKeyEvent &) {});\n#endif\n}\n\nvoid InputPanel::on_left_click(wxMouseEvent& event)\n{\n\tif (m_focused_element == wxID_NONE)\n\t\treturn;\n\n\tconst auto focuses_element = FindWindow(m_focused_element);\n\twxASSERT(focuses_element);\n\n\twxFocusEvent focus(wxEVT_KILL_FOCUS, m_focused_element);\n\tfocus.SetWindow(focuses_element);\n\tfocuses_element->GetEventHandler()->ProcessEvent(focus);\n\n\tthis->SetFocusIgnoringChildren();\n}\n\nvoid InputPanel::on_edit_key_focus(wxFocusEvent& event)\n{\n\tauto* text = dynamic_cast<wxTextCtrl*>(event.GetEventObject());\n\twxASSERT(text);\n\n\tm_color_backup[text->GetId()] = text->GetBackgroundColour();\n\n\ttext->SetBackgroundColour(kKeyColourEditMode);\n\t#if BOOST_OS_WINDOWS\n\ttext->HideNativeCaret();\n\t#endif\n\ttext->Refresh();\n\n\tm_focused_element = text->GetId();\n\tevent.Skip();\n}\n\nvoid InputPanel::on_edit_key_kill_focus(wxFocusEvent& event)\n{\n\treset_focused_element();\n\tevent.Skip();\n}\n\nvoid InputPanel::on_right_click(wxMouseEvent& event)\n{\n\tm_right_down = true;\n\tif(m_focused_element == wxID_NONE)\n\t{\n\t\tauto* text = dynamic_cast<wxTextCtrl*>(event.GetEventObject());\n\t\twxASSERT(text);\n\t\ttext->SetFocus();\n\t}\n}\n\nbool InputPanel::reset_focused_element()\n{\n\tif (m_focused_element == wxID_NONE)\n\t\treturn false;\n\n\tauto* prev_element = dynamic_cast<wxTextCtrl*>(FindWindow(m_focused_element));\n\twxASSERT(prev_element);\n\n\tif(m_color_backup.find(prev_element->GetId()) != m_color_backup.cend())\n\t\tprev_element->SetBackgroundColour(m_color_backup[prev_element->GetId()]);\n\telse\n\t\tprev_element->SetBackgroundColour(kKeyColourNormalMode);\n\n#if BOOST_OS_WINDOWS\n\tprev_element->HideNativeCaret();\n#endif\n\tprev_element->Refresh();\n\t\n\tm_focused_element = wxID_NONE;\n\treturn true;\n}\n"
  },
  {
    "path": "src/gui/wxgui/input/panels/InputPanel.h",
    "content": "#pragma once\n\n#include <wx/panel.h>\n#include <wx/settings.h>\n\n#include \"input/emulated/EmulatedController.h\"\n#include \"input/api/Controller.h\"\n\n#include \"wxgui/wxHelper.h\"\n\nclass ControllerBase;\nclass wxTextCtrl;\nclass wxComboBox;\n\nclass InputPanel : public wxPanel\n{\npublic:\n\tconst wxColour kKeyColourNormalMode = GetBackgroundColour();\n\tconst wxColour kKeyColourEditMode = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);\n\tconst wxColour kKeyColourActiveMode = wxHelper::CalculateAccentColour(GetBackgroundColour());\n\n\tInputPanel(wxWindow* parent);\n\n\tControllerPtr get_active_controller() const;\n\n\tvirtual void on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller);\n\tvoid on_left_click(wxMouseEvent& event);\n\n\tvoid reset_configuration();\n\tvirtual void load_controller(const EmulatedControllerPtr& controller);\n\n\tvoid set_selected_controller(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller_base);\n\tvoid reset_colours();\n\nprotected:\n\tvoid bind_hotkey_events(wxTextCtrl* text_ctrl);\n\n\tvoid on_edit_key_focus(wxFocusEvent& event);\n\tvoid on_edit_key_kill_focus(wxFocusEvent& event);\n\tvoid on_right_click(wxMouseEvent& event);\n\n\tbool reset_focused_element();\n\n\tbool m_right_down = false;\n\tint m_focused_element = wxID_NONE;\n\tstd::unordered_map<int, wxColour> m_color_backup;\n};\n\n"
  },
  {
    "path": "src/gui/wxgui/input/panels/ProControllerInputPanel.cpp",
    "content": "#include \"wxgui/input/panels/ProControllerInputPanel.h\"\n\n#include <wx/gbsizer.h>\n#include <wx/stattext.h>\n#include <wx/statline.h>\n#include <wx/textctrl.h>\n\n#include \"input/emulated/ProController.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/components/wxInputDraw.h\"\n\nconst ProController::ButtonId g_kFirstColumnItems[] = { ProController::kButtonId_A, ProController::kButtonId_B, ProController::kButtonId_X, ProController::kButtonId_Y, ProController::kButtonId_L, ProController::kButtonId_R, ProController::kButtonId_ZL, ProController::kButtonId_ZR, ProController::kButtonId_Plus, ProController::kButtonId_Minus };\nconst ProController::ButtonId g_kSecondColumnItems[] = { ProController::kButtonId_StickL, ProController::kButtonId_StickL_Up, ProController::kButtonId_StickL_Down, ProController::kButtonId_StickL_Left, ProController::kButtonId_StickL_Right };\nconst ProController::ButtonId g_kThirdColumnItems[] = { ProController::kButtonId_StickR, ProController::kButtonId_StickR_Up, ProController::kButtonId_StickR_Down, ProController::kButtonId_StickR_Left, ProController::kButtonId_StickR_Right };\nconst ProController::ButtonId g_kFourthRowItems[] = { ProController::kButtonId_Up, ProController::kButtonId_Down, ProController::kButtonId_Left, ProController::kButtonId_Right };\n\n\nProControllerInputPanel::ProControllerInputPanel(wxWindow* parent)\n\t: InputPanel(parent)\n{\n\tauto bold_font = GetFont();\n\tbold_font.MakeBold();\n\n\tauto main_sizer = new wxGridBagSizer();\n\n\tsint32 row = 0;\n\tsint32 column = 0;\n\tfor (auto id : g_kFirstColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\t//////////////////////////////////////////////////////////////////\n\n\tmain_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 2), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);\n\n\trow = 0;\n\tcolumn += 3;\n\n\tauto text = new wxStaticText(this, wxID_ANY, _(\"Left Axis\"));\n\ttext->SetFont(bold_font);\n\tmain_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (auto id : g_kSecondColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\trow++;\n\t\n\t// input drawer\n\tm_left_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\tmain_sizer->Add(m_left_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);\n\n\tmain_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);\n\n\t//////////////////////////////////////////////////////////////////\n\n\trow = 0;\n\tcolumn += 4;\n\n\ttext = new wxStaticText(this, wxID_ANY, _(\"Right Axis\"));\n\ttext->SetFont(bold_font);\n\tmain_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (auto id : g_kThirdColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\trow++;\n\n\t// input drawer\n\tm_right_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\tmain_sizer->Add(m_right_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);\n\n\tmain_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);\n\n\t//////////////////////////////////////////////////////////////////\n\n\trow = 0;\n\tcolumn += 4;\n\n\ttext = new wxStaticText(this, wxID_ANY, _(\"D-pad\"));\n\ttext->SetFont(bold_font);\n\tmain_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (auto id : g_kFourthRowItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\t//////////////////////////////////////////////////////////////////\n\n\tSetSizerAndFit(main_sizer);\n}\n\nvoid ProControllerInputPanel::add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const ProController::ButtonId &button_id) {\n\tsizer->Add(\n\t\tnew wxStaticText(this, wxID_ANY, wxGetTranslation(wxString::FromUTF8(ProController::get_button_name(button_id)))),\n\t\twxGBPosition(row, column),\n\t\twxDefaultSpan,\n\t\twxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\tauto text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);\n\ttext_ctrl->SetClientData((void*)button_id);\n\ttext_ctrl->SetMinSize(wxSize(150, -1));\n\ttext_ctrl->SetEditable(false);\n\ttext_ctrl->SetBackgroundColour(kKeyColourNormalMode);\n\tbind_hotkey_events(text_ctrl);\n\tsizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);\n}\n\nvoid ProControllerInputPanel::on_timer(const EmulatedControllerPtr& emulated_controller,\n\tconst ControllerPtr& controller_base)\n{\n\tInputPanel::on_timer(emulated_controller, controller_base);\n\n\tif (emulated_controller)\n\t{\n\t\tconst auto axis = emulated_controller->get_axis();\n\t\tconst auto rotation = emulated_controller->get_rotation();\n\n\t\tm_left_draw->SetAxisValue(axis);\n\t\tm_right_draw->SetAxisValue(rotation);\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/input/panels/ProControllerInputPanel.h",
    "content": "#pragma once\n\n#include <wx/gbsizer.h>\n#include \"input/emulated/ProController.h\"\n#include \"wxgui/input/panels/InputPanel.h\"\n#include \"wxgui/components/wxInputDraw.h\"\n\nclass ProControllerInputPanel : public InputPanel\n{\npublic:\n\tProControllerInputPanel(wxWindow* parent);\n\n\tvoid on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller) override;\n\nprivate:\n\twxInputDraw* m_left_draw, * m_right_draw;\n\n\tvoid add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const ProController::ButtonId &button_id);\n};\n"
  },
  {
    "path": "src/gui/wxgui/input/panels/VPADInputPanel.cpp",
    "content": "#include \"wxgui/input/panels/VPADInputPanel.h\"\n\n#include <wx/gbsizer.h>\n#include <wx/stattext.h>\n#include <wx/statline.h>\n#include <wx/textctrl.h>\n#include <wx/slider.h>\n#include <wx/checkbox.h>\n\n\n#include \"wxgui/helpers/wxControlObject.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/components/wxInputDraw.h\"\n#include \"input/emulated/VPADController.h\"\n\nconstexpr VPADController::ButtonId g_kFirstColumnItems[] =\n{\n\tVPADController::kButtonId_A, VPADController::kButtonId_B, VPADController::kButtonId_X, VPADController::kButtonId_Y,\n\tVPADController::kButtonId_L, VPADController::kButtonId_R, VPADController::kButtonId_ZL, VPADController::kButtonId_ZR,\n\tVPADController::kButtonId_Plus, VPADController::kButtonId_Minus\n};\n\nconstexpr VPADController::ButtonId g_kSecondColumnItems[] =\n{\n\tVPADController::kButtonId_StickL, VPADController::kButtonId_StickL_Up, VPADController::kButtonId_StickL_Down, VPADController::kButtonId_StickL_Left, VPADController::kButtonId_StickL_Right\n};\n\nconstexpr VPADController::ButtonId g_kThirdColumnItems[] =\n{\n\tVPADController::kButtonId_StickR, VPADController::kButtonId_StickR_Up, VPADController::kButtonId_StickR_Down, VPADController::kButtonId_StickR_Left, VPADController::kButtonId_StickR_Right\n};\n\nconstexpr VPADController::ButtonId g_kFourthRowItems[] =\n{\n\tVPADController::kButtonId_Up, VPADController::kButtonId_Down, VPADController::kButtonId_Left, VPADController::kButtonId_Right\n};\n\n\nVPADInputPanel::VPADInputPanel(wxWindow* parent)\n\t: InputPanel(parent)\n{\n\tauto bold_font = GetFont();\n\tbold_font.MakeBold();\n\n\tauto* main_sizer = new wxGridBagSizer();\n\n\tsint32 row = 0;\n\tsint32 column = 0;\n\tfor (const auto& id : g_kFirstColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\t//////////////////////////////////////////////////////////////////\n\n\tmain_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 2), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);\n\n\trow = 0;\n\tcolumn += 3;\n\n\tauto text = new wxStaticText(this, wxID_ANY, _(\"Left Axis\"));\n\ttext->SetFont(bold_font);\n\tmain_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (const auto& id : g_kSecondColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\trow++;\n\t\n\t// input drawer\n\tm_left_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\tmain_sizer->Add(m_left_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);\n\n\tmain_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);\n\n\t//////////////////////////////////////////////////////////////////\n\n\trow = 0;\n\tcolumn += 4;\n\n\ttext = new wxStaticText(this, wxID_ANY, _(\"Right Axis\"));\n\ttext->SetFont(bold_font);\n\tmain_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (const auto& id : g_kThirdColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\trow++;\n\n\t// input drawer\n\tm_right_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\tmain_sizer->Add(m_right_draw, wxGBPosition(row, column + 1), wxGBSpan(2, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);\n\n\t// Volume\n\trow = 10;\n\n\ttext = new wxStaticText(this, wxID_ANY, _(\"Volume\"));\n\ttext->Disable();\n\tmain_sizer->Add(text, wxGBPosition(row, column), wxDefaultSpan, wxALL, 5);\n\n\tauto*m_volume = new wxSlider(this, wxID_ANY, 0, 0, 100);\n\tm_volume->Disable();\n\tmain_sizer->Add(m_volume, wxGBPosition(row, column + 1), wxDefaultSpan, wxTOP | wxBOTTOM | wxEXPAND, 5);\n\n\tconst auto volume_text = new wxStaticText(this, wxID_ANY, wxString::Format(\"%d%%\", 0));\n\tvolume_text->Disable();\n\tmain_sizer->Add(volume_text, wxGBPosition(row, column + 2), wxDefaultSpan, wxALL, 5);\n\tm_volume->Bind(wxEVT_SLIDER, &VPADInputPanel::OnVolumeChange, this, wxID_ANY, wxID_ANY, new wxControlObject(volume_text));\n\n\tmain_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxALL | wxEXPAND, 5);\n\n\t//////////////////////////////////////////////////////////////////\n\n\trow = 0;\n\tcolumn += 4;\n\n\ttext = new wxStaticText(this, wxID_ANY, _(\"D-pad\"));\n\ttext->SetFont(bold_font);\n\tmain_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (const auto& id : g_kFourthRowItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(main_sizer, row, column, id);\n\t}\n\n\t// Blow Mic\n\trow = 8;\n\tadd_button_row(main_sizer, row, column, VPADController::kButtonId_Mic, _(\"blow mic\"));\n\trow++;\n\n\tadd_button_row(main_sizer, row, column, VPADController::kButtonId_Screen, _(\"show screen\"));\n\trow++;\n\n\tauto toggleScreenText = new wxStaticText(this, wxID_ANY, _(\"toggle screen\"));\n\tmain_sizer->Add(toggleScreenText,\n\t\twxGBPosition(row, column),\n\t\twxDefaultSpan,\n\t\twxALL | wxALIGN_CENTER_VERTICAL, 5);\n\tm_togglePadViewCheckBox = new wxCheckBox(this, wxID_ANY, {}, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);\n\twxString toggleScreenTT = _(\"Makes the \\\"show screen\\\" button toggle between the TV and gamepad screens\");\n\tm_togglePadViewCheckBox->SetToolTip(toggleScreenTT);\n\ttoggleScreenText->SetToolTip(toggleScreenTT);\n\tmain_sizer->Add(m_togglePadViewCheckBox, wxGBPosition(row,column+1), wxDefaultSpan, wxALL | wxEXPAND, 5);\n\n\t//////////////////////////////////////////////////////////////////\n\n\tSetSizer(main_sizer);\n\tLayout();\n}\n\nvoid VPADInputPanel::add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const VPADController::ButtonId &button_id) {\n\tadd_button_row(sizer, row, column, button_id, wxGetTranslation(wxString::FromUTF8(VPADController::get_button_name(button_id))));\n}\n\nvoid VPADInputPanel::add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column,\n                                    const VPADController::ButtonId &button_id, const wxString &label) {\n\tsizer->Add(\n\t\tnew wxStaticText(this, wxID_ANY, label),\n\t\twxGBPosition(row, column),\n\t\twxDefaultSpan,\n\t\twxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\tauto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);\n\ttext_ctrl->SetClientData((void*)button_id);\n\ttext_ctrl->SetMinSize(wxSize(150, -1));\n\ttext_ctrl->SetEditable(false);\n\ttext_ctrl->SetBackgroundColour(kKeyColourNormalMode);\n\tbind_hotkey_events(text_ctrl);\n\tsizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);\n}\n\nvoid VPADInputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller_base)\n{\n\tInputPanel::on_timer(emulated_controller, controller_base);\n\n\tstatic_cast<VPADController*>(emulated_controller.get())->set_screen_toggle(m_togglePadViewCheckBox->GetValue());\n\n\tif(emulated_controller)\n\t{\n\t\tconst auto axis = emulated_controller->get_axis();\n\t\tconst auto rotation = emulated_controller->get_rotation();\n\n\t\tm_left_draw->SetAxisValue(axis);\n\t\tm_right_draw->SetAxisValue(rotation);\n\t}\n}\n\nvoid VPADInputPanel::OnVolumeChange(wxCommandEvent& event)\n{\n\n}\nvoid VPADInputPanel::load_controller(const EmulatedControllerPtr& controller)\n{\n\tInputPanel::load_controller(controller);\n\n\tconst bool isToggle = static_cast<VPADController*>(controller.get())->is_screen_active_toggle();\n\tm_togglePadViewCheckBox->SetValue(isToggle);\n}\n"
  },
  {
    "path": "src/gui/wxgui/input/panels/VPADInputPanel.h",
    "content": "#pragma once\n\n#include <wx/gbsizer.h>\n#include \"wxgui/input/panels/InputPanel.h\"\n\nclass wxInputDraw;\nclass wxCheckBox;\n\nclass VPADInputPanel : public InputPanel\n{\npublic:\n\tVPADInputPanel(wxWindow* parent);\n\n\tvoid on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller) override;\n\tvirtual void load_controller(const EmulatedControllerPtr& controller) override;\n\nprivate:\n\tvoid OnVolumeChange(wxCommandEvent& event);\n\n\twxInputDraw* m_left_draw, * m_right_draw;\n\twxCheckBox* m_togglePadViewCheckBox;\n\n\tvoid add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const VPADController::ButtonId &button_id);\n\tvoid add_button_row(wxGridBagSizer *sizer, sint32 row, sint32 column, const VPADController::ButtonId &button_id, const wxString &label);\n};\n"
  },
  {
    "path": "src/gui/wxgui/input/panels/WiimoteInputPanel.cpp",
    "content": "#include \"wxgui/input/panels/WiimoteInputPanel.h\"\n\n#include <wx/button.h>\n#include <wx/gbsizer.h>\n#include <wx/stattext.h>\n#include <wx/statline.h>\n#include <wx/textctrl.h>\n#include <wx/slider.h>\n#include <wx/checkbox.h>\n\n#include \"wxgui/helpers/wxControlObject.h\"\n#include \"input/emulated/WiimoteController.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/components/wxInputDraw.h\"\n\nconstexpr WiimoteController::ButtonId g_kFirstColumnItems[] =\n{\n\tWiimoteController::kButtonId_A, WiimoteController::kButtonId_B, WiimoteController::kButtonId_1, WiimoteController::kButtonId_2, WiimoteController::kButtonId_Plus, WiimoteController::kButtonId_Minus, WiimoteController::kButtonId_Home\n};\n\nconstexpr WiimoteController::ButtonId g_kSecondColumnItems[] =\n{\n\tWiimoteController::kButtonId_Up, WiimoteController::kButtonId_Down, WiimoteController::kButtonId_Left, WiimoteController::kButtonId_Right\n};\n\nconstexpr WiimoteController::ButtonId g_kThirdColumnItems[] =\n{\n\tWiimoteController::kButtonId_Nunchuck_C, WiimoteController::kButtonId_Nunchuck_Z,\n\tWiimoteController::kButtonId_None,\n\tWiimoteController::kButtonId_Nunchuck_Up,WiimoteController::kButtonId_Nunchuck_Down,WiimoteController::kButtonId_Nunchuck_Left,WiimoteController::kButtonId_Nunchuck_Right\n};\n\nWiimoteInputPanel::WiimoteInputPanel(wxWindow* parent)\n\t: InputPanel(parent)\n{\n\tauto bold_font = GetFont();\n\tbold_font.MakeBold();\n\n\tauto* main_sizer = new wxBoxSizer(wxVERTICAL);\n    auto* horiz_main_sizer = new wxBoxSizer(wxHORIZONTAL);\n\n    auto* extensions_sizer = new wxBoxSizer(wxHORIZONTAL);\n    horiz_main_sizer->Add(extensions_sizer, wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL));\n\n    extensions_sizer->Add(new wxStaticText(this, wxID_ANY, _(\"Extensions:\")));\n    extensions_sizer->AddSpacer(10);\n\n\tm_motion_plus = new wxCheckBox(this, wxID_ANY, _(\"MotionPlus\"));\n\tm_motion_plus->Bind(wxEVT_CHECKBOX, &WiimoteInputPanel::on_extension_change, this);\n\textensions_sizer->Add(m_motion_plus);\n\n\tm_nunchuck = new wxCheckBox(this, wxID_ANY, _(\"Nunchuck\"));\n\tm_nunchuck->Bind(wxEVT_CHECKBOX, &WiimoteInputPanel::on_extension_change, this);\n\textensions_sizer->Add(m_nunchuck);\n\n\tm_classic = new wxCheckBox(this, wxID_ANY, _(\"Classic\"));\n\tm_classic->Bind(wxEVT_CHECKBOX, &WiimoteInputPanel::on_extension_change, this);\n\tm_classic->Hide();\n\textensions_sizer->Add(m_classic);\n\n\tmain_sizer->Add(horiz_main_sizer, 0, wxEXPAND | wxALL, 5);\n\tmain_sizer->Add(new wxStaticLine(this), 0, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5);\n\n\tm_item_sizer = new wxGridBagSizer();\n\n\tsint32 row = 0;\n\tsint32 column = 0;\n\tfor (const auto& id : g_kFirstColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(row, column, id);\n\t}\n\n\tm_item_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 2), wxGBSpan(11, 1), wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);\n\n\t//////////////////////////////////////////////////////////////////\n\n\trow = 0;\n\tcolumn += 3;\n\n\tauto text = new wxStaticText(this, wxID_ANY, _(\"D-pad\"));\n\ttext->SetFont(bold_font);\n\tm_item_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (const auto& id : g_kSecondColumnItems)\n\t{\n\t\trow++;\n\t\tadd_button_row(row, column, id);\n\t}\n\n\trow = 8;\n\t// Volume\n\ttext = new wxStaticText(this, wxID_ANY, _(\"Volume\"));\n\ttext->Disable();\n\tm_item_sizer->Add(text, wxGBPosition(row, column), wxDefaultSpan, wxALL, 5);\n\n\tm_volume = new wxSlider(this, wxID_ANY, 0, 0, 100);\n\tm_volume->Disable();\n\tm_item_sizer->Add(m_volume, wxGBPosition(row, column + 1), wxDefaultSpan, wxTOP | wxBOTTOM | wxEXPAND, 5);\n\n\tconst auto volume_text = new wxStaticText(this, wxID_ANY, wxString::Format(\"%d%%\", 0));\n\tvolume_text->Disable();\n\tm_item_sizer->Add(volume_text, wxGBPosition(row, column + 2), wxDefaultSpan, wxALL, 5);\n\tm_volume->Bind(wxEVT_SLIDER, &WiimoteInputPanel::on_volume_change, this, wxID_ANY, wxID_ANY, new wxControlObject(volume_text));\n\trow++;\n\n\tm_item_sizer->Add(new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVERTICAL), wxGBPosition(0, column + 3), wxGBSpan(11, 1), wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);\n\n\t//////////////////////////////////////////////////////////////////\n\n\trow = 0;\n\tcolumn += 4;\n\n\ttext = new wxStaticText(this, wxID_ANY, _(\"Nunchuck\"));\n\ttext->SetFont(bold_font);\n\tm_item_sizer->Add(text, wxGBPosition(row, column), wxGBSpan(1, 3), wxALL | wxEXPAND, 5);\n\n\tfor (const auto& id : g_kThirdColumnItems)\n\t{\n\t\trow++;\n\t\tif (id == WiimoteController::kButtonId_None)\n\t\t\tcontinue;\n\n\t\tm_item_sizer->Add(\n\t\t\tnew wxStaticText(this, wxID_ANY, wxGetTranslation(wxString::FromUTF8(WiimoteController::get_button_name(id)))),\n\t\t\twxGBPosition(row, column),\n\t\t\twxDefaultSpan,\n\t\t\twxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\tauto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);\n\t\ttext_ctrl->SetClientData((void*)id);\n\t\ttext_ctrl->SetMinSize(wxSize(150, -1));\n\t\ttext_ctrl->SetEditable(false);\n\t\ttext_ctrl->SetBackgroundColour(kKeyColourNormalMode);\n\t\tbind_hotkey_events(text_ctrl);\n\t\ttext_ctrl->Enable(m_nunchuck->GetValue());\n\t\tm_item_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);\n\n\t\tm_nunchuck_items.push_back(text_ctrl);\n\t}\n\n\n\t// input drawer\n\tm_draw = new wxInputDraw(this, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\tm_draw->Enable(m_nunchuck->GetValue());\n\tm_item_sizer->Add(5, 0, wxGBPosition(3, column + 3), wxDefaultSpan, wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);\n\tm_item_sizer->Add(m_draw, wxGBPosition(3, column + 4), wxGBSpan(4, 1), wxTOP | wxBOTTOM | wxEXPAND | wxALIGN_CENTER, 5);\n\n\tm_nunchuck_items.push_back(m_draw);\n\n\t//////////////////////////////////////////////////////////////////\n\n\tmain_sizer->Add(m_item_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5);\n\t\n\tSetSizer(main_sizer);\n\tLayout();\n}\n\nvoid WiimoteInputPanel::add_button_row(sint32 row, sint32 column, const WiimoteController::ButtonId &button_id) {\n\tm_item_sizer->Add(\n\t\tnew wxStaticText(this, wxID_ANY, wxGetTranslation(wxString::FromUTF8(WiimoteController::get_button_name(button_id)))),\n\t\twxGBPosition(row, column),\n\t\twxDefaultSpan,\n\t\twxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\tauto* text_ctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB);\n\ttext_ctrl->SetClientData((void*)button_id);\n\ttext_ctrl->SetMinSize(wxSize(150, -1));\n\ttext_ctrl->SetEditable(false);\n\ttext_ctrl->SetBackgroundColour(kKeyColourNormalMode);\n\tbind_hotkey_events(text_ctrl);\n\tm_item_sizer->Add(text_ctrl, wxGBPosition(row, column + 1), wxDefaultSpan, wxALL | wxEXPAND, 5);\n}\n\nvoid WiimoteInputPanel::set_active_device_type(WPADDeviceType type)\n{\n\tm_device_type = type;\n\n\tm_motion_plus->SetValue(type == kWAPDevMPLS || type == kWAPDevMPLSFreeStyle || type == kWAPDevMPLSClassic);\n\tswitch(type)\n\t{\n\tcase kWAPDevFreestyle: \n\tcase kWAPDevMPLSFreeStyle:\n\t\tm_nunchuck->SetValue(true);\n\t\tm_classic->SetValue(false);\n\t\tfor (const auto& item : m_nunchuck_items)\n\t\t{\n\t\t\titem->Enable(true);\n\t\t}\n\t\tbreak;\n\n\tcase kWAPDevClassic: \n\tcase kWAPDevMPLSClassic:\n\t\tm_nunchuck->SetValue(false);\n\t\tm_classic->SetValue(true);\n\t\tfor (const auto& item : m_nunchuck_items)\n\t\t{\n\t\t\titem->Enable(false);\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tm_nunchuck->SetValue(false);\n\t\tm_classic->SetValue(false);\n\t\tfor (const auto& item : m_nunchuck_items)\n\t\t{\n\t\t\titem->Enable(false);\n\t\t}\n\t}\n}\n\nvoid WiimoteInputPanel::on_volume_change(wxCommandEvent& event)\n{\n}\n\nvoid WiimoteInputPanel::on_extension_change(wxCommandEvent& event)\n{\n\tif(m_motion_plus->GetValue() && m_nunchuck->GetValue())\n\t\tset_active_device_type(kWAPDevMPLSFreeStyle);\n\telse if(m_motion_plus->GetValue() && m_classic->GetValue())\n\t\tset_active_device_type(kWAPDevMPLSClassic);\n\telse if (m_motion_plus->GetValue())\n\t\tset_active_device_type(kWAPDevMPLS);\n\telse if (m_nunchuck->GetValue())\n\t\tset_active_device_type(kWAPDevFreestyle);\n\telse if (m_classic->GetValue())\n\t\tset_active_device_type(kWAPDevClassic);\n\telse \n\t\tset_active_device_type(kWAPDevCore);\n}\n\nvoid WiimoteInputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller)\n{\n\tif (emulated_controller)\n\t{\n\t\tconst auto wiimote = std::dynamic_pointer_cast<WiimoteController>(emulated_controller);\n\t\twxASSERT(wiimote);\n\n\t\twiimote->set_device_type(m_device_type);\n\t}\n\n\tInputPanel::on_timer(emulated_controller, controller);\n\n\tif (emulated_controller)\n\t{\n\t\tconst auto axis = emulated_controller->get_axis();\n\t\tm_draw->SetAxisValue(axis);\n\t}\n}\n\nvoid WiimoteInputPanel::load_controller(const EmulatedControllerPtr& emulated_controller)\n{\n\tInputPanel::load_controller(emulated_controller);\n\n\tif (emulated_controller) {\n\t\tconst auto wiimote = std::dynamic_pointer_cast<WiimoteController>(emulated_controller);\n\t\twxASSERT(wiimote);\n\t\tset_active_device_type(wiimote->get_device_type());\n\t}\n}\n"
  },
  {
    "path": "src/gui/wxgui/input/panels/WiimoteInputPanel.h",
    "content": "#pragma once\n\n#include \"wxgui/input/panels/InputPanel.h\"\n#include \"input/emulated/WiimoteController.h\"\n#include <wx/slider.h>\n\nclass wxCheckBox;\nclass wxGridBagSizer;\nclass wxInputDraw;\n\nclass WiimoteInputPanel : public InputPanel\n{\npublic:\n\tWiimoteInputPanel(wxWindow* parent);\n\n\tvoid on_timer(const EmulatedControllerPtr& emulated_controller, const ControllerPtr& controller) override;\n\n\tvoid load_controller(const EmulatedControllerPtr& emulated_controller) override;\n\nprivate:\n\twxInputDraw* m_draw;\n\n\tWPADDeviceType m_device_type = kWAPDevCore;\n\tvoid set_active_device_type(WPADDeviceType type);\n\n\tvoid on_volume_change(wxCommandEvent& event);\n\tvoid on_extension_change(wxCommandEvent& event);\n    void on_pair_button(wxCommandEvent& event);\n\n\twxGridBagSizer* m_item_sizer;\n\n\twxCheckBox* m_nunchuck, * m_classic;\n\twxCheckBox* m_motion_plus;\n\n\twxSlider* m_volume;\n\n\tstd::vector<wxWindow*> m_nunchuck_items;\n\n\tvoid add_button_row(sint32 row, sint32 column, const WiimoteController::ButtonId &button_id);\n};\n\n\n\n\n"
  },
  {
    "path": "src/gui/wxgui/input/settings/DefaultControllerSettings.cpp",
    "content": "#include \"wxgui/input/settings/DefaultControllerSettings.h\"\n\n#include <wx/sizer.h>\n#include <wx/stattext.h>\n#include <wx/slider.h>\n#include <wx/button.h>\n#include <wx/gbsizer.h>\n#include <wx/statline.h>\n#include <wx/checkbox.h>\n#include <wx/statbox.h>\n\n#include \"wxgui/helpers/wxControlObject.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/components/wxInputDraw.h\"\n#include \"wxgui/input/InputAPIAddWindow.h\"\n\n\nDefaultControllerSettings::DefaultControllerSettings(wxWindow* parent, const wxPoint& position, std::shared_ptr<ControllerBase> controller)\n\t: wxDialog(parent, wxID_ANY, _(\"Controller settings\"), position, wxDefaultSize,\n\t           wxDEFAULT_DIALOG_STYLE), m_controller(std::move(controller))\n{\n\tm_settings = m_controller->get_settings();\n\tm_rumble_backup = m_settings.rumble;\n\n\tthis->SetSizeHints(wxDefaultSize, wxDefaultSize);\n\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\t// options\n\t{\n\t\tauto* box = new wxStaticBox(this, wxID_ANY, _(\"Options\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\t// Motion\n\t\tm_use_motion = new wxCheckBox(box, wxID_ANY, _(\"Use motion\"));\n\t\tm_use_motion->SetValue(m_settings.motion);\n\t\tm_use_motion->Enable(m_controller->has_motion());\n\t\tbox_sizer->Add(m_use_motion, 0, wxEXPAND | wxALL, 5);\n\n\t\t// Vibration\n\t\tauto* rumbleSizer = new wxBoxSizer(wxHORIZONTAL);\n\n\t\tconst auto rumble = (int)(m_settings.rumble * 100);\n\t\trumbleSizer->Add(new wxStaticText(box, wxID_ANY, _(\"Rumble\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\tm_rumble = new wxSlider(box, wxID_ANY, rumble, 0, 100);\n\t\trumbleSizer->Add(m_rumble, 1, wxALL | wxEXPAND, 5);\n\n\t\tconst auto text = new wxStaticText(box, wxID_ANY, wxString::Format(\"%d%%\", rumble));\n\t\trumbleSizer->Add(text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\tm_rumble->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_rumble_change, this, wxID_ANY, wxID_ANY, new wxControlObject(text));\n\n\t\tbox_sizer->Add(rumbleSizer);\n\n\t\tsizer->Add(box_sizer, 1, wxALL|wxEXPAND, 5);\n\t}\n\n\tauto* row_sizer = new wxBoxSizer(wxHORIZONTAL);\n\t// Axis\n\t{\n\t\tauto* box = new wxStaticBox(this, wxID_ANY, _(\"Axis\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\t{\n\t\t\tauto* content_sizer = new wxFlexGridSizer(0, 3, 0, 0);\n\n\t\t\t// Deadzone\n\t\t\tconst auto deadzone = (int)(m_settings.axis.deadzone * 100);\n\t\t\tcontent_sizer->Add(new wxStaticText(box, wxID_ANY, _(\"Deadzone\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\tm_axis_deadzone = new wxSlider(box, wxID_ANY, deadzone, 0, 100);\n\t\t\tcontent_sizer->Add(m_axis_deadzone, 1, wxALL | wxEXPAND, 5);\n\n\t\t\tconst auto deadzone_text = new wxStaticText(box, wxID_ANY, wxString::Format(\"%d%%\", deadzone));\n\t\t\tcontent_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\tm_axis_deadzone->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_deadzone_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\tnew wxControlObject(deadzone_text));\n\n\n\t\t\t// Range\n\t\t\tconst auto range = (int)(m_settings.axis.range * 100);\n\t\t\tcontent_sizer->Add(new wxStaticText(box, wxID_ANY, _(\"Range\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\tm_axis_range = new wxSlider(box, wxID_ANY, range, 50, 200);\n\t\t\tcontent_sizer->Add(m_axis_range, 1, wxALL | wxEXPAND, 5);\n\n\t\t\tconst auto range_text = new wxStaticText(box, wxID_ANY, wxString::Format(\"%d%%\", range));\n\t\t\tcontent_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\tm_axis_range->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_range_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\tnew wxControlObject(range_text));\n\n\t\t\tcontent_sizer->AddSpacer(1);\n\t\t\tm_axis_draw = new wxInputDraw(box, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\t\t\tcontent_sizer->Add(m_axis_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);\n\n\t\t\tbox_sizer->Add(content_sizer, 1, wxEXPAND, 0);\n\t\t}\n\n\t\trow_sizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\t\n\t// Rotation\n\t{\n\t\tauto* box = new wxStaticBox(this, wxID_ANY, _(\"Rotation\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\t{\n\t\t\tauto* content_sizer = new wxFlexGridSizer(0, 3, 0, 0);\n\n\t\t\t// Deadzone\n\t\t\tconst auto deadzone = (int)(m_settings.rotation.deadzone * 100);\n\t\t\tcontent_sizer->Add(new wxStaticText(box, wxID_ANY, _(\"Deadzone\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\tm_rotation_deadzone = new wxSlider(box, wxID_ANY, deadzone, 0, 100);\n\t\t\tcontent_sizer->Add(m_rotation_deadzone, 1, wxALL | wxEXPAND, 5);\n\n\t\t\tconst auto deadzone_text = new wxStaticText(box, wxID_ANY, wxString::Format(\"%d%%\", deadzone));\n\t\t\tcontent_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\tm_rotation_deadzone->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_deadzone_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\tnew wxControlObject(deadzone_text));\n\n\n\t\t\t// Range\n\t\t\tconst auto range = (int)(m_settings.rotation.range * 100);\n\t\t\tcontent_sizer->Add(new wxStaticText(box, wxID_ANY, _(\"Range\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\tm_rotation_range = new wxSlider(box, wxID_ANY, range, 50, 200);\n\t\t\tcontent_sizer->Add(m_rotation_range, 1, wxALL | wxEXPAND, 5);\n\n\t\t\tconst auto range_text = new wxStaticText(box, wxID_ANY, wxString::Format(\"%d%%\", range));\n\t\t\tcontent_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\tm_rotation_range->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_range_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\tnew wxControlObject(range_text));\n\n\t\t\tcontent_sizer->AddSpacer(1);\n\t\t\tm_rotation_draw = new wxInputDraw(box, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\t\t\tcontent_sizer->Add(m_rotation_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);\n\n\t\t\tbox_sizer->Add(content_sizer, 1, wxEXPAND, 0);\n\t\t}\n\n\t\trow_sizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t// Trigger\n\t{\n\t\tauto* box = new wxStaticBox(this, wxID_ANY, _(\"Trigger\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\t{\n\t\t\tauto* content_sizer = new wxFlexGridSizer(0, 3, 0, 0);\n\n\t\t\t// Deadzone\n\t\t\tconst auto deadzone = (int)(m_settings.trigger.deadzone * 100);\n\t\t\tcontent_sizer->Add(new wxStaticText(box, wxID_ANY, _(\"Deadzone\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\tm_trigger_deadzone = new wxSlider(box, wxID_ANY, deadzone, 0, 100);\n\t\t\tcontent_sizer->Add(m_trigger_deadzone, 1, wxALL | wxEXPAND, 5);\n\n\t\t\tconst auto deadzone_text = new wxStaticText(box, wxID_ANY, wxString::Format(\"%d%%\", deadzone));\n\t\t\tcontent_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\tm_trigger_deadzone->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_deadzone_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\tnew wxControlObject(deadzone_text));\n\n\n\t\t\t// Range\n\t\t\tconst auto range = (int)(m_settings.trigger.range * 100);\n\t\t\tcontent_sizer->Add(new wxStaticText(box, wxID_ANY, _(\"Range\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\tm_trigger_range = new wxSlider(box, wxID_ANY, range, 50, 200);\n\t\t\tcontent_sizer->Add(m_trigger_range, 1, wxALL | wxEXPAND, 5);\n\n\t\t\tconst auto range_text = new wxStaticText(box, wxID_ANY, wxString::Format(\"%d%%\", range));\n\t\t\tcontent_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\tm_trigger_range->Bind(wxEVT_SLIDER, &DefaultControllerSettings::on_range_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\tnew wxControlObject(range_text));\n\n\t\t\tcontent_sizer->AddSpacer(1);\n\t\t\tm_trigger_draw = new wxInputDraw(box, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\t\t\tcontent_sizer->Add(m_trigger_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);\n\n\t\t\tbox_sizer->Add(content_sizer, 1, wxEXPAND, 0);\n\t\t}\n\n\t\trow_sizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\tsizer->Add(row_sizer);\n\n\t{\n\t\tauto* control_sizer = new wxFlexGridSizer(0, 4, 0, 0);\n\t\tcontrol_sizer->AddGrowableCol(3);\n\n\t\tauto* ok_button = new wxButton(this, wxID_ANY, _(\"OK\"));\n\t\tok_button->Bind(wxEVT_BUTTON, [this](auto&) { update_settings(); EndModal(wxID_OK); });\n\t\tcontrol_sizer->Add(ok_button, 0, wxALL, 5);\n\n\t\tcontrol_sizer->Add(0, 0, 0, wxEXPAND, 5);\n\n\t\tauto* cancel_button = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\t\tcancel_button->Bind(wxEVT_BUTTON, [this](auto&) { EndModal(wxID_CANCEL); });\n\t\tcontrol_sizer->Add(cancel_button, 0, wxALL, 5);\n\n\t\tauto* calibrate_button = new wxButton(this, wxID_ANY, _(\"Calibrate\"));\n\t\tcalibrate_button->Bind(wxEVT_BUTTON, [this](auto&) { m_controller->calibrate(); });\n\t\tcontrol_sizer->Add(calibrate_button, 0, wxALL | wxALIGN_RIGHT, 5);\n\n\t\tsizer->Add(control_sizer, 0, wxEXPAND, 5);\n\t}\n\n\t\n\n\tthis->SetSizer(sizer);\n\tthis->Layout();\n\tthis->Fit();\n\n\tthis->Bind(wxEVT_CLOSE_WINDOW, &DefaultControllerSettings::on_close, this);\n\n\tm_timer = new wxTimer(this);\n\tBind(wxEVT_TIMER, &DefaultControllerSettings::on_timer, this);\n\tm_timer->Start(100);\n}\n\nDefaultControllerSettings::~DefaultControllerSettings()\n{\n\tm_controller->stop_rumble();\n\tm_timer->Stop();\n}\n\nvoid DefaultControllerSettings::update_settings()\n{\n\t// update settings\n\tm_controller->set_settings(m_settings);\n\tif (m_use_motion)\n\t\tm_controller->set_use_motion(m_use_motion->GetValue());\n}\n\nvoid DefaultControllerSettings::on_timer(wxTimerEvent& event)\n{\n\tif (m_rumble_time.has_value() && std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_rumble_time.value()).count() > 500 )\n\t{\n\t\tm_controller->stop_rumble();\n\t\tm_rumble_time = {};\n\t}\n\n\tconst auto& default_state = m_controller->get_default_state();\n\n\tauto state = m_controller->raw_state();\n\tm_controller->apply_axis_setting(state.axis, default_state.axis, m_settings.axis);\n\tm_controller->apply_axis_setting(state.rotation, default_state.rotation, m_settings.rotation);\n\tm_controller->apply_axis_setting(state.trigger, default_state.trigger, m_settings.trigger);\n\n\tif (m_controller->api() == InputAPI::SDLController)\n\t{\n\t\tstate.axis.y *= -1;\n\t\tstate.rotation.y *= -1;\n\t}\n\n\tm_axis_draw->SetDeadzone(m_settings.axis.deadzone);\n\tm_axis_draw->SetAxisValue(state.axis);\n\n\tm_rotation_draw->SetDeadzone(m_settings.rotation.deadzone);\n\tm_rotation_draw->SetAxisValue(state.rotation);\n\n\tm_trigger_draw->SetDeadzone(m_settings.trigger.deadzone);\n\tm_trigger_draw->SetAxisValue(state.trigger);\n}\n\nvoid DefaultControllerSettings::on_close(wxCloseEvent& event)\n{\n\tif (this->GetReturnCode() == 0 || this->GetReturnCode() == wxID_OK)\n\t\tupdate_settings();\n\n\tevent.Skip();\n}\n\nvoid DefaultControllerSettings::on_deadzone_change(wxCommandEvent& event)\n{\n\tupdate_slider_text(event);\n\tconst auto new_value = (float)event.GetInt() / 100.0f;\n\n\tif (event.GetEventObject() == m_axis_deadzone)\n\t\tm_settings.axis.deadzone = new_value;\n\telse if (event.GetEventObject() == m_rotation_deadzone)\n\t\tm_settings.rotation.deadzone = new_value;\n\telse if (event.GetEventObject() == m_trigger_deadzone)\n\t\tm_settings.trigger.deadzone = new_value;\n}\n\nvoid DefaultControllerSettings::on_range_change(wxCommandEvent& event)\n{\n\tupdate_slider_text(event);\n\n\tconst auto new_value = (float)event.GetInt() / 100.0f;\n\n\tif (event.GetEventObject() == m_axis_range)\n\t\tm_settings.axis.range = new_value;\n\telse if (event.GetEventObject() == m_rotation_range)\n\t\tm_settings.rotation.range = new_value;\n\telse if (event.GetEventObject() == m_trigger_range)\n\t\tm_settings.trigger.range = new_value;\n}\n\nvoid DefaultControllerSettings::on_rumble_change(wxCommandEvent& event)\n{\n\tupdate_slider_text(event);\n\n\tconst auto rumble_value = event.GetInt();\n\tm_settings.rumble = (float)rumble_value / 100.0f;\n\n\tm_controller->set_rumble(m_settings.rumble);\n\tif (rumble_value != 0)\n\t\tm_controller->start_rumble();\n\telse\n\t\tm_controller->stop_rumble();\n\n\tm_controller->set_rumble(m_rumble_backup);\n\n\tm_rumble_time = std::chrono::steady_clock::now();\n}\n"
  },
  {
    "path": "src/gui/wxgui/input/settings/DefaultControllerSettings.h",
    "content": "#pragma once\n\n#include <wx/dialog.h>\n#include <wx/timer.h>\n#include <wx/slider.h>\n\n#include \"input/api/Controller.h\"\n\nclass wxCheckBox;\nclass wxInputDraw;\n\nclass DefaultControllerSettings : public wxDialog\n{\npublic:\n\tDefaultControllerSettings(wxWindow* parent, const wxPoint& position, ControllerPtr controller);\n\t~DefaultControllerSettings();\n\nprivate:\n\tvoid update_settings();\n\n\tControllerPtr m_controller;\n\tControllerBase::Settings m_settings;\n\tfloat m_rumble_backup;\n\n\twxTimer* m_timer;\n\tstd::optional<std::chrono::steady_clock::time_point> m_rumble_time{};\n\n\twxSlider* m_axis_deadzone, *m_axis_range;\n\twxSlider* m_rotation_deadzone, *m_rotation_range;\n\twxSlider* m_trigger_deadzone, *m_trigger_range;\n\twxSlider* m_rumble;\n\n\twxCheckBox* m_use_motion = nullptr;\n\n\twxInputDraw* m_axis_draw, * m_rotation_draw, *m_trigger_draw;\n\n\tvoid on_timer(wxTimerEvent& event);\n\tvoid on_close(wxCloseEvent& event);\n\tvoid on_deadzone_change(wxCommandEvent& event);\n\tvoid on_range_change(wxCommandEvent& event);\n\tvoid on_rumble_change(wxCommandEvent& event);\n};\n"
  },
  {
    "path": "src/gui/wxgui/input/settings/WiimoteControllerSettings.cpp",
    "content": "#include \"wxgui/input/settings/WiimoteControllerSettings.h\"\n\n#include <wx/sizer.h>\n#include <wx/stattext.h>\n#include <wx/slider.h>\n#include <wx/button.h>\n#include <wx/gbsizer.h>\n#include <wx/statline.h>\n#include <wx/checkbox.h>\n#include <wx/statbox.h>\n\n#include \"wxgui/helpers/wxControlObject.h\"\n#include \"wxgui/helpers/wxHelpers.h\"\n#include \"wxgui/components/wxInputDraw.h\"\n#include \"wxgui/input/InputAPIAddWindow.h\"\n\n#ifdef SUPPORTS_WIIMOTE\n\nWiimoteControllerSettings::WiimoteControllerSettings(wxWindow* parent, const wxPoint& position, std::shared_ptr<NativeWiimoteController> controller)\n\t: wxDialog(parent, wxID_ANY, _(\"Controller settings\"), position, wxDefaultSize,\n\t\twxDEFAULT_DIALOG_STYLE), m_controller(std::move(controller))\n{\n\tm_settings = m_controller->get_settings();\n\tm_rumble_backup = m_settings.rumble;\n\tm_packet_delay_backup = m_controller->get_packet_delay();\n\n\tthis->SetSizeHints(wxDefaultSize, wxDefaultSize);\n\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\t// extension info\n\t{\n\t\tauto* box = new wxStaticBox(this, wxID_ANY, _(\"Connected extension\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\tm_extension_text = new wxStaticText(box, wxID_ANY, _(\"None\"));\n\t\tbox_sizer->Add(m_extension_text, 0, wxALL, 5);\n\n\t\tsizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t// options\n\t{\n\t\tauto* box = new wxStaticBox(this, wxID_ANY, _(\"Options\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(box, wxVERTICAL);\n\n\t\t{\n\t\t\tauto* row_sizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\t// Rumble\n\t\t\tm_rumble = new wxCheckBox(box, wxID_ANY, _(\"Rumble\"));\n\t\t\tm_rumble->SetValue(m_settings.rumble > 0);\n\t\t\trow_sizer->Add(m_rumble, 0, wxALL, 5);\n\n\t\t\tm_rumble->Bind(wxEVT_CHECKBOX, &WiimoteControllerSettings::on_rumble_change, this);\n\n\t\t\t// Motion\n\t\t\tm_use_motion = new wxCheckBox(box, wxID_ANY, _(\"Use motion\"));\n\t\t\tm_use_motion->SetValue(m_settings.motion);\n\t\t\tm_use_motion->Enable(m_controller->has_motion());\n\t\t\trow_sizer->Add(m_use_motion, 0, wxALL, 5);\n\n\t\t\tbox_sizer->Add(row_sizer);\n\t\t}\n\t\t{\n\t\t\tauto* row_sizer = new wxBoxSizer(wxHORIZONTAL);\n\n\t\t\t// Delay\n\t\t\trow_sizer->Add(new wxStaticText(box, wxID_ANY, _(\"Packet delay\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\tm_package_delay = new wxSlider(box, wxID_ANY, m_packet_delay_backup, 1, 100);\n\t\t\trow_sizer->Add(m_package_delay, 1, wxALL | wxEXPAND, 5);\n\n\t\t\tconst auto range_text = new wxStaticText(box, wxID_ANY, wxString::Format(\"%dms\", m_packet_delay_backup));\n\t\t\trow_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\tm_package_delay->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_delay_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\tnew wxControlObject(range_text));\n\n\t\t\tbox_sizer->Add(row_sizer);\n\t\t}\n\n\t\tsizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t// Nunchuck\n\t{\n\t\tm_nunchuck_settings = new wxStaticBox(this, wxID_ANY, _(\"Nunchuck\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(m_nunchuck_settings, wxVERTICAL);\n\n\t\t{\n\t\t\tauto* content_sizer = new wxFlexGridSizer(0, 3, 0, 0);\n\n\t\t\t// Deadzone\n\t\t\tconst auto deadzone = (int)(m_settings.axis.deadzone * 100);\n\t\t\tcontent_sizer->Add(new wxStaticText(m_nunchuck_settings, wxID_ANY, _(\"Deadzone\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\tm_nunchuck_deadzone = new wxSlider(m_nunchuck_settings, wxID_ANY, deadzone, 0, 100);\n\t\t\tcontent_sizer->Add(m_nunchuck_deadzone, 1, wxALL | wxEXPAND, 5);\n\n\t\t\tconst auto deadzone_text = new wxStaticText(m_nunchuck_settings, wxID_ANY, wxString::Format(\"%d%%\", deadzone));\n\t\t\tcontent_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\tm_nunchuck_deadzone->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\tnew wxControlObject(deadzone_text));\n\n\n\t\t\t// Range\n\t\t\tconst auto range = (int)(m_settings.axis.range * 100);\n\t\t\tcontent_sizer->Add(new wxStaticText(m_nunchuck_settings, wxID_ANY, _(\"Range\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\tm_nunchuck_range = new wxSlider(m_nunchuck_settings, wxID_ANY, range, 50, 200);\n\t\t\tcontent_sizer->Add(m_nunchuck_range, 1, wxALL | wxEXPAND, 5);\n\n\t\t\tconst auto range_text = new wxStaticText(m_nunchuck_settings, wxID_ANY, wxString::Format(\"%d%%\", range));\n\t\t\tcontent_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\tm_nunchuck_range->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\tnew wxControlObject(range_text));\n\n\t\t\tcontent_sizer->AddSpacer(1);\n\t\t\tm_nunchuck_draw = new wxInputDraw(m_nunchuck_settings, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\t\t\tcontent_sizer->Add(m_nunchuck_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);\n\n\t\t\tbox_sizer->Add(content_sizer, 1, wxEXPAND, 0);\n\t\t}\n\n\t\tsizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t// Classic\n\t{\n\t\tm_classic_settings = new wxStaticBox(this, wxID_ANY, _(\"Classic\"));\n\t\tauto* box_sizer = new wxStaticBoxSizer(m_classic_settings, wxVERTICAL);\n\n\t\t{\n\t\t\tauto* content_sizer = new wxFlexGridSizer(0, 6, 0, 0);\n\n\t\t\t// Deadzone\n\t\t\t{\n\t\t\t\t// Axis\n\t\t\t\tconst auto deadzone = (int)(m_settings.axis.deadzone * 100);\n\t\t\t\tcontent_sizer->Add(new wxStaticText(m_classic_settings, wxID_ANY, _(\"Deadzone\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\t\tm_classic_axis_deadzone = new wxSlider(m_classic_settings, wxID_ANY, deadzone, 0, 100);\n\t\t\t\tcontent_sizer->Add(m_classic_axis_deadzone, 1, wxALL | wxEXPAND, 5);\n\n\t\t\t\tconst auto deadzone_text = new wxStaticText(m_classic_settings, wxID_ANY, wxString::Format(\"%d%%\", deadzone));\n\t\t\t\tcontent_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\t\tm_classic_axis_deadzone->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\t\tnew wxControlObject(deadzone_text));\n\t\t\t}\n\t\t\t{\n\t\t\t\t// Range\n\t\t\t\tconst auto deadzone = (int)(m_settings.rotation.deadzone * 100);\n\t\t\t\tcontent_sizer->Add(new wxStaticText(m_classic_settings, wxID_ANY, _(\"Deadzone\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\t\tm_classic_rotation_deadzone = new wxSlider(m_classic_settings, wxID_ANY, deadzone, 0, 100);\n\t\t\t\tcontent_sizer->Add(m_classic_rotation_deadzone, 1, wxALL | wxEXPAND, 5);\n\n\t\t\t\tconst auto deadzone_text = new wxStaticText(m_classic_settings, wxID_ANY, wxString::Format(\"%d%%\", deadzone));\n\t\t\t\tcontent_sizer->Add(deadzone_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\t\tm_classic_rotation_deadzone->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\t\tnew wxControlObject(deadzone_text));\n\t\t\t}\n\n\t\t\t// Range\n\t\t\t{\n\t\t\t\t// Axis\n\t\t\t\tconst auto range = (int)(m_settings.axis.range * 100);\n\t\t\t\tcontent_sizer->Add(new wxStaticText(m_classic_settings, wxID_ANY, _(\"Range\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\t\tm_classic_axis_range = new wxSlider(m_classic_settings, wxID_ANY, range, 50, 200);\n\t\t\t\tcontent_sizer->Add(m_classic_axis_range, 1, wxALL | wxEXPAND, 5);\n\n\t\t\t\tconst auto range_text = new wxStaticText(m_classic_settings, wxID_ANY, wxString::Format(\"%d%%\", range));\n\t\t\t\tcontent_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\t\tm_classic_axis_range->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\t\tnew wxControlObject(range_text));\n\t\t\t}\n\t\t\t{\n\t\t\t\t// Rotation\n\t\t\t\tconst auto range = (int)(m_settings.rotation.range * 100);\n\t\t\t\tcontent_sizer->Add(new wxStaticText(m_classic_settings, wxID_ANY, _(\"Range\")), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\t\t\t\tm_classic_rotation_range = new wxSlider(m_classic_settings, wxID_ANY, range, 50, 200);\n\t\t\t\tcontent_sizer->Add(m_classic_rotation_range, 1, wxALL | wxEXPAND, 5);\n\n\t\t\t\tconst auto range_text = new wxStaticText(m_classic_settings, wxID_ANY, wxString::Format(\"%d%%\", range));\n\t\t\t\tcontent_sizer->Add(range_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\t\t\t\tm_classic_rotation_range->Bind(wxEVT_SLIDER, &WiimoteControllerSettings::on_slider_change, this, wxID_ANY, wxID_ANY,\n\t\t\t\t\tnew wxControlObject(range_text));\n\t\t\t}\n\n\t\t\tcontent_sizer->AddSpacer(1);\n\t\t\tm_classic_axis_draw = new wxInputDraw(m_classic_settings, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\t\t\tcontent_sizer->Add(m_classic_axis_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);\n\t\t\tcontent_sizer->AddSpacer(1);\n\n\t\t\tcontent_sizer->AddSpacer(1);\n\t\t\tm_classic_rotation_draw = new wxInputDraw(m_classic_settings, wxID_ANY, wxDefaultPosition, { 60, 60 });\n\t\t\tcontent_sizer->Add(m_classic_rotation_draw, 0, wxTOP | wxBOTTOM | wxALIGN_CENTER, 5);\n\n\t\t\tbox_sizer->Add(content_sizer, 1, wxEXPAND, 0);\n\t\t}\n\n\t\tsizer->Add(box_sizer, 0, wxALL | wxEXPAND, 5);\n\t}\n\n\t{\n\t\tauto* control_sizer = new wxFlexGridSizer(0, 4, 0, 0);\n\t\tcontrol_sizer->AddGrowableCol(3);\n\n\t\tauto* ok_button = new wxButton(this, wxID_ANY, _(\"OK\"));\n\t\tok_button->Bind(wxEVT_BUTTON, [this](auto&) { update_settings(); EndModal(wxID_OK); });\n\t\tcontrol_sizer->Add(ok_button, 0, wxALL, 5);\n\n\t\tcontrol_sizer->Add(0, 0, 0, wxEXPAND, 5);\n\n\t\tauto* cancel_button = new wxButton(this, wxID_ANY, _(\"Cancel\"));\n\t\tcancel_button->Bind(wxEVT_BUTTON, [this](auto&) { EndModal(wxID_CANCEL); });\n\t\tcontrol_sizer->Add(cancel_button, 0, wxALL, 5);\n\n\t\tauto* calibrate_button = new wxButton(this, wxID_ANY, _(\"Calibrate\"));\n\t\tcalibrate_button->Bind(wxEVT_BUTTON, [this](auto&) { m_controller->calibrate(); });\n\t\tcontrol_sizer->Add(calibrate_button, 0, wxALL | wxALIGN_RIGHT, 5);\n\n\t\tsizer->Add(control_sizer, 0, wxEXPAND, 5);\n\t}\n\n\n\n\tthis->SetSizer(sizer);\n\tthis->Layout();\n\tthis->Fit();\n\n\tthis->Bind(wxEVT_CLOSE_WINDOW, &WiimoteControllerSettings::on_close, this);\n\n\tm_timer = new wxTimer(this);\n\tBind(wxEVT_TIMER, &WiimoteControllerSettings::on_timer, this);\n\tm_timer->Start(100);\n}\n\nWiimoteControllerSettings::~WiimoteControllerSettings()\n{\n\tm_controller->stop_rumble();\n\tm_timer->Stop();\n}\n\nvoid WiimoteControllerSettings::update_settings()\n{\n\t// update settings\n\tm_controller->set_settings(m_settings);\n\tif (m_use_motion)\n\t\tm_controller->set_use_motion(m_use_motion->GetValue());\n\n\tm_controller->set_packet_delay(m_package_delay->GetValue());\n}\n\nvoid WiimoteControllerSettings::on_timer(wxTimerEvent& event)\n{\n\tif (m_rumble_time.has_value() && std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_rumble_time.value()).count() > 500)\n\t{\n\t\tm_controller->stop_rumble();\n\t\tm_rumble_time = {};\n\t}\n\n\tconst auto& default_state = m_controller->get_default_state();\n\n\tauto state = m_controller->raw_state();\n\tm_controller->apply_axis_setting(state.axis, default_state.axis, m_settings.axis);\n\tm_controller->apply_axis_setting(state.rotation, default_state.rotation, m_settings.rotation);\n\tm_controller->apply_axis_setting(state.trigger, default_state.trigger, m_settings.trigger);\n\n\tif (m_nunchuck_settings->IsEnabled())\n\t{\n\t\tm_nunchuck_draw->SetDeadzone(m_settings.axis.deadzone);\n\t\tm_nunchuck_draw->SetAxisValue(state.axis);\n\t}\n\n\tif (m_classic_settings->IsEnabled())\n\t{\n\t\tm_classic_axis_draw->SetDeadzone(m_settings.axis.deadzone);\n\t\tm_classic_axis_draw->SetAxisValue(state.axis);\n\n\t\tm_classic_rotation_draw->SetDeadzone(m_settings.rotation.deadzone);\n\t\tm_classic_rotation_draw->SetAxisValue(state.rotation);\n\t}\n\n\twxString label;\n\tswitch (m_controller->get_extension())\n\t{\n\tcase NativeWiimoteController::Nunchuck:\n\t\tlabel = _(\"Nunchuck\");\n\t\tm_nunchuck_settings->Enable();\n\t\tm_classic_settings->Disable();\n\t\tbreak; \n\tcase NativeWiimoteController::Classic: \n\t\tlabel = _(\"Classic\");\n\t\tm_nunchuck_settings->Disable();\n\t\tm_classic_settings->Enable();\n\t\tbreak;\n\tdefault: \n\t\tm_nunchuck_settings->Disable();\n\t\tm_classic_settings->Disable();\n\t}\n\n\tif(m_controller->is_mpls_attached())\n\t{\n\t\tconst bool empty = label.empty();\n\t\tif (!empty)\n\t\t\tlabel.Append(\" (\");\n\n\t\tlabel.Append(_(\"MotionPlus\"));\n\n\t\tif (!empty)\n\t\t\tlabel.Append(\")\");\n\t}\n\t\n\tif(label.empty())\n\t{\n\t\tlabel = _(\"None\");\n\t}\n\n\tm_extension_text->SetLabelText(label);\n}\n\nvoid WiimoteControllerSettings::on_close(wxCloseEvent& event)\n{\n\tif (this->GetReturnCode() == 0 || this->GetReturnCode() == wxID_OK)\n\t\tupdate_settings();\n\n\tevent.Skip();\n}\n\nvoid WiimoteControllerSettings::on_slider_change(wxCommandEvent& event)\n{\n\tupdate_slider_text(event);\n\tconst auto new_value = (float)event.GetInt() / 100.0f;\n\n\tauto* obj = event.GetEventObject();\n\tif (obj == m_nunchuck_deadzone || obj == m_classic_axis_deadzone)\n\t\tm_settings.axis.deadzone = new_value;\n\telse if (obj == m_nunchuck_range || obj == m_classic_axis_range)\n\t\t\tm_settings.axis.range = new_value;\n\telse if (obj == m_classic_rotation_deadzone)\n\t\t\tm_settings.rotation.deadzone = new_value;\n\telse if (obj == m_classic_rotation_range)\n\t\t\tm_settings.rotation.range = new_value;\n}\n\nvoid WiimoteControllerSettings::on_rumble_change(wxCommandEvent& event)\n{\n\tconst auto rumble_value = m_rumble->GetValue();\n\tm_settings.rumble = rumble_value ? 1.0f : 0.0f;\n\n\tm_controller->set_rumble(m_settings.rumble);\n\tif (rumble_value)\n\t\tm_controller->start_rumble();\n\telse\n\t\tm_controller->stop_rumble();\n\n\tm_controller->set_rumble(m_rumble_backup);\n\n\tm_rumble_time = std::chrono::steady_clock::now();\n}\n\nvoid WiimoteControllerSettings::on_delay_change(wxCommandEvent& event)\n{\n\tupdate_slider_text(event, \"%dms\");\n}\n\n#endif"
  },
  {
    "path": "src/gui/wxgui/input/settings/WiimoteControllerSettings.h",
    "content": "#pragma once\n\n#ifdef SUPPORTS_WIIMOTE\n\n#include <wx/dialog.h>\n#include <wx/timer.h>\n#include <wx/slider.h>\n\n#include \"input/api/Controller.h\"\n#include \"input/api/Wiimote/NativeWiimoteController.h\"\n\nclass wxStaticBox;\nclass wxStaticText;\nclass wxCheckBox;\nclass wxInputDraw;\n\nclass WiimoteControllerSettings : public wxDialog\n{\npublic:\n\tWiimoteControllerSettings(wxWindow* parent, const wxPoint& position, std::shared_ptr<NativeWiimoteController> controller);\n\t~WiimoteControllerSettings();\n\nprivate:\n\tvoid update_settings();\n\n\tstd::shared_ptr<NativeWiimoteController> m_controller;\n\tControllerBase::Settings m_settings;\n\tfloat m_rumble_backup;\n\tuint32 m_packet_delay_backup;\n\n\twxTimer* m_timer;\n\tstd::optional<std::chrono::steady_clock::time_point> m_rumble_time{};\n\n\twxStaticText* m_extension_text;\n\n\twxSlider* m_package_delay;\n\twxCheckBox* m_rumble = nullptr;\n\twxCheckBox* m_use_motion = nullptr;\n\n\twxStaticBox* m_nunchuck_settings;\n\twxSlider* m_nunchuck_deadzone, * m_nunchuck_range;\n\twxInputDraw* m_nunchuck_draw;\n\n\twxStaticBox* m_classic_settings;\n\twxSlider* m_classic_axis_deadzone, * m_classic_axis_range;\n\twxInputDraw* m_classic_axis_draw;\n\twxSlider* m_classic_rotation_deadzone, * m_classic_rotation_range;\n\twxInputDraw* m_classic_rotation_draw;\n\n\t\n\n\t\n\n\tvoid on_timer(wxTimerEvent& event);\n\tvoid on_close(wxCloseEvent& event);\n\tvoid on_slider_change(wxCommandEvent& event);\n\tvoid on_rumble_change(wxCommandEvent& event);\n\tvoid on_delay_change(wxCommandEvent& event);\n};\n\n#endif"
  },
  {
    "path": "src/gui/wxgui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Scheduler.h\"\n#include \"DebugPPCThreadsWindow.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/RPL/rpl_symbol_storage.h\"\n\n#include \"wxgui/components/wxProgressDialogManager.h\"\n\n#include <cinttypes>\n#include <helpers/wxHelpers.h>\n#include <wx/listctrl.h>\n\nenum\n{\n\t// options\n\tREFRESH_ID = wxID_HIGHEST + 1,\n\tAUTO_REFRESH_ID,\n\tCLOSE_ID,\n\tGPLIST_ID,\n\n\t// list context menu options\n\tTHREADLIST_MENU_BOOST_PRIO_1,\n\tTHREADLIST_MENU_BOOST_PRIO_5,\n\tTHREADLIST_MENU_DECREASE_PRIO_1,\n\tTHREADLIST_MENU_DECREASE_PRIO_5,\n\tTHREADLIST_MENU_SUSPEND,\n\tTHREADLIST_MENU_RESUME,\n\tTHREADLIST_MENU_DUMP_STACK_TRACE,\n\tTHREADLIST_MENU_PROFILE_THREAD,\n};\n\nwxBEGIN_EVENT_TABLE(DebugPPCThreadsWindow, wxFrame)\n\tEVT_BUTTON(CLOSE_ID, DebugPPCThreadsWindow::OnCloseButton)\n\t\tEVT_BUTTON(REFRESH_ID, DebugPPCThreadsWindow::OnRefreshButton)\n\t\t\tEVT_CLOSE(DebugPPCThreadsWindow::OnClose)\n\t\t\t\twxEND_EVENT_TABLE()\n\n\t\t\t\t\tDebugPPCThreadsWindow::DebugPPCThreadsWindow(wxFrame& parent)\n\t: wxFrame(&parent, wxID_ANY, _(\"PPC threads\"), wxDefaultPosition, wxSize(930, 280),\n\t\t\t  wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER)\n{\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\tm_thread_list = new wxListView(this, GPLIST_ID, wxPoint(0, 0), wxSize(930, 240), wxLC_REPORT);\n\n\tm_thread_list->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, \"Courier New\")); // wxSystemSettings::GetFont(wxSYS_OEM_FIXED_FONT));\n\n\t// add columns\n\twxListItem col0;\n\tcol0.SetId(0);\n\tcol0.SetText(\"Address\");\n\tcol0.SetWidth(75);\n\tm_thread_list->InsertColumn(0, col0);\n\twxListItem col1;\n\tcol1.SetId(1);\n\tcol1.SetText(\"Entry\");\n\tcol1.SetWidth(75);\n\tm_thread_list->InsertColumn(1, col1);\n\twxListItem col2;\n\tcol2.SetId(2);\n\tcol2.SetText(\"Stack\");\n\tcol2.SetWidth(145);\n\tm_thread_list->InsertColumn(2, col2);\n\twxListItem col3;\n\tcol3.SetId(3);\n\tcol3.SetText(\"PC\");\n\tcol3.SetWidth(120);\n\tm_thread_list->InsertColumn(3, col3);\n\twxListItem colLR;\n\tcolLR.SetId(4);\n\tcolLR.SetText(\"LR\");\n\tcolLR.SetWidth(75);\n\tm_thread_list->InsertColumn(4, colLR);\n\twxListItem col4;\n\tcol4.SetId(5);\n\tcol4.SetText(\"State\");\n\tcol4.SetWidth(90);\n\tm_thread_list->InsertColumn(5, col4);\n\twxListItem col5;\n\tcol5.SetId(6);\n\tcol5.SetText(\"Affinity\");\n\tcol5.SetWidth(70);\n\tm_thread_list->InsertColumn(6, col5);\n\twxListItem colPriority;\n\tcolPriority.SetId(7);\n\tcolPriority.SetText(\"Priority\");\n\tcolPriority.SetWidth(80);\n\tm_thread_list->InsertColumn(7, colPriority);\n\twxListItem col6;\n\tcol6.SetId(8);\n\tcol6.SetText(\"SliceStart\");\n\tcol6.SetWidth(110);\n\tm_thread_list->InsertColumn(8, col6);\n\twxListItem col7;\n\tcol7.SetId(9);\n\tcol7.SetText(\"SumWakeTime\");\n\tcol7.SetWidth(110);\n\tm_thread_list->InsertColumn(9, col7);\n\twxListItem col8;\n\tcol8.SetId(10);\n\tcol8.SetText(\"ThreadName\");\n\tcol8.SetWidth(180);\n\tm_thread_list->InsertColumn(10, col8);\n\twxListItem col9;\n\tcol9.SetId(11);\n\tcol9.SetText(\"GPR\");\n\tcol9.SetWidth(180);\n\tm_thread_list->InsertColumn(11, col9);\n\twxListItem col10;\n\tcol10.SetId(12);\n\tcol10.SetText(\"Extra info\");\n\tcol10.SetWidth(180);\n\tm_thread_list->InsertColumn(12, col10);\n\n\tsizer->Add(m_thread_list, 1, wxEXPAND | wxALL, 5);\n\n\tauto* row = new wxBoxSizer(wxHORIZONTAL);\n\twxButton* button = new wxButton(this, REFRESH_ID, _(\"Refresh\"), wxPoint(0, 0), wxSize(80, 26));\n\trow->Add(button, 0, wxALL, 5);\n\n\tm_auto_refresh = new wxCheckBox(this, AUTO_REFRESH_ID, _(\"Auto refresh\"));\n\tm_auto_refresh->SetValue(true);\n\trow->Add(m_auto_refresh, 0, wxEXPAND | wxALL, 5);\n\n\tsizer->Add(row, 0, wxEXPAND | wxALL, 5);\n\n\tm_thread_list->Bind(wxEVT_RIGHT_DOWN, &DebugPPCThreadsWindow::OnThreadListRightClick, this);\n\n\tSetSizer(sizer);\n\n\tRefreshThreadList();\n\n\tm_timer = new wxTimer(this);\n\tthis->Bind(wxEVT_TIMER, &DebugPPCThreadsWindow::OnTimer, this);\n\tm_timer->Start(250);\n}\n\nDebugPPCThreadsWindow::~DebugPPCThreadsWindow()\n{\n\tm_timer->Stop();\n}\n\nvoid DebugPPCThreadsWindow::OnCloseButton(wxCommandEvent& event)\n{\n\tClose();\n}\n\nvoid DebugPPCThreadsWindow::OnRefreshButton(wxCommandEvent& event)\n{\n\tRefreshThreadList();\n}\n\nvoid DebugPPCThreadsWindow::OnClose(wxCloseEvent& event)\n{\n\tClose();\n}\n\nvoid DebugPPCThreadsWindow::OnTimer(wxTimerEvent& event)\n{\n\tif (m_auto_refresh->IsChecked())\n\t\tRefreshThreadList();\n}\n\n#define _r(__idx) _swapEndianU32(cafeThread->context.gpr[__idx])\n\nvoid DebugPPCThreadsWindow::RefreshThreadList()\n{\n\twxWindowUpdateLocker lock(m_thread_list);\n\n\tlong selected_thread = 0;\n\tconst int selection = m_thread_list->GetFirstSelected();\n\tif (selection != wxNOT_FOUND)\n\t\tselected_thread = m_thread_list->GetItemData(selection);\n\n\tconst int scrollPos = m_thread_list->GetScrollPos(0);\n\tm_thread_list->DeleteAllItems();\n\n\tif (activeThreadCount > 0)\n\t{\n\t\t__OSLockScheduler();\n\t\tsrwlock_activeThreadList.LockWrite();\n\t\tfor (sint32 i = 0; i < activeThreadCount; i++)\n\t\t{\n\t\t\tMPTR threadItrMPTR = activeThread[i];\n\t\t\tOSThread_t* cafeThread = (OSThread_t*)memory_getPointerFromVirtualOffset(threadItrMPTR);\n\n\t\t\twxListItem item;\n\t\t\titem.SetId(i);\n\t\t\titem.SetText(wxString::Format(\"%08X\", threadItrMPTR));\n\t\t\tm_thread_list->InsertItem(item);\n\t\t\tm_thread_list->SetItemData(item, (long)threadItrMPTR);\n\t\t\t// entry point\n\t\t\tm_thread_list->SetItem(i, 1, wxString::Format(\"%08X\", cafeThread->entrypoint.GetMPTR()));\n\t\t\t// stack base (low)\n\t\t\tm_thread_list->SetItem(i, 2, wxString::Format(\"%08X - %08X\", cafeThread->stackEnd.GetMPTR(), cafeThread->stackBase.GetMPTR()));\n\t\t\t// pc\n\t\t\tRPLStoredSymbol* symbol = rplSymbolStorage_getByAddress(cafeThread->context.srr0);\n\t\t\twxString pcLabel;\n\t\t\tif (symbol)\n\t\t\t\tpcLabel = wxString::Format(\"%s (0x%08x)\", (const char*)symbol->symbolName, cafeThread->context.srr0);\n\t\t\telse\n\t\t\t\tpcLabel = wxString::Format(\"%08X\", cafeThread->context.srr0);\n\t\t\tm_thread_list->SetItem(i, 3, pcLabel);\n\t\t\t// lr\n\t\t\tm_thread_list->SetItem(i, 4, wxString::Format(\"%08X\", _swapEndianU32(cafeThread->context.lr)));\n\t\t\t// state\n\t\t\tOSThread_t::THREAD_STATE threadState = cafeThread->state;\n\t\t\twxString threadStateStr = \"UNDEFINED\";\n\t\t\tif (cafeThread->suspendCounter != 0)\n\t\t\t\tthreadStateStr = \"SUSPENDED\";\n\t\t\telse if (threadState == OSThread_t::THREAD_STATE::STATE_NONE)\n\t\t\t\tthreadStateStr = \"NONE\";\n\t\t\telse if (threadState == OSThread_t::THREAD_STATE::STATE_READY)\n\t\t\t\tthreadStateStr = \"READY\";\n\t\t\telse if (threadState == OSThread_t::THREAD_STATE::STATE_RUNNING)\n\t\t\t\tthreadStateStr = \"RUNNING\";\n\t\t\telse if (threadState == OSThread_t::THREAD_STATE::STATE_WAITING)\n\t\t\t\tthreadStateStr = \"WAITING\";\n\t\t\telse if (threadState == OSThread_t::THREAD_STATE::STATE_MORIBUND)\n\t\t\t\tthreadStateStr = \"MORIBUND\";\n\t\t\tm_thread_list->SetItem(i, 5, threadStateStr);\n\t\t\t// affinity\n\t\t\tuint8 affinity = cafeThread->attr & 7;\n\t\t\tuint8 affinityReal = cafeThread->context.affinity;\n\t\t\twxString affinityLabel;\n\t\t\tif (affinity != affinityReal)\n\t\t\t\taffinityLabel = wxString::Format(\"(!) %d%d%d real: %d%d%d\", (affinity >> 0) & 1, (affinity >> 1) & 1, (affinity >> 2) & 1, (affinityReal >> 0) & 1, (affinityReal >> 1) & 1, (affinityReal >> 2) & 1);\n\t\t\telse\n\t\t\t\taffinityLabel = wxString::Format(\"%d%d%d\", (affinity >> 0) & 1, (affinity >> 1) & 1, (affinity >> 2) & 1);\n\t\t\tm_thread_list->SetItem(i, 6, affinityLabel);\n\t\t\t// priority\n\t\t\tsint32 effectivePriority = cafeThread->effectivePriority;\n\t\t\tm_thread_list->SetItem(i, 7, wxString::Format(\"%d\", effectivePriority));\n\t\t\t// last awake in cycles\n\t\t\tuint64 lastWakeUpTime = cafeThread->wakeUpTime;\n\t\t\tm_thread_list->SetItem(i, 8, wxString::Format(\"%\" PRIu64, lastWakeUpTime));\n\t\t\t// awake time in cycles\n\t\t\tuint64 awakeTime = cafeThread->totalCycles;\n\t\t\tm_thread_list->SetItem(i, 9, wxString::Format(\"%\" PRIu64, awakeTime));\n\t\t\t// thread name\n\t\t\tconst char* threadName = \"NULL\";\n\t\t\tif (!cafeThread->threadName.IsNull())\n\t\t\t\tthreadName = cafeThread->threadName.GetPtr();\n\t\t\tm_thread_list->SetItem(i, 10, threadName);\n\t\t\t// GPR\n\t\t\tm_thread_list->SetItem(i, 11, wxString::Format(\"r3 %08x r4 %08x r5 %08x r6 %08x r7 %08x\", _r(3), _r(4), _r(5), _r(6), _r(7)));\n\t\t\t// waiting condition / extra info\n\t\t\tcoreinit::OSMutex* mutex = cafeThread->waitingForMutex;\n\t\t\twxString extraInfoLabel;\n\t\t\tif (mutex)\n\t\t\t\textraInfoLabel = wxString::Format(\"Mutex 0x%08x (Held by thread 0x%08X Lock-Count: %d)\", memory_getVirtualOffsetFromPointer(mutex), mutex->owner.GetMPTR(), (uint32)mutex->lockCount);\n\n\t\t\t// OSSetThreadCancelState\n\t\t\tif (cafeThread->requestFlags & OSThread_t::REQUEST_FLAG_CANCEL)\n\t\t\t\textraInfoLabel += \"[Cancel requested]\";\n\n\t\t\tm_thread_list->SetItem(i, 12, extraInfoLabel);\n\n\t\t\tif (selected_thread != 0 && selected_thread == (long)threadItrMPTR)\n\t\t\t{\n\t\t\t\tm_thread_list->Select(i);\n\t\t\t\tm_thread_list->Focus(i);\n\t\t\t}\n\t\t}\n\t\tsrwlock_activeThreadList.UnlockWrite();\n\t\t__OSUnlockScheduler();\n\t}\n\n\tm_thread_list->SetScrollPos(0, scrollPos, true);\n}\n\nvoid DebugPPCThreadsWindow::DumpStackTrace(OSThread_t* thread)\n{\n\tcemuLog_log(LogType::Force, \"Dumping stack trace for thread {0:08x} LR: {1:08x}\", memory_getVirtualOffsetFromPointer(thread), _swapEndianU32(thread->context.lr));\n\tDebugLogStackTrace(thread, _swapEndianU32(thread->context.gpr[1]), true);\n}\n\nvoid DebugPPCThreadsWindow::PresentProfileResults(OSThread_t* thread, const std::unordered_map<VAddr, uint32>& samples)\n{\n\tstd::vector<std::pair<VAddr, uint32>> sortedSamples;\n\t// count samples\n\tuint32 totalSampleCount = 0;\n\tfor (auto& sample : samples)\n\t\ttotalSampleCount += sample.second;\n\tcemuLog_log(LogType::Force, \"--- Thread {:08x} profile results with {:} samples captured ---\",\n\t\t\t\tMEMPTR<OSThread_t>(thread).GetMPTR(), totalSampleCount);\n\tcemuLog_log(LogType::Force, \"Exclusive time, grouped by function:\");\n\t// print samples grouped by function\n\tsortedSamples.clear();\n\tfor (auto& sample : samples)\n\t{\n\t\tRPLStoredSymbol* symbol = rplSymbolStorage_getByClosestAddress(sample.first);\n\t\tVAddr sampleAddr = sample.first;\n\t\tif (symbol)\n\t\t\tsampleAddr = symbol->address;\n\t\tauto it = std::find_if(sortedSamples.begin(), sortedSamples.end(),\n\t\t\t\t\t\t\t   [sampleAddr](const std::pair<VAddr, uint32>& a) { return a.first == sampleAddr; });\n\t\tif (it != sortedSamples.end())\n\t\t\tit->second += sample.second;\n\t\telse\n\t\t\tsortedSamples.push_back(std::make_pair(sampleAddr, sample.second));\n\t}\n\tstd::sort(sortedSamples.begin(), sortedSamples.end(),\n\t\t\t  [](const std::pair<VAddr, uint32>& a, const std::pair<VAddr, uint32>& b) { return a.second > b.second; });\n\tfor (auto& sample : sortedSamples)\n\t{\n\t\tif (sample.second < 3)\n\t\t\tcontinue;\n\t\tVAddr sampleAddr = sample.first;\n\t\tRPLStoredSymbol* symbol = rplSymbolStorage_getByClosestAddress(sample.first);\n\t\tstd::string strName;\n\t\tif (symbol)\n\t\t{\n\t\t\tstrName = fmt::format(\"{}.{}+0x{:x}\", (const char*)symbol->libName, (const char*)symbol->symbolName,\n\t\t\t\t\t\t\t\t  sampleAddr - symbol->address);\n\t\t}\n\t\telse\n\t\t\tstrName = \"Unknown\";\n\t\tcemuLog_log(LogType::Force, \"[{:08x}] {:8.2f}% (Samples: {:5}) Symbol: {}\", sample.first,\n\t\t\t\t\t(double)(sample.second * 100) / (double)totalSampleCount, sample.second, strName);\n\t}\n}\n\nvoid DebugPPCThreadsWindow::ProfileThreadWorker(OSThread_t* thread)\n{\n\twxProgressDialogManager progressDialog(this);\n\tprogressDialog.Create(_(\"Profiling thread\"),\n\t\t\t\t\t\t  _(\"Capturing samples...\"),\n\t\t\t\t\t\t  1000, // range\n\t\t\t\t\t\t  wxPD_CAN_SKIP);\n\n\tstd::unordered_map<VAddr, uint32> samples;\n\t// loop for one minute\n\tuint64 startTime = std::chrono::duration_cast<std::chrono::milliseconds>(\n\t\t\t\t\t\t   std::chrono::system_clock::now().time_since_epoch())\n\t\t\t\t\t\t   .count();\n\tuint32 totalSampleCount = 0;\n\twhile (true)\n\t{\n\t\t// suspend thread\n\t\tcoreinit::OSSuspendThread(thread);\n\t\t// wait until thread is not running anymore\n\t\t__OSLockScheduler();\n\t\twhile (coreinit::OSIsThreadRunningNoLock(thread))\n\t\t{\n\t\t\t__OSUnlockScheduler();\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\t\t__OSLockScheduler();\n\t\t}\n\t\tuint32 sampleIP = thread->context.srr0;\n\t\t__OSUnlockScheduler();\n\t\tcoreinit::OSResumeThread(thread);\n\t\t// count sample\n\t\tsamples[sampleIP]++;\n\t\ttotalSampleCount++;\n\t\tif ((totalSampleCount % 50) == 0)\n\t\t{\n\t\t\twxString msg = formatWxString(_(\"Capturing samples... ({:})\\nResults will be written to log.txt\\n\"), totalSampleCount);\n\t\t\tif (totalSampleCount < 30000)\n\t\t\t\tmsg.Append(_(\"Click Skip button for early results with lower accuracy\"));\n\t\t\telse\n\t\t\t\tmsg.Append(_(\"Click Skip button to finish\"));\n\t\t\tprogressDialog.Update(totalSampleCount * 1000 / 30000, msg);\n\t\t\tif (progressDialog.IsCancelledOrSkipped())\n\t\t\t\tbreak;\n\t\t}\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t}\n\tPresentProfileResults(thread, samples);\n\tprogressDialog.Destroy();\n}\n\nvoid DebugPPCThreadsWindow::ProfileThread(OSThread_t* thread)\n{\n\tstd::thread profileThread(&DebugPPCThreadsWindow::ProfileThreadWorker, this, thread);\n\tprofileThread.detach();\n}\n\nvoid DebugPPCThreadsWindow::OnThreadListPopupClick(wxCommandEvent& evt)\n{\n\tMPTR threadMPTR = (MPTR)(size_t)static_cast<wxMenu*>(evt.GetEventObject())->GetClientData();\n\tOSThread_t* osThread = (OSThread_t*)memory_getPointerFromVirtualOffset(threadMPTR);\n\t__OSLockScheduler();\n\tif (!coreinit::__OSIsThreadActive(osThread))\n\t{\n\t\t__OSUnlockScheduler();\n\t\treturn;\n\t}\n\t__OSUnlockScheduler();\n\t// handle command\n\tswitch (evt.GetId())\n\t{\n\tcase THREADLIST_MENU_BOOST_PRIO_5:\n\t\tosThread->basePriority = osThread->basePriority - 5;\n\t\tbreak;\n\tcase THREADLIST_MENU_BOOST_PRIO_1:\n\t\tosThread->basePriority = osThread->basePriority - 1;\n\t\tbreak;\n\tcase THREADLIST_MENU_DECREASE_PRIO_5:\n\t\tosThread->basePriority = osThread->basePriority + 5;\n\t\tbreak;\n\tcase THREADLIST_MENU_DECREASE_PRIO_1:\n\t\tosThread->basePriority = osThread->basePriority + 1;\n\t\tbreak;\n\tcase THREADLIST_MENU_SUSPEND:\n\t\tcoreinit::OSSuspendThread(osThread);\n\t\tbreak;\n\tcase THREADLIST_MENU_RESUME:\n\t\tcoreinit::OSResumeThread(osThread);\n\t\tbreak;\n\tcase THREADLIST_MENU_DUMP_STACK_TRACE:\n\t\tDumpStackTrace(osThread);\n\t\tbreak;\n\tcase THREADLIST_MENU_PROFILE_THREAD:\n\t\tProfileThread(osThread);\n\t\tbreak;\n\t}\n\tcoreinit::__OSUpdateThreadEffectivePriority(osThread);\n\t// update thread list\n\tRefreshThreadList();\n}\n\nvoid DebugPPCThreadsWindow::OnThreadListRightClick(wxMouseEvent& event)\n{\n\t// Get the item index\n\tint hitTestFlag;\n\tint itemIndex = m_thread_list->HitTest(event.GetPosition(), hitTestFlag);\n\tif (itemIndex == wxNOT_FOUND)\n\t\treturn;\n\t// select item\n\tm_thread_list->Focus(itemIndex);\n\tlong sel = m_thread_list->GetFirstSelected();\n\tif (sel != wxNOT_FOUND)\n\t\tm_thread_list->Select(sel, false);\n\tm_thread_list->Select(itemIndex);\n\t// check if thread is still on the list of active threads\n\tMPTR threadMPTR = (MPTR)m_thread_list->GetItemData(itemIndex);\n\t__OSLockScheduler();\n\tif (!coreinit::__OSIsThreadActive(MEMPTR<OSThread_t>(threadMPTR)))\n\t{\n\t\t__OSUnlockScheduler();\n\t\treturn;\n\t}\n\t__OSUnlockScheduler();\n\t// create menu entry\n\twxMenu menu;\n\tmenu.SetClientData((void*)(size_t)threadMPTR);\n\tmenu.Append(THREADLIST_MENU_BOOST_PRIO_5, _(\"Boost priority (-5)\"));\n\tmenu.Append(THREADLIST_MENU_BOOST_PRIO_1, _(\"Boost priority (-1)\"));\n\tmenu.AppendSeparator();\n\tmenu.Append(THREADLIST_MENU_DECREASE_PRIO_5, _(\"Decrease priority (+5)\"));\n\tmenu.Append(THREADLIST_MENU_DECREASE_PRIO_1, _(\"Decrease priority (+1)\"));\n\tmenu.AppendSeparator();\n\tmenu.Append(THREADLIST_MENU_RESUME, _(\"Resume\"));\n\tmenu.Append(THREADLIST_MENU_SUSPEND, _(\"Suspend\"));\n\tmenu.AppendSeparator();\n\tmenu.Append(THREADLIST_MENU_DUMP_STACK_TRACE, _(\"Write stack trace to log\"));\n\tmenu.Append(THREADLIST_MENU_PROFILE_THREAD, _(\"Profile thread\"));\n\tmenu.Bind(wxEVT_COMMAND_MENU_SELECTED, &DebugPPCThreadsWindow::OnThreadListPopupClick, this);\n\tPopupMenu(&menu);\n}\n\nvoid DebugPPCThreadsWindow::Close()\n{\n\tthis->Destroy();\n}\n"
  },
  {
    "path": "src/gui/wxgui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.h",
    "content": "#pragma once\n\n#include <wx/wx.h>\n\nclass wxListView;\n\nclass DebugPPCThreadsWindow: public wxFrame\n{\npublic:\n\tDebugPPCThreadsWindow(wxFrame& parent);\n\t~DebugPPCThreadsWindow();\n\n\tvoid OnCloseButton(wxCommandEvent& event);\n\tvoid OnRefreshButton(wxCommandEvent& event);\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid RefreshThreadList();\n\tvoid OnThreadListPopupClick(wxCommandEvent &evt);\n\tvoid OnThreadListRightClick(wxMouseEvent& event);\n\n\tvoid Close();\n\nprivate:\n    void ProfileThread(struct OSThread_t* thread);\n    void ProfileThreadWorker(OSThread_t* thread);\n    void PresentProfileResults(OSThread_t* thread, const std::unordered_map<VAddr, uint32>& samples);\n    void DumpStackTrace(struct OSThread_t* thread);\n\n\twxListView* m_thread_list;\n\twxCheckBox* m_auto_refresh;\n\twxTimer* m_timer;\n\n\tvoid OnTimer(wxTimerEvent& event);\n\n\twxDECLARE_EVENT_TABLE();\n\n\n};\n"
  },
  {
    "path": "src/gui/wxgui/windows/TextureRelationViewer/TextureRelationWindow.cpp",
    "content": "#include \"wxgui/wxgui.h\"\n#include \"wxHelper.h\"\n#include \"TextureRelationWindow.h\"\n#include \"Cafe/HW/Latte/Core/LatteTexture.h\"\n\nenum\n{\n\t// options\n\tREFRESH_ID,\n\tCLOSE_ID,\n\tTEX_LIST_A_ID,\n\tTEX_LIST_B_ID,\n\tCHECKBOX_SHOW_ONLY_ACTIVE,\n\tCHECKBOX_SHOW_VIEWS,\n};\n\nwxBEGIN_EVENT_TABLE(TextureRelationViewerWindow, wxFrame)\nEVT_BUTTON(CLOSE_ID, TextureRelationViewerWindow::OnCloseButton)\nEVT_BUTTON(REFRESH_ID, TextureRelationViewerWindow::OnRefreshButton)\nEVT_CHECKBOX(CHECKBOX_SHOW_ONLY_ACTIVE, TextureRelationViewerWindow::OnCheckbox)\nEVT_CHECKBOX(CHECKBOX_SHOW_VIEWS, TextureRelationViewerWindow::OnCheckbox)\n\nEVT_CLOSE(TextureRelationViewerWindow::OnClose)\nwxEND_EVENT_TABLE()\n\nwxListCtrl* textureRelationListA;\nbool isTextureViewerOpen = false;\n\nvoid openTextureViewer(wxFrame& parentFrame)\n{\n\tif (isTextureViewerOpen)\n\t\treturn;\n\tauto frame = new TextureRelationViewerWindow(parentFrame);\n\tframe->Show(true);\n}\n\nTextureRelationViewerWindow::TextureRelationViewerWindow(wxFrame& parent)\n\t: wxFrame(&parent, wxID_ANY, _(\"Texture cache\"), wxDefaultPosition, wxSize(1000, 480), wxCLOSE_BOX | wxCLIP_CHILDREN | wxCAPTION | wxRESIZE_BORDER)\n{\n\tisTextureViewerOpen = true;\n\n\tthis->showOnlyActive = false;\n\tthis->showTextureViews = true;\n\n\twxPanel* mainPane = new wxPanel(this);\n\twxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);\n\ttextureRelationListA = new wxListCtrl(mainPane, TEX_LIST_A_ID, wxPoint(0, 0), wxSize(1008, 440), wxLC_REPORT);\n\n\ttextureRelationListA->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, \"Courier New\"));//wxSystemSettings::GetFont(wxSYS_OEM_FIXED_FONT));\n\n\t// add columns\n\twxListItem colType;\n\tsint32 columnIndex = 0;\n\tcolType.SetId(columnIndex); columnIndex++;\n\tcolType.SetText(\"Type\");\n\tcolType.SetWidth(85);\n\ttextureRelationListA->InsertColumn(columnIndex-1, colType);\n    wxListItem colPhysAddr;\n    colPhysAddr.SetId(columnIndex); columnIndex++;\n    colPhysAddr.SetText(\"PhysAddr\");\n    colPhysAddr.SetWidth(80);\n    textureRelationListA->InsertColumn(columnIndex-1, colPhysAddr);\n    wxListItem colPhysMipAddr;\n    colPhysMipAddr.SetId(columnIndex); columnIndex++;\n    colPhysMipAddr.SetText(\"MipPAddr\");\n    colPhysMipAddr.SetWidth(80);\n    textureRelationListA->InsertColumn(columnIndex-1, colPhysMipAddr);\n\twxListItem colDim;\n\tcolDim.SetId(columnIndex); columnIndex++;\n\tcolDim.SetText(\"Dim\");\n\tcolDim.SetWidth(80);\n\ttextureRelationListA->InsertColumn(columnIndex-1, colDim);\n\twxListItem colResolution;\n\tcolResolution.SetId(columnIndex); columnIndex++;\n\tcolResolution.SetText(\"Resolution\");\n\tcolResolution.SetWidth(110);\n\ttextureRelationListA->InsertColumn(columnIndex-1, colResolution);\n\twxListItem colFormat;\n\tcolFormat.SetId(columnIndex); columnIndex++;\n\tcolFormat.SetText(\"Format\");\n\tcolFormat.SetWidth(70);\n\ttextureRelationListA->InsertColumn(columnIndex-1, colFormat);\n\twxListItem colPitch;\n\tcolPitch.SetId(columnIndex); columnIndex++;\n\tcolPitch.SetText(\"Pitch\");\n\tcolPitch.SetWidth(80);\n\ttextureRelationListA->InsertColumn(columnIndex-1, colPitch);\n\twxListItem colTilemode;\n\tcolTilemode.SetId(columnIndex); columnIndex++;\n\tcolTilemode.SetText(\"Tilemode\");\n\tcolTilemode.SetWidth(80);\n\ttextureRelationListA->InsertColumn(columnIndex-1, colTilemode);\n\twxListItem colSliceRange;\n\tcolSliceRange.SetId(columnIndex); columnIndex++;\n\tcolSliceRange.SetText(\"SliceRange\");\n\tcolSliceRange.SetWidth(90);\n\ttextureRelationListA->InsertColumn(columnIndex-1, colSliceRange);\n\twxListItem colMipRange;\n\tcolMipRange.SetId(columnIndex); columnIndex++;\n\tcolMipRange.SetText(\"MipRange\");\n\tcolMipRange.SetWidth(90);\n\ttextureRelationListA->InsertColumn(columnIndex-1, colMipRange);\n\twxListItem colAge;\n\tcolAge.SetId(columnIndex); columnIndex++;\n\tcolAge.SetText(\"Last access\");\n\tcolAge.SetWidth(90);\n\ttextureRelationListA->InsertColumn(columnIndex - 1, colAge);\n\twxListItem colOverwriteRes;\n\tcolOverwriteRes.SetId(columnIndex); columnIndex++;\n\tcolOverwriteRes.SetText(\"OverwriteRes\");\n\tcolOverwriteRes.SetWidth(110);\n\ttextureRelationListA->InsertColumn(columnIndex - 1, colOverwriteRes);\n\n\twxBoxSizer* sizerBottom = new wxBoxSizer(wxHORIZONTAL);\n\n\tsizer->Add(textureRelationListA, 1, wxEXPAND | wxBOTTOM, 0);\n\twxButton* button = new wxButton(mainPane, REFRESH_ID, _(\"Refresh\"));\n\tsizerBottom->Add(button, 0, wxALIGN_CENTER_VERTICAL | wxBOTTOM | wxTOP | wxLEFT, 10);\n\n\twxCheckBox* checkboxShowOnlyActive = new wxCheckBox(mainPane, CHECKBOX_SHOW_ONLY_ACTIVE, _(\"Show only active\"));\n\tsizerBottom->Add(checkboxShowOnlyActive, 0, wxALIGN_CENTER_VERTICAL | wxBOTTOM | wxTOP | wxLEFT, 10);\n\n\twxCheckBox* checkboxShowViews = new wxCheckBox(mainPane, CHECKBOX_SHOW_VIEWS, _(\"Show views\"));\n\tsizerBottom->Add(checkboxShowViews, 0, wxALIGN_CENTER_VERTICAL | wxBOTTOM | wxTOP | wxLEFT, 10);\n\tcheckboxShowViews->SetValue(true);\n\n\ttextureRelationListA->Bind(wxEVT_RIGHT_DOWN, &TextureRelationViewerWindow::OnTextureListRightClick, this);\n\n\tsizer->Add(\n\t\tsizerBottom,\n\t\t0,                // vertically unstretchable\n\t\twxALIGN_LEFT);\n\tmainPane->SetSizer(sizer);\n\n\tRefreshTextureList();\n}\n\nTextureRelationViewerWindow::~TextureRelationViewerWindow()\n{\n\tisTextureViewerOpen = false;\n}\n\nvoid TextureRelationViewerWindow::OnCloseButton(wxCommandEvent& event)\n{\n\tClose();\n}\n\nvoid TextureRelationViewerWindow::OnRefreshButton(wxCommandEvent& event)\n{\n\tRefreshTextureList();\n}\n\nvoid TextureRelationViewerWindow::OnCheckbox(wxCommandEvent& event)\n{\n\tif (event.GetId() == CHECKBOX_SHOW_ONLY_ACTIVE)\n\t{\n\t\tshowOnlyActive = event.IsChecked();\n\t\tRefreshTextureList();\n\t}\n\telse if (event.GetId() == CHECKBOX_SHOW_VIEWS)\n\t{\n\t\tshowTextureViews = event.IsChecked();\n\t\tRefreshTextureList();\n\t}\n}\n\nvoid TextureRelationViewerWindow::OnClose(wxCloseEvent& event)\n{\n\tClose();\n}\n\nvoid TextureRelationViewerWindow::_setTextureRelationListItemTexture(wxListCtrl* uiList, sint32 rowIndex, struct LatteTextureInformation* texInfo)\n{\n\twxString typeLabel;\n\t// count number of alternative views for base view\n\tsint32 alternativeViewCount = texInfo->alternativeViewCount;\n\tif (texInfo->isUpdatedOnGPU)\n\t\ttypeLabel = \"TEXTURE*\";\n\telse\n\t\ttypeLabel = \"TEXTURE\";\n\tif (alternativeViewCount > 0)\n\t{\n\t\ttypeLabel += wxString::Format(\"(%d)\", alternativeViewCount + 1);\n\t}\n\twxListItem item;\n\titem.SetId(rowIndex);\n\titem.SetText(typeLabel);\n\titem.SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\tuiList->InsertItem(item);\n\n\tsint32 columnIndex = 1;\n    // phys address\n    uiList->SetItem(rowIndex, columnIndex, wxString::Format(\"%08X\", texInfo->physAddress));\n    columnIndex++;\n    // phys mip address\n    uiList->SetItem(rowIndex, columnIndex, wxString::Format(\"%08X\", texInfo->physMipAddress));\n    columnIndex++;\n\t// dim\n\twxString dimLabel;\n\tif (texInfo->dim == Latte::E_DIM::DIM_2D)\n\t\tdimLabel = \"2D\";\n\telse if (texInfo->dim == Latte::E_DIM::DIM_2D_ARRAY)\n\t\tdimLabel = \"2D_ARRAY\";\n\telse if (texInfo->dim == Latte::E_DIM::DIM_3D)\n\t\tdimLabel = \"3D\";\n\telse if (texInfo->dim == Latte::E_DIM::DIM_CUBEMAP)\n\t\tdimLabel = \"CUBEMAP\";\n\telse if (texInfo->dim == Latte::E_DIM::DIM_1D)\n\t\tdimLabel = \"1D\";\n\telse if (texInfo->dim == Latte::E_DIM::DIM_2D_MSAA)\n\t\tdimLabel = \"2D_MSAA\";\n\telse if (texInfo->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA)\n\t\tdimLabel = \"2D_MS_ARRAY\";\n\telse\n\t\tdimLabel = \"UKN\";\n\tuiList->SetItem(rowIndex, columnIndex, dimLabel);\n\tcolumnIndex++;\n\t// resolution\n\twxString resolutionLabel;\n\tif (texInfo->depth == 1)\n\t\tresolutionLabel = wxString::Format(\"%dx%d\", texInfo->width, texInfo->height);\n\telse\n\t\tresolutionLabel = wxString::Format(\"%dx%dx%d\", texInfo->width, texInfo->height, texInfo->depth);\n\tuiList->SetItem(rowIndex, columnIndex, resolutionLabel);\n\tcolumnIndex++;\n\t// format\n\twxString formatLabel;\n\tif(texInfo->isDepth)\n\t\tformatLabel = wxString::Format(\"%04x(d)\", (uint32)texInfo->format);\n\telse\n\t\tformatLabel = wxString::Format(\"%04x\", (uint32)texInfo->format);\n\tuiList->SetItem(rowIndex, columnIndex, formatLabel);\n\tcolumnIndex++;\n\t// pitch\n\tuiList->SetItem(rowIndex, columnIndex, wxString::Format(\"%d\", texInfo->pitch));\n\tcolumnIndex++;\n\t// tilemode\n\tuiList->SetItem(rowIndex, columnIndex, wxString::Format(\"%d\", (int)texInfo->tileMode));\n\tcolumnIndex++;\n\t// sliceRange\n\tuiList->SetItem(rowIndex, columnIndex, \"\");\n\tcolumnIndex++;\n\t// mipRange\n\tuiList->SetItem(rowIndex, columnIndex, texInfo->mipLevels == 1 ? \"1 mip\" : wxString::Format(\"%d mips\", texInfo->mipLevels));\n\tcolumnIndex++;\n\t// last access\n\tuiList->SetItem(rowIndex, columnIndex, wxString::Format(\"%lus\", (GetTickCount() - texInfo->lastAccessTick + 499) / 1000));\n\tcolumnIndex++;\n\t// overwrite resolution\n\twxString overwriteResLabel;\n\tif (texInfo->overwriteInfo.hasResolutionOverwrite)\n\t{\n\t\tif(texInfo->overwriteInfo.depth != 1 || texInfo->depth != 1)\n\t\t\toverwriteResLabel = wxString::Format(\"%dx%dx%d\", texInfo->overwriteInfo.width, texInfo->overwriteInfo.height, texInfo->overwriteInfo.depth);\n\t\telse\n\t\t\toverwriteResLabel = wxString::Format(\"%dx%d\", texInfo->overwriteInfo.width, texInfo->overwriteInfo.height);\n\t}\n\tuiList->SetItem(rowIndex, columnIndex, overwriteResLabel);\n\tcolumnIndex++;\n}\n\nvoid TextureRelationViewerWindow::_setTextureRelationListItemView(wxListCtrl* uiList, sint32 rowIndex, struct LatteTextureInformation* texInfo, struct LatteTextureViewInformation* viewInfo)\n{\n\t// count number of alternative views\n\tsint32 alternativeViewCount = 0; // todo\n\t// set type string\n\t// find and handle highlight entry\n\twxListItem item;\n\titem.SetId(rowIndex);\n\titem.SetText(alternativeViewCount == 0 ? \"> VIEW\" : wxString::Format(\"> VIEW(%d)\", alternativeViewCount+1));\n\titem.SetBackgroundColour(wxHelper::CalculateAccentColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)));\n\tuiList->InsertItem(item);\n\t//uiList->SetItemPtrData(item, (wxUIntPtr)viewInfo);\n\tsint32 columnIndex = 1;\n    // phys address\n    uiList->SetItem(rowIndex, columnIndex, \"\");\n    columnIndex++;\n    // phys mip address\n    uiList->SetItem(rowIndex, columnIndex, \"\");\n    columnIndex++;\n\t// dim\n\twxString dimLabel;\n\tif (viewInfo->dim == Latte::E_DIM::DIM_2D)\n\t\tdimLabel = \"2D\";\n\telse if (viewInfo->dim == Latte::E_DIM::DIM_2D_ARRAY)\n\t\tdimLabel = \"2D_ARRAY\";\n\telse if (viewInfo->dim == Latte::E_DIM::DIM_3D)\n\t\tdimLabel = \"3D\";\n\telse if (viewInfo->dim == Latte::E_DIM::DIM_CUBEMAP)\n\t\tdimLabel = \"CUBEMAP\";\n\telse if (viewInfo->dim == Latte::E_DIM::DIM_1D)\n\t\tdimLabel = \"1D\";\n\telse if (viewInfo->dim == Latte::E_DIM::DIM_2D_MSAA)\n\t\tdimLabel = \"2D_MSAA\";\n\telse if (viewInfo->dim == Latte::E_DIM::DIM_2D_ARRAY_MSAA)\n\t\tdimLabel = \"2D_ARRAY_MSAA\";\n\telse\n\t\tdimLabel = \"UKN\";\n\tuiList->SetItem(rowIndex, columnIndex, dimLabel);\n\tcolumnIndex++;\n\t// resolution\n\tuiList->SetItem(rowIndex, columnIndex, \"\");\n\tcolumnIndex++;\n\t// format\n\tuiList->SetItem(rowIndex, columnIndex, wxString::Format(\"%04x\", (uint32)viewInfo->format));\n\tcolumnIndex++;\n\t// pitch\n\tuiList->SetItem(rowIndex, columnIndex, \"\");\n\tcolumnIndex++;\n\t// tilemode\n\tuiList->SetItem(rowIndex, columnIndex, \"\");\n\tcolumnIndex++;\n\t// sliceRange\n\tuiList->SetItem(rowIndex, columnIndex, wxString::Format(\"%d-%d\", viewInfo->firstSlice, viewInfo->firstSlice+ viewInfo->numSlice-1));\n\tcolumnIndex++;\n\t// mipRange\n\tuiList->SetItem(rowIndex, columnIndex, wxString::Format(\"%d-%d\", viewInfo->firstMip, viewInfo->firstMip + viewInfo->numMip - 1));\n\tcolumnIndex++;\n\t// last access\n\tuiList->SetItem(rowIndex, columnIndex, \"\");\n\tcolumnIndex++;\n}\n\nvoid TextureRelationViewerWindow::RefreshTextureList()\n{\n\tint scrollPos = textureRelationListA->GetScrollPos(wxVERTICAL);\n\ttextureRelationListA->DeleteAllItems();\n\n\tstd::vector<LatteTextureInformation> texCache = LatteTexture_QueryCacheInfo();\n\n\t// sort by physAddr in ascending order\n\tfor (sint32 i1 = 0; i1 < texCache.size(); i1++)\n\t{\n\t\tfor (sint32 i2 = i1+1; i2 < texCache.size(); i2++)\n\t\t{\n\t\t\tif (texCache[i1].physAddress > texCache[i2].physAddress)\n\t\t\t{\n\t\t\t\tstd::swap(texCache[i1], texCache[i2]);\n\t\t\t}\n\t\t}\n\t}\n\n\ttextureRelationListA->Freeze();\n\n\tsint32 rowIndex = 0;\n\tuint32 currentTick = GetTickCount();\n\tfor (auto& tex : texCache)\n\t{\n\t\tuint32 timeSinceLastAccess = currentTick - tex.lastAccessTick;\n\t\tif (showOnlyActive && timeSinceLastAccess > 3000)\n\t\t\tcontinue; // hide textures which haven't been updated in more than 3 seconds\n\n\t\t_setTextureRelationListItemTexture(textureRelationListA, rowIndex, &tex);\n\t\trowIndex++;\n\t\tif (showTextureViews)\n\t\t{\n\t\t\tfor (auto& view : tex.views)\n\t\t\t{\n\t\t\t\t_setTextureRelationListItemView(textureRelationListA, rowIndex, &tex, &view);\n\t\t\t\trowIndex++;\n\t\t\t}\n\t\t}\n\t}\n\ttextureRelationListA->Thaw();\n\tlong itemCount = textureRelationListA->GetItemCount();\n\tif (itemCount > 0)\n\t\ttextureRelationListA->EnsureVisible(std::min<long>(itemCount - 1, scrollPos + textureRelationListA->GetCountPerPage() - 1));\n}\n\nvoid TextureRelationViewerWindow::OnTextureListRightClick(wxMouseEvent& event)\n{\n}\n\nvoid TextureRelationViewerWindow::Close()\n{\n\tthis->Destroy();\n}\n"
  },
  {
    "path": "src/gui/wxgui/windows/TextureRelationViewer/TextureRelationWindow.h",
    "content": "#pragma once\n\n#include <wx/wx.h>\n\nclass wxListCtrl;\n\nclass TextureRelationViewerWindow : public wxFrame\n{\npublic:\n\tTextureRelationViewerWindow(wxFrame& parent);\n\t~TextureRelationViewerWindow();\n\n\tvoid OnCloseButton(wxCommandEvent& event);\n\tvoid OnRefreshButton(wxCommandEvent& event);\n\tvoid OnCheckbox(wxCommandEvent& event);\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid RefreshTextureList();\n\tvoid OnTextureListRightClick(wxMouseEvent& event);\n\n\tvoid Close();\n\nprivate:\n\n\twxDECLARE_EVENT_TABLE();\n\n\tvoid _setTextureRelationListItemTexture(wxListCtrl* uiList, sint32 rowIndex, struct LatteTextureInformation* texInfo);\n\tvoid _setTextureRelationListItemView(wxListCtrl* uiList, sint32 rowIndex, struct LatteTextureInformation* texInfo, struct LatteTextureViewInformation* viewInfo);\n\n\tbool showOnlyActive;\n\tbool showTextureViews;\n};\n\nvoid openTextureViewer(wxFrame& parentFrame);\n"
  },
  {
    "path": "src/gui/wxgui/wxCemuConfig.cpp",
    "content": "#include \"wxCemuConfig.h\"\n#include \"Common/precompiled.h\"\n#include \"config/CemuConfig.h\"\n#include \"config/XMLConfig.h\"\n#include \"util/helpers/helpers.h\"\n#include <wx/language.h>\n\nXMLWxCemuConfig_t g_wxConfig(&GetConfigHandle);\n\nvoid wxCemuConfig::AddRecentlyLaunchedFile(std::string_view file)\n{\n\trecent_launch_files.insert(recent_launch_files.begin(), std::string(file));\n\tRemoveDuplicatesKeepOrder(recent_launch_files);\n\twhile (recent_launch_files.size() > kMaxRecentEntries)\n\t\trecent_launch_files.pop_back();\n}\n\nvoid wxCemuConfig::AddRecentNfcFile(std::string_view file)\n{\n\trecent_nfc_files.insert(recent_nfc_files.begin(), std::string(file));\n\tRemoveDuplicatesKeepOrder(recent_nfc_files);\n\twhile (recent_nfc_files.size() > kMaxRecentEntries)\n\t\trecent_nfc_files.pop_back();\n}\n\nvoid wxCemuConfig::Load(XMLConfigParser& parser)\n{\n\tlanguage = parser.get<sint32>(\"language\", wxLANGUAGE_DEFAULT);\n\tmsw_theme = parser.get<sint32>(\"msw_theme\", msw_theme);\n\tuse_discord_presence = parser.get(\"use_discord_presence\", true);\n\tfullscreen_menubar = parser.get(\"fullscreen_menubar\", false);\n\tferal_gamemode = parser.get(\"feral_gamemode\", false);\n\tcheck_update = parser.get(\"check_update\", check_update);\n\treceive_untested_updates = parser.get(\"receive_untested_updates\", receive_untested_updates);\n\tsave_screenshot = parser.get(\"save_screenshot\", save_screenshot);\n\tdid_show_vulkan_warning = parser.get(\"vk_warning\", did_show_vulkan_warning);\n\tdid_show_graphic_pack_download = parser.get(\"gp_download\", did_show_graphic_pack_download);\n\tdid_show_macos_disclaimer = parser.get(\"macos_disclaimer\", did_show_macos_disclaimer);\n\tfullscreen = parser.get(\"fullscreen\", fullscreen);\n\n\twindow_position.x = parser.get(\"window_position\").get(\"x\", -1);\n\twindow_position.y = parser.get(\"window_position\").get(\"y\", -1);\n\n\twindow_size.x = parser.get(\"window_size\").get(\"x\", -1);\n\twindow_size.y = parser.get(\"window_size\").get(\"y\", -1);\n\twindow_maximized = parser.get(\"window_maximized\", false);\n\n\tpad_open = parser.get(\"open_pad\", false);\n\tpad_position.x = parser.get(\"pad_position\").get(\"x\", -1);\n\tpad_position.y = parser.get(\"pad_position\").get(\"y\", -1);\n\n\tpad_size.x = parser.get(\"pad_size\").get(\"x\", -1);\n\tpad_size.y = parser.get(\"pad_size\").get(\"y\", -1);\n\tpad_maximized = parser.get(\"pad_maximized\", false);\n\n\tauto gamelist = parser.get(\"GameList\");\n\tgame_list_style = gamelist.get(\"style\", 0);\n\tgame_list_column_order = gamelist.get(\"order\", \"\");\n\n\tshow_icon_column = parser.get(\"show_icon_column\", true);\n\n\t// return default width if value in config file out of range\n\tauto loadColumnSize = [&gamelist](const char* name, uint32 defaultWidth) {\n\t\tsint64 val = gamelist.get(name, DefaultColumnSize::name);\n\t\tif (val < 0 || val > (sint64)std::numeric_limits<uint32>::max)\n\t\t\treturn defaultWidth;\n\t\treturn static_cast<uint32>(val);\n\t};\n\tcolumn_width.name = loadColumnSize(\"name_width\", DefaultColumnSize::name);\n\tcolumn_width.version = loadColumnSize(\"version_width\", DefaultColumnSize::version);\n\tcolumn_width.dlc = loadColumnSize(\"dlc_width\", DefaultColumnSize::dlc);\n\tcolumn_width.game_time = loadColumnSize(\"game_time_width\", DefaultColumnSize::game_time);\n\tcolumn_width.game_started = loadColumnSize(\"game_started_width\", DefaultColumnSize::game_started);\n\tcolumn_width.region = loadColumnSize(\"region_width\", DefaultColumnSize::region);\n\tcolumn_width.title_id = loadColumnSize(\"title_id\", DefaultColumnSize::title_id);\n\n\trecent_launch_files.clear();\n\tauto launch_parser = parser.get(\"RecentLaunchFiles\");\n\tfor (auto element = launch_parser.get(\"Entry\"); element.valid(); element = launch_parser.get(\"Entry\", element))\n\t{\n\t\tconst std::string path = element.value(\"\");\n\t\tif (path.empty())\n\t\t\tcontinue;\n\n\t\ttry\n\t\t{\n\t\t\trecent_launch_files.emplace_back(path);\n\t\t} catch (const std::exception&)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"config load error: can't load recently launched game file: {}\", path);\n\t\t}\n\t}\n\n\trecent_nfc_files.clear();\n\tauto nfc_parser = parser.get(\"RecentNFCFiles\");\n\tfor (auto element = nfc_parser.get(\"Entry\"); element.valid(); element = nfc_parser.get(\"Entry\", element))\n\t{\n\t\tconst std::string path = element.value(\"\");\n\t\tif (path.empty())\n\t\t\tcontinue;\n\t\ttry\n\t\t{\n\t\t\trecent_nfc_files.emplace_back(path);\n\t\t} catch (const std::exception&)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"config load error: can't load recently launched nfc file: {}\", path);\n\t\t}\n\t}\n\n\t// hotkeys\n\tauto xml_hotkeys = parser.get(\"Hotkeys\");\n\thotkeys.modifiers = xml_hotkeys.get(\"modifiers\", sHotkeyCfg{});\n\thotkeys.exitFullscreen = xml_hotkeys.get(\"ExitFullscreen\", sHotkeyCfg{uKeyboardHotkey{WXK_ESCAPE}});\n\thotkeys.toggleFullscreen = xml_hotkeys.get(\"ToggleFullscreen\", sHotkeyCfg{uKeyboardHotkey{WXK_F11}});\n\thotkeys.toggleFullscreenAlt = xml_hotkeys.get(\"ToggleFullscreenAlt\", sHotkeyCfg{uKeyboardHotkey{WXK_CONTROL_M, true}}); // ALT+ENTER\n\thotkeys.takeScreenshot = xml_hotkeys.get(\"TakeScreenshot\", sHotkeyCfg{uKeyboardHotkey{WXK_F12}});\n\thotkeys.toggleFastForward = xml_hotkeys.get(\"ToggleFastForward\", sHotkeyCfg{});\n\thotkeys.exitApplication = xml_hotkeys.get(\"ExitApplication\", sHotkeyCfg{});\n#ifdef CEMU_DEBUG_ASSERT\n\thotkeys.endEmulation = xml_hotkeys.get(\"EndEmulation\", sHotkeyCfg{uKeyboardHotkey{WXK_F5}});\n#endif\n}\n\nvoid wxCemuConfig::Save(XMLConfigParser& config)\n{\n\t// general settings\n\tconfig.set<sint32>(\"language\", language);\n\tconfig.set<sint32>(\"msw_theme\", msw_theme);\n\tconfig.set<bool>(\"use_discord_presence\", use_discord_presence);\n\tconfig.set<bool>(\"fullscreen_menubar\", fullscreen_menubar);\n\tconfig.set<bool>(\"feral_gamemode\", feral_gamemode);\n\tconfig.set<bool>(\"check_update\", check_update);\n\tconfig.set<bool>(\"receive_untested_updates\", receive_untested_updates);\n\tconfig.set<bool>(\"save_screenshot\", save_screenshot);\n\tconfig.set<bool>(\"vk_warning\", did_show_vulkan_warning);\n\tconfig.set<bool>(\"gp_download\", did_show_graphic_pack_download);\n\tconfig.set<bool>(\"macos_disclaimer\", did_show_macos_disclaimer);\n\tconfig.set<bool>(\"fullscreen\", fullscreen);\n\n\tauto wpos = config.set(\"window_position\");\n\twpos.set<sint32>(\"x\", window_position.x);\n\twpos.set<sint32>(\"y\", window_position.y);\n\tauto wsize = config.set(\"window_size\");\n\twsize.set<sint32>(\"x\", window_size.x);\n\twsize.set<sint32>(\"y\", window_size.y);\n\tconfig.set<bool>(\"window_maximized\", window_maximized);\n\n\tconfig.set<bool>(\"open_pad\", pad_open);\n\tauto ppos = config.set(\"pad_position\");\n\tppos.set<sint32>(\"x\", pad_position.x);\n\tppos.set<sint32>(\"y\", pad_position.y);\n\tauto psize = config.set(\"pad_size\");\n\tpsize.set<sint32>(\"x\", pad_size.x);\n\tpsize.set<sint32>(\"y\", pad_size.y);\n\tconfig.set<bool>(\"pad_maximized\", pad_maximized);\n\tconfig.set<bool>(\"show_icon_column\", show_icon_column);\n\n\tauto gamelist = config.set(\"GameList\");\n\tgamelist.set(\"style\", game_list_style);\n\tgamelist.set(\"order\", game_list_column_order);\n\tgamelist.set(\"name_width\", column_width.name);\n\tgamelist.set(\"version_width\", column_width.version);\n\tgamelist.set(\"dlc_width\", column_width.dlc);\n\tgamelist.set(\"game_time_width\", column_width.game_time);\n\tgamelist.set(\"game_started_width\", column_width.game_started);\n\tgamelist.set(\"region_width\", column_width.region);\n\tgamelist.set(\"title_id\", column_width.title_id);\n\n\tauto launch_files_parser = config.set(\"RecentLaunchFiles\");\n\tfor (const auto& entry : recent_launch_files)\n\t{\n\t\tlaunch_files_parser.set(\"Entry\", entry.c_str());\n\t}\n\n\tauto nfc_files_parser = config.set(\"RecentNFCFiles\");\n\tfor (const auto& entry : recent_nfc_files)\n\t{\n\t\tnfc_files_parser.set(\"Entry\", entry.c_str());\n\t}\n\n\t// hotkeys\n\tauto xml_hotkeys = config.set(\"Hotkeys\");\n\txml_hotkeys.set(\"modifiers\", hotkeys.modifiers);\n\txml_hotkeys.set(\"ExitFullscreen\", hotkeys.exitFullscreen);\n\txml_hotkeys.set(\"ToggleFullscreen\", hotkeys.toggleFullscreen);\n\txml_hotkeys.set(\"ToggleFullscreenAlt\", hotkeys.toggleFullscreenAlt);\n\txml_hotkeys.set(\"TakeScreenshot\", hotkeys.takeScreenshot);\n\txml_hotkeys.set(\"ToggleFastForward\", hotkeys.toggleFastForward);\n\txml_hotkeys.set(\"ExitApplication\", hotkeys.exitApplication);\n}\n"
  },
  {
    "path": "src/gui/wxgui/wxCemuConfig.h",
    "content": "#pragma once\n\n#include \"config/CemuConfig.h\"\n#include \"config/XMLConfig.h\"\n#include \"util/math/vector2.h\"\n\n#include \"wxgui.h\"\n\nnamespace DefaultColumnSize\n{\n\tenum : uint32\n\t{\n\t\tname = 500u,\n\t\tversion = 60u,\n\t\tdlc = 50u,\n\t\tgame_time = 140u,\n\t\tgame_started = 160u,\n\t\tregion = 80u,\n\t\ttitle_id = 160u\n\t};\n};\n\nenum class MSWThemeOption : int\n{\n\tkAuto = 0,\n\tkLight = 1,\n\tkDark = 2,\n};\nENABLE_ENUM_ITERATORS(MSWThemeOption, MSWThemeOption::kAuto, MSWThemeOption::kDark);\n\ntypedef union\n{\n\tstruct\n\t{\n\t\tuint16 key : 13; // enough bits for all keycodes\n\t\tuint16 alt : 1;\n\t\tuint16 ctrl : 1;\n\t\tuint16 shift : 1;\n\t};\n\tuint16 raw;\n} uKeyboardHotkey;\n\ntypedef sint16 ControllerHotkey_t;\n\nstruct sHotkeyCfg\n{\n\tstatic constexpr uint8 keyboardNone{WXK_NONE};\n\tstatic constexpr sint8 controllerNone{-1}; // no enums to work with, but buttons start from 0\n\n\tuKeyboardHotkey keyboard{keyboardNone};\n\tControllerHotkey_t controller{controllerNone};\n\n\t/* for defaults */\n\tsHotkeyCfg(const uKeyboardHotkey& keyboard = {keyboardNone}, const ControllerHotkey_t& controller = {controllerNone}) : keyboard(keyboard), controller(controller) {};\n\n\t/* for reading from xml */\n\tsHotkeyCfg(const char* xml_values)\n\t{\n\t\tstd::istringstream iss(xml_values);\n\t\tiss >> keyboard.raw >> controller;\n\t}\n};\n\ntemplate<>\nstruct fmt::formatter<sHotkeyCfg> : formatter<string_view>\n{\n\ttemplate<typename FormatContext>\n\tauto format(const sHotkeyCfg c, FormatContext& ctx) const\n\t{\n\t\tstd::string xml_values = fmt::format(\"{} {}\", c.keyboard.raw, c.controller);\n\t\treturn formatter<string_view>::format(xml_values, ctx);\n\t}\n};\n\nstruct wxCemuConfig\n{\n\tConfigValue<sint32> language{wxLANGUAGE_DEFAULT};\n\tConfigValue<int> msw_theme { static_cast<int>(MSWThemeOption::kAuto) };\n\tConfigValue<bool> use_discord_presence{true};\n\tConfigValue<bool> fullscreen{ false };\n\tConfigValue<bool> fullscreen_menubar{false};\n\tConfigValue<bool> feral_gamemode{false};\n\n\t// max 15 entries\n\tstatic constexpr size_t kMaxRecentEntries = 15;\n\tstd::vector<std::string> recent_launch_files;\n\tstd::vector<std::string> recent_nfc_files;\n\n\tVector2i window_position{-1, -1};\n\tVector2i window_size{-1, -1};\n\tConfigValue<bool> window_maximized;\n\n\tConfigValue<bool> pad_open;\n\tVector2i pad_position{-1, -1};\n\tVector2i pad_size{-1, -1};\n\tConfigValue<bool> pad_maximized;\n\n\tConfigValue<bool> check_update{true};\n\tConfigValue<bool> receive_untested_updates{false};\n\tConfigValue<bool> save_screenshot{true};\n\n\tConfigValue<bool> did_show_vulkan_warning{false};\n\tConfigValue<bool> did_show_graphic_pack_download{false}; // no longer used but we keep the config value around in case people downgrade Cemu. Despite the name this was used for the Getting Started dialog\n\tConfigValue<bool> did_show_macos_disclaimer{false};\n\n\tConfigValue<bool> show_icon_column{true};\n\n\tint game_list_style = 0;\n\tstd::string game_list_column_order;\n\tstruct\n\t{\n\t\tuint32 name = DefaultColumnSize::name;\n\t\tuint32 version = DefaultColumnSize::version;\n\t\tuint32 dlc = DefaultColumnSize::dlc;\n\t\tuint32 game_time = DefaultColumnSize::game_time;\n\t\tuint32 game_started = DefaultColumnSize::game_started;\n\t\tuint32 region = DefaultColumnSize::region;\n\t\tuint32 title_id = 0;\n\t} column_width{};\n\n\t// hotkeys\n\tstruct\n\t{\n\t\tsHotkeyCfg modifiers;\n\t\tsHotkeyCfg toggleFullscreen;\n\t\tsHotkeyCfg toggleFullscreenAlt;\n\t\tsHotkeyCfg exitFullscreen;\n\t\tsHotkeyCfg takeScreenshot;\n\t\tsHotkeyCfg toggleFastForward;\n\t\tsHotkeyCfg exitApplication;\n#ifdef CEMU_DEBUG_ASSERT\n\t\tsHotkeyCfg endEmulation;\n#endif\n\t} hotkeys{};\n\n\tvoid AddRecentlyLaunchedFile(std::string_view file);\n\tvoid AddRecentNfcFile(std::string_view file);\n\n\tvoid Load(XMLConfigParser& parser);\n\tvoid Save(XMLConfigParser& parser);\n};\n\ntypedef XMLChildConfig<wxCemuConfig, &wxCemuConfig::Load, &wxCemuConfig::Save> XMLWxCemuConfig_t;\n\nextern XMLWxCemuConfig_t g_wxConfig;\n\ninline XMLWxCemuConfig_t& GetWxGuiConfigHandle()\n{\n\treturn g_wxConfig;\n}\n\ninline wxCemuConfig& GetWxGUIConfig()\n{\n\treturn GetWxGuiConfigHandle().Data();\n}\n"
  },
  {
    "path": "src/gui/wxgui/wxHelper.h",
    "content": "#pragma once\n#include <wx/string.h>\n#include <wx/bitmap.h>\n#include <wx/mstream.h>\n\nnamespace wxHelper\n{\n    inline fs::path MakeFSPath(const wxString& str)\n    {\n        auto tmpUtf8 = str.ToUTF8();\n        auto sv = std::basic_string_view<char8_t>((const char8_t*)tmpUtf8.data(), tmpUtf8.length());\n        return fs::path(sv);\n    }\n\n\tinline wxString FromPath(const fs::path& path)\n\t{\n\t\tstd::string str = _pathToUtf8(path);\n\t\treturn wxString::FromUTF8(str);\n\t}\n\n\tinline wxColour CalculateAccentColour(const wxColour& bgColour)\n\t{\n\t\tconst uint32 bgLightness = (bgColour.GetRed() + bgColour.GetGreen() + bgColour.GetBlue()) / 3;\n\t\tconst bool isDarkTheme = bgLightness < 128;\n\t\twxColour bgColourSecondary = bgColour.ChangeLightness(isDarkTheme ? 110 : 90); // color for even rows\n\t\t// for very light themes we'll use a blue tint to match the older Windows Cemu look\n\t\tif (bgLightness > 250)\n\t\t\tbgColourSecondary = wxColour(bgColour.Red() - 13, bgColour.Green() - 6, bgColour.Blue() - 2);\n\t\treturn bgColourSecondary;\n\t}\n\n\tstatic wxBitmap LoadThemedBitmapFromPNG(const uint8* data, size_t size, const wxColour& tint)\n    {\n    \twxMemoryInputStream strm(data, size);\n    \twxImage img(strm, wxBITMAP_TYPE_PNG);\n    \timg.Replace(0x00, 0x00, 0x00, tint.Red(), tint.Green(), tint.Blue());\n    \treturn wxBitmap(img);\n    }\n};\n"
  },
  {
    "path": "src/gui/wxgui/wxWindowSystem.cpp",
    "content": "#include \"input/HotkeySettings.h\"\n#include \"interface/WindowSystem.h\"\n\n#include \"helpers/wxHelpers.h\"\n\n#if BOOST_OS_LINUX || BOOST_OS_BSD\n#include <gdk/gdkkeysyms.h>\n#include <gtk/gtk.h>\n#include <gdk/gdk.h>\n#include <gdk/gdkwindow.h>\n#include <gdk/gdkx.h>\n#ifdef HAS_WAYLAND\n#include <gdk/gdkwayland.h>\n#endif\n#endif\n\n#if BOOST_OS_MACOS\n#include <Carbon/Carbon.h>\n#endif\n\n#include \"wxgui/wxgui.h\"\n#include \"wxgui/CemuApp.h\"\n#include \"wxgui/MainWindow.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"config/ActiveSettings.h\"\n#include \"config/NetworkSettings.h\"\n#include \"config/CemuConfig.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"Cafe/CafeSystem.h\"\n\nWindowSystem::WindowInfo g_window_info{};\n\nstd::shared_mutex g_mutex;\nMainWindow* g_mainFrame = nullptr;\n\n#if BOOST_OS_WINDOWS\nvoid _wxLaunch()\n{\n\tSetThreadName(\"MainThread_UI\");\n\twxEntry();\n}\n#endif\n\nvoid WindowSystem::Create()\n{\n\tSetThreadName(\"cemu\");\n#if BOOST_OS_WINDOWS\n\t// on Windows wxWidgets there is a bug where wxDirDialog->ShowModal will deadlock in Windows internals somehow\n\t// moving the UI thread off the main thread fixes this\n\tstd::thread t = std::thread(_wxLaunch);\n\tt.join();\n#else\n\tint argc = 0;\n\tchar* argv[1]{};\n\twxEntry(argc, argv);\n#endif\n}\n\nvoid WindowSystem::ShowErrorDialog(std::string_view message, std::string_view title, std::optional<WindowSystem::ErrorCategory> /*errorId*/)\n{\n\twxString caption;\n\tif (title.empty())\n\t\tcaption = wxASCII_STR(wxMessageBoxCaptionStr);\n\telse\n\t\tcaption = wxString::FromUTF8(title);\n\twxMessageBox(wxString::FromUTF8(message), caption, wxOK | wxCENTRE | wxICON_ERROR);\n}\n\nWindowSystem::WindowInfo& WindowSystem::GetWindowInfo()\n{\n\treturn g_window_info;\n}\n\nvoid WindowSystem::UpdateWindowTitles(bool isIdle, bool isLoading, double fps)\n{\n\tstd::string windowText;\n\twindowText = BUILD_VERSION_WITH_NAME_STRING;\n\n\tif (isIdle)\n\t{\n\t\tif (g_mainFrame)\n\t\t\tg_mainFrame->AsyncSetTitle(windowText);\n\t\treturn;\n\t}\n\tif (isLoading)\n\t{\n\t\twindowText.append(\" - Loading...\");\n\t\tif (g_mainFrame)\n\t\t\tg_mainFrame->AsyncSetTitle(windowText);\n\t\treturn;\n\t}\n\n\tconst char* renderer = \"\";\n\tif (g_renderer)\n\t{\n\t\tswitch (g_renderer->GetType())\n\t\t{\n\t\tcase RendererAPI::OpenGL:\n\t\t\trenderer = \"[OpenGL]\";\n\t\t\tbreak;\n\t\tcase RendererAPI::Vulkan:\n\t\t\trenderer = \"[Vulkan]\";\n\t\t\tbreak;\n#if ENABLE_METAL\n\t\tcase RendererAPI::Metal:\n\t\t\trenderer = \"[Metal]\";\n\t\t\tbreak;\n#endif\n\t\tdefault:;\n\t\t}\n\t}\n\n\t// get GPU vendor/mode\n\tconst char* graphicMode = \"[Generic]\";\n\tif (LatteGPUState.glVendor == GLVENDOR_AMD)\n\t\tgraphicMode = \"[AMD GPU]\";\n\telse if (LatteGPUState.glVendor == GLVENDOR_INTEL)\n\t\tgraphicMode = \"[Intel GPU]\";\n\telse if (LatteGPUState.glVendor == GLVENDOR_NVIDIA)\n\t\tgraphicMode = \"[NVIDIA GPU]\";\n\telse if (LatteGPUState.glVendor == GLVENDOR_APPLE)\n\t\tgraphicMode = \"[Apple GPU]\";\n\n\tconst uint64 titleId = CafeSystem::GetForegroundTitleId();\n\twindowText.append(fmt::format(\" - FPS: {:.2f} {} {} [TitleId: {:08x}-{:08x}]\", (double)fps, renderer, graphicMode, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF)));\n\n\tif (ActiveSettings::IsOnlineEnabled())\n\t{\n\t\tif (ActiveSettings::GetNetworkService() == NetworkService::Nintendo)\n\t\t\twindowText.append(\" [Online]\");\n\t\telse if (ActiveSettings::GetNetworkService() == NetworkService::Pretendo)\n\t\t\twindowText.append(\" [Online-Pretendo]\");\n\t\telse if (ActiveSettings::GetNetworkService() == NetworkService::Custom)\n\t\t\twindowText.append(\" [Online-\" + GetNetworkConfig().networkname.GetValue() + \"]\");\n\t}\n\twindowText.append(\" \");\n\twindowText.append(CafeSystem::GetForegroundTitleName());\n\t// append region\n\tCafeConsoleRegion region = CafeSystem::GetForegroundTitleRegion();\n\tuint16 titleVersion = CafeSystem::GetForegroundTitleVersion();\n\tif (region == CafeConsoleRegion::JPN)\n\t\twindowText.append(fmt::format(\" [JP v{}]\", titleVersion));\n\telse if (region == CafeConsoleRegion::USA)\n\t\twindowText.append(fmt::format(\" [US v{}]\", titleVersion));\n\telse if (region == CafeConsoleRegion::EUR)\n\t\twindowText.append(fmt::format(\" [EU v{}]\", titleVersion));\n\telse\n\t\twindowText.append(fmt::format(\" [v{}]\", titleVersion));\n\n\tstd::shared_lock lock(g_mutex);\n\tif (g_mainFrame)\n\t{\n\t\tg_mainFrame->AsyncSetTitle(windowText);\n\t\tauto* pad = g_mainFrame->GetPadView();\n\t\tif (pad)\n\t\t\tpad->AsyncSetTitle(fmt::format(\"{} - FPS: {:.02f}\", _(\"GamePad View\").utf8_string(), fps));\n\t}\n}\n\nvoid WindowSystem::GetWindowSize(int& w, int& h)\n{\n\tw = g_window_info.width;\n\th = g_window_info.height;\n}\n\nvoid WindowSystem::GetPadWindowSize(int& w, int& h)\n{\n\tif (g_window_info.pad_open)\n\t{\n\t\tw = g_window_info.pad_width;\n\t\th = g_window_info.pad_height;\n\t}\n\telse\n\t{\n\t\tw = 0;\n\t\th = 0;\n\t}\n}\n\nvoid WindowSystem::GetWindowPhysSize(int& w, int& h)\n{\n\tw = g_window_info.phys_width;\n\th = g_window_info.phys_height;\n}\n\nvoid WindowSystem::GetPadWindowPhysSize(int& w, int& h)\n{\n\tif (g_window_info.pad_open)\n\t{\n\t\tw = g_window_info.phys_pad_width;\n\t\th = g_window_info.phys_pad_height;\n\t}\n\telse\n\t{\n\t\tw = 0;\n\t\th = 0;\n\t}\n}\n\ndouble WindowSystem::GetWindowDPIScale()\n{\n\treturn g_window_info.dpi_scale;\n}\n\ndouble WindowSystem::GetPadDPIScale()\n{\n\treturn g_window_info.pad_open ? g_window_info.pad_dpi_scale.load() : 1.0;\n}\n\nbool WindowSystem::IsPadWindowOpen()\n{\n\treturn g_window_info.pad_open;\n}\n\nbool WindowSystem::IsKeyDown(uint32 key)\n{\n\treturn g_window_info.get_keystate(key);\n}\n\nbool WindowSystem::IsKeyDown(PlatformKeyCodes platformKey)\n{\n\tuint32 key = 0;\n\n\tswitch (platformKey)\n\t{\n#if BOOST_OS_WINDOWS\n\tcase PlatformKeyCodes::LCONTROL:\n\t\tkey = VK_LCONTROL;\n\t\tbreak;\n\tcase PlatformKeyCodes::RCONTROL:\n\t\tkey = VK_RCONTROL;\n\t\tbreak;\n\tcase PlatformKeyCodes::TAB:\n\t\tkey = VK_TAB;\n\t\tbreak;\n\tcase PlatformKeyCodes::ESCAPE:\n\t\tkey = VK_ESCAPE;\n\t\tbreak;\n#elif BOOST_OS_LINUX || BOOST_OS_BSD\n\tcase PlatformKeyCodes::LCONTROL:\n\t\tkey = GDK_KEY_Control_L;\n\t\tbreak;\n\tcase PlatformKeyCodes::RCONTROL:\n\t\tkey = GDK_KEY_Control_R;\n\t\tbreak;\n\tcase PlatformKeyCodes::TAB:\n\t\tkey = GDK_KEY_Tab;\n\t\tbreak;\n\tcase PlatformKeyCodes::ESCAPE:\n\t\tkey = GDK_KEY_Escape;\n\t\tbreak;\n#elif BOOST_OS_MACOS\n\tcase PlatformKeyCodes::LCONTROL:\n\t\tkey = kVK_Control;\n\t\tbreak;\n\tcase PlatformKeyCodes::RCONTROL:\n\t\tkey = kVK_RightControl;\n\t\tbreak;\n\tcase PlatformKeyCodes::TAB:\n\t\tkey = kVK_Tab;\n\t\tbreak;\n\tcase PlatformKeyCodes::ESCAPE:\n\t\tkey = kVK_Escape;\n\t\tbreak;\n#endif\n\tdefault:\n\t\treturn false;\n\t}\n\n\treturn WindowSystem::IsKeyDown(key);\n}\n\nstd::string WindowSystem::GetKeyCodeName(uint32 button)\n{\n#if BOOST_OS_WINDOWS\n\tLONG scan_code = MapVirtualKeyA((UINT)button, MAPVK_VK_TO_VSC_EX);\n\tif (HIBYTE(scan_code))\n\t\tscan_code |= 0x100;\n\n\t// because MapVirtualKey strips the extended bit for some keys\n\tswitch (button)\n\t{\n\tcase VK_LEFT:\n\tcase VK_UP:\n\tcase VK_RIGHT:\n\tcase VK_DOWN: // arrow keys\n\tcase VK_PRIOR:\n\tcase VK_NEXT: // page up and page down\n\tcase VK_END:\n\tcase VK_HOME:\n\tcase VK_INSERT:\n\tcase VK_DELETE:\n\tcase VK_DIVIDE: // numpad slash\n\tcase VK_NUMLOCK:\n\t{\n\t\tscan_code |= 0x100; // set extended bit\n\t\tbreak;\n\t}\n\t}\n\n\tscan_code <<= 16;\n\n\tchar key_name[128];\n\tif (GetKeyNameTextA(scan_code, key_name, std::size(key_name)) != 0)\n\t\treturn key_name;\n\telse\n\t\treturn fmt::format(\"key_{}\", button);\n#elif BOOST_OS_LINUX || BOOST_OS_BSD\n\treturn gdk_keyval_name(button);\n#else\n\treturn fmt::format(\"key_{}\", button);\n#endif\n}\n\nbool WindowSystem::InputConfigWindowHasFocus()\n{\n\treturn g_inputConfigWindowHasFocus;\n}\n\nvoid WindowSystem::NotifyGameLoaded()\n{\n\tstd::shared_lock lock(g_mutex);\n\tif (g_mainFrame)\n\t{\n\t\tg_mainFrame->OnGameLoaded();\n\t\tg_mainFrame->UpdateSettingsAfterGameLaunch();\n\t}\n}\n\nvoid WindowSystem::NotifyGameExited()\n{\n\tstd::shared_lock lock(g_mutex);\n\tif (g_mainFrame)\n\t\tg_mainFrame->RestoreSettingsAfterGameExited();\n}\n\nvoid WindowSystem::RefreshGameList()\n{\n\tstd::shared_lock lock(g_mutex);\n\tif (g_mainFrame)\n\t{\n\t\tg_mainFrame->RequestGameListRefresh();\n\t}\n}\n\nvoid WindowSystem::CaptureInput(const ControllerState& currentState, const ControllerState& lastState)\n{\n\tHotkeySettings::CaptureInput(currentState, lastState);\n}\n\nbool WindowSystem::IsFullScreen()\n{\n\treturn g_window_info.is_fullscreen;\n}\n"
  },
  {
    "path": "src/gui/wxgui/wxcomponents/checktree.cpp",
    "content": "#include \"wxgui/wxcomponents/checktree.h\"\n\n#include <wx/dcmemory.h>\n#include <wx/icon.h>\n#include <wx/imaglist.h>\n#include <wx/renderer.h>\n\nwxDEFINE_EVENT(wxEVT_CHECKTREE_FOCUS, wxTreeEvent);\nwxDEFINE_EVENT(wxEVT_CHECKTREE_CHOICE, wxTreeEvent);\n\n//IMPLEMENT_DYNAMIC_CLASS(wxCheckTree, wxTreeCtrl)\n\nbool on_check_or_label(int flags)\n{\n\treturn flags & (wxTREE_HITTEST_ONITEMSTATEICON | wxTREE_HITTEST_ONITEMLABEL) ? true : false;\n}\n\nbool on_check(int flags)\n{\n\treturn flags & (wxTREE_HITTEST_ONITEMSTATEICON) ? true : false;\n}\n\nbool on_label(int flags)\n{\n\treturn flags & (wxTREE_HITTEST_ONITEMLABEL) ? true : false;\n}\n\nvoid unhighlight(wxTreeCtrl* m_treeCtrl1, wxTreeItemId& id)\n{\n\tif (!id.IsOk())\n\t\treturn;\n\n\tconst int state = m_treeCtrl1->GetItemState(id);\n\tif (wxCheckTree::UNCHECKED <= state && state < wxCheckTree::UNCHECKED_DISABLED)\n\t{\n\t\tm_treeCtrl1->SetItemState(id, wxCheckTree::UNCHECKED);\n\t}\n\telse if (wxCheckTree::CHECKED <= state && state < wxCheckTree::CHECKED_DISABLED)\n\t{\n\t\tm_treeCtrl1->SetItemState(id, wxCheckTree::CHECKED);\n\t}\n}\n\n\nvoid mohighlight(wxTreeCtrl* m_treeCtrl1, wxTreeItemId& id, bool toggle)\n{\n\tif (!id.IsOk())\n\t\treturn;\n\n\tconst int i = m_treeCtrl1->GetItemState(id);\n\tif (i < 0)\n\t\treturn;\n\n\tbool is_checked = false;\n\tif (wxCheckTree::UNCHECKED <= i && i < wxCheckTree::UNCHECKED_DISABLED)\n\t{\n\t\tm_treeCtrl1->SetItemState(id, toggle ? wxCheckTree::CHECKED_MOUSE_OVER : wxCheckTree::UNCHECKED_MOUSE_OVER);\n\t\tis_checked = true;\n\t}\n\telse if (wxCheckTree::CHECKED <= i && i < wxCheckTree::CHECKED_DISABLED)\n\t{\n\t\tm_treeCtrl1->SetItemState(id, toggle ? wxCheckTree::UNCHECKED_MOUSE_OVER : wxCheckTree::CHECKED_MOUSE_OVER);\n\t\tis_checked = false;\n\t}\n\n\tif (toggle)\n\t{\n\t\twxTreeEvent event2(wxEVT_CHECKTREE_CHOICE, m_treeCtrl1, id);\n\t\tevent2.SetExtraLong(is_checked ? 1 : 0);\n\t\tm_treeCtrl1->ProcessWindowEvent(event2);\n\t}\n}\n\nvoid ldhighlight(wxTreeCtrl* m_treeCtrl1, wxTreeItemId& id)\n{\n\tif (!id.IsOk())\n\t\treturn;\n\n\tconst int i = m_treeCtrl1->GetItemState(id);\n\tif (wxCheckTree::UNCHECKED <= i && i < wxCheckTree::UNCHECKED_DISABLED)\n\t{\n\t\tm_treeCtrl1->SetItemState(id, wxCheckTree::UNCHECKED_LEFT_DOWN);\n\t}\n\telse if (wxCheckTree::CHECKED <= i && i < wxCheckTree::CHECKED_DISABLED)\n\t{\n\t\tm_treeCtrl1->SetItemState(id, wxCheckTree::CHECKED_LEFT_DOWN);\n\t}\n}\n\nwxIMPLEMENT_CLASS(wxCheckTree, wxTreeCtrl);\n\nwxCheckTree::wxCheckTree()\n{\n\tInit();\n}\n\nwxCheckTree::wxCheckTree(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size, long style)\n\t: wxTreeCtrl(parent, id, pos, size, style)\n{\n\tInit();\n}\n\n\nvoid wxCheckTree::Init()\n{\n\tint width = wxRendererNative::Get().GetCheckBoxSize(this).GetWidth();\n\tint height = wxRendererNative::Get().GetCheckBoxSize(this).GetHeight();\n\n\tauto states = new wxImageList(width, height, true);\n\n\twxBitmap unchecked_bmp(width, height);\n\twxBitmap unchecked_mouse_over_bmp(width, height);\n\twxBitmap unchecked_left_down_bmp(width, height);\n\twxBitmap unchecked_disabled_bmp(width, height);\n\twxBitmap checked_bmp(width, height);\n\twxBitmap checked_mouse_over_bmp(width, height);\n\twxBitmap checked_left_down_bmp(width, height);\n\twxBitmap checked_disabled_bmp(width, height);\n\n\twxMemoryDC renderer_dc;\n\n\t// Unchecked\n\trenderer_dc.SelectObject(unchecked_bmp);\n\trenderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));\n\trenderer_dc.Clear();\n\twxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_NONE);\n\n\t// Unchecked Mouse Over\n\trenderer_dc.SelectObject(unchecked_mouse_over_bmp);\n\trenderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));\n\trenderer_dc.Clear();\n\twxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CURRENT);\n\n\t// Unchecked and Disabled\n\trenderer_dc.SelectObject(unchecked_disabled_bmp);\n\trenderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));\n\trenderer_dc.Clear();\n\twxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_DISABLED);\n\n\t// Unchecked Left Down\n\trenderer_dc.SelectObject(unchecked_left_down_bmp);\n\trenderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));\n\trenderer_dc.Clear();\n\twxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CURRENT | wxCONTROL_PRESSED);\n\n\t// Checked\n\trenderer_dc.SelectObject(checked_bmp);\n\trenderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));\n\trenderer_dc.Clear();\n\twxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CHECKED);\n\n\t// Checked Mouse Over\n\trenderer_dc.SelectObject(checked_mouse_over_bmp);\n\trenderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));\n\trenderer_dc.Clear();\n\twxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CHECKED | wxCONTROL_CURRENT);\n\n\t// Checked Left Down\n\trenderer_dc.SelectObject(checked_left_down_bmp);\n\trenderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));\n\trenderer_dc.Clear();\n\twxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CHECKED | wxCONTROL_CURRENT | wxCONTROL_PRESSED);\n\n\t// Checked and Disabled\n\trenderer_dc.SelectObject(checked_disabled_bmp);\n\trenderer_dc.SetBackground(*wxTheBrushList->FindOrCreateBrush(GetBackgroundColour()));\n\trenderer_dc.Clear();\n\twxRendererNative::Get().DrawCheckBox(this, renderer_dc, wxRect(0, 0, width, height), wxCONTROL_CHECKED | wxCONTROL_DISABLED);\n\n\trenderer_dc.SelectObject(wxNullBitmap);\n\n\tstates->Add(unchecked_bmp);\n\tstates->Add(unchecked_mouse_over_bmp);\n\tstates->Add(unchecked_left_down_bmp);\n\tstates->Add(unchecked_disabled_bmp);\n\tstates->Add(checked_bmp);\n\tstates->Add(checked_mouse_over_bmp);\n\tstates->Add(checked_left_down_bmp);\n\tstates->Add(checked_disabled_bmp);\n\n\tAssignStateImageList(states);\n\n\tConnect(wxEVT_TREE_SEL_CHANGING, wxTreeEventHandler( wxCheckTree::On_Tree_Sel_Changed ), nullptr, this);\n\n\tConnect(wxEVT_CHAR, wxKeyEventHandler( wxCheckTree::On_Char ), nullptr, this);\n\tConnect(wxEVT_KEY_DOWN, wxKeyEventHandler( wxCheckTree::On_KeyDown ), nullptr, this);\n\tConnect(wxEVT_KEY_UP, wxKeyEventHandler( wxCheckTree::On_KeyUp ), nullptr, this);\n\n\tConnect(wxEVT_ENTER_WINDOW, wxMouseEventHandler( wxCheckTree::On_Mouse_Enter_Tree ), nullptr, this);\n\tConnect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler( wxCheckTree::On_Mouse_Leave_Tree ), nullptr, this);\n\tConnect(wxEVT_LEFT_DCLICK, wxMouseEventHandler( wxCheckTree::On_Left_DClick ), nullptr, this);\n\tConnect(wxEVT_LEFT_DOWN, wxMouseEventHandler( wxCheckTree::On_Left_Down ), nullptr, this);\n\tConnect(wxEVT_LEFT_UP, wxMouseEventHandler( wxCheckTree::On_Left_Up ), nullptr, this);\n\tConnect(wxEVT_MOTION, wxMouseEventHandler( wxCheckTree::On_Mouse_Motion ), nullptr, this);\n\tConnect(wxEVT_MOUSEWHEEL, wxMouseEventHandler( wxCheckTree::On_Mouse_Wheel ), nullptr, this);\n\n\tConnect(wxEVT_SET_FOCUS, wxFocusEventHandler( wxCheckTree::On_Tree_Focus_Set ), nullptr, this);\n\tConnect(wxEVT_KILL_FOCUS, wxFocusEventHandler( wxCheckTree::On_Tree_Focus_Lost ), nullptr, this);\n}\n\nvoid wxCheckTree::Sort(const wxTreeItemId& node, bool recursive)\n{\n\tif (recursive)\n\t{\n\t\twxTreeItemIdValue cookie;\n\t\tfor(auto it = GetFirstChild(node, cookie); it.IsOk(); it = GetNextChild(it, cookie))\n\t\t{\n\t\t\tSort(it, true);\n\t\t}\n\t}\n\n\tif(GetChildrenCount(node, false) > 0)\n\t\tthis->SortChildren(node);\n}\n\nint wxCheckTree::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)\n{\n\tconst bool check1 = GetChildrenCount(item1, false) == 0;\n\tconst bool check2 = GetChildrenCount(item2, false) == 0;\n\n\tif (!check1 && check2)\n\t\treturn -1;\n\n\tif (check1 && !check2)\n\t\treturn 1;\n\n\treturn GetItemText(item1).Lower().compare(GetItemText(item2).Lower());\n}\n\n\nvoid wxCheckTree::SetItemTextColour(const wxTreeItemId& item, const wxColour& col)\n{\n\tconst auto it = m_colors.find(item);\n\tif (it == m_colors.end())\n\t\tm_colors.emplace(std::pair<wxTreeItemId,wxColour>(item, col));\n\telse\n\t\tm_colors[item] = col;\n\n\twxTreeCtrl::SetItemTextColour(item, col);\n}\n\nbool wxCheckTree::EnableCheckBox(const wxTreeItemId& item, bool enable)\n{\n\tif (!item.IsOk())\n\t\treturn false;\n\t\n\tconst int state = GetItemState(item);\n\n\tif (state < 0 || state > CHECKED_DISABLED)\n\t\treturn false;\n\n\tif (enable)\n\t{\n\t\tif (state == UNCHECKED_DISABLED)\n\t\t\tSetItemState(item, UNCHECKED);\n\t\telse if (state == CHECKED_DISABLED)\n\t\t\tSetItemState(item, CHECKED);\n\n\t\tconst auto it = m_colors.find(item);\n\t\tif (it != m_colors.end())\n\t\t{\n\t\t\tSetItemTextColour(item, it->second);\n\t\t\tm_colors.erase(it);\n\t\t}\n\n\t\treturn true;\n\t}\n\tif (state == UNCHECKED_DISABLED || state == CHECKED_DISABLED)\n\t{\n\t\t//don't disable a second time or we'll lose the\n\t\t//text color information.\n\t\treturn true;\n\t}\n\n\tif (state == UNCHECKED || state == UNCHECKED_MOUSE_OVER || state == UNCHECKED_LEFT_DOWN)\n\t\tSetItemState(item, UNCHECKED_DISABLED);\n\telse if (state == CHECKED || state == CHECKED_MOUSE_OVER || state == CHECKED_LEFT_DOWN)\n\t\tSetItemState(item, CHECKED_DISABLED);\n\n\tconst wxColour col = GetItemTextColour(item);\n\tSetItemTextColour(item, wxColour(161, 161, 146));\n\tm_colors[item] = col;\n\treturn true;\n}\n\nbool wxCheckTree::DisableCheckBox(const wxTreeItemId& item)\n{\n\treturn EnableCheckBox(item, false);\n}\n\nvoid wxCheckTree::MakeCheckable(const wxTreeItemId& item, bool state)\n{\n\tif (!item.IsOk())\n\t\treturn;\n\n\tconst int i = GetItemState(item);\n\tif (i < 0 || i > CHECKED_DISABLED)\n\t\tSetItemState(item, state ? CHECKED : UNCHECKED);\n}\n\nbool wxCheckTree::IsCheckable(const wxTreeItemId& item)\n{\n\tif (!item.IsOk())\n\t\treturn false;\n\n\tconst int i = GetItemState(item);\n\treturn i >= 0 && i <= CHECKED_DISABLED;\n}\n\nvoid wxCheckTree::Check(const wxTreeItemId& item, bool state)\n{\n\tif (!item.IsOk())\n\t\treturn;\n\n\tconst int old_state = GetItemState(item);\n\tif (UNCHECKED <= old_state && old_state <= CHECKED_DISABLED)\n\t{\n\t\tconst bool enable = !(old_state == UNCHECKED_DISABLED || old_state == CHECKED_DISABLED);\n\t\tint check = enable ? CHECKED : CHECKED_DISABLED;\n\t\tint uncheck = enable ? UNCHECKED : UNCHECKED_DISABLED;\n\t\tconst int new_state = state ? check : uncheck;\n\n\t\tif (new_state != old_state)\n\t\t{\n\t\t\tSetItemState(item, new_state);\n\t\t}\n\t}\n}\n\nvoid wxCheckTree::Uncheck(const wxTreeItemId& item)\n{\n\tCheck(item, false);\n}\n\nvoid wxCheckTree::On_Tree_Sel_Changed(wxTreeEvent& event)\n{\n\twxTreeItemId id = event.GetItem();\n\n\tunhighlight(this, last_kf);\n\tmohighlight(this, id, false);\n\tlast_kf = id;\n\n\tevent.Skip();\n}\n\nvoid wxCheckTree::On_Char(wxKeyEvent& event)\n{\n\tif (!GetSelection().IsOk() && GetCount() > 0)\n\t{\n\t\t//If there is no selection, any keypress should just select the first item\n\t\twxTreeItemIdValue cookie;\n\t\tconst auto new_item = HasFlag(wxTR_HIDE_ROOT) ? GetFirstChild(GetRootItem(), cookie) : GetRootItem();\n\t\tSelectItem(new_item);\n\t\tlast_kf = new_item;\n\t\treturn;\n\t}\n\n\tevent.Skip();\n}\n\nvoid wxCheckTree::On_KeyDown(wxKeyEvent& event)\n{\n\tif (event.GetKeyCode() == WXK_SPACE)\n\t{\n\t\tlast_kf = this->GetSelection();\n\t\tldhighlight(this, last_kf);\n\t}\n\n\tevent.Skip();\n}\n\nvoid wxCheckTree::On_KeyUp(wxKeyEvent& event)\n{\n\tif (event.GetKeyCode() == WXK_SPACE)\n\t{\n\t\t//last_kf = this->GetSelection();\n \t\tmohighlight(this, last_kf, true);\n\t}\n\telse if (event.GetKeyCode() == WXK_ESCAPE)\n\t{\n\t\tunhighlight(this, last_kf);\n\t\tlast_kf = {};\n\t\tUnselect();\n\t}\n\n\tevent.Skip();\n}\n\n\nvoid wxCheckTree::On_Mouse_Enter_Tree(wxMouseEvent& event)\n{\n\tif (event.LeftIsDown())\n\t{\n\t\tmouse_entered_tree_with_left_down = true;\n\t}\n}\n\nvoid wxCheckTree::On_Mouse_Leave_Tree(wxMouseEvent& event)\n{\n\tunhighlight(this, last_mouse_over);\n\tunhighlight(this, last_left_down);\n\tlast_mouse_over = {};\n\tlast_left_down = {};\n}\n\nvoid wxCheckTree::On_Left_DClick(wxMouseEvent& event)\n{\n\tint flags;\n\n\tHitTest(event.GetPosition(), flags);\n\n\t//double clicks on buttons can be annoying, so we'll ignore those\n\t//but all other double clicks will just have 1 more click added to them\n\n\t//without this, the check boxes are not as responsive as they should be\n\tif (!(flags & wxTREE_HITTEST_ONITEMBUTTON))\n\t{\n\t\tOn_Left_Down(event);\n\t\tOn_Left_Up(event);\n\t}\n}\n\nvoid wxCheckTree::On_Left_Down(wxMouseEvent& event)\n{\n\tint flags;\n\twxTreeItemId id = HitTest(event.GetPosition(), flags);\n\tif (!id.IsOk())\n\t\treturn;\n\n\tint i = GetItemState(id);\n\n\tif (id.IsOk() && i >= 0 && on_check(flags))\n\t{\n\t\tlast_left_down = id;\n\t\tldhighlight(this, id);\n\t}\n\telse if (on_label(flags))\n\t\tevent.Skip();\n}\n\nvoid wxCheckTree::On_Left_Up(wxMouseEvent& event)\n{\n\tSetFocus();\n\n\tint flags;\n\twxTreeItemId id = HitTest(event.GetPosition(), flags);\n\tif (!id.IsOk())\n\t\treturn;\n\n\tint i = GetItemState(id);\n\n\tif (mouse_entered_tree_with_left_down)\n\t{\n\t\tmouse_entered_tree_with_left_down = false;\n\n\t\tif (i >= 0 && on_check(flags))\n\t\t{\n\t\t\tmohighlight(this, id, false);\n\t\t\tlast_mouse_over = id;\n\t\t}\n\t}\n\telse if (id.IsOk())\n\t{\n\t\tif (flags & wxTREE_HITTEST_ONITEMBUTTON && ItemHasChildren(id))\n\t\t{\n\t\t\tif (IsExpanded(id))\n\t\t\t{\n\t\t\t\tCollapse(id);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tExpand(id);\n\t\t\t}\n\t\t}\n\t\telse if (i >= 0 && on_check(flags))\n\t\t{\n\t\t\tif (id != last_left_down)\n\t\t\t{\n\t\t\t\tunhighlight(this, last_left_down);\n\t\t\t\tmohighlight(this, id, false);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tmohighlight(this, id, true);\n\t\t\t}\n\n\t\t\tlast_left_down = wxTreeItemId();\n\t\t\tlast_mouse_over = id;\n\t\t}\n\t\telse if (on_label(flags))\n\t\t{\n\t\t\tevent.Skip();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tunhighlight(this, last_left_down);\n\t\t\tunhighlight(this, last_mouse_over);\n\t\t\tlast_left_down = wxTreeItemId();\n\t\t\tlast_mouse_over = wxTreeItemId();\n\t\t}\n\t}\n\telse\n\t{\n\t\t//id is not ok\n\t\tunhighlight(this, last_left_down);\n\t\tunhighlight(this, last_mouse_over);\n\t\tlast_left_down = wxTreeItemId();\n\t\tlast_mouse_over = wxTreeItemId();\n\t}\n}\n\nvoid wxCheckTree::On_Mouse_Motion(wxMouseEvent& event)\n{\n\tif (mouse_entered_tree_with_left_down)\n\t{\n\t\t//just ignore everything until the left button is released\n\t\treturn;\n\t}\n\n\tint flags;\n\twxTreeItemId id = HitTest(event.GetPosition(), flags);\n\n\tif (!id.IsOk())\n\t{\n\t\tunhighlight(this, last_mouse_over);\n\t\tlast_mouse_over = {};\n\t}\n\telse if (event.LeftIsDown() && last_left_down.IsOk())\n\t{\n\t\t//to match the behavior of ordinary check boxes,\n\t\t//if we've moved to a new item while holding the mouse button down\n\t\t//we want to set the item where the left down click occured to have\n\t\t//mouse over highlight.  And if we return to the box where the\n\t\t//left down occured, we want to return it to the having the left down highlight\n\n\t\t//I don't understand why this is the behavior\n\t\t//of ordinary check boxes, but I'm goin to match it anyway.\n\n\t\tif (id == last_left_down)\n\t\t{\n\t\t\tconst auto state = GetItemState(last_left_down);\n\t\t\tif (state != UNCHECKED_LEFT_DOWN && state != CHECKED_LEFT_DOWN)\n\t\t\t{\n\t\t\t\tldhighlight(this, last_left_down);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tmohighlight(this, last_left_down, false);\n\t}\n\telse\n\t{\n\t\t//4 cases 1 we're still on the same item, but we've moved off the state icon or label\n\t\t//        2 we're still on the same item and on the state icon or label - do nothing\n\t\t//        3 we're on a new item but not on its state icon or label (or the new item has no state)\n\t\t//        4 we're on a new item, it has a state icon, and we're on the state icon or label\n\n\t\tconst int state = GetItemState(id);\n\t\tif (id == last_mouse_over)\n\t\t{\n\t\t\tif (state < 0 || !on_check(flags))\n\t\t\t{\n\t\t\t\tunhighlight(this, last_mouse_over);\n\t\t\t\tlast_mouse_over = {};\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (state < 0 || !on_check(flags))\n\t\t\t{\n\t\t\t\tunhighlight(this, last_mouse_over);\n\t\t\t\tlast_mouse_over = {};\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tunhighlight(this, last_mouse_over);\n\t\t\t\tmohighlight(this, id, false);\n\t\t\t\tlast_mouse_over = id;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid wxCheckTree::On_Mouse_Wheel(wxMouseEvent& event)\n{\n\tevent.Skip();\n}\n\nvoid wxCheckTree::On_Tree_Focus_Set(wxFocusEvent& event)\n{\n\t//event.Skip();\n\n\t//skipping this event will set the last selected item\n\t//to be highlighted and I want the tree items to only be\n\t//highlighted by keyboard actions.\n}\n\nvoid wxCheckTree::On_Tree_Focus_Lost(wxFocusEvent& event)\n{\n\tunhighlight(this, last_kf);\n\tUnselect();\n\tevent.Skip();\n}\n\nvoid wxCheckTree::SetFocusFromKbd()\n{\n\tif (last_kf.IsOk())\n\t\tSelectItem(last_kf);\n\n\twxTreeEvent event2(wxEVT_CHECKTREE_FOCUS, this, wxTreeItemId());\n\tProcessWindowEvent(event2);\n\n\twxWindow::SetFocusFromKbd();\n}\n"
  },
  {
    "path": "src/gui/wxgui/wxcomponents/checktree.h",
    "content": "#ifndef checktree_H_INCLUDED\n#define checktree_H_INCLUDED\n\n// credits to: https://forums.wxwidgets.org/viewtopic.php?t=39582\n\n#include \"wx/treectrl.h\"\n#include <map>\n\n#define WXMAKINGDLL_CHECKTREE\n\n// dll export macros\n#ifdef WXMAKINGDLL_CHECKTREE\n    #define WXDLLIMPEXP_CHECKTREE WXEXPORT\n#elif defined(WXUSING_CHECKTREE_SOURCE)\n    #define WXDLLIMPEXP_CHECKTREE\n#elif defined(WXUSINGDLL)\n    #define WXDLLIMPEXP_CHECKTREE WXIMPORT\n#else // not making nor using DLL\n    #define WXDLLIMPEXP_CHECKTREE\n#endif\n\n#include <wx/object.h> \n// wxDECLARE_CLASS, wxIMPLEMENT_CLASS  for sorting?\n\nclass WXDLLIMPEXP_CHECKTREE wxCheckTree : public wxTreeCtrl\n{\n\twxDECLARE_ABSTRACT_CLASS(wxCheckTree);\n\n    public:\n\t\twxCheckTree();\n        wxCheckTree(wxWindow *parent, const wxWindowID id,\n                   const wxPoint& pos, const wxSize& size,\n                   long style);\n\t\t\n\n        void Init();\n\t\tvoid Sort(const wxTreeItemId& node, bool recursive);\n\n\t\tint OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2) override;\n\n        //methods overriden from base class:\n        void SetFocusFromKbd() override;\n        void SetItemTextColour(const wxTreeItemId &item, const wxColour &col) override;\n\n        //interaction with the check boxes:\n        bool EnableCheckBox(const wxTreeItemId &item, bool enable = true );\n        bool DisableCheckBox(const wxTreeItemId &item);\n        void Check(const wxTreeItemId &item,bool state=true);\n        void Uncheck(const wxTreeItemId &item);\n\t\tvoid MakeCheckable(const wxTreeItemId &item, bool state = false);\n\t\tbool IsCheckable(const wxTreeItemId& item);\n\n\t\tenum\n\t\t{\n\t\t    UNCHECKED,\n\t\t    UNCHECKED_MOUSE_OVER,\n\t\t    UNCHECKED_LEFT_DOWN,\n\t\t    UNCHECKED_DISABLED,\n            CHECKED,\n\t\t    CHECKED_MOUSE_OVER,\n\t\t    CHECKED_LEFT_DOWN,\n\t\t    CHECKED_DISABLED\n\t\t};\n\n    private:\n        //event handlers\n\t\tvoid On_Tree_Sel_Changed( wxTreeEvent& event );\n\n        void On_Char( wxKeyEvent& event );\n        void On_KeyDown( wxKeyEvent& event );\n        void On_KeyUp( wxKeyEvent& event );\n\n        void On_Mouse_Enter_Tree( wxMouseEvent& event );\n        void On_Mouse_Leave_Tree( wxMouseEvent& event );\n        void On_Left_DClick( wxMouseEvent& event );\n        void On_Left_Down( wxMouseEvent& event );\n        void On_Left_Up( wxMouseEvent& event );\n        void On_Mouse_Motion( wxMouseEvent& event );\n        void On_Mouse_Wheel( wxMouseEvent& event );\n\n        void On_Tree_Focus_Set( wxFocusEvent& event );\n        void On_Tree_Focus_Lost( wxFocusEvent& event );\n\n        //private data:\n        std::map<wxTreeItemId,wxColour> m_colors;\n\n        bool mouse_entered_tree_with_left_down = false;\n\n        wxTreeItemId last_mouse_over{};\n\t\twxTreeItemId last_left_down{};\n\t\twxTreeItemId last_kf{};\n\n\n    // NB: due to an ugly wxMSW hack you _must_ use DECLARE_DYNAMIC_CLASS()\n    //     if you want your overloaded OnCompareItems() to be called.\n    //     OTOH, if you don't want it you may omit the next line - this will\n    //     make default (alphabetical) sorting much faster under wxMSW.\n    //DECLARE_DYNAMIC_CLASS(wxCheckTree)\n};\n\nwxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CHECKTREE, wxEVT_CHECKTREE_CHOICE, wxTreeEvent);\nwxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CHECKTREE, wxEVT_CHECKTREE_FOCUS, wxTreeEvent);\n\n\n#endif // checktree_H_INCLUDED\n"
  },
  {
    "path": "src/gui/wxgui/wxgui.h",
    "content": "#pragma once\n\n#define wxNO_UNSAFE_WXSTRING_CONV 1\n\n#include <wx/wxprec.h>\n#ifndef WX_PRECOMP\n#include <wx/wx.h>\n#endif\n\n#include <wx/listctrl.h>\n#include <wx/notebook.h>\n#include <wx/panel.h>\n#include <wx/timer.h>\n#include <wx/slider.h>\n#include <wx/stattext.h>\n#include <wx/textctrl.h>\n#include <wx/spinctrl.h>\n#include <wx/listbase.h>\n#include <wx/display.h>\n#include <wx/aboutdlg.h>\n#include <wx/dialog.h>\n#include <wx/timer.h>\n#include <wx/gauge.h>\n#include <wx/dataview.h>\n#include <wx/statline.h>\n#include <wx/wrapsizer.h>\n#include <wx/gbsizer.h>\n#include <wx/radiobox.h>\n#include <wx/combobox.h>\n#include <wx/sizer.h>\n#include <wx/scrolbar.h>\n#include <wx/richtext/richtextctrl.h>\n#include <wx/dcbuffer.h>\n#include <wx/combo.h>\n#include <wx/wupdlock.h>\n#include <wx/infobar.h>\n#include <wx/splitter.h>\n\nextern bool g_inputConfigWindowHasFocus;\n\ninline bool SendSliderEvent(wxSlider* slider, int new_value)\n{\n\twxCommandEvent cevent(wxEVT_SLIDER, slider->GetId());\n\tcevent.SetInt(new_value);\n\tcevent.SetEventObject(slider);\n\treturn slider->HandleWindowEvent(cevent);\n}\n"
  },
  {
    "path": "src/imgui/CMakeLists.txt",
    "content": "add_library(imguiImpl\n\timgui_impl_opengl3.cpp\n\timgui_impl_opengl3.h\n\timgui_impl_vulkan.cpp\n\timgui_impl_vulkan.h\n\timgui_extension.cpp\n\timgui_extension.h\n)\n\nif (ENABLE_METAL)\n    target_sources(imguiImpl PRIVATE\n        imgui_impl_metal.mm\n        imgui_impl_metal.h\n    )\n\n    target_compile_definitions(imguiImpl PRIVATE IMGUI_IMPL_METAL_CPP)\nendif ()\n\nset_property(TARGET imguiImpl PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\ntarget_include_directories(imguiImpl PUBLIC \"../\")\n\n# imgui source files\ntarget_sources(imguiImpl PRIVATE\n\"../../dependencies/imgui/imgui.cpp\"\n\"../../dependencies/imgui/imgui_draw.cpp\"\n\"../../dependencies/imgui/imgui_tables.cpp\"\n\"../../dependencies/imgui/imgui_widgets.cpp\"\n)\n\ntarget_include_directories(imguiImpl PUBLIC \"../../dependencies/imgui/\")\n\ntarget_link_libraries(imguiImpl PRIVATE\n\tCemuCommon\n\tCemuGui\n)\n"
  },
  {
    "path": "src/imgui/imgui_extension.cpp",
    "content": "#include \"imgui_extension.h\"\n#include \"WindowSystem.h\"\n#include \"Cafe/HW/Latte/Renderer/Renderer.h\"\n#include \"resource/IconsFontAwesome5.h\"\n#include \"imgui_impl_opengl3.h\"\n#include \"resource/resource.h\"\n#include \"imgui_impl_vulkan.h\"\n#include \"input/InputManager.h\"\n\n// <imgui_internal.h>\ntemplate<typename T> static T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; }\ntemplate<typename T> static T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; }\nstatic ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }\n\nint rotation_start_index;\nvoid ImRotateStart()\n{\n\trotation_start_index = ImGui::GetWindowDrawList()->VtxBuffer.Size;\n}\n\nImVec2 ImRotationCenter()\n{\n\tImVec2 l(FLT_MAX, FLT_MAX), u(-FLT_MAX, -FLT_MAX); // bounds\n\n\tconst auto& buf = ImGui::GetWindowDrawList()->VtxBuffer;\n\tfor (int i = rotation_start_index; i < buf.Size; i++)\n\t\tl = ImMin(l, buf[i].pos), u = ImMax(u, buf[i].pos);\n\n\treturn ImVec2((l.x + u.x) / 2, (l.y + u.y) / 2); // or use _ClipRectStack?\n}\n\nvoid ImRotateEnd(float rad, ImVec2 center)\n{\n\tconst float s = sin(rad);\n\tconst float c = cos(rad);\n\tcenter = ImRotate(center, s, c) - center;\n\n\tauto& buf = ImGui::GetWindowDrawList()->VtxBuffer;\n\tfor (int i = rotation_start_index; i < buf.Size; i++)\n\t\tbuf[i].pos = ImRotate(buf[i].pos, s, c) - center;\n}\n\nuint8* extractCafeDefaultFont(sint32* size);\nsint32 g_font_size = 0;\nuint8* g_font_data = nullptr;\n#if !BOOST_OS_WINDOWS\nextern int const g_fontawesome_size;\nextern char const g_fontawesome_data[];\n#endif\nstd::unordered_map<int, ImFont*> g_imgui_fonts;\nstd::stack<int> g_font_requests;\n\nvoid ImGui_PrecacheFonts()\n{\n\twhile (!g_font_requests.empty())\n\t{\n\t\tconst int size = g_font_requests.top();\n\t\tg_font_requests.pop();\n\t\t\n\t\tauto& io = ImGui::GetIO();\n\t\tcemu_assert(io.Fonts->Locked == false);\n\n\t\tif (g_font_size == 0)\n\t\t\tg_font_data = extractCafeDefaultFont(&g_font_size);\n\n\t\tImFontConfig cfg{};\n\t\tcfg.FontDataOwnedByAtlas = false;\n\t\t//cfg.FontData = g_font_data;\n\t\t//cfg.FontDataSize = g_font_size;\n\t\t//cfg.SizePixels = size;\n\t\tImFont* font = io.Fonts->AddFontFromMemoryTTF(g_font_data, g_font_size, (float)size, &cfg);\n\n\t\tImFontConfig cfgmerge{};\n\t\tcfgmerge.FontDataOwnedByAtlas = false;\n\t\tcfgmerge.MergeMode = true;\n\t\tcfgmerge.GlyphMinAdvanceX = 20.0f;\n\t\t//cfgmerge.GlyphOffset = { 2,2 };\n\n\t\tstatic const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };\n\n#if BOOST_OS_WINDOWS\n\t\tconst auto hinstance = GetModuleHandle(nullptr);\n\t\tconst HRSRC res = FindResource(hinstance, MAKEINTRESOURCE(IDR_FONTAWESOME), RT_RCDATA);\n\t\tif (res)\n\t\t{\n\t\t\tconst HGLOBAL mem = ::LoadResource(hinstance, res);\n\t\t\tif (mem)\n\t\t\t{\n\t\t\t\tvoid* data = LockResource(mem);\n\t\t\t\tconst size_t len = SizeofResource(hinstance, res);\n\n\t\t\t\tio.Fonts->AddFontFromMemoryTTF(data, (int)len, (float)size, &cfgmerge, icon_ranges);\n\t\t\t}\n\t\t}\n#else\n\t\tio.Fonts->AddFontFromMemoryTTF((void*)g_fontawesome_data, (int)g_fontawesome_size, (float)size, &cfgmerge, icon_ranges);\n#endif\n\n\t\tg_imgui_fonts[(int)size] = font;\n\n\t\t// Vulkan doesn't let us destroy resources that are still being used, so we flush here\n\t\tg_renderer->Flush(true);\n\t\tg_renderer->DeleteFontTextures();\n\t}\n}\n\nvoid ImGui_ClearFonts()\n{\n    g_imgui_fonts.clear();\n}\n\nImFont* ImGui_GetFont(float size)\n{\n\tconst auto it = g_imgui_fonts.find((int)size);\n\tif (it != g_imgui_fonts.cend())\n\t\treturn it->second;\n\n\tg_font_requests.emplace((int)size);\n\treturn nullptr; // will create the font in next precache call\n}\n\nvoid ImGui_UpdateWindowInformation(bool mainWindow)\n{\n\tstatic std::map<uint32, ImGuiKey> keyboard_mapping;\n\tauto& windowInfo = WindowSystem::GetWindowInfo();\n\tstatic uint32 current_key = 0;\n\tImGuiIO& io = ImGui::GetIO();\n\tio.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;\n\tio.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;\n#if BOOST_OS_WINDOWS\n\tio.ImeWindowHandle = mainWindow ? windowInfo.window_main.surface : windowInfo.window_pad.surface;\n#else\n\tio.ImeWindowHandle = nullptr;\n#endif\n\n\tio.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);\n\n\tauto& instance = InputManager::instance();\n\n\tconst auto mousePos = instance.get_mouse_position(!mainWindow);\n\tio.MousePos = { (float)mousePos.x, (float)mousePos.y };\n\n\tbool padDown;\n\tconst auto pos = instance.get_left_down_mouse_info(&padDown);\n\tio.MouseDown[0] = padDown != mainWindow && pos.has_value();\n\tauto get_mapping = [&](uint32 key_code)\n\t{\n\t\tauto key = keyboard_mapping.find(key_code);\n\t\tif (key != keyboard_mapping.end())\n\t\t\treturn key->second;\n\t\tImGuiKey mapped_key = (ImGuiKey)((uint32)current_key + ImGuiKey_NamedKey_BEGIN);\n\t\tcurrent_key = (current_key + 1) % (uint32)ImGuiKey_NamedKey_COUNT;\n\t\tkeyboard_mapping[key_code] = mapped_key;\n\t\treturn mapped_key;\n\t};\n\twindowInfo.iter_keystates([&](auto&& el){ io.AddKeyEvent(get_mapping(el.first), el.second); });\n\n\t// printf(\"%f %f %d\\n\", io.MousePos.x, io.MousePos.y, io.MouseDown[0]);\n\n\tfor (auto i = 0; i < InputManager::kMaxController; ++i)\n\t{\n\t\tconst auto controller = instance.get_controller(i);\n\t\tif (!controller)\n\t\t\tcontinue;\n\n\t\tif (controller->is_start_down())\n\t\t\tio.NavInputs[ImGuiNavInput_Input] = 1.0f;\n\n\t\tif (controller->is_a_down())\n\t\t\tio.NavInputs[ImGuiNavInput_Activate] = 1.0f;\n\t\t\n\t\tif (controller->is_b_down())\n\t\t\tio.NavInputs[ImGuiNavInput_Cancel] = 1.0f;\n\t\t\n\t\tif (controller->is_left_down())\n\t\t\tio.NavInputs[ImGuiNavInput_DpadLeft] = 1.0f;\n\t\t\n\t\tif (controller->is_right_down())\n\t\t\tio.NavInputs[ImGuiNavInput_DpadRight] = 1.0f;\n\t\t\n\t\tif (controller->is_up_down())\n\t\t\tio.NavInputs[ImGuiNavInput_DpadUp] = 1.0f;\n\t\t\n\t\tif (controller->is_down_down())\n\t\t\tio.NavInputs[ImGuiNavInput_DpadDown] = 1.0f;\n\t}\n}\n"
  },
  {
    "path": "src/imgui/imgui_extension.h",
    "content": "#pragma once\n#include \"imgui.h\"\n\nvoid ImRotateStart();\nImVec2 ImRotationCenter();\nvoid ImRotateEnd(float rad, ImVec2 center = ImRotationCenter());\n\ninline ImVec2 operator-(const ImVec2& l, const ImVec2& r) { return{ l.x - r.x, l.y - r.y }; }\ninline bool operator<(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x < rhs.x; }\ninline bool operator>=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x >= rhs.x; }\n\nbool ImGui_BeginPadDistinct(const char* name, bool* p_open, ImGuiWindowFlags flags, bool pad);\n\nvoid ImGui_PrecacheFonts();\nvoid ImGui_ClearFonts();\nImFont* ImGui_GetFont(float size);\nvoid ImGui_UpdateWindowInformation(bool mainWindow);"
  },
  {
    "path": "src/imgui/imgui_impl_metal.h",
    "content": "// dear imgui: Renderer Backend for Metal\n// This needs to be used along with a Platform Backend (e.g. OSX)\n\n// Implemented features:\n//  [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!\n//  [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.\n\n// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.\n// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.\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 \"imgui.h\"      // IMGUI_IMPL_API\n\n//-----------------------------------------------------------------------------\n// ObjC API\n//-----------------------------------------------------------------------------\n\n#ifdef __OBJC__\n\n@class MTLRenderPassDescriptor;\n@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;\n\nIMGUI_IMPL_API bool ImGui_ImplMetal_Init(id<MTLDevice> device);\nIMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();\nIMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor);\nIMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData,\n                                                   id<MTLCommandBuffer> commandBuffer,\n                                                   id<MTLRenderCommandEncoder> commandEncoder);\n\n// Called by Init/NewFrame/Shutdown\nIMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device);\nIMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();\nIMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);\nIMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();\n\n#endif\n\n//-----------------------------------------------------------------------------\n// C++ API\n//-----------------------------------------------------------------------------\n\n// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file\n// More info about using Metal from C++: https://developer.apple.com/metal/cpp/\n\n#ifdef IMGUI_IMPL_METAL_CPP\n#include <Metal/Metal.hpp>\n#ifndef __OBJC__\n\nIMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device);\nIMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();\nIMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor);\nIMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,\n                                                   MTL::CommandBuffer* commandBuffer,\n                                                   MTL::RenderCommandEncoder* commandEncoder);\n\n// Called by Init/NewFrame/Shutdown\nIMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device);\nIMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();\nIMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device);\nIMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();\n\n#endif\n#endif\n"
  },
  {
    "path": "src/imgui/imgui_impl_metal.mm",
    "content": "// dear imgui: Renderer Backend for Metal\n// This needs to be used along with a Platform Backend (e.g. OSX)\n\n// Implemented features:\n//  [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID!\n//  [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.\n\n// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.\n// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.\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// CHANGELOG\n// (minor and older changes stripped away, please see git history for details)\n//  2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'.\n//  2022-07-05: Metal: Add dispatch synchronization.\n//  2022-06-30: Metal: Use __bridge for ARC based systems.\n//  2022-06-01: Metal: Fixed null dereference on exit inside command buffer completion handler.\n//  2022-04-27: Misc: Store backend data in a per-context struct, allowing to use this backend with multiple contexts.\n//  2022-01-03: Metal: Ignore ImDrawCmd where ElemCount == 0 (very rare but can technically be manufactured by user code).\n//  2021-12-30: Metal: Added Metal C++ support. Enable with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file.\n//  2021-08-24: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted. (#4464)\n//  2021-05-19: Metal: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)\n//  2021-02-18: Metal: Change blending equation to preserve alpha in output buffer.\n//  2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst.\n//  2019-05-29: Metal: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.\n//  2019-04-30: Metal: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.\n//  2019-02-11: Metal: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.\n//  2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.\n//  2018-07-05: Metal: Added new Metal backend implementation.\n\n#include \"imgui.h\"\n#include \"imgui_impl_metal.h\"\n#import <time.h>\n#import <Metal/Metal.h>\n\n#pragma mark - Support classes\n\n// A wrapper around a MTLBuffer object that knows the last time it was reused\n@interface MetalBuffer : NSObject\n@property (nonatomic, strong) id<MTLBuffer> buffer;\n@property (nonatomic, assign) double        lastReuseTime;\n- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer;\n@end\n\n// An object that encapsulates the data necessary to uniquely identify a\n// render pipeline state. These are used as cache keys.\n@interface FramebufferDescriptor : NSObject<NSCopying>\n@property (nonatomic, assign) unsigned long  sampleCount;\n@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;\n@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;\n@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;\n- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor;\n@end\n\n// A singleton that stores long-lived objects that are needed by the Metal\n// renderer backend. Stores the render pipeline state cache and the default\n// font texture, and manages the reusable buffer cache.\n@interface MetalContext : NSObject\n@property (nonatomic, strong) id<MTLDevice>                 device;\n@property (nonatomic, strong) id<MTLDepthStencilState>      depthStencilState;\n@property (nonatomic, strong) FramebufferDescriptor*        framebufferDescriptor; // framebuffer descriptor for current frame; transient\n@property (nonatomic, strong) NSMutableDictionary*          renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors\n@property (nonatomic, strong, nullable) id<MTLTexture>      fontTexture;\n@property (nonatomic, strong) NSMutableArray<MetalBuffer*>* bufferCache;\n@property (nonatomic, assign) double                        lastBufferCachePurge;\n- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;\n- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device;\n@end\n\nstruct ImGui_ImplMetal_Data\n{\n    MetalContext*               SharedMetalContext;\n\n    ImGui_ImplMetal_Data()      { memset(this, 0, sizeof(*this)); }\n};\n\nstatic ImGui_ImplMetal_Data*    ImGui_ImplMetal_CreateBackendData() { return IM_NEW(ImGui_ImplMetal_Data)(); }\nstatic ImGui_ImplMetal_Data*    ImGui_ImplMetal_GetBackendData()    { return ImGui::GetCurrentContext() ? (ImGui_ImplMetal_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; }\nstatic void                     ImGui_ImplMetal_DestroyBackendData(){ IM_DELETE(ImGui_ImplMetal_GetBackendData()); }\n\nstatic inline CFTimeInterval    GetMachAbsoluteTimeInSeconds()      { return (CFTimeInterval)(double)(clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1e9); }\n\n#ifdef IMGUI_IMPL_METAL_CPP\n\n#pragma mark - Dear ImGui Metal C++ Backend API\n\nbool ImGui_ImplMetal_Init(MTL::Device* device)\n{\n    return ImGui_ImplMetal_Init((__bridge id<MTLDevice>)(device));\n}\n\nvoid ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor)\n{\n    ImGui_ImplMetal_NewFrame((__bridge MTLRenderPassDescriptor*)(renderPassDescriptor));\n}\n\nvoid ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,\n                                    MTL::CommandBuffer* commandBuffer,\n                                    MTL::RenderCommandEncoder* commandEncoder)\n{\n    ImGui_ImplMetal_RenderDrawData(draw_data,\n                                   (__bridge id<MTLCommandBuffer>)(commandBuffer),\n                                   (__bridge id<MTLRenderCommandEncoder>)(commandEncoder));\n\n}\n\nbool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device)\n{\n    return ImGui_ImplMetal_CreateFontsTexture((__bridge id<MTLDevice>)(device));\n}\n\nbool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device)\n{\n    return ImGui_ImplMetal_CreateDeviceObjects((__bridge id<MTLDevice>)(device));\n}\n\n#endif // #ifdef IMGUI_IMPL_METAL_CPP\n\n#pragma mark - Dear ImGui Metal Backend API\n\nbool ImGui_ImplMetal_Init(id<MTLDevice> device)\n{\n    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_CreateBackendData();\n    ImGuiIO& io = ImGui::GetIO();\n    io.BackendRendererUserData = (void*)bd;\n    io.BackendRendererName = \"imgui_impl_metal\";\n    io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.\n\n    bd->SharedMetalContext = [[MetalContext alloc] init];\n    bd->SharedMetalContext.device = device;\n\n    return true;\n}\n\nvoid ImGui_ImplMetal_Shutdown()\n{\n    ImGui_ImplMetal_DestroyDeviceObjects();\n    ImGui_ImplMetal_DestroyBackendData();\n}\n\nvoid ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor)\n{\n    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();\n    IM_ASSERT(bd->SharedMetalContext != nil && \"No Metal context. Did you call ImGui_ImplMetal_Init() ?\");\n    bd->SharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor];\n\n    if (bd->SharedMetalContext.depthStencilState == nil)\n        ImGui_ImplMetal_CreateDeviceObjects(bd->SharedMetalContext.device);\n}\n\nstatic void ImGui_ImplMetal_SetupRenderState(ImDrawData* drawData, id<MTLCommandBuffer> commandBuffer,\n    id<MTLRenderCommandEncoder> commandEncoder, id<MTLRenderPipelineState> renderPipelineState,\n    MetalBuffer* vertexBuffer, size_t vertexBufferOffset)\n{\n    IM_UNUSED(commandBuffer);\n    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();\n    [commandEncoder setCullMode:MTLCullModeNone];\n    [commandEncoder setDepthStencilState:bd->SharedMetalContext.depthStencilState];\n\n    // Setup viewport, orthographic projection matrix\n    // Our visible imgui space lies from draw_data->DisplayPos (top left) to\n    // draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.\n    MTLViewport viewport =\n    {\n        .originX = 0.0,\n        .originY = 0.0,\n        .width = (double)(drawData->DisplaySize.x * drawData->FramebufferScale.x),\n        .height = (double)(drawData->DisplaySize.y * drawData->FramebufferScale.y),\n        .znear = 0.0,\n        .zfar = 1.0\n    };\n    [commandEncoder setViewport:viewport];\n\n    float L = drawData->DisplayPos.x;\n    float R = drawData->DisplayPos.x + drawData->DisplaySize.x;\n    float T = drawData->DisplayPos.y;\n    float B = drawData->DisplayPos.y + drawData->DisplaySize.y;\n    float N = (float)viewport.znear;\n    float F = (float)viewport.zfar;\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/(F-N),   0.0f },\n        { (R+L)/(L-R),  (T+B)/(B-T), N/(F-N),   1.0f },\n    };\n    [commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];\n\n    [commandEncoder setRenderPipelineState:renderPipelineState];\n\n    [commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];\n    [commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];\n}\n\n// Metal Render function.\nvoid ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)\n{\n    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();\n    MetalContext* ctx = bd->SharedMetalContext;\n\n    // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)\n    int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x);\n    int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y);\n    if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0)\n        return;\n\n    // Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame\n    // The hit rate for this cache should be very near 100%.\n    id<MTLRenderPipelineState> renderPipelineState = ctx.renderPipelineStateCache[ctx.framebufferDescriptor];\n    if (renderPipelineState == nil)\n    {\n        // No luck; make a new render pipeline state\n        renderPipelineState = [ctx renderPipelineStateForFramebufferDescriptor:ctx.framebufferDescriptor device:commandBuffer.device];\n\n        // Cache render pipeline state for later reuse\n        ctx.renderPipelineStateCache[ctx.framebufferDescriptor] = renderPipelineState;\n    }\n\n    size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert);\n    size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx);\n    MetalBuffer* vertexBuffer = [ctx dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];\n    MetalBuffer* indexBuffer = [ctx dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];\n\n    ImGui_ImplMetal_SetupRenderState(drawData, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 0);\n\n    // Will project scissor/clipping rectangles into framebuffer space\n    ImVec2 clip_off = drawData->DisplayPos;         // (0,0) unless using multi-viewports\n    ImVec2 clip_scale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2)\n\n    // Render command lists\n    size_t vertexBufferOffset = 0;\n    size_t indexBufferOffset = 0;\n    for (int n = 0; n < drawData->CmdListsCount; n++)\n    {\n        const ImDrawList* cmd_list = drawData->CmdLists[n];\n\n        memcpy((char*)vertexBuffer.buffer.contents + vertexBufferOffset, cmd_list->VtxBuffer.Data, (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));\n        memcpy((char*)indexBuffer.buffer.contents + indexBufferOffset, cmd_list->IdxBuffer.Data, (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));\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)\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_ImplMetal_SetupRenderState(drawData, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset);\n                else\n                    pcmd->UserCallback(cmd_list, pcmd);\n            }\n            else\n            {\n                // Project scissor/clipping rectangles into framebuffer space\n                ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);\n                ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);\n\n                // Clamp to viewport as setScissorRect() won't accept values that are off bounds\n                if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }\n                if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }\n                if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }\n                if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }\n                if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)\n                    continue;\n                if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this\n                    continue;\n\n                // Apply scissor/clipping rectangle\n                MTLScissorRect scissorRect =\n                {\n                    .x = NSUInteger(clip_min.x),\n                    .y = NSUInteger(clip_min.y),\n                    .width = NSUInteger(clip_max.x - clip_min.x),\n                    .height = NSUInteger(clip_max.y - clip_min.y)\n                };\n                [commandEncoder setScissorRect:scissorRect];\n\n                // Bind texture, Draw\n                if (ImTextureID tex_id = pcmd->GetTexID())\n                    [commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) atIndex:0];\n\n                [commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];\n                [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle\n                                           indexCount:pcmd->ElemCount\n                                            indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32\n                                          indexBuffer:indexBuffer.buffer\n                                    indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];\n            }\n        }\n\n        vertexBufferOffset += (size_t)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert);\n        indexBufferOffset += (size_t)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx);\n    }\n\n    [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)\n    {\n        dispatch_async(dispatch_get_main_queue(), ^{\n            ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();\n            if (bd != nullptr)\n            {\n                @synchronized(bd->SharedMetalContext.bufferCache)\n                {\n                    [bd->SharedMetalContext.bufferCache addObject:vertexBuffer];\n                    [bd->SharedMetalContext.bufferCache addObject:indexBuffer];\n                }\n            }\n        });\n    }];\n}\n\nbool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device)\n{\n    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();\n    ImGuiIO& io = ImGui::GetIO();\n\n    // We are retrieving and uploading the font atlas as a 4-channels RGBA texture here.\n    // In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.\n    // However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.\n    // You can make that change in your implementation.\n    unsigned char* pixels;\n    int width, height;\n    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);\n    MTLTextureDescriptor* textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm\n                                                                                                 width:(NSUInteger)width\n                                                                                                height:(NSUInteger)height\n                                                                                             mipmapped:NO];\n    textureDescriptor.usage = MTLTextureUsageShaderRead;\n#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n    textureDescriptor.storageMode = MTLStorageModeManaged;\n#else\n    textureDescriptor.storageMode = MTLStorageModeShared;\n#endif\n    id <MTLTexture> texture = [device newTextureWithDescriptor:textureDescriptor];\n    [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4];\n    bd->SharedMetalContext.fontTexture = texture;\n    io.Fonts->SetTexID((__bridge void*)bd->SharedMetalContext.fontTexture); // ImTextureID == void*\n\n    return (bd->SharedMetalContext.fontTexture != nil);\n}\n\nvoid ImGui_ImplMetal_DestroyFontsTexture()\n{\n    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();\n    ImGuiIO& io = ImGui::GetIO();\n    bd->SharedMetalContext.fontTexture = nil;\n    io.Fonts->SetTexID(nullptr);\n}\n\nbool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)\n{\n    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();\n    MTLDepthStencilDescriptor* depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];\n    depthStencilDescriptor.depthWriteEnabled = NO;\n    depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;\n    bd->SharedMetalContext.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];\n    ImGui_ImplMetal_CreateFontsTexture(device);\n\n    return true;\n}\n\nvoid ImGui_ImplMetal_DestroyDeviceObjects()\n{\n    ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();\n    ImGui_ImplMetal_DestroyFontsTexture();\n    [bd->SharedMetalContext.renderPipelineStateCache removeAllObjects];\n}\n\n#pragma mark - MetalBuffer implementation\n\n@implementation MetalBuffer\n- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer\n{\n    if ((self = [super init]))\n    {\n        _buffer = buffer;\n        _lastReuseTime = GetMachAbsoluteTimeInSeconds();\n    }\n    return self;\n}\n@end\n\n#pragma mark - FramebufferDescriptor implementation\n\n@implementation FramebufferDescriptor\n- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor\n{\n    if ((self = [super init]))\n    {\n        _sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;\n        _colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;\n        _depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat;\n        _stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat;\n    }\n    return self;\n}\n\n- (nonnull id)copyWithZone:(nullable NSZone*)zone\n{\n    FramebufferDescriptor* copy = [[FramebufferDescriptor allocWithZone:zone] init];\n    copy.sampleCount = self.sampleCount;\n    copy.colorPixelFormat = self.colorPixelFormat;\n    copy.depthPixelFormat = self.depthPixelFormat;\n    copy.stencilPixelFormat = self.stencilPixelFormat;\n    return copy;\n}\n\n- (NSUInteger)hash\n{\n    NSUInteger sc = _sampleCount & 0x3;\n    NSUInteger cf = _colorPixelFormat & 0x3FF;\n    NSUInteger df = _depthPixelFormat & 0x3FF;\n    NSUInteger sf = _stencilPixelFormat & 0x3FF;\n    NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc;\n    return hash;\n}\n\n- (BOOL)isEqual:(id)object\n{\n    FramebufferDescriptor* other = object;\n    if (![other isKindOfClass:[FramebufferDescriptor class]])\n        return NO;\n    return other.sampleCount == self.sampleCount      &&\n    other.colorPixelFormat   == self.colorPixelFormat &&\n    other.depthPixelFormat   == self.depthPixelFormat &&\n    other.stencilPixelFormat == self.stencilPixelFormat;\n}\n\n@end\n\n#pragma mark - MetalContext implementation\n\n@implementation MetalContext\n- (instancetype)init\n{\n    if ((self = [super init]))\n    {\n        self.renderPipelineStateCache = [NSMutableDictionary dictionary];\n        self.bufferCache = [NSMutableArray array];\n        _lastBufferCachePurge = GetMachAbsoluteTimeInSeconds();\n    }\n    return self;\n}\n\n- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device\n{\n    uint64_t now = GetMachAbsoluteTimeInSeconds();\n\n    @synchronized(self.bufferCache)\n    {\n        // Purge old buffers that haven't been useful for a while\n        if (now - self.lastBufferCachePurge > 1.0)\n        {\n            NSMutableArray* survivors = [NSMutableArray array];\n            for (MetalBuffer* candidate in self.bufferCache)\n                if (candidate.lastReuseTime > self.lastBufferCachePurge)\n                    [survivors addObject:candidate];\n            self.bufferCache = [survivors mutableCopy];\n            self.lastBufferCachePurge = now;\n        }\n\n        // See if we have a buffer we can reuse\n        MetalBuffer* bestCandidate = nil;\n        for (MetalBuffer* candidate in self.bufferCache)\n            if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime))\n                bestCandidate = candidate;\n\n        if (bestCandidate != nil)\n        {\n            [self.bufferCache removeObject:bestCandidate];\n            bestCandidate.lastReuseTime = now;\n            return bestCandidate;\n        }\n    }\n\n    // No luck; make a new buffer\n    id<MTLBuffer> backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared];\n    return [[MetalBuffer alloc] initWithBuffer:backing];\n}\n\n// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.\n- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device\n{\n    NSError* error = nil;\n\n    NSString* shaderSource = @\"\"\n    \"#include <metal_stdlib>\\n\"\n    \"using namespace metal;\\n\"\n    \"\\n\"\n    \"struct Uniforms {\\n\"\n    \"    float4x4 projectionMatrix;\\n\"\n    \"};\\n\"\n    \"\\n\"\n    \"struct VertexIn {\\n\"\n    \"    float2 position  [[attribute(0)]];\\n\"\n    \"    float2 texCoords [[attribute(1)]];\\n\"\n    \"    uchar4 color     [[attribute(2)]];\\n\"\n    \"};\\n\"\n    \"\\n\"\n    \"struct VertexOut {\\n\"\n    \"    float4 position [[position]];\\n\"\n    \"    float2 texCoords;\\n\"\n    \"    float4 color;\\n\"\n    \"};\\n\"\n    \"\\n\"\n    \"vertex VertexOut vertex_main(VertexIn in                 [[stage_in]],\\n\"\n    \"                             constant Uniforms &uniforms [[buffer(1)]]) {\\n\"\n    \"    VertexOut out;\\n\"\n    \"    out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);\\n\"\n    \"    out.texCoords = in.texCoords;\\n\"\n    \"    out.color = float4(in.color) / float4(255.0);\\n\"\n    \"    return out;\\n\"\n    \"}\\n\"\n    \"\\n\"\n    \"fragment half4 fragment_main(VertexOut in [[stage_in]],\\n\"\n    \"                             texture2d<half, access::sample> texture [[texture(0)]]) {\\n\"\n    \"    constexpr sampler linearSampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear);\\n\"\n    \"    half4 texColor = texture.sample(linearSampler, in.texCoords);\\n\"\n    \"    return half4(in.color) * texColor;\\n\"\n    \"}\\n\";\n\n    id<MTLLibrary> library = [device newLibraryWithSource:shaderSource options:nil error:&error];\n    if (library == nil)\n    {\n        NSLog(@\"Error: failed to create Metal library: %@\", error);\n        return nil;\n    }\n\n    id<MTLFunction> vertexFunction = [library newFunctionWithName:@\"vertex_main\"];\n    id<MTLFunction> fragmentFunction = [library newFunctionWithName:@\"fragment_main\"];\n\n    if (vertexFunction == nil || fragmentFunction == nil)\n    {\n        NSLog(@\"Error: failed to find Metal shader functions in library: %@\", error);\n        return nil;\n    }\n\n    MTLVertexDescriptor* vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];\n    vertexDescriptor.attributes[0].offset = IM_OFFSETOF(ImDrawVert, pos);\n    vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position\n    vertexDescriptor.attributes[0].bufferIndex = 0;\n    vertexDescriptor.attributes[1].offset = IM_OFFSETOF(ImDrawVert, uv);\n    vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; // texCoords\n    vertexDescriptor.attributes[1].bufferIndex = 0;\n    vertexDescriptor.attributes[2].offset = IM_OFFSETOF(ImDrawVert, col);\n    vertexDescriptor.attributes[2].format = MTLVertexFormatUChar4; // color\n    vertexDescriptor.attributes[2].bufferIndex = 0;\n    vertexDescriptor.layouts[0].stepRate = 1;\n    vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;\n    vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert);\n\n    MTLRenderPipelineDescriptor* pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];\n    pipelineDescriptor.vertexFunction = vertexFunction;\n    pipelineDescriptor.fragmentFunction = fragmentFunction;\n    pipelineDescriptor.vertexDescriptor = vertexDescriptor;\n    pipelineDescriptor.rasterSampleCount = self.framebufferDescriptor.sampleCount;\n    pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat;\n    pipelineDescriptor.colorAttachments[0].blendingEnabled = YES;\n    pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;\n    pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;\n    pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;\n    pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;\n    pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;\n    pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;\n    pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat;\n    pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;\n\n    id<MTLRenderPipelineState> renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];\n    if (error != nil)\n        NSLog(@\"Error: failed to create Metal pipeline state: %@\", error);\n\n    return renderPipelineState;\n}\n\n@end\n"
  },
  {
    "path": "src/imgui/imgui_impl_opengl3.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 in imgui.cpp.\n//  [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bits 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//  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#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)\n#define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#include \"imgui.h\"\n#include \"imgui_impl_opengl3.h\"\n#include <stdio.h>\n#include \"Common/GLInclude/GLInclude.h\"\n#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier\n#include <stddef.h>     // intptr_t\n#else\n#include <stdint.h>     // intptr_t\n#endif\n#if defined(__APPLE__)\n#include \"TargetConditionals.h\"\n#endif\n\n// Auto-detect GL version\n#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)\n#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))\n#define IMGUI_IMPL_OPENGL_ES3           // iOS, Android  -> GL ES 3, \"#version 300 es\"\n#undef IMGUI_IMPL_OPENGL_LOADER_GL3W\n#undef IMGUI_IMPL_OPENGL_LOADER_GLEW\n#undef IMGUI_IMPL_OPENGL_LOADER_GLAD\n#undef IMGUI_IMPL_OPENGL_LOADER_CUSTOM\n#elif defined(__EMSCRIPTEN__)\n#define IMGUI_IMPL_OPENGL_ES2           // Emscripten    -> GL ES 2, \"#version 100\"\n#undef IMGUI_IMPL_OPENGL_LOADER_GL3W\n#undef IMGUI_IMPL_OPENGL_LOADER_GLEW\n#undef IMGUI_IMPL_OPENGL_LOADER_GLAD\n#undef IMGUI_IMPL_OPENGL_LOADER_CUSTOM\n#endif\n#endif\n\n// GL includes\n#if defined(IMGUI_IMPL_OPENGL_ES2)\n#include <GLES2/gl2.h>\n#elif defined(IMGUI_IMPL_OPENGL_ES3)\n#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))\n#include <OpenGLES/ES3/gl.h>  // Use GL ES 3\n#else\n#include <GLES3/gl3.h>  // Use GL ES 3\n#endif\n#else\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#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)\n#include <GL/gl3w.h>    // Needs to be initialized with gl3wInit() in user's code\n#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)\n#include <GL/glew.h>    // Needs to be initialized with glewInit() in user's code\n#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)\n#include <glad/glad.h>  // Needs to be initialized with gladLoadGL() in user's code\n#else\n//#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM\"glext.h\"\"glext.h\"\n#endif\n#endif\n\n// Desktop GL has glDrawElementsBaseVertex() which GL ES and WebGL don't have.\n#if defined(IMGUI_IMPL_OPENGL_ES2) || defined(IMGUI_IMPL_OPENGL_ES3)\n#define IMGUI_IMPL_OPENGL_HAS_DRAW_WITH_BASE_VERTEX     0\n#else\n#define IMGUI_IMPL_OPENGL_HAS_DRAW_WITH_BASE_VERTEX     1\n#endif\n\n// OpenGL Data\nstatic char         g_GlslVersionString[32] = \"\";\nstatic GLuint       g_FontTexture = 0;\nstatic GLuint       g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;\nstatic int          g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;                                // Uniforms location\nstatic int          g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location\nstatic unsigned int g_VboHandle = 0, g_ElementsHandle = 0;\n\n// Functions\nbool    ImGui_ImplOpenGL3_Init(const char* glsl_version)\n{\n\t// Setup back-end capabilities flags\n\tImGuiIO& io = ImGui::GetIO();\n\tio.BackendRendererName = \"imgui_impl_opengl3\";\n#if IMGUI_IMPL_OPENGL_HAS_DRAW_WITH_BASE_VERTEX\n\tio.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.\n#endif\n\n\t// Store GLSL version string so we can refer to it later in case we recreate shaders. Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.\n#if defined(IMGUI_IMPL_OPENGL_ES2)\n\tif (glsl_version == NULL)\n\t\tglsl_version = \"#version 100\";\n#elif defined(IMGUI_IMPL_OPENGL_ES3)\n\tif (glsl_version == NULL)\n\t\tglsl_version = \"#version 300 es\";\n#else\n\tif (glsl_version == NULL)\n\t\tglsl_version = \"#version 130\";\n#endif\n\tIM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));\n\tstrcpy(g_GlslVersionString, glsl_version);\n\tstrcat(g_GlslVersionString, \"\\n\");\n\n\t// Dummy construct to make it easily visible in the IDE and debugger which GL loader has been selected. \n\t// The code actually never uses the 'gl_loader' variable! It is only here so you can read it!\n\t// If auto-detection fails or doesn't select the same GL loader file as used by your application, \n\t// you are likely to get a crash below.\n\t// You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.\n\tconst char* gl_loader = \"Unknown\";\n\tIM_UNUSED(gl_loader);\n#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)\n\tgl_loader = \"GL3W\";\n#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)\n\tgl_loader = \"GLEW\";\n#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)\n\tgl_loader = \"GLAD\";\n#else // IMGUI_IMPL_OPENGL_LOADER_CUSTOM\n\tgl_loader = \"Custom\";\n#endif\n\n\t// Make a dummy GL call (we don't actually need the result)\n\t// IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.\n\t// Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.\n\tGLint current_texture;\n\tglGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);\n\n\treturn true;\n}\n\nvoid    ImGui_ImplOpenGL3_Shutdown()\n{\n\tImGui_ImplOpenGL3_DestroyDeviceObjects();\n}\n\nvoid    ImGui_ImplOpenGL3_NewFrame()\n{\n\tif (!g_ShaderHandle)\n\t\tImGui_ImplOpenGL3_CreateDeviceObjects();\n\t\n\tif(g_FontTexture == 0)\n\t\tImGui_ImplOpenGL3_CreateFontsTexture();\n}\n\nstatic void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)\n{\n\t// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill\n\tglEnablei(GL_BLEND, 0);\n\tglBlendEquationSeparatei(0, GL_FUNC_ADD, GL_FUNC_ADD);\n\tglBlendFuncSeparatei(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\tglDisable(GL_CULL_FACE);\n\tglDisable(GL_DEPTH_TEST);\n\tglEnable(GL_SCISSOR_TEST);\n#ifdef GL_POLYGON_MODE\n\tglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n#endif\n\n\t// Setup viewport, orthographic projection matrix\n\t// 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\tglViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);\n\tfloat L = draw_data->DisplayPos.x;\n\tfloat R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;\n\tfloat T = draw_data->DisplayPos.y;\n\tfloat B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;\n\tconst float ortho_projection[4][4] =\n\t{\n\t\t{ 2.0f / (R - L),   0.0f,         0.0f,   0.0f },\n\t\t{ 0.0f,         2.0f / (T - B),   0.0f,   0.0f },\n\t\t{ 0.0f,         0.0f,        -1.0f,   0.0f },\n\t\t{ (R + L) / (L - R),  (T + B) / (B - T),  0.0f,   1.0f },\n\t};\n\tglUseProgram(g_ShaderHandle);\n\tglUniform1i(g_AttribLocationTex, 0);\n\tglUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);\n#ifdef GL_SAMPLER_BINDING\n\tglBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.\n#endif\n\n\t(void)vertex_array_object;\n#ifndef IMGUI_IMPL_OPENGL_ES2\n\tglBindVertexArray(vertex_array_object);\n#endif\n\n\t// Bind vertex/index buffers and setup attributes for ImDrawVert\n\tglBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);\n\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);\n\tglEnableVertexAttribArray(g_AttribLocationVtxPos);\n\tglEnableVertexAttribArray(g_AttribLocationVtxUV);\n\tglEnableVertexAttribArray(g_AttribLocationVtxColor);\n\tglVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));\n\tglVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));\n\tglVertexAttribPointer(g_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\t// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)\n\tint fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);\n\tint fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);\n\tif (fb_width <= 0 || fb_height <= 0)\n\t\treturn;\n\n\t// Backup GL state\n\tGLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);\n\tglActiveTexture(GL_TEXTURE0);\n\tGLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);\n\tGLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);\n#ifdef GL_SAMPLER_BINDING\n\tGLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler);\n#endif\n\tGLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);\n#ifndef IMGUI_IMPL_OPENGL_ES2\n\tGLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object);\n#endif\n#ifdef GL_POLYGON_MODE\n\tGLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);\n#endif\n\tGLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);\n\tGLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);\n\t//GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);\n\t//GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);\n\t//GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);\n\t//GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);\n\t//GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);\n\t//GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);\n\t//GLboolean last_enable_blend = false; glIsEnabled(GL_BLEND);\n\tGLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);\n\tGLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);\n\tGLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);\n\tbool clip_origin_lower_left = true;\n#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__)\n\tGLenum last_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)\n\tif (last_clip_origin == GL_UPPER_LEFT)\n\t\tclip_origin_lower_left = false;\n#endif\n\n\t// Setup desired GL state\n\t// 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\t// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.\n\tGLuint vertex_array_object = 0;\n#ifndef IMGUI_IMPL_OPENGL_ES2\n\tglGenVertexArrays(1, &vertex_array_object);\n#endif\n\tImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);\n\n\t// Will project scissor/clipping rectangles into framebuffer space\n\tImVec2 clip_off = draw_data->DisplayPos;         // (0,0) unless using multi-viewports\n\tImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)\n\n\t// Render command lists\n\tfor (int n = 0; n < draw_data->CmdListsCount; n++)\n\t{\n\t\tconst ImDrawList* cmd_list = draw_data->CmdLists[n];\n\n\t\t// Upload vertex/index buffers\n\t\tglBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);\n\t\tglBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);\n\n\t\tfor (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)\n\t\t{\n\t\t\tconst ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];\n\t\t\tif (pcmd->UserCallback != NULL)\n\t\t\t{\n\t\t\t\t// User callback, registered via ImDrawList::AddCallback()\n\t\t\t\t// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)\n\t\t\t\tif (pcmd->UserCallback == ImDrawCallback_ResetRenderState)\n\t\t\t\t\tImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);\n\t\t\t\telse\n\t\t\t\t\tpcmd->UserCallback(cmd_list, pcmd);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Project scissor/clipping rectangles into framebuffer space\n\t\t\t\tImVec4 clip_rect;\n\t\t\t\tclip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;\n\t\t\t\tclip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;\n\t\t\t\tclip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;\n\t\t\t\tclip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;\n\n\t\t\t\tif (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)\n\t\t\t\t{\n\t\t\t\t\t// Apply scissor/clipping rectangle\n\t\t\t\t\tif (clip_origin_lower_left)\n\t\t\t\t\t\tglScissor((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\t\t\t\t\telse\n\t\t\t\t\t\tglScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)\n\n\t\t\t\t\t// Bind texture, Draw\n\t\t\t\t\tglBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);\n#if IMGUI_IMPL_OPENGL_HAS_DRAW_WITH_BASE_VERTEX\n\t\t\t\t\tglDrawElementsBaseVertex(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\t\t\t\t\tglDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));\n#endif\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Destroy the temporary VAO\n#ifndef IMGUI_IMPL_OPENGL_ES2\n\tglDeleteVertexArrays(1, &vertex_array_object);\n#endif\n\n\t// Restore modified GL state\n\tglUseProgram(last_program);\n\tglBindTexture(GL_TEXTURE_2D, last_texture);\n#ifdef GL_SAMPLER_BINDING\n\tglBindSampler(0, last_sampler);\n#endif\n\tglActiveTexture(last_active_texture);\n#ifndef IMGUI_IMPL_OPENGL_ES2\n\tglBindVertexArray(last_vertex_array_object);\n#endif\n\tglBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);\n\t//glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);\n\t//glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);\n\t//if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);\n\tglDisablei(GL_BLEND, 0);\n\tif (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);\n\tif (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);\n\tif (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);\n#ifdef GL_POLYGON_MODE\n\tglPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);\n#endif\n\tglViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);\n\tglScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);\n}\n\nbool ImGui_ImplOpenGL3_CreateFontsTexture()\n{\n\tif (g_FontTexture != 0) // already created\n\t\treturn false;\n\t\n\t// Build texture atlas\n\tImGuiIO& io = ImGui::GetIO();\n\tunsigned char* pixels;\n\tint width, height;\n\tio.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);   // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.\n\n\t// Upload texture to graphics system\n\tGLint last_texture;\n\tglGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);\n\tglGenTextures(1, &g_FontTexture);\n\tglBindTexture(GL_TEXTURE_2D, g_FontTexture);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n#ifdef GL_UNPACK_ROW_LENGTH\n\tglPixelStorei(GL_UNPACK_ROW_LENGTH, 0);\n#endif\n\tglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);\n\n\t// Store our identifier\n\tio.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture;\n\n\t// Restore state\n\tglBindTexture(GL_TEXTURE_2D, last_texture);\n\n\treturn true;\n}\n\nvoid ImGui_ImplOpenGL3_DestroyFontsTexture()\n{\n\tif (g_FontTexture)\n\t{\n\t\tImGuiIO& io = ImGui::GetIO();\n\t\tglDeleteTextures(1, &g_FontTexture);\n\t\tio.Fonts->TexID = 0;\n\t\tg_FontTexture = 0;\n\t}\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\tGLint status = 0, log_length = 0;\n\tglGetShaderiv(handle, GL_COMPILE_STATUS, &status);\n\tglGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);\n\tif ((GLboolean)status == GL_FALSE)\n\t\tfprintf(stderr, \"ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\\n\", desc);\n\tif (log_length > 1)\n\t{\n\t\tImVector<char> buf;\n\t\tbuf.resize((int)(log_length + 1));\n\t\tglGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());\n\t\tfprintf(stderr, \"%s\\n\", buf.begin());\n\t}\n\treturn (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\tGLint status = 0, log_length = 0;\n\tglGetProgramiv(handle, GL_LINK_STATUS, &status);\n\tglGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);\n\tif ((GLboolean)status == GL_FALSE)\n\t\tfprintf(stderr, \"ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\\n\", desc, g_GlslVersionString);\n\tif (log_length > 1)\n\t{\n\t\tImVector<char> buf;\n\t\tbuf.resize((int)(log_length + 1));\n\t\tglGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin());\n\t\tfprintf(stderr, \"%s\\n\", buf.begin());\n\t}\n\treturn (GLboolean)status == GL_TRUE;\n}\n\nbool    ImGui_ImplOpenGL3_CreateDeviceObjects()\n{\n\t// Backup GL state\n\tGLint last_texture, last_array_buffer;\n\tglGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);\n\tglGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);\n#ifndef IMGUI_IMPL_OPENGL_ES2\n\tGLint last_vertex_array;\n\tglGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);\n#endif\n\n\t// Parse GLSL version string\n\tint glsl_version = 130;\n\tsscanf(g_GlslVersionString, \"#version %d\", &glsl_version);\n\n\tconst GLchar* vertex_shader_glsl_120 =\n\t\t\"uniform mat4 ProjMtx;\\n\"\n\t\t\"attribute vec2 Position;\\n\"\n\t\t\"attribute vec2 UV;\\n\"\n\t\t\"attribute vec4 Color;\\n\"\n\t\t\"varying vec2 Frag_UV;\\n\"\n\t\t\"varying vec4 Frag_Color;\\n\"\n\t\t\"void main()\\n\"\n\t\t\"{\\n\"\n\t\t\"    Frag_UV = UV;\\n\"\n\t\t\"    Frag_Color = Color;\\n\"\n\t\t\"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n\t\t\"}\\n\";\n\n\tconst GLchar* vertex_shader_glsl_130 =\n\t\t\"uniform mat4 ProjMtx;\\n\"\n\t\t\"in vec2 Position;\\n\"\n\t\t\"in vec2 UV;\\n\"\n\t\t\"in vec4 Color;\\n\"\n\t\t\"out vec2 Frag_UV;\\n\"\n\t\t\"out vec4 Frag_Color;\\n\"\n\t\t\"void main()\\n\"\n\t\t\"{\\n\"\n\t\t\"    Frag_UV = UV;\\n\"\n\t\t\"    Frag_Color = Color;\\n\"\n\t\t\"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n\t\t\"}\\n\";\n\n\tconst GLchar* vertex_shader_glsl_300_es =\n\t\t\"precision mediump float;\\n\"\n\t\t\"layout (location = 0) in vec2 Position;\\n\"\n\t\t\"layout (location = 1) in vec2 UV;\\n\"\n\t\t\"layout (location = 2) in vec4 Color;\\n\"\n\t\t\"uniform mat4 ProjMtx;\\n\"\n\t\t\"out vec2 Frag_UV;\\n\"\n\t\t\"out vec4 Frag_Color;\\n\"\n\t\t\"void main()\\n\"\n\t\t\"{\\n\"\n\t\t\"    Frag_UV = UV;\\n\"\n\t\t\"    Frag_Color = Color;\\n\"\n\t\t\"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n\t\t\"}\\n\";\n\n\tconst GLchar* vertex_shader_glsl_410_core =\n\t\t\"layout (location = 0) in vec2 Position;\\n\"\n\t\t\"layout (location = 1) in vec2 UV;\\n\"\n\t\t\"layout (location = 2) in vec4 Color;\\n\"\n\t\t\"uniform mat4 ProjMtx;\\n\"\n\t\t\"out vec2 Frag_UV;\\n\"\n\t\t\"out vec4 Frag_Color;\\n\"\n\t\t\"void main()\\n\"\n\t\t\"{\\n\"\n\t\t\"    Frag_UV = UV;\\n\"\n\t\t\"    Frag_Color = Color;\\n\"\n\t\t\"    gl_Position = ProjMtx * vec4(Position.xy,0,1);\\n\"\n\t\t\"}\\n\";\n\n\tconst GLchar* fragment_shader_glsl_120 =\n\t\t\"#ifdef GL_ES\\n\"\n\t\t\"    precision mediump float;\\n\"\n\t\t\"#endif\\n\"\n\t\t\"uniform sampler2D Texture;\\n\"\n\t\t\"varying vec2 Frag_UV;\\n\"\n\t\t\"varying vec4 Frag_Color;\\n\"\n\t\t\"void main()\\n\"\n\t\t\"{\\n\"\n\t\t\"    gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\\n\"\n\t\t\"}\\n\";\n\n\tconst GLchar* fragment_shader_glsl_130 =\n\t\t\"uniform sampler2D Texture;\\n\"\n\t\t\"in vec2 Frag_UV;\\n\"\n\t\t\"in vec4 Frag_Color;\\n\"\n\t\t\"out vec4 Out_Color;\\n\"\n\t\t\"void main()\\n\"\n\t\t\"{\\n\"\n\t\t\"    Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n\t\t\"}\\n\";\n\n\tconst GLchar* fragment_shader_glsl_300_es =\n\t\t\"precision mediump float;\\n\"\n\t\t\"uniform sampler2D Texture;\\n\"\n\t\t\"in vec2 Frag_UV;\\n\"\n\t\t\"in vec4 Frag_Color;\\n\"\n\t\t\"layout (location = 0) out vec4 Out_Color;\\n\"\n\t\t\"void main()\\n\"\n\t\t\"{\\n\"\n\t\t\"    Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n\t\t\"}\\n\";\n\n\tconst GLchar* fragment_shader_glsl_410_core =\n\t\t\"in vec2 Frag_UV;\\n\"\n\t\t\"in vec4 Frag_Color;\\n\"\n\t\t\"uniform sampler2D Texture;\\n\"\n\t\t\"layout (location = 0) out vec4 Out_Color;\\n\"\n\t\t\"void main()\\n\"\n\t\t\"{\\n\"\n\t\t\"    Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n\t\t\"}\\n\";\n\n\t// Select shaders matching our GLSL versions\n\tconst GLchar* vertex_shader = NULL;\n\tconst GLchar* fragment_shader = NULL;\n\tif (glsl_version < 130)\n\t{\n\t\tvertex_shader = vertex_shader_glsl_120;\n\t\tfragment_shader = fragment_shader_glsl_120;\n\t}\n\telse if (glsl_version >= 410)\n\t{\n\t\tvertex_shader = vertex_shader_glsl_410_core;\n\t\tfragment_shader = fragment_shader_glsl_410_core;\n\t}\n\telse if (glsl_version == 300)\n\t{\n\t\tvertex_shader = vertex_shader_glsl_300_es;\n\t\tfragment_shader = fragment_shader_glsl_300_es;\n\t}\n\telse\n\t{\n\t\tvertex_shader = vertex_shader_glsl_130;\n\t\tfragment_shader = fragment_shader_glsl_130;\n\t}\n\n\t// Create shaders\n\tconst GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader };\n\tg_VertHandle = glCreateShader(GL_VERTEX_SHADER);\n\tglShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);\n\tglCompileShader(g_VertHandle);\n\tCheckShader(g_VertHandle, \"vertex shader\");\n\n\tconst GLchar* fragment_shader_with_version[2] = { g_GlslVersionString, fragment_shader };\n\tg_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);\n\tglShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);\n\tglCompileShader(g_FragHandle);\n\tCheckShader(g_FragHandle, \"fragment shader\");\n\n\tg_ShaderHandle = glCreateProgram();\n\tglAttachShader(g_ShaderHandle, g_VertHandle);\n\tglAttachShader(g_ShaderHandle, g_FragHandle);\n\tglLinkProgram(g_ShaderHandle);\n\tCheckProgram(g_ShaderHandle, \"shader program\");\n\n\tg_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, \"Texture\");\n\tg_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, \"ProjMtx\");\n\tg_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, \"Position\");\n\tg_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, \"UV\");\n\tg_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, \"Color\");\n\n\t// Create buffers\n\tglGenBuffers(1, &g_VboHandle);\n\tglGenBuffers(1, &g_ElementsHandle);\n\n\tImGui_ImplOpenGL3_CreateFontsTexture();\n\n\t// Restore modified GL state\n\tglBindTexture(GL_TEXTURE_2D, last_texture);\n\tglBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);\n#ifndef IMGUI_IMPL_OPENGL_ES2\n\tglBindVertexArray(last_vertex_array);\n#endif\n\n\treturn true;\n}\n\nvoid    ImGui_ImplOpenGL3_DestroyDeviceObjects()\n{\n\tif (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }\n\tif (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }\n\tif (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }\n\tif (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }\n\tif (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; }\n\tif (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; }\n\tif (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }\n\n\tImGui_ImplOpenGL3_DestroyFontsTexture();\n}\n"
  },
  {
    "path": "src/imgui/imgui_impl_opengl3.h",
    "content": "// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline\n// - Desktop GL: 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 in imgui.cpp.\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\n// Specific OpenGL versions\n//#define IMGUI_IMPL_OPENGL_ES2     // Auto-detected on Emscripten\n//#define IMGUI_IMPL_OPENGL_ES3     // Auto-detected on iOS/Android\n\n#include \"imgui.h\"\n\n#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM \"glext.h\"\n#include \"Common/GLInclude/GLInclude.h\"\n\n// Set default OpenGL3 loader to be gl3w\n#if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)     \\\n && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)     \\\n && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)     \\\n && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)\n#define IMGUI_IMPL_OPENGL_LOADER_GL3W\n#endif\n\n#undef IMGUI_IMPL_OPENGL_LOADER_GL3W\n\nIMGUI_IMPL_API bool     ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_Shutdown();\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_NewFrame();\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);\n\n// Called by Init/NewFrame/Shutdown\nIMGUI_IMPL_API bool     ImGui_ImplOpenGL3_CreateFontsTexture();\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_DestroyFontsTexture();\nIMGUI_IMPL_API bool     ImGui_ImplOpenGL3_CreateDeviceObjects();\nIMGUI_IMPL_API void     ImGui_ImplOpenGL3_DestroyDeviceObjects();\n"
  },
  {
    "path": "src/imgui/imgui_impl_vulkan.cpp",
    "content": "// dear imgui: Renderer for Vulkan\n// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)\n\n// Implemented features:\n//  [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.\n// In this binding, ImTextureID is used to store a 'VkDescriptorSet' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.\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// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.\n// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/\n\n// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.\n// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.\n//   You will use those if you want to use this rendering back-end in your engine/app.\n// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by \n//   the back-end itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.\n// Read comments in imgui_impl_vulkan.h.\n\n// CHANGELOG\n// (minor and older changes stripped away, please see git history for details)\n//  2019-05-29: Vulkan: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.\n//  2019-04-30: Vulkan: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.\n//  2019-04-04: *BREAKING CHANGE*: Vulkan: Added ImageCount/MinImageCount fields in ImGui_ImplVulkan_InitInfo, required for initialization (was previously a hard #define IMGUI_VK_QUEUED_FRAMES 2). Added ImGui_ImplVulkan_SetMinImageCount().\n//  2019-04-04: Vulkan: Added VkInstance argument to ImGui_ImplVulkanH_CreateWindow() optional helper.\n//  2019-04-04: Vulkan: Avoid passing negative coordinates to vkCmdSetScissor, which debug validation layers do not like.\n//  2019-04-01: Vulkan: Support for 32-bit index buffer (#define ImDrawIdx unsigned int).\n//  2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display.\n//  2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.\n//  2018-08-25: Vulkan: Fixed mishandled VkSurfaceCapabilitiesKHR::maxImageCount=0 case.\n//  2018-06-22: Inverted the parameters to ImGui_ImplVulkan_RenderDrawData() to be consistent with other bindings.\n//  2018-06-08: Misc: Extracted imgui_impl_vulkan.cpp/.h away from the old combined GLFW+Vulkan example.\n//  2018-06-08: Vulkan: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.\n//  2018-03-03: Vulkan: Various refactor, created a couple of ImGui_ImplVulkanH_XXX helper that the example can use and that viewport support will use.\n//  2018-03-01: Vulkan: Renamed ImGui_ImplVulkan_Init_Info to ImGui_ImplVulkan_InitInfo and fields to match more closely Vulkan terminology.\n//  2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback, ImGui_ImplVulkan_Render() calls ImGui_ImplVulkan_RenderDrawData() itself.\n//  2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.\n//  2017-05-15: Vulkan: Fix scissor offset being negative. Fix new Vulkan validation warnings. Set required depth member for buffer image copy.\n//  2016-11-13: Vulkan: Fix validation layer warnings and errors and redeclare gl_PerVertex.\n//  2016-10-18: Vulkan: Add location decorators & change to use structs as in/out in glsl, update embedded spv (produced with glslangValidator -x). Null the released resources.\n//  2016-08-27: Vulkan: Fix Vulkan example for use when a depth buffer is active.\n\n#include \"imgui.h\"\n#include \"imgui_impl_vulkan.h\"\n#include <stdio.h>\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h\"\n\n\n// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()\n// [Please zero-clear before use!]\nstruct ImGui_ImplVulkanH_FrameRenderBuffers\n{\n    VkDeviceMemory      VertexBufferMemory;\n    VkDeviceMemory      IndexBufferMemory;\n    VkDeviceSize        VertexBufferSize;\n    VkDeviceSize        IndexBufferSize;\n    VkBuffer            VertexBuffer;\n    VkBuffer            IndexBuffer;\n};\n\n// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers\n// [Please zero-clear before use!]\nstruct ImGui_ImplVulkanH_WindowRenderBuffers\n{\n    uint32_t            Index;\n    uint32_t            Count;\n    ImGui_ImplVulkanH_FrameRenderBuffers*   FrameRenderBuffers;\n};\n\n// Vulkan data\nstatic ImGui_ImplVulkan_InitInfo g_VulkanInitInfo = {};\nstatic VkRenderPass             g_RenderPass = VK_NULL_HANDLE;\nstatic VkDeviceSize             g_BufferMemoryAlignment = 256;\nstatic VkPipelineCreateFlags    g_PipelineCreateFlags = 0x00;\nstatic VkDescriptorSetLayout    g_DescriptorSetLayout = VK_NULL_HANDLE;\nstatic VkPipelineLayout         g_PipelineLayout = VK_NULL_HANDLE;\n// static VkDescriptorSet          g_DescriptorSet = VK_NULL_HANDLE;\nstatic VkPipeline               g_Pipeline = VK_NULL_HANDLE;\n\n// Font data\nstatic VkSampler                g_FontSampler = VK_NULL_HANDLE;\nstatic VkDeviceMemory           g_FontMemory = VK_NULL_HANDLE;\nstatic VkImage                  g_FontImage = VK_NULL_HANDLE;\nstatic VkImageView              g_FontView = VK_NULL_HANDLE;\nstatic VkDeviceMemory           g_UploadBufferMemory = VK_NULL_HANDLE;\nstatic VkBuffer                 g_UploadBuffer = VK_NULL_HANDLE;\n\n// Render buffers\nstatic ImGui_ImplVulkanH_WindowRenderBuffers    g_MainWindowRenderBuffers;\n\n// Forward Declarations\nbool ImGui_ImplVulkan_CreateDeviceObjects();\nvoid ImGui_ImplVulkan_DestroyDeviceObjects();\nvoid ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);\nvoid ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);\nvoid ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);\nvoid ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);\nvoid ImGui_ImplVulkanH_CreateWindowSwapchain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);\nvoid ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);\n\nstruct ImGuiTexture\n{\n    VkImage image;\n    VkDeviceMemory memory;\n    VkImageView view;\n    VkSampler sampler;\n    VkDescriptorSet descriptor_set;\n    VkBuffer uploadBuffer;\n    VkDeviceMemory uploadBufferMemory;\n};\n\n\n//-----------------------------------------------------------------------------\n// SHADERS\n//-----------------------------------------------------------------------------\n\n// glsl_shader.vert, compiled with:\n// # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert\n/*\n#version 450 core\nlayout(location = 0) in vec2 aPos;\nlayout(location = 1) in vec2 aUV;\nlayout(location = 2) in vec4 aColor;\nlayout(push_constant) uniform uPushConstant { vec2 uScale; vec2 uTranslate; } pc;\n\nout gl_PerVertex { vec4 gl_Position; };\nlayout(location = 0) out struct { vec4 Color; vec2 UV; } 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*/\nstatic uint32_t __glsl_shader_vert_spv[] =\n{\n    0x07230203,0x00010000,0x00080001,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b,\n    0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,\n    0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015,\n    0x0000001b,0x0000001c,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,\n    0x00000000,0x00030005,0x00000009,0x00000000,0x00050006,0x00000009,0x00000000,0x6f6c6f43,\n    0x00000072,0x00040006,0x00000009,0x00000001,0x00005655,0x00030005,0x0000000b,0x0074754f,\n    0x00040005,0x0000000f,0x6c6f4361,0x0000726f,0x00030005,0x00000015,0x00565561,0x00060005,\n    0x00000019,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x00000019,0x00000000,\n    0x505f6c67,0x7469736f,0x006e6f69,0x00030005,0x0000001b,0x00000000,0x00040005,0x0000001c,\n    0x736f5061,0x00000000,0x00060005,0x0000001e,0x73755075,0x6e6f4368,0x6e617473,0x00000074,\n    0x00050006,0x0000001e,0x00000000,0x61635375,0x0000656c,0x00060006,0x0000001e,0x00000001,\n    0x61725475,0x616c736e,0x00006574,0x00030005,0x00000020,0x00006370,0x00040047,0x0000000b,\n    0x0000001e,0x00000000,0x00040047,0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015,\n    0x0000001e,0x00000001,0x00050048,0x00000019,0x00000000,0x0000000b,0x00000000,0x00030047,\n    0x00000019,0x00000002,0x00040047,0x0000001c,0x0000001e,0x00000000,0x00050048,0x0000001e,\n    0x00000000,0x00000023,0x00000000,0x00050048,0x0000001e,0x00000001,0x00000023,0x00000008,\n    0x00030047,0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,\n    0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040017,\n    0x00000008,0x00000006,0x00000002,0x0004001e,0x00000009,0x00000007,0x00000008,0x00040020,\n    0x0000000a,0x00000003,0x00000009,0x0004003b,0x0000000a,0x0000000b,0x00000003,0x00040015,\n    0x0000000c,0x00000020,0x00000001,0x0004002b,0x0000000c,0x0000000d,0x00000000,0x00040020,\n    0x0000000e,0x00000001,0x00000007,0x0004003b,0x0000000e,0x0000000f,0x00000001,0x00040020,\n    0x00000011,0x00000003,0x00000007,0x0004002b,0x0000000c,0x00000013,0x00000001,0x00040020,\n    0x00000014,0x00000001,0x00000008,0x0004003b,0x00000014,0x00000015,0x00000001,0x00040020,\n    0x00000017,0x00000003,0x00000008,0x0003001e,0x00000019,0x00000007,0x00040020,0x0000001a,\n    0x00000003,0x00000019,0x0004003b,0x0000001a,0x0000001b,0x00000003,0x0004003b,0x00000014,\n    0x0000001c,0x00000001,0x0004001e,0x0000001e,0x00000008,0x00000008,0x00040020,0x0000001f,\n    0x00000009,0x0000001e,0x0004003b,0x0000001f,0x00000020,0x00000009,0x00040020,0x00000021,\n    0x00000009,0x00000008,0x0004002b,0x00000006,0x00000028,0x00000000,0x0004002b,0x00000006,\n    0x00000029,0x3f800000,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,\n    0x00000005,0x0004003d,0x00000007,0x00000010,0x0000000f,0x00050041,0x00000011,0x00000012,\n    0x0000000b,0x0000000d,0x0003003e,0x00000012,0x00000010,0x0004003d,0x00000008,0x00000016,\n    0x00000015,0x00050041,0x00000017,0x00000018,0x0000000b,0x00000013,0x0003003e,0x00000018,\n    0x00000016,0x0004003d,0x00000008,0x0000001d,0x0000001c,0x00050041,0x00000021,0x00000022,\n    0x00000020,0x0000000d,0x0004003d,0x00000008,0x00000023,0x00000022,0x00050085,0x00000008,\n    0x00000024,0x0000001d,0x00000023,0x00050041,0x00000021,0x00000025,0x00000020,0x00000013,\n    0x0004003d,0x00000008,0x00000026,0x00000025,0x00050081,0x00000008,0x00000027,0x00000024,\n    0x00000026,0x00050051,0x00000006,0x0000002a,0x00000027,0x00000000,0x00050051,0x00000006,\n    0x0000002b,0x00000027,0x00000001,0x00070050,0x00000007,0x0000002c,0x0000002a,0x0000002b,\n    0x00000028,0x00000029,0x00050041,0x00000011,0x0000002d,0x0000001b,0x0000000d,0x0003003e,\n    0x0000002d,0x0000002c,0x000100fd,0x00010038\n};\n\n// glsl_shader.frag, compiled with:\n// # glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag\n/*\n#version 450 core\nlayout(location = 0) out vec4 fColor;\nlayout(set=0, binding=0) uniform sampler2D sTexture;\nlayout(location = 0) in struct { vec4 Color; vec2 UV; } In;\nvoid main()\n{\n    fColor = In.Color * texture(sTexture, In.UV.st);\n}\n*/\nstatic uint32_t __glsl_shader_frag_spv[] =\n{\n    0x07230203,0x00010000,0x00080001,0x0000001e,0x00000000,0x00020011,0x00000001,0x0006000b,\n    0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,\n    0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010,\n    0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,\n    0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000,\n    0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001,\n    0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000016,0x78655473,0x65727574,\n    0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e,\n    0x00000000,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021,\n    0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,\n    0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003,\n    0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,0x00000006,\n    0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,0x00000001,\n    0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,0x00000020,\n    0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,0x00000001,\n    0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,\n    0x00000001,0x00000000,0x0003001b,0x00000014,0x00000013,0x00040020,0x00000015,0x00000000,\n    0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x0004002b,0x0000000e,0x00000018,\n    0x00000001,0x00040020,0x00000019,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004,\n    0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d,\n    0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000014,0x00000017,\n    0x00000016,0x00050041,0x00000019,0x0000001a,0x0000000d,0x00000018,0x0004003d,0x0000000a,\n    0x0000001b,0x0000001a,0x00050057,0x00000007,0x0000001c,0x00000017,0x0000001b,0x00050085,\n    0x00000007,0x0000001d,0x00000012,0x0000001c,0x0003003e,0x00000009,0x0000001d,0x000100fd,\n    0x00010038\n};\n\n//-----------------------------------------------------------------------------\n// FUNCTIONS\n//-----------------------------------------------------------------------------\n\nstatic uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)\n{\n    ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;\n    VkPhysicalDeviceMemoryProperties prop;\n    vkGetPhysicalDeviceMemoryProperties(v->PhysicalDevice, &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 check_vk_result(VkResult err)\n{\n    ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;\n    if (v->CheckVkResultFn)\n        v->CheckVkResultFn(err);\n}\n\nstatic void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage)\n{\n\tImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;\n\tvkDeviceWaitIdle(v->Device); // make sure previously created buffer is not in use anymore\n    VkResult err;\n\tif (buffer != VK_NULL_HANDLE)\n\t\tvkDestroyBuffer(v->Device, buffer, v->Allocator);\n\tif (buffer_memory != VK_NULL_HANDLE)\n\t\tvkFreeMemory(v->Device, buffer_memory, v->Allocator);\n    VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / g_BufferMemoryAlignment + 1) * g_BufferMemoryAlignment;\n    VkBufferCreateInfo buffer_info = {};\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = vertex_buffer_size_aligned;\n    buffer_info.usage = usage;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n    err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer);\n    check_vk_result(err);\n\n    VkMemoryRequirements req;\n    vkGetBufferMemoryRequirements(v->Device, buffer, &req);\n    g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;\n    VkMemoryAllocateInfo alloc_info = {};\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n    alloc_info.allocationSize = req.size;\n    alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);\n    err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &buffer_memory);\n    check_vk_result(err);\n\n    err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0);\n    check_vk_result(err);\n    p_buffer_size = new_size;\n}\n\nstatic void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkCommandBuffer command_buffer, ImGui_ImplVulkanH_FrameRenderBuffers* rb, int fb_width, int fb_height)\n{\n    // Bind pipeline\n    {\n        vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_Pipeline);\n        //VkDescriptorSet desc_set[1] = { g_DescriptorSet };\n        //vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL);\n    }\n\n    // Bind Vertex And Index Buffer:\n    {\n        VkBuffer vertex_buffers[1] = { rb->VertexBuffer };\n        VkDeviceSize vertex_offset[1] = { 0 };\n        vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, vertex_offset);\n        vkCmdBindIndexBuffer(command_buffer, rb->IndexBuffer, 0, sizeof(ImDrawIdx) == 2 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32);\n    }\n\n    // Setup viewport:\n    {\n        VkViewport viewport;\n        viewport.x = 0;\n        viewport.y = 0;\n        viewport.width = (float)fb_width;\n        viewport.height = (float)fb_height;\n        viewport.minDepth = 0.0f;\n        viewport.maxDepth = 1.0f;\n        vkCmdSetViewport(command_buffer, 0, 1, &viewport);\n    }\n\n    // Setup scale and translation:\n    // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (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        vkCmdPushConstants(command_buffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale);\n        vkCmdPushConstants(command_buffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate);\n    }\n}\n\n// 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)\nvoid ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer)\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    ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;\n\n    // Allocate array to store enough vertex/index buffers\n    ImGui_ImplVulkanH_WindowRenderBuffers* wrb = &g_MainWindowRenderBuffers;\n    if (wrb->FrameRenderBuffers == NULL)\n    {\n        wrb->Index = 0;\n        wrb->Count = v->ImageCount;\n        wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);\n        memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count);\n    }\n    IM_ASSERT(wrb->Count == v->ImageCount);\n    wrb->Index = (wrb->Index + 1) % wrb->Count;\n    ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index];\n\n    VkResult err;\n\n    // Create or resize the 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 (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size)\n        CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);\n    if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size)\n        CreateOrResizeBuffer(rb->IndexBuffer, rb->IndexBufferMemory, rb->IndexBufferSize, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);\n\n    // Upload vertex/index data into a single contiguous GPU buffer\n    {\n\t\tcemu_assert_debug(vertex_size != 0);\n\t\tcemu_assert_debug(index_size != 0);\n\n\n        // todo - read and use actual nonCoherentAtomSize instead of assuming 0x80\n\t\tuint32 aligned_vertex_size = (vertex_size + 0x7F) & ~0x7F;\n\t\tuint32 aligned_index_size = (index_size + 0x7F) & ~0x7F;\n\n        ImDrawVert* vtx_dst = NULL;\n        ImDrawIdx* idx_dst = NULL;\n        err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, aligned_vertex_size, 0, (void**)(&vtx_dst));\n        check_vk_result(err);\n        err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, aligned_index_size, 0, (void**)(&idx_dst));\n        check_vk_result(err);\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 = rb->VertexBufferMemory;\n        range[0].size = VK_WHOLE_SIZE;\n        range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;\n        range[1].memory = rb->IndexBufferMemory;\n        range[1].size = VK_WHOLE_SIZE;\n        err = vkFlushMappedMemoryRanges(v->Device, 2, range);\n        check_vk_result(err);\n        vkUnmapMemory(v->Device, rb->VertexBufferMemory);\n        vkUnmapMemory(v->Device, rb->IndexBufferMemory);\n    }\n\n    // Setup desired Vulkan state\n    ImGui_ImplVulkan_SetupRenderState(draw_data, command_buffer, rb, fb_width, fb_height);\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    // Render command lists\n    // (Because we merged all buffers into a single one, we maintain our own offset into them)\n    int vtx_offset  = 0;\n    int idx_offset  = 0;\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            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_ImplVulkan_SetupRenderState(draw_data, command_buffer, rb, fb_width, fb_height);\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                    // Negative offsets are illegal for vkCmdSetScissor\n                    if (clip_rect.x < 0.0f)\n                        clip_rect.x = 0.0f;\n                    if (clip_rect.y < 0.0f)\n                        clip_rect.y = 0.0f;\n\n                    // Apply scissor/clipping rectangle\n                    VkRect2D scissor;\n                    scissor.offset.x = (int32_t)(clip_rect.x);\n                    scissor.offset.y = (int32_t)(clip_rect.y);\n                    scissor.extent.width = (uint32_t)(clip_rect.z - clip_rect.x);\n                    scissor.extent.height = (uint32_t)(clip_rect.w - clip_rect.y);\n                    vkCmdSetScissor(command_buffer, 0, 1, &scissor);\n\n                    VkDescriptorSet desc_set[1] = { ((ImGuiTexture*)pcmd->TextureId)->descriptor_set };\n                    vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, g_PipelineLayout, 0, 1, desc_set, 0, NULL);\n\n                    // Draw\n                    //vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);\n                    vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0);\n                }\n            }\n\t\t\tidx_offset += pcmd->ElemCount;\n        }\n\t\tvtx_offset += cmd_list->VtxBuffer.Size;\n       // global_idx_offset += cmd_list->IdxBuffer.Size;\n       // global_vtx_offset += cmd_list->VtxBuffer.Size;\n    }\n}\n\nvoid ImGui_ImplVulkan_DestroyFontsTexture()\n{\n\tImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;\n\tImGui_ImplVulkan_DestroyFontUploadObjects();\n\tif (g_FontView)             { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }\n    if (g_FontImage)            { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }\n    if (g_FontMemory)           { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }\n\n\tImGuiIO& io = ImGui::GetIO();\n\tauto texture = io.Fonts->TexID;\n\tif(texture != (ImTextureID)nullptr)\n\t{\n\t\tImGui_ImplVulkan_DeleteTexture(texture);\n\t\tdelete (ImGuiTexture*)texture;\n\t\tio.Fonts->TexID = nullptr;\n\t}\n}\n\nbool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)\n{\n\tif(g_FontView)\n\t\treturn true;\n\n    ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;\n    ImGuiIO& io = ImGui::GetIO();\n\n    unsigned char* pixels;\n    int width, height;\n    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);\n    size_t upload_size = width*height*4*sizeof(char);\n\n    VkResult err;\n\n    // Create the Image:\n    {\n        VkImageCreateInfo info = {};\n        info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n        info.imageType = VK_IMAGE_TYPE_2D;\n        info.format = VK_FORMAT_R8G8B8A8_UNORM;\n        info.extent.width = width;\n        info.extent.height = height;\n        info.extent.depth = 1;\n        info.mipLevels = 1;\n        info.arrayLayers = 1;\n        info.samples = VK_SAMPLE_COUNT_1_BIT;\n        info.tiling = VK_IMAGE_TILING_OPTIMAL;\n        info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;\n        info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n        info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n        err = vkCreateImage(v->Device, &info, v->Allocator, &g_FontImage);\n        check_vk_result(err);\n        VkMemoryRequirements req;\n        vkGetImageMemoryRequirements(v->Device, g_FontImage, &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 = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);\n        err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_FontMemory);\n        check_vk_result(err);\n        err = vkBindImageMemory(v->Device, g_FontImage, g_FontMemory, 0);\n        check_vk_result(err);\n    }\n\n    // Create the Image View:\n    {\n        VkImageViewCreateInfo info = {};\n        info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n        info.image = g_FontImage;\n        info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n        info.format = VK_FORMAT_R8G8B8A8_UNORM;\n        info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n        info.subresourceRange.levelCount = 1;\n        info.subresourceRange.layerCount = 1;\n        err = vkCreateImageView(v->Device, &info, v->Allocator, &g_FontView);\n        check_vk_result(err);\n    }\n\n    //// Update the Descriptor Set:\n    //{\n    //    VkDescriptorImageInfo desc_image[1] = {};\n    //    desc_image[0].sampler = g_FontSampler;\n    //    desc_image[0].imageView = g_FontView;\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 = g_DescriptorSet;\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    //    vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);\n    //}\n    VkDescriptorSet font_descriptor_set = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture(g_FontSampler, g_FontView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);\n\n    // Create the Upload Buffer:\n    {\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        err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &g_UploadBuffer);\n        check_vk_result(err);\n        VkMemoryRequirements req;\n        vkGetBufferMemoryRequirements(v->Device, g_UploadBuffer, &req);\n        g_BufferMemoryAlignment = (g_BufferMemoryAlignment > req.alignment) ? g_BufferMemoryAlignment : req.alignment;\n        VkMemoryAllocateInfo alloc_info = {};\n        alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n        alloc_info.allocationSize = req.size;\n        alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);\n        err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &g_UploadBufferMemory);\n        check_vk_result(err);\n        err = vkBindBufferMemory(v->Device, g_UploadBuffer, g_UploadBufferMemory, 0);\n        check_vk_result(err);\n    }\n\n    // Upload to Buffer:\n    {\n\t\tcemu_assert_debug(upload_size != 0);\n        char* map = NULL;\n        err = vkMapMemory(v->Device, g_UploadBufferMemory, 0, upload_size, 0, (void**)(&map));\n        check_vk_result(err);\n        memcpy(map, pixels, upload_size);\n        VkMappedMemoryRange range[1] = {};\n        range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;\n        range[0].memory = g_UploadBufferMemory;\n        range[0].size = upload_size;\n        err = vkFlushMappedMemoryRanges(v->Device, 1, range);\n        check_vk_result(err);\n        vkUnmapMemory(v->Device, g_UploadBufferMemory);\n    }\n\n    // Copy to Image:\n    {\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 = g_FontImage;\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        vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 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        vkCmdCopyBufferToImage(command_buffer, g_UploadBuffer, g_FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 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 = g_FontImage;\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        vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, use_barrier);\n    }\n\n    // Store our identifier\n    //io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontImage;\n\n\tauto texture = new ImGuiTexture();\n    texture->descriptor_set = font_descriptor_set;\n    io.Fonts->TexID = (ImTextureID)texture;\n\t\n    return true;\n}\n\nbool ImGui_ImplVulkan_CreateDeviceObjects()\n{\n    ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;\n    VkResult err;\n    VkShaderModule vert_module;\n    VkShaderModule frag_module;\n\n    // Create The Shader Modules:\n    {\n        VkShaderModuleCreateInfo vert_info = {};\n        vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n        vert_info.codeSize = sizeof(__glsl_shader_vert_spv);\n        vert_info.pCode = (uint32_t*)__glsl_shader_vert_spv;\n        err = vkCreateShaderModule(v->Device, &vert_info, v->Allocator, &vert_module);\n        check_vk_result(err);\n        VkShaderModuleCreateInfo frag_info = {};\n        frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n        frag_info.codeSize = sizeof(__glsl_shader_frag_spv);\n        frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;\n        err = vkCreateShaderModule(v->Device, &frag_info, v->Allocator, &frag_module);\n        check_vk_result(err);\n    }\n\n    if (!g_FontSampler)\n    {\n        VkSamplerCreateInfo info = {};\n        info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n        info.magFilter = VK_FILTER_LINEAR;\n        info.minFilter = VK_FILTER_LINEAR;\n        info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n        info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n        info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n        info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n        info.minLod = -1000;\n        info.maxLod = 1000;\n        info.maxAnisotropy = 1.0f;\n        err = vkCreateSampler(v->Device, &info, v->Allocator, &g_FontSampler);\n        check_vk_result(err);\n    }\n\n    if (!g_DescriptorSetLayout)\n    {\n        VkSampler sampler[1] = {g_FontSampler};\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 info = {};\n        info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n        info.bindingCount = 1;\n        info.pBindings = binding;\n        err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &g_DescriptorSetLayout);\n        check_vk_result(err);\n    }\n\n    //// Create Descriptor Set:\n    //{\n    //    VkDescriptorSetAllocateInfo alloc_info = {};\n    //    alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    //    alloc_info.descriptorPool = v->DescriptorPool;\n    //    alloc_info.descriptorSetCount = 1;\n    //    alloc_info.pSetLayouts = &g_DescriptorSetLayout;\n    //    err = vkAllocateDescriptorSets(v->Device, &alloc_info, &g_DescriptorSet);\n    //    check_vk_result(err);\n    //}\n\n    if (!g_PipelineLayout)\n    {\n        // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix\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        VkDescriptorSetLayout set_layout[1] = { g_DescriptorSetLayout };\n        VkPipelineLayoutCreateInfo layout_info = {};\n        layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n        layout_info.setLayoutCount = 1;\n        layout_info.pSetLayouts = set_layout;\n        layout_info.pushConstantRangeCount = 1;\n        layout_info.pPushConstantRanges = push_constants;\n        err = vkCreatePipelineLayout(v->Device, &layout_info, v->Allocator, &g_PipelineLayout);\n        check_vk_result(err);\n    }\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_MINUS_SRC_ALPHA;\n    color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;\n    color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD;\n    color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | 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 = g_PipelineCreateFlags;\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 = g_PipelineLayout;\n    info.renderPass = g_RenderPass;\n    err = vkCreateGraphicsPipelines(v->Device, v->PipelineCache, 1, &info, v->Allocator, &g_Pipeline);\n    check_vk_result(err);\n\n    vkDestroyShaderModule(v->Device, vert_module, v->Allocator);\n    vkDestroyShaderModule(v->Device, frag_module, v->Allocator);\n\n    return true;\n}\n\nvoid    ImGui_ImplVulkan_DestroyFontUploadObjects()\n{\n    ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;\n    if (g_UploadBuffer)\n    {\n        vkDestroyBuffer(v->Device, g_UploadBuffer, v->Allocator);\n        g_UploadBuffer = VK_NULL_HANDLE;\n    }\n    if (g_UploadBufferMemory)\n    {\n        vkFreeMemory(v->Device, g_UploadBufferMemory, v->Allocator);\n        g_UploadBufferMemory = VK_NULL_HANDLE;\n    }\n}\n\nvoid    ImGui_ImplVulkan_DestroyDeviceObjects()\n{\n    ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;\n    ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);\n    ImGui_ImplVulkan_DestroyFontUploadObjects();\n\n    if (g_FontView)             { vkDestroyImageView(v->Device, g_FontView, v->Allocator); g_FontView = VK_NULL_HANDLE; }\n    if (g_FontImage)            { vkDestroyImage(v->Device, g_FontImage, v->Allocator); g_FontImage = VK_NULL_HANDLE; }\n    if (g_FontMemory)           { vkFreeMemory(v->Device, g_FontMemory, v->Allocator); g_FontMemory = VK_NULL_HANDLE; }\n    if (g_FontSampler)          { vkDestroySampler(v->Device, g_FontSampler, v->Allocator); g_FontSampler = VK_NULL_HANDLE; }\n    if (g_DescriptorSetLayout)  { vkDestroyDescriptorSetLayout(v->Device, g_DescriptorSetLayout, v->Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; }\n    if (g_PipelineLayout)       { vkDestroyPipelineLayout(v->Device, g_PipelineLayout, v->Allocator); g_PipelineLayout = VK_NULL_HANDLE; }\n    if (g_Pipeline)             { vkDestroyPipeline(v->Device, g_Pipeline, v->Allocator); g_Pipeline = VK_NULL_HANDLE; }\n}\n\nbool    ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass)\n{\n    // Setup back-end capabilities flags\n    ImGuiIO& io = ImGui::GetIO();\n    io.BackendRendererName = \"imgui_impl_vulkan\";\n   // io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.\n\n    IM_ASSERT(info->Instance != VK_NULL_HANDLE);\n    IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE);\n    IM_ASSERT(info->Device != VK_NULL_HANDLE);\n    IM_ASSERT(info->Queue != VK_NULL_HANDLE);\n    IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE);\n    IM_ASSERT(info->MinImageCount >= 2);\n    IM_ASSERT(info->ImageCount >= info->MinImageCount);\n    IM_ASSERT(render_pass != VK_NULL_HANDLE);\n\n    g_VulkanInitInfo = *info;\n    g_RenderPass = render_pass;\n    ImGui_ImplVulkan_CreateDeviceObjects();\n\n    return true;\n}\n\nImTextureID ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout) {\n    VkResult err;\n\n    VkDescriptorSet descriptor_set;\n    // Create Descriptor Set:\n    {\n        VkDescriptorSetAllocateInfo alloc_info = {};\n        alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n        alloc_info.descriptorPool = g_VulkanInitInfo.DescriptorPool;\n        alloc_info.descriptorSetCount = 1;\n        alloc_info.pSetLayouts = &g_DescriptorSetLayout;\n        err = vkAllocateDescriptorSets(g_VulkanInitInfo.Device, &alloc_info, &descriptor_set);\n        check_vk_result(err);\n    }\n\n    // Update the Descriptor Set:\n    {\n        VkDescriptorImageInfo desc_image[1] = {};\n        desc_image[0].sampler = sampler;\n        desc_image[0].imageView = image_view;\n        desc_image[0].imageLayout = image_layout;\n        VkWriteDescriptorSet write_desc[1] = {};\n        write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n        write_desc[0].dstSet = descriptor_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        vkUpdateDescriptorSets(g_VulkanInitInfo.Device, 1, write_desc, 0, NULL);\n    }\n\n    return (ImTextureID)descriptor_set;\n}\n\nvoid ImGui_ImplVulkan_Shutdown()\n{\n    ImGui_ImplVulkan_DestroyDeviceObjects();\n}\n\nvoid ImGui_ImplVulkan_NewFrame(VkCommandBuffer command_buffer, VkFramebuffer framebuffer, VkExtent2D extent)\n{\n\tauto& io = ImGui::GetIO();\n\n\tVkRenderPassBeginInfo renderPassInfo{};\n\trenderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n\trenderPassInfo.renderPass = g_RenderPass;\n\trenderPassInfo.framebuffer = framebuffer;\n\trenderPassInfo.renderArea.offset = {0, 0};\n\trenderPassInfo.renderArea.extent = extent;\n\trenderPassInfo.clearValueCount = 0;\n\tvkCmdBeginRenderPass(command_buffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);\n}\n\nvoid ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)\n{\n    IM_ASSERT(min_image_count >= 2);\n    if (g_VulkanInitInfo.MinImageCount == min_image_count)\n        return;\n\n    ImGui_ImplVulkan_InitInfo* v = &g_VulkanInitInfo;\n    VkResult err = vkDeviceWaitIdle(v->Device);\n    check_vk_result(err);\n    ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &g_MainWindowRenderBuffers, v->Allocator);\n    g_VulkanInitInfo.MinImageCount = min_image_count;\n}\n\n\n//-------------------------------------------------------------------------\n// Internal / Miscellaneous Vulkan Helpers\n// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.)\n//-------------------------------------------------------------------------\n// You probably do NOT need to use or care about those functions.\n// Those functions only exist because:\n//   1) they facilitate the readability and maintenance of the multiple main.cpp examples files.\n//   2) the upcoming multi-viewport feature will need them internally.\n// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,\n// but it is too much code to duplicate everywhere so we exceptionally expose them.\n//\n// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).\n// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.\n// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)\n//-------------------------------------------------------------------------\n\nVkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space)\n{\n    IM_ASSERT(request_formats != NULL);\n    IM_ASSERT(request_formats_count > 0);\n\n    // Per Spec Format and View Format are expected to be the same unless VK_IMAGE_CREATE_MUTABLE_BIT was set at image creation\n    // Assuming that the default behavior is without setting this bit, there is no need for separate Swapchain image and image view format\n    // Additionally several new color spaces were introduced with Vulkan Spec v1.0.40,\n    // hence we must make sure that a format with the mostly available color space, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, is found and used.\n    uint32_t avail_count;\n    vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &avail_count, NULL);\n    ImVector<VkSurfaceFormatKHR> avail_format;\n    avail_format.resize((int)avail_count);\n    vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &avail_count, avail_format.Data);\n\n    // First check if only one format, VK_FORMAT_UNDEFINED, is available, which would imply that any format is available\n    if (avail_count == 1)\n    {\n        if (avail_format[0].format == VK_FORMAT_UNDEFINED)\n        {\n            VkSurfaceFormatKHR ret;\n            ret.format = request_formats[0];\n            ret.colorSpace = request_color_space;\n            return ret;\n        }\n        else\n        {\n            // No point in searching another format\n            return avail_format[0];\n        }\n    }\n    else\n    {\n        // Request several formats, the first found will be used\n        for (int request_i = 0; request_i < request_formats_count; request_i++)\n            for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++)\n                if (avail_format[avail_i].format == request_formats[request_i] && avail_format[avail_i].colorSpace == request_color_space)\n                    return avail_format[avail_i];\n\n        // If none of the requested image formats could be found, use the first available\n        return avail_format[0];\n    }\n}\n\nVkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count)\n{\n    IM_ASSERT(request_modes != NULL);\n    IM_ASSERT(request_modes_count > 0);\n\n    // Request a certain mode and confirm that it is available. If not use VK_PRESENT_MODE_FIFO_KHR which is mandatory\n    uint32_t avail_count = 0;\n    vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &avail_count, NULL);\n    ImVector<VkPresentModeKHR> avail_modes;\n    avail_modes.resize((int)avail_count);\n    vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &avail_count, avail_modes.Data);\n    //for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++)\n    //    printf(\"[vulkan] avail_modes[%d] = %d\\n\", avail_i, avail_modes[avail_i]);\n\n    for (int request_i = 0; request_i < request_modes_count; request_i++)\n        for (uint32_t avail_i = 0; avail_i < avail_count; avail_i++)\n            if (request_modes[request_i] == avail_modes[avail_i])\n                return request_modes[request_i];\n\n    return VK_PRESENT_MODE_FIFO_KHR; // Always available\n}\n\nvoid ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator)\n{\n    IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE);\n    (void)physical_device;\n    (void)allocator;\n\n    // Create Command Buffers\n    VkResult err;\n    for (uint32_t i = 0; i < wd->ImageCount; i++)\n    {\n        ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];\n        ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i];\n        {\n            VkCommandPoolCreateInfo info = {};\n            info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;\n            info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;\n            info.queueFamilyIndex = queue_family;\n            err = vkCreateCommandPool(device, &info, allocator, &fd->CommandPool);\n            check_vk_result(err);\n        }\n        {\n            VkCommandBufferAllocateInfo info = {};\n            info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;\n            info.commandPool = fd->CommandPool;\n            info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n            info.commandBufferCount = 1;\n            err = vkAllocateCommandBuffers(device, &info, &fd->CommandBuffer);\n            check_vk_result(err);\n        }\n        {\n            VkFenceCreateInfo info = {};\n            info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n            info.flags = VK_FENCE_CREATE_SIGNALED_BIT;\n            err = vkCreateFence(device, &info, allocator, &fd->Fence);\n            check_vk_result(err);\n        }\n        {\n            VkSemaphoreCreateInfo info = {};\n            info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n            err = vkCreateSemaphore(device, &info, allocator, &fsd->ImageAcquiredSemaphore);\n            check_vk_result(err);\n            err = vkCreateSemaphore(device, &info, allocator, &fsd->RenderCompleteSemaphore);\n            check_vk_result(err);\n        }\n    }\n}\n\nint ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode)\n{\n    if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR)\n        return 3;\n    if (present_mode == VK_PRESENT_MODE_FIFO_KHR || present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)\n        return 2;\n    if (present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR)\n        return 1;\n    IM_ASSERT(0);\n    return 1;\n}\n\n// Also destroy old swap chain and in-flight frames data, if any.\nvoid ImGui_ImplVulkanH_CreateWindowSwapchain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)\n{\n    VkResult err;\n    VkSwapchainKHR old_swapchain = wd->Swapchain;\n    err = vkDeviceWaitIdle(device);\n    check_vk_result(err);\n\n    // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one.\n    // Destroy old Framebuffer\n    for (uint32_t i = 0; i < wd->ImageCount; i++)\n    {\n        ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);\n        ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);\n    }\n    IM_FREE(wd->Frames);\n    IM_FREE(wd->FrameSemaphores);\n    wd->Frames = NULL;\n    wd->FrameSemaphores = NULL;\n    wd->ImageCount = 0;\n    if (wd->RenderPass)\n        vkDestroyRenderPass(device, wd->RenderPass, allocator);\n\n    // If min image count was not specified, request different count of images dependent on selected present mode\n    if (min_image_count == 0)\n        min_image_count = ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(wd->PresentMode);\n\n    // Create Swapchain\n    {\n        VkSwapchainCreateInfoKHR info = {};\n        info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;\n        info.surface = wd->Surface;\n        info.minImageCount = min_image_count;\n        info.imageFormat = wd->SurfaceFormat.format;\n        info.imageColorSpace = wd->SurfaceFormat.colorSpace;\n        info.imageArrayLayers = 1;\n        info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;\n        info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;           // Assume that graphics family == present family\n        info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;\n        info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;\n        info.presentMode = wd->PresentMode;\n        info.clipped = VK_TRUE;\n        info.oldSwapchain = old_swapchain;\n        VkSurfaceCapabilitiesKHR cap;\n        err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, wd->Surface, &cap);\n        check_vk_result(err);\n        if (info.minImageCount < cap.minImageCount)\n            info.minImageCount = cap.minImageCount;\n        else if (cap.maxImageCount != 0 && info.minImageCount > cap.maxImageCount)\n            info.minImageCount = cap.maxImageCount;\n\n        if (cap.currentExtent.width == 0xffffffff)\n        {\n            info.imageExtent.width = wd->Width = w;\n            info.imageExtent.height = wd->Height = h;\n        }\n        else\n        {\n            info.imageExtent.width = wd->Width = cap.currentExtent.width;\n            info.imageExtent.height = wd->Height = cap.currentExtent.height;\n        }\n        err = vkCreateSwapchainKHR(device, &info, allocator, &wd->Swapchain);\n        check_vk_result(err);\n        err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, NULL);\n        check_vk_result(err);\n        VkImage backbuffers[16] = {};\n        IM_ASSERT(wd->ImageCount >= min_image_count);\n        IM_ASSERT(wd->ImageCount < IM_ARRAYSIZE(backbuffers));\n        err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers);\n        check_vk_result(err);\n\n        IM_ASSERT(wd->Frames == NULL);\n        wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount);\n        wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount);\n        memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount);\n        memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount);\n        for (uint32_t i = 0; i < wd->ImageCount; i++)\n            wd->Frames[i].Backbuffer = backbuffers[i];\n    }\n    if (old_swapchain)\n        vkDestroySwapchainKHR(device, old_swapchain, allocator);\n\n    // Create the Render Pass\n    {\n        VkAttachmentDescription attachment = {};\n        attachment.format = wd->SurfaceFormat.format;\n        attachment.samples = VK_SAMPLE_COUNT_1_BIT;\n\t\tattachment.loadOp = wd->ClearEnable ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;// VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n        attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n        attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n        attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n        attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n        attachment.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 info = {};\n        info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n        info.attachmentCount = 1;\n        info.pAttachments = &attachment;\n        info.subpassCount = 1;\n        info.pSubpasses = &subpass;\n        info.dependencyCount = 1;\n        info.pDependencies = &dependency;\n        err = vkCreateRenderPass(device, &info, allocator, &wd->RenderPass);\n        check_vk_result(err);\n    }\n\n    // Create The Image Views\n    {\n        VkImageViewCreateInfo info = {};\n        info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n        info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n        info.format = wd->SurfaceFormat.format;\n        info.components.r = VK_COMPONENT_SWIZZLE_R;\n        info.components.g = VK_COMPONENT_SWIZZLE_G;\n        info.components.b = VK_COMPONENT_SWIZZLE_B;\n        info.components.a = VK_COMPONENT_SWIZZLE_A;\n        VkImageSubresourceRange image_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };\n        info.subresourceRange = image_range;\n        for (uint32_t i = 0; i < wd->ImageCount; i++)\n        {\n            ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];\n            info.image = fd->Backbuffer;\n            err = vkCreateImageView(device, &info, allocator, &fd->BackbufferView);\n            check_vk_result(err);\n        }\n    }\n\n    // Create Framebuffer\n    {\n        VkImageView attachment[1];\n        VkFramebufferCreateInfo info = {};\n        info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;\n        info.renderPass = wd->RenderPass;\n        info.attachmentCount = 1;\n        info.pAttachments = attachment;\n        info.width = wd->Width;\n        info.height = wd->Height;\n        info.layers = 1;\n        for (uint32_t i = 0; i < wd->ImageCount; i++)\n        {\n            ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i];\n            attachment[0] = fd->BackbufferView;\n            err = vkCreateFramebuffer(device, &info, allocator, &fd->Framebuffer);\n            check_vk_result(err);\n        }\n    }\n}\n\nvoid ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)\n{\n    (void)instance;\n\tImGui_ImplVulkanH_CreateWindowSwapchain(physical_device, device, wd, allocator, width, height, min_image_count);\n    ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);\n}\n\nvoid ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator)\n{\n    vkDeviceWaitIdle(device); // FIXME: We could wait on the Queue if we had the queue in wd-> (otherwise VulkanH functions can't use globals)\n    //vkQueueWaitIdle(g_Queue);\n\n    for (uint32_t i = 0; i < wd->ImageCount; i++)\n    {\n        ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator);\n        ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);\n    }\n    IM_FREE(wd->Frames);\n    IM_FREE(wd->FrameSemaphores);\n    wd->Frames = NULL;\n    wd->FrameSemaphores = NULL;\n    vkDestroyRenderPass(device, wd->RenderPass, allocator);\n    vkDestroySwapchainKHR(device, wd->Swapchain, allocator);\n    vkDestroySurfaceKHR(instance, wd->Surface, allocator);\n\n    *wd = ImGui_ImplVulkanH_Window();\n}\n\nvoid ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator)\n{\n    vkDestroyFence(device, fd->Fence, allocator);\n    vkFreeCommandBuffers(device, fd->CommandPool, 1, &fd->CommandBuffer);\n    vkDestroyCommandPool(device, fd->CommandPool, allocator);\n    fd->Fence = VK_NULL_HANDLE;\n    fd->CommandBuffer = VK_NULL_HANDLE;\n    fd->CommandPool = VK_NULL_HANDLE;\n\n    vkDestroyImageView(device, fd->BackbufferView, allocator);\n    vkDestroyFramebuffer(device, fd->Framebuffer, allocator);\n}\n\nvoid ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator)\n{\n    vkDestroySemaphore(device, fsd->ImageAcquiredSemaphore, allocator);\n    vkDestroySemaphore(device, fsd->RenderCompleteSemaphore, allocator);\n    fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;\n}\n\nvoid ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)\n{\n    if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }\n    if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }\n    if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }\n    if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }\n    buffers->VertexBufferSize = 0;\n    buffers->IndexBufferSize = 0;\n}\n\nvoid ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator)\n{\n    for (uint32_t n = 0; n < buffers->Count; n++)\n        ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator);\n    IM_FREE(buffers->FrameRenderBuffers);\n    buffers->FrameRenderBuffers = NULL;\n    buffers->Index = 0;\n    buffers->Count = 0;\n}\n\nImTextureID ImGui_ImplVulkan_GenerateTexture(VkCommandBuffer commandBuffer, const std::vector<uint8>& data, const Vector2i& size)\n{\n    try\n    {\n        auto* texture = new ImGuiTexture();\n    \t\n        VkResult err;\n        // Create the Image View:\n        {\n            VkImageCreateInfo info = {};\n            info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n            info.imageType = VK_IMAGE_TYPE_2D;\n            info.format = VK_FORMAT_R8G8B8A8_UNORM;\n            info.extent.width = size.x;\n            info.extent.height = size.y;\n            info.extent.depth = 1;\n            info.mipLevels = 1;\n            info.arrayLayers = 1;\n            info.samples = VK_SAMPLE_COUNT_1_BIT;\n            info.tiling = VK_IMAGE_TILING_OPTIMAL;\n            info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;\n            info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n            info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n            err = vkCreateImage(g_VulkanInitInfo.Device, &info, g_VulkanInitInfo.Allocator, &texture->image);\n            check_vk_result(err);\n            VkMemoryRequirements req;\n            vkGetImageMemoryRequirements(g_VulkanInitInfo.Device, texture->image, &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 = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits);\n            err = vkAllocateMemory(g_VulkanInitInfo.Device, &alloc_info, g_VulkanInitInfo.Allocator, &texture->memory);\n            check_vk_result(err);\n            err = vkBindImageMemory(g_VulkanInitInfo.Device, texture->image, texture->memory, 0);\n            check_vk_result(err);\n        }\n\n        // Create the Image View:\n        {\n            VkImageViewCreateInfo info = {};\n            info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n            info.image = texture->image;\n            info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n            info.format = VK_FORMAT_R8G8B8A8_UNORM;\n            info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n            info.subresourceRange.levelCount = 1;\n            info.subresourceRange.layerCount = 1;\n            err = vkCreateImageView(g_VulkanInitInfo.Device, &info, g_VulkanInitInfo.Allocator, &texture->view);\n\t\t\tcheck_vk_result(err);\n        }\n\n        // create sampler\n        {\n            VkSamplerCreateInfo info = {};\n            info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n            info.magFilter = VK_FILTER_LINEAR;\n            info.minFilter = VK_FILTER_LINEAR;\n            info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n            info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n            info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n            info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n            info.minLod = -1000;\n            info.maxLod = 1000;\n            info.maxAnisotropy = 1.0f;\n            err = vkCreateSampler(g_VulkanInitInfo.Device, &info, g_VulkanInitInfo.Allocator, &texture->sampler);\n            check_vk_result(err);\n        }\n\n       texture->descriptor_set = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture(texture->sampler, texture->view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);\n\n     \n        // Create the Upload Buffer:\n        {\n            VkBufferCreateInfo buffer_info = {};\n            buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n            buffer_info.size = data.size();\n            buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;\n            buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n            err = vkCreateBuffer(g_VulkanInitInfo.Device, &buffer_info, g_VulkanInitInfo.Allocator, &texture->uploadBuffer);\n            check_vk_result(err);\n            VkMemoryRequirements req;\n            vkGetBufferMemoryRequirements(g_VulkanInitInfo.Device, texture->uploadBuffer, &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 = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits);\n            err = vkAllocateMemory(g_VulkanInitInfo.Device, &alloc_info, g_VulkanInitInfo.Allocator, &texture->uploadBufferMemory);\n            check_vk_result(err);\n            err = vkBindBufferMemory(g_VulkanInitInfo.Device, texture->uploadBuffer, texture->uploadBufferMemory, 0);\n            check_vk_result(err);\n        }\n\n        // Upload to Buffer:\n        {\n            cemu_assert_debug(data.size() != 0);\n            char* map = NULL;\n            err = vkMapMemory(g_VulkanInitInfo.Device, texture->uploadBufferMemory, 0, data.size(), 0, (void**)(&map));\n            check_vk_result(err);\n            memcpy(map, data.data(), data.size());\n            VkMappedMemoryRange range[1] = {};\n            range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;\n            range[0].memory = texture->uploadBufferMemory;\n            range[0].size = data.size();\n            err = vkFlushMappedMemoryRanges(g_VulkanInitInfo.Device, 1, range);\n            check_vk_result(err);\n            vkUnmapMemory(g_VulkanInitInfo.Device, texture->uploadBufferMemory);\n        }\n\n        // Copy to Image:\n        {\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 = texture->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            vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 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 = size.x;\n            region.imageExtent.height = size.y;\n            region.imageExtent.depth = 1;\n            vkCmdCopyBufferToImage(commandBuffer, texture->uploadBuffer, texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 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 = texture->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            vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, use_barrier);\n        }\n\n        return (ImTextureID)texture;\n    }\n    catch (const std::exception & ex)\n    {\n        cemuLog_log(LogType::Force, \"can't generate imgui texture: {}\", ex.what());\n        return nullptr;\n    }\n}\n\nvoid ImGui_ImplVulkan_DeleteTexture(ImTextureID id)\n{\n    auto textureInfo = (ImGuiTexture*)id;\n\n    vkFreeDescriptorSets(g_VulkanInitInfo.Device, g_VulkanInitInfo.DescriptorPool, 1, &textureInfo->descriptor_set);\n    vkDestroySampler(g_VulkanInitInfo.Device, textureInfo->sampler, nullptr);\n    vkDestroyImageView(g_VulkanInitInfo.Device, textureInfo->view, nullptr);\n    vkDestroyImage(g_VulkanInitInfo.Device, textureInfo->image, nullptr);\n    vkDestroyBuffer(g_VulkanInitInfo.Device, textureInfo->uploadBuffer, nullptr);\n    vkFreeMemory(g_VulkanInitInfo.Device, textureInfo->memory, nullptr);\n    vkFreeMemory(g_VulkanInitInfo.Device, textureInfo->uploadBufferMemory, nullptr);\n\n    *textureInfo = {};\n}\n"
  },
  {
    "path": "src/imgui/imgui_impl_vulkan.h",
    "content": "// dear imgui: Renderer for Vulkan\n// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)\n\n// Implemented features:\n//  [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.\n// Missing features:\n//  [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this binding! See https://github.com/ocornut/imgui/pull/914\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// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.\n// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/\n\n// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.\n// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.\n//   You will use those if you want to use this rendering back-end in your engine/app.\n// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by \n//   the back-end itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.\n// Read comments in imgui_impl_vulkan.h.\n\n#pragma once\n\n#include <imgui.h>\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h\"\n#include \"util/math/vector2.h\"\n\n// Initialization data, for ImGui_ImplVulkan_Init()\n// [Please zero-clear before use!]\nstruct ImGui_ImplVulkan_InitInfo\n{\n    VkInstance          Instance;\n    VkPhysicalDevice    PhysicalDevice;\n    VkDevice            Device;\n    uint32_t            QueueFamily;\n    VkQueue             Queue;\n    VkPipelineCache     PipelineCache;\n    VkDescriptorPool    DescriptorPool;\n    uint32_t            MinImageCount;          // >= 2\n    uint32_t            ImageCount;             // >= MinImageCount\n    const VkAllocationCallbacks* Allocator;\n    void                (*CheckVkResultFn)(VkResult err);\n};\n\n// Called by user code\nIMGUI_IMPL_API bool     ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);\nIMGUI_IMPL_API void     ImGui_ImplVulkan_Shutdown();\nIMGUI_IMPL_API void     ImGui_ImplVulkan_NewFrame(VkCommandBuffer command_buffer, VkFramebuffer framebuffer, VkExtent2D extent);\nIMGUI_IMPL_API void     ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);\nIMGUI_IMPL_API bool     ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);\nIMGUI_IMPL_API void     ImGui_ImplVulkan_DestroyFontsTexture();\nIMGUI_IMPL_API void     ImGui_ImplVulkan_DestroyFontUploadObjects();\nIMGUI_IMPL_API void     ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)\n//\n//IMGUI_IMPL_API bool           ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);\n//IMGUI_IMPL_API void           ImGui_ImplVulkan_Shutdown();\n//IMGUI_IMPL_API void           ImGui_ImplVulkan_NewFrame();\n//IMGUI_IMPL_API void           ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);\n//IMGUI_IMPL_API bool           ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);\n//IMGUI_IMPL_API void           ImGui_ImplVulkan_InvalidateFontUploadObjects();\nIMGUI_IMPL_API ImTextureID    ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout);\nIMGUI_IMPL_API ImTextureID ImGui_ImplVulkan_GenerateTexture(VkCommandBuffer commandBuffer, const std::vector<uint8>& data, const Vector2i& size);\nIMGUI_IMPL_API void ImGui_ImplVulkan_DeleteTexture(ImTextureID id);\n\n\n//-------------------------------------------------------------------------\n// Internal / Miscellaneous Vulkan Helpers\n// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)\n//-------------------------------------------------------------------------\n// You probably do NOT need to use or care about those functions.\n// Those functions only exist because:\n//   1) they facilitate the readability and maintenance of the multiple main.cpp examples files.\n//   2) the upcoming multi-viewport feature will need them internally.\n// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,\n// but it is too much code to duplicate everywhere so we exceptionally expose them.\n//\n// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).\n// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.\n// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)\n//-------------------------------------------------------------------------\n\nstruct ImGui_ImplVulkanH_Frame;\nstruct ImGui_ImplVulkanH_Window;\n\n// Helpers\nIMGUI_IMPL_API void                 ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);\nIMGUI_IMPL_API void                 ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);\nIMGUI_IMPL_API VkSurfaceFormatKHR   ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);\nIMGUI_IMPL_API VkPresentModeKHR     ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);\nIMGUI_IMPL_API int                  ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);\n\n// Helper structure to hold the data needed by one rendering frame\n// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)\n// [Please zero-clear before use!]\nstruct ImGui_ImplVulkanH_Frame\n{\n    VkCommandPool       CommandPool;\n    VkCommandBuffer     CommandBuffer;\n    VkFence             Fence;\n    VkImage             Backbuffer;\n    VkImageView         BackbufferView;\n    VkFramebuffer       Framebuffer;\n};\n\nstruct ImGui_ImplVulkanH_FrameSemaphores\n{\n    VkSemaphore         ImageAcquiredSemaphore;\n    VkSemaphore         RenderCompleteSemaphore;\n};\n\n// Helper structure to hold the data needed by one rendering context into one OS window\n// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)\nstruct ImGui_ImplVulkanH_Window\n{\n    int                 Width;\n    int                 Height;\n    VkSwapchainKHR      Swapchain;\n    VkSurfaceKHR        Surface;\n    VkSurfaceFormatKHR  SurfaceFormat;\n    VkPresentModeKHR    PresentMode;\n    VkRenderPass        RenderPass;\n    bool                ClearEnable;\n    VkClearValue        ClearValue;\n    uint32_t            FrameIndex;             // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)\n    uint32_t            ImageCount;             // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)\n    uint32_t            SemaphoreIndex;         // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)\n    ImGui_ImplVulkanH_Frame*            Frames;\n    ImGui_ImplVulkanH_FrameSemaphores*  FrameSemaphores;\n\n    ImGui_ImplVulkanH_Window() \n    { \n        memset(this, 0, sizeof(*this)); \n        PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;\n        ClearEnable = true;\n    }\n};\n\n"
  },
  {
    "path": "src/input/CMakeLists.txt",
    "content": "add_library(CemuInput\n\tInputManager.cpp\n\tInputManager.h\n\tControllerFactory.cpp\n\tControllerFactory.h\n\tapi/ControllerState.h\n\tapi/Controller.cpp\n\tapi/Controller.h\n\tapi/ControllerState.cpp\n\tapi/InputAPI.h\n\tapi/ControllerProvider.h\n\tapi/DSU/DSUController.h\n\tapi/DSU/DSUControllerProvider.cpp\n\tapi/DSU/DSUController.cpp\n\tapi/DSU/DSUControllerProvider.h\n\tapi/DSU/DSUMessages.h\n\tapi/DSU/DSUMessages.cpp\n\tapi/SDL/SDLController.cpp\n\tapi/SDL/SDLControllerProvider.cpp\n\tapi/SDL/SDLController.h\n\tapi/SDL/SDLControllerProvider.h\n\tapi/Keyboard/KeyboardControllerProvider.h\n\tapi/Keyboard/KeyboardControllerProvider.cpp\n\tapi/Keyboard/KeyboardController.cpp\n\tapi/Keyboard/KeyboardController.h\n\tapi/GameCube/GameCubeController.cpp\n\tapi/GameCube/GameCubeControllerProvider.h\n\tapi/GameCube/GameCubeControllerProvider.cpp\n\tapi/GameCube/GameCubeController.h\n\temulated/ProController.cpp\n\temulated/EmulatedController.h\n\temulated/EmulatedController.cpp\n\temulated/ProController.h\n\temulated/WPADController.cpp\n\temulated/WPADController.h\n\temulated/WiimoteController.h\n\temulated/VPADController.cpp\n\temulated/WiimoteController.cpp\n\temulated/VPADController.h\n\temulated/ClassicController.cpp\n\temulated/ClassicController.h\n)\n\nset_property(TARGET CemuInput PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\nif(WIN32)\n\t# XInput\n\ttarget_sources(CemuInput PRIVATE\n\t\tapi/XInput/XInputControllerProvider.cpp\n\t\tapi/XInput/XInputControllerProvider.h\n\t\tapi/XInput/XInputController.cpp\n\t\tapi/XInput/XInputController.h\n\t)\n\n\t# DirectInput\n\ttarget_sources(CemuInput PRIVATE\n\t\tapi/DirectInput/DirectInputControllerProvider.cpp\n\t\tapi/DirectInput/DirectInputController.h\n\t\tapi/DirectInput/DirectInputControllerProvider.h\n\t\tapi/DirectInput/DirectInputController.cpp\n\t)\nendif()\n\nif (SUPPORTS_WIIMOTE)\n\ttarget_compile_definitions(CemuInput PUBLIC SUPPORTS_WIIMOTE)\n\ttarget_sources(CemuInput PRIVATE\n\t\t\tapi/Wiimote/WiimoteControllerProvider.h\n\t\t\tapi/Wiimote/WiimoteControllerProvider.cpp\n\t\t\tapi/Wiimote/WiimoteMessages.h\n\t\t\tapi/Wiimote/NativeWiimoteController.h\n\t\t\tapi/Wiimote/NativeWiimoteController.cpp\n\t\t\tapi/Wiimote/WiimoteDevice.h\n\t)\n\tif (ENABLE_HIDAPI)\n\t\ttarget_sources(CemuInput PRIVATE\n\t\t\t\tapi/Wiimote/hidapi/HidapiWiimote.cpp\n\t\t\t\tapi/Wiimote/hidapi/HidapiWiimote.h)\n\tendif ()\n\n\tif (ENABLE_BLUEZ)\n\t\ttarget_sources(CemuInput PRIVATE\n\t\t\t\tapi/Wiimote/l2cap/L2CapWiimote.cpp\n\t\t\t\tapi/Wiimote/l2cap/L2CapWiimote.h)\n\tendif()\nendif ()\n\n\ntarget_include_directories(CemuInput PUBLIC \"../\")\n\ntarget_link_libraries(CemuInput PRIVATE\n\tCemuCommon\n\tCemuGui\n)\n\nif (ENABLE_HIDAPI)\n\ttarget_link_libraries(CemuInput PRIVATE hidapi::hidapi)\nendif()\n\nif (ENABLE_BLUEZ)\n\ttarget_link_libraries(CemuInput PRIVATE bluez::bluez)\nendif ()\n"
  },
  {
    "path": "src/input/ControllerFactory.cpp",
    "content": "#include \"input/ControllerFactory.h\"\n\n#include \"input/emulated/VPADController.h\"\n#include \"input/emulated/ProController.h\"\n#include \"input/emulated/ClassicController.h\"\n#include \"input/emulated/WiimoteController.h\"\n\n#include \"input/api/SDL/SDLController.h\"\n#include \"input/api/Keyboard/KeyboardController.h\"\n#include \"input/api/DSU/DSUController.h\"\n#include \"input/api/GameCube/GameCubeController.h\"\n\n#if BOOST_OS_WINDOWS\n#include \"input/api/XInput/XInputController.h\"\n#include \"input/api/DirectInput/DirectInputController.h\"\n#endif\n\n#if HAS_WIIMOTE\n#include \"input/api/Wiimote/NativeWiimoteController.h\"\n#endif\n\nControllerPtr ControllerFactory::CreateController(InputAPI::Type api, std::string_view uuid,\n                                                  std::string_view display_name)\n{\n\tswitch (api)\n\t{\n#if HAS_KEYBOARD\n\tcase InputAPI::Keyboard:\n\t\treturn std::make_shared<KeyboardController>();\n#endif\n#if HAS_DIRECTINPUT\n\tcase InputAPI::DirectInput:\n\t\t{\n\t\t\tGUID guid;\n\t\t\t// Workaround for mouse2joystick users, which has 0 as it's uuid in it's profile and counts on Cemu applying it to the first directinput controller. GUIDFromString also doesn't allow for invalid uuids either.\n\t\t\tif (uuid == \"0\")\n\t\t\t{\n\t\t\t\tconst auto provider = InputManager::instance().get_api_provider(InputAPI::DirectInput);\n\t\t\t\tconst auto controllers = provider->get_controllers();\n\t\t\t\tif (controllers.empty())\n\t\t\t\t\tthrow std::invalid_argument(fmt::format(\n\t\t\t\t\t\t\"can't apply non-uuid-specific directinput profile when no controllers are available\"));\n\t\t\t\tif (!GUIDFromString(controllers.front()->uuid().c_str(), guid))\n\t\t\t\t\tthrow std::invalid_argument(fmt::format(\"invalid guid format: {}\", uuid));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!GUIDFromString(uuid.data(), guid))\n\t\t\t\t\tthrow std::invalid_argument(fmt::format(\"invalid guid format: {}\", uuid));\n\t\t\t}\n\n\t\t\treturn std::make_shared<DirectInputController>(guid);\n\t\t}\n#endif\n#if HAS_XINPUT\n\tcase InputAPI::XInput:\n\t\t{\n\t\t\tconst auto index = ConvertString<uint32>(uuid);\n\t\t\treturn std::make_shared<XInputController>(index);\n\t\t}\n#endif\n#if HAS_SDL\n\tcase InputAPI::SDLController:\n\t\t{\n\t\t\t// diid_guid\n\t\t\tconst auto index = uuid.find_first_of('_');\n\t\t\tif (index == std::string_view::npos)\n\t\t\t\tthrow std::invalid_argument(fmt::format(\"invalid sdl uuid format: {}\", uuid));\n\n\t\t\tconst auto guid_index = ConvertString<size_t>(uuid.substr(0, index));\n\t\t\tconst auto guid = SDL_JoystickGetGUIDFromString(std::string{uuid.substr(index + 1)}.c_str());\n\n\t\t\tif (display_name.empty())\n\t\t\t\treturn std::make_shared<SDLController>(guid, guid_index);\n\t\t\telse\n\t\t\t\treturn std::make_shared<SDLController>(guid, guid_index, display_name);\n\t\t}\n#endif\n#if HAS_DSU\n\tcase InputAPI::DSUClient:\n\t\t{\n\t\t\tconst auto index = ConvertString<uint32>(uuid);\n\t\t\treturn std::make_shared<DSUController>(index);\n\t\t}\n#endif\n#if HAS_GAMECUBE\n\tcase InputAPI::GameCube:\n\t\t{\n\t\t\tconst auto index = uuid.find_first_of('_');\n\t\t\tif (index == std::string_view::npos)\n\t\t\t\tthrow std::invalid_argument(fmt::format(\"invalid gamecube uuid format: {}\", uuid));\n\n\t\t\tconst auto adapter = ConvertString<int>(uuid.substr(0, index));\n\t\t\tconst auto controller_index = ConvertString<int>(uuid.substr(index + 1));\n\t\t\treturn std::make_shared<GameCubeController>(adapter, controller_index);\n\t\t}\n#endif\n#if HAS_WIIMOTE\n\tcase InputAPI::Wiimote:\n\t\t{\n\t\t\tconst auto index = ConvertString<uint32>(uuid);\n\t\t\treturn std::make_shared<NativeWiimoteController>(index);\n\t\t}\n#endif\n\tdefault:\n\t\tthrow std::invalid_argument(fmt::format(\"unhandled controller api: {}\", api));\n\t}\n\t/*\n\tcase InputAPI::WGIGamepad: break;\n\tcase InputAPI::WGIRawController: break;\n\t*/\n}\n\nEmulatedControllerPtr\nControllerFactory::CreateEmulatedController(size_t player_index, EmulatedController::Type type)\n{\n\tswitch (type)\n\t{\n\tcase EmulatedController::Type::VPAD:\n\t\treturn std::make_shared<VPADController>(player_index);\n\tcase EmulatedController::Type::Pro:\n\t\treturn std::make_shared<ProController>(player_index);\n\tcase EmulatedController::Type::Classic:\n\t\treturn std::make_shared<ClassicController>(player_index);\n\tcase EmulatedController::Type::Wiimote:\n\t\treturn std::make_shared<WiimoteController>(player_index);\n\tdefault:\n\t\tthrow std::runtime_error(fmt::format(\"unknown emulated controller type: {}\", type));\n\t}\n}\n\nControllerProviderPtr ControllerFactory::CreateControllerProvider(InputAPI::Type api, const ControllerProviderSettings& settings)\n{\n\tswitch (api)\n\t{\n#if HAS_KEYBOARD\n\tcase InputAPI::Keyboard:\n\t\treturn std::make_shared<KeyboardControllerProvider>();\n#endif\n#if HAS_SDL\n\tcase InputAPI::SDLController:\n\t\treturn std::make_shared<SDLControllerProvider>();\n#endif\n#if HAS_XINPUT\n\tcase InputAPI::XInput:\n\t\treturn std::make_shared<XInputControllerProvider>();\n#endif\n#if HAS_DIRECTINPUT\n\tcase InputAPI::DirectInput:\n\t\treturn std::make_shared<DirectInputControllerProvider>();\n#endif\n#if HAS_DSU\n\tcase InputAPI::DSUClient:\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\tconst auto& dsu_settings = dynamic_cast<const DSUProviderSettings&>(settings);\n\t\t\t\treturn std::make_shared<DSUControllerProvider>(dsu_settings);\n\t\t\t}\n\t\t\tcatch (const std::bad_cast&)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"failing to cast ControllerProviderSettings class to DSUControllerProvider\");\n\t\t\t\treturn std::make_shared<DSUControllerProvider>();\n\t\t\t}\n\t\t}\n\n#endif\n#if HAS_GAMECUBE\n\tcase InputAPI::GameCube:\n\t\treturn std::make_shared<GameCubeControllerProvider>();\n#endif\n#if HAS_WIIMOTE\n\tcase InputAPI::Wiimote:\n\t\treturn std::make_shared<WiimoteControllerProvider>();\n#endif\n\tdefault:\n\t\tcemu_assert_debug(false);\n\t\treturn {};\n\t}\n}\n"
  },
  {
    "path": "src/input/ControllerFactory.h",
    "content": "#pragma once\n\n#include \"input/api/InputAPI.h\"\n#include \"input/api/Controller.h\"\n#include \"input/emulated/EmulatedController.h\"\n\nclass ControllerFactory\n{\npublic:\n\tstatic ControllerPtr CreateController(InputAPI::Type api, std::string_view uuid, std::string_view display_name);\n\tstatic EmulatedControllerPtr CreateEmulatedController(size_t player_index, EmulatedController::Type type);\n\tstatic ControllerProviderPtr CreateControllerProvider(InputAPI::Type api, const ControllerProviderSettings& settings);\n};\n"
  },
  {
    "path": "src/input/InputManager.cpp",
    "content": "#include \"input/InputManager.h\"\n#include \"config/ActiveSettings.h\"\n#include \"input/ControllerFactory.h\"\n#include <boost/property_tree/ini_parser.hpp>\n#include <pugixml.hpp>\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"util/EventService.h\"\n\nInputManager::InputManager()\n{\n\t/*\n\tauto create_provider = []\n\ttemplate <typename TProvider>\n\t()\n\t{\n\t\tstatic_assert(std::is_base_of_v<ControllerProvider, TProvider>);\n\t\ttry\n\t\t{\n\t\t\tauto controller = std::make_shared<TProvider>();\n\t\t\tm_api_available[controller->api()] = controller;\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, ex.what());\n\t\t}\n\t}\n\t*/\n#if HAS_KEYBOARD\n\tcreate_provider<KeyboardControllerProvider>();\n#endif\n#if HAS_SDL\n\tcreate_provider<SDLControllerProvider>();\n#endif\n#if HAS_XINPUT\n\tcreate_provider<XInputControllerProvider>();\n#endif\n#if HAS_DIRECTINPUT\n\tcreate_provider<DirectInputControllerProvider>();\n#endif\n#if HAS_DSU\n\tcreate_provider<DSUControllerProvider>();\n#endif\n#if HAS_GAMECUBE\n\tcreate_provider<GameCubeControllerProvider>();\n#endif\n#if HAS_WIIMOTE\n\tcreate_provider<WiimoteControllerProvider>();\n#endif\n\n\tm_update_thread_shutdown.store(false);\n\tm_update_thread = std::thread(&InputManager::update_thread, this);\n}\n\nInputManager::~InputManager()\n{\n\tm_update_thread_shutdown.store(true);\n\tm_update_thread.join();\n}\n\nvoid InputManager::load() noexcept\n{\n\tfor (size_t i = 0; i < kMaxController; ++i)\n\t{\n\t\ttry\n\t\t{\n\t\t\tload(i);\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"can't load controller profile: {}\", ex.what());\n\t\t}\n\t}\n}\n\nbool InputManager::load(size_t player_index, std::string_view filename)\n{\n\tfs::path file_path;\n\tif (filename.empty())\n\t\tfile_path = ActiveSettings::GetConfigPath(\"controllerProfiles/controller{}\", player_index);\n\telse\n\t\tfile_path = ActiveSettings::GetConfigPath(\"controllerProfiles/{}\", filename);\n\n\tauto old_file = file_path;\n\told_file.replace_extension(\".txt\"); // test .txt extension\n\tfile_path.replace_extension(\".xml\"); // force .xml extension\n\n\tif (fs::exists(old_file) && !fs::exists(file_path))\n\t\tmigrate_config(old_file);\n\n\tif (!fs::exists(file_path))\n\t\treturn false;\n\n\ttry\n\t{\n\t\tauto xmlData = FileStream::LoadIntoMemory(file_path);\n\t\tif (!xmlData || xmlData->empty())\n\t\t\treturn false;\n\t\n\t\tpugi::xml_document doc;\n\t\tif (!doc.load_buffer(xmlData->data(), xmlData->size()))\n\t\t\treturn false;\n\n\t\tconst pugi::xml_node root = doc.document_element();\n\n\t\tconst auto type_node = root.child(\"type\");\n\t\tif (!type_node)\n\t\t\treturn false;\n\n\t\tconst auto emulate = EmulatedController::type_from_string(type_node.child_value());\n\t\tauto emulated_controller = ControllerFactory::CreateEmulatedController(player_index, emulate);\n\n\n\t\tif (const auto profile_name_node = root.child(\"profile\"))\n\t\t\temulated_controller->m_profile_name = profile_name_node.child_value();\n\n\t\t// custom settings\n\t\temulated_controller->load(root);\n\n\t\tfor (const auto controller_node : root.select_nodes(\"controller\"))\n\t\t{\n\t\t\tconst auto cnode = controller_node.node();\n\t\t\tconst auto api_node = cnode.child(\"api\");\n\t\t\tif (!api_node)\n\t\t\t\tcontinue;\n\n\t\t\tconst auto uuid_node = cnode.child(\"uuid\");\n\t\t\tif (!uuid_node)\n\t\t\t\tcontinue;\n\n\t\t\tconst auto* display_name = cnode.child_value(\"display_name\");\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\tconst auto api = InputAPI::from_string(api_node.child_value());\n\t\t\t\tauto controller = ControllerFactory::CreateController(api, uuid_node.child_value(), display_name);\n\t\t\t\temulated_controller->add_controller(controller);\n\n\t\t\t\t// load optional settings\n\t\t\t\tauto settings = controller->get_settings();\n\t\t\t\tif (const auto axis_node = cnode.child(\"axis\"))\n\t\t\t\t{\n\t\t\t\t\tif (const auto value = axis_node.child(\"deadzone\"))\n\t\t\t\t\t\tsettings.axis.deadzone = ConvertString<float>(value.child_value());\n\n\t\t\t\t\tif (const auto value = axis_node.child(\"range\"))\n\t\t\t\t\t\tsettings.axis.range = ConvertString<float>(value.child_value());\n\t\t\t\t}\n\t\t\t\tif (const auto rotation_node = cnode.child(\"rotation\"))\n\t\t\t\t{\n\t\t\t\t\tif (const auto value = rotation_node.child(\"deadzone\"))\n\t\t\t\t\t\tsettings.rotation.deadzone = ConvertString<float>(value.child_value());\n\n\t\t\t\t\tif (const auto value = rotation_node.child(\"range\"))\n\t\t\t\t\t\tsettings.rotation.range = ConvertString<float>(value.child_value());\n\t\t\t\t}\n\t\t\t\tif (const auto trigger_node = cnode.child(\"trigger\"))\n\t\t\t\t{\n\t\t\t\t\tif (const auto value = trigger_node.child(\"deadzone\"))\n\t\t\t\t\t\tsettings.trigger.deadzone = ConvertString<float>(value.child_value());\n\n\t\t\t\t\tif (const auto value = trigger_node.child(\"range\"))\n\t\t\t\t\t\tsettings.trigger.range = ConvertString<float>(value.child_value());\n\t\t\t\t}\n\n\t\t\t\tif (const auto value = cnode.child(\"rumble\"))\n\t\t\t\t\tsettings.rumble = ConvertString<float>(value.child_value());\n\n\t\t\t\tif (const auto value = cnode.child(\"motion\"))\n\t\t\t\t\tsettings.motion = ConvertString<bool>(value.child_value());\n\n\t\t\t\tcontroller->set_settings(settings);\n\n\t\t\t\t// custom settings\n\t\t\t\tcontroller->load(cnode);\n\t\t\t\t\n\n\t\t\t\t// mappings\n\t\t\t\tif (const auto mappings_node = cnode.child(\"mappings\"))\n\t\t\t\t{\n\t\t\t\t\tfor (const auto& entry : mappings_node.select_nodes(\"entry\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tconst auto enode = entry.node();\n\n\t\t\t\t\t\tconst auto mapping_node = enode.child(\"mapping\");\n\t\t\t\t\t\tif (!mapping_node)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tconst auto button_node = enode.child(\"button\");\n\t\t\t\t\t\tif (!button_node)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tconst auto mapping = ConvertString<uint64>(mapping_node.child_value());\n\t\t\t\t\t\tconst auto button = ConvertString<uint64>(button_node.child_value());\n\n\t\t\t\t\t\temulated_controller->set_mapping(mapping, controller, button);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (const std::exception& ex)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"can't load controller: {}\", ex.what());\n\t\t\t}\n\t\t}\n\n\t\tset_controller(emulated_controller);\n\t\treturn true;\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"can't load config file: {}\", ex.what());\n\t\treturn false;\n\t}\n}\n\nbool InputManager::migrate_config(const fs::path& file_path)\n{\n\ttry\n\t{\n\t\tauto xmlData = FileStream::LoadIntoMemory(file_path);\n\t\tif (!xmlData || xmlData->empty())\n\t\t\treturn false;\n\n\t\tstd::string iniDataStr((const char*)xmlData->data(), xmlData->size());\n\n\t\tstd::stringstream iniData(iniDataStr);\n\t\tboost::property_tree::ptree m_data;\n\t\tread_ini(iniData, m_data);\n\n\t\tconst auto emulate_string = m_data.get<std::string>(\"General.emulate\");\n\t\tconst auto api_string = m_data.get<std::string>(\"General.api\");\n\t\tauto uuid_opt = m_data.get_optional<std::string>(\"General.controller\");\n\t\tconst auto display_name = m_data.get_optional<std::string>(\"General.display\");\n\n\t\tstd::string uuid;\n\t\tif (api_string == to_string(InputAPI::Keyboard))\n\t\t\tuuid = to_string(InputAPI::Keyboard);\n\t\telse\n\t\t{\n\t\t\tif (!uuid_opt)\n\t\t\t\treturn false;\n\n\t\t\tuuid = uuid_opt.value();\n\t\t\tif (api_string == to_string(InputAPI::SDLController))\n\t\t\t{\n\t\t\t\tuuid += \"_0\";\n\t\t\t}\n\t\t}\n\n\t\tfs::path out_file = file_path;\n\t\tout_file.replace_extension(\".xml\");\n\n\t\tpugi::xml_document doc;\n\t\tauto declaration_node = doc.append_child(pugi::node_declaration);\n\t\tdeclaration_node.append_attribute(\"version\") = \"1.0\";\n\t\tdeclaration_node.append_attribute(\"encoding\") = \"UTF-8\";\n\n\t\tauto emulated_controller = doc.append_child(\"emulated_controller\");\n\t\temulated_controller.append_child(\"type\").append_child(pugi::node_pcdata).set_value(emulate_string.c_str());\n\n\t\tbool has_keyboard = api_string == to_string(InputAPI::Keyboard);\n\t\tif (!has_keyboard) // test if only keyboard configured\n\t\t{\n\t\t\tauto controller = emulated_controller.append_child(\"controller\");\n\t\t\tcontroller.append_child(\"api\").append_child(pugi::node_pcdata).set_value(api_string.c_str());\n\t\t\tcontroller.append_child(\"uuid\").append_child(pugi::node_pcdata).set_value(uuid.c_str());\n\t\t\tif (display_name.has_value() && !display_name->empty())\n\t\t\t\tcontroller.append_child(\"display_name\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\t\tdisplay_name.value().c_str());\n\n\n\t\t\tcontroller.append_child(\"rumble\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\tm_data.get<std::string>(\"Controller.rumble\").c_str());\n\n\t\t\tauto axis_node = controller.append_child(\"axis\");\n\t\t\taxis_node.append_child(\"deadzone\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\tm_data.get<std::string>(\"Controller.leftDeadzone\").c_str());\n\t\t\taxis_node.append_child(\"range\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\tm_data.get<std::string>(\"Controller.leftRange\").c_str());\n\n\t\t\tauto rotation_node = controller.append_child(\"rotation\");\n\t\t\trotation_node.append_child(\"deadzone\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\tm_data.get<std::string>(\"Controller.rightDeadzone\").c_str());\n\t\t\trotation_node.append_child(\"range\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\tm_data.get<std::string>(\"Controller.rightRange\").c_str());\n\n\t\t\tauto mappings_node = controller.append_child(\"mappings\");\n\t\t\tfor (int i = 1; i < 28; ++i) // test all possible mappings (max is 27 for vpad controller)\n\t\t\t{\n\t\t\t\tauto mapping = m_data.get_optional<std::string>(fmt::format(\"Controller.{}\", i));\n\t\t\t\tif (!mapping || mapping->empty())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (!boost::starts_with(mapping.value(), \"button_\"))\n\t\t\t\t{\n\t\t\t\t\tif (boost::starts_with(mapping.value(), \"key_\"))\n\t\t\t\t\t\thas_keyboard = true;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst auto button = ConvertString<uint64>(mapping.value().substr(7), 16);\n\n\t\t\t\tuint64 flag_bit = 0;\n\t\t\t\tfor (auto b = 0; b < 64; ++b)\n\t\t\t\t{\n\t\t\t\t\tif (HAS_BIT(button, b))\n\t\t\t\t\t{\n\t\t\t\t\t\tflag_bit = b;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// fix old flag layout to new one for all kind of axis stuff\n\t\t\t\tif (flag_bit >= 24 && flag_bit <= 31)\n\t\t\t\t\tflag_bit += 8;\n\t\t\t\telse if (flag_bit == 32) flag_bit = kTriggerXP;\n\t\t\t\telse if (flag_bit == 33) flag_bit = kRotationXP;\n\t\t\t\telse if (flag_bit == 34) flag_bit = kRotationYP;\n\t\t\t\telse if (flag_bit == 35) flag_bit = kTriggerYP;\n\t\t\t\telse if (flag_bit == 36) flag_bit = kAxisXN;\n\t\t\t\telse if (flag_bit == 37) flag_bit = kAxisYN;\n\t\t\t\telse if (flag_bit == 38) flag_bit = kTriggerXN;\n\t\t\t\telse if (flag_bit == 39) flag_bit = kRotationXN;\n\t\t\t\telse if (flag_bit == 40) flag_bit = kRotationYN;\n\t\t\t\telse if (flag_bit == 41) flag_bit = kTriggerYN;\n\n\t\t\t\t// fix old api mappings\n\t\t\t\tif (api_string == to_string(InputAPI::XInput))\n\t\t\t\t{\n\t\t\t\t\tconst std::unordered_map<uint64, uint64> xinput =\n\t\t\t\t\t{\n\t\t\t\t\t\t{kButton0, 12}, // XINPUT_GAMEPAD_A\n\t\t\t\t\t\t{kButton1, 13}, // XINPUT_GAMEPAD_B\n\t\t\t\t\t\t{kButton2, 14}, // XINPUT_GAMEPAD_X\n\t\t\t\t\t\t{kButton3, 15}, // XINPUT_GAMEPAD_Y\n\n\t\t\t\t\t\t{kButton4, 8}, // XINPUT_GAMEPAD_LEFT_SHOULDER\n\t\t\t\t\t\t{kButton5, 9}, // XINPUT_GAMEPAD_LEFT_SHOULDER\n\n\t\t\t\t\t\t{kButton6, 4}, // XINPUT_GAMEPAD_START\n\t\t\t\t\t\t{kButton7, 5}, // XINPUT_GAMEPAD_BACK\n\n\t\t\t\t\t\t{kButton8, 6}, // XINPUT_GAMEPAD_LEFT_THUMB\n\t\t\t\t\t\t{kButton9, 7}, // XINPUT_GAMEPAD_RIGHT_THUMB\n\n\t\t\t\t\t\t{kButton10, 0}, // XINPUT_GAMEPAD_DPAD_UP\n\t\t\t\t\t\t{kButton11, 1}, // XINPUT_GAMEPAD_DPAD_DOWN\n\t\t\t\t\t\t{kButton12, 2}, // XINPUT_GAMEPAD_DPAD_LEFT\n\t\t\t\t\t\t{kButton13, 3}, // XINPUT_GAMEPAD_DPAD_RIGHT\n\t\t\t\t\t};\n\n\t\t\t\t\tconst auto it = xinput.find(flag_bit);\n\t\t\t\t\tif (it != xinput.cend())\n\t\t\t\t\t\tflag_bit = it->second;\n\t\t\t\t}\n\t\t\t\telse if (api_string == \"DSU\")\n\t\t\t\t{\n\t\t\t\t\tconst std::unordered_map<uint64, uint64> dsu =\n\t\t\t\t\t{\n\t\t\t\t\t\t{7, kButton0}, // ButtonSelect\n\t\t\t\t\t\t{8, kButton1}, // ButtonLStick\n\t\t\t\t\t\t{9, kButton2}, // ButtonRStick\n\t\t\t\t\t\t{6, kButton3}, // ButtonStart\n\n\t\t\t\t\t\t{4, kButton10}, // ButtonL\n\t\t\t\t\t\t{5, kButton11}, // ButtonR\n\n\t\t\t\t\t\t{0, kButton14}, // ButtonA\n\t\t\t\t\t\t{1, kButton13}, // ButtonB\n\t\t\t\t\t\t{2, kButton15}, // ButtonX\n\t\t\t\t\t\t{3, kButton12}, // ButtonY\n\t\t\t\t\t};\n\n\t\t\t\t\tconst auto it = dsu.find(flag_bit);\n\t\t\t\t\tif (it != dsu.cend())\n\t\t\t\t\t\tflag_bit = it->second;\n\t\t\t\t}\n\n\n\t\t\t\tauto entry_node = mappings_node.append_child(\"entry\");\n\t\t\t\tentry_node.append_child(\"mapping\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\t\tfmt::format(\"{}\", i).c_str());\n\t\t\t\tentry_node.append_child(\"button\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\t\tfmt::format(\"{}\", flag_bit).c_str());\n\t\t\t}\n\t\t}\n\n\t\tif (has_keyboard)\n\t\t{\n\t\t\tauto controller = emulated_controller.append_child(\"controller\");\n\t\t\tcontroller.append_child(\"api\").append_child(pugi::node_pcdata).set_value(\"Keyboard\");\n\t\t\tcontroller.append_child(\"uuid\").append_child(pugi::node_pcdata).set_value(\"Keyboard\");\n\n\t\t\tauto mappings_node = controller.append_child(\"mappings\");\n\t\t\tfor (int i = 1; i < 28; ++i) // test all possible mappings (max is 27 for vpad controller)\n\t\t\t{\n\t\t\t\tauto mapping = m_data.get_optional<std::string>(fmt::format(\"Controller.{}\", i));\n\t\t\t\tif (!mapping || mapping->empty())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (!boost::starts_with(mapping.value(), \"key_\"))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tconst auto button = ConvertString<uint64>(mapping.value().substr(4));\n\n\t\t\t\tauto entry_node = mappings_node.append_child(\"entry\");\n\t\t\t\tentry_node.append_child(\"mapping\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\t\tfmt::format(\"{}\", i).c_str());\n\t\t\t\tentry_node.append_child(\"button\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\t\tfmt::format(\"{}\", button).c_str());\n\t\t\t}\n\t\t}\n\n\t\tstd::ofstream write_file(out_file, std::ios::out | std::ios::trunc);\n\t\tif (write_file.is_open())\n\t\t{\n\t\t\tdoc.save(write_file);\n\t\t\treturn true;\n\t\t}\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"can't migrate config file {}: {}\", file_path.string(), ex.what());\n\t}\n\n\treturn false;\n}\n\nvoid InputManager::save() noexcept\n{\n\tfor (size_t i = 0; i < kMaxController; ++i)\n\t{\n\t\ttry\n\t\t{\n\t\t\tsave(i);\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"can't save controller profile: {}\", ex.what());\n\t\t}\n\t}\n}\n\nbool InputManager::save(size_t player_index, std::string_view filename)\n{\n\t// dont overwrite files if set by gameprofile\n\tif (m_is_gameprofile_set[player_index])\n\t\treturn true;\n\n\tauto emulated_controller = get_controller(player_index);\n\tif (!emulated_controller)\n\t\treturn false;\n\n\tfs::path file_path = ActiveSettings::GetConfigPath(\"controllerProfiles\");\n\tfs::create_directories(file_path);\n\n\tconst auto is_default_file = filename.empty();\n\tif (is_default_file)\n\t\tfile_path /= fmt::format(\"controller{}\", player_index);\n\telse\n\t\tfile_path /= _utf8ToPath(filename);\n\n\tfile_path.replace_extension(\".xml\"); // force .xml extension\n\n\tpugi::xml_document doc;\n\tauto declaration_node = doc.append_child(pugi::node_declaration);\n\tdeclaration_node.append_attribute(\"version\") = \"1.0\";\n\tdeclaration_node.append_attribute(\"encoding\") = \"UTF-8\";\n\n\tauto emulated_controller_node = doc.append_child(\"emulated_controller\");\n\temulated_controller_node.append_child(\"type\").append_child(pugi::node_pcdata).set_value(std::string{\n\t\temulated_controller->type_string()\n\t}.c_str());\n\n\tif(!is_default_file)\n\t\temulated_controller->m_profile_name = std::string{filename};\n\n\tif (emulated_controller->has_profile_name())\n\t\temulated_controller_node.append_child(\"profile\").append_child(pugi::node_pcdata).set_value(\n\t\t\temulated_controller->get_profile_name().c_str());\n\n\t// custom settings\n\temulated_controller->save(emulated_controller_node);\n\n\tfor (const auto& controller : emulated_controller->get_controllers())\n\t{\n\t\tauto controller_node = emulated_controller_node.append_child(\"controller\");\n\n\t\t// general\n\t\tcontroller_node.append_child(\"api\").append_child(pugi::node_pcdata).set_value(std::string{\n\t\t\tcontroller->api_name()\n\t\t}.c_str());\n\t\tcontroller_node.append_child(\"uuid\").append_child(pugi::node_pcdata).set_value(controller->uuid().c_str());\n\t\tcontroller_node.append_child(\"display_name\").append_child(pugi::node_pcdata).set_value(\n\t\t\tcontroller->display_name().c_str());\n\n\t\t// settings\n\t\tconst auto& settings = controller->get_settings();\n\n\t\tif (controller->has_motion())\n\t\t\tcontroller_node.append_child(\"motion\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\tfmt::format(\"{}\", settings.motion).c_str());\n\n\t\tif (controller->has_rumble())\n\t\t\tcontroller_node.append_child(\"rumble\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\tfmt::format(\"{}\", settings.rumble).c_str());\n\n\t\tauto axis_node = controller_node.append_child(\"axis\");\n\t\taxis_node.append_child(\"deadzone\").append_child(pugi::node_pcdata).set_value(\n\t\t\tfmt::format(\"{}\", settings.axis.deadzone).c_str());\n\t\taxis_node.append_child(\"range\").append_child(pugi::node_pcdata).set_value(\n\t\t\tfmt::format(\"{}\", settings.axis.range).c_str());\n\n\t\tauto rotation_node = controller_node.append_child(\"rotation\");\n\t\trotation_node.append_child(\"deadzone\").append_child(pugi::node_pcdata).set_value(\n\t\t\tfmt::format(\"{}\", settings.rotation.deadzone).c_str());\n\t\trotation_node.append_child(\"range\").append_child(pugi::node_pcdata).set_value(\n\t\t\tfmt::format(\"{}\", settings.rotation.range).c_str());\n\n\t\tauto trigger_node = controller_node.append_child(\"trigger\");\n\t\ttrigger_node.append_child(\"deadzone\").append_child(pugi::node_pcdata).set_value(\n\t\t\tfmt::format(\"{}\", settings.trigger.deadzone).c_str());\n\t\ttrigger_node.append_child(\"range\").append_child(pugi::node_pcdata).set_value(\n\t\t\tfmt::format(\"{}\", settings.trigger.range).c_str());\n\n\t\t// custom settings\n\t\tcontroller->save(controller_node);\n\n\t\t// mappings for current controller\n\t\tauto mappings_node = controller_node.append_child(\"mappings\");\n\t\tfor (const auto& mapping : emulated_controller->m_mappings)\n\t\t{\n\t\t\tif (!mapping.second.controller.expired() && *controller == *mapping.second.controller.lock())\n\t\t\t{\n\t\t\t\tauto entry_node = mappings_node.append_child(\"entry\");\n\t\t\t\tentry_node.append_child(\"mapping\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\t\tfmt::format(\"{}\", mapping.first).c_str());\n\t\t\t\tentry_node.append_child(\"button\").append_child(pugi::node_pcdata).set_value(\n\t\t\t\t\tfmt::format(\"{}\", mapping.second.button).c_str());\n\t\t\t}\n\t\t}\n\t}\n\tFileStream* fs = FileStream::createFile2(file_path);\n\tif (!fs)\n\t\treturn false;\n\tstd::stringstream xmlData;\n\tdoc.save(xmlData);\n\tstd::string xmlStr = xmlData.str();\n\tfs->writeData(xmlStr.data(), xmlStr.size());\n\tdelete fs;\n\treturn true;\n}\n\nbool InputManager::is_gameprofile_set(size_t player_index) const\n{\n\treturn m_is_gameprofile_set[player_index];\n}\n\nEmulatedControllerPtr InputManager::set_controller(EmulatedControllerPtr controller)\n{\n\tauto prev_controller = delete_controller(controller->player_index());\n\n\t// assign controllers to new emulated controller if empty\n\tif (prev_controller && controller->get_controllers().empty())\n\t{\n\t\tfor (const auto& c : prev_controller->get_controllers())\n\t\t{\n\t\t\tcontroller->add_controller(c);\n\t\t}\n\t}\n\n\t// try to connect all controllers\n\t/*for (auto& c : controller->get_controllers())\n\t{\n\t\tc->connect();\n\t}*/\n\n\tstd::scoped_lock lock(m_mutex);\n\tswitch (controller->type())\n\t{\n\tcase EmulatedController::Type::VPAD:\n\t\tfor (auto& pad : m_vpad)\n\t\t{\n\t\t\tif (!pad)\n\t\t\t{\n\t\t\t\tpad.swap(controller);\n\t\t\t\treturn prev_controller;\n\t\t\t}\n\t\t}\n\n\t\tbreak;\n\n\tdefault:\n\t\tfor (auto& pad : m_wpad)\n\t\t{\n\t\t\tif (!pad)\n\t\t\t{\n\t\t\t\tpad.swap(controller);\n\t\t\t\treturn prev_controller;\n\t\t\t}\n\t\t}\n\n\t\tbreak;\n\t}\n\t\n\tcemu_assert_debug(false);\n\treturn prev_controller;\n}\n\nEmulatedControllerPtr InputManager::set_controller(size_t player_index, EmulatedController::Type type)\n{\n\ttry\n\t{\n\t\tauto emulated_controller = ControllerFactory::CreateEmulatedController(player_index, type);\n\t\tset_controller(emulated_controller);\n\t\treturn emulated_controller;\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"Unable to set controller type {} on player index {}: {}\", type, player_index, ex.what());\n\t}\n\n\treturn {};\n}\n\nEmulatedControllerPtr InputManager::set_controller(size_t player_index, EmulatedController::Type type,\n                                                   const std::shared_ptr<ControllerBase>& controller)\n{\n\tauto result = set_controller(player_index, type);\n\tif (result)\n\t\tresult->add_controller(controller);\n\n\treturn result;\n}\n\nEmulatedControllerPtr InputManager::get_controller(size_t player_index) const\n{\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& pad : m_vpad)\n\t{\n\t\tif (pad && pad->player_index() == player_index)\n\t\t\treturn pad;\n\t}\n\n\tfor (const auto& pad : m_wpad)\n\t{\n\t\tif (pad && pad->player_index() == player_index)\n\t\t\treturn pad;\n\t}\n\n\treturn {};\n}\n\nEmulatedControllerPtr InputManager::delete_controller(size_t player_index, bool delete_profile)\n{\n\tstd::scoped_lock lock(m_mutex);\n\tfor (auto& controller : m_vpad)\n\t{\n\t\tauto result = controller;\n\t\tif (result && result->player_index() == player_index)\n\t\t{\n\t\t\tcontroller = {};\n\n\t\t\tif(delete_profile)\n\t\t\t{\n\t\t\t\tstd::error_code ec{};\n\t\t\t\tfs::remove(ActiveSettings::GetConfigPath(\"controllerProfiles/controller{}.xml\", player_index), ec);\n\t\t\t\tfs::remove(ActiveSettings::GetConfigPath(\"controllerProfiles/controller{}.txt\", player_index), ec);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tfor (auto& controller : m_wpad)\n\t{\n\t\tauto result = controller;\n\t\tif (result && result->player_index() == player_index)\n\t\t{\n\t\t\tcontroller = {};\n\n\t\t\tstd::error_code ec{};\n\t\t\tfs::remove(ActiveSettings::GetConfigPath(\"controllerProfiles/controller{}.xml\", player_index), ec);\n\t\t\tfs::remove(ActiveSettings::GetConfigPath(\"controllerProfiles/controller{}.txt\", player_index), ec);\n\n\t\t\treturn result;\n\t\t}\n\t}\n\n\treturn {};\n}\n\n\nstd::shared_ptr<VPADController> InputManager::get_vpad_controller(size_t index) const\n{\n\tif (index >= m_vpad.size())\n\t\treturn {};\n\n\tstd::shared_lock lock(m_mutex);\n\treturn std::static_pointer_cast<VPADController>(m_vpad[index]);\n}\n\nstd::shared_ptr<WPADController> InputManager::get_wpad_controller(size_t index) const\n{\n\tif (index >= m_wpad.size())\n\t\treturn {};\n\n\tstd::shared_lock lock(m_mutex);\n\treturn std::static_pointer_cast<WPADController>(m_wpad[index]);\n}\n\nstd::pair<size_t, size_t> InputManager::get_controller_count() const\n{\n\tstd::shared_lock lock(m_mutex);\n\tconst size_t vpad = std::count_if(m_vpad.cbegin(), m_vpad.cend(), [](const auto& v) { return v != nullptr; });\n\tconst size_t wpad = std::count_if(m_wpad.cbegin(), m_wpad.cend(), [](const auto& v) { return v != nullptr; });\n\treturn std::make_pair(vpad, wpad);\n}\n\nvoid InputManager::on_device_changed()\n{\n\tstd::shared_lock lock(m_mutex);\n\tfor (auto& pad : m_vpad)\n\t{\n\t\tif (pad)\n\t\t\tpad->connect();\n\t}\n\n\tfor (auto& pad : m_wpad)\n\t{\n\t\tif (pad)\n\t\t\tpad->connect();\n\t}\n\tlock.unlock();\n\n\tEventService::instance().signal<Events::ControllerChanged>();\n}\n\nControllerProviderPtr InputManager::get_api_provider(InputAPI::Type api) const\n{\n\tif(!m_api_available[api].empty())\n\t\treturn *(m_api_available[api].begin());\n\t\n\tcemu_assert_debug(false);\n\treturn {};\n}\n\nControllerProviderPtr InputManager::get_api_provider(InputAPI::Type api, const ControllerProviderSettings& settings)\n{\n\tfor(const auto& p : m_api_available[api])\n\t{\n\t\tif(*p == settings)\n\t\t{\n\t\t\treturn p;\n\t\t}\n\t}\n\n\tconst auto result = ControllerFactory::CreateControllerProvider(api, settings);\n\tm_api_available[api].emplace_back(result);\n\treturn result;\n}\n\nvoid InputManager::apply_game_profile()\n{\n\tconst auto& profiles = g_current_game_profile->GetControllerProfile();\n\tfor (int i = 0; i < kMaxController; ++i)\n\t{\n\t\tif (profiles[i] && !profiles[i]->empty())\n\t\t{\n\t\t\tif (load(i, profiles[i].value()))\n\t\t\t{\n\t\t\t\tm_is_gameprofile_set[i] = true;\n\t\t\t\tif (const auto controller = get_controller(i))\n\t\t\t\t{\n\t\t\t\t\tif (!controller->has_profile_name())\n\t\t\t\t\t\tcontroller->m_profile_name = profiles[i].value();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nstd::vector<std::string> InputManager::get_profiles()\n{\n\tconst auto path = ActiveSettings::GetConfigPath(\"controllerProfiles\");\n\tif (!exists(path))\n\t\treturn {};\n\n\tstd::set<std::string> tmp;\n\tfor (const auto& entry : fs::directory_iterator(path))\n\t{\n\t\tconst auto& p = entry.path();\n\t\tif (p.has_extension() && (p.extension() == \".xml\" || p.extension() == \".txt\"))\n\t\t{\n\t\t\tauto stem = _pathToUtf8(p.filename().stem());\n\t\t\tif (is_valid_profilename(stem))\n\t\t\t{\n\t\t\t\ttmp.emplace(stem);\n\t\t\t}\n\t\t}\n\t}\n\n\tstd::vector<std::string> result;\n\tresult.reserve(tmp.size());\n\tresult.insert(result.end(), tmp.begin(), tmp.end());\n\treturn result;\n}\n\nbool InputManager::is_valid_profilename(const std::string& name)\n{\n\tif (!IsValidFilename(name))\n\t\treturn false;\n\n\t// dont allow default profile names\n\tfor (size_t i = 0; i < kMaxController; i++)\n\t{\n\t\tif (name == fmt::format(\"controller{}\", i))\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nglm::ivec2 InputManager::get_mouse_position(bool pad_window) const\n{\n\tif (pad_window)\n\t{\n\t\tstd::shared_lock lock(m_pad_mouse.m_mutex);\n\t\treturn m_pad_mouse.position;\n\t}\n\telse\n\t{\n\t\tstd::shared_lock lock(m_main_mouse.m_mutex);\n\t\treturn m_main_mouse.position;\n\t}\n}\n\nstd::optional<glm::ivec2> InputManager::get_left_down_mouse_info(bool* is_pad)\n{\n\tif (is_pad)\n\t\t*is_pad = false;\n\n\t{\n\t\tstd::shared_lock lock(m_main_mouse.m_mutex);\n\t\tif (std::exchange(m_main_mouse.left_down_toggle, false))\n\t\t\treturn m_main_mouse.position;\n\n\t\tif (m_main_mouse.left_down)\n\t\t\treturn m_main_mouse.position;\n\t}\n\n\t{\n\t\tstd::shared_lock lock(m_main_touch.m_mutex);\n\t\tif (std::exchange(m_main_touch.left_down_toggle, false))\n\t\t\treturn m_main_touch.position;\n\n\t\tif (m_main_touch.left_down)\n\t\t\treturn m_main_touch.position;\n\t}\n\n\tif (is_pad)\n\t\t*is_pad = true;\n\n\t{\n\t\tstd::shared_lock lock(m_pad_mouse.m_mutex);\n\t\tif (std::exchange(m_pad_mouse.left_down_toggle, false))\n\t\t\treturn m_pad_mouse.position;\n\n\t\tif (m_pad_mouse.left_down)\n\t\t\treturn m_pad_mouse.position;\n\t}\n\n\t{\n\t\tstd::shared_lock lock(m_pad_touch.m_mutex);\n\t\tif (std::exchange(m_pad_touch.left_down_toggle, false))\n\t\t\treturn m_pad_touch.position;\n\n\t\tif (m_pad_touch.left_down)\n\t\t\treturn m_pad_touch.position;\n\t}\n\n\treturn {};\n}\n\nstd::optional<glm::ivec2> InputManager::get_right_down_mouse_info(bool* is_pad)\n{\n\tif (is_pad)\n\t\t*is_pad = false;\n\n\t{\n\t\tstd::shared_lock lock(m_main_mouse.m_mutex);\n\t\tif (std::exchange(m_main_mouse.right_down_toggle, false))\n\t\t\treturn m_main_mouse.position;\n\n\t\tif (m_main_mouse.right_down)\n\t\t\treturn m_main_mouse.position;\n\t}\n\n\t{\n\t\tstd::shared_lock lock(m_main_touch.m_mutex);\n\t\tif (std::exchange(m_main_touch.right_down_toggle, false))\n\t\t\treturn m_main_touch.position;\n\n\t\tif (m_main_touch.right_down)\n\t\t\treturn m_main_touch.position;\n\t}\n\n\tif (is_pad)\n\t\t*is_pad = true;\n\n\t{\n\t\tstd::shared_lock lock(m_pad_mouse.m_mutex);\n\t\tif (std::exchange(m_pad_mouse.right_down_toggle, false))\n\t\t\treturn m_pad_mouse.position;\n\n\t\tif (m_pad_mouse.right_down)\n\t\t\treturn m_pad_mouse.position;\n\t}\n\n\t{\n\t\tstd::shared_lock lock(m_pad_touch.m_mutex);\n\t\tif (std::exchange(m_pad_touch.right_down_toggle, false))\n\t\t\treturn m_pad_touch.position;\n\n\t\tif (m_pad_touch.right_down)\n\t\t\treturn m_pad_touch.position;\n\t}\n\n\treturn {};\n}\n\nvoid InputManager::update_thread()\n{\n\tSetThreadName(\"Input_update\");\n\twhile (!m_update_thread_shutdown.load(std::memory_order::relaxed))\n\t{\n\t\tstd::shared_lock lock(m_mutex);\n\t\tfor (auto& pad : m_vpad)\n\t\t{\n\t\t\tif (pad)\n\t\t\t\tpad->update();\n\t\t}\n\n\t\tfor (auto& pad : m_wpad)\n\t\t{\n\t\t\tif (pad)\n\t\t\t\tpad->update();\n\t\t}\n\t\tlock.unlock();\n\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\tstd::this_thread::yield();\n\t}\n}\n"
  },
  {
    "path": "src/input/InputManager.h",
    "content": "#pragma once\n\n#if BOOST_OS_WINDOWS\n#include \"input/api/DirectInput/DirectInputControllerProvider.h\"\n#include \"input/api/XInput/XInputControllerProvider.h\"\n#endif\n\n#ifdef SUPPORTS_WIIMOTE\n#include \"input/api/Wiimote/WiimoteControllerProvider.h\"\n#endif\n\n#include \"util/helpers/Singleton.h\"\n\n#include \"input/api/SDL/SDLControllerProvider.h\"\n#include \"input/api/Keyboard/KeyboardControllerProvider.h\"\n#include \"input/api/DSU/DSUControllerProvider.h\"\n#include \"input/api/GameCube/GameCubeControllerProvider.h\"\n\n#include \"input/emulated/VPADController.h\"\n#include \"input/emulated/WPADController.h\"\n\n#include <atomic>\n#include <optional>\n\nclass InputManager : public Singleton<InputManager>\n{\n\tfriend class Singleton<InputManager>;\n\tInputManager();\n\t~InputManager();\n\n\tfriend class MainWindow;\n\tfriend class PadViewFrame;\n\npublic:\n\tconstexpr static size_t kMaxController = 8;\n\tconstexpr static size_t kMaxVPADControllers = 2;\n\tconstexpr static size_t kMaxWPADControllers = 7;\n\t\n\tvoid load() noexcept;\n\tbool load(size_t player_index, std::string_view filename = {});\n\n\tbool migrate_config(const fs::path& file_path);\n\n\tvoid save() noexcept;\n\tbool save(size_t player_index, std::string_view filename = {});\n\n\tbool is_gameprofile_set(size_t player_index) const;\n\n\tEmulatedControllerPtr set_controller(EmulatedControllerPtr controller);\n\tEmulatedControllerPtr set_controller(size_t player_index, EmulatedController::Type type);\n\tEmulatedControllerPtr set_controller(size_t player_index, EmulatedController::Type type, const std::shared_ptr<ControllerBase>& controller);\n\n\tEmulatedControllerPtr delete_controller(size_t player_index, bool delete_profile = false);\n\t\n\tEmulatedControllerPtr get_controller(size_t player_index) const;\n\tstd::shared_ptr<VPADController> get_vpad_controller(size_t index) const;\n\tstd::shared_ptr<WPADController> get_wpad_controller(size_t index) const;\n\tstd::pair<size_t, size_t> get_controller_count() const;\n\n\tbool is_api_available(InputAPI::Type api) const { return !m_api_available[api].empty(); }\n\t\n\tControllerProviderPtr get_api_provider(std::string_view api_name) const;\n\tControllerProviderPtr get_api_provider(InputAPI::Type api) const;\n\t// will create the provider with the given settings if it doesn't exist yet\n\tControllerProviderPtr get_api_provider(InputAPI::Type api, const ControllerProviderSettings& settings);\n\n\tconst auto& get_api_providers() const\n\t{\n\t\treturn m_api_available;\n\t}\n\n\tvoid apply_game_profile();\n\tvoid on_device_changed();\n\n\n\tstatic std::vector<std::string> get_profiles();\n\tstatic bool is_valid_profilename(const std::string& name);\n\n\tstruct MouseInfo\n\t{\n\t\tmutable std::shared_mutex m_mutex;\n\t\tglm::ivec2 position{};\n\t\tbool left_down = false;\n\t\tbool right_down = false;\n\n\t\tbool left_down_toggle = false;\n\t\tbool right_down_toggle = false;\n\t} m_main_mouse{}, m_pad_mouse{}, m_main_touch{}, m_pad_touch{};\n\tglm::ivec2 get_mouse_position(bool pad_window) const;\n\tstd::optional<glm::ivec2> get_left_down_mouse_info(bool* is_pad);\n\tstd::optional<glm::ivec2> get_right_down_mouse_info(bool* is_pad);\n\n\tstd::atomic<float> m_mouse_wheel;\n\nprivate:\n\tvoid update_thread();\n\n\tstd::thread m_update_thread;\n\tstd::atomic<bool> m_update_thread_shutdown{false};\n\n\tstd::array<std::vector<ControllerProviderPtr>, InputAPI::MAX> m_api_available{ };\n\n\tmutable std::shared_mutex m_mutex;\n\tstd::array<EmulatedControllerPtr, kMaxVPADControllers> m_vpad;\n\tstd::array<EmulatedControllerPtr, kMaxWPADControllers> m_wpad;\n\n\tstd::array<bool, kMaxController> m_is_gameprofile_set{};\n\n\ttemplate <typename TProvider>\n\tvoid create_provider() // lambda templates only work in c++20 -> define locally in ctor\n\t{\n\t\tstatic_assert(std::is_base_of_v<ControllerProviderBase, TProvider>);\n\t\ttry\n\t\t{\n\t\t\tauto controller = std::make_shared<TProvider>();\n\t\t\tm_api_available[controller->api()] = std::vector<ControllerProviderPtr>{ controller };\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, ex.what());\n\t\t}\n\t}\n};\n"
  },
  {
    "path": "src/input/api/Controller.cpp",
    "content": "#include \"input/api/Controller.h\"\n#include \"config/CemuConfig.h\"\n#include \"WindowSystem.h\"\n\nControllerBase::ControllerBase(std::string_view uuid, std::string_view display_name)\n\t: m_uuid{uuid}, m_display_name{display_name}\n{\n}\n\nconst ControllerState& ControllerBase::update_state()\n{\n\tif (!m_is_calibrated)\n\t\tcalibrate();\n\n\tControllerState result = raw_state();\n\n\t// ignore default buttons\n\tresult.buttons.UnsetButtons(m_default_state.buttons);\n\t// apply deadzone and range and ignore default axis values\n\tapply_axis_setting(result.axis, m_default_state.axis, m_settings.axis);\n\tapply_axis_setting(result.rotation, m_default_state.rotation, m_settings.rotation);\n\tapply_axis_setting(result.trigger, m_default_state.trigger, m_settings.trigger);\n\n#define APPLY_AXIS_BUTTON(_axis_, _flag_) \\\n\tif (result._axis_.x < -ControllerState::kAxisThreshold) \\\n\t\tresult.buttons.SetButtonState((_flag_) + (kAxisXN - kAxisXP), true); \\\n\telse if (result._axis_.x > ControllerState::kAxisThreshold) \\\n\t\tresult.buttons.SetButtonState((_flag_), true); \\\n\tif (result._axis_.y < -ControllerState::kAxisThreshold) \\\n\t\tresult.buttons.SetButtonState((_flag_) + 1 + (kAxisXN - kAxisXP), true); \\\n\telse if (result._axis_.y > ControllerState::kAxisThreshold) \\\n\t\tresult.buttons.SetButtonState((_flag_) + 1, true);\n\n\tif (result.axis.x < -ControllerState::kAxisThreshold) \n\t\tresult.buttons.SetButtonState((kAxisXP) + (kAxisXN - kAxisXP), true);\n\telse if (result.axis.x > ControllerState::kAxisThreshold) \n\t\tresult.buttons.SetButtonState((kAxisXP), true);\n\tif (result.axis.y < -ControllerState::kAxisThreshold) \n\t\tresult.buttons.SetButtonState((kAxisXP) + 1 + (kAxisXN - kAxisXP), true);\n\telse if (result.axis.y > ControllerState::kAxisThreshold) \n\t\tresult.buttons.SetButtonState((kAxisXP) + 1, true);\n\tAPPLY_AXIS_BUTTON(rotation, kRotationXP);\n\tAPPLY_AXIS_BUTTON(trigger, kTriggerXP);\n\n\t/*\n// positive values\n\tkAxisXP,\n\tkAxisYP,\n\n\tkRotationXP,\n\tkRotationYP,\n\n\tkTriggerXP,\n\tkTriggerYP,\n\n\t// negative values\n\tkAxisXN,\n\tkAxisYN,\n\n\tkRotationXN,\n\tkRotationYN,\n\n\tkTriggerXN,\n\tkTriggerYN,\n\t */\n\n\n#undef APPLY_AXIS_BUTTON\n\n\tWindowSystem::CaptureInput(result, m_last_state);\n\n\tm_last_state = std::move(result);\n\treturn m_last_state;\n}\n\nvoid ControllerBase::apply_axis_setting(glm::vec2& axis, const glm::vec2& default_value,\n                                        const AxisSetting& setting) const\n{\n\tconstexpr float kMaxValue = 1.0f + ControllerState::kMinAxisValue;\n\tif (setting.deadzone < 1.0f)\n\t{\n\t\tif (axis.x < default_value.x)\n\t\t\taxis.x = (axis.x - default_value.x) / (kMaxValue + default_value.x);\n\t\telse\n\t\t\taxis.x = (axis.x - default_value.x) / (kMaxValue - default_value.x);\n\n\t\tif (axis.y < default_value.y)\n\t\t\taxis.y = (axis.y - default_value.y) / (kMaxValue + default_value.y);\n\t\telse\n\t\t\taxis.y = (axis.y - default_value.y) / (kMaxValue - default_value.y);\n\n\t\tauto len = length(axis);\n\t\tif (len >= setting.deadzone)\n\t\t{\n\t\t\taxis *= setting.range;\n\t\t\tlen = length(axis);\n\n\t\t\t// Scaled Radial Dead Zone: stickInput = stickInput.normalized * ((stickInput.magnitude - deadzone) / (1 - deadzone));\n\t\t\tif (len > 0)\n\t\t\t{\n\t\t\t\taxis = normalize(axis);\n\t\t\t\taxis *= ((len - setting.deadzone) / (kMaxValue - setting.deadzone));\n\n\t\t\t\tif (length(axis) > 1.0f)\n\t\t\t\t\taxis = normalize(axis);\n\t\t\t}\n\n\t\t\tif (axis.x != 0 || axis.y != 0)\n\t\t\t{\n\t\t\t\tif (std::abs(axis.x) < ControllerState::kMinAxisValue)\n\t\t\t\t\taxis.x = ControllerState::kMinAxisValue;\n\n\t\t\t\tif (std::abs(axis.y) < ControllerState::kMinAxisValue)\n\t\t\t\t\taxis.y = ControllerState::kMinAxisValue;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\taxis = {0, 0};\n}\n\nbool ControllerBase::operator==(const ControllerBase& c) const\n{\n\treturn api() == c.api() && uuid() == c.uuid();\n}\n\nfloat ControllerBase::get_axis_value(uint64 button) const\n{\n\tif (m_last_state.buttons.GetButtonState(button))\n\t{\n\t\tif (button <= kButtonNoneAxisMAX || !has_axis())\n\t\t\treturn 1.0f;\n\n\t\tswitch (button)\n\t\t{\n\t\tcase kAxisXP:\n\t\tcase kAxisXN:\n\t\t\treturn std::abs(m_last_state.axis.x);\n\t\tcase kAxisYP:\n\t\tcase kAxisYN:\n\t\t\treturn std::abs(m_last_state.axis.y);\n\n\t\tcase kRotationXP:\n\t\tcase kRotationXN:\n\t\t\treturn std::abs(m_last_state.rotation.x);\n\t\tcase kRotationYP:\n\t\tcase kRotationYN:\n\t\t\treturn std::abs(m_last_state.rotation.y);\n\n\t\tcase kTriggerXP:\n\t\tcase kTriggerXN:\n\t\t\treturn std::abs(m_last_state.trigger.x);\n\t\tcase kTriggerYP:\n\t\tcase kTriggerYN:\n\t\t\treturn std::abs(m_last_state.trigger.y);\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nconst ControllerState& ControllerBase::calibrate()\n{\n\tm_default_state = raw_state();\n\tm_is_calibrated = is_connected();\n\treturn m_default_state;\n}\n\n\nstd::string ControllerBase::get_button_name(uint64 button) const\n{\n\tswitch (button)\n\t{\n\tcase kButtonZL: return \"ZL\";\n\tcase kButtonZR: return \"ZR\";\n\n\tcase kButtonUp: return \"DPAD-Up\";\n\tcase kButtonDown: return \"DPAD-Down\";\n\tcase kButtonLeft: return \"DPAD-Left\";\n\tcase kButtonRight: return \"DPAD-Right\";\n\n\tcase kAxisXP: return \"X-Axis+\";\n\tcase kAxisYP: return \"Y-Axis+\";\n\n\tcase kAxisXN: return \"X-Axis-\";\n\tcase kAxisYN: return \"Y-Axis-\";\n\n\tcase kRotationXP: return \"X-Rotation+\";\n\tcase kRotationYP: return \"Y-Rotation+\";\n\n\tcase kRotationXN: return \"X-Rotation-\";\n\tcase kRotationYN: return \"Y-Rotation-\";\n\n\tcase kTriggerXP: return \"X-Trigger+\";\n\tcase kTriggerYP: return \"Y-Trigger+\";\n\n\tcase kTriggerXN: return \"X-Trigger-\";\n\tcase kTriggerYN: return \"y-Trigger-\";\n\t}\n\n\n\treturn fmt::format(\"Button {}\", (uint64)button);\n}\n\nControllerBase::Settings ControllerBase::get_settings() const\n{\n\tstd::scoped_lock lock(m_settings_mutex);\n\treturn m_settings;\n}\n\nvoid ControllerBase::set_settings(const Settings& settings)\n{\n\tstd::scoped_lock lock(m_settings_mutex);\n\tm_settings = settings;\n}\n\nvoid ControllerBase::set_axis_settings(const AxisSetting& settings)\n{\n\tstd::scoped_lock lock(m_settings_mutex);\n\tm_settings.axis = settings;\n}\n\nvoid ControllerBase::set_rotation_settings(const AxisSetting& settings)\n{\n\tstd::scoped_lock lock(m_settings_mutex);\n\tm_settings.rotation = settings;\n}\n\nvoid ControllerBase::set_trigger_settings(const AxisSetting& settings)\n{\n\tstd::scoped_lock lock(m_settings_mutex);\n\tm_settings.trigger = settings;\n}\n\nvoid ControllerBase::set_rumble(float rumble)\n{\n\tstd::scoped_lock lock(m_settings_mutex);\n\tm_settings.rumble = rumble;\n}\n\nvoid ControllerBase::set_use_motion(bool state)\n{\n\tstd::scoped_lock lock(m_settings_mutex);\n\tm_settings.motion = state;\n}\n"
  },
  {
    "path": "src/input/api/Controller.h",
    "content": "#pragma once\n\n#include \"input/InputManager.h\"\n#include \"input/motion/MotionSample.h\"\n#include \"input/api/ControllerState.h\"\n\nnamespace pugi\n{\n\tclass xml_node;\n}\n\nenum Buttons2 : uint64\n{\n\t// General\n\tkButton0,\n\tkButton1,\n\tkButton2,\n\tkButton3,\n\tkButton4,\n\tkButton5,\n\tkButton6,\n\tkButton7,\n\tkButton8,\n\tkButton9,\n\tkButton10,\n\tkButton11,\n\tkButton12,\n\tkButton13,\n\tkButton14,\n\tkButton15,\n\tkButton16,\n\tkButton17,\n\tkButton18,\n\tkButton19,\n\tkButton20,\n\tkButton21,\n\tkButton22,\n\tkButton23,\n\tkButton24,\n\tkButton25,\n\tkButton26,\n\tkButton27,\n\tkButton28,\n\tkButton29,\n\tkButton30,\n\tkButton31,\n\n\t// Trigger\n\tkButtonZL,\n\tkButtonZR,\n\n\t// DPAD\n\tkButtonUp,\n\tkButtonDown,\n\tkButtonLeft,\n\tkButtonRight,\n\n\t// positive values\n\tkAxisXP,\n\tkAxisYP,\n\n\tkRotationXP,\n\tkRotationYP,\n\n\tkTriggerXP,\n\tkTriggerYP,\n\n\t// negative values\n\tkAxisXN,\n\tkAxisYN,\n\n\tkRotationXN,\n\tkRotationYN,\n\n\tkTriggerXN,\n\tkTriggerYN,\n\t\n\tkButtonMAX,\n\n\tkButtonNoneAxisMAX = kButtonRight,\n\tkButtonAxisStart = kAxisXP,\n};\n\nclass ControllerBase\n{\npublic:\n\tControllerBase(std::string_view uuid, std::string_view display_name);\n\tvirtual ~ControllerBase() = default;\n\n\tconst std::string& uuid() const { return m_uuid; }\n\tconst std::string& display_name() const { return m_display_name; }\n\t\n\tvirtual std::string_view api_name() const = 0;\n\tvirtual InputAPI::Type api() const = 0;\n\n\tvirtual void update() {}\n\n\tvirtual bool connect() { return is_connected(); }\n\tvirtual bool is_connected() = 0;\n\t\t\n\tvirtual bool has_battery() { return false; }\n\tvirtual bool has_low_battery() { return false; }\n\n\tconst ControllerState& calibrate();\n\tconst ControllerState& update_state();\n\tconst ControllerState& get_state() const { return m_last_state; }\n\tconst ControllerState& get_default_state() { return is_calibrated() ? m_default_state : calibrate(); }\n\tvirtual ControllerState raw_state() = 0;\n\n\tbool is_calibrated() const { return m_is_calibrated; }\n\n\tfloat get_axis_value(uint64 button) const;\n\tvirtual bool has_axis() const { return true; }\n\n\tbool use_motion() { return has_motion() && m_settings.motion; }\n\tvirtual bool has_motion() { return false; }\n\tvirtual MotionSample get_motion_sample() { return {}; }\n\n\tvirtual bool has_position() { return false; }\n\tvirtual glm::vec2 get_position() { return {}; }\n\tvirtual glm::vec2 get_prev_position() { return {}; }\n\tvirtual PositionVisibility GetPositionVisibility() {return PositionVisibility::NONE;};\n\n\tvirtual bool has_rumble() { return false; }\n\tvirtual void start_rumble() {}\n\tvirtual void stop_rumble() {}\n\n\tvirtual std::string get_button_name(uint64 button) const;\n\n\tvirtual void save(pugi::xml_node& node){}\n\tvirtual void load(const pugi::xml_node& node){}\n\n\tstruct AxisSetting\n\t{\n\t\tAxisSetting(float deadzone = 0.25f) : deadzone(deadzone) {}\n\t\tfloat deadzone;\n\t\tfloat range = 1.0f;\n\t};\n\tstruct Settings\n\t{\n\t\tAxisSetting axis{}, rotation{}, trigger{};\n\t\tfloat rumble = 0;\n\t\tbool motion = false; // only valid when has_motion is true\n\t};\n\tSettings get_settings() const;\n\tvoid set_settings(const Settings& settings);\n\tvoid set_axis_settings(const AxisSetting& settings);\n\tvoid set_rotation_settings(const AxisSetting& settings);\n\tvoid set_trigger_settings(const AxisSetting& settings);\n\tvoid set_rumble(float rumble);\n\tvoid set_use_motion(bool state);\n\n\tvoid apply_axis_setting(glm::vec2& axis, const glm::vec2& default_value, const AxisSetting& setting) const;\n\n\tbool operator==(const ControllerBase& c) const;\n\tbool operator!=(const ControllerBase& c) const { return !(*this == c); }\n\nprotected:\n\tstd::string m_uuid;\n\tstd::string m_display_name;\n\n\tControllerState m_last_state{};\n\n\tbool m_is_calibrated = false;\n\tControllerState m_default_state{};\n\n\tmutable std::mutex m_settings_mutex;\n\tSettings m_settings{};\n};\n\ntemplate<class TProvider>\nclass Controller : public ControllerBase\n{\npublic:\n\tController(std::string_view uuid, std::string_view display_name)\n\t\t: ControllerBase(uuid, display_name)\n\t{\n\t\tstatic_assert(std::is_base_of_v<ControllerProviderBase, TProvider>);\n\t\tm_provider = std::dynamic_pointer_cast<TProvider>(InputManager::instance().get_api_provider(TProvider::kAPIType));\n\t\tcemu_assert_debug(m_provider != nullptr);\n\t}\n\n\tController(std::string_view uuid, std::string_view display_name, const ControllerProviderSettings& settings)\n\t\t: ControllerBase(uuid, display_name)\n\t{\n\t\tstatic_assert(std::is_base_of_v<ControllerProviderBase, TProvider>);\n\t\tm_provider = std::dynamic_pointer_cast<TProvider>(InputManager::instance().get_api_provider(TProvider::kAPIType, settings));\n\t\tcemu_assert_debug(m_provider != nullptr);\n\t}\n\n\t// update provider if settings are different from default provider\n\tvoid update_provider(std::shared_ptr<TProvider> provider)\n\t{\n\t\tm_provider = std::move(provider);\n\t}\n\nprotected:\n\tusing base_type = Controller<TProvider>;\n\tstd::shared_ptr<TProvider> m_provider;\n};\n\nusing ControllerPtr = std::shared_ptr<ControllerBase>;\n\n"
  },
  {
    "path": "src/input/api/ControllerProvider.h",
    "content": "#pragma once\n\n#include \"input/api/InputAPI.h\"\n\nclass ControllerBase;\n\nstruct ControllerProviderSettings\n{\n\tvirtual ~ControllerProviderSettings() = default;\n\tvirtual bool operator==(const ControllerProviderSettings&) const = 0;\n};\n\nclass ControllerProviderBase\n{\npublic:\n\tControllerProviderBase() = default;\n\tvirtual ~ControllerProviderBase() = default;\n\n\tvirtual InputAPI::Type api() const = 0;\n\tstd::string_view api_name() const { return to_string(api()); }\n\n\tvirtual std::vector<std::shared_ptr<ControllerBase>> get_controllers() = 0;\n\n\tvirtual bool has_settings() const\n\t{\n\t\treturn false;\n\t}\n\n\tvirtual bool operator==(const ControllerProviderBase& p) const\n\t{\n\t\treturn api() == p.api();\n\t}\n\tvirtual bool operator==(const ControllerProviderSettings& p) const\n\t{\n\t\treturn false;\n\t}\n};\n\nusing ControllerProviderPtr = std::shared_ptr<ControllerProviderBase>;\n\ntemplate <typename TSettings>\nclass ControllerProvider : public ControllerProviderBase\n{\n\tusing base_type = ControllerProviderBase;\npublic:\n\tControllerProvider() = default;\n\n\tControllerProvider(const TSettings& settings)\n\t\t: m_settings(settings)\n\t{}\n\n\tbool has_settings() const override\n\t{\n\t\treturn true;\n\t}\n\n\tconst TSettings& get_settings() const\n\t{\n\t\treturn m_settings;\n\t}\n\n\tbool operator==(const ControllerProviderBase& p) const override\n\t{\n\t\tif (!base_type::operator==(p))\n\t\t\treturn false;\n\n\t\tif (!p.has_settings())\n\t\t\treturn false;\n\n\t\tauto* ptr = dynamic_cast<const ControllerProvider<TSettings>*>(&p);\n\t\tif (!ptr)\n\t\t\treturn false;\n\n\t\treturn base_type::operator==(p) && m_settings == ptr->m_settings;\n\t}\n\n\tbool operator==(const ControllerProviderSettings& p) const override\n\t{\n\t\tauto* ptr = dynamic_cast<const TSettings*>(&p);\n\t\tif (!ptr)\n\t\t\treturn false;\n\n\t\treturn m_settings == *ptr;\n\t}\n\nprotected:\n\tTSettings m_settings{};\n};\n"
  },
  {
    "path": "src/input/api/ControllerState.cpp",
    "content": "﻿#include \"input/api/ControllerState.h\"\n\nbool ControllerState::operator==(const ControllerState& other) const\n{\n\treturn buttons == other.buttons;\n\t\t/*&& (std::signbit(axis.x) == std::signbit(other.axis.x) && std::abs(axis.x - other.axis.x) <= kAxisThreshold)\n\t\t&& (std::signbit(axis.y) == std::signbit(other.axis.y) && std::abs(axis.y - other.axis.y) <= kAxisThreshold)\n\t\t&& (std::signbit(rotation.x) == std::signbit(other.rotation.x) && std::abs(rotation.x - other.rotation.x) <= kAxisThreshold)\n\t\t&& (std::signbit(rotation.y) == std::signbit(other.rotation.y) && std::abs(rotation.y - other.rotation.y) <= kAxisThreshold)\n\t\t&& (std::signbit(trigger.x) == std::signbit(other.trigger.x) && std::abs(trigger.x - other.trigger.x) <= kAxisThreshold)\n\t\t&& (std::signbit(trigger.y) == std::signbit(other.trigger.y) && std::abs(trigger.y - other.trigger.y) <= kAxisThreshold);*/\n\t\t\n}\n"
  },
  {
    "path": "src/input/api/ControllerState.h",
    "content": "﻿#pragma once\n\n#include <glm/vec2.hpp>\n#include \"util/helpers/fspinlock.h\"\n\nenum class PositionVisibility {\n\tNONE = 0,\n\tFULL = 1,\n\tPARTIAL = 2\n};\n\n// helper class for storing and managing button press states in a thread-safe manner\nstruct ControllerButtonState\n{\n\tControllerButtonState() = default;\n\tControllerButtonState(const ControllerButtonState& other)\n\t{\n\t\tthis->m_pressedButtons = other.m_pressedButtons;\n\t}\n\n\tControllerButtonState(ControllerButtonState&& other)\n\t{\n\t\tthis->m_pressedButtons = std::move(other.m_pressedButtons);\n\t}\n\n\tvoid SetButtonState(uint32 buttonId, bool isPressed)\n\t{\n\t\tstd::lock_guard _l(this->m_spinlock);\n\t\tif (isPressed)\n\t\t{\n\t\t\tif (std::find(m_pressedButtons.cbegin(), m_pressedButtons.cend(), buttonId) != m_pressedButtons.end())\n\t\t\t\treturn;\n\t\t\tm_pressedButtons.emplace_back(buttonId);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::erase(m_pressedButtons, buttonId);\n\t\t}\n\t}\n\n\t// set multiple buttons at once within a single lock interval\n\tvoid SetPressedButtons(std::span<uint32> buttonList)\n\t{\n\t\tstd::lock_guard _l(this->m_spinlock);\n\t\tfor (auto& buttonId : buttonList)\n\t\t{\n\t\t\tif (std::find(m_pressedButtons.cbegin(), m_pressedButtons.cend(), buttonId) == m_pressedButtons.end())\n\t\t\t\tm_pressedButtons.emplace_back(buttonId);\n\t\t}\n\t}\n\n\t// returns true if pressed\n\tbool GetButtonState(uint32 buttonId) const\n\t{\n\t\tstd::lock_guard _l(this->m_spinlock);\n\t\tbool r = std::find(m_pressedButtons.cbegin(), m_pressedButtons.cend(), buttonId) != m_pressedButtons.cend();\n\t\treturn r;\n\t}\n\n\t// remove pressed state for all pressed buttons in buttonsToUnset\n\tvoid UnsetButtons(const ControllerButtonState& buttonsToUnset)\n\t{\n\t\tstd::scoped_lock _l(this->m_spinlock, buttonsToUnset.m_spinlock);\n\t\tfor (auto it = m_pressedButtons.begin(); it != m_pressedButtons.end();)\n\t\t{\n\t\t\tif (std::find(buttonsToUnset.m_pressedButtons.cbegin(), buttonsToUnset.m_pressedButtons.cend(), *it) == buttonsToUnset.m_pressedButtons.cend())\n\t\t\t{\n\t\t\t\t++it;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tit = m_pressedButtons.erase(it);\n\t\t}\n\t}\n\n\t// returns true if no buttons are pressed\n\tbool IsIdle() const\n\t{\n\t\tstd::lock_guard _l(this->m_spinlock);\n\t\tconst bool r = m_pressedButtons.empty();\n\t\treturn r;\n\t}\n\n\tstd::vector<uint32> GetButtonList() const\n\t{\n\t\tstd::lock_guard _l(this->m_spinlock);\n\t\tstd::vector<uint32> copy = m_pressedButtons;\n\t\treturn copy;\n\t}\n\n\tbool operator==(const ControllerButtonState& other) const\n\t{\n\t\tstd::scoped_lock _l(this->m_spinlock, other.m_spinlock);\n\t\tauto& otherButtons = other.m_pressedButtons;\n\t\tif (m_pressedButtons.size() != otherButtons.size())\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\tfor (auto& buttonId : m_pressedButtons)\n\t\t{\n\t\t\tif (std::find(otherButtons.cbegin(), otherButtons.cend(), buttonId) == otherButtons.cend())\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tControllerButtonState& operator=(ControllerButtonState&& other)\n\t{\n\t\tcemu_assert_debug(!other.m_spinlock.is_locked());\n\t\tstd::scoped_lock _l(this->m_spinlock, other.m_spinlock);\n\t\tthis->m_pressedButtons = std::move(other.m_pressedButtons);\n\t\treturn *this;\n\t}\n\nprivate:\n\tstd::vector<uint32> m_pressedButtons; // since only very few buttons are pressed at a time, using a vector with linear scan is more efficient than a set/map\n\tmutable FSpinlock m_spinlock;\n};\n\nstruct ControllerState\n{\n\t// when does a axis counts as pressed\n\tconstexpr static float kAxisThreshold = 0.1f;\n\n\t// on the real console the stick x or y values never really reach 0.0 if one of the axis is moved\n\t// some games rely on this due to incorrectly checking if the stick is tilted via if (vstick.x != 0 && vstick.y != 0)\n\t// here we simulate a slight bias if the axis is almost perfectly centered\n\tconstexpr static float kMinAxisValue = 0.0000001f;\n\n\t// [-1; 1]\n\tglm::vec2 axis{ };\n\tglm::vec2 rotation{ };\n\tglm::vec2 trigger{ };\n\n\tControllerButtonState buttons{};\n\n\tuint64 last_state = 0;\n\n\tbool operator==(const ControllerState& other) const;\n\tbool operator!=(const ControllerState& other) const\n\t{\n\t\treturn !(*this == other);\n\t}\n};\n"
  },
  {
    "path": "src/input/api/DSU/DSUController.cpp",
    "content": "#include \"input/api/DSU/DSUController.h\"\n\n#include <boost/program_options/value_semantic.hpp>\n\nDSUController::DSUController(uint32 index)\n\t: base_type(fmt::format(\"{}\", index), fmt::format(\"Controller {}\", index + 1)), m_index(index)\n{\n\tif (index >= DSUControllerProvider::kMaxClients)\n\t\tthrow std::runtime_error(fmt::format(\"max {} dsu controllers are supported! given index: {}\",\n\t\t                                     DSUControllerProvider::kMaxClients, index));\n}\n\nDSUController::DSUController(uint32 index, const DSUProviderSettings& settings)\n\t: base_type(fmt::format(\"{}\", index), fmt::format(\"Controller {}\", index + 1), settings), m_index(index)\n{\n\tif (index >= DSUControllerProvider::kMaxClients)\n\t\tthrow std::runtime_error(fmt::format(\"max {} dsu controllers are supported! given index: {}\",\n\t\t\tDSUControllerProvider::kMaxClients, index));\n}\n\nvoid DSUController::save(pugi::xml_node& node)\n{\n\tbase_type::save(node);\n\n\tnode.append_child(\"ip\").append_child(pugi::node_pcdata).set_value(\n\t\tfmt::format(\"{}\", m_provider->get_settings().ip).c_str());\n\tnode.append_child(\"port\").append_child(pugi::node_pcdata).set_value(\n\t\tfmt::format(\"{}\", m_provider->get_settings().port).c_str());\n}\n\nvoid DSUController::load(const pugi::xml_node& node)\n{\n\tbase_type::load(node);\n\n\tDSUProviderSettings settings;\n\tif (const auto value = node.child(\"ip\"))\n\t\tsettings.ip = value.child_value();\n\tif (const auto value = node.child(\"port\"))\n\t\tsettings.port = ConvertString<uint16>(value.child_value());\n\n\tconst auto provider = InputManager::instance().get_api_provider(api(), settings);\n\tupdate_provider(std::dynamic_pointer_cast<DSUControllerProvider>(provider));\n\tconnect();\n}\n\nbool DSUController::connect()\n{\n\tif (is_connected())\n\t\treturn true;\n\n\tm_provider->request_pad_data(m_index);\n\treturn is_connected();\n}\n\nbool DSUController::is_connected()\n{\n\treturn m_provider->is_connected(m_index);\n}\n\nMotionSample DSUController::get_motion_sample()\n{\n\treturn m_provider->get_motion_sample(m_index);\n}\n\nbool DSUController::has_position()\n{\n\tconst auto state = m_provider->get_state(m_index);\n\treturn state.data.tpad1.active || state.data.tpad2.active;\n}\n\nglm::vec2 DSUController::get_position()\n{\n\t// touchpad resolution is 1920x942\n\tconst auto state = m_provider->get_state(m_index);\n\tif (state.data.tpad1.active)\n\t\treturn glm::vec2{(float)state.data.tpad1.x / 1920.0f, (float)state.data.tpad1.y / 942.0f};\n\n\tif (state.data.tpad2.active)\n\t\treturn glm::vec2{(float)state.data.tpad2.x / 1920.0f, (float)state.data.tpad2.y / 942.0f};\n\n\treturn {};\n}\n\nglm::vec2 DSUController::get_prev_position()\n{\n\tconst auto state = m_provider->get_prev_state(m_index);\n\tif (state.data.tpad1.active)\n\t\treturn glm::vec2{(float)state.data.tpad1.x / 1920.0f, (float)state.data.tpad1.y / 942.0f};\n\n\tif (state.data.tpad2.active)\n\t\treturn glm::vec2{(float)state.data.tpad2.x / 1920.0f, (float)state.data.tpad2.y / 942.0f};\n\n\treturn {};\n}\n\nPositionVisibility DSUController::GetPositionVisibility()\n{\n\tconst auto state = m_provider->get_prev_state(m_index);\n\n\treturn (state.data.tpad1.active || state.data.tpad2.active) ? PositionVisibility::FULL : PositionVisibility::NONE;\n}\n\nstd::string DSUController::get_button_name(uint64 button) const\n{\n\tswitch (button)\n\t{\n\tcase kButton0: return \"Share\";\n\tcase kButton1: return \"Stick L\";\n\tcase kButton2: return \"Stick R\";\n\tcase kButton3: return \"Options\";\n\tcase kButton4: return \"Up\";\n\tcase kButton5: return \"Right\";\n\tcase kButton6: return \"Down\";\n\tcase kButton7: return \"Left\";\n\n\tcase kButton8: return \"ZL\";\n\tcase kButton9: return \"ZR\";\n\tcase kButton10: return \"L\";\n\tcase kButton11: return \"R\";\n\tcase kButton12: return \"Triangle\";\n\tcase kButton13: return \"Circle\";\n\tcase kButton14: return \"Cross\";\n\tcase kButton15: return \"Square\";\n\n\tcase kButton16: return \"Touch\";\n\t}\n\treturn base_type::get_button_name(button);\n}\n\nControllerState DSUController::raw_state()\n{\n\tControllerState result{};\n\n\tif (!is_connected())\n\t\treturn result;\n\n\tconst auto state = m_provider->get_state(m_index);\n\t// didn't read any data from the controller yet\n\tif (state.info.state != DsState::Connected)\n\t\treturn result;\n\n\tint bitindex = 0;\n\tfor (int i = 0; i < 8; ++i, ++bitindex)\n\t{\n\t\tif (HAS_BIT(state.data.state1, i))\n\t\t{\n\t\t\tresult.buttons.SetButtonState(bitindex, true);\n\t\t}\n\t}\n\n\tfor (int i = 0; i < 8; ++i, ++bitindex)\n\t{\n\t\tif (HAS_BIT(state.data.state2, i))\n\t\t{\n\t\t\tresult.buttons.SetButtonState(bitindex, true);\n\t\t}\n\t}\n\n\tif (state.data.touch)\n\t\tresult.buttons.SetButtonState(kButton16, true);\n\n\tresult.axis.x = (float)state.data.lx / std::numeric_limits<uint8>::max();\n\tresult.axis.x = (result.axis.x * 2.0f) - 1.0f;\n\n\tresult.axis.y = (float)state.data.ly / std::numeric_limits<uint8>::max();\n\tresult.axis.y = (result.axis.y * 2.0f) - 1.0f;\n\n\tresult.rotation.x = (float)state.data.rx / std::numeric_limits<uint8>::max();\n\tresult.rotation.x = (result.rotation.x * 2.0f) - 1.0f;\n\n\tresult.rotation.y = (float)state.data.ry / std::numeric_limits<uint8>::max();\n\tresult.rotation.y = (result.rotation.y * 2.0f) - 1.0f;\n\n    result.trigger.x = (float)state.data.l2 / std::numeric_limits<uint8>::max();\n    result.trigger.y = (float)state.data.r2 / std::numeric_limits<uint8>::max();\n\n    return result;\n}\n"
  },
  {
    "path": "src/input/api/DSU/DSUController.h",
    "content": "#pragma once\n\n#include \"input/api/Controller.h\"\n#include \"input/api/DSU/DSUControllerProvider.h\"\n#include \"Cafe/HW/AI/AI.h\"\n#include \"Cafe/HW/AI/AI.h\"\n#include \"Cafe/HW/AI/AI.h\"\n#include \"Cafe/HW/AI/AI.h\"\n\nclass DSUController : public Controller<DSUControllerProvider>\n{\npublic:\n\tDSUController(uint32 index);\n\tDSUController(uint32 index, const DSUProviderSettings& settings);\n\t\n\tstd::string_view api_name() const override\n\t{\n\t\tstatic_assert(to_string(InputAPI::DSUClient) == \"DSUController\");\n\t\treturn to_string(InputAPI::DSUClient);\n\t}\n\tInputAPI::Type api() const override { return InputAPI::DSUClient; }\n\n\tvoid save(pugi::xml_node& node) override;\n\tvoid load(const pugi::xml_node& node) override;\n\n\tbool connect() override;\n\tbool is_connected() override;\n\t\n\tbool has_motion() override { return true; }\n\tMotionSample get_motion_sample() override;\n\n\tbool has_position() override;\n\tglm::vec2 get_position() override;\n\tglm::vec2 get_prev_position() override;\n\tPositionVisibility GetPositionVisibility() override;\n\n\tstd::string get_button_name(uint64 button) const override;\n\nprotected:\n\tControllerState raw_state() override;\n\nprivate:\n\tuint32 m_index;\n};\n\n"
  },
  {
    "path": "src/input/api/DSU/DSUControllerProvider.cpp",
    "content": "#include \"input/api/DSU/DSUControllerProvider.h\"\n#include \"input/api/DSU/DSUController.h\"\n\n#if BOOST_OS_WINDOWS\n#include <boost/asio/detail/socket_option.hpp>\n#include <winsock2.h>\n#elif BOOST_OS_LINUX || BOOST_OS_MACOS\n#include <sys/time.h>\n#include <sys/socket.h>\n#endif\n\nDSUControllerProvider::DSUControllerProvider()\n\t: base_type(), m_uid(rand()), m_socket(m_io_service)\n{\n\tif (!connect())\n\t{\n\t\tthrow std::runtime_error(\"dsu client can't open the udp connection\");\n\t}\n\n\tm_running = true;\n\tm_reader_thread = std::thread(&DSUControllerProvider::reader_thread, this);\n\tm_writer_thread = std::thread(&DSUControllerProvider::writer_thread, this);\n\trequest_version();\n}\n\nDSUControllerProvider::DSUControllerProvider(const DSUProviderSettings& settings)\n\t: base_type(settings), m_uid(rand()), m_socket(m_io_service)\n{\n\tif (!connect())\n\t{\n\t\tthrow std::runtime_error(\"dsu client can't open the udp connection\");\n\t}\n\n\tm_running = true;\n\tm_reader_thread = std::thread(&DSUControllerProvider::reader_thread, this);\n\tm_writer_thread = std::thread(&DSUControllerProvider::writer_thread, this);\n\trequest_version();\n}\n\nDSUControllerProvider::~DSUControllerProvider()\n{\n\tif (m_running)\n\t{\n\t\tm_running = false;\n\t\tm_writer_thread.join();\n\t\tm_reader_thread.join();\n\t}\n}\n\nstd::vector<std::shared_ptr<ControllerBase>> DSUControllerProvider::get_controllers()\n{\n\tstd::vector<ControllerPtr> result;\n\n\tstd::array<uint8_t, kMaxClients> indices;\n\tfor (auto i = 0; i < kMaxClients; ++i)\n\t\tindices[i] = get_packet_index(i);\n\n\trequest_pad_info();\n\n\tconst auto controller_result = wait_update(indices, 3000);\n\tfor (auto i = 0; i < kMaxClients; ++i)\n\t{\n\t\tif (controller_result[i] && is_connected(i))\n\t\t\tresult.emplace_back(std::make_shared<DSUController>(i, m_settings));\n\t}\n\n\treturn result;\n}\n\nbool DSUControllerProvider::connect()\n{\n\t// already connected?\n\tif (m_receiver_endpoint.address().to_string() == get_settings().ip && m_receiver_endpoint.port() == get_settings().port)\n\t\treturn true;\n\n\ttry\n\t{\n\t\tusing namespace boost::asio;\n\n\t\tip::udp::resolver resolver(m_io_service);\n\t\tm_receiver_endpoint = *resolver.resolve(get_settings().ip, fmt::format(\"{}\", get_settings().port)).cbegin();\n\n\t\tif (m_socket.is_open())\n\t\t\tm_socket.close();\n\n\t\tm_socket.open(ip::udp::v4());\n\n        // set timeout for our threads to give a chance to exit\n#if BOOST_OS_WINDOWS\n        m_socket.set_option(boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO>{200});\n#elif BOOST_OS_LINUX || BOOST_OS_MACOS\n        timeval timeout{.tv_usec = 200 * 1000};\n        setsockopt(m_socket.native_handle(), SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeval));\n#endif\n\t\t// reset data\n\t\tm_state = {};\n\t\tm_prev_state = {};\n\n\t\t// restart threads\n\t\treturn true;\n\t}\n\tcatch (const std::exception& ex)\n\t{\n\t\tcemuLog_log(LogType::Force, \"dsu client connect error: {}\", ex.what());\n\t\treturn false;\n\t}\n}\n\nbool DSUControllerProvider::is_connected(uint8_t index) const\n{\n\tif (index >= kMaxClients)\n\t\treturn false;\n\n\tstd::scoped_lock lock(m_mutex[index]);\n\treturn m_state[index].info.state == DsState::Connected;\n}\n\nDSUControllerProvider::ControllerState DSUControllerProvider::get_state(uint8_t index) const\n{\n\tif (index >= kMaxClients)\n\t\treturn {};\n\n\tstd::scoped_lock lock(m_mutex[index]);\n\treturn m_state[index];\n}\n\nDSUControllerProvider::ControllerState DSUControllerProvider::get_prev_state(uint8_t index) const\n{\n\tif (index >= kMaxClients)\n\t\treturn {};\n\n\tstd::scoped_lock lock(m_mutex[index]);\n\treturn m_prev_state[index];\n}\n\nstd::array<bool, DSUControllerProvider::kMaxClients> DSUControllerProvider::wait_update(\n\tconst std::array<uint8_t, kMaxClients>& indices, size_t timeout) const\n{\n\tstd::array<bool, kMaxClients> result{false, false, false, false};\n\n\tconst auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout);\n\tdo\n\t{\n\t\tfor (int i = 0; i < kMaxClients; ++i)\n\t\t{\n\t\t\tif (result[i])\n\t\t\t\tcontinue;\n\n\t\t\tstd::unique_lock lock(m_mutex[i]);\n\t\t\tresult[i] = indices[i] < m_state[i].packet_index;\n\t\t}\n\n\t\tif (std::all_of(result.cbegin(), result.cend(), [](const bool& v) { return v == true; }))\n\t\t\tbreak;\n\n\t\t//std::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\tstd::this_thread::yield();\n\t}\n\twhile (std::chrono::steady_clock::now() < end);\n\n\treturn result;\n}\n\nbool DSUControllerProvider::wait_update(uint8_t index, uint32_t packet_index, size_t timeout) const\n{\n\tif (index >= kMaxClients)\n\t\treturn false;\n\n\tstd::unique_lock lock(m_mutex[index]);\n\n\tif (packet_index < m_state[index].packet_index)\n\t\treturn true;\n\n\tconst auto result = m_wait_cond[index].wait_for(lock, std::chrono::milliseconds(timeout),\n\t                                                [this, index, packet_index]()\n\t                                                {\n\t\t                                                return packet_index < m_state[index].packet_index;\n\t                                                });\n\n\treturn result;\n}\n\nuint32_t DSUControllerProvider::get_packet_index(uint8_t index) const\n{\n\tstd::scoped_lock lock(m_mutex[index]);\n\treturn m_state[index].packet_index;\n}\n\nvoid DSUControllerProvider::request_version()\n{\n\tauto msg = std::make_unique<VersionRequest>(m_uid);\n\n\tstd::scoped_lock lock(m_writer_mutex);\n\tm_writer_jobs.push(std::move(msg));\n\tm_writer_cond.notify_one();\n}\n\nvoid DSUControllerProvider::request_pad_info()\n{\n\tauto msg = std::make_unique<ListPorts>(m_uid, 4, std::array<uint8_t, 4>{0, 1, 2, 3});\n\n\tstd::scoped_lock lock(m_writer_mutex);\n\tm_writer_jobs.push(std::move(msg));\n\tm_writer_cond.notify_one();\n}\n\nvoid DSUControllerProvider::request_pad_info(uint8_t index)\n{\n\tif (index >= kMaxClients)\n\t\treturn;\n\n\tauto msg = std::make_unique<ListPorts>(m_uid, 1, std::array<uint8_t, 4>{index});\n\n\tstd::scoped_lock lock(m_writer_mutex);\n\tm_writer_jobs.push(std::move(msg));\n\tm_writer_cond.notify_one();\n}\n\nvoid DSUControllerProvider::request_pad_data()\n{\n\tauto msg = std::make_unique<DataRequest>(m_uid);\n\n\tstd::scoped_lock lock(m_writer_mutex);\n\tm_writer_jobs.push(std::move(msg));\n\tm_writer_cond.notify_one();\n}\n\nvoid DSUControllerProvider::request_pad_data(uint8_t index)\n{\n\tif (index >= kMaxClients)\n\t\treturn;\n\n\tauto msg = std::make_unique<DataRequest>(m_uid, index);\n\n\tstd::scoped_lock lock(m_writer_mutex);\n\tm_writer_jobs.push(std::move(msg));\n\tm_writer_cond.notify_one();\n}\n\nMotionSample DSUControllerProvider::get_motion_sample(uint8_t index) const\n{\n\tif (index >= kMaxClients)\n\t\treturn MotionSample();\n\tstd::scoped_lock lock(m_mutex[index]);\n\treturn m_state[index].motion_sample;\n}\n\n\nvoid DSUControllerProvider::reader_thread()\n{\n\tSetThreadName(\"DSU-reader\");\n\tbool first_read = true;\n\twhile (m_running.load(std::memory_order_relaxed))\n\t{\n\t\tServerMessage* msg;\n\t\t//try\n\t\t//{\n\t\tstd::array<char, 100> recv_buf; // NOLINT(cppcoreguidelines-pro-type-member-init, hicpp-member-init)\n\t\tboost::asio::ip::udp::endpoint sender_endpoint;\n\t\tboost::system::error_code ec{};\n\t\tconst size_t len = m_socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint, 0, ec);\n\t\tif (ec)\n\t\t{\n#ifdef DEBUG_DSU_CLIENT\n\t\t\t\tprintf(\" DSUControllerProvider::ReaderThread: exception %s\\n\", ec.what());\n#endif\n\n\t\t\t// there's probably no server listening on the given address:port\n\t\t\tif (first_read) // workaroud: first read always fails?\n\t\t\t\tfirst_read = false;\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(250));\n\t\t\t\tstd::this_thread::yield();\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n#ifdef DEBUG_DSU_CLIENT\n\t\t\tprintf(\" DSUControllerProvider::ReaderThread: received message with len: 0x%llx\\n\", len);\n#endif\n\n\t\tif (len < sizeof(ServerMessage)) // cant be a valid message\n\t\t\tcontinue;\n\n\t\tmsg = (ServerMessage*)recv_buf.data();\n\t\t//\t\t}\n\t\t//\t\tcatch (const std::exception&)\n\t\t//\t\t{\n\t\t//#ifdef DEBUG_DSU_CLIENT\n\t\t//\t\t\tprintf(\" DSUControllerProvider::ReaderThread: exception %s\\n\", ex.what());\n\t\t//#endif\n\t\t//\n\t\t//\t\t\t// there's probably no server listening on the given address:port\n\t\t//\t\t\tif (first_read) // workaroud: first read always fails?\n\t\t//\t\t\t\tfirst_read = false;\n\t\t//\t\t\telse\n\t\t//\t\t\t{\n\t\t//\t\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(250));\n\t\t//\t\t\t\tstd::this_thread::yield();\n\t\t//\t\t\t}\n\t\t//\t\t\tcontinue;\n\t\t//\t\t}\n\n\t\tuint8_t index = 0xFF;\n\t\tswitch (msg->GetMessageType())\n\t\t{\n\t\tcase MessageType::Version:\n\t\t\t{\n\t\t\t\tconst auto rsp = (VersionResponse*)msg;\n\t\t\t\tif (!rsp->IsValid())\n\t\t\t\t{\n#ifdef DEBUG_DSU_CLIENT\n\t\t\t\tprintf(\" DSUControllerProvider::ReaderThread: VersionResponse is invalid!\\n\");\n#endif\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n#ifdef DEBUG_DSU_CLIENT\n\t\t\tprintf(\" DSUControllerProvider::ReaderThread: server version is: 0x%x\\n\", rsp->GetVersion());\n#endif\n\n\t\t\t\tm_server_version = rsp->GetVersion();\n\t\t\t\t// wdc\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase MessageType::Information:\n\t\t\t{\n\t\t\t\tconst auto info = (PortInfo*)msg;\n\t\t\t\tif (!info->IsValid())\n\t\t\t\t{\n#ifdef DEBUG_DSU_CLIENT\n\t\t\t\tprintf(\" DSUControllerProvider::ReaderThread: PortInfo is invalid!\\n\");\n#endif\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tindex = info->GetIndex();\n#ifdef DEBUG_DSU_CLIENT\n\t\t\tprintf(\" DSUControllerProvider::ReaderThread: received PortInfo for index %d\\n\", index);\n#endif\n\n\t\t\t\tauto& mutex = m_mutex[index];\n\t\t\t\tstd::scoped_lock lock(mutex);\n\t\t\t\tm_prev_state[index] = m_state[index];\n\t\t\t\tm_state[index] = *info;\n\t\t\t\tm_wait_cond[index].notify_all();\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase MessageType::Data:\n\t\t\t{\n\t\t\t\tconst auto rsp = (DataResponse*)msg;\n\t\t\t\tif (!rsp->IsValid())\n\t\t\t\t{\n#ifdef DEBUG_DSU_CLIENT\n\t\t\t\tprintf(\" DSUControllerProvider::ReaderThread: DataResponse is invalid!\\n\");\n#endif\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tindex = rsp->GetIndex();\n#ifdef DEBUG_DSU_CLIENT\n\t\t\tprintf(\" DSUControllerProvider::ReaderThread: received DataResponse for index %d\\n\", index);\n#endif\n\n\t\t\t\tauto& mutex = m_mutex[index];\n\t\t\t\tstd::scoped_lock lock(mutex);\n\t\t\t\tm_prev_state[index] = m_state[index];\n\t\t\t\tm_state[index] = *rsp;\n\t\t\t\tm_wait_cond[index].notify_all();\n\t\t\t\t// update motion info immediately, guaranteeing that we dont drop packets\n\t\t\t\tintegrate_motion(index, *rsp);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (index != 0xFF)\n\t\t\trequest_pad_data(index);\n\t}\n}\n\nvoid DSUControllerProvider::writer_thread()\n{\n\tSetThreadName(\"DSU-writer\");\n\twhile (m_running.load(std::memory_order_relaxed))\n\t{\n\t\tstd::unique_lock lock(m_writer_mutex);\n\t\twhile (m_writer_jobs.empty())\n\t\t{\n\t\t\tif (m_writer_cond.wait_for(lock, std::chrono::milliseconds(250)) == std::cv_status::timeout)\n\t\t\t{\n\t\t\t\tif (!m_running.load(std::memory_order_relaxed))\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst auto msg = std::move(m_writer_jobs.front());\n\t\tm_writer_jobs.pop();\n\t\tlock.unlock();\n\n#ifdef DEBUG_DSU_CLIENT\n\t\tprintf(\" DSUControllerProvider::WriterThread: sending message: 0x%x (len: 0x%x)\\n\", (int)msg->GetMessageType(), msg->GetSize());\n#endif\n\t\ttry\n\t\t{\n\t\t\tm_socket.send_to(boost::asio::buffer(msg.get(), msg->GetSize()), m_receiver_endpoint);\n\t\t}\n\t\tcatch (const std::exception& ec)\n\t\t{\n#ifdef DEBUG_DSU_CLIENT\n\t\t\tprintf(\" DSUControllerProvider::WriterThread: exception %s\\n\", ec.what());\n#endif\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(250));\n\t\t}\n\t}\n}\n\nvoid DSUControllerProvider::integrate_motion(uint8_t index, const DataResponse& data_response)\n{\n\tconst uint64 ts = data_response.GetMotionTimestamp();\n\tif (ts <= m_last_motion_timestamp[index])\n\t{\n\t\tconst uint64 dif = m_last_motion_timestamp[index] - ts;\n\t\tif (dif >= 10000000) // timestamp more than 10 seconds in the past, a controller reset probably happened\n\t\t\tm_last_motion_timestamp[index] = 0;\n\t\treturn;\n\t}\n\n\tconst uint64 elapsedTime = ts - m_last_motion_timestamp[index];\n\tm_last_motion_timestamp[index] = ts;\n\tconst double elapsedTimeD = (double)elapsedTime / 1000000.0;\n\tconst auto& acc = data_response.GetAcceleration();\n\tconst auto& gyro = data_response.GetGyro();\n\n\tm_motion_handler[index].processMotionSample((float)elapsedTimeD,\n\t                                            gyro.x * 0.0174533f,\n\t                                            gyro.y * 0.0174533f,\n\t                                            gyro.z * 0.0174533f,\n\t                                            acc.x,\n\t                                            -acc.y,\n\t                                            -acc.z);\n\n\tm_state[index].motion_sample = m_motion_handler[index].getMotionSample();\n}\n\nDSUControllerProvider::ControllerState& DSUControllerProvider::ControllerState::operator=(const PortInfo& port_info)\n{\n\tinfo = port_info.GetInfo();\n\tlast_update = std::chrono::steady_clock::now();\n\tpacket_index++; // increase packet index for every packet we assign/recv\n\treturn *this;\n}\n\nDSUControllerProvider::ControllerState& DSUControllerProvider::ControllerState::operator=(\n\tconst DataResponse& data_response)\n{\n\tthis->operator=(static_cast<const PortInfo&>(data_response));\n\tdata = data_response.GetData();\n\treturn *this;\n}\n"
  },
  {
    "path": "src/input/api/DSU/DSUControllerProvider.h",
    "content": "#pragma once\n\n#include \"input/motion/MotionHandler.h\"\n#include \"input/api/DSU/DSUMessages.h\"\n\n#include \"input/api/ControllerProvider.h\"\n\n#include <boost/asio.hpp>\n\n#ifndef HAS_DSU\n#define HAS_DSU 1\n#endif\n\n// #define DEBUG_DSU_CLIENT\n\nstruct DSUProviderSettings : public ControllerProviderSettings\n{\n\tstd::string ip;\n\tuint16 port;\n\n\tDSUProviderSettings() : ip(\"127.0.0.1\"), port(26760) {}\n\n\tDSUProviderSettings(std::string ip, uint16 port)\n\t\t: ip(std::move(ip)), port(port)\n\t{\n\t}\n\n\tbool operator==(const DSUProviderSettings& s) const\n\t{\n\t\treturn port == s.port && ip == s.ip;\n\t}\n\n\tbool operator==(const ControllerProviderSettings& s) const override\n\t{\n\t\tconst auto* ptr = dynamic_cast<const DSUProviderSettings*>(&s);\n\t\treturn ptr && *this == *ptr;\n\t}\n};\n\n\nclass DSUControllerProvider : public ControllerProvider<DSUProviderSettings>\n{\n\tfriend class DSUController;\n\tusing base_type = ControllerProvider<DSUProviderSettings>;\npublic:\n\tconstexpr static int kMaxClients = 8;\n\n\tstruct ControllerState\n\t{\n\t\t// when was info updated last time\n\t\tstd::chrono::steady_clock::time_point last_update{};\n\t\tuint64_t packet_index = 0; // our packet index count\n\n\t\tPortInfoData info{};\n\t\tDataResponseData data{};\n\t\tMotionSample motion_sample{};\n\n\t\tControllerState& operator=(const PortInfo& port_info);\n\t\tControllerState& operator=(const DataResponse& data_response);\n\t};\n\n\tDSUControllerProvider();\n\tDSUControllerProvider(const DSUProviderSettings& settings);\n\t~DSUControllerProvider();\n\n\tinline static InputAPI::Type kAPIType = InputAPI::DSUClient;\n\tInputAPI::Type api() const override { return kAPIType; }\n\n\tstd::vector<std::shared_ptr<ControllerBase>> get_controllers() override;\n\n\tbool connect();\n\n\tbool is_connected(uint8_t index) const;\n\tControllerState get_state(uint8_t index) const;\n\tControllerState get_prev_state(uint8_t index) const;\n\tMotionSample get_motion_sample(uint8_t index) const;\n\n\tstd::array<bool, kMaxClients> wait_update(const std::array<uint8_t, kMaxClients>& indices, size_t timeout) const;\n\tbool wait_update(uint8_t index, uint32_t packet_index, size_t timeout) const;\n\n\tuint32_t get_packet_index(uint8_t index) const;\n\t// refresh pad info for all pads\n\tvoid request_pad_info();\n\t// refresh pad info for pad with given index\n\tvoid request_pad_info(uint8_t index);\n\tvoid request_version();\n\tvoid request_pad_data();\n\tvoid request_pad_data(uint8_t index);\n\n\nprivate:\n\tuint16 m_server_version = 0;\n\n\tstd::atomic_bool m_running = false;\n\tstd::thread m_reader_thread, m_writer_thread;\n\n\tvoid reader_thread();\n\tvoid writer_thread();\n\tvoid integrate_motion(uint8_t index, const DataResponse& data_response);\n\n\tstd::mutex m_writer_mutex;\n\tstd::condition_variable m_writer_cond;\n\n\tuint32 m_uid;\n\tboost::asio::io_context m_io_service;\n\tboost::asio::ip::udp::endpoint m_receiver_endpoint;\n\tboost::asio::ip::udp::socket m_socket;\n\n\tstd::array<ControllerState, kMaxClients> m_state{};\n\tstd::array<ControllerState, kMaxClients> m_prev_state{};\n\tmutable std::array<std::mutex, kMaxClients> m_mutex;\n\tmutable std::array<std::condition_variable, kMaxClients> m_wait_cond;\n\n\tstd::queue<std::unique_ptr<ClientMessage>> m_writer_jobs;\n\n\tstd::array<WiiUMotionHandler, kMaxClients> m_motion_handler;\n\tstd::array<uint64, kMaxClients> m_last_motion_timestamp{};\n};\n"
  },
  {
    "path": "src/input/api/DSU/DSUMessages.cpp",
    "content": "#include \"input/api/DSU/DSUMessages.h\"\n#include \"util/crypto/crc32.h\"\n\nconstexpr uint32_t kMagicClient = 'CUSD';\nconstexpr uint32_t kMagicServer = 'SUSD';\nconstexpr uint16_t kProtocolVersion = 1001;\n\nMessageHeader::MessageHeader(uint32_t magic, uint32_t uid)\n\t: m_magic(magic), m_protocol_version(kProtocolVersion), m_uid(uid) { }\n\nvoid MessageHeader::Finalize(size_t size)\n{\n\tm_packet_size = (uint16_t)(size - sizeof(MessageHeader));\n\tm_crc32 = CRC32(size);\n}\n\nuint32_t MessageHeader::CRC32(size_t size) const\n{\n\tuint32_t tmp, tmp2;\n\n\ttmp = m_crc32;\n\tm_crc32 = 0;\n\ttmp2 = crc32_calc(this, size);\n\tm_crc32 = tmp;\n\n\treturn tmp2;\n}\n\nbool MessageHeader::IsClientMessage() const { return m_magic == kMagicClient; }\nbool MessageHeader::IsServerMessage() const { return m_magic == kMagicServer; }\n\nMessage::Message(uint32_t magic, uint32_t uid, MessageType type)\n\t: MessageHeader(magic, uid), m_message_type(type)\n{\n\t\n}\n\nClientMessage::ClientMessage(uint32_t uid, MessageType message_type)\n\t: Message(kMagicClient, uid, message_type) { }\n\nVersionRequest::VersionRequest(uint32_t uid)\n\t: ClientMessage(uid, MessageType::Version)\n{\n\tFinalize(sizeof(VersionRequest));\n}\n\nListPorts::ListPorts(uint32_t uid, uint32_t num_pads_requests, const std::array<uint8_t, 4>& request_indices)\n\t: ClientMessage(uid, MessageType::Information), m_count(num_pads_requests), m_indices(request_indices)\n{\n\tFinalize(sizeof(ListPorts));\n}\n\nDataRequest::DataRequest(uint32_t uid)\n\t: ClientMessage(uid, MessageType::Data), m_reg_flags(RegisterFlag::AllPads), m_index(0), m_mac_address({})\n{\n\tFinalize(sizeof(DataRequest));\n}\n\nDataRequest::DataRequest(uint32_t uid, uint8_t index)\n\t: ClientMessage(uid, MessageType::Data), m_reg_flags(RegisterFlag::Index), m_index(index), m_mac_address({})\n{\n\tFinalize(sizeof(DataRequest));\n}\n\nDataRequest::DataRequest(uint32_t uid, const MACAddress_t& mac_address)\n\t: ClientMessage(uid, MessageType::Data), m_reg_flags(RegisterFlag::MACAddress), m_index(0), m_mac_address(mac_address)\n{\n\tFinalize(sizeof(DataRequest));\n}\n\nDataRequest::DataRequest(uint32_t uid, uint8_t index, const MACAddress_t& mac_address)\n\t: ClientMessage(uid, MessageType::Data), m_reg_flags(RegisterFlag::Index | RegisterFlag::MACAddress), m_index(index), m_mac_address(mac_address)\n{\n\tFinalize(sizeof(DataRequest));\n}\n\nbool ServerMessage::ValidateCRC32(size_t size) const\n{\n\treturn GetCRC32() == CRC32(size);\n}\n\nbool VersionResponse::IsValid() const\n{\n\treturn ValidateCRC32(sizeof(VersionResponse));\n}\n\nbool PortInfo::IsValid() const\n{\n\treturn ValidateCRC32(sizeof(PortInfo));\n}\n\nbool DataResponse::IsValid() const\n{\n\treturn ValidateCRC32(sizeof(DataResponse));\n}\n"
  },
  {
    "path": "src/input/api/DSU/DSUMessages.h",
    "content": "#pragma once\n\n// https://v1993.github.io/cemuhook-protocol/\n\n#include \"Common/enumFlags.h\"\n#include \"util/math/vector3.h\"\n\n#include <array>\n#include <cstdint>\n\nenum class DsState : uint8_t\n{\n\tDisconnected = 0x00,\n\tReserved = 0x01,\n\tConnected = 0x02\n};\n\nenum class DsConnection : uint8_t\n{\n\tNone = 0x00,\n\tUsb = 0x01,\n\tBluetooth = 0x02\n};\n\nenum class DsModel : uint8_t\n{\n\tNone = 0,\n\tDS3 = 1,\n\tDS4 = 2,\n\tGeneric = 3\n};\n\nenum class DsBattery : uint8_t\n{\n\tNone = 0x00,\n\tDying = 0x01,\n\tLow = 0x02,\n\tMedium = 0x03,\n\tHigh = 0x04,\n\tFull = 0x05,\n\tCharging = 0xEE,\n\tCharged = 0xEF\n};\n\nenum class RegisterFlag : uint8_t\n{\n\tAllPads = 0x00,\n\tIndex = 0x01,\n\tMACAddress = 0x02\n};\nENABLE_BITMASK_OPERATORS(RegisterFlag);\n\nenum class MessageType : uint32_t\n{\n\tVersion = 0x100000,\n\tInformation = 0x100001,\n\tData = 0x100002,\n\tRumble = 0x100003, // TODO\n};\n\nusing MACAddress_t = std::array<uint8_t, 6>;\n\n#pragma pack(push,1)\n\nclass MessageHeader\n{\npublic:\n\tMessageHeader(uint32_t magic, uint32_t uid);\n\n\t[[nodiscard]] uint16_t GetSize() const { return sizeof(MessageHeader) + m_packet_size; }\n\t[[nodiscard]] bool IsClientMessage() const;\n\t[[nodiscard]] bool IsServerMessage() const;\n\t[[nodiscard]] uint32_t GetCRC32() const { return m_crc32; }\n\t\nprotected:\n\tvoid Finalize(size_t size);\n\n\t[[nodiscard]] uint32_t CRC32(size_t size) const;\nprivate:\n\tuint32_t m_magic;\n\tuint16_t m_protocol_version;\n\tuint16_t m_packet_size = 0;\n\tmutable uint32_t m_crc32 = 0;\n\tuint32_t m_uid;\n};\nstatic_assert(sizeof(MessageHeader) == 0x10);\n\nclass Message : public MessageHeader\n{\npublic:\n\tMessage(uint32_t magic, uint32_t uid, MessageType type);\n\n\t[[nodiscard]] MessageType GetMessageType() const { return m_message_type; }\nprivate:\n\tMessageType m_message_type;\n};\nstatic_assert(sizeof(Message) == 0x14);\n\n// client messages\nclass ClientMessage : public Message\n{\npublic:\n\tClientMessage(uint32_t uid, MessageType message_type);\n};\nstatic_assert(sizeof(ClientMessage) == sizeof(Message));\n\nclass VersionRequest : public ClientMessage\n{\npublic:\n\tVersionRequest(uint32_t uid);\n};\nstatic_assert(sizeof(VersionRequest) == sizeof(ClientMessage));\n\nclass ListPorts : public ClientMessage\n{\npublic:\n\tListPorts(uint32_t uid, uint32_t num_pads_requests, const std::array<uint8_t, 4>& request_indices);\n\nprivate:\n\tuint32_t m_count;\n\tstd::array<uint8_t, 4> m_indices;\n};\n\nclass DataRequest : public ClientMessage\n{\npublic:\n\tDataRequest(uint32_t uid);\n\tDataRequest(uint32_t uid, uint8_t index);\n\tDataRequest(uint32_t uid, const MACAddress_t& mac_address);\n\tDataRequest(uint32_t uid, uint8_t index, const MACAddress_t& mac_address);\n\nprivate:\n\tRegisterFlag m_reg_flags;\n\tuint8_t m_index;\n\tMACAddress_t m_mac_address;\n};\n\n// server messages\nclass ServerMessage : public Message\n{\npublic:\n\tServerMessage() = delete;\n\nprotected:\n\t[[nodiscard]] bool ValidateCRC32(size_t size) const;\n};\n\nclass VersionResponse : public ServerMessage\n{\npublic:\n\t[[nodiscard]] bool IsValid() const;\n\t[[nodiscard]] uint16_t GetVersion() const { return m_version; }\n\nprivate:\n\tuint16_t m_version;\n\tuint8_t padding[2];\n};\nstatic_assert(sizeof(VersionResponse) == 0x18);\n\nstruct PortInfoData\n{\n\tuint8_t index;\n\tDsState state;\n\tDsModel model;\n\tDsConnection connection;\n\tMACAddress_t mac_address;\n\tDsBattery battery;\n\tuint8_t is_active;\n};\n\nclass PortInfo : public ServerMessage\n{\npublic:\n\t[[nodiscard]] bool IsValid() const;\n\n\t[[nodiscard]] const PortInfoData& GetInfo() const { return m_info; }\n\n\t[[nodiscard]] uint8_t GetIndex() const { return m_info.index; }\n\t[[nodiscard]] DsState GetState() const { return m_info.state; }\n\t[[nodiscard]] DsModel GetModel() const { return m_info.model; }\n\t[[nodiscard]] DsConnection GetConnection() const { return m_info.connection; }\n\t[[nodiscard]] MACAddress_t GetMacAddress() const { return m_info.mac_address; }\n\t[[nodiscard]] DsBattery GetBattery() const { return m_info.battery; }\n\t[[nodiscard]] bool IsActive() const { return m_info.is_active != 0; }\n\nprotected:\n\tPortInfoData m_info;\n};\nstatic_assert(sizeof(PortInfo) == 0x20);\n\nstruct TouchPoint\n{\n\tuint8_t active;\n\tuint8_t index;\n\tint16_t x, y;\n};\nstatic_assert(sizeof(TouchPoint) == 0x6);\n\nstruct DataResponseData\n{\n\tuint32_t m_packet_index;\n\n\tuint8_t state1;\n\tuint8_t state2;\n\tuint8_t ps;\n\tuint8_t touch;\n\n\t// y values are inverted by convention\n\tuint8_t lx, ly;\n\tuint8_t rx, ry;\n\n\tuint8_t dpad_left;\n\tuint8_t dpad_down;\n\tuint8_t dpad_right;\n\tuint8_t dpad_up;\n\n\tuint8_t square;\n\tuint8_t cross;\n\tuint8_t circle;\n\tuint8_t triangle;\n\n\tuint8_t r1;\n\tuint8_t l1;\n\tuint8_t r2;\n\tuint8_t l2;\n\n\tTouchPoint tpad1, tpad2;\n\n\tuint64_t motion_timestamp;\n\tVector3f accel;\n\tVector3f gyro;\n};\n\nclass DataResponse : public PortInfo\n{\npublic:\n\t[[nodiscard]] bool IsValid() const;\n\n\t[[nodiscard]] const DataResponseData& GetData() const { return m_data; }\n\t\n\tuint32_t GetPacketIndex() const { return m_data.m_packet_index; }\n\tuint8_t GetState1() const { return m_data.state1; }\n\tuint8_t GetState2() const { return m_data.state2; }\n\tuint8_t GetPs() const { return m_data.ps; }\n\tuint8_t GetTouch() const { return m_data.touch; }\n\tuint8_t GetLx() const { return m_data.lx; }\n\tuint8_t GetLy() const { return m_data.ly; }\n\tuint8_t GetRx() const { return m_data.rx; }\n\tuint8_t GetRy() const { return m_data.ry; }\n\tuint8_t GetDpadLeft() const { return m_data.dpad_left; }\n\tuint8_t GetDpadDown() const { return m_data.dpad_down; }\n\tuint8_t GetDpadRight() const { return m_data.dpad_right; }\n\tuint8_t GetDpadUp() const { return m_data.dpad_up; }\n\tuint8_t GetSquare() const { return m_data.square; }\n\tuint8_t GetCross() const { return m_data.cross; }\n\tuint8_t GetCircle() const { return m_data.circle; }\n\tuint8_t GetTriangle() const { return m_data.triangle; }\n\tuint8_t GetR1() const { return m_data.r1; }\n\tuint8_t GetL1() const { return m_data.l1; }\n\tuint8_t GetR2() const { return m_data.r2; }\n\tuint8_t GetL2() const { return m_data.l2; }\n\tconst TouchPoint& GetTpad1() const { return m_data.tpad1; }\n\tconst TouchPoint& GetTpad2() const { return m_data.tpad2; }\n\tuint64_t GetMotionTimestamp() const { return m_data.motion_timestamp; }\n\t\n\tconst Vector3f& GetAcceleration() const { return m_data.accel; }\n\tconst Vector3f& GetGyro() const { return m_data.gyro; }\n\nprivate:\n\tDataResponseData m_data;\n};\n\n//static_assert(sizeof(DataResponse) == 0x20);\n\n#pragma pack(pop)"
  },
  {
    "path": "src/input/api/DirectInput/DirectInputController.cpp",
    "content": "#include \"input/api/DirectInput/DirectInputController.h\"\n#include \"WindowSystem.h\"\n\nDirectInputController::DirectInputController(const GUID& guid)\n\t: base_type(StringFromGUID(guid), fmt::format(\"[{}]\", StringFromGUID(guid))),\n\tm_guid{ guid }\n{\n\t\n}\n\nDirectInputController::DirectInputController(const GUID& guid, std::string_view display_name)\n\t: base_type(StringFromGUID(guid), display_name), m_guid(guid)\n{\n}\n\nDirectInputController::~DirectInputController()\n{\n\tif (m_device)\n\t{\n\t\tm_device->Unacquire();\n\n\t\t// TODO: test if really needed\n\t\t// workaround for gamecube controllers crash on release?\n\t\tbool should_release_device = true;\n\t\tif (m_product_guid == GUID{})\n\t\t{\n\t\t\tDIDEVICEINSTANCEW info{};\n\t\t\tinfo.dwSize = sizeof(DIDEVICEINSTANCEW);\n\t\t\tif (SUCCEEDED(m_device->GetDeviceInfo(&info)))\n\t\t\t{\n\t\t\t\tm_product_guid = info.guidProduct;\n\t\t\t}\n\t\t}\n\n\t\t// info.guidProduct = {18440079-0000-0000-0000-504944564944}\n\t\tconstexpr GUID kGameCubeController = { 0x18440079, 0, 0, {0,0,0x50,0x49,0x44,0x56,0x49,0x44} };\n\t\tif (kGameCubeController == m_product_guid)\n\t\t\tshould_release_device = false;\n\n\t\tif (!should_release_device)\n\t\t\tm_device.Detach();\n\t}\n}\n\nvoid DirectInputController::save(pugi::xml_node& node)\n{\n\tbase_type::save(node);\n\n\tnode.append_child(\"product_guid\").append_child(pugi::node_pcdata).set_value(\n\t\tfmt::format(\"{}\", StringFromGUID(m_product_guid)).c_str());\n}\n\nvoid DirectInputController::load(const pugi::xml_node& node)\n{\n\tbase_type::load(node);\n\n\tif (const auto value = node.child(\"product_guid\")) {\n\t\tif (GUIDFromString(value.child_value(), m_product_guid) && m_product_guid != GUID{} && !is_connected())\n\t\t{\n\t\t\t// test if another controller with the same product guid is connectable and replace\n\t\t\tfor(const auto& c : m_provider->get_controllers())\n\t\t\t{\n\t\t\t\tif(const auto ptr = std::dynamic_pointer_cast<DirectInputController>(c))\n\t\t\t\t{\n\t\t\t\t\tif (ptr->is_connected() && ptr->get_product_guid() == m_product_guid)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst auto tmp_guid = m_guid;\n\t\t\t\t\t\tm_guid = ptr->get_guid();\n\t\t\t\t\t\tif (connect())\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t// couldn't connect\n\t\t\t\t\t\tm_guid = tmp_guid;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t}\n\t\t}\n\t}\n}\n\nbool DirectInputController::connect()\n{\n\tif (is_connected())\n\t\treturn true;\n\n\tm_effect = nullptr;\n\n\tstd::scoped_lock lock(m_mutex);\n\tHRESULT hr = m_provider->get_dinput()->CreateDevice(m_guid, &m_device, nullptr);\n\tif (FAILED(hr) || m_device == nullptr)\n\t\treturn false;\n\n\tDIDEVICEINSTANCEW idi{};\n\tidi.dwSize = sizeof(DIDEVICEINSTANCEW);\n\tif (SUCCEEDED(m_device->GetDeviceInfo(&idi)))\n\t{\n\t\t// overwrite guid name with \"real\" display name\n\t\tm_display_name = boost::nowide::narrow(idi.tszProductName);\n\t}\n\n\t// set data format\n\tif (FAILED(m_device->SetDataFormat(m_provider->get_data_format())))\n\t{\n\t\treturn false;\n\t}\n\n\tHWND hwndMainWindow = static_cast<HWND>(WindowSystem::GetWindowInfo().window_main.surface);\n\n\t// set access\n\tif (FAILED(m_device->SetCooperativeLevel(hwndMainWindow, DISCL_BACKGROUND | DISCL_EXCLUSIVE)))\n\t{\n\t\tif (FAILED(m_device->SetCooperativeLevel(hwndMainWindow, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\t// rumble can only be used with exclusive access\n\t}\n\telse\n\t{\n\t\tGUID guid_effect = GUID_NULL;\n\t\t// check if constant force is supported\n\t\tHRESULT result = m_device->EnumEffects([](LPCDIEFFECTINFOW eff, LPVOID guid) -> BOOL\n\t\t\t{\n\t\t\t\t*(GUID*)guid = eff->guid;\n\t\t\t\treturn DIENUM_STOP;\n\t\t\t}, &guid_effect, DIEFT_CONSTANTFORCE);\n\n\t\tif (SUCCEEDED(result) && guid_effect != GUID_NULL)\n\t\t{\n\t\t\tDWORD dwAxes[2] = { DIJOFS_X, DIJOFS_Y };\n\t\t\tLONG lDirection[2] = { 1, 0 };\n\n\t\t\tDICONSTANTFORCE constant_force = { DI_FFNOMINALMAX }; // DI_FFNOMINALMAX -> should be max normally?!\n\n\t\t\tDIEFFECT effect{};\n\t\t\teffect.dwSize = sizeof(DIEFFECT);\n\t\t\teffect.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;\n\t\t\teffect.dwDuration = INFINITE; // DI_SECONDS;\n\t\t\teffect.dwGain = DI_FFNOMINALMAX; // No scaling\n\t\t\teffect.dwTriggerButton = DIEB_NOTRIGGER; // Not a button response DIEB_NOTRIGGER DIJOFS_BUTTON0\n\t\t\teffect.cAxes = 2;\n\t\t\teffect.rgdwAxes = dwAxes;\n\t\t\teffect.rglDirection = lDirection;\n\t\t\teffect.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);\n\t\t\teffect.lpvTypeSpecificParams = &constant_force;\n\t\t\tm_device->CreateEffect(guid_effect, &effect, &m_effect, nullptr);\n\t\t}\n\t}\n\n\tDIDEVICEINSTANCEW info{};\n\tinfo.dwSize = sizeof(DIDEVICEINSTANCEW);\n\tif (SUCCEEDED(m_device->GetDeviceInfo(&info)))\n\t{\n\t\tm_product_guid = info.guidProduct;\n\t}\n\n\tstd::fill(m_min_axis.begin(), m_min_axis.end(), 0);\n\tstd::fill(m_max_axis.begin(), m_max_axis.end(), std::numeric_limits<uint16>::max());\n\tm_device->EnumObjects(\n\t\t[](LPCDIDEVICEOBJECTINSTANCEW lpddoi, LPVOID pvRef) -> BOOL\n\t\t{\n\t\t\tauto* thisptr = (DirectInputController*)pvRef;\n\n\t\t\tconst auto instance = DIDFT_GETINSTANCE(lpddoi->dwType);\n\t\t\t// some tools may use state.rglSlider properties, so they have 8 instead of 6 axis\n\t\t\tif(instance >= thisptr->m_min_axis.size())\n\t\t\t{\n\t\t\t\treturn DIENUM_CONTINUE;\n\t\t\t}\n\t\t\t\n\t\t\tDIPROPRANGE range{};\n\t\t\trange.diph.dwSize = sizeof(range);\n\t\t\trange.diph.dwHeaderSize = sizeof(range.diph);\n\t\t\trange.diph.dwHow = DIPH_BYID;\n\t\t\trange.diph.dwObj = lpddoi->dwType;\n\t\t\tif (thisptr->m_device->GetProperty(DIPROP_RANGE, &range.diph) == DI_OK)\n\t\t\t{\n\t\t\t\tthisptr->m_min_axis[instance] = range.lMin;\n\t\t\t\tthisptr->m_max_axis[instance] = range.lMax;\n\t\t\t}\n\n\t\t\treturn DIENUM_CONTINUE;\n\t\t}, this, DIDFT_AXIS);\n\n\tm_device->Acquire();\n\treturn true;\n}\n\nbool DirectInputController::is_connected()\n{\n\tstd::shared_lock lock(m_mutex);\n\treturn m_device != nullptr;\n}\n\nbool DirectInputController::has_rumble()\n{\n\treturn m_effect != nullptr;\n}\n\nvoid DirectInputController::start_rumble()\n{\n\tif (!has_rumble())\n\t\treturn;\n}\n\nvoid DirectInputController::stop_rumble()\n{\n\tif (!has_rumble())\n\t\treturn;\n}\n\nstd::string DirectInputController::get_button_name(uint64 button) const\n{\n\tswitch(button)\n\t{\n\tcase kAxisXP: return \"X+\";\n\tcase kAxisYP: return \"Y+\";\n\n\tcase kAxisXN: return \"X-\";\n\tcase kAxisYN: return \"Y-\";\n\n\tcase kRotationXP: return \"RX+\";\n\tcase kRotationYP: return \"RY+\";\n\n\tcase kRotationXN: return \"RX-\";\n\tcase kRotationYN: return \"RY-\";\n\n\tcase kTriggerXP: return \"Z+\";\n\tcase kTriggerYP: return \"RZ+\";\n\n\tcase kTriggerXN: return \"Z-\";\n\tcase kTriggerYN: return \"RZ-\";\n\t}\n\n\treturn base_type::get_button_name(button);\n}\n\nControllerState DirectInputController::raw_state()\n{\n\tControllerState result{};\n\tif (!is_connected())\n\t\treturn result;\n\tHRESULT hr = m_device->Poll();\n\tif (FAILED(hr))\n\t{\n\t\tif (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED)\n\t\t{\n\t\t\tresult.last_state = hr;\n\t\t\tm_device->Acquire();\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tDIJOYSTATE state{};\n\thr = m_device->GetDeviceState(sizeof(state), &state);\n\tif (FAILED(hr))\n\t{\n\t\tif (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED)\n\t\t{\n\t\t\tresult.last_state = hr;\n\t\t\tm_device->Acquire();\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tresult.last_state = hr;\n\n\t// buttons\n\tfor (size_t i = 0; i < std::size(state.rgbButtons); ++i)\n\t{\n\t\tif (HAS_BIT(state.rgbButtons[i], 7))\n\t\t\tresult.buttons.SetButtonState(i, true);\n\t}\n\t\n\t// axis\n\tconstexpr float kThreshold = 0.001f;\n\tfloat v = (float(state.lX - m_min_axis[0]) / float(m_max_axis[0] - m_min_axis[0])) * 2.0f - 1.0f;\n\tif (std::abs(v) >= kThreshold)\n\t\tresult.axis.x = v;\n\n\tv = (float(state.lY - m_min_axis[1]) / float(m_max_axis[1] - m_min_axis[1])) * 2.0f - 1.0f;\n\tif (std::abs(v) >= kThreshold)\n\t\tresult.axis.y = -v;\n\n\t// Right Stick\n\tv = (float(state.lRx - m_min_axis[3]) / float(m_max_axis[3] - m_min_axis[3])) * 2.0f - 1.0f;\n\tif (std::abs(v) >= kThreshold)\n\t\tresult.rotation.x = v;\n\n\tv = (float(state.lRy - m_min_axis[4]) / float(m_max_axis[4] - m_min_axis[4])) * 2.0f - 1.0f;\n\tif (std::abs(v) >= kThreshold)\n\t\tresult.rotation.y = -v;\n\n\t// Trigger\n\tv = (float(state.lZ - m_min_axis[2]) / float(m_max_axis[2] - m_min_axis[2])) * 2.0f - 1.0f;\n\tif (std::abs(v) >= kThreshold)\n\t\tresult.trigger.x = v;\n\n\tv = (float(state.lRz - m_min_axis[5]) / float(m_max_axis[5] - m_min_axis[5])) * 2.0f - 1.0f;\n\tif (std::abs(v) >= kThreshold)\n\t\tresult.trigger.y = -v;\n\n\t// dpad\n\tconst auto pov = state.rgdwPOV[0];\n\tif (pov != static_cast<DWORD>(-1))\n\t{\n\t\tswitch (pov)\n\t\t{\n\t\tcase 0: result.buttons.SetButtonState(kButtonUp, true);\n\t\t\tbreak;\n\t\tcase 4500: result.buttons.SetButtonState(kButtonUp, true); // up + right\n\t\tcase 9000: result.buttons.SetButtonState(kButtonRight, true);\n\t\t\tbreak;\n\t\tcase 13500: result.buttons.SetButtonState(kButtonRight, true); // right + down\n\t\tcase 18000: result.buttons.SetButtonState(kButtonDown, true);\n\t\t\tbreak;\n\t\tcase 22500: result.buttons.SetButtonState(kButtonDown, true); // down + left\n\t\tcase 27000: result.buttons.SetButtonState(kButtonLeft, true);\n\t\t\tbreak;\n\t\tcase 31500: result.buttons.SetButtonState(kButtonLeft, true); // left + up\n\t\t\t\t\tresult.buttons.SetButtonState(kButtonUp, true); // left + up\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn result;\n}\n"
  },
  {
    "path": "src/input/api/DirectInput/DirectInputController.h",
    "content": "#pragma once\n\n#include \"input/api/DirectInput/DirectInputControllerProvider.h\"\n#include \"input/api/Controller.h\"\n#include <wrl/client.h>\n\nclass DirectInputController : public Controller<DirectInputControllerProvider>\n{\npublic:\n\tDirectInputController(const GUID& guid);\n\tDirectInputController(const GUID& guid, std::string_view display_name);\n\t~DirectInputController() override;\n\t\n\tstd::string_view api_name() const override\n\t{\n\t\tstatic_assert(to_string(InputAPI::DirectInput) == \"DirectInput\");\n\t\treturn to_string(InputAPI::DirectInput);\n\t}\n\tInputAPI::Type api() const override { return InputAPI::DirectInput; }\n\n\tvoid save(pugi::xml_node& node) override;\n\tvoid load(const pugi::xml_node& node) override;\n\t\n\tbool connect() override;\n\tbool is_connected() override;\n\n\tbool has_rumble() override;\n\t\n\tvoid start_rumble() override;\n\tvoid stop_rumble() override;\n\n\tstd::string get_button_name(uint64 button) const override;\n\n\tconst GUID& get_guid() const { return m_guid; }\n\tconst GUID& get_product_guid() const { return m_product_guid; }\n\nprotected:\n\tControllerState raw_state() override;\n\nprivate:\n\tGUID m_guid;\n\tGUID m_product_guid{};\n\n\tstd::shared_mutex m_mutex;\n\tMicrosoft::WRL::ComPtr<IDirectInputDevice8W> m_device;\n\tMicrosoft::WRL::ComPtr<IDirectInputEffect> m_effect;\n\n\tstd::array<LONG, 6> m_min_axis{};\n\tstd::array<LONG, 6> m_max_axis{};\n};\n"
  },
  {
    "path": "src/input/api/DirectInput/DirectInputControllerProvider.cpp",
    "content": "#include \"input/api/DirectInput/DirectInputControllerProvider.h\"\n\n#include \"input/api/DirectInput/DirectInputController.h\"\n\nDirectInputControllerProvider::DirectInputControllerProvider()\n{\n\tconst auto r = DirectInput8Create(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, IID_IDirectInput8W, (void**)&m_dinput8, nullptr);\n\tif (FAILED(r))\n\t{\n\t\tconst auto error = GetLastError();\n\t\tthrow std::runtime_error(fmt::format(\"can't create direct input object (error: {:#x})\", error));\n\t}\n}\n\nDirectInputControllerProvider::~DirectInputControllerProvider()\n{\n}\n\nstd::vector<std::shared_ptr<ControllerBase>> DirectInputControllerProvider::get_controllers()\n{\n\tstd::vector<std::shared_ptr<ControllerBase>> result;\n\n\tm_dinput8->EnumDevices(DI8DEVCLASS_GAMECTRL,\n\t\t[](LPCDIDEVICEINSTANCEW lpddi, LPVOID pvRef) -> BOOL\n\t\t{\n\t\t\tauto* controllers = (decltype(&result))pvRef;\n\n\t\t\tstd::string display_name = boost::nowide::narrow(lpddi->tszProductName);\n\t\t\tcontrollers->emplace_back(std::make_shared<DirectInputController>(lpddi->guidInstance, display_name));\n\n\t\t\treturn DIENUM_CONTINUE;\n\t\t}, &result, DIEDFL_ALLDEVICES);\n\t\n\n\treturn result;\n}\n\nLPCDIDATAFORMAT DirectInputControllerProvider::get_data_format() const\n{\n\treturn GetdfDIJoystick();\n}\n"
  },
  {
    "path": "src/input/api/DirectInput/DirectInputControllerProvider.h",
    "content": "#pragma once\n#if BOOST_OS_WINDOWS\n\n#define DIRECTINPUT_VERSION 0x0800\n\n#include <dinput.h>\n#include <wrl/client.h>\n\n#include \"input/api/ControllerProvider.h\"\n\n#ifndef HAS_DIRECTINPUT\n#define HAS_DIRECTINPUT 1\n#endif\n\nclass DirectInputControllerProvider : public ControllerProviderBase\n{\npublic:\n\tDirectInputControllerProvider();\n\t~DirectInputControllerProvider() override;\n\n\tinline static InputAPI::Type kAPIType = InputAPI::DirectInput;\n\tInputAPI::Type api() const override { return kAPIType; }\n\n\tstd::vector<std::shared_ptr<ControllerBase>> get_controllers() override;\n\n\tIDirectInput8W* get_dinput() const { return m_dinput8.Get(); }\n\tLPCDIDATAFORMAT get_data_format() const;\n\nprivate:\n\tHMODULE m_module = nullptr;\n\n\tdecltype(&DirectInput8Create) m_DirectInput8Create;\n\tdecltype(&GetdfDIJoystick) m_GetdfDIJoystick = nullptr;\n\n\tMicrosoft::WRL::ComPtr<IDirectInput8W> m_dinput8;\n};\n\n#endif\n"
  },
  {
    "path": "src/input/api/GameCube/GameCubeController.cpp",
    "content": "#include \"input/api/GameCube/GameCubeController.h\"\n\n#ifdef HAS_GAMECUBE\n\nGameCubeController::GameCubeController(uint32 adapter, uint32 index)\n\t: base_type(fmt::format(\"{}_{}\", adapter, index), fmt::format(\"Controller {}\", index + 1)), m_adapter(adapter),\n\t  m_index(index)\n{\n\t// update names if multiple adapters are connected\n\tif (adapter > 0)\n\t\tm_display_name = fmt::format(\"Controller {} ({})\", index + 1, adapter);\n\n\tm_settings.axis.range = 1.20f;\n\tm_settings.rotation.range = 1.25f;\n\tm_settings.trigger.range = 1.07f;\n}\n\nbool GameCubeController::is_connected()\n{\n\treturn m_provider->is_connected(m_adapter);\n}\n\nbool GameCubeController::has_rumble()\n{\n\treturn m_provider->has_rumble_connected(m_adapter);\n}\n\nvoid GameCubeController::start_rumble()\n{\n\tif (m_settings.rumble <= 0)\n\t\treturn;\n\n\tm_provider->set_rumble_state(m_adapter, m_index, true);\n}\n\nvoid GameCubeController::stop_rumble()\n{\n\tm_provider->set_rumble_state(m_adapter, m_index, false);\n}\n\nstd::string GameCubeController::get_button_name(uint64 button) const\n{\n\tswitch (button)\n\t{\n\tcase kButton0: return \"A\";\n\tcase kButton1: return \"B\";\n\tcase kButton2: return \"X\";\n\tcase kButton3: return \"Y\";\n\n\tcase kButton4: return \"Left\";\n\tcase kButton5: return \"Right\";\n\tcase kButton6: return \"Down\";\n\tcase kButton7: return \"Up\";\n\n\tcase kButton8: return \"Start\";\n\tcase kButton9: return \"Z\";\n\n\tcase kButton10: return \"Trigger R\";\n\tcase kButton11: return \"Trigger L\";\n\t}\n\n\treturn base_type::get_button_name(button);\n}\n\nControllerState GameCubeController::raw_state()\n{\n\tControllerState result{};\n\tif (!is_connected())\n\t\treturn result;\n\n\tconst auto state = m_provider->get_state(m_adapter, m_index);\n\tif (state.valid)\n\t{\n\t\tfor (auto i = 0; i <= kButton11; ++i)\n\t\t{\n\t\t\tif (HAS_BIT(state.button, i))\n\t\t\t{\n\t\t\t\tresult.buttons.set(i);\n\t\t\t}\n\t\t}\n\n\t\t// printf(\"(%d, %d) - (%d, %d) - (%d, %d)\\n\", state.lstick_x, state.lstick_y, state.rstick_x, state.rstick_y, state.lstick, state.rstick);\n\t\tresult.axis.x = (float)state.lstick_x / std::numeric_limits<uint8>::max();\n\t\tresult.axis.x = (result.axis.x * 2.0f) - 1.0f;\n\n\t\tresult.axis.y = (float)state.lstick_y / std::numeric_limits<uint8>::max();\n\t\tresult.axis.y = (result.axis.y * 2.0f) - 1.0f;\n\n\t\tresult.rotation.x = (float)state.rstick_x / std::numeric_limits<uint8>::max();\n\t\tresult.rotation.x = (result.rotation.x * 2.0f) - 1.0f;\n\n\t\tresult.rotation.y = (float)state.rstick_y / std::numeric_limits<uint8>::max();\n\t\tresult.rotation.y = (result.rotation.y * 2.0f) - 1.0f;\n\n\n\t\tresult.trigger.x = (float)state.lstick / std::numeric_limits<uint8>::max();\n\t\tresult.trigger.y = (float)state.rstick / std::numeric_limits<uint8>::max();\n\t}\n\t\n\treturn result;\n}\n\n#endif"
  },
  {
    "path": "src/input/api/GameCube/GameCubeController.h",
    "content": "#pragma once\n\n#include \"input/api/Controller.h\"\n#include \"input/api/GameCube/GameCubeControllerProvider.h\"\n\n#ifdef HAS_GAMECUBE\n\nclass GameCubeController : public Controller<GameCubeControllerProvider>\n{\npublic:\n\tGameCubeController(uint32 adapter, uint32 index);\n\t\n\tstd::string_view api_name() const override\n\t{\n\t\tstatic_assert(to_string(InputAPI::GameCube) == \"GameCube\");\n\t\treturn to_string(InputAPI::GameCube);\n\t}\n\tInputAPI::Type api() const override { return InputAPI::GameCube; }\n\n\tbool is_connected() override;\n\tbool has_rumble() override;\n\tvoid start_rumble() override;\n\tvoid stop_rumble() override;\n\n\tstd::string get_button_name(uint64 button) const override;\n\nprotected:\n\tControllerState raw_state() override;\n\n\tuint32 m_adapter;\n\tuint32 m_index;\n};\n\n#endif"
  },
  {
    "path": "src/input/api/GameCube/GameCubeControllerProvider.cpp",
    "content": "#include \"input/api/GameCube/GameCubeControllerProvider.h\"\n#include \"input/api/GameCube/GameCubeController.h\"\n#include \"util/libusbWrapper/libusbWrapper.h\"\n\n#if HAS_GAMECUBE\n\nconstexpr uint16_t kVendorId = 0x57e, kProductId = 0x337;\n\nGameCubeControllerProvider::GameCubeControllerProvider()\n{\n\tm_libusb = libusbWrapper::getInstance();\n\tm_libusb->init();\n\tif(!m_libusb->isAvailable())\n\t\tthrow std::runtime_error(\"libusbWrapper not available\");\n    m_libusb->p_libusb_init(&m_context);\n\n\tfor(auto i = 0; i < kMaxAdapters; ++i)\n\t{\n\t\tauto device = fetch_usb_device(i);\n\t\tif(std::get<0>(device))\n\t\t{\n\t\t\tm_adapters[i].m_device_handle = std::get<0>(device);\n\t\t\tm_adapters[i].m_endpoint_reader = std::get<1>(device);\n\t\t\tm_adapters[i].m_endpoint_writer = std::get<2>(device);\n\t\t}\n\t}\n\n\tif (m_libusb->p_libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))\n\t{\n\t\tm_libusb->p_libusb_hotplug_register_callback(m_context, static_cast<libusb_hotplug_event>(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT),\n\t\t\tLIBUSB_HOTPLUG_NO_FLAGS, kVendorId, kProductId, LIBUSB_HOTPLUG_MATCH_ANY, &GameCubeControllerProvider::hotplug_event, this, &m_callback_handle);\n\t}\n\n\tm_running = true;\n\tm_reader_thread = std::thread(&GameCubeControllerProvider::reader_thread, this);\n\tm_writer_thread = std::thread(&GameCubeControllerProvider::writer_thread, this);\n}\n\nGameCubeControllerProvider::~GameCubeControllerProvider()\n{\n\tif (m_running)\n\t{\n\t\tm_running = false;\n\t\tm_writer_thread.join();\n\t\tm_reader_thread.join();\n\t}\n\n\tif (m_callback_handle)\n\t{\n\t\tm_libusb->p_libusb_hotplug_deregister_callback(m_context, m_callback_handle);\n\t\tm_callback_handle = 0;\n\t}\n\n\tfor (auto& a : m_adapters)\n\t{\n\t\tm_libusb->p_libusb_close(a.m_device_handle);\n\t}\n\n\tif (m_context)\n\t{\n\t\tm_libusb->p_libusb_exit(m_context);\n\t\tm_context = nullptr;\n\t}\n}\n\nstd::vector<ControllerPtr> GameCubeControllerProvider::get_controllers()\n{\n\tstd::vector<ControllerPtr> result;\n\n\tconst auto adapter_count = get_adapter_count();\n\tfor (uint32 adapter_index = 0; adapter_index < adapter_count && adapter_index < kMaxAdapters; ++adapter_index)\n\t{\n\t\t// adapter doesn't tell us which one is actually connected, so we return all of them\n\t\tfor (int index = 0; index < 4; ++index)\n\t\t\tresult.emplace_back(std::make_shared<GameCubeController>(adapter_index, index));\n\t}\n\n\treturn result;\n}\n\nuint32 GameCubeControllerProvider::get_adapter_count() const\n{\n\tuint32 adapter_count = 0;\n\n\tlibusb_device** devices;\n\tconst auto count = m_libusb->p_libusb_get_device_list(nullptr, &devices);\n\tif (count < 0)\n\t{\n\t\tcemuLog_log(LogType::Force, \"libusb error {} at libusb_get_device_list: {}\", static_cast<int>(count), m_libusb->p_libusb_error_name(static_cast<int>(count)));\n\t\treturn adapter_count;\n\t}\n\n\tfor (ssize_t i = 0; i < count; ++i)\n\t{\n\t\tif (!devices[i])\n\t\t\tcontinue;\n\n\t\tlibusb_device_descriptor desc;\n\t\tint ret = m_libusb->p_libusb_get_device_descriptor(devices[i], &desc);\n\t\tif (ret != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"libusb error {} at libusb_get_device_descriptor: {}\", ret, m_libusb->p_libusb_error_name(ret));\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (desc.idVendor != kVendorId || desc.idProduct != kProductId)\n\t\t\tcontinue;\n\n\t\t++adapter_count;\n\t}\n\n\tm_libusb->p_libusb_free_device_list(devices, 1);\n\treturn adapter_count;\n}\n\nbool GameCubeControllerProvider::has_rumble_connected(uint32 adapter_index) const\n{\n\tif (adapter_index >= m_adapters.size())\n\t\treturn false;\n\n\tstd::scoped_lock lock(m_adapters[adapter_index].m_state_mutex);\n\treturn m_adapters[adapter_index].m_rumble_connected;\n}\n\nbool GameCubeControllerProvider::is_connected(uint32 adapter_index) const\n{\n\tif (adapter_index >= m_adapters.size())\n\t\treturn false;\n\n\treturn m_adapters[adapter_index].m_device_handle != nullptr;\n}\n\nvoid GameCubeControllerProvider::set_rumble_state(uint32 adapter_index, uint32 index, bool state)\n{\n\tif (adapter_index >= m_adapters.size())\n\t\treturn;\n\n\tif (index >= kMaxIndex)\n\t\treturn;\n\n\tstd::scoped_lock lock(m_writer_mutex);\n\tm_adapters[adapter_index].rumble_states[index] = state;\n\tm_rumble_changed = true;\n\tm_writer_cond.notify_all();\n}\n\nGameCubeControllerProvider::GCState GameCubeControllerProvider::get_state(uint32 adapter_index, uint32 index)\n{\n\tif (adapter_index >= m_adapters.size())\n\t\treturn {};\n\n\tif (index >= kMaxIndex)\n\t\treturn {};\n\n\tstd::scoped_lock lock(m_adapters[adapter_index].m_state_mutex);\n\treturn m_adapters[adapter_index].m_states[index];\n}\n\n#ifdef interface\n#undef interface\n#endif\n\nstd::tuple<libusb_device_handle*, uint8, uint8> GameCubeControllerProvider::fetch_usb_device(uint32 adapter) const\n{\n\tstd::tuple<libusb_device_handle*, uint8, uint8> result{nullptr, 0xFF, 0xFF};\n\n\tlibusb_device** devices;\n\tconst auto count = m_libusb->p_libusb_get_device_list(nullptr, &devices);\n\tif (count < 0)\n\t{\n\t\tcemuLog_log(LogType::Force, \"libusb error {} at libusb_get_device_list: {}\", static_cast<int>(count), m_libusb->p_libusb_error_name(static_cast<int>(count)));\n\t\treturn result;\n\t}\n\n\tint adapter_index = 0;\n\tfor (ssize_t i = 0; i < count; ++i)\n\t{\n\t\tif (!devices[i])\n\t\t\tcontinue;\n\n\t\tlibusb_device_descriptor desc;\n\t\tint ret = m_libusb->p_libusb_get_device_descriptor(devices[i], &desc);\n\t\tif (ret != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"libusb error {} at libusb_get_device_descriptor: {}\", ret, m_libusb->p_libusb_error_name(ret));\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (desc.idVendor != kVendorId || desc.idProduct != kProductId)\n\t\t\tcontinue;\n\n\t\tif (adapter != adapter_index++)\n\t\t\tcontinue;\n\n\t\tlibusb_device_handle* device_handle;\n\t\tret = m_libusb->p_libusb_open(devices[i], &device_handle);\n\t\tif (ret != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"libusb error {} at libusb_open: {}\", ret, m_libusb->p_libusb_error_name(ret));\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (m_libusb->p_libusb_kernel_driver_active(device_handle, 0) == 1)\n\t\t{\n\t\t\tret = m_libusb->p_libusb_detach_kernel_driver(device_handle, 0);\n\t\t\tif (ret != 0)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"libusb error {} at libusb_detach_kernel_driver: {}\", ret, m_libusb->p_libusb_error_name(ret));\n\t\t\t\tm_libusb->p_libusb_close(device_handle);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tret = m_libusb->p_libusb_claim_interface(device_handle, 0);\n\t\tif (ret != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"libusb error {} at libusb_claim_interface: {}\", ret, m_libusb->p_libusb_error_name(ret));\n\t\t\tm_libusb->p_libusb_close(device_handle);\n\t\t\tcontinue;\n\t\t}\n\n\t\tlibusb_config_descriptor* config = nullptr;\n\t\tm_libusb->p_libusb_get_config_descriptor(devices[i], 0, &config);\n\t\tfor (auto ic = 0; ic < config->bNumInterfaces; ic++)\n\t\t{\n\t\t\tconst auto& interface = config->interface[ic];\n\t\t\tfor (auto j = 0; j < interface.num_altsetting; j++)\n\t\t\t{\n\t\t\t\tconst auto& interface_desc = interface.altsetting[j];\n\t\t\t\tfor (auto k = 0; k < interface_desc.bNumEndpoints; k++)\n\t\t\t\t{\n\t\t\t\t\tconst auto& endpoint = interface_desc.endpoint[k];\n\t\t\t\t\tif (endpoint.bEndpointAddress & LIBUSB_ENDPOINT_IN)\n\t\t\t\t\t\tstd::get<1>(result) = endpoint.bEndpointAddress;\n\t\t\t\t\telse\n\t\t\t\t\t\tstd::get<2>(result) = endpoint.bEndpointAddress;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tm_libusb->p_libusb_free_config_descriptor(config);\n\n\t\t// start polling\n\t\tint size = 0;\n\t\tuint8_t payload = 0x13;\n\t\tm_libusb->p_libusb_interrupt_transfer(device_handle, std::get<2>(result), &payload, sizeof(payload), &size, 25);\n\n\t\tstd::get<0>(result) = device_handle;\n\n\t\tbreak;\n\t}\n\n\tm_libusb->p_libusb_free_device_list(devices, 1);\n\treturn result;\n}\n\nvoid GameCubeControllerProvider::reader_thread()\n{\n\tSetThreadName(\"GCControllerAdapter::reader_thread\");\n\twhile (m_running.load(std::memory_order_relaxed))\n\t{\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\tstd::this_thread::yield();\n\n\t\tfor(auto& adapter : m_adapters)\n\t\t{\n\t\t\tif (!adapter.m_device_handle)\n\t\t\t\tcontinue;\n\n\t\t\tstd::array<uint8_t, 37> data{};\n\t\t\tint read;\n\t\t\tconst int result = m_libusb->p_libusb_interrupt_transfer(adapter.m_device_handle, adapter.m_endpoint_reader, data.data(), static_cast<int>(data.size()), &read, 25);\n\t\t\tif (result == 0)\n\t\t\t{\n\t\t\t\t/*\n\t\t\t\tbyte 1\n\t\t\t\t\t0x10 NORMAL STATE\n\t\t\t\t\t0x20 WAVEBIRD STATE\n\t\t\t\t\t0x04 RUMBLE POWER\n\t\t\t\t */\n\t\t\t\tfor (int i = 0; i < 4; ++i)\n\t\t\t\t{\n\t\t\t\t\tGCState state;\n\t\t\t\t\tstate.valid = true;\n\t\t\t\t\tstate.button = *(uint16*)&data[1 + (i * 9) + 1];\n\t\t\t\t\tstate.lstick_x = data[1 + (i * 9) + 3];\n\t\t\t\t\tstate.lstick_y = data[1 + (i * 9) + 4];\n\t\t\t\t\tstate.rstick_x = data[1 + (i * 9) + 5];\n\t\t\t\t\tstate.rstick_y = data[1 + (i * 9) + 6];\n\t\t\t\t\tstate.lstick = data[1 + (i * 9) + 7];\n\t\t\t\t\tstate.rstick = data[1 + (i * 9) + 8];\n\n\t\t\t\t\tstd::scoped_lock lock(adapter.m_state_mutex);\n\t\t\t\t\tadapter.m_rumble_connected = HAS_FLAG(data[1], 4);\n\t\t\t\t\tadapter.m_states[i] = state;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (result == LIBUSB_ERROR_NO_DEVICE || result == LIBUSB_ERROR_IO)\n\t\t\t{\n\t\t\t\tcemuLog_log(LogType::Force, \"libusb error {} at libusb_interrupt_transfer: {}\", result, m_libusb->p_libusb_error_name(result));\n\t\t\t\tif (const auto handle = adapter.m_device_handle.exchange(nullptr))\n\t\t\t\t\tm_libusb->p_libusb_close(handle);\n\t\t\t}\n\t\t\telse { cemuLog_log(LogType::Force, \"libusb error {} at libusb_interrupt_transfer: {}\", result, m_libusb->p_libusb_error_name(result)); }\n\t\t}\n\t}\n}\n\nvoid GameCubeControllerProvider::writer_thread()\n{\n\tSetThreadName(\"GCControllerAdapter::writer_thread\");\n\n\tstd::array<std::array<bool, 4>, kMaxAdapters> rumble_states{};\n\n\twhile (m_running.load(std::memory_order_relaxed))\n\t{\n\t\tstd::unique_lock lock(m_writer_mutex);\n\t\tif (!m_rumble_changed && m_writer_cond.wait_for(lock, std::chrono::milliseconds(250)) == std::cv_status::timeout)\n\t\t{\n\t\t\tif (!m_running)\n\t\t\t\treturn;\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tbool cmd_sent = false;\n\t\tfor (size_t i = 0; i < kMaxAdapters; ++i)\n\t\t{\n\t\t\tauto& adapter = m_adapters[i];\n\t\t\tif (!adapter.m_device_handle)\n\t\t\t\tcontinue;\n\n\t\t\tif (adapter.rumble_states == rumble_states[i])\n\t\t\t\tcontinue;\n\n\t\t\trumble_states[i] = adapter.rumble_states;\n\t\t\tm_rumble_changed = false;\n\t\t\tlock.unlock();\n\n\t\t\tstd::array<uint8, 5> rumble{ 0x11, rumble_states[i][0],rumble_states[i][1],rumble_states[i][2], rumble_states[i][3] };\n\n\t\t\tint written;\n\t\t\tconst int result = m_libusb->p_libusb_interrupt_transfer(adapter.m_device_handle, adapter.m_endpoint_writer, rumble.data(), static_cast<int>(rumble.size()), &written, 25);\n\t\t\tif (result != 0) { cemuLog_log(LogType::Force, \"libusb error {} at libusb_interrupt_transfer: {}\", result, m_libusb->p_libusb_error_name(result)); }\n\t\t\tcmd_sent = true;\n\n\t\t\tlock.lock();\n\t\t}\n\n\t\tif(cmd_sent)\n\t\t{\n\t\t\tlock.unlock();\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(50));\n\t\t}\n\t}\n}\n\nint GameCubeControllerProvider::hotplug_event(libusb_context* ctx, libusb_device* dev, libusb_hotplug_event event, void* user_data)\n{\n\tauto* thisptr = static_cast<GameCubeControllerProvider*>(user_data);\n\tif (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED == event)\n\t{\n\t\tfor (auto i = 0; i < kMaxAdapters; ++i)\n\t\t{\n\t\t\tif (thisptr->m_adapters[i].m_device_handle)\n\t\t\t\tcontinue;\n\n\t\t\tauto device = thisptr->fetch_usb_device(i);\n\t\t\tif (std::get<0>(device))\n\t\t\t{\n\t\t\t\tthisptr->m_adapters[i].m_endpoint_reader = std::get<1>(device);\n\t\t\t\tthisptr->m_adapters[i].m_endpoint_writer = std::get<2>(device);\n\n\t\t\t\tthisptr->m_adapters[i].m_device_handle = std::get<0>(device);\n\t\t\t}\n\t\t}\n\t}\n\t/*else\n\t{\n\t\tconst auto device_handle = thisptr->m_device_handle.exchange(nullptr);\n\t\tif (device_handle)\n\t\t\tthisptr->m_libusb->p_libusb_close(device_handle);\n\t}*/\n\n\treturn 0;\n}\n\n#endif\n"
  },
  {
    "path": "src/input/api/GameCube/GameCubeControllerProvider.h",
    "content": "#pragma once\n\n#include \"util/libusbWrapper/libusbWrapper.h\"\n#include \"input/api/ControllerProvider.h\"\n\n#ifdef HAS_GAMECUBE\n\nclass GameCubeControllerProvider : public ControllerProviderBase\n{\n\tfriend class DSUController;\npublic:\n\tconstexpr static size_t kMaxAdapters = 4;\n\tconstexpr static size_t kMaxIndex = 4;\n\n\tGameCubeControllerProvider();\n\t~GameCubeControllerProvider();\n\n\tinline static InputAPI::Type kAPIType = InputAPI::GameCube;\n\tInputAPI::Type api() const override { return kAPIType; }\n\n\tstd::vector<std::shared_ptr<ControllerBase>> get_controllers() override;\n\n\tuint32 get_adapter_count() const;\n\tbool has_rumble_connected(uint32 adapter_index) const;\n\tbool is_connected(uint32 adapter_index) const;\n\n\tvoid set_rumble_state(uint32 adapter_index, uint32 index, bool state);\n\t\n\tstruct GCState\n\t{\n\t\tbool valid = false;\n\t\tuint16 button = 0;\n\n\t\tuint8 lstick_x = 0;\n\t\tuint8 lstick_y = 0;\n\n\t\tuint8 rstick_x = 0;\n\t\tuint8 rstick_y = 0;\n\n\t\tuint8 lstick = 0;\n\t\tuint8 rstick = 0;\n\t};\n\tGCState get_state(uint32 adapter_index, uint32 index);\n\nprivate:\n\tstd::shared_ptr<libusbWrapper> m_libusb;\n\tlibusb_context* m_context = nullptr;\n\n\tstd::atomic_bool m_running = false;\n\tstd::thread m_reader_thread, m_writer_thread;\n\n\tvoid reader_thread();\n\tvoid writer_thread();\n\n\t// handle, endpoint_reader, endpoint_writer\n\tstd::tuple<libusb_device_handle*, uint8, uint8> fetch_usb_device(uint32 adapter) const;\n\n\tstd::mutex m_writer_mutex;\n\tstd::condition_variable m_writer_cond;\n\tbool m_rumble_changed = false;\n\tstruct Adapter\n\t{\n\t\tstd::atomic<libusb_device_handle*> m_device_handle{};\n\n\t\tuint8 m_endpoint_reader = 0xFF, m_endpoint_writer = 0xFF;\n\n\t\tmutable std::mutex m_state_mutex;\n\t\tstd::array<GCState, kMaxIndex> m_states{};\n\t\tbool m_rumble_connected = false;\n\n\t\tstd::array<bool, kMaxIndex> rumble_states{};\n\t};\n\tstd::array<Adapter, kMaxAdapters> m_adapters;\n\t\n\tlibusb_hotplug_callback_handle m_callback_handle = 0;\n\tstatic int hotplug_event(struct libusb_context* ctx, struct libusb_device* dev, libusb_hotplug_event event, void* user_data);\n};\n\n#endif"
  },
  {
    "path": "src/input/api/InputAPI.h",
    "content": "#pragma once\n\n#include \"util/helpers/helpers.h\"\n\nnamespace InputAPI\n{\n\tenum Type\n\t{\n\t\tKeyboard,\n\t\tSDLController,\n\t\tXInput,\n\t\tDirectInput,\n\t\tDSUClient,\n\t\tGameCube,\n\t\tWiimote,\n\n\t\tWGIGamepad,\n\t\tWGIRawController,\n\n\t\tMAX\n\t};\n\n\tconstexpr std::string_view to_string(Type type)\n\t{\n\t\tswitch (type)\n\t\t{\n\t\tcase Keyboard:\n\t\t\treturn \"Keyboard\";\n\t\tcase DirectInput:\n\t\t\treturn \"DirectInput\";\n\t\tcase XInput:\n\t\t\treturn \"XInput\";\n\t\tcase Wiimote:\n\t\t\treturn \"Wiimote\";\n\t\tcase GameCube:\n\t\t\treturn \"GameCube\";\n\t\tcase DSUClient:\n\t\t\treturn \"DSUController\";\n\t\tcase WGIGamepad:\n\t\t\treturn \"WGIGamepad\";\n\t\tcase WGIRawController:\n\t\t\treturn \"WGIRawController\";\n\t\tcase SDLController:\n\t\t\treturn \"SDLController\";\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\tthrow std::runtime_error(fmt::format(\"unknown input api: {}\", to_underlying(type)));\n\t}\n\n\tconstexpr Type from_string(std::string_view str)\n\t{\n\t\tif (str == to_string(Keyboard))\n\t\t\treturn Keyboard;\n\t\telse if (str == to_string(DirectInput))\n\t\t\treturn DirectInput;\n\t\telse if (str == to_string(XInput))\n\t\t\treturn XInput;\n\t\telse if (str == to_string(Wiimote))\n\t\t\treturn Wiimote;\n\t\telse if (str == to_string(GameCube))\n\t\t\treturn GameCube;\n\t\telse if (str == to_string(DSUClient))\n\t\t\treturn DSUClient;\n\t\telse if (str == to_string(SDLController))\n\t\t\treturn SDLController;\n\t\telse if (str == \"DSU\") // legacy\n\t\t\treturn DSUClient;\n\t\t\n\t\t//else if (str == \"WGIGamepad\")\n\t\t//\treturn WGIGamepad;\n\t\t//\n\t\t//else if (str == \"WGIRawController\")\n\t\t//\treturn WGIRawController;\n\n\t\tthrow std::runtime_error(fmt::format(\"unknown input api: {}\", str));\n\t}\n}\n"
  },
  {
    "path": "src/input/api/Keyboard/KeyboardController.cpp",
    "content": "#include <boost/container/small_vector.hpp>\n\n#include \"input/api/Keyboard/KeyboardController.h\"\n#include \"WindowSystem.h\"\n\nKeyboardController::KeyboardController()\n\t: base_type(\"keyboard\", \"Keyboard\")\n{\n\t\n}\n\nstd::string KeyboardController::get_button_name(uint64 button) const\n{\n\treturn WindowSystem::GetKeyCodeName(button);\n}\n\nControllerState KeyboardController::raw_state()\n{\n\tControllerState result{};\n\n\tif (WindowSystem::GetWindowInfo().debugger_focused)\n\t\treturn result;\n\n\tboost::container::small_vector<uint32, 16> pressedKeys;\n\tWindowSystem::GetWindowInfo().iter_keystates([&pressedKeys](const std::pair<const uint32, bool>& keyState) { if (keyState.second) pressedKeys.emplace_back(keyState.first); });\n\tresult.buttons.SetPressedButtons(pressedKeys);\n\treturn result;\n}\n"
  },
  {
    "path": "src/input/api/Keyboard/KeyboardController.h",
    "content": "#pragma once\n\n#include \"input/api/Keyboard/KeyboardControllerProvider.h\"\n#include \"input/api/Controller.h\"\n\nclass KeyboardController : public Controller<KeyboardControllerProvider>\n{\npublic:\n\tKeyboardController();\n\n\tstd::string_view api_name() const override // TODO: use constexpr virtual function with c++20\n\t{\n\t\tstatic_assert(to_string(InputAPI::Keyboard) == \"Keyboard\");\n\t\treturn to_string(InputAPI::Keyboard);\n\t}\n\tInputAPI::Type api() const override { return InputAPI::Keyboard; }\n\n\tbool is_connected() override { return true; }\n\n\tbool has_axis() const override { return false; }\n\n\tstd::string get_button_name(uint64 button) const override;\n\nprotected:\n\tControllerState raw_state() override;\n\n};\n"
  },
  {
    "path": "src/input/api/Keyboard/KeyboardControllerProvider.cpp",
    "content": "#include \"input/api/Keyboard/KeyboardControllerProvider.h\"\n\n#include \"input/api/Keyboard/KeyboardController.h\"\n\nstd::vector<std::shared_ptr<ControllerBase>> KeyboardControllerProvider::get_controllers()\n{\n\tstd::vector<std::shared_ptr<ControllerBase>> result;\n\tresult.emplace_back(std::make_shared<KeyboardController>());\n\treturn result;\n}\n"
  },
  {
    "path": "src/input/api/Keyboard/KeyboardControllerProvider.h",
    "content": "#pragma once\n\n#include \"input/api/ControllerProvider.h\"\n\n#ifndef HAS_KEYBOARD\n#define HAS_KEYBOARD 1\n#endif\n\nclass KeyboardControllerProvider : public ControllerProviderBase\n{\n\tfriend class KeyboardController;\npublic:\n\tinline static InputAPI::Type kAPIType = InputAPI::Keyboard;\n\tInputAPI::Type api() const override { return kAPIType; }\n\n\tstd::vector<std::shared_ptr<ControllerBase>> get_controllers() override;\n};\n"
  },
  {
    "path": "src/input/api/SDL/SDLController.cpp",
    "content": "#include \"input/api/SDL/SDLController.h\"\n\n#include \"input/api/SDL/SDLControllerProvider.h\"\n\nSDLController::SDLController(const SDL_JoystickGUID& guid, size_t guid_index)\n\t: base_type(fmt::format(\"{}_\", guid_index), fmt::format(\"Controller {}\", guid_index + 1)), m_guid_index(guid_index),\n\t  m_guid(guid)\n{\n\tchar tmp[64];\n\tSDL_JoystickGetGUIDString(m_guid, tmp, std::size(tmp));\n\tm_uuid += tmp;\n}\n\nSDLController::SDLController(const SDL_JoystickGUID& guid, size_t guid_index, std::string_view display_name)\n\t: base_type(fmt::format(\"{}_\", guid_index), display_name), m_guid_index(guid_index), m_guid(guid)\n{\n\tchar tmp[64];\n\tSDL_JoystickGetGUIDString(m_guid, tmp, std::size(tmp));\n\tm_uuid += tmp;\n}\n\nSDLController::~SDLController()\n{\n\tif (m_controller)\n\t\tSDL_GameControllerClose(m_controller);\n}\n\nbool SDLController::is_connected()\n{\n\tstd::scoped_lock lock(m_controller_mutex);\n\tif (!m_controller)\n\t{\n\t\treturn false;\n\t}\n\n\tif (!SDL_GameControllerGetAttached(m_controller))\n\t{\n\t\tm_controller = nullptr;\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nbool SDLController::connect()\n{\n\tif (is_connected())\n\t{\n\t\treturn true;\n\t}\n\n\tm_has_rumble = false;\n\n\tconst auto index = m_provider->get_index(m_guid_index, m_guid);\n\n\tstd::scoped_lock lock(m_controller_mutex);\n\tm_diid = SDL_JoystickGetDeviceInstanceID(index);\n\tif (m_diid == -1)\n\t\treturn false;\n\n\tm_controller = SDL_GameControllerOpen(index);\n\tif (!m_controller)\n\t\treturn false;\n\n\tif (const char* name = SDL_GameControllerName(m_controller))\n\t\tm_display_name = name;\n\n\tfor (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i)\n\t{\n\t\tm_buttons[i] = SDL_GameControllerHasButton(m_controller, (SDL_GameControllerButton)i);\n\t}\n\n\tfor (int i = 0; i < SDL_CONTROLLER_AXIS_MAX; ++i)\n\t{\n\t\tm_axis[i] = SDL_GameControllerHasAxis(m_controller, (SDL_GameControllerAxis)i);\n\t}\n\n\tif (SDL_GameControllerHasSensor(m_controller, SDL_SENSOR_ACCEL))\n\t{\n\t\tm_has_accel = true;\n\t\tSDL_GameControllerSetSensorEnabled(m_controller, SDL_SENSOR_ACCEL, SDL_TRUE);\n\t}\n\n\tif (SDL_GameControllerHasSensor(m_controller, SDL_SENSOR_GYRO))\n\t{\n\t\tm_has_gyro = true;\n\t\tSDL_GameControllerSetSensorEnabled(m_controller, SDL_SENSOR_GYRO, SDL_TRUE);\n\t}\n\n\tm_has_rumble = SDL_GameControllerRumble(m_controller, 0, 0, 0) == 0;\n\treturn true;\n}\n\nvoid SDLController::start_rumble()\n{\n\tstd::scoped_lock lock(m_controller_mutex);\n\tif (is_connected() && !m_has_rumble)\n\t\treturn;\n\n\tif (m_settings.rumble <= 0)\n\t\treturn;\n\n\tSDL_GameControllerRumble(m_controller, (Uint16)(m_settings.rumble * 0xFFFF), (Uint16)(m_settings.rumble * 0xFFFF),\n\t                         5 * 1000);\n}\n\nvoid SDLController::stop_rumble()\n{\n\tstd::scoped_lock lock(m_controller_mutex);\n\tif (is_connected() && !m_has_rumble)\n\t\treturn;\n\n\tSDL_GameControllerRumble(m_controller, 0, 0, 0);\n}\n\nMotionSample SDLController::get_motion_sample()\n{\n\tif (is_connected() && has_motion())\n\t{\n\t\treturn m_provider->motion_sample(m_diid);\n\t}\n\n\treturn {};\n}\n\nstd::string SDLController::get_button_name(uint64 button) const\n{\n\tif (const char* name = SDL_GameControllerGetStringForButton((SDL_GameControllerButton)button))\n\t\treturn name;\n\n\treturn base_type::get_button_name(button);\n}\n\nControllerState SDLController::raw_state()\n{\n\tControllerState result{};\n\n\tstd::scoped_lock lock(m_controller_mutex);\n\tif (!is_connected())\n\t\treturn result;\n\n\tfor (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i)\n\t{\n\t\tif (m_buttons[i] && SDL_GameControllerGetButton(m_controller, (SDL_GameControllerButton)i))\n\t\t\tresult.buttons.SetButtonState(i, true);\n\t}\n\n\tif (m_axis[SDL_CONTROLLER_AXIS_LEFTX])\n\t\tresult.axis.x = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_LEFTX) / 32767.0f;\n\n\tif (m_axis[SDL_CONTROLLER_AXIS_LEFTY])\n\t\tresult.axis.y = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_LEFTY) / 32767.0f;\n\n\tif (m_axis[SDL_CONTROLLER_AXIS_RIGHTX])\n\t\tresult.rotation.x = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_RIGHTX) / 32767.0f;\n\n\tif (m_axis[SDL_CONTROLLER_AXIS_RIGHTY])\n\t\tresult.rotation.y = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_RIGHTY) / 32767.0f;\n\n\tif (m_axis[SDL_CONTROLLER_AXIS_TRIGGERLEFT])\n\t\tresult.trigger.x = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) / 32767.0f;\n\n\tif (m_axis[SDL_CONTROLLER_AXIS_TRIGGERRIGHT])\n\t\tresult.trigger.y = (float)SDL_GameControllerGetAxis(m_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) / 32767.0f;\n\n\treturn result;\n}\n"
  },
  {
    "path": "src/input/api/SDL/SDLController.h",
    "content": "#pragma once\n\n#include \"input/api/Controller.h\"\n#include \"input/api/SDL/SDLControllerProvider.h\"\n\n#include <SDL2/SDL_gamecontroller.h>\n\nclass SDLController : public Controller<SDLControllerProvider>\n{\npublic:\n\tSDLController(const SDL_JoystickGUID& guid, size_t guid_index);\n\tSDLController(const SDL_JoystickGUID& guid, size_t guid_index, std::string_view display_name);\n\t\n\t~SDLController() override;\n\t\n\tstd::string_view api_name() const override\n\t{\n\t\tstatic_assert(to_string(InputAPI::SDLController) == \"SDLController\");\n\t\treturn to_string(InputAPI::SDLController);\n\t}\n\tInputAPI::Type api() const override { return InputAPI::SDLController; }\n\n\tbool is_connected() override;\n\tbool connect() override;\n\t\n\tbool has_motion() override { return m_has_gyro && m_has_accel; }\n\tbool has_rumble() override { return m_has_rumble; }\n\t\n\tvoid start_rumble() override;\n\tvoid stop_rumble() override;\n\n\tMotionSample get_motion_sample() override;\n\n\tstd::string get_button_name(uint64 button) const override;\n\tconst SDL_JoystickGUID& get_guid() const { return m_guid; }\n\n\tconstexpr static SDL_JoystickGUID kLeftJoyCon{ 0x03, 0x00, 0x00, 0x00, 0x7e, 0x05, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00,0x68 ,0x00 };\n\tconstexpr static SDL_JoystickGUID kRightJoyCon{ 0x03, 0x00, 0x00, 0x00, 0x7e, 0x05, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00 };\n\tconstexpr static SDL_JoystickGUID kSwitchProController{ 0x03, 0x00, 0x00, 0x00, 0x7e, 0x05, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00 };\n\nprotected:\n\tControllerState raw_state() override;\n\nprivate:\n\tinline static SDL_JoystickGUID kEmptyGUID{};\n\n\tsize_t m_guid_index;\n\tSDL_JoystickGUID m_guid;\n\tstd::recursive_mutex m_controller_mutex;\n\tSDL_GameController* m_controller = nullptr;\n\tSDL_JoystickID m_diid = -1;\n\n\tbool m_has_gyro = false;\n\tbool m_has_accel = false;\n\tbool m_has_rumble = false;\n\t\n\tstd::array<bool, SDL_CONTROLLER_BUTTON_MAX> m_buttons{};\n\tstd::array<bool, SDL_CONTROLLER_AXIS_MAX> m_axis{};\n};\n\n"
  },
  {
    "path": "src/input/api/SDL/SDLControllerProvider.cpp",
    "content": "#include \"input/api/SDL/SDLControllerProvider.h\"\n\n#include \"input/api/SDL/SDLController.h\"\n#include \"util/helpers/TempState.h\"\n\n#include <SDL2/SDL.h>\n#include <boost/functional/hash.hpp>\n\nstruct SDL_JoystickGUIDHash\n{\n\tstd::size_t operator()(const SDL_JoystickGUID& guid) const\n\t{\n\t\treturn boost::hash_value(guid.data);\n\t}\n};\n\nSDLControllerProvider::SDLControllerProvider()\n{\n\tSDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, \"1\");\n\n\tSDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, \"1\");\n\tSDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5, \"1\");\n\n\tSDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, \"1\");\n\tSDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, \"1\");\n\n\tSDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, \"1\");\n\tSDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH, \"1\");\n\tSDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, \"1\");\n\tSDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STADIA, \"1\");\n\tSDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAM, \"1\");\n\tSDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_LUNA, \"1\");\n\n\tif (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC | SDL_INIT_EVENTS) < 0) \n\t\tthrow std::runtime_error(fmt::format(\"couldn't initialize SDL: {}\", SDL_GetError()));\n\t\t\n\n\tif (SDL_GameControllerEventState(SDL_ENABLE) < 0) {\n\t\tcemuLog_log(LogType::Force, \"Couldn't enable SDL gamecontroller event polling: {}\", SDL_GetError());\n\t}\n\n\tm_running = true;\n\tm_thread = std::thread(&SDLControllerProvider::event_thread, this);\n}\n\nSDLControllerProvider::~SDLControllerProvider()\n{\n\tif (m_running)\n\t{\n\t\tm_running = false;\n\t\t// wake the thread with a quit event if it's currently waiting for events\n\t\tSDL_Event evt;\n\t\tevt.type = SDL_QUIT;\n\t\tSDL_PushEvent(&evt);\n\t\t// wait until thread exited\n\t\tm_thread.join();\n\t}\n\n\tSDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC | SDL_INIT_EVENTS);\n}\n\nstd::vector<std::shared_ptr<ControllerBase>> SDLControllerProvider::get_controllers()\n{\n\tstd::vector<std::shared_ptr<ControllerBase>> result;\n\n\tstd::unordered_map<SDL_JoystickGUID, size_t, SDL_JoystickGUIDHash> guid_counter;\n\n\tTempState lock(SDL_LockJoysticks, SDL_UnlockJoysticks);\n\tfor (int i = 0; i < SDL_NumJoysticks(); ++i)\n\t{\n\t\tif (SDL_JoystickGetDeviceType(i) == SDL_JOYSTICK_TYPE_GAMECONTROLLER)\n\t\t{\n\t\t\tconst auto guid = SDL_JoystickGetDeviceGUID(i);\n\n\t\t\tconst auto it = guid_counter.try_emplace(guid, 0);\n\n\t\t\tif (auto* controller = SDL_GameControllerOpen(i))\n\t\t\t{\n\t\t\t\tconst char* name = SDL_GameControllerName(controller);\n\n\t\t\t\tresult.emplace_back(std::make_shared<SDLController>(guid, it.first->second, name));\n\t\t\t\tSDL_GameControllerClose(controller);\n\t\t\t}\n\t\t\telse\n\t\t\t\tresult.emplace_back(std::make_shared<SDLController>(guid, it.first->second));\n\n\t\t\t++it.first->second;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nint SDLControllerProvider::get_index(size_t guid_index, const SDL_JoystickGUID& guid) const\n{\n\tsize_t index = 0;\n\n\tTempState lock(SDL_LockJoysticks, SDL_UnlockJoysticks);\n\tfor (int i = 0; i < SDL_NumJoysticks(); ++i)\n\t{\n\t\tif (SDL_JoystickGetDeviceType(i) == SDL_JOYSTICK_TYPE_GAMECONTROLLER)\n\t\t{\n\t\t\tif(guid == SDL_JoystickGetDeviceGUID(i))\n\t\t\t{\n\t\t\t\tif (index == guid_index)\n\t\t\t\t{\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\n\t\t\t\t++index;\n\t\t\t}\n\t\t\t\n\t\t}\n\t}\n\n\treturn -1;\n}\n\nMotionSample SDLControllerProvider::motion_sample(int diid)\n{\n\tstd::scoped_lock lock(m_motion_data_mtx[diid]);\n\treturn m_motion_data[diid];\n}\n\nvoid SDLControllerProvider::event_thread()\n{\n\tSetThreadName(\"SDL_events\");\n\twhile (m_running.load(std::memory_order_relaxed))\n\t{\n\t\tSDL_Event event{};\n\t\tSDL_WaitEvent(&event);\n\n\t\tswitch (event.type)\n\t\t{\n\t\tcase SDL_QUIT:\n\t\t\tm_running = false;\n\t\t\treturn;\n\t\t\t\n\t\tcase SDL_CONTROLLERAXISMOTION: /**< Game controller axis motion */\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcase SDL_CONTROLLERBUTTONDOWN: /**< Game controller button pressed */\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcase SDL_CONTROLLERBUTTONUP: /**< Game controller button released */\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcase SDL_CONTROLLERDEVICEADDED: /**< A new Game controller has been inserted into the system */\n\t\t{\n\t\t\tInputManager::instance().on_device_changed();\n\t\t\tbreak;\n\t\t}\n\t\tcase SDL_CONTROLLERDEVICEREMOVED: /**< An opened Game controller has been removed */\n\t\t{\n\t\t\tInputManager::instance().on_device_changed();\n\t\t\tbreak;\n\t\t}\n\t\tcase SDL_CONTROLLERDEVICEREMAPPED: /**< The controller mapping was updated */\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcase SDL_CONTROLLERTOUCHPADDOWN:        /**< Game controller touchpad was touched */\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcase SDL_CONTROLLERTOUCHPADMOTION:      /**< Game controller touchpad finger was moved */\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcase SDL_CONTROLLERTOUCHPADUP:          /**< Game controller touchpad finger was lifted */\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcase SDL_CONTROLLERSENSORUPDATE:        /**< Game controller sensor was updated */\n\t\t{\n\t\t\tconst auto index = event.csensor.which;\n\t\t\tconst auto ts = event.csensor.timestamp;\n\t\t\tauto& motionTracking = m_motion_tracking[index];\n\n\t\t\tif (event.csensor.sensor == SDL_SENSOR_ACCEL)\n\t\t\t{\n\t\t\t\tconst auto dif = ts - motionTracking.lastTimestampAccel;\n\t\t\t\tif (dif <= 0)\n\t\t\t\t\tbreak;\n\n\t\t\t\tif (dif >= 10000)\n\t\t\t\t{\n\t\t\t\t\tmotionTracking.hasAcc = false;\n\t\t\t\t\tmotionTracking.hasGyro = false;\n\t\t\t\t\tmotionTracking.lastTimestampAccel = ts;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tmotionTracking.lastTimestampAccel = ts;\n\t\t\t\tmotionTracking.acc[0] = -event.csensor.data[0] / 9.81f;\n\t\t\t\tmotionTracking.acc[1] = -event.csensor.data[1] / 9.81f;\n\t\t\t\tmotionTracking.acc[2] = -event.csensor.data[2] / 9.81f;\n\t\t\t\tmotionTracking.hasAcc = true;\n\t\t\t}\n\t\t\tif (event.csensor.sensor == SDL_SENSOR_GYRO)\n\t\t\t{\n\t\t\t\tconst auto dif = ts - motionTracking.lastTimestampGyro;\n\t\t\t\tif (dif <= 0)\n\t\t\t\t\tbreak;\n\n\t\t\t\tif (dif >= 10000)\n\t\t\t\t{\n\t\t\t\t\tmotionTracking.hasAcc = false;\n\t\t\t\t\tmotionTracking.hasGyro = false;\n\t\t\t\t\tmotionTracking.lastTimestampGyro = ts;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmotionTracking.lastTimestampGyro = ts;\n\t\t\t\tmotionTracking.gyro[0] = event.csensor.data[0];\n\t\t\t\tmotionTracking.gyro[1] = -event.csensor.data[1];\n\t\t\t\tmotionTracking.gyro[2] = -event.csensor.data[2];\n\t\t\t\tmotionTracking.hasGyro = true;\n\t\t\t}\n\t\t\tif (motionTracking.hasAcc && motionTracking.hasGyro)\n\t\t\t{\n\t\t\t\tauto ts = std::max(motionTracking.lastTimestampGyro, motionTracking.lastTimestampAccel);\n\t\t\t\tif (ts > motionTracking.lastTimestampIntegrate)\n\t\t\t\t{\n\t\t\t\t\tconst auto tsDif = ts - motionTracking.lastTimestampIntegrate;\n\t\t\t\t\tmotionTracking.lastTimestampIntegrate = ts;\n\t\t\t\t\tfloat tsDifD = (float)tsDif / 1000.0f;\n\t\t\t\t\tif (tsDifD >= 1.0f)\n\t\t\t\t\t\ttsDifD = 1.0f;\n\t\t\t\t\tm_motion_handler[index].processMotionSample(tsDifD, motionTracking.gyro.x, motionTracking.gyro.y, motionTracking.gyro.z, motionTracking.acc.x, -motionTracking.acc.y, -motionTracking.acc.z);\n\n\t\t\t\t\tstd::scoped_lock lock(m_motion_data_mtx[index]);\n\t\t\t\t\tm_motion_data[index] = m_motion_handler[index].getMotionSample();\n\t\t\t\t}\n\t\t\t\tmotionTracking.hasAcc = false;\n\t\t\t\tmotionTracking.hasGyro = false;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/input/api/SDL/SDLControllerProvider.h",
    "content": "#pragma once\n#include <SDL2/SDL_joystick.h>\n#include \"input/motion/MotionHandler.h\"\n#include \"input/api/ControllerProvider.h\"\n\n#ifndef HAS_SDL\n#define HAS_SDL 1\n#endif\n\nstatic bool operator==(const SDL_JoystickGUID& g1, const SDL_JoystickGUID& g2)\n{\n\treturn memcmp(&g1, &g2, sizeof(SDL_JoystickGUID)) == 0;\n}\n\nclass SDLControllerProvider : public ControllerProviderBase\n{\n\tfriend class SDLController;\npublic:\n\tSDLControllerProvider();\n\t~SDLControllerProvider();\n\n\tinline static InputAPI::Type kAPIType = InputAPI::SDLController;\n\tInputAPI::Type api() const override { return kAPIType; }\n\n\tstd::vector<std::shared_ptr<ControllerBase>> get_controllers() override;\n\t\n\tint get_index(size_t guid_index, const SDL_JoystickGUID& guid) const;\n\n\tMotionSample motion_sample(int diid);\n\nprivate:\n\tvoid event_thread();\n\t\n\tstd::atomic_bool m_running = false;\n\tstd::thread m_thread;\n\n\tstd::array<WiiUMotionHandler, 8> m_motion_handler{};\n\tstd::array<MotionSample, 8> m_motion_data{};\n\tstd::array<std::mutex, 8> m_motion_data_mtx{};\n\n\tstruct MotionInfoTracking\n\t{\n\t\tuint64 lastTimestampGyro{};\n\t\tuint64 lastTimestampAccel{};\n\t\tuint64 lastTimestampIntegrate{};\n\t\tbool hasGyro{};\n\t\tbool hasAcc{};\n\t\tglm::vec3 gyro{};\n\t\tglm::vec3 acc{};\n\t};\n\n\tstd::array<MotionInfoTracking, 8> m_motion_tracking{};\n\n};\n"
  },
  {
    "path": "src/input/api/Wiimote/NativeWiimoteController.cpp",
    "content": "#include \"input/api/Wiimote/NativeWiimoteController.h\"\n\n#include \"input/api/Wiimote/WiimoteControllerProvider.h\"\n\n#include <pugixml.hpp>\n\nNativeWiimoteController::NativeWiimoteController(size_t index)\n\t: base_type(fmt::format(\"{}\", index), fmt::format(\"Controller {}\", index + 1)), m_index(index)\n{\n\tm_settings.motion = true;\n}\n\nvoid NativeWiimoteController::save(pugi::xml_node& node)\n{\n\tbase_type::save(node);\n\n\tnode.append_child(\"packet_delay\").append_child(pugi::node_pcdata).set_value(\n\t\tfmt::format(\"{}\", m_packet_delay).c_str());\n}\n\nvoid NativeWiimoteController::load(const pugi::xml_node& node)\n{\n\tbase_type::load(node);\n\n\tif (const auto value = node.child(\"packet_delay\"))\n\t\tm_packet_delay = ConvertString<uint32>(value.child_value());\n}\n\nbool NativeWiimoteController::connect()\n{\n\tif (is_connected())\n\t\treturn true;\n\n\tif (!m_provider->is_registered_device(m_index))\n\t{\n\t\tm_provider->get_controllers();\n\t}\n\n\tif (m_provider->is_connected(m_index))\n\t{\n\t\tm_provider->set_packet_delay(m_index, m_packet_delay);\n\t\tm_provider->set_led(m_index, m_player_index);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nbool NativeWiimoteController::is_connected()\n{\n\tif (m_provider->is_connected(m_index))\n\t{\n\t\tm_provider->set_packet_delay(m_index, m_packet_delay);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvoid NativeWiimoteController::set_player_index(size_t player_index)\n{\n\tm_player_index = player_index;\n\tm_provider->set_led(m_index, m_player_index);\n}\n\nNativeWiimoteController::Extension NativeWiimoteController::get_extension() const\n{\n\tExtension result = None;\n\tconst auto ext = m_provider->get_state(m_index).m_extension;\n\tif (std::holds_alternative<NunchuckData>(ext))\n\t\tresult = Nunchuck;\n\telse if (std::holds_alternative<ClassicData>(ext))\n\t\tresult = Classic;\n\n\treturn result;\n}\n\nbool NativeWiimoteController::is_mpls_attached() const\n{\n\treturn m_provider->get_state(m_index).m_motion_plus.has_value();\n}\n\nbool NativeWiimoteController::has_position()\n{\n\tconst auto state = m_provider->get_state(m_index);\n\treturn std::any_of(state.ir_camera.dots.cbegin(), state.ir_camera.dots.cend(),\n\t                   [](const IRDot& v) { return v.visible; });\n}\n\nglm::vec2 NativeWiimoteController::get_position()\n{\n\tconst auto state = m_provider->get_state(m_index);\n\treturn state.ir_camera.position;\n}\n\nglm::vec2 NativeWiimoteController::get_prev_position()\n{\n\tconst auto state = m_provider->get_state(m_index);\n\treturn state.ir_camera.m_prev_position;\n}\nPositionVisibility NativeWiimoteController::GetPositionVisibility()\n{\n\tconst auto state = m_provider->get_state(m_index);\n\treturn state.ir_camera.m_positionVisibility;\n}\n\nbool NativeWiimoteController::has_low_battery()\n{\n\tconst auto state = m_provider->get_state(m_index);\n\treturn HAS_FLAG(state.flags, kBatteryEmpty);\n}\n\nvoid NativeWiimoteController::start_rumble()\n{\n\tif (m_settings.rumble < 1.0f)\n\t{\n\t\treturn;\n\t}\n\n\tm_provider->set_rumble(m_index, true);\n}\n\nvoid NativeWiimoteController::stop_rumble()\n{\n\tm_provider->set_rumble(m_index, false);\n}\n\nMotionSample NativeWiimoteController::get_motion_sample()\n{\n\tconst auto state = m_provider->get_state(m_index);\n\treturn state.motion_sample;\n}\n\nMotionSample NativeWiimoteController::get_nunchuck_motion_sample() const\n{\n\tconst auto state = m_provider->get_state(m_index);\n\tif (std::holds_alternative<NunchuckData>(state.m_extension))\n\t{\n\t\treturn std::get<NunchuckData>(state.m_extension).motion_sample;\n\t}\n\n\treturn {};\n}\n\nstd::string NativeWiimoteController::get_button_name(uint64 button) const\n{\n\tswitch (button)\n\t{\n\tcase kWiimoteButton_A: return \"A\";\n\tcase kWiimoteButton_B: return \"B\";\n\n\tcase kWiimoteButton_One: return \"1\";\n\tcase kWiimoteButton_Two: return \"2\";\n\n\tcase kWiimoteButton_Plus: return \"+\";\n\tcase kWiimoteButton_Minus: return \"-\";\n\n\tcase kWiimoteButton_Home: return \"HOME\";\n\n\tcase kWiimoteButton_Up: return \"UP\";\n\tcase kWiimoteButton_Down: return \"DOWN\";\n\tcase kWiimoteButton_Left: return \"LEFT\";\n\tcase kWiimoteButton_Right: return \"RIGHT\";\n\n\t// nunchuck\n\tcase kWiimoteButton_C: return \"C\";\n\tcase kWiimoteButton_Z: return \"Z\";\n\n\t// classic\n\tcase kHighestWiimote + kClassicButton_A: return \"A\";\n\tcase kHighestWiimote + kClassicButton_B: return \"B\";\n\tcase kHighestWiimote + kClassicButton_Y: return \"Y\";\n\tcase kHighestWiimote + kClassicButton_X: return \"X\";\n\n\tcase kHighestWiimote + kClassicButton_Plus: return \"+\";\n\tcase kHighestWiimote + kClassicButton_Minus: return \"-\";\n\n\tcase kHighestWiimote + kClassicButton_Home: return \"HOME\";\n\n\tcase kHighestWiimote + kClassicButton_Up: return \"UP\";\n\tcase kHighestWiimote + kClassicButton_Down: return \"DOWN\";\n\tcase kHighestWiimote + kClassicButton_Left: return \"LEFT\";\n\tcase kHighestWiimote + kClassicButton_Right: return \"RIGHT\";\n\n\tcase kHighestWiimote + kClassicButton_L: return \"L\";\n\tcase kHighestWiimote + kClassicButton_R: return \"R\";\n\n\tcase kHighestWiimote + kClassicButton_ZL: return \"ZL\";\n\tcase kHighestWiimote + kClassicButton_ZR: return \"ZR\";\n\t}\n\n\treturn base_type::get_button_name(button);\n}\n\nuint32 NativeWiimoteController::get_packet_delay()\n{\n\tm_packet_delay = m_provider->get_packet_delay(m_index);\n\treturn m_packet_delay;\n}\n\nvoid NativeWiimoteController::set_packet_delay(uint32 delay)\n{\n\tm_packet_delay = delay;\n\tm_provider->set_packet_delay(m_index, delay);\n}\n\nControllerState NativeWiimoteController::raw_state()\n{\n\tControllerState result{};\n\tif (!is_connected())\n\t\treturn result;\n\n\tconst auto state = m_provider->get_state(m_index);\n\tfor (int i = 0; i < std::numeric_limits<uint16>::digits; i++)\n\t\tresult.buttons.SetButtonState(i, (state.buttons & (1 << i)) != 0);\n\n\tif (std::holds_alternative<NunchuckData>(state.m_extension))\n\t{\n\t\tconst auto nunchuck = std::get<NunchuckData>(state.m_extension);\n\t\tif (nunchuck.c)\n\t\t\tresult.buttons.SetButtonState(kWiimoteButton_C, true);\n\n\t\tif (nunchuck.z)\n\t\t\tresult.buttons.SetButtonState(kWiimoteButton_Z, true);\n\n\t\tresult.axis = nunchuck.axis;\n\t}\n\telse if (std::holds_alternative<ClassicData>(state.m_extension))\n\t{\n\t\tconst auto classic = std::get<ClassicData>(state.m_extension);\n\t\tuint64 buttons = (uint64)classic.buttons << kHighestWiimote;\n\t\tfor (int i = 0; i < std::numeric_limits<uint64>::digits; i++)\n\t\t{\n\t\t\t// OR with base buttons\n\t\t\tif((buttons & (1 << i)))\n\t\t\t\tresult.buttons.SetButtonState(i, true);\n\t\t}\n\t\tresult.axis = classic.left_axis;\n\t\tresult.rotation = classic.right_axis;\n\t\tresult.trigger = classic.trigger;\n\t}\n\n\treturn result;\n}\n"
  },
  {
    "path": "src/input/api/Wiimote/NativeWiimoteController.h",
    "content": "#pragma once\n\n#include \"input/api/Controller.h\"\n#include \"input/api/Wiimote/WiimoteControllerProvider.h\"\n\n// todo: find better name because of emulated nameclash\nclass NativeWiimoteController : public Controller<WiimoteControllerProvider>\n{\npublic:\n\tNativeWiimoteController(size_t index);\n\n\tenum Extension\n\t{\n\t\tNone,\n\t\tNunchuck,\n\t\tClassic,\n\t\tMotionPlus,\n\t};\n\t\n\tstd::string_view api_name() const override\n\t{\n\t\tstatic_assert(to_string(InputAPI::Wiimote) == \"Wiimote\");\n\t\treturn to_string(InputAPI::Wiimote);\n\t}\n\tInputAPI::Type api() const override { return InputAPI::Wiimote; }\n\n\tvoid save(pugi::xml_node& node) override;\n\tvoid load(const pugi::xml_node& node) override;\n\n\tbool connect() override;\n\tbool is_connected() override;\n\n\tvoid set_player_index(size_t player_index);\n\n\tExtension get_extension() const;\n\tbool is_mpls_attached() const;\n\n\tControllerState raw_state() override;\n\n\tbool has_position() override;\n\tglm::vec2 get_position() override;\n\tglm::vec2 get_prev_position() override;\n\tPositionVisibility GetPositionVisibility() override;\n\t\n\tbool has_motion() override { return true; }\n\tbool has_rumble() override { return true; }\n\n\tbool has_battery() override { return true; }\n\tbool has_low_battery() override;\n\t\n\tvoid start_rumble() override;\n\tvoid stop_rumble() override;\n\n\tMotionSample get_motion_sample() override;\n\tMotionSample get_nunchuck_motion_sample() const;\n\n\tstd::string get_button_name(uint64 button) const override;\n\n\tuint32 get_packet_delay();\n\tvoid set_packet_delay(uint32 delay);\n\nprivate:\n\tsize_t m_index;\n\tsize_t m_player_index = 0;\n\tuint32 m_packet_delay = WiimoteControllerProvider::kDefaultPacketDelay;\n};\n\n"
  },
  {
    "path": "src/input/api/Wiimote/WiimoteControllerProvider.cpp",
    "content": "#include \"input/api/Wiimote/WiimoteControllerProvider.h\"\n#include \"input/api/Wiimote/NativeWiimoteController.h\"\n#include \"input/api/Wiimote/WiimoteMessages.h\"\n\n#ifdef HAS_HIDAPI\n#include \"input/api/Wiimote/hidapi/HidapiWiimote.h\"\n#endif\n#ifdef HAS_BLUEZ\n#include \"input/api/Wiimote/l2cap/L2CapWiimote.h\"\n#endif\n\n#include <numbers>\n#include <queue>\n\nWiimoteControllerProvider::WiimoteControllerProvider()\n\t: m_running(true)\n{\n\tm_reader_thread = std::thread(&WiimoteControllerProvider::reader_thread, this);\n\tm_writer_thread = std::thread(&WiimoteControllerProvider::writer_thread, this);\n\tm_connectionThread = std::thread(&WiimoteControllerProvider::connectionThread, this);\n}\n\nWiimoteControllerProvider::~WiimoteControllerProvider()\n{\n\tif (m_running)\n\t{\n\t\tm_running = false;\n\t\tm_writer_thread.join();\n\t\tm_reader_thread.join();\n\t\tm_connectionThread.join();\n\t}\n}\n\nstd::vector<std::shared_ptr<ControllerBase>> WiimoteControllerProvider::get_controllers()\n{\n\tm_connectedDeviceMutex.lock();\n\tauto devices = m_connectedDevices;\n\tm_connectedDeviceMutex.unlock();\n\n\tstd::scoped_lock lock(m_device_mutex);\n\n\tfor (auto& device : devices)\n\t{\n\t\tconst auto writeable = device->write_data({kStatusRequest, 0x00});\n        if (!writeable)\n            continue;\n\n\t\tbool isDuplicate = false;\n\t\tssize_t lowestReplaceableIndex = -1;\n\t\tfor (ssize_t i = m_wiimotes.size() - 1; i >= 0; --i)\n\t\t{\n\t\t\tconst auto& wiimoteDevice = m_wiimotes[i].device;\n\t\t\tif (wiimoteDevice)\n\t\t\t{\n\t\t\t\tif (*wiimoteDevice == *device)\n\t\t\t\t{\n\t\t\t\t\tisDuplicate = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlowestReplaceableIndex = i;\n\t\t}\n\t\tif (isDuplicate)\n\t\t\tcontinue;\n\t\tif (lowestReplaceableIndex != -1)\n\t\t\tm_wiimotes.replace(lowestReplaceableIndex, std::make_unique<Wiimote>(device));\n\t\telse\n\t\t\tm_wiimotes.push_back(std::make_unique<Wiimote>(device));\n\t}\n\n\tstd::vector<std::shared_ptr<ControllerBase>> result;\n\tresult.reserve(m_wiimotes.size());\n\tfor (size_t i = 0; i < m_wiimotes.size(); ++i)\n\t{\n\t\tresult.emplace_back(std::make_shared<NativeWiimoteController>(i));\n\t}\n\n\treturn result;\n}\n\nbool WiimoteControllerProvider::is_connected(size_t index)\n{\n\tstd::shared_lock lock(m_device_mutex);\n\treturn index < m_wiimotes.size() && m_wiimotes[index].device;\n}\n\nbool WiimoteControllerProvider::is_registered_device(size_t index)\n{\n\tstd::shared_lock lock(m_device_mutex);\n\treturn index < m_wiimotes.size();\n}\n\nvoid WiimoteControllerProvider::set_rumble(size_t index, bool state)\n{\n\tstd::shared_lock lock(m_device_mutex);\n\tif (index >= m_wiimotes.size())\n\t\treturn;\n\t\n\tm_wiimotes[index].rumble = state;\n\tlock.unlock();\n\n\tsend_packet(index, { kStatusRequest, 0x00 });\n}\n\nvoid WiimoteControllerProvider::request_status(size_t index)\n{\n\tsend_packet(index, {kStatusRequest, 0x00});\n}\n\nvoid WiimoteControllerProvider::set_led(size_t index, size_t player_index)\n{\n\tuint8 mask = 0;\n\tmask |= 1 << (4 + (player_index % 4));\n\tif (player_index >= 4)\n\t\tmask |= 1 << (4 + ((player_index - 3) % 4));\n\tsend_packet(index, {kLED, mask});\n}\n\nuint32 WiimoteControllerProvider::get_packet_delay(size_t index)\n{\n\tstd::shared_lock lock(m_device_mutex);\n\tif (index < m_wiimotes.size())\n\t{\n\t\treturn m_wiimotes[index].data_delay;\n\t}\n\n\treturn kDefaultPacketDelay;\n}\n\nvoid WiimoteControllerProvider::set_packet_delay(size_t index, uint32 delay)\n{\n\tstd::shared_lock lock(m_device_mutex);\n\tif (index < m_wiimotes.size())\n\t{\n\t\tm_wiimotes[index].data_delay = delay;\n\t}\n}\n\nWiimoteControllerProvider::WiimoteState WiimoteControllerProvider::get_state(size_t index)\n{\n\tstd::shared_lock lock(m_device_mutex);\n\tif (index < m_wiimotes.size())\n\t{\n\t\tstd::shared_lock data_lock(m_wiimotes[index].mutex);\n\t\treturn m_wiimotes[index].state;\n\t}\n\n\treturn {};\n}\n\nvoid WiimoteControllerProvider::connectionThread()\n{\n\tSetThreadName(\"Wiimote-connect\");\n\twhile (m_running.load(std::memory_order_relaxed))\n\t{\n\t\tstd::vector<WiimoteDevicePtr> devices;\n#ifdef HAS_HIDAPI\n\t\tconst auto& hidDevices = HidapiWiimote::get_devices();\n\t\tstd::ranges::move(hidDevices, std::back_inserter(devices));\n#endif\n#ifdef HAS_BLUEZ\n\t\tconst auto& l2capDevices = L2CapWiimote::get_devices();\n\t\tstd::ranges::move(l2capDevices, std::back_inserter(devices));\n#endif\n\t\t{\n\t\t\tstd::scoped_lock lock(m_connectedDeviceMutex);\n\t\t\tm_connectedDevices.clear();\n\t\t\tstd::ranges::move(devices, std::back_inserter(m_connectedDevices));\n\t\t}\n\t\tstd::this_thread::sleep_for(std::chrono::seconds(2));\n\t}\n}\n\n\nvoid WiimoteControllerProvider::reader_thread()\n{\n\tSetThreadName(\"Wiimote-reader\");\n\tstd::chrono::steady_clock::time_point lastCheck = {};\n\twhile (m_running.load(std::memory_order_relaxed))\n\t{\n\t\tconst auto now = std::chrono::steady_clock::now();\n\t\tif (std::chrono::duration_cast<std::chrono::seconds>(now - lastCheck) > std::chrono::milliseconds(500))\n\t\t{\n\t\t\t// check for new connected wiimotes\n\t\t\tget_controllers();\n\t\t\tlastCheck = std::chrono::steady_clock::now();\n\t\t}\n\n\t\tbool receivedAnyPacket = false;\n\t\tstd::shared_lock lock(m_device_mutex);\n\t\tfor (size_t index = 0; index < m_wiimotes.size(); ++index)\n\t\t{\n\t\t\tauto& wiimote = m_wiimotes[index];\n\t\t\tif (!wiimote.device)\n\t\t\t\tcontinue;\n\n\t\t\tconst auto read_data = wiimote.device->read_data();\n\t\t\tif (!read_data)\n\t\t\t{\n\t\t\t\twiimote.device.reset();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (read_data->empty())\n\t\t\t\tcontinue;\n\t\t\treceivedAnyPacket = true;\n\n\t\t\tstd::shared_lock read_lock(wiimote.mutex);\n\t\t\tWiimoteState new_state = wiimote.state;\n\t\t\tread_lock.unlock();\n\n\t\t\tbool update_report = false;\n\n\t\t\tconst uint8* data = read_data->data();\n\t\t\tconst auto id = (InputReportId)*data;\n\t\t\t++data;\n\t\t\tswitch (id)\n\t\t\t{\n\t\t\tcase kStatus:\n\t\t\t\t{\n                    cemuLog_logDebug(LogType::Force,\"WiimoteControllerProvider::read_thread: kStatus\");\n\t\t\t\t\tnew_state.buttons = (*(uint16*)data) & (~0x60E0);\n\t\t\t\t\tdata += 2;\n\t\t\t\t\tnew_state.flags = *data;\n\t\t\t\t\t++data;\n\t\t\t\t\tdata += 2; // skip zeroes\n\t\t\t\t\tnew_state.battery_level = *data;\n\t\t\t\t\t++data;\n\n\t\t\t\t\tnew_state.ir_camera.mode = set_ir_camera(index, true);\n\t\t\t\t\tif(!new_state.m_calibrated)\n\t\t\t\t\t\tcalibrate(index);\n\n\t\t\t\t\tif(!new_state.m_motion_plus)\n\t\t\t\t\t\tdetect_motion_plus(index);\n\n\t\t\t\t\tif (HAS_FLAG(new_state.flags, kExtensionConnected))\n\t\t\t\t\t{\n                        cemuLog_logDebug(LogType::Force,\"Extension flag is set\");\n\t\t\t\t\t\tif(new_state.m_extension.index() == 0)\n\t\t\t\t\t\t\trequest_extension(index);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnew_state.m_extension = {};\n\t\t\t\t\t}\n\n\t\t\t\t\tupdate_report = true;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase kRead:\n\t\t\t\t{\n                    cemuLog_logDebug(LogType::Force,\"WiimoteControllerProvider::read_thread: kRead\");\n\t\t\t\t\tnew_state.buttons = (*(uint16*)data) & (~0x60E0);\n\t\t\t\t\tdata += 2;\n\t\t\t\t\tconst uint8 error_flag = *data & 0xF, size = (*data >> 4) + 1;\n\t\t\t\t\t++data;\n\n\t\t\t\t\tif (error_flag)\n\t\t\t\t\t{\n\n\t\t\t\t\t\t// 7 means that wiimote is already enabled or not available\n                        cemuLog_logDebug(LogType::Force,\"Received error on data read {:#x}\", error_flag);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tauto address = *(betype<uint16>*)data;\n\t\t\t\t\tdata += 2;\n\t\t\t\t\tif (address == (kRegisterCalibration & 0xFFFF))\n\t\t\t\t\t{\n                        cemuLog_logDebug(LogType::Force,\"Calibration received\");\n\n\t\t\t\t\t\tcemu_assert(size == 8);\n\n\t\t\t\t\t\tnew_state.m_calib_acceleration.zero.x = (uint16)*data << 2;\n\t\t\t\t\t\t++data;\n\t\t\t\t\t\tnew_state.m_calib_acceleration.zero.y = (uint16)*data << 2;\n\t\t\t\t\t\t++data;\n\t\t\t\t\t\tnew_state.m_calib_acceleration.zero.z = (uint16)*data << 2;\n\t\t\t\t\t\t++data;\n\t\t\t\t\t\t// --XXYYZZ\n\t\t\t\t\t\tnew_state.m_calib_acceleration.zero.x |= (*data >> 4) & 0x3; // 5|4 -> 1|0\n\t\t\t\t\t\tnew_state.m_calib_acceleration.zero.y |= (*data >> 2) & 0x3; // 3|4 -> 1|0\n\t\t\t\t\t\tnew_state.m_calib_acceleration.zero.z |= *data & 0x3;\n\t\t\t\t\t\t++data;\n\n\t\t\t\t\t\tnew_state.m_calib_acceleration.gravity.x = (uint16)*data << 2;\n\t\t\t\t\t\t++data;\n\t\t\t\t\t\tnew_state.m_calib_acceleration.gravity.y = (uint16)*data << 2;\n\t\t\t\t\t\t++data;\n\t\t\t\t\t\tnew_state.m_calib_acceleration.gravity.z = (uint16)*data << 2;\n\t\t\t\t\t\t++data;\n\t\t\t\t\t\tnew_state.m_calib_acceleration.gravity.x |= (*data >> 4) & 0x3; // 5|4 -> 1|0\n\t\t\t\t\t\tnew_state.m_calib_acceleration.gravity.y |= (*data >> 2) & 0x3; // 3|4 -> 1|0\n\t\t\t\t\t\tnew_state.m_calib_acceleration.gravity.z |= *data & 0x3;\n\t\t\t\t\t\t++data;\n\n\t\t\t\t\t\tnew_state.m_calibrated = true;\n\t\t\t\t\t}\n\t\t\t\t\telse if (address == (kRegisterExtensionType & 0xFFFF))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (size == 0xf)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcemuLog_logDebug(LogType::Force,\"Extension type received but no extension connected\");\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcemu_assert(size == 6);\n\t\t\t\t\t\tauto be_type = *(betype<uint64>*)data;\n\t\t\t\t\t\tdata += 6; // 48\n\t\t\t\t\t\tbe_type >>= 16;\n\t\t\t\t\t\tbe_type &= 0xFFFFFFFFFFFF;\n\t\t\t\t\t\tswitch (be_type.value())\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase kExtensionNunchuck:\n                            cemuLog_logDebug(LogType::Force,\"Extension Type Received: Nunchuck\");\n\t\t\t\t\t\t\tnew_state.m_extension = NunchuckData{};\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase kExtensionClassic:\n                            cemuLog_logDebug(LogType::Force,\"Extension Type Received: Classic\");\n\t\t\t\t\t\t\tnew_state.m_extension = ClassicData{};\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase kExtensionClassicPro:\n                            cemuLog_logDebug(LogType::Force,\"Extension Type Received: Classic Pro\");\n\t\t\t\t\t\t\tnew_state.m_extension = ClassicData{};\n                            break;\n\t\t\t\t\t\tcase kExtensionGuitar:\n                            cemuLog_logDebug(LogType::Force,\"Extension Type Received: Guitar\");\n                            break;\n\t\t\t\t\t\tcase kExtensionDrums:\n                            cemuLog_logDebug(LogType::Force,\"Extension Type Received: Drums\");\n                            break;\n\t\t\t\t\t\tcase kExtensionBalanceBoard:\n                            cemuLog_logDebug(LogType::Force,\"Extension Type Received: Balance Board\");\n                            break;\n\t\t\t\t\t\tcase kExtensionMotionPlus:\n                            cemuLog_logDebug(LogType::Force,\"Extension Type Received: MotionPlus\");\n\t\t\t\t\t\t\tset_motion_plus(index, true);\n\t\t\t\t\t\t\tnew_state.m_motion_plus = MotionPlusData{};\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase kExtensionPartialyInserted:\n                            cemuLog_logDebug(LogType::Force,\"Extension only partially inserted\");\n\t\t\t\t\t\t\tnew_state.m_extension = {};\n\t\t\t\t\t\t\trequest_status(index);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase kExtensionMotionPlusInactive:\n                            cemuLog_logDebug(LogType::Force,\"Extension Type Received: Inactive MotionPlus\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n                            cemuLog_logDebug(LogType::Force,\"Unknown extension: {:#x}\", be_type.value());\n                            new_state.m_extension = {};\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (new_state.m_extension.index() != 0)\n\t\t\t\t\t\t\tsend_read_packet(index, kRegisterMemory, kRegisterExtensionCalibration, 0x10);\n\t\t\t\t\t}\n\t\t\t\t\telse if (address == (kRegisterExtensionCalibration & 0xFFFF))\n\t\t\t\t\t{\n\t\t\t\t\t\tcemu_assert(size == 0x10);\n                        cemuLog_logDebug(LogType::Force,\"Extension calibration received\");\n\t\t\t\t\t\tstd::visit(\n\t\t\t\t\t\t\toverloaded\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t[](auto)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t[data](MotionPlusData& mp)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// TODO fix\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t[data](NunchuckData& nunchuck)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tstd::array<uint8, 14> zero{};\n\t\t\t\t\t\t\t\t\tif (memcmp(zero.data(), data, zero.size()) == 0)\n\t\t\t\t\t\t\t\t\t{\n                                        cemuLog_logDebug(LogType::Force,\"Extension calibration data is zero\");\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.zero.x = (uint16)data[0] << 2;\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.zero.y = (uint16)data[1] << 2;\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.zero.z = (uint16)data[2] << 2;\n\t\t\t\t\t\t\t\t\t// --XXYYZZ\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.zero.x |= (data[3] >> 4) & 0x3; // 5|4 -> 1|0\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.zero.y |= (data[3] >> 2) & 0x3; // 3|4 -> 1|0\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.zero.z |= data[3] & 0x3;\n\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.gravity.x = (uint16)data[4] << 2;;\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.gravity.y = (uint16)data[5] << 2;;\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.gravity.z = (uint16)data[6] << 2;;\n\t\t\t\t\t\t\t\t\t// --XXYYZZ\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.gravity.x |= (data[7] >> 4) & 0x3; // 5|4 -> 1|0\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.gravity.y |= (data[7] >> 2) & 0x3; // 3|4 -> 1|0\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.gravity.z |= data[7] & 0x3;\n\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.max.x = data[8];\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.max.y = data[11];\n\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.min.x = data[9];\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.min.y = data[12];\n\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.center.x = data[10];\n\t\t\t\t\t\t\t\t\tnunchuck.calibration.center.y = data[13];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}, new_state.m_extension);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n                        cemuLog_logDebug(LogType::Force,\"Unhandled read data received\");\n                        continue;\n\t\t\t\t\t}\n\n\t\t\t\t\tupdate_report = true;\n\t\t\t\t}\n\t\t\t\tbreak;\n            case kAcknowledge:\n                {\n                    new_state.buttons = *(uint16*)data & (~0x60E0);\n                    data += 2;\n                    const auto report_id = *data++;\n                    const auto error = *data++;\n                    if (error)\n                        cemuLog_logDebug(LogType::Force, \"Error {:#x} from output report {:#x}\", error, report_id);\n                    break;\n                }\n\t\t\tcase kDataCore:\n\t\t\t\t{\n\t\t\t\t\t// 30 BB BB\n\t\t\t\t\tnew_state.buttons = *(uint16*)data & (~0x60E0);\n\t\t\t\t\tdata += 2;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase kDataCoreAcc:\n\t\t\t\t{\n\t\t\t\t\t// 31 BB BB AA AA AA\n\t\t\t\t\tnew_state.buttons = *(uint16*)data & (~0x60E0);\n\t\t\t\t\tparse_acceleration(new_state, data);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase kDataCoreExt8:\n\t\t\t\t{\n\t\t\t\t\t// 32 BB BB EE EE EE EE EE EE EE EE\n\t\t\t\t\tnew_state.buttons = *(uint16*)data & (~0x60E0);\n\t\t\t\t\tdata += 2;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase kDataCoreAccIR:\n\t\t\t\t{\n\t\t\t\t\t// 33 BB BB AA AA AA II II II II II II II II II II II II \n\t\t\t\t\tnew_state.buttons = *(uint16*)data & (~0x60E0);\n\t\t\t\t\tparse_acceleration(new_state, data);\n\t\t\t\t\tdata += parse_ir(new_state, data);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase kDataCoreExt19:\n\t\t\t\t{\n\t\t\t\t\t// 34 BB BB EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE \n\t\t\t\t\tnew_state.buttons = *(uint16*)data & (~0x60E0);\n\t\t\t\t\tdata += 2;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase kDataCoreAccExt:\n\t\t\t\t{\n\t\t\t\t\t// 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE\n\t\t\t\t\tnew_state.buttons = *(uint16*)data & (~0x60E0);\n\t\t\t\t\tparse_acceleration(new_state, data);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase kDataCoreIRExt:\n\t\t\t\t{\n\t\t\t\t\t// 36 BB BB II II II II II II II II II II EE EE EE EE EE EE EE EE EE\n\t\t\t\t\tnew_state.buttons = *(uint16*)data & (~0x60E0);\n\t\t\t\t\tdata += 2;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase kDataCoreAccIRExt:\n\t\t\t\t{\n\t\t\t\t\t// 37 BB BB AA AA AA II II II II II II II II II II EE EE EE EE EE EE\n\t\t\t\t\tnew_state.buttons = *(uint16*)data & (~0x60E0);\n\t\t\t\t\tparse_acceleration(new_state, data);\n\t\t\t\t\tdata += parse_ir(new_state, data); // 10\n\n\t\t\t\t\tstd::visit(\n\t\t\t\t\t\toverloaded\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t[](auto)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t[data](MotionPlusData& mp) mutable\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tglm::vec<3, uint16> raw;\n\t\t\t\t\t\t\t\traw.x = *data;\n\t\t\t\t\t\t\t\t++data;\n\t\t\t\t\t\t\t\traw.y = *data;\n\t\t\t\t\t\t\t\t++data;\n\t\t\t\t\t\t\t\traw.z = *data;\n\t\t\t\t\t\t\t\t++data;\n\n\t\t\t\t\t\t\t\traw.x |= (uint16)*data << 6; // 7|2 -> 13|8\n\t\t\t\t\t\t\t\tmp.slow_yaw = *data & 2;\n\t\t\t\t\t\t\t\tmp.slow_pitch = *data & 1;\n\t\t\t\t\t\t\t\t++data;\n\n\t\t\t\t\t\t\t\traw.y |= (uint16)*data << 6; // 7|2 -> 13|8\n\t\t\t\t\t\t\t\tmp.slow_roll = *data & 2;\n\t\t\t\t\t\t\t\tmp.extension_connected = *data & 1;\n\t\t\t\t\t\t\t\t++data;\n\n\t\t\t\t\t\t\t\traw.z |= (uint16)*data << 6; // 7|2 -> 13|8\n\n\t\t\t\t\t\t\t\tauto& calib = mp.calibration;\n\n\t\t\t\t\t\t\t\tglm::vec3 orientation = raw;\n\t\t\t\t\t\t\t\t/*orientation -= calib.zero;\n\t\n\t\t\t\t\t\t\t\tVector3<float> tmp = calib.gravity;\n\t\t\t\t\t\t\t\ttmp -= calib.zero;\n\t\t\t\t\t\t\t\torientation /= tmp;*/\n\n\t\t\t\t\t\t\t\tmp.orientation = orientation;\n                                cemuLog_logDebug(LogType::Force,\"MotionPlus: {:.2f}, {:.2f} {:.2f}\", mp.orientation.x, mp.orientation.y, mp.orientation.z);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t[data](NunchuckData& nunchuck) mutable\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnunchuck.raw_axis.x = *data;\n\t\t\t\t\t\t\t\t++data;\n\t\t\t\t\t\t\t\tnunchuck.raw_axis.y = *data;\n\t\t\t\t\t\t\t\t++data;\n\n\t\t\t\t\t\t\t\tglm::vec<3, uint16> raw_acc;\n\t\t\t\t\t\t\t\traw_acc.x = (uint16)*data << 2;\n\t\t\t\t\t\t\t\t++data;\n\t\t\t\t\t\t\t\traw_acc.y = (uint16)*data << 2;\n\t\t\t\t\t\t\t\t++data;\n\t\t\t\t\t\t\t\traw_acc.z = (uint16)*data << 2;\n\t\t\t\t\t\t\t\t++data;\n\t\t\t\t\t\t\t\tnunchuck.z = (*data & 1) == 0;\n\t\t\t\t\t\t\t\tnunchuck.c = (*data & 2) == 0;\n\n\t\t\t\t\t\t\t\traw_acc.x |= (*data >> 2) & 0x3; // 3|2 -> 1|0\n\t\t\t\t\t\t\t\traw_acc.y |= (*data >> 4) & 0x3; // 5|4 -> 1|0\n\t\t\t\t\t\t\t\traw_acc.z |= (*data >> 6) & 0x3; // 7|6 -> 1|0\n\n\t\t\t\t\t\t\t\tauto& calib = nunchuck.calibration;\n\n\t\t\t\t\t\t\t\tif (nunchuck.raw_axis.x < nunchuck.calibration.center.x) // [-1, 0]\n\t\t\t\t\t\t\t\t\tnunchuck.axis.x = ((float)nunchuck.raw_axis.x - calib.min.x) / ((float)nunchuck.\n\t\t\t\t\t\t\t\t\t\tcalibration.center.x - calib.min.x + 0.012f) - 1.0f;\n\t\t\t\t\t\t\t\telse // [0, 1]\n\t\t\t\t\t\t\t\t\tnunchuck.axis.x = (float)(nunchuck.raw_axis.x - nunchuck.calibration.center.x) / (\n\t\t\t\t\t\t\t\t\t\tnunchuck.calibration.max.x - nunchuck.calibration.center.x + 0.012f);\n\n\t\t\t\t\t\t\t\tif (nunchuck.raw_axis.y <= nunchuck.calibration.center.y) // [-1, 0]\n\t\t\t\t\t\t\t\t\tnunchuck.axis.y = ((float)nunchuck.raw_axis.y - calib.min.y) / ((float)nunchuck.\n\t\t\t\t\t\t\t\t\t\tcalibration.center.y - calib.min.y + 0.012f) - 1.0f;\n\t\t\t\t\t\t\t\telse // [0, 1]\n\t\t\t\t\t\t\t\t\tnunchuck.axis.y = (float)(nunchuck.raw_axis.y - nunchuck.calibration.center.y) / (\n\t\t\t\t\t\t\t\t\t\tnunchuck.calibration.max.y - nunchuck.calibration.center.y);\n\n\t\t\t\t\t\t\t\tglm::vec3 acceleration = raw_acc;\n\t\t\t\t\t\t\t\tnunchuck.prev_acceleration = nunchuck.acceleration;\n\t\t\t\t\t\t\t\tnunchuck.acceleration = acceleration - glm::vec3(calib.zero);\n\n\t\t\t\t\t\t\t\tfloat acc[3]{ -nunchuck.acceleration.x, -nunchuck.acceleration.z, nunchuck.acceleration.y };\n\t\t\t\t\t\t\t\tconst auto grav = nunchuck.calibration.gravity - nunchuck.calibration.zero;\n\n\t\t\t\t\t\t\t\tauto tacc = nunchuck.acceleration;\n\t\t\t\t\t\t\t\tauto pacc = nunchuck.prev_acceleration;\n\t\t\t\t\t\t\t\tif (grav != glm::vec<3, uint16>{})\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tacc[0] /= (float)grav.x;\n\t\t\t\t\t\t\t\t\tacc[1] /= (float)grav.y;\n\t\t\t\t\t\t\t\t\tacc[2] /= (float)grav.z;\n\n\t\t\t\t\t\t\t\t\ttacc.x /= (float)grav.x;\n\t\t\t\t\t\t\t\t\tpacc.x /= (float)grav.x;\n\n\t\t\t\t\t\t\t\t\ttacc.y /= (float)grav.y;\n\t\t\t\t\t\t\t\t\tpacc.y /= (float)grav.y;\n\n\t\t\t\t\t\t\t\t\ttacc.z /= (float)grav.z;\n\t\t\t\t\t\t\t\t\tpacc.z /= (float)grav.z;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfloat zero3[3]{};\n\t\t\t\t\t\t\t\tfloat zero4[4]{};\n\n\n\t\t\t\t\t\t\t\tnunchuck.motion_sample = MotionSample(\n\t\t\t\t\t\t\t\t\tacc,\n\t\t\t\t\t\t\t\t\tglm::length(tacc - pacc),\n\t\t\t\t\t\t\t\t\tzero3,\n\t\t\t\t\t\t\t\t\tzero3,\n\t\t\t\t\t\t\t\t\tzero4\n\t\t\t\t\t\t\t\t);\n                                cemuLog_logDebug(LogType::Force,\"Nunchuck: Z={}, C={} | {}, {} | {:.2f}, {:.2f}, {:.2f}\",\n                                                 nunchuck.z, nunchuck.c,\n                                                 nunchuck.axis.x, nunchuck.axis.y,\n                                                 RadToDeg(nunchuck.acceleration.x), RadToDeg(nunchuck.acceleration.y),\n                                                 RadToDeg(nunchuck.acceleration.z));\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t[data](ClassicData& classic) mutable\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tclassic.left_raw_axis.x = *data & 0x3F;\n\t\t\t\t\t\t\t\tclassic.right_raw_axis.x = (*data & 0xC0) >> 3; // 7|6 -> 4|3\n\t\t\t\t\t\t\t\t++data;\n\n\t\t\t\t\t\t\t\tclassic.left_raw_axis.y = *data & 0x3F;\n\t\t\t\t\t\t\t\tclassic.right_raw_axis.x |= (*data & 0xC0) >> 5; // 7|6 -> 2|1\n\t\t\t\t\t\t\t\t++data;\n\n\t\t\t\t\t\t\t\tclassic.right_raw_axis.y = *data & 0x1F;\n\t\t\t\t\t\t\t\tclassic.raw_trigger.x = (*data & 0x60) >> 2; // 6|5 -> 4|3\n\t\t\t\t\t\t\t\tclassic.right_raw_axis.x |= (*data & 0x80) >> 7; // 7 -> 0\n\t\t\t\t\t\t\t\t++data;\n\n\t\t\t\t\t\t\t\tclassic.raw_trigger.x |= (*data & 0xE0) >> 5; // 7|5 -> 2|0\n\t\t\t\t\t\t\t\tclassic.raw_trigger.y = (*data & 0x1F);\n\t\t\t\t\t\t\t\t++data;\n\n\t\t\t\t\t\t\t\tclassic.buttons = ~(*(uint16*)data);\n\t\t\t\t\t\t\t\tdata += 2;\n\n\t\t\t\t\t\t\t\tclassic.left_axis = classic.left_raw_axis;\n\t\t\t\t\t\t\t\tclassic.left_axis /= 63.0f;\n\t\t\t\t\t\t\t\tclassic.left_axis = classic.left_axis * 2.0f - 1.0f;\n\n\t\t\t\t\t\t\t\tclassic.right_axis = classic.right_raw_axis;\n\t\t\t\t\t\t\t\tclassic.right_axis /= 31.0f;\n\t\t\t\t\t\t\t\tclassic.right_axis = classic.right_axis * 2.0f - 1.0f;\n\n\t\t\t\t\t\t\t\tclassic.trigger = classic.raw_trigger;\n\t\t\t\t\t\t\t\tclassic.trigger /= 31.0f;\n                                cemuLog_logDebug(LogType::Force,\"Classic Controller: Buttons={:b} | {}, {} | {}, {} | {}, {}\",\n                                                 classic.buttons, classic.left_axis.x, classic.left_axis.y,\n                                                 classic.right_axis.x, classic.right_axis.y, classic.trigger.x,\n                                                 classic.trigger.y);\n\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, new_state.m_extension);\n\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tcase kDataExt:\n\t\t\t\t{\n\t\t\t\t\t// 3d EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tdefault:\n                cemuLog_logDebug(LogType::Force,\"unhandled input packet id {} for wiimote {}\", id, index);\n\t\t\t}\n\n\t\t\t// update motion data\n\t\t\t//const auto motionnow = std::chrono::high_resolution_clock::now();\n\t\t\t//const auto delta_time = (float)std::chrono::duration_cast<std::chrono::milliseconds>(motionnow - new_state.m_last_motion_timestamp).count() / 1000.0f;\n\t\t\t//new_state.m_last_motion_timestamp = motionnow;\n\n\t\t\tfloat acc[3]{-new_state.m_acceleration.x, -new_state.m_acceleration.z, new_state.m_acceleration.y};\n\t\t\tconst auto grav = new_state.m_calib_acceleration.gravity - new_state.m_calib_acceleration.zero;\n\n\t\t\tauto tacc = new_state.m_acceleration;\n\t\t\tauto pacc = new_state.m_prev_acceleration;\n\t\t\tif (grav != glm::vec<3, uint16>{})\n\t\t\t{\n\t\t\t\tacc[0] /= (float)grav.x;\n\t\t\t\tacc[1] /= (float)grav.y;\n\t\t\t\tacc[2] /= (float)grav.z;\n\n\t\t\t\ttacc.x /= (float)grav.x;\n\t\t\t\tpacc.x /= (float)grav.x;\n\n\t\t\t\ttacc.y /= (float)grav.y;\n\t\t\t\tpacc.y /= (float)grav.y;\n\n\t\t\t\ttacc.z /= (float)grav.z;\n\t\t\t\tpacc.z /= (float)grav.z;\n\t\t\t}\n\t\t\tfloat zero3[3]{};\n\t\t\tfloat zero4[4]{};\n\n\n\t\t\tnew_state.motion_sample = MotionSample(\n\t\t\t\tacc,\n\t\t\t\tglm::length(tacc - pacc),\n\t\t\t\tzero3,\n\t\t\t\tzero3,\n\t\t\t\tzero4\n\t\t\t);\n\n\t\t\tstd::unique_lock data_lock(wiimote.mutex);\n\t\t\twiimote.state = new_state;\n\t\t\tdata_lock.unlock();\n\n\t\t\tif (update_report)\n\t\t\t\tupdate_report_type(index);\n\t\t}\n\n\t\tlock.unlock();\n\t\tif (!receivedAnyPacket)\n\t\t{\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\t}\n\t}\n}\n\nvoid WiimoteControllerProvider::parse_acceleration(WiimoteState& wiimote_state, const uint8*& data)\n{\n\tglm::vec<3, uint16> raw_acc;\n\t// acc encoded in BB BB\n\traw_acc.x = (*data >> 5) & 3; // 6|5 -> 1|0\n\t++data;\n\traw_acc.y = (*data >> 4) & 2; // 5 -> 1\n\traw_acc.z = (*data >> 5) & 2; // 6 -> 1\n\t++data;\n\n\traw_acc.x |= (uint16)*data << 2;\n\t++data;\n\traw_acc.y |= (uint16)*data << 2;\n\t++data;\n\traw_acc.z |= (uint16)*data << 2;\n\t++data;\n\n\twiimote_state.m_prev_acceleration = wiimote_state.m_acceleration;\n\tglm::vec3 acceleration = raw_acc;\n\n\tconst auto& calib = wiimote_state.m_calib_acceleration;\n\twiimote_state.m_acceleration = acceleration - glm::vec3(calib.zero);\n\n\tglm::vec3 tmp = calib.gravity;\n\ttmp -= calib.zero;\n\tacceleration = (wiimote_state.m_acceleration / tmp);\n\n\tconst float pi_2 = (float)std::numbers::pi / 2.0f;\n\twiimote_state.m_roll = std::atan2(acceleration.z, acceleration.x) - pi_2;\n}\n\nvoid WiimoteControllerProvider::rotate_ir(WiimoteState& wiimote_state)\n{\n\tconst float rot = wiimote_state.m_roll;\n\tif (rot == 0.0f)\n\t\treturn;\n\n\tconst float sin = std::sin(rot);\n\tconst float cos = std::cos(rot);\n\tint i = -1;\n\tfor (auto& dot : wiimote_state.ir_camera.dots)\n\t{\n\t\ti++;\n\t\tif (!dot.visible)\n\t\t\tcontinue;\n\t\t// move to center, rotate and move back\n\t\tdot.pos -= 0.5f;\n\t\tdot.pos.x = (dot.pos.x * cos) + (dot.pos.y * (-sin));\n\t\tdot.pos.y = (dot.pos.x * sin) + (dot.pos.y * cos);\n\t\tdot.pos += 0.5f;\n\t}\n}\n\nvoid WiimoteControllerProvider::calculate_ir_position(WiimoteState& wiimote_state)\n{\n\tauto& ir = wiimote_state.ir_camera;\n\tir.m_prev_position = ir.position;\n\n\tstd::pair indices = ir.indices;\n\tif (ir.middle.x != 0)\n\t{\n\t\tconst float last_angle = std::atan(ir.middle.y / ir.middle.x);\n\t\tfloat best_distance = std::numeric_limits<float>::max();\n\t\tfor (size_t i = 0; i < ir.dots.size(); ++i)\n\t\t{\n\t\t\tif (!ir.dots[i].visible)\n\t\t\t\tcontinue;\n\n\t\t\tfor (size_t j = i + 1; j < ir.dots.size(); ++j)\n\t\t\t{\n\t\t\t\tif (!ir.dots[j].visible)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tconst auto mid = (ir.dots[i].pos + ir.dots[j].pos) / 2.0f;\n\t\t\t\tif (mid.x == 0)\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// check if angle is close enough to the last known one\n\t\t\t\tfloat angle = std::atan(mid.y / mid.x);\n\t\t\t\tif (std::abs(last_angle - angle) > DegToRad(10.0f))\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// check if distance between points is similar to last known distance\n\t\t\t\tconst float distance = std::abs(ir.distance - glm::length(ir.dots[i].pos - ir.dots[j].pos));\n\t\t\t\tif (distance > 0.1f && distance > best_distance)\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// found a new pair\n\t\t\t\tbest_distance = distance;\n\t\t\t\tindices = {(sint32)i, (sint32)j};\n\t\t\t}\n\t\t}\n\t}\n\n\tif (ir.dots[indices.first].visible && ir.dots[indices.second].visible)\n\t{\n\t\tir.prev_dots[indices.first] = ir.dots[indices.first];\n\t\tir.prev_dots[indices.second] = ir.dots[indices.second];\n\t\tir.position = (ir.dots[indices.first].pos + ir.dots[indices.second].pos) / 2.0f;\n\n\t\tir.middle = ir.position;\n\t\tir.distance = glm::length(ir.dots[indices.first].pos - ir.dots[indices.second].pos);\n\t\tir.indices = indices;\n\t\tir.m_positionVisibility = PositionVisibility::FULL;\n\t}\n\telse if (ir.dots[indices.first].visible)\n\t{\n\t\tir.position = ir.middle + (ir.dots[indices.first].pos - ir.prev_dots[indices.first].pos);\n\t\tir.m_positionVisibility = PositionVisibility::PARTIAL;\n\t}\n\telse if (ir.dots[indices.second].visible)\n\t{\n\t\tir.position = ir.middle + (ir.dots[indices.second].pos - ir.prev_dots[indices.second].pos);\n\t\tir.m_positionVisibility = PositionVisibility::PARTIAL;\n\t}\n\telse {\n\t\tir.m_positionVisibility = PositionVisibility::NONE;\n\t}\n}\n\n\nsint32 WiimoteControllerProvider::parse_ir(WiimoteState& wiimote_state, const uint8* data)\n{\n\tswitch (wiimote_state.ir_camera.mode)\n\t{\n\tcase kIRDisabled:\n\t\twiimote_state.ir_camera.dots = {};\n\t\treturn 0;\n\tcase kBasicIR:\n\t\t{\n\t\t\tconst auto ir = (BasicIR*)data;\n\t\t\tfor (int i = 0; i < 2; ++i)\n\t\t\t{\n\t\t\t\tauto& dot1 = wiimote_state.ir_camera.dots[i * 2];\n\t\t\t\tauto& dot2 = wiimote_state.ir_camera.dots[i * 2 + 1];\n\n\t\t\t\tdot1.raw.x = ir[i].x1 | (ir[i].bits.x1 << 8); // 9|8\n\t\t\t\tdot1.raw.y = ir[i].y1 | (ir[i].bits.y1 << 8);\n\t\t\t\tdot1.size = 0;\n\n\t\t\t\tdot2.raw.x = ir[i].x2 | (ir[i].bits.x2 << 8);\n\t\t\t\tdot2.raw.y = ir[i].y2 | (ir[i].bits.y2 << 8);\n\t\t\t\tdot2.size = 0;\n\n\t\t\t\tdot1.visible = dot1.raw != glm::vec<2, uint16>(0x3ff, 0x3ff);\n\t\t\t\tif (dot1.visible)\n\t\t\t\t\tdot1.pos = glm::vec2(1.0f - dot1.raw.x / 1023.0f, (float)dot1.raw.y / 768.0f);\n\t\t\t\telse\n\t\t\t\t\tdot1.pos = {};\n\n\t\t\t\tdot2.visible = dot2.raw != glm::vec<2, uint16>(0x3ff, 0x3ff);\n\t\t\t\tif (dot2.visible)\n\t\t\t\t\tdot2.pos = glm::vec2(1.0f - dot2.raw.x / 1023.0f, (float)dot2.raw.y / 768.0f);\n\t\t\t\telse\n\t\t\t\t\tdot2.pos = {};\n\t\t\t}\n\n\t\t\trotate_ir(wiimote_state);\n\t\t\tcalculate_ir_position(wiimote_state);\n\t\t\treturn sizeof(BasicIR) * 2;\n\t\t}\n\tcase kExtendedIR:\n\t\t{\n\t\t\tconst auto ir = (ExtendedIR*)data;\n\t\t\tfor (int i = 0; i < 4; ++i)\n\t\t\t{\n\t\t\t\tauto& dot = wiimote_state.ir_camera.dots[i];\n\t\t\t\tdot.raw.x = ir[i].x;\n\t\t\t\tdot.raw.y = ir[i].y;\n\n\t\t\t\tdot.raw.x |= (uint16)ir[i].bits.x << 8; // 9|8\n\t\t\t\tdot.raw.y |= (uint16)ir[i].bits.y << 8; // 9|8\n\n\t\t\t\tdot.size = ir[i].bits.size;\n\n\t\t\t\tdot.visible = dot.raw != glm::vec<2, uint16>(0x3ff, 0x3ff);\n\t\t\t\tif (dot.visible)\n\t\t\t\t\tdot.pos = glm::vec2(1.0f - dot.raw.x / 1023.0f, (float)dot.raw.y / 768.0f);\n\t\t\t\telse\n\t\t\t\t\tdot.pos = {};\n\t\t\t}\n\n\t\t\trotate_ir(wiimote_state);\n\t\t\tcalculate_ir_position(wiimote_state);\n\t\t\treturn sizeof(ExtendedIR) * 4;\n\t\t}\n\tdefault:\n\t\tcemu_assert(false);\n\t\tbreak;\n\t}\n\treturn 0;\n}\n\nvoid WiimoteControllerProvider::request_extension(size_t index)\n{\n\t// send_write_packet(index, kRegisterMemory, kRegisterExtensionEncrypted, { 0x00 });\n\tsend_write_packet(index, kRegisterMemory, kRegisterExtension1, {0x55});\n\tsend_write_packet(index, kRegisterMemory, kRegisterExtension2, {0x00});\n\tsend_read_packet(index, kRegisterMemory, kRegisterExtensionType, 6);\n}\n\nvoid WiimoteControllerProvider::detect_motion_plus(size_t index)\n{\n\tsend_read_packet(index, kRegisterMemory, kRegisterMotionPlusDetect, 6);\n}\n\nvoid WiimoteControllerProvider::set_motion_plus(size_t index, bool state)\n{\n\tif (state) {\n\t\tsend_write_packet(index, kRegisterMemory, kRegisterMotionPlusInit, { 0x55 });\n\t\tsend_write_packet(index, kRegisterMemory, kRegisterMotionPlusEnable, { 0x04 });\n\t}\n\telse\n\t{\n\t\tsend_write_packet(index, kRegisterMemory, kRegisterExtension1, { 0x55 });\n\t}\n}\n\n\nvoid WiimoteControllerProvider::writer_thread()\n{\n\tSetThreadName(\"Wiimote-writer\");\n\twhile (m_running.load(std::memory_order_relaxed))\n\t{\n\t\tstd::unique_lock writer_lock(m_writer_mutex);\n\t\twhile (m_write_queue.empty())\n\t\t{\n\t\t\tif (m_writer_cond.wait_for(writer_lock, std::chrono::milliseconds(250)) == std::cv_status::timeout)\n\t\t\t{\n\t\t\t\tif (!m_running.load(std::memory_order_relaxed))\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tauto index = (size_t)-1;\n\t\tstd::vector<uint8> data;\n\t\tstd::shared_lock device_lock(m_device_mutex);\n\n\t\t// get first packet of device which is ready to be sent\n\t\tconst auto now = std::chrono::high_resolution_clock::now();\n\t\tfor (auto it = m_write_queue.begin(); it != m_write_queue.end(); ++it)\n\t\t{\n\t\t\tif (it->first >= m_wiimotes.size())\n\t\t\t\tcontinue;\n\n\t\t\tconst auto delay = m_wiimotes[it->first].data_delay.load(std::memory_order_relaxed);\n\t\t\tif (now >= m_wiimotes[it->first].data_ts + std::chrono::milliseconds(delay))\n\t\t\t{\n\t\t\t\tindex = it->first;\n\t\t\t\tdata = it->second;\n\t\t\t\tm_write_queue.erase(it);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\twriter_lock.unlock();\n\n\t\tif (index != (size_t)-1 && !data.empty())\n\t\t{\n\t\t\tauto& wiimote = m_wiimotes[index];\n\t\t\tif (!wiimote.device)\n\t\t\t\tcontinue;\n\t\t\tif (wiimote.rumble)\n\t\t\t\tdata[1] |= 1;\n\t\t\tif (!wiimote.device->write_data(data))\n\t\t\t{\n\t\t\t\twiimote.device.reset();\n\t\t\t\twiimote.rumble = false;\n\t\t\t}\n\t\t\telse\n\t\t\t\twiimote.data_ts = std::chrono::high_resolution_clock::now();\n\t\t}\n\t\tdevice_lock.unlock();\n\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\tstd::this_thread::yield();\n\t}\n}\n\nvoid WiimoteControllerProvider::calibrate(size_t index)\n{\n\tsend_read_packet(index, kEEPROMMemory, kRegisterCalibration, 8);\n}\n\nvoid WiimoteControllerProvider::update_report_type(size_t index)\n{\n\tstd::shared_lock read_lock(m_wiimotes[index].mutex);\n\tauto& state = m_wiimotes[index].state;\n\n\tconst bool extension = state.m_extension.index() != 0; // TODO || HasMotionPlus();\n\tconst bool ir = state.ir_camera.mode != kIRDisabled;\n\tconst bool motion = true; // UseMotion();\n\n\tInputReportId report_type;\n\tif (extension && ir && motion)\n\t\treport_type = kDataCoreAccIRExt;\n\telse if (extension && ir)\n\t\treport_type = kDataCoreIRExt;\n\telse if (extension && motion)\n\t\treport_type = kDataCoreAccExt;\n\telse if (ir && motion)\n\t\treport_type = kDataCoreAccIR;\n\telse if (extension)\n\t\treport_type = kDataCoreExt19;\n\telse if (ir)\n\t\treport_type = kDataCoreAccIR;\n\telse if (motion)\n\t\treport_type = kDataCoreAcc;\n\telse\n\t\treport_type = kDataCore;\n\n    cemuLog_logDebug(LogType::Force,\"Setting report type to {}\", report_type);\n\tsend_packet(index, {kType, 0x04, report_type});\n\n\tstate.ir_camera.mode = set_ir_camera(index, true);\n}\n\nIRMode WiimoteControllerProvider::set_ir_camera(size_t index, bool state)\n{\n\tstd::shared_lock read_lock(m_wiimotes[index].mutex);\n\tauto& wiimote_state = m_wiimotes[index].state;\n\n\tIRMode mode;\n\tif (!state)\n\t\tmode = kIRDisabled;\n\telse\n\t{\n\t\tmode = wiimote_state.m_extension.index() == 0 ? kExtendedIR : kBasicIR;\n\t}\n\n\tif (wiimote_state.ir_camera.mode == mode)\n\t\treturn mode;\n\n\twiimote_state.ir_camera.mode = mode;\n\n\tconst uint8_t data = state ? 0x04 : 0x00;\n\tsend_packet(index, {kIR, data});\n\tsend_packet(index, {kIR2, data});\n\tif (state)\n\t{\n\t\tsend_write_packet(index, kRegisterMemory, kRegisterIR, {0x08});\n\t\tsend_write_packet(index, kRegisterMemory, kRegisterIRSensitivity1,\n\t\t                  {0x02, 0x00, 0x00, 0x71, 0x01, 0x00, 0xaa, 0x00, 0x64});\n\t\tsend_write_packet(index, kRegisterMemory, kRegisterIRSensitivity2, {0x63, 0x03});\n\t\tsend_write_packet(index, kRegisterMemory, kRegisterIRMode, {(uint8)mode});\n\t\tsend_write_packet(index, kRegisterMemory, kRegisterIR, {0x08});\n\t}\n\n\tupdate_report_type(index);\n\treturn mode;\n}\n\nvoid WiimoteControllerProvider::send_packet(size_t index, std::vector<uint8> data)\n{\n\tcemu_assert(data.size() > 1);\n\n\tstd::shared_lock device_lock(m_device_mutex);\n\tif (index >= m_wiimotes.size())\n\t\treturn;\n\n\tdevice_lock.unlock();\n\n\tstd::unique_lock lock(m_writer_mutex);\n\tm_write_queue.emplace_back(index, data);\n\tm_writer_cond.notify_one();\n}\n\nvoid WiimoteControllerProvider::send_read_packet(size_t index, MemoryType type, RegisterAddress address, uint16 size)\n{\n\tstd::vector<uint8> data(7);\n\tdata[0] = kReadMemory;\n\tdata[1] = type;\n\t*(betype<uint32>*)(data.data() + 2) = (address & 0xFFFFFF) << 8; // only uint24\n\t*(betype<uint16>*)(data.data() + 2 + 3) = size;\n\n\tsend_packet(index, std::move(data));\n}\n\nvoid WiimoteControllerProvider::send_write_packet(size_t index, MemoryType type, RegisterAddress address,\n                                                  const std::vector<uint8>& data)\n{\n\tcemu_assert(data.size() <= 16);\n\tstd::vector<uint8> packet(6 + 16);\n\tpacket[0] = kWriteMemory;\n\tpacket[1] = type;\n\t*(betype<uint32>*)(packet.data() + 2) = (address & 0xFFFFFF) << 8; // only uint24\n\t*(packet.data() + 2 + 3) = (uint8)data.size();\n\tstd::copy(data.begin(), data.end(), packet.data() + 2 + 3 + 1);\n\tsend_packet(index, std::move(packet));\n}\n"
  },
  {
    "path": "src/input/api/Wiimote/WiimoteControllerProvider.h",
    "content": "#pragma once\n\n#include \"input/motion/MotionHandler.h\"\n#include \"input/api/Wiimote/WiimoteDevice.h\"\n#include \"input/api/Wiimote/WiimoteMessages.h\"\n\n#include \"input/api/ControllerProvider.h\"\n#include \"input/api/ControllerState.h\"\n\n#include <list>\n#include <variant>\n#include <boost/ptr_container/ptr_vector.hpp>\n\n#ifndef HAS_WIIMOTE\n#define HAS_WIIMOTE 1\n#endif\n\n#define WIIMOTE_DEBUG 1\n\nclass WiimoteControllerProvider : public ControllerProviderBase\n{\n\tfriend class WiimoteController;\npublic:\n\tconstexpr static uint32 kDefaultPacketDelay = 25;\n\n\tWiimoteControllerProvider();\n\t~WiimoteControllerProvider();\n\n\tinline static InputAPI::Type kAPIType = InputAPI::Wiimote;\n\tInputAPI::Type api() const override { return kAPIType; }\n\n\tstd::vector<std::shared_ptr<ControllerBase>> get_controllers() override;\n\n\tbool is_connected(size_t index);\n\tbool is_registered_device(size_t index);\n\tvoid set_rumble(size_t index, bool state);\n\tvoid request_status(size_t index);\n\tvoid set_led(size_t index, size_t player_index);\n\n\tuint32 get_packet_delay(size_t index);\n\tvoid set_packet_delay(size_t index, uint32 delay);\n\n\tstruct WiimoteState\n\t{\n\t\tuint16 buttons = 0;\n\t\tuint8 flags = 0;\n\t\tuint8 battery_level = 0;\n\n\t\tglm::vec3 m_acceleration{}, m_prev_acceleration{};\n\t\tfloat m_roll = 0;\n\n\t\tstd::chrono::high_resolution_clock::time_point m_last_motion_timestamp{};\n\t\tMotionSample motion_sample{};\n\t\tWiiUMotionHandler motion_handler{};\n\n\t\tbool m_calibrated = false;\n\t\tCalibration m_calib_acceleration{};\n\n\t\tstruct IRCamera\n\t\t{\n\t\t\tIRMode mode = kIRDisabled;\n\t\t\tstd::array<IRDot, 4> dots{}, prev_dots{};\n\n\t\t\tglm::vec2 position{}, m_prev_position{};\n\t\t\tPositionVisibility m_positionVisibility;\n\t\t\tglm::vec2 middle {};\n\t\t\tfloat distance = 0;\n\t\t\tstd::pair<sint32, sint32> indices{ 0,1 };\n\t\t}ir_camera{};\n\n\t\tstd::optional<MotionPlusData> m_motion_plus;\n\t\tstd::variant<std::monostate, NunchuckData, ClassicData> m_extension{};\n\t};\n\tWiimoteState get_state(size_t index);\n\t\n\nprivate:\n\tstd::atomic_bool m_running = false;\n\tstd::thread m_reader_thread, m_writer_thread;\n\tstd::shared_mutex m_device_mutex;\n\n\tstd::thread m_connectionThread;\n\tstd::vector<WiimoteDevicePtr> m_connectedDevices;\n\tstd::mutex m_connectedDeviceMutex;\n\tstruct Wiimote\n\t{\n\t\tWiimote(WiimoteDevicePtr device)\n\t\t\t: device(std::move(device)) {}\n\n\t\tWiimoteDevicePtr device;\n\t\tstd::atomic_bool rumble = false;\n\n\t\tstd::shared_mutex mutex;\n\t\tWiimoteState state{};\n\n\t\tstd::atomic_uint32_t data_delay = kDefaultPacketDelay;\n\t\tstd::chrono::high_resolution_clock::time_point data_ts{};\n\t};\n\tboost::ptr_vector<Wiimote> m_wiimotes;\n\n\tstd::list<std::pair<size_t,std::vector<uint8>>> m_write_queue;\n\tstd::mutex m_writer_mutex;\n\tstd::condition_variable m_writer_cond;\n\n\tvoid reader_thread();\n\tvoid writer_thread();\n\tvoid connectionThread();\n\n\tvoid calibrate(size_t index);\n\tIRMode set_ir_camera(size_t index, bool state);\n\n\tvoid send_packet(size_t index, std::vector<uint8> data);\n\tvoid send_read_packet(size_t index, MemoryType type, RegisterAddress address, uint16 size);\n\tvoid send_write_packet(size_t index, MemoryType type, RegisterAddress address, const std::vector<uint8>& data);\n\n\tvoid parse_acceleration(WiimoteState& wiimote_state, const uint8*& data);\n\n\tvoid rotate_ir(WiimoteState& wiimote_state);\n\tvoid calculate_ir_position(WiimoteState& wiimote_state);\n\tint parse_ir(WiimoteState& wiimote_state, const uint8* data);\n\n\tvoid request_extension(size_t index);\n\tvoid detect_motion_plus(size_t index);\n\tvoid set_motion_plus(size_t index, bool state);\n\n\tvoid update_report_type(size_t index);\n};\n\n\n\n"
  },
  {
    "path": "src/input/api/Wiimote/WiimoteDevice.h",
    "content": "#pragma once\n\nclass WiimoteDevice\n{\n\tfriend class WiimoteInfo;\npublic:\n\tvirtual ~WiimoteDevice() = default;\n\n\tvirtual bool write_data(const std::vector<uint8>& data) = 0;\n\tvirtual std::optional<std::vector<uint8_t>> read_data() = 0;\n\n\tvirtual bool operator==(const WiimoteDevice& o) const = 0;\n};\n\nusing WiimoteDevicePtr = std::shared_ptr<WiimoteDevice>;\n"
  },
  {
    "path": "src/input/api/Wiimote/WiimoteMessages.h",
    "content": "#pragma once\n\n// https://wiibrew.org/wiki/Wiimote\n\nenum InputReportId : uint8\n{\n\tkNone = 0,\n\n\tkStatus = 0x20,\n\tkRead = 0x21,\n\tkAcknowledge = 0x22,\n\n\tkDataCore = 0x30,\n\tkDataCoreAcc = 0x31,\n\tkDataCoreExt8 = 0x32,\n\tkDataCoreAccIR = 0x33,\n\tkDataCoreExt19 = 0x34,\n\tkDataCoreAccExt = 0x35,\n\tkDataCoreIRExt = 0x36,\n\tkDataCoreAccIRExt = 0x37,\n\tkDataExt = 0x3d,\n};\n\nenum RegisterAddress : uint32\n{\n\tkRegisterCalibration = 0x16,\n\tkRegisterCalibration2 = 0x20, // backup calibration data\n\n\tkRegisterIR = 0x4b00030,\n\tkRegisterIRSensitivity1 = 0x4b00000,\n\tkRegisterIRSensitivity2 = 0x4b0001a,\n\tkRegisterIRMode = 0x4b00033,\n\n\tkRegisterExtensionEncrypted = 0x4a40040,\n\n\tkRegisterExtension1 = 0x4a400f0,\n\tkRegisterExtension2 = 0x4a400fb,\n\tkRegisterExtensionType = 0x4a400fa,\n\tkRegisterExtensionCalibration = 0x4a40020,\n\n\tkRegisterMotionPlusDetect = 0x4a600fa,\n\tkRegisterMotionPlusInit = 0x4a600f0,\n\tkRegisterMotionPlusEnable = 0x4a600fe,\n};\n\nenum ExtensionType : uint64\n{\n\tkExtensionNunchuck = 0x0000A4200000,\n\tkExtensionClassic = 0x0000A4200101,\n\tkExtensionClassicPro = 0x0100A4200101,\n\tkExtensionDrawsome = 0xFF00A4200013,\n\tkExtensionGuitar = 0x0000A4200103,\n\tkExtensionDrums = 0x0100A4200103,\n\tkExtensionBalanceBoard = 0x2A2C,\n\n\tkExtensionMotionPlusInactive = 0xa4200005,\n\tkExtensionMotionPlus = 0xa6200005,\n\n\tkExtensionPartialyInserted = 0xffffffffffff,\n};\n\nenum MemoryType : uint8\n{\n\tkEEPROMMemory = 0,\n\tkRegisterMemory = 0x4,\n};\n\nenum StatusBitmask : uint8\n{\n\tkBatteryEmpty = 0x1,\n\tkExtensionConnected = 0x2,\n\tkSpeakerEnabled = 0x4,\n\tkIREnabled = 0x8,\n\tkLed1 = 0x10,\n\tkLed2 = 0x20,\n\tkLed3 = 0x40,\n\tkLed4 = 0x80\n};\n\nenum OutputReportId : uint8\n{\n\tkLED = 0x11,\n\tkType = 0x12,\n\tkIR = 0x13,\n\tkSpeakerState = 0x14,\n\tkStatusRequest = 0x15,\n\tkWriteMemory = 0x16,\n\tkReadMemory = 0x17,\n\tkSpeakerData = 0x18,\n\tkSpeakerMute = 0x19,\n\tkIR2 = 0x1A,\n};\n\nenum IRMode : uint8\n{\n\tkIRDisabled,\n\tkBasicIR = 1,\n\tkExtendedIR = 3,\n\tkFullIR = 5,\n};\n\nenum WiimoteButtons\n{\n\tkWiimoteButton_Left = 0,\n\tkWiimoteButton_Right = 1,\n\tkWiimoteButton_Down = 2,\n\tkWiimoteButton_Up = 3,\n\tkWiimoteButton_Plus = 4,\n\n\tkWiimoteButton_Two = 8,\n\tkWiimoteButton_One = 9,\n\tkWiimoteButton_B = 10,\n\tkWiimoteButton_A = 11,\n\tkWiimoteButton_Minus = 12,\n\n\tkWiimoteButton_Home = 15,\n\n\t// self defined\n\tkWiimoteButton_C = 16,\n\tkWiimoteButton_Z = 17,\n\n\tkHighestWiimote = 20,\n};\n\nenum ClassicButtons\n{\n\tkClassicButton_R = 1,\n\tkClassicButton_Plus = 2,\n\tkClassicButton_Home = 3,\n\tkClassicButton_Minus = 4,\n\tkClassicButton_L = 5,\n\tkClassicButton_Down = 6,\n\tkClassicButton_Right = 7,\n\tkClassicButton_Up = 8,\n\tkClassicButton_Left = 9,\n\tkClassicButton_ZR = 10,\n\tkClassicButton_X = 11,\n\tkClassicButton_A = 12,\n\tkClassicButton_Y = 13,\n\tkClassicButton_B = 14,\n\tkClassicButton_ZL = 15,\n};\n\nstruct Calibration\n{\n\tglm::vec<3, uint16> zero{ 0x200, 0x200, 0x200 };\n\tglm::vec<3, uint16> gravity{ 0x240, 0x240, 0x240 };\n};\n\nstruct BasicIR\n{\n\tuint8 x1;\n\tuint8 y1;\n\n\tstruct\n\t{\n\t\tuint8 x2 : 2;\n\t\tuint8 y2 : 2;\n\t\tuint8 x1 : 2;\n\t\tuint8 y1 : 2;\n\t} bits;\n\tstatic_assert(sizeof(bits) == 1);\n\n\tuint8 x2;\n\tuint8 y2;\n};\nstatic_assert(sizeof(BasicIR) == 5);\n\nstruct ExtendedIR\n{\n\tuint8 x;\n\tuint8 y;\n\tstruct\n\t{\n\t\tuint8 size : 4;\n\t\tuint8 x : 2;\n\t\tuint8 y : 2;\n\t} bits;\n\tstatic_assert(sizeof(bits) == 1);\n};\nstatic_assert(sizeof(ExtendedIR) == 3);\n\nstruct IRDot\n{\n\tbool visible = false;\n\tglm::vec2 pos;\n\tglm::vec<2, uint16> raw;\n\tuint32 size;\n};\n\nstruct IRCamera\n{\n\tIRMode mode;\n\tstd::array<IRDot, 4> dots{}, prev_dots{};\n\n\tglm::vec2 position, m_prev_position;\n\tglm::vec2 middle;\n\tfloat distance;\n\tstd::pair<sint32, sint32> indices{ 0,1 };\n};\n\nstruct NunchuchCalibration : Calibration\n{\n\tglm::vec<2, uint8> min{};\n\tglm::vec<2, uint8> center{ 0x7f, 0x7f };\n\tglm::vec<2, uint8> max{ 0xff, 0xff };\n};\n\nstruct MotionPlusData\n{\n\tCalibration calibration{};\n\n\tglm::vec3 orientation; // yaw, roll, pitch\n\tbool slow_roll = false;\n\tbool slow_pitch = false;\n\tbool slow_yaw = false;\n\tbool extension_connected = false;\n};\n\nstruct NunchuckData\n{\n\tglm::vec3 acceleration{}, prev_acceleration{};\n\tNunchuchCalibration calibration{};\n\n\tbool c = false;\n\tbool z = false;\n\n\tglm::vec2 axis{};\n\tglm::vec<2, uint8> raw_axis{};\n\n\tMotionSample motion_sample{};\n};\n\nstruct ClassicData\n{\n\tglm::vec2 left_axis{};\n\tglm::vec<2, uint8> left_raw_axis{};\n\n\tglm::vec2 right_axis{};\n\tglm::vec<2, uint8> right_raw_axis{};\n\n\tglm::vec2 trigger{};\n\tglm::vec<2, uint8> raw_trigger{};\n\tuint16 buttons = 0;\n};\n"
  },
  {
    "path": "src/input/api/Wiimote/hidapi/HidapiWiimote.cpp",
    "content": "#include \"HidapiWiimote.h\"\n#include <cwchar>\n\nstatic constexpr uint16 WIIMOTE_VENDOR_ID = 0x057e;\nstatic constexpr uint16 WIIMOTE_PRODUCT_ID = 0x0306;\nstatic constexpr uint16 WIIMOTE_MP_PRODUCT_ID = 0x0330;\nstatic constexpr uint16 WIIMOTE_MAX_INPUT_REPORT_LENGTH = 22;\nstatic constexpr auto PRO_CONTROLLER_NAME = L\"Nintendo RVL-CNT-01-UC\";\n\nHidapiWiimote::HidapiWiimote(hid_device* dev, std::string_view path)\n : m_handle(dev), m_path(path) {\n\n}\n\nbool HidapiWiimote::write_data(const std::vector<uint8> &data) {\n    return hid_write(m_handle, data.data(), data.size()) >= 0;\n}\n\nstd::optional<std::vector<uint8>> HidapiWiimote::read_data() {\n    std::array<uint8, WIIMOTE_MAX_INPUT_REPORT_LENGTH> read_data{};\n    const auto result = hid_read(m_handle, read_data.data(), WIIMOTE_MAX_INPUT_REPORT_LENGTH);\n    if (result < 0)\n        return {};\n    return {{read_data.cbegin(), read_data.cbegin() + result}};\n}\n\nstd::vector<WiimoteDevicePtr> HidapiWiimote::get_devices() {\n    std::vector<WiimoteDevicePtr> wiimote_devices;\n    hid_init();\n    const auto device_enumeration = hid_enumerate(WIIMOTE_VENDOR_ID, 0x0);\n\n    for (auto it = device_enumeration; it != nullptr; it = it->next){\n        if (it->product_id != WIIMOTE_PRODUCT_ID && it->product_id != WIIMOTE_MP_PRODUCT_ID)\n            continue;\n        if (std::wcscmp(it->product_string, PRO_CONTROLLER_NAME) == 0)\n            continue;\n        auto dev = hid_open_path(it->path);\n        if (!dev){\n            cemuLog_logDebug(LogType::Force, \"Unable to open Wiimote device at {}: {}\", it->path, boost::nowide::narrow(hid_error(nullptr)));\n        }\n        else {\n            hid_set_nonblocking(dev, true);\n            wiimote_devices.push_back(std::make_shared<HidapiWiimote>(dev, it->path));\n        }\n    }\n    hid_free_enumeration(device_enumeration);\n    return wiimote_devices;\n}\n\nbool HidapiWiimote::operator==(const WiimoteDevice& rhs) const  {\n    auto other = dynamic_cast<const HidapiWiimote*>(&rhs);\n\tif (!other)\n\t\treturn false;\n\treturn m_path == other->m_path;\n}\n\nHidapiWiimote::~HidapiWiimote() {\n    hid_close(m_handle);\n}\n"
  },
  {
    "path": "src/input/api/Wiimote/hidapi/HidapiWiimote.h",
    "content": "#pragma once\n\n#include <api/Wiimote/WiimoteDevice.h>\n#include <hidapi.h>\n\nclass HidapiWiimote : public WiimoteDevice {\npublic:\n    HidapiWiimote(hid_device* dev, std::string_view path);\n    ~HidapiWiimote() override;\n\n    bool write_data(const std::vector<uint8> &data) override;\n    std::optional<std::vector<uint8>> read_data() override;\n    bool operator==(const WiimoteDevice& o) const override;\n\n    static std::vector<WiimoteDevicePtr> get_devices();\n\nprivate:\n    hid_device* m_handle;\n    const std::string m_path;\n\n};\n"
  },
  {
    "path": "src/input/api/Wiimote/l2cap/L2CapWiimote.cpp",
    "content": "#include \"L2CapWiimote.h\"\n#include <bluetooth/l2cap.h>\n\nconstexpr auto comparator = [](const bdaddr_t& a, const bdaddr_t& b) {\n\treturn bacmp(&a, &b);\n};\n\nstatic auto s_addresses = std::map<bdaddr_t, bool, decltype(comparator)>(comparator);\nstatic std::mutex s_addressMutex;\n\nstatic bool AttemptConnect(int sockFd, const sockaddr_l2& addr)\n{\n\tauto res = connect(sockFd, reinterpret_cast<const sockaddr*>(&addr),\n\t\t\t\t\t   sizeof(sockaddr_l2));\n\tif (res == 0)\n\t\treturn true;\n\treturn connect(sockFd, reinterpret_cast<const sockaddr*>(&addr),\n\t\t\t\t   sizeof(sockaddr_l2)) == 0;\n}\n\nstatic bool AttemptSetNonBlock(int sockFd)\n{\n\treturn fcntl(sockFd, F_SETFL, fcntl(sockFd, F_GETFL) | O_NONBLOCK) == 0;\n}\n\nL2CapWiimote::L2CapWiimote(int controlFd, int dataFd, bdaddr_t addr)\n\t: m_controlFd(controlFd), m_dataFd(dataFd), m_addr(addr)\n{\n}\n\nL2CapWiimote::~L2CapWiimote()\n{\n\tclose(m_dataFd);\n\tclose(m_controlFd);\n\tconst auto& b = m_addr.b;\n\tcemuLog_logDebug(LogType::Force, \"Wiimote at {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x} disconnected\", b[5], b[4], b[3], b[2], b[1], b[0]);\n\n\t// Re-add to candidate vec\n\ts_addressMutex.lock();\n\ts_addresses[m_addr] = false;\n\ts_addressMutex.unlock();\n}\n\nvoid L2CapWiimote::AddCandidateAddress(bdaddr_t addr)\n{\n\tstd::scoped_lock lock(s_addressMutex);\n\ts_addresses.try_emplace(addr, false);\n}\n\nstd::vector<WiimoteDevicePtr> L2CapWiimote::get_devices()\n{\n\ts_addressMutex.lock();\n\tstd::vector<bdaddr_t> unconnected;\n\tfor (const auto& [addr, connected] : s_addresses)\n\t{\n\t\tif (!connected)\n\t\t\tunconnected.push_back(addr);\n\t}\n\ts_addressMutex.unlock();\n\n\tstd::vector<WiimoteDevicePtr> outDevices;\n\tfor (const auto& addr : unconnected)\n\t{\n\t\t// Control socket, PSM 0x11, needs to be open for the data socket to be opened\n\t\tauto controlFd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);\n\t\tif (controlFd < 0)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Failed to open control socket: {}\", strerror(errno));\n\t\t\tcontinue;\n\t\t}\n\n\t\tsockaddr_l2 controlAddr{};\n\t\tcontrolAddr.l2_family = AF_BLUETOOTH;\n\t\tcontrolAddr.l2_psm = htobs(0x11);\n\t\tcontrolAddr.l2_bdaddr = addr;\n\n\t\tif (!AttemptConnect(controlFd, controlAddr) || !AttemptSetNonBlock(controlFd))\n\t\t{\n\t\t\tconst auto& b = addr.b;\n\t\t\tcemuLog_logDebug(LogType::Force, \"Failed to connect control socket to '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}': {}\",\n\t\t\t\t\t\t\t b[5], b[4], b[3], b[2], b[1], b[0], strerror(errno));\n\t\t\tclose(controlFd);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Socket for sending and receiving data from controller, PSM 0x13\n\t\tauto dataFd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);\n\t\tif (dataFd < 0)\n\t\t{\n\t\t\tcemuLog_logDebug(LogType::Force, \"Failed to open data socket: {}\", strerror(errno));\n\t\t\tclose(controlFd);\n\t\t\tcontinue;\n\t\t}\n\t\tsockaddr_l2 dataAddr{};\n\t\tdataAddr.l2_family = AF_BLUETOOTH;\n\t\tdataAddr.l2_psm = htobs(0x13);\n\t\tdataAddr.l2_bdaddr = addr;\n\n\t\tif (!AttemptConnect(dataFd, dataAddr) || !AttemptSetNonBlock(dataFd))\n\t\t{\n\t\t\tconst auto& b = addr.b;\n\t\t\tcemuLog_logDebug(LogType::Force, \"Failed to connect data socket to '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}': {}\",\n\t\t\t\t\t\t\t b[5], b[4], b[3], b[2], b[1], b[0], strerror(errno));\n\t\t\tclose(dataFd);\n\t\t\tclose(controlFd);\n\t\t\tcontinue;\n\t\t}\n\t\toutDevices.emplace_back(std::make_shared<L2CapWiimote>(controlFd, dataFd, addr));\n\n\t\ts_addressMutex.lock();\n\t\ts_addresses[addr] = true;\n\t\ts_addressMutex.unlock();\n\t}\n\treturn outDevices;\n}\n\nbool L2CapWiimote::write_data(const std::vector<uint8>& data)\n{\n\tconst auto size = data.size();\n\tcemu_assert_debug(size < 23);\n\tuint8 buffer[23];\n\t// All outgoing messages must be prefixed with 0xA2\n\tbuffer[0] = 0xA2;\n\tstd::memcpy(buffer + 1, data.data(), size);\n\tconst auto outSize = size + 1;\n\treturn send(m_dataFd, buffer, outSize, 0) == outSize;\n}\n\nstd::optional<std::vector<uint8>> L2CapWiimote::read_data()\n{\n\tuint8 buffer[23];\n\tconst auto nBytes = recv(m_dataFd, buffer, 23, 0);\n\n\tif (nBytes < 0 && errno == EWOULDBLOCK)\n\t\treturn std::vector<uint8>{};\n\t// All incoming messages must be prefixed with 0xA1\n\tif (nBytes < 2 || buffer[0] != 0xA1)\n\t\treturn std::nullopt;\n\treturn std::vector(buffer + 1, buffer + 1 + nBytes - 1);\n}\n\nbool L2CapWiimote::operator==(const WiimoteDevice& rhs) const\n{\n\tauto mote = dynamic_cast<const L2CapWiimote*>(&rhs);\n\tif (!mote)\n\t\treturn false;\n\treturn bacmp(&m_addr, &mote->m_addr) == 0;\n}"
  },
  {
    "path": "src/input/api/Wiimote/l2cap/L2CapWiimote.h",
    "content": "#pragma once\n#include <input/api/Wiimote/WiimoteDevice.h>\n#include <bluetooth/bluetooth.h>\n\nclass L2CapWiimote : public WiimoteDevice\n{\n  public:\n\tL2CapWiimote(int controlFd, int dataFd, bdaddr_t addr);\n\t~L2CapWiimote() override;\n\n\tbool write_data(const std::vector<uint8>& data) override;\n\tstd::optional<std::vector<uint8>> read_data() override;\n\tbool operator==(const WiimoteDevice& o) const override;\n\n\tstatic void AddCandidateAddress(bdaddr_t addr);\n\tstatic std::vector<WiimoteDevicePtr> get_devices();\n  private:\n\tint m_controlFd;\n\tint m_dataFd;\n\tbdaddr_t m_addr;\n};\n\n"
  },
  {
    "path": "src/input/api/XInput/XInputController.cpp",
    "content": "#include \"input/api/XInput/XInputController.h\"\n\nXInputController::XInputController(uint32 index)\n\t: base_type(fmt::format(\"{}\", index), fmt::format(\"Controller {}\", index + 1))\n{\n\tif (index >= XUSER_MAX_COUNT)\n\t\tthrow std::runtime_error(fmt::format(\"invalid xinput index {} (must be smaller than {})\", index,\n\t\t                                     XUSER_MAX_COUNT));\n\n\tm_index = index;\n\n\tm_settings.axis.deadzone = m_settings.rotation.deadzone = m_settings.trigger.deadzone = 0.15f;\n}\n\nbool XInputController::connect()\n{\n\tif (m_connected)\n\t\treturn true;\n\n\tm_has_battery = false;\n\n\tXINPUT_CAPABILITIES caps{};\n\tm_connected = m_provider->m_XInputGetCapabilities(m_index, XINPUT_FLAG_GAMEPAD, &caps) !=\n\t\tERROR_DEVICE_NOT_CONNECTED;\n\tif (!m_connected) return false;\n\n\tm_has_rumble = (caps.Vibration.wLeftMotorSpeed > 0) || (caps.Vibration.wRightMotorSpeed > 0);\n\n\tif (m_provider->m_XInputGetBatteryInformation)\n\t{\n\t\tXINPUT_BATTERY_INFORMATION battery{};\n\t\tif (m_provider->m_XInputGetBatteryInformation(m_index, BATTERY_DEVTYPE_GAMEPAD, &battery) == ERROR_SUCCESS)\n\t\t{\n\t\t\tm_has_battery = (battery.BatteryType == BATTERY_TYPE_ALKALINE || battery.BatteryType ==\n\t\t\t\tBATTERY_TYPE_NIMH);\n\t\t}\n\t}\n\t\n\treturn m_connected;\n}\n\nbool XInputController::is_connected()\n{\n\treturn m_connected;\n}\n\n\nvoid XInputController::start_rumble()\n{\n\tif (!has_rumble() || m_settings.rumble <= 0)\n\t\treturn;\n\n\tXINPUT_VIBRATION vibration;\n\tvibration.wLeftMotorSpeed = static_cast<WORD>(m_settings.rumble * std::numeric_limits<uint16>::max());\n\tvibration.wRightMotorSpeed = static_cast<WORD>(m_settings.rumble * std::numeric_limits<uint16>::max());\n\tm_provider->m_XInputSetState(m_index, &vibration);\n}\n\nvoid XInputController::stop_rumble()\n{\n\tif (!has_rumble())\n\t\treturn;\n\n\tXINPUT_VIBRATION vibration{};\n\tm_provider->m_XInputSetState(m_index, &vibration);\n}\n\nbool XInputController::has_low_battery()\n{\n\tif (!has_battery())\n\t\treturn false;\n\n\tXINPUT_BATTERY_INFORMATION battery{};\n\tif (m_provider->m_XInputGetBatteryInformation(m_index, BATTERY_DEVTYPE_GAMEPAD, &battery) == ERROR_SUCCESS)\n\t{\n\t\treturn (battery.BatteryType == BATTERY_TYPE_ALKALINE || battery.BatteryType == BATTERY_TYPE_NIMH) && battery\n\t\t\t.BatteryLevel <= BATTERY_LEVEL_LOW;\n\t}\n\n\treturn false;\n}\n\nstd::string XInputController::get_button_name(uint64 button) const\n{\n\tswitch (1ULL << button)\n\t{\n\tcase XINPUT_GAMEPAD_A: return \"A\";\n\tcase XINPUT_GAMEPAD_B: return \"B\";\n\tcase XINPUT_GAMEPAD_X: return \"X\";\n\tcase XINPUT_GAMEPAD_Y: return \"Y\";\n\n\tcase XINPUT_GAMEPAD_LEFT_SHOULDER: return \"L\";\n\tcase XINPUT_GAMEPAD_RIGHT_SHOULDER: return \"R\";\n\n\tcase XINPUT_GAMEPAD_START: return \"Start\";\n\tcase XINPUT_GAMEPAD_BACK: return \"Select\";\n\n\tcase XINPUT_GAMEPAD_LEFT_THUMB: return \"L-Stick\";\n\tcase XINPUT_GAMEPAD_RIGHT_THUMB: return \"R-Stick\";\n\tcase XINPUT_GAMEPAD_DPAD_UP: return \"DPAD-Up\";\n\tcase XINPUT_GAMEPAD_DPAD_DOWN: return \"DPAD-Down\";\n\tcase XINPUT_GAMEPAD_DPAD_LEFT: return \"DPAD-Left\";\n\tcase XINPUT_GAMEPAD_DPAD_RIGHT: return \"DPAD-Right\";\n\t}\n\n\treturn Controller::get_button_name(button);\n}\n\nControllerState XInputController::raw_state()\n{\n\tControllerState result{};\n\tif (!m_connected)\n\t\treturn result;\n\n\tXINPUT_STATE state;\n\tif (m_provider->m_XInputGetState(m_index, &state) != ERROR_SUCCESS)\n\t{\n\t\tm_connected = false;\n\t\treturn result;\n\t}\n\n\t// Buttons\n\tfor(int i=0;i<std::numeric_limits<WORD>::digits;i++)\n\t\tresult.buttons.SetButtonState(i, (state.Gamepad.wButtons & (1 << i)) != 0);\n\n\tif (state.Gamepad.sThumbLX > 0)\n\t\tresult.axis.x = (float)state.Gamepad.sThumbLX / std::numeric_limits<sint16>::max();\n\telse if (state.Gamepad.sThumbLX < 0)\n\t\tresult.axis.x = (float)-state.Gamepad.sThumbLX / std::numeric_limits<sint16>::min();\n\n\tif (state.Gamepad.sThumbLY > 0)\n\t\tresult.axis.y = (float)state.Gamepad.sThumbLY / std::numeric_limits<sint16>::max();\n\telse if (state.Gamepad.sThumbLY < 0)\n\t\tresult.axis.y = (float)-state.Gamepad.sThumbLY / std::numeric_limits<sint16>::min();\n\n\t// Right Stick\n\tif (state.Gamepad.sThumbRX > 0)\n\t\tresult.rotation.x = (float)state.Gamepad.sThumbRX / std::numeric_limits<sint16>::max();\n\telse if (state.Gamepad.sThumbRX < 0)\n\t\tresult.rotation.x = (float)-state.Gamepad.sThumbRX / std::numeric_limits<sint16>::min();\n\n\tif (state.Gamepad.sThumbRY > 0)\n\t\tresult.rotation.y = (float)state.Gamepad.sThumbRY / std::numeric_limits<sint16>::max();\n\telse if (state.Gamepad.sThumbRY < 0)\n\t\tresult.rotation.y = (float)-state.Gamepad.sThumbRY / std::numeric_limits<sint16>::min();\n\n\t// Trigger\n\tresult.trigger.x = (float)state.Gamepad.bLeftTrigger / std::numeric_limits<uint8>::max();\n\tresult.trigger.y = (float)state.Gamepad.bRightTrigger / std::numeric_limits<uint8>::max();\n\t\n\treturn result;\n}\n"
  },
  {
    "path": "src/input/api/XInput/XInputController.h",
    "content": "#pragma once\n\n#include \"input/api/XInput/XInputControllerProvider.h\"\n#include \"input/api/Controller.h\"\n\nclass XInputController : public Controller<XInputControllerProvider>\n{\npublic:\n\tXInputController(uint32 index);\n\t\n\tstd::string_view api_name() const override\n\t{\n\t\tstatic_assert(to_string(InputAPI::XInput) == \"XInput\");\n\t\treturn to_string(InputAPI::XInput);\n\t}\n\tInputAPI::Type api() const override { return InputAPI::XInput; }\n\t\n\tbool connect() override;\n\tbool is_connected() override;\n\t\n\tbool has_rumble() override { return m_has_rumble; }\n\tbool has_battery() override { return m_has_battery; }\n\tbool has_low_battery() override;\n\t\n\tvoid start_rumble() override;\n\tvoid stop_rumble() override;\n\n\tstd::string get_button_name(uint64 button) const override;\n\nprotected:\n\tControllerState raw_state() override;\n\nprivate:\n\tuint32 m_index;\n\tbool m_connected = false;\n\tbool m_has_battery = false;\n\tbool m_has_rumble = false;\n};\n"
  },
  {
    "path": "src/input/api/XInput/XInputControllerProvider.cpp",
    "content": "#include <Windows.h>\n\n#include \"input/api/XInput/XInputControllerProvider.h\"\n#include \"input/api/XInput/XInputController.h\"\n\nXInputControllerProvider::XInputControllerProvider()\n{\n\t// try to load newest to oldest\n\tm_module = LoadLibraryA(\"XInput1_4.DLL\");\n\tif (!m_module)\n\t{\n\t\tm_module = LoadLibraryA(\"XInput1_3.DLL\");\n\t\tif (!m_module)\n\t\t{\n\t\t\tm_module = LoadLibraryA(\"XInput9_1_0.dll\");\n\t\t\tif (!m_module)\n\t\t\t\tthrow std::runtime_error(\"can't load any xinput dll\");\n\t\t}\n\t}\n\n#define GET_XINPUT_PROC(__FUNC__) m_##__FUNC__ = (decltype(m_##__FUNC__))GetProcAddress(m_module, #__FUNC__)\n\tGET_XINPUT_PROC(XInputGetCapabilities);\n\tGET_XINPUT_PROC(XInputGetState);\n\tGET_XINPUT_PROC(XInputSetState);\n\n\tif (!m_XInputGetCapabilities || !m_XInputGetState || !m_XInputSetState)\n\t{\n\t\tFreeLibrary(m_module);\n\t\tthrow std::runtime_error(\"can't find necessary xinput functions\");\n\t}\n\n\t// only available in XInput1_4 and XInput1_3\n\tGET_XINPUT_PROC(XInputGetBatteryInformation);\n#undef GET_XINPUT_PROC\n\n}\n\nXInputControllerProvider::~XInputControllerProvider()\n{\n\tif (m_module)\n\t\tFreeLibrary(m_module);\n}\n\nstd::vector<std::shared_ptr<ControllerBase>> XInputControllerProvider::get_controllers()\n{\n\tstd::vector<std::shared_ptr<ControllerBase>> result;\n\tfor(DWORD i = 0; i < XUSER_MAX_COUNT; ++i)\n\t{\n\t\tXINPUT_CAPABILITIES caps;\n\t\tif (m_XInputGetCapabilities(i, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS)\n\t\t{\n\t\t\tresult.emplace_back(std::make_shared<XInputController>(i));\n\t\t}\n\t}\n\n\treturn result;\n}\n"
  },
  {
    "path": "src/input/api/XInput/XInputControllerProvider.h",
    "content": "#pragma once\n#if BOOST_OS_WINDOWS\n#include \"input/api/ControllerProvider.h\"\n\n#include <Xinput.h>\n\n#ifndef HAS_XINPUT\n#define HAS_XINPUT 1\n#endif\n\n\nclass XInputControllerProvider : public ControllerProviderBase\n{\n\tfriend class XInputController;\npublic:\n\tXInputControllerProvider();\n\t~XInputControllerProvider() override;\n\n\tinline static InputAPI::Type kAPIType = InputAPI::XInput;\n\tInputAPI::Type api() const override { return kAPIType; }\n\n\tstd::vector<std::shared_ptr<ControllerBase>> get_controllers() override;\n\nprivate:\n\tHMODULE m_module = nullptr;\n\tdecltype(&XInputGetBatteryInformation) m_XInputGetBatteryInformation;\n\tdecltype(&XInputGetCapabilities) m_XInputGetCapabilities;\n\tdecltype(&XInputSetState) m_XInputSetState;\n\tdecltype(&XInputGetState) m_XInputGetState;\n};\n\n#endif"
  },
  {
    "path": "src/input/emulated/ClassicController.cpp",
    "content": "#include \"input/emulated/ClassicController.h\"\n\n#include \"input/api/Controller.h\"\n#include \"input/api/SDL/SDLController.h\"\n\nClassicController::ClassicController(size_t player_index)\n\t: WPADController(player_index, kDataFormat_CLASSIC)\n{\n}\n\nuint32 ClassicController::get_emulated_button_flag(uint32 id) const\n{\n\treturn s_get_emulated_button_flag(id);\n}\n\nuint32 ClassicController::s_get_emulated_button_flag(uint32 id)\n{\n\tswitch (id)\n\t{\n\tcase kButtonId_A:\n\t\treturn kCLButton_A;\n\tcase kButtonId_B:\n\t\treturn kCLButton_B;\n\tcase kButtonId_X:\n\t\treturn kCLButton_X;\n\tcase kButtonId_Y:\n\t\treturn kCLButton_Y;\n\n\tcase kButtonId_Plus:\n\t\treturn kCLButton_Plus;\n\tcase kButtonId_Minus:\n\t\treturn kCLButton_Minus;\n\n\tcase kButtonId_Up:\n\t\treturn kCLButton_Up;\n\tcase kButtonId_Down:\n\t\treturn kCLButton_Down;\n\tcase kButtonId_Left:\n\t\treturn kCLButton_Left;\n\tcase kButtonId_Right:\n\t\treturn kCLButton_Right;\n\n\tcase kButtonId_L:\n\t\treturn kCLButton_L;\n\tcase kButtonId_ZL:\n\t\treturn kCLButton_ZL;\n\tcase kButtonId_R:\n\t\treturn kCLButton_R;\n\tcase kButtonId_ZR:\n\t\treturn kCLButton_ZR;\n\t}\n\n\treturn 0;\n}\n\nstd::string_view ClassicController::get_button_name(ButtonId id)\n{\n\tswitch (id)\n\t{\n\tcase kButtonId_A: return \"A\";\n\tcase kButtonId_B: return \"B\";\n\tcase kButtonId_X: return \"X\";\n\tcase kButtonId_Y: return \"Y\";\n\tcase kButtonId_L: return \"L\";\n\tcase kButtonId_R: return \"R\";\n\tcase kButtonId_ZL: return \"ZL\";\n\tcase kButtonId_ZR: return \"ZR\";\n\n\tcase kButtonId_Plus: return \"+\";\n\tcase kButtonId_Minus: return \"-\";\n\tcase kButtonId_Home: return TR_NOOP(\"home\");\n\n\tcase kButtonId_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_Right: return TR_NOOP(\"right\");\n\n\tcase kButtonId_StickL_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_StickL_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_StickL_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_StickL_Right: return TR_NOOP(\"right\");\n\n\tcase kButtonId_StickR_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_StickR_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_StickR_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_StickR_Right: return TR_NOOP(\"right\");\n\n\tdefault:\n\t\treturn \"\";\n\t}\n}\n\nglm::vec2 ClassicController::get_axis() const\n{\n\tconst auto left = get_axis_value(kButtonId_StickL_Left);\n\tconst auto right = get_axis_value(kButtonId_StickL_Right);\n\n\tconst auto up = get_axis_value(kButtonId_StickL_Up);\n\tconst auto down = get_axis_value(kButtonId_StickL_Down);\n\n\tglm::vec2 result;\n\tresult.x = (left > right) ? -left : right;\n\tresult.y = (up > down) ? up : -down;\n\treturn length(result) > 1.0f ? normalize(result) : result;\n}\n\nglm::vec2 ClassicController::get_rotation() const\n{\n\tconst auto left = get_axis_value(kButtonId_StickR_Left);\n\tconst auto right = get_axis_value(kButtonId_StickR_Right);\n\n\tconst auto up = get_axis_value(kButtonId_StickR_Up);\n\tconst auto down = get_axis_value(kButtonId_StickR_Down);\n\n\tglm::vec2 result;\n\tresult.x = (left > right) ? -left : right;\n\tresult.y = (up > down) ? up : -down;\n\treturn length(result) > 1.0f ? normalize(result) : result;\n}\n\nglm::vec2 ClassicController::get_trigger() const\n{\n\tconst auto left = get_axis_value(kButtonId_ZL);\n\tconst auto right = get_axis_value(kButtonId_ZR);\n\treturn { left, right };\n}\n\nbool ClassicController::set_default_mapping(const std::shared_ptr<ControllerBase>& controller)\n{\n\tstd::vector<std::pair<uint64, uint64>> mapping;\n\tswitch (controller->api())\n\t{\n\tcase InputAPI::SDLController: {\n\t\tconst auto sdl_controller = std::static_pointer_cast<SDLController>(controller);\n\t\tif (sdl_controller->get_guid() == SDLController::kLeftJoyCon)\n\t\t{\n\t\t\tmapping =\n\t\t\t{\n\t\t\t\t{kButtonId_L, kButton9},\n\t\t\t\t{kButtonId_ZL, kTriggerXP},\n\n\t\t\t\t{kButtonId_Minus, kButton4},\n\n\t\t\t\t{kButtonId_Up, kButton11},\n\t\t\t\t{kButtonId_Down, kButton12},\n\t\t\t\t{kButtonId_Left, kButton13},\n\t\t\t\t{kButtonId_Right, kButton14},\n\n\t\t\t\t{kButtonId_StickL_Up, kAxisYN},\n\t\t\t\t{kButtonId_StickL_Down, kAxisYP},\n\t\t\t\t{kButtonId_StickL_Left, kAxisXN},\n\t\t\t\t{kButtonId_StickL_Right, kAxisXP},\n\t\t\t};\n\t\t}\n\t\telse if (sdl_controller->get_guid() == SDLController::kRightJoyCon)\n\t\t{\n\t\t\tmapping =\n\t\t\t{\n\t\t\t\t{kButtonId_A, kButton0},\n\t\t\t\t{kButtonId_B, kButton1},\n\t\t\t\t{kButtonId_X, kButton2},\n\t\t\t\t{kButtonId_Y, kButton3},\n\n\t\t\t\t{kButtonId_R, kButton10},\n\t\t\t\t{kButtonId_ZR, kTriggerYP},\n\n\t\t\t\t{kButtonId_Plus, kButton6},\n\n\t\t\t\t{kButtonId_StickR_Up, kRotationYN},\n\t\t\t\t{kButtonId_StickR_Down, kRotationYP},\n\t\t\t\t{kButtonId_StickR_Left, kRotationXN},\n\t\t\t\t{kButtonId_StickR_Right, kRotationXP},\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmapping =\n\t\t\t{\n\t\t\t\t{kButtonId_A, kButton1},\n\t\t\t\t{kButtonId_B, kButton0},\n\t\t\t\t{kButtonId_X, kButton3},\n\t\t\t\t{kButtonId_Y, kButton2},\n\n\t\t\t\t{kButtonId_L, kButton9},\n\t\t\t\t{kButtonId_R, kButton10},\n\t\t\t\t{kButtonId_ZL, kTriggerXP},\n\t\t\t\t{kButtonId_ZR, kTriggerYP},\n\n\t\t\t\t{kButtonId_Plus, kButton6},\n\t\t\t\t{kButtonId_Minus, kButton4},\n\n\t\t\t\t{kButtonId_Up, kButton11},\n\t\t\t\t{kButtonId_Down, kButton12},\n\t\t\t\t{kButtonId_Left, kButton13},\n\t\t\t\t{kButtonId_Right, kButton14},\n\n\t\t\t\t{kButtonId_StickL_Up, kAxisYN},\n\t\t\t\t{kButtonId_StickL_Down, kAxisYP},\n\t\t\t\t{kButtonId_StickL_Left, kAxisXN},\n\t\t\t\t{kButtonId_StickL_Right, kAxisXP},\n\n\t\t\t\t{kButtonId_StickR_Up, kRotationYN},\n\t\t\t\t{kButtonId_StickR_Down, kRotationYP},\n\t\t\t\t{kButtonId_StickR_Left, kRotationXN},\n\t\t\t\t{kButtonId_StickR_Right, kRotationXP},\n\t\t\t};\n\t\t}\n\t}\n\tcase InputAPI::XInput:\n\t{\n\t\tmapping =\n\t\t{\n\t\t\t{kButtonId_A, kButton13},\n\t\t\t{kButtonId_B, kButton12},\n\t\t\t{kButtonId_X, kButton15},\n\t\t\t{kButtonId_Y, kButton14},\n\n\t\t\t{kButtonId_L, kButton8},\n\t\t\t{kButtonId_R, kButton9},\n\t\t\t{kButtonId_ZL, kTriggerXP},\n\t\t\t{kButtonId_ZR, kTriggerYP},\n\n\t\t\t{kButtonId_Plus, kButton4},\n\t\t\t{kButtonId_Minus, kButton5},\n\n\t\t\t{kButtonId_Up, kButton0},\n\t\t\t{kButtonId_Down, kButton1},\n\t\t\t{kButtonId_Left, kButton2},\n\t\t\t{kButtonId_Right, kButton3},\n\n\t\t\t{kButtonId_StickL_Up, kAxisYP},\n\t\t\t{kButtonId_StickL_Down, kAxisYN},\n\t\t\t{kButtonId_StickL_Left, kAxisXN},\n\t\t\t{kButtonId_StickL_Right, kAxisXP},\n\n\t\t\t{kButtonId_StickR_Up, kRotationYP},\n\t\t\t{kButtonId_StickR_Down, kRotationYN},\n\t\t\t{kButtonId_StickR_Left, kRotationXN},\n\t\t\t{kButtonId_StickR_Right, kRotationXP},\n\t\t};\n\t\t\n\t\tbreak;\n\t}\n\t}\n\n\tbool mapping_updated = false;\n\tstd::for_each(mapping.cbegin(), mapping.cend(), [this, &controller, &mapping_updated](const auto& m)\n\t\t{\n\t\t\tif (m_mappings.find(m.first) == m_mappings.cend())\n\t\t\t{\n\t\t\t\tset_mapping(m.first, controller, m.second);\n\t\t\t\tmapping_updated = true;\n\t\t\t}\n\t\t});\n\n\treturn mapping_updated;\n}"
  },
  {
    "path": "src/input/emulated/ClassicController.h",
    "content": "#pragma once\n\n#include \"input/emulated/WPADController.h\"\n\nclass ClassicController : public WPADController\n{\npublic:\n\tenum ButtonId\n\t{\n\t\tkButtonId_None,\n\n\t\tkButtonId_A,\n\t\tkButtonId_B,\n\t\tkButtonId_X,\n\t\tkButtonId_Y,\n\n\t\tkButtonId_L,\n\t\tkButtonId_R,\n\t\tkButtonId_ZL,\n\t\tkButtonId_ZR,\n\n\t\tkButtonId_Plus,\n\t\tkButtonId_Minus,\n\t\tkButtonId_Home,\n\n\t\tkButtonId_Up,\n\t\tkButtonId_Down,\n\t\tkButtonId_Left,\n\t\tkButtonId_Right,\n\n\t\tkButtonId_StickL_Up,\n\t\tkButtonId_StickL_Down,\n\t\tkButtonId_StickL_Left,\n\t\tkButtonId_StickL_Right,\n\n\t\tkButtonId_StickR_Up,\n\t\tkButtonId_StickR_Down,\n\t\tkButtonId_StickR_Left,\n\t\tkButtonId_StickR_Right,\n\n\t\tkButtonId_Max,\n\t};\n\n\tClassicController(size_t player_index);\n\n\tType type() const override { return Type::Classic; }\n\tWPADDeviceType get_device_type() const override { return kWAPDevClassic; }\n\n\tuint32 get_emulated_button_flag(uint32 id) const override;\n\tsize_t get_highest_mapping_id() const override { return kButtonId_Max; }\n\tbool is_axis_mapping(uint64 mapping) const override { return mapping >= kButtonId_StickL_Up && mapping <= kButtonId_StickR_Right; }\n\n\tglm::vec2 get_axis() const override;\n\tglm::vec2 get_rotation() const override;\n\tglm::vec2 get_trigger() const override;\n\n\n\tstatic uint32 s_get_emulated_button_flag(uint32 id);\n\n\tstatic std::string_view get_button_name(ButtonId id);\n\n\tbool is_start_down() const override { return is_mapping_down(kButtonId_Plus); }\n\tbool is_left_down() const override { return is_mapping_down(kButtonId_Left); }\n\tbool is_right_down() const override { return is_mapping_down(kButtonId_Right); }\n\tbool is_up_down() const override { return is_mapping_down(kButtonId_Up); }\n\tbool is_down_down() const override { return is_mapping_down(kButtonId_Down); }\n\tbool is_a_down() const override { return is_mapping_down(kButtonId_A); }\n\tbool is_b_down() const override { return is_mapping_down(kButtonId_B); }\n\tbool is_home_down() const override { return is_mapping_down(kButtonId_Home); }\n\n\tbool set_default_mapping(const std::shared_ptr<ControllerBase>& controller) override;\n};\n"
  },
  {
    "path": "src/input/emulated/EmulatedController.cpp",
    "content": "#include \"input/emulated/EmulatedController.h\"\n\n#include \"input/api/Controller.h\"\n\n#ifdef SUPPORTS_WIIMOTE\n#include \"input/api/Wiimote/NativeWiimoteController.h\"\n#endif\n\nstd::string_view EmulatedController::type_to_string(Type type)\n{\n\tswitch (type)\n\t{\n\tcase VPAD: return \"Wii U GamePad\";\n\tcase Pro: return \"Wii U Pro Controller\";\n\tcase Classic: return \"Wii U Classic Controller\";\n\tcase Wiimote: return \"Wiimote\";\n\t}\n\n\tthrow std::runtime_error(fmt::format(\"unknown emulated controller: {}\", to_underlying(type)));\n}\n\nEmulatedController::Type EmulatedController::type_from_string(std::string_view str)\n{\n\tif (str == \"Wii U GamePad\")\n\t\treturn VPAD;\n\telse if (str == \"Wii U Pro Controller\")\n\t\treturn Pro;\n\telse if (str == \"Wii U Classic Controller\")\n\t\treturn Classic;\n\telse if (str == \"Wiimote\")\n\t\treturn Wiimote;\n\n\tthrow std::runtime_error(fmt::format(\"unknown emulated controller: {}\", str));\n}\n\nEmulatedController::EmulatedController(size_t player_index)\n\t: m_player_index(player_index)\n{\n}\n\nvoid EmulatedController::calibrate()\n{\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& controller : m_controllers)\n\t{\n\t\tcontroller->calibrate();\n\t}\n}\n\nvoid EmulatedController::connect()\n{\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& controller : m_controllers)\n\t{\n\t\tcontroller->connect();\n\t}\n}\n\nvoid EmulatedController::update()\n{\n\tstd::shared_lock lock(m_mutex);\n\tfor(const auto& controller : m_controllers)\n\t{\n\t\tcontroller->update();\n\t}\n}\n\nvoid EmulatedController::controllers_update_states()\n{\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& controller : m_controllers)\n\t{\n\t\tcontroller->update_state();\n\t}\n}\n\nvoid EmulatedController::start_rumble()\n{\n\tm_rumble = true;\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& controller : m_controllers)\n\t{\n\t\tcontroller->start_rumble();\n\t}\n}\n\nvoid EmulatedController::stop_rumble()\n{\n\tif (!m_rumble)\n\t\treturn;\n\n\tm_rumble = false;\n\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& controller : m_controllers)\n\t{\n\t\tcontroller->stop_rumble();\n\t}\n}\n\nbool EmulatedController::is_battery_low() const\n{\n\tstd::shared_lock lock(m_mutex);\n\treturn std::any_of(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) {return c->has_low_battery(); });\n}\n\nbool EmulatedController::has_motion() const\n{\n\tstd::shared_lock lock(m_mutex);\n\treturn std::any_of(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) {return c->use_motion(); });\n}\n\nMotionSample EmulatedController::get_motion_data() const\n{\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& controller : m_controllers)\n\t{\n\t\tif (controller->use_motion())\n\t\t\treturn controller->get_motion_sample();\n\t}\n\n\treturn {};\n}\n\nbool EmulatedController::has_second_motion() const\n{\n\tint motion = 0;\n\tstd::shared_lock lock(m_mutex);\n\tfor(const auto& controller : m_controllers)\n\t{\n\t\tif(controller->use_motion())\n\t\t{\n\t\t\t// if wiimote has nunchuck connected, we use its acceleration\n            #if SUPPORTS_WIIMOTE\n            if(controller->api() == InputAPI::Wiimote)\n\t\t\t{\n\t\t\t\tif(((NativeWiimoteController*)controller.get())->get_extension() == NativeWiimoteController::Nunchuck)\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n            #endif\n\t\t\tmotion++;\n\t\t}\n\t}\n\n\treturn motion >= 2;\n}\n\nMotionSample EmulatedController::get_second_motion_data() const\n{\n\tint motion = 0;\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& controller : m_controllers)\n\t{\n\t\tif (controller->use_motion())\n\t\t{\n\t\t\t// if wiimote has nunchuck connected, we use its acceleration\n            #ifdef SUPPORTS_WIIMOTE\n\t\t\tif (controller->api() == InputAPI::Wiimote)\n\t\t\t{\n\t\t\t\tif (((NativeWiimoteController*)controller.get())->get_extension() == NativeWiimoteController::Nunchuck)\n\t\t\t\t{\n\t\t\t\t\treturn ((NativeWiimoteController*)controller.get())->get_nunchuck_motion_sample();\n\t\t\t\t}\n\t\t\t}\n\t\t\t#endif\n\n\t\t\tmotion++;\n\t\t\tif(motion == 2)\n\t\t\t{\n\t\t\t\treturn controller->get_motion_sample();\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {};\n}\n\nbool EmulatedController::has_position() const\n{\n\tstd::shared_lock lock(m_mutex);\n\treturn std::any_of(m_controllers.cbegin(), m_controllers.cend(), [](const auto& c) {return c->has_position(); });\n}\n\nglm::vec2 EmulatedController::get_position() const\n{\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& controller : m_controllers)\n\t{\n\t\tif (controller->has_position())\n\t\t\treturn controller->get_position();\n\t}\n\n\treturn {};\n}\n\nglm::vec2 EmulatedController::get_prev_position() const\n{\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& controller : m_controllers)\n\t{\n\t\tif (controller->has_position())\n\t\t\treturn controller->get_prev_position();\n\t}\n\n\treturn {};\n}\n\nPositionVisibility EmulatedController::GetPositionVisibility() const\n{\n\tstd::shared_lock lock(m_mutex);\n\tfor (const auto& controller : m_controllers)\n\t{\n\t\tif (controller->has_position())\n\t\t\treturn controller->GetPositionVisibility();\n\t}\n\treturn PositionVisibility::NONE;\n}\n\nvoid EmulatedController::add_controller(std::shared_ptr<ControllerBase> controller)\n{\n\tcontroller->connect();\n\n    #ifdef SUPPORTS_WIIMOTE\n    if (const auto wiimote = std::dynamic_pointer_cast<NativeWiimoteController>(controller)) {\n\t\twiimote->set_player_index(m_player_index);\n\t}\n    #endif\n\tstd::scoped_lock lock(m_mutex);\n\tm_controllers.emplace_back(std::move(controller));\n}\n\nvoid EmulatedController::remove_controller(const std::shared_ptr<ControllerBase>& controller)\n{\n\tstd::scoped_lock lock(m_mutex);\n\tconst auto it = std::find(m_controllers.cbegin(), m_controllers.cend(), controller);\n\tif (it != m_controllers.cend())\n\t{\n\t\tm_controllers.erase(it);\n\n\t\tfor(auto m = m_mappings.begin(); m != m_mappings.end();)\n\t\t{\n\t\t\tif(auto mc = m->second.controller.lock())\n\t\t\t{\n\t\t\t\tif(*mc == *controller)\n\t\t\t\t{\n\t\t\t\t\tm = m_mappings.erase(m);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t++m;\n\t\t}\n\t}\n}\n\nvoid EmulatedController::clear_controllers()\n{\n\tstd::scoped_lock lock(m_mutex);\n\tm_controllers.clear();\n}\n\nfloat EmulatedController::get_axis_value(uint64 mapping) const\n{\n\tconst auto it = m_mappings.find(mapping);\n\tif (it != m_mappings.cend())\n\t{\n\t\tif (const auto controller = it->second.controller.lock()) {\n\t\t\treturn controller->get_axis_value(it->second.button);\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nbool EmulatedController::is_mapping_down(uint64 mapping) const\n{\n\tconst auto it = m_mappings.find(mapping);\n\tif (it != m_mappings.cend())\n\t{\n\t\tif (const auto controller = it->second.controller.lock())\n\t\t\treturn controller->get_state().buttons.GetButtonState(it->second.button);\n\t}\n\treturn false;\n}\n\n\nstd::string EmulatedController::get_mapping_name(uint64 mapping) const\n{\n\tconst auto it = m_mappings.find(mapping);\n\tif (it != m_mappings.cend())\n\t{\n\t\tif (const auto controller = it->second.controller.lock()) {\n\t\t\treturn controller->get_button_name(it->second.button);\n\t\t}\n\t}\n\n\treturn {};\n}\n\nstd::shared_ptr<ControllerBase> EmulatedController::get_mapping_controller(uint64 mapping) const\n{\n\tconst auto it = m_mappings.find(mapping);\n\tif (it != m_mappings.cend())\n\t{\n\t\tif (const auto controller = it->second.controller.lock()) {\n\t\t\treturn controller;\n\t\t}\n\t}\n\n\treturn {};\n}\n\nvoid EmulatedController::delete_mapping(uint64 mapping)\n{\n\tm_mappings.erase(mapping);\n}\n\nvoid EmulatedController::clear_mappings()\n{\n\tm_mappings.clear();\n}\n\nvoid EmulatedController::set_mapping(uint64 mapping, const std::shared_ptr<ControllerBase>& controller,\n                                     uint64 button)\n{\n\tm_mappings[mapping] = { controller, button };\n}\n\nbool EmulatedController::operator==(const EmulatedController& o) const\n{\n\treturn type() == o.type() && m_player_index == o.m_player_index;\n}\n\nbool EmulatedController::operator!=(const EmulatedController& o) const\n{\n\treturn !(*this == o);\n}\n"
  },
  {
    "path": "src/input/emulated/EmulatedController.h",
    "content": "#pragma once\n#include <pugixml.hpp>\n\nclass ControllerBase;\n\n#include \"input/motion/MotionSample.h\"\n\n#include \"input/api/ControllerState.h\"\n#include \"input/api/InputAPI.h\"\n\n#include \"util/helpers/helpers.h\"\n\n// mapping = wii u controller button id\n// button = api button id\n\nclass EmulatedController\n{\n\tfriend class InputManager;\npublic:\n\tEmulatedController(size_t player_index);\n\tvirtual ~EmulatedController() = default;\n\n\tvirtual void load(const pugi::xml_node& node){};\n\tvirtual void save(pugi::xml_node& node){};\n\n\tenum Type\n\t{\n\t\tVPAD,\n\t\tPro,\n\t\tClassic,\n\t\tWiimote,\n\n\t\tMAX\n\t};\n\tvirtual Type type() const = 0;\n\tstd::string_view type_string() const { return type_to_string(type()); }\n\n\tstatic std::string_view type_to_string(Type type);\n\tstatic Type type_from_string(std::string_view str);\n\n\tsize_t player_index() const { return m_player_index; }\n\tconst std::string& get_profile_name() const { return m_profile_name; }\n\tbool has_profile_name() const { return !m_profile_name.empty() && m_profile_name != \"default\"; }\n\n\tvoid calibrate();\n\n\tvoid connect();\n\tvirtual void update();\n\tvoid controllers_update_states();\n\n\tvirtual glm::vec2 get_axis() const = 0;\n\tvirtual glm::vec2 get_rotation() const = 0;\n\tvirtual glm::vec2 get_trigger() const = 0;\n\n\tvoid start_rumble();\n\tvoid stop_rumble();\n\n\tbool is_battery_low() const;\n\n\tbool has_motion() const;\n\tMotionSample get_motion_data() const;\n\n\t// some controllers (nunchuck) provide extra motion data\n\tbool has_second_motion() const;\n\tMotionSample get_second_motion_data() const;\n\n\tbool has_position() const;\n\tglm::vec2 get_position() const;\n\tglm::vec2 get_prev_position() const;\n\tPositionVisibility GetPositionVisibility() const;\n\n\tvoid add_controller(std::shared_ptr<ControllerBase> controller);\n\tvoid remove_controller(const std::shared_ptr<ControllerBase>& controller);\n\tvoid clear_controllers();\n\tconst std::vector<std::shared_ptr<ControllerBase>>& get_controllers() const { return m_controllers; }\n\n\tbool is_mapping_down(uint64 mapping) const;\n\tstd::string get_mapping_name(uint64 mapping) const;\n\tstd::shared_ptr<ControllerBase> get_mapping_controller(uint64 mapping) const;\n\tvoid delete_mapping(uint64 mapping);\n\tvoid clear_mappings();\n\tvoid set_mapping(uint64 mapping, const std::shared_ptr<ControllerBase>& controller_base, uint64 button);\n\n\tvirtual uint32 get_emulated_button_flag(uint32 mapping) const = 0;\n\n\tbool operator==(const EmulatedController& o) const;\n\tbool operator!=(const EmulatedController& o) const;\n\n\tvirtual size_t get_highest_mapping_id() const = 0;\n\tvirtual bool is_axis_mapping(uint64 mapping) const = 0;\n\n\tvirtual bool is_start_down() const = 0;\n\tvirtual bool is_left_down() const = 0;\n\tvirtual bool is_right_down() const = 0;\n\tvirtual bool is_up_down() const = 0;\n\tvirtual bool is_down_down() const = 0;\n\tvirtual bool is_a_down() const = 0;\n\tvirtual bool is_b_down() const = 0;\n\tvirtual bool is_home_down() const = 0;\n\n\tbool was_home_button_down() { return std::exchange(m_homebutton_down, false); }\n\n\tvirtual bool set_default_mapping(const std::shared_ptr<ControllerBase>& controller) { return false; }\n\nprotected:\n\tsize_t m_player_index;\n\tstd::string m_profile_name = \"default\";\n\n\tmutable std::shared_mutex m_mutex;\n\tstd::vector<std::shared_ptr<ControllerBase>> m_controllers;\n\n\tfloat get_axis_value(uint64 mapping) const;\n\tbool m_rumble = false;\n\n\tstruct Mapping\n\t{\n\t\tstd::weak_ptr<ControllerBase> controller;\n\t\tuint64 button;\n\t};\n\tstd::unordered_map<uint64, Mapping> m_mappings;\n\n\tbool m_homebutton_down = false;\n};\n\nusing EmulatedControllerPtr = std::shared_ptr<EmulatedController>;\n\ntemplate <>\nstruct fmt::formatter<EmulatedController::Type> : formatter<string_view> {\n\ttemplate <typename FormatContext>\n\tauto format(EmulatedController::Type v, FormatContext& ctx) const {\n\t\tswitch (v)\n\t\t{\n\t\tcase EmulatedController::Type::VPAD: return formatter<string_view>::format(\"Wii U Gamepad\", ctx);\n\t\tcase EmulatedController::Type::Pro: return formatter<string_view>::format(\"Wii U Pro Controller\", ctx);\n\t\tcase EmulatedController::Type::Classic: return formatter<string_view>::format(\"Wii U Classic Controller Pro\", ctx);\n\t\tcase EmulatedController::Type::Wiimote: return formatter<string_view>::format(\"Wiimote\", ctx);\n\t\t}\n\t\tthrow std::invalid_argument(fmt::format(\"invalid emulated controller type with value {}\", to_underlying(v)));\n\t}\n};\n"
  },
  {
    "path": "src/input/emulated/ProController.cpp",
    "content": "#include \"input/emulated/ProController.h\"\n\n#include \"input/api/Controller.h\"\n#include \"input/api/SDL/SDLController.h\"\n\nProController::ProController(size_t player_index)\n\t: WPADController(player_index, kDataFormat_URCC)\n{\n\n}\n\nuint32 ProController::get_emulated_button_flag(uint32 id) const\n{\n\treturn s_get_emulated_button_flag(id);\n}\n\nuint32 ProController::s_get_emulated_button_flag(uint32 id)\n{\n\tswitch (id)\n\t{\n\tcase kButtonId_A:\n\t\treturn kProButton_A;\n\tcase kButtonId_B:\n\t\treturn kProButton_B;\n\tcase kButtonId_X:\n\t\treturn kProButton_X;\n\tcase kButtonId_Y:\n\t\treturn kProButton_Y;\n\n\tcase kButtonId_Plus:\n\t\treturn kProButton_Plus;\n\tcase kButtonId_Minus:\n\t\treturn kProButton_Minus;\n\tcase kButtonId_Up:\n\t\treturn kProButton_Up;\n\tcase kButtonId_Down:\n\t\treturn kProButton_Down;\n\tcase kButtonId_Left:\n\t\treturn kProButton_Left;\n\tcase kButtonId_Right:\n\t\treturn kProButton_Right;\n\n\tcase kButtonId_StickL:\n\t\treturn kProButton_StickL;\n\tcase kButtonId_StickR:\n\t\treturn kProButton_StickR;\n\n\tcase kButtonId_L:\n\t\treturn kProButton_L;\n\tcase kButtonId_ZL:\n\t\treturn kProButton_ZL;\n\tcase kButtonId_R:\n\t\treturn kProButton_R;\n\tcase kButtonId_ZR:\n\t\treturn kProButton_ZR;\n\n\tdefault:\n\t\treturn 0;\n\t}\n}\n\nstd::string_view ProController::get_button_name(ButtonId id)\n{\n\tswitch (id)\n\t{\n\tcase kButtonId_A: return \"A\";\n\tcase kButtonId_B: return \"B\";\n\tcase kButtonId_X: return \"X\";\n\tcase kButtonId_Y: return \"Y\";\n\tcase kButtonId_L: return \"L\";\n\tcase kButtonId_R: return \"R\";\n\tcase kButtonId_ZL: return \"ZL\";\n\tcase kButtonId_ZR: return \"ZR\";\n\tcase kButtonId_Plus: return \"+\";\n\tcase kButtonId_Minus: return \"-\";\n\tcase kButtonId_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_Right: return TR_NOOP(\"right\");\n\tcase kButtonId_StickL: return TR_NOOP(\"click\");\n\tcase kButtonId_StickR: return TR_NOOP(\"click\");\n\tcase kButtonId_StickL_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_StickL_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_StickL_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_StickL_Right: return TR_NOOP(\"right\");\n\tcase kButtonId_StickR_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_StickR_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_StickR_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_StickR_Right: return TR_NOOP(\"right\");\n\tcase kButtonId_Home: return TR_NOOP(\"home\");\n\tdefault:\n\t\tcemu_assert_debug(false);\n\t\treturn \"\";\n\t}\n}\n\n\nglm::vec2 ProController::get_axis() const\n{\n\tconst auto left = get_axis_value(kButtonId_StickL_Left);\n\tconst auto right = get_axis_value(kButtonId_StickL_Right);\n\n\tconst auto up = get_axis_value(kButtonId_StickL_Up);\n\tconst auto down = get_axis_value(kButtonId_StickL_Down);\n\n\tglm::vec2 result;\n\tresult.x = (left > right) ? -left : right;\n\tresult.y = (up > down) ? up : -down;\n\treturn result;\n}\n\nglm::vec2 ProController::get_rotation() const\n{\n\tconst auto left = get_axis_value(kButtonId_StickR_Left);\n\tconst auto right = get_axis_value(kButtonId_StickR_Right);\n\n\tconst auto up = get_axis_value(kButtonId_StickR_Up);\n\tconst auto down = get_axis_value(kButtonId_StickR_Down);\n\n\tglm::vec2 result;\n\tresult.x = (left > right) ? -left : right;\n\tresult.y = (up > down) ? up : -down;\n\treturn result;\n}\n\nglm::vec2 ProController::get_trigger() const\n{\n\tconst auto left = get_axis_value(kButtonId_ZL);\n\tconst auto right = get_axis_value(kButtonId_ZR);\n\treturn { left, right };\n}\n\nbool ProController::set_default_mapping(const std::shared_ptr<ControllerBase>& controller)\n{\n\tstd::vector<std::pair<uint64, uint64>> mapping;\n\tswitch (controller->api())\n\t{\n\tcase InputAPI::SDLController: {\n\t\tconst auto sdl_controller = std::static_pointer_cast<SDLController>(controller);\n\t\tif (sdl_controller->get_guid() == SDLController::kLeftJoyCon)\n\t\t{\n\t\t\tmapping =\n\t\t\t{\n\t\t\t\t{kButtonId_L, kButton9},\n\t\t\t\t{kButtonId_ZL, kTriggerXP},\n\n\t\t\t\t{kButtonId_Minus, kButton4},\n\n\t\t\t\t{kButtonId_Up, kButton11},\n\t\t\t\t{kButtonId_Down, kButton12},\n\t\t\t\t{kButtonId_Left, kButton13},\n\t\t\t\t{kButtonId_Right, kButton14},\n\n\t\t\t\t{kButtonId_StickL, kButton7},\n\n\t\t\t\t{kButtonId_StickL_Up, kAxisYN},\n\t\t\t\t{kButtonId_StickL_Down, kAxisYP},\n\t\t\t\t{kButtonId_StickL_Left, kAxisXN},\n\t\t\t\t{kButtonId_StickL_Right, kAxisXP},\n\t\t\t};\n\t\t}\n\t\telse if (sdl_controller->get_guid() == SDLController::kRightJoyCon)\n\t\t{\n\t\t\tmapping =\n\t\t\t{\n\t\t\t\t{kButtonId_A, kButton0},\n\t\t\t\t{kButtonId_B, kButton1},\n\t\t\t\t{kButtonId_X, kButton2},\n\t\t\t\t{kButtonId_Y, kButton3},\n\n\t\t\t\t{kButtonId_R, kButton10},\n\t\t\t\t{kButtonId_ZR, kTriggerYP},\n\n\t\t\t\t{kButtonId_Plus, kButton6},\n\n\t\t\t\t{kButtonId_StickR, kButton8},\n\n\t\t\t\t{kButtonId_StickR_Up, kRotationYN},\n\t\t\t\t{kButtonId_StickR_Down, kRotationYP},\n\t\t\t\t{kButtonId_StickR_Left, kRotationXN},\n\t\t\t\t{kButtonId_StickR_Right, kRotationXP},\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmapping =\n\t\t\t{\n\t\t\t\t{kButtonId_A, kButton1},\n\t\t\t\t{kButtonId_B, kButton0},\n\t\t\t\t{kButtonId_X, kButton3},\n\t\t\t\t{kButtonId_Y, kButton2},\n\n\t\t\t\t{kButtonId_L, kButton9},\n\t\t\t\t{kButtonId_R, kButton10},\n\t\t\t\t{kButtonId_ZL, kTriggerXP},\n\t\t\t\t{kButtonId_ZR, kTriggerYP},\n\n\t\t\t\t{kButtonId_Plus, kButton6},\n\t\t\t\t{kButtonId_Minus, kButton4},\n\n\t\t\t\t{kButtonId_Up, kButton11},\n\t\t\t\t{kButtonId_Down, kButton12},\n\t\t\t\t{kButtonId_Left, kButton13},\n\t\t\t\t{kButtonId_Right, kButton14},\n\n\t\t\t\t{kButtonId_StickL, kButton7},\n\t\t\t\t{kButtonId_StickR, kButton8},\n\n\t\t\t\t{kButtonId_StickL_Up, kAxisYN},\n\t\t\t\t{kButtonId_StickL_Down, kAxisYP},\n\t\t\t\t{kButtonId_StickL_Left, kAxisXN},\n\t\t\t\t{kButtonId_StickL_Right, kAxisXP},\n\n\t\t\t\t{kButtonId_StickR_Up, kRotationYN},\n\t\t\t\t{kButtonId_StickR_Down, kRotationYP},\n\t\t\t\t{kButtonId_StickR_Left, kRotationXN},\n\t\t\t\t{kButtonId_StickR_Right, kRotationXP},\n\t\t\t};\n\t\t}\n\t\tbreak;\n\t}\n\tcase InputAPI::XInput:\n\t{\n\t\tmapping =\n\t\t{\n\t\t\t{kButtonId_A, kButton13},\n\t\t\t{kButtonId_B, kButton12},\n\t\t\t{kButtonId_X, kButton15},\n\t\t\t{kButtonId_Y, kButton14},\n\n\t\t\t{kButtonId_L, kButton8},\n\t\t\t{kButtonId_R, kButton9},\n\t\t\t{kButtonId_ZL, kTriggerXP},\n\t\t\t{kButtonId_ZR, kTriggerYP},\n\n\t\t\t{kButtonId_Plus, kButton4},\n\t\t\t{kButtonId_Minus, kButton5},\n\n\t\t\t{kButtonId_Up, kButton0},\n\t\t\t{kButtonId_Down, kButton1},\n\t\t\t{kButtonId_Left, kButton2},\n\t\t\t{kButtonId_Right, kButton3},\n\n\t\t\t{kButtonId_StickL, kButton6},\n\t\t\t{kButtonId_StickR, kButton7},\n\n\t\t\t{kButtonId_StickL_Up, kAxisYP},\n\t\t\t{kButtonId_StickL_Down, kAxisYN},\n\t\t\t{kButtonId_StickL_Left, kAxisXN},\n\t\t\t{kButtonId_StickL_Right, kAxisXP},\n\n\t\t\t{kButtonId_StickR_Up, kRotationYP},\n\t\t\t{kButtonId_StickR_Down, kRotationYN},\n\t\t\t{kButtonId_StickR_Left, kRotationXN},\n\t\t\t{kButtonId_StickR_Right, kRotationXP},\n\t\t};\n\t\tbreak;\n\t}\n\t}\n\n\tbool mapping_updated = false;\n\tstd::for_each(mapping.cbegin(), mapping.cend(), [this, &controller, &mapping_updated](const auto& m)\n\t\t{\n\t\t\tif (m_mappings.find(m.first) == m_mappings.cend())\n\t\t\t{\n\t\t\t\tset_mapping(m.first, controller, m.second);\n\t\t\t\tmapping_updated = true;\n\t\t\t}\n\t\t});\n\n\treturn mapping_updated;\n}"
  },
  {
    "path": "src/input/emulated/ProController.h",
    "content": "#pragma once\n\n#include \"input/emulated/WPADController.h\"\n\nclass ProController : public WPADController\n{\npublic:\n\tenum ButtonId\n\t{\n\t\tkButtonId_None,\n\n\t\tkButtonId_A,\n\t\tkButtonId_B,\n\t\tkButtonId_X,\n\t\tkButtonId_Y,\n\n\t\tkButtonId_L,\n\t\tkButtonId_R,\n\t\tkButtonId_ZL,\n\t\tkButtonId_ZR,\n\n\t\tkButtonId_Plus,\n\t\tkButtonId_Minus,\n\t\tkButtonId_Home,\n\n\t\tkButtonId_Up,\n\t\tkButtonId_Down,\n\t\tkButtonId_Left,\n\t\tkButtonId_Right,\n\n\t\tkButtonId_StickL,\n\t\tkButtonId_StickR,\n\n\t\tkButtonId_StickL_Up,\n\t\tkButtonId_StickL_Down,\n\t\tkButtonId_StickL_Left,\n\t\tkButtonId_StickL_Right,\n\n\t\tkButtonId_StickR_Up,\n\t\tkButtonId_StickR_Down,\n\t\tkButtonId_StickR_Left,\n\t\tkButtonId_StickR_Right,\n\n\t\tkButtonId_Max,\n\t};\n\n\tProController(size_t player_index);\n\n\tType type() const override { return Type::Pro; }\n\tWPADDeviceType get_device_type() const override { return kWAPDevURCC; }\n\n\tuint32 get_emulated_button_flag(uint32 id) const override;\n\tsize_t get_highest_mapping_id() const override { return kButtonId_Max; }\n\tbool is_axis_mapping(uint64 mapping) const override { return mapping >= kButtonId_StickL_Up && mapping <= kButtonId_StickR_Right; }\n\n\tglm::vec2 get_axis() const override;\n\tglm::vec2 get_rotation() const override;\n\tglm::vec2 get_trigger() const override;\n\n\tstatic uint32 s_get_emulated_button_flag(uint32 id);\n\n\tstatic std::string_view get_button_name(ButtonId id);\n\n\tbool is_start_down() const override { return is_mapping_down(kButtonId_Plus); }\n\tbool is_left_down() const override { return is_mapping_down(kButtonId_Left); }\n\tbool is_right_down() const override { return is_mapping_down(kButtonId_Right); }\n\tbool is_up_down() const override { return is_mapping_down(kButtonId_Up); }\n\tbool is_down_down() const override { return is_mapping_down(kButtonId_Down); }\n\tbool is_a_down() const override { return is_mapping_down(kButtonId_A); }\n\tbool is_b_down() const override { return is_mapping_down(kButtonId_B); }\n\tbool is_home_down() const override { return is_mapping_down(kButtonId_Home); }\n\n\tbool set_default_mapping(const std::shared_ptr<ControllerBase>& controller) override;\n};\n"
  },
  {
    "path": "src/input/emulated/VPADController.cpp",
    "content": "#include \"input/emulated/VPADController.h\"\n#include \"input/api/Controller.h\"\n#include \"input/api/SDL/SDLController.h\"\n#include \"WindowSystem.h\"\n#include \"input/InputManager.h\"\n#include \"Cafe/HW/Latte/Core/Latte.h\"\n#include \"Cafe/CafeSystem.h\"\n\nenum ControllerVPADMapping2 : uint32\n{\n\tVPAD_A = 0x8000,\n\tVPAD_B = 0x4000,\n\tVPAD_X = 0x2000,\n\tVPAD_Y = 0x1000,\n\n\tVPAD_L = 0x0020,\n\tVPAD_R = 0x0010,\n\tVPAD_ZL = 0x0080,\n\tVPAD_ZR = 0x0040,\n\n\tVPAD_PLUS = 0x0008,\n\tVPAD_MINUS = 0x0004,\n\tVPAD_HOME = 0x0002,\n\n\tVPAD_UP = 0x0200,\n\tVPAD_DOWN = 0x0100,\n\tVPAD_LEFT = 0x0800,\n\tVPAD_RIGHT = 0x0400,\n\n\tVPAD_STICK_R = 0x00020000,\n\tVPAD_STICK_L = 0x00040000,\n\n\tVPAD_STICK_L_UP = 0x10000000,\n\tVPAD_STICK_L_DOWN = 0x08000000,\n\tVPAD_STICK_L_LEFT = 0x40000000,\n\tVPAD_STICK_L_RIGHT = 0x20000000,\n\n\tVPAD_STICK_R_UP = 0x01000000,\n\tVPAD_STICK_R_DOWN = 0x00800000,\n\tVPAD_STICK_R_LEFT = 0x04000000,\n\tVPAD_STICK_R_RIGHT = 0x02000000,\n\n\t// special flag\n\tVPAD_REPEAT = 0x80000000,\n};\n\nvoid VPADController::VPADRead(VPADStatus_t& status, const BtnRepeat& repeat)\n{\n\tcontrollers_update_states();\n\tm_mic_active = false;\n\tm_screen_active = false;\n\tfor (uint32 i = kButtonId_A; i < kButtonId_Max; ++i)\n\t{\n\t\t// axis will be aplied later\n\t\tif (is_axis_mapping(i))\n\t\t\tcontinue;\n\n\t\tif (is_mapping_down(i))\n\t\t{\n\t\t\tconst uint32 value = get_emulated_button_flag(i);\n\t\t\tif (value == 0)\n\t\t\t{\n\t\t\t\t// special buttons\n\t\t\t\tif (i == kButtonId_Mic)\n\t\t\t\t\tm_mic_active = true;\n\t\t\t\telse if (i == kButtonId_Screen)\n\t\t\t\t\tm_screen_active = true;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tstatus.hold |= value;\n\t\t}\n\t}\n\n\tm_homebutton_down |= is_home_down();\n\n\tconst auto axis = get_axis();\n\tstatus.leftStick.x = axis.x;\n\tstatus.leftStick.y = axis.y;\n\n\tconstexpr float kAxisThreshold = 0.5f;\n\tconstexpr float kHoldAxisThreshold = 0.1f;\n\tconst uint32 last_hold = m_last_holdvalue;\n\n\tif (axis.x <= -kAxisThreshold || (HAS_FLAG(last_hold, VPAD_STICK_L_LEFT) && axis.x <= -kHoldAxisThreshold))\n\t\tstatus.hold |= VPAD_STICK_L_LEFT;\n\telse if (axis.x >= kAxisThreshold || (HAS_FLAG(last_hold, VPAD_STICK_L_RIGHT) && axis.x >= kHoldAxisThreshold))\n\t\tstatus.hold |= VPAD_STICK_L_RIGHT;\n\n\tif (axis.y <= -kAxisThreshold || (HAS_FLAG(last_hold, VPAD_STICK_L_DOWN) && axis.y <= -kHoldAxisThreshold))\n\t\tstatus.hold |= VPAD_STICK_L_DOWN;\n\telse if (axis.y >= kAxisThreshold || (HAS_FLAG(last_hold, VPAD_STICK_L_UP) && axis.y >= kHoldAxisThreshold))\n\t\tstatus.hold |= VPAD_STICK_L_UP;\n\n\tconst auto rotation = get_rotation();\n\tstatus.rightStick.x = rotation.x;\n\tstatus.rightStick.y = rotation.y;\n\n\tif (rotation.x <= -kAxisThreshold || (HAS_FLAG(last_hold, VPAD_STICK_R_LEFT) && rotation.x <= -kHoldAxisThreshold))\n\t\tstatus.hold |= VPAD_STICK_R_LEFT;\n\telse if (rotation.x >= kAxisThreshold || (HAS_FLAG(last_hold, VPAD_STICK_R_RIGHT) && rotation.x >=\n\t\tkHoldAxisThreshold))\n\t\tstatus.hold |= VPAD_STICK_R_RIGHT;\n\n\tif (rotation.y <= -kAxisThreshold || (HAS_FLAG(last_hold, VPAD_STICK_R_DOWN) && rotation.y <= -kHoldAxisThreshold))\n\t\tstatus.hold |= VPAD_STICK_R_DOWN;\n\telse if (rotation.y >= kAxisThreshold || (HAS_FLAG(last_hold, VPAD_STICK_R_UP) && rotation.y >= kHoldAxisThreshold))\n\t\tstatus.hold |= VPAD_STICK_R_UP;\n\n\t// button repeat\n\tconst auto now = std::chrono::high_resolution_clock::now();\n\tif (status.hold != m_last_holdvalue)\n\t{\n\t\tm_last_hold_change = m_last_pulse = now;\n\t}\n\n\tif (repeat.pulse > 0)\n\t{\n\t\tif (m_last_hold_change + std::chrono::milliseconds(repeat.delay) >= now)\n\t\t{\n\t\t\tif ((m_last_pulse + std::chrono::milliseconds(repeat.pulse)) < now)\n\t\t\t{\n\t\t\t\tm_last_pulse = now;\n\t\t\t\tstatus.hold |= VPAD_REPEAT;\n\t\t\t}\n\t\t}\n\t}\n\n\t// general\n\tstatus.release = m_last_holdvalue & ~status.hold;\n\tstatus.trig = ~m_last_holdvalue & status.hold;\n\tm_last_holdvalue = status.hold;\n\n\t// touch\n\tupdate_touch(status);\n\n\t// motion\n\tstatus.dir.x = {1, 0, 0};\n\tstatus.dir.y = {0, 1, 0};\n\tstatus.dir.z = {0, 0, 1};\n\tstatus.accXY = {1.0f, 0.0f};\n\tupdate_motion(status);\n}\n\nvoid VPADController::update()\n{\n\tEmulatedController::update();\n\n\tif (!CafeSystem::IsTitleRunning())\n\t\treturn;\n\n\tstd::unique_lock lock(m_rumble_mutex);\n\tif (m_rumble_queue.empty())\n\t{\n\t\tm_parser = 0;\n\t\tlock.unlock();\n\n\t\tstop_rumble();\n\n\t\treturn;\n\t}\n\n\tconst auto tick = now_cached();\n\tif (std::chrono::duration_cast<std::chrono::milliseconds>(tick - m_last_rumble_check).count() < 1000 / 60)\n\t\treturn;\n\n\tm_last_rumble_check = tick;\n\n\tconst auto& it = m_rumble_queue.front();\n\tif (it[m_parser])\n\t\tstart_rumble();\n\telse\n\t\tstop_rumble();\n\n\t++m_parser;\n\tif (m_parser >= it.size())\n\t{\n\t\tm_rumble_queue.pop();\n\t\tm_parser = 0;\n\t}\n}\n\nvoid VPADController::update_touch(VPADStatus_t& status)\n{\n\tstatus.tpData.touch = kTpTouchOff;\n\tstatus.tpData.validity = kTpInvalid;\n\t// keep x,y from previous update\n\t// NGDK (Neko Game Development Kit 2) games (e.g. Mysterios Cities of Gold) rely on x/y remaining intact after touch is released\n\tstatus.tpData.x = (uint16)m_last_touch_position.x;\n\tstatus.tpData.y = (uint16)m_last_touch_position.y;\n\n\tauto& instance = InputManager::instance();\n\tbool pad_view;\n\tif (has_position())\n\t{\n\t\tconst auto mouse = get_position();\n\n\t\tstatus.tpData.touch = kTpTouchOn;\n\t\tstatus.tpData.validity = kTpValid;\n\t\tstatus.tpData.x = (uint16)(mouse.x * 3883.0f + 92.0f);\n\t\tstatus.tpData.y = (uint16)(4095.0f - mouse.y * 3694.0f - 254.0f);\n\n\t\tm_last_touch_position = glm::ivec2{status.tpData.x, status.tpData.y};\n\t}\n\telse if (const auto left_mouse = instance.get_left_down_mouse_info(&pad_view))\n\t{\n\t\tglm::ivec2 image_pos, image_size;\n\t\tLatteRenderTarget_getScreenImageArea(&image_pos.x, &image_pos.y, &image_size.x, &image_size.y, nullptr, nullptr, pad_view);\n\n\t\tglm::vec2 relative_mouse_pos = left_mouse.value() - image_pos;\n\t\trelative_mouse_pos = { std::min(relative_mouse_pos.x, (float)image_size.x), std::min(relative_mouse_pos.y, (float)image_size.y) };\n\t\trelative_mouse_pos = { std::max(relative_mouse_pos.x, 0.0f), std::max(relative_mouse_pos.y, 0.0f) };\n\t\trelative_mouse_pos /= image_size;\n\n\t\tstatus.tpData.touch = kTpTouchOn;\n\t\tstatus.tpData.validity = kTpValid;\n\t\tstatus.tpData.x = (uint16)((relative_mouse_pos.x * 3883.0f) + 92.0f);\n\t\tstatus.tpData.y = (uint16)(4095.0f - (relative_mouse_pos.y * 3694.0f) - 254.0f);\n\n\t\tm_last_touch_position = glm::ivec2{ status.tpData.x, status.tpData.y };\n\n\t\t/*cemuLog_log(LogType::Force, \"TDATA: {},{} -> {},{} -> {},{} -> {},{} -> {},{} -> {},{}\",\n\t\t\tleft_mouse->x, left_mouse->y,\n\t\t\t(left_mouse.value() - image_pos).x, (left_mouse.value() - image_pos).y,\n\t\t\trelative_mouse_pos.x, relative_mouse_pos.y,\n\t\t\t(uint16)(relative_mouse_pos.x * 3883.0 + 92.0), (uint16)(4095.0 - relative_mouse_pos.y * 3694.0 - 254.0),\n\t\t\tstatus.tpData.x.value(), status.tpData.y.value(), status.tpData.x.bevalue(), status.tpData.y.bevalue()\n\t\t);*/\n\t}\n\n\tstatus.tpProcessed1 = status.tpData;\n\tstatus.tpProcessed2 = status.tpData;\n}\n\nvoid VPADController::update_motion(VPADStatus_t& status)\n{\n\tif (has_motion())\n\t{\n\t\tauto motionSample = get_motion_data();\n\n\t\tglm::vec3 acc;\n\t\tmotionSample.getVPADAccelerometer(&acc[0]);\n\t\t//const auto& acc = motionSample.getVPADAccelerometer();\n\t\tstatus.acc.x = acc.x;\n\t\tstatus.acc.y = acc.y;\n\t\tstatus.acc.z = acc.z;\n\t\tstatus.accMagnitude = motionSample.getVPADAccMagnitude();\n\t\tstatus.accAcceleration = motionSample.getVPADAccAcceleration();\n\n\t\tglm::vec3 gyroChange;\n\t\tmotionSample.getVPADGyroChange(&gyroChange[0]);\n\t\t//const auto& gyroChange = motionSample.getVPADGyroChange();\n\t\tstatus.gyroChange.x = gyroChange.x;\n\t\tstatus.gyroChange.y = gyroChange.y;\n\t\tstatus.gyroChange.z = gyroChange.z;\n\n\t\t//debug_printf(\"GyroChange %7.2lf %7.2lf %7.2lf\\n\", (float)status.gyroChange.x, (float)status.gyroChange.y, (float)status.gyroChange.z);\n\n\t\tglm::vec3 gyroOrientation;\n\t\tmotionSample.getVPADOrientation(&gyroOrientation[0]);\n\t\t//const auto& gyroOrientation = motionSample.getVPADOrientation();\n\t\tstatus.gyroOrientation.x = gyroOrientation.x;\n\t\tstatus.gyroOrientation.y = gyroOrientation.y;\n\t\tstatus.gyroOrientation.z = gyroOrientation.z;\n\n\t\tfloat attitude[9];\n\t\tmotionSample.getVPADAttitudeMatrix(attitude);\n\t\tstatus.dir.x.x = attitude[0];\n\t\tstatus.dir.x.y = attitude[1];\n\t\tstatus.dir.x.z = attitude[2];\n\t\tstatus.dir.y.x = attitude[3];\n\t\tstatus.dir.y.y = attitude[4];\n\t\tstatus.dir.y.z = attitude[5];\n\t\tstatus.dir.z.x = attitude[6];\n\t\tstatus.dir.z.y = attitude[7];\n\t\tstatus.dir.z.z = attitude[8];\n\t\treturn;\n\t}\n\n\tbool pad_view;\n\tauto& input_manager = InputManager::instance();\n\tif (const auto right_mouse = input_manager.get_right_down_mouse_info(&pad_view))\n\t{\n\t\tconst Vector2<float> mousePos(right_mouse->x, right_mouse->y);\n\n\t\tint w, h;\n\t\tif (pad_view)\n\t\t\tWindowSystem::GetPadWindowPhysSize(w, h);\n\t\telse\n\t\t\tWindowSystem::GetWindowPhysSize(w, h);\n\n\t\tfloat wx = mousePos.x / w;\n\t\tfloat wy = mousePos.y / h;\n\n\t\tstatic glm::vec3 m_lastGyroRotation{}, m_startGyroRotation{};\n\t\tstatic bool m_startGyroRotationSet{};\n\n\t\tfloat rotX = (wy * 2 - 1.0f) * 135.0f; // up/down best\n\t\tfloat rotY = (wx * 2 - 1.0f) * -180.0f; // left/right\n\t\tfloat rotZ = input_manager.m_mouse_wheel * 14.0f + m_lastGyroRotation.z;\n\t\tinput_manager.m_mouse_wheel = 0.0f;\n\n\t\tif (!m_startGyroRotationSet)\n\t\t{\n\t\t\tm_startGyroRotation = {rotX, rotY, rotZ};\n\t\t\tm_startGyroRotationSet = true;\n\t\t}\n\n\t\t/*\tdebug_printf(\"\\n\\ngyro:\\n<%.02f, %.02f, %.02f>\\n\\n\",\n\t\t\t\trotX, rotY, rotZ);*/\n\n\t\tQuaternion<float> q(rotX, rotY, rotZ);\n\t\tauto rot = q.GetTransposedRotationMatrix();\n\n\t\t/*m_forward = std::get<0>(rot);\n\t\tm_right = std::get<1>(rot);\n\t\tm_up = std::get<2>(rot);*/\n\n\t\tstatus.dir.x = std::get<0>(rot);\n\t\tstatus.dir.y = std::get<1>(rot);\n\t\tstatus.dir.z = std::get<2>(rot);\n\n\t\t/*debug_printf(\"rot:\\n<%.02f, %.02f, %.02f>\\n<%.02f, %.02f, %.02f>\\n<%.02f, %.02f, %.02f>\\n\\n\",\n\t\t\t(float)status.dir.x.x, (float)status.dir.x.y, (float)status.dir.x.z,\n\t\t\t(float)status.dir.y.x, (float)status.dir.y.y, (float)status.dir.y.z,\n\t\t\t(float)status.dir.z.x, (float)status.dir.z.y, (float)status.dir.z.z);*/\n\n\t\tglm::vec3 rotation(rotX - m_lastGyroRotation.x, (rotY - m_lastGyroRotation.y) * 15.0f,\n\t\t                   rotZ - m_lastGyroRotation.z);\n\n\t\trotation.x = std::min(1.0f, std::max(-1.0f, rotation.x / 360.0f));\n\t\trotation.y = std::min(1.0f, std::max(-1.0f, rotation.y / 360.0f));\n\t\trotation.z = std::min(1.0f, std::max(-1.0f, rotation.z / 360.0f));\n\n\t\t/*debug_printf(\"\\n\\ngyro:\\n<%.02f, %.02f, %.02f>\\n\\n\",\n\t\t\trotation.x, rotation.y, rotation.z);*/\n\n\t\tconstexpr float pi2 = (float)(M_PI * 2);\n\t\tstatus.gyroChange = {rotation.x, rotation.y, rotation.z};\n\t\tstatus.gyroOrientation = {rotation.x, rotation.y, rotation.z};\n\t\t//status.angle = { rotation.x / pi2, rotation.y / pi2, rotation.z / pi2 };\n\n\t\tstatus.acc = {rotation.x, rotation.y, rotation.z};\n\t\tstatus.accAcceleration = 1.0f;\n\t\tstatus.accMagnitude = 1.0f;\n\n\t\tstatus.accXY = {1.0f, 0.0f};\n\n\t\tm_lastGyroRotation = {rotX, rotY, rotZ};\n\t}\n}\n\n\nstd::string_view VPADController::get_button_name(ButtonId id)\n{\n\tswitch (id)\n\t{\n\tcase kButtonId_A: return \"A\";\n\tcase kButtonId_B: return \"B\";\n\tcase kButtonId_X: return \"X\";\n\tcase kButtonId_Y: return \"Y\";\n\tcase kButtonId_L: return \"L\";\n\tcase kButtonId_R: return \"R\";\n\tcase kButtonId_ZL: return \"ZL\";\n\tcase kButtonId_ZR: return \"ZR\";\n\tcase kButtonId_Plus: return \"+\";\n\tcase kButtonId_Minus: return \"-\";\n\tcase kButtonId_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_Right: return TR_NOOP(\"right\");\n\tcase kButtonId_StickL: return TR_NOOP(\"click\");\n\tcase kButtonId_StickR: return TR_NOOP(\"click\");\n\tcase kButtonId_StickL_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_StickL_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_StickL_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_StickL_Right: return TR_NOOP(\"right\");\n\tcase kButtonId_StickR_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_StickR_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_StickR_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_StickR_Right: return TR_NOOP(\"right\");\n\tcase kButtonId_Home: return TR_NOOP(\"home\");\n\tdefault:\n\t\tcemu_assert_debug(false);\n\t\treturn \"\";\n\t}\n}\n\nvoid VPADController::clear_rumble()\n{\n\tstd::scoped_lock lock(m_rumble_mutex);\n\twhile (!m_rumble_queue.empty())\n\t\tm_rumble_queue.pop();\n\n\tm_parser = 0;\n}\n\nbool VPADController::push_rumble(uint8* pattern, uint8 length)\n{\n\tif (pattern == nullptr || length == 0)\n\t{\n\t\tclear_rumble();\n\t\treturn true;\n\t}\n\n\tstd::scoped_lock lock(m_rumble_mutex);\n\tif (m_rumble_queue.size() >= 5)\n\t{\n\t\tcemuLog_logDebugOnce(LogType::Force, \"VPADControlMotor(): Pattern too long\");\n\t\treturn false;\n\t}\n\n\t// len = max 15 bytes of data = 120 bits = 1 seconds\n\t// we will use 60 hz for 1 second\n\tstd::vector<bool> bitset;\n\tint byte = 0;\n\tint len = (int)length;\n\twhile (len > 0)\n\t{\n\t\tconst uint8 p = pattern[byte];\n\t\tfor (int j = 0; j < 8 && j < len; j += 2)\n\t\t{\n\t\t\tconst bool set = (p & (3 << j)) != 0;\n\t\t\tbitset.push_back(set);\n\t\t}\n\n\t\t++byte;\n\t\tlen -= 8;\n\t}\n\n\n\tm_rumble_queue.emplace(std::move(bitset));\n\tm_last_rumble_check = {};\n\n\treturn true;\n}\n\nuint32 VPADController::get_emulated_button_flag(uint32 id) const\n{\n\tswitch (id)\n\t{\n\tcase kButtonId_A: return VPAD_A;\n\tcase kButtonId_B: return VPAD_B;\n\tcase kButtonId_X: return VPAD_X;\n\tcase kButtonId_Y: return VPAD_Y;\n\tcase kButtonId_L: return VPAD_L;\n\tcase kButtonId_R: return VPAD_R;\n\tcase kButtonId_ZL: return VPAD_ZL;\n\tcase kButtonId_ZR: return VPAD_ZR;\n\tcase kButtonId_Plus: return VPAD_PLUS;\n\tcase kButtonId_Minus: return VPAD_MINUS;\n\tcase kButtonId_Up: return VPAD_UP;\n\tcase kButtonId_Down: return VPAD_DOWN;\n\tcase kButtonId_Left: return VPAD_LEFT;\n\tcase kButtonId_Right: return VPAD_RIGHT;\n\tcase kButtonId_StickL: return VPAD_STICK_L;\n\tcase kButtonId_StickR: return VPAD_STICK_R;\n\n\tcase kButtonId_StickL_Up: return VPAD_STICK_L_UP;\n\tcase kButtonId_StickL_Down: return VPAD_STICK_L_DOWN;\n\tcase kButtonId_StickL_Left: return VPAD_STICK_L_LEFT;\n\tcase kButtonId_StickL_Right: return VPAD_STICK_L_RIGHT;\n\n\tcase kButtonId_StickR_Up: return VPAD_STICK_R_UP;\n\tcase kButtonId_StickR_Down: return VPAD_STICK_R_DOWN;\n\tcase kButtonId_StickR_Left: return VPAD_STICK_R_LEFT;\n\tcase kButtonId_StickR_Right: return VPAD_STICK_R_RIGHT;\n\t}\n\treturn 0;\n}\n\nglm::vec2 VPADController::get_axis() const\n{\n\tconst auto left = get_axis_value(kButtonId_StickL_Left);\n\tconst auto right = get_axis_value(kButtonId_StickL_Right);\n\n\tconst auto up = get_axis_value(kButtonId_StickL_Up);\n\tconst auto down = get_axis_value(kButtonId_StickL_Down);\n\n\tglm::vec2 result;\n\tresult.x = (left > right) ? -left : right;\n\tresult.y = (up > down) ? up : -down;\n\treturn length(result) > 1.0f ? normalize(result) : result;\n}\n\nglm::vec2 VPADController::get_rotation() const\n{\n\tconst auto left = get_axis_value(kButtonId_StickR_Left);\n\tconst auto right = get_axis_value(kButtonId_StickR_Right);\n\n\tconst auto up = get_axis_value(kButtonId_StickR_Up);\n\tconst auto down = get_axis_value(kButtonId_StickR_Down);\n\n\tglm::vec2 result;\n\tresult.x = (left > right) ? -left : right;\n\tresult.y = (up > down) ? up : -down;\n\treturn length(result) > 1.0f ? normalize(result) : result;\n}\n\nglm::vec2 VPADController::get_trigger() const\n{\n\tconst auto left = get_axis_value(kButtonId_ZL);\n\tconst auto right = get_axis_value(kButtonId_ZR);\n\treturn {left, right};\n}\n\nbool VPADController::set_default_mapping(const std::shared_ptr<ControllerBase>& controller)\n{\n\tstd::vector<std::pair<uint64, uint64>> mapping;\n\tswitch (controller->api())\n\t{\n\tcase InputAPI::SDLController: {\n\t\tconst auto sdl_controller = std::static_pointer_cast<SDLController>(controller);\n\t\tif (sdl_controller->get_guid() == SDLController::kLeftJoyCon)\n\t\t{\n\t\t\tmapping =\n\t\t\t{\n\t\t\t\t{kButtonId_L, kButton9},\n\t\t\t\t{kButtonId_ZL, kTriggerXP},\n\n\t\t\t\t{kButtonId_Minus, kButton4},\n\n\t\t\t\t{kButtonId_Up, kButton11},\n\t\t\t\t{kButtonId_Down, kButton12},\n\t\t\t\t{kButtonId_Left, kButton13},\n\t\t\t\t{kButtonId_Right, kButton14},\n\n\t\t\t\t{kButtonId_StickL, kButton7},\n\n\t\t\t\t{kButtonId_StickL_Up, kAxisYN},\n\t\t\t\t{kButtonId_StickL_Down, kAxisYP},\n\t\t\t\t{kButtonId_StickL_Left, kAxisXN},\n\t\t\t\t{kButtonId_StickL_Right, kAxisXP},\n\n\t\t\t\t{kButtonId_Mic, kButton15},\n\t\t\t};\n\t\t}\n\t\telse if (sdl_controller->get_guid() == SDLController::kRightJoyCon)\n\t\t{\n\t\t\tmapping =\n\t\t\t{\n\t\t\t\t{kButtonId_A, kButton0},\n\t\t\t\t{kButtonId_B, kButton1},\n\t\t\t\t{kButtonId_X, kButton2},\n\t\t\t\t{kButtonId_Y, kButton3},\n\n\t\t\t\t{kButtonId_R, kButton10},\n\t\t\t\t{kButtonId_ZR, kTriggerYP},\n\n\t\t\t\t{kButtonId_Plus, kButton6},\n\n\t\t\t\t{kButtonId_StickR, kButton8},\n\n\t\t\t\t{kButtonId_StickR_Up, kRotationYN},\n\t\t\t\t{kButtonId_StickR_Down, kRotationYP},\n\t\t\t\t{kButtonId_StickR_Left, kRotationXN},\n\t\t\t\t{kButtonId_StickR_Right, kRotationXP},\n\t\t\t};\n\t\t}\n\t\telse if (sdl_controller->get_guid() == SDLController::kSwitchProController)\n\t\t{\n\t\t\t// Switch Pro Controller is similar to default mapping, but with a/b and x/y swapped\n\t\t\tmapping =\n\t\t\t{\n\t\t\t\t{kButtonId_A, kButton0},\n\t\t\t\t{kButtonId_B, kButton1},\n\t\t\t\t{kButtonId_X, kButton2},\n\t\t\t\t{kButtonId_Y, kButton3},\n\n\t\t\t\t{kButtonId_L, kButton9},\n\t\t\t\t{kButtonId_R, kButton10},\n\t\t\t\t{kButtonId_ZL, kTriggerXP},\n\t\t\t\t{kButtonId_ZR, kTriggerYP},\n\n\t\t\t\t{kButtonId_Plus, kButton6},\n\t\t\t\t{kButtonId_Minus, kButton4},\n\n\t\t\t\t{kButtonId_Up, kButton11},\n\t\t\t\t{kButtonId_Down, kButton12},\n\t\t\t\t{kButtonId_Left, kButton13},\n\t\t\t\t{kButtonId_Right, kButton14},\n\n\t\t\t\t{kButtonId_StickL, kButton7},\n\t\t\t\t{kButtonId_StickR, kButton8},\n\n\t\t\t\t{kButtonId_StickL_Up, kAxisYN},\n\t\t\t\t{kButtonId_StickL_Down, kAxisYP},\n\t\t\t\t{kButtonId_StickL_Left, kAxisXN},\n\t\t\t\t{kButtonId_StickL_Right, kAxisXP},\n\n\t\t\t\t{kButtonId_StickR_Up, kRotationYN},\n\t\t\t\t{kButtonId_StickR_Down, kRotationYP},\n\t\t\t\t{kButtonId_StickR_Left, kRotationXN},\n\t\t\t\t{kButtonId_StickR_Right, kRotationXP},\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\tmapping =\n\t\t\t{\n\t\t\t\t{kButtonId_A, kButton1},\n\t\t\t\t{kButtonId_B, kButton0},\n\t\t\t\t{kButtonId_X, kButton3},\n\t\t\t\t{kButtonId_Y, kButton2},\n\n\t\t\t\t{kButtonId_L, kButton9},\n\t\t\t\t{kButtonId_R, kButton10},\n\t\t\t\t{kButtonId_ZL, kTriggerXP},\n\t\t\t\t{kButtonId_ZR, kTriggerYP},\n\n\t\t\t\t{kButtonId_Plus, kButton6},\n\t\t\t\t{kButtonId_Minus, kButton4},\n\n\t\t\t\t{kButtonId_Up, kButton11},\n\t\t\t\t{kButtonId_Down, kButton12},\n\t\t\t\t{kButtonId_Left, kButton13},\n\t\t\t\t{kButtonId_Right, kButton14},\n\n\t\t\t\t{kButtonId_StickL, kButton7},\n\t\t\t\t{kButtonId_StickR, kButton8},\n\n\t\t\t\t{kButtonId_StickL_Up, kAxisYN},\n\t\t\t\t{kButtonId_StickL_Down, kAxisYP},\n\t\t\t\t{kButtonId_StickL_Left, kAxisXN},\n\t\t\t\t{kButtonId_StickL_Right, kAxisXP},\n\n\t\t\t\t{kButtonId_StickR_Up, kRotationYN},\n\t\t\t\t{kButtonId_StickR_Down, kRotationYP},\n\t\t\t\t{kButtonId_StickR_Left, kRotationXN},\n\t\t\t\t{kButtonId_StickR_Right, kRotationXP},\n\t\t\t};\n\t\t}\n\t\tbreak;\n\t}\n\tcase InputAPI::XInput:\n\t{\n\t\tmapping =\n\t\t{\n\t\t\t{kButtonId_A, kButton13},\n\t\t\t{kButtonId_B, kButton12},\n\t\t\t{kButtonId_X, kButton15},\n\t\t\t{kButtonId_Y, kButton14},\n\n\t\t\t{kButtonId_L, kButton8},\n\t\t\t{kButtonId_R, kButton9},\n\t\t\t{kButtonId_ZL, kTriggerXP},\n\t\t\t{kButtonId_ZR, kTriggerYP},\n\n\t\t\t{kButtonId_Plus, kButton4},\n\t\t\t{kButtonId_Minus, kButton5},\n\n\t\t\t{kButtonId_Up, kButton0},\n\t\t\t{kButtonId_Down, kButton1},\n\t\t\t{kButtonId_Left, kButton2},\n\t\t\t{kButtonId_Right, kButton3},\n\n\t\t\t{kButtonId_StickL, kButton6},\n\t\t\t{kButtonId_StickR, kButton7},\n\n\t\t\t{kButtonId_StickL_Up, kAxisYP},\n\t\t\t{kButtonId_StickL_Down, kAxisYN},\n\t\t\t{kButtonId_StickL_Left, kAxisXN},\n\t\t\t{kButtonId_StickL_Right, kAxisXP},\n\n\t\t\t{kButtonId_StickR_Up, kRotationYP},\n\t\t\t{kButtonId_StickR_Down, kRotationYN},\n\t\t\t{kButtonId_StickR_Left, kRotationXN},\n\t\t\t{kButtonId_StickR_Right, kRotationXP},\n\t\t};\n\t\t\n\t\tbreak;\n\t}\n\t}\n\n\tbool mapping_updated = false;\n\tstd::for_each(mapping.cbegin(), mapping.cend(), [this, &controller, &mapping_updated](const auto& m)\n\t\t{\n\t\t\tif (m_mappings.find(m.first) == m_mappings.cend())\n\t\t\t{\n\t\t\t\tset_mapping(m.first, controller, m.second);\n\t\t\t\tmapping_updated = true;\n\t\t\t}\n\t\t});\n\n\treturn mapping_updated;\n}\n\nvoid VPADController::load(const pugi::xml_node& node)\n{\n\tif (const auto value = node.child(\"toggle_display\"))\n\t\tm_screen_active_toggle = ConvertString<bool>(value.child_value());\n}\n\nvoid VPADController::save(pugi::xml_node& node)\n{\n\tnode.append_child(\"toggle_display\").append_child(pugi::node_pcdata).set_value(fmt::format(\"{}\", (int)m_screen_active_toggle).c_str());\n}\n"
  },
  {
    "path": "src/input/emulated/VPADController.h",
    "content": "#pragma once\n\n#include \"input/emulated/EmulatedController.h\"\n#include \"Cafe/OS/libs/vpad/vpad.h\"\n\n\nclass VPADController : public EmulatedController\n{\npublic:\n\tenum ButtonId\n\t{\n\t\tkButtonId_None,\n\n\t\tkButtonId_A,\n\t\tkButtonId_B,\n\t\tkButtonId_X,\n\t\tkButtonId_Y,\n\n\t\tkButtonId_L,\n\t\tkButtonId_R,\n\t\tkButtonId_ZL,\n\t\tkButtonId_ZR,\n\n\t\tkButtonId_Plus,\n\t\tkButtonId_Minus,\n\n\t\tkButtonId_Up,\n\t\tkButtonId_Down,\n\t\tkButtonId_Left,\n\t\tkButtonId_Right,\n\n\t\tkButtonId_StickL,\n\t\tkButtonId_StickR,\n\n\t\tkButtonId_StickL_Up,\n\t\tkButtonId_StickL_Down,\n\t\tkButtonId_StickL_Left,\n\t\tkButtonId_StickL_Right,\n\n\t\tkButtonId_StickR_Up,\n\t\tkButtonId_StickR_Down,\n\t\tkButtonId_StickR_Left,\n\t\tkButtonId_StickR_Right,\n\n\t\tkButtonId_Mic,\n\t\tkButtonId_Screen,\n\n\t\tkButtonId_Home,\n\n\t\tkButtonId_Max,\n\t};\n\n\tusing EmulatedController::EmulatedController;\n\n\tType type() const override { return VPAD; }\n\n\tvoid VPADRead(VPADStatus_t& status, const BtnRepeat& repeat);\n\n\tvoid update() override;\n\n\tuint32 get_emulated_button_flag(uint32 id) const override;\n\n\tglm::vec2 get_axis() const override;\n\tglm::vec2 get_rotation() const override;\n\tglm::vec2 get_trigger() const override;\n\n\tbool is_mic_active() { return m_mic_active; }\n\tbool is_screen_active() { return m_screen_active; }\n\tbool is_screen_active_toggle() { return m_screen_active_toggle; }\n\tvoid set_screen_toggle(bool toggle) {m_screen_active_toggle = toggle;}\n\n\tstatic std::string_view get_button_name(ButtonId id);\n\n\tvoid clear_rumble();\n\tbool push_rumble(uint8* pattern, uint8 length);\n\n\tsize_t get_highest_mapping_id() const override { return kButtonId_Max; }\n\tbool is_axis_mapping(uint64 mapping) const override { return mapping >= kButtonId_StickL_Up && mapping <= kButtonId_StickR_Right; }\n\n\tbool is_start_down() const override { return is_mapping_down(kButtonId_Plus); }\n\tbool is_left_down() const override { return is_mapping_down(kButtonId_Left); }\n\tbool is_right_down() const override { return is_mapping_down(kButtonId_Right); }\n\tbool is_up_down() const override { return is_mapping_down(kButtonId_Up); }\n\tbool is_down_down() const override { return is_mapping_down(kButtonId_Down); }\n\tbool is_a_down() const override { return is_mapping_down(kButtonId_A); }\n\tbool is_b_down() const override { return is_mapping_down(kButtonId_B); }\n\tbool is_home_down() const override { return is_mapping_down(kButtonId_Home); }\n\n\tbool set_default_mapping(const std::shared_ptr<ControllerBase>& controller) override;\n\n\tvoid load(const pugi::xml_node& node) override;\n\tvoid save(pugi::xml_node& node) override;\n\nprivate:\n\tbool m_mic_active = false;\n\tbool m_screen_active = false;\n\tbool m_screen_active_toggle = false;\n\tuint32be m_last_holdvalue = 0;\n\n\tstd::chrono::high_resolution_clock::time_point m_last_hold_change{}, m_last_pulse{};\n\n\tstd::mutex m_rumble_mutex;\n\tstd::chrono::high_resolution_clock::time_point m_last_rumble_check{};\n\tstd::queue<std::vector<bool>> m_rumble_queue;\n\tuint8 m_parser = 0;\n\n\tvoid update_touch(VPADStatus_t& status);\n\tvoid update_motion(VPADStatus_t& status);\n\tglm::ivec2 m_last_touch_position{};\n};\n"
  },
  {
    "path": "src/input/emulated/WPADController.cpp",
    "content": "#include <api/Controller.h>\n#include \"input/emulated/WPADController.h\"\n\n#include \"input/emulated/ClassicController.h\"\n#include \"input/emulated/ProController.h\"\n#include \"input/emulated/WiimoteController.h\"\n\nWPADController::WPADController(size_t player_index, WPADDataFormat data_format)\n\t: EmulatedController(player_index), m_data_format(data_format)\n{\n}\n\nWPADDataFormat WPADController::get_default_data_format() const\n{\n\tswitch (get_device_type())\n\t{\n\tcase kWAPDevCore:\n\t\treturn kDataFormat_CORE_ACC_DPD;\n\tcase kWAPDevFreestyle:\n\t\treturn kDataFormat_FREESTYLE_ACC;\n\tcase kWAPDevClassic:\n\t\treturn kDataFormat_CLASSIC;\n\tcase kWAPDevMPLS:\n\t\treturn kDataFormat_MPLS;\n\tcase kWAPDevMPLSFreeStyle:\n\t\treturn kDataFormat_FREESTYLE_ACC_DPD;\n\tcase kWAPDevMPLSClassic:\n\t\treturn kDataFormat_CLASSIC_ACC_DPD;\n\tcase kWAPDevURCC:\n\t\treturn kDataFormat_URCC;\n\tdefault:\n\t\treturn kDataFormat_CORE;\n\t}\n}\n\nuint32 WPADController::get_emulated_button_flag(WPADDataFormat format, uint32 id) const\n{\n\tswitch(format)\n\t{\n\tcase kDataFormat_CORE:\n\tcase kDataFormat_CORE_ACC:\n\tcase kDataFormat_CORE_ACC_DPD:\n\tcase kDataFormat_CORE_ACC_DPD_FULL:\n\tcase kDataFormat_FREESTYLE:\n\tcase kDataFormat_FREESTYLE_ACC:\n\tcase kDataFormat_FREESTYLE_ACC_DPD:\n\tcase kDataFormat_MPLS:\n\t\treturn WiimoteController::s_get_emulated_button_flag(id);\n\tcase kDataFormat_CLASSIC:\n\tcase kDataFormat_CLASSIC_ACC:\n\tcase kDataFormat_CLASSIC_ACC_DPD:\n\t\treturn ClassicController::s_get_emulated_button_flag(id);\n\t\n\tcase kDataFormat_TRAIN: break;\n\tcase kDataFormat_GUITAR: break;\n\tcase kDataFormat_BALANCE_CHECKER: break;\n\tcase kDataFormat_DRUM: break;\n\t\n\tcase kDataFormat_TAIKO: break;\n\tcase kDataFormat_URCC:\n\t\treturn ProController::s_get_emulated_button_flag(id);\n\n\t}\n\n\treturn 0;\n}\n\nvoid WPADController::WPADRead(WPADStatus_t* status)\n{\n\tcontrollers_update_states();\n\tuint32 button = 0;\n\tfor (uint32 i = 1; i < get_highest_mapping_id(); ++i)\n\t{\n\t\tif (is_mapping_down(i))\n\t\t{\n\t\t\tconst uint32 value = get_emulated_button_flag(m_data_format, i);\n\t\t\tbutton |= value;\n\t\t}\n\t}\n\n\tm_homebutton_down |= is_home_down();\n\n\t// todo fill position api from wiimote\n\n\tswitch (m_data_format)\n\t{\n\tcase kDataFormat_CORE:\n\tcase kDataFormat_CORE_ACC:\n\tcase kDataFormat_CORE_ACC_DPD:\n\tcase kDataFormat_CORE_ACC_DPD_FULL:\n\t{\n\t\tmemset(status, 0x00, sizeof(*status));\n\t\tstatus->button = button;\n\t\tbreak;\n\t}\n\n\tcase kDataFormat_FREESTYLE:\n\tcase kDataFormat_FREESTYLE_ACC:\n\tcase kDataFormat_FREESTYLE_ACC_DPD:\n\t{\n\t\tWPADFSStatus_t* ex_status = (WPADFSStatus_t*)status;\n\t\tmemset(ex_status, 0x00, sizeof(*ex_status));\n\t\tex_status->button = button;\n\n\t\tauto axis = get_axis();\n\t\taxis *= 127.0f;\n\t\tex_status->fsStickX = (sint8)axis.x;\n\t\tex_status->fsStickY = (sint8)axis.y;\n\t\tbreak;\n\t}\n\n\tcase kDataFormat_CLASSIC:\n\tcase kDataFormat_CLASSIC_ACC:\n\tcase kDataFormat_CLASSIC_ACC_DPD:\n\tcase kDataFormat_GUITAR:\n\tcase kDataFormat_DRUM:\n\tcase kDataFormat_TAIKO:\n\t{\n\t\tWPADCLStatus_t* ex_status = (WPADCLStatus_t*)status;\n\t\tmemset(ex_status, 0x00, sizeof(*ex_status));\n\t\tex_status->clButton = button;\n\t\t\n\t\tauto axis = get_axis();\n\t\taxis *= 2048.0f;\n\t\tex_status->clLStickX = (uint16)axis.x;\n\t\tex_status->clLStickY = (uint16)axis.y;\n\n\t\tauto rotation = get_rotation();\n\t\trotation *= 2048.0f;\n\t\tex_status->clRStickX = (uint16)rotation.x;\n\t\tex_status->clRStickY = (uint16)rotation.y;\n\t\tbreak;\n\t}\n\tcase kDataFormat_TRAIN:\n\t{\n\t\tWPADTRStatus_t* ex_status = (WPADTRStatus_t*)status;\n\t\t// TODO\n\t\tbreak;\n\t}\n\tcase kDataFormat_BALANCE_CHECKER:\n\t{\n\t\tWPADBLStatus_t* ex_status = (WPADBLStatus_t*)status;\n\t\t// TODO\n\t\tbreak;\n\t}\n\tcase kDataFormat_MPLS:\n\t{\n\t\tWPADMPStatus_t* ex_status = (WPADMPStatus_t*)status;\n\t\tex_status->stat = 1; // attached\n\t\t// TODO\n\t\tbreak;\n\t}\n\tcase kDataFormat_URCC:\n\t{\n\t\tWPADUCStatus_t* ex_status = (WPADUCStatus_t*)status;\n\t\tmemset(ex_status, 0x00, sizeof(*ex_status));\n\t\tex_status->ucButton = button;\n\n\t\tex_status->cable = TRUE;\n\t\tex_status->charge = TRUE;\n\n\t\tauto axis = get_axis();\n\t\taxis *= 2048.0f;\n\t\tex_status->ucLStickX = (uint16)axis.x;\n\t\tex_status->ucLStickY = (uint16)axis.y;\n\n\t\tauto rotation = get_rotation();\n\t\trotation *= 2048.0f;\n\t\tex_status->ucRStickX = (uint16)rotation.x;\n\t\tex_status->ucRStickY = (uint16)rotation.y;\n\n\t\tbreak;\n\t}\n\tdefault:\n\t\tcemu_assert(false);\n\t}\n\n\tstatus->dev = get_device_type();\n\tstatus->err = WPAD_ERR_NONE;\n}\n\nvoid WPADController::KPADRead(KPADStatus_t& status, const BtnRepeat& repeat)\n{\n\tuint32be* hold, *release, *trigger;\n\tswitch (type())\n\t{\n\tcase Pro:\n\t\thold = &status.ex_status.uc.hold;\n\t\trelease = &status.ex_status.uc.release;\n\t\ttrigger = &status.ex_status.uc.trig;\n\t\tbreak;\n\tcase Classic:\n\t\thold = &status.ex_status.cl.hold;\n\t\trelease = &status.ex_status.cl.release;\n\t\ttrigger = &status.ex_status.cl.trig;\n\t\tbreak;\n\tdefault:\n\t\thold = &status.hold;\n\t\trelease = &status.release;\n\t\ttrigger = &status.trig;\n\t}\n\n\tcontrollers_update_states();\n\tfor (uint32 i = 1; i < get_highest_mapping_id(); ++i)\n\t{\n\t\tif (is_mapping_down(i))\n\t\t{\n\t\t\tconst uint32 value = get_emulated_button_flag(m_data_format, i);\n\t\t\t*hold |= value;\n\t\t}\n\t}\n\n\tm_homebutton_down |= is_home_down();\n\t\n\t// button repeat\n\tconst auto now = std::chrono::steady_clock::now();\n\tif (*hold != m_last_holdvalue)\n\t{\n\t\tm_last_hold_change = m_last_pulse = now;\n\t}\n\n\tif (repeat.pulse > 0)\n\t{\n\t\tif (m_last_hold_change + std::chrono::milliseconds(repeat.delay) >= now)\n\t\t{\n\t\t\tif ((m_last_pulse + std::chrono::milliseconds(repeat.pulse)) < now)\n\t\t\t{\n\t\t\t\tm_last_pulse = now;\n\t\t\t\t*hold |= kWPADButtonRepeat;\n\t\t\t}\n\t\t}\n\t}\n\n\t// axis\n\tconst auto axis = get_axis();\n\tconst auto rotation = get_rotation();\n\n\t*release = m_last_holdvalue & ~*hold;\n\t//status.release = m_last_holdvalue & ~*hold;\n\t*trigger = ~m_last_holdvalue & *hold;\n\t//status.trig = ~m_last_holdvalue & *hold;\n\tm_last_holdvalue = *hold;\n\n\tif (is_mpls_attached())\n\t{\n\t\tstatus.mpls.dir.X.x = 1;\n\t\tstatus.mpls.dir.X.y = 0;\n\t\tstatus.mpls.dir.X.z = 0;\n\n\t\tstatus.mpls.dir.Y.x = 0;\n\t\tstatus.mpls.dir.Y.y = 1;\n\t\tstatus.mpls.dir.Y.z = 0;\n\n\t\tstatus.mpls.dir.Z.x = 0;\n\t\tstatus.mpls.dir.Z.y = 0;\n\t\tstatus.mpls.dir.Z.z = 1;\n\t}\n\n\tif (has_motion())\n\t{\n\t\tauto motion_sample = get_motion_data();\n\n\t\tglm::vec3 acc;\n\t\tmotion_sample.getAccelerometer(&acc[0]);\n\t\tstatus.acc.x = acc.x;\n\t\tstatus.acc.y = acc.y;\n\t\tstatus.acc.z = acc.z;\n\n\t\tstatus.acc_value = motion_sample.getVPADAccMagnitude();\n\t\tstatus.acc_speed = motion_sample.getVPADAccAcceleration();\n\n\t\t//glm::vec2 acc_vert;\n\t\t//motion_sample.getVPADAccXY(&acc_vert[0]);\n\t\t//status.acc_vertical.x = acc_vert.x;\n\t\t//status.acc_vertical.y = acc_vert.y;\n\n\t\tstatus.accVertical.x = std::min(1.0f, std::abs(acc.x + acc.y));\n\t\tstatus.accVertical.y = std::min(std::max(-1.0f, -acc.z), 1.0f);\n\n\t\tif (is_mpls_attached())\n\t\t{\n\t\t\t// todo\n\t\t\tglm::vec3 gyroChange;\n\t\t\tmotion_sample.getVPADGyroChange(&gyroChange[0]);\n\t\t\t//const auto& gyroChange = motionSample.getVPADGyroChange();\n\t\t\tstatus.mpls.mpls.x = gyroChange.x;\n\t\t\tstatus.mpls.mpls.y = gyroChange.y;\n\t\t\tstatus.mpls.mpls.z = gyroChange.z;\n\n\t\t\t//debug_printf(\"GyroChange %7.2lf %7.2lf %7.2lf\\n\", (float)status.gyroChange.x, (float)status.gyroChange.y, (float)status.gyroChange.z);\n\n\t\t\tglm::vec3 gyroOrientation;\n\t\t\tmotion_sample.getVPADOrientation(&gyroOrientation[0]);\n\t\t\t//const auto& gyroOrientation = motionSample.getVPADOrientation();\n\t\t\tstatus.mpls.angle.x = gyroOrientation.x;\n\t\t\tstatus.mpls.angle.y = gyroOrientation.y;\n\t\t\tstatus.mpls.angle.z = gyroOrientation.z;\n\n\t\t\tfloat attitude[9];\n\t\t\tmotion_sample.getVPADAttitudeMatrix(attitude);\n\t\t\tstatus.mpls.dir.X.x = attitude[0];\n\t\t\tstatus.mpls.dir.X.y = attitude[1];\n\t\t\tstatus.mpls.dir.X.z = attitude[2];\n\t\t\tstatus.mpls.dir.Y.x = attitude[3];\n\t\t\tstatus.mpls.dir.Y.y = attitude[4];\n\t\t\tstatus.mpls.dir.Y.z = attitude[5];\n\t\t\tstatus.mpls.dir.Z.x = attitude[6];\n\t\t\tstatus.mpls.dir.Z.y = attitude[7];\n\t\t\tstatus.mpls.dir.Z.z = attitude[8];\n\t\t}\n\t}\n\tauto visibility = GetPositionVisibility();\n\tif (has_position() && visibility != PositionVisibility::NONE)\n\t{\n\t\tif (visibility == PositionVisibility::FULL)\n\t\t\tstatus.dpd_valid_fg = 2;\n\t\telse\n\t\t\tstatus.dpd_valid_fg = -1;\n\n\t\tconst auto position = get_position();\n\n\t\tconst auto pos = (position * 2.0f) - 1.0f;\n\t\tstatus.pos.x = pos.x;\n\t\tstatus.pos.y = pos.y;\n\n\t\tconst auto delta = position - get_prev_position();\n\t\tstatus.vec.x = delta.x;\n\t\tstatus.vec.y = delta.y;\n\t\tstatus.speed = glm::length(delta);\n\t}\n\telse\n\t\tstatus.dpd_valid_fg = 0;\n\n\tswitch (type())\n\t{\n\tcase Wiimote:\n\t\tstatus.ex_status.fs.stick.x = axis.x;\n\t\tstatus.ex_status.fs.stick.y = axis.y;\n\n\t\tif(has_second_motion())\n\t\t{\n\t\t\tauto motion_sample = get_second_motion_data();\n\n\t\t\tglm::vec3 acc;\n\t\t\tmotion_sample.getAccelerometer(&acc[0]);\n\t\t\tstatus.ex_status.fs.acc.x = acc.x;\n\t\t\tstatus.ex_status.fs.acc.y = acc.y;\n\t\t\tstatus.ex_status.fs.acc.z = acc.z;\n\n\t\t\tstatus.ex_status.fs.accValue = motion_sample.getVPADAccMagnitude();\n\t\t\tstatus.ex_status.fs.accSpeed = motion_sample.getVPADAccAcceleration();\n\t\t}\n\n\t\tbreak;\n\tcase Pro:\n\t\tstatus.ex_status.uc.lstick.x = axis.x;\n\t\tstatus.ex_status.uc.lstick.y = axis.y;\n\n\t\tstatus.ex_status.uc.rstick.x = rotation.x;\n\t\tstatus.ex_status.uc.rstick.y = rotation.y;\n\n\t\tstatus.ex_status.uc.charge = FALSE;\n\t\tstatus.ex_status.uc.cable = TRUE;\n\n\t\tbreak;\n\tcase Classic:\n\t\tstatus.ex_status.cl.lstick.x = axis.x;\n\t\tstatus.ex_status.cl.lstick.y = axis.y;\n\n\t\tstatus.ex_status.cl.rstick.x = rotation.x;\n\t\tstatus.ex_status.cl.rstick.y = rotation.y;\n\n\t\tif (HAS_FLAG((uint32)status.ex_status.cl.hold, kCLButton_ZL))\n\t\t\tstatus.ex_status.cl.ltrigger = 1.0f;\n\n\t\tif (HAS_FLAG((uint32)status.ex_status.cl.hold, kCLButton_ZR))\n\t\t\tstatus.ex_status.cl.rtrigger = 1.0f;\n\t\tbreak;\n\tdefault:\n\t\tcemu_assert(false);\n\t}\n\n\t\n}\n"
  },
  {
    "path": "src/input/emulated/WPADController.h",
    "content": "#pragma once\n\n#include \"input/emulated/EmulatedController.h\"\n#include \"Cafe/OS/libs/padscore/padscore.h\"\n#include \"Cafe/OS/libs/vpad/vpad.h\"\n\nconstexpr uint32 kWPADButtonRepeat = 0x80000000;\n\nenum WPADDeviceType\n{\n\tkWAPDevCore = 0,\n\tkWAPDevFreestyle = 1,\n\tkWAPDevClassic = 2,\n\tkWAPDevMPLS = 5,\n\tkWAPDevMPLSFreeStyle = 6,\n\tkWAPDevMPLSClassic = 7,\n\tkWAPDevURCC = 31,\n\tkWAPDevNotFound = 253,\n\tkWAPDevUnknown = 255,\n};\n\n// core, balanceboard\nenum WPADCoreButtons\n{\n\tkWPADButton_Left = 0x1,\n\tkWPADButton_Right = 0x2,\n\tkWPADButton_Down = 0x4,\n\tkWPADButton_Up = 0x8,\n\tkWPADButton_Plus = 0x10,\n\tkWPADButton_2 = 0x100,\n\tkWPADButton_1 = 0x200,\n\tkWPADButton_B = 0x400,\n\tkWPADButton_A = 0x800,\n\tkWPADButton_Minus = 0x1000,\n\tkWPADButton_Home = 0x8000,\n};\n\n// Nunchuck aka Freestyle\nenum WPADNunchuckButtons\n{\n\tkWPADButton_Z = 0x2000,\n\tkWPADButton_C = 0x4000,\n};\n\n// Classic Controller\nenum WPADClassicButtons\n{\n\tkCLButton_Up = 0x1,\n\tkCLButton_Left = 0x2,\n\tkCLButton_ZR = 0x4,\n\tkCLButton_X = 0x8,\n\tkCLButton_A = 0x10,\n\tkCLButton_Y = 0x20,\n\tkCLButton_B = 0x40,\n\tkCLButton_ZL = 0x80,\n\tkCLButton_R = 0x200,\n\tkCLButton_Plus = 0x400,\n\tkCLButton_Home = 0x800,\n\tkCLButton_Minus = 0x1000,\n\tkCLButton_L = 0x2000,\n\tkCLButton_Down = 0x4000,\n\tkCLButton_Right = 0x8000\n};\n\n// Pro Controller aka URCC\nenum WPADProButtons\n{\n\tkProButton_Up = 0x1,\n\tkProButton_Left = 0x2,\n\tkProButton_ZR = 0x4,\n\tkProButton_X = 0x8,\n\tkProButton_A = 0x10,\n\tkProButton_Y = 0x20,\n\tkProButton_B = 0x40,\n\tkProButton_ZL = 0x80,\n\tkProButton_R = 0x200,\n\tkProButton_Plus = 0x400,\n\tkProButton_Home = 0x800,\n\tkProButton_Minus = 0x1000,\n\tkProButton_L = 0x2000,\n\tkProButton_Down = 0x4000,\n\tkProButton_Right = 0x8000,\n\tkProButton_StickR = 0x10000,\n\tkProButton_StickL = 0x20000\n};\n\nenum WPADDataFormat {\n\t kDataFormat_CORE = 0,\n\t kDataFormat_CORE_ACC = 1,\n\t kDataFormat_CORE_ACC_DPD = 2,\n\t kDataFormat_FREESTYLE = 3,\n\t kDataFormat_FREESTYLE_ACC = 4,\n\t kDataFormat_FREESTYLE_ACC_DPD = 5,\n\t kDataFormat_CLASSIC = 6,\n\t kDataFormat_CLASSIC_ACC = 7,\n\t kDataFormat_CLASSIC_ACC_DPD = 8,\n\t kDataFormat_CORE_ACC_DPD_FULL = 9, // buttons, motion, pointing\n\t kDataFormat_TRAIN = 10,\n\t kDataFormat_GUITAR = 11,\n\t kDataFormat_BALANCE_CHECKER = 12,\n\t kDataFormat_DRUM = 15,\n\t kDataFormat_MPLS = 16, // buttons, motion, pointing, motion plus\n\t kDataFormat_TAIKO = 17,\n\t kDataFormat_URCC = 22, // buttons, URCC aka pro\n};\n\nclass WPADController : public EmulatedController\n{\n\tusing base_type = EmulatedController;\npublic:\n\tWPADController(size_t player_index, WPADDataFormat data_format);\n\n\tuint32 get_emulated_button_flag(WPADDataFormat format, uint32 id) const;\n\n\tvirtual WPADDeviceType get_device_type() const = 0;\n\n\tWPADDataFormat get_data_format() const { return m_data_format; }\n\tvoid set_data_format(WPADDataFormat data_format) { m_data_format = data_format; }\n\n\tvoid WPADRead(WPADStatus_t* status);\n\n\tvoid KPADRead(KPADStatus_t& status, const BtnRepeat& repeat);\n\tvirtual bool is_mpls_attached() { return false; }\n\n\tenum class ConnectCallbackStatus\n\t{\n\t\tNone, // do nothing\n\t\tReportDisconnect, // call disconnect\n\t\tReportConnect, // call connect\n\t};\n\tConnectCallbackStatus m_status = ConnectCallbackStatus::ReportConnect;\n\tConnectCallbackStatus m_extension_status = ConnectCallbackStatus::ReportConnect;\n\n\tWPADDataFormat get_default_data_format() const;\n\nprotected:\n\tWPADDataFormat m_data_format;\n\nprivate:\n\tuint32be m_last_holdvalue = 0;\n\n\tstd::chrono::steady_clock::time_point m_last_hold_change{}, m_last_pulse{};\n\n\t\n};\n"
  },
  {
    "path": "src/input/emulated/WiimoteController.cpp",
    "content": "#include \"input/emulated/WiimoteController.h\"\n\n#include \"input/api/Controller.h\"\n#include \"input/api/Wiimote/NativeWiimoteController.h\"\n\nWiimoteController::WiimoteController(size_t player_index)\n\t: WPADController(player_index, kDataFormat_CORE_ACC_DPD)\n{\n}\n\nvoid WiimoteController::set_device_type(WPADDeviceType device_type)\n{\n\tm_device_type = device_type;\n\tm_data_format = get_default_data_format();\n}\n\nbool WiimoteController::is_mpls_attached()\n{\n\treturn m_device_type == kWAPDevMPLS || m_device_type == kWAPDevMPLSClassic || m_device_type == kWAPDevMPLSFreeStyle;\n}\n\nuint32 WiimoteController::get_emulated_button_flag(uint32 id) const\n{\n\treturn s_get_emulated_button_flag(id);\n}\n\nbool WiimoteController::set_default_mapping(const std::shared_ptr<ControllerBase>& controller)\n{\n\tstd::vector<std::pair<uint64, uint64>> mapping;\n\tswitch (controller->api())\n\t{\n\tcase InputAPI::Wiimote: {\n\t\tconst auto sdl_controller = std::static_pointer_cast<NativeWiimoteController>(controller);\n\t\tmapping =\n\t\t{\n\t\t\t{kButtonId_A, kWiimoteButton_A},\n\t\t\t{kButtonId_B, kWiimoteButton_B},\n\t\t\t{kButtonId_1, kWiimoteButton_One},\n\t\t\t{kButtonId_2, kWiimoteButton_Two},\n\n\t\t\t{kButtonId_Home, kWiimoteButton_Home},\n\n\t\t\t{kButtonId_Plus, kWiimoteButton_Plus},\n\t\t\t{kButtonId_Minus, kWiimoteButton_Minus},\n\n\t\t\t{kButtonId_Up, kWiimoteButton_Up},\n\t\t\t{kButtonId_Down, kWiimoteButton_Down},\n\t\t\t{kButtonId_Left, kWiimoteButton_Left},\n\t\t\t{kButtonId_Right, kWiimoteButton_Right},\n\n\t\t\t{kButtonId_Nunchuck_Z, kWiimoteButton_Z},\n\t\t\t{kButtonId_Nunchuck_C, kWiimoteButton_C},\n\n\t\t\t{kButtonId_Nunchuck_Up, kAxisYP},\n\t\t\t{kButtonId_Nunchuck_Down, kAxisYN},\n\t\t\t{kButtonId_Nunchuck_Left, kAxisXN},\n\t\t\t{kButtonId_Nunchuck_Right, kAxisXP},\n\t\t};\n\t}\n\t}\n\n\tbool mapping_updated = false;\n\tstd::for_each(mapping.cbegin(), mapping.cend(), [this, &controller, &mapping_updated](const auto& m)\n\t\t{\n\t\t\tif (m_mappings.find(m.first) == m_mappings.cend())\n\t\t\t{\n\t\t\t\tset_mapping(m.first, controller, m.second);\n\t\t\t\tmapping_updated = true;\n\t\t\t}\n\t\t});\n\n\treturn mapping_updated;\n}\n\nglm::vec2 WiimoteController::get_axis() const\n{\n\tconst auto left = get_axis_value(kButtonId_Nunchuck_Left);\n\tconst auto right = get_axis_value(kButtonId_Nunchuck_Right);\n\n\tconst auto up = get_axis_value(kButtonId_Nunchuck_Up);\n\tconst auto down = get_axis_value(kButtonId_Nunchuck_Down);\n\n\tglm::vec2 result;\n\tresult.x = (left > right) ? -left : right;\n\tresult.y = (up > down) ? up : -down;\n\treturn result;\n}\n\nglm::vec2 WiimoteController::get_rotation() const\n{\n\treturn {};\n}\n\nglm::vec2 WiimoteController::get_trigger() const\n{\n\treturn {};\n}\n\nvoid WiimoteController::load(const pugi::xml_node& node)\n{\n\tbase_type::load(node);\n\n\tif (const auto value = node.child(\"device_type\"))\n\t\tm_device_type = ConvertString<WPADDeviceType>(value.child_value());\n}\n\nvoid WiimoteController::save(pugi::xml_node& node)\n{\n\tbase_type::save(node);\n\n\tnode.append_child(\"device_type\").append_child(pugi::node_pcdata).set_value(fmt::format(\"{}\", (int)m_device_type).c_str());\n}\n\nuint32 WiimoteController::s_get_emulated_button_flag(uint32 id)\n{\n\tswitch (id)\n\t{\n\t\tcase kButtonId_A:\n\t\t\treturn kWPADButton_A;\n\t\tcase kButtonId_B:\n\t\t\treturn kWPADButton_B;\n\t\tcase kButtonId_1:\n\t\t\treturn kWPADButton_1;\n\t\tcase kButtonId_2:\n\t\t\treturn kWPADButton_2;\n\n\t\tcase kButtonId_Plus:\n\t\t\treturn kWPADButton_Plus;\n\t\tcase kButtonId_Minus:\n\t\t\treturn kWPADButton_Minus;\n\t\tcase kButtonId_Home:\n\t\t\treturn kWPADButton_Home;\n\n\t\tcase kButtonId_Up:\n\t\t\treturn kWPADButton_Up;\n\t\tcase kButtonId_Down:\n\t\t\treturn kWPADButton_Down;\n\t\tcase kButtonId_Left:\n\t\t\treturn kWPADButton_Left;\n\t\tcase kButtonId_Right:\n\t\t\treturn kWPADButton_Right;\n\n\t\tcase kButtonId_Nunchuck_Z:\n\t\t\treturn kWPADButton_Z;\n\t\tcase kButtonId_Nunchuck_C:\n\t\t\treturn kWPADButton_C;\n\t}\n\n\treturn 0;\n}\n\nstd::string_view WiimoteController::get_button_name(ButtonId id)\n{\n\tswitch (id)\n\t{\n\tcase kButtonId_A: return \"A\";\n\tcase kButtonId_B: return \"B\";\n\tcase kButtonId_1: return \"1\";\n\tcase kButtonId_2: return \"2\";\n\n\tcase kButtonId_Home: return TR_NOOP(\"home\");\n\tcase kButtonId_Plus: return \"+\";\n\tcase kButtonId_Minus: return \"-\";\n\n\tcase kButtonId_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_Right: return TR_NOOP(\"right\");\n\n\tcase kButtonId_Nunchuck_Z: return \"Z\";\n\tcase kButtonId_Nunchuck_C: return \"C\";\n\n\tcase kButtonId_Nunchuck_Up: return TR_NOOP(\"up\");\n\tcase kButtonId_Nunchuck_Down: return TR_NOOP(\"down\");\n\tcase kButtonId_Nunchuck_Left: return TR_NOOP(\"left\");\n\tcase kButtonId_Nunchuck_Right: return TR_NOOP(\"right\");\n\n\tdefault:\n\t\treturn \"\";\n\t}\n}\n\n\n"
  },
  {
    "path": "src/input/emulated/WiimoteController.h",
    "content": "#pragma once\n\n#include \"input/emulated/WPADController.h\"\n\nclass WiimoteController : public WPADController\n{\n\tusing base_type = WPADController;\npublic:\n\tenum ButtonId\n\t{\n\t\tkButtonId_None,\n\n\t\tkButtonId_A,\n\t\tkButtonId_B,\n\t\tkButtonId_1,\n\t\tkButtonId_2,\n\n\t\tkButtonId_Nunchuck_Z,\n\t\tkButtonId_Nunchuck_C,\n\n\t\tkButtonId_Plus,\n\t\tkButtonId_Minus,\n\n\n\t\tkButtonId_Up,\n\t\tkButtonId_Down,\n\t\tkButtonId_Left,\n\t\tkButtonId_Right,\n\n\n\t\tkButtonId_Nunchuck_Up,\n\t\tkButtonId_Nunchuck_Down,\n\t\tkButtonId_Nunchuck_Left,\n\t\tkButtonId_Nunchuck_Right,\n\n\t\tkButtonId_Home,\n\n\t\tkButtonId_Max,\n\t};\n\n\tWiimoteController(size_t player_index);\n\n\tType type() const override { return Type::Wiimote; }\n\tWPADDeviceType get_device_type() const override { return m_device_type; }\n\tvoid set_device_type(WPADDeviceType device_type);\n\n\tbool is_mpls_attached() override;\n\n\tuint32 get_emulated_button_flag(uint32 id) const override;\n\tsize_t get_highest_mapping_id() const override { return kButtonId_Max; }\n\tbool is_axis_mapping(uint64 mapping) const override { return mapping >= kButtonId_Nunchuck_Up && mapping <= kButtonId_Nunchuck_Right; }\n\n\tbool set_default_mapping(const std::shared_ptr<ControllerBase>& controller) override;\n\n\tglm::vec2 get_axis() const override;\n\tglm::vec2 get_rotation() const override;\n\tglm::vec2 get_trigger() const override;\n\n\tvoid load(const pugi::xml_node& node) override;\n\tvoid save(pugi::xml_node& node) override;\n\t\n\tstatic uint32 s_get_emulated_button_flag(uint32 id);\n\n\tstatic std::string_view get_button_name(ButtonId id);\n\n\tbool is_start_down() const override { return is_mapping_down(kButtonId_Plus); }\n\tbool is_left_down() const override { return is_mapping_down(kButtonId_Left); }\n\tbool is_right_down() const override { return is_mapping_down(kButtonId_Right); }\n\tbool is_up_down() const override { return is_mapping_down(kButtonId_Up); }\n\tbool is_down_down() const override { return is_mapping_down(kButtonId_Down); }\n\tbool is_a_down() const override { return is_mapping_down(kButtonId_A); }\n\tbool is_b_down() const override { return is_mapping_down(kButtonId_B); }\n\tbool is_home_down() const override { return is_mapping_down(kButtonId_Home); }\n\nprivate:\n\tWPADDeviceType m_device_type = kWAPDevCore;\n};\n"
  },
  {
    "path": "src/input/motion/Mahony.h",
    "content": "#pragma once\n\n#include <math.h>\n#include <cmath>\n#include \"util/math/quaternion.h\"\n\nclass MahonySensorFusion\n{\npublic:\n\tMahonySensorFusion()\n\t{\n\t\t// assume default forward pose (holding controller in hand, tilted forward so the sticks/buttons face upward)\n\t\tm_imuQ.Assign(sqrtf(0.5), sqrtf(0.5), 0.0f, 0.0f);\n\t}\n\n\t// gx, gy, gz are in radians/sec\n\tvoid updateIMU(float deltaTime, float gx, float gy, float gz, float ax, float ay, float az)\n\t{\n\t\tVector3f av(ax, ay, az);\n\t\tVector3f gv(gx, gy, gz);\n\t\tif (deltaTime > 0.2f)\n\t\t\tdeltaTime = 0.2f; // dont let stutter mess up the internal state\n\t\tupdateGyroBias(gx, gy, gz);\n\t\tgv.x -= m_gyroBias[0];\n\t\tgv.y -= m_gyroBias[1];\n\t\tgv.z -= m_gyroBias[2];\n\n\t\t// ignore small angles to avoid drift due to bias (especially on yaw)\n\t\tif (fabs(gv.x) < 0.015f)\n\t\t\tgv.x = 0.0f;\n\t\tif (fabs(gv.y) < 0.015f)\n\t\t\tgv.y = 0.0f;\n\t\tif (fabs(gv.z) < 0.015f)\n\t\t\tgv.z = 0.0f;\n\n\t\t// cemuLog_logDebug(LogType::Force, \"[IMU Quat] time {:7.4} | {:7.2} {:7.2} {:7.2} {:7.2} | gyro( - bias) {:7.4} {:7.4} {:7.4} | acc {:7.2} {:7.2} {:7.2} | GyroBias {:7.4} {:7.4} {:7.4}\", deltaTime, m_imuQ.x, m_imuQ.y, m_imuQ.z, m_imuQ.w, gv.x, gv.y, gv.z, ax, ay, az, m_gyroBias[0], m_gyroBias[1], m_gyroBias[2]);\n\n\t\tif (fabs(av.x) > 0.000001f || fabs(av.y) > 0.000001f || fabs(av.z) > 0.000001f)\n\t\t{\n\t\t\tav.Normalize();\n\t\t\tVector3f grav = m_imuQ.GetVectorZ();\n\t\t\tgrav.Scale(0.5f);\n\t\t\tVector3f errorFeedback = grav.Cross(av);\n\t\t\t// apply scaled feedback\n\t\t\tgv -= errorFeedback;\n\t\t}\n\t\tgv.Scale(0.5f * deltaTime);\n\t\tm_imuQ += (m_imuQ * Quaternionf(0.0f, gv.x, gv.y, gv.z));\n\t\tm_imuQ.NormalizeXYZW();\n\t\tupdateOrientationAngles();\n\t}\n\n\tfloat getRollRadians()\n\t{\n\t\treturn m_roll + (float)m_rollWinding * 2.0f * 3.14159265f;\n\t}\n\n\tfloat getPitchRadians()\n\t{\n\t\treturn m_pitch + (float)m_pitchWinding * 2.0f * 3.14159265f;\n\t}\n\n\tfloat getYawRadians()\n\t{\n\t\treturn m_yaw + (float)m_yawWinding * 2.0f * 3.14159265f;\n\t}\n\n\tvoid getQuaternion(float q[4]) const\n\t{\n\t\tq[0] = m_imuQ.w;\n\t\tq[1] = m_imuQ.x;\n\t\tq[2] = m_imuQ.y;\n\t\tq[3] = m_imuQ.z;\n\t}\n\n\tvoid getGyroBias(float gBias[3]) const\n\t{\n\t\tgBias[0] = m_gyroBias[0];\n\t\tgBias[1] = m_gyroBias[1];\n\t\tgBias[2] = m_gyroBias[2];\n\t}\n\nprivate:\n\n\t// calculate roll, yaw and pitch in radians. (-0.5 to 0.5)\n\tvoid calcOrientation()\n\t{\n\t\tfloat sinr_cosp = 2.0f * (m_imuQ.z * m_imuQ.w + m_imuQ.x * m_imuQ.y);\n\t\tfloat cosr_cosp = 1.0f - 2.0f * (m_imuQ.w * m_imuQ.w + m_imuQ.x * m_imuQ.x);\n\t\tm_roll = std::atan2(sinr_cosp, cosr_cosp);\n\n\t\t// pitch (y-axis rotation)\n\t\tfloat sinp = 2.0f * (m_imuQ.z * m_imuQ.x - m_imuQ.y * m_imuQ.w);\n\t\tif (std::abs(sinp) >= 1.0)\n\t\t\tm_pitch = std::copysign(3.14159265359f / 2.0f, sinp);\n\t\telse\n\t\t\tm_pitch = std::asin(sinp);\n\n\t\t// yaw (z-axis rotation)\n\t\tfloat siny_cosp = 2.0f * (m_imuQ.z * m_imuQ.y + m_imuQ.w * m_imuQ.x);\n\t\tfloat cosy_cosp = 1.0f - 2.0f * (m_imuQ.x * m_imuQ.x + m_imuQ.y * m_imuQ.y);\n\t\tm_yaw = std::atan2(siny_cosp, cosy_cosp);\n\t}\n\n\tvoid updateOrientationAngles()\n\t{\n\t\tauto calcWindingCountChange = [](float prevAngle, float newAngle) -> int\n\t\t{\n\t\t\tif (newAngle > prevAngle)\n\t\t\t{\n\t\t\t\tfloat angleDif = newAngle - prevAngle;\n\t\t\t\tif (angleDif > 3.14159265f)\n\t\t\t\t\treturn -1;\n\t\t\t}\n\t\t\telse if (newAngle < prevAngle)\n\t\t\t{\n\t\t\t\tfloat angleDif = prevAngle - newAngle;\n\t\t\t\tif (angleDif > 3.14159265f)\n\t\t\t\t\treturn 1;\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\t\tfloat prevRoll = m_roll;\n\t\tfloat prevPitch = m_pitch;\n\t\tfloat prevYaw = m_yaw;\n\t\tcalcOrientation();\n\t\t// calculate roll, yaw and pitch including winding count to match what VPAD API returns\n\t\tm_rollWinding += calcWindingCountChange(prevRoll, m_roll);\n\t\tm_pitchWinding += calcWindingCountChange(prevPitch, m_pitch);\n\t\tm_yawWinding += calcWindingCountChange(prevYaw, m_yaw);\n\t}\n\n\tvoid updateGyroBias(float gx, float gy, float gz)\n\t{\n\t\t// dont let actual movement influence the bias\n\t\t// but be careful about setting this too low, there are controllers out there with really bad bias (my Switch Pro had -0.0933 0.0619 0.0179 in resting state)\n\t\tif (fabs(gx) >= 0.35f || fabs(gy) >= 0.35f || fabs(gz) >= 0.35f)\n\t\t\treturn;\n\n\t\tm_gyroTotalSum[0] += gx;\n\t\tm_gyroTotalSum[1] += gy;\n\t\tm_gyroTotalSum[2] += gz;\n\t\tm_gyroTotalSampleCount++;\n\t\tif (m_gyroTotalSampleCount >= 200)\n\t\t{\n\t\t\tm_gyroBias[0] = (float)(m_gyroTotalSum[0] / (double)m_gyroTotalSampleCount);\n\t\t\tm_gyroBias[1] = (float)(m_gyroTotalSum[1] / (double)m_gyroTotalSampleCount);\n\t\t\tm_gyroBias[2] = (float)(m_gyroTotalSum[2] / (double)m_gyroTotalSampleCount);\n\t\t}\n\t}\n\n\tprivate:\n\t\tQuaternionf m_imuQ; // current orientation\n\t\t// angle data\n\t\tfloat m_roll{};\n\t\tfloat m_pitch{};\n\t\tfloat m_yaw{};\n\t\tint m_rollWinding{};\n\t\tint m_pitchWinding{};\n\t\tint m_yawWinding{};\n\t\t// gyro bias\n\t\tfloat m_gyroBias[3]{};\n\t\tdouble m_gyroTotalSum[3]{};\n\t\tuint64 m_gyroTotalSampleCount{};\n};\n"
  },
  {
    "path": "src/input/motion/MotionHandler.h",
    "content": "#pragma once\n#include \"Mahony.h\"\n#include \"MotionSample.h\"\n\n// utility class to translate external motion input (DSU, SDL GamePad sensors) into the values expected by VPAD API (and maybe others in the future)\nclass WiiUMotionHandler\n{\npublic:\n\t// gyro is in radians/sec\n\tvoid processMotionSample(\n\t\tfloat deltaTime,\n\t\tfloat gx, float gy, float gz,\n\t\tfloat accx, float accy, float accz)\n\t{\n\t\tm_gyro[0] = gx;\n\t\tm_gyro[1] = gy;\n\t\tm_gyro[2] = gz;\n\t\tm_prevAcc[0] = m_acc[0];\n\t\tm_prevAcc[1] = m_acc[1];\n\t\tm_prevAcc[2] = m_acc[2];\n\t\tm_acc[0] = accx;\n\t\tm_acc[1] = accy;\n\t\tm_acc[2] = accz;\n\t\t// integrate acc and gyro samples into IMU\n\t\tm_imu.updateIMU(deltaTime, gx, gy, gz, accx, accy, accz);\n\n\t\t// get orientation from IMU\n\t\tm_orientation[0] = _radToOrientation(-m_imu.getYawRadians()) - 0.50f;\n\t\tm_orientation[1] = _radToOrientation(-m_imu.getPitchRadians()) - 0.50f;\n\t\tm_orientation[2] = _radToOrientation(m_imu.getRollRadians());\n\t}\n\n\tMotionSample getMotionSample()\n\t{\n\t\tfloat q[4];\n\t\tm_imu.getQuaternion(q);\n\t\tfloat gBias[3];\n\t\tm_imu.getGyroBias(gBias);\n\t\tfloat gyroDebiased[3];\n\t\tgyroDebiased[0] = m_gyro[0] - gBias[0];\n\t\tgyroDebiased[1] = m_gyro[1] - gBias[1];\n\t\tgyroDebiased[2] = m_gyro[2] - gBias[2];\n\t\treturn MotionSample(m_acc, MotionSample::calculateAccAcceleration(m_prevAcc, m_acc), gyroDebiased, m_orientation, q);\n\t}\nprivate:\n\n\t// VPAD orientation unit is 1.0 = one revolution around the axis\n\tfloat _radToOrientation(float rad)\n\t{\n\t\treturn rad / (2.0f * 3.14159265f);\n\t}\n\n\tMahonySensorFusion m_imu;\n\t// state\n\tfloat m_gyro[3]{};\n\tfloat m_acc[3]{};\n\tfloat m_prevAcc[3]{};\n\t// calculated values\n\tfloat m_orientation[3]{};\n};"
  },
  {
    "path": "src/input/motion/MotionSample.h",
    "content": "#pragma once\n#include \"util/math/vector3.h\"\n#include \"util/math/quaternion.h\"\n\nstruct Quat\n{\n\tfloat w;\n\tfloat x;\n\tfloat y;\n\tfloat z;\n\n\tQuat()\n\t{\n\t\tw = 1.0f;\n\t\tx = 0.0f;\n\t\ty = 0.0f;\n\t\tz = 0.0f;\n\t}\n\n\tQuat(float inW, float inX, float inY, float inZ)\n\t{\n\t\tw = inW;\n\t\tx = inX;\n\t\ty = inY;\n\t\tz = inZ;\n\t}\n\n\tstatic Quat AngleAxis(float inAngle, float inX, float inY, float inZ)\n\t{\n\t\tQuat result = Quat(cosf(inAngle * 0.5f), inX, inY, inZ);\n\t\tresult.Normalize();\n\t\treturn result;\n\t}\n\n\tvoid Set(float inW, float inX, float inY, float inZ)\n\t{\n\t\tw = inW;\n\t\tx = inX;\n\t\ty = inY;\n\t\tz = inZ;\n\t}\n\n\tQuat& operator*=(const Quat& rhs)\n\t{\n\t\tSet(w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z,\n\t\t\tw * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y,\n\t\t\tw * rhs.y - x * rhs.z + y * rhs.w + z * rhs.x,\n\t\t\tw * rhs.z + x * rhs.y - y * rhs.x + z * rhs.w);\n\t\treturn *this;\n\t}\n\n\tfriend Quat operator*(Quat lhs, const Quat& rhs)\n\t{\n\t\tlhs *= rhs;\n\t\treturn lhs;\n\t}\n\n\tvoid Normalize()\n\t{\n\t\t//printf(\"Normalizing: %.4f, %.4f, %.4f, %.4f\\n\", w, x, y, z);\n\t\tconst float length = sqrtf(x * x + y * y + z * z);\n\t\tfloat targetLength = 1.0f - w * w;\n\t\tif (targetLength <= 0.0f || length <= 0.0f)\n\t\t{\n\t\t\tSet(1.0f, 0.0f, 0.0f, 0.0f);\n\t\t\treturn;\n\t\t}\n\t\ttargetLength = sqrtf(targetLength);\n\t\tconst float fixFactor = targetLength / length;\n\n\t\tx *= fixFactor;\n\t\ty *= fixFactor;\n\t\tz *= fixFactor;\n\n\t\t//printf(\"Normalized: %.4f, %.4f, %.4f, %.4f\\n\", w, x, y, z);\n\t\treturn;\n\t}\n\n\tQuat Normalized() const\n\t{\n\t\tQuat result = *this;\n\t\tresult.Normalize();\n\t\treturn result;\n\t}\n\n\tvoid Conjugate()\n\t{\n\t\tx = -x;\n\t\ty = -y;\n\t\tz = -z;\n\t\treturn;\n\t}\n\n\tQuat Conjugated() const\n\t{\n\t\tQuat result = *this;\n\t\tresult.Conjugate();\n\t\treturn result;\n\t}\n};\n\n// helper class to store unified motion data\n// supports retrieving values in their API-specific (VPAD, KPAD etc.) format\nclass MotionSample\n{\npublic:\n\tMotionSample() = default;\n\n\tMotionSample(float acc[3], float accAcceleration, float gyro[3], float orientation[3],\n\t\tfloat quaternion[4]\n\t)\n\t{\n\t\tm_acc[0] = acc[0];\n\t\tm_acc[1] = acc[1];\n\t\tm_acc[2] = acc[2];\n\t\tm_accAcceleration = accAcceleration;\n\t\tm_gyro[0] = gyro[0];\n\t\tm_gyro[1] = gyro[1];\n\t\tm_gyro[2] = gyro[2];\n\t\tm_orientation[0] = orientation[0];\n\t\tm_orientation[1] = orientation[1];\n\t\tm_orientation[2] = orientation[2];\n\t\tm_q[0] = quaternion[0];\n\t\tm_q[1] = quaternion[1];\n\t\tm_q[2] = quaternion[2];\n\t\tm_q[3] = quaternion[3];\n\t\tm_accMagnitude = sqrtf(m_acc[0] * m_acc[0] + m_acc[1] * m_acc[1] + m_acc[2] * m_acc[2]);\n\t}\n\n\tvoid getVPADOrientation(float orientation[3])\n\t{\n\t\torientation[0] = m_orientation[0];\n\t\torientation[1] = m_orientation[1];\n\t\torientation[2] = m_orientation[2];\n\t}\n\n\tvoid getVPADGyroChange(float gyro[3])\n\t{\n\t\t// filter noise\n\t\tif (fabs(gyro[0]) < 0.012f)\n\t\t\tgyro[0] = 0.0f;\n\t\tif (fabs(gyro[1]) < 0.012f)\n\t\t\tgyro[1] = 0.0f;\n\t\tif (fabs(gyro[2]) < 0.012f)\n\t\t\tgyro[2] = 0.0f;\n\t\t// convert\n\t\tgyro[0] = _radToOrientation(-m_gyro[0]);\n\t\tgyro[1] = _radToOrientation(-m_gyro[1]);\n\t\tgyro[2] = _radToOrientation(m_gyro[2]);\n\t}\n\n\tvoid getVPADAccelerometer(float acc[3])\n\t{\n\t\tacc[0] = -m_acc[0];\n\t\tacc[1] = -m_acc[1];\n\t\tacc[2] = m_acc[2];\n\t}\n\n\tfloat getVPADAccMagnitude()\n\t{\n\t\treturn m_accMagnitude;\n\t}\n\n\tfloat getVPADAccAcceleration() // Possibly not entirely correct. Our results are smaller than VPAD API ones\n\t{\n\t\treturn m_accAcceleration;\n\t}\n\n\tvoid getVPADAccXY(float accXY[2])\n\t{\n\t\tfloat invMag = 1.0f / m_accMagnitude;\n\t\tfloat normAcc[3];\n\t\tnormAcc[0] = m_acc[0] * invMag;\n\t\tnormAcc[1] = m_acc[1] * invMag;\n\t\tnormAcc[2] = m_acc[2] * invMag;\n\t\taccXY[0] = sqrtf(normAcc[0] * normAcc[0] + normAcc[1] * normAcc[1]);\n\t\taccXY[1] = -sin(getAtanPitch(-normAcc[2], normAcc[0], -normAcc[1]));\n\t}\n\n\tvoid getXVector(float vOut[3], Quaternionf& q)\n\t{\n\t\tfloat X = q.x;\n\t\tfloat Y = q.y;\n\t\tfloat Z = q.z;\n\t\tfloat W = q.w;\n\t\tfloat xy = X * Y;\n\t\tfloat xz = X * Z;\n\t\tfloat yy = Y * Y;\n\t\tfloat yw = Y * W;\n\t\tfloat zz = Z * Z;\n\t\tfloat zw = Z * W;\n\t\tvOut[0] = 1.0f - 2.0f * (yy + zz); // x.x\n\t\tvOut[2] = 2.0f * (xy + zw); // x.y\n\t\tvOut[1] = 2.0f * (xz - yw); // x.z\n\t}\n\n\tvoid getVPADAttitudeMatrix(float mtx[9])\n\t{\n\t\t// VPADs attitude matrix has mixed axis handedness, the most sane way to replicate it is by generating Y and Z by rotating the X vector\n\t\tQuaternionf qImu(m_q[0], m_q[1], m_q[2], m_q[3]);\n\t\tQuaternionf qY = qImu * Quaternionf::FromAngleAxis(1.5708f * 1.0f, 0.0f, 0.0f, 1.0f);\n\t\tQuaternionf qZ = qImu * Quaternionf::FromAngleAxis(1.5708f * 1.0f, 0.0f, 1.0f, 0.0f);\n \t\tgetXVector(mtx + 0, qImu);\n\t\tgetXVector(mtx + 3, qY);\n\t\tgetXVector(mtx + 6, qZ);\n\t}\n\n\tstatic float calculateAccAcceleration(float prevAcc[3], float currentAcc[3])\n\t{\n\t\tfloat ax = currentAcc[0] - prevAcc[0];\n\t\tfloat ay = currentAcc[1] - prevAcc[1];\n\t\tfloat az = currentAcc[2] - prevAcc[2];\n\t\treturn sqrtf(ax * ax + ay * ay + az * az);\n\t}\n\n\tvoid getAccelerometer(float acc[3])\n\t{\n\t\tacc[0] = m_acc[0];\n\t\tacc[1] = m_acc[1];\n\t\tacc[2] = m_acc[2];\n\t}\n\tvoid getGyrometer(float gyro[3])\n\t{\n\t\tgyro[0] = m_gyro[0];\n\t\tgyro[1] = m_gyro[1];\n\t\tgyro[2] = m_gyro[2];\n\t}\n\nprivate:\n\tstatic float _radToOrientation(float rad)\n\t{\n\t\treturn rad / (2.0f * 3.14159265f);\n\t}\n\n\tstatic float getAtanPitch(float X, float Y, float Z)\n\t{\n\t\treturn atan2f(-X, sqrtf(Y * Y + Z * Z));\n\t}\n\n\t// provided values\n\tfloat m_gyro[3]{};\n\tfloat m_acc[3]{};\n\tfloat m_accAcceleration{};\n\tfloat m_orientation[3]{};\n\tfloat m_q[4]{};\n\t// calculated values\n\tfloat m_accMagnitude{};\n};\n\n/*\n\nCaptured VPAD attitude values\n\nAssuming GamePad is in a direct line between player (holder) and the monitor\n\nDRC flat on table, screen facing up. Top pointing away (away from person, pointing towards monitor):\n1.00   -0.03   -0.00\n0.03    0.99   -0.13\n0.01    0.13    0.99\n\nTurned 45° to the right:\n 0.71   -0.03    0.71\n 0.12    0.99   -0.08\n-0.70    0.14    0.70\n\nTurned 45° to the right (top of GamePad pointing right now):\n 0.08   -0.03    1.00\t\t\t-> Z points towards person\n 0.15    0.99    0.01\n-0.99    0.15    0.09\t\t\t-> DRC Z-Axis now points towards X-minus\n\nTurned 90° to the right (top of gamepad now pointing towards holder, away from monitor):\n-1.00   -0.01    0.06\n 0.00    0.99    0.15\n-0.06    0.15   -0.99\n\nTurned 90° to the right (pointing left):\n-0.17   -0.01   -0.99\n-0.13    0.99    0.02\n 0.98    0.13   -0.17\n\nAfter another 90° we end up in the initial position:\n 0.99   -0.03   -0.11\n 0.01    0.99   -0.13\n 0.12    0.12    0.99\n\n------\nFrom initial position, lean the GamePad on its left side. 45° up. So the screen is pointing to the top left\n 0.66   -0.75   -0.03\n 0.74    0.66   -0.11\n 0.10    0.05    0.99\n\nFurther 45°, GamePad now on its left, screen pointing left:\n-0.03   -1.00   -0.00\n 0.99   -0.03   -0.15\n 0.15   -0.01    0.99\n\nFrom initial position, lean the GamePad on its right side. 45° up. So the screen is pointing to the top right\n 0.75    0.65   -0.11\n-0.65    0.76    0.07\n 0.12    0.02    0.99\n\nFrom initial position, tilt the GamePad up 90° (bottom side remains in touch with surface):\n 0.99   -0.05   -0.10\n-0.10    0.01   -0.99\n 0.05    1.00    0.01\n\nFrom initial position, stand the GamePad on its top side:\n 1.00   -0.01   -0.09\n 0.09   -0.01    1.00\n-0.01   -1.00   -0.01\n\nRotate GamePad 180° around x axis, so it now lies on its screen (top of GamePad pointing to holder):\n 0.99   -0.03   -0.15\n-0.04   -1.00   -0.08\n-0.15    0.09   -0.99\n\n*/"
  },
  {
    "path": "src/main.cpp",
    "content": "#include \"WindowSystem.h\"\n#include \"util/crypto/aes128.h\"\n#include \"Cafe/OS/RPL/rpl.h\"\n#include \"Cafe/OS/libs/gx2/GX2.h\"\n#include \"Cafe/OS/libs/coreinit/coreinit_Thread.h\"\n#include \"Cafe/GameProfile/GameProfile.h\"\n#include \"Cafe/GraphicPack/GraphicPack2.h\"\n#include \"config/CemuConfig.h\"\n#include \"config/NetworkSettings.h\"\n#include \"config/LaunchSettings.h\"\n#include \"input/InputManager.h\"\n\n#include \"Cafe/CafeSystem.h\"\n#include \"Cafe/TitleList/TitleList.h\"\n#include \"Cafe/TitleList/SaveList.h\"\n\n#include \"Common/ExceptionHandler/ExceptionHandler.h\"\n#include \"Common/cpu_features.h\"\n\n#include \"util/helpers/helpers.h\"\n#include \"config/ActiveSettings.h\"\n#include \"Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.h\"\n\n#include \"Cafe/IOSU/legacy/iosu_crypto.h\"\n#include \"Cafe/OS/libs/vpad/vpad.h\"\n\n#include \"audio/IAudioAPI.h\"\n#include \"audio/IAudioInputAPI.h\"\n#if BOOST_OS_WINDOWS\n#pragma comment(lib,\"Dbghelp.lib\")\n#endif\n\n#define SDL_MAIN_HANDLED\n#include <SDL.h>\n\n#if BOOST_OS_LINUX\n#define _putenv(__s) putenv((char*)(__s))\n#include <sys/sysinfo.h>\n#elif BOOST_OS_MACOS || BOOST_OS_BSD\n#define _putenv(__s) putenv((char*)(__s))\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#endif\n\n#if BOOST_OS_WINDOWS\nextern \"C\"\n{\n\t__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;\n\t__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;\n}\n#endif\n\nstd::atomic_bool g_isGPUInitFinished = false;\n\nstd::wstring executablePath;\n\n// some implementations of _putenv dont copy the string and instead only store a pointer\n// thus we use a helper to keep a permanent copy\nstd::vector<std::string*> sPutEnvMap;\n\nvoid _putenvSafe(const char* c)\n{\n    auto s = new std::string(c);\n    sPutEnvMap.emplace_back(s);\n    _putenv(s->c_str());\n}\n\nvoid reconfigureGLDrivers()\n{\n\t// reconfigure GL drivers to store \n\tconst fs::path nvCacheDir = ActiveSettings::GetCachePath(\"shaderCache/driver/nvidia/\");\n\n\tstd::error_code err;\n\tfs::create_directories(nvCacheDir, err);\n\n\tstd::string nvCacheDirEnvOption(\"__GL_SHADER_DISK_CACHE_PATH=\");\n\tnvCacheDirEnvOption.append(_pathToUtf8(nvCacheDir));\n\n#if BOOST_OS_WINDOWS\n\tstd::wstring tmpW = boost::nowide::widen(nvCacheDirEnvOption);\n\t_wputenv(tmpW.c_str());\n#else\n    _putenvSafe(nvCacheDirEnvOption.c_str());\n#endif\n    _putenvSafe(\"__GL_SHADER_DISK_CACHE_SKIP_CLEANUP=1\");\n\n}\n\nvoid reconfigureVkDrivers()\n{\n    _putenvSafe(\"DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1=1\");\n    _putenvSafe(\"DISABLE_VK_LAYER_VALVE_steam_fossilize_1=1\");\n}\n\nvoid WindowsInitCwd()\n{\n\t#if BOOST_OS_WINDOWS\n\texecutablePath.resize(4096);\n\tint i = GetModuleFileNameW(NULL, executablePath.data(), executablePath.size());\n\tif(i >= 0)\n\t\texecutablePath.resize(i);\n\telse\n\t\texecutablePath.clear();\n\tSetCurrentDirectoryW(executablePath.c_str());\n\t// set high priority\n\tSetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);\n\t#endif\n}\n\nvoid CemuCommonInit()\n{\n\treconfigureGLDrivers();\n\treconfigureVkDrivers();\n\t// crypto init\n\tAES128_init();\n\t// init PPC timer\n\t// call this as early as possible because it measures frequency of RDTSC using an asynchronous thread over 3 seconds\n\tPPCTimer_init();\n\n\tWindowsInitCwd();\n    ExceptionHandler_Init();\n\t// read config\n\tGetConfigHandle().Load();\n\tif (NetworkConfig::XMLExists())\n\t\tn_config.Load();\n\t// parallelize expensive init code\n\tstd::future<int> futureInitAudioAPI = std::async(std::launch::async, []{ IAudioAPI::InitializeStatic(); IAudioInputAPI::InitializeStatic(); return 0; });\n\tstd::future<int> futureInitGraphicPacks = std::async(std::launch::async, []{ GraphicPack2::LoadAll(); return 0; });\n\tInputManager::instance().load();\n\tfutureInitAudioAPI.wait();\n\tfutureInitGraphicPacks.wait();\n\t// init Cafe system\n\tCafeSystem::Initialize();\n\t// init title list\n\tCafeTitleList::Initialize(ActiveSettings::GetUserDataPath(\"title_list_cache.xml\"));\n\tfor (auto& it : GetConfig().game_paths)\n\t\tCafeTitleList::AddScanPath(_utf8ToPath(it));\n\tfs::path mlcPath = ActiveSettings::GetMlcPath();\n\tif (!mlcPath.empty())\n\t\tCafeTitleList::SetMLCPath(mlcPath);\n\tCafeTitleList::Refresh();\n\t// init save list\n\tCafeSaveList::Initialize();\n\tif (!mlcPath.empty())\n\t{\n\t\tCafeSaveList::SetMLCPath(mlcPath);\n\t\tCafeSaveList::Refresh();\n\t}\n}\n\nvoid mainEmulatorLLE();\nvoid ppcAsmTest();\nvoid gx2CopySurfaceTest();\nvoid ExpressionParser_test();\nvoid FSTVolumeTest();\nvoid CRCTest();\n\nvoid UnitTests()\n{\n\tExpressionParser_test();\n\tgx2CopySurfaceTest();\n\tppcAsmTest();\n\tFSTVolumeTest();\n\tCRCTest();\n}\n\nbool isConsoleConnected = false;\nvoid requireConsole()\n{\n    #if BOOST_OS_WINDOWS\n    if (isConsoleConnected)\n        return;\n\n    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);\n    DWORD dwFileType = GetFileType(hOut);\n\n    if (dwFileType == FILE_TYPE_UNKNOWN || dwFileType == FILE_TYPE_CHAR)\n    {\n        if (AttachConsole(ATTACH_PARENT_PROCESS) != FALSE)\n        {\n            freopen(\"CONOUT$\", \"w\", stdout);\n            freopen(\"CONOUT$\", \"w\", stderr);\n            freopen(\"CONIN$\", \"r\", stdin);\n            isConsoleConnected = true;\n        }\n    }\n    else\n    {\n        isConsoleConnected = true; \n    }\n    #endif\n}\n\nvoid HandlePostUpdate()\n{\n\t// finalize update process\n\t// delete update cemu.exe.backup if available\n\tconst auto filename = ActiveSettings::GetExecutablePath().replace_extension(\"exe.backup\");\n\tif (fs::exists(filename))\n\t{\n#if BOOST_OS_WINDOWS\n\t\tHANDLE lock;\n\t\tdo\n\t\t{\n\t\t\tlock = CreateMutexW(nullptr, TRUE, L\"Global\\\\cemu_update_lock\");\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\t} while (lock == nullptr);\n\t\tconst DWORD wait_result = WaitForSingleObject(lock, 2000);\n\t\tCloseHandle(lock);\n\n\t\tif (wait_result == WAIT_OBJECT_0)\n\t\t{\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(500));\n\t\t\tstd::error_code ec;\n\t\t\tfs::remove(filename, ec);\n\t\t}\n#else\n\t\twhile (fs::exists(filename))\n\t\t{\n\t\t\tstd::error_code ec;\n\t\t\tfs::remove(filename, ec);\n\t\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1000));\n\t\t}\n#endif\n\t}\n}\n\nvoid ToolShaderCacheMerger();\n\n#if BOOST_OS_WINDOWS\n\n// entrypoint for release builds\nint wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)\n{\n\tif (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE)))\n\t\tcemuLog_log(LogType::Force, \"CoInitializeEx() failed\");\n\tSDL_SetMainReady();\n\tif (!LaunchSettings::HandleCommandline(lpCmdLine))\n\t\treturn 0;\n\tWindowSystem::Create();\n\treturn 0;\n}\n\n// entrypoint for debug builds with console\nint main(int argc, char* argv[])\n{\n\tif (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE)))\n\t\tcemuLog_log(LogType::Force, \"CoInitializeEx() failed\");\n\tSDL_SetMainReady();\n\tif (!LaunchSettings::HandleCommandline(argc, argv))\n\t\treturn 0;\n\tWindowSystem::Create();\n\treturn 0;\n}\n\n#else\n\nint main(int argc, char *argv[])\n{\n#if BOOST_OS_LINUX || BOOST_OS_BSD\n    XInitThreads();\n#endif\n    if (!LaunchSettings::HandleCommandline(argc, argv))\n\t\treturn 0;\n\tWindowSystem::Create();\n\treturn 0;\n}\n#endif\n\nextern \"C\" DLLEXPORT uint64 gameMeta_getTitleId()\n{\n\treturn CafeSystem::GetForegroundTitleId();\n}\n"
  },
  {
    "path": "src/mainLLE.cpp",
    "content": "#include \"util/crypto/aes128.h\"\n#include \"WindowSystem.h\"\n#include \"Common/FileStream.h\"\n\nvoid CemuCommonInit();\n\ntypedef struct  \n{\n\t/* +0x000 */ uint32be magic;\n}ppcAncastHeader_t;\n\nvoid loadEncryptedPPCAncastKernel()\n{\n\tauto kernelData = FileStream::LoadIntoMemory(\"kernel.img\");\n\tif (!kernelData)\n\t\texit(-1);\n\t// check header\n\tppcAncastHeader_t* ancastHeader = (ppcAncastHeader_t*)kernelData->data();\n\tif(ancastHeader->magic != (uint32be)0xEFA282D9)\n\t\tassert_dbg(); // invalid magic\n\tmemcpy(memory_getPointerFromPhysicalOffset(0x08000000), kernelData->data(), kernelData->size());\n}\n\nvoid loadPPCBootrom()\n{\n\tauto bootromData = FileStream::LoadIntoMemory(\"bootrom.bin\");\n\tif (!bootromData)\n\t\texit(-1);\n\tmemcpy(memory_getPointerFromPhysicalOffset(0x00000000), bootromData->data(), bootromData->size());\n}\n\nvoid mainEmulatorLLE()\n{\n\tCemuCommonInit();\n\t// memory init\n\tmemory_initPhysicalLayout();\n\t\n\t// start GUI thread\n\tWindowSystem::Create();\n\t// load kernel ancast image\n\tloadPPCBootrom();\n\tloadEncryptedPPCAncastKernel();\n\t\n\tPPCTimer_waitForInit();\n\t// begin execution\n\tPPCCoreLLE_startSingleCoreScheduler(0x00000100);\n}\n\n"
  },
  {
    "path": "src/resource/CMakeLists.txt",
    "content": "add_library(CemuResource)\n\nset_property(TARGET CemuResource PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\nenable_language(ASM)\n\n# icon resources\ntarget_sources(CemuResource PRIVATE\nembedded/resources.cpp\nembedded/resources.h\n)\n\nif(UNIX)\n    if(NOT APPLE)\n        target_sources(CemuResource PRIVATE embedded/fontawesome.S)\n    else()\n        target_sources(CemuResource PRIVATE embedded/fontawesome_macos.S)\n    endif()\nendif()\n\ntarget_sources(CemuResource PRIVATE CafeDefaultFont.cpp)\n\ntarget_include_directories(CemuResource PUBLIC \"../\")\n\ntarget_link_libraries(CemuResource PRIVATE CemuCommon)\n"
  },
  {
    "path": "src/resource/CafeDefaultFont.cpp",
    "content": "\nunsigned char cafeDefaultFontZLIB[] = {\n\t0x78, 0xda, 0xdc, 0xbc, 0x07, 0x78, 0x54, 0xd5, 0xda, 0xf7, 0x7d, 0xef, 0x36, 0xbb, 0x0c, 0xbd, 0x43, 0x80, 0x4c, 0x08, 0x20, 0x25, 0xf4, 0x16, 0x3a, 0x24, 0xf4, 0x1a, 0x7a, 0x82, 0x20, 0x09, 0x84, 0xde, 0x7b, 0x91, 0x2e, 0x20, 0x20, 0x45, 0x04, 0xe9, 0x4d, 0x40, 0x40, 0x40, 0x98, 0x50, 0x94, 0x5e, 0x04, 0x15, 0x15, 0x05, 0x15, 0x15, 0x05, 0x01, 0x15, 0x05, 0x14, 0x14, 0xa5, 0x2a, 0x65, 0xde, 0xdf, 0x9e, 0x4c, 0x10, 0x50, 0xcf, 0x79, 0xce, 0xf3, 0x3d, 0xcf, 0x77, 0x5d, 0xef,\n\t0x8b, 0xe7, 0xcf, 0x6a, 0xf7, 0xba, 0xfb, 0x5e, 0x7b, 0xad, 0xd9, 0xeb, 0x20, 0x8a, 0x88, 0x64, 0xe2, 0x2f, 0x5d, 0xa4, 0x7e, 0x5c, 0xf3, 0x56, 0x67, 0xf7, 0x1e, 0xec, 0x20, 0x9e, 0x0e, 0xe3, 0x45, 0x2b, 0xff, 0xa0, 0x7e, 0xab, 0x36, 0x31, 0x7d, 0xd6, 0x9f, 0x18, 0x21, 0xf6, 0x9c, 0xf1, 0x22,\n\t0x05, 0xfb, 0x34, 0x6f, 0x55, 0xaa, 0x6c, 0x6f, 0xcf, 0xa5, 0x3b, 0x22, 0xca, 0x54, 0x66, 0x25, 0x76, 0xe9, 0x9b, 0x34, 0x20, 0x6e, 0xc3, 0x97, 0x7f, 0x88, 0x94, 0x29, 0x28, 0x92, 0x6d, 0x6d, 0x97, 0x61, 0x43, 0x7c, 0x55, 0xce, 0x6f, 0x6f, 0x27, 0xd2, 0xd2, 0xc7, 0xf8, 0x0f, 0xdd, 0x06, 0x74, 0xef, 0x7b, 0x21, 0xdb, 0xe9, 0x6b, 0x22, 0x75, 0x8f, 0x89, 0x78, 0x17, 0x74, 0x4f, 0x1a, 0x3c, 0xc0, 0x95, 0x06, 0xff, 0x11, 0x94, 0x56, 0xf7, 0x3e, 0x23, 0xbb, 0xbd, 0x3a, 0xae, 0x50, 0x37, 0x91, 0x89, 0x0d, 0xc4, 0x78, 0xbb, 0x40, 0x8f, 0xae, 0x49, 0xc9, 0xde, 0x97, 0x9f, 0x3b, 0x0d, 0xff, 0x74, 0x8c, 0x57, 0xec, 0x41, 0x47, 0xfa, 0xcf, 0xd3, 0xad, 0xa3, 0x5d, 0x87, 0x76, 0xc1, 0x1e, 0x7d, 0x87, 0x8c, 0x38, 0x32, 0xe3, 0x62, 0x79, 0xda, 0x97, 0x44, 0x4a, 0x55, 0xeb, 0xd3,\n\t0xbf, 0x4b, 0x52, 0xd1, 0xcd, 0x1b, 0x1c, 0x91, 0x56, 0x16, 0xed, 0x5a, 0x7d, 0x93, 0x46, 0x0c, 0x48, 0x3f, 0x3f, 0xfd, 0x30, 0xc6, 0x7b, 0x40, 0xef, 0xeb, 0x97, 0xd4, 0xb7, 0xeb, 0x9e, 0x37, 0x93, 0x96, 0x8a, 0xa7, 0x7e, 0x1f, 0xf4, 0xfb, 0x71, 0x40, 0xff, 0xc1, 0x43, 0x1e, 0x94, 0x13, 0xd7, 0xbe, 0x78, 0x77, 0x7c, 0xc0, 0xa0, 0xae, 0x03, 0xfa, 0x3b, 0x3d, 0xab, 0x88, 0xb4, 0x48, 0xa6, 0xbd, 0x4b, 0x5c, 0x5f, 0xa8, 0xda, 0x17, 0x49, 0x53, 0x53, 0xee, 0x76, 0xca, 0x58, 0xed, 0xa6, 0xe4, 0x36, 0x4f, 0xd0, 0x23, 0x1f, 0x5f, 0x5a, 0x3f, 0xd2, 0x2d, 0x4f, 0x26, 0xcd, 0x48, 0xbe, 0xbb, 0xfc, 0xfe, 0x79, 0x67, 0x9c, 0xe5, 0xea, 0x6f, 0x8b, 0x1a, 0x9c, 0x21, 0xee, 0xdf, 0xe6, 0x1b, 0x0f, 0xda, 0x8a, 0x38, 0xfb, 0xee, 0x2e, 0xbf, 0x7d, 0xc4, 0x19, 0x17, 0xea, 0x7f, 0xf8,\n\t0xc7, 0x7b, 0xdc, 0xed, 0xe1, 0xef, 0xab, 0x58, 0x3f, 0x5b, 0x3c, 0xcc, 0x8c, 0x93, 0x44, 0x19, 0xee, 0x7a, 0xc9, 0xbb, 0x40, 0x34, 0x46, 0x75, 0x3d, 0x5e, 0xb9, 0x21, 0x86, 0x88, 0x31, 0xc2, 0xc8, 0x06, 0xcb, 0x5c, 0xa9, 0xa5, 0xb6, 0x5b, 0x3a, 0xa8, 0xc5, 0x50, 0x2b, 0xa3, 0xa1, 0xaa, 0xaa, 0xae, 0xa9, 0xda, 0x37, 0xa2, 0x06, 0xe2, 0xe4, 0x4a, 0x80, 0xb9, 0x11, 0x2e, 0xef, 0x21, 0x23, 0xe3, 0x9a, 0xc8, 0x41, 0x91, 0x07, 0x81, 0x54, 0x1d, 0xac, 0x5d, 0x6a, 0x3b, 0x9f, 0x28, 0x2b, 0xdc, 0x31, 0xed, 0x8e, 0xb1, 0xd4, 0xb5, 0x54, 0xbc, 0x7a, 0x29, 0x89, 0x0a, 0xaa, 0xfa, 0x3b, 0x12, 0x5a, 0x89, 0x6a, 0xb4, 0x10, 0xc5, 0xac, 0x17, 0xb8, 0x65, 0x64, 0x95, 0x14, 0xa3, 0x82, 0xb4, 0x0f, 0xe2, 0x57, 0x49, 0xf1, 0xa8, 0xa2, 0xea, 0x13, 0x25, 0x25, 0x88, 0xde, 0x8c, 0x6d,\n\t0x93, 0x04, 0xe3, 0x2e, 0xfd, 0x5e, 0xc9, 0xad, 0x46, 0x4b, 0x8a, 0x5a, 0x59, 0xba, 0x68, 0x2d, 0x24, 0xa7, 0x51, 0x99, 0x71, 0x0f, 0x88, 0x94, 0x1c, 0x6e, 0x69, 0x36, 0x84, 0xf6, 0x6e, 0x2a, 0x3c, 0x75, 0x25, 0xc1, 0x85, 0x35, 0x5e, 0x3a, 0xe8, 0xbb, 0xa1, 0xd9, 0x11, 0xec, 0x6b, 0xaf, 0x5f, 0xa5, 0x5e, 0x4b, 0xaa, 0x07, 0xb1, 0x4a, 0xf2, 0xeb, 0xfb, 0x25, 0xca, 0x38, 0x2c, 0x2b, 0x82, 0x40, 0x27, 0x2b, 0x5c, 0xc2, 0x8c, 0xbc, 0x92, 0x51, 0xbf, 0x12, 0x78, 0xa0, 0xbf, 0x21, 0x65, 0xb5, 0x8b, 0x52, 0xdd, 0x85, 0xa7, 0x89, 0xd4, 0xd2, 0x93, 0x65, 0x9a, 0xb6, 0x4f, 0x9a, 0x6b, 0xfb, 0xa5, 0xb9, 0xf5, 0x94, 0x34, 0x37, 0x8f, 0x49, 0x73, 0xcf, 0x64, 0x30, 0x45, 0x9a, 0x33, 0xd6, 0x32, 0x88, 0xae, 0xd2, 0x4a, 0xef, 0x27, 0xcd, 0xd0, 0xa9, 0xb9, 0x0b, 0xf5, 0x90, 0x94,\n\t0x34, 0x4b, 0x48, 0x49, 0x7b, 0xbd, 0x94, 0x34, 0xaa, 0x52, 0x2f, 0x42, 0x7d, 0x95, 0x94, 0xd4, 0x9f, 0x97, 0x52, 0x41, 0x4c, 0xf9, 0x9b, 0x32, 0x54, 0x37, 0x15, 0x20, 0xcc, 0x51, 0x42, 0xf5, 0xbf, 0x41, 0x1a, 0x9d, 0xe7, 0x23, 0xf8, 0x36, 0xa2, 0xbd, 0x96, 0x76, 0x38, 0xb2, 0x92, 0x99, 0x77, 0x9e, 0x76, 0x36, 0xa9, 0x1a, 0xd4, 0xab, 0x93, 0x4c, 0xd3, 0x3b, 0x05, 0x56, 0x81, 0x5f, 0x95, 0x8b, 0xd2, 0x17, 0xd4, 0x24, 0x83, 0x5f, 0xd2, 0xf3, 0x4a, 0x27, 0xe5, 0x62, 0x60, 0xa7, 0x72, 0x29, 0xb0, 0x4b, 0x37, 0xa0, 0x01, 0xea, 0x60, 0x29, 0xa6, 0x9c, 0x95, 0x99, 0x9e, 0xa1, 0xee, 0x9c, 0x10, 0x06, 0x61, 0xcf, 0x00, 0xa9, 0xeb, 0x39, 0x29, 0x71, 0xd8, 0x38, 0x2d, 0x88, 0x2e, 0xd2, 0x52, 0xfd, 0x1a, 0x9f, 0x74, 0x95, 0x1a, 0x2e, 0x3c, 0x31, 0x20, 0x56, 0x6a, 0xe8, 0xf3,\n\t0x64, 0xaa, 0x5a, 0x5b, 0x4a, 0xa9, 0x27, 0xa5, 0xa8, 0xfa, 0x89, 0x3c, 0xa5, 0x9e, 0xc6, 0xc7, 0xdd, 0xa4, 0xa8, 0xfe, 0xb5, 0x14, 0xd1, 0xcf, 0x4a, 0x51, 0x23, 0x51, 0x8a, 0x9a, 0xd7, 0x41, 0x5b, 0x29, 0x62, 0xb6, 0xa3, 0xff, 0x19, 0x19, 0x1b, 0x44, 0x06, 0xc9, 0xea, 0x29, 0x2e, 0xf9, 0xb4, 0x6b, 0x92, 0x55, 0x4f, 0x2f, 0x99, 0xb5, 0x19, 0x12, 0xad, 0x9e, 0x93, 0x4e, 0x5a, 0x41, 0x49, 0xd0, 0xa2, 0xa4, 0xb7, 0x1a, 0x25, 0x45, 0xd4, 0xee, 0x12, 0xa7, 0x66, 0x96, 0xd2, 0x94, 0x65, 0xd5, 0x58, 0x29, 0xad, 0xbc, 0x28, 0x05, 0xd5, 0x5a, 0x52, 0xc8, 0xed, 0x57, 0x0a, 0x63, 0xd3, 0x53, 0x81, 0xcb, 0x6a, 0x0b, 0xea, 0xc5, 0x24, 0x4e, 0x1b, 0x0b, 0x6d, 0x37, 0xd0, 0x13, 0xfa, 0x1e, 0x94, 0xdd, 0xa5, 0x8c, 0xb2, 0x8c, 0xb1, 0xef, 0xa5, 0xa8, 0xe2, 0x97, 0x08, 0xc6, 0x1a,\n\t0xa9, 0x05, 0xc5, 0xd4, 0x5a, 0x93, 0x57, 0x75, 0x25, 0x87, 0x5a, 0x48, 0x0c, 0xe5, 0x96, 0x14, 0xd7, 0x7c, 0x32, 0x0c, 0x84, 0x6b, 0x3e, 0x25, 0x2f, 0x70, 0xa8, 0xb7, 0x06, 0x4d, 0x42, 0x65, 0x3d, 0x32, 0xb8, 0x08, 0x65, 0x8f, 0x50, 0x5f, 0x3c, 0x68, 0x00, 0xfa, 0x81, 0x21, 0x60, 0x38, 0xe8, 0x08, 0xde, 0x02, 0x1f, 0x85, 0xca, 0x2f, 0xc0, 0x56, 0xb0, 0x34, 0x95, 0x9f, 0x92, 0x91, 0xfa, 0x2f, 0xe0, 0x3c, 0xf5, 0x82, 0x20, 0x5a, 0x77, 0x73, 0xb7, 0xad, 0xe4, 0x76, 0x73, 0xd6, 0x88, 0x63, 0x29, 0x3c, 0x25, 0xad, 0xdc, 0x3c, 0xd6, 0x0f, 0x4b, 0x6d, 0xcf, 0x0b, 0x12, 0xeb, 0xe9, 0x21, 0x89, 0x9e, 0xd6, 0x92, 0xac, 0xbf, 0x8a, 0xff, 0x13, 0x65, 0x2a, 0xf1, 0xe8, 0xab, 0xd7, 0xc7, 0x77, 0x2d, 0xd1, 0x61, 0xa6, 0xb4, 0xd4, 0x72, 0x48, 0x53, 0xfc, 0x9e, 0x45, 0x7f, 0x5d,\n\t0xfa, 0x18, 0xd9, 0xf1, 0x7b, 0x1e, 0x99, 0xa0, 0x57, 0x95, 0xa7, 0xf4, 0x2d, 0xd0, 0x5a, 0x92, 0x55, 0xcb, 0x23, 0xcd, 0xb4, 0xfc, 0xd2, 0x58, 0xff, 0x42, 0x1a, 0xea, 0x3d, 0xe4, 0x59, 0x7d, 0x3b, 0x79, 0xbc, 0x86, 0xbe, 0x8d, 0x92, 0x4b, 0x6f, 0x23, 0x63, 0x8d, 0x93, 0xd2, 0xd4, 0xf8, 0x8c, 0xf6, 0xdb, 0x81, 0x07, 0x1e, 0x43, 0x46, 0x7a, 0x3c, 0xae, 0xad, 0x8a, 0x6b, 0x6f, 0x5b, 0x65, 0x8b, 0xb4, 0x74, 0x41, 0xfc, 0x52, 0xf4, 0x0a, 0xa9, 0xf0, 0x94, 0x92, 0x0c, 0x56, 0x94, 0x64, 0xe0, 0x19, 0x2d, 0x1c, 0x7c, 0xe6, 0x1a, 0x81, 0xed, 0x81, 0x3f, 0xac, 0x18, 0x30, 0x2d, 0xf5, 0xf9, 0x33, 0x8e, 0x40, 0x7b, 0x85, 0xe7, 0xfc, 0xd9, 0x40, 0xc0, 0x53, 0x44, 0x1a, 0x7a, 0xc2, 0xa1, 0xa1, 0xcf, 0x28, 0x2b, 0xf1, 0x56, 0x5f, 0x49, 0xb1, 0x8e, 0x52, 0x3f, 0x26, 0xf9, 0xcc,\n\t0x4c, 0xd0, 0xbd, 0x4d, 0x3d, 0x56, 0xca, 0x1b, 0x75, 0xa4, 0xbd, 0x55, 0x8e, 0x7a, 0xe5, 0xc0, 0x1f, 0xc6, 0x87, 0x3c, 0x8b, 0xa7, 0xc1, 0x16, 0x29, 0xaf, 0xbf, 0x8c, 0xbd, 0xad, 0xa4, 0xa9, 0x76, 0x81, 0x7c, 0xab, 0x91, 0x0a, 0xfd, 0x8c, 0x64, 0xf7, 0x54, 0x94, 0x9c, 0xda, 0x44, 0x29, 0xa3, 0x3f, 0x47, 0x3b, 0x17, 0x58, 0x24, 0xe2, 0x99, 0xc5, 0xfa, 0x32, 0x8d, 0x7a, 0x4f, 0x99, 0xe6, 0x49, 0xcb, 0x5d, 0xea, 0xda, 0x2d, 0xc9, 0x83, 0x4f, 0x32, 0x1b, 0xb3, 0xf1, 0xd5, 0xc1, 0xd4, 0x71, 0x3d, 0x9d, 0x34, 0xf3, 0x0c, 0x82, 0xee, 0x3d, 0xea, 0x2f, 0x4b, 0x5e, 0xe3, 0x75, 0xe8, 0x0e, 0x81, 0x77, 0xa5, 0x12, 0x68, 0xee, 0x79, 0x8a, 0xfa, 0x37, 0xac, 0x5d, 0xad, 0x03, 0x5f, 0x40, 0x9f, 0x0f, 0x7f, 0x24, 0x83, 0x8d, 0x6e, 0xa9, 0xfa, 0x64, 0xba, 0xc6, 0xf3, 0xaf, 0x9d,\n\t0x92, 0x78, 0xe5, 0x7d, 0xe9, 0xa6, 0x66, 0x92, 0xe7, 0x94, 0x3b, 0x32, 0x52, 0x39, 0x25, 0x3d, 0x8d, 0x8b, 0xd2, 0x13, 0x9f, 0x75, 0x54, 0x36, 0x4b, 0x67, 0xf5, 0x07, 0xe9, 0xa8, 0x7e, 0x2f, 0x9d, 0xc9, 0xb9, 0xd6, 0xea, 0x45, 0x50, 0x89, 0xbe, 0x68, 0x19, 0xa5, 0x75, 0x97, 0xce, 0x5a, 0x0f, 0xca, 0xd9, 0x52, 0x5b, 0xf9, 0x83, 0x75, 0x4d, 0x64, 0xbb, 0x5b, 0x57, 0x2f, 0xc9, 0x28, 0x7d, 0xaa, 0x6c, 0xf3, 0x54, 0x90, 0xb1, 0xda, 0x62, 0x89, 0xa5, 0x7e, 0x48, 0xcd, 0x28, 0x3d, 0x89, 0x69, 0x5b, 0x10, 0x4d, 0x2e, 0x6f, 0x05, 0x55, 0xd5, 0x8e, 0xd0, 0x76, 0x94, 0x5a, 0x5a, 0x4b, 0x19, 0x06, 0x4d, 0x5f, 0x17, 0xda, 0x77, 0xd2, 0xd9, 0x78, 0x41, 0xea, 0x52, 0x1f, 0x0d, 0x06, 0x2b, 0x4b, 0x65, 0xa4, 0xfa, 0x9b, 0x8c, 0x34, 0xe6, 0x4b, 0x1b, 0xcf, 0x4c, 0xe9, 0xea, 0x19,\n\t0x2d, 0x49, 0x69, 0x30, 0xce, 0x4b, 0x3b, 0xe3, 0x73, 0x79, 0x16, 0x5f, 0xb6, 0x86, 0x76, 0x1c, 0xc8, 0xa5, 0x47, 0xb3, 0xf6, 0x4d, 0x65, 0x9d, 0x9c, 0x2a, 0x53, 0x40, 0x09, 0x50, 0x24, 0x88, 0x68, 0x29, 0xe6, 0x99, 0x26, 0xd1, 0x76, 0x76, 0x79, 0x8f, 0x76, 0x29, 0xfd, 0x77, 0xe9, 0xae, 0xa5, 0x97, 0x02, 0x7a, 0x35, 0x69, 0xa7, 0x3f, 0xc5, 0x7a, 0xd7, 0x5b, 0x0a, 0x69, 0x97, 0xa4, 0xb2, 0x5e, 0x4f, 0x9e, 0xd1, 0x4e, 0x32, 0xde, 0x4c, 0x7a, 0xe0, 0xdb, 0xba, 0xcc, 0x2b, 0x0f, 0x26, 0x81, 0x56, 0x21, 0xd8, 0xa0, 0x13, 0x88, 0x0f, 0x95, 0x1d, 0x41, 0x7b, 0xa3, 0x88, 0x74, 0xc3, 0xa7, 0xf9, 0x58, 0x63, 0x9a, 0x91, 0x53, 0xcd, 0xf5, 0x4d, 0x52, 0x48, 0xaf, 0x2d, 0xf5, 0xf5, 0x22, 0x52, 0x49, 0x6f, 0x10, 0xf4, 0x41, 0x15, 0xb0, 0x34, 0xa4, 0x5b, 0x0b, 0x90, 0x15, 0xf4,\n\t0x02, 0x3d, 0x40, 0x17, 0x75, 0xa9, 0x54, 0x01, 0x6e, 0x59, 0x0f, 0xc4, 0x00, 0x1f, 0x68, 0x0e, 0x9a, 0x81, 0x36, 0xa0, 0x29, 0x88, 0x03, 0xed, 0x40, 0x1f, 0x17, 0x4a, 0x33, 0xa9, 0x0a, 0xca, 0x85, 0xe6, 0x26, 0x82, 0x3a, 0xa0, 0x36, 0xc8, 0x17, 0x9a, 0xeb, 0xce, 0x69, 0x19, 0x2a, 0x5b, 0x28, 0xb9, 0x1e, 0xcc, 0x35, 0x3e, 0x92, 0x67, 0x8c, 0xad, 0xbc, 0x53, 0x90, 0x09, 0xe6, 0x82, 0x31, 0xa0, 0x73, 0xa8, 0x3e, 0x0f, 0x6c, 0x00, 0x2b, 0xc0, 0xb9, 0x10, 0xcd, 0x1b, 0xe0, 0x28, 0x78, 0xd1, 0xd3, 0x5f, 0xba, 0xeb, 0x75, 0xa5, 0x86, 0x71, 0x50, 0x7a, 0xea, 0x93, 0xa5, 0x85, 0xf6, 0x2b, 0x6f, 0xdc, 0xf3, 0xac, 0x87, 0xfd, 0xa4, 0x1e, 0xcf, 0x7e, 0x43, 0x68, 0x92, 0x79, 0xdb, 0xf7, 0x04, 0x43, 0x8c, 0x33, 0xb2, 0x19, 0x6c, 0x01, 0x25, 0xc0, 0x94, 0xb4, 0xd2, 0x1d, 0x77,\n\t0xc7, 0xf0, 0xd5, 0x87, 0xe0, 0xe8, 0x9f, 0x6b, 0x53, 0x20, 0x7f, 0x2a, 0x1e, 0x5b, 0xab, 0xdc, 0xb2, 0x3e, 0x68, 0x9a, 0x5a, 0x06, 0x6e, 0x3d, 0xde, 0x76, 0xc7, 0x95, 0x3c, 0x9e, 0xf5, 0xbc, 0x2b, 0x57, 0xa0, 0xf3, 0x47, 0xf8, 0xfd, 0x01, 0xeb, 0xf0, 0x11, 0xd6, 0x9e, 0x92, 0x32, 0x08, 0x8c, 0x34, 0x56, 0xf1, 0x2c, 0xee, 0x02, 0xc3, 0x24, 0x51, 0x1f, 0x28, 0x1b, 0x79, 0xce, 0x36, 0x12, 0x8f, 0xce, 0xaa, 0x8e, 0x5f, 0x77, 0x4a, 0x45, 0xb5, 0x0d, 0xcf, 0x43, 0x47, 0xca, 0x76, 0x52, 0x4c, 0xbd, 0x26, 0xe9, 0xd5, 0x0b, 0xac, 0xa5, 0xf3, 0x03, 0xb7, 0xd4, 0x79, 0x52, 0x5c, 0xe4, 0x3e, 0x7a, 0x2a, 0x8d, 0x90, 0xb3, 0x0b, 0xd9, 0x9f, 0x83, 0xb5, 0x8f, 0xc8, 0x1f, 0x1e, 0x5a, 0xfb, 0x32, 0x68, 0x8e, 0x2c, 0x7c, 0x04, 0x2f, 0x3d, 0xd1, 0xee, 0x07, 0x3e, 0x48, 0x5d, 0x47,\n\t0xe1, 0xe5, 0xf0, 0x4e, 0xfe, 0x13, 0x2e, 0x6d, 0x45, 0xb0, 0x92, 0xb1, 0x88, 0x54, 0x48, 0x03, 0xd6, 0xc7, 0x7c, 0x7a, 0xa2, 0x32, 0x3e, 0xb8, 0xfb, 0x70, 0xe4, 0x0e, 0x7d, 0xbf, 0x81, 0xda, 0xd4, 0xcf, 0x6a, 0x0e, 0xeb, 0xaf, 0xc3, 0x7a, 0x08, 0x2f, 0xb5, 0xa6, 0xf4, 0xd2, 0x56, 0xca, 0x2a, 0xc6, 0x3e, 0xb0, 0x66, 0x49, 0xcb, 0x10, 0x7a, 0x84, 0x30, 0x30, 0xad, 0xcd, 0xb3, 0x1a, 0xaf, 0xc6, 0x48, 0x2b, 0xa5, 0x39, 0x76, 0x77, 0x93, 0x56, 0x6a, 0x27, 0xe9, 0xce, 0x3b, 0xa8, 0x95, 0xda, 0x39, 0x58, 0x1f, 0xa0, 0xb5, 0x95, 0xfe, 0xca, 0x76, 0xe9, 0xad, 0xbc, 0x21, 0xb5, 0x78, 0x27, 0x55, 0x57, 0x9b, 0x21, 0xcb, 0x27, 0x25, 0x5d, 0x88, 0x04, 0x86, 0x07, 0x6d, 0x0d, 0xca, 0xe6, 0xfd, 0x56, 0x57, 0x8a, 0x1b, 0x2d, 0xa5, 0x8c, 0x51, 0x43, 0x4a, 0x19, 0xd5, 0xa5, 0x83,\n\t0x19, 0x29, 0xc5, 0x59, 0x57, 0x9b, 0xe9, 0x63, 0xa4, 0x85, 0xf1, 0x1a, 0xcf, 0xc7, 0x6a, 0x49, 0xd2, 0x7b, 0x07, 0x06, 0xe2, 0xf3, 0x04, 0xa3, 0x5e, 0xe0, 0xac, 0x3a, 0x4d, 0x36, 0xf0, 0xee, 0x4c, 0xb1, 0x86, 0xca, 0x6a, 0xe3, 0x6e, 0x60, 0xa0, 0xbb, 0xae, 0x9a, 0x67, 0xa5, 0x83, 0x71, 0x95, 0x79, 0xdb, 0x58, 0x37, 0x2b, 0x49, 0x23, 0xa3, 0x96, 0x44, 0xb9, 0x7b, 0x19, 0xf7, 0xfd, 0x60, 0xf8, 0xe5, 0x55, 0x63, 0x63, 0xe0, 0xbe, 0xbe, 0x4f, 0x2a, 0xea, 0x0b, 0xa5, 0x34, 0xeb, 0x61, 0x3c, 0x31, 0x8b, 0x86, 0xbe, 0xbd, 0xd5, 0x8c, 0x38, 0xb2, 0xa7, 0x32, 0xd8, 0x0f, 0x19, 0x1a, 0xb9, 0xf9, 0xb6, 0x94, 0x35, 0x2e, 0x88, 0x87, 0xb5, 0xbe, 0xa3, 0x7e, 0x47, 0xb2, 0x18, 0x73, 0x25, 0xd2, 0xdd, 0x07, 0xb1, 0x66, 0xa7, 0x18, 0x2f, 0x07, 0xd7, 0xe4, 0xb2, 0x46, 0x6d, 0x29,\n\t0xab, 0xf7, 0x95, 0x18, 0x78, 0xa5, 0xe8, 0x5d, 0x03, 0x37, 0xdd, 0x3d, 0x90, 0x3e, 0x39, 0x70, 0x4e, 0x3b, 0xc2, 0x7b, 0xc8, 0xdd, 0x57, 0x64, 0x21, 0xee, 0x1b, 0x02, 0xc3, 0x3c, 0x9b, 0xe8, 0x6f, 0x9f, 0xba, 0x7f, 0xd0, 0x2b, 0x8a, 0xed, 0xa9, 0x4a, 0x2e, 0xb1, 0x47, 0xd0, 0xba, 0xf1, 0x4c, 0x5d, 0xe6, 0x7d, 0xc4, 0x5e, 0x40, 0xdf, 0x25, 0x99, 0xb4, 0x79, 0x52, 0x55, 0x1b, 0x22, 0x31, 0xda, 0x00, 0x89, 0xd4, 0x46, 0xb1, 0x5e, 0x44, 0x4a, 0x23, 0xde, 0x61, 0xa2, 0x0d, 0x0e, 0xfc, 0x68, 0x78, 0xe1, 0x57, 0x4c, 0x1a, 0x6a, 0xab, 0x58, 0xe3, 0xa2, 0xa5, 0xab, 0xfe, 0x16, 0x7b, 0x91, 0x9f, 0xd8, 0xdb, 0xdc, 0x90, 0x96, 0x2e, 0x82, 0xfb, 0x8c, 0x04, 0xa9, 0xcc, 0x9a, 0x68, 0xba, 0x7b, 0x0f, 0xf6, 0x49, 0x85, 0xd5, 0x2d, 0x81, 0x39, 0xfa, 0x24, 0x89, 0xd5, 0x46, 0xb2,\n\t0x46, 0x15, 0x93, 0xa7, 0xf5, 0x14, 0xe4, 0x8f, 0x42, 0x2e, 0x3c, 0xf4, 0x8c, 0xac, 0xe1, 0x55, 0xa4, 0x0c, 0x7b, 0xc5, 0x69, 0xee, 0xfb, 0xed, 0xe1, 0xde, 0xea, 0x11, 0xfc, 0xed, 0x9e, 0x8a, 0x7d, 0x8a, 0xbb, 0x37, 0x61, 0xdf, 0x37, 0x06, 0x1b, 0x5b, 0x04, 0x6d, 0x76, 0xf7, 0x7e, 0x87, 0xa5, 0x9c, 0x76, 0x2e, 0x64, 0xb7, 0x0b, 0x57, 0x77, 0xc0, 0xda, 0x5a, 0xcf, 0x7d, 0x07, 0xeb, 0x27, 0xf0, 0x77, 0xef, 0xe0, 0x5e, 0xb0, 0x15, 0x7b, 0xdd, 0xa6, 0xda, 0x99, 0xc0, 0x35, 0xdd, 0x2b, 0x1e, 0xf6, 0x4f, 0x63, 0xd3, 0xf6, 0x51, 0xac, 0x99, 0xf9, 0x94, 0x93, 0xbc, 0x93, 0x97, 0xf2, 0xce, 0x19, 0x2a, 0x63, 0xc1, 0xb8, 0xd4, 0x7d, 0x56, 0x60, 0x42, 0x90, 0xa6, 0x67, 0xea, 0xfb, 0x8a, 0x77, 0x65, 0x33, 0xe3, 0x0e, 0xeb, 0xce, 0x19, 0x9e, 0xa9, 0x34, 0xb0, 0xd7, 0x0a, 0x62,\n\t0x8a, 0x1c, 0x06, 0x2a, 0x31, 0x70, 0x75, 0x9a, 0xaa, 0xf5, 0x96, 0x3a, 0xca, 0xc9, 0x40, 0x7d, 0x50, 0x4f, 0x2d, 0x1b, 0x68, 0x0b, 0x6d, 0x56, 0xf5, 0x7d, 0xec, 0x78, 0x8f, 0x1c, 0xd8, 0x28, 0x6d, 0x78, 0x5f, 0x0f, 0x64, 0x2d, 0xce, 0xe2, 0xee, 0xad, 0x28, 0xd3, 0x69, 0x07, 0x88, 0xc3, 0x4c, 0x7c, 0x3f, 0x1a, 0x5f, 0xe2, 0x77, 0x6d, 0x3c, 0x6b, 0xe5, 0xb1, 0x40, 0x01, 0xf5, 0x18, 0x39, 0x7b, 0x9c, 0xfd, 0xd0, 0x4a, 0xf6, 0x10, 0x87, 0xc8, 0x9b, 0xde, 0xd8, 0x51, 0x11, 0x1d, 0xca, 0x05, 0xda, 0xea, 0xba, 0x98, 0xea, 0xcf, 0x41, 0x3f, 0xb4, 0x34, 0x23, 0x40, 0x47, 0x9e, 0x8d, 0x4c, 0xd2, 0x92, 0x75, 0xab, 0x90, 0x6e, 0x4a, 0x11, 0xe3, 0x13, 0x29, 0xe2, 0x59, 0xc2, 0xbe, 0x33, 0x9b, 0x8c, 0x37, 0xf2, 0xc8, 0x44, 0xbd, 0xa8, 0xf4, 0xc6, 0xa6, 0xe1, 0x41, 0x68, 0x92,\n\t0xd5, 0x88, 0x65, 0x5f, 0xd1, 0x48, 0x9a, 0x50, 0x2f, 0xaf, 0xb9, 0xf9, 0xfe, 0x34, 0xbc, 0xba, 0x4b, 0x76, 0xad, 0x1d, 0x36, 0xcc, 0x64, 0x5f, 0xf6, 0x19, 0xef, 0xd3, 0x01, 0x92, 0x41, 0xbb, 0x4e, 0x3b, 0x4a, 0x6a, 0xeb, 0x2b, 0xf0, 0xdf, 0xd7, 0x52, 0x81, 0x7d, 0x7b, 0x73, 0x72, 0xb9, 0x15, 0x7b, 0xfd, 0x96, 0x9e, 0x4f, 0xe9, 0x3b, 0xc4, 0xbb, 0x6a, 0x31, 0xb9, 0x0b, 0x98, 0xe7, 0xda, 0x1f, 0x19, 0x44, 0x63, 0xc9, 0xce, 0xfb, 0x62, 0xb4, 0x7e, 0x94, 0x77, 0x5c, 0x75, 0xe6, 0x1c, 0x92, 0x04, 0x64, 0x65, 0x31, 0x2e, 0xb3, 0x8f, 0x9b, 0x46, 0x1e, 0x0c, 0x44, 0x6e, 0x17, 0xde, 0x23, 0x4d, 0x88, 0x6b, 0x6e, 0x64, 0x2b, 0x92, 0x39, 0xe8, 0xeb, 0x9d, 0xc4, 0xb3, 0xa1, 0xe4, 0x51, 0xaf, 0x4b, 0x46, 0xed, 0x53, 0xce, 0x38, 0xef, 0xa2, 0xc7, 0x57, 0xe2, 0xd3, 0x8a, 0x52,\n\t0x0e, 0x0a, 0xa2, 0xba, 0xa6, 0x4b, 0x05, 0xad, 0xb2, 0x24, 0x2b, 0x1d, 0xa5, 0x0b, 0xef, 0xf6, 0xdc, 0xe4, 0x73, 0x32, 0xef, 0xe3, 0x64, 0xed, 0x2a, 0xa0, 0x5f, 0xcb, 0xc2, 0x5e, 0x33, 0x5e, 0x2a, 0xa8, 0xcb, 0xa4, 0x84, 0xba, 0x8a, 0xb1, 0xb7, 0xc1, 0x30, 0xc9, 0xa3, 0x85, 0xf1, 0xae, 0x4a, 0xe0, 0x5d, 0x12, 0xc5, 0x3e, 0x93, 0xbd, 0x27, 0xb9, 0x5b, 0x96, 0x75, 0xa4, 0x8c, 0xf2, 0x93, 0x94, 0x53, 0xae, 0x8b, 0x8f, 0x3d, 0x6a, 0xcd, 0xe0, 0x7e, 0x36, 0x0b, 0x7b, 0xd8, 0xde, 0x52, 0x46, 0xed, 0xc3, 0xf8, 0x0b, 0xac, 0x1d, 0x63, 0xc4, 0x5d, 0x9b, 0x72, 0xa9, 0xbd, 0x18, 0x8b, 0x91, 0x0c, 0x6a, 0x7b, 0xe2, 0xc2, 0x7a, 0xa1, 0xda, 0x62, 0xf3, 0xde, 0x6f, 0xe0, 0xd6, 0xd9, 0xaf, 0x8c, 0x35, 0x16, 0xe0, 0xfb, 0x11, 0x12, 0xa9, 0xe7, 0x23, 0x7e, 0x27, 0xd0, 0xe1, 0x04,\n\t0xfb, 0xbd, 0x63, 0x3c, 0xaf, 0xe7, 0xa5, 0xbc, 0x3a, 0x81, 0x18, 0xbf, 0xca, 0x73, 0xe4, 0xf2, 0x0f, 0x67, 0xff, 0xdb, 0x53, 0x4a, 0x21, 0xd7, 0x87, 0x0d, 0x86, 0xbb, 0xef, 0x55, 0x9e, 0x61, 0x8f, 0xdf, 0x5a, 0x9a, 0xb0, 0x67, 0x6e, 0xa1, 0xf4, 0x95, 0xca, 0xca, 0xc8, 0xc0, 0xe9, 0x60, 0x3b, 0x5e, 0x62, 0x39, 0xb7, 0x05, 0xf7, 0xce, 0xa0, 0x91, 0xda, 0x23, 0xb0, 0x3d, 0xb8, 0x77, 0xee, 0x27, 0x2d, 0xdc, 0x7d, 0xb4, 0x2b, 0x5b, 0xf9, 0x51, 0x4a, 0x28, 0xc5, 0x02, 0x3b, 0x94, 0x3d, 0x52, 0x40, 0x9d, 0xcd, 0x9e, 0x7c, 0x2a, 0xef, 0xd0, 0x91, 0xd2, 0x5e, 0x6d, 0x2e, 0xb1, 0xee, 0x7e, 0x9a, 0x33, 0x64, 0x71, 0x75, 0x84, 0x14, 0x57, 0x2e, 0x04, 0x7e, 0x57, 0x67, 0xf0, 0x3e, 0x1d, 0xcf, 0x5e, 0x68, 0x83, 0xe4, 0x51, 0xf6, 0x4b, 0x49, 0xb5, 0x1e, 0xef, 0xe8, 0x79, 0x72,\n\t0x58, 0x0f, 0x97, 0xc3, 0xec, 0x8f, 0x7a, 0xb2, 0x7f, 0x4f, 0x02, 0x89, 0x6a, 0x11, 0x89, 0x04, 0x55, 0x35, 0x3f, 0xfb, 0x69, 0xa0, 0xfc, 0xca, 0x1e, 0xe7, 0x33, 0xd9, 0xeb, 0x82, 0x75, 0x73, 0xd6, 0xa3, 0x60, 0x59, 0x9f, 0xa5, 0x26, 0xc2, 0xeb, 0x07, 0x79, 0xe5, 0x49, 0xb0, 0x07, 0x99, 0xe1, 0x82, 0xf3, 0x47, 0x69, 0x77, 0xdd, 0xd5, 0x6f, 0x4b, 0x4e, 0xf6, 0x14, 0x29, 0xc6, 0x58, 0x9e, 0xe3, 0xd1, 0xac, 0xbf, 0xaf, 0x51, 0x7f, 0x95, 0x5c, 0x99, 0x4d, 0x7e, 0xb3, 0x87, 0xd6, 0xd6, 0xb3, 0x7f, 0xdb, 0xc0, 0xd9, 0xee, 0x1e, 0xeb, 0xd3, 0x4a, 0xce, 0x79, 0x1f, 0x48, 0x38, 0xfb, 0xe3, 0x51, 0x7a, 0xcf, 0xc0, 0xe5, 0xe0, 0x7e, 0x78, 0x26, 0x75, 0x9e, 0x47, 0xed, 0xae, 0x64, 0x37, 0xca, 0x91, 0x2f, 0x1b, 0xc5, 0xab, 0x2d, 0x0f, 0xae, 0x6d, 0x51, 0x3a, 0xe7, 0x42, 0xf6,\n\t0x6d, 0xab, 0x3c, 0x55, 0xe0, 0x19, 0x25, 0x85, 0xc9, 0xd9, 0xc2, 0xfa, 0x6f, 0xac, 0xd5, 0xb3, 0x24, 0xbd, 0xb1, 0x82, 0xbe, 0xb9, 0x20, 0x45, 0x0a, 0x7b, 0xe2, 0x24, 0x9f, 0xa7, 0x2d, 0xe7, 0xd3, 0x3b, 0x8c, 0x8d, 0x60, 0x6f, 0x3c, 0x9a, 0xbc, 0xd8, 0x20, 0xf9, 0x8d, 0x0c, 0x92, 0xd1, 0x78, 0x46, 0x32, 0x98, 0x85, 0x24, 0x9f, 0x31, 0x53, 0xe2, 0xdd, 0x7d, 0x31, 0xef, 0xdf, 0x14, 0xcf, 0x06, 0xce, 0x01, 0xc0, 0x98, 0x44, 0x5d, 0x61, 0x1f, 0xec, 0x9e, 0x67, 0x1b, 0xa4, 0xee, 0x9b, 0xcd, 0xf9, 0x94, 0xee, 0x7b, 0x82, 0xb5, 0xdd, 0x7d, 0x17, 0xb0, 0x77, 0x4a, 0x41, 0x6e, 0x21, 0xa3, 0x8f, 0x64, 0xe0, 0x1d, 0x5d, 0x9d, 0x7d, 0x7d, 0x25, 0x4f, 0x49, 0x90, 0x51, 0x72, 0xf3, 0x1e, 0xcf, 0x65, 0xfa, 0x02, 0x7f, 0x98, 0xdd, 0x99, 0x73, 0x13, 0x99, 0xf7, 0x25, 0xaf, 0xfb,\n\t0x7e, 0xe1, 0x3d, 0xf2, 0x87, 0xfe, 0x61, 0x70, 0xbf, 0x1c, 0xa5, 0x2d, 0x90, 0x12, 0xda, 0x17, 0xac, 0x45, 0xcb, 0xf0, 0xd3, 0xd8, 0xe0, 0x33, 0x39, 0x4d, 0xef, 0x8f, 0x6d, 0x57, 0xa0, 0x65, 0x8f, 0x6c, 0x7c, 0xca, 0x58, 0x17, 0xfa, 0x4e, 0xe2, 0x83, 0x00, 0xfb, 0x67, 0x4b, 0x32, 0xe9, 0x99, 0x24, 0x1b, 0xcf, 0x51, 0x16, 0xde, 0x11, 0x79, 0x59, 0x87, 0x9b, 0xb1, 0xc6, 0x35, 0x65, 0x7d, 0x98, 0x66, 0xe4, 0xe3, 0xbd, 0x06, 0xd8, 0x13, 0x4e, 0xc3, 0x0f, 0x12, 0x7c, 0xbe, 0x58, 0xc3, 0x75, 0x87, 0xb3, 0xc5, 0x37, 0x94, 0xac, 0x95, 0xda, 0xe8, 0xc0, 0x6f, 0x41, 0x7f, 0xd6, 0x66, 0xdd, 0x5a, 0xc8, 0xfe, 0xb2, 0x31, 0x67, 0x96, 0xb2, 0x52, 0x1e, 0x7d, 0x5b, 0x18, 0x45, 0x39, 0xf3, 0x7d, 0x42, 0x8c, 0xea, 0xb0, 0x87, 0xcf, 0x0e, 0x7d, 0x3c, 0x7c, 0x17, 0xf2, 0x1c, 0xb9,\n\t0x6b, 0xeb, 0xf7, 0xec, 0xe9, 0xf7, 0x41, 0x93, 0x24, 0x1d, 0x8d, 0x51, 0x9c, 0x83, 0xa6, 0x4a, 0x3d, 0x50, 0x81, 0xf7, 0xcc, 0xd3, 0xee, 0x3e, 0xd5, 0x1c, 0x2f, 0x1f, 0x5a, 0xcd, 0xa5, 0xa3, 0x67, 0xad, 0x1c, 0x45, 0x56, 0x53, 0xde, 0x67, 0x4d, 0xed, 0x59, 0x9c, 0x45, 0xbf, 0x09, 0xee, 0x1b, 0xc3, 0x99, 0xdb, 0x9e, 0x78, 0x76, 0xd3, 0xf7, 0xc8, 0xd3, 0x46, 0x77, 0x69, 0xef, 0x19, 0x8c, 0x0d, 0xab, 0x64, 0x13, 0x71, 0x70, 0xf7, 0xcd, 0x73, 0xf1, 0xcf, 0x70, 0xca, 0x45, 0x5a, 0x11, 0xa5, 0x92, 0x56, 0x24, 0xf0, 0x93, 0x71, 0x26, 0xf0, 0x91, 0x71, 0x46, 0xdd, 0x9c, 0x8a, 0xb4, 0x7a, 0xe0, 0x23, 0x6b, 0x18, 0xef, 0xe1, 0x82, 0xf0, 0x24, 0x4e, 0x9c, 0x25, 0x12, 0x8d, 0xe6, 0x81, 0x0b, 0xc6, 0x52, 0xde, 0x55, 0x13, 0xe5, 0x29, 0xcf, 0x10, 0xf6, 0xd0, 0xcd, 0x59, 0x4f,\n\t0xe2, 0xb1, 0x63, 0x8a, 0xd4, 0xd1, 0x7b, 0x05, 0x6e, 0xe9, 0x33, 0x65, 0xa0, 0xb6, 0x57, 0xf2, 0x98, 0x5d, 0xa5, 0x85, 0xd5, 0x43, 0xba, 0x98, 0x83, 0x88, 0xc5, 0x38, 0x62, 0xf2, 0x39, 0x31, 0x7d, 0x56, 0x72, 0x58, 0x94, 0xac, 0xfb, 0xb9, 0x9d, 0xba, 0xe8, 0xb4, 0x4a, 0x12, 0xac, 0x9e, 0xd8, 0x76, 0x57, 0x9e, 0xc6, 0xfe, 0x81, 0xc6, 0xc0, 0xe0, 0x7a, 0x6b, 0x7a, 0xca, 0xe0, 0xdb, 0xcc, 0xf8, 0xe5, 0x3b, 0xd6, 0xbb, 0x41, 0x92, 0x0b, 0x1d, 0x9a, 0xeb, 0x37, 0x79, 0x47, 0xe4, 0x96, 0x36, 0xbc, 0x0b, 0x9b, 0xf3, 0x3c, 0xe4, 0x08, 0x9d, 0x43, 0xdd, 0x3d, 0x5f, 0x3c, 0x7b, 0x8e, 0xf7, 0xc1, 0x41, 0xfa, 0x97, 0xbb, 0x60, 0xaf, 0xd9, 0xdc, 0x7a, 0x4d, 0x1a, 0xfc, 0x4f, 0xc3, 0xfd, 0x8d, 0x00, 0x9f, 0x75, 0x03, 0x1d, 0x3c, 0x4d, 0xd8, 0x63, 0x2b, 0xf2, 0x6c, 0x68, 0xff,\n\t0x1d, 0x0b, 0x3a, 0xb3, 0xcf, 0x6d, 0xcd, 0x7e, 0xa4, 0xad, 0x71, 0x1c, 0x3d, 0x47, 0x48, 0x0b, 0xbb, 0x80, 0xb4, 0x41, 0xaf, 0x07, 0x5a, 0x32, 0xfb, 0xa7, 0xcb, 0x9c, 0x41, 0xdd, 0x33, 0x4e, 0x45, 0x19, 0xa7, 0xb6, 0x64, 0x3f, 0xde, 0x52, 0x5e, 0xe0, 0x1c, 0xd7, 0x07, 0xbc, 0xc0, 0x3a, 0xe0, 0x9e, 0x67, 0x0e, 0x85, 0x30, 0x42, 0xad, 0x22, 0x4b, 0x38, 0x67, 0xb5, 0x55, 0x4b, 0x73, 0x8e, 0x2a, 0x2d, 0xf5, 0xd5, 0xe7, 0x38, 0x0f, 0x3d, 0x27, 0x0d, 0xd4, 0x81, 0xd2, 0x10, 0x34, 0xd1, 0x8e, 0x05, 0xae, 0xba, 0x67, 0x1b, 0x9e, 0x93, 0xee, 0xe4, 0x6e, 0x7b, 0x7d, 0x81, 0x74, 0x31, 0xb2, 0x48, 0x5b, 0x9e, 0xfb, 0xe6, 0x7a, 0x75, 0xf6, 0x53, 0xe4, 0x87, 0x51, 0x9e, 0x3d, 0xcc, 0xdb, 0xc4, 0xe6, 0x7b, 0xf6, 0x48, 0x4d, 0xd9, 0x5b, 0x1d, 0xe6, 0xdc, 0x12, 0xcd, 0xb3, 0x1e,\n\t0x2d, 0x43, 0xc0, 0x08, 0xd0, 0x04, 0xd4, 0x04, 0x2d, 0x40, 0x25, 0xfd, 0x2b, 0xfc, 0x79, 0x0f, 0x1e, 0x19, 0x78, 0xd7, 0xf4, 0x20, 0x26, 0xe3, 0xc8, 0xa9, 0xce, 0xbc, 0x7b, 0xdc, 0xf1, 0x05, 0xd8, 0x7c, 0x1c, 0x39, 0xd1, 0x8c, 0x47, 0xcb, 0x73, 0x60, 0x61, 0xa8, 0x9c, 0x03, 0x56, 0x83, 0x37, 0xc1, 0x7b, 0xa1, 0x33, 0x8e, 0xdb, 0x3f, 0x11, 0xf4, 0x06, 0xee, 0xd9, 0xa3, 0xdc, 0x13, 0x67, 0x90, 0x78, 0xd0, 0x36, 0xd4, 0x7e, 0x3a, 0x74, 0x06, 0x71, 0xcf, 0x31, 0x35, 0x41, 0xb1, 0xd0, 0x39, 0x24, 0x26, 0xd4, 0x1f, 0x05, 0x6d, 0x34, 0xa8, 0xf0, 0x37, 0x7c, 0x12, 0x40, 0x9b, 0xd0, 0x59, 0x26, 0x22, 0x74, 0xee, 0x79, 0xf2, 0xec, 0xd3, 0x21, 0x14, 0x9b, 0x47, 0xf9, 0x37, 0x0e, 0xf1, 0xaf, 0x05, 0x8a, 0xc2, 0xa3, 0x4a, 0xe8, 0x4c, 0x54, 0x2e, 0xc4, 0xb3, 0xad, 0xba, 0x83,\n\t0x18, 0xa5, 0xce, 0x75, 0x75, 0x48, 0x7e, 0x64, 0x6e, 0xc3, 0xd0, 0x5c, 0xb7, 0x5d, 0x04, 0x54, 0xf8, 0x1b, 0xdb, 0x5c, 0xf9, 0x7d, 0x43, 0x7a, 0x75, 0x02, 0x0d, 0x42, 0xb2, 0xb2, 0x3f, 0x72, 0xc6, 0x7a, 0xf4, 0xac, 0x95, 0x26, 0xa7, 0x73, 0x88, 0xce, 0x95, 0xd3, 0x22, 0x54, 0x77, 0xfb, 0x8b, 0xc1, 0xb3, 0x22, 0xa8, 0xa4, 0xfe, 0x2a, 0x33, 0x25, 0x99, 0xb5, 0xa2, 0x98, 0xc4, 0x79, 0xb2, 0xb1, 0x66, 0x02, 0xf7, 0x3d, 0x2c, 0x72, 0xcf, 0xeb, 0x42, 0xed, 0xc4, 0xfb, 0xc7, 0x3d, 0x9b, 0x24, 0x07, 0x1e, 0xa8, 0xe5, 0x28, 0x0b, 0xb2, 0x17, 0x4a, 0x0e, 0xee, 0x31, 0x9b, 0x6b, 0xf3, 0x59, 0x43, 0xf7, 0xca, 0xd3, 0xc1, 0x3d, 0xd4, 0x76, 0xce, 0xee, 0xeb, 0xa4, 0x98, 0x56, 0x5f, 0x3a, 0x6a, 0xad, 0x38, 0x87, 0x26, 0x4a, 0x27, 0xf6, 0x20, 0x6d, 0xb5, 0xe6, 0xd2, 0x41, 0x2b,\n\t0x01, 0x06, 0x49, 0x15, 0x2d, 0x47, 0x30, 0x77, 0x2f, 0x82, 0x9a, 0xee, 0xb9, 0x82, 0x58, 0x2e, 0xe5, 0xfd, 0xd5, 0x86, 0x77, 0x4e, 0x1b, 0x75, 0x2f, 0x7b, 0x80, 0xd4, 0x33, 0x48, 0x91, 0x10, 0x9a, 0xa4, 0xfe, 0xb6, 0x13, 0xfc, 0x8d, 0xc8, 0x3d, 0xf3, 0xcc, 0x01, 0x53, 0xc0, 0xca, 0x50, 0x39, 0x0b, 0xa4, 0x0b, 0x21, 0x3e, 0x75, 0x4e, 0xf0, 0xf7, 0xa3, 0xe1, 0x9c, 0x5a, 0xba, 0x70, 0xbe, 0x13, 0xde, 0x61, 0x92, 0x56, 0xaa, 0x8b, 0x45, 0x78, 0xa7, 0x8a, 0xd2, 0x14, 0xb9, 0x53, 0x29, 0xb7, 0xa0, 0xc0, 0x1f, 0x60, 0x0c, 0xe3, 0xbe, 0xc0, 0x35, 0xe6, 0x19, 0x69, 0xb2, 0x79, 0xde, 0x4a, 0x5a, 0x6f, 0x4b, 0x47, 0x6b, 0xb4, 0xd4, 0x77, 0xcf, 0x89, 0x50, 0xdd, 0x36, 0x4a, 0xcb, 0xb1, 0x54, 0xdd, 0x1f, 0x64, 0x74, 0xf9, 0xa8, 0x19, 0x64, 0x12, 0xef, 0x5c, 0xb1, 0xd6, 0x4a,\n\t0xbd, 0x20, 0xfe, 0x17, 0xd6, 0x06, 0xdd, 0x8f, 0xdf, 0x4a, 0xcb, 0x24, 0x17, 0xd4, 0xfb, 0x52, 0x8e, 0x4d, 0x8d, 0x8b, 0xfb, 0xe7, 0x5e, 0xb1, 0xb4, 0x5f, 0xa5, 0x1f, 0xf9, 0x1d, 0xcd, 0xb5, 0xbf, 0x7b, 0xe8, 0x37, 0x34, 0x6f, 0xe8, 0x77, 0x96, 0xb4, 0xdf, 0xd6, 0x5a, 0xa5, 0xfd, 0xf6, 0x86, 0xbd, 0xe7, 0xf1, 0xf7, 0xc4, 0x90, 0x7f, 0xdd, 0xb1, 0x0e, 0x9a, 0xef, 0xc1, 0x0f, 0xf4, 0xbf, 0x84, 0x8d, 0xf7, 0x42, 0x7d, 0x0d, 0x42, 0x73, 0x5d, 0xfa, 0x8b, 0x21, 0x9e, 0xf0, 0x0f, 0xac, 0x0c, 0xfd, 0x36, 0x97, 0x2a, 0xf3, 0x92, 0xb8, 0xe7, 0xc9, 0x57, 0x42, 0x48, 0x3d, 0x1b, 0xba, 0xe7, 0xcc, 0xc7, 0xcf, 0x9f, 0xf3, 0xf4, 0x6f, 0xd9, 0xe7, 0xbb, 0x48, 0x94, 0x0b, 0xa1, 0xf8, 0xbd, 0x0d, 0x66, 0x30, 0x56, 0xc3, 0x68, 0x23, 0x0b, 0x5d, 0x84, 0xf4, 0x7f, 0x14, 0xc3, 0xd3,\n\t0x60, 0x54, 0xe1, 0xac, 0x16, 0xfa, 0x9d, 0x96, 0xf6, 0x28, 0xf7, 0x37, 0x40, 0xf7, 0x37, 0x57, 0x6d, 0x10, 0x67, 0x9e, 0x39, 0xb2, 0xd5, 0x30, 0x39, 0x5b, 0x4f, 0x96, 0x41, 0xc4, 0xd6, 0xcd, 0xb1, 0xdd, 0xb8, 0x65, 0x58, 0x2a, 0x02, 0xef, 0x07, 0x7f, 0x13, 0x5e, 0x9b, 0x0a, 0xf7, 0x37, 0x5d, 0x17, 0x5a, 0x7c, 0xe0, 0xae, 0xb1, 0x55, 0xda, 0x19, 0x8b, 0xc1, 0x46, 0xb0, 0x2e, 0x58, 0xb6, 0xe1, 0xcc, 0xd8, 0x86, 0x7d, 0x78, 0x1d, 0xde, 0x73, 0x6d, 0x8d, 0x8f, 0x41, 0x02, 0xeb, 0x72, 0x1d, 0x49, 0x50, 0x73, 0x07, 0x36, 0xe9, 0x3e, 0xf1, 0xe9, 0x85, 0x38, 0x37, 0x0d, 0x24, 0xf7, 0x53, 0xf5, 0xc3, 0x67, 0x72, 0xc4, 0xdd, 0x67, 0xb9, 0xbf, 0xb9, 0xbb, 0xcf, 0x85, 0xeb, 0x73, 0x3d, 0x39, 0x30, 0x3f, 0xf8, 0x8c, 0x94, 0xa6, 0xef, 0x19, 0x19, 0xab, 0x3d, 0xc7, 0xbe, 0xd5,\n\t0xfd, 0xcd, 0x7b, 0x34, 0x6d, 0x72, 0x5e, 0xe3, 0x19, 0x34, 0xd6, 0xc8, 0x61, 0xf6, 0xf9, 0xd1, 0xda, 0x26, 0x99, 0x1e, 0xfc, 0xfd, 0xaf, 0x82, 0xb4, 0x0f, 0xd2, 0xec, 0x63, 0x9d, 0xad, 0xcc, 0x7b, 0x16, 0x7b, 0xd5, 0x32, 0xf2, 0x32, 0xfc, 0x22, 0xdc, 0xbd, 0x9d, 0xbb, 0xc7, 0xd3, 0xde, 0xe3, 0xac, 0x51, 0x5f, 0x2a, 0x98, 0x9b, 0xd8, 0xaf, 0x26, 0x07, 0x16, 0x68, 0xdd, 0x02, 0xbf, 0x6b, 0xcf, 0x06, 0x3e, 0xd2, 0xfa, 0xc0, 0xff, 0xa2, 0xf4, 0x52, 0x9e, 0x92, 0x9a, 0x0a, 0xfb, 0xaa, 0xe0, 0x6f, 0xb2, 0x85, 0xc4, 0x62, 0xaf, 0x19, 0xa7, 0xd6, 0x97, 0xcc, 0x2a, 0xe7, 0x15, 0xf6, 0xb7, 0x25, 0xd3, 0xf8, 0x90, 0xc3, 0xfd, 0x5d, 0x84, 0x7e, 0xa3, 0x6d, 0x1d, 0x82, 0xeb, 0xe7, 0x1e, 0xf8, 0x6b, 0x4a, 0x5a, 0x3b, 0xf8, 0xdb, 0x83, 0xc3, 0x5e, 0x78, 0x6a, 0x30, 0xc7, 0x76,\n\t0x85, 0x62, 0xb9, 0xd2, 0x3d, 0xa7, 0xf3, 0x9e, 0x18, 0xcc, 0x39, 0x6a, 0xb0, 0x7b, 0xde, 0x52, 0xef, 0xb2, 0x9f, 0x3f, 0x29, 0xe1, 0xd0, 0xb7, 0x25, 0x2f, 0x03, 0x94, 0xf7, 0xc0, 0x8f, 0xa0, 0x3c, 0x88, 0x0a, 0x95, 0x85, 0x41, 0x83, 0x50, 0x3b, 0x1a, 0x14, 0x01, 0xcd, 0x40, 0x6b, 0xd0, 0x0e, 0x54, 0x07, 0xab, 0x5c, 0x99, 0x80, 0x3c, 0xbc, 0x3f, 0x3a, 0xc4, 0xe3, 0x17, 0x70, 0x1c, 0xf0, 0x2e, 0xbe, 0x5f, 0x11, 0xd4, 0x49, 0xc5, 0x03, 0xb4, 0xba, 0xff, 0x0e, 0x58, 0x43, 0xbd, 0x4f, 0x48, 0x46, 0xf9, 0x10, 0xaf, 0x06, 0xa9, 0xbc, 0x1f, 0x58, 0x21, 0x44, 0x85, 0xe6, 0xbb, 0xfd, 0x53, 0xc0, 0x40, 0xd0, 0x0d, 0x8c, 0x07, 0xfd, 0x52, 0xeb, 0xf7, 0xae, 0xa4, 0xc2, 0xd5, 0xed, 0xc1, 0x07, 0x7a, 0x5b, 0x79, 0xe5, 0x51, 0xb0, 0x46, 0xf5, 0xa1, 0xfc, 0x0b, 0xe8, 0xef, 0x40,\n\t0xf9, 0x17, 0xd0, 0xdf, 0x8e, 0xf2, 0x2f, 0x70, 0xd7, 0x3a, 0xca, 0xbf, 0x80, 0xfe, 0xbe, 0x94, 0x7f, 0x87, 0xff, 0x2d, 0x3d, 0xfe, 0x89, 0xfe, 0xff, 0x15, 0x3d, 0xfe, 0xc9, 0xcf, 0xff, 0x2b, 0x7a, 0x84, 0xf2, 0xf1, 0xe7, 0x50, 0x2e, 0xfe, 0xfc, 0xe4, 0xb3, 0x90, 0xfa, 0x1d, 0x24, 0xf8, 0x3d, 0x24, 0x1f, 0x34, 0x7a, 0x28, 0x0f, 0x1b, 0xa4, 0xe6, 0xa5, 0x9b, 0x9f, 0x69, 0xb9, 0x7a, 0xdf, 0x0e, 0xee, 0xed, 0x79, 0xee, 0x58, 0xbf, 0xca, 0xfe, 0x17, 0x72, 0xd5, 0x9d, 0xf7, 0x01, 0xf5, 0xaa, 0x8f, 0x3c, 0x5b, 0xaf, 0x83, 0xf5, 0x80, 0x37, 0xdc, 0xbd, 0x4f, 0xfe, 0x7c, 0x8e, 0x1e, 0xe4, 0x4a, 0xc5, 0xbd, 0xcc, 0xe0, 0x23, 0x00, 0xcf, 0xbb, 0xec, 0x6f, 0xef, 0xa1, 0xd3, 0xbd, 0xdb, 0x21, 0x1e, 0xe8, 0x74, 0x8f, 0x77, 0xdd, 0xbd, 0x32, 0x80, 0x13, 0xc3, 0xbd, 0x15, 0x80,\n\t0xfe, 0x7b, 0x2d, 0x42, 0xcf, 0xeb, 0xa3, 0x68, 0xf7, 0x38, 0xd2, 0xf4, 0x4a, 0x45, 0xf0, 0xfb, 0xe4, 0x7f, 0x15, 0xcd, 0x02, 0x81, 0xff, 0x88, 0xfe, 0x5f, 0xa1, 0x43, 0x5a, 0x3d, 0xd0, 0x0c, 0x54, 0x06, 0xcb, 0x43, 0xed, 0x06, 0xa0, 0xe2, 0x23, 0xed, 0x3b, 0x7f, 0x9d, 0xff, 0x2f, 0xe6, 0x60, 0x71, 0x10, 0xf4, 0xbb, 0xdf, 0x5c, 0x83, 0xa8, 0x13, 0xb8, 0x11, 0xfc, 0xf6, 0xea, 0xa2, 0xa0, 0xd8, 0x0f, 0xeb, 0x2e, 0xca, 0xb3, 0x47, 0x7e, 0x14, 0xee, 0xb7, 0xd9, 0xa6, 0xe2, 0x0b, 0xae, 0xef, 0x6e, 0x9b, 0x77, 0xc6, 0x93, 0x70, 0xf6, 0x49, 0x8a, 0x3d, 0x31, 0xf5, 0xfb, 0xed, 0x63, 0xdf, 0x70, 0xff, 0x05, 0x8c, 0x02, 0xe2, 0xf9, 0x37, 0x34, 0xf6, 0x13, 0xed, 0x17, 0x1e, 0xd6, 0xb7, 0x05, 0xde, 0xf9, 0xfb, 0x39, 0x81, 0xfc, 0xfa, 0xc4, 0x07, 0xe5, 0x00, 0x65, 0xa0, 0x10,\n\t0x65, 0x09, 0x10, 0xa6, 0x4f, 0x09, 0x34, 0xa3, 0x5d, 0xf9, 0xb1, 0xef, 0xca, 0xff, 0x84, 0xb4, 0xef, 0xc8, 0x12, 0xe8, 0x95, 0x56, 0xff, 0x2b, 0x02, 0xf9, 0x8d, 0xbb, 0x0f, 0xca, 0x01, 0xb7, 0x7c, 0x8e, 0x76, 0x21, 0xca, 0x12, 0x20, 0xcc, 0x6d, 0x33, 0xb7, 0x19, 0x7d, 0x65, 0xfe, 0x2b, 0xb4, 0x6a, 0x74, 0x60, 0x95, 0x1a, 0x2d, 0x33, 0x29, 0x4f, 0x87, 0xf0, 0x05, 0x6d, 0x8d, 0xf2, 0x0a, 0xe5, 0xf2, 0xe0, 0x77, 0xef, 0xe8, 0x40, 0x9b, 0x50, 0x7f, 0x4a, 0xa8, 0x4c, 0x00, 0xaf, 0x52, 0xff, 0x0c, 0x94, 0x4a, 0xa5, 0x0d, 0xfc, 0x96, 0x3a, 0x16, 0xc8, 0xa0, 0x46, 0x3f, 0x88, 0x04, 0x6e, 0x39, 0x98, 0x76, 0x76, 0xca, 0x7c, 0xc0, 0x1b, 0x6a, 0x57, 0x06, 0xe1, 0x8f, 0xc8, 0x48, 0x71, 0x61, 0xbc, 0x25, 0x29, 0xee, 0xb7, 0xf5, 0x20, 0xba, 0xa4, 0x7e, 0x63, 0xff, 0x3b, 0xe8,\n\t0x1e, 0xce, 0x3c, 0xee, 0xb7, 0xf7, 0x5c, 0x92, 0x35, 0x58, 0x7a, 0x24, 0x43, 0xa8, 0x4c, 0xe1, 0x2c, 0x9e, 0xe2, 0x31, 0x52, 0xbf, 0xc7, 0x3f, 0x89, 0x7f, 0xf6, 0xe5, 0xe3, 0xb0, 0x3b, 0x43, 0x7f, 0xf1, 0xcf, 0xef, 0xf8, 0xff, 0x12, 0xb1, 0x81, 0xe7, 0xff, 0x4b, 0x74, 0xff, 0x11, 0x02, 0xb5, 0x3d, 0x75, 0x1f, 0xb4, 0x05, 0x94, 0x81, 0x86, 0x94, 0x71, 0xa0, 0x06, 0xf5, 0xbe, 0xa9, 0x6d, 0x68, 0x62, 0x24, 0x21, 0x78, 0xb7, 0xe0, 0x51, 0x1c, 0x63, 0x8f, 0x95, 0x56, 0xdf, 0x01, 0xae, 0x3e, 0x86, 0x9e, 0x4f, 0xb4, 0x53, 0x1e, 0xbb, 0x8f, 0xf0, 0xef, 0xe0, 0xde, 0x57, 0x78, 0x12, 0x47, 0x02, 0x1f, 0x3c, 0xd9, 0xf7, 0xf0, 0x3e, 0xc3, 0xff, 0x34, 0x42, 0xeb, 0x8c, 0x7b, 0x47, 0xe2, 0xef, 0xe0, 0xde, 0x9b, 0x78, 0x14, 0xc1, 0x3b, 0x14, 0x4f, 0xe2, 0xa7, 0x07, 0x3f, 0xfc,\n\t0x6d, 0x7f, 0xea, 0xd8, 0x11, 0xfd, 0xa7, 0xfb, 0xdb, 0xc0, 0x2e, 0xea, 0x05, 0xc0, 0x09, 0x70, 0xf2, 0xe1, 0xf8, 0xc5, 0xc0, 0x3d, 0xf7, 0x4e, 0xc6, 0x3f, 0x21, 0xed, 0xae, 0xc6, 0x7f, 0x84, 0x4b, 0x81, 0xd1, 0xff, 0xf9, 0x1c, 0xf6, 0xe3, 0x25, 0xfe, 0xd2, 0x5f, 0x36, 0xed, 0x9e, 0x48, 0x1a, 0xd2, 0xbe, 0x1b, 0x04, 0xd1, 0x2d, 0x74, 0x77, 0xe4, 0x49, 0xbc, 0x15, 0xf8, 0x36, 0xed, 0x4e, 0xc9, 0xc3, 0xef, 0x0a, 0x69, 0x78, 0x3d, 0xb5, 0xb4, 0xec, 0xe0, 0xb7, 0x86, 0xe6, 0xff, 0x7d, 0x04, 0x0e, 0xfe, 0xa5, 0xaf, 0x98, 0xe4, 0xfa, 0x77, 0xf3, 0xdc, 0xbb, 0x2b, 0xea, 0x17, 0x8f, 0xdc, 0x55, 0x79, 0xfd, 0x91, 0x7b, 0x2a, 0x8f, 0xf4, 0x3d, 0xfc, 0x76, 0x52, 0x3c, 0x74, 0x17, 0xe5, 0xf6, 0xe3, 0x7d, 0xc1, 0xf3, 0x8b, 0x7b, 0x0f, 0xe5, 0x9f, 0xf0, 0xa4, 0xdd, 0x21, 0x18,\n\t0x0b, 0x9f, 0xe8, 0xeb, 0x14, 0x78, 0xf5, 0xe1, 0x7d, 0x94, 0x4e, 0x81, 0xd7, 0x28, 0xeb, 0x85, 0xea, 0xbf, 0x6a, 0x3f, 0x06, 0xef, 0xb4, 0x84, 0x10, 0x78, 0x4f, 0xcd, 0x21, 0x5d, 0x28, 0xcf, 0xd1, 0x9e, 0x4c, 0xb9, 0x0f, 0x7c, 0x0c, 0xbe, 0x03, 0x5f, 0x80, 0xf3, 0xca, 0xc9, 0xc0, 0x87, 0xa9, 0x6d, 0xa9, 0xe4, 0x8e, 0xab, 0x7a, 0xb0, 0xff, 0x90, 0xaa, 0x8b, 0xa3, 0x7c, 0xc6, 0xb9, 0x40, 0x97, 0x17, 0x82, 0x74, 0x17, 0x03, 0x35, 0xdd, 0xb3, 0x9a, 0x5a, 0x3a, 0xf0, 0x15, 0x73, 0x36, 0x07, 0xef, 0xca, 0xdc, 0x09, 0xbc, 0x9b, 0x7a, 0x57, 0x26, 0xb0, 0x2a, 0xed, 0xce, 0x4c, 0x10, 0xee, 0x9d, 0x18, 0x8f, 0x4c, 0x53, 0xce, 0x4a, 0x27, 0x30, 0x59, 0x8d, 0x92, 0x7c, 0x94, 0xcf, 0x2a, 0x67, 0x03, 0x9f, 0x82, 0xe3, 0x60, 0x87, 0x3a, 0x4c, 0x6a, 0x6a, 0x3f, 0xc8, 0x4c, 0xcf,\n\t0xf0, 0xe0, 0xf7, 0x9f, 0x3f, 0xf1, 0x36, 0x18, 0xc3, 0xbb, 0xad, 0xd3, 0x23, 0x77, 0x6e, 0xfe, 0x09, 0x5b, 0xa0, 0x6d, 0x1b, 0xba, 0xd7, 0xf0, 0x9f, 0x62, 0xa0, 0x5b, 0x72, 0xae, 0xfc, 0x6f, 0xcf, 0x0d, 0x95, 0x03, 0xff, 0x25, 0x6d, 0xdd, 0xc7, 0x72, 0x3f, 0x39, 0x70, 0xcb, 0xcd, 0x7f, 0xb7, 0x1e, 0xfc, 0x7e, 0x75, 0x46, 0x7a, 0x50, 0x4e, 0x50, 0xef, 0x49, 0xce, 0xd0, 0x37, 0xad, 0xe1, 0x41, 0x5c, 0xe0, 0xcc, 0x77, 0x46, 0xa6, 0xaa, 0x67, 0x02, 0x3f, 0xa6, 0xdd, 0x29, 0xfa, 0xb7, 0xd8, 0x26, 0x35, 0x82, 0x77, 0x8d, 0xdc, 0x7b, 0x46, 0x27, 0xa5, 0x98, 0xfa, 0x69, 0xea, 0xb7, 0xc6, 0x87, 0xf8, 0x35, 0xb0, 0xc1, 0xbd, 0x73, 0x14, 0xc4, 0x19, 0x79, 0xea, 0x61, 0xfd, 0xc9, 0xb6, 0x5b, 0xff, 0x1a, 0x50, 0x1a, 0x19, 0xa5, 0xa8, 0x8b, 0xb4, 0x31, 0xb3, 0x6d, 0x08, 0x6d,\n\t0xe4, 0xa9, 0x87, 0xf5, 0x27, 0xdb, 0x6e, 0x3d, 0x0d, 0x93, 0x68, 0x4f, 0xfa, 0x93, 0xee, 0xe1, 0xfd, 0xa6, 0xbf, 0x43, 0xc7, 0xe0, 0xb7, 0xc1, 0xb1, 0xff, 0x92, 0xe6, 0xef, 0xb0, 0xf2, 0x61, 0x7d, 0x98, 0x7b, 0x6f, 0x2a, 0x88, 0x1c, 0xa9, 0xdf, 0xf8, 0xfe, 0x09, 0xee, 0xbd, 0xaa, 0x34, 0xe8, 0xf5, 0x25, 0x8b, 0x7b, 0xc7, 0xea, 0xbf, 0x0b, 0xf7, 0xfb, 0xa1, 0x7b, 0x3f, 0xeb, 0x2f, 0x38, 0x2d, 0xd1, 0xc1, 0x7b, 0x5a, 0x7f, 0x73, 0x57, 0x4b, 0x8d, 0x79, 0xe4, 0xbe, 0x96, 0x8b, 0x81, 0x92, 0xa0, 0x2c, 0x91, 0x91, 0x4a, 0xcd, 0xc0, 0xdd, 0xe0, 0x9d, 0xad, 0x68, 0x69, 0x17, 0xbc, 0xb3, 0xd5, 0x33, 0xf8, 0xbd, 0x2a, 0x78, 0x67, 0x4b, 0xd9, 0x00, 0x7e, 0x96, 0x32, 0x8f, 0xdd, 0xd7, 0x62, 0x6f, 0xa2, 0xb6, 0x93, 0xf0, 0xe0, 0x9d, 0xad, 0x46, 0x92, 0xc3, 0xbd, 0xb3, 0x15,\n\t0xbc, 0x33, 0xe5, 0xde, 0x95, 0x72, 0xef, 0x49, 0xb5, 0x08, 0xec, 0xf5, 0x74, 0x91, 0xde, 0x9e, 0xd6, 0x81, 0x11, 0x9e, 0xd6, 0x0f, 0x66, 0x02, 0xb7, 0xfc, 0x9a, 0xf6, 0x38, 0xca, 0xe7, 0xc1, 0xd0, 0x50, 0x7b, 0xb5, 0xa7, 0x55, 0x60, 0x94, 0xfb, 0xdd, 0xfc, 0xdf, 0xd1, 0x06, 0xef, 0x5d, 0xfd, 0xff, 0x80, 0xe0, 0x5d, 0xae, 0x7f, 0x83, 0xe0, 0x3d, 0xaf, 0x0d, 0x52, 0x24, 0x58, 0xfe, 0x2f, 0xc1, 0xbd, 0x3f, 0xa6, 0xe6, 0x09, 0x6c, 0x50, 0xcb, 0x52, 0x4e, 0x91, 0xda, 0xb4, 0xc7, 0xa8, 0xb9, 0x03, 0x7f, 0x80, 0xef, 0xe9, 0x3f, 0x1d, 0x6a, 0xdf, 0x00, 0xdf, 0xa6, 0xb6, 0xa1, 0xcd, 0x1d, 0x48, 0x74, 0x7f, 0x6b, 0x4a, 0x9d, 0x2b, 0x15, 0xa8, 0xef, 0x05, 0x6f, 0x81, 0x0f, 0x8c, 0x5c, 0xe2, 0x0f, 0xde, 0x3b, 0x73, 0xd1, 0x86, 0xbc, 0xfd, 0x1f, 0x82, 0xfb, 0x5d, 0x3f, 0xed,\n\t0xbe, 0xda, 0xff, 0x26, 0xd2, 0xee, 0xbe, 0xb9, 0x77, 0xde, 0x1e, 0xbb, 0xf7, 0xf6, 0x28, 0x1a, 0xa5, 0xee, 0x57, 0xdd, 0x3b, 0x6f, 0x8f, 0x22, 0xf8, 0xdd, 0x2e, 0x53, 0xe8, 0x7e, 0xdb, 0xb3, 0x81, 0x40, 0xda, 0x1d, 0x36, 0xf7, 0xee, 0x5a, 0xf0, 0xfe, 0xda, 0x04, 0x29, 0xa3, 0x4d, 0xe7, 0x79, 0x4a, 0xbb, 0xc7, 0xf6, 0x24, 0x72, 0xca, 0xb4, 0xb4, 0xfb, 0x6c, 0xee, 0x7d, 0xb5, 0xe0, 0x1d, 0xb5, 0x77, 0xa5, 0x92, 0x7b, 0x97, 0x4d, 0x59, 0xc1, 0x33, 0xe1, 0xde, 0x3b, 0xdb, 0x22, 0x83, 0xf5, 0x23, 0x3c, 0x0b, 0x5b, 0xa4, 0x2b, 0xe7, 0xfe, 0xae, 0xca, 0x6b, 0xc1, 0x6f, 0xdc, 0x53, 0xdd, 0x3b, 0x64, 0xec, 0x45, 0xa6, 0x6b, 0xee, 0x3d, 0xde, 0x6c, 0xf2, 0x97, 0x3f, 0xc1, 0x7b, 0x65, 0x85, 0x65, 0x88, 0x67, 0x95, 0xd4, 0xd1, 0xa7, 0xca, 0x4b, 0xe0, 0x8a, 0x67, 0x2d, 0x7b,\n\t0xdb, 0x47, 0xb1, 0x2e, 0xf5, 0x7e, 0xd0, 0x93, 0x08, 0xde, 0x17, 0x7a, 0x12, 0xee, 0xfd, 0xa1, 0x27, 0x10, 0xfa, 0x5d, 0x6c, 0x73, 0xda, 0x7d, 0x20, 0x91, 0x54, 0xb8, 0xbf, 0xcb, 0x05, 0xef, 0x3c, 0x3f, 0x44, 0xe0, 0x73, 0xb0, 0x96, 0x7a, 0x7d, 0xd0, 0x34, 0xf5, 0x77, 0xbc, 0x3f, 0x11, 0xba, 0x2f, 0x54, 0x90, 0xb9, 0x0f, 0xe1, 0xde, 0x1f, 0xa2, 0x0c, 0x41, 0x16, 0xba, 0x70, 0x7f, 0xeb, 0x4b, 0xab, 0x87, 0xf0, 0xd2, 0x13, 0xed, 0x7e, 0xe0, 0x03, 0xf0, 0x56, 0xaa, 0x2e, 0x69, 0xbf, 0x57, 0x3c, 0x84, 0x4b, 0x1f, 0xbc, 0x57, 0x44, 0xf9, 0x08, 0x94, 0x08, 0x17, 0xee, 0xef, 0xcb, 0xb4, 0xd3, 0x90, 0x8f, 0xbe, 0xf1, 0xee, 0x3d, 0x23, 0xea, 0x41, 0xb8, 0xf7, 0x8d, 0x28, 0x83, 0x70, 0xef, 0x1d, 0x51, 0xa6, 0xe1, 0x2c, 0xb4, 0x0e, 0x65, 0xf0, 0xfe, 0x91, 0xb2, 0x55, 0x46,\n\t0xa4, 0xf9, 0x82, 0xbe, 0x5e, 0x20, 0x78, 0x17, 0x29, 0xa4, 0x9b, 0x8b, 0xe0, 0x9d, 0x24, 0xb7, 0x0c, 0xd5, 0xdd, 0x3b, 0xe5, 0x0f, 0xe1, 0xde, 0x51, 0xa2, 0x0c, 0x22, 0x44, 0x17, 0xbc, 0xab, 0x44, 0x19, 0x84, 0x7b, 0x67, 0x89, 0x32, 0x08, 0xf7, 0xee, 0x12, 0x65, 0x10, 0xee, 0x1d, 0xa6, 0xb4, 0x7e, 0xf7, 0x2e, 0x13, 0x65, 0x10, 0xee, 0x9d, 0xa6, 0x87, 0xfd, 0x9d, 0x1f, 0xa3, 0x71, 0xef, 0xcc, 0x07, 0xe1, 0xde, 0x75, 0xa2, 0x0c, 0xc2, 0xfd, 0x2d, 0x95, 0xf2, 0x21, 0xdc, 0xfb, 0x4f, 0x94, 0x41, 0xb8, 0xf7, 0xa0, 0x28, 0x83, 0x70, 0xef, 0x43, 0xa5, 0xf9, 0x20, 0xf5, 0x4e, 0x54, 0x2a, 0x9e, 0xa8, 0xa7, 0xc6, 0xd8, 0x71, 0x7d, 0xf4, 0x10, 0x59, 0x83, 0x77, 0x98, 0x5c, 0xac, 0x65, 0xed, 0x73, 0xef, 0xdf, 0xec, 0x91, 0x12, 0x6a, 0xa7, 0xc0, 0x0c, 0x2d, 0x73, 0xa0, 0xbe,\n\t0xb6, 0x3f, 0x70, 0x5f, 0x2b, 0x14, 0x98, 0xae, 0xe5, 0x95, 0x70, 0xf7, 0x2e, 0x88, 0x7b, 0x87, 0xc3, 0xbd, 0xbf, 0x91, 0x76, 0x77, 0xe3, 0xdf, 0xdd, 0xdb, 0xf8, 0xdb, 0xbb, 0x1a, 0xa1, 0xbb, 0x09, 0xc8, 0x4e, 0x72, 0xe1, 0xde, 0x49, 0xd0, 0x6f, 0x07, 0x24, 0x78, 0x8f, 0xe0, 0xf6, 0xfd, 0x43, 0x60, 0x87, 0x7e, 0xfb, 0x41, 0x69, 0xf0, 0x23, 0x38, 0x99, 0xda, 0xef, 0xe2, 0xc1, 0x27, 0x9c, 0x07, 0x83, 0xdf, 0xe6, 0x83, 0x6b, 0x40, 0xb1, 0xd4, 0xbb, 0x41, 0xee, 0x7e, 0x88, 0x9c, 0x0e, 0x7e, 0xa3, 0x81, 0x5f, 0x10, 0xee, 0x77, 0x1a, 0xf7, 0x0e, 0x71, 0xea, 0x3d, 0xe2, 0x3f, 0xeb, 0xee, 0xf7, 0x61, 0xf7, 0xbb, 0xaf, 0xfb, 0x3b, 0x8a, 0xbb, 0xe7, 0x77, 0x7f, 0x4b, 0x31, 0x1b, 0x89, 0xcf, 0xa8, 0x25, 0xa5, 0xdc, 0x4f, 0x25, 0x21, 0xe4, 0x4d, 0xbd, 0xd9, 0x9f, 0x65, 0x69,\n\t0xf0, 0xce, 0xbe, 0xdb, 0xd6, 0xb3, 0xb8, 0x77, 0xdd, 0x6e, 0xc9, 0x78, 0xf1, 0x04, 0xbf, 0x1c, 0x8c, 0x55, 0x9b, 0xab, 0x4f, 0xab, 0xbd, 0xd5, 0xe1, 0xea, 0x08, 0xf5, 0x39, 0x75, 0x92, 0xba, 0x50, 0x5d, 0xa5, 0x6e, 0xd4, 0xfa, 0x6b, 0x43, 0xb5, 0xb1, 0xda, 0x74, 0x6d, 0x86, 0xf6, 0x8a, 0xf6, 0x91, 0x3e, 0xc5, 0xc8, 0x9a, 0xa1, 0x66, 0xbe, 0x74, 0xf9, 0x32, 0xe4, 0x2b, 0x92, 0xaf, 0x68, 0xbe, 0x98, 0x7c, 0xab, 0xf2, 0xed, 0xce, 0xf7, 0x7e, 0xfe, 0x25, 0xf9, 0x97, 0xe7, 0xff, 0x3d, 0x3c, 0x7b, 0x78, 0xbe, 0xf0, 0xba, 0xe1, 0x4d, 0xc3, 0xdb, 0x85, 0x27, 0x84, 0x3f, 0x1d, 0xde, 0x31, 0x7c, 0x4c, 0xf8, 0xf6, 0xf0, 0x23, 0xe1, 0x9f, 0x86, 0x9f, 0x0e, 0xff, 0x25, 0xfc, 0x46, 0xf8, 0x03, 0x5f, 0x26, 0x5f, 0x01, 0x5f, 0x61, 0x5f, 0x69, 0x5f, 0x79, 0x5f, 0x15, 0x5f, 0x0d,\n\t0x5f, 0x1d, 0x5f, 0x27, 0xdf, 0x40, 0xdf, 0x48, 0xdf, 0x38, 0xdf, 0x2c, 0xdf, 0x3c, 0xdf, 0x1a, 0xdf, 0x26, 0xdf, 0x0e, 0xdf, 0x6e, 0xdf, 0xd7, 0x11, 0x46, 0x44, 0xd6, 0x88, 0x9c, 0x11, 0xbe, 0x88, 0x02, 0x11, 0x85, 0x23, 0x4a, 0x46, 0x94, 0x8d, 0x68, 0x16, 0xd1, 0x29, 0x62, 0x52, 0xc4, 0xa2, 0x88, 0xf5, 0x05, 0xd4, 0x02, 0x19, 0x0b, 0x64, 0x29, 0x90, 0xbd, 0x40, 0x9e, 0x02, 0xe1, 0x05, 0x8a, 0x16, 0x28, 0x5e, 0xa0, 0x41, 0x81, 0xa4, 0x02, 0x5d, 0x23, 0xd5, 0xc8, 0x4c, 0x91, 0x11, 0x05, 0x07, 0x17, 0xfc, 0xb1, 0xe0, 0x8d, 0x42, 0x6c, 0x0e, 0x0a, 0xa5, 0x2b, 0x94, 0xa9, 0x50, 0xb6, 0x42, 0xb9, 0x0a, 0xbd, 0x52, 0x68, 0x63, 0xa1, 0x63, 0x85, 0x8e, 0x17, 0xfa, 0xa1, 0xb0, 0x14, 0xae, 0x56, 0xb8, 0xe7, 0x53, 0xe3, 0xa2, 0xfa, 0x44, 0x0d, 0x2f, 0x99, 0x73, 0x5d, 0x9e,\n\t0x75, 0x11, 0x77, 0x02, 0x77, 0xf5, 0x07, 0x91, 0x0f, 0x02, 0x81, 0x40, 0x70, 0x31, 0xf3, 0xc9, 0x4a, 0x35, 0x4e, 0xed, 0xa0, 0xf6, 0xc1, 0xee, 0x91, 0xd8, 0x3d, 0x59, 0x5d, 0xa4, 0xae, 0x56, 0x37, 0x69, 0x43, 0xb4, 0x51, 0xda, 0x24, 0xec, 0x9e, 0xa5, 0xad, 0xd6, 0x4e, 0xe8, 0x53, 0xb1, 0x5b, 0xf2, 0xa5, 0xcf, 0x97, 0x11, 0xbb, 0x8b, 0xe5, 0x8b, 0xcd, 0xb7, 0x3a, 0xdf, 0x9e, 0x7c, 0x0f, 0xb0, 0x7b, 0x65, 0xb8, 0x84, 0xe7, 0x0a, 0xf7, 0x85, 0x37, 0x08, 0x8f, 0x0b, 0xd9, 0xdd, 0x29, 0x7c, 0x7c, 0xf8, 0x1b, 0xe1, 0xef, 0x84, 0x7f, 0x1e, 0xfe, 0x75, 0xf8, 0x6f, 0xe1, 0xb7, 0x7c, 0xe2, 0xcb, 0x82, 0xdd, 0xa5, 0x7c, 0x65, 0x7d, 0x95, 0x7d, 0xd5, 0xb0, 0xfb, 0x19, 0xdf, 0x00, 0xdf, 0x10, 0xdf, 0x28, 0xdf, 0x78, 0xdf, 0x6c, 0xdf, 0x4a, 0xdf, 0xab, 0xbe, 0xd7, 0x7d, 0x3b,\n\t0x43, 0x76, 0xe7, 0x78, 0xc4, 0xee, 0xa6, 0x11, 0xad, 0x22, 0x9e, 0x8b, 0x78, 0x31, 0x64, 0x77, 0x66, 0xec, 0xce, 0x5d, 0x20, 0x7f, 0xc8, 0xee, 0xc4, 0x02, 0xc9, 0x41, 0xbb, 0x7d, 0x05, 0x13, 0xb1, 0xfb, 0xa7, 0x82, 0x81, 0xc7, 0xec, 0xde, 0x50, 0xe8, 0xfd, 0x47, 0xec, 0x1e, 0x16, 0x95, 0x18, 0x35, 0x04, 0xbb, 0x73, 0xae, 0xf3, 0x61, 0xb7, 0x3c, 0xf0, 0x05, 0xed, 0x4e, 0xfd, 0x7f, 0x79, 0x74, 0x00, 0x6d, 0xac, 0x7c, 0xd2, 0xda, 0xce, 0x10, 0x7c, 0x66, 0xc9, 0xb9, 0xfb, 0xa3, 0x82, 0xdf, 0x29, 0xa7, 0xa7, 0xad, 0xf4, 0xb7, 0xc3, 0xbf, 0x7f, 0x20, 0xf2, 0xfd, 0xbd, 0x9f, 0xfb, 0x7d, 0x7f, 0x97, 0xf2, 0x80, 0xdb, 0x77, 0xf1, 0xa9, 0x47, 0xdf, 0x05, 0x97, 0x4b, 0xf1, 0x5f, 0x94, 0xfc, 0xcd, 0x9f, 0x6f, 0xb2, 0x07, 0xff, 0xb6, 0x41, 0x9f, 0xef, 0x75, 0x91, 0x0b, 0xdd,\n\t0xa8, 0xe5, 0x14, 0xf9, 0x8e, 0x35, 0xe1, 0xbb, 0xbe, 0xdf, 0x67, 0xf8, 0xae, 0xf3, 0xf9, 0xde, 0xe7, 0x59, 0xdf, 0xcf, 0xd7, 0x3d, 0x1f, 0x73, 0xe9, 0xe6, 0xf9, 0x97, 0xbe, 0xa9, 0x96, 0x36, 0xf3, 0xbb, 0xed, 0xe7, 0x0e, 0x9d, 0x7b, 0x53, 0xe4, 0xdb, 0x09, 0x41, 0x0e, 0xf7, 0xce, 0x2d, 0x3a, 0xc7, 0x7a, 0x75, 0x2e, 0xe1, 0x9b, 0x42, 0xdf, 0xe4, 0xfa, 0xc6, 0x3e, 0x2f, 0xe7, 0x86, 0x9e, 0x9f, 0x42, 0xbb, 0xd8, 0xb9, 0x88, 0x73, 0xf9, 0xcf, 0x85, 0x9d, 0xcb, 0x75, 0xee, 0xab, 0x73, 0x9f, 0xd0, 0xde, 0x02, 0x5d, 0xae, 0xb3, 0xa7, 0xcf, 0xe6, 0xfa, 0xfa, 0x57, 0x77, 0xde, 0x17, 0xe1, 0xcf, 0x2c, 0x7e, 0xe6, 0xe5, 0x74, 0x48, 0x34, 0x13, 0x3d, 0x93, 0x83, 0x36, 0xdf, 0x60, 0x47, 0x28, 0x46, 0xba, 0x3f, 0x75, 0x34, 0x7c, 0xa0, 0xb4, 0x88, 0x67, 0xbb, 0x67, 0x2f, 0x7f,\n\t0xbf, 0xe3, 0xb9, 0x62, 0xc6, 0x58, 0xee, 0xf7, 0x4f, 0xb1, 0x0f, 0xa6, 0x52, 0xd8, 0xf4, 0x3b, 0x23, 0x9c, 0xf9, 0x22, 0xde, 0x8f, 0xd2, 0x8d, 0x4f, 0xb7, 0x21, 0xdd, 0xf6, 0x74, 0x0f, 0xd2, 0x5b, 0xa9, 0x63, 0xe9, 0x33, 0xa5, 0x6f, 0x92, 0x7e, 0x7b, 0xfa, 0x13, 0xe9, 0x7f, 0x4c, 0x7f, 0x23, 0x43, 0xae, 0x0c, 0x79, 0x33, 0x44, 0x65, 0x68, 0x22, 0x92, 0xa1, 0x57, 0x86, 0x3e, 0xfc, 0xed, 0xbe, 0x2d, 0x82, 0x7f, 0x07, 0xc1, 0x13, 0x96, 0x61, 0xec, 0x9f, 0x72, 0x33, 0x4c, 0x7c, 0xa4, 0x3e, 0x2a, 0xc3, 0xe8, 0x0c, 0xf3, 0x32, 0xcc, 0x0f, 0xb5, 0x56, 0xb9, 0xc8, 0xb0, 0x26, 0xd4, 0x5a, 0xf9, 0xb8, 0x4f, 0x33, 0xcc, 0x7b, 0xa2, 0x3d, 0xf5, 0xb1, 0xd6, 0xf8, 0x0c, 0x0b, 0x1f, 0xd6, 0xe7, 0xa7, 0xbd, 0xac, 0x95, 0xf2, 0xca, 0x33, 0xca, 0x20, 0xa5, 0x97, 0x3e, 0x5c, 0xe9,\n\t0xa4, 0x74, 0x54, 0xe2, 0x94, 0x16, 0x4a, 0x5b, 0x65, 0x9b, 0x52, 0x89, 0x77, 0x49, 0x15, 0xa5, 0x9e, 0x32, 0x5b, 0x79, 0x51, 0x99, 0xa3, 0xbc, 0xa4, 0xcc, 0x55, 0xe6, 0xe9, 0x43, 0x95, 0x97, 0xf5, 0x61, 0xca, 0x7c, 0xa5, 0xb2, 0x12, 0xad, 0xec, 0x56, 0xde, 0x54, 0xf6, 0x28, 0x15, 0x94, 0x44, 0x56, 0x0c, 0x8f, 0x98, 0x62, 0x8b, 0x57, 0xd2, 0x4b, 0x06, 0xc9, 0x28, 0x99, 0x25, 0xab, 0x64, 0x93, 0xec, 0x92, 0x4b, 0x72, 0x4b, 0x98, 0xe4, 0xe7, 0x09, 0x8a, 0x90, 0x02, 0x52, 0x50, 0x0a, 0x4b, 0x11, 0x29, 0x2a, 0xc5, 0xa4, 0xb8, 0x44, 0x29, 0x2d, 0x95, 0x86, 0x4a, 0x2b, 0xe5, 0x69, 0xa5, 0xa9, 0x6c, 0x90, 0x12, 0x52, 0x5a, 0xca, 0x48, 0x25, 0xa9, 0xca, 0xca, 0xde, 0x51, 0x3a, 0xf1, 0x3e, 0xe9, 0x26, 0x3d, 0xf4, 0x21, 0xd2, 0x47, 0xfa, 0xf2, 0x4e, 0x18, 0x24, 0x43, 0x64,\n\t0x28, 0x2b, 0xd0, 0x68, 0x99, 0x22, 0x53, 0x65, 0x9a, 0x4c, 0x97, 0x17, 0x64, 0x86, 0xd2, 0x5a, 0xa9, 0xaf, 0xb4, 0x51, 0x3a, 0xb0, 0x17, 0x1a, 0xa1, 0xf4, 0x56, 0xfa, 0x28, 0xdd, 0x95, 0x7e, 0x4a, 0x03, 0x25, 0x41, 0x76, 0x28, 0x49, 0x32, 0x53, 0xa9, 0xa3, 0x1c, 0x40, 0xfb, 0x2e, 0xf2, 0xa6, 0xd2, 0x4d, 0xd9, 0xab, 0x8f, 0xd4, 0x47, 0xc9, 0x26, 0x67, 0x9c, 0xd2, 0x9e, 0xf7, 0xd5, 0x61, 0xfd, 0x59, 0x99, 0xa5, 0xd4, 0xd5, 0x47, 0xeb, 0x63, 0xf4, 0xb1, 0xfa, 0x38, 0xb3, 0xb8, 0x19, 0x65, 0x96, 0x30, 0x4b, 0x9a, 0xa5, 0xcc, 0xb2, 0xac, 0xa3, 0x96, 0x39, 0xda, 0x1c, 0x63, 0x8e, 0x35, 0xc7, 0x9b, 0xef, 0x9a, 0x47, 0xcd, 0xf7, 0xcc, 0x0f, 0xc4, 0xb1, 0x34, 0x2b, 0xbd, 0x95, 0xc1, 0xca, 0x68, 0x65, 0xb2, 0x32, 0x2b, 0x3b, 0x24, 0xaf, 0xd5, 0xde, 0x7a, 0xda, 0xea, 0x60,\n\t0x3d, 0x63, 0x8d, 0x91, 0x70, 0x19, 0x65, 0x2d, 0xb4, 0x16, 0x59, 0x8b, 0xad, 0x25, 0xd6, 0x52, 0x6b, 0x05, 0xeb, 0x69, 0x59, 0xeb, 0xb8, 0x75, 0xc2, 0xfa, 0xd8, 0xfa, 0xd4, 0xce, 0x6b, 0xe7, 0xb3, 0xf3, 0xdb, 0x3e, 0xa9, 0x62, 0x37, 0xb6, 0x5b, 0xdb, 0x6d, 0xec, 0xb6, 0x76, 0x3b, 0x3b, 0x9e, 0x77, 0xd9, 0x00, 0x7b, 0xbf, 0x7d, 0xc0, 0x3e, 0x68, 0x1f, 0xb2, 0xbf, 0x97, 0xc1, 0xf6, 0x45, 0xb3, 0xb4, 0xb5, 0xcc, 0x2c, 0x63, 0x2d, 0x17, 0x5d, 0x4a, 0x9a, 0xbd, 0xad, 0x83, 0x66, 0x1f, 0xeb, 0x90, 0xd9, 0xcf, 0x3a, 0x6c, 0xf6, 0xb5, 0xde, 0x32, 0x07, 0x4b, 0xb4, 0x39, 0x4a, 0x2a, 0x9b, 0x13, 0xac, 0x93, 0xe6, 0x44, 0xeb, 0x33, 0xf3, 0x39, 0xeb, 0x73, 0x49, 0x27, 0xd5, 0xcc, 0x71, 0xd6, 0x27, 0xe6, 0x1a, 0x2b, 0x60, 0xbe, 0x6a, 0x8b, 0xb9, 0xd6, 0x56, 0xcc, 0x75, 0xb6,\n\t0x6a, 0x6e, 0x94, 0x44, 0xc9, 0x24, 0x49, 0xe6, 0xfb, 0x76, 0xb8, 0x79, 0xcc, 0x8e, 0x30, 0x3f, 0xb4, 0x0b, 0x48, 0x16, 0xe9, 0x62, 0x7e, 0x24, 0xc9, 0xe6, 0x65, 0x3b, 0xa7, 0xf9, 0xa3, 0x5d, 0xc6, 0xbc, 0x6a, 0x97, 0x93, 0x9e, 0xe6, 0x75, 0xbb, 0x8a, 0x79, 0xc3, 0xae, 0x2a, 0x39, 0xa5, 0xb7, 0xf1, 0x93, 0x91, 0x4d, 0x72, 0x48, 0x2f, 0x4b, 0xb1, 0x1b, 0x5a, 0xba, 0xdd, 0xc4, 0x52, 0xed, 0x46, 0xce, 0x29, 0xc9, 0x23, 0xfd, 0xac, 0x2c, 0x76, 0x82, 0x95, 0xd5, 0x6e, 0x6f, 0x65, 0xb3, 0x9f, 0x66, 0x2f, 0x32, 0xd0, 0xaa, 0x6e, 0x4f, 0xb0, 0x6a, 0xda, 0xcf, 0x59, 0x35, 0xec, 0x89, 0x56, 0x3d, 0xfb, 0x05, 0xab, 0xbe, 0x3d, 0x43, 0x22, 0x65, 0xb8, 0xd5, 0xc0, 0x9e, 0x69, 0xb5, 0xb6, 0x17, 0x5a, 0x71, 0x32, 0x46, 0x0a, 0xc9, 0x58, 0xab, 0xa3, 0x71, 0xc5, 0xea, 0x64, 0xbf,\n\t0x65, 0x25, 0xda, 0x87, 0xad, 0x24, 0xfb, 0x88, 0xd5, 0xd9, 0x7e, 0x5b, 0x9e, 0x92, 0xe7, 0xad, 0x21, 0xf6, 0x69, 0x6b, 0xac, 0xfd, 0x83, 0x35, 0xce, 0x9a, 0x63, 0x5f, 0xb7, 0xe6, 0xda, 0x37, 0xad, 0x97, 0xec, 0x1b, 0xf2, 0xac, 0x3a, 0x40, 0xad, 0xed, 0x6c, 0x51, 0x07, 0xaa, 0x31, 0xea, 0x20, 0x35, 0x56, 0xad, 0xa3, 0x0e, 0x36, 0x9f, 0x55, 0xeb, 0xaa, 0xf5, 0xd4, 0x21, 0xea, 0x50, 0xb5, 0xbe, 0xda, 0x40, 0x6d, 0xa8, 0x36, 0x52, 0x87, 0xa9, 0x8d, 0xd5, 0x26, 0xbc, 0x77, 0x9a, 0x1a, 0xf9, 0xd5, 0x66, 0xea, 0x48, 0xbb, 0x9a, 0x3a, 0x8a, 0x77, 0x51, 0x9c, 0xd3, 0x4a, 0x6d, 0xa1, 0xfc, 0xa0, 0x5c, 0x52, 0x5b, 0xaa, 0xcf, 0xaa, 0xad, 0xd4, 0xd1, 0x6a, 0x6b, 0xb5, 0x8d, 0x3a, 0xc6, 0xc9, 0xa5, 0xbe, 0xac, 0x8e, 0x55, 0xdb, 0xaa, 0xe3, 0xd4, 0x76, 0xca, 0x45, 0xe5, 0xb2,\n\t0x1a, 0xaf, 0x26, 0xa8, 0xed, 0xd5, 0xf1, 0xbc, 0xbb, 0x26, 0xb0, 0x8a, 0x77, 0x54, 0x27, 0xf2, 0xf6, 0x9a, 0xaf, 0x3e, 0xc3, 0x4a, 0xbe, 0x40, 0x1d, 0xe1, 0x9c, 0x76, 0xce, 0xa8, 0x0b, 0x9d, 0xcf, 0xbc, 0xef, 0x7b, 0x8f, 0x79, 0x3f, 0x30, 0xff, 0x30, 0xef, 0xda, 0x31, 0x96, 0xd7, 0x4a, 0x67, 0xb7, 0x32, 0x63, 0xad, 0xcd, 0xe6, 0xe7, 0x76, 0x61, 0x2b, 0xdc, 0xee, 0x66, 0x75, 0xb5, 0xdf, 0xb3, 0xba, 0xd9, 0xef, 0x5b, 0xdd, 0xed, 0x0f, 0xac, 0x1e, 0xf6, 0x31, 0xab, 0xa7, 0xfd, 0xa1, 0x3a, 0xd9, 0xac, 0x63, 0x6d, 0x31, 0xeb, 0x5a, 0x7e, 0xb3, 0x8b, 0xb5, 0x5b, 0xed, 0xa4, 0x4e, 0x31, 0xd7, 0xdb, 0x9a, 0xf9, 0x8b, 0x5d, 0xde, 0xf8, 0xda, 0xf8, 0xc6, 0xf2, 0xd9, 0xdd, 0xbd, 0x33, 0x8d, 0x23, 0xc6, 0x61, 0x73, 0x84, 0x39, 0xd2, 0xfa, 0xc8, 0x7c, 0xcd, 0xd6, 0xd5, 0x44,\n\t0x35, 0xc9, 0xf2, 0xd8, 0x4d, 0xcd, 0x72, 0xd6, 0x4a, 0xb3, 0xb3, 0xb5, 0xcb, 0x2a, 0x6f, 0x8f, 0x32, 0xeb, 0x59, 0x6f, 0x9a, 0xf5, 0xad, 0x37, 0xcc, 0x39, 0xd6, 0x4f, 0xe6, 0x4b, 0xd6, 0x8f, 0xe6, 0x17, 0x76, 0x09, 0xf3, 0x94, 0x1d, 0x65, 0x45, 0xd8, 0x23, 0xad, 0x02, 0xf6, 0x08, 0xab, 0x96, 0x3d, 0xdd, 0xaa, 0x6d, 0x4f, 0xb3, 0x7a, 0xd9, 0x9f, 0x59, 0xbd, 0xed, 0x93, 0x56, 0x43, 0x7b, 0x96, 0xd5, 0xc2, 0x5e, 0xe0, 0x9d, 0xa5, 0x3e, 0x6f, 0x6e, 0xb1, 0x33, 0xa9, 0x9d, 0xd5, 0xa9, 0x6a, 0x17, 0x75, 0x9a, 0x9a, 0xac, 0x4e, 0x37, 0x1b, 0x58, 0x29, 0xe6, 0x5c, 0xeb, 0x5b, 0x2b, 0xd2, 0xee, 0x61, 0x15, 0xf4, 0xfc, 0x6e, 0x15, 0xb2, 0x7b, 0x5a, 0x85, 0xed, 0x5e, 0xd6, 0x14, 0xfb, 0xaa, 0xfa, 0x82, 0x3a, 0x43, 0x9d, 0xc9, 0x6e, 0x6c, 0x96, 0x3a, 0xdb, 0x6c, 0x68, 0x0e,\n\t0xb0, 0xde, 0x36, 0x6f, 0x5a, 0x6d, 0xd4, 0x17, 0xd5, 0x39, 0xde, 0x79, 0xea, 0x4b, 0x66, 0x77, 0xb5, 0xab, 0x93, 0xd3, 0x9c, 0x67, 0x7d, 0x67, 0x5e, 0xb1, 0x4b, 0xa9, 0xdd, 0xd4, 0xb9, 0x6a, 0x77, 0x7b, 0x92, 0xda, 0x43, 0x9d, 0xe7, 0xbc, 0xa3, 0xee, 0x54, 0x77, 0x19, 0x79, 0xd5, 0xdd, 0xb6, 0x57, 0xdd, 0xa3, 0xee, 0x55, 0xf7, 0xa9, 0xfb, 0xd5, 0x03, 0xea, 0x41, 0x23, 0x9f, 0xd3, 0xd7, 0x2e, 0xe6, 0x29, 0xe4, 0xbc, 0xa5, 0x5e, 0x51, 0xaf, 0x3a, 0x27, 0xd4, 0x9f, 0xd5, 0x5f, 0xd4, 0x6b, 0xea, 0xaf, 0xde, 0x97, 0xbd, 0xf3, 0x3d, 0x19, 0xd4, 0xbb, 0xea, 0x3d, 0xf5, 0xbe, 0xa3, 0x6b, 0x63, 0x1d, 0x8f, 0x93, 0x5e, 0x1b, 0xa7, 0x8d, 0xd7, 0x26, 0x38, 0x59, 0x9c, 0xec, 0xde, 0xd7, 0xbc, 0x1b, 0x9c, 0x2f, 0x9c, 0x2f, 0x79, 0x6f, 0x4e, 0xd1, 0x26, 0x6b, 0xcf, 0x6b, 0x53,\n\t0x9d, 0x4b, 0xce, 0x65, 0x6d, 0x1a, 0xe7, 0x94, 0xcd, 0xe2, 0xd7, 0x5e, 0x90, 0x37, 0x3d, 0x3f, 0x7b, 0xb2, 0x1a, 0xdf, 0x1b, 0xdf, 0x1a, 0xdf, 0x19, 0x17, 0x78, 0xb7, 0xce, 0x34, 0xee, 0x1b, 0x0f, 0x78, 0xc3, 0xce, 0xd6, 0x5e, 0xd4, 0xe6, 0xb0, 0x97, 0x3f, 0x24, 0x7b, 0xe4, 0x88, 0x6c, 0x93, 0x03, 0xda, 0x4b, 0x46, 0x25, 0x6d, 0xae, 0x63, 0x39, 0x19, 0x9c, 0xac, 0xde, 0xd7, 0xb5, 0x79, 0xda, 0xcb, 0xda, 0x7c, 0x6d, 0x81, 0xb6, 0x50, 0x5b, 0xa4, 0x2d, 0xf6, 0x64, 0x33, 0xd6, 0x38, 0x5f, 0x19, 0xaf, 0x1a, 0x6b, 0x8d, 0x75, 0xc6, 0x7a, 0xe3, 0x35, 0xcf, 0x2f, 0xc6, 0x3d, 0xcf, 0x35, 0xe3, 0x92, 0x71, 0xd7, 0xd8, 0x60, 0x6c, 0x34, 0x36, 0x19, 0xaf, 0x1b, 0x9b, 0x8d, 0x2d, 0x86, 0xdf, 0xf3, 0x94, 0xa7, 0xa8, 0xa7, 0xb8, 0xa7, 0x94, 0xa7, 0x9c, 0x13, 0xf0, 0x54, 0xf0,\n\t0x54, 0xf5, 0x94, 0x31, 0x6d, 0x4f, 0x25, 0x4f, 0x65, 0x4f, 0x09, 0xaf, 0xea, 0x35, 0xbc, 0x96, 0xd7, 0xf1, 0xa6, 0x37, 0x33, 0x7a, 0xb3, 0x78, 0x73, 0xc8, 0x56, 0x4f, 0xac, 0xa7, 0x8e, 0x37, 0x97, 0x37, 0xb7, 0x37, 0xcc, 0xe8, 0xe8, 0xdd, 0xe8, 0xcd, 0xef, 0x0d, 0xf7, 0xfa, 0xbc, 0x11, 0xde, 0x02, 0xde, 0x48, 0xd3, 0x6b, 0x5a, 0xde, 0x82, 0x9e, 0x5f, 0x3d, 0xd5, 0x3d, 0x35, 0xbc, 0x85, 0xbc, 0x85, 0xbd, 0x45, 0x3c, 0xf5, 0x3c, 0xf5, 0x3d, 0x0d, 0xbc, 0x19, 0x3d, 0x0d, 0x3d, 0x8d, 0x9c, 0x6f, 0x9d, 0xef, 0x3c, 0x77, 0x3c, 0x31, 0x9e, 0xcc, 0x9e, 0xba, 0x9e, 0x8b, 0xde, 0x4d, 0xde, 0xa2, 0xde, 0x62, 0xde, 0xe2, 0xde, 0x12, 0xde, 0xd2, 0x9e, 0x30, 0xcf, 0x8f, 0x9e, 0x2b, 0x9e, 0xe6, 0xde, 0x6c, 0x9e, 0x9a, 0x9e, 0x04, 0xef, 0x53, 0xce, 0x05, 0xaf, 0xe9, 0xcd, 0xe7,\n\t0x2d, 0x67, 0xe6, 0x34, 0x73, 0x79, 0x2b, 0x78, 0x2b, 0xaa, 0x79, 0xbd, 0xd1, 0xde, 0xaa, 0xde, 0x1a, 0xde, 0x52, 0xde, 0x5a, 0xde, 0xda, 0xde, 0x18, 0x6f, 0x5d, 0x33, 0xbd, 0xb7, 0xbe, 0xb7, 0x81, 0xb7, 0x91, 0xb7, 0x89, 0xb7, 0x99, 0xb7, 0x85, 0xb7, 0x95, 0xb7, 0x8d, 0x91, 0xc7, 0x1b, 0xef, 0x6d, 0xef, 0xed, 0xe8, 0x4d, 0xf4, 0x76, 0xf1, 0x76, 0xf3, 0xf6, 0xf4, 0xf6, 0xf1, 0xf6, 0xf7, 0x0e, 0xf2, 0x0e, 0xf5, 0x8e, 0xf4, 0x8e, 0xf6, 0x8e, 0x33, 0x1a, 0x7a, 0xe7, 0x18, 0xb7, 0x8d, 0x3b, 0xce, 0xe7, 0x72, 0x45, 0xae, 0x9a, 0x15, 0x9c, 0xef, 0xcd, 0xc9, 0xe6, 0xeb, 0xe6, 0x09, 0x6b, 0x82, 0x93, 0xc7, 0xe9, 0x63, 0x96, 0x37, 0xbb, 0xca, 0xbb, 0x72, 0xd4, 0x9c, 0x64, 0xcd, 0x33, 0x37, 0xc9, 0x7b, 0xe6, 0x71, 0xf3, 0x67, 0x79, 0xdf, 0xbc, 0x67, 0x19, 0xf2, 0x81, 0x95,\n\t0x5d, 0x8e, 0x59, 0x15, 0xe4, 0x43, 0xab, 0xa5, 0x35, 0x5e, 0x3e, 0xb2, 0x46, 0xc8, 0x71, 0x39, 0x61, 0x7e, 0x6c, 0x4d, 0x74, 0x4a, 0x39, 0x0d, 0x9d, 0x96, 0x4e, 0x6f, 0x67, 0x92, 0x7c, 0x2c, 0x9f, 0xc8, 0x49, 0xf9, 0x4c, 0x3e, 0x97, 0x2f, 0xe4, 0x94, 0x7c, 0x29, 0xa7, 0xed, 0xca, 0x72, 0x46, 0xbe, 0x66, 0x7f, 0x7d, 0xce, 0xee, 0x20, 0xdf, 0xc8, 0xb7, 0x72, 0x41, 0xbe, 0x93, 0xef, 0xe5, 0x07, 0xb9, 0x28, 0x97, 0xe5, 0x47, 0xf9, 0xc9, 0x38, 0xeb, 0x3c, 0x67, 0x77, 0x74, 0x26, 0x3a, 0x0b, 0xb4, 0x35, 0xda, 0x3a, 0x6d, 0x99, 0x77, 0xb3, 0x77, 0x8b, 0xb6, 0x49, 0x7b, 0x4d, 0xdb, 0xae, 0xad, 0xd0, 0x36, 0xb3, 0x87, 0xda, 0xaa, 0x2d, 0xd7, 0x5e, 0xd7, 0x56, 0x6a, 0x5b, 0xb4, 0x55, 0x5a, 0x8a, 0x5e, 0x46, 0x8f, 0xd6, 0xcb, 0xea, 0x95, 0xf5, 0x72, 0x7a, 0x15, 0xbd, 0xbc,\n\t0x5e, 0x55, 0xaf, 0xa0, 0x57, 0xd3, 0x2b, 0xea, 0xd5, 0xf5, 0x4a, 0x7a, 0x0d, 0x6d, 0xbd, 0xb6, 0xc1, 0x7a, 0xc7, 0x2e, 0xed, 0xec, 0xd2, 0x5e, 0xd5, 0xd6, 0x5a, 0xd5, 0xb4, 0x6d, 0xe6, 0x40, 0x76, 0x9f, 0x7e, 0x6d, 0xa3, 0xb1, 0xdf, 0xf8, 0xdd, 0xf8, 0xc3, 0x7c, 0xde, 0x9c, 0xaa, 0xa4, 0x73, 0xfc, 0x8a, 0x6d, 0x35, 0x32, 0x3f, 0x31, 0x3f, 0x35, 0x7f, 0x92, 0xdf, 0xe5, 0x0f, 0x25, 0xbd, 0xb3, 0xd3, 0xd9, 0xe1, 0xec, 0x56, 0x14, 0xb3, 0xa2, 0x5c, 0x33, 0xbb, 0xc9, 0xaf, 0x72, 0xdd, 0x9c, 0x22, 0x37, 0xe4, 0xa6, 0xdc, 0x72, 0xb6, 0xcb, 0x6d, 0xb9, 0x63, 0xde, 0x37, 0x37, 0x5b, 0x39, 0xe5, 0x9e, 0x55, 0xd1, 0xec, 0x6f, 0xb5, 0x92, 0xfb, 0x12, 0xb0, 0x46, 0x2a, 0xa2, 0xa8, 0x8a, 0xa6, 0xe8, 0x8a, 0xa1, 0x78, 0x14, 0x53, 0xb1, 0x14, 0x47, 0xf1, 0x5a, 0xaf, 0x28, 0x19,\n\t0x95, 0xcc, 0x4a, 0x16, 0x25, 0x9b, 0xf5, 0x85, 0x92, 0x5d, 0xc9, 0xa1, 0xe4, 0x74, 0xde, 0x53, 0x72, 0x29, 0xb9, 0x95, 0x30, 0x25, 0xaf, 0xfd, 0x8c, 0x12, 0x6e, 0x3f, 0x6b, 0x1d, 0x51, 0x7c, 0xf6, 0x25, 0xa5, 0x80, 0x7d, 0x5e, 0x89, 0x54, 0x0a, 0x29, 0x85, 0x95, 0xa7, 0x94, 0x22, 0x4a, 0x51, 0xa5, 0x98, 0x52, 0x5c, 0x29, 0xa1, 0x94, 0xb4, 0x4e, 0x59, 0x5f, 0x2a, 0xa5, 0x9c, 0xc3, 0x4a, 0x94, 0x3d, 0xdb, 0xce, 0x65, 0x17, 0xb4, 0x4b, 0x2a, 0x79, 0x94, 0x7c, 0x76, 0x0e, 0xe7, 0x23, 0xe7, 0x7d, 0xfb, 0xb2, 0x52, 0x50, 0xaf, 0xa5, 0x37, 0x56, 0x32, 0x28, 0xa5, 0xf5, 0xda, 0x7a, 0x13, 0x3d, 0x46, 0x6f, 0xaa, 0xc7, 0xea, 0xcd, 0xf4, 0x3a, 0x7a, 0x73, 0xbd, 0xae, 0x1e, 0xa7, 0xd7, 0xd3, 0x5b, 0x38, 0xb9, 0xd9, 0x6d, 0xdc, 0x55, 0xf2, 0xcb, 0x03, 0x25, 0xc2, 0x39, 0xe4,\n\t0x9c, 0xd4, 0xeb, 0xeb, 0x2d, 0xf5, 0x06, 0x7a, 0x2b, 0xbd, 0xa1, 0xde, 0xda, 0x7b, 0xd4, 0xfb, 0x9e, 0xde, 0x48, 0x6f, 0x63, 0x24, 0x78, 0xf7, 0x7b, 0x0f, 0x7a, 0x0f, 0x7b, 0xdf, 0x31, 0xda, 0x1b, 0x4f, 0x6b, 0x6f, 0x68, 0xdf, 0x69, 0x6f, 0x6a, 0x17, 0xac, 0xaa, 0xf6, 0x78, 0xf9, 0x4d, 0xc9, 0xaa, 0xed, 0xd4, 0xbe, 0xd7, 0x76, 0x69, 0x3f, 0x68, 0xbb, 0xb5, 0x8b, 0xc6, 0x4d, 0xe3, 0xaa, 0xb6, 0x47, 0xbb, 0xa4, 0xed, 0xd5, 0x2e, 0x6b, 0xfb, 0xb4, 0x1f, 0xb5, 0xfd, 0xda, 0x4f, 0xda, 0x01, 0xed, 0x8a, 0x76, 0x50, 0xbb, 0xaa, 0x1d, 0xd2, 0x7e, 0xd6, 0xde, 0xd2, 0x7e, 0x31, 0x6e, 0x19, 0x3f, 0x6b, 0x87, 0xb5, 0x6b, 0xd6, 0x8b, 0xda, 0xaf, 0xda, 0x11, 0xed, 0x37, 0xed, 0x6d, 0xed, 0xba, 0xf6, 0x8e, 0x76, 0x43, 0x7b, 0x57, 0xbb, 0xa9, 0x1d, 0xd5, 0x6e, 0x69, 0xef, 0x69,\n\t0xb7, 0xb5, 0xf7, 0xb5, 0x3b, 0xda, 0x07, 0xda, 0xef, 0xe6, 0x45, 0x27, 0xc5, 0x39, 0xa2, 0x1d, 0xd3, 0xfe, 0xd0, 0x3e, 0xd4, 0xee, 0x6a, 0x1f, 0x69, 0xf7, 0xb4, 0xe3, 0xda, 0x7d, 0xed, 0x84, 0xf6, 0x40, 0xfb, 0x58, 0x0b, 0x98, 0x97, 0xcc, 0x4e, 0xd6, 0x76, 0x33, 0xd1, 0xda, 0x61, 0x26, 0x5b, 0x7b, 0xcc, 0x55, 0xd6, 0x65, 0xed, 0x13, 0x5d, 0xbc, 0xbb, 0xbc, 0x7b, 0x9d, 0xad, 0xce, 0xdb, 0xce, 0x36, 0xe7, 0xa8, 0xf6, 0xa9, 0xae, 0x38, 0x6f, 0x38, 0xc7, 0x9c, 0x37, 0x9d, 0x0f, 0xad, 0x72, 0xf6, 0x70, 0xed, 0xa4, 0xae, 0x7a, 0x77, 0x7b, 0xf7, 0x39, 0x07, 0x9d, 0x4f, 0x9d, 0x3d, 0xf6, 0x35, 0x67, 0xaf, 0xfd, 0xab, 0xb3, 0xcf, 0xfe, 0xcd, 0xd9, 0xef, 0x7c, 0xac, 0x7d, 0xa6, 0x6b, 0xce, 0x01, 0xe7, 0x13, 0xed, 0x73, 0x5d, 0xd7, 0xbe, 0xd0, 0x0d, 0xed, 0x94, 0xee, 0xd1,\n\t0xbe, 0xb4, 0x3e, 0xd4, 0xbe, 0xd2, 0x4d, 0xed, 0xb4, 0x6e, 0x69, 0x67, 0x74, 0x5b, 0xfb, 0x5a, 0x77, 0xb4, 0xb3, 0xba, 0x57, 0x3b, 0xa7, 0xa7, 0xd3, 0xce, 0xeb, 0xe9, 0xb5, 0x6f, 0xf4, 0x0c, 0xda, 0xb7, 0x7a, 0x46, 0xe7, 0xb8, 0xf3, 0x81, 0xfd, 0x87, 0x56, 0x43, 0xab, 0xa9, 0xd5, 0xb2, 0xef, 0xd9, 0x0f, 0xec, 0x80, 0x56, 0x5b, 0x8b, 0xd1, 0x62, 0x1d, 0x55, 0xab, 0xe3, 0x98, 0x8e, 0xad, 0xd5, 0x75, 0x1c, 0xad, 0x9e, 0x56, 0x5f, 0x6b, 0xe0, 0xa4, 0x73, 0x32, 0x3a, 0x99, 0xb4, 0x86, 0x5a, 0x23, 0x27, 0xb3, 0xd6, 0x58, 0x6b, 0xa2, 0x35, 0xd5, 0x9a, 0x69, 0xcd, 0xb5, 0x38, 0x8f, 0xe9, 0x61, 0x39, 0xf7, 0x38, 0x1e, 0xaf, 0x27, 0x9d, 0xd6, 0x42, 0x6b, 0xe9, 0x49, 0xaf, 0xb5, 0x32, 0x2e, 0x1b, 0x3f, 0x7a, 0xc4, 0xa3, 0x68, 0xad, 0x3d, 0xaa, 0x47, 0xf3, 0xe8, 0x5a, 0x1b,\n\t0x8f, 0xe1, 0xf1, 0x68, 0x6d, 0xb5, 0x76, 0x5a, 0xbc, 0xf7, 0x43, 0x23, 0xdc, 0xe9, 0x67, 0x8f, 0xd5, 0x12, 0xb4, 0xf6, 0xd6, 0x01, 0xeb, 0x98, 0x75, 0xd5, 0x4e, 0x67, 0x47, 0x1b, 0x3e, 0xbb, 0xbe, 0xdd, 0xd2, 0x1e, 0x67, 0x4f, 0xb5, 0x5f, 0xf6, 0xce, 0xb5, 0x4f, 0xd9, 0xdf, 0xd9, 0xbf, 0x5b, 0xdb, 0xbc, 0xb3, 0x8d, 0x08, 0xa3, 0x80, 0x11, 0xe9, 0xbc, 0xeb, 0xdd, 0x63, 0x87, 0x19, 0x01, 0xed, 0x69, 0xfb, 0x53, 0xad, 0x83, 0xd6, 0xd1, 0xbe, 0xaf, 0x3d, 0xa3, 0x75, 0xd2, 0x12, 0x1d, 0x45, 0x4b, 0x72, 0x34, 0x27, 0x07, 0x67, 0x90, 0x67, 0xb5, 0xd1, 0xda, 0x18, 0xef, 0x44, 0xef, 0x64, 0xb5, 0xba, 0x77, 0xaa, 0x99, 0xdb, 0xcc, 0x63, 0x86, 0x99, 0x79, 0xcd, 0x7c, 0x66, 0x7e, 0xef, 0x70, 0xef, 0x74, 0xef, 0x0c, 0x33, 0xc9, 0xda, 0x69, 0xf6, 0xb0, 0xf6, 0x9a, 0x3d, 0xad,\n\t0x7d, 0x66, 0x2f, 0x6b, 0xbf, 0x39, 0xc8, 0x7a, 0xd7, 0x1c, 0x62, 0x1d, 0x35, 0x87, 0x5a, 0xef, 0x99, 0xc3, 0xac, 0xf7, 0x8d, 0x1f, 0x8c, 0x8b, 0xe6, 0x70, 0xeb, 0x03, 0xf3, 0x65, 0xeb, 0x82, 0x39, 0xdf, 0xfa, 0xde, 0x5c, 0x60, 0xfd, 0x60, 0x2e, 0xb4, 0x2e, 0x9a, 0x8b, 0xac, 0x4b, 0xe6, 0x6a, 0xeb, 0x8a, 0xb9, 0xc1, 0x36, 0x4c, 0xbf, 0x9d, 0xd9, 0x4c, 0xb1, 0xb3, 0x98, 0x5b, 0xed, 0xac, 0x9e, 0x02, 0x76, 0x36, 0x73, 0x9b, 0xa7, 0xa0, 0xf9, 0xa5, 0x9d, 0xc7, 0xfc, 0xca, 0x2e, 0x62, 0x5e, 0xb3, 0x2b, 0x98, 0xbf, 0xda, 0x15, 0xcd, 0xdf, 0xec, 0x4a, 0xe6, 0x2d, 0xbb, 0xba, 0x79, 0xdb, 0xae, 0x61, 0xde, 0xb1, 0x6b, 0x9a, 0xbf, 0xdb, 0xb5, 0xcc, 0x07, 0x76, 0x1d, 0x33, 0x60, 0xd7, 0xb5, 0xc4, 0xae, 0x67, 0x99, 0x76, 0x33, 0xcb, 0xb2, 0x9b, 0x5b, 0xb6, 0x1d, 0x67, 0x39,\n\t0x76, 0x0b, 0xeb, 0x29, 0xbb, 0xb7, 0x55, 0xc4, 0xee, 0x63, 0x15, 0xb5, 0xfb, 0x5a, 0xc5, 0xec, 0x7e, 0x56, 0x25, 0x7b, 0xb4, 0x15, 0x6d, 0x8f, 0xb1, 0x62, 0xec, 0xc9, 0x56, 0xac, 0x3d, 0xc5, 0xaa, 0x63, 0x3f, 0x6f, 0xd5, 0xf5, 0x44, 0x5a, 0x8d, 0xed, 0x17, 0xad, 0x26, 0xf6, 0x1c, 0xab, 0xa9, 0xfd, 0x92, 0xd5, 0xcc, 0x9e, 0x6b, 0x35, 0xb7, 0xe7, 0x59, 0x6d, 0xed, 0x45, 0x56, 0x3b, 0x7b, 0xb1, 0x15, 0x6f, 0x2f, 0xb1, 0x12, 0xec, 0xa5, 0x6a, 0x4f, 0xfb, 0x23, 0xab, 0x8f, 0x7d, 0xdc, 0xea, 0x6b, 0x9f, 0xb0, 0xfa, 0xd9, 0x1f, 0x5b, 0xfd, 0xed, 0x4f, 0xac, 0x01, 0xf6, 0xe7, 0xd6, 0x40, 0xfb, 0x0b, 0x6b, 0x90, 0xfd, 0xa5, 0x35, 0xd8, 0xfe, 0xca, 0x1a, 0x6a, 0x9f, 0xb1, 0x86, 0xd9, 0x5f, 0x5b, 0xc3, 0xed, 0xb3, 0xd6, 0x28, 0xfb, 0x1b, 0xeb, 0x59, 0xfb, 0x5b, 0xeb, 0x79,\n\t0xfb, 0x67, 0xeb, 0x65, 0xfb, 0x96, 0x35, 0xdf, 0xbe, 0x6d, 0x2d, 0xb0, 0xef, 0xd8, 0xd9, 0x3d, 0x85, 0xed, 0x73, 0xf6, 0x2f, 0xde, 0x3a, 0xf6, 0x7c, 0xb3, 0x92, 0xb5, 0xca, 0x8c, 0xb6, 0x56, 0x9b, 0x95, 0xad, 0x35, 0x66, 0x15, 0xeb, 0x55, 0xb3, 0xaa, 0xb5, 0xd6, 0xac, 0x66, 0xad, 0x33, 0xab, 0x5b, 0xeb, 0xcd, 0x1a, 0xd6, 0x6b, 0x66, 0x4d, 0x6b, 0x83, 0x59, 0xcb, 0xda, 0x68, 0xd6, 0xb6, 0x36, 0x71, 0x26, 0x78, 0xdd, 0x9c, 0x66, 0x7d, 0x65, 0x4e, 0xb7, 0x4e, 0x9b, 0x2f, 0x58, 0x67, 0xcc, 0x19, 0xd6, 0xd7, 0xe6, 0x4c, 0xeb, 0xac, 0x39, 0xcb, 0x3a, 0x67, 0xce, 0xb6, 0xce, 0x9b, 0x2f, 0x5a, 0xdf, 0x98, 0x27, 0xed, 0x42, 0xe6, 0x67, 0x76, 0x6e, 0x2b, 0x97, 0xdd, 0xc9, 0xca, 0x6d, 0x27, 0x5a, 0x79, 0xec, 0x24, 0x2b, 0xcc, 0xee, 0x6c, 0xe5, 0xb5, 0xbb, 0x58, 0xf9, 0xec,\n\t0x64, 0x2b, 0xbf, 0xdd, 0xd5, 0xf9, 0xd1, 0xb9, 0xe1, 0xfc, 0xe4, 0xdc, 0x74, 0xae, 0x38, 0xb7, 0x9c, 0xab, 0xce, 0x6d, 0xe7, 0x67, 0xe7, 0x8e, 0xd5, 0xc5, 0x7e, 0xd7, 0x4a, 0xb6, 0x8f, 0x3a, 0xbf, 0x38, 0xbf, 0x3b, 0xd7, 0x9c, 0x3f, 0x9c, 0x5f, 0x9d, 0xbb, 0xce, 0x6f, 0xce, 0x3d, 0xe7, 0xba, 0x73, 0xdf, 0x1a, 0x6d, 0x5f, 0xb0, 0x9e, 0xb3, 0x7f, 0xb4, 0x26, 0xdb, 0x57, 0xac, 0x49, 0xf6, 0x4f, 0x4e, 0x69, 0xa7, 0xbc, 0x53, 0xd6, 0xa9, 0xe8, 0x94, 0x71, 0x2a, 0x38, 0xe5, 0x9c, 0x4a, 0x66, 0x23, 0xb3, 0x99, 0xd9, 0xc4, 0x8c, 0x33, 0x1b, 0x9b, 0xcd, 0xcd, 0xa6, 0x66, 0x0b, 0xa7, 0x91, 0xd3, 0xd4, 0x69, 0xe2, 0x34, 0x77, 0x1a, 0x3b, 0xcd, 0xcc, 0xc5, 0xe6, 0x32, 0x73, 0xa9, 0xb9, 0xc2, 0x5c, 0x62, 0x2e, 0x77, 0x5a, 0x3b, 0xf1, 0x4e, 0x5b, 0xa7, 0xbd, 0xd3, 0xc6, 0x49,\n\t0x70, 0xda, 0x39, 0x4f, 0x9b, 0xdb, 0xcd, 0x9d, 0xe6, 0x1b, 0xe6, 0x6e, 0x73, 0x87, 0xb9, 0xcb, 0x7c, 0xd3, 0xdc, 0xe3, 0xf4, 0x77, 0x06, 0x3b, 0x03, 0x9d, 0xa1, 0xce, 0x00, 0x67, 0x88, 0x33, 0xc8, 0x19, 0x66, 0x9e, 0x36, 0xcf, 0x99, 0x5f, 0x9b, 0xdf, 0x98, 0x67, 0xcc, 0xf3, 0xe6, 0x59, 0xf3, 0x5b, 0xbb, 0xbf, 0x3d, 0xc8, 0x1e, 0x68, 0x0f, 0xb1, 0x07, 0xd8, 0x83, 0xad, 0xe2, 0x56, 0x49, 0xab, 0x84, 0x55, 0xda, 0x8a, 0xb2, 0x4a, 0x39, 0x93, 0x9d, 0x69, 0xce, 0xf3, 0xce, 0x0b, 0xce, 0x14, 0x67, 0xba, 0x33, 0xd5, 0x99, 0x61, 0xbd, 0xe0, 0x2c, 0x74, 0x96, 0x3a, 0x8b, 0x9d, 0xe5, 0xce, 0x22, 0x67, 0x99, 0xb3, 0xc4, 0x59, 0xe1, 0xe4, 0x75, 0x7c, 0x4e, 0x7e, 0xa7, 0x80, 0x93, 0xcf, 0x89, 0x70, 0xc2, 0x9d, 0x48, 0xa7, 0xb2, 0x13, 0xed, 0xb4, 0x70, 0xe2, 0x9c, 0x8e, 0x4e,\n\t0x07, 0xe7, 0x59, 0x67, 0x94, 0x3d, 0xcc, 0x1e, 0xea, 0xcc, 0x71, 0x5e, 0x74, 0x5e, 0x71, 0x56, 0x3a, 0x35, 0x9c, 0x18, 0xa7, 0x96, 0x53, 0xc7, 0xa9, 0xe9, 0xc4, 0x3a, 0xb5, 0x9d, 0xba, 0x66, 0x3b, 0xf3, 0x69, 0x33, 0xc1, 0xec, 0x68, 0xc6, 0x9b, 0x1d, 0xcc, 0xf6, 0xe6, 0x33, 0x4e, 0xa2, 0x93, 0xec, 0x74, 0x76, 0xba, 0x39, 0x49, 0x4e, 0x57, 0xa7, 0x8b, 0xd3, 0xdd, 0x3c, 0x60, 0x1e, 0x36, 0x0f, 0x99, 0x6f, 0x9b, 0x07, 0xcd, 0x23, 0xe6, 0x5b, 0xe6, 0x3b, 0xce, 0x1a, 0x67, 0xbd, 0xb3, 0xd6, 0xd9, 0xe0, 0xbc, 0xea, 0xbc, 0xe6, 0xac, 0x73, 0x36, 0x3a, 0x4f, 0x39, 0xc5, 0x9d, 0xa2, 0x4e, 0x09, 0xa7, 0x88, 0x13, 0xe5, 0x14, 0x73, 0x4a, 0x3a, 0xd5, 0x9c, 0xaa, 0x4e, 0x7d, 0xa7, 0xba, 0x53, 0xcf, 0xa9, 0xe2, 0x34, 0x30, 0xdb, 0x98, 0xad, 0xcd, 0x56, 0x66, 0x4b, 0xb3, 0xad,\n\t0x51, 0xcf, 0x68, 0x68, 0x44, 0x1b, 0xd5, 0x8c, 0xba, 0x4e, 0x4f, 0xa7, 0x93, 0xd3, 0xc3, 0x79, 0xc6, 0xe9, 0x65, 0xbe, 0x62, 0xae, 0x34, 0xf7, 0x99, 0x7b, 0xcd, 0xfd, 0x46, 0x0d, 0xa3, 0xba, 0x51, 0xd3, 0x19, 0xeb, 0x8c, 0xe1, 0x14, 0x38, 0xdc, 0x19, 0xed, 0x8c, 0x34, 0x7f, 0x30, 0xbf, 0x37, 0x2f, 0x98, 0xdf, 0x19, 0x31, 0x46, 0x2d, 0xa3, 0xb6, 0x33, 0xcf, 0x99, 0xeb, 0xcc, 0x72, 0x66, 0x3a, 0xe3, 0x9d, 0x09, 0xce, 0x4b, 0xce, 0x6c, 0x6b, 0xb6, 0x35, 0xcb, 0x9a, 0x69, 0xcd, 0xb0, 0xaa, 0x18, 0x75, 0x8c, 0x58, 0xa3, 0xaa, 0xf3, 0xba, 0xb3, 0xda, 0xd9, 0xe4, 0xac, 0x72, 0x36, 0x5b, 0x65, 0xad, 0x32, 0x4e, 0x21, 0xa7, 0xa0, 0x53, 0xd8, 0xa8, 0x62, 0x54, 0x36, 0x1a, 0x1b, 0x4d, 0x8c, 0xa6, 0x46, 0x23, 0xa3, 0x99, 0xd1, 0xdc, 0x88, 0x33, 0x5a, 0x18, 0x2d, 0x8d, 0x56,\n\t0x46, 0x6b, 0xa3, 0xac, 0x51, 0xda, 0x28, 0x63, 0x74, 0x32, 0x12, 0x95, 0x46, 0x46, 0x39, 0xa5, 0xb1, 0xd2, 0xc4, 0xf9, 0xda, 0xf8, 0xc5, 0xf8, 0x55, 0xa9, 0xa6, 0x54, 0x57, 0x6a, 0x19, 0xe5, 0x95, 0x1a, 0x4a, 0x4d, 0xa5, 0xb6, 0x51, 0x41, 0x69, 0xa7, 0xc4, 0x2b, 0xcd, 0x8c, 0x24, 0x7d, 0xbc, 0xbb, 0xe7, 0x32, 0x7e, 0x33, 0x6e, 0x28, 0x15, 0x8d, 0xeb, 0xfa, 0x97, 0x8e, 0xa1, 0x9f, 0xd4, 0x3f, 0xd3, 0x3f, 0xd7, 0x2f, 0xeb, 0x3f, 0xca, 0x32, 0xfd, 0x67, 0xfb, 0xae, 0x23, 0x8e, 0xd7, 0xc9, 0xa6, 0x2d, 0xb1, 0x1b, 0xe8, 0xd9, 0xf5, 0x1c, 0x7a, 0x4e, 0x3d, 0x97, 0x9e, 0x5b, 0xf9, 0x51, 0xe9, 0xa1, 0x0c, 0x54, 0x3a, 0xeb, 0x91, 0xea, 0x32, 0xe3, 0x53, 0x25, 0xc5, 0x38, 0xa9, 0x6c, 0x35, 0xbe, 0x30, 0xbe, 0x34, 0x3e, 0x33, 0xbe, 0x32, 0x3e, 0x37, 0x4e, 0x19, 0xa7, 0x8d,\n\t0x33, 0xc6, 0x27, 0x6a, 0x5f, 0xef, 0x8b, 0xca, 0x7b, 0xca, 0x07, 0xca, 0xfb, 0xca, 0x31, 0xe5, 0x63, 0xe5, 0x13, 0xe5, 0x23, 0xe5, 0x43, 0xe5, 0xb8, 0x72, 0x42, 0x79, 0x57, 0xd9, 0xae, 0x34, 0x57, 0xde, 0x56, 0xde, 0xd2, 0x0b, 0x2a, 0x3b, 0xf5, 0xc2, 0x46, 0x37, 0xbd, 0xb8, 0x72, 0x54, 0xf9, 0x49, 0xb9, 0x62, 0x9c, 0xb3, 0x6b, 0x1b, 0xe7, 0xad, 0xca, 0x6a, 0x2f, 0x6b, 0xab, 0xbd, 0xcc, 0xbb, 0x53, 0x5d, 0xa4, 0xf6, 0x56, 0x17, 0xab, 0x7d, 0xd4, 0x25, 0xea, 0x52, 0xb5, 0xbf, 0xba, 0x5c, 0x5d, 0x21, 0xb5, 0x24, 0x56, 0x12, 0xa4, 0x89, 0xb4, 0x17, 0x8f, 0xea, 0x84, 0xfe, 0x09, 0x0a, 0x45, 0xfe, 0xbf, 0xfd, 0xf9, 0xbf, 0xfb, 0x84, 0x2b, 0xc1, 0xb3, 0xa9, 0x65, 0x8e, 0xe1, 0x24, 0x9a, 0x99, 0x73, 0xe7, 0x22, 0xce, 0x9c, 0x8b, 0x39, 0x6f, 0x2e, 0xe1, 0xc4, 0x59, 0x96,\n\t0xd3, 0xe6, 0xf1, 0xe0, 0x79, 0x33, 0x1f, 0x27, 0x4e, 0xce, 0x9b, 0x9c, 0x36, 0xdb, 0x70, 0xde, 0x6c, 0x6b, 0xc7, 0x73, 0xde, 0x3c, 0xc0, 0x59, 0x93, 0x93, 0x26, 0xb9, 0xd0, 0x2d, 0x78, 0x46, 0x4e, 0x50, 0x9a, 0x29, 0xed, 0x65, 0x94, 0xd2, 0x45, 0x49, 0x52, 0x92, 0x65, 0x13, 0x67, 0xe5, 0x9d, 0x9c, 0x79, 0xf3, 0x2a, 0x6f, 0x29, 0x7b, 0x95, 0x7d, 0xca, 0x7e, 0xa5, 0x1f, 0x67, 0xe4, 0xc3, 0x44, 0xef, 0x1d, 0xf9, 0x46, 0x39, 0x22, 0x33, 0x65, 0x96, 0x13, 0xc6, 0x99, 0x76, 0x80, 0x3e, 0x8e, 0x33, 0xf6, 0x01, 0xe5, 0x6d, 0x75, 0x98, 0xb2, 0xcb, 0xfd, 0x17, 0x4b, 0x94, 0xba, 0x4a, 0x55, 0x51, 0x39, 0x39, 0x97, 0xb4, 0x32, 0xb9, 0x67, 0x43, 0x37, 0x0b, 0x83, 0x79, 0xe7, 0xe6, 0xe0, 0x1b, 0xca, 0x51, 0xfb, 0xa2, 0x35, 0x4e, 0xf1, 0x93, 0x41, 0x31, 0x4a, 0xac, 0x1b, 0x4d,\n\t0x32, 0xb1, 0xb9, 0x52, 0x4b, 0xa9, 0xad, 0x8f, 0xe7, 0xa4, 0x3d, 0x96, 0xf3, 0xf6, 0x78, 0x4e, 0xd9, 0xc1, 0xd3, 0xb5, 0xf9, 0xae, 0x7b, 0xb2, 0x36, 0x72, 0x70, 0xc2, 0x76, 0xcf, 0xd4, 0xed, 0x25, 0x99, 0x73, 0xc0, 0x36, 0x79, 0x33, 0xb4, 0xd3, 0x3f, 0x2c, 0x07, 0xd8, 0xed, 0xfb, 0x85, 0xff, 0x45, 0xf9, 0xfc, 0xd2, 0x26, 0xbe, 0x6e, 0x82, 0xcf, 0xd7, 0x78, 0xa7, 0x64, 0x68, 0xd1, 0xd8, 0xef, 0x69, 0xd5, 0x3e, 0xde, 0x5f, 0x3e, 0xcc, 0x5f, 0x24, 0x21, 0xb1, 0x9b, 0x6f, 0x7a, 0x9b, 0x78, 0xbf, 0x5a, 0x28, 0x69, 0x97, 0x25, 0x96, 0x74, 0xe9, 0x12, 0xd9, 0x39, 0x2c, 0x22, 0xc2, 0x2f, 0x09, 0x7e, 0x89, 0x8d, 0xac, 0xb3, 0x95, 0xec, 0x89, 0x4d, 0x8c, 0x29, 0xe1, 0x57, 0xa2, 0xfc, 0xbe, 0xc4, 0x6e, 0x25, 0xfc, 0x6a, 0x94, 0x2f, 0xd9, 0xe7, 0x3f, 0x18, 0xe7, 0xd7, 0x0b,\n\t0xb7, 0xdf, 0x5a, 0x44, 0x71, 0x62, 0xeb, 0x76, 0xa9, 0xdb, 0xf2, 0xe9, 0xf8, 0x88, 0xc8, 0x88, 0xb0, 0xe9, 0xf1, 0x3e, 0x7f, 0x5c, 0x5c, 0x7c, 0x84, 0xbf, 0x56, 0x42, 0x98, 0xcf, 0x1f, 0xed, 0xd6, 0xa2, 0x13, 0x12, 0x7c, 0x29, 0xa9, 0x44, 0x49, 0xc9, 0xfe, 0x22, 0x74, 0x85, 0x5a, 0x3e, 0x7f, 0x69, 0x77, 0xbc, 0xb4, 0x4b, 0x79, 0x30, 0x2e, 0xde, 0x87, 0x12, 0xd3, 0x93, 0x7c, 0x7e, 0x27, 0x2e, 0x3e, 0x91, 0x1e, 0x9f, 0x3b, 0xe6, 0xb8, 0xb5, 0x8a, 0x6e, 0xad, 0x62, 0x62, 0x58, 0x62, 0x42, 0x42, 0x42, 0x98, 0x5f, 0x29, 0x9e, 0x90, 0x10, 0xe9, 0x97, 0xb8, 0xf8, 0xae, 0x09, 0x09, 0x25, 0xfc, 0x5a, 0x94, 0x0f, 0x3e, 0x7a, 0xa1, 0x24, 0x14, 0x32, 0x62, 0xe3, 0xe2, 0xfd, 0x46, 0x64, 0x8c, 0xdf, 0x13, 0x19, 0x83, 0xfa, 0x09, 0x7e, 0x25, 0xb1, 0x84, 0x5f, 0x8f, 0x8a, 0x44,\n\t0x2f, 0x5f, 0x72, 0x8a, 0xd1, 0x39, 0xc6, 0xe7, 0x8e, 0xa4, 0x0a, 0x77, 0xff, 0xf6, 0x1b, 0x89, 0x75, 0xbb, 0xf8, 0xb5, 0x62, 0x11, 0xf4, 0xc7, 0xfa, 0xa6, 0xfb, 0xa6, 0xc3, 0x3b, 0xa5, 0xb4, 0x51, 0x08, 0xb3, 0x5a, 0xc4, 0x27, 0xc6, 0x85, 0x25, 0xb5, 0x4c, 0x88, 0x8f, 0x4c, 0x60, 0xb4, 0x56, 0xab, 0x78, 0x86, 0xc2, 0x5c, 0xa3, 0x42, 0x92, 0x4b, 0xf8, 0x8d, 0x28, 0xbf, 0x19, 0x5b, 0x7c, 0xab, 0xa8, 0xa9, 0xae, 0xf1, 0xd0, 0x8c, 0x8c, 0x89, 0xc4, 0xc5, 0x91, 0x31, 0x49, 0x7e, 0xb5, 0x73, 0x37, 0xbf, 0xd2, 0x05, 0xf9, 0x7e, 0xa3, 0x58, 0x09, 0xbf, 0x19, 0xe5, 0x73, 0x95, 0xf4, 0xc6, 0x76, 0xd9, 0xa9, 0x4b, 0x67, 0x9f, 0xcb, 0xc1, 0x5f, 0x2b, 0x31, 0xc1, 0x25, 0x49, 0xac, 0x13, 0x54, 0xd2, 0x8a, 0xda, 0x6a, 0x7a, 0x25, 0xb6, 0x6e, 0x4c, 0xb1, 0x88, 0x87, 0xce, 0xb6,\n\t0xa3, 0x1e, 0x77, 0xbe, 0x93, 0xca, 0x45, 0x29, 0x8e, 0x0a, 0xb1, 0x58, 0x9c, 0xe8, 0xab, 0x3b, 0x3d, 0x32, 0xc9, 0x0d, 0x44, 0xd0, 0x53, 0x12, 0xe6, 0x7a, 0xd3, 0xef, 0x0b, 0x43, 0xc9, 0x34, 0x2d, 0xfd, 0x5a, 0xa1, 0xc8, 0xa4, 0x3a, 0xa9, 0x22, 0xbc, 0xff, 0x30, 0xdd, 0x5f, 0x90, 0x59, 0x12, 0xf6, 0xa7, 0x69, 0x8f, 0x4e, 0x4a, 0x17, 0x15, 0x34, 0x68, 0xab, 0xd7, 0xd1, 0xea, 0xc6, 0x47, 0x84, 0x45, 0x46, 0x24, 0x14, 0x8b, 0x28, 0xe1, 0x4f, 0x1f, 0x95, 0xa2, 0xaa, 0x75, 0xfd, 0xc9, 0x49, 0x75, 0x4a, 0xf8, 0x33, 0x44, 0x41, 0xe8, 0xf3, 0xf9, 0xd3, 0xc5, 0x36, 0x72, 0xa7, 0x53, 0x89, 0x8c, 0x49, 0xf0, 0xa7, 0x77, 0x5b, 0x2d, 0x69, 0xa5, 0xa7, 0x55, 0xc2, 0x9f, 0x11, 0x36, 0x99, 0x82, 0x2e, 0xf1, 0xe1, 0x81, 0x2e, 0xc8, 0xf5, 0x67, 0x88, 0x4d, 0xf4, 0x4d, 0x4f, 0xf4,\n\t0xf9, 0x33, 0xe0, 0xb4, 0x12, 0xfe, 0x4c, 0x51, 0x8d, 0x5b, 0xc7, 0xa7, 0xe8, 0xc9, 0x75, 0x12, 0x0a, 0xfa, 0xd3, 0x77, 0x8d, 0x1c, 0x51, 0xc2, 0x9f, 0x39, 0xaa, 0x71, 0x8b, 0xf8, 0xc6, 0xad, 0x52, 0x3b, 0xc3, 0x22, 0xe8, 0xcf, 0x1a, 0xec, 0xcf, 0x12, 0x95, 0x22, 0x19, 0x63, 0xdb, 0xc4, 0xa7, 0x64, 0xcc, 0x18, 0xeb, 0x57, 0x92, 0x62, 0xfc, 0x19, 0x8b, 0xbb, 0x49, 0x4a, 0xea, 0xc6, 0xa4, 0xa4, 0x73, 0xff, 0x4a, 0xcf, 0x5f, 0x7e, 0x25, 0x07, 0x91, 0xd0, 0x0a, 0xc5, 0xc5, 0xa7, 0xb8, 0xce, 0xc3, 0xda, 0x98, 0xe9, 0x84, 0xd7, 0x15, 0x5b, 0x2c, 0x22, 0x92, 0x69, 0x69, 0xf5, 0xb0, 0xd4, 0x71, 0x77, 0x0a, 0xb9, 0xef, 0xf6, 0x24, 0x60, 0x49, 0x7d, 0xf4, 0xaf, 0x4f, 0xef, 0xe3, 0xa1, 0xfa, 0x87, 0x00, 0xa6, 0x88, 0x64, 0x8d, 0xc4, 0x5b, 0xb1, 0x7e, 0xa9, 0xb1, 0x55, 0x51,\n\t0x94, 0x60, 0xac, 0xb2, 0x46, 0x49, 0x8a, 0xa8, 0x75, 0x5b, 0xc7, 0xfb, 0x33, 0x46, 0xc6, 0xf8, 0xea, 0xfa, 0xbd, 0x24, 0xa5, 0x13, 0x49, 0xbe, 0xc5, 0xf8, 0x12, 0x11, 0xbf, 0x23, 0x53, 0x26, 0x85, 0x35, 0x30, 0x26, 0x66, 0x7a, 0x62, 0x4a, 0x16, 0x4f, 0x71, 0xff, 0xd0, 0xe2, 0x61, 0x05, 0x70, 0x53, 0x36, 0x6c, 0xcb, 0x5a, 0xbc, 0x84, 0x3f, 0x7b, 0x54, 0x8a, 0xe2, 0x96, 0x39, 0xf0, 0xb3, 0x5b, 0xe6, 0x8c, 0x4a, 0xd1, 0xdc, 0x32, 0x57, 0x54, 0x8a, 0xee, 0x96, 0xb9, 0xa3, 0x52, 0x0c, 0xb7, 0xcc, 0x13, 0x95, 0xe2, 0x71, 0xcb, 0xb0, 0xa8, 0x14, 0xd3, 0x2d, 0xf3, 0x46, 0xa5, 0x58, 0x6e, 0x99, 0x2f, 0x2a, 0xc5, 0x76, 0xcb, 0xa2, 0x51, 0xbe, 0x92, 0x7e, 0xa5, 0x63, 0x09, 0x7f, 0xb1, 0x60, 0x65, 0x60, 0x09, 0x7f, 0xf1, 0x60, 0x65, 0x50, 0x09, 0x7f, 0xfe, 0x28, 0xf1, 0xa7,\n\t0x2f, 0xfe, 0xdf, 0xd0, 0x31, 0x1c, 0x1d, 0xf3, 0xc3, 0xdb, 0x87, 0x8e, 0x6e, 0x19, 0x81, 0x8e, 0x6e, 0x59, 0x00, 0x1d, 0xdd, 0x32, 0x12, 0x1d, 0xdd, 0xb2, 0x20, 0x3a, 0xba, 0x65, 0x21, 0x74, 0x74, 0xcb, 0xc2, 0xe8, 0xe8, 0x96, 0x4f, 0xa1, 0xa3, 0x5b, 0x16, 0x41, 0x47, 0xb7, 0x8c, 0x8a, 0xf2, 0x55, 0x0b, 0xa6, 0x5a, 0x89, 0x28, 0xc4, 0x66, 0x4a, 0xf4, 0xc5, 0x12, 0x9f, 0xc4, 0xd8, 0x60, 0x38, 0x78, 0x7c, 0xa2, 0xdc, 0x7c, 0x2b, 0x19, 0xe5, 0x2f, 0x51, 0xdc, 0x5f, 0x82, 0x27, 0xa9, 0x14, 0x49, 0x5c, 0xdf, 0xf7, 0x0f, 0x91, 0x88, 0x4c, 0x8a, 0x8e, 0x74, 0x97, 0xb1, 0x7f, 0x49, 0x41, 0x2a, 0x95, 0xf0, 0x97, 0x7e, 0x18, 0x1e, 0x25, 0x87, 0xbf, 0x54, 0xb1, 0x14, 0x43, 0xc9, 0x5e, 0x37, 0x9e, 0x65, 0xc8, 0x35, 0xb0, 0xcc, 0xa3, 0x9e, 0xf9, 0xeb, 0x70, 0xd9, 0x28, 0x5f,\n\t0x85, 0xa0, 0xbe, 0xe5, 0xa0, 0x53, 0xea, 0xfe, 0x55, 0x08, 0x4f, 0xd8, 0xdf, 0x0a, 0x77, 0xfb, 0x25, 0xc7, 0xf6, 0xe0, 0xcb, 0xb4, 0x4e, 0x8d, 0xc8, 0xe8, 0x94, 0xb2, 0x4a, 0x76, 0x2c, 0x2a, 0x8f, 0xfd, 0x28, 0xfc, 0xf7, 0xfa, 0x92, 0xd8, 0x49, 0xd1, 0x25, 0xfc, 0x15, 0xa2, 0x4a, 0xe6, 0xac, 0x56, 0xc2, 0x5f, 0xf1, 0xdf, 0x91, 0x92, 0x84, 0x5d, 0x20, 0xaf, 0x44, 0x48, 0x24, 0x47, 0x21, 0x5f, 0x49, 0x5f, 0x7d, 0xf7, 0xe1, 0xc5, 0x95, 0x0d, 0xa7, 0x4f, 0xaf, 0x1f, 0x59, 0x9f, 0xa7, 0x3d, 0x9e, 0x65, 0x9d, 0x65, 0x91, 0x27, 0xba, 0xa2, 0xa2, 0x64, 0xcf, 0x86, 0xfc, 0x68, 0x56, 0x99, 0x1c, 0x3c, 0x20, 0xfc, 0x2f, 0x48, 0xe2, 0xb7, 0x63, 0x8b, 0x77, 0x9d, 0x5e, 0x32, 0xd2, 0xe7, 0xab, 0x36, 0x1d, 0x5e, 0x95, 0xff, 0x1c, 0xf6, 0x95, 0x4c, 0xe5, 0xe1, 0xd7, 0xe1, 0x09,\n\t0x95, 0xcf, 0x9f, 0xe8, 0x3e, 0xef, 0xb5, 0x5a, 0xc4, 0x6f, 0x53, 0x7d, 0x9a, 0x2f, 0x6c, 0x9b, 0x5a, 0x58, 0xcb, 0x93, 0x10, 0xe3, 0xae, 0x81, 0x16, 0xab, 0x69, 0x64, 0x90, 0x3a, 0xb2, 0x1e, 0x4f, 0x5f, 0xec, 0x93, 0x8f, 0x52, 0xa2, 0xbb, 0x0e, 0xa5, 0x2e, 0xf6, 0x6a, 0x6c, 0x62, 0x72, 0xa4, 0x5f, 0x8b, 0x4d, 0x4a, 0x66, 0x58, 0x8d, 0x4d, 0x0a, 0xa3, 0x9e, 0xe8, 0xae, 0x41, 0x4f, 0xce, 0x49, 0x42, 0x25, 0x16, 0xe6, 0xc8, 0x7a, 0xc4, 0x30, 0x12, 0x09, 0xf5, 0xb0, 0x8b, 0x22, 0x28, 0x05, 0x7e, 0x7f, 0x23, 0x24, 0x32, 0x75, 0xb5, 0xd3, 0x79, 0xc0, 0xf1, 0xbd, 0x41, 0x42, 0x19, 0x7f, 0xe1, 0x0a, 0x47, 0xd7, 0xa2, 0x42, 0x41, 0x25, 0xf8, 0x3b, 0x2e, 0x75, 0x95, 0xfb, 0x53, 0x16, 0x21, 0xaf, 0xe2, 0xfa, 0xc0, 0x47, 0x8f, 0x51, 0x38, 0xe4, 0x83, 0xc8, 0x6a, 0xb8, 0xa6,\n\t0x6a, 0xb0, 0xdb, 0x6f, 0xf1, 0xf0, 0xf8, 0x7c, 0xf5, 0x22, 0xeb, 0xbb, 0xc2, 0xdc, 0x68, 0x55, 0x0b, 0xba, 0xcc, 0x35, 0x20, 0xe4, 0x51, 0x69, 0x1d, 0x5f, 0xd2, 0x57, 0x8d, 0x77, 0xa3, 0xab, 0x71, 0xa8, 0xd3, 0xe7, 0xea, 0x92, 0xe6, 0x72, 0x4f, 0x21, 0x5a, 0x0d, 0x1f, 0x7d, 0xfb, 0xa6, 0x06, 0xea, 0xef, 0x32, 0x38, 0x14, 0x99, 0x48, 0x37, 0x8d, 0xab, 0x87, 0x34, 0x88, 0x4d, 0x0b, 0x4d, 0xa2, 0xfb, 0x7a, 0x7e, 0xd2, 0xc4, 0xb4, 0x50, 0xd6, 0x88, 0x8a, 0xf4, 0x95, 0x74, 0xbd, 0x56, 0x8f, 0x85, 0xb9, 0x5a, 0x42, 0xc9, 0x94, 0x92, 0x4a, 0x36, 0x1e, 0xc0, 0x9a, 0x0f, 0xbb, 0xe3, 0x1e, 0xed, 0xae, 0xf5, 0x38, 0xf5, 0xdf, 0xd2, 0xd4, 0x8e, 0xf2, 0x47, 0x17, 0xff, 0x5b, 0xa6, 0x31, 0x51, 0xfe, 0xca, 0xc5, 0xa7, 0x23, 0xd8, 0x4d, 0x16, 0xb4, 0xfd, 0x2b, 0x0d, 0x61, 0x29,\n\t0xe9, 0x2f, 0x09, 0x69, 0xec, 0xc3, 0x0c, 0x4b, 0xf3, 0xae, 0x9b, 0x5c, 0x91, 0xa4, 0x7a, 0x49, 0x1e, 0x92, 0x54, 0x76, 0x75, 0x58, 0x34, 0x58, 0xc3, 0xff, 0x1b, 0xa9, 0x58, 0xff, 0x7f, 0x2a, 0xfb, 0x5c, 0xf5, 0xdd, 0xf5, 0xa5, 0x5a, 0x24, 0x4b, 0xc8, 0x23, 0xf1, 0x8e, 0x48, 0x08, 0xe9, 0x58, 0xd7, 0x75, 0x46, 0x9a, 0xfd, 0xf5, 0x5c, 0xfb, 0x23, 0x22, 0x43, 0x0e, 0x08, 0xd9, 0xf1, 0xd0, 0xe4, 0xfa, 0x98, 0x9c, 0x3d, 0xf5, 0xe1, 0xe4, 0xed, 0xce, 0x73, 0x98, 0xb5, 0xa4, 0xbf, 0x3c, 0xcf, 0x62, 0x83, 0x7f, 0xe8, 0x6f, 0xc8, 0x9a, 0xab, 0x64, 0xcb, 0xea, 0xaf, 0x40, 0xbd, 0x51, 0x94, 0xbf, 0x12, 0x45, 0x63, 0xd7, 0x6b, 0x75, 0xf1, 0xab, 0xaf, 0x1e, 0xaf, 0xb2, 0x34, 0x3f, 0x35, 0x89, 0x72, 0xd3, 0xd1, 0xdf, 0x98, 0x6a, 0xd3, 0xa8, 0xad, 0xac, 0x33, 0x54, 0x9a, 0x51,\n\t0x51, 0xdc, 0x4a, 0xf3, 0xa8, 0xad, 0x4a, 0xb0, 0x27, 0x8e, 0x4a, 0xb0, 0xa7, 0x85, 0x4b, 0x53, 0x97, 0x4a, 0x4b, 0x97, 0xc6, 0xad, 0xb4, 0x72, 0x69, 0xdc, 0x4a, 0x6b, 0x97, 0xc6, 0xad, 0xb4, 0x71, 0x69, 0x6a, 0x53, 0x69, 0xeb, 0xd2, 0xb8, 0x95, 0x76, 0x2e, 0x8d, 0x5b, 0x89, 0x77, 0x69, 0xdc, 0x4a, 0x82, 0x4b, 0x13, 0x4b, 0xa5, 0xbd, 0x4b, 0xe3, 0x56, 0x9e, 0x76, 0x69, 0xdc, 0x4a, 0x07, 0x97, 0xc6, 0xad, 0x74, 0x74, 0x69, 0xea, 0x51, 0x79, 0xc6, 0xa5, 0x71, 0x2b, 0x9d, 0x5c, 0x1a, 0xb7, 0x92, 0xe8, 0xd2, 0xb8, 0x95, 0x24, 0x97, 0x26, 0x86, 0x4a, 0x67, 0x97, 0xc6, 0xad, 0x74, 0x71, 0x69, 0xdc, 0x4a, 0xb2, 0x4b, 0xe3, 0x56, 0xba, 0x46, 0xf9, 0xab, 0x3c, 0x74, 0x73, 0x37, 0xb7, 0xe1, 0xaf, 0x41, 0xad, 0x7b, 0xb0, 0x56, 0x93, 0x5a, 0x8f, 0x60, 0x3e, 0xd1, 0xa8, 0x45,\n\t0xa3, 0x67, 0x94, 0xbf, 0xea, 0x43, 0xea, 0x5e, 0x6e, 0x23, 0x48, 0xdd, 0x3b, 0x58, 0x73, 0xa9, 0xfb, 0x04, 0x6b, 0x2e, 0x69, 0xdf, 0x28, 0x7f, 0xb5, 0x87, 0xa4, 0xfd, 0xdc, 0x46, 0x90, 0xb4, 0x7f, 0xb0, 0xe6, 0x92, 0x0e, 0x08, 0xd6, 0x5c, 0xd2, 0x81, 0x51, 0xfe, 0xea, 0x0f, 0x49, 0x07, 0xb9, 0x8d, 0x20, 0xe9, 0xe0, 0x60, 0xcd, 0x25, 0x1d, 0x12, 0xac, 0xb9, 0xa4, 0x43, 0xa3, 0xb6, 0xd9, 0xba, 0x9a, 0xb6, 0x79, 0x8a, 0x29, 0xee, 0xb7, 0xba, 0xfa, 0xb5, 0x82, 0x71, 0x23, 0xd2, 0xde, 0x29, 0x25, 0x44, 0xd8, 0x8c, 0x1f, 0x6d, 0xc9, 0x46, 0x45, 0x99, 0xc5, 0xca, 0x9c, 0xba, 0x00, 0x0c, 0x48, 0x11, 0x4f, 0xcc, 0x1b, 0xfd, 0xda, 0xd7, 0xab, 0x58, 0xc0, 0x90, 0x62, 0x6e, 0xa3, 0x56, 0xba, 0x24, 0xab, 0xa9, 0x55, 0xdd, 0x53, 0xd4, 0xca, 0x69, 0x1a, 0x56, 0xa8, 0xab, 0xb7,\n\t0xa7, 0x9d, 0xa7, 0xae, 0x5e, 0xce, 0xe3, 0x33, 0x82, 0x5d, 0xde, 0x98, 0xfd, 0xb9, 0xc6, 0x67, 0x1d, 0x9f, 0x71, 0xbc, 0x33, 0xde, 0xe3, 0x5e, 0x68, 0xb0, 0xe9, 0xcb, 0x14, 0xb3, 0x9f, 0xe3, 0x60, 0xda, 0x7f, 0xc1, 0x3e, 0x2d, 0xb9, 0x4e, 0x4a, 0x41, 0x65, 0x6a, 0x0b, 0x72, 0x7b, 0x6a, 0x7c, 0xb0, 0x55, 0xd8, 0x6d, 0xed, 0xb6, 0xc6, 0x8b, 0xa2, 0xd7, 0x9a, 0xda, 0xa5, 0x75, 0xb0, 0x93, 0xad, 0x76, 0x42, 0xad, 0x74, 0x5d, 0xac, 0xe6, 0x56, 0x4d, 0x4f, 0x71, 0x2b, 0xb7, 0x69, 0xa4, 0x2b, 0xb6, 0x53, 0x09, 0x4c, 0xf6, 0xeb, 0x33, 0x79, 0xb9, 0xd4, 0x49, 0x31, 0x92, 0xeb, 0xfc, 0x67, 0xe7, 0xc7, 0xf7, 0xf9, 0x6f, 0xa1, 0x2c, 0x74, 0xff, 0xc5, 0x41, 0xed, 0x8e, 0xc8, 0x83, 0x8d, 0xee, 0xbf, 0x47, 0x68, 0x6c, 0x0a, 0xfc, 0xaa, 0x5b, 0x81, 0xdf, 0x52, 0x5b, 0x8f, 0xd2,\n\t0x18, 0x4b, 0xb5, 0x1b, 0x81, 0xeb, 0x0f, 0x36, 0xa5, 0x51, 0x19, 0x1b, 0xa1, 0xbb, 0x1e, 0xa2, 0x9b, 0xc5, 0x7f, 0xbd, 0xa5, 0xb7, 0x67, 0x12, 0x54, 0x73, 0xd5, 0x2b, 0x6e, 0x9f, 0x67, 0xb2, 0xb1, 0x46, 0x7b, 0x41, 0x3d, 0xfb, 0xd8, 0xf8, 0x00, 0x6d, 0xee, 0x63, 0x34, 0x23, 0xb4, 0x17, 0x1e, 0xa3, 0x7b, 0x54, 0xde, 0xfe, 0xc7, 0xb4, 0xba, 0x66, 0xec, 0x0f, 0xea, 0xf5, 0x72, 0xea, 0xbf, 0x9a, 0x98, 0xfa, 0x47, 0xd1, 0x1f, 0xc1, 0x0c, 0x8e, 0xc4, 0xae, 0x2d, 0x4d, 0x44, 0x74, 0x2b, 0xf8, 0xaf, 0xc2, 0x89, 0x87, 0x3e, 0x93, 0xba, 0xb9, 0x53, 0xc4, 0xca, 0xe5, 0xfe, 0x13, 0x90, 0xa0, 0xb5, 0x88, 0x53, 0x04, 0x8c, 0x17, 0xf1, 0x32, 0xe6, 0x2d, 0x0f, 0xce, 0x88, 0xa4, 0x1b, 0xe1, 0x7e, 0xd9, 0x06, 0x71, 0x60, 0x2f, 0x38, 0x29, 0x92, 0x61, 0x08, 0x38, 0x2f, 0x92, 0xf1,\n\t0xa8, 0x48, 0xa6, 0x1e, 0x22, 0x99, 0xa7, 0xb2, 0xb5, 0x8c, 0x06, 0x07, 0x45, 0xb2, 0x41, 0x97, 0x9d, 0x73, 0x6c, 0x0e, 0x64, 0xe7, 0xb8, 0x26, 0x92, 0x6b, 0x1e, 0x40, 0x66, 0x6e, 0xc2, 0x90, 0x1b, 0x79, 0x79, 0x38, 0xe1, 0x85, 0xf9, 0x00, 0x7c, 0xf2, 0x42, 0x97, 0xf7, 0x98, 0x48, 0xbe, 0xd2, 0x22, 0xf9, 0x1b, 0x88, 0x84, 0xc3, 0x3f, 0x02, 0x1e, 0x05, 0xe0, 0x1b, 0xc9, 0x06, 0xa4, 0x10, 0xba, 0x15, 0xa6, 0xaf, 0x28, 0x63, 0xc5, 0x99, 0x53, 0xe2, 0x8a, 0x48, 0x49, 0xc6, 0x4a, 0x22, 0xbb, 0x14, 0xba, 0x95, 0xc6, 0x13, 0x65, 0xe8, 0x2b, 0x07, 0xdf, 0xf2, 0xc8, 0xad, 0x78, 0x42, 0xa4, 0x0a, 0x72, 0xab, 0x4e, 0x12, 0xa9, 0x8e, 0x2d, 0x35, 0xb1, 0xa9, 0x26, 0x3a, 0xd4, 0xc2, 0xfe, 0xda, 0xd8, 0x51, 0xfb, 0x45, 0x9e, 0x5a, 0xe4, 0xc6, 0x30, 0x27, 0x16, 0xba, 0x3a, 0xd8,\n\t0x58, 0xe7, 0x08, 0x2b, 0x0b, 0x32, 0xea, 0x57, 0x03, 0xd0, 0xbb, 0xff, 0xc6, 0x66, 0x43, 0xec, 0x6b, 0x88, 0x8f, 0x1a, 0xae, 0x21, 0xe9, 0xe9, 0x6f, 0xc2, 0xdc, 0xa6, 0xf8, 0xaf, 0x19, 0x65, 0x1c, 0xed, 0x96, 0xd8, 0xdc, 0x2a, 0x4a, 0xa4, 0x35, 0xb6, 0xb5, 0x81, 0x57, 0xbb, 0xf5, 0x22, 0x09, 0xb5, 0x44, 0xda, 0xd3, 0x7e, 0x1a, 0xdf, 0x3d, 0x8d, 0x3e, 0x1d, 0xa0, 0xef, 0x00, 0xef, 0x8e, 0x2e, 0xd0, 0xb3, 0x13, 0x73, 0x12, 0xf1, 0x63, 0xe2, 0x68, 0x91, 0x24, 0xec, 0xe2, 0x6d, 0x2b, 0x9d, 0xa1, 0xed, 0x8c, 0x5d, 0x9d, 0x19, 0xef, 0x82, 0x6e, 0xc9, 0xf4, 0x75, 0x4d, 0x14, 0xe9, 0x06, 0x7a, 0x40, 0xd3, 0x13, 0xfa, 0x9e, 0xd8, 0xda, 0xeb, 0x9e, 0x48, 0xef, 0x0b, 0x22, 0x7d, 0xb0, 0xbd, 0x1f, 0x63, 0x03, 0xe8, 0x43, 0x45, 0x19, 0x8a, 0x2e, 0x43, 0xd1, 0x7d, 0x58, 0x32,\n\t0x80, 0xef, 0x70, 0x62, 0x30, 0x02, 0x3e, 0xa3, 0xb0, 0xe1, 0x59, 0xc6, 0x46, 0x83, 0x31, 0xf8, 0x64, 0x3c, 0x7c, 0x26, 0x50, 0x9f, 0x80, 0xcf, 0x26, 0xd2, 0x7e, 0x8e, 0x3a, 0x2e, 0x92, 0x49, 0xc4, 0x6d, 0x32, 0x7e, 0x98, 0x8c, 0x6e, 0x53, 0xd0, 0x7f, 0x0a, 0xfc, 0x9f, 0x27, 0x4e, 0x53, 0x91, 0x3d, 0x15, 0xbe, 0xd3, 0x06, 0x88, 0x4c, 0xcf, 0x0b, 0x90, 0xfd, 0x02, 0x34, 0x33, 0x98, 0x3f, 0x13, 0x3f, 0xcf, 0x62, 0xce, 0x2c, 0x74, 0x9e, 0x4d, 0xae, 0xcc, 0x26, 0x4e, 0x2f, 0x62, 0xeb, 0x8b, 0xc8, 0x7c, 0x11, 0x5f, 0xcf, 0x21, 0x7e, 0x2f, 0xd1, 0x37, 0x37, 0x5e, 0x64, 0x5e, 0x41, 0x80, 0x4d, 0x2f, 0xe3, 0xab, 0x97, 0xf1, 0xcd, 0x7c, 0xe4, 0xce, 0x87, 0xef, 0x02, 0xfc, 0xbe, 0x60, 0x21, 0xc0, 0x8e, 0x85, 0xc4, 0x69, 0x21, 0x72, 0x16, 0xd2, 0xbf, 0x08, 0xb9, 0x8b, 0xe0,\n\t0xb3, 0x08, 0x1d, 0x17, 0x93, 0x13, 0x8b, 0xe1, 0xbf, 0x04, 0x3d, 0x97, 0x30, 0x77, 0x29, 0xfa, 0x2d, 0x25, 0x76, 0xcb, 0xf0, 0xd9, 0x32, 0xf8, 0x2c, 0x23, 0x36, 0xcb, 0xa9, 0x2f, 0xc7, 0xf7, 0x2b, 0xe0, 0xbf, 0x92, 0xfa, 0x4a, 0x64, 0xbf, 0x02, 0xef, 0x57, 0xe8, 0x7b, 0x05, 0x9f, 0xad, 0x42, 0x87, 0xd5, 0xe8, 0xb0, 0x1a, 0x7e, 0x6b, 0x98, 0xb3, 0x06, 0xde, 0x6b, 0x18, 0x7b, 0x35, 0x1b, 0x20, 0xef, 0xd6, 0x22, 0x63, 0xed, 0x4a, 0x80, 0x1e, 0xeb, 0xd0, 0x67, 0x3d, 0xf9, 0xb8, 0x1e, 0xbb, 0x5e, 0x03, 0x1b, 0xd1, 0x6b, 0x13, 0xbe, 0x7e, 0x1d, 0x47, 0x6f, 0xc6, 0x7f, 0x5b, 0xe0, 0xeb, 0xa7, 0x9d, 0x42, 0xbc, 0x52, 0xb0, 0x69, 0x2b, 0xfe, 0xd8, 0x86, 0xdf, 0xb7, 0x11, 0xeb, 0x1d, 0xf4, 0xbd, 0x01, 0xef, 0x37, 0xf0, 0xd3, 0x9b, 0xf8, 0x70, 0x27, 0xba, 0xed, 0x86, 0xd7,\n\t0x6e, 0x74, 0xd8, 0xb3, 0x49, 0x64, 0x2f, 0xf3, 0xf6, 0x61, 0xdb, 0x3e, 0xea, 0xfb, 0xb1, 0xe9, 0x00, 0xf6, 0x1e, 0x64, 0xde, 0x21, 0x78, 0xbf, 0xc5, 0xbc, 0xb7, 0x98, 0x73, 0x98, 0x3c, 0x39, 0xcc, 0xfc, 0x23, 0xe8, 0x79, 0x84, 0xe7, 0xe5, 0x6d, 0x74, 0x7c, 0x1b, 0x1e, 0xef, 0x20, 0xfb, 0x1d, 0xf8, 0x1c, 0x45, 0xd7, 0xa3, 0xcc, 0x79, 0x0f, 0x5f, 0xbf, 0x87, 0xbe, 0xef, 0x5f, 0x12, 0xf9, 0x80, 0x39, 0xc7, 0xc8, 0xd3, 0x63, 0xd8, 0xf2, 0x21, 0x7c, 0x3f, 0x84, 0xee, 0x23, 0x68, 0x8e, 0x23, 0xeb, 0x38, 0xf9, 0x70, 0x9c, 0x78, 0x9c, 0xe0, 0xd9, 0x39, 0x41, 0xdf, 0xc7, 0xe4, 0xf6, 0xc7, 0xc8, 0xfa, 0x18, 0xdb, 0x3e, 0x81, 0xfe, 0x53, 0x62, 0xf4, 0x59, 0x3a, 0x00, 0x8f, 0xcf, 0xb1, 0xe3, 0x73, 0x64, 0x7f, 0x81, 0x0f, 0x4e, 0x61, 0xdb, 0x97, 0x37, 0x44, 0xbe, 0x22, 0x1e,\n\t0x5f, 0x41, 0x7b, 0x1a, 0x3b, 0xcf, 0xa0, 0xcb, 0x19, 0xea, 0x67, 0xf1, 0xc9, 0x59, 0x6c, 0x38, 0x87, 0x8e, 0xe7, 0xe0, 0x71, 0x1e, 0xbd, 0xbf, 0xc1, 0x86, 0x6f, 0xa8, 0x7f, 0x8b, 0xcd, 0xdf, 0x21, 0xf3, 0x3b, 0xe6, 0xc1, 0x4a, 0x2e, 0xd0, 0xfe, 0x01, 0x9f, 0xfd, 0x40, 0xec, 0x7e, 0x60, 0xee, 0x45, 0xf8, 0x5c, 0x24, 0x3e, 0x97, 0xb0, 0xe3, 0x12, 0x32, 0x2f, 0x23, 0xf3, 0x32, 0xcf, 0xce, 0x8f, 0xe0, 0x27, 0xf4, 0xbc, 0x4a, 0xff, 0x55, 0x6c, 0xfa, 0x19, 0x5d, 0x7f, 0x81, 0xf6, 0x17, 0x72, 0xed, 0x1a, 0xf6, 0x5f, 0xa3, 0xfc, 0x15, 0xbd, 0x7f, 0x23, 0x2f, 0xaf, 0x93, 0x03, 0xd7, 0xe1, 0x7f, 0x1d, 0xfb, 0x6f, 0x90, 0x83, 0x37, 0x88, 0xef, 0x0d, 0x9e, 0xc9, 0x1b, 0xf0, 0xbb, 0x81, 0xd0, 0x1b, 0xd8, 0x7f, 0x93, 0x5c, 0xb8, 0x49, 0xdf, 0x4d, 0x9e, 0x83, 0x9b, 0xcc, 0xbd,\n\t0x85, 0xce, 0xb7, 0x98, 0x77, 0x0b, 0xda, 0x5b, 0xd8, 0x77, 0x0b, 0xda, 0xdb, 0xe4, 0xca, 0x6d, 0xfc, 0x72, 0x1b, 0x7d, 0x6f, 0x63, 0xef, 0x6d, 0xe6, 0xde, 0x21, 0xcf, 0xef, 0xe0, 0xcb, 0x3b, 0xd4, 0x7f, 0x87, 0xfe, 0x77, 0xd6, 0x8c, 0x3f, 0x78, 0x9e, 0xfe, 0xc0, 0xb6, 0xbb, 0xee, 0xff, 0x87, 0xb5, 0x60, 0xe8, 0xff, 0x6b, 0x8a, 0xdf, 0x02, 0x2b, 0x45, 0x91, 0x93, 0x6c, 0x7c, 0xaa, 0x01, 0xea, 0x6a, 0x69, 0xc0, 0x4b, 0x49, 0x5d, 0x28, 0x8a, 0x76, 0x4a, 0x14, 0xa3, 0x88, 0x28, 0x9e, 0xed, 0xa2, 0x58, 0x94, 0xf6, 0x41, 0x51, 0x9c, 0x49, 0xa2, 0xa4, 0xeb, 0x01, 0xee, 0x88, 0x92, 0xfe, 0xbc, 0x28, 0x19, 0x59, 0x96, 0x33, 0xe5, 0x15, 0x25, 0xf3, 0x26, 0x51, 0xb2, 0xbc, 0x28, 0x4a, 0xd6, 0x3e, 0xec, 0x9a, 0xb2, 0x81, 0x23, 0xa2, 0x64, 0x1f, 0x20, 0x4a, 0xce, 0x64, 0x51,\n\t0x72, 0xcd, 0x10, 0x25, 0x37, 0xc8, 0x13, 0x0f, 0xfc, 0x00, 0x3e, 0x79, 0x4e, 0x00, 0xe6, 0xe7, 0xb9, 0x26, 0x4a, 0x18, 0x3c, 0xc2, 0x32, 0x01, 0x1f, 0x40, 0x7e, 0xd8, 0x3d, 0x51, 0xf2, 0x32, 0x8f, 0xb5, 0x54, 0xe1, 0xcc, 0xac, 0xe4, 0x87, 0x57, 0xf8, 0x54, 0x51, 0x7c, 0x71, 0x60, 0xa7, 0x28, 0x11, 0x7b, 0x45, 0x29, 0x80, 0x8e, 0x91, 0xc8, 0x8d, 0x44, 0x9f, 0xc8, 0x79, 0x60, 0x0d, 0x40, 0xcf, 0x48, 0x68, 0x23, 0xb1, 0x27, 0xf2, 0x82, 0x28, 0x05, 0xa1, 0x29, 0x78, 0x45, 0x94, 0x42, 0xc8, 0x2c, 0x8c, 0x6d, 0x4f, 0xc1, 0xef, 0xa9, 0x1b, 0xa2, 0x14, 0xe9, 0x20, 0x4a, 0xd1, 0x5c, 0x20, 0x1a, 0xa0, 0x53, 0xd1, 0x11, 0x00, 0x7b, 0x8b, 0xc2, 0xbb, 0x28, 0x36, 0x17, 0xc5, 0xb6, 0x62, 0x8c, 0x17, 0x63, 0xbc, 0x18, 0xe3, 0xc5, 0x18, 0x2f, 0xc6, 0x78, 0x31, 0xc6, 0x8b, 0x31,\n\t0x5e, 0x8c, 0xf1, 0xe2, 0xe8, 0x18, 0x95, 0x28, 0x4a, 0x09, 0xf4, 0x2e, 0x39, 0x04, 0xd0, 0x2e, 0x8d, 0xed, 0x65, 0x90, 0x55, 0x16, 0xbd, 0xca, 0xad, 0x17, 0x85, 0x75, 0x5c, 0x29, 0x8f, 0x4f, 0xca, 0x63, 0x6f, 0x79, 0xec, 0xac, 0xd0, 0x00, 0x8c, 0x06, 0x47, 0x45, 0xa9, 0x08, 0xcf, 0x8a, 0xe8, 0x5a, 0x89, 0x76, 0x34, 0x73, 0xa2, 0x99, 0x5f, 0xb9, 0x0e, 0x40, 0x46, 0x15, 0x6c, 0xae, 0x82, 0xbe, 0x55, 0xf1, 0x4b, 0x55, 0x6c, 0xad, 0x46, 0xbd, 0xfa, 0x31, 0x51, 0x6a, 0xa0, 0x7b, 0x4d, 0x6c, 0xad, 0x85, 0x7f, 0x6b, 0xe1, 0x9f, 0x5a, 0x67, 0xd8, 0x1c, 0xb6, 0x06, 0x94, 0x31, 0xb4, 0x63, 0xd0, 0x2d, 0x16, 0x99, 0xb1, 0xd8, 0x5f, 0xa7, 0x09, 0x60, 0x4e, 0x5d, 0xda, 0xf5, 0xa0, 0xaf, 0x07, 0xdf, 0xfa, 0xc8, 0xaf, 0x8f, 0xcf, 0x1b, 0x40, 0xdb, 0x30, 0x1d, 0x40, 0xb7, 0x46,\n\t0x94, 0x8d, 0x2e, 0x89, 0xd2, 0x98, 0x39, 0x4d, 0xb0, 0xb1, 0x29, 0x7d, 0xcd, 0x90, 0xdf, 0x0c, 0x1d, 0x9b, 0x43, 0xd7, 0x1c, 0xbd, 0xe2, 0xd0, 0xbd, 0x05, 0x68, 0x49, 0xcc, 0x5a, 0x31, 0xbf, 0x75, 0x79, 0x51, 0xda, 0x60, 0x63, 0x1b, 0xda, 0x6d, 0xa1, 0x6b, 0x87, 0x7d, 0xf1, 0xe8, 0x90, 0x80, 0x1f, 0x3a, 0x60, 0x57, 0x47, 0x62, 0xf2, 0x0c, 0xed, 0xc4, 0x82, 0xa2, 0x24, 0xd1, 0xd7, 0x19, 0x5d, 0xba, 0xc0, 0x3b, 0xb9, 0x96, 0x28, 0x5d, 0x91, 0xc7, 0x7b, 0x41, 0xe9, 0x86, 0x8c, 0x6e, 0xf0, 0xee, 0x4e, 0x2e, 0x75, 0x27, 0x46, 0x3d, 0xf0, 0x73, 0x0f, 0xfc, 0xd0, 0x83, 0xb8, 0xf5, 0xc4, 0xf7, 0x3d, 0x89, 0x51, 0x4f, 0xf8, 0xf7, 0xc2, 0x27, 0xbd, 0x18, 0xef, 0x8d, 0xdd, 0x3c, 0x3a, 0x4a, 0x1f, 0x72, 0xaa, 0x0f, 0x34, 0x7d, 0x99, 0xdf, 0x17, 0x7f, 0xf7, 0x25, 0xef, 0xfa,\n\t0x12, 0x8f, 0x7e, 0xe4, 0x6f, 0x3f, 0x72, 0xa4, 0x1f, 0x39, 0xd0, 0x1f, 0xdd, 0xfa, 0x93, 0x6f, 0x03, 0xa0, 0x19, 0x80, 0xfc, 0x01, 0xf4, 0x0d, 0x64, 0x6c, 0x20, 0x7c, 0x06, 0xa1, 0xfb, 0x20, 0x6c, 0x18, 0x0c, 0xcd, 0x60, 0x78, 0x0e, 0x41, 0x9f, 0x21, 0x8c, 0x0f, 0x85, 0x76, 0xe8, 0xd2, 0x10, 0x88, 0xcb, 0x30, 0x74, 0x1f, 0x86, 0xfc, 0x61, 0xf0, 0x1e, 0x4e, 0x5e, 0x0e, 0x47, 0xe7, 0xe1, 0xd8, 0x39, 0x02, 0x3b, 0x46, 0x92, 0x57, 0xa3, 0xd0, 0x65, 0x14, 0x76, 0x8e, 0x22, 0xef, 0x46, 0x41, 0xff, 0x2c, 0x7c, 0x9e, 0xc5, 0x87, 0xa3, 0xb1, 0x63, 0x34, 0x31, 0x1b, 0x83, 0xbc, 0xb1, 0xd0, 0x8d, 0xc5, 0x6f, 0xe3, 0x88, 0xf1, 0x78, 0xf7, 0x5a, 0x34, 0xf6, 0x4d, 0x80, 0xcf, 0x04, 0xe2, 0x34, 0x11, 0x3f, 0x4d, 0x44, 0x9f, 0xe7, 0x28, 0x9f, 0xc3, 0x57, 0x93, 0xe8, 0x9f, 0x4c,\n\t0x9c, 0x26, 0xe3, 0xcf, 0x29, 0xe8, 0xf5, 0x3c, 0x3e, 0x78, 0x1e, 0x7f, 0x3d, 0x0f, 0x8f, 0xa9, 0xe4, 0xd2, 0x34, 0xfc, 0x30, 0x9d, 0xf1, 0x17, 0xe8, 0x9f, 0xa1, 0x03, 0xf4, 0x9c, 0x41, 0x3e, 0xcc, 0x24, 0xc6, 0xb3, 0xe0, 0x37, 0x1b, 0x5f, 0xbc, 0x88, 0x9c, 0x39, 0xe8, 0x31, 0x87, 0xf9, 0x2f, 0x81, 0xb9, 0xb4, 0xe7, 0xe1, 0xdf, 0x97, 0xc9, 0xfb, 0xf9, 0xc4, 0x9e, 0x77, 0x95, 0xb2, 0x80, 0x58, 0x2f, 0x44, 0xdf, 0x45, 0xf0, 0x5e, 0x8c, 0x0f, 0x16, 0x13, 0x83, 0x25, 0xc8, 0x5f, 0x8a, 0x8c, 0x65, 0x8c, 0x2f, 0x87, 0xf7, 0x72, 0x74, 0x58, 0x41, 0xdf, 0x4a, 0xec, 0xe1, 0xdd, 0xa3, 0xac, 0x22, 0xff, 0x56, 0xe3, 0x1f, 0xde, 0x3b, 0xca, 0xab, 0xf0, 0x7a, 0x15, 0xbf, 0xac, 0x83, 0xff, 0x7a, 0xe2, 0xba, 0x1e, 0x1d, 0x5e, 0x43, 0xa7, 0x0d, 0x3c, 0x2b, 0x1b, 0xf0, 0xd5, 0x46,\n\t0xe2, 0xb3, 0x09, 0xde, 0x9b, 0xf0, 0xd3, 0x26, 0x78, 0x6c, 0x46, 0xc6, 0x16, 0xe6, 0xf9, 0x89, 0xe7, 0x56, 0xfc, 0xb8, 0x0d, 0xfe, 0xdb, 0x29, 0x77, 0xe0, 0xbb, 0x37, 0x88, 0xcd, 0x9b, 0xd4, 0x77, 0xc2, 0x73, 0x17, 0x79, 0xbc, 0x1b, 0x1d, 0xf7, 0xe0, 0xcf, 0xbd, 0xf8, 0x6e, 0x1f, 0x3a, 0xee, 0x27, 0xce, 0x07, 0xe0, 0x79, 0x10, 0x1f, 0x1c, 0x82, 0xe7, 0x5b, 0x96, 0x28, 0x87, 0x91, 0x75, 0x04, 0x1b, 0xdf, 0x41, 0x9f, 0x77, 0xf0, 0xdf, 0x51, 0xf4, 0x7e, 0x8f, 0xdc, 0x7e, 0x9f, 0x79, 0x1f, 0x60, 0xeb, 0x31, 0x7c, 0xfc, 0x21, 0x38, 0xce, 0x73, 0x79, 0x02, 0x9f, 0xf0, 0x8e, 0x50, 0x3e, 0xc1, 0x3f, 0x9f, 0x32, 0x76, 0x12, 0xfa, 0xcf, 0xd0, 0xe9, 0x0b, 0x62, 0xf1, 0x05, 0x39, 0x70, 0x8a, 0x79, 0x5f, 0xa2, 0x17, 0xef, 0x08, 0xe5, 0x2b, 0xf2, 0xe8, 0x34, 0x31, 0x3f, 0xe3,\n\t0x02, 0xbf, 0x9d, 0x21, 0xd6, 0x5f, 0xe3, 0xe3, 0xb3, 0xc8, 0x3e, 0x47, 0x6c, 0xce, 0x13, 0xa7, 0x6f, 0xe0, 0xfb, 0x1d, 0x7c, 0xbe, 0xe7, 0x99, 0xfa, 0x01, 0x3e, 0x97, 0xe1, 0xf3, 0x13, 0x7a, 0x5c, 0xc5, 0xe6, 0x9f, 0xe1, 0x77, 0x0d, 0x7d, 0x7f, 0xc5, 0x5f, 0xd7, 0x89, 0xd3, 0x0d, 0xd6, 0xcb, 0x9b, 0xcc, 0xbd, 0x05, 0xfd, 0x6d, 0xe4, 0xdc, 0x41, 0x8f, 0x3f, 0xe8, 0xbb, 0x0b, 0xee, 0xe1, 0x93, 0xfb, 0xf0, 0x67, 0xfd, 0x55, 0x59, 0x7b, 0x55, 0xe5, 0x84, 0xa8, 0x5a, 0xbc, 0xa8, 0x7a, 0x13, 0x51, 0x8d, 0xbc, 0xa2, 0x7a, 0x7c, 0x60, 0xa9, 0xa8, 0xe6, 0x8b, 0xa2, 0xda, 0x45, 0xc0, 0x29, 0x51, 0x1d, 0xc6, 0xd9, 0xc7, 0xaa, 0xe9, 0x2c, 0xb0, 0x57, 0xd4, 0x0c, 0xb9, 0x44, 0xcd, 0x18, 0x2d, 0x6a, 0xa6, 0x5a, 0x60, 0x93, 0xa8, 0x99, 0x27, 0x89, 0x9a, 0x85, 0xfe, 0xac, 0x2b,\n\t0x45, 0xcd, 0x36, 0x5e, 0xd4, 0xec, 0x89, 0xa2, 0xe6, 0xa0, 0xcc, 0xd9, 0x43, 0xd4, 0x5c, 0xf0, 0xcf, 0x9d, 0x0c, 0xae, 0x88, 0x9a, 0x07, 0x9e, 0x61, 0xf0, 0xc9, 0x0b, 0xff, 0x7c, 0xa3, 0x45, 0xcd, 0x5f, 0x47, 0xd4, 0x70, 0xfa, 0x7c, 0xc8, 0x8e, 0x80, 0x67, 0xc4, 0x35, 0x51, 0x0b, 0xdc, 0x10, 0xb5, 0x60, 0x41, 0x30, 0x55, 0xd4, 0x42, 0xc8, 0x28, 0xb4, 0x5e, 0xd4, 0xc2, 0x99, 0xc0, 0x05, 0x51, 0x9f, 0x3a, 0x26, 0x6a, 0x91, 0x19, 0xa2, 0x16, 0xa5, 0x2c, 0x86, 0x0c, 0xd6, 0x42, 0xb5, 0xb8, 0x5f, 0xd4, 0x28, 0xe4, 0x94, 0x80, 0x57, 0x49, 0xf8, 0x94, 0x82, 0x6f, 0x69, 0x68, 0xca, 0x44, 0x81, 0x3e, 0xa2, 0x96, 0x3d, 0x2a, 0x6a, 0xf9, 0x23, 0xa2, 0x56, 0xaa, 0x26, 0x6a, 0x95, 0xd2, 0xa2, 0x56, 0x45, 0x8f, 0x1a, 0xba, 0xa8, 0xb5, 0xe0, 0x1b, 0x33, 0x42, 0xd4, 0x58, 0x74,\n\t0x8b, 0x3d, 0x2f, 0x2a, 0x6b, 0x96, 0x5a, 0x17, 0x79, 0xf5, 0xd0, 0xa7, 0x3e, 0xba, 0xd4, 0x67, 0x5e, 0x43, 0x6c, 0x68, 0x84, 0xed, 0x8d, 0xe3, 0x00, 0x3c, 0x9a, 0x20, 0xa7, 0x09, 0xfd, 0x4d, 0x0f, 0x8a, 0xda, 0x0c, 0x3b, 0x9a, 0x5d, 0x12, 0xb5, 0xf9, 0x00, 0x70, 0x46, 0xd4, 0x38, 0xe6, 0xb5, 0x40, 0xe7, 0x96, 0xc8, 0x68, 0x89, 0x7e, 0xad, 0xa0, 0x6f, 0x83, 0x2f, 0xdb, 0x32, 0xb7, 0x2d, 0x3e, 0x6a, 0x87, 0x2f, 0xd9, 0xdf, 0xaa, 0xf1, 0xb4, 0xe3, 0xd1, 0x3b, 0x01, 0x7d, 0x12, 0x98, 0xdf, 0x1e, 0xf9, 0x4f, 0xc3, 0xb7, 0x03, 0x32, 0x3b, 0xe0, 0xc7, 0x8e, 0xe8, 0xd0, 0x11, 0x5e, 0xcf, 0x50, 0xef, 0x34, 0x44, 0xd4, 0x44, 0xec, 0x48, 0x64, 0x3c, 0x11, 0x9e, 0x49, 0xe9, 0x00, 0x3c, 0x3a, 0x33, 0xb7, 0x33, 0xed, 0x2e, 0xf0, 0x4d, 0xc6, 0x0f, 0x5d, 0x69, 0x77, 0xc5, 0x0f,\n\t0xdd, 0x98, 0xdb, 0x6d, 0xa7, 0xa8, 0xdd, 0xd1, 0xa9, 0x3b, 0x7e, 0xef, 0x81, 0x9d, 0x3d, 0x98, 0xdb, 0x03, 0x9f, 0xf6, 0xc4, 0x8e, 0x5e, 0x1c, 0x61, 0x7a, 0x61, 0x73, 0x2f, 0xfc, 0xdc, 0x9b, 0xb2, 0x0f, 0x32, 0xfa, 0x12, 0xd3, 0xbe, 0xf0, 0xec, 0x8b, 0x5f, 0xfa, 0x41, 0xd3, 0x9f, 0x39, 0x03, 0xe8, 0x1b, 0x70, 0x4f, 0xd4, 0x41, 0xe8, 0x37, 0x78, 0x8d, 0xa8, 0x43, 0x90, 0xc3, 0x9a, 0xa4, 0x0e, 0x5b, 0x28, 0xea, 0x70, 0xe2, 0x3c, 0x02, 0x9e, 0x23, 0xb3, 0x01, 0xe4, 0x8c, 0xc2, 0x0f, 0xa3, 0xb0, 0x9f, 0xf5, 0x47, 0x1d, 0x0d, 0xed, 0x18, 0xf4, 0x1d, 0x0b, 0xdf, 0x71, 0x0d, 0x44, 0x1d, 0xcf, 0xd8, 0x78, 0xf8, 0x4e, 0x40, 0xef, 0x89, 0xf8, 0xe6, 0x39, 0xc6, 0x27, 0xc1, 0x77, 0x0a, 0xf1, 0x99, 0x82, 0xcf, 0x9f, 0x67, 0xce, 0x54, 0x7c, 0x39, 0x0d, 0x5d, 0xa6, 0x63, 0xcf,\n\t0x0c, 0x62, 0x37, 0x13, 0xde, 0xb3, 0xb0, 0x7b, 0x36, 0xba, 0xcc, 0x41, 0x8f, 0x39, 0xc4, 0x60, 0x0e, 0x73, 0x58, 0x53, 0xd4, 0x97, 0xd0, 0x7b, 0x2e, 0x39, 0x3a, 0x17, 0x9a, 0x79, 0x1d, 0x00, 0x39, 0xcc, 0xfa, 0xa2, 0xbe, 0x8c, 0x1e, 0xf3, 0x89, 0xcb, 0x02, 0xfa, 0x17, 0x42, 0xbf, 0x08, 0x1d, 0x16, 0x91, 0x63, 0x8b, 0xc9, 0xcf, 0xc5, 0xc8, 0x5f, 0x82, 0xfd, 0x4b, 0xf1, 0xe9, 0x32, 0xf4, 0x5f, 0x4e, 0xdf, 0x72, 0xf8, 0xad, 0x80, 0x76, 0x25, 0x72, 0x56, 0xa2, 0xfb, 0x2b, 0xcc, 0x5f, 0xd5, 0x5a, 0xd4, 0xd5, 0xc4, 0x68, 0x35, 0xf9, 0xbe, 0x86, 0x5c, 0x7b, 0x15, 0x7d, 0xd7, 0x62, 0xf3, 0x5a, 0xf4, 0x5b, 0x87, 0x1e, 0xeb, 0xd0, 0x71, 0x1d, 0x31, 0x5d, 0xcf, 0xfc, 0xf5, 0xf8, 0xf8, 0x35, 0xf2, 0xed, 0x35, 0x68, 0x37, 0xe0, 0xfb, 0x0d, 0xf8, 0x6f, 0x03, 0x7c, 0x36, 0x32,\n\t0xb6, 0x11, 0xf9, 0x1b, 0x91, 0xb7, 0x09, 0xfd, 0x36, 0xe1, 0xb7, 0x4d, 0xd8, 0xf9, 0x3a, 0xba, 0x6f, 0xc6, 0x9e, 0xcd, 0xe8, 0xb4, 0x19, 0x9f, 0xb2, 0x07, 0x56, 0xb7, 0x40, 0xb7, 0x05, 0xde, 0x7e, 0x78, 0xfb, 0xc9, 0x09, 0x3f, 0x3a, 0xf8, 0xa1, 0x4f, 0xa1, 0x6f, 0x2b, 0xbe, 0xdb, 0xc6, 0x9c, 0x6d, 0xe8, 0xbe, 0x9d, 0x39, 0x3b, 0xd0, 0xfb, 0x0d, 0xf8, 0xbf, 0x41, 0x7b, 0x27, 0x39, 0xc5, 0x7a, 0xa5, 0xee, 0x22, 0x6f, 0x76, 0x13, 0xef, 0x3d, 0xc8, 0xdf, 0x4b, 0xac, 0xf7, 0xe1, 0xd3, 0x7d, 0xd0, 0xee, 0x67, 0xde, 0x01, 0xec, 0x3f, 0x80, 0x6e, 0x07, 0xe9, 0x3b, 0x84, 0x1d, 0x6f, 0x21, 0xef, 0x6d, 0xe6, 0xbd, 0x0b, 0xdd, 0x51, 0x6c, 0x7c, 0x8f, 0xf1, 0xf7, 0xe0, 0xf7, 0x3e, 0xfa, 0x7e, 0x80, 0xcf, 0x8f, 0xe1, 0x9b, 0x0f, 0xc9, 0xff, 0x0f, 0xc9, 0xcb, 0x8f, 0xd0, 0xe1,\n\t0x38, 0xf5, 0xe3, 0xe8, 0x71, 0x02, 0xfb, 0x3f, 0xc6, 0x47, 0x9f, 0xa2, 0xeb, 0xa7, 0xf8, 0xe4, 0x24, 0x3e, 0xf8, 0x8c, 0xf9, 0x9f, 0x21, 0xe7, 0x73, 0x78, 0x7c, 0x0e, 0xcd, 0x17, 0x94, 0xa7, 0xd0, 0xe3, 0x4b, 0xe6, 0x7c, 0x85, 0x8d, 0xa7, 0x91, 0x73, 0x06, 0x9a, 0x33, 0xe8, 0xfc, 0x35, 0xe5, 0xd7, 0xd8, 0x7f, 0x16, 0x7f, 0x9d, 0x43, 0x8f, 0xf3, 0xd8, 0x79, 0x1e, 0xfe, 0xdf, 0xd0, 0xf7, 0x1d, 0x71, 0xfb, 0x8e, 0xf8, 0x5f, 0x20, 0x7f, 0x7f, 0x40, 0xc6, 0x45, 0x72, 0xe6, 0x12, 0x3e, 0xbb, 0x4c, 0xfb, 0x47, 0x7c, 0xfb, 0x13, 0xcf, 0xfc, 0x15, 0xfa, 0xaf, 0x22, 0xfb, 0x17, 0xf2, 0xf6, 0x1a, 0x79, 0x79, 0x8d, 0xb9, 0xbf, 0x92, 0x4b, 0xbf, 0x21, 0xeb, 0x3a, 0xb2, 0xd8, 0xbb, 0xaa, 0x37, 0xc8, 0xfb, 0x9b, 0xcc, 0xbb, 0x89, 0xcf, 0x59, 0xef, 0xd4, 0x5b, 0xe4, 0xc1, 0x1d,\n\t0xe6, 0xfe, 0x0e, 0xff, 0xdf, 0xf1, 0xc5, 0xef, 0xc4, 0xfa, 0x0f, 0x78, 0xdf, 0xc5, 0x07, 0x77, 0x89, 0xd3, 0x3d, 0xca, 0x7b, 0xd0, 0xdc, 0x67, 0xfc, 0x01, 0xf4, 0x81, 0xf1, 0xa2, 0xc9, 0x11, 0xd1, 0x94, 0xa9, 0xa2, 0xa9, 0xf1, 0xe0, 0xa8, 0x68, 0x5a, 0x6b, 0xd1, 0xf4, 0x5c, 0xa2, 0x19, 0xe9, 0x40, 0x5e, 0x70, 0x43, 0x34, 0x4f, 0x13, 0xd1, 0x4c, 0x68, 0xad, 0x13, 0xa2, 0xd9, 0x03, 0x44, 0xf3, 0x96, 0x16, 0x8d, 0xbd, 0xa8, 0x96, 0x3e, 0x5a, 0xb4, 0x0c, 0x9b, 0x44, 0x63, 0x1f, 0xaa, 0x65, 0x5e, 0x2a, 0x5a, 0x96, 0xed, 0x00, 0x7e, 0xd9, 0xe8, 0xcf, 0x3e, 0x5a, 0xb4, 0x9c, 0x1d, 0x44, 0xcb, 0x6d, 0x01, 0xe6, 0xe6, 0x01, 0x61, 0xf3, 0x44, 0xcb, 0x0b, 0xaf, 0xfc, 0xf4, 0x85, 0x9f, 0x11, 0xcd, 0x37, 0x44, 0x34, 0xd6, 0x3e, 0x2d, 0x82, 0x79, 0x91, 0x7e, 0xd1, 0x0a, 0xc2,\n\t0xbf, 0xd0, 0x49, 0xd1, 0x0a, 0x5f, 0x12, 0xed, 0x29, 0xf8, 0x14, 0xb9, 0x23, 0x5a, 0x31, 0x5d, 0x34, 0xf6, 0x7c, 0x5a, 0x14, 0xfa, 0x45, 0x1d, 0x14, 0xad, 0x84, 0x0f, 0x8c, 0x00, 0xa7, 0x44, 0x2b, 0x09, 0x7f, 0xce, 0xf1, 0x5a, 0xa9, 0x6c, 0xa0, 0x01, 0xc0, 0x8e, 0x52, 0xd8, 0x50, 0x3a, 0x13, 0x80, 0xbe, 0x0c, 0xbc, 0xca, 0xc5, 0x89, 0x56, 0x1e, 0x39, 0x15, 0xa0, 0xad, 0x08, 0xaf, 0x4a, 0xc8, 0xaf, 0x74, 0x4c, 0xb4, 0xca, 0xf4, 0x57, 0xa9, 0x25, 0x1a, 0xc7, 0x10, 0xad, 0x1a, 0x3c, 0xaa, 0xa3, 0x5b, 0x0d, 0xf8, 0xd7, 0xa4, 0xaf, 0x26, 0x72, 0x6b, 0x63, 0x53, 0x0c, 0x34, 0x31, 0xe8, 0x12, 0xbb, 0x46, 0xb4, 0x3a, 0x2f, 0x8a, 0x56, 0x77, 0x86, 0x68, 0x0d, 0x56, 0x82, 0x9d, 0xa2, 0x35, 0xa4, 0x6c, 0x4c, 0xd9, 0x74, 0xbd, 0x68, 0xcd, 0x90, 0xdb, 0x02, 0xde, 0x2d, 0xf0,\n\t0x41, 0x4b, 0xfc, 0xd7, 0xaa, 0xbc, 0x68, 0xad, 0xa3, 0x44, 0x6b, 0x87, 0xde, 0xf1, 0xe8, 0x16, 0x0f, 0x0f, 0xd6, 0x37, 0xad, 0x23, 0x36, 0x3f, 0x83, 0xbd, 0xcf, 0x5c, 0x10, 0xad, 0x13, 0x7e, 0x4d, 0xa4, 0x9d, 0x84, 0x5f, 0x3a, 0x17, 0x04, 0xf0, 0xe9, 0xc2, 0xbc, 0x64, 0xf8, 0x26, 0x63, 0x7b, 0x32, 0x73, 0xd8, 0xb3, 0x69, 0x5d, 0xf1, 0x75, 0x57, 0x78, 0x76, 0xc5, 0xe6, 0xae, 0xf0, 0xef, 0x8a, 0x8e, 0x5d, 0x99, 0xdf, 0xbd, 0x1a, 0x20, 0x16, 0xdd, 0xd1, 0xad, 0x3b, 0xbe, 0xe8, 0x01, 0x6d, 0x0f, 0x74, 0xef, 0x81, 0xad, 0x3d, 0xe0, 0xd5, 0x03, 0xde, 0x9c, 0xfd, 0x35, 0xd6, 0x3b, 0xad, 0x37, 0xfc, 0x7b, 0xe3, 0x8f, 0x3e, 0xf8, 0xae, 0x6f, 0x11, 0xd1, 0xfa, 0x61, 0x7f, 0x7f, 0xfc, 0xd1, 0x9f, 0x18, 0xf5, 0x87, 0x67, 0xff, 0xbd, 0xe0, 0x8a, 0x68, 0x03, 0xb0, 0x79, 0x00,\n\t0xfe, 0x19, 0x08, 0xfd, 0xe0, 0x3a, 0x20, 0x59, 0xb4, 0x21, 0xd8, 0xcd, 0x1a, 0xa8, 0x0d, 0xc1, 0xaf, 0x43, 0x90, 0x3b, 0x14, 0x7f, 0x0d, 0x85, 0x6e, 0x28, 0xfe, 0x1e, 0x8a, 0xac, 0xa1, 0x8c, 0x0f, 0x65, 0x7c, 0x28, 0xe3, 0x43, 0x19, 0x1f, 0x46, 0x5e, 0x0c, 0x47, 0xb7, 0xe1, 0xc8, 0x1b, 0xce, 0xf8, 0x70, 0xc6, 0x87, 0x33, 0x3e, 0x9c, 0xf1, 0xe1, 0x8c, 0x0f, 0xc7, 0xb7, 0x23, 0xf0, 0xc9, 0x08, 0x7c, 0x3e, 0x02, 0xdd, 0x46, 0xc2, 0x6f, 0x14, 0xbe, 0x1b, 0x45, 0xdf, 0x28, 0xe4, 0xb2, 0xa6, 0x6a, 0xa3, 0xa0, 0x7b, 0x16, 0xfd, 0x9e, 0xed, 0x23, 0xda, 0x68, 0x64, 0x8d, 0xc1, 0xae, 0xb1, 0xf0, 0x65, 0x3f, 0xa7, 0x8d, 0xc7, 0x8f, 0x13, 0xd0, 0x71, 0x02, 0x7e, 0x98, 0x48, 0xce, 0x3c, 0x97, 0x28, 0xda, 0x24, 0xfc, 0x3f, 0x69, 0x21, 0xc0, 0xee, 0x49, 0xc4, 0x64, 0x12, 0xb2,\n\t0x26, 0xe1, 0x93, 0x49, 0xf8, 0x70, 0x12, 0xf2, 0x26, 0x93, 0x6f, 0x93, 0xf1, 0xf3, 0x64, 0xec, 0x9e, 0x02, 0x9e, 0x47, 0xaf, 0xe7, 0x99, 0x3b, 0x15, 0x99, 0x53, 0xf1, 0xeb, 0x54, 0xf2, 0x6f, 0x1a, 0xb2, 0xa7, 0xa1, 0xf3, 0x34, 0xe6, 0x4f, 0x47, 0x9f, 0xe9, 0xe8, 0xfc, 0x02, 0x7c, 0x66, 0x10, 0xaf, 0x19, 0xc8, 0x9b, 0x01, 0x7f, 0xf6, 0x7d, 0xda, 0x4c, 0xf4, 0x9b, 0x89, 0xcf, 0x67, 0x31, 0x6f, 0x36, 0xf1, 0x7d, 0x91, 0x1c, 0x63, 0xdf, 0xa7, 0xbd, 0x44, 0x9c, 0x5e, 0xc2, 0x97, 0x73, 0x91, 0x33, 0x0f, 0x3f, 0xb3, 0x36, 0x6b, 0x2f, 0x53, 0x7f, 0x99, 0x9c, 0x7e, 0x19, 0x3b, 0xe7, 0x13, 0x8b, 0xf9, 0xf4, 0xcd, 0x27, 0xa7, 0xe6, 0x13, 0xb7, 0xf9, 0xf8, 0x65, 0x3e, 0x3a, 0xcc, 0x67, 0x7c, 0x3e, 0xe3, 0x0b, 0x18, 0x5f, 0xc0, 0xf8, 0x02, 0xc6, 0x17, 0x30, 0xbe, 0x80, 0xf1,\n\t0x05, 0x8c, 0x2f, 0x60, 0x7c, 0x01, 0xe3, 0x0b, 0x19, 0x5f, 0xc8, 0xf8, 0x42, 0xc6, 0x17, 0x32, 0xbe, 0x90, 0xf1, 0x85, 0x8c, 0x2f, 0x64, 0x7c, 0x21, 0xe3, 0x8b, 0x18, 0x5f, 0xc4, 0xf8, 0x22, 0xc6, 0x17, 0x31, 0xbe, 0x88, 0xf1, 0x45, 0x8c, 0x2f, 0x62, 0x7c, 0x11, 0xe3, 0x8b, 0x19, 0x5f, 0xcc, 0xf8, 0x62, 0xc6, 0x17, 0x33, 0xbe, 0x98, 0xf1, 0xc5, 0x8c, 0x2f, 0x66, 0x7c, 0x31, 0xe3, 0x4b, 0x18, 0x5f, 0xc2, 0xf8, 0x12, 0xc6, 0x97, 0x30, 0xbe, 0x84, 0xf1, 0x25, 0x8c, 0x2f, 0x61, 0x7c, 0x09, 0xe3, 0x4b, 0x19, 0x5f, 0xca, 0xf8, 0x52, 0xc6, 0x97, 0x32, 0xce, 0x3b, 0x45, 0x5b, 0xca, 0xf8, 0x52, 0xc6, 0x97, 0x32, 0xbe, 0x8c, 0xf1, 0x65, 0x8c, 0x2f, 0x63, 0x7c, 0x19, 0xe3, 0xcb, 0x18, 0x5f, 0xc6, 0xf8, 0x32, 0xc6, 0x97, 0x31, 0xbe, 0x3c, 0x5b, 0x2a, 0x56, 0xe0, 0xbf, 0x57,\n\t0xa0, 0xe1, 0x7d, 0xa3, 0xad, 0xc6, 0xef, 0xab, 0xf1, 0xf1, 0x6a, 0xe2, 0xb4, 0x86, 0xf8, 0xbe, 0x8a, 0xdf, 0x5f, 0x25, 0xd7, 0x5f, 0xc5, 0xbf, 0x6b, 0x89, 0xe5, 0x7a, 0x72, 0xe0, 0x35, 0xc6, 0x36, 0x12, 0xaf, 0x4d, 0xf8, 0xfb, 0x75, 0x72, 0xe1, 0x75, 0xf2, 0x74, 0x33, 0xfc, 0xb7, 0x90, 0x1b, 0x7e, 0xe6, 0xa7, 0x20, 0x67, 0x2b, 0xf9, 0xbb, 0x8d, 0x9c, 0xd9, 0x4e, 0xcc, 0x76, 0x30, 0x67, 0x07, 0xb9, 0xff, 0x06, 0xb4, 0x6f, 0x4c, 0x0a, 0x81, 0x98, 0xbe, 0x09, 0xef, 0x37, 0xe9, 0x7b, 0x13, 0xd9, 0x6f, 0x92, 0x33, 0x6f, 0xc2, 0x77, 0x27, 0x63, 0x3b, 0x79, 0xd6, 0x76, 0x31, 0xb6, 0x8b, 0xfa, 0x6e, 0x62, 0xbc, 0x87, 0xe7, 0x6f, 0x2f, 0xd8, 0x87, 0x8c, 0xfd, 0xc4, 0xf3, 0x00, 0xfc, 0x0e, 0xb2, 0x9e, 0x1d, 0x42, 0xf7, 0xb7, 0xc8, 0xc3, 0xb7, 0xd0, 0xf7, 0x2d, 0xe2, 0x7e,\n\t0x98, 0x67, 0xe3, 0xf0, 0x99, 0xff, 0x0c, 0x47, 0xd0, 0xf5, 0x6d, 0xf2, 0xfd, 0x6d, 0xf2, 0xe2, 0x1d, 0x72, 0xf2, 0x1d, 0x64, 0x1c, 0x45, 0xfe, 0x87, 0xf0, 0xfc, 0x08, 0x99, 0xc7, 0x79, 0x86, 0x4f, 0x90, 0x3b, 0x27, 0xc8, 0xa7, 0x8f, 0xd3, 0xa5, 0xe2, 0x93, 0x5c, 0x21, 0x90, 0xcf, 0x9f, 0xe2, 0x9b, 0x93, 0xe4, 0xe2, 0x67, 0xe8, 0xf2, 0x39, 0x3a, 0x7d, 0xc1, 0xf3, 0x70, 0x0a, 0x3f, 0x7d, 0x09, 0xef, 0xaf, 0xd0, 0xe9, 0x34, 0xbe, 0xfe, 0x9a, 0x75, 0xe7, 0x2c, 0xcf, 0xee, 0x79, 0xe6, 0x7e, 0x43, 0x4c, 0xbe, 0xc5, 0x47, 0x17, 0xe8, 0xff, 0x81, 0xf6, 0x45, 0xf2, 0xf7, 0x32, 0x36, 0xfd, 0x48, 0xdf, 0x15, 0x62, 0xf2, 0x33, 0x72, 0xae, 0xe1, 0xdb, 0x6b, 0xf8, 0xef, 0x1a, 0xed, 0x5f, 0x79, 0x6e, 0x7f, 0xa5, 0xef, 0x37, 0x78, 0xfc, 0xc6, 0x5a, 0xf7, 0x1b, 0xbe, 0xbe, 0x8e,\n\t0x8e, 0xd7, 0x4f, 0xa4, 0xe2, 0x06, 0x3e, 0xba, 0x89, 0xff, 0x6e, 0xe2, 0xcf, 0x5b, 0xe8, 0x79, 0x0b, 0x39, 0xb7, 0xe0, 0x75, 0x9b, 0x38, 0xdf, 0xc1, 0x4f, 0xbf, 0xf3, 0x0c, 0xfd, 0xce, 0x73, 0xfd, 0x07, 0x71, 0xb8, 0xcb, 0xfc, 0x7b, 0xc8, 0xbf, 0x87, 0x9e, 0xf7, 0xe0, 0x7f, 0x8f, 0xfe, 0xfb, 0xf8, 0xf9, 0x3e, 0xcf, 0xd8, 0x7d, 0xfc, 0x7c, 0x9f, 0xe7, 0xe6, 0x3e, 0xcf, 0xe6, 0x03, 0x62, 0xf2, 0x00, 0xbf, 0x3e, 0xc0, 0x9f, 0x0f, 0x78, 0x8e, 0x1f, 0x30, 0xf7, 0x01, 0xb2, 0x02, 0xf0, 0x0e, 0xac, 0x11, 0x5d, 0x6a, 0x81, 0x64, 0x70, 0x0c, 0xdc, 0x10, 0x5d, 0xc9, 0x0b, 0xea, 0x80, 0x3e, 0xe0, 0x9a, 0xe8, 0x6a, 0x69, 0x30, 0x00, 0xf8, 0x01, 0x6d, 0x6d, 0x08, 0xa0, 0xd4, 0x5b, 0x83, 0x2b, 0xa2, 0x1b, 0xcc, 0x35, 0xce, 0x8b, 0xee, 0x61, 0x9e, 0x87, 0xba, 0x67, 0x13, 0xb8,\n\t0x24, 0xba, 0x59, 0x10, 0x24, 0x82, 0xa5, 0xe0, 0x94, 0xe8, 0x56, 0x36, 0x10, 0x07, 0xe8, 0x63, 0xef, 0xaf, 0x3b, 0xc8, 0xf6, 0xd2, 0xf6, 0xba, 0xe5, 0x5e, 0x70, 0x52, 0xf4, 0x74, 0xf0, 0x4d, 0x4f, 0x5f, 0xfa, 0x7b, 0xa2, 0x67, 0xd8, 0x2e, 0x7a, 0xc6, 0x78, 0x40, 0x5f, 0xa6, 0x85, 0xa2, 0x67, 0xae, 0x06, 0x90, 0x99, 0x19, 0xbd, 0x38, 0x13, 0xe8, 0xbc, 0x0f, 0xf5, 0xcc, 0xd0, 0x64, 0x3e, 0x23, 0x7a, 0x96, 0x74, 0x80, 0xf1, 0x2c, 0x8c, 0x65, 0xa1, 0x3f, 0x0b, 0xb6, 0x64, 0x81, 0x47, 0xd6, 0x28, 0xd0, 0x01, 0xcc, 0x00, 0xc8, 0xc8, 0x76, 0x47, 0xf4, 0xec, 0x99, 0xc0, 0x8b, 0xa2, 0xe7, 0xc0, 0x2e, 0xde, 0x9f, 0x7a, 0x4e, 0xea, 0x39, 0xd1, 0x2f, 0x17, 0xfa, 0xe7, 0x6a, 0x00, 0xe0, 0x91, 0x8b, 0xbe, 0x5c, 0xd8, 0x9b, 0x87, 0xf1, 0x30, 0x64, 0x84, 0x31, 0x1e, 0x86, 0x1e,\n\t0xf9, 0xa6, 0x8a, 0x9e, 0xff, 0x04, 0xc0, 0xbe, 0xfc, 0xf0, 0x0a, 0xc7, 0xc6, 0x70, 0xe4, 0x86, 0xa3, 0x73, 0x78, 0x0f, 0xd1, 0x23, 0x44, 0x74, 0xce, 0x18, 0x7a, 0x64, 0x2e, 0x40, 0x7f, 0x24, 0xb6, 0x46, 0xa2, 0x6b, 0x24, 0x3c, 0x22, 0xb1, 0x2f, 0x92, 0xb1, 0x82, 0xf8, 0xa1, 0x10, 0x7c, 0x0a, 0xa3, 0x53, 0x11, 0x7c, 0x59, 0x8c, 0x76, 0x71, 0x74, 0xe6, 0xdd, 0xab, 0x97, 0x38, 0x22, 0x7a, 0x49, 0xe4, 0x96, 0x44, 0x46, 0x49, 0xe4, 0x95, 0x42, 0xd7, 0x52, 0xe8, 0x59, 0x0a, 0xfe, 0xa5, 0x88, 0x41, 0x29, 0xf4, 0x2a, 0x8d, 0xcf, 0xcb, 0x60, 0x2f, 0x67, 0x10, 0xbd, 0x0c, 0xb1, 0x2b, 0x83, 0x4f, 0xca, 0x30, 0xbf, 0x2c, 0xb2, 0xcb, 0xa2, 0x2f, 0x67, 0x12, 0xbd, 0x1c, 0x76, 0x94, 0x83, 0x57, 0x79, 0x74, 0x28, 0x8f, 0x7f, 0xcb, 0xd3, 0x57, 0x1e, 0x9d, 0x2b, 0xc0, 0xab, 0x02,\n\t0xbc, 0x2a, 0xc0, 0xab, 0x02, 0xbc, 0x2a, 0x20, 0xab, 0x22, 0xba, 0x55, 0xc4, 0x5f, 0x15, 0x2f, 0x88, 0x5e, 0x09, 0x5d, 0x2b, 0xad, 0x07, 0xf8, 0xaa, 0x12, 0x3a, 0x54, 0x72, 0xfb, 0xb0, 0x33, 0x1a, 0x79, 0xd1, 0x3e, 0x50, 0x1e, 0xc0, 0x3b, 0x1a, 0x39, 0xd1, 0xf0, 0x88, 0x86, 0x3e, 0x9a, 0xd8, 0x44, 0x13, 0xf3, 0x68, 0xf4, 0x8f, 0xc6, 0xc6, 0x68, 0xe4, 0x44, 0xe3, 0xfb, 0xca, 0xe8, 0x5e, 0x19, 0xff, 0x54, 0x8e, 0x06, 0x4d, 0x00, 0xbe, 0xa8, 0x8c, 0xbd, 0x95, 0xb1, 0xbd, 0x32, 0xfa, 0x56, 0x46, 0x76, 0x65, 0x74, 0xac, 0x8c, 0x6f, 0x2b, 0x63, 0x53, 0x15, 0xf4, 0xaf, 0x82, 0x6e, 0x55, 0xc8, 0xa1, 0x2a, 0x23, 0x00, 0xfe, 0xa9, 0xb2, 0x12, 0xa0, 0x5f, 0x15, 0xf4, 0xaf, 0x42, 0x9c, 0xab, 0xe0, 0x93, 0xaa, 0x3a, 0xc0, 0xbf, 0x55, 0xb1, 0xbf, 0x2a, 0xf6, 0x57, 0xc5, 0xfe,\n\t0xaa, 0xf8, 0xbe, 0xea, 0x68, 0x80, 0x4d, 0x55, 0xb1, 0xb7, 0xea, 0x4e, 0x80, 0x4d, 0x55, 0xc9, 0xcb, 0x6a, 0xf8, 0xa0, 0x1a, 0xf2, 0xaa, 0xa1, 0x53, 0x75, 0xf4, 0xae, 0x8e, 0x7d, 0x35, 0xf0, 0x79, 0x0d, 0x74, 0xa9, 0x81, 0x8d, 0x35, 0xe1, 0x53, 0x13, 0x59, 0x35, 0xd1, 0xa3, 0x16, 0xb6, 0xd5, 0x42, 0x5e, 0x6d, 0xf8, 0xd7, 0x66, 0xbc, 0x36, 0x7d, 0x31, 0xd8, 0x10, 0x33, 0x4f, 0xf4, 0x58, 0xe4, 0xc6, 0x62, 0x73, 0x2c, 0x36, 0xd6, 0xc1, 0x8f, 0x75, 0x90, 0x57, 0x07, 0xff, 0xd4, 0x45, 0xe7, 0xba, 0xf8, 0xab, 0x1e, 0xfe, 0xa9, 0x47, 0x5f, 0x3d, 0x74, 0xad, 0xcf, 0x9c, 0xfa, 0xf8, 0xa6, 0x3e, 0x76, 0x35, 0x40, 0x3f, 0xf6, 0x33, 0x7a, 0x43, 0xf2, 0xab, 0x21, 0xe3, 0x0d, 0xd1, 0xa9, 0x11, 0x7a, 0x37, 0x42, 0x66, 0x23, 0x7c, 0xdb, 0x18, 0xbf, 0x34, 0xc6, 0x77, 0x4d, 0x18,\n\t0x6f, 0x82, 0xdd, 0x4d, 0xf0, 0x49, 0x53, 0xfc, 0xdc, 0x14, 0x3b, 0x9a, 0xe1, 0xc3, 0x66, 0xe8, 0xd1, 0x0c, 0x3d, 0x9b, 0x33, 0xde, 0x1c, 0x9e, 0xcd, 0xf1, 0x41, 0x1c, 0x76, 0xc4, 0x31, 0xa7, 0x05, 0x7d, 0x2d, 0xb0, 0xbd, 0x05, 0x32, 0x5b, 0x62, 0x47, 0x4b, 0x62, 0xd1, 0x0a, 0x3d, 0x5b, 0x91, 0xc3, 0xad, 0x90, 0xd9, 0x1a, 0x3b, 0x5b, 0x33, 0xbf, 0x35, 0xbe, 0x6b, 0x43, 0x0c, 0xda, 0xd0, 0xd7, 0x16, 0xdb, 0xda, 0x22, 0xa7, 0x2d, 0xb6, 0xb5, 0x23, 0x36, 0xed, 0xe0, 0xd9, 0x0e, 0x9e, 0xf1, 0xe8, 0x11, 0x0f, 0x9f, 0x04, 0x9e, 0xcd, 0x04, 0xf4, 0x4c, 0xa0, 0xde, 0x1e, 0x3b, 0xdb, 0xe3, 0xbb, 0xa7, 0x2d, 0x00, 0xcf, 0xa7, 0xe9, 0xeb, 0x00, 0xcf, 0x0e, 0xf0, 0xec, 0xc0, 0xfc, 0x8e, 0xac, 0x13, 0x1d, 0x89, 0x23, 0x7b, 0x2e, 0xfd, 0x19, 0xe2, 0xf6, 0x0c, 0x3a, 0x75, 0xc2,\n\t0xf6, 0x4e, 0xc4, 0x21, 0x91, 0x78, 0x26, 0xe2, 0xaf, 0x44, 0x7c, 0x93, 0xc4, 0x78, 0x12, 0x32, 0x93, 0x98, 0xd3, 0x19, 0xdb, 0x3b, 0x93, 0x2f, 0x5d, 0xc8, 0xa9, 0x2e, 0x8c, 0x77, 0xc1, 0xb6, 0x64, 0xe4, 0x24, 0x23, 0x33, 0x19, 0xdf, 0x74, 0x25, 0x06, 0x9c, 0x37, 0xf5, 0x6e, 0xd8, 0xde, 0x0d, 0xdb, 0xba, 0x11, 0x8f, 0xee, 0xd4, 0xbb, 0x23, 0xb3, 0x3b, 0x76, 0xf4, 0x40, 0x66, 0x0f, 0xe6, 0xf7, 0xc0, 0x77, 0x3d, 0xf1, 0x6d, 0x4f, 0x6c, 0xea, 0x85, 0xcc, 0x5e, 0xc4, 0xa8, 0x37, 0xb6, 0xf7, 0x26, 0x1e, 0xbd, 0x99, 0xd3, 0x87, 0x39, 0x7d, 0x98, 0xd3, 0x07, 0x9e, 0x7d, 0xe9, 0xeb, 0x8b, 0x1d, 0x7d, 0xc9, 0x01, 0xce, 0xa1, 0x7a, 0x3f, 0x74, 0xea, 0x8f, 0xef, 0xfa, 0x93, 0x8b, 0xfd, 0xc9, 0xd7, 0x01, 0xc8, 0x1c, 0x40, 0x5e, 0x0c, 0x64, 0xfe, 0x40, 0xe2, 0x38, 0x10, 0x5f,\n\t0x0c, 0x44, 0xb7, 0x81, 0xe3, 0x01, 0x7c, 0x07, 0xba, 0x63, 0xcc, 0x19, 0x88, 0xae, 0x03, 0xe1, 0x37, 0x08, 0xdb, 0x06, 0x41, 0x37, 0x88, 0x38, 0x0d, 0x62, 0xee, 0x20, 0xe2, 0x31, 0x08, 0xfa, 0x41, 0xf8, 0x72, 0x10, 0x31, 0x18, 0x84, 0x7e, 0x83, 0x19, 0x1b, 0x8c, 0xcf, 0x07, 0x33, 0x77, 0x08, 0x7c, 0x87, 0xe0, 0x83, 0x21, 0xc4, 0x68, 0x08, 0xf6, 0x0f, 0x41, 0xef, 0x21, 0xd8, 0x36, 0x04, 0x9b, 0xd9, 0xff, 0xe9, 0x43, 0x88, 0xf5, 0x10, 0xec, 0x18, 0x42, 0xce, 0x0e, 0x85, 0x8e, 0xbd, 0x9f, 0x3e, 0x94, 0xf1, 0xa1, 0x8c, 0xb3, 0xff, 0xd3, 0x87, 0x32, 0x3e, 0x0c, 0x1e, 0xc3, 0x18, 0x1b, 0x06, 0x8f, 0x61, 0xf0, 0x18, 0x86, 0x8e, 0xc3, 0x98, 0x33, 0x1c, 0x3f, 0x0e, 0xa7, 0x3e, 0x1c, 0xdf, 0x8c, 0x40, 0x8f, 0x91, 0xe4, 0xfb, 0x48, 0xec, 0x1a, 0xc9, 0xd8, 0x28, 0xc6, 0x46,\n\t0x61, 0xef, 0x28, 0x9e, 0xa3, 0x51, 0xe4, 0xe2, 0xb3, 0xc4, 0xe8, 0x59, 0x72, 0x76, 0x34, 0xfe, 0x1a, 0x4d, 0x9d, 0x33, 0xb5, 0x3e, 0x9a, 0xf6, 0x18, 0xda, 0x63, 0x68, 0x8f, 0xa1, 0x3d, 0x86, 0xf6, 0x58, 0x62, 0x3c, 0x16, 0x3f, 0x8f, 0xc5, 0x7f, 0x63, 0xe9, 0x1b, 0x8b, 0xed, 0x63, 0xc9, 0xfb, 0xb1, 0xf0, 0x18, 0x87, 0x1e, 0xe3, 0xf0, 0xdd, 0x38, 0xec, 0x1b, 0x87, 0x7d, 0xe3, 0x98, 0xc7, 0xbe, 0x51, 0x1f, 0x4f, 0xff, 0x78, 0x72, 0x67, 0x3c, 0xbe, 0x1f, 0x8f, 0x1d, 0xe3, 0xe1, 0x33, 0x1e, 0x7f, 0x4f, 0x80, 0xd7, 0x04, 0x74, 0x9e, 0x00, 0xbf, 0x09, 0xd0, 0x4e, 0x80, 0x76, 0x02, 0x3e, 0x9d, 0x80, 0x8f, 0x26, 0x90, 0xeb, 0x13, 0xa0, 0x9b, 0x00, 0xdd, 0x44, 0xe6, 0x4e, 0xc4, 0x2f, 0x13, 0xc9, 0xb3, 0x89, 0xf8, 0x71, 0x22, 0x7e, 0x7b, 0x0e, 0xbd, 0x9f, 0xc3, 0x8e, 0xe7,\n\t0xf0, 0xfb, 0x73, 0xc4, 0x69, 0x12, 0x7e, 0x9f, 0x84, 0x0f, 0x26, 0x91, 0x2f, 0x93, 0xf0, 0xd1, 0x24, 0xec, 0x9e, 0x44, 0x5e, 0x4d, 0xc2, 0x47, 0xec, 0x4d, 0xf5, 0x49, 0xe4, 0x1f, 0xfb, 0x52, 0x9d, 0x3d, 0xa9, 0x3e, 0x19, 0xba, 0xc9, 0xe4, 0xf7, 0x64, 0xec, 0x9f, 0x0c, 0xcd, 0x64, 0xe2, 0x32, 0x19, 0x5e, 0x93, 0x19, 0x9f, 0x4c, 0xbe, 0x4f, 0x21, 0xa7, 0xa7, 0x10, 0xc3, 0x29, 0xd0, 0x4c, 0x21, 0x3f, 0x9e, 0x47, 0xff, 0xe7, 0x99, 0x3f, 0x15, 0xfd, 0xd8, 0xa7, 0xea, 0xd3, 0xdc, 0x12, 0x3d, 0xa7, 0xa1, 0xe7, 0x34, 0xf4, 0x9c, 0x86, 0x7f, 0xa7, 0xb1, 0x7e, 0x4f, 0x87, 0xef, 0x74, 0x74, 0x99, 0x81, 0x9f, 0x67, 0xe2, 0xdf, 0xd9, 0xcc, 0x9b, 0x8d, 0x3f, 0x66, 0x13, 0x93, 0xd9, 0xd8, 0x37, 0x1b, 0xdf, 0xcf, 0x66, 0xce, 0x6c, 0xe6, 0xcc, 0x66, 0xce, 0x8b, 0x3c, 0xe7, 0x73,\n\t0xa0, 0x9d, 0x83, 0x6d, 0x73, 0xb0, 0x6d, 0x0e, 0xb6, 0xcd, 0x21, 0x17, 0xe7, 0xe0, 0xa7, 0x39, 0xf8, 0x69, 0x0e, 0xf6, 0xbf, 0x84, 0x2e, 0x2f, 0x11, 0xef, 0x97, 0xb0, 0xe3, 0x25, 0x74, 0x9b, 0x4b, 0x7b, 0x2e, 0xba, 0xcd, 0x45, 0xb7, 0xb9, 0xe8, 0x36, 0x97, 0x31, 0xf6, 0xbd, 0xfa, 0x5c, 0x6c, 0x98, 0xcb, 0xb3, 0x31, 0x97, 0xe7, 0x70, 0x2e, 0x3a, 0xcc, 0xc3, 0x1f, 0xf3, 0xd0, 0xe7, 0x65, 0xfc, 0x3b, 0x1f, 0x3f, 0xcf, 0x77, 0x4b, 0x74, 0x67, 0xff, 0xab, 0xcf, 0x47, 0xf7, 0x85, 0xf0, 0x59, 0x08, 0x9f, 0x85, 0xf0, 0x61, 0x5f, 0xab, 0x2f, 0x84, 0xcf, 0x42, 0xf8, 0x2c, 0x84, 0x0f, 0x7b, 0x5b, 0x7d, 0x21, 0x7c, 0x16, 0x92, 0xcf, 0x8b, 0xb0, 0x61, 0x11, 0x36, 0x2c, 0x22, 0xa6, 0x8b, 0x98, 0xcf, 0xfe, 0x56, 0x5f, 0x84, 0x1d, 0x8b, 0xf0, 0xff, 0x22, 0x7c, 0xc6, 0x1e, 0x57,\n\t0x5f, 0x4c, 0x7c, 0x16, 0x13, 0xef, 0xc5, 0xe4, 0xc3, 0x62, 0xf2, 0x61, 0x31, 0xf3, 0x16, 0xe3, 0x67, 0xf6, 0xb5, 0xfa, 0x12, 0xc6, 0x96, 0x60, 0xff, 0x12, 0xe6, 0xb2, 0xb7, 0xd5, 0x97, 0x30, 0x77, 0x09, 0x73, 0x97, 0x30, 0x97, 0xfd, 0xad, 0xbe, 0x04, 0x5d, 0x97, 0xa2, 0xeb, 0x52, 0x74, 0x65, 0x8f, 0xab, 0xb3, 0xc7, 0xd5, 0xd9, 0xe3, 0xea, 0xec, 0x71, 0x75, 0xf6, 0xb8, 0x3a, 0x7b, 0x5c, 0x9d, 0x3d, 0xae, 0xce, 0x1e, 0x57, 0x67, 0x8f, 0xab, 0x2f, 0x23, 0xb6, 0xcb, 0x88, 0xed, 0x32, 0xe2, 0xc6, 0x3e, 0x57, 0x5f, 0x46, 0x6c, 0x97, 0x11, 0x9b, 0x65, 0xc4, 0x6e, 0x19, 0xb9, 0xb2, 0x1c, 0x79, 0xcb, 0xd1, 0x65, 0x39, 0xfe, 0x5e, 0xce, 0xf8, 0x72, 0xc6, 0x97, 0x33, 0xbe, 0x9c, 0xf1, 0xe5, 0xf0, 0x59, 0x81, 0xdd, 0x2b, 0xb0, 0x7b, 0x05, 0x39, 0xb7, 0x02, 0x39, 0x2b, 0xd0,\n\t0x67, 0x05, 0xfa, 0xac, 0x40, 0x9f, 0x15, 0xc8, 0x5a, 0x81, 0x3e, 0x2b, 0xd1, 0x67, 0x25, 0xfa, 0xac, 0x44, 0xde, 0x4a, 0xe4, 0xad, 0x44, 0xde, 0x4a, 0xe4, 0xad, 0x84, 0xdf, 0x4a, 0xec, 0x5b, 0x09, 0xcd, 0x2b, 0xd0, 0xbc, 0x02, 0xcd, 0x2b, 0xc4, 0x6a, 0x15, 0x63, 0xab, 0x18, 0x5b, 0xcd, 0xb3, 0xb2, 0x9a, 0x78, 0xae, 0x26, 0x9e, 0xab, 0x89, 0xe7, 0x6a, 0xe2, 0xb9, 0x9a, 0x78, 0xb2, 0xd7, 0xd6, 0xd7, 0x10, 0x83, 0x35, 0xc4, 0x60, 0x0d, 0xba, 0xad, 0x41, 0xb7, 0x35, 0xe4, 0xd0, 0x1a, 0xe2, 0xb0, 0x86, 0x7c, 0x78, 0x95, 0xbe, 0x57, 0x79, 0x7e, 0xd6, 0xe2, 0xeb, 0xb5, 0xe8, 0xbf, 0x16, 0x7f, 0xad, 0x85, 0x66, 0x2d, 0xba, 0xad, 0x65, 0x7c, 0x2d, 0xf9, 0xb2, 0x0e, 0x5d, 0xd6, 0xc1, 0x77, 0x1d, 0xb2, 0xd6, 0x21, 0x6b, 0x1d, 0x76, 0xad, 0xc3, 0xae, 0x75, 0xd8, 0xb5, 0x0e,\n\t0xbb, 0xd6, 0x63, 0xd7, 0x7a, 0xec, 0x5a, 0x4f, 0x3c, 0xd7, 0xe3, 0xc3, 0xf5, 0xc4, 0x73, 0x3d, 0xf1, 0x5c, 0x4f, 0x3c, 0xd7, 0xe3, 0xc7, 0xd7, 0xe8, 0x7b, 0x8d, 0x67, 0x76, 0x03, 0x7a, 0x6c, 0x40, 0x8f, 0x0d, 0xd8, 0xbf, 0x81, 0x35, 0x61, 0x83, 0xdb, 0x47, 0x1e, 0x6e, 0x20, 0x76, 0x1b, 0x90, 0xb3, 0x81, 0xbc, 0xdc, 0x44, 0xfc, 0x36, 0x11, 0xbf, 0xd7, 0xf1, 0xf9, 0xeb, 0xd8, 0xf3, 0x3a, 0x7e, 0x7a, 0x1d, 0x5d, 0x5f, 0x47, 0xde, 0xeb, 0xe4, 0xe4, 0x66, 0xfa, 0x37, 0xa3, 0xe7, 0x66, 0xf4, 0xd9, 0x8c, 0x9d, 0x9b, 0xb1, 0x73, 0x33, 0x76, 0x6e, 0xc6, 0xce, 0xcd, 0xe4, 0xed, 0x66, 0x97, 0x86, 0x58, 0x6c, 0x41, 0xd6, 0x16, 0x64, 0x6d, 0x41, 0xd6, 0x16, 0xfa, 0xfd, 0xd0, 0xfb, 0xa1, 0xf7, 0xa3, 0x7f, 0x0a, 0xfa, 0xa5, 0x20, 0x77, 0x2b, 0x76, 0x6d, 0x85, 0xef, 0x56, 0xec,\n\t0xd8, 0x8a, 0x1d, 0xdb, 0xb0, 0x63, 0x1b, 0x76, 0x6c, 0xc3, 0x8e, 0x6d, 0xe8, 0xb7, 0x0d, 0xfd, 0xb6, 0x21, 0x7b, 0x1b, 0x7e, 0xd8, 0x86, 0x7e, 0xdb, 0xd0, 0x6f, 0x1b, 0xcf, 0xda, 0x76, 0x9e, 0xaf, 0xed, 0xe8, 0xb8, 0x83, 0xdc, 0xdc, 0x41, 0x6e, 0xee, 0xc0, 0x87, 0x3b, 0xd0, 0x73, 0x07, 0x7a, 0xec, 0x40, 0x8f, 0x1d, 0xc8, 0x7b, 0x03, 0x3d, 0xdf, 0x40, 0xe6, 0x9b, 0xc8, 0xdf, 0x89, 0x2e, 0x3b, 0xe1, 0xb9, 0x13, 0x3f, 0xec, 0x44, 0xf6, 0x4e, 0x7c, 0xb3, 0x13, 0xdf, 0xec, 0xc4, 0x37, 0x3b, 0xc9, 0xf5, 0x9d, 0xd8, 0xbc, 0x13, 0x7e, 0xbb, 0x98, 0xb3, 0x0b, 0xdb, 0x76, 0x11, 0x83, 0x5d, 0xe4, 0xec, 0x2e, 0x78, 0xee, 0x22, 0x0e, 0xbb, 0xc8, 0x91, 0x5d, 0xf0, 0xdc, 0x05, 0xcd, 0x6e, 0xe2, 0xbc, 0x1b, 0x3e, 0xbb, 0xe1, 0xb3, 0x1b, 0x3e, 0xbb, 0xf1, 0xdd, 0x6e, 0xf2, 0x62,\n\t0x37, 0x3c, 0x76, 0x33, 0xbe, 0x07, 0x1e, 0x7b, 0xe0, 0xb1, 0x07, 0x1e, 0x7b, 0xe0, 0xb1, 0x07, 0x1e, 0x7b, 0xe0, 0xb1, 0x07, 0x1b, 0xf6, 0x60, 0xc3, 0x5e, 0x74, 0xdd, 0xcb, 0x9a, 0xb9, 0x17, 0xda, 0x7d, 0xd0, 0xee, 0x83, 0x76, 0x1f, 0xb4, 0xfb, 0xa0, 0xe5, 0xec, 0xa3, 0xef, 0x83, 0xcf, 0x7e, 0x72, 0x61, 0x3f, 0xb6, 0xed, 0xc7, 0xb6, 0xfd, 0xd0, 0xef, 0x27, 0x1f, 0xf6, 0x93, 0x33, 0xfb, 0xd1, 0x63, 0x3f, 0xb9, 0xba, 0x9f, 0x5c, 0xdd, 0x4f, 0x1e, 0x1e, 0x20, 0x0f, 0x0f, 0x90, 0x87, 0x07, 0xf0, 0xe3, 0x01, 0x72, 0xf5, 0x00, 0xb9, 0x7a, 0x80, 0xb1, 0x03, 0x8c, 0x1d, 0x64, 0xec, 0x20, 0xba, 0x1e, 0x44, 0xf6, 0x41, 0xe6, 0x1d, 0x64, 0xde, 0x41, 0xc6, 0x0e, 0x32, 0x76, 0x88, 0xb1, 0x43, 0xcc, 0x3b, 0xc4, 0xbc, 0x43, 0xcc, 0x3b, 0xc4, 0xbc, 0x43, 0xe4, 0xd6, 0x21, 0x62,\n\t0x73, 0x88, 0xdc, 0x7a, 0x8b, 0x98, 0xbc, 0x45, 0x4c, 0xde, 0x22, 0x26, 0x87, 0x89, 0xc9, 0x61, 0x62, 0x72, 0x18, 0xff, 0x1d, 0xc6, 0xee, 0xc3, 0xc4, 0xf0, 0x30, 0x31, 0x3f, 0x8c, 0xaf, 0x0f, 0xe3, 0xeb, 0xc3, 0xf8, 0xe5, 0x30, 0x3c, 0x8f, 0xc0, 0xf3, 0x08, 0x3c, 0x8f, 0xe0, 0xef, 0x23, 0xc4, 0xee, 0x6d, 0xe6, 0xbf, 0x4b, 0xac, 0x8e, 0x12, 0xab, 0xa3, 0xe8, 0x71, 0x94, 0x5c, 0x3a, 0x4a, 0x3c, 0x8e, 0x32, 0xff, 0x28, 0xf3, 0x8f, 0x32, 0xff, 0x7d, 0xf4, 0x7a, 0x1f, 0xbd, 0xde, 0x47, 0xaf, 0xf7, 0xe1, 0x71, 0x8c, 0x79, 0xc7, 0x88, 0xf9, 0x31, 0x72, 0xe3, 0x18, 0x7e, 0x3d, 0x86, 0x5f, 0x3f, 0x44, 0x9f, 0x8f, 0x18, 0x3b, 0x4e, 0xfb, 0x38, 0xed, 0xe3, 0xf8, 0xee, 0x38, 0xcf, 0xcb, 0x09, 0x7c, 0x74, 0x02, 0x1f, 0x7d, 0x0c, 0xbf, 0x4f, 0x98, 0xf3, 0x09, 0x73, 0x3e, 0x81,\n\t0xe6, 0x13, 0x68, 0x3e, 0x81, 0xe6, 0x13, 0x68, 0x3e, 0x85, 0xe6, 0x53, 0x68, 0x3e, 0xc5, 0x8f, 0x9f, 0xe2, 0xc7, 0x93, 0xf8, 0xf9, 0x24, 0x7e, 0x3e, 0x89, 0x9f, 0x4f, 0xe2, 0x97, 0x93, 0xc8, 0x3f, 0x89, 0xfc, 0x93, 0xc8, 0x3f, 0x89, 0x8c, 0xcf, 0xb0, 0xe1, 0x33, 0x6c, 0xf8, 0x0c, 0x5b, 0x3f, 0x27, 0x3e, 0xa7, 0x88, 0xf1, 0x29, 0x62, 0x7c, 0x8a, 0x5c, 0x39, 0x45, 0xae, 0x9c, 0x82, 0xef, 0x69, 0x78, 0x9e, 0x86, 0xe7, 0x69, 0x78, 0x9e, 0x86, 0xe7, 0x69, 0x78, 0x9d, 0x21, 0xb6, 0x67, 0x88, 0xed, 0x19, 0x78, 0x7c, 0x8d, 0xbe, 0x5f, 0xe3, 0xbf, 0xaf, 0xb1, 0xff, 0x6b, 0xfc, 0x77, 0x96, 0xdc, 0x3b, 0x4b, 0x8e, 0x9d, 0x25, 0xae, 0xe7, 0x98, 0x7b, 0x1e, 0x5f, 0x9c, 0xc7, 0x17, 0xe7, 0xf1, 0xc5, 0x79, 0x74, 0x3f, 0x8f, 0xcf, 0xbf, 0xe1, 0x79, 0xf9, 0x16, 0xba, 0x6f, 0x79,\n\t0x5e, 0xbe, 0xc5, 0x7f, 0xdf, 0xe2, 0x87, 0x6f, 0xb1, 0xe9, 0x5b, 0x6c, 0xfa, 0x16, 0x9b, 0xbe, 0xc5, 0xa6, 0x6f, 0x91, 0xfd, 0x2d, 0x36, 0x7d, 0x07, 0x8f, 0xef, 0x90, 0x7f, 0x01, 0xb9, 0xdf, 0x23, 0xf3, 0x12, 0xcf, 0xdb, 0x25, 0xe6, 0x5f, 0x66, 0xfe, 0x65, 0xe6, 0x5f, 0x66, 0xfe, 0x65, 0xe6, 0x5f, 0x66, 0xfe, 0x65, 0xe6, 0x73, 0xe6, 0xd4, 0x7f, 0x24, 0x46, 0x3f, 0x51, 0xff, 0x09, 0x5e, 0x57, 0x98, 0x7b, 0x05, 0xdd, 0xaf, 0xe0, 0x87, 0xab, 0xd0, 0x5d, 0x85, 0xee, 0x2a, 0x63, 0x57, 0x19, 0xbb, 0x8a, 0x9c, 0xab, 0xc8, 0xb9, 0x8a, 0x9c, 0x9f, 0x91, 0xf3, 0x33, 0xb4, 0x3f, 0x43, 0xfb, 0x33, 0x76, 0xfe, 0x4c, 0x0e, 0xfe, 0x8c, 0xcf, 0x7e, 0x86, 0xdf, 0x2f, 0x8c, 0xfd, 0x82, 0x8f, 0x7e, 0x21, 0x1f, 0x7e, 0xc1, 0x47, 0xbf, 0xe0, 0xa3, 0x6b, 0xd0, 0xfc, 0x8a, 0xef, 0x7e,\n\t0xc3, 0xf6, 0xdf, 0xb0, 0xfd, 0x3a, 0xbc, 0xaf, 0xc3, 0xfb, 0x3a, 0xbc, 0xaf, 0xc3, 0xfb, 0x3a, 0xbc, 0xaf, 0xc3, 0xfb, 0x26, 0x3e, 0xbe, 0x49, 0xde, 0xdf, 0x24, 0xef, 0x6f, 0x12, 0x8f, 0x9b, 0xd8, 0x7f, 0x13, 0x9f, 0xdd, 0xc4, 0x47, 0x37, 0xf1, 0xd1, 0x4d, 0xfc, 0x7e, 0x0b, 0xbf, 0xdc, 0x22, 0x47, 0x6e, 0xc3, 0xe3, 0x36, 0x3c, 0x6e, 0xc3, 0xe3, 0x36, 0x3c, 0x38, 0xe7, 0xea, 0x7f, 0x90, 0x37, 0x7f, 0xa0, 0xc3, 0x1f, 0xd8, 0xf4, 0x07, 0xb6, 0xff, 0x81, 0xed, 0x77, 0xb1, 0xfd, 0x2e, 0xb6, 0xdf, 0xc5, 0xf6, 0xbb, 0xcc, 0xb9, 0xcb, 0x1c, 0xce, 0xbe, 0xfa, 0x3d, 0xe4, 0xdd, 0xc3, 0x16, 0xce, 0xbf, 0xfa, 0x7d, 0x6c, 0xb9, 0x8f, 0x2d, 0xf7, 0xd1, 0xf3, 0x3e, 0xb6, 0xdc, 0xe7, 0x79, 0xba, 0xcf, 0xda, 0xf2, 0x00, 0x9e, 0x0f, 0x88, 0xc7, 0x03, 0xe8, 0x02, 0xd0, 0x05, 0xa0,\n\t0x0b, 0x40, 0x17, 0x80, 0x2e, 0x00, 0x5d, 0x00, 0xba, 0x00, 0x32, 0x03, 0xdb, 0xc5, 0x90, 0x4b, 0x62, 0x28, 0x02, 0x72, 0x81, 0x3a, 0xa0, 0x03, 0x18, 0x02, 0x66, 0x80, 0x35, 0x60, 0x2f, 0x38, 0x09, 0xae, 0x88, 0xa1, 0xea, 0x20, 0x2f, 0x28, 0x0f, 0x9a, 0x80, 0x64, 0x30, 0x1a, 0xcc, 0x03, 0x9b, 0xc0, 0x11, 0x31, 0x34, 0xe8, 0x35, 0xe8, 0x35, 0xe8, 0x0d, 0x78, 0x7a, 0xce, 0x8b, 0x61, 0xde, 0x13, 0x83, 0x33, 0xb1, 0x61, 0x45, 0x01, 0x64, 0xd8, 0x89, 0x60, 0x04, 0x78, 0x11, 0xf8, 0xc5, 0xf0, 0xd2, 0xf6, 0xd2, 0xf6, 0xd2, 0xf6, 0xae, 0x07, 0x07, 0xc1, 0x29, 0x70, 0x4d, 0x8c, 0x74, 0xf0, 0x4a, 0x07, 0xaf, 0xf4, 0xc8, 0x4e, 0xcf, 0xfc, 0xf4, 0xcc, 0x4f, 0x0f, 0x7d, 0xc6, 0x49, 0x00, 0xda, 0x8c, 0xd0, 0x66, 0xb6, 0x80, 0x0f, 0x44, 0x83, 0x38, 0xd0, 0x43, 0x8c, 0x2c, 0xb5,\n\t0x40, 0x3c, 0x18, 0x00, 0xa6, 0x82, 0x95, 0x60, 0x27, 0x38, 0x01, 0xb0, 0x39, 0x2b, 0x36, 0x67, 0x45, 0xbf, 0xac, 0xf0, 0xcb, 0x0a, 0x7d, 0x56, 0x6c, 0xc8, 0x76, 0x43, 0x8c, 0xec, 0x20, 0x47, 0x3a, 0x50, 0x10, 0x54, 0x03, 0xad, 0x41, 0x1f, 0x80, 0xbc, 0x1c, 0x4b, 0x01, 0x3e, 0xcb, 0x71, 0x0c, 0x5c, 0x00, 0xd8, 0x95, 0xb3, 0x08, 0xc0, 0x17, 0x39, 0xd1, 0x3f, 0x37, 0xf2, 0xf3, 0xc0, 0x27, 0x0f, 0xbe, 0xc8, 0x83, 0x2f, 0xf2, 0x9c, 0x01, 0xf0, 0x0b, 0x83, 0x5f, 0x18, 0xfc, 0xc2, 0xe0, 0x17, 0x06, 0xbf, 0x30, 0xf8, 0x85, 0xc1, 0x2f, 0x0c, 0x7e, 0x9c, 0xb9, 0x8d, 0x30, 0xf8, 0x85, 0xc1, 0x2f, 0x0c, 0x7e, 0x79, 0xe1, 0x97, 0x17, 0xdd, 0xf3, 0xa2, 0x7b, 0x5e, 0x7c, 0x9b, 0x17, 0xbd, 0xf3, 0xa2, 0x77, 0x5e, 0xf4, 0xce, 0x8b, 0xde, 0xf9, 0xd1, 0x3b, 0x3f, 0x7a, 0xe7, 0x2f,\n\t0x0d, 0x1a, 0x00, 0x7c, 0x11, 0x0e, 0x6d, 0x38, 0x76, 0x86, 0x63, 0x67, 0x38, 0xf4, 0xe1, 0xd0, 0x87, 0x43, 0x1f, 0x7e, 0x29, 0xf5, 0x9f, 0x90, 0xf1, 0xd1, 0xef, 0xa3, 0xdf, 0x47, 0x7f, 0x04, 0x3a, 0x45, 0xa0, 0x53, 0x01, 0x74, 0x2a, 0x80, 0x4e, 0x05, 0xd0, 0xa9, 0x00, 0xfd, 0x05, 0xa0, 0x2f, 0x00, 0x7d, 0x24, 0xf4, 0x9c, 0xe9, 0x8d, 0x48, 0xf8, 0x47, 0xc2, 0x9f, 0x73, 0xbd, 0x11, 0x89, 0x6d, 0x91, 0xff, 0x87, 0xb6, 0xf7, 0x80, 0x8f, 0xeb, 0xaa, 0x12, 0xc6, 0xef, 0x7d, 0x75, 0x7a, 0xd1, 0x34, 0x4d, 0x93, 0x34, 0x9a, 0xae, 0x2e, 0x8d, 0x34, 0xea, 0xd2, 0x93, 0xac, 0x2e, 0xd9, 0xb2, 0xdc, 0x65, 0x49, 0x6e, 0x92, 0xe5, 0x6e, 0xcb, 0x25, 0x71, 0x1c, 0x3b, 0x4e, 0xec, 0x38, 0xcd, 0x49, 0x9c, 0x4a, 0x28, 0x49, 0x20, 0x90, 0x02, 0xa9, 0x98, 0x84, 0x34, 0x12, 0x20, 0xc4,\n\t0xde, 0xc0, 0x42, 0x60, 0xd9, 0xef, 0x4b, 0xb2, 0xbb, 0xf9, 0x01, 0x7f, 0xb2, 0xcb, 0x02, 0x4b, 0x59, 0x42, 0x58, 0x20, 0x10, 0x6b, 0xfc, 0x9d, 0x7b, 0xdf, 0x7b, 0x53, 0x64, 0xc9, 0x76, 0x58, 0xfe, 0xce, 0x4f, 0x99, 0x99, 0xf7, 0xee, 0xbd, 0xef, 0xdc, 0x73, 0xce, 0x3d, 0xed, 0x9e, 0x7b, 0x1e, 0xd0, 0x26, 0x08, 0xf8, 0x0e, 0x02, 0xbe, 0x83, 0x40, 0x9b, 0x20, 0xd0, 0x26, 0x04, 0x78, 0x0f, 0x01, 0xde, 0x43, 0x30, 0xef, 0x30, 0x8c, 0x15, 0xfe, 0x10, 0xf1, 0x51, 0xf8, 0x8c, 0xc2, 0x7c, 0x62, 0x40, 0xd7, 0x38, 0xf0, 0x52, 0x09, 0xcc, 0xb7, 0x14, 0xc6, 0x2b, 0xfd, 0x14, 0xe2, 0xcb, 0x01, 0x37, 0xe0, 0xd7, 0x93, 0x92, 0x36, 0x7c, 0x15, 0xfc, 0xae, 0x06, 0xbc, 0x57, 0xc3, 0x9c, 0x6b, 0xa0, 0x7f, 0x0d, 0x8c, 0x99, 0x80, 0xf6, 0x09, 0xc0, 0x43, 0x2d, 0xc0, 0x53, 0x07, 0xbc,\n\t0x95, 0x04, 0x7a, 0x27, 0xbf, 0x83, 0xf8, 0x7a, 0xc0, 0x6f, 0x3d, 0xe0, 0xa9, 0x01, 0xf0, 0xd6, 0x00, 0xbc, 0xd0, 0x08, 0x73, 0x6d, 0x84, 0x76, 0x4d, 0x00, 0x5f, 0x13, 0xe0, 0xba, 0x19, 0xda, 0xb6, 0xc0, 0x98, 0x2d, 0xf0, 0x6c, 0xf0, 0x7d, 0xf9, 0x56, 0xe0, 0xb5, 0x56, 0xe8, 0xdb, 0x0a, 0xb4, 0x05, 0x3f, 0x98, 0x6f, 0x05, 0x7e, 0x6e, 0x05, 0x7e, 0x6e, 0x05, 0x7e, 0x6e, 0x05, 0xfe, 0x6c, 0x05, 0x9e, 0x6a, 0x85, 0x71, 0xda, 0x80, 0xa7, 0xda, 0xa0, 0x4f, 0x1b, 0xb4, 0x6b, 0x83, 0x31, 0xda, 0x80, 0x26, 0x6d, 0xd0, 0xa6, 0x0d, 0x68, 0xd7, 0x06, 0xe3, 0xb7, 0xc3, 0xfd, 0x76, 0xe0, 0xf7, 0x76, 0xe0, 0xf7, 0x76, 0x80, 0xa1, 0x1d, 0xda, 0xb4, 0x03, 0x4d, 0xda, 0x61, 0x1e, 0xed, 0xf0, 0xdc, 0x76, 0x68, 0xd7, 0x0e, 0xf8, 0x6c, 0x07, 0x7c, 0x4a, 0x80, 0x4f, 0x09, 0xc6, 0x92,\n\t0x00, 0x9f, 0x12, 0xcc, 0x59, 0x02, 0x58, 0x25, 0x78, 0xa6, 0x04, 0xed, 0x24, 0xc0, 0x87, 0x04, 0xcf, 0xeb, 0x80, 0x36, 0x1d, 0x00, 0x57, 0x07, 0x8c, 0xd5, 0x01, 0xf7, 0x3b, 0xe0, 0x7e, 0x07, 0xdc, 0xef, 0x80, 0xfb, 0x1d, 0xf0, 0xbc, 0x0e, 0x80, 0xbd, 0x13, 0x60, 0xef, 0x84, 0x36, 0x9d, 0x00, 0x53, 0x27, 0xc0, 0xde, 0x09, 0xb0, 0x77, 0x42, 0xbb, 0x4e, 0x80, 0xab, 0x13, 0x60, 0x5f, 0x04, 0x7d, 0x17, 0x01, 0x1c, 0x8b, 0x00, 0x8e, 0x45, 0x00, 0xc7, 0x22, 0xe8, 0xbf, 0x08, 0xe0, 0x58, 0x04, 0x70, 0x2c, 0x02, 0x38, 0xba, 0xe0, 0x19, 0x5d, 0x00, 0x47, 0x17, 0xc0, 0xd1, 0x05, 0x70, 0x74, 0xc1, 0x73, 0xba, 0xa0, 0x7f, 0x17, 0xb4, 0xeb, 0x82, 0xe7, 0x74, 0x01, 0x1c, 0xdd, 0xd0, 0xa6, 0x1b, 0x9e, 0xd1, 0x0d, 0x63, 0x75, 0xc3, 0xfd, 0x6e, 0xe0, 0x8f, 0x6e, 0xa0, 0x6d, 0x37,\n\t0xe0, 0xba, 0x1b, 0xd6, 0x6b, 0x37, 0xd0, 0xb1, 0xe7, 0x3a, 0xc4, 0xf7, 0x02, 0x0c, 0xbd, 0x00, 0x43, 0x2f, 0xc0, 0xd0, 0x0b, 0x63, 0xf4, 0x02, 0x0c, 0xbd, 0x00, 0x43, 0x2f, 0xe0, 0x0f, 0xfc, 0x7d, 0xbe, 0x0f, 0xf0, 0xd3, 0x07, 0xf8, 0xe9, 0x03, 0xfc, 0xf4, 0xc1, 0x58, 0x7d, 0x00, 0x57, 0x1f, 0xc0, 0xd5, 0x07, 0x70, 0xf5, 0xc1, 0xf3, 0xfa, 0x00, 0xae, 0x7e, 0x98, 0x57, 0x3f, 0xcc, 0x6b, 0x00, 0xe6, 0x35, 0x00, 0xcf, 0x1c, 0x80, 0x31, 0x07, 0x60, 0xcc, 0x01, 0x18, 0x73, 0x00, 0xc6, 0x1c, 0x80, 0x31, 0x07, 0x60, 0xcc, 0x01, 0x18, 0x73, 0x00, 0xc6, 0x1c, 0x84, 0x31, 0x07, 0x61, 0xcc, 0x41, 0x18, 0x73, 0x10, 0xc6, 0x1c, 0x84, 0x31, 0x07, 0x61, 0xcc, 0x41, 0x18, 0x73, 0x10, 0xc6, 0x1c, 0x84, 0x31, 0x07, 0x61, 0xae, 0x43, 0xc0, 0x2f, 0x8b, 0xe1, 0xda, 0x62, 0xb8, 0xb6,\n\t0x18, 0xae, 0x2d, 0x86, 0x6b, 0x8b, 0x61, 0xfe, 0x4b, 0x60, 0x6e, 0x4b, 0x60, 0xfe, 0x4b, 0x60, 0xfe, 0x4b, 0x60, 0xfe, 0x4b, 0x60, 0x7e, 0x4b, 0x80, 0xae, 0x4b, 0x60, 0xad, 0x2d, 0x01, 0x1e, 0x5a, 0x02, 0x38, 0x58, 0x02, 0xcf, 0x19, 0x86, 0x76, 0xc3, 0x00, 0xcf, 0x30, 0x3c, 0x63, 0x18, 0xda, 0x0c, 0x03, 0x2c, 0xc3, 0x30, 0xd6, 0x30, 0xdc, 0x1f, 0x86, 0xfb, 0x4b, 0xe1, 0xfe, 0x52, 0xb8, 0xbf, 0x14, 0x70, 0xb2, 0x14, 0x70, 0xb2, 0x14, 0x70, 0x32, 0x62, 0x81, 0x3f, 0x58, 0x9f, 0x23, 0xd0, 0x67, 0x04, 0x78, 0x70, 0x04, 0x9e, 0x3f, 0x02, 0xbc, 0x3a, 0x02, 0x6b, 0x67, 0x19, 0xf0, 0xf3, 0x32, 0xe0, 0xf9, 0x65, 0xd0, 0x7e, 0x19, 0xb4, 0x5f, 0x06, 0xed, 0x97, 0x43, 0xfb, 0xe5, 0xb0, 0x8e, 0x96, 0x03, 0x1c, 0xcb, 0xe1, 0x19, 0x2b, 0x60, 0x4e, 0x2b, 0xa0, 0xef, 0x0a, 0x98,\n\t0xd3, 0x0a, 0x98, 0xd3, 0x4a, 0x78, 0xde, 0x6a, 0x58, 0x5b, 0xab, 0x61, 0x4d, 0xac, 0x06, 0xfc, 0xaf, 0x86, 0xb5, 0xb5, 0x06, 0xf0, 0xb3, 0x06, 0xf0, 0xb3, 0x06, 0xf0, 0xb3, 0x06, 0x60, 0x1a, 0x85, 0xb5, 0x31, 0x0a, 0xf7, 0x47, 0xe1, 0xfe, 0x28, 0xdc, 0x1f, 0x85, 0x79, 0x8f, 0xc2, 0xda, 0x5b, 0x0b, 0xf4, 0x59, 0x0b, 0xb8, 0x5b, 0x0b, 0xdf, 0xc7, 0x00, 0xb7, 0x63, 0x30, 0xf6, 0x18, 0x8c, 0x3b, 0x06, 0x6d, 0xc7, 0xa0, 0xed, 0x18, 0xe0, 0x63, 0x1c, 0xf0, 0x30, 0x0e, 0x63, 0x8d, 0x03, 0x9c, 0xe3, 0x30, 0xaf, 0x09, 0xc0, 0xed, 0x04, 0xe0, 0x65, 0x02, 0xc6, 0x9e, 0x80, 0xdf, 0xeb, 0xe0, 0xfe, 0x06, 0x58, 0x9b, 0x1b, 0xa0, 0xdf, 0x06, 0xe8, 0xb3, 0x01, 0xae, 0x6d, 0x80, 0xf1, 0x36, 0xc2, 0x78, 0x1b, 0xe1, 0xb9, 0x1b, 0x41, 0x96, 0x6e, 0x84, 0xb6, 0x1b, 0x61, 0x6e, 0x1b,\n\t0x81, 0x46, 0x1b, 0x61, 0x5e, 0x1b, 0x61, 0x5e, 0x9b, 0x60, 0x5e, 0x9b, 0x00, 0x0f, 0x9b, 0x40, 0x4e, 0x6d, 0x02, 0xd9, 0xb3, 0x09, 0x70, 0xb1, 0x09, 0x9e, 0xb1, 0x09, 0x70, 0xb1, 0x09, 0x9e, 0x3b, 0x09, 0x6b, 0x71, 0x12, 0xc6, 0x9d, 0x84, 0xb9, 0x4e, 0x02, 0x9c, 0x93, 0x80, 0xf7, 0x49, 0xe0, 0x81, 0x29, 0xc0, 0xc5, 0x14, 0xcc, 0x77, 0x0a, 0x68, 0xbd, 0x19, 0xee, 0x6f, 0x86, 0xb1, 0x37, 0x43, 0x9f, 0x69, 0xc0, 0xf3, 0x34, 0xc8, 0xa7, 0x2d, 0xb0, 0x9e, 0xb7, 0xc0, 0xf3, 0xb7, 0x82, 0xcc, 0xd9, 0x0a, 0xb0, 0x6c, 0x03, 0x58, 0xb7, 0x01, 0x5c, 0xdb, 0xe1, 0xfe, 0x76, 0xa0, 0xdf, 0x0e, 0xa0, 0xc9, 0x0e, 0x98, 0xdf, 0x4e, 0x18, 0x7f, 0x27, 0xd0, 0x74, 0x27, 0xc0, 0xb2, 0x0b, 0xf0, 0xb8, 0x0b, 0xe8, 0xbf, 0x1b, 0xe6, 0xb6, 0x1b, 0xe0, 0xd9, 0x0d, 0xcf, 0xdb, 0x0d, 0xb0,\n\t0xee, 0x86, 0xe7, 0xed, 0x81, 0xf1, 0xf6, 0x00, 0x0e, 0xf7, 0x00, 0xce, 0x66, 0xe0, 0xfe, 0x0c, 0xd0, 0x60, 0x06, 0xe0, 0xdb, 0x0b, 0x7d, 0xf6, 0x42, 0x9f, 0x7d, 0x70, 0x6d, 0x1f, 0xe0, 0x7b, 0x3f, 0xc0, 0xb2, 0x1f, 0xae, 0xed, 0x87, 0x6b, 0x07, 0x60, 0x2e, 0x07, 0x80, 0x2e, 0x07, 0x40, 0x16, 0x5e, 0x01, 0xf8, 0xb9, 0x02, 0x60, 0xb9, 0x02, 0xfa, 0x5f, 0x09, 0xb8, 0x38, 0x08, 0xcf, 0x3d, 0x08, 0xf0, 0x5c, 0x05, 0x73, 0xbe, 0x0a, 0x68, 0x7e, 0x08, 0x9e, 0x77, 0x08, 0x64, 0xd8, 0x21, 0x80, 0xe9, 0x10, 0xcc, 0xe3, 0x6a, 0xc0, 0xcb, 0xd5, 0xd0, 0xff, 0x6a, 0xe0, 0x81, 0xc3, 0x00, 0xef, 0x11, 0x78, 0xfe, 0x35, 0xc0, 0xcb, 0xd7, 0xc0, 0x33, 0xae, 0x81, 0x67, 0x5f, 0x03, 0xe3, 0x1e, 0x05, 0xbc, 0x1d, 0x05, 0xd8, 0x8f, 0xc2, 0xba, 0xb8, 0x16, 0xc6, 0xbe, 0x0e, 0xf0, 0x7c,\n\t0x0c, 0x64, 0xe8, 0x31, 0xb8, 0x77, 0x1c, 0xe6, 0x79, 0x1c, 0xc6, 0xb9, 0x1e, 0xe6, 0x7d, 0x3d, 0xd0, 0xed, 0x7a, 0x80, 0xe9, 0x7a, 0x18, 0xe7, 0x7a, 0x98, 0xcf, 0xf5, 0x00, 0xf7, 0xf5, 0x30, 0xa7, 0x13, 0x30, 0x16, 0xf8, 0xfc, 0xfc, 0x0d, 0xc0, 0x0b, 0x37, 0x02, 0xfe, 0x6e, 0x04, 0x9a, 0xdc, 0x04, 0xd7, 0x6e, 0x06, 0xdc, 0xdc, 0x0c, 0x70, 0xde, 0x02, 0x78, 0x3c, 0x09, 0xe3, 0xde, 0x0a, 0x30, 0xde, 0x06, 0xf3, 0xba, 0x0d, 0xe0, 0xbd, 0x1d, 0x3e, 0x6f, 0x87, 0xcf, 0x53, 0x80, 0xff, 0x53, 0x30, 0xd6, 0x1d, 0xd0, 0x1e, 0x7c, 0x76, 0xfe, 0x4e, 0x80, 0xef, 0x4e, 0x80, 0xf5, 0x2e, 0x80, 0xf9, 0x6e, 0x80, 0xe1, 0x6e, 0xf8, 0x7e, 0x0f, 0x7c, 0xbf, 0x17, 0xbe, 0xdf, 0x0b, 0xdf, 0x3f, 0x01, 0xb0, 0x7d, 0x02, 0x78, 0xfa, 0x3e, 0xf8, 0x7d, 0x1f, 0xd0, 0xe3, 0x93, 0x30, 0x87,\n\t0x4f, 0xc1, 0x58, 0x9f, 0x82, 0xf9, 0x82, 0x1f, 0xcd, 0x7f, 0x1a, 0xe0, 0xfb, 0x34, 0xd0, 0xeb, 0x33, 0x20, 0x3f, 0xee, 0x07, 0x9e, 0xb9, 0x1f, 0x60, 0x7d, 0x00, 0xae, 0x3f, 0x00, 0x38, 0x01, 0x3f, 0x97, 0x7f, 0x10, 0xe8, 0xff, 0x20, 0x7c, 0x82, 0xff, 0xca, 0x7f, 0x16, 0x60, 0xff, 0x1c, 0x8c, 0x05, 0xbe, 0x27, 0xff, 0x79, 0xc0, 0xd3, 0xe7, 0xe1, 0xf9, 0x5f, 0x00, 0xf8, 0xbf, 0x00, 0x73, 0x79, 0x18, 0xc6, 0x79, 0x18, 0x78, 0xf9, 0x61, 0x78, 0xc6, 0xc3, 0xb0, 0x86, 0x1f, 0x01, 0x5e, 0x06, 0xbf, 0x92, 0x7f, 0x14, 0x70, 0xf7, 0x18, 0xd0, 0xef, 0x8b, 0xd0, 0xee, 0x4b, 0x80, 0x9b, 0xc7, 0x01, 0x9e, 0x27, 0xa0, 0xed, 0x93, 0xa0, 0x77, 0x9e, 0x84, 0xfe, 0x4f, 0xc1, 0xf7, 0xa7, 0x60, 0xdc, 0xa7, 0x01, 0x9f, 0xcf, 0xc0, 0xbd, 0x67, 0x00, 0x87, 0x5f, 0x86, 0x7b, 0x5f, 0x86,\n\t0x7b, 0xa7, 0xa1, 0xef, 0x69, 0x98, 0xdf, 0x69, 0xb8, 0xf6, 0x15, 0x18, 0xef, 0x2b, 0x30, 0xc6, 0xb3, 0x00, 0xe3, 0xb3, 0xd0, 0xf6, 0x39, 0x80, 0xf1, 0x39, 0xc0, 0xd3, 0x73, 0x80, 0xbb, 0xaf, 0xc2, 0x73, 0xbe, 0x0a, 0x63, 0x3c, 0x0f, 0x38, 0x01, 0x3f, 0x8b, 0x7f, 0x01, 0x70, 0xf4, 0x02, 0xf4, 0x79, 0x11, 0x68, 0xfb, 0x22, 0xac, 0x8b, 0x17, 0xe1, 0x19, 0x2f, 0x02, 0x6f, 0xbf, 0x48, 0xae, 0xc1, 0xb8, 0x2f, 0x02, 0x1d, 0x5e, 0x04, 0x18, 0x5f, 0x02, 0x7c, 0xbf, 0x04, 0xfc, 0xf1, 0x12, 0xd0, 0x0a, 0x7c, 0x2e, 0x1e, 0x7c, 0x2e, 0x1e, 0x7c, 0x2e, 0xfe, 0x6b, 0xf0, 0x9c, 0xaf, 0x01, 0xcc, 0xe0, 0x43, 0xf1, 0xe0, 0x2b, 0xf1, 0xaf, 0xc0, 0xfc, 0x5f, 0x85, 0xb1, 0x5e, 0x05, 0xba, 0x82, 0x4f, 0xc4, 0x7f, 0x1d, 0xfa, 0x83, 0xef, 0xc3, 0x7f, 0x03, 0xc6, 0xf8, 0x26, 0x8c, 0xfd,\n\t0x1a, 0x8c, 0xf3, 0x1a, 0x3c, 0xf3, 0x35, 0x80, 0xf5, 0x35, 0xc0, 0x1b, 0xf8, 0x36, 0xfc, 0x6b, 0x40, 0xab, 0xd7, 0x61, 0xbc, 0x7f, 0x28, 0x46, 0x1c, 0x2a, 0x03, 0xe3, 0x92, 0xe5, 0x1f, 0x40, 0x61, 0xd4, 0x88, 0x5a, 0x51, 0x07, 0xea, 0x96, 0x3a, 0x11, 0xcb, 0x60, 0x86, 0xc5, 0x33, 0x08, 0x73, 0x0c, 0xe6, 0x48, 0x29, 0x37, 0x86, 0x45, 0xcc, 0x24, 0x34, 0xe6, 0x35, 0x1c, 0xac, 0x3e, 0xad, 0x56, 0x18, 0x45, 0x82, 0x30, 0x39, 0x88, 0x34, 0x1a, 0x71, 0x14, 0x89, 0xe2, 0x94, 0x38, 0xd4, 0x21, 0x59, 0xad, 0xf6, 0x58, 0x24, 0x58, 0xe2, 0x0b, 0xe9, 0x74, 0xfe, 0x52, 0x5b, 0x1b, 0x9b, 0xa8, 0x29, 0x60, 0x1c, 0x76, 0x13, 0x67, 0xc6, 0xc1, 0x68, 0xa4, 0x8d, 0xab, 0xab, 0x8d, 0x04, 0x8b, 0x4d, 0x4c, 0xb0, 0x38, 0x6a, 0xab, 0x6d, 0x63, 0x94, 0x9b, 0xf0, 0xb3, 0x82, 0xc1, 0x01,\n\t0x6b, 0xa0, 0x1e, 0xfe, 0xfe, 0xec, 0x69, 0xee, 0x59, 0x5a, 0x29, 0x6d, 0x1f, 0x88, 0xfb, 0xcb, 0xeb, 0xaa, 0x82, 0x5c, 0xde, 0x0d, 0x26, 0xde, 0x53, 0x96, 0xac, 0x2c, 0x5a, 0x94, 0x8c, 0xd6, 0x47, 0x7d, 0x06, 0xaf, 0x71, 0x5d, 0x5e, 0x61, 0x89, 0x3b, 0xbf, 0xa4, 0x30, 0x0f, 0x3e, 0xf3, 0xdd, 0xf0, 0x99, 0x7a, 0x98, 0xfd, 0x97, 0x73, 0xf1, 0x24, 0xbb, 0xf9, 0xdc, 0xfd, 0xdc, 0x41, 0x67, 0xc4, 0x6f, 0x0d, 0x75, 0x4c, 0x34, 0xd6, 0x0f, 0x37, 0x97, 0x46, 0x42, 0xae, 0x2d, 0x57, 0x04, 0x13, 0xa5, 0xd1, 0xf2, 0x86, 0x68, 0x65, 0xbd, 0xd5, 0x6e, 0xcd, 0x9f, 0x15, 0xf3, 0x4b, 0x8b, 0xf2, 0xf2, 0x8a, 0x4a, 0xf3, 0xdd, 0xa5, 0x64, 0x80, 0x52, 0xee, 0xd6, 0xbf, 0x4e, 0x35, 0xf1, 0x31, 0x98, 0x1c, 0xfc, 0x07, 0x42, 0x16, 0x70, 0x20, 0x22, 0x07, 0xaa, 0x94, 0xca, 0x58, 0x8c,\n\t0x38, 0x3c, 0x40, 0xcc, 0x56, 0x06, 0x23, 0x66, 0x13, 0xe2, 0xb8, 0xc9, 0x41, 0x16, 0x63, 0x3c, 0x85, 0x87, 0x10, 0x72, 0xd8, 0x6d, 0x56, 0x93, 0x51, 0xa7, 0x81, 0xc6, 0xa2, 0xa0, 0xb3, 0x97, 0x62, 0x36, 0x12, 0x35, 0x61, 0x91, 0xc5, 0xc1, 0xe2, 0x48, 0x94, 0x0d, 0xb0, 0x26, 0x5c, 0x8a, 0x71, 0x82, 0x7d, 0xea, 0x6d, 0x97, 0x4b, 0xef, 0xd2, 0xbf, 0xc5, 0x3e, 0xfe, 0x88, 0x2f, 0xa4, 0xb9, 0x76, 0xf6, 0xa6, 0x6b, 0xc5, 0x88, 0xf7, 0x11, 0xa6, 0xe5, 0x5f, 0x18, 0x17, 0x53, 0xde, 0xb8, 0xba, 0x74, 0xc0, 0x3f, 0xfb, 0xf6, 0xec, 0x7f, 0xf9, 0x9c, 0x78, 0x71, 0xea, 0x39, 0x5b, 0x21, 0x39, 0xe9, 0x00, 0x50, 0xe0, 0xd4, 0x13, 0xfc, 0x3d, 0x14, 0x8e, 0x0a, 0x74, 0xf0, 0x79, 0x00, 0x83, 0xc7, 0x03, 0x83, 0xa7, 0xf3, 0x97, 0xae, 0x91, 0x02, 0x5a, 0x80, 0x86, 0x65, 0x10, 0xbb,\n\t0x09, 0xcc, 0xde, 0xc9, 0x41, 0x81, 0x63, 0x18, 0x66, 0x6a, 0x50, 0x83, 0x45, 0x11, 0x8f, 0x21, 0x8c, 0xb7, 0xe2, 0x21, 0xaf, 0x14, 0x43, 0x1a, 0x46, 0x64, 0x34, 0xe2, 0xcc, 0xbc, 0x6d, 0x51, 0xa6, 0xe9, 0xa8, 0xe4, 0x46, 0xa8, 0xbc, 0x34, 0x16, 0x29, 0x2c, 0xf0, 0xfb, 0xbc, 0x6e, 0xa7, 0x23, 0xcf, 0x6a, 0xd0, 0x91, 0xf9, 0xe8, 0xb2, 0xe7, 0x63, 0x22, 0x33, 0xaa, 0xab, 0x4d, 0xd6, 0x67, 0xcf, 0x0b, 0x07, 0x4d, 0xac, 0xc3, 0xee, 0x4c, 0xd4, 0x10, 0x12, 0xba, 0xd8, 0x27, 0xd5, 0x59, 0xfe, 0xa6, 0x70, 0x5d, 0xed, 0xd8, 0xe6, 0xa1, 0xb6, 0x39, 0x73, 0x6d, 0x89, 0xdb, 0xe3, 0x01, 0x47, 0x65, 0xd4, 0xe9, 0xb7, 0x19, 0x78, 0x33, 0x9f, 0x35, 0xf7, 0x73, 0x6f, 0xb8, 0x7c, 0xc3, 0x9d, 0x8d, 0x9b, 0xa3, 0x19, 0x14, 0xfc, 0x75, 0x4a, 0x5f, 0x10, 0x29, 0x77, 0x07, 0x4b, 0x44,\n\t0x51, 0x34, 0x12, 0x7c, 0x9c, 0xff, 0x13, 0x42, 0xc2, 0xef, 0x01, 0x1f, 0x1c, 0x72, 0xa1, 0x25, 0xd2, 0x20, 0xc6, 0x3c, 0xd0, 0x85, 0x56, 0x2b, 0x10, 0xc4, 0x8d, 0x64, 0x96, 0x8c, 0x06, 0x31, 0x1b, 0x61, 0x96, 0xdc, 0x28, 0x25, 0x92, 0x0e, 0x6b, 0x34, 0x78, 0x4c, 0x21, 0x15, 0xcf, 0x03, 0x55, 0x5d, 0xbc, 0xcb, 0x09, 0x14, 0xcb, 0xb3, 0x5a, 0xcc, 0x26, 0x83, 0x56, 0x23, 0x0a, 0x30, 0x16, 0xa7, 0xa7, 0xd3, 0x14, 0x44, 0x2d, 0x16, 0x03, 0xea, 0xcc, 0x02, 0x8e, 0x80, 0x8d, 0xfc, 0xb1, 0x0f, 0x8f, 0x7b, 0x02, 0xa9, 0xb7, 0x79, 0x0b, 0x3e, 0xf7, 0xc7, 0xca, 0xd9, 0x1f, 0x3f, 0xa1, 0x8f, 0xfb, 0xbf, 0xc0, 0xfc, 0x8e, 0xd3, 0xcf, 0x06, 0x1a, 0x99, 0xe2, 0xd9, 0x3f, 0x34, 0xc1, 0x14, 0x7e, 0xb6, 0xa2, 0x6b, 0xf6, 0xab, 0xa9, 0xfb, 0x9e, 0xc6, 0xd7, 0xa6, 0x9e, 0x75, 0x7a,\n\t0xf9, 0x07, 0x9e, 0x4e, 0x35, 0x7e, 0x91, 0xbc, 0xd2, 0x87, 0x45, 0x5f, 0x81, 0xb5, 0xf4, 0x1c, 0xc0, 0xab, 0x43, 0x36, 0x14, 0x45, 0x5d, 0x52, 0x47, 0x01, 0xc6, 0x0c, 0x40, 0x0c, 0x94, 0x05, 0x56, 0x9a, 0x14, 0x31, 0xcb, 0x72, 0x63, 0x1a, 0x4c, 0x40, 0x15, 0x88, 0x53, 0x34, 0x06, 0xa0, 0x4f, 0xf1, 0x43, 0x0e, 0xbb, 0x5e, 0x8f, 0x51, 0x24, 0x64, 0x8f, 0x3a, 0xa2, 0x7a, 0x9b, 0x3e, 0x0f, 0x20, 0x15, 0x91, 0x0e, 0xeb, 0xb4, 0x00, 0x67, 0x18, 0x30, 0x4d, 0x96, 0x4e, 0xc0, 0x0d, 0x08, 0x4f, 0x92, 0x6f, 0x75, 0xca, 0xd2, 0x11, 0x39, 0x2b, 0x59, 0x40, 0x01, 0x2b, 0xf3, 0xec, 0xc8, 0xfe, 0xfe, 0xe2, 0x7b, 0xef, 0x4f, 0xbd, 0xf5, 0xc7, 0x07, 0x3f, 0x7d, 0xf7, 0x67, 0x6e, 0xfa, 0xd6, 0x91, 0xe6, 0xa2, 0xce, 0xa9, 0x2e, 0xdc, 0xd8, 0x75, 0xfc, 0x1b, 0x87, 0x66, 0x3f, 0x7a,\n\t0x3c, 0xd2, 0x39, 0x96, 0xdc, 0x71, 0x38, 0x15, 0xe0, 0x86, 0x52, 0x25, 0xd7, 0xee, 0x3c, 0x3c, 0xf3, 0xc5, 0xda, 0x4d, 0xb7, 0xae, 0xa9, 0xdd, 0xb0, 0xbc, 0xd3, 0xd9, 0x96, 0xfa, 0xf3, 0xf8, 0x27, 0x77, 0xb7, 0x00, 0xc4, 0x18, 0xad, 0x3d, 0xff, 0x3e, 0x50, 0xe8, 0x29, 0x54, 0x4e, 0x24, 0x80, 0x0d, 0x56, 0x3e, 0x8b, 0x79, 0xc4, 0x0c, 0x20, 0x16, 0x10, 0xc6, 0xa2, 0x19, 0x80, 0x97, 0x27, 0x2a, 0x10, 0xf0, 0xcc, 0x8c, 0x21, 0x86, 0xd9, 0x31, 0x08, 0xb0, 0x53, 0x86, 0xda, 0x89, 0x87, 0x30, 0x8a, 0x86, 0xfd, 0xde, 0x7c, 0xa7, 0xd5, 0x2c, 0xf2, 0xa8, 0x1c, 0x97, 0x8b, 0x04, 0xc1, 0x35, 0x85, 0x94, 0x85, 0x2a, 0x30, 0xc0, 0x9f, 0x97, 0x0c, 0x25, 0x6a, 0x9c, 0x2e, 0x91, 0x5e, 0x60, 0x88, 0x1c, 0x70, 0xd8, 0x0b, 0x18, 0xc2, 0x45, 0xf5, 0x6d, 0x98, 0x7b, 0x20, 0xcf, 0xb8,\n\t0x62, 0xcd, 0xec, 0xb3, 0x0f, 0xcc, 0x3e, 0xb7, 0x69, 0xcb, 0xd7, 0x30, 0xfb, 0xe0, 0xa7, 0xff, 0x7b, 0x4d, 0x8f, 0xe8, 0xb0, 0xda, 0x12, 0xcb, 0xaf, 0x1e, 0xdb, 0xf1, 0xec, 0xb1, 0xde, 0x81, 0xe3, 0xa7, 0xa7, 0xdb, 0x26, 0x97, 0x0f, 0x84, 0x34, 0x79, 0xb8, 0xd6, 0x34, 0xbe, 0x75, 0xdf, 0xce, 0xd7, 0xb1, 0xe9, 0x0b, 0x5f, 0xc0, 0xa6, 0xd7, 0x77, 0x4e, 0x2d, 0x9f, 0xd4, 0x9b, 0x22, 0x95, 0x91, 0xc1, 0xdb, 0xbf, 0x7f, 0xec, 0xfa, 0x37, 0x4f, 0x0d, 0x98, 0x0b, 0x2a, 0x03, 0xa2, 0x96, 0x54, 0xd5, 0x58, 0x9b, 0xba, 0x9f, 0xce, 0xa7, 0x0f, 0xfd, 0xa7, 0xbc, 0x84, 0xcc, 0xa5, 0x58, 0xe4, 0xfd, 0xb0, 0x18, 0x90, 0x19, 0xa8, 0xc2, 0x0e, 0x78, 0x73, 0xaf, 0xb0, 0xec, 0xc0, 0xe8, 0xe0, 0x69, 0x2d, 0x34, 0xac, 0x02, 0xee, 0xd2, 0x8a, 0x82, 0x76, 0x06, 0x01, 0xc3, 0x68, 0x35,\n\t0xbb, 0x61, 0xe5, 0x50, 0x4a, 0xed, 0x20, 0xf2, 0x0e, 0x8d, 0x71, 0x40, 0xb9, 0x9d, 0x20, 0x0f, 0x18, 0x86, 0x4e, 0x7f, 0x06, 0x96, 0x9e, 0xfc, 0x80, 0xcb, 0xe8, 0xb7, 0x27, 0xb7, 0x9f, 0x54, 0x3f, 0xb7, 0x0b, 0xac, 0x5a, 0x10, 0xb6, 0x33, 0xf3, 0x76, 0x45, 0x2c, 0xab, 0xf6, 0x1c, 0x1d, 0x95, 0x4c, 0xbd, 0xdd, 0xb1, 0x60, 0x38, 0xe6, 0x0c, 0xd9, 0x63, 0x79, 0x44, 0xe2, 0x86, 0x4d, 0xd8, 0x8c, 0x0b, 0xb0, 0x2c, 0x54, 0x23, 0xd1, 0xfa, 0x24, 0x11, 0xb1, 0x32, 0xcb, 0x44, 0xeb, 0x2b, 0x98, 0x4b, 0x11, 0x01, 0x56, 0x33, 0x6f, 0x1e, 0xf9, 0x8f, 0x07, 0x2c, 0x13, 0x23, 0x81, 0xe6, 0xe5, 0xd5, 0xf1, 0xfe, 0xa2, 0x3c, 0xc1, 0x26, 0x58, 0x1c, 0x05, 0xf6, 0x68, 0x7c, 0x64, 0x71, 0xfc, 0x8e, 0x5f, 0x3e, 0x32, 0x7a, 0x29, 0xda, 0xe8, 0xf2, 0x8c, 0xdf, 0x5d, 0xbf, 0x57, 0xdb,\n\t0x60, 0xef, 0x4d, 0x06, 0x6a, 0x43, 0x76, 0xb3, 0xa9, 0xd5, 0x06, 0x2b, 0xb9, 0x28, 0x3f, 0xe4, 0xd7, 0x1d, 0xd1, 0x1d, 0x78, 0x0d, 0xb3, 0xf7, 0x5f, 0x84, 0x64, 0x26, 0x22, 0xff, 0x60, 0xfd, 0xf0, 0xf7, 0x01, 0x37, 0x1a, 0x90, 0x1b, 0x15, 0x4a, 0x3e, 0xa4, 0xa0, 0x6a, 0x92, 0x4c, 0x1d, 0x8d, 0x81, 0x48, 0x98, 0x42, 0x43, 0x81, 0x58, 0x20, 0xc4, 0xe9, 0xf2, 0x4b, 0xb1, 0x9d, 0x11, 0x38, 0xe0, 0xfe, 0x40, 0x0d, 0xe7, 0xcc, 0x13, 0x6b, 0x2b, 0x18, 0xfa, 0xbd, 0x8d, 0xe1, 0xef, 0xdb, 0xf2, 0x6a, 0xea, 0xaf, 0x0f, 0xcd, 0xfe, 0x8c, 0xf1, 0x3d, 0x84, 0x85, 0x57, 0xb7, 0xbc, 0xdb, 0x73, 0xec, 0xc5, 0xbd, 0xa9, 0xaf, 0xe1, 0x9e, 0xbd, 0x2f, 0x1e, 0xeb, 0x61, 0x7e, 0xf0, 0xf9, 0xd4, 0x87, 0x5f, 0xdf, 0x0a, 0x16, 0xc4, 0xd7, 0x53, 0x7f, 0x7e, 0xe8, 0xba, 0xef, 0xdd, 0x3e,\n\t0xf0, 0xd1, 0xab, 0x03, 0xb7, 0x7f, 0x57, 0xd5, 0x01, 0x5f, 0x84, 0x67, 0x5b, 0x50, 0x00, 0xb5, 0x4b, 0x2d, 0x22, 0x66, 0x04, 0x4c, 0x68, 0xb1, 0x11, 0x00, 0xe0, 0xc6, 0xb4, 0x74, 0xd1, 0x6a, 0xb2, 0x16, 0x6d, 0x9e, 0x15, 0xa3, 0x22, 0x22, 0x40, 0x3d, 0xd6, 0x40, 0x5e, 0xc0, 0x6c, 0x32, 0x1a, 0xf4, 0x5a, 0x64, 0xc1, 0x16, 0x5d, 0x7a, 0xd1, 0xca, 0x20, 0x39, 0x02, 0x56, 0x4c, 0x40, 0x74, 0x28, 0xf0, 0x06, 0xeb, 0x12, 0x56, 0xe6, 0x27, 0x04, 0x18, 0x05, 0x30, 0x5f, 0xea, 0x67, 0xb8, 0x87, 0x82, 0xaa, 0x00, 0xfe, 0xda, 0x6b, 0x4f, 0x01, 0x4c, 0xc7, 0x08, 0x74, 0xa9, 0xe2, 0x23, 0x29, 0x27, 0xf7, 0x3e, 0x85, 0x96, 0x42, 0xce, 0xdc, 0x77, 0x84, 0x39, 0x49, 0x0b, 0xc7, 0x10, 0x59, 0x53, 0x06, 0xf0, 0xea, 0x89, 0xc6, 0x02, 0xae, 0xe1, 0x78, 0x96, 0xdb, 0x48, 0x30, 0x36,\n\t0x4a, 0x31, 0x26, 0x60, 0x90, 0x7f, 0xa3, 0x32, 0xca, 0xe0, 0xff, 0x7a, 0xa4, 0xb7, 0x92, 0x7f, 0xa2, 0xce, 0x5d, 0x1a, 0x16, 0x65, 0xb0, 0xc8, 0x1f, 0x57, 0x86, 0xcf, 0xdd, 0xc8, 0x5e, 0x3d, 0x3b, 0xce, 0x14, 0xcd, 0xfe, 0xf4, 0xe9, 0xa7, 0xd3, 0xc2, 0x0c, 0xc6, 0x4f, 0x3d, 0xc1, 0xb5, 0x50, 0xbb, 0xe0, 0x0a, 0x99, 0xbd, 0xe3, 0x44, 0xff, 0x0b, 0x1c, 0xbf, 0x11, 0x88, 0xc1, 0x8c, 0xc2, 0x93, 0x80, 0x2c, 0x82, 0x80, 0x47, 0x45, 0x22, 0x6e, 0x07, 0xb5, 0x98, 0x30, 0x2a, 0xad, 0xb3, 0x0d, 0x7c, 0x5d, 0x85, 0xe0, 0x37, 0xd6, 0x6a, 0x66, 0x2e, 0xda, 0x07, 0x65, 0xba, 0x00, 0x3f, 0x87, 0x8a, 0xa3, 0x14, 0x44, 0xab, 0xa3, 0x98, 0xf0, 0x73, 0x46, 0xff, 0x64, 0xa0, 0x0d, 0x88, 0x39, 0xea, 0x87, 0x6b, 0x51, 0xb4, 0xce, 0xec, 0xb8, 0x3a, 0x05, 0xe6, 0x51, 0x3c, 0x96, 0xa3,\n\t0x72, 0x52, 0x3f, 0x56, 0xf4, 0x8c, 0x3a, 0xb5, 0xa7, 0x73, 0x94, 0x8c, 0x8c, 0xc7, 0x52, 0x98, 0xa7, 0x16, 0xc5, 0xa5, 0x08, 0xc1, 0x2c, 0x08, 0xeb, 0x8d, 0x3c, 0x90, 0x9b, 0x1d, 0x05, 0xa0, 0x01, 0x5e, 0x50, 0x9e, 0x0c, 0x41, 0xa1, 0x16, 0x69, 0x09, 0x74, 0x02, 0xe1, 0x3d, 0x0a, 0x4d, 0x10, 0xfe, 0x8f, 0x6f, 0x62, 0xa4, 0xd9, 0xd7, 0xde, 0x61, 0xaf, 0xe6, 0x7e, 0x97, 0x2a, 0x7c, 0x7a, 0xf6, 0x73, 0xf0, 0x14, 0x18, 0x73, 0x14, 0x64, 0x69, 0x37, 0xc8, 0x9e, 0x6a, 0xd4, 0x2a, 0x35, 0xd9, 0x40, 0x05, 0x80, 0xba, 0xe1, 0x30, 0x86, 0xf1, 0x06, 0x80, 0x2e, 0xc4, 0xde, 0xe2, 0x26, 0x55, 0xe6, 0xde, 0x91, 0x66, 0xee, 0x9d, 0x94, 0x52, 0xd5, 0xa8, 0x3a, 0x1c, 0x2b, 0x8b, 0x05, 0x09, 0xa5, 0xb0, 0x95, 0x20, 0x21, 0x14, 0x51, 0x17, 0x6f, 0x01, 0x43, 0x56, 0x6f, 0xb4, 0x82,\n\t0xcd, 0x59, 0xbc, 0x56, 0xc0, 0x53, 0x2b, 0xe6, 0xbb, 0x77, 0xfd, 0xe9, 0xae, 0x67, 0x52, 0xbf, 0x78, 0x63, 0xc7, 0x96, 0xd7, 0xb0, 0xf5, 0x89, 0x55, 0xf7, 0x1c, 0xdd, 0x51, 0xd1, 0x6a, 0xaa, 0xf0, 0x7a, 0xda, 0x57, 0x1f, 0x18, 0xbe, 0xf2, 0x1b, 0x37, 0xf6, 0x0d, 0xdd, 0xfa, 0xed, 0xc3, 0x55, 0xcb, 0x87, 0x7a, 0x83, 0x6f, 0xd9, 0xdd, 0xcc, 0x2b, 0xb3, 0x3f, 0x5c, 0xb2, 0x98, 0x8a, 0xd1, 0x87, 0xb1, 0xf9, 0x5b, 0x3b, 0x3c, 0x55, 0x8b, 0x4a, 0x36, 0xb8, 0x0c, 0x56, 0x73, 0xac, 0x38, 0x7f, 0xf1, 0x9d, 0xdf, 0x3b, 0x7a, 0xe2, 0x9f, 0xef, 0x1a, 0xd2, 0xdb, 0x0b, 0xf2, 0x70, 0x79, 0x7e, 0xde, 0x21, 0xa4, 0xf2, 0x1b, 0xdf, 0x4f, 0xf9, 0x2d, 0x2a, 0x85, 0x80, 0xac, 0xc4, 0x46, 0xda, 0x28, 0xf0, 0x0c, 0xc1, 0x11, 0x98, 0x49, 0xf3, 0xf0, 0x19, 0x26, 0x18, 0x82, 0xbf, 0x04,\n\t0xfc, 0x9f, 0xef, 0x7f, 0x7b, 0xd6, 0xf6, 0xce, 0x3b, 0xcc, 0x6f, 0x89, 0x9a, 0x67, 0x6e, 0x9a, 0x3d, 0xc4, 0x3f, 0x30, 0x7b, 0x23, 0x73, 0x35, 0xac, 0x3a, 0x30, 0x45, 0x78, 0xa2, 0xe3, 0x59, 0xd0, 0xf1, 0x49, 0x29, 0xa1, 0xd7, 0x32, 0xa2, 0x00, 0x12, 0x19, 0x8b, 0x68, 0x23, 0x79, 0x06, 0x8b, 0xb9, 0x8d, 0x44, 0xad, 0x4f, 0x0e, 0xf2, 0x20, 0xa2, 0xa7, 0xd8, 0x21, 0x45, 0x9f, 0x2b, 0xff, 0x2c, 0x06, 0xc2, 0x2a, 0x40, 0x8d, 0x70, 0x50, 0x79, 0x1a, 0x59, 0x5f, 0xe4, 0x89, 0xf0, 0x7f, 0xee, 0xc8, 0xac, 0x8d, 0xf9, 0x2d, 0xbe, 0xe2, 0x21, 0xf2, 0xec, 0x87, 0x1e, 0x82, 0xa7, 0xbf, 0xfd, 0x10, 0x67, 0xfc, 0xf5, 0xaf, 0x3f, 0xfa, 0x03, 0x81, 0x80, 0x33, 0x5e, 0x8b, 0x2d, 0xa9, 0xf7, 0xc9, 0x9f, 0x32, 0x3f, 0x7c, 0x13, 0x85, 0xc3, 0x26, 0x59, 0x64, 0xa1, 0x43, 0x27, 0x65,\n\t0xb5, 0x30, 0x3a, 0x67, 0x69, 0x00, 0xa6, 0x81, 0x6f, 0x7a, 0xe7, 0x1d, 0x62, 0xa8, 0x61, 0x34, 0x99, 0x7a, 0x02, 0xbf, 0x05, 0x5f, 0xfd, 0x68, 0x48, 0x5e, 0x1b, 0x2e, 0xca, 0xda, 0xd4, 0xf0, 0x18, 0x24, 0xbc, 0x93, 0x59, 0x09, 0x05, 0x60, 0xc3, 0x71, 0x60, 0xb7, 0xcc, 0x64, 0xb5, 0x40, 0x99, 0x06, 0xa3, 0x92, 0x36, 0x18, 0x25, 0x2c, 0x2f, 0xe8, 0x3c, 0x59, 0x2c, 0x4f, 0x90, 0x96, 0xc3, 0xea, 0xf8, 0x2d, 0x85, 0xd5, 0x9b, 0xdf, 0x29, 0x5a, 0x88, 0xbf, 0xe7, 0xda, 0x4f, 0x18, 0xb9, 0xce, 0xbf, 0xcf, 0x3c, 0x03, 0x70, 0x3a, 0xd0, 0xb2, 0xc1, 0xd3, 0xbe, 0xa5, 0x6b, 0x9e, 0x17, 0x31, 0xcc, 0x6c, 0xc0, 0x4b, 0x3e, 0xc1, 0x2e, 0x19, 0xa5, 0x17, 0x25, 0x2b, 0x92, 0x69, 0x08, 0x0c, 0xaa, 0xb0, 0xa1, 0x57, 0xca, 0x47, 0x98, 0x05, 0x0b, 0x80, 0x99, 0x51, 0xd7, 0x80, 0x7a,\n\t0x6b, 0xf4, 0x05, 0x47, 0xb1, 0x5d, 0x11, 0xc0, 0xd4, 0x9a, 0xa7, 0xba, 0x83, 0x82, 0x59, 0x67, 0x4d, 0x30, 0xcf, 0xb4, 0xec, 0x7f, 0x72, 0xcf, 0xd4, 0x76, 0x03, 0xe3, 0x72, 0x59, 0x9b, 0xab, 0xa4, 0xc9, 0xae, 0xe0, 0xdb, 0xf8, 0x7f, 0xae, 0x7a, 0xed, 0x86, 0x5e, 0xdf, 0xd1, 0x3c, 0x97, 0x35, 0x32, 0x72, 0x74, 0x0d, 0xfb, 0x74, 0x86, 0x9f, 0xda, 0x00, 0xb6, 0x00, 0xe1, 0x27, 0x23, 0x88, 0x5a, 0x5a, 0xd1, 0x9f, 0x98, 0xad, 0x93, 0x3c, 0x26, 0xe8, 0xe7, 0x30, 0x5d, 0x79, 0x56, 0x6b, 0x3c, 0x1a, 0x2e, 0xa2, 0xe8, 0x01, 0x6d, 0x56, 0x8f, 0xdb, 0x70, 0x33, 0x06, 0x44, 0x89, 0x4e, 0x17, 0x55, 0x63, 0x51, 0x5c, 0xc1, 0x52, 0x4e, 0x4b, 0xe0, 0x1b, 0x7b, 0x22, 0x95, 0x36, 0xfc, 0x8f, 0xce, 0x8a, 0xe2, 0x17, 0x66, 0x7f, 0x03, 0xb6, 0x54, 0x7d, 0x9c, 0x89, 0xbf, 0x6c, 0xf7,\n\t0x3b, 0xac, 0x62, 0x2a, 0xaa, 0xb3, 0x7b, 0x8a, 0x5d, 0xab, 0xdf, 0x7e, 0x9b, 0xad, 0xb4, 0xb9, 0x18, 0x9b, 0xd7, 0x31, 0xfb, 0x80, 0xa7, 0x48, 0x6f, 0x6b, 0x9a, 0x5d, 0x2b, 0xe8, 0x2d, 0x7a, 0xa6, 0xca, 0x98, 0xa7, 0xe7, 0x67, 0xaf, 0xa0, 0x76, 0x10, 0xc0, 0xc5, 0xfe, 0x02, 0xbe, 0xf1, 0x54, 0x03, 0x11, 0x40, 0x88, 0xca, 0x46, 0x6b, 0xd3, 0xa2, 0x94, 0x47, 0xbc, 0xd5, 0xca, 0x01, 0x4f, 0x84, 0x1d, 0x84, 0xcb, 0xd8, 0x5f, 0x9c, 0xfb, 0xee, 0xdb, 0xcf, 0x81, 0xd5, 0xf7, 0x91, 0x8b, 0xce, 0xcb, 0x09, 0xf2, 0x84, 0x83, 0xfe, 0x56, 0x54, 0x22, 0x45, 0x2d, 0x06, 0xbd, 0x86, 0x63, 0x05, 0xc0, 0xed, 0xc0, 0x7c, 0x43, 0x59, 0x91, 0xd5, 0x95, 0x1e, 0x4a, 0xac, 0xab, 0x6d, 0xc7, 0x30, 0x60, 0xd8, 0x61, 0x17, 0x79, 0x2b, 0xc7, 0x9d, 0xfb, 0xee, 0x4b, 0x9e, 0xcf, 0xbe, 0x8d,\n\t0xaf, 0xf6, 0xa7, 0x1e, 0x7e, 0xee, 0x39, 0xa6, 0x78, 0xdd, 0xbd, 0x7e, 0xe3, 0x72, 0xe6, 0xdb, 0xb3, 0x9f, 0x79, 0xed, 0xce, 0x90, 0xfe, 0x85, 0x54, 0x0d, 0x3a, 0x7f, 0x5e, 0x81, 0xf5, 0x0d, 0x26, 0x82, 0x48, 0xb5, 0x71, 0x11, 0x3d, 0x4b, 0x8e, 0xda, 0xc9, 0x73, 0x10, 0x3e, 0x09, 0x30, 0x14, 0xa1, 0x72, 0xa9, 0xc4, 0x63, 0x24, 0x45, 0x3e, 0xe1, 0xf9, 0x2c, 0x02, 0x8f, 0x62, 0x86, 0xe7, 0xe6, 0x2c, 0xd9, 0x22, 0x54, 0x18, 0x70, 0x24, 0x15, 0xb9, 0x16, 0xb4, 0x02, 0xf7, 0x61, 0xa1, 0x14, 0x17, 0x47, 0xb1, 0xd3, 0x41, 0xd0, 0x0a, 0x16, 0x03, 0x98, 0x15, 0x2e, 0x8a, 0xf9, 0x84, 0xf0, 0xc9, 0xaf, 0xb1, 0x4c, 0xaa, 0xd8, 0x5d, 0x5b, 0x50, 0x9b, 0x9f, 0x72, 0x0b, 0xaf, 0x7c, 0xd6, 0x57, 0x68, 0xc2, 0x3f, 0x35, 0xe5, 0xeb, 0x1d, 0x3e, 0xfc, 0x2f, 0xc6, 0x42, 0x1f, 0x61,\n\t0x42, 0x36, 0xe5, 0xaa, 0xf5, 0x9e, 0xbb, 0xa7, 0xba, 0x9a, 0x9d, 0x69, 0xa8, 0x3e, 0xc7, 0xf0, 0x0f, 0xe8, 0xdd, 0xe7, 0x1e, 0xf1, 0x34, 0xf9, 0x9b, 0xeb, 0xd9, 0x31, 0xb7, 0x3e, 0x47, 0x96, 0x38, 0x90, 0x5f, 0xf2, 0x70, 0x2c, 0x43, 0x96, 0x06, 0x4e, 0x03, 0xe4, 0x40, 0x8e, 0x80, 0x2b, 0xc0, 0xeb, 0x5c, 0x04, 0x1e, 0x30, 0x65, 0x88, 0x55, 0xa3, 0x42, 0x52, 0x81, 0xeb, 0x40, 0x96, 0xec, 0x74, 0x07, 0xac, 0xe7, 0xde, 0x66, 0xd8, 0x57, 0x76, 0xfb, 0x7c, 0x56, 0xb6, 0x9c, 0x65, 0xc9, 0x73, 0xf3, 0xec, 0x9c, 0xdb, 0x5b, 0xeb, 0x3a, 0x07, 0x2b, 0xc1, 0xe8, 0xfa, 0xe8, 0xe7, 0xfe, 0xfa, 0x7c, 0xf6, 0xff, 0x50, 0x3d, 0xf6, 0x19, 0xfa, 0xac, 0x10, 0xda, 0x37, 0x78, 0xba, 0x18, 0xd8, 0x5d, 0x67, 0x07, 0x61, 0xac, 0x25, 0xb5, 0x4f, 0xc1, 0x04, 0x54, 0x7f, 0x30, 0x0c, 0x59,\n\t0x0d, 0xe4, 0x76, 0x3e, 0xc8, 0x34, 0xa2, 0xeb, 0x81, 0xf1, 0xa7, 0x32, 0x8b, 0x62, 0x86, 0x2c, 0x8a, 0x42, 0x75, 0x51, 0x64, 0x37, 0x51, 0xd7, 0xc6, 0x0c, 0x55, 0x62, 0xf0, 0x25, 0x84, 0x42, 0x81, 0xfc, 0x40, 0x38, 0x2c, 0x8b, 0x40, 0xd5, 0x1c, 0x53, 0x56, 0x49, 0xb2, 0x15, 0x5f, 0x38, 0x9d, 0xc8, 0xc8, 0xb5, 0xa3, 0xd5, 0x4b, 0xcb, 0x1d, 0xa2, 0xcb, 0x64, 0x8a, 0x85, 0x47, 0x56, 0x9e, 0xfb, 0xb7, 0xdc, 0xa9, 0x1d, 0x58, 0x7e, 0x72, 0x32, 0x99, 0x67, 0x5b, 0x95, 0x6f, 0x36, 0x4d, 0x6d, 0xa9, 0xe1, 0xec, 0x17, 0xcc, 0x92, 0xd8, 0x2f, 0xa3, 0xe7, 0x7f, 0xcf, 0xff, 0x1a, 0x74, 0x0e, 0xf1, 0x3c, 0xb2, 0x6c, 0xa7, 0x1c, 0xf5, 0x12, 0x8b, 0xc5, 0xb2, 0x6c, 0xa7, 0x2c, 0xc5, 0xa2, 0x9a, 0x50, 0x59, 0x6a, 0x85, 0xff, 0x35, 0x35, 0x47, 0x3e, 0x97, 0xfa, 0xcb, 0x2b, 0x5b,\n\t0xb7, 0xbe, 0x82, 0xc5, 0xcf, 0x65, 0xac, 0xa9, 0xbd, 0x2f, 0x1e, 0xef, 0xe9, 0x39, 0x4e, 0x3e, 0x65, 0x8b, 0xea, 0x0f, 0x67, 0x76, 0xee, 0x3c, 0x83, 0x8d, 0x9f, 0x7f, 0x08, 0x9b, 0xce, 0xec, 0xda, 0x75, 0x26, 0xf5, 0xc1, 0x43, 0xd7, 0xbd, 0x79, 0x6a, 0x68, 0xe8, 0xd4, 0x9b, 0xd7, 0x1d, 0xfb, 0xde, 0xa9, 0xc1, 0xc1, 0x53, 0xdf, 0x23, 0xbe, 0xd1, 0xe8, 0xf9, 0x7b, 0x00, 0xbe, 0x1f, 0x83, 0x86, 0x70, 0xa1, 0x66, 0xb4, 0x45, 0xb2, 0xd4, 0x82, 0x5d, 0xe5, 0xd2, 0x83, 0xa4, 0x8f, 0x07, 0x01, 0x85, 0x2c, 0x38, 0xba, 0x45, 0x80, 0xfe, 0x42, 0x10, 0x01, 0xec, 0x7e, 0x30, 0xb1, 0x36, 0x0f, 0x52, 0xc3, 0x0b, 0x16, 0xd3, 0x0e, 0x22, 0x89, 0xa9, 0xd3, 0xb1, 0x93, 0xa1, 0x54, 0xe0, 0x39, 0x7e, 0x9f, 0xdc, 0x6c, 0xbe, 0x16, 0x20, 0x52, 0xa3, 0xb1, 0x70, 0x65, 0x09, 0x15, 0xa9,\n\t0xe1, 0x02, 0x9c, 0x90, 0x3d, 0xa8, 0x4a, 0x40, 0xb6, 0x3c, 0x3f, 0xc0, 0xbb, 0x6a, 0x8e, 0x01, 0x65, 0x44, 0xe2, 0xfe, 0xd9, 0x22, 0x19, 0xfb, 0xb8, 0xbe, 0x8d, 0x6d, 0xc6, 0x4c, 0x20, 0x79, 0x6c, 0x80, 0xcc, 0xaf, 0xa5, 0x61, 0x63, 0xd3, 0xed, 0xcb, 0xc9, 0x8c, 0x7b, 0x3b, 0xd9, 0xd1, 0x2d, 0x33, 0x14, 0x29, 0xdb, 0x5f, 0x1e, 0x5e, 0xe7, 0xea, 0x28, 0x5c, 0xf9, 0xda, 0xcc, 0x35, 0x14, 0x35, 0xfb, 0xdf, 0x58, 0x3e, 0xa8, 0xcf, 0xb3, 0xe7, 0xe7, 0xed, 0xfe, 0x65, 0x61, 0x11, 0xcc, 0xf7, 0xd8, 0x55, 0xaf, 0xf5, 0x8c, 0x46, 0xe2, 0x04, 0x03, 0xd7, 0x7f, 0xaf, 0x97, 0x7d, 0x71, 0x32, 0xf5, 0xab, 0xc7, 0x29, 0x9a, 0xaa, 0xca, 0xaf, 0x2b, 0xf2, 0x62, 0x61, 0x12, 0x17, 0x3d, 0x4b, 0x91, 0xd5, 0x50, 0xbb, 0xc5, 0xec, 0x30, 0x08, 0x84, 0x7e, 0xe3, 0xe7, 0x3f, 0xd0, 0x94,\n\t0x52, 0xfa, 0x55, 0xe1, 0x82, 0xc1, 0xd3, 0x65, 0x84, 0x53, 0xa3, 0x58, 0xc4, 0x2e, 0x0c, 0x6e, 0x3d, 0xe1, 0x54, 0xf8, 0x21, 0xc8, 0x3f, 0x80, 0x53, 0x0b, 0xe0, 0x76, 0x10, 0x56, 0xbc, 0x06, 0x89, 0x9a, 0x8d, 0x02, 0x26, 0x78, 0x20, 0x7a, 0x67, 0xc7, 0xa0, 0x5e, 0xab, 0x63, 0x09, 0x2e, 0x58, 0x59, 0x7a, 0x7a, 0x65, 0xa6, 0x2e, 0xcf, 0x6d, 0x4a, 0x51, 0x46, 0xbe, 0xf2, 0xa3, 0x34, 0x44, 0x70, 0x61, 0x27, 0xf2, 0xf8, 0xc6, 0xcb, 0xea, 0x44, 0xac, 0xba, 0x29, 0xe5, 0x07, 0x3b, 0x06, 0xcc, 0xb6, 0x87, 0xa5, 0x8e, 0x8d, 0xd2, 0x37, 0x8b, 0x44, 0x82, 0x70, 0xe9, 0x9e, 0xa4, 0xb8, 0x45, 0xa1, 0xdd, 0x8e, 0x91, 0xbd, 0xca, 0x5e, 0x55, 0x59, 0x51, 0x5e, 0x56, 0x5a, 0x12, 0x8f, 0x85, 0x83, 0x24, 0x48, 0x01, 0xe6, 0xb5, 0x0d, 0xdb, 0x0c, 0xd9, 0xe6, 0xb5, 0xc2, 0xae, 0x60,\n\t0xd0, 0xd6, 0x65, 0x5c, 0x4d, 0xba, 0xd2, 0x5c, 0x75, 0xaa, 0xcd, 0xc8, 0xfc, 0xcf, 0xf4, 0x23, 0x07, 0xda, 0xda, 0x0e, 0x3c, 0x32, 0x3d, 0xfd, 0xd8, 0x81, 0xf6, 0xf6, 0x03, 0x8f, 0xf1, 0x0f, 0xe2, 0x73, 0x9f, 0x5b, 0xf9, 0x97, 0x07, 0xef, 0xfc, 0xcd, 0xe3, 0x13, 0x13, 0x8f, 0xff, 0xe6, 0xce, 0x07, 0xff, 0xb2, 0x92, 0xdd, 0x28, 0x5b, 0x8f, 0x8f, 0x2c, 0xbe, 0xe3, 0xfb, 0xc7, 0xae, 0xfb, 0xc1, 0x9d, 0x4b, 0x96, 0xdc, 0xf9, 0x83, 0xeb, 0x8e, 0x7d, 0xff, 0x8e, 0xc5, 0xda, 0xa7, 0x7f, 0x3a, 0x73, 0x14, 0xcc, 0x24, 0x85, 0xb7, 0xaf, 0xdd, 0xfb, 0x53, 0xc5, 0x3e, 0xa6, 0xbe, 0x0a, 0x77, 0x8c, 0xfa, 0xfa, 0x6e, 0x54, 0x23, 0x55, 0x92, 0x68, 0x11, 0xb8, 0xca, 0xec, 0x24, 0x4c, 0x98, 0x19, 0x13, 0x30, 0x35, 0x75, 0x39, 0x6e, 0x8a, 0x1b, 0x32, 0x80, 0x6f, 0x9f, 0xef, 0x72,\n\t0xda, 0xf5, 0x6e, 0x83, 0x5b, 0xf6, 0xeb, 0x65, 0xf7, 0x98, 0x72, 0x25, 0x48, 0x08, 0x9b, 0xe2, 0xcf, 0x53, 0xe9, 0xcb, 0x4c, 0x8d, 0x1c, 0x5e, 0x5e, 0xf2, 0xf0, 0x63, 0x3f, 0xf9, 0xc9, 0xc9, 0x37, 0x6f, 0xec, 0xe8, 0xb9, 0xf9, 0x7b, 0x27, 0x7e, 0xf2, 0x36, 0xf3, 0x72, 0xc9, 0xe2, 0x1d, 0x1d, 0xd7, 0xdf, 0x37, 0x7b, 0x96, 0xf9, 0x0f, 0xe9, 0x8a, 0xc7, 0x36, 0x6f, 0x7e, 0xfc, 0xea, 0x45, 0xb3, 0xbf, 0xa3, 0x21, 0xa3, 0x1c, 0x38, 0xbc, 0xa8, 0x5e, 0xaa, 0x15, 0xb1, 0x12, 0x6c, 0x10, 0xd2, 0x00, 0x11, 0x94, 0x67, 0x40, 0xf1, 0xb8, 0x29, 0x30, 0x5e, 0x83, 0x57, 0x06, 0x46, 0xb3, 0x30, 0x30, 0x89, 0x79, 0xc1, 0x79, 0x1b, 0xbf, 0x50, 0x32, 0xb4, 0xa3, 0xe3, 0xc4, 0x27, 0x66, 0xff, 0x01, 0xe0, 0xb9, 0x92, 0xc0, 0x73, 0xa8, 0x2b, 0xf5, 0x07, 0xfe, 0x81, 0xd4, 0x2c, 0x81,\n\t0x67, 0x6d, 0xea, 0x47, 0x42, 0x35, 0xe5, 0xe3, 0x4a, 0x74, 0xe0, 0x85, 0x4a, 0x37, 0x43, 0x34, 0xbb, 0xec, 0x58, 0x7b, 0xc0, 0x9d, 0x62, 0x72, 0x17, 0x2d, 0xa5, 0xfb, 0x4e, 0x96, 0xb0, 0x9c, 0x83, 0xb6, 0xb8, 0xf0, 0x26, 0x91, 0xb0, 0x5b, 0xc9, 0xc2, 0xbf, 0x48, 0xf7, 0xd1, 0xd1, 0x17, 0x63, 0xa1, 0x50, 0x2c, 0xc4, 0x13, 0x99, 0xab, 0x08, 0x30, 0x95, 0x43, 0xe4, 0xc0, 0x9c, 0x30, 0x47, 0xdc, 0xd1, 0x08, 0x0a, 0x4e, 0xa8, 0x62, 0x4c, 0x15, 0x6b, 0x5c, 0xea, 0x74, 0xb4, 0xc5, 0xf3, 0xc1, 0xee, 0x63, 0x73, 0xe4, 0x5e, 0x7c, 0x68, 0x0f, 0x88, 0x3a, 0x45, 0x9c, 0x1d, 0x53, 0xc4, 0xdb, 0x47, 0xa7, 0x40, 0xed, 0x69, 0x42, 0x73, 0x64, 0xdf, 0xd4, 0xf3, 0x0f, 0x5c, 0x57, 0x95, 0xa1, 0xcd, 0xcf, 0x29, 0x6d, 0x82, 0xc4, 0xb6, 0x0d, 0x50, 0x2b, 0x47, 0x50, 0xa2, 0x73, 0x84,\n\t0x53, 0xa8, 0x33, 0x99, 0x36, 0x75, 0x80, 0x4f, 0x88, 0x71, 0x6b, 0x35, 0xea, 0xe7, 0xe3, 0x13, 0x98, 0x07, 0x18, 0x3b, 0x58, 0x36, 0xab, 0xd5, 0x18, 0x90, 0xd3, 0xc5, 0xf4, 0x2d, 0xbb, 0x66, 0x45, 0xc9, 0xc3, 0x0f, 0xff, 0x23, 0xbb, 0xe1, 0x1b, 0x8d, 0x9e, 0xd4, 0x83, 0xd6, 0x58, 0xec, 0xd6, 0xb7, 0xf1, 0x67, 0x6f, 0xfd, 0xc7, 0xeb, 0xdb, 0x2b, 0x46, 0xaf, 0x1b, 0x89, 0xf9, 0x99, 0x5f, 0xc6, 0xfa, 0x37, 0xb7, 0x1e, 0x39, 0x3a, 0xfb, 0x87, 0xd9, 0xfc, 0x72, 0xfc, 0x81, 0xdb, 0x31, 0x0b, 0xc6, 0x4a, 0xe3, 0xb6, 0x7b, 0xc7, 0x07, 0x4f, 0x6c, 0x1b, 0xb2, 0xe7, 0x97, 0x02, 0xbb, 0xb4, 0x9e, 0x7f, 0x9f, 0xfd, 0x15, 0xd0, 0xac, 0x1d, 0xb5, 0x49, 0xcd, 0xed, 0x00, 0x56, 0x11, 0x06, 0xad, 0x4c, 0xde, 0xb2, 0x04, 0x16, 0x03, 0x0b, 0x36, 0x20, 0x07, 0x5a, 0x72, 0xb7, 0x0a,\n\t0xef, 0x8e, 0x41, 0x35, 0x08, 0x04, 0xd2, 0xb6, 0xb5, 0xb9, 0x04, 0xd6, 0xa7, 0xcf, 0x13, 0x04, 0x71, 0xeb, 0x94, 0x2d, 0xd8, 0xf4, 0xc2, 0x14, 0xd4, 0x08, 0xaf, 0xac, 0xfe, 0xd2, 0x64, 0x11, 0xea, 0x68, 0x04, 0xd8, 0xe9, 0x62, 0x3f, 0xa5, 0x73, 0x5a, 0xf3, 0x2a, 0xba, 0x37, 0x2c, 0x6a, 0x5f, 0x2f, 0x05, 0x9a, 0x37, 0x5c, 0x7d, 0xdd, 0xd5, 0x1b, 0x9a, 0x3b, 0x8e, 0x3c, 0xbf, 0xbf, 0xfb, 0xf8, 0x81, 0xcd, 0xb1, 0x56, 0xad, 0xdb, 0xe2, 0xa8, 0x1f, 0xd9, 0x3b, 0xd2, 0xb9, 0xb5, 0x37, 0xd2, 0x44, 0x6f, 0x36, 0xb5, 0xec, 0xff, 0xd2, 0xce, 0x43, 0xdf, 0x1b, 0xe4, 0x9e, 0xb5, 0x5a, 0x02, 0xf1, 0x40, 0xa0, 0x71, 0x71, 0x79, 0xd3, 0x50, 0x32, 0x56, 0xda, 0xb0, 0xf2, 0xf0, 0xe8, 0xfa, 0xc7, 0x8e, 0xf4, 0x7a, 0xab, 0xbb, 0x4b, 0xa7, 0x0d, 0x96, 0xb2, 0xba, 0xb2, 0x60, 0xc7,\n\t0x78, 0x43, 0xfb, 0xd2, 0x64, 0x24, 0x9e, 0x5c, 0x7d, 0xfd, 0x86, 0xc5, 0x77, 0xee, 0x59, 0xb4, 0xb8, 0x4f, 0xb6, 0x3b, 0x5b, 0x53, 0xf7, 0xd3, 0xb9, 0xae, 0x41, 0x2f, 0xca, 0xb6, 0xbb, 0x6d, 0x0d, 0xc6, 0x9a, 0x46, 0x10, 0xae, 0x75, 0x3e, 0x86, 0xe5, 0xa3, 0x98, 0x61, 0x39, 0x10, 0xb7, 0x17, 0x5c, 0xe5, 0x38, 0x22, 0x77, 0x49, 0x87, 0x4a, 0x18, 0x06, 0x88, 0x28, 0xcc, 0x20, 0x41, 0xc4, 0x82, 0x48, 0xf0, 0xa2, 0x19, 0x03, 0x5f, 0x76, 0xc7, 0xa0, 0x1a, 0xb6, 0xd9, 0x03, 0x14, 0x05, 0x87, 0x97, 0xa0, 0x68, 0x86, 0x70, 0x6e, 0x72, 0x6e, 0x0f, 0x70, 0x00, 0xc1, 0x5d, 0x9f, 0x99, 0xaf, 0xa7, 0x8a, 0xdb, 0x19, 0xa2, 0xc9, 0x6c, 0xab, 0x56, 0x2c, 0xea, 0x68, 0x6b, 0xa9, 0x4f, 0x56, 0x55, 0x94, 0xc4, 0xc3, 0xc1, 0x60, 0xb1, 0x76, 0x7e, 0x24, 0x5f, 0x24, 0xf2, 0x83, 0x3f,\n\t0x16, 0xf2, 0xeb, 0xa6, 0xee, 0x5d, 0x67, 0x9d, 0x37, 0x04, 0x14, 0x3b, 0xf1, 0xe3, 0x25, 0x1f, 0x93, 0x22, 0x2b, 0x3f, 0x75, 0x70, 0xa9, 0xb1, 0x6d, 0x9e, 0x70, 0xd0, 0x61, 0x7e, 0x6a, 0xd9, 0xc2, 0x64, 0xc2, 0xa8, 0x80, 0x24, 0xa7, 0xd2, 0x38, 0x38, 0x78, 0x22, 0xc4, 0x52, 0x55, 0x7d, 0x71, 0x1a, 0xd8, 0x25, 0x6e, 0x1f, 0xb5, 0x62, 0xa8, 0x0b, 0x5e, 0x17, 0xe0, 0x4e, 0xa4, 0x1a, 0xde, 0x4a, 0x25, 0xb9, 0x69, 0xee, 0x57, 0x1f, 0x39, 0xb9, 0x5f, 0x3d, 0x2b, 0xd3, 0x99, 0xec, 0x6b, 0xdc, 0x0d, 0x63, 0x98, 0x49, 0x7c, 0x84, 0x03, 0x36, 0xc6, 0xd4, 0xb3, 0xd7, 0x88, 0x0c, 0xcf, 0xab, 0xdb, 0x17, 0xaa, 0x6b, 0x6f, 0x46, 0x66, 0xc5, 0x9f, 0xd4, 0xea, 0xbc, 0x19, 0xef, 0xbe, 0x2e, 0x40, 0xfe, 0x1c, 0xcc, 0x77, 0x71, 0x67, 0xea, 0x1b, 0x6f, 0xa5, 0x5e, 0xc5, 0x5d, 0xf2,\n\t0x53, 0x52, 0xdb, 0x8f, 0xcc, 0xc6, 0x98, 0x7f, 0x3d, 0x82, 0xef, 0x7b, 0xf6, 0x59, 0xfa, 0xac, 0xcf, 0x9d, 0xff, 0x1d, 0x1f, 0x84, 0x67, 0xb9, 0x51, 0x48, 0x0a, 0xb0, 0x8a, 0xf7, 0x92, 0xb1, 0x48, 0x40, 0x9b, 0xd9, 0x4c, 0x06, 0x51, 0x40, 0x6e, 0xec, 0xe6, 0x55, 0xfd, 0x05, 0xd2, 0x55, 0x59, 0x1d, 0xf4, 0x6b, 0x01, 0xc3, 0xbc, 0xb7, 0xea, 0xe6, 0x75, 0x35, 0x6f, 0x2d, 0xbd, 0xef, 0x9d, 0x1b, 0x6f, 0x7c, 0xe7, 0xbe, 0xa5, 0x6f, 0x57, 0xaf, 0xbb, 0xf9, 0xc9, 0xa6, 0x6d, 0x77, 0xad, 0x21, 0x9b, 0x1b, 0x47, 0xdf, 0x79, 0x60, 0xcd, 0x9a, 0x07, 0xde, 0x39, 0x0a, 0xdf, 0x1f, 0x58, 0x73, 0xf7, 0xb6, 0x26, 0xf2, 0xcc, 0xd4, 0x63, 0xf4, 0x99, 0x35, 0x68, 0xf3, 0xf3, 0x4e, 0x32, 0x35, 0x65, 0xa7, 0xc0, 0x0f, 0xee, 0x33, 0x35, 0x4e, 0x79, 0x5e, 0x56, 0xaa, 0xd4, 0xb2, 0xa6,\n\t0xa0, 0x50, 0x29, 0x1a, 0x52, 0x1d, 0x81, 0x0b, 0xda, 0xa1, 0x4c, 0xb3, 0x51, 0xc9, 0x4c, 0x5f, 0xeb, 0x56, 0x13, 0x76, 0x38, 0x42, 0xc1, 0x72, 0x0d, 0xf1, 0xbe, 0x08, 0xb8, 0x62, 0x96, 0x4f, 0x5a, 0x98, 0x71, 0x57, 0x2b, 0x58, 0x65, 0x0e, 0xb2, 0x1b, 0xc8, 0x07, 0x3b, 0x8f, 0x3c, 0xb7, 0xd7, 0x16, 0xf6, 0xe7, 0xa5, 0xdd, 0xd4, 0x02, 0xea, 0xbe, 0x76, 0x26, 0xaf, 0xfd, 0xee, 0xed, 0x83, 0x64, 0x66, 0xab, 0xc8, 0x5c, 0xf9, 0x07, 0xce, 0xdd, 0xbf, 0xef, 0x8d, 0x4f, 0x4d, 0x9a, 0xf5, 0x05, 0xa1, 0x12, 0x97, 0xec, 0xb7, 0xf6, 0x13, 0x77, 0xb6, 0x76, 0x7d, 0x44, 0x18, 0xbf, 0xff, 0x87, 0x57, 0xab, 0xd3, 0x95, 0xd1, 0x20, 0xd3, 0x55, 0xdd, 0xab, 0xc9, 0x43, 0x01, 0xa9, 0x40, 0x4f, 0xfd, 0x59, 0x70, 0x20, 0x32, 0xfe, 0x3a, 0x79, 0xcf, 0x17, 0x02, 0xff, 0x9f, 0xb8, 0x55,\n\t0x5a, 0x1c, 0xc4, 0xaa, 0x03, 0xd3, 0x86, 0xa9, 0x07, 0xc3, 0x8f, 0xcc, 0xbe, 0xf4, 0xcd, 0xd9, 0x97, 0x9e, 0xf0, 0x05, 0xb5, 0xf8, 0x84, 0xc9, 0xab, 0xd7, 0xe5, 0x9b, 0xf0, 0xf5, 0x62, 0xd8, 0x4b, 0x3c, 0x08, 0xfe, 0x01, 0x9f, 0xf3, 0x5c, 0x55, 0x68, 0x55, 0x65, 0xe5, 0xaa, 0x10, 0xfb, 0x43, 0x7b, 0x01, 0x7d, 0x9e, 0x17, 0x21, 0x0d, 0xf1, 0xe7, 0x22, 0xc4, 0x4f, 0x2d, 0xca, 0xe3, 0x59, 0xe2, 0x39, 0xf3, 0x1c, 0x2c, 0xef, 0x1c, 0xa7, 0x25, 0x82, 0xc2, 0x2d, 0x01, 0x27, 0xf5, 0xa2, 0xc8, 0x53, 0x23, 0x51, 0x58, 0xe9, 0x73, 0x1f, 0xde, 0x8c, 0xc9, 0x4f, 0xa7, 0xe2, 0x4b, 0x69, 0xb8, 0x94, 0xf4, 0x5a, 0xea, 0x0b, 0x06, 0xad, 0x5e, 0x97, 0xfa, 0xec, 0x37, 0x53, 0xd2, 0xb3, 0xbe, 0x88, 0x80, 0xbd, 0x1a, 0xa3, 0x28, 0x9a, 0x75, 0xb8, 0x4b, 0x88, 0x7a, 0x5b, 0x7d, 0x21,\n\t0x0d, 0x5e, 0x94, 0x67, 0x32, 0x98, 0xb0, 0x8f, 0x8f, 0x51, 0x08, 0xb9, 0x78, 0x51, 0x79, 0x45, 0xe1, 0x47, 0xff, 0xc2, 0x3f, 0xe0, 0x75, 0x9d, 0x6b, 0xf7, 0x75, 0x86, 0x42, 0x9d, 0x3e, 0xf6, 0x5b, 0xf6, 0x02, 0x80, 0xbb, 0xbd, 0xbe, 0xa7, 0xbb, 0x81, 0x7c, 0x07, 0x98, 0x81, 0x78, 0xbc, 0x1e, 0x60, 0xf6, 0xa2, 0x22, 0xc9, 0xef, 0xb5, 0x19, 0x79, 0x8e, 0x00, 0xcd, 0xe2, 0x2c, 0x90, 0x63, 0xc5, 0xb1, 0x22, 0xb2, 0x88, 0x02, 0xd4, 0xc3, 0x02, 0x60, 0x89, 0x19, 0xac, 0x95, 0x01, 0x56, 0xbd, 0x6c, 0x5e, 0xff, 0x7f, 0x5d, 0x3e, 0x4d, 0xea, 0x76, 0x8d, 0x3e, 0xf5, 0x49, 0x9d, 0xc7, 0xfe, 0x6d, 0xfc, 0xeb, 0x54, 0xc9, 0xff, 0x75, 0x39, 0x35, 0x78, 0x87, 0xc6, 0x84, 0x57, 0x68, 0x9d, 0xd6, 0xef, 0xa5, 0xa2, 0x6e, 0x13, 0x33, 0xec, 0xce, 0x9b, 0xfd, 0x91, 0xc9, 0xcd, 0xfc,\n\t0x07, 0xf3, 0xb2, 0xc9, 0x34, 0xfb, 0x7d, 0x8f, 0x13, 0x9f, 0xb7, 0x58, 0x66, 0x97, 0x22, 0x7c, 0x3e, 0x05, 0x6b, 0xf0, 0xbf, 0x01, 0x0e, 0x3b, 0xf1, 0xf3, 0x0c, 0x2c, 0x79, 0xfb, 0x1a, 0x1e, 0x60, 0x70, 0x86, 0x58, 0x65, 0xc5, 0x56, 0x56, 0xf6, 0xf3, 0xac, 0x17, 0xe0, 0x8a, 0xf9, 0xe9, 0x5b, 0xb3, 0x1f, 0xbc, 0xe2, 0x2b, 0xd6, 0xe3, 0x06, 0x5b, 0xa1, 0x41, 0xef, 0xb7, 0xe1, 0x7a, 0x5d, 0xd0, 0xfb, 0x2a, 0xd3, 0x30, 0xfb, 0x1d, 0xa6, 0x81, 0x9d, 0xf2, 0x3a, 0x67, 0x7f, 0x11, 0xee, 0x2c, 0x2a, 0xea, 0x0c, 0x33, 0xee, 0xbc, 0x42, 0x99, 0x37, 0xc8, 0xc1, 0x9d, 0xab, 0xe0, 0x79, 0x26, 0x14, 0x96, 0x8a, 0x45, 0x98, 0x29, 0xd9, 0x7b, 0x61, 0x54, 0xe1, 0x01, 0x2d, 0x46, 0x15, 0x09, 0xe2, 0xb0, 0xda, 0x64, 0x3f, 0x48, 0x24, 0xb1, 0x23, 0xc2, 0xc2, 0x98, 0x08, 0x92, 0xab,\n\t0x9c, 0xe7, 0x7e, 0xc1, 0x06, 0x3e, 0xfa, 0x8e, 0x5e, 0xcb, 0x7a, 0xcf, 0xfd, 0x85, 0x2b, 0xe0, 0x17, 0x87, 0x02, 0x1f, 0x3d, 0xfa, 0xf4, 0x0a, 0x6b, 0x81, 0x89, 0x5b, 0xf7, 0xb4, 0xac, 0xd3, 0x89, 0xae, 0xdc, 0xce, 0xe9, 0x01, 0xc7, 0x8d, 0x68, 0xef, 0x0b, 0x05, 0x66, 0x06, 0xd3, 0xa5, 0x47, 0x0c, 0xf2, 0x08, 0x12, 0x05, 0x5e, 0x10, 0xf9, 0x19, 0xf2, 0xd2, 0x3a, 0xcc, 0xa3, 0x49, 0x90, 0x32, 0x74, 0x45, 0xed, 0x26, 0x92, 0x8b, 0x1d, 0xe3, 0xe4, 0x08, 0x96, 0x57, 0x2a, 0xb9, 0x48, 0x43, 0xea, 0x53, 0x2a, 0x36, 0xce, 0x4e, 0x0e, 0x56, 0xa2, 0x3e, 0x18, 0xcc, 0x8f, 0x86, 0xa3, 0x31, 0x8b, 0x46, 0xe7, 0x03, 0xd9, 0xcf, 0xa6, 0xe3, 0x7e, 0x58, 0x96, 0xeb, 0x0e, 0xe2, 0x24, 0x57, 0xc2, 0x0d, 0x2a, 0x4b, 0x40, 0xb8, 0xd7, 0xa7, 0xb7, 0x5a, 0x23, 0x51, 0xe6, 0xc9, 0x83,\n\t0x8f, 0x6d, 0xad, 0x70, 0x97, 0x36, 0x15, 0x97, 0x0f, 0x76, 0xb6, 0xf8, 0x67, 0xcf, 0xae, 0xfc, 0xf6, 0xc1, 0xd5, 0x37, 0x8e, 0x57, 0xae, 0xf6, 0x17, 0x68, 0x1d, 0xd1, 0xa1, 0xe5, 0xeb, 0x1a, 0x5b, 0xb6, 0x2d, 0x29, 0xef, 0xb8, 0xe7, 0xb7, 0x4f, 0x6f, 0x5a, 0x2f, 0xad, 0x6e, 0xaf, 0x74, 0xdb, 0xfd, 0x5a, 0x7c, 0x86, 0xf3, 0x57, 0x75, 0xc4, 0x22, 0xf5, 0x41, 0x4b, 0x5e, 0xa0, 0xaa, 0x90, 0xd9, 0x33, 0xb2, 0xb4, 0x71, 0xfa, 0xd4, 0xaa, 0xd9, 0xab, 0x6c, 0x9e, 0xd1, 0x50, 0x7d, 0xd4, 0x1e, 0xe8, 0x9a, 0xee, 0x6a, 0xd9, 0xb3, 0xa6, 0x81, 0x1b, 0xd8, 0xbf, 0xaf, 0x28, 0x5a, 0xe4, 0x34, 0xcb, 0x78, 0x49, 0x3d, 0xc1, 0xbe, 0x43, 0xf1, 0xb2, 0x14, 0x7d, 0x42, 0xb2, 0x34, 0x60, 0x81, 0xf7, 0x11, 0xe4, 0x74, 0x80, 0x05, 0x88, 0xd9, 0x81, 0xf4, 0x16, 0x09, 0x68, 0x3e, 0x81,\n\t0x23, 0x71, 0x61, 0x52, 0xae, 0x8d, 0x18, 0xa7, 0xe2, 0x18, 0x28, 0x3f, 0x05, 0x43, 0xd4, 0xde, 0x23, 0xa1, 0xe4, 0x8c, 0xbc, 0xaa, 0x4f, 0x77, 0xd1, 0xb2, 0x1a, 0x56, 0x0e, 0x29, 0x2f, 0xd8, 0x15, 0x65, 0x7a, 0x82, 0x33, 0x3e, 0xbc, 0xb8, 0x0c, 0x74, 0x66, 0x7e, 0x19, 0xe0, 0x4e, 0x8e, 0x28, 0x67, 0xe1, 0x2e, 0x2d, 0xbb, 0x16, 0x42, 0x5d, 0x65, 0x1a, 0xbd, 0xd9, 0x71, 0xb8, 0x39, 0xf8, 0xc4, 0xa5, 0x54, 0xae, 0x0d, 0x77, 0x78, 0xf5, 0x0b, 0x61, 0x33, 0xa8, 0x60, 0x3c, 0x27, 0x6a, 0x37, 0x07, 0xc5, 0xb3, 0xff, 0x4e, 0x83, 0x78, 0x5b, 0xa3, 0x9a, 0xe2, 0xf9, 0x31, 0xdc, 0xae, 0x92, 0x20, 0x3b, 0xc2, 0xc7, 0x22, 0xe9, 0xfc, 0xfb, 0x02, 0xe2, 0x48, 0xdd, 0xf6, 0x7c, 0x34, 0x8e, 0xc5, 0xc1, 0xd3, 0x1e, 0xc0, 0xb1, 0x61, 0x64, 0x90, 0xd1, 0x31, 0x95, 0x51, 0x06, 0xf3,\n\t0xc4, 0x6f, 0x4c, 0xff, 0xe4, 0x78, 0x46, 0xdd, 0xe1, 0xaa, 0x43, 0x3a, 0x30, 0xa5, 0x75, 0x2c, 0xe1, 0x3f, 0xb2, 0xc9, 0x3c, 0xa3, 0x31, 0x31, 0xac, 0xd9, 0xc8, 0x20, 0x90, 0x6e, 0x93, 0x5a, 0x10, 0x13, 0xfa, 0x31, 0x03, 0xd6, 0xeb, 0x77, 0x83, 0x16, 0xc3, 0x58, 0x18, 0x03, 0x9b, 0x45, 0xd8, 0x29, 0x10, 0x1b, 0xdd, 0xf3, 0xb7, 0x75, 0xde, 0x03, 0x9d, 0xa5, 0xf6, 0xac, 0x7e, 0x1c, 0xf8, 0xf0, 0x0b, 0xf6, 0x03, 0xc6, 0x57, 0xba, 0x11, 0xca, 0xa6, 0x47, 0x00, 0xcf, 0x30, 0xe4, 0x76, 0x9b, 0x4c, 0xee, 0x71, 0xf7, 0xd8, 0xca, 0xe5, 0xc3, 0x8b, 0xfb, 0x7a, 0xc0, 0x34, 0x6a, 0xad, 0x4b, 0x94, 0x97, 0x86, 0x8a, 0x0b, 0xfd, 0xa6, 0x7c, 0x53, 0x7e, 0x3c, 0x62, 0xb1, 0x10, 0x69, 0x92, 0x26, 0x58, 0x5d, 0x58, 0xf1, 0x01, 0xc0, 0x3e, 0x62, 0x65, 0x0a, 0x3a, 0x0b, 0x29, 0xb9,\n\t0x23, 0xd1, 0x8b, 0x10, 0xdd, 0xe9, 0x52, 0x48, 0x6f, 0x17, 0x82, 0xcc, 0xd3, 0x07, 0x1f, 0xdb, 0x52, 0xb1, 0x7e, 0x49, 0xfd, 0xfa, 0x9e, 0x38, 0xf3, 0x68, 0x41, 0xd3, 0xca, 0x64, 0xf3, 0x58, 0x67, 0x1c, 0x8c, 0x88, 0xf2, 0xc1, 0xe9, 0xb6, 0xee, 0xb5, 0x2d, 0x11, 0xab, 0xd9, 0x26, 0xd4, 0x06, 0x47, 0x37, 0xef, 0xa8, 0xdd, 0xff, 0x8d, 0x46, 0xdf, 0xea, 0xed, 0x07, 0x5b, 0x7a, 0xf7, 0x2f, 0x2f, 0x97, 0xe6, 0xf0, 0xc0, 0x4b, 0xfb, 0x0e, 0xde, 0x1d, 0x4c, 0x3e, 0x73, 0x70, 0xf9, 0x9d, 0xdb, 0x5b, 0xf2, 0xbc, 0xf8, 0xff, 0xe3, 0x03, 0x75, 0xdd, 0xb1, 0xe5, 0x83, 0xc5, 0xbd, 0x3b, 0xfa, 0xcf, 0xb4, 0x6e, 0x5b, 0x52, 0x16, 0x1b, 0xd8, 0xb1, 0xe8, 0xd0, 0xaa, 0xeb, 0x56, 0x94, 0xf8, 0x8a, 0x7d, 0x3a, 0xcd, 0xa2, 0x92, 0xd6, 0x48, 0xde, 0xae, 0xbd, 0x2d, 0x2b, 0x93, 0xee,\n\t0x50, 0xef, 0x8e, 0xde, 0x96, 0xfd, 0x13, 0xad, 0x5c, 0xc5, 0xfe, 0xab, 0x8a, 0xe3, 0xc5, 0xc0, 0x0a, 0x4b, 0x47, 0x26, 0x57, 0xaf, 0xdc, 0xd4, 0x71, 0xf8, 0xf4, 0x4c, 0x79, 0x21, 0xac, 0xbb, 0x5b, 0xce, 0x7f, 0xc0, 0xd9, 0xf8, 0xb3, 0xc8, 0x80, 0xc2, 0xe8, 0x53, 0xb2, 0xb7, 0x6f, 0x30, 0x1a, 0x88, 0xa8, 0x2d, 0x24, 0xfb, 0x57, 0x84, 0x03, 0xd4, 0x9f, 0xa0, 0x05, 0x54, 0x0e, 0xf0, 0xaa, 0x11, 0x16, 0x55, 0xec, 0x10, 0x5f, 0x8a, 0xc8, 0x27, 0xd9, 0x17, 0x2b, 0xbe, 0x58, 0x13, 0xea, 0xe0, 0x17, 0xce, 0xbd, 0x0b, 0x0e, 0x66, 0xda, 0x23, 0xa3, 0x8e, 0xbc, 0xa4, 0xb5, 0x46, 0x62, 0xe1, 0x50, 0x26, 0x0c, 0x43, 0x77, 0xaf, 0x8b, 0x05, 0xb1, 0x4e, 0xc5, 0xae, 0xe2, 0x1c, 0x88, 0x02, 0x28, 0x80, 0x04, 0x1e, 0xaa, 0x9a, 0xe9, 0xbc, 0xf9, 0x9e, 0xe3, 0x07, 0x57, 0x1c, 0xae,\n\t0x6b, 0x7f, 0x68, 0x7a, 0xf4, 0x8e, 0xa9, 0x64, 0xeb, 0xde, 0x2f, 0x6c, 0xae, 0x5e, 0xd6, 0xdd, 0xe4, 0xd1, 0x6a, 0x4a, 0x8e, 0x9e, 0xf9, 0x6b, 0x7b, 0xcd, 0xeb, 0x67, 0x9f, 0x7f, 0x7c, 0xa8, 0xe7, 0xae, 0x9e, 0x55, 0xdd, 0xc7, 0x5e, 0x3a, 0x70, 0xf8, 0xbb, 0x77, 0x0e, 0xdb, 0x42, 0xb5, 0x81, 0x95, 0x71, 0x98, 0x3d, 0x46, 0xc3, 0xe7, 0x3f, 0x60, 0xef, 0xe4, 0x34, 0x60, 0xf7, 0xed, 0x90, 0x74, 0x65, 0xa0, 0xbc, 0x3c, 0x60, 0xc9, 0x33, 0x8a, 0xe7, 0x19, 0xca, 0xb8, 0x32, 0x0c, 0x66, 0x99, 0xb4, 0x2b, 0xb3, 0x9b, 0xd8, 0x80, 0xaa, 0xa8, 0xf5, 0x5e, 0x46, 0xb3, 0x3d, 0x44, 0x22, 0x6b, 0x63, 0x91, 0x60, 0x2c, 0x98, 0x09, 0xd9, 0xe7, 0x06, 0xce, 0xa8, 0x65, 0x94, 0x66, 0x2e, 0x6a, 0x69, 0x8f, 0x68, 0xad, 0x16, 0x4b, 0xb0, 0x6e, 0xb0, 0xbe, 0x6f, 0x77, 0x7f, 0x24, 0x36,\n\t0xb0, 0xbd, 0xa3, 0x7d, 0x59, 0x32, 0x64, 0xcb, 0x37, 0x36, 0x04, 0x57, 0x6f, 0xda, 0x51, 0xbf, 0xfe, 0xd1, 0x43, 0x3d, 0xed, 0x87, 0xbf, 0x7a, 0x60, 0xd7, 0x63, 0x1d, 0x6c, 0x93, 0xde, 0xe8, 0xf6, 0xbb, 0x6b, 0x37, 0x9c, 0x5c, 0x35, 0x7a, 0xeb, 0xfa, 0xea, 0xc2, 0x50, 0x61, 0x5e, 0x5f, 0x69, 0x4b, 0x24, 0xaf, 0xe7, 0xc6, 0x33, 0x47, 0xf6, 0xbe, 0x76, 0xeb, 0x70, 0x8f, 0x44, 0xf5, 0xdc, 0x30, 0xf8, 0x30, 0x64, 0xae, 0xdd, 0xe8, 0x0b, 0xb2, 0x5c, 0xb5, 0x94, 0x62, 0x9e, 0x2d, 0xf0, 0x73, 0x2c, 0x16, 0xcc, 0xa0, 0x8f, 0xc8, 0xe6, 0x76, 0xee, 0x25, 0x86, 0x55, 0xbd, 0x97, 0x32, 0xc4, 0xf1, 0x22, 0xcf, 0x89, 0x33, 0x44, 0x07, 0x89, 0xc2, 0x6e, 0x24, 0x60, 0x5e, 0xc0, 0xbb, 0x55, 0x33, 0x70, 0xb7, 0x1c, 0xf3, 0x1c, 0x57, 0x63, 0x9e, 0x35, 0x0b, 0x34, 0xc7, 0x0c, 0x8f,\n\t0x99, 0xac, 0x5e, 0x24, 0x0c, 0x3a, 0xae, 0x86, 0x41, 0xf5, 0x80, 0x9e, 0x70, 0x65, 0xc8, 0x5e, 0x4a, 0x54, 0xd6, 0xc5, 0x37, 0xa6, 0x59, 0x15, 0x49, 0xe2, 0x7c, 0x98, 0x74, 0xb1, 0x77, 0xb6, 0x7c, 0x71, 0xc2, 0x3a, 0xb1, 0x34, 0xd0, 0x94, 0x76, 0x48, 0xcc, 0x4e, 0xbf, 0x3d, 0x16, 0x1b, 0x19, 0x2a, 0x59, 0x75, 0xf7, 0x8e, 0x56, 0x05, 0x6f, 0xb5, 0x0b, 0x20, 0xf8, 0xae, 0x81, 0x01, 0x4d, 0xcb, 0x3c, 0x0e, 0xc8, 0xb5, 0xda, 0x25, 0x37, 0xbc, 0x74, 0x40, 0xc6, 0x68, 0xdf, 0x05, 0x28, 0x97, 0x71, 0x7c, 0xfe, 0x03, 0xf1, 0x4b, 0x82, 0x0f, 0xad, 0x43, 0x8f, 0x49, 0x24, 0x20, 0xc5, 0x8d, 0x84, 0x88, 0xdb, 0x6e, 0xc5, 0x1a, 0xbe, 0x1d, 0x8b, 0x1a, 0x6e, 0x40, 0x5e, 0x25, 0x75, 0x88, 0x67, 0x34, 0x0c, 0x0f, 0x6a, 0x49, 0x43, 0x72, 0x6f, 0x76, 0x23, 0x3d, 0x08, 0x37, 0x3d,\n\t0x37, 0x89, 0x0c, 0x86, 0xcd, 0x83, 0x24, 0x0c, 0x84, 0xc6, 0x74, 0x60, 0x71, 0xed, 0xa6, 0xf9, 0x37, 0xa3, 0x5a, 0xe0, 0x2b, 0x62, 0x80, 0x78, 0xa5, 0xc6, 0xcb, 0xed, 0xa7, 0x6c, 0x19, 0x89, 0xa2, 0x76, 0x0c, 0x69, 0xb5, 0x7b, 0xb4, 0x80, 0x5e, 0xfb, 0xba, 0x89, 0xb5, 0x6b, 0x86, 0x17, 0x77, 0x2f, 0x02, 0x34, 0x97, 0x87, 0x6d, 0x41, 0x47, 0xb1, 0x91, 0xa8, 0xb7, 0xb4, 0x39, 0x60, 0x95, 0xd7, 0x19, 0x7c, 0x51, 0x77, 0x0a, 0x9d, 0x2e, 0x30, 0xac, 0xc4, 0xcb, 0xe1, 0xd5, 0x0a, 0x5c, 0xa7, 0xa4, 0x67, 0x25, 0x78, 0x9b, 0x74, 0xff, 0xe6, 0x15, 0xd7, 0xae, 0x2a, 0x3b, 0x3b, 0xb5, 0x65, 0xf0, 0xfa, 0x86, 0x33, 0xba, 0x48, 0x4d, 0x4b, 0x51, 0xf3, 0x9a, 0xe6, 0x82, 0x96, 0x64, 0x41, 0xd2, 0x5d, 0x7b, 0x59, 0x3c, 0x6d, 0x8f, 0xda, 0xbc, 0xfe, 0xc4, 0x86, 0xdb, 0xd7, 0x76,\n\t0x6d, 0x19, 0x6e, 0xf5, 0xb2, 0x07, 0x3b, 0x96, 0x36, 0x6c, 0x06, 0x3d, 0x76, 0x88, 0xb9, 0x69, 0xd7, 0xa1, 0xde, 0xd6, 0x59, 0x17, 0x3f, 0x69, 0x2f, 0x74, 0xe8, 0x43, 0x6d, 0xcb, 0x2a, 0xba, 0x4f, 0x34, 0x58, 0xe2, 0xf9, 0x7d, 0x17, 0xe7, 0x7f, 0x96, 0xa9, 0xda, 0x9a, 0xec, 0x39, 0x34, 0x9a, 0xf0, 0x05, 0xbc, 0x0a, 0x8d, 0xce, 0x02, 0x8d, 0xb6, 0xe0, 0xed, 0xb2, 0x05, 0x66, 0x5b, 0x8d, 0x79, 0xe3, 0x96, 0x32, 0x50, 0x7d, 0xbd, 0x58, 0xaf, 0xf1, 0x28, 0xbe, 0xbc, 0x93, 0x5c, 0x2d, 0xc3, 0x5a, 0x7e, 0x0b, 0xc6, 0x5a, 0xf5, 0x06, 0xaf, 0x8a, 0xc2, 0x56, 0xa0, 0xb6, 0x06, 0x23, 0x0d, 0x29, 0x16, 0xc3, 0xe8, 0x59, 0x06, 0x9c, 0x74, 0x64, 0xe4, 0x05, 0xe3, 0x24, 0xd2, 0x20, 0x3d, 0xab, 0xd1, 0x4f, 0x02, 0xee, 0xa9, 0xa4, 0xe3, 0xc7, 0xb4, 0x38, 0x2d, 0x0b, 0x0c, 0x3a,\n\t0x46, 0x16, 0x1a, 0xf2, 0x83, 0xff, 0x17, 0x83, 0xec, 0xe1, 0x54, 0x89, 0xdb, 0x71, 0x79, 0x83, 0x68, 0xb5, 0xd3, 0x83, 0x73, 0x24, 0x53, 0x7a, 0x20, 0xa9, 0xfb, 0x6f, 0x19, 0xc3, 0x80, 0x75, 0xba, 0xa9, 0x1c, 0x19, 0x07, 0xe2, 0xdb, 0x39, 0x31, 0xb6, 0x6a, 0xe5, 0x8a, 0x65, 0x8b, 0x07, 0xbb, 0x3a, 0x8b, 0x6d, 0x71, 0x59, 0xe4, 0x99, 0xd4, 0x8d, 0xf9, 0xcb, 0x67, 0x23, 0x57, 0xc2, 0x9a, 0xd9, 0xb7, 0x13, 0x44, 0xe0, 0x43, 0x1a, 0x90, 0x53, 0x23, 0x59, 0x39, 0x1c, 0x7a, 0x99, 0x82, 0x32, 0xcd, 0x54, 0x9d, 0x9b, 0x97, 0xb4, 0x7a, 0x84, 0x0a, 0x87, 0xcf, 0x8c, 0xab, 0x4c, 0xc5, 0x9e, 0x67, 0x53, 0x9f, 0xf6, 0x07, 0x6c, 0x7e, 0x13, 0x3e, 0xfa, 0xe5, 0xfc, 0xa0, 0x29, 0xf5, 0x86, 0xb9, 0xa0, 0xa0, 0x16, 0xb8, 0x36, 0xd1, 0x52, 0x98, 0xe6, 0xda, 0x4b, 0x09, 0xd8, 0x34,\n\t0x83, 0x79, 0x02, 0x3e, 0x7c, 0xee, 0xf3, 0x86, 0x3c, 0x3c, 0x6c, 0xb3, 0xa5, 0x0e, 0x86, 0xed, 0xc6, 0x62, 0x7b, 0xca, 0x68, 0x71, 0xe0, 0x4f, 0xb9, 0x8c, 0xa9, 0x42, 0x7e, 0x93, 0xbd, 0x28, 0x9b, 0x6b, 0x65, 0x79, 0xf1, 0xbe, 0x70, 0x00, 0x78, 0x71, 0x3b, 0x7a, 0x4d, 0x8e, 0x65, 0x9a, 0x97, 0x60, 0x9d, 0xa6, 0xd8, 0xc0, 0x60, 0x5d, 0x2b, 0x88, 0x4c, 0x9a, 0x6f, 0xa4, 0x5c, 0xe1, 0x94, 0x2b, 0xa3, 0x72, 0xc3, 0x16, 0x70, 0xc7, 0x05, 0xcc, 0x92, 0xe8, 0x10, 0x0f, 0x56, 0xf3, 0x6e, 0xa4, 0x45, 0x8c, 0x46, 0xcb, 0x4c, 0xea, 0x39, 0x46, 0x89, 0x0f, 0xed, 0x1e, 0xa4, 0xdf, 0x75, 0xa3, 0x48, 0xa7, 0x9b, 0x06, 0x6a, 0xf1, 0x3c, 0x02, 0xab, 0x48, 0xd9, 0xaa, 0x6d, 0x5c, 0xa0, 0x3b, 0x50, 0x52, 0xed, 0x8c, 0xe7, 0xef, 0x0b, 0x92, 0x64, 0x72, 0xe3, 0xba, 0x89, 0xf1, 0xb1,\n\t0x55, 0x2b, 0x28, 0x79, 0xcb, 0x2b, 0x6c, 0x54, 0x92, 0x84, 0x65, 0xe3, 0x58, 0xce, 0x2b, 0xa8, 0x6f, 0x63, 0x33, 0xb1, 0xf6, 0xcb, 0x95, 0x23, 0xae, 0x88, 0x4a, 0x7e, 0x3f, 0x71, 0xb0, 0xac, 0xaa, 0xfd, 0xec, 0x74, 0x09, 0x07, 0xaa, 0x6e, 0xe8, 0x3d, 0x7c, 0xc3, 0x15, 0xd6, 0xfc, 0x67, 0x34, 0x56, 0xa3, 0x26, 0x3f, 0xb9, 0xb2, 0xb5, 0x6f, 0xd7, 0x40, 0xb8, 0x36, 0x51, 0x50, 0x77, 0x99, 0x22, 0xa5, 0x24, 0x5a, 0x59, 0xbd, 0xf1, 0xae, 0x0d, 0xeb, 0x6e, 0x5a, 0x5d, 0x82, 0x8b, 0x52, 0x3f, 0x6d, 0xaa, 0xf4, 0x46, 0x7d, 0x76, 0x8d, 0xd6, 0x20, 0x0c, 0x95, 0x55, 0x9d, 0xbc, 0x8e, 0xd9, 0xe0, 0x70, 0x0c, 0xe7, 0x17, 0x74, 0x76, 0x2d, 0x2a, 0xa8, 0x18, 0x6e, 0x0e, 0x94, 0x0d, 0x6c, 0xac, 0x6d, 0xbe, 0xba, 0xde, 0x12, 0xbb, 0x94, 0x64, 0x11, 0xc6, 0x36, 0x74, 0x5d, 0xbb,\n\t0xb1, 0xb9, 0x61, 0xfc, 0xca, 0xb6, 0xdf, 0x9c, 0x9a, 0x7d, 0xba, 0xa5, 0xd9, 0x64, 0x35, 0x69, 0x75, 0xb2, 0xae, 0xa5, 0x74, 0x3d, 0x81, 0x77, 0xc9, 0xe4, 0xf2, 0x1f, 0xc4, 0xc8, 0x58, 0xe3, 0x03, 0xd7, 0x66, 0x31, 0x66, 0xb4, 0x3b, 0x2c, 0x60, 0x65, 0x6c, 0x1f, 0x81, 0xa5, 0x36, 0x8e, 0x75, 0x7a, 0x61, 0x40, 0xc9, 0x05, 0x53, 0x1b, 0x89, 0xf3, 0x37, 0xba, 0xd8, 0x7d, 0x83, 0x30, 0x30, 0xaa, 0x70, 0x46, 0x0f, 0x68, 0x5b, 0x2d, 0xa6, 0xe9, 0x61, 0x0c, 0xd6, 0x82, 0xba, 0x35, 0x21, 0xde, 0x68, 0xe2, 0x27, 0x45, 0xc2, 0x0d, 0xc6, 0x31, 0x64, 0x34, 0xee, 0x1e, 0xa4, 0xdf, 0x69, 0xa6, 0xcf, 0xf4, 0xa0, 0x06, 0xf4, 0x86, 0xe2, 0x09, 0x11, 0x53, 0x5a, 0x37, 0x0e, 0x34, 0x9f, 0xd1, 0xa9, 0xf9, 0x69, 0x8b, 0x16, 0x18, 0x0d, 0x24, 0x82, 0x32, 0x16, 0xb1, 0xd8, 0x2f, 0x31,\n\t0x94, 0x34, 0x30, 0x77, 0x14, 0x3d, 0x6b, 0x60, 0xf5, 0x86, 0x99, 0xcb, 0x1d, 0x0d, 0x14, 0x9c, 0x3a, 0x18, 0x08, 0x99, 0xfc, 0xeb, 0x8e, 0x5e, 0x79, 0x60, 0xf3, 0xe4, 0xfa, 0x75, 0x6b, 0xd7, 0x0c, 0xf6, 0x53, 0x0e, 0x2c, 0x09, 0x5a, 0x2d, 0x66, 0x25, 0xa9, 0x23, 0xc3, 0x37, 0x6a, 0xb0, 0xe9, 0xe3, 0xf2, 0xe4, 0x65, 0x98, 0x1e, 0x59, 0xb2, 0xca, 0xc1, 0xb7, 0xe4, 0xb2, 0x54, 0xd3, 0xbc, 0xcc, 0x9a, 0x48, 0x5c, 0x4c, 0xff, 0xb5, 0x7c, 0x69, 0x7c, 0xfe, 0x08, 0x6a, 0xda, 0x60, 0x29, 0x89, 0xba, 0xf2, 0x55, 0x16, 0x66, 0x7f, 0x99, 0xe1, 0xb6, 0x75, 0x0b, 0x32, 0x70, 0x72, 0x7e, 0xd5, 0xb8, 0xa0, 0x75, 0xb3, 0xf8, 0x86, 0x97, 0xa9, 0x75, 0x23, 0x94, 0xaf, 0xab, 0x52, 0xd9, 0x1a, 0x7c, 0x85, 0x65, 0x60, 0x23, 0xff, 0x08, 0xac, 0x65, 0x13, 0xf8, 0x0a, 0xd3, 0x92, 0x21,\n\t0x04, 0x56, 0x8d, 0xdd, 0x44, 0x82, 0x81, 0x8c, 0x62, 0xcd, 0xf8, 0x48, 0xda, 0xd8, 0x66, 0x62, 0xc7, 0x53, 0x4d, 0xb0, 0x5b, 0x36, 0xf0, 0xd5, 0x6d, 0x41, 0xa9, 0xe8, 0x82, 0xdb, 0x34, 0xb3, 0x58, 0x71, 0xbf, 0x89, 0xd5, 0x2f, 0x99, 0xcc, 0x66, 0x73, 0xd8, 0x1c, 0x8e, 0x85, 0x42, 0x91, 0x62, 0xba, 0x03, 0x4e, 0x76, 0x5d, 0x05, 0x99, 0x26, 0xc9, 0x7a, 0x1b, 0xd0, 0xaf, 0x52, 0x51, 0x20, 0xaa, 0xaa, 0xb0, 0xb2, 0xf9, 0x55, 0x7b, 0xba, 0x6f, 0xbc, 0x27, 0xd0, 0x3e, 0xde, 0xb4, 0xf2, 0x48, 0xf2, 0xec, 0x95, 0x71, 0x9d, 0xb5, 0xe3, 0xd1, 0x9d, 0xab, 0x6f, 0x9f, 0x4a, 0xb6, 0xec, 0xfb, 0xc2, 0xf4, 0xf8, 0xb1, 0x04, 0xcb, 0xb4, 0xd7, 0x7c, 0xeb, 0xe5, 0x8d, 0xb7, 0xac, 0x8e, 0x0f, 0x75, 0x73, 0x8f, 0xfc, 0xb5, 0x25, 0x7a, 0xc5, 0xe2, 0x89, 0xae, 0xeb, 0x5f, 0x3f, 0xba,\n\t0xf7, 0xf5, 0x53, 0x23, 0x2d, 0xf5, 0x4c, 0x19, 0x22, 0xb9, 0x10, 0x30, 0x37, 0xde, 0x4b, 0x73, 0x21, 0xea, 0xe5, 0x5c, 0x08, 0xd6, 0x4e, 0xe3, 0x12, 0xcb, 0xc1, 0x3f, 0x9a, 0xa1, 0x73, 0x2e, 0x47, 0x57, 0x49, 0x86, 0x30, 0xb8, 0xac, 0x8e, 0x9c, 0x39, 0x87, 0xb5, 0x58, 0x04, 0x83, 0x8b, 0x17, 0x99, 0x8d, 0x20, 0x2d, 0xe9, 0xec, 0xa8, 0x5a, 0x9c, 0x9e, 0x13, 0xb4, 0x89, 0x2f, 0xdc, 0x2e, 0x3b, 0x66, 0x43, 0x3d, 0x04, 0x53, 0x79, 0x99, 0xd5, 0x6a, 0x8b, 0x85, 0x02, 0xb6, 0x88, 0x9c, 0xcc, 0x96, 0x83, 0x05, 0x1c, 0x9c, 0x07, 0x0d, 0x75, 0xc1, 0xba, 0x44, 0x5d, 0xc2, 0x91, 0x60, 0xdd, 0x95, 0x33, 0x5d, 0x37, 0xde, 0xab, 0x60, 0x03, 0xaf, 0xbe, 0x87, 0xe0, 0x43, 0x7a, 0x2c, 0x1b, 0x1f, 0xbf, 0xfa, 0xd5, 0xd9, 0x7b, 0x98, 0x5f, 0xb5, 0x25, 0x5e, 0x78, 0x69, 0xe3, 0x0d,\n\t0xcb, 0xc3, 0x43, 0xdd, 0xec, 0x8a, 0x8f, 0x6e, 0x23, 0x38, 0x91, 0xae, 0xfd, 0xc6, 0xd1, 0xbd, 0xdf, 0xb8, 0x65, 0x71, 0x4b, 0xf2, 0x7f, 0x8e, 0xbc, 0xf5, 0x16, 0xcc, 0x7d, 0x09, 0xf5, 0x0d, 0x6f, 0x45, 0x36, 0xd4, 0x89, 0x56, 0x83, 0x47, 0xc0, 0x33, 0x24, 0x00, 0xd7, 0xd6, 0xda, 0x54, 0x5b, 0x59, 0x21, 0xb0, 0x7d, 0xb2, 0xfd, 0x63, 0x27, 0xce, 0x21, 0x20, 0x64, 0x32, 0x3b, 0x64, 0xed, 0x9d, 0xe7, 0xf2, 0x1e, 0x1a, 0x17, 0xc6, 0x28, 0x1e, 0x2d, 0xf4, 0xcb, 0x9b, 0xb1, 0x6a, 0x30, 0xbb, 0x3e, 0x93, 0x91, 0x06, 0x8e, 0xb6, 0xea, 0xd8, 0x65, 0x6c, 0x81, 0xa8, 0x18, 0x8d, 0x24, 0xdb, 0x71, 0x24, 0x5a, 0x81, 0xdb, 0x49, 0x88, 0xaf, 0xde, 0xe5, 0x14, 0x44, 0x26, 0xde, 0xb5, 0x67, 0xb8, 0x9c, 0xb5, 0x24, 0xfa, 0xd6, 0xb7, 0x90, 0x35, 0x54, 0xb6, 0x78, 0x1a, 0xfb, 0x9b,\n\t0x37, 0x76, 0x47, 0xa4, 0x23, 0x5f, 0x3b, 0x34, 0xf9, 0xd4, 0xd1, 0xfe, 0xf6, 0x03, 0x8f, 0x6d, 0x9d, 0x7a, 0x4a, 0x72, 0xcc, 0x4c, 0xbc, 0x12, 0x36, 0x68, 0xec, 0x1b, 0x56, 0x6c, 0xf5, 0xf8, 0x4c, 0xce, 0x8d, 0x2f, 0x8e, 0x3c, 0x1e, 0xd1, 0x6b, 0xad, 0x27, 0x13, 0xdb, 0x1e, 0xda, 0x5d, 0x32, 0xd4, 0x1c, 0xac, 0x5a, 0xbe, 0xb7, 0x63, 0xe9, 0xd5, 0x2b, 0x4a, 0xb9, 0xb6, 0xea, 0x6b, 0x3e, 0xfd, 0xd2, 0xce, 0x3b, 0xff, 0xf3, 0xf3, 0x2b, 0x49, 0xf8, 0x79, 0xe2, 0x8b, 0x47, 0x07, 0x96, 0x8d, 0x5c, 0xf7, 0xd5, 0xf6, 0x1b, 0xdb, 0xec, 0x21, 0x83, 0x14, 0x76, 0x8b, 0x15, 0xb1, 0x2e, 0x4b, 0x6b, 0xd5, 0x55, 0xed, 0xb6, 0xa0, 0x01, 0x70, 0x43, 0xfc, 0xc5, 0x77, 0x39, 0xf2, 0x56, 0x87, 0x72, 0xb0, 0xb2, 0x29, 0x26, 0x22, 0x48, 0xe0, 0x78, 0x4e, 0xe0, 0x67, 0x48, 0xe8, 0x90,\n\t0x13, 0x30, 0x58, 0xe3, 0x8a, 0x43, 0xbb, 0x9b, 0x84, 0xc9, 0x33, 0xb8, 0xb9, 0x9c, 0x86, 0x14, 0x5b, 0xc0, 0x82, 0x65, 0x25, 0xd1, 0x70, 0xa0, 0xd0, 0xed, 0x32, 0x1b, 0xe1, 0x51, 0x9a, 0x90, 0x46, 0xe7, 0x28, 0xc5, 0x54, 0x76, 0x91, 0x98, 0x6b, 0x96, 0xca, 0x94, 0xc3, 0x0d, 0x01, 0x35, 0x4e, 0xe1, 0x62, 0x4b, 0x02, 0xd2, 0x78, 0xcb, 0xe1, 0xdb, 0x6d, 0xcc, 0xf3, 0xa1, 0x75, 0xdb, 0xf7, 0xd6, 0x6f, 0x7b, 0xee, 0xfa, 0xfe, 0xce, 0xc3, 0xcf, 0xee, 0x99, 0x78, 0x70, 0x5f, 0x87, 0xdd, 0x3b, 0x3b, 0xcd, 0x56, 0x8c, 0xcc, 0x74, 0x77, 0xac, 0xef, 0xae, 0xcc, 0xcb, 0x37, 0x32, 0xbb, 0x9a, 0x36, 0xf5, 0xc5, 0x4e, 0x1d, 0x4d, 0x85, 0x48, 0xe0, 0xa0, 0xf7, 0x96, 0xef, 0x9d, 0xd8, 0xfe, 0xe2, 0xcd, 0x4b, 0x5a, 0x0f, 0x3c, 0xb1, 0xab, 0xbc, 0x70, 0xec, 0xa6, 0xb5, 0x65, 0x05,\n\t0xc1, 0x82, 0x3c, 0xb2, 0x16, 0x86, 0x53, 0x4f, 0x28, 0x73, 0xee, 0xc2, 0x86, 0xe7, 0x6b, 0x48, 0xd8, 0x57, 0x71, 0x90, 0xab, 0x91, 0xc8, 0x13, 0xff, 0x6e, 0x46, 0x07, 0x33, 0xe2, 0x45, 0x4c, 0xce, 0x58, 0xa5, 0x17, 0xb9, 0x20, 0x28, 0x3b, 0x04, 0x39, 0x91, 0xb9, 0xc1, 0xd3, 0x86, 0xcb, 0xec, 0xb8, 0x73, 0x6e, 0xc7, 0xfc, 0xbf, 0xed, 0x89, 0x52, 0x83, 0xda, 0x47, 0x8d, 0x05, 0x5e, 0xb4, 0x6f, 0x76, 0x30, 0x10, 0x54, 0x8d, 0x07, 0x21, 0xb2, 0x97, 0x56, 0x55, 0x51, 0x1a, 0x0f, 0x07, 0xfd, 0x5e, 0x5b, 0x9e, 0x51, 0x4f, 0x29, 0xa2, 0xcf, 0xa1, 0x48, 0xd6, 0x96, 0xc6, 0x7c, 0x64, 0x21, 0x2a, 0x45, 0xcc, 0x39, 0x02, 0x91, 0x26, 0x93, 0x48, 0x43, 0x81, 0x52, 0x72, 0xf3, 0x53, 0x47, 0x7a, 0x16, 0x22, 0x54, 0x43, 0xf2, 0x53, 0x2b, 0x6c, 0x91, 0x42, 0x5b, 0xe6, 0x44, 0x84,\n\t0x42, 0xb9, 0x73, 0x33, 0x24, 0x02, 0x98, 0x58, 0x17, 0xe1, 0x06, 0x6e, 0xf9, 0xf6, 0xb1, 0x0b, 0xa9, 0xd7, 0xd7, 0xde, 0x6f, 0xd2, 0x17, 0x84, 0x4a, 0xf3, 0x95, 0xd8, 0x1f, 0x46, 0x15, 0x40, 0xd0, 0x2f, 0xf3, 0xcf, 0xa1, 0x42, 0xd4, 0x20, 0xd5, 0x59, 0xcc, 0x64, 0x0b, 0x04, 0xf3, 0x1c, 0x33, 0x90, 0x95, 0xf8, 0xc3, 0x71, 0x68, 0x14, 0x04, 0x1d, 0xe8, 0x5f, 0x22, 0xb7, 0xa7, 0x78, 0xb2, 0x4f, 0x51, 0x88, 0x0a, 0xad, 0x8e, 0xba, 0xb0, 0x93, 0xc8, 0xe6, 0x84, 0x15, 0x16, 0x64, 0x2b, 0x4e, 0x28, 0x7a, 0x50, 0x34, 0xd1, 0x55, 0x2c, 0x5b, 0x6c, 0x6f, 0x6e, 0x77, 0xf9, 0x3f, 0x5b, 0x33, 0x71, 0xfd, 0xb2, 0xee, 0x26, 0x0e, 0x9b, 0x5c, 0x01, 0x5b, 0xf9, 0x40, 0xad, 0x0f, 0xfb, 0x53, 0xff, 0xc5, 0xae, 0x31, 0xf2, 0x2e, 0xe7, 0xc8, 0xf8, 0xea, 0x9b, 0xd7, 0x57, 0xdb, 0x37,\n\t0x19, 0x8d, 0x02, 0x76, 0xd6, 0xae, 0x6c, 0x5f, 0x75, 0xea, 0xdc, 0x63, 0x72, 0x7c, 0xbc, 0xe2, 0xfc, 0x07, 0xc2, 0x8f, 0xf8, 0x77, 0x51, 0x03, 0xea, 0xc6, 0xdf, 0x90, 0x23, 0x86, 0x76, 0x17, 0x26, 0xc2, 0x84, 0xe7, 0xba, 0x1b, 0x23, 0xac, 0x8e, 0xcf, 0x03, 0x6b, 0x94, 0x1b, 0x50, 0x7c, 0x1e, 0xf5, 0x9e, 0x3e, 0xe7, 0xde, 0x85, 0x97, 0x19, 0xb8, 0x3c, 0xaa, 0x78, 0x6c, 0x95, 0x40, 0x5e, 0xcd, 0x18, 0x61, 0x8d, 0xcd, 0x60, 0xdb, 0x12, 0x83, 0x16, 0x11, 0x4f, 0x99, 0x7c, 0xe5, 0x46, 0x45, 0xcc, 0x71, 0x20, 0x92, 0x75, 0x3a, 0x3c, 0x26, 0x10, 0xa4, 0xec, 0xa4, 0xf9, 0xf9, 0xae, 0x8f, 0xdb, 0x6d, 0x0f, 0x56, 0xe3, 0x9d, 0x09, 0x70, 0x96, 0x36, 0x0f, 0xd2, 0xbe, 0xe8, 0x63, 0x74, 0x2d, 0xa6, 0x3c, 0x9e, 0xdb, 0x15, 0xe9, 0xf5, 0x4a, 0x4f, 0xb4, 0x70, 0xc7, 0x10, 0x8d,\n\t0x2a, 0x5c, 0x46, 0x47, 0x12, 0x25, 0x98, 0x92, 0xbb, 0x23, 0xb9, 0x33, 0xc0, 0xaa, 0x01, 0xb4, 0x69, 0xd8, 0x49, 0xb9, 0xff, 0x65, 0xf5, 0x1a, 0xa5, 0x6f, 0x94, 0xc9, 0x5b, 0xd4, 0xd1, 0xda, 0xdc, 0x90, 0x0c, 0x3b, 0xad, 0x56, 0x47, 0x30, 0x12, 0x2b, 0x36, 0x64, 0x45, 0x14, 0x72, 0x02, 0x75, 0x72, 0x16, 0x95, 0xcc, 0x24, 0xc1, 0x1c, 0x06, 0xa2, 0xbe, 0x5e, 0x76, 0xa0, 0x8f, 0x73, 0xcc, 0x17, 0xc8, 0x2b, 0x59, 0x1b, 0xef, 0xdf, 0xd1, 0x5d, 0x4c, 0x78, 0xe9, 0x2c, 0x61, 0xb2, 0xba, 0x2b, 0x5e, 0xbc, 0xbe, 0x74, 0xf1, 0xf0, 0xca, 0x84, 0x33, 0x13, 0x00, 0x64, 0x77, 0x5e, 0x10, 0xe3, 0x6b, 0x35, 0x58, 0xca, 0x16, 0xef, 0x68, 0x5f, 0x02, 0x8c, 0xa6, 0xb0, 0xe0, 0x92, 0xb1, 0xcf, 0xcc, 0xb4, 0x0b, 0x1a, 0x11, 0x7f, 0x94, 0x54, 0x43, 0x83, 0x32, 0xff, 0x69, 0x57, 0x03,\n\t0xff, 0x8d, 0xa0, 0x75, 0x4c, 0x8d, 0x4c, 0x41, 0xb7, 0x19, 0x2c, 0x56, 0xc9, 0xc2, 0x30, 0xda, 0x38, 0xd6, 0xa3, 0x75, 0xcb, 0x30, 0x6b, 0xd6, 0x37, 0x63, 0xd1, 0xcc, 0xab, 0x4c, 0x98, 0xd3, 0xc0, 0x92, 0xd3, 0x60, 0x81, 0x7b, 0x1a, 0xb8, 0xa7, 0xb2, 0x63, 0x1b, 0x20, 0x5b, 0x4e, 0xbf, 0xda, 0x3c, 0x98, 0x39, 0xb2, 0x60, 0x31, 0x32, 0x7a, 0xbd, 0x30, 0x06, 0xe2, 0x68, 0xb7, 0xfc, 0x1d, 0x8d, 0xea, 0x58, 0x86, 0x2c, 0x46, 0x64, 0x36, 0x8b, 0x63, 0x56, 0x93, 0x41, 0xc3, 0x89, 0xe2, 0x4e, 0x51, 0xe5, 0xce, 0xff, 0xcd, 0x28, 0x7b, 0x44, 0x95, 0x59, 0x3b, 0xe5, 0xb0, 0x2c, 0x19, 0x0a, 0xfd, 0xed, 0x23, 0x11, 0x9c, 0xb4, 0x2f, 0x38, 0x12, 0xb2, 0x58, 0x94, 0x71, 0x8c, 0xf8, 0xa2, 0xc3, 0x84, 0xa8, 0xd3, 0xf1, 0x31, 0x87, 0x81, 0x11, 0x58, 0x8d, 0x66, 0x4a, 0x1e, 0x0e,\n\t0xc9, 0x43, 0x49, 0x1d, 0x88, 0x03, 0x77, 0x83, 0xd3, 0x4e, 0xca, 0xa3, 0xfd, 0x0d, 0x63, 0xc8, 0x5c, 0x5e, 0x84, 0xd0, 0xf8, 0xda, 0x55, 0x2b, 0x80, 0x39, 0x46, 0x96, 0x0e, 0x2f, 0x59, 0x3c, 0x34, 0x38, 0xd0, 0xdf, 0xd5, 0x19, 0x89, 0x05, 0x83, 0x61, 0x22, 0x13, 0xf3, 0x80, 0xe7, 0x17, 0x94, 0x89, 0x59, 0x3c, 0x7e, 0xe9, 0x65, 0x11, 0xb0, 0xe6, 0x44, 0xbc, 0xe7, 0x17, 0xa6, 0xaf, 0x52, 0xce, 0x5f, 0x42, 0x38, 0x7f, 0xfe, 0x75, 0x52, 0x92, 0x5e, 0x27, 0xa9, 0x01, 0x1e, 0x65, 0xad, 0x0e, 0x99, 0xff, 0x87, 0xa8, 0x08, 0x9e, 0x34, 0x28, 0x22, 0xb8, 0x27, 0xbd, 0x1e, 0x66, 0xbf, 0x74, 0xd1, 0xd5, 0xb3, 0xf6, 0xdc, 0x63, 0xe9, 0x58, 0xba, 0xbc, 0x6f, 0x0a, 0xba, 0x84, 0x2f, 0xe1, 0xbf, 0x09, 0x32, 0xfb, 0xdf, 0x65, 0x96, 0xb6, 0x84, 0xc0, 0x9a, 0x0d, 0x5b, 0xcc, 0x2c,\n\t0x49, 0xc5, 0xd6, 0x88, 0x2c, 0x59, 0x28, 0x36, 0x72, 0x9d, 0x5c, 0x63, 0xe8, 0x35, 0x66, 0x00, 0xda, 0xf4, 0x79, 0x2f, 0x6c, 0xaa, 0x2e, 0x8b, 0x38, 0x11, 0x3a, 0x73, 0x89, 0x0e, 0x36, 0xb4, 0x88, 0x46, 0x05, 0x99, 0x4c, 0x7a, 0x1d, 0x03, 0x54, 0xd2, 0x0c, 0x29, 0x83, 0x07, 0x78, 0x7a, 0x36, 0x8a, 0xc3, 0x0b, 0x37, 0xfc, 0x18, 0x83, 0x8e, 0x52, 0xeb, 0x0b, 0xa6, 0xd4, 0x50, 0x9f, 0xb4, 0x12, 0x95, 0x47, 0x28, 0x6c, 0xb8, 0x34, 0x85, 0x73, 0xd5, 0x20, 0x21, 0xe5, 0x02, 0xd4, 0xab, 0x99, 0x38, 0xb1, 0x6c, 0x51, 0x0b, 0x8f, 0x8d, 0xf9, 0x45, 0x76, 0x55, 0x39, 0x02, 0xa1, 0x16, 0x20, 0xce, 0xd6, 0x5c, 0x7d, 0xb9, 0x49, 0x21, 0x44, 0x1a, 0xff, 0xc2, 0x13, 0x20, 0xb3, 0x6a, 0xb1, 0x59, 0x5e, 0xc6, 0xe6, 0x28, 0x66, 0x45, 0x1b, 0xe6, 0x51, 0x08, 0x33, 0x1c, 0x4f, 0x63,\n\t0x47, 0xd9, 0x57, 0xb4, 0x34, 0x76, 0x44, 0xa4, 0x46, 0x29, 0x3d, 0xd6, 0x49, 0x28, 0xb2, 0x79, 0x90, 0x04, 0x16, 0x15, 0x23, 0x54, 0x4b, 0x4f, 0xff, 0x68, 0xb0, 0x8c, 0x10, 0x81, 0xa5, 0xd9, 0x7f, 0x8a, 0x88, 0xa8, 0x04, 0xc4, 0x6d, 0x4e, 0x1f, 0x07, 0xbd, 0xac, 0x6e, 0x21, 0x9a, 0x42, 0x9a, 0xdb, 0x2d, 0x2b, 0xf4, 0xaf, 0xd5, 0x5e, 0xd8, 0x49, 0x22, 0x79, 0x65, 0x22, 0x8b, 0xc5, 0x49, 0xb9, 0xdf, 0x45, 0x5b, 0x8f, 0x2a, 0xc4, 0xaa, 0x45, 0xb5, 0x89, 0x1a, 0x47, 0xd0, 0x16, 0x84, 0xbf, 0xf9, 0x88, 0x05, 0xee, 0x93, 0x75, 0xbe, 0x28, 0x37, 0x9e, 0x63, 0xb7, 0x90, 0x85, 0x55, 0x3e, 0xb2, 0x62, 0xac, 0x21, 0x37, 0x80, 0x9d, 0xa5, 0x79, 0xb2, 0x55, 0x88, 0xa8, 0x11, 0x67, 0x9f, 0xbb, 0x20, 0x30, 0x9d, 0xb5, 0x62, 0x54, 0x1a, 0x69, 0xc3, 0x40, 0xa3, 0xc5, 0x78, 0x54,\n\t0xb1, 0x6a, 0xcc, 0x58, 0x87, 0x5b, 0x40, 0x31, 0xe8, 0x62, 0x58, 0x83, 0x1a, 0x31, 0x43, 0x36, 0x05, 0xbc, 0xf3, 0x5c, 0x36, 0x70, 0x2a, 0xb5, 0x1a, 0x41, 0xed, 0x5e, 0x28, 0xe3, 0x4d, 0x06, 0xe0, 0x58, 0x45, 0x8c, 0xd1, 0xef, 0x68, 0x54, 0x2f, 0xf3, 0xb2, 0xc5, 0x6c, 0xd4, 0x72, 0xf4, 0x78, 0xb5, 0x42, 0xbb, 0x56, 0x59, 0xfe, 0x91, 0x51, 0xd0, 0xdf, 0x34, 0x08, 0xa1, 0x64, 0xd3, 0x82, 0x83, 0xa0, 0xcc, 0x10, 0xd8, 0x60, 0x98, 0x6f, 0x04, 0x30, 0xc1, 0x39, 0xa4, 0x63, 0x38, 0xdd, 0x05, 0x92, 0xf8, 0x52, 0x5d, 0x09, 0x8d, 0x49, 0x46, 0xcd, 0x62, 0x44, 0xc5, 0x6e, 0x5f, 0x6f, 0x4f, 0xb7, 0xd4, 0xd6, 0xdc, 0x44, 0x49, 0x4d, 0x96, 0xa6, 0xf5, 0x72, 0x84, 0xef, 0x25, 0xc9, 0x7f, 0x91, 0xf5, 0x4a, 0x99, 0x62, 0xd9, 0xf2, 0xf1, 0x0b, 0x98, 0x22, 0x5b, 0xcc, 0x5e, 0x4c,\n\t0xb4, 0x5e, 0x92, 0x4f, 0x94, 0x05, 0x8d, 0x51, 0x25, 0x78, 0x83, 0x7f, 0xe4, 0xcf, 0xa2, 0x22, 0xd4, 0x24, 0xd5, 0x5b, 0x2d, 0xd4, 0x36, 0x27, 0xdb, 0xef, 0x2a, 0xba, 0xe8, 0x7a, 0x50, 0x6d, 0x73, 0x9a, 0x87, 0x05, 0x8b, 0x80, 0x1e, 0xc5, 0x28, 0x02, 0x51, 0x55, 0x1b, 0x76, 0x92, 0x84, 0xab, 0x5c, 0x64, 0x28, 0x1b, 0x64, 0x74, 0x9e, 0x74, 0x96, 0xdf, 0x27, 0xb3, 0x6c, 0x3e, 0xf8, 0x95, 0x83, 0x91, 0x15, 0x7e, 0x91, 0xa9, 0x88, 0x8f, 0x5d, 0xb7, 0x2c, 0xc2, 0x6c, 0x3f, 0x9b, 0xda, 0xa0, 0x4c, 0xa1, 0x1a, 0xfc, 0x8f, 0x76, 0x9d, 0x6e, 0xda, 0xce, 0x84, 0xfa, 0x76, 0xf5, 0x95, 0x9e, 0xcb, 0xa7, 0xd0, 0x65, 0xc3, 0xd6, 0x2d, 0x75, 0x3a, 0x00, 0x2c, 0x72, 0x34, 0x84, 0x21, 0xfb, 0x9d, 0x33, 0xf4, 0x28, 0x03, 0x59, 0x9a, 0xf2, 0x7a, 0x1d, 0x25, 0xe7, 0x95, 0x89, 0xc1,\n\t0x48, 0xc1, 0xc3, 0xc8, 0xeb, 0x51, 0x0e, 0x52, 0x1b, 0x75, 0x5a, 0x81, 0x43, 0x45, 0xb8, 0x48, 0x4b, 0x13, 0x54, 0x9d, 0x85, 0x58, 0xce, 0x40, 0xc1, 0x2a, 0x6c, 0xd9, 0x76, 0x21, 0xf3, 0x0f, 0x2d, 0x7d, 0xd6, 0x7b, 0xf6, 0xb8, 0xfc, 0xa6, 0x6b, 0x3f, 0x7f, 0x17, 0x05, 0x90, 0x5a, 0x7d, 0x8d, 0x57, 0x7f, 0x93, 0x3f, 0x1b, 0x29, 0xfa, 0xc0, 0x68, 0x3d, 0xc9, 0xdf, 0x79, 0x9b, 0x02, 0x5e, 0x36, 0xe8, 0xc4, 0x97, 0x00, 0x58, 0xb9, 0xb7, 0xf8, 0x57, 0x90, 0x0f, 0x7c, 0xf4, 0x65, 0xd2, 0xb0, 0x09, 0x2c, 0xb1, 0x10, 0x78, 0x3a, 0x5a, 0x82, 0x4d, 0x76, 0x40, 0x83, 0x45, 0x06, 0x31, 0x22, 0x02, 0x6f, 0x50, 0x3b, 0x39, 0x38, 0x2f, 0x6e, 0x75, 0x69, 0xdc, 0x96, 0x97, 0x95, 0xc6, 0x0b, 0xfc, 0x30, 0x92, 0xcf, 0x6a, 0xb5, 0x85, 0x83, 0x4e, 0x7d, 0x0e, 0x86, 0x93, 0x04, 0xc1,\n\t0xc4, 0xd1, 0x2b, 0x16, 0xd4, 0x39, 0xc8, 0x73, 0x8a, 0x44, 0x05, 0x33, 0x4d, 0x8d, 0xb2, 0x25, 0x28, 0xc2, 0x3f, 0x73, 0x9b, 0x3b, 0x6a, 0x2b, 0xf0, 0x74, 0xb5, 0xcb, 0xa8, 0x5e, 0x74, 0xbd, 0xc1, 0x65, 0xbc, 0x42, 0xa3, 0xd5, 0x6a, 0x0e, 0xea, 0xdc, 0x86, 0x9b, 0xdf, 0x7b, 0x41, 0x99, 0xc1, 0xb1, 0x47, 0x9f, 0xe6, 0x85, 0x1d, 0x56, 0xdd, 0xda, 0x2d, 0xc7, 0xe4, 0x99, 0x71, 0x77, 0x69, 0x0c, 0xd7, 0x68, 0x0c, 0x06, 0xcd, 0x35, 0x60, 0x78, 0xeb, 0x49, 0xbc, 0x8a, 0xcc, 0xed, 0x9b, 0x30, 0xb7, 0x28, 0x7a, 0x0e, 0xd0, 0x0e, 0x0a, 0x00, 0xd1, 0xed, 0x73, 0x7a, 0xfd, 0x2b, 0x70, 0x9d, 0x9e, 0x20, 0x47, 0xc7, 0x25, 0x53, 0x12, 0xfc, 0xba, 0x7a, 0x2c, 0xe0, 0x38, 0xd6, 0x68, 0x49, 0x1e, 0x4d, 0x8c, 0xea, 0x56, 0x41, 0xa0, 0xc1, 0xa7, 0xcd, 0xf4, 0x20, 0x8f, 0x7c, 0xe6,\n\t0x7d, 0x92, 0x9a, 0x59, 0x8a, 0x99, 0x9f, 0x51, 0x99, 0x51, 0x92, 0xf9, 0x48, 0x4e, 0xeb, 0xd1, 0x34, 0x23, 0xa5, 0xd7, 0x3c, 0x2d, 0x41, 0x04, 0xc7, 0x62, 0xb1, 0xae, 0x58, 0xd7, 0xa2, 0x4e, 0x82, 0x21, 0x0f, 0x39, 0x2c, 0x42, 0xbd, 0x80, 0x9c, 0x70, 0x4e, 0x01, 0xc3, 0xcf, 0xf9, 0x8d, 0x2f, 0x86, 0x45, 0x76, 0x93, 0x3d, 0x50, 0x96, 0xef, 0x2a, 0x2d, 0xb2, 0xd9, 0x8a, 0x4a, 0x5d, 0xf9, 0x65, 0x01, 0x3b, 0x1e, 0xb6, 0xc1, 0x95, 0x7c, 0xf9, 0x4a, 0x3e, 0x5c, 0xb1, 0x9d, 0xf3, 0x5d, 0x88, 0x59, 0x5e, 0x97, 0xae, 0xd6, 0x00, 0x2d, 0xa0, 0x87, 0x7b, 0xce, 0xef, 0xbf, 0xfe, 0x78, 0x21, 0x54, 0x2b, 0xb8, 0xfd, 0x2a, 0xc5, 0xed, 0x8b, 0x19, 0xdc, 0x2a, 0xd7, 0x9f, 0xa4, 0xd7, 0x5f, 0xce, 0xc2, 0x39, 0xac, 0x89, 0xd4, 0x13, 0xdc, 0x00, 0xac, 0x89, 0x26, 0x74, 0x9b, 0x64,\n\t0x56, 0xd7, 0xab, 0xb6, 0x1c, 0x8b, 0xbc, 0x9a, 0xb8, 0x14, 0xcf, 0x62, 0x2f, 0xa2, 0xc0, 0x58, 0x45, 0x81, 0x69, 0x88, 0x02, 0xa3, 0xee, 0x35, 0x35, 0x34, 0xb7, 0x8a, 0xf4, 0xf0, 0xab, 0x12, 0x1d, 0xba, 0x68, 0x1f, 0x94, 0xe9, 0x22, 0x2b, 0xbf, 0x26, 0xd4, 0xd4, 0xd8, 0xe0, 0x08, 0x05, 0xa3, 0x54, 0x02, 0x5c, 0xa8, 0xfc, 0x72, 0x25, 0xc0, 0xfc, 0x89, 0x98, 0x0b, 0x0b, 0x06, 0x57, 0x4e, 0xfe, 0x51, 0x81, 0x72, 0x9a, 0xb0, 0x66, 0x61, 0x71, 0x91, 0x95, 0x69, 0xd4, 0xaf, 0x1c, 0x31, 0x9c, 0x23, 0xdf, 0xc8, 0xba, 0x04, 0xf9, 0x66, 0x36, 0x5d, 0xb6, 0x7c, 0x4b, 0xaf, 0x3e, 0xcd, 0xa5, 0x56, 0xdf, 0x7c, 0x8b, 0x6d, 0x01, 0x7a, 0xcb, 0xf0, 0x08, 0x7b, 0x80, 0x7e, 0x8d, 0x68, 0x95, 0xb4, 0x3c, 0x0c, 0xb0, 0x44, 0xcc, 0x0c, 0x8f, 0x2d, 0x24, 0x47, 0x81, 0x6e, 0xd5, 0xcf,\n\t0x67, 0x34, 0x92, 0x43, 0xa5, 0x69, 0xa3, 0xd1, 0xa0, 0xd7, 0xb2, 0x54, 0x4b, 0x01, 0x90, 0x8d, 0xa8, 0x11, 0x4c, 0xc6, 0x3a, 0x2a, 0x88, 0x89, 0x62, 0x32, 0x5e, 0x5a, 0x31, 0x5d, 0x20, 0x9c, 0xd3, 0x53, 0x50, 0x8d, 0xc4, 0xb4, 0x1a, 0xfa, 0x7a, 0xf3, 0x95, 0xcf, 0x1e, 0x8c, 0x2c, 0x27, 0x94, 0x89, 0x8d, 0x1d, 0x23, 0x94, 0x39, 0x93, 0x5a, 0x7f, 0x26, 0xd5, 0xbf, 0x80, 0xe2, 0x99, 0x57, 0x8a, 0xa7, 0xe9, 0x40, 0xec, 0xc6, 0xdd, 0x60, 0xb7, 0x37, 0xa3, 0x7f, 0x91, 0x4c, 0x2e, 0xac, 0xe3, 0xf3, 0xb1, 0xa0, 0xd3, 0x92, 0x83, 0xc6, 0x4a, 0x58, 0xaf, 0x06, 0x81, 0xa4, 0x16, 0xb4, 0xdc, 0x0c, 0x68, 0x7b, 0x35, 0x94, 0xa0, 0xc8, 0x00, 0xf9, 0x08, 0x20, 0x37, 0xaa, 0x17, 0x19, 0x22, 0x05, 0x8c, 0x06, 0x96, 0x95, 0x53, 0x13, 0x64, 0x63, 0xbc, 0x36, 0xab, 0x27, 0x0f, 0x4a,\n\t0x81, 0x1e, 0x22, 0x21, 0x5d, 0xe5, 0xaf, 0x0b, 0xf4, 0xfd, 0x5b, 0x1e, 0x48, 0x76, 0x81, 0x60, 0x36, 0xcd, 0xa8, 0xb9, 0xa9, 0xb1, 0xb6, 0xaa, 0xbc, 0x34, 0x48, 0xad, 0x01, 0xf8, 0x47, 0x36, 0x9b, 0x03, 0xd6, 0x0b, 0x35, 0xca, 0x1c, 0x02, 0x00, 0xf7, 0xb8, 0x6c, 0xb2, 0xb0, 0x2e, 0x56, 0x69, 0xc0, 0x3f, 0x01, 0x6a, 0x26, 0x35, 0x78, 0x76, 0xa7, 0xcb, 0xf7, 0xb9, 0x0b, 0x48, 0xf0, 0xca, 0xbf, 0xff, 0xee, 0xd3, 0xbe, 0x07, 0x41, 0x23, 0x99, 0x8f, 0x69, 0xac, 0x9a, 0x9e, 0x2d, 0x8b, 0x02, 0xcc, 0x76, 0x15, 0xad, 0x0b, 0x59, 0xef, 0x5f, 0x7e, 0xad, 0x22, 0xf5, 0x91, 0xd1, 0x7a, 0x3b, 0xf6, 0x34, 0xae, 0xed, 0xd8, 0x74, 0x8e, 0x00, 0x2c, 0xcb, 0x13, 0x71, 0x31, 0xff, 0x0a, 0x13, 0x41, 0x2b, 0xe8, 0x9e, 0xc3, 0x33, 0xdc, 0xb1, 0xf4, 0xf5, 0xe6, 0xac, 0xeb, 0xcf, 0x71,\n\t0x47, 0x55, 0xd9, 0x2e, 0x46, 0x15, 0xd9, 0x3e, 0x81, 0x35, 0xf2, 0x26, 0x9f, 0xad, 0x1d, 0x63, 0xed, 0x0a, 0x89, 0x31, 0xe2, 0x6a, 0xcc, 0x73, 0xec, 0xc0, 0x72, 0xac, 0x05, 0xb7, 0xca, 0x06, 0x1f, 0x86, 0x9c, 0x3b, 0x9c, 0xba, 0x5f, 0xdc, 0x80, 0x8c, 0x46, 0xed, 0x98, 0x01, 0x53, 0xad, 0xa7, 0xd3, 0xa9, 0x5f, 0xb3, 0x15, 0x01, 0xd1, 0xd9, 0x9a, 0x51, 0x93, 0x1e, 0x24, 0x3b, 0xb1, 0xc1, 0x44, 0x96, 0x86, 0xff, 0xbc, 0xb2, 0xf2, 0x48, 0x42, 0x7f, 0xc3, 0x18, 0x4d, 0x34, 0xa1, 0xdd, 0xd1, 0x65, 0xf6, 0x96, 0x6a, 0x65, 0x4d, 0xa2, 0x21, 0x9a, 0x64, 0x9e, 0x21, 0xe6, 0xef, 0x46, 0xcc, 0x3e, 0x50, 0x25, 0x13, 0xb1, 0x89, 0xf1, 0xb1, 0x35, 0xab, 0x46, 0x86, 0x87, 0x06, 0x7b, 0x16, 0xb5, 0xb5, 0x10, 0x02, 0x3b, 0x88, 0x86, 0xb1, 0x5e, 0x96, 0x86, 0xb9, 0x1c, 0x26, 0xc8,\n\t0x16, 0x21, 0xfc, 0xbf, 0x52, 0x25, 0x53, 0x42, 0x54, 0x45, 0x09, 0x55, 0x32, 0xa0, 0x76, 0x8a, 0xe0, 0x4a, 0x19, 0x51, 0x3b, 0xf2, 0x67, 0xea, 0x06, 0xba, 0xf0, 0xce, 0xce, 0xbf, 0x4c, 0x3f, 0x73, 0x5b, 0x7e, 0x2c, 0xcf, 0xef, 0xe9, 0x06, 0xd9, 0x73, 0x39, 0xba, 0xe8, 0xe2, 0xec, 0x93, 0x23, 0xb3, 0x14, 0xfe, 0x48, 0x64, 0xf1, 0xc7, 0x8b, 0x59, 0x7c, 0x53, 0x92, 0x75, 0xfd, 0x65, 0x72, 0x5d, 0xd6, 0x4f, 0xc2, 0x77, 0x40, 0xbe, 0x2d, 0x47, 0x2f, 0x49, 0xae, 0xb9, 0xf2, 0xcd, 0xd0, 0x89, 0x75, 0x1a, 0x5e, 0xd1, 0x53, 0xc9, 0xf9, 0x44, 0x9d, 0x6c, 0x91, 0x0b, 0x69, 0x8b, 0x5c, 0x4f, 0x2c, 0x72, 0x1a, 0x5a, 0xd7, 0x8d, 0x01, 0xf9, 0xb6, 0x92, 0x6d, 0xdd, 0x56, 0xa4, 0x15, 0x49, 0x09, 0x92, 0x99, 0xcb, 0x1f, 0x00, 0x65, 0xfa, 0xcb, 0xa6, 0xfd, 0x72, 0xb4, 0x7c, 0x99,\n\t0x12, 0x57, 0xe9, 0xe9, 0x92, 0xda, 0xa2, 0xaa, 0x04, 0xb5, 0x7e, 0x5c, 0x09, 0xba, 0xb0, 0x72, 0xfb, 0x38, 0x82, 0xd5, 0x36, 0xaf, 0xca, 0xab, 0xfb, 0x58, 0xe2, 0x76, 0x01, 0x2d, 0x98, 0xa3, 0x77, 0x5e, 0x41, 0x75, 0xe8, 0x51, 0x79, 0x69, 0x5a, 0xc0, 0xd6, 0x61, 0xb5, 0x3c, 0x11, 0xc1, 0xcc, 0x40, 0x29, 0xe6, 0xfb, 0xe4, 0x3c, 0x3c, 0x4d, 0xe6, 0x72, 0x3a, 0xeb, 0xa3, 0x0c, 0xd6, 0xcc, 0x82, 0x82, 0x55, 0x27, 0xcb, 0x48, 0x83, 0x3e, 0x2d, 0x58, 0x4b, 0xa0, 0xf9, 0x02, 0x02, 0x75, 0x6e, 0xe3, 0x51, 0xc9, 0x09, 0xc4, 0xa8, 0x43, 0x75, 0xb5, 0x89, 0xaa, 0x8a, 0xb4, 0x34, 0x35, 0x5e, 0xb6, 0x34, 0xcd, 0x59, 0x48, 0x4f, 0x5d, 0xe6, 0x22, 0xf9, 0x38, 0x2b, 0x40, 0xe1, 0xe9, 0x4f, 0x50, 0x3f, 0xa4, 0x0a, 0xf5, 0x4b, 0x3d, 0x8a, 0xcd, 0x25, 0x0a, 0xe1, 0x10, 0x8d, 0x77,\n\t0x64, 0x19, 0x12, 0x82, 0xa0, 0x1a, 0x12, 0xa4, 0xda, 0x15, 0xb5, 0x9b, 0x28, 0x7f, 0xce, 0x50, 0x8b, 0xa2, 0x0a, 0x55, 0xd9, 0x92, 0x61, 0x62, 0x30, 0x91, 0x93, 0x3b, 0x17, 0x31, 0x98, 0xd2, 0xe7, 0xb0, 0x99, 0x1a, 0x12, 0x97, 0x5b, 0xd0, 0x4e, 0x0a, 0xf4, 0xed, 0x1d, 0x0e, 0xd4, 0xfb, 0x44, 0x46, 0x63, 0x76, 0xdb, 0x16, 0x4b, 0x0b, 0xd9, 0x47, 0x1f, 0xfd, 0x6b, 0xfb, 0xae, 0x91, 0x0a, 0x9d, 0x76, 0xbb, 0x4e, 0xcb, 0xf5, 0x2e, 0x65, 0x3f, 0x43, 0x14, 0x32, 0x9d, 0x13, 0xb5, 0x43, 0x7a, 0xd1, 0x66, 0x69, 0xd3, 0x9c, 0x75, 0xaa, 0xd3, 0x36, 0x82, 0x2d, 0xc2, 0xcf, 0x6b, 0x8b, 0xe8, 0x31, 0xb1, 0x0f, 0x95, 0xf5, 0x65, 0x34, 0x30, 0x34, 0x1b, 0x4b, 0xa3, 0xa1, 0xf6, 0xe1, 0x0c, 0x35, 0x4a, 0x7a, 0x11, 0xf8, 0xcb, 0x60, 0x99, 0x77, 0x84, 0xc3, 0xca, 0xa2, 0x32, 0x7d,\n\t0xcc, 0x45, 0x95, 0x7d, 0x10, 0x9d, 0xce, 0xff, 0xe3, 0x2c, 0xa5, 0x40, 0xef, 0xde, 0xa5, 0x80, 0x15, 0x0d, 0xe7, 0x8d, 0x00, 0x4e, 0x2e, 0x7f, 0x01, 0xa5, 0xd1, 0x64, 0xe3, 0x7a, 0x46, 0x08, 0x96, 0x72, 0x63, 0x5e, 0x6f, 0xf0, 0xef, 0xa2, 0x16, 0x12, 0xf3, 0x22, 0x29, 0x74, 0xa6, 0x4a, 0xa2, 0x5a, 0x30, 0xab, 0x2b, 0xc4, 0x02, 0x4b, 0x42, 0x5e, 0x70, 0x81, 0xcb, 0xba, 0xa0, 0xc4, 0x50, 0x62, 0xa0, 0x47, 0x05, 0x9e, 0x15, 0x26, 0x11, 0xa9, 0xf5, 0x25, 0x47, 0xbe, 0x40, 0x08, 0xa1, 0x51, 0x2d, 0xa7, 0x98, 0x72, 0x19, 0x6d, 0x57, 0x40, 0xd7, 0x99, 0xda, 0x9e, 0xc6, 0xa1, 0x48, 0x27, 0x74, 0xb1, 0x3e, 0x21, 0x7a, 0x4c, 0x61, 0x81, 0x3e, 0xca, 0x7e, 0x0d, 0x74, 0xc4, 0xb9, 0xfd, 0xa4, 0x0a, 0x98, 0x92, 0x86, 0xc3, 0x9a, 0xc9, 0xdc, 0xae, 0x0b, 0x75, 0xa0, 0x09, 0x76,\n\t0x80, 0x87, 0x16, 0xd4, 0x02, 0x66, 0x4f, 0x43, 0xd0, 0x1a, 0x8e, 0x86, 0x03, 0xb6, 0xf9, 0x8c, 0x4d, 0x12, 0xf4, 0xb8, 0x68, 0x02, 0xdd, 0x82, 0xc1, 0xaf, 0x8b, 0xe7, 0xc5, 0x2d, 0x1c, 0x0c, 0x5b, 0x38, 0xed, 0x6d, 0x6e, 0x4c, 0x0c, 0xe4, 0x9f, 0xb6, 0x13, 0x68, 0xb8, 0x12, 0x37, 0x4b, 0x36, 0x33, 0xd6, 0xe3, 0x2e, 0x58, 0xc7, 0x7a, 0x80, 0xd2, 0x58, 0x8b, 0xc1, 0x0e, 0x1c, 0x90, 0x29, 0x56, 0x07, 0x7e, 0x96, 0x56, 0x23, 0x68, 0x27, 0x91, 0x5e, 0x7f, 0x61, 0xf4, 0xcb, 0x8c, 0x8d, 0x46, 0x34, 0x6a, 0x10, 0x59, 0x96, 0x46, 0xee, 0x2d, 0x26, 0x1d, 0xa7, 0x06, 0x85, 0x0b, 0x68, 0xc8, 0x4c, 0xed, 0x4c, 0xdd, 0x56, 0x32, 0x02, 0xba, 0xec, 0x01, 0x42, 0x34, 0x64, 0x76, 0xa9, 0x01, 0x60, 0x91, 0x4d, 0xab, 0xa3, 0x28, 0xfb, 0x07, 0x99, 0x41, 0xa4, 0x66, 0x92, 0x97, 0xcb,\n\t0x70, 0xfa, 0xc9, 0xdc, 0x71, 0x2e, 0xab, 0xb7, 0xb2, 0xe5, 0x80, 0x56, 0xa2, 0x95, 0x2b, 0x14, 0xd5, 0xd8, 0xd7, 0x03, 0x8b, 0xb8, 0x9d, 0x12, 0xfb, 0xb2, 0xb7, 0x1c, 0x2e, 0x9f, 0x01, 0x2e, 0xb2, 0xa6, 0xeb, 0x0e, 0xbc, 0x74, 0x9c, 0x86, 0xbf, 0x2e, 0xc5, 0x16, 0x72, 0x38, 0xac, 0x20, 0xf5, 0xcb, 0x85, 0x57, 0xf9, 0xc7, 0xe2, 0x94, 0x8c, 0xae, 0xe4, 0xdc, 0xfc, 0x4b, 0xa8, 0x10, 0x6d, 0x7e, 0x1e, 0x16, 0xb5, 0x40, 0x32, 0x0f, 0x22, 0x40, 0x9f, 0x02, 0xa0, 0x46, 0x7a, 0x1d, 0x13, 0x61, 0xcf, 0xcb, 0xc2, 0x5e, 0x64, 0x94, 0xbc, 0x9b, 0x62, 0xb9, 0xda, 0x1c, 0x69, 0x85, 0x16, 0x68, 0x34, 0x2a, 0x59, 0x94, 0xad, 0x6d, 0x5b, 0x87, 0x35, 0x30, 0xaf, 0x2e, 0x68, 0x56, 0x51, 0x45, 0xd4, 0x9a, 0x23, 0x28, 0x63, 0xa9, 0x76, 0xeb, 0x83, 0xdb, 0x57, 0xdd, 0x3f, 0xb8, 0xeb,\n\t0x4c, 0x72, 0x47, 0xf4, 0x9a, 0x1b, 0x31, 0x73, 0x4e, 0x99, 0x6f, 0xcd, 0x8a, 0xfb, 0xf6, 0x75, 0x1a, 0xff, 0xba, 0x92, 0x2f, 0x66, 0x84, 0x3b, 0x8e, 0xd5, 0x9c, 0xca, 0x96, 0x59, 0x77, 0xc3, 0x1c, 0x1a, 0xd0, 0x9b, 0xb2, 0x97, 0xa4, 0x57, 0x36, 0xde, 0x05, 0x2d, 0x39, 0x68, 0x41, 0x7e, 0x89, 0xca, 0xaf, 0x51, 0xb9, 0x41, 0x50, 0xa4, 0x7b, 0x1a, 0x3c, 0xc7, 0x64, 0xe4, 0xbc, 0x46, 0x95, 0xf3, 0x3a, 0x56, 0x10, 0xa6, 0x04, 0x35, 0x21, 0xa2, 0x82, 0xc6, 0xd6, 0x95, 0x96, 0xe8, 0xd2, 0xbd, 0x68, 0xec, 0x3f, 0x9b, 0x99, 0xe5, 0xb2, 0x39, 0xf3, 0xb7, 0x56, 0x9c, 0x2c, 0xba, 0x1b, 0x02, 0x76, 0x41, 0x0d, 0xc5, 0xd3, 0x65, 0xab, 0x91, 0x44, 0x36, 0xee, 0x2e, 0x1a, 0x64, 0xad, 0xdd, 0xf6, 0xe0, 0xf6, 0x25, 0x77, 0x75, 0x9f, 0x78, 0xbd, 0x6e, 0x57, 0xe4, 0x9a, 0x9b, 0x2e,\n\t0x1e, 0x54, 0xa5, 0x58, 0x36, 0xe0, 0x6c, 0x34, 0x2b, 0xbc, 0x52, 0x71, 0xfe, 0x7d, 0x7e, 0x39, 0xff, 0x1c, 0xf8, 0x84, 0x5f, 0x56, 0xf2, 0xba, 0x23, 0x58, 0x03, 0xce, 0x2d, 0x02, 0x57, 0x88, 0x98, 0x50, 0x51, 0xac, 0xc1, 0xfd, 0xde, 0xec, 0xab, 0xac, 0x7a, 0x75, 0x54, 0x95, 0xfa, 0x1a, 0x5e, 0xe0, 0x35, 0x24, 0x29, 0x56, 0x50, 0x0e, 0xad, 0xeb, 0x75, 0x0c, 0xc3, 0x70, 0xa3, 0x5a, 0xd9, 0x5a, 0x22, 0xf4, 0x1c, 0x27, 0xee, 0x0e, 0xc9, 0x0f, 0x00, 0x81, 0x7f, 0xa9, 0xe6, 0x34, 0xc5, 0x8b, 0xf4, 0x91, 0x2b, 0x1e, 0xca, 0x21, 0x1b, 0xea, 0xb3, 0xca, 0x16, 0x96, 0xad, 0x24, 0x48, 0x83, 0x65, 0xf3, 0xa4, 0x2c, 0x5e, 0xc4, 0xde, 0xb2, 0x91, 0x35, 0x6d, 0x0d, 0x38, 0x38, 0xef, 0xdc, 0x9c, 0xc3, 0x54, 0xe3, 0xd9, 0x79, 0x31, 0xfc, 0x56, 0x39, 0xeb, 0xca, 0x9b, 0xc2, 0x45,\n\t0xec, 0xda, 0xb9, 0x69, 0x83, 0x69, 0xdb, 0x6b, 0x6e, 0x6a, 0x06, 0xae, 0xb6, 0xda, 0x52, 0x4f, 0x9e, 0x22, 0x6b, 0xf0, 0xfc, 0xfb, 0xe2, 0x3f, 0x01, 0x5e, 0x57, 0xa0, 0xb7, 0x65, 0x34, 0xe5, 0x87, 0x08, 0xc7, 0x82, 0x81, 0x22, 0x12, 0x03, 0xa5, 0x17, 0xeb, 0x75, 0xdc, 0x40, 0x18, 0x8b, 0x04, 0xb9, 0xea, 0x2d, 0x5e, 0xb9, 0x65, 0x54, 0x6f, 0x29, 0x18, 0xae, 0x46, 0xc0, 0xda, 0x58, 0x64, 0x66, 0xb2, 0x77, 0xed, 0x4c, 0x06, 0x86, 0x72, 0x9f, 0x20, 0x0b, 0x63, 0xd0, 0x7c, 0xfa, 0xb5, 0xe0, 0x2f, 0xb0, 0x7a, 0xfd, 0x94, 0x9e, 0x3a, 0x19, 0x22, 0xe6, 0x31, 0x3d, 0xf7, 0xc8, 0xab, 0x45, 0x1c, 0xb2, 0x77, 0x30, 0xb2, 0xfb, 0xc2, 0x5a, 0x32, 0x1a, 0x69, 0xa2, 0x82, 0x7e, 0x1c, 0xa4, 0xf6, 0x4e, 0xbd, 0xe2, 0x64, 0xac, 0x40, 0x8a, 0x28, 0x1d, 0xec, 0x6f, 0x6f, 0x6d, 0x6a,\n\t0xb4, 0x06, 0x95, 0xad, 0x3d, 0xeb, 0xc7, 0xda, 0xda, 0x53, 0x11, 0x1f, 0x58, 0x80, 0x5e, 0x0b, 0x8a, 0x51, 0x42, 0x90, 0x45, 0x2d, 0x40, 0x10, 0x75, 0xd7, 0xef, 0xed, 0x32, 0x8e, 0x10, 0xa4, 0x30, 0xf5, 0x5e, 0x53, 0x05, 0x25, 0xa1, 0x2e, 0x4d, 0xc2, 0x86, 0x85, 0x25, 0xe8, 0x02, 0x34, 0x9a, 0x87, 0xa6, 0xb2, 0xc1, 0xc4, 0xa2, 0xe6, 0xd4, 0xbd, 0xec, 0xaf, 0x39, 0x2d, 0x32, 0xa3, 0x20, 0x9a, 0x40, 0x9f, 0x94, 0xcc, 0x31, 0x8c, 0xf0, 0xf2, 0x1a, 0x86, 0x43, 0x83, 0x60, 0x5f, 0x92, 0x80, 0x0f, 0xd9, 0x20, 0x2a, 0x23, 0x76, 0x06, 0xc7, 0x23, 0x0e, 0xd4, 0x14, 0x62, 0x58, 0x9e, 0x99, 0x24, 0x71, 0x2e, 0x9a, 0xca, 0xa8, 0x1e, 0x96, 0x64, 0x59, 0xba, 0x51, 0x33, 0x43, 0x44, 0x48, 0x25, 0xdc, 0x15, 0xc1, 0x2c, 0xc5, 0x33, 0x17, 0xf4, 0x9b, 0xb7, 0xc7, 0xa8, 0xe4, 0x0f,\n\t0x85, 0x30, 0x0a, 0x4d, 0x84, 0x26, 0xc6, 0xd7, 0x76, 0x75, 0x36, 0x35, 0x54, 0x57, 0x16, 0x15, 0x38, 0xed, 0x5a, 0x11, 0x99, 0xb1, 0x59, 0x9f, 0x29, 0x57, 0xa1, 0x24, 0x3b, 0xe2, 0xda, 0x0a, 0x2e, 0x6a, 0xc2, 0x6a, 0x46, 0xae, 0xcd, 0x61, 0xcf, 0xa4, 0xe3, 0xca, 0xd7, 0x85, 0x4c, 0xb2, 0x60, 0xb2, 0x5e, 0x4e, 0xc4, 0xad, 0x57, 0xf3, 0x71, 0x5d, 0xf8, 0xbf, 0x6b, 0x87, 0xeb, 0xbc, 0x3b, 0xb6, 0x6e, 0xd9, 0xe1, 0xad, 0x1b, 0xc6, 0xdb, 0x63, 0xdd, 0xe3, 0x9b, 0xb7, 0x57, 0xd7, 0x2e, 0x0a, 0x74, 0x6f, 0xeb, 0xef, 0xdb, 0x3d, 0x18, 0x7d, 0xa3, 0x7c, 0x97, 0xc9, 0xd2, 0x34, 0x7d, 0xfb, 0x8a, 0xee, 0x96, 0x82, 0xc2, 0xe6, 0xf5, 0x87, 0xaf, 0x3d, 0xbc, 0xbe, 0xb9, 0xe3, 0xc8, 0xb3, 0x7b, 0xf7, 0x7e, 0x71, 0x4f, 0xfd, 0xf8, 0x48, 0x59, 0xad, 0x25, 0x50, 0x5d, 0x34, 0xb8,\n\t0xaa, 0x69, 0xcb, 0x1d, 0x2b, 0x4f, 0xac, 0xc7, 0x1f, 0xf9, 0x12, 0x7d, 0xa5, 0x6b, 0xb6, 0x6d, 0x5b, 0x53, 0xda, 0x9b, 0xf0, 0xcf, 0xfe, 0x30, 0x54, 0xea, 0xd6, 0x0b, 0xbc, 0xe8, 0x19, 0xa8, 0x29, 0x6a, 0x88, 0xbb, 0xdc, 0xe5, 0x6d, 0x5c, 0x59, 0x7f, 0x48, 0x6b, 0x29, 0xec, 0x8e, 0x0c, 0x1e, 0x5a, 0x55, 0x61, 0xce, 0x2b, 0x75, 0x04, 0x8b, 0xcd, 0x9c, 0xd6, 0x95, 0x18, 0xed, 0xed, 0x3c, 0xb2, 0xa1, 0xa9, 0x6c, 0x60, 0x53, 0xdd, 0xc0, 0x16, 0xbf, 0xbd, 0xbb, 0xd1, 0x59, 0x59, 0x59, 0x62, 0x2d, 0xb9, 0x75, 0x62, 0xf0, 0xaa, 0x55, 0x15, 0xf5, 0x64, 0x8f, 0x62, 0x59, 0xea, 0x53, 0xec, 0x8f, 0x38, 0x1d, 0x32, 0x81, 0x2d, 0xf7, 0xa8, 0x4c, 0x04, 0x5b, 0x23, 0x46, 0x82, 0x89, 0x14, 0x0f, 0x8e, 0x02, 0xbb, 0xe7, 0xd3, 0xda, 0x11, 0x5e, 0x7a, 0x55, 0x9c, 0x73, 0x55, 0xd9,\n\t0x4a, 0x8c, 0xa7, 0x0b, 0x42, 0x80, 0x82, 0x19, 0x03, 0xad, 0x46, 0xf6, 0xd1, 0xd4, 0xe3, 0x19, 0x53, 0xd9, 0x25, 0x21, 0xbc, 0x52, 0xb9, 0xda, 0x96, 0xb8, 0x43, 0x54, 0x8e, 0x29, 0xfb, 0x6e, 0xf3, 0xb6, 0x07, 0xcd, 0x68, 0x36, 0x9b, 0x5b, 0xcc, 0xcd, 0xb1, 0x78, 0x30, 0x1c, 0x8b, 0x14, 0xd3, 0xfa, 0x06, 0x73, 0x52, 0x72, 0xb3, 0x3d, 0x03, 0x99, 0x50, 0xad, 0x73, 0x4e, 0x73, 0xd4, 0x27, 0x13, 0x6c, 0x7e, 0xc5, 0xde, 0x2e, 0x92, 0xa4, 0x3b, 0xd1, 0xbc, 0xec, 0x48, 0xf2, 0x6c, 0xc7, 0xe1, 0x67, 0xf7, 0x5d, 0xfb, 0x7c, 0x4b, 0xb9, 0xc6, 0x6d, 0xb3, 0x95, 0x34, 0xaf, 0x68, 0xef, 0xdb, 0xd9, 0x17, 0x0a, 0x2c, 0x1a, 0x5c, 0x99, 0x98, 0xb8, 0x77, 0x4b, 0x3d, 0x49, 0x53, 0xdd, 0x74, 0x73, 0x9d, 0x41, 0x17, 0x67, 0xb9, 0x96, 0xc4, 0xd7, 0x4e, 0x8f, 0xdf, 0xb0, 0x2a, 0x3e,\n\t0xd4, 0xcd, 0x7c, 0xe3, 0x5c, 0xcf, 0xf8, 0xfd, 0x33, 0xed, 0xfd, 0xc9, 0x41, 0x93, 0xd9, 0x17, 0xf0, 0xc5, 0xfb, 0x27, 0x1b, 0xb7, 0x87, 0xeb, 0x43, 0x79, 0x5d, 0xc7, 0xbf, 0x7e, 0xf5, 0xce, 0x57, 0x4f, 0x0e, 0x77, 0xb5, 0xf6, 0x45, 0x65, 0x3d, 0x7b, 0x0b, 0x30, 0xfc, 0x7b, 0xe0, 0x47, 0x39, 0x50, 0x29, 0xd8, 0xfb, 0x98, 0x9c, 0xba, 0x02, 0x21, 0x33, 0xa0, 0xaa, 0x3a, 0x25, 0xa9, 0x49, 0xa9, 0xf3, 0x6b, 0x25, 0x07, 0xa0, 0x68, 0xe1, 0x97, 0x79, 0xf6, 0x06, 0x13, 0x78, 0x28, 0x77, 0xbb, 0xef, 0xcc, 0x3c, 0x67, 0x90, 0xce, 0x92, 0x5a, 0xc3, 0x5f, 0x20, 0xcf, 0x14, 0xbd, 0x40, 0xc7, 0x10, 0xa9, 0xda, 0x28, 0x80, 0x5a, 0x31, 0x63, 0x9e, 0x2d, 0xc2, 0xb2, 0x3f, 0x8a, 0x98, 0x7d, 0xa0, 0x7a, 0x44, 0xb4, 0x4f, 0x3e, 0x3f, 0x93, 0xde, 0xce, 0x56, 0x76, 0xc7, 0x08, 0x10,\n\t0x41, 0x6b, 0x5c, 0x3e, 0xa3, 0x4d, 0x82, 0x91, 0x8c, 0xba, 0x6d, 0x64, 0x9b, 0x0f, 0x2a, 0xa6, 0xea, 0x94, 0x31, 0x94, 0xb7, 0xcb, 0x60, 0xd8, 0x95, 0x17, 0x32, 0xde, 0xfc, 0xbb, 0xd3, 0xfa, 0x39, 0x40, 0x0a, 0x3a, 0xad, 0xeb, 0x44, 0x5e, 0xde, 0x09, 0x97, 0x16, 0x5b, 0xcf, 0x8d, 0xcf, 0x03, 0x30, 0x3e, 0xff, 0x7b, 0x80, 0xf7, 0xa7, 0xf0, 0xcd, 0x8f, 0x1a, 0xa5, 0x64, 0x06, 0x47, 0x20, 0x60, 0x35, 0x98, 0x1c, 0xaf, 0xdd, 0x08, 0x4c, 0x91, 0xc1, 0xd6, 0x74, 0x1a, 0x5b, 0xe4, 0x1f, 0xc1, 0x98, 0x76, 0x81, 0x23, 0x63, 0x72, 0x1a, 0x32, 0x48, 0x46, 0xc0, 0xdc, 0x67, 0x14, 0xa0, 0xa6, 0x01, 0xa8, 0xb3, 0x9f, 0xfc, 0xe4, 0x59, 0x5c, 0x9c, 0xfa, 0x09, 0xbb, 0xa1, 0x73, 0x09, 0x05, 0xe7, 0x2e, 0x66, 0xcf, 0xae, 0x43, 0x3d, 0x6d, 0xb3, 0x95, 0xdc, 0x75, 0x47, 0xbe, 0xf3,\n\t0x9d, 0x23, 0x64, 0x2d, 0xec, 0x02, 0xe2, 0x5d, 0xcd, 0xbf, 0x4c, 0x6b, 0x39, 0x92, 0x2a, 0x91, 0x4a, 0xd2, 0xff, 0x66, 0x7a, 0x14, 0x60, 0x3a, 0x5d, 0xa0, 0xc1, 0x9e, 0xa7, 0x23, 0x69, 0x6a, 0xac, 0x95, 0x27, 0xa9, 0x97, 0xf0, 0x4c, 0xdb, 0xdc, 0x80, 0xdf, 0xca, 0x33, 0xbf, 0x74, 0x86, 0x6b, 0xbc, 0xde, 0xaa, 0xb0, 0xc3, 0x11, 0xae, 0xf2, 0x7a, 0x6b, 0xc2, 0x4e, 0xf6, 0xc3, 0x73, 0x1a, 0xf6, 0x43, 0xdc, 0xe4, 0xad, 0x26, 0xd7, 0xaa, 0xbd, 0x3e, 0xf9, 0x93, 0xe6, 0x1c, 0xb6, 0xa7, 0x9e, 0xc0, 0xa7, 0xe1, 0xb9, 0x36, 0x54, 0x8d, 0xf6, 0x7d, 0x35, 0x80, 0x59, 0xdc, 0xaf, 0x94, 0xcd, 0x16, 0x69, 0x58, 0x33, 0xcb, 0x79, 0x23, 0x7a, 0x9c, 0x6c, 0xd7, 0x64, 0x92, 0x4a, 0x63, 0x48, 0x60, 0xc1, 0x61, 0x23, 0xc9, 0xbc, 0xf3, 0xb4, 0x45, 0x99, 0xa6, 0xa3, 0x92, 0x03, 0x23,\n\t0x92, 0x3e, 0x4a, 0xca, 0xbe, 0xe6, 0x3b, 0xe5, 0x14, 0x68, 0x52, 0x3e, 0xc9, 0x96, 0x93, 0xc4, 0x6b, 0x62, 0x6c, 0x0b, 0xd7, 0x71, 0xfc, 0x20, 0x7b, 0x4a, 0x30, 0xc5, 0x87, 0x95, 0xa8, 0x54, 0xfd, 0x19, 0x6b, 0x4e, 0xb4, 0x8a, 0x7b, 0x2a, 0x6b, 0x8e, 0x3e, 0x32, 0xe7, 0xbf, 0x56, 0xab, 0xf1, 0x27, 0x40, 0xc4, 0x9c, 0x1a, 0xa6, 0x77, 0xc3, 0xff, 0x56, 0xb1, 0x1f, 0x02, 0x4e, 0xdd, 0x92, 0x93, 0xc9, 0xc1, 0x35, 0xc5, 0x33, 0xab, 0xe0, 0x19, 0xaf, 0x3a, 0x2b, 0xa3, 0x11, 0xae, 0xae, 0x4f, 0xdd, 0xc7, 0x7e, 0x9d, 0xe2, 0xac, 0x15, 0x8d, 0xa0, 0x3b, 0x24, 0x53, 0x2b, 0x28, 0xf3, 0x18, 0xa8, 0xfb, 0x02, 0xcc, 0x72, 0xea, 0xfe, 0x41, 0x5c, 0xab, 0x63, 0x08, 0x52, 0xf4, 0x1a, 0x86, 0xa0, 0x85, 0xe4, 0x0e, 0x4e, 0xa7, 0x6b, 0xd5, 0xec, 0x24, 0x68, 0xa2, 0x04, 0x9e, 0x91,\n\t0xf3, 0xe3, 0x2f, 0xd2, 0x76, 0x4f, 0x76, 0xdb, 0x51, 0xa9, 0xb0, 0xbd, 0x0d, 0xa3, 0xfe, 0xde, 0xb6, 0x91, 0xf6, 0x91, 0xc6, 0xfa, 0xda, 0x44, 0x45, 0x59, 0xb8, 0xd8, 0xe7, 0x71, 0xd8, 0x33, 0x25, 0xbe, 0xe6, 0xa2, 0x94, 0x4f, 0xcc, 0x89, 0xe0, 0xa4, 0x45, 0x14, 0x29, 0x3c, 0x42, 0xb1, 0x5b, 0x6f, 0xcb, 0x4a, 0xca, 0x22, 0x7d, 0x7f, 0xa6, 0xe2, 0xda, 0x57, 0x1d, 0x71, 0x3a, 0x23, 0xd5, 0xf8, 0x9f, 0xcf, 0x94, 0x4f, 0xdc, 0x39, 0x19, 0xe8, 0xf6, 0x99, 0x18, 0xad, 0xd5, 0xe7, 0x98, 0xd9, 0xeb, 0x49, 0xb6, 0xf5, 0x97, 0xae, 0xbc, 0x76, 0x45, 0xfc, 0xec, 0xe4, 0x74, 0xb0, 0xbe, 0x22, 0xee, 0x98, 0x54, 0x9a, 0xfa, 0xbc, 0x55, 0x21, 0x87, 0x23, 0x54, 0x75, 0x21, 0x19, 0xbe, 0x7a, 0xce, 0xba, 0xfc, 0xe6, 0x4d, 0x49, 0x9d, 0x8e, 0x44, 0x7e, 0xb6, 0x1c, 0x9c, 0xf0, 0x97,\n\t0xfa, 0xcd, 0xf5, 0x53, 0xa7, 0x56, 0x91, 0x8a, 0xa2, 0x3b, 0x0f, 0xe9, 0x3d, 0x25, 0x85, 0xdc, 0x37, 0xd5, 0xb6, 0x6a, 0x5f, 0x5a, 0xcb, 0xfc, 0xa5, 0xd4, 0x27, 0xe8, 0xda, 0xb0, 0xa2, 0x30, 0x4a, 0x48, 0x55, 0x5a, 0x5a, 0xb9, 0x04, 0x91, 0x82, 0xe0, 0x54, 0xac, 0xf1, 0x32, 0xba, 0x32, 0xe5, 0x06, 0x11, 0x2a, 0x2e, 0xca, 0x77, 0x92, 0x12, 0x91, 0xe1, 0x30, 0x2d, 0xad, 0x34, 0x37, 0x82, 0x73, 0xe1, 0xa2, 0xc9, 0x89, 0xd2, 0xfc, 0x52, 0x9e, 0x46, 0x06, 0x03, 0xec, 0x87, 0x1f, 0x7d, 0x27, 0x2b, 0x1a, 0xc3, 0x35, 0xcc, 0xb7, 0x96, 0xf0, 0xf9, 0x97, 0x01, 0x4e, 0xc2, 0x4b, 0x36, 0x14, 0x91, 0x82, 0x3a, 0x2d, 0x3d, 0x31, 0xc0, 0x5e, 0x08, 0x1c, 0xdc, 0xb7, 0x25, 0xc3, 0x5c, 0x2e, 0x60, 0x4a, 0x6c, 0x0d, 0xaf, 0x9a, 0x13, 0x45, 0xcb, 0x7a, 0x34, 0x8d, 0x97, 0x71, 0x0d,\n\t0x19, 0x39, 0x3f, 0x4b, 0x65, 0x58, 0xb5, 0x54, 0x91, 0x5b, 0x03, 0x54, 0x39, 0x69, 0x42, 0x58, 0x59, 0xa9, 0x8e, 0x05, 0x77, 0xfc, 0xc8, 0x4f, 0x03, 0x25, 0x72, 0x69, 0xc5, 0x8b, 0x39, 0xc5, 0x78, 0xe8, 0xe2, 0x6e, 0x2e, 0x7f, 0x76, 0x61, 0xdf, 0xf5, 0x6c, 0x06, 0x36, 0xc0, 0x83, 0x9f, 0xd4, 0xd0, 0x9c, 0x03, 0x1b, 0xcf, 0xfc, 0xff, 0x05, 0x17, 0xfb, 0x61, 0x6a, 0xd7, 0x02, 0x70, 0x01, 0x2c, 0x04, 0xae, 0x12, 0x60, 0xa6, 0x35, 0x00, 0xa3, 0x19, 0x15, 0x48, 0x5e, 0xb3, 0x41, 0x23, 0x72, 0x48, 0x40, 0x72, 0x7d, 0xd1, 0xcd, 0xca, 0xaa, 0x77, 0x39, 0x48, 0xc9, 0x5a, 0x4c, 0xac, 0x2d, 0x78, 0xa4, 0x5a, 0x57, 0x94, 0x59, 0xe3, 0x7b, 0xf0, 0xec, 0x57, 0x3c, 0x9f, 0x3c, 0xcb, 0xfe, 0x79, 0x6f, 0x50, 0xdf, 0x7d, 0xee, 0xb7, 0xcc, 0x9b, 0x83, 0x07, 0xfc, 0xc6, 0x45, 0xcc,\n\t0xa6, 0xd9, 0x9f, 0x9f, 0x3f, 0x8f, 0x6e, 0x87, 0x71, 0x3f, 0x4b, 0xce, 0xcf, 0x70, 0x07, 0xe4, 0xf3, 0x33, 0xe8, 0x93, 0x2a, 0x1e, 0xf8, 0x3f, 0x73, 0x1a, 0x78, 0xee, 0x98, 0xa4, 0xe7, 0x41, 0xb5, 0xc4, 0xf5, 0x0c, 0xcb, 0x31, 0x4a, 0xc9, 0x13, 0xa7, 0x40, 0xab, 0xdd, 0x32, 0x98, 0x91, 0xfd, 0x71, 0x9e, 0x55, 0xbc, 0x76, 0x0f, 0x92, 0xf3, 0xce, 0x55, 0xe7, 0x7e, 0x77, 0xe6, 0xa6, 0xec, 0xad, 0x97, 0xa0, 0x12, 0x50, 0x99, 0x8e, 0x48, 0x28, 0x20, 0x7b, 0xeb, 0x24, 0xd4, 0xaf, 0x14, 0x5f, 0x60, 0xb3, 0x95, 0x92, 0x29, 0x5b, 0x3d, 0xdd, 0x72, 0x45, 0x5c, 0x67, 0x6a, 0xb8, 0x65, 0x7c, 0xf3, 0x51, 0xbf, 0xb3, 0x67, 0xd5, 0xc6, 0x9a, 0x91, 0x6b, 0xd7, 0x54, 0x9c, 0x9d, 0x5c, 0x5f, 0x32, 0xd4, 0x18, 0x38, 0xbb, 0x6e, 0xac, 0x7d, 0x67, 0x39, 0xfb, 0x61, 0x74, 0xe3, 0xa2,\n\t0x95, 0x7b, 0xd6, 0x27, 0x97, 0xd4, 0xe4, 0x27, 0x36, 0xdd, 0x39, 0x4e, 0x94, 0xe6, 0xbe, 0x03, 0xfe, 0xa6, 0x55, 0x8d, 0xe4, 0xdb, 0x95, 0x33, 0x9d, 0x8d, 0xb3, 0xa6, 0x2c, 0x1b, 0x03, 0xe6, 0xe5, 0x46, 0x5d, 0xcf, 0xdb, 0x68, 0x99, 0x7e, 0x79, 0x46, 0x79, 0x54, 0x65, 0x72, 0x38, 0xcb, 0xc2, 0xf0, 0x4a, 0x4e, 0x59, 0x21, 0xcc, 0x35, 0x3d, 0x46, 0x5f, 0x0c, 0x80, 0x2a, 0x95, 0xab, 0xce, 0xe5, 0x42, 0x2d, 0xab, 0x79, 0x30, 0x61, 0xa5, 0x40, 0xdf, 0xc8, 0x44, 0x5d, 0x96, 0x6e, 0x87, 0x19, 0xb0, 0x3b, 0x82, 0x4d, 0x71, 0x57, 0xae, 0x4e, 0x07, 0xc0, 0x15, 0xb8, 0xc0, 0xce, 0x7f, 0x8f, 0xe2, 0xfb, 0x61, 0x39, 0x40, 0xa2, 0x0b, 0x61, 0x9e, 0xb3, 0x51, 0xe5, 0xee, 0x4d, 0xff, 0x60, 0xd3, 0x55, 0x20, 0x7d, 0xb4, 0x9a, 0xb0, 0x80, 0x95, 0x34, 0xef, 0xa9, 0xb9, 0x95, 0xe9,\n\t0xc9, 0x10, 0x45, 0x60, 0x0b, 0x4c, 0xa7, 0xcb, 0x0e, 0xcf, 0xd7, 0x4e, 0x8a, 0x22, 0x70, 0x22, 0x78, 0x52, 0x7a, 0x7e, 0x9e, 0xa6, 0xb9, 0x95, 0xe7, 0x75, 0x01, 0x5b, 0x38, 0x10, 0x8e, 0x87, 0x44, 0x62, 0x4b, 0xaa, 0xd3, 0x9e, 0x5b, 0xe7, 0xb4, 0x6e, 0x21, 0x34, 0xc4, 0x57, 0x1c, 0xcf, 0x29, 0x76, 0x3a, 0x1f, 0x56, 0x8e, 0x2f, 0xbf, 0x65, 0x32, 0x69, 0xb5, 0xaf, 0x74, 0x9b, 0x8c, 0x53, 0x5b, 0x98, 0x7b, 0xb3, 0x30, 0x44, 0xcf, 0xed, 0x70, 0xc5, 0x80, 0x1f, 0x1b, 0x2a, 0x44, 0xc3, 0xb2, 0x96, 0x72, 0xd1, 0x12, 0xa7, 0x32, 0xc9, 0x78, 0x75, 0x56, 0xd4, 0xaf, 0x9f, 0xf7, 0x0e, 0xc9, 0x79, 0x97, 0xc0, 0x17, 0xc1, 0xc8, 0xeb, 0xb6, 0x17, 0x3a, 0x0a, 0x65, 0xad, 0x43, 0xdf, 0xe5, 0x31, 0x47, 0x83, 0xd8, 0xd4, 0x0c, 0x5e, 0x50, 0xe0, 0x4c, 0xd3, 0xcc, 0xf3, 0xd7, 0x76,\n\t0x75, 0x5d, 0xfb, 0xfc, 0xcc, 0xde, 0xe7, 0xaf, 0xeb, 0xee, 0xbe, 0xee, 0xf9, 0xbd, 0x77, 0x9e, 0x3a, 0x75, 0xe7, 0xdd, 0x77, 0xdc, 0xc1, 0x69, 0xfa, 0x6f, 0xf9, 0xd6, 0x55, 0x57, 0xbd, 0x7e, 0x73, 0x7f, 0xff, 0xcd, 0xaf, 0x5f, 0x75, 0xd5, 0xb7, 0x6e, 0xe9, 0x3f, 0x77, 0xfc, 0xf5, 0xd3, 0xa7, 0xcf, 0x9c, 0x39, 0x7d, 0xfa, 0x75, 0xd0, 0xb3, 0xdd, 0xe7, 0xbf, 0xca, 0x75, 0x70, 0x4b, 0x11, 0x3c, 0x04, 0x25, 0x48, 0xdd, 0xd3, 0x0a, 0x8c, 0x39, 0x1b, 0x91, 0xab, 0xa1, 0x02, 0xa5, 0xee, 0xa9, 0x96, 0xd6, 0x3d, 0xbd, 0xa0, 0xaa, 0xe9, 0xee, 0x4b, 0xd6, 0x3d, 0xcd, 0xb4, 0xa0, 0xa7, 0x8d, 0xb4, 0xa1, 0x58, 0xa8, 0x22, 0x16, 0xa0, 0x05, 0x37, 0xe4, 0xfa, 0x27, 0xb5, 0x95, 0x58, 0x5e, 0x42, 0x76, 0x57, 0xc6, 0xf1, 0xa2, 0x15, 0x4f, 0x33, 0x5e, 0x56, 0x3d, 0x15, 0x55, 0xf7,\n\t0x74, 0x4d, 0xf6, 0xed, 0x19, 0x8a, 0x56, 0x0e, 0x77, 0x6d, 0xed, 0x9f, 0x59, 0x1c, 0xad, 0x65, 0x36, 0xb4, 0x77, 0x92, 0xc9, 0x7e, 0x62, 0x4f, 0xb5, 0xb3, 0xb3, 0xa8, 0xef, 0x9e, 0xce, 0x5e, 0x32, 0xe5, 0xcf, 0xec, 0x95, 0x6c, 0xe1, 0xe0, 0xc6, 0xd3, 0x65, 0x89, 0x8d, 0xb7, 0xad, 0xb9, 0x63, 0x6c, 0xa2, 0xa6, 0x16, 0x3e, 0xef, 0x9b, 0x60, 0x76, 0x77, 0x7d, 0xf3, 0x20, 0xc1, 0x80, 0xb4, 0xa8, 0xd8, 0xfd, 0xed, 0xee, 0xd7, 0x0f, 0x13, 0x2c, 0x74, 0xaf, 0x2e, 0x04, 0xf4, 0xa3, 0xa5, 0xe7, 0x3f, 0x10, 0x6e, 0x02, 0x7a, 0xe9, 0x90, 0x13, 0xf5, 0xa2, 0x5f, 0x0d, 0x9e, 0xae, 0x22, 0x71, 0xb3, 0x16, 0xd0, 0x25, 0x65, 0x21, 0x86, 0xa1, 0x25, 0x6a, 0xc8, 0x2f, 0x56, 0xf9, 0xa5, 0x24, 0x0f, 0x97, 0x21, 0x5e, 0xc7, 0xe8, 0x78, 0x66, 0x46, 0x8f, 0xb1, 0x11, 0xeb, 0x78, 0xac,\n\t0x9b, 0x24, 0x9b, 0x40, 0xf2, 0xf1, 0x8d, 0xdd, 0x83, 0x9c, 0x81, 0x61, 0x98, 0xec, 0xc2, 0x34, 0x55, 0x1f, 0xab, 0x0f, 0xad, 0x47, 0x93, 0xbc, 0xb0, 0x39, 0xca, 0xb4, 0x4e, 0x9f, 0x15, 0x99, 0xdb, 0x91, 0x94, 0xa1, 0x71, 0xb9, 0x0c, 0x7a, 0x84, 0x5c, 0xbd, 0xae, 0x1e, 0xa9, 0xad, 0xa9, 0xa1, 0xaa, 0xa2, 0x24, 0x56, 0x5c, 0xe4, 0xf7, 0xe6, 0x59, 0xf4, 0x4e, 0x83, 0x13, 0x26, 0xaa, 0x0b, 0x99, 0xd2, 0x67, 0x8a, 0x48, 0x95, 0xc9, 0x2c, 0x2e, 0xc2, 0x59, 0x07, 0x89, 0xe4, 0x32, 0x34, 0x39, 0x87, 0x00, 0x33, 0x75, 0x67, 0xf8, 0x7f, 0x2b, 0x68, 0x5c, 0x21, 0xd7, 0x9a, 0x49, 0xd5, 0xde, 0x78, 0xfd, 0xf5, 0x37, 0xde, 0x74, 0xe2, 0x04, 0x33, 0x42, 0xab, 0xce, 0xb4, 0xac, 0x92, 0xca, 0x6d, 0x2e, 0x63, 0x03, 0x2d, 0x3a, 0x73, 0xe0, 0x9b, 0x8d, 0xc9, 0x33, 0x37, 0x4e, 0x3d,\n\t0x76, 0x65, 0x67, 0xe7, 0x55, 0x5f, 0xda, 0x72, 0xfc, 0x1b, 0xc9, 0xda, 0x97, 0x4f, 0x2c, 0xbf, 0x63, 0x5b, 0x4b, 0x9e, 0x97, 0x19, 0x55, 0x0b, 0xcb, 0xa4, 0xaa, 0x55, 0x7e, 0xc4, 0xab, 0x48, 0x8d, 0x19, 0x7a, 0xa0, 0x88, 0x9c, 0x14, 0xdb, 0xb3, 0x7f, 0xd7, 0x15, 0x2a, 0xd3, 0xee, 0xdf, 0xbe, 0xf9, 0x2a, 0xa5, 0xa8, 0x0c, 0xb5, 0xa9, 0x6f, 0x49, 0x3d, 0xc9, 0xd9, 0x38, 0x3d, 0xf8, 0x43, 0x51, 0x74, 0x5c, 0xd2, 0x9b, 0xc8, 0x4b, 0x4c, 0x02, 0xb4, 0xa2, 0x8c, 0x5a, 0x41, 0x86, 0x1c, 0x0d, 0x25, 0x8b, 0x6a, 0x77, 0x76, 0xad, 0x4e, 0x8e, 0xdb, 0x9a, 0xce, 0x34, 0x9e, 0xaf, 0xc9, 0x1e, 0xb5, 0x09, 0xad, 0x20, 0x33, 0x3d, 0xb7, 0xbe, 0x4c, 0x56, 0x0b, 0x52, 0x41, 0x26, 0x60, 0x8b, 0x45, 0x23, 0x39, 0x15, 0x64, 0xe4, 0x73, 0x5a, 0xd1, 0xf4, 0xeb, 0x85, 0xa8, 0xd4, 0x51,\n\t0x84, 0xcc, 0x50, 0xe6, 0x1c, 0xe9, 0x35, 0x75, 0xba, 0xa2, 0xfe, 0x15, 0xeb, 0x93, 0xab, 0x6f, 0x9f, 0xaa, 0x6f, 0xdd, 0xfb, 0xf0, 0xf4, 0xd8, 0xf1, 0x04, 0x91, 0x31, 0x7f, 0x4d, 0x1f, 0x24, 0xed, 0xb9, 0x21, 0xd2, 0x5e, 0xee, 0xee, 0x3a, 0xf1, 0xfa, 0xd1, 0xbd, 0xdf, 0x3a, 0x35, 0xd2, 0x92, 0x4c, 0xf5, 0xf2, 0x8b, 0xa3, 0xe9, 0x79, 0xd3, 0xf3, 0xa2, 0x41, 0x34, 0x29, 0x19, 0xcc, 0xa6, 0x4c, 0x29, 0x9d, 0xf4, 0x4a, 0xbd, 0xb0, 0x2e, 0x4e, 0xf6, 0xe4, 0x17, 0x6c, 0x91, 0x9e, 0x99, 0xa4, 0xb5, 0xda, 0x62, 0xe1, 0xf9, 0x26, 0x96, 0x53, 0x1b, 0x47, 0x9e, 0x58, 0xee, 0xb4, 0xda, 0x3f, 0xbf, 0x55, 0x9d, 0xd3, 0xc4, 0x75, 0x89, 0x33, 0x67, 0xb2, 0x66, 0x74, 0x67, 0xef, 0xaa, 0x45, 0xc7, 0xe5, 0xf9, 0x74, 0xb5, 0xa4, 0x1a, 0x45, 0x37, 0x92, 0xe3, 0x13, 0x4f, 0xb2, 0x3f,\n\t0x52, 0xe8, 0xf8, 0x90, 0x52, 0x21, 0x8a, 0x1c, 0xfc, 0xcd, 0x53, 0x0e, 0xc1, 0x7a, 0xe9, 0x4f, 0x5e, 0xfd, 0xa9, 0xac, 0x3f, 0x1f, 0x3d, 0x50, 0x47, 0xeb, 0x5c, 0xe7, 0xd4, 0xd7, 0x52, 0x4f, 0xf0, 0x79, 0x16, 0x6a, 0xb3, 0x27, 0x5d, 0xae, 0x95, 0x1e, 0x16, 0x9e, 0xce, 0x3d, 0x4b, 0x9c, 0xd3, 0x64, 0x54, 0x3e, 0x2d, 0x1c, 0x35, 0x47, 0x62, 0x41, 0xfb, 0x02, 0xa7, 0x85, 0xad, 0xd9, 0xeb, 0xa3, 0x80, 0x91, 0x23, 0x11, 0xe5, 0xfb, 0xbb, 0x32, 0xc7, 0x85, 0xcf, 0xb6, 0x3f, 0xb4, 0x4d, 0x3d, 0x1b, 0x5b, 0xbd, 0xac, 0xa7, 0xd9, 0x63, 0xd4, 0xc5, 0x59, 0xa6, 0xb5, 0x56, 0x3d, 0x30, 0xcc, 0xfc, 0xeb, 0x5f, 0x9f, 0xc3, 0x3f, 0xef, 0x5b, 0xad, 0x1e, 0x18, 0xce, 0x2b, 0xae, 0x2a, 0xec, 0xcf, 0xc4, 0x19, 0x98, 0x7f, 0x02, 0xdc, 0xe4, 0xa3, 0x4f, 0xc8, 0x53, 0xd2, 0x09, 0x20,\n\t0x97, 0xac, 0xe0, 0x3f, 0x32, 0x03, 0x4a, 0x11, 0x64, 0x72, 0x85, 0x53, 0xae, 0x90, 0x1f, 0x8c, 0xf2, 0x63, 0x54, 0x09, 0xdd, 0xe4, 0xc9, 0x25, 0xc2, 0x65, 0x15, 0x83, 0x64, 0xe3, 0x47, 0xee, 0x29, 0xdb, 0x0c, 0xe9, 0x0a, 0xe2, 0xe9, 0xbb, 0x92, 0x3f, 0x9d, 0x6f, 0x9b, 0x6b, 0x54, 0xc8, 0xf7, 0x47, 0xc1, 0xa8, 0x70, 0x14, 0xdb, 0x33, 0x11, 0x0d, 0xa7, 0x4b, 0x14, 0x80, 0x17, 0xa8, 0x28, 0x51, 0xeb, 0x86, 0x77, 0x54, 0x9f, 0xdc, 0x18, 0x68, 0x76, 0x1a, 0x45, 0x8f, 0xa9, 0xa1, 0xa8, 0xb2, 0xaf, 0xb1, 0xcc, 0x76, 0x66, 0xa6, 0xc8, 0xc5, 0xb3, 0x75, 0x53, 0xfb, 0xcc, 0xe6, 0x7b, 0xbc, 0x7a, 0x6f, 0xdd, 0xe2, 0xea, 0xd9, 0x13, 0xec, 0x87, 0x2e, 0x3f, 0x9d, 0x67, 0xdb, 0xf9, 0xf7, 0x59, 0x2f, 0xc8, 0xe0, 0x56, 0x52, 0xdf, 0xb5, 0x15, 0x63, 0xbe, 0x00, 0xe6, 0xb1, 0x60,\n\t0x7d, 0xd7, 0xdd, 0xd9, 0xf5, 0x5d, 0x9b, 0x1b, 0x63, 0x91, 0x60, 0xe0, 0xa2, 0xf5, 0x5d, 0x23, 0x0b, 0x55, 0x18, 0x65, 0x7e, 0xaa, 0xc9, 0x33, 0x59, 0xa2, 0xf5, 0x03, 0x89, 0x92, 0xee, 0x2a, 0x4f, 0x79, 0xff, 0xc4, 0xc6, 0x89, 0xfe, 0xf2, 0xc4, 0xe4, 0xdd, 0xeb, 0xb6, 0x3d, 0xdb, 0x52, 0xa1, 0xc9, 0xb7, 0xdb, 0x62, 0x0d, 0x4b, 0x5b, 0x6a, 0x06, 0xaa, 0xf3, 0xcb, 0xfb, 0xd7, 0x6d, 0x5a, 0xd7, 0x5f, 0x5e, 0x3d, 0x71, 0xcb, 0x9a, 0xcd, 0x0f, 0x37, 0xb1, 0xfd, 0x46, 0xbd, 0xd3, 0xe3, 0x74, 0x84, 0x13, 0xfe, 0x48, 0x4d, 0xc8, 0x5f, 0x14, 0x6f, 0x5d, 0xd5, 0xd6, 0x7b, 0x68, 0x4d, 0x4d, 0x8f, 0x1c, 0x38, 0xf2, 0xba, 0x4b, 0x1b, 0x0a, 0x63, 0x75, 0x11, 0x5f, 0x51, 0x89, 0x34, 0xde, 0xd9, 0xbc, 0x73, 0x59, 0xb5, 0xd4, 0x40, 0xe6, 0x98, 0xba, 0x9f, 0xce, 0x71, 0x0d, 0x7a,\n\t0x42, 0xf6, 0xfd, 0xad, 0x6b, 0x30, 0x16, 0x1b, 0x93, 0x75, 0x3e, 0x8e, 0x15, 0x48, 0x55, 0x57, 0xb2, 0xa5, 0x3c, 0xe7, 0x1a, 0x97, 0x55, 0x15, 0x09, 0x61, 0x1e, 0x96, 0xc1, 0x0c, 0xe2, 0x49, 0x81, 0xa3, 0xdd, 0x48, 0x60, 0xb1, 0xc0, 0xee, 0xce, 0x04, 0x41, 0x69, 0x41, 0xd7, 0x71, 0x35, 0x08, 0x57, 0xb3, 0x40, 0xf3, 0x34, 0x22, 0xd5, 0xd0, 0x29, 0x20, 0x72, 0x5c, 0x8d, 0xc4, 0x59, 0xe5, 0x62, 0xae, 0x6a, 0x29, 0x57, 0xcd, 0xdf, 0xaf, 0x94, 0xeb, 0xbc, 0x88, 0x2e, 0x5d, 0x7e, 0x78, 0x78, 0x81, 0xb7, 0xf9, 0xac, 0xfd, 0x44, 0xdd, 0xc7, 0xc4, 0x7f, 0xc7, 0xcc, 0xaa, 0x06, 0x4d, 0xd3, 0x7c, 0x6f, 0xf6, 0xd1, 0x74, 0x56, 0x2d, 0x4c, 0x16, 0x99, 0xf7, 0x84, 0x6a, 0xc1, 0x87, 0x0e, 0xe3, 0x56, 0xc9, 0xdc, 0x82, 0x45, 0x7e, 0x33, 0x60, 0x67, 0x14, 0x4c, 0x1f, 0x1a, 0x64,\n\t0xd0, 0xd3, 0x2d, 0x5e, 0xa4, 0x61, 0x35, 0x32, 0x1f, 0x6a, 0x08, 0xfa, 0x04, 0x64, 0xe0, 0x05, 0xc3, 0x64, 0x86, 0x1f, 0xf5, 0x58, 0x79, 0xd1, 0xdc, 0xf4, 0x20, 0x79, 0x11, 0x0f, 0x33, 0xa6, 0xc3, 0xb2, 0x51, 0x34, 0x78, 0xda, 0x4a, 0x0b, 0xa8, 0xcc, 0x61, 0x64, 0x65, 0x00, 0x1a, 0x89, 0x50, 0x87, 0x20, 0xdf, 0x17, 0x18, 0x23, 0xff, 0x7f, 0x07, 0x84, 0xb4, 0x28, 0xd3, 0x57, 0xab, 0x61, 0xb5, 0x17, 0xef, 0x8b, 0xb4, 0x5a, 0xa5, 0xab, 0xbc, 0xcc, 0x94, 0x51, 0xc8, 0x56, 0xb1, 0x77, 0xef, 0x9e, 0x8d, 0x1b, 0x26, 0xc6, 0x48, 0x8e, 0x1c, 0x39, 0x97, 0x96, 0x59, 0x7a, 0xc6, 0x8f, 0xb9, 0xf4, 0x16, 0x2c, 0xbf, 0x72, 0xa9, 0x32, 0x1a, 0x7f, 0xcb, 0x8a, 0xad, 0xaf, 0x2f, 0xab, 0x58, 0x7f, 0xc7, 0xa6, 0xf5, 0xb7, 0xae, 0x2d, 0x5b, 0xb0, 0x78, 0x86, 0xc5, 0xa8, 0xf1, 0x34,\n\t0xae, 0x69, 0xeb, 0xdb, 0xd9, 0x17, 0xec, 0x68, 0xd3, 0x5a, 0x35, 0x1f, 0x7b, 0x89, 0xeb, 0x57, 0x6d, 0xec, 0x3f, 0x3e, 0xd9, 0xd4, 0x38, 0x71, 0x55, 0xdb, 0xfc, 0x05, 0x33, 0xfc, 0x1d, 0x9d, 0x8b, 0x0a, 0x2a, 0x46, 0x5a, 0x8a, 0xcb, 0x86, 0xa6, 0x1a, 0x7a, 0x6f, 0x6a, 0x12, 0x4d, 0x1a, 0x59, 0xc6, 0x83, 0x5c, 0xa0, 0xfc, 0x77, 0x1f, 0xfe, 0xb4, 0x4c, 0x69, 0xf7, 0x6a, 0xac, 0x15, 0xaf, 0xc3, 0x58, 0x7b, 0xa0, 0x31, 0xc9, 0x1a, 0x68, 0x7d, 0x67, 0x43, 0x94, 0x16, 0x84, 0xf2, 0x2e, 0x74, 0x8f, 0xa3, 0xc5, 0xa2, 0xf4, 0xf4, 0x38, 0x23, 0xd2, 0xf1, 0x3a, 0x79, 0xe1, 0xeb, 0xc8, 0xc2, 0xd7, 0x20, 0x93, 0xa8, 0x31, 0x65, 0xed, 0x96, 0x80, 0x29, 0xa9, 0xd3, 0x8e, 0xd2, 0x02, 0x4b, 0x7a, 0xb0, 0x18, 0x69, 0x96, 0xe4, 0xce, 0x5c, 0xf1, 0x21, 0x73, 0x6d, 0xcf, 0x5c, 0x19,\n\t0xa2, 0x0c, 0x65, 0xd4, 0x31, 0x99, 0xc1, 0xc8, 0xf7, 0x4b, 0x8e, 0x96, 0xff, 0xf7, 0x02, 0x4c, 0x1a, 0xc9, 0x8c, 0xa2, 0xd7, 0xf1, 0x7a, 0xe0, 0x64, 0xbd, 0x41, 0x2f, 0x18, 0x80, 0xb1, 0x0d, 0x9c, 0x81, 0xec, 0x4f, 0x5c, 0x6c, 0x54, 0xa4, 0xd7, 0x2b, 0x83, 0x66, 0x8b, 0x3d, 0x52, 0xd0, 0xff, 0xb6, 0x93, 0x47, 0x0e, 0x5f, 0x75, 0xe5, 0xce, 0xed, 0x5b, 0xa6, 0x37, 0x4f, 0xad, 0x9f, 0xc8, 0x15, 0x83, 0xe6, 0xbf, 0x97, 0x18, 0xfc, 0xfb, 0x32, 0xfd, 0xdf, 0x26, 0x3d, 0xff, 0x5e, 0x6b, 0xa1, 0x63, 0x66, 0x75, 0xfd, 0xbc, 0xe2, 0xf6, 0x1a, 0x4d, 0x47, 0xd5, 0xdf, 0x73, 0x89, 0x60, 0x74, 0xf3, 0xf9, 0xf7, 0xb9, 0x55, 0xfc, 0x73, 0x68, 0x00, 0x5d, 0x45, 0x03, 0x0a, 0xcf, 0x7b, 0x31, 0x79, 0x5d, 0x8c, 0x17, 0x3e, 0x79, 0x16, 0xab, 0x51, 0x86, 0x42, 0x04, 0xf2, 0x9a, 0x63,\n\t0xa8, 0xcd, 0x22, 0x47, 0x1b, 0x76, 0xc8, 0x51, 0x01, 0x5e, 0xdd, 0x42, 0x0f, 0xce, 0xd7, 0x22, 0x3b, 0x78, 0x40, 0x77, 0xcd, 0x6d, 0x18, 0x75, 0x77, 0xb5, 0xb7, 0x86, 0x83, 0x45, 0x05, 0x6e, 0x17, 0x1a, 0xc0, 0x03, 0x62, 0xc6, 0xed, 0xe6, 0x80, 0xf6, 0xdc, 0xc2, 0x72, 0x8d, 0x4b, 0x93, 0x8d, 0xc4, 0x58, 0xda, 0x18, 0xe6, 0xaa, 0xed, 0xf7, 0x4f, 0x56, 0x95, 0xb4, 0xf7, 0xb7, 0x97, 0xd4, 0x0e, 0x8f, 0x0d, 0xd7, 0x36, 0x4d, 0xdf, 0x32, 0xbc, 0xe1, 0xf3, 0x2d, 0xe5, 0xda, 0x7c, 0x9b, 0x2d, 0x5e, 0xd7, 0x9f, 0x88, 0x75, 0x56, 0xb8, 0x8b, 0xea, 0x16, 0xf5, 0x2e, 0xaa, 0x2b, 0x2a, 0xeb, 0x5c, 0xd2, 0x59, 0xe6, 0x4e, 0xae, 0x6e, 0x5d, 0xb4, 0x73, 0x28, 0x7e, 0xb6, 0xe7, 0xf8, 0x8b, 0xfc, 0x73, 0x6d, 0xeb, 0xf7, 0x26, 0x9a, 0x57, 0x76, 0xd4, 0x54, 0x54, 0x17, 0x46, 0x12,\n\t0xe5, 0x55, 0xbd, 0x5b, 0x17, 0x2f, 0x3d, 0xb2, 0xaa, 0x3c, 0x2d, 0x7f, 0xca, 0x5a, 0x82, 0xb1, 0xa6, 0xb2, 0xe2, 0x60, 0xac, 0xae, 0xaf, 0xa6, 0x7e, 0xb8, 0xbd, 0xae, 0xa9, 0xbb, 0xb2, 0xa8, 0xbd, 0xa6, 0xb0, 0x64, 0xd9, 0x35, 0xcb, 0xce, 0xc5, 0xd9, 0x1f, 0x6f, 0x7b, 0xfa, 0x48, 0x97, 0x9c, 0xd3, 0xc2, 0x3c, 0x0b, 0xb8, 0xf3, 0x92, 0x77, 0xfd, 0x68, 0x44, 0x06, 0x23, 0x07, 0x2d, 0x3a, 0xa9, 0x46, 0x4a, 0x29, 0x8e, 0xa6, 0x95, 0x3a, 0xe3, 0x4e, 0x47, 0x1d, 0x7d, 0xf9, 0x8a, 0x4d, 0xdd, 0x8b, 0x66, 0xd2, 0xd1, 0x2d, 0x79, 0xd7, 0xfa, 0xfb, 0x64, 0xb7, 0xb9, 0xab, 0x45, 0x24, 0x7b, 0xcb, 0x79, 0xe5, 0x7d, 0x35, 0x1e, 0x9a, 0x01, 0xc0, 0x75, 0xd1, 0xad, 0xe2, 0x69, 0xbd, 0x96, 0xc3, 0xf9, 0xc9, 0xd5, 0xed, 0x1f, 0xbd, 0xae, 0x6c, 0x29, 0xc3, 0xf3, 0xe3, 0xe7, 0xdf,\n\t0x67, 0x5e, 0xe7, 0x5b, 0x51, 0x31, 0x6a, 0x91, 0x1a, 0xb5, 0x40, 0xb7, 0x22, 0x90, 0x27, 0xe4, 0x18, 0x06, 0xcb, 0xec, 0x23, 0x5b, 0x2e, 0xb4, 0xf2, 0xf1, 0x34, 0x3d, 0x8c, 0x31, 0x2e, 0xc8, 0x35, 0xbf, 0xc8, 0x3b, 0x06, 0xe8, 0x29, 0x2e, 0x52, 0x14, 0xba, 0x18, 0x17, 0x13, 0xfc, 0xf3, 0x99, 0xc5, 0xb1, 0xc0, 0xbe, 0x38, 0xfe, 0xf6, 0xe1, 0x1b, 0xae, 0xb4, 0xba, 0x1e, 0x25, 0x7b, 0xdd, 0x93, 0x84, 0xb3, 0x9b, 0x95, 0xbd, 0x6e, 0x3d, 0x70, 0xf6, 0x09, 0x8b, 0xc2, 0x61, 0x2e, 0x5c, 0x79, 0xc1, 0x2e, 0x36, 0xcd, 0x6b, 0x8e, 0x82, 0xfd, 0x59, 0xcb, 0xbf, 0x81, 0x22, 0xe8, 0x48, 0x4a, 0x7e, 0x4f, 0x51, 0xb9, 0x5c, 0xa3, 0x1d, 0xe0, 0xff, 0x07, 0x80, 0xbf, 0x04, 0x49, 0x52, 0xab, 0x08, 0xf0, 0x16, 0xd3, 0x83, 0xc5, 0x14, 0x7e, 0x10, 0x8d, 0x5a, 0x2c, 0x88, 0x48, 0xd8,\n\t0x98, 0x3d, 0x13, 0x51, 0xd4, 0x8c, 0x23, 0x8d, 0x66, 0xa7, 0x66, 0xa8, 0x24, 0x5e, 0x12, 0x24, 0x7b, 0x59, 0x31, 0x2b, 0x2d, 0xee, 0x6b, 0x4b, 0xd4, 0xcd, 0x99, 0x81, 0x63, 0x01, 0x21, 0xd0, 0x7e, 0x6b, 0xce, 0x4c, 0x70, 0x28, 0xf5, 0xa3, 0x9c, 0xd9, 0xc0, 0x3a, 0xbd, 0x95, 0x79, 0xfe, 0xd1, 0xac, 0xf9, 0x3c, 0x7a, 0x24, 0xf5, 0x83, 0xec, 0xe5, 0x84, 0xdb, 0x65, 0xdc, 0xf3, 0x2b, 0x72, 0x72, 0x54, 0x4a, 0x31, 0x27, 0x78, 0x81, 0x00, 0x66, 0x0c, 0xc6, 0xfd, 0x40, 0x19, 0xe6, 0x68, 0x8e, 0x4a, 0xe6, 0xaa, 0x4e, 0xbd, 0x9a, 0xce, 0x51, 0xe1, 0x04, 0x51, 0xa0, 0xa5, 0x35, 0x45, 0xba, 0x87, 0xbb, 0x63, 0x50, 0x4b, 0xd2, 0x76, 0xf8, 0x51, 0x0d, 0x56, 0x5d, 0xe3, 0x71, 0x9a, 0x86, 0x42, 0xad, 0x8c, 0xaa, 0x4b, 0x34, 0xd7, 0xcb, 0x45, 0xfc, 0x48, 0x27, 0xf5, 0x45, 0x38,\n\t0xe9, 0x1c, 0x15, 0x47, 0x5d, 0xd8, 0x1a, 0x23, 0xa5, 0xb5, 0x0c, 0x4a, 0x16, 0xf0, 0x42, 0xc2, 0x51, 0xc1, 0xde, 0x7c, 0x47, 0xa1, 0xd9, 0x99, 0x94, 0x67, 0x2e, 0xa2, 0x32, 0x98, 0xfc, 0xf9, 0x7c, 0xc7, 0xa1, 0x2f, 0x4c, 0x52, 0xc9, 0x60, 0x75, 0xfe, 0x02, 0x22, 0x0c, 0x8a, 0xa5, 0x9e, 0xe0, 0xbe, 0x48, 0xf7, 0xa5, 0x96, 0xa1, 0x0f, 0x25, 0x73, 0x23, 0x3d, 0x88, 0xc5, 0x02, 0x57, 0x77, 0x66, 0xb6, 0xf5, 0xea, 0xc8, 0x19, 0x04, 0xac, 0x41, 0x33, 0x86, 0xcc, 0x96, 0x1d, 0x39, 0xcc, 0xa6, 0x2a, 0x22, 0x9e, 0x67, 0x81, 0xdf, 0xc9, 0xf6, 0x1d, 0x41, 0x4a, 0x56, 0xe1, 0x99, 0x02, 0x6a, 0x2d, 0x2a, 0x9d, 0x91, 0x9e, 0xd5, 0xb1, 0x7a, 0xdd, 0xa5, 0x07, 0x41, 0x59, 0x63, 0x48, 0x52, 0xa6, 0xbb, 0xa0, 0x13, 0x16, 0xee, 0xae, 0x6c, 0x1e, 0x0a, 0xe3, 0x40, 0xa9, 0x9d, 0xd9,\n\t0x43, 0x10, 0x85, 0x88, 0x11, 0x18, 0x79, 0x03, 0x1d, 0x52, 0x7b, 0x6b, 0x5d, 0x6d, 0x75, 0x25, 0x48, 0xc3, 0xac, 0x1d, 0x45, 0x23, 0x91, 0x88, 0x17, 0xd9, 0x51, 0xbc, 0x24, 0xf1, 0x72, 0x77, 0x1c, 0xd9, 0x5f, 0x66, 0x36, 0x81, 0xc8, 0x96, 0x63, 0x35, 0xdd, 0x72, 0x9c, 0x5e, 0xdc, 0xd6, 0x90, 0x62, 0xe6, 0xd1, 0x4f, 0x8f, 0x95, 0x91, 0xfc, 0x22, 0xe6, 0x75, 0x75, 0x3b, 0xd2, 0x67, 0xbf, 0xd4, 0x76, 0xe4, 0x45, 0x68, 0x9c, 0x93, 0x3f, 0x2f, 0xaf, 0x19, 0x6e, 0x08, 0xd6, 0x7b, 0x08, 0x6d, 0x90, 0x74, 0x3e, 0x8c, 0x05, 0x0b, 0x7d, 0xf3, 0x96, 0x1a, 0xc8, 0xe6, 0x05, 0x9e, 0x8a, 0x2d, 0xfa, 0x7a, 0x06, 0xd9, 0x33, 0x1e, 0x67, 0xe5, 0x72, 0xf5, 0x5e, 0xa9, 0xe8, 0x82, 0xdb, 0x70, 0x83, 0xb4, 0x61, 0xc7, 0x95, 0x77, 0xc0, 0x48, 0x3a, 0x99, 0xc7, 0x2d, 0x24, 0x30, 0x1d,\n\t0xb8, 0x0c, 0x44, 0x71, 0x43, 0x67, 0x53, 0xcc, 0x3c, 0x2c, 0xfd, 0x58, 0x29, 0x61, 0x69, 0xe6, 0xf5, 0x8b, 0x4d, 0x8d, 0xca, 0x2f, 0x22, 0x03, 0x86, 0x61, 0x3e, 0x6d, 0x68, 0x48, 0xea, 0x27, 0xf2, 0xb7, 0x25, 0xca, 0x20, 0x10, 0x60, 0x1c, 0xd1, 0x02, 0xfb, 0xb4, 0xe4, 0xbd, 0x6f, 0xec, 0x28, 0x4f, 0x4f, 0xd1, 0xea, 0x48, 0x8d, 0x82, 0x71, 0x8d, 0x9e, 0x51, 0xa4, 0x70, 0x6d, 0x4d, 0x65, 0x45, 0x69, 0xbc, 0xd0, 0x2f, 0xbf, 0x8e, 0x47, 0x91, 0xc7, 0x6d, 0xb8, 0xcd, 0x30, 0xaf, 0x3c, 0xbe, 0x78, 0xba, 0xd2, 0x45, 0x44, 0xf5, 0x0f, 0x95, 0x74, 0xb1, 0x0b, 0x6d, 0x91, 0x54, 0xfd, 0xc5, 0x64, 0xf8, 0x02, 0xf9, 0x48, 0x39, 0x92, 0x9d, 0xce, 0x5f, 0xfc, 0x29, 0xc8, 0xc0, 0xd5, 0xe8, 0x0b, 0x92, 0x7d, 0x35, 0xd6, 0x9b, 0x25, 0x10, 0x7d, 0xb5, 0x85, 0x60, 0x4b, 0xb3, 0xa0,\n\t0x03, 0xf5, 0x64, 0xb9, 0x12, 0xca, 0x56, 0x19, 0xe1, 0x16, 0x32, 0xeb, 0x11, 0xc9, 0x6f, 0x31, 0x8f, 0x21, 0xb3, 0x79, 0xc7, 0xa0, 0x4e, 0x24, 0xef, 0x7d, 0xc3, 0xa3, 0x26, 0x03, 0xdd, 0x4b, 0x23, 0x22, 0x8c, 0x1d, 0x07, 0x8c, 0x29, 0x31, 0x92, 0xda, 0x4b, 0x77, 0xa1, 0x2b, 0x8c, 0xf4, 0x13, 0xc6, 0xb5, 0x72, 0x1c, 0x78, 0x54, 0xf2, 0xac, 0x5a, 0x31, 0xbc, 0x64, 0xf1, 0x60, 0x5f, 0x6f, 0x4f, 0x57, 0x4b, 0x73, 0x43, 0x32, 0x68, 0xa3, 0x3a, 0xc2, 0x91, 0xb0, 0xc8, 0xe5, 0xdf, 0x73, 0x13, 0x65, 0x2f, 0x89, 0xca, 0xe0, 0x42, 0x74, 0x50, 0xc5, 0xe3, 0x8f, 0x72, 0x2a, 0x23, 0x9d, 0x4d, 0x79, 0x2e, 0x81, 0xe4, 0x6c, 0xf6, 0x52, 0x49, 0xf3, 0x73, 0x39, 0xc5, 0x8f, 0x6f, 0xcd, 0x96, 0x84, 0x17, 0x72, 0xde, 0xc2, 0x9c, 0x28, 0x93, 0x4a, 0x16, 0xa7, 0xb2, 0xfc, 0x14, 0x03,\n\t0x54, 0x7e, 0xee, 0xc6, 0x79, 0x92, 0x65, 0x09, 0xe6, 0x0c, 0x9d, 0xe5, 0x24, 0xa3, 0x6b, 0x60, 0x5d, 0x46, 0x80, 0x36, 0x01, 0x7a, 0x41, 0x8a, 0x01, 0x7a, 0xad, 0x19, 0xe9, 0x45, 0xcf, 0x91, 0x18, 0x46, 0xc9, 0x61, 0x9f, 0x5c, 0x82, 0x0c, 0x5a, 0xb0, 0xd9, 0x3c, 0x47, 0x8a, 0x76, 0xa4, 0x47, 0x40, 0x16, 0xd6, 0xcc, 0x5a, 0xcc, 0x97, 0x37, 0x12, 0xca, 0x1a, 0x48, 0xea, 0xce, 0x1a, 0x43, 0x30, 0x0b, 0x17, 0x19, 0x63, 0x2e, 0xad, 0xb3, 0xc7, 0x01, 0x79, 0x1a, 0xc7, 0x68, 0xd7, 0x8e, 0xad, 0xd3, 0x13, 0xe3, 0x63, 0xa3, 0xa4, 0x64, 0xed, 0x40, 0x7f, 0x4f, 0x57, 0x53, 0xc3, 0x85, 0x92, 0x35, 0xef, 0x6f, 0x90, 0xac, 0x97, 0xcb, 0x12, 0xb9, 0x42, 0x57, 0xd8, 0x38, 0x27, 0xcf, 0xe3, 0x51, 0x25, 0xcf, 0xa3, 0x31, 0xe5, 0xbc, 0x20, 0x4d, 0xb0, 0x7e, 0x41, 0x31, 0x8c, 0x7f,\n\t0x48, 0x93, 0x0b, 0x99, 0xa7, 0xcd, 0x97, 0x9d, 0x1c, 0xf2, 0xb1, 0x19, 0x67, 0x1e, 0x19, 0x2d, 0x10, 0x9b, 0x4c, 0x42, 0xfb, 0x25, 0x7d, 0x35, 0x78, 0x9f, 0x61, 0x0b, 0x93, 0x11, 0xd2, 0x01, 0x1d, 0xd6, 0x68, 0x35, 0xfb, 0x68, 0xd1, 0x51, 0xed, 0x28, 0xc9, 0x35, 0x9e, 0xa6, 0x1b, 0x6b, 0x60, 0x5f, 0x12, 0x5b, 0x84, 0x4a, 0xea, 0xf0, 0x3c, 0x6d, 0xa8, 0xb0, 0x26, 0x0d, 0x65, 0x9d, 0x4a, 0xc5, 0x75, 0x9e, 0xd4, 0xde, 0xd6, 0xd2, 0xd8, 0x40, 0x64, 0x36, 0x15, 0xdb, 0xd4, 0x36, 0xf9, 0xdf, 0x51, 0x41, 0xf8, 0x87, 0xb3, 0x80, 0xe0, 0x8f, 0xbd, 0x08, 0x99, 0x67, 0x3e, 0x3e, 0xde, 0x88, 0xfc, 0x3f, 0x0a, 0x76, 0xed, 0x3b, 0xec, 0x87, 0xc8, 0x8d, 0x16, 0xbf, 0x90, 0xcf, 0x93, 0xa0, 0xae, 0x82, 0x26, 0x1b, 0xcf, 0x31, 0x34, 0x65, 0x82, 0x6c, 0x3f, 0x62, 0x55, 0x85, 0xb9,\n\t0xd4, 0xab, 0x54, 0x73, 0x65, 0xbb, 0x45, 0xe4, 0x75, 0xad, 0x6e, 0xe4, 0x0e, 0x3a, 0x22, 0x01, 0xe5, 0x3d, 0x9c, 0xc5, 0x95, 0x73, 0x12, 0x5c, 0x92, 0xf5, 0x56, 0xf6, 0x9d, 0x2b, 0x62, 0x06, 0x53, 0xa0, 0x6f, 0xd9, 0x78, 0x7a, 0x43, 0xf9, 0x78, 0x23, 0x49, 0xe8, 0x89, 0x4e, 0xab, 0x5b, 0xa7, 0x24, 0x0d, 0x65, 0xd7, 0xa1, 0xde, 0x36, 0xe6, 0x97, 0x14, 0x3e, 0xb0, 0xa5, 0x3a, 0x01, 0xbe, 0x6a, 0xb4, 0x59, 0x32, 0x14, 0x1a, 0x00, 0xc0, 0x62, 0x2d, 0x29, 0x6c, 0xaf, 0x1c, 0x16, 0xf4, 0x71, 0x58, 0x01, 0x52, 0x86, 0x44, 0x7e, 0x69, 0xf4, 0xb8, 0xfa, 0xea, 0xda, 0x20, 0xa9, 0xf5, 0x8e, 0x05, 0x7e, 0x66, 0x6e, 0x33, 0x94, 0x69, 0x05, 0x4a, 0x37, 0x18, 0xb3, 0x05, 0x1d, 0x65, 0xc5, 0x74, 0x37, 0x78, 0x9e, 0xb7, 0x6a, 0x64, 0xc0, 0x4f, 0xe4, 0xbc, 0x49, 0x83, 0xeb, 0x94,\n\t0x97, 0x44, 0x7b, 0x58, 0x37, 0x77, 0x4a, 0x67, 0xe6, 0x7f, 0xc3, 0x2d, 0x1b, 0x9a, 0x67, 0x9a, 0x17, 0xe4, 0x42, 0xd9, 0x10, 0x62, 0x3f, 0x82, 0x39, 0xcf, 0x7d, 0x3f, 0xd0, 0xf4, 0x45, 0xde, 0x0f, 0x64, 0x93, 0x5f, 0x3b, 0x43, 0x52, 0xf5, 0xd8, 0x8f, 0x52, 0x53, 0xa7, 0x53, 0x53, 0x9f, 0x77, 0x15, 0xf0, 0x7f, 0x30, 0xda, 0x34, 0x1a, 0xbb, 0xe9, 0x4f, 0x42, 0x81, 0x43, 0xce, 0x9a, 0x72, 0x5a, 0x67, 0xef, 0x8c, 0x2e, 0x8e, 0x44, 0x86, 0x62, 0xcc, 0x8c, 0xd5, 0x09, 0xcf, 0xf2, 0x23, 0x24, 0x98, 0xd8, 0x8f, 0x50, 0x39, 0xc9, 0x76, 0x8b, 0xb8, 0x34, 0x59, 0xef, 0x06, 0x9a, 0xce, 0x7a, 0x37, 0x50, 0x39, 0x2a, 0x6b, 0x09, 0xc4, 0x03, 0xca, 0xbb, 0x81, 0x8a, 0xa3, 0x6c, 0x05, 0x8e, 0x0a, 0x22, 0x2b, 0x94, 0xe2, 0x39, 0x4f, 0xa7, 0x2f, 0x08, 0xca, 0x02, 0x46, 0x30, 0xa5,\n\t0x5e, 0x7e, 0xc0, 0xa7, 0x7b, 0x47, 0x63, 0xe0, 0xb5, 0x96, 0x7f, 0xd3, 0x05, 0xee, 0x4d, 0xbd, 0xf4, 0x19, 0x57, 0x21, 0xff, 0xa2, 0xd6, 0x24, 0x68, 0x1d, 0xfa, 0xef, 0xf1, 0x3e, 0xfb, 0x4a, 0xa7, 0x9f, 0x7f, 0x43, 0x6f, 0xd7, 0x08, 0x16, 0xdd, 0xd7, 0xf8, 0x42, 0x3b, 0x81, 0x33, 0xcc, 0xdc, 0xe7, 0xae, 0x76, 0xd7, 0x56, 0xcf, 0xee, 0x0c, 0xcb, 0x20, 0x47, 0xfa, 0x42, 0xa1, 0xbe, 0x08, 0x73, 0xc0, 0xea, 0x70, 0x58, 0x67, 0x6f, 0x8b, 0xf4, 0x87, 0x43, 0xfd, 0x51, 0x3a, 0x01, 0xa4, 0xe2, 0xeb, 0xc7, 0x80, 0x2f, 0x1f, 0x79, 0x57, 0x90, 0xcf, 0x6e, 0xca, 0xbc, 0x2b, 0x68, 0x3a, 0xf3, 0xae, 0xa0, 0x78, 0xe6, 0x5d, 0x41, 0xac, 0x09, 0x8b, 0x6c, 0xe6, 0x65, 0x41, 0x36, 0x02, 0x6a, 0xb2, 0x19, 0x0c, 0x9d, 0x1f, 0xbf, 0xea, 0xf2, 0x6a, 0xfe, 0xc8, 0xeb, 0x34, 0xef, 0xe9,\n\t0x3c, 0x8e, 0x67, 0xf0, 0xa6, 0xd4, 0x53, 0xaf, 0xba, 0x1c, 0x9a, 0xdf, 0xf3, 0x06, 0xdd, 0x3f, 0xe5, 0x15, 0x3c, 0x97, 0x7a, 0xca, 0x6d, 0xc2, 0xd7, 0x9b, 0x7d, 0x86, 0xd4, 0x57, 0x4d, 0x6e, 0x46, 0x8f, 0x7f, 0x6b, 0x32, 0xa5, 0x6e, 0x37, 0xfb, 0x2d, 0x38, 0x51, 0x94, 0xf2, 0x11, 0x38, 0xac, 0xa9, 0x27, 0x39, 0x0c, 0x70, 0x38, 0x51, 0xb1, 0x54, 0x68, 0x16, 0x98, 0x5c, 0xc2, 0x6d, 0xa5, 0x88, 0x74, 0x22, 0x47, 0x71, 0x50, 0x26, 0x1c, 0x4d, 0xae, 0xcc, 0x7e, 0x67, 0x10, 0xc1, 0x17, 0x87, 0x67, 0xdf, 0xd4, 0x16, 0xf8, 0xef, 0xfa, 0x5a, 0x6a, 0xfd, 0x13, 0x6e, 0x9f, 0x80, 0x19, 0x8d, 0x99, 0x17, 0x2d, 0xda, 0xbf, 0x88, 0x05, 0x36, 0xf6, 0xc3, 0xbf, 0xbe, 0xe7, 0xcc, 0xc7, 0x9f, 0x60, 0x5f, 0xca, 0x37, 0xcf, 0x7e, 0xd6, 0x55, 0xe9, 0xca, 0xaf, 0x74, 0x31, 0x1b, 0x29,\n\t0x12, 0x30, 0x6a, 0x00, 0x1c, 0x2c, 0x86, 0x67, 0x9b, 0xc9, 0x7b, 0x83, 0x34, 0x39, 0xef, 0x0d, 0x9a, 0x9e, 0xf3, 0xde, 0x20, 0xbb, 0xfc, 0xde, 0x20, 0x21, 0xe7, 0xc5, 0x41, 0xec, 0x62, 0xb3, 0x61, 0xf6, 0xd7, 0x4c, 0xc1, 0xb9, 0x59, 0x93, 0x91, 0xc9, 0x9f, 0xfd, 0x0d, 0xf3, 0x27, 0xf6, 0x31, 0x47, 0xcc, 0x34, 0xdb, 0xf6, 0xe9, 0x65, 0xa6, 0xa8, 0x95, 0xf9, 0xf6, 0xa7, 0x41, 0x2f, 0xaf, 0x67, 0x25, 0x66, 0x23, 0xff, 0x0c, 0xd2, 0xa3, 0x3a, 0xd4, 0x2c, 0x35, 0xe8, 0xe1, 0x29, 0x1e, 0xba, 0x93, 0x74, 0xc1, 0xbb, 0x80, 0xc0, 0x45, 0x64, 0x31, 0xbb, 0x5e, 0x7d, 0x27, 0xd0, 0x0e, 0x61, 0x88, 0xbe, 0x01, 0x28, 0x1c, 0xc9, 0xbc, 0x01, 0xc8, 0xa9, 0xe4, 0x18, 0x5d, 0xf2, 0xfd, 0x3f, 0xf8, 0x9d, 0x45, 0xe3, 0x0d, 0xf9, 0xd5, 0xd1, 0xaa, 0xae, 0x60, 0xea, 0xf1, 0xba, 0xc3,\n\t0x83, 0xc9, 0x55, 0x2d, 0x85, 0x9d, 0x76, 0xbb, 0xc6, 0x98, 0x5f, 0x5e, 0x5d, 0x5f, 0x1c, 0xed, 0xac, 0xf2, 0x86, 0xd7, 0xdc, 0xb1, 0xa3, 0x3e, 0x19, 0xae, 0x0e, 0xf9, 0xad, 0x66, 0xbb, 0xc8, 0x0d, 0x32, 0x16, 0x4f, 0xc0, 0x1e, 0x2d, 0x0a, 0x16, 0xe3, 0xe9, 0x9a, 0x8a, 0xe2, 0xb6, 0x95, 0x89, 0xd4, 0x71, 0x83, 0xad, 0xc2, 0x51, 0xe4, 0xd0, 0x3b, 0x62, 0xad, 0xf1, 0xe2, 0xae, 0x64, 0x90, 0x29, 0x6e, 0x6d, 0xb0, 0xda, 0xad, 0x79, 0x5a, 0xf9, 0xbd, 0xb3, 0x6c, 0x0b, 0xf3, 0x3d, 0xfe, 0x69, 0xe0, 0x23, 0x3f, 0x89, 0x82, 0xf0, 0xe4, 0x55, 0x64, 0x0c, 0x5e, 0x9f, 0x4e, 0xbc, 0xd8, 0xc1, 0x0e, 0x91, 0x54, 0x0b, 0xb7, 0xcb, 0xee, 0x77, 0xf8, 0x2f, 0x96, 0x6a, 0x51, 0x57, 0xab, 0x6c, 0x91, 0xdf, 0xd3, 0x73, 0x60, 0xa4, 0xbc, 0x7c, 0xe4, 0x40, 0x4f, 0xef, 0x81, 0x65, 0xe5,\n\t0xe5, 0xcb, 0x0e, 0xf4, 0x7e, 0xee, 0x73, 0xcb, 0x97, 0x2c, 0xe1, 0x9f, 0x2e, 0x1d, 0xd9, 0xdf, 0xd7, 0x7f, 0x60, 0xa4, 0xac, 0x6c, 0xe4, 0x40, 0x7f, 0xdf, 0xfe, 0x91, 0xd2, 0x14, 0x77, 0xf6, 0xec, 0xe4, 0xc6, 0x8d, 0x93, 0xf2, 0x7e, 0xf5, 0x0e, 0xb6, 0x9f, 0xf9, 0x16, 0x7d, 0x67, 0x9c, 0x83, 0xbc, 0xc9, 0x9d, 0x1e, 0x55, 0xdf, 0x4f, 0x8e, 0x09, 0x31, 0xe0, 0x63, 0x6c, 0x42, 0x1c, 0x37, 0x49, 0x0e, 0x8c, 0x92, 0xd7, 0x2b, 0x9a, 0x8c, 0x5a, 0x0d, 0x34, 0x13, 0x29, 0x18, 0x51, 0xb2, 0x16, 0xcd, 0x98, 0xa7, 0x38, 0x0c, 0xca, 0x2f, 0x83, 0x4d, 0xe0, 0x9f, 0xb6, 0xf0, 0x02, 0x2b, 0x68, 0x5b, 0xf0, 0x95, 0xbb, 0x2d, 0x76, 0x3e, 0xf4, 0x5e, 0x88, 0x75, 0x9a, 0x77, 0xff, 0xe6, 0x28, 0x57, 0xf1, 0x88, 0x3e, 0xdf, 0xe8, 0x71, 0x3d, 0xfc, 0x9f, 0x66, 0xe3, 0xe4, 0xa4, 0xde,\n\t0xca, 0x2c, 0x97, 0x9f, 0x1d, 0x63, 0x6f, 0xc5, 0xff, 0xc1, 0x3f, 0x06, 0xb4, 0xad, 0x21, 0x3b, 0x6c, 0x84, 0xb6, 0xee, 0xf9, 0x69, 0xab, 0xd0, 0xb4, 0x27, 0x53, 0x5b, 0xb8, 0x83, 0x05, 0xf2, 0x3a, 0xa3, 0xe1, 0x10, 0x90, 0x57, 0x93, 0x43, 0xde, 0xe4, 0x1c, 0xea, 0x46, 0x2e, 0x20, 0xee, 0x78, 0xa2, 0x2b, 0x66, 0x0d, 0xfa, 0x83, 0x09, 0x4f, 0xea, 0x67, 0x13, 0xc7, 0x2a, 0xfa, 0x13, 0xde, 0x76, 0xbb, 0x5d, 0xd4, 0xdb, 0xc3, 0xd1, 0x72, 0x5f, 0xf7, 0x0a, 0x7f, 0xef, 0xc1, 0xd1, 0x92, 0x88, 0x3f, 0xea, 0x77, 0x5b, 0x4c, 0x40, 0xd9, 0x1d, 0x8c, 0xd1, 0xe6, 0x36, 0xfb, 0xdd, 0xf9, 0x1e, 0x5c, 0xbf, 0xac, 0x20, 0x39, 0x58, 0x9e, 0x7a, 0xd9, 0x90, 0x57, 0x64, 0xf5, 0xe4, 0x69, 0xfb, 0x7a, 0x7d, 0x4d, 0x95, 0x45, 0x8c, 0xbb, 0xaa, 0xdc, 0x68, 0x31, 0x9a, 0xf5, 0xf2, 0x9c,\n\t0x96, 0xb2, 0xb7, 0x32, 0x49, 0xe1, 0x04, 0x32, 0x80, 0xb7, 0x96, 0x94, 0x12, 0x46, 0xc0, 0x27, 0x29, 0x9b, 0x8b, 0xfd, 0xf4, 0xac, 0x0d, 0xa8, 0x80, 0xf6, 0xf4, 0x0e, 0x77, 0x4f, 0xe6, 0xdd, 0x30, 0xbd, 0xec, 0x90, 0x35, 0x4c, 0xdf, 0xfa, 0xa2, 0xf1, 0x94, 0xda, 0x16, 0x7c, 0xeb, 0x8b, 0xf2, 0xda, 0x5d, 0x6b, 0xe2, 0x5d, 0x7b, 0x85, 0x27, 0xd1, 0x56, 0x57, 0x51, 0x54, 0x93, 0x5f, 0x30, 0x94, 0x28, 0xe9, 0x49, 0xf8, 0x8a, 0x9a, 0x97, 0xd5, 0x54, 0xb5, 0x79, 0x58, 0xd6, 0x62, 0x1a, 0x3b, 0xc9, 0x15, 0xb8, 0xac, 0x8b, 0xd7, 0xac, 0xea, 0xf1, 0xfa, 0x36, 0x16, 0x86, 0x82, 0x5d, 0x9b, 0xa4, 0xa6, 0xa9, 0xfe, 0x78, 0xb8, 0xa0, 0xc8, 0x6c, 0x60, 0x7e, 0x0f, 0xeb, 0xb6, 0x0a, 0xf0, 0xfe, 0x5b, 0xfe, 0x11, 0x14, 0x27, 0x75, 0x48, 0xe2, 0x18, 0xf3, 0x2e, 0xcc, 0x31, 0xd9,\n\t0xfb, 0x9a, 0x39, 0x6f, 0x71, 0xe9, 0x49, 0xbf, 0xe1, 0xa0, 0x97, 0x1b, 0x8a, 0x45, 0x83, 0xa1, 0x20, 0x85, 0x32, 0x1d, 0x7c, 0x16, 0x1c, 0xd9, 0x46, 0x46, 0x4e, 0x02, 0x3c, 0x3e, 0x2b, 0xea, 0xf5, 0x3a, 0x5b, 0x7e, 0xc0, 0xdd, 0xde, 0x22, 0x35, 0xf8, 0x83, 0xf9, 0x79, 0x46, 0x8d, 0x91, 0x8b, 0x39, 0x13, 0xc9, 0x7a, 0x6f, 0xd5, 0xaa, 0x8e, 0x70, 0x40, 0xda, 0xd0, 0xd6, 0xb2, 0x36, 0xc8, 0x47, 0x34, 0x5a, 0xbd, 0x49, 0xbf, 0x72, 0x68, 0xc9, 0x0a, 0x30, 0x1d, 0x04, 0x31, 0xe1, 0x29, 0xb6, 0x6b, 0x42, 0xdd, 0x53, 0x52, 0xe3, 0xa6, 0xbe, 0x78, 0x24, 0x4c, 0xf1, 0x5a, 0x03, 0x78, 0xcd, 0xa7, 0x78, 0x0d, 0x92, 0xa8, 0x5d, 0x31, 0x46, 0x9c, 0x81, 0xf0, 0x68, 0x1e, 0x8d, 0x1a, 0x11, 0x0d, 0xdc, 0x9e, 0xde, 0x33, 0xef, 0xc9, 0xd4, 0xdf, 0xee, 0x60, 0x86, 0x8c, 0x46, 0x63,\n\t0xd0, 0x18, 0x8c, 0x85, 0x42, 0xa1, 0x62, 0x51, 0x93, 0xd9, 0x2b, 0x77, 0x2e, 0x58, 0x58, 0x1b, 0xdf, 0x6e, 0x2f, 0xf7, 0x24, 0xda, 0x93, 0x35, 0x45, 0x55, 0x8e, 0x5b, 0x57, 0xfa, 0x44, 0xb1, 0x68, 0x69, 0x03, 0x45, 0x71, 0xd3, 0xb2, 0x44, 0x49, 0xb3, 0x8b, 0xb7, 0x3b, 0x65, 0xe4, 0x7a, 0x98, 0x95, 0xb3, 0x66, 0x77, 0x75, 0xa8, 0x22, 0xd4, 0x35, 0xd5, 0x4e, 0x30, 0xec, 0x71, 0x60, 0x23, 0x81, 0x15, 0xf0, 0xcb, 0x58, 0x01, 0xbf, 0x1a, 0x54, 0x8a, 0xfa, 0xa4, 0x6e, 0x3b, 0x60, 0x97, 0xe4, 0xac, 0x0a, 0x0c, 0x18, 0x7b, 0xa4, 0xf6, 0xb1, 0x06, 0x93, 0x7d, 0xcf, 0x49, 0xb5, 0x12, 0x76, 0x0e, 0x82, 0xb5, 0x20, 0x1e, 0xb4, 0xa5, 0xda, 0x92, 0x50, 0xb1, 0x27, 0x3f, 0xcf, 0xa2, 0xd4, 0xda, 0xd5, 0x6a, 0xd2, 0xb5, 0x76, 0x49, 0x80, 0x7f, 0xbe, 0x57, 0x07, 0xc8, 0xe9, 0x2f,\n\t0xf8, 0x3e, 0x83, 0x3b, 0xea, 0xad, 0x69, 0xd4, 0x30, 0x62, 0x77, 0xa3, 0xbf, 0xa4, 0xc8, 0x63, 0xc8, 0x13, 0x63, 0xce, 0x64, 0x63, 0x93, 0x37, 0xb9, 0xbe, 0x27, 0x16, 0xec, 0x98, 0x68, 0xae, 0x59, 0xd1, 0x5a, 0x6c, 0xb0, 0x71, 0x6f, 0x3b, 0xa2, 0xfe, 0xbc, 0x86, 0xc4, 0x8a, 0xbe, 0x0e, 0xa3, 0xd5, 0x68, 0x94, 0x11, 0xde, 0xb3, 0xad, 0xbb, 0x76, 0x5d, 0x4f, 0xbc, 0xa8, 0x75, 0x4d, 0x63, 0x91, 0x83, 0xc8, 0xf7, 0x10, 0x7b, 0x0f, 0x3e, 0x22, 0x5c, 0x03, 0x26, 0x56, 0x42, 0xaa, 0x72, 0xc3, 0xc4, 0x78, 0x3c, 0x60, 0x04, 0x7c, 0xf7, 0xab, 0x90, 0xb7, 0xd3, 0x73, 0x48, 0xa3, 0x24, 0xba, 0x20, 0x11, 0x43, 0x87, 0x2c, 0x4a, 0xa7, 0xd5, 0x6a, 0xcb, 0x30, 0x88, 0xe0, 0xc7, 0x09, 0x47, 0x30, 0xeb, 0x24, 0x17, 0x29, 0x3b, 0x82, 0x0f, 0x61, 0x97, 0x2b, 0x5a, 0x71, 0xfc, 0x9a,\n\t0x93, 0x71, 0xb3, 0x7d, 0x68, 0xfb, 0xba, 0x60, 0x40, 0x28, 0x37, 0xeb, 0x62, 0x49, 0xdf, 0x54, 0x6a, 0x02, 0x3f, 0x2c, 0x72, 0x16, 0x73, 0x53, 0x60, 0xed, 0x56, 0x2d, 0xcd, 0xc2, 0x0e, 0x33, 0x3f, 0x61, 0x5c, 0xfc, 0xa3, 0x20, 0x23, 0xdc, 0x68, 0x09, 0xba, 0x4f, 0x32, 0x17, 0x80, 0x9a, 0xe9, 0xc2, 0xe0, 0xf4, 0x5b, 0x19, 0xf9, 0xfc, 0x0e, 0xa9, 0xcd, 0x51, 0x91, 0x3e, 0x87, 0x43, 0xce, 0xed, 0x48, 0xe9, 0x73, 0x3b, 0x3d, 0xe9, 0x44, 0xf4, 0x8e, 0xf4, 0x79, 0x9c, 0x3e, 0x92, 0xc5, 0x34, 0xff, 0x81, 0x9f, 0x9c, 0x8e, 0x99, 0xe6, 0xa3, 0x92, 0xdf, 0xe3, 0x01, 0xbd, 0xb3, 0xc4, 0x03, 0x4e, 0x72, 0x7d, 0x5d, 0x45, 0x59, 0x38, 0x94, 0xef, 0xb4, 0x98, 0x45, 0x1e, 0xe9, 0xb1, 0x5e, 0xaf, 0x21, 0x52, 0x39, 0x93, 0xaa, 0x64, 0x03, 0x3a, 0xd1, 0x43, 0x3a, 0x84, 0xc1, 0xe8,\n\t0xd1, 0x1d, 0xa7, 0xba, 0x78, 0x85, 0x4c, 0xa4, 0x3e, 0x73, 0x72, 0x27, 0x99, 0x75, 0x70, 0x47, 0x57, 0x1a, 0x8f, 0x97, 0xc2, 0xdf, 0x97, 0x23, 0x4d, 0xfd, 0xc5, 0x56, 0x47, 0xcd, 0xa2, 0xf6, 0xd6, 0x5b, 0xfc, 0x25, 0x9a, 0xc2, 0x86, 0xc1, 0x32, 0x93, 0xc7, 0xe8, 0xa8, 0x1e, 0x5c, 0x35, 0x58, 0x5d, 0xdc, 0xb1, 0xbe, 0xb5, 0x65, 0x4d, 0x93, 0x2f, 0x1e, 0xb6, 0x39, 0x03, 0xc1, 0x58, 0x45, 0x51, 0xc3, 0xe2, 0xf2, 0x45, 0x35, 0xdc, 0xd3, 0xf1, 0xe2, 0x60, 0x3c, 0x1e, 0x0c, 0x94, 0xa4, 0xde, 0xb2, 0x5b, 0x05, 0xcc, 0xe9, 0x3d, 0x16, 0x4f, 0x24, 0xce, 0x44, 0xea, 0x5c, 0xa2, 0x36, 0xdf, 0x1b, 0x6d, 0x2b, 0xcb, 0x67, 0x19, 0xa3, 0xd9, 0x66, 0x60, 0xf9, 0xfc, 0xda, 0x9a, 0x60, 0x67, 0x6d, 0x91, 0x2b, 0x52, 0xed, 0x0d, 0x56, 0x99, 0xf4, 0x61, 0x9f, 0xab, 0xd6, 0xea, 0xec,\n\t0xad, 0x8c, 0xb6, 0x97, 0xb9, 0x3c, 0xb2, 0x6d, 0xb3, 0x94, 0xbd, 0x87, 0xf1, 0xc3, 0x5a, 0xbb, 0xf0, 0x1c, 0x49, 0x7b, 0x3a, 0xef, 0xa2, 0x87, 0x26, 0x73, 0x76, 0xa8, 0xe7, 0x48, 0x60, 0x61, 0xcd, 0x7b, 0x62, 0xe3, 0x5d, 0x7f, 0x4f, 0x55, 0x69, 0x47, 0xb9, 0xeb, 0x64, 0x2c, 0xe6, 0xaf, 0x73, 0x9d, 0x3c, 0xc9, 0x6f, 0xf3, 0x04, 0x0a, 0x6a, 0xfb, 0x4b, 0x53, 0xcf, 0xe3, 0xc1, 0x92, 0x4a, 0xb7, 0x33, 0x75, 0x2b, 0x48, 0x24, 0x7a, 0x16, 0x81, 0xbd, 0x07, 0xfd, 0x5a, 0xb8, 0x81, 0x9e, 0x81, 0xd8, 0x32, 0x78, 0xda, 0x42, 0x33, 0x41, 0x94, 0x83, 0x10, 0xed, 0x83, 0x0a, 0x87, 0x21, 0xd4, 0x81, 0x88, 0x27, 0x1d, 0xcf, 0xbe, 0xdb, 0x9d, 0x7b, 0x77, 0xee, 0x0d, 0xfa, 0x2a, 0x05, 0xb8, 0x31, 0x4a, 0x5f, 0x33, 0x9f, 0x39, 0x43, 0x01, 0x4b, 0x8a, 0x24, 0xca, 0xd4, 0xcf, 0x49,\n\t0x07, 0xff, 0xd7, 0x93, 0x0f, 0x9a, 0xf2, 0x0b, 0xf3, 0xac, 0x85, 0x2e, 0x93, 0xc9, 0x55, 0x68, 0xcd, 0x2b, 0xcc, 0x37, 0xf1, 0x27, 0x52, 0x66, 0xfc, 0xfb, 0x27, 0xf3, 0xe4, 0x4b, 0x79, 0x70, 0xc9, 0x68, 0xcc, 0x2f, 0x44, 0xcc, 0xf9, 0xff, 0x62, 0x7e, 0x42, 0x61, 0xb6, 0x82, 0x4c, 0xba, 0x49, 0xd2, 0xe7, 0x61, 0x96, 0xa3, 0x99, 0xdf, 0xc4, 0x51, 0xb0, 0xd0, 0x44, 0x2e, 0x25, 0x4f, 0xbd, 0x9d, 0xfa, 0x70, 0x94, 0xbb, 0xa8, 0x07, 0xd0, 0x97, 0x9e, 0x45, 0xba, 0x49, 0xf7, 0x3c, 0x4d, 0xa4, 0x02, 0xb8, 0x06, 0x36, 0x0d, 0x83, 0x67, 0x32, 0xcd, 0xb2, 0x1a, 0x8c, 0xd2, 0xf7, 0x8d, 0x66, 0xe5, 0xbb, 0x6b, 0x9c, 0xa5, 0xb6, 0xb9, 0xf9, 0xee, 0xb9, 0x13, 0x74, 0xfe, 0x5b, 0x5e, 0xbc, 0xb3, 0xca, 0x56, 0x68, 0xe5, 0x19, 0x83, 0x2d, 0xec, 0x79, 0xd0, 0xe4, 0x2a, 0x4a, 0xcf,\n\t0x35, 0x94, 0x80, 0x99, 0x8a, 0xc1, 0xf6, 0x4a, 0x1f, 0xcf, 0x0f, 0xea, 0x35, 0xfe, 0x18, 0xfe, 0x4b, 0xce, 0xa4, 0x6b, 0x54, 0xde, 0x68, 0x03, 0xde, 0xf0, 0x11, 0xde, 0xf0, 0x60, 0x30, 0xba, 0x80, 0x2f, 0x10, 0xa9, 0x93, 0x36, 0x49, 0x29, 0x05, 0xeb, 0x4d, 0xa2, 0x05, 0x36, 0x00, 0xe5, 0x11, 0xab, 0xd5, 0x1a, 0xb1, 0x50, 0x59, 0x40, 0xb5, 0x31, 0x49, 0xe6, 0x76, 0x90, 0xb3, 0x1d, 0x00, 0x58, 0x3b, 0x4d, 0xf5, 0x16, 0x05, 0xf2, 0x2a, 0xe6, 0xb6, 0x6b, 0x2c, 0x6e, 0xfe, 0x4a, 0xc1, 0x6a, 0xf6, 0x9f, 0x3c, 0xe9, 0x32, 0x59, 0x84, 0x03, 0x42, 0xbe, 0xf5, 0xe8, 0x7d, 0x66, 0x4f, 0xbe, 0x91, 0xbd, 0x47, 0x67, 0xfe, 0xba, 0x49, 0xf8, 0x15, 0xf3, 0xfb, 0xd4, 0x2a, 0x51, 0xff, 0x29, 0xa3, 0xfe, 0x55, 0xaf, 0xd9, 0xe0, 0x53, 0xe0, 0x40, 0xef, 0x02, 0x1c, 0xe9, 0xb3, 0x1b,\n\t0xed, 0x0a, 0x03, 0xa8, 0x67, 0x37, 0x14, 0xfa, 0xbe, 0x7b, 0x52, 0x38, 0x31, 0x6b, 0x26, 0x4c, 0x46, 0xfb, 0xb0, 0xb5, 0x20, 0x97, 0x83, 0x24, 0x37, 0x1d, 0xfc, 0x69, 0xe4, 0xa7, 0xdb, 0x4e, 0x24, 0xd2, 0x48, 0x5e, 0xee, 0xc2, 0x10, 0xae, 0x16, 0x88, 0xaf, 0x09, 0x5a, 0x23, 0x60, 0x0b, 0xda, 0x8a, 0x6d, 0xa1, 0x62, 0x62, 0x5c, 0xd8, 0x32, 0x6f, 0xb7, 0x73, 0x52, 0xf6, 0x26, 0x2b, 0x7d, 0x4e, 0xc6, 0xf2, 0x3f, 0xfa, 0x17, 0x55, 0x55, 0xb5, 0x5b, 0x3c, 0x63, 0x35, 0x6b, 0x26, 0x4e, 0x0e, 0x07, 0xab, 0x4e, 0x86, 0x63, 0xb0, 0x24, 0x4e, 0xae, 0xf4, 0x08, 0xfc, 0x58, 0x51, 0x3c, 0x51, 0x52, 0x53, 0xba, 0x65, 0x3d, 0x61, 0xfa, 0xd1, 0xf2, 0x32, 0xf2, 0x51, 0x5a, 0xe1, 0xb4, 0xa7, 0x6e, 0x64, 0xb4, 0x1e, 0xb2, 0xcf, 0x43, 0x70, 0xea, 0xe3, 0x1f, 0xc1, 0x22, 0xf7, 0xed,\n\t0xf3, 0x3f, 0x83, 0x79, 0x69, 0xbf, 0x82, 0xf0, 0x4b, 0xec, 0x3d, 0xa7, 0x13, 0xa5, 0xb2, 0x4d, 0x41, 0xf4, 0x49, 0x23, 0xc0, 0x6d, 0x43, 0x5e, 0x02, 0x79, 0xda, 0x46, 0xec, 0xc9, 0x24, 0xe7, 0xf6, 0x62, 0xd5, 0x5c, 0xf4, 0x3a, 0xbc, 0x8a, 0xb9, 0xa8, 0x59, 0xc8, 0x5c, 0x84, 0x96, 0x75, 0x4d, 0x1b, 0xba, 0xc3, 0xe1, 0xee, 0x0d, 0x4d, 0xcd, 0x1b, 0xba, 0x22, 0x91, 0xae, 0x0d, 0xcd, 0x57, 0x5e, 0x79, 0x90, 0x7f, 0x24, 0xdc, 0x33, 0xd9, 0xd6, 0x36, 0xd9, 0x13, 0x89, 0xc8, 0x9f, 0xe1, 0xd4, 0xf2, 0xcf, 0xc3, 0x3f, 0xd9, 0xae, 0x61, 0x7e, 0xc3, 0x24, 0xc1, 0x56, 0x23, 0xef, 0xc0, 0x58, 0xa7, 0xe4, 0x35, 0xaa, 0xe9, 0x7d, 0x55, 0x39, 0x49, 0x8b, 0x3d, 0xe9, 0xc4, 0xbd, 0x5e, 0xb2, 0xa3, 0xdd, 0xa9, 0xa6, 0xf6, 0x49, 0x73, 0x0d, 0x9f, 0xac, 0x16, 0x72, 0xce, 0x22, 0x49,\n\t0xed, 0xcb, 0xb2, 0x7f, 0xd4, 0x9c, 0xc5, 0x1c, 0x03, 0xc8, 0x41, 0xb1, 0xfd, 0xae, 0xbd, 0x12, 0xec, 0x1f, 0x93, 0x3b, 0xe8, 0x8c, 0x54, 0xbb, 0x0c, 0x45, 0x23, 0x8d, 0x25, 0xdd, 0xb2, 0x09, 0x54, 0xda, 0x94, 0x7f, 0x72, 0xa5, 0x5f, 0x90, 0x0d, 0xa0, 0xd2, 0x96, 0xb0, 0xc5, 0xef, 0x5d, 0x11, 0x06, 0x05, 0x3d, 0x49, 0x4d, 0x20, 0xb7, 0xf3, 0x07, 0xcc, 0xe9, 0x7c, 0x3a, 0x9f, 0x6a, 0x98, 0x8f, 0x4b, 0x99, 0xcf, 0x31, 0x79, 0x0a, 0x66, 0x62, 0x54, 0x98, 0x64, 0xa3, 0x82, 0xa5, 0x2f, 0x83, 0x23, 0x57, 0xf8, 0xac, 0x2b, 0xa3, 0x72, 0xc3, 0xac, 0x0c, 0xbe, 0x9e, 0x74, 0x7a, 0x5e, 0x2f, 0x11, 0x8d, 0x9d, 0xe9, 0x0c, 0x3e, 0x29, 0xd7, 0x1a, 0xc9, 0x69, 0xa2, 0xbe, 0xee, 0x23, 0x24, 0x27, 0xf0, 0x69, 0xe6, 0x49, 0xe0, 0xab, 0xcb, 0xb5, 0x49, 0xea, 0x93, 0x09, 0xb0, 0x4a,\n\t0x2a, 0x3c, 0xc9, 0x16, 0xb3, 0x27, 0xec, 0x0c, 0xd4, 0x80, 0x24, 0x2d, 0x1c, 0x54, 0xed, 0xbe, 0x44, 0x95, 0xe4, 0xe1, 0x45, 0x2f, 0x6f, 0x73, 0x59, 0x97, 0xae, 0x94, 0xe7, 0x8c, 0xb7, 0xcf, 0x2e, 0xfd, 0xcf, 0xa2, 0x88, 0x6a, 0x98, 0x04, 0xbc, 0x9e, 0x7c, 0x99, 0xff, 0xf1, 0x9d, 0x30, 0x67, 0x07, 0x1a, 0x97, 0x27, 0xa2, 0xe3, 0x41, 0x98, 0x98, 0xd4, 0x2c, 0x3d, 0xf8, 0xc1, 0xc9, 0x3f, 0x94, 0x79, 0x66, 0x25, 0xe9, 0xf5, 0x28, 0xea, 0x5d, 0xce, 0xe9, 0x97, 0x32, 0xf9, 0x79, 0xea, 0x0d, 0x92, 0xd3, 0x0f, 0x8e, 0x6e, 0x5a, 0x11, 0xa8, 0xd9, 0x77, 0x82, 0x9a, 0x7c, 0xf7, 0x03, 0x4f, 0x67, 0x79, 0x20, 0x5f, 0xcb, 0xe5, 0x69, 0x0a, 0x4c, 0xd1, 0x32, 0xcb, 0xc9, 0x65, 0x0e, 0x13, 0xcf, 0x77, 0x54, 0x26, 0x2d, 0xdb, 0x6d, 0x7c, 0x49, 0x38, 0x75, 0x96, 0xd1, 0x9a, 0xed,\n\t0x24, 0x8e, 0x06, 0xb6, 0xe9, 0x57, 0x81, 0xd7, 0x6b, 0x89, 0x6d, 0x5a, 0x0b, 0x26, 0xa8, 0xfb, 0x62, 0x39, 0x77, 0x3d, 0xe9, 0x9c, 0xbb, 0x5e, 0x66, 0xa8, 0x3c, 0x18, 0x2e, 0x07, 0x53, 0x82, 0x88, 0x1b, 0x21, 0x6d, 0x9a, 0xce, 0xb3, 0x35, 0x4e, 0x58, 0x8b, 0x4b, 0x9b, 0xa8, 0x77, 0xe9, 0xac, 0x3a, 0xa7, 0xa7, 0xd8, 0x59, 0x1c, 0x09, 0xd7, 0x4b, 0xf5, 0x61, 0x6f, 0x72, 0xb8, 0x36, 0x39, 0x59, 0x50, 0x24, 0x58, 0x8c, 0x46, 0x87, 0x27, 0xe4, 0x2d, 0x29, 0x0e, 0x37, 0x48, 0x0d, 0x61, 0x77, 0x62, 0xa0, 0xa6, 0x7e, 0xcc, 0xcf, 0x57, 0x5a, 0x74, 0x7a, 0x9d, 0xc7, 0xe5, 0x70, 0xd9, 0xec, 0x81, 0xda, 0x92, 0x48, 0x47, 0xa5, 0x27, 0xe4, 0x4b, 0x6a, 0xf5, 0x46, 0xb3, 0x21, 0x60, 0x77, 0xe6, 0xdb, 0x6c, 0xc1, 0xa6, 0xca, 0x40, 0x53, 0xb9, 0x27, 0xec, 0x27, 0xf2, 0x26, 0x00,\n\t0x73, 0x39, 0x29, 0xd4, 0xa3, 0x42, 0xb2, 0x6a, 0x0d, 0x34, 0x3f, 0x20, 0x77, 0x8f, 0x59, 0x4a, 0xc7, 0x84, 0x7a, 0xd1, 0x50, 0xd0, 0x6a, 0x8d, 0x66, 0x59, 0x4e, 0x6a, 0xa8, 0xae, 0x1d, 0x27, 0x9b, 0xb1, 0x83, 0x18, 0x51, 0xd4, 0xa2, 0xa0, 0x30, 0x9f, 0xf4, 0xf5, 0x47, 0x7b, 0x06, 0x6b, 0xf4, 0xe6, 0x15, 0x5e, 0xde, 0xd3, 0x7b, 0xd3, 0x4d, 0x4e, 0x1b, 0xe8, 0x35, 0x70, 0x98, 0xd8, 0x97, 0x5d, 0xae, 0xa5, 0xdd, 0xd8, 0x69, 0x36, 0x35, 0x58, 0x6e, 0x70, 0x3d, 0x38, 0x95, 0xfa, 0x1f, 0x87, 0x1b, 0xec, 0x69, 0x02, 0xcb, 0x00, 0xc8, 0x10, 0x27, 0xf8, 0x79, 0x2e, 0x02, 0x8b, 0x13, 0x74, 0x0a, 0xf8, 0x78, 0x44, 0xf6, 0x11, 0x71, 0x27, 0x65, 0x02, 0x6e, 0xb2, 0x00, 0x75, 0x21, 0x57, 0xd0, 0x11, 0x02, 0x54, 0xa6, 0x63, 0x6a, 0x78, 0x4e, 0x50, 0x8a, 0x71, 0xae, 0x74, 0x6b,\n\t0xc5, 0xa2, 0x81, 0xba, 0x92, 0xce, 0x32, 0xd7, 0x2d, 0xf1, 0x98, 0xbf, 0xd6, 0xc5, 0x3f, 0x30, 0xfb, 0x67, 0x77, 0xa4, 0x28, 0x4a, 0xd4, 0x3b, 0x1e, 0x4c, 0x3d, 0x5f, 0x52, 0xe9, 0x71, 0xe2, 0x03, 0x88, 0xd6, 0x33, 0x06, 0x7b, 0x62, 0x9e, 0x77, 0x4f, 0x4b, 0x19, 0x91, 0x9d, 0x87, 0x40, 0x57, 0x70, 0xa0, 0xbf, 0x30, 0x1b, 0x64, 0xa9, 0x27, 0x41, 0xc3, 0x13, 0x44, 0x4b, 0x24, 0x18, 0xff, 0xf7, 0xaf, 0x79, 0x73, 0x9f, 0xd9, 0xc9, 0x4c, 0x08, 0x7a, 0x5e, 0x30, 0x88, 0xeb, 0x58, 0xbb, 0x89, 0x3c, 0x8c, 0xd1, 0x9a, 0x0c, 0xb3, 0xfe, 0x5a, 0x8f, 0xa7, 0xce, 0x7f, 0xce, 0x60, 0x82, 0xe7, 0xb8, 0x41, 0xbe, 0xb7, 0xf2, 0x0f, 0x82, 0x5f, 0x03, 0xcf, 0x09, 0x3a, 0x34, 0x2c, 0x39, 0x7d, 0x44, 0xcf, 0xd8, 0x48, 0x83, 0x8a, 0xcf, 0x18, 0x0f, 0xc4, 0x5b, 0x2c, 0x94, 0x49, 0xb3,\n\t0x1f, 0x02, 0x18, 0xae, 0xa1, 0x3f, 0x64, 0xad, 0xc4, 0xe6, 0x04, 0x9b, 0xdc, 0x7b, 0xcd, 0x2e, 0xa6, 0x8b, 0xd3, 0x70, 0xbc, 0x41, 0x5c, 0xa2, 0xf5, 0xd7, 0x17, 0x69, 0x16, 0x0b, 0x3a, 0x2e, 0xaf, 0x97, 0x75, 0x98, 0x76, 0x7e, 0x71, 0xa7, 0x4d, 0x5c, 0x0d, 0x3e, 0x2f, 0xa7, 0x1b, 0x15, 0x5c, 0xdb, 0xf9, 0x07, 0xcc, 0xd6, 0xff, 0xf1, 0x54, 0xb8, 0x5c, 0x15, 0x9e, 0x3f, 0x17, 0x14, 0xfe, 0xc9, 0x5d, 0xee, 0x1a, 0xff, 0x93, 0xc5, 0x0c, 0x58, 0xc1, 0x0e, 0x4b, 0x81, 0xa5, 0xa0, 0x38, 0xf5, 0x5b, 0x37, 0xb5, 0xaf, 0x9c, 0x80, 0x8f, 0x8a, 0xf4, 0x7b, 0xa6, 0xb3, 0x63, 0x47, 0xd2, 0xa0, 0x42, 0x84, 0x58, 0x5e, 0x89, 0x85, 0x23, 0xe8, 0x57, 0x4a, 0xc4, 0x2a, 0xc7, 0x62, 0xa3, 0x14, 0xea, 0x24, 0x85, 0x58, 0x64, 0x2a, 0x6e, 0x30, 0xd9, 0xf8, 0x2d, 0xac, 0xc0, 0xaf, 0xe1,\n\t0xf3, 0x4c, 0x87, 0x4f, 0x3f, 0x7e, 0x83, 0xd9, 0xc4, 0x6f, 0xe5, 0x75, 0x4b, 0x74, 0xce, 0xa3, 0x8f, 0xb3, 0xf7, 0x98, 0xf5, 0xcf, 0xe8, 0xf2, 0x34, 0x27, 0x75, 0x16, 0x6c, 0x3c, 0xa7, 0xd1, 0x7e, 0x29, 0xcf, 0x79, 0x8d, 0xfd, 0x8f, 0xb2, 0x7d, 0xc7, 0x83, 0xec, 0x2b, 0x82, 0xe7, 0x5f, 0x10, 0x33, 0xa2, 0x04, 0xe9, 0x54, 0x63, 0x46, 0x79, 0x41, 0x42, 0x10, 0x39, 0x66, 0x54, 0x7f, 0x01, 0x51, 0x8a, 0x52, 0xbf, 0xd6, 0xda, 0xed, 0x5b, 0x26, 0xff, 0xf9, 0x10, 0x10, 0x6e, 0x8a, 0xd7, 0x72, 0xbc, 0x8e, 0xdf, 0xc4, 0xd9, 0x8d, 0x40, 0x99, 0x2b, 0x1c, 0x96, 0xff, 0x83, 0x7f, 0x62, 0xd6, 0xff, 0xc1, 0x5c, 0x68, 0xb6, 0x16, 0x5a, 0xde, 0xd7, 0x9b, 0xe5, 0xe7, 0x96, 0x82, 0xfc, 0xf9, 0x36, 0x7d, 0xb7, 0x7c, 0x5c, 0x8a, 0x90, 0x6c, 0x5e, 0x0d, 0x2d, 0xf8, 0xa5, 0xc6, 0x8c,\n\t0xa4, 0x74, 0xcc, 0xa8, 0x43, 0x89, 0x19, 0x69, 0xe4, 0x98, 0x11, 0x9b, 0x90, 0x63, 0x46, 0xb6, 0x60, 0x5d, 0x00, 0x7f, 0x5b, 0xa7, 0xff, 0xc5, 0x9f, 0x52, 0xdb, 0x75, 0x86, 0x5f, 0xbe, 0x8f, 0x4f, 0xf1, 0x9b, 0xcc, 0x05, 0x86, 0xd4, 0x3b, 0x3b, 0x9b, 0xb5, 0x7e, 0x33, 0xae, 0xd8, 0x01, 0xcf, 0xb8, 0x92, 0xbb, 0x8d, 0x71, 0xf0, 0x4f, 0x21, 0x2d, 0xf2, 0x48, 0x2e, 0xf8, 0x8d, 0xf7, 0x13, 0x63, 0x64, 0x07, 0xd9, 0x3b, 0x14, 0x38, 0xa4, 0xc5, 0x5a, 0x36, 0xab, 0xf8, 0x6e, 0x94, 0xc5, 0x95, 0xc1, 0x62, 0x13, 0x29, 0xb3, 0x6b, 0xfe, 0x2d, 0xff, 0x94, 0xcb, 0xf5, 0x81, 0xd1, 0x4a, 0xd8, 0x05, 0xfa, 0x15, 0x0a, 0x3a, 0x26, 0x26, 0xb6, 0xc1, 0x38, 0xf9, 0x92, 0x83, 0xbc, 0xac, 0x1a, 0xed, 0x03, 0xc0, 0xb6, 0x65, 0x8f, 0x62, 0x23, 0x71, 0x3c, 0x1a, 0x50, 0xf8, 0x5d, 0x71,\n\t0x28, 0xef, 0xbd, 0xdb, 0x5c, 0x5e, 0x6b, 0xea, 0x0d, 0xb1, 0x4d, 0xef, 0x4a, 0xfd, 0x37, 0xb8, 0x69, 0xf2, 0xbb, 0xb5, 0xb1, 0x0f, 0xe0, 0xf9, 0x16, 0x85, 0xc7, 0x4d, 0x2a, 0x17, 0x61, 0xb4, 0x9f, 0x88, 0xce, 0x1d, 0x98, 0xe0, 0x58, 0x8b, 0x34, 0x41, 0x7a, 0xc6, 0x94, 0x06, 0x06, 0x89, 0x7c, 0x62, 0xbe, 0xf5, 0x5b, 0xb3, 0xcf, 0x75, 0xe5, 0xbd, 0xa6, 0x40, 0x90, 0x7f, 0x2a, 0x95, 0xb2, 0x1a, 0x3f, 0x70, 0xb9, 0xe4, 0x71, 0x74, 0x82, 0x8e, 0x0d, 0x00, 0x3c, 0x7a, 0xe4, 0x92, 0xec, 0xe4, 0xd5, 0x65, 0x78, 0x1f, 0x5c, 0xdf, 0x06, 0x7f, 0x7a, 0xa4, 0xa3, 0xa3, 0x28, 0xc1, 0xbd, 0x36, 0x36, 0xc1, 0x06, 0x52, 0x5f, 0xb3, 0xfa, 0x5c, 0xb7, 0xff, 0xbb, 0xd6, 0x6a, 0xf7, 0x58, 0xc5, 0xb6, 0xd4, 0xbf, 0x9b, 0x34, 0x38, 0xcf, 0x60, 0x14, 0x19, 0x99, 0x0e, 0x2b, 0xb8, 0xbb,\n\t0x98, 0x37, 0x81, 0x0e, 0x16, 0xe4, 0x95, 0xf2, 0x45, 0x4c, 0x98, 0x8f, 0x10, 0x02, 0xed, 0x07, 0x4a, 0x4c, 0x32, 0x43, 0xd6, 0x52, 0x0b, 0x7d, 0xbb, 0xf8, 0xdc, 0x4a, 0xbe, 0xcc, 0x9b, 0x73, 0xcb, 0xf6, 0xce, 0x29, 0xcf, 0x4b, 0xc6, 0x1e, 0x02, 0xbc, 0xbd, 0x4b, 0xcf, 0x83, 0xbb, 0xc9, 0x29, 0x37, 0x32, 0xb6, 0x7a, 0x0a, 0x1c, 0x6d, 0xb3, 0xc6, 0x33, 0x23, 0xa7, 0x4f, 0x7a, 0x33, 0xef, 0xe6, 0x1e, 0xea, 0xce, 0x3e, 0xc4, 0x3d, 0x17, 0x5e, 0x58, 0xd7, 0x3a, 0xf9, 0x04, 0x28, 0xc1, 0xa4, 0xfc, 0x02, 0x7b, 0x8a, 0x4a, 0x0b, 0x32, 0x5b, 0x69, 0x6c, 0x3a, 0x2d, 0x3f, 0x9c, 0xae, 0xa4, 0xcc, 0xa8, 0x6f, 0xbe, 0xf7, 0xc2, 0x7b, 0x37, 0x1b, 0x5c, 0xe2, 0xd5, 0x5a, 0xf8, 0x77, 0x58, 0x74, 0x19, 0xf8, 0x07, 0x52, 0x7f, 0xc4, 0x7a, 0xad, 0x70, 0x5c, 0x6b, 0x30, 0x68, 0x8f,\n\t0xf3, 0x3a, 0xfa, 0x8c, 0x1e, 0x05, 0xee, 0x3c, 0x02, 0x37, 0x19, 0x38, 0x83, 0x60, 0x59, 0x36, 0xe9, 0xe6, 0x97, 0x4d, 0xef, 0xfe, 0xee, 0x85, 0xdf, 0x9d, 0x32, 0x06, 0x4d, 0xfb, 0x58, 0x01, 0x1c, 0x46, 0x76, 0x9f, 0x29, 0x68, 0x14, 0xbd, 0xa9, 0xdf, 0x61, 0xab, 0x60, 0x3b, 0x05, 0x8b, 0x82, 0xd3, 0xf2, 0xb7, 0xdb, 0xc9, 0x41, 0xc3, 0x18, 0x77, 0x35, 0x23, 0xf2, 0x6f, 0x20, 0xa3, 0xcc, 0x97, 0x98, 0x1c, 0xfe, 0x43, 0x68, 0x33, 0x06, 0xbe, 0x34, 0xe8, 0x90, 0x11, 0x1b, 0x15, 0xbe, 0x24, 0xda, 0x4a, 0x0e, 0xa7, 0xe1, 0x9f, 0xb9, 0x0c, 0xa2, 0x2d, 0xe0, 0xd1, 0x17, 0x79, 0xbb, 0x9a, 0xf8, 0x37, 0x9c, 0x06, 0x6d, 0xa0, 0x79, 0xac, 0xcb, 0x65, 0x26, 0xf3, 0xc5, 0x68, 0x2b, 0xf7, 0x24, 0xf3, 0x75, 0xfe, 0x0e, 0x90, 0x21, 0x60, 0x87, 0x0b, 0xc4, 0xfe, 0x06, 0x2c, 0xaf,\n\t0x4f, 0xe7, 0x96, 0x4d, 0xb2, 0x34, 0x65, 0x29, 0xcf, 0x6a, 0x36, 0xea, 0x34, 0x1c, 0x8b, 0xbc, 0xd8, 0x2b, 0xa7, 0x8c, 0x25, 0xeb, 0x13, 0x8a, 0x3d, 0x48, 0x74, 0x73, 0x50, 0x3d, 0x04, 0x9b, 0x2a, 0x0e, 0xe3, 0x83, 0xde, 0xaa, 0xae, 0x78, 0xb0, 0x35, 0x59, 0xed, 0x0c, 0x84, 0xf1, 0x21, 0x6f, 0xcd, 0xa2, 0x78, 0xa8, 0x35, 0x59, 0xc5, 0x27, 0x63, 0x65, 0x35, 0xcb, 0x9a, 0x8b, 0x7c, 0xc5, 0xbe, 0x92, 0xd2, 0xea, 0xe5, 0x4d, 0x01, 0x5f, 0xc0, 0x47, 0xe9, 0x2c, 0x32, 0xef, 0x09, 0xbf, 0x07, 0xdd, 0x96, 0x94, 0x12, 0xf0, 0x7c, 0xd6, 0x49, 0x7d, 0x44, 0x8e, 0x50, 0x1c, 0xad, 0x46, 0x24, 0xa4, 0xcf, 0x32, 0xf4, 0x25, 0x58, 0xc4, 0x3e, 0x45, 0x78, 0x18, 0x23, 0x9f, 0xc7, 0x6a, 0x86, 0xb9, 0x16, 0xe2, 0x42, 0xfe, 0xff, 0x11, 0xf7, 0x1e, 0xe0, 0x51, 0x5c, 0x67, 0xa3, 0xf0,\n\t0x9c, 0x29, 0xdb, 0x7b, 0xd5, 0xf6, 0xde, 0x57, 0x75, 0xb5, 0xbb, 0xea, 0xbb, 0xea, 0x42, 0x15, 0x15, 0x10, 0x42, 0x20, 0x10, 0x42, 0xa2, 0x09, 0x90, 0x05, 0xc6, 0x14, 0xd3, 0x3b, 0xb6, 0x01, 0x57, 0x8a, 0x71, 0xdc, 0x8d, 0x0b, 0x8e, 0x71, 0x83, 0xb8, 0x24, 0xb1, 0x0d, 0x8e, 0xed, 0x24, 0x4e, 0xc7, 0xce, 0xcd, 0xe7, 0xe4, 0x4b, 0xfb, 0x92, 0x38, 0x71, 0x12, 0xc7, 0x8e, 0x73, 0x1d, 0x83, 0x46, 0xf7, 0x9c, 0x33, 0xbb, 0xab, 0x82, 0xb0, 0xc9, 0xfd, 0xff, 0xe7, 0xb9, 0x8f, 0x8d, 0x76, 0x67, 0xe7, 0xcc, 0x99, 0x53, 0xde, 0xf3, 0xf6, 0x92, 0x4e, 0x79, 0x31, 0x31, 0x16, 0x19, 0xa9, 0x4d, 0x0f, 0x86, 0x94, 0xe9, 0x9d, 0x7a, 0xc9, 0x4d, 0x86, 0xbc, 0xba, 0x9c, 0x9c, 0x86, 0xf2, 0x98, 0x49, 0xef, 0xd4, 0x49, 0x36, 0x19, 0xf2, 0xeb, 0xb2, 0x73, 0x1b, 0xca, 0xa3, 0xbc, 0x83,\n\t0x4a, 0xb3, 0x4b, 0x95, 0xdd, 0x91, 0x80, 0x94, 0xc6, 0xa1, 0xb2, 0xb8, 0x95, 0xd9, 0x9d, 0x49, 0xaf, 0xc3, 0x67, 0x47, 0x3c, 0xdd, 0x3c, 0xfa, 0x6e, 0xf2, 0x6d, 0x66, 0x37, 0xce, 0x13, 0x5a, 0xc8, 0x29, 0x06, 0xa4, 0x93, 0x12, 0x74, 0x22, 0x89, 0x4a, 0x4d, 0x21, 0x40, 0x04, 0xdd, 0x14, 0x48, 0x6d, 0x01, 0x20, 0xda, 0x7a, 0xce, 0xa1, 0x8c, 0x9a, 0x9c, 0x82, 0xfa, 0x2b, 0x32, 0x6a, 0xd6, 0x69, 0x70, 0x7e, 0x4c, 0x94, 0x0d, 0x13, 0xe7, 0xc7, 0xd4, 0x80, 0x5d, 0xd3, 0xf3, 0x63, 0x7e, 0x65, 0xda, 0x4b, 0x8e, 0xa7, 0x6f, 0xe0, 0x29, 0xc8, 0x9f, 0xf3, 0x3e, 0xc7, 0x63, 0xb5, 0x24, 0x8d, 0x33, 0x0c, 0xeb, 0xba, 0x07, 0x95, 0x87, 0x32, 0x42, 0xeb, 0x03, 0x36, 0xb5, 0xda, 0x16, 0xd0, 0xa3, 0x0c, 0xd1, 0xe0, 0x71, 0x38, 0x3c, 0x3d, 0x1c, 0x26, 0x7c, 0x6d, 0x30, 0x4b, 0x0f,\n\t0x87, 0xcb, 0xdb, 0x95, 0x15, 0x40, 0x42, 0x5c, 0x60, 0x22, 0x83, 0xf4, 0xd4, 0x6b, 0x7c, 0x06, 0xd6, 0xd0, 0xdf, 0x23, 0x9f, 0x63, 0x1a, 0xe1, 0xe6, 0x41, 0x9c, 0x87, 0x90, 0x0e, 0x31, 0x27, 0x85, 0x91, 0x09, 0xd0, 0xa2, 0x54, 0xa0, 0xe8, 0x58, 0xb5, 0x43, 0xeb, 0x58, 0x43, 0xd6, 0x8c, 0xbd, 0xca, 0x34, 0x6e, 0xc7, 0xcf, 0xac, 0xe7, 0xe5, 0x91, 0x67, 0x78, 0x0f, 0x7f, 0xd5, 0x33, 0xeb, 0xc9, 0xa2, 0xb1, 0xb7, 0x79, 0x0f, 0xaf, 0xc3, 0xcf, 0xdc, 0x04, 0x71, 0xe2, 0x13, 0xf0, 0x3c, 0x6b, 0xd1, 0x79, 0x26, 0x48, 0x04, 0x33, 0xc4, 0x22, 0xbc, 0x45, 0xe8, 0x38, 0x20, 0x8b, 0x26, 0x8f, 0x21, 0xb4, 0x40, 0xcb, 0xa4, 0x0d, 0xcf, 0x91, 0x54, 0x26, 0x14, 0x0c, 0x2f, 0xe0, 0x68, 0xdb, 0xaa, 0x2a, 0xcb, 0x21, 0xa9, 0x23, 0x1e, 0x0c, 0xc6, 0x1d, 0xd2, 0x43, 0x96, 0xaa, 0x55,\n\t0xf4, 0xad, 0xa1, 0xa6, 0x25, 0x45, 0xf6, 0x98, 0x4f, 0xab, 0xf5, 0xc5, 0xec, 0x45, 0x4b, 0x9a, 0xb8, 0xf9, 0x2c, 0xe4, 0x09, 0xc9, 0x37, 0xf8, 0x6a, 0x28, 0x1c, 0xa7, 0x35, 0xdb, 0xa3, 0xf0, 0x4d, 0x04, 0xd9, 0x9d, 0x8e, 0x55, 0x25, 0x09, 0x08, 0x96, 0x72, 0x19, 0x7e, 0x9f, 0x12, 0x28, 0xa7, 0xbd, 0x2f, 0x06, 0x3f, 0x79, 0xe0, 0x68, 0xc3, 0x68, 0x5b, 0xf0, 0x1e, 0x85, 0xa7, 0x2c, 0xdc, 0x5d, 0x7b, 0xcf, 0x43, 0x3c, 0xa1, 0xbd, 0x6a, 0x69, 0x8d, 0x2b, 0xe6, 0xd1, 0xb4, 0xd4, 0x6e, 0xbf, 0x05, 0x76, 0xf0, 0x06, 0xbd, 0x82, 0x5c, 0xc4, 0xfc, 0x01, 0xc7, 0x55, 0x56, 0x70, 0xf6, 0x41, 0x15, 0x31, 0x49, 0x97, 0x0f, 0x07, 0x32, 0x88, 0xd8, 0xe6, 0xac, 0x74, 0x14, 0x34, 0x3c, 0x18, 0x00, 0x8f, 0x00, 0x9d, 0x0b, 0x12, 0x40, 0xe8, 0x73, 0x7b, 0xfd, 0x93, 0x3c, 0x1c, 0x27,\n\t0x04, 0xb6, 0x38, 0xe6, 0xb5, 0x38, 0xc5, 0xd2, 0x1b, 0x8e, 0xa2, 0xa6, 0x40, 0xb0, 0xa9, 0xd8, 0xe9, 0x2c, 0x6e, 0x0a, 0x06, 0x9a, 0x8a, 0x1c, 0xab, 0x0b, 0x73, 0xc2, 0xd1, 0x68, 0x38, 0xa7, 0x90, 0xf1, 0x86, 0xa0, 0x18, 0x60, 0x8e, 0xd4, 0x85, 0x82, 0x75, 0xf9, 0x66, 0x73, 0x7e, 0x5d, 0x30, 0x14, 0x8b, 0x85, 0xc2, 0xb1, 0x18, 0x07, 0x67, 0x3f, 0x60, 0x3e, 0x21, 0x3b, 0xf8, 0x3d, 0x78, 0x7c, 0x90, 0xda, 0x5f, 0x6b, 0x14, 0xd7, 0x33, 0x86, 0x1f, 0xd8, 0xa2, 0x75, 0x5e, 0x7f, 0x7d, 0xcc, 0x66, 0x8b, 0xd5, 0xfb, 0xbd, 0x75, 0x51, 0xdb, 0xe2, 0xc2, 0x5c, 0xf4, 0xae, 0xdc, 0x42, 0xde, 0xc3, 0xfe, 0xea, 0x3c, 0x93, 0x29, 0xaf, 0xda, 0xef, 0xab, 0xca, 0x31, 0x1a, 0x73, 0xaa, 0x7c, 0xc1, 0x78, 0x3c, 0x98, 0xcd, 0x8d, 0x81, 0x82, 0x6b, 0x34, 0x48, 0x7e, 0xce, 0xaf, 0xc2,\n\t0x63, 0x08, 0x20, 0xd9, 0xc3, 0x8c, 0x4a, 0x7d, 0x42, 0x29, 0x09, 0x05, 0x66, 0xd2, 0x04, 0x3d, 0x3a, 0xd3, 0x82, 0xb9, 0x26, 0xdf, 0xbf, 0xd6, 0xda, 0x25, 0x65, 0x76, 0xbb, 0x3d, 0x60, 0xf7, 0x7b, 0xd0, 0xf8, 0x51, 0x24, 0xd4, 0x97, 0x8d, 0x7f, 0x82, 0xcc, 0x5e, 0x7b, 0x35, 0xc1, 0x3b, 0x7f, 0x95, 0x5b, 0xf4, 0x37, 0xde, 0x29, 0x73, 0xba, 0x18, 0x67, 0xa8, 0xbe, 0xc0, 0x6c, 0x2e, 0xa8, 0xcf, 0x2c, 0x2c, 0x9e, 0x54, 0x34, 0x0a, 0x3e, 0x65, 0xc7, 0x14, 0x1c, 0x65, 0xa6, 0x88, 0xf7, 0x99, 0x9f, 0x52, 0x41, 0x41, 0x12, 0xcf, 0x2d, 0x44, 0x14, 0x26, 0xf3, 0xaf, 0x63, 0xd8, 0x70, 0xcc, 0x21, 0x7b, 0xf0, 0xfa, 0xc6, 0xcc, 0x70, 0x63, 0xa6, 0x22, 0xef, 0x5b, 0x0b, 0xaa, 0x3c, 0x9e, 0x9a, 0x02, 0xab, 0xb5, 0xa0, 0xc6, 0xe3, 0xa9, 0x2a, 0xb0, 0xce, 0x2f, 0x08, 0x07, 0xa3,\n\t0xd1, 0x60, 0xb8, 0x00, 0xfc, 0x9b, 0xfd, 0x85, 0xd2, 0xa2, 0xbf, 0xf5, 0x82, 0x50, 0x01, 0xc9, 0x3d, 0xef, 0x66, 0x6f, 0x32, 0xdb, 0x60, 0xc8, 0x4e, 0x7a, 0xbd, 0x15, 0x61, 0x83, 0x21, 0x5c, 0xe1, 0x0d, 0x44, 0xa3, 0x81, 0x50, 0x24, 0x02, 0x4e, 0xfc, 0x54, 0x26, 0x78, 0x8b, 0xe3, 0x02, 0x48, 0xe2, 0x39, 0xfa, 0x56, 0xaa, 0x0d, 0xf3, 0x25, 0x5a, 0xc2, 0x9d, 0x74, 0x70, 0x68, 0x92, 0xa1, 0x68, 0x78, 0x4c, 0x20, 0xb3, 0x24, 0x82, 0x44, 0x51, 0xa4, 0x15, 0x69, 0xe4, 0x52, 0xcc, 0xa4, 0xf0, 0xa6, 0x30, 0x29, 0x0e, 0x2a, 0x3d, 0x26, 0x52, 0xf2, 0x96, 0xd4, 0xaa, 0x6f, 0xdf, 0x2f, 0x75, 0xb9, 0xc0, 0x85, 0xcf, 0x20, 0xe7, 0xd2, 0xf7, 0x82, 0x40, 0xae, 0xca, 0x52, 0x66, 0x78, 0x17, 0xfc, 0x21, 0x56, 0x4a, 0x78, 0x18, 0x16, 0x4f, 0x41, 0x1e, 0x66, 0x37, 0xa4, 0xb1, 0x28,\n\t0xa6, 0x37, 0x9c, 0x0c, 0xe0, 0xb7, 0x21, 0xac, 0xc7, 0xbd, 0x36, 0x8d, 0xf7, 0xf0, 0xbb, 0xd5, 0x22, 0xd5, 0xe4, 0x77, 0xf3, 0x33, 0xef, 0xce, 0x7c, 0x23, 0x85, 0x3f, 0x50, 0x98, 0xf4, 0x0b, 0x6f, 0x97, 0x85, 0x5c, 0xe0, 0x8b, 0xcb, 0x4a, 0xbb, 0x7e, 0xe5, 0x4b, 0xaa, 0xb0, 0x8b, 0x6f, 0xfa, 0x54, 0xa6, 0xf8, 0x9d, 0x5e, 0xff, 0xa9, 0x5c, 0xfe, 0x3b, 0x5d, 0x16, 0xe2, 0x9b, 0xe8, 0xe7, 0xa0, 0x9c, 0xff, 0x1a, 0xca, 0xbb, 0x80, 0xe3, 0xe7, 0x39, 0x37, 0x19, 0xc8, 0x60, 0xbb, 0x71, 0xb0, 0xff, 0x34, 0x5c, 0x4a, 0xea, 0xa7, 0xe7, 0x4f, 0x61, 0x8a, 0x32, 0xd9, 0x1e, 0x0a, 0xd0, 0x67, 0x01, 0x7c, 0x5c, 0xce, 0x33, 0x92, 0x4a, 0xbe, 0x05, 0xf6, 0x89, 0x70, 0x1e, 0x9e, 0x42, 0xca, 0x75, 0x19, 0xa1, 0xed, 0x99, 0x3b, 0x56, 0x6a, 0xdd, 0xb9, 0x26, 0x63, 0x8e, 0x53, 0xab,\n\t0x75, 0xe6, 0x18, 0x4d, 0xb9, 0x6e, 0x2d, 0xef, 0xa4, 0x31, 0xc7, 0xa5, 0xd5, 0xba, 0xb8, 0x2b, 0x78, 0x97, 0xe3, 0x75, 0xfe, 0xce, 0xde, 0x4b, 0xf6, 0x13, 0x66, 0x48, 0xd7, 0xd7, 0x73, 0xd8, 0x44, 0x64, 0x80, 0xc2, 0x22, 0x12, 0x9a, 0xb0, 0x8c, 0x9e, 0xba, 0x20, 0x33, 0x11, 0x87, 0x2a, 0x02, 0x2e, 0x1d, 0x35, 0x34, 0xa5, 0xfa, 0x7c, 0x2a, 0x90, 0x0b, 0xde, 0xa1, 0x46, 0xa7, 0x96, 0xa5, 0xd7, 0xe2, 0xdf, 0x08, 0x0e, 0x13, 0x4e, 0x54, 0x9e, 0xef, 0x39, 0xa7, 0x73, 0x6b, 0x7c, 0xe8, 0xfc, 0x33, 0xd7, 0x0a, 0x1f, 0x88, 0x80, 0xe7, 0x67, 0x74, 0xeb, 0x8f, 0xaf, 0xad, 0x9f, 0xc1, 0xdf, 0x9e, 0xcb, 0x73, 0xf9, 0x6b, 0xf6, 0x49, 0xb2, 0x1d, 0x72, 0x3c, 0x06, 0x62, 0x3e, 0x37, 0x24, 0x31, 0x85, 0x8d, 0xc4, 0x52, 0x09, 0xa4, 0x7f, 0x26, 0x7c, 0x45, 0xa6, 0xae, 0x52, 0xf1,\n\t0x64, 0x52, 0x92, 0x22, 0x53, 0x7b, 0xb4, 0x1c, 0x79, 0xc7, 0x2b, 0x51, 0x70, 0x25, 0x31, 0x9a, 0xce, 0x76, 0xb6, 0x1c, 0x3b, 0x7d, 0x40, 0x01, 0x4a, 0xc3, 0x67, 0x08, 0x03, 0x30, 0xd0, 0xc8, 0xeb, 0x6f, 0x72, 0xae, 0x63, 0x7d, 0xc6, 0x55, 0x82, 0xb4, 0xa5, 0x73, 0x17, 0xf7, 0xd4, 0x0f, 0x4e, 0x38, 0x46, 0xbc, 0xcb, 0xe5, 0x23, 0x2e, 0x5f, 0xed, 0x97, 0x4e, 0x38, 0x40, 0x20, 0xb2, 0xe5, 0x66, 0xb7, 0x80, 0xbf, 0x8f, 0x3f, 0x04, 0x47, 0x1b, 0xe7, 0x82, 0xff, 0x25, 0x64, 0xda, 0xa9, 0x0a, 0x07, 0xfa, 0xab, 0x10, 0x70, 0x42, 0xce, 0x86, 0x9c, 0xe0, 0x68, 0x7a, 0x92, 0xe2, 0xc9, 0xcc, 0x1b, 0x33, 0x85, 0x79, 0xfb, 0x3e, 0xe4, 0x33, 0x65, 0x46, 0x8d, 0xd8, 0x6e, 0xac, 0x2d, 0xe8, 0xd3, 0x49, 0x44, 0x8e, 0x68, 0x53, 0x21, 0xe4, 0xdd, 0x7c, 0xe8, 0x5d, 0x45, 0xf4, 0x01,\n\t0x28, 0xa3, 0x20, 0x9a, 0x99, 0x82, 0x49, 0x24, 0xf3, 0x40, 0xf6, 0x84, 0x23, 0x97, 0xc0, 0xa5, 0x8e, 0x80, 0xdf, 0x9f, 0x59, 0xb2, 0x85, 0x3e, 0x00, 0x4c, 0x78, 0x1d, 0x9f, 0x25, 0x08, 0x3a, 0x04, 0xe9, 0x25, 0xc3, 0xc9, 0x10, 0x04, 0xd9, 0x03, 0x17, 0x24, 0x84, 0xd4, 0x4a, 0x61, 0x94, 0x99, 0x48, 0x41, 0xf1, 0x21, 0x4f, 0x8d, 0x9d, 0xf3, 0xe8, 0xd0, 0xd8, 0x82, 0xf7, 0xa8, 0xcd, 0xf4, 0x67, 0x97, 0xc5, 0xb0, 0x3d, 0x3a, 0x73, 0x50, 0xe2, 0x64, 0xca, 0xe1, 0x77, 0x1c, 0xf9, 0x9f, 0x34, 0x33, 0x29, 0x8e, 0x1c, 0x3d, 0x0e, 0xbb, 0x9e, 0xcf, 0xf5, 0xa1, 0x35, 0xe1, 0x3e, 0xe2, 0x0e, 0x00, 0xa5, 0x5e, 0x19, 0xe0, 0x03, 0x1d, 0x97, 0xd4, 0x38, 0x0e, 0x22, 0x9f, 0x51, 0xdd, 0xec, 0x41, 0xb1, 0x51, 0x2c, 0x36, 0x4a, 0xc9, 0xb3, 0xc6, 0x2f, 0x3e, 0x90, 0x48, 0x49, 0xf9,\n\t0xcf, 0x9f, 0xa2, 0x4e, 0x58, 0x67, 0xe7, 0xe6, 0xb5, 0xd9, 0xaf, 0xdc, 0x9c, 0x4c, 0x24, 0xca, 0x2d, 0x49, 0x07, 0xfd, 0x1b, 0x38, 0x9b, 0x9e, 0xf1, 0x7f, 0x30, 0x7f, 0x81, 0x38, 0x05, 0xe9, 0xf0, 0x43, 0x58, 0xc6, 0xc3, 0xe6, 0x5b, 0xd0, 0x9f, 0x4e, 0x62, 0x13, 0xc9, 0x98, 0x63, 0x0a, 0xc9, 0x66, 0xc8, 0xdf, 0x78, 0x94, 0x0a, 0x1e, 0xdf, 0x88, 0x6b, 0x16, 0x7b, 0x34, 0x24, 0x8f, 0x76, 0x39, 0xdd, 0x5e, 0x78, 0x64, 0x54, 0x31, 0x77, 0xa4, 0x80, 0xd6, 0xa9, 0xf8, 0x85, 0x53, 0x4b, 0x13, 0x93, 0x12, 0x32, 0x34, 0x76, 0x89, 0xfa, 0xef, 0x65, 0xaf, 0xb2, 0x5f, 0x3c, 0x70, 0x3f, 0xfb, 0xef, 0x57, 0x96, 0x2f, 0x7f, 0x05, 0xf0, 0xef, 0x7f, 0x00, 0xf0, 0x5e, 0x5d, 0xf6, 0x8b, 0xba, 0x9d, 0xe7, 0x6f, 0xb8, 0xe1, 0xfc, 0xae, 0xba, 0xba, 0x5d, 0xe8, 0x73, 0x67, 0x1d, 0x15,\n\t0x7a, 0x7a, 0xf6, 0x83, 0xec, 0xa7, 0x17, 0x86, 0x87, 0x2f, 0x00, 0xe9, 0x83, 0x0f, 0x00, 0xd9, 0x85, 0xd5, 0xab, 0x2f, 0xb0, 0x9f, 0x3c, 0xb0, 0xe3, 0xfb, 0x87, 0x9b, 0x9b, 0x0f, 0x7f, 0x7f, 0xc7, 0xce, 0xef, 0x1d, 0x6e, 0x6a, 0x3a, 0xfc, 0x3d, 0xb4, 0xbe, 0xc8, 0x9c, 0xd5, 0x86, 0xf5, 0x13, 0x90, 0x4e, 0x0b, 0x26, 0x56, 0x08, 0xf1, 0x64, 0x61, 0xb8, 0x2d, 0x61, 0x3b, 0x5a, 0x1d, 0x47, 0x2a, 0x21, 0x09, 0x5e, 0x20, 0xb4, 0xc9, 0x20, 0xc2, 0xb4, 0x9d, 0x33, 0xbb, 0x84, 0xec, 0xcd, 0x32, 0x93, 0x58, 0x94, 0x25, 0x63, 0xb7, 0xf2, 0x3d, 0xa6, 0xfb, 0xc9, 0x86, 0x6f, 0x9b, 0x75, 0xd4, 0x8f, 0xdc, 0x73, 0x73, 0x73, 0xe7, 0xba, 0xaf, 0xe4, 0xa9, 0x6d, 0x68, 0x23, 0x28, 0xa2, 0x13, 0xee, 0xe1, 0x21, 0xf8, 0x95, 0x22, 0xf8, 0x50, 0x62, 0x2b, 0x4a, 0x46, 0x21, 0x85, 0x80,\n\t0x78, 0x8f, 0xe9, 0xc7, 0xfb, 0xcf, 0x83, 0xa7, 0x34, 0xd4, 0x84, 0x0a, 0xc7, 0xe0, 0xbd, 0x0d, 0x93, 0xcd, 0x34, 0x0d, 0x25, 0x3b, 0x91, 0x50, 0x40, 0xf3, 0x69, 0x3e, 0xe4, 0x4e, 0x90, 0x4a, 0x5b, 0xc0, 0x87, 0x98, 0x10, 0x4a, 0xc2, 0xe8, 0x1f, 0xe2, 0xa9, 0xe8, 0x43, 0x97, 0xdf, 0xa1, 0xe3, 0x97, 0xdf, 0xf9, 0x1c, 0xf3, 0x63, 0xa7, 0x9e, 0x7f, 0xfe, 0xb2, 0xfe, 0xf9, 0xe7, 0xc9, 0x6d, 0x2f, 0xa5, 0x61, 0x86, 0x99, 0x85, 0xed, 0xfa, 0x88, 0xf7, 0x48, 0xe9, 0x9b, 0x42, 0x58, 0x33, 0x8f, 0xa6, 0x04, 0xa1, 0x86, 0xe6, 0x67, 0x71, 0x7e, 0x63, 0xf0, 0x1f, 0x33, 0xeb, 0xd2, 0x98, 0xfa, 0x3d, 0xfa, 0x78, 0x1a, 0x70, 0x00, 0x51, 0x09, 0xc7, 0xbb, 0x11, 0x7e, 0xf5, 0x20, 0xfe, 0x1e, 0xa9, 0xde, 0xac, 0x70, 0x35, 0xd4, 0xd8, 0xd8, 0x8a, 0x98, 0xfa, 0x54, 0x77, 0x48, 0xa3,\n\t0x9b, 0x1a, 0x30, 0x20, 0xdc, 0x2e, 0x43, 0x96, 0x5e, 0x4b, 0x78, 0x80, 0x87, 0xe1, 0x23, 0x46, 0xca, 0xeb, 0x43, 0x69, 0x5c, 0xac, 0x94, 0x56, 0x87, 0x2b, 0x84, 0xf2, 0x11, 0xfa, 0xe6, 0x04, 0x79, 0x21, 0x40, 0xd6, 0x40, 0x87, 0x16, 0xbc, 0x9d, 0xdf, 0xea, 0x0b, 0xd5, 0x58, 0x80, 0x5c, 0xa9, 0x95, 0xd0, 0x40, 0xeb, 0x62, 0xbf, 0x6b, 0x0d, 0x6a, 0xbd, 0xd5, 0x16, 0xf2, 0x9d, 0xcb, 0xef, 0xe8, 0x94, 0xe0, 0x47, 0xac, 0x53, 0x2c, 0xa3, 0xe3, 0xf4, 0x67, 0x7c, 0x81, 0xbe, 0xd0, 0xc9, 0x3e, 0xa3, 0xb1, 0x64, 0x69, 0x84, 0xfa, 0x02, 0x3f, 0xbb, 0xcf, 0xe5, 0x97, 0x32, 0xcc, 0xe9, 0xd9, 0x59, 0xb9, 0x2a, 0xd2, 0x45, 0xc6, 0x25, 0x76, 0xe5, 0x82, 0xd3, 0x1c, 0xaf, 0x51, 0x3d, 0x7e, 0x98, 0xd7, 0xc0, 0x93, 0x11, 0x22, 0x48, 0xd7, 0x72, 0xf1, 0x3a, 0x0b, 0x69, 0xe1, 0x28,\n\t0xc1, 0x63, 0x78, 0xeb, 0x04, 0x00, 0xd7, 0xfc, 0xa6, 0x01, 0xca, 0x6f, 0xc0, 0x30, 0x44, 0x37, 0xa2, 0x3e, 0x4c, 0x2f, 0x1f, 0x82, 0x28, 0xd3, 0x96, 0x9b, 0x93, 0xa5, 0x54, 0x66, 0xa1, 0xff, 0x14, 0x22, 0xbe, 0x25, 0xe4, 0xe1, 0xc2, 0x9d, 0x7c, 0xd8, 0x3d, 0xd1, 0x4a, 0xea, 0xd5, 0x5c, 0x7d, 0x5e, 0xbe, 0xd6, 0x15, 0xe5, 0x4a, 0x9c, 0xc6, 0xa3, 0x11, 0xea, 0xc9, 0x95, 0x67, 0x36, 0x55, 0x56, 0x6e, 0x3a, 0xb3, 0xf2, 0x9d, 0xcc, 0x97, 0x7b, 0x3f, 0xff, 0xfa, 0xc2, 0x85, 0x5f, 0xff, 0xfc, 0x5e, 0xfc, 0xa5, 0xef, 0xeb, 0x9f, 0x9f, 0x7c, 0xe7, 0x33, 0xd0, 0xbc, 0xf3, 0xcc, 0x92, 0xfe, 0xa7, 0x77, 0x36, 0x93, 0x64, 0xf3, 0xce, 0xa7, 0xfb, 0x97, 0x9c, 0xd9, 0xd9, 0x0c, 0xe8, 0x45, 0x60, 0xd9, 0xd7, 0x3f, 0xdc, 0xb3, 0xe7, 0x4f, 0xcf, 0x0c, 0x81, 0xd7, 0x5f, 0x07, 0x43,\n\t0xcf, 0xfc, 0x69, 0xcf, 0x9e, 0x0f, 0xbf, 0xbe, 0x0c, 0xbc, 0x8c, 0xf7, 0x6e, 0x31, 0x41, 0xf0, 0xf8, 0x78, 0xed, 0xb1, 0x6c, 0x47, 0x23, 0xd4, 0x43, 0x13, 0x03, 0x5c, 0x26, 0x98, 0xf4, 0xb9, 0x87, 0x2d, 0x3d, 0x84, 0x5b, 0xa9, 0xd4, 0x7b, 0x94, 0x4a, 0xad, 0x90, 0x6f, 0xe2, 0x12, 0x0a, 0xe1, 0xc2, 0x4e, 0x54, 0x54, 0x89, 0x2d, 0x15, 0x68, 0xe0, 0xca, 0x88, 0x12, 0x4e, 0x45, 0x59, 0x18, 0x8b, 0xf0, 0xf8, 0x6d, 0xa7, 0xfe, 0x78, 0xfc, 0xd2, 0xf1, 0x3f, 0xdc, 0xdb, 0x76, 0xd8, 0xe9, 0xc9, 0xee, 0x3f, 0x31, 0x7c, 0x69, 0xf8, 0xe4, 0x92, 0x6c, 0x8f, 0x93, 0x39, 0x35, 0x36, 0xbe, 0xe3, 0x07, 0x77, 0xcf, 0xe1, 0xb1, 0x0f, 0x83, 0x85, 0xbc, 0xb9, 0x77, 0xfd, 0x70, 0x3b, 0x09, 0x82, 0x36, 0xb6, 0x61, 0xe1, 0xed, 0x43, 0xc5, 0x0c, 0x75, 0xe7, 0x95, 0xd5, 0x4c, 0xf1, 0xd0,\n\t0xed, 0x0b, 0xc1, 0x37, 0x6c, 0x41, 0x38, 0xb6, 0xa5, 0x70, 0xc9, 0x3e, 0x66, 0x9e, 0x22, 0x4a, 0x89, 0xf9, 0x49, 0x89, 0x91, 0x47, 0x52, 0xa0, 0xc8, 0x4d, 0x12, 0xd8, 0x37, 0x0e, 0x45, 0xe7, 0x65, 0xa5, 0x73, 0x6c, 0x44, 0x9a, 0x78, 0x0c, 0x89, 0xf8, 0xb9, 0x14, 0xc4, 0x99, 0x26, 0x6e, 0x45, 0xa7, 0xdd, 0xc2, 0x86, 0x39, 0xd8, 0x61, 0x49, 0xc8, 0x15, 0x0c, 0xba, 0xf8, 0x7c, 0x43, 0xc8, 0x83, 0x8b, 0xc7, 0x46, 0x27, 0x87, 0x9c, 0xc1, 0xa9, 0x68, 0x1d, 0x48, 0x1f, 0xea, 0x40, 0xa5, 0x91, 0xa9, 0xc9, 0xbe, 0xa8, 0x08, 0xb0, 0x98, 0x8f, 0x7d, 0x8e, 0xb1, 0xcf, 0x5a, 0xf7, 0x0f, 0x14, 0xb7, 0xee, 0x3d, 0xdb, 0xdf, 0x7f, 0x76, 0x6f, 0x5b, 0xf1, 0xd2, 0xfd, 0xad, 0x63, 0x9f, 0x39, 0x7c, 0x40, 0xe1, 0x6b, 0xf7, 0xf7, 0x9e, 0x58, 0x9b, 0x58, 0xfd, 0xcd, 0xb1, 0xdb, 0x6f,\n\t0x1f, 0xfb, 0xe6, 0xea, 0xc4, 0xda, 0x13, 0xbd, 0xfe, 0x76, 0xdf, 0xf3, 0x6b, 0xac, 0xbe, 0xcf, 0x64, 0x7d, 0x47, 0xce, 0x2f, 0xdb, 0x74, 0x6e, 0x73, 0x59, 0xd9, 0xe6, 0x73, 0x9b, 0x96, 0x9d, 0x3f, 0xd2, 0x27, 0xfb, 0xcc, 0x67, 0x5d, 0x23, 0xe0, 0xd9, 0x36, 0x3c, 0xf0, 0x9d, 0x91, 0xbb, 0xfe, 0x85, 0x7a, 0xfa, 0xd7, 0x5d, 0x23, 0xdf, 0x79, 0x60, 0x83, 0x8d, 0x27, 0x48, 0xf9, 0x77, 0x8c, 0x7f, 0x42, 0x9f, 0xa4, 0xc5, 0x84, 0x86, 0x28, 0x27, 0xb6, 0x9d, 0x8f, 0xe6, 0x59, 0x29, 0x44, 0xd1, 0x38, 0x5a, 0x6c, 0xc0, 0x2a, 0x7f, 0x94, 0xa9, 0x39, 0x86, 0xca, 0xb7, 0xa0, 0x90, 0x12, 0xa4, 0xd4, 0x2b, 0xcc, 0x84, 0xfe, 0x5f, 0xa3, 0x41, 0x2e, 0x89, 0xc3, 0xdb, 0x19, 0x26, 0x27, 0x63, 0x34, 0x98, 0x7e, 0x1f, 0x99, 0xfa, 0xb4, 0x5a, 0x6d, 0xb9, 0xb6, 0xcc, 0xed, 0x47, 0x82,\n\t0xa1, 0x00, 0xa1, 0xcd, 0x89, 0xf2, 0xd1, 0x38, 0x91, 0x17, 0xc0, 0xf9, 0xe7, 0x91, 0xf5, 0x79, 0x5a, 0x16, 0xc2, 0x52, 0xc4, 0xbb, 0xe1, 0x66, 0x54, 0x8e, 0x3c, 0x27, 0xd1, 0x9a, 0x5b, 0xbc, 0xac, 0x35, 0xc7, 0x5f, 0x33, 0xbf, 0x20, 0xbf, 0xbb, 0x36, 0x47, 0x00, 0xf6, 0x55, 0x57, 0xf8, 0x1a, 0xca, 0x73, 0x65, 0xf6, 0xb6, 0xb9, 0xbd, 0xd9, 0x73, 0xee, 0x5c, 0x5d, 0x51, 0xbb, 0xf9, 0x91, 0xc5, 0x2b, 0xef, 0xcb, 0x57, 0x49, 0x7c, 0x1b, 0x62, 0xa4, 0x30, 0xcb, 0x1f, 0xb7, 0x93, 0xdf, 0x75, 0x94, 0xe7, 0x9a, 0x73, 0x16, 0xdd, 0x31, 0xb8, 0x70, 0xdf, 0x1c, 0xbf, 0xa7, 0x65, 0x63, 0x27, 0xfb, 0xad, 0x36, 0x63, 0x50, 0x1b, 0xae, 0xce, 0xcd, 0xaf, 0x0b, 0x6b, 0x6b, 0x77, 0xbd, 0xb2, 0xe1, 0xe6, 0xef, 0x1e, 0x6e, 0xe9, 0xae, 0x5a, 0xe4, 0x1b, 0xfb, 0x43, 0x7e, 0x5f, 0x20,\n\t0x58, 0xea, 0x51, 0x71, 0xeb, 0x75, 0x80, 0x3d, 0x46, 0xeb, 0x20, 0xbc, 0x58, 0x88, 0x62, 0xe2, 0x44, 0x52, 0x06, 0xb1, 0x26, 0x89, 0x88, 0x67, 0x1c, 0x1e, 0x3a, 0x2a, 0x05, 0x33, 0x4e, 0xc4, 0xfe, 0x43, 0xa4, 0x3b, 0x90, 0x36, 0x72, 0x46, 0x32, 0x45, 0xc2, 0x0b, 0x51, 0xda, 0xe2, 0xbc, 0x4c, 0xaa, 0x92, 0xab, 0x5a, 0x46, 0xaf, 0x6e, 0x09, 0x1b, 0xa1, 0xc3, 0xfe, 0x25, 0x2d, 0x71, 0x71, 0x0d, 0x49, 0x71, 0x51, 0xac, 0x30, 0xe0, 0x75, 0xf8, 0x9d, 0x08, 0xe0, 0x52, 0x4e, 0x15, 0x08, 0xdc, 0x42, 0x20, 0x1a, 0x49, 0x67, 0xe3, 0x84, 0x8b, 0xeb, 0x9b, 0xf0, 0xae, 0xe0, 0xa7, 0x6b, 0x74, 0xfb, 0x94, 0x2e, 0xd0, 0x14, 0x5c, 0xd6, 0x3a, 0x6b, 0x4d, 0xa3, 0x27, 0xbf, 0x73, 0x6d, 0x45, 0x85, 0xaf, 0x68, 0x41, 0x95, 0x7b, 0x64, 0xa0, 0x74, 0x6e, 0x91, 0xe9, 0x42, 0xe1, 0x8a,\n\t0x07, 0x87, 0x87, 0xee, 0x5a, 0x9c, 0x3b, 0x3a, 0x34, 0x6b, 0xb4, 0x2d, 0x90, 0x58, 0xff, 0xc8, 0xe0, 0x53, 0x4b, 0x2f, 0x00, 0xa2, 0xac, 0x24, 0xb7, 0x63, 0x75, 0xa2, 0x79, 0x79, 0xc2, 0x7c, 0xaf, 0xbe, 0xb0, 0xa3, 0x6c, 0xe4, 0x86, 0xd0, 0xe2, 0x63, 0xc3, 0xbc, 0x1d, 0x6f, 0x1d, 0x6c, 0x28, 0x5d, 0xb2, 0xbd, 0x66, 0xe4, 0x7e, 0x97, 0xaa, 0xa6, 0x7f, 0x53, 0x5d, 0xf7, 0xd7, 0x36, 0xd4, 0xad, 0x61, 0xe3, 0x10, 0x8f, 0xad, 0x86, 0x70, 0xe6, 0x61, 0x9e, 0x26, 0xe4, 0x78, 0xe5, 0x56, 0x25, 0x45, 0x16, 0x80, 0x92, 0x69, 0x71, 0xc6, 0x65, 0x04, 0x6c, 0x6e, 0xe4, 0xa6, 0x03, 0x8f, 0xdf, 0x08, 0x9e, 0x27, 0xb1, 0x06, 0x62, 0xe1, 0x54, 0x0a, 0xde, 0x34, 0x0c, 0x0d, 0x23, 0xcb, 0xdb, 0x57, 0x37, 0xc3, 0x95, 0xd7, 0x85, 0x7e, 0xbf, 0x36, 0xa0, 0x77, 0xa3, 0xcc, 0x1a, 0xa9,\n\t0x5c, 0x2b, 0x70, 0x2d, 0x80, 0x93, 0x8f, 0xc3, 0x3e, 0xb9, 0x24, 0x0a, 0x9e, 0xc9, 0x25, 0xca, 0x55, 0x99, 0x94, 0x2b, 0x20, 0x44, 0xf9, 0xea, 0x06, 0x2b, 0x93, 0xc3, 0xad, 0xe1, 0xdc, 0x9e, 0x1d, 0xb3, 0x79, 0xcd, 0x43, 0xe5, 0xc6, 0xd6, 0xd6, 0xca, 0x75, 0xbd, 0x65, 0x42, 0xf0, 0xc3, 0xba, 0x35, 0xcd, 0xfe, 0x96, 0xbd, 0xcf, 0x0f, 0x6d, 0xf8, 0xfa, 0x68, 0xbc, 0xf3, 0xae, 0xef, 0x6d, 0x9c, 0xb7, 0xa5, 0xc5, 0xb5, 0x9c, 0x1c, 0xdc, 0xfa, 0xfc, 0xba, 0x58, 0x64, 0xc1, 0xce, 0xd6, 0xd6, 0x91, 0x12, 0xe7, 0x09, 0x5b, 0x7d, 0x73, 0x9b, 0xaf, 0xb6, 0xb5, 0x0c, 0x12, 0xe4, 0x01, 0xaa, 0x64, 0xe9, 0x81, 0xd9, 0x37, 0xbe, 0xbc, 0xab, 0x76, 0xc1, 0x53, 0xff, 0x3c, 0xfe, 0x1d, 0x90, 0xf3, 0xfd, 0xe5, 0x91, 0x8e, 0x65, 0x85, 0xf3, 0xee, 0xe0, 0x78, 0xe3, 0x00, 0x7b, 0x86,\n\t0xce, 0x86, 0x74, 0x11, 0xdb, 0x6f, 0x91, 0x4f, 0x82, 0x49, 0xc0, 0x50, 0x68, 0x45, 0xb0, 0x61, 0x11, 0x45, 0x39, 0x90, 0xb1, 0x26, 0x5c, 0xdd, 0x00, 0x61, 0x47, 0x17, 0xe1, 0xf4, 0xf8, 0x74, 0x0c, 0xe2, 0x8d, 0x64, 0x14, 0xc6, 0x8b, 0x4c, 0x28, 0xe5, 0x69, 0x61, 0x05, 0x2a, 0x7d, 0x05, 0x85, 0xa4, 0x08, 0x3a, 0xdb, 0x3c, 0x77, 0x78, 0x7b, 0xcd, 0x05, 0x5d, 0x5e, 0xbc, 0xbc, 0xb6, 0x2d, 0xec, 0x15, 0xe8, 0x7c, 0xb6, 0xbe, 0x23, 0xc3, 0x2d, 0xa6, 0x9c, 0xd6, 0x44, 0xbe, 0x8a, 0xe7, 0xd4, 0x50, 0x9f, 0x6f, 0xf9, 0xd7, 0x47, 0xbf, 0x1e, 0x64, 0xe7, 0x82, 0xaf, 0xaf, 0x7c, 0xfb, 0x99, 0xdb, 0x97, 0x17, 0xcf, 0x92, 0x9b, 0x34, 0x92, 0xe5, 0x6f, 0xb2, 0xbf, 0x3d, 0xdf, 0xfc, 0xe4, 0xf3, 0xe7, 0x7b, 0xbc, 0x26, 0x0e, 0xce, 0x9b, 0xc7, 0x3f, 0xa5, 0x79, 0xcc, 0x63, 0x90,\n\t0xcb, 0xaa, 0x21, 0x96, 0x27, 0xc5, 0x35, 0x80, 0xa4, 0xa3, 0x22, 0x72, 0x62, 0xbb, 0xac, 0xc8, 0x8f, 0x02, 0x6e, 0xc0, 0x48, 0xda, 0xd7, 0x27, 0xd4, 0x84, 0xbc, 0xec, 0x30, 0x5b, 0x54, 0x88, 0xe4, 0xdd, 0x2f, 0x6b, 0x90, 0x8b, 0xfc, 0xbe, 0x95, 0x90, 0x28, 0x57, 0xe4, 0x84, 0x2d, 0x26, 0xbd, 0x0e, 0x9b, 0x77, 0xf9, 0x5c, 0x11, 0x79, 0x4c, 0xa6, 0x38, 0x2a, 0x35, 0xd9, 0x25, 0x6b, 0x5a, 0x8a, 0xd8, 0x0c, 0xc2, 0xd4, 0x93, 0xa1, 0x8a, 0x65, 0x8d, 0x81, 0x9c, 0xe6, 0x81, 0x58, 0xd1, 0x50, 0x6b, 0xae, 0xb3, 0x76, 0x39, 0xb8, 0x8f, 0x32, 0x18, 0x64, 0xc9, 0xce, 0x05, 0x81, 0xae, 0xba, 0xd8, 0xfc, 0xd1, 0x0d, 0xa3, 0xf3, 0x63, 0x55, 0x37, 0x9f, 0x5d, 0x3d, 0xfa, 0xdc, 0x96, 0xe4, 0x73, 0xcf, 0x65, 0xcf, 0x2e, 0x75, 0xf9, 0xe7, 0xee, 0x5e, 0xe0, 0xea, 0xe9, 0x5b, 0xe8,\n\t0x3b, 0x18, 0x6a, 0x5f, 0x3f, 0xab, 0x6d, 0xd3, 0xa2, 0x26, 0xbb, 0x36, 0xb1, 0x70, 0x5b, 0x47, 0xf5, 0xc6, 0xf9, 0x51, 0x7a, 0xbb, 0x51, 0x29, 0x57, 0xca, 0x23, 0x6e, 0x67, 0x69, 0x49, 0xa2, 0x69, 0xe1, 0xc6, 0x63, 0x8b, 0x97, 0x9f, 0xb9, 0xb9, 0xb6, 0x61, 0xc7, 0xd3, 0x83, 0xa7, 0xff, 0x92, 0x30, 0x15, 0x55, 0xb5, 0x15, 0x14, 0xce, 0xab, 0xf4, 0x30, 0x22, 0x99, 0x10, 0xee, 0x5f, 0xc7, 0xf8, 0xa7, 0xd4, 0x02, 0x9c, 0x4f, 0x63, 0x5f, 0x52, 0x84, 0xbc, 0x38, 0xa5, 0xb8, 0xf4, 0x36, 0xb7, 0x40, 0xd9, 0x04, 0x09, 0xc5, 0x40, 0x92, 0x1e, 0xc9, 0x14, 0x2b, 0x87, 0x0c, 0x12, 0x9f, 0x66, 0x06, 0xd2, 0x0e, 0xd4, 0x31, 0x9c, 0xc2, 0xbc, 0x17, 0xd7, 0xbb, 0xc4, 0x09, 0x5d, 0xaf, 0xbb, 0x7d, 0x2e, 0xa2, 0x31, 0xaa, 0xb2, 0x92, 0x78, 0x34, 0x37, 0x3b, 0x1c, 0x74, 0x3b, 0x6d,\n\t0x96, 0x2c, 0x9d, 0x1b, 0x71, 0x53, 0x9e, 0x34, 0xa6, 0x9c, 0x58, 0xa1, 0x54, 0xf1, 0x87, 0x4c, 0xa4, 0x73, 0x29, 0xe4, 0x4a, 0xd2, 0x96, 0x59, 0x2e, 0x30, 0x6c, 0x81, 0x6b, 0x5e, 0xff, 0x60, 0x7e, 0xe7, 0x5d, 0x23, 0x95, 0x43, 0x73, 0xb2, 0x2b, 0xfc, 0xaa, 0x82, 0x81, 0xbb, 0x07, 0x46, 0x1f, 0x29, 0x0e, 0x8b, 0xd5, 0x32, 0x99, 0x27, 0xde, 0x5e, 0x1c, 0x6d, 0x8b, 0x1a, 0x37, 0xae, 0x7e, 0xe4, 0x91, 0x2d, 0x37, 0x59, 0x8b, 0x3b, 0x0a, 0x93, 0x73, 0x4b, 0x7c, 0xea, 0x2c, 0xe9, 0xed, 0xa1, 0x32, 0xaf, 0x32, 0xd8, 0x76, 0x43, 0x7d, 0xf7, 0x66, 0xbb, 0x2a, 0x52, 0x56, 0x69, 0x8b, 0x0d, 0x34, 0x67, 0xd7, 0xc4, 0x9a, 0x94, 0x62, 0xbd, 0x59, 0xaf, 0xf3, 0x46, 0x2c, 0xc9, 0xf6, 0x5d, 0x73, 0xeb, 0x3d, 0x89, 0x1c, 0xa3, 0xcd, 0x6d, 0x53, 0xc1, 0xb5, 0x6a, 0x61, 0xcf, 0x53,\n\t0xc5, 0x90, 0x07, 0x88, 0x23, 0x1b, 0x51, 0x18, 0xeb, 0xbc, 0x8d, 0x06, 0x92, 0xa8, 0x4f, 0x8b, 0x0b, 0x21, 0xa2, 0x39, 0x1e, 0xcb, 0xcf, 0x26, 0x11, 0xa7, 0xa5, 0x43, 0x52, 0x07, 0x83, 0x69, 0x24, 0x3a, 0xa3, 0xd8, 0x66, 0x8e, 0xc1, 0x22, 0xc5, 0xaa, 0x20, 0x66, 0x15, 0xce, 0x08, 0xd2, 0x4e, 0x2a, 0x44, 0x32, 0x59, 0x61, 0x4f, 0x78, 0x69, 0x7f, 0x4f, 0xb5, 0xdf, 0x59, 0xb3, 0xa4, 0x72, 0xe1, 0xba, 0xa4, 0x2e, 0xdb, 0x7f, 0x5c, 0xed, 0x96, 0x85, 0x3b, 0x6a, 0xe6, 0xee, 0xeb, 0xcd, 0x6d, 0xbd, 0xe5, 0x5b, 0x23, 0x89, 0x83, 0x0d, 0x37, 0xe8, 0xac, 0x6a, 0x21, 0x79, 0x0f, 0xd3, 0x28, 0xce, 0x72, 0x16, 0xb8, 0x83, 0xfd, 0xab, 0x37, 0xee, 0x3c, 0x34, 0xab, 0x72, 0x61, 0x55, 0xae, 0xc6, 0x5c, 0x51, 0xdd, 0xe8, 0xaf, 0xde, 0x9e, 0x2c, 0xb5, 0x77, 0x05, 0xd5, 0x5e, 0xaf,\n\t0x57, 0x63, 0xac, 0xe9, 0xdf, 0x35, 0x6f, 0xdd, 0xa5, 0x77, 0xbf, 0xbf, 0x52, 0x20, 0x94, 0xa8, 0xf4, 0xe2, 0xc5, 0xf8, 0xac, 0xaa, 0xd8, 0xa7, 0x68, 0x1d, 0xdc, 0x6b, 0x3b, 0x91, 0x83, 0x6a, 0x9a, 0x52, 0x84, 0x41, 0x40, 0xd2, 0x19, 0x67, 0x0b, 0xc4, 0x59, 0xc7, 0x90, 0xed, 0x36, 0x8c, 0x4c, 0xe2, 0x79, 0x64, 0x33, 0x2a, 0x5e, 0xea, 0x76, 0x23, 0x61, 0x40, 0x3d, 0x35, 0xa7, 0xd3, 0x64, 0x37, 0x8b, 0x42, 0x6f, 0x08, 0xa8, 0xc4, 0x06, 0x9f, 0xb9, 0x63, 0xb3, 0xb1, 0xf6, 0xec, 0xea, 0x49, 0x9e, 0xef, 0xc9, 0x64, 0x98, 0xfa, 0xb6, 0x34, 0x4b, 0x2d, 0x6e, 0x6e, 0x9f, 0x35, 0x1f, 0x79, 0xba, 0x5f, 0x71, 0x53, 0x1f, 0x70, 0xf9, 0xcf, 0xc8, 0x5f, 0x35, 0xd5, 0x43, 0x7c, 0x3a, 0x0c, 0xf1, 0x69, 0x25, 0xc4, 0xa7, 0x3c, 0x28, 0xe1, 0x39, 0x50, 0xa6, 0x5a, 0x3e, 0x4a, 0xa6,\n\t0x0f, 0xf9, 0x5a, 0x28, 0x9d, 0xa0, 0x03, 0x07, 0x99, 0xc3, 0xc9, 0x74, 0x87, 0x69, 0x96, 0xcb, 0x90, 0x60, 0x68, 0xd0, 0xcb, 0x1c, 0x72, 0x07, 0x5f, 0xca, 0x97, 0x8a, 0x85, 0xf0, 0x59, 0x9e, 0x53, 0x88, 0x98, 0x70, 0x15, 0xf6, 0xed, 0xf2, 0xa1, 0x48, 0x64, 0x1e, 0x05, 0x10, 0x3a, 0xd1, 0x6a, 0x48, 0x0c, 0x36, 0x80, 0xc3, 0x8d, 0x20, 0xcc, 0x3f, 0x71, 0xeb, 0xa1, 0x13, 0x7c, 0x20, 0x3a, 0xbe, 0xff, 0xc0, 0x09, 0x11, 0x08, 0x8d, 0xbc, 0xb8, 0xbd, 0xb6, 0x16, 0x25, 0x41, 0x3b, 0x87, 0x92, 0xa0, 0x9d, 0x23, 0x8f, 0xb1, 0xff, 0xb8, 0x72, 0x05, 0xc8, 0x0f, 0x00, 0xf2, 0xd3, 0x4f, 0x59, 0x96, 0x3c, 0xbc, 0xe8, 0x25, 0xf6, 0x6f, 0xcf, 0xbf, 0xc0, 0xfe, 0xf5, 0xa5, 0xbe, 0xbe, 0x97, 0x80, 0xfa, 0x85, 0xe7, 0x81, 0xea, 0xa5, 0x45, 0x18, 0xaf, 0xa0, 0xd8, 0xbf, 0x4f, 0x98,\n\t0x27, 0xa1, 0xfc, 0x56, 0x43, 0x24, 0x92, 0x65, 0x50, 0x06, 0x84, 0x68, 0x86, 0x46, 0x99, 0x04, 0x70, 0x59, 0x9b, 0x55, 0x4d, 0x28, 0x53, 0x3e, 0xd1, 0x8b, 0xfc, 0x8e, 0x50, 0xe6, 0x70, 0x1e, 0x8f, 0x4b, 0x39, 0x44, 0x35, 0x0b, 0x85, 0xc2, 0x1a, 0x61, 0x8d, 0x5f, 0x17, 0x70, 0xf9, 0xbc, 0x1e, 0xa7, 0x4a, 0x8c, 0x0b, 0x46, 0x41, 0xd6, 0x09, 0x39, 0x1a, 0x40, 0x58, 0xe1, 0x85, 0x90, 0x5f, 0x1a, 0x37, 0x68, 0x08, 0x19, 0x68, 0x69, 0xb1, 0x73, 0x1e, 0x4a, 0x03, 0x90, 0xd6, 0xb6, 0x16, 0xfa, 0x26, 0xe1, 0x0d, 0xf0, 0xe7, 0x1f, 0xbd, 0x6d, 0xdd, 0xb1, 0xac, 0xa1, 0x89, 0x12, 0xd8, 0x1c, 0x03, 0xbc, 0xf2, 0xad, 0xaf, 0x6e, 0x1b, 0x3a, 0x3e, 0x98, 0x1f, 0x2a, 0xad, 0xa8, 0x49, 0xe6, 0x77, 0x96, 0xbb, 0x4c, 0xf1, 0xae, 0xe2, 0xea, 0xb5, 0x6d, 0x61, 0xde, 0xa1, 0xdf, 0x7c,\n\t0x6d, 0x6e, 0x70, 0xf6, 0xba, 0xc6, 0xee, 0x3b, 0x6f, 0x9c, 0xa3, 0xa7, 0xef, 0x9f, 0xd7, 0x44, 0x1f, 0x38, 0x59, 0xf3, 0xab, 0xb6, 0x2c, 0x7f, 0x6d, 0xdb, 0x53, 0xec, 0x5f, 0x5f, 0x5b, 0x96, 0x58, 0xff, 0xd0, 0x92, 0x97, 0x12, 0x25, 0x6d, 0xc6, 0x80, 0xa9, 0x62, 0xa8, 0xf9, 0xa5, 0xc4, 0x8a, 0xa6, 0x40, 0xe2, 0x96, 0xff, 0x7e, 0xb0, 0xad, 0x16, 0xf8, 0x5a, 0x37, 0xcc, 0x8e, 0x2f, 0xae, 0xf3, 0x47, 0x57, 0x3d, 0xbc, 0x16, 0xc1, 0xd0, 0xce, 0xf1, 0x7f, 0x92, 0x28, 0x7f, 0xa3, 0x32, 0x25, 0xf7, 0xe6, 0x64, 0x3c, 0x48, 0x20, 0x47, 0xe4, 0x71, 0x61, 0x99, 0x55, 0x8d, 0x4c, 0xd2, 0xa5, 0x20, 0x83, 0xec, 0x76, 0x5e, 0x4c, 0xd4, 0xcd, 0x31, 0x86, 0x4b, 0xed, 0x15, 0x8b, 0x92, 0x76, 0xea, 0xf3, 0x31, 0xf7, 0xac, 0x96, 0x32, 0xad, 0x5d, 0x27, 0x0e, 0x36, 0xad, 0x48, 0xa0,\n\t0x3e, 0x7d, 0xe3, 0x9f, 0xd1, 0x15, 0x70, 0x3d, 0xc3, 0xc4, 0x2f, 0x92, 0x62, 0x2b, 0xa4, 0x8c, 0x3a, 0x29, 0x49, 0x93, 0x69, 0x24, 0xa4, 0x4f, 0xfb, 0x8e, 0x45, 0x9a, 0x18, 0x9c, 0xa1, 0x11, 0x01, 0x6a, 0x2e, 0x56, 0xa9, 0x48, 0x26, 0xdf, 0x8e, 0x4e, 0xba, 0x5d, 0x48, 0xa4, 0x53, 0x53, 0xcc, 0x78, 0x3b, 0x37, 0xa3, 0x90, 0xf9, 0x92, 0xce, 0xc3, 0x5f, 0xf6, 0x74, 0xd2, 0x34, 0x71, 0x07, 0xf1, 0xfe, 0xa9, 0xdb, 0x29, 0xc4, 0x86, 0x0b, 0x74, 0xa3, 0x40, 0x98, 0x30, 0x11, 0xf2, 0x78, 0x73, 0x5c, 0x3c, 0x28, 0xd6, 0x79, 0xd2, 0x9c, 0x20, 0xc5, 0x89, 0xab, 0x58, 0x61, 0x07, 0xa8, 0x1c, 0x2a, 0x43, 0x00, 0x49, 0xe4, 0xff, 0x1f, 0xa1, 0x2b, 0x0a, 0x72, 0x03, 0x6d, 0xf5, 0x65, 0xda, 0x27, 0x05, 0x22, 0x92, 0x91, 0x0a, 0x3e, 0xe2, 0x9b, 0x0d, 0x8f, 0x81, 0x43, 0x4b, 0xc4,\n\t0x06, 0x77, 0xbe, 0x6b, 0x96, 0xd8, 0x94, 0xe3, 0x0e, 0x75, 0xd4, 0x97, 0xa8, 0xc1, 0x2e, 0x4d, 0xa2, 0xf8, 0x40, 0x5b, 0xc0, 0xa4, 0x08, 0x37, 0x97, 0x81, 0xf3, 0x7a, 0x9f, 0x5a, 0xed, 0xd3, 0x8c, 0xbd, 0x20, 0xcf, 0xa2, 0xbe, 0x06, 0x14, 0xd6, 0x40, 0x96, 0x08, 0xd3, 0x44, 0x45, 0xa0, 0xa6, 0xf0, 0xf2, 0x17, 0xc5, 0x05, 0x1c, 0xad, 0x3e, 0x00, 0xcf, 0xff, 0x93, 0x70, 0xef, 0x3c, 0xc4, 0x2f, 0x38, 0xde, 0x57, 0x6c, 0x13, 0x42, 0x04, 0x20, 0x03, 0x04, 0x0f, 0xe7, 0xae, 0x4b, 0x5d, 0x01, 0x5e, 0x46, 0x93, 0xe5, 0x42, 0xa8, 0x21, 0x87, 0xcb, 0xa1, 0x88, 0xd7, 0xb5, 0x09, 0xa5, 0x8e, 0x4b, 0x7f, 0xe7, 0xd0, 0x44, 0x6a, 0xa1, 0xa7, 0x37, 0xcd, 0x9d, 0xd4, 0x34, 0x77, 0xa2, 0xa9, 0xf1, 0x7a, 0x9a, 0x16, 0x21, 0xe6, 0xdb, 0x91, 0x69, 0x85, 0x49, 0x47, 0x38, 0xd5, 0x88,\n\t0x98, 0x68, 0xd3, 0xc3, 0x39, 0xdb, 0x21, 0x99, 0x4b, 0xed, 0x52, 0x7b, 0xbc, 0x2e, 0xc4, 0x81, 0x67, 0xd6, 0x19, 0x1d, 0x23, 0x28, 0xed, 0x62, 0xaf, 0xf3, 0x29, 0xa1, 0x3b, 0xf0, 0x0b, 0xfd, 0x64, 0x75, 0x45, 0xb0, 0x25, 0x99, 0x23, 0x2e, 0xbd, 0xbb, 0xef, 0xd6, 0x26, 0x3e, 0xd3, 0x1f, 0xcc, 0xbe, 0x38, 0x38, 0x34, 0x6f, 0x77, 0xe8, 0x62, 0x73, 0xe2, 0x40, 0xab, 0x31, 0x98, 0x15, 0x69, 0x89, 0xf6, 0x2c, 0xe9, 0x0a, 0xce, 0x75, 0xb3, 0x9f, 0x86, 0x02, 0xf4, 0xbf, 0xc7, 0xee, 0x1b, 0xde, 0xd1, 0x3f, 0x97, 0x3c, 0x3e, 0xe6, 0x6c, 0xaa, 0x9f, 0x88, 0x35, 0xf9, 0x08, 0xae, 0xa5, 0x1e, 0xd9, 0x4b, 0xe4, 0x13, 0xfe, 0x13, 0x58, 0x5c, 0x08, 0xa7, 0x3c, 0x36, 0x74, 0x0e, 0x2d, 0xcd, 0xd7, 0x85, 0x00, 0x4f, 0x04, 0x78, 0xfc, 0x49, 0xf1, 0x39, 0x98, 0xcd, 0xa1, 0x3e, 0xb2,\n\t0xf5, 0xae, 0x3b, 0xd4, 0xba, 0x89, 0x1d, 0x7c, 0x40, 0x6f, 0x63, 0x3e, 0x91, 0xaa, 0x04, 0x91, 0xd9, 0x89, 0x3c, 0x0d, 0x83, 0xf8, 0x9b, 0x43, 0xec, 0xc7, 0x2c, 0xfb, 0x8f, 0x55, 0x99, 0xa0, 0x97, 0xd6, 0x73, 0x6f, 0xbc, 0xbd, 0xd8, 0x61, 0x84, 0xef, 0x6d, 0x85, 0x34, 0x08, 0xa9, 0x2f, 0xaa, 0x90, 0x1c, 0x5a, 0x08, 0x65, 0x7f, 0xd0, 0xe8, 0x74, 0x90, 0x64, 0x3d, 0x66, 0x25, 0xc9, 0x45, 0x14, 0x2e, 0xa3, 0x85, 0x38, 0x15, 0xa2, 0xb9, 0xaa, 0xb2, 0xa2, 0xcc, 0xe1, 0x2d, 0xc0, 0xdc, 0x16, 0xc2, 0x2d, 0x93, 0x88, 0x67, 0x4a, 0x7a, 0x9b, 0x91, 0x32, 0xa5, 0x52, 0xd7, 0x63, 0x47, 0x17, 0x07, 0x25, 0xc8, 0xb3, 0xf4, 0x54, 0x0e, 0x37, 0x07, 0x8f, 0xec, 0xef, 0x3d, 0xd8, 0xb0, 0xa2, 0xd6, 0xe1, 0x6d, 0x59, 0xdf, 0x9a, 0xec, 0x2a, 0xd0, 0x20, 0x02, 0xe5, 0x91, 0xd8, 0x8a,\n\t0xb2, 0x5b, 0x8f, 0xac, 0xae, 0xca, 0x8a, 0x75, 0x27, 0x3b, 0xe7, 0xda, 0xe2, 0x8d, 0xa1, 0x33, 0x61, 0x37, 0xf9, 0x0c, 0xd3, 0xe8, 0x0a, 0xf8, 0x6a, 0x16, 0xc4, 0x7a, 0x97, 0xdc, 0xeb, 0xac, 0x98, 0x5b, 0x18, 0x6b, 0x2d, 0x2f, 0x34, 0xeb, 0x0b, 0x8a, 0xab, 0x7c, 0xb3, 0x76, 0x27, 0xcb, 0xec, 0x9d, 0x01, 0xad, 0xc7, 0x61, 0x91, 0xea, 0x12, 0x8b, 0xf7, 0x2d, 0xcc, 0x5d, 0xb2, 0xa0, 0xc5, 0xe8, 0xde, 0x3c, 0x27, 0xb7, 0xa3, 0xb6, 0x58, 0x1b, 0x70, 0xcd, 0xe2, 0xd6, 0xb6, 0x09, 0xce, 0xd1, 0x0c, 0xe7, 0x58, 0x4e, 0xe4, 0x25, 0xb3, 0x3d, 0x88, 0x1e, 0x34, 0xaa, 0x55, 0x88, 0xce, 0x52, 0x34, 0x40, 0xe9, 0x9e, 0x33, 0x85, 0x16, 0x90, 0x86, 0xa3, 0xac, 0xa4, 0x30, 0x3f, 0x27, 0x4c, 0x94, 0x83, 0x72, 0xce, 0x54, 0xf4, 0xd5, 0x53, 0x43, 0x98, 0x69, 0xf2, 0x72, 0x90, 0xee,\n\t0xe9, 0x13, 0x73, 0x8b, 0xed, 0x71, 0x3c, 0x31, 0x43, 0x49, 0x5f, 0x6d, 0xef, 0xa2, 0xc4, 0x8d, 0x8f, 0xaf, 0x78, 0x29, 0xcf, 0xb2, 0xac, 0x76, 0x79, 0x9d, 0xeb, 0xe8, 0xbe, 0x05, 0xe4, 0x13, 0x5f, 0x31, 0xab, 0xbc, 0xa1, 0xbe, 0x56, 0x83, 0xe7, 0xf0, 0xca, 0x9e, 0x5b, 0x17, 0x47, 0xda, 0x5d, 0x01, 0x47, 0x49, 0x7b, 0xfe, 0xaa, 0x75, 0xf7, 0x72, 0x73, 0x9b, 0x35, 0xfe, 0x39, 0x7d, 0x82, 0xfa, 0x98, 0x88, 0x03, 0xcb, 0x8b, 0xf9, 0x80, 0xe0, 0xa7, 0xe5, 0x54, 0x33, 0x83, 0xcd, 0xfd, 0x80, 0x1c, 0xc1, 0xd1, 0x87, 0xd8, 0xe1, 0x39, 0x07, 0xe7, 0xe5, 0xcd, 0xc5, 0xe7, 0x46, 0xfc, 0xa5, 0x6d, 0xc2, 0x64, 0x1a, 0x1d, 0x7e, 0x55, 0x3f, 0xca, 0xeb, 0xe8, 0x47, 0x7d, 0x1d, 0xfd, 0x68, 0xb1, 0xe8, 0xc7, 0x20, 0xcf, 0x15, 0x24, 0xc7, 0xa0, 0x96, 0x6b, 0x66, 0xea, 0xed, 0x2b,\n\t0x1b, 0x61, 0x41, 0x1a, 0x23, 0x4c, 0xb1, 0x47, 0xe3, 0xd5, 0xe9, 0x5d, 0x01, 0xa7, 0x80, 0x6f, 0xe6, 0x20, 0x16, 0x4b, 0xc8, 0x74, 0x29, 0x27, 0x44, 0x73, 0x31, 0x23, 0x0e, 0x1e, 0xc9, 0x31, 0x88, 0xe5, 0x48, 0x3a, 0x04, 0xaa, 0xb8, 0x0b, 0x63, 0x4f, 0x07, 0x7d, 0xc2, 0x6e, 0x3b, 0x0c, 0x00, 0x5f, 0xa1, 0xb3, 0xfb, 0xb2, 0xfc, 0x0d, 0xb1, 0x2d, 0x1b, 0x04, 0x22, 0x31, 0xc5, 0x9e, 0xa2, 0xf5, 0xde, 0x48, 0x62, 0x56, 0x40, 0x6a, 0xc9, 0x92, 0x6b, 0xac, 0xe5, 0x11, 0x37, 0xef, 0xe7, 0x22, 0xb5, 0x59, 0x45, 0x33, 0xd4, 0x9d, 0x46, 0x77, 0x76, 0xbb, 0xff, 0xe6, 0x67, 0x37, 0x37, 0xfa, 0xa4, 0xad, 0x0e, 0xe7, 0xe3, 0xe7, 0xb3, 0x97, 0x6d, 0xb9, 0x6b, 0xfe, 0x19, 0xf6, 0x8b, 0x6f, 0xef, 0x68, 0xb6, 0xd3, 0x42, 0xb9, 0x68, 0x5f, 0xe3, 0xc3, 0x80, 0xff, 0xcd, 0x4e, 0x89,\n\t0x41, 0x8b, 0x1c, 0x2b, 0xb7, 0x40, 0xdc, 0x69, 0xa0, 0x85, 0x84, 0x02, 0x62, 0x9b, 0xdc, 0x64, 0x18, 0x49, 0x7d, 0x2e, 0xec, 0x6a, 0x99, 0x26, 0x7f, 0xb1, 0x8c, 0x03, 0x65, 0x21, 0xc2, 0x59, 0x79, 0x74, 0xb3, 0xda, 0x1f, 0xf0, 0x3a, 0x99, 0xb4, 0x24, 0x1b, 0xcb, 0xe8, 0x4d, 0x5c, 0x53, 0x6c, 0x4b, 0x28, 0x33, 0x22, 0x48, 0x14, 0xec, 0xac, 0xd9, 0x77, 0xa7, 0xaf, 0x7e, 0x49, 0x69, 0x6c, 0x71, 0x5d, 0xe0, 0x62, 0xc5, 0x86, 0x27, 0x57, 0xf5, 0x3f, 0xb9, 0xa3, 0x11, 0x25, 0x02, 0x9c, 0x77, 0x67, 0xf1, 0x45, 0x20, 0xa9, 0xad, 0xe0, 0x92, 0x00, 0xfa, 0x9a, 0xd7, 0xd6, 0x2f, 0x7b, 0x7c, 0x43, 0xb2, 0x76, 0xcf, 0xeb, 0x37, 0xa3, 0xec, 0x88, 0x15, 0xc5, 0x6c, 0x15, 0x91, 0xce, 0x25, 0x7b, 0x96, 0xfa, 0x27, 0x1c, 0x9f, 0x1f, 0x69, 0x07, 0x55, 0x48, 0xa7, 0xd6, 0x48, 0x32,\n\t0x24, 0xf6, 0x8a, 0x84, 0xb4, 0x29, 0x27, 0xe3, 0xf1, 0x08, 0x25, 0x1b, 0x25, 0x94, 0x5b, 0x94, 0x7e, 0xa5, 0xcf, 0x66, 0xc1, 0x05, 0x2f, 0x14, 0x40, 0xc1, 0xe7, 0xa7, 0xcf, 0x8e, 0x2e, 0x35, 0x54, 0x9f, 0x07, 0x9f, 0x12, 0x2b, 0x98, 0xec, 0xab, 0x1a, 0x21, 0x77, 0x2e, 0x3e, 0xd8, 0xed, 0xbf, 0xf3, 0xf0, 0xed, 0xb7, 0x69, 0xfc, 0x89, 0x20, 0x18, 0x73, 0x5a, 0xff, 0x3c, 0xab, 0xbd, 0x7a, 0xdb, 0x0b, 0x23, 0x6b, 0xce, 0xed, 0xac, 0x6f, 0x3a, 0xf2, 0x93, 0xfd, 0xd4, 0xc2, 0xbc, 0x85, 0x07, 0xe7, 0x3f, 0xf3, 0xc2, 0x2b, 0x2f, 0x24, 0xd6, 0x2f, 0xaa, 0x96, 0x1f, 0x5b, 0xa8, 0xf2, 0x17, 0x9d, 0xdb, 0x36, 0xf2, 0xea, 0xfe, 0xe6, 0xba, 0xdd, 0xdf, 0xda, 0xb8, 0xf1, 0xdb, 0x7b, 0x53, 0xf8, 0x13, 0xe1, 0xb1, 0xdd, 0x90, 0x17, 0xcd, 0x43, 0x71, 0x6a, 0x79, 0xd8, 0xe8, 0x60,\n\t0x32, 0x62, 0x5e, 0x1a, 0x10, 0xeb, 0x32, 0x6b, 0x0a, 0x9a, 0x73, 0xc2, 0x2e, 0x27, 0xc5, 0x9f, 0x9e, 0x57, 0x69, 0xe6, 0xf3, 0x8d, 0xf0, 0x2b, 0x35, 0x5b, 0xa8, 0x54, 0x28, 0xdc, 0x85, 0x4d, 0xf1, 0x86, 0x35, 0x8d, 0xde, 0xfc, 0xbe, 0x83, 0x3d, 0xc9, 0xce, 0x49, 0xd8, 0x6a, 0xd1, 0xe3, 0x5b, 0x67, 0x25, 0xb6, 0x3c, 0x7f, 0xe3, 0xea, 0xc7, 0x92, 0x54, 0x89, 0x58, 0x6a, 0xb0, 0x18, 0x0a, 0xe6, 0x6d, 0xa8, 0x59, 0xb4, 0xb9, 0xbd, 0xc8, 0x72, 0xd5, 0x59, 0x36, 0xd7, 0xdf, 0x78, 0x76, 0xef, 0xd2, 0x67, 0xf7, 0xb6, 0xd4, 0x25, 0xb9, 0x31, 0x67, 0x8d, 0x7f, 0x4e, 0xdd, 0x0a, 0xcf, 0xae, 0x89, 0x58, 0xcc, 0x1d, 0x5a, 0x1d, 0x46, 0xb7, 0x48, 0x30, 0x9c, 0xc2, 0x06, 0xa5, 0x8e, 0xeb, 0x4c, 0x77, 0xf1, 0x91, 0xb8, 0xc6, 0x63, 0x3d, 0x3d, 0xe7, 0x5d, 0x5a, 0x8f, 0x8b, 0x03,\n\t0x19, 0xa4, 0x6c, 0x9b, 0xca, 0x45, 0x29, 0x71, 0x49, 0x43, 0x07, 0x75, 0xab, 0xdb, 0xc1, 0x7e, 0x77, 0x12, 0x43, 0xc5, 0x7e, 0xcf, 0xe1, 0xa0, 0x0a, 0xa8, 0x87, 0x9c, 0x9e, 0xb1, 0x37, 0x1b, 0x9b, 0x33, 0x8c, 0x15, 0x59, 0x37, 0xd7, 0xe0, 0xe5, 0xc6, 0x8d, 0x62, 0x7b, 0xff, 0x0c, 0x69, 0x95, 0x17, 0xd1, 0x2a, 0xc8, 0xf0, 0x63, 0x2a, 0x95, 0x8a, 0x19, 0x28, 0xc4, 0xa4, 0xca, 0x4b, 0x78, 0x3c, 0xda, 0x00, 0xa6, 0x14, 0x93, 0x34, 0x0a, 0x88, 0x56, 0x66, 0xf2, 0x16, 0x91, 0x3e, 0x2f, 0x5c, 0x61, 0xea, 0x05, 0x91, 0x46, 0x2e, 0x6c, 0xdd, 0xf9, 0x78, 0x6f, 0xff, 0x89, 0x15, 0xf1, 0x0b, 0x8e, 0xb2, 0xce, 0x48, 0x5e, 0x5f, 0x53, 0xae, 0x58, 0xa1, 0x12, 0x90, 0x22, 0x85, 0x56, 0x44, 0x7d, 0x9e, 0x58, 0x3f, 0xba, 0x3e, 0x79, 0xc7, 0xcf, 0x0e, 0x54, 0x46, 0x97, 0x1e, 0xe9,\n\t0x41, 0xc1, 0xad, 0xb1, 0x39, 0x65, 0x36, 0xff, 0xc2, 0x7b, 0xd7, 0x47, 0x86, 0x86, 0x06, 0x23, 0x2a, 0xa3, 0x9c, 0x8f, 0xe1, 0xb5, 0x85, 0x3d, 0xc3, 0xec, 0x83, 0xfb, 0x2f, 0x25, 0x8a, 0x10, 0x96, 0x0f, 0x62, 0x08, 0x98, 0x38, 0x4b, 0x3c, 0x2c, 0x66, 0x23, 0x0e, 0x20, 0x7d, 0x9a, 0x8a, 0xe2, 0x4a, 0x65, 0x96, 0xcf, 0x0f, 0x21, 0xd5, 0x98, 0xd6, 0x04, 0x23, 0x21, 0x70, 0xf2, 0x61, 0x4a, 0x29, 0x5a, 0x11, 0x9a, 0xd0, 0x5b, 0x91, 0x76, 0x9b, 0xd3, 0xb0, 0xe9, 0xa9, 0xca, 0xbe, 0xa3, 0x4b, 0x0a, 0x42, 0x75, 0xf3, 0xf3, 0x12, 0x0d, 0xe7, 0x43, 0x1d, 0x1b, 0x9a, 0x06, 0x1e, 0xbd, 0xb1, 0xb2, 0xf3, 0xd8, 0xfb, 0x7b, 0xce, 0xef, 0xfe, 0xd9, 0xdd, 0xed, 0x91, 0x45, 0x7b, 0xdb, 0x0b, 0xf8, 0x50, 0x5a, 0x13, 0xf4, 0x2d, 0xcd, 0x5f, 0x74, 0xdb, 0x82, 0x3d, 0xa0, 0x64, 0xc5,\n\t0xdd, 0x0b, 0x5b, 0xb7, 0x2f, 0x28, 0x98, 0xdd, 0xd7, 0xb5, 0xa9, 0xcd, 0xd3, 0xbc, 0xf7, 0xc5, 0xe5, 0x5b, 0xbf, 0x7b, 0x74, 0x36, 0x60, 0x5f, 0x06, 0x75, 0xa0, 0xed, 0x96, 0x6f, 0xdf, 0xd0, 0x7b, 0xff, 0x9e, 0x21, 0x47, 0x9b, 0xc4, 0xa8, 0x57, 0x51, 0x05, 0x2f, 0x6f, 0x6a, 0x3f, 0x38, 0x50, 0x02, 0xb0, 0x9e, 0xbb, 0x15, 0xce, 0x69, 0x3f, 0xa4, 0x5b, 0x9c, 0x9e, 0x7b, 0x49, 0x8a, 0x85, 0x4a, 0xd5, 0xa4, 0x45, 0x8a, 0x56, 0x24, 0xd0, 0xa0, 0x8c, 0xdb, 0x29, 0x15, 0x37, 0x2a, 0x3b, 0xc0, 0xe3, 0x2d, 0xe7, 0xe1, 0x00, 0xe5, 0x6b, 0xb7, 0x5a, 0x9b, 0x6a, 0xd5, 0x93, 0x94, 0x4d, 0xd6, 0x88, 0x8b, 0xae, 0xad, 0x11, 0x9f, 0x58, 0x07, 0x65, 0x84, 0xaa, 0x5b, 0x70, 0xb8, 0xbf, 0xa0, 0xa0, 0xff, 0xf0, 0x82, 0xf3, 0x0b, 0xb9, 0x2f, 0x0b, 0xcf, 0xef, 0xb9, 0x74, 0xac, 0xbd,\n\t0xfd, 0xd8, 0xa5, 0x3d, 0x93, 0xbe, 0x80, 0xc2, 0xfe, 0x5b, 0xba, 0xbb, 0x6f, 0xe9, 0x8f, 0x02, 0x10, 0xe5, 0xbe, 0x15, 0x02, 0x6a, 0x0f, 0x68, 0x3c, 0xf0, 0xfa, 0x4d, 0x1b, 0x5f, 0x3b, 0xd0, 0xc8, 0x4d, 0xbe, 0xf1, 0xc0, 0x6b, 0x1b, 0x6f, 0x7a, 0x1d, 0x5e, 0x81, 0xbb, 0x50, 0x7e, 0x7d, 0x96, 0x3d, 0x45, 0xbd, 0x0f, 0x99, 0xb8, 0x08, 0xf1, 0x68, 0x52, 0x98, 0xed, 0x56, 0x8b, 0x68, 0x06, 0x87, 0x8d, 0xcb, 0xb0, 0xd2, 0x19, 0xf1, 0xc7, 0xc8, 0xc3, 0x33, 0x96, 0x8a, 0xc5, 0x46, 0xdc, 0x5d, 0x1e, 0x91, 0xe6, 0x01, 0x67, 0xbe, 0x5f, 0x94, 0xe1, 0xbc, 0xcd, 0x93, 0xee, 0x43, 0xb0, 0xc8, 0x9b, 0x08, 0xe8, 0x2e, 0xe2, 0x52, 0xa8, 0xe0, 0xc3, 0x93, 0xe2, 0xc1, 0x67, 0x68, 0xd2, 0xc3, 0xc5, 0x96, 0xc0, 0xb1, 0x15, 0x04, 0x3c, 0xde, 0x10, 0x56, 0x61, 0x33, 0x19, 0x16, 0x7c,\n\t0x26, 0xfe, 0x3b, 0x15, 0x00, 0x8c, 0x53, 0x48, 0xc3, 0x85, 0x8c, 0x50, 0xef, 0xdb, 0x73, 0x83, 0x2d, 0xb5, 0x65, 0xc6, 0x27, 0x18, 0xb9, 0xe0, 0x7b, 0x8c, 0xd9, 0x70, 0x0b, 0x98, 0xf3, 0x9c, 0xcc, 0xec, 0xc9, 0x77, 0xba, 0x49, 0x99, 0xc3, 0xbe, 0xfc, 0x40, 0xf0, 0x11, 0x5a, 0x26, 0x7c, 0x99, 0x67, 0x32, 0xdc, 0xc2, 0xbe, 0xf2, 0xba, 0xc4, 0xe4, 0x08, 0x59, 0x7e, 0xd2, 0x16, 0x30, 0xca, 0x43, 0x2d, 0xe5, 0x60, 0x87, 0xad, 0x44, 0xcf, 0x0e, 0x2a, 0xf4, 0xe4, 0x3b, 0xe0, 0x76, 0xab, 0xdf, 0x20, 0x6e, 0x40, 0xcc, 0xf8, 0xec, 0x7e, 0xf6, 0x36, 0x6b, 0xb1, 0x0e, 0xec, 0x51, 0x64, 0x8d, 0x75, 0xb2, 0x2d, 0xa6, 0x80, 0x51, 0xca, 0x9d, 0xcf, 0x4d, 0x10, 0x6e, 0x4e, 0x42, 0xb8, 0xc9, 0x46, 0x31, 0x5d, 0x41, 0xbb, 0x85, 0x02, 0xa4, 0x08, 0x6b, 0x15, 0xb1, 0x3d, 0x07, 0xbb,\n\t0x03, 0xe7, 0x70, 0x52, 0x46, 0x46, 0x91, 0x96, 0x4d, 0x84, 0xcd, 0x6a, 0xa5, 0x09, 0x09, 0x16, 0x60, 0x62, 0xd3, 0xdd, 0x04, 0xb2, 0x32, 0xe0, 0x1c, 0xe6, 0x19, 0x33, 0x03, 0x82, 0x0f, 0x88, 0x37, 0x98, 0x01, 0x89, 0x56, 0x26, 0xe8, 0xbd, 0xf7, 0xdd, 0xd1, 0x0b, 0xec, 0x5f, 0xd8, 0x8f, 0xf6, 0x4b, 0xf4, 0x0a, 0x51, 0xfe, 0x82, 0x3d, 0x5d, 0x17, 0xda, 0xf6, 0x0f, 0x14, 0x49, 0x55, 0x2a, 0xc6, 0xa5, 0x49, 0x9d, 0xdd, 0xbb, 0xbf, 0xbf, 0x33, 0x29, 0x64, 0xbf, 0x01, 0xea, 0x55, 0x80, 0xfc, 0x2f, 0x52, 0x27, 0xd7, 0x99, 0x24, 0x6c, 0xac, 0xe9, 0xc6, 0xae, 0x42, 0x11, 0x23, 0xf9, 0xe2, 0x53, 0x7e, 0xde, 0xc2, 0x3b, 0x56, 0xce, 0x5a, 0xbb, 0xb0, 0x2b, 0x87, 0xf3, 0xa7, 0xee, 0x1a, 0xff, 0x98, 0x79, 0x0e, 0xe2, 0x96, 0x3a, 0xe4, 0x67, 0x21, 0x05, 0x14, 0x8e, 0x3d, 0x21,\n\t0x29, 0x28, 0x48, 0x8c, 0xf0, 0x79, 0x78, 0xe0, 0x13, 0xda, 0x05, 0x0e, 0xd7, 0xd4, 0x11, 0xb5, 0x1e, 0x6d, 0x8e, 0xde, 0xef, 0xc3, 0xfa, 0x72, 0x9d, 0x2a, 0x8d, 0x6e, 0x32, 0x2a, 0x72, 0x55, 0x1c, 0xcd, 0x81, 0xcf, 0xc1, 0x34, 0xc6, 0x3e, 0x33, 0x20, 0x22, 0x26, 0x58, 0xd6, 0x5c, 0xb2, 0xfc, 0xe8, 0xdc, 0xf8, 0xfc, 0xc6, 0x22, 0xad, 0xb6, 0x78, 0xd6, 0xfc, 0xe8, 0xdc, 0xa3, 0xcb, 0x4b, 0x9a, 0xcb, 0x6e, 0x11, 0x19, 0x94, 0xb4, 0x48, 0x11, 0xf2, 0x99, 0x43, 0x95, 0xad, 0xae, 0x70, 0x65, 0x48, 0x7b, 0x51, 0x1b, 0xaa, 0xcc, 0x76, 0xb5, 0x54, 0x86, 0xcc, 0xbe, 0x90, 0x42, 0xc4, 0x28, 0xb3, 0x20, 0x92, 0x5a, 0xcf, 0x8e, 0xef, 0xbf, 0xe9, 0x8d, 0x83, 0x8d, 0xc6, 0xdc, 0x4a, 0x9f, 0xaf, 0x32, 0xd7, 0xd8, 0x78, 0xf0, 0x8d, 0x9b, 0xf6, 0x03, 0xb0, 0x5e, 0xa8, 0x75, 0x64,\n\t0x99, 0xfa, 0xd6, 0x6d, 0x2b, 0x5d, 0x7b, 0xa4, 0xd3, 0x1e, 0x68, 0x5c, 0x56, 0x01, 0x78, 0xec, 0x17, 0x48, 0x37, 0x67, 0xef, 0x3c, 0xb2, 0xb6, 0x74, 0xdb, 0xba, 0x3e, 0x53, 0x96, 0x43, 0x2b, 0x44, 0xf6, 0xe2, 0x2e, 0x7a, 0x0b, 0x59, 0xc9, 0xfc, 0x82, 0xe0, 0x11, 0x51, 0xae, 0x34, 0xa4, 0x24, 0xe3, 0x7e, 0x1f, 0xc1, 0x56, 0x72, 0xec, 0x77, 0xd5, 0x8d, 0x55, 0x43, 0xd8, 0x35, 0xb4, 0xa5, 0x27, 0x89, 0xbc, 0x1a, 0x79, 0x04, 0xcf, 0x41, 0x21, 0x7d, 0x05, 0x72, 0x76, 0xe6, 0x53, 0xa0, 0xab, 0x6a, 0x93, 0x45, 0x2b, 0x5e, 0x43, 0x6f, 0x01, 0x8b, 0x3c, 0x36, 0xf6, 0x7f, 0x30, 0x1e, 0x99, 0x4b, 0xef, 0xa4, 0xac, 0xcc, 0xaf, 0x61, 0xdb, 0x2c, 0x28, 0x4a, 0xac, 0x4f, 0x27, 0xa9, 0x46, 0x59, 0x8d, 0xbb, 0x19, 0xb4, 0xc4, 0xd8, 0x8f, 0x2f, 0x6d, 0xa4, 0x84, 0x5d, 0xa7, 0xf8,\n\t0x31, 0x2d, 0xec, 0x1e, 0x5d, 0x2f, 0x44, 0x7c, 0x15, 0x87, 0x3d, 0x43, 0x24, 0x96, 0x55, 0xaf, 0xfd, 0x28, 0x3c, 0x26, 0x2a, 0x82, 0x08, 0x40, 0x56, 0x40, 0xab, 0x96, 0x8a, 0xf1, 0xf0, 0xf8, 0x13, 0xc3, 0xf3, 0x70, 0x2c, 0xca, 0x35, 0xdd, 0xdc, 0x3a, 0x2a, 0xe1, 0xe8, 0x45, 0x6b, 0x41, 0x8f, 0xc2, 0xe4, 0xd1, 0x04, 0x8b, 0xe5, 0x26, 0xb7, 0x56, 0xe3, 0x31, 0x29, 0xc6, 0xc6, 0x15, 0x66, 0x8f, 0x46, 0xe3, 0x32, 0x29, 0x14, 0x26, 0x97, 0x46, 0xe3, 0x31, 0x2b, 0xe8, 0x9d, 0xdc, 0xfc, 0xf6, 0x6a, 0xdc, 0x26, 0x79, 0x71, 0x40, 0xeb, 0x36, 0x2b, 0x14, 0x66, 0xd8, 0x18, 0x5e, 0xc1, 0x87, 0x34, 0xa9, 0xeb, 0xf1, 0x71, 0xa2, 0x83, 0xfa, 0x16, 0x58, 0xc8, 0xfc, 0x99, 0xe2, 0x13, 0x7f, 0x87, 0x34, 0xf2, 0x6e, 0x2e, 0xee, 0x86, 0xbe, 0x3b, 0x15, 0x77, 0x83, 0xf4, 0x95, 0x01,\n\t0xb0, 0x10, 0xcc, 0x81, 0x7c, 0x8e, 0x2e, 0xa9, 0x46, 0x55, 0x2a, 0xeb, 0xb1, 0x17, 0x2b, 0xe7, 0x6e, 0xca, 0x69, 0xde, 0x48, 0xbe, 0x2f, 0x07, 0xc4, 0x2b, 0x48, 0xaf, 0x0f, 0x11, 0x4c, 0x90, 0xb0, 0x36, 0x8e, 0x94, 0x2b, 0x29, 0x81, 0x29, 0xa0, 0x16, 0x66, 0x19, 0xcc, 0x60, 0xce, 0x31, 0xf6, 0xf7, 0x9b, 0x7c, 0x62, 0xbb, 0xc4, 0x53, 0x3f, 0xab, 0x25, 0x34, 0xac, 0xb7, 0x62, 0x7a, 0x84, 0xec, 0xf9, 0x47, 0xe0, 0x19, 0x94, 0x70, 0x55, 0x88, 0xf8, 0x20, 0x6d, 0xab, 0x60, 0x18, 0x2c, 0x4f, 0x19, 0x52, 0x24, 0x09, 0x1e, 0x49, 0x23, 0xd5, 0x2c, 0x93, 0x02, 0xc2, 0x6c, 0x32, 0x1a, 0xb2, 0x74, 0x52, 0x8b, 0x0c, 0x85, 0x82, 0x4b, 0x80, 0x44, 0xc0, 0x9b, 0x50, 0xfe, 0x42, 0xda, 0x9d, 0x09, 0xf3, 0x71, 0xe0, 0x64, 0x47, 0xe4, 0xed, 0xed, 0xa3, 0x0d, 0x0e, 0x47, 0xfd, 0x68,\n\t0x3b, 0xfb, 0x4f, 0x20, 0xd9, 0xfb, 0xda, 0xd6, 0xd2, 0x9a, 0xdd, 0xdf, 0xda, 0xc4, 0xda, 0xa9, 0x33, 0x63, 0x81, 0x27, 0xdc, 0x95, 0xf3, 0x63, 0xc5, 0xf3, 0x2b, 0x1c, 0xac, 0x81, 0x3c, 0x5a, 0xba, 0xfc, 0x48, 0xd7, 0xc0, 0x83, 0xa3, 0xe5, 0xcc, 0xa9, 0xd3, 0x6c, 0x0d, 0x91, 0xf1, 0x35, 0xd0, 0x4f, 0xf7, 0x35, 0x30, 0x20, 0x8c, 0x60, 0xe4, 0x7c, 0x0d, 0x78, 0x19, 0x5f, 0x03, 0xfd, 0xd8, 0xc8, 0x7b, 0xd4, 0x50, 0xc6, 0xd7, 0x20, 0xf5, 0x2c, 0xef, 0xbf, 0x09, 0x3e, 0xf2, 0x34, 0x40, 0x19, 0xf7, 0x47, 0xaf, 0xee, 0x40, 0xa9, 0xa0, 0x79, 0x59, 0xa9, 0x1e, 0x94, 0x11, 0xdc, 0x07, 0xf9, 0xc6, 0x23, 0x5c, 0x27, 0xa0, 0x9a, 0xd3, 0xa5, 0xcb, 0xd8, 0x47, 0x79, 0x04, 0xb6, 0x5d, 0xdb, 0x88, 0xda, 0x24, 0xe2, 0x39, 0x71, 0xee, 0x2a, 0x43, 0x93, 0x90, 0xcf, 0x08, 0xe8, 0x94,\n\t0x2d, 0xdb, 0x98, 0xbe, 0x22, 0x7b, 0x11, 0x08, 0x5a, 0xc8, 0x66, 0x81, 0x80, 0x20, 0x04, 0x36, 0x81, 0xcd, 0x6a, 0xd1, 0x69, 0x35, 0x2a, 0xb9, 0x0c, 0x82, 0x18, 0x9f, 0xe0, 0x2b, 0x45, 0x3c, 0x6d, 0xc8, 0xa3, 0x74, 0x60, 0xb9, 0x18, 0xb2, 0x39, 0x90, 0xcf, 0x54, 0xa6, 0x3e, 0x22, 0x15, 0x94, 0x11, 0xc4, 0x1d, 0x4a, 0xba, 0x8a, 0x2d, 0x91, 0x84, 0x4a, 0x1b, 0x02, 0xf4, 0x32, 0xaf, 0x75, 0xfb, 0xe5, 0xbb, 0xe0, 0x9f, 0x7b, 0xac, 0x65, 0x45, 0xf9, 0x7e, 0x8b, 0x80, 0x5a, 0x7a, 0x9a, 0x6e, 0xfd, 0x88, 0x3d, 0xc1, 0xfe, 0xeb, 0x5c, 0x29, 0x5b, 0x66, 0x76, 0x82, 0x5e, 0xf6, 0x77, 0x66, 0x27, 0x49, 0xca, 0xab, 0xb7, 0xbc, 0x0a, 0x94, 0x60, 0xf5, 0xdf, 0x2e, 0x8b, 0xb9, 0x75, 0x83, 0xf8, 0x5f, 0x60, 0x85, 0x63, 0x2e, 0x46, 0x35, 0x59, 0x62, 0x06, 0x12, 0xf0, 0x40, 0x23,\n\t0x8e, 0xf3, 0x05, 0xf0, 0x9c, 0x0c, 0x08, 0xf9, 0x24, 0xc3, 0x18, 0x9a, 0x20, 0x76, 0x25, 0x08, 0x23, 0xd1, 0x5c, 0x90, 0xe7, 0x40, 0xe1, 0xde, 0xf0, 0x8f, 0x5d, 0xc4, 0xb3, 0x64, 0x3c, 0x0b, 0x70, 0xa9, 0x13, 0xa4, 0xeb, 0xe4, 0xdc, 0x0b, 0x2a, 0x50, 0xb5, 0x01, 0x5f, 0x3a, 0x59, 0x43, 0x29, 0x50, 0x4e, 0x2e, 0x68, 0x0a, 0xa9, 0x0a, 0x94, 0xee, 0x05, 0xd6, 0xdb, 0x72, 0xab, 0x35, 0xec, 0x63, 0xe6, 0x9a, 0xc2, 0x87, 0xdf, 0x79, 0xa8, 0xb0, 0xd6, 0xc4, 0x3e, 0xa6, 0xa9, 0xce, 0x39, 0x0c, 0xee, 0xb3, 0xb7, 0x44, 0x42, 0x65, 0x16, 0x76, 0xe5, 0x63, 0x8e, 0x62, 0x25, 0xe8, 0xb6, 0x55, 0x87, 0x0f, 0xbd, 0x73, 0x4b, 0xb8, 0xda, 0x06, 0xba, 0x95, 0xc5, 0xf6, 0xd3, 0xec, 0x4a, 0x4b, 0x59, 0xa8, 0xa0, 0xd5, 0x1e, 0x70, 0x81, 0x8f, 0x83, 0x9e, 0xb1, 0x1b, 0xc9, 0x5b, 0x3c,\n\t0x41, 0x56, 0xe1, 0x0a, 0x90, 0x2b, 0xe3, 0x95, 0x0a, 0x79, 0x51, 0x90, 0x2c, 0x76, 0x58, 0x58, 0x43, 0xd8, 0x4c, 0xae, 0x1e, 0xbb, 0xd3, 0x1c, 0x06, 0x7f, 0xb4, 0x38, 0xc6, 0xde, 0x0a, 0x16, 0xc9, 0x95, 0xc9, 0x38, 0x37, 0x57, 0x2f, 0xe4, 0xff, 0x5d, 0xcc, 0x53, 0x44, 0x05, 0xd2, 0xe3, 0x8b, 0x01, 0xcd, 0x64, 0xc1, 0x83, 0x9e, 0xb6, 0x00, 0x67, 0x67, 0x82, 0xf7, 0xd3, 0x89, 0x2d, 0x19, 0x88, 0xa4, 0x91, 0xca, 0x32, 0xa5, 0x51, 0xb1, 0x67, 0x52, 0xa2, 0x38, 0x00, 0xd6, 0xe3, 0x5f, 0x77, 0x7b, 0x17, 0x48, 0xeb, 0xf1, 0xb3, 0x43, 0x5c, 0xed, 0x00, 0x9d, 0xc6, 0x29, 0x80, 0xdb, 0xab, 0xce, 0x58, 0xa3, 0x32, 0x36, 0xba, 0x69, 0xf1, 0x3e, 0x24, 0xdf, 0x15, 0x4d, 0xe3, 0xf4, 0x74, 0x1e, 0x80, 0xbe, 0x8e, 0xff, 0x3a, 0x38, 0xf2, 0xc2, 0xb6, 0x9a, 0x65, 0x8b, 0x63, 0xf3,\n\t0x12, 0xae, 0xba, 0xfd, 0x17, 0xb7, 0x9d, 0xbc, 0x32, 0xaf, 0x5c, 0x60, 0x94, 0xeb, 0xca, 0xe6, 0x6f, 0xef, 0x3d, 0xf1, 0x78, 0x68, 0xf6, 0x68, 0xc3, 0x77, 0x5e, 0x41, 0x18, 0xd9, 0x37, 0x6b, 0x55, 0x4d, 0xdb, 0xda, 0xd6, 0x88, 0x4a, 0xa9, 0x13, 0x31, 0xba, 0x86, 0x96, 0xf8, 0x92, 0x03, 0xed, 0x2b, 0x1f, 0xce, 0xcb, 0xaa, 0xea, 0xec, 0x8f, 0x2d, 0x7a, 0x74, 0x4b, 0xfd, 0xd0, 0xdc, 0x21, 0x89, 0x22, 0x1c, 0x0d, 0xdf, 0xb2, 0x23, 0x36, 0x3f, 0xe9, 0x02, 0xcf, 0x58, 0xe2, 0xed, 0x85, 0xb9, 0xad, 0x71, 0x9b, 0x23, 0xe0, 0x50, 0x28, 0x89, 0x29, 0xfe, 0x18, 0x26, 0xe4, 0x6d, 0xa7, 0xe1, 0x21, 0x53, 0x4f, 0x23, 0xb6, 0x58, 0x19, 0xb0, 0x9b, 0x89, 0x11, 0x93, 0x2b, 0x13, 0x61, 0x54, 0x06, 0x95, 0x0c, 0x3a, 0x62, 0x48, 0xdd, 0x1d, 0x8b, 0xa7, 0x5d, 0x4d, 0x10, 0x51, 0xe2,\n\t0xf1, 0x21, 0x40, 0x20, 0x9f, 0x73, 0x66, 0xd6, 0x25, 0x5a, 0xa0, 0xf6, 0x6b, 0xc6, 0xb6, 0xc9, 0xf3, 0x6d, 0xf7, 0xbf, 0xc7, 0xf0, 0x55, 0x7e, 0x0d, 0xb9, 0x5b, 0x9e, 0x67, 0x63, 0x4e, 0x7d, 0xb1, 0x94, 0xfa, 0x20, 0x7b, 0x20, 0x96, 0xd7, 0x61, 0xbf, 0x52, 0x6d, 0x08, 0x32, 0xa7, 0xae, 0xb8, 0xb3, 0x07, 0xe2, 0x79, 0x9d, 0x76, 0xea, 0x9b, 0x86, 0xe0, 0xc4, 0x38, 0x2a, 0xe0, 0x38, 0xec, 0x28, 0xf7, 0x8a, 0x65, 0x4a, 0xfc, 0x26, 0xc2, 0xe1, 0x06, 0xec, 0x21, 0x02, 0x47, 0x03, 0x81, 0x53, 0xe9, 0xb3, 0xf3, 0x78, 0xc6, 0x34, 0x74, 0x52, 0x78, 0x4c, 0x57, 0x83, 0x20, 0x53, 0xf1, 0x6d, 0x7b, 0x48, 0xcd, 0x1e, 0x93, 0x9a, 0xec, 0x3e, 0xe3, 0x13, 0x97, 0x2e, 0xdd, 0x1e, 0x4e, 0x58, 0xc0, 0x0a, 0x45, 0xb6, 0xfd, 0x05, 0xb6, 0xc7, 0x90, 0xf4, 0xc6, 0x9a, 0x5c, 0x4e, 0x3b,\n\t0x49, 0x6a, 0x4c, 0x4a, 0xfe, 0xd8, 0x8d, 0xcc, 0xa9, 0xb1, 0x3b, 0x4d, 0x01, 0xf0, 0x37, 0xa3, 0x63, 0xec, 0x9c, 0x3b, 0x57, 0x26, 0xab, 0x2c, 0xc6, 0xb5, 0x93, 0xbe, 0x18, 0xff, 0x84, 0xa1, 0x70, 0x3c, 0x4a, 0x6d, 0xd3, 0x59, 0x27, 0x8e, 0xed, 0x85, 0x03, 0xe3, 0x30, 0x21, 0x91, 0x76, 0x14, 0x30, 0x12, 0xb8, 0x3c, 0xce, 0xc4, 0x0d, 0xf8, 0x13, 0xba, 0x8b, 0x99, 0x78, 0x17, 0x94, 0x68, 0xce, 0xeb, 0x9c, 0x5e, 0xa5, 0x82, 0xe1, 0x19, 0xb0, 0x57, 0x8b, 0x88, 0x44, 0x9b, 0x8c, 0x05, 0x77, 0xd2, 0x08, 0xd4, 0x0e, 0x86, 0x7a, 0x8f, 0x2d, 0x95, 0xe5, 0xd7, 0xcc, 0x5d, 0xb6, 0xa1, 0x6a, 0x43, 0xbd, 0xb7, 0xa5, 0xbe, 0xb2, 0xd0, 0x23, 0xa2, 0x96, 0xd2, 0x9f, 0xb1, 0x7f, 0x65, 0x87, 0xd9, 0xdf, 0xbd, 0x30, 0xe4, 0x09, 0xee, 0xb7, 0xf4, 0x3e, 0x05, 0x4c, 0xe0, 0x14, 0x40,\n\t0xb1, 0xbd, 0x70, 0x4c, 0x02, 0x09, 0xc6, 0xd1, 0x39, 0xc4, 0x06, 0x6e, 0x54, 0x0e, 0x61, 0x06, 0x51, 0xd3, 0x34, 0x4e, 0x4b, 0x0d, 0x11, 0xb5, 0x80, 0x4c, 0x0b, 0x0f, 0x46, 0x8a, 0x8b, 0x2b, 0xbf, 0x56, 0x1b, 0x8c, 0xb3, 0xf0, 0x77, 0x6c, 0x62, 0x70, 0x31, 0x10, 0x98, 0x4d, 0x08, 0xb9, 0x67, 0x87, 0xbd, 0x6e, 0xa7, 0x1d, 0x23, 0xf8, 0x1c, 0x59, 0x0e, 0x87, 0xe0, 0x45, 0xd7, 0x46, 0xf0, 0xd3, 0x67, 0xa6, 0xe4, 0xc9, 0x66, 0x44, 0xf7, 0xb6, 0x99, 0xe6, 0x3b, 0x23, 0xfa, 0x9f, 0x79, 0x11, 0xc6, 0xee, 0x4b, 0xd1, 0x2a, 0x41, 0x27, 0x5e, 0x07, 0x17, 0x31, 0xcc, 0x91, 0x7e, 0x2b, 0x5f, 0x44, 0x92, 0x34, 0xc0, 0xb3, 0x84, 0x28, 0x0e, 0xe1, 0x65, 0x44, 0xae, 0x16, 0x64, 0x16, 0xc1, 0x25, 0x42, 0x95, 0x51, 0xc9, 0x6e, 0x82, 0x8f, 0x5a, 0xf1, 0x67, 0x6c, 0xd5, 0x93, 0xb4,\n\t0xa0, 0xb9, 0x3b, 0x1d, 0x28, 0xd3, 0x58, 0x8a, 0xbc, 0xb9, 0x64, 0x2e, 0x6e, 0xf6, 0xe2, 0x6b, 0xcf, 0x1e, 0xc3, 0x20, 0xa4, 0x1c, 0x4a, 0xde, 0x1c, 0x3c, 0xeb, 0x86, 0xd4, 0xac, 0x5f, 0x4f, 0xcf, 0x7a, 0x4c, 0xfd, 0xde, 0x7b, 0xe4, 0x5f, 0x2f, 0xcd, 0x38, 0x51, 0x24, 0x22, 0x42, 0x18, 0xdc, 0x47, 0x6e, 0x86, 0x93, 0x9b, 0xf0, 0x57, 0x43, 0x32, 0x54, 0xe0, 0x1a, 0x36, 0x21, 0x7b, 0xc6, 0x26, 0xe4, 0x60, 0x9a, 0xf5, 0x3a, 0x31, 0x44, 0xf7, 0x0e, 0x9b, 0x2e, 0xa0, 0x0f, 0x88, 0xb5, 0x62, 0xad, 0x52, 0x8e, 0xcb, 0x96, 0x08, 0x21, 0x0a, 0x4a, 0x59, 0xcd, 0xe3, 0x3e, 0xce, 0x29, 0x83, 0x0f, 0x90, 0x03, 0x9b, 0x76, 0xaa, 0x53, 0x1b, 0x88, 0x0a, 0x5b, 0x76, 0x7c, 0x7d, 0xc5, 0x8a, 0xaf, 0x6f, 0x6f, 0x11, 0x92, 0x92, 0xb6, 0x6d, 0x4f, 0x2e, 0x1b, 0x7a, 0x72, 0xfb, 0x6c,\n\t0x09, 0xf8, 0x0b, 0xf6, 0x60, 0x9b, 0xea, 0xd5, 0x46, 0x1e, 0xba, 0xe1, 0xf9, 0x9b, 0x2b, 0x2b, 0x6f, 0x7e, 0xfe, 0x86, 0x07, 0x57, 0x3d, 0xb9, 0xa1, 0x02, 0x69, 0x69, 0xc8, 0x9d, 0xd8, 0x81, 0x6d, 0x9a, 0x53, 0x5b, 0xea, 0x4c, 0xab, 0xa6, 0xfb, 0x7a, 0x65, 0x4e, 0x72, 0x9a, 0xe6, 0x66, 0x7c, 0xbd, 0x54, 0x97, 0xc6, 0x1a, 0xdf, 0xa3, 0xfb, 0x27, 0x7c, 0xbd, 0x48, 0x88, 0xcf, 0x3f, 0x81, 0x5f, 0x6d, 0x44, 0xdd, 0xb9, 0x2c, 0x05, 0xc9, 0x15, 0x75, 0x42, 0xb8, 0x5c, 0x95, 0xc2, 0x50, 0xe9, 0xc4, 0xbc, 0x0e, 0x74, 0x06, 0xa7, 0xff, 0xe8, 0x42, 0xd6, 0x55, 0x09, 0x2e, 0x24, 0x6d, 0xf5, 0x3a, 0x3d, 0x08, 0x7b, 0x09, 0x71, 0x6a, 0x0a, 0x0e, 0x44, 0x13, 0x5c, 0xb6, 0x26, 0x80, 0x2c, 0x7a, 0x18, 0x7d, 0xd1, 0x9f, 0x8c, 0xbd, 0x64, 0xae, 0x6c, 0x9a, 0x9b, 0xbf, 0xa1, 0x21,\n\t0x2b, 0x3f, 0x27, 0xa0, 0xaa, 0x1e, 0xfb, 0xf6, 0x5b, 0x66, 0x87, 0x04, 0xb4, 0xf9, 0xf5, 0x62, 0xab, 0x0a, 0xd8, 0x04, 0x1e, 0x13, 0x73, 0xea, 0xb2, 0xb3, 0xac, 0x2d, 0x47, 0x1d, 0xdc, 0x2f, 0x32, 0xe5, 0xb8, 0x0f, 0x51, 0x9f, 0x9b, 0x74, 0x63, 0xf7, 0x34, 0xb5, 0xfa, 0x5a, 0xbc, 0xe4, 0x0a, 0x95, 0x0d, 0xe3, 0x8c, 0x71, 0x38, 0xe7, 0x65, 0xcc, 0xc3, 0x84, 0x01, 0xe9, 0x19, 0x74, 0x58, 0x37, 0x8d, 0x07, 0x84, 0x44, 0x59, 0x03, 0x12, 0xd6, 0x8c, 0x38, 0x86, 0xdb, 0x89, 0xb9, 0x0d, 0x1c, 0xb9, 0x6d, 0x01, 0x98, 0xb4, 0xba, 0x26, 0x67, 0x3f, 0xa2, 0xfe, 0x69, 0x3f, 0xb0, 0xac, 0x38, 0x14, 0xcb, 0xae, 0x52, 0xb3, 0xdd, 0xdf, 0x1e, 0xfb, 0xc6, 0x93, 0x66, 0x97, 0x10, 0xec, 0xe1, 0xdc, 0xf9, 0xe8, 0x0f, 0x86, 0xfa, 0xd5, 0xba, 0xbd, 0x85, 0xb1, 0xcb, 0x10, 0x6f, 0x99,\n\t0x75, 0x57, 0xf2, 0x38, 0x97, 0x3e, 0x08, 0x37, 0xb3, 0xe0, 0xbb, 0xff, 0x9b, 0xf9, 0x20, 0x25, 0x7b, 0xe7, 0x25, 0xb3, 0xa7, 0x78, 0x96, 0x41, 0x31, 0x1a, 0x72, 0x2f, 0x03, 0x50, 0xc8, 0xc6, 0x5c, 0x8b, 0x91, 0xd7, 0x3c, 0x59, 0x92, 0xe6, 0xa1, 0xf2, 0x91, 0xd7, 0xe1, 0x5b, 0xb6, 0xa9, 0xf7, 0xae, 0x15, 0x25, 0x25, 0x2b, 0xee, 0xea, 0xfd, 0x2e, 0xfc, 0x52, 0x5c, 0x8c, 0xbe, 0x1c, 0xfc, 0xed, 0x43, 0x3d, 0x3d, 0x0f, 0xfd, 0xf6, 0x20, 0xfe, 0x32, 0xff, 0xe1, 0xdf, 0xee, 0xff, 0x2e, 0xe8, 0x02, 0x55, 0x23, 0x77, 0xcf, 0xe9, 0xba, 0x7b, 0xa4, 0x8a, 0x24, 0xe1, 0xb7, 0xae, 0x39, 0xf0, 0x1b, 0xa0, 0x7e, 0x4d, 0xf5, 0x9d, 0xfa, 0xd1, 0x86, 0x0d, 0x3f, 0xba, 0xaf, 0x8f, 0x7a, 0xfa, 0x69, 0xaa, 0xef, 0xbe, 0x1f, 0x6d, 0xb8, 0x11, 0x7d, 0x7f, 0x1c, 0xe3, 0x7f, 0xf6, 0x51,\n\t0xe6, 0xcf, 0x70, 0xaf, 0x65, 0xc8, 0x3f, 0x13, 0x31, 0x4e, 0x06, 0xce, 0x1b, 0x0b, 0xbb, 0x82, 0x1a, 0x9b, 0x70, 0x55, 0x36, 0x44, 0x8a, 0x64, 0x84, 0x0c, 0xa5, 0x09, 0x76, 0xf1, 0x21, 0x3e, 0xf5, 0xa4, 0xb9, 0x26, 0xee, 0xe4, 0x31, 0x7f, 0xf6, 0x5a, 0xb7, 0x5d, 0x3e, 0xf8, 0x1e, 0x79, 0xee, 0xd2, 0x69, 0x8e, 0x27, 0x82, 0xfb, 0x25, 0x46, 0xe0, 0x94, 0xea, 0x5f, 0x95, 0xee, 0x1f, 0xf7, 0x6c, 0xc0, 0xc6, 0x97, 0xf9, 0x18, 0x1a, 0x11, 0xd0, 0x58, 0xc0, 0x44, 0xff, 0x2e, 0x25, 0xea, 0x3f, 0xc3, 0x90, 0x71, 0x6f, 0x60, 0x54, 0x6c, 0x3e, 0x64, 0xc1, 0xd8, 0x7c, 0xf8, 0x06, 0x44, 0xd2, 0x10, 0xc7, 0x95, 0x7e, 0x07, 0xa6, 0x61, 0xf3, 0x20, 0x9f, 0xb9, 0x03, 0xbe, 0x43, 0x8d, 0xec, 0x12, 0x2a, 0x8a, 0xe4, 0xd4, 0x39, 0x9c, 0xf7, 0x44, 0x1a, 0x38, 0xd3, 0x24, 0x55, 0x4d,\n\t0xa8, 0xb5, 0xea, 0x0c, 0x49, 0x95, 0x01, 0xec, 0x1c, 0x07, 0x25, 0x3c, 0x10, 0x8b, 0x2b, 0xe9, 0x1d, 0x97, 0xd6, 0xfd, 0xfc, 0x9b, 0xf7, 0x8d, 0x54, 0xbc, 0xd7, 0x78, 0xea, 0x1f, 0x8f, 0xa1, 0x57, 0x91, 0x4b, 0xac, 0x4e, 0x3a, 0x77, 0xe0, 0xbe, 0x1b, 0xc0, 0x7b, 0x6c, 0x60, 0xd1, 0x86, 0x7c, 0x75, 0x90, 0x7c, 0x20, 0x43, 0x37, 0xf9, 0xaf, 0xc2, 0x77, 0x8a, 0x91, 0x0e, 0x91, 0xc7, 0xc0, 0x05, 0x03, 0x06, 0xac, 0x53, 0x26, 0xe6, 0x67, 0xde, 0x25, 0x26, 0xc4, 0xb8, 0x4e, 0x68, 0x7a, 0x4e, 0x91, 0xd4, 0x3f, 0xfe, 0xab, 0x9f, 0x7f, 0xf6, 0x1e, 0x59, 0x7d, 0x89, 0xac, 0x47, 0xef, 0x48, 0x2f, 0x16, 0x9a, 0x0c, 0x5e, 0x2f, 0xc1, 0x5d, 0xd8, 0xf7, 0x14, 0xe5, 0x24, 0xa0, 0xf1, 0xe0, 0x39, 0x47, 0xbf, 0xe9, 0x3b, 0xa2, 0x22, 0x54, 0xb8, 0x77, 0xa5, 0x4b, 0xc8, 0x33, 0x4d,\n\t0xdf, 0x13, 0xf4, 0x4f, 0x80, 0x18, 0xd7, 0xcf, 0x7f, 0xcd, 0xbd, 0xe9, 0xbd, 0x69, 0x5b, 0x83, 0xb7, 0x07, 0xe2, 0x73, 0x28, 0x48, 0x33, 0xf7, 0xcc, 0x24, 0x7b, 0xd0, 0x34, 0xd3, 0x43, 0x20, 0x26, 0xf5, 0xff, 0x83, 0xec, 0x11, 0x75, 0x28, 0xa9, 0xe3, 0x33, 0xcb, 0x1e, 0xec, 0x20, 0x39, 0x32, 0x33, 0xf1, 0xf9, 0xfb, 0xd3, 0x88, 0xd2, 0xa0, 0x3c, 0x08, 0x70, 0x8d, 0x79, 0x8b, 0xe0, 0xd8, 0xbc, 0x80, 0x8f, 0x6b, 0xe9, 0x29, 0xe9, 0x9f, 0x4f, 0x93, 0x97, 0x4c, 0x44, 0x41, 0x32, 0x97, 0x37, 0x69, 0xcc, 0x06, 0xce, 0x49, 0x66, 0xc1, 0xc4, 0x70, 0xf1, 0x60, 0x4d, 0x32, 0x13, 0x37, 0x58, 0xfe, 0x35, 0x07, 0x1b, 0xb9, 0xa6, 0x98, 0x74, 0xe9, 0x1a, 0x32, 0x12, 0x1c, 0x26, 0x20, 0x0a, 0xc7, 0x3f, 0xa6, 0x3f, 0x84, 0x34, 0x23, 0x8f, 0xa8, 0x4c, 0x56, 0x28, 0x50, 0x6e, 0x8e,\n\t0xc6, 0x6b, 0x30, 0xb0, 0xfd, 0x33, 0x32, 0xbc, 0x6a, 0xb7, 0x52, 0xe3, 0x75, 0xfb, 0x21, 0xdb, 0x9a, 0xca, 0x2b, 0xc1, 0x91, 0x09, 0xec, 0xc1, 0x8e, 0x5d, 0xee, 0x75, 0xfa, 0x14, 0x25, 0x81, 0xab, 0xc9, 0xd1, 0x12, 0x74, 0xa7, 0xb1, 0xfb, 0x6f, 0x27, 0x4f, 0x01, 0xea, 0xe5, 0x65, 0xfd, 0x2f, 0x8c, 0x9d, 0x7a, 0x6e, 0x6c, 0x5e, 0x97, 0x54, 0x25, 0x52, 0x09, 0xdc, 0x8d, 0x5d, 0x03, 0x15, 0x7d, 0x8f, 0xed, 0x68, 0x17, 0x8d, 0x95, 0x90, 0x17, 0x25, 0xed, 0xdb, 0x1e, 0xed, 0xef, 0xdd, 0xdc, 0x19, 0x51, 0x2b, 0x35, 0x7c, 0xfa, 0xb3, 0xce, 0xa5, 0xc3, 0x6f, 0xb0, 0x9f, 0x3c, 0xf4, 0x10, 0xfb, 0xc9, 0x1b, 0xc3, 0xa3, 0xcb, 0x17, 0xc8, 0x84, 0x7c, 0x47, 0xae, 0x55, 0x0e, 0x29, 0xca, 0xba, 0x07, 0x87, 0x9f, 0xbc, 0xb1, 0xc2, 0x9b, 0xeb, 0x95, 0xa5, 0x64, 0x97, 0xf9, 0xe3,\n\t0x1f, 0x33, 0x72, 0x3c, 0xa7, 0x8e, 0x64, 0x9b, 0x1a, 0xe2, 0x32, 0x0a, 0x6e, 0x00, 0xd2, 0x08, 0xd1, 0x0c, 0x4d, 0x31, 0x23, 0x02, 0x28, 0xc2, 0xf0, 0x79, 0x04, 0x1f, 0x4d, 0x0c, 0x62, 0x36, 0x5e, 0x7f, 0x3a, 0xe6, 0xde, 0x8e, 0x12, 0x8b, 0xa7, 0x27, 0x06, 0x88, 0xa0, 0xdf, 0xed, 0x72, 0x3a, 0x2c, 0xa6, 0x2c, 0x9d, 0x12, 0xe5, 0xc6, 0xc9, 0x03, 0x79, 0x42, 0x1e, 0x8a, 0xf3, 0xe3, 0xfc, 0xf3, 0x39, 0xd7, 0x08, 0xe4, 0xd9, 0x3d, 0xc5, 0xc5, 0x86, 0x0f, 0x05, 0xd6, 0xd4, 0x84, 0x2b, 0x00, 0x7d, 0x4a, 0x25, 0xed, 0x9a, 0x37, 0xf6, 0xdc, 0xa9, 0xb1, 0xe7, 0x97, 0x2c, 0x7b, 0x19, 0x50, 0xf7, 0x9d, 0xf8, 0xdb, 0xbc, 0x3a, 0xbe, 0x56, 0xa9, 0x8e, 0x74, 0x6e, 0xee, 0xed, 0x7f, 0x74, 0x6b, 0xbb, 0x84, 0x7c, 0x63, 0xac, 0x4c, 0xd4, 0xbe, 0xfd, 0xb1, 0x45, 0x15, 0x03, 0x9d,\n\t0x8d, 0x6e, 0x81, 0x0a, 0x14, 0xca, 0x16, 0x2c, 0x1f, 0x1d, 0x7e, 0x03, 0xc8, 0x1e, 0x7a, 0x08, 0xc8, 0xde, 0x18, 0x5e, 0xda, 0x39, 0x20, 0x96, 0xc1, 0xa9, 0x55, 0xdc, 0xf8, 0xe4, 0xf0, 0x83, 0xeb, 0x5e, 0xd8, 0x52, 0x29, 0xb7, 0xe6, 0x3a, 0xf8, 0x42, 0x4e, 0xae, 0x7c, 0x76, 0xfc, 0x13, 0xfe, 0xfb, 0x70, 0x9e, 0x6a, 0xc8, 0xd3, 0x7d, 0x8f, 0xa3, 0x70, 0x90, 0xa7, 0xe3, 0x43, 0xfe, 0x97, 0x0f, 0x77, 0x0b, 0x49, 0x92, 0xa8, 0xfa, 0xaa, 0xbd, 0x49, 0x90, 0x51, 0x08, 0x3b, 0xa8, 0x74, 0xe2, 0xd6, 0xaf, 0x68, 0xe8, 0xc2, 0x0d, 0x11, 0x97, 0xe8, 0x99, 0x68, 0x88, 0x98, 0x9e, 0xb4, 0x9a, 0x79, 0x7a, 0xe3, 0x64, 0xe0, 0x5a, 0xed, 0xe0, 0x21, 0x34, 0xa6, 0x1a, 0x13, 0xb8, 0x2d, 0xae, 0x71, 0xa2, 0xd1, 0x00, 0x42, 0x93, 0xa3, 0xc9, 0xc9, 0x0e, 0x87, 0x82, 0x01, 0x3f, 0xca,\n\t0x0e, 0xc5, 0x65, 0xf9, 0x98, 0xc2, 0x28, 0xa6, 0x0c, 0x16, 0x5c, 0x75, 0xc1, 0x09, 0xa7, 0x14, 0xd2, 0xc7, 0xb1, 0x4d, 0x4c, 0xd5, 0xd0, 0xa3, 0xeb, 0x2a, 0x2a, 0xd6, 0x3d, 0x3a, 0x94, 0xfa, 0x1c, 0xfb, 0x99, 0x64, 0xd9, 0x53, 0x7f, 0xbc, 0xed, 0x9e, 0xcf, 0xce, 0xf4, 0xf5, 0x9d, 0xf9, 0xec, 0x9e, 0x5b, 0xff, 0xf4, 0xd4, 0x32, 0x09, 0xfb, 0xfe, 0x7b, 0xef, 0x3d, 0xd2, 0x72, 0xe4, 0xdd, 0x9d, 0x3b, 0x7e, 0x70, 0xb4, 0xb5, 0xf5, 0xe8, 0x0f, 0x76, 0xec, 0x7c, 0xf7, 0x48, 0x0b, 0xb9, 0xf5, 0xe8, 0xdf, 0x9f, 0x5e, 0x94, 0x66, 0x3f, 0xde, 0x18, 0xee, 0x7b, 0xea, 0xef, 0x47, 0xc7, 0xf6, 0xc1, 0x23, 0xb1, 0x17, 0xd5, 0x68, 0xfd, 0x02, 0x9e, 0xcf, 0x03, 0xf8, 0x7c, 0xfa, 0x89, 0x68, 0xb2, 0xc0, 0x02, 0x20, 0x72, 0x6c, 0xc4, 0x8c, 0x14, 0x09, 0xa8, 0x4c, 0x9a, 0x2b, 0x0e,\n\t0x5d, 0x1a, 0x51, 0xe5, 0x4f, 0xbf, 0xd7, 0x98, 0xa5, 0x84, 0x02, 0x3a, 0x7c, 0x42, 0xec, 0xe0, 0x23, 0xee, 0x49, 0xe9, 0x48, 0x7b, 0xb2, 0x02, 0x24, 0x02, 0x23, 0x06, 0x0a, 0xcb, 0xc0, 0x19, 0xc7, 0x2c, 0x07, 0xf5, 0x3c, 0xfb, 0xf7, 0xf4, 0x79, 0x05, 0x7f, 0xbc, 0x74, 0xde, 0x98, 0x13, 0x0e, 0xea, 0xd8, 0xf7, 0xa1, 0xb8, 0xfb, 0x00, 0x58, 0x51, 0xda, 0xd5, 0xb5, 0xad, 0x33, 0x50, 0xb3, 0xfb, 0x9b, 0x9b, 0xc1, 0x1f, 0x28, 0x09, 0xf8, 0x93, 0x2b, 0xd9, 0x13, 0x2b, 0x5e, 0x90, 0x70, 0x5e, 0xf9, 0x27, 0xb9, 0x54, 0xa8, 0x0f, 0xd8, 0xd9, 0x76, 0x28, 0xdd, 0xf2, 0xe7, 0x7b, 0x55, 0xb5, 0xfd, 0x9b, 0xeb, 0x17, 0x1c, 0x1f, 0x2e, 0xc3, 0x70, 0x6f, 0x82, 0x23, 0x7b, 0x04, 0x8e, 0xdb, 0x81, 0x72, 0x4d, 0xe0, 0x15, 0x47, 0xd1, 0x5a, 0x48, 0x0d, 0x9e, 0xd2, 0x37, 0x60, 0xe3,\n\t0x2f, 0xca, 0xd6, 0x60, 0x44, 0xf0, 0x3d, 0xc1, 0xa9, 0xca, 0x24, 0x70, 0xf1, 0x1d, 0xc0, 0xc1, 0xc1, 0x37, 0x87, 0x52, 0x32, 0x7e, 0xa3, 0x18, 0xd1, 0xb8, 0x10, 0x32, 0x44, 0xd9, 0xdf, 0x4f, 0xa7, 0xf1, 0x4a, 0x5f, 0x5f, 0x06, 0xdb, 0xfc, 0xec, 0x12, 0x7b, 0x23, 0x6d, 0x61, 0xab, 0xa9, 0xe2, 0x34, 0x72, 0xc9, 0x60, 0x9c, 0xb1, 0x11, 0xfa, 0xe3, 0x33, 0x67, 0xd8, 0x59, 0xdc, 0xf8, 0xc6, 0xc7, 0x99, 0x83, 0xe9, 0x9c, 0x0d, 0x72, 0x44, 0xde, 0x50, 0xe0, 0x33, 0x85, 0xfc, 0x40, 0x47, 0x10, 0x1c, 0xa5, 0x24, 0x21, 0x12, 0xa4, 0x75, 0x2b, 0x7a, 0xad, 0x0a, 0x49, 0x6c, 0x90, 0xdf, 0x81, 0x2c, 0x05, 0x92, 0x20, 0x73, 0x00, 0x76, 0x9c, 0xc2, 0x63, 0x21, 0xb7, 0xdc, 0xf0, 0xee, 0xd3, 0xb7, 0x2e, 0x89, 0x5e, 0x2a, 0xd9, 0xf7, 0x8b, 0xfb, 0xd3, 0x23, 0x28, 0xb0, 0x38, 0x98,\n\t0xdc, 0xa5, 0xf7, 0x8d, 0xb0, 0x85, 0xe0, 0xdd, 0xbe, 0x9b, 0xf2, 0x95, 0xc1, 0xb1, 0x15, 0x68, 0x00, 0xdc, 0x79, 0x29, 0x84, 0xeb, 0xb3, 0x31, 0xc5, 0xfb, 0xd7, 0x24, 0x2b, 0xb9, 0x1a, 0xd9, 0x08, 0xb3, 0x89, 0x32, 0x18, 0x78, 0x82, 0xaf, 0x9f, 0xc0, 0xc0, 0xff, 0x31, 0x4f, 0x1f, 0x75, 0x70, 0xa5, 0xb3, 0xb5, 0xd4, 0xe6, 0x6b, 0x10, 0x8f, 0x93, 0x60, 0xe8, 0x12, 0x38, 0xcf, 0xce, 0x9a, 0x99, 0x82, 0x78, 0x1e, 0x78, 0xff, 0xfd, 0x07, 0x3e, 0xe2, 0xc6, 0x8c, 0xfc, 0x66, 0x6b, 0x98, 0xd3, 0x84, 0x94, 0xc8, 0x27, 0x76, 0x27, 0x45, 0x6a, 0xec, 0x2d, 0x91, 0x0d, 0xe8, 0x06, 0xee, 0xbc, 0x9b, 0x20, 0x6a, 0xa6, 0x47, 0xd3, 0x87, 0xcd, 0x34, 0xe1, 0x62, 0xc9, 0x9d, 0x74, 0xf3, 0x97, 0x35, 0xc1, 0xc7, 0xd6, 0xc0, 0xdd, 0x4d, 0xcd, 0x9f, 0x99, 0x72, 0x4c, 0x91, 0x8b, 0x66,\n\t0x7e, 0x9e, 0xcb, 0x61, 0xd0, 0x43, 0xf4, 0x27, 0x05, 0x52, 0x1e, 0x9e, 0x72, 0x2c, 0xed, 0x4a, 0xac, 0xd1, 0xa9, 0x65, 0x14, 0x7f, 0x72, 0x09, 0xbe, 0xb4, 0xbb, 0x58, 0xdc, 0xa3, 0xd7, 0xf1, 0xf8, 0xe4, 0xbc, 0xdb, 0x6f, 0xbf, 0xed, 0xb6, 0xda, 0xd5, 0x2d, 0xfe, 0xa3, 0x3f, 0x1b, 0x38, 0xb2, 0x30, 0x0f, 0x6e, 0xed, 0xe2, 0xd1, 0xc4, 0xd0, 0x43, 0x37, 0x94, 0xd5, 0xed, 0x3c, 0xb7, 0x76, 0xc5, 0xf3, 0x7b, 0x9a, 0x4a, 0x76, 0xfe, 0xe8, 0x6e, 0xb0, 0x52, 0x4c, 0x9b, 0x1c, 0xbb, 0xcf, 0x3f, 0x7e, 0xfa, 0xa5, 0x50, 0xd7, 0x96, 0xd9, 0xcf, 0x5e, 0xa4, 0xe7, 0x08, 0x6a, 0x37, 0x3c, 0x3c, 0x94, 0xdd, 0x18, 0x35, 0x37, 0xec, 0x3a, 0x3f, 0x32, 0x7a, 0x7e, 0x57, 0x5d, 0xed, 0xd7, 0x00, 0xf1, 0xca, 0xfd, 0x40, 0xf2, 0xf6, 0x66, 0x89, 0x75, 0xc8, 0x91, 0x43, 0x22, 0x1b, 0xd8,\n\t0xf8, 0xa7, 0xb4, 0x00, 0xf3, 0x4c, 0x15, 0xc4, 0xb1, 0x73, 0xb9, 0x22, 0x9c, 0xf4, 0x21, 0xe5, 0xf4, 0x84, 0x02, 0xc6, 0xf1, 0x2c, 0xd0, 0x11, 0x4d, 0x55, 0xc6, 0x74, 0x64, 0x2c, 0xf8, 0x33, 0xde, 0x76, 0x65, 0x2a, 0xe8, 0x5c, 0xf3, 0xe9, 0x6b, 0x3e, 0x88, 0xf0, 0x19, 0xae, 0x23, 0x5a, 0x52, 0xe4, 0xf7, 0x6a, 0x2a, 0xb4, 0xe5, 0xd8, 0x9d, 0x95, 0x77, 0x95, 0x3b, 0x2b, 0x35, 0xa5, 0x66, 0xd3, 0x14, 0x37, 0x4d, 0x07, 0xb2, 0xae, 0x90, 0x79, 0x65, 0x43, 0xb3, 0x82, 0x05, 0x5d, 0xc3, 0x25, 0x85, 0x7d, 0x75, 0x41, 0x47, 0xcd, 0x4a, 0xca, 0x17, 0xb5, 0xc9, 0x4a, 0x17, 0xdf, 0xbc, 0xe3, 0xe6, 0xc5, 0xa5, 0xf5, 0x3b, 0x9f, 0x1b, 0x1e, 0x7d, 0xe6, 0xa6, 0xf2, 0x27, 0x4f, 0xe6, 0x76, 0x25, 0xdc, 0x81, 0xae, 0xed, 0x73, 0xc1, 0xab, 0x0e, 0xcb, 0xc1, 0x60, 0xe7, 0xcd, 0x1d,\n\t0xcd, 0xa3, 0xdd, 0x95, 0x16, 0x6d, 0x62, 0xde, 0x86, 0xe6, 0x9a, 0xcd, 0x0b, 0x62, 0x74, 0x0f, 0xca, 0x6f, 0xe5, 0x2a, 0x8a, 0x15, 0x55, 0x77, 0xad, 0x3d, 0xdc, 0x7b, 0xc3, 0x73, 0x37, 0x57, 0x35, 0x6c, 0x7f, 0x66, 0xd9, 0xc3, 0x3f, 0xaf, 0xc8, 0x8a, 0x56, 0xb5, 0x47, 0xf3, 0x17, 0xd4, 0x85, 0xb6, 0x5b, 0x2d, 0x58, 0x57, 0x8e, 0x6a, 0xdf, 0xde, 0x4d, 0x7d, 0x0e, 0xf9, 0x7e, 0x3d, 0x11, 0x46, 0x27, 0xc2, 0xc9, 0x59, 0x12, 0x53, 0xc0, 0x80, 0xc2, 0x77, 0x38, 0xa1, 0xd1, 0x84, 0x99, 0x28, 0x8c, 0xf5, 0x8c, 0x4c, 0xb3, 0x21, 0x4b, 0x2c, 0x06, 0x44, 0x28, 0x90, 0x15, 0x36, 0x84, 0xc5, 0x7a, 0x31, 0xc4, 0x1e, 0x42, 0x3e, 0x21, 0x02, 0x22, 0x61, 0x1a, 0x3c, 0x90, 0xd3, 0xb9, 0x21, 0x63, 0x72, 0x70, 0xc5, 0xd3, 0x26, 0xc6, 0x94, 0x3d, 0xdc, 0xa1, 0x24, 0xb5, 0x7d, 0x6b,\n\t0x34, 0x79, 0xad, 0xc5, 0x3f, 0x7d, 0x25, 0x58, 0x1f, 0xb1, 0xa8, 0xb3, 0x1b, 0xe3, 0xbc, 0xbe, 0x03, 0xf3, 0x02, 0xaa, 0x70, 0x53, 0xc9, 0xc8, 0xd6, 0xf2, 0xe5, 0xb7, 0xb6, 0xb2, 0xeb, 0x0e, 0xf6, 0x34, 0x3b, 0x8a, 0x83, 0x7a, 0xf6, 0x35, 0xf2, 0xaf, 0xec, 0x0f, 0xb3, 0x42, 0xe5, 0x6e, 0x53, 0x81, 0x3f, 0x6b, 0x97, 0xa7, 0x6a, 0x5e, 0xc4, 0xd1, 0x50, 0x19, 0x93, 0x6b, 0x36, 0x0e, 0x34, 0xad, 0x6d, 0x74, 0xa3, 0x62, 0xc8, 0x5c, 0x0d, 0x5f, 0x17, 0xfc, 0x3a, 0x45, 0xc7, 0x6b, 0x9a, 0x49, 0xc7, 0x4b, 0xb9, 0xd8, 0xc0, 0x05, 0xf2, 0x24, 0xb5, 0xf4, 0xca, 0xa9, 0x54, 0x1d, 0x65, 0xfc, 0x2c, 0xfd, 0x09, 0xe4, 0xce, 0xea, 0x39, 0xcb, 0xb3, 0x9e, 0x46, 0xca, 0x3f, 0x6a, 0x68, 0x7a, 0x3f, 0xa6, 0xa4, 0x0e, 0xdd, 0x99, 0xd0, 0x01, 0xa7, 0x6f, 0x70, 0xc2, 0x22, 0xd2, 0xcc,\n\t0x2a, 0x53, 0x7c, 0x39, 0x87, 0x2e, 0xf1, 0xbb, 0xc0, 0x87, 0xf4, 0x27, 0xec, 0x28, 0x7a, 0xdb, 0x17, 0xdc, 0x79, 0xd6, 0xb2, 0x8f, 0xd2, 0xe7, 0xe0, 0xbb, 0xa7, 0xe9, 0x82, 0x4d, 0xd7, 0xad, 0x0b, 0xd6, 0xcf, 0xa0, 0x0b, 0x86, 0xc7, 0xd0, 0x33, 0x55, 0x13, 0x5c, 0x50, 0x41, 0xa9, 0xe2, 0x10, 0x5d, 0x27, 0xd8, 0x1f, 0x89, 0x9c, 0xd9, 0x31, 0x2b, 0xd5, 0x65, 0x33, 0x6c, 0xba, 0xf2, 0x86, 0xd1, 0x7c, 0xb3, 0xc3, 0x55, 0x93, 0x28, 0xca, 0x71, 0x8a, 0xc8, 0xc3, 0x87, 0xc9, 0x1f, 0xdf, 0xf5, 0xa7, 0x67, 0xb6, 0x06, 0x78, 0x6c, 0x8b, 0xd9, 0x0e, 0x7a, 0xd9, 0x5f, 0xea, 0x9c, 0xe0, 0x43, 0x5d, 0xd5, 0xc6, 0x37, 0x80, 0xfe, 0xf5, 0x2b, 0xa7, 0xe0, 0xda, 0xe8, 0xc7, 0xc7, 0x79, 0x76, 0xea, 0xdf, 0x44, 0x11, 0xd2, 0x01, 0x47, 0x67, 0xd4, 0x01, 0x9b, 0x32, 0x3a, 0xe0, 0xfc,\n\t0xdc, 0xab, 0x75, 0xc0, 0xd4, 0x24, 0x1d, 0x30, 0x35, 0x5d, 0x07, 0xac, 0xce, 0xe8, 0x80, 0x53, 0x86, 0x43, 0x4e, 0xff, 0xc6, 0xb3, 0xef, 0x8f, 0xc6, 0x15, 0x2f, 0xeb, 0x6b, 0xb3, 0x17, 0x7f, 0x6b, 0x71, 0x76, 0xad, 0xfe, 0x25, 0x65, 0xbc, 0x70, 0x3f, 0xa0, 0x8c, 0x95, 0x79, 0x9e, 0xa8, 0x9e, 0x65, 0x4f, 0x9a, 0x73, 0xa4, 0xef, 0x6a, 0xca, 0x82, 0x1d, 0xdf, 0x9a, 0xdd, 0x19, 0x78, 0x57, 0x96, 0x63, 0x3e, 0xc1, 0xb2, 0x59, 0x85, 0x9e, 0xbc, 0x4a, 0xa3, 0x03, 0x4a, 0xc2, 0x5e, 0x2f, 0x5b, 0x06, 0x2e, 0xc2, 0xbf, 0xef, 0xba, 0x1c, 0xe0, 0x91, 0x70, 0x91, 0x4c, 0x9a, 0xeb, 0x05, 0x3b, 0x2c, 0x59, 0xec, 0x77, 0x1c, 0x4e, 0xf0, 0x3c, 0xdb, 0x52, 0x0d, 0x4a, 0xb2, 0x2c, 0xec, 0x0e, 0x6f, 0x9e, 0x54, 0x16, 0x0f, 0xe3, 0xfd, 0xcf, 0x1f, 0xff, 0x84, 0xca, 0x4b, 0xfb, 0x70,\n\t0x4b, 0x01, 0xcd, 0x18, 0xff, 0x13, 0xdd, 0xaf, 0xf3, 0x3f, 0xd4, 0xfd, 0x3a, 0xa7, 0xe9, 0x7e, 0x4b, 0x8b, 0x63, 0x85, 0x39, 0xe1, 0x50, 0xc0, 0xe5, 0xb0, 0x9a, 0xa7, 0xeb, 0x7e, 0x27, 0x0e, 0x0c, 0xe2, 0x78, 0xd2, 0xd1, 0xab, 0x38, 0x92, 0x03, 0xd3, 0xe6, 0xd8, 0x64, 0xdd, 0xef, 0xac, 0xe2, 0xc7, 0xd6, 0x2f, 0x3c, 0xdc, 0x0f, 0x05, 0xbc, 0xda, 0x48, 0xdf, 0x9a, 0xca, 0x35, 0x47, 0x5b, 0xf3, 0x06, 0x97, 0xcc, 0x73, 0x15, 0x49, 0xb3, 0xd4, 0x81, 0xd2, 0xce, 0x8a, 0x68, 0x67, 0xb1, 0x75, 0xc3, 0x96, 0x75, 0xeb, 0x86, 0x37, 0x1a, 0xa3, 0x6d, 0x85, 0x25, 0xb3, 0x8b, 0x3c, 0x52, 0x99, 0x5a, 0x4c, 0x1d, 0x8e, 0xd5, 0x64, 0x37, 0x2d, 0x2e, 0xb4, 0x56, 0x96, 0x45, 0x94, 0x96, 0x6d, 0x7d, 0xf5, 0xa3, 0x6d, 0x41, 0x95, 0xb7, 0x2c, 0xd4, 0xa0, 0xb2, 0xb9, 0x6d, 0xc6, 0x9c,\n\t0x0a, 0x4f, 0xc3, 0xdc, 0x5d, 0xed, 0x49, 0x73, 0xc4, 0xa7, 0xd3, 0x9b, 0xf5, 0x62, 0x25, 0x77, 0x5e, 0xc6, 0xc7, 0x71, 0x5e, 0x6d, 0xe3, 0x74, 0xbd, 0xaf, 0x69, 0x92, 0xde, 0xd7, 0x48, 0x18, 0xbe, 0x4c, 0xef, 0xcb, 0xe5, 0x2c, 0xa6, 0x2e, 0x5f, 0xa4, 0x69, 0x91, 0x5a, 0xc4, 0x66, 0x8b, 0xdd, 0xfa, 0x0d, 0x17, 0x68, 0x5a, 0xa3, 0x06, 0x3f, 0x15, 0x7b, 0xf4, 0x28, 0x79, 0x35, 0x79, 0x5c, 0x93, 0x6f, 0xd0, 0x7a, 0x64, 0x63, 0xbb, 0x55, 0x10, 0x00, 0xc7, 0x96, 0x69, 0xf2, 0xb3, 0xc2, 0x26, 0x72, 0x9b, 0xd2, 0x9e, 0x1e, 0x03, 0xce, 0x11, 0x6d, 0x45, 0x3a, 0x5f, 0x01, 0x20, 0x19, 0x88, 0xb3, 0x18, 0x38, 0x10, 0x86, 0x4b, 0xd0, 0x61, 0xc2, 0xa9, 0x1c, 0xe1, 0xc9, 0x74, 0x28, 0x21, 0x44, 0x3a, 0x53, 0x1c, 0x44, 0x06, 0xc0, 0xc0, 0x64, 0xc8, 0xe4, 0xf4, 0xbf, 0xe4, 0xdf,\n\t0xe5, 0x05, 0x10, 0x90, 0xc6, 0xb3, 0x0a, 0xbd, 0x79, 0x55, 0x10, 0x00, 0xf6, 0x47, 0x8b, 0x35, 0x08, 0x02, 0x57, 0x5c, 0xb8, 0xb0, 0x20, 0x58, 0xaa, 0xa5, 0x2e, 0xe8, 0xad, 0x69, 0xa0, 0x61, 0x17, 0x40, 0xc8, 0xc2, 0x70, 0x46, 0xfd, 0x9b, 0x6d, 0x75, 0x3a, 0x70, 0xbc, 0x25, 0xa4, 0xd1, 0x0a, 0x9c, 0xb3, 0x7a, 0xba, 0xbe, 0xd7, 0x74, 0x2d, 0x7d, 0xaf, 0xe9, 0xab, 0xf4, 0xbd, 0x9c, 0xab, 0x16, 0x56, 0x39, 0xa1, 0x93, 0x4c, 0x2b, 0x2e, 0xb0, 0x3f, 0x96, 0xe4, 0xd5, 0x74, 0x2e, 0x5c, 0x92, 0xdf, 0x1b, 0x73, 0xd6, 0x56, 0x97, 0x15, 0xb8, 0x45, 0xe4, 0x5d, 0xd4, 0xa2, 0xd7, 0xd8, 0x0f, 0x2f, 0x6c, 0xaa, 0xd6, 0x5b, 0xb7, 0xe8, 0xab, 0x37, 0x5e, 0x00, 0x59, 0xaf, 0x21, 0x1c, 0x03, 0xc7, 0xc3, 0x9b, 0x87, 0xf1, 0x7a, 0xf8, 0xda, 0xba, 0x5e, 0xd3, 0x75, 0xe8, 0x7a, 0x4d,\n\t0x5f, 0xaa, 0xeb, 0x95, 0x20, 0x2a, 0x10, 0x74, 0x3b, 0xed, 0x56, 0x54, 0xbb, 0x44, 0x1c, 0x96, 0x84, 0x39, 0x3a, 0x20, 0x9a, 0x4c, 0x07, 0x94, 0xea, 0x49, 0x8c, 0xd1, 0xb4, 0x49, 0x29, 0xe9, 0xdf, 0x0e, 0x0e, 0xe8, 0xf2, 0x5a, 0x8a, 0x7e, 0xf8, 0xc3, 0x15, 0xb7, 0xcf, 0xf3, 0xe5, 0x2f, 0xba, 0x75, 0x3e, 0xbb, 0x6a, 0xa6, 0x69, 0x1e, 0xe9, 0x6f, 0x72, 0x96, 0x67, 0x9b, 0xd8, 0xa7, 0xc1, 0x6f, 0x22, 0x73, 0xd6, 0x96, 0xd5, 0xde, 0xd8, 0x95, 0x7b, 0xf5, 0xcc, 0xd9, 0x8d, 0xe9, 0x3a, 0xf5, 0x04, 0x75, 0x99, 0x70, 0x23, 0x3f, 0x7d, 0x8b, 0x1c, 0x22, 0x2b, 0x94, 0xa5, 0x0c, 0x25, 0x2b, 0x06, 0xc4, 0x08, 0x03, 0xcf, 0x24, 0x65, 0x4a, 0x2b, 0x12, 0xe1, 0x0e, 0xb8, 0x09, 0x97, 0x23, 0xcb, 0xa7, 0xe4, 0xf1, 0xb2, 0xd2, 0x90, 0x8a, 0xc1, 0x14, 0x19, 0x08, 0xb0, 0xf7, 0xab,\n\t0x72, 0x92, 0x6e, 0x0d, 0x9b, 0x2a, 0x88, 0xb3, 0x7c, 0x3e, 0x7b, 0x46, 0x68, 0x56, 0xeb, 0x54, 0x16, 0x21, 0x7b, 0x9a, 0x27, 0x38, 0xfb, 0x35, 0x8d, 0x5f, 0x06, 0x02, 0x52, 0x9d, 0x48, 0xa4, 0x95, 0x02, 0x8f, 0xcc, 0xaf, 0xa1, 0x2e, 0x5f, 0x61, 0xc8, 0x7d, 0xd6, 0x66, 0xfb, 0xd8, 0x63, 0x4a, 0xb5, 0x5a, 0x49, 0x2e, 0xb0, 0xb7, 0xd8, 0xc6, 0x36, 0x53, 0x97, 0x55, 0x46, 0x56, 0x94, 0x15, 0x33, 0x99, 0x62, 0x59, 0xe0, 0x5f, 0x26, 0x65, 0xa6, 0xf6, 0x3c, 0xdc, 0x27, 0x31, 0x82, 0xe3, 0x94, 0xd5, 0xa2, 0x1f, 0xeb, 0x98, 0x26, 0x8f, 0x71, 0xaa, 0x16, 0xc6, 0x95, 0x51, 0x19, 0x53, 0xbf, 0xb9, 0xc8, 0xe6, 0x5e, 0xb8, 0x00, 0x7e, 0x8c, 0x0e, 0x0c, 0xf8, 0x19, 0x1b, 0xa6, 0x3e, 0x67, 0x47, 0xc0, 0x51, 0x54, 0xbb, 0x18, 0x12, 0x95, 0x00, 0xde, 0x7f, 0x07, 0xd2, 0x71, 0x3b,\n\t0x67, 0xd0, 0x71, 0x9b, 0xae, 0xd2, 0x71, 0x13, 0x48, 0xe7, 0xd7, 0x8d, 0x9a, 0xc1, 0x91, 0x90, 0x74, 0xff, 0x0c, 0xad, 0x7a, 0x92, 0x16, 0xb4, 0xe7, 0x19, 0x6e, 0x18, 0xed, 0xba, 0x43, 0xe2, 0xe0, 0x76, 0x5d, 0x7c, 0xcd, 0x5d, 0xcf, 0xa8, 0xb8, 0xe9, 0xe7, 0x06, 0x97, 0xea, 0xf2, 0x5a, 0xe3, 0x3f, 0xfc, 0xc1, 0xca, 0xa3, 0x3d, 0xbe, 0xfc, 0xc5, 0xb7, 0xcc, 0x67, 0x57, 0x72, 0x53, 0xb8, 0x38, 0xc3, 0x0e, 0x4f, 0x4c, 0x09, 0xed, 0x2c, 0xe2, 0x57, 0xd2, 0x35, 0xdf, 0xb9, 0x98, 0x87, 0xe5, 0x1c, 0x8e, 0xb6, 0xcf, 0xa0, 0xe4, 0x76, 0x4e, 0x56, 0x72, 0x9b, 0xbe, 0xa2, 0x09, 0x06, 0x66, 0xe3, 0xb5, 0xc2, 0x23, 0xb0, 0x2a, 0x1c, 0xb9, 0x20, 0xc6, 0x7d, 0x39, 0x9c, 0xc2, 0x75, 0x5a, 0x0a, 0x4a, 0x20, 0x97, 0x1e, 0xdf, 0xb7, 0xf7, 0x1e, 0x29, 0x90, 0xdf, 0xb3, 0x6b, 0xcf,\n\t0x31, 0x39, 0x08, 0x4e, 0xab, 0x0f, 0x0f, 0x5e, 0x3f, 0xf9, 0xf0, 0xc3, 0x27, 0x77, 0xdd, 0x7d, 0xdf, 0x7d, 0x77, 0x83, 0x37, 0xa7, 0x97, 0x88, 0xcf, 0xd4, 0x1f, 0xc6, 0x70, 0x30, 0x45, 0xdf, 0x6d, 0xba, 0x96, 0xbe, 0x9b, 0xdb, 0x77, 0x6a, 0x5e, 0x9a, 0x89, 0x01, 0xb0, 0x11, 0x41, 0x7d, 0x90, 0x7e, 0x9e, 0x4c, 0x47, 0x33, 0x9b, 0x66, 0xb4, 0x51, 0x47, 0x1d, 0xd4, 0x07, 0xec, 0xce, 0x8b, 0xec, 0x4e, 0xea, 0x0d, 0xdc, 0xc1, 0xd2, 0xbb, 0xb8, 0x31, 0x40, 0x80, 0xa4, 0x0d, 0x34, 0x4d, 0x58, 0x88, 0xca, 0x17, 0x8d, 0x58, 0xfd, 0xcc, 0x25, 0x1c, 0x52, 0x66, 0xb4, 0xd0, 0xce, 0x94, 0x16, 0x1a, 0x67, 0x5d, 0xe0, 0x7a, 0x4f, 0xd3, 0x34, 0xfc, 0x7b, 0xcf, 0x39, 0x87, 0xda, 0xe3, 0xe6, 0xf4, 0xd3, 0x14, 0x17, 0x78, 0x31, 0x49, 0x41, 0x9d, 0x2a, 0x67, 0x40, 0xfe, 0x52, 0x95,\n\t0x5b, 0x54, 0xe5, 0x35, 0xb9, 0x35, 0x02, 0x4b, 0xa8, 0x44, 0xc1, 0xfe, 0xf4, 0x2c, 0xbb, 0x0c, 0xb9, 0x70, 0x7f, 0x2c, 0x53, 0x0b, 0x04, 0x5a, 0x09, 0xd5, 0x5c, 0xdc, 0x10, 0x90, 0xf1, 0x84, 0x62, 0x7a, 0xb5, 0x27, 0x78, 0xe5, 0x3d, 0xce, 0x87, 0x3b, 0xd0, 0xe6, 0xf3, 0xb5, 0x06, 0xe1, 0xfe, 0xb7, 0xb0, 0x8f, 0x32, 0x55, 0x90, 0xe7, 0x47, 0xfb, 0xef, 0x03, 0xaa, 0x09, 0x1f, 0x31, 0xc3, 0x24, 0xef, 0x2f, 0xe7, 0x24, 0xef, 0x2f, 0x07, 0xf2, 0xfe, 0xb2, 0xf0, 0xd2, 0xfe, 0xbd, 0x5f, 0xd6, 0xd4, 0x35, 0xd1, 0x54, 0x79, 0xfd, 0xbd, 0x6a, 0xaf, 0xbf, 0x57, 0xfd, 0xf5, 0xf6, 0x7a, 0x5d, 0x1d, 0x72, 0x5e, 0xbf, 0x32, 0x9f, 0x17, 0x6b, 0xe2, 0x35, 0x4a, 0x0d, 0xd6, 0xc4, 0x7b, 0x90, 0x4b, 0xa7, 0xd7, 0xe7, 0xc2, 0xe9, 0x9a, 0x67, 0xf6, 0x68, 0xb3, 0x9c, 0x79, 0xf1, 0xc5,\n\t0x33, 0x4f, 0x3d, 0xfd, 0xe2, 0x8b, 0x4f, 0x3f, 0x7b, 0xf3, 0x3b, 0x28, 0x73, 0xc0, 0x3b, 0x37, 0x9f, 0xdf, 0xfa, 0x36, 0xfa, 0xf2, 0xf6, 0xd6, 0xf3, 0x7b, 0x45, 0x17, 0x9f, 0x78, 0xe2, 0x4d, 0x91, 0xe8, 0xcd, 0x27, 0x9e, 0xb8, 0x28, 0xa2, 0x76, 0xf1, 0x5a, 0xf7, 0xbf, 0xba, 0x6e, 0xfd, 0xab, 0xfb, 0x5b, 0x78, 0xec, 0x73, 0xa0, 0x95, 0xd7, 0xb2, 0xff, 0xd5, 0xf5, 0xeb, 0x5e, 0xdd, 0xdf, 0xca, 0x03, 0x77, 0xa7, 0xe0, 0x16, 0xf2, 0xb2, 0xf7, 0x42, 0xb8, 0xcb, 0xe8, 0xde, 0x4d, 0xff, 0xb1, 0xee, 0x9d, 0xbe, 0xd7, 0x6e, 0xd8, 0x78, 0xe5, 0x7e, 0x84, 0x02, 0xee, 0xe2, 0xd8, 0x50, 0x88, 0xcd, 0x4e, 0x21, 0xc8, 0xe4, 0xfa, 0xc7, 0xe7, 0x62, 0x42, 0xf7, 0x6e, 0xfa, 0x4f, 0x75, 0xef, 0xd4, 0x6f, 0xd8, 0x33, 0x90, 0xf3, 0x65, 0x9f, 0x4e, 0xe1, 0x49, 0xf6, 0x37, 0x13, 0xef,\n\t0xe0, 0x7c, 0x69, 0xe1, 0x69, 0xd9, 0x8d, 0x63, 0x72, 0x42, 0x49, 0xbf, 0x62, 0x06, 0xdd, 0xbb, 0x69, 0x42, 0xf7, 0xae, 0x24, 0x94, 0x1a, 0xd5, 0x64, 0xdd, 0x3b, 0x98, 0xd0, 0xbd, 0x53, 0xbb, 0x2f, 0xec, 0xfe, 0xfd, 0x93, 0xfd, 0x17, 0x63, 0xc3, 0x0f, 0xae, 0xc2, 0x08, 0xf9, 0xb4, 0x53, 0x1e, 0xdf, 0xbf, 0x1e, 0xcc, 0x66, 0x7f, 0x50, 0xd7, 0xe9, 0x90, 0x66, 0x81, 0xb7, 0x32, 0x67, 0x9d, 0xf9, 0x10, 0xe3, 0xfc, 0x8c, 0xde, 0xdd, 0x74, 0xbd, 0x7a, 0x77, 0xe6, 0xc3, 0x2f, 0x1e, 0xb8, 0x00, 0x6e, 0xb9, 0x08, 0x0e, 0x71, 0x85, 0x48, 0xb8, 0x85, 0x42, 0x13, 0xc1, 0x6b, 0xc5, 0x7b, 0x04, 0xd7, 0x3b, 0x49, 0xeb, 0xdd, 0x4d, 0xff, 0xb7, 0x7a, 0x77, 0xde, 0x23, 0x76, 0xc3, 0xa6, 0x2f, 0x8e, 0x71, 0x6f, 0x9a, 0xbe, 0x2d, 0x78, 0x6b, 0x20, 0x8d, 0x31, 0x43, 0x7c, 0xb1, 0x08,\n\t0xd3, 0x18, 0xd3, 0x8c, 0x7a, 0x77, 0xd3, 0x14, 0xbd, 0x3b, 0x22, 0x1b, 0x29, 0x82, 0x61, 0x92, 0x98, 0x38, 0x82, 0x21, 0xb8, 0x26, 0xc1, 0x88, 0x42, 0x09, 0xf1, 0xc3, 0xab, 0x38, 0x83, 0xf5, 0xec, 0xb7, 0xc1, 0xe5, 0x99, 0x38, 0x81, 0x25, 0xf7, 0x60, 0x02, 0x81, 0xe5, 0x59, 0xc6, 0x8d, 0xc7, 0x64, 0x80, 0x73, 0x2d, 0x4f, 0x96, 0x08, 0xd2, 0xa3, 0x12, 0xf2, 0x48, 0xc4, 0x73, 0xf1, 0x27, 0x53, 0x33, 0xa3, 0x11, 0x8f, 0xca, 0x62, 0x84, 0xc4, 0x0c, 0x8f, 0xcc, 0x20, 0x31, 0x7c, 0x05, 0x03, 0x13, 0x51, 0xa2, 0x8d, 0x27, 0xb5, 0x4b, 0x97, 0x4e, 0x1a, 0x1b, 0x22, 0x63, 0xeb, 0x5f, 0xa6, 0x7e, 0x73, 0x61, 0xa6, 0xb1, 0x7d, 0xce, 0x6e, 0x04, 0x07, 0xd0, 0x5e, 0x11, 0x1c, 0x5d, 0xa6, 0x6e, 0x49, 0x8d, 0x6f, 0x9a, 0xde, 0xdf, 0x34, 0x45, 0xef, 0x8f, 0x06, 0x36, 0x75, 0x48,\n\t0xfc, 0x6b, 0x0f, 0x69, 0xc6, 0xe1, 0x5c, 0x63, 0x2c, 0x1c, 0x0c, 0xc6, 0xa1, 0xcc, 0xb3, 0x11, 0xd2, 0xd1, 0x6c, 0x62, 0xf3, 0x8b, 0x2a, 0x40, 0x65, 0xcc, 0xa3, 0xd9, 0x5f, 0xa5, 0xf9, 0xbf, 0x4e, 0x71, 0xa7, 0xff, 0x1a, 0xe2, 0x8e, 0xd8, 0xe5, 0x56, 0xaa, 0x5c, 0xde, 0x49, 0xc6, 0x82, 0x09, 0x52, 0x3a, 0x91, 0x9e, 0x67, 0xaa, 0xa1, 0xa0, 0xaa, 0xf2, 0xb1, 0xd5, 0xeb, 0x5f, 0xd8, 0x92, 0xa8, 0xdb, 0xf4, 0xe8, 0xa2, 0xf8, 0xaa, 0x25, 0xdd, 0xae, 0x28, 0x14, 0x69, 0x3c, 0x45, 0x1d, 0x89, 0x8d, 0xf7, 0xca, 0xd8, 0x10, 0xf8, 0x89, 0x20, 0xb7, 0x71, 0x28, 0x11, 0x6f, 0x8e, 0x7a, 0x14, 0x0a, 0xa5, 0x80, 0xda, 0x95, 0xac, 0x6b, 0xbb, 0xe5, 0xb5, 0x1b, 0x6e, 0xbe, 0xb0, 0xaf, 0x0e, 0x09, 0x32, 0x55, 0x2a, 0x8b, 0xd3, 0xf2, 0xd0, 0xf1, 0x03, 0xb5, 0xab, 0x9b, 0xfd, 0x7a,\n\t0x93, 0x5e, 0x9a, 0xb2, 0x0f, 0x40, 0x3e, 0x82, 0x3a, 0x8a, 0xe7, 0xbf, 0x3d, 0x29, 0xca, 0x06, 0x80, 0x6f, 0x82, 0x72, 0xdf, 0x84, 0xcc, 0x87, 0xd2, 0x09, 0x11, 0xe4, 0x08, 0x4a, 0x67, 0x42, 0x31, 0x34, 0x9c, 0x1c, 0x41, 0x41, 0xdc, 0xd3, 0x9f, 0x4e, 0xa5, 0xef, 0x44, 0x38, 0x08, 0xa7, 0xd2, 0x77, 0xf0, 0xf0, 0x22, 0x5c, 0x77, 0x7b, 0x17, 0xf2, 0x43, 0x16, 0xfb, 0xbd, 0x2e, 0xa7, 0x52, 0xe3, 0xc2, 0x8b, 0x00, 0xa6, 0x19, 0x0e, 0x66, 0x2c, 0x85, 0xa0, 0xd3, 0x53, 0x9d, 0x02, 0xa5, 0x42, 0xe1, 0x89, 0x36, 0xc7, 0x13, 0x43, 0x4d, 0xb9, 0x02, 0xf0, 0x53, 0x36, 0x24, 0x3b, 0xb9, 0x29, 0xd1, 0x51, 0xe4, 0x51, 0x67, 0x49, 0xa3, 0xae, 0xee, 0x25, 0xab, 0xe2, 0x8b, 0x1e, 0xdd, 0x54, 0x97, 0xd8, 0xf2, 0xc2, 0xfa, 0xd5, 0x8f, 0x55, 0x52, 0x49, 0xb1, 0x14, 0xce, 0xd6, 0xdf,\n\t0xbc, 0xba, 0xf6, 0xc0, 0xf1, 0x87, 0xe0, 0x0a, 0xa8, 0xaa, 0x42, 0x65, 0x5e, 0x55, 0xdd, 0xbe, 0x0b, 0x37, 0xdf, 0xf0, 0xda, 0x2d, 0x6d, 0xc8, 0x23, 0x1f, 0xc2, 0xe2, 0xf8, 0x27, 0xcc, 0xfb, 0x70, 0x0d, 0xc4, 0x84, 0xf7, 0x4b, 0x6c, 0x07, 0xce, 0xeb, 0xb5, 0x1d, 0x38, 0xbf, 0xda, 0x76, 0x60, 0xca, 0xd8, 0x04, 0x9c, 0x5f, 0x6a, 0x3b, 0x98, 0xdc, 0x6e, 0x66, 0xdb, 0x81, 0x44, 0x02, 0x08, 0x89, 0x57, 0xe2, 0xf5, 0x20, 0xfb, 0x8c, 0xdd, 0x6c, 0x54, 0x29, 0xb8, 0xd2, 0x05, 0xa2, 0x49, 0xfa, 0x49, 0x5c, 0x42, 0x66, 0x8a, 0x6e, 0x92, 0xf4, 0xb9, 0x30, 0x27, 0x4a, 0x93, 0x07, 0x76, 0xef, 0x3e, 0xb0, 0x7f, 0xf7, 0x6e, 0xf6, 0x55, 0x51, 0xc3, 0x86, 0x07, 0x06, 0x86, 0x9f, 0xde, 0x5c, 0x55, 0xb3, 0xe5, 0xe9, 0x15, 0x43, 0x0f, 0xdd, 0x58, 0x27, 0xf8, 0xcb, 0x85, 0x0b, 0x87,\n\t0xde, 0x38, 0x7b, 0xf6, 0xc2, 0x85, 0xb3, 0x67, 0xdf, 0x00, 0xdf, 0x5e, 0xf6, 0xd8, 0xfa, 0x8a, 0x34, 0xcb, 0x96, 0xb8, 0xe9, 0x89, 0x95, 0x6c, 0x2d, 0x3c, 0x44, 0xed, 0x58, 0x8f, 0x03, 0x41, 0x89, 0xe2, 0x64, 0x2c, 0x3f, 0xd2, 0xb6, 0x5b, 0x67, 0xb0, 0x11, 0x20, 0x7a, 0x6d, 0x4a, 0x1b, 0x09, 0x90, 0xa3, 0x85, 0xd8, 0x2f, 0xf6, 0x99, 0x0c, 0x0a, 0x99, 0x54, 0x02, 0x1f, 0x13, 0x3a, 0x04, 0xd8, 0x50, 0x90, 0x52, 0xa5, 0x46, 0x38, 0x3d, 0x09, 0x84, 0x03, 0x4a, 0x46, 0x4d, 0x36, 0x14, 0x90, 0x5f, 0x7b, 0x30, 0xde, 0x98, 0xad, 0x1e, 0x5d, 0x02, 0x1a, 0x5e, 0xae, 0xb5, 0x78, 0x4d, 0x1a, 0xd1, 0x0f, 0x45, 0x3a, 0xb3, 0xd7, 0xb8, 0x1f, 0x58, 0x3c, 0xc9, 0xe6, 0x15, 0x55, 0xd6, 0xe0, 0x82, 0x3b, 0x96, 0x91, 0x2e, 0xd0, 0x69, 0x2b, 0x28, 0xb3, 0xb6, 0xf5, 0x80, 0x4b, 0x88,\n\t0xf6, 0x08, 0x55, 0x46, 0x05, 0xfb, 0x5b, 0xa5, 0x41, 0x29, 0x04, 0x9b, 0x12, 0x3a, 0x51, 0xb4, 0x7e, 0x4e, 0x38, 0xb6, 0xbc, 0x23, 0x42, 0x80, 0xf1, 0xf7, 0xd9, 0x73, 0xd4, 0x27, 0xcc, 0x45, 0xc2, 0x45, 0x2c, 0x4d, 0xca, 0x11, 0x0b, 0xa7, 0x87, 0xd0, 0x4b, 0x36, 0x8a, 0x84, 0x24, 0x59, 0xcf, 0x29, 0x40, 0x2d, 0x3c, 0x40, 0x43, 0x86, 0x99, 0xa0, 0x29, 0x9c, 0xcb, 0x07, 0xe2, 0xa8, 0x01, 0x6c, 0xed, 0x48, 0x73, 0x7f, 0x33, 0xdf, 0xc7, 0x2a, 0x31, 0xc4, 0x05, 0x26, 0x39, 0xda, 0xa5, 0xce, 0xe5, 0x00, 0x9c, 0x4b, 0x32, 0xaf, 0x21, 0xf9, 0xbe, 0x4c, 0xdc, 0x01, 0x62, 0x48, 0x5c, 0xd1, 0x08, 0xa7, 0x23, 0x07, 0xcd, 0xc9, 0x93, 0x83, 0x2f, 0x3e, 0xb7, 0x6f, 0xe3, 0x7d, 0x91, 0xf6, 0xb8, 0xc5, 0x56, 0xd2, 0x1e, 0x69, 0xda, 0x5d, 0x74, 0xf1, 0xd9, 0x67, 0x2f, 0x82, 0x6e,\n\t0xf6, 0x09, 0xca, 0x51, 0xd5, 0xfa, 0xe1, 0xcf, 0x7f, 0xc5, 0xf6, 0x7f, 0xb3, 0xa2, 0xe7, 0xb9, 0x57, 0xde, 0x5a, 0xdb, 0xbc, 0xb6, 0xc1, 0x55, 0x57, 0x31, 0xb6, 0x86, 0xae, 0x3b, 0xf6, 0xc7, 0x3f, 0x1e, 0x23, 0x52, 0xf6, 0x5f, 0xba, 0x94, 0x91, 0x63, 0x59, 0xa7, 0x2e, 0x59, 0x8d, 0x72, 0x65, 0x8c, 0x66, 0xd4, 0xf9, 0x88, 0x7b, 0x62, 0x7a, 0xb8, 0x7d, 0x10, 0x4e, 0xc3, 0xaf, 0xff, 0xa9, 0x14, 0x13, 0xc5, 0xe4, 0x11, 0x0e, 0x99, 0xbc, 0xc8, 0x49, 0x31, 0xbf, 0xff, 0x5d, 0x46, 0x8a, 0x59, 0xc4, 0xfe, 0x1b, 0xf0, 0x5f, 0x06, 0x55, 0xec, 0xb7, 0x66, 0xc2, 0xbb, 0x8b, 0x8f, 0x81, 0x2c, 0xf6, 0x4f, 0xc7, 0x3e, 0xc6, 0xb8, 0x67, 0x29, 0x7d, 0x80, 0x7c, 0x15, 0xfb, 0xcd, 0xa1, 0x78, 0x12, 0xa4, 0x45, 0x26, 0x48, 0x9c, 0x2b, 0xd2, 0x80, 0x4c, 0x32, 0x7a, 0xad, 0x5c, 0x0a,\n\t0x61, 0xd9, 0x04, 0x4c, 0x0c, 0x2f, 0x9d, 0x52, 0xb4, 0x40, 0x37, 0x49, 0x61, 0x5c, 0x8a, 0x82, 0x99, 0xc1, 0x51, 0x7f, 0xdc, 0x21, 0x5f, 0xa7, 0xd1, 0x05, 0x5a, 0xd7, 0xd6, 0xd5, 0xad, 0x6d, 0x0d, 0xe8, 0x34, 0xeb, 0xe4, 0x8e, 0x38, 0xfd, 0x89, 0xca, 0x5f, 0x99, 0xeb, 0xd6, 0x15, 0xcc, 0x2e, 0xb6, 0xd9, 0x8a, 0x67, 0x17, 0xe8, 0xdc, 0xb9, 0x95, 0x7e, 0x14, 0x7b, 0xff, 0x14, 0xbd, 0x96, 0x5c, 0xcf, 0x94, 0x73, 0xf5, 0xa9, 0x71, 0xca, 0xb2, 0x51, 0x94, 0x2c, 0x92, 0x24, 0xba, 0xd3, 0x6a, 0x6c, 0x82, 0x6c, 0x9b, 0xf2, 0x72, 0xd1, 0x97, 0xbc, 0xfc, 0x88, 0xc9, 0xa5, 0x15, 0x0e, 0xaa, 0x95, 0xf6, 0xb2, 0x39, 0x85, 0x91, 0xae, 0x32, 0x87, 0x4a, 0x35, 0x24, 0xd0, 0xba, 0xe8, 0x77, 0xc5, 0xc6, 0x90, 0xdd, 0xae, 0x76, 0x17, 0xfb, 0x75, 0x3a, 0x7f, 0xb1, 0x5b, 0x6d, 0xb7,\n\t0x87, 0x8c, 0x29, 0x7c, 0xbb, 0x94, 0xf9, 0x37, 0xf9, 0x2a, 0x9f, 0xfa, 0xff, 0xe9, 0xfd, 0x33, 0x4f, 0x9e, 0xb7, 0x50, 0xe9, 0x4b, 0xa0, 0xc9, 0xb7, 0x44, 0xcd, 0xe6, 0x68, 0x0b, 0x9a, 0x7c, 0xc2, 0xa7, 0xe4, 0x74, 0xae, 0x87, 0xc6, 0xff, 0x01, 0xee, 0x80, 0x6b, 0x8e, 0xa4, 0x46, 0x24, 0x69, 0x23, 0x0f, 0x6e, 0x64, 0x05, 0x1b, 0xc8, 0x04, 0x41, 0x0c, 0x53, 0x90, 0x33, 0xb2, 0x9a, 0x35, 0x2a, 0xd8, 0x46, 0xaa, 0x63, 0x50, 0x8a, 0x3e, 0x9c, 0x7d, 0xc8, 0x85, 0xdc, 0x2b, 0xa8, 0x69, 0xf9, 0x0c, 0xc1, 0x1a, 0x9a, 0x2f, 0xe2, 0xed, 0xe1, 0x89, 0xf8, 0x74, 0x50, 0xe3, 0xce, 0x33, 0x9b, 0xf2, 0x50, 0xbe, 0xbb, 0x3c, 0x93, 0x39, 0xcf, 0xad, 0x61, 0x4e, 0x8d, 0x5d, 0xcc, 0x9e, 0xdb, 0xbd, 0x20, 0x12, 0x59, 0xd0, 0x3d, 0x37, 0x9b, 0x2c, 0xfb, 0xe2, 0x7f, 0x4d, 0xbe, 0x0b,\n\t0x5b, 0x73, 0xf1, 0x66, 0xff, 0xa0, 0xf2, 0x98, 0x33, 0x84, 0x8f, 0x28, 0x45, 0xde, 0x36, 0x13, 0x19, 0x4d, 0xa0, 0x04, 0x4e, 0xaf, 0x49, 0x47, 0x17, 0xad, 0x42, 0x74, 0x03, 0x4b, 0xa8, 0xc3, 0x4c, 0x33, 0x24, 0x1a, 0x61, 0x33, 0x4e, 0x67, 0xa2, 0xce, 0x20, 0x35, 0x5a, 0x0e, 0x5c, 0x3e, 0xef, 0x44, 0x41, 0x74, 0x97, 0xd3, 0x37, 0x3d, 0xf5, 0x62, 0x9b, 0xbd, 0x79, 0xfe, 0x8a, 0xf2, 0xf6, 0x83, 0x03, 0x45, 0xd9, 0x35, 0xed, 0xf5, 0x11, 0x46, 0xbd, 0x57, 0xc6, 0x04, 0xab, 0x3b, 0xea, 0xf2, 0xec, 0x45, 0xcd, 0xa1, 0xb2, 0xae, 0x52, 0xaf, 0xd4, 0x22, 0x3d, 0xa2, 0x71, 0x4d, 0x9e, 0x83, 0x4b, 0xc3, 0x98, 0x2d, 0x85, 0x7e, 0x7d, 0xce, 0xdc, 0x4d, 0x4d, 0xcd, 0x6b, 0x3b, 0xca, 0x63, 0x51, 0xc7, 0xb1, 0x47, 0x73, 0x6a, 0x4a, 0x8b, 0x6a, 0xbb, 0xcb, 0x02, 0x55, 0xb9, 0x06,\n\t0x48, 0x4f, 0x0c, 0x97, 0xcf, 0x5c, 0x35, 0x2b, 0x9c, 0xaf, 0x16, 0xce, 0x6b, 0x3f, 0xf3, 0x1c, 0xa1, 0x26, 0x92, 0xc8, 0x9a, 0x10, 0x80, 0xf3, 0xc9, 0x71, 0x91, 0x90, 0x33, 0x68, 0x0c, 0x02, 0xb2, 0x81, 0xa0, 0x68, 0x88, 0x33, 0x88, 0x11, 0x14, 0xed, 0x8d, 0xd1, 0xfb, 0x00, 0x66, 0x11, 0xd3, 0xd5, 0x0f, 0x01, 0x51, 0x51, 0x56, 0x5a, 0x8c, 0x2a, 0xd1, 0x70, 0x86, 0x60, 0x94, 0xde, 0xd7, 0x33, 0x4d, 0xd6, 0xa6, 0x32, 0x3c, 0x03, 0x9a, 0x7b, 0x0e, 0xf0, 0x51, 0x71, 0x2c, 0x57, 0x32, 0x29, 0xcc, 0x82, 0x3d, 0x3b, 0xcf, 0x4c, 0x9e, 0x0b, 0x9c, 0x9b, 0xd8, 0x3e, 0x37, 0xbb, 0x65, 0xe7, 0xc2, 0xc2, 0xe2, 0xb9, 0x43, 0xf3, 0x2b, 0x79, 0x60, 0x93, 0x39, 0xaa, 0x3f, 0xff, 0xe2, 0x01, 0x46, 0x29, 0xc8, 0x2a, 0x4f, 0x56, 0xe4, 0x59, 0x0d, 0x79, 0x35, 0x41, 0x4b, 0x48, 0xa0,\n\t0xd3, 0x52, 0xff, 0x9e, 0x34, 0x21, 0xbc, 0x20, 0xf4, 0x41, 0x89, 0xd4, 0xdf, 0x72, 0x43, 0xe3, 0xec, 0x35, 0x2d, 0x45, 0x85, 0x65, 0xa1, 0xd3, 0xb3, 0x1e, 0x68, 0x25, 0x97, 0xe5, 0x8c, 0xfd, 0x53, 0x5d, 0x17, 0xb4, 0xe5, 0x85, 0x83, 0x79, 0x25, 0x5e, 0x67, 0x49, 0xd8, 0x20, 0x50, 0x40, 0x19, 0x99, 0x18, 0x62, 0xff, 0x06, 0x06, 0x89, 0x7f, 0x23, 0xa7, 0xb1, 0xa4, 0x49, 0x03, 0x88, 0xfa, 0x4c, 0x4e, 0xe4, 0xa5, 0x28, 0x57, 0x37, 0x9c, 0x93, 0x0d, 0xd8, 0x50, 0x5a, 0xbd, 0xc8, 0xb4, 0xca, 0xa3, 0x7c, 0x1f, 0xce, 0xf4, 0x57, 0x41, 0xc5, 0x7f, 0x63, 0xca, 0x86, 0x87, 0xc9, 0x91, 0x63, 0xb6, 0xe7, 0x3b, 0x14, 0xc6, 0x82, 0xc6, 0x5c, 0x87, 0x5c, 0xc8, 0x17, 0xd9, 0x6d, 0x26, 0x1e, 0xda, 0x21, 0x94, 0xd8, 0x56, 0x1f, 0x88, 0xd9, 0xb2, 0x97, 0x2e, 0x59, 0xe0, 0xb3, 0xc9,\n\t0x94, 0x7c, 0x39, 0x5f, 0xec, 0xce, 0x2d, 0xb6, 0x8f, 0x8f, 0x13, 0xbb, 0xe1, 0xbb, 0x0f, 0x51, 0xbf, 0x24, 0xbc, 0x20, 0xee, 0x22, 0x00, 0x1f, 0x94, 0x10, 0x46, 0xf2, 0xf7, 0x84, 0xf0, 0x59, 0x00, 0xbe, 0x41, 0xfe, 0x1e, 0x79, 0xff, 0xc3, 0x36, 0x9b, 0xe0, 0x19, 0xd8, 0x81, 0xdb, 0x94, 0x28, 0xb8, 0x36, 0x8a, 0xa9, 0x6d, 0xe0, 0x1c, 0x56, 0xc0, 0x36, 0x23, 0x70, 0x0e, 0x53, 0x72, 0x4b, 0xc2, 0xad, 0xe1, 0x52, 0x40, 0xc6, 0xa7, 0xc1, 0xd6, 0x8a, 0xe9, 0x70, 0x73, 0xe3, 0x55, 0x40, 0x01, 0xdf, 0x0b, 0xfb, 0x64, 0xb6, 0xc1, 0x3e, 0xe1, 0x7b, 0x61, 0x8f, 0x3e, 0x50, 0x42, 0xa3, 0xc8, 0x22, 0xf8, 0x7e, 0x92, 0xcf, 0xe5, 0xb4, 0xa5, 0xce, 0x82, 0x4e, 0x1e, 0xd2, 0x3f, 0xf0, 0x9e, 0x67, 0x08, 0x90, 0x17, 0x52, 0xe7, 0x20, 0x23, 0x01, 0xb2, 0x1f, 0xca, 0x48, 0x1d, 0xfa,\n\t0x38, 0x1d, 0xb6, 0x66, 0xb5, 0x55, 0x95, 0x2b, 0x68, 0x61, 0x96, 0x47, 0xa2, 0xb1, 0xcb, 0x24, 0x1a, 0xea, 0xec, 0xac, 0x07, 0xbf, 0x76, 0xb4, 0xd8, 0x23, 0xb6, 0x89, 0xac, 0x3d, 0xcb, 0x47, 0x62, 0x7a, 0xb7, 0x00, 0xbf, 0x6b, 0x09, 0xf5, 0x14, 0xe8, 0x61, 0xae, 0xc0, 0xd9, 0x25, 0x09, 0x19, 0xfd, 0x51, 0x2a, 0xfe, 0xe1, 0x23, 0x2e, 0xfe, 0x01, 0xde, 0x87, 0xef, 0x22, 0x0f, 0xc1, 0x77, 0x79, 0x41, 0x19, 0x1e, 0x43, 0x19, 0x88, 0xa7, 0x9f, 0x23, 0x8f, 0x32, 0x57, 0xe0, 0xe8, 0xf0, 0x73, 0xe8, 0x79, 0x50, 0x0b, 0x9f, 0x57, 0x65, 0x9e, 0x47, 0xcb, 0x94, 0xee, 0x08, 0x10, 0x5d, 0x50, 0x12, 0x69, 0x02, 0x8a, 0x89, 0x31, 0x03, 0x1c, 0x31, 0xe7, 0xf3, 0xc6, 0x70, 0xe4, 0x04, 0xfc, 0x00, 0x44, 0xd8, 0x96, 0x35, 0xbb, 0xaa, 0x4c, 0x49, 0x0b, 0x0d, 0xa9, 0x41, 0x03, 0xc5,\n\t0xac, 0x07, 0xef, 0xbb, 0xbd, 0xd8, 0x2b, 0xb6, 0x09, 0xad, 0x3d, 0x2b, 0xb8, 0x41, 0xc3, 0x77, 0xc3, 0xbe, 0xc8, 0x5d, 0xb0, 0x2f, 0x2f, 0x48, 0xe2, 0x31, 0x25, 0xd1, 0x98, 0xe0, 0x3b, 0x96, 0x10, 0x3b, 0xc0, 0xb7, 0xa8, 0xd3, 0xf8, 0x1d, 0x7c, 0x1a, 0xbe, 0xc3, 0xa3, 0xe3, 0xc9, 0x01, 0x15, 0x55, 0xeb, 0xad, 0x40, 0x0e, 0x78, 0x58, 0x91, 0x7d, 0x56, 0x26, 0x30, 0x26, 0x2e, 0x5f, 0x4e, 0x18, 0x05, 0xb2, 0x13, 0x0a, 0x29, 0x5f, 0x26, 0xf8, 0xd8, 0x18, 0x92, 0xd8, 0xc0, 0x7e, 0x23, 0xd8, 0x67, 0x95, 0x06, 0x8d, 0xe3, 0x06, 0x09, 0x5f, 0x85, 0x6a, 0xb9, 0x6e, 0x86, 0x7d, 0xbd, 0x97, 0xea, 0x4b, 0x49, 0xa2, 0xf1, 0x6a, 0x29, 0x5f, 0x0e, 0xaa, 0x13, 0x10, 0xcf, 0x01, 0xb9, 0xc0, 0x1b, 0x4b, 0x00, 0xf0, 0x1e, 0xd7, 0x8d, 0x5c, 0x26, 0x90, 0x0a, 0x4e, 0xa0, 0x7e, 0x49,\n\t0x87, 0x91, 0xdd, 0x64, 0x93, 0x84, 0x8c, 0xac, 0x41, 0xca, 0x53, 0x4b, 0xc6, 0x8d, 0x41, 0xa9, 0x15, 0xad, 0x15, 0xb1, 0x83, 0xfc, 0x1b, 0xec, 0xcb, 0x0b, 0xaa, 0xf0, 0x78, 0xab, 0x00, 0xb7, 0xcf, 0xf0, 0x1d, 0x14, 0x0f, 0xff, 0x5e, 0x8d, 0x7f, 0xaf, 0x46, 0xbf, 0xa3, 0xbc, 0x7b, 0xe3, 0x8f, 0x52, 0xad, 0x90, 0xdf, 0x10, 0x72, 0x30, 0xc5, 0x05, 0xa8, 0x0e, 0x82, 0x66, 0x97, 0x13, 0xc1, 0x94, 0x3e, 0x65, 0x14, 0x2a, 0x05, 0x63, 0xb2, 0x32, 0x7b, 0x07, 0xd9, 0x25, 0x8b, 0xba, 0x3a, 0x15, 0x5e, 0x0f, 0xf3, 0x73, 0xa7, 0x27, 0xe5, 0xa7, 0xc6, 0x3e, 0x02, 0x66, 0xa1, 0x7c, 0xdc, 0xe9, 0xe7, 0x47, 0xb9, 0xbc, 0x99, 0xa9, 0x54, 0xcc, 0x11, 0xa5, 0xeb, 0xd9, 0xe3, 0xc7, 0x79, 0xe0, 0xf3, 0x87, 0x21, 0xfe, 0x79, 0x81, 0x7d, 0x0a, 0x34, 0xe3, 0xb6, 0x7c, 0x94, 0x83, 0x3a,\n\t0xc5, 0x9d, 0xf4, 0xa7, 0xf3, 0xf1, 0x2f, 0xa7, 0x38, 0x5d, 0x18, 0x4a, 0x0b, 0x1c, 0xc1, 0xac, 0xa0, 0xeb, 0x85, 0xe3, 0xc7, 0xd1, 0xd3, 0x57, 0x7e, 0xcb, 0xfe, 0xf1, 0xca, 0x6f, 0x66, 0x18, 0x2f, 0xca, 0xb7, 0x8f, 0x12, 0xf8, 0x12, 0xcd, 0x2e, 0x3b, 0xf7, 0x3e, 0xa4, 0x0f, 0x46, 0x68, 0xa6, 0xb2, 0x13, 0x4a, 0x22, 0xe4, 0x9c, 0x0e, 0x7b, 0x99, 0x8c, 0xb9, 0xe8, 0x71, 0x7e, 0xe1, 0xf7, 0xe0, 0xec, 0x90, 0xc4, 0x66, 0x92, 0x47, 0xae, 0x21, 0xcf, 0x7c, 0x55, 0xfe, 0xe8, 0xcd, 0xe0, 0x9f, 0xac, 0x84, 0x3c, 0xc3, 0xe5, 0x15, 0x7d, 0x9e, 0x14, 0x51, 0x97, 0xc8, 0xe3, 0x5f, 0xf5, 0xcc, 0xf3, 0x94, 0xf3, 0xca, 0xaf, 0xc8, 0xe3, 0x87, 0xb9, 0xb8, 0x54, 0x52, 0xc4, 0x9c, 0xff, 0xea, 0x67, 0xb6, 0x31, 0xc5, 0x5f, 0xbc, 0x95, 0x7e, 0xa6, 0x9a, 0xfd, 0x0d, 0xd5, 0x3d, 0x3e,\n\t0x00, 0x9f, 0xb1, 0x25, 0xcd, 0x24, 0xce, 0xd0, 0x3d, 0x87, 0x4c, 0x95, 0x94, 0x02, 0x44, 0x4b, 0xba, 0xd2, 0x10, 0xa4, 0x7e, 0x8c, 0xd6, 0x11, 0xa5, 0xba, 0xaf, 0x7c, 0x74, 0xdf, 0xae, 0x5d, 0xf0, 0xce, 0xeb, 0xc4, 0x0f, 0xa9, 0xb7, 0xa8, 0x9f, 0x43, 0xbc, 0x90, 0xcd, 0x09, 0x00, 0xe2, 0xb4, 0xee, 0x6f, 0x08, 0x89, 0x81, 0x8a, 0x89, 0x70, 0xad, 0x54, 0x22, 0xd1, 0x17, 0x38, 0x8c, 0x31, 0x9d, 0x1a, 0xbd, 0x5e, 0xbe, 0xe2, 0xd6, 0xd9, 0xb3, 0x0f, 0xaf, 0x28, 0x2f, 0x5f, 0x71, 0x78, 0xf6, 0xec, 0x5b, 0x57, 0x94, 0x93, 0x1d, 0xed, 0x87, 0x57, 0x96, 0x97, 0xaf, 0x3c, 0xdc, 0x3e, 0xfb, 0x56, 0xf4, 0x79, 0x2b, 0xb7, 0xe7, 0x2b, 0xc0, 0xf3, 0xe0, 0x34, 0xf9, 0x69, 0x2a, 0x1f, 0xed, 0xb4, 0xce, 0x67, 0xee, 0x7a, 0x85, 0x21, 0x54, 0x6c, 0x77, 0x94, 0xa2, 0x04, 0xc1, 0xa5,\n\t0x0e, 0x7b, 0x71, 0xc8, 0x40, 0x76, 0xa4, 0xaf, 0x1c, 0xc5, 0xe8, 0xb3, 0x18, 0x3e, 0x3c, 0x97, 0xbd, 0x04, 0x7e, 0xc3, 0xd3, 0x10, 0x7a, 0x74, 0x0e, 0xf8, 0xe8, 0x1c, 0x68, 0x54, 0x7a, 0x74, 0xac, 0x26, 0x02, 0x5f, 0x51, 0x96, 0x3a, 0x62, 0xe5, 0x90, 0x52, 0xa1, 0xec, 0x6e, 0x5a, 0x51, 0x69, 0xb5, 0x56, 0xae, 0x68, 0xea, 0x86, 0x17, 0x43, 0x2b, 0xc9, 0xf5, 0x3f, 0x63, 0xd7, 0xbc, 0xe0, 0x70, 0x8b, 0xa3, 0xeb, 0x7e, 0xf7, 0x3f, 0x7f, 0xde, 0xbc, 0xe5, 0xcf, 0xff, 0xf3, 0xbb, 0x75, 0x51, 0xb1, 0xdb, 0xf1, 0x02, 0xbb, 0x9a, 0xab, 0x1d, 0x0a, 0xfb, 0xbe, 0x38, 0xa5, 0xef, 0x42, 0xd2, 0x87, 0x4e, 0x56, 0x4a, 0x09, 0x87, 0xc2, 0xaa, 0x62, 0x2a, 0x60, 0x5c, 0x35, 0x04, 0x61, 0xb0, 0xbb, 0x69, 0x79, 0x95, 0xd5, 0x5a, 0xb5, 0x1c, 0xf6, 0xad, 0x54, 0x0e, 0xad, 0x82, 0x7d,\n\t0x83, 0x3b, 0x33, 0x7d, 0x6f, 0xd9, 0x9c, 0xe9, 0x1b, 0xdc, 0x81, 0xfb, 0x7e, 0x8e, 0xfd, 0x05, 0x19, 0x86, 0x70, 0x2d, 0x25, 0x56, 0xa4, 0x13, 0xf3, 0x91, 0x34, 0x0a, 0xa0, 0x47, 0x82, 0x46, 0x26, 0x52, 0x8e, 0x98, 0x14, 0xcd, 0xa6, 0x99, 0xd4, 0x80, 0xcb, 0xaf, 0x84, 0xd3, 0xcf, 0x5e, 0xfb, 0xb9, 0x1e, 0xce, 0x8a, 0x2d, 0x25, 0x24, 0x4a, 0xb5, 0x83, 0x41, 0x35, 0x0d, 0x94, 0xd8, 0xc5, 0x18, 0x05, 0x60, 0xa1, 0x3a, 0x7c, 0x73, 0x1f, 0xd4, 0x5b, 0xd9, 0x7d, 0x60, 0xb3, 0x55, 0xcf, 0xec, 0xf8, 0xf7, 0x7f, 0x59, 0x75, 0x2d, 0x7c, 0x5f, 0x8b, 0xce, 0x0a, 0x1f, 0x2d, 0x65, 0x7f, 0x01, 0xce, 0xe1, 0xb1, 0xa5, 0xe2, 0xba, 0xb3, 0xd2, 0xb9, 0xf2, 0x27, 0x12, 0x09, 0x73, 0xe0, 0x95, 0x1a, 0x9a, 0x7a, 0xe2, 0x3e, 0x57, 0xcb, 0x6c, 0x39, 0x97, 0x4c, 0xf1, 0x1a, 0x4f, 0xf5,\n\t0xf4, 0x9c, 0x53, 0x3b, 0x5c, 0xf8, 0xd0, 0xe2, 0x14, 0xae, 0xa5, 0x80, 0x2b, 0x23, 0xe3, 0x00, 0xe7, 0xd8, 0xbd, 0xd6, 0xac, 0x07, 0x1f, 0xcc, 0xb2, 0x82, 0x2d, 0xec, 0x2f, 0xe0, 0x60, 0x78, 0x1e, 0x38, 0x2c, 0xee, 0x0c, 0xc3, 0xf5, 0x82, 0x52, 0x0a, 0x51, 0x46, 0x1c, 0x79, 0x51, 0x8c, 0xc3, 0x2a, 0xb9, 0xa1, 0x39, 0x08, 0x06, 0x55, 0x16, 0x40, 0x05, 0x38, 0x69, 0x82, 0x02, 0x34, 0x5c, 0x06, 0x54, 0x6f, 0xaa, 0x3b, 0x25, 0x6f, 0x02, 0xb2, 0x2d, 0x35, 0x46, 0xf3, 0x0c, 0x0d, 0xc1, 0x44, 0xc1, 0xf2, 0xaf, 0xee, 0x07, 0x79, 0x84, 0x40, 0x98, 0x88, 0x21, 0xdf, 0x36, 0x8b, 0x29, 0x4b, 0x4b, 0x94, 0x81, 0x52, 0x5c, 0xaf, 0x80, 0x4b, 0xbd, 0x85, 0x03, 0x7b, 0xb0, 0x6d, 0x17, 0x67, 0xd1, 0xe0, 0x7c, 0xb9, 0x39, 0xb6, 0x00, 0x09, 0xaf, 0x51, 0x4e, 0x00, 0xc9, 0xe4, 0xdb,\n\t0x70, 0x81, 0x5f, 0x37, 0xcd, 0x91, 0x29, 0x64, 0x73, 0x6a, 0x6a, 0xf0, 0x47, 0x93, 0x4a, 0x62, 0x8b, 0xcd, 0xd9, 0xde, 0x15, 0x94, 0xab, 0xe5, 0xd5, 0x55, 0x55, 0xd5, 0xf0, 0x23, 0xd8, 0xb5, 0x7d, 0x4e, 0xcc, 0x26, 0x61, 0x76, 0xf4, 0x77, 0x15, 0x0d, 0x0d, 0x2c, 0xce, 0x6f, 0x5a, 0xad, 0x56, 0xaf, 0x6e, 0xca, 0xef, 0x1f, 0x58, 0x16, 0xef, 0xea, 0x57, 0xeb, 0xe6, 0xe5, 0xce, 0xb9, 0xa9, 0x3e, 0xb2, 0x64, 0xc9, 0xe2, 0x82, 0x44, 0xdb, 0x8d, 0x6d, 0x89, 0xfc, 0xfe, 0x25, 0x4b, 0x22, 0xf5, 0x37, 0xcd, 0xc9, 0x9d, 0xa7, 0x53, 0xc3, 0xf5, 0x4a, 0xc2, 0xf5, 0x32, 0xe1, 0xf5, 0xda, 0xfb, 0xa2, 0x15, 0xe5, 0x9b, 0x48, 0xad, 0x97, 0x1d, 0x4d, 0x8f, 0x41, 0xd3, 0x63, 0x20, 0x7b, 0x87, 0xa6, 0x3b, 0x2d, 0xf1, 0x77, 0x6a, 0xb9, 0x4c, 0x57, 0xb7, 0x23, 0x27, 0x72, 0x1e, 0x7f,\n\t0x65, 0x2f, 0x08, 0xf6, 0xca, 0x4a, 0xf3, 0x72, 0x42, 0xfe, 0x48, 0x48, 0xc1, 0x43, 0xb0, 0x97, 0x5e, 0x25, 0xec, 0x85, 0x86, 0xf6, 0x3c, 0xbd, 0x20, 0xe9, 0xe2, 0x82, 0xd8, 0x06, 0x8e, 0xc0, 0x20, 0x8d, 0x03, 0x90, 0x04, 0x4d, 0x9a, 0xaa, 0xaa, 0xd0, 0x52, 0xcc, 0xd9, 0x3e, 0x27, 0x6a, 0x93, 0xa8, 0xf0, 0x92, 0x75, 0xd5, 0xd4, 0x74, 0xa5, 0x97, 0x2c, 0x0a, 0x6f, 0xa0, 0x25, 0xab, 0xaa, 0x22, 0x23, 0x6d, 0x89, 0x82, 0xc5, 0x13, 0x6b, 0xd0, 0xdf, 0x15, 0x5f, 0x36, 0xd0, 0x9f, 0x5e, 0xb4, 0xc5, 0x03, 0x43, 0x45, 0x93, 0x17, 0xad, 0x3f, 0x3f, 0xd1, 0x86, 0xe1, 0x6a, 0x03, 0x35, 0x8f, 0xfc, 0x80, 0xf9, 0x1f, 0xa2, 0x80, 0xa8, 0x4a, 0xaa, 0xf2, 0xc2, 0x21, 0x9f, 0xd5, 0x68, 0xd0, 0xa9, 0x94, 0x52, 0x06, 0x48, 0x39, 0xef, 0x23, 0x9c, 0x17, 0x28, 0x7d, 0xe2, 0x06, 0x09,\n\t0x8c, 0x1b, 0x31, 0x96, 0x9d, 0x04, 0xcf, 0x2f, 0xba, 0x9c, 0x59, 0x24, 0xce, 0x01, 0x8e, 0x6a, 0xce, 0xa2, 0x9d, 0x8f, 0x62, 0x03, 0xb9, 0x1c, 0xa0, 0x08, 0x2f, 0x54, 0x31, 0x1b, 0xe1, 0x21, 0x3d, 0x2e, 0x2f, 0xa9, 0xc5, 0x41, 0x52, 0x09, 0x80, 0x1c, 0x4c, 0x51, 0x61, 0xb9, 0x0f, 0x72, 0x9f, 0x50, 0x59, 0xc5, 0xf2, 0x45, 0x8c, 0x40, 0x6c, 0x56, 0x3e, 0x9e, 0xfb, 0xb8, 0xca, 0xa9, 0xf6, 0x3a, 0x9e, 0x80, 0x3f, 0x5a, 0xc4, 0x02, 0xfe, 0x22, 0x86, 0xcf, 0xfd, 0xaa, 0x74, 0xa8, 0x9c, 0x4e, 0xda, 0xd9, 0x31, 0x20, 0xd6, 0x2b, 0x5c, 0xfe, 0x37, 0x5e, 0xd7, 0xb8, 0x94, 0x32, 0x9d, 0x68, 0x49, 0xc7, 0x12, 0x91, 0x94, 0x64, 0xb4, 0x03, 0xf0, 0xf7, 0x2c, 0x85, 0xd2, 0xab, 0xb9, 0xf0, 0xba, 0xc6, 0xa3, 0x94, 0xeb, 0xc4, 0xfd, 0x1d, 0xfd, 0x22, 0x19, 0x49, 0x6b, 0x39, 0xdc,\n\t0xbb, 0x9a, 0x3d, 0x49, 0x9b, 0x98, 0xb7, 0x09, 0x17, 0xd2, 0x6a, 0x18, 0xb4, 0x90, 0x74, 0x1a, 0x35, 0x10, 0xa2, 0x05, 0x50, 0x28, 0x01, 0x14, 0x0a, 0xaa, 0x1e, 0x44, 0x3a, 0xfe, 0xb4, 0x67, 0x0a, 0x2e, 0x8b, 0x3c, 0x92, 0x4a, 0x4f, 0xe8, 0xf2, 0x7a, 0x5d, 0x1a, 0x9c, 0x01, 0x1e, 0x4a, 0xce, 0x9c, 0x03, 0xb0, 0x9a, 0x4b, 0xbc, 0x80, 0xf2, 0x33, 0x51, 0xa8, 0x52, 0x26, 0x85, 0x84, 0x17, 0x38, 0x67, 0xf2, 0xa8, 0x51, 0x5b, 0x68, 0xb1, 0x14, 0x6a, 0x8d, 0xec, 0x8d, 0xd9, 0xb9, 0x8e, 0xc6, 0xd6, 0x36, 0x9f, 0x31, 0x5c, 0x52, 0x12, 0x36, 0xfa, 0xda, 0x5a, 0x1b, 0x1d, 0xb9, 0xd9, 0x54, 0x27, 0x3b, 0x72, 0xe5, 0x1f, 0x12, 0x99, 0x4c, 0x42, 0xc9, 0xc1, 0xd1, 0x2a, 0x47, 0x54, 0x28, 0x91, 0xd0, 0xe0, 0x43, 0x83, 0x81, 0xd5, 0xd3, 0x12, 0x89, 0x30, 0xea, 0xa8, 0x9a, 0x3c,\n\t0xd6, 0x38, 0xaa, 0x4a, 0x1a, 0xf6, 0x93, 0x3c, 0x7e, 0xb6, 0x8f, 0x64, 0x78, 0x2a, 0x11, 0xc4, 0xe1, 0x4a, 0x31, 0x84, 0x2f, 0x1a, 0xe5, 0xf6, 0xa5, 0x00, 0xa7, 0xa3, 0xe0, 0xf3, 0x07, 0x9b, 0x84, 0xc8, 0x17, 0xb2, 0x17, 0x99, 0x36, 0x87, 0x90, 0xec, 0x37, 0x42, 0x36, 0xc7, 0x63, 0x70, 0xd4, 0x4a, 0xb5, 0xcf, 0xe7, 0xc2, 0x59, 0x01, 0x80, 0x23, 0x1d, 0xe7, 0x9e, 0x9e, 0x01, 0x2e, 0xb9, 0x5b, 0x8e, 0x10, 0xe1, 0x8c, 0x33, 0x71, 0x90, 0x47, 0xc1, 0x2d, 0xe9, 0x29, 0xa4, 0xe6, 0x94, 0x9a, 0x04, 0xb8, 0x65, 0xe6, 0xc9, 0xb1, 0x37, 0x02, 0x45, 0x95, 0xb3, 0x50, 0x20, 0x91, 0xd2, 0xac, 0x1e, 0xcd, 0x11, 0x7c, 0x48, 0x4b, 0x25, 0x82, 0x42, 0x67, 0x15, 0x59, 0x3d, 0xf3, 0x54, 0x21, 0x6f, 0xb3, 0x64, 0x7c, 0x0f, 0xb5, 0x8b, 0x79, 0x8a, 0x90, 0x43, 0xac, 0x0d, 0x65, 0xab,\n\t0x6e, 0x00, 0x98, 0xe6, 0x80, 0x14, 0x1e, 0x2b, 0xa2, 0x10, 0x90, 0x34, 0x75, 0x55, 0x41, 0x31, 0x64, 0xc3, 0x25, 0x17, 0xa5, 0xeb, 0x8a, 0xad, 0x02, 0xcd, 0x73, 0x3a, 0x2b, 0xca, 0x8a, 0xe3, 0x05, 0x79, 0x06, 0xbd, 0x46, 0x85, 0x4b, 0x1e, 0xa3, 0x50, 0x8d, 0x54, 0x0a, 0x10, 0x19, 0x98, 0x9a, 0x22, 0x84, 0x37, 0x81, 0xa0, 0xae, 0x8a, 0x3c, 0xe4, 0x4d, 0x2e, 0xf1, 0x09, 0x99, 0x21, 0x79, 0xf5, 0x8a, 0x1d, 0xe5, 0x91, 0x70, 0x62, 0xe9, 0xe6, 0xb2, 0xb2, 0x08, 0x69, 0x14, 0xa8, 0x64, 0x0a, 0x5f, 0xbc, 0x31, 0x92, 0x3b, 0xab, 0xc0, 0x94, 0xd7, 0x36, 0xb8, 0x62, 0xb0, 0x2d, 0xaf, 0xa5, 0x33, 0xaf, 0x2c, 0x32, 0x70, 0x7b, 0xdf, 0x8a, 0xe7, 0xca, 0x72, 0x04, 0x59, 0x6a, 0x75, 0xa0, 0xb8, 0xb3, 0xa2, 0x7f, 0x45, 0x41, 0xfb, 0xb2, 0xd5, 0xcb, 0xda, 0x0b, 0xe6, 0xf4, 0xe6,\n\t0x57, 0xe4, 0x2f, 0x3c, 0x38, 0x6f, 0xf0, 0xe1, 0x12, 0xf2, 0xbd, 0xbc, 0xda, 0x78, 0xc4, 0x6a, 0xa8, 0x0f, 0x47, 0x1a, 0xe2, 0xf9, 0x16, 0x4b, 0x2d, 0xf8, 0x50, 0x26, 0xd2, 0x19, 0x74, 0x7a, 0x5f, 0xa1, 0xd5, 0x1d, 0xcf, 0x0d, 0xe4, 0xc4, 0xea, 0x17, 0x94, 0xb7, 0xef, 0xf4, 0x7a, 0x96, 0xd4, 0xd6, 0x6f, 0x9a, 0x57, 0x50, 0x17, 0x6b, 0x92, 0xc9, 0xcd, 0x0e, 0x53, 0x77, 0x7d, 0x38, 0x51, 0x10, 0x08, 0x45, 0xea, 0xfa, 0x92, 0x6d, 0x5b, 0xdd, 0xde, 0x15, 0x4d, 0x65, 0xc3, 0x1d, 0xf9, 0xc9, 0x22, 0x08, 0x1f, 0xb5, 0xe3, 0x51, 0xa6, 0x06, 0xfb, 0x08, 0x7a, 0x92, 0xce, 0x94, 0x7d, 0x7d, 0x04, 0xe9, 0x5a, 0x6e, 0x20, 0xd3, 0xee, 0x6c, 0x03, 0x44, 0xb3, 0x1f, 0xa9, 0xab, 0x14, 0x38, 0x53, 0xa8, 0x2b, 0x65, 0x5e, 0x4f, 0x8b, 0x68, 0x0e, 0xa6, 0xe6, 0x17, 0x67, 0xd8, 0x7f,\n\t0x9d, 0x59, 0xfe, 0xd8, 0x86, 0x44, 0x62, 0xc3, 0x63, 0xcb, 0xa9, 0x32, 0xfa, 0xb3, 0x2f, 0x92, 0xcc, 0x6b, 0x5f, 0x24, 0xa9, 0xee, 0x8a, 0x55, 0x47, 0x3a, 0xba, 0x8f, 0x0e, 0x21, 0xbe, 0xe2, 0x66, 0xf2, 0x05, 0x5a, 0x32, 0x35, 0xdf, 0xf6, 0x94, 0xfa, 0x43, 0x61, 0x7b, 0xba, 0x4a, 0xd0, 0xd4, 0x04, 0x66, 0x11, 0x5a, 0x72, 0x58, 0x6d, 0x14, 0x7c, 0x20, 0xd3, 0x08, 0x04, 0x6a, 0xc9, 0xcf, 0x78, 0x26, 0xed, 0x3d, 0x60, 0xdf, 0x36, 0xf2, 0x05, 0x8d, 0x02, 0x9c, 0x31, 0x17, 0x18, 0x0c, 0x05, 0x66, 0xb6, 0x4b, 0xae, 0x25, 0xff, 0x84, 0xd9, 0x66, 0x00, 0x61, 0x9d, 0x62, 0x08, 0x13, 0x3a, 0x97, 0x04, 0x60, 0xc0, 0x28, 0x72, 0xdc, 0x5c, 0x87, 0xb8, 0x5d, 0x12, 0x82, 0x04, 0x03, 0x3f, 0x18, 0x6a, 0x80, 0x37, 0x59, 0x9f, 0x72, 0xfd, 0xe5, 0x72, 0xc8, 0xff, 0x9d, 0xa8, 0x03,\n\t0x5f, 0xf3, 0x36, 0x2c, 0xaf, 0x2a, 0x5c, 0xba, 0xb0, 0xcb, 0x35, 0xf9, 0x82, 0x5c, 0xd3, 0x51, 0x5b, 0xb7, 0xae, 0x33, 0xdb, 0xe6, 0xb5, 0xb5, 0xc3, 0x2f, 0x1d, 0x39, 0x76, 0x8f, 0x1d, 0xe7, 0x5d, 0xa0, 0xee, 0x01, 0x2e, 0x9c, 0xaf, 0xc3, 0x9e, 0xb4, 0x60, 0xc7, 0x11, 0xe4, 0xcb, 0xcb, 0x05, 0xec, 0xa3, 0xdc, 0xef, 0xf0, 0x3b, 0x0a, 0x25, 0xc3, 0xe5, 0xa0, 0x94, 0xd8, 0x3f, 0x1e, 0x62, 0x36, 0x25, 0x70, 0xa9, 0x18, 0x8b, 0xd3, 0x62, 0xe3, 0xa9, 0x98, 0x53, 0xec, 0x7f, 0x9f, 0x42, 0x18, 0xe3, 0x14, 0x70, 0x60, 0xf9, 0x94, 0xba, 0x87, 0xdc, 0x84, 0x63, 0x25, 0x16, 0x62, 0xf9, 0x61, 0x21, 0x98, 0x8b, 0xe1, 0x7e, 0xce, 0xf8, 0xc7, 0xcc, 0x7e, 0xe6, 0x0c, 0x21, 0x26, 0x1a, 0x88, 0x95, 0x49, 0x59, 0xc8, 0x4a, 0x32, 0x74, 0x43, 0x85, 0x52, 0x4c, 0x13, 0x58, 0x63, 0x8f,\n\t0xd5, 0xd1, 0xe9, 0x74, 0xec, 0xab, 0x90, 0xbe, 0x18, 0xf4, 0xa2, 0x11, 0x2c, 0xc5, 0xe9, 0xe0, 0xb9, 0xaf, 0x00, 0x17, 0x6c, 0x9c, 0xda, 0x86, 0x48, 0x35, 0xc1, 0x44, 0x7d, 0x18, 0xa9, 0x2d, 0x25, 0xb5, 0xd5, 0x85, 0x05, 0x3e, 0x8f, 0xc7, 0xe5, 0xc3, 0x24, 0x28, 0x95, 0x60, 0x18, 0x05, 0x87, 0xa6, 0x4a, 0x96, 0x65, 0xea, 0xaa, 0xe7, 0x4c, 0x24, 0x9d, 0xe3, 0xf3, 0x7c, 0x13, 0x49, 0x8b, 0xf5, 0x48, 0x70, 0x45, 0xb2, 0x0c, 0xf2, 0x76, 0xfa, 0xf5, 0x40, 0x7f, 0x76, 0x53, 0x7f, 0x64, 0xe5, 0x93, 0x55, 0xa4, 0xf0, 0x5b, 0x76, 0x8f, 0x7e, 0x6f, 0xdf, 0xa7, 0xb7, 0xb7, 0xdf, 0xbb, 0xb9, 0x29, 0xa7, 0xe3, 0x86, 0xaa, 0xd2, 0x78, 0x6c, 0xe9, 0xed, 0xbd, 0xed, 0x7b, 0x17, 0xc7, 0xe9, 0xcd, 0x1e, 0xa5, 0xc0, 0x92, 0x5b, 0x15, 0xca, 0x6b, 0x89, 0x59, 0x14, 0x8e, 0x42, 0x37,\n\t0xb8, 0xdb, 0x13, 0xe6, 0xc3, 0xde, 0x36, 0x81, 0x86, 0x2a, 0xf2, 0xe5, 0xf8, 0x89, 0x79, 0x15, 0xfd, 0x55, 0xce, 0xa6, 0x04, 0xfb, 0x47, 0x79, 0xd6, 0xbe, 0x79, 0x83, 0xf1, 0xe5, 0x77, 0xf7, 0xd5, 0x6e, 0x5d, 0xd1, 0x65, 0x6d, 0xb9, 0xbd, 0x79, 0xd6, 0xae, 0xc5, 0x45, 0x91, 0xb9, 0x23, 0xe5, 0x06, 0x41, 0xc0, 0x18, 0x0b, 0x99, 0xed, 0xf1, 0xc6, 0xa0, 0x23, 0x91, 0xa8, 0xf4, 0xb0, 0xfd, 0x55, 0x77, 0xcc, 0xd2, 0x64, 0x6d, 0xfc, 0x5d, 0x3f, 0x5e, 0xbf, 0xc1, 0x71, 0x05, 0x2f, 0xca, 0xcc, 0x81, 0x78, 0xa3, 0x8f, 0x98, 0x95, 0xac, 0xeb, 0x03, 0x84, 0xb0, 0x15, 0x02, 0x67, 0x1e, 0xa0, 0xf9, 0x10, 0x69, 0xf0, 0x08, 0x4a, 0xc8, 0x83, 0x94, 0x19, 0xa5, 0x65, 0x10, 0x12, 0x03, 0x24, 0xaa, 0xe5, 0x0c, 0xa5, 0x4d, 0x3e, 0x64, 0x6c, 0x18, 0x86, 0xee, 0x4e, 0x29, 0xa0, 0x68,\n\t0xa6, 0x6d, 0xc1, 0x7c, 0x77, 0x30, 0xe8, 0xf7, 0xfb, 0x03, 0x5e, 0x07, 0x46, 0x93, 0x69, 0x0f, 0x60, 0x2e, 0x22, 0x8e, 0x37, 0x91, 0x60, 0x82, 0xfb, 0x5d, 0xc5, 0xb9, 0x4c, 0xc4, 0x74, 0x36, 0x90, 0x09, 0x18, 0xac, 0xa0, 0xe1, 0x92, 0x65, 0xaa, 0x17, 0x4e, 0xad, 0x07, 0x49, 0x67, 0x79, 0x83, 0x0d, 0x9b, 0xe6, 0xe5, 0x27, 0x2a, 0xac, 0xe5, 0xf1, 0x3c, 0xc5, 0x71, 0x35, 0x30, 0x17, 0x58, 0x73, 0xe7, 0x24, 0xbd, 0xdd, 0x27, 0x7e, 0xb4, 0x79, 0xef, 0x9f, 0x9e, 0x1a, 0x58, 0x79, 0xfe, 0xf3, 0xc3, 0xc7, 0xff, 0xd4, 0xae, 0xb3, 0x0b, 0x4c, 0x2b, 0xd9, 0x8f, 0xce, 0x9c, 0x65, 0x7f, 0xf6, 0xcb, 0xad, 0xf1, 0xa5, 0x87, 0xcf, 0xbc, 0xbd, 0x7a, 0xe1, 0x73, 0xf7, 0xed, 0x5d, 0x14, 0xab, 0x18, 0xbe, 0x73, 0x4e, 0xd3, 0xa0, 0xbc, 0x64, 0x7f, 0x6b, 0xd9, 0xfc, 0x32, 0x4b, 0xe5,\n\t0xce, 0xd7, 0xb6, 0xd7, 0x2e, 0xcf, 0xa5, 0xf2, 0x05, 0xe5, 0x03, 0x3b, 0xab, 0xeb, 0x3a, 0xd5, 0x79, 0xb3, 0x2b, 0xd4, 0xb3, 0x7a, 0x0b, 0xd5, 0xf1, 0xc1, 0x5b, 0xbb, 0x0e, 0xfc, 0xe0, 0x40, 0xed, 0xe0, 0x73, 0x9f, 0x1e, 0x7e, 0x7c, 0x9c, 0x78, 0xaa, 0x3b, 0x99, 0x2f, 0x15, 0x69, 0x1a, 0xea, 0xba, 0xd6, 0xfe, 0x18, 0x64, 0x7f, 0x7b, 0xf8, 0xbb, 0x67, 0xef, 0x58, 0x5e, 0x1c, 0x68, 0x5b, 0x77, 0xec, 0xfc, 0xaa, 0xe1, 0x6f, 0xec, 0x6f, 0x69, 0x68, 0x6e, 0xad, 0x0e, 0x36, 0x0e, 0x96, 0xce, 0x79, 0xfa, 0xd6, 0x79, 0x3a, 0x0d, 0xe7, 0x83, 0xd2, 0x3f, 0xfe, 0x09, 0xcf, 0x08, 0xf1, 0x70, 0x88, 0xa8, 0x26, 0x16, 0x11, 0x7b, 0x92, 0x32, 0x0d, 0xc2, 0xbb, 0x80, 0x46, 0x55, 0x7f, 0x68, 0xea, 0xaa, 0xdc, 0xaf, 0x69, 0x7b, 0x00, 0x0d, 0x61, 0x9a, 0x86, 0xac, 0x8f, 0x40, 0x90,\n\t0xce, 0x56, 0xcc, 0xe7, 0x63, 0x9b, 0xd0, 0x30, 0x6f, 0x4a, 0xee, 0xd7, 0xaf, 0x6c, 0xbf, 0x16, 0xd9, 0x90, 0x24, 0xe1, 0xb0, 0x3f, 0xe8, 0x77, 0x79, 0xfc, 0x5e, 0x21, 0xda, 0x0c, 0xb4, 0xcc, 0x53, 0xd7, 0x93, 0x3f, 0x35, 0xe3, 0x13, 0xda, 0x1c, 0x0f, 0xde, 0x80, 0x89, 0x20, 0xce, 0x1c, 0x3a, 0xae, 0xb1, 0xc2, 0x5f, 0xb0, 0xfe, 0x10, 0x5e, 0xcb, 0x68, 0x3a, 0x26, 0x90, 0x33, 0x55, 0xc5, 0x8f, 0xad, 0x1f, 0x78, 0x70, 0x34, 0x51, 0xbb, 0xf9, 0xf4, 0x92, 0xd5, 0x27, 0x8b, 0x22, 0x8c, 0x52, 0x2a, 0xb7, 0xe5, 0x35, 0x14, 0xd7, 0x0c, 0x37, 0xfb, 0x03, 0xb3, 0x96, 0x96, 0x46, 0x6a, 0x22, 0x81, 0x2b, 0xd5, 0x85, 0x8b, 0xf7, 0x3d, 0xf4, 0xca, 0xe0, 0x71, 0x20, 0x7e, 0x6b, 0xdd, 0xba, 0xb7, 0xd8, 0xcf, 0x8e, 0x0f, 0xbe, 0xf2, 0xd0, 0xbe, 0xc5, 0x85, 0xab, 0xc3, 0xb3, 0x47,\n\t0x0f, 0x3d, 0xd0, 0xdd, 0xfd, 0xe0, 0xad, 0xa3, 0xed, 0xe1, 0x70, 0xfb, 0xe8, 0xad, 0x0f, 0x76, 0x77, 0x3f, 0x70, 0x68, 0x74, 0x76, 0x18, 0xfc, 0x1e, 0x08, 0x98, 0xfa, 0xea, 0x59, 0xb5, 0x5b, 0x1e, 0x5f, 0x3a, 0xf8, 0xc4, 0xa6, 0x9a, 0xba, 0xa2, 0x06, 0x9e, 0x54, 0x67, 0xd4, 0x85, 0xdb, 0xd7, 0x35, 0x34, 0xad, 0x9f, 0x1d, 0x50, 0xe8, 0x8d, 0xff, 0x1c, 0x7c, 0x15, 0x75, 0x81, 0x7b, 0x3b, 0xce, 0xfe, 0xeb, 0xad, 0x75, 0x85, 0x8b, 0xf7, 0x3e, 0xfc, 0xca, 0xe0, 0xbc, 0x87, 0x6f, 0x5b, 0xd7, 0x91, 0x9d, 0xdd, 0xb1, 0xee, 0xb6, 0x87, 0x7a, 0x7a, 0x1e, 0x39, 0xbc, 0xbe, 0x33, 0x3b, 0xbb, 0x73, 0xfd, 0xe1, 0x47, 0xd0, 0x5e, 0xd0, 0x99, 0xbd, 0x40, 0x71, 0x54, 0x71, 0xa2, 0x8d, 0xb8, 0x9b, 0x5b, 0xfd, 0x7c, 0xb8, 0x11, 0xa8, 0x14, 0xc1, 0x48, 0xc6, 0x0e, 0x80, 0x75, 0xff,\n\t0x34, 0xaa, 0x5c, 0xc3, 0xe3, 0xf1, 0x7b, 0x25, 0x80, 0xcf, 0x5f, 0xd5, 0x24, 0x86, 0xac, 0x00, 0x4e, 0x39, 0x3a, 0x2c, 0x80, 0x3b, 0xf0, 0x1f, 0x3e, 0xb3, 0x56, 0x00, 0x77, 0xc1, 0x53, 0x5c, 0x64, 0x31, 0xa3, 0x00, 0x81, 0xea, 0xca, 0xa2, 0xb6, 0xe2, 0xb6, 0x50, 0xc0, 0x1c, 0xb7, 0xc4, 0xa7, 0x86, 0x6b, 0x49, 0xd3, 0x8a, 0xec, 0xa9, 0xf6, 0x04, 0xec, 0x3f, 0x00, 0x26, 0x2d, 0x3d, 0x4a, 0xd5, 0xa6, 0x9e, 0xb2, 0x39, 0xe8, 0xbc, 0x50, 0xc9, 0xb2, 0xd6, 0x6c, 0x95, 0x32, 0x58, 0x1f, 0xdb, 0xba, 0xb5, 0x77, 0x4f, 0x77, 0x30, 0x38, 0x6f, 0xdf, 0xc2, 0x8d, 0x4f, 0x01, 0xcd, 0xd5, 0x0b, 0xcc, 0x2d, 0xfc, 0xf4, 0xfd, 0xc0, 0xbb, 0x44, 0x7e, 0xc7, 0x90, 0x5d, 0xe1, 0x76, 0x97, 0x04, 0x74, 0xec, 0x2b, 0xe0, 0x9d, 0x70, 0xeb, 0xca, 0xf2, 0xd2, 0x15, 0xed, 0xb9, 0xec, 0x5b,\n\t0xd4, 0xb6, 0xcb, 0x6f, 0x5e, 0xb5, 0xae, 0x3d, 0xdc, 0x7a, 0x33, 0xdd, 0xd3, 0xf7, 0x81, 0xdb, 0x9d, 0x29, 0x6b, 0xee, 0x24, 0x2a, 0x88, 0xb9, 0xc4, 0x03, 0x2f, 0xaa, 0x01, 0x9d, 0xc9, 0x18, 0x5f, 0x80, 0xf2, 0xa4, 0xf0, 0x68, 0x8a, 0x37, 0x22, 0x4e, 0xaf, 0xa3, 0x08, 0xe5, 0xeb, 0xa2, 0x50, 0x61, 0x72, 0x3e, 0x5f, 0xd0, 0x2b, 0x05, 0x28, 0xc7, 0xab, 0x04, 0x32, 0x60, 0xc2, 0x5e, 0x42, 0x28, 0x1c, 0x16, 0xc2, 0xb5, 0xff, 0x4f, 0x1f, 0x5a, 0x2b, 0x84, 0x8b, 0xef, 0x4b, 0x26, 0xdc, 0x2e, 0xb4, 0xf8, 0x8d, 0x0d, 0x89, 0xb9, 0xc9, 0xb9, 0x05, 0x79, 0xae, 0x0a, 0x77, 0x85, 0xc3, 0x6e, 0xb3, 0x18, 0xf4, 0x52, 0xa7, 0xcc, 0xc9, 0x2d, 0xbf, 0x6c, 0xfa, 0xf2, 0xeb, 0x38, 0xc6, 0x06, 0x95, 0x39, 0xcc, 0xb8, 0x80, 0x5e, 0xc7, 0x3e, 0x38, 0x91, 0x05, 0x4e, 0x19, 0xa8, 0x8e,\n\t0x6c, 0xdd, 0xfa, 0xcc, 0x13, 0xcb, 0x96, 0xab, 0x4c, 0x92, 0x9f, 0x3f, 0xec, 0x56, 0xbc, 0x22, 0x34, 0x18, 0x67, 0x3d, 0x05, 0x0a, 0xfe, 0xb3, 0xed, 0xf8, 0x93, 0xc6, 0x5b, 0xec, 0x76, 0x17, 0xba, 0x94, 0xec, 0x2f, 0xc1, 0xe9, 0x1d, 0x5b, 0x7a, 0xf7, 0x19, 0xc5, 0x76, 0x1d, 0xfb, 0x92, 0x19, 0xb8, 0x64, 0x32, 0xf6, 0xd1, 0xff, 0xab, 0x5d, 0x41, 0x78, 0xbe, 0x9b, 0x6a, 0x4c, 0xd5, 0xc7, 0xf0, 0x22, 0xfe, 0xd0, 0xa6, 0xd5, 0x48, 0xc4, 0x90, 0xd0, 0x21, 0xcf, 0x58, 0x80, 0x3c, 0x63, 0x31, 0xdf, 0x43, 0xf4, 0x08, 0x05, 0x7c, 0x8a, 0x20, 0x06, 0xb8, 0xb2, 0xd0, 0x99, 0x4b, 0xe4, 0x5f, 0x2e, 0xf0, 0x0a, 0x3c, 0x4a, 0x4d, 0x14, 0xf9, 0x86, 0x40, 0x4e, 0xd8, 0x8c, 0xb4, 0x47, 0x88, 0x1d, 0x72, 0x79, 0x50, 0x51, 0x71, 0xcc, 0xaf, 0xc0, 0x25, 0xd3, 0xa7, 0x5c, 0x22, 0xd5,\n\t0x38, 0xfa, 0x19, 0x99, 0xf0, 0xbb, 0xc1, 0x87, 0x67, 0x0f, 0x9e, 0xa5, 0x3f, 0xd9, 0x28, 0x3a, 0xcb, 0x37, 0xc8, 0x35, 0x4e, 0xe9, 0x59, 0xe1, 0xc6, 0xf5, 0x2a, 0xa5, 0xf8, 0x7e, 0xa9, 0x90, 0x11, 0xf3, 0x1f, 0x10, 0x2b, 0x95, 0xcc, 0xa9, 0x51, 0xd6, 0x0e, 0x7e, 0x3d, 0x3a, 0xf6, 0x75, 0xd0, 0xdb, 0xc1, 0xbe, 0x24, 0x97, 0x5b, 0x41, 0x5d, 0x3b, 0xfb, 0x28, 0xd9, 0xc1, 0x97, 0xb1, 0xbf, 0x34, 0xda, 0xe5, 0x16, 0x88, 0xab, 0x64, 0x7c, 0x34, 0x87, 0x2d, 0x54, 0x0d, 0x93, 0x60, 0x9e, 0x24, 0xa2, 0xc4, 0x1c, 0xe2, 0x63, 0xce, 0x82, 0xac, 0x8a, 0x42, 0x0e, 0xb6, 0xb5, 0xba, 0xaa, 0xa4, 0x98, 0x41, 0x5c, 0x0c, 0x9f, 0x46, 0x65, 0x8c, 0xd1, 0x8f, 0xc2, 0xa9, 0x3f, 0xf6, 0x70, 0xcd, 0xc3, 0x19, 0x36, 0x98, 0x0f, 0x31, 0x32, 0x9f, 0x1c, 0x21, 0x68, 0x01, 0x8f, 0x84, 0x9c,\n\t0xf0, 0x42, 0xcc, 0x09, 0x8b, 0x45, 0x42, 0x0a, 0x23, 0x53, 0x8a, 0x1a, 0xc2, 0x46, 0xea, 0x1c, 0xf8, 0x4c, 0xe1, 0xd5, 0xcf, 0xf0, 0x49, 0xba, 0x1b, 0x3d, 0x47, 0x0a, 0xe1, 0x23, 0x24, 0xca, 0x2e, 0x96, 0x61, 0xa4, 0xd3, 0xcf, 0x26, 0x63, 0xd3, 0x39, 0xee, 0xeb, 0x79, 0x1a, 0xa0, 0xa8, 0x1a, 0x4d, 0x2c, 0x16, 0x9b, 0x13, 0xeb, 0xaa, 0xaf, 0xd3, 0xb9, 0x35, 0xd9, 0x2e, 0x6f, 0xb6, 0x5b, 0x29, 0x41, 0x58, 0xfc, 0xea, 0x1a, 0xbf, 0x93, 0xbd, 0x22, 0x26, 0xd7, 0xf8, 0xe5, 0xb6, 0x84, 0x87, 0xfd, 0x54, 0x27, 0xb6, 0x84, 0x73, 0xb0, 0x43, 0x7b, 0x02, 0xfe, 0x25, 0x52, 0x0b, 0xb5, 0x16, 0x9f, 0xc9, 0x93, 0xe3, 0x2f, 0xab, 0x2f, 0xf3, 0x9b, 0x63, 0x6d, 0x05, 0x96, 0xe2, 0xc2, 0x1c, 0x95, 0x5d, 0xa2, 0x94, 0x64, 0x39, 0xc2, 0x36, 0x28, 0x6a, 0xa3, 0xdf, 0x4d, 0x91, 0xe6,\n\t0xbc, 0xd8, 0x42, 0x3b, 0x95, 0x77, 0x93, 0xf0, 0xac, 0xcc, 0xa1, 0x91, 0x1b, 0xf8, 0xcf, 0x08, 0x37, 0xa1, 0xcd, 0x7b, 0x80, 0x27, 0x66, 0xe8, 0xd4, 0xee, 0x65, 0xab, 0x25, 0x72, 0xa9, 0xdb, 0x92, 0x65, 0xd4, 0xea, 0x7d, 0x89, 0x48, 0xb0, 0x21, 0x6a, 0x13, 0x6b, 0x2d, 0xaa, 0x0a, 0xa5, 0x42, 0xa3, 0x08, 0xdb, 0xcd, 0x16, 0x8d, 0xd6, 0x57, 0x19, 0x77, 0x26, 0xf2, 0x21, 0x57, 0x97, 0x8f, 0x76, 0xb8, 0x93, 0xfd, 0x86, 0x55, 0x2e, 0x07, 0xb5, 0xb3, 0xd3, 0x3b, 0x2c, 0xb3, 0x40, 0x2e, 0x3d, 0xb5, 0xc5, 0x70, 0x8f, 0xbb, 0x28, 0x3b, 0xf9, 0x67, 0xe6, 0x69, 0x5c, 0x27, 0xd0, 0x8c, 0x14, 0x52, 0x53, 0x2a, 0xa5, 0xad, 0xa2, 0x9a, 0xd3, 0x65, 0x02, 0xaf, 0xae, 0x22, 0x36, 0x95, 0xc9, 0xe8, 0x8a, 0xf4, 0x6c, 0xac, 0xab, 0xdb, 0x34, 0x3f, 0x12, 0x99, 0xbf, 0xa9, 0xae, 0x6e,\n\t0x63, 0x4f, 0xe4, 0x90, 0xa5, 0xb0, 0x2e, 0x10, 0xa8, 0x47, 0x22, 0x58, 0x7d, 0x20, 0x50, 0x57, 0x68, 0xa1, 0x97, 0xd5, 0xdc, 0x34, 0x2f, 0x12, 0x99, 0x77, 0x53, 0x4d, 0xf5, 0x4d, 0x3d, 0x85, 0x85, 0x3d, 0x37, 0x55, 0xc1, 0xbb, 0x56, 0x2b, 0xba, 0x5b, 0x1f, 0xb5, 0x5a, 0xa3, 0xf5, 0x68, 0x3c, 0xdb, 0x89, 0xff, 0xa2, 0x85, 0xf4, 0x10, 0x1c, 0x4f, 0x1c, 0x79, 0x0c, 0xe5, 0x66, 0xfb, 0x3c, 0x70, 0x3b, 0x63, 0x79, 0x6e, 0x2b, 0xc4, 0x6a, 0x71, 0x8b, 0x49, 0x4b, 0x93, 0x04, 0xd5, 0x98, 0xe3, 0x25, 0xa9, 0x06, 0x33, 0x20, 0xeb, 0x09, 0xce, 0x60, 0x9b, 0xce, 0x07, 0xb9, 0x06, 0x34, 0x87, 0x02, 0x3e, 0x34, 0x60, 0x7d, 0x08, 0x4c, 0x1b, 0x20, 0xf0, 0x71, 0x12, 0x24, 0xdf, 0x87, 0x39, 0xc6, 0x58, 0xdc, 0x17, 0xe7, 0x4a, 0xae, 0xeb, 0xe3, 0x7a, 0x2c, 0x5c, 0xf1, 0xf8, 0x7a,\n\t0xb0, 0xda, 0x59, 0xd2, 0x16, 0xce, 0x6e, 0x2b, 0x75, 0x3a, 0x4b, 0xdb, 0xb2, 0xc3, 0x6d, 0x25, 0x4e, 0xb2, 0xf8, 0x58, 0x78, 0xa8, 0xb8, 0x68, 0x69, 0xe8, 0xc4, 0x92, 0x63, 0x16, 0xbb, 0xcd, 0x7c, 0x7c, 0x60, 0xd2, 0xb5, 0xc3, 0x66, 0x3e, 0x46, 0x3e, 0x10, 0x6e, 0x41, 0xcd, 0x5b, 0xd2, 0x8f, 0xb1, 0xca, 0xe3, 0xe8, 0xc6, 0xf1, 0xa5, 0xc7, 0x42, 0x93, 0x1b, 0x1e, 0x5f, 0x7a, 0x4f, 0x78, 0x59, 0x71, 0x7c, 0x69, 0xe8, 0x78, 0x2a, 0xff, 0xe2, 0x3f, 0xe8, 0xe5, 0xf0, 0x6c, 0xd5, 0x13, 0x0b, 0x92, 0x3d, 0x90, 0x5f, 0xa7, 0xa2, 0x40, 0x20, 0x44, 0xb5, 0x6a, 0x29, 0x24, 0x40, 0x8c, 0x10, 0x42, 0xbe, 0x80, 0x2f, 0x14, 0x8c, 0x40, 0x2e, 0x46, 0xca, 0xc5, 0xfb, 0x43, 0x74, 0x2b, 0x06, 0x7c, 0x21, 0x8f, 0x9f, 0x49, 0x40, 0x0f, 0x61, 0x5f, 0x20, 0x10, 0xf5, 0x12, 0x22, 0xd1,\n\t0xb0, 0xa8, 0xb9, 0xbe, 0x2e, 0x99, 0xa8, 0x28, 0x47, 0x02, 0xa5, 0xd3, 0xe5, 0x71, 0xa9, 0x5c, 0x1e, 0xb7, 0x42, 0x06, 0xa1, 0x58, 0x1d, 0xc1, 0x72, 0xf1, 0x04, 0x03, 0xc2, 0xe3, 0x63, 0x89, 0xda, 0x01, 0xf9, 0x69, 0x33, 0xd0, 0x73, 0xdf, 0xb1, 0x9b, 0x0b, 0x8d, 0x2b, 0x8f, 0xa6, 0xe2, 0x39, 0x5d, 0xd1, 0x88, 0xb7, 0x10, 0xad, 0x91, 0x2b, 0xeb, 0x88, 0x76, 0xf1, 0xe1, 0xf3, 0xc3, 0xfb, 0x5f, 0xab, 0xad, 0x16, 0xa8, 0x14, 0x4a, 0x4f, 0xd9, 0x82, 0x59, 0xb7, 0xbc, 0x64, 0x27, 0xb3, 0xac, 0x46, 0x56, 0x0d, 0x31, 0x18, 0x78, 0x1b, 0x7e, 0xd9, 0x6c, 0xfe, 0xc6, 0xa1, 0x68, 0x6b, 0x49, 0xc0, 0x66, 0x90, 0x8a, 0xa4, 0x82, 0xce, 0xfa, 0x1f, 0x1f, 0x59, 0xff, 0xf2, 0xc1, 0x6e, 0xe5, 0xa1, 0x9d, 0xf0, 0xfe, 0x2e, 0xea, 0x96, 0xad, 0xef, 0xdc, 0xd6, 0x3c, 0x34, 0xaf, 0x49,\n\t0x24, 0xf3, 0x84, 0x3d, 0xdf, 0x3c, 0x5f, 0xae, 0xb6, 0xab, 0xbd, 0x1a, 0x08, 0x82, 0xf0, 0xcb, 0xc5, 0x37, 0x35, 0x36, 0xb7, 0x4d, 0xc3, 0x13, 0xb4, 0x2e, 0x1b, 0x6d, 0xbb, 0xf3, 0xc7, 0x3b, 0x47, 0x64, 0x66, 0xb9, 0xc6, 0xab, 0x46, 0xeb, 0x23, 0x87, 0xeb, 0x63, 0xa4, 0x87, 0x89, 0x5a, 0x6e, 0x7d, 0x28, 0x78, 0x8a, 0xd0, 0xfa, 0xd4, 0x42, 0x49, 0x6b, 0xd6, 0xf4, 0x45, 0x4a, 0x73, 0x69, 0xc8, 0x7a, 0x3d, 0x75, 0xad, 0x96, 0x4e, 0x5a, 0xa1, 0x8a, 0xf2, 0xb2, 0xd2, 0x78, 0x34, 0x2f, 0x27, 0xb3, 0x3e, 0xd2, 0x2f, 0x5b, 0x1f, 0x9e, 0x66, 0xda, 0xfa, 0x90, 0x33, 0xaf, 0x8f, 0xfc, 0x80, 0xba, 0x67, 0xef, 0xb3, 0xab, 0xb6, 0x7c, 0xbd, 0x26, 0x5f, 0x62, 0x53, 0x2a, 0x03, 0xa5, 0xed, 0x45, 0x7b, 0x4f, 0xdb, 0xc0, 0x6f, 0xed, 0x59, 0x6c, 0x3d, 0x64, 0xdf, 0x4f, 0xc2, 0xcf,\n\t0x27, 0x8d, 0x0f, 0xec, 0xac, 0xe9, 0xab, 0x0a, 0xa9, 0x14, 0x7a, 0x59, 0x41, 0xd5, 0x9b, 0xfb, 0x56, 0x3d, 0xbd, 0xbd, 0x43, 0xb9, 0x67, 0x33, 0x5c, 0x9c, 0x2d, 0xe4, 0x77, 0x17, 0xdf, 0xbb, 0xba, 0xa4, 0xa5, 0xa6, 0x44, 0xaa, 0xce, 0xb2, 0x64, 0xed, 0xdb, 0xe6, 0xd1, 0x38, 0x14, 0x76, 0xa5, 0xcc, 0x28, 0x85, 0x5f, 0xf6, 0x1f, 0xb4, 0xfb, 0xec, 0x0a, 0x79, 0x69, 0xc7, 0xfc, 0xf2, 0x91, 0xfb, 0x07, 0xe6, 0x4b, 0x8d, 0x32, 0xa5, 0x5d, 0x81, 0x79, 0xde, 0xf9, 0xe3, 0x3a, 0xda, 0xc5, 0x5b, 0x81, 0x6b, 0x6e, 0x35, 0x13, 0xcf, 0x24, 0x4d, 0x65, 0x10, 0xe1, 0x35, 0xd7, 0x54, 0x42, 0x8e, 0x29, 0x5f, 0x2d, 0x80, 0x82, 0x67, 0x9e, 0x0f, 0x1e, 0x0a, 0x1b, 0xa4, 0x2f, 0x4c, 0xa6, 0x98, 0x07, 0x4d, 0xd1, 0xa3, 0x04, 0x43, 0x91, 0x14, 0x24, 0x3d, 0xc8, 0x23, 0x8a, 0x24, 0xd6,\n\t0x70, 0xd6, 0x14, 0x2c, 0x82, 0x11, 0xc4, 0xda, 0x4c, 0x12, 0xf2, 0xaf, 0x6e, 0x3b, 0x4c, 0xe0, 0xc2, 0x1f, 0xd7, 0xd1, 0x25, 0x4a, 0x6a, 0x0d, 0x21, 0xb3, 0xa2, 0xb4, 0x24, 0x1c, 0x84, 0xeb, 0x68, 0x41, 0x8a, 0x0e, 0x4f, 0x4a, 0xc9, 0x41, 0x71, 0x51, 0x78, 0xb6, 0x94, 0x46, 0x9e, 0x2b, 0xd7, 0x8b, 0xa2, 0x91, 0x52, 0xea, 0x0d, 0xbd, 0x9a, 0x33, 0x03, 0x70, 0x35, 0xb3, 0x11, 0x97, 0xc0, 0xe7, 0x34, 0x41, 0xe4, 0x8a, 0xad, 0x7b, 0x5c, 0x65, 0xed, 0x39, 0x4d, 0x89, 0xde, 0x52, 0xb3, 0xbd, 0xb8, 0x25, 0x7c, 0x53, 0xc3, 0x6d, 0x23, 0xb5, 0xe5, 0xeb, 0x9f, 0x18, 0x96, 0x00, 0xab, 0xbe, 0x41, 0x71, 0xd3, 0x77, 0x1b, 0x4a, 0x85, 0x46, 0x85, 0x26, 0xbf, 0x66, 0x61, 0xa5, 0xa7, 0xee, 0xc0, 0x70, 0x55, 0xc9, 0xda, 0x87, 0x57, 0x88, 0xd0, 0x2d, 0xd9, 0x8a, 0x13, 0x25, 0xb9,\n\t0x5a, 0xb3, 0x2c, 0x50, 0xdc, 0x98, 0x73, 0x5c, 0x7a, 0x70, 0x55, 0x6e, 0x4d, 0xc4, 0x2d, 0x27, 0x8f, 0xf0, 0xbc, 0x45, 0x0d, 0xbe, 0xec, 0x9a, 0x88, 0x57, 0xe1, 0xd3, 0x45, 0x3b, 0xb6, 0x2c, 0x9c, 0xff, 0xc0, 0xe6, 0x66, 0xfe, 0x69, 0x8d, 0xfd, 0x57, 0xd2, 0xfe, 0xc6, 0xf9, 0x12, 0x85, 0x3b, 0x37, 0x5b, 0x08, 0xc6, 0xb4, 0xd1, 0xee, 0x5d, 0x4b, 0x1a, 0x6f, 0x5d, 0x53, 0x47, 0xdf, 0xaa, 0xb1, 0xbf, 0x29, 0xeb, 0x2c, 0x69, 0x70, 0x64, 0xd9, 0xec, 0x02, 0x84, 0x7f, 0xf6, 0x8d, 0x67, 0x41, 0x9c, 0xf5, 0x47, 0xb8, 0x1f, 0x18, 0x67, 0xe5, 0x78, 0x48, 0x0a, 0xca, 0x6d, 0xc8, 0x85, 0x0d, 0x29, 0x9f, 0x47, 0x09, 0x0a, 0x02, 0x2d, 0xc5, 0x8c, 0x40, 0xc1, 0x0d, 0x30, 0x58, 0x15, 0x04, 0x39, 0xb4, 0x35, 0x69, 0x7b, 0xee, 0x1a, 0xa2, 0xd9, 0xa5, 0xf5, 0xb9, 0x8c, 0xb9, 0x58,\n\t0xe3, 0x81, 0xeb, 0xcb, 0xe9, 0x1d, 0xe9, 0x82, 0xdc, 0xf1, 0xab, 0x96, 0x20, 0x05, 0x80, 0x9c, 0xba, 0x4b, 0x4f, 0xae, 0x46, 0x35, 0x62, 0xb6, 0xdf, 0x00, 0x7e, 0x92, 0x78, 0x79, 0xa5, 0x84, 0xb4, 0xe8, 0x67, 0x29, 0x7a, 0x4f, 0xde, 0x90, 0xa8, 0xda, 0xf6, 0xf2, 0x46, 0x29, 0xbc, 0x6a, 0x50, 0xb6, 0xef, 0x8e, 0x45, 0x04, 0x0a, 0x85, 0xc4, 0x1e, 0x2a, 0xf5, 0xc7, 0xca, 0xdb, 0x8b, 0xbc, 0x2a, 0x89, 0x9a, 0x47, 0x8d, 0xf0, 0x8a, 0x16, 0xef, 0xe9, 0x38, 0xf9, 0x92, 0xa1, 0xb1, 0x51, 0xf0, 0x38, 0x9c, 0xa7, 0xb8, 0x6d, 0xcf, 0xb9, 0xd1, 0xb5, 0xaf, 0x1e, 0xea, 0xa0, 0xcf, 0x68, 0xec, 0x7f, 0x94, 0x26, 0xf3, 0x6b, 0xc5, 0x52, 0xa5, 0x2e, 0x8b, 0x3f, 0x66, 0xa1, 0x6d, 0x0e, 0xa3, 0x50, 0x00, 0xb7, 0x35, 0x1b, 0x32, 0x80, 0xf3, 0x21, 0x9f, 0x59, 0x82, 0xbc, 0x4b, 0xe5,\n\t0x90, 0x29, 0x8c, 0x84, 0xfd, 0x14, 0x0f, 0x4e, 0x11, 0x67, 0x24, 0xa1, 0x19, 0xc4, 0x1b, 0xa6, 0xb4, 0xcc, 0x58, 0xa4, 0xc7, 0xc2, 0xd1, 0x52, 0x5e, 0xb3, 0x1e, 0x4a, 0xf0, 0xda, 0xb0, 0xc7, 0x29, 0x40, 0x2c, 0x0c, 0x52, 0x1d, 0x4f, 0x92, 0xd5, 0xbd, 0x29, 0x61, 0xdd, 0xc2, 0x69, 0xf9, 0xd0, 0x1f, 0x7e, 0x0c, 0xc5, 0x5e, 0x22, 0x0f, 0x1f, 0x54, 0x9d, 0x49, 0xe9, 0xca, 0x76, 0xd9, 0xb7, 0xc7, 0xd7, 0x9c, 0x5e, 0xdb, 0xba, 0x65, 0x51, 0x9d, 0xa1, 0xcd, 0x5c, 0xa0, 0x55, 0xfb, 0xf3, 0x13, 0xc1, 0xb2, 0xde, 0x72, 0x1b, 0x78, 0x16, 0x1e, 0xad, 0xfd, 0xb1, 0xbc, 0x8a, 0x72, 0xf2, 0xb0, 0x44, 0x6f, 0x53, 0x5f, 0x29, 0x77, 0x26, 0xf2, 0xcc, 0x6f, 0x90, 0x0f, 0x99, 0xfd, 0x6c, 0xdf, 0x63, 0x5b, 0x1a, 0x7c, 0x35, 0x0b, 0xa2, 0x05, 0x32, 0xda, 0x60, 0x08, 0x3b, 0x54, 0xfe,\n\t0xa6, 0x95, 0x55, 0xe3, 0x6d, 0x1a, 0xfb, 0x1f, 0x1a, 0x56, 0x67, 0xcb, 0x3a, 0xe5, 0xb6, 0x2c, 0xc5, 0x36, 0x91, 0x3d, 0xbf, 0x3a, 0x1b, 0x60, 0x9b, 0x24, 0xe1, 0x67, 0x1f, 0xa2, 0xce, 0x31, 0xcf, 0x13, 0x6e, 0x22, 0x9e, 0x2c, 0x94, 0x03, 0x14, 0x56, 0xc7, 0xa0, 0x0c, 0x43, 0x3c, 0x40, 0xf2, 0xfa, 0x27, 0x29, 0x2a, 0x52, 0x46, 0xb6, 0xe5, 0xa9, 0x50, 0x15, 0xb7, 0xd6, 0xa5, 0x36, 0x38, 0xb5, 0x02, 0xb4, 0x6f, 0x10, 0x98, 0x5d, 0xd1, 0x42, 0x88, 0x4c, 0xe2, 0x6a, 0x1f, 0x52, 0x83, 0x23, 0x18, 0xc6, 0x9a, 0x4b, 0x04, 0xd8, 0x0e, 0x2d, 0xb9, 0xa2, 0x5b, 0x3a, 0x6b, 0xf3, 0x53, 0x6b, 0x93, 0xe1, 0xd6, 0x72, 0xbf, 0x60, 0xde, 0x9d, 0xd9, 0x3f, 0xd1, 0x64, 0xfd, 0xe3, 0xd7, 0x36, 0x47, 0x76, 0x5b, 0x79, 0x50, 0xa8, 0x05, 0x65, 0xe4, 0x17, 0x63, 0xf9, 0xcb, 0xef, 0x5a,\n\t0x9c, 0xbd, 0xac, 0x02, 0x18, 0xe2, 0xf3, 0x2a, 0xc9, 0x37, 0xe5, 0xc2, 0x40, 0xfb, 0x43, 0x6f, 0x5e, 0x1c, 0xb6, 0x1b, 0x0c, 0xf1, 0xf9, 0xc9, 0x53, 0x9c, 0xbd, 0xd0, 0x0f, 0xf7, 0x60, 0x31, 0xe4, 0x29, 0x9d, 0x68, 0x0f, 0x8c, 0x80, 0x10, 0xa2, 0xf0, 0x3f, 0xb8, 0xfa, 0x88, 0x4b, 0x5f, 0xc2, 0x43, 0x71, 0x57, 0xc8, 0xeb, 0xb3, 0x5f, 0x04, 0x30, 0x8f, 0x43, 0xd3, 0x4b, 0xe9, 0x66, 0xa7, 0x5d, 0x93, 0xf2, 0x2e, 0x86, 0x6c, 0xa4, 0x98, 0x53, 0xa8, 0xe2, 0xff, 0xb8, 0xd8, 0x03, 0xf4, 0x1f, 0x98, 0x1a, 0x53, 0x53, 0x0a, 0xc8, 0xef, 0x82, 0x10, 0xfb, 0x2c, 0x68, 0x63, 0x9f, 0xbd, 0xc8, 0x7d, 0xc0, 0xcb, 0x95, 0x0f, 0x9b, 0x5d, 0x22, 0xc0, 0x93, 0x6b, 0x05, 0x7c, 0x8d, 0x0c, 0x30, 0x02, 0x8f, 0xe9, 0x11, 0x72, 0xdd, 0xda, 0x65, 0x23, 0xec, 0x4f, 0x41, 0xf6, 0xc8, 0xb2,\n\t0xb5, 0x54, 0xc0, 0xa8, 0x1f, 0xfb, 0xb5, 0x27, 0x61, 0xb3, 0x25, 0x3c, 0xa4, 0x5d, 0x6d, 0xe5, 0x74, 0xd7, 0x41, 0x38, 0x5e, 0x29, 0xdd, 0x37, 0x79, 0xbc, 0x70, 0x6c, 0x84, 0x70, 0x74, 0xa6, 0x51, 0x7f, 0xc5, 0x78, 0xb5, 0xae, 0xe8, 0xe4, 0xf1, 0x4e, 0x70, 0x57, 0x70, 0xbc, 0x0f, 0x03, 0x86, 0x7d, 0x17, 0x44, 0xd8, 0x77, 0x9f, 0x65, 0xbf, 0x0f, 0x0a, 0xe1, 0x3f, 0x1e, 0x7b, 0xd7, 0x3d, 0xf6, 0xb0, 0xe8, 0xa7, 0x1a, 0x83, 0x40, 0xa0, 0x57, 0xff, 0x44, 0x1c, 0x73, 0xed, 0x27, 0xd5, 0xab, 0xfb, 0x86, 0x3f, 0xf8, 0x60, 0xb8, 0x6f, 0x35, 0xd9, 0xe4, 0xd5, 0xb1, 0x27, 0x83, 0x65, 0x16, 0x6b, 0xb9, 0x1f, 0x0c, 0xea, 0xbd, 0x9c, 0xec, 0x5a, 0x34, 0xfe, 0x31, 0xaf, 0x87, 0x79, 0x96, 0x10, 0xc2, 0x33, 0xdc, 0x04, 0xb7, 0xf9, 0x1f, 0xa8, 0x22, 0x12, 0x0f, 0x12, 0x5f, 0x21,\n\t0x1f, 0xe9, 0xb5, 0x90, 0x23, 0x5e, 0x1c, 0x12, 0x17, 0x12, 0x82, 0xfc, 0x88, 0x04, 0x02, 0x07, 0x8f, 0xe4, 0x43, 0x16, 0x93, 0xa0, 0x44, 0x7c, 0xac, 0xae, 0x11, 0x89, 0x85, 0xa2, 0xa5, 0xd8, 0xcd, 0x16, 0x11, 0x21, 0xb8, 0xfa, 0x62, 0x31, 0xe8, 0x15, 0xa4, 0xb4, 0x5d, 0x9c, 0x5a, 0xac, 0xf4, 0x2b, 0x1f, 0xc7, 0x0f, 0xf2, 0x78, 0x38, 0x9b, 0xf2, 0xaa, 0xa9, 0x5d, 0x24, 0x13, 0xff, 0xe9, 0xd3, 0x58, 0xa1, 0x26, 0x16, 0xa7, 0x45, 0x6a, 0x88, 0x89, 0x2d, 0x62, 0xd1, 0xfc, 0x79, 0x1d, 0xb3, 0x1b, 0xea, 0x2a, 0xca, 0xf2, 0x73, 0x7d, 0x1e, 0xa7, 0xdd, 0x64, 0x50, 0xca, 0x45, 0x71, 0x71, 0xdc, 0xe5, 0x94, 0xa2, 0xba, 0x90, 0xa9, 0x98, 0xbc, 0x10, 0xc8, 0xa4, 0xd4, 0xf8, 0x32, 0xfd, 0x05, 0x84, 0xf0, 0xe9, 0x45, 0x48, 0x27, 0xea, 0x29, 0xa2, 0xc4, 0xdb, 0xf4, 0x0f, 0xc5,\n\t0x66, 0xe3, 0x6d, 0x97, 0x7f, 0x2b, 0xb2, 0x69, 0x6e, 0x07, 0x8f, 0x88, 0x85, 0x65, 0xd9, 0xbb, 0x7b, 0x3b, 0x76, 0x2f, 0xc8, 0x8f, 0x2e, 0xde, 0xdb, 0xde, 0xbe, 0x35, 0x58, 0xc0, 0x48, 0x25, 0x12, 0x83, 0x3b, 0x16, 0xcc, 0x69, 0x89, 0xdb, 0x1c, 0x10, 0x8b, 0x1b, 0x83, 0x6e, 0x9b, 0x82, 0x27, 0xa1, 0x25, 0xb1, 0x81, 0x43, 0x5d, 0x5d, 0x87, 0x06, 0x62, 0xe9, 0xcf, 0x93, 0xb6, 0xe2, 0x8e, 0x48, 0xa4, 0xa3, 0xd8, 0xb6, 0x61, 0xd9, 0xb2, 0x0d, 0xcc, 0xcd, 0x52, 0xf5, 0x17, 0xbb, 0x65, 0x4a, 0x6a, 0xb7, 0xb0, 0xaa, 0xb8, 0xb4, 0x68, 0xe9, 0xc1, 0xf6, 0x8e, 0x43, 0x4b, 0xe3, 0xb1, 0x50, 0x3d, 0x5f, 0xa4, 0xd4, 0x2a, 0x1d, 0x15, 0x0b, 0x4a, 0x4a, 0x7a, 0x2b, 0x1c, 0x8c, 0x44, 0x2d, 0x63, 0x78, 0x63, 0xbf, 0x9b, 0x7d, 0x60, 0xb0, 0xb8, 0x78, 0xf0, 0xc0, 0xec, 0xd9, 0x07,\n\t0xd1, 0xe7, 0xc1, 0xd9, 0xc5, 0xbd, 0x09, 0xa7, 0x33, 0xd1, 0x5b, 0x3c, 0xba, 0x73, 0x27, 0xdc, 0xf3, 0x77, 0x08, 0x42, 0x70, 0x16, 0xf2, 0xbe, 0x5a, 0xc2, 0x01, 0x65, 0x9c, 0x62, 0xe2, 0x26, 0x2e, 0x40, 0xdf, 0x43, 0x30, 0x62, 0xc0, 0x13, 0x30, 0xbc, 0x01, 0x88, 0xd1, 0x85, 0x90, 0xed, 0x80, 0x27, 0x0a, 0x95, 0x77, 0xe0, 0xa3, 0x6c, 0xef, 0x5c, 0x62, 0x63, 0xbc, 0x25, 0x81, 0xab, 0xda, 0x51, 0x78, 0xef, 0x51, 0x6b, 0xec, 0x69, 0xbc, 0x2a, 0xdd, 0xb6, 0x27, 0x69, 0x72, 0x39, 0xf5, 0xba, 0xe2, 0xa2, 0x78, 0x2c, 0x3b, 0xe4, 0x8c, 0xba, 0xa2, 0x16, 0x93, 0xce, 0xa1, 0x77, 0xc0, 0xff, 0x15, 0x12, 0x64, 0x48, 0x8d, 0x28, 0x5d, 0xd3, 0x42, 0xdc, 0x20, 0x87, 0x8a, 0xad, 0x6e, 0xa9, 0x4a, 0xbd, 0xd4, 0x34, 0x27, 0x25, 0x06, 0x95, 0x67, 0x3c, 0xfd, 0xf2, 0xb0, 0xc1, 0xa1,\n\t0xbc, 0x72, 0x89, 0xa4, 0x5e, 0x59, 0x63, 0x36, 0x2b, 0xa9, 0x6c, 0x8a, 0x22, 0xbf, 0xd9, 0xb9, 0x78, 0x71, 0x67, 0xd7, 0xa2, 0x45, 0x9d, 0x8d, 0x9b, 0xbb, 0x73, 0x73, 0xbb, 0x37, 0x37, 0xc2, 0xcf, 0xbc, 0xbc, 0xee, 0xcd, 0xec, 0x1a, 0xf2, 0xb6, 0xb1, 0x75, 0x28, 0x3d, 0x90, 0x4a, 0x43, 0x1b, 0x4c, 0x85, 0xfa, 0x2b, 0x3e, 0xe6, 0x94, 0x54, 0x7f, 0xf9, 0x0f, 0x96, 0x78, 0x16, 0xb5, 0x78, 0x79, 0xdf, 0xc2, 0xe5, 0xcb, 0x17, 0xf6, 0x2d, 0x1f, 0xfb, 0x7b, 0x64, 0x1e, 0x64, 0xde, 0x37, 0xf5, 0x14, 0x70, 0x9f, 0xf3, 0x22, 0x1b, 0x6f, 0x83, 0xf4, 0x2d, 0x17, 0xe3, 0x7e, 0x54, 0x5b, 0xb2, 0x18, 0xe9, 0x2c, 0x85, 0x90, 0xd9, 0x82, 0xf2, 0x14, 0xcd, 0x00, 0xba, 0x5f, 0x06, 0x24, 0x12, 0x38, 0x63, 0x14, 0x73, 0x2c, 0xee, 0x51, 0xc8, 0xa5, 0x94, 0x58, 0x3c, 0xd4, 0x84, 0x1c,\n\t0x3c, 0x97, 0x32, 0xcd, 0x34, 0x4d, 0x17, 0xd3, 0xc5, 0xb1, 0xc2, 0x48, 0x41, 0x7e, 0x6e, 0x38, 0xe8, 0xf3, 0x7a, 0xdc, 0x0e, 0x97, 0x4e, 0xa9, 0x76, 0xb8, 0x95, 0x0a, 0x25, 0x3a, 0xd9, 0x2e, 0x2a, 0xc2, 0x15, 0xde, 0x45, 0xa4, 0x4c, 0x0e, 0x2f, 0xb1, 0x58, 0xa1, 0x76, 0x61, 0xe1, 0x56, 0x0d, 0x57, 0x24, 0x01, 0x22, 0x6a, 0x17, 0xd6, 0xe0, 0xe2, 0x73, 0x4e, 0x45, 0xb8, 0x44, 0xae, 0xe4, 0x4f, 0xff, 0x5a, 0xfe, 0x11, 0x78, 0x53, 0xce, 0xf8, 0x83, 0x3b, 0x2a, 0x9e, 0xb4, 0x99, 0xf8, 0xc2, 0x0f, 0x3b, 0xe6, 0xc9, 0x0c, 0x0a, 0x3e, 0x5d, 0xfd, 0x51, 0xb5, 0xa0, 0xc0, 0x3e, 0xb7, 0xe3, 0x90, 0xd5, 0xcc, 0x17, 0xbe, 0x53, 0xfe, 0x3b, 0x19, 0x6c, 0x72, 0x67, 0x2d, 0x2f, 0xcf, 0x3e, 0xaf, 0xe3, 0xaf, 0xed, 0xdd, 0x76, 0x37, 0xaf, 0x96, 0x5a, 0xc5, 0xbe, 0x0d, 0xde, 0xee,\n\t0xb4, 0x59, 0xd9, 0xb7, 0x3d, 0xe1, 0x04, 0xbb, 0x50, 0xaa, 0xb7, 0xaa, 0x20, 0x8a, 0x3b, 0xed, 0x77, 0x82, 0x87, 0xdd, 0xd9, 0x09, 0x50, 0xd4, 0x61, 0xb7, 0x82, 0x05, 0x76, 0x0f, 0xbb, 0x08, 0x3c, 0xe8, 0xb7, 0xb3, 0xa7, 0xb1, 0x7c, 0xb1, 0x6c, 0xfc, 0x9f, 0xf4, 0x1d, 0x90, 0x70, 0x23, 0x19, 0x69, 0x2e, 0xc7, 0x50, 0x21, 0x33, 0x2d, 0xa4, 0xf2, 0xe4, 0x40, 0x5a, 0x52, 0x9a, 0xe0, 0x9f, 0xae, 0xba, 0x85, 0xd9, 0xa5, 0x99, 0x1e, 0xe8, 0xb9, 0x76, 0x65, 0xf8, 0xe9, 0xa5, 0x49, 0xe9, 0x3b, 0xe6, 0xdc, 0x7e, 0x61, 0xcd, 0x9a, 0x37, 0x8e, 0x76, 0x75, 0x1d, 0x7d, 0x63, 0xcd, 0x9a, 0x0b, 0xb7, 0xcf, 0xb9, 0x58, 0xd2, 0xb7, 0x25, 0x59, 0xb9, 0xa9, 0xaf, 0xb8, 0xb8, 0x6f, 0x53, 0x65, 0x72, 0x4b, 0x5f, 0x09, 0x99, 0xb7, 0xff, 0x67, 0x77, 0xb6, 0xb6, 0xde, 0xf9, 0xb3, 0xfd,\n\t0xfb, 0xdf, 0x43, 0x9f, 0xef, 0xed, 0x5f, 0x73, 0xdf, 0x60, 0x5e, 0xde, 0xe0, 0x7d, 0x6b, 0x56, 0x9f, 0x1a, 0xcc, 0xcd, 0x1d, 0xe4, 0x72, 0xa8, 0x3a, 0x51, 0x7d, 0x72, 0x7a, 0x09, 0x21, 0x41, 0x76, 0x02, 0x31, 0x0f, 0xdb, 0x09, 0xd2, 0x3e, 0x27, 0xc8, 0x35, 0x0e, 0xfe, 0x95, 0x10, 0x12, 0x25, 0x67, 0x27, 0xc0, 0x11, 0x98, 0x90, 0x4e, 0xe7, 0x22, 0x03, 0xf1, 0xb7, 0x48, 0xf2, 0x57, 0xc6, 0x3c, 0x65, 0x15, 0x38, 0x49, 0x2f, 0xb9, 0xfc, 0x35, 0xca, 0xa2, 0x2f, 0x30, 0xdc, 0xaf, 0x61, 0xf4, 0xdd, 0xc0, 0x85, 0xec, 0x05, 0xdd, 0x28, 0xe6, 0x0d, 0xf2, 0xeb, 0x3c, 0xb0, 0x9d, 0x46, 0xd7, 0xad, 0xe3, 0x3e, 0xea, 0x02, 0xbe, 0xde, 0x71, 0x19, 0x5d, 0x7b, 0xc6, 0x63, 0x74, 0x36, 0xf2, 0x27, 0x07, 0x3b, 0xcd, 0xe8, 0xba, 0x78, 0xdc, 0x4b, 0xdd, 0x0e, 0x69, 0x03, 0x0f, 0xec,\n\t0xfa, 0x05, 0xba, 0xee, 0x1b, 0xff, 0x07, 0x75, 0x99, 0x99, 0x05, 0xaf, 0x77, 0xf3, 0xd0, 0x75, 0xee, 0x78, 0x8c, 0xfa, 0x26, 0xbe, 0xbf, 0xe7, 0x47, 0xe8, 0x7a, 0x39, 0xbc, 0xff, 0x07, 0xa6, 0x03, 0x5e, 0xef, 0x15, 0xa3, 0xeb, 0xda, 0xf1, 0x28, 0x75, 0x0e, 0xee, 0x09, 0x0f, 0xec, 0xfb, 0x0b, 0xce, 0x25, 0x02, 0xf7, 0x88, 0xfe, 0x7f, 0xbc, 0x47, 0x74, 0xcb, 0xde, 0xe7, 0x06, 0x07, 0x9f, 0xdd, 0xd3, 0xd2, 0xb2, 0xe7, 0xd9, 0xc1, 0xc1, 0xe7, 0xf6, 0xb6, 0xbc, 0x11, 0x6e, 0x1b, 0x4e, 0x26, 0x87, 0x5b, 0x43, 0xa1, 0x56, 0xf4, 0xd9, 0x16, 0x26, 0xf3, 0x8e, 0xbc, 0x7f, 0xa4, 0xbe, 0x1e, 0xfe, 0x39, 0xfa, 0xfe, 0xd1, 0xfa, 0x7a, 0xf8, 0x67, 0xa6, 0x3d, 0xda, 0x03, 0xd7, 0xf2, 0x7b, 0x70, 0x8f, 0x14, 0x84, 0x3f, 0xe9, 0x91, 0x0a, 0xb8, 0x18, 0x28, 0xc4, 0x49, 0xe2, 0x7c,\n\t0xf7, 0x38, 0x30, 0x89, 0xdb, 0x29, 0x05, 0xa1, 0x30, 0x2a, 0x95, 0xc8, 0x3d, 0xc4, 0xa3, 0x45, 0x0e, 0xd1, 0x99, 0xdd, 0x8a, 0x28, 0xa9, 0xef, 0x5d, 0xb9, 0x02, 0xf2, 0x29, 0xf2, 0x77, 0x86, 0x42, 0x59, 0x29, 0x38, 0x76, 0xe2, 0xe8, 0xd1, 0xa3, 0xe4, 0x56, 0x73, 0x89, 0xed, 0x6b, 0x2a, 0x46, 0x3b, 0x07, 0x38, 0xae, 0xe4, 0xc0, 0xf7, 0x74, 0xc2, 0xf7, 0xfc, 0x1c, 0xee, 0x51, 0x1e, 0x51, 0x9a, 0x2c, 0xb2, 0x00, 0x8a, 0xcc, 0x46, 0xde, 0x36, 0x28, 0x31, 0x13, 0x89, 0x44, 0x2c, 0x54, 0xf1, 0x0c, 0x79, 0x8b, 0xe2, 0x2c, 0x24, 0xd8, 0x84, 0xbe, 0x14, 0xb9, 0x85, 0xba, 0x1c, 0xa6, 0x2c, 0x95, 0x82, 0xa1, 0x89, 0x3c, 0x90, 0x8b, 0xf9, 0x79, 0x6c, 0x76, 0x8d, 0x82, 0x89, 0x6a, 0x9a, 0x69, 0xf3, 0xd2, 0x84, 0xbb, 0x3f, 0x9f, 0x41, 0x01, 0xe6, 0x77, 0x38, 0x3c, 0x57, 0xb6,\n\t0x80, 0x97, 0x51, 0xf0, 0xbb, 0x25, 0xda, 0x9c, 0x53, 0xd4, 0x51, 0xe2, 0x11, 0x0b, 0x34, 0x3a, 0x46, 0xce, 0x5b, 0x23, 0xad, 0x59, 0x73, 0x7c, 0xf1, 0x9c, 0x43, 0x4b, 0x62, 0xde, 0xea, 0xbe, 0x62, 0xf6, 0x07, 0xb9, 0xbd, 0xee, 0x67, 0xfc, 0xe6, 0x55, 0x6b, 0x40, 0x6f, 0xb0, 0xb5, 0xb5, 0x23, 0x3b, 0x50, 0x1b, 0xb1, 0x38, 0x62, 0x75, 0x5e, 0xad, 0x1a, 0x90, 0xea, 0xd6, 0x03, 0x83, 0x25, 0x91, 0x05, 0xdb, 0x9b, 0xcb, 0x57, 0x2d, 0x99, 0x1f, 0xfa, 0xb3, 0x38, 0xe5, 0xd3, 0xdc, 0x09, 0xe1, 0xed, 0x6d, 0x38, 0x97, 0x6a, 0x54, 0xc5, 0x0a, 0xe5, 0xee, 0x36, 0x42, 0x99, 0x1a, 0x4e, 0x85, 0xc7, 0xd0, 0x0c, 0x8f, 0x1e, 0x21, 0x52, 0x92, 0x21, 0xf2, 0x7d, 0x20, 0xe9, 0xab, 0x4b, 0xa6, 0xc7, 0xfc, 0xca, 0xac, 0x70, 0x8e, 0x9b, 0x2f, 0x32, 0x4d, 0x38, 0xf4, 0xf2, 0xa6, 0xc6,\n\t0xfb, 0xa7, 0x13, 0x67, 0xe1, 0x59, 0x46, 0xa7, 0xcf, 0xd6, 0x77, 0x93, 0xb4, 0x6a, 0xf8, 0x9e, 0xc5, 0x73, 0x8f, 0x0c, 0x15, 0xaf, 0x1b, 0xde, 0xb1, 0xa5, 0xfc, 0x86, 0x87, 0x06, 0x97, 0xde, 0xb9, 0xb2, 0x3e, 0x6b, 0xbe, 0x27, 0x47, 0x2c, 0x0b, 0x27, 0xe6, 0x16, 0x95, 0x2c, 0xae, 0xf6, 0x38, 0x5b, 0x6e, 0xee, 0x4d, 0xae, 0x6d, 0xcf, 0x71, 0x96, 0xb4, 0xe5, 0xc4, 0xdb, 0x53, 0xb3, 0x57, 0x30, 0xe4, 0xff, 0x46, 0x73, 0x2a, 0xe8, 0xd9, 0xda, 0xb4, 0xfa, 0x98, 0xd7, 0xf9, 0xe8, 0xce, 0xa6, 0x43, 0xab, 0x92, 0xb9, 0xdd, 0x5b, 0x9a, 0xfd, 0x0a, 0xa5, 0xc1, 0x57, 0x17, 0xb3, 0xbb, 0x12, 0x73, 0x0b, 0x8a, 0xe7, 0x95, 0xd9, 0xf6, 0x93, 0x96, 0xe2, 0x39, 0xc5, 0xf9, 0xcd, 0x11, 0xa3, 0x3d, 0x56, 0xe7, 0x43, 0x8b, 0xc1, 0xf9, 0xf9, 0x0a, 0xe1, 0xd9, 0x52, 0xc2, 0xb3, 0x45,\n\t0x43, 0x4a, 0x56, 0x9b, 0xac, 0x82, 0x54, 0x88, 0x56, 0x01, 0xbc, 0x91, 0xb8, 0x4a, 0x3c, 0x84, 0x9c, 0x75, 0x7c, 0x86, 0x47, 0x61, 0xa7, 0x34, 0xfc, 0x85, 0x00, 0x0b, 0xb0, 0xdb, 0xf7, 0x6c, 0x86, 0x81, 0xeb, 0xa2, 0x65, 0xb4, 0x1a, 0xb5, 0x5c, 0x2a, 0x11, 0x8b, 0x04, 0xe8, 0x01, 0x01, 0x52, 0xd2, 0xfe, 0x1f, 0xd6, 0xde, 0x03, 0x3e, 0xae, 0xe2, 0xda, 0x1f, 0xbf, 0x73, 0xdb, 0x56, 0xed, 0xea, 0x6e, 0xef, 0xbd, 0x6a, 0xb5, 0xea, 0xbb, 0xea, 0xd2, 0xaa, 0x5a, 0x56, 0xb5, 0x5c, 0x54, 0x2c, 0xd9, 0x96, 0x2d, 0xc9, 0xb2, 0x6c, 0xe3, 0xde, 0x1b, 0x2e, 0xd8, 0xd8, 0x60, 0x4c, 0xb1, 0x4d, 0x28, 0x26, 0x06, 0x4c, 0xc7, 0x26, 0x10, 0xc0, 0x24, 0x04, 0x02, 0x31, 0xbc, 0x17, 0x42, 0x09, 0x79, 0x09, 0x10, 0xe0, 0x05, 0xd2, 0xe0, 0x25, 0x79, 0x09, 0x09, 0x25, 0xa6, 0xd9, 0xba,\n\t0xfa, 0xcf, 0xcc, 0xbd, 0xbb, 0x5a, 0xc9, 0x32, 0xf0, 0x3e, 0xff, 0x9f, 0xc1, 0xde, 0xdd, 0x5b, 0x67, 0xce, 0xcc, 0x9c, 0x73, 0xe6, 0x94, 0xef, 0xe1, 0x8a, 0x8a, 0xb1, 0x52, 0x2e, 0x64, 0x38, 0x7b, 0x84, 0x39, 0x45, 0xde, 0xa9, 0xe4, 0xc3, 0x54, 0x85, 0xc5, 0x70, 0xe2, 0xde, 0xb1, 0x27, 0xb4, 0x7e, 0x2a, 0x93, 0x3c, 0xfc, 0x28, 0xb0, 0x82, 0x8f, 0xcb, 0x1b, 0xc6, 0x6e, 0x18, 0x36, 0x98, 0xf9, 0x1f, 0x80, 0x4e, 0xbb, 0xa1, 0x9b, 0x9a, 0x75, 0xf1, 0x69, 0x61, 0x4c, 0x16, 0xc1, 0x35, 0xfe, 0x14, 0x5c, 0xc3, 0x51, 0x34, 0xbf, 0xfc, 0x70, 0x3c, 0x50, 0x4d, 0x45, 0xb2, 0x39, 0x00, 0x77, 0xf3, 0x33, 0x51, 0x35, 0x3d, 0x02, 0x55, 0xd3, 0xbb, 0x4c, 0x0d, 0x7b, 0xaf, 0x2e, 0x94, 0x15, 0x72, 0xe3, 0x3d, 0x51, 0x7c, 0x72, 0x5e, 0x52, 0x15, 0x30, 0x4e, 0x54, 0xd3, 0x44, 0x1b,\n\t0xf6, 0xa0, 0x56, 0xd8, 0x3e, 0x80, 0x05, 0x8b, 0x7b, 0x96, 0x9e, 0x18, 0x8d, 0xcf, 0xdc, 0xf3, 0xe8, 0xd2, 0x8a, 0x95, 0x03, 0x9d, 0xce, 0x62, 0x55, 0x81, 0x29, 0x7f, 0xeb, 0xcc, 0xba, 0x15, 0x2d, 0x21, 0xdf, 0x8c, 0xd1, 0xfa, 0xbc, 0xd1, 0xf8, 0x86, 0x15, 0xe4, 0x21, 0x7f, 0x88, 0x6f, 0x22, 0x57, 0xea, 0x2b, 0x46, 0x6f, 0x9a, 0x37, 0xfa, 0xd0, 0xb6, 0x5a, 0x53, 0xa8, 0xc8, 0xde, 0xae, 0x53, 0x71, 0x9e, 0x82, 0x48, 0xfb, 0xaa, 0xba, 0xb2, 0x85, 0xb5, 0x3e, 0x4d, 0xa6, 0x87, 0xdc, 0xb0, 0xc4, 0x15, 0x49, 0xc5, 0x50, 0x9f, 0x87, 0x7c, 0x49, 0x4b, 0xe4, 0x23, 0x44, 0x7b, 0xa3, 0x80, 0xc8, 0x32, 0x2d, 0x46, 0xcf, 0x4a, 0x0a, 0xae, 0x8e, 0xfc, 0x5c, 0xbf, 0xd7, 0x6a, 0x16, 0x42, 0xa6, 0x85, 0xd5, 0x31, 0x19, 0x3b, 0x8b, 0x12, 0x0a, 0x15, 0x4f, 0x0a, 0xa4, 0x16, 0x01,\n\t0x6f, 0x49, 0x4f, 0xdd, 0x68, 0x73, 0x30, 0xd4, 0x34, 0x5c, 0x59, 0xbf, 0xbc, 0x25, 0x18, 0x98, 0x31, 0x62, 0xc9, 0xb4, 0xab, 0xa2, 0x2b, 0xaa, 0x67, 0xdd, 0xb4, 0xba, 0xa6, 0x7e, 0xc7, 0x99, 0xd1, 0x65, 0x0f, 0x6e, 0x4a, 0xb4, 0xcd, 0x03, 0x4d, 0xba, 0xe2, 0xc0, 0x7d, 0x87, 0xa2, 0x6d, 0x23, 0xe5, 0x89, 0xe1, 0x19, 0xfe, 0x9c, 0xd6, 0x81, 0xc2, 0xaa, 0xd1, 0xb6, 0x6c, 0xf2, 0x65, 0x9d, 0x5f, 0x6b, 0x73, 0xc6, 0x96, 0x7e, 0x6f, 0xc9, 0x82, 0xbb, 0xb7, 0x36, 0xd4, 0x6d, 0x3b, 0x3d, 0xda, 0xf7, 0x8b, 0x35, 0xe0, 0x49, 0xbb, 0x2b, 0x39, 0x16, 0x71, 0xea, 0x23, 0x38, 0x16, 0x1c, 0xf6, 0xbd, 0x23, 0x07, 0x36, 0x85, 0xb2, 0x8a, 0xc9, 0x79, 0xa8, 0x00, 0xac, 0x48, 0x73, 0x21, 0xa5, 0xd2, 0x1b, 0xa4, 0x91, 0x36, 0x88, 0xe6, 0x7f, 0x12, 0x23, 0x0b, 0x17, 0xc6, 0xa5, 0x3e,\n\t0x92, 0xca, 0xc7, 0xfe, 0x24, 0x2f, 0xb2, 0x5d, 0x4f, 0x3a, 0x1d, 0xde, 0xb1, 0xa5, 0x66, 0x0f, 0xbd, 0x70, 0xa1, 0x3e, 0xa8, 0xbb, 0xf0, 0x33, 0xa3, 0x8f, 0x36, 0x97, 0x86, 0x6d, 0xb6, 0x8d, 0x50, 0x43, 0x58, 0x00, 0xe9, 0xf5, 0xdf, 0x90, 0x4f, 0x23, 0x3e, 0x3c, 0x03, 0xed, 0x86, 0x4b, 0x00, 0xce, 0xf8, 0x67, 0x24, 0x00, 0x19, 0x0a, 0x50, 0xb0, 0x23, 0x0a, 0x01, 0xc1, 0x9e, 0xf1, 0x64, 0x15, 0x51, 0x84, 0xd5, 0x53, 0x53, 0x9d, 0x9f, 0xeb, 0xb4, 0xeb, 0x82, 0xfa, 0xa0, 0x40, 0x3b, 0xe9, 0x34, 0xb4, 0xd3, 0xa6, 0x31, 0x5b, 0x74, 0x5c, 0x9b, 0x5e, 0xd0, 0x25, 0x9e, 0xe6, 0x07, 0x86, 0x6d, 0x27, 0xad, 0x15, 0x8b, 0xeb, 0x7c, 0xe1, 0x19, 0x8b, 0x62, 0xb1, 0x05, 0x33, 0xc2, 0xbe, 0xda, 0x81, 0x8a, 0xe2, 0x39, 0xa5, 0x76, 0x73, 0x7c, 0x5e, 0x45, 0x45, 0x57, 0xdc, 0x02,\n\t0xd7, 0xd1, 0xd1, 0xad, 0x3b, 0x6b, 0x36, 0xdd, 0x3b, 0x34, 0x78, 0xcf, 0xa6, 0x9a, 0x1d, 0xdb, 0x86, 0x86, 0xcb, 0x96, 0x1f, 0x9d, 0x3f, 0xff, 0xd8, 0x8a, 0xb2, 0xe1, 0x03, 0xbe, 0x44, 0x6f, 0x2c, 0xb1, 0xb0, 0xc2, 0x6e, 0xaf, 0x58, 0x98, 0x88, 0xf5, 0x26, 0x7c, 0x74, 0x99, 0xa7, 0xac, 0x3d, 0x92, 0x3d, 0x27, 0x11, 0x0c, 0x26, 0xe6, 0x64, 0x47, 0xda, 0xcb, 0x3c, 0x63, 0xe3, 0xfe, 0xfb, 0x77, 0xf5, 0xde, 0x30, 0x1c, 0x8f, 0x0f, 0xdf, 0xd0, 0xbb, 0xeb, 0x7e, 0x7f, 0xe8, 0xc4, 0xca, 0x96, 0xbd, 0x8b, 0x8a, 0x8b, 0x17, 0xed, 0x6d, 0x59, 0x79, 0x02, 0x4e, 0x8b, 0xf9, 0x50, 0x36, 0xbd, 0x02, 0x65, 0x11, 0x07, 0xe7, 0x4c, 0x4e, 0x22, 0xa2, 0x47, 0x3b, 0x1d, 0x3c, 0x67, 0xd6, 0x27, 0x7b, 0x4f, 0xe0, 0x6c, 0x0b, 0x22, 0x15, 0x1c, 0x90, 0x1d, 0x0a, 0x87, 0x3c, 0x0c, 0x8a,\n\t0xd4, 0x11, 0x5c, 0xb8, 0x29, 0x9b, 0x25, 0xdc, 0xe3, 0xa4, 0x6b, 0xe2, 0x22, 0x37, 0x15, 0xc6, 0xc5, 0xb0, 0x7f, 0x53, 0xf5, 0x92, 0x3a, 0x6f, 0xa0, 0x7e, 0x61, 0x71, 0xf9, 0x40, 0xbd, 0x0f, 0xac, 0x30, 0x06, 0xb8, 0xfc, 0x3d, 0x6d, 0x33, 0xaf, 0x5e, 0x56, 0x55, 0xbb, 0xf9, 0xde, 0xc1, 0x25, 0x77, 0xae, 0xad, 0x34, 0x46, 0x12, 0x61, 0xfe, 0xb7, 0x5c, 0xbe, 0xe7, 0x7e, 0xf2, 0xb7, 0x5b, 0xf7, 0x84, 0x1b, 0xe7, 0x17, 0x94, 0x2f, 0x48, 0xb8, 0x03, 0x75, 0xfd, 0x7c, 0x9e, 0x3d, 0x6e, 0x8d, 0x16, 0x14, 0x0c, 0x1c, 0x59, 0xd0, 0x73, 0xdb, 0xba, 0xda, 0xca, 0x35, 0x27, 0x16, 0x95, 0xaf, 0x5e, 0x79, 0x45, 0x29, 0xbf, 0xc8, 0x68, 0xc7, 0xf3, 0x7e, 0xe9, 0xf8, 0x27, 0xf4, 0x39, 0x8c, 0x65, 0x17, 0xc4, 0x68, 0xeb, 0x13, 0x7b, 0xfb, 0x09, 0x89, 0x39, 0x21, 0x18, 0x27, 0x15,\n\t0x27, 0xc4, 0xd8, 0x70, 0x97, 0x08, 0xc7, 0x73, 0xfd, 0xb7, 0xbf, 0xbc, 0x6a, 0xd5, 0xcb, 0xb7, 0xf5, 0xf5, 0xdd, 0x86, 0x3e, 0x6f, 0xef, 0x7f, 0xb9, 0x6c, 0xf1, 0xde, 0xa6, 0xa6, 0xbd, 0x8b, 0x4b, 0x4b, 0x85, 0xcf, 0x32, 0xf2, 0x97, 0xcf, 0xf0, 0xff, 0x78, 0xb2, 0xa7, 0xe7, 0x49, 0xa0, 0x7b, 0xe6, 0x19, 0xa0, 0x47, 0xdf, 0xf8, 0xbf, 0x3f, 0x73, 0xf7, 0xbb, 0xfb, 0x4b, 0x4a, 0xf6, 0xbf, 0x7b, 0xf7, 0xdd, 0xef, 0x5e, 0x55, 0x52, 0x72, 0xd5, 0xbb, 0x68, 0xea, 0xc2, 0x16, 0x92, 0x3d, 0xcc, 0x49, 0x21, 0x0f, 0x39, 0x83, 0x9d, 0x94, 0x23, 0x8c, 0xa6, 0xf3, 0x60, 0x4b, 0x4a, 0x42, 0xaa, 0x08, 0x95, 0x91, 0xc3, 0xf3, 0x59, 0x54, 0x66, 0x50, 0x96, 0x30, 0x52, 0x67, 0x7a, 0x5e, 0x24, 0xc9, 0x37, 0x94, 0x0e, 0x87, 0x4d, 0x56, 0x06, 0x4e, 0x30, 0x27, 0xbf, 0x5e, 0x4c, 0xd7,\n\t0x9a, 0x0a, 0x2c, 0x4f, 0xc9, 0xe5, 0x40, 0xa1, 0x9c, 0x01, 0x86, 0x71, 0x0c, 0x75, 0x3b, 0x9c, 0xa2, 0x1a, 0x48, 0x03, 0x16, 0xdc, 0xf8, 0x6f, 0xf4, 0xbb, 0x63, 0xfc, 0x63, 0xda, 0x8a, 0x7f, 0xdf, 0xc4, 0x63, 0x9d, 0x06, 0x9e, 0x1f, 0x64, 0xee, 0x80, 0xbf, 0x8f, 0x6a, 0xd0, 0xef, 0x19, 0xe3, 0x1f, 0x53, 0x1f, 0xa2, 0x7c, 0x78, 0x70, 0xec, 0x3d, 0xf4, 0xbb, 0x18, 0x9e, 0x57, 0xe0, 0xdf, 0xc7, 0x5f, 0x47, 0xbf, 0xeb, 0x20, 0xa3, 0xf8, 0x04, 0xdf, 0x7f, 0xf3, 0x1f, 0x10, 0x8d, 0xcb, 0x20, 0x8d, 0xdb, 0xff, 0x5f, 0xd2, 0xb8, 0xbd, 0xf3, 0xba, 0xe7, 0x56, 0xad, 0x7a, 0xee, 0xf0, 0xac, 0x59, 0x87, 0xd1, 0xe7, 0x75, 0x9d, 0x2f, 0xc7, 0x7a, 0x37, 0x54, 0x57, 0x6f, 0x40, 0xd6, 0x76, 0xfc, 0x19, 0xfb, 0xce, 0x34, 0x46, 0x45, 0xe5, 0x79, 0x48, 0x63, 0x0e, 0xe9, 0x20, 0x2a,\n\t0x89, 0xa8, 0x83, 0x40, 0xd2, 0x4e, 0xd5, 0x41, 0x20, 0xc7, 0xb0, 0x4e, 0xd2, 0x41, 0x52, 0x34, 0x86, 0x4a, 0x08, 0x7f, 0xf1, 0x4b, 0x90, 0x47, 0xfd, 0x5b, 0x65, 0x33, 0x6b, 0xd9, 0x4a, 0xf0, 0xc8, 0xc9, 0xe3, 0xc7, 0x8f, 0x53, 0x67, 0xa2, 0x79, 0xaf, 0x2b, 0x58, 0x3a, 0x43, 0x32, 0x0f, 0xac, 0xff, 0xfa, 0x73, 0x8c, 0x0f, 0x09, 0xe9, 0xe4, 0xc0, 0xf8, 0x90, 0x05, 0x89, 0x5c, 0x3b, 0x64, 0xaa, 0x51, 0x41, 0x7a, 0x89, 0xc9, 0x40, 0x2b, 0x30, 0xba, 0x57, 0xba, 0x02, 0xa2, 0xd7, 0x0a, 0xea, 0x07, 0x33, 0xa1, 0x7e, 0x60, 0x26, 0x9a, 0x2e, 0x93, 0x27, 0xa9, 0x1f, 0x18, 0xdf, 0xe6, 0x5d, 0x97, 0xef, 0x62, 0x45, 0xa6, 0x16, 0xfc, 0x67, 0x69, 0x7f, 0xc2, 0x1b, 0xa8, 0x9d, 0x5f, 0x54, 0xd4, 0x5d, 0x9f, 0x23, 0x57, 0x45, 0xc2, 0x4b, 0x55, 0xb3, 0x77, 0xdc, 0xb5, 0x60, 0xe1,\n\t0xc9, 0x0d, 0xb5, 0xb9, 0x9d, 0x2b, 0x2a, 0xf8, 0x63, 0x59, 0xf3, 0x02, 0x3f, 0xf6, 0x3b, 0x36, 0xd5, 0xe9, 0xa2, 0x1a, 0xf0, 0xf3, 0xd2, 0xe5, 0xa3, 0xab, 0x2a, 0x2b, 0xfa, 0x2a, 0x1c, 0x8e, 0x78, 0x73, 0x24, 0x60, 0x91, 0x68, 0x86, 0x6e, 0x19, 0x29, 0x42, 0x81, 0x1f, 0xb3, 0x0e, 0xed, 0xd8, 0x58, 0xc1, 0x1f, 0x56, 0xa8, 0x30, 0x7f, 0xed, 0x84, 0x73, 0xc3, 0x0e, 0xfb, 0x50, 0x8b, 0x6a, 0xc2, 0xab, 0xa1, 0xfe, 0x61, 0x13, 0xf4, 0x8f, 0xa4, 0xbe, 0x01, 0x25, 0xad, 0x98, 0x44, 0x24, 0x8e, 0xf2, 0x4a, 0xd0, 0x5a, 0x5e, 0x9a, 0x9f, 0x97, 0x9b, 0x13, 0xf0, 0x99, 0x0c, 0x3e, 0x56, 0xae, 0x4f, 0xcb, 0x24, 0x22, 0xbf, 0xb3, 0xe6, 0x11, 0xdc, 0xa1, 0x46, 0x6d, 0x5f, 0x70, 0x62, 0x75, 0x95, 0xa7, 0x7a, 0x7e, 0xc9, 0xa1, 0x6b, 0x5a, 0xaf, 0xfa, 0xc1, 0xe0, 0xda, 0xbb, 0xd7,\n\t0xb5, 0x58, 0xe6, 0xb9, 0xab, 0x54, 0xea, 0x60, 0xed, 0x60, 0x4b, 0xd3, 0xca, 0x26, 0x9f, 0xad, 0xe3, 0xf0, 0x9a, 0xfe, 0x2b, 0xdb, 0xbd, 0xbe, 0x1a, 0x38, 0x15, 0x7a, 0x70, 0xaf, 0x43, 0xb4, 0x1e, 0xf5, 0x24, 0xb6, 0xf8, 0xe0, 0xec, 0x86, 0xe5, 0xb3, 0x8a, 0x35, 0x81, 0x87, 0xf7, 0x0d, 0xdf, 0xb5, 0xba, 0xbc, 0x78, 0xf0, 0xda, 0x39, 0x3e, 0x95, 0xd2, 0xee, 0x68, 0xa9, 0xcb, 0xc9, 0x6d, 0xe9, 0x8f, 0x96, 0x2c, 0xac, 0x0b, 0x1c, 0x01, 0xbe, 0x44, 0x4f, 0xbc, 0xbc, 0xa7, 0xdc, 0x2e, 0xd2, 0x00, 0xce, 0x5d, 0x2d, 0x1c, 0xb3, 0x4e, 0x38, 0xf7, 0x19, 0xc2, 0x40, 0x54, 0x24, 0x4a, 0x51, 0xb4, 0x85, 0x56, 0x82, 0xb5, 0x47, 0xac, 0x61, 0x08, 0x41, 0x7e, 0x43, 0x90, 0xbf, 0xe3, 0xa4, 0xae, 0x21, 0xb2, 0x95, 0x65, 0x09, 0x82, 0x35, 0xb0, 0x06, 0xbd, 0x0e, 0x25, 0x5c, 0x42,\n\t0x26, 0xcf, 0x10, 0x8c, 0xa8, 0x6a, 0xc4, 0xa7, 0xd3, 0x35, 0xde, 0xa2, 0x18, 0x5e, 0x46, 0x2d, 0x37, 0xe8, 0xee, 0x7b, 0x78, 0xec, 0x1a, 0x83, 0x83, 0xd1, 0x91, 0x67, 0x7f, 0x44, 0x2a, 0xc9, 0x3c, 0x7b, 0x8d, 0x77, 0xac, 0x63, 0x2d, 0x67, 0xe2, 0x8f, 0x80, 0x75, 0x66, 0xed, 0x10, 0x75, 0xfb, 0x45, 0x5c, 0xcb, 0x73, 0x39, 0xa4, 0xbf, 0x14, 0xd7, 0x9d, 0x81, 0x32, 0x27, 0xe0, 0x27, 0x49, 0x1a, 0x2a, 0x1b, 0x68, 0x00, 0x92, 0xa9, 0xd0, 0xb0, 0xbd, 0x24, 0x81, 0x91, 0x9f, 0x70, 0x3e, 0xfc, 0x60, 0x2a, 0x15, 0x1a, 0x0e, 0x84, 0x57, 0x1b, 0xf2, 0x06, 0x42, 0x6e, 0xa4, 0xfd, 0x4d, 0xd5, 0x36, 0xd2, 0x60, 0x9e, 0x10, 0xd1, 0x27, 0x94, 0x8d, 0x8d, 0xab, 0x7a, 0xd7, 0x9c, 0xde, 0x58, 0x8e, 0x56, 0x5a, 0xcd, 0xc6, 0xa5, 0xdd, 0x9e, 0x0a, 0xad, 0x4b, 0x5f, 0xd8, 0x38, 0x50,\n\t0x3b, 0x73, 0x63, 0x67, 0x24, 0xd0, 0xba, 0xae, 0x75, 0xf9, 0x96, 0xed, 0x1b, 0xc9, 0x47, 0x63, 0x55, 0x7c, 0x0b, 0x75, 0x95, 0xb1, 0x6e, 0xe3, 0xc9, 0x05, 0xeb, 0x9e, 0xbe, 0x6a, 0x86, 0x25, 0x52, 0xe2, 0x9c, 0x6b, 0x73, 0x06, 0x9c, 0xb9, 0x5d, 0x5b, 0x66, 0xd6, 0x2c, 0x6b, 0x0e, 0x06, 0x7c, 0xe4, 0x7d, 0xf3, 0xb2, 0x62, 0x82, 0x8c, 0x5e, 0x06, 0xdb, 0x58, 0x81, 0xe3, 0xd6, 0x10, 0x37, 0x80, 0x14, 0xec, 0x9d, 0xc2, 0xcd, 0x34, 0x84, 0xc6, 0x37, 0x55, 0x3a, 0x43, 0x09, 0x81, 0xc5, 0x33, 0x5d, 0xc1, 0x49, 0xc7, 0x9e, 0x56, 0x15, 0x64, 0x1d, 0x26, 0x3b, 0xd4, 0x0e, 0xcd, 0x98, 0x47, 0x6b, 0x63, 0x4e, 0x74, 0x07, 0x72, 0xb9, 0x0b, 0x4b, 0xed, 0x21, 0xfa, 0x90, 0x2d, 0x57, 0x67, 0xd3, 0xee, 0x17, 0xf4, 0x45, 0x28, 0x7e, 0x68, 0x0e, 0xce, 0x55, 0x0e, 0xae, 0x38, 0xc8,\n\t0x41, 0x75, 0x82, 0x7c, 0x82, 0x67, 0xa0, 0xbe, 0x3f, 0x98, 0x74, 0xa5, 0xad, 0x10, 0x2d, 0x88, 0xd9, 0x90, 0x03, 0x4d, 0x2b, 0x9a, 0xe2, 0x97, 0x97, 0x4c, 0xc1, 0x1b, 0x76, 0x37, 0x2c, 0x9f, 0x19, 0x08, 0x37, 0x0f, 0x57, 0x56, 0x2f, 0x6b, 0x0e, 0x81, 0x6b, 0x82, 0x9e, 0xf8, 0xfe, 0x96, 0x8e, 0x1b, 0x57, 0xd7, 0x36, 0x5e, 0xf9, 0xd8, 0xf2, 0xd1, 0x87, 0xb7, 0xd4, 0x1a, 0x23, 0x95, 0x41, 0xfe, 0x7e, 0x55, 0xcc, 0xf3, 0x38, 0xf5, 0xef, 0xfd, 0x37, 0x44, 0x5b, 0x06, 0xe3, 0x35, 0xa3, 0x33, 0x83, 0xe1, 0xe6, 0xa5, 0xbc, 0xa4, 0x30, 0x3f, 0x9c, 0x15, 0x1f, 0xbd, 0x6d, 0x68, 0xe1, 0x7d, 0xdb, 0x67, 0xd4, 0x6f, 0x3f, 0x3d, 0x52, 0xbd, 0x6e, 0xe5, 0x68, 0x31, 0xcf, 0xe9, 0x2c, 0x98, 0x27, 0x97, 0x8d, 0x1b, 0xc8, 0x25, 0x90, 0x31, 0x48, 0xc0, 0x7d, 0xf0, 0xb7, 0x03, 0xe5,\n\t0x14, 0x91, 0x3f, 0x1a, 0x77, 0xa4, 0x72, 0x8a, 0x06, 0xc7, 0x1d, 0x64, 0x09, 0xb8, 0x08, 0xcf, 0xdf, 0x4f, 0x50, 0xc2, 0x79, 0x90, 0x7e, 0xbe, 0x11, 0x9e, 0x6f, 0xc3, 0xf7, 0x3f, 0x40, 0x90, 0xd3, 0x9c, 0xaf, 0x85, 0xcf, 0x9f, 0x81, 0xcf, 0x3f, 0x48, 0x80, 0x69, 0xce, 0xbb, 0xe0, 0xfd, 0xc3, 0xe0, 0x6b, 0x78, 0xfe, 0xa1, 0xe4, 0xf3, 0x27, 0xbd, 0xbf, 0x03, 0xde, 0x5f, 0x89, 0xcf, 0x3f, 0x9c, 0x6c, 0xdf, 0xa4, 0xfb, 0xdb, 0xe1, 0xf9, 0x79, 0xf8, 0xfc, 0xe9, 0xe4, 0xf3, 0x27, 0xdd, 0x3f, 0x0f, 0x3e, 0x7f, 0x0e, 0x3e, 0x7f, 0x66, 0xda, 0xf6, 0xb7, 0xc1, 0xfb, 0x3b, 0x70, 0xfb, 0x1e, 0x49, 0x3e, 0x9f, 0x4a, 0x3f, 0x3f, 0x0b, 0xde, 0x5f, 0x87, 0xcf, 0xff, 0x60, 0x7c, 0x7c, 0x9a, 0xe7, 0x77, 0x8f, 0xef, 0x20, 0x1b, 0xc0, 0x76, 0x4a, 0x42, 0x9f, 0x9b, 0xb6, 0x7d, 0x2b,\n\t0x89, 0x26, 0x32, 0x8f, 0x78, 0x0c, 0x9e, 0x7f, 0x61, 0xfa, 0xf3, 0xe3, 0xff, 0x24, 0xf3, 0x80, 0x02, 0x9e, 0x7f, 0x71, 0x5a, 0xfa, 0x97, 0xf3, 0x77, 0x01, 0x2b, 0xb9, 0x04, 0x9e, 0xff, 0xaf, 0x69, 0xdb, 0x5f, 0x08, 0xcf, 0xeb, 0xf0, 0xf9, 0x5f, 0x8f, 0xf3, 0x53, 0xcf, 0x63, 0x99, 0xf8, 0x25, 0x1c, 0xdf, 0x0f, 0xb0, 0x4c, 0x3c, 0xf2, 0x8d, 0xfb, 0x78, 0xc5, 0x74, 0xa7, 0x86, 0x2e, 0xbf, 0xc5, 0x17, 0xee, 0x52, 0x5d, 0xee, 0xae, 0xcb, 0xec, 0xfe, 0xff, 0x0f, 0xfb, 0x7f, 0x72, 0x49, 0x76, 0xcb, 0x70, 0x59, 0xe9, 0x50, 0x73, 0x24, 0xd2, 0x3c, 0x54, 0x5a, 0x36, 0xdc, 0x92, 0x7d, 0xbd, 0xce, 0x57, 0x60, 0xb7, 0xe7, 0x79, 0x75, 0x28, 0x0b, 0xcf, 0x9a, 0xef, 0x37, 0x80, 0x55, 0x03, 0xd7, 0xf5, 0x47, 0xa3, 0xfd, 0xd7, 0x0d, 0x24, 0x3f, 0xdb, 0x87, 0xca, 0x0d, 0x86, 0xf2,\n\t0xa1, 0xf6, 0xb6, 0xe1, 0x32, 0xa3, 0xb1, 0x6c, 0x18, 0xf3, 0x81, 0x01, 0x48, 0x88, 0x18, 0xf9, 0xbe, 0xa0, 0xdf, 0x28, 0x58, 0x86, 0xba, 0xac, 0x01, 0x00, 0xaa, 0x37, 0xa6, 0x09, 0xe1, 0x5b, 0xc8, 0x09, 0xdb, 0xff, 0x62, 0xc8, 0x3e, 0x63, 0xfc, 0xe0, 0x4d, 0xcc, 0xb0, 0xd6, 0x27, 0x8d, 0xfc, 0x71, 0xd3, 0x82, 0x05, 0x0b, 0xc0, 0xdd, 0x39, 0x9d, 0x6a, 0x85, 0xbc, 0xe2, 0xf9, 0xb1, 0x2b, 0x05, 0x5e, 0x53, 0x0f, 0xdf, 0xd1, 0x02, 0xe9, 0x9c, 0x85, 0xb0, 0x04, 0x8d, 0xb0, 0xe7, 0xc1, 0xe4, 0xde, 0x1f, 0xbb, 0xf2, 0x06, 0x27, 0x8b, 0x5c, 0xbb, 0x95, 0x53, 0x43, 0x91, 0x9b, 0x05, 0xc2, 0x93, 0x44, 0x2e, 0xf2, 0x4b, 0x09, 0xd9, 0xfd, 0x53, 0x04, 0xae, 0x1a, 0x09, 0x5c, 0xd2, 0x66, 0x34, 0x8d, 0x7d, 0xa5, 0xc8, 0x78, 0xb7, 0xa0, 0xae, 0x38, 0x2b, 0x12, 0xcb, 0x50, 0x58,\n\t0xed, 0xed, 0x92, 0x68, 0x7d, 0x6f, 0x51, 0xbc, 0xab, 0xc2, 0x6d, 0xce, 0x8a, 0xdb, 0x6f, 0x31, 0xe5, 0xe9, 0xf7, 0x9a, 0xf5, 0x73, 0x73, 0x55, 0x0e, 0xd5, 0x6f, 0xf3, 0x96, 0x17, 0xe6, 0x15, 0x45, 0x83, 0x5a, 0x35, 0x93, 0x11, 0xef, 0x8c, 0x59, 0x9d, 0xc5, 0xed, 0x39, 0xa1, 0x86, 0xaa, 0x72, 0xc7, 0xed, 0x12, 0xa9, 0x90, 0x07, 0xf6, 0x25, 0xd9, 0x08, 0xdb, 0x5b, 0x42, 0xfc, 0x47, 0x42, 0xae, 0x84, 0xf2, 0xd5, 0x84, 0xe5, 0x6b, 0xaa, 0x9e, 0x14, 0x01, 0x9b, 0x97, 0xbe, 0xbd, 0x17, 0x84, 0xec, 0x6a, 0x90, 0x9c, 0x29, 0x97, 0xbd, 0x44, 0x30, 0xd0, 0x2b, 0xbf, 0xfd, 0x29, 0xaa, 0x6f, 0x7b, 0xca, 0x37, 0x3e, 0x00, 0xe3, 0x03, 0xc9, 0x7c, 0x9c, 0x29, 0x3b, 0x7b, 0x72, 0xda, 0xb0, 0xc4, 0x70, 0x79, 0x49, 0x3f, 0x41, 0xdc, 0x60, 0x97, 0x24, 0x5a, 0xdb, 0x95, 0x5f, 0x34,\n\t0xb7, 0xc2, 0xb5, 0x7e, 0x6f, 0xa4, 0xb1, 0x3f, 0xaf, 0x64, 0x6e, 0x75, 0x34, 0xb3, 0xd2, 0x94, 0x25, 0x65, 0x32, 0x6d, 0x59, 0x4e, 0x5b, 0xb6, 0x43, 0x9d, 0x19, 0xa8, 0xca, 0xe9, 0xaa, 0x8f, 0x47, 0xa3, 0x31, 0xa5, 0xc2, 0x64, 0x23, 0x31, 0x15, 0x1d, 0x85, 0x0d, 0xc1, 0xdd, 0xd1, 0xc0, 0xe6, 0xd2, 0xae, 0x52, 0xbb, 0x29, 0x6f, 0x66, 0x81, 0x45, 0x2e, 0xd7, 0xc8, 0xed, 0x56, 0xad, 0xc6, 0x1e, 0xd0, 0xd9, 0xc3, 0x56, 0xe5, 0x22, 0x50, 0x52, 0x90, 0x9b, 0x0f, 0x27, 0x8f, 0x8a, 0x11, 0x72, 0xf7, 0xe1, 0xda, 0xfb, 0x1d, 0xb6, 0x23, 0x40, 0x99, 0x8e, 0xed, 0x08, 0xe2, 0xac, 0x40, 0x86, 0x84, 0x49, 0x82, 0x1d, 0xcb, 0xf4, 0xcb, 0x9a, 0x0f, 0x62, 0x45, 0xc5, 0x94, 0x20, 0xd2, 0x91, 0xdf, 0x46, 0x14, 0xe9, 0x60, 0x1f, 0xfb, 0x57, 0xf0, 0x33, 0x95, 0xaa, 0x6d, 0x13, 0xff,\n\t0x6b, 0x9d, 0x81, 0x52, 0x80, 0x79, 0x57, 0x03, 0xf5, 0xfb, 0x91, 0x42, 0xfe, 0xc5, 0x26, 0x45, 0xe6, 0xe9, 0xd3, 0x5c, 0x46, 0x15, 0x78, 0x83, 0x2f, 0xc4, 0x78, 0x20, 0x5f, 0x92, 0x95, 0xb0, 0x1d, 0x59, 0xc4, 0xa7, 0x09, 0x95, 0x17, 0xd0, 0x84, 0x07, 0x90, 0xb4, 0x1a, 0xca, 0xa5, 0x64, 0x3c, 0xa7, 0x37, 0x0d, 0xe0, 0x04, 0x21, 0x86, 0x0f, 0xa6, 0xa4, 0xbb, 0x28, 0xd3, 0x27, 0xc6, 0xfd, 0x5b, 0x2f, 0x9d, 0x18, 0xff, 0xef, 0xf8, 0x54, 0xd5, 0x77, 0x7d, 0xea, 0x77, 0x7a, 0x20, 0x9e, 0x17, 0x72, 0xaf, 0x2e, 0xe0, 0xd3, 0x09, 0x0a, 0x88, 0x36, 0x9e, 0x5e, 0x4f, 0x75, 0x12, 0xcc, 0xe4, 0x84, 0xb1, 0x23, 0x02, 0xc6, 0x22, 0x59, 0x65, 0x3d, 0xe5, 0x8e, 0x70, 0xf3, 0x50, 0x45, 0xc3, 0x9a, 0x40, 0x96, 0x5a, 0x9f, 0x61, 0x75, 0x67, 0xbb, 0xcc, 0x51, 0xaf, 0xbe, 0xba, 0xc2,\n\t0x12, 0xb3, 0x74, 0x55, 0x83, 0xd5, 0xfe, 0xec, 0x9f, 0x82, 0xd7, 0x65, 0xae, 0xb2, 0x8e, 0xbc, 0xf2, 0x81, 0xc6, 0x40, 0xdc, 0x57, 0xa1, 0xcd, 0xd4, 0x64, 0xaa, 0x5d, 0x79, 0xee, 0xd2, 0x2a, 0xa5, 0xd4, 0x04, 0xd6, 0x95, 0xdb, 0x83, 0x02, 0xcf, 0x6d, 0x83, 0xf4, 0x9e, 0x0b, 0xe9, 0xad, 0x26, 0xb2, 0x89, 0xe7, 0x9e, 0xd4, 0x02, 0xa1, 0x40, 0x07, 0x22, 0xb4, 0x05, 0xb6, 0x97, 0xa4, 0x97, 0x8a, 0xa6, 0x8e, 0xa1, 0x94, 0xa9, 0x63, 0x35, 0x95, 0xa4, 0xef, 0x24, 0xbc, 0xe2, 0x89, 0x0b, 0x86, 0xa8, 0x24, 0x55, 0x2f, 0x73, 0x81, 0xf0, 0x04, 0xd5, 0x37, 0x3f, 0xe1, 0x1b, 0x6e, 0xc6, 0x74, 0xe3, 0x00, 0x91, 0x9d, 0xe5, 0x76, 0x1a, 0xf5, 0x32, 0x09, 0xa1, 0x06, 0xea, 0x09, 0x7b, 0xcb, 0x04, 0x20, 0xf2, 0xa5, 0xd6, 0x16, 0xc1, 0x99, 0x0e, 0x66, 0xdb, 0x72, 0x3c, 0xda, 0x44,\n\t0xa9, 0x23, 0xcf, 0xcd, 0xd5, 0x94, 0xe9, 0x72, 0x0d, 0xb6, 0x86, 0x50, 0xa0, 0xa5, 0xdc, 0x1f, 0x68, 0x18, 0x28, 0xaf, 0x58, 0x54, 0xe7, 0xed, 0x7a, 0x48, 0x16, 0x34, 0x6f, 0x1f, 0xd6, 0xba, 0xa3, 0xd6, 0x8a, 0x5a, 0xad, 0x27, 0xc7, 0x52, 0xdc, 0x08, 0x6e, 0x34, 0xe7, 0x98, 0x0d, 0x56, 0x73, 0x51, 0x67, 0x49, 0x61, 0x5f, 0x5d, 0x28, 0xd0, 0xb0, 0xa8, 0x6c, 0xc5, 0xda, 0x0f, 0x54, 0x1a, 0xa1, 0x96, 0x1b, 0x24, 0xe4, 0x2c, 0x48, 0x43, 0x2d, 0xe1, 0x4d, 0xb8, 0x00, 0x26, 0x21, 0x25, 0x46, 0x4f, 0x2e, 0x4e, 0xb1, 0x6b, 0x2d, 0xa1, 0xd5, 0x86, 0xd3, 0xf4, 0x37, 0x6a, 0xc2, 0xba, 0x42, 0xce, 0x92, 0x30, 0xfc, 0xbf, 0x68, 0x99, 0xda, 0xc0, 0xad, 0x04, 0x5a, 0x9d, 0x9e, 0xff, 0xa1, 0x52, 0x47, 0xfe, 0xae, 0x45, 0x65, 0x52, 0x8c, 0xbd, 0x2e, 0xe5, 0x54, 0x52, 0xd2, 0x14,\n\t0xb0, 0xea, 0x95, 0x4b, 0x70, 0xfc, 0x07, 0x1a, 0xaf, 0x0e, 0xc8, 0x0b, 0x33, 0x10, 0xaa, 0x12, 0xf1, 0x5e, 0x42, 0x6e, 0x86, 0x9a, 0x6e, 0x0e, 0x56, 0x77, 0x85, 0x61, 0xb3, 0x5f, 0xde, 0xdc, 0xb2, 0x9a, 0x4e, 0x8e, 0xdc, 0x37, 0x5c, 0x34, 0x44, 0x27, 0x47, 0xef, 0x5b, 0x9f, 0xa4, 0xfa, 0xf6, 0x27, 0x7d, 0xcb, 0x43, 0xf0, 0x48, 0x1a, 0xd5, 0x2a, 0x40, 0x14, 0xc7, 0x82, 0x7e, 0xa3, 0x5e, 0x65, 0x57, 0xdb, 0xe1, 0x78, 0x66, 0x80, 0x0c, 0xc1, 0x06, 0x14, 0x4f, 0x96, 0x47, 0x85, 0xc3, 0x39, 0xa9, 0xaa, 0xaf, 0xf1, 0x1b, 0xcc, 0x3f, 0xa0, 0xbd, 0xbc, 0x84, 0x73, 0x66, 0x99, 0xf3, 0x6b, 0x4a, 0xca, 0x2c, 0x01, 0xb3, 0x32, 0x2f, 0x16, 0x2b, 0xcc, 0xb0, 0x04, 0x47, 0x6b, 0x2b, 0xfc, 0xf5, 0x8b, 0x4a, 0x4b, 0x17, 0xd5, 0x05, 0x2a, 0x6a, 0x0b, 0x0b, 0x3c, 0x55, 0xf3, 0x0a,\n\t0x0b, 0xbb, 0x2a, 0x3d, 0x05, 0xc3, 0x55, 0x79, 0xce, 0x2c, 0xab, 0xb2, 0xb0, 0x32, 0xaf, 0x8a, 0x34, 0x64, 0x5a, 0xbc, 0x9a, 0x82, 0xd2, 0xd2, 0x02, 0x8d, 0xd7, 0x92, 0x39, 0x66, 0xec, 0xad, 0xca, 0x9f, 0x55, 0xe2, 0x74, 0x96, 0xcc, 0xca, 0xaf, 0xea, 0x35, 0x1a, 0x3b, 0x4b, 0xb2, 0x66, 0xa2, 0x58, 0xb5, 0x99, 0x59, 0x25, 0x02, 0xee, 0x0c, 0xfc, 0x97, 0xac, 0x87, 0x63, 0xa1, 0x80, 0xdc, 0x2a, 0x98, 0xf0, 0xa9, 0x05, 0x5d, 0x3a, 0x65, 0xe6, 0x11, 0x75, 0x6a, 0x51, 0x93, 0x0e, 0xf8, 0xb0, 0x26, 0xad, 0x4d, 0xba, 0xf5, 0x60, 0xaf, 0x50, 0x9d, 0x4e, 0x76, 0xaa, 0x1a, 0x2d, 0x04, 0x7f, 0xbc, 0x5d, 0x51, 0x52, 0x92, 0xa8, 0x2d, 0x28, 0x49, 0x6c, 0x51, 0x3b, 0x55, 0xb9, 0xe5, 0xc1, 0x96, 0x72, 0x9f, 0xaf, 0x6e, 0x41, 0x69, 0x69, 0x5f, 0xc2, 0x93, 0x61, 0xf6, 0x19, 0x8f,\n\t0xca, 0x03, 0xa6, 0x5d, 0x24, 0x53, 0x56, 0x96, 0x28, 0x8c, 0x57, 0x55, 0xf1, 0x2f, 0xe8, 0x3c, 0x9c, 0xc9, 0x16, 0x6f, 0x2b, 0xc8, 0x9e, 0x53, 0x13, 0x74, 0x57, 0x75, 0xc5, 0x03, 0x75, 0xd5, 0x95, 0xee, 0xdf, 0xe0, 0xe9, 0x49, 0x00, 0xfe, 0x28, 0x6c, 0xca, 0x7e, 0xb8, 0xb7, 0x10, 0xf3, 0xa8, 0x41, 0x72, 0x57, 0x21, 0xe4, 0x7d, 0x07, 0x53, 0x79, 0xdf, 0x67, 0x75, 0x79, 0xae, 0x39, 0x54, 0x5c, 0x97, 0xef, 0x9d, 0x5b, 0xe6, 0x31, 0x31, 0xf3, 0x5d, 0x1e, 0x41, 0x6f, 0x5b, 0x38, 0xfe, 0x25, 0xb3, 0x91, 0xb9, 0x87, 0x08, 0x82, 0x47, 0xc9, 0x7d, 0x18, 0x39, 0xe0, 0x01, 0xc2, 0x42, 0x3e, 0x0f, 0xa0, 0x9e, 0x4c, 0xe5, 0xc2, 0xdf, 0x02, 0x72, 0xc1, 0xf3, 0x29, 0x3d, 0xaf, 0x1f, 0x5e, 0xdf, 0x29, 0x5e, 0xbf, 0x47, 0xbc, 0xde, 0x84, 0xaf, 0x7f, 0x98, 0xd2, 0x4d, 0xbd, 0x1e,\n\t0x52, 0x6b, 0x90, 0x38, 0x4d, 0x07, 0xe8, 0x1b, 0x10, 0xfe, 0x11, 0xe4, 0x9b, 0x34, 0x05, 0xe8, 0x79, 0x0c, 0x82, 0xc2, 0x42, 0x50, 0xa1, 0x28, 0x36, 0x00, 0xe9, 0x22, 0x34, 0x68, 0xe3, 0x26, 0x92, 0x83, 0xc4, 0x10, 0x06, 0x84, 0x02, 0x43, 0x07, 0xf8, 0x2b, 0x4e, 0xf2, 0xab, 0xc1, 0x8d, 0x27, 0xc1, 0x51, 0x72, 0x1e, 0xdf, 0x0d, 0x1e, 0x3c, 0x06, 0xee, 0xe7, 0x71, 0x82, 0x1f, 0xfc, 0x4d, 0x9d, 0x27, 0xff, 0xf6, 0x6d, 0x79, 0xd9, 0x47, 0xa9, 0x25, 0x17, 0xbf, 0x4f, 0xfe, 0xed, 0x18, 0x6e, 0xcb, 0x4e, 0xe2, 0x2d, 0x5a, 0x49, 0xf7, 0xc3, 0xb6, 0xb0, 0x8f, 0xb3, 0x28, 0x3f, 0xdf, 0x2f, 0x03, 0x41, 0x19, 0x28, 0x96, 0x01, 0xa3, 0x0c, 0x50, 0xf7, 0xf0, 0x77, 0xf3, 0x27, 0x97, 0x81, 0x01, 0xfe, 0xf4, 0x08, 0x98, 0x07, 0xe6, 0x2c, 0xe3, 0x1f, 0x01, 0x0b, 0xdf, 0x06, 0x8b,\n\t0xf8, 0x93, 0xa3, 0x60, 0x00, 0xcc, 0x1d, 0xe5, 0x1f, 0x06, 0x73, 0x46, 0xf9, 0x47, 0xf8, 0xbb, 0x85, 0xfc, 0x84, 0x25, 0xc4, 0x53, 0xb4, 0x9f, 0xbe, 0x1a, 0x7e, 0x33, 0x12, 0x11, 0x22, 0x3b, 0x11, 0x46, 0xea, 0x55, 0x32, 0x11, 0x98, 0x46, 0xd9, 0xf0, 0x53, 0x32, 0x3b, 0xa0, 0xb6, 0xe9, 0x17, 0x7a, 0x88, 0xda, 0x05, 0xa6, 0x44, 0x5d, 0x72, 0x53, 0x7e, 0x2f, 0xa1, 0x5e, 0xb8, 0x58, 0x09, 0x16, 0x4c, 0x85, 0x3d, 0x99, 0xfa, 0x1b, 0xf6, 0x0c, 0x9c, 0xb1, 0x09, 0x07, 0x6c, 0x22, 0x0e, 0xc7, 0xd8, 0xdc, 0x29, 0x07, 0xf0, 0x7c, 0x3e, 0x0a, 0xce, 0x50, 0xe7, 0xa9, 0xe3, 0x38, 0x67, 0xdf, 0x93, 0x70, 0x8a, 0xad, 0x5d, 0x7c, 0x09, 0xe5, 0x92, 0x89, 0xfb, 0x28, 0x94, 0x24, 0x49, 0x3f, 0x4c, 0xc3, 0x9a, 0x63, 0xe0, 0xaf, 0x22, 0x86, 0xe5, 0x31, 0xe2, 0x2c, 0xf5, 0x39, 0xbd,\n\t0x07, 0xb2, 0xbd, 0x75, 0x02, 0xcb, 0xc9, 0x22, 0x24, 0x2c, 0x2b, 0x59, 0x8a, 0x6d, 0xfd, 0x23, 0x52, 0xc0, 0xca, 0x65, 0x24, 0x94, 0x8c, 0xcc, 0x12, 0x1a, 0xe0, 0xc7, 0x0b, 0x3a, 0x27, 0x25, 0x94, 0x01, 0x4d, 0x84, 0xe0, 0xc5, 0x12, 0xc1, 0x7b, 0xf1, 0xcd, 0x97, 0xe2, 0xaa, 0x9f, 0x88, 0xb7, 0x26, 0x03, 0x47, 0x38, 0x1c, 0x38, 0x82, 0x00, 0xbc, 0x24, 0x5e, 0x84, 0x5e, 0x86, 0xff, 0x16, 0x4a, 0x0a, 0xf5, 0xe4, 0xcf, 0xfb, 0xc1, 0xb5, 0x7c, 0xce, 0xa6, 0xeb, 0x36, 0xf1, 0x63, 0xa0, 0xb9, 0x9f, 0x9f, 0x0f, 0xfe, 0xb1, 0xf6, 0xba, 0xb5, 0x7f, 0xa3, 0xc0, 0xf3, 0xc7, 0xbe, 0xf8, 0xe2, 0xd8, 0xf3, 0xc7, 0xfe, 0xf1, 0x8f, 0x63, 0x88, 0x06, 0x0f, 0x81, 0xcd, 0xd4, 0xef, 0xa8, 0xd7, 0x70, 0x16, 0xc3, 0x91, 0x04, 0xaa, 0x8c, 0x41, 0x69, 0x91, 0x95, 0x11, 0x25, 0xe9, 0xe4,\n\t0x7a, 0x48, 0x86, 0xa5, 0x9b, 0x05, 0xfc, 0x48, 0x1f, 0x82, 0xc2, 0x02, 0x12, 0x9c, 0xcd, 0x08, 0x1b, 0x27, 0x61, 0x07, 0x65, 0x70, 0x4c, 0xe1, 0x28, 0x2e, 0x4a, 0xda, 0xae, 0x96, 0xa2, 0xfc, 0xe4, 0x48, 0x32, 0x99, 0x3a, 0x75, 0x39, 0xbc, 0x8c, 0x45, 0xa3, 0x3e, 0x71, 0x57, 0x72, 0xf8, 0x7b, 0x13, 0x56, 0xbb, 0x0d, 0x10, 0x45, 0x05, 0x91, 0x70, 0xc0, 0x87, 0x12, 0x18, 0x4c, 0x06, 0x94, 0x33, 0x86, 0x32, 0xc6, 0xe4, 0x62, 0xf4, 0x7c, 0xb1, 0x31, 0x0d, 0xa5, 0x2c, 0x28, 0x88, 0x37, 0xed, 0x65, 0x8e, 0x53, 0x5a, 0x47, 0x49, 0x8e, 0x57, 0x6a, 0xf1, 0x6e, 0xa8, 0x2a, 0x5a, 0x36, 0x34, 0x10, 0x75, 0x94, 0xe6, 0x7a, 0x64, 0x4e, 0xdf, 0xa6, 0xda, 0xd8, 0xe8, 0xd0, 0xa2, 0xec, 0x6f, 0x38, 0x47, 0x0d, 0xa9, 0xf4, 0x26, 0xf9, 0xce, 0xbc, 0x1c, 0x57, 0xd0, 0xad, 0xd2, 0x9b,\n\t0x15, 0x5b, 0x8a, 0x0a, 0xdc, 0x41, 0x37, 0xff, 0xe0, 0x74, 0x47, 0xd1, 0x58, 0x9f, 0x24, 0x3e, 0xa0, 0x1e, 0xa4, 0x17, 0x12, 0x99, 0x70, 0xcd, 0x28, 0x65, 0x28, 0xdf, 0x9e, 0x95, 0x18, 0x8c, 0x8c, 0x03, 0xd8, 0x01, 0x88, 0x09, 0xe2, 0xee, 0xed, 0x70, 0x51, 0x51, 0x18, 0x9c, 0xd6, 0x71, 0x17, 0x3f, 0xa7, 0xe4, 0x9c, 0x8e, 0x3c, 0xa7, 0x57, 0x2a, 0xf5, 0x6f, 0x2b, 0x6c, 0xdc, 0x61, 0x70, 0x7c, 0x16, 0x38, 0x7e, 0x98, 0xb3, 0x89, 0xbe, 0xbc, 0xdf, 0xc3, 0x67, 0xfd, 0x4d, 0x7c, 0x56, 0xa6, 0x80, 0x8f, 0x81, 0x03, 0x76, 0xfd, 0xf1, 0xe2, 0x40, 0xd0, 0x8f, 0x32, 0x71, 0xa9, 0xbf, 0x5d, 0xfc, 0x9c, 0xd3, 0x81, 0xd3, 0xa1, 0x58, 0x2c, 0xc4, 0xcf, 0xd5, 0x71, 0xe4, 0x2f, 0x66, 0xf1, 0x2b, 0xd0, 0x03, 0xde, 0x4e, 0x3d, 0x13, 0xdb, 0x39, 0x66, 0xc1, 0xb5, 0xf7, 0x2c, 0xa4,\n\t0xbe, 0x1a, 0xd5, 0x91, 0x97, 0x4a, 0x48, 0x86, 0xc6, 0x72, 0x68, 0x31, 0x4a, 0xb4, 0x22, 0xd8, 0x4b, 0xa7, 0x35, 0x4d, 0xd3, 0x6a, 0x5a, 0x8d, 0xa6, 0x90, 0x86, 0xcb, 0x94, 0x41, 0x6d, 0xac, 0x18, 0xad, 0x41, 0xfd, 0x04, 0xab, 0x19, 0xa4, 0xce, 0x5d, 0xac, 0xa2, 0xce, 0xf1, 0xab, 0xee, 0x44, 0x40, 0xb8, 0x77, 0x7e, 0x70, 0x8c, 0xfc, 0xfa, 0x18, 0xff, 0x3d, 0x30, 0x7a, 0x0c, 0xac, 0xe7, 0xaf, 0x43, 0x73, 0xe7, 0x2c, 0x31, 0x8b, 0x7a, 0x9e, 0x46, 0xd5, 0xdf, 0xf4, 0x08, 0x51, 0x0a, 0x3e, 0x46, 0xad, 0x62, 0x59, 0xa2, 0x69, 0x7a, 0xd6, 0x83, 0x1f, 0x8f, 0x33, 0x20, 0xd2, 0x29, 0x75, 0x96, 0x92, 0x5f, 0xfc, 0x1c, 0x94, 0xe6, 0xc5, 0x6c, 0x05, 0x46, 0x70, 0xca, 0xa6, 0x41, 0xf4, 0xd2, 0xd8, 0xe0, 0xbb, 0x5e, 0xd6, 0x28, 0x59, 0xb5, 0xfc, 0x45, 0xa5, 0x83, 0xbb, 0x1a,\n\t0xec, 0xe8, 0x04, 0x5b, 0x0f, 0x70, 0x4e, 0x05, 0x7c, 0xe7, 0x4b, 0xf0, 0x9d, 0xbf, 0x9e, 0x78, 0xa7, 0x5e, 0x25, 0x81, 0x93, 0xeb, 0x9b, 0xdf, 0x29, 0x12, 0x14, 0x25, 0x38, 0x0b, 0x14, 0x7d, 0x09, 0xbd, 0x13, 0xfd, 0xd5, 0xd8, 0xc0, 0x29, 0x63, 0x81, 0x2d, 0x96, 0xc7, 0x2f, 0xb0, 0x69, 0xe0, 0x3b, 0xdf, 0xe8, 0xe4, 0xaf, 0xba, 0x9a, 0x73, 0x28, 0x5f, 0x94, 0xab, 0x59, 0xa5, 0xe6, 0x9c, 0xc2, 0xc9, 0x1d, 0x40, 0x63, 0x74, 0x03, 0x88, 0x53, 0x9f, 0x41, 0xbe, 0xca, 0x10, 0x55, 0x62, 0xfd, 0x78, 0xfc, 0xb6, 0x11, 0xbc, 0xb6, 0xe7, 0xa1, 0x8d, 0x4f, 0x2f, 0xf2, 0x29, 0xb5, 0x59, 0x31, 0xd7, 0x45, 0xa9, 0x97, 0x93, 0x8f, 0xf7, 0x3e, 0x89, 0x0a, 0x01, 0xe0, 0x34, 0x4c, 0x0c, 0x82, 0xfb, 0xd9, 0x7d, 0x63, 0x75, 0xd4, 0x20, 0x88, 0x03, 0xe7, 0x31, 0x31, 0xe6, 0xe2, 0x9f,\n\t0xac, 0x99, 0x79, 0x88, 0x50, 0x42, 0xae, 0x99, 0x97, 0x88, 0x1a, 0xf4, 0x24, 0x86, 0x15, 0x07, 0x04, 0x43, 0x02, 0x06, 0x69, 0x54, 0xc9, 0x38, 0xa7, 0x09, 0xc4, 0x28, 0x5d, 0x28, 0xe8, 0xf7, 0xe1, 0xcd, 0x15, 0x10, 0x77, 0xe6, 0x70, 0x97, 0x0a, 0xc4, 0xac, 0x41, 0x23, 0xca, 0x1b, 0x4e, 0x16, 0xca, 0xc3, 0x79, 0x57, 0x46, 0x37, 0xa3, 0xaf, 0xde, 0xf4, 0xc0, 0xb2, 0xa5, 0x0f, 0x6d, 0xaf, 0xa7, 0x8e, 0x5d, 0x5c, 0x39, 0x63, 0xff, 0x73, 0x5b, 0x6e, 0xf9, 0x68, 0xfe, 0xf2, 0xbc, 0xed, 0xb7, 0x3d, 0xbb, 0xee, 0x0c, 0xff, 0xb7, 0x17, 0x97, 0x5f, 0xf1, 0x02, 0x50, 0xdd, 0xfd, 0x08, 0x90, 0x9f, 0x1d, 0xa0, 0x2f, 0x2c, 0xa3, 0xd6, 0x0d, 0x9c, 0xda, 0x54, 0xd7, 0xb0, 0xfd, 0x81, 0x41, 0xcd, 0x38, 0xb1, 0xe0, 0xcc, 0xfe, 0x59, 0x1b, 0xb7, 0xb7, 0x35, 0xac, 0x6a, 0x0d, 0xad,\n\t0x79, 0x11, 0x28, 0x6e, 0x3f, 0x01, 0x32, 0x7e, 0xbe, 0x6e, 0xe3, 0xcf, 0xf9, 0xaf, 0x6e, 0x44, 0x6d, 0xaf, 0x1a, 0xff, 0x84, 0x76, 0x31, 0x67, 0x60, 0xdb, 0x2b, 0x91, 0xcf, 0xb0, 0xb2, 0x2c, 0x37, 0xc7, 0xcd, 0xa0, 0x50, 0x8b, 0x66, 0x3a, 0x09, 0xb0, 0x34, 0xa9, 0xe1, 0x80, 0x88, 0x15, 0x66, 0x85, 0x4c, 0x06, 0x94, 0x22, 0x83, 0xa1, 0xb6, 0xd0, 0x02, 0x46, 0x66, 0xde, 0x00, 0xce, 0x60, 0x64, 0x52, 0xd6, 0x35, 0x56, 0x97, 0x8a, 0xbe, 0x32, 0x0a, 0x88, 0x84, 0x95, 0x28, 0xb9, 0x91, 0xd2, 0x94, 0x6d, 0x18, 0x6e, 0xd3, 0x8e, 0xfe, 0x60, 0x57, 0x43, 0xc9, 0xc5, 0x8b, 0x59, 0x9d, 0x41, 0x65, 0xf1, 0xac, 0x65, 0xdb, 0x0f, 0xb7, 0x56, 0xf5, 0x55, 0xd8, 0x17, 0x3e, 0xfc, 0xc9, 0x31, 0xa0, 0xf5, 0xc5, 0x3c, 0xbe, 0x86, 0xea, 0x62, 0xc3, 0x5d, 0xe6, 0xee, 0x0d, 0x87, 0xdb,\n\t0x6b, 0x57, 0xb4, 0x84, 0x5c, 0xd5, 0x6e, 0xc6, 0x38, 0xff, 0xfb, 0x6f, 0x6c, 0x0d, 0x0f, 0xaf, 0xdf, 0x55, 0x57, 0x5d, 0x3f, 0xd6, 0x25, 0xd5, 0x2a, 0x46, 0x7f, 0xfe, 0xe8, 0xb1, 0x15, 0xe5, 0x91, 0x99, 0x83, 0x25, 0x83, 0x8f, 0xdd, 0xb2, 0xbb, 0x40, 0x61, 0x54, 0xac, 0x3e, 0xda, 0xe3, 0xf3, 0x54, 0x75, 0x17, 0x85, 0x5a, 0xf6, 0x2e, 0x29, 0x89, 0x6f, 0xfd, 0x8f, 0xeb, 0x75, 0x52, 0xb5, 0x14, 0xc9, 0xb5, 0x51, 0xe2, 0x4b, 0xa6, 0x8b, 0xba, 0x0f, 0xdb, 0x69, 0x3a, 0x88, 0xb6, 0x44, 0x73, 0x4b, 0xb1, 0x59, 0x4d, 0xa3, 0x68, 0x12, 0x89, 0x1c, 0xee, 0x7a, 0x84, 0x6a, 0x75, 0x32, 0x52, 0x4a, 0x21, 0xcb, 0x77, 0x37, 0xfe, 0x42, 0x30, 0x7d, 0x2c, 0x60, 0x08, 0xa6, 0x23, 0x1c, 0x42, 0x1e, 0xbf, 0x19, 0x0d, 0x95, 0xe5, 0x85, 0xf9, 0xa1, 0x8e, 0x70, 0x47, 0xba, 0xdf, 0x4f,\n\t0x91, 0x96, 0x22, 0x84, 0x19, 0x99, 0x83, 0x72, 0xa3, 0xfe, 0x4e, 0xa4, 0x75, 0xa6, 0x03, 0x3e, 0x07, 0xd3, 0x71, 0x19, 0x51, 0xfe, 0x34, 0x45, 0xeb, 0x10, 0xde, 0x9b, 0x35, 0xa7, 0xc2, 0xe3, 0x2d, 0x8f, 0xe5, 0x99, 0x4c, 0x79, 0xb1, 0xf2, 0xb1, 0x9f, 0xa4, 0xbe, 0x7a, 0x3d, 0x95, 0x39, 0xf0, 0x64, 0x25, 0x79, 0x63, 0xf5, 0xfa, 0x2e, 0xa8, 0xfa, 0xad, 0xaf, 0x2e, 0xee, 0x6b, 0x4b, 0xd8, 0xec, 0x89, 0xd6, 0xfe, 0xe2, 0xea, 0x75, 0xdd, 0x85, 0x85, 0xdd, 0xeb, 0xaa, 0x8b, 0xfb, 0x5b, 0x13, 0x76, 0x5b, 0xa2, 0xad, 0x0f, 0xdc, 0x62, 0xc8, 0xa9, 0xcf, 0xcd, 0x69, 0xc8, 0x31, 0xd8, 0x0b, 0xea, 0xfc, 0x81, 0xda, 0x02, 0xbb, 0xbd, 0xa0, 0x36, 0xe0, 0xaf, 0x2b, 0xb0, 0x1b, 0xe0, 0xc1, 0xdc, 0xfa, 0x1c, 0x03, 0xa9, 0x2a, 0x98, 0xbf, 0xab, 0xad, 0x6d, 0xd7, 0xfc, 0x02, 0x77,\n\t0x49, 0x4b, 0x38, 0xdc, 0x52, 0xe2, 0x9e, 0xfa, 0x5b, 0xd0, 0x11, 0xc7, 0x3f, 0xa5, 0x0b, 0x99, 0x87, 0x09, 0x8e, 0xa8, 0x22, 0x36, 0x9f, 0xcd, 0x61, 0xd2, 0x6a, 0xa3, 0x04, 0x52, 0x01, 0x0a, 0x62, 0x91, 0x54, 0x04, 0xdd, 0x87, 0x72, 0x60, 0x57, 0x08, 0xe0, 0xa8, 0xe2, 0x0c, 0xb1, 0x7e, 0xa7, 0x0b, 0xd1, 0xb6, 0x28, 0xa1, 0x07, 0x04, 0xaa, 0x60, 0x9b, 0x9d, 0xe5, 0x71, 0x61, 0xe8, 0x2e, 0x0e, 0x70, 0x49, 0x5f, 0x6a, 0x8a, 0x88, 0x06, 0x2a, 0x69, 0x7d, 0x20, 0x27, 0xc7, 0xf9, 0xc5, 0x8b, 0xd2, 0x8b, 0x18, 0x80, 0x2f, 0xab, 0xd7, 0x2e, 0x6c, 0xd0, 0xc9, 0xfd, 0x15, 0x73, 0x4a, 0x3b, 0x77, 0xce, 0x8d, 0x6c, 0x6e, 0x08, 0xb6, 0x74, 0xf6, 0xc4, 0xfa, 0x6e, 0x5e, 0x51, 0xd6, 0x7c, 0xec, 0xf7, 0xc7, 0x7b, 0x8e, 0x2e, 0x2f, 0x6f, 0x3b, 0xf4, 0xec, 0xea, 0x91, 0xef, 0xe5,\n\t0x91, 0xbe, 0xda, 0x45, 0xe5, 0xe1, 0xc6, 0xd2, 0x2c, 0x95, 0xc2, 0xa0, 0x38, 0x5c, 0xb4, 0xf2, 0xbe, 0xb5, 0x59, 0x1d, 0x95, 0xfe, 0xf2, 0xd1, 0x1b, 0xe6, 0x5d, 0x79, 0x0d, 0x7d, 0xc6, 0x96, 0x65, 0x57, 0x37, 0x5f, 0xf7, 0xca, 0xee, 0x57, 0xf9, 0x47, 0x3e, 0x3b, 0x50, 0xb6, 0xf2, 0xd6, 0x81, 0x0d, 0xbf, 0x38, 0x3e, 0x6f, 0xce, 0x2c, 0x57, 0x85, 0x71, 0xe0, 0xa6, 0x25, 0x05, 0x3a, 0xb3, 0x2e, 0x43, 0x87, 0xf9, 0x3e, 0xcd, 0xdf, 0x4b, 0x7d, 0xc4, 0x2e, 0x82, 0x33, 0x0a, 0xd7, 0x11, 0x00, 0x84, 0xe8, 0x43, 0x41, 0x99, 0x3d, 0x48, 0xc6, 0x8a, 0xe0, 0xfc, 0xcb, 0xc8, 0xd6, 0x60, 0x38, 0x28, 0x98, 0xe4, 0x92, 0xd1, 0xfb, 0x54, 0x12, 0xaa, 0x51, 0xc8, 0x8f, 0x17, 0x0a, 0x7e, 0x81, 0xdf, 0x65, 0xd4, 0x0e, 0xed, 0x6d, 0xf3, 0xb6, 0xba, 0x14, 0xa4, 0x4c, 0xeb, 0x32, 0x97,\n\t0xcf, 0x2b, 0xf3, 0x4a, 0xf6, 0x2a, 0x6b, 0x87, 0x85, 0x63, 0x14, 0x3a, 0x56, 0x36, 0xaf, 0xdc, 0x23, 0xa5, 0xdf, 0x59, 0x7a, 0x74, 0x20, 0x9a, 0xc1, 0xcd, 0x51, 0xaa, 0x25, 0x94, 0xa5, 0xa4, 0xb7, 0xfa, 0x42, 0xeb, 0x94, 0x03, 0xb8, 0x7d, 0x61, 0xc8, 0x75, 0xde, 0x62, 0x1f, 0x81, 0x9a, 0x5c, 0x38, 0x11, 0xc8, 0xc4, 0x95, 0x7f, 0xc4, 0x12, 0x24, 0x49, 0xe0, 0xd8, 0xe4, 0x46, 0xcf, 0x48, 0x18, 0xbc, 0x6e, 0x6c, 0x97, 0x93, 0xe1, 0xb8, 0x36, 0x04, 0x58, 0x30, 0x11, 0xb5, 0x8a, 0xab, 0x54, 0xbe, 0x35, 0xf6, 0xf6, 0xbd, 0xe7, 0xef, 0x74, 0x44, 0xc1, 0x1c, 0x93, 0x93, 0x39, 0xa4, 0x50, 0x33, 0x4c, 0x86, 0x14, 0xdc, 0xcb, 0x38, 0x75, 0xec, 0x23, 0x5f, 0xcd, 0x26, 0x6f, 0xf4, 0x45, 0xab, 0x8d, 0x1c, 0xbf, 0xdb, 0xdb, 0xe4, 0xb3, 0x97, 0xb9, 0x98, 0x00, 0x67, 0x80, 0x6f,\n\t0x68, 0xe4, 0x1f, 0x66, 0x42, 0xb8, 0x46, 0xa0, 0x33, 0x61, 0xc3, 0x75, 0x3e, 0x44, 0x57, 0x06, 0xca, 0x25, 0x5b, 0x86, 0x91, 0xc5, 0xa7, 0x66, 0xce, 0x7b, 0x63, 0x6e, 0x26, 0x74, 0xf6, 0x65, 0xde, 0xf1, 0xf2, 0x59, 0xfa, 0x4f, 0xf4, 0xf9, 0xaf, 0xce, 0xb2, 0xcd, 0xe8, 0xef, 0xfd, 0xb8, 0x3f, 0x33, 0xf9, 0x87, 0xe9, 0x0b, 0xd8, 0xdf, 0x10, 0x49, 0x84, 0x94, 0xb0, 0x23, 0x80, 0x90, 0x62, 0xf4, 0x49, 0x42, 0x84, 0x2c, 0xc7, 0x99, 0x52, 0x18, 0x49, 0x12, 0xd2, 0xdc, 0xc2, 0x69, 0x45, 0xd8, 0x17, 0x28, 0x3d, 0xa0, 0x0c, 0x41, 0x02, 0x44, 0x06, 0x90, 0xec, 0x70, 0xd3, 0x17, 0x2e, 0xee, 0x22, 0xa3, 0x63, 0xbf, 0xa1, 0xf6, 0x5e, 0x68, 0x97, 0x2b, 0x50, 0x59, 0x67, 0x85, 0x9c, 0xfe, 0x21, 0x7d, 0x7e, 0xac, 0xa5, 0x74, 0xac, 0xe5, 0xfe, 0x46, 0xb5, 0x4b, 0x45, 0x7e, 0x49,\n\t0x7e, 0xa6, 0x72, 0xab, 0x1a, 0xf1, 0x7a, 0x18, 0x1a, 0xbf, 0x81, 0xf6, 0x31, 0xff, 0x26, 0x54, 0x84, 0x0e, 0xe5, 0x1c, 0x69, 0x14, 0x12, 0x1a, 0x73, 0x0e, 0x24, 0xa4, 0x50, 0x39, 0x97, 0x51, 0x9d, 0x16, 0x89, 0x2a, 0xc8, 0x08, 0x50, 0x7a, 0x3e, 0x2b, 0xa1, 0x44, 0xba, 0x41, 0x5a, 0xca, 0x40, 0x21, 0xb5, 0xec, 0x2b, 0xb5, 0x4e, 0x9a, 0x61, 0xff, 0xfc, 0x53, 0x4e, 0x2f, 0x95, 0x1a, 0x39, 0xf0, 0x28, 0x3f, 0x74, 0x90, 0x1f, 0x02, 0x27, 0x0e, 0x92, 0xe7, 0x00, 0xef, 0x4a, 0x78, 0x6a, 0xab, 0x78, 0x82, 0x57, 0xfa, 0x1a, 0xbd, 0xde, 0x46, 0x2f, 0x38, 0x7f, 0xf1, 0x97, 0x54, 0x01, 0x55, 0x20, 0xe0, 0x18, 0x11, 0xb5, 0x92, 0x7e, 0xfa, 0x1c, 0x61, 0x46, 0xf3, 0x8b, 0x93, 0xe2, 0x7a, 0x57, 0x70, 0x96, 0x35, 0x99, 0x01, 0x98, 0x31, 0x15, 0xd6, 0x28, 0xbf, 0x14, 0x6f, 0x0d,\n\t0x00, 0x42, 0x3c, 0x03, 0x08, 0xf5, 0xa3, 0x10, 0x76, 0x19, 0xce, 0x2d, 0x84, 0xf3, 0x85, 0x10, 0xbf, 0x46, 0xc9, 0xaa, 0x3a, 0xbd, 0x54, 0xc7, 0x7f, 0x5e, 0x18, 0x8a, 0x6f, 0xae, 0xa6, 0x3f, 0xbd, 0xa0, 0xaa, 0xde, 0x1c, 0xd7, 0x45, 0x2d, 0x40, 0xa9, 0x93, 0xea, 0xeb, 0xc8, 0xab, 0xc8, 0xaa, 0x46, 0x43, 0x44, 0xc7, 0x7f, 0x51, 0xe8, 0x90, 0x48, 0x7f, 0x28, 0x95, 0x70, 0x41, 0x33, 0x7f, 0x5e, 0x17, 0x31, 0x34, 0xa2, 0x76, 0x6c, 0x20, 0xea, 0x25, 0x23, 0xf4, 0x8b, 0x84, 0x49, 0x6c, 0x07, 0xea, 0xbb, 0x09, 0x80, 0x26, 0x80, 0x61, 0xea, 0x92, 0x78, 0x3b, 0x7d, 0x18, 0x1a, 0x57, 0x68, 0x07, 0xdc, 0x7f, 0x20, 0x14, 0x33, 0xec, 0x72, 0x81, 0xd2, 0x12, 0x4e, 0x25, 0x5c, 0xd0, 0xbb, 0x1a, 0x48, 0x46, 0xc6, 0xce, 0xa1, 0x76, 0x00, 0x79, 0x7e, 0x38, 0xbe, 0xa9, 0xfa, 0x82,\n\t0x8a, 0xfe, 0x14, 0xb6, 0x23, 0x5c, 0xc0, 0xff, 0x1b, 0x37, 0x63, 0xef, 0xd8, 0x39, 0xd4, 0x0c, 0x20, 0xcb, 0x77, 0xa1, 0x66, 0x48, 0xdd, 0xf9, 0x40, 0x21, 0xb4, 0x02, 0x3d, 0xfc, 0x91, 0x71, 0x07, 0x13, 0x65, 0x35, 0x90, 0x1e, 0x9a, 0x84, 0xda, 0x6c, 0xca, 0x94, 0xd0, 0x48, 0x67, 0x20, 0x46, 0xad, 0x00, 0xe3, 0xa1, 0xb0, 0xf0, 0x1d, 0xa8, 0xc3, 0xfa, 0xf4, 0x9a, 0x21, 0xb9, 0x00, 0x30, 0xd1, 0x06, 0xd4, 0xb5, 0xcf, 0x51, 0xd7, 0x1e, 0x93, 0x4a, 0x32, 0x43, 0x66, 0xf8, 0xb6, 0x88, 0xbe, 0x91, 0xac, 0xa1, 0x7e, 0x53, 0x8f, 0xdb, 0x02, 0x69, 0xb2, 0xa5, 0xfa, 0x42, 0x26, 0xfd, 0x71, 0xf5, 0xd6, 0xb8, 0x3e, 0x6a, 0x81, 0x3d, 0x97, 0xea, 0xeb, 0xc9, 0x04, 0x7a, 0xe7, 0x0f, 0xf8, 0x07, 0x98, 0x1c, 0x38, 0xe7, 0xcc, 0x84, 0x2e, 0xc1, 0x69, 0x64, 0x24, 0xd4, 0x97, 0x51,\n\t0x12, 0xd7, 0x20, 0xd1, 0x6a, 0x47, 0x6f, 0x85, 0x3b, 0x2d, 0x64, 0x05, 0x05, 0x06, 0xa3, 0x08, 0xe6, 0x9d, 0xac, 0x4a, 0x6d, 0x64, 0x72, 0xc6, 0x9e, 0x1b, 0x3b, 0x87, 0xde, 0x0c, 0xfb, 0xea, 0x4a, 0xbe, 0x19, 0x92, 0x3b, 0x62, 0xf8, 0xdb, 0xd8, 0x73, 0x64, 0x75, 0x3d, 0x1e, 0x8d, 0x02, 0xf4, 0x66, 0xfa, 0x5f, 0x17, 0xb8, 0xea, 0xad, 0xc5, 0x7a, 0x71, 0x34, 0x70, 0x5f, 0xa3, 0xe3, 0xff, 0x66, 0xba, 0x18, 0x3b, 0xa4, 0x79, 0x56, 0x22, 0xa8, 0x54, 0x90, 0xe8, 0xad, 0x97, 0x0b, 0x82, 0x31, 0x11, 0xa6, 0x76, 0xb7, 0x10, 0x34, 0x10, 0xf4, 0x04, 0x62, 0x5c, 0x51, 0x31, 0x9c, 0x03, 0x41, 0x31, 0x16, 0x03, 0x4e, 0x82, 0x58, 0x90, 0xe9, 0x5a, 0xec, 0x30, 0xb3, 0xb5, 0xbd, 0x17, 0xf7, 0xec, 0xa4, 0xae, 0x8c, 0xf6, 0x45, 0x2c, 0x95, 0x3e, 0xfe, 0x2a, 0x9b, 0x8f, 0x64, 0xec,\n\t0x17, 0x7f, 0x43, 0xfa, 0xad, 0x60, 0x4b, 0x7d, 0xac, 0xb7, 0xf7, 0xe2, 0xbe, 0x9d, 0xd4, 0xae, 0x68, 0x87, 0x87, 0xa6, 0x4d, 0x4e, 0xa4, 0x69, 0x12, 0x07, 0x60, 0x1b, 0x7e, 0x80, 0xdb, 0x00, 0x77, 0x56, 0x78, 0xb0, 0x31, 0x28, 0x05, 0x7a, 0xf7, 0xbc, 0x09, 0xac, 0xa2, 0x3a, 0x2e, 0x8c, 0xf4, 0x22, 0xbf, 0x04, 0x12, 0xdf, 0xa0, 0x87, 0x14, 0xf0, 0x4a, 0x38, 0xb7, 0x04, 0xf9, 0x1c, 0x85, 0xe9, 0xc7, 0xfc, 0x60, 0xe7, 0xc5, 0x3d, 0xbd, 0xb5, 0xac, 0xd9, 0xb1, 0x98, 0x82, 0x8c, 0xd7, 0xc6, 0x5f, 0xe5, 0xab, 0xb4, 0x44, 0xfa, 0xa2, 0x6b, 0x77, 0x52, 0x3b, 0x7b, 0x7b, 0x63, 0xf5, 0xfc, 0x41, 0xab, 0x9f, 0xa4, 0xa2, 0x8b, 0x9d, 0x26, 0x9a, 0xf6, 0x74, 0x44, 0x85, 0xdc, 0x0d, 0xd8, 0xf7, 0x2c, 0xf8, 0x5e, 0x5f, 0xc2, 0xad, 0x56, 0x91, 0x64, 0x13, 0xea, 0x36, 0x89, 0x90,\n\t0xdb, 0xd2, 0x7c, 0x09, 0x26, 0xc2, 0x58, 0x27, 0x86, 0x4a, 0x30, 0xc5, 0x45, 0x71, 0x23, 0x9a, 0x65, 0xa8, 0x36, 0x50, 0x31, 0x1c, 0x0c, 0x44, 0x84, 0x78, 0x31, 0xd3, 0x75, 0xf1, 0x57, 0xf0, 0x85, 0x60, 0x87, 0xf0, 0x42, 0xdc, 0x79, 0xdc, 0x10, 0x2a, 0x7a, 0xf1, 0x0d, 0xb0, 0xc4, 0x61, 0x06, 0x34, 0xe5, 0xee, 0x88, 0x52, 0xbb, 0x76, 0x5d, 0xdc, 0xdb, 0xdb, 0x5b, 0xd4, 0x08, 0x36, 0xdb, 0x7c, 0x00, 0xf7, 0x7b, 0x1c, 0xf6, 0x3b, 0x4c, 0x58, 0x50, 0xec, 0x91, 0x2a, 0x83, 0xc4, 0x9a, 0x29, 0x06, 0x8e, 0x23, 0xe7, 0x23, 0xca, 0x0f, 0x91, 0x42, 0x91, 0x1a, 0x8b, 0x51, 0x0b, 0xc9, 0xae, 0x8f, 0x14, 0x72, 0xc6, 0x02, 0xdc, 0x73, 0x3c, 0xf6, 0x46, 0x80, 0x8d, 0x78, 0xc5, 0xb0, 0x3d, 0x7a, 0xe3, 0x01, 0x48, 0x77, 0xf8, 0x92, 0xf6, 0x28, 0x75, 0x25, 0xa4, 0x42, 0x74, 0x7e,\n\t0x36, 0xa4, 0x3c, 0xd8, 0x01, 0x29, 0x4f, 0x45, 0x49, 0xbf, 0x8d, 0x3f, 0xe4, 0xad, 0xb0, 0x44, 0xe6, 0x47, 0xa9, 0x9d, 0xbb, 0x2e, 0xee, 0x43, 0x94, 0xa7, 0x80, 0xd9, 0xb1, 0x24, 0xb5, 0xf6, 0xd1, 0x9a, 0x0b, 0x21, 0x5e, 0xe7, 0xd6, 0x49, 0x51, 0x34, 0x5c, 0x73, 0x48, 0x4f, 0x82, 0x26, 0x14, 0x46, 0x77, 0xc9, 0xb2, 0x73, 0xd9, 0x4b, 0x11, 0x28, 0xd0, 0xa4, 0x75, 0x67, 0x10, 0x56, 0xbe, 0x4c, 0xe0, 0x09, 0xb0, 0x51, 0x97, 0x5f, 0x87, 0x17, 0x23, 0xee, 0xa0, 0xc0, 0x09, 0xc6, 0x9e, 0x4f, 0x32, 0x0a, 0x9d, 0x97, 0xa3, 0xde, 0xbc, 0xec, 0xe2, 0xb4, 0x06, 0x05, 0xfe, 0x40, 0xd6, 0x26, 0x39, 0x87, 0xce, 0xa5, 0x9a, 0xb4, 0x60, 0xe1, 0x7a, 0x85, 0x6b, 0x27, 0x17, 0xae, 0xd7, 0x2c, 0xb8, 0x2f, 0x32, 0x20, 0x9c, 0x43, 0x71, 0xb1, 0xc0, 0x49, 0x91, 0xbe, 0x40, 0x65, 0xe9,\n\t0x4b, 0x57, 0x58, 0x3d, 0x4e, 0x40, 0xfe, 0x33, 0xb9, 0x78, 0xd0, 0x73, 0x31, 0x3f, 0xfa, 0x4c, 0x1b, 0x31, 0x34, 0x90, 0x35, 0x64, 0x95, 0xb0, 0x9c, 0x0b, 0x9c, 0x12, 0xa9, 0xca, 0xa5, 0xc3, 0x2b, 0xaa, 0x81, 0x7f, 0x20, 0xb9, 0xa2, 0x74, 0x1e, 0x8e, 0x2e, 0xaf, 0xde, 0x02, 0xd7, 0xb1, 0x19, 0xb7, 0xbb, 0x9e, 0xac, 0x19, 0xfb, 0x59, 0x7d, 0xb2, 0xab, 0x9b, 0xab, 0x2f, 0xbc, 0xc8, 0x79, 0x75, 0xb8, 0xaf, 0xf5, 0xa8, 0x8d, 0xaf, 0xd1, 0x03, 0x64, 0x35, 0xf3, 0x22, 0x1c, 0xcd, 0xf2, 0x27, 0x95, 0x69, 0x96, 0x64, 0x0e, 0x4f, 0xf3, 0x91, 0x24, 0x98, 0xea, 0x30, 0x29, 0x80, 0x31, 0x91, 0x60, 0x7d, 0xda, 0xa1, 0xde, 0x27, 0x03, 0x06, 0x0f, 0x9a, 0xfc, 0x5a, 0x11, 0xa6, 0x98, 0x55, 0x83, 0x94, 0x1b, 0x44, 0xd0, 0x49, 0x5e, 0x73, 0x0e, 0x96, 0x2e, 0xec, 0xad, 0x2b, 0xd4,\n\t0x2c, 0x8c, 0x05, 0x5d, 0x01, 0x9d, 0xc3, 0xa4, 0x91, 0xca, 0x14, 0x0c, 0x73, 0xa3, 0xd1, 0xd6, 0x5c, 0x5c, 0xd0, 0xac, 0x9b, 0x73, 0x48, 0x12, 0x34, 0x1a, 0xdd, 0x32, 0xb9, 0x0c, 0xee, 0x99, 0x51, 0x7b, 0x5e, 0x62, 0x3e, 0x21, 0x9b, 0x24, 0x3e, 0xd8, 0x9e, 0x86, 0x54, 0x7b, 0x94, 0x42, 0x49, 0x20, 0xdc, 0x9e, 0x29, 0x81, 0x58, 0x68, 0xbb, 0x82, 0x1b, 0x35, 0xe5, 0xf8, 0x77, 0x68, 0xd9, 0x4b, 0x8e, 0x65, 0xa5, 0x0b, 0x07, 0x67, 0xc6, 0xd5, 0x8b, 0xe2, 0xd1, 0x70, 0x40, 0xe7, 0xb2, 0xe8, 0x24, 0x32, 0x05, 0xcb, 0x7e, 0x6c, 0xb2, 0x35, 0x16, 0x17, 0x94, 0xab, 0xca, 0x57, 0x48, 0xec, 0x3a, 0x83, 0x55, 0xaa, 0x90, 0xc2, 0x96, 0x91, 0xc4, 0x5c, 0xfa, 0x46, 0x9a, 0x64, 0x4b, 0xe1, 0xce, 0xd4, 0x8c, 0x22, 0x6c, 0xf4, 0x62, 0xe5, 0x26, 0xac, 0x4e, 0xa4, 0x83, 0xd5, 0x64,\n\t0x66, 0x66, 0x9a, 0x33, 0x4d, 0x5c, 0xd8, 0xc5, 0x08, 0x90, 0x35, 0xb9, 0x70, 0x5c, 0x59, 0xc1, 0x3e, 0xa8, 0x2d, 0xf4, 0x0b, 0xee, 0x3e, 0xe4, 0x6b, 0x7b, 0x75, 0x9f, 0x49, 0xb3, 0x5d, 0x2a, 0x93, 0x49, 0x77, 0x48, 0x8c, 0xca, 0x83, 0x7f, 0x3c, 0x4b, 0x1a, 0x3f, 0x71, 0x55, 0x9a, 0x2c, 0xab, 0x32, 0x5d, 0x5e, 0xfa, 0x46, 0xf5, 0x5e, 0xa9, 0x52, 0x29, 0xdd, 0xcb, 0xca, 0x80, 0xe2, 0x8e, 0x77, 0xdc, 0x8c, 0xdd, 0x7d, 0xc8, 0x60, 0x82, 0xaf, 0x68, 0x65, 0xe5, 0x34, 0x29, 0xb9, 0x1b, 0xea, 0x13, 0x16, 0x62, 0xe6, 0x59, 0x0d, 0xdc, 0x59, 0x51, 0x88, 0x3c, 0x05, 0x18, 0xb0, 0x4e, 0x30, 0x61, 0xae, 0x41, 0xb1, 0xe1, 0x6b, 0xd1, 0xb6, 0x65, 0x14, 0xc3, 0x67, 0x21, 0xfc, 0x26, 0x02, 0x65, 0xb4, 0x51, 0xeb, 0xd0, 0x99, 0xd1, 0xde, 0x84, 0x9a, 0x10, 0x4a, 0xe2, 0x2a, 0xe1,\n\t0x63, 0xe4, 0x78, 0xf7, 0x22, 0x36, 0x8a, 0x2a, 0x44, 0x8a, 0x4f, 0x2e, 0x99, 0x6c, 0x2c, 0x4d, 0x0a, 0x2d, 0x92, 0xaa, 0x35, 0x66, 0x6e, 0xf4, 0x48, 0x86, 0x4f, 0x73, 0x85, 0x52, 0x79, 0x85, 0xc6, 0x97, 0x71, 0xf0, 0x5f, 0x8f, 0x4a, 0xee, 0x7e, 0xc7, 0xc3, 0xc2, 0x66, 0x29, 0x38, 0x25, 0xcb, 0x2f, 0x93, 0x19, 0xaf, 0xd2, 0x68, 0xae, 0x32, 0xca, 0x80, 0x80, 0x17, 0x3c, 0xee, 0xa0, 0x6f, 0x24, 0x5f, 0x85, 0xb4, 0x52, 0x10, 0x56, 0xc4, 0x39, 0x35, 0x0a, 0xdc, 0x50, 0xb4, 0x0b, 0x41, 0x8d, 0xa0, 0x70, 0xc6, 0xe1, 0x20, 0xd5, 0xca, 0x85, 0x83, 0x3a, 0x6c, 0x93, 0x42, 0x8b, 0x00, 0xa9, 0xb7, 0x4e, 0xc0, 0x4c, 0x21, 0xd8, 0x3e, 0x63, 0xa5, 0xeb, 0x93, 0x9f, 0x72, 0x66, 0x8d, 0x5a, 0xba, 0x9a, 0xcc, 0x99, 0x42, 0x32, 0x66, 0xb1, 0x9d, 0x71, 0xbf, 0xc3, 0x2a, 0x39, 0xc5,\n\t0xa1, 0x4f, 0xd2, 0x28, 0x26, 0xb6, 0x81, 0x95, 0x93, 0xef, 0x4a, 0x4e, 0x41, 0x9d, 0x05, 0x73, 0x51, 0x93, 0x30, 0x5e, 0xc9, 0x4c, 0x54, 0x84, 0xdd, 0xb8, 0x16, 0xb6, 0x62, 0x94, 0x6a, 0xf5, 0x73, 0x61, 0x41, 0x4d, 0x9a, 0xd4, 0x79, 0x46, 0x68, 0x93, 0x01, 0x2e, 0xc4, 0x77, 0x27, 0x77, 0x9d, 0xbf, 0x05, 0xb7, 0xc9, 0xe3, 0xce, 0x5c, 0xcd, 0xca, 0x27, 0x7a, 0x3e, 0xcb, 0xce, 0x7a, 0xde, 0x31, 0x19, 0x0e, 0x11, 0xc2, 0x5c, 0xa1, 0x36, 0xb0, 0x6b, 0xb0, 0x7f, 0x66, 0xee, 0x59, 0x07, 0x4b, 0xd2, 0x78, 0x1a, 0x2b, 0x44, 0x07, 0x0d, 0xc1, 0xd0, 0xcb, 0xc4, 0x06, 0xc0, 0xdd, 0x31, 0xc5, 0x0c, 0x0a, 0x33, 0xc7, 0x8a, 0x2b, 0x4d, 0x22, 0x03, 0xf4, 0x9a, 0x69, 0xce, 0xf6, 0x26, 0x64, 0x06, 0x93, 0x17, 0xce, 0x2b, 0x41, 0x5d, 0x9c, 0x4c, 0xa6, 0xe2, 0xa4, 0xcf, 0xe4, 0xd2,\n\t0x59, 0x7e, 0xc9, 0x44, 0xab, 0x75, 0xb6, 0xe5, 0xf9, 0xab, 0xa3, 0x96, 0xfa, 0x62, 0x55, 0x5b, 0xac, 0xc8, 0xeb, 0xce, 0xb4, 0xe8, 0x39, 0x89, 0x5c, 0xc1, 0x4c, 0x9a, 0x75, 0x77, 0x1a, 0xed, 0x1a, 0xb8, 0x07, 0xcd, 0x9f, 0xa9, 0x89, 0x2c, 0x93, 0x04, 0xcd, 0x7a, 0xbc, 0x40, 0x65, 0x84, 0x30, 0x07, 0xa9, 0x0d, 0x92, 0x8f, 0x09, 0x1b, 0xdc, 0xe7, 0x2f, 0x3d, 0xeb, 0x55, 0xc1, 0xdd, 0x7d, 0xb2, 0x6f, 0x5e, 0xb4, 0xd7, 0x87, 0xbb, 0xfe, 0x35, 0x04, 0x32, 0x04, 0x2f, 0x85, 0x6b, 0x83, 0x5a, 0x7b, 0xe9, 0x7a, 0xf5, 0x4d, 0xba, 0x8a, 0x5a, 0x35, 0xed, 0x65, 0xb0, 0xb7, 0x5c, 0xd8, 0x6c, 0x30, 0x79, 0x70, 0x6f, 0x2f, 0xdf, 0x3b, 0xed, 0xa4, 0x41, 0x23, 0xa3, 0x97, 0xe9, 0xdb, 0xc1, 0x29, 0xb3, 0xf7, 0x19, 0x93, 0x6d, 0x72, 0xf7, 0xf0, 0x2a, 0xe7, 0xf7, 0x4e, 0x9a, 0xc8,\n\t0x78, 0x1c, 0xc9, 0x77, 0xd8, 0x97, 0x08, 0x27, 0x91, 0x8b, 0x32, 0x0d, 0x51, 0x83, 0xd1, 0x2e, 0x22, 0x00, 0x68, 0x96, 0x6a, 0x66, 0xe0, 0xbf, 0xf4, 0xfa, 0xd4, 0x4e, 0x02, 0x6e, 0x97, 0x59, 0x8a, 0x40, 0xe1, 0x4a, 0x83, 0x2c, 0x9c, 0xd9, 0x7e, 0x6f, 0xd8, 0x8b, 0xa3, 0xd3, 0x41, 0x0a, 0x2e, 0x0a, 0x6e, 0xe4, 0x92, 0x78, 0x51, 0xd8, 0x3f, 0xa8, 0x9d, 0x32, 0x88, 0xe4, 0x3b, 0x26, 0xb8, 0x4d, 0xcd, 0x69, 0x2c, 0x2b, 0xb4, 0x1a, 0xdd, 0x7a, 0xf9, 0x56, 0x53, 0x6e, 0x43, 0x34, 0xb7, 0xb1, 0xb4, 0xd0, 0x06, 0x7f, 0x29, 0x96, 0x4f, 0x19, 0x45, 0xf6, 0x85, 0xe8, 0xec, 0x44, 0xc0, 0x15, 0x74, 0x6b, 0xec, 0x5e, 0x0e, 0x7d, 0x75, 0x07, 0x5d, 0x1a, 0x9b, 0x57, 0x33, 0xf6, 0xcb, 0x49, 0x2b, 0x01, 0x8f, 0x17, 0xf9, 0x47, 0x69, 0x23, 0x5c, 0x07, 0x39, 0xc4, 0x15, 0x09, 0x95,\n\t0x1a, 0xb0, 0x8c, 0x13, 0xc1, 0x85, 0xa0, 0xd8, 0x09, 0x31, 0x4f, 0xce, 0x35, 0x79, 0x55, 0x30, 0x08, 0xca, 0x05, 0xfb, 0x3c, 0x71, 0x4e, 0xe8, 0x28, 0xda, 0xcd, 0xfa, 0x27, 0x5f, 0x82, 0xc0, 0x46, 0xba, 0x53, 0x17, 0xb2, 0x2c, 0xda, 0xcd, 0xb2, 0x54, 0x07, 0x72, 0x8c, 0x86, 0xbd, 0x68, 0x41, 0xe1, 0x9e, 0x4f, 0x1a, 0x1b, 0xed, 0x65, 0xe9, 0x30, 0x75, 0x81, 0x7d, 0x6e, 0xce, 0x6b, 0xcc, 0xc9, 0x69, 0xaa, 0x8c, 0x5b, 0x8d, 0x1e, 0x83, 0x72, 0xab, 0x39, 0xbf, 0x31, 0x9a, 0xdb, 0x54, 0x19, 0xb3, 0x19, 0x3d, 0x46, 0x65, 0xfa, 0x8a, 0x03, 0x81, 0xe9, 0x49, 0x20, 0xf8, 0x48, 0x67, 0xd0, 0x87, 0xc9, 0x3f, 0xb2, 0xa7, 0x08, 0x3d, 0x1c, 0x3d, 0x38, 0x76, 0x12, 0x38, 0x4d, 0x99, 0x75, 0x70, 0x1f, 0x0e, 0x15, 0x58, 0x94, 0xfd, 0x8c, 0xfa, 0x4f, 0x60, 0xdc, 0xf8, 0x41, 0xd0,\n\t0x6a, 0x30, 0x00, 0xc2, 0xe0, 0x34, 0x38, 0xac, 0x66, 0x2e, 0x53, 0x29, 0x67, 0x19, 0x42, 0x0f, 0xf4, 0xd8, 0x2d, 0x8e, 0x76, 0xda, 0x85, 0xc9, 0x00, 0x66, 0x04, 0xfc, 0xa5, 0xc5, 0xb9, 0x4e, 0x68, 0xb9, 0x81, 0x1b, 0xfa, 0x76, 0xb6, 0x7b, 0xaf, 0xd1, 0xe7, 0xcc, 0x2c, 0x2c, 0x9c, 0x99, 0xa3, 0xbf, 0xc6, 0xdb, 0xbe, 0xf3, 0xf3, 0x8f, 0xd4, 0x36, 0xe3, 0xa6, 0x63, 0x2a, 0xb7, 0x97, 0x3e, 0x1c, 0x69, 0x59, 0x52, 0xe2, 0x8a, 0x07, 0xf5, 0xfa, 0x60, 0xdc, 0x55, 0xb2, 0xa4, 0x25, 0x42, 0x1a, 0x79, 0x9e, 0xcb, 0xf8, 0xd4, 0x64, 0xc0, 0xfe, 0x5b, 0x96, 0xa1, 0xca, 0xa5, 0x01, 0xc8, 0x1f, 0xed, 0x28, 0xd2, 0x9e, 0x45, 0x3c, 0x71, 0x1d, 0x83, 0x6a, 0xac, 0xad, 0x43, 0xa9, 0x8d, 0xeb, 0xb0, 0x13, 0xb7, 0x1b, 0x57, 0xd5, 0x96, 0x00, 0xc8, 0x3c, 0x3a, 0x20, 0xb3, 0x26, 0x20,\n\t0xcf, 0xd6, 0x69, 0x38, 0xa5, 0x3d, 0xc3, 0x8e, 0x18, 0xb7, 0x57, 0x8a, 0xb5, 0x1d, 0x4c, 0x5b, 0xc4, 0xb9, 0x85, 0x96, 0x62, 0x37, 0x15, 0x6a, 0x27, 0x55, 0xce, 0x3f, 0xc2, 0xd9, 0x8c, 0xab, 0x7f, 0x25, 0xe3, 0x74, 0x16, 0xee, 0xf5, 0xbe, 0xed, 0xad, 0xee, 0x5d, 0x0b, 0x47, 0x46, 0x16, 0xee, 0x72, 0xb7, 0x6e, 0x97, 0x06, 0xf8, 0x3f, 0xaa, 0x24, 0x80, 0x53, 0xaa, 0x24, 0xe4, 0xd8, 0xef, 0xc3, 0x4d, 0x03, 0x25, 0x35, 0xad, 0xad, 0x35, 0x25, 0x03, 0x4d, 0xe1, 0x24, 0xdd, 0xde, 0x49, 0xa7, 0x1b, 0x0d, 0x50, 0xd6, 0xb8, 0x80, 0x81, 0x32, 0x85, 0x6e, 0x46, 0x48, 0x37, 0x9b, 0xc5, 0xe0, 0x34, 0x3a, 0xbf, 0x8d, 0x6e, 0x14, 0xe2, 0xa4, 0x18, 0xbf, 0x6d, 0x1a, 0xba, 0xfd, 0x09, 0xce, 0x89, 0xa3, 0xab, 0x8d, 0x76, 0xf5, 0x47, 0xd3, 0xd1, 0xcd, 0x68, 0xfc, 0x34, 0x23, 0x13,\n\t0xd2, 0x06, 0xf2, 0xf4, 0xcf, 0x59, 0x86, 0xfc, 0x8d, 0xd4, 0x4f, 0xc8, 0xa0, 0x5c, 0xa9, 0x48, 0x94, 0x62, 0xa4, 0x62, 0x44, 0x37, 0x28, 0xdc, 0x90, 0xb3, 0xe9, 0x52, 0xba, 0x29, 0xe4, 0x80, 0x30, 0x42, 0xb2, 0x65, 0xaa, 0xe5, 0x56, 0x85, 0x95, 0xa5, 0x09, 0x19, 0x90, 0xa1, 0x06, 0x6a, 0xd1, 0xde, 0x1e, 0x35, 0x47, 0x06, 0xa6, 0x10, 0xee, 0x3f, 0x3c, 0x7e, 0xcd, 0xeb, 0xcb, 0x8c, 0x0e, 0x15, 0xff, 0x04, 0xb8, 0x6d, 0x32, 0xd9, 0xfc, 0x0a, 0x23, 0xff, 0x4f, 0xb9, 0x02, 0x38, 0xc7, 0xfe, 0x30, 0x89, 0x68, 0x49, 0x9a, 0xfd, 0x19, 0x4a, 0xe5, 0x3c, 0x62, 0x69, 0x42, 0xae, 0x46, 0x3a, 0x34, 0xdc, 0x27, 0x25, 0xbd, 0xbb, 0x0e, 0xc8, 0xd3, 0x19, 0x82, 0x5c, 0x86, 0x74, 0x56, 0x1a, 0x79, 0xce, 0x18, 0x82, 0x62, 0xa8, 0x45, 0x12, 0x54, 0x53, 0x67, 0x90, 0xc6, 0xe0, 0x6a,\n\t0xf0, 0x02, 0x9a, 0x64, 0xd6, 0x5c, 0xe6, 0x0a, 0x28, 0xb4, 0xad, 0x56, 0x6b, 0x9e, 0x35, 0xcf, 0xa7, 0xf3, 0x1b, 0xb2, 0xfc, 0x52, 0x81, 0x27, 0x4e, 0xb0, 0xc1, 0x5c, 0x90, 0xa6, 0xe4, 0xf8, 0x93, 0x2e, 0xd6, 0xd4, 0x00, 0x80, 0xfe, 0x58, 0x08, 0xab, 0x5e, 0x5a, 0x89, 0x5c, 0xce, 0xfa, 0x1c, 0x50, 0x21, 0x9b, 0x0f, 0x15, 0xb2, 0x45, 0x60, 0x27, 0x24, 0x7e, 0xdf, 0xa4, 0xe1, 0x60, 0x25, 0x58, 0x1d, 0xc3, 0xec, 0xb0, 0xc8, 0x64, 0x6b, 0x2e, 0x41, 0x2a, 0x9a, 0x03, 0x0d, 0x44, 0xfa, 0xc0, 0x88, 0x73, 0x18, 0x8e, 0x05, 0xd2, 0xd3, 0xb2, 0x89, 0x6d, 0x93, 0xfb, 0x8c, 0xd4, 0xb5, 0x10, 0x6a, 0x3b, 0xbc, 0x0c, 0x2f, 0x36, 0xd8, 0xf9, 0xa5, 0x13, 0x5d, 0xa3, 0x28, 0x06, 0xf2, 0x0e, 0x06, 0xf1, 0x0c, 0x86, 0x82, 0x02, 0x21, 0x3c, 0xe5, 0x52, 0x66, 0xd5, 0xe5, 0xae, 0x15,\n\t0xe8, 0x90, 0x6d, 0xcd, 0xf6, 0xfc, 0xdf, 0xe8, 0x80, 0x47, 0x17, 0xf4, 0xa5, 0xab, 0x79, 0xbe, 0x94, 0xf2, 0x07, 0xb6, 0xc0, 0xc1, 0xed, 0x4b, 0x0d, 0xb5, 0x64, 0x01, 0x9b, 0x52, 0xfb, 0x62, 0x46, 0x41, 0x15, 0x2c, 0xb3, 0xa1, 0x81, 0x4e, 0x0e, 0xfa, 0x04, 0x7f, 0x41, 0xb2, 0x41, 0x4f, 0xc4, 0x10, 0x7a, 0xa6, 0x0d, 0xd0, 0x92, 0x6c, 0xc0, 0xb0, 0x64, 0xf3, 0x24, 0xcf, 0x12, 0x40, 0x19, 0x33, 0xa4, 0x74, 0xea, 0xa2, 0x29, 0xc8, 0x43, 0xe9, 0xbc, 0x86, 0x98, 0x31, 0x36, 0xb1, 0x70, 0xe4, 0xd3, 0x33, 0x9c, 0xe4, 0x97, 0x4b, 0x78, 0xe7, 0x34, 0x0b, 0xc9, 0x89, 0x24, 0xc5, 0xe6, 0xe9, 0xa5, 0xc8, 0xa5, 0x4b, 0x0b, 0xbc, 0x81, 0xb8, 0xe5, 0xa5, 0x3c, 0x54, 0xe8, 0x5f, 0x2b, 0x1c, 0x5f, 0x24, 0x37, 0x50, 0x4e, 0xc4, 0xfe, 0x84, 0xdc, 0x04, 0xfb, 0x17, 0xc2, 0xfd, 0x13,\n\t0x64, 0x86, 0x1f, 0xf6, 0x86, 0x81, 0x52, 0x1c, 0x8e, 0x99, 0xd8, 0xdf, 0x64, 0x37, 0xe1, 0x70, 0xd1, 0x7d, 0xc8, 0x41, 0x36, 0x8a, 0x4a, 0x07, 0x46, 0x2e, 0xb9, 0x2e, 0x8d, 0x2e, 0x28, 0xb5, 0x11, 0xef, 0x26, 0xf0, 0x9d, 0xc8, 0x95, 0xa6, 0xd5, 0x00, 0x22, 0x27, 0x1b, 0x55, 0x73, 0xd5, 0xe4, 0x6b, 0xf3, 0x33, 0x94, 0x72, 0x29, 0x24, 0x0e, 0x07, 0xb8, 0x34, 0xe2, 0xa4, 0x96, 0xea, 0x37, 0x92, 0x26, 0x7d, 0xe5, 0x7a, 0x91, 0xe4, 0xd8, 0x3c, 0xbd, 0x54, 0x61, 0x99, 0xf4, 0xb5, 0x0c, 0xde, 0xb9, 0x0c, 0x49, 0x00, 0xb0, 0xf0, 0x47, 0x49, 0xd9, 0xf8, 0x3e, 0x11, 0xdb, 0x5f, 0x44, 0x16, 0x58, 0x43, 0x88, 0xd8, 0xfe, 0xcc, 0x94, 0x50, 0x43, 0x52, 0xa6, 0x73, 0x67, 0x9b, 0x50, 0xc9, 0x01, 0xad, 0x2b, 0x62, 0x32, 0x65, 0xbb, 0x75, 0x9f, 0x9b, 0xb2, 0xd1, 0x8f, 0x6c, 0x93,\n\t0x39, 0xdb, 0xad, 0xd5, 0xba, 0xb3, 0x11, 0x8d, 0x7b, 0xc7, 0x3f, 0x61, 0xaf, 0x64, 0xb3, 0xe0, 0x33, 0x4b, 0x91, 0x1c, 0xc8, 0xb5, 0x60, 0xcb, 0x12, 0x0b, 0x30, 0x50, 0x47, 0x2a, 0xac, 0x97, 0x01, 0x13, 0x30, 0x8b, 0xc8, 0xb7, 0xa9, 0x2b, 0xd5, 0x95, 0x44, 0x23, 0x5e, 0x77, 0x7a, 0x99, 0x87, 0xc9, 0x79, 0x37, 0x40, 0x40, 0xc7, 0x41, 0xff, 0x92, 0x29, 0xf8, 0x40, 0xc1, 0x8d, 0x22, 0x22, 0x96, 0xc6, 0x8a, 0xa0, 0xc8, 0x58, 0xfb, 0xd4, 0x9e, 0xc6, 0xc6, 0x3d, 0x4f, 0xad, 0x5d, 0xfb, 0xd4, 0xde, 0xc6, 0xc6, 0xbd, 0x4f, 0x51, 0xcf, 0x49, 0xa4, 0x07, 0xf7, 0x94, 0x56, 0x8c, 0x3c, 0xc3, 0x7f, 0x7d, 0xe7, 0x49, 0xfe, 0xab, 0x9f, 0x2c, 0x5b, 0xf6, 0x13, 0x20, 0x39, 0x79, 0x2f, 0x90, 0x2f, 0x6c, 0x68, 0x51, 0x71, 0xaa, 0x75, 0x0f, 0xb6, 0x1c, 0x79, 0x65, 0xcf, 0xee, 0x57,\n\t0x51, 0xad, 0xbb, 0x57, 0x77, 0xef, 0x79, 0xe5, 0x48, 0x0b, 0xb3, 0xc7, 0x50, 0xe6, 0xd8, 0xfe, 0x90, 0xa3, 0xf7, 0xb7, 0xdb, 0xef, 0xe2, 0x3f, 0x7b, 0x61, 0xe5, 0xca, 0x17, 0x40, 0xc6, 0x5d, 0x77, 0x02, 0xd5, 0x0b, 0x57, 0xac, 0x1d, 0x51, 0xd4, 0x44, 0x75, 0x36, 0xab, 0xcb, 0x88, 0xac, 0x73, 0x27, 0xc7, 0xff, 0xc5, 0x9e, 0x86, 0xfd, 0x8c, 0xa2, 0xd8, 0x45, 0x09, 0x60, 0x49, 0x76, 0x1d, 0xc2, 0x32, 0xa6, 0x18, 0x62, 0x90, 0x16, 0x02, 0xa6, 0x27, 0x42, 0xbb, 0x21, 0x55, 0xa3, 0x44, 0x36, 0xa7, 0xf7, 0xeb, 0xfd, 0x46, 0xbc, 0xc0, 0x85, 0xa0, 0x11, 0x09, 0x97, 0xa4, 0x30, 0xae, 0x18, 0x27, 0x2c, 0x10, 0xae, 0x50, 0x9f, 0xea, 0x0e, 0x7b, 0x87, 0x44, 0x1a, 0x1b, 0xba, 0x69, 0xe1, 0xac, 0x9b, 0xdf, 0x3a, 0x70, 0xe0, 0xad, 0x9b, 0x67, 0xbd, 0x99, 0xbf, 0xf0, 0x60, 0x57,\n\t0xd7, 0xc1, 0x85, 0x05, 0x6f, 0x2c, 0x5c, 0x81, 0x1a, 0xcf, 0x66, 0xc1, 0xb6, 0xb6, 0x6c, 0xef, 0x2d, 0x00, 0x63, 0xaf, 0xed, 0x7a, 0xeb, 0x44, 0x4f, 0xcf, 0x89, 0xb7, 0x76, 0x51, 0xc3, 0x17, 0x4f, 0xf4, 0xdc, 0x34, 0x5a, 0x56, 0x36, 0x7a, 0x63, 0x0f, 0x35, 0xfc, 0x1a, 0xd9, 0x18, 0x17, 0x9b, 0x8c, 0x6b, 0x8c, 0x7c, 0x4a, 0xff, 0x85, 0x3e, 0x0a, 0x65, 0x6d, 0x3e, 0xb1, 0x2c, 0xa1, 0x08, 0xc3, 0xe1, 0x08, 0x68, 0x10, 0xd8, 0x92, 0xc8, 0xd4, 0x6d, 0x93, 0x87, 0x69, 0xd5, 0xa4, 0x61, 0xb2, 0x7e, 0xc3, 0xe9, 0xd5, 0x48, 0x97, 0xd7, 0xe3, 0x12, 0x4c, 0xf9, 0xca, 0x3c, 0x9f, 0xc7, 0x62, 0x12, 0x8a, 0x2f, 0x49, 0xe4, 0x53, 0x8a, 0x2f, 0x09, 0x83, 0x68, 0xd0, 0x4f, 0x9a, 0x5a, 0x86, 0xd4, 0x00, 0xc6, 0x0b, 0xc9, 0xb2, 0x1b, 0x8e, 0x1c, 0xb9, 0xe1, 0xa6, 0xeb, 0xaf, 0xa7,\n\t0xf2, 0x59, 0xe9, 0xae, 0xed, 0x45, 0x69, 0x45, 0x33, 0xd7, 0xee, 0x7e, 0xb1, 0xba, 0xa2, 0x56, 0xa5, 0x51, 0x15, 0xc6, 0x53, 0xe5, 0x98, 0x68, 0x99, 0x2e, 0x6e, 0x5b, 0xff, 0x7d, 0xcb, 0xda, 0x63, 0xe9, 0x15, 0x34, 0x17, 0x74, 0x29, 0x6b, 0x22, 0x99, 0x26, 0x93, 0xc3, 0x10, 0xc4, 0x35, 0x2c, 0x76, 0x8d, 0x7f, 0xcc, 0xd8, 0x61, 0xbf, 0x73, 0x88, 0xd5, 0x09, 0x65, 0xc0, 0x4b, 0x12, 0x94, 0x2b, 0x83, 0x14, 0xf8, 0xba, 0x43, 0xa8, 0x16, 0xca, 0x52, 0x70, 0xf8, 0x08, 0x0a, 0xc1, 0xcb, 0xad, 0x41, 0x15, 0xa8, 0x96, 0xa2, 0xc0, 0xf3, 0x34, 0xa8, 0x50, 0xdf, 0xb4, 0x97, 0x60, 0x78, 0x03, 0xb1, 0x70, 0x09, 0xc6, 0x0b, 0x85, 0xfb, 0x50, 0xf8, 0x92, 0xa8, 0xd6, 0xab, 0x0f, 0xb8, 0x27, 0x8f, 0x34, 0xd2, 0x8b, 0x45, 0x3f, 0x11, 0x1a, 0x6c, 0xb4, 0xe0, 0x8b, 0xd3, 0x86, 0x3a,\n\t0x5e, 0xc8, 0x64, 0xb2, 0x92, 0xac, 0x39, 0xdb, 0x66, 0x6d, 0x0c, 0x29, 0x55, 0xee, 0xa6, 0xd9, 0xfd, 0xb1, 0xb9, 0x57, 0x76, 0x65, 0xbf, 0x38, 0x34, 0xd2, 0xb2, 0xb7, 0xf4, 0x85, 0xe6, 0x4e, 0xdc, 0x6b, 0xfa, 0x28, 0xec, 0x6c, 0xcd, 0xaa, 0xce, 0x7c, 0x7a, 0x4c, 0x1a, 0x5c, 0xea, 0x2d, 0x0b, 0x1b, 0x4b, 0x86, 0x8f, 0x74, 0x91, 0x57, 0x8f, 0x6d, 0xbd, 0x62, 0xeb, 0x8c, 0x2a, 0xf2, 0xaf, 0xf7, 0x4b, 0x1a, 0xf2, 0x52, 0xbd, 0x46, 0x3b, 0xd3, 0x39, 0xe3, 0x32, 0x7a, 0x39, 0xf3, 0x22, 0xfc, 0x96, 0x09, 0xb5, 0xfd, 0x1b, 0x12, 0xca, 0x10, 0x20, 0x25, 0xa6, 0x4c, 0x9a, 0x12, 0xaa, 0x59, 0x23, 0x70, 0xb4, 0xa8, 0x52, 0x41, 0xca, 0xa4, 0x90, 0x11, 0xca, 0x68, 0x5c, 0xb9, 0x89, 0x00, 0x0b, 0x08, 0xb9, 0x7c, 0x18, 0x79, 0x06, 0x31, 0x7c, 0xc0, 0x52, 0x34, 0x8f, 0xb1, 0xcf,\n\t0x0c, 0x65, 0xd3, 0x5b, 0x13, 0xf9, 0xdf, 0x7e, 0x3d, 0xbc, 0xb2, 0x25, 0xa9, 0x68, 0x63, 0x64, 0x4a, 0x03, 0xc7, 0x71, 0xb9, 0x5c, 0x6e, 0x4e, 0x34, 0x3b, 0xa2, 0x0d, 0xf9, 0xdc, 0x3a, 0x9f, 0x97, 0xc3, 0xb8, 0x47, 0x46, 0xe4, 0x04, 0xc6, 0x05, 0x54, 0x85, 0x78, 0xaa, 0x62, 0x80, 0xd0, 0xe5, 0x3c, 0xb9, 0x53, 0x70, 0x1f, 0x62, 0x42, 0x5d, 0xa8, 0x01, 0xea, 0xc3, 0x8b, 0x56, 0xf2, 0xe9, 0xdc, 0x35, 0xb5, 0x87, 0x8e, 0x5e, 0xb5, 0x69, 0xee, 0xb6, 0x18, 0x98, 0x75, 0xdd, 0xc6, 0xb0, 0x5c, 0x53, 0x77, 0x72, 0xb4, 0xf7, 0x86, 0xe1, 0xe2, 0xca, 0xf5, 0xa7, 0x96, 0xf6, 0x5f, 0x59, 0xf8, 0xc9, 0x27, 0x2f, 0x6c, 0xdf, 0x41, 0xbd, 0x5f, 0x55, 0xf8, 0x93, 0x9f, 0x9c, 0xb9, 0xaf, 0xb5, 0x91, 0x7a, 0x7d, 0xc7, 0x85, 0xc3, 0xc1, 0x4d, 0x1d, 0xfd, 0x68, 0xfe, 0x6c, 0x7a, 0xe1,\n\t0x70, 0x5b, 0x65, 0xfc, 0xcb, 0x1d, 0x6f, 0xbc, 0x01, 0xd7, 0xc2, 0x3a, 0x62, 0x29, 0xfd, 0x34, 0xfd, 0x08, 0xf6, 0x1d, 0xa2, 0x18, 0x93, 0xcb, 0xa4, 0x80, 0x7e, 0x57, 0xe4, 0xb1, 0x75, 0x5d, 0xc7, 0x5f, 0x5a, 0xbb, 0xf6, 0xa5, 0xe3, 0x5d, 0xc9, 0xcf, 0x47, 0xca, 0x87, 0x0f, 0xb6, 0xb7, 0x1f, 0x5a, 0x5a, 0x5e, 0xbe, 0xf4, 0x50, 0x7b, 0xfb, 0xc1, 0xe1, 0x72, 0xf2, 0x9a, 0xf4, 0xd3, 0xe8, 0x13, 0x1d, 0x15, 0xae, 0x42, 0x9f, 0x87, 0x08, 0x9c, 0x4c, 0xbd, 0x95, 0x58, 0x4e, 0x3f, 0x45, 0x3f, 0x00, 0xd7, 0xa8, 0x91, 0xf0, 0xc2, 0x51, 0x2b, 0x27, 0x66, 0x10, 0x73, 0xa0, 0x04, 0x5a, 0x41, 0x6c, 0x26, 0xf6, 0x11, 0xd7, 0x13, 0xb7, 0x13, 0xf7, 0x13, 0x8f, 0x13, 0xcf, 0x11, 0x7c, 0xcb, 0xa3, 0x79, 0x70, 0xfc, 0x7a, 0xc4, 0x10, 0x9e, 0x41, 0x39, 0x20, 0x15, 0x00, 0xd5, 0x98,\n\t0x1b, 0x54, 0x01, 0xa8, 0x2a, 0x48, 0xa4, 0xac, 0x64, 0x30, 0x13, 0x48, 0x39, 0x20, 0xd3, 0x48, 0x65, 0x83, 0x3a, 0xa0, 0xd1, 0x03, 0xad, 0x41, 0xa3, 0x1d, 0x34, 0x01, 0x83, 0x19, 0x18, 0x1d, 0x06, 0xe3, 0xa0, 0x0d, 0x58, 0xec, 0xc0, 0xea, 0xb4, 0x58, 0x07, 0x09, 0x07, 0xe1, 0x74, 0x38, 0x17, 0x65, 0x00, 0x24, 0xe6, 0x94, 0x50, 0xcc, 0xad, 0x42, 0x43, 0xbd, 0xf0, 0xd2, 0x47, 0xc3, 0x73, 0x08, 0x09, 0x0c, 0x0a, 0xba, 0xef, 0xfa, 0x12, 0xc2, 0x61, 0x75, 0x3a, 0xba, 0xd3, 0x5f, 0xe5, 0x70, 0xf6, 0xa1, 0xb7, 0x41, 0xc9, 0x58, 0xf6, 0xd3, 0x67, 0x7e, 0x74, 0xf6, 0x87, 0x8f, 0x9e, 0x7e, 0xe8, 0xbe, 0x7b, 0xee, 0xfc, 0xfe, 0x6d, 0xb7, 0x1c, 0xbb, 0xe9, 0xc8, 0xe1, 0x83, 0x07, 0xf6, 0xee, 0xde, 0xb1, 0x6d, 0xd3, 0x86, 0x35, 0xab, 0x96, 0x2f, 0x1b, 0x5a, 0xb2, 0xb0, 0xbf,\n\t0xa7, 0x6b, 0xf6, 0xac, 0xd6, 0xe6, 0xc6, 0xfa, 0x44, 0x55, 0x59, 0x89, 0x4f, 0xfc, 0xe3, 0x71, 0xa1, 0xc8, 0x1a, 0x84, 0xbb, 0x6d, 0xc0, 0xe8, 0x36, 0x01, 0xe3, 0xff, 0xf1, 0x7b, 0xfa, 0xbd, 0x92, 0xef, 0xf0, 0x9d, 0x49, 0xfb, 0xee, 0xff, 0xff, 0x71, 0x3c, 0xbd, 0x0d, 0x64, 0x9f, 0xd7, 0x6c, 0xf1, 0xf9, 0x2c, 0x66, 0xef, 0x59, 0x9f, 0xd9, 0xe2, 0xf5, 0x5a, 0xcc, 0xbe, 0x3b, 0xd0, 0x3f, 0xe8, 0xc7, 0xb0, 0xcf, 0x8c, 0xbe, 0x98, 0x7d, 0x59, 0xc9, 0x2f, 0x63, 0x83, 0xc9, 0x6f, 0xb7, 0x27, 0x6f, 0x1b, 0x49, 0x5e, 0xed, 0x4f, 0xde, 0x4f, 0xdd, 0x96, 0xbc, 0xe8, 0xe2, 0xb5, 0xc9, 0x93, 0x54, 0x66, 0xf2, 0xdb, 0x58, 0x77, 0xf2, 0x4e, 0x52, 0x99, 0xbc, 0x83, 0xbf, 0x3e, 0x79, 0xc7, 0x4f, 0x92, 0x27, 0xe9, 0x15, 0xc2, 0x29, 0x9f, 0x42, 0xb8, 0xcd, 0xdb, 0x26, 0xfe, 0xde,\n\t0x8b, 0x7f, 0xfb, 0x7c, 0x77, 0x89, 0xbf, 0xc1, 0x5b, 0xdf, 0x72, 0xc1, 0xf7, 0xc5, 0x4f, 0xf1, 0x5d, 0xbe, 0x7d, 0x69, 0xdf, 0xd1, 0x67, 0x8b, 0x78, 0xbd, 0x45, 0xfc, 0xcc, 0x14, 0x3f, 0x51, 0x7d, 0x97, 0xf1, 0x4f, 0x18, 0x03, 0xf3, 0x30, 0x9c, 0xfd, 0xbb, 0x5b, 0x1e, 0x75, 0xc1, 0x59, 0xae, 0xce, 0x85, 0x13, 0x31, 0x84, 0xea, 0x34, 0xa3, 0xc0, 0x60, 0x04, 0xf7, 0x88, 0x8e, 0xb0, 0xe2, 0x11, 0xa8, 0x51, 0x23, 0xac, 0x47, 0x17, 0x2e, 0x34, 0x81, 0x40, 0x52, 0x50, 0x64, 0xe7, 0x8a, 0x16, 0xc1, 0x9f, 0xc2, 0x00, 0x2c, 0x82, 0xad, 0x89, 0x60, 0x2a, 0x10, 0x9a, 0x65, 0x31, 0x32, 0x51, 0x32, 0x17, 0x4e, 0xe4, 0x57, 0x49, 0x61, 0x0d, 0x37, 0xfc, 0x9c, 0x3e, 0xe8, 0xf6, 0x87, 0x05, 0x53, 0x87, 0xe8, 0xa4, 0xe6, 0xd2, 0x61, 0xcf, 0xb1, 0xba, 0xc6, 0x25, 0x83, 0x03, 0x92,\n\t0x70, 0x29, 0xfb, 0x2a, 0x56, 0xad, 0xda, 0x50, 0x3b, 0x74, 0xff, 0x96, 0xda, 0xf2, 0x0d, 0x0f, 0xaf, 0xae, 0xe8, 0xc9, 0xb5, 0xb2, 0x66, 0x55, 0x46, 0x3c, 0xb6, 0x73, 0xab, 0x7f, 0xe6, 0xaa, 0xa6, 0x9a, 0xd5, 0x4b, 0x7a, 0xb3, 0xde, 0xba, 0x4d, 0xe3, 0x22, 0xe9, 0x57, 0x6b, 0xbb, 0x0a, 0x75, 0x33, 0x77, 0x3f, 0x32, 0x3c, 0xf6, 0xde, 0xf2, 0x7b, 0xd7, 0x96, 0x6b, 0x74, 0x83, 0x26, 0x95, 0x7a, 0xc7, 0x41, 0xb2, 0xa0, 0x71, 0x4d, 0x7b, 0x96, 0xbb, 0xa2, 0x3b, 0x7e, 0xe1, 0x3c, 0x73, 0xc2, 0x63, 0x49, 0xd6, 0xba, 0x39, 0x8e, 0x69, 0x91, 0x4f, 0xbc, 0x24, 0x48, 0x2b, 0x75, 0x3e, 0xa4, 0x45, 0x16, 0xdc, 0x52, 0x24, 0x69, 0x21, 0x92, 0x28, 0xfd, 0x30, 0x85, 0x49, 0x04, 0x8f, 0xb0, 0x69, 0x47, 0x7a, 0x7b, 0x85, 0x07, 0xd8, 0xd2, 0x68, 0x84, 0x3b, 0x9f, 0x74, 0x3c, 0x81,\n\t0x35, 0x38, 0xb6, 0xdc, 0x25, 0xc4, 0x96, 0x33, 0x68, 0xc5, 0xaf, 0x99, 0x7a, 0x6d, 0x92, 0x50, 0x6b, 0x44, 0x92, 0x8a, 0x57, 0x7d, 0x03, 0x49, 0xd7, 0x60, 0x7c, 0x4b, 0x44, 0x53, 0xef, 0x37, 0xd1, 0x54, 0x00, 0xb4, 0xfc, 0x6e, 0x44, 0x65, 0xb5, 0xf6, 0xa0, 0xf5, 0xf2, 0x64, 0xbd, 0xb8, 0x7b, 0xf9, 0x3d, 0x88, 0xac, 0x4b, 0xcc, 0x2a, 0x86, 0x65, 0x76, 0x1c, 0xa4, 0xae, 0xbf, 0x84, 0xb0, 0x80, 0x18, 0x80, 0xba, 0xd0, 0x17, 0x90, 0xae, 0x25, 0xc4, 0xfd, 0x09, 0x45, 0xd4, 0x0f, 0xe7, 0x86, 0x1c, 0xbb, 0x9d, 0x05, 0x4d, 0x28, 0x2c, 0xa0, 0x37, 0x43, 0x0d, 0x3f, 0x29, 0xfd, 0x06, 0x85, 0xca, 0x6b, 0xe2, 0x57, 0xd1, 0x5d, 0xb0, 0x92, 0x48, 0x12, 0xec, 0x3b, 0xde, 0x80, 0xf2, 0x7f, 0x20, 0xd9, 0x26, 0xae, 0xc5, 0x52, 0x52, 0xa8, 0xea, 0x26, 0x66, 0x04, 0x4e, 0x5c, 0x89,\n\t0xc8, 0x16, 0xe2, 0xf4, 0x61, 0x7f, 0x70, 0x92, 0xd5, 0x4d, 0xa4, 0x17, 0x2d, 0xa8, 0x8b, 0x93, 0x09, 0xe6, 0x4c, 0xd1, 0x96, 0xfe, 0xa2, 0xfb, 0xc4, 0xbb, 0xfb, 0x16, 0x9f, 0x3e, 0xb6, 0x35, 0xda, 0xa0, 0xca, 0x94, 0x67, 0x66, 0x95, 0x36, 0x2f, 0xda, 0xd2, 0xd2, 0x7d, 0xed, 0x40, 0x91, 0x40, 0xb6, 0xc1, 0xde, 0xac, 0x37, 0x6f, 0xd5, 0xb8, 0x01, 0x55, 0x89, 0x08, 0x3c, 0x7c, 0xff, 0xe6, 0x5a, 0x92, 0xdd, 0xf7, 0xf3, 0x03, 0xf5, 0xbe, 0xca, 0x39, 0x79, 0x03, 0x3a, 0xa5, 0x2d, 0x9c, 0x17, 0xb6, 0x65, 0x77, 0xef, 0x9a, 0x03, 0x7e, 0x9b, 0x24, 0x1e, 0xaf, 0xa1, 0xae, 0xf4, 0x58, 0x8e, 0x43, 0x2a, 0xeb, 0x11, 0x95, 0x79, 0xa1, 0x26, 0xd5, 0xc3, 0xe3, 0xe7, 0xa9, 0x3f, 0x41, 0xa5, 0x28, 0x4c, 0xbc, 0xd1, 0xf2, 0x68, 0x36, 0xa4, 0x84, 0x8a, 0x10, 0x93, 0x25, 0xb8, 0xe4,\n\t0xf4, 0xcc, 0x9b, 0x7c, 0x94, 0xc1, 0x0b, 0x18, 0x1d, 0x60, 0x27, 0x0e, 0xa0, 0xc9, 0x29, 0x9b, 0xb4, 0x80, 0x57, 0x4d, 0x59, 0xc0, 0xc2, 0xd3, 0xa7, 0x3f, 0x2f, 0x24, 0x45, 0xe4, 0x4d, 0x9a, 0xdc, 0xab, 0xa6, 0x4c, 0xee, 0xd5, 0x42, 0xdd, 0x11, 0x5c, 0xe5, 0x41, 0x9c, 0xa9, 0xd3, 0x5c, 0x82, 0x33, 0x21, 0x38, 0xad, 0xdf, 0x9d, 0x24, 0x7a, 0x6a, 0xae, 0xb2, 0x53, 0x97, 0x7f, 0x40, 0x2c, 0x5b, 0x89, 0xe7, 0xe9, 0x50, 0xa4, 0xad, 0xa5, 0x35, 0x6b, 0xc6, 0x96, 0xae, 0xbc, 0xc7, 0xee, 0x8b, 0x26, 0xbc, 0x26, 0x46, 0xaf, 0x54, 0x78, 0xdd, 0xed, 0x1d, 0xf3, 0x17, 0xcc, 0xdd, 0x5e, 0xfc, 0xec, 0xc1, 0x4c, 0x3b, 0xa0, 0xd6, 0x47, 0x4b, 0x5c, 0x8a, 0x78, 0xff, 0xce, 0x46, 0xfe, 0xfa, 0x93, 0x0f, 0xaa, 0xd4, 0x3d, 0xba, 0x0c, 0x59, 0x6b, 0x3f, 0xd8, 0xd1, 0x3b, 0xd4, 0xd9,\n\t0x38, 0x56, 0x44, 0x7d, 0x65, 0x37, 0x88, 0xf4, 0xa4, 0x45, 0x7a, 0x2e, 0x4c, 0xa8, 0x9c, 0x50, 0xec, 0x1a, 0xa1, 0xd2, 0xcd, 0xa2, 0x10, 0xe4, 0x66, 0xa1, 0x87, 0x66, 0xa1, 0x48, 0x13, 0xb1, 0x28, 0x35, 0xd3, 0x96, 0xb6, 0xa4, 0x82, 0xdc, 0x53, 0xe7, 0xf0, 0x51, 0x71, 0x7a, 0xad, 0x12, 0xcf, 0xe3, 0xe9, 0x84, 0xba, 0xe6, 0x41, 0x3d, 0xf3, 0x7f, 0x63, 0x8f, 0x52, 0x13, 0x89, 0xfa, 0xd3, 0xe5, 0x3a, 0x44, 0xa2, 0x2e, 0x47, 0x50, 0x97, 0x5b, 0x4e, 0x3e, 0x90, 0xa1, 0xee, 0x36, 0x28, 0x65, 0xad, 0x7d, 0xe4, 0xea, 0x89, 0xfe, 0xcc, 0x49, 0x76, 0x18, 0xd7, 0x2e, 0x1b, 0xff, 0x9c, 0x3a, 0x07, 0xfb, 0x95, 0x4b, 0xfc, 0x2c, 0x6d, 0x46, 0xc0, 0xed, 0x37, 0xad, 0x47, 0xfe, 0xa6, 0xe4, 0x8c, 0x98, 0x38, 0xd0, 0x9b, 0x5c, 0x89, 0x53, 0x39, 0x11, 0x1e, 0xb5, 0xd4, 0xd7, 0x09,\n\t0xc6, 0x2d, 0xce, 0x80, 0xef, 0x78, 0xc3, 0xea, 0xc9, 0x0c, 0x2c, 0x7d, 0x46, 0xb0, 0xbd, 0xc2, 0x2c, 0x49, 0x4f, 0x90, 0xc1, 0x93, 0xc2, 0x1b, 0x9c, 0x8e, 0x81, 0xa5, 0x56, 0x24, 0x39, 0xcd, 0xbc, 0xa8, 0x17, 0x88, 0xb4, 0xb9, 0x2b, 0xaf, 0x6a, 0xed, 0x9d, 0x83, 0x4d, 0xbb, 0x57, 0xf6, 0xba, 0xab, 0x32, 0x54, 0x52, 0x5d, 0x61, 0xdb, 0xaa, 0x59, 0x9b, 0xb7, 0xce, 0x5f, 0x30, 0x67, 0x47, 0xf1, 0xb3, 0x87, 0x32, 0x6d, 0xe9, 0xb3, 0xe3, 0x97, 0x03, 0x37, 0x0e, 0x16, 0x58, 0xa2, 0x95, 0xde, 0x2e, 0x4e, 0x1e, 0xca, 0x0f, 0xad, 0x5d, 0x0e, 0xaa, 0x10, 0x4d, 0xf9, 0x33, 0xe4, 0x6e, 0x71, 0x8e, 0xb4, 0xf3, 0x0f, 0x81, 0xe7, 0xa8, 0x2f, 0x09, 0x3b, 0xd1, 0xfe, 0x44, 0x06, 0x9c, 0xfe, 0x33, 0x05, 0xfb, 0x85, 0x81, 0xc0, 0xc5, 0x57, 0xd0, 0xae, 0x04, 0x39, 0x20, 0x92, 0x38,\n\t0x81, 0x28, 0xf7, 0x01, 0xfe, 0x86, 0xd3, 0x68, 0xcd, 0xc4, 0x05, 0xc4, 0xc4, 0xf9, 0xde, 0xa7, 0xbc, 0x61, 0x4e, 0x2f, 0xa4, 0xd7, 0x62, 0x18, 0x19, 0x8c, 0x29, 0x8a, 0x2a, 0xa1, 0x61, 0x20, 0x48, 0x01, 0x76, 0xd4, 0x08, 0x9e, 0x73, 0x2e, 0x2c, 0xea, 0x1b, 0x6e, 0xad, 0x2a, 0x79, 0x91, 0xd3, 0x85, 0xdd, 0xfa, 0xdc, 0xa0, 0xc1, 0xae, 0x55, 0x32, 0x6a, 0x86, 0x7f, 0xcf, 0x68, 0xeb, 0xa8, 0x2d, 0x1d, 0x0e, 0xa2, 0xfa, 0xe3, 0x0a, 0x47, 0x20, 0x6a, 0xf6, 0x66, 0x49, 0x24, 0x12, 0x54, 0x63, 0x2e, 0x4e, 0x5d, 0x4b, 0x9e, 0x62, 0xb7, 0xc0, 0xcd, 0x6f, 0x43, 0xa2, 0x56, 0x0b, 0x99, 0x1e, 0x36, 0x9c, 0x34, 0x27, 0x8b, 0x3e, 0xc2, 0x01, 0x41, 0x99, 0x6a, 0xab, 0x92, 0x5b, 0xa8, 0xee, 0x54, 0x19, 0x86, 0x1e, 0x94, 0xef, 0x17, 0xf4, 0xdb, 0xad, 0x26, 0x03, 0xa7, 0x86, 0x5b,\n\t0xc9, 0x28, 0x88, 0x4a, 0x64, 0x28, 0x26, 0xef, 0xbb, 0x61, 0xc2, 0x91, 0x73, 0xbe, 0x3b, 0xd2, 0x5b, 0xf3, 0xb7, 0x43, 0xb8, 0x09, 0xf5, 0x4a, 0xa9, 0xa3, 0x64, 0x8c, 0x5d, 0x43, 0xc8, 0x50, 0xdc, 0x55, 0xb2, 0x8a, 0x1c, 0x2a, 0x5b, 0x89, 0x83, 0x94, 0x3a, 0x10, 0xdf, 0x9e, 0x85, 0x43, 0x08, 0x64, 0x84, 0x0c, 0x85, 0x40, 0xb1, 0x32, 0xb8, 0x69, 0x48, 0x82, 0x1c, 0xea, 0x2f, 0x00, 0x29, 0xff, 0xe5, 0xf7, 0xc0, 0x7f, 0x31, 0x5f, 0xfc, 0x7c, 0x1b, 0xff, 0x1e, 0xf9, 0xde, 0x56, 0x6c, 0x8f, 0x8a, 0x53, 0x12, 0xaa, 0x05, 0xd2, 0x47, 0x0d, 0x57, 0x7b, 0xe7, 0xd9, 0xb0, 0x9e, 0xa4, 0x30, 0x68, 0xba, 0x1f, 0xfb, 0xd4, 0x00, 0xc0, 0xd1, 0xa5, 0xdd, 0x28, 0x47, 0x02, 0xef, 0xb7, 0x7b, 0xd0, 0x3b, 0xe6, 0xa2, 0x8d, 0xb8, 0x85, 0x20, 0x29, 0x72, 0xfd, 0x34, 0x57, 0x50, 0x70,\n\t0x30, 0x43, 0x3e, 0x5f, 0xc0, 0xc3, 0xc8, 0x26, 0x32, 0x3c, 0xc4, 0x54, 0x69, 0x6c, 0x4b, 0x9c, 0x92, 0xe5, 0xc1, 0x4a, 0x5e, 0xdf, 0xb4, 0x6c, 0x64, 0xa3, 0xa3, 0x74, 0x76, 0x61, 0xd1, 0xec, 0x52, 0x27, 0xb9, 0x63, 0x87, 0x35, 0xa2, 0x19, 0xcc, 0x2b, 0x9e, 0x7b, 0xed, 0x92, 0x78, 0x7c, 0xc9, 0xb5, 0x73, 0xe7, 0x5e, 0xb3, 0x24, 0xde, 0xda, 0xc0, 0x80, 0xf5, 0xbb, 0x77, 0xaf, 0x17, 0x61, 0xeb, 0xc6, 0x5e, 0x53, 0xeb, 0xae, 0x50, 0xa6, 0xe3, 0xd9, 0x0d, 0x9c, 0x40, 0xf9, 0x72, 0x59, 0x70, 0xac, 0x5d, 0xb0, 0x2f, 0x71, 0x54, 0x8b, 0x24, 0x0e, 0xc7, 0xd9, 0x8a, 0xac, 0xd5, 0x97, 0x94, 0xa0, 0x11, 0x41, 0xaf, 0xbb, 0x53, 0xfb, 0xe6, 0x1e, 0xb2, 0x35, 0xea, 0x0d, 0x46, 0x7d, 0x90, 0x60, 0x96, 0xcb, 0xe1, 0x5d, 0xa7, 0x97, 0x9a, 0x49, 0x01, 0x5e, 0x83, 0x8f, 0x33, 0xf4,\n\t0x0a, 0xb3, 0x27, 0xea, 0x88, 0x15, 0xe5, 0x37, 0x77, 0x35, 0xe7, 0x7b, 0x6a, 0x07, 0x2a, 0xbd, 0x0d, 0x89, 0x12, 0x7d, 0x36, 0xa3, 0x51, 0xa8, 0x1c, 0xc1, 0x22, 0x7f, 0xac, 0x0c, 0x9f, 0x70, 0x55, 0xcf, 0x2f, 0xaf, 0x5d, 0x1b, 0x64, 0xfe, 0x68, 0x50, 0x6b, 0xd5, 0xd1, 0x80, 0xcb, 0x6b, 0xb1, 0xe6, 0x34, 0x57, 0x16, 0xf4, 0xd4, 0x04, 0x54, 0x66, 0x9f, 0xbe, 0x59, 0xaa, 0xd0, 0x99, 0x74, 0x39, 0x79, 0x3e, 0xbf, 0xd9, 0x94, 0xd3, 0x51, 0x1f, 0x6e, 0xaf, 0xf0, 0x85, 0x91, 0x0e, 0x9a, 0x01, 0xc7, 0xfb, 0xcf, 0x70, 0xbc, 0x35, 0x28, 0x9a, 0x59, 0x81, 0xe3, 0xec, 0xe0, 0xae, 0x19, 0x80, 0x0e, 0x44, 0xed, 0x59, 0x62, 0x26, 0x3c, 0xe7, 0xe6, 0x68, 0x19, 0x8a, 0x8c, 0xf2, 0x4e, 0x01, 0x84, 0x2c, 0x24, 0xff, 0xcc, 0xbf, 0x73, 0x90, 0x7f, 0x67, 0xab, 0xce, 0xcc, 0xdc, 0x29,\n\t0xd5, 0x48, 0x25, 0x99, 0xd2, 0x93, 0x8c, 0x59, 0xcb, 0xae, 0x19, 0xf3, 0x92, 0xef, 0x69, 0xd5, 0xfc, 0x62, 0x4b, 0x85, 0xdb, 0x5d, 0x61, 0x01, 0x27, 0x33, 0xf4, 0xf0, 0x5d, 0x66, 0xf8, 0xae, 0x5f, 0xc0, 0x77, 0x59, 0x11, 0x1e, 0x9a, 0x55, 0xa7, 0x82, 0xab, 0x42, 0x48, 0xdd, 0x22, 0x3b, 0x5a, 0x10, 0x43, 0x87, 0xaf, 0x0b, 0x69, 0xb2, 0x50, 0xb1, 0x4b, 0xb1, 0x60, 0x4c, 0x12, 0x9a, 0x55, 0x8b, 0x23, 0x0f, 0xb5, 0xf1, 0x6a, 0x10, 0x2f, 0x87, 0x4c, 0xf3, 0x17, 0x37, 0xab, 0xb5, 0xcc, 0x49, 0xc8, 0xd2, 0x6e, 0x61, 0x34, 0xaa, 0xeb, 0x3e, 0xfe, 0x9f, 0x9b, 0xd5, 0x2a, 0xe6, 0x24, 0x2b, 0xbb, 0x56, 0xae, 0xbf, 0xe1, 0xaf, 0xd4, 0x51, 0xb5, 0x02, 0xa8, 0xd8, 0x0c, 0xe6, 0x73, 0x79, 0x26, 0xd8, 0x02, 0x86, 0xa5, 0x72, 0xfe, 0x82, 0x9e, 0x7b, 0x4f, 0xc7, 0x9f, 0xc2, 0x7a,\n\t0x26, 0xe4, 0xce, 0x47, 0xc9, 0xbb, 0x60, 0x1b, 0x74, 0xa8, 0x4a, 0xa2, 0x92, 0x22, 0xa8, 0x24, 0x28, 0x5b, 0xb2, 0xc3, 0xd9, 0x1e, 0x8e, 0x92, 0x19, 0x05, 0x74, 0x7c, 0x2c, 0x20, 0x70, 0x67, 0xc5, 0x44, 0xb6, 0x9b, 0x6f, 0xe6, 0x3f, 0xdf, 0xaf, 0x33, 0x4a, 0x76, 0xca, 0x39, 0x09, 0x9b, 0x29, 0xdf, 0x05, 0xfb, 0x7a, 0x80, 0x7e, 0x90, 0xff, 0x5f, 0x60, 0x02, 0xff, 0xa1, 0xc9, 0xfc, 0x93, 0x31, 0xa4, 0xd3, 0x85, 0x8c, 0x7f, 0xca, 0x10, 0xeb, 0x49, 0x45, 0xe0, 0xbb, 0x86, 0xe1, 0xbb, 0x32, 0x44, 0xc4, 0x91, 0xe4, 0x12, 0x12, 0xb3, 0x7d, 0x67, 0x81, 0x56, 0x4e, 0xc7, 0x69, 0x71, 0x77, 0x75, 0x12, 0x21, 0xcc, 0xaf, 0x18, 0xb8, 0x63, 0x6e, 0x72, 0x58, 0xcd, 0xdf, 0x0a, 0x56, 0x8e, 0xfd, 0x2a, 0x03, 0x2c, 0xe3, 0xef, 0x21, 0xdd, 0x6c, 0xb1, 0xd1, 0xc8, 0xd3, 0xdb, 0x2a,\n\t0x0c, 0x3a, 0xc0, 0x6f, 0x25, 0xc0, 0xd8, 0x23, 0x2c, 0x4b, 0xce, 0x66, 0x6f, 0xfb, 0xa6, 0x3c, 0x1b, 0xf4, 0xb4, 0xb1, 0x47, 0xe8, 0x7b, 0x2e, 0xf4, 0xb3, 0xb7, 0x1d, 0x23, 0x70, 0xf4, 0xe4, 0x2d, 0xe0, 0x2d, 0xb6, 0xfd, 0x1b, 0xef, 0x81, 0xac, 0x10, 0x34, 0x1f, 0x3e, 0xcc, 0xb6, 0xf3, 0x18, 0xa1, 0x80, 0xf8, 0x31, 0x7d, 0x0b, 0x39, 0x82, 0xef, 0xc1, 0x35, 0x25, 0x49, 0x21, 0x1d, 0x84, 0x4c, 0x4b, 0x07, 0x49, 0xaf, 0x29, 0x89, 0x6e, 0xff, 0xf1, 0x75, 0xd7, 0x01, 0xf7, 0x75, 0xd7, 0xa1, 0x27, 0x80, 0xb3, 0xf0, 0x29, 0xe4, 0xf8, 0x5b, 0xf4, 0x61, 0x72, 0x3d, 0x73, 0x1a, 0xb2, 0x0b, 0x3d, 0x8a, 0x48, 0xc2, 0xf0, 0x77, 0x7d, 0xa8, 0x5a, 0x3c, 0x54, 0xa0, 0x41, 0xab, 0x5c, 0x0e, 0x08, 0xb9, 0x5e, 0xae, 0xd7, 0x64, 0x0a, 0x0e, 0x1e, 0x5c, 0x9c, 0x29, 0xe5, 0x6f, 0xf2,\n\t0xe2, 0xb8, 0x02, 0xc1, 0xf5, 0x74, 0xab, 0xd7, 0x9b, 0x71, 0x75, 0xa7, 0xd1, 0x91, 0xf1, 0xd2, 0x13, 0x38, 0xa4, 0xe0, 0xf1, 0x05, 0x46, 0xbb, 0xea, 0x3c, 0x73, 0x1a, 0xb9, 0x98, 0x38, 0x40, 0xa2, 0x48, 0x02, 0xfc, 0x05, 0xf9, 0x9a, 0xee, 0x63, 0xe5, 0xe4, 0x11, 0x89, 0x15, 0xe5, 0x5f, 0x11, 0xd1, 0x44, 0x16, 0x03, 0x95, 0x5e, 0x1c, 0x71, 0x88, 0xbf, 0x10, 0xa0, 0x0f, 0xb7, 0x1d, 0x3b, 0x98, 0x32, 0x55, 0x72, 0xad, 0x42, 0x2b, 0xbe, 0x9b, 0x9d, 0x78, 0x77, 0x2e, 0xf0, 0xa6, 0xbe, 0x81, 0x3b, 0xbd, 0x11, 0xd5, 0x4d, 0x0b, 0x8d, 0xd6, 0xcc, 0x5f, 0xfe, 0xc5, 0x1b, 0xe5, 0x7e, 0x3c, 0x6a, 0x74, 0x73, 0x17, 0x24, 0x56, 0xa3, 0xf1, 0xcf, 0x99, 0xaa, 0xcf, 0x4c, 0x86, 0x3f, 0xab, 0xd5, 0x9f, 0xa5, 0x7c, 0x0a, 0x37, 0xc2, 0x5e, 0x86, 0xd1, 0x3b, 0x91, 0x83, 0x95, 0x44,\n\t0x0e, 0xd6, 0xc9, 0x5e, 0x37, 0x40, 0x04, 0x7c, 0x36, 0xcb, 0x84, 0xe3, 0x40, 0x32, 0xbd, 0xe3, 0x60, 0x8a, 0x45, 0x7a, 0x1a, 0x77, 0x41, 0x50, 0xe7, 0x8d, 0x22, 0xb8, 0x5d, 0x9d, 0xce, 0x9d, 0x6d, 0x36, 0x47, 0xbd, 0xba, 0x69, 0x7c, 0x04, 0x07, 0xcd, 0xd9, 0x1e, 0x9d, 0xce, 0x03, 0xcf, 0xe7, 0xa0, 0xcf, 0x1c, 0x62, 0xc2, 0xf7, 0x83, 0x30, 0x45, 0xfc, 0x28, 0x4f, 0x83, 0xc1, 0x15, 0x5c, 0x10, 0xfe, 0x5c, 0xd2, 0x6f, 0x33, 0xe1, 0x87, 0x63, 0xb1, 0x1f, 0x4e, 0xaf, 0x73, 0xbb, 0x1c, 0x36, 0x8b, 0x59, 0xe7, 0xd7, 0xfb, 0x43, 0x50, 0x2d, 0x30, 0x5c, 0x92, 0x9b, 0x3f, 0xd5, 0x81, 0x49, 0x6a, 0xa6, 0x36, 0x6e, 0xef, 0x24, 0x9b, 0xbe, 0xe4, 0x80, 0x39, 0x8a, 0xce, 0xc1, 0x6b, 0x72, 0xd0, 0x67, 0x0e, 0xbf, 0x74, 0xb2, 0x27, 0x13, 0xad, 0x9d, 0xcd, 0xf4, 0xed, 0xe4, 0x83,\n\t0x70, 0xdf, 0xa2, 0x47, 0x11, 0x20, 0x28, 0x11, 0x5a, 0x0c, 0x5e, 0x42, 0xe1, 0x31, 0x2b, 0x48, 0x48, 0xc8, 0x09, 0x22, 0x0a, 0x15, 0xb3, 0x1d, 0xc8, 0x87, 0x90, 0xe6, 0x4c, 0x00, 0x37, 0x74, 0xac, 0xa8, 0xb5, 0x5f, 0x93, 0xe1, 0x2e, 0xce, 0xca, 0x2a, 0x76, 0x67, 0x5c, 0x63, 0xaf, 0x5d, 0xc1, 0x3c, 0x1c, 0x69, 0x19, 0x2c, 0x4e, 0xd2, 0xa8, 0x78, 0xb0, 0x45, 0xc8, 0x87, 0x03, 0x3e, 0xba, 0x93, 0xd4, 0xb2, 0x99, 0x84, 0x19, 0x45, 0xc8, 0x9a, 0xa7, 0x09, 0x0c, 0xf5, 0x35, 0xe3, 0xf5, 0x91, 0x2c, 0x56, 0xcc, 0x7a, 0x04, 0xed, 0x41, 0xb0, 0x72, 0x48, 0x40, 0xa7, 0x52, 0xca, 0x48, 0x4d, 0x66, 0x23, 0xfc, 0x97, 0x29, 0x4a, 0x24, 0xe2, 0x15, 0x95, 0xdd, 0xb3, 0xe8, 0x15, 0xb2, 0x4c, 0x26, 0x83, 0x95, 0x59, 0x7d, 0x11, 0x33, 0xa8, 0x8f, 0xe5, 0xd6, 0xcc, 0xad, 0xed, 0xf8,\n\t0x5e, 0x9d, 0xf0, 0x3e, 0x15, 0xdd, 0x09, 0xc6, 0xe0, 0xfb, 0xac, 0x68, 0x55, 0x69, 0xa7, 0x79, 0x9f, 0xc5, 0x54, 0x8f, 0xcb, 0xe4, 0x21, 0x42, 0x67, 0x81, 0xa0, 0x83, 0xc2, 0xe9, 0x97, 0x6a, 0x80, 0xb1, 0xf4, 0xe1, 0x5b, 0xc1, 0x18, 0xe7, 0x8c, 0x98, 0x19, 0x19, 0x23, 0x31, 0x99, 0xcd, 0x52, 0x54, 0xfb, 0x6e, 0x56, 0x57, 0x65, 0x45, 0xac, 0x86, 0xb9, 0xd3, 0x12, 0x75, 0x69, 0x80, 0x39, 0xe2, 0xb3, 0xca, 0x20, 0x0b, 0x54, 0xcb, 0x2d, 0x75, 0xdf, 0xeb, 0xa8, 0x9d, 0x5b, 0x03, 0x9f, 0x79, 0x0b, 0x2f, 0x25, 0xd7, 0x8d, 0xbf, 0x2a, 0x64, 0x9a, 0xa1, 0x42, 0x98, 0x08, 0x3f, 0x4c, 0x4c, 0x11, 0x41, 0xf1, 0xcc, 0xa8, 0xf0, 0x14, 0x21, 0xe1, 0x04, 0x80, 0x03, 0x86, 0x13, 0x10, 0x80, 0xc9, 0x75, 0xd7, 0x22, 0x54, 0xe2, 0x22, 0xbe, 0xe2, 0xd4, 0x2e, 0x81, 0x7f, 0xa6, 0x3d,\n\t0x27, 0x55, 0xc1, 0x60, 0x01, 0x52, 0xb2, 0xc4, 0x6a, 0x96, 0x49, 0x86, 0x00, 0x50, 0x05, 0x8d, 0x42, 0xbd, 0x9b, 0x5c, 0xc7, 0x3f, 0x76, 0xed, 0xb5, 0xa0, 0x83, 0x7f, 0xf8, 0x14, 0x78, 0xf1, 0x14, 0xba, 0x9f, 0x3e, 0x40, 0xae, 0x63, 0x9b, 0xe1, 0xfa, 0x70, 0xa0, 0x1c, 0xfe, 0x69, 0xb2, 0x55, 0x26, 0xe5, 0xaa, 0x08, 0x2d, 0x78, 0x97, 0x3e, 0x00, 0x1a, 0xae, 0xc4, 0xef, 0xbf, 0x09, 0xbe, 0x7f, 0x0b, 0x7e, 0x7f, 0x08, 0x45, 0x36, 0x88, 0x38, 0x0d, 0xa8, 0xce, 0x60, 0x0a, 0xaf, 0x01, 0x20, 0x30, 0xa9, 0xb4, 0xde, 0x00, 0x0c, 0xd7, 0x50, 0xc8, 0x91, 0x5b, 0x78, 0xcb, 0x99, 0xc3, 0xfc, 0x81, 0x5d, 0xbb, 0x40, 0x23, 0xff, 0xf4, 0xa4, 0xbe, 0x40, 0x79, 0x24, 0xc2, 0xa9, 0x43, 0xba, 0xcc, 0xc3, 0xfd, 0x21, 0x91, 0x87, 0x3a, 0xc5, 0xe0, 0x18, 0xaf, 0x10, 0xe0, 0x4d, 0xae,\n\t0xbb, 0xff, 0xf0, 0xfd, 0xe0, 0xdd, 0xc7, 0xf9, 0x9f, 0xe0, 0x06, 0x4d, 0x3c, 0x43, 0x81, 0x9f, 0x81, 0xe0, 0xc6, 0xc1, 0x02, 0x64, 0x36, 0xc7, 0x0f, 0x10, 0x29, 0x92, 0x0a, 0x14, 0xd7, 0x7b, 0x45, 0x23, 0x6f, 0x21, 0x7e, 0x0e, 0xfc, 0x1f, 0xd2, 0x05, 0x92, 0x36, 0x45, 0xdb, 0x87, 0xe1, 0xb3, 0xc2, 0xc9, 0x7a, 0xbf, 0xa9, 0xe2, 0xa5, 0x02, 0x7b, 0x46, 0x66, 0xe4, 0x5b, 0xc0, 0xbb, 0x7c, 0xe0, 0xb7, 0xbb, 0xe0, 0xb5, 0xab, 0xf8, 0x83, 0x64, 0xcd, 0xf8, 0x3f, 0x08, 0x03, 0x92, 0x2d, 0x72, 0x11, 0x55, 0x06, 0x99, 0x7b, 0x27, 0x6c, 0x1c, 0x59, 0x7e, 0x4c, 0x48, 0xa6, 0x70, 0x9a, 0x5a, 0x76, 0xe0, 0x91, 0xa3, 0x8e, 0x8a, 0xfe, 0xca, 0x96, 0x0d, 0xee, 0x7e, 0xb9, 0x8a, 0x96, 0xab, 0xf5, 0x2e, 0x6b, 0x76, 0xa1, 0x6e, 0x34, 0xbf, 0xaf, 0x21, 0xab, 0x75, 0x9e, 0x8f, 0x06,\n\t0x7a, 0x8b, 0xbe, 0xaa, 0x18, 0xb5, 0xe9, 0x15, 0xf8, 0x9e, 0xef, 0xe3, 0xf7, 0x40, 0xee, 0xad, 0xc4, 0xfa, 0x01, 0x21, 0x38, 0xed, 0x85, 0xf8, 0x71, 0xac, 0xdc, 0xac, 0x21, 0x5b, 0xf5, 0xbe, 0x42, 0x0f, 0x26, 0x54, 0x52, 0x93, 0x4e, 0x01, 0xf8, 0x57, 0x82, 0x42, 0xb0, 0xa0, 0x28, 0x62, 0x75, 0xe9, 0x33, 0xe5, 0x74, 0x86, 0x7c, 0x81, 0x7b, 0x63, 0x0b, 0x4a, 0x96, 0xb9, 0x69, 0x67, 0x71, 0x15, 0x7c, 0x0b, 0xa0, 0x7d, 0xf3, 0x5a, 0xb3, 0x1a, 0xfa, 0xf2, 0x47, 0x05, 0xdf, 0xe5, 0x39, 0x3e, 0x9f, 0x5c, 0x38, 0x8e, 0xec, 0xd5, 0x4e, 0xa2, 0x5a, 0xa8, 0x2a, 0xa9, 0x9d, 0x30, 0x5a, 0x0b, 0x7d, 0x5b, 0x0e, 0x70, 0xd5, 0xd4, 0xcb, 0x98, 0xb2, 0x7b, 0xcf, 0xfa, 0x02, 0x97, 0x33, 0x66, 0x4f, 0xe4, 0x02, 0x9f, 0x73, 0x97, 0x34, 0x87, 0xb3, 0x5a, 0x4a, 0x3d, 0x9e, 0xd2, 0x96,\n\t0xac, 0x70, 0x73, 0x89, 0x7b, 0x65, 0x51, 0x6e, 0x24, 0x1e, 0x8f, 0xe4, 0x16, 0xf1, 0xff, 0x8c, 0xcc, 0x28, 0xb0, 0xd9, 0x0a, 0x66, 0x44, 0xb2, 0x1a, 0xf3, 0x6d, 0xb6, 0xfc, 0x46, 0xc8, 0x3f, 0x8a, 0xb3, 0xa2, 0xb1, 0x18, 0x5e, 0xbb, 0xcd, 0x7c, 0x0c, 0xbc, 0x35, 0xfe, 0x77, 0x38, 0x46, 0xa9, 0x7a, 0xc0, 0xe2, 0x40, 0x2d, 0x9f, 0xa8, 0x07, 0x9c, 0x26, 0x5a, 0x7b, 0x9f, 0x10, 0x46, 0x8f, 0x11, 0x85, 0xab, 0x1e, 0xcb, 0x56, 0x40, 0x14, 0xf0, 0xa7, 0xc9, 0xb7, 0xc7, 0x7f, 0x04, 0xe7, 0x9e, 0x19, 0x6e, 0x68, 0x84, 0x00, 0xc0, 0xc5, 0x13, 0x53, 0x46, 0x0c, 0x6b, 0x8b, 0xa1, 0x65, 0xe4, 0x26, 0xdf, 0xde, 0xcf, 0x0f, 0xed, 0x27, 0xef, 0xe3, 0x4f, 0xdf, 0x7a, 0x2b, 0x50, 0x12, 0xe2, 0xfd, 0xaf, 0xe3, 0xfb, 0x5d, 0xc4, 0xfa, 0x27, 0x25, 0xe8, 0x66, 0xd1, 0xb9, 0x6b, 0x90,\n\t0xb0, 0x70, 0x21, 0x50, 0x14, 0xb9, 0x14, 0xcf, 0xc2, 0x7e, 0x20, 0x3c, 0xd2, 0x2a, 0xc0, 0x2d, 0xeb, 0x85, 0xb3, 0xe4, 0xba, 0xc9, 0x27, 0x13, 0xd6, 0xb4, 0xe3, 0x90, 0xac, 0xdd, 0xa9, 0xd3, 0x14, 0x31, 0xab, 0x57, 0xf0, 0xf7, 0xb8, 0x08, 0x97, 0x57, 0xeb, 0xd5, 0xfa, 0xbc, 0xc8, 0xdf, 0xc3, 0x08, 0xd6, 0x5d, 0xa1, 0xca, 0x07, 0x2e, 0xd6, 0x69, 0x80, 0x93, 0x4b, 0xf8, 0x62, 0x34, 0xc4, 0x2b, 0x01, 0xf9, 0xf6, 0xe8, 0xdc, 0xfc, 0x56, 0xb3, 0xb9, 0x35, 0x7f, 0xee, 0xe8, 0xb5, 0x6e, 0x8f, 0xd3, 0x75, 0xd8, 0xe5, 0xf4, 0xb8, 0x9b, 0x0c, 0x2b, 0x47, 0x7c, 0x6e, 0xb7, 0x6f, 0x64, 0xa5, 0xc1, 0x10, 0x8e, 0x02, 0x10, 0x0d, 0x1a, 0x0c, 0x41, 0xf4, 0x19, 0x36, 0x08, 0x7d, 0xba, 0x53, 0xa4, 0x49, 0xb5, 0x08, 0x1e, 0x83, 0xd6, 0x34, 0x1c, 0xd8, 0xa5, 0x88, 0xf5, 0xcf, 0x4f,\n\t0x6e, 0xf3, 0x34, 0xf8, 0x28, 0x58, 0x97, 0x76, 0x50, 0xa8, 0xe0, 0x9b, 0xce, 0xc0, 0xdc, 0x88, 0xfb, 0xc4, 0xc8, 0xb7, 0xc7, 0xe6, 0xef, 0x07, 0x27, 0x9a, 0xf8, 0xbf, 0x02, 0xd3, 0x7d, 0xf7, 0xa1, 0xf9, 0x95, 0xe4, 0x1f, 0xc9, 0x9c, 0x5b, 0x8a, 0x10, 0xb2, 0x9e, 0x53, 0x81, 0xe1, 0xbd, 0x88, 0xa9, 0xa4, 0xad, 0x7b, 0x7d, 0x21, 0x94, 0xf7, 0x6e, 0xf0, 0xd5, 0x5f, 0xff, 0x7a, 0x25, 0x6f, 0x01, 0xff, 0x73, 0xe6, 0x37, 0x5b, 0xc0, 0x8b, 0x68, 0xcf, 0xc7, 0xbf, 0x46, 0xbe, 0x31, 0x7e, 0x96, 0x30, 0x11, 0xbd, 0x89, 0x0c, 0x23, 0xa4, 0x94, 0x86, 0x43, 0x66, 0x57, 0x6c, 0x59, 0x43, 0x94, 0xe6, 0x68, 0x86, 0x4c, 0x95, 0xdf, 0x14, 0x6b, 0xe7, 0x5a, 0x70, 0x82, 0x2d, 0x8d, 0x73, 0x92, 0x88, 0x6e, 0xf4, 0x99, 0x52, 0x46, 0x30, 0xbe, 0x82, 0x41, 0x97, 0xa9, 0x52, 0xc8, 0xe1,\n\t0x3e, 0xd0, 0x04, 0x4c, 0x48, 0x13, 0x62, 0xd0, 0xce, 0x2f, 0xe0, 0x55, 0x01, 0x5c, 0x28, 0x35, 0x10, 0xf4, 0x08, 0x99, 0xa6, 0xc6, 0x38, 0x69, 0x6d, 0x1a, 0x54, 0x1d, 0x64, 0x2b, 0x30, 0x59, 0x2b, 0xd8, 0x83, 0xaa, 0xc1, 0xa6, 0xc1, 0xc2, 0xc2, 0xe6, 0xd6, 0x4e, 0x5f, 0x3d, 0xc8, 0x41, 0x34, 0xcd, 0x01, 0xf5, 0xbe, 0xce, 0xd6, 0x86, 0x06, 0x61, 0xae, 0xdc, 0x49, 0x6f, 0x26, 0x97, 0xb3, 0x35, 0x38, 0xc7, 0x5a, 0x8a, 0x73, 0x3c, 0x8d, 0x12, 0x54, 0x9a, 0x25, 0x58, 0x6c, 0x2c, 0x36, 0x82, 0x37, 0x8f, 0xcf, 0x3a, 0x9e, 0xfc, 0x9f, 0xe9, 0x17, 0xbe, 0x1d, 0xeb, 0x3c, 0x7e, 0xbc, 0x13, 0xcf, 0x77, 0x37, 0xbd, 0x9f, 0xa4, 0xd9, 0xff, 0x16, 0xa2, 0x41, 0x27, 0xb2, 0x83, 0xa0, 0x32, 0xdb, 0x2d, 0xe6, 0x08, 0x51, 0x64, 0x07, 0x67, 0xe5, 0xcc, 0x78, 0xc2, 0x8a, 0x95, 0x7b,\n\t0x0b, 0xf5, 0x42, 0x09, 0x41, 0xbc, 0xf0, 0x62, 0x55, 0x00, 0x6c, 0xb7, 0x79, 0x6c, 0xee, 0xb2, 0xd9, 0x05, 0x91, 0x2c, 0x9b, 0xdb, 0xe6, 0x2a, 0x9b, 0x9d, 0x9f, 0x1d, 0x62, 0x1a, 0x0c, 0xb9, 0xf1, 0x4a, 0x5f, 0xa8, 0x21, 0xdf, 0xb6, 0x0d, 0xf8, 0xdd, 0x86, 0xbc, 0x78, 0x95, 0x37, 0x5c, 0x9f, 0x67, 0xdd, 0x0c, 0xfc, 0xf8, 0xbd, 0xcc, 0x3f, 0x49, 0x5a, 0x9a, 0xf9, 0xff, 0xfe, 0xbd, 0xec, 0x3d, 0x06, 0x7f, 0x56, 0xa1, 0x2f, 0x54, 0x1b, 0x35, 0x6f, 0x03, 0x56, 0xb7, 0x21, 0x90, 0x55, 0xe4, 0x0d, 0xd7, 0x44, 0x8d, 0x9b, 0x01, 0x16, 0x47, 0x4d, 0x74, 0x21, 0xf9, 0x1e, 0xd4, 0x2b, 0x3c, 0x28, 0x4a, 0xc9, 0x6e, 0x81, 0x1a, 0xa3, 0x42, 0x8a, 0x5d, 0xc7, 0x36, 0x2b, 0x49, 0x35, 0xc9, 0x65, 0x28, 0x7e, 0x1d, 0x0e, 0x33, 0xe4, 0xf4, 0x42, 0x21, 0x1c, 0xa8, 0x4e, 0x51, 0xd4,\n\t0x20, 0x96, 0x9f, 0x1e, 0xc2, 0x13, 0xf0, 0x69, 0x82, 0x42, 0x15, 0x58, 0x91, 0xe5, 0xe2, 0x02, 0x38, 0x13, 0xe5, 0x26, 0x71, 0xfd, 0x1b, 0xec, 0x03, 0x24, 0xdf, 0xb3, 0xe6, 0xd5, 0x87, 0x5d, 0xb5, 0xae, 0xc1, 0xfe, 0x45, 0x1a, 0xb7, 0xca, 0xed, 0x07, 0xeb, 0xad, 0x05, 0x75, 0x61, 0x6f, 0x83, 0x7b, 0xa8, 0x7f, 0x91, 0xdb, 0xe4, 0xf1, 0x03, 0xe6, 0x9a, 0x82, 0xd9, 0xe5, 0x2e, 0xbd, 0xea, 0xf6, 0xc2, 0x63, 0x52, 0x59, 0x5e, 0x24, 0x7f, 0x4e, 0x99, 0xdb, 0x88, 0x7e, 0xa8, 0x72, 0xb2, 0x11, 0x2e, 0x23, 0xaf, 0xa7, 0x6b, 0xc6, 0x37, 0xc0, 0x3d, 0x75, 0x69, 0x42, 0xae, 0x56, 0x92, 0xa0, 0x49, 0x42, 0xc3, 0xb6, 0x09, 0x93, 0x4f, 0x91, 0xac, 0x2f, 0xbd, 0x7c, 0xfa, 0x3a, 0xbc, 0x4f, 0x18, 0xf5, 0x58, 0xa1, 0x31, 0xe8, 0x24, 0x0c, 0x64, 0x31, 0xfe, 0x40, 0xbc, 0x18, 0x61,\n\t0x1a, 0xd1, 0x5e, 0x87, 0x83, 0x3f, 0xcf, 0xe7, 0xf0, 0x9f, 0xa3, 0x5d, 0x8f, 0x1c, 0xfc, 0x9a, 0xff, 0x47, 0x66, 0xa1, 0x7a, 0xff, 0xf0, 0xf0, 0x21, 0xf8, 0x71, 0xd5, 0xc8, 0x08, 0x1a, 0x97, 0xdd, 0x63, 0x1f, 0x92, 0xef, 0x8f, 0xff, 0x10, 0xea, 0xd6, 0x75, 0xc2, 0xbb, 0xd4, 0x38, 0x16, 0x84, 0x58, 0x80, 0xc5, 0x2f, 0x2e, 0x7a, 0x6c, 0xc1, 0xeb, 0x13, 0x23, 0x44, 0xa2, 0x7f, 0x84, 0x38, 0x91, 0x5e, 0xac, 0x7c, 0x0a, 0xeb, 0x54, 0x46, 0xc8, 0x34, 0x49, 0xd1, 0x0c, 0x25, 0xa2, 0x36, 0x0e, 0xf7, 0x76, 0xe4, 0xe6, 0x9b, 0x86, 0x0f, 0xa2, 0xd7, 0xf0, 0x07, 0x4f, 0x9d, 0x02, 0x0a, 0xd8, 0x00, 0xfe, 0x3c, 0x6a, 0xec, 0x97, 0xf4, 0x36, 0x32, 0x9b, 0xad, 0x43, 0xa8, 0x2e, 0x8f, 0x33, 0x00, 0xcd, 0x5d, 0x3c, 0x71, 0xc9, 0xec, 0x0f, 0x66, 0xdd, 0x72, 0xcb, 0x2c, 0x66, 0xe1,\n\t0x07, 0xb3, 0x8e, 0x1d, 0xeb, 0x84, 0xd7, 0x7d, 0x4a, 0xdf, 0x04, 0xf7, 0x37, 0xe5, 0x04, 0x87, 0xe7, 0x4b, 0x0a, 0x5d, 0x0a, 0x31, 0x33, 0xd1, 0x06, 0x44, 0x11, 0x1d, 0x3a, 0xce, 0x24, 0x30, 0xd6, 0xa4, 0xf6, 0xaa, 0x17, 0x7c, 0xb2, 0xe0, 0xad, 0xc2, 0xb9, 0x68, 0xa3, 0x3a, 0xb7, 0x30, 0x52, 0x52, 0x12, 0xa1, 0x6f, 0x72, 0x94, 0x74, 0xe4, 0xe5, 0xb5, 0x97, 0x38, 0x46, 0x4a, 0xe2, 0xf1, 0x62, 0x41, 0x2e, 0xd5, 0xd0, 0xc3, 0xe4, 0xfb, 0xac, 0x1d, 0xfb, 0x51, 0xd3, 0xf5, 0x66, 0xa8, 0x24, 0xa3, 0xc8, 0x44, 0xa8, 0xe9, 0xa3, 0x19, 0x9a, 0xa6, 0xc3, 0xe9, 0x75, 0x5e, 0x0f, 0xd6, 0x9b, 0x83, 0xfa, 0xe0, 0x65, 0xf4, 0x66, 0x41, 0x67, 0x0d, 0xa4, 0x54, 0x56, 0x52, 0xaa, 0x85, 0x0a, 0xb3, 0x29, 0x82, 0x82, 0x4c, 0x22, 0x38, 0xd8, 0x64, 0xcb, 0xfc, 0x5d, 0x9d, 0xfe, 0x2b,\n\t0x87, 0x57, 0xc4, 0x3a, 0x0a, 0xcd, 0xbb, 0xfc, 0x9d, 0x57, 0xd2, 0xef, 0x99, 0x84, 0x10, 0x14, 0x93, 0x59, 0xb8, 0x0a, 0x04, 0xa3, 0x9d, 0xab, 0x6b, 0xfb, 0x56, 0xd9, 0x8b, 0x5a, 0xa2, 0xb5, 0xab, 0x3b, 0xa3, 0x78, 0xbd, 0xbf, 0x3f, 0xf6, 0x05, 0xa9, 0x19, 0x7f, 0x1e, 0xd3, 0x8c, 0x4e, 0xae, 0x77, 0xb8, 0xd2, 0xb7, 0xdd, 0x32, 0xeb, 0x83, 0x0f, 0x66, 0xf1, 0xff, 0x7d, 0x6c, 0xd6, 0x07, 0x1f, 0xce, 0x82, 0x2d, 0x95, 0x8f, 0x7d, 0x4e, 0x56, 0x8d, 0x3f, 0x77, 0x09, 0x6d, 0xab, 0x30, 0x6d, 0xf9, 0xff, 0xfe, 0xb0, 0xf3, 0xd8, 0xb1, 0x59, 0x08, 0x7f, 0x70, 0xec, 0x73, 0xca, 0x85, 0xaf, 0x53, 0x10, 0xd2, 0x27, 0xe5, 0x28, 0x1c, 0x3b, 0x2f, 0xe2, 0xc4, 0x17, 0x03, 0x34, 0xc3, 0x8d, 0x83, 0x1f, 0xa0, 0x3b, 0xc8, 0x67, 0xe1, 0xe5, 0x1f, 0x7c, 0x50, 0xf3, 0x21, 0x1a, 0x13,\n\t0xfe, 0x57, 0xb7, 0xde, 0xda, 0xf9, 0xc1, 0x07, 0x82, 0xcc, 0xa4, 0xef, 0x23, 0x73, 0xd8, 0x0e, 0x71, 0x6c, 0x52, 0xf9, 0x7b, 0x70, 0x58, 0xba, 0x45, 0x93, 0x0e, 0x41, 0x75, 0x98, 0x38, 0x9d, 0x30, 0x36, 0x82, 0x84, 0x8e, 0x25, 0xe5, 0x36, 0x68, 0x46, 0x63, 0x92, 0x1c, 0x1f, 0x26, 0xa3, 0x38, 0x1e, 0x2f, 0x19, 0x71, 0x94, 0xb4, 0xe7, 0xe5, 0x75, 0x94, 0x88, 0xb5, 0x2f, 0x96, 0xf3, 0x6b, 0xc1, 0x9b, 0xe3, 0x1f, 0x11, 0xb9, 0x44, 0x5d, 0x42, 0x9b, 0x9b, 0x13, 0x09, 0x79, 0x5d, 0x4e, 0x93, 0x51, 0x9b, 0xa9, 0x90, 0xb0, 0x2a, 0x21, 0xfd, 0xd3, 0xf7, 0x1d, 0x16, 0xc5, 0x93, 0xc1, 0x80, 0x03, 0x69, 0xdd, 0x0c, 0xaa, 0x37, 0xed, 0xfc, 0xa6, 0x12, 0xd5, 0x06, 0x63, 0x40, 0x2c, 0x50, 0x1d, 0xaf, 0x06, 0x46, 0x70, 0x30, 0xc3, 0xa2, 0xb2, 0x9b, 0xda, 0xbc, 0x6d, 0x99, 0x46,\n\t0x99, 0xaa, 0x89, 0x91, 0xc8, 0x0c, 0x2a, 0xf8, 0x43, 0x6d, 0x55, 0x3b, 0xac, 0x33, 0xbd, 0x33, 0xed, 0x1a, 0x74, 0x4c, 0x63, 0x6b, 0xf3, 0xfe, 0x54, 0x2a, 0x27, 0x29, 0x2e, 0xbb, 0x32, 0x5b, 0xa6, 0x53, 0xd9, 0x3c, 0xbd, 0x3d, 0x9c, 0x2d, 0x43, 0xa9, 0x91, 0x46, 0xab, 0xb2, 0xf1, 0xf1, 0x48, 0x65, 0x56, 0xa6, 0xd5, 0xe6, 0x99, 0xdf, 0xcb, 0xd9, 0x55, 0xa6, 0xcc, 0xec, 0x0a, 0x48, 0x94, 0xbb, 0xf9, 0x23, 0x24, 0x3f, 0xfe, 0x1b, 0xec, 0x23, 0x2f, 0x26, 0x1a, 0x13, 0x75, 0x31, 0x00, 0x68, 0xc8, 0x18, 0x10, 0xf0, 0xe3, 0x94, 0xc4, 0x5f, 0x21, 0xdf, 0x97, 0x59, 0xc3, 0xb4, 0x9a, 0x4d, 0x19, 0x50, 0x4d, 0x2b, 0xcc, 0x0f, 0x07, 0xbd, 0x6e, 0x53, 0xb1, 0xb9, 0x58, 0xcb, 0x29, 0x8d, 0x19, 0x46, 0x21, 0x4e, 0x45, 0x48, 0xf8, 0x9d, 0x88, 0x53, 0xf1, 0xa6, 0x7d, 0xf7, 0xa7,\n\t0x21, 0x21, 0x4d, 0x36, 0x3e, 0x56, 0x01, 0xb2, 0xdd, 0xe9, 0xf3, 0x39, 0x5d, 0x3e, 0xdf, 0xef, 0x5c, 0x5e, 0xaf, 0x0b, 0x7e, 0x82, 0x40, 0xa0, 0x2a, 0x62, 0x34, 0x46, 0xaa, 0x02, 0x79, 0xf5, 0x5a, 0x5d, 0x5d, 0x5e, 0xa0, 0x2a, 0xdb, 0x64, 0xca, 0x86, 0xbf, 0xea, 0x74, 0xda, 0x7a, 0xfe, 0x9f, 0x3e, 0xbb, 0xdd, 0x97, 0xfe, 0xf7, 0x43, 0x73, 0x76, 0xb9, 0xc7, 0x53, 0x91, 0x6d, 0x0e, 0xba, 0x5c, 0x41, 0x73, 0x76, 0x85, 0xc7, 0x53, 0x9e, 0x6d, 0x0e, 0xb8, 0x5c, 0x01, 0x61, 0xfc, 0x5e, 0xa1, 0xdb, 0xc9, 0xcd, 0xec, 0x95, 0x44, 0x06, 0xd1, 0x24, 0x44, 0xa3, 0x9b, 0x08, 0xac, 0xc1, 0x88, 0x59, 0xee, 0x90, 0xcd, 0xf6, 0x22, 0x43, 0xef, 0x20, 0x62, 0x2e, 0x06, 0xc4, 0xf8, 0xd7, 0x09, 0x1b, 0x87, 0xb4, 0x13, 0x02, 0x63, 0xc9, 0x20, 0x32, 0xdc, 0x5a, 0x37, 0x66, 0x2c, 0x14,\n\t0xae, 0x69, 0xe0, 0xd5, 0xe2, 0x72, 0x07, 0xe4, 0xe6, 0x2d, 0x4b, 0xf4, 0x2a, 0x69, 0xdd, 0xd7, 0x9b, 0x97, 0x18, 0x32, 0x24, 0x75, 0xcc, 0x29, 0xfe, 0x61, 0x93, 0xf6, 0x31, 0x30, 0xcf, 0xac, 0x79, 0x0c, 0xe3, 0x09, 0xf1, 0x05, 0xd2, 0x8a, 0x71, 0x84, 0x21, 0x5c, 0x7d, 0x36, 0x43, 0xc9, 0x32, 0x34, 0x6a, 0x07, 0xe2, 0x6d, 0x4a, 0x32, 0x99, 0x43, 0x8e, 0x95, 0x3b, 0x8d, 0x60, 0x01, 0xe9, 0x4e, 0x1e, 0xc5, 0x72, 0x5b, 0x01, 0x08, 0xb9, 0x14, 0xc5, 0xb9, 0x51, 0x29, 0xc8, 0x08, 0x96, 0x76, 0xbb, 0x7c, 0xc1, 0x62, 0x07, 0x45, 0xcf, 0x38, 0x3a, 0xf6, 0x97, 0x77, 0xd7, 0x14, 0xbd, 0xce, 0x2b, 0xf8, 0xd7, 0xe1, 0x7f, 0x8a, 0xd7, 0x0b, 0xd7, 0xbc, 0xfb, 0x97, 0x31, 0xfe, 0x45, 0x43, 0x24, 0x11, 0xde, 0xd7, 0x35, 0x38, 0xd8, 0xb5, 0x2f, 0x9c, 0x88, 0x18, 0x10, 0x86, 0xcb,\n\t0x6c, 0xfa, 0x06, 0x69, 0x05, 0xf3, 0x2a, 0x25, 0x21, 0x83, 0x04, 0xc1, 0x2e, 0x14, 0xb0, 0xfa, 0xd8, 0x85, 0x29, 0x8c, 0x97, 0x65, 0xf4, 0x6f, 0xa5, 0x01, 0x66, 0x39, 0x3c, 0x9f, 0x75, 0xe9, 0x79, 0x84, 0x67, 0xc9, 0x6f, 0x95, 0x06, 0xc6, 0x95, 0x82, 0x5e, 0x6a, 0xfb, 0xee, 0x7a, 0x29, 0xda, 0x55, 0x2c, 0x93, 0xfc, 0xf4, 0xcb, 0xda, 0x7f, 0x1f, 0xc5, 0xcf, 0x59, 0x4b, 0x1f, 0x92, 0xda, 0x99, 0xff, 0x21, 0x1c, 0xc4, 0x9a, 0x96, 0x47, 0xb5, 0x38, 0x3b, 0x25, 0x5d, 0xdc, 0x21, 0xc5, 0x70, 0x18, 0xfb, 0x20, 0x90, 0xb2, 0x89, 0x82, 0x5f, 0x51, 0xde, 0x03, 0x4a, 0x94, 0xc6, 0x97, 0x30, 0xcc, 0x70, 0x4b, 0x32, 0x6e, 0x0a, 0x5d, 0x06, 0xb7, 0x44, 0xc9, 0x2b, 0x20, 0x77, 0xa4, 0x11, 0x4c, 0xcf, 0xc4, 0x95, 0x0c, 0xf2, 0x37, 0xc8, 0x34, 0x7e, 0x9f, 0xc6, 0x2f, 0xe4, 0x0a,\n\t0xe0, 0xea, 0xe3, 0x34, 0x9a, 0x8e, 0x62, 0x34, 0x20, 0x8d, 0x4d, 0x0a, 0x52, 0xfb, 0x9f, 0xfe, 0xbe, 0xec, 0xec, 0x83, 0x77, 0xde, 0x73, 0x66, 0xf1, 0xad, 0x47, 0x4e, 0x96, 0xac, 0x3b, 0xb3, 0x09, 0xff, 0x3a, 0xbd, 0xf8, 0xd6, 0xeb, 0x4f, 0x32, 0xaf, 0xdc, 0xf6, 0x80, 0x23, 0x5a, 0x14, 0x75, 0xcc, 0xeb, 0x6b, 0xdb, 0x32, 0x27, 0xe2, 0x88, 0xc6, 0xd0, 0x57, 0x34, 0xa6, 0xf4, 0x83, 0x90, 0x9e, 0x1f, 0xa2, 0x3c, 0x70, 0x71, 0x4c, 0x67, 0x08, 0xbb, 0x89, 0x89, 0x31, 0xc5, 0x45, 0xea, 0xb9, 0xb4, 0xbd, 0x37, 0x1a, 0x5e, 0xe2, 0x92, 0x21, 0xc5, 0x08, 0x1f, 0x71, 0x9f, 0xdb, 0x45, 0x1b, 0x25, 0x39, 0x70, 0x48, 0x8f, 0xa1, 0x21, 0x2d, 0x7c, 0x1d, 0xfc, 0x1b, 0x14, 0x80, 0x7c, 0x70, 0xfe, 0xf5, 0x22, 0x34, 0xa4, 0xcc, 0x6c, 0x43, 0xa4, 0x3a, 0xbc, 0xb7, 0x6b, 0x68, 0xa8,\n\t0x6b, 0x6f, 0xb8, 0x3a, 0x62, 0x10, 0xc7, 0x44, 0x2f, 0xd5, 0x41, 0x19, 0x2d, 0x23, 0xe2, 0x4f, 0xc9, 0x00, 0x68, 0xa2, 0xc1, 0x77, 0x16, 0xd0, 0x9c, 0x28, 0xa0, 0x59, 0x24, 0xa0, 0xe1, 0x7f, 0x92, 0xf3, 0x48, 0x22, 0x7e, 0xfe, 0xd5, 0x4e, 0x76, 0x9f, 0x28, 0x94, 0x8f, 0x8e, 0x08, 0x98, 0xe9, 0x74, 0x2f, 0xf8, 0x03, 0x1b, 0x83, 0x3c, 0x22, 0x97, 0xa8, 0x49, 0x54, 0x29, 0xe0, 0x33, 0xcc, 0x50, 0x36, 0xa1, 0x58, 0x56, 0x96, 0x81, 0x77, 0xa3, 0x6a, 0x61, 0xac, 0x84, 0x64, 0x51, 0x5c, 0x32, 0x01, 0x59, 0x07, 0x92, 0x53, 0x14, 0xee, 0x2f, 0xd5, 0x87, 0xbc, 0x25, 0x54, 0x87, 0xd7, 0x63, 0x08, 0xe8, 0x7d, 0x81, 0x4c, 0x54, 0x35, 0x0a, 0x88, 0xae, 0x90, 0x78, 0x31, 0x25, 0x40, 0xa3, 0x71, 0xa9, 0x02, 0xd0, 0x01, 0x5c, 0xff, 0x39, 0x56, 0x94, 0x4a, 0x58, 0x1f, 0xc9, 0x2e,\n\t0xf7, 0xaa, 0xec, 0x56, 0x7b, 0xb6, 0xf1, 0xab, 0x59, 0xeb, 0xa1, 0x06, 0x65, 0x2a, 0xe1, 0xb4, 0xac, 0xdc, 0x93, 0xc8, 0xa9, 0x69, 0xb1, 0x54, 0x8d, 0xb6, 0x37, 0x58, 0xdc, 0x16, 0x83, 0x3a, 0x43, 0xc3, 0x30, 0x0e, 0x52, 0xc1, 0x19, 0x94, 0x16, 0xbd, 0xde, 0x00, 0x34, 0x33, 0xad, 0x79, 0xb5, 0x41, 0xfe, 0xf7, 0x72, 0xce, 0x6a, 0x77, 0x55, 0x57, 0x9b, 0x0b, 0xb3, 0x6c, 0xa4, 0x61, 0x96, 0x42, 0xa5, 0xc8, 0x90, 0xc1, 0x76, 0xce, 0x81, 0x7d, 0xe1, 0xd9, 0x42, 0x82, 0x25, 0xc2, 0xc4, 0xf6, 0x27, 0x35, 0x40, 0x48, 0xbd, 0x71, 0xe0, 0x3a, 0x69, 0x14, 0x4b, 0xb2, 0x14, 0xb9, 0x26, 0xd5, 0x0b, 0x14, 0x73, 0x4c, 0x2f, 0x42, 0xd5, 0xec, 0x41, 0xaf, 0x04, 0x19, 0xd7, 0x50, 0x2d, 0xe1, 0xac, 0xa9, 0x97, 0x49, 0x50, 0x51, 0x67, 0x96, 0x02, 0x28, 0xc4, 0x95, 0xa6, 0xb1, 0x26,\n\t0x82, 0x7c, 0x09, 0x24, 0x0d, 0x47, 0xd9, 0x24, 0x91, 0xc0, 0x2d, 0x43, 0x58, 0x12, 0x42, 0xc9, 0xfb, 0x50, 0xf1, 0x96, 0xc1, 0xf7, 0xb2, 0x1e, 0x19, 0xb2, 0xbb, 0x60, 0x9e, 0xa8, 0x06, 0xc9, 0x5a, 0x74, 0x4e, 0x30, 0x19, 0xfa, 0x00, 0x6d, 0x7e, 0xc0, 0xf5, 0x91, 0x9c, 0xec, 0x7c, 0x29, 0x29, 0xa9, 0xcc, 0x37, 0xfb, 0x6d, 0x46, 0x85, 0x4a, 0xea, 0xd3, 0xe5, 0x16, 0x14, 0x99, 0xf2, 0xe6, 0x56, 0xf9, 0x9c, 0x65, 0x73, 0x8a, 0xa2, 0xcd, 0x71, 0x87, 0x82, 0x63, 0x76, 0xf8, 0x4a, 0xf3, 0xa2, 0x2d, 0x55, 0xa5, 0x4a, 0xb5, 0x52, 0x99, 0x63, 0x72, 0x70, 0x12, 0x67, 0xd5, 0x82, 0xca, 0x9c, 0x39, 0x55, 0x3e, 0x5b, 0xbc, 0xbd, 0xc0, 0xae, 0x15, 0x74, 0x8b, 0x25, 0xf4, 0x00, 0x71, 0x91, 0xfd, 0x1a, 0x2e, 0x11, 0x0e, 0x45, 0x59, 0x22, 0xdc, 0x14, 0x8c, 0x6b, 0x85, 0x71, 0x6c,\n\t0x68, 0x20, 0x58, 0x37, 0x40, 0x6a, 0x76, 0x10, 0xc8, 0x6c, 0x29, 0x45, 0x42, 0x13, 0xea, 0x50, 0xfa, 0x88, 0x16, 0x55, 0xc4, 0x14, 0x18, 0xb7, 0x60, 0x1d, 0xfa, 0x68, 0xc7, 0xb5, 0x4a, 0xbd, 0x3d, 0xd3, 0x19, 0x8d, 0x3a, 0x5d, 0x39, 0xac, 0x8e, 0x6f, 0x05, 0x4f, 0xdc, 0x9a, 0x69, 0xd3, 0x2b, 0xa3, 0x2e, 0x57, 0x34, 0x4a, 0x08, 0x74, 0x26, 0xdd, 0x90, 0xce, 0x5a, 0xc2, 0x2e, 0xbc, 0x4f, 0xdc, 0x49, 0x33, 0x38, 0x41, 0x17, 0x6e, 0xfe, 0x52, 0x7b, 0x69, 0x84, 0x1d, 0x61, 0x35, 0xeb, 0xec, 0x7a, 0xfb, 0x04, 0xca, 0x3e, 0x98, 0x84, 0xf0, 0x56, 0x45, 0x6a, 0x45, 0x21, 0x02, 0xaf, 0x2d, 0x2f, 0x9a, 0x87, 0xc4, 0xf4, 0xbc, 0xa2, 0xa2, 0x79, 0x95, 0x1e, 0x4f, 0xe5, 0xbc, 0xa2, 0x58, 0x7e, 0x7e, 0x6c, 0x19, 0x5b, 0xe8, 0xae, 0xec, 0x89, 0x17, 0xf7, 0x54, 0xb9, 0xdd, 0x55,\n\t0x3d, 0xc5, 0xf1, 0x9e, 0x4a, 0x37, 0x7f, 0x75, 0x23, 0xfc, 0x73, 0xf8, 0x30, 0xec, 0xcd, 0x08, 0x1c, 0xf3, 0x71, 0x36, 0x1b, 0xee, 0xa3, 0x30, 0xe2, 0x3f, 0x45, 0xe2, 0xaa, 0xee, 0xcd, 0x0c, 0x0d, 0x35, 0x7d, 0x82, 0x9c, 0x37, 0xa1, 0xc1, 0x89, 0xbb, 0x51, 0x21, 0x65, 0xd8, 0xab, 0x0f, 0x70, 0x2c, 0x52, 0x16, 0xb8, 0xf4, 0x02, 0xe5, 0x13, 0x11, 0x87, 0x60, 0xbc, 0x4d, 0xa1, 0x62, 0x25, 0xd6, 0x9a, 0x9c, 0x40, 0x69, 0x48, 0xb7, 0xc3, 0xe3, 0xb5, 0x44, 0x75, 0x6c, 0x36, 0x5f, 0xa4, 0x94, 0x3b, 0xad, 0x6e, 0x4b, 0x4e, 0x4d, 0x00, 0xf8, 0xf8, 0xdf, 0xf9, 0x43, 0x06, 0x1d, 0x40, 0xb6, 0x37, 0x34, 0xef, 0xde, 0x87, 0xf4, 0x08, 0x60, 0x3c, 0x63, 0x00, 0x18, 0x03, 0x9c, 0x7a, 0xe9, 0x3e, 0x1d, 0x34, 0x10, 0xab, 0xe0, 0x9c, 0x02, 0x04, 0x03, 0x2e, 0x99, 0x49, 0x21, 0x9f,\n\t0xd7, 0xe7, 0x15, 0x18, 0x58, 0xaa, 0xb0, 0x61, 0xca, 0x9f, 0x38, 0xd5, 0x91, 0x07, 0x7e, 0xcc, 0x28, 0xe4, 0x32, 0x4e, 0x6f, 0x33, 0x14, 0x17, 0x95, 0xe4, 0x99, 0x1d, 0x7a, 0x4e, 0xa1, 0x96, 0xfa, 0x42, 0x4b, 0xf2, 0xb2, 0x5a, 0x4b, 0x3d, 0xf6, 0xb2, 0xb9, 0x25, 0xb1, 0x0e, 0x17, 0x73, 0x4e, 0x22, 0x95, 0x67, 0xc8, 0x5b, 0x6a, 0x1b, 0x66, 0x2a, 0xd5, 0x19, 0xca, 0x9c, 0x5c, 0xa7, 0xab, 0xb2, 0xa7, 0xb4, 0xa0, 0x2b, 0xe1, 0xf3, 0x08, 0x18, 0x17, 0x68, 0xfc, 0x48, 0xf6, 0x2b, 0xb8, 0xe6, 0xbd, 0x44, 0x22, 0x51, 0xe9, 0x81, 0xec, 0x59, 0x81, 0x34, 0x6d, 0x0d, 0x1c, 0x32, 0xaa, 0x19, 0xea, 0x01, 0x34, 0xc9, 0xcc, 0x43, 0x8c, 0x16, 0xa0, 0x32, 0xda, 0x68, 0x34, 0xbb, 0x71, 0xca, 0x33, 0xce, 0x44, 0xee, 0x50, 0x2a, 0x95, 0x5e, 0xa5, 0x37, 0x14, 0xd0, 0xf9, 0xdc, 0x78,\n\t0xa7, 0x12, 0x98, 0x08, 0x4c, 0xd4, 0x72, 0x53, 0xea, 0xbd, 0xe3, 0xb8, 0x44, 0x70, 0xc0, 0x9d, 0x9b, 0x5d, 0x1c, 0x0d, 0xb8, 0xb2, 0x75, 0x3b, 0x5a, 0x95, 0x2a, 0x56, 0x66, 0x6b, 0xcc, 0xf3, 0x55, 0x45, 0xcd, 0xb6, 0xa2, 0x99, 0xd9, 0x81, 0x42, 0x3d, 0xf3, 0xb8, 0xa7, 0xbe, 0xad, 0xa5, 0xc2, 0x6c, 0x24, 0x95, 0x63, 0x23, 0x4a, 0x79, 0xd0, 0x11, 0x70, 0x55, 0x74, 0x97, 0x14, 0xf5, 0x24, 0xfc, 0x06, 0xed, 0x47, 0x98, 0x0f, 0xae, 0xa1, 0x07, 0x48, 0x29, 0x6c, 0xaf, 0x1e, 0x21, 0xf4, 0x23, 0x8f, 0xa2, 0x50, 0x9b, 0x02, 0x5b, 0xcb, 0x90, 0x48, 0x42, 0x9b, 0x84, 0x41, 0x8c, 0x3b, 0x06, 0x55, 0x1a, 0x04, 0x3c, 0xa6, 0xf5, 0x0a, 0x7e, 0x5a, 0xad, 0x98, 0x3d, 0x86, 0x92, 0xe2, 0x53, 0xee, 0xe6, 0x7f, 0x58, 0x2a, 0xb2, 0x02, 0x65, 0x70, 0x54, 0xbd, 0x5e, 0x0b, 0x6c, 0xd1,\n\t0x0e, 0x96, 0x30, 0xda, 0x2c, 0xb9, 0x89, 0x00, 0xff, 0x3b, 0xe0, 0xf3, 0x87, 0xf4, 0x5a, 0xfe, 0x29, 0xf2, 0x56, 0x41, 0x26, 0xae, 0x86, 0xef, 0x45, 0xfc, 0xc4, 0x87, 0xb0, 0xce, 0x59, 0x94, 0x06, 0x65, 0xc7, 0x20, 0x17, 0x12, 0xd8, 0x04, 0x04, 0x78, 0x06, 0xa7, 0xbc, 0x04, 0x7b, 0x0c, 0x7a, 0x51, 0x49, 0x60, 0x82, 0x44, 0x2f, 0xd6, 0x7a, 0xb4, 0x3e, 0xa1, 0x80, 0x9e, 0x50, 0xaf, 0x54, 0xc8, 0x4a, 0x40, 0x0d, 0x40, 0x64, 0x9a, 0xd4, 0x10, 0x78, 0xf6, 0xcf, 0xc6, 0xe2, 0x40, 0xb4, 0x44, 0x65, 0x9c, 0x13, 0x6d, 0x99, 0xbd, 0xb3, 0xde, 0x91, 0xb5, 0xc3, 0xed, 0x30, 0x06, 0xb9, 0x1d, 0x6d, 0x0a, 0x35, 0xcb, 0x7c, 0x6d, 0x76, 0x45, 0xfd, 0xd9, 0x81, 0xbe, 0xb9, 0xa8, 0x61, 0x6d, 0x41, 0xdc, 0xbe, 0x90, 0x5f, 0xcb, 0xf1, 0x8f, 0x83, 0x57, 0x95, 0x72, 0xd4, 0xbe, 0x15,\n\t0xf4, 0x00, 0xb8, 0x1a, 0xf2, 0x6e, 0x3d, 0xca, 0x93, 0x87, 0x0a, 0x38, 0xa1, 0xc2, 0x9c, 0x9b, 0x46, 0xfa, 0x31, 0xde, 0xef, 0xe2, 0x95, 0xd9, 0x8b, 0x56, 0x7a, 0x1b, 0xd4, 0x6b, 0xbc, 0x13, 0x34, 0xc1, 0xe5, 0x19, 0xd3, 0x1b, 0xf2, 0x07, 0x43, 0x49, 0xc0, 0xa9, 0x93, 0xd2, 0x99, 0x12, 0xab, 0xc2, 0x1d, 0x54, 0xed, 0x9c, 0xa9, 0x53, 0x51, 0xcc, 0x1f, 0x83, 0x51, 0xf5, 0xa2, 0x4c, 0xda, 0xeb, 0xe4, 0xff, 0x02, 0x5e, 0x55, 0x71, 0x98, 0x26, 0x09, 0x38, 0xd7, 0x77, 0xb1, 0x4f, 0x10, 0x4e, 0x84, 0xf4, 0xa3, 0x10, 0xea, 0x45, 0x60, 0x8d, 0x8a, 0x82, 0x1c, 0x86, 0xa1, 0xc0, 0x62, 0xc4, 0x3a, 0x71, 0xe2, 0x06, 0xd1, 0x0f, 0xbf, 0x10, 0xb3, 0xe0, 0x4e, 0x2d, 0xa8, 0x15, 0x8a, 0x83, 0xb0, 0xd8, 0xd8, 0x83, 0xff, 0xc1, 0x9e, 0x38, 0x7d, 0xa1, 0xde, 0xab, 0xd7, 0x89, 0xe6,\n\t0x3e, 0x23, 0xd8, 0x15, 0x6b, 0xa8, 0xae, 0x8d, 0xc8, 0x55, 0xcd, 0x26, 0xd6, 0x90, 0xd8, 0xb4, 0xc9, 0x2f, 0xcb, 0x90, 0xcb, 0x58, 0x56, 0x49, 0xd1, 0xfb, 0xb2, 0x66, 0x54, 0x7e, 0xa6, 0x52, 0x16, 0xaa, 0x36, 0xe8, 0xaf, 0x99, 0xff, 0x97, 0x20, 0xc3, 0x30, 0x2c, 0xc6, 0x99, 0xad, 0x84, 0xe3, 0xa3, 0x87, 0x6b, 0x9f, 0x43, 0x36, 0xcc, 0x09, 0xdf, 0xa3, 0x08, 0x4c, 0x81, 0xf1, 0xee, 0x33, 0x39, 0x21, 0x4d, 0x9e, 0xf2, 0x52, 0x49, 0x67, 0x1c, 0x46, 0xc2, 0x2d, 0x24, 0xf5, 0x4f, 0xac, 0x79, 0x62, 0x44, 0xa5, 0x25, 0x5b, 0xa5, 0x0a, 0x46, 0x96, 0xd9, 0x4e, 0x6a, 0x95, 0x68, 0x81, 0x43, 0xd2, 0x2a, 0xde, 0x75, 0x57, 0x39, 0xcb, 0xeb, 0xde, 0x95, 0x67, 0x60, 0x2c, 0x5b, 0xf8, 0x0e, 0x1b, 0x7c, 0x87, 0x15, 0x61, 0xdd, 0x59, 0xb5, 0x19, 0x29, 0x9f, 0x23, 0x4a, 0x60, 0x40,\n\t0xae, 0x47, 0xa2, 0x0f, 0xa7, 0x00, 0x77, 0x84, 0x35, 0x69, 0xb9, 0xa4, 0x40, 0xcc, 0xec, 0x2b, 0x0e, 0x0a, 0x31, 0x22, 0x42, 0x7f, 0x25, 0xa4, 0x6d, 0xb3, 0x2a, 0x93, 0xe9, 0xa5, 0xa5, 0xad, 0x4c, 0xa6, 0x72, 0xf5, 0xed, 0xc7, 0xb7, 0xa8, 0x94, 0x4c, 0x2f, 0xc5, 0x32, 0xf5, 0x32, 0xed, 0xda, 0x63, 0xf4, 0x80, 0x4a, 0xf6, 0x3d, 0x4e, 0xb5, 0x45, 0xa6, 0xfa, 0xe7, 0xfb, 0x12, 0xd9, 0x4d, 0x32, 0x8d, 0x6c, 0xa5, 0xe6, 0x1d, 0x1c, 0x9f, 0x9c, 0x03, 0x37, 0xc4, 0x9f, 0xb2, 0xf9, 0x22, 0x2e, 0x5d, 0x34, 0x91, 0x85, 0x22, 0x86, 0x60, 0x4f, 0x91, 0x59, 0x21, 0xc9, 0xe6, 0xa7, 0xba, 0x00, 0x42, 0xf0, 0x0f, 0xb6, 0x61, 0x16, 0x03, 0x89, 0x7f, 0xaa, 0x3f, 0x68, 0xca, 0xef, 0x53, 0x83, 0x60, 0xdf, 0x10, 0xff, 0x05, 0x4e, 0x5b, 0xc8, 0x42, 0x99, 0x0a, 0x59, 0x38, 0x6d, 0x01,\n\t0xbc, 0x85, 0x72, 0x16, 0x92, 0xb9, 0x0b, 0xe8, 0x93, 0xb9, 0x77, 0x88, 0xdf, 0x39, 0xd4, 0x65, 0x8a, 0xb8, 0x34, 0x1a, 0x57, 0x24, 0x99, 0xce, 0x00, 0x82, 0xa6, 0x88, 0x53, 0xab, 0x75, 0x46, 0x26, 0xf2, 0x1b, 0xa6, 0x69, 0x33, 0x32, 0xbd, 0x60, 0xef, 0x1d, 0xc2, 0x79, 0x4f, 0xc2, 0xea, 0x4d, 0xc6, 0xf1, 0x48, 0xb5, 0x39, 0x08, 0x8c, 0xd4, 0x14, 0xdb, 0xeb, 0x54, 0x70, 0xbd, 0x0b, 0x43, 0x60, 0xdf, 0xe0, 0xd6, 0xa9, 0x4d, 0xe6, 0xb3, 0xa6, 0x36, 0x99, 0xf6, 0x0c, 0xa1, 0xce, 0xfd, 0x46, 0x6c, 0x9a, 0x59, 0x6c, 0x3b, 0xe8, 0x99, 0x38, 0x80, 0xdb, 0x8e, 0x7c, 0xbb, 0x9b, 0x79, 0x25, 0x71, 0xf3, 0xf8, 0x9b, 0x44, 0x2d, 0x61, 0x4c, 0xe8, 0xaa, 0x9c, 0x24, 0x46, 0x1a, 0xc1, 0xd8, 0x07, 0xa3, 0x65, 0x25, 0x3e, 0xb4, 0xb7, 0x93, 0x24, 0xc1, 0x8b, 0x84, 0x78, 0xf5, 0xa4,\n\t0xad, 0x08, 0x5b, 0x2d, 0x91, 0x54, 0x17, 0x70, 0x2d, 0x63, 0xa2, 0x39, 0x49, 0xcc, 0x4e, 0x0a, 0xe6, 0x50, 0x87, 0x2c, 0x70, 0x53, 0xa4, 0xd4, 0xe8, 0xcc, 0x5a, 0x4f, 0x56, 0x56, 0x41, 0x96, 0x2b, 0xe8, 0x76, 0xf9, 0x5d, 0x3a, 0x0e, 0x52, 0x24, 0x50, 0x60, 0xf7, 0xd8, 0x43, 0xb9, 0x21, 0xf8, 0x3f, 0xd4, 0x21, 0x94, 0x32, 0x85, 0x22, 0x33, 0xe0, 0x36, 0x76, 0xb3, 0xea, 0x0c, 0xb9, 0x44, 0xa9, 0x92, 0x28, 0x7c, 0x36, 0x9b, 0x07, 0xee, 0x39, 0x58, 0x39, 0xe7, 0xb0, 0x5a, 0x6d, 0x9a, 0xcc, 0x0c, 0x45, 0x26, 0x83, 0x22, 0x9d, 0x58, 0xaf, 0x55, 0x6f, 0xc9, 0x94, 0xb1, 0x12, 0x85, 0xc6, 0x69, 0xb5, 0xba, 0x0d, 0x6a, 0xa9, 0x44, 0xc6, 0x30, 0x70, 0x0d, 0x66, 0x68, 0x0d, 0x82, 0xff, 0x6b, 0x3b, 0xf9, 0x20, 0xf3, 0x14, 0x61, 0x20, 0xca, 0x05, 0x5d, 0x5b, 0x33, 0x51, 0x7e,\n\t0x79, 0xb8, 0x45, 0x48, 0xc2, 0x46, 0x09, 0xf4, 0x49, 0xf7, 0xdd, 0xc4, 0x49, 0xb8, 0x19, 0x3a, 0xab, 0xf3, 0xe9, 0x44, 0x18, 0xed, 0x34, 0xb7, 0xa2, 0x90, 0x51, 0x05, 0x80, 0xd6, 0x19, 0xd0, 0xfa, 0x6b, 0xf2, 0x6d, 0xd7, 0xe4, 0x76, 0x6f, 0x6f, 0x8b, 0xcd, 0x2d, 0x77, 0x5d, 0xc3, 0xac, 0xf7, 0x45, 0x4d, 0x32, 0x53, 0x6e, 0x5d, 0x76, 0xcd, 0xfa, 0xae, 0x02, 0x6b, 0xf9, 0xc2, 0x7a, 0xc1, 0x8e, 0x40, 0x6f, 0x23, 0x35, 0xa2, 0xed, 0xe5, 0x52, 0x3b, 0x02, 0xb3, 0x10, 0xd9, 0x11, 0x3a, 0x2f, 0xb1, 0x0f, 0xc8, 0x24, 0x69, 0xf6, 0x01, 0x06, 0xdd, 0x50, 0x2c, 0xd8, 0x07, 0xa8, 0x8c, 0x0f, 0x90, 0x65, 0x40, 0xb0, 0x0f, 0xd4, 0x7c, 0xf8, 0x21, 0x3c, 0x24, 0xc4, 0xef, 0xc3, 0xc1, 0x63, 0x50, 0x2d, 0x0f, 0x39, 0xd4, 0x48, 0xca, 0x88, 0x2b, 0x13, 0xf2, 0x02, 0xb8, 0x3e, 0x1c,\n\t0x58, 0x46, 0x08, 0xb1, 0x4e, 0xee, 0xa4, 0xd1, 0x80, 0x95, 0xc2, 0x85, 0x23, 0xa4, 0x28, 0x0d, 0x62, 0x2c, 0x26, 0x1c, 0x65, 0x81, 0x23, 0xf6, 0x83, 0x28, 0xb3, 0x95, 0x62, 0x97, 0x25, 0x2f, 0x95, 0x42, 0x3d, 0x97, 0xee, 0xbf, 0xf4, 0xca, 0xde, 0x84, 0x5d, 0xaf, 0x53, 0x40, 0x6e, 0x13, 0x0e, 0x06, 0x7c, 0xba, 0x32, 0x7d, 0xa9, 0x42, 0xab, 0xd0, 0xa8, 0x94, 0x32, 0x09, 0x21, 0x07, 0x72, 0x79, 0x1a, 0xaa, 0xad, 0xdb, 0x4c, 0x16, 0x4e, 0xb6, 0x45, 0x48, 0x68, 0x1c, 0x09, 0xe5, 0xe6, 0x04, 0x89, 0x69, 0x34, 0xb0, 0x82, 0x4b, 0x0e, 0xce, 0x29, 0xea, 0x83, 0xce, 0xf5, 0x33, 0x3d, 0xc7, 0x6e, 0xe7, 0xdf, 0xf8, 0xfc, 0x8e, 0x5b, 0x6e, 0xba, 0xed, 0xea, 0x9f, 0xed, 0x28, 0x77, 0xd5, 0x0e, 0xd5, 0x83, 0xd2, 0xfa, 0xbd, 0x3f, 0xdd, 0x3a, 0x76, 0xd1, 0xbc, 0x73, 0x35, 0x1c,\n\t0x5d, 0xb9, 0x73, 0x1b, 0xa7, 0x2d, 0x1e, 0xbd, 0x7d, 0xf8, 0xc1, 0x40, 0x6d, 0x5f, 0x7c, 0xc5, 0x76, 0xde, 0x4d, 0xb7, 0xf2, 0x59, 0x57, 0xae, 0xdc, 0xb6, 0xf6, 0xfe, 0xa2, 0x25, 0xd7, 0xf6, 0x14, 0x0d, 0xcc, 0xa9, 0x35, 0x54, 0xf1, 0x5f, 0xf4, 0x7f, 0x6f, 0x55, 0x05, 0x3d, 0xbe, 0xb8, 0xc7, 0x92, 0xaf, 0xd2, 0x07, 0xa4, 0xb6, 0xbc, 0xae, 0xa2, 0xf6, 0x9d, 0xbd, 0x79, 0xb0, 0x5f, 0xf9, 0xb0, 0x17, 0x2e, 0x48, 0xa7, 0x4c, 0xa8, 0xb7, 0x95, 0x26, 0xe2, 0x19, 0x4a, 0x9c, 0x17, 0x8f, 0xb2, 0x53, 0x50, 0xb6, 0x06, 0x4e, 0x36, 0x6f, 0x61, 0x91, 0x7a, 0xdf, 0x2f, 0xa0, 0x22, 0x6b, 0x38, 0x94, 0xe3, 0xc9, 0xd9, 0x35, 0x76, 0x35, 0x52, 0x6f, 0x33, 0x41, 0xa6, 0x24, 0x5d, 0x7f, 0x73, 0x73, 0x41, 0x84, 0x14, 0x9d, 0x8c, 0xee, 0x77, 0x73, 0x94, 0xec, 0xea, 0x97, 0x0e, 0xd4,\n\t0xd6, 0x5d, 0xf5, 0xc2, 0x95, 0x63, 0x5f, 0xbc, 0x07, 0x0c, 0xb7, 0x83, 0xfc, 0xee, 0x2d, 0x2d, 0x6e, 0x5f, 0xdb, 0xe6, 0x39, 0xfc, 0xaf, 0xa8, 0xe3, 0x33, 0x77, 0xde, 0xdb, 0xb7, 0xe4, 0xa1, 0x1d, 0x33, 0xa8, 0x3b, 0x6f, 0x04, 0x2b, 0xc6, 0xbe, 0x1a, 0xd3, 0xc5, 0xba, 0x96, 0xc7, 0x63, 0xc3, 0xed, 0x79, 0x63, 0xcf, 0x42, 0x8a, 0xe7, 0x8e, 0x7f, 0x4c, 0xff, 0x99, 0x39, 0x2d, 0xc4, 0x40, 0xa1, 0x98, 0x98, 0x08, 0x48, 0x2f, 0x6f, 0x86, 0x22, 0xfb, 0xe0, 0xc0, 0xac, 0x12, 0xd5, 0x26, 0xa1, 0x68, 0x26, 0x1e, 0x92, 0x95, 0x4c, 0x2b, 0x1a, 0x0b, 0xa7, 0xdd, 0x68, 0xd0, 0x72, 0x70, 0x14, 0x50, 0x0c, 0x94, 0x98, 0xe6, 0x99, 0x86, 0xcf, 0x9d, 0x9e, 0x24, 0x48, 0x1b, 0x34, 0x22, 0x98, 0x16, 0xc2, 0x6c, 0xbe, 0x5b, 0xae, 0x91, 0xfa, 0x9a, 0xe7, 0x0c, 0x56, 0x2d, 0x7d, 0x74,\n\t0x6f, 0xf3, 0x8c, 0x3d, 0x8f, 0xaf, 0x98, 0xbf, 0x7d, 0x76, 0xa1, 0x96, 0xd3, 0x4b, 0x1a, 0x7b, 0x3e, 0xba, 0xed, 0x04, 0xa0, 0x9e, 0x1e, 0x59, 0xfc, 0xc4, 0xd8, 0x89, 0x1f, 0x5e, 0xec, 0x99, 0x9b, 0x01, 0x8a, 0x64, 0x12, 0x77, 0xae, 0x43, 0xdd, 0x7c, 0xe4, 0xd5, 0x7d, 0x7b, 0x5e, 0xbb, 0xae, 0x25, 0x90, 0x1b, 0x50, 0x29, 0x06, 0xe7, 0x0c, 0xad, 0x3c, 0xc7, 0x7f, 0x7a, 0xf7, 0xdd, 0xfc, 0xa7, 0xe7, 0x56, 0xae, 0x5b, 0xd6, 0xaf, 0x12, 0x74, 0x87, 0xfe, 0xf1, 0x8f, 0xd9, 0x72, 0xf6, 0x1d, 0xc8, 0x4b, 0x70, 0x7f, 0x28, 0xd2, 0x9f, 0x89, 0x52, 0xe1, 0xa0, 0xd2, 0xc2, 0x48, 0x18, 0x5a, 0xb2, 0x06, 0x6d, 0xaf, 0x24, 0xec, 0x2a, 0xc4, 0x0a, 0x01, 0x89, 0x6b, 0x8e, 0x24, 0xb1, 0xe6, 0x50, 0x61, 0x52, 0x21, 0x66, 0x36, 0x10, 0xf2, 0x06, 0x82, 0xe1, 0x10, 0x56, 0x27, 0xfc,\n\t0x13, 0x15, 0x65, 0x50, 0x32, 0x97, 0xc1, 0x88, 0x6a, 0x5a, 0xa7, 0x82, 0xbb, 0x82, 0x48, 0x96, 0xdb, 0xc1, 0xf4, 0x61, 0x5e, 0x50, 0xdc, 0x33, 0x5c, 0xcf, 0xd8, 0x0f, 0x4f, 0x8c, 0x3d, 0xb1, 0x78, 0xe4, 0x69, 0x40, 0x9d, 0xe8, 0xb9, 0xa5, 0x16, 0x38, 0x1b, 0xd7, 0xcd, 0xa9, 0xe8, 0xcd, 0xb5, 0x4a, 0x03, 0xba, 0x60, 0x76, 0x4b, 0x43, 0xa3, 0x44, 0xc7, 0x69, 0x0b, 0xe7, 0x6c, 0xeb, 0x5b, 0xf1, 0xf8, 0x9e, 0x19, 0x2d, 0x7b, 0x1f, 0x1d, 0xae, 0x1a, 0x9c, 0xdb, 0xec, 0x93, 0x6a, 0xe4, 0x9a, 0x8c, 0x97, 0x97, 0xad, 0x5b, 0x79, 0x0e, 0xa8, 0xee, 0xbe, 0x1b, 0xa8, 0xce, 0xad, 0x74, 0x3b, 0xa5, 0x1a, 0x59, 0xcd, 0x96, 0xbe, 0xb8, 0x8e, 0x5b, 0xe5, 0x94, 0x33, 0x8a, 0xe5, 0x43, 0xcb, 0x07, 0x15, 0x2a, 0x48, 0x88, 0x96, 0xeb, 0x5e, 0xdb, 0xb3, 0xef, 0xd5, 0x23, 0xcd, 0x6a,\n\t0x47, 0xae, 0x5b, 0x22, 0x53, 0x61, 0x7e, 0x02, 0xd7, 0x25, 0xfb, 0x12, 0x9c, 0x6f, 0x4a, 0x22, 0x9b, 0x18, 0x78, 0xd2, 0x07, 0x04, 0x5b, 0x1a, 0x8e, 0x3f, 0x47, 0xdb, 0x11, 0x1c, 0x21, 0x00, 0xa7, 0xdc, 0x64, 0x18, 0x69, 0x07, 0xb2, 0x17, 0x00, 0x7a, 0x19, 0xd2, 0x38, 0xfb, 0x2f, 0xbd, 0xa0, 0x37, 0xa1, 0x57, 0x65, 0xa0, 0x4d, 0x85, 0xc9, 0x90, 0x91, 0xad, 0x8a, 0xc0, 0x69, 0xa9, 0x04, 0xca, 0x49, 0x89, 0x70, 0x6e, 0x38, 0x25, 0x85, 0x21, 0x66, 0xe9, 0xe9, 0xd7, 0xda, 0x78, 0x32, 0xfb, 0x8d, 0x7f, 0x1a, 0x34, 0xde, 0x09, 0xd8, 0x67, 0x46, 0x70, 0xde, 0xdb, 0xd8, 0x87, 0x53, 0x96, 0xd9, 0xe9, 0xe6, 0xeb, 0x5e, 0xde, 0xb3, 0xfb, 0x95, 0xeb, 0x9a, 0x2f, 0x3c, 0x43, 0x7f, 0xbc, 0xec, 0x59, 0xfe, 0x8b, 0x3b, 0xef, 0xe2, 0xbf, 0x7c, 0x76, 0xd9, 0xb4, 0x6b, 0x0b, 0xd5,\n\t0x1f, 0xca, 0xc6, 0x7d, 0xb5, 0xa3, 0xaa, 0x32, 0xa2, 0x5f, 0x68, 0x10, 0x07, 0x2c, 0x4b, 0x70, 0x6c, 0x33, 0x0b, 0x04, 0xd8, 0x20, 0x04, 0xa1, 0x93, 0x01, 0x75, 0x8b, 0x0c, 0x7b, 0x86, 0xdd, 0x66, 0xb5, 0x98, 0x32, 0x55, 0xf0, 0x26, 0x85, 0x1b, 0x25, 0x75, 0xfb, 0x39, 0x77, 0x72, 0xe8, 0x00, 0xfc, 0x2a, 0x4a, 0x68, 0x37, 0xe7, 0x8e, 0x51, 0xdd, 0xfc, 0xbf, 0x3b, 0xd7, 0xcd, 0x70, 0xbb, 0x9b, 0xd6, 0x75, 0x82, 0x3f, 0xf0, 0xae, 0x6d, 0xcf, 0xee, 0xab, 0x2f, 0xdf, 0xf9, 0xfc, 0x7e, 0xa0, 0x1c, 0x0b, 0x3f, 0x08, 0xfe, 0xe2, 0xae, 0x9a, 0x5f, 0x1a, 0x9f, 0x5f, 0xe3, 0xa3, 0x3f, 0xfb, 0x7a, 0xa8, 0x72, 0xdd, 0x5d, 0x83, 0x73, 0xaf, 0x5f, 0x56, 0x0e, 0x9e, 0xb9, 0x1f, 0xd5, 0xba, 0x41, 0xf5, 0x09, 0x31, 0x0e, 0x19, 0x8a, 0xc7, 0x13, 0x94, 0x85, 0xc5, 0x69, 0x61, 0xd4,\n\t0x13, 0xd5, 0x24, 0x27, 0x1c, 0xcd, 0x61, 0x10, 0x73, 0x63, 0x0c, 0x4d, 0x04, 0xf6, 0xf8, 0xca, 0xc5, 0x03, 0xe4, 0xbd, 0x63, 0xbf, 0x27, 0xdd, 0x63, 0x7d, 0xd4, 0xb6, 0x33, 0xe0, 0x8d, 0xfb, 0xc1, 0xcf, 0xcf, 0xa0, 0x3d, 0xc4, 0xf8, 0x27, 0x4c, 0x1b, 0xf3, 0x18, 0xe4, 0xb9, 0x45, 0x68, 0xd7, 0x33, 0x81, 0x78, 0x27, 0xc1, 0x56, 0xc5, 0xc5, 0x13, 0x90, 0x77, 0xc4, 0x04, 0x34, 0x1e, 0x41, 0x14, 0xe4, 0x45, 0xc2, 0xa8, 0xe8, 0x1a, 0xa7, 0x86, 0x77, 0xca, 0x7d, 0x52, 0x1c, 0xa5, 0x20, 0xce, 0x54, 0x21, 0x5c, 0x14, 0x68, 0x26, 0x23, 0xdd, 0xb9, 0x31, 0x10, 0x1e, 0x8d, 0x4d, 0x06, 0xee, 0x92, 0x65, 0x47, 0xfb, 0x16, 0xdf, 0xb6, 0xa6, 0x51, 0x79, 0x61, 0xac, 0x78, 0xdf, 0x8d, 0x27, 0x3a, 0x8e, 0x5d, 0x7c, 0x6a, 0xa4, 0xff, 0x91, 0xaf, 0xee, 0xd8, 0xfb, 0xbb, 0xbb, 0xfa,\n\t0x58, 0xb5, 0x59, 0x4b, 0xbd, 0xcf, 0xcc, 0xd8, 0xf5, 0xd8, 0xea, 0xc4, 0xd2, 0x39, 0xb5, 0x45, 0x11, 0x0d, 0x67, 0x91, 0x92, 0x4d, 0x0b, 0x6f, 0x5f, 0x55, 0x59, 0x71, 0xc5, 0xed, 0x03, 0xe4, 0xa1, 0xca, 0xae, 0x98, 0x69, 0xe8, 0x1c, 0xff, 0xa7, 0x1f, 0x1f, 0xe7, 0xf9, 0x9f, 0xae, 0xea, 0x3a, 0xf5, 0xaf, 0x5b, 0x9d, 0x61, 0x93, 0x7c, 0xff, 0x2f, 0x0e, 0xd4, 0xeb, 0x9d, 0x3e, 0xa7, 0x5e, 0xa5, 0x40, 0xeb, 0x76, 0xf1, 0xf8, 0x27, 0xf4, 0x3a, 0xe6, 0x0c, 0xd1, 0x48, 0xb4, 0x26, 0x66, 0xda, 0xa0, 0x7a, 0xab, 0x46, 0xdb, 0x21, 0xa4, 0xe3, 0x42, 0x85, 0x06, 0xf6, 0x4f, 0xc2, 0xa0, 0x75, 0x8b, 0x0c, 0x56, 0x8c, 0x04, 0x25, 0xb2, 0x8a, 0xc1, 0xaf, 0x93, 0xd6, 0x6d, 0x43, 0x1d, 0x42, 0x4b, 0xcc, 0xcb, 0x09, 0xf8, 0xdc, 0x4e, 0x8b, 0x09, 0x77, 0xd2, 0x3f, 0x61, 0x01, 0x10,\n\t0xeb, 0x84, 0x4f, 0x13, 0x96, 0x09, 0x35, 0xe2, 0x4b, 0x97, 0x2e, 0xbd, 0x2e, 0x77, 0xe3, 0x81, 0x9b, 0x3b, 0x06, 0x9f, 0xbe, 0xbe, 0x2b, 0xd8, 0x34, 0x92, 0xa8, 0x5f, 0x54, 0x66, 0x99, 0x71, 0xf5, 0xb9, 0x1d, 0xb7, 0xbd, 0xdf, 0x91, 0xa7, 0xb2, 0x29, 0x34, 0x05, 0xb3, 0xb7, 0xf6, 0xb6, 0xae, 0x6e, 0xf2, 0x46, 0x67, 0x6f, 0x68, 0xfa, 0xfb, 0x58, 0xd7, 0xae, 0xd9, 0xe1, 0xdc, 0xf9, 0xfb, 0xe6, 0xb6, 0xae, 0x6a, 0xcb, 0x57, 0xe3, 0xd5, 0xfb, 0x7a, 0xc5, 0xdc, 0x98, 0xb9, 0x74, 0xd5, 0xdd, 0xa3, 0x95, 0xab, 0x17, 0xcc, 0x34, 0xe9, 0xaa, 0x5a, 0xbb, 0xa3, 0xad, 0xd7, 0x8e, 0x56, 0x75, 0xcf, 0x9c, 0x63, 0x52, 0xba, 0x02, 0x2e, 0x6f, 0x79, 0x47, 0xa4, 0xb0, 0x23, 0x6e, 0xbd, 0x2d, 0xda, 0xd4, 0x9f, 0x57, 0x36, 0x38, 0x33, 0xcb, 0x19, 0xc9, 0x56, 0x4a, 0xf1, 0xfa, 0x05,\n\t0xe3, 0x6b, 0xf9, 0xe3, 0x74, 0x04, 0xce, 0x1d, 0x1b, 0x11, 0x4b, 0x14, 0xa8, 0x05, 0xab, 0x82, 0xe0, 0x49, 0x5b, 0x8c, 0x8c, 0xc5, 0x74, 0xaf, 0x50, 0x32, 0x48, 0x84, 0xfa, 0x5b, 0x83, 0xc3, 0x3a, 0x6d, 0x84, 0x4d, 0x9b, 0xe5, 0xe7, 0x38, 0xbc, 0x35, 0x44, 0x68, 0xc3, 0xdc, 0xd4, 0x62, 0x80, 0xf1, 0x18, 0x3c, 0x0c, 0xae, 0x26, 0x13, 0x63, 0xcf, 0x07, 0x3b, 0x77, 0xcc, 0x75, 0x17, 0xe7, 0x47, 0x4d, 0x36, 0xc8, 0x86, 0x34, 0xd9, 0xfa, 0x96, 0x7a, 0x6a, 0x1b, 0xfd, 0x2f, 0xde, 0x79, 0x66, 0xec, 0xcc, 0x9c, 0x6b, 0x87, 0x8a, 0x19, 0x99, 0x4a, 0xb6, 0xca, 0x21, 0x87, 0xea, 0xfe, 0xf2, 0x21, 0xe6, 0xc8, 0x19, 0xcc, 0x57, 0x7b, 0x21, 0x5f, 0xdd, 0x0e, 0xf9, 0x6a, 0x03, 0xb2, 0x67, 0x43, 0x95, 0x9a, 0x2d, 0x80, 0x93, 0x91, 0x31, 0xc1, 0xa5, 0xe5, 0x42, 0x70, 0x05, 0xcd,\n\t0x04, 0x8b, 0x86, 0x48, 0x32, 0x98, 0xd2, 0x8b, 0x45, 0xc9, 0x8d, 0x05, 0x46, 0xb2, 0x88, 0x5d, 0x28, 0x08, 0x37, 0x52, 0xfe, 0x50, 0x08, 0x9b, 0xac, 0x10, 0xfb, 0x9c, 0x40, 0xac, 0xc4, 0x84, 0xe7, 0x04, 0x14, 0x40, 0x6e, 0x32, 0x0e, 0x29, 0xdc, 0xca, 0xa6, 0x71, 0x5c, 0x21, 0x21, 0x8f, 0x29, 0xaf, 0x54, 0xe5, 0x58, 0x2d, 0xd5, 0xdd, 0x1b, 0x3a, 0x36, 0xfd, 0xf4, 0x40, 0x53, 0xeb, 0xd5, 0xcf, 0xac, 0x2d, 0x5e, 0xd0, 0x39, 0xd3, 0xf7, 0x86, 0xce, 0x0c, 0xce, 0xc5, 0x37, 0xee, 0xbf, 0xb5, 0xf7, 0x04, 0xff, 0xd5, 0xb3, 0xcb, 0x47, 0x9e, 0x07, 0xdc, 0x43, 0xc3, 0xf7, 0x35, 0x62, 0xae, 0x3b, 0x3f, 0x37, 0xd5, 0x5d, 0xfa, 0xfc, 0x80, 0x51, 0xc9, 0xa9, 0x43, 0x1e, 0x53, 0xdb, 0x0d, 0xaf, 0xec, 0xda, 0xff, 0x5f, 0x37, 0xb4, 0x2a, 0x74, 0x0e, 0x0d, 0x88, 0x9a, 0x34, 0x5b,\n\t0xc7, 0x7e, 0x15, 0x2c, 0x0b, 0x6a, 0x31, 0xe7, 0x3d, 0x05, 0xd4, 0x3f, 0x5b, 0xe1, 0x75, 0x05, 0x26, 0xf8, 0x2e, 0xa2, 0x88, 0x80, 0x75, 0xf3, 0x3e, 0xec, 0xdf, 0x28, 0x73, 0x07, 0x21, 0x83, 0x7a, 0x76, 0x76, 0x22, 0xac, 0xcd, 0xa0, 0xa8, 0x64, 0x50, 0xe4, 0xa0, 0x50, 0x8b, 0x6b, 0xbe, 0x20, 0xcc, 0x09, 0xc2, 0xa8, 0xcf, 0x54, 0x29, 0x15, 0xc8, 0x7b, 0x86, 0x0b, 0x83, 0x88, 0xf1, 0x91, 0xac, 0x44, 0x06, 0xdc, 0x32, 0xbc, 0x57, 0x95, 0xe1, 0xf0, 0xc8, 0x23, 0x1a, 0xd5, 0x2f, 0xa5, 0x7a, 0xf5, 0xcd, 0x32, 0x0d, 0x58, 0x0c, 0x1e, 0xbc, 0x70, 0x06, 0xfc, 0x60, 0xec, 0xc9, 0xd7, 0x8c, 0x46, 0x05, 0x78, 0x05, 0x3c, 0xa7, 0xb5, 0xbf, 0x72, 0x4a, 0xa9, 0x05, 0x2e, 0x63, 0x96, 0xee, 0x37, 0x4a, 0x05, 0x38, 0x33, 0xf6, 0x28, 0xd9, 0x4f, 0xd5, 0x64, 0x72, 0x63, 0x8b, 0xc9,\n\t0x93, 0x2e, 0x3c, 0x3e, 0x0f, 0x8d, 0xff, 0x9b, 0x5c, 0x0e, 0xdb, 0xc3, 0x11, 0xad, 0x42, 0x60, 0x7a, 0xa6, 0x50, 0xec, 0x5a, 0xe4, 0x7d, 0xab, 0xc9, 0x24, 0x5a, 0xfd, 0xe4, 0xe3, 0x2b, 0x05, 0x8c, 0xa9, 0x29, 0x97, 0xf6, 0xf6, 0x3e, 0xe9, 0xf7, 0xe2, 0x20, 0x14, 0x2d, 0x32, 0xcd, 0x94, 0x4f, 0x60, 0xc8, 0x3f, 0xf4, 0x56, 0x7d, 0x5b, 0xaf, 0x35, 0xa7, 0xca, 0x57, 0x3f, 0xd2, 0xe8, 0x63, 0xee, 0xb8, 0x70, 0xdb, 0xec, 0xf6, 0x19, 0x16, 0xaf, 0x41, 0x96, 0x33, 0x67, 0x9d, 0xa0, 0x7b, 0x3e, 0x86, 0x71, 0xd4, 0x1e, 0x82, 0x92, 0x67, 0x75, 0xcb, 0xa3, 0x01, 0xf8, 0x3e, 0xb9, 0x02, 0x90, 0xc0, 0x8c, 0x61, 0x0a, 0xac, 0xf8, 0x07, 0x2b, 0xfc, 0xe8, 0x15, 0x4e, 0xa3, 0x6c, 0x97, 0xa4, 0x16, 0x04, 0xfa, 0x10, 0xaf, 0x46, 0xd9, 0xd7, 0x29, 0x99, 0x94, 0x3c, 0x89, 0x13, 0x78,\n\t0x52, 0xb5, 0xdf, 0xc4, 0x0b, 0x50, 0xd4, 0x3b, 0x17, 0xcc, 0x0a, 0xf9, 0x5d, 0x38, 0xea, 0x1d, 0xa7, 0x68, 0x0a, 0xbb, 0xff, 0xd4, 0x44, 0x91, 0xa0, 0x5a, 0x92, 0x08, 0x8f, 0x10, 0x2f, 0x05, 0x28, 0x89, 0x70, 0x80, 0x68, 0x21, 0x38, 0xd0, 0x18, 0x28, 0x34, 0x02, 0x79, 0xf5, 0x99, 0x4d, 0x55, 0x9d, 0x4e, 0xad, 0xd4, 0xaf, 0x53, 0x67, 0x19, 0x4a, 0x7a, 0xec, 0x9f, 0x69, 0x73, 0xad, 0xae, 0x42, 0x23, 0xe9, 0xf8, 0xb1, 0xce, 0xae, 0xe7, 0x24, 0x7c, 0x81, 0xbe, 0x20, 0x77, 0xc1, 0x9b, 0x6f, 0x52, 0xb9, 0x1a, 0x17, 0x38, 0x3c, 0xd2, 0xa5, 0xc9, 0x58, 0xe9, 0x94, 0x51, 0x34, 0x9b, 0x17, 0xe1, 0xef, 0x74, 0x85, 0x94, 0x8a, 0xa0, 0x6b, 0x6c, 0x01, 0xab, 0xc8, 0x54, 0x90, 0xd9, 0x16, 0xf3, 0xd8, 0x46, 0x48, 0x7d, 0x40, 0x9c, 0x1a, 0xff, 0x44, 0xf2, 0x22, 0x5c, 0xbb, 0x05,\n\t0x44, 0xf7, 0x53, 0xf9, 0x6a, 0x14, 0x30, 0x89, 0x64, 0x2f, 0x32, 0x60, 0x1b, 0xa4, 0x12, 0x86, 0x42, 0x78, 0x91, 0x2c, 0xae, 0x94, 0x8d, 0x5c, 0xad, 0x42, 0x51, 0x1d, 0x4b, 0xf2, 0x04, 0x92, 0x07, 0xf8, 0xac, 0x90, 0xd9, 0x8b, 0x93, 0xbd, 0xd0, 0xd8, 0x14, 0x10, 0x05, 0x7e, 0xbd, 0x5f, 0x1f, 0x0a, 0xb8, 0x11, 0xdc, 0x32, 0x48, 0x4b, 0xd6, 0x0d, 0xa6, 0xe5, 0xec, 0xa6, 0x12, 0xb4, 0x39, 0x11, 0xce, 0x97, 0x93, 0xbc, 0xb8, 0xaa, 0x44, 0x69, 0x74, 0xb5, 0x2f, 0x5c, 0x9d, 0x68, 0x58, 0xdf, 0x57, 0x67, 0x70, 0x2d, 0x5c, 0xb3, 0xa3, 0x72, 0xdd, 0xe9, 0xf5, 0xa5, 0x6f, 0x86, 0x5b, 0x97, 0xd7, 0xd4, 0xac, 0x9e, 0x9d, 0xf3, 0x96, 0xbb, 0x76, 0x69, 0xc3, 0xc8, 0x03, 0x85, 0xcc, 0x89, 0xaf, 0x47, 0xe2, 0x8f, 0x20, 0xd4, 0x7c, 0x7f, 0xfd, 0xe2, 0xca, 0x86, 0xa1, 0x84, 0x63,\n\t0xc6, 0x35, 0xbf, 0xd8, 0x43, 0xdd, 0x70, 0x71, 0x4d, 0xff, 0xe1, 0x85, 0x79, 0xb9, 0x0b, 0x0f, 0x2f, 0x40, 0xdf, 0xbb, 0xae, 0x5d, 0x5c, 0x74, 0xec, 0x26, 0xea, 0x0f, 0x02, 0x8f, 0xda, 0xc8, 0xcc, 0x84, 0xfd, 0x0c, 0x10, 0x57, 0x3c, 0xa9, 0x49, 0xc3, 0x0c, 0x33, 0x42, 0xae, 0x9d, 0xea, 0x0b, 0x71, 0x49, 0xe2, 0xd6, 0xb4, 0xa7, 0xb1, 0xa7, 0x43, 0x27, 0x04, 0xa5, 0x2d, 0x4a, 0xbb, 0x00, 0xa7, 0x18, 0x41, 0x89, 0x0d, 0x5f, 0x12, 0xf0, 0x86, 0x22, 0xee, 0x94, 0xe5, 0x50, 0x28, 0x03, 0x3e, 0x11, 0x1d, 0x95, 0xe4, 0x6f, 0xc9, 0xb2, 0xe0, 0x1c, 0x33, 0x33, 0x59, 0xf6, 0xdb, 0xd3, 0xb2, 0x69, 0xd2, 0xca, 0x4f, 0x56, 0x01, 0x4f, 0x2f, 0xf3, 0xad, 0x47, 0x4c, 0x4f, 0xcb, 0xad, 0x4e, 0xb2, 0xbc, 0x47, 0x92, 0x45, 0xbf, 0x7f, 0x2d, 0xec, 0x73, 0x7a, 0xa1, 0xcc, 0xfd, 0x3b,\n\t0xd4, 0x91, 0xe5, 0x38, 0x4a, 0x14, 0x4a, 0x5d, 0x09, 0xa0, 0x58, 0x80, 0x23, 0x7f, 0xb0, 0x5e, 0x2c, 0x05, 0x58, 0x31, 0x16, 0x39, 0x1e, 0x54, 0x8c, 0x8d, 0x06, 0x54, 0x72, 0xd7, 0xed, 0x34, 0x84, 0x8d, 0x61, 0x85, 0x5e, 0xa1, 0x17, 0xa5, 0x2e, 0xb6, 0x51, 0x0b, 0xca, 0x71, 0xb1, 0xc8, 0xfa, 0x24, 0x69, 0x3a, 0x53, 0x8a, 0xe5, 0x81, 0x98, 0xac, 0x6d, 0xf7, 0x23, 0xa3, 0xa3, 0x8f, 0x5c, 0xd9, 0x26, 0x23, 0x95, 0x1d, 0xbb, 0x1e, 0x1a, 0x59, 0xfa, 0xd0, 0x95, 0xb3, 0x94, 0xe0, 0xef, 0x13, 0x3a, 0x53, 0x0a, 0x2b, 0x80, 0xbc, 0x66, 0xed, 0xe3, 0x3b, 0x6a, 0x6a, 0x76, 0x3c, 0xbe, 0xf6, 0xae, 0x15, 0x0f, 0x6d, 0xaa, 0xaa, 0xda, 0xf4, 0xd0, 0x0a, 0x72, 0xcf, 0x15, 0x2f, 0xf0, 0x9f, 0xde, 0x39, 0x05, 0x1e, 0x00, 0x92, 0xb7, 0x9f, 0xbf, 0x47, 0x12, 0xc3, 0xb5, 0x14, 0xcb,\n\t0x89, 0xd1, 0x84, 0x3c, 0x1f, 0x32, 0x66, 0x1b, 0x98, 0x48, 0xaf, 0x47, 0xd9, 0x39, 0x90, 0x55, 0x33, 0xb8, 0x37, 0x13, 0xc8, 0xba, 0x48, 0xc2, 0x2e, 0x63, 0xc5, 0xec, 0x9d, 0x4b, 0xcf, 0xaf, 0x16, 0xcf, 0x63, 0x54, 0xdd, 0xf2, 0xb2, 0x58, 0x61, 0x6e, 0xd4, 0xef, 0xb5, 0x98, 0x2e, 0x5f, 0xa1, 0x14, 0x88, 0x25, 0x69, 0x31, 0x54, 0xc2, 0xe4, 0x7a, 0x8d, 0x82, 0xd9, 0x0e, 0x1b, 0x0e, 0xc9, 0x4f, 0x87, 0xee, 0xd9, 0x58, 0x5d, 0xbd, 0xf1, 0x9e, 0xa1, 0x61, 0xe1, 0x93, 0xfa, 0xb5, 0x36, 0x58, 0x16, 0x8a, 0x2d, 0x8e, 0xd4, 0x34, 0x2c, 0x38, 0x7d, 0xfe, 0x96, 0x5b, 0xcf, 0x9f, 0xee, 0xef, 0x3f, 0x7d, 0xfe, 0xd6, 0xab, 0xde, 0x99, 0x5b, 0x7f, 0xf7, 0xd2, 0xce, 0x6d, 0xb3, 0xc3, 0x6f, 0xdd, 0xd3, 0x76, 0xfd, 0x6b, 0x7b, 0x76, 0xff, 0xf2, 0x86, 0xf6, 0xf6, 0x1b, 0x7e, 0xb9,\n\t0x7b, 0xcf, 0x6b, 0xd7, 0xb7, 0x51, 0xb7, 0x87, 0x1a, 0x0a, 0xed, 0x79, 0xc1, 0x85, 0x1f, 0x1d, 0x86, 0xc4, 0x38, 0xb7, 0x12, 0x32, 0x75, 0x91, 0x18, 0x9d, 0x2d, 0x0d, 0xf3, 0x0a, 0x17, 0x1d, 0x98, 0xf3, 0xf5, 0xb0, 0xa8, 0x2f, 0x33, 0x4f, 0xe0, 0x7d, 0x6c, 0x36, 0xb1, 0x2c, 0xa5, 0x2f, 0xa3, 0x0d, 0xac, 0x15, 0x25, 0xe5, 0x50, 0x34, 0xb6, 0xb1, 0x23, 0xf6, 0x28, 0x11, 0xa0, 0x13, 0xc4, 0x74, 0x26, 0x37, 0x82, 0xd5, 0x02, 0xcc, 0xb2, 0xd4, 0x45, 0x58, 0x77, 0x4e, 0xbf, 0xa6, 0x37, 0x61, 0x84, 0xec, 0x1a, 0x69, 0xcd, 0x46, 0x83, 0x4e, 0x91, 0xad, 0x8c, 0x08, 0xdb, 0x55, 0x69, 0x0a, 0xc0, 0x39, 0x00, 0x27, 0xb4, 0x56, 0xdc, 0xd8, 0x61, 0xd6, 0x34, 0x8d, 0xda, 0x7c, 0x73, 0xe7, 0xf6, 0x39, 0x59, 0xa7, 0xee, 0x7b, 0xff, 0xfd, 0x6b, 0x5e, 0x3d, 0x50, 0xdb, 0x78, 0xe8,\n\t0xe5, 0xfd, 0xef, 0xbf, 0x31, 0x45, 0x61, 0x26, 0x7f, 0x9c, 0xd5, 0xb6, 0xa2, 0x66, 0xdf, 0xcd, 0x63, 0x2f, 0x92, 0x7f, 0x4e, 0x6c, 0xbc, 0x6f, 0x78, 0xf8, 0xc1, 0x6d, 0x75, 0x63, 0xff, 0x9a, 0x56, 0x5f, 0x7e, 0x6c, 0x3c, 0x8b, 0xfe, 0x1f, 0xe6, 0x61, 0xd8, 0x57, 0x3f, 0xaa, 0x02, 0xed, 0x45, 0x5a, 0x05, 0x2a, 0x00, 0x48, 0xae, 0x87, 0x12, 0x1c, 0x10, 0x2c, 0x18, 0x94, 0xa4, 0x7a, 0x23, 0x26, 0x09, 0xc2, 0x7e, 0x00, 0xc2, 0x62, 0x42, 0x96, 0x16, 0x2d, 0x97, 0xa1, 0x98, 0xae, 0x0b, 0x70, 0x14, 0x27, 0x98, 0xab, 0x3e, 0x85, 0xc5, 0x6d, 0x30, 0x92, 0x4d, 0xb3, 0x77, 0xce, 0xcd, 0x3a, 0x75, 0xea, 0x17, 0xd4, 0xc0, 0x4f, 0x4b, 0x2d, 0xfc, 0x1d, 0x5c, 0x28, 0x74, 0xed, 0x9b, 0x6f, 0xfe, 0xe2, 0xda, 0x5f, 0xec, 0xab, 0xce, 0xe9, 0xdd, 0xdd, 0x19, 0xb2, 0x93, 0x1a, 0x54,\n\t0xcc, 0x77, 0xc7, 0xae, 0xb1, 0x7f, 0x8f, 0x99, 0xb2, 0xc1, 0x67, 0x66, 0x3d, 0x7f, 0x88, 0x79, 0xf8, 0xc3, 0xd2, 0xd1, 0x63, 0xfd, 0x2d, 0x57, 0x8d, 0xb6, 0xea, 0x4c, 0x11, 0xd8, 0xa8, 0xe6, 0xf1, 0x8f, 0xa9, 0x2f, 0xe0, 0xbc, 0xad, 0x44, 0x1a, 0xbe, 0x5d, 0xa8, 0x2e, 0x0c, 0xd9, 0x04, 0x8d, 0xd1, 0x91, 0x90, 0xb7, 0x69, 0x55, 0x5a, 0x6e, 0xa7, 0xe8, 0xc5, 0x84, 0x5a, 0x6f, 0x79, 0x69, 0xbc, 0x28, 0xa4, 0xcd, 0xf5, 0x20, 0xb6, 0xa1, 0x4d, 0x55, 0xb8, 0x99, 0xb0, 0xf1, 0x1b, 0xd2, 0xfc, 0x43, 0x6c, 0x3a, 0xa6, 0xf3, 0x96, 0x96, 0x57, 0xb6, 0xae, 0x7c, 0x60, 0x7d, 0x45, 0xf9, 0xc0, 0xf6, 0xdd, 0xdb, 0x07, 0xca, 0xaf, 0xdf, 0xd1, 0xb9, 0xb6, 0xb3, 0x58, 0x9f, 0x69, 0x96, 0x55, 0x86, 0x87, 0x36, 0xec, 0x6d, 0xd8, 0xf0, 0xc4, 0x8e, 0x9a, 0xf2, 0x81, 0x1d, 0xbb, 0x77,\n\t0x0c, 0x94, 0x3b, 0x2b, 0xfb, 0x2a, 0xea, 0x06, 0x1a, 0x72, 0x34, 0x9c, 0x41, 0xce, 0x18, 0x9b, 0xda, 0x6a, 0xae, 0x38, 0xd2, 0xb6, 0x68, 0xef, 0xfc, 0xf2, 0xdc, 0xec, 0x8a, 0x79, 0x89, 0x95, 0x1b, 0xb2, 0x63, 0xd9, 0x99, 0xca, 0xa5, 0x91, 0x86, 0x7c, 0x6b, 0xd5, 0x9a, 0x13, 0x0b, 0x7b, 0x76, 0xf4, 0x54, 0xe6, 0xe7, 0x54, 0x74, 0x96, 0x67, 0xb7, 0x97, 0xba, 0xdd, 0x61, 0x77, 0x26, 0xf2, 0x61, 0x66, 0xc3, 0xb9, 0xe7, 0x81, 0x73, 0xcf, 0x82, 0x62, 0x2c, 0x38, 0x14, 0x53, 0xd6, 0x4c, 0x26, 0x97, 0x16, 0x96, 0xc9, 0x50, 0x85, 0xb0, 0x98, 0xdc, 0x28, 0xaa, 0xcd, 0x28, 0xd4, 0xf3, 0x10, 0xe1, 0xa9, 0xd3, 0xa7, 0x88, 0x9b, 0xf1, 0xf0, 0x25, 0x6f, 0xfe, 0xa8, 0xb6, 0xaf, 0xd8, 0x2c, 0x17, 0xa6, 0x85, 0xae, 0x78, 0xc5, 0xed, 0x43, 0xd4, 0x3c, 0xfa, 0x7f, 0x2f, 0x18, 0xe8,\n\t0xff, 0xd5, 0x87, 0xab, 0xb3, 0x4c, 0x79, 0x93, 0x26, 0x02, 0x96, 0xd5, 0x0e, 0x7e, 0x23, 0x7d, 0x15, 0x7c, 0xb7, 0x89, 0xb8, 0xee, 0x49, 0x21, 0x14, 0x35, 0xc9, 0xc3, 0x91, 0x0d, 0x46, 0xd0, 0x32, 0x01, 0x98, 0x88, 0x15, 0x4d, 0xf1, 0xf0, 0x69, 0x4e, 0x2f, 0xc7, 0xa7, 0x11, 0x64, 0x83, 0x0e, 0x1f, 0x23, 0xc8, 0x45, 0x13, 0x97, 0x51, 0x18, 0x68, 0x0f, 0x81, 0x6d, 0x81, 0x94, 0xc9, 0x2b, 0xfd, 0x2c, 0xae, 0xfb, 0xc5, 0x71, 0x7a, 0xbf, 0x1b, 0xfb, 0x63, 0x70, 0x2c, 0x6a, 0x3c, 0x2d, 0x14, 0x35, 0x86, 0x76, 0x44, 0x7a, 0x37, 0xf9, 0x4c, 0xf3, 0x6c, 0x4f, 0x54, 0xa5, 0xb0, 0x48, 0xf4, 0xd1, 0x79, 0x85, 0x0b, 0xf6, 0xcd, 0x09, 0xf0, 0x71, 0x7a, 0x29, 0x5f, 0x92, 0xbd, 0xe8, 0x0a, 0x95, 0xda, 0xd4, 0xa5, 0xe5, 0xe2, 0x4b, 0xae, 0x99, 0xc3, 0x10, 0x3f, 0xfc, 0x21, 0xca,\n\t0x87, 0x1a, 0xff, 0x98, 0xf9, 0x18, 0xf6, 0xad, 0x1c, 0xe5, 0xfb, 0x14, 0xc8, 0xa1, 0xb4, 0x0d, 0xe9, 0x50, 0x6c, 0x51, 0xb3, 0xb0, 0x90, 0x53, 0x18, 0x28, 0x42, 0xde, 0x1d, 0xdc, 0x3c, 0x00, 0x22, 0x2f, 0x27, 0x12, 0x76, 0xda, 0xb5, 0x9c, 0x4a, 0x49, 0x94, 0x83, 0x72, 0xb4, 0xb7, 0x65, 0x92, 0x5b, 0x07, 0x0c, 0x29, 0x5c, 0x14, 0x2f, 0x74, 0xeb, 0x91, 0xa3, 0x75, 0x02, 0x5a, 0x21, 0x88, 0x70, 0x86, 0xed, 0x00, 0xa3, 0xce, 0x52, 0x68, 0xca, 0x53, 0x59, 0x37, 0x8e, 0x3d, 0x7b, 0x45, 0xd5, 0xea, 0xdb, 0xfa, 0x42, 0xb3, 0x03, 0xfc, 0xc7, 0x41, 0x37, 0xa9, 0x68, 0xbf, 0x7a, 0xa8, 0xb4, 0x63, 0xff, 0xa3, 0x8b, 0x17, 0x3f, 0xba, 0xbf, 0xbd, 0x74, 0xf0, 0xea, 0x76, 0x52, 0xe1, 0x0e, 0xc2, 0x33, 0x9d, 0xa1, 0xbe, 0x5b, 0x57, 0x57, 0x5f, 0xf1, 0xec, 0x58, 0xe6, 0xe2, 0xc7,\n\t0xce, 0x1f, 0x5f, 0xfd, 0x9f, 0x77, 0x6d, 0x74, 0xb1, 0x92, 0x2b, 0x9c, 0x81, 0xf3, 0xaa, 0x45, 0x47, 0x9e, 0x1a, 0xd9, 0x76, 0x76, 0x5b, 0x45, 0x05, 0xfc, 0x67, 0xe4, 0xa9, 0x23, 0x8b, 0x54, 0xe7, 0x03, 0xce, 0x2b, 0x24, 0xac, 0x6b, 0xe3, 0x5d, 0xff, 0xb9, 0xfa, 0xf8, 0xf9, 0xc7, 0x04, 0x5c, 0x8b, 0x7b, 0xc7, 0xff, 0xc5, 0xcc, 0xc3, 0x76, 0x9b, 0xf9, 0xd8, 0xd5, 0xfa, 0x64, 0x14, 0x61, 0x21, 0x34, 0x5b, 0xd1, 0x27, 0x5c, 0x1f, 0x62, 0x2e, 0xb5, 0x81, 0x10, 0x54, 0x0d, 0xbc, 0x32, 0xd2, 0x52, 0x11, 0x51, 0x48, 0x23, 0x39, 0x29, 0x25, 0x3a, 0x2d, 0xc1, 0xfc, 0xa9, 0x2c, 0xa8, 0x6b, 0x08, 0xf9, 0x76, 0x22, 0xb6, 0x13, 0x39, 0x55, 0xcd, 0xa0, 0x93, 0x75, 0xc5, 0x11, 0x8c, 0x25, 0x55, 0x93, 0x37, 0x2f, 0xf6, 0xf8, 0xfd, 0x89, 0x35, 0xb7, 0x3d, 0xf9, 0x8b, 0xa5, 0xdd,\n\t0xd7, 0x0f, 0x17, 0xbf, 0x61, 0x2b, 0x6a, 0xcb, 0xab, 0x39, 0x78, 0xe5, 0x9a, 0x39, 0x79, 0x0a, 0x57, 0x59, 0x8e, 0x36, 0x4b, 0xab, 0x0b, 0x48, 0xad, 0xcc, 0x41, 0x4e, 0xfb, 0xc7, 0x5f, 0xdf, 0xc8, 0x7f, 0xfe, 0xe1, 0x33, 0xfb, 0x67, 0x96, 0x6c, 0x7c, 0x7c, 0x07, 0xf5, 0x5f, 0x17, 0x73, 0x3b, 0x56, 0xcf, 0x70, 0x97, 0x2c, 0xbf, 0xe5, 0xf9, 0x0f, 0xf7, 0x14, 0xf5, 0xd7, 0x87, 0x58, 0x38, 0x79, 0x1d, 0xab, 0xf1, 0x1e, 0x68, 0x0c, 0xae, 0x8b, 0xef, 0x41, 0x3e, 0xe5, 0x24, 0x16, 0x08, 0xb3, 0x4e, 0x89, 0x24, 0xae, 0x5d, 0xc7, 0xa1, 0x18, 0x35, 0xa8, 0x49, 0xa2, 0x9f, 0x54, 0xf2, 0xa7, 0x98, 0x5d, 0xcf, 0x61, 0x33, 0x3c, 0x05, 0xc4, 0x12, 0xb2, 0x43, 0xa4, 0x60, 0x69, 0x15, 0xd6, 0xd1, 0x44, 0x69, 0x59, 0x78, 0xbc, 0xf7, 0xac, 0x47, 0x17, 0xf2, 0x08, 0xe8, 0xe8, 0x53,\n\t0x14, 0xc6, 0x64, 0x02, 0x11, 0x86, 0x8c, 0x8d, 0x17, 0x53, 0x77, 0x24, 0x6e, 0x1f, 0x8d, 0x77, 0xe6, 0x5a, 0xa5, 0x41, 0x9d, 0x3a, 0x62, 0xcc, 0x6f, 0x72, 0xf0, 0x47, 0xde, 0x18, 0xfb, 0xf4, 0x27, 0x36, 0x8f, 0x02, 0x94, 0x68, 0x9d, 0x0a, 0x43, 0x88, 0x7e, 0x73, 0xfd, 0xa0, 0x96, 0x5b, 0x86, 0x76, 0x07, 0xb2, 0x58, 0xc1, 0xd8, 0xcd, 0x63, 0x2f, 0x91, 0x25, 0xd4, 0x90, 0xd5, 0x30, 0xf6, 0x17, 0x7f, 0xc2, 0x95, 0x68, 0x40, 0x31, 0xa7, 0x50, 0x8b, 0xdd, 0x01, 0xe7, 0xa2, 0x01, 0xf9, 0x4a, 0x15, 0x08, 0x82, 0x11, 0x19, 0xff, 0x68, 0x1c, 0x64, 0xba, 0x18, 0x4a, 0x4f, 0x49, 0x2f, 0x21, 0x91, 0x60, 0xfd, 0x16, 0x67, 0x1a, 0x41, 0xcd, 0x96, 0x83, 0x8b, 0x01, 0xfe, 0xd5, 0xe2, 0x8d, 0x92, 0x90, 0x63, 0x94, 0x84, 0x13, 0x47, 0x89, 0x46, 0xe8, 0x2f, 0xbd, 0xc3, 0xc8, 0xff,\n\t0x10, 0x54, 0xf3, 0x1d, 0xfc, 0x03, 0x94, 0xfb, 0xc2, 0x4b, 0x0a, 0x19, 0x58, 0xc9, 0xbf, 0x08, 0x7e, 0x00, 0x2a, 0x2e, 0x7e, 0x45, 0x3b, 0x98, 0x36, 0xbf, 0x8b, 0xcf, 0xba, 0x8b, 0xb7, 0x9d, 0x99, 0xcb, 0x39, 0x54, 0x24, 0x71, 0x17, 0x78, 0xf6, 0x8c, 0xb0, 0xe6, 0xf3, 0xe0, 0x3e, 0xbb, 0x06, 0xeb, 0xa7, 0x55, 0x89, 0xf2, 0x5c, 0x40, 0x33, 0x41, 0xb8, 0x2c, 0xd1, 0x1e, 0x93, 0x6a, 0x46, 0xba, 0x36, 0x2d, 0xf8, 0x4d, 0x69, 0xe4, 0x37, 0x4d, 0xcf, 0xf9, 0xc6, 0xa6, 0x49, 0x38, 0x39, 0x38, 0x3d, 0x32, 0x98, 0x63, 0xaf, 0x92, 0x30, 0xe1, 0x27, 0x32, 0xe0, 0xd2, 0xed, 0x7e, 0x11, 0x90, 0x6c, 0x2a, 0x8a, 0xb6, 0x22, 0x87, 0xaf, 0x7c, 0x72, 0x7d, 0xac, 0xef, 0xb6, 0x57, 0xd6, 0xce, 0xbc, 0x66, 0xfb, 0x68, 0x78, 0xb6, 0x42, 0xcb, 0x2a, 0x75, 0xda, 0xcc, 0x58, 0xdb, 0x50,\n\t0xf5, 0xdc, 0xdd, 0x3d, 0xd1, 0xc0, 0xdc, 0x43, 0x83, 0x0f, 0xab, 0x38, 0xb0, 0x6d, 0x6c, 0x25, 0xf5, 0xac, 0xc2, 0x40, 0x6d, 0x61, 0x6a, 0x56, 0x1e, 0xe9, 0xdc, 0xf0, 0xf4, 0xde, 0x46, 0x47, 0xe9, 0xec, 0xd8, 0x42, 0x25, 0x2d, 0xcd, 0xd4, 0x64, 0x07, 0x2d, 0x05, 0x5d, 0x6b, 0xaa, 0x8b, 0x17, 0xd4, 0x07, 0xfb, 0x39, 0x1f, 0x07, 0xd6, 0x9e, 0xe9, 0xd0, 0x84, 0x75, 0xb0, 0x3f, 0x3d, 0xb0, 0x3f, 0xa3, 0xb8, 0x3f, 0x79, 0x89, 0x28, 0x64, 0x31, 0xa8, 0x2a, 0xd2, 0x1a, 0x82, 0x86, 0x8a, 0x37, 0xb3, 0x0a, 0xed, 0x90, 0x7b, 0x85, 0x89, 0x2e, 0xb8, 0xc5, 0x70, 0xb1, 0x68, 0x3f, 0xa7, 0x37, 0xe1, 0x0a, 0x18, 0xe9, 0xb6, 0x01, 0x01, 0xa3, 0x1d, 0x52, 0x19, 0x95, 0x18, 0xb9, 0xc4, 0x18, 0x60, 0x30, 0xd2, 0xa3, 0xe1, 0xd1, 0xed, 0xd7, 0xcc, 0x5c, 0xfb, 0xca, 0x6d, 0x7d, 0xb1,\n\t0xf5, 0x4f, 0xec, 0xe6, 0x57, 0x19, 0x14, 0xd4, 0xb3, 0x63, 0x2b, 0xc1, 0x36, 0x2e, 0xe3, 0xa1, 0xc1, 0x43, 0xf3, 0x02, 0xd1, 0x9e, 0x3d, 0x73, 0xab, 0x87, 0xda, 0x62, 0x99, 0x5a, 0x9d, 0x42, 0xa2, 0x51, 0xbc, 0x1e, 0x9b, 0x5d, 0xea, 0x68, 0xdc, 0xfb, 0xf4, 0x86, 0xce, 0xeb, 0x57, 0xd4, 0x30, 0xe0, 0x80, 0x2e, 0xac, 0xe9, 0x38, 0xc3, 0x5f, 0x0f, 0x5b, 0xde, 0x1f, 0xac, 0x5f, 0x50, 0x5c, 0xbd, 0xa6, 0xab, 0xc0, 0x12, 0xcc, 0xd6, 0x64, 0x4a, 0x69, 0x25, 0xec, 0x43, 0xc9, 0xf8, 0xc7, 0x74, 0x0e, 0xe6, 0x55, 0xcb, 0x12, 0x4a, 0xa8, 0x5e, 0x81, 0xdc, 0x1c, 0x3d, 0x64, 0x8e, 0x48, 0x2f, 0x0b, 0x60, 0x2c, 0x3b, 0x80, 0x8b, 0x3d, 0x0d, 0x22, 0x7b, 0x1c, 0x4e, 0xfe, 0x9d, 0xd8, 0xfc, 0xe3, 0xfd, 0x9b, 0x8f, 0x40, 0x49, 0xa0, 0xcc, 0xb2, 0xe4, 0x75, 0xb0, 0xa3, 0xec, 0xfc,\n\t0xa9, 0x97, 0xc1, 0xcd, 0x92, 0xbe, 0x21, 0x14, 0x0d, 0x79, 0x3d, 0x42, 0xb2, 0x3e, 0xeb, 0x75, 0x53, 0xe9, 0x65, 0xdf, 0x02, 0x97, 0x8e, 0xa2, 0x50, 0x4b, 0x8f, 0xf5, 0xe0, 0xb8, 0x4b, 0x04, 0x61, 0xcf, 0xc6, 0xaa, 0xf8, 0xa1, 0xd1, 0x70, 0xab, 0x6f, 0xef, 0x0b, 0x7b, 0x13, 0xdd, 0x37, 0x3e, 0x33, 0xfc, 0xd0, 0x27, 0xb3, 0x67, 0x2a, 0x38, 0xa9, 0x5c, 0x23, 0xd5, 0x16, 0x77, 0x8c, 0x36, 0xf4, 0xec, 0xea, 0x0c, 0xe6, 0x74, 0xed, 0x68, 0xab, 0xdc, 0x5d, 0xb1, 0xed, 0x24, 0xe7, 0xd7, 0x54, 0x1a, 0x1c, 0x5a, 0x19, 0xf5, 0x7d, 0x66, 0x46, 0x56, 0x8c, 0xbf, 0x57, 0x22, 0xa9, 0xdb, 0x7c, 0x6a, 0x60, 0xed, 0x53, 0x7b, 0x1a, 0x36, 0x8e, 0xce, 0xcb, 0x90, 0xca, 0xa4, 0x99, 0xd9, 0x61, 0x7b, 0x51, 0xf7, 0xda, 0xca, 0x9a, 0xa1, 0x7a, 0xaf, 0x46, 0xe7, 0x23, 0xd5, 0xa4, 0x52,\n\t0x63, 0x54, 0x8c, 0x08, 0xf3, 0x74, 0x3e, 0xe4, 0xdf, 0x7f, 0x81, 0xfc, 0xad, 0x0a, 0xd9, 0x1b, 0x0c, 0xb8, 0x76, 0x1b, 0xf2, 0x00, 0x02, 0x1a, 0xce, 0x53, 0x29, 0x21, 0x61, 0xa5, 0x92, 0x41, 0x19, 0x60, 0xd1, 0x32, 0x62, 0x89, 0x54, 0xd5, 0x83, 0x15, 0x02, 0x2c, 0x92, 0x30, 0x55, 0xab, 0x2a, 0xb5, 0x6e, 0xad, 0x3f, 0x94, 0x1d, 0xf2, 0x67, 0xca, 0x11, 0x22, 0x8b, 0x57, 0x3f, 0xd9, 0xac, 0xe0, 0x20, 0x8d, 0xd3, 0x98, 0x20, 0x62, 0x82, 0x09, 0x42, 0xfc, 0xe0, 0x0a, 0x99, 0xbf, 0xdc, 0x2d, 0x9a, 0x13, 0xbe, 0x16, 0xcd, 0x09, 0x5d, 0x47, 0x77, 0xad, 0x88, 0x56, 0xa8, 0x72, 0xac, 0xd6, 0xea, 0xae, 0x8d, 0x1d, 0x1b, 0xd3, 0xad, 0x0f, 0x6f, 0xeb, 0xcd, 0x80, 0x7d, 0xdb, 0x60, 0x02, 0xff, 0x79, 0x37, 0xe8, 0x78, 0x71, 0xb2, 0x1d, 0xc1, 0x92, 0x57, 0x97, 0x35, 0x9d, 0xd1,\n\t0x61, 0xc8, 0xa8, 0x5d, 0xbe, 0xd9, 0xa8, 0xbd, 0x82, 0xff, 0x54, 0xd8, 0x3f, 0x8f, 0x7f, 0x02, 0xb7, 0x83, 0x27, 0xa0, 0x5e, 0x70, 0x4a, 0x60, 0x6a, 0x7e, 0x82, 0x21, 0x48, 0x09, 0x43, 0x2e, 0x66, 0xb1, 0x4b, 0x44, 0x06, 0xa4, 0xd2, 0x64, 0x2a, 0xb8, 0x44, 0x82, 0xc3, 0xd0, 0x27, 0x25, 0x97, 0x5f, 0xf6, 0x62, 0xc8, 0x57, 0x84, 0x3b, 0x92, 0x22, 0x20, 0x8f, 0x90, 0x49, 0x19, 0xa9, 0x8c, 0x59, 0x33, 0xf9, 0x1e, 0xe2, 0xb2, 0xb7, 0x40, 0x21, 0xad, 0x8a, 0x84, 0x03, 0x5e, 0x64, 0xaf, 0xd4, 0x87, 0xdc, 0x98, 0xa8, 0xf1, 0x49, 0x25, 0x32, 0x2a, 0xb1, 0x82, 0x52, 0x88, 0x82, 0xf8, 0xa9, 0x64, 0x25, 0x64, 0x64, 0x21, 0x87, 0xda, 0x21, 0x5b, 0xd1, 0x39, 0x30, 0xe7, 0x8a, 0x84, 0xa5, 0xf7, 0xc6, 0x67, 0x06, 0x3b, 0xaf, 0x5f, 0x59, 0x35, 0xa6, 0x7d, 0xeb, 0x2d, 0xf2, 0xa3,\n\t0x37, 0xc1, 0xe2, 0xde, 0x9a, 0xf5, 0xdd, 0x05, 0x15, 0xcd, 0x46, 0xaf, 0xc2, 0xcd, 0x52, 0xff, 0x32, 0x97, 0x0e, 0xec, 0x6a, 0xf8, 0x01, 0xff, 0xf5, 0x0f, 0xba, 0x73, 0x96, 0xde, 0xb3, 0xe9, 0xaf, 0x63, 0x5b, 0x99, 0x13, 0x63, 0x07, 0xc8, 0x6d, 0x17, 0xa9, 0x6b, 0xf7, 0x55, 0xef, 0xfb, 0xf9, 0xc1, 0x81, 0x41, 0x79, 0x40, 0x88, 0xbd, 0x79, 0x8c, 0x7f, 0x88, 0xc9, 0x83, 0xf2, 0x41, 0x0d, 0x37, 0x87, 0xa1, 0x84, 0x3f, 0x00, 0x15, 0x27, 0x67, 0xa6, 0x1a, 0x83, 0xf9, 0x62, 0x63, 0x19, 0x26, 0x0c, 0x66, 0xf7, 0xcb, 0xc8, 0x56, 0xce, 0x12, 0x0e, 0x23, 0x66, 0xef, 0x8f, 0xfb, 0x04, 0x44, 0x2b, 0xb1, 0xfc, 0x53, 0xb2, 0xc0, 0x07, 0x4b, 0xa7, 0x12, 0xe2, 0x0f, 0x3c, 0x02, 0x54, 0x3f, 0x5a, 0x94, 0xdd, 0xb1, 0xa6, 0xa1, 0x6a, 0xc3, 0xe8, 0xc2, 0x2c, 0xaa, 0x6c, 0xf5, 0xba,\n\t0x4d, 0x35, 0x6b, 0x1f, 0xdb, 0x9a, 0x38, 0x70, 0x9e, 0xbf, 0xef, 0xcd, 0x37, 0x11, 0x92, 0xc7, 0x3d, 0xcd, 0x0f, 0x9c, 0xfb, 0xc3, 0xbe, 0xa6, 0x0d, 0xb3, 0xb3, 0xdd, 0x55, 0x5d, 0xb1, 0xd7, 0xca, 0x3a, 0x0b, 0x0c, 0xb3, 0xaf, 0x7e, 0x64, 0xc1, 0x7d, 0xfc, 0xef, 0xbf, 0xfa, 0x4d, 0x37, 0xff, 0x1a, 0x7b, 0x71, 0x02, 0x1b, 0xe5, 0x21, 0x8c, 0x8d, 0xe2, 0x40, 0x16, 0x22, 0x07, 0xe4, 0xf6, 0x46, 0xe4, 0xb2, 0xc7, 0x45, 0xdb, 0xc5, 0x84, 0x38, 0x91, 0xc6, 0x42, 0xb6, 0x10, 0xdc, 0xe2, 0xfb, 0x04, 0xa9, 0x4b, 0xa5, 0xa2, 0x27, 0xa6, 0xc2, 0x8d, 0x54, 0xae, 0x5a, 0xb5, 0x1e, 0xc3, 0x8d, 0xbc, 0x35, 0x05, 0x5d, 0xe4, 0xb5, 0x1a, 0x11, 0x5d, 0xe4, 0xeb, 0xff, 0x66, 0xec, 0x69, 0x78, 0x22, 0xf7, 0xe1, 0xc6, 0x90, 0xc4, 0x20, 0xe4, 0x31, 0x77, 0xc2, 0x79, 0xa5, 0x25, 0x3a,\n\t0x50, 0x54, 0x45, 0x7d, 0x9e, 0x4d, 0x8e, 0x3d, 0xea, 0x0c, 0x6c, 0x50, 0xd2, 0x62, 0x25, 0x8e, 0x33, 0x06, 0xbc, 0xeb, 0xd0, 0xb5, 0x97, 0x95, 0x04, 0xfd, 0xc9, 0xe0, 0xa1, 0xe4, 0x26, 0x2e, 0x28, 0xe8, 0x3f, 0x49, 0xdc, 0xb0, 0x09, 0x19, 0x90, 0xb2, 0xb0, 0xc6, 0x8b, 0x61, 0x4b, 0x25, 0x42, 0x3c, 0xbf, 0x11, 0x17, 0xe8, 0x09, 0x06, 0xe2, 0x85, 0xe4, 0x9e, 0x99, 0xdb, 0x7b, 0xf3, 0xd1, 0xe0, 0xd6, 0x6c, 0xe8, 0x2e, 0x2a, 0xe8, 0xd9, 0x4e, 0x02, 0xaf, 0xab, 0xa0, 0x6b, 0x5d, 0x75, 0xc3, 0xae, 0xc5, 0xa5, 0x33, 0xaf, 0x7d, 0x79, 0xcf, 0x9e, 0x97, 0xaf, 0x99, 0x59, 0xbe, 0x64, 0x4f, 0x23, 0x3a, 0xed, 0x0c, 0xdd, 0x62, 0xd6, 0x2a, 0xb5, 0xa6, 0xc2, 0xee, 0x0d, 0x89, 0xb2, 0x91, 0xd6, 0xa8, 0x51, 0xa7, 0xd4, 0xf9, 0x6f, 0x73, 0xd5, 0x8d, 0x34, 0x25, 0x16, 0xb7, 0x56,\n\t0xd8, 0x6d, 0x95, 0xad, 0x8b, 0x13, 0x4d, 0x23, 0x75, 0x2e, 0x86, 0xcc, 0x5b, 0x5d, 0xd4, 0xb2, 0x61, 0x7e, 0xa3, 0xc3, 0xd5, 0x36, 0x72, 0xf5, 0xfc, 0x81, 0x3b, 0x56, 0x55, 0x54, 0xac, 0xba, 0x63, 0xa0, 0x7b, 0xdf, 0x60, 0xb3, 0xd3, 0xd1, 0xb4, 0x70, 0x6b, 0x47, 0xc9, 0x50, 0xb1, 0xcf, 0x62, 0x6f, 0xce, 0xa9, 0xe8, 0x6b, 0x2a, 0xb3, 0xfe, 0x7f, 0xe4, 0xbd, 0x07, 0x74, 0x1c, 0xc7, 0x95, 0x2e, 0xdc, 0xd5, 0x61, 0x72, 0xce, 0x98, 0x3c, 0x98, 0x8c, 0x30, 0x18, 0x60, 0x30, 0x83, 0x0c, 0x0c, 0x40, 0xe4, 0x41, 0x20, 0x40, 0x02, 0x04, 0x88, 0xc0, 0x80, 0xc0, 0x4c, 0x82, 0x14, 0x83, 0x28, 0x06, 0x49, 0x4c, 0x22, 0x29, 0x89, 0x0a, 0xa4, 0x6c, 0x2b, 0x38, 0x48, 0xb6, 0x68, 0x99, 0x92, 0x6c, 0x4b, 0x32, 0x25, 0xdb, 0x92, 0x65, 0xcb, 0xa4, 0xed, 0xf5, 0xea, 0x39, 0xae, 0x1c,\n\t0x76, 0xed, 0xf5, 0xda, 0xbb, 0x7e, 0x6b, 0xaf, 0xd3, 0x93, 0xe4, 0x67, 0x3f, 0x05, 0x62, 0xf0, 0xaa, 0xaa, 0xbb, 0x67, 0x7a, 0x06, 0x41, 0xb4, 0xdf, 0xff, 0x9f, 0xf7, 0x9f, 0xf3, 0xeb, 0x1c, 0x0a, 0xe8, 0x9e, 0xaa, 0x41, 0xf7, 0xad, 0xaa, 0x5b, 0xf7, 0xde, 0xfa, 0xee, 0x77, 0xad, 0xb5, 0xdd, 0x13, 0xf5, 0x45, 0x5d, 0x0e, 0x6b, 0x80, 0xcd, 0x59, 0x79, 0x88, 0x3e, 0x0b, 0xe5, 0xe1, 0x25, 0x4e, 0xb3, 0x66, 0xab, 0xcc, 0x02, 0x9d, 0x7a, 0x29, 0x76, 0x87, 0x6d, 0x99, 0x0b, 0x12, 0xdb, 0x16, 0x85, 0xf8, 0x28, 0x33, 0xb3, 0x1d, 0x8a, 0x81, 0x48, 0xc4, 0x6e, 0xd4, 0x29, 0x36, 0x2d, 0x96, 0x65, 0x25, 0x44, 0xd5, 0xd8, 0x10, 0x33, 0x04, 0x22, 0x4e, 0x59, 0xaa, 0x2d, 0xcf, 0x9c, 0x32, 0x47, 0x70, 0x4c, 0x6c, 0x5e, 0xc2, 0xab, 0x35, 0x1a, 0x3d, 0x7e, 0x4c, 0xaa, 0xe9, 0x37,\n\t0xe6, 0x31, 0xf8, 0x34, 0xa2, 0xd5, 0x94, 0xdd, 0x45, 0xc5, 0x80, 0x3e, 0xeb, 0x5f, 0x7d, 0x64, 0x38, 0xba, 0xa6, 0xd4, 0x28, 0xb2, 0x2a, 0x94, 0x91, 0xc2, 0x50, 0x5d, 0x50, 0x77, 0x63, 0x56, 0x2e, 0xa5, 0x6c, 0x68, 0xc7, 0x37, 0xdd, 0xf8, 0xcd, 0xb3, 0xcf, 0xf5, 0x9d, 0xda, 0x90, 0xd0, 0x1a, 0x86, 0x2c, 0x6a, 0x95, 0x3d, 0xba, 0x2a, 0x58, 0x88, 0xf6, 0x7e, 0x7a, 0xf2, 0xd9, 0x7e, 0x9f, 0xe7, 0xfd, 0x27, 0xd1, 0x1c, 0x10, 0x41, 0x9b, 0xf1, 0x17, 0xf8, 0xac, 0xc4, 0x8f, 0x10, 0x3d, 0x52, 0x54, 0xeb, 0x0b, 0xa1, 0x19, 0x18, 0x62, 0x13, 0x02, 0xe4, 0x4d, 0x09, 0x9d, 0x27, 0xbf, 0x0f, 0x2f, 0x73, 0xbf, 0x91, 0xd3, 0x9e, 0x9e, 0x8c, 0xd9, 0xeb, 0xf7, 0xf2, 0x63, 0xde, 0x00, 0xbc, 0x38, 0x41, 0x0f, 0x15, 0xfd, 0x8a, 0xd1, 0x1b, 0xe6, 0xfd, 0x15, 0x2c, 0xff, 0x5f, 0x39,\n\t0xb8, 0xfd, 0x0a, 0xcf, 0x09, 0x78, 0xe5, 0xca, 0x1b, 0xe4, 0xcf, 0x7e, 0x74, 0x85, 0x7c, 0x60, 0x94, 0x67, 0xfd, 0x5b, 0xbf, 0x9e, 0xe7, 0x02, 0x5c, 0xff, 0x38, 0xb9, 0x7d, 0xfe, 0x43, 0xe8, 0x1f, 0xbb, 0xa6, 0x27, 0xd2, 0x97, 0x44, 0xf7, 0xc1, 0xf5, 0xa2, 0x23, 0x1a, 0x80, 0x92, 0xd5, 0x7e, 0xca, 0xb2, 0x08, 0x49, 0xd0, 0x76, 0x1d, 0xf2, 0x1c, 0xd0, 0xc0, 0xe0, 0x6b, 0x86, 0xbf, 0xe6, 0x38, 0x38, 0x3c, 0xb8, 0xd4, 0x15, 0x1b, 0x97, 0xe0, 0x5f, 0x61, 0x0f, 0x16, 0xbd, 0xc0, 0x73, 0x51, 0x2c, 0xd3, 0x70, 0x67, 0x7e, 0x43, 0xf7, 0xcd, 0x7e, 0x63, 0x80, 0xd5, 0xce, 0x0c, 0x0e, 0x56, 0x65, 0x4f, 0x47, 0x97, 0x6a, 0x9c, 0x2c, 0x21, 0xc4, 0x94, 0x88, 0x42, 0x07, 0x18, 0xcb, 0xb5, 0x27, 0xb2, 0xcd, 0x71, 0xb5, 0x4f, 0xb9, 0xc7, 0x1b, 0x0c, 0x05, 0x83, 0xec, 0x29, 0x24,\n\t0xa6, 0xa1, 0x13, 0xec, 0x52, 0x99, 0x14, 0xbd, 0xdc, 0xf8, 0x09, 0x5c, 0x71, 0x55, 0x28, 0xdf, 0x5d, 0xcb, 0x3b, 0x50, 0x66, 0xfa, 0x8e, 0xee, 0x4f, 0xef, 0xdd, 0xf2, 0xfc, 0xc9, 0x54, 0xcb, 0x2d, 0x1f, 0x1d, 0xab, 0x99, 0xdb, 0xb1, 0x31, 0x44, 0xaa, 0x91, 0xef, 0x74, 0x6a, 0x4d, 0x60, 0xfc, 0xad, 0xb3, 0xc7, 0x7e, 0xfa, 0xf1, 0xf5, 0xdb, 0x5e, 0xfc, 0xcb, 0x3d, 0x35, 0x5b, 0x36, 0xad, 0x2f, 0xa1, 0x48, 0xbb, 0xe9, 0x91, 0xee, 0x01, 0x6f, 0xa9, 0x52, 0x61, 0x15, 0xd1, 0xdd, 0x43, 0xeb, 0xba, 0xef, 0x7b, 0xe3, 0xfc, 0x89, 0x6f, 0x9e, 0x69, 0xb5, 0xd5, 0x8d, 0x25, 0xe7, 0x6d, 0x06, 0x6d, 0x62, 0xea, 0xdc, 0x9a, 0x6f, 0xed, 0xd8, 0xbb, 0xe9, 0x25, 0x20, 0xbe, 0xfc, 0x05, 0x60, 0x79, 0x6d, 0x46, 0x17, 0x6e, 0x2d, 0xdf, 0x6a, 0x73, 0xbe, 0xb7, 0x6e, 0xc3, 0x4e, 0xa5,\n\t0xaa, 0x80, 0x1d, 0x43, 0x1d, 0x7c, 0xb5, 0xb7, 0x70, 0x2c, 0x25, 0x88, 0x32, 0x71, 0xfc, 0x38, 0xbe, 0x20, 0x92, 0x64, 0x80, 0x5b, 0xf0, 0x85, 0x31, 0x11, 0x1f, 0x52, 0x39, 0xd8, 0x14, 0x47, 0x47, 0xdd, 0x05, 0x79, 0xc1, 0x05, 0xe9, 0xb2, 0xc1, 0x05, 0x34, 0xe1, 0x3c, 0x82, 0xf0, 0xc2, 0x9a, 0x25, 0xc2, 0x0b, 0x57, 0xae, 0x80, 0x8f, 0x09, 0x02, 0x0c, 0xbf, 0x0d, 0x75, 0xe1, 0x00, 0xc3, 0x9f, 0xe7, 0x2d, 0xa5, 0xe0, 0xed, 0x02, 0xe3, 0xfc, 0x0b, 0x64, 0xef, 0xa3, 0xe4, 0x17, 0x84, 0x21, 0x06, 0xf8, 0xdc, 0x5e, 0x68, 0x40, 0xed, 0x81, 0xcf, 0x2d, 0x21, 0xdc, 0xe8, 0xd4, 0x45, 0x29, 0x63, 0x10, 0x42, 0xa3, 0x1b, 0xee, 0x8b, 0x94, 0x54, 0x82, 0x88, 0x2f, 0x28, 0x62, 0x33, 0xb7, 0x41, 0x62, 0x9f, 0x5c, 0x2a, 0x95, 0xba, 0xa5, 0x6e, 0xad, 0x57, 0xef, 0xd1, 0xea, 0xac,\n\t0x70, 0x89, 0xc0, 0x31, 0xf2, 0x98, 0x59, 0x7e, 0x05, 0x3f, 0x76, 0x21, 0x3c, 0xf1, 0x18, 0x0b, 0x7d, 0xf2, 0xe0, 0x21, 0xa1, 0x62, 0x46, 0x6a, 0x2a, 0xfd, 0x9d, 0xcd, 0x5a, 0x87, 0x5c, 0x6e, 0xd3, 0x82, 0xfa, 0xf4, 0x5f, 0xde, 0x48, 0xff, 0x25, 0xfd, 0xbd, 0x7f, 0x7e, 0x1a, 0x79, 0x12, 0x77, 0x81, 0x9f, 0x9d, 0x91, 0x79, 0x6d, 0xaf, 0x3c, 0xfd, 0xcf, 0xd4, 0x3f, 0x7f, 0x21, 0xd0, 0xe2, 0xf6, 0xb4, 0xf8, 0xbf, 0x90, 0x2e, 0x9b, 0x7f, 0x87, 0x94, 0x80, 0x1f, 0x3c, 0x02, 0xc2, 0x36, 0xd3, 0x3b, 0xef, 0xe8, 0x5c, 0xe9, 0x9f, 0x3c, 0xb2, 0xb0, 0x40, 0x7c, 0x3c, 0xfd, 0x21, 0xc6, 0xcb, 0x3c, 0x46, 0x06, 0x88, 0x00, 0xae, 0x93, 0x78, 0x15, 0x0c, 0xbd, 0x07, 0x50, 0xa5, 0x50, 0xf2, 0x8b, 0xef, 0x01, 0x8c, 0x2a, 0x47, 0x7b, 0xe3, 0x63, 0xf4, 0x7f, 0xe2, 0x31, 0xa8, 0x24,\n\t0xee, 0x40, 0xa8, 0x0c, 0x8a, 0x70, 0x02, 0x11, 0xcd, 0x73, 0x2a, 0xe2, 0x8a, 0x8c, 0x79, 0x83, 0x81, 0xdc, 0xa2, 0x14, 0x9a, 0xef, 0x98, 0x91, 0x67, 0x4e, 0x84, 0x2b, 0x32, 0x32, 0x24, 0xca, 0x85, 0x9f, 0x5b, 0xae, 0x39, 0x91, 0x6d, 0x3d, 0x9a, 0x34, 0x23, 0x30, 0x40, 0xa1, 0x1b, 0x9d, 0x0f, 0x7f, 0xf0, 0x38, 0x2e, 0xe1, 0xdf, 0xaf, 0x1c, 0x32, 0x42, 0x7e, 0x3f, 0x9c, 0x96, 0xac, 0xdf, 0x0f, 0xe7, 0xee, 0xca, 0x03, 0xfc, 0xd9, 0x9c, 0x78, 0xc0, 0xdd, 0x39, 0x23, 0xcd, 0xee, 0xcb, 0x4f, 0x33, 0x0f, 0x30, 0x1f, 0x25, 0xc2, 0x08, 0x8d, 0xe1, 0x07, 0xb8, 0x68, 0x1e, 0x6b, 0x03, 0x4d, 0xb1, 0x43, 0x2c, 0x01, 0xd0, 0xea, 0x19, 0x47, 0x16, 0xc4, 0x74, 0x8a, 0x4d, 0x54, 0x84, 0xff, 0x0f, 0x13, 0x21, 0xbf, 0x47, 0xab, 0x0d, 0x7b, 0xbc, 0x28, 0x0a, 0xef, 0xd7, 0xa2, 0x0a,\n\t0xd3, 0x5a, 0xee, 0x58, 0x81, 0x62, 0x23, 0x5f, 0x5a, 0xee, 0x08, 0xa2, 0x0e, 0xa0, 0xd2, 0x27, 0x70, 0xbf, 0x8e, 0x33, 0x0f, 0x04, 0x9c, 0xb7, 0x77, 0xb1, 0x87, 0x09, 0x41, 0x99, 0xc1, 0x5a, 0x68, 0x5e, 0xf7, 0xa3, 0x1f, 0xb5, 0x07, 0xca, 0xf4, 0xe0, 0xdb, 0xa6, 0x48, 0xe1, 0x8b, 0xf3, 0x7f, 0x30, 0x04, 0x4c, 0x55, 0x61, 0xf0, 0xa9, 0x4f, 0xa7, 0x57, 0x39, 0x0a, 0xc1, 0x10, 0x3e, 0x4c, 0x88, 0x2a, 0x75, 0x72, 0x06, 0x1d, 0x27, 0xcc, 0x3f, 0xa8, 0x37, 0x93, 0x7a, 0x9b, 0x71, 0xfe, 0xb1, 0x02, 0x8f, 0x5c, 0x5f, 0x3b, 0x3f, 0x4f, 0xf3, 0x39, 0xa4, 0x4f, 0xe3, 0xbd, 0x4b, 0x8f, 0x50, 0xc0, 0x12, 0x04, 0xbd, 0xec, 0xe6, 0x7d, 0xc7, 0x29, 0x3c, 0x88, 0x6c, 0x51, 0xfa, 0xec, 0xa3, 0xa3, 0xba, 0x9f, 0xd0, 0x9c, 0x40, 0x81, 0x30, 0xee, 0xb9, 0xf3, 0x76, 0x16, 0xf8, 0x90,\n\t0x37, 0x76, 0x09, 0xb7, 0x92, 0x74, 0x03, 0x7a, 0x9c, 0x9c, 0x0d, 0x04, 0xfe, 0x5d, 0x68, 0x43, 0xfc, 0xe6, 0xff, 0x06, 0x56, 0xe4, 0x49, 0x8c, 0x15, 0x59, 0x3b, 0xd5, 0x38, 0xf3, 0xf9, 0x13, 0x29, 0x84, 0x15, 0x19, 0xbb, 0x6d, 0x4d, 0x4c, 0xaf, 0x35, 0x88, 0xdb, 0xd7, 0xfd, 0x49, 0x80, 0x15, 0x99, 0xff, 0x1b, 0xb1, 0x22, 0x2d, 0x70, 0x5e, 0xbf, 0x82, 0xeb, 0xfd, 0x0a, 0xce, 0xe8, 0x19, 0x7e, 0x91, 0x0b, 0xca, 0xfe, 0xf0, 0x9c, 0x39, 0xf8, 0xfc, 0x81, 0x3b, 0xa0, 0xd7, 0x52, 0xaf, 0xdc, 0x38, 0x43, 0x7e, 0x6a, 0xfe, 0x6b, 0x64, 0x12, 0x9d, 0x25, 0x3c, 0x0b, 0xfe, 0xfd, 0x59, 0x72, 0x23, 0xc1, 0x9f, 0x81, 0xd1, 0xfb, 0xe1, 0xf7, 0x62, 0xf6, 0x8d, 0x4c, 0xa6, 0x2a, 0xf6, 0x43, 0xb1, 0xee, 0xc8, 0x26, 0xdb, 0xb3, 0xd6, 0x32, 0xbd, 0x9f, 0xb5, 0x86, 0x11, 0x55, 0x2a,\n\t0xb4, 0x77, 0x1f, 0x44, 0xe7, 0x8b, 0x7f, 0x59, 0x78, 0x9b, 0xd6, 0x31, 0xd7, 0x09, 0x15, 0x51, 0x46, 0xbc, 0xcc, 0xae, 0x5b, 0x85, 0x5a, 0x85, 0xb2, 0x31, 0x3c, 0xf0, 0xdb, 0x70, 0x04, 0x84, 0xbf, 0xa4, 0xb3, 0x3b, 0xa1, 0x1f, 0xee, 0xe3, 0x52, 0xc0, 0x90, 0x22, 0x66, 0x13, 0x5c, 0xa7, 0x33, 0x99, 0x33, 0xbd, 0x59, 0x16, 0x0d, 0x80, 0x92, 0x6e, 0x76, 0x52, 0x7c, 0xa0, 0xee, 0x26, 0x1a, 0xa3, 0x0a, 0xe4, 0xc9, 0xf0, 0xf2, 0xed, 0x68, 0x7a, 0x3a, 0x83, 0x33, 0xc0, 0x05, 0xc7, 0x93, 0xaa, 0xb2, 0x08, 0x12, 0x55, 0x20, 0xe4, 0x0f, 0x14, 0x22, 0xc3, 0xc1, 0xcf, 0x1e, 0xcd, 0x70, 0xde, 0x64, 0x3c, 0xb7, 0xd0, 0x78, 0x50, 0x8c, 0xd7, 0x10, 0x9b, 0x5a, 0x6f, 0xf4, 0x82, 0x9e, 0xe8, 0x9e, 0xd6, 0xd3, 0x97, 0x3c, 0x4d, 0x63, 0xb5, 0x43, 0x47, 0x13, 0x4d, 0x9f, 0xd8, 0xb6,\n\t0xee, 0xde, 0xe9, 0x44, 0xfd, 0xbe, 0x27, 0x66, 0xcb, 0x07, 0xda, 0x6a, 0x0b, 0x64, 0x92, 0xf0, 0xed, 0x17, 0x2f, 0x5e, 0xff, 0xdd, 0xef, 0xde, 0x6d, 0xac, 0x78, 0xf1, 0x8b, 0x9b, 0x4e, 0xaf, 0xf1, 0xf7, 0xb4, 0xdd, 0xd7, 0x39, 0xd4, 0x74, 0xfc, 0xd5, 0xe3, 0x7b, 0x5f, 0x3d, 0xd7, 0xab, 0xf7, 0x55, 0x7a, 0x86, 0xc2, 0xf4, 0xfe, 0xa3, 0x6f, 0xbc, 0x71, 0x14, 0xea, 0xc0, 0x73, 0x50, 0x7e, 0x7a, 0x2c, 0xbf, 0x20, 0xf1, 0x54, 0x8e, 0xfc, 0x5c, 0xb9, 0xf2, 0x73, 0x09, 0xe5, 0x87, 0xf8, 0xd7, 0xb0, 0xe5, 0x96, 0x7d, 0xcb, 0xdd, 0x4b, 0x89, 0x6e, 0xe5, 0x76, 0x58, 0x6a, 0xbe, 0x25, 0x9b, 0x2c, 0x16, 0x98, 0x4c, 0xab, 0xf5, 0x21, 0x61, 0x61, 0xce, 0xb3, 0xe5, 0x85, 0x15, 0x60, 0x65, 0x85, 0x42, 0x14, 0x50, 0x4a, 0x6d, 0x67, 0x2e, 0x7a, 0x9a, 0xc6, 0x6b, 0x87, 0x8e, 0xc5,\n\t0x9b, 0x1e, 0xdf, 0x0a, 0xa5, 0x54, 0xd5, 0xb0, 0xf7, 0x93, 0xb3, 0x9b, 0x4e, 0x57, 0x4a, 0x25, 0x45, 0xc7, 0xa9, 0xf8, 0xfc, 0x85, 0xf7, 0x9a, 0x2a, 0x5e, 0xfb, 0xd2, 0xa6, 0x73, 0xeb, 0xc2, 0x3d, 0xed, 0xf7, 0x77, 0x0c, 0xaf, 0x3a, 0xf1, 0xf5, 0xe3, 0x7b, 0x5f, 0xbb, 0x30, 0xd0, 0xdd, 0x32, 0x14, 0x66, 0xae, 0x5f, 0xc0, 0xe7, 0xd7, 0xff, 0x06, 0xe5, 0x53, 0x99, 0x2b, 0x1f, 0x03, 0x52, 0x85, 0x3e, 0xf8, 0xac, 0x59, 0x39, 0xd1, 0x50, 0x4e, 0x8b, 0x6e, 0xd3, 0xf0, 0x36, 0x27, 0x2f, 0xdb, 0x07, 0x8b, 0xca, 0xb6, 0xa2, 0x94, 0x5c, 0x1f, 0x2c, 0x20, 0xa9, 0x1e, 0xcb, 0x07, 0x47, 0x6c, 0x3e, 0x50, 0x3e, 0x41, 0x7d, 0x0c, 0xec, 0x5a, 0x59, 0x3e, 0xaf, 0xdf, 0x78, 0x70, 0x79, 0xf1, 0x50, 0x7f, 0x39, 0x89, 0x8e, 0xec, 0x01, 0xb1, 0x1a, 0xca, 0xe7, 0x22, 0x73, 0x84, 0x68,\n\t0x02, 0x06, 0xf6, 0x3d, 0xd4, 0x71, 0x20, 0x16, 0x95, 0x40, 0x1d, 0x81, 0x98, 0xa3, 0x58, 0x02, 0xcb, 0x38, 0x90, 0x08, 0xef, 0x70, 0x32, 0x29, 0xcb, 0xcb, 0x3f, 0x40, 0x9b, 0x09, 0xde, 0x27, 0xa7, 0x32, 0xfa, 0x70, 0x77, 0x8a, 0xd7, 0x91, 0x3b, 0x71, 0x81, 0x78, 0xe7, 0xdf, 0xda, 0x8d, 0xad, 0x2b, 0x8f, 0x09, 0x92, 0xf3, 0xb3, 0x1d, 0x44, 0xb0, 0x23, 0x06, 0x62, 0x2c, 0xd9, 0x29, 0x59, 0x49, 0x88, 0xa1, 0xd7, 0x8f, 0xf2, 0x8b, 0xf2, 0xfb, 0x11, 0x12, 0xb1, 0x48, 0xb2, 0x74, 0x37, 0x64, 0x8f, 0x2a, 0x3c, 0xfe, 0x40, 0x28, 0xe0, 0x0d, 0x79, 0xe1, 0xf6, 0xe7, 0x28, 0x5e, 0x0a, 0xf2, 0x96, 0x9f, 0x70, 0x63, 0xce, 0x81, 0xdb, 0xe0, 0x74, 0x05, 0xea, 0x4c, 0xa5, 0x54, 0xab, 0xd1, 0x78, 0xe3, 0xa9, 0xaa, 0xce, 0xdd, 0x5d, 0x81, 0x50, 0xf7, 0xf6, 0xe6, 0xa6, 0xc1, 0x84,\n\t0x4f, 0x6f, 0x51, 0x56, 0x7b, 0xd7, 0x6d, 0xde, 0x51, 0xb5, 0xe1, 0xc9, 0xc3, 0xed, 0x4d, 0x47, 0xbe, 0xb0, 0x7f, 0xa2, 0xd7, 0x91, 0xdc, 0x92, 0x0a, 0x0f, 0x96, 0x1a, 0xc5, 0x56, 0xb9, 0x2a, 0xe2, 0x4e, 0x46, 0xa9, 0x13, 0x9d, 0x72, 0x65, 0x81, 0xa3, 0xa0, 0x72, 0xe3, 0xf9, 0xe1, 0xd1, 0xbb, 0x37, 0x94, 0xbb, 0x7c, 0x2e, 0x5d, 0x67, 0x71, 0x7d, 0x40, 0xd7, 0x7e, 0xe6, 0xda, 0xd1, 0xbd, 0x5f, 0xbb, 0xbb, 0xdf, 0xb6, 0xba, 0xf1, 0x96, 0x91, 0x38, 0xeb, 0xfd, 0x0c, 0xf5, 0x62, 0x5b, 0x74, 0x70, 0xe1, 0x6d, 0xea, 0xe7, 0xdc, 0x1c, 0xdf, 0x9e, 0x54, 0x78, 0x01, 0x41, 0xeb, 0x55, 0xac, 0xe7, 0xc0, 0x2f, 0x63, 0x8e, 0x4d, 0x6f, 0x26, 0x63, 0x92, 0xef, 0x4e, 0xf1, 0x29, 0x17, 0x6c, 0xfc, 0xd8, 0xb7, 0x64, 0x13, 0x6c, 0xfe, 0xf0, 0xa6, 0x3b, 0x0b, 0x44, 0xd0, 0x87, 0x7c,\n\t0x5e, 0x76, 0x15, 0xf3, 0x9c, 0xd1, 0xec, 0x29, 0xbc, 0x7e, 0x31, 0x63, 0x34, 0xc6, 0x77, 0x59, 0xb2, 0xb3, 0xf4, 0x68, 0xe2, 0xfa, 0xc1, 0xb0, 0x4c, 0xdb, 0xfc, 0xe4, 0x4e, 0x5e, 0xe1, 0x8d, 0xdf, 0x19, 0x9b, 0xbf, 0x8f, 0x8a, 0x53, 0x64, 0x66, 0xa2, 0xb6, 0xa5, 0x7f, 0x19, 0x3c, 0xd0, 0x3b, 0xd1, 0x7a, 0x12, 0xce, 0xd5, 0xaf, 0x5f, 0x18, 0xa8, 0xaf, 0x02, 0x1f, 0xbb, 0x80, 0xde, 0xb1, 0x68, 0xe1, 0xcf, 0xd4, 0xaf, 0x19, 0x54, 0x63, 0xb6, 0x95, 0x98, 0x48, 0xca, 0xe2, 0x70, 0xdf, 0x6a, 0xc5, 0x59, 0x30, 0xdc, 0x99, 0x2e, 0x02, 0xd5, 0x12, 0xc8, 0x25, 0xe5, 0xd6, 0xd4, 0x8e, 0x9c, 0xa9, 0xb7, 0xd2, 0xe7, 0x68, 0xdc, 0x93, 0xd2, 0xe6, 0xc6, 0x32, 0x9f, 0x2d, 0xcc, 0xb0, 0x75, 0x44, 0x73, 0x8e, 0x71, 0x85, 0xac, 0x67, 0x22, 0x21, 0x67, 0x9b, 0x20, 0x30, 0x0c, 0x16,\n\t0xaa, 0x67, 0xfb, 0xca, 0x0a, 0xdb, 0xb6, 0xb6, 0x37, 0x6e, 0xe9, 0x0e, 0x47, 0x7a, 0xa6, 0xd2, 0xbf, 0xa6, 0x2d, 0x05, 0xaa, 0xe6, 0x35, 0xe3, 0xe1, 0xb5, 0x6d, 0x89, 0xd1, 0x7d, 0x87, 0xf6, 0x8d, 0x26, 0x5a, 0x8e, 0x7e, 0x6e, 0xf7, 0xbe, 0xe7, 0x8f, 0x24, 0x9f, 0x7f, 0xa1, 0x74, 0x75, 0xbd, 0x37, 0x34, 0x7c, 0x6a, 0xdc, 0x3b, 0xb2, 0x61, 0x22, 0x48, 0xb6, 0x1b, 0x92, 0x13, 0xc7, 0xd6, 0xac, 0x3a, 0xb4, 0x3e, 0x5e, 0xbc, 0x7a, 0x7f, 0x57, 0xff, 0xe1, 0x0d, 0xa9, 0x74, 0xb1, 0x55, 0xa7, 0xd6, 0xaa, 0x63, 0xbe, 0xc2, 0xda, 0xba, 0xc6, 0x9e, 0x89, 0x5b, 0x3f, 0xbc, 0x71, 0xcb, 0xb3, 0x47, 0xda, 0x3a, 0x6f, 0x7f, 0x76, 0xe6, 0xa9, 0xdf, 0x37, 0x59, 0xab, 0x5b, 0xfa, 0x2b, 0x2a, 0x47, 0x9b, 0xfd, 0x22, 0x99, 0x4a, 0xca, 0x72, 0x86, 0x1d, 0x4c, 0x1f, 0x20, 0x1f, 0x65,\n\t0x5e, 0x20, 0xa2, 0xc4, 0x3f, 0x73, 0x6b, 0x18, 0x9d, 0x80, 0x8a, 0x0b, 0xa1, 0x7c, 0xcc, 0x28, 0x52, 0x8c, 0xd6, 0xb0, 0xf0, 0x0e, 0x83, 0xd7, 0x30, 0xef, 0x28, 0x62, 0x53, 0x17, 0x8b, 0x03, 0x8c, 0x22, 0x5c, 0xca, 0x2c, 0x36, 0xad, 0xa8, 0x71, 0x28, 0xa4, 0x39, 0x4a, 0xe8, 0x28, 0xae, 0xd0, 0x70, 0x7b, 0x46, 0x0d, 0x3a, 0xe1, 0x3d, 0xc4, 0xce, 0xbe, 0x71, 0xa9, 0x0e, 0x24, 0x2e, 0xf7, 0x03, 0x8d, 0x6d, 0x92, 0xc6, 0xe1, 0x38, 0xf8, 0x24, 0xcb, 0xb4, 0xc3, 0x9e, 0xa1, 0xdf, 0xe2, 0xf1, 0xfb, 0xb5, 0xc6, 0x18, 0x97, 0xf9, 0xc7, 0x55, 0x71, 0xe6, 0x21, 0x5f, 0x39, 0x9c, 0x99, 0x41, 0x14, 0xd7, 0x8e, 0x71, 0xeb, 0x91, 0xfc, 0x30, 0x50, 0x99, 0x3d, 0xfa, 0xd2, 0xee, 0x4a, 0x3b, 0x70, 0xa4, 0xff, 0x2b, 0xbc, 0xf6, 0xc4, 0x68, 0xf9, 0x6a, 0xb8, 0xc4, 0xcc, 0x2a, 0x55,\n\t0xc8, 0x3f, 0x30, 0xb4, 0xdd, 0xec, 0xf8, 0x58, 0xc5, 0xc4, 0xc9, 0xc1, 0xb6, 0x5a, 0xa6, 0x41, 0xa9, 0x14, 0x01, 0x53, 0xe5, 0x50, 0xd3, 0xf0, 0x85, 0x1b, 0xf7, 0xaf, 0x39, 0xbf, 0x39, 0xa1, 0xd5, 0x0f, 0xc3, 0x75, 0x35, 0xbd, 0x95, 0x3a, 0xa5, 0x64, 0xcc, 0xa6, 0x81, 0xf1, 0x75, 0x67, 0x37, 0x94, 0x1b, 0x90, 0x9e, 0x3c, 0xb7, 0xf0, 0xa6, 0x28, 0x02, 0xd7, 0x58, 0x80, 0x38, 0xce, 0xea, 0x31, 0x99, 0x19, 0x1a, 0xa4, 0x3a, 0xc0, 0xb0, 0x71, 0x14, 0x78, 0x21, 0x62, 0x2f, 0xb8, 0x13, 0x29, 0x07, 0xca, 0x30, 0x65, 0x31, 0x61, 0xb8, 0xd4, 0x0a, 0x47, 0x7e, 0x49, 0xb2, 0x87, 0x70, 0x48, 0x0c, 0xe8, 0x73, 0xe4, 0x3c, 0xcf, 0x66, 0x90, 0x63, 0xfc, 0x82, 0x43, 0x0d, 0xd9, 0x20, 0x3e, 0x1b, 0x40, 0x81, 0x3e, 0x50, 0xc0, 0xab, 0xd5, 0x07, 0xd9, 0xaa, 0x24, 0xd9, 0x6a, 0x05,\n\t0xd9, 0x54, 0x1f, 0x2d, 0x8f, 0x27, 0x30, 0x60, 0x69, 0x88, 0x22, 0x65, 0x1b, 0x2f, 0xcd, 0xcc, 0x5e, 0xda, 0x58, 0x36, 0xbd, 0x25, 0x75, 0xb2, 0xfa, 0xda, 0xb5, 0xe4, 0xa3, 0x33, 0x88, 0xc7, 0xfe, 0x1b, 0x9b, 0xa6, 0xa9, 0x77, 0xe6, 0x0f, 0x0f, 0x5f, 0x98, 0xa9, 0x46, 0x94, 0xf5, 0xc0, 0xb4, 0xeb, 0x70, 0x47, 0xc3, 0xbc, 0x99, 0xb9, 0x3e, 0xff, 0x42, 0xf3, 0x6a, 0x74, 0x27, 0xfd, 0xbb, 0x3f, 0x1c, 0x3c, 0x48, 0xde, 0x85, 0xec, 0x0a, 0x68, 0x7b, 0xeb, 0x69, 0x39, 0x21, 0x27, 0x3c, 0xc4, 0xaa, 0x97, 0x6c, 0x72, 0x64, 0xfc, 0xf2, 0x08, 0x1f, 0x6d, 0x26, 0xf0, 0xb8, 0x3b, 0xc5, 0x73, 0x87, 0xa0, 0xf3, 0x27, 0x6c, 0x50, 0xe1, 0xe8, 0x1a, 0x7f, 0x7f, 0xf4, 0x45, 0x8f, 0xdd, 0x1f, 0xc4, 0x21, 0x49, 0x1c, 0x22, 0xc3, 0x91, 0xf6, 0xcc, 0x76, 0xc6, 0x45, 0x23, 0xcd, 0xa0,\n\t0x67, 0xdb, 0x97, 0xcf, 0xaf, 0x3e, 0xb2, 0x65, 0xe4, 0x9e, 0x2a, 0x59, 0xcb, 0xf3, 0xb7, 0xf4, 0x9e, 0xde, 0x54, 0xd5, 0xb0, 0xf5, 0x9e, 0x8f, 0x3d, 0xb5, 0xfa, 0xda, 0x81, 0xb0, 0x6c, 0x6b, 0xd1, 0xae, 0xd3, 0x9f, 0x98, 0x3c, 0x70, 0xb0, 0xa7, 0xfd, 0x74, 0xef, 0x64, 0x74, 0xfc, 0xdc, 0xc8, 0xc4, 0x93, 0x17, 0x0e, 0x4f, 0xf7, 0x3b, 0xd2, 0xff, 0xc9, 0xf4, 0x06, 0x59, 0x3b, 0xf4, 0x1c, 0x5c, 0xd3, 0xf3, 0xcc, 0xd3, 0x44, 0x84, 0x38, 0xc6, 0xc5, 0xb8, 0x7c, 0x40, 0xc4, 0x28, 0x38, 0xfb, 0x07, 0x5e, 0x88, 0xb9, 0x0b, 0x2e, 0xc6, 0x95, 0x61, 0x99, 0x47, 0xe2, 0xcf, 0xa2, 0xf7, 0x66, 0x79, 0x57, 0x1d, 0x57, 0x58, 0x16, 0xc3, 0x6d, 0x10, 0xcc, 0x65, 0x48, 0x7c, 0xc4, 0xe2, 0x25, 0x1a, 0xa2, 0xe8, 0x05, 0x9c, 0xa1, 0xfe, 0xa0, 0xdf, 0x8d, 0xe7, 0x68, 0xd6, 0x2d, 0x12,\n\t0x71, 0x60, 0xac, 0x40, 0xc6, 0xa3, 0x5f, 0xb4, 0x47, 0x80, 0x9e, 0x88, 0xd1, 0xae, 0x06, 0x51, 0x55, 0xa1, 0xf5, 0xf9, 0xf4, 0xc3, 0x0e, 0x8f, 0xde, 0xa1, 0x02, 0xc7, 0x3f, 0x67, 0xf1, 0xaa, 0xd2, 0xdf, 0x54, 0x3b, 0x9d, 0x95, 0xd7, 0xc2, 0x6b, 0xef, 0x1c, 0xad, 0xe8, 0xcf, 0x4e, 0x5b, 0x72, 0x46, 0xa1, 0x03, 0xfd, 0x7a, 0x7d, 0xfa, 0x90, 0xdf, 0xa0, 0x2c, 0x34, 0xa4, 0x95, 0x1a, 0x23, 0xf8, 0x88, 0x59, 0x99, 0x76, 0xd1, 0x09, 0xe1, 0xcc, 0x85, 0xf2, 0x90, 0x2e, 0xfc, 0x85, 0xd6, 0x42, 0x79, 0x54, 0x12, 0x77, 0x26, 0x75, 0x85, 0x70, 0xcf, 0x8e, 0x96, 0x45, 0x4a, 0x51, 0xf0, 0x41, 0x29, 0xcd, 0x6a, 0x4c, 0x33, 0x5f, 0x74, 0x7c, 0x07, 0x5e, 0xc6, 0x38, 0xcd, 0x88, 0x23, 0x52, 0x2e, 0x59, 0xee, 0x63, 0x4c, 0x9b, 0x6c, 0xcb, 0x7e, 0x82, 0xbd, 0x2f, 0xf6, 0xe3, 0x0c,\n\t0x55, 0x32, 0xc2, 0x31, 0x55, 0x12, 0x31, 0x7f, 0x51, 0x84, 0xf5, 0xc3, 0x30, 0x13, 0x0f, 0x54, 0x91, 0xa8, 0x7c, 0x2f, 0xaa, 0x4f, 0x8e, 0xd2, 0x96, 0x30, 0x2b, 0x43, 0x10, 0x79, 0x93, 0xbc, 0x3e, 0x75, 0x81, 0x2a, 0xb3, 0x18, 0x25, 0xb4, 0xd2, 0xda, 0x78, 0x95, 0xaf, 0x6b, 0x55, 0xad, 0xf1, 0x29, 0x89, 0x9c, 0x66, 0x94, 0x92, 0x7f, 0x13, 0xd9, 0x0b, 0xae, 0x80, 0x73, 0x85, 0x2f, 0x87, 0xbf, 0x6c, 0x91, 0x5b, 0x7d, 0xe5, 0x85, 0x5d, 0x72, 0x7b, 0x99, 0x3f, 0xdc, 0xdf, 0x56, 0xad, 0x77, 0x7d, 0x35, 0xfc, 0x15, 0x50, 0x61, 0x6c, 0xac, 0x3d, 0xdb, 0x1f, 0xb6, 0x69, 0x4a, 0x7a, 0xea, 0xc1, 0x37, 0xcc, 0x45, 0x06, 0x43, 0x91, 0x71, 0xfe, 0xd3, 0x6a, 0x0b, 0xf5, 0xc8, 0x44, 0xeb, 0x81, 0xd6, 0x56, 0x67, 0xd8, 0x22, 0xeb, 0x52, 0xdb, 0x0c, 0x72, 0x4d, 0xa8, 0xb5, 0x72,\n\t0x6d, 0xfb, 0x81, 0xb6, 0x1b, 0x5f, 0xab, 0xa9, 0xc0, 0x35, 0x38, 0xa0, 0x6f, 0xfc, 0x0a, 0x2d, 0x81, 0x7b, 0x66, 0x25, 0xdc, 0x4f, 0xe4, 0x1e, 0x68, 0x22, 0x54, 0xe2, 0x44, 0xbf, 0x6c, 0x0d, 0x0e, 0xde, 0x80, 0xdb, 0x9d, 0x45, 0x11, 0xa2, 0xb5, 0xb9, 0x95, 0x61, 0x6b, 0x70, 0x2c, 0xfe, 0x78, 0x0f, 0xf7, 0x31, 0xdc, 0x26, 0xfd, 0x46, 0x5f, 0x28, 0xec, 0xcb, 0xd9, 0x26, 0xd9, 0x73, 0x82, 0xaa, 0x45, 0x25, 0x37, 0x72, 0x62, 0xe0, 0x22, 0x31, 0xa5, 0xb3, 0x6f, 0x5d, 0xfb, 0xe0, 0x7d, 0xf7, 0x3d, 0xd8, 0x39, 0x54, 0xaa, 0xba, 0x5e, 0xba, 0xf9, 0xa3, 0x99, 0xba, 0x1b, 0x33, 0x4f, 0x27, 0xab, 0x4f, 0xac, 0x49, 0xed, 0xee, 0xf2, 0x5e, 0x57, 0xba, 0x13, 0xe1, 0xa2, 0xee, 0x42, 0x4a, 0x56, 0x5c, 0x8b, 0xca, 0x6f, 0x94, 0x34, 0x77, 0xd8, 0x40, 0xfd, 0xed, 0xdb, 0x5a, 0xf9,\n\t0xca, 0x1b, 0x8d, 0xf5, 0x75, 0x4d, 0x08, 0xf7, 0x73, 0x43, 0x45, 0xbd, 0x8d, 0x4a, 0x8f, 0xfb, 0x1d, 0x04, 0xbf, 0xa6, 0xe1, 0xbc, 0x40, 0xef, 0x7c, 0x8d, 0x5d, 0x0a, 0x9a, 0x22, 0xb8, 0x52, 0xb2, 0x76, 0x30, 0xda, 0x2a, 0xe0, 0x2d, 0x71, 0xce, 0x2d, 0xde, 0xe7, 0xca, 0x5d, 0x2d, 0x42, 0x33, 0x97, 0x85, 0x4f, 0xd1, 0xf4, 0xd6, 0x8c, 0xb9, 0xb6, 0x72, 0xe3, 0x3d, 0x7c, 0xe3, 0x64, 0x09, 0x4a, 0xfe, 0x86, 0x0a, 0x72, 0x2e, 0x67, 0x81, 0x2d, 0xd3, 0x7c, 0x94, 0x5d, 0x6f, 0x7a, 0x64, 0x26, 0xe3, 0x9c, 0x85, 0x95, 0xcc, 0xe4, 0xa5, 0x97, 0xdc, 0x32, 0x26, 0xf3, 0xc4, 0x1d, 0xb1, 0x45, 0xeb, 0x6d, 0x69, 0xe3, 0xb9, 0xb5, 0x3e, 0x5d, 0xc3, 0xdc, 0x9d, 0xb3, 0xe0, 0xb0, 0x0e, 0x6a, 0x5d, 0x78, 0x93, 0x72, 0xc3, 0xf9, 0xd4, 0x80, 0xd0, 0x46, 0x4e, 0x68, 0x32, 0x35, 0x40,\n\t0x2b, 0x0c, 0x1d, 0x81, 0xa0, 0x4d, 0x01, 0x6d, 0x76, 0x34, 0x60, 0x30, 0xef, 0x2a, 0x57, 0xb3, 0x85, 0x87, 0x24, 0xc0, 0x15, 0x57, 0x53, 0x1d, 0x8f, 0x15, 0xba, 0xed, 0x56, 0xb3, 0x11, 0x1a, 0xff, 0x46, 0x2e, 0x13, 0x23, 0x0f, 0xac, 0x53, 0x06, 0x84, 0xc0, 0x1e, 0xde, 0x0e, 0x35, 0xc1, 0x01, 0x72, 0xd7, 0x7f, 0xf1, 0xc0, 0xe8, 0xf9, 0xc9, 0x8a, 0x48, 0x6a, 0xc3, 0xf4, 0x86, 0x54, 0xc4, 0x5a, 0xde, 0x51, 0x52, 0xd1, 0x99, 0x08, 0x6a, 0x2d, 0xaa, 0x92, 0xda, 0xcb, 0x3b, 0x87, 0x4e, 0x8f, 0x45, 0x23, 0xa9, 0x8d, 0x33, 0x1b, 0x53, 0x11, 0x4b, 0x45, 0x4f, 0xbc, 0xb6, 0xbf, 0x2a, 0x6c, 0xd0, 0x9a, 0x25, 0x91, 0x9d, 0x89, 0xf6, 0xe2, 0xbe, 0x1d, 0xcd, 0xc9, 0xf1, 0xd6, 0x68, 0xc0, 0x5b, 0x54, 0x19, 0xb0, 0x97, 0xfb, 0x0c, 0x26, 0xab, 0xc9, 0xd2, 0x51, 0x9d, 0x2c, 0x4a,\n\t0x6d, 0x6d, 0x6c, 0x1a, 0x6d, 0x8e, 0xf8, 0xbd, 0x25, 0x35, 0x61, 0x47, 0x3c, 0x5c, 0x60, 0xf3, 0xd8, 0xd5, 0xaa, 0x14, 0xaa, 0x79, 0x9e, 0xbe, 0x44, 0x5e, 0x67, 0x1a, 0xe0, 0xec, 0xb9, 0xcc, 0x8e, 0xb2, 0x4a, 0x89, 0xf3, 0x40, 0x09, 0x06, 0x4e, 0x19, 0x09, 0xe6, 0x8e, 0x16, 0xdc, 0x90, 0x52, 0xbc, 0xbe, 0x8d, 0xb0, 0x19, 0x9c, 0x22, 0x28, 0x0a, 0x11, 0x33, 0x87, 0x52, 0x33, 0x70, 0x0c, 0x67, 0x36, 0x7b, 0x5c, 0x8d, 0x4f, 0xf0, 0xb0, 0x19, 0x30, 0x27, 0x86, 0xb3, 0x22, 0x9e, 0xd3, 0x81, 0x90, 0x10, 0x52, 0x42, 0x22, 0x5d, 0xba, 0x23, 0x21, 0x95, 0xf2, 0xfd, 0xa0, 0x53, 0x5e, 0x11, 0xf5, 0xfb, 0xbd, 0x5e, 0xad, 0x36, 0x64, 0xc4, 0xc7, 0x76, 0x7e, 0x96, 0x67, 0x97, 0x85, 0x5b, 0x23, 0x3e, 0xd8, 0x3a, 0x0e, 0x32, 0x8e, 0xd7, 0x22, 0x0f, 0xf7, 0x15, 0x1a, 0x12, 0xa4,\n\t0xb5, 0xac, 0x3a, 0xb1, 0xae, 0xa1, 0xf0, 0x80, 0xd6, 0x72, 0xb9, 0x84, 0x32, 0xeb, 0xa6, 0x81, 0x3b, 0xfd, 0xcb, 0xda, 0x32, 0x5b, 0xd0, 0x66, 0x90, 0x0e, 0x3b, 0x9a, 0xa1, 0xad, 0xde, 0x53, 0xaa, 0x66, 0x6d, 0xf5, 0xfa, 0xb8, 0xc8, 0xe4, 0x6b, 0x9d, 0x6a, 0x22, 0x37, 0x1a, 0x8d, 0xfd, 0x66, 0x50, 0xa6, 0xd5, 0xa7, 0x9f, 0xbe, 0x30, 0xff, 0x6c, 0x7d, 0x9d, 0x4a, 0xab, 0xfa, 0x7d, 0xd3, 0x2d, 0x23, 0x95, 0x5a, 0x43, 0x7f, 0x81, 0x4a, 0x35, 0x30, 0xc8, 0xd6, 0x8b, 0x5f, 0x78, 0x93, 0xfc, 0x3a, 0xf3, 0x0c, 0xdc, 0xa3, 0x3e, 0xcc, 0xc9, 0x4e, 0x0b, 0xdd, 0x11, 0x29, 0xf4, 0x42, 0x4a, 0x00, 0x21, 0xc6, 0xb2, 0xd3, 0x42, 0xeb, 0x2c, 0x7b, 0x83, 0x93, 0x5d, 0x21, 0x52, 0x31, 0xdc, 0xa1, 0x2f, 0xb2, 0x8d, 0xb0, 0xab, 0x3d, 0x8b, 0x8e, 0x2b, 0x71, 0x69, 0x2b, 0xd6, 0x98,\n\t0x08, 0x43, 0x8b, 0x8b, 0xa1, 0x29, 0x66, 0x8e, 0x67, 0xf3, 0x5d, 0xb6, 0x2d, 0x0e, 0x60, 0xfa, 0x0a, 0x5d, 0x4e, 0x87, 0xbd, 0xc0, 0x6c, 0x32, 0xa8, 0x51, 0xbe, 0x69, 0x04, 0x44, 0xa4, 0x18, 0x04, 0x14, 0xe0, 0x24, 0xd5, 0x94, 0x05, 0x8b, 0xb0, 0x0b, 0x87, 0xb3, 0xba, 0x84, 0xcc, 0x79, 0xe0, 0x5b, 0x47, 0x4e, 0x1f, 0xd4, 0x9a, 0x2f, 0x7b, 0x75, 0x27, 0x76, 0x96, 0x75, 0x06, 0xd5, 0xe8, 0xac, 0xc6, 0xef, 0x6d, 0xac, 0x46, 0xf2, 0xaa, 0x8b, 0xd8, 0x82, 0x76, 0x83, 0x44, 0x26, 0x17, 0xd5, 0x46, 0x4f, 0x69, 0xce, 0xdf, 0xc1, 0x4a, 0xe8, 0xe7, 0x07, 0xe7, 0x34, 0x9a, 0x7e, 0xb8, 0x64, 0xd6, 0x0c, 0x5f, 0xe4, 0xe5, 0x24, 0x95, 0x4d, 0x96, 0x44, 0xb1, 0x7c, 0x34, 0x50, 0x37, 0x5d, 0x86, 0xeb, 0xc7, 0x47, 0x7c, 0x84, 0xe3, 0xad, 0x93, 0xc0, 0x1d, 0xc7, 0x63, 0xc1, 0x58,\n\t0x26, 0x4e, 0xa9, 0xa0, 0x5b, 0x34, 0x7f, 0x0b, 0x5d, 0x91, 0xfc, 0x15, 0x5f, 0x53, 0x41, 0xc7, 0x1e, 0x54, 0xd1, 0x3c, 0xc5, 0xf8, 0xd6, 0x8c, 0x5d, 0x8a, 0x10, 0x42, 0xb3, 0xd9, 0x73, 0xac, 0xcc, 0xa7, 0xc8, 0x33, 0x40, 0x89, 0xa3, 0x98, 0x7b, 0x7c, 0x36, 0x73, 0x78, 0xc5, 0x7f, 0x3e, 0x3a, 0xfa, 0x52, 0xa1, 0xdf, 0xe3, 0xcf, 0x9e, 0x57, 0x0a, 0xa4, 0x22, 0x66, 0xb9, 0x7f, 0x33, 0x20, 0x9a, 0x46, 0x50, 0x45, 0xbe, 0xa7, 0x2a, 0x6d, 0x19, 0xa9, 0xc9, 0x0a, 0xc4, 0x1d, 0xd7, 0xa7, 0x9d, 0x52, 0xa7, 0xe3, 0x81, 0x2f, 0xa7, 0x37, 0x5c, 0x29, 0xb0, 0x89, 0x00, 0x29, 0x55, 0x89, 0x24, 0x1a, 0x09, 0xb5, 0x3a, 0xb0, 0xaa, 0xc2, 0xa1, 0xd6, 0x22, 0x79, 0xd8, 0x4b, 0xde, 0x7f, 0xdc, 0x64, 0x01, 0x0f, 0x51, 0x5f, 0xb4, 0xa8, 0xe7, 0x3f, 0x66, 0x8e, 0x5a, 0x2c, 0x51, 0x0b,\n\t0x96, 0x49, 0x1d, 0xd4, 0x7f, 0xab, 0xa9, 0x77, 0x08, 0x33, 0xc2, 0xd3, 0x28, 0x96, 0xc1, 0xd3, 0xcc, 0x2e, 0x81, 0xa7, 0x31, 0xb0, 0x78, 0x1a, 0xb8, 0x99, 0xc4, 0x8c, 0x1e, 0x8a, 0x03, 0xd4, 0xe8, 0xbd, 0x71, 0x8f, 0x1e, 0x79, 0x64, 0xab, 0xd5, 0x8a, 0x6f, 0x7c, 0x2b, 0xfd, 0xc3, 0xff, 0x22, 0x9d, 0x37, 0xe6, 0x55, 0xca, 0xdf, 0xfd, 0x1a, 0x74, 0xff, 0xc3, 0xfc, 0x1f, 0xc8, 0xbf, 0x52, 0x97, 0x8d, 0x21, 0x55, 0xfa, 0xfd, 0xb3, 0xe9, 0xd7, 0x1f, 0x1e, 0x54, 0x05, 0xb5, 0x20, 0x71, 0x16, 0x48, 0x1f, 0x66, 0xe3, 0x87, 0xe9, 0x0f, 0x53, 0xe7, 0xe0, 0x73, 0x94, 0x22, 0x5c, 0xa2, 0x15, 0x65, 0x61, 0x77, 0x43, 0xdd, 0x86, 0xd0, 0x33, 0x73, 0xd0, 0x9d, 0x26, 0x69, 0x11, 0x4a, 0x0f, 0x66, 0xf3, 0x7c, 0xb8, 0x3a, 0x45, 0x04, 0xa6, 0xfa, 0xb1, 0x40, 0x37, 0xda, 0xa7, 0xc5,\n\t0x05, 0x3b, 0xf5, 0x28, 0xa0, 0x63, 0xca, 0x85, 0x9c, 0xe4, 0xfa, 0xd1, 0x08, 0x9a, 0x12, 0x3f, 0x4a, 0xfe, 0x34, 0xad, 0x03, 0x3d, 0xd6, 0x17, 0xba, 0xb6, 0xb7, 0xba, 0xc3, 0xbd, 0xbb, 0x5b, 0xeb, 0xfa, 0x6b, 0xc2, 0x06, 0x8f, 0xb6, 0xd4, 0xd9, 0x31, 0x34, 0xd3, 0x70, 0xe8, 0x8b, 0x47, 0x93, 0xe5, 0xb3, 0x8f, 0x6e, 0x4f, 0x5f, 0xd7, 0x98, 0xa8, 0x77, 0x1e, 0x4e, 0x6f, 0x35, 0x7a, 0x9a, 0x02, 0x6d, 0x9b, 0x6a, 0x5b, 0x77, 0xa6, 0x82, 0x05, 0xae, 0x02, 0x47, 0xca, 0x16, 0xf1, 0xe8, 0xda, 0x6f, 0xfb, 0xd4, 0xe4, 0xea, 0xbb, 0xa6, 0x1a, 0x44, 0xe0, 0x36, 0x6d, 0x31, 0x5b, 0x63, 0xc2, 0x9b, 0x7e, 0x88, 0xf2, 0xc2, 0xe7, 0xaf, 0x24, 0xca, 0x92, 0x25, 0x0e, 0x44, 0x22, 0x81, 0x8e, 0xce, 0x51, 0x54, 0x60, 0x8a, 0x3f, 0xc1, 0x9c, 0xcd, 0x6c, 0x3b, 0x73, 0x64, 0x8f, 0xd6,\n\t0x50, 0x54, 0x14, 0x31, 0x70, 0x94, 0x2f, 0x62, 0x06, 0xf9, 0x79, 0x22, 0xb1, 0x80, 0x84, 0x9d, 0x8b, 0xe7, 0xb3, 0x74, 0xab, 0x00, 0x07, 0xfd, 0x39, 0x66, 0x64, 0x0a, 0x98, 0xb4, 0xe9, 0xf7, 0x46, 0x6f, 0x1f, 0x08, 0x7c, 0xeb, 0xdb, 0xb5, 0xdd, 0xc5, 0x9a, 0xee, 0x4e, 0xb3, 0xc7, 0xa2, 0x15, 0x29, 0xac, 0x62, 0x73, 0xe9, 0x40, 0xd5, 0x43, 0x9f, 0x7a, 0xec, 0x89, 0xb3, 0xb7, 0xed, 0xd8, 0xf3, 0x29, 0x2b, 0xf0, 0xa5, 0x45, 0xe4, 0x4f, 0xa9, 0xcb, 0xd6, 0x88, 0xea, 0x4f, 0xa2, 0x48, 0xf7, 0x74, 0xc3, 0x03, 0x9f, 0x33, 0x8b, 0x0c, 0x36, 0x97, 0x2e, 0x5c, 0x41, 0x8b, 0x68, 0x95, 0x65, 0xd4, 0xa0, 0x3d, 0x7a, 0xcb, 0xae, 0xbb, 0xb4, 0xca, 0x8d, 0xbd, 0x5d, 0x6b, 0x1b, 0x0b, 0x0d, 0x40, 0xfe, 0x30, 0x7c, 0x8f, 0x9a, 0x85, 0xbf, 0x50, 0x65, 0xf0, 0x3d, 0x12, 0xc4, 0x81,\n\t0xa4, 0x2a, 0x08, 0xfd, 0xac, 0x00, 0x5c, 0x01, 0x1a, 0xcc, 0xd2, 0xcf, 0x6e, 0xd1, 0x81, 0x4c, 0x6d, 0x15, 0x02, 0x21, 0x04, 0xe8, 0x29, 0x94, 0x19, 0x96, 0x47, 0xa3, 0x8f, 0x31, 0x11, 0x37, 0xd3, 0x10, 0xf1, 0xed, 0x27, 0xe5, 0x5e, 0xfd, 0xda, 0x80, 0xdf, 0xcf, 0x9d, 0xce, 0x2d, 0x81, 0xa3, 0xc9, 0x04, 0xb6, 0x03, 0x02, 0x14, 0x0d, 0x82, 0x94, 0x20, 0xbb, 0xcf, 0x03, 0xfa, 0xec, 0x55, 0xf6, 0x89, 0xf3, 0x13, 0x91, 0xe4, 0xce, 0xfb, 0xfa, 0xb7, 0x7d, 0xa5, 0xbd, 0x46, 0xa6, 0x91, 0x68, 0xd5, 0x8a, 0x92, 0x86, 0xde, 0x48, 0xd5, 0x40, 0xdc, 0x7a, 0x68, 0x57, 0x68, 0x24, 0x70, 0xcb, 0x01, 0x99, 0x5e, 0xee, 0x0d, 0x7b, 0xc9, 0x17, 0x2b, 0x6a, 0xd3, 0x6f, 0x91, 0x07, 0x69, 0xba, 0xb4, 0x7f, 0x4f, 0x0b, 0xdc, 0x8c, 0x23, 0x03, 0xc3, 0x8d, 0x0a, 0xb1, 0x5a, 0xee, 0x76,\n\t0x1a, 0x5d, 0x95, 0x6d, 0x81, 0xa1, 0x49, 0xa5, 0xd2, 0x0d, 0x1f, 0x3f, 0x64, 0x1c, 0x6d, 0x0d, 0x60, 0x1b, 0xae, 0x7b, 0xe1, 0x6d, 0xea, 0x0d, 0xa8, 0x33, 0x24, 0x70, 0x66, 0xee, 0xe6, 0x25, 0xb0, 0x5c, 0xa2, 0xd8, 0x6e, 0x61, 0xa2, 0x98, 0xed, 0xa6, 0x1a, 0xe2, 0x88, 0x07, 0xf4, 0xfe, 0x4a, 0x8a, 0x82, 0x7e, 0x8f, 0xab, 0xc0, 0xac, 0x56, 0xc2, 0x3f, 0x25, 0xc1, 0xf9, 0x56, 0x7a, 0x2e, 0xea, 0xc1, 0x63, 0x18, 0x32, 0x56, 0x5d, 0x82, 0x4b, 0x28, 0x83, 0x97, 0xc1, 0x77, 0x3d, 0xc9, 0x89, 0xba, 0x23, 0x17, 0x74, 0xf3, 0x29, 0xdf, 0xe4, 0xf6, 0xbd, 0x55, 0xdb, 0x5e, 0x38, 0xd9, 0xd5, 0x72, 0xe4, 0xb9, 0xb9, 0x89, 0x8f, 0xee, 0x4b, 0xea, 0x6d, 0xe4, 0x23, 0x54, 0x64, 0x60, 0xae, 0xad, 0x79, 0xb2, 0x2d, 0xaa, 0xb3, 0x28, 0xc1, 0xbd, 0xb5, 0x9b, 0x3b, 0x43, 0x17, 0x8e,\n\t0x83, 0x9f, 0x17, 0x35, 0x04, 0x74, 0x1d, 0xe7, 0x5f, 0x3f, 0xb5, 0xed, 0x8b, 0x77, 0xf5, 0x35, 0xec, 0xff, 0xcc, 0xae, 0x88, 0x6b, 0xec, 0xec, 0x68, 0x89, 0xd3, 0xeb, 0x44, 0x09, 0xd6, 0x34, 0x41, 0xa4, 0x2f, 0x41, 0x53, 0x08, 0xee, 0x87, 0x84, 0x9e, 0xf0, 0x12, 0x9b, 0x81, 0x3c, 0xa9, 0xee, 0x86, 0x96, 0xc5, 0x50, 0x1d, 0xa9, 0x60, 0xe2, 0x80, 0x54, 0x52, 0x9c, 0x8f, 0x56, 0x03, 0xdd, 0x6b, 0x85, 0x92, 0x51, 0x4c, 0x11, 0x4a, 0xb8, 0x99, 0x2a, 0xc9, 0x29, 0x95, 0x54, 0x43, 0x51, 0x12, 0x91, 0x1a, 0x4d, 0x7b, 0xb0, 0x99, 0x90, 0xcb, 0x67, 0x53, 0x70, 0xc3, 0xa1, 0x65, 0x63, 0x84, 0x4c, 0x86, 0x5f, 0x39, 0xb3, 0xfd, 0xa6, 0x3e, 0x1f, 0x82, 0x5f, 0x50, 0x4f, 0xc8, 0x65, 0xb4, 0x4c, 0x4e, 0xcf, 0xad, 0xfc, 0x45, 0xcb, 0x7c, 0x47, 0xb2, 0x65, 0xa9, 0xee, 0x52, 0xd8,\n\t0x1d, 0xce, 0x57, 0x35, 0x40, 0x9c, 0x37, 0x9b, 0x55, 0x40, 0x2a, 0x01, 0x22, 0x42, 0x2a, 0xda, 0xb4, 0xf4, 0x97, 0x40, 0x73, 0xaf, 0xc4, 0x68, 0x90, 0x4a, 0x09, 0x62, 0xf3, 0xa6, 0xf1, 0xb1, 0x35, 0x03, 0xed, 0x6d, 0xad, 0x2d, 0x15, 0xe5, 0xd1, 0xb2, 0xe2, 0xb0, 0xdf, 0xe7, 0xb0, 0x19, 0xbc, 0x46, 0xaf, 0x54, 0x2f, 0xd5, 0x73, 0x83, 0xa2, 0x43, 0xcc, 0x68, 0x68, 0x2e, 0x26, 0x9a, 0x40, 0x84, 0x41, 0x9e, 0x06, 0x28, 0x14, 0x65, 0x21, 0xac, 0x01, 0xe0, 0xe5, 0x32, 0x49, 0xbc, 0xf1, 0x18, 0x54, 0xd4, 0x98, 0xa9, 0xb8, 0x8a, 0x83, 0x15, 0x57, 0x98, 0x3d, 0x88, 0xbd, 0xd8, 0x09, 0xb2, 0xfc, 0x62, 0xb0, 0xa7, 0xc8, 0x1c, 0x03, 0x06, 0x71, 0xa8, 0x75, 0x53, 0xf2, 0xfc, 0x03, 0x0a, 0x92, 0x0a, 0xb5, 0x0c, 0x6f, 0x9c, 0x29, 0xab, 0xe8, 0x92, 0x03, 0x66, 0xcb, 0x0e, 0x5b,\n\t0xbc, 0x3f, 0x56, 0xd9, 0x1f, 0xb7, 0xed, 0x00, 0xbf, 0xb9, 0xd5, 0x38, 0x78, 0xe0, 0x43, 0xeb, 0xb7, 0x7e, 0x6c, 0x77, 0x93, 0x64, 0xdb, 0x71, 0xf3, 0x9a, 0xda, 0x8a, 0x86, 0xe6, 0xe6, 0xd4, 0x70, 0xed, 0x96, 0xfb, 0x86, 0x4e, 0x6d, 0x00, 0xd6, 0xd2, 0x5d, 0x2a, 0x4d, 0xed, 0xec, 0xbd, 0x6b, 0xbd, 0xcd, 0x4e, 0xa7, 0xb3, 0x7a, 0xfc, 0xe0, 0xb1, 0xc3, 0x53, 0xcd, 0xa2, 0xa9, 0x03, 0x88, 0x60, 0xba, 0xb9, 0x76, 0xbb, 0xcd, 0x6b, 0x90, 0x8b, 0xc4, 0x22, 0x43, 0x8d, 0x97, 0x3a, 0xb7, 0x6d, 0xa4, 0xb8, 0x23, 0xe6, 0xb0, 0xc7, 0x3a, 0x8b, 0x47, 0xb6, 0xdd, 0x00, 0xd1, 0xa1, 0x66, 0xbf, 0xbf, 0x79, 0x28, 0x7a, 0xa2, 0xa8, 0xd9, 0xa0, 0x6f, 0xa9, 0x2a, 0x5d, 0xe7, 0x2e, 0xba, 0x7b, 0x22, 0x75, 0xeb, 0x70, 0xa4, 0xaa, 0xcb, 0x27, 0xd5, 0xb8, 0xda, 0x02, 0xa9, 0xc3, 0xc3,\n\t0x11, 0x89, 0x44, 0x53, 0x68, 0x74, 0x38, 0x54, 0x22, 0x65, 0x41, 0x7c, 0x98, 0xe5, 0x6e, 0x5e, 0xf8, 0x5d, 0xfa, 0x12, 0x55, 0x01, 0x75, 0x44, 0x04, 0xe9, 0x6a, 0x35, 0xc7, 0x9f, 0x91, 0xbb, 0xd6, 0x17, 0x97, 0xd6, 0x98, 0x43, 0x4c, 0xef, 0x21, 0x6f, 0x30, 0xc4, 0x16, 0x57, 0xce, 0x47, 0x3c, 0x66, 0x71, 0xc0, 0x19, 0x45, 0x87, 0x79, 0xa5, 0x3f, 0xb4, 0xfd, 0xd1, 0xd9, 0xf2, 0xe4, 0xb1, 0x97, 0x0e, 0x35, 0xcc, 0x0e, 0x75, 0x38, 0x23, 0x12, 0x8b, 0xce, 0x10, 0xae, 0x5e, 0x5d, 0xd7, 0xba, 0xbb, 0x37, 0xec, 0x6e, 0xdb, 0xde, 0xf5, 0xbc, 0x15, 0xa4, 0xd2, 0x7a, 0xf2, 0xa7, 0x26, 0x0d, 0xf8, 0xb1, 0xa8, 0x61, 0xea, 0xae, 0xd5, 0x93, 0x4f, 0x1e, 0xe9, 0xd0, 0x79, 0x22, 0xb6, 0x94, 0x4a, 0x0d, 0xd5, 0x75, 0xa8, 0x67, 0x57, 0x6b, 0xed, 0xa6, 0xb6, 0x40, 0x93, 0x07, 0xfa,\n\t0xb1, 0x0f, 0x0f, 0x5a, 0x8b, 0xb5, 0x28, 0x07, 0x65, 0x30, 0xfd, 0x61, 0x66, 0x17, 0x73, 0x1d, 0xd7, 0xa1, 0xef, 0x25, 0x7e, 0x92, 0xb4, 0xa6, 0x00, 0x29, 0xae, 0xb3, 0x2a, 0xa0, 0x11, 0xe4, 0x00, 0x22, 0xba, 0x4a, 0x0a, 0xf7, 0xbe, 0xca, 0x52, 0x92, 0x21, 0x98, 0x6e, 0x3e, 0x0c, 0x2d, 0x91, 0x64, 0xeb, 0xde, 0xed, 0xce, 0x54, 0x5b, 0xd9, 0x99, 0xc5, 0xc8, 0x41, 0xeb, 0x92, 0xcb, 0x59, 0x81, 0x9b, 0x12, 0x9c, 0xde, 0xe6, 0x15, 0xba, 0xed, 0x59, 0xae, 0x5b, 0xb2, 0x14, 0xf1, 0xc1, 0x20, 0x42, 0xbb, 0x65, 0x7b, 0x0a, 0xdb, 0xc3, 0xc9, 0x5b, 0x00, 0x88, 0xde, 0x9e, 0xae, 0x8e, 0xa6, 0x86, 0xe2, 0xb0, 0xc7, 0x85, 0x28, 0x9c, 0x58, 0x92, 0x3b, 0x19, 0x66, 0x4e, 0xe5, 0x88, 0xed, 0xc4, 0xd0, 0x55, 0xc8, 0x09, 0xa3, 0x9a, 0x0d, 0xbc, 0x4b, 0x68, 0xe2, 0xe7, 0xa2, 0x18,\n\t0xd5, 0x8b, 0xc7, 0x73, 0x76, 0x51, 0x80, 0x35, 0x46, 0x9f, 0x8c, 0x55, 0x45, 0xe3, 0xe1, 0x76, 0xb7, 0xa9, 0x2d, 0x7d, 0x3d, 0x27, 0xd2, 0x4a, 0x85, 0x47, 0x62, 0x89, 0x81, 0x84, 0x1d, 0x58, 0x6b, 0xc7, 0x9b, 0x7b, 0x77, 0x04, 0xe4, 0x7a, 0x99, 0xda, 0x63, 0xad, 0xb7, 0x26, 0x1c, 0x6a, 0xb3, 0x5c, 0xde, 0xfc, 0x29, 0x61, 0x0c, 0xf6, 0xfa, 0x7f, 0x45, 0x03, 0x9e, 0xb8, 0xcf, 0x55, 0x55, 0x41, 0xfd, 0x3e, 0x1b, 0x89, 0xfd, 0x41, 0xc8, 0x63, 0x77, 0xf9, 0x6a, 0xbb, 0x83, 0xc1, 0xde, 0x86, 0x40, 0xa2, 0x42, 0x17, 0x30, 0x98, 0xa5, 0xba, 0x70, 0xf9, 0x68, 0x30, 0x3c, 0x11, 0xdb, 0xd0, 0x3b, 0x9e, 0x0d, 0xd1, 0x92, 0x25, 0x2c, 0x26, 0xa2, 0x0b, 0xfa, 0x40, 0xff, 0xfe, 0x7f, 0x11, 0x7b, 0x65, 0x8c, 0x6f, 0xe8, 0x28, 0x8a, 0xf4, 0x6d, 0xa9, 0x2e, 0x5f, 0xd7, 0x1c, 0x28,\n\t0xea, 0xd8, 0x00, 0xbe, 0x60, 0xb5, 0x44, 0xfb, 0xb7, 0xd5, 0x34, 0xec, 0x1b, 0x8d, 0x27, 0x6f, 0x7d, 0x7a, 0xfb, 0x8e, 0x2b, 0x87, 0x92, 0xf1, 0x75, 0x7b, 0x1b, 0x6a, 0xb6, 0xf4, 0x97, 0x59, 0x1c, 0xf7, 0x9a, 0x75, 0x12, 0xa5, 0x26, 0xdc, 0x3e, 0x51, 0x19, 0x19, 0x6c, 0xf0, 0xaa, 0x55, 0x12, 0x9d, 0xef, 0xac, 0x2b, 0xb9, 0xa9, 0xb9, 0x73, 0xd7, 0x50, 0xab, 0xcb, 0xd1, 0xba, 0x76, 0x47, 0x6b, 0xdb, 0x74, 0xb3, 0x9b, 0x31, 0x44, 0xf6, 0x56, 0xa6, 0xf6, 0x8d, 0xb4, 0xb9, 0xdc, 0x3d, 0xb3, 0x67, 0xc7, 0x37, 0x7f, 0x74, 0x4f, 0x7d, 0xfd, 0xce, 0x8f, 0x4c, 0xac, 0x3f, 0x35, 0xdd, 0xed, 0x76, 0x77, 0x4d, 0xde, 0x36, 0x90, 0x98, 0x49, 0xf8, 0xac, 0x8e, 0xce, 0x40, 0xd3, 0xc6, 0x9e, 0x7a, 0xbb, 0xad, 0xbe, 0x67, 0x63, 0x63, 0xa0, 0xcb, 0x6e, 0x43, 0x1c, 0xb1, 0x44, 0x75,\n\t0xfa, 0x22, 0x35, 0x03, 0xd7, 0x62, 0x21, 0x8a, 0x19, 0xa2, 0x28, 0xaa, 0xcc, 0x08, 0x28, 0x91, 0x84, 0xc7, 0x5e, 0x71, 0x17, 0x64, 0x06, 0xd7, 0xed, 0x16, 0x58, 0x23, 0xcb, 0x40, 0xaf, 0x82, 0xf9, 0xd0, 0x2b, 0x61, 0xd3, 0x1c, 0xe4, 0x95, 0xcc, 0xa8, 0x35, 0xea, 0xa1, 0xe5, 0x8a, 0x56, 0x34, 0x93, 0xef, 0xe7, 0xe4, 0x40, 0xae, 0xe0, 0x4a, 0xf6, 0x50, 0x33, 0xd0, 0xb9, 0xe9, 0x2e, 0xc2, 0xce, 0x8d, 0x42, 0x89, 0x9c, 0x9b, 0xf9, 0x63, 0x2a, 0x25, 0x69, 0x41, 0x86, 0xa1, 0x5a, 0x31, 0xff, 0x7b, 0xb2, 0xb3, 0x0c, 0x1d, 0x3b, 0xe8, 0xf4, 0xab, 0x2d, 0x6a, 0xf5, 0xc0, 0x60, 0x03, 0xb2, 0x10, 0xc9, 0x6f, 0x3d, 0x3c, 0x08, 0x4d, 0xc6, 0xf9, 0x46, 0x34, 0xf6, 0x33, 0xe9, 0xfb, 0xc9, 0x5f, 0xe1, 0x75, 0x5b, 0x8c, 0x32, 0xc7, 0xa0, 0x83, 0x40, 0x06, 0xd1, 0x5a, 0xf5, 0x39,\n\t0x50, 0x75, 0xf7, 0xee, 0x0c, 0xab, 0x26, 0x4d, 0xcf, 0x64, 0xf3, 0xed, 0xe7, 0xa8, 0x1e, 0x40, 0x14, 0x17, 0xd9, 0xad, 0x3a, 0x0d, 0xbb, 0x36, 0x44, 0x79, 0x6b, 0x83, 0xe2, 0x57, 0x83, 0x19, 0xbf, 0x81, 0x60, 0x31, 0x40, 0x5f, 0x25, 0x06, 0xfe, 0x17, 0x3b, 0xf9, 0x5d, 0xc6, 0xf6, 0xc3, 0x78, 0xba, 0x0f, 0x26, 0x6c, 0x78, 0xba, 0x9f, 0x1f, 0x87, 0x26, 0xb6, 0xda, 0x6d, 0xab, 0x33, 0x96, 0x98, 0xcb, 0xaf, 0xbf, 0x59, 0xee, 0xf7, 0xc4, 0xbd, 0xee, 0xaa, 0x0a, 0x50, 0x2d, 0x9c, 0xd1, 0xeb, 0xd5, 0x2e, 0x0d, 0x9a, 0xd0, 0xe1, 0xee, 0xc2, 0xb9, 0x27, 0x98, 0x41, 0x1c, 0x1f, 0xb9, 0x8f, 0xd9, 0x07, 0xed, 0x09, 0x39, 0xd1, 0x4c, 0x9c, 0x4d, 0x1a, 0xab, 0xa2, 0x24, 0x49, 0xc3, 0x17, 0x61, 0xb2, 0x2f, 0x42, 0x67, 0xf8, 0xde, 0xb2, 0xef, 0x23, 0x1a, 0xe3, 0xa2, 0xb8, 0xa8,\n\t0x86, 0x95, 0x44, 0xf0, 0x6a, 0x08, 0x28, 0xc7, 0x37, 0xe3, 0xca, 0x5d, 0xf1, 0x2a, 0x23, 0xbf, 0x29, 0x76, 0xcb, 0x1a, 0xea, 0xe2, 0xb1, 0x8a, 0xf2, 0x48, 0x49, 0x56, 0x1c, 0xd2, 0xe5, 0xc4, 0xc1, 0x2a, 0x87, 0x5c, 0x71, 0x08, 0x88, 0x9f, 0x32, 0x55, 0xa3, 0xe8, 0xb3, 0x9c, 0x7a, 0x30, 0xb6, 0xdf, 0x4a, 0x85, 0x47, 0x91, 0x42, 0xc0, 0x12, 0x6a, 0xb9, 0x7b, 0x3d, 0x92, 0x10, 0xd4, 0x07, 0xc6, 0x52, 0x73, 0x39, 0x1b, 0x24, 0x3e, 0x10, 0x86, 0x0a, 0xa2, 0x73, 0x60, 0x02, 0x57, 0x3c, 0x7d, 0xab, 0x3c, 0xe0, 0xa9, 0xcc, 0xca, 0xcc, 0x8b, 0x65, 0xd6, 0x28, 0x90, 0x99, 0x77, 0xee, 0x71, 0x92, 0x0b, 0x1f, 0x53, 0xef, 0x64, 0xab, 0xa0, 0x62, 0x3d, 0x50, 0x96, 0xbe, 0x8f, 0x2a, 0x64, 0x1a, 0xa0, 0x1c, 0x6b, 0x88, 0xc1, 0x64, 0x3f, 0x2a, 0x11, 0x98, 0x3b, 0x1f, 0xe8, 0x6e,\n\t0x82, 0x11, 0x31, 0xfb, 0x78, 0xe9, 0x88, 0x11, 0x1e, 0x87, 0xdd, 0x91, 0x24, 0x39, 0x53, 0xa3, 0xa6, 0xba, 0x2a, 0x11, 0x8f, 0x09, 0x27, 0xc8, 0xb2, 0x12, 0x31, 0x2f, 0x21, 0x91, 0x3c, 0xb7, 0x9f, 0xac, 0x86, 0xc2, 0x48, 0x84, 0xdb, 0xdc, 0x78, 0xba, 0x70, 0xc2, 0xc0, 0xd2, 0xc0, 0xf3, 0x45, 0xc5, 0x49, 0x03, 0x79, 0xb5, 0xc5, 0xb4, 0x59, 0x37, 0x85, 0x5c, 0x59, 0xa1, 0x1c, 0x0a, 0x1d, 0x2e, 0x6f, 0x5d, 0xfe, 0xdc, 0x41, 0x72, 0xf8, 0x2f, 0x41, 0x00, 0x00, 0xef, 0x61, 0x0b, 0x6f, 0x8b, 0x9e, 0xc0, 0xe7, 0x71, 0x0e, 0xa2, 0x8d, 0xf8, 0x48, 0x52, 0xb3, 0x0a, 0xfa, 0xad, 0xb1, 0x88, 0xd3, 0xa1, 0x56, 0x11, 0xe2, 0x6c, 0x1e, 0xa2, 0x8b, 0x90, 0x4a, 0x67, 0x52, 0x6c, 0xb2, 0x21, 0x4a, 0xad, 0x44, 0x95, 0xd4, 0xd0, 0x06, 0x22, 0x16, 0x91, 0x18, 0x4a, 0x62, 0xe3, 0xa3,\n\t0xd5, 0x2b, 0x34, 0xdb, 0x83, 0x76, 0x26, 0xef, 0xa2, 0x16, 0x50, 0x96, 0xd3, 0x7c, 0x33, 0x80, 0x5b, 0x21, 0xc8, 0x42, 0x5b, 0x6b, 0xc8, 0xe7, 0x0d, 0xf9, 0x03, 0x4b, 0x42, 0x16, 0x82, 0xb9, 0xa7, 0x79, 0x79, 0x67, 0xce, 0x4b, 0x1c, 0xee, 0xc5, 0xa8, 0x9f, 0x47, 0xf7, 0xb4, 0xa2, 0x0d, 0x07, 0xc3, 0x18, 0x72, 0x77, 0x1f, 0x36, 0xb6, 0x86, 0xf7, 0x97, 0xad, 0xf7, 0xc4, 0xeb, 0x02, 0xfe, 0xfc, 0x63, 0xbf, 0xeb, 0xef, 0x36, 0x72, 0x1b, 0x4d, 0xaa, 0x3d, 0x90, 0xdd, 0x73, 0xc8, 0x9e, 0x8e, 0x21, 0x3e, 0xd4, 0x36, 0xdc, 0xfd, 0x60, 0xee, 0x51, 0x20, 0xbb, 0xcf, 0x20, 0x1b, 0xe1, 0x19, 0xd1, 0x13, 0xb4, 0x18, 0xcb, 0xb7, 0x93, 0xb8, 0x97, 0x55, 0x9e, 0xba, 0x66, 0xf8, 0xfa, 0xe5, 0x48, 0xc4, 0x0c, 0x01, 0xb7, 0x54, 0x06, 0xc7, 0x32, 0xd1, 0x4d, 0x69, 0xee, 0x4d, 0x4e,\n\t0xd7, 0xba, 0x58, 0x71, 0x49, 0x25, 0xa4, 0x40, 0xa2, 0x50, 0x54, 0xd9, 0x34, 0x50, 0x24, 0xd5, 0xd9, 0xa5, 0xe4, 0x2e, 0x68, 0x05, 0x85, 0xda, 0xd1, 0x1a, 0xf2, 0xea, 0xff, 0x2e, 0xa1, 0xc2, 0xa5, 0x9a, 0x2b, 0x52, 0x0c, 0xa0, 0xab, 0x30, 0xaf, 0x20, 0xd7, 0x2f, 0x27, 0x2f, 0xe7, 0x08, 0x51, 0x20, 0xe6, 0x4d, 0xa7, 0x2b, 0x65, 0x8c, 0xd1, 0x50, 0xed, 0x97, 0xfd, 0x65, 0x69, 0xc9, 0x36, 0xf7, 0x4c, 0xb6, 0x9e, 0x62, 0x25, 0x5b, 0x9f, 0x48, 0xf7, 0x80, 0x5f, 0x75, 0x0c, 0xaf, 0x3a, 0xf9, 0x1a, 0x16, 0x6d, 0x77, 0xcb, 0x90, 0x59, 0x1b, 0xc4, 0xbe, 0x72, 0x63, 0xfa, 0x19, 0xea, 0x28, 0xd4, 0x81, 0x23, 0xc4, 0x47, 0xb9, 0xa0, 0x0b, 0x14, 0x1b, 0xd5, 0xad, 0x26, 0x45, 0x24, 0x0e, 0xba, 0x70, 0x57, 0xe2, 0x2c, 0x62, 0xb8, 0x84, 0xa0, 0x19, 0xe8, 0x81, 0x80, 0x39, 0x02,\n\t0x21, 0xcc, 0xc8, 0xdd, 0x04, 0x29, 0x62, 0x48, 0xd1, 0x6e, 0xa8, 0xe3, 0xb8, 0x50, 0x27, 0x52, 0x8f, 0xd9, 0x22, 0x68, 0x15, 0x8b, 0x9a, 0x8b, 0x19, 0x52, 0xbc, 0x9b, 0xe7, 0xab, 0xc9, 0xf4, 0x22, 0xb2, 0x9d, 0x46, 0x93, 0x9a, 0xe1, 0xb5, 0x6b, 0x06, 0xaa, 0x13, 0xb1, 0xf2, 0x92, 0x22, 0x6f, 0x04, 0xfa, 0xa2, 0x66, 0x9e, 0xcb, 0x30, 0x08, 0x6d, 0xfd, 0x5c, 0x1b, 0x55, 0xb4, 0x34, 0xf9, 0x85, 0x88, 0xb5, 0x25, 0x00, 0xf6, 0x57, 0x31, 0x64, 0x94, 0x3a, 0x5a, 0xda, 0x1b, 0xa9, 0x1b, 0x6a, 0x6b, 0x0a, 0x7a, 0x1b, 0xab, 0x13, 0x89, 0x6a, 0x64, 0xc0, 0x1a, 0xf4, 0xa1, 0xea, 0xd5, 0xf5, 0x15, 0xdd, 0xe5, 0x96, 0xd2, 0xae, 0xc9, 0xcd, 0x93, 0x5d, 0xa5, 0xe5, 0x13, 0xe7, 0x46, 0x66, 0x3e, 0x59, 0x5b, 0x2c, 0xd1, 0xa9, 0x34, 0xc1, 0xaa, 0xee, 0x58, 0x51, 0x5b, 0xd4, 0x5a,\n\t0xda, 0x35, 0xb1, 0x69, 0xa2, 0xab, 0xb4, 0x68, 0xe0, 0x50, 0x9f, 0xda, 0xa9, 0xb1, 0x94, 0x94, 0xc5, 0x3d, 0xee, 0x12, 0x94, 0xad, 0x97, 0xfe, 0x81, 0x41, 0x6b, 0x2c, 0xed, 0xac, 0x88, 0xd4, 0x06, 0xad, 0x36, 0xaf, 0x03, 0x9a, 0xb9, 0x76, 0x8f, 0xad, 0xa0, 0xb8, 0xda, 0x15, 0x8a, 0x07, 0xec, 0xee, 0xa2, 0xe4, 0x78, 0x4b, 0xdd, 0xce, 0xc1, 0xf2, 0x64, 0x75, 0x87, 0x52, 0x6e, 0xb2, 0x9a, 0x8c, 0xfe, 0x98, 0x23, 0x50, 0xe1, 0x73, 0xb8, 0xc3, 0x0d, 0xc3, 0x8d, 0xc9, 0x3d, 0xc3, 0xd5, 0x52, 0x85, 0x53, 0x6b, 0x2b, 0xf1, 0xe8, 0x54, 0x6a, 0x0b, 0x1b, 0x53, 0xae, 0x81, 0x63, 0xf1, 0x16, 0xb4, 0x1f, 0xfc, 0xc4, 0xce, 0xab, 0x0a, 0x0c, 0x7f, 0x63, 0x25, 0xee, 0x45, 0x14, 0x36, 0x24, 0x12, 0x21, 0x17, 0xf9, 0xe1, 0x8a, 0xc9, 0x21, 0xd2, 0x8c, 0xac, 0xa0, 0x8b, 0x32, 0xad,\n\t0xf8, 0x38, 0x6a, 0x6e, 0x6b, 0x22, 0xdb, 0x18, 0x5a, 0x0b, 0x1e, 0x3f, 0xb4, 0x17, 0xd8, 0x8a, 0x84, 0xac, 0x68, 0xe9, 0xdc, 0xdc, 0x26, 0xe0, 0x64, 0x78, 0xb9, 0xbd, 0x05, 0xe5, 0x36, 0x30, 0x37, 0xdc, 0xb5, 0x6e, 0xdf, 0xe0, 0x43, 0x4a, 0x55, 0xd6, 0x46, 0x18, 0xbc, 0x75, 0xac, 0xab, 0xa3, 0xbf, 0x32, 0x2b, 0x8b, 0x8a, 0x9e, 0x91, 0x9e, 0x8a, 0x1c, 0x4b, 0x81, 0x4a, 0xf4, 0x8e, 0xa4, 0xca, 0xd9, 0x17, 0x04, 0x50, 0x17, 0xa2, 0x23, 0x14, 0x0a, 0xfa, 0xb1, 0xe1, 0x64, 0x40, 0xa7, 0x26, 0xb1, 0xb3, 0x82, 0x12, 0xdd, 0x28, 0xfc, 0x6a, 0x7c, 0x20, 0x0e, 0x63, 0xc9, 0xbc, 0x45, 0x56, 0xb6, 0x66, 0x46, 0xd6, 0xe1, 0x16, 0x1b, 0xbd, 0xda, 0xec, 0x59, 0x3d, 0x54, 0xfe, 0x62, 0xc7, 0xc8, 0xae, 0xa3, 0xcd, 0x9b, 0x1f, 0xbf, 0xa5, 0x29, 0x36, 0x71, 0x47, 0xcf, 0xb5, 0xbe,\n\t0x3b, 0xc7, 0x63, 0xde, 0x55, 0xd3, 0xcd, 0x2d, 0x1b, 0xdb, 0xcb, 0xa1, 0x8b, 0x4d, 0x4d, 0x15, 0xd6, 0x15, 0x5b, 0xaa, 0xa6, 0xee, 0x5e, 0xd3, 0x73, 0x7a, 0xe7, 0x6a, 0xd3, 0x6f, 0x41, 0xbf, 0xac, 0xbc, 0x67, 0x36, 0x59, 0xb9, 0xae, 0xc9, 0xeb, 0xf4, 0x39, 0xf5, 0x08, 0x47, 0x91, 0x7e, 0x84, 0xfe, 0x0f, 0x5a, 0x0e, 0xf5, 0x4a, 0x35, 0xf1, 0x2b, 0x8e, 0x8d, 0xb7, 0x08, 0x9a, 0xfc, 0x16, 0x15, 0x0f, 0xcb, 0x46, 0x97, 0x0c, 0x7f, 0xb9, 0x08, 0x95, 0xbd, 0x7b, 0x79, 0xb0, 0xb5, 0x75, 0x99, 0x86, 0x8b, 0xc0, 0xd6, 0x85, 0x1c, 0xd8, 0x7a, 0x36, 0x17, 0xa9, 0xf1, 0x81, 0x60, 0xeb, 0xa5, 0xdb, 0xe7, 0x82, 0xad, 0x11, 0xd6, 0x3a, 0x10, 0x0a, 0x72, 0xa7, 0x27, 0xb9, 0x7e, 0x47, 0x2e, 0xd2, 0x3a, 0x43, 0xdd, 0x67, 0xae, 0x4a, 0x08, 0x61, 0xd6, 0x94, 0xa5, 0xf4, 0x96, 0xd6,\n\t0x8c, 0x36, 0x02, 0xaf, 0x97, 0xae, 0xae, 0xec, 0xde, 0xde, 0xe6, 0x11, 0x42, 0xd8, 0x06, 0xdb, 0xeb, 0xac, 0x4a, 0x59, 0xf8, 0x60, 0x65, 0xbd, 0x3b, 0x82, 0x26, 0x02, 0x45, 0x36, 0x54, 0xf2, 0x3a, 0x68, 0xfe, 0xe3, 0x7a, 0x5d, 0x7c, 0xe4, 0x96, 0xa6, 0x2f, 0x76, 0xae, 0xe3, 0xb5, 0xba, 0xae, 0x30, 0xea, 0xea, 0x0a, 0xbe, 0xff, 0xc3, 0xc1, 0x01, 0x95, 0x0a, 0xd5, 0xeb, 0x09, 0xa4, 0x9f, 0xa4, 0x67, 0xe1, 0x9c, 0x97, 0x40, 0xab, 0xf9, 0x00, 0x8e, 0x44, 0xbc, 0xa8, 0xc1, 0xe0, 0xfd, 0x6e, 0x1b, 0xfe, 0x05, 0xe0, 0x9c, 0x4f, 0x14, 0xa0, 0x28, 0x90, 0x88, 0x10, 0xc7, 0xb8, 0x94, 0x42, 0x14, 0xce, 0x9b, 0xc5, 0x6c, 0x01, 0x4e, 0xee, 0x34, 0xda, 0x89, 0x12, 0x1c, 0x68, 0x62, 0x98, 0x6d, 0x82, 0x56, 0x41, 0x4e, 0x03, 0xe8, 0x9b, 0x11, 0x44, 0xa1, 0xc7, 0xed, 0xb4, 0x59,\n\t0xcd, 0x46, 0x83, 0x5e, 0xa7, 0x55, 0x2b, 0x65, 0x28, 0xa4, 0x22, 0x41, 0xbe, 0x19, 0xe0, 0xcb, 0xc7, 0x31, 0x5e, 0xae, 0xb8, 0x9b, 0x37, 0x1f, 0xe2, 0x0c, 0x5e, 0xdf, 0x2d, 0x51, 0x33, 0x12, 0x8d, 0x74, 0x3b, 0x38, 0xf3, 0xfd, 0xf4, 0x41, 0x14, 0xdf, 0xfd, 0xca, 0x9f, 0x7f, 0xf6, 0xc4, 0xc1, 0x2b, 0x05, 0x76, 0xd1, 0x66, 0x70, 0x68, 0x52, 0xec, 0xd2, 0x3d, 0xb6, 0xff, 0x23, 0xe4, 0xfe, 0xf4, 0xfb, 0xe6, 0xa8, 0xd9, 0x12, 0x35, 0x03, 0x5a, 0x71, 0x63, 0x87, 0xc9, 0x02, 0x1e, 0x21, 0xc3, 0x27, 0x80, 0xca, 0xa2, 0xfe, 0xcd, 0x6f, 0xb4, 0x26, 0x9c, 0x07, 0x45, 0x2e, 0x3c, 0x00, 0x7d, 0x84, 0xad, 0xcc, 0x3c, 0xb4, 0x95, 0xca, 0x89, 0x8b, 0x57, 0x8d, 0x80, 0xca, 0x9c, 0xb2, 0xbb, 0x32, 0xfe, 0x26, 0xca, 0xde, 0x15, 0xe3, 0x90, 0x36, 0x5a, 0xe1, 0x79, 0x93, 0xc5, 0xc1,\n\t0x37, 0xc3, 0xf9, 0xec, 0x70, 0x87, 0x9b, 0xca, 0x69, 0x84, 0xf0, 0x79, 0x14, 0x43, 0xa1, 0xe5, 0x2f, 0x6c, 0x27, 0x62, 0xf3, 0xde, 0xb3, 0x93, 0x03, 0xb1, 0x1a, 0x94, 0x95, 0x42, 0xf5, 0xea, 0x29, 0x30, 0xf3, 0x9e, 0xaa, 0x04, 0x63, 0x57, 0xb3, 0x14, 0xec, 0x19, 0x14, 0x73, 0xee, 0x1c, 0x31, 0x66, 0xe7, 0xc7, 0x8f, 0x5b, 0x7a, 0xba, 0x5b, 0x5a, 0x7a, 0x53, 0xe4, 0x1b, 0xa5, 0xab, 0xcb, 0x47, 0x4f, 0xac, 0x0d, 0x17, 0xae, 0x8d, 0xb6, 0xec, 0xee, 0x2f, 0x89, 0x8e, 0x1c, 0xee, 0xee, 0x3e, 0xbc, 0x2e, 0x3a, 0x34, 0xe0, 0x0f, 0xa9, 0x54, 0x66, 0x31, 0x5d, 0x36, 0xd0, 0xdf, 0x37, 0x80, 0xfe, 0xbd, 0x77, 0x4e, 0xaf, 0x4b, 0x4c, 0x9d, 0x5f, 0x43, 0xfd, 0x83, 0xd9, 0x5c, 0xdc, 0xbb, 0xb3, 0xa5, 0x6d, 0xef, 0x40, 0x69, 0x64, 0xdd, 0xf1, 0x81, 0xf7, 0xbb, 0xb6, 0x4c, 0xf3,\n\t0x7a, 0x62, 0x15, 0x9c, 0xd9, 0x8d, 0xcc, 0x33, 0x44, 0x9c, 0xe5, 0xbf, 0xa5, 0x68, 0x1a, 0xe3, 0x71, 0x45, 0x80, 0x92, 0xc0, 0x7d, 0x88, 0xe0, 0x08, 0xa7, 0xb8, 0xd3, 0x43, 0x8e, 0x55, 0x1c, 0x33, 0xd2, 0xc0, 0x1e, 0x71, 0x73, 0x49, 0x10, 0x3a, 0x42, 0x09, 0x29, 0xab, 0xd8, 0xc4, 0x28, 0x86, 0xc9, 0xe6, 0x32, 0xf3, 0xda, 0x4d, 0x90, 0x29, 0x85, 0x4d, 0x47, 0x8a, 0xc7, 0xf7, 0xc4, 0x8c, 0x94, 0x52, 0xeb, 0xd3, 0xa5, 0x2f, 0x16, 0x0d, 0x05, 0xc0, 0x37, 0xdc, 0xfe, 0x1b, 0x75, 0x5a, 0x3d, 0xf8, 0x46, 0xba, 0x9a, 0x1c, 0x8c, 0xd7, 0xf8, 0x5b, 0xd6, 0x57, 0x56, 0x8e, 0xb4, 0x46, 0x64, 0xca, 0x92, 0xd0, 0x16, 0xf5, 0xe0, 0xd1, 0xc7, 0x27, 0x26, 0x3e, 0xb1, 0xbf, 0xa5, 0xb2, 0xe4, 0x39, 0x72, 0x42, 0xe7, 0xd3, 0xa7, 0xef, 0x91, 0xab, 0xfc, 0xce, 0x83, 0xab, 0x0c, 0xa5,\n\t0x3a, 0xf0, 0xad, 0x47, 0xda, 0xce, 0xf5, 0xd7, 0x8f, 0xd5, 0x3b, 0x9d, 0x89, 0xee, 0xe2, 0x80, 0x55, 0xac, 0x9b, 0xfe, 0xc8, 0x96, 0xca, 0xaa, 0xad, 0x0f, 0x4d, 0x0e, 0xdd, 0xdb, 0xfc, 0x08, 0xab, 0xe7, 0x43, 0x0b, 0x7f, 0xa2, 0xa2, 0xd0, 0x5e, 0xae, 0x41, 0x39, 0xdc, 0x65, 0x80, 0x62, 0xf4, 0xb8, 0x04, 0x32, 0xdc, 0x28, 0xe9, 0x7d, 0xbc, 0xbf, 0x87, 0x78, 0xf3, 0x78, 0x87, 0x0f, 0xbe, 0x33, 0x97, 0xe4, 0xa9, 0xd5, 0x86, 0x9c, 0x3e, 0x53, 0x29, 0x9b, 0xe9, 0xc8, 0xee, 0x71, 0x6c, 0xd8, 0x26, 0x21, 0xdc, 0x11, 0x39, 0x4e, 0xd4, 0xac, 0x25, 0x0c, 0xde, 0x70, 0x96, 0x37, 0xb6, 0x34, 0x96, 0x3b, 0x6b, 0xb6, 0xdc, 0xbf, 0xae, 0x7a, 0x6e, 0x76, 0xd8, 0x51, 0xad, 0xb0, 0xe8, 0xca, 0x5b, 0x86, 0xab, 0x63, 0xab, 0xab, 0x9c, 0xce, 0x8a, 0xa6, 0x96, 0xa6, 0x72, 0xe7, 0x01,\n\t0xa1, 0x1d, 0x4c, 0x45, 0x8b, 0xea, 0x4a, 0xfd, 0x81, 0x48, 0xe3, 0x50, 0x6d, 0xff, 0xe9, 0x8d, 0x09, 0x53, 0xb8, 0xba, 0xb0, 0x53, 0xe7, 0xf4, 0x3a, 0xed, 0xb1, 0x8e, 0xe2, 0xd2, 0x64, 0xd4, 0x1f, 0x2c, 0x6d, 0x1a, 0xae, 0x8f, 0xe6, 0xd8, 0xc1, 0xd0, 0x6b, 0x4d, 0xdf, 0x46, 0x7d, 0x0f, 0xda, 0xc1, 0x7a, 0x62, 0x23, 0x4b, 0x2b, 0xee, 0x96, 0x00, 0x91, 0x4c, 0x4a, 0x32, 0x84, 0x88, 0xd9, 0x44, 0x03, 0xae, 0xfc, 0x0c, 0x07, 0xb6, 0x65, 0x53, 0xeb, 0xa1, 0x0f, 0x8c, 0x6a, 0xd0, 0x2c, 0xdb, 0x0e, 0x9d, 0xf2, 0xe9, 0x38, 0xa4, 0x37, 0xff, 0x9f, 0x1c, 0xe1, 0xf4, 0xf8, 0x12, 0x9f, 0x98, 0x8d, 0x1c, 0x25, 0xea, 0x78, 0x8c, 0xe4, 0x21, 0x30, 0x92, 0x7e, 0xea, 0x7a, 0xfa, 0x29, 0xf4, 0x03, 0x8c, 0x5c, 0x07, 0x23, 0xe4, 0x53, 0x7f, 0x78, 0x64, 0x1e, 0xfe, 0xff, 0x91, 0x3f,\n\t0x3c, 0x42, 0x9e, 0x98, 0x3f, 0xfe, 0x08, 0xc2, 0x8e, 0x40, 0x7d, 0xf3, 0x28, 0x7c, 0x46, 0x3b, 0x9a, 0x5b, 0x50, 0xee, 0x8c, 0x0a, 0x88, 0x30, 0xf7, 0x2f, 0x8d, 0x9f, 0x89, 0xc3, 0x08, 0x8a, 0x31, 0x8f, 0x77, 0x1e, 0x50, 0xde, 0x4e, 0xd8, 0xbd, 0x5a, 0xbd, 0x57, 0x8b, 0x2b, 0x0e, 0xf1, 0x38, 0xf9, 0xa5, 0x40, 0x39, 0xf4, 0xa3, 0xee, 0x82, 0x5b, 0xbf, 0x93, 0x0b, 0xc5, 0xb9, 0x94, 0xee, 0xb5, 0xbb, 0xc1, 0x18, 0x79, 0xd7, 0x22, 0x08, 0x8e, 0x92, 0xc5, 0xb4, 0xc0, 0xe7, 0xda, 0x03, 0x9f, 0xcb, 0x87, 0x9e, 0x4b, 0x09, 0x2d, 0x57, 0x7c, 0x66, 0xc1, 0x90, 0x04, 0x33, 0x85, 0x10, 0x93, 0x33, 0x2c, 0x0e, 0x05, 0x61, 0xd8, 0xc6, 0x11, 0x96, 0x7f, 0x9a, 0x3b, 0xaf, 0x82, 0x6d, 0x7c, 0x84, 0x4f, 0xeb, 0xf7, 0x78, 0xcd, 0x7e, 0x8e, 0x45, 0x27, 0x1f, 0x94, 0x12, 0xe3, 0x11,\n\t0xfd, 0x59, 0x6c, 0xca, 0x52, 0x50, 0x14, 0xc5, 0xaf, 0x5d, 0xd6, 0x5b, 0xe7, 0xb2, 0x70, 0x14, 0xe6, 0xfa, 0x8d, 0xc7, 0x73, 0x01, 0x28, 0x8f, 0xb3, 0xaf, 0xc0, 0xc3, 0x50, 0xe0, 0xc3, 0xe2, 0x98, 0xc7, 0x93, 0x38, 0xe6, 0x61, 0x20, 0x8a, 0x93, 0x21, 0x71, 0x0e, 0x66, 0x1f, 0x7b, 0xc0, 0x39, 0x90, 0x7d, 0x68, 0x72, 0x68, 0xd9, 0x04, 0xfc, 0x7c, 0xb0, 0x3e, 0x1b, 0x93, 0x80, 0x62, 0x9b, 0x3f, 0x95, 0x1b, 0x86, 0x48, 0xff, 0x0a, 0xfd, 0xcd, 0xbc, 0xf0, 0x03, 0xdc, 0x37, 0xaa, 0xa0, 0x52, 0xbb, 0x41, 0x4b, 0x09, 0x05, 0xdc, 0xbb, 0xfb, 0x92, 0xd2, 0xf2, 0x52, 0xbd, 0x86, 0x06, 0x58, 0x97, 0xda, 0x79, 0x72, 0x52, 0x68, 0x6a, 0x90, 0x38, 0xbc, 0x8f, 0xb5, 0x83, 0x2d, 0x69, 0x42, 0x47, 0xab, 0x78, 0xdf, 0xe4, 0xe3, 0xfe, 0xf8, 0x83, 0xd1, 0xa4, 0x12, 0xfe, 0x57, 0xad,\n\t0xac, 0xf2, 0x15, 0x9a, 0xfd, 0x0c, 0x22, 0xf7, 0xc5, 0x67, 0x3c, 0x1c, 0x61, 0x89, 0x14, 0x78, 0x11, 0xd5, 0x52, 0x30, 0x80, 0x8e, 0x7e, 0xaa, 0x82, 0x11, 0x10, 0x17, 0x10, 0xc7, 0x8a, 0xcd, 0xd9, 0xca, 0xa3, 0xa0, 0x26, 0x99, 0x8a, 0x96, 0x46, 0x2b, 0x35, 0x72, 0xf2, 0x17, 0xe9, 0x99, 0xe7, 0xfe, 0xdd, 0xd1, 0xe0, 0xb4, 0x88, 0x65, 0x1e, 0xa5, 0x45, 0xa1, 0xd3, 0xe8, 0x3d, 0xc9, 0x0d, 0x4d, 0x8d, 0x63, 0x75, 0x0e, 0x77, 0xdd, 0xea, 0xe8, 0x66, 0x75, 0x81, 0x5c, 0x62, 0x52, 0xff, 0x95, 0x71, 0x19, 0xc8, 0x63, 0xee, 0xb5, 0x89, 0xa2, 0x58, 0x6d, 0xd4, 0x1a, 0x37, 0x83, 0xd6, 0x1b, 0x12, 0xf0, 0x1d, 0x89, 0x4a, 0xd4, 0x62, 0x2a, 0x12, 0x43, 0xeb, 0x3b, 0xe0, 0x1e, 0x2a, 0xaa, 0x99, 0x5c, 0x15, 0xf0, 0x35, 0x0e, 0x44, 0x2a, 0x86, 0x3a, 0x6a, 0xcd, 0xdf, 0x74, 0x76,\n\t0x84, 0x8a, 0xd6, 0x96, 0x92, 0x73, 0x5a, 0x13, 0x94, 0x7b, 0x39, 0x7c, 0x8b, 0xe7, 0xa0, 0xdc, 0x17, 0x61, 0xfc, 0x67, 0x6f, 0x06, 0xe3, 0x4f, 0x3e, 0x37, 0x7f, 0x07, 0xb8, 0x96, 0x3e, 0x09, 0x8e, 0xa1, 0xea, 0xc1, 0x0f, 0x83, 0xa2, 0x87, 0xc1, 0x63, 0x59, 0x6c, 0x95, 0x0f, 0x7e, 0x6f, 0x3e, 0xc6, 0x7f, 0x76, 0x19, 0x8c, 0x3f, 0xe5, 0x4b, 0x17, 0x7e, 0xe5, 0x2b, 0xe0, 0x17, 0xe0, 0x9b, 0xe9, 0x5a, 0xea, 0x9d, 0xf4, 0x26, 0x5c, 0x56, 0x67, 0xe1, 0x6d, 0xe6, 0x0c, 0xf4, 0x29, 0x94, 0x50, 0x1f, 0x27, 0x93, 0xf2, 0x20, 0x1c, 0x97, 0x38, 0x52, 0x62, 0xbc, 0x23, 0xac, 0xc9, 0x81, 0x8d, 0x65, 0xa8, 0xba, 0xb2, 0xb7, 0x10, 0x55, 0xd7, 0xd5, 0x50, 0x30, 0x8c, 0x98, 0xba, 0xfc, 0xbc, 0xc9, 0x97, 0xa9, 0xc2, 0x90, 0xc3, 0xf6, 0x5e, 0x05, 0x87, 0x00, 0x07, 0x01, 0x70, 0x6c,\n\t0x90, 0x6a, 0xde, 0xf6, 0xe0, 0x44, 0x51, 0x71, 0xfb, 0xfa, 0x68, 0x53, 0xe7, 0x4b, 0xc5, 0x83, 0x07, 0x53, 0x53, 0x4f, 0x1e, 0x68, 0xee, 0x7f, 0x72, 0xfe, 0xb3, 0x57, 0xde, 0x7b, 0x72, 0x20, 0xb6, 0xe1, 0xf4, 0x40, 0x85, 0x18, 0x6a, 0x7d, 0xc9, 0xe4, 0x74, 0x78, 0xec, 0xbe, 0xd9, 0x0b, 0xd2, 0xa6, 0x99, 0xf3, 0x43, 0x7d, 0xb7, 0x8f, 0x57, 0xac, 0x9e, 0x5c, 0x7b, 0xb8, 0xdf, 0xdf, 0x73, 0xfa, 0xea, 0xd6, 0x63, 0xff, 0xed, 0xfe, 0xfe, 0xbe, 0xbb, 0xbf, 0xb6, 0x6f, 0xec, 0xe3, 0xa7, 0x66, 0x3d, 0xfd, 0x0a, 0xab, 0x59, 0x47, 0x55, 0x7c, 0xf9, 0x70, 0xf7, 0xf1, 0x0d, 0x0d, 0x32, 0x56, 0x3e, 0x65, 0xe9, 0x2b, 0x74, 0x1f, 0xf3, 0x32, 0x91, 0x40, 0x7c, 0x7e, 0x6a, 0x15, 0x89, 0xfd, 0x45, 0x49, 0x18, 0xda, 0xdb, 0x28, 0xe8, 0xc5, 0xf2, 0x3e, 0xcd, 0xe0, 0x64, 0xe3, 0x51,\n\t0xe4, 0x3e, 0xce, 0xa6, 0x64, 0x52, 0x31, 0x85, 0xd7, 0x2b, 0xc3, 0xe0, 0xb0, 0x31, 0xf4, 0x22, 0xe1, 0x17, 0x25, 0x88, 0x84, 0xd6, 0x18, 0x0e, 0xa2, 0xe2, 0xd6, 0x26, 0xa4, 0xcf, 0x62, 0x19, 0x44, 0x23, 0xde, 0x57, 0x31, 0x88, 0x0a, 0x1d, 0xc3, 0xe7, 0x14, 0x83, 0x76, 0x09, 0xeb, 0x44, 0x7b, 0xb4, 0xdf, 0x41, 0xc0, 0xc6, 0x47, 0xee, 0x29, 0x08, 0xea, 0x9d, 0xd6, 0xd6, 0x26, 0x72, 0xbb, 0x9e, 0xab, 0x0f, 0x6d, 0x37, 0x28, 0x18, 0xa5, 0xd8, 0xe9, 0x9e, 0x88, 0x8f, 0xcd, 0xf4, 0x34, 0x25, 0xd2, 0x1b, 0xa9, 0x11, 0x0c, 0x6e, 0xbc, 0xf3, 0xc9, 0x67, 0x19, 0xd1, 0x0e, 0xad, 0x6c, 0xfd, 0x96, 0x3b, 0x6f, 0x58, 0x04, 0x15, 0xa3, 0xbb, 0xf8, 0x42, 0xd2, 0xeb, 0x6f, 0x5c, 0x66, 0xe3, 0x39, 0x70, 0xff, 0xfd, 0x3a, 0x7c, 0x47, 0x3b, 0x11, 0x21, 0x06, 0x92, 0x7d, 0x2a, 0x20,\n\t0x01, 0x6a, 0x40, 0xa2, 0xc3, 0x78, 0xf4, 0x92, 0x88, 0x4e, 0x57, 0x4c, 0xcc, 0x21, 0x04, 0x47, 0x96, 0xbb, 0x6c, 0x06, 0xbb, 0x17, 0xfc, 0x2b, 0x23, 0x00, 0xe4, 0x34, 0x0d, 0xdf, 0x33, 0x52, 0xe2, 0x76, 0x39, 0x1d, 0x48, 0x73, 0x6a, 0xb9, 0x57, 0xb5, 0xae, 0xf0, 0xaa, 0xf0, 0x9d, 0x40, 0x1e, 0xaf, 0x76, 0x1d, 0xc8, 0x7f, 0xcb, 0xeb, 0xe9, 0x8d, 0xe4, 0xa6, 0xab, 0xdf, 0xbb, 0x4b, 0x59, 0xc0, 0x6c, 0x65, 0xa4, 0xb4, 0x58, 0xbe, 0x55, 0x54, 0xa0, 0x38, 0xb9, 0xd4, 0x2b, 0xa2, 0xf7, 0xa1, 0x1f, 0x80, 0x66, 0x8d, 0xf8, 0x04, 0x34, 0xdd, 0x74, 0xea, 0x13, 0x12, 0x31, 0x91, 0x79, 0xbf, 0x3d, 0xf0, 0xfd, 0x7c, 0xf0, 0xfd, 0xce, 0x5f, 0x2d, 0x80, 0xaf, 0xc5, 0xf3, 0x88, 0x96, 0x62, 0x37, 0x04, 0x1a, 0x42, 0x70, 0xe2, 0xcf, 0xa4, 0xa4, 0x38, 0x14, 0xcb, 0x5f, 0x21, 0x57,\n\t0x75, 0x54, 0x8c, 0x55, 0x08, 0xd6, 0xc0, 0x34, 0x06, 0x62, 0xa0, 0xf6, 0x32, 0xc0, 0xb7, 0x96, 0x8c, 0xc9, 0xa1, 0x58, 0x76, 0x2c, 0xd1, 0x76, 0x34, 0xe9, 0x0a, 0xf8, 0x01, 0x51, 0x1c, 0xf6, 0x47, 0x02, 0x11, 0x97, 0x93, 0x4d, 0x0c, 0xd4, 0x69, 0x15, 0x72, 0x89, 0x88, 0xf0, 0x01, 0x9f, 0x82, 0x23, 0xc2, 0xe5, 0x6a, 0xbc, 0xaa, 0x28, 0x5e, 0x20, 0x5e, 0x01, 0xd4, 0x95, 0xc9, 0x54, 0xa2, 0x25, 0x0d, 0x85, 0xe5, 0x3e, 0xbb, 0x02, 0x17, 0x9d, 0xbd, 0xb5, 0x2a, 0x15, 0x31, 0x60, 0xb9, 0x5c, 0x47, 0xa2, 0x8a, 0x0e, 0x1f, 0x06, 0xdf, 0xce, 0x14, 0xa7, 0x65, 0x5e, 0x16, 0x29, 0x2d, 0xba, 0xb7, 0x95, 0xda, 0xdb, 0x49, 0xe8, 0xa9, 0x56, 0x72, 0x52, 0xe1, 0xa5, 0xb5, 0xe6, 0xf8, 0x70, 0xb1, 0x9a, 0xab, 0x58, 0xcb, 0xc9, 0xe5, 0x39, 0x3c, 0xee, 0x15, 0xc4, 0x67, 0x58, 0x96,\n\t0x67, 0x39, 0x3f, 0xc5, 0x19, 0xe4, 0x0e, 0xa9, 0x90, 0x41, 0x05, 0xa7, 0x82, 0x98, 0x9d, 0x0a, 0xa3, 0x6c, 0x9b, 0xb0, 0x0c, 0x48, 0x60, 0x77, 0x09, 0x9a, 0x13, 0x68, 0x3a, 0x28, 0xc4, 0x64, 0xde, 0x84, 0x90, 0x73, 0x13, 0xc2, 0x96, 0x8c, 0xe5, 0xb5, 0xc5, 0x53, 0x07, 0xfd, 0x2a, 0x1e, 0x53, 0x00, 0x0c, 0x0a, 0x5e, 0xdc, 0x6b, 0x34, 0x69, 0x83, 0x73, 0x88, 0x88, 0x94, 0x86, 0x83, 0xde, 0x42, 0x47, 0x85, 0xb3, 0x22, 0x3b, 0x9f, 0x94, 0x1f, 0x38, 0x9f, 0x16, 0xd5, 0x61, 0x5d, 0x6a, 0x3e, 0x89, 0x51, 0x69, 0xd6, 0x73, 0x2a, 0xae, 0x34, 0xeb, 0x39, 0x7b, 0xcb, 0x8e, 0xe5, 0xe6, 0x13, 0x73, 0x79, 0x51, 0xc9, 0x56, 0x1a, 0xcb, 0xed, 0x5f, 0x44, 0xb5, 0xb8, 0x16, 0x57, 0x39, 0xd1, 0x47, 0xfc, 0x38, 0x29, 0x6f, 0x4e, 0x92, 0xb4, 0x38, 0x06, 0x64, 0x72, 0x5e, 0xe7, 0x95,\n\t0xc1, 0x3d, 0x1d, 0xba, 0x24, 0xb3, 0xb8, 0x74, 0x2c, 0xf4, 0xd0, 0x89, 0x69, 0x14, 0x63, 0xc2, 0xf1, 0x61, 0x28, 0x2a, 0xb9, 0x5c, 0x34, 0x2a, 0xc5, 0x51, 0x65, 0x95, 0x82, 0x94, 0xc9, 0xa6, 0x65, 0xc8, 0xda, 0x37, 0x22, 0x28, 0x15, 0xea, 0xc6, 0xec, 0xbb, 0xe9, 0x5e, 0xc9, 0x38, 0xdb, 0x81, 0xa0, 0xc5, 0x12, 0x31, 0x2d, 0x99, 0xcb, 0x76, 0x24, 0x38, 0xc0, 0xd5, 0x92, 0xfd, 0xa0, 0x3f, 0xe0, 0xae, 0xa8, 0x08, 0x85, 0x2a, 0xfa, 0x2a, 0xfa, 0x7a, 0x7b, 0x52, 0xdd, 0x5d, 0x9d, 0x6d, 0xab, 0x1a, 0xeb, 0x6b, 0xaa, 0x43, 0xe5, 0xa1, 0x68, 0x30, 0x14, 0x0a, 0xf9, 0xd4, 0x99, 0x1a, 0x72, 0x59, 0x3f, 0x80, 0xc9, 0xbb, 0xd6, 0x8b, 0x31, 0x45, 0x3d, 0xda, 0x0b, 0x57, 0x1a, 0x12, 0x6a, 0x52, 0xe7, 0x0c, 0x99, 0x8c, 0x41, 0x87, 0x56, 0xeb, 0x08, 0x1a, 0x4d, 0x21, 0xa7, 0x0e,\n\t0xf4, 0x6a, 0xe1, 0x1d, 0x13, 0x7b, 0xc7, 0x04, 0xef, 0x68, 0xcb, 0x7e, 0xa6, 0xf5, 0x15, 0x6c, 0x3f, 0xa1, 0xf2, 0x78, 0x6f, 0x3c, 0xbf, 0x78, 0xbc, 0xe8, 0x2f, 0x9a, 0x02, 0xa8, 0x6d, 0x00, 0xb5, 0xd5, 0xa1, 0x6f, 0xcb, 0xbb, 0x06, 0x3b, 0x7f, 0xae, 0x56, 0xfd, 0xa3, 0xd9, 0xf2, 0xee, 0x37, 0x97, 0x1b, 0x47, 0x5e, 0x97, 0x8b, 0xbe, 0x01, 0xe7, 0x7b, 0x3f, 0xd0, 0xb3, 0xd2, 0x36, 0xb4, 0x57, 0x94, 0x53, 0x4a, 0xa9, 0x17, 0xba, 0x1c, 0x1a, 0xb8, 0x22, 0xa8, 0xee, 0x36, 0x20, 0xed, 0xb4, 0x25, 0x0d, 0xf0, 0x87, 0x22, 0xf7, 0x23, 0x9c, 0x29, 0x84, 0xba, 0x54, 0x13, 0x4a, 0xa5, 0x14, 0xce, 0x5d, 0xa9, 0x14, 0x2a, 0x43, 0x99, 0x8c, 0xff, 0x15, 0xad, 0x7a, 0xc9, 0xa8, 0x4a, 0x4e, 0x4a, 0x24, 0xb3, 0x29, 0x8d, 0x5a, 0xcc, 0xd0, 0xe8, 0xc0, 0x26, 0xc3, 0x2a, 0xb5, 0x95,\n\t0xe4, 0x4b, 0x16, 0x25, 0x60, 0x7f, 0xc5, 0x18, 0xa1, 0x50, 0xcc, 0xb0, 0xdd, 0x89, 0x9b, 0xec, 0x9d, 0x6c, 0xc8, 0xf0, 0x4e, 0xdd, 0xf4, 0x17, 0x10, 0xd9, 0xfe, 0x70, 0xc0, 0x11, 0x09, 0x65, 0x3f, 0xd1, 0xdf, 0xd7, 0xdb, 0xdd, 0xb9, 0xaa, 0xb9, 0xb1, 0xa1, 0x3a, 0x1e, 0x8d, 0x98, 0x70, 0x6e, 0xbc, 0xcf, 0x1b, 0xd4, 0xc2, 0x2d, 0xc9, 0xb3, 0xfc, 0xce, 0x93, 0xaf, 0x98, 0x50, 0x01, 0x88, 0x0c, 0x5e, 0x7f, 0xd1, 0xa0, 0x8b, 0x46, 0xb9, 0x8d, 0xc9, 0xa1, 0x57, 0x30, 0x6a, 0xc6, 0xe9, 0x9a, 0xac, 0x84, 0x1b, 0x53, 0x63, 0x45, 0x7a, 0xc3, 0xb5, 0x74, 0xd7, 0x75, 0x16, 0x9d, 0x7f, 0x6a, 0x70, 0x55, 0x3d, 0x93, 0x45, 0xf1, 0x7f, 0xe5, 0x91, 0x7b, 0x2c, 0x21, 0x9d, 0xc3, 0xda, 0x06, 0x07, 0x7c, 0x99, 0x9d, 0x4a, 0xa0, 0xc7, 0x7a, 0x30, 0x6a, 0x7f, 0x4a, 0xc1, 0x61, 0xfb,\n\t0xdb, 0x73, 0x46, 0x9b, 0xd5, 0x6b, 0xe2, 0x2a, 0x38, 0xce, 0x71, 0xa2, 0x83, 0x78, 0x8d, 0x1d, 0x36, 0x4d, 0x89, 0xc5, 0x4c, 0x49, 0x19, 0x29, 0x76, 0x2c, 0x8b, 0x01, 0x03, 0x47, 0x59, 0x03, 0x7f, 0x48, 0xb2, 0xb7, 0xa9, 0xec, 0x08, 0x2b, 0x44, 0xb4, 0x48, 0x41, 0xcf, 0x41, 0xc9, 0x32, 0x63, 0x2a, 0xa5, 0x84, 0xc2, 0xa9, 0xee, 0x08, 0xee, 0xca, 0x5f, 0x20, 0x94, 0x3f, 0x3d, 0x2a, 0x13, 0x93, 0xc8, 0xfc, 0x52, 0xcb, 0x29, 0x8a, 0xb3, 0x38, 0x2b, 0x05, 0x5d, 0x25, 0x63, 0xec, 0x39, 0x32, 0xdb, 0x8f, 0x5c, 0xbe, 0xdb, 0x68, 0xd2, 0x4e, 0x10, 0x1d, 0x6d, 0xe8, 0x2c, 0x04, 0xf9, 0xb3, 0x95, 0xb1, 0x68, 0xc4, 0x6b, 0x8c, 0xfb, 0xf1, 0xd8, 0x68, 0xd0, 0xb8, 0xfc, 0xcd, 0x03, 0x40, 0x2d, 0xda, 0x54, 0x99, 0x67, 0x6e, 0x52, 0xf8, 0xe2, 0x17, 0x05, 0x3b, 0xed, 0x36, 0x06,\n\t0xed, 0xb4, 0x7f, 0x83, 0xec, 0x17, 0xed, 0xbe, 0x78, 0x2c, 0x44, 0x7f, 0x86, 0x63, 0x51, 0x47, 0xb4, 0x81, 0x71, 0x56, 0x35, 0xca, 0x2d, 0x66, 0x52, 0xc6, 0x0d, 0x85, 0x8d, 0x2d, 0xf2, 0x85, 0x6e, 0x89, 0xf8, 0x5b, 0x39, 0x0d, 0x46, 0xb9, 0x28, 0x5c, 0x23, 0x9c, 0xec, 0xcc, 0x98, 0x46, 0x38, 0x1a, 0xfc, 0x85, 0x0a, 0xa0, 0x81, 0xd2, 0xe4, 0x8c, 0x8d, 0x9c, 0x13, 0xb2, 0x82, 0x1f, 0x1b, 0xf6, 0xef, 0x54, 0xc8, 0xc0, 0xdf, 0xd1, 0xd3, 0xf8, 0xff, 0xc0, 0xdf, 0x4f, 0xd6, 0xc0, 0x2f, 0x10, 0xce, 0x09, 0x0d, 0x3b, 0x27, 0xf8, 0xce, 0xe4, 0xf2, 0x7d, 0x51, 0x64, 0xcf, 0xdd, 0x50, 0x4f, 0x10, 0x2d, 0xc9, 0xfa, 0xb6, 0x86, 0x36, 0x28, 0xca, 0xba, 0xda, 0x9a, 0x9c, 0x69, 0xa2, 0xbd, 0xe9, 0x69, 0x92, 0x67, 0x71, 0x50, 0x19, 0x0b, 0x63, 0xe5, 0x19, 0x72, 0xe5, 0x49, 0xde,\n\t0xfe, 0xb0, 0xab, 0x6f, 0xad, 0xee, 0xad, 0x30, 0x91, 0xdb, 0x87, 0x33, 0x36, 0xc7, 0x07, 0xcf, 0x10, 0x6c, 0x93, 0xa8, 0x34, 0x19, 0x9b, 0x84, 0x79, 0x86, 0x37, 0x42, 0x78, 0xfb, 0x4c, 0xec, 0xc1, 0xeb, 0x35, 0x05, 0x26, 0xb9, 0xf5, 0xea, 0xd3, 0xa8, 0x29, 0x44, 0x71, 0x27, 0x96, 0x90, 0xdd, 0x5e, 0x00, 0xd0, 0x7a, 0x85, 0x3f, 0xe8, 0xec, 0xed, 0x0c, 0x6e, 0xbd, 0x56, 0x0d, 0x94, 0xd0, 0xc4, 0x50, 0x12, 0x73, 0x2a, 0x80, 0x58, 0xf0, 0xb5, 0x0a, 0x14, 0x12, 0xe4, 0x4c, 0x55, 0xfe, 0x42, 0x86, 0x18, 0x84, 0x46, 0x45, 0x14, 0x89, 0x0c, 0x0d, 0x8d, 0x5c, 0x4a, 0x89, 0xc5, 0xd3, 0x62, 0x7e, 0x56, 0x64, 0xbf, 0x81, 0x10, 0x7e, 0x81, 0x0a, 0xdc, 0xd4, 0x37, 0x18, 0xff, 0x0f, 0x9f, 0x21, 0xb9, 0x2a, 0xa7, 0x33, 0x8e, 0xf1, 0xce, 0xa4, 0xf8, 0xef, 0x21, 0x05, 0x5f, 0x43,\n\t0x2e, 0xff, 0x2d, 0x68, 0x8e, 0x14, 0x42, 0x05, 0x42, 0x74, 0xb4, 0xc3, 0x59, 0x52, 0x97, 0x48, 0x55, 0xa5, 0x58, 0x65, 0x52, 0x51, 0x8e, 0x2d, 0x27, 0x34, 0x53, 0x74, 0x39, 0x7e, 0xc7, 0x07, 0x29, 0x11, 0x5e, 0xef, 0x2f, 0x63, 0x51, 0xad, 0xa8, 0x45, 0xae, 0xe1, 0xb9, 0x44, 0x1f, 0x42, 0x66, 0xd6, 0x79, 0x25, 0x67, 0x66, 0x9d, 0x77, 0x64, 0xcc, 0xac, 0x15, 0x95, 0x08, 0x3f, 0x9d, 0x96, 0x30, 0xbd, 0x58, 0xdb, 0x4b, 0xbc, 0x16, 0xda, 0x5e, 0x71, 0xa2, 0x89, 0x58, 0x43, 0x6c, 0x01, 0x21, 0x6e, 0xbe, 0xc0, 0xc9, 0xa1, 0x14, 0x4e, 0x0e, 0x5b, 0x52, 0x8f, 0xe7, 0x8b, 0x9a, 0x54, 0x00, 0x0d, 0x60, 0x14, 0xe8, 0x6e, 0x26, 0xdd, 0xb7, 0x51, 0x0f, 0x94, 0x40, 0xad, 0x9c, 0xd5, 0x02, 0xb5, 0x06, 0xa8, 0x08, 0xb5, 0x6a, 0x5a, 0x81, 0xc5, 0x8d, 0x10, 0xe8, 0x9c, 0xb4, 0xd9,\n\t0x5f, 0x73, 0x84, 0xad, 0xcb, 0x1b, 0xf4, 0x06, 0xf4, 0x2d, 0xca, 0x7d, 0x7f, 0xef, 0x97, 0x24, 0x5b, 0x60, 0x7f, 0x5a, 0xb9, 0x8f, 0x80, 0xdd, 0x80, 0x82, 0x99, 0xcb, 0x7e, 0x0f, 0x91, 0x99, 0x05, 0xbc, 0xbb, 0xb5, 0xdc, 0x97, 0xc0, 0x51, 0x0f, 0x24, 0xe0, 0xa8, 0x4f, 0x6f, 0x5e, 0x3f, 0xb2, 0xba, 0xaf, 0xbd, 0x35, 0xd1, 0x94, 0x68, 0xac, 0xab, 0x59, 0x34, 0xf2, 0x86, 0xbf, 0x6f, 0xe4, 0x33, 0xf6, 0x9d, 0xfe, 0x03, 0x2c, 0xc1, 0x9b, 0x9d, 0x11, 0xcc, 0xb5, 0x8c, 0x9d, 0x77, 0x7f, 0xbe, 0x09, 0x98, 0x7e, 0x21, 0xdf, 0x4c, 0xfc, 0x5b, 0x26, 0x8b, 0xa8, 0x96, 0xb5, 0x00, 0xd3, 0xc7, 0x3f, 0xc0, 0x54, 0xc4, 0xf1, 0x58, 0xe8, 0xd3, 0x3f, 0xc5, 0x34, 0x10, 0x8d, 0xc4, 0x57, 0x92, 0x6a, 0x3f, 0x74, 0x6f, 0x0a, 0x00, 0xa0, 0xc8, 0xee, 0x08, 0x1c, 0xad, 0x2e, 0xd6, 0x4a,\n\t0x0b, 0x12, 0x22, 0xb1, 0x68, 0x1f, 0x2a, 0x44, 0xc7, 0x63, 0xb0, 0x51, 0x55, 0x13, 0x1a, 0xc7, 0x07, 0x33, 0x64, 0x64, 0x6c, 0x59, 0x73, 0x27, 0x4e, 0x80, 0x40, 0xcd, 0x09, 0xf8, 0x09, 0x90, 0x4a, 0xe6, 0x96, 0xee, 0x46, 0x08, 0x7a, 0x25, 0x2b, 0xb8, 0x0e, 0xb4, 0x84, 0xce, 0xeb, 0x80, 0x9b, 0xa2, 0xca, 0x31, 0x28, 0xb3, 0x55, 0xd8, 0x09, 0x1d, 0xf0, 0x37, 0xd4, 0x85, 0xb5, 0x21, 0x7d, 0x91, 0x57, 0x6b, 0xc4, 0x67, 0xd1, 0xb9, 0x46, 0xda, 0x22, 0xf4, 0x72, 0x2e, 0x3e, 0x22, 0x27, 0xb2, 0x60, 0xa6, 0x9f, 0xe2, 0xac, 0xb2, 0x9a, 0x34, 0x89, 0xd2, 0x1f, 0xec, 0x06, 0x89, 0x54, 0x21, 0xaa, 0x8d, 0x9e, 0xee, 0x38, 0x72, 0x3a, 0x93, 0x1b, 0x41, 0x7e, 0x5d, 0x93, 0x63, 0xc9, 0xa5, 0xff, 0x35, 0x63, 0x8f, 0x09, 0xf1, 0xfd, 0x7c, 0x02, 0x00, 0x1b, 0x19, 0xce, 0x09, 0x35,\n\t0x70, 0xf1, 0xef, 0xf4, 0x15, 0x31, 0xc2, 0x8b, 0xac, 0x07, 0x12, 0x56, 0xbc, 0x86, 0x06, 0x40, 0xc9, 0xcb, 0xed, 0x24, 0x5b, 0x43, 0x96, 0xea, 0xee, 0x85, 0x4e, 0x4b, 0x97, 0x2d, 0xf7, 0xb6, 0x8a, 0xbb, 0xcd, 0x39, 0x9d, 0xa5, 0x0a, 0xe8, 0x5c, 0xc9, 0xf6, 0x49, 0x45, 0x24, 0x45, 0xc9, 0x47, 0x95, 0x00, 0xe1, 0x5b, 0x11, 0xae, 0x84, 0x1c, 0x97, 0x30, 0x24, 0xca, 0xaa, 0x54, 0xa9, 0x49, 0x2e, 0xa4, 0xb4, 0x15, 0xf0, 0xe3, 0x52, 0xc9, 0x76, 0x52, 0x43, 0x43, 0x42, 0x45, 0x12, 0xaa, 0xb9, 0xe5, 0x7b, 0x13, 0xd0, 0xd5, 0xe5, 0xfb, 0x26, 0xab, 0x33, 0xdd, 0x18, 0x15, 0x93, 0xdf, 0x0d, 0xa7, 0x70, 0xa2, 0xbe, 0xcc, 0xb8, 0x84, 0x45, 0x0a, 0x64, 0xbb, 0xc2, 0x31, 0x82, 0x3e, 0xff, 0xba, 0x21, 0xe8, 0x51, 0x75, 0xb6, 0xb5, 0xae, 0x6a, 0x46, 0x99, 0x3f, 0xe1, 0xa0, 0xcf,\n\t0xeb, 0x76, 0x1a, 0x74, 0x6a, 0x95, 0x52, 0x21, 0x66, 0xa0, 0x0c, 0xd6, 0x6b, 0x30, 0xc6, 0xc5, 0xf5, 0x41, 0xa3, 0xf7, 0x81, 0x23, 0xba, 0x78, 0x60, 0x45, 0x6f, 0x66, 0xcd, 0xed, 0xda, 0xb4, 0xa9, 0x96, 0xcb, 0xd3, 0xe0, 0x07, 0x36, 0x5d, 0xb5, 0xec, 0x50, 0x83, 0xef, 0x97, 0xd0, 0x68, 0xc4, 0x9f, 0x55, 0x65, 0x47, 0xfc, 0x3b, 0x02, 0xfb, 0x3b, 0x7f, 0xbc, 0x97, 0x1f, 0x7f, 0x50, 0x9e, 0x3f, 0x0b, 0xf0, 0x1e, 0x7f, 0x6c, 0xe1, 0x4f, 0xd4, 0x15, 0x1c, 0x23, 0xac, 0x22, 0x0e, 0x26, 0xe5, 0x21, 0xb8, 0xe3, 0x01, 0x2b, 0xae, 0x86, 0xc7, 0x0e, 0x55, 0x80, 0xa0, 0xc4, 0xa4, 0x98, 0xc2, 0x09, 0xdc, 0x62, 0x8a, 0xe0, 0xf2, 0xfe, 0x45, 0xfc, 0xa1, 0x5e, 0x36, 0xd3, 0xbb, 0x68, 0x51, 0x43, 0x0e, 0xdd, 0x8f, 0xa3, 0x6d, 0x39, 0x8c, 0x04, 0xa3, 0xd0, 0x92, 0x0c, 0xfa, 0xfd,\n\t0x5e, 0x7f, 0x88, 0x2d, 0x2e, 0x9a, 0x89, 0x2c, 0x8a, 0xf3, 0x45, 0x8b, 0x39, 0x61, 0x71, 0xa5, 0xb5, 0xec, 0xe9, 0x33, 0xa8, 0x3f, 0x74, 0x79, 0x4b, 0x59, 0x41, 0x71, 0x6d, 0xe1, 0xe8, 0x1d, 0xb5, 0x9b, 0x37, 0x24, 0x87, 0x9b, 0xa2, 0x05, 0x06, 0x87, 0xd4, 0x3b, 0xf4, 0xad, 0x43, 0xeb, 0xce, 0x8c, 0x97, 0xad, 0x73, 0x38, 0xa5, 0xc6, 0x60, 0xcf, 0x9a, 0xc9, 0x9a, 0xfa, 0x6d, 0x7d, 0xa5, 0xcd, 0x17, 0xff, 0xf8, 0x2c, 0x19, 0xa7, 0x1d, 0xd1, 0xe6, 0x50, 0xa0, 0xca, 0xab, 0x69, 0x6b, 0x48, 0xdf, 0xb2, 0xef, 0x16, 0x77, 0xd0, 0x6d, 0x52, 0x25, 0x57, 0xaf, 0xae, 0x9e, 0xbd, 0x30, 0x4c, 0x9e, 0xd5, 0xd9, 0x46, 0x7d, 0xd5, 0x01, 0x83, 0xa7, 0x75, 0xa6, 0xad, 0x7e, 0xcf, 0x48, 0x35, 0xcd, 0xda, 0x3e, 0x03, 0x0b, 0x6f, 0x53, 0x3f, 0xc3, 0x67, 0xd2, 0x41, 0xe2, 0x31, 0xee,\n\t0x4c, 0xda, 0x07, 0x08, 0xda, 0x90, 0x3d, 0x93, 0x86, 0x97, 0x8c, 0x21, 0x7b, 0x26, 0x6d, 0xc5, 0x05, 0x8a, 0xd1, 0x61, 0xb0, 0x88, 0x21, 0x17, 0x25, 0xfa, 0xb3, 0x87, 0x86, 0x76, 0x4e, 0x70, 0xcb, 0x90, 0x01, 0xb8, 0x17, 0x7d, 0x9c, 0x4f, 0x04, 0x00, 0x95, 0x8d, 0x5a, 0xad, 0x0e, 0xaa, 0x03, 0x21, 0x9f, 0x0f, 0xb1, 0x01, 0x14, 0xe4, 0xb3, 0x01, 0x68, 0x17, 0x23, 0x86, 0xaa, 0x12, 0x31, 0xca, 0x5c, 0xb6, 0x77, 0x55, 0x16, 0xda, 0x82, 0xd8, 0x00, 0x04, 0x88, 0x96, 0xcd, 0x67, 0xe3, 0x0a, 0x59, 0x98, 0xa2, 0x1a, 0xb3, 0xa0, 0x95, 0x9f, 0xde, 0x90, 0x08, 0x31, 0x40, 0x6d, 0x0d, 0x9d, 0x41, 0x56, 0x2e, 0x98, 0xf7, 0x84, 0x93, 0xcb, 0x23, 0x2f, 0xb9, 0x70, 0xba, 0x22, 0xc8, 0xa4, 0xb6, 0xa2, 0xb7, 0x41, 0x5a, 0x73, 0x11, 0x53, 0x87, 0x75, 0xb9, 0x8f, 0xf7, 0xe4, 0x10,\n\t0x79, 0xcc, 0xae, 0x48, 0xe4, 0x31, 0xbb, 0x22, 0x91, 0xc7, 0x68, 0x52, 0xea, 0xc9, 0x30, 0x79, 0x70, 0x35, 0x5a, 0x17, 0xa5, 0x3e, 0x67, 0x99, 0x3c, 0x70, 0xfe, 0x73, 0xfc, 0xd8, 0x50, 0xed, 0x78, 0x93, 0xe7, 0xe2, 0x99, 0xb6, 0x3d, 0x51, 0x55, 0xfc, 0xae, 0xcd, 0xb3, 0x9f, 0xdc, 0xdb, 0x50, 0x35, 0x7d, 0xef, 0xba, 0x9d, 0x97, 0x93, 0x5a, 0x59, 0xf8, 0xc0, 0x81, 0xb0, 0x0c, 0x78, 0xda, 0x7a, 0xc3, 0xeb, 0xce, 0x6d, 0xfa, 0xd2, 0x6b, 0x15, 0x4d, 0x67, 0x1a, 0xdb, 0x06, 0x2e, 0x7c, 0x7d, 0xef, 0xf1, 0xaf, 0x9f, 0x6c, 0x9d, 0xe8, 0x3d, 0x10, 0xa4, 0xde, 0x11, 0xca, 0x04, 0xe7, 0x77, 0x26, 0x78, 0x2e, 0x1d, 0x4d, 0xc9, 0xe2, 0xfc, 0xce, 0x12, 0x41, 0x7e, 0x27, 0x9d, 0xcd, 0xef, 0xf4, 0x2c, 0x9f, 0xb2, 0x99, 0xcb, 0x74, 0xf2, 0x01, 0x0d, 0xb1, 0x98, 0x56, 0xce, 0xeb,\n\t0x5c, 0x4c, 0x7e, 0x82, 0xf2, 0x3a, 0x7d, 0x37, 0x95, 0xd7, 0x89, 0x85, 0x76, 0xf3, 0x99, 0x9d, 0x1c, 0x19, 0xca, 0xcd, 0x25, 0x77, 0x22, 0x66, 0x94, 0xbc, 0x6c, 0x6a, 0xb4, 0x3f, 0xc5, 0xe0, 0x1a, 0xdc, 0x0f, 0x75, 0x53, 0x09, 0xb1, 0x23, 0x29, 0xb3, 0x42, 0x53, 0xa0, 0x04, 0x67, 0xfa, 0xb3, 0x62, 0xf3, 0xf1, 0xb4, 0x50, 0x44, 0x2e, 0x2b, 0xd4, 0x6e, 0x21, 0x2b, 0x94, 0xed, 0x26, 0x9a, 0x21, 0x90, 0x5e, 0x52, 0x8a, 0xa9, 0x47, 0xf0, 0xd4, 0xc9, 0x83, 0xde, 0x67, 0xf2, 0x40, 0x29, 0xa1, 0x34, 0xf6, 0xdd, 0x14, 0xcd, 0xc8, 0xae, 0xcb, 0xcd, 0x5f, 0x55, 0xb0, 0xac, 0x22, 0xe7, 0x10, 0xab, 0x48, 0x05, 0x66, 0x15, 0x41, 0x99, 0x26, 0xed, 0x77, 0x5d, 0x3b, 0xba, 0xf7, 0xab, 0xf7, 0xf4, 0xb5, 0x27, 0xe1, 0xfc, 0x59, 0xbd, 0x10, 0xa3, 0x3e, 0x8a, 0x75, 0x70, 0x07, 0x71,\n\t0x32, 0xa9, 0xeb, 0x00, 0x94, 0xc8, 0x09, 0x08, 0x50, 0x8b, 0x71, 0x73, 0x55, 0x80, 0xe9, 0xc8, 0x64, 0x19, 0x71, 0xc5, 0x8a, 0xb2, 0x00, 0x05, 0x4e, 0xb9, 0x66, 0x0a, 0xd9, 0xe1, 0x77, 0xbe, 0x99, 0x86, 0xf8, 0xad, 0x8d, 0x80, 0x68, 0x5b, 0x15, 0x29, 0xf1, 0x15, 0x9a, 0x8d, 0x18, 0xe8, 0xa9, 0x64, 0xb1, 0x07, 0x7e, 0x0e, 0x7b, 0x80, 0x81, 0x5b, 0x40, 0x08, 0xe7, 0x32, 0x99, 0x73, 0xc5, 0x20, 0x00, 0xc9, 0x67, 0x8a, 0x1f, 0x91, 0xed, 0x33, 0x1b, 0x23, 0x45, 0xe6, 0x90, 0xbf, 0x10, 0x6e, 0xa8, 0xc0, 0x24, 0x81, 0x82, 0xf2, 0xc5, 0xbb, 0xa1, 0xa0, 0xba, 0x03, 0xcd, 0xf5, 0x96, 0xda, 0x8e, 0x35, 0xe5, 0x0d, 0x23, 0xb5, 0xf6, 0x92, 0xa1, 0xe3, 0x83, 0x86, 0xa0, 0x5e, 0x0c, 0xf7, 0x5e, 0xb7, 0xbb, 0x47, 0xa2, 0x96, 0xae, 0xda, 0xd1, 0x13, 0x6e, 0x3a, 0xf2, 0xc2, 0x81,\n\t0x5d, 0x97, 0x93, 0x27, 0xdb, 0x13, 0x81, 0x98, 0xa1, 0x7c, 0xa0, 0x01, 0xce, 0xdc, 0x97, 0x58, 0x56, 0x96, 0xa9, 0xfb, 0xd6, 0x1f, 0x7b, 0x34, 0x34, 0xb2, 0xbf, 0xcd, 0xee, 0x6b, 0x58, 0x53, 0x56, 0xb3, 0xa9, 0x23, 0x44, 0x91, 0xde, 0x9e, 0x62, 0xab, 0x86, 0x56, 0xd4, 0xef, 0x88, 0xda, 0x46, 0x6f, 0x7b, 0x64, 0x0c, 0x91, 0xb4, 0x40, 0x71, 0x62, 0x3c, 0xd1, 0x45, 0xfa, 0x3f, 0x30, 0x0e, 0xb4, 0x92, 0xb8, 0x9c, 0x54, 0x84, 0x04, 0x50, 0x22, 0x2e, 0xa5, 0x9a, 0x65, 0x05, 0x5a, 0x04, 0xdc, 0x59, 0x92, 0xab, 0x71, 0xb9, 0xc6, 0x2b, 0xa1, 0x82, 0x66, 0x3e, 0x18, 0x15, 0x84, 0x40, 0x41, 0xfa, 0xbf, 0x05, 0x14, 0x84, 0xa0, 0x9f, 0x42, 0x44, 0x90, 0x10, 0x9f, 0xb8, 0x14, 0x22, 0x08, 0xe1, 0x14, 0xb3, 0x60, 0xa0, 0x2c, 0x20, 0x71, 0xfe, 0x23, 0x2c, 0x18, 0xe8, 0xab, 0x59,\n\t0x30, 0x10, 0x82, 0x78, 0xbe, 0xbb, 0x30, 0x38, 0xa0, 0x46, 0xc0, 0x0f, 0xcc, 0x6b, 0xc3, 0x38, 0x39, 0x7d, 0xf6, 0x00, 0xa7, 0xcf, 0x50, 0x09, 0xe6, 0x04, 0x20, 0xc4, 0x01, 0x2c, 0x48, 0xac, 0xcf, 0xcc, 0x80, 0xce, 0xb9, 0xc5, 0x33, 0x99, 0x0a, 0x32, 0x67, 0xf9, 0xac, 0x22, 0x6e, 0xb5, 0xa1, 0xed, 0x0d, 0x17, 0x65, 0x2c, 0x21, 0x28, 0x5a, 0x4c, 0x53, 0x62, 0x41, 0xe2, 0xac, 0xa0, 0x29, 0x42, 0x69, 0xf3, 0x86, 0xc3, 0x1e, 0x04, 0xf6, 0x94, 0x87, 0x7c, 0x5e, 0x8f, 0x3f, 0xb8, 0x94, 0xa8, 0x16, 0xab, 0xa4, 0x25, 0x76, 0xc0, 0x5c, 0x61, 0x71, 0xbc, 0x24, 0x26, 0x91, 0x45, 0xa5, 0x0c, 0xf9, 0x07, 0xd7, 0x2e, 0xe6, 0xc6, 0x11, 0x8a, 0x8b, 0x32, 0x09, 0xf5, 0xd2, 0xfb, 0x5f, 0xc8, 0x85, 0xc6, 0x12, 0xf9, 0xf9, 0x70, 0x47, 0xae, 0xba, 0x11, 0x6d, 0x34, 0x37, 0xd1, 0x82,\n\t0x04, 0x43, 0x8a, 0x48, 0x46, 0x34, 0x87, 0x0b, 0x8e, 0x23, 0xdc, 0xe5, 0x14, 0xaf, 0x7f, 0x31, 0xd2, 0x32, 0x6b, 0x3e, 0xdd, 0x54, 0x4b, 0x4c, 0x99, 0x63, 0x91, 0x49, 0x09, 0x02, 0x1d, 0xc1, 0x20, 0x74, 0xb6, 0xb4, 0x54, 0x56, 0x8a, 0x00, 0x54, 0x6c, 0x7d, 0x72, 0x8e, 0xc5, 0x53, 0xcc, 0x16, 0x65, 0xcf, 0x61, 0x42, 0xcb, 0x22, 0x53, 0xaa, 0x28, 0xa5, 0xfe, 0xde, 0x23, 0x75, 0x13, 0x49, 0xcf, 0x9d, 0x36, 0x7d, 0x72, 0xdf, 0x47, 0x27, 0xe6, 0x9e, 0x3b, 0xd2, 0xd2, 0x75, 0xf2, 0x85, 0x6d, 0x55, 0x7b, 0xb7, 0x4f, 0xfa, 0xaa, 0x95, 0x16, 0x5d, 0xb4, 0x6d, 0xb2, 0xb9, 0x6d, 0x6e, 0x20, 0x42, 0x91, 0xbb, 0x8e, 0x5f, 0x08, 0x75, 0x6e, 0xae, 0x3d, 0xec, 0x2a, 0xdd, 0x75, 0x65, 0x7f, 0x43, 0xdf, 0xd9, 0x97, 0xb6, 0x9f, 0x7a, 0xfd, 0x5c, 0x87, 0x2e, 0xd0, 0x50, 0x84, 0x51,\n\t0x28, 0x25, 0xeb, 0xef, 0x1a, 0xfb, 0xff, 0x65, 0x3e, 0x20, 0x49, 0xb4, 0xc3, 0x35, 0x72, 0x1a, 0xeb, 0xec, 0x3e, 0xe2, 0xdb, 0xec, 0xc4, 0xd7, 0x35, 0x27, 0xa0, 0x87, 0x94, 0x2c, 0xb6, 0x98, 0x68, 0x11, 0x52, 0xbc, 0x80, 0x45, 0x42, 0x67, 0x6e, 0x8a, 0xb9, 0x9b, 0xa3, 0xbc, 0x88, 0x68, 0xa8, 0x2f, 0x68, 0x34, 0xe2, 0x5c, 0x65, 0x14, 0x3e, 0x85, 0x77, 0x77, 0xe6, 0x84, 0x60, 0x67, 0xc6, 0x72, 0xbc, 0x99, 0xd6, 0x7b, 0x58, 0x35, 0x04, 0xd7, 0x15, 0xc5, 0x56, 0xa2, 0xa4, 0x10, 0xb2, 0x77, 0xa5, 0xe6, 0x58, 0x0d, 0x15, 0x07, 0xbc, 0x25, 0xa5, 0x45, 0x3e, 0x5c, 0xdc, 0x3a, 0x93, 0x55, 0x1a, 0x64, 0x78, 0x1d, 0x24, 0xe6, 0xf3, 0xf3, 0x22, 0x34, 0x72, 0x8a, 0xfc, 0xec, 0x24, 0xcb, 0x6e, 0x89, 0xe6, 0x2a, 0xb3, 0xc9, 0x01, 0x32, 0x8a, 0xe9, 0x5d, 0xe0, 0xac, 0x1f, 0x6f,\n\t0xea, 0xdc, 0xd9, 0xe9, 0x87, 0xda, 0xfb, 0x90, 0xa3, 0x2f, 0x56, 0x3f, 0x10, 0x35, 0xf4, 0xd2, 0x74, 0xcb, 0xd1, 0xe7, 0xe6, 0xba, 0x0f, 0x6f, 0x68, 0x8f, 0x98, 0xf4, 0x76, 0xf2, 0xa4, 0xe7, 0xa1, 0xed, 0xcd, 0x1b, 0xb0, 0xc4, 0xab, 0xbc, 0x68, 0x4c, 0xfa, 0xee, 0xd9, 0x3f, 0x6a, 0xfb, 0x81, 0x56, 0x56, 0x52, 0xe5, 0x2e, 0x94, 0x43, 0x85, 0x05, 0x26, 0x7c, 0xbd, 0xcd, 0x45, 0x15, 0x13, 0xa7, 0xd7, 0x28, 0x0b, 0x14, 0x43, 0x2a, 0x73, 0xb0, 0xae, 0xdd, 0xad, 0xb1, 0xd9, 0x6b, 0x5d, 0x68, 0x38, 0xbc, 0xf5, 0xfd, 0xa3, 0x63, 0xc5, 0x76, 0xa3, 0xec, 0x57, 0x3b, 0xb6, 0xa2, 0x01, 0xc1, 0x3b, 0x6a, 0xb0, 0x77, 0x6f, 0x77, 0x97, 0xdf, 0x68, 0xaf, 0x8f, 0xb5, 0xa9, 0x30, 0x59, 0x2c, 0x80, 0x7a, 0xec, 0xcf, 0xd4, 0x38, 0xe6, 0x86, 0xe8, 0x4e, 0x76, 0xc0, 0xcd, 0x44, 0x1c,\n\t0x85, 0x4a, 0xcc, 0xcb, 0x9e, 0x9e, 0xa3, 0x5a, 0x50, 0x04, 0x34, 0x93, 0x50, 0x05, 0x2d, 0x06, 0xce, 0x3e, 0x92, 0xa0, 0x18, 0x32, 0x4b, 0x41, 0xba, 0x3b, 0xc3, 0x3e, 0x0a, 0x15, 0x50, 0x5d, 0x4d, 0xc0, 0x1b, 0xf0, 0x40, 0xe5, 0x22, 0xc9, 0xa0, 0x74, 0xf9, 0xfd, 0x10, 0x97, 0xf6, 0x13, 0x2d, 0x95, 0x59, 0x9d, 0x10, 0x6c, 0x89, 0x94, 0x45, 0xae, 0x57, 0xa9, 0xfc, 0x55, 0x03, 0x35, 0xf1, 0xfe, 0xb8, 0xf5, 0xd6, 0x5d, 0xfb, 0xf6, 0x1d, 0x39, 0xe4, 0xaa, 0x59, 0x13, 0x6b, 0x5a, 0x5b, 0x17, 0xc2, 0x46, 0xc3, 0xc8, 0xe6, 0xd9, 0xf2, 0xc1, 0x4b, 0x7b, 0x9a, 0x67, 0x87, 0x4a, 0x9b, 0x82, 0xba, 0x8a, 0xa9, 0x87, 0xa6, 0xf6, 0x7d, 0xaa, 0x86, 0x5a, 0xa5, 0x95, 0x9b, 0xed, 0x66, 0x53, 0x20, 0xe6, 0x48, 0x0e, 0x9c, 0x18, 0xee, 0xf0, 0x37, 0x45, 0xac, 0x3c, 0x2d, 0x99, 0xb6,\n\t0xa8, 0x7f, 0x6f, 0xc7, 0xba, 0xc3, 0x6e, 0x5d, 0x65, 0x7d, 0xb3, 0x2b, 0x31, 0xd5, 0x53, 0xda, 0x9a, 0xe0, 0xeb, 0x2f, 0xfc, 0x4f, 0xfa, 0xab, 0xb4, 0x94, 0x18, 0x03, 0x45, 0x49, 0x7d, 0x3f, 0x90, 0xc8, 0xc6, 0xcc, 0xa4, 0x58, 0xaa, 0x06, 0x24, 0x34, 0xdf, 0x18, 0x9a, 0xe6, 0xf4, 0x52, 0x82, 0x90, 0x4a, 0xc4, 0x12, 0x29, 0xd2, 0xbf, 0x1c, 0x29, 0x94, 0x98, 0x10, 0x41, 0xbb, 0x71, 0x0a, 0x9f, 0x6d, 0xd1, 0xa8, 0xec, 0xba, 0x44, 0xc2, 0x67, 0x86, 0x72, 0xd0, 0x70, 0xd6, 0x52, 0x57, 0xfc, 0x9d, 0xbd, 0xb3, 0x66, 0xec, 0xdf, 0xfb, 0xb7, 0x93, 0x0d, 0x99, 0x8e, 0x40, 0x4c, 0x88, 0xd1, 0x89, 0x5b, 0xde, 0x17, 0x10, 0x2b, 0xf5, 0x47, 0x0e, 0x82, 0x69, 0xcd, 0x40, 0x4f, 0x77, 0x47, 0x5b, 0x53, 0x43, 0x7d, 0x6d, 0x65, 0x45, 0x59, 0x29, 0xf4, 0x41, 0x3d, 0x41, 0x39, 0x02,\n\t0xb5, 0xa3, 0x09, 0x8c, 0x15, 0x89, 0xc0, 0xf3, 0x6c, 0x40, 0xb6, 0x8d, 0x90, 0x6c, 0x4c, 0x08, 0xee, 0x43, 0xa9, 0xe7, 0x19, 0x5b, 0x59, 0xc0, 0x2b, 0xca, 0x22, 0x18, 0xab, 0xa8, 0x6f, 0xca, 0x65, 0x96, 0x80, 0x0d, 0xcf, 0x65, 0x91, 0xde, 0xd1, 0x1b, 0x6b, 0x80, 0x8b, 0xe0, 0x5f, 0x18, 0x39, 0x53, 0xbe, 0xba, 0xc6, 0xd5, 0xb6, 0xef, 0x52, 0x7f, 0xd9, 0xcc, 0xa6, 0x11, 0x2f, 0xd4, 0xb5, 0xfa, 0x50, 0xed, 0x60, 0x63, 0x7c, 0x6d, 0xad, 0xeb, 0xe0, 0xd1, 0x7d, 0xfb, 0x76, 0xdd, 0x6a, 0x8d, 0xf7, 0x57, 0xd6, 0xae, 0xae, 0xf6, 0xab, 0x54, 0x7a, 0x79, 0x49, 0xcd, 0xe5, 0x43, 0x1b, 0x1f, 0x98, 0xaa, 0x00, 0xe0, 0xc3, 0xe4, 0xbc, 0xa5, 0xa0, 0xce, 0x5a, 0xe2, 0x86, 0x93, 0xa8, 0xa0, 0x16, 0x2e, 0x86, 0xfa, 0x76, 0xb7, 0x6a, 0x35, 0x49, 0x93, 0xea, 0xb2, 0xa6, 0xfe, 0xb2,\n\t0x8e, 0xbd, 0x7d, 0x45, 0xda, 0x40, 0x7d, 0x71, 0x87, 0x1e, 0x4e, 0x0e, 0x6b, 0xa4, 0xd1, 0xdf, 0x39, 0x74, 0x62, 0xa0, 0xd9, 0x1e, 0x0b, 0x98, 0xe0, 0xe4, 0x91, 0x6b, 0x7b, 0x12, 0xad, 0xa5, 0xa9, 0xa9, 0xb8, 0x44, 0x25, 0xa9, 0xc7, 0xfc, 0x3b, 0xd0, 0x57, 0xb1, 0xc0, 0x35, 0xe1, 0x24, 0xaa, 0x51, 0xe5, 0x13, 0x34, 0x19, 0x9c, 0x22, 0x01, 0x01, 0xef, 0x12, 0xfc, 0x81, 0x2b, 0x36, 0xc0, 0x5b, 0x92, 0x1e, 0x15, 0xb7, 0x09, 0xf8, 0x1c, 0x36, 0xcc, 0xbe, 0xea, 0x04, 0x4e, 0xb6, 0x9e, 0x70, 0x42, 0xc8, 0xe7, 0x26, 0x48, 0x65, 0x65, 0x90, 0x46, 0x11, 0xe5, 0x40, 0x59, 0xa1, 0x8c, 0xc9, 0x07, 0xc6, 0x67, 0x2d, 0x55, 0x23, 0x4d, 0x13, 0x77, 0x0e, 0xfa, 0xfd, 0x03, 0x27, 0xc6, 0x93, 0xe3, 0x75, 0x36, 0x73, 0x45, 0x5f, 0xe2, 0x51, 0xb0, 0x6d, 0x68, 0xfa, 0x9f, 0xfe, 0xe1,\n\t0xfc, 0x0f, 0xee, 0xe9, 0x68, 0x87, 0xfa, 0x78, 0xd7, 0xa3, 0x9b, 0x4b, 0xb5, 0xc1, 0x24, 0x39, 0xdc, 0xd3, 0x64, 0x8f, 0x05, 0x2d, 0x15, 0x1b, 0xce, 0x8f, 0x8c, 0xdc, 0xb3, 0xa9, 0xb2, 0xa0, 0xb4, 0x31, 0xe0, 0xad, 0x2f, 0xb5, 0x9e, 0xac, 0x71, 0x9f, 0x9e, 0xb8, 0xff, 0x61, 0x9e, 0x90, 0xa7, 0xac, 0x6f, 0xaa, 0xd2, 0xd9, 0x54, 0x1b, 0xc5, 0x3a, 0x7b, 0x4d, 0xfa, 0x21, 0xfa, 0xd7, 0xcc, 0x33, 0xd0, 0xae, 0xe9, 0x22, 0xbe, 0xcc, 0x71, 0x52, 0x22, 0xbb, 0xa6, 0x0b, 0x10, 0xd2, 0x1a, 0x6c, 0xc4, 0x14, 0x01, 0x46, 0x8c, 0x39, 0x29, 0x91, 0x6d, 0x93, 0x7f, 0x9b, 0xb3, 0x6f, 0x2a, 0x08, 0x11, 0x9c, 0x86, 0x22, 0xf1, 0x5c, 0xae, 0x9d, 0x83, 0x4f, 0x7c, 0xb1, 0x9d, 0x83, 0x4f, 0x93, 0x70, 0x65, 0x83, 0x6c, 0x12, 0x6b, 0x0d, 0x34, 0x78, 0xa4, 0x34, 0x25, 0x9d, 0xe3, 0x3b,\n\t0xe7, 0x18, 0x3e, 0x2b, 0xf5, 0x45, 0xa9, 0x2e, 0x6d, 0x41, 0xaf, 0x3f, 0x88, 0x0d, 0x20, 0x1c, 0x5e, 0xfc, 0x20, 0x03, 0x48, 0x98, 0x75, 0xc8, 0x0a, 0x3e, 0xdf, 0x92, 0xa4, 0x0a, 0x58, 0x3c, 0x39, 0xdc, 0x17, 0x07, 0x8f, 0x26, 0x3c, 0x6d, 0xdb, 0xbb, 0x2b, 0x57, 0x67, 0xf8, 0x55, 0x2a, 0x9b, 0x8f, 0x3c, 0xbf, 0xef, 0x8e, 0xab, 0xf5, 0x11, 0x89, 0x45, 0xaf, 0x2f, 0xaa, 0x5b, 0x0b, 0x95, 0x79, 0x97, 0xaf, 0xe9, 0xe2, 0xec, 0xc4, 0xc5, 0x2d, 0x55, 0x19, 0x03, 0xa9, 0xa1, 0xf2, 0xcb, 0x9f, 0x1f, 0x3f, 0x3d, 0x8c, 0x0c, 0xa4, 0x58, 0x13, 0x26, 0x46, 0x44, 0x94, 0x1a, 0x03, 0x03, 0xef, 0xbf, 0x36, 0xfe, 0xd8, 0xde, 0x64, 0x57, 0x02, 0x27, 0x61, 0xd8, 0x8b, 0xba, 0xa7, 0x6b, 0x0e, 0xf6, 0x0c, 0xb6, 0x9e, 0xf8, 0xca, 0x6d, 0x3b, 0x5f, 0x39, 0xdf, 0x5f, 0x9f, 0xc0, 0x3a,\n\t0xaa, 0x77, 0xe1, 0x2f, 0xd4, 0xf7, 0x68, 0x8a, 0x28, 0x23, 0x76, 0x25, 0x55, 0x0e, 0xa8, 0x96, 0x10, 0x15, 0xb6, 0x1c, 0xbb, 0xc9, 0xdc, 0x8c, 0xe4, 0x32, 0xd4, 0x36, 0xf1, 0x11, 0x77, 0x84, 0xc0, 0x16, 0x5a, 0x0d, 0x2b, 0x35, 0xc0, 0xd6, 0x02, 0x9c, 0x91, 0x41, 0x3f, 0x2a, 0x47, 0x2b, 0x93, 0x32, 0x34, 0x51, 0x06, 0xca, 0xd8, 0x52, 0xc2, 0x09, 0xbe, 0xfe, 0x86, 0x56, 0x48, 0x24, 0x69, 0xca, 0x2b, 0xd4, 0x41, 0x8e, 0xb6, 0x4c, 0x16, 0xdf, 0xa1, 0x35, 0x82, 0x81, 0xc0, 0xda, 0xc9, 0x9d, 0x4d, 0x7b, 0x5e, 0x3e, 0xd7, 0xd3, 0x7d, 0xfe, 0xda, 0xe1, 0x63, 0x57, 0x9b, 0x12, 0xca, 0x90, 0xc5, 0x1c, 0xa9, 0xe9, 0x28, 0xeb, 0xb9, 0x6d, 0x38, 0x52, 0x3e, 0x7a, 0xdb, 0xbd, 0x66, 0xc3, 0x4b, 0x06, 0xcd, 0xce, 0xf4, 0x94, 0x3d, 0x6c, 0x53, 0xf6, 0x9e, 0xff, 0xea, 0xbe, 0x7d,\n\t0x5f, 0x3d, 0xd7, 0xd3, 0x55, 0x3f, 0x6c, 0x90, 0xa9, 0x55, 0x56, 0xbd, 0xa2, 0x62, 0xe2, 0xe4, 0xc0, 0xba, 0x73, 0x1b, 0xca, 0x09, 0x72, 0xe1, 0xcd, 0xf4, 0x25, 0xea, 0xf7, 0xd4, 0x3b, 0x84, 0x1a, 0xda, 0xd4, 0x81, 0xa4, 0x37, 0xe1, 0x57, 0x67, 0xea, 0x79, 0x66, 0xe9, 0xdb, 0xe6, 0x40, 0x4f, 0x3c, 0x16, 0x0a, 0xd8, 0x0a, 0x82, 0x34, 0x4b, 0x48, 0xc4, 0x0d, 0x32, 0xd4, 0x37, 0x65, 0xa0, 0x2a, 0x37, 0x21, 0xb7, 0x09, 0x08, 0xaa, 0x08, 0xb1, 0x38, 0x53, 0xf0, 0xba, 0xd1, 0x22, 0x33, 0xba, 0x8c, 0xde, 0xb0, 0xd5, 0xe0, 0xb9, 0x6c, 0x74, 0xea, 0x24, 0xee, 0x86, 0xb1, 0xba, 0xc6, 0xb1, 0x7a, 0xa7, 0x44, 0xe7, 0x34, 0x35, 0xa6, 0xb7, 0x5d, 0x36, 0x86, 0x10, 0x7b, 0xa7, 0x94, 0x12, 0x2b, 0x80, 0x58, 0x62, 0x37, 0x5c, 0x4e, 0xef, 0x28, 0x2a, 0x19, 0x74, 0x19, 0x83, 0x4e,\n\t0x5d, 0x55, 0x2c, 0xb8, 0xba, 0x68, 0x95, 0xb9, 0x68, 0x55, 0x75, 0xa5, 0x2d, 0x31, 0xd1, 0x1a, 0x0c, 0xb7, 0x4d, 0xc4, 0x6c, 0xb1, 0x9a, 0x96, 0xa2, 0xdb, 0xc8, 0x77, 0x4d, 0xda, 0xf9, 0xbf, 0xca, 0x4d, 0x72, 0xb3, 0x89, 0x94, 0x6a, 0x4d, 0xf3, 0x52, 0x82, 0xe5, 0xfa, 0xff, 0x33, 0x4d, 0xd1, 0x34, 0xb4, 0x7f, 0x52, 0xa8, 0xfa, 0x44, 0x67, 0x85, 0x5b, 0x89, 0x73, 0x8e, 0x69, 0x7c, 0x38, 0xc7, 0xb0, 0x1c, 0x75, 0xd9, 0x11, 0xf1, 0x97, 0x96, 0xfa, 0x8b, 0xfd, 0x38, 0x32, 0x83, 0xde, 0xca, 0xc4, 0xbf, 0x14, 0x97, 0x56, 0xc2, 0x12, 0x94, 0x88, 0x29, 0xb3, 0x13, 0x08, 0x4c, 0xb8, 0x26, 0x40, 0xe5, 0x72, 0x95, 0xb1, 0x28, 0x4f, 0xf0, 0xaf, 0x46, 0x63, 0xb9, 0xd7, 0x59, 0x6e, 0x36, 0x04, 0xaf, 0x98, 0xca, 0x6a, 0x3b, 0x23, 0x81, 0x90, 0x16, 0x78, 0xbd, 0xb1, 0xb0, 0x5b,\n\t0xf3, 0x72, 0x8b, 0xd7, 0xee, 0x69, 0x5a, 0x5f, 0x53, 0xbb, 0xbe, 0xc1, 0xed, 0x2e, 0x6c, 0x7a, 0x45, 0xe3, 0x09, 0x55, 0x16, 0x7a, 0x49, 0x6d, 0x30, 0x10, 0xe9, 0xac, 0x2d, 0x33, 0x9d, 0x95, 0x6b, 0x24, 0x22, 0x8d, 0x1c, 0xb4, 0x7b, 0x62, 0x96, 0x60, 0xac, 0xa8, 0xd8, 0x9e, 0x70, 0xd5, 0x93, 0x94, 0xab, 0xcc, 0xad, 0x55, 0x18, 0x6c, 0xea, 0x4e, 0xb9, 0xc9, 0x67, 0x49, 0xff, 0x71, 0x63, 0x6c, 0x63, 0x51, 0x6c, 0xb4, 0xd9, 0x1f, 0x48, 0x0e, 0x95, 0x95, 0x4d, 0x95, 0x6f, 0x00, 0x26, 0x8b, 0xd7, 0x2c, 0xef, 0x54, 0xdb, 0x0c, 0x0a, 0xad, 0xbb, 0xcc, 0xf5, 0x1d, 0x95, 0x53, 0xaf, 0x77, 0xaa, 0xd0, 0x3c, 0x3e, 0x9e, 0x7e, 0x9a, 0xfa, 0x31, 0x1c, 0x53, 0x23, 0xe2, 0xc9, 0x36, 0x60, 0xc0, 0x38, 0x3a, 0xaf, 0x40, 0x45, 0x0f, 0x48, 0x01, 0xf1, 0x47, 0x16, 0xb9, 0x6c, 0x24,\n\t0x8c, 0x5e, 0xa3, 0x97, 0xc3, 0x80, 0x66, 0xb2, 0xd0, 0x78, 0xb7, 0xae, 0x4a, 0x4b, 0xfd, 0x98, 0x87, 0x29, 0x5f, 0x9f, 0xde, 0x92, 0x3a, 0x51, 0x43, 0xbd, 0xf3, 0xde, 0x0b, 0xe0, 0xc7, 0x2d, 0xfd, 0x08, 0x9f, 0x8c, 0xc8, 0x9b, 0x77, 0x1d, 0xee, 0x68, 0x24, 0x7f, 0x9b, 0xc1, 0x87, 0xfe, 0x0a, 0xfa, 0x68, 0x98, 0x17, 0x11, 0xf3, 0x1a, 0xd9, 0xe1, 0x42, 0x42, 0x31, 0x0e, 0x2d, 0xb4, 0xbb, 0x30, 0xaf, 0x91, 0x1d, 0x88, 0x04, 0x37, 0x46, 0x05, 0x11, 0x48, 0x9e, 0x3e, 0x3b, 0x93, 0xeb, 0x83, 0x11, 0xd6, 0x00, 0x27, 0xdf, 0x31, 0x22, 0x68, 0x91, 0xc3, 0xbd, 0x95, 0x73, 0x39, 0x96, 0x68, 0x85, 0xb3, 0x96, 0xfc, 0x7a, 0xaf, 0x91, 0xcd, 0x5a, 0x12, 0x30, 0xa9, 0xf1, 0x10, 0xec, 0x25, 0xc2, 0x44, 0x82, 0xf7, 0x3a, 0x59, 0xbd, 0x88, 0xf3, 0x8b, 0x3a, 0xc4, 0x82, 0xb0, 0xe7,\n\t0x0f, 0xf3, 0xc0, 0xec, 0x45, 0xe1, 0x20, 0x8c, 0xcd, 0xbe, 0x88, 0xdf, 0xb9, 0x8a, 0xb8, 0xc1, 0xe5, 0x1e, 0x22, 0x2c, 0x82, 0x01, 0x88, 0xa9, 0x04, 0x90, 0x88, 0xfd, 0xd0, 0xb0, 0xa3, 0x79, 0xca, 0xa2, 0xfc, 0x4f, 0x44, 0x48, 0xab, 0xc3, 0x9b, 0x64, 0xde, 0xcd, 0x51, 0x2e, 0x2d, 0x31, 0x98, 0x49, 0xf7, 0xde, 0x81, 0x94, 0x2f, 0xe7, 0x77, 0xa1, 0x23, 0x25, 0x36, 0xbd, 0x0b, 0xcb, 0x62, 0x2e, 0x43, 0xb3, 0x16, 0x21, 0x18, 0x89, 0x48, 0x02, 0xbd, 0xb5, 0x15, 0xba, 0xf1, 0x12, 0x44, 0xbd, 0x92, 0xf1, 0x0c, 0xdb, 0x11, 0xd7, 0x91, 0x97, 0xea, 0x8a, 0xfd, 0xa0, 0xc9, 0x82, 0x38, 0x1f, 0xab, 0x88, 0x2a, 0xbf, 0xc7, 0x1f, 0x86, 0xff, 0xfc, 0xa8, 0x10, 0x40, 0x6c, 0x91, 0x7c, 0x1d, 0x99, 0x41, 0x58, 0xcc, 0xd0, 0xc9, 0x0d, 0xca, 0xb9, 0x7c, 0x91, 0x73, 0x03, 0xe2, 0x69,\n\t0xdb, 0xd1, 0x1d, 0x1b, 0x28, 0xd5, 0xe0, 0x9a, 0x1f, 0xee, 0x86, 0x4a, 0x3c, 0x3e, 0xb9, 0xc2, 0xff, 0x11, 0x37, 0x36, 0xa9, 0x26, 0x41, 0x26, 0x3a, 0x79, 0x9d, 0x1d, 0x27, 0xa4, 0x0b, 0x10, 0xc9, 0xdd, 0x8f, 0x99, 0xeb, 0x84, 0x82, 0xf0, 0x12, 0xab, 0x92, 0x49, 0x17, 0x20, 0xd0, 0xfa, 0x27, 0xc8, 0x6e, 0xb1, 0x84, 0x04, 0x34, 0x4a, 0x2b, 0x23, 0xa7, 0x78, 0x86, 0x5b, 0xde, 0x7c, 0xc0, 0xb4, 0x49, 0x04, 0xe1, 0x2d, 0xf4, 0xb8, 0x91, 0xd9, 0xa0, 0x51, 0xab, 0x94, 0xa8, 0x5c, 0xba, 0x1f, 0xfb, 0xb1, 0x3c, 0xd0, 0x18, 0x2e, 0x0b, 0xc6, 0x8b, 0x4b, 0x12, 0xe6, 0x04, 0x41, 0x62, 0x60, 0x87, 0xc4, 0x50, 0x68, 0x2d, 0x8b, 0xb4, 0x54, 0x83, 0xcb, 0x9f, 0xbe, 0xde, 0x5c, 0x3f, 0xd5, 0x11, 0x74, 0x55, 0x75, 0x97, 0x14, 0x25, 0x2d, 0xd7, 0x3f, 0x4d, 0x11, 0x1d, 0x6a, 0x57,\n\t0x81, 0x26, 0xe2, 0x0e, 0x14, 0xdd, 0x3b, 0x7f, 0x2f, 0x79, 0x8b, 0xa3, 0x66, 0x20, 0x5e, 0x96, 0x8a, 0x3b, 0x0a, 0x8c, 0xe0, 0x27, 0xf3, 0xf5, 0x78, 0x1e, 0x9d, 0x4d, 0x5f, 0x24, 0x2f, 0xe0, 0xfc, 0x88, 0x06, 0x76, 0x38, 0xb5, 0x18, 0xfe, 0x88, 0x74, 0x71, 0x36, 0xe3, 0xdf, 0x02, 0x37, 0x7e, 0x04, 0xe6, 0x9e, 0x63, 0x51, 0xb5, 0x82, 0x14, 0xff, 0x17, 0x3d, 0x85, 0x46, 0xb6, 0xb6, 0x9b, 0x60, 0x01, 0x73, 0xde, 0x0f, 0x79, 0x81, 0x4b, 0xc0, 0xb9, 0x7e, 0xd9, 0x1f, 0x52, 0xaa, 0x2c, 0xa2, 0xf4, 0x17, 0xd9, 0x3c, 0x1b, 0xe6, 0xe5, 0xf7, 0x22, 0xaf, 0xe3, 0xc4, 0x1a, 0x34, 0x8f, 0x2f, 0xd1, 0x93, 0xf0, 0xef, 0xc7, 0x88, 0x8e, 0x64, 0xab, 0x0f, 0x50, 0xb4, 0x1a, 0xb3, 0x11, 0x64, 0xc8, 0xc4, 0x00, 0x83, 0xfc, 0xff, 0x39, 0x56, 0x64, 0x34, 0xcd, 0x1f, 0x41, 0xe2, 0xb0,\n\t0x48, 0xf6, 0x39, 0x70, 0x95, 0x24, 0x6f, 0x30, 0x8c, 0x63, 0x22, 0x2b, 0x53, 0x87, 0x20, 0x74, 0x3f, 0x0b, 0x13, 0xc7, 0xe5, 0xd2, 0x7e, 0xb5, 0xf9, 0xbe, 0xc9, 0xc8, 0xf2, 0xfc, 0x21, 0x67, 0xb4, 0x52, 0xe0, 0x49, 0x6b, 0xaf, 0x5d, 0xc3, 0x14, 0x22, 0x6f, 0x48, 0x1b, 0x37, 0xdd, 0xd9, 0x3b, 0x79, 0xf9, 0x58, 0x57, 0x96, 0x42, 0xa4, 0xa8, 0x6f, 0x77, 0x6b, 0xed, 0x86, 0x56, 0x5f, 0x93, 0xd6, 0xad, 0x04, 0xf7, 0xdf, 0x78, 0x9c, 0xb9, 0x9e, 0xae, 0xc4, 0x44, 0x22, 0x50, 0x27, 0x2e, 0xbc, 0xc9, 0xfc, 0x01, 0xea, 0xc4, 0x10, 0x31, 0x96, 0x94, 0x07, 0xe5, 0xd0, 0xf7, 0x65, 0x30, 0x21, 0x1f, 0x57, 0x2f, 0x90, 0x2d, 0x45, 0xcc, 0xa2, 0x71, 0x89, 0xf1, 0x45, 0x35, 0x8a, 0x67, 0x05, 0x35, 0x8a, 0xc7, 0x73, 0x6a, 0x14, 0x87, 0x88, 0x10, 0x54, 0x9d, 0xfa, 0x80, 0x4f, 0x58,\n\t0xa3, 0x18, 0x43, 0x64, 0xd0, 0x4e, 0x1e, 0xe0, 0x95, 0x68, 0xa3, 0x50, 0x9d, 0x32, 0x7f, 0x38, 0x10, 0x52, 0x28, 0xab, 0xcf, 0x8d, 0xcf, 0x1c, 0x77, 0x98, 0xdb, 0x87, 0x36, 0x97, 0x7f, 0xea, 0xf9, 0xeb, 0x53, 0x1b, 0x8a, 0x7a, 0x6a, 0x3c, 0xd7, 0x27, 0xc7, 0x9a, 0x76, 0x96, 0x22, 0xcc, 0x7d, 0x70, 0x63, 0xcb, 0xd0, 0x9e, 0xc9, 0x44, 0x5f, 0xb9, 0xe5, 0x1f, 0xbe, 0x84, 0x54, 0xec, 0xde, 0x03, 0x8e, 0xda, 0xe1, 0x1a, 0xf4, 0xdb, 0x81, 0xbd, 0x2d, 0x35, 0xe4, 0xdb, 0x68, 0xbc, 0x6e, 0x4f, 0x3f, 0xc9, 0xfc, 0x11, 0xbe, 0x53, 0x11, 0xe2, 0x76, 0x09, 0xa3, 0x77, 0x82, 0x9a, 0x10, 0xbe, 0x93, 0xf0, 0x65, 0xb8, 0x92, 0xca, 0x59, 0x5d, 0x5f, 0x44, 0x14, 0xc1, 0x07, 0x36, 0x06, 0xfc, 0x5a, 0xee, 0x81, 0xb1, 0xc9, 0x11, 0x10, 0x56, 0x54, 0x5e, 0xf4, 0xbc, 0x7f, 0xbc, 0x6e,\n\t0xab, 0x5b, 0x95, 0x2a, 0x9e, 0xb9, 0x9d, 0x7d, 0xdc, 0x81, 0xdb, 0xd7, 0x45, 0xae, 0x4d, 0x4f, 0xc2, 0x07, 0x2e, 0xbc, 0xb6, 0x61, 0xac, 0x11, 0x3d, 0xf0, 0x7b, 0xcf, 0x82, 0x5f, 0xb8, 0xe3, 0x21, 0xd3, 0xee, 0xc9, 0x44, 0x6f, 0xb9, 0x25, 0x36, 0x75, 0xdf, 0xf8, 0x92, 0x0f, 0x8d, 0x75, 0x25, 0xf3, 0xbf, 0xa0, 0x9d, 0x5f, 0x47, 0x3c, 0xcf, 0x6a, 0x38, 0x79, 0x5c, 0x44, 0x8a, 0x98, 0x02, 0x7c, 0xb4, 0x67, 0xcb, 0x5e, 0xd1, 0x19, 0xe6, 0x5c, 0x97, 0x18, 0xa7, 0xb1, 0x22, 0x1d, 0x09, 0x75, 0x3d, 0x2a, 0xd8, 0x33, 0x9d, 0xca, 0x98, 0xb8, 0xd9, 0x70, 0x28, 0x9b, 0x9e, 0xcd, 0xb6, 0x05, 0x60, 0x99, 0xa6, 0xe8, 0x34, 0x50, 0x44, 0x8b, 0x28, 0x8c, 0xb8, 0x5b, 0xaa, 0x35, 0x6f, 0xfe, 0xb2, 0xa1, 0x50, 0x55, 0x6d, 0x35, 0xdc, 0x4e, 0x90, 0x8e, 0xe3, 0x2c, 0x5c, 0xae, 0x58,\n\t0x2f, 0xb5, 0x92, 0x52, 0x53, 0xe5, 0xee, 0x39, 0xe8, 0x3c, 0xa7, 0x89, 0x1d, 0x6b, 0x53, 0xc7, 0xd0, 0xa6, 0x8a, 0x81, 0xdb, 0x47, 0x22, 0xf9, 0xca, 0x4d, 0x38, 0xf8, 0x88, 0x77, 0x81, 0x9a, 0x5b, 0x85, 0x07, 0xbf, 0xc2, 0x1c, 0xdb, 0x7c, 0xff, 0x78, 0xbe, 0x82, 0xdb, 0xb7, 0x1f, 0x49, 0x15, 0x6d, 0x49, 0x07, 0xe7, 0x5a, 0x6a, 0xe6, 0x55, 0xdc, 0x79, 0x0f, 0x58, 0xb8, 0x13, 0xed, 0x43, 0x50, 0xb6, 0x45, 0x7c, 0x0d, 0x35, 0x99, 0x1e, 0x6e, 0xb1, 0x76, 0x80, 0x4a, 0xea, 0xd9, 0x32, 0x17, 0x4c, 0x46, 0xb2, 0x76, 0xbc, 0x6a, 0x45, 0x80, 0xcf, 0xaa, 0x65, 0xf9, 0x9b, 0xc7, 0x72, 0x88, 0x9e, 0xdd, 0x2c, 0x55, 0x45, 0x4e, 0xf6, 0x6d, 0x6e, 0xbb, 0x64, 0x90, 0xa0, 0x01, 0xbc, 0xc3, 0xcc, 0x2d, 0xd5, 0x94, 0xf7, 0x74, 0xe7, 0x58, 0xd2, 0x7f, 0x14, 0x2e, 0xf5, 0x1a, 0x7d,\n\t0xec, 0x06, 0x4d, 0xe5, 0x6d, 0xd0, 0x8b, 0xe5, 0x89, 0x84, 0x97, 0xcc, 0x90, 0x50, 0xb0, 0x9b, 0x74, 0x9e, 0x57, 0x10, 0x47, 0xf2, 0xda, 0xc1, 0xf3, 0x4d, 0xf0, 0x1b, 0xf5, 0x8d, 0xff, 0x12, 0xca, 0x8c, 0x8e, 0x07, 0xb9, 0x7d, 0x9a, 0xfe, 0x2d, 0x96, 0xcf, 0x3d, 0x2f, 0x9a, 0xd4, 0x38, 0x77, 0x94, 0x17, 0x04, 0x8a, 0x85, 0x73, 0xe9, 0x3f, 0xe8, 0x68, 0x33, 0x93, 0x39, 0x3d, 0x47, 0x64, 0x05, 0xc1, 0x65, 0x4a, 0x0b, 0x8f, 0x40, 0x73, 0xda, 0x21, 0x14, 0x08, 0x89, 0xca, 0x45, 0xcc, 0x2d, 0xd5, 0x94, 0xc8, 0xb6, 0x44, 0x82, 0xf0, 0x04, 0x03, 0x1e, 0x7d, 0x50, 0x90, 0x5f, 0x4d, 0x2e, 0xcd, 0xd8, 0x21, 0x28, 0x69, 0xf4, 0x5b, 0x2e, 0x96, 0xbe, 0x04, 0x3d, 0x07, 0x1f, 0x4f, 0x47, 0x5a, 0x1d, 0xc5, 0xd0, 0xc9, 0xab, 0x8b, 0xa9, 0x38, 0xe6, 0xeb, 0xd9, 0x40, 0x3a, 0x6b,\n\t0xa3, 0xfd, 0x12, 0xdb, 0x87, 0x8e, 0xa4, 0x15, 0x27, 0x41, 0xcd, 0x62, 0xf0, 0xf0, 0x34, 0x6f, 0x0c, 0x7a, 0xcc, 0x1e, 0x06, 0x85, 0x1f, 0xb2, 0x35, 0xc7, 0xbd, 0xd9, 0x1a, 0xe3, 0xd4, 0x2f, 0x37, 0x9a, 0x9d, 0xaa, 0xf9, 0x3f, 0x92, 0xe4, 0x93, 0x9b, 0x2d, 0x16, 0x35, 0x69, 0x22, 0x29, 0xa4, 0xb0, 0xd4, 0x3a, 0xf2, 0x09, 0x73, 0xa9, 0x61, 0xfe, 0x21, 0xea, 0x1d, 0xb9, 0x61, 0x7e, 0xbc, 0x20, 0x6a, 0x24, 0x67, 0x08, 0x0a, 0xfb, 0xf5, 0x85, 0x50, 0xe6, 0x22, 0x68, 0x91, 0x7b, 0x88, 0xad, 0x5c, 0xb9, 0x89, 0x25, 0x0a, 0x89, 0xef, 0x16, 0x16, 0x12, 0xb7, 0x7d, 0x40, 0x13, 0x7c, 0x4a, 0x64, 0x55, 0xab, 0x10, 0x58, 0xa0, 0xc0, 0xac, 0xf2, 0xa8, 0x3d, 0x62, 0xa5, 0x58, 0x29, 0x97, 0xc2, 0x3f, 0x23, 0x62, 0x43, 0xce, 0xf8, 0xc8, 0xb0, 0x8a, 0xaf, 0x6d, 0x9a, 0x97, 0x14,\n\t0x04, 0xac, 0xd2, 0x0b, 0xe7, 0xee, 0xba, 0x57, 0x0a, 0xe4, 0xf7, 0x9e, 0x3a, 0x73, 0x41, 0x0e, 0x5c, 0x73, 0x57, 0x6f, 0x6f, 0x6d, 0xbd, 0xfd, 0x2a, 0x4f, 0xad, 0x0b, 0xbe, 0xfb, 0xd8, 0x53, 0x4f, 0x3d, 0xb6, 0xfd, 0xa1, 0x27, 0x9e, 0x78, 0x08, 0x7c, 0xbf, 0xeb, 0xdc, 0x6b, 0xb7, 0xde, 0xfa, 0xf5, 0xb3, 0x5d, 0xbc, 0xeb, 0xce, 0x9e, 0xad, 0xf6, 0x2d, 0xfc, 0x95, 0xf9, 0x01, 0xf4, 0x15, 0xf5, 0x44, 0x14, 0xd5, 0x91, 0x40, 0x45, 0x08, 0x65, 0x41, 0x38, 0xe2, 0x66, 0x94, 0x29, 0x81, 0x56, 0x1b, 0xbc, 0x60, 0xd8, 0x8b, 0x51, 0xf6, 0x63, 0x2f, 0x21, 0x46, 0x15, 0x1c, 0x25, 0x9b, 0x44, 0x99, 0x72, 0xe2, 0xbb, 0x53, 0x72, 0x29, 0x4a, 0x1e, 0x11, 0x1c, 0xb5, 0xd7, 0xe4, 0xb6, 0xe2, 0x5c, 0xc8, 0x0c, 0x77, 0x27, 0xd7, 0x7e, 0x14, 0x4f, 0x29, 0xf6, 0x22, 0xeb, 0x5c, 0xba,\n\t0x30, 0x8b, 0x52, 0xd4, 0x80, 0xe8, 0x9d, 0x4b, 0x8a, 0x8b, 0xc2, 0x21, 0xbf, 0xd7, 0x56, 0x60, 0x32, 0xb2, 0x25, 0xc9, 0x15, 0x4b, 0x94, 0x24, 0xf7, 0x8b, 0x3d, 0xf1, 0x5c, 0x07, 0x1c, 0x95, 0x1b, 0xc6, 0x94, 0xa8, 0x64, 0x74, 0xd5, 0x8e, 0xee, 0x50, 0xa8, 0x7b, 0xc7, 0xaa, 0x56, 0xf6, 0x27, 0xf5, 0xdf, 0xc1, 0xfc, 0x87, 0xea, 0x3f, 0x3d, 0xbb, 0xf5, 0xe9, 0xc3, 0xab, 0x56, 0x1d, 0x7e, 0x7a, 0xeb, 0xec, 0xa7, 0xeb, 0xc9, 0xed, 0xe9, 0x46, 0x30, 0x95, 0xfe, 0xe8, 0xc5, 0x8a, 0xc9, 0x33, 0x6b, 0x07, 0xcf, 0x4c, 0xc6, 0x62, 0x93, 0x67, 0x06, 0xd7, 0x9e, 0x99, 0xac, 0x10, 0x3d, 0x7c, 0xb2, 0x25, 0xd5, 0x77, 0xf7, 0xab, 0x73, 0x7b, 0x5e, 0xbd, 0xbb, 0x2f, 0xb5, 0xea, 0xd4, 0x23, 0xe9, 0xdf, 0x5d, 0x4c, 0xff, 0x07, 0xc1, 0xe6, 0x7e, 0xbd, 0xc5, 0x3c, 0x0d, 0xe7, 0x83,\n\t0x83, 0xad, 0x50, 0x5c, 0x8a, 0x46, 0xb8, 0x1b, 0xc5, 0x32, 0x00, 0x3a, 0x0b, 0xc5, 0xf4, 0xe8, 0x58, 0x30, 0x24, 0x3e, 0x10, 0x44, 0xeb, 0x0b, 0x4e, 0x07, 0x97, 0x33, 0x56, 0x1e, 0x0e, 0x3a, 0xeb, 0x5c, 0x75, 0xc6, 0x40, 0xc0, 0x27, 0x41, 0x26, 0x4e, 0x96, 0xc9, 0x4d, 0x10, 0xe7, 0x6c, 0x00, 0x31, 0x23, 0x55, 0x41, 0x67, 0x9d, 0xb5, 0x60, 0xc6, 0x9d, 0x06, 0x3e, 0x6a, 0xd2, 0x58, 0xdc, 0x52, 0xea, 0xeb, 0x4d, 0x16, 0xfd, 0xcf, 0xbf, 0xfe, 0xf5, 0x9d, 0xe2, 0xe6, 0x3e, 0x6f, 0x49, 0x73, 0xb1, 0xf1, 0xda, 0xc6, 0x97, 0x00, 0xf3, 0x64, 0x6f, 0xed, 0xb6, 0x07, 0xd6, 0x25, 0xd6, 0x77, 0x55, 0x1b, 0x8c, 0x35, 0x5d, 0xa3, 0xf1, 0xe1, 0x07, 0xb6, 0xd6, 0xf6, 0x7d, 0x1a, 0x2a, 0xb5, 0x4f, 0x36, 0x6e, 0xe9, 0x0a, 0x87, 0xd6, 0x1c, 0x5f, 0xf7, 0xcd, 0xaf, 0xbf, 0x76, 0x7d,\n\t0xf8, 0xf6, 0xb5, 0x45, 0xe1, 0xae, 0x2d, 0x8d, 0xdf, 0xff, 0x3e, 0x39, 0x33, 0xf1, 0xd8, 0x77, 0xe6, 0x66, 0x3e, 0x77, 0x22, 0x65, 0x2d, 0x6b, 0x0e, 0x06, 0x9b, 0xcb, 0xac, 0x3d, 0xa7, 0x3e, 0x3f, 0xb5, 0xe7, 0xbf, 0x3d, 0x36, 0x81, 0xed, 0x38, 0xe5, 0xc2, 0x9f, 0xc8, 0xb5, 0x70, 0x7d, 0x59, 0x10, 0x17, 0x09, 0x22, 0xcf, 0x96, 0x9b, 0x45, 0x70, 0x0e, 0x2b, 0xb0, 0x35, 0x65, 0xcb, 0x5e, 0x51, 0x19, 0x7c, 0x86, 0x9e, 0xcd, 0xcc, 0x63, 0x2d, 0x3d, 0x6e, 0x29, 0xf2, 0xc4, 0xdb, 0x5c, 0xd2, 0x1e, 0xb2, 0x3f, 0x28, 0x3e, 0x27, 0x06, 0x93, 0x36, 0x3a, 0x79, 0x22, 0x37, 0x41, 0x0b, 0x61, 0x3d, 0x63, 0x96, 0x7b, 0xdb, 0x42, 0x58, 0x0a, 0x0d, 0x7e, 0x0f, 0xe7, 0xdb, 0x61, 0x28, 0x2f, 0x57, 0x5d, 0x88, 0x2b, 0xb7, 0x57, 0xa5, 0x25, 0xd7, 0xee, 0x75, 0x59, 0x18, 0x45, 0xf4,\n\t0xee, 0x4d, 0x9e, 0x3a, 0x93, 0x52, 0x6c, 0x55, 0x55, 0xbb, 0xcb, 0x3a, 0x6b, 0x4a, 0xf4, 0x68, 0x59, 0x9b, 0x1d, 0xf7, 0x4d, 0xed, 0x53, 0xa9, 0x2f, 0xda, 0xe4, 0xb6, 0x78, 0x6f, 0x05, 0x79, 0x24, 0xf3, 0x7e, 0xd0, 0x4e, 0xfc, 0x1b, 0xdf, 0x6f, 0x66, 0xf9, 0xf7, 0x9b, 0xf9, 0xc0, 0xf7, 0x9b, 0xf9, 0x7f, 0xe1, 0xfd, 0x98, 0xeb, 0xef, 0xd5, 0xe7, 0xbe, 0x1f, 0xdd, 0x81, 0xdf, 0x0f, 0xee, 0xa3, 0x63, 0x70, 0xfc, 0x02, 0xc4, 0xd3, 0xdc, 0xfb, 0x59, 0xa5, 0xf0, 0x8d, 0xd4, 0x70, 0xff, 0xc4, 0xef, 0xc7, 0x5f, 0x51, 0x19, 0xa6, 0x2e, 0x3b, 0xc1, 0x0f, 0x1f, 0xe7, 0x5a, 0xe7, 0x6d, 0x20, 0x25, 0x78, 0xfd, 0xf3, 0xbc, 0x1b, 0x79, 0x6d, 0x09, 0xe1, 0x1e, 0x52, 0x94, 0x61, 0xe7, 0x13, 0xb6, 0x16, 0xf8, 0xec, 0x79, 0xdb, 0x08, 0xf4, 0x76, 0x0d, 0x39, 0xdb, 0x48, 0xc3, 0xe2,\n\t0xf7, 0x17, 0x1e, 0xcf, 0x8e, 0x71, 0x9b, 0x48, 0xe4, 0x44, 0x9e, 0x30, 0xae, 0xe7, 0xef, 0x21, 0x6f, 0x4e, 0xed, 0x15, 0x8c, 0xfb, 0xfb, 0xaf, 0x73, 0xc7, 0xb0, 0x78, 0x1f, 0x7d, 0x9a, 0xfc, 0x1e, 0x2d, 0x87, 0xa2, 0x7f, 0x88, 0x1d, 0x5e, 0x19, 0xd2, 0xd4, 0x5a, 0xc0, 0x51, 0xf3, 0x96, 0x70, 0x77, 0x68, 0xee, 0x0e, 0xba, 0x20, 0xb9, 0x8b, 0x51, 0x6e, 0x42, 0x2c, 0x4d, 0xcc, 0x5b, 0xf2, 0x7f, 0x44, 0xcc, 0xeb, 0x81, 0xa2, 0x10, 0x94, 0xef, 0x36, 0x8b, 0x45, 0xd8, 0x0b, 0x15, 0x94, 0x11, 0x6d, 0x2e, 0x3f, 0x9f, 0xf7, 0xd6, 0xd7, 0xe6, 0xdc, 0x66, 0x86, 0x8a, 0x4f, 0xef, 0x53, 0x73, 0xaf, 0x5a, 0x7e, 0xa3, 0x8c, 0xe9, 0x35, 0x3b, 0x78, 0xbf, 0x1e, 0xbf, 0x67, 0x98, 0xf8, 0x3d, 0x3b, 0xcc, 0x6a, 0x39, 0x54, 0xe8, 0x26, 0x54, 0x1e, 0xce, 0x03, 0x44, 0xa8, 0x8e, 0x06,\n\t0xfb, 0xc8, 0xfc, 0x6d, 0x86, 0xbf, 0x8d, 0xee, 0x50, 0xc2, 0x3b, 0xfc, 0x6b, 0x5b, 0xb2, 0x2b, 0x60, 0x36, 0xb7, 0xec, 0x1c, 0x3f, 0x8f, 0xd0, 0x07, 0x99, 0xb9, 0xb1, 0x3b, 0xbf, 0x0d, 0x3b, 0x8f, 0xb8, 0xfa, 0x74, 0xf9, 0x6d, 0x09, 0x61, 0x15, 0xbb, 0x30, 0x41, 0x52, 0x0c, 0xc5, 0x32, 0x8d, 0x53, 0x88, 0x69, 0x9c, 0xe3, 0xe2, 0x5d, 0xdc, 0x16, 0x1d, 0x40, 0xc8, 0xfc, 0x9e, 0x20, 0x5c, 0x45, 0x6e, 0x4c, 0xcd, 0xcb, 0x02, 0xdb, 0xf2, 0x45, 0xb8, 0xa8, 0x76, 0xdd, 0x39, 0x24, 0x3a, 0x45, 0xf4, 0xfc, 0xe6, 0x5c, 0x89, 0xc6, 0xe1, 0x34, 0x42, 0x25, 0xeb, 0xd4, 0xdc, 0x44, 0xa3, 0xde, 0x31, 0x3b, 0xee, 0x9f, 0x61, 0xe5, 0x6b, 0xaf, 0xec, 0x2d, 0x9f, 0xef, 0xc0, 0x13, 0x69, 0x35, 0x3b, 0xc9, 0xb0, 0x9c, 0xaf, 0xc1, 0x8d, 0xe1, 0xdb, 0x34, 0xdc, 0xa5, 0x88, 0x41, 0x5c,\n\t0x5d, 0xf2, 0xaa, 0x0c, 0x73, 0xf2, 0xda, 0xe0, 0x4f, 0x8a, 0xe5, 0xf7, 0x40, 0x25, 0x27, 0xb5, 0xc2, 0x57, 0xe5, 0xdc, 0x33, 0x0b, 0x82, 0xd0, 0x50, 0x24, 0x31, 0x27, 0x78, 0x33, 0xfc, 0x11, 0x74, 0x86, 0xfd, 0x7e, 0x9c, 0x88, 0xec, 0x59, 0x14, 0xf6, 0x31, 0x82, 0xbb, 0xae, 0xe7, 0x9e, 0xb5, 0x5f, 0x26, 0x2f, 0xae, 0x39, 0x3f, 0x95, 0xd0, 0xe9, 0x87, 0xe1, 0xe5, 0xeb, 0xf8, 0x99, 0xa0, 0xb3, 0x41, 0x4a, 0xf0, 0x33, 0xb5, 0x5e, 0x45, 0x05, 0x51, 0x01, 0x57, 0x94, 0x5a, 0x9b, 0xc9, 0xb2, 0xe2, 0x83, 0x05, 0xe8, 0x29, 0x00, 0x42, 0x4f, 0x61, 0x46, 0xcd, 0x9c, 0x8f, 0x46, 0x5f, 0x84, 0xce, 0x83, 0x07, 0xbb, 0xe4, 0x95, 0xb8, 0x1c, 0x70, 0xf6, 0x34, 0x46, 0xeb, 0x05, 0xad, 0x9c, 0x2b, 0x6e, 0xe2, 0x5d, 0x73, 0xf2, 0xca, 0xeb, 0xf0, 0x7a, 0x98, 0x75, 0xcc, 0xe7, 0x77,\n\t0xb1, 0x18, 0x2e, 0xb8, 0xc1, 0x3f, 0x0e, 0x75, 0x91, 0x0c, 0x5a, 0x4f, 0x89, 0x64, 0xcc, 0xc5, 0xd6, 0x95, 0xcc, 0x3f, 0xf7, 0x98, 0xcd, 0x56, 0x95, 0xb4, 0xe4, 0x54, 0x94, 0x14, 0x2f, 0xaa, 0x44, 0x48, 0x71, 0x39, 0xfe, 0x1e, 0xee, 0x4c, 0x08, 0x2e, 0x8b, 0x97, 0x13, 0xfd, 0xf1, 0x82, 0x2d, 0xdb, 0x0e, 0x93, 0xe3, 0x9f, 0x89, 0x9a, 0x7f, 0x22, 0x77, 0xd8, 0x07, 0x5e, 0x01, 0xf1, 0x2d, 0x0f, 0x4d, 0x96, 0xee, 0xdf, 0xe9, 0x2b, 0x20, 0x8d, 0x70, 0x8f, 0x0b, 0xf4, 0x0e, 0xa6, 0x9f, 0x9b, 0xff, 0x7d, 0x00, 0xb4, 0xea, 0x34, 0xe9, 0xfd, 0xd4, 0x3b, 0xc5, 0xbd, 0x3b, 0x9b, 0xb7, 0x3c, 0xe2, 0x31, 0x06, 0xf0, 0x33, 0x9e, 0x85, 0x4f, 0xf3, 0x89, 0xec, 0x33, 0x2a, 0xd9, 0x2c, 0x7f, 0x0e, 0xe3, 0xc3, 0x70, 0x59, 0xae, 0xb0, 0xe1, 0x38, 0xc1, 0x3d, 0xa3, 0xc7, 0x65, 0x43,\n\t0xa5, 0x2f, 0x0d, 0xd9, 0x67, 0xf4, 0xb3, 0x87, 0x32, 0xe8, 0x19, 0x45, 0xfc, 0xc1, 0xae, 0x87, 0x2b, 0x2c, 0xa8, 0x4f, 0xd4, 0x01, 0xf0, 0xea, 0xd6, 0x2d, 0x05, 0x95, 0xfd, 0x89, 0x43, 0x60, 0xa2, 0xc0, 0xb7, 0x73, 0x7f, 0xc9, 0x86, 0x4b, 0x5b, 0xd2, 0xff, 0xf8, 0xca, 0x80, 0xc3, 0x21, 0xff, 0x89, 0xb1, 0xfc, 0x33, 0x97, 0x06, 0x7b, 0x03, 0x70, 0x13, 0x4e, 0x3f, 0x07, 0xfe, 0x14, 0x30, 0x7a, 0x1e, 0xde, 0xda, 0xbc, 0xb3, 0xb7, 0x98, 0x7a, 0x27, 0x7d, 0x40, 0xad, 0x03, 0xad, 0x01, 0x8e, 0x8f, 0x1f, 0xea, 0x74, 0x0f, 0xb4, 0x3b, 0xfa, 0x89, 0x0f, 0x27, 0xd5, 0xfd, 0x00, 0x48, 0xa2, 0x76, 0x92, 0x14, 0x07, 0x01, 0xf4, 0x94, 0xb9, 0xdc, 0x5e, 0x54, 0x88, 0x0a, 0x3e, 0xa6, 0x68, 0x0e, 0xd5, 0xfa, 0x10, 0x89, 0x77, 0xf3, 0xa7, 0x1e, 0xb8, 0xe0, 0x34, 0x57, 0xee, 0x01,\n\t0xb9, 0x08, 0xd9, 0xc3, 0x93, 0x44, 0x7e, 0x0f, 0x9e, 0x04, 0x7b, 0x89, 0x9e, 0x02, 0x1a, 0xec, 0xd1, 0xa4, 0xbe, 0x37, 0x55, 0x5b, 0x1d, 0x8f, 0x15, 0x87, 0x7d, 0x85, 0x48, 0x14, 0x3e, 0xe8, 0x8a, 0x9b, 0x8a, 0x81, 0x28, 0x9f, 0x9e, 0x0a, 0x8e, 0x96, 0x31, 0x7f, 0xd9, 0x35, 0x80, 0x65, 0xe8, 0xad, 0xc8, 0xff, 0xae, 0xb2, 0x6a, 0x82, 0x89, 0xee, 0x58, 0x31, 0x4b, 0x49, 0xb5, 0x79, 0xa2, 0xab, 0x34, 0x36, 0xf5, 0xe0, 0xe4, 0xd8, 0x60, 0x79, 0x92, 0x5f, 0x91, 0x3d, 0x45, 0xdd, 0x5b, 0x93, 0x0e, 0x7c, 0x7e, 0x12, 0xce, 0xe5, 0xb5, 0x8a, 0x4e, 0x9e, 0x1d, 0x9d, 0xf9, 0x64, 0x2d, 0xd5, 0x65, 0xc9, 0x67, 0xa2, 0xea, 0x38, 0x3c, 0x52, 0x61, 0xef, 0xea, 0x1d, 0xce, 0xae, 0xd9, 0x47, 0x96, 0x25, 0xb2, 0x82, 0x3e, 0x68, 0x47, 0xfa, 0xc3, 0xe4, 0x05, 0xe6, 0x0a, 0xe1, 0x27,\n\t0xf6, 0x72, 0xb5, 0x57, 0x10, 0x6f, 0xbb, 0x8d, 0xf7, 0x41, 0x25, 0x50, 0x53, 0xda, 0x78, 0x1f, 0x14, 0x7d, 0x6c, 0x16, 0x44, 0x2a, 0x73, 0xdd, 0x4a, 0x1f, 0x81, 0xa2, 0x00, 0x6c, 0x55, 0x7b, 0x12, 0x55, 0xb5, 0xcf, 0x46, 0x26, 0x05, 0x3e, 0x65, 0x52, 0xea, 0x41, 0x47, 0x50, 0xb8, 0xb0, 0xbd, 0x7e, 0xe5, 0x23, 0x27, 0xec, 0x52, 0x2e, 0x8a, 0x37, 0x62, 0x4d, 0x00, 0xaf, 0x91, 0x26, 0x08, 0xc3, 0x6b, 0xba, 0x92, 0x57, 0x05, 0x6a, 0xd5, 0xf4, 0x96, 0xf7, 0xbf, 0xbd, 0xe6, 0x9e, 0x99, 0x1a, 0xfe, 0x0a, 0xbe, 0x5f, 0x3b, 0x7e, 0xbf, 0xa7, 0x09, 0x1f, 0x31, 0x7a, 0x55, 0x8f, 0xe9, 0x74, 0x05, 0xef, 0x91, 0x53, 0x20, 0x85, 0xdf, 0xd1, 0x7d, 0xcb, 0xd4, 0x7c, 0xd8, 0x91, 0xa9, 0xf9, 0x80, 0xf9, 0x39, 0xa5, 0x9e, 0x00, 0x52, 0xc2, 0xdc, 0x51, 0x84, 0xc0, 0x21, 0xcc, 0xd1,\n\t0x1a, 0x8b, 0xe2, 0x79, 0x3c, 0x83, 0x8e, 0x91, 0xbb, 0xe6, 0xc3, 0x7b, 0xaf, 0xb0, 0x5a, 0x84, 0x6e, 0xda, 0x3a, 0x9d, 0xad, 0x09, 0xfa, 0xfe, 0xd7, 0xd8, 0x50, 0x1f, 0x41, 0x2e, 0x0c, 0xa7, 0xef, 0x23, 0xff, 0x08, 0xdf, 0x43, 0x4e, 0xd4, 0x13, 0x8f, 0x72, 0x67, 0x8e, 0xe8, 0xa8, 0xa0, 0x16, 0x00, 0x91, 0x07, 0xd5, 0xf6, 0x29, 0xf6, 0x91, 0x0c, 0x5b, 0x07, 0xcf, 0x00, 0xe8, 0x45, 0xb7, 0x33, 0x95, 0x73, 0x38, 0x14, 0x87, 0xe0, 0xcc, 0x51, 0x9c, 0xc3, 0x92, 0x1b, 0x20, 0x28, 0x1a, 0xee, 0x80, 0x68, 0x8d, 0x70, 0x78, 0x8f, 0xcc, 0x01, 0xa3, 0xb0, 0x21, 0xc6, 0xfc, 0x55, 0x27, 0x10, 0xd9, 0x65, 0x81, 0x99, 0x27, 0x77, 0x44, 0x98, 0x3f, 0x73, 0x05, 0xa2, 0x65, 0x66, 0x83, 0xae, 0x4b, 0x8d, 0x2f, 0xa2, 0x30, 0x11, 0x8b, 0x02, 0xd0, 0xd1, 0x0b, 0xe2, 0xf5, 0x53, 0xc5,\n\t0xb5, 0x49, 0xc4, 0x93, 0x65, 0xed, 0x46, 0x77, 0x7b, 0x38, 0x1e, 0xad, 0xfa, 0x97, 0xfc, 0x8a, 0x4f, 0xe5, 0xe6, 0x52, 0x63, 0xbd, 0xd5, 0xa3, 0x96, 0x68, 0x24, 0xe3, 0xe7, 0x9b, 0xc7, 0x6b, 0xad, 0xc0, 0x96, 0x18, 0x4c, 0xc4, 0x46, 0xc2, 0xd4, 0x5b, 0x15, 0x55, 0x6e, 0x6f, 0xa5, 0x27, 0x50, 0xce, 0x04, 0x85, 0xa1, 0xe6, 0x1b, 0xfe, 0xc7, 0xe7, 0x0a, 0x53, 0xe1, 0xb0, 0x4e, 0x6a, 0xd6, 0xb8, 0xd4, 0xeb, 0x03, 0x0d, 0xbd, 0xc1, 0x60, 0x77, 0x9d, 0xd7, 0x65, 0xf7, 0x84, 0xe0, 0x5b, 0xe9, 0x17, 0xde, 0x26, 0x9f, 0x61, 0x9a, 0x88, 0x42, 0x62, 0x00, 0x55, 0x7e, 0xa2, 0x68, 0x02, 0x5b, 0x8a, 0x3c, 0xf8, 0x98, 0x26, 0x90, 0x56, 0x80, 0x8a, 0x90, 0x3f, 0x1b, 0xe4, 0xaa, 0x34, 0x2c, 0xf9, 0xc9, 0x1e, 0x3c, 0x17, 0x50, 0xce, 0x86, 0x16, 0xcf, 0x69, 0xae, 0x42, 0x0e, 0x66,\n\t0xe5, 0x60, 0xa3, 0x4b, 0x99, 0xf9, 0x60, 0x32, 0x22, 0xab, 0xc6, 0x48, 0x3e, 0xc3, 0xd2, 0xf2, 0xa4, 0x7f, 0x09, 0xdc, 0x42, 0xbc, 0xfe, 0xa9, 0x8e, 0xa3, 0xa7, 0x0e, 0x6a, 0xcd, 0x60, 0xdc, 0x94, 0xfe, 0xbe, 0x56, 0x0f, 0x86, 0x2f, 0x90, 0x83, 0x1c, 0x06, 0x7f, 0x43, 0x71, 0xf4, 0xfc, 0x1d, 0xf3, 0x8f, 0x9b, 0x8c, 0x38, 0xc7, 0xf9, 0x22, 0xf9, 0x1c, 0xd3, 0x00, 0x9f, 0x7d, 0x0a, 0x57, 0xff, 0x66, 0x64, 0x80, 0x25, 0xe2, 0xe0, 0xcc, 0x5a, 0x86, 0xde, 0x27, 0xa0, 0x1a, 0xca, 0x6c, 0x7e, 0x38, 0x98, 0xe6, 0xe5, 0x19, 0x89, 0x70, 0x9e, 0xb1, 0x90, 0x91, 0x28, 0xdb, 0x0a, 0x17, 0x7a, 0x0c, 0xc1, 0x6d, 0xb0, 0x90, 0x25, 0x9e, 0x5d, 0x54, 0x01, 0x37, 0x9f, 0x8a, 0xe8, 0x81, 0xca, 0x06, 0xac, 0xae, 0x44, 0x9a, 0xd2, 0x81, 0x58, 0xf7, 0x8e, 0x36, 0x4f, 0x4e, 0xe9, 0x8d,\n\t0x06, 0xa1, 0xf1, 0x40, 0x9d, 0x15, 0x12, 0x0c, 0x91, 0x44, 0x62, 0xe1, 0x4d, 0xfa, 0x7e, 0xcc, 0x15, 0xe6, 0x27, 0x66, 0x5f, 0x54, 0x4b, 0x48, 0x96, 0xf0, 0x05, 0x45, 0x78, 0x9c, 0x32, 0x09, 0xa2, 0x21, 0x84, 0x72, 0x16, 0x11, 0x9b, 0xa4, 0x80, 0x4b, 0x9d, 0x61, 0x63, 0x3e, 0x78, 0x0f, 0x2f, 0x5c, 0xa2, 0x01, 0x57, 0xa3, 0x3e, 0x9b, 0x1e, 0xa0, 0xf1, 0xfb, 0xbc, 0x85, 0x28, 0xbe, 0x1d, 0xf0, 0xe8, 0xbd, 0x1a, 0x39, 0x57, 0x1f, 0x1c, 0x07, 0x49, 0xfd, 0x5e, 0x36, 0xf4, 0x4b, 0x2d, 0x2a, 0x10, 0x4e, 0xb5, 0xa6, 0xcb, 0xf0, 0xa9, 0x19, 0xe8, 0x39, 0x77, 0x20, 0xa4, 0x50, 0x79, 0x3a, 0x07, 0xc7, 0x71, 0xd0, 0xe6, 0xf0, 0xe1, 0xeb, 0xe0, 0x07, 0xd7, 0xce, 0x81, 0xef, 0x4e, 0xa0, 0xf3, 0xb3, 0x57, 0xd3, 0x15, 0xd9, 0x58, 0xcd, 0xc4, 0x59, 0xf0, 0x44, 0x7a, 0x12, 0xfd,\n\t0x43, 0x7b, 0xd7, 0xd0, 0xc2, 0x5f, 0xe8, 0x75, 0xf0, 0xbd, 0xea, 0x88, 0x0d, 0x49, 0x85, 0x19, 0x6d, 0xfc, 0x71, 0x0f, 0x02, 0x94, 0x70, 0x33, 0xcc, 0x42, 0x8a, 0x48, 0x14, 0x06, 0x60, 0x77, 0xda, 0x0c, 0x5d, 0x35, 0x72, 0xa1, 0x96, 0xfe, 0x08, 0x33, 0xf9, 0xeb, 0xd1, 0x7a, 0x2b, 0x29, 0x72, 0x3b, 0x6d, 0x05, 0x2a, 0x05, 0x51, 0x07, 0xea, 0xb0, 0xa9, 0x00, 0x75, 0x65, 0x1e, 0xbf, 0x32, 0x9a, 0x7d, 0x18, 0xb6, 0x66, 0x64, 0x69, 0x98, 0xf9, 0xf8, 0x7d, 0x30, 0x8e, 0x69, 0xb3, 0xa8, 0x2f, 0xb8, 0x57, 0x79, 0x50, 0x91, 0xbb, 0xde, 0x33, 0x2f, 0x6d, 0xdb, 0xf6, 0xe2, 0x99, 0xde, 0x70, 0xf7, 0x96, 0x46, 0xcf, 0x2a, 0xf7, 0x13, 0x85, 0x76, 0x70, 0x20, 0x3a, 0xdc, 0xe4, 0xaf, 0x18, 0xda, 0x9b, 0x6c, 0xda, 0x3b, 0x54, 0xe1, 0x4f, 0x0e, 0x95, 0x83, 0x83, 0x8e, 0x42, 0x6a,\n\t0x4c, 0xc4, 0x98, 0x57, 0xef, 0x3c, 0xd9, 0x35, 0x73, 0xe5, 0x58, 0x7b, 0xfb, 0xb1, 0x2b, 0x33, 0x5d, 0x27, 0x77, 0xae, 0x36, 0x33, 0xa2, 0xcd, 0x56, 0xcf, 0x4f, 0x25, 0x75, 0xe3, 0x07, 0x5b, 0x7a, 0xf7, 0xf5, 0x04, 0x02, 0x3d, 0xfb, 0x7a, 0x5b, 0x0e, 0x8e, 0xd7, 0x49, 0x7e, 0xea, 0xb1, 0x6e, 0xc6, 0xfb, 0xf7, 0xde, 0x85, 0xb7, 0xa9, 0x5f, 0xd3, 0x62, 0xa2, 0x8a, 0xb8, 0xc4, 0xad, 0x2b, 0x56, 0xcb, 0x92, 0xbc, 0x07, 0x91, 0x79, 0x69, 0x76, 0xea, 0x2e, 0xf9, 0xf1, 0x1e, 0xfc, 0x71, 0x14, 0x83, 0xfa, 0x51, 0xd0, 0x2b, 0xa3, 0xa8, 0x73, 0x9b, 0x24, 0x0b, 0x91, 0xd1, 0x4c, 0x33, 0xd4, 0x1c, 0x5f, 0xed, 0x75, 0x71, 0x23, 0x16, 0xd7, 0x1f, 0x2a, 0x29, 0x0a, 0xb1, 0x2a, 0x3b, 0xb7, 0xc0, 0x2b, 0x14, 0x18, 0xd2, 0x48, 0x48, 0x11, 0x61, 0x4c, 0x89, 0x50, 0x70, 0xac, 0x4a,\n\t0x0f, 0x82, 0x85, 0x92, 0x54, 0xf9, 0xc6, 0xa3, 0xed, 0xb6, 0x35, 0xf7, 0xbe, 0xbc, 0x75, 0xf0, 0xf4, 0x86, 0x18, 0x74, 0x28, 0xa5, 0xf2, 0x8b, 0x76, 0x2b, 0x2d, 0x12, 0x6b, 0x9c, 0xf1, 0xce, 0xa2, 0x9a, 0x1d, 0x03, 0xe5, 0xfa, 0x40, 0xb5, 0xdf, 0x53, 0x2c, 0x55, 0x59, 0x69, 0xea, 0xf7, 0x6a, 0x65, 0xf3, 0xce, 0x0b, 0xbd, 0x0f, 0xbf, 0xfd, 0x99, 0xd1, 0xea, 0x3d, 0x4f, 0xed, 0xe9, 0xf9, 0xc2, 0xc6, 0xc4, 0xfe, 0x46, 0xb7, 0xb9, 0x7c, 0xba, 0x6c, 0xe2, 0xa9, 0x96, 0xbe, 0xbd, 0x9d, 0x85, 0x0d, 0x47, 0x5e, 0x3a, 0x92, 0xda, 0x54, 0x6d, 0x94, 0x29, 0xad, 0x50, 0x5e, 0x3a, 0x38, 0xec, 0xef, 0xc1, 0x39, 0xa3, 0x23, 0xe0, 0x2c, 0x90, 0x60, 0x03, 0x96, 0x10, 0xc4, 0xf9, 0xb4, 0x25, 0x6e, 0x44, 0x9e, 0xe3, 0xc1, 0xb9, 0xbc, 0xc2, 0x4a, 0x5c, 0x31, 0xea, 0xbd, 0x4f, 0x98,\n\t0x5d, 0xcc, 0x9f, 0x55, 0x3a, 0x89, 0xc4, 0xa0, 0xfa, 0xab, 0xc8, 0x69, 0x78, 0x04, 0x3c, 0xf6, 0x79, 0xb3, 0x86, 0x9c, 0x0b, 0xa1, 0x61, 0x09, 0xcd, 0xdf, 0xaf, 0x35, 0xc1, 0xaf, 0xc5, 0x63, 0xe2, 0x58, 0x48, 0x8b, 0x54, 0xf0, 0xa2, 0x98, 0xf0, 0x24, 0x9d, 0x3e, 0x93, 0x04, 0xe9, 0x81, 0x6e, 0x36, 0x8a, 0xca, 0x9f, 0xa0, 0x84, 0x3d, 0x45, 0xf5, 0x6e, 0xe4, 0x93, 0x2d, 0xfa, 0x4b, 0xe8, 0x32, 0x10, 0x14, 0xf1, 0x7f, 0xb6, 0xc2, 0xac, 0x37, 0x61, 0xaa, 0x24, 0x68, 0xec, 0x89, 0x54, 0x8f, 0xc0, 0x47, 0x78, 0x51, 0xaa, 0x16, 0x49, 0x8d, 0xf2, 0xd7, 0x19, 0xbb, 0x61, 0xc8, 0xe4, 0x60, 0xbe, 0x69, 0xd4, 0x29, 0xf4, 0x5f, 0x16, 0xb9, 0x0c, 0x17, 0x41, 0xe7, 0xa3, 0x76, 0xd9, 0x4f, 0xd4, 0x52, 0x46, 0x21, 0xf9, 0x67, 0x59, 0xe1, 0x25, 0xf4, 0x6c, 0x81, 0x2e, 0x9f, 0xaf,\n\t0x2b, 0x30, 0x7f, 0x8f, 0xc6, 0x68, 0xd4, 0x90, 0xfb, 0x53, 0x9d, 0x5d, 0xdd, 0xec, 0x73, 0xfa, 0xe6, 0xb7, 0x57, 0x46, 0xad, 0xe5, 0x56, 0xf2, 0x21, 0x68, 0x4d, 0x10, 0x0a, 0xc4, 0x09, 0xc5, 0xf4, 0x12, 0x26, 0xc2, 0x9e, 0x2c, 0x30, 0x21, 0x9e, 0x11, 0x24, 0x14, 0x82, 0xdc, 0xc7, 0x09, 0xc5, 0x2b, 0x10, 0x0a, 0x10, 0x0a, 0x05, 0xb3, 0xfc, 0x51, 0x37, 0x50, 0xc1, 0x96, 0x74, 0x5a, 0xaa, 0x82, 0x03, 0x24, 0x7d, 0x57, 0xe4, 0xd2, 0x3f, 0x46, 0x56, 0xe2, 0x52, 0x2e, 0x16, 0x35, 0xb9, 0xd9, 0x5c, 0x66, 0xb1, 0x44, 0xcd, 0xf3, 0x1f, 0xd7, 0x9a, 0x18, 0x97, 0xc9, 0x92, 0xde, 0x81, 0x6b, 0xd8, 0xc0, 0xbf, 0xf7, 0x39, 0xea, 0x5d, 0xe8, 0x43, 0x38, 0x92, 0x56, 0x39, 0xc5, 0xa6, 0xa4, 0x90, 0xb8, 0x52, 0x22, 0xeb, 0xa5, 0x14, 0x17, 0x6a, 0x29, 0x36, 0xce, 0xaa, 0xc5, 0xee,\n\t0x16, 0x27, 0x02, 0xf4, 0xe7, 0xc8, 0xc6, 0xaf, 0xa4, 0xef, 0x7b, 0xb2, 0xc0, 0x21, 0xfb, 0xb2, 0x4b, 0x2f, 0xb5, 0x68, 0xbe, 0x24, 0x71, 0x5a, 0x2e, 0x83, 0x7b, 0xd2, 0xfb, 0xc1, 0x79, 0x72, 0x4f, 0x81, 0x3e, 0xfd, 0xb9, 0xfa, 0x0a, 0x6b, 0xc2, 0x09, 0x06, 0x34, 0x76, 0xcc, 0x0b, 0x7a, 0x91, 0x6e, 0xc6, 0xbc, 0xe2, 0xb3, 0x57, 0xe5, 0x1c, 0x2f, 0x28, 0x1b, 0xb2, 0x5e, 0x82, 0x69, 0x6b, 0x51, 0xc8, 0x7a, 0x11, 0x19, 0x68, 0x96, 0x94, 0x4b, 0x10, 0x6b, 0xc0, 0xa1, 0x06, 0xad, 0xd1, 0x98, 0x1b, 0x6a, 0xc8, 0x63, 0xe8, 0x32, 0x66, 0x83, 0xd5, 0xcd, 0xa5, 0x3d, 0xe1, 0xd4, 0x96, 0xa4, 0x63, 0xfe, 0x33, 0x42, 0x4a, 0x50, 0xd2, 0x1e, 0x4d, 0xe6, 0x46, 0x19, 0x22, 0x39, 0xd4, 0x5d, 0x3f, 0xc6, 0x76, 0x26, 0xf2, 0x29, 0x6a, 0x16, 0x9a, 0xe9, 0x21, 0xf8, 0x4e, 0x72, 0xa2,\n\t0x92, 0xe8, 0x4a, 0xb6, 0x87, 0xb0, 0xdf, 0xe3, 0x05, 0x54, 0x47, 0x86, 0x42, 0x3b, 0x53, 0xb5, 0x40, 0x2a, 0x96, 0x50, 0x7c, 0xb2, 0x09, 0xd4, 0xe5, 0x0a, 0x05, 0x1c, 0xe9, 0x4a, 0x45, 0x25, 0x0a, 0x82, 0x06, 0x03, 0x59, 0xaa, 0x68, 0x59, 0x6e, 0x06, 0x81, 0x37, 0x8b, 0xcc, 0x2d, 0x06, 0xd9, 0x7c, 0x81, 0xdc, 0x37, 0x22, 0xd3, 0xd3, 0x38, 0x67, 0x20, 0xe0, 0xd5, 0x5c, 0x2a, 0x68, 0xe8, 0x1e, 0xa9, 0xc4, 0x29, 0x02, 0xc3, 0xc7, 0x06, 0x87, 0x44, 0x4a, 0x11, 0xe3, 0x71, 0xf5, 0x88, 0x14, 0xe2, 0xb4, 0x4d, 0xf8, 0x86, 0x0f, 0x37, 0x24, 0x82, 0x95, 0x86, 0x68, 0x7f, 0xdd, 0xd4, 0xc9, 0x3e, 0x97, 0xb7, 0x61, 0x20, 0x52, 0x3b, 0xd5, 0x19, 0xf2, 0x74, 0x17, 0x59, 0x35, 0x8c, 0x3c, 0xba, 0x2e, 0x94, 0x47, 0x54, 0x86, 0xea, 0x33, 0x3c, 0xfa, 0xff, 0xdd, 0xfa, 0x0c, 0x9f,\n\t0xbc, 0xb5, 0x2d, 0x7b, 0xb8, 0x1a, 0xe8, 0xda, 0xb1, 0xa8, 0x3e, 0x03, 0x49, 0xb8, 0xd3, 0xf7, 0x53, 0x8d, 0xf0, 0xf9, 0x2b, 0x88, 0x24, 0x71, 0x67, 0x52, 0x99, 0x70, 0x49, 0x28, 0x91, 0x58, 0x2d, 0x23, 0x81, 0x88, 0xe4, 0xb8, 0xd6, 0x42, 0x99, 0x9a, 0x89, 0x59, 0x8a, 0x7a, 0xae, 0x58, 0xc2, 0x4e, 0x7c, 0xea, 0xc6, 0xbf, 0x12, 0x32, 0x16, 0xf9, 0xa6, 0x24, 0x21, 0x16, 0x91, 0x62, 0x41, 0x17, 0x61, 0xc3, 0xd1, 0xa4, 0xa9, 0x32, 0x56, 0x5b, 0x1d, 0x4b, 0x56, 0x26, 0x51, 0xa0, 0x3b, 0xe8, 0xc7, 0x27, 0xf5, 0x6c, 0xd8, 0x9f, 0x62, 0x7d, 0x5a, 0x68, 0x12, 0xf2, 0x60, 0xfb, 0x2a, 0xb6, 0x4c, 0x53, 0x62, 0xb1, 0x3c, 0xb2, 0xa6, 0xa5, 0x93, 0x04, 0x4f, 0x6c, 0x7b, 0x74, 0xb6, 0x22, 0x1e, 0x73, 0xd9, 0xeb, 0x6c, 0x1e, 0x95, 0xa5, 0xea, 0xec, 0xc0, 0xe8, 0xd1, 0xde, 0x42,\n\t0x00, 0x5c, 0x4d, 0x13, 0x4d, 0x53, 0x4f, 0xac, 0xb2, 0x16, 0xb6, 0x6d, 0xeb, 0x78, 0xc1, 0x06, 0xba, 0xd3, 0x06, 0x28, 0x20, 0x6d, 0xfa, 0x78, 0xcd, 0x84, 0x37, 0x76, 0x5b, 0x5b, 0x4d, 0xb9, 0x2e, 0xd4, 0x80, 0xa4, 0x35, 0x7d, 0xba, 0x7f, 0xe8, 0x23, 0xf5, 0xe5, 0x09, 0x64, 0x21, 0x96, 0x7a, 0x03, 0xc5, 0x6d, 0xc3, 0x25, 0xe1, 0x9e, 0x5a, 0xef, 0x9a, 0xd6, 0x86, 0xde, 0x3a, 0x24, 0x33, 0xb7, 0x89, 0x93, 0xd9, 0xfb, 0x3f, 0x74, 0xd8, 0x2a, 0x93, 0x45, 0x6e, 0x83, 0xd7, 0xa6, 0x41, 0xe3, 0x5f, 0x08, 0x85, 0xf8, 0x31, 0xe6, 0xf2, 0x8a, 0x9c, 0xb7, 0x3b, 0xf2, 0x38, 0x6f, 0x29, 0x41, 0xd6, 0xa1, 0x36, 0x8f, 0xf3, 0xf6, 0x17, 0xde, 0x89, 0xad, 0x7b, 0x12, 0xdb, 0xaf, 0x9e, 0x4e, 0x55, 0x4e, 0xdd, 0x3f, 0x71, 0x7d, 0xe6, 0x22, 0x9c, 0xbf, 0xfd, 0x7b, 0x3b, 0x5b, 0x36,\n\t0x76, 0x20, 0xce, 0x5b, 0x46, 0x8c, 0x20, 0xc9, 0x8d, 0xb7, 0x3e, 0xb7, 0x7f, 0xe4, 0xa3, 0x77, 0x6c, 0xb4, 0xa6, 0x7d, 0x64, 0xab, 0xb2, 0x75, 0xfa, 0xce, 0xd4, 0xc0, 0x6d, 0x83, 0x45, 0x1c, 0x84, 0x1c, 0xae, 0xae, 0x08, 0x1c, 0x85, 0x2b, 0xf8, 0x99, 0x4a, 0x93, 0x45, 0x28, 0xea, 0xe9, 0x21, 0x70, 0x55, 0xad, 0x4c, 0x00, 0x2e, 0xfb, 0x5c, 0x78, 0xc5, 0x59, 0x7d, 0xa6, 0x30, 0x0e, 0x72, 0xf0, 0xc8, 0x62, 0x27, 0x89, 0x23, 0x47, 0xd9, 0x83, 0x06, 0xb3, 0xd6, 0x0b, 0x9e, 0x9f, 0xb8, 0x7f, 0xaa, 0x32, 0x75, 0xfa, 0xea, 0xf6, 0xc4, 0x9e, 0xad, 0x13, 0xde, 0x2a, 0xa5, 0x45, 0x57, 0xde, 0xb1, 0xb1, 0xa5, 0x73, 0x6f, 0x7f, 0x51, 0x64, 0xe3, 0xc5, 0x99, 0xeb, 0xe0, 0xe7, 0xd6, 0x8d, 0x77, 0x7c, 0x74, 0x64, 0xff, 0x73, 0xb7, 0x36, 0x66, 0x70, 0xfc, 0x45, 0x83, 0xb7, 0x0d,\n\t0xa4, 0xee, 0x9c, 0x6e, 0x55, 0xce, 0xbf, 0x82, 0xf9, 0x81, 0x17, 0xfe, 0x4a, 0x9d, 0x64, 0x1e, 0x23, 0x3c, 0xd0, 0xce, 0x96, 0xbb, 0x10, 0xa5, 0x9d, 0x1a, 0x13, 0x63, 0x72, 0x66, 0x50, 0xa6, 0x14, 0x02, 0x45, 0x4d, 0x09, 0x49, 0x31, 0x6d, 0xcb, 0x7c, 0x84, 0x4c, 0xed, 0x17, 0x2d, 0xfc, 0xb3, 0x2f, 0x01, 0xa8, 0xc5, 0x53, 0x26, 0xa8, 0x8d, 0x81, 0x05, 0xfc, 0xe8, 0xa7, 0xd8, 0x47, 0xc7, 0xa9, 0x08, 0xe5, 0xed, 0x1b, 0x5b, 0xee, 0xff, 0x24, 0x7a, 0xf0, 0x6b, 0xd4, 0xd7, 0xac, 0x1b, 0xee, 0x7c, 0x6c, 0x64, 0xff, 0xf3, 0xf0, 0xc1, 0x83, 0xf5, 0x45, 0x9d, 0x7a, 0xa7, 0xcf, 0x79, 0xf9, 0x09, 0xf8, 0xd8, 0x2d, 0x2a, 0xb2, 0x15, 0xcb, 0x73, 0x67, 0xfa, 0x13, 0xd4, 0x33, 0xf8, 0xdc, 0xb1, 0x36, 0x59, 0x55, 0x04, 0x00, 0xc3, 0x26, 0xb2, 0xe6, 0x57, 0xa2, 0x5e, 0x84, 0x61,\n\t0xdd, 0x4a, 0xc3, 0x2d, 0x97, 0x4f, 0xff, 0x02, 0x2b, 0x14, 0x9e, 0x06, 0x64, 0x5c, 0xa3, 0xc3, 0xe1, 0xdd, 0xdd, 0x38, 0xff, 0x2b, 0xd6, 0x1e, 0x43, 0x56, 0x54, 0xb8, 0x6f, 0x5f, 0x57, 0x75, 0x57, 0x05, 0xca, 0xff, 0xaa, 0xf2, 0x0e, 0x4f, 0x6e, 0x8e, 0x6c, 0x7d, 0xf6, 0x78, 0xfb, 0xbb, 0x6f, 0x6e, 0x79, 0x32, 0x49, 0xd5, 0xe2, 0xf4, 0xa5, 0xa6, 0x93, 0xaf, 0xdf, 0xfb, 0xd0, 0xf7, 0xef, 0xac, 0xcd, 0xa4, 0x7f, 0xa5, 0x3e, 0x05, 0xe8, 0x2f, 0x82, 0x31, 0xb0, 0xb9, 0x3d, 0x09, 0x77, 0xab, 0x91, 0x85, 0xb7, 0x98, 0x1d, 0xd0, 0x47, 0x44, 0xbc, 0x55, 0x75, 0x98, 0x47, 0x10, 0xba, 0x7e, 0x14, 0x03, 0x35, 0x12, 0x17, 0x88, 0xc3, 0x13, 0x80, 0x2f, 0x5b, 0x18, 0x42, 0xff, 0xb1, 0x3e, 0x8b, 0x81, 0xc4, 0x0f, 0x0b, 0x1f, 0xab, 0x52, 0x87, 0x15, 0x12, 0xd0, 0x89, 0xf3, 0x20,\n\t0xb7, 0xfe, 0x7c, 0x8a, 0x80, 0x1d, 0x93, 0x4f, 0xff, 0x8f, 0x07, 0x1f, 0xf8, 0x1f, 0x4f, 0x4f, 0xc2, 0x9f, 0x0f, 0x3c, 0x08, 0x7f, 0x5e, 0x4b, 0x1e, 0x7a, 0x6a, 0xeb, 0x96, 0xa7, 0x0e, 0x35, 0x37, 0x1f, 0x7a, 0x6a, 0xcb, 0xd6, 0xa7, 0x0e, 0x25, 0xd3, 0xaf, 0x18, 0x7d, 0x65, 0x36, 0x6b, 0xa4, 0x10, 0xee, 0x42, 0x11, 0xab, 0xad, 0xcc, 0x67, 0x24, 0xbf, 0xfb, 0x78, 0xfa, 0xcf, 0xd7, 0x76, 0xee, 0xbc, 0x06, 0x94, 0x8f, 0x7f, 0x02, 0xa8, 0xbe, 0xbe, 0x6b, 0xd7, 0xb5, 0xf4, 0x9f, 0x3f, 0x71, 0xe2, 0x87, 0x97, 0xfa, 0xfb, 0x2f, 0xfd, 0xf0, 0xc4, 0xc9, 0x1f, 0x5e, 0xec, 0xef, 0xbf, 0xf8, 0xc3, 0x93, 0xd6, 0x88, 0xd7, 0x68, 0xf4, 0xb2, 0x3d, 0xe0, 0x37, 0xb0, 0xe7, 0x77, 0x6b, 0x16, 0xde, 0xa6, 0xed, 0x1c, 0xde, 0x78, 0xfb, 0xd5, 0x32, 0x7c, 0x0c, 0xc5, 0xd3, 0xf0, 0x53,\n\t0x22, 0x7c, 0x1c, 0x35, 0x85, 0xc7, 0x41, 0x0c, 0x16, 0xe5, 0xee, 0xad, 0xd8, 0x02, 0x1f, 0x4d, 0x9a, 0xdd, 0x2e, 0x40, 0x14, 0x85, 0x5c, 0xd5, 0xee, 0x6a, 0x87, 0xcd, 0xa8, 0x97, 0x4b, 0x11, 0xf8, 0x58, 0x82, 0x0d, 0xec, 0x5c, 0xd4, 0x71, 0x16, 0xae, 0x4f, 0x65, 0xd3, 0xd7, 0xb2, 0x20, 0x7d, 0xf0, 0x2f, 0x08, 0x04, 0x60, 0xab, 0x1b, 0x6b, 0x1e, 0x3f, 0x31, 0xe0, 0xf7, 0x0f, 0xde, 0x39, 0xd1, 0x34, 0x52, 0x65, 0x99, 0x1d, 0x7f, 0xf4, 0xd6, 0x53, 0xaf, 0x9f, 0x6f, 0xef, 0xb8, 0xe7, 0x07, 0xe7, 0xff, 0xe1, 0x9f, 0xa6, 0x87, 0x22, 0xc9, 0xa0, 0xb6, 0x74, 0xf3, 0xa3, 0xe0, 0x9f, 0xac, 0xa5, 0xf5, 0xde, 0x40, 0x63, 0x69, 0x41, 0xe5, 0xa6, 0x7b, 0x46, 0x46, 0xce, 0x6f, 0xa8, 0xb0, 0x04, 0x63, 0xf6, 0xa6, 0x9e, 0x93, 0x64, 0x9c, 0x3f, 0xc3, 0x7c, 0xf8, 0xfe, 0x89, 0xd3,\n\t0x6e, 0x4d, 0xb4, 0xb6, 0xc9, 0x59, 0x39, 0xd5, 0x57, 0xc6, 0x61, 0x5e, 0xe9, 0x67, 0xe9, 0x7f, 0x23, 0x9a, 0x89, 0x5b, 0x93, 0xfa, 0x2a, 0x20, 0x16, 0x45, 0xa0, 0x70, 0x18, 0x13, 0x5c, 0xf4, 0x4e, 0x68, 0x48, 0xd0, 0x99, 0xc4, 0x34, 0x11, 0xc1, 0x56, 0x57, 0xe7, 0x98, 0x24, 0x05, 0x88, 0xa9, 0xac, 0x83, 0x64, 0xbb, 0x99, 0x76, 0x18, 0x98, 0x2d, 0x0f, 0x05, 0x43, 0x5e, 0x83, 0x3e, 0x14, 0xc2, 0x20, 0xa1, 0x5c, 0x94, 0x6b, 0x4c, 0x88, 0x86, 0xcd, 0x3d, 0x9c, 0x14, 0xa2, 0x62, 0xb1, 0xe2, 0xa6, 0xbe, 0x9b, 0x50, 0x84, 0xcd, 0xe6, 0xb2, 0x9a, 0x8e, 0xb2, 0x14, 0x8b, 0x7c, 0xed, 0x44, 0x10, 0x59, 0x9d, 0x11, 0x0c, 0xf6, 0x7e, 0xf9, 0xd8, 0x9e, 0x97, 0xcf, 0xf6, 0x76, 0x9f, 0xbf, 0x7e, 0xb8, 0x71, 0x7b, 0xc4, 0x14, 0x5f, 0xd7, 0x1c, 0x5d, 0xe5, 0xb5, 0x88, 0xdd, 0x5a,\n\t0xb9, 0x4d, 0x15, 0x2d, 0xa6, 0x8e, 0xe7, 0x63, 0x61, 0x79, 0xc4, 0x6c, 0x75, 0x9c, 0xc7, 0xcb, 0x1a, 0xb4, 0x86, 0xd2, 0xa1, 0x96, 0xb0, 0x4a, 0xb5, 0xd9, 0x2a, 0xa3, 0x29, 0xaa, 0xa5, 0x09, 0xaa, 0xc5, 0x85, 0xe1, 0xf4, 0xfd, 0xe0, 0x9f, 0x98, 0x2f, 0xc1, 0x35, 0xe1, 0x22, 0x9a, 0x88, 0xd5, 0xc9, 0x5e, 0x68, 0x19, 0x32, 0x85, 0x66, 0x68, 0x3d, 0x95, 0xf8, 0x49, 0xb8, 0x6b, 0x77, 0xa3, 0x32, 0xd6, 0x24, 0x43, 0x61, 0x5a, 0x65, 0x9e, 0xfa, 0x90, 0xad, 0x64, 0xc1, 0xad, 0xea, 0x39, 0xba, 0xc7, 0x68, 0x00, 0x44, 0x53, 0x63, 0x4d, 0x55, 0x59, 0xa9, 0xad, 0xc0, 0xe0, 0x32, 0xba, 0xd8, 0x13, 0x5a, 0x29, 0x9e, 0x1f, 0xb9, 0xe0, 0x73, 0xc1, 0x1e, 0x65, 0x02, 0x8b, 0x83, 0x1d, 0xfc, 0xd6, 0x06, 0x75, 0x54, 0xa7, 0x2d, 0xea, 0x37, 0x1a, 0xfd, 0x51, 0x9b, 0xad, 0xc2, 0x6f,\n\t0x32, 0xf9, 0x2b, 0xd2, 0xbf, 0x88, 0xb4, 0x1b, 0x5d, 0x38, 0xfe, 0x01, 0x3e, 0x56, 0x6e, 0x2e, 0x31, 0xa2, 0x7d, 0x4d, 0xa2, 0x91, 0x8c, 0xdd, 0xdd, 0x82, 0x02, 0x1e, 0xc0, 0x96, 0x18, 0xa8, 0x42, 0x11, 0x8f, 0xeb, 0xf4, 0x33, 0x46, 0x7f, 0xb9, 0xcd, 0x5e, 0x8e, 0x7a, 0x97, 0xdb, 0x6d, 0xf0, 0xe7, 0x7b, 0xd3, 0x15, 0x55, 0x2e, 0x5f, 0xdc, 0xe3, 0x2f, 0x07, 0x9b, 0x9f, 0x98, 0x2b, 0x4c, 0x85, 0xd8, 0xb8, 0x87, 0x6a, 0x94, 0x8d, 0x7b, 0xd4, 0xfa, 0x50, 0xdc, 0x83, 0xfa, 0x3c, 0xcb, 0xd9, 0x8e, 0xea, 0x03, 0xc0, 0xfd, 0xdf, 0x85, 0xb0, 0xa6, 0xea, 0x4c, 0xe4, 0x97, 0xa4, 0xc1, 0x14, 0x74, 0xa7, 0x33, 0x80, 0x8a, 0x0c, 0xfc, 0xc8, 0x45, 0xb8, 0x82, 0x41, 0xbf, 0x47, 0x8b, 0x53, 0xc4, 0x31, 0x84, 0x8e, 0xab, 0x9b, 0x08, 0xd0, 0x8b, 0x06, 0x39, 0xec, 0x30, 0x55, 0x07,\n\t0xb4, 0xd4, 0xd1, 0xeb, 0x88, 0x85, 0x36, 0xfd, 0x7d, 0xc4, 0x42, 0x0b, 0xb6, 0x5a, 0x7d, 0x06, 0xbb, 0x2a, 0x7d, 0xe7, 0xe7, 0x2c, 0x3e, 0x25, 0xa8, 0x95, 0xa8, 0xb4, 0x46, 0x75, 0x25, 0xf5, 0xce, 0x7b, 0x5f, 0x20, 0x7f, 0xa3, 0xd0, 0xa5, 0x9f, 0xd3, 0xeb, 0xc1, 0xb9, 0x42, 0xb3, 0xc2, 0x6b, 0x00, 0x7f, 0xd6, 0x18, 0xd3, 0x5b, 0xe5, 0x2a, 0x31, 0x05, 0x7e, 0xc9, 0xe3, 0x51, 0xc9, 0x9f, 0xc1, 0xe7, 0x63, 0x08, 0x17, 0x86, 0x79, 0x70, 0x87, 0xac, 0x59, 0xfe, 0x53, 0x86, 0x60, 0xb4, 0x5a, 0x5a, 0x66, 0x2a, 0xf6, 0x1b, 0x91, 0xbb, 0x4e, 0xfe, 0x6c, 0xfe, 0xb3, 0xaf, 0x7c, 0xec, 0x63, 0xd4, 0x3b, 0x1c, 0xd7, 0xe5, 0x60, 0xfa, 0x69, 0x2e, 0xe7, 0x30, 0x5b, 0x23, 0x17, 0x61, 0xf3, 0x2b, 0xe1, 0xab, 0xfb, 0x72, 0x73, 0x0e, 0x85, 0xb7, 0xf8, 0x1a, 0xb9, 0xcb, 0xe5, 0x1c,\n\t0xf2, 0x25, 0xa9, 0xd8, 0xf2, 0xc1, 0x1c, 0xcd, 0xfb, 0x8a, 0x8d, 0xf7, 0x64, 0x6a, 0x0d, 0xaf, 0x9c, 0xa4, 0x98, 0xd7, 0x1c, 0x65, 0x52, 0x85, 0xbc, 0xfa, 0xbf, 0x21, 0x4b, 0x51, 0x9b, 0x0f, 0xc9, 0x8f, 0xec, 0xe3, 0xaa, 0x4f, 0x0c, 0xa3, 0x1c, 0xc5, 0xdc, 0xe8, 0xe9, 0x35, 0x9c, 0xd8, 0x39, 0x93, 0x68, 0xd8, 0xfb, 0xc4, 0xcc, 0xc6, 0xd3, 0xa5, 0x59, 0x72, 0xf7, 0xde, 0x36, 0xca, 0x28, 0x8c, 0xa0, 0xbd, 0xb7, 0x01, 0xfc, 0xa6, 0x8b, 0x4d, 0xec, 0x7c, 0xed, 0xc2, 0xea, 0xd6, 0x5a, 0xbe, 0x2e, 0xca, 0xbf, 0x33, 0xd7, 0xe1, 0x7c, 0xd1, 0x13, 0x15, 0x88, 0xed, 0x0b, 0x11, 0x77, 0x68, 0x22, 0x80, 0x10, 0x39, 0xf5, 0x0c, 0x62, 0xae, 0x01, 0x68, 0x41, 0x71, 0x59, 0xfa, 0xf0, 0x3e, 0xc8, 0xbf, 0x1f, 0xe5, 0xee, 0x4b, 0x72, 0xee, 0x67, 0x6f, 0x51, 0xdc, 0xad, 0xd1, 0x51,\n\t0x8e, 0x15, 0xc4, 0x89, 0x09, 0x0e, 0x91, 0xbb, 0x27, 0x1a, 0x43, 0x16, 0xe5, 0x6e, 0x3c, 0x1b, 0xe8, 0x71, 0x86, 0x23, 0xec, 0x64, 0xff, 0x54, 0x88, 0xe0, 0x08, 0x95, 0xf9, 0x46, 0xc4, 0xf2, 0xed, 0xd9, 0x1c, 0xb8, 0x4c, 0x7b, 0x82, 0x6b, 0x2e, 0x19, 0x25, 0x10, 0xb5, 0x5e, 0x7e, 0x6b, 0xf4, 0xc0, 0xd1, 0x0f, 0x68, 0x8d, 0xb3, 0xe1, 0xd1, 0xaf, 0xcc, 0x38, 0xc1, 0x15, 0x74, 0x89, 0x2c, 0xdb, 0x85, 0xa7, 0x7e, 0x99, 0xce, 0x90, 0x53, 0xe3, 0xda, 0x2e, 0x70, 0xd4, 0x15, 0x5a, 0x7d, 0xc8, 0xe7, 0x31, 0x07, 0xbc, 0x50, 0xaf, 0x38, 0x8a, 0xfd, 0xc8, 0xa9, 0x11, 0xe7, 0x26, 0xf3, 0xb2, 0x2e, 0x9b, 0x67, 0x89, 0x4a, 0x2e, 0x5a, 0x0f, 0xf5, 0x73, 0x5a, 0x02, 0x9d, 0x9a, 0x9f, 0xe7, 0x54, 0x1b, 0xa1, 0xfe, 0x11, 0xfb, 0x70, 0xce, 0x1b, 0x1f, 0x5a, 0x94, 0x99, 0x7a, 0x9d,\n\t0x12, 0x9d, 0x91, 0x4a, 0xc9, 0x6f, 0x4d, 0x08, 0x0a, 0x8c, 0x9c, 0xc1, 0x4e, 0xce, 0xc3, 0xf9, 0x35, 0x5b, 0xd2, 0x95, 0xec, 0xba, 0xba, 0x24, 0xb6, 0xe1, 0x5c, 0xe8, 0x21, 0x70, 0x17, 0x3b, 0x38, 0xe6, 0x5e, 0x40, 0xc8, 0x10, 0x30, 0x3c, 0x06, 0x9d, 0x87, 0x06, 0xa8, 0xfb, 0x44, 0x4e, 0xa8, 0x5b, 0x19, 0x7e, 0x02, 0xf0, 0x1f, 0x8b, 0xf3, 0x3f, 0xc6, 0x9f, 0x28, 0x96, 0xf8, 0x84, 0x1f, 0xf5, 0x2a, 0x82, 0x96, 0x30, 0x12, 0x04, 0x50, 0x23, 0xa1, 0xbb, 0x4b, 0x8a, 0xa6, 0x08, 0xb9, 0x7c, 0x06, 0x87, 0x9f, 0x65, 0x63, 0x0a, 0x80, 0xf3, 0xb1, 0xd0, 0x89, 0x0d, 0x07, 0x73, 0xce, 0x1e, 0x2e, 0x70, 0x7f, 0xb8, 0x79, 0xc9, 0xee, 0x84, 0xa0, 0xb7, 0x58, 0xfc, 0x81, 0x5f, 0x84, 0xe6, 0x49, 0xd3, 0xf2, 0x5f, 0x44, 0x70, 0xdf, 0xa3, 0x18, 0x25, 0x14, 0x8a, 0xd9, 0xe5, 0xbe,\n\t0x26, 0xb9, 0x8a, 0xa0, 0xa5, 0x8c, 0xf4, 0xa6, 0xbe, 0x01, 0xf7, 0x05, 0x00, 0xa7, 0xf0, 0xec, 0xc9, 0x85, 0xe1, 0x8d, 0x26, 0x0d, 0x03, 0xab, 0xfb, 0xfb, 0x52, 0x5d, 0xcd, 0xd0, 0x97, 0x43, 0x6e, 0xa4, 0x3e, 0x50, 0xa8, 0x5c, 0x94, 0xc0, 0xe3, 0xbf, 0x19, 0xec, 0xee, 0x92, 0x93, 0x07, 0x39, 0x57, 0xb9, 0xa9, 0xcd, 0xe4, 0x16, 0xec, 0x7a, 0x1e, 0xe5, 0x5c, 0xcf, 0x52, 0xa9, 0x45, 0x6b, 0x08, 0xd7, 0x40, 0xd7, 0x73, 0x17, 0x74, 0x3d, 0x5b, 0xb7, 0x77, 0xbd, 0xa0, 0x52, 0x80, 0xd4, 0xfc, 0x7f, 0x1e, 0x5c, 0x6a, 0x5e, 0x99, 0x35, 0xc2, 0xb4, 0xe7, 0x17, 0x57, 0xaa, 0x1c, 0xa8, 0xb5, 0xca, 0xc1, 0x47, 0x6e, 0x3c, 0xbe, 0x78, 0xc6, 0xb1, 0xde, 0x2a, 0xe2, 0x03, 0x1b, 0x5c, 0x68, 0x16, 0xff, 0x16, 0xd7, 0x25, 0xd3, 0x12, 0x6e, 0x62, 0x04, 0xbc, 0xc9, 0xcd, 0xbd, 0x7e,\n\t0x40, 0x4a, 0x75, 0x80, 0x21, 0x9b, 0xdc, 0x24, 0x01, 0x14, 0x40, 0x44, 0xd0, 0xdd, 0xd5, 0x40, 0xd4, 0xc1, 0xcf, 0xbd, 0x7e, 0x40, 0x2d, 0xf3, 0x71, 0x21, 0xf7, 0xb1, 0x7c, 0xe9, 0x8f, 0xa3, 0xcb, 0x7e, 0x2c, 0xe9, 0xb0, 0x2d, 0xfe, 0x84, 0x66, 0x3f, 0x19, 0xcd, 0x68, 0xac, 0x22, 0x54, 0xa9, 0x88, 0x60, 0xc0, 0x14, 0x1c, 0x5f, 0x16, 0x40, 0x23, 0x1d, 0x93, 0x03, 0x94, 0x95, 0xa5, 0x52, 0xd0, 0x4a, 0x1a, 0x2a, 0xa6, 0x71, 0x89, 0x98, 0x14, 0x89, 0xa6, 0x45, 0xfc, 0x74, 0xad, 0xcc, 0xe9, 0x01, 0xc7, 0x9c, 0xef, 0x40, 0xac, 0xdc, 0x97, 0xcd, 0x21, 0x5b, 0xd4, 0x97, 0xe0, 0xba, 0xca, 0x47, 0x71, 0x8d, 0xd0, 0xa5, 0x7a, 0x46, 0xf1, 0xdc, 0xbe, 0xe9, 0x9e, 0x62, 0x8c, 0xb4, 0xe5, 0x2e, 0x25, 0xe3, 0x70, 0xa6, 0xee, 0x91, 0xc0, 0xb9, 0x5d, 0x7b, 0x13, 0xdf, 0xa0, 0xa4,\n\t0xb2, 0x5f, 0x00, 0xb5, 0x1e, 0x3e, 0x65, 0x85, 0x9d, 0xb1, 0xc2, 0xf3, 0x7b, 0x3c, 0x80, 0xf0, 0x8c, 0x78, 0x46, 0xd6, 0x0c, 0x0e, 0xac, 0xee, 0x4d, 0xad, 0x6a, 0x6e, 0xa8, 0x2b, 0x2f, 0x0b, 0xfa, 0x9d, 0x76, 0x93, 0x41, 0xcb, 0x85, 0x80, 0xd4, 0xb9, 0x21, 0x20, 0x06, 0x25, 0xed, 0xe4, 0x69, 0x45, 0x66, 0x99, 0xb0, 0xd0, 0xb2, 0x13, 0x1d, 0x88, 0x1e, 0xc0, 0xbc, 0x12, 0xe1, 0x80, 0x57, 0x33, 0x7f, 0x88, 0x14, 0x51, 0x50, 0x6d, 0xfe, 0x6b, 0x8e, 0xda, 0x24, 0xbf, 0x94, 0x0d, 0x1d, 0x0d, 0x1d, 0x67, 0x43, 0x47, 0x6e, 0x37, 0x0a, 0x1d, 0xcd, 0x5f, 0x5d, 0x62, 0xc2, 0x33, 0x2a, 0xc5, 0xfc, 0xef, 0x32, 0x61, 0x24, 0x3d, 0x23, 0x61, 0x72, 0xd4, 0xea, 0x5d, 0x4b, 0x07, 0x96, 0x96, 0x98, 0xf3, 0x99, 0x5a, 0x7c, 0x7e, 0x68, 0xe5, 0x28, 0x98, 0x06, 0xc2, 0x4c, 0xf4, 0x13,\n\t0xff, 0x81, 0x0d, 0x93, 0x17, 0xfb, 0x9b, 0x49, 0x4a, 0x0c, 0x38, 0x3a, 0x4d, 0x74, 0x05, 0xd0, 0x15, 0x7f, 0x9b, 0x27, 0xd1, 0x8c, 0x10, 0x22, 0x89, 0x68, 0x1f, 0x81, 0xce, 0x51, 0x58, 0x8c, 0x05, 0x77, 0xac, 0x8d, 0x49, 0xf3, 0x58, 0xf4, 0x3f, 0xaa, 0x71, 0x89, 0xcd, 0x5a, 0x76, 0x83, 0x43, 0xf4, 0x88, 0xe5, 0x39, 0xbd, 0xe0, 0xc6, 0x9c, 0x39, 0x0e, 0xc7, 0xbf, 0x2f, 0xd5, 0xf1, 0x6f, 0xfd, 0x4b, 0x5c, 0x35, 0xcd, 0x54, 0x57, 0x67, 0x47, 0x5b, 0x43, 0x7d, 0x55, 0xa5, 0xc7, 0x65, 0xb7, 0x6a, 0x35, 0x84, 0x19, 0x98, 0x64, 0x59, 0x98, 0xa3, 0x28, 0x5e, 0x59, 0xe5, 0xd5, 0xa2, 0x71, 0x05, 0x8b, 0x4a, 0x3f, 0xd1, 0xac, 0xa5, 0x9d, 0x7b, 0xfa, 0xc4, 0x62, 0x5e, 0xa8, 0xd1, 0x81, 0xa9, 0x84, 0xae, 0xb4, 0x6b, 0x72, 0xd3, 0x64, 0x57, 0xa9, 0xe3, 0x3f, 0xdc, 0xc9, 0x0d,\n\t0x4d, 0x64, 0xef, 0x12, 0xf5, 0x9e, 0x94, 0xbe, 0xc6, 0x8d, 0xe7, 0xc6, 0xdf, 0x38, 0xf7, 0xb9, 0x69, 0x7f, 0xb6, 0x44, 0xdc, 0xc9, 0xc0, 0x48, 0x6c, 0xe6, 0x53, 0x35, 0x17, 0xcd, 0xc1, 0x0a, 0xab, 0xbf, 0xdc, 0x6b, 0xf7, 0x14, 0x35, 0x4f, 0xb4, 0x34, 0xd7, 0xcf, 0xff, 0x31, 0xd0, 0x1c, 0x75, 0x90, 0x57, 0xb9, 0x42, 0x4f, 0x15, 0x8e, 0x40, 0x85, 0xdf, 0xe1, 0x0e, 0x37, 0x0e, 0x37, 0x06, 0x7b, 0xdb, 0xea, 0x8a, 0x0b, 0x2a, 0x46, 0x0e, 0xb5, 0x93, 0xfa, 0xec, 0x69, 0x96, 0x5a, 0x9b, 0xac, 0x61, 0xfd, 0xd4, 0x50, 0xfa, 0x12, 0xfd, 0x1a, 0x73, 0x05, 0xee, 0x7c, 0xed, 0xa0, 0x8f, 0x85, 0xa0, 0x98, 0xf4, 0x40, 0x46, 0x36, 0x02, 0x20, 0x47, 0x95, 0x23, 0xa3, 0x40, 0x42, 0x04, 0x00, 0x23, 0x42, 0xfb, 0xe0, 0x52, 0x1f, 0x88, 0x19, 0xde, 0x16, 0xad, 0x24, 0x64, 0x24, 0x45,\n\t0xca, 0x28, 0x61, 0x7e, 0x28, 0xe2, 0x24, 0xe7, 0x16, 0x17, 0xb2, 0x29, 0x90, 0xcc, 0x59, 0xae, 0x11, 0x41, 0x75, 0xd4, 0xc2, 0x9b, 0xef, 0xbb, 0x27, 0xbf, 0x2f, 0x7a, 0xdc, 0x3a, 0xd8, 0x97, 0x26, 0x65, 0x34, 0x1c, 0x55, 0x5a, 0x4e, 0x53, 0x72, 0x81, 0xd9, 0xfa, 0xc1, 0x5f, 0x91, 0x6c, 0x59, 0xd4, 0x7b, 0x51, 0xa2, 0xea, 0x92, 0xdf, 0x22, 0xcc, 0x54, 0x85, 0xb3, 0x45, 0x87, 0x8a, 0x05, 0xd7, 0xd6, 0xf8, 0x30, 0x58, 0xc0, 0x6f, 0x2c, 0x54, 0xa0, 0xed, 0xce, 0xc0, 0xe1, 0xe3, 0x3c, 0xfe, 0x0f, 0x04, 0x0e, 0x34, 0x2c, 0x7d, 0x5e, 0x09, 0xce, 0xb5, 0x56, 0xda, 0xe3, 0xd1, 0xb0, 0x26, 0xfd, 0x5d, 0x50, 0x91, 0x7f, 0xca, 0x9c, 0x87, 0x31, 0x8a, 0x1e, 0xe9, 0x6a, 0xd8, 0xd8, 0x52, 0x98, 0x9d, 0x2b, 0x15, 0xc0, 0xde, 0x9e, 0xd4, 0x58, 0x0b, 0xb5, 0xe4, 0x96, 0x7f, 0xc9,\n\t0xc1, 0x1c, 0xbc, 0xba, 0xe6, 0xdc, 0x54, 0x42, 0x6b, 0x18, 0x2a, 0x50, 0x29, 0x5f, 0x9f, 0x2d, 0x4d, 0x04, 0x3b, 0xa7, 0x1b, 0xc8, 0xb5, 0xd9, 0xc9, 0x81, 0x6b, 0xde, 0x85, 0x16, 0x62, 0xcc, 0x05, 0xb8, 0xa6, 0x95, 0x84, 0x8d, 0x98, 0x06, 0xa7, 0x58, 0x86, 0x49, 0xe3, 0xf4, 0x3a, 0x92, 0x92, 0x97, 0x18, 0xe0, 0x5e, 0x92, 0xea, 0x24, 0xc5, 0x98, 0xa0, 0x5a, 0xdc, 0xc1, 0x15, 0x70, 0x46, 0x1f, 0x32, 0x8b, 0x3f, 0xcc, 0xde, 0x27, 0x85, 0xf7, 0x79, 0x15, 0x00, 0x47, 0x4f, 0x21, 0xdb, 0xc7, 0x93, 0x3c, 0xf0, 0x87, 0xf8, 0x52, 0xe4, 0xda, 0x61, 0x56, 0xe9, 0xdd, 0x29, 0xfc, 0x3b, 0x27, 0x7f, 0x52, 0x09, 0xad, 0x70, 0xf1, 0x38, 0xaa, 0x48, 0xb2, 0x33, 0xc3, 0x7b, 0xf9, 0x77, 0x7f, 0xc5, 0x9e, 0x4c, 0xf1, 0xe9, 0xea, 0x25, 0xbf, 0x02, 0x0e, 0x2f, 0xff, 0x05, 0x60, 0xb9,\n\t0xfe, 0x68, 0x02, 0xe5, 0x75, 0x25, 0x97, 0xeb, 0x8a, 0xc2, 0xd2, 0x6c, 0xc7, 0x94, 0x12, 0x20, 0x8f, 0x8a, 0xfb, 0x12, 0x34, 0x81, 0xe0, 0xde, 0xb2, 0x79, 0xe3, 0x86, 0xc9, 0x89, 0xb1, 0x35, 0x83, 0xfd, 0xbd, 0xf5, 0xb5, 0x15, 0x51, 0xbf, 0x17, 0x95, 0x8b, 0xe2, 0xe9, 0x89, 0x54, 0xf9, 0xf4, 0x44, 0x7e, 0xf6, 0x58, 0x98, 0xad, 0x2b, 0xed, 0x61, 0x6e, 0x92, 0xac, 0x08, 0x9d, 0x39, 0x2d, 0x26, 0xee, 0x63, 0x4f, 0x54, 0xaa, 0xd9, 0xa3, 0x08, 0x1f, 0xa2, 0x2f, 0x9a, 0x9f, 0xa8, 0xae, 0x29, 0xea, 0x70, 0x7a, 0x03, 0x95, 0xb1, 0xf4, 0xbf, 0x53, 0x5f, 0xca, 0x92, 0x3e, 0x75, 0xfb, 0x9b, 0xeb, 0x58, 0x2e, 0xa3, 0xd1, 0x9a, 0x5c, 0x2e, 0xa3, 0x94, 0x44, 0x2d, 0x0d, 0xb4, 0x39, 0xea, 0xee, 0x4f, 0x1d, 0x3b, 0x95, 0x3d, 0x52, 0xff, 0xd7, 0xb5, 0x5b, 0x73, 0x89, 0x8d, 0x2e,\n\t0x34, 0xb4, 0xfa, 0xdd, 0xf5, 0x97, 0x46, 0xb6, 0x7e, 0xbe, 0xcd, 0x2d, 0xa0, 0x38, 0x0a, 0xae, 0x5b, 0x92, 0xe2, 0x68, 0x7b, 0x54, 0x53, 0x64, 0x6b, 0xa9, 0xbf, 0x70, 0x27, 0x39, 0x96, 0x9d, 0x9f, 0x6e, 0xc4, 0x76, 0x84, 0xe3, 0xc8, 0xe9, 0x8b, 0x22, 0x07, 0xf3, 0x02, 0xd1, 0x09, 0xa4, 0x9c, 0x0f, 0x57, 0x5b, 0x43, 0xca, 0xa4, 0x08, 0x42, 0x42, 0xeb, 0xd9, 0x6c, 0x50, 0xce, 0xa3, 0xce, 0xdc, 0x17, 0x71, 0xf7, 0xf3, 0x6e, 0x51, 0x59, 0x08, 0x65, 0x8c, 0x67, 0x31, 0xdf, 0xc1, 0x26, 0x6b, 0xb1, 0x27, 0xb3, 0x98, 0xd0, 0x1c, 0x17, 0x57, 0x60, 0xb3, 0x7a, 0x04, 0x58, 0xe2, 0x39, 0xc0, 0x6b, 0xb1, 0xf2, 0x6c, 0x57, 0xc1, 0x99, 0xae, 0x48, 0xb4, 0x42, 0x47, 0x38, 0xf3, 0x48, 0x06, 0x31, 0x70, 0xcc, 0xdd, 0x54, 0x5f, 0xc1, 0x01, 0x0d, 0x52, 0x3a, 0x1d, 0x6d, 0xc9, 0x86,\n\t0xea, 0x84, 0x09, 0xf1, 0xaa, 0x7a, 0xfc, 0x61, 0x1f, 0x56, 0x3a, 0x2b, 0x27, 0x0f, 0xe1, 0xf4, 0x8f, 0x15, 0x48, 0x99, 0x2b, 0xcc, 0xd4, 0x11, 0x4f, 0xe7, 0x20, 0x9b, 0xf5, 0x91, 0xaf, 0x70, 0xd8, 0xc4, 0x90, 0xf4, 0xeb, 0x1c, 0x29, 0xf3, 0xc9, 0xc1, 0xb6, 0x5a, 0x3a, 0x4b, 0xaf, 0xfa, 0xf9, 0x90, 0x9c, 0xda, 0xee, 0xe3, 0x93, 0x41, 0x4e, 0x08, 0x35, 0x0e, 0xf9, 0x10, 0x97, 0x2e, 0x92, 0x65, 0x65, 0x1e, 0xc7, 0x2c, 0xaa, 0x9b, 0x95, 0x1c, 0x8b, 0xea, 0x70, 0x10, 0x8e, 0xe7, 0x1d, 0x70, 0x03, 0xfe, 0x36, 0xb4, 0x9d, 0x9b, 0x89, 0xc6, 0x64, 0x9d, 0x03, 0x63, 0x33, 0x79, 0xfc, 0x25, 0x3a, 0x55, 0x9c, 0x49, 0xe5, 0xa0, 0x30, 0xf9, 0xbd, 0x1a, 0xfe, 0xda, 0x4c, 0x34, 0xd7, 0xd7, 0x04, 0x7c, 0x6e, 0x97, 0xad, 0x20, 0x2e, 0x46, 0xc7, 0x34, 0x68, 0x57, 0xae, 0x03, 0xf9,\n\t0x05, 0x1a, 0x45, 0xcb, 0x6c, 0xd2, 0xa0, 0x15, 0x6d, 0xc2, 0x6f, 0x0c, 0x4c, 0x55, 0xe9, 0x72, 0xe1, 0x6a, 0x25, 0x18, 0xf2, 0x96, 0xca, 0xdd, 0x95, 0x1b, 0x36, 0x9d, 0x1d, 0xff, 0xd1, 0xb9, 0xcf, 0x4e, 0x07, 0x98, 0xeb, 0xef, 0x9f, 0x44, 0xdb, 0x6e, 0xce, 0x5e, 0x5c, 0x8f, 0x80, 0x6a, 0x35, 0x1d, 0x96, 0xe5, 0xf7, 0x61, 0xfa, 0x18, 0x9a, 0xbb, 0x27, 0xe0, 0x0b, 0xfc, 0x0c, 0xbe, 0xab, 0x99, 0x08, 0x22, 0x04, 0x17, 0x89, 0x33, 0x1e, 0xb9, 0xb3, 0x28, 0x8a, 0x0f, 0xed, 0xe1, 0x7a, 0x37, 0x5e, 0xa3, 0xc7, 0xc0, 0x46, 0xbd, 0x39, 0x7f, 0x9a, 0xcf, 0xa2, 0xab, 0x03, 0xe8, 0xa4, 0x89, 0xfe, 0x19, 0xb2, 0xe7, 0xa0, 0xd3, 0xfc, 0x7e, 0xdf, 0xad, 0x83, 0x45, 0xd7, 0x3a, 0x92, 0x26, 0x68, 0x20, 0xfe, 0x98, 0x92, 0x53, 0x97, 0x59, 0xf7, 0xd8, 0x9e, 0xdc, 0xd1, 0x4f, 0x7f,\n\t0xf6, 0xfd, 0x35, 0xab, 0xea, 0xc8, 0x6f, 0x3e, 0xcc, 0xee, 0xf9, 0x3b, 0xa0, 0x82, 0x7f, 0x95, 0x79, 0x8c, 0x10, 0x13, 0x6a, 0x22, 0x9a, 0x2c, 0x15, 0x21, 0x66, 0x18, 0x06, 0xe1, 0x0a, 0x29, 0x82, 0x4d, 0x88, 0x61, 0x18, 0x6c, 0x13, 0xb1, 0x04, 0xe0, 0xd3, 0x38, 0xe5, 0x12, 0xb3, 0xbf, 0xa3, 0x00, 0x8f, 0x27, 0x4b, 0xc0, 0x8f, 0xff, 0x51, 0xaf, 0x9e, 0x99, 0xff, 0xd2, 0x19, 0x6a, 0x0d, 0xfb, 0x7f, 0x70, 0x28, 0x7d, 0x8e, 0x0c, 0x83, 0x6e, 0xf6, 0x27, 0x01, 0x16, 0x0e, 0xa1, 0x5c, 0x71, 0x9c, 0xaf, 0x7d, 0x30, 0xa9, 0x32, 0x01, 0x92, 0xf6, 0x43, 0x63, 0x02, 0x8e, 0x2c, 0x43, 0x71, 0xc0, 0x36, 0x0f, 0xc5, 0x07, 0x2e, 0x77, 0xa4, 0x32, 0x85, 0x8d, 0x73, 0x12, 0xc8, 0x51, 0x5d, 0x63, 0x8a, 0x14, 0x91, 0x14, 0xce, 0x1e, 0x5e, 0xb1, 0xe9, 0x68, 0x52, 0x0d, 0x7f, 0x09,\n\t0x10, 0x81, 0xa0, 0xdf, 0x13, 0xf4, 0x6a, 0x51, 0xa1, 0x2c, 0x61, 0xc2, 0xf9, 0x12, 0x78, 0xb7, 0xfc, 0x04, 0xf4, 0xca, 0x7a, 0x77, 0x19, 0x42, 0x07, 0xa9, 0x4b, 0x58, 0x74, 0x50, 0x36, 0x1f, 0xfd, 0x0d, 0x36, 0x1f, 0x9d, 0x52, 0xe0, 0xd2, 0x81, 0xfd, 0xec, 0xf1, 0xf2, 0x3c, 0x85, 0x73, 0xd3, 0x7f, 0x87, 0xf3, 0xe3, 0x0e, 0xa5, 0x2f, 0xd2, 0xbf, 0xc0, 0x79, 0xda, 0x5f, 0x46, 0x59, 0xe8, 0x24, 0x9c, 0x5f, 0x8c, 0x48, 0xca, 0xbd, 0x2b, 0x3a, 0x30, 0x0f, 0x08, 0xde, 0x95, 0xc8, 0x7d, 0x7e, 0xb4, 0x15, 0x08, 0x00, 0xfd, 0x85, 0xb8, 0x18, 0x0c, 0xbc, 0x09, 0x24, 0xe2, 0xb9, 0xe5, 0x7b, 0x11, 0x82, 0x4e, 0xd0, 0x88, 0xe2, 0xa5, 0xc4, 0xf5, 0x23, 0x6e, 0xa2, 0x1b, 0x8a, 0xe4, 0x78, 0xbc, 0x7a, 0x24, 0xaf, 0x60, 0xa1, 0x94, 0x27, 0xf1, 0x15, 0x70, 0xb0, 0x2d, 0x2f, 0x34,\n\t0x01, 0xec, 0x9f, 0xfe, 0x05, 0x87, 0xc6, 0x5e, 0x49, 0x8a, 0xd7, 0x78, 0xe8, 0x36, 0x7f, 0x36, 0xff, 0xec, 0x4a, 0x12, 0xcd, 0x24, 0x04, 0x90, 0x84, 0x1e, 0xce, 0xd7, 0xb7, 0x30, 0xee, 0xca, 0x44, 0x94, 0x25, 0x4b, 0x68, 0x84, 0xfb, 0xed, 0x46, 0x45, 0xbd, 0x11, 0x95, 0xd1, 0x66, 0x2e, 0xdd, 0x81, 0x2b, 0xc1, 0x67, 0x32, 0x22, 0x6a, 0x5b, 0x39, 0xae, 0xae, 0x88, 0xaa, 0x7b, 0x03, 0x1e, 0x13, 0xc2, 0xd2, 0xcc, 0x7b, 0xc4, 0x2c, 0x1c, 0x84, 0xfc, 0xe4, 0x11, 0xa9, 0x5e, 0x26, 0x35, 0x48, 0x8f, 0x90, 0xf7, 0x3f, 0x50, 0xe0, 0x94, 0xf4, 0xa4, 0xc7, 0x7a, 0x44, 0x1e, 0xcb, 0x83, 0xe0, 0xbe, 0xaf, 0x81, 0x3b, 0x40, 0x9f, 0xb9, 0xc9, 0xe7, 0x6f, 0x32, 0xa7, 0x5f, 0x48, 0xdf, 0x61, 0xd1, 0x7f, 0xf7, 0xbb, 0x5a, 0x2b, 0x42, 0xa4, 0x90, 0x0b, 0x69, 0xb8, 0x66, 0xff, 0x27,\n\t0x8e, 0xf5, 0x5a, 0x88, 0xbe, 0x64, 0x0a, 0xba, 0x1d, 0xd0, 0x97, 0xc1, 0x58, 0x6e, 0x40, 0x6e, 0x42, 0xee, 0x03, 0x43, 0x11, 0xcc, 0x26, 0xc4, 0x8c, 0x9d, 0xa5, 0x5b, 0xa6, 0xc7, 0xb8, 0x02, 0x3c, 0x22, 0x11, 0x74, 0x2d, 0x2d, 0x22, 0x54, 0x78, 0x47, 0x8f, 0xb2, 0xbe, 0x15, 0x72, 0x99, 0x54, 0x22, 0x46, 0xe1, 0x61, 0x39, 0x7e, 0x4c, 0xfc, 0x8c, 0x7a, 0xb8, 0xbe, 0xd1, 0xbf, 0x20, 0xf7, 0x9c, 0x1e, 0x23, 0xf9, 0xa1, 0x06, 0xb9, 0x45, 0xf9, 0x79, 0x70, 0xa9, 0x10, 0xcc, 0xa6, 0x9f, 0x29, 0x04, 0x0f, 0xcc, 0xff, 0xc0, 0x95, 0x7e, 0x60, 0x5a, 0xe2, 0xb3, 0xde, 0x47, 0x32, 0xe4, 0x5b, 0xf0, 0x61, 0xff, 0x10, 0x68, 0xb2, 0xa7, 0x1f, 0x02, 0xff, 0x86, 0x73, 0xa0, 0x1e, 0x7e, 0xf7, 0xbb, 0x06, 0x33, 0xf5, 0xce, 0xc3, 0xd8, 0x86, 0xeb, 0x59, 0x78, 0x53, 0xa4, 0xa0, 0xe5,\n\t0x58, 0x6e, 0xa3, 0xc4, 0x37, 0x38, 0x36, 0xd7, 0xee, 0x16, 0x68, 0x68, 0x87, 0xbd, 0x24, 0x81, 0x4b, 0xea, 0xe0, 0x4b, 0x29, 0x77, 0x39, 0xca, 0x7b, 0xf8, 0x32, 0x8a, 0xa4, 0x64, 0x88, 0x25, 0x0a, 0x1a, 0xfa, 0x0c, 0x31, 0x27, 0x01, 0xa4, 0x52, 0x45, 0x02, 0x86, 0x84, 0x66, 0x15, 0x32, 0x67, 0xc6, 0x14, 0x40, 0x2e, 0xdf, 0x9d, 0xa2, 0x71, 0x9c, 0x13, 0xad, 0xc4, 0x9d, 0x28, 0x25, 0xa0, 0x91, 0x90, 0x49, 0x49, 0xe9, 0xd2, 0xdd, 0x88, 0x6c, 0x2f, 0xb8, 0xc7, 0x2d, 0xf9, 0x05, 0xa3, 0xc9, 0x42, 0x82, 0x18, 0x1d, 0x59, 0xdd, 0xd7, 0xd9, 0x9e, 0x6c, 0xac, 0xab, 0x89, 0xc7, 0x4a, 0x8b, 0x83, 0x7e, 0x04, 0x1f, 0xd3, 0x69, 0xd8, 0x62, 0x99, 0x3e, 0x75, 0x96, 0xf8, 0xac, 0x09, 0x93, 0xe7, 0x06, 0xd8, 0x5d, 0x2b, 0x9f, 0x97, 0x38, 0xc8, 0x7b, 0xd2, 0x02, 0x32, 0x34, 0x96,\n\t0xb5, 0x4b, 0x68, 0x1a, 0x89, 0xdf, 0x75, 0xd6, 0x0e, 0x25, 0x0e, 0x9e, 0x56, 0x7d, 0xe9, 0xd6, 0x27, 0xb7, 0x44, 0x26, 0xfb, 0xaa, 0x36, 0x74, 0x84, 0xa7, 0x26, 0x93, 0xeb, 0x10, 0xad, 0xae, 0x5d, 0xe6, 0x1d, 0xfa, 0xe2, 0xbe, 0x43, 0x17, 0xbd, 0x89, 0xcf, 0x1e, 0x5c, 0x73, 0xff, 0xf6, 0x7a, 0xad, 0x8d, 0xdc, 0xc3, 0x44, 0x52, 0xb3, 0x0d, 0x6d, 0xeb, 0xeb, 0x03, 0x5a, 0xbb, 0xb2, 0xd2, 0xbb, 0x7e, 0x66, 0x47, 0xe5, 0xbe, 0xaf, 0xd6, 0xd8, 0xd7, 0x6d, 0x3f, 0x54, 0xdf, 0xbe, 0x7f, 0x4d, 0x69, 0xf2, 0xe2, 0x9f, 0x9e, 0x05, 0x4f, 0x34, 0x6c, 0xeb, 0x2b, 0x79, 0xf8, 0xae, 0xc3, 0x4c, 0x61, 0xbc, 0x2d, 0x34, 0x98, 0xf2, 0xb6, 0xef, 0xe8, 0x7a, 0xeb, 0x96, 0x5b, 0x0b, 0x43, 0x85, 0x46, 0x75, 0xd3, 0xc0, 0xea, 0xcd, 0xc3, 0x43, 0x9b, 0x9a, 0x8f, 0x7c, 0x7e, 0x2e, 0xe2,\n\t0x1a, 0xbe, 0x63, 0x6d, 0x91, 0xdd, 0x6b, 0xd7, 0xaf, 0x2a, 0xaa, 0x0f, 0xea, 0x76, 0xcd, 0xd5, 0xaf, 0x4d, 0x14, 0xf8, 0x3a, 0x76, 0x74, 0xd6, 0xef, 0x1f, 0xaf, 0xa7, 0xe1, 0xb8, 0x55, 0xc2, 0xc1, 0x43, 0xb5, 0xd5, 0x54, 0x70, 0x77, 0x28, 0x25, 0x86, 0x93, 0x6b, 0xdc, 0x39, 0xe7, 0x1e, 0x52, 0x54, 0x0b, 0x8b, 0x82, 0x3b, 0xe3, 0x26, 0x39, 0x40, 0x45, 0xbd, 0x14, 0x58, 0x15, 0xca, 0x00, 0x17, 0xa3, 0x9f, 0x16, 0xf7, 0x14, 0x58, 0xd4, 0x6a, 0x40, 0xe0, 0x14, 0xbd, 0x80, 0xa5, 0xb4, 0xa0, 0x54, 0x6d, 0x56, 0x9b, 0x74, 0x1a, 0x3c, 0xe5, 0xc4, 0x84, 0x0a, 0xa8, 0x94, 0x19, 0x27, 0x36, 0x50, 0x0c, 0x8c, 0x31, 0xa3, 0xd7, 0x58, 0xc0, 0x32, 0xa0, 0x06, 0xbc, 0x71, 0x1e, 0xb6, 0xcf, 0x42, 0xe4, 0xe3, 0x08, 0x68, 0x48, 0xd6, 0xc7, 0x3b, 0x8b, 0xf5, 0xeb, 0xa6, 0xbf, 0x7a,\n\t0xf5, 0xea, 0x87, 0x36, 0x4d, 0x8f, 0x6e, 0x9a, 0xba, 0x30, 0x56, 0xb4, 0x76, 0xf2, 0x7b, 0xe5, 0x93, 0xe7, 0x47, 0xd3, 0x77, 0xde, 0x73, 0xcf, 0x7d, 0xb6, 0xe2, 0x6a, 0x47, 0xfb, 0x9a, 0xed, 0xeb, 0xe7, 0xc8, 0x9f, 0xa5, 0x7f, 0xd0, 0x3b, 0xd8, 0xdd, 0x7e, 0xc1, 0xdf, 0x3a, 0x51, 0xdd, 0x7f, 0xb4, 0x30, 0x7a, 0x35, 0xb9, 0xb3, 0xbf, 0x74, 0x61, 0x3d, 0xf9, 0x71, 0x6c, 0xaf, 0xf5, 0x2d, 0xfc, 0x85, 0xfa, 0x0c, 0x4d, 0x11, 0x25, 0xc4, 0x21, 0x94, 0x2d, 0x4c, 0x23, 0xde, 0x10, 0x26, 0xcb, 0x4d, 0x49, 0xd1, 0xd0, 0x8a, 0x46, 0x5b, 0x3d, 0xc1, 0xd0, 0x04, 0xb3, 0x9b, 0x77, 0xc0, 0x76, 0x67, 0x15, 0x17, 0xc0, 0x47, 0x80, 0x1f, 0xd8, 0x8e, 0xc7, 0x1f, 0x22, 0xe0, 0x86, 0xc5, 0xa4, 0x55, 0x43, 0x13, 0xba, 0x04, 0x94, 0xb0, 0x69, 0x00, 0xae, 0xbc, 0x30, 0x8b, 0x78, 0xf1,\n\t0xb1, 0x77, 0x55, 0x82, 0x5a, 0xa5, 0x91, 0xa7, 0x1a, 0x5f, 0x3c, 0xb6, 0xf7, 0xea, 0x1d, 0xad, 0x5d, 0xa7, 0xbf, 0xb4, 0x67, 0xee, 0x4a, 0x43, 0x93, 0x08, 0xda, 0xc0, 0x85, 0xf1, 0xfe, 0xfa, 0xd6, 0x7d, 0x03, 0xa5, 0xd1, 0x35, 0x73, 0xcd, 0xc1, 0xc6, 0x78, 0x99, 0x45, 0xfd, 0xa6, 0x7c, 0xb0, 0x77, 0x00, 0x1f, 0xe8, 0xbd, 0x7a, 0xbe, 0xa7, 0xb3, 0x7e, 0x54, 0x82, 0x4c, 0xda, 0xe8, 0xd8, 0xa9, 0xb5, 0xc3, 0xa7, 0xc7, 0xa2, 0x12, 0x9d, 0xc3, 0xa8, 0x64, 0x73, 0x2c, 0x68, 0x84, 0x63, 0x53, 0x10, 0x05, 0xf8, 0x94, 0x88, 0xb3, 0xff, 0x66, 0x33, 0xa7, 0xdb, 0x70, 0x8b, 0xf5, 0x84, 0x3c, 0x18, 0x7b, 0x01, 0xd8, 0xcc, 0x04, 0x94, 0x3d, 0x21, 0x66, 0x13, 0x16, 0xd0, 0x23, 0xd1, 0xaa, 0xee, 0xbb, 0x5e, 0xdd, 0x9f, 0x3e, 0x0e, 0x4e, 0xec, 0x7f, 0xf5, 0xae, 0xee, 0xd7, 0x4a,\n\t0xd6, 0x1e, 0x4a, 0x7d, 0xe3, 0x1b, 0xa9, 0x43, 0x6b, 0x4b, 0xc0, 0xfc, 0xdc, 0xcb, 0x77, 0xa5, 0xa8, 0x77, 0x52, 0x67, 0x5e, 0xde, 0x33, 0x78, 0x6a, 0xbc, 0x7c, 0xbe, 0xba, 0x7c, 0xec, 0x34, 0xd2, 0x99, 0x46, 0xf8, 0x37, 0x0b, 0xe0, 0xdf, 0xd4, 0x10, 0x1e, 0xa2, 0x29, 0x59, 0x2f, 0x46, 0x5e, 0x09, 0x9e, 0x33, 0xf8, 0x9c, 0x54, 0x8a, 0x33, 0xfa, 0x24, 0x3c, 0x40, 0x7a, 0x9a, 0xe9, 0xd1, 0x69, 0x01, 0x81, 0x6a, 0xa5, 0xd9, 0xad, 0x5a, 0x8f, 0xce, 0x83, 0xf5, 0x93, 0x94, 0xd0, 0x00, 0x8d, 0x20, 0xde, 0x81, 0x1f, 0xc6, 0xe8, 0xd5, 0xea, 0x79, 0xdf, 0x02, 0xee, 0xff, 0x68, 0x76, 0x98, 0xbb, 0x0f, 0xad, 0x2d, 0x2d, 0x5d, 0x7b, 0xa8, 0xfb, 0x9b, 0xe9, 0xf4, 0x37, 0x6f, 0x81, 0xcf, 0x07, 0x9f, 0xf5, 0x96, 0xf4, 0xb1, 0xdb, 0x6f, 0xff, 0x08, 0x7c, 0x96, 0xb5, 0xe8, 0xa9,\n\t0xd2, 0x3f, 0xda, 0x99, 0xfe, 0x1e, 0xb5, 0x11, 0x3d, 0x24, 0x7a, 0x5c, 0xf0, 0xed, 0x9d, 0xe0, 0x1a, 0x97, 0x27, 0x2c, 0xc5, 0x18, 0x2c, 0xa8, 0xd5, 0x09, 0x96, 0xa8, 0x76, 0x13, 0x66, 0x1d, 0x19, 0xe5, 0x73, 0xb0, 0x30, 0x66, 0x0c, 0x33, 0x66, 0xc0, 0x56, 0x72, 0x6c, 0x85, 0xb0, 0x27, 0x7b, 0x7c, 0x1e, 0xa9, 0xc7, 0x08, 0xda, 0x51, 0x8e, 0x28, 0xb8, 0x36, 0x7f, 0x07, 0x79, 0x07, 0xb5, 0x81, 0xd5, 0x82, 0x48, 0x03, 0x02, 0xa2, 0x7c, 0xe1, 0xcf, 0x54, 0x3d, 0x2d, 0x21, 0x9a, 0x50, 0xad, 0x3c, 0x25, 0xb4, 0x72, 0xac, 0x38, 0xa7, 0x0e, 0x95, 0xfe, 0x16, 0x89, 0x51, 0x8c, 0x9b, 0xc3, 0x41, 0x31, 0x88, 0x50, 0x8d, 0x9e, 0xe2, 0x2b, 0x80, 0xe7, 0xe0, 0x30, 0x1b, 0xeb, 0x6b, 0xaa, 0xca, 0xcb, 0x10, 0x57, 0xac, 0xcb, 0x61, 0x31, 0xb1, 0xdc, 0x8b, 0xd9, 0x92, 0xad, 0x7c,\n\t0x08, 0x3b, 0xb0, 0x44, 0x04, 0x3b, 0x87, 0x26, 0x2d, 0xf8, 0xbf, 0x99, 0x7b, 0xef, 0xf8, 0xb8, 0xaa, 0x33, 0x7f, 0xf8, 0x9e, 0x5b, 0xa6, 0xb7, 0x3b, 0x77, 0x7a, 0xbf, 0xd3, 0x35, 0x45, 0x33, 0xd2, 0x34, 0x75, 0x8d, 0x7a, 0xb5, 0xe5, 0x26, 0xd9, 0xb2, 0xdc, 0x25, 0xcb, 0x0d, 0xe3, 0x46, 0x31, 0x60, 0x63, 0x8a, 0x29, 0xb6, 0xc1, 0x06, 0x4c, 0x30, 0xb0, 0x26, 0x01, 0x42, 0x09, 0x25, 0x04, 0x08, 0x90, 0x90, 0xd0, 0x4b, 0x76, 0x93, 0x25, 0x6d, 0x13, 0x9c, 0xdf, 0xb2, 0x3f, 0x02, 0xd9, 0x6c, 0x92, 0x25, 0x09, 0x09, 0x90, 0x90, 0x90, 0x80, 0xae, 0xdf, 0x73, 0xce, 0xbd, 0x53, 0x24, 0xcb, 0x40, 0xf2, 0xbe, 0x7f, 0xbc, 0xf9, 0x10, 0x8f, 0x66, 0x6e, 0x39, 0xfd, 0xe9, 0xcf, 0xf7, 0xa9, 0x2b, 0x61, 0xdd, 0x75, 0x4e, 0x8f, 0x26, 0xdb, 0x10, 0xd6, 0xdd, 0xcd, 0x93, 0xbb, 0xef,\n\t0x6d, 0x4c, 0xaa, 0x39, 0x9d, 0x36, 0xd4, 0xb0, 0xa8, 0x29, 0x3b, 0x92, 0x73, 0x78, 0x9b, 0x97, 0xe5, 0xf7, 0xec, 0xb9, 0xe4, 0x02, 0x6f, 0xe3, 0x92, 0xac, 0x04, 0x91, 0x47, 0x6d, 0x8b, 0x21, 0xd0, 0xbb, 0x85, 0xbb, 0xfa, 0xc7, 0x2e, 0x46, 0xa0, 0x77, 0x45, 0x6f, 0x7e, 0x72, 0x41, 0xb2, 0x3b, 0x3f, 0x5c, 0x86, 0xc8, 0xf3, 0xe6, 0xc3, 0x96, 0x2b, 0x46, 0xfb, 0x43, 0xed, 0x49, 0x04, 0x92, 0xc7, 0xa1, 0xb5, 0x9f, 0x12, 0xc6, 0xc1, 0x2e, 0x38, 0xaf, 0x94, 0x24, 0x5d, 0xa2, 0xd4, 0x2c, 0x09, 0xf4, 0x1f, 0xce, 0x28, 0x32, 0xd3, 0x6f, 0x45, 0x33, 0x6a, 0x32, 0xaa, 0x14, 0xf0, 0x1e, 0x8a, 0x65, 0xe0, 0xa0, 0x50, 0x38, 0x31, 0x35, 0x07, 0x3c, 0xf3, 0xd0, 0xcb, 0xff, 0x6b, 0x09, 0xd5, 0x3b, 0xab, 0x1d, 0xbf, 0x28, 0x65, 0x53, 0xf8, 0x85, 0xb3, 0x2e, 0x68, 0xb1, 0x04, 0xeb,\n\t0x9c, 0xae, 0x7a, 0x74, 0xa5, 0x1e, 0x9d, 0x6d, 0xdd, 0xe9, 0x0f, 0xc1, 0x07, 0x38, 0xe7, 0xfb, 0x1c, 0x6c, 0xb0, 0x7d, 0x52, 0x0e, 0x08, 0x9c, 0x63, 0x25, 0xc7, 0xb1, 0xa1, 0x92, 0xb6, 0xcf, 0x12, 0x62, 0xf0, 0xa6, 0x94, 0x92, 0x71, 0x0e, 0x51, 0x32, 0xef, 0xce, 0xb9, 0xb0, 0x63, 0x6e, 0x54, 0x4d, 0x25, 0x21, 0x0f, 0x45, 0xd5, 0x8c, 0x3f, 0xc5, 0xf9, 0x2d, 0x95, 0xe3, 0xe2, 0x8f, 0xb4, 0x81, 0xea, 0xa4, 0x7e, 0xf0, 0x41, 0x6c, 0xd9, 0xfe, 0x25, 0x43, 0xc3, 0x50, 0xb3, 0x22, 0x39, 0x93, 0x3a, 0xe2, 0x59, 0xbc, 0xf4, 0x59, 0xb0, 0x65, 0xf4, 0xf0, 0xfa, 0x2c, 0xe7, 0x6a, 0x74, 0x19, 0x38, 0xd5, 0xfa, 0xdd, 0xe4, 0x71, 0x69, 0xff, 0xfd, 0x1a, 0xf6, 0xd9, 0x85, 0x66, 0xc9, 0x31, 0x4f, 0x56, 0x91, 0x24, 0xfe, 0x06, 0x79, 0x96, 0x0d, 0xf9, 0x90, 0x0c, 0xce, 0x57, 0x57,\n\t0x31, 0x45, 0xd9, 0x43, 0x12, 0x02, 0x15, 0x64, 0xde, 0x16, 0x2b, 0xf5, 0xeb, 0xfb, 0x79, 0x9f, 0x46, 0x78, 0x5b, 0x17, 0xe0, 0x9b, 0x9f, 0x79, 0x26, 0x91, 0xb1, 0x02, 0x3b, 0x1b, 0x75, 0xdf, 0x2d, 0x3c, 0xa0, 0x77, 0xb3, 0x71, 0x3f, 0xc7, 0x81, 0x0b, 0x38, 0xbd, 0xd0, 0x49, 0x7d, 0x24, 0x2c, 0xf7, 0x82, 0xf5, 0x56, 0xa3, 0xb0, 0xd2, 0xe4, 0x54, 0x18, 0x52, 0xb0, 0xbd, 0x0e, 0xd8, 0x0f, 0x05, 0xec, 0x07, 0x4b, 0xc4, 0x8a, 0x11, 0x83, 0x46, 0xad, 0xa0, 0x29, 0x19, 0x4a, 0x50, 0x9b, 0xcf, 0x9d, 0xcc, 0x12, 0xac, 0xb5, 0xec, 0x4e, 0x96, 0xe7, 0xb2, 0xed, 0xf0, 0x4c, 0xb2, 0x21, 0xb3, 0x49, 0x0f, 0x58, 0x4a, 0x31, 0xf3, 0xc8, 0xf9, 0x96, 0xb5, 0xcf, 0x00, 0x99, 0xed, 0x0f, 0x5f, 0xfc, 0x22, 0x38, 0xb7, 0xf9, 0xa0, 0x4d, 0x59, 0x0f, 0xfe, 0x20, 0x6c, 0xbe, 0xf2, 0x32,\n\t0xb7, 0x72, 0x9f, 0xf0, 0xa6, 0x94, 0x1f, 0xfd, 0x21, 0xbd, 0x18, 0xe7, 0x95, 0x47, 0x88, 0x36, 0x71, 0x51, 0xcc, 0x44, 0x25, 0xef, 0xad, 0x12, 0x6e, 0xe3, 0x9c, 0xef, 0x77, 0x1c, 0xd2, 0x84, 0xc2, 0x70, 0x2a, 0x73, 0x5f, 0x89, 0x27, 0x98, 0x1b, 0x82, 0x43, 0x2f, 0x46, 0x84, 0xa0, 0x44, 0x10, 0xd0, 0xe7, 0x0b, 0xc9, 0xa5, 0x17, 0x0e, 0x95, 0xa8, 0xc5, 0xd0, 0x85, 0x4b, 0x93, 0x90, 0x7c, 0x3d, 0x7f, 0x64, 0xe1, 0xc2, 0x23, 0xcf, 0xe3, 0x4c, 0xee, 0x85, 0x47, 0x9e, 0xc3, 0x44, 0xac, 0x6e, 0xd5, 0xc1, 0x25, 0xcb, 0x0e, 0xae, 0x4a, 0xa7, 0x57, 0x1d, 0xc4, 0x7c, 0x23, 0x07, 0xf9, 0xc6, 0xb1, 0x12, 0xdf, 0x70, 0x40, 0x1e, 0x18, 0xab, 0xc2, 0xc3, 0x0e, 0x95, 0x80, 0xae, 0x65, 0xe0, 0x53, 0x01, 0xb1, 0x3f, 0xc7, 0x7d, 0x38, 0xb4, 0x06, 0xf2, 0x8d, 0x68, 0xd8, 0xe3, 0x42,\n\t0xc8, 0xd0, 0x0a, 0x59, 0x89, 0x6f, 0x14, 0xea, 0xad, 0x25, 0x84, 0xd0, 0x79, 0x80, 0x0f, 0x25, 0x0a, 0x90, 0xbf, 0xdd, 0xa0, 0xb7, 0xa5, 0x72, 0x6d, 0x91, 0xe2, 0xae, 0x65, 0xe9, 0xe4, 0x92, 0x5d, 0xdd, 0x2d, 0x8b, 0x72, 0x7e, 0x83, 0xde, 0x28, 0x6b, 0x6f, 0x79, 0x68, 0xe7, 0x8e, 0xa7, 0xaf, 0x1a, 0xe8, 0xbe, 0xec, 0xc9, 0x9d, 0x97, 0x3e, 0xd9, 0x36, 0xa8, 0x79, 0x4f, 0x6b, 0x76, 0x1b, 0x15, 0xe9, 0x89, 0xab, 0xc6, 0x96, 0x1d, 0x9c, 0x48, 0x43, 0x8e, 0xa1, 0x55, 0x8c, 0xb7, 0xf4, 0x0f, 0x1f, 0x7e, 0x6e, 0xf7, 0xee, 0xe7, 0x0f, 0x43, 0x7e, 0xb2, 0x44, 0x8d, 0xd7, 0x6a, 0x84, 0x30, 0xd1, 0xd3, 0xd4, 0x6f, 0xe0, 0x5a, 0x05, 0x88, 0xe6, 0xa1, 0x47, 0xeb, 0xa5, 0xb5, 0xc2, 0x2b, 0x51, 0x09, 0xd6, 0xc4, 0xf8, 0x55, 0x46, 0x9c, 0x20, 0x08, 0xd6, 0x96, 0x2f, 0x93, 0x70,\n\t0xa1, 0xc2, 0xd2, 0x42, 0x71, 0x73, 0xce, 0x75, 0xa8, 0x04, 0x33, 0x84, 0x45, 0xa9, 0x11, 0x31, 0x78, 0xe7, 0xd0, 0xc0, 0xc0, 0x21, 0x11, 0x80, 0x80, 0xba, 0x0a, 0xc5, 0xf7, 0x7c, 0xeb, 0x85, 0xec, 0x06, 0xf8, 0xef, 0xf3, 0xe0, 0xf4, 0xce, 0x27, 0x0e, 0xf4, 0xf4, 0x1c, 0x78, 0x62, 0xe7, 0xae, 0xa7, 0xd0, 0xe7, 0x53, 0xbb, 0xfa, 0xcf, 0x1d, 0x8e, 0xdc, 0x76, 0xc3, 0xc0, 0xce, 0x05, 0x11, 0xa9, 0x9e, 0xf4, 0x52, 0xe2, 0x16, 0x7a, 0x2b, 0xf5, 0x6b, 0x22, 0x4e, 0xd8, 0x8b, 0x96, 0xa8, 0x8d, 0x24, 0xfa, 0x4a, 0xc0, 0x6e, 0xd3, 0x90, 0xb1, 0x79, 0x6b, 0x48, 0xa4, 0x92, 0x67, 0x0b, 0x95, 0xc2, 0xd7, 0xc8, 0x46, 0x05, 0x05, 0x0c, 0x99, 0x1e, 0x54, 0xd7, 0xb3, 0x95, 0xc9, 0x23, 0xb5, 0x80, 0xba, 0x40, 0x9b, 0x88, 0xd6, 0xae, 0xb9, 0x7e, 0xdd, 0xda, 0xa3, 0x6b, 0x6a, 0x6b,\n\t0x12, 0x5a, 0x46, 0xbe, 0xb2, 0x67, 0xa0, 0xdc, 0xc3, 0x9e, 0x95, 0x0a, 0x1a, 0x50, 0x06, 0x43, 0x62, 0x63, 0xb1, 0x7f, 0xf7, 0x48, 0x3c, 0x3e, 0xb2, 0xbb, 0xbf, 0xb8, 0x31, 0x61, 0x30, 0xc8, 0x75, 0xcc, 0xd2, 0xee, 0x47, 0xf7, 0x9c, 0xf7, 0xd4, 0xfe, 0xce, 0xce, 0xfd, 0x4f, 0x9d, 0xb7, 0xe7, 0xd1, 0xee, 0xa5, 0x8c, 0x0e, 0xcb, 0xc0, 0x4b, 0x08, 0x25, 0xfd, 0x07, 0x5a, 0x4e, 0xa0, 0x4c, 0xcb, 0x1c, 0x94, 0xa5, 0xec, 0x61, 0xc8, 0x03, 0xea, 0x7c, 0x9c, 0x12, 0x1e, 0x74, 0x33, 0xae, 0xb1, 0x17, 0x02, 0x54, 0xbf, 0x09, 0x90, 0x7d, 0xa5, 0x09, 0x96, 0xd2, 0xa7, 0x2a, 0x59, 0x26, 0x18, 0x37, 0x41, 0x44, 0xbf, 0x25, 0xd7, 0x96, 0x2f, 0x43, 0x19, 0xe3, 0xa9, 0x54, 0x28, 0x1a, 0xc6, 0x27, 0x41, 0x9a, 0xcb, 0x76, 0x20, 0x91, 0x7c, 0x39, 0xa8, 0xc8, 0xa0, 0x05, 0x6c, 0x6a,\n\t0xb1, 0x56, 0x50, 0x32, 0x51, 0xc8, 0x3e, 0x18, 0xcb, 0xa3, 0xe9, 0x3d, 0xb9, 0x7a, 0x79, 0x34, 0x03, 0x27, 0xfb, 0xf0, 0x72, 0x2a, 0xf7, 0x83, 0x9e, 0x57, 0xf7, 0xa3, 0xe9, 0x0f, 0x05, 0x16, 0x7a, 0xad, 0x3f, 0xe9, 0xfe, 0xf6, 0xf9, 0xe8, 0x8b, 0xd7, 0x3d, 0xc4, 0x3b, 0xc8, 0xc7, 0xfa, 0xb6, 0xa1, 0xe9, 0x2e, 0x8c, 0x15, 0xd7, 0xa1, 0xc9, 0x8f, 0xcd, 0xa8, 0x6f, 0xed, 0x1e, 0x40, 0x4b, 0x31, 0x72, 0x6d, 0x63, 0x93, 0x29, 0x18, 0xdc, 0x70, 0xb2, 0xa5, 0x88, 0x56, 0x68, 0xe0, 0xd2, 0x7c, 0x83, 0xa5, 0xd3, 0x87, 0xc6, 0xbd, 0xe0, 0xf4, 0x07, 0xb2, 0x83, 0x18, 0xa7, 0xd7, 0x02, 0x97, 0xe3, 0xc6, 0xa2, 0xca, 0x0b, 0x54, 0x20, 0x85, 0x73, 0xe6, 0xc5, 0x73, 0x13, 0x27, 0xa0, 0xa2, 0x02, 0x54, 0x0a, 0xa8, 0x2d, 0x6a, 0xa0, 0x64, 0xa0, 0xa0, 0xd6, 0x2b, 0xab, 0x70, 0x23,\n\t0x48, 0x35, 0x39, 0x4b, 0xb6, 0xff, 0xdc, 0x77, 0x63, 0xdc, 0x6a, 0x5e, 0xa7, 0x03, 0x44, 0x6f, 0x77, 0x47, 0x7b, 0x73, 0x63, 0xa6, 0x2e, 0x19, 0x0f, 0xf0, 0x6e, 0xa7, 0xce, 0xa2, 0xb3, 0x98, 0x8c, 0x50, 0xfc, 0xd4, 0x02, 0x6d, 0x95, 0xf8, 0x59, 0x8a, 0x3c, 0xaa, 0x42, 0x33, 0xb6, 0x58, 0x67, 0x9f, 0xab, 0x79, 0x84, 0xf9, 0x08, 0xfd, 0xb5, 0xee, 0xa9, 0x4e, 0xfe, 0xca, 0x6b, 0xaf, 0xbe, 0xf2, 0xca, 0x4f, 0x7e, 0xec, 0x69, 0x5c, 0x96, 0xbf, 0xe0, 0xa0, 0x6e, 0x66, 0x0f, 0x16, 0xca, 0xcf, 0x7b, 0xae, 0xb1, 0xf0, 0xd2, 0xd5, 0x53, 0xf7, 0x5f, 0xd0, 0xd9, 0xb9, 0xf7, 0x81, 0x4d, 0x57, 0x3c, 0x97, 0xcf, 0x3e, 0x7d, 0xe5, 0xd2, 0x63, 0x5b, 0x5a, 0x8c, 0x4e, 0x72, 0x1b, 0x93, 0x84, 0x22, 0x7c, 0xcb, 0x58, 0xb1, 0x96, 0xb3, 0x68, 0x0f, 0xd7, 0xaf, 0x3b, 0xbc, 0xe2, 0xd1,\n\t0x17, 0x5f, 0x78, 0xec, 0xd1, 0x57, 0x80, 0x55, 0x94, 0xdb, 0xc1, 0xbf, 0xa1, 0x18, 0xc5, 0x1d, 0x7b, 0xce, 0xb9, 0x40, 0x3c, 0x0a, 0xd7, 0x0e, 0xec, 0xd9, 0xba, 0x71, 0x6f, 0xc7, 0xc5, 0x25, 0x91, 0x5d, 0x8c, 0x60, 0x25, 0x89, 0x65, 0x90, 0x1e, 0x9d, 0x03, 0xe9, 0x35, 0x07, 0x4f, 0xe8, 0x92, 0xa2, 0xb2, 0x3b, 0xed, 0x52, 0xd1, 0x62, 0x06, 0xaf, 0x12, 0x63, 0x11, 0x88, 0x88, 0x27, 0x74, 0xc9, 0x8a, 0x83, 0xc5, 0xd6, 0x33, 0x7e, 0x15, 0x85, 0x54, 0x8c, 0xa8, 0x31, 0x62, 0x5a, 0xd8, 0xd4, 0x10, 0x09, 0xa1, 0x18, 0x2d, 0x59, 0x95, 0xb8, 0x15, 0x11, 0x13, 0x62, 0x80, 0x98, 0xae, 0x2a, 0x9f, 0x93, 0x37, 0x83, 0x02, 0xf8, 0xf2, 0x05, 0x38, 0x5d, 0xa5, 0xda, 0xc3, 0x58, 0x21, 0x8a, 0x84, 0xf3, 0x19, 0xf0, 0x76, 0x72, 0xa4, 0xc5, 0x1f, 0x6a, 0x5f, 0x56, 0x1b, 0x1b, 0x2a,\n\t0xf0, 0xfe, 0xe6, 0x11, 0x70, 0xbe, 0x8d, 0xe3, 0x0b, 0x43, 0xb1, 0xda, 0x65, 0xed, 0xa1, 0xdc, 0xc6, 0x9b, 0xd7, 0xac, 0x39, 0x3e, 0x9d, 0x8b, 0x74, 0x8c, 0xa6, 0xe2, 0x0b, 0x1a, 0xfd, 0x26, 0xe7, 0xb5, 0x66, 0x56, 0xa5, 0xd2, 0xfa, 0x1a, 0x06, 0x62, 0xa1, 0xf6, 0x94, 0x53, 0xab, 0x54, 0x19, 0x7d, 0x87, 0x4d, 0xb1, 0xae, 0x54, 0x4d, 0x7b, 0x26, 0x66, 0xe2, 0x62, 0x99, 0x62, 0x4d, 0xaa, 0x2b, 0x66, 0xa2, 0xce, 0xe5, 0x87, 0xfd, 0xf5, 0x23, 0xed, 0xf5, 0x66, 0x6b, 0xc3, 0xd0, 0xfa, 0x62, 0xcf, 0xae, 0x45, 0x89, 0xc4, 0xa2, 0x5d, 0x3d, 0x6d, 0xab, 0xfb, 0xf2, 0x16, 0x73, 0xb6, 0x73, 0x59, 0x2e, 0xd4, 0x19, 0xf5, 0x99, 0x8d, 0x09, 0x57, 0xb8, 0x31, 0x15, 0x36, 0xb2, 0x91, 0x74, 0x73, 0xd8, 0x9a, 0x64, 0xad, 0x3e, 0x44, 0x1f, 0x26, 0xc1, 0x27, 0x74, 0x0e, 0xee, 0x45,\n\t0x16, 0xe5, 0x71, 0xd0, 0x14, 0x72, 0xc2, 0xed, 0x29, 0xa7, 0x32, 0x97, 0xb8, 0x5a, 0xd0, 0xe8, 0xc7, 0x98, 0x30, 0xe2, 0x9e, 0x28, 0x97, 0x5a, 0xa6, 0xce, 0x39, 0x7a, 0xe3, 0x4d, 0x47, 0xbf, 0xd7, 0x73, 0xe0, 0xc9, 0x5d, 0x08, 0x44, 0x05, 0x7c, 0xf2, 0xe8, 0xcb, 0x2f, 0x3f, 0xba, 0xf7, 0xa5, 0x6b, 0x07, 0x07, 0xaf, 0x7d, 0x69, 0x2f, 0x7a, 0xf7, 0xe9, 0x0f, 0xe8, 0x3c, 0xf8, 0x04, 0xbe, 0x41, 0xe2, 0x66, 0x46, 0xd4, 0x00, 0x09, 0x76, 0x97, 0x28, 0x21, 0x66, 0x65, 0x73, 0x7f, 0xc4, 0x59, 0x70, 0x1a, 0xb1, 0x61, 0xbf, 0x29, 0x88, 0x1b, 0x2e, 0x4d, 0x6e, 0x46, 0x44, 0x69, 0xa4, 0xf3, 0x25, 0xc0, 0x96, 0xef, 0x1d, 0xbb, 0xe9, 0x86, 0xa3, 0xe0, 0x93, 0xbd, 0x2f, 0x5d, 0x33, 0x30, 0x70, 0xcd, 0x4b, 0x7b, 0x1f, 0x7d, 0xe9, 0xa5, 0x47, 0x89, 0x72, 0xee, 0xf4, 0x6a, 0x6c,\n\t0x97, 0xb0, 0x12, 0xf5, 0xc5, 0x14, 0xb2, 0x48, 0x40, 0xdd, 0x04, 0x67, 0x4d, 0x93, 0x50, 0xed, 0x97, 0x72, 0x7b, 0xa0, 0xee, 0xaf, 0x52, 0x02, 0x6c, 0x98, 0x50, 0x5a, 0x55, 0x56, 0xa8, 0x8c, 0x28, 0x80, 0xa2, 0x0c, 0x14, 0x8b, 0xd2, 0xa6, 0xb9, 0xb2, 0x43, 0x18, 0x25, 0x6a, 0xfc, 0x64, 0xcb, 0xc6, 0x8d, 0x5b, 0x8e, 0x1e, 0x9d, 0xbe, 0x79, 0x7d, 0xaa, 0x6e, 0xf2, 0xf8, 0xe4, 0xd1, 0x67, 0xc0, 0xdf, 0xa7, 0x46, 0x17, 0xaf, 0x13, 0x6e, 0x01, 0x42, 0x7a, 0x6c, 0x6f, 0xdf, 0xe0, 0x25, 0x2b, 0xea, 0x84, 0x7f, 0x81, 0xad, 0x92, 0x90, 0x2b, 0x10, 0x54, 0xb3, 0x94, 0x17, 0xdd, 0x54, 0x2c, 0xd8, 0xb1, 0xc5, 0x14, 0x83, 0xda, 0x90, 0x80, 0x9a, 0xc4, 0xa1, 0x91, 0x72, 0x50, 0x95, 0xbc, 0xad, 0x86, 0x6c, 0x45, 0xcd, 0xab, 0x7d, 0x16, 0x93, 0x01, 0xca, 0xf7, 0xf0, 0x31, 0x25,\n\t0xaf, 0xc0, 0xd6, 0xd2, 0x12, 0x33, 0x28, 0x05, 0xcc, 0x51, 0xb2, 0x38, 0xe0, 0x44, 0xe7, 0x02, 0x5c, 0x06, 0xf2, 0xc0, 0xc5, 0x62, 0x72, 0x34, 0xc8, 0x94, 0x33, 0xa2, 0x4f, 0x8b, 0x59, 0xd2, 0xc7, 0x37, 0x93, 0x66, 0x30, 0x22, 0x66, 0x47, 0x83, 0x5f, 0x7e, 0xa2, 0x00, 0xd7, 0x19, 0x8c, 0xc2, 0x33, 0x61, 0x70, 0x41, 0xd8, 0xcc, 0xdf, 0xbe, 0x09, 0xa5, 0x49, 0x13, 0x67, 0xf6, 0xd3, 0x8c, 0xed, 0x37, 0x50, 0xd2, 0x22, 0x00, 0x4d, 0x4c, 0xca, 0xc5, 0x28, 0x3e, 0x84, 0x41, 0x53, 0x4a, 0xe0, 0x96, 0xfa, 0xc9, 0xfb, 0x3c, 0x0e, 0x9b, 0xae, 0xd2, 0xcf, 0x10, 0x2b, 0xf1, 0x0e, 0xd8, 0x4f, 0x5e, 0xa2, 0xad, 0xe1, 0x08, 0x85, 0x52, 0x7b, 0x3c, 0xc8, 0x8f, 0x41, 0x1e, 0xb8, 0x30, 0x3f, 0x92, 0xb5, 0x6f, 0xda, 0x0c, 0xf2, 0xc2, 0xf7, 0x36, 0x1f, 0x5f, 0x9b, 0x40, 0xe9, 0xe5,\n\t0xa7, 0x1f, 0xa8, 0x33, 0xff, 0x4c, 0xed, 0x76, 0x2f, 0xbe, 0x19, 0x8c, 0x88, 0x89, 0xe6, 0xd4, 0xd4, 0x27, 0x0a, 0x94, 0x5f, 0xbe, 0xf9, 0x36, 0xde, 0x8c, 0x7a, 0x2a, 0x3c, 0x63, 0xd4, 0x83, 0x23, 0x68, 0x9f, 0x42, 0x9d, 0x89, 0xca, 0xe3, 0xda, 0xe3, 0x28, 0xb3, 0x0d, 0xad, 0xe6, 0x78, 0x09, 0x69, 0x69, 0x6e, 0xe5, 0x71, 0x3e, 0xc7, 0x53, 0x79, 0xe1, 0x07, 0xcf, 0x08, 0xdf, 0xa7, 0x78, 0x6a, 0xe2, 0x93, 0x7b, 0xa9, 0x89, 0x3b, 0x44, 0x5e, 0xb8, 0xef, 0xf4, 0x9f, 0xa9, 0x57, 0xe1, 0x3b, 0xec, 0x84, 0x54, 0x5d, 0xd2, 0x48, 0xe1, 0x84, 0x1c, 0x1a, 0x54, 0x81, 0x95, 0x8b, 0x70, 0xd2, 0x73, 0xaf, 0xe0, 0x42, 0xe4, 0xf3, 0xdc, 0x3e, 0x3e, 0x5e, 0x84, 0xda, 0xbc, 0x89, 0xd3, 0x69, 0xe4, 0x32, 0xc2, 0x0e, 0xec, 0x4c, 0x89, 0x46, 0x20, 0x0b, 0x9c, 0xb4, 0x69, 0xd1, 0x9f,\n\t0x1e, 0x92, 0xf4, 0x15, 0x96, 0xb7, 0x78, 0x9f, 0x69, 0xda, 0x7e, 0x72, 0xc3, 0x86, 0x93, 0xe7, 0x34, 0x7d, 0xdb, 0xd7, 0x32, 0x76, 0x7b, 0xb0, 0x73, 0x4d, 0x13, 0xb9, 0x6e, 0xe6, 0xce, 0x89, 0xdb, 0x77, 0xb6, 0xb7, 0xef, 0xbc, 0x7d, 0x02, 0xfd, 0xdd, 0xb8, 0xa6, 0x0b, 0xe5, 0x2b, 0x6d, 0x24, 0xfa, 0xe9, 0xed, 0xd4, 0x5d, 0xb0, 0xaf, 0xd1, 0x62, 0x88, 0xc1, 0x19, 0x30, 0x52, 0x82, 0xc4, 0x7a, 0x48, 0xce, 0x00, 0xb9, 0x5c, 0x12, 0x00, 0x49, 0x30, 0x62, 0xe6, 0x93, 0x78, 0xf0, 0x1c, 0x8f, 0x44, 0x4d, 0x89, 0x14, 0xc1, 0x49, 0xc0, 0x5b, 0x38, 0xc2, 0x6f, 0xa4, 0x3e, 0x8a, 0x6c, 0x0a, 0x34, 0xc5, 0xac, 0xb3, 0xc1, 0x2c, 0xa9, 0xbb, 0x2e, 0x14, 0x51, 0xa4, 0x56, 0x95, 0xf1, 0xb5, 0xae, 0x68, 0x20, 0x30, 0x5f, 0x1e, 0x21, 0xfa, 0x99, 0x5f, 0xe0, 0xb6, 0x93, 0x50, 0xfe,\n\t0x1d, 0x2c, 0xf6, 0xc1, 0xf6, 0x69, 0xb1, 0x7d, 0x06, 0xb6, 0xaf, 0x80, 0x5b, 0x83, 0x91, 0xd1, 0xcc, 0x24, 0x41, 0x42, 0xd5, 0x75, 0xb9, 0x12, 0xc8, 0x08, 0x94, 0x02, 0x3f, 0x59, 0xe9, 0x51, 0xaa, 0xd6, 0xe9, 0x68, 0x2c, 0xd4, 0x76, 0xa4, 0x3a, 0x42, 0x01, 0x47, 0xd2, 0x99, 0x44, 0x3d, 0x54, 0xe1, 0xe5, 0x99, 0xb7, 0x87, 0xa1, 0x39, 0x10, 0x4d, 0xdc, 0x5c, 0xc8, 0xa6, 0xff, 0x3c, 0x63, 0x08, 0x17, 0xf7, 0xc3, 0x21, 0x08, 0x7f, 0xb4, 0xc5, 0x7c, 0x46, 0xa3, 0x2f, 0x66, 0xb3, 0x27, 0x78, 0x8e, 0xe3, 0x13, 0xf6, 0x39, 0xdf, 0xe7, 0x1d, 0xe3, 0x72, 0x78, 0xc1, 0x66, 0x4b, 0xf8, 0x38, 0xce, 0x87, 0x3e, 0x79, 0x4e, 0xd8, 0x6f, 0x42, 0xbf, 0xc4, 0xd0, 0x23, 0x31, 0xf4, 0x8b, 0x09, 0xce, 0xff, 0xf8, 0xe9, 0x05, 0xf4, 0x7a, 0xfa, 0x19, 0x22, 0x86, 0xa8, 0x87, 0x0c, 0xa5,\n\t0x64, 0x0c, 0x4a, 0x11, 0xf0, 0xeb, 0xa5, 0xf8, 0x66, 0x48, 0x4a, 0xe0, 0xa6, 0x5a, 0x4e, 0x88, 0x6a, 0x11, 0x20, 0x46, 0x58, 0x33, 0x1f, 0xe6, 0x53, 0x52, 0xa5, 0x9f, 0x2a, 0x0d, 0x54, 0x1a, 0x68, 0x6d, 0xf5, 0x90, 0x51, 0x16, 0x8a, 0x9c, 0xfa, 0x5e, 0xe7, 0x68, 0x05, 0x34, 0x0f, 0x8d, 0x6b, 0xf7, 0xf9, 0xee, 0x66, 0x09, 0xde, 0x6d, 0x57, 0x67, 0xe3, 0x8c, 0x16, 0x8e, 0x9b, 0xa6, 0x1b, 0x0e, 0x4d, 0x6c, 0x3c, 0xe0, 0xb6, 0xf4, 0x8e, 0x21, 0x00, 0xb9, 0xe5, 0xb5, 0x08, 0x2e, 0x70, 0xa8, 0xd1, 0xff, 0xca, 0x1a, 0x84, 0xbe, 0xf7, 0x2a, 0x1c, 0x20, 0xde, 0xdb, 0x46, 0xc9, 0x0e, 0x6b, 0x44, 0x74, 0x5c, 0x8d, 0xf5, 0x3b, 0x0a, 0xa1, 0x9c, 0x95, 0xd2, 0xcd, 0xe0, 0xbf, 0x46, 0x82, 0xe5, 0xb1, 0x7a, 0xa2, 0x04, 0x01, 0x31, 0xe5, 0x4c, 0xc4, 0xae, 0xe5, 0x20, 0x4f, 0xa7,\n\t0xde, 0x17, 0x36, 0x3e, 0x28, 0x4c, 0x9f, 0xb0, 0x79, 0x15, 0xef, 0x69, 0x2c, 0x2a, 0x85, 0x49, 0xf3, 0x07, 0xb9, 0xcf, 0x8a, 0x34, 0x4a, 0xea, 0x23, 0x1b, 0x37, 0x73, 0xab, 0x67, 0x30, 0x12, 0x19, 0xf4, 0x90, 0x9b, 0x59, 0x94, 0x5f, 0xe8, 0x85, 0xd4, 0xeb, 0xdf, 0x31, 0x9e, 0x22, 0xd4, 0xcd, 0xfc, 0x26, 0x19, 0x46, 0x0d, 0x46, 0x65, 0x84, 0x67, 0x83, 0x89, 0xc1, 0xcb, 0xcd, 0xbc, 0x0d, 0x23, 0xcb, 0xc2, 0x16, 0x4b, 0xb6, 0xde, 0x4a, 0xd3, 0x79, 0xd1, 0xc7, 0x59, 0xfd, 0x2d, 0xc3, 0xfc, 0xbb, 0xf0, 0xea, 0x83, 0x6f, 0x31, 0x0a, 0x9a, 0x56, 0x30, 0xbf, 0x78, 0x50, 0x78, 0xf5, 0x0e, 0x3b, 0xcf, 0x3c, 0xc2, 0x68, 0x18, 0x95, 0xe1, 0xdf, 0x18, 0xbf, 0xad, 0x00, 0xbb, 0xf7, 0xaf, 0x0a, 0xad, 0x4c, 0xa9, 0xfe, 0x2a, 0xfc, 0x86, 0x7a, 0x47, 0x3e, 0xae, 0xf3, 0x1a, 0x8d,\n\t0x5e, 0xdd, 0xcc, 0x42, 0xea, 0x23, 0xab, 0x69, 0xe6, 0x1e, 0x6b, 0xce, 0xdd, 0x94, 0x22, 0x57, 0xb1, 0x0e, 0xd8, 0xe9, 0x7b, 0x2c, 0x19, 0x57, 0xa1, 0x16, 0x7d, 0x81, 0x7d, 0x2e, 0xc0, 0xf9, 0xe9, 0x87, 0x7d, 0xd6, 0x4a, 0x56, 0x9e, 0x12, 0xf9, 0x80, 0x73, 0x37, 0x2e, 0xd1, 0x10, 0x13, 0xcb, 0x89, 0xaa, 0x13, 0x76, 0xe5, 0x48, 0xc9, 0x42, 0x54, 0x3f, 0x37, 0xf3, 0x11, 0xa9, 0xff, 0xe4, 0x63, 0x23, 0xa9, 0x10, 0xe4, 0xe4, 0x7b, 0xd4, 0x63, 0x5e, 0xd7, 0x4c, 0xe0, 0xb6, 0x21, 0xa7, 0x83, 0x7c, 0x0b, 0xd9, 0x31, 0xb2, 0xa7, 0xff, 0x42, 0x05, 0xe1, 0x7b, 0xd3, 0xc4, 0xe6, 0x22, 0x4a, 0xe1, 0xa2, 0x63, 0x0c, 0x7c, 0xb9, 0x11, 0x7b, 0x32, 0xcb, 0xc0, 0xd1, 0x14, 0xdc, 0x2e, 0x00, 0xa9, 0xca, 0xf4, 0xb8, 0x84, 0xd7, 0x54, 0xa5, 0x64, 0x7f, 0xea, 0x0d, 0x98, 0x19, 0x22,\n\t0xa8, 0xa3, 0x34, 0x91, 0x36, 0x47, 0x93, 0xb5, 0x18, 0xea, 0x08, 0x4b, 0xe7, 0x73, 0xcc, 0x1b, 0x96, 0x2a, 0x25, 0x08, 0x87, 0xe8, 0xb5, 0xc3, 0xde, 0x53, 0x72, 0x95, 0x51, 0x58, 0x7a, 0xc1, 0x50, 0xa0, 0x7b, 0xe7, 0xf1, 0x85, 0x1b, 0x9f, 0xe8, 0xec, 0x57, 0xb1, 0x8c, 0x8a, 0x65, 0xd5, 0xfe, 0x74, 0x7b, 0x4d, 0x7e, 0x51, 0xde, 0x69, 0xcb, 0x8e, 0xb6, 0x1e, 0xd2, 0xe8, 0x7f, 0x23, 0xac, 0xa0, 0x3e, 0xea, 0xd3, 0x07, 0x8c, 0x7f, 0x92, 0xa5, 0x87, 0x36, 0x34, 0x8e, 0x5d, 0xb5, 0x3a, 0xbd, 0x78, 0xe9, 0x32, 0x35, 0x25, 0xd7, 0xa9, 0xdd, 0x76, 0xd6, 0x97, 0xeb, 0x0d, 0xfb, 0x1b, 0x63, 0xd6, 0x25, 0x3a, 0xaf, 0xee, 0xed, 0xdb, 0xd0, 0x5e, 0xeb, 0x3a, 0xfd, 0x1e, 0xe5, 0x85, 0x32, 0x43, 0x1b, 0xd1, 0x59, 0x6c, 0xf7, 0xc0, 0x41, 0x27, 0xe2, 0x3a, 0x2d, 0xcd, 0x20, 0xb8,\n\t0xd0, 0xf9, 0xe1, 0x0e, 0xce, 0x2d, 0xfb, 0x4d, 0xe1, 0x80, 0x9b, 0x9b, 0x0a, 0x39, 0xbf, 0xcf, 0xe5, 0xb0, 0x9a, 0xfd, 0x32, 0x11, 0x51, 0xba, 0x2c, 0x37, 0xe5, 0xca, 0x86, 0x63, 0x6c, 0x14, 0x2e, 0x8b, 0x9a, 0xf2, 0xaa, 0xfc, 0x63, 0x1c, 0xa6, 0xe3, 0x6d, 0xf9, 0xc6, 0xf9, 0xe3, 0x87, 0xd7, 0xd6, 0xe7, 0x47, 0xb7, 0x64, 0x53, 0x63, 0x1d, 0xe1, 0x8d, 0xe3, 0xf5, 0xfd, 0xf9, 0x08, 0x6b, 0xd3, 0x25, 0x9a, 0xee, 0xdf, 0x36, 0x7a, 0xd5, 0x44, 0xba, 0x6e, 0xe1, 0xfa, 0x74, 0x66, 0xcd, 0x40, 0xc2, 0x56, 0x37, 0x9c, 0x6b, 0x1a, 0x29, 0xd4, 0x98, 0x58, 0xab, 0xf2, 0x9c, 0x7c, 0x6f, 0x6c, 0x68, 0x53, 0x5b, 0xd7, 0x58, 0x83, 0x5f, 0xbf, 0x59, 0x69, 0x74, 0xc6, 0xfd, 0x8d, 0x7d, 0x16, 0x87, 0xc5, 0xd6, 0xd7, 0x50, 0x8c, 0xf6, 0x4f, 0x35, 0xb7, 0x8d, 0xd4, 0x7b, 0xb5, 0x9b,\n\t0x55, 0x66, 0x3e, 0x13, 0x75, 0x65, 0x23, 0x36, 0x27, 0xef, 0xd2, 0xeb, 0xa4, 0x9a, 0x84, 0xa7, 0xff, 0x44, 0x07, 0xe1, 0x00, 0xea, 0x88, 0xda, 0x62, 0x3c, 0x61, 0x83, 0xeb, 0xab, 0x94, 0xc0, 0x51, 0xe1, 0xc8, 0x30, 0xb2, 0xb2, 0x08, 0xeb, 0xb3, 0x03, 0x6f, 0xfb, 0x3a, 0x22, 0x9d, 0x0c, 0x05, 0x43, 0x68, 0xa5, 0x42, 0xb3, 0xe5, 0xe4, 0x56, 0x5c, 0xff, 0xab, 0x50, 0xc9, 0x94, 0x92, 0x64, 0xc7, 0x0c, 0x1d, 0x44, 0x70, 0xd0, 0xeb, 0x7e, 0xb6, 0x69, 0xfa, 0x67, 0xeb, 0xc2, 0x51, 0x96, 0x0c, 0xfa, 0x17, 0x8d, 0xae, 0x88, 0x67, 0x57, 0xb4, 0x07, 0xea, 0x37, 0x1c, 0x5d, 0xb5, 0xea, 0xd8, 0xfa, 0xfa, 0x40, 0xfb, 0x8a, 0x6c, 0x7c, 0xc5, 0xe8, 0xa2, 0xc0, 0x55, 0x03, 0x7a, 0x27, 0xa7, 0x19, 0xee, 0xec, 0x1c, 0xd6, 0x70, 0x4e, 0xfd, 0x80, 0xc2, 0x16, 0xf7, 0xd7, 0x9d, 0xbb,\n\t0xf7, 0xd2, 0x8e, 0xae, 0xf3, 0x46, 0xd3, 0xe9, 0xd1, 0xf3, 0xba, 0x3a, 0x0e, 0x5c, 0x78, 0x6e, 0x5d, 0x20, 0x66, 0x53, 0x54, 0xd9, 0xf0, 0x18, 0xa4, 0xfb, 0x11, 0x12, 0x74, 0x5c, 0x85, 0x65, 0x1a, 0x70, 0xfe, 0xa9, 0xe8, 0x28, 0x54, 0x0a, 0xad, 0xcf, 0x92, 0x97, 0x51, 0x1b, 0x3f, 0xf9, 0x17, 0x9c, 0xe0, 0x0b, 0xa0, 0xf0, 0x45, 0x50, 0xef, 0xfd, 0x53, 0x39, 0xc4, 0xef, 0xdd, 0x6d, 0xf7, 0x48, 0x44, 0x44, 0xfd, 0x47, 0x19, 0x6f, 0xbb, 0x1e, 0xdc, 0xfe, 0xa0, 0x8d, 0x23, 0x37, 0x7b, 0x06, 0xa2, 0xd1, 0x01, 0xcf, 0xcc, 0xad, 0xa2, 0xc7, 0x86, 0xa8, 0xc2, 0x22, 0xc4, 0x3c, 0x1d, 0xed, 0x95, 0x71, 0xa2, 0xca, 0xb2, 0x53, 0xe2, 0xe9, 0x25, 0xa7, 0x26, 0xf5, 0xf6, 0xb3, 0x42, 0xe0, 0x59, 0x6a, 0x79, 0xa9, 0x93, 0x80, 0x58, 0x44, 0x10, 0xf4, 0x66, 0xf8, 0x67, 0x88, 0x88,\n\t0x17, 0xa3, 0x32, 0x40, 0x23, 0xe1, 0x15, 0x4a, 0x2d, 0x65, 0xd8, 0x56, 0xc9, 0xed, 0x04, 0xaf, 0x07, 0x59, 0xd6, 0x1a, 0x62, 0x59, 0xb3, 0x08, 0x7b, 0x8a, 0x77, 0x54, 0x20, 0x07, 0xd7, 0x01, 0x83, 0x28, 0xb0, 0x38, 0x49, 0x2d, 0x83, 0x72, 0xe9, 0x58, 0xa8, 0xc9, 0xd0, 0x9b, 0x0b, 0xe7, 0xdc, 0xb5, 0xf5, 0xd9, 0xad, 0x77, 0x9e, 0x53, 0x38, 0xe0, 0xf6, 0xdb, 0x1b, 0x26, 0xba, 0x9e, 0xed, 0x5a, 0xdd, 0x68, 0xe7, 0x3d, 0xd4, 0x47, 0xc2, 0xf1, 0x95, 0x37, 0x6d, 0x69, 0x63, 0xfe, 0xf4, 0x27, 0x59, 0xdb, 0x96, 0x9b, 0xc6, 0xc1, 0xf6, 0x90, 0x4b, 0xf8, 0x69, 0xf3, 0x44, 0x31, 0x44, 0x93, 0xe7, 0xcc, 0xdc, 0x4c, 0x87, 0x8a, 0x13, 0xcd, 0x20, 0xe1, 0x0a, 0xe1, 0xb1, 0x39, 0x20, 0x5d, 0x78, 0x11, 0xf6, 0xcd, 0x4a, 0xf4, 0x88, 0x56, 0x34, 0x0b, 0x32, 0xee, 0x8e, 0x97, 0x10,\n\t0xbd, 0xc4, 0xec, 0x74, 0x11, 0x66, 0xb6, 0xea, 0x82, 0x04, 0x73, 0x56, 0x96, 0x2e, 0xbe, 0x61, 0x09, 0x84, 0x59, 0x83, 0x98, 0x43, 0xcd, 0xf2, 0x32, 0x12, 0xc3, 0xb5, 0xe2, 0x6d, 0x44, 0x19, 0x0b, 0x3c, 0xf5, 0xe2, 0x73, 0xc2, 0xef, 0xd4, 0xc1, 0xfa, 0xe2, 0xf0, 0x58, 0x3a, 0x53, 0x9b, 0xb7, 0x65, 0xd2, 0xc9, 0xa0, 0x43, 0x46, 0x5e, 0x45, 0x6d, 0x7c, 0x5e, 0x78, 0xe7, 0xe5, 0x8b, 0xbb, 0x6d, 0x46, 0x76, 0xaf, 0xa1, 0x69, 0xd7, 0x4b, 0xc0, 0xfb, 0xef, 0x58, 0x26, 0xd6, 0x53, 0xc7, 0xc9, 0xff, 0x41, 0x2e, 0x48, 0xa8, 0x77, 0x16, 0x8a, 0x59, 0xba, 0x24, 0xeb, 0xd1, 0xbb, 0xa1, 0x60, 0x43, 0x82, 0x3d, 0x0c, 0xda, 0xd5, 0xc4, 0x28, 0xf6, 0xde, 0xad, 0x44, 0x1a, 0xf5, 0xc2, 0x79, 0x7c, 0x76, 0x11, 0xbc, 0xda, 0x90, 0xd4, 0xcd, 0xf2, 0xd9, 0x81, 0x5f, 0x8f, 0xc8, 0xf5,\n\t0x0a, 0xb9, 0x5e, 0x3e, 0x02, 0x7e, 0x76, 0x9e, 0xc9, 0x26, 0xab, 0x13, 0xfe, 0xb3, 0x8e, 0x76, 0x18, 0x2f, 0x00, 0x9e, 0xdb, 0xe9, 0x07, 0xdf, 0x30, 0xa6, 0xdd, 0xee, 0xb4, 0xf1, 0x0d, 0xe1, 0x1d, 0x93, 0xee, 0xd0, 0x21, 0xad, 0x99, 0x7c, 0x53, 0x94, 0xd1, 0x09, 0xea, 0x38, 0x75, 0x0b, 0xaa, 0x4d, 0x45, 0xd8, 0x88, 0x2b, 0x9f, 0x14, 0x5d, 0x76, 0xe2, 0x64, 0x85, 0x09, 0x39, 0xd2, 0x69, 0xe5, 0x8a, 0xf5, 0x67, 0xb8, 0xf0, 0x90, 0xcb, 0x4e, 0xdc, 0x28, 0x34, 0xd6, 0x7d, 0xcf, 0x7a, 0x23, 0x94, 0xf7, 0x69, 0x6a, 0xb4, 0xe4, 0xe6, 0xa3, 0xe8, 0x91, 0xf1, 0xa2, 0xfb, 0xb3, 0x1d, 0x7d, 0x70, 0x60, 0xd6, 0x8c, 0x39, 0x60, 0x9d, 0xe5, 0xe8, 0x03, 0x6f, 0xd6, 0x28, 0x39, 0xd5, 0x2e, 0x10, 0xb6, 0xfc, 0xf5, 0x1d, 0x2b, 0xb0, 0x09, 0x5b, 0xcc, 0xa7, 0x89, 0xa2, 0xc2, 0x65,\n\t0xde, 0x05, 0x76, 0x90, 0x11, 0xfa, 0x41, 0x30, 0xe6, 0xae, 0xb7, 0xbc, 0x0f, 0x16, 0x3c, 0x7d, 0xfe, 0x33, 0x17, 0x3f, 0x74, 0x48, 0xcf, 0x91, 0x6f, 0x5e, 0x84, 0xe5, 0xa8, 0x29, 0x38, 0xdf, 0xd7, 0xc1, 0xf1, 0xa9, 0xa0, 0x36, 0x1a, 0x42, 0xb4, 0xd2, 0x85, 0xa6, 0x79, 0x10, 0xca, 0x4f, 0x72, 0x80, 0xc1, 0x3f, 0xaa, 0xf2, 0x99, 0x25, 0x2c, 0x56, 0x66, 0xd8, 0x6c, 0x52, 0x43, 0xf6, 0x0d, 0xd9, 0x6a, 0xc8, 0x1c, 0x52, 0x73, 0x6a, 0xa3, 0x4e, 0x23, 0x22, 0x25, 0x29, 0xab, 0xd1, 0x9c, 0xcc, 0xac, 0x79, 0x7e, 0x9f, 0x10, 0x0b, 0xf6, 0x05, 0xd3, 0x6e, 0x75, 0x43, 0xcf, 0xe5, 0x53, 0xc5, 0x9e, 0x96, 0xe2, 0xc0, 0xe6, 0x4e, 0x6f, 0x73, 0xd7, 0x8d, 0xc1, 0x9e, 0xa9, 0x0e, 0xe1, 0xd7, 0xb4, 0xca, 0xe8, 0x0a, 0x99, 0x12, 0x75, 0xaf, 0x80, 0xf7, 0x5e, 0x8a, 0xe5, 0x0b, 0xf1,\n\t0x0b, 0x5c, 0x99, 0xfe, 0x64, 0x66, 0xa9, 0xcd, 0x7f, 0x69, 0x6a, 0x51, 0x33, 0x8f, 0x17, 0x85, 0x22, 0x7c, 0xd4, 0xcd, 0xe4, 0x03, 0xb2, 0x5d, 0x84, 0x01, 0x4a, 0x7f, 0x29, 0x62, 0x59, 0x71, 0xb1, 0x1f, 0xdb, 0x5e, 0x35, 0x40, 0xa6, 0x86, 0x14, 0x5d, 0x06, 0x85, 0xbe, 0x33, 0x3c, 0x5d, 0xd8, 0x63, 0x8d, 0x5c, 0x5c, 0xd3, 0xf2, 0x61, 0xa7, 0x83, 0x65, 0x01, 0x81, 0x21, 0x28, 0xa3, 0x8e, 0x94, 0x33, 0xc5, 0xda, 0x59, 0x9b, 0x58, 0xcf, 0x54, 0x74, 0x59, 0x68, 0xcb, 0xa3, 0x40, 0x6c, 0x0a, 0xbb, 0xb7, 0xce, 0x36, 0x14, 0xec, 0xde, 0x02, 0xb7, 0x07, 0x53, 0x6e, 0xb5, 0xd6, 0x93, 0xf2, 0x5f, 0xb1, 0x73, 0xe7, 0x54, 0x47, 0x77, 0x73, 0xc7, 0xc0, 0x96, 0x4e, 0x6f, 0x4b, 0xe7, 0x0d, 0xc1, 0xee, 0x8d, 0x45, 0xe1, 0x57, 0xeb, 0xd7, 0x53, 0xa7, 0xcd, 0xfe, 0xa8, 0x09, 0x15,\n\t0xee, 0xed, 0x5d, 0x30, 0x48, 0x2a, 0xde, 0x28, 0xe4, 0xf3, 0x85, 0xad, 0x78, 0x60, 0xcb, 0xac, 0xe2, 0xc0, 0x9e, 0x5c, 0x00, 0xfe, 0x4b, 0xdc, 0x6f, 0x68, 0x3d, 0xfe, 0x0c, 0xd7, 0x03, 0xf9, 0x7a, 0xdc, 0xe8, 0xdc, 0x11, 0x22, 0x0c, 0x78, 0xa9, 0xa6, 0xd5, 0x67, 0x79, 0x7a, 0xc8, 0x3f, 0xe7, 0x27, 0x0f, 0x2f, 0x13, 0x7e, 0x03, 0xec, 0xcb, 0x0e, 0x4f, 0xe6, 0x6f, 0xf7, 0x36, 0x2e, 0xc9, 0x5c, 0x71, 0x45, 0x66, 0x49, 0xa3, 0x97, 0x01, 0x8b, 0xae, 0x5e, 0x5f, 0x20, 0xdf, 0x2c, 0xac, 0xbf, 0x66, 0x51, 0xe3, 0x44, 0xbb, 0x5f, 0xb0, 0xf2, 0xed, 0x13, 0x22, 0x8d, 0x43, 0x6d, 0xe6, 0x60, 0x9b, 0x6a, 0x42, 0x82, 0x02, 0x75, 0x11, 0xb4, 0x0c, 0x40, 0x49, 0x92, 0x59, 0x5f, 0xf2, 0xaa, 0xa0, 0x03, 0x8f, 0x29, 0x33, 0x8a, 0xf2, 0xe7, 0xcf, 0xbc, 0x0c, 0x75, 0x30, 0x72, 0x54,\n\t0x12, 0x59, 0x48, 0x6a, 0xc1, 0x78, 0x51, 0x37, 0xc7, 0xe3, 0xc2, 0xe1, 0x79, 0x14, 0x3d, 0x2e, 0x1f, 0x7f, 0xf8, 0x21, 0x68, 0x12, 0x52, 0xe0, 0xc7, 0xcc, 0x5f, 0xd1, 0x76, 0x14, 0xb7, 0x22, 0xec, 0x47, 0x2b, 0xec, 0x87, 0x1e, 0xf7, 0x63, 0x49, 0x09, 0x05, 0x63, 0xb6, 0x38, 0xbb, 0xbe, 0x24, 0x0a, 0x4d, 0x23, 0xa2, 0xe4, 0x3b, 0xe3, 0x2a, 0x12, 0x76, 0x47, 0x91, 0x58, 0x32, 0x8e, 0x53, 0x07, 0xc7, 0x8b, 0x4a, 0x31, 0xee, 0x04, 0xcb, 0xbb, 0x50, 0x50, 0x42, 0xcb, 0x05, 0xff, 0xe5, 0x49, 0xbd, 0x50, 0x0b, 0x9a, 0x3e, 0xfc, 0x50, 0xf8, 0x0e, 0xf8, 0x0f, 0xea, 0xf8, 0xc5, 0xcf, 0x9c, 0xff, 0xf4, 0x45, 0xd8, 0x4e, 0x4c, 0x1d, 0x21, 0x5f, 0x94, 0xed, 0x85, 0x1a, 0x45, 0xae, 0x58, 0x6f, 0x84, 0x6f, 0x8c, 0x02, 0x28, 0x31, 0xc0, 0xbd, 0x45, 0x21, 0x18, 0x06, 0xb4, 0x8f,\n\t0xb0, 0x52, 0x4c, 0xa3, 0x83, 0x5b, 0x02, 0x3f, 0x05, 0xc3, 0x5c, 0x34, 0x16, 0x0d, 0x88, 0x4d, 0x64, 0xd8, 0x33, 0x9c, 0x83, 0xf3, 0x24, 0x0e, 0xe6, 0xc0, 0xab, 0x7f, 0x6f, 0xb8, 0x6a, 0x62, 0xd1, 0x35, 0x93, 0x0d, 0xf9, 0xa9, 0xa3, 0x2b, 0x26, 0x0e, 0x26, 0xe3, 0x6a, 0x1f, 0x67, 0xf4, 0x47, 0xd2, 0x9e, 0xcc, 0xd2, 0x66, 0xaf, 0xbf, 0x75, 0x69, 0x7d, 0xac, 0xcd, 0xb5, 0x4c, 0x07, 0x69, 0xaa, 0xf0, 0xc3, 0x9a, 0x50, 0xc3, 0xd4, 0xa1, 0xc5, 0x4b, 0x0e, 0x4f, 0x15, 0x0a, 0xb1, 0x5e, 0x83, 0x42, 0xa3, 0x36, 0x6a, 0xe5, 0x81, 0xe2, 0x44, 0xa1, 0x65, 0x4d, 0xd1, 0xaf, 0xd3, 0x5e, 0x68, 0xd0, 0x48, 0xeb, 0x77, 0x0a, 0xcf, 0x1b, 0xe4, 0xfd, 0x28, 0xab, 0x8d, 0x26, 0x20, 0x51, 0x11, 0x3d, 0x11, 0xeb, 0x71, 0x96, 0x1b, 0x31, 0x4e, 0x22, 0x08, 0xb8, 0x05, 0x67, 0xb8, 0xc1,\n\t0x44, 0xbe, 0x85, 0x90, 0x60, 0xc8, 0x53, 0x27, 0x84, 0x67, 0x4e, 0x9c, 0x00, 0xdd, 0xb2, 0x9d, 0x33, 0x01, 0xb8, 0x3c, 0xdf, 0x21, 0xdf, 0x14, 0xbe, 0x07, 0xf2, 0xd8, 0xfe, 0x42, 0x1d, 0x27, 0xfe, 0x2e, 0x43, 0xe1, 0x3d, 0x36, 0x64, 0xdf, 0x9c, 0x3d, 0xc9, 0xac, 0x81, 0x84, 0xe2, 0x3a, 0x07, 0x5f, 0xf2, 0xf7, 0x13, 0x27, 0x60, 0x47, 0xde, 0x14, 0xd7, 0xd2, 0x4e, 0x1d, 0x01, 0xfb, 0xe1, 0x33, 0x1c, 0x92, 0xf5, 0x45, 0x5f, 0x0e, 0x01, 0x25, 0xc8, 0xdd, 0xd8, 0xb2, 0x8b, 0xfc, 0x34, 0x70, 0x27, 0x73, 0x7c, 0xb0, 0xda, 0x09, 0x33, 0xcb, 0x05, 0xb3, 0xdf, 0xd3, 0xb6, 0xaa, 0xb5, 0xd0, 0xa0, 0x04, 0x06, 0xbd, 0xc2, 0x69, 0x2a, 0xe4, 0x4f, 0xd0, 0xff, 0xd2, 0x36, 0xd5, 0x17, 0xd1, 0xae, 0xd2, 0x18, 0x64, 0xed, 0x0b, 0xc1, 0x7f, 0x96, 0xf6, 0xed, 0x5b, 0xb0, 0x0d, 0x17,\n\t0xca, 0x03, 0x57, 0x63, 0xfd, 0x93, 0x41, 0xf8, 0xf9, 0x50, 0xe1, 0x91, 0xf2, 0xf4, 0x51, 0x78, 0x36, 0x39, 0x41, 0xa3, 0x2c, 0xec, 0x11, 0x96, 0x0d, 0x45, 0x82, 0xd8, 0x0b, 0xc3, 0x21, 0x4b, 0x2b, 0xc6, 0xcc, 0x40, 0x58, 0x6e, 0x56, 0x4e, 0x12, 0x10, 0x44, 0xa7, 0xcc, 0xdf, 0x3d, 0x21, 0xf6, 0x5b, 0x3a, 0xb7, 0xf5, 0x8a, 0x77, 0xcc, 0x0e, 0xd6, 0xad, 0x7d, 0xef, 0x2a, 0x87, 0x43, 0xf9, 0xac, 0xca, 0x69, 0x8d, 0xdd, 0x72, 0x0b, 0xd3, 0x65, 0xfd, 0x8b, 0x51, 0x27, 0xfc, 0xd4, 0xa5, 0x93, 0x5b, 0x39, 0xe1, 0x41, 0xbd, 0x0e, 0xc8, 0x74, 0x6a, 0xe1, 0x15, 0x38, 0x64, 0xb1, 0x2f, 0x66, 0xcc, 0x27, 0x3a, 0x24, 0x20, 0x3e, 0x02, 0x1b, 0x8c, 0x90, 0x44, 0x83, 0x8b, 0x95, 0x88, 0x88, 0x4a, 0xe8, 0x37, 0x0a, 0x61, 0x8f, 0x90, 0xa3, 0x25, 0xc7, 0x0c, 0x49, 0x2c, 0x1c, 0x2f,\n\t0xaa, 0xab, 0x33, 0xfd, 0x80, 0x98, 0xe9, 0x67, 0x16, 0x46, 0x6e, 0xa1, 0x8d, 0x07, 0xc8, 0x37, 0x67, 0xee, 0x2e, 0x9f, 0x53, 0xea, 0x30, 0x6c, 0x83, 0x47, 0xfb, 0xd3, 0xa1, 0x61, 0x28, 0x9c, 0x8c, 0x2f, 0xc1, 0x1b, 0x31, 0xc8, 0x1d, 0x4e, 0x50, 0xcb, 0xd1, 0x67, 0xf5, 0x7a, 0xf3, 0x84, 0x8f, 0xb7, 0xe4, 0xca, 0xb5, 0x33, 0xb2, 0x05, 0x64, 0x9c, 0xf1, 0x47, 0xa8, 0x0a, 0x6a, 0x72, 0xb5, 0x8a, 0x75, 0xf8, 0x2a, 0xea, 0x3f, 0x0c, 0x21, 0x53, 0x90, 0xfd, 0x29, 0x49, 0x1e, 0xdc, 0x6d, 0x32, 0xa9, 0x7e, 0xa0, 0x34, 0x28, 0x14, 0xac, 0xf2, 0x35, 0x25, 0xa4, 0x7a, 0x68, 0x63, 0x7c, 0xdb, 0x1b, 0x16, 0x76, 0xf3, 0x3c, 0x38, 0xc6, 0x05, 0xf5, 0x42, 0x0f, 0xf9, 0xa6, 0x9c, 0x15, 0xf6, 0xb3, 0x51, 0x93, 0x39, 0x6a, 0x04, 0x97, 0xb3, 0xf2, 0x0a, 0x3d, 0x41, 0xfb, 0xd1, 0x84,\n\t0xfc, 0x51, 0x32, 0x2c, 0x97, 0x21, 0x14, 0x67, 0x38, 0xd4, 0xe5, 0x18, 0xcd, 0x99, 0x18, 0x47, 0xab, 0x84, 0x7b, 0x67, 0x22, 0x4c, 0xbc, 0x95, 0xad, 0x02, 0x73, 0xb6, 0xcc, 0xc2, 0x72, 0x26, 0x4f, 0x2d, 0x64, 0xed, 0x6a, 0xe1, 0x26, 0xea, 0xe0, 0x42, 0x93, 0x51, 0x0b, 0x76, 0x92, 0x24, 0xea, 0x84, 0x46, 0x07, 0x5e, 0x0b, 0x7b, 0x85, 0xb5, 0xe4, 0x9b, 0x0a, 0x83, 0x50, 0x6f, 0x0a, 0xb1, 0xe0, 0x24, 0x6e, 0x77, 0x11, 0x6c, 0xf7, 0xa5, 0x52, 0xbb, 0xcc, 0x3c, 0xed, 0x4e, 0xe0, 0x76, 0x47, 0x70, 0xbb, 0x1c, 0x1b, 0x2e, 0xb5, 0x0b, 0x27, 0x05, 0xa7, 0x78, 0x22, 0x23, 0x88, 0x4c, 0x8e, 0x64, 0x7a, 0xf2, 0xa5, 0xab, 0x28, 0xe1, 0x26, 0xb5, 0x8d, 0x5d, 0x78, 0x10, 0x2a, 0xa8, 0xbb, 0x34, 0x46, 0x71, 0xf0, 0x77, 0xf9, 0x82, 0x42, 0x4e, 0xa7, 0x81, 0x27, 0x63, 0x8a, 0x0d,\n\t0x99, 0xc0, 0x0f, 0x0c, 0x0a, 0x4c, 0xb3, 0x21, 0xdd, 0xa0, 0x02, 0x90, 0x6e, 0x20, 0x3f, 0xcb, 0xfc, 0x34, 0x3b, 0xfc, 0x99, 0x2e, 0x2f, 0xb4, 0xef, 0xa9, 0x00, 0xa2, 0xdd, 0x88, 0x6e, 0x97, 0x3e, 0x31, 0xfd, 0x46, 0xd4, 0xfb, 0x82, 0x4d, 0x9b, 0x2e, 0x80, 0x14, 0xfc, 0xda, 0x8d, 0x8d, 0x8d, 0x1b, 0xaf, 0x5d, 0xb4, 0xe8, 0x10, 0xfa, 0x3c, 0x84, 0xe9, 0xb8, 0xbf, 0x7d, 0xa2, 0x71, 0xf7, 0xe5, 0x97, 0xa3, 0x7e, 0x24, 0x21, 0xfd, 0xda, 0x89, 0xcf, 0xdc, 0x30, 0x91, 0x29, 0xa6, 0x7b, 0xbb, 0xd2, 0x2e, 0x15, 0x83, 0xf5, 0x5e, 0x34, 0x0b, 0xe4, 0x6e, 0xa2, 0x0c, 0x69, 0x0a, 0x86, 0xb1, 0xe1, 0x78, 0xd8, 0x34, 0xd4, 0x58, 0x65, 0x38, 0x06, 0xff, 0xa0, 0xe1, 0x58, 0x26, 0xda, 0x8d, 0x41, 0xc9, 0x6e, 0x3c, 0xe2, 0xc9, 0x46, 0x2c, 0xb6, 0x58, 0xc1, 0xeb, 0xaa, 0x0b, 0x9a,\n\t0x2d, 0x91, 0x2c, 0x60, 0x59, 0x8d, 0x25, 0x9c, 0x75, 0xfb, 0x1a, 0x13, 0xf6, 0xc8, 0xc0, 0x39, 0x3d, 0x3d, 0xe7, 0x0c, 0x46, 0x1c, 0xc9, 0x66, 0xde, 0x93, 0x8b, 0x5a, 0xb5, 0xdc, 0x76, 0x56, 0x2b, 0xd7, 0x5a, 0x42, 0xf5, 0xee, 0xba, 0x4e, 0x05, 0xa3, 0x40, 0x10, 0x42, 0x1a, 0x77, 0x92, 0x77, 0xc5, 0x03, 0x6e, 0x9d, 0xd6, 0x1d, 0x4c, 0x38, 0xf9, 0xa4, 0x5b, 0x43, 0x6e, 0xb7, 0x16, 0xac, 0x81, 0x86, 0x64, 0x50, 0xcf, 0xd6, 0x14, 0x7a, 0x6b, 0xeb, 0x97, 0x36, 0xfb, 0x7c, 0xcd, 0x4b, 0xeb, 0x13, 0xdd, 0x99, 0x88, 0xc1, 0x10, 0x4a, 0x37, 0x87, 0x1d, 0xb5, 0x50, 0xfb, 0xb3, 0x05, 0xec, 0x11, 0x9f, 0x43, 0x63, 0x6d, 0xcf, 0xe8, 0xdd, 0x6a, 0xa8, 0x49, 0x97, 0xf8, 0xe8, 0x25, 0x58, 0x8e, 0xb4, 0x22, 0xe4, 0x12, 0xc8, 0x28, 0xe8, 0x3d, 0x32, 0x09, 0xc7, 0x0c, 0x92, 0x05,\n\t0x24, 0xde, 0x2e, 0x67, 0xa4, 0xd2, 0x47, 0x04, 0x35, 0xf2, 0xe9, 0x16, 0x56, 0x73, 0xc5, 0xc2, 0x6a, 0x0e, 0xb0, 0x60, 0x65, 0x7f, 0x67, 0x57, 0xdf, 0xba, 0x75, 0x43, 0xdb, 0xfb, 0xfc, 0x81, 0xfe, 0xed, 0x03, 0xeb, 0x6e, 0x61, 0x98, 0xce, 0x96, 0x7c, 0xc7, 0x87, 0x60, 0x5b, 0xb0, 0x7d, 0x79, 0x26, 0x3f, 0x51, 0x0c, 0x7e, 0x0c, 0x69, 0x82, 0xd8, 0x87, 0x07, 0x71, 0x1f, 0xbc, 0x44, 0x4b, 0xb1, 0xd1, 0x8d, 0x29, 0x14, 0xaa, 0xeb, 0x41, 0xee, 0x29, 0xe5, 0x12, 0xc9, 0xc4, 0x9e, 0xc8, 0x2a, 0x3d, 0x81, 0xfd, 0x30, 0x71, 0x46, 0x56, 0xaf, 0x56, 0xce, 0xd3, 0x0f, 0x80, 0x74, 0xce, 0x12, 0xa5, 0xaa, 0x00, 0x64, 0xf6, 0x0f, 0x76, 0xf5, 0xf4, 0x8d, 0x80, 0x47, 0xaf, 0x09, 0x71, 0xd7, 0x29, 0x2c, 0xa6, 0xcc, 0x2d, 0xbf, 0x1a, 0xde, 0xde, 0xeb, 0x1b, 0x19, 0x72, 0x9b, 0x18,\n\t0x4b, 0x4f, 0x26, 0xd3, 0xf8, 0x3f, 0xc2, 0x7e, 0xcf, 0xcf, 0x21, 0xa9, 0xfa, 0x1d, 0xf9, 0xa6, 0xaf, 0x71, 0x24, 0x35, 0x70, 0xae, 0x83, 0xf5, 0x20, 0xf9, 0x1f, 0xf6, 0x6f, 0xb5, 0x0c, 0x95, 0x81, 0xf3, 0x21, 0xf4, 0x5a, 0x64, 0x55, 0x47, 0x40, 0x35, 0x48, 0x1e, 0x2d, 0x11, 0x90, 0xb2, 0xd1, 0x12, 0x97, 0x13, 0x81, 0x9c, 0x73, 0xf5, 0xa9, 0x13, 0xa7, 0xc8, 0x2e, 0xe6, 0x4f, 0x33, 0x77, 0x92, 0xeb, 0xf6, 0xc3, 0x67, 0x56, 0x62, 0x9e, 0xb9, 0x93, 0x30, 0x13, 0x41, 0x14, 0x8a, 0x09, 0x5f, 0x22, 0x1a, 0xc9, 0xf1, 0x36, 0x43, 0x58, 0x9a, 0x46, 0x56, 0xa3, 0x82, 0x2c, 0xd3, 0x0c, 0xcc, 0x8c, 0x34, 0x92, 0x39, 0x66, 0x47, 0x0b, 0x38, 0x3a, 0xb4, 0xe4, 0x96, 0xf8, 0xc8, 0xee, 0x3e, 0xe4, 0x92, 0xbb, 0x65, 0x29, 0x6d, 0x58, 0xb5, 0x08, 0x3c, 0x21, 0x0c, 0x77, 0xed, 0x5c,\n\t0x9c, 0x4c, 0x2e, 0xde, 0xd9, 0x85, 0xfe, 0x5e, 0xb4, 0x0a, 0xe3, 0x39, 0x51, 0xc7, 0xe9, 0x16, 0xd8, 0x56, 0x04, 0xb5, 0xe5, 0xe3, 0xc8, 0xb2, 0x49, 0x47, 0x82, 0x48, 0xda, 0x02, 0x57, 0x3e, 0x42, 0x84, 0x9b, 0x24, 0x83, 0x0e, 0xa0, 0x2a, 0x06, 0x1d, 0xc9, 0xca, 0x5b, 0x6d, 0xcf, 0x29, 0x61, 0x19, 0x65, 0xe8, 0x96, 0xff, 0x3e, 0x74, 0x0b, 0x2a, 0xba, 0x20, 0xa3, 0x6f, 0xbd, 0xf6, 0x97, 0x97, 0xd6, 0xa8, 0x76, 0x33, 0x72, 0x46, 0xa1, 0xb9, 0x8a, 0xb1, 0x9b, 0x12, 0x26, 0xab, 0xfc, 0xa0, 0x46, 0x41, 0x2b, 0xe8, 0x3d, 0x94, 0x93, 0xc3, 0x34, 0xe0, 0x0d, 0xb5, 0x4d, 0xa7, 0xb3, 0xa9, 0x85, 0x30, 0xf9, 0xa6, 0x5f, 0xd8, 0x6a, 0x8c, 0x5a, 0x93, 0x41, 0x70, 0x8b, 0xd6, 0xcc, 0xe9, 0x85, 0xad, 0xfe, 0xb8, 0x39, 0xc2, 0x82, 0x5b, 0x74, 0x26, 0x54, 0xdb, 0x93, 0x3a, 0x44,\n\t0xd2, 0xcc, 0x3d, 0x90, 0xdd, 0xd6, 0x11, 0xbb, 0x8b, 0xba, 0x30, 0x00, 0x0c, 0xb2, 0x78, 0xd9, 0x70, 0xbe, 0xaf, 0xc8, 0x21, 0x02, 0x67, 0x94, 0x86, 0x9f, 0x1c, 0x2a, 0x19, 0x22, 0xb0, 0x76, 0x85, 0xb5, 0x87, 0xb3, 0x17, 0x92, 0x9f, 0xac, 0xbe, 0x11, 0xb2, 0x10, 0x4b, 0x08, 0xd5, 0x86, 0x0f, 0xe3, 0x28, 0x5b, 0x4e, 0xb2, 0x52, 0xc8, 0xe4, 0xe6, 0xb3, 0x96, 0x86, 0xc7, 0x10, 0x7d, 0xe8, 0x80, 0xff, 0x28, 0xd3, 0x5d, 0x63, 0xf0, 0x7b, 0x02, 0x19, 0x47, 0x2c, 0xec, 0x8e, 0xb8, 0xed, 0x06, 0x9d, 0x59, 0x66, 0xaf, 0xdd, 0x51, 0x4c, 0x0d, 0xd4, 0x3b, 0xdb, 0x4c, 0x26, 0xb9, 0x3a, 0x3a, 0x58, 0xe8, 0x59, 0xe6, 0xe9, 0xbb, 0x60, 0x9c, 0x7e, 0x85, 0xd4, 0x72, 0x76, 0xbd, 0xdb, 0x6e, 0x73, 0x3c, 0x9b, 0x4e, 0x6a, 0x0d, 0x5a, 0x9d, 0x3a, 0x19, 0xab, 0xf1, 0xe6, 0x87, 0x12,\n\t0xa0, 0x4f, 0xc3, 0xf2, 0x81, 0x40, 0x7f, 0xaf, 0xbb, 0x29, 0xe5, 0x25, 0x45, 0x59, 0xb6, 0x0e, 0xee, 0x0d, 0x2b, 0x73, 0x1f, 0x94, 0x65, 0x43, 0xc4, 0x01, 0x51, 0xa2, 0xd3, 0xfb, 0xa1, 0x50, 0xa2, 0x41, 0x81, 0x97, 0x46, 0x54, 0x25, 0x06, 0x41, 0x11, 0xc3, 0x5f, 0x98, 0xaa, 0x5f, 0x24, 0x11, 0xb4, 0xaa, 0x22, 0xfc, 0xb6, 0x4a, 0xc8, 0xfb, 0x34, 0x32, 0x71, 0xfb, 0x71, 0xf2, 0x71, 0x69, 0x0a, 0xa4, 0x40, 0xee, 0xd9, 0x37, 0x41, 0xf9, 0x53, 0xab, 0xd5, 0x86, 0xb4, 0xc1, 0x68, 0x30, 0x18, 0x9c, 0x55, 0xee, 0xdd, 0xf2, 0x29, 0xd5, 0xde, 0xc1, 0xf5, 0xa6, 0x5a, 0x47, 0xa6, 0x3d, 0x97, 0x08, 0xd6, 0x5b, 0x0f, 0x8f, 0x3a, 0xe5, 0x1a, 0xdf, 0xc2, 0x7c, 0xac, 0x37, 0xe3, 0xf2, 0x35, 0x2f, 0xc9, 0xa4, 0xdb, 0x1c, 0x72, 0xb9, 0x93, 0xe1, 0xac, 0xec, 0x82, 0x15, 0x63, 0xbd,\n\t0x6e, 0x27, 0xd8, 0x3a, 0xf3, 0x57, 0x7b, 0xc2, 0x1f, 0x0f, 0x76, 0x4f, 0xb5, 0x37, 0x4d, 0x0d, 0xd4, 0xf0, 0x0e, 0xbb, 0x0d, 0xe9, 0x26, 0xf5, 0xd4, 0x75, 0x54, 0x9a, 0xb9, 0x1f, 0x9e, 0x79, 0x13, 0xb1, 0x04, 0x28, 0xc4, 0x95, 0xe6, 0xda, 0x01, 0xa9, 0xea, 0x03, 0x4a, 0xd2, 0x04, 0xe4, 0xca, 0x08, 0x2f, 0x01, 0x57, 0x4a, 0xbf, 0x2a, 0xaa, 0x7f, 0x95, 0x70, 0x2b, 0xd3, 0x84, 0x92, 0x94, 0x93, 0xa8, 0x64, 0xa3, 0x5c, 0xa3, 0x25, 0x91, 0x2e, 0x36, 0x89, 0xf0, 0x19, 0x54, 0x13, 0x6a, 0xa0, 0x52, 0xe1, 0x08, 0xff, 0x73, 0x25, 0xa0, 0x2c, 0x14, 0xeb, 0x3d, 0x5d, 0xce, 0x65, 0xca, 0x94, 0x9f, 0xa3, 0xb1, 0x9d, 0xe1, 0x2c, 0xcf, 0xcf, 0x7e, 0xb4, 0xaa, 0x40, 0xe4, 0x19, 0x4f, 0x11, 0x55, 0x8d, 0xa2, 0xea, 0x90, 0xf3, 0x3c, 0x3f, 0x3e, 0x0e, 0x25, 0x71, 0x62, 0xc9, 0xe2,\n\t0xa1, 0x81, 0x9e, 0xae, 0x96, 0xa6, 0x42, 0x2e, 0x53, 0x17, 0xaf, 0x09, 0x05, 0x3c, 0x2e, 0x84, 0x93, 0x89, 0xc3, 0x2e, 0x75, 0xf3, 0x84, 0x5d, 0xca, 0x3e, 0x23, 0xea, 0x12, 0x54, 0x82, 0x24, 0xca, 0x2e, 0x5d, 0x71, 0xb3, 0x7e, 0x55, 0x6d, 0x0d, 0xd8, 0xeb, 0x73, 0xf2, 0x2b, 0xf1, 0xa6, 0xf5, 0xa5, 0xda, 0x63, 0x11, 0x77, 0x18, 0x32, 0x01, 0x9d, 0x09, 0xee, 0xd9, 0xa9, 0x96, 0xa6, 0x21, 0x93, 0x7b, 0xac, 0x31, 0xb9, 0xa0, 0xd1, 0xa7, 0xe1, 0x40, 0x44, 0xd1, 0x91, 0xf1, 0xc7, 0x9c, 0x9c, 0x46, 0xad, 0x61, 0x42, 0x96, 0x6c, 0x43, 0x83, 0x23, 0xbf, 0xc6, 0xe7, 0xdb, 0xd1, 0xbe, 0x70, 0x39, 0xde, 0xcc, 0x9b, 0xcc, 0x31, 0xde, 0xdc, 0xda, 0xb0, 0x8c, 0xd4, 0x9b, 0x9d, 0x7a, 0xaf, 0xbb, 0xa9, 0x6b, 0x77, 0xba, 0x4e, 0x67, 0xd4, 0xe9, 0xe1, 0x9e, 0x8e, 0xc6, 0xc2, 0xc1,\n\t0x18, 0x94, 0xb3, 0x1b, 0x7d, 0x96, 0xce, 0x56, 0xad, 0x5e, 0x23, 0x97, 0xa5, 0x1d, 0x7e, 0x4e, 0x51, 0x9b, 0xc9, 0xa4, 0x16, 0xf4, 0xbb, 0x9b, 0xeb, 0x78, 0x52, 0xda, 0xdf, 0x1c, 0x3c, 0xe3, 0x0a, 0x22, 0x4e, 0xb4, 0x16, 0x9b, 0xce, 0x5a, 0x91, 0x77, 0xb2, 0x1c, 0xff, 0x32, 0x8d, 0xe2, 0xa6, 0x62, 0xd1, 0x50, 0xe0, 0x2c, 0xe5, 0x78, 0x43, 0xf3, 0x95, 0xe3, 0x95, 0xe6, 0x22, 0xf2, 0xb0, 0xc6, 0x11, 0x76, 0xd6, 0x37, 0x2a, 0x84, 0xaf, 0x59, 0xf2, 0x8d, 0x4d, 0xce, 0xfc, 0xda, 0xbe, 0x68, 0xa0, 0x73, 0x4d, 0x53, 0xfd, 0xb2, 0x56, 0x3f, 0x1c, 0x6b, 0x83, 0xbc, 0xa7, 0xd1, 0x1d, 0x83, 0x6c, 0xd0, 0xa0, 0xa4, 0x27, 0xcc, 0x11, 0xb7, 0xb1, 0x90, 0x7d, 0xdf, 0x09, 0xbb, 0x1c, 0xec, 0xdd, 0xdc, 0x93, 0x5b, 0xd3, 0x5b, 0xe3, 0x6b, 0x1d, 0x6f, 0xf0, 0x59, 0xfa, 0x3b, 0xb4,\n\t0xac, 0x16, 0xe9, 0x0c, 0x19, 0x28, 0x9f, 0x7f, 0x0f, 0xf6, 0xbd, 0x40, 0xec, 0x28, 0xea, 0x0a, 0x80, 0x90, 0x25, 0xe0, 0xe9, 0xf3, 0x4a, 0x70, 0xc3, 0x41, 0xb8, 0x95, 0xfc, 0x88, 0x55, 0xd2, 0xa2, 0x18, 0x83, 0xd3, 0xfa, 0x27, 0xc5, 0x6d, 0x57, 0xca, 0xd4, 0x9e, 0x16, 0x83, 0x62, 0xca, 0x90, 0xc2, 0x67, 0xdc, 0x5c, 0xb9, 0x6f, 0xbc, 0xa8, 0xaa, 0x0d, 0x07, 0x82, 0x7c, 0x30, 0x22, 0xaf, 0x2e, 0x04, 0x2b, 0xab, 0xaa, 0x03, 0x6b, 0x99, 0xa7, 0x0c, 0x2c, 0x28, 0x1d, 0x4d, 0x70, 0x87, 0x42, 0xab, 0x54, 0x72, 0xf6, 0xa0, 0x23, 0x1a, 0xaf, 0x4b, 0x36, 0x37, 0x67, 0x93, 0xf1, 0x98, 0x2b, 0xe4, 0xb4, 0x68, 0x8c, 0xf2, 0xa8, 0x25, 0x9b, 0xcb, 0x58, 0x10, 0xd6, 0x69, 0x5d, 0x34, 0x19, 0x40, 0xf8, 0xdd, 0xad, 0xcb, 0xbd, 0x4c, 0x42, 0x2b, 0x53, 0x69, 0x54, 0x2e, 0x9b, 0xdd,\n\t0x33, 0xe1, 0x75, 0xb9, 0x43, 0x3a, 0x56, 0xa7, 0xcd, 0x38, 0xfc, 0x26, 0x85, 0xb9, 0xa6, 0x25, 0x52, 0xdb, 0x66, 0xe0, 0xda, 0xdd, 0xae, 0x4c, 0xc4, 0x1a, 0x42, 0x3c, 0xcf, 0x47, 0x1d, 0x05, 0x2f, 0x32, 0xf7, 0xc2, 0x79, 0x78, 0xab, 0xa8, 0x42, 0x31, 0x7e, 0x36, 0x1c, 0xe3, 0x27, 0x9a, 0xc5, 0x63, 0xe5, 0x50, 0xbf, 0x39, 0x21, 0x7e, 0x18, 0xa4, 0xa9, 0x52, 0xa2, 0x7c, 0x1a, 0xa7, 0xf0, 0xa8, 0x3f, 0xed, 0x89, 0x6d, 0xf3, 0x3d, 0xa1, 0xf9, 0x07, 0xdb, 0xf8, 0x47, 0x5e, 0x8f, 0x92, 0xc2, 0xd4, 0x68, 0xd2, 0x03, 0xa1, 0xda, 0xa0, 0xc4, 0x12, 0xca, 0x61, 0x87, 0xe0, 0x8c, 0xb0, 0xc3, 0x7c, 0x55, 0x6d, 0x56, 0xc9, 0xba, 0x1d, 0xf1, 0xc1, 0xc9, 0xcd, 0x5a, 0x62, 0x0b, 0x5b, 0x82, 0xb5, 0xc1, 0x08, 0xef, 0xcc, 0x2f, 0xce, 0xb5, 0x8e, 0x79, 0xbd, 0x0a, 0xad, 0x4a, 0x69,\n\t0x84, 0x6b, 0x51, 0x13, 0x4b, 0xd7, 0xc2, 0xb5, 0xa8, 0x8d, 0xc7, 0xdc, 0x21, 0xa7, 0x59, 0x63, 0x50, 0x31, 0x23, 0xf0, 0x88, 0xc8, 0xcd, 0xd1, 0xe6, 0x48, 0xac, 0x99, 0x35, 0xb5, 0x7a, 0x91, 0x98, 0x17, 0x72, 0xe7, 0xb5, 0x72, 0x95, 0x56, 0xe5, 0xb2, 0x3a, 0x2a, 0x6b, 0x81, 0x78, 0x43, 0x3b, 0x79, 0x17, 0xf1, 0x3b, 0xe6, 0x0e, 0x1c, 0x63, 0x08, 0xb9, 0x39, 0xd2, 0xaf, 0x49, 0x6a, 0x2d, 0x8a, 0x32, 0x44, 0x7a, 0x25, 0x31, 0x09, 0xe6, 0x06, 0x18, 0x72, 0x50, 0x56, 0x90, 0xcf, 0x09, 0x44, 0x5a, 0x74, 0xf8, 0x5f, 0x74, 0x36, 0x9f, 0x91, 0xf5, 0x58, 0x75, 0x3a, 0xab, 0x87, 0x35, 0xfa, 0x6c, 0x3a, 0xea, 0x66, 0x52, 0x39, 0xf3, 0xd7, 0x93, 0x46, 0x2f, 0xfa, 0x09, 0xb9, 0x5d, 0x10, 0xb7, 0xf6, 0x8a, 0x7a, 0xc9, 0x22, 0xf2, 0x2d, 0xd2, 0x0d, 0xd7, 0x3a, 0x42, 0x7c, 0xb5,\n\t0xa8, 0xe2, 0xa1, 0x5a, 0xcf, 0x56, 0xe1, 0xe0, 0xe2, 0xd2, 0x98, 0x24, 0x58, 0x8b, 0x8f, 0x2a, 0x92, 0x0c, 0x27, 0x45, 0x87, 0x00, 0xfe, 0x93, 0x2e, 0xad, 0xef, 0x19, 0x77, 0x6d, 0xab, 0xdc, 0xb5, 0x8d, 0x2e, 0xad, 0xe9, 0x67, 0xbd, 0xeb, 0xb3, 0x5e, 0x23, 0x82, 0x77, 0x72, 0xc1, 0x68, 0x0d, 0x86, 0xd6, 0xe2, 0xce, 0x52, 0xa5, 0x6e, 0x56, 0x45, 0x1e, 0xeb, 0x8f, 0x7d, 0x03, 0x99, 0x78, 0x47, 0xd2, 0x6a, 0x49, 0x0f, 0x66, 0xdd, 0x71, 0x87, 0x9e, 0xd1, 0xab, 0x14, 0x06, 0x7d, 0x7f, 0x34, 0xea, 0xce, 0x41, 0x6e, 0xe6, 0x50, 0x32, 0xeb, 0xbd, 0x21, 0x77, 0x6e, 0x20, 0x2e, 0xfc, 0x28, 0x39, 0xdc, 0xe0, 0x55, 0xab, 0x5b, 0x59, 0x25, 0xb3, 0x02, 0x14, 0x63, 0x29, 0xbb, 0x45, 0x38, 0x42, 0x2a, 0x6d, 0xe2, 0x1c, 0x05, 0x21, 0x5d, 0xf8, 0x6f, 0x48, 0x17, 0xa2, 0x48, 0x6a,\n\t0x46, 0xf9, 0x36, 0x51, 0x1c, 0x2b, 0x57, 0x0a, 0x7e, 0x2b, 0x05, 0xbd, 0x61, 0xc6, 0x5b, 0x89, 0x98, 0x86, 0x87, 0x3c, 0x0a, 0x4f, 0x78, 0xa0, 0xba, 0xbb, 0xd5, 0x5b, 0x29, 0x05, 0x66, 0xa7, 0x14, 0x2e, 0x90, 0xab, 0xd5, 0x2a, 0xce, 0xe6, 0xb7, 0xb7, 0xb7, 0x74, 0x34, 0xb8, 0x03, 0x56, 0x0e, 0x1e, 0xe5, 0x1a, 0x4b, 0x26, 0xdf, 0xe0, 0x4c, 0x8f, 0x15, 0xc3, 0x7c, 0xc7, 0xda, 0xf6, 0x96, 0x71, 0xa8, 0x30, 0x29, 0x94, 0x1a, 0xad, 0x66, 0x6c, 0x68, 0xe1, 0x32, 0x9d, 0x41, 0xa7, 0xc9, 0x60, 0x6a, 0xd6, 0x33, 0x55, 0x6c, 0xdc, 0xd0, 0x5f, 0x03, 0x95, 0x16, 0x40, 0xd4, 0xd1, 0xb7, 0x91, 0x4d, 0x70, 0x3d, 0xf5, 0xc4, 0x79, 0x55, 0xb1, 0x1b, 0x55, 0xc1, 0x21, 0x93, 0x44, 0x69, 0xdd, 0xe6, 0x5e, 0xd9, 0x46, 0x94, 0xbd, 0xe8, 0xf3, 0x3c, 0x33, 0xdf, 0xed, 0x18, 0xb3, 0x04,\n\t0x7e, 0xd7, 0x13, 0xfa, 0x20, 0x2b, 0x96, 0x1f, 0xca, 0x06, 0xfc, 0x95, 0x40, 0x13, 0xf0, 0xf0, 0x05, 0x17, 0x1e, 0x0d, 0x77, 0xaf, 0x6b, 0x6e, 0x5a, 0xd7, 0x13, 0xa2, 0x6f, 0xbb, 0xeb, 0xae, 0xb6, 0xc9, 0xde, 0x50, 0xa8, 0x77, 0xb2, 0x4d, 0x9c, 0xd7, 0x7a, 0xea, 0x7a, 0xb2, 0x99, 0xbe, 0x0d, 0xc5, 0x53, 0x8b, 0x31, 0x2c, 0x92, 0x71, 0x00, 0x8b, 0x6f, 0xd8, 0x27, 0x63, 0x20, 0x0c, 0xfc, 0x19, 0xa1, 0x24, 0x68, 0x12, 0xc9, 0xe6, 0x50, 0xcf, 0xba, 0xa6, 0x66, 0xf8, 0xda, 0xeb, 0xf7, 0xb6, 0x34, 0xd2, 0xb7, 0xb5, 0x4d, 0xf5, 0x84, 0x42, 0x3d, 0x53, 0x6d, 0x77, 0x2d, 0x5a, 0x2c, 0xbe, 0xbb, 0x83, 0x7a, 0x84, 0x5c, 0xca, 0xec, 0x83, 0x27, 0xe9, 0x42, 0x69, 0x1e, 0xb0, 0x91, 0x86, 0x58, 0x5b, 0xf2, 0x21, 0x4e, 0x92, 0xa5, 0x5c, 0x57, 0x73, 0xf9, 0xa7, 0x72, 0xf1, 0xd4,\n\t0x73, 0xf1, 0x54, 0x78, 0xce, 0xf2, 0x18, 0xaa, 0xe7, 0x57, 0x65, 0x5d, 0xab, 0x72, 0x25, 0xc3, 0x09, 0x79, 0x8a, 0x35, 0xf3, 0x11, 0x11, 0x9d, 0x0e, 0xcc, 0xf1, 0x97, 0x63, 0xe7, 0x31, 0xa9, 0xf3, 0x44, 0x3c, 0x68, 0xcb, 0x3d, 0x09, 0x86, 0x62, 0x69, 0x87, 0xb8, 0xcf, 0xe8, 0x8f, 0x7d, 0x03, 0x59, 0xb4, 0x51, 0x8f, 0xc0, 0xad, 0x99, 0xb5, 0x1e, 0x19, 0x73, 0xca, 0xe1, 0xeb, 0x06, 0xa1, 0x0e, 0x5d, 0xcb, 0x9c, 0x44, 0x91, 0x8a, 0xc5, 0x06, 0x3f, 0x3c, 0x9b, 0x6a, 0x86, 0x44, 0xf5, 0xef, 0x30, 0x50, 0x2b, 0x35, 0x2e, 0xfa, 0x4b, 0x26, 0x45, 0xdc, 0x56, 0x31, 0x27, 0x46, 0x9c, 0xb5, 0x00, 0x11, 0x08, 0x70, 0x7e, 0x2e, 0x38, 0x4f, 0x7d, 0x3b, 0x50, 0xaa, 0x6f, 0x97, 0x91, 0x94, 0x0e, 0x29, 0x57, 0xab, 0x16, 0x8a, 0x76, 0x4a, 0x67, 0xb1, 0xb6, 0xae, 0xcd, 0x60, 0x5f,\n\t0x55, 0xb7, 0x62, 0xcd, 0xe1, 0x91, 0x40, 0xfa, 0x70, 0x24, 0x6c, 0x8f, 0x73, 0xcc, 0x49, 0x28, 0xd4, 0xf1, 0xee, 0x50, 0x26, 0x5e, 0x9f, 0xd8, 0xb4, 0x16, 0x0c, 0x09, 0x4f, 0x8e, 0xd7, 0xc6, 0xd1, 0x47, 0xba, 0xc6, 0x6a, 0x02, 0xd8, 0x46, 0x68, 0x83, 0xeb, 0x18, 0x86, 0x7b, 0xae, 0x86, 0xd8, 0x57, 0x54, 0x87, 0xcc, 0x70, 0xa6, 0x14, 0xd8, 0xcf, 0x56, 0x9a, 0x78, 0xd4, 0x49, 0x11, 0x85, 0x9a, 0x96, 0xac, 0x3e, 0xd2, 0x06, 0xc4, 0x88, 0xea, 0x73, 0xaf, 0x68, 0xce, 0xf2, 0xcc, 0x7c, 0xb7, 0xc3, 0xf9, 0xfe, 0x46, 0x4d, 0x4d, 0x28, 0x18, 0xc4, 0x25, 0x44, 0xce, 0x70, 0xda, 0x55, 0x18, 0x66, 0x89, 0xc6, 0x37, 0x03, 0x32, 0x0c, 0xd4, 0x0e, 0x7b, 0x66, 0x53, 0x6d, 0x6a, 0x53, 0xc6, 0x6e, 0x57, 0x03, 0xce, 0x37, 0x12, 0xa9, 0x49, 0x3b, 0xd2, 0x5d, 0xb1, 0x58, 0x17, 0xfc,\n\t0xa8, 0x09, 0x8f, 0xf8, 0x4c, 0xd4, 0x8b, 0x6a, 0xa3, 0x5e, 0x11, 0xf4, 0xf9, 0x82, 0x0a, 0xbd, 0x51, 0x9d, 0x31, 0xbb, 0xd3, 0xdb, 0x1b, 0x82, 0xed, 0x49, 0x87, 0x23, 0xd9, 0x1e, 0x6c, 0xd8, 0x9e, 0x76, 0x9b, 0x45, 0x59, 0x7e, 0x11, 0xf9, 0x0e, 0xd9, 0x22, 0xdb, 0x4b, 0xd8, 0x89, 0x2c, 0x5a, 0xa1, 0x08, 0xc0, 0xba, 0x34, 0xa8, 0x07, 0x0c, 0x41, 0x0d, 0x42, 0xc9, 0x47, 0xb6, 0xa7, 0x84, 0x16, 0x3e, 0xcb, 0x61, 0x40, 0x60, 0x11, 0x91, 0xab, 0x8d, 0x04, 0xf9, 0x28, 0x86, 0x66, 0xe5, 0x3c, 0x60, 0x6e, 0x8c, 0x3b, 0x0e, 0xd8, 0x8a, 0xcc, 0xea, 0x7a, 0x89, 0x4e, 0x98, 0x03, 0x6f, 0xb0, 0x71, 0x37, 0x9f, 0xf2, 0xea, 0xcc, 0x81, 0xb8, 0xd9, 0xa7, 0xcf, 0xd6, 0xa7, 0xc2, 0x99, 0xf8, 0x61, 0x57, 0xd3, 0x8a, 0x96, 0xc6, 0xc5, 0x19, 0x5b, 0x3a, 0xdd, 0x3d, 0xc0, 0xb7, 0x8c,\n\t0x66, 0xc3, 0x6d, 0xb6, 0xc3, 0x74, 0xc0, 0x86, 0x00, 0xc2, 0x9c, 0xc1, 0x84, 0x4d, 0x7e, 0x6e, 0xb8, 0x3e, 0x9b, 0x1c, 0x59, 0xc7, 0x20, 0x8b, 0x21, 0x9f, 0xed, 0xf6, 0x67, 0x16, 0x99, 0x4c, 0x93, 0x5d, 0x89, 0x25, 0x6d, 0x21, 0x8b, 0xf5, 0x87, 0xe2, 0x99, 0xd1, 0x91, 0xbf, 0x27, 0x73, 0xcc, 0x5d, 0x50, 0x33, 0xaf, 0x29, 0x86, 0xad, 0x0a, 0x06, 0x63, 0xdf, 0xa2, 0x0b, 0x7b, 0x70, 0xf4, 0x15, 0xb6, 0x17, 0x61, 0x26, 0x04, 0xef, 0xf0, 0x04, 0x42, 0x16, 0x7c, 0x2e, 0x75, 0x94, 0xe8, 0x93, 0x13, 0x11, 0xa7, 0xeb, 0x71, 0xd0, 0x1c, 0x22, 0xc6, 0x64, 0x4e, 0x93, 0x68, 0xec, 0xf2, 0x1f, 0x56, 0x79, 0x13, 0x4d, 0x21, 0xce, 0x51, 0x93, 0x59, 0x58, 0x08, 0xaa, 0x8c, 0x1e, 0xa8, 0x86, 0x32, 0x16, 0x1d, 0x73, 0x32, 0xbf, 0xf7, 0xa2, 0x0b, 0xb2, 0x6f, 0xbd, 0xd9, 0x7c, 0xc5,\n\t0xf6, 0xbe, 0xac, 0xd9, 0x53, 0x3f, 0x71, 0xe9, 0x50, 0x60, 0x78, 0xc1, 0x20, 0x6f, 0x33, 0xc2, 0xa9, 0xaa, 0x85, 0xfb, 0x29, 0x21, 0x3b, 0x1f, 0xc5, 0x9f, 0x11, 0x0f, 0x8a, 0x9b, 0x48, 0xdd, 0x06, 0xc9, 0x6e, 0x9d, 0x02, 0x71, 0x08, 0x09, 0x00, 0x03, 0xfd, 0x04, 0xca, 0x3f, 0xcd, 0xba, 0xa1, 0x94, 0x07, 0xef, 0x42, 0x86, 0x78, 0x12, 0x17, 0x77, 0x87, 0x1f, 0x34, 0x39, 0x59, 0x66, 0x2d, 0xd3, 0x54, 0x09, 0xf8, 0xc2, 0x0c, 0x0f, 0x14, 0x96, 0x4c, 0x67, 0x5f, 0xfc, 0xf4, 0x67, 0x51, 0x2d, 0x55, 0x40, 0x34, 0x37, 0xc4, 0xa2, 0x4e, 0xbb, 0xc5, 0x44, 0xb0, 0x80, 0x95, 0x55, 0x8a, 0x94, 0x4b, 0x96, 0x22, 0xae, 0x4a, 0xa4, 0xf3, 0xd0, 0x55, 0xd2, 0xab, 0x68, 0x2c, 0xc2, 0x33, 0x05, 0x6a, 0xb3, 0x45, 0x14, 0xbb, 0x62, 0x89, 0x7a, 0x39, 0x9d, 0x2b, 0xfe, 0x33, 0xd2, 0xc0,\n\t0x2a, 0x43, 0xc9, 0xb4, 0xc9, 0x65, 0x4f, 0xf5, 0x2e, 0xee, 0x4d, 0xf9, 0x3b, 0xd6, 0xb6, 0xb4, 0xac, 0xed, 0x0c, 0x2c, 0x5a, 0x62, 0x0a, 0x38, 0xf4, 0x6b, 0xd7, 0x9b, 0xea, 0x73, 0x59, 0x33, 0xf5, 0x97, 0xfe, 0x76, 0x7f, 0x3e, 0xe6, 0xd7, 0x29, 0xdd, 0x35, 0x85, 0x20, 0xb2, 0x2e, 0x91, 0x1c, 0xab, 0x51, 0xaa, 0x94, 0x06, 0x8d, 0xd1, 0x17, 0xae, 0xeb, 0x5e, 0x53, 0xcc, 0x8d, 0x77, 0x84, 0x82, 0xc5, 0x95, 0xb9, 0x91, 0x3d, 0x7e, 0x8d, 0x93, 0x8f, 0xd8, 0x5b, 0x87, 0x29, 0x99, 0x82, 0x81, 0xf3, 0x9a, 0x22, 0x7f, 0x4f, 0xe9, 0xb1, 0xfe, 0x5d, 0x8f, 0x72, 0x54, 0xc3, 0xd8, 0xab, 0x85, 0xad, 0x40, 0x78, 0x7d, 0xb1, 0x54, 0x8e, 0x82, 0xf4, 0x45, 0x9f, 0x16, 0x1c, 0x67, 0x7d, 0x1d, 0xcb, 0xda, 0xa0, 0xf6, 0x2c, 0x17, 0xd1, 0xb2, 0x4b, 0xa5, 0x54, 0x03, 0x62, 0xf7, 0xcd,\n\t0x15, 0x7f, 0x2c, 0xb2, 0x81, 0x59, 0x3d, 0x22, 0xf6, 0x0a, 0x0a, 0x44, 0x06, 0x6f, 0x2e, 0x5a, 0x61, 0xf6, 0x45, 0x38, 0xbb, 0xef, 0xf2, 0x8d, 0xa3, 0x0d, 0xab, 0x3a, 0x82, 0xb5, 0x8b, 0x77, 0x75, 0x5e, 0xde, 0xb9, 0x63, 0x24, 0xe9, 0xca, 0xf4, 0xc5, 0x83, 0x0c, 0xc9, 0x28, 0x65, 0x81, 0xf8, 0xf2, 0x61, 0xea, 0x03, 0x72, 0xe5, 0xf2, 0x60, 0x63, 0xc4, 0xe4, 0x4b, 0xac, 0x5b, 0x1a, 0xe9, 0x5e, 0x93, 0xef, 0xd8, 0x3c, 0x10, 0x01, 0x5f, 0xfa, 0x12, 0x88, 0xf4, 0x4e, 0xb6, 0xd4, 0x2e, 0xe9, 0xca, 0xb1, 0x0d, 0x0a, 0xa3, 0x41, 0x43, 0x59, 0x86, 0xf3, 0x0b, 0x96, 0x23, 0xb0, 0x30, 0xa8, 0xcb, 0xfd, 0x82, 0x54, 0x30, 0x5f, 0x26, 0x52, 0xc4, 0x8a, 0xa2, 0x32, 0xee, 0xe7, 0x54, 0xc8, 0x1b, 0x31, 0x28, 0xa1, 0x25, 0x20, 0x5c, 0x64, 0xa8, 0x39, 0x13, 0xeb, 0x70, 0x4e, 0x06,\n\t0xc2, 0xbd, 0xc0, 0xe4, 0xda, 0x85, 0x32, 0xe7, 0x18, 0x0c, 0x77, 0xcf, 0x10, 0x73, 0x2f, 0x8b, 0x6e, 0x99, 0x14, 0x51, 0x0b, 0xc9, 0x48, 0x3c, 0x80, 0xd5, 0x62, 0xa9, 0xa0, 0x3c, 0x22, 0x9a, 0x7a, 0x6c, 0x04, 0xe5, 0x22, 0xc8, 0xbe, 0x94, 0x6b, 0x11, 0xed, 0x03, 0xc8, 0x4c, 0x20, 0xd9, 0xca, 0xe1, 0x98, 0x33, 0xa4, 0xc2, 0xe2, 0xb1, 0x27, 0xa3, 0x7e, 0x5d, 0x27, 0x29, 0xa7, 0x17, 0xd2, 0x2c, 0x3b, 0x79, 0xdf, 0x02, 0x9d, 0xd7, 0xc7, 0x29, 0x2d, 0xe6, 0xa6, 0x85, 0xb6, 0x6e, 0x52, 0xc6, 0x0c, 0xd2, 0x46, 0x76, 0xf2, 0xde, 0xa5, 0x2a, 0xb7, 0x9b, 0xea, 0x2f, 0x78, 0x8c, 0x4a, 0x5b, 0x3c, 0x70, 0x3b, 0xcb, 0x6b, 0xee, 0x55, 0xeb, 0xc1, 0xb6, 0xc7, 0x3d, 0xe6, 0x8c, 0x9a, 0xd3, 0x2a, 0x12, 0x8d, 0x27, 0x59, 0x8f, 0xe6, 0x3e, 0xb5, 0x5e, 0xb8, 0xed, 0x79, 0xab, 0x4d,\n\t0xa4, 0x2f, 0xfd, 0xc2, 0x5e, 0xb2, 0x01, 0xd4, 0x11, 0x1a, 0x82, 0x27, 0x96, 0x15, 0x55, 0x88, 0xb6, 0xa0, 0x5a, 0x32, 0x25, 0x90, 0x5e, 0x4b, 0x99, 0xaa, 0x94, 0x62, 0x24, 0x69, 0x7a, 0x2b, 0x8d, 0xab, 0x2e, 0xe1, 0x35, 0x2d, 0x5f, 0x45, 0xd6, 0x34, 0xa2, 0x6c, 0x4c, 0x1b, 0xff, 0x06, 0x17, 0x8d, 0x04, 0x71, 0xd1, 0x25, 0xab, 0x07, 0x54, 0xa8, 0x4d, 0x60, 0x96, 0x20, 0x89, 0xe8, 0xcc, 0x7f, 0x58, 0xf2, 0x8e, 0x4c, 0x5b, 0x73, 0x3a, 0xd9, 0x7e, 0xd8, 0xd7, 0xb6, 0xaa, 0x25, 0xb3, 0xb2, 0x27, 0x0a, 0xd5, 0xfe, 0xfa, 0x68, 0xb7, 0xf3, 0xf0, 0xb0, 0xd3, 0x82, 0x74, 0xfe, 0x62, 0x7b, 0x7e, 0x79, 0xab, 0x3f, 0xd4, 0x3d, 0xd9, 0xda, 0x3c, 0x39, 0x50, 0x63, 0xb7, 0xfe, 0x88, 0x20, 0x4e, 0x9f, 0x26, 0x52, 0xc2, 0x5e, 0x4a, 0x0f, 0xd2, 0x94, 0x9c, 0x1a, 0x21, 0x88, 0x8f,\n\t0xaf, 0x23, 0x94, 0x8f, 0x11, 0xe4, 0x37, 0x3f, 0xbe, 0xee, 0xd1, 0x4c, 0x5c, 0x1c, 0xd7, 0xa5, 0xa7, 0xdf, 0x93, 0x5d, 0x46, 0x43, 0x3d, 0x8f, 0x68, 0x27, 0xbe, 0x53, 0xd4, 0xa3, 0xf2, 0xca, 0xcd, 0x50, 0xcb, 0x8a, 0xf9, 0x49, 0x9a, 0xa1, 0xca, 0x6a, 0x06, 0x43, 0x21, 0x47, 0xd6, 0x4e, 0x35, 0x8a, 0xbd, 0x64, 0xc4, 0xd8, 0x4b, 0x72, 0x5c, 0xa5, 0xc0, 0x11, 0xbf, 0x4a, 0x5c, 0x62, 0xa9, 0x14, 0x49, 0x2d, 0x72, 0xea, 0xcf, 0xfb, 0xc4, 0x0e, 0x19, 0xc6, 0xae, 0x99, 0x7b, 0xb3, 0x0a, 0x43, 0x02, 0x54, 0xaa, 0x01, 0xcd, 0x7a, 0x00, 0x1e, 0x78, 0x17, 0x81, 0xe1, 0x1f, 0xb3, 0x99, 0xda, 0x44, 0x34, 0x8c, 0x52, 0x28, 0xcd, 0x9c, 0x56, 0x8d, 0x95, 0x55, 0x0d, 0x0e, 0xc5, 0xc7, 0x47, 0x43, 0x4e, 0x95, 0x43, 0xd2, 0x03, 0xbc, 0x18, 0xd8, 0x53, 0x52, 0xe0, 0xca, 0xba, 0x7c,\n\t0x99, 0xeb, 0x22, 0x46, 0xcc, 0xfc, 0x88, 0x2f, 0xae, 0x6a, 0xb9, 0xe4, 0x7a, 0x8e, 0x4d, 0xdf, 0x71, 0xe1, 0x92, 0x9b, 0xb6, 0x17, 0x4d, 0xce, 0x99, 0x69, 0xaa, 0x76, 0xf1, 0xce, 0x9e, 0x8e, 0xb5, 0x3d, 0x29, 0xa3, 0x4d, 0xdb, 0x10, 0x5c, 0xbd, 0x69, 0x4b, 0xea, 0xe0, 0x2b, 0xad, 0x0b, 0x5e, 0xbf, 0x68, 0xe9, 0x81, 0xd1, 0xc4, 0x2b, 0x93, 0x93, 0xe3, 0xb7, 0x37, 0xf2, 0xb7, 0x92, 0xdb, 0x9b, 0x36, 0xf4, 0x47, 0x8f, 0x5e, 0x0a, 0xe4, 0x5d, 0x8b, 0x5b, 0xcf, 0x7b, 0x70, 0x7b, 0xd2, 0x3b, 0x71, 0xcd, 0xca, 0x04, 0x8a, 0xa6, 0xc6, 0xa0, 0xb0, 0xe7, 0xae, 0xdf, 0xb0, 0xa3, 0x52, 0xe9, 0x7b, 0xed, 0xa2, 0xa9, 0x8b, 0xc0, 0x2f, 0x88, 0x12, 0xae, 0xd0, 0x79, 0x70, 0xee, 0x35, 0x44, 0x0e, 0x72, 0x6b, 0x73, 0xc4, 0xaf, 0x21, 0x68, 0x19, 0x51, 0xef, 0xb4, 0x31, 0x34, 0x25,\n\t0xe3, 0x0c, 0x24, 0xc0, 0xca, 0x2e, 0x9a, 0x4f, 0x3f, 0x1c, 0x3b, 0xdc, 0x30, 0x32, 0x94, 0xc3, 0x8e, 0x52, 0xd8, 0xcf, 0xc5, 0x66, 0x25, 0x31, 0xcc, 0x89, 0x2c, 0xd5, 0xf8, 0x0e, 0x9f, 0x71, 0x93, 0x14, 0x0f, 0x21, 0x21, 0x88, 0x92, 0xa5, 0x32, 0xdf, 0x7a, 0xad, 0x56, 0x9b, 0xd3, 0xe6, 0xc2, 0x41, 0x93, 0xd5, 0x1a, 0xc5, 0x39, 0xe4, 0x1e, 0xca, 0x2a, 0x99, 0xe3, 0x18, 0x13, 0x96, 0xd7, 0x6b, 0xa9, 0x08, 0xce, 0x2b, 0x47, 0xf4, 0xa5, 0x50, 0x55, 0x4f, 0x13, 0x55, 0xa4, 0xce, 0x81, 0x5f, 0xb5, 0x9f, 0xbf, 0x6b, 0x67, 0x8b, 0x98, 0x3a, 0x7e, 0x6c, 0xff, 0xfe, 0x57, 0x8a, 0xe7, 0xc1, 0xaf, 0x2f, 0xb7, 0xa5, 0x8f, 0x5d, 0xbe, 0x6f, 0x56, 0x85, 0x86, 0xb6, 0x24, 0x79, 0x58, 0x97, 0xac, 0xaf, 0xd5, 0xdd, 0x87, 0xe2, 0x25, 0xb7, 0x1d, 0xba, 0x97, 0x15, 0x5e, 0x04, 0x03,\n\t0x5a, 0xf8, 0x8b, 0x5e, 0xd0, 0x01, 0x41, 0xb3, 0x74, 0xe0, 0xf0, 0x3d, 0x2c, 0x98, 0xac, 0xd4, 0x6d, 0x78, 0x4c, 0xb3, 0x64, 0x50, 0xe4, 0x7f, 0x81, 0xd3, 0xef, 0xd1, 0x63, 0x70, 0x6e, 0x26, 0x88, 0xc9, 0xe2, 0xba, 0x09, 0x00, 0x94, 0x08, 0xf3, 0xb7, 0x1f, 0x28, 0xe4, 0x49, 0x5c, 0xdf, 0x7b, 0x2e, 0xf6, 0x2f, 0x8a, 0xa2, 0x94, 0x9f, 0x4b, 0xc8, 0x51, 0x18, 0xc3, 0xb9, 0x84, 0x82, 0x01, 0x0a, 0xe6, 0x5c, 0x82, 0x81, 0x34, 0x46, 0x76, 0x6e, 0x09, 0xc4, 0xed, 0xdc, 0x72, 0x05, 0x6e, 0x54, 0x8b, 0x62, 0x79, 0x30, 0x19, 0x08, 0xc5, 0xe1, 0x3f, 0x62, 0x61, 0xda, 0x59, 0x59, 0x92, 0x74, 0xe9, 0x2c, 0xe6, 0x9b, 0x11, 0x4b, 0xb5, 0xcc, 0x9f, 0x03, 0x47, 0x4b, 0x18, 0xaa, 0x26, 0x19, 0xdc, 0x71, 0x90, 0xe6, 0x86, 0xcb, 0x88, 0x8f, 0x1b, 0xab, 0xd1, 0x8e, 0xfc, 0x8d, 0x43,\n\t0x4b, 0x47, 0x23, 0xac, 0x97, 0x6d, 0x69, 0xd0, 0x5b, 0xce, 0x05, 0xc6, 0x78, 0x7f, 0x83, 0x02, 0xd5, 0x15, 0xda, 0xf2, 0x78, 0x4b, 0xad, 0xc2, 0x66, 0xe2, 0xa2, 0x52, 0x21, 0x21, 0x7f, 0xf3, 0xf0, 0xb2, 0x31, 0x34, 0xe9, 0xf0, 0x3e, 0xeb, 0x76, 0x63, 0x72, 0xb8, 0x49, 0x59, 0xb7, 0xfa, 0xd0, 0x0a, 0x5c, 0x54, 0x48, 0x82, 0x3d, 0xca, 0xb8, 0xf9, 0x5a, 0xbf, 0xd3, 0xe1, 0x36, 0x31, 0x4c, 0x2e, 0xa6, 0xb3, 0xa6, 0xc6, 0x07, 0xf3, 0x1a, 0x9f, 0x1f, 0x15, 0x18, 0xea, 0xcd, 0x57, 0x6a, 0x0a, 0x05, 0xea, 0x02, 0xf0, 0x1e, 0x33, 0x23, 0xcf, 0xc5, 0xb4, 0xd6, 0xf4, 0xca, 0xa1, 0xbc, 0x9a, 0xaf, 0x91, 0xca, 0x0b, 0xa1, 0xd8, 0x04, 0xe1, 0x66, 0xea, 0x47, 0xb4, 0x12, 0xaa, 0x09, 0x01, 0x62, 0x0d, 0x71, 0x7d, 0x51, 0xdd, 0x07, 0x18, 0x72, 0xa4, 0x16, 0xb1, 0x55, 0x69, 0xaf,\n\t0xc5, 0x11, 0x80, 0x2d, 0x54, 0xde, 0x27, 0x4b, 0xb9, 0x62, 0x90, 0x66, 0x95, 0x70, 0x13, 0x15, 0x8a, 0xcd, 0x18, 0x47, 0x0a, 0x27, 0xe2, 0xee, 0x94, 0xe3, 0xc3, 0xab, 0x40, 0x15, 0x37, 0x51, 0x32, 0xfe, 0xd9, 0x9e, 0xaa, 0x7e, 0x00, 0xe3, 0x4e, 0x4d, 0xac, 0x5c, 0x31, 0x56, 0x6c, 0xcb, 0x67, 0x93, 0x71, 0x9f, 0x07, 0x17, 0xb1, 0xd2, 0x03, 0x3d, 0xca, 0xc3, 0x64, 0x2a, 0x19, 0x85, 0x90, 0x71, 0x51, 0x68, 0x21, 0x2a, 0x39, 0x35, 0x54, 0x49, 0x7c, 0x14, 0x7f, 0x93, 0xe5, 0xce, 0x10, 0xc8, 0xaa, 0xe4, 0x32, 0x14, 0x79, 0x48, 0xba, 0x37, 0x9d, 0xe3, 0xcc, 0x8f, 0x64, 0xb2, 0x23, 0x39, 0xe7, 0x39, 0x3f, 0xaa, 0xe9, 0x99, 0x98, 0xde, 0x5a, 0x97, 0xed, 0xe4, 0x7b, 0xb6, 0x0c, 0xf4, 0xed, 0x18, 0x8a, 0x24, 0x74, 0x86, 0xa6, 0xe9, 0xeb, 0x97, 0xf5, 0x34, 0x7b, 0xbd, 0xcd,\n\t0x6b, 0x2f, 0x39, 0x70, 0xc9, 0xda, 0xe6, 0x8e, 0x7d, 0x8f, 0xef, 0xda, 0xf9, 0x95, 0x1d, 0x85, 0x89, 0xc5, 0x89, 0x8c, 0x81, 0x4f, 0xf3, 0x43, 0x63, 0x4d, 0x9b, 0x8e, 0x8d, 0x76, 0xee, 0x49, 0x0b, 0xff, 0x9b, 0x7c, 0x7b, 0xf3, 0x78, 0xac, 0x3f, 0xe3, 0x76, 0x43, 0x86, 0x39, 0xbe, 0x99, 0x7a, 0x3c, 0x18, 0xb7, 0xab, 0x19, 0x99, 0xdc, 0x31, 0x58, 0xcf, 0x17, 0x6a, 0xac, 0xf6, 0x64, 0xdb, 0x27, 0x13, 0x9e, 0xde, 0xf0, 0xd0, 0xde, 0xb1, 0x5a, 0xbd, 0x31, 0x6e, 0x0e, 0xf8, 0x0d, 0xb4, 0xd2, 0x92, 0x1d, 0xef, 0xeb, 0xbc, 0x64, 0x5d, 0x53, 0x62, 0x70, 0x7d, 0x6e, 0x70, 0x93, 0xc7, 0xd4, 0xdd, 0x68, 0xa9, 0xab, 0x8d, 0x1b, 0x62, 0x47, 0x56, 0x0d, 0x5d, 0x34, 0x56, 0xeb, 0x76, 0xf6, 0x87, 0x94, 0x65, 0x9f, 0xe0, 0x65, 0x50, 0xaf, 0x50, 0xe3, 0x4c, 0x46, 0xc9, 0x27, 0x2e,\n\t0xc6, 0x66, 0x63, 0xcf, 0xf8, 0x24, 0x71, 0x66, 0x6e, 0x68, 0x00, 0x2a, 0x2f, 0x50, 0xa5, 0x36, 0xf3, 0x39, 0xf2, 0xb2, 0x13, 0x82, 0x70, 0xe2, 0x04, 0x20, 0x91, 0x66, 0x70, 0xea, 0x14, 0xa9, 0x7c, 0xee, 0x39, 0xb8, 0x0e, 0x11, 0xb8, 0xc6, 0xf7, 0xe3, 0xfc, 0x8d, 0x1e, 0xe4, 0x67, 0x6b, 0x81, 0x27, 0xa7, 0x5e, 0x45, 0xe2, 0x68, 0xbb, 0x72, 0xd0, 0x66, 0x39, 0x4f, 0x63, 0x27, 0x18, 0x06, 0x44, 0x4f, 0x77, 0x47, 0x6b, 0x4d, 0x04, 0xf9, 0xd9, 0x18, 0xbc, 0x0e, 0xb3, 0xfd, 0x6c, 0x70, 0x86, 0xf1, 0x5f, 0xf4, 0x19, 0x7e, 0x36, 0x5c, 0xdf, 0x24, 0xc0, 0x63, 0xb0, 0x61, 0xf0, 0xa3, 0xce, 0x2d, 0x83, 0x51, 0x67, 0xaa, 0x2d, 0x30, 0x70, 0xf5, 0x74, 0x8b, 0xbf, 0xb8, 0x16, 0xfc, 0xd4, 0x69, 0x18, 0xdc, 0xb7, 0xb2, 0xbe, 0x73, 0xf2, 0xbc, 0xc9, 0xce, 0xb6, 0x8b, 0x1e, 0xdb,\n\t0xb3, 0xe5, 0x8e, 0xad, 0xb9, 0xa6, 0x73, 0x6e, 0x5d, 0x13, 0x68, 0x4b, 0xb9, 0xd2, 0x2b, 0xf6, 0x0d, 0xe5, 0x36, 0xc7, 0x85, 0x8f, 0x12, 0x41, 0xca, 0xf7, 0x73, 0x7f, 0xeb, 0xb2, 0xfa, 0xd4, 0x70, 0x7b, 0xc6, 0x62, 0x69, 0x1e, 0x1c, 0xcf, 0x45, 0x7a, 0xb3, 0x1e, 0xfa, 0xa0, 0xc7, 0xa1, 0x08, 0x8e, 0x2d, 0x1b, 0xb2, 0xb9, 0x72, 0xad, 0xc3, 0x53, 0x07, 0x97, 0x2f, 0x3c, 0x7a, 0x4e, 0x31, 0xbb, 0x7c, 0x77, 0x7b, 0xc7, 0x79, 0x93, 0x0b, 0x9d, 0xc6, 0x50, 0x4d, 0xca, 0x1d, 0x59, 0xb9, 0x6e, 0x43, 0x4a, 0x26, 0xab, 0x09, 0x0c, 0xc0, 0x31, 0xd7, 0x9f, 0xfe, 0x33, 0x7d, 0x3b, 0xf5, 0x37, 0x6c, 0xcb, 0xdf, 0x27, 0xb2, 0x2d, 0xb7, 0x52, 0x4e, 0xa2, 0xc8, 0x42, 0x24, 0x71, 0xac, 0x57, 0x88, 0x78, 0x1a, 0x92, 0xfd, 0x69, 0x07, 0x55, 0xd2, 0x6e, 0x3e, 0xe5, 0xa6, 0x73, 0x70,\n\t0xd5, 0xc4, 0x4f, 0x7d, 0x09, 0xaa, 0x71, 0x1d, 0x0a, 0xa2, 0x95, 0x31, 0x87, 0xcc, 0x21, 0x83, 0x4a, 0xaa, 0x68, 0x23, 0xd1, 0x88, 0x50, 0xa0, 0x34, 0x61, 0xb3, 0x0b, 0xda, 0x2c, 0x14, 0x52, 0xde, 0x96, 0xe5, 0x85, 0xc2, 0x58, 0x8b, 0x17, 0x0c, 0x1f, 0x13, 0xa3, 0xd9, 0xb7, 0x37, 0x1d, 0x3b, 0xf6, 0x0c, 0xf8, 0xf1, 0xb3, 0xc7, 0xc0, 0x4f, 0x5b, 0x50, 0xf8, 0x3a, 0x0a, 0x6b, 0x6f, 0x69, 0x29, 0x05, 0xb5, 0xb7, 0x1c, 0x05, 0x27, 0x84, 0x2d, 0xe8, 0xff, 0x88, 0x6f, 0x64, 0x21, 0x6d, 0xfc, 0x26, 0xce, 0x2b, 0xae, 0x45, 0x11, 0x15, 0x52, 0x0f, 0x91, 0xbf, 0xae, 0xd4, 0x43, 0xc9, 0xb3, 0x0b, 0x47, 0x50, 0x9b, 0x8c, 0xa0, 0xde, 0x05, 0x59, 0x53, 0x10, 0xf7, 0xae, 0x94, 0x03, 0x5e, 0x03, 0x02, 0x73, 0x6a, 0xed, 0xd4, 0x82, 0x48, 0xb8, 0x8d, 0x6c, 0x46, 0xbc, 0x20, 0x03,\n\t0x2e, 0xe7, 0x9b, 0x97, 0x65, 0xe2, 0xcb, 0xfb, 0x33, 0x0a, 0xc1, 0x46, 0x15, 0x6e, 0x52, 0x2d, 0xbb, 0xf4, 0x8b, 0xa3, 0xeb, 0x6f, 0xdb, 0x52, 0x38, 0x74, 0xe8, 0x15, 0xf0, 0x8e, 0xcc, 0xab, 0x23, 0x95, 0x06, 0xb3, 0xea, 0x6a, 0xa5, 0x51, 0xa7, 0x22, 0x6f, 0x00, 0xbb, 0xf2, 0xa3, 0x2d, 0x5e, 0x7e, 0xf8, 0xc0, 0xea, 0x4b, 0xbf, 0x71, 0x61, 0x43, 0x6e, 0xea, 0xd8, 0xf8, 0xe4, 0x51, 0x70, 0x8b, 0xb0, 0x75, 0xec, 0x2b, 0x63, 0x46, 0x87, 0x5e, 0x9e, 0xdf, 0x38, 0x39, 0x95, 0xc5, 0x7b, 0xdd, 0x20, 0xec, 0xa1, 0x7a, 0x98, 0x07, 0x21, 0xb7, 0x7b, 0x41, 0xaa, 0x6d, 0x96, 0x00, 0x72, 0x59, 0xb9, 0xca, 0x65, 0x02, 0x28, 0xa4, 0x2f, 0x52, 0x55, 0x50, 0x3f, 0x02, 0x0d, 0xc1, 0x44, 0xa4, 0xaa, 0x26, 0xd8, 0xd4, 0x50, 0xb9, 0x52, 0xd8, 0xd6, 0x32, 0x32, 0x68, 0x8d, 0x24, 0x60,\n\t0xed, 0x9c, 0xff, 0x09, 0xa2, 0xea, 0x81, 0x62, 0x06, 0x72, 0x09, 0x5a, 0x21, 0xc7, 0x75, 0xd1, 0x14, 0xb8, 0x2e, 0x9a, 0xf8, 0x28, 0xc6, 0x86, 0xa1, 0xd6, 0x42, 0x1a, 0x27, 0xbd, 0xa0, 0xa4, 0x20, 0x4e, 0x49, 0x28, 0x22, 0xa1, 0x08, 0x1f, 0x09, 0xf1, 0x41, 0x13, 0x46, 0x11, 0x11, 0x9d, 0xad, 0x67, 0x56, 0x97, 0xcb, 0xe6, 0xcb, 0x70, 0x44, 0x73, 0xaa, 0x26, 0x92, 0x54, 0x60, 0xe1, 0xbe, 0x71, 0xaa, 0x4e, 0x2a, 0xe0, 0xa1, 0xc7, 0x05, 0x3e, 0x3a, 0xdc, 0x6e, 0xbd, 0x2e, 0x1d, 0x5a, 0xb2, 0xb0, 0x8c, 0x45, 0x24, 0x82, 0x9d, 0x81, 0x9d, 0x08, 0xfc, 0x77, 0x45, 0x75, 0xd9, 0xb8, 0x97, 0xed, 0x3a, 0xdd, 0xd4, 0x66, 0xb2, 0x0a, 0xea, 0xec, 0xdf, 0x61, 0x97, 0x1b, 0xe0, 0x9c, 0xae, 0x84, 0x7b, 0xa1, 0x0d, 0x10, 0x45, 0x35, 0xaf, 0x85, 0x44, 0xd8, 0x86, 0xa7, 0x50, 0x3c,\n\t0x02, 0x29, 0x42, 0x26, 0xa7, 0xe5, 0xd8, 0xe6, 0xcf, 0xc8, 0xd1, 0x58, 0xe5, 0xf2, 0x12, 0xf0, 0xad, 0x34, 0xb8, 0x73, 0xe6, 0x4e, 0xa7, 0xef, 0x73, 0x3d, 0xb6, 0x63, 0xbe, 0x55, 0xc8, 0xcf, 0x7d, 0xac, 0x34, 0xb3, 0xf3, 0x3c, 0x3e, 0x67, 0x49, 0xce, 0xf2, 0xa0, 0xb4, 0x24, 0x67, 0x3e, 0x2f, 0xd9, 0xbb, 0x58, 0x53, 0x38, 0x10, 0x45, 0xd8, 0x50, 0x78, 0x4d, 0x2a, 0xe1, 0xdc, 0x9f, 0x55, 0xf6, 0x2f, 0x3c, 0xab, 0x90, 0x05, 0xa9, 0x59, 0x71, 0x60, 0x71, 0xb8, 0x69, 0xc7, 0xdd, 0x9b, 0x5a, 0xd6, 0xd7, 0xa4, 0x8b, 0x12, 0xb4, 0x8b, 0x54, 0x80, 0x25, 0xa9, 0xb4, 0x71, 0x5c, 0xbc, 0x6d, 0x79, 0x47, 0xeb, 0x78, 0x93, 0x7b, 0xdb, 0x8e, 0x7b, 0x1c, 0x20, 0x28, 0xc8, 0x50, 0x0d, 0x0b, 0x72, 0x52, 0x5e, 0x3b, 0xb8, 0xb1, 0xb5, 0xef, 0xa2, 0xf1, 0x0c, 0xab, 0xdf, 0x53, 0xbd,\n\t0x52, 0xaf, 0x61, 0x66, 0xec, 0x72, 0xd5, 0x75, 0x45, 0xfa, 0x97, 0xb5, 0xf9, 0x4d, 0x40, 0x7d, 0xdb, 0x12, 0x47, 0xad, 0x4e, 0xb4, 0x53, 0x50, 0x47, 0xc8, 0xbc, 0xe4, 0x73, 0xdc, 0x2b, 0xf9, 0x1c, 0xb5, 0x50, 0xe3, 0xd3, 0xa0, 0x31, 0x23, 0x0f, 0x3c, 0xf6, 0x39, 0xc2, 0x5f, 0x98, 0xaa, 0x5f, 0x24, 0x9f, 0xa3, 0x15, 0xab, 0x86, 0x0c, 0x40, 0xa0, 0x7d, 0x34, 0xa8, 0xb8, 0x6c, 0x9c, 0x45, 0xbe, 0x5c, 0x58, 0x71, 0x72, 0xa8, 0xa4, 0x3f, 0xce, 0xbe, 0x07, 0x19, 0x6c, 0x83, 0xd1, 0x50, 0x50, 0xb4, 0x80, 0x56, 0xe9, 0x1a, 0xf2, 0xc8, 0xec, 0x74, 0x44, 0xb9, 0x0c, 0x47, 0xea, 0x59, 0xdf, 0xb0, 0xd6, 0x85, 0x12, 0xd9, 0xb6, 0x8c, 0xa3, 0xd6, 0xa4, 0x75, 0x14, 0xd3, 0xf5, 0x4b, 0x9a, 0x7d, 0xae, 0x4c, 0x6f, 0x2c, 0x3f, 0xe2, 0x53, 0x2b, 0xed, 0xa3, 0xa3, 0x76, 0x25, 0x5d,\n\t0xef, 0x74, 0xf7, 0x8e, 0xad, 0x58, 0xc0, 0x5a, 0x57, 0x38, 0xf8, 0x9a, 0x81, 0xa9, 0xa6, 0xf6, 0xa9, 0x6e, 0xa8, 0xb5, 0x25, 0xed, 0x92, 0xad, 0x96, 0x24, 0xd2, 0x54, 0x02, 0xfc, 0x09, 0xeb, 0xb8, 0x45, 0x62, 0x71, 0x71, 0x61, 0x11, 0x50, 0x32, 0x07, 0xaa, 0x81, 0x97, 0xc3, 0x46, 0x99, 0x0c, 0x60, 0xfa, 0x08, 0x12, 0x4a, 0xfe, 0x24, 0x5a, 0xf7, 0xd9, 0x42, 0xc3, 0xa4, 0xb8, 0xd2, 0x72, 0xd1, 0x83, 0x07, 0x88, 0xb6, 0x96, 0x78, 0xd4, 0xe7, 0x31, 0x73, 0x06, 0x5d, 0xa5, 0xb2, 0x1d, 0xa8, 0xc0, 0xc5, 0x55, 0xeb, 0xf7, 0xb3, 0xd0, 0xe1, 0x62, 0xa0, 0x84, 0x0e, 0x37, 0xcb, 0x5f, 0xd3, 0x12, 0x8b, 0x1b, 0x8d, 0x0a, 0x9d, 0x56, 0x2b, 0xbb, 0x5e, 0xa6, 0x41, 0x86, 0x5e, 0xde, 0xde, 0xde, 0x02, 0x75, 0x5b, 0x4f, 0x30, 0x6e, 0xf3, 0xd7, 0xfb, 0xf4, 0x96, 0x64, 0x57, 0x52,\n\t0xae, 0x93, 0xa3, 0xfc, 0x7a, 0x8b, 0x35, 0x27, 0x53, 0x76, 0x2f, 0xe6, 0x8b, 0xeb, 0xda, 0x5a, 0x56, 0x06, 0xa9, 0x0f, 0x5c, 0x56, 0x1d, 0x27, 0x37, 0xf2, 0x0e, 0x90, 0x55, 0x28, 0xd5, 0x3a, 0xf5, 0xf2, 0xc5, 0xb5, 0x2d, 0x5c, 0x34, 0xeb, 0xd5, 0x70, 0xfe, 0x5a, 0xa7, 0x27, 0x1f, 0xb1, 0x02, 0x83, 0x9f, 0x63, 0x55, 0x94, 0xa2, 0x25, 0xed, 0xde, 0x3f, 0x81, 0x2c, 0xc1, 0xe1, 0x10, 0x9e, 0x8b, 0x14, 0x5c, 0xf7, 0x3a, 0xd9, 0x56, 0x42, 0x4b, 0x14, 0x88, 0xc6, 0x62, 0xde, 0x07, 0xb7, 0x3f, 0x42, 0x91, 0x21, 0x07, 0x33, 0xf5, 0xe9, 0x9a, 0x60, 0x40, 0x46, 0xf5, 0x4b, 0xe8, 0x54, 0x93, 0xe5, 0xf0, 0x84, 0x69, 0x14, 0x9e, 0xe0, 0x75, 0x9b, 0x39, 0x31, 0xab, 0x94, 0x91, 0x22, 0x60, 0x2a, 0xe5, 0xfc, 0x3c, 0x25, 0xed, 0x58, 0x12, 0x8c, 0x20, 0x05, 0x97, 0x47, 0xc2, 0xf9,\n\t0x76, 0x54, 0x7b, 0xa9, 0x16, 0xaa, 0xc5, 0x16, 0x6b, 0xc1, 0x6a, 0x91, 0xc9, 0x41, 0x12, 0x55, 0x70, 0x20, 0x0d, 0xcd, 0x75, 0x2d, 0xed, 0x5d, 0xcf, 0x36, 0x74, 0x5c, 0x7b, 0x59, 0x6e, 0x55, 0x57, 0x98, 0x6f, 0x1d, 0xcd, 0xad, 0x6e, 0x56, 0xd7, 0xc6, 0xa6, 0xed, 0x4a, 0xb9, 0xce, 0xa5, 0x75, 0xe9, 0x8d, 0x9c, 0x5a, 0xbf, 0x65, 0x6c, 0xa5, 0x4b, 0x2e, 0xd7, 0x50, 0x7f, 0x31, 0xc6, 0xfb, 0xb2, 0xfe, 0xf4, 0x40, 0xa6, 0xb7, 0x1f, 0x9c, 0xce, 0xde, 0x3c, 0x7d, 0xe2, 0x5e, 0x7f, 0x71, 0x55, 0x73, 0xed, 0xd2, 0xf6, 0x70, 0x6b, 0xaa, 0xd7, 0xd1, 0x9e, 0xd4, 0x59, 0x15, 0x7a, 0x46, 0xc1, 0xc8, 0x7c, 0xae, 0x34, 0x9b, 0x2e, 0x24, 0xb5, 0x56, 0x39, 0xf6, 0x55, 0x5d, 0x0f, 0xbe, 0x89, 0x7c, 0x55, 0xc0, 0x5c, 0x54, 0xa9, 0xff, 0x7f, 0xee, 0xab, 0x12, 0xbd, 0x88, 0xff, 0x48,\n\t0x1b, 0xc5, 0xe4, 0x67, 0x21, 0x6b, 0x6c, 0x9b, 0xe3, 0xe0, 0x2a, 0x79, 0xb8, 0xc2, 0xb5, 0x7e, 0xd1, 0xc3, 0x05, 0xe6, 0x9a, 0x10, 0x67, 0x57, 0x4b, 0x99, 0xeb, 0xe1, 0x0a, 0x47, 0x6a, 0xbd, 0xcb, 0xdb, 0xea, 0x86, 0xb3, 0xae, 0x40, 0x6d, 0xb4, 0x3e, 0xd8, 0x34, 0x14, 0x35, 0x67, 0x72, 0x59, 0x4b, 0x54, 0xc9, 0x6a, 0x2c, 0x8e, 0x90, 0x33, 0x11, 0xaf, 0xcd, 0x36, 0x37, 0xd7, 0xa6, 0x63, 0x35, 0x8e, 0xa0, 0xdd, 0xa8, 0x54, 0x69, 0x15, 0xcc, 0x94, 0x3b, 0x68, 0x8d, 0x64, 0x5c, 0xee, 0x76, 0xce, 0xd0, 0x9a, 0x8a, 0x34, 0xd7, 0x98, 0xe5, 0x26, 0xbf, 0x23, 0xab, 0xd1, 0xb1, 0xba, 0x90, 0xdb, 0xe5, 0x9d, 0xf0, 0x38, 0xac, 0x6e, 0x95, 0x56, 0x25, 0xd7, 0x62, 0x7e, 0xcc, 0x90, 0x6f, 0x81, 0x2c, 0x73, 0x07, 0x61, 0x47, 0xb1, 0xff, 0x6a, 0x15, 0xb2, 0xf9, 0x0f, 0xa2, 0x30,\n\t0x6f, 0xe4, 0x2b, 0x25, 0xd6, 0x8b, 0x2e, 0xa0, 0x75, 0x88, 0xa6, 0x30, 0x28, 0x91, 0x80, 0x0b, 0x9b, 0xc5, 0x72, 0x49, 0x81, 0x59, 0xfa, 0x50, 0x1e, 0x0b, 0x10, 0xb9, 0x8c, 0x39, 0x03, 0xb2, 0x1d, 0xc6, 0x68, 0x57, 0xda, 0xe8, 0x35, 0xd0, 0x40, 0x6b, 0x0c, 0x3b, 0x8a, 0xc5, 0xc3, 0x1d, 0xf4, 0x25, 0x7f, 0x0c, 0xb4, 0xa7, 0x5c, 0x0c, 0x33, 0xac, 0x52, 0xb8, 0xa3, 0x7f, 0x9c, 0x7c, 0xfe, 0x79, 0x64, 0x4b, 0x27, 0xdf, 0x25, 0x2d, 0x50, 0xe6, 0x35, 0xa3, 0x9a, 0x07, 0x26, 0x0c, 0x82, 0x81, 0x71, 0x4b, 0x66, 0x65, 0xa6, 0x8f, 0xe3, 0xa4, 0x10, 0x51, 0xfc, 0x35, 0x13, 0xe6, 0x00, 0x94, 0x78, 0xa5, 0x18, 0xc1, 0xdc, 0x5c, 0xe5, 0x9d, 0x25, 0x2d, 0x87, 0xdd, 0xbd, 0xe9, 0x58, 0x67, 0xc2, 0x7a, 0xa8, 0x06, 0xd9, 0xec, 0xa1, 0x34, 0xbc, 0xf8, 0x3f, 0x9d, 0x3e, 0x4f, 0x76,\n\t0x00, 0x5b, 0xc7, 0x63, 0x29, 0x87, 0x19, 0x9c, 0x2f, 0xd2, 0xa4, 0x18, 0x75, 0x33, 0xc8, 0xca, 0xae, 0x21, 0x58, 0xc2, 0x8d, 0x50, 0xf8, 0xb4, 0x62, 0xe4, 0x27, 0x50, 0x20, 0x40, 0x4c, 0x62, 0x52, 0x0e, 0x18, 0x14, 0xff, 0xc4, 0x90, 0x28, 0xa0, 0x18, 0x17, 0x8d, 0x9a, 0xa4, 0xe0, 0x21, 0x74, 0xbb, 0x9c, 0x0e, 0x54, 0x70, 0xd7, 0x6c, 0xe2, 0x8c, 0x6a, 0x25, 0xb2, 0x31, 0xa2, 0x48, 0x72, 0xae, 0x12, 0x9d, 0x81, 0x66, 0x84, 0x83, 0x5d, 0xcc, 0x49, 0x53, 0xf1, 0xd5, 0x92, 0xcb, 0x2f, 0x98, 0xd5, 0xd9, 0x7c, 0xe7, 0x17, 0x0f, 0xc3, 0xb9, 0x28, 0x32, 0x6f, 0x60, 0x8f, 0x9f, 0xcf, 0xaa, 0xcb, 0x04, 0x91, 0xff, 0x4f, 0xb8, 0xeb, 0x37, 0xbf, 0x99, 0xfc, 0xfa, 0xd7, 0x45, 0x7d, 0x77, 0x98, 0x3a, 0x06, 0x5a, 0xe1, 0x5a, 0xb0, 0x28, 0xb7, 0x4a, 0x0e, 0xca, 0xf0, 0x18, 0x88,\n\t0x1a, 0x60, 0x87, 0x23, 0x39, 0x1c, 0x0a, 0xe0, 0x6c, 0x13, 0x4e, 0xc4, 0xc6, 0x2b, 0xcb, 0xe2, 0xc3, 0x87, 0x1c, 0xee, 0x3a, 0xa3, 0x27, 0xcc, 0xf1, 0x99, 0x00, 0xcb, 0xdc, 0x21, 0x9c, 0xf0, 0xfa, 0x62, 0x7a, 0x8b, 0x5e, 0x61, 0x8b, 0x35, 0xf1, 0xe2, 0xbb, 0x17, 0x53, 0x37, 0x13, 0xaf, 0x63, 0x5f, 0x26, 0x57, 0x34, 0x94, 0x42, 0x94, 0xe1, 0xcc, 0x56, 0x42, 0x63, 0x5f, 0x3f, 0x78, 0x10, 0x39, 0x26, 0x51, 0x2d, 0x34, 0x38, 0x3f, 0x39, 0x78, 0xaf, 0x1a, 0xf9, 0x81, 0x18, 0x80, 0xdd, 0x4c, 0x14, 0xb1, 0xbe, 0x94, 0x5f, 0x31, 0x09, 0x86, 0xab, 0x42, 0x96, 0xab, 0x46, 0x0c, 0x72, 0xcd, 0x57, 0x37, 0xc3, 0xff, 0xe8, 0xdd, 0x3f, 0xff, 0xf9, 0xc2, 0x37, 0x71, 0x1c, 0xfc, 0xe9, 0xff, 0x22, 0x7f, 0x0e, 0x5a, 0xe1, 0x5c, 0x3b, 0x88, 0x30, 0xd1, 0x80, 0x30, 0x6a, 0xb2, 0x50,\n\t0x1f, 0xb7, 0x01, 0x1a, 0x78, 0xa0, 0x1a, 0x42, 0xab, 0x18, 0x92, 0xa0, 0xa0, 0x26, 0x2f, 0x53, 0x40, 0x0d, 0x14, 0x05, 0xc5, 0x43, 0x0e, 0x40, 0x01, 0x1a, 0xae, 0x01, 0x0a, 0xf2, 0xc2, 0x86, 0x41, 0x38, 0xe8, 0x68, 0xc4, 0xe5, 0xac, 0x4f, 0x47, 0x1a, 0xa2, 0x0d, 0x7e, 0x9f, 0x33, 0xec, 0x0a, 0x1b, 0xa3, 0x71, 0x25, 0x76, 0x41, 0x49, 0xb5, 0x3c, 0x52, 0x62, 0xd9, 0xdf, 0x1c, 0x22, 0xfa, 0x56, 0x28, 0x5b, 0x57, 0x97, 0x3b, 0x9d, 0xbd, 0x3e, 0x20, 0xea, 0xd2, 0xda, 0xd5, 0x71, 0xa3, 0x45, 0xa5, 0xae, 0xed, 0x08, 0xe6, 0xfc, 0x06, 0x60, 0xf4, 0x25, 0xdd, 0x81, 0xc0, 0xe1, 0xd7, 0x4c, 0x2e, 0x85, 0xd6, 0x65, 0xb0, 0xda, 0xec, 0x77, 0xb0, 0xa2, 0x5b, 0x96, 0x0d, 0x66, 0x74, 0x56, 0x1f, 0xf5, 0xbf, 0x2b, 0xdb, 0xd8, 0x00, 0xe7, 0xd1, 0xca, 0x75, 0xc6, 0xb0, 0xd9, 0x5f,\n\t0x63, 0x32, 0x45, 0xbd, 0x26, 0x03, 0x78, 0x6b, 0xe6, 0x76, 0xb3, 0x57, 0xa3, 0xb7, 0xe9, 0x59, 0x2b, 0xf9, 0xb5, 0xd9, 0x2b, 0x5a, 0x5a, 0x47, 0xd9, 0x20, 0x5c, 0x47, 0x57, 0xd1, 0x2e, 0xad, 0x63, 0x19, 0x59, 0x01, 0x52, 0x85, 0xcf, 0xb3, 0x88, 0xb2, 0xc1, 0x99, 0xdf, 0xce, 0x5e, 0x44, 0x40, 0x74, 0x91, 0xdf, 0x07, 0x8d, 0xb2, 0xab, 0x08, 0x1b, 0x91, 0x28, 0xd6, 0x28, 0xa5, 0x78, 0xe5, 0x2a, 0xc7, 0x17, 0xb1, 0x16, 0x5b, 0x83, 0x30, 0x5c, 0xa4, 0x8d, 0xb0, 0xb1, 0x5c, 0x34, 0x24, 0xe5, 0xb9, 0xcd, 0xc1, 0xc9, 0x84, 0xc7, 0x15, 0x1e, 0x1c, 0xd0, 0xc8, 0x86, 0x9a, 0xe3, 0xd6, 0x1a, 0x87, 0x8a, 0x31, 0x2a, 0x14, 0x9c, 0xce, 0xce, 0xed, 0x3a, 0x44, 0x7d, 0x72, 0x39, 0xdf, 0x56, 0xe7, 0x51, 0xa9, 0x1b, 0x59, 0x25, 0xe3, 0xf3, 0x05, 0xc9, 0xf7, 0x67, 0x2e, 0x2c, 0xe9,\n\t0xa8, 0xe0, 0x7a, 0x78, 0x5e, 0x4b, 0x35, 0x40, 0x26, 0x87, 0xaa, 0xc3, 0x86, 0xcf, 0x8c, 0x0c, 0x06, 0xd7, 0x0b, 0x2f, 0x1f, 0xa4, 0xc9, 0x1d, 0xa4, 0x52, 0x98, 0x16, 0xfd, 0xda, 0x6f, 0x53, 0x59, 0xc8, 0x17, 0x32, 0xc4, 0x2b, 0x45, 0x1d, 0x24, 0x30, 0x44, 0x12, 0x1e, 0x33, 0x33, 0x3c, 0x67, 0x25, 0x03, 0xa3, 0x1f, 0x07, 0xaf, 0x93, 0x6b, 0x45, 0x40, 0x52, 0x54, 0xe3, 0x18, 0x52, 0x6c, 0x39, 0x0e, 0xe2, 0x11, 0xbf, 0x30, 0x25, 0x9e, 0x30, 0xcf, 0x9d, 0xdb, 0xaa, 0xef, 0xdc, 0xc6, 0x94, 0x78, 0xc1, 0xe7, 0x79, 0xe7, 0xe7, 0x79, 0x1d, 0x96, 0x33, 0x79, 0x2e, 0xc0, 0x05, 0x90, 0xa5, 0x16, 0xc9, 0x99, 0x9c, 0x98, 0x2b, 0x28, 0x95, 0x90, 0x3d, 0xd3, 0xe7, 0x2d, 0x95, 0x01, 0xa9, 0xf6, 0x7d, 0xff, 0xc8, 0xd9, 0x91, 0x4c, 0xb7, 0x1b, 0x1c, 0x13, 0xf5, 0x2b, 0x56, 0x5b,\n\t0xd2, 0x43, 0x59, 0x57, 0xc2, 0x61, 0xc0, 0xfe, 0x6f, 0x43, 0x5f, 0xd9, 0xb9, 0x87, 0x7d, 0xe0, 0x53, 0xae, 0x50, 0x26, 0x56, 0x1f, 0xdf, 0xb4, 0x16, 0x79, 0xc1, 0x0b, 0x5e, 0x95, 0xba, 0x95, 0x55, 0xc9, 0x56, 0x80, 0xe2, 0x78, 0x32, 0x81, 0x9c, 0x94, 0xe9, 0x1a, 0x8b, 0x49, 0xb8, 0x5a, 0x14, 0xb0, 0x10, 0x1d, 0xfd, 0x3d, 0xf6, 0x49, 0xf2, 0xc8, 0x17, 0xee, 0x83, 0x84, 0x5b, 0x49, 0x61, 0x3b, 0x0e, 0x89, 0xa1, 0x2b, 0x64, 0x40, 0x32, 0xff, 0x95, 0xbd, 0x93, 0x78, 0xad, 0x78, 0x82, 0xc7, 0x0e, 0xc9, 0x00, 0x2b, 0x39, 0x24, 0x73, 0x9f, 0xe5, 0x8e, 0x3c, 0xec, 0x68, 0x8e, 0xcd, 0xeb, 0x8b, 0x5c, 0xf4, 0xa6, 0x23, 0x78, 0x56, 0x57, 0x24, 0x01, 0x4e, 0x3f, 0x41, 0xbe, 0x2d, 0xc5, 0x33, 0xdc, 0x55, 0x54, 0xa1, 0x58, 0x06, 0x07, 0x2e, 0x63, 0x2d, 0xae, 0xb9, 0xb3, 0x52,\n\t0x9e, 0x1a, 0x92, 0x01, 0x4a, 0x44, 0x76, 0xc1, 0x01, 0x08, 0x64, 0x69, 0xb1, 0xcf, 0x7a, 0xcb, 0xb6, 0x72, 0x8e, 0xf9, 0xa7, 0xbe, 0xe5, 0x53, 0x5f, 0x80, 0x63, 0x18, 0xfc, 0xd1, 0x48, 0xc0, 0x3c, 0x3b, 0x86, 0xa1, 0xbc, 0x70, 0x67, 0x2c, 0xac, 0x18, 0xc3, 0x90, 0x15, 0xd9, 0x4c, 0xc4, 0x9d, 0xb3, 0x96, 0x56, 0x92, 0x36, 0xe0, 0x95, 0x1c, 0x75, 0x28, 0xca, 0x31, 0x0c, 0xc8, 0xa1, 0x8c, 0x02, 0x17, 0xee, 0xab, 0x5e, 0x45, 0xc1, 0x56, 0x8a, 0xf3, 0x78, 0x9b, 0x7c, 0x1a, 0xcf, 0x4b, 0xb6, 0x58, 0x67, 0x01, 0xa5, 0x32, 0x6c, 0x04, 0x76, 0x88, 0xac, 0x2d, 0xd7, 0xd5, 0x9d, 0x1c, 0xaa, 0xf6, 0x8d, 0x58, 0x82, 0x3c, 0x37, 0x5f, 0x79, 0x6b, 0x71, 0x87, 0x79, 0xcf, 0xac, 0x70, 0xfd, 0xb4, 0x3d, 0xe1, 0xca, 0x0e, 0xa5, 0x2d, 0xe5, 0x00, 0x0b, 0xa5, 0x14, 0x80, 0xd1, 0x67,\n\t0x30, 0x28, 0x54, 0x06, 0x9a, 0xfc, 0x50, 0xad, 0xf2, 0x16, 0x86, 0x93, 0x20, 0x5d, 0x0e, 0xb1, 0x08, 0x4a, 0xbd, 0x7f, 0x61, 0x85, 0x4c, 0xc5, 0x96, 0x79, 0x07, 0xe9, 0x81, 0xfc, 0x00, 0xc7, 0xcf, 0xb2, 0x32, 0x1c, 0xd3, 0x8a, 0xdd, 0xbe, 0xe3, 0xa2, 0x0b, 0xb2, 0xc4, 0x9f, 0x59, 0x5b, 0x55, 0x94, 0x3c, 0x65, 0x31, 0xb9, 0x81, 0x14, 0xbc, 0x8f, 0xc0, 0x61, 0x48, 0x4f, 0x8f, 0xc1, 0xa4, 0x7a, 0x87, 0xdc, 0xd3, 0xc3, 0xea, 0xd5, 0xbf, 0x27, 0x49, 0xe6, 0x8e, 0x99, 0xbf, 0xaa, 0x34, 0xc0, 0xc9, 0x7a, 0xb4, 0x1f, 0x92, 0x4a, 0x85, 0x56, 0xf8, 0x1f, 0x96, 0xd7, 0xbd, 0x8f, 0x73, 0xa7, 0xd2, 0x50, 0x4e, 0x6e, 0x84, 0x3a, 0x03, 0x0d, 0x39, 0x90, 0x17, 0x45, 0xad, 0x41, 0x76, 0x80, 0x21, 0x1f, 0x50, 0x12, 0x0f, 0x49, 0xc3, 0x63, 0x89, 0x83, 0x3b, 0x2a, 0xbe, 0x5b, 0xad,\n\t0x06, 0xfe, 0x4d, 0x58, 0xcd, 0x1a, 0xaf, 0xd6, 0xcb, 0xa8, 0x19, 0x35, 0x14, 0x96, 0x69, 0x82, 0xe6, 0x51, 0x35, 0x43, 0x0e, 0x2e, 0x5b, 0x41, 0xb4, 0xd2, 0xca, 0x0b, 0x73, 0xf2, 0xe1, 0x9f, 0xd4, 0x9c, 0xb7, 0x5b, 0x03, 0x14, 0xad, 0x0d, 0x8d, 0x6d, 0x8a, 0x03, 0x28, 0x24, 0x42, 0x8c, 0x61, 0xe8, 0x0e, 0x87, 0xbb, 0xd7, 0xd1, 0x17, 0x5e, 0x77, 0xdd, 0x60, 0x47, 0x57, 0x57, 0xc7, 0x2f, 0x51, 0x7c, 0x44, 0xdb, 0x64, 0x6f, 0x38, 0x2c, 0x7e, 0x86, 0xc4, 0xdc, 0xfe, 0x14, 0xf9, 0x07, 0x4a, 0x2f, 0xdb, 0x45, 0xc8, 0xa0, 0x34, 0x1f, 0x41, 0x32, 0x0c, 0xa1, 0x24, 0x64, 0x4a, 0xd9, 0x6a, 0xf1, 0xdc, 0x89, 0x3d, 0x94, 0x57, 0x87, 0x20, 0x46, 0xc2, 0x36, 0x16, 0x4e, 0x90, 0x89, 0x35, 0x89, 0x26, 0x22, 0x31, 0x24, 0x3d, 0x20, 0xfa, 0xe7, 0x38, 0x51, 0x6d, 0xad, 0xf2, 0xde,\n\t0xe5, 0x32, 0xe0, 0xad, 0x05, 0x2b, 0x56, 0x2c, 0xb8, 0x1c, 0xff, 0xd3, 0x29, 0xc6, 0x19, 0x77, 0xc2, 0x3f, 0x16, 0x25, 0x93, 0x8b, 0xe0, 0x1f, 0xd4, 0x9f, 0xc8, 0xd1, 0x91, 0x91, 0x65, 0x24, 0xb9, 0x6c, 0x64, 0x64, 0x94, 0x04, 0x8f, 0x83, 0x70, 0xcf, 0x86, 0xd6, 0xb6, 0x0d, 0xbd, 0x61, 0xe4, 0xad, 0x0b, 0xf7, 0x6e, 0x68, 0x6b, 0xdd, 0xd0, 0x13, 0x06, 0xaf, 0xe1, 0xf5, 0x4b, 0x42, 0x1e, 0xfc, 0x34, 0x9c, 0xcf, 0x3e, 0xa2, 0xbf, 0xd8, 0xd3, 0x07, 0x80, 0x02, 0xe5, 0xde, 0xca, 0x03, 0x38, 0x90, 0x0e, 0x5e, 0x87, 0x42, 0x8f, 0x0c, 0x81, 0xd2, 0x13, 0x0c, 0xc5, 0xac, 0x25, 0xa4, 0x42, 0x03, 0x93, 0x43, 0xa2, 0xb5, 0x57, 0xaa, 0x32, 0x09, 0xf5, 0x90, 0x24, 0xd4, 0xb2, 0xfd, 0xa6, 0x64, 0x80, 0xc7, 0x7a, 0xb6, 0xec, 0x0c, 0x67, 0xea, 0xa7, 0x2a, 0xdc, 0xc8, 0xa8, 0x4b,\n\t0x97, 0x75, 0xaf, 0x2f, 0xa8, 0x58, 0x95, 0xd9, 0xe9, 0xb7, 0xf8, 0x43, 0xa1, 0x42, 0xb1, 0x10, 0x72, 0xe6, 0x17, 0x65, 0xc3, 0x41, 0x93, 0x43, 0xef, 0x54, 0x29, 0xcd, 0x8c, 0xca, 0x91, 0xb2, 0xc6, 0x5a, 0x42, 0x2c, 0xcf, 0x18, 0x74, 0x1a, 0xb3, 0x23, 0xe8, 0x8c, 0x05, 0x42, 0x0d, 0xc5, 0x86, 0x90, 0x3d, 0x33, 0x58, 0x9f, 0x9f, 0x70, 0x33, 0x29, 0x83, 0x4a, 0xad, 0x72, 0x58, 0xcd, 0x56, 0xce, 0xc4, 0x67, 0x63, 0x08, 0x95, 0x43, 0x69, 0xe1, 0x03, 0x72, 0x8d, 0xa9, 0x56, 0xad, 0xf2, 0xd4, 0xb5, 0xfb, 0xda, 0xf3, 0x4a, 0xb5, 0x56, 0xaf, 0xe1, 0x4d, 0x16, 0xa8, 0xb4, 0x07, 0x9a, 0x52, 0x7c, 0x53, 0xd2, 0x11, 0x72, 0x23, 0x5a, 0xf4, 0x24, 0x94, 0x75, 0xcf, 0x97, 0xed, 0x85, 0x5a, 0x37, 0xe4, 0x9f, 0x4e, 0xc8, 0x36, 0x15, 0x58, 0xfb, 0x42, 0x71, 0x5d, 0x00, 0xe5, 0x4d,\n\t0xcd, 0x09, 0x1e, 0x89, 0x46, 0x24, 0x68, 0xa9, 0x79, 0x60, 0xa6, 0xe7, 0x62, 0xdd, 0xbf, 0x61, 0x4e, 0x0e, 0x64, 0x5d, 0x69, 0x87, 0x5e, 0x64, 0xa5, 0x01, 0xde, 0x5c, 0xdb, 0x2f, 0x7e, 0x67, 0x51, 0x0d, 0xe0, 0x00, 0x4f, 0x3d, 0x52, 0xa2, 0x02, 0x4a, 0x26, 0x1d, 0x25, 0x55, 0xc9, 0x05, 0x12, 0x4d, 0x60, 0x52, 0x51, 0xd4, 0x9a, 0x1f, 0xf2, 0xf6, 0xeb, 0x64, 0x0d, 0x44, 0x8a, 0xb8, 0xbc, 0xa8, 0xf3, 0x42, 0xc5, 0xd0, 0x04, 0x48, 0x39, 0xe2, 0xf1, 0x25, 0x0c, 0xe1, 0x88, 0x58, 0x28, 0x9c, 0x94, 0x03, 0xb9, 0x68, 0x15, 0x81, 0xff, 0xad, 0x2b, 0xd7, 0x0b, 0x9f, 0x1c, 0x52, 0x2a, 0x48, 0xb8, 0x4c, 0x72, 0x9c, 0xcb, 0xf9, 0x19, 0x77, 0x02, 0x54, 0x15, 0x82, 0xc0, 0x77, 0x8f, 0x17, 0x59, 0xd1, 0xdb, 0x1a, 0x60, 0xd9, 0x08, 0x17, 0x8c, 0x86, 0x54, 0xa8, 0xbe, 0xd5, 0x3c,\n\t0x02, 0x83, 0xac, 0x02, 0xa9, 0xde, 0x0e, 0xf2, 0xcd, 0x38, 0xe5, 0x50, 0xc2, 0xc6, 0x05, 0xd7, 0xb1, 0xa1, 0x96, 0x98, 0x35, 0xe6, 0x50, 0xd3, 0xa8, 0xe0, 0xb1, 0xd6, 0x6a, 0xd6, 0x9b, 0x5a, 0xfa, 0xea, 0xd4, 0xfa, 0xa5, 0x2e, 0xc6, 0xde, 0x7f, 0xcd, 0x35, 0x66, 0xce, 0xcc, 0xaa, 0x68, 0xf5, 0x8d, 0x3e, 0x28, 0x58, 0x28, 0xa1, 0x60, 0xa1, 0x92, 0xb9, 0x03, 0x3c, 0xbd, 0xa8, 0x07, 0x58, 0xf4, 0xba, 0x06, 0xc3, 0x55, 0xd6, 0x3b, 0xa6, 0x84, 0x3f, 0x9b, 0xed, 0x3a, 0xa9, 0x56, 0x03, 0x3c, 0xfb, 0x9b, 0x20, 0x3f, 0x53, 0x10, 0x01, 0xa2, 0xa3, 0xd8, 0xa6, 0x80, 0xab, 0xa1, 0xc7, 0xc6, 0xac, 0xea, 0xda, 0xe2, 0x88, 0x1c, 0xca, 0xc7, 0x51, 0x85, 0xf1, 0x49, 0x6c, 0xe0, 0x10, 0xe3, 0xbb, 0xa8, 0xe1, 0x80, 0x9f, 0xf7, 0x61, 0x4b, 0x67, 0xb9, 0xb4, 0x78, 0x40, 0xdc, 0x94,\n\t0xed, 0x48, 0x4c, 0x2d, 0x87, 0x53, 0x97, 0xb5, 0x15, 0x2c, 0xb4, 0x7e, 0xe9, 0x69, 0xac, 0x2f, 0xfc, 0x5b, 0x1b, 0x0a, 0xb9, 0x91, 0x68, 0x7b, 0x2e, 0x77, 0xe8, 0xe9, 0xc3, 0x6d, 0xf4, 0x1e, 0x3f, 0x54, 0x1b, 0x2c, 0x43, 0x6f, 0xdb, 0x83, 0xde, 0x30, 0x52, 0x24, 0xfc, 0x6b, 0xbf, 0x07, 0xff, 0x87, 0xcf, 0x54, 0x86, 0x3a, 0x4a, 0x8e, 0x42, 0x9a, 0x98, 0x44, 0x91, 0x26, 0x61, 0x8d, 0x02, 0x76, 0xd1, 0xcd, 0xe2, 0x0a, 0x9f, 0xe5, 0x7c, 0x2e, 0x72, 0x72, 0xa8, 0x94, 0x33, 0x41, 0x41, 0x19, 0x09, 0x10, 0x08, 0xee, 0xde, 0x66, 0x31, 0xa0, 0x2c, 0xe0, 0x24, 0x48, 0xca, 0xcb, 0xa5, 0xea, 0xf2, 0x05, 0x19, 0x8e, 0xd6, 0x80, 0xb3, 0xaa, 0x93, 0xec, 0x89, 0x88, 0x36, 0x40, 0x35, 0xd0, 0x02, 0x49, 0xa8, 0x3f, 0x22, 0x2a, 0x8a, 0xa0, 0xbb, 0x61, 0x5d, 0x6f, 0xa4, 0xbb, 0x29,\n\t0xc2, 0x77, 0xda, 0x4c, 0x2f, 0x86, 0x1a, 0x06, 0x0b, 0x85, 0xa1, 0xc6, 0xd0, 0x8b, 0x26, 0x5b, 0x67, 0x20, 0xd4, 0xd8, 0x1b, 0xe9, 0x5d, 0x47, 0x1d, 0x45, 0x69, 0x79, 0x5d, 0x9b, 0x6d, 0xb2, 0x1e, 0xa3, 0xf5, 0x56, 0x59, 0x5f, 0x43, 0x7b, 0x4f, 0x4f, 0x7b, 0x43, 0x9f, 0xec, 0x56, 0xab, 0xb1, 0x47, 0x66, 0xdb, 0xdc, 0x55, 0xbf, 0xb4, 0xd5, 0x8f, 0xfb, 0xbe, 0x92, 0xba, 0x9e, 0xf4, 0x62, 0xdd, 0x4b, 0xcc, 0x87, 0x00, 0x62, 0x3d, 0xcf, 0x7f, 0x28, 0x1f, 0xa2, 0xa5, 0xb6, 0xfe, 0x4a, 0x6f, 0xf3, 0xb2, 0x5c, 0x6e, 0x69, 0xb3, 0xf7, 0xca, 0x7a, 0x9a, 0x84, 0xf4, 0xaa, 0x5e, 0xf8, 0x41, 0x7a, 0x49, 0x13, 0xcf, 0x37, 0x2d, 0x49, 0xc3, 0xbf, 0x7f, 0x98, 0xc1, 0x79, 0x79, 0x5d, 0xb0, 0x2d, 0x0f, 0xe4, 0x73, 0x75, 0x28, 0xba, 0x5e, 0x89, 0xbd, 0xe4, 0xa5, 0x9a, 0xe2, 0x93,\n\t0xf3, 0xe8, 0xfb, 0x95, 0xab, 0xdb, 0xe6, 0xd1, 0xed, 0xcf, 0xf6, 0xec, 0xd9, 0x1e, 0x43, 0xe1, 0x48, 0xd1, 0x9a, 0x48, 0x14, 0x3b, 0xd7, 0x67, 0x43, 0xd9, 0xa1, 0xea, 0xe2, 0x61, 0x5c, 0x5c, 0xdc, 0x82, 0x6b, 0x8b, 0x5b, 0xe6, 0x96, 0x16, 0x37, 0xdb, 0xa3, 0xae, 0x5c, 0x57, 0x58, 0x97, 0x18, 0x9a, 0x6a, 0x5c, 0xb9, 0x45, 0x09, 0x80, 0x7a, 0x0b, 0x67, 0x24, 0x65, 0x8a, 0x5a, 0xde, 0x9a, 0xe0, 0x4d, 0x4a, 0xbd, 0x49, 0xad, 0x85, 0xdc, 0xce, 0x48, 0x32, 0xb7, 0x28, 0xe4, 0xc1, 0xe6, 0xc1, 0xd0, 0x82, 0x4b, 0x46, 0x93, 0xbb, 0x76, 0x84, 0x27, 0xf2, 0x85, 0x4e, 0x8b, 0x3e, 0x93, 0xaa, 0x5f, 0xe6, 0xed, 0xc8, 0xd9, 0xb3, 0x8b, 0x1b, 0x42, 0x71, 0x33, 0x43, 0x21, 0x4e, 0x0a, 0x08, 0x39, 0xe4, 0xa3, 0x6e, 0xac, 0xdf, 0x95, 0xb1, 0x45, 0x70, 0x34, 0x0f, 0x06, 0x18, 0x11,\n\t0x03, 0x79, 0x58, 0xc2, 0x20, 0x49, 0xd1, 0x38, 0x1f, 0x04, 0x92, 0x52, 0x94, 0x10, 0xd2, 0x8e, 0xf3, 0xbd, 0xdc, 0xdf, 0xdf, 0xff, 0xda, 0x6e, 0xbd, 0x19, 0x8a, 0x72, 0x5a, 0x46, 0xcd, 0x4e, 0xd0, 0x9c, 0x0e, 0xf1, 0x50, 0x52, 0xa9, 0x53, 0x7f, 0xe2, 0xc8, 0x3a, 0xb2, 0xd9, 0x4f, 0xd4, 0x12, 0xce, 0x42, 0x9c, 0x7c, 0x8d, 0x6c, 0x86, 0xed, 0xf0, 0xc8, 0x33, 0x20, 0x16, 0xb3, 0x2e, 0xc9, 0x15, 0x95, 0xc8, 0xba, 0x52, 0xb2, 0x3c, 0x18, 0xe6, 0x4c, 0xa8, 0x26, 0x75, 0x95, 0x54, 0x21, 0xd5, 0xa4, 0xe6, 0x02, 0x22, 0xba, 0x4a, 0xa6, 0x52, 0x92, 0x9a, 0x6c, 0x76, 0xc0, 0x83, 0xde, 0x1c, 0x62, 0x85, 0x5f, 0x2b, 0x95, 0xbf, 0xff, 0x23, 0xb8, 0xde, 0xf8, 0xce, 0xfb, 0x46, 0x87, 0xce, 0xa4, 0x50, 0xb0, 0x34, 0xf9, 0x0b, 0x91, 0xfe, 0x3a, 0x9a, 0x95, 0x2e, 0x35, 0xc8, 0x6c,\n\t0x6b, 0xf2, 0x99, 0x84, 0x1f, 0xdf, 0xe8, 0xf3, 0x31, 0x4a, 0x16, 0x9e, 0xeb, 0x38, 0x95, 0x25, 0x57, 0xc3, 0x3d, 0xa7, 0x24, 0xd2, 0xc8, 0x0e, 0x98, 0xc0, 0x08, 0xe9, 0x04, 0x08, 0x62, 0xdb, 0xa6, 0x77, 0x9e, 0x9a, 0xd4, 0x93, 0x92, 0xe9, 0x52, 0xac, 0x4c, 0x0d, 0x0f, 0xb7, 0x4a, 0x05, 0x08, 0x55, 0x5a, 0x95, 0x46, 0x88, 0xbf, 0x01, 0x3f, 0x3a, 0x47, 0x72, 0x86, 0x50, 0x02, 0xa5, 0xaa, 0xca, 0x0e, 0x28, 0x13, 0x4b, 0x52, 0x5b, 0xe6, 0x96, 0x1e, 0x0a, 0x54, 0xc6, 0x23, 0x93, 0x53, 0xe0, 0xbe, 0x58, 0x1d, 0xcb, 0x71, 0x2e, 0xcd, 0x46, 0xad, 0x2f, 0x52, 0xeb, 0xec, 0x6e, 0x47, 0xb6, 0x3e, 0x2f, 0x05, 0xd9, 0xa1, 0xc5, 0x92, 0x27, 0x65, 0xd4, 0xc7, 0x70, 0x6c, 0xef, 0x81, 0xa3, 0x2a, 0xc5, 0x3b, 0xd4, 0x69, 0xa7, 0x4d, 0xc7, 0x45, 0x92, 0xe9, 0x62, 0x48, 0xdf, 0x9f,\n\t0xf5, 0xe6, 0xa3, 0x56, 0x03, 0x8f, 0x4d, 0x7b, 0xd6, 0x1a, 0x53, 0x69, 0x98, 0x7a, 0xb7, 0x42, 0xf8, 0x31, 0x96, 0x75, 0xff, 0x46, 0xbe, 0x0d, 0xbe, 0x05, 0xc7, 0x18, 0x22, 0xa6, 0x8a, 0x2a, 0x3f, 0xa0, 0x51, 0x36, 0x0d, 0x0e, 0xbb, 0x53, 0xe3, 0x42, 0xe2, 0x14, 0x0d, 0xc5, 0xf3, 0xcd, 0x38, 0xeb, 0x1b, 0x79, 0xab, 0x11, 0xb5, 0x5b, 0x5b, 0x02, 0xc4, 0xc7, 0x11, 0xb7, 0xbc, 0x78, 0x0b, 0xa2, 0xd9, 0x67, 0xb9, 0x07, 0x65, 0x0b, 0x9b, 0x82, 0x41, 0x53, 0xa4, 0x8c, 0x8e, 0x53, 0xc2, 0x65, 0x9c, 0x65, 0x3f, 0xca, 0x42, 0x7a, 0x57, 0xaa, 0xbe, 0xbd, 0x66, 0xa5, 0xbf, 0x73, 0xb2, 0xa3, 0x73, 0xdc, 0xe3, 0x53, 0x5b, 0xb5, 0x66, 0x47, 0xc0, 0xd1, 0xd2, 0x59, 0xe8, 0x58, 0xcb, 0x5d, 0xff, 0x36, 0xb8, 0xda, 0xa0, 0xa6, 0x8f, 0xe8, 0x36, 0x0e, 0xa7, 0x47, 0x3b, 0xc2, 0x90,\n\t0x07, 0x73, 0x6a, 0x8d, 0xba, 0xd8, 0x9c, 0x69, 0x4b, 0x98, 0x0d, 0x5f, 0xdd, 0xd6, 0x64, 0xf4, 0xaa, 0xb1, 0x9c, 0xd3, 0x01, 0xe9, 0xf1, 0x90, 0xec, 0x22, 0x42, 0x05, 0xb7, 0x66, 0x08, 0xd1, 0x3a, 0x84, 0x5a, 0x04, 0x35, 0x77, 0x72, 0xb2, 0x4a, 0x28, 0xab, 0x8a, 0xa2, 0x33, 0x22, 0x60, 0x2b, 0xb7, 0xd3, 0x18, 0xe2, 0x42, 0x6a, 0x56, 0xcd, 0xea, 0xb5, 0xf0, 0x49, 0x55, 0x10, 0x4b, 0x62, 0x62, 0xfc, 0x45, 0x21, 0x27, 0x0a, 0x63, 0x73, 0xc1, 0x89, 0xfe, 0x8d, 0xe4, 0xa0, 0x2a, 0xee, 0x4a, 0xf0, 0x1c, 0x29, 0xef, 0xc8, 0x37, 0x14, 0xe5, 0x55, 0x12, 0x59, 0x4f, 0x38, 0xdc, 0xb3, 0x8e, 0x7e, 0xa3, 0x75, 0x2c, 0x6f, 0xb7, 0xe7, 0xc7, 0x5a, 0xd7, 0xed, 0xda, 0xb0, 0x61, 0x17, 0x68, 0x4f, 0xaf, 0xb9, 0x6e, 0xd5, 0xea, 0xeb, 0xd6, 0xa6, 0xd3, 0x6b, 0xaf, 0x5b, 0xbd, 0xea,\n\t0xba, 0x35, 0x69, 0xbc, 0xf7, 0xb7, 0xc0, 0x33, 0x96, 0x87, 0xfd, 0x0d, 0x11, 0x77, 0x20, 0x7c, 0x7a, 0x06, 0x65, 0xd9, 0x13, 0x6c, 0x15, 0x8c, 0x8c, 0x5d, 0xc4, 0x68, 0x80, 0x02, 0x22, 0xca, 0x0e, 0x9f, 0x2c, 0xa1, 0xa5, 0x55, 0x34, 0x8e, 0xb3, 0xdc, 0x50, 0xd1, 0x37, 0x3e, 0xe5, 0x0d, 0x9f, 0xf2, 0x30, 0xd6, 0x35, 0xa2, 0x21, 0xee, 0xac, 0xba, 0x46, 0xe0, 0x0c, 0x6f, 0xd1, 0x9f, 0xb0, 0x41, 0x2b, 0x69, 0x3d, 0x12, 0xc1, 0xe2, 0xbb, 0x35, 0x3d, 0x98, 0x29, 0x07, 0x4d, 0x1b, 0xfa, 0x98, 0xad, 0x4e, 0xdf, 0x2c, 0x3d, 0xe3, 0x08, 0x69, 0x4d, 0x0e, 0xe7, 0x25, 0x19, 0x63, 0x05, 0xce, 0x9d, 0x3b, 0x04, 0x56, 0x62, 0x3a, 0xbf, 0xa2, 0xa8, 0x86, 0xf2, 0x04, 0xad, 0x96, 0x91, 0xe2, 0x86, 0x44, 0x9e, 0x04, 0x3b, 0x12, 0xe1, 0x45, 0x9c, 0x9c, 0x52, 0x68, 0x27, 0xd2, 0xe6,\n\t0xcf, 0x15, 0x93, 0x80, 0x2b, 0x97, 0xb0, 0x2f, 0x01, 0x5f, 0x01, 0x12, 0x86, 0x0e, 0x14, 0xf5, 0xf9, 0x40, 0x88, 0x97, 0x4c, 0x71, 0x7e, 0xa9, 0x4a, 0x38, 0xde, 0x84, 0xa2, 0xbe, 0x08, 0x56, 0x2e, 0x36, 0x1b, 0x68, 0xb9, 0xbd, 0x98, 0x08, 0x5a, 0x94, 0x50, 0x28, 0xf0, 0x6a, 0xc3, 0x49, 0x03, 0x72, 0x4f, 0xeb, 0x4d, 0x99, 0x64, 0x86, 0xdd, 0x6a, 0x64, 0x62, 0x21, 0xd0, 0x22, 0xd6, 0x37, 0x81, 0x72, 0xcf, 0xbb, 0x90, 0x56, 0x05, 0x10, 0x3e, 0xb2, 0x15, 0xf6, 0x51, 0xa7, 0x24, 0x51, 0xc0, 0x3b, 0x21, 0x45, 0x86, 0xcd, 0xed, 0x01, 0xc7, 0xf1, 0x81, 0xc8, 0x6c, 0x62, 0x35, 0xa7, 0xf1, 0x2a, 0xc8, 0x7e, 0xf0, 0xae, 0x23, 0xe9, 0x8d, 0xb5, 0xd6, 0x70, 0xd6, 0xe6, 0x58, 0xd8, 0x54, 0xee, 0xc9, 0x61, 0xb3, 0x15, 0x93, 0x2c, 0x06, 0x92, 0x2c, 0xa5, 0xa7, 0xae, 0x8d, 0x3f,\n\t0x27, 0x5e, 0x67, 0x90, 0x3a, 0x35, 0xf3, 0x1f, 0x01, 0xb7, 0xa8, 0xf8, 0x90, 0x28, 0xa7, 0x9c, 0x34, 0x63, 0x59, 0xc4, 0x47, 0xe4, 0x8b, 0x19, 0xcd, 0x19, 0xe8, 0xb9, 0x12, 0xdf, 0x94, 0x95, 0x0c, 0xf5, 0x3e, 0x0f, 0xb6, 0x10, 0x72, 0xf3, 0x64, 0x45, 0x16, 0x20, 0x31, 0x12, 0xcf, 0x2b, 0x46, 0x98, 0xc6, 0x32, 0x09, 0x64, 0xf8, 0x80, 0x4d, 0x44, 0x43, 0xb5, 0xf1, 0x57, 0xe5, 0x66, 0x6d, 0x3a, 0x63, 0xcd, 0x2c, 0x6e, 0x7a, 0xe4, 0xa0, 0x43, 0xa7, 0x65, 0x96, 0x2a, 0xf9, 0x0b, 0xa9, 0x4f, 0x02, 0x6e, 0x4f, 0xfc, 0xd0, 0x5f, 0x0d, 0x66, 0xb9, 0x79, 0x61, 0x3d, 0xdf, 0x14, 0xb7, 0x93, 0xca, 0xa7, 0xe4, 0xea, 0x23, 0x76, 0x3c, 0x6f, 0x2f, 0x53, 0xdf, 0x27, 0x8d, 0xb2, 0x41, 0x48, 0x4f, 0x6d, 0x45, 0x33, 0x32, 0xd0, 0x11, 0x28, 0x75, 0x76, 0x0b, 0x20, 0x14, 0x32, 0x44,\n\t0x14, 0x29, 0xdc, 0xb6, 0x45, 0x04, 0x93, 0xe1, 0xc0, 0xbf, 0x46, 0x82, 0x86, 0xa7, 0x65, 0x36, 0x6e, 0xf4, 0x0a, 0xd9, 0x60, 0x3e, 0x2c, 0xd0, 0x5a, 0x1b, 0xb9, 0x5f, 0x94, 0xb7, 0xe0, 0x7b, 0xa8, 0x3b, 0xf0, 0x7b, 0x38, 0x22, 0x50, 0xf4, 0x31, 0x24, 0x8d, 0x5c, 0x10, 0x08, 0xc8, 0x04, 0x6c, 0x51, 0x43, 0x8a, 0x6b, 0x34, 0xa8, 0x38, 0x35, 0x27, 0xbe, 0x54, 0x36, 0xeb, 0xa5, 0xfc, 0x7c, 0xaf, 0x27, 0xb5, 0xf3, 0xb4, 0x54, 0x69, 0x11, 0x9d, 0xcf, 0xa7, 0xc1, 0x3a, 0x19, 0xa2, 0x26, 0xb2, 0xaf, 0xb3, 0x1a, 0x90, 0x46, 0x54, 0x0c, 0x6e, 0x78, 0xc8, 0xe5, 0x3c, 0x40, 0x0f, 0x6a, 0xc9, 0x7c, 0x01, 0xc4, 0x4d, 0x1a, 0x9d, 0xcf, 0xa4, 0x09, 0xd9, 0x95, 0x34, 0xdb, 0xd2, 0xb9, 0xc8, 0xe6, 0x49, 0x30, 0xff, 0xa5, 0x08, 0x5a, 0xf3, 0xbb, 0x36, 0x8f, 0x7b, 0x54, 0x1e, 0x75,\n\t0xb8, 0xf1, 0x86, 0x2f, 0xde, 0x89, 0x19, 0xe7, 0x7a, 0x7a, 0x0b, 0x48, 0x33, 0xbf, 0x16, 0x71, 0x11, 0x6d, 0x52, 0x70, 0x38, 0xdc, 0x3d, 0x6b, 0x4b, 0xbe, 0xef, 0x8d, 0x84, 0x14, 0x1c, 0x2e, 0x16, 0x9a, 0x46, 0xc9, 0x77, 0xcb, 0x25, 0xd7, 0x18, 0x20, 0x47, 0xc6, 0x9f, 0x82, 0xea, 0x98, 0x98, 0x39, 0x2a, 0xa6, 0xf7, 0x98, 0x4b, 0xc6, 0x42, 0x90, 0xae, 0xcd, 0x66, 0x6b, 0x63, 0x43, 0x8d, 0x3c, 0xdf, 0x38, 0x14, 0x63, 0xae, 0xcd, 0x27, 0xe2, 0xf9, 0x55, 0xae, 0xba, 0xde, 0x58, 0xbc, 0x37, 0xe3, 0x12, 0x79, 0xec, 0x3a, 0xd8, 0x76, 0x6a, 0x76, 0xdb, 0x88, 0x5c, 0x52, 0x6b, 0x4b, 0xae, 0xb7, 0x8d, 0x00, 0xb7, 0x7d, 0xb6, 0xa0, 0xbf, 0x72, 0xdb, 0x5c, 0x35, 0x68, 0x07, 0x24, 0x87, 0xeb, 0xaa, 0x9b, 0xa6, 0x5f, 0xcd, 0xc7, 0x13, 0xf9, 0x35, 0xae, 0x4c, 0x6f, 0x3c, 0xd6,\n\t0x5b, 0xe7, 0x42, 0x31, 0x51, 0x90, 0xbe, 0x11, 0xb2, 0x0b, 0xa1, 0x5e, 0x9c, 0x2c, 0xc6, 0x0c, 0xda, 0xd9, 0xb5, 0xee, 0x01, 0xd8, 0x45, 0xa0, 0x1d, 0xb9, 0x5c, 0x0a, 0x9b, 0x23, 0xc8, 0x91, 0x40, 0xd4, 0x26, 0x2a, 0x31, 0x95, 0xcc, 0x1a, 0xb3, 0x58, 0xee, 0xbe, 0x94, 0x41, 0x13, 0xb0, 0xe4, 0x1a, 0x1a, 0xec, 0xa8, 0x26, 0xd1, 0x9a, 0x55, 0x87, 0xb3, 0xfd, 0x09, 0x53, 0x77, 0xd1, 0x13, 0xe7, 0x1d, 0x1a, 0x56, 0x21, 0xf3, 0xa2, 0x84, 0x24, 0x14, 0x6a, 0xb8, 0xf4, 0x5a, 0xdf, 0x07, 0xa0, 0x20, 0xf7, 0xa7, 0x9a, 0x7c, 0xfd, 0xbd, 0x3a, 0x83, 0x4e, 0xf4, 0x1d, 0x34, 0xc3, 0xbe, 0xd8, 0x71, 0x5f, 0xa0, 0xfe, 0xab, 0x85, 0x74, 0xd6, 0x3d, 0xa7, 0xc6, 0x3d, 0x45, 0x9d, 0xd1, 0x1f, 0x5b, 0x20, 0x8c, 0xa3, 0xf1, 0xb9, 0x4a, 0x24, 0x78, 0xb9, 0x68, 0x8d, 0x4c, 0x2a, 0x73,\n\t0xff, 0x97, 0x89, 0x75, 0x35, 0x7d, 0xeb, 0x61, 0x9f, 0x1a, 0x72, 0x96, 0xa8, 0x82, 0xd5, 0x38, 0xf8, 0xb8, 0xa7, 0xd8, 0x6d, 0x4a, 0xf6, 0x65, 0x0f, 0xd3, 0x57, 0xfb, 0xae, 0x5d, 0xda, 0xb2, 0xaa, 0xcd, 0xa7, 0x30, 0xf9, 0x1d, 0x19, 0x2d, 0xec, 0x4a, 0x6f, 0xbf, 0xaf, 0x29, 0xe5, 0x97, 0x0b, 0xdf, 0x15, 0xd7, 0x65, 0x05, 0x95, 0xa0, 0x56, 0xc0, 0x33, 0x5b, 0x85, 0xb7, 0x84, 0x13, 0xea, 0xf7, 0x88, 0xa6, 0x64, 0x36, 0x29, 0xa2, 0x35, 0xcd, 0x83, 0xb7, 0xb4, 0xe2, 0x0a, 0xa3, 0x43, 0x71, 0xa7, 0xce, 0x0c, 0xf5, 0x37, 0xcd, 0xad, 0x72, 0xa7, 0xf9, 0x10, 0x18, 0x9c, 0xa6, 0x12, 0x26, 0x03, 0xc8, 0xba, 0xeb, 0x1d, 0x8e, 0x7a, 0xb7, 0xf0, 0x9a, 0xde, 0x8c, 0x32, 0x5c, 0x2b, 0x6d, 0x60, 0x39, 0x4e, 0xf5, 0xe9, 0x72, 0x5c, 0x19, 0x23, 0xae, 0x9c, 0xca, 0x4b, 0xad, 0x10,\n\t0x9e, 0x9a, 0x16, 0x1e, 0xc5, 0xad, 0x39, 0x0d, 0x52, 0x63, 0x90, 0x38, 0xde, 0x40, 0xee, 0x34, 0x19, 0x84, 0xef, 0x37, 0xa6, 0xed, 0x19, 0x37, 0xc8, 0xe8, 0xcd, 0xe2, 0x78, 0x1e, 0xa7, 0x6f, 0x05, 0xed, 0xb2, 0x85, 0x12, 0xae, 0x05, 0x52, 0x4e, 0x47, 0x25, 0xeb, 0x3d, 0x01, 0x4a, 0xb8, 0x16, 0x19, 0x36, 0xf0, 0xf8, 0xf5, 0xd7, 0xcb, 0x16, 0x0a, 0x83, 0xe2, 0x99, 0x7e, 0x06, 0xfe, 0x63, 0xc7, 0x78, 0x50, 0xfa, 0xb3, 0xa2, 0xb4, 0x71, 0x1c, 0x67, 0xc4, 0x5b, 0xbf, 0x0d, 0x27, 0x1a, 0xf3, 0x9c, 0x0e, 0xa0, 0x29, 0xe1, 0x41, 0x97, 0x02, 0x8a, 0xc4, 0xf2, 0x83, 0xc2, 0x97, 0x4f, 0x89, 0x7f, 0x80, 0xd5, 0x40, 0xad, 0x87, 0xff, 0x13, 0x3e, 0x24, 0xdf, 0x45, 0x9f, 0x40, 0x8d, 0xfb, 0xf5, 0x0c, 0xb8, 0x8c, 0xb4, 0x93, 0x0f, 0xc0, 0x36, 0x66, 0xe1, 0x6d, 0x88, 0x9a, 0x33,\n\t0x14, 0x94, 0x91, 0x08, 0x5b, 0x7a, 0xe5, 0x4d, 0xe5, 0x37, 0x7d, 0x51, 0x7a, 0x03, 0x20, 0x8e, 0x82, 0x16, 0x72, 0x1f, 0xf9, 0x07, 0xf8, 0xfc, 0x02, 0x91, 0x2f, 0x3b, 0x30, 0x1c, 0xe3, 0x34, 0x4e, 0x6a, 0x81, 0x2f, 0x43, 0x9f, 0x00, 0x41, 0x4f, 0x00, 0x62, 0x21, 0x64, 0xab, 0xe8, 0xc0, 0xee, 0x9e, 0xef, 0x9a, 0x98, 0xf0, 0x22, 0x27, 0xe4, 0x50, 0xef, 0xc3, 0xc6, 0x27, 0x33, 0x8f, 0x43, 0x59, 0xc8, 0x7d, 0x82, 0xf1, 0x91, 0x9b, 0xc0, 0xb7, 0x0f, 0x1c, 0x00, 0x19, 0xe1, 0xfb, 0xe2, 0x5c, 0x56, 0xda, 0xec, 0x10, 0xdb, 0xb4, 0xe2, 0x8e, 0x6f, 0x3a, 0x23, 0xa3, 0x1c, 0x29, 0x14, 0xf3, 0xa6, 0x9a, 0x8f, 0x3f, 0x75, 0x46, 0xb2, 0xf9, 0xbe, 0x47, 0x6e, 0x7a, 0x04, 0xfc, 0x81, 0xdc, 0x29, 0xbc, 0x06, 0xb2, 0x97, 0xce, 0x6e, 0x47, 0x4d, 0x84, 0x8b, 0x01, 0xec, 0xd0, 0x18,\n\t0xad, 0xf2, 0xa2, 0xd0, 0x34, 0x5a, 0x03, 0x1a, 0x2c, 0x98, 0xdf, 0x89, 0x82, 0x5f, 0x88, 0xde, 0x79, 0xea, 0xf6, 0xdb, 0x0f, 0xdc, 0x76, 0x9b, 0xf8, 0xbe, 0x53, 0xf0, 0x7d, 0xa3, 0x9f, 0xba, 0x07, 0x78, 0x33, 0x7f, 0x14, 0xfc, 0x41, 0x30, 0x92, 0xa3, 0x07, 0xa4, 0x3e, 0xdc, 0x49, 0x9e, 0xa4, 0xfc, 0x84, 0x9d, 0x58, 0x2b, 0xda, 0x0f, 0xb4, 0x7a, 0x94, 0x0d, 0x31, 0x68, 0xb7, 0x42, 0xee, 0x45, 0xf4, 0x3b, 0x67, 0x7d, 0x07, 0xfd, 0x52, 0x4e, 0xaf, 0x11, 0x60, 0xe8, 0xaa, 0xe5, 0x00, 0x94, 0x0f, 0xac, 0x13, 0x2f, 0x2f, 0x4a, 0x04, 0x9a, 0x7d, 0x90, 0xc7, 0x9f, 0x0c, 0xf1, 0x11, 0xec, 0xc6, 0x08, 0x59, 0x2d, 0x62, 0xa6, 0xec, 0x6c, 0xdb, 0x8f, 0xfc, 0x28, 0xa0, 0x59, 0x75, 0xa2, 0xe0, 0xf3, 0xab, 0xd5, 0x0e, 0x19, 0xe7, 0x5e, 0x90, 0x69, 0x5d, 0x9c, 0x36, 0x7d, 0x89,\n\t0x7c, 0x7e, 0x32, 0x64, 0xb3, 0xb7, 0x64, 0x7a, 0x74, 0x3a, 0x7b, 0x93, 0xce, 0x1a, 0x69, 0xee, 0xf5, 0xe9, 0x5b, 0xc5, 0x7d, 0x5b, 0x4b, 0xfe, 0x82, 0xec, 0x81, 0xb2, 0x80, 0x96, 0xc8, 0x12, 0xa1, 0xa2, 0x3f, 0x1b, 0x0f, 0xb8, 0xb5, 0x18, 0x1b, 0x02, 0x8f, 0x08, 0xac, 0x45, 0x22, 0x00, 0x3c, 0xc3, 0x99, 0xba, 0x50, 0xd0, 0x6e, 0x0d, 0xd1, 0x28, 0xcc, 0xb7, 0x4a, 0x5f, 0x4e, 0x81, 0xc2, 0x6c, 0x14, 0x88, 0x76, 0x20, 0x6a, 0x50, 0xe8, 0xe4, 0x49, 0xf1, 0xe1, 0x20, 0xa1, 0x52, 0x9b, 0x0c, 0x5a, 0x93, 0x46, 0xa9, 0x5d, 0xa7, 0x65, 0x55, 0x0c, 0xeb, 0xcf, 0x07, 0x43, 0xb9, 0x80, 0x81, 0x56, 0xb3, 0x5a, 0xd7, 0xbf, 0xed, 0xd6, 0x59, 0x99, 0x8d, 0x2a, 0x86, 0x52, 0x30, 0x1b, 0x19, 0x9d, 0x6e, 0xd7, 0x77, 0xa8, 0xa7, 0xcc, 0x61, 0x9d, 0xc9, 0x65, 0x71, 0x70, 0x41, 0x93,\n\t0x33, 0xe8, 0x08, 0xba, 0x1d, 0x7a, 0xe4, 0xde, 0xb7, 0x46, 0x73, 0x1e, 0xbd, 0xdd, 0x13, 0xb4, 0xe7, 0xc0, 0x6e, 0x9d, 0xfa, 0x87, 0x1c, 0xa7, 0x36, 0x2a, 0x7f, 0xa8, 0xd6, 0x09, 0xc7, 0x50, 0x2f, 0xef, 0x82, 0x03, 0x59, 0x87, 0xeb, 0x4e, 0x89, 0x7e, 0x12, 0xd1, 0x45, 0x32, 0x59, 0x41, 0x8f, 0x94, 0x97, 0xfd, 0x24, 0x22, 0xc4, 0x6a, 0x8e, 0x5c, 0xf7, 0x45, 0xe1, 0x2d, 0xc0, 0x33, 0x27, 0xff, 0x3e, 0xc5, 0x28, 0x8e, 0x83, 0x59, 0xef, 0x80, 0x1c, 0x59, 0xe2, 0x20, 0xeb, 0x25, 0x6b, 0x70, 0xe5, 0x35, 0xe5, 0x1d, 0x2f, 0xbe, 0x87, 0xad, 0x7a, 0x0f, 0xf5, 0x9d, 0xe3, 0xa0, 0x4b, 0xdc, 0x8b, 0xff, 0xaf, 0xdf, 0x45, 0x1e, 0x3c, 0x4e, 0x5e, 0xf5, 0xff, 0xd1, 0xbb, 0x40, 0xe7, 0x71, 0xea, 0x5f, 0x67, 0xbf, 0x0b, 0xfb, 0x93, 0xa4, 0x29, 0x12, 0x0f, 0xf5, 0xdc, 0x9a, 0xf2,\n\t0x40, 0x7a, 0x8b, 0xd0, 0x21, 0xbe, 0xe4, 0x38, 0x83, 0x7c, 0x94, 0xd7, 0x11, 0x57, 0x90, 0x0f, 0x53, 0xe7, 0xc3, 0xdb, 0x42, 0x28, 0x0d, 0x78, 0x5e, 0xc8, 0x9a, 0x79, 0xf0, 0x6a, 0x1e, 0x9e, 0x79, 0xfb, 0x26, 0x40, 0x5e, 0x46, 0xfe, 0x69, 0xe6, 0x7a, 0xb1, 0x1f, 0xa5, 0xf7, 0xc8, 0x09, 0x7f, 0xd1, 0x8b, 0xd9, 0xd7, 0xa8, 0x24, 0x2f, 0x20, 0x5b, 0x33, 0x3a, 0x63, 0x24, 0x58, 0x30, 0x0b, 0x16, 0x37, 0xc3, 0xf2, 0xe4, 0xc3, 0xc2, 0xee, 0x9b, 0x6e, 0x02, 0x47, 0xc1, 0x33, 0xc2, 0x77, 0xc8, 0x3f, 0x09, 0xdf, 0x39, 0x7d, 0x9a, 0x48, 0x9f, 0xe6, 0x48, 0x23, 0x48, 0x40, 0x76, 0xd2, 0x71, 0xfa, 0xf4, 0xc7, 0xd7, 0x4a, 0x31, 0xf6, 0xd7, 0x8a, 0x31, 0xf6, 0xf0, 0xfa, 0x85, 0x74, 0x9a, 0x7c, 0x40, 0xf6, 0x2d, 0x32, 0x4c, 0x3c, 0x4d, 0xdc, 0x43, 0x44, 0x98, 0xc6, 0xd3, 0x13,\n\t0xc4, 0x47, 0x40, 0xce, 0x34, 0x13, 0x2f, 0x12, 0x1f, 0x11, 0xf6, 0xc7, 0x08, 0xf0, 0xcd, 0xd3, 0xf7, 0xc0, 0xbb, 0x1f, 0x03, 0xe0, 0xd1, 0x8f, 0xd0, 0x27, 0x29, 0x7e, 0xa2, 0x3e, 0x42, 0x69, 0x9c, 0xfe, 0x05, 0x73, 0x3f, 0xe1, 0x27, 0x1e, 0x7e, 0x12, 0x21, 0x9e, 0x95, 0x50, 0xb8, 0x8d, 0xc8, 0xc8, 0x24, 0x42, 0x26, 0x66, 0x50, 0xfa, 0x76, 0x82, 0xaa, 0x24, 0x0c, 0x96, 0xaf, 0xe4, 0x2a, 0x57, 0xd8, 0xb3, 0x3e, 0x63, 0x3e, 0xeb, 0x33, 0xd6, 0xb3, 0x3c, 0x33, 0xdf, 0xed, 0x28, 0xda, 0x61, 0xfc, 0x1b, 0x11, 0xab, 0x3f, 0xca, 0x33, 0x72, 0x7b, 0x9c, 0xcb, 0x4a, 0xe9, 0x47, 0x99, 0x7a, 0x64, 0xc6, 0xd2, 0x51, 0xa2, 0xb6, 0x43, 0xa2, 0xdc, 0x24, 0xeb, 0x05, 0x23, 0x27, 0xae, 0xd8, 0xec, 0xf5, 0x6e, 0xbe, 0xe2, 0xc4, 0xc8, 0x05, 0xfd, 0xd9, 0xad, 0xeb, 0x96, 0xb5, 0x05,\n\t0x7e, 0x1a, 0x68, 0x5b, 0xb6, 0x6e, 0x6b, 0xb6, 0x9f, 0xd9, 0x1f, 0x6b, 0x39, 0xfa, 0xee, 0x63, 0x8f, 0xbd, 0x7b, 0xb4, 0x25, 0x76, 0x4d, 0x78, 0xf4, 0xda, 0x97, 0x04, 0xe1, 0x1e, 0xe1, 0x7c, 0x70, 0xe4, 0x1e, 0x40, 0xbe, 0x74, 0xed, 0x68, 0x58, 0x5c, 0xb7, 0xc7, 0xe0, 0x9c, 0xc4, 0xe1, 0xfe, 0xb1, 0x21, 0xbf, 0x97, 0x5c, 0xcc, 0x9c, 0x29, 0x89, 0x1d, 0x62, 0xd1, 0xac, 0xc9, 0x72, 0x95, 0x95, 0xb8, 0xd4, 0x3f, 0xc9, 0x2d, 0xca, 0x06, 0xa3, 0xbc, 0x5c, 0x8e, 0x0b, 0xac, 0x94, 0x21, 0x53, 0x6a, 0xa9, 0x00, 0x06, 0x47, 0x34, 0x83, 0x6b, 0xc0, 0xf8, 0xc0, 0xfa, 0x26, 0x2b, 0x14, 0xa0, 0xd9, 0x56, 0xa0, 0xf7, 0x37, 0xc4, 0x84, 0xaf, 0x9d, 0xa2, 0x2e, 0xa6, 0xff, 0x28, 0x78, 0xec, 0xf5, 0x0b, 0x32, 0x1a, 0xab, 0x49, 0xe3, 0x0a, 0x5b, 0x95, 0x33, 0x5f, 0x62, 0x4e, 0x7e,\n\t0x15, 0x6d, 0xb2, 0xc5, 0x70, 0x8f, 0x25, 0x99, 0xaf, 0x40, 0xe9, 0x39, 0x46, 0x7c, 0xff, 0xa9, 0xa8, 0x89, 0x44, 0xf8, 0x29, 0x25, 0x6b, 0x95, 0x24, 0x0a, 0x66, 0x70, 0xa4, 0x2d, 0xe6, 0xc1, 0x95, 0x85, 0x28, 0x5f, 0xcd, 0xcd, 0xbd, 0x6a, 0xfe, 0xd4, 0x67, 0x1d, 0x9f, 0xfa, 0xac, 0xeb, 0x53, 0x9e, 0x3d, 0xdb, 0x63, 0x78, 0xd9, 0x10, 0xfc, 0x72, 0xac, 0xc6, 0xeb, 0x56, 0x2b, 0x71, 0x04, 0xb0, 0xbc, 0x82, 0xb4, 0x53, 0x82, 0x06, 0x93, 0xcf, 0xc1, 0xdb, 0x64, 0x03, 0xe4, 0xf3, 0xab, 0xbf, 0xb0, 0xa5, 0xb1, 0x71, 0xcb, 0x17, 0x56, 0x4b, 0x9f, 0xba, 0xf3, 0x9f, 0xbb, 0x66, 0x60, 0xe5, 0x3d, 0xbf, 0x3a, 0x72, 0xe4, 0xd7, 0x5f, 0x5e, 0x39, 0x70, 0xcd, 0xf3, 0xe7, 0xbf, 0x0e, 0xde, 0xce, 0x6f, 0xbc, 0x71, 0xd5, 0xc4, 0x8d, 0x53, 0xf9, 0xfc, 0xd4, 0x8d, 0x13, 0xab, 0x6e,\n\t0xdc, 0x98, 0x7f, 0xcc, 0xb0, 0xe1, 0x96, 0x97, 0x76, 0xec, 0xfb, 0xc9, 0xed, 0xcb, 0x97, 0xdf, 0xfe, 0x93, 0x7d, 0x3b, 0x5f, 0xfa, 0xc2, 0x06, 0x03, 0x36, 0x9f, 0xc0, 0x35, 0xe5, 0x10, 0x0e, 0x25, 0x5c, 0x53, 0x2d, 0x46, 0x28, 0x12, 0x43, 0xa1, 0x36, 0xc0, 0xee, 0xc6, 0x11, 0x79, 0x49, 0x20, 0x2c, 0x2e, 0xce, 0x47, 0xcb, 0x6d, 0x18, 0x2d, 0xb3, 0xc0, 0xf1, 0x48, 0xae, 0x92, 0x53, 0x3c, 0x45, 0x1e, 0xf6, 0xb8, 0x75, 0x1f, 0x7f, 0xf2, 0x7d, 0x30, 0x7d, 0xc8, 0x0b, 0xff, 0xa0, 0x32, 0x51, 0x3f, 0x99, 0xa2, 0x02, 0x51, 0xff, 0xcc, 0x8f, 0xcb, 0x7b, 0x85, 0xf9, 0x2b, 0x7c, 0x6f, 0x18, 0xd9, 0xc3, 0xdc, 0x7a, 0xd9, 0x19, 0x98, 0x54, 0x54, 0x1c, 0x83, 0x65, 0x26, 0x30, 0xe1, 0x09, 0x13, 0x21, 0xde, 0x5a, 0x60, 0x65, 0x72, 0x09, 0x8c, 0x2a, 0x2f, 0x02, 0x2f, 0x21, 0x9b,\n\t0x60, 0x05, 0x8f, 0x0a, 0x88, 0x78, 0x54, 0x28, 0x23, 0x82, 0xf9, 0xeb, 0xf7, 0x29, 0x5a, 0xd8, 0xc3, 0xfa, 0x1d, 0x32, 0x7b, 0xc0, 0x20, 0xec, 0xa6, 0xe9, 0x1f, 0x3c, 0xe1, 0x72, 0x1a, 0xc1, 0x15, 0x6a, 0x16, 0x8a, 0x92, 0x6a, 0x70, 0xb9, 0x52, 0x67, 0xe0, 0x74, 0x88, 0x72, 0xd1, 0x4e, 0x57, 0x27, 0x2f, 0x98, 0x2c, 0x4e, 0xa7, 0x05, 0xbc, 0xeb, 0xef, 0x74, 0x7d, 0xfc, 0x2b, 0xe6, 0xa4, 0xce, 0x22, 0xe4, 0x74, 0x36, 0x8d, 0xd6, 0xae, 0x03, 0xdf, 0x55, 0xeb, 0x90, 0xa9, 0x0b, 0x63, 0x74, 0x33, 0xbd, 0xcc, 0x43, 0x44, 0x3d, 0x31, 0x5a, 0xd4, 0xeb, 0x10, 0x1c, 0x67, 0x7d, 0x5d, 0xaa, 0x36, 0xc9, 0x88, 0x31, 0x9d, 0x2c, 0x46, 0x1e, 0x01, 0xb8, 0x18, 0xc6, 0xce, 0x52, 0x7e, 0x4c, 0xe5, 0x5c, 0x9e, 0x71, 0xa9, 0x7c, 0x3a, 0x9f, 0x8a, 0x84, 0xb9, 0x30, 0x9a, 0x3f, 0x10,\n\t0xc2, 0x75, 0x52, 0x91, 0xd5, 0x41, 0x26, 0xa1, 0x57, 0xd0, 0x16, 0xa3, 0xd9, 0x44, 0xca, 0x21, 0xeb, 0x04, 0xf9, 0x82, 0x88, 0xb2, 0x0f, 0x45, 0x63, 0x26, 0x02, 0xe0, 0xa8, 0x21, 0x55, 0xbb, 0xb3, 0x79, 0x4b, 0xa6, 0xe5, 0xa6, 0x15, 0x57, 0xbc, 0x35, 0xcd, 0xc7, 0x8c, 0xdd, 0xfd, 0x47, 0x6f, 0xb9, 0x7b, 0xd5, 0x43, 0x40, 0xf9, 0xe4, 0x9a, 0xab, 0xae, 0xbb, 0xc2, 0xe4, 0x50, 0x2b, 0x74, 0xe1, 0x65, 0x7d, 0x29, 0x00, 0x22, 0xab, 0x9a, 0x85, 0x2d, 0x2b, 0xc8, 0x63, 0xce, 0xd4, 0xcc, 0xb9, 0xd4, 0xf0, 0x47, 0xfe, 0x3a, 0x53, 0x38, 0xda, 0xdc, 0xc8, 0x02, 0xfb, 0xa6, 0x64, 0x4f, 0xd2, 0x3a, 0xf9, 0xb4, 0xf0, 0x97, 0xfb, 0xbe, 0x29, 0xdc, 0xf0, 0x0d, 0xce, 0x1d, 0x64, 0x13, 0x57, 0x7c, 0xf9, 0xb9, 0x2d, 0x3a, 0x97, 0x2e, 0xd0, 0x1d, 0x78, 0xef, 0x46, 0x70, 0x70, 0x49,\n\t0xbb, 0x70, 0xb1, 0x24, 0xbf, 0x0b, 0x5f, 0xa2, 0x0f, 0x31, 0x7f, 0x83, 0x12, 0xc0, 0x43, 0x4f, 0x40, 0x31, 0x92, 0xe8, 0x13, 0xcf, 0x12, 0x8b, 0x05, 0xc0, 0x72, 0xd1, 0xc8, 0x0c, 0x51, 0x3a, 0x46, 0x73, 0x2e, 0xe4, 0x88, 0xd2, 0x09, 0x9a, 0xf7, 0x09, 0xc7, 0xd9, 0x9e, 0x70, 0xcd, 0xff, 0xc4, 0x3c, 0x37, 0x8b, 0xa7, 0x45, 0x0b, 0x88, 0x78, 0x2c, 0x1c, 0x24, 0xb2, 0x20, 0x4b, 0xa3, 0xb3, 0x22, 0x9d, 0x11, 0x2b, 0x92, 0x40, 0x70, 0x38, 0x25, 0x8e, 0x9d, 0x47, 0x27, 0xc6, 0x98, 0x0f, 0x62, 0xb3, 0x57, 0xe9, 0xdc, 0x50, 0xd6, 0x6d, 0x5f, 0xbf, 0xbc, 0x6f, 0xf1, 0x91, 0xa7, 0x37, 0xad, 0xdd, 0xd5, 0x62, 0x4c, 0x46, 0x6f, 0xe5, 0x42, 0xca, 0xd0, 0x60, 0xc7, 0x15, 0xbf, 0x7d, 0x6c, 0xf3, 0xa6, 0x6f, 0x01, 0xea, 0x64, 0xef, 0x8a, 0x8c, 0x95, 0x5e, 0xc6, 0x9a, 0x54, 0x64,\n\t0x78, 0xf9, 0xf5, 0xf4, 0x7b, 0x3d, 0x07, 0x5f, 0xdc, 0x77, 0xe0, 0x5b, 0x07, 0xc7, 0x9c, 0xb6, 0xb6, 0xbe, 0x05, 0x91, 0x81, 0x2b, 0x8b, 0x2d, 0xbe, 0xa5, 0x35, 0xe6, 0x70, 0x90, 0x67, 0x7d, 0x7b, 0x9f, 0xfa, 0xf0, 0x8b, 0x5f, 0x04, 0xd4, 0xd3, 0x1b, 0x95, 0x9c, 0xd7, 0xa2, 0x31, 0x9a, 0x14, 0xf5, 0x0b, 0xb3, 0x4e, 0xc4, 0x6b, 0xb6, 0x9f, 0xfe, 0x80, 0x0e, 0x31, 0x5f, 0x25, 0x65, 0xc4, 0x4f, 0xf0, 0x9c, 0x8e, 0x9c, 0xfe, 0x80, 0xda, 0x42, 0x2b, 0x88, 0x34, 0xf1, 0x00, 0x4e, 0xef, 0x78, 0xd2, 0x84, 0x63, 0x52, 0x9c, 0xf0, 0x13, 0xa1, 0xe9, 0x8f, 0x8b, 0x0a, 0xac, 0x97, 0x10, 0xe1, 0xc8, 0xd7, 0x97, 0x41, 0x6a, 0xf2, 0xb8, 0x02, 0x25, 0x36, 0x60, 0xa5, 0xca, 0x09, 0xd8, 0x61, 0x42, 0xce, 0xc8, 0x18, 0xb9, 0x0c, 0xf9, 0xd3, 0x51, 0xa0, 0x6e, 0xf5, 0xed, 0x44, 0xd5,\n\t0xdd, 0xc5, 0x64, 0x39, 0xb0, 0x73, 0xce, 0x03, 0xa5, 0xa2, 0x2e, 0xb3, 0xee, 0xc7, 0x71, 0x72, 0x7e, 0xd6, 0x14, 0xb4, 0x46, 0x33, 0x0a, 0xb9, 0x2b, 0x1e, 0x2a, 0x81, 0x6c, 0x94, 0x74, 0xc4, 0x4a, 0x76, 0x8e, 0x1c, 0xca, 0xba, 0x62, 0x86, 0x2e, 0xce, 0xb4, 0xd9, 0xe2, 0x1b, 0xe8, 0xef, 0x71, 0x5f, 0xf4, 0xc2, 0xd5, 0xfd, 0x1d, 0x57, 0xff, 0xe0, 0x3a, 0x4f, 0x21, 0xdf, 0xe0, 0x53, 0x33, 0x01, 0xbb, 0xce, 0x5b, 0x93, 0x0f, 0xf6, 0xef, 0x5a, 0x94, 0x56, 0x90, 0x9a, 0x99, 0xf7, 0x75, 0xf7, 0xdf, 0x94, 0x6a, 0x8f, 0xbb, 0xb4, 0x3e, 0x0f, 0xe3, 0xd6, 0x18, 0xd4, 0x74, 0xef, 0xd5, 0x2f, 0xef, 0xdb, 0xf5, 0xc2, 0x91, 0x11, 0x5a, 0xa1, 0x55, 0x2e, 0xe6, 0x39, 0xd8, 0xc1, 0xe8, 0xf0, 0xf6, 0x9e, 0x6b, 0x6f, 0xbd, 0x5b, 0xa6, 0x90, 0xd9, 0x7d, 0x70, 0xce, 0x8a, 0x70, 0xce,\n\t0x26, 0x4a, 0x73, 0x66, 0xc3, 0x73, 0x86, 0x78, 0x0c, 0x9a, 0x33, 0x44, 0x3d, 0xca, 0x73, 0x26, 0x46, 0xff, 0xad, 0x2f, 0x4f, 0x54, 0xbe, 0x82, 0xf1, 0x93, 0x02, 0x95, 0x39, 0x9b, 0x1d, 0x2c, 0x58, 0x7d, 0x7b, 0x69, 0x36, 0x52, 0x9f, 0x16, 0x5d, 0xb8, 0x9e, 0x98, 0xef, 0x7e, 0x31, 0xb6, 0x90, 0x35, 0x06, 0x2d, 0x0d, 0x41, 0x34, 0x67, 0xdc, 0x6c, 0x64, 0x96, 0x2a, 0xe0, 0x8c, 0x02, 0x14, 0xa1, 0x4a, 0x85, 0x45, 0xc2, 0x91, 0x31, 0xbe, 0x21, 0x9f, 0xf7, 0x5e, 0xf7, 0x83, 0xab, 0x3b, 0xfa, 0xaf, 0x7e, 0xe1, 0x22, 0x77, 0xcf, 0x40, 0x3f, 0xaf, 0x66, 0xdc, 0x3e, 0xad, 0x3b, 0xde, 0x9e, 0xba, 0xe9, 0x3e, 0xdd, 0xcc, 0xfb, 0xa4, 0x46, 0x91, 0x5e, 0xb4, 0x73, 0x20, 0x98, 0xab, 0xf1, 0xea, 0xed, 0x01, 0x9a, 0xfa, 0xb5, 0x52, 0xab, 0xa0, 0x47, 0x8e, 0xbc, 0xb0, 0x6b, 0xdf,\n\t0xcb, 0x57, 0xf7, 0xd2, 0x6a, 0x83, 0xa6, 0xcf, 0x67, 0x87, 0x13, 0x75, 0xf7, 0xad, 0xd7, 0xf6, 0x6c, 0x1f, 0x8e, 0xc2, 0xc9, 0x33, 0xf9, 0xd0, 0xbe, 0xab, 0x39, 0xfd, 0x1e, 0xfd, 0x01, 0xf3, 0x20, 0x21, 0x23, 0xde, 0x10, 0xb1, 0x32, 0x4f, 0xbf, 0x4f, 0x4f, 0xd2, 0x72, 0xb8, 0xbc, 0xc5, 0x62, 0x6b, 0xd4, 0x0e, 0x4f, 0x52, 0x40, 0x0d, 0x25, 0x2c, 0x03, 0x2a, 0x49, 0x43, 0x0d, 0x46, 0x00, 0xd9, 0x0f, 0x99, 0x4e, 0x5f, 0x89, 0x29, 0xe5, 0x2b, 0xb1, 0xca, 0x59, 0x4c, 0x88, 0x53, 0x44, 0x2d, 0xaa, 0x6d, 0x17, 0x60, 0xe4, 0x66, 0x84, 0x00, 0x8d, 0x8d, 0x04, 0x90, 0x70, 0x41, 0xba, 0x04, 0x22, 0x6d, 0xa4, 0x04, 0xcf, 0x8d, 0x06, 0x08, 0x7f, 0x41, 0xb4, 0xd8, 0xaa, 0x23, 0xe1, 0x60, 0xe9, 0xc9, 0xba, 0x86, 0xc6, 0xc9, 0xfe, 0xb0, 0xaa, 0xbd, 0xc3, 0xdd, 0x64, 0x9b, 0x79,\n\t0x6d, 0x7f, 0x7b, 0x9f, 0x5b, 0x15, 0x6a, 0xf4, 0xe7, 0xc5, 0x9f, 0x95, 0xf8, 0x67, 0x32, 0xbb, 0x4f, 0xfa, 0xf9, 0xc8, 0x25, 0x3a, 0x83, 0xa5, 0x65, 0xcb, 0x03, 0x7f, 0xfc, 0x72, 0x72, 0x81, 0x63, 0xe6, 0x8e, 0x4d, 0x0f, 0xff, 0xfd, 0xd1, 0xed, 0xad, 0x66, 0xf4, 0x63, 0xf3, 0xd6, 0xaf, 0xfc, 0xf1, 0xee, 0xc4, 0xb0, 0x83, 0x9c, 0x94, 0x7e, 0xc4, 0x3a, 0x8a, 0xf7, 0xf4, 0x7b, 0xb2, 0xc7, 0xa9, 0xf7, 0x08, 0x9e, 0xe8, 0x45, 0xa3, 0xea, 0x00, 0x40, 0x91, 0xc5, 0x15, 0x67, 0x10, 0x33, 0x81, 0x2c, 0x65, 0xa7, 0x1c, 0xe5, 0x2f, 0x2b, 0x26, 0x90, 0x93, 0xb5, 0x16, 0x73, 0x15, 0x11, 0x05, 0x2a, 0xcb, 0x0c, 0xfb, 0xfd, 0xfe, 0x5e, 0x7f, 0x8f, 0x35, 0x1c, 0x09, 0x9a, 0x6b, 0xec, 0x41, 0x15, 0x5c, 0xb0, 0x52, 0x26, 0x06, 0x26, 0x16, 0x7c, 0x05, 0x9b, 0xbb, 0x15, 0x64, 0x00,\n\t0xce, 0x29, 0xab, 0x0a, 0x11, 0xad, 0xd4, 0xda, 0x09, 0xe0, 0x43, 0x41, 0xbd, 0x6a, 0x8e, 0x77, 0x24, 0x03, 0x0b, 0x3a, 0xe2, 0x5a, 0x8b, 0x4b, 0xff, 0xc9, 0xcb, 0x3a, 0x97, 0x45, 0x1b, 0xef, 0x58, 0x18, 0x48, 0x74, 0xc4, 0xcd, 0xaf, 0x90, 0xef, 0x7a, 0xbd, 0x0f, 0xf3, 0xb1, 0xa6, 0xcd, 0x37, 0x8e, 0x15, 0x56, 0x0e, 0x36, 0x98, 0x6b, 0x8e, 0x6f, 0x1d, 0xbb, 0x61, 0x73, 0x53, 0x8c, 0x7f, 0x5b, 0xc5, 0xb9, 0x8c, 0xe0, 0xcb, 0x6d, 0x9b, 0x06, 0x6b, 0x7c, 0x4b, 0x8f, 0xed, 0x48, 0xac, 0x59, 0xb9, 0xd4, 0x1f, 0x58, 0xba, 0x72, 0x75, 0x62, 0xc7, 0xb1, 0xa5, 0xbe, 0x9a, 0xc1, 0x4d, 0x6d, 0xbf, 0x01, 0xd3, 0xab, 0x1d, 0xc1, 0xa5, 0x0f, 0xaf, 0xbc, 0xf0, 0xa5, 0x43, 0x83, 0x8e, 0x74, 0x47, 0x64, 0xe1, 0xd4, 0xe0, 0xa1, 0x97, 0x2e, 0x5c, 0xf9, 0xf0, 0xd2, 0xa5, 0x1a, 0xbb,\n\t0x59, 0x8c, 0x5f, 0xbf, 0x58, 0xd8, 0x4a, 0xdb, 0x68, 0x25, 0x61, 0x20, 0x3a, 0x89, 0x37, 0xc4, 0x3c, 0xd8, 0x4e, 0xa0, 0xc0, 0x79, 0xb0, 0x41, 0xbc, 0xdb, 0x01, 0xc0, 0x41, 0x03, 0xf9, 0x72, 0x2d, 0xf9, 0xc4, 0x50, 0x05, 0x0f, 0x2b, 0x8d, 0x60, 0x44, 0xea, 0xe9, 0x52, 0x55, 0xb4, 0x20, 0x85, 0xca, 0xf6, 0x89, 0x69, 0x63, 0xf3, 0x3c, 0x57, 0xbe, 0x17, 0x15, 0x2e, 0x4a, 0x40, 0xce, 0xc6, 0xc8, 0xa8, 0xb3, 0xdc, 0x49, 0x92, 0x38, 0x6e, 0xbc, 0xfc, 0x7e, 0x78, 0x3b, 0x2d, 0xa3, 0xf7, 0x7c, 0xae, 0x67, 0x64, 0x62, 0x8c, 0x57, 0xb4, 0x86, 0x87, 0xc2, 0x6b, 0x4d, 0xd8, 0xaf, 0x94, 0xa3, 0x5c, 0x02, 0x50, 0x55, 0xdf, 0xce, 0x4c, 0x89, 0xf8, 0x47, 0x99, 0x8a, 0xcc, 0x08, 0xb0, 0xaf, 0x10, 0x47, 0xe1, 0xcc, 0x4e, 0xd5, 0x05, 0x6d, 0xf5, 0x97, 0xf7, 0x5c, 0x7d, 0x3c, 0xd2,\n\t0x37, 0xd9, 0x9c, 0x5f, 0xd7, 0x5b, 0xa3, 0x71, 0xb4, 0x4c, 0x0e, 0x24, 0xa7, 0xb3, 0xc5, 0xb1, 0x8c, 0x99, 0x54, 0x72, 0x86, 0x02, 0xd9, 0xdc, 0x57, 0xb7, 0x22, 0x37, 0xfd, 0xe5, 0xdd, 0xad, 0x6d, 0x17, 0x3c, 0xb8, 0x6d, 0xfd, 0x43, 0x07, 0x06, 0x5b, 0x76, 0xdf, 0x3d, 0xbd, 0xe6, 0xb6, 0x46, 0xe0, 0xed, 0x69, 0xff, 0xd6, 0x13, 0x6b, 0xae, 0x59, 0x1e, 0x8d, 0x0c, 0xef, 0xe8, 0x13, 0x0a, 0x8b, 0xb6, 0x75, 0x38, 0x55, 0xf6, 0xfa, 0xfe, 0xb4, 0xc6, 0x6a, 0xd4, 0xe4, 0x23, 0xaa, 0xe4, 0xe6, 0x87, 0x2e, 0x05, 0xdf, 0xdd, 0xf4, 0x95, 0x0b, 0x8a, 0x3d, 0x57, 0x3e, 0x7f, 0xd1, 0x8e, 0x67, 0x0f, 0x8f, 0xf4, 0x62, 0xec, 0x0e, 0xf2, 0xf4, 0x3b, 0xc2, 0x43, 0xb4, 0x1d, 0xaf, 0x49, 0x12, 0xe3, 0x3c, 0xc1, 0x35, 0x09, 0xe0, 0xdc, 0x64, 0x8c, 0x92, 0x8c, 0xe9, 0x7a, 0xe5, 0xa0,\n\t0x95, 0xec, 0xa3, 0x89, 0x21, 0x71, 0xec, 0xc8, 0x10, 0xc1, 0x45, 0xe7, 0x1f, 0xf6, 0x19, 0x69, 0xc8, 0x08, 0x23, 0x17, 0x5b, 0x2b, 0x40, 0x7b, 0xfd, 0xe5, 0xdd, 0x68, 0x94, 0x1b, 0xf0, 0x28, 0x5f, 0xc1, 0x63, 0x79, 0xf0, 0x32, 0x3c, 0x96, 0x15, 0xc7, 0x1b, 0x6f, 0xbb, 0xed, 0x15, 0xa8, 0x23, 0x79, 0x7a, 0xda, 0x2a, 0x03, 0xaa, 0xee, 0x78, 0x5b, 0xe3, 0x37, 0x8f, 0x1e, 0x3e, 0x7c, 0x14, 0xd1, 0x8d, 0x85, 0xc2, 0xc3, 0xcc, 0x35, 0xcc, 0x49, 0xc8, 0xaf, 0xfe, 0x17, 0xd3, 0x8d, 0x8b, 0x85, 0x87, 0x30, 0xed, 0xad, 0x21, 0x2e, 0x13, 0xe9, 0xa7, 0x0a, 0x85, 0x01, 0x38, 0x11, 0xd0, 0x2d, 0xca, 0x11, 0x42, 0x51, 0x79, 0xe2, 0x97, 0x71, 0xf1, 0x32, 0x4f, 0xd0, 0x90, 0x06, 0xd1, 0x18, 0xfd, 0x95, 0xa1, 0xe1, 0x52, 0x97, 0x6b, 0xec, 0xe5, 0xa5, 0x01, 0xa2, 0xf2, 0xca, 0x25,\n\t0xed, 0x60, 0xce, 0xbd, 0x25, 0x17, 0x4d, 0xe9, 0xd6, 0xf1, 0xa2, 0x0a, 0x2a, 0x08, 0x21, 0x3e, 0x14, 0x94, 0xcb, 0x9d, 0x52, 0x59, 0xb1, 0x8a, 0x4f, 0x06, 0x95, 0x62, 0xad, 0xda, 0x01, 0x14, 0x12, 0x11, 0x2f, 0xce, 0xee, 0x7e, 0xe2, 0xb2, 0xce, 0x83, 0x1d, 0x1a, 0x3a, 0x60, 0x77, 0x6f, 0x28, 0x8e, 0x6d, 0x6b, 0x31, 0xcf, 0xf4, 0xac, 0xca, 0x5b, 0x28, 0xa5, 0xd1, 0x50, 0x00, 0x06, 0x3e, 0x1f, 0xf9, 0xcb, 0x2b, 0xe0, 0xa3, 0xcb, 0x5f, 0xbd, 0xaa, 0xc7, 0x60, 0x84, 0xbc, 0xc6, 0x90, 0xdd, 0x70, 0xdd, 0xf2, 0xbc, 0x39, 0xd1, 0x93, 0xd2, 0xd8, 0x8c, 0x1a, 0x67, 0xd0, 0xac, 0x9c, 0xb9, 0x52, 0xb4, 0x7f, 0x8c, 0xc0, 0x35, 0xf4, 0xc3, 0x71, 0xab, 0xa1, 0xa6, 0x97, 0x2a, 0x26, 0x7c, 0x1a, 0xac, 0x4c, 0x54, 0xd3, 0x47, 0x49, 0x68, 0x4f, 0xa3, 0x80, 0x64, 0x3f, 0x6f, 0x35,\n\t0x8b, 0x99, 0x10, 0x48, 0x5a, 0x0f, 0x95, 0xf3, 0xc6, 0x4d, 0x16, 0xeb, 0x99, 0x92, 0x7a, 0xd3, 0x0d, 0x47, 0x8f, 0xde, 0x70, 0xd3, 0xb1, 0x63, 0xa9, 0x89, 0x1b, 0xa7, 0xf3, 0x3d, 0x97, 0x89, 0x85, 0x86, 0xf2, 0xd3, 0x37, 0x4e, 0xbc, 0x7c, 0xf8, 0xa5, 0x47, 0x51, 0xb9, 0xa1, 0x47, 0x5f, 0xba, 0x41, 0x3f, 0x7a, 0xf0, 0xd1, 0x6d, 0xa8, 0x20, 0x17, 0x2a, 0x45, 0xb6, 0xed, 0xb1, 0x83, 0xa3, 0x7a, 0xe1, 0x71, 0xbc, 0x1e, 0x66, 0xe1, 0x41, 0xea, 0xb7, 0xb8, 0xe6, 0xc3, 0x6e, 0xa9, 0xfc, 0x53, 0x95, 0x70, 0x5e, 0x3b, 0x84, 0xab, 0x2a, 0x94, 0xe4, 0xb1, 0x33, 0x2e, 0x35, 0xe0, 0x4b, 0xb6, 0xb3, 0x3d, 0x35, 0xef, 0x03, 0x08, 0xb6, 0xa5, 0x24, 0xec, 0x83, 0x59, 0xc2, 0x3e, 0x79, 0xf5, 0x95, 0x50, 0xc6, 0xff, 0x68, 0xa6, 0x1f, 0x8c, 0x1f, 0x84, 0x52, 0xff, 0xbb, 0xe4, 0x37,\n\t0x85, 0x07, 0xa1, 0xb8, 0x6f, 0x25, 0xdf, 0x8d, 0xfa, 0x05, 0x64, 0x91, 0x38, 0x04, 0xe7, 0xf0, 0x21, 0xd8, 0xd7, 0x08, 0xaa, 0x37, 0xe2, 0xd1, 0xcd, 0x23, 0xeb, 0xe3, 0x46, 0xf0, 0xd1, 0x4f, 0x93, 0xc3, 0x22, 0x1a, 0x23, 0x6b, 0x8d, 0xcc, 0x91, 0xf7, 0x03, 0xd5, 0xe2, 0x3e, 0x14, 0x3f, 0xca, 0xf8, 0xb3, 0x54, 0x86, 0x7e, 0xe8, 0x51, 0x85, 0x42, 0xf8, 0xb9, 0x21, 0xe8, 0x74, 0x05, 0x0d, 0xc2, 0xcf, 0x15, 0x8a, 0xaf, 0xbd, 0xa0, 0x33, 0x19, 0x74, 0x8a, 0xff, 0x51, 0x1b, 0x14, 0x0a, 0x93, 0xfa, 0x97, 0x0a, 0x1d, 0x6b, 0xd2, 0xe1, 0x9a, 0x1a, 0x5f, 0x88, 0x4d, 0x27, 0x85, 0x43, 0x16, 0x87, 0xc3, 0x02, 0x2e, 0x4c, 0x4e, 0xc7, 0x3e, 0xb1, 0x30, 0x0b, 0x28, 0xb9, 0x4e, 0x23, 0xfc, 0xaf, 0xce, 0xa1, 0xd1, 0x38, 0x0c, 0xc0, 0xa2, 0xd1, 0xc9, 0xd1, 0xe0, 0xd5, 0xb0, 0xcf,\n\t0xc3, 0x34, 0xaa, 0x89, 0x5b, 0x92, 0xf7, 0xb3, 0x99, 0xba, 0x74, 0xea, 0xd3, 0xe4, 0x7d, 0x2c, 0x07, 0xa4, 0xe7, 0x95, 0xf7, 0xf1, 0xa5, 0x06, 0x24, 0xef, 0xd7, 0x48, 0xf2, 0x3e, 0x77, 0xa6, 0xbc, 0x2f, 0xed, 0x8c, 0x79, 0xe5, 0xfd, 0xdf, 0x81, 0xae, 0xec, 0x74, 0x32, 0x7d, 0x7e, 0xcf, 0xba, 0x6f, 0x2d, 0xf6, 0xc5, 0x8c, 0x8d, 0x2d, 0x7b, 0xf7, 0x5f, 0x3d, 0x74, 0xe4, 0x67, 0x37, 0x0d, 0xf9, 0x5a, 0xc7, 0x9b, 0x76, 0x43, 0x79, 0x5f, 0xae, 0x73, 0x0c, 0x76, 0xa7, 0x01, 0xf0, 0x8f, 0xe5, 0x85, 0x5f, 0x2d, 0x25, 0x69, 0x6b, 0xcd, 0xcc, 0x87, 0xe0, 0xa1, 0xdf, 0x07, 0x9a, 0x2c, 0xd1, 0x44, 0xa1, 0x00, 0xe5, 0xfd, 0x95, 0x89, 0xce, 0x84, 0x65, 0xcd, 0x23, 0x1f, 0x9e, 0x58, 0xf7, 0xf8, 0xc3, 0x0f, 0xae, 0xe0, 0xdc, 0x01, 0xb6, 0xe6, 0xbc, 0x13, 0x4f, 0x9f, 0xab, 0x73,\n\t0xe8, 0x22, 0x8b, 0x83, 0x3f, 0xbc, 0x08, 0x5c, 0x30, 0xd2, 0x26, 0x5c, 0x21, 0xca, 0xfb, 0x23, 0xc2, 0x37, 0xa8, 0xfd, 0x74, 0x13, 0xdc, 0x0b, 0x7c, 0xd1, 0xa3, 0xd3, 0x92, 0x64, 0x1f, 0x51, 0xc6, 0xe7, 0x84, 0x37, 0xd4, 0x92, 0xc3, 0xc9, 0x78, 0x30, 0xc0, 0x7b, 0x29, 0x24, 0x65, 0xcf, 0x2f, 0x61, 0xb7, 0x61, 0xc7, 0x77, 0x29, 0xcd, 0x1f, 0x1e, 0x51, 0x60, 0xad, 0x5b, 0x73, 0x68, 0xbc, 0xb8, 0xb4, 0xde, 0x84, 0xc5, 0x6b, 0x8d, 0xb7, 0x21, 0xb9, 0xf6, 0x2b, 0xfb, 0x07, 0x3a, 0x2e, 0x7f, 0xee, 0xd2, 0xd1, 0x31, 0x2c, 0x5a, 0x5f, 0x7b, 0xd9, 0xea, 0x83, 0xa3, 0x51, 0x32, 0xb9, 0xf6, 0xe2, 0xc5, 0x0d, 0x6e, 0x6b, 0x7d, 0x63, 0x67, 0x59, 0xb2, 0x0e, 0xf1, 0x6e, 0xad, 0xab, 0xef, 0xfc, 0x47, 0xaf, 0x9a, 0xba, 0xff, 0xa2, 0xee, 0x40, 0xad, 0xc6, 0x68, 0x56, 0x4c, 0x2d,\n\t0x09, 0xf7, 0x6f, 0x45, 0xe7, 0x33, 0x21, 0xdc, 0x44, 0x73, 0xcc, 0xf7, 0x08, 0x0d, 0xd1, 0x4e, 0xb6, 0x15, 0x35, 0x5a, 0x0d, 0x9a, 0x78, 0xb7, 0x84, 0x00, 0xa1, 0xc6, 0x39, 0x73, 0x72, 0x19, 0x29, 0x93, 0xa3, 0xea, 0xd0, 0x22, 0x9a, 0x01, 0x24, 0x29, 0x99, 0xa1, 0x33, 0xe9, 0x6e, 0x16, 0xb1, 0xa8, 0x74, 0x19, 0x8a, 0xeb, 0x1f, 0x7a, 0xac, 0x01, 0x3f, 0xa6, 0xfb, 0xe7, 0x5a, 0xe3, 0xfe, 0xb9, 0xd6, 0xcc, 0xff, 0x5c, 0x6b, 0xd6, 0x7f, 0xae, 0x35, 0xdb, 0x3f, 0xd7, 0x9a, 0xef, 0x9f, 0x6b, 0x2d, 0x8a, 0xe5, 0x0a, 0x78, 0x32, 0x76, 0x13, 0x72, 0x52, 0xbe, 0xbb, 0xfc, 0xe0, 0xd9, 0x9f, 0x29, 0xc6, 0xe7, 0xb9, 0x9d, 0xa6, 0x77, 0xcd, 0xf3, 0x88, 0x64, 0x5c, 0x11, 0xd3, 0x80, 0x2c, 0x76, 0x8b, 0x15, 0x65, 0xdf, 0x61, 0xf5, 0xa6, 0x3a, 0xfb, 0x2e, 0x37, 0x3b, 0xfb, 0xae,\n\t0x92, 0x30, 0x8c, 0x2b, 0x69, 0x88, 0x84, 0xdc, 0x0d, 0xa0, 0x78, 0x08, 0x86, 0xd3, 0x3b, 0x3b, 0xaf, 0x3d, 0x7e, 0xc5, 0x85, 0xcb, 0x2e, 0xc9, 0xb5, 0xdf, 0x39, 0x3d, 0x7e, 0x6c, 0x2a, 0xdf, 0xba, 0xeb, 0xee, 0x8d, 0xeb, 0xae, 0xca, 0x78, 0x0b, 0x0b, 0x6b, 0x91, 0x7c, 0x86, 0xd8, 0x09, 0xdf, 0x38, 0x52, 0xab, 0x71, 0x88, 0x7f, 0xff, 0xbd, 0xbd, 0xfe, 0xa5, 0x57, 0x9e, 0x7c, 0x60, 0xb8, 0xf7, 0xc6, 0xde, 0xb1, 0x9e, 0xcb, 0xbf, 0x79, 0xde, 0x25, 0xdf, 0xbb, 0x61, 0xa4, 0xbf, 0xfd, 0xef, 0xbd, 0xab, 0xf2, 0x66, 0xc4, 0x9e, 0x1a, 0x80, 0x1e, 0xb2, 0x27, 0x66, 0xf9, 0xec, 0xef, 0x58, 0x76, 0x17, 0x6e, 0xa6, 0xbf, 0x0b, 0x65, 0xf7, 0x22, 0x78, 0x5f, 0x74, 0x0d, 0xb8, 0x1a, 0x6a, 0x48, 0x9a, 0xc9, 0x38, 0x49, 0x19, 0xed, 0x03, 0x94, 0xcc, 0x0b, 0xd5, 0x20, 0x14, 0x3e,\n\t0xc9, 0x0c, 0x16, 0x00, 0xd3, 0xef, 0x3c, 0xcb, 0x65, 0x52, 0xbc, 0x3c, 0x2e, 0x6e, 0x58, 0x1f, 0x8a, 0x64, 0x41, 0x09, 0x8a, 0x98, 0xd7, 0x4a, 0x12, 0x48, 0x99, 0x57, 0x57, 0x78, 0xc8, 0xa7, 0xdf, 0x27, 0x32, 0x14, 0xee, 0x73, 0xbe, 0xcf, 0xfc, 0x39, 0xdf, 0x67, 0xfd, 0x9c, 0xef, 0xb3, 0x7d, 0xce, 0xf7, 0x39, 0x3e, 0xe7, 0xfb, 0xfc, 0x9f, 0xf3, 0x7d, 0x09, 0x1c, 0x02, 0x5a, 0x2a, 0x16, 0x3c, 0xcf, 0xfd, 0x25, 0x8a, 0x89, 0x6e, 0x2f, 0x06, 0xcb, 0x77, 0x56, 0x42, 0x88, 0xe6, 0x3c, 0x50, 0xbd, 0x35, 0xb5, 0xc5, 0xb6, 0x64, 0x3c, 0x1a, 0x0e, 0x60, 0xa1, 0xc7, 0x16, 0x67, 0xe6, 0xc9, 0x17, 0xf9, 0x3c, 0xba, 0x57, 0x33, 0xa0, 0xbf, 0xeb, 0x2e, 0x6e, 0x1a, 0xaa, 0x19, 0x4e, 0xea, 0x65, 0x0e, 0x8d, 0x36, 0xe5, 0x2b, 0xa6, 0xeb, 0x72, 0x6b, 0x7a, 0x22, 0x74, 0xae, 0xd1,\n\t0x9a, 0xe0, 0x66, 0xe9, 0x62, 0x0d, 0xeb, 0xfb, 0xa2, 0x74, 0xae, 0xc1, 0x96, 0x34, 0x55, 0x74, 0xb1, 0x93, 0xc9, 0xf6, 0x3d, 0x2b, 0x72, 0xac, 0x69, 0xc4, 0xae, 0xd3, 0x8d, 0x2d, 0x68, 0xe1, 0xf2, 0xeb, 0x4f, 0xfe, 0xfc, 0x36, 0x5f, 0xce, 0x54, 0xad, 0x96, 0x99, 0x1b, 0x36, 0xde, 0xf9, 0xcb, 0xdb, 0x7d, 0x8d, 0x26, 0xac, 0x96, 0x3d, 0xb2, 0xbd, 0x45, 0xf2, 0x93, 0xde, 0x7d, 0xfa, 0x6f, 0xe0, 0x35, 0x72, 0x87, 0x98, 0x73, 0x23, 0xd5, 0x30, 0xd9, 0x59, 0x55, 0xdd, 0xf4, 0x2c, 0x39, 0x37, 0x77, 0x3f, 0xee, 0xf2, 0xb5, 0xd8, 0xc2, 0x29, 0x6b, 0x4d, 0x5b, 0xcc, 0x4c, 0xee, 0x10, 0x46, 0x03, 0xc1, 0x3c, 0xe7, 0x36, 0xa9, 0x3c, 0x99, 0xde, 0x1a, 0x2c, 0x93, 0x3d, 0x26, 0xdc, 0x2b, 0xd3, 0xcb, 0xa1, 0xc0, 0x49, 0x34, 0x13, 0x8b, 0x8a, 0x0b, 0xea, 0x83, 0xa4, 0x52, 0x0e,\n\t0x06, 0x49, 0x15, 0xaa, 0xb5, 0xb0, 0x1b, 0xd1, 0x7f, 0x39, 0x85, 0x70, 0x6b, 0xe5, 0x72, 0x3b, 0x46, 0x9c, 0x75, 0x0c, 0xa9, 0x81, 0x52, 0x89, 0xad, 0xce, 0x6e, 0x7a, 0xd8, 0xe5, 0x02, 0x84, 0xab, 0xd9, 0xd5, 0xdc, 0xd4, 0x50, 0x9b, 0x4c, 0xc4, 0x50, 0xe9, 0x71, 0xab, 0x99, 0xd5, 0x2b, 0xe5, 0x50, 0x7c, 0x75, 0x6a, 0x64, 0x38, 0x98, 0xa2, 0x0a, 0x88, 0xaa, 0xb9, 0xac, 0x0e, 0x02, 0x2a, 0xc0, 0x61, 0x49, 0x04, 0xcd, 0x77, 0x05, 0xf5, 0x1d, 0x1b, 0x1c, 0x51, 0x15, 0x40, 0x5a, 0x66, 0xb2, 0xd4, 0x2c, 0xdc, 0xd1, 0xdb, 0xbb, 0x63, 0x61, 0x8d, 0xc5, 0xb4, 0x47, 0xcf, 0x17, 0xa2, 0xd1, 0x02, 0xaf, 0x27, 0xf7, 0xdd, 0xf6, 0xc3, 0xdd, 0xf7, 0xd2, 0x0a, 0x2e, 0x6a, 0x9a, 0xb9, 0x54, 0x5f, 0xe7, 0xfd, 0xd2, 0x29, 0x46, 0x6e, 0x8c, 0x9a, 0xc8, 0x2b, 0xf5, 0x69, 0xef, 0x97,\n\t0xe4, 0x64, 0xd0, 0x52, 0xbf, 0x20, 0xe7, 0x72, 0xe5, 0x16, 0xd4, 0x5b, 0x82, 0xa9, 0xf6, 0x08, 0xcb, 0x46, 0xda, 0x53, 0x7f, 0xbb, 0x77, 0x46, 0x00, 0x13, 0xd4, 0xff, 0x4d, 0x4e, 0xe6, 0xd3, 0x4b, 0x7c, 0x9f, 0x74, 0xd9, 0x63, 0xcc, 0xc9, 0x4f, 0x82, 0xc9, 0xc9, 0x42, 0x7a, 0xa9, 0x8f, 0x7a, 0xd6, 0x1e, 0xfb, 0x58, 0x0d, 0xe7, 0x20, 0x4c, 0x10, 0xf4, 0x5f, 0x98, 0x93, 0x90, 0xef, 0x05, 0x88, 0xee, 0x62, 0x07, 0x54, 0x27, 0xa0, 0x52, 0x81, 0xac, 0x12, 0xaa, 0x12, 0x58, 0x39, 0xdc, 0x55, 0x76, 0x8c, 0xf1, 0x41, 0xad, 0x82, 0x7b, 0xcb, 0x41, 0x0d, 0xeb, 0xb4, 0x48, 0x40, 0xc5, 0xc5, 0xd6, 0x51, 0xda, 0x9c, 0x45, 0x1b, 0xd0, 0x05, 0xd4, 0x4a, 0x42, 0x03, 0x34, 0x6a, 0x59, 0xa5, 0xfa, 0x27, 0xaa, 0xb3, 0x32, 0xab, 0xd0, 0x7a, 0x2e, 0x83, 0xca, 0x6f, 0x98, 0xc9, 0x8f,\n\t0x16, 0xef, 0xee, 0xe7, 0xf9, 0xbe, 0xdd, 0x8b, 0x85, 0x3f, 0x03, 0xcd, 0x55, 0x2f, 0xec, 0x6f, 0xee, 0xbe, 0xf2, 0xb9, 0x8b, 0x04, 0xdf, 0x07, 0x1f, 0xbc, 0x0e, 0x56, 0x08, 0x5f, 0x79, 0x20, 0xd8, 0xb1, 0x32, 0xdf, 0xb8, 0xb2, 0x8d, 0x17, 0xec, 0xe4, 0x0d, 0xcd, 0x9b, 0x8f, 0x2d, 0x9b, 0xbc, 0x6b, 0x77, 0x2b, 0x1d, 0xbd, 0xeb, 0x27, 0x3f, 0xb9, 0xeb, 0x8f, 0x68, 0x2f, 0xa0, 0xfe, 0xee, 0xc7, 0x76, 0xe4, 0x64, 0x31, 0x46, 0x23, 0xe1, 0x12, 0x17, 0x00, 0x41, 0x46, 0x17, 0x1c, 0x48, 0x67, 0x47, 0x87, 0xc5, 0x81, 0x85, 0x3f, 0x2d, 0xa1, 0xc5, 0x6e, 0x58, 0x56, 0x21, 0x73, 0x48, 0x15, 0xd7, 0x03, 0xb8, 0xe2, 0x3b, 0x6f, 0x06, 0xef, 0x82, 0xe5, 0xc2, 0x03, 0xa7, 0xde, 0x7f, 0x9f, 0x9a, 0xa6, 0x3f, 0x14, 0xba, 0xee, 0x9a, 0xd9, 0x42, 0x9e, 0xb8, 0x8b, 0x9c, 0xba, 0x5f,\n\t0xb2, 0x29, 0x0b, 0x5f, 0xa0, 0x1f, 0x87, 0x6d, 0xc4, 0x89, 0x67, 0x45, 0xeb, 0xa1, 0x0e, 0xa1, 0x12, 0x87, 0xa0, 0x22, 0xab, 0xc7, 0xc1, 0x66, 0xce, 0x59, 0x3f, 0x50, 0x38, 0x7f, 0xdb, 0x25, 0x01, 0x6a, 0xd3, 0x0c, 0x41, 0x4f, 0x42, 0x4d, 0x14, 0xc7, 0x39, 0xda, 0x51, 0x22, 0x83, 0xa3, 0x62, 0x35, 0x72, 0x63, 0xab, 0x51, 0x2d, 0xce, 0x4b, 0x25, 0x19, 0x8a, 0x21, 0xb1, 0x64, 0x37, 0xdf, 0x23, 0x25, 0x4b, 0x10, 0x7a, 0x02, 0xd2, 0x86, 0xb9, 0x37, 0x4b, 0xc5, 0x92, 0x67, 0x3d, 0x83, 0x91, 0x90, 0xd5, 0x2c, 0x6b, 0x8e, 0xfa, 0x4d, 0x51, 0xbf, 0x42, 0xe6, 0x9a, 0x1d, 0x15, 0x5b, 0x3e, 0xf1, 0x15, 0xcb, 0xbf, 0x1c, 0x7b, 0x45, 0x78, 0x70, 0x4d, 0xfb, 0x91, 0x25, 0xdb, 0x5e, 0xb8, 0x61, 0xd9, 0xc2, 0xa3, 0xaf, 0x5e, 0x30, 0xb5, 0x55, 0x43, 0x5a, 0xad, 0x6c, 0x73, 0x7a,\n\t0xe4, 0xe0, 0xea, 0x6c, 0x7e, 0xfd, 0x35, 0x8b, 0x13, 0xfd, 0x4d, 0x69, 0xf3, 0x29, 0x6a, 0x7a, 0x66, 0x27, 0xa5, 0xf7, 0x05, 0x5b, 0xae, 0x7d, 0xf3, 0xae, 0x5b, 0x7e, 0xff, 0xe5, 0xe5, 0xae, 0x4b, 0x8d, 0x56, 0x36, 0xb7, 0xe3, 0x81, 0xf3, 0x2f, 0xb9, 0x77, 0x2a, 0xae, 0x31, 0x39, 0xb4, 0x33, 0xc7, 0x98, 0x93, 0xf7, 0xc3, 0xb9, 0xd3, 0x0a, 0xf7, 0x2a, 0x0e, 0xc3, 0xb9, 0x2b, 0xa2, 0xdd, 0xd4, 0xe2, 0x25, 0x49, 0x78, 0xa2, 0x94, 0x40, 0x4e, 0x03, 0x52, 0x2d, 0x27, 0x27, 0x51, 0xa0, 0x37, 0xec, 0xae, 0x06, 0xa8, 0xd5, 0x60, 0x15, 0x83, 0x5c, 0xfd, 0x0e, 0xc4, 0x50, 0xdd, 0xd8, 0x26, 0x54, 0x24, 0x8a, 0x0d, 0xf9, 0xba, 0x14, 0x1b, 0x82, 0x1a, 0x1a, 0x1b, 0xe2, 0x03, 0x5a, 0x99, 0x3b, 0x1e, 0x62, 0x91, 0xa9, 0x84, 0xad, 0x2e, 0x5b, 0x8e, 0xb8, 0x2a, 0x3e, 0x38, 0x00,\n\t0x4b, 0xbe, 0x11, 0x20, 0xd9, 0xec, 0x9b, 0x01, 0xae, 0x68, 0x9e, 0xaf, 0x94, 0x34, 0x87, 0x72, 0x3d, 0x50, 0x1c, 0x0e, 0x7b, 0x0e, 0x14, 0x52, 0x5d, 0x26, 0xe1, 0x3e, 0x57, 0x77, 0xf6, 0xcb, 0xdf, 0xbd, 0x3b, 0xdb, 0xe3, 0x14, 0xee, 0x33, 0x75, 0xd5, 0x1e, 0x05, 0x77, 0xf8, 0x16, 0x64, 0xe2, 0x2d, 0x6e, 0x61, 0xeb, 0x7d, 0x7c, 0x23, 0x0b, 0x96, 0x7b, 0xbb, 0x12, 0x87, 0xbf, 0x7b, 0x24, 0xd1, 0xe5, 0x05, 0xcb, 0xd9, 0x46, 0xdf, 0xfd, 0xc2, 0x56, 0x77, 0x4b, 0xbc, 0x7e, 0xa1, 0x0f, 0x24, 0xef, 0x17, 0x5a, 0x5c, 0x7e, 0x30, 0x51, 0x13, 0x00, 0xef, 0xc5, 0x42, 0x33, 0xe7, 0x93, 0x47, 0x42, 0x31, 0xc1, 0x10, 0xa8, 0x21, 0xb7, 0x16, 0x3a, 0x0c, 0xfa, 0x86, 0x18, 0xd9, 0xc8, 0xbb, 0x05, 0x7b, 0xc2, 0x45, 0x6e, 0x9f, 0x39, 0xee, 0x4a, 0x80, 0xdf, 0xb8, 0xf9, 0x99, 0x7f,\n\t0x8d, 0x35, 0xe8, 0xd9, 0x62, 0x41, 0x68, 0x2d, 0xed, 0xa7, 0x7b, 0x99, 0x5b, 0xe1, 0x9c, 0x44, 0x50, 0x66, 0x78, 0x00, 0x90, 0x0c, 0x8e, 0xd9, 0x25, 0xe5, 0x0c, 0xf2, 0x63, 0xd1, 0xb4, 0x7d, 0x08, 0xd1, 0x18, 0xb0, 0x0a, 0xc5, 0x65, 0x55, 0x4d, 0x47, 0x84, 0x88, 0xc0, 0x79, 0x60, 0x23, 0x7c, 0x40, 0x29, 0x73, 0xce, 0x9e, 0x08, 0xaa, 0x5c, 0xbf, 0x7d, 0xce, 0x68, 0x99, 0x5b, 0xe1, 0x68, 0xc7, 0x7c, 0x71, 0x4e, 0x38, 0xa1, 0x75, 0xfa, 0x22, 0x8e, 0x07, 0x5e, 0x7f, 0xfd, 0xc6, 0x44, 0xbb, 0x1b, 0x6c, 0x31, 0x24, 0x7d, 0x4f, 0x08, 0xe3, 0xf6, 0x62, 0x38, 0x3f, 0x14, 0x00, 0x39, 0x69, 0x44, 0x7e, 0x1f, 0x49, 0x9a, 0x9c, 0xac, 0x7c, 0xe6, 0x7c, 0xe6, 0xe4, 0xcc, 0x71, 0x67, 0x0d, 0xf8, 0x83, 0x83, 0x9f, 0x79, 0x2a, 0x98, 0xd2, 0xe9, 0x3a, 0x1a, 0x85, 0xb6, 0x8a, 0x7f,\n\t0x65, 0x2f, 0xec, 0xbb, 0x1f, 0x55, 0xc3, 0x32, 0x01, 0x99, 0x1c, 0x72, 0x7f, 0x19, 0x39, 0x48, 0xc8, 0xd0, 0xc1, 0x93, 0x41, 0xea, 0x20, 0x87, 0x44, 0x44, 0x4e, 0xae, 0x57, 0x00, 0x74, 0xf6, 0x90, 0x16, 0xeb, 0x20, 0x86, 0x23, 0xe2, 0xb9, 0x33, 0xf9, 0x94, 0x70, 0x09, 0x79, 0xb8, 0xf7, 0x50, 0xc6, 0x3a, 0x8b, 0xa3, 0x2a, 0x50, 0xaf, 0x51, 0x1d, 0x31, 0x89, 0xdc, 0x01, 0x5c, 0x01, 0x85, 0xd9, 0xfb, 0x7c, 0x9b, 0x4f, 0x78, 0xde, 0x92, 0x4f, 0x9e, 0x38, 0xf8, 0xfa, 0xeb, 0x07, 0x4f, 0xf8, 0xd2, 0x16, 0xd0, 0xa1, 0x4b, 0xf9, 0x1e, 0x11, 0x2e, 0x49, 0x0e, 0x35, 0x0c, 0xf9, 0x3a, 0x49, 0x32, 0xec, 0x25, 0x85, 0xbf, 0x02, 0xa5, 0xd8, 0x55, 0x90, 0x16, 0xfe, 0x83, 0x86, 0x23, 0xf8, 0x83, 0xd3, 0x37, 0xf3, 0x54, 0xaf, 0x43, 0x57, 0x6c, 0x26, 0x24, 0xda, 0xc0, 0xdc, 0x0b,\n\t0xfb, 0x1a, 0x45, 0x11, 0x7d, 0x21, 0x00, 0x14, 0x38, 0xdd, 0x59, 0x0e, 0xa5, 0x15, 0x9a, 0x5a, 0x4f, 0xa0, 0x6a, 0x6f, 0x0a, 0x54, 0x93, 0x09, 0x75, 0x94, 0x14, 0x3b, 0xca, 0x7b, 0x79, 0xb1, 0xab, 0x11, 0x9f, 0x4a, 0xec, 0x6a, 0x65, 0x7a, 0x2b, 0x24, 0x6b, 0xee, 0x34, 0x33, 0xf7, 0x3e, 0x5f, 0x3d, 0xc5, 0x88, 0x72, 0x59, 0x84, 0xdf, 0x9e, 0x39, 0xd1, 0x95, 0xf9, 0x15, 0x09, 0xd8, 0xdf, 0x66, 0x4f, 0x31, 0xee, 0xb3, 0x9b, 0x20, 0x64, 0xdd, 0x18, 0x77, 0x14, 0xd2, 0x33, 0x1f, 0x00, 0xe2, 0xde, 0xc0, 0xb5, 0x19, 0x4a, 0x65, 0xb9, 0xe8, 0x72, 0x77, 0x23, 0x3c, 0xee, 0xaa, 0x1c, 0xee, 0x87, 0x59, 0x5d, 0x45, 0x4e, 0x74, 0xec, 0x88, 0xa8, 0x9a, 0x53, 0x59, 0xb7, 0xd4, 0x49, 0x87, 0x2f, 0xea, 0x78, 0xe0, 0xa7, 0xc2, 0x46, 0x72, 0xc7, 0x8d, 0x96, 0x10, 0xef, 0xd1, 0x83,\n\t0xcd, 0x86, 0x5a, 0x2f, 0xec, 0x63, 0x7a, 0x24, 0x3f, 0xec, 0xaf, 0xea, 0xe2, 0x1f, 0xbf, 0x3a, 0x73, 0x5c, 0xa6, 0x77, 0x9a, 0xc4, 0x2e, 0xf6, 0x3a, 0xf4, 0xb0, 0x87, 0x78, 0xef, 0xca, 0x78, 0x1c, 0x73, 0x95, 0x29, 0xa6, 0xa5, 0x5d, 0xbb, 0xbe, 0x6a, 0xd7, 0xae, 0x9c, 0xb3, 0x6b, 0x8d, 0x84, 0x51, 0x9c, 0xd1, 0x59, 0xbb, 0xb6, 0x5c, 0xe5, 0x27, 0xc3, 0xca, 0xf8, 0xb0, 0xe7, 0xd2, 0xdf, 0xcd, 0x70, 0xa7, 0x4e, 0x91, 0xef, 0xbe, 0x2e, 0x6d, 0x44, 0x84, 0x9c, 0x06, 0xd7, 0xf5, 0x6a, 0xf2, 0xe2, 0x8f, 0xd5, 0xe2, 0x9e, 0x93, 0xbf, 0x51, 0xa2, 0xf1, 0xa8, 0x4d, 0xc0, 0xe0, 0xd2, 0x4b, 0xf4, 0x38, 0xd4, 0x00, 0x50, 0xcb, 0xb8, 0x4d, 0x70, 0x26, 0x8d, 0xc7, 0x14, 0xbe, 0xd4, 0x94, 0xfc, 0x8d, 0x99, 0x1d, 0xaf, 0x8b, 0xed, 0x40, 0xd2, 0xf4, 0xb1, 0xba, 0xd2, 0x88, 0x78,\n\t0x26, 0x6f, 0x56, 0xb4, 0xc2, 0x36, 0x52, 0xc4, 0xcb, 0xa2, 0xa1, 0x49, 0x8f, 0x48, 0x7a, 0x04, 0x92, 0x74, 0xa3, 0x9e, 0x14, 0x89, 0xfc, 0xac, 0x5f, 0x44, 0x2a, 0x8f, 0x6e, 0x0c, 0x96, 0xa9, 0xb0, 0x4c, 0x86, 0x61, 0x4b, 0xec, 0x38, 0x19, 0xec, 0x0c, 0x32, 0x9f, 0x10, 0xb1, 0xb6, 0xe6, 0x50, 0xee, 0x39, 0xcf, 0xcc, 0xa2, 0xf3, 0xd1, 0xb3, 0xd1, 0xf9, 0xd9, 0x0f, 0x61, 0x42, 0xaf, 0x61, 0x31, 0xa5, 0xb7, 0x44, 0xfd, 0xe8, 0x8c, 0xcd, 0xa6, 0xf4, 0x6d, 0xe0, 0x2c, 0xb4, 0x1e, 0xfd, 0x9f, 0x31, 0x42, 0x6a, 0x7f, 0xce, 0xf3, 0x22, 0xb5, 0x9f, 0xdc, 0x4a, 0xca, 0x49, 0x48, 0xef, 0x8d, 0x4d, 0x75, 0x23, 0x57, 0xae, 0x91, 0xe8, 0x7d, 0x73, 0xda, 0xfc, 0xfa, 0xcc, 0xe0, 0x29, 0x7a, 0x3d, 0xa5, 0xe3, 0x25, 0x82, 0x7f, 0xcf, 0x72, 0x97, 0xaf, 0xdd, 0xc7, 0x5a, 0x0d, 0xb3,\n\t0x49, 0x3e, 0xfd, 0xe1, 0xc7, 0x6a, 0xe6, 0x24, 0x96, 0xa5, 0x56, 0x9e, 0x7e, 0x4f, 0x36, 0xc9, 0x3c, 0x04, 0x65, 0xb4, 0x71, 0xa0, 0x13, 0x27, 0xca, 0x10, 0x03, 0x34, 0xb5, 0xa8, 0xc8, 0x50, 0x32, 0xc2, 0x06, 0x37, 0x25, 0x35, 0x28, 0x89, 0xc4, 0xf0, 0x77, 0x66, 0xf6, 0xef, 0x73, 0x7e, 0x52, 0x50, 0x18, 0x56, 0x94, 0xc5, 0xe6, 0x3f, 0x39, 0x3c, 0x20, 0x72, 0x62, 0x12, 0xc5, 0x2b, 0x63, 0xe1, 0xd6, 0x87, 0xb2, 0xa1, 0x64, 0x32, 0xb1, 0x88, 0x13, 0x5f, 0x76, 0xc3, 0x7c, 0xc6, 0x8d, 0x01, 0x50, 0x12, 0xc8, 0xa3, 0x08, 0x83, 0x86, 0xa1, 0x51, 0x69, 0x03, 0xf1, 0x81, 0x12, 0x50, 0xfc, 0x19, 0xf7, 0x17, 0xeb, 0x3f, 0xe5, 0x56, 0x50, 0xbe, 0x13, 0xa1, 0xa6, 0x95, 0x1f, 0x42, 0x12, 0xb7, 0x6e, 0xf9, 0x68, 0x4d, 0x4d, 0x34, 0x68, 0x8d, 0x06, 0xc3, 0x09, 0x44, 0x55, 0x40,\n\t0xa9, 0x4a, 0x8d, 0xb8, 0x12, 0xd5, 0xd5, 0x06, 0x00, 0x29, 0x39, 0x11, 0x67, 0x7b, 0xc1, 0x4a, 0xd5, 0xba, 0xca, 0xe8, 0xa5, 0xc8, 0x7f, 0x8b, 0xb5, 0x4a, 0xec, 0x15, 0xfb, 0xa6, 0x25, 0x92, 0xf3, 0x8e, 0xad, 0x60, 0x23, 0xad, 0x09, 0x7f, 0x53, 0xcc, 0x46, 0x3e, 0xd4, 0x78, 0x59, 0x47, 0xd7, 0x89, 0xc1, 0x81, 0x7b, 0xc6, 0x6f, 0xf9, 0xdb, 0xd7, 0x27, 0x27, 0xbf, 0x0d, 0xf4, 0x0f, 0x55, 0x5c, 0x65, 0xbe, 0x68, 0x3e, 0xb8, 0xed, 0xf1, 0xcb, 0xfb, 0xfa, 0x0e, 0x3c, 0xbe, 0x2d, 0xdc, 0xe7, 0x0b, 0xb5, 0x25, 0xec, 0x4f, 0xdc, 0xbb, 0xf2, 0xe0, 0x58, 0x6c, 0xfb, 0xda, 0x48, 0xbf, 0xab, 0x65, 0xd8, 0x61, 0x0f, 0xd3, 0xe4, 0x7d, 0x23, 0x97, 0x4d, 0x2f, 0x74, 0x77, 0xfd, 0xe4, 0xaa, 0xc6, 0x73, 0x47, 0x73, 0x81, 0xc1, 0x5d, 0x33, 0x5e, 0xd6, 0xe0, 0x8f, 0x84, 0xc2, 0xe7,\n\t0xbc, 0x04, 0x74, 0x77, 0xdf, 0x0d, 0x74, 0x2f, 0x6d, 0xa3, 0x95, 0x1a, 0xe5, 0x62, 0x3e, 0xc3, 0xc8, 0x98, 0xa1, 0xeb, 0xbf, 0x7f, 0xf9, 0x95, 0xaf, 0x1d, 0x1d, 0x54, 0x28, 0x6a, 0xa6, 0xf7, 0x1d, 0x1f, 0x7b, 0xeb, 0x9d, 0xbe, 0xfd, 0x5f, 0x59, 0xf7, 0xa5, 0xd3, 0xc4, 0x84, 0x5a, 0xa9, 0x0f, 0xf0, 0xe8, 0x6c, 0x79, 0x84, 0x7b, 0xe9, 0x83, 0x70, 0x5f, 0xe8, 0xd0, 0xf9, 0xc5, 0x28, 0x67, 0x58, 0x68, 0xb6, 0x0f, 0x95, 0xea, 0x6b, 0x3a, 0x86, 0xc4, 0x2d, 0x0f, 0xbf, 0xeb, 0x08, 0x1d, 0x22, 0x16, 0xac, 0x5c, 0x66, 0x97, 0x44, 0xe1, 0x12, 0x45, 0x33, 0x93, 0xcf, 0xfc, 0x1f, 0xc8, 0xcd, 0xde, 0x11, 0xf2, 0xf4, 0x34, 0xfd, 0xdb, 0x8f, 0x9f, 0x15, 0x49, 0x05, 0xfd, 0xdb, 0xc7, 0x1f, 0x47, 0x6d, 0xe8, 0xe1, 0x11, 0x39, 0x0d, 0xdb, 0x70, 0x21, 0x6c, 0x0b, 0x17, 0xa7, 0xa2,\n\t0x20, 0xc5, 0x1c, 0xac, 0xc8, 0x83, 0x32, 0x50, 0x11, 0x05, 0x13, 0x7e, 0x1c, 0x8c, 0x87, 0xa8, 0x26, 0x10, 0x85, 0x40, 0x14, 0x9a, 0x05, 0x66, 0xb9, 0xfa, 0x11, 0xd9, 0x24, 0xdf, 0x47, 0x85, 0xb7, 0x7f, 0x8a, 0xaa, 0x8e, 0xcd, 0x7c, 0xf0, 0x6d, 0x97, 0x4f, 0x0b, 0x1a, 0x4c, 0x5e, 0xb5, 0xda, 0x65, 0x02, 0x05, 0xb5, 0xdf, 0xf9, 0xcc, 0xcc, 0x07, 0xa4, 0xff, 0x2e, 0xe1, 0x00, 0xb8, 0xfc, 0xae, 0x45, 0x54, 0xcc, 0x65, 0x16, 0x34, 0xfe, 0x06, 0xa7, 0xb3, 0xc1, 0x0f, 0xfe, 0x6c, 0xf4, 0x7e, 0x72, 0x4a, 0xc4, 0xf4, 0x85, 0x7c, 0x7e, 0x08, 0xf3, 0xca, 0xfa, 0x62, 0x8a, 0xb7, 0x73, 0x6a, 0x9a, 0xa1, 0x50, 0xa7, 0x28, 0xca, 0x8e, 0x55, 0x3e, 0x87, 0x54, 0xb8, 0xa2, 0x4c, 0x2c, 0xfd, 0x84, 0x3f, 0xea, 0x8f, 0xf2, 0x01, 0x34, 0xf8, 0x6a, 0x06, 0x2f, 0x09, 0x38, 0x4a, 0xb1,\n\t0x8f, 0x12, 0xf3, 0x81, 0x8c, 0x6b, 0x08, 0x92, 0xce, 0x25, 0x56, 0x97, 0x42, 0xb8, 0x5e, 0xa1, 0x16, 0x4e, 0xa8, 0x1c, 0xa6, 0x7f, 0x05, 0xbf, 0x13, 0x62, 0x3f, 0xb1, 0x5a, 0x14, 0x60, 0x9b, 0x42, 0x07, 0x96, 0x29, 0x2d, 0xec, 0xbf, 0x0b, 0x11, 0x70, 0x89, 0x44, 0x56, 0xed, 0x3a, 0x72, 0xc4, 0x6e, 0x9c, 0xf9, 0xbf, 0x3a, 0x3b, 0xf9, 0x4b, 0xf2, 0x69, 0x9d, 0x6e, 0xe6, 0xfb, 0x0e, 0x0b, 0x38, 0x6d, 0x30, 0xcc, 0x2c, 0x9a, 0xf9, 0x36, 0xe6, 0x3d, 0x90, 0xb6, 0xbf, 0x8f, 0x69, 0x7b, 0x5d, 0xb1, 0x16, 0x85, 0xfc, 0x50, 0xe3, 0x32, 0xdc, 0x59, 0x85, 0x9c, 0x64, 0x18, 0xb0, 0x92, 0xf8, 0x6c, 0xca, 0xce, 0xe3, 0x95, 0xe2, 0x45, 0xca, 0xfe, 0x3e, 0x5c, 0xae, 0x8f, 0x0f, 0x0b, 0x1b, 0x69, 0x35, 0xe4, 0x36, 0x4f, 0x9d, 0x92, 0x7a, 0x01, 0x19, 0xcb, 0x57, 0x3f, 0xfe, 0x26,\n\t0x22, 0x15, 0x62, 0x0c, 0xc0, 0xbd, 0x0c, 0x8a, 0xaf, 0x75, 0x20, 0x79, 0xc2, 0xaa, 0x20, 0x71, 0xd1, 0x68, 0x92, 0x82, 0xb2, 0x20, 0xb3, 0x53, 0x9c, 0x29, 0x34, 0x47, 0x73, 0xdb, 0x76, 0x10, 0x0e, 0xab, 0x99, 0x63, 0x67, 0x4d, 0x14, 0xab, 0x03, 0xb8, 0x3a, 0x29, 0x6b, 0xf2, 0x00, 0x9c, 0x1a, 0xc0, 0xac, 0x40, 0x9c, 0x65, 0xcf, 0xff, 0x79, 0xf6, 0x8e, 0x9d, 0x6d, 0xa7, 0x06, 0x4f, 0xbe, 0x7f, 0x5f, 0x99, 0xbd, 0x6c, 0xf0, 0xf8, 0xe9, 0xd4, 0xe4, 0x1d, 0xbb, 0xc0, 0x29, 0xa1, 0x66, 0xed, 0x05, 0x75, 0x5c, 0x8c, 0xbc, 0x13, 0xf5, 0x06, 0xf7, 0x07, 0xee, 0x23, 0x84, 0xcf, 0x67, 0x47, 0x9e, 0x15, 0x9b, 0x85, 0xa4, 0x19, 0x54, 0xac, 0x8a, 0x26, 0x07, 0x4b, 0x58, 0xc4, 0x90, 0xe5, 0xa0, 0x5e, 0xa1, 0xaa, 0x37, 0x48, 0xbf, 0x70, 0x0e, 0xe1, 0xee, 0xa0, 0x4e, 0xd9, 0x09,\n\t0x3b, 0xcb, 0x99, 0x59, 0x93, 0xa4, 0x5f, 0x04, 0x58, 0x94, 0xe8, 0x91, 0x93, 0x95, 0xd2, 0xe8, 0x50, 0xb9, 0x54, 0xd8, 0x2f, 0xfa, 0xb2, 0xd7, 0xcf, 0xdb, 0x71, 0x62, 0xf3, 0x23, 0xfb, 0x7b, 0x4f, 0xed, 0xbf, 0xfa, 0xc4, 0xf4, 0x7e, 0x1c, 0x77, 0xb7, 0xc1, 0xcb, 0x0a, 0x1f, 0x0a, 0x54, 0x64, 0xf2, 0xee, 0xbd, 0xa8, 0x4f, 0xfb, 0xf6, 0xcb, 0x40, 0x9b, 0xf0, 0x3d, 0x9d, 0x8f, 0xbc, 0xb3, 0x14, 0xff, 0xf4, 0x30, 0xec, 0x13, 0x87, 0xe2, 0xdf, 0xf4, 0x28, 0xe0, 0x09, 0x85, 0x49, 0x52, 0xa8, 0x7c, 0x13, 0x8a, 0xbb, 0x96, 0x36, 0x13, 0x18, 0x66, 0xad, 0x66, 0x23, 0x2d, 0xc3, 0x71, 0xbe, 0x1e, 0x0a, 0xc7, 0x5f, 0xd5, 0x02, 0x31, 0x5f, 0x1c, 0x5c, 0xb3, 0xfb, 0xc7, 0x5f, 0xbf, 0x71, 0xba, 0xe1, 0xf5, 0xb6, 0x23, 0xff, 0x7d, 0xef, 0xa9, 0x53, 0x54, 0xb3, 0x87, 0xc7, 0x13,\n\t0x20, 0xc4, 0xc0, 0xcf, 0xf0, 0x04, 0xcc, 0xac, 0x93, 0xe8, 0xb6, 0xfd, 0xf4, 0xfb, 0xb2, 0xe5, 0xcc, 0x63, 0x84, 0x8a, 0xe8, 0x26, 0x16, 0x14, 0x07, 0x9b, 0x00, 0x80, 0x2c, 0x0f, 0xf9, 0x5f, 0x4a, 0xd6, 0x2f, 0x85, 0x92, 0x84, 0x8a, 0x6a, 0x19, 0xe3, 0xf5, 0xff, 0xe1, 0xed, 0x3d, 0xe0, 0xdb, 0xaa, 0xce, 0xfe, 0xf1, 0x7b, 0xee, 0xd0, 0xde, 0xdb, 0x92, 0x65, 0x6b, 0x4b, 0x96, 0x65, 0x5b, 0xb6, 0x6c, 0xc9, 0xdb, 0xb2, 0xe3, 0x3d, 0x13, 0x6f, 0xc7, 0x76, 0x96, 0x13, 0x67, 0x39, 0x89, 0xe3, 0x0c, 0xb2, 0xc8, 0x26, 0x10, 0x32, 0x58, 0x01, 0xc2, 0x4a, 0x09, 0x23, 0x40, 0xc2, 0x08, 0x90, 0xb0, 0xc2, 0x48, 0x49, 0x4a, 0x0b, 0x94, 0xf6, 0x2d, 0x2d, 0xb4, 0x6f, 0x79, 0xcb, 0x5b, 0x0a, 0x1d, 0x6f, 0x29, 0x2d, 0xd0, 0xd2, 0x02, 0x89, 0x6f, 0x7e, 0xe7, 0x9c, 0x7b, 0x25, 0xcb,\n\t0x23, 0x8b, 0xf6, 0xff, 0xe7, 0x43, 0x12, 0xe9, 0xea, 0x9c, 0x73, 0xcf, 0x7c, 0xd6, 0xf9, 0x3e, 0xcf, 0x83, 0x54, 0x6e, 0x1b, 0xb2, 0x96, 0xe1, 0xbb, 0x35, 0xbb, 0x00, 0x4e, 0x44, 0xe5, 0xb4, 0x50, 0x76, 0x46, 0xba, 0xd3, 0x91, 0x6a, 0x4d, 0x32, 0xaa, 0x95, 0xd8, 0x27, 0x48, 0x22, 0x88, 0x85, 0x69, 0x45, 0x86, 0xe8, 0x38, 0x3c, 0x7d, 0x2c, 0x4e, 0xab, 0x81, 0xcf, 0xb4, 0x01, 0x48, 0x6f, 0xec, 0xea, 0xd3, 0x88, 0xc3, 0x1d, 0x21, 0xc8, 0x27, 0x73, 0x63, 0xfe, 0xa2, 0xdb, 0x7a, 0xe7, 0xde, 0x3d, 0x5c, 0x2d, 0xfb, 0x40, 0xb5, 0xf8, 0xe8, 0x9f, 0xf6, 0x6f, 0xff, 0xcd, 0xfd, 0xbd, 0xc9, 0xee, 0xf3, 0x4e, 0xa6, 0x66, 0xf3, 0xd3, 0x2b, 0x66, 0xef, 0x1e, 0xa8, 0x4a, 0x56, 0x9b, 0x45, 0xd1, 0xc8, 0x8e, 0x5b, 0xef, 0x69, 0xb9, 0xf9, 0x9f, 0xcf, 0x2f, 0x15, 0x88, 0x4a, 0x57,\n\t0x75, 0xe7, 0xaa, 0x75, 0x2b, 0x92, 0xb4, 0xca, 0xe6, 0x0a, 0x6a, 0xe6, 0xac, 0x7b, 0x96, 0x97, 0x14, 0x2f, 0xbb, 0x67, 0xce, 0xb6, 0x0f, 0xee, 0xef, 0xed, 0x7c, 0xf0, 0x6f, 0x77, 0x95, 0x05, 0xae, 0x7b, 0x73, 0xd7, 0xb4, 0x40, 0x6e, 0x40, 0x21, 0x9d, 0x5e, 0xda, 0x91, 0x67, 0x9a, 0xf5, 0x02, 0x50, 0x1c, 0x37, 0x14, 0xcc, 0x41, 0xc6, 0x0c, 0x3d, 0x93, 0x22, 0x55, 0x64, 0xa6, 0x16, 0x65, 0xa2, 0xb9, 0x60, 0x8f, 0xf1, 0x73, 0x51, 0x45, 0xb4, 0x46, 0x5b, 0x8a, 0xf8, 0xb9, 0xc8, 0xf0, 0x93, 0x02, 0x94, 0x82, 0xf1, 0x72, 0x13, 0x82, 0x54, 0x31, 0x2b, 0x9a, 0x90, 0xaa, 0xca, 0xdc, 0x9c, 0xc0, 0x77, 0x98, 0x10, 0xc0, 0x47, 0x66, 0xfd, 0xce, 0x33, 0xd2, 0xf7, 0xd7, 0x1d, 0x67, 0xb7, 0xbc, 0x77, 0xa8, 0x8f, 0xb9, 0x8a, 0x09, 0x59, 0x38, 0xa8, 0x40, 0x5e, 0x46, 0x8a, 0xa5,\n\t0xcf, 0xb1, 0x0f, 0x4c, 0x9a, 0x13, 0x24, 0x27, 0xdd, 0xcd, 0xa4, 0xc1, 0xbd, 0x12, 0x24, 0xae, 0xe5, 0xef, 0xeb, 0xa0, 0x2c, 0x24, 0x50, 0x01, 0x2e, 0x12, 0x78, 0xec, 0x0b, 0x19, 0xbf, 0xaf, 0x4b, 0x25, 0x04, 0x04, 0x45, 0x0b, 0x28, 0x14, 0x6a, 0x07, 0x51, 0x60, 0x9a, 0x36, 0x8f, 0x99, 0xbb, 0xac, 0x04, 0x4e, 0x28, 0x05, 0x8f, 0x15, 0x8d, 0x2c, 0x38, 0x93, 0x4b, 0xc6, 0x0c, 0x5d, 0x56, 0x94, 0xd2, 0x5b, 0x8a, 0xd4, 0x1f, 0xa8, 0xcc, 0x66, 0x60, 0x5d, 0x16, 0x0a, 0xb5, 0xcc, 0xd4, 0x9a, 0xac, 0x7d, 0xbc, 0x2e, 0x44, 0x8d, 0x58, 0x1c, 0x65, 0x9b, 0x56, 0xcc, 0xaa, 0xf2, 0x36, 0xee, 0x79, 0x63, 0xc3, 0xbc, 0x21, 0x19, 0x96, 0x6f, 0xa0, 0x3e, 0x3b, 0x2b, 0xb7, 0xe9, 0xda, 0x43, 0x33, 0xd8, 0x0f, 0x13, 0x75, 0x22, 0xaa, 0xd5, 0x67, 0x14, 0x24, 0xe7, 0xb5, 0xae, 0xba,\n\t0x67, 0x60, 0xff, 0x47, 0xf7, 0xb6, 0x5b, 0xb6, 0x68, 0x0c, 0xaa, 0x9c, 0xc1, 0x43, 0x43, 0x3b, 0x1e, 0xe8, 0x49, 0x4d, 0x54, 0x8b, 0xb0, 0x0f, 0xe0, 0xb7, 0x90, 0x76, 0x7d, 0x82, 0x69, 0xd7, 0x62, 0x4e, 0x96, 0x70, 0xc1, 0xfe, 0xf2, 0x56, 0x07, 0x2c, 0x99, 0x82, 0x5e, 0x4e, 0x1a, 0xc6, 0x5f, 0x70, 0x58, 0x1f, 0x3c, 0x62, 0xdf, 0x58, 0x31, 0x22, 0xfe, 0x33, 0x16, 0x24, 0x9c, 0xe3, 0x8b, 0xf6, 0x40, 0x99, 0x13, 0x13, 0x3b, 0x83, 0xc3, 0xc3, 0xcb, 0xb4, 0x6e, 0x6c, 0x2e, 0xb2, 0x4b, 0x48, 0x34, 0x72, 0x2e, 0x39, 0xb6, 0x19, 0x68, 0xed, 0x6a, 0xe6, 0x93, 0xbb, 0x7e, 0x3a, 0xf2, 0x7d, 0xb6, 0x48, 0x91, 0x5d, 0xd9, 0xb9, 0x70, 0x6d, 0xc5, 0xda, 0x1a, 0x4f, 0x53, 0x4d, 0x79, 0xae, 0x5b, 0x42, 0xcd, 0x7f, 0x04, 0x59, 0x7d, 0xe8, 0xaf, 0xd8, 0xcf, 0xd8, 0x21, 0xf6, 0xe3,\n\t0x13, 0x83, 0x6e, 0xff, 0xf5, 0xd6, 0xde, 0x63, 0xc0, 0x02, 0xee, 0x05, 0xa9, 0xe7, 0xa4, 0xbc, 0x3e, 0x7a, 0x80, 0xa9, 0x83, 0xe3, 0xb0, 0x12, 0x8f, 0x70, 0x98, 0x21, 0x11, 0xf6, 0x73, 0xb0, 0x9c, 0xe4, 0x7c, 0x2a, 0xf8, 0x95, 0xb4, 0xf1, 0xeb, 0x33, 0x17, 0x73, 0x83, 0xa9, 0x96, 0x32, 0x6e, 0xb9, 0x1c, 0xb7, 0x9e, 0xe3, 0xca, 0x27, 0x2c, 0x28, 0xb6, 0x5c, 0x8e, 0x2f, 0xc9, 0x5b, 0x30, 0x13, 0x2a, 0xa0, 0xdc, 0x23, 0x38, 0x86, 0x91, 0x95, 0xb0, 0x22, 0x09, 0xd7, 0xa1, 0x73, 0x23, 0x6e, 0x03, 0xd4, 0x93, 0x56, 0x3e, 0x2e, 0xe7, 0x33, 0x75, 0x45, 0xab, 0x8f, 0xae, 0x88, 0xdb, 0x2d, 0xa2, 0xf3, 0x2a, 0x9d, 0x31, 0xa9, 0xff, 0xdb, 0x5f, 0x8e, 0x3c, 0xb3, 0x31, 0x9a, 0xbc, 0x05, 0x0a, 0xae, 0xa9, 0xd5, 0x2b, 0x67, 0x90, 0x49, 0x63, 0x1a, 0x00, 0xaf, 0x97, 0x0b, 0x10,\n\t0xce, 0x54, 0x39, 0x59, 0xb7, 0xe1, 0xd6, 0x11, 0x69, 0x38, 0xb1, 0xb5, 0xe1, 0x52, 0x6f, 0x70, 0x1c, 0x50, 0x8d, 0x39, 0x20, 0xb7, 0x32, 0x63, 0x8a, 0x4d, 0x3a, 0x5a, 0x91, 0x98, 0x62, 0x83, 0x16, 0x61, 0x9c, 0x5a, 0x83, 0x79, 0xdf, 0x31, 0xcc, 0x6b, 0x30, 0xef, 0x4b, 0x92, 0x90, 0x14, 0x72, 0x39, 0xa3, 0xe0, 0x94, 0x50, 0xe4, 0x30, 0xce, 0x34, 0x86, 0x25, 0x16, 0x8c, 0x93, 0x4e, 0x90, 0x90, 0xe0, 0x76, 0x40, 0xac, 0x8f, 0x97, 0x90, 0x9c, 0x1c, 0xf7, 0x0b, 0x4d, 0xe0, 0x7e, 0xf4, 0xd6, 0x3f, 0x43, 0xe6, 0xfb, 0xab, 0x04, 0xe6, 0x87, 0xf8, 0x0c, 0xfb, 0x67, 0xab, 0x03, 0x9c, 0x07, 0xa7, 0x26, 0xb3, 0xbf, 0xd8, 0xf8, 0x85, 0xb0, 0x83, 0x84, 0x0b, 0xd9, 0x25, 0x92, 0x95, 0x90, 0xed, 0x21, 0x5e, 0x4c, 0x0b, 0x68, 0x52, 0x30, 0xcc, 0x24, 0x4c, 0x03, 0x46, 0x34, 0x8d,\n\t0x4d, 0x83, 0x8b, 0x70, 0xa5, 0xdb, 0xf5, 0xe1, 0xc4, 0xfd, 0x89, 0x2e, 0x56, 0x71, 0x5a, 0xcf, 0x84, 0xfc, 0x99, 0x38, 0xdb, 0x1d, 0x67, 0xd3, 0x14, 0xae, 0x87, 0x53, 0x73, 0x84, 0x22, 0x59, 0x47, 0x52, 0x6e, 0x4a, 0xae, 0x89, 0x4d, 0x12, 0x9c, 0x3a, 0x94, 0x9c, 0xaa, 0x00, 0xbf, 0x55, 0x98, 0xa4, 0xfa, 0x64, 0xf0, 0x4b, 0x79, 0x6a, 0xf2, 0x21, 0x3c, 0x63, 0x14, 0x6b, 0xcc, 0xb5, 0x9c, 0xbf, 0x2d, 0x3b, 0x9b, 0x1a, 0xce, 0xcf, 0x3e, 0x4f, 0x32, 0xf7, 0x4a, 0x93, 0xce, 0x3f, 0x64, 0x2e, 0xb4, 0x16, 0x45, 0xa8, 0xde, 0x24, 0x29, 0xc7, 0xb3, 0x49, 0xa2, 0xed, 0xc2, 0x17, 0x4c, 0x13, 0xa6, 0xd3, 0xb9, 0x97, 0xcc, 0x7b, 0x65, 0x8b, 0x5f, 0xd6, 0xd8, 0x11, 0x40, 0x38, 0x27, 0x88, 0x12, 0x83, 0x59, 0x92, 0x78, 0x92, 0x2c, 0x42, 0x24, 0x39, 0x16, 0x2e, 0x95, 0xbb, 0x38,\n\t0x05, 0x08, 0x28, 0x99, 0x90, 0x96, 0x8d, 0xc3, 0x55, 0xd1, 0x58, 0x26, 0xb3, 0xc7, 0x29, 0xf0, 0xb9, 0xd1, 0xc8, 0x8e, 0x5b, 0xee, 0x6d, 0x39, 0x70, 0xfe, 0xf9, 0x85, 0x7d, 0x4f, 0x7e, 0x73, 0xdf, 0xf6, 0xff, 0x39, 0xdc, 0x2b, 0x50, 0x26, 0x69, 0xa9, 0x0f, 0x31, 0x31, 0x8e, 0x0e, 0xb6, 0x55, 0xe4, 0xa6, 0x6b, 0x20, 0x39, 0x26, 0x6b, 0x63, 0x74, 0x97, 0xdc, 0x5d, 0xd2, 0x99, 0x67, 0x9a, 0xff, 0x3a, 0xfb, 0xbb, 0x17, 0x6f, 0x67, 0xd9, 0x57, 0x97, 0x23, 0x1a, 0x9c, 0x9a, 0x66, 0x92, 0x40, 0x2a, 0x5c, 0xa9, 0x4f, 0x75, 0xa5, 0xea, 0x15, 0x78, 0x7f, 0x04, 0x2f, 0x7c, 0x41, 0x97, 0xc3, 0xf5, 0xc8, 0x41, 0x91, 0xcb, 0xb2, 0x20, 0xe7, 0xf1, 0x42, 0x96, 0xaf, 0xc4, 0x71, 0x94, 0x08, 0x14, 0x66, 0x9e, 0x8b, 0x87, 0x4d, 0xa3, 0x78, 0xd8, 0xbc, 0xdb, 0x30, 0xde, 0x30, 0xa0,\n\t0x8f, 0xc0, 0x9a, 0x10, 0xd4, 0x07, 0xb3, 0x7c, 0x2a, 0x81, 0xc0, 0x3c, 0x16, 0x29, 0x33, 0x06, 0x14, 0x33, 0x18, 0x39, 0x3e, 0xc3, 0xa7, 0xbd, 0x40, 0xcb, 0x15, 0x8b, 0x8d, 0xb9, 0x60, 0xcb, 0xc9, 0x55, 0x79, 0xbd, 0x77, 0xbf, 0xbd, 0xb2, 0xee, 0xc6, 0x8d, 0x8b, 0xd3, 0x5a, 0xa5, 0x5a, 0x81, 0x4c, 0xa7, 0x55, 0xe5, 0x35, 0xcd, 0x2f, 0x6b, 0xdf, 0xda, 0x9d, 0xe1, 0x69, 0xdf, 0x3d, 0x70, 0x4c, 0xa1, 0x06, 0x1b, 0x46, 0x87, 0xa8, 0x57, 0xa4, 0x06, 0x6a, 0x1d, 0x53, 0x3e, 0xb4, 0x7f, 0xc6, 0xea, 0x97, 0xb6, 0x57, 0xa7, 0x14, 0xb4, 0xe6, 0xcd, 0x92, 0xd1, 0x22, 0x95, 0x26, 0xe0, 0x35, 0xe7, 0x74, 0x0e, 0x97, 0x45, 0xfa, 0x2b, 0xbd, 0x7d, 0x6a, 0x97, 0x1a, 0xac, 0x7c, 0xa2, 0x45, 0x93, 0xa6, 0x83, 0xba, 0x6b, 0x0f, 0x5c, 0xa7, 0x4f, 0x99, 0xc7, 0xe1, 0x6c, 0xeb, 0x89,\n\t0xb4, 0x8b, 0xc4, 0x7a, 0xb1, 0xc5, 0x03, 0x98, 0xdb, 0x99, 0x46, 0xa3, 0x01, 0x79, 0x18, 0xdb, 0x53, 0x0d, 0x69, 0xc6, 0x34, 0xa9, 0x5e, 0xaa, 0xe7, 0x57, 0x4a, 0x8c, 0x56, 0x8a, 0xf7, 0x30, 0xe6, 0xf3, 0x19, 0x0b, 0x01, 0x0f, 0x6b, 0x15, 0xc0, 0xd5, 0x71, 0x79, 0x38, 0x35, 0x0a, 0xe4, 0x89, 0x9b, 0xb6, 0x3e, 0xb9, 0x78, 0xf1, 0x93, 0x5b, 0x9a, 0xc4, 0xa4, 0xac, 0x65, 0xf3, 0xd1, 0x85, 0x83, 0x47, 0xb7, 0x4c, 0x97, 0x81, 0x4f, 0xef, 0x07, 0x82, 0x97, 0x17, 0x2e, 0x7c, 0x99, 0xfd, 0xf6, 0xfe, 0xef, 0xb1, 0xdf, 0x9c, 0x5a, 0xb4, 0xe8, 0x14, 0x10, 0x92, 0x37, 0xae, 0x7c, 0x76, 0x53, 0x79, 0xf9, 0xa6, 0x67, 0x57, 0x1e, 0x5e, 0x7a, 0x74, 0x6d, 0x29, 0xc2, 0xb7, 0x90, 0xdb, 0x96, 0x9d, 0x61, 0xbf, 0xbc, 0xff, 0x30, 0xfb, 0xf7, 0x33, 0x43, 0x43, 0x67, 0x80, 0xfc, 0xf0,\n\t0xfd, 0x40, 0x71, 0x66, 0x19, 0x77, 0x4e, 0x68, 0x23, 0xb6, 0x91, 0x43, 0x5d, 0x83, 0x89, 0xe5, 0x56, 0x9f, 0x52, 0x9d, 0x91, 0x11, 0x32, 0xa4, 0xcd, 0x08, 0x90, 0x54, 0x96, 0xa0, 0xcd, 0xe8, 0xc1, 0xf5, 0x48, 0x97, 0xf9, 0x14, 0x99, 0x9b, 0xcf, 0x3d, 0xc3, 0x49, 0xa5, 0x9c, 0xbd, 0xd4, 0xcd, 0x1e, 0xc0, 0xf6, 0x6c, 0x07, 0xf1, 0x63, 0x7c, 0xcd, 0x79, 0x52, 0x09, 0x10, 0x59, 0xb0, 0xa0, 0x7f, 0x19, 0x10, 0x8b, 0x94, 0x9b, 0x0e, 0x29, 0xb3, 0x90, 0xd3, 0x6c, 0x50, 0x06, 0x3c, 0x71, 0x0f, 0x21, 0x16, 0xe3, 0xb5, 0xc7, 0x42, 0x87, 0xb9, 0x21, 0xae, 0xf4, 0x5a, 0xa9, 0x18, 0x59, 0x86, 0xca, 0xab, 0x00, 0x41, 0x83, 0x86, 0x2f, 0x53, 0x35, 0xa6, 0xd3, 0xa2, 0x9a, 0xd1, 0xac, 0xc9, 0x95, 0x20, 0x5d, 0x84, 0xd2, 0xf9, 0xec, 0xa9, 0xea, 0xe2, 0x58, 0xfd, 0x3a, 0x4e, 0x8f,\n\t0x41, 0xc1, 0x39, 0xb4, 0x76, 0xb7, 0x1b, 0x12, 0x47, 0x19, 0xd2, 0x79, 0xb1, 0xb9, 0x3d, 0x34, 0x45, 0xb0, 0x11, 0xfb, 0x98, 0x09, 0xbe, 0x93, 0x3d, 0xfa, 0x2b, 0x6b, 0xf9, 0xc2, 0x7a, 0x7f, 0x63, 0x86, 0x52, 0x68, 0x96, 0xc9, 0x33, 0x6d, 0xd1, 0x20, 0x3b, 0xfa, 0xe5, 0x97, 0xbc, 0x51, 0x9e, 0x55, 0x7d, 0x5b, 0xb6, 0xb0, 0x3e, 0x4d, 0xa3, 0x9d, 0x6e, 0x52, 0x2a, 0x3b, 0x9b, 0x8a, 0x79, 0x13, 0x3d, 0xd2, 0xb3, 0x0e, 0x30, 0xfd, 0x58, 0x26, 0x79, 0x9a, 0x9b, 0x1e, 0x79, 0x96, 0xd7, 0x9e, 0x44, 0x0b, 0x19, 0x31, 0x2f, 0x96, 0x24, 0x7c, 0x27, 0xe3, 0xd1, 0x86, 0x53, 0x38, 0x9d, 0x10, 0xd1, 0x74, 0xaa, 0x0f, 0xa9, 0x1a, 0x53, 0x72, 0x33, 0x77, 0xec, 0x76, 0x6d, 0x72, 0xe9, 0x71, 0xbc, 0xcc, 0x31, 0xe1, 0x16, 0x6e, 0x52, 0x71, 0x2a, 0xc6, 0xc9, 0x82, 0x44, 0x10, 0x2a,\n\t0x79, 0x4e, 0x38, 0x37, 0x98, 0x6b, 0x4c, 0x15, 0xb0, 0xed, 0x52, 0x3a, 0x5f, 0x7f, 0xec, 0xd6, 0x4d, 0x68, 0x86, 0x42, 0x19, 0x9c, 0xa1, 0x4d, 0x97, 0x57, 0x00, 0x37, 0x3d, 0xfc, 0x2e, 0xba, 0x6d, 0x8b, 0xcf, 0xdc, 0x25, 0x14, 0xc1, 0x17, 0xd1, 0x7d, 0x30, 0x3c, 0x81, 0x05, 0x70, 0x3e, 0x6d, 0x08, 0x99, 0x64, 0x80, 0xfb, 0x8f, 0xc1, 0xf3, 0x06, 0x75, 0x41, 0x21, 0x82, 0x73, 0x92, 0xf3, 0x38, 0x66, 0x00, 0x38, 0x23, 0x24, 0x32, 0x49, 0x43, 0xb9, 0xcc, 0x86, 0xa4, 0x32, 0x7b, 0x62, 0xd7, 0x11, 0x49, 0x89, 0xf7, 0x1e, 0xf9, 0x3f, 0xc3, 0x2d, 0xc0, 0x14, 0xfc, 0x22, 0xb1, 0xbb, 0x6f, 0x80, 0x67, 0xd8, 0xfb, 0xc1, 0x7c, 0x76, 0xd6, 0x2f, 0x8c, 0x7a, 0xbe, 0xcb, 0x9a, 0x94, 0xb7, 0xd9, 0x4e, 0xb0, 0x88, 0x3d, 0x92, 0xd0, 0xc9, 0xfd, 0x87, 0xc9, 0x65, 0xb1, 0x5e, 0xda,\n\t0x46, 0x6f, 0x3b, 0x0c, 0x27, 0x38, 0x82, 0x28, 0x20, 0x3e, 0x83, 0x16, 0x1c, 0x91, 0x89, 0xf7, 0xfb, 0xe5, 0xb8, 0x35, 0x0e, 0xcb, 0xd2, 0xc7, 0x69, 0xfb, 0x72, 0x39, 0x41, 0xc8, 0x2d, 0x72, 0x8b, 0xd9, 0xa4, 0x52, 0xc0, 0xd2, 0x52, 0xbb, 0x10, 0x52, 0x0f, 0xb7, 0x3a, 0x6e, 0x56, 0x81, 0x3b, 0x93, 0x27, 0xef, 0x90, 0x31, 0x51, 0x99, 0xbf, 0x9e, 0xb1, 0xb1, 0xcd, 0x9f, 0xd6, 0xba, 0xb1, 0x0d, 0x3c, 0xc5, 0xce, 0xb8, 0xf1, 0xc7, 0xbb, 0xca, 0xab, 0x6f, 0x78, 0x7b, 0xe7, 0xaf, 0x0f, 0x93, 0xf5, 0x81, 0x96, 0xe5, 0xe5, 0x15, 0x4b, 0x1a, 0xd2, 0xe8, 0x73, 0xdf, 0xce, 0x8f, 0xae, 0x3d, 0xb2, 0x60, 0xc1, 0x63, 0x1b, 0x2a, 0x49, 0x25, 0xe6, 0x3f, 0x91, 0x0b, 0x5f, 0x31, 0x5f, 0xc1, 0xbe, 0xa8, 0x88, 0x32, 0x30, 0x70, 0x32, 0x05, 0x40, 0x75, 0x80, 0x77, 0x0b, 0x71, 0x89,\n\t0x01, 0x0a, 0x94, 0x2a, 0x84, 0x7a, 0x1a, 0x8d, 0x8e, 0x10, 0x8d, 0x6d, 0x46, 0x48, 0xa7, 0x8d, 0xb9, 0xb9, 0xdb, 0xc9, 0xd8, 0x4d, 0xf8, 0xe5, 0xcb, 0x3a, 0xe3, 0x69, 0xb3, 0xae, 0xb4, 0x5d, 0xf3, 0x55, 0xb4, 0x9b, 0x7c, 0x15, 0xed, 0x7a, 0xae, 0xb8, 0xdd, 0x68, 0xe6, 0x45, 0x8a, 0xc5, 0x1d, 0xfd, 0x9d, 0xe8, 0x9e, 0x3a, 0x5e, 0x81, 0xbf, 0xa5, 0xb6, 0xa8, 0xd5, 0x80, 0x50, 0x97, 0xa9, 0x4b, 0x43, 0xd9, 0xe8, 0x3a, 0xd5, 0x61, 0x4b, 0x36, 0x4b, 0xc5, 0x84, 0x0a, 0xa8, 0x24, 0x82, 0x31, 0x04, 0x3e, 0x27, 0xf7, 0x31, 0x63, 0x61, 0xa0, 0xc7, 0x58, 0x35, 0xbe, 0xfc, 0x19, 0x0b, 0xf4, 0x82, 0xcc, 0x66, 0x64, 0x3b, 0x5a, 0x5a, 0x6f, 0xfd, 0xa2, 0x8a, 0xd2, 0x79, 0x95, 0x2e, 0xf2, 0x71, 0x46, 0x22, 0x64, 0xb2, 0xba, 0xb7, 0xb7, 0x0e, 0xdd, 0xec, 0x28, 0x7c, 0x7b, 0xe7,\n\t0xe0, 0x43, 0xab, 0x4b, 0xf1, 0x52, 0xbf, 0xd7, 0x50, 0x1f, 0x28, 0x71, 0xab, 0x19, 0x21, 0xe3, 0xb1, 0x93, 0x9f, 0x06, 0xa6, 0x2f, 0xaf, 0x28, 0x5f, 0xda, 0xe8, 0x77, 0x96, 0x76, 0x85, 0xc0, 0xc0, 0x66, 0x67, 0x4d, 0x45, 0x91, 0x61, 0xe6, 0xbe, 0xb9, 0xa1, 0x59, 0xbd, 0xd3, 0xe7, 0x95, 0x5f, 0xf3, 0xf0, 0xc0, 0xc2, 0x63, 0x1b, 0xe1, 0x2e, 0x38, 0xf7, 0xda, 0xd0, 0x6c, 0x6b, 0x64, 0x7a, 0x28, 0xb5, 0x28, 0xe4, 0x93, 0xa5, 0x7a, 0x70, 0xbe, 0x79, 0xc8, 0xeb, 0xde, 0x67, 0x8e, 0x11, 0xb5, 0x44, 0x43, 0xb4, 0xd6, 0x0f, 0x69, 0x77, 0x1e, 0xce, 0xed, 0x07, 0x37, 0x2d, 0x0a, 0xa8, 0x81, 0xe2, 0x96, 0x03, 0x01, 0x40, 0x40, 0x79, 0x48, 0x53, 0x85, 0x24, 0x36, 0xee, 0x63, 0xae, 0x67, 0x8b, 0x03, 0xe5, 0xed, 0x58, 0xb8, 0xaa, 0x25, 0x6a, 0x52, 0xdd, 0x4e, 0x9f, 0xdd, 0x97,\n\t0x86, 0xe5, 0xde, 0x44, 0xaf, 0x47, 0x3e, 0x63, 0xd5, 0x98, 0x4d, 0x97, 0xcb, 0x4f, 0x3a, 0x2e, 0xe6, 0x6c, 0x0a, 0x69, 0xe4, 0xf0, 0x9d, 0x68, 0x06, 0x98, 0x53, 0x78, 0xcc, 0x3d, 0xdb, 0x5a, 0x5b, 0x6f, 0x98, 0x1b, 0x76, 0xd5, 0x0f, 0x37, 0xbc, 0x71, 0x0a, 0xa1, 0x83, 0xbd, 0x75, 0x4b, 0x2b, 0x5b, 0x56, 0x34, 0x87, 0x34, 0x6a, 0x83, 0x24, 0xb7, 0xf5, 0x83, 0xdd, 0xc3, 0x27, 0x36, 0x57, 0x2e, 0x9c, 0x7d, 0xed, 0x2a, 0x9d, 0xb7, 0xc0, 0xdd, 0x53, 0x23, 0x10, 0x08, 0x3c, 0x0e, 0x72, 0x71, 0x7c, 0xe8, 0x99, 0xb3, 0x6e, 0x9d, 0xdf, 0x3a, 0x52, 0x6b, 0x7f, 0xca, 0x1a, 0x99, 0x91, 0x9b, 0xd5, 0x1c, 0x49, 0xb5, 0xa7, 0xd9, 0x55, 0xea, 0x05, 0xb5, 0x4d, 0x91, 0x79, 0x37, 0xcc, 0x58, 0xf2, 0x60, 0x30, 0xf3, 0xad, 0x43, 0x45, 0x2d, 0x39, 0x66, 0x7a, 0xe5, 0x60, 0x7c, 0x3a,\n\t0x50, 0x9e, 0x32, 0xc8, 0x33, 0x4f, 0x60, 0x3f, 0x97, 0xda, 0x68, 0x95, 0x13, 0xd0, 0x82, 0x4c, 0x84, 0xd1, 0xac, 0x47, 0xb8, 0x4c, 0x9a, 0x41, 0x72, 0x0c, 0x81, 0x92, 0x0a, 0x0f, 0xc4, 0x0c, 0x09, 0x36, 0xee, 0x36, 0xa1, 0x67, 0xbc, 0xd9, 0x27, 0x87, 0xc8, 0xf1, 0x68, 0x7d, 0x76, 0xf7, 0x84, 0xcb, 0x04, 0x3c, 0x13, 0xde, 0x4b, 0xce, 0x84, 0x15, 0xd0, 0x27, 0x10, 0xc3, 0x75, 0xd6, 0xad, 0x68, 0x78, 0x03, 0x24, 0x8c, 0xba, 0x29, 0xa4, 0x55, 0x1b, 0xc4, 0xb9, 0x33, 0xd0, 0xa8, 0xb7, 0x54, 0x2e, 0x99, 0x3b, 0xbc, 0x83, 0x37, 0x12, 0x81, 0x6b, 0xa6, 0xaf, 0xac, 0x99, 0x7a, 0x90, 0x4b, 0x1f, 0xce, 0x4a, 0x7f, 0xfa, 0xc6, 0xcf, 0x38, 0x1d, 0xf0, 0xc2, 0xdf, 0x04, 0xff, 0x07, 0xcf, 0x7e, 0x1e, 0xb1, 0x90, 0x07, 0xa0, 0xa0, 0x85, 0xa5, 0x00, 0xca, 0xca, 0xc2, 0x87, 0xdd,\n\t0x49, 0xe2, 0x13, 0x3b, 0xa1, 0x4b, 0x1b, 0x3b, 0xe2, 0x15, 0xfe, 0x29, 0x8a, 0x10, 0xf1, 0x12, 0x5c, 0xb0, 0x3b, 0xbe, 0x30, 0xa7, 0x01, 0xe6, 0x11, 0xb9, 0x6e, 0xa8, 0x02, 0xea, 0xd3, 0x44, 0xe3, 0x85, 0xb9, 0xbc, 0x29, 0x14, 0x41, 0x5d, 0x2c, 0x04, 0x1b, 0x5e, 0x72, 0xc1, 0x4f, 0xf0, 0x92, 0xcf, 0xdc, 0xd1, 0xd1, 0xb4, 0xb5, 0x2f, 0x67, 0x2a, 0xf5, 0x50, 0xe3, 0xca, 0x75, 0x74, 0x56, 0x73, 0xdb, 0x7d, 0x21, 0x5c, 0xe4, 0x42, 0xc3, 0xcc, 0xfd, 0x73, 0x43, 0x19, 0xdd, 0xdb, 0x3b, 0xa9, 0xc7, 0xa6, 0xd4, 0x19, 0x8f, 0x87, 0xeb, 0x33, 0x74, 0xc3, 0x83, 0xa9, 0xc5, 0x68, 0x71, 0xdd, 0x58, 0x6f, 0xb8, 0xf0, 0xb9, 0x30, 0x08, 0xe7, 0xc0, 0x4f, 0x2c, 0xe2, 0x54, 0x45, 0xe7, 0xd8, 0xf6, 0xa6, 0x09, 0x74, 0xd9, 0x3b, 0x97, 0xc1, 0xa6, 0x3c, 0xbc, 0xb5, 0xe3, 0xd3, 0xe0,\n\t0xbd, 0x58, 0x29, 0x2c, 0x41, 0x8d, 0x9d, 0x02, 0x8e, 0x6d, 0xfa, 0x89, 0x34, 0x37, 0x4e, 0xbc, 0x30, 0xe9, 0x20, 0x24, 0xe8, 0x5c, 0xe3, 0x07, 0x2f, 0xd4, 0x73, 0x83, 0xdf, 0xd9, 0xde, 0xbc, 0xa5, 0x2f, 0x87, 0xd7, 0xc4, 0x34, 0xae, 0x3c, 0x38, 0x5e, 0x6e, 0x53, 0x2f, 0x8a, 0x6f, 0xea, 0x40, 0xf7, 0x8e, 0x4e, 0x50, 0x18, 0x57, 0xcf, 0x9e, 0x0e, 0x37, 0x64, 0xe8, 0x12, 0x36, 0x30, 0x40, 0xf7, 0x19, 0xcc, 0x49, 0x28, 0xbb, 0xe6, 0x10, 0x79, 0xd1, 0x1c, 0x3d, 0xf6, 0xa9, 0x41, 0x19, 0xad, 0x90, 0x05, 0x08, 0xc1, 0x8a, 0xf1, 0xa5, 0x8d, 0x2d, 0x9e, 0x57, 0xd7, 0x1e, 0xdb, 0xae, 0x2e, 0x5f, 0xc0, 0xe7, 0xc6, 0x9a, 0x1a, 0xd7, 0xdd, 0x98, 0x68, 0x1a, 0xb3, 0xf0, 0xf3, 0xe2, 0x6b, 0x9c, 0x9a, 0xe1, 0xd4, 0x1a, 0xcc, 0xc9, 0xee, 0x07, 0xff, 0x78, 0xf3, 0xa3, 0xec, 0x67,\n\t0x67, 0x96, 0x2e, 0x3c, 0x0d, 0xd4, 0x47, 0x3b, 0x6f, 0xdb, 0xbc, 0x34, 0xa3, 0x58, 0x91, 0x69, 0xb1, 0x94, 0x75, 0xae, 0x69, 0x59, 0xf3, 0xea, 0xae, 0xda, 0xa6, 0xfd, 0x6f, 0x5d, 0x3b, 0xff, 0xbe, 0xa1, 0x02, 0xf6, 0x39, 0x7d, 0x12, 0x79, 0xea, 0xfa, 0x1b, 0x7e, 0x79, 0x47, 0x0b, 0x36, 0xcd, 0x3f, 0x08, 0x94, 0xdf, 0x5f, 0x8a, 0xf2, 0xe9, 0xcd, 0x31, 0xca, 0xd4, 0x4a, 0x9f, 0xc3, 0xd4, 0x74, 0xf3, 0xdb, 0x9b, 0xaf, 0xfb, 0xd9, 0xcd, 0x8d, 0xd9, 0x73, 0xf6, 0xf7, 0x9b, 0x34, 0xeb, 0x39, 0x3d, 0x37, 0xf9, 0xc2, 0x57, 0xf4, 0x03, 0x58, 0xcf, 0xfb, 0x96, 0x63, 0x53, 0xa9, 0xb1, 0x00, 0xfc, 0xe8, 0xbe, 0x96, 0xe9, 0xe1, 0x8d, 0xe5, 0x7c, 0x6c, 0x2d, 0x7b, 0xdc, 0x8d, 0xf1, 0x92, 0xc5, 0x9c, 0x71, 0x7f, 0xc6, 0x2b, 0x68, 0xcd, 0x7c, 0x65, 0xad, 0x25, 0x5f, 0x49, 0x6b,\n\t0x97, 0x6d, 0x88, 0xe3, 0x28, 0x0a, 0x4e, 0x53, 0xd5, 0x7b, 0xe1, 0x36, 0xe2, 0x16, 0x64, 0xc2, 0x59, 0x29, 0xc2, 0x7b, 0x8a, 0x07, 0xf9, 0xdb, 0xf3, 0xe8, 0x1d, 0x6c, 0x7e, 0xc2, 0x5e, 0x59, 0x86, 0xb6, 0xd2, 0xf3, 0x47, 0xd1, 0x46, 0x62, 0xc3, 0xcc, 0xbd, 0xcf, 0x9c, 0x5f, 0x34, 0x6e, 0x8b, 0xe0, 0x8d, 0xf4, 0xdc, 0x0f, 0xd0, 0x36, 0xa2, 0x0e, 0x3e, 0x83, 0xe2, 0x95, 0x40, 0xdd, 0x6d, 0x84, 0x79, 0x82, 0xa8, 0x46, 0x71, 0x90, 0x93, 0xe1, 0x69, 0x57, 0x22, 0xbf, 0x87, 0xfa, 0x8b, 0xf8, 0x49, 0x0d, 0xc4, 0xee, 0xfd, 0xc6, 0x91, 0xff, 0xaa, 0x69, 0x25, 0x45, 0xa1, 0xec, 0x60, 0xa6, 0xc7, 0x65, 0x4f, 0x35, 0x9b, 0xb0, 0x82, 0x9a, 0xe0, 0x2a, 0x15, 0x89, 0xe1, 0x61, 0x0d, 0x13, 0xaf, 0x8a, 0x70, 0x12, 0xe3, 0xb1, 0x4d, 0x85, 0x25, 0x4b, 0x23, 0x3d, 0x92, 0xb5, 0x66,\n\t0xd7, 0x1d, 0x2d, 0x03, 0x2f, 0xdd, 0xd4, 0xe9, 0xad, 0x5d, 0x18, 0xad, 0x9c, 0x5d, 0x68, 0xae, 0xb9, 0xfe, 0xf5, 0x4d, 0x77, 0x7f, 0xd8, 0x12, 0x54, 0x24, 0x4b, 0x35, 0x39, 0xad, 0xeb, 0x7b, 0x1a, 0x57, 0xd4, 0x3a, 0x33, 0x5a, 0x57, 0xd7, 0x7e, 0x3a, 0xda, 0xb9, 0xb9, 0x35, 0x0d, 0x12, 0x8d, 0xf6, 0xc6, 0xe5, 0x4d, 0xd9, 0x4a, 0x91, 0x46, 0xa2, 0x91, 0xff, 0xb4, 0xb8, 0x3d, 0x2f, 0xa9, 0x60, 0xf9, 0x03, 0x8b, 0x4b, 0x56, 0xf4, 0xd7, 0x99, 0x74, 0xa5, 0x8d, 0x5d, 0x19, 0x8d, 0x7b, 0x16, 0x97, 0x76, 0xd5, 0xb5, 0x99, 0x64, 0x36, 0x8f, 0xcd, 0x59, 0xd4, 0x92, 0x1e, 0x6a, 0x09, 0x5b, 0xee, 0xce, 0xa8, 0xed, 0x0b, 0x16, 0x0e, 0xd4, 0xf9, 0x53, 0xd3, 0x03, 0x32, 0x91, 0x58, 0xc1, 0xdb, 0xc9, 0x0e, 0x30, 0x1f, 0x60, 0xfc, 0xcc, 0xb7, 0x9c, 0x4e, 0x23, 0xe6, 0xed, 0x4b,\n\t0xe2, 0x98, 0x7d, 0xc9, 0x86, 0xd1, 0x32, 0x34, 0x2d, 0xec, 0x21, 0x10, 0xba, 0x0a, 0x5f, 0xbc, 0x51, 0xbd, 0xcc, 0x54, 0x42, 0xb9, 0x03, 0xa3, 0x65, 0xc6, 0xc0, 0x71, 0x53, 0x55, 0x49, 0x94, 0xcc, 0x39, 0x31, 0x3e, 0x8f, 0x00, 0x0c, 0xc9, 0x4c, 0x51, 0x03, 0x69, 0x6e, 0x66, 0xee, 0x33, 0xe6, 0xbf, 0xce, 0xf1, 0x62, 0x7d, 0x4e, 0xbc, 0x5e, 0x1c, 0x5c, 0x77, 0xe9, 0xea, 0x5c, 0x00, 0x61, 0x14, 0x53, 0x28, 0x9d, 0x48, 0x47, 0x66, 0x3b, 0xa4, 0x04, 0x49, 0xa0, 0x68, 0xec, 0x9e, 0x52, 0xf7, 0x99, 0xc2, 0x90, 0xf7, 0xc1, 0x64, 0x15, 0x68, 0x4a, 0xb3, 0xde, 0x2f, 0xc6, 0x89, 0xf4, 0x17, 0x37, 0xf0, 0x91, 0xc4, 0x6e, 0xc8, 0x7b, 0x4f, 0xc1, 0xf9, 0xb7, 0x10, 0x85, 0x09, 0xb8, 0xb6, 0x18, 0xa0, 0x0d, 0xe1, 0xdb, 0x08, 0x4e, 0x55, 0xb1, 0x5c, 0x0c, 0xd7, 0x56, 0x98, 0x5c,\n\t0x58, 0x10, 0xf9, 0x8f, 0xe0, 0xda, 0x62, 0x26, 0x20, 0x6a, 0xfa, 0x94, 0xb0, 0x36, 0xf0, 0xe1, 0x81, 0x17, 0x56, 0x1d, 0xa3, 0x69, 0x89, 0x56, 0xc2, 0x66, 0x48, 0x5d, 0xc6, 0xb5, 0x67, 0x68, 0x5a, 0xa7, 0x05, 0x3f, 0x97, 0xba, 0x8d, 0x6b, 0x99, 0x7b, 0x5d, 0x86, 0x9c, 0xe9, 0x05, 0xa9, 0xa9, 0x05, 0xd3, 0x11, 0xaa, 0xad, 0xdc, 0xa7, 0xd1, 0xf8, 0xca, 0xb3, 0xbe, 0xfd, 0x9a, 0x55, 0x83, 0x5e, 0xf2, 0xa0, 0x2e, 0x3b, 0x49, 0xef, 0x56, 0x8c, 0xee, 0xd0, 0xd8, 0xa8, 0x6f, 0x46, 0x17, 0xea, 0xb2, 0x4d, 0x01, 0x0b, 0xb9, 0x59, 0x6d, 0x3b, 0x7f, 0x2f, 0x67, 0x23, 0x0a, 0x10, 0x04, 0xf5, 0x3b, 0x5a, 0x42, 0x48, 0xe0, 0xc1, 0xba, 0x28, 0xae, 0xcd, 0x32, 0x0e, 0xd7, 0x26, 0x93, 0x02, 0x22, 0x8e, 0x6a, 0x33, 0x1a, 0x74, 0x52, 0xbb, 0xcc, 0x0e, 0xc7, 0x2d, 0x01, 0x12, 0x0e,\n\t0xd7, 0x16, 0xe6, 0x44, 0x30, 0xb5, 0x76, 0x22, 0xac, 0x0d, 0x79, 0xcd, 0x90, 0x43, 0x0b, 0x06, 0x0c, 0xc1, 0xa6, 0xfc, 0x9f, 0xfe, 0x74, 0xf1, 0x2d, 0xdd, 0xde, 0xec, 0xd9, 0x7b, 0x67, 0xb2, 0xab, 0x4f, 0x9c, 0x78, 0xe9, 0x83, 0x0f, 0x6e, 0x9a, 0xdb, 0xe0, 0x28, 0xc9, 0xb0, 0xb0, 0x4f, 0x80, 0x8f, 0x42, 0x1d, 0x2b, 0x8a, 0xab, 0xd6, 0xb4, 0x67, 0x51, 0x60, 0xdf, 0xa6, 0x4d, 0xfb, 0x6e, 0xe1, 0xe2, 0xb7, 0xc2, 0xf7, 0x6f, 0xc4, 0xfe, 0x17, 0x53, 0xe3, 0xd9, 0x2c, 0x17, 0xc5, 0xb3, 0xa1, 0x20, 0x9d, 0x71, 0x3c, 0xdb, 0x43, 0x3f, 0xff, 0xf9, 0x99, 0x13, 0x27, 0xc8, 0xbb, 0xa9, 0xf9, 0xec, 0xa7, 0xfb, 0xd8, 0x52, 0xf0, 0xfa, 0x3e, 0xf0, 0xd8, 0x01, 0x02, 0xfb, 0x4c, 0x1c, 0xa0, 0xee, 0x81, 0xed, 0x07, 0x10, 0x96, 0x0d, 0x67, 0x23, 0xa1, 0x00, 0x03, 0xd2, 0x80, 0x80,\n\t0x31, 0x68, 0x49, 0x64, 0x59, 0xb2, 0x8c, 0x7f, 0x42, 0x63, 0x9c, 0x43, 0x00, 0x1b, 0xb7, 0x01, 0xce, 0xb0, 0x86, 0x6e, 0x39, 0x84, 0x3d, 0xdc, 0x76, 0xc1, 0x16, 0x03, 0xa4, 0xde, 0x62, 0xfb, 0x9a, 0x95, 0x8c, 0x39, 0x7a, 0xd9, 0x63, 0x65, 0x51, 0xa8, 0x59, 0x14, 0x70, 0x7b, 0x42, 0x1d, 0xce, 0x4b, 0x87, 0x12, 0xd0, 0x02, 0x0a, 0xc1, 0xaf, 0xf9, 0x76, 0x69, 0x82, 0xa4, 0xa7, 0x28, 0xca, 0xeb, 0xcd, 0x01, 0x22, 0xa0, 0xf5, 0x39, 0x8c, 0x3e, 0x27, 0xb6, 0xb6, 0x22, 0xf2, 0x3d, 0x1e, 0x4a, 0x3d, 0x19, 0xe5, 0x80, 0xef, 0xbe, 0x28, 0x27, 0x9b, 0x96, 0xb5, 0xbc, 0xaa, 0xeb, 0x86, 0xfe, 0xec, 0x92, 0xa5, 0xb7, 0x76, 0x78, 0xea, 0xd3, 0x28, 0x01, 0x09, 0x2b, 0xc9, 0x3c, 0xd6, 0x60, 0x6b, 0xb1, 0xdd, 0x5e, 0xd2, 0x91, 0x5b, 0xd4, 0x68, 0x3d, 0x43, 0x7d, 0x7d, 0x80, 0x3d,\n\t0xec, 0xf2, 0x96, 0xae, 0x7e, 0x64, 0xf1, 0x9a, 0x53, 0x3b, 0x6a, 0xc4, 0xd2, 0x14, 0x4f, 0x8a, 0x5a, 0x27, 0xf1, 0xb4, 0x5f, 0x3f, 0xa7, 0xe7, 0x9a, 0xda, 0x14, 0x87, 0x9e, 0x45, 0xab, 0x02, 0x08, 0x23, 0xfb, 0xb0, 0x60, 0x0f, 0xf5, 0x0d, 0x51, 0x86, 0x76, 0x51, 0xd1, 0x94, 0x78, 0x36, 0xcb, 0x45, 0xf0, 0x6c, 0x65, 0x44, 0x59, 0x24, 0xef, 0xe2, 0x78, 0x36, 0x2a, 0x01, 0xcf, 0x46, 0x4d, 0xc4, 0xb3, 0x69, 0xe3, 0x78, 0x36, 0x14, 0x57, 0x28, 0x8e, 0x3c, 0xd2, 0x0a, 0xf6, 0xa4, 0x9a, 0xd7, 0x95, 0xe7, 0x45, 0x54, 0x2f, 0x19, 0xab, 0x32, 0xe6, 0xbc, 0x3a, 0x27, 0xa3, 0xca, 0xf8, 0xa2, 0x3a, 0x92, 0x7b, 0x3d, 0xa0, 0xcc, 0xe5, 0x41, 0x77, 0x9e, 0x91, 0x65, 0xef, 0x4e, 0xce, 0x94, 0xbf, 0xa3, 0x2b, 0xf6, 0xb7, 0xbe, 0x3a, 0xbd, 0x2d, 0xed, 0x1d, 0x45, 0x66, 0xf2, 0x5d,\n\t0x2c, 0x6b, 0xca, 0x75, 0x07, 0xcb, 0xcd, 0x8f, 0x1e, 0x60, 0x9b, 0x92, 0x6d, 0xa0, 0xd7, 0xee, 0x04, 0x21, 0x8f, 0x87, 0x2d, 0x06, 0x67, 0xe1, 0xdf, 0xef, 0x38, 0xed, 0xe0, 0xa1, 0x40, 0xbe, 0x42, 0x9e, 0xe5, 0x01, 0x5b, 0xad, 0x26, 0xf6, 0x0d, 0xbb, 0x03, 0x3c, 0xcb, 0x36, 0x4d, 0x03, 0x85, 0x26, 0x2b, 0xbb, 0xd5, 0x13, 0x94, 0x2b, 0x22, 0x01, 0xf6, 0x73, 0x4e, 0x8e, 0x40, 0x74, 0x65, 0x08, 0xce, 0x8a, 0x1b, 0xd9, 0xcb, 0xb1, 0xef, 0x59, 0x3d, 0x21, 0x24, 0x68, 0x38, 0x1b, 0x03, 0x28, 0x4c, 0x9a, 0x05, 0x33, 0xe1, 0xbe, 0x38, 0x49, 0x86, 0xdb, 0xc3, 0xae, 0x46, 0x03, 0x37, 0xc5, 0xd0, 0x88, 0x63, 0xe3, 0x08, 0x4d, 0x9e, 0x07, 0xee, 0x0a, 0x87, 0xfc, 0x9b, 0x32, 0x07, 0x76, 0xf9, 0x82, 0x29, 0xd7, 0x13, 0xac, 0x30, 0x3f, 0xf2, 0x43, 0x3c, 0xdc, 0x02, 0x1d, 0x1a,\n\t0xee, 0xe2, 0x33, 0x67, 0xfa, 0xfc, 0x45, 0x7a, 0xea, 0x8c, 0x31, 0x65, 0xac, 0x67, 0xdc, 0x90, 0xe0, 0x20, 0xf0, 0x90, 0xa8, 0x6f, 0xd8, 0x66, 0x07, 0xc6, 0x20, 0xec, 0xbe, 0x70, 0x81, 0x2e, 0x87, 0x7d, 0x75, 0x22, 0xdb, 0xb6, 0x1e, 0x30, 0x02, 0x1b, 0x20, 0x21, 0x09, 0x40, 0xc8, 0x9e, 0x38, 0xa2, 0x48, 0x40, 0xa0, 0xac, 0x10, 0xf0, 0xac, 0xd1, 0xb4, 0xa5, 0x81, 0xe2, 0xac, 0x1b, 0x1e, 0x7c, 0xc2, 0x8c, 0x63, 0xd6, 0x0d, 0x6a, 0x1c, 0x74, 0x0d, 0x9e, 0xf6, 0x30, 0xb7, 0x22, 0x14, 0x37, 0x12, 0xba, 0x7c, 0x57, 0xee, 0x34, 0xe9, 0x9d, 0xca, 0x42, 0xe7, 0x75, 0x0b, 0xce, 0x9c, 0x59, 0x70, 0x5d, 0x24, 0xe9, 0x31, 0x49, 0x7e, 0xf2, 0xc1, 0xdf, 0xe8, 0xe0, 0x94, 0x47, 0x8d, 0x29, 0x1e, 0x10, 0xb2, 0xbb, 0x18, 0x76, 0x14, 0x30, 0x5c, 0xe7, 0x3e, 0xfd, 0x83, 0x3c, 0x1b,\n\t0x14, 0x9a, 0x2d, 0xec, 0x56, 0x6f, 0x96, 0x5c, 0x11, 0xce, 0xc0, 0xf3, 0x1a, 0x80, 0x7d, 0xed, 0x86, 0x7d, 0xf5, 0x20, 0xdc, 0x9a, 0xf3, 0x12, 0xb8, 0x35, 0x4b, 0x0c, 0x08, 0x96, 0x6a, 0xe5, 0x71, 0x6b, 0xee, 0x31, 0xdc, 0x5a, 0x7c, 0x3f, 0xc5, 0x69, 0x12, 0x9a, 0xcf, 0xc4, 0xdd, 0x43, 0x77, 0x5f, 0x9f, 0x5b, 0xa8, 0x7b, 0x11, 0x4e, 0xe5, 0x12, 0x48, 0x2c, 0xce, 0x9c, 0x3a, 0x85, 0xa6, 0xf3, 0x1d, 0x6e, 0xbe, 0x8d, 0x79, 0x68, 0x8b, 0xc4, 0xe7, 0x91, 0xdc, 0xb7, 0x64, 0xc9, 0xbe, 0x53, 0x0e, 0x3b, 0x28, 0xc4, 0x93, 0x0d, 0xfb, 0x9a, 0x1f, 0xe0, 0x65, 0xc9, 0x0b, 0xf4, 0x7b, 0xb0, 0xaf, 0x36, 0x44, 0xaf, 0xac, 0x53, 0xe3, 0xd5, 0xe2, 0xdd, 0x44, 0x17, 0x78, 0xb0, 0x8b, 0x71, 0xbc, 0x5a, 0xac, 0x8b, 0x1c, 0x5e, 0x6d, 0x42, 0xe7, 0xde, 0x1b, 0xeb, 0x1c, 0xfb, 0x1a,\n\t0x49, 0x5f, 0xbc, 0x6f, 0x03, 0x77, 0xa0, 0x45, 0x1e, 0xd7, 0x33, 0x6e, 0x6f, 0x22, 0x3a, 0x37, 0x09, 0xa7, 0x66, 0xf9, 0x8e, 0x38, 0x35, 0xfa, 0x1e, 0x5b, 0xd2, 0xba, 0x77, 0xd8, 0xac, 0x33, 0x67, 0xc0, 0xcf, 0xce, 0xf2, 0x27, 0x07, 0xfc, 0x82, 0x0d, 0x50, 0x5f, 0xb3, 0xc3, 0xe0, 0x66, 0xc8, 0x66, 0xe0, 0x3b, 0xa1, 0xf8, 0xf9, 0x3c, 0xa6, 0xdd, 0x28, 0xb7, 0x5f, 0x22, 0x4e, 0x4d, 0xc0, 0x6f, 0x29, 0xee, 0x9a, 0x5e, 0x9d, 0x80, 0x3f, 0x49, 0x78, 0x87, 0x9d, 0x79, 0x9e, 0xf5, 0x9f, 0xe5, 0xde, 0x80, 0x28, 0xf7, 0xf9, 0x7b, 0xc7, 0xda, 0xe7, 0xcf, 0xdb, 0x01, 0x41, 0x16, 0x6c, 0x3f, 0x48, 0x3c, 0xcf, 0x91, 0x59, 0x0c, 0x3b, 0xf6, 0x41, 0xc1, 0x52, 0x95, 0x88, 0x43, 0xe6, 0x1f, 0x50, 0x09, 0x94, 0x7b, 0x02, 0xda, 0xcc, 0x32, 0x35, 0x42, 0x8d, 0xa3, 0xdc, 0x7c, 0x59,\n\t0x14, 0x62, 0x07, 0xaa, 0x39, 0xb3, 0x27, 0xd4, 0x61, 0xae, 0x00, 0x97, 0x66, 0x99, 0x8c, 0x4b, 0x33, 0x4e, 0x81, 0x4b, 0xf3, 0x5c, 0x1a, 0x98, 0x46, 0x7d, 0x94, 0xb5, 0xbc, 0x92, 0x27, 0xdb, 0xed, 0x9e, 0x06, 0x1f, 0x29, 0xa0, 0x10, 0xd9, 0x76, 0x73, 0x64, 0xbb, 0xb8, 0x33, 0xd7, 0x1a, 0xf4, 0xda, 0x94, 0x68, 0xbe, 0xa8, 0x6e, 0x52, 0xe0, 0xbc, 0x28, 0xe9, 0x16, 0xab, 0x74, 0x12, 0x48, 0xbc, 0xe1, 0x74, 0xc2, 0xa9, 0xe3, 0x7c, 0x2f, 0xa1, 0x6c, 0x7e, 0x0c, 0xfb, 0x5e, 0x36, 0xa3, 0xb8, 0xd3, 0x28, 0xbb, 0x7b, 0x35, 0x45, 0x0a, 0x08, 0x0d, 0x46, 0x9f, 0x4d, 0x02, 0x8e, 0x39, 0x26, 0x20, 0xcc, 0x1a, 0xeb, 0x7d, 0xbe, 0x7c, 0x87, 0xde, 0xe7, 0x72, 0xf9, 0x38, 0x38, 0x97, 0x01, 0xa3, 0xb9, 0x90, 0x7b, 0x4f, 0x22, 0x96, 0x8b, 0x4c, 0x94, 0xce, 0x91, 0x47, 0x5e, 0x02,\n\t0x8e, 0x6b, 0x2c, 0x33, 0x3a, 0xdc, 0xec, 0x38, 0x94, 0x25, 0x0a, 0xb8, 0xfb, 0x5a, 0x79, 0x61, 0x41, 0x51, 0x59, 0x51, 0x41, 0x31, 0xf8, 0x8b, 0xb5, 0x3e, 0xad, 0x6a, 0x73, 0x41, 0xc1, 0xc6, 0x8a, 0x81, 0xc7, 0xb7, 0xd5, 0x97, 0x6d, 0x7c, 0x76, 0x8d, 0xb3, 0xca, 0x29, 0x65, 0x52, 0x92, 0x64, 0x29, 0x8a, 0xda, 0xe5, 0xf5, 0x9e, 0x8c, 0xb6, 0x75, 0x0d, 0x6a, 0x9b, 0xaa, 0xba, 0x39, 0xbd, 0x79, 0x79, 0x65, 0xe5, 0xca, 0x19, 0x19, 0xa0, 0x1f, 0xca, 0xdf, 0x49, 0x36, 0x95, 0xcd, 0xca, 0x80, 0x7f, 0xf6, 0xdd, 0x11, 0x0a, 0xdd, 0xda, 0xdd, 0x31, 0xb7, 0x7f, 0xf4, 0x15, 0xb1, 0xc4, 0x6a, 0x31, 0x5b, 0x63, 0x11, 0x10, 0x24, 0xd2, 0x56, 0x9b, 0x0e, 0x50, 0xb9, 0x73, 0x6e, 0xec, 0xec, 0xd9, 0x37, 0x2f, 0x97, 0x22, 0xab, 0x4e, 0xad, 0x6a, 0xde, 0xd0, 0x9e, 0x1e, 0xec, 0xba,\n\t0xa6, 0x66, 0xf1, 0x2b, 0xb5, 0x32, 0x01, 0x89, 0xe3, 0x21, 0x98, 0xd9, 0x87, 0xa9, 0xff, 0x81, 0x93, 0x35, 0x01, 0xaf, 0x65, 0xb9, 0x5a, 0xbc, 0x56, 0xff, 0x4b, 0xa9, 0x49, 0xeb, 0xdf, 0x61, 0xb7, 0x51, 0xaf, 0x53, 0xf3, 0x47, 0x83, 0xdc, 0x91, 0xa1, 0xe6, 0x1f, 0x38, 0xc0, 0xe5, 0x06, 0x3c, 0x46, 0x7d, 0x8d, 0x73, 0x56, 0x5a, 0xa3, 0x66, 0x29, 0x45, 0xe0, 0x7c, 0xe7, 0x68, 0x82, 0x2d, 0xfc, 0x99, 0x4c, 0x77, 0xa8, 0x29, 0x81, 0x11, 0x59, 0x6a, 0xd5, 0xe3, 0x83, 0xea, 0x15, 0x01, 0x72, 0xf0, 0x2c, 0xbb, 0xfc, 0xb0, 0xd1, 0x2a, 0xfc, 0xd2, 0xac, 0x10, 0xe9, 0x14, 0xff, 0x14, 0xa6, 0xe8, 0xee, 0xaa, 0x40, 0xe9, 0x12, 0xa9, 0xe7, 0x8c, 0xaa, 0xd1, 0x97, 0xaa, 0xeb, 0x9c, 0xb5, 0x2e, 0xb2, 0x5a, 0x6d, 0x40, 0xef, 0xd1, 0xc1, 0xf7, 0x9c, 0x87, 0xef, 0xb1, 0xa0, 0xbb,\n\t0x1a, 0x8b, 0x66, 0x2a, 0x5c, 0x98, 0x85, 0x67, 0x4e, 0xe9, 0x63, 0xb8, 0x30, 0x26, 0xee, 0xf8, 0x9c, 0x37, 0xf1, 0xe5, 0x80, 0x5c, 0xf2, 0xe1, 0x87, 0x67, 0x3f, 0xfc, 0x70, 0x52, 0x0f, 0xd8, 0xe5, 0xb2, 0x7d, 0x2f, 0xbf, 0xbc, 0xaf, 0x79, 0x42, 0x27, 0xce, 0x73, 0x11, 0xcd, 0x34, 0x90, 0x1e, 0x85, 0x61, 0x3f, 0x5c, 0x08, 0x0b, 0xe6, 0x30, 0xeb, 0xc6, 0xb0, 0x60, 0x9c, 0xd0, 0x0d, 0xfa, 0xc8, 0xf1, 0x04, 0xc9, 0x45, 0x38, 0x7d, 0x8e, 0xb4, 0x49, 0x58, 0x30, 0x2a, 0x16, 0xc5, 0x90, 0xbb, 0x18, 0xd0, 0xa2, 0x6e, 0x85, 0xd1, 0xc5, 0x40, 0x1e, 0x1d, 0x86, 0xbc, 0x71, 0x81, 0xd1, 0x22, 0xfa, 0x8a, 0x91, 0x88, 0x3e, 0x92, 0x98, 0xf5, 0x4f, 0x82, 0x79, 0xec, 0xe3, 0x2f, 0x1b, 0xf5, 0xa2, 0x2f, 0x18, 0x99, 0xe4, 0xa7, 0x9a, 0x94, 0x67, 0xd9, 0xc7, 0x01, 0xc9, 0x53, 0xae,\n\t0x24, 0x05, 0xd8, 0xa1, 0x4c, 0x96, 0xb1, 0x27, 0x14, 0x49, 0xa4, 0x14, 0x7c, 0xa6, 0x50, 0xb0, 0xfb, 0x94, 0x56, 0x15, 0x08, 0xd9, 0xd8, 0x64, 0x76, 0x13, 0x8a, 0x7a, 0x9a, 0xcc, 0x3e, 0xcc, 0xac, 0xc0, 0xf4, 0x73, 0x1c, 0x16, 0xcc, 0xf2, 0x1d, 0xb1, 0x60, 0xcc, 0x0a, 0xd8, 0xb9, 0xf3, 0xdf, 0x63, 0x5f, 0xa3, 0x94, 0xec, 0x57, 0x63, 0x04, 0x94, 0x9a, 0x77, 0xc7, 0x1d, 0xa3, 0x39, 0xe8, 0x6c, 0xe2, 0x00, 0x7f, 0x70, 0x8e, 0x4a, 0xe0, 0x3b, 0x4d, 0xe8, 0x3e, 0x5c, 0x3f, 0x19, 0x0b, 0x66, 0x99, 0x12, 0x0b, 0x66, 0x22, 0x4c, 0x46, 0x9d, 0x66, 0x32, 0x16, 0x0c, 0x24, 0x62, 0xc1, 0xe8, 0x12, 0xb8, 0x15, 0x7f, 0xbc, 0xe3, 0x93, 0xa3, 0x73, 0xcf, 0x86, 0x87, 0x0e, 0x2f, 0x3d, 0x13, 0x23, 0xe0, 0x8f, 0x38, 0x94, 0x91, 0xeb, 0x57, 0x83, 0xe9, 0xec, 0x4f, 0xaa, 0xdb, 0xec,\n\t0x72, 0x13, 0xf8, 0x21, 0xa7, 0x2f, 0x00, 0xa2, 0x09, 0xca, 0xe1, 0xdb, 0xf1, 0xbe, 0xc9, 0x8f, 0xe6, 0x99, 0x8d, 0x3a, 0x01, 0x24, 0x78, 0xdc, 0x75, 0x38, 0x54, 0x1b, 0x40, 0x2c, 0x81, 0xdd, 0x5c, 0x7c, 0x3a, 0x12, 0x30, 0x60, 0x16, 0xc2, 0xa2, 0xd7, 0xab, 0xf5, 0xf1, 0xcb, 0x79, 0xb8, 0x5a, 0xfa, 0x09, 0x18, 0x30, 0xb8, 0x62, 0x6a, 0x6a, 0xfb, 0x59, 0x77, 0x8d, 0x73, 0x67, 0xf3, 0xb6, 0xbe, 0xd0, 0xd9, 0xa6, 0xa6, 0x9d, 0xb6, 0x5a, 0x2f, 0x72, 0x22, 0x06, 0x47, 0xc4, 0x4a, 0xe6, 0xed, 0x57, 0xc9, 0xd4, 0xda, 0xd5, 0x6d, 0xa8, 0x4b, 0x1d, 0xed, 0x62, 0x60, 0x65, 0xff, 0x40, 0xcb, 0xc5, 0xe0, 0x87, 0x04, 0xc7, 0x5f, 0xa8, 0x57, 0x61, 0x9f, 0xd4, 0x08, 0x07, 0x26, 0x9f, 0x84, 0x03, 0xb3, 0x8c, 0xe1, 0xc0, 0x74, 0xea, 0x18, 0x0e, 0x0c, 0x8c, 0xc7, 0x81, 0x35, 0x6e,\n\t0xff, 0xfd, 0x63, 0xf3, 0xce, 0x46, 0x86, 0x0e, 0x2f, 0x39, 0x73, 0x86, 0x9c, 0x81, 0x07, 0xcf, 0x1e, 0x07, 0x39, 0xd5, 0xad, 0x76, 0x99, 0x89, 0x2d, 0xc0, 0x04, 0x92, 0x24, 0xb2, 0x2f, 0x7c, 0x49, 0xff, 0x82, 0xcf, 0x11, 0xbe, 0x3d, 0x2a, 0x29, 0x83, 0xfa, 0x77, 0x06, 0x94, 0x98, 0x62, 0x0e, 0xca, 0x3e, 0x42, 0x40, 0x33, 0xb4, 0x80, 0x19, 0x26, 0xc5, 0x24, 0x94, 0x4d, 0x68, 0xc8, 0xdc, 0x06, 0x62, 0x17, 0xeb, 0x0e, 0x64, 0xbd, 0xc4, 0xa1, 0x17, 0xec, 0x42, 0xcc, 0x29, 0xae, 0xa4, 0xa8, 0x13, 0xe5, 0x26, 0x30, 0x11, 0x44, 0x7e, 0x24, 0x94, 0x9d, 0x9e, 0xe6, 0x71, 0xa1, 0xc8, 0xf9, 0x1a, 0x35, 0xce, 0xef, 0x3d, 0x86, 0x93, 0x12, 0x08, 0xdd, 0x31, 0xf8, 0x93, 0x71, 0x0a, 0xbc, 0x14, 0x8f, 0x1f, 0xe3, 0xbc, 0x84, 0xc3, 0x11, 0xda, 0xc5, 0xe7, 0xf6, 0x66, 0xf7, 0x9b,\n\t0x54, 0xca, 0xc6, 0x26, 0x79, 0xe3, 0xfa, 0x07, 0x06, 0xfa, 0xef, 0x1b, 0x29, 0x4f, 0xcc, 0xf1, 0x1d, 0xd4, 0x18, 0xe5, 0xf9, 0xce, 0x59, 0x4b, 0x57, 0x46, 0x06, 0x9f, 0xda, 0xde, 0x44, 0x17, 0x0c, 0x36, 0x05, 0xd4, 0xda, 0x58, 0x72, 0xef, 0xaf, 0x39, 0xf5, 0xbb, 0x30, 0x97, 0xec, 0xb9, 0x73, 0x59, 0xe9, 0x14, 0x69, 0xbe, 0xa7, 0x6d, 0x3f, 0x7d, 0x2d, 0x50, 0x67, 0x75, 0x56, 0x43, 0x5d, 0x9d, 0xe3, 0x2b, 0xd9, 0x70, 0xff, 0x72, 0xf3, 0x86, 0xf1, 0x62, 0x55, 0xfc, 0xbc, 0xe5, 0xe7, 0x40, 0xe1, 0x03, 0xf2, 0x95, 0x2b, 0x99, 0x0a, 0xab, 0x10, 0xee, 0xa2, 0xd2, 0x92, 0x48, 0xde, 0xbf, 0x33, 0x0f, 0x42, 0xee, 0x14, 0x64, 0x52, 0x57, 0x3d, 0x19, 0xd6, 0xda, 0xd6, 0x99, 0x19, 0xb6, 0xa4, 0xf5, 0x1d, 0xfb, 0x17, 0x95, 0x5c, 0xcd, 0x7c, 0x38, 0xf2, 0xdc, 0x26, 0x01, 0xfb,\n\t0x67, 0x78, 0xa4, 0xda, 0x15, 0x2d, 0x5b, 0x9f, 0x5a, 0x91, 0x38, 0x2f, 0x9c, 0xce, 0xf9, 0x29, 0x96, 0x5b, 0x9e, 0x7e, 0x2e, 0xdd, 0x47, 0x0a, 0x71, 0xd4, 0xb4, 0x00, 0xbf, 0x93, 0xd0, 0x4c, 0xe0, 0xe3, 0x44, 0xf2, 0x81, 0x96, 0x39, 0x0d, 0xb7, 0x41, 0x24, 0x26, 0xa1, 0x22, 0xd8, 0xc7, 0xcd, 0x09, 0x2f, 0x9c, 0xb8, 0x27, 0x96, 0xe7, 0x0a, 0x11, 0xc2, 0x39, 0x63, 0x15, 0x49, 0x1c, 0x0c, 0x24, 0x56, 0x4e, 0x44, 0x12, 0xa4, 0x88, 0x88, 0x97, 0xc7, 0xa9, 0xa9, 0x27, 0x14, 0xef, 0xc1, 0x39, 0xaa, 0x33, 0x33, 0x3c, 0xae, 0x14, 0x6b, 0x92, 0x51, 0xa3, 0x52, 0x2a, 0xe4, 0x32, 0xa9, 0x98, 0x08, 0x82, 0x20, 0xba, 0x6b, 0x62, 0xe2, 0x28, 0x89, 0xb8, 0x4a, 0x92, 0x20, 0xa5, 0x4e, 0x14, 0x64, 0xc8, 0xda, 0x98, 0x4e, 0xf9, 0x0f, 0x4e, 0x39, 0xe1, 0x25, 0x56, 0xb5, 0xcb, 0xf8,\n\t0xc0, 0xd3, 0x9c, 0x1c, 0xc3, 0xab, 0x9f, 0x72, 0xf7, 0x07, 0xfe, 0x9e, 0x1b, 0xfa, 0x91, 0x80, 0x12, 0x53, 0x53, 0x38, 0x09, 0xd6, 0xe2, 0x53, 0x88, 0x7e, 0xfa, 0xe6, 0xca, 0x17, 0xb6, 0xd7, 0xc6, 0x04, 0x19, 0x3c, 0x87, 0x04, 0xdc, 0x5b, 0x1f, 0xc0, 0x39, 0x9c, 0x8c, 0x35, 0xb3, 0x5c, 0x19, 0xd6, 0xcc, 0xf2, 0x9d, 0xb1, 0x66, 0x02, 0x12, 0x1d, 0x2d, 0x6c, 0xa2, 0xa2, 0x34, 0x11, 0xbb, 0x9a, 0xfe, 0xe0, 0xf6, 0xe7, 0x47, 0x4e, 0xb0, 0x3f, 0x93, 0x05, 0x2b, 0xdb, 0xfa, 0xe7, 0x65, 0xf7, 0x86, 0x1d, 0x55, 0xd3, 0x8a, 0x73, 0x5c, 0x12, 0xf2, 0xc0, 0x01, 0x64, 0x8a, 0xa1, 0x66, 0x9f, 0x66, 0xff, 0xef, 0xcc, 0xfa, 0x69, 0xc6, 0x94, 0x8d, 0xc6, 0x69, 0xeb, 0xce, 0x00, 0xd3, 0xe9, 0x18, 0x4d, 0xdd, 0xcd, 0xde, 0x46, 0x7d, 0x04, 0xc7, 0xe0, 0x20, 0xe6, 0xf1, 0x26, 0xc0,\n\t0x86, 0xe3, 0xfe, 0x49, 0xc8, 0x32, 0xcb, 0x54, 0x20, 0x41, 0x6b, 0xac, 0x08, 0x8a, 0x06, 0x8b, 0xb2, 0x9f, 0x25, 0x14, 0xa5, 0xf9, 0x1b, 0x02, 0x07, 0xe1, 0xc0, 0x10, 0xb1, 0xa4, 0x44, 0x88, 0x18, 0x5c, 0x1b, 0x6a, 0x2a, 0x94, 0x18, 0xf5, 0x51, 0xce, 0xbc, 0xfd, 0x7d, 0xfe, 0xaa, 0x34, 0xb8, 0x13, 0xa0, 0xa8, 0x0b, 0x17, 0xc4, 0xe9, 0x4d, 0xaf, 0xcd, 0xb3, 0x72, 0xe2, 0x37, 0xa4, 0xc6, 0xe9, 0x43, 0x07, 0xe7, 0x04, 0x24, 0x52, 0xa5, 0x51, 0x6f, 0x54, 0xaa, 0x75, 0x62, 0x7d, 0xc1, 0xfc, 0x66, 0xf0, 0x54, 0x82, 0x38, 0xce, 0xeb, 0x18, 0x28, 0xfe, 0x84, 0x72, 0xb2, 0x8e, 0xf1, 0x1d, 0xf0, 0x62, 0xf4, 0xb1, 0x03, 0x2f, 0xac, 0x3a, 0x19, 0x57, 0x30, 0xd4, 0x13, 0xd4, 0x0b, 0xc4, 0x93, 0xa0, 0x5c, 0xb6, 0x3d, 0xc6, 0x1f, 0x8d, 0x53, 0xe0, 0xc5, 0x2c, 0x53, 0xe1, 0xc5,\n\t0x20, 0x7f, 0x44, 0xec, 0x71, 0x0a, 0xbc, 0x58, 0x02, 0x87, 0xa4, 0xb6, 0xbf, 0x03, 0x19, 0xe4, 0x4b, 0x3b, 0x3e, 0x79, 0x0c, 0x31, 0xc8, 0xfb, 0x97, 0x22, 0x76, 0xc4, 0x7e, 0x04, 0xcf, 0xf3, 0xdf, 0x80, 0xc6, 0x3e, 0x81, 0x45, 0xc6, 0xc6, 0xce, 0xbc, 0x45, 0x9d, 0x23, 0x7c, 0x44, 0x61, 0x34, 0x92, 0xaa, 0x16, 0x51, 0x02, 0xcc, 0x1d, 0x05, 0x40, 0x00, 0xb9, 0x23, 0x93, 0x30, 0x07, 0x13, 0xc0, 0x62, 0x3e, 0xc2, 0x17, 0xb0, 0x9b, 0xbc, 0x13, 0xc1, 0x62, 0x97, 0x88, 0xba, 0x87, 0x0c, 0x1f, 0xcc, 0x5b, 0xb7, 0x3f, 0xbf, 0xea, 0xb0, 0x50, 0xc8, 0x3e, 0x2e, 0x4e, 0xd6, 0x1a, 0x34, 0x56, 0x31, 0xfb, 0x88, 0x40, 0x74, 0xfc, 0x90, 0xce, 0xa7, 0x00, 0x69, 0x72, 0x83, 0x44, 0xa2, 0x97, 0x03, 0xb7, 0xc2, 0xa7, 0x3b, 0x84, 0xa7, 0x8d, 0xdc, 0x95, 0xd2, 0x68, 0x1b, 0x3d, 0xa2,\n\t0xd6, 0x6a, 0xd5, 0x64, 0x9f, 0xad, 0x29, 0x75, 0x74, 0x03, 0x75, 0x4e, 0x63, 0x66, 0x25, 0xa6, 0xb0, 0xc5, 0x12, 0x36, 0x81, 0x7f, 0x5a, 0xd4, 0xe7, 0xef, 0xc2, 0xf4, 0xba, 0xfe, 0xc2, 0x97, 0x14, 0x47, 0xaf, 0x33, 0x88, 0xe5, 0x1c, 0x6f, 0xf3, 0x5c, 0x14, 0x3c, 0xe6, 0x48, 0x04, 0x8f, 0x59, 0xae, 0xa8, 0x20, 0xba, 0x7b, 0x40, 0x78, 0x98, 0x80, 0xdf, 0xeb, 0xb6, 0xa7, 0x26, 0x19, 0x95, 0x72, 0x4c, 0xcb, 0x91, 0x1d, 0x5f, 0xcb, 0x6b, 0x02, 0x60, 0x7c, 0x18, 0x2f, 0x74, 0x6b, 0x15, 0x0f, 0xde, 0xe5, 0xfd, 0xc6, 0x1e, 0xed, 0x2f, 0xda, 0xb8, 0x5f, 0x33, 0xda, 0xe0, 0x9a, 0xb5, 0x64, 0x65, 0x64, 0xf1, 0xb3, 0x3b, 0xea, 0x2a, 0x36, 0x3e, 0x3d, 0x0c, 0x29, 0x77, 0x54, 0x6b, 0x81, 0x1a, 0x22, 0xa6, 0xdc, 0xb3, 0x20, 0xe5, 0x36, 0xc9, 0xc1, 0x3e, 0x8e, 0x4a, 0x83, 0xff,\n\t0x41, 0xac, 0xa9, 0xe6, 0xc6, 0xb7, 0x77, 0x2e, 0x7e, 0xe1, 0xfa, 0xe6, 0x92, 0xd5, 0x8f, 0x2d, 0xcb, 0x4c, 0xed, 0xbd, 0xa1, 0x07, 0x53, 0x69, 0x14, 0x9b, 0xf4, 0xc2, 0x97, 0xec, 0x3d, 0x54, 0x21, 0xdc, 0x43, 0x02, 0xf2, 0xf7, 0x22, 0x14, 0xc4, 0xbc, 0x05, 0xf2, 0x7a, 0x14, 0x87, 0x06, 0xe5, 0xb6, 0xb2, 0xa3, 0xfb, 0x3b, 0x35, 0x77, 0x87, 0x39, 0x09, 0x98, 0xe5, 0x48, 0x04, 0x66, 0x59, 0x2e, 0x53, 0x04, 0x99, 0xc1, 0xa3, 0x66, 0xa5, 0x02, 0x6e, 0x7f, 0x22, 0xc9, 0xa8, 0xb0, 0x2b, 0xed, 0x42, 0xb9, 0x50, 0x0e, 0xa9, 0xaa, 0x80, 0x10, 0x38, 0x38, 0xf8, 0x16, 0xf2, 0x5e, 0x89, 0x25, 0xeb, 0x02, 0x13, 0xf2, 0x43, 0x00, 0xb3, 0x78, 0xff, 0xee, 0xeb, 0xf7, 0x89, 0x81, 0x74, 0xdf, 0xce, 0x5d, 0xfb, 0xa5, 0x20, 0x15, 0x45, 0xb0, 0xa9, 0xdc, 0x72, 0x72, 0x78, 0xe5, 0xc9,\n\t0xad, 0x55, 0x55, 0x5b, 0x4f, 0x82, 0x9f, 0xdc, 0xfb, 0xe8, 0xa3, 0xf7, 0x2e, 0xb9, 0xfd, 0x81, 0x07, 0x6e, 0x07, 0xff, 0x85, 0x22, 0xd8, 0xac, 0x7b, 0xfd, 0x86, 0xba, 0xba, 0x1b, 0x5e, 0x5f, 0x87, 0x22, 0xda, 0x70, 0x67, 0xf3, 0x06, 0xf6, 0x21, 0xca, 0x01, 0xc7, 0x29, 0xc3, 0x31, 0x63, 0x91, 0x0e, 0xce, 0x69, 0x30, 0x50, 0x2f, 0xe6, 0x6c, 0xf6, 0x9c, 0xcc, 0x8f, 0x54, 0x17, 0x15, 0x83, 0x4e, 0x86, 0x3d, 0x41, 0x79, 0xa1, 0x1c, 0x6c, 0xda, 0x29, 0xa4, 0xee, 0x23, 0x35, 0x1c, 0x6a, 0x2e, 0x8d, 0xf0, 0x20, 0xf4, 0x21, 0xe1, 0x08, 0x32, 0x74, 0xc8, 0xcb, 0x36, 0x62, 0x1a, 0x76, 0xb5, 0xf8, 0x2c, 0xcb, 0x77, 0xc7, 0x67, 0x59, 0xfe, 0x0d, 0x7c, 0x96, 0xe5, 0x0a, 0xf1, 0x59, 0xc8, 0x7c, 0x1c, 0x9a, 0x32, 0x7b, 0xe4, 0x98, 0x49, 0xf9, 0xa5, 0x89, 0xd8, 0xa3, 0x9f, 0x8f,\n\t0xd9, 0x98, 0xdf, 0xfd, 0xfe, 0xb8, 0xfb, 0x88, 0x98, 0xc5, 0x99, 0xd3, 0x7d, 0x0e, 0xd0, 0xb9, 0x70, 0xce, 0xb2, 0xaf, 0x1e, 0x9f, 0x65, 0xb9, 0x2a, 0x7c, 0x96, 0xe5, 0xea, 0xf0, 0x59, 0x96, 0x29, 0xf1, 0x59, 0xd9, 0x57, 0x84, 0xcf, 0xa2, 0x04, 0xe3, 0xd4, 0x30, 0x5e, 0x2a, 0x40, 0x6a, 0x58, 0xee, 0xc4, 0xb0, 0x08, 0x4b, 0x8c, 0x16, 0xf1, 0x57, 0x22, 0xe5, 0x6f, 0xa5, 0x66, 0x1d, 0x56, 0xc9, 0x4e, 0x19, 0x0d, 0xa2, 0x2f, 0x84, 0xda, 0xff, 0x12, 0x1b, 0xd4, 0x48, 0x25, 0x23, 0x0e, 0x7c, 0x7f, 0x02, 0x38, 0x0b, 0xec, 0x48, 0x49, 0x4a, 0xd4, 0xcc, 0xac, 0xa9, 0x20, 0xa4, 0x52, 0x41, 0xcd, 0x6c, 0x0b, 0xc0, 0xf3, 0x99, 0x0b, 0x0f, 0x2e, 0x0b, 0xe7, 0xd3, 0x7e, 0x29, 0x7c, 0x96, 0x65, 0x0c, 0x9f, 0xe5, 0x1b, 0x8f, 0xcf, 0x8a, 0x75, 0x1d, 0xd8, 0xf3, 0x42, 0xe3, 0x7a,\n\t0x0f, 0xe0, 0x1e, 0xa0, 0xd8, 0x97, 0x13, 0xbb, 0x1b, 0x66, 0xd9, 0x6f, 0xd8, 0x8f, 0xc6, 0xf5, 0xf8, 0x83, 0x0b, 0xe7, 0xc7, 0xba, 0x08, 0xde, 0xdc, 0x0f, 0x0e, 0x27, 0xf4, 0x71, 0xf6, 0x7e, 0x14, 0x27, 0xf7, 0xc2, 0x97, 0xcc, 0x3b, 0xcc, 0x59, 0x42, 0x45, 0x4c, 0x03, 0x64, 0x54, 0x91, 0x09, 0xf0, 0xfd, 0x3e, 0x81, 0x80, 0x51, 0xb1, 0xcc, 0x2c, 0x6e, 0x51, 0x1c, 0x15, 0x84, 0x6f, 0x6b, 0xe1, 0x01, 0xed, 0x25, 0x10, 0x05, 0x99, 0x88, 0x4a, 0x52, 0x5f, 0x59, 0x61, 0x0e, 0x96, 0x64, 0xba, 0x9a, 0x96, 0xcd, 0x78, 0xf7, 0x40, 0x22, 0x3e, 0x32, 0x56, 0xe3, 0x22, 0x2d, 0x5f, 0x49, 0x39, 0x1e, 0xbb, 0x14, 0x55, 0xc1, 0x13, 0x35, 0x4d, 0x5d, 0xe1, 0xd6, 0xfa, 0x5c, 0x99, 0x1e, 0x07, 0x96, 0x44, 0xf8, 0x04, 0xb5, 0xfc, 0xc5, 0x98, 0x7b, 0x2a, 0xbc, 0x12, 0x5a, 0x86, 0x18,\n\t0x7e, 0x61, 0x0c, 0xb2, 0x44, 0x19, 0x83, 0x2b, 0xaa, 0x76, 0xdd, 0xe6, 0xab, 0xea, 0xcf, 0xcb, 0xeb, 0xab, 0xf2, 0x91, 0xf7, 0xc4, 0x30, 0x4b, 0x0b, 0x6f, 0x72, 0xe6, 0x3e, 0xbb, 0x72, 0xf0, 0xf0, 0x8a, 0x42, 0x14, 0x80, 0xad, 0x6f, 0x5b, 0xe8, 0xac, 0xd6, 0x9d, 0xef, 0x8e, 0xe3, 0x96, 0x28, 0xb2, 0x2c, 0xe7, 0xfb, 0x2f, 0xce, 0xdd, 0xdd, 0x95, 0xe6, 0xae, 0xe8, 0x8b, 0xfc, 0x8e, 0x43, 0x75, 0xec, 0x9b, 0x1b, 0xea, 0xe8, 0xe8, 0x6e, 0xaf, 0xdc, 0xf1, 0xfa, 0xe6, 0x95, 0xaf, 0xef, 0x9f, 0x51, 0x1c, 0x21, 0x03, 0xe7, 0xf6, 0x22, 0x2c, 0x87, 0x35, 0xd2, 0x12, 0x8a, 0xa3, 0x39, 0xd0, 0xfe, 0x52, 0x5f, 0xf8, 0x1b, 0xfd, 0x47, 0x1a, 0x69, 0x31, 0x9b, 0xa3, 0x12, 0x5f, 0x1c, 0xbb, 0xc4, 0x4d, 0x99, 0x37, 0x0e, 0x61, 0x12, 0xe2, 0x0c, 0x6d, 0x09, 0xd8, 0x25, 0x47, 0xe2,\n\t0xe5, 0x35, 0x0a, 0x70, 0x49, 0x53, 0x42, 0x8a, 0x16, 0x22, 0xb0, 0x13, 0x49, 0x09, 0x71, 0x8e, 0xa3, 0x8b, 0x97, 0xe7, 0x0e, 0x5f, 0x15, 0x51, 0x99, 0xe1, 0x76, 0x7a, 0x2e, 0x01, 0x77, 0x0a, 0x4f, 0x89, 0xf1, 0x51, 0x90, 0x42, 0x43, 0x2c, 0x3a, 0x3c, 0x37, 0x77, 0xf4, 0x8f, 0x63, 0x93, 0xd5, 0xb0, 0xad, 0x3f, 0x0f, 0xa5, 0x12, 0x5a, 0xb5, 0x6a, 0x68, 0x9d, 0x39, 0xaf, 0x25, 0xb7, 0x70, 0x7a, 0xbe, 0x5b, 0xae, 0xd0, 0x4a, 0x33, 0x0a, 0x8e, 0xac, 0xee, 0xdf, 0x3f, 0x37, 0x5b, 0xe3, 0xab, 0x08, 0xbe, 0xd2, 0xd4, 0xd0, 0x5d, 0x33, 0x11, 0x04, 0x13, 0x98, 0xb1, 0xa6, 0x3e, 0x18, 0xf5, 0xaa, 0xb6, 0xcf, 0x88, 0x26, 0x87, 0xbc, 0x06, 0x63, 0xb2, 0x51, 0xaa, 0x6e, 0x08, 0x57, 0x66, 0x34, 0xcc, 0xc9, 0xb5, 0x96, 0x15, 0x87, 0xd4, 0x79, 0xaf, 0x77, 0xd4, 0x8d, 0x01, 0x61,\n\t0x00, 0xa1, 0x85, 0xf2, 0xd9, 0xb3, 0x38, 0x8e, 0x68, 0x6d, 0xb4, 0x2a, 0x15, 0x2a, 0x20, 0x81, 0x4b, 0x62, 0x9c, 0x1c, 0x53, 0x62, 0x9c, 0x82, 0x44, 0x10, 0x4d, 0x80, 0x73, 0x22, 0xc6, 0xc9, 0x73, 0xe9, 0xd1, 0x23, 0x88, 0x13, 0xf5, 0x2c, 0x94, 0xe1, 0xde, 0x5c, 0xb9, 0x71, 0x64, 0x04, 0x0e, 0x34, 0x97, 0x1b, 0xa8, 0x02, 0x0e, 0x34, 0x50, 0x70, 0x64, 0x55, 0xff, 0x4d, 0x73, 0x72, 0xb4, 0xfe, 0xaa, 0x50, 0xff, 0xf2, 0x98, 0xe9, 0x23, 0xb7, 0xb6, 0x73, 0x8a, 0x81, 0xa5, 0x94, 0xc3, 0x81, 0x59, 0xb7, 0xf4, 0xdf, 0x8c, 0x74, 0x8e, 0x0b, 0x5f, 0x0a, 0x48, 0x48, 0x67, 0x22, 0xc4, 0xaf, 0xb8, 0x53, 0x3b, 0x19, 0xdb, 0x64, 0x49, 0xc0, 0x36, 0x39, 0xc7, 0x82, 0xfa, 0x5c, 0xb2, 0x9c, 0x7d, 0x2c, 0xb8, 0xce, 0x15, 0xb4, 0x67, 0xbe, 0xa2, 0xf6, 0x2e, 0xdf, 0x14, 0x17, 0xf8,\n\t0x1a, 0x4e, 0x70, 0x84, 0x08, 0x5f, 0x0c, 0x4c, 0x35, 0x51, 0xd3, 0x99, 0x70, 0x1c, 0x99, 0x3f, 0x72, 0x5b, 0x6a, 0x5b, 0x6b, 0xc3, 0xd6, 0xbe, 0xdc, 0xa9, 0x14, 0x20, 0xee, 0x14, 0x7a, 0xd4, 0x08, 0x32, 0x62, 0x27, 0x97, 0xc6, 0x0f, 0x5e, 0xa0, 0x7b, 0x7b, 0x27, 0xa9, 0x9c, 0xa8, 0x17, 0x8d, 0x76, 0x4f, 0x3c, 0x7e, 0xe8, 0x9e, 0xea, 0x1f, 0xcc, 0xcf, 0xf1, 0xfd, 0xec, 0x5f, 0xb9, 0x39, 0x4f, 0x86, 0xe7, 0x0c, 0x92, 0x4f, 0x01, 0x0f, 0x8f, 0xb2, 0x8c, 0x81, 0xa8, 0xc6, 0xe6, 0xfb, 0xe2, 0x65, 0xc6, 0xe6, 0xfa, 0x72, 0xed, 0x98, 0xaf, 0xa0, 0x1d, 0xdf, 0x65, 0xdb, 0x89, 0xda, 0x26, 0xfd, 0x9c, 0x88, 0xe6, 0x72, 0xc6, 0x62, 0x2a, 0x73, 0x17, 0xba, 0xe9, 0x53, 0x23, 0xba, 0x4a, 0xc0, 0x04, 0x44, 0x57, 0xc2, 0x12, 0xbc, 0x10, 0x3f, 0xd5, 0x68, 0x09, 0x38, 0x65, 0x69,\n\t0x1c, 0xed, 0x9b, 0x30, 0xeb, 0x3b, 0x63, 0x2a, 0xd4, 0xe4, 0xc9, 0xe6, 0xec, 0x7c, 0x17, 0xbe, 0xa2, 0x4d, 0xb4, 0x80, 0xc8, 0x24, 0xce, 0x9d, 0xe4, 0x60, 0x5d, 0x1c, 0x24, 0x2a, 0x25, 0x86, 0xee, 0x9a, 0x1b, 0x43, 0x77, 0x39, 0x12, 0xd1, 0x5d, 0xfc, 0xc4, 0x5f, 0xaa, 0x94, 0x33, 0x1e, 0x93, 0xea, 0xf2, 0x6d, 0x99, 0xaf, 0xa8, 0xad, 0xe4, 0x2b, 0x68, 0xeb, 0x72, 0xcd, 0x8c, 0x81, 0xa1, 0x32, 0x89, 0x4c, 0x8d, 0x67, 0x3c, 0x3a, 0x6d, 0x7c, 0x0c, 0xe6, 0x38, 0x36, 0x0d, 0x93, 0x55, 0x9c, 0x0e, 0x94, 0x36, 0x95, 0x8c, 0x3c, 0x38, 0xb8, 0xee, 0xec, 0x9e, 0xc6, 0xfa, 0x1b, 0xcf, 0x6c, 0x28, 0x5d, 0xd6, 0xdf, 0x60, 0x0d, 0xca, 0xd2, 0x4c, 0x8a, 0xb4, 0xe2, 0x19, 0x91, 0x86, 0xb5, 0x33, 0xfc, 0xc7, 0x8f, 0x6c, 0xdd, 0xf1, 0x4b, 0xb5, 0x1e, 0x5c, 0x58, 0xdb, 0x7f, 0xc7,\n\t0xe2, 0xfc, 0xa6, 0x1b, 0x5f, 0x1b, 0x19, 0x39, 0x7d, 0x63, 0x93, 0xde, 0x1d, 0xb4, 0xd4, 0xeb, 0xa4, 0x4a, 0x91, 0xc9, 0xa8, 0x0a, 0xcd, 0xd9, 0xdd, 0xf1, 0xca, 0x8b, 0x1b, 0x97, 0xe9, 0x54, 0x43, 0x78, 0xfe, 0xcd, 0x17, 0xfe, 0x4e, 0xb7, 0x60, 0xbb, 0xf8, 0x51, 0x6e, 0xbf, 0xa7, 0xc2, 0xfe, 0x03, 0x1a, 0x30, 0xf4, 0x30, 0xd2, 0x1f, 0xf1, 0x75, 0x03, 0x56, 0xf3, 0x27, 0xcc, 0xfc, 0x25, 0x8b, 0x39, 0xe3, 0xbb, 0xfe, 0xb2, 0xad, 0x5d, 0xb6, 0xa1, 0x31, 0xec, 0x98, 0xd3, 0x89, 0xf6, 0x2a, 0x9e, 0xae, 0x71, 0x54, 0x03, 0x1b, 0xb9, 0xc7, 0xf3, 0x9e, 0xdc, 0x31, 0x42, 0xd1, 0x9f, 0x8b, 0x2e, 0x40, 0xd8, 0x6d, 0x0d, 0xf5, 0xdd, 0xb5, 0xe3, 0xc8, 0xc2, 0x7e, 0x0e, 0x75, 0x48, 0xea, 0x0e, 0x1c, 0x18, 0xfd, 0xcb, 0x50, 0xe7, 0xca, 0x31, 0x44, 0x25, 0x8a, 0x93, 0xda, 0x7a,\n\t0xe1, 0xef, 0x50, 0x30, 0x15, 0x91, 0x02, 0xe2, 0x7d, 0xac, 0xab, 0x12, 0x50, 0x86, 0x7e, 0x1b, 0xce, 0x93, 0x01, 0xea, 0xaa, 0x7f, 0xe3, 0x04, 0x64, 0xa9, 0x13, 0x21, 0xed, 0xeb, 0x8d, 0x50, 0x88, 0xae, 0xb3, 0xe0, 0x6f, 0x22, 0xfe, 0x1b, 0x2f, 0x41, 0x3b, 0xa6, 0x22, 0x85, 0x9c, 0x55, 0x02, 0x33, 0x20, 0xab, 0x20, 0x06, 0xa8, 0x4a, 0x23, 0x84, 0x50, 0x35, 0x15, 0x8a, 0x86, 0xa7, 0xae, 0x41, 0x88, 0x44, 0x09, 0x15, 0x90, 0xd8, 0x9d, 0x41, 0x08, 0x49, 0x11, 0x39, 0xae, 0x02, 0xb6, 0x3a, 0x30, 0x31, 0x2c, 0x88, 0x73, 0x5c, 0xa5, 0xa8, 0x3f, 0x5e, 0x1e, 0xaa, 0x9a, 0x22, 0xc1, 0xec, 0x8b, 0x56, 0x23, 0xf9, 0x04, 0xec, 0x6e, 0xb7, 0x16, 0x19, 0xa2, 0x54, 0x5c, 0xc4, 0x98, 0x49, 0xa4, 0x59, 0x0b, 0x95, 0x92, 0x49, 0x92, 0x79, 0x1e, 0xad, 0x3a, 0x33, 0x15, 0x55, 0x56,\n\t0xab, 0x5e, 0x9a, 0x80, 0xa9, 0xca, 0x9e, 0xc2, 0x48, 0x25, 0x1a, 0x2f, 0x87, 0xa3, 0x5c, 0xd8, 0x50, 0x9b, 0x9d, 0xc6, 0x3c, 0x02, 0x35, 0x82, 0x67, 0xb8, 0xdd, 0xa4, 0xb0, 0x00, 0x91, 0x20, 0x08, 0xe5, 0x6a, 0x29, 0x52, 0x26, 0xd0, 0x7d, 0xeb, 0xd8, 0x03, 0x86, 0xa4, 0x62, 0x91, 0xc2, 0x73, 0xe0, 0x4c, 0x4a, 0x44, 0x42, 0xc9, 0xb0, 0x18, 0xdd, 0x87, 0x23, 0xad, 0x63, 0x20, 0x36, 0x19, 0x4b, 0xd1, 0x78, 0x25, 0x3d, 0x48, 0x3b, 0x1b, 0x44, 0xc7, 0x12, 0x4f, 0xc2, 0x7c, 0x14, 0x68, 0x30, 0x12, 0xab, 0x44, 0x20, 0xbc, 0x59, 0x07, 0xac, 0x4a, 0x30, 0x14, 0x42, 0xc5, 0x5c, 0xa6, 0x26, 0xa7, 0xd1, 0x65, 0x13, 0xd9, 0x59, 0x19, 0x4e, 0xb7, 0xcf, 0x89, 0xcd, 0x4b, 0x32, 0x94, 0x0e, 0x17, 0xdd, 0xbc, 0xf0, 0x7f, 0x26, 0xdf, 0x47, 0x8e, 0x0b, 0x2c, 0x11, 0x51, 0x33, 0xd3,\n\t0xd8, 0x62, 0x30, 0x9f, 0xbd, 0x17, 0x9c, 0x1d, 0xdd, 0x62, 0x9b, 0xe6, 0x82, 0x6a, 0x76, 0x65, 0xdd, 0x75, 0x2f, 0xae, 0x18, 0x3e, 0x5a, 0x52, 0x26, 0x50, 0xab, 0x54, 0x8e, 0xbc, 0x96, 0xe2, 0xca, 0x91, 0x19, 0x19, 0xc1, 0xb6, 0xe1, 0xf2, 0xba, 0x10, 0xf5, 0xc5, 0x5d, 0xec, 0x67, 0xb7, 0xb1, 0x7f, 0x38, 0x08, 0x8e, 0x8b, 0x24, 0x8d, 0xbb, 0x5f, 0x5e, 0x31, 0xfc, 0xda, 0x9e, 0x96, 0xda, 0xa2, 0x1e, 0x91, 0xdc, 0x94, 0x62, 0xca, 0xe9, 0xbf, 0xae, 0xb5, 0x7d, 0x7b, 0x4f, 0x96, 0x12, 0x3c, 0x80, 0x93, 0xa4, 0xf5, 0x5f, 0x30, 0x30, 0x1a, 0xc1, 0x62, 0x42, 0x42, 0x68, 0x89, 0x4e, 0xe2, 0xc3, 0xa8, 0xb5, 0x38, 0x48, 0x0a, 0x98, 0xca, 0x72, 0x12, 0x08, 0x9a, 0x80, 0x08, 0x34, 0x6b, 0x49, 0x42, 0x9c, 0x0a, 0x28, 0xc2, 0x06, 0xe7, 0x49, 0xc0, 0x87, 0xd6, 0xcc, 0x41, 0x41,\n\t0x8c, 0x05, 0xcc, 0x20, 0x21, 0x82, 0x0a, 0x95, 0x48, 0x3c, 0x4c, 0x88, 0x09, 0x20, 0x26, 0x96, 0xd3, 0xc8, 0xf3, 0x8d, 0x5c, 0x08, 0xb7, 0xce, 0xd8, 0x84, 0x60, 0x55, 0x78, 0x28, 0x9e, 0x0b, 0x25, 0xfb, 0xe2, 0x35, 0xc9, 0x55, 0x53, 0x57, 0x8c, 0x06, 0x51, 0x1d, 0x66, 0xe4, 0xca, 0xab, 0xc0, 0xfd, 0xa9, 0xef, 0x68, 0xab, 0xab, 0x89, 0x96, 0x16, 0xe6, 0xe5, 0xe6, 0xb8, 0x1c, 0x29, 0xd6, 0x64, 0x73, 0x85, 0x46, 0x22, 0x31, 0xa0, 0x48, 0x8f, 0x28, 0x01, 0x3a, 0x94, 0xf6, 0x95, 0x28, 0x84, 0xa3, 0xce, 0x60, 0x64, 0x14, 0x40, 0x89, 0x8d, 0x5b, 0x11, 0x8f, 0x57, 0x88, 0x13, 0xe8, 0x71, 0xa8, 0x4d, 0x2e, 0x47, 0x91, 0x30, 0x9c, 0x83, 0x16, 0x24, 0x82, 0x3f, 0xc3, 0xba, 0xfc, 0xca, 0x78, 0x29, 0xde, 0x9e, 0x6c, 0x24, 0xb7, 0xd9, 0x6b, 0x3c, 0x8b, 0x75, 0x99, 0x66, 0x79,\n\t0x92, 0x7c, 0x53, 0xed, 0xda, 0xd6, 0x8c, 0x75, 0x0b, 0x28, 0xa6, 0xfe, 0x47, 0x37, 0xa8, 0x49, 0xab, 0xb1, 0x4e, 0x5f, 0x5f, 0xa9, 0x01, 0x29, 0xc6, 0x5a, 0xf3, 0x9c, 0xbb, 0x96, 0x14, 0x34, 0xdf, 0xf4, 0xd6, 0x26, 0x25, 0xfa, 0xa6, 0x11, 0xa9, 0xc5, 0xd6, 0xb0, 0x59, 0x01, 0x3f, 0xd7, 0x19, 0x1a, 0xae, 0xcd, 0xad, 0x16, 0xe9, 0xd4, 0xb2, 0x64, 0x77, 0x56, 0xea, 0x60, 0xc3, 0xca, 0x30, 0x86, 0x72, 0xbe, 0x22, 0x95, 0x00, 0xba, 0x9a, 0x86, 0xe4, 0xce, 0x9c, 0xd4, 0x7f, 0xdd, 0x63, 0x83, 0x8f, 0x7c, 0x51, 0xe1, 0xef, 0x1e, 0x52, 0x3d, 0xae, 0xb3, 0xfd, 0x1a, 0x28, 0x4e, 0xea, 0x6c, 0x40, 0xee, 0xdd, 0x7e, 0xfc, 0x97, 0x1b, 0xf7, 0x7d, 0x71, 0xea, 0xda, 0xa4, 0x83, 0x3a, 0xdb, 0xab, 0x50, 0xc1, 0xbc, 0x59, 0x67, 0xfb, 0x5f, 0x63, 0x63, 0xce, 0x80, 0x54, 0xa1, 0x32,\n\t0x59, 0x15, 0xe7, 0x3e, 0x96, 0x16, 0x64, 0x0b, 0x11, 0xb8, 0x13, 0x10, 0xf3, 0x2f, 0x7c, 0xce, 0x24, 0x31, 0x8f, 0x13, 0xd3, 0x88, 0x3f, 0x72, 0x94, 0x41, 0xef, 0x82, 0xcc, 0x7f, 0x1a, 0x54, 0x93, 0x4a, 0x44, 0x50, 0x3f, 0x88, 0xe8, 0xc4, 0x70, 0xcd, 0x68, 0x78, 0x54, 0xf8, 0xe7, 0x60, 0xfc, 0xf3, 0x1e, 0x8e, 0xf7, 0x65, 0x10, 0x8c, 0x40, 0x28, 0x60, 0x84, 0x48, 0x3b, 0x47, 0x80, 0xb1, 0x61, 0x94, 0x9b, 0x4a, 0x48, 0x74, 0xc1, 0xa9, 0xc7, 0x8a, 0xd6, 0x52, 0x4e, 0x53, 0x1f, 0x5b, 0x6c, 0xf4, 0xa6, 0x4c, 0x58, 0x49, 0x24, 0x60, 0x44, 0xf1, 0x4a, 0x04, 0x0a, 0x1d, 0x4d, 0x8a, 0x88, 0x81, 0xb1, 0x6a, 0x44, 0x42, 0xad, 0x68, 0x6e, 0xbc, 0x02, 0x42, 0x36, 0x10, 0xc8, 0x16, 0x80, 0x92, 0x81, 0x2f, 0x8f, 0x41, 0x6a, 0xa6, 0xac, 0x86, 0xa8, 0x91, 0xdb, 0x0f, 0x8f, 0x96,\n\t0xcb, 0xef, 0x50, 0xc7, 0xd2, 0xa1, 0x73, 0x59, 0x3c, 0x79, 0xcb, 0x32, 0x9f, 0x06, 0x2b, 0x1e, 0xbb, 0x65, 0xd2, 0x09, 0x33, 0xaa, 0xb1, 0x3f, 0x3f, 0xe7, 0x78, 0x49, 0x9f, 0x11, 0x9a, 0x15, 0xf9, 0xb6, 0xaa, 0x4e, 0x87, 0xaf, 0xba, 0xb4, 0xc0, 0x2a, 0xd2, 0x48, 0xd5, 0x8a, 0xf6, 0xee, 0xd1, 0x67, 0xee, 0x1d, 0x3d, 0x31, 0x17, 0x27, 0x85, 0xb8, 0xfb, 0xb3, 0xee, 0x6a, 0xa1, 0x4e, 0xa3, 0x0d, 0xb5, 0x6e, 0x9c, 0x89, 0xd2, 0x47, 0x14, 0x2d, 0xbe, 0xa5, 0x63, 0x41, 0xaa, 0x89, 0x91, 0x66, 0x8c, 0x34, 0xda, 0x8b, 0x0c, 0xe4, 0x47, 0x16, 0xe9, 0xd2, 0xb9, 0xec, 0x23, 0x8c, 0x36, 0xc5, 0x67, 0x86, 0x8b, 0xd0, 0xb7, 0x68, 0x24, 0x1e, 0x95, 0x65, 0x68, 0x7e, 0x1b, 0x5c, 0x22, 0x4f, 0x96, 0x07, 0xc5, 0x64, 0x59, 0xfd, 0xf2, 0x8d, 0x5d, 0x4a, 0xf2, 0x45, 0xa3, 0x75, 0xef,\n\t0xbc, 0x61, 0x85, 0x12, 0xad, 0x55, 0x35, 0x54, 0x5b, 0x2b, 0x70, 0x2e, 0xbb, 0x08, 0x9c, 0x0b, 0x34, 0x09, 0xf8, 0x06, 0x1c, 0xd2, 0x1b, 0x94, 0x7f, 0x60, 0x2e, 0x0a, 0x63, 0x8f, 0xc1, 0xad, 0x03, 0x0d, 0x1c, 0x69, 0xc1, 0xb9, 0xed, 0xd4, 0xb1, 0xff, 0x70, 0xb6, 0xf0, 0x38, 0x49, 0x89, 0x9b, 0x85, 0x3e, 0x04, 0xff, 0x60, 0x65, 0x20, 0x9b, 0xfd, 0xe9, 0xfb, 0xaf, 0xbf, 0x4e, 0x15, 0xd2, 0x7f, 0x63, 0xdb, 0x9e, 0x60, 0xcf, 0xad, 0x40, 0x59, 0xa0, 0x56, 0xd0, 0xb2, 0x27, 0x30, 0x8f, 0xcf, 0x83, 0xef, 0x9d, 0xc3, 0x1c, 0x23, 0x2a, 0x88, 0xfa, 0x68, 0x4d, 0x0e, 0x10, 0x49, 0x8c, 0x2a, 0x19, 0x82, 0x41, 0xd7, 0x4b, 0x81, 0x48, 0x08, 0xf9, 0x95, 0x88, 0x80, 0xbd, 0x88, 0x53, 0x4a, 0x89, 0x44, 0xdc, 0x4b, 0x88, 0xc5, 0x4b, 0x31, 0x91, 0xeb, 0xe5, 0x7a, 0x52, 0x51, 0x5e,\n\t0x5c, 0x98, 0x19, 0x80, 0xc4, 0xcd, 0xe8, 0x76, 0x3b, 0xd5, 0x2a, 0x4c, 0xdf, 0x50, 0x24, 0x2e, 0x74, 0xf3, 0x85, 0x1c, 0x3c, 0xc2, 0x21, 0x3b, 0x87, 0xc0, 0xcc, 0x2b, 0xa5, 0xb8, 0x8c, 0xdf, 0x4e, 0x0c, 0x46, 0x4d, 0x48, 0x3b, 0xe8, 0xe1, 0xc5, 0x19, 0x2b, 0xb0, 0x53, 0xcb, 0xd8, 0x19, 0xe0, 0x29, 0x9b, 0x89, 0xdd, 0x1d, 0x09, 0x96, 0x96, 0x90, 0xfb, 0x65, 0x06, 0x9b, 0xf6, 0x7c, 0xa9, 0xa3, 0x34, 0x98, 0x7c, 0xfa, 0xf4, 0x69, 0x9b, 0xe9, 0x86, 0xc8, 0xf2, 0x47, 0x56, 0x34, 0x6f, 0x9a, 0x5d, 0x95, 0xd4, 0x9c, 0x9c, 0x63, 0xd0, 0xfa, 0xb2, 0xcb, 0xfc, 0xc5, 0xbd, 0x25, 0x29, 0xe0, 0x29, 0xf2, 0xe3, 0xed, 0x45, 0x3a, 0xfb, 0xea, 0xda, 0x65, 0x19, 0x8a, 0x36, 0x65, 0xaa, 0x49, 0xb5, 0x59, 0x62, 0xcb, 0x9e, 0x96, 0xf1, 0xe8, 0xf0, 0xf6, 0x62, 0x9d, 0xed, 0x96, 0x59,\n\t0x47, 0x36, 0xd6, 0x7a, 0x2b, 0xfb, 0xf2, 0x72, 0x14, 0x74, 0x52, 0x52, 0xc0, 0xae, 0xf1, 0x35, 0x2c, 0xa9, 0xb8, 0x95, 0xc0, 0x69, 0xa9, 0xa0, 0x24, 0xc1, 0xfc, 0x2f, 0x9c, 0x77, 0x0a, 0xd2, 0x16, 0x39, 0xa4, 0x83, 0x45, 0x44, 0x7f, 0x74, 0xa6, 0x46, 0xa5, 0xa0, 0x18, 0xbd, 0x56, 0x4e, 0x41, 0x69, 0x99, 0x21, 0xe6, 0xc9, 0x04, 0x3a, 0x9a, 0x06, 0x52, 0xb1, 0x10, 0x65, 0xaa, 0x27, 0xe7, 0xaa, 0x81, 0x52, 0x39, 0xd0, 0x20, 0x81, 0x2b, 0x32, 0x5f, 0xd4, 0xa8, 0xd3, 0x49, 0x24, 0xba, 0x22, 0x5d, 0x51, 0x61, 0x41, 0x7e, 0x24, 0x9c, 0x97, 0x13, 0xcc, 0xca, 0xf0, 0xa7, 0xf9, 0xbc, 0x1e, 0xb7, 0xcb, 0xe9, 0xb0, 0xa7, 0x24, 0x5b, 0x92, 0x0c, 0x7a, 0xad, 0x46, 0x22, 0x97, 0xc8, 0x35, 0x7a, 0xb5, 0xca, 0x80, 0x53, 0x57, 0x19, 0x43, 0x90, 0x0c, 0xc1, 0x89, 0x70, 0x7b, 0x9d,\n\t0x7a, 0x0a, 0xa9, 0x86, 0x21, 0x46, 0x1f, 0xd2, 0x8f, 0x05, 0x94, 0xe1, 0xd7, 0x8f, 0x9f, 0x25, 0xce, 0xde, 0x8e, 0xa4, 0xed, 0x90, 0x9e, 0xde, 0xc1, 0x7e, 0x58, 0xf5, 0x1b, 0x21, 0x4d, 0x1d, 0x62, 0x47, 0xab, 0x7e, 0x2f, 0xa0, 0xa8, 0x87, 0xc9, 0x5f, 0x3c, 0x69, 0x33, 0xad, 0x7d, 0x34, 0xc9, 0xae, 0x66, 0x3f, 0x66, 0xef, 0x7c, 0xea, 0xc9, 0x27, 0x9f, 0xb4, 0x25, 0xad, 0x39, 0x9a, 0x9c, 0xac, 0x06, 0x6e, 0x30, 0xef, 0xc9, 0x27, 0x29, 0x66, 0x03, 0xbb, 0x32, 0xa5, 0xc8, 0xfc, 0xc4, 0x8a, 0x0d, 0x1b, 0x48, 0x93, 0xb5, 0xd0, 0xf4, 0xda, 0xf0, 0x86, 0x22, 0x9d, 0x6d, 0xf4, 0x13, 0x8d, 0x0e, 0xfc, 0x73, 0xf4, 0x13, 0x32, 0x79, 0xc5, 0x06, 0x38, 0x3d, 0xa4, 0x57, 0x6e, 0x1c, 0x1d, 0x25, 0xbd, 0xa3, 0xff, 0x8d, 0x8c, 0x27, 0x70, 0x26, 0x32, 0xe0, 0x9e, 0x58, 0x85, 0x73,\n\t0x82, 0xc9, 0xa1, 0x94, 0x55, 0x13, 0xad, 0x94, 0x22, 0xf0, 0xbe, 0x80, 0xc0, 0x50, 0x78, 0xbc, 0x01, 0x06, 0x1a, 0x70, 0x7a, 0x05, 0xb2, 0x47, 0x02, 0x09, 0x06, 0x39, 0x88, 0x74, 0x88, 0xf9, 0x82, 0x46, 0x40, 0x38, 0x1d, 0x29, 0x3c, 0x22, 0x57, 0xaf, 0x55, 0x2a, 0xe4, 0x52, 0xa1, 0x80, 0x46, 0xa0, 0x0e, 0x46, 0xc6, 0xa5, 0x60, 0x8d, 0xd8, 0x93, 0x80, 0x1d, 0xc5, 0x41, 0x03, 0x4e, 0x45, 0x3c, 0x70, 0x1b, 0xce, 0xfe, 0x64, 0x0c, 0x81, 0x7f, 0xdc, 0x79, 0x50, 0x01, 0xd7, 0xfe, 0x69, 0x26, 0xad, 0x69, 0xf5, 0xf4, 0x11, 0xf2, 0x8b, 0xeb, 0xc4, 0xb5, 0x9b, 0x4f, 0xae, 0x1d, 0x79, 0x73, 0xef, 0x5e, 0x50, 0xb4, 0xf9, 0xa5, 0x6b, 0xcb, 0x05, 0x3b, 0xc8, 0xdb, 0xaf, 0xdb, 0x78, 0x81, 0x00, 0xc3, 0xd1, 0xd9, 0x65, 0x29, 0xec, 0x01, 0x44, 0x59, 0x59, 0x21, 0x75, 0xfb, 0x30,\n\t0xb8, 0x33, 0x6f, 0xe1, 0x41, 0x84, 0x73, 0x7a, 0xe7, 0xc2, 0xdf, 0x85, 0x5e, 0xd8, 0x6f, 0x09, 0xec, 0x75, 0x1f, 0xf1, 0x7c, 0x54, 0xd1, 0x07, 0x84, 0x84, 0x1e, 0xea, 0xfa, 0x65, 0x80, 0x92, 0x20, 0xeb, 0x16, 0x72, 0x8d, 0x2b, 0x20, 0x04, 0x42, 0x5a, 0x88, 0x2e, 0x07, 0xc4, 0xb4, 0x84, 0x16, 0x43, 0x9e, 0x2e, 0x25, 0x84, 0x02, 0xa9, 0x70, 0x40, 0x86, 0xd2, 0xf0, 0x8a, 0x11, 0x62, 0x0a, 0x99, 0x8d, 0xe4, 0x5c, 0x2a, 0x34, 0x89, 0x84, 0xea, 0x15, 0x21, 0x1c, 0xc1, 0x7c, 0x44, 0xa4, 0x4a, 0xae, 0xa6, 0x2e, 0x92, 0x9b, 0xe6, 0xa3, 0x16, 0x70, 0x8e, 0x83, 0x15, 0x22, 0x28, 0x0d, 0x38, 0x11, 0x6c, 0x79, 0x66, 0x77, 0x5d, 0x4d, 0x65, 0x45, 0x51, 0x41, 0xc0, 0xef, 0x71, 0x3b, 0xec, 0xb6, 0x14, 0xb3, 0x49, 0xea, 0x94, 0x39, 0x39, 0xf0, 0xb2, 0x42, 0x12, 0xcb, 0xf7, 0xe4,\n\t0x49, 0x00, 0x2f, 0x0b, 0xe1, 0x0e, 0xe0, 0x02, 0xf3, 0xe1, 0x39, 0x03, 0x09, 0x69, 0x3a, 0xe9, 0xc9, 0x49, 0x46, 0xb0, 0x42, 0x46, 0xc7, 0x04, 0x0a, 0xb2, 0xba, 0xf5, 0xda, 0x76, 0xff, 0x83, 0x0f, 0x3e, 0xfe, 0xf8, 0x9e, 0x37, 0xb7, 0x97, 0x65, 0xf6, 0x6c, 0x9d, 0x91, 0x96, 0x0c, 0x7a, 0x5f, 0xcd, 0x4f, 0x66, 0x7f, 0xa9, 0xf6, 0xa6, 0x2d, 0xfb, 0x85, 0xc0, 0x23, 0x37, 0x29, 0xec, 0xe9, 0x05, 0x9e, 0xe2, 0xea, 0xe2, 0x99, 0x8b, 0x66, 0x16, 0xfb, 0x5b, 0xd7, 0xb7, 0xf8, 0x67, 0xd4, 0x96, 0x99, 0xd2, 0x45, 0x46, 0x8d, 0xc6, 0x16, 0x28, 0xce, 0x70, 0xe7, 0x39, 0x54, 0xc5, 0xbd, 0x8b, 0x7b, 0x8b, 0xbd, 0x4d, 0x23, 0x0d, 0xed, 0xbb, 0x33, 0xc9, 0x3f, 0xf9, 0xea, 0x16, 0x94, 0x6c, 0xda, 0x3c, 0xfa, 0x77, 0xf2, 0x44, 0xc1, 0xe2, 0x03, 0x7d, 0x0d, 0x3b, 0x17, 0x37, 0xea,\n\t0x4c, 0xe9, 0xa3, 0x3f, 0xcb, 0x00, 0x5f, 0x26, 0xe9, 0x47, 0x9f, 0x65, 0xee, 0x3d, 0x7f, 0xce, 0xa8, 0xd6, 0xaa, 0x73, 0xfd, 0x2e, 0x7f, 0xaa, 0x2d, 0xb7, 0xb5, 0xa2, 0x68, 0xa0, 0x36, 0x4d, 0x69, 0x71, 0xeb, 0xeb, 0xe4, 0x0a, 0xbd, 0x49, 0xaf, 0xb6, 0xba, 0xf5, 0xde, 0xf4, 0xd4, 0xd4, 0x70, 0x77, 0x5d, 0xce, 0xcc, 0x4a, 0x5f, 0x24, 0x93, 0xc0, 0xd9, 0xea, 0xfa, 0xe1, 0x5f, 0x5f, 0xe2, 0x73, 0x28, 0x23, 0x54, 0x44, 0x12, 0x61, 0x25, 0x3c, 0x44, 0x37, 0xf1, 0x1c, 0x12, 0x9d, 0x45, 0x1a, 0x83, 0x98, 0x94, 0xc6, 0x8d, 0x5c, 0x39, 0x4a, 0xb1, 0x20, 0x89, 0x66, 0x80, 0x42, 0x26, 0x61, 0x68, 0x52, 0x0a, 0x0f, 0xa4, 0x41, 0x47, 0x6a, 0x34, 0x03, 0x0d, 0x66, 0x93, 0x4a, 0x48, 0x31, 0x04, 0x21, 0xea, 0x41, 0xf1, 0x87, 0x68, 0x91, 0x68, 0xb0, 0x41, 0x0e, 0xa4, 0xd2, 0xf9,\n\t0x52, 0x24, 0x48, 0x70, 0x8f, 0xf8, 0x22, 0x90, 0xaa, 0xcd, 0xbb, 0x58, 0x2b, 0x7c, 0x95, 0x9e, 0x68, 0x81, 0xd7, 0x2b, 0x97, 0x7b, 0xbb, 0xbd, 0xdd, 0x5d, 0x9d, 0x1d, 0x6d, 0xd3, 0x5b, 0x1a, 0xeb, 0xaa, 0xab, 0x2a, 0xa2, 0x65, 0x25, 0xdc, 0x41, 0xcf, 0x0d, 0xe5, 0x64, 0x07, 0xb3, 0x32, 0x03, 0x69, 0x3e, 0x0e, 0x84, 0xae, 0x51, 0xcb, 0x55, 0x72, 0x55, 0x92, 0x5a, 0xad, 0xb2, 0xf0, 0x87, 0x5c, 0xe8, 0x34, 0xf2, 0xb7, 0x64, 0x5e, 0xa7, 0x12, 0xc4, 0xbe, 0x50, 0xa1, 0x88, 0xdd, 0x1d, 0xf2, 0x72, 0x19, 0x4f, 0x19, 0xa1, 0x1d, 0x9f, 0x7b, 0xca, 0x49, 0xd9, 0xd1, 0x9f, 0x3c, 0xbb, 0x97, 0x3b, 0xf4, 0x54, 0x88, 0xcb, 0x05, 0x8a, 0x64, 0x8f, 0xb1, 0x4f, 0x54, 0x48, 0x2f, 0xa8, 0x63, 0x3f, 0xf1, 0xbe, 0x9b, 0x74, 0x9f, 0x5f, 0x94, 0x24, 0x15, 0xaa, 0xc5, 0xec, 0x69, 0xcf,\n\t0x71, 0xef, 0x2b, 0x87, 0x3c, 0x22, 0x8d, 0x48, 0x9a, 0x24, 0xda, 0xf7, 0x73, 0x2f, 0xfb, 0x3b, 0xf0, 0xeb, 0xf5, 0x7a, 0x91, 0x41, 0x2c, 0x36, 0x88, 0x28, 0x85, 0x0f, 0x48, 0x6c, 0x49, 0x9f, 0xdd, 0xf1, 0xf1, 0x2d, 0xec, 0x3b, 0xb7, 0x7e, 0x72, 0x07, 0xfb, 0x6b, 0x20, 0xf1, 0xfd, 0xce, 0x96, 0xb4, 0x6f, 0xf5, 0x91, 0x64, 0x2f, 0xd3, 0x07, 0x5a, 0x17, 0xd0, 0x69, 0x96, 0x65, 0x56, 0x2f, 0xbd, 0x00, 0x4c, 0xef, 0x83, 0x1f, 0xef, 0x5e, 0xfd, 0x06, 0x35, 0xf7, 0xd0, 0xf0, 0xd1, 0x9c, 0x0d, 0xd1, 0xf2, 0x0d, 0xd9, 0xc0, 0x7c, 0x08, 0x7d, 0x46, 0x6e, 0xf7, 0x39, 0xf0, 0xf3, 0x70, 0xb7, 0x77, 0x61, 0x28, 0xb4, 0xd0, 0xfb, 0xa3, 0x43, 0x90, 0xca, 0x8e, 0x3e, 0x41, 0xb6, 0xa1, 0x3f, 0xc3, 0xe8, 0x0b, 0x78, 0xdb, 0x62, 0x64, 0x17, 0x82, 0xbb, 0x74, 0x29, 0xdc, 0xbf, 0x7a,\n\t0x2b, 0x9b, 0x37, 0xcc, 0x61, 0x2e, 0x7e, 0x04, 0xa9, 0xc6, 0x87, 0xf4, 0x4e, 0xb8, 0xa2, 0x49, 0x08, 0xcb, 0x47, 0x30, 0x24, 0xe2, 0x67, 0xc3, 0xd8, 0xd0, 0x28, 0x58, 0x2e, 0x16, 0x22, 0x6b, 0x3f, 0x43, 0x90, 0x88, 0xb7, 0x63, 0x7d, 0x0a, 0x9f, 0x32, 0xec, 0x13, 0x9c, 0x24, 0x4f, 0x32, 0x19, 0x74, 0x5a, 0xec, 0x15, 0x2c, 0x73, 0x68, 0xed, 0x12, 0x89, 0x31, 0x1d, 0x11, 0x0a, 0x1c, 0xb1, 0x22, 0x17, 0x85, 0xab, 0x55, 0xdb, 0x1d, 0x1e, 0x7c, 0x45, 0x1a, 0xb2, 0xab, 0x7f, 0x44, 0x96, 0xbc, 0xf0, 0xc4, 0x33, 0xcf, 0xb2, 0xab, 0xe9, 0x05, 0xa3, 0x67, 0x5e, 0x7c, 0xfc, 0x99, 0x67, 0xc1, 0x1e, 0x7a, 0xe7, 0x91, 0x23, 0xac, 0x08, 0x7c, 0x7d, 0xe2, 0xbc, 0x8e, 0xde, 0x79, 0x6e, 0xd3, 0xc3, 0x8f, 0x80, 0xaf, 0x59, 0xd1, 0x09, 0xea, 0x2f, 0x31, 0xfc, 0x10, 0x73, 0x2b, 0xce,\n\t0x0f, 0xef, 0x8f, 0x7a, 0x45, 0x02, 0x92, 0x16, 0xa3, 0xa4, 0xa0, 0x34, 0x98, 0x87, 0xa0, 0x91, 0x03, 0x18, 0x10, 0x3b, 0x9f, 0x68, 0x74, 0x3a, 0xb4, 0x18, 0x13, 0xab, 0x36, 0xd9, 0x24, 0x12, 0x8c, 0xdb, 0x85, 0xa7, 0x0c, 0x05, 0xc7, 0x8c, 0x41, 0xf9, 0x13, 0x63, 0x7a, 0x0a, 0x50, 0x32, 0x24, 0x28, 0x52, 0xde, 0xfa, 0xa2, 0xce, 0xaa, 0x57, 0x0b, 0xd9, 0x72, 0xb5, 0xc7, 0xbe, 0xf2, 0x17, 0xef, 0xbe, 0xfb, 0x8b, 0x6a, 0x4f, 0x96, 0x16, 0xbc, 0xa5, 0xcf, 0x72, 0x9c, 0x64, 0x95, 0xa9, 0xc9, 0xe0, 0x29, 0x76, 0x49, 0xb6, 0x4b, 0x20, 0x55, 0x49, 0xc9, 0x6c, 0x83, 0x81, 0x1a, 0x5d, 0x4d, 0xee, 0x3d, 0x4c, 0xae, 0x18, 0xbd, 0x45, 0x6b, 0x24, 0xf5, 0x16, 0xfd, 0xe8, 0x5b, 0x5e, 0xcd, 0x61, 0x7d, 0x6e, 0xac, 0x8f, 0xf4, 0x09, 0x1c, 0xf7, 0x25, 0x2f, 0x9a, 0x63, 0xd2, 0x6a,\n\t0xd4, 0x2a, 0xa5, 0x02, 0x92, 0x53, 0x06, 0xe5, 0x5c, 0x55, 0xa2, 0xeb, 0x79, 0x9c, 0x7c, 0x15, 0xab, 0xc4, 0x09, 0x59, 0x1f, 0x51, 0x24, 0x96, 0xe4, 0x64, 0x2e, 0xeb, 0xa3, 0x5b, 0xcf, 0xe8, 0x51, 0xba, 0x1e, 0x25, 0xa2, 0x19, 0x4c, 0x9e, 0x3b, 0x8f, 0x81, 0x7b, 0xab, 0x0c, 0x70, 0xf0, 0xbf, 0xbf, 0x00, 0x2b, 0xfb, 0x31, 0xb0, 0x9a, 0xb5, 0x9f, 0xbf, 0xc7, 0xfe, 0x05, 0xe8, 0xd8, 0xbf, 0x98, 0x75, 0x7f, 0x60, 0xc3, 0xf4, 0x42, 0xfa, 0xcf, 0xec, 0xbb, 0xb7, 0x5f, 0x7f, 0xe0, 0xd6, 0xdb, 0xbb, 0x34, 0xe9, 0xe2, 0xcd, 0xa3, 0xbf, 0x03, 0x2f, 0xdf, 0xbc, 0xeb, 0xe6, 0x5b, 0x6f, 0xee, 0xd4, 0xfa, 0x25, 0xeb, 0xc0, 0x2d, 0x28, 0x9c, 0x1b, 0x3c, 0xa1, 0xa5, 0xec, 0x31, 0x71, 0x31, 0xec, 0x5b, 0x80, 0x28, 0x23, 0xda, 0x89, 0x51, 0x2e, 0x2e, 0x4d, 0x2b, 0xce, 0xc7, 0x64,\n\t0x41, 0xff, 0x0a, 0xe2, 0x71, 0x69, 0xf2, 0x08, 0x78, 0xb8, 0x68, 0x66, 0x11, 0x94, 0xfc, 0x68, 0x52, 0xb4, 0x1c, 0xab, 0xee, 0x88, 0x99, 0x0c, 0x20, 0x29, 0x0e, 0xd3, 0xc5, 0xe5, 0x0d, 0x08, 0xba, 0x06, 0xfa, 0xa0, 0x4e, 0x05, 0x30, 0xb5, 0x5c, 0x24, 0x89, 0x05, 0x91, 0x2f, 0xbb, 0x82, 0xca, 0x44, 0x42, 0x5d, 0x04, 0x03, 0x1d, 0xd7, 0x4c, 0x34, 0xca, 0xb5, 0x80, 0x84, 0xc9, 0xef, 0xd6, 0x04, 0x14, 0x30, 0xad, 0x80, 0x68, 0x6f, 0x9b, 0xde, 0x5c, 0x5d, 0x59, 0x54, 0x90, 0x9d, 0x95, 0xe6, 0x75, 0x39, 0xcc, 0x26, 0x9d, 0x46, 0x2a, 0x26, 0x02, 0x20, 0xc0, 0x71, 0xb5, 0x14, 0xa0, 0x41, 0xc1, 0xee, 0x69, 0xa7, 0x3d, 0x12, 0xc3, 0x21, 0x22, 0x20, 0x20, 0xf6, 0xee, 0x0a, 0xc7, 0x0d, 0xc2, 0x25, 0x00, 0x70, 0xb9, 0xb2, 0x60, 0x21, 0x0e, 0x70, 0xaa, 0xe4, 0xef, 0x97, 0x85,\n\t0x48, 0x79, 0xf6, 0x78, 0x21, 0x01, 0x08, 0x3c, 0x79, 0xfe, 0x56, 0x8f, 0x2f, 0xed, 0x91, 0x8f, 0xd8, 0x7f, 0xec, 0x63, 0x1d, 0x96, 0x39, 0xdb, 0x32, 0xf7, 0xc8, 0x0b, 0xf2, 0x57, 0x3e, 0x9c, 0xdc, 0x5e, 0xf9, 0xd6, 0xec, 0xa7, 0xef, 0x18, 0xb1, 0xdb, 0xb4, 0xab, 0x3f, 0x78, 0xac, 0xbc, 0x7f, 0x7a, 0x73, 0xb6, 0x33, 0x8b, 0x59, 0x61, 0xec, 0xcb, 0xcf, 0x1b, 0xec, 0xa9, 0x31, 0x9a, 0x80, 0xa7, 0x36, 0x18, 0xe8, 0x6e, 0x8e, 0xea, 0xde, 0x34, 0xcf, 0xdd, 0xf5, 0xc8, 0xdc, 0xce, 0x9b, 0x66, 0x9a, 0x53, 0x93, 0x87, 0x6e, 0x7e, 0xac, 0xbb, 0x7e, 0x99, 0x73, 0xf5, 0xeb, 0xcc, 0xbd, 0x8b, 0x5e, 0x61, 0xff, 0x75, 0xff, 0x61, 0xf6, 0xeb, 0x57, 0x16, 0xcd, 0x15, 0x3e, 0xff, 0x02, 0x99, 0x1e, 0x0e, 0x8d, 0x0e, 0x0d, 0x3f, 0x98, 0xd3, 0x7a, 0xc7, 0xcf, 0xb7, 0x6d, 0xfd, 0xe0,\n\t0xfe, 0x99, 0xa6, 0x64, 0x53, 0xd0, 0xb1, 0xea, 0xdc, 0x70, 0xcd, 0xb4, 0xf0, 0xc2, 0x3b, 0xe6, 0x2c, 0xba, 0xa5, 0x37, 0x2d, 0x6d, 0xc6, 0xfa, 0x16, 0x59, 0x62, 0x92, 0x98, 0xc2, 0x3c, 0x36, 0x9f, 0x3b, 0xd3, 0x85, 0xec, 0x76, 0x7a, 0x21, 0xf3, 0x29, 0x94, 0x94, 0x1a, 0x88, 0xea, 0xa8, 0xba, 0xa1, 0x3a, 0x9a, 0x6e, 0x64, 0x04, 0x28, 0x83, 0x6d, 0x55, 0x38, 0x8f, 0x22, 0x6b, 0xb8, 0x08, 0xee, 0xc8, 0x84, 0x88, 0xed, 0x5b, 0x0b, 0x1a, 0xb8, 0xb0, 0xdf, 0x18, 0xfe, 0x8c, 0xf3, 0x41, 0x0e, 0x70, 0x0f, 0x7a, 0x9e, 0xaf, 0xaf, 0x75, 0xd8, 0x32, 0x29, 0x89, 0x9e, 0x8f, 0xb9, 0x48, 0xc5, 0xac, 0xe7, 0x48, 0xc1, 0x9a, 0x90, 0x38, 0x85, 0x33, 0xe9, 0x08, 0xbd, 0x5c, 0x21, 0xaf, 0x82, 0x12, 0x4a, 0x51, 0x08, 0x1b, 0x40, 0xee, 0x32, 0x07, 0x8a, 0xec, 0x16, 0xa7, 0x56, 0x64,\n\t0x70, 0x66, 0x9a, 0x92, 0x32, 0x1c, 0xba, 0xf6, 0xac, 0x46, 0x5b, 0xb0, 0xbf, 0x2e, 0x23, 0xd4, 0x3e, 0x54, 0x58, 0xbc, 0xb8, 0x25, 0xd3, 0xe0, 0xcd, 0x4d, 0x4d, 0x9f, 0x5e, 0xea, 0xf6, 0x4c, 0xeb, 0x0f, 0x37, 0xda, 0x0b, 0xfd, 0x26, 0xa3, 0x2f, 0x9c, 0xea, 0x6e, 0x98, 0x56, 0xa8, 0xfb, 0xf1, 0x36, 0x55, 0xda, 0x42, 0x90, 0x44, 0x2f, 0x2f, 0x5f, 0x39, 0xd8, 0x9f, 0x11, 0x5d, 0x3e, 0x6f, 0x66, 0x46, 0x59, 0x7f, 0xb1, 0xd5, 0x5a, 0xd8, 0x7d, 0xbe, 0xad, 0xf9, 0xfa, 0xe2, 0x69, 0x7b, 0x0e, 0xdc, 0xdf, 0xdd, 0x7f, 0xcb, 0x40, 0x28, 0x38, 0xe7, 0xe6, 0x39, 0xa5, 0xd7, 0xed, 0xde, 0x53, 0x19, 0x1e, 0xd9, 0x72, 0x6b, 0x67, 0xd3, 0xb6, 0x65, 0x7d, 0xbe, 0x1a, 0x7b, 0x4b, 0xe7, 0xac, 0x60, 0xb0, 0xaf, 0x6f, 0x66, 0x66, 0xd5, 0x96, 0xa1, 0xee, 0x54, 0xb0, 0x97, 0x7d, 0xc1,\n\t0x4f, 0x1e, 0x46, 0x37, 0x4f, 0x44, 0x2a, 0xfc, 0xeb, 0x1a, 0x9c, 0xab, 0x5e, 0x41, 0xe8, 0xa0, 0x74, 0x3d, 0x10, 0x9d, 0x63, 0x85, 0x1b, 0xaa, 0x4e, 0x29, 0x27, 0x69, 0x19, 0x9a, 0x27, 0x9a, 0x98, 0x2b, 0x55, 0x91, 0x40, 0x22, 0xc4, 0x69, 0x70, 0xa0, 0x30, 0x49, 0x12, 0x22, 0x31, 0x29, 0x42, 0x8e, 0xf7, 0x8a, 0x5e, 0x42, 0xa1, 0x80, 0x5b, 0x53, 0x2c, 0x9e, 0x2f, 0x6e, 0x94, 0x88, 0x09, 0x22, 0x2f, 0x37, 0x98, 0x99, 0x11, 0x48, 0x8f, 0x49, 0x94, 0xf6, 0xd4, 0x14, 0x83, 0x5e, 0xa7, 0x51, 0x29, 0xe5, 0x32, 0xb1, 0x42, 0xa2, 0x40, 0x80, 0x05, 0xb7, 0x06, 0x4d, 0x60, 0x29, 0xc8, 0x2b, 0x06, 0x5e, 0xbb, 0x5e, 0x8b, 0x44, 0x2c, 0xbd, 0xda, 0x8e, 0x04, 0x05, 0xe0, 0x34, 0xe8, 0x90, 0xf8, 0x1d, 0xd2, 0x3b, 0x15, 0x63, 0xce, 0x06, 0x63, 0xf2, 0x16, 0x15, 0x81, 0xdd, 0x62,\n\t0xcb, 0xb7, 0x6c, 0xbe, 0xd5, 0xca, 0xb6, 0x83, 0xa7, 0xcc, 0xb7, 0xee, 0xdc, 0x42, 0xb2, 0x3b, 0xe0, 0xb3, 0x9d, 0xb7, 0x7b, 0xbf, 0xfa, 0xc9, 0x96, 0x1f, 0xdd, 0x0a, 0xff, 0x03, 0x35, 0xcb, 0x1f, 0x5b, 0xdf, 0xa4, 0xbe, 0x85, 0x1a, 0x56, 0xda, 0xd4, 0xf2, 0x24, 0xd9, 0x08, 0xfb, 0xdf, 0x33, 0xe7, 0xbf, 0x4a, 0x52, 0x03, 0xad, 0xec, 0x47, 0xb2, 0x24, 0xb9, 0x3a, 0x55, 0xb5, 0xf8, 0xc1, 0xe7, 0xd9, 0x36, 0x4a, 0xb8, 0x78, 0x64, 0x09, 0x98, 0x1e, 0xe8, 0xb8, 0xb6, 0x95, 0x8f, 0x2f, 0x6a, 0x60, 0xaa, 0xb0, 0x5d, 0xa1, 0x82, 0xa8, 0x8b, 0x56, 0x87, 0xfc, 0xa4, 0x80, 0x2c, 0x96, 0xc0, 0x83, 0x08, 0xc5, 0x24, 0x1a, 0xa5, 0x36, 0xa6, 0x51, 0xaa, 0x74, 0x6a, 0x04, 0xe7, 0x76, 0x16, 0x02, 0x28, 0x58, 0xd2, 0x02, 0x9c, 0x00, 0x68, 0x69, 0xdc, 0xb8, 0x37, 0x44, 0x34, 0x4a,\n\t0xa5, 0xd2, 0x0a, 0x69, 0x85, 0xbb, 0xd9, 0x69, 0x76, 0x65, 0x8a, 0x50, 0x72, 0x66, 0x2e, 0x2f, 0x97, 0x11, 0x60, 0x93, 0x09, 0xa7, 0xb1, 0x47, 0xf8, 0xcc, 0x7e, 0xbc, 0xca, 0xce, 0xa9, 0xe9, 0x50, 0x99, 0xf0, 0x52, 0xfc, 0x61, 0x53, 0xe3, 0xa3, 0x47, 0x81, 0xa5, 0xc7, 0xd6, 0x45, 0xb3, 0xfb, 0x76, 0xb6, 0x93, 0x4f, 0x2c, 0xfb, 0xe7, 0xcd, 0xe9, 0x3e, 0x15, 0xd2, 0xc0, 0x8d, 0xdb, 0x7e, 0x7a, 0x73, 0xd3, 0xdc, 0xe7, 0x00, 0x38, 0x2c, 0x47, 0x2a, 0xbb, 0x76, 0xdf, 0xbb, 0xd3, 0x91, 0x23, 0xaf, 0x29, 0x5c, 0xd3, 0x5b, 0xb2, 0x54, 0x91, 0xa2, 0x0a, 0xb6, 0x35, 0xd6, 0x38, 0x1f, 0xd2, 0x27, 0xd1, 0x5f, 0x8a, 0xda, 0xf7, 0x9f, 0xb9, 0x66, 0xc9, 0xd3, 0x37, 0xcc, 0x36, 0x91, 0xc2, 0xd1, 0xff, 0x6a, 0x6e, 0xa2, 0x1e, 0xd3, 0xd9, 0xfe, 0x96, 0xbc, 0xf5, 0x85, 0xbf, 0xec,\n\t0xfe, 0x1e, 0x10, 0x9d, 0x1e, 0x16, 0xdc, 0xa8, 0xb3, 0x9d, 0x96, 0xce, 0xa9, 0x43, 0x8e, 0xbd, 0x72, 0x87, 0xcd, 0xcc, 0x9c, 0x7b, 0x02, 0x00, 0xa9, 0x2e, 0x45, 0x03, 0x32, 0x78, 0xbf, 0x5e, 0x8a, 0x18, 0x84, 0x3c, 0x67, 0x98, 0x97, 0x6f, 0xfc, 0x48, 0xd7, 0x12, 0x03, 0x52, 0x06, 0xea, 0xe5, 0x50, 0xae, 0x51, 0x2a, 0x24, 0x14, 0xd2, 0xf7, 0xe6, 0x21, 0x36, 0x84, 0xd8, 0x11, 0x03, 0xe8, 0xb9, 0x84, 0x4c, 0x36, 0x80, 0xa1, 0xfa, 0xf3, 0x19, 0xc8, 0x12, 0xe5, 0x7e, 0xf9, 0x98, 0x5a, 0x61, 0x53, 0x3b, 0xb5, 0x76, 0x35, 0x92, 0x35, 0x54, 0x58, 0xd7, 0x12, 0xda, 0x41, 0x4c, 0xa2, 0x00, 0x46, 0xb8, 0xdc, 0x5a, 0x4c, 0x4e, 0xec, 0xf8, 0x1e, 0x19, 0xd9, 0xe2, 0x50, 0xd2, 0x39, 0x6d, 0x48, 0x6b, 0xd7, 0x53, 0xdb, 0xd8, 0x77, 0x0a, 0xc1, 0x11, 0xf6, 0xcc, 0x2f, 0xa6, 0x89,\n\t0xf4, 0x12, 0xa9, 0x4e, 0x04, 0x6e, 0x2c, 0xfd, 0xd3, 0x73, 0xf7, 0x3d, 0x9c, 0xec, 0x16, 0x6e, 0x1b, 0x3d, 0xbf, 0x4d, 0xe0, 0xb5, 0x3c, 0x7c, 0xdf, 0x93, 0xbf, 0x2d, 0x85, 0x42, 0xc4, 0x8c, 0xb3, 0xbf, 0x3a, 0x0b, 0x7a, 0xc8, 0xcf, 0x1e, 0x07, 0x05, 0x6f, 0x25, 0xd7, 0xf8, 0xfd, 0xb5, 0x56, 0xf6, 0xd8, 0xe3, 0x7b, 0xd9, 0x06, 0x8b, 0x11, 0xec, 0x60, 0xaf, 0xd5, 0xa5, 0x80, 0x93, 0x7b, 0x1f, 0xdf, 0x47, 0x3a, 0x46, 0x3f, 0xdc, 0x87, 0x78, 0x55, 0xef, 0x85, 0xcf, 0xe9, 0xb9, 0xcc, 0xe3, 0x44, 0x0b, 0xd1, 0x12, 0x6d, 0xd4, 0x40, 0xe5, 0xbd, 0xa5, 0xb9, 0xa1, 0xbe, 0xae, 0x16, 0xf5, 0x16, 0xf9, 0xe8, 0x01, 0x25, 0x0d, 0x0a, 0xa0, 0x1a, 0x4b, 0xd5, 0x13, 0xf8, 0xb6, 0x19, 0xe1, 0x72, 0x28, 0xf8, 0xff, 0xf2, 0x58, 0x48, 0x3e, 0xac, 0x4e, 0xe2, 0x5b, 0xc7, 0x21, 0xa6,\n\t0xb1, 0xac, 0x24, 0x2f, 0x37, 0x3b, 0xcb, 0xed, 0xf4, 0x09, 0x50, 0x9a, 0x00, 0x66, 0x2c, 0x16, 0xeb, 0x84, 0xb8, 0x01, 0x46, 0x21, 0x27, 0x42, 0xb9, 0xc7, 0xd2, 0xb5, 0x8d, 0x85, 0x2a, 0xe4, 0x9c, 0x70, 0xbd, 0x11, 0x58, 0x3d, 0xe2, 0x7e, 0x8c, 0xf4, 0x65, 0x44, 0x52, 0x4b, 0x7a, 0x8b, 0xa7, 0xcd, 0xae, 0xca, 0xd2, 0xa0, 0x88, 0x02, 0x0d, 0x6f, 0xad, 0x1f, 0x7a, 0x6c, 0x55, 0x71, 0xc0, 0x7d, 0xd4, 0xfc, 0xa5, 0xb3, 0xd9, 0x07, 0x46, 0xcc, 0xac, 0x24, 0xad, 0x36, 0x37, 0xc5, 0x5d, 0x35, 0x50, 0x3a, 0x63, 0xe5, 0x8c, 0x88, 0x41, 0x69, 0x16, 0x95, 0xa4, 0xcd, 0x5f, 0xbd, 0xbd, 0x6a, 0xf5, 0x89, 0x4d, 0xe5, 0x46, 0x7f, 0xa1, 0xe3, 0x4d, 0x0b, 0x08, 0xf9, 0xdb, 0x7d, 0x6c, 0x94, 0x16, 0xec, 0x72, 0xf6, 0x94, 0xfa, 0xaa, 0xf3, 0xe2, 0x51, 0x07, 0x4a, 0x16, 0x5d, 0xdf,\n\t0xd0, 0x3c, 0x12, 0x48, 0x1b, 0x2c, 0x34, 0x7a, 0x35, 0x3d, 0x83, 0xeb, 0xf4, 0x59, 0xc5, 0x8d, 0xc1, 0x9c, 0xda, 0x2c, 0x63, 0x20, 0x2f, 0xa0, 0x92, 0x0d, 0xa6, 0x57, 0x65, 0x5b, 0x50, 0x82, 0xa7, 0x50, 0x47, 0x4d, 0x61, 0x52, 0x70, 0x61, 0xbd, 0xce, 0xad, 0x5d, 0xc6, 0x9f, 0x11, 0x25, 0x3e, 0x23, 0x25, 0x08, 0x8f, 0x6a, 0x83, 0xf3, 0xe3, 0x03, 0x04, 0x95, 0x0d, 0xf5, 0x4d, 0x09, 0x94, 0x26, 0x54, 0x80, 0x04, 0x0c, 0x8a, 0x48, 0x41, 0x8f, 0x40, 0x35, 0x4c, 0x48, 0x20, 0xf3, 0x8b, 0x50, 0x00, 0xff, 0x5f, 0x8e, 0x12, 0x61, 0xae, 0x8a, 0x59, 0xbc, 0x96, 0x72, 0x2c, 0x0b, 0x12, 0xda, 0x21, 0xd0, 0xe8, 0x81, 0x1a, 0xa5, 0xd9, 0x95, 0xac, 0x12, 0x21, 0x63, 0x00, 0x7f, 0x58, 0xdc, 0x68, 0x13, 0x5c, 0xfc, 0xa8, 0x70, 0x16, 0xad, 0x31, 0x47, 0x64, 0x8a, 0x5c, 0xfc, 0xf8,\n\t0xc6, 0xca, 0xf0, 0x9c, 0xeb, 0xa6, 0x93, 0x6b, 0xbb, 0x47, 0x9f, 0x11, 0xa3, 0x73, 0x52, 0x6b, 0xd8, 0xfa, 0x93, 0x5b, 0x9a, 0x07, 0x5f, 0x00, 0xe0, 0x1e, 0x39, 0xfa, 0xaa, 0x5d, 0xf9, 0x5c, 0x4d, 0xb5, 0x10, 0xaa, 0xb3, 0xfe, 0x92, 0xee, 0xd2, 0xc5, 0x4c, 0xe9, 0x40, 0x5b, 0xbd, 0x0b, 0xdb, 0xae, 0xe8, 0x7f, 0xd0, 0x2d, 0xfb, 0x7e, 0xb4, 0x79, 0xf9, 0x89, 0xdd, 0x33, 0xb5, 0xba, 0x45, 0x23, 0x47, 0x74, 0xb6, 0x4f, 0xf4, 0x9b, 0x5e, 0xfe, 0xd7, 0xcd, 0x87, 0x81, 0xfc, 0xf5, 0x65, 0x60, 0xb7, 0xce, 0xf6, 0x03, 0x55, 0x6f, 0xe5, 0x80, 0x54, 0x61, 0xf5, 0x78, 0x25, 0xe7, 0x5e, 0x52, 0xa6, 0x64, 0xd9, 0xb1, 0x9d, 0x8a, 0x26, 0x74, 0x17, 0xbe, 0x14, 0x64, 0xc3, 0xb3, 0x21, 0x86, 0xf4, 0xa2, 0x81, 0xe8, 0x21, 0xbe, 0x88, 0x2a, 0x6a, 0xa0, 0x88, 0x5e, 0x01, 0x28, 0xb1,\n\t0x1b, 0xbb, 0x7d, 0x70, 0xd7, 0x2b, 0x45, 0x52, 0x00, 0x55, 0x70, 0xa1, 0x18, 0x65, 0x63, 0x84, 0x14, 0x85, 0x11, 0xa0, 0x58, 0xbf, 0x14, 0x29, 0xa4, 0x90, 0x5d, 0x42, 0xd4, 0x23, 0x07, 0x48, 0xe2, 0xc7, 0xc0, 0x12, 0x19, 0xc7, 0xe2, 0xd1, 0xd4, 0xd0, 0x88, 0x9b, 0xc7, 0x03, 0x0a, 0x17, 0x4c, 0x6a, 0x02, 0xd6, 0x22, 0x24, 0x42, 0x91, 0x64, 0x5e, 0xbc, 0xad, 0x8b, 0x34, 0x10, 0x2d, 0xb9, 0xba, 0xba, 0xbc, 0x3c, 0x81, 0xad, 0x24, 0x2b, 0x70, 0xa8, 0xbc, 0xa4, 0x69, 0xd3, 0x7a, 0xba, 0xbb, 0x3a, 0x5a, 0x67, 0x34, 0x37, 0x4e, 0x6b, 0x98, 0xd6, 0x90, 0xe5, 0xf4, 0x66, 0xb8, 0x34, 0x70, 0x67, 0x4b, 0xc6, 0xfc, 0xed, 0x20, 0xd9, 0xbe, 0xb4, 0x72, 0x87, 0xae, 0x31, 0x04, 0x31, 0xdd, 0x0e, 0x70, 0xa7, 0x5e, 0x09, 0x00, 0x3e, 0x1b, 0x76, 0xbc, 0xce, 0x20, 0xc4, 0x34, 0x49,\n\t0xac, 0xe6, 0x7d, 0xe7, 0x7e, 0x27, 0x4d, 0xd1, 0xdf, 0x4c, 0xff, 0x58, 0x69, 0x90, 0xa5, 0xa6, 0xe5, 0x39, 0x4a, 0xca, 0x0a, 0x3a, 0xe7, 0x77, 0x16, 0x78, 0xeb, 0x87, 0xaa, 0xbc, 0xcd, 0x50, 0xbd, 0x0b, 0x0a, 0x74, 0x32, 0xa5, 0x33, 0xab, 0xd4, 0x3f, 0xad, 0xcc, 0x1e, 0xae, 0xaa, 0xad, 0x0a, 0xdb, 0x5d, 0x35, 0x83, 0x15, 0xf5, 0x9b, 0x03, 0xe7, 0x7e, 0xd4, 0x22, 0x54, 0x8a, 0x84, 0x4a, 0x61, 0x0b, 0xf8, 0xe5, 0x6a, 0x9d, 0x49, 0x90, 0xcd, 0xfe, 0x77, 0x36, 0x6d, 0xd6, 0xac, 0x05, 0x29, 0x77, 0x33, 0x9b, 0xe4, 0xda, 0x6f, 0x77, 0x28, 0xd4, 0x64, 0x9d, 0x41, 0xa9, 0x51, 0x66, 0xb8, 0x6d, 0x2e, 0xb3, 0x39, 0xb3, 0xa1, 0x24, 0xa7, 0xbb, 0xdc, 0xa3, 0x48, 0x72, 0xe9, 0xeb, 0x45, 0x32, 0x5d, 0x92, 0x2e, 0x94, 0x6e, 0x71, 0x18, 0x55, 0x3a, 0x6b, 0x56, 0x55, 0x28, 0xad,\n\t0xa9, 0xd8, 0xed, 0x77, 0x81, 0xca, 0x5f, 0x6b, 0x82, 0x56, 0x6b, 0x50, 0xf3, 0x6b, 0xf6, 0xff, 0x74, 0x8a, 0xdd, 0xbb, 0xe5, 0x7a, 0xf2, 0x37, 0xdc, 0xfd, 0xde, 0xe3, 0x70, 0xf1, 0x37, 0x51, 0xff, 0x05, 0x37, 0x78, 0x11, 0x67, 0x9c, 0x57, 0xc3, 0x59, 0x1b, 0x6c, 0x88, 0x65, 0x0e, 0x47, 0x32, 0x2d, 0xca, 0xfc, 0xca, 0x27, 0x15, 0x8f, 0x3f, 0xeb, 0x89, 0x4a, 0x13, 0x33, 0x8a, 0xbb, 0x71, 0x46, 0x71, 0x7a, 0xd3, 0xf9, 0xe0, 0xd6, 0x6d, 0xdb, 0xa8, 0xff, 0x3a, 0xff, 0x34, 0x6e, 0x7b, 0x19, 0x6c, 0xbb, 0x84, 0x6e, 0x47, 0x81, 0x5f, 0xa3, 0x86, 0x58, 0x26, 0x6a, 0x8a, 0x5b, 0x4b, 0x28, 0x16, 0xbb, 0x50, 0x1a, 0x71, 0x6d, 0x4c, 0xc6, 0xe0, 0xe2, 0x94, 0x60, 0x93, 0xa0, 0xda, 0xb9, 0x0c, 0x81, 0xd9, 0x10, 0xa8, 0x6d, 0x6b, 0x4e, 0xff, 0xae, 0xb6, 0xb6, 0x5d, 0xfd, 0x39,\n\t0x5b, 0xc9, 0xcd, 0xb3, 0x8f, 0x6e, 0x6b, 0x6c, 0xdc, 0x76, 0x74, 0xf6, 0xe8, 0x76, 0x72, 0x73, 0xd3, 0xf6, 0x59, 0x79, 0x79, 0xb3, 0xb6, 0x37, 0x8d, 0x6e, 0x87, 0xd4, 0xfc, 0x36, 0xb8, 0x3f, 0xbf, 0xa2, 0x2b, 0xe0, 0x27, 0x21, 0x21, 0x25, 0x02, 0xd1, 0x34, 0xde, 0xe0, 0x89, 0x7c, 0xcb, 0x20, 0xaf, 0x07, 0x73, 0x09, 0x9a, 0x61, 0xe8, 0x0e, 0x3e, 0x08, 0x1c, 0xcd, 0x34, 0x71, 0x0e, 0x66, 0x02, 0xc8, 0xd0, 0xb4, 0xf6, 0xb1, 0x6b, 0x80, 0xdb, 0xa8, 0x79, 0xe7, 0x0f, 0xc5, 0xfe, 0x90, 0x7f, 0x3d, 0x00, 0xfe, 0x74, 0x60, 0xf4, 0x2f, 0x07, 0x60, 0x5b, 0xd7, 0xc0, 0x91, 0x6e, 0x61, 0x0e, 0xc1, 0x53, 0x22, 0x41, 0x19, 0x55, 0xc4, 0x22, 0xa8, 0x44, 0x11, 0x02, 0xa2, 0x16, 0x35, 0x8f, 0xd0, 0x09, 0x70, 0x38, 0x1a, 0x2d, 0x09, 0xa7, 0x41, 0x4c, 0xaa, 0xed, 0x5a, 0x35, 0xd4,\n\t0x8c, 0x22, 0xf4, 0x67, 0xac, 0x82, 0x55, 0x50, 0x9f, 0xdc, 0xfa, 0xed, 0xd7, 0xe4, 0x0e, 0x40, 0xad, 0x07, 0x4b, 0xd9, 0x3b, 0x46, 0x93, 0xa8, 0xbc, 0xf3, 0xf9, 0xd4, 0x8f, 0xc0, 0x7b, 0x80, 0x9b, 0xfb, 0xbb, 0x40, 0x1f, 0x75, 0x8e, 0xfc, 0x3f, 0x38, 0x8d, 0xa5, 0x9c, 0x61, 0xdf, 0x80, 0xe4, 0x33, 0xb0, 0x10, 0x43, 0xb0, 0x3a, 0xd0, 0x46, 0xee, 0x41, 0xac, 0xbc, 0xc9, 0x12, 0xd5, 0x63, 0x36, 0x3d, 0xf1, 0x79, 0xcf, 0x49, 0x38, 0x0a, 0x94, 0xc9, 0x05, 0xd8, 0xf5, 0x08, 0x95, 0x77, 0x6e, 0x34, 0x65, 0x2b, 0x35, 0x8f, 0xec, 0xf8, 0x06, 0xa0, 0x84, 0xee, 0x00, 0x44, 0xd8, 0x28, 0x55, 0x2a, 0xe8, 0x24, 0xf4, 0x44, 0xc9, 0x49, 0x64, 0xfa, 0x45, 0x77, 0xb7, 0x99, 0xd8, 0x2d, 0x8e, 0xb3, 0x6d, 0xa2, 0xb3, 0xb2, 0x04, 0xc9, 0x85, 0x7a, 0x9e, 0xa0, 0xc1, 0x32, 0x5d, 0xbc,\n\t0xd4, 0x48, 0x80, 0x96, 0x9e, 0x93, 0x7a, 0xaf, 0x0b, 0x37, 0x1f, 0xbf, 0x18, 0xa1, 0xf8, 0xf5, 0x01, 0x91, 0xe2, 0xc1, 0x1b, 0x9a, 0x9c, 0x4d, 0x36, 0x19, 0x25, 0xd6, 0xda, 0x92, 0x0a, 0xbb, 0x8a, 0xac, 0x2f, 0x51, 0x7f, 0x3d, 0xf5, 0xf9, 0xee, 0x5c, 0xb9, 0xba, 0x4d, 0xa6, 0x14, 0x52, 0xbe, 0x85, 0xcf, 0xde, 0xf8, 0x6d, 0x23, 0x01, 0x2e, 0x7c, 0xca, 0x2e, 0x06, 0x5f, 0x30, 0xef, 0x11, 0x46, 0xa2, 0xf0, 0xa4, 0x84, 0xc7, 0x34, 0x07, 0xb0, 0x74, 0x4a, 0x92, 0x0b, 0x70, 0x9a, 0x7b, 0x24, 0x6a, 0x2c, 0x41, 0xbb, 0x4c, 0x85, 0xf3, 0x0b, 0x27, 0x3c, 0x42, 0x1d, 0xf0, 0xa0, 0x0e, 0xb8, 0x75, 0x5c, 0x50, 0xc1, 0x48, 0x29, 0x17, 0x95, 0x4f, 0x1d, 0x02, 0x5f, 0x58, 0x72, 0x2a, 0xdb, 0x67, 0x87, 0x9c, 0x8d, 0x36, 0x29, 0xdf, 0x85, 0xc2, 0x94, 0x97, 0xde, 0xbd, 0xf6, 0x95,\n\t0xdd, 0x33, 0xc3, 0x86, 0x58, 0x1f, 0x16, 0x3d, 0x7b, 0x23, 0x23, 0x86, 0x7d, 0xf8, 0x09, 0x69, 0x12, 0x28, 0xc8, 0x83, 0x70, 0x4f, 0x98, 0xf0, 0x4c, 0x12, 0xa0, 0x03, 0xbd, 0xa5, 0x07, 0xeb, 0x78, 0x6a, 0x15, 0x5a, 0x39, 0x14, 0x8b, 0x4b, 0xa0, 0xf8, 0xe6, 0xb4, 0x20, 0x4a, 0x9a, 0xb6, 0xa2, 0xd9, 0x79, 0x92, 0x95, 0x51, 0x99, 0x82, 0x87, 0x60, 0x1d, 0x63, 0x54, 0x87, 0x40, 0xd5, 0x60, 0x04, 0x76, 0x6a, 0x31, 0x96, 0x23, 0x28, 0x35, 0x16, 0x99, 0x91, 0xf3, 0x74, 0xe6, 0x56, 0xc1, 0x43, 0xff, 0x5a, 0x24, 0x3a, 0x48, 0xf0, 0x75, 0xf0, 0x7b, 0x18, 0x22, 0x25, 0x6a, 0x99, 0x72, 0xc5, 0xe2, 0xeb, 0x85, 0x50, 0x94, 0x02, 0xc5, 0xa8, 0x6d, 0x2b, 0x35, 0x87, 0x34, 0x9d, 0xfb, 0x07, 0xbd, 0x17, 0xc5, 0x81, 0xf8, 0x09, 0x7a, 0x67, 0xbc, 0x3e, 0x6c, 0x00, 0xd6, 0x87, 0x02,\n\t0x36, 0xaa, 0x8f, 0xf6, 0x19, 0x09, 0xe2, 0xf5, 0xb1, 0x03, 0x19, 0x7c, 0xf9, 0xa8, 0x8d, 0x9a, 0xc3, 0xca, 0x68, 0xd9, 0x56, 0xee, 0xfd, 0x68, 0x9c, 0xb0, 0xcf, 0x0c, 0xc6, 0x74, 0xf2, 0x47, 0x16, 0x75, 0x20, 0x76, 0x72, 0x49, 0xa2, 0x39, 0xf1, 0xd4, 0x02, 0x7c, 0x6a, 0x05, 0x8a, 0xf3, 0xf7, 0x6f, 0x25, 0x0f, 0x6e, 0xa5, 0xf7, 0x9e, 0xfb, 0x07, 0xde, 0x97, 0x68, 0xbe, 0xf0, 0xd8, 0x19, 0xc2, 0x15, 0xb5, 0xc3, 0xba, 0x78, 0x55, 0x62, 0xb3, 0x36, 0x13, 0x7b, 0x22, 0x8d, 0x6b, 0x06, 0xfb, 0xa7, 0x52, 0x99, 0xe7, 0xef, 0x27, 0x7f, 0x2b, 0x78, 0xe8, 0xdc, 0xea, 0xad, 0xb4, 0x8c, 0xdb, 0xdf, 0x0f, 0xb2, 0xcb, 0x84, 0x67, 0x21, 0x4f, 0x69, 0x23, 0xee, 0x7e, 0xbe, 0x35, 0xe8, 0xa1, 0x04, 0x4c, 0x0c, 0xd1, 0xee, 0x92, 0x40, 0x32, 0xce, 0x30, 0xe9, 0x0d, 0x22, 0x80, 0xa2,\n\t0x52, 0x20, 0x80, 0x61, 0x6e, 0x1c, 0x8f, 0x18, 0x44, 0xdb, 0x22, 0x27, 0x9e, 0x13, 0xc0, 0x81, 0x26, 0x11, 0x8e, 0x63, 0x60, 0xca, 0x3a, 0x5c, 0x49, 0x34, 0x5c, 0x7e, 0xba, 0x2f, 0x52, 0x12, 0x5f, 0x54, 0x68, 0x60, 0xeb, 0x6d, 0x44, 0x9b, 0x1b, 0x12, 0x1f, 0x5f, 0xda, 0x7a, 0xdd, 0x1a, 0x29, 0x4a, 0xf1, 0xa9, 0xe6, 0x09, 0x3c, 0x17, 0x6a, 0x38, 0xe1, 0x8e, 0x9f, 0xcb, 0x3e, 0xcb, 0xbb, 0xcd, 0xf0, 0x22, 0x4d, 0x02, 0xe2, 0x22, 0x1e, 0x4e, 0x27, 0xa2, 0x16, 0x9e, 0xcd, 0xdf, 0xf7, 0xf9, 0xf3, 0xbe, 0x6b, 0xf7, 0xee, 0x09, 0x37, 0xcf, 0xce, 0xd5, 0x80, 0x7c, 0x95, 0x46, 0x4c, 0x99, 0x9b, 0x6f, 0x5a, 0x93, 0xb9, 0xfd, 0xfa, 0x0d, 0xde, 0xf5, 0x47, 0x06, 0x33, 0x6c, 0x2d, 0xb3, 0x57, 0x56, 0x54, 0xaf, 0xea, 0x9d, 0x66, 0xb0, 0xcd, 0x5a, 0xb1, 0xa9, 0x64, 0xd5, 0xe3,\n\t0xab, 0x0a, 0xde, 0x4f, 0x6b, 0x5c, 0x5c, 0x5e, 0x3e, 0xdc, 0x9a, 0xf9, 0xbe, 0xbd, 0x62, 0x41, 0xd5, 0xa2, 0x47, 0x43, 0xcc, 0xbd, 0xdf, 0x9e, 0x59, 0x70, 0xcf, 0xe2, 0x08, 0x94, 0xd2, 0xc4, 0x7a, 0xa7, 0x45, 0xaa, 0x31, 0xca, 0xb2, 0x6a, 0xb3, 0x93, 0xe0, 0x57, 0x7d, 0xa8, 0xa3, 0xec, 0x99, 0xa2, 0xd9, 0xd3, 0x5c, 0xee, 0xca, 0xb9, 0x25, 0x55, 0xf3, 0xa3, 0x29, 0x35, 0x37, 0xbe, 0xb9, 0x8d, 0xba, 0xf9, 0xfc, 0x70, 0xdf, 0xde, 0x59, 0xc1, 0xac, 0x59, 0x7b, 0xfb, 0xd1, 0xe7, 0xce, 0x3d, 0x73, 0x73, 0x0f, 0xdc, 0x4a, 0xfd, 0x96, 0x9b, 0xfb, 0x42, 0x48, 0x7b, 0x47, 0x98, 0x87, 0x09, 0x27, 0x50, 0x45, 0x95, 0x5a, 0x0d, 0x54, 0x74, 0x90, 0x1b, 0x27, 0x24, 0xbe, 0x74, 0x0c, 0x62, 0x68, 0xe6, 0x7d, 0xb4, 0x90, 0x41, 0x99, 0xec, 0x15, 0x30, 0x24, 0x4e, 0x8f, 0x8e, 0x33,\n\t0xbf, 0x5b, 0x38, 0x72, 0x34, 0x45, 0x89, 0xd0, 0x58, 0x09, 0xd9, 0x65, 0xdb, 0x50, 0x5f, 0xb6, 0x0d, 0xed, 0x65, 0xdb, 0xd0, 0x5f, 0xa6, 0x8d, 0x4b, 0x55, 0xef, 0x19, 0x03, 0x73, 0x38, 0x09, 0xa7, 0xd1, 0xeb, 0xd3, 0xaa, 0x85, 0xc2, 0xa4, 0xb1, 0x58, 0xe8, 0x3c, 0x59, 0xe3, 0x38, 0x3c, 0xbe, 0x8a, 0xc2, 0xa1, 0x61, 0x47, 0xde, 0xdb, 0xf0, 0xdb, 0xd3, 0xf7, 0xad, 0x28, 0x49, 0x9b, 0xb9, 0x6f, 0xc0, 0x92, 0xae, 0x45, 0xeb, 0x10, 0xae, 0xf1, 0xa9, 0x1a, 0xbe, 0xf7, 0xaf, 0x63, 0x5c, 0x30, 0x72, 0x9b, 0x5d, 0x14, 0x5e, 0x7e, 0x74, 0xfd, 0xdc, 0xc3, 0xab, 0xa2, 0x34, 0x3d, 0x4b, 0xad, 0x97, 0xd2, 0x59, 0xcd, 0x83, 0xe1, 0xe5, 0x37, 0x16, 0xab, 0x33, 0xa0, 0x06, 0x8a, 0xe2, 0x5f, 0x2e, 0xc3, 0xf1, 0xc8, 0x83, 0xc4, 0xc1, 0xe7, 0x02, 0x04, 0x29, 0x88, 0xfb, 0xf3, 0xb8,\n\t0x08, 0x28, 0x3d, 0x0a, 0x09, 0x24, 0x34, 0x09, 0xd3, 0x91, 0x64, 0x12, 0xc0, 0x48, 0x67, 0xce, 0xb7, 0x31, 0x88, 0x24, 0xf0, 0x1c, 0x2a, 0xe6, 0xcb, 0xe3, 0x88, 0x97, 0xa5, 0x00, 0xb5, 0x8a, 0x41, 0x5e, 0x75, 0x08, 0x49, 0x3d, 0x3f, 0x5e, 0x95, 0x8b, 0x11, 0x91, 0x58, 0x28, 0x16, 0x82, 0x1d, 0x39, 0x98, 0x53, 0xcc, 0xb8, 0xa2, 0x38, 0xd5, 0x91, 0xc5, 0x9e, 0xa6, 0x81, 0xff, 0xa3, 0x9c, 0x7b, 0x7c, 0x08, 0x74, 0x0e, 0x21, 0x80, 0x2e, 0xeb, 0x12, 0x2e, 0xc0, 0xb9, 0xdd, 0x3d, 0x29, 0x36, 0x7a, 0xde, 0xca, 0xa7, 0x37, 0x46, 0x07, 0x73, 0x1b, 0x4a, 0xc8, 0x08, 0xda, 0xde, 0x86, 0xbc, 0x9e, 0xca, 0xbc, 0xc1, 0xe2, 0xc6, 0xc1, 0xe2, 0xa4, 0xc8, 0xf5, 0x9f, 0x3c, 0x99, 0x18, 0x34, 0x7d, 0x55, 0xdf, 0x2d, 0xf3, 0xf3, 0x24, 0xfe, 0xb0, 0x54, 0x6d, 0x90, 0xa5, 0xd7, 0x86,\n\t0xac, 0x12, 0x63, 0xb8, 0x3b, 0x0a, 0xf6, 0xf7, 0x5e, 0x93, 0xa7, 0xce, 0xe0, 0x02, 0xa9, 0x03, 0x62, 0x0e, 0xd4, 0x57, 0xe4, 0x50, 0x5f, 0xa9, 0x22, 0x32, 0xa3, 0xe9, 0x0e, 0x9c, 0x4f, 0x7c, 0xcc, 0x77, 0x90, 0xd3, 0x3f, 0x43, 0xf1, 0x20, 0x45, 0xf0, 0xf4, 0x66, 0xf9, 0xb4, 0x59, 0x5e, 0x06, 0xae, 0x9e, 0x36, 0xc1, 0x39, 0x58, 0xa7, 0xc0, 0xd1, 0xbe, 0x27, 0xa9, 0x1d, 0x02, 0xec, 0x6d, 0xcc, 0x5d, 0x2e, 0x22, 0x3d, 0xe5, 0xe3, 0x8c, 0x60, 0x70, 0xfe, 0xdd, 0x4b, 0x07, 0xee, 0x5a, 0x94, 0x17, 0xe9, 0x5d, 0xbd, 0x6e, 0x75, 0x6f, 0x64, 0xff, 0xb5, 0x50, 0xc7, 0x08, 0x23, 0x1d, 0xa3, 0x34, 0x6d, 0xfe, 0x9a, 0x6d, 0x58, 0xc7, 0xc8, 0xef, 0x5d, 0xb3, 0x71, 0x4d, 0x6f, 0xfe, 0xf2, 0x05, 0xd9, 0x8d, 0x21, 0x8b, 0x42, 0xa5, 0x50, 0xaa, 0xa9, 0xe5, 0xd9, 0xc3, 0xb5, 0xd1,\n\t0x0d, 0x73, 0x8a, 0x72, 0xfb, 0xb7, 0x35, 0xf6, 0xef, 0x9c, 0x5b, 0x59, 0x10, 0xae, 0xe8, 0x2e, 0x5d, 0xb6, 0x6a, 0x4c, 0xab, 0x28, 0x1d, 0xbe, 0x77, 0x56, 0xfb, 0xfa, 0xee, 0x68, 0x38, 0x5c, 0xd5, 0x5b, 0xde, 0x3a, 0x27, 0x39, 0xb3, 0xc8, 0x66, 0xf6, 0x5a, 0xf5, 0x62, 0xb5, 0x41, 0xc2, 0xe5, 0x22, 0xfe, 0x04, 0x12, 0xca, 0x25, 0x70, 0x9c, 0x24, 0x61, 0x47, 0xb7, 0x8a, 0x76, 0x2d, 0x5c, 0x49, 0x14, 0xd4, 0x87, 0x41, 0x2e, 0xa3, 0x98, 0x34, 0x85, 0x1a, 0x50, 0x30, 0x08, 0x2c, 0x48, 0x04, 0x90, 0x43, 0x4a, 0x4a, 0xb2, 0xd9, 0xa4, 0x90, 0x49, 0x44, 0x50, 0x3f, 0x23, 0x09, 0x52, 0x88, 0xf2, 0xd9, 0x8a, 0x01, 0x63, 0x47, 0x82, 0x26, 0x0a, 0x45, 0x8b, 0x06, 0x9e, 0x0a, 0x30, 0x27, 0xb4, 0x72, 0x37, 0xe9, 0x74, 0x2e, 0xbb, 0x9a, 0x5d, 0x45, 0xb7, 0x7c, 0xbb, 0x81, 0xac,\n\t0x35, 0x94, 0xdc, 0x39, 0xbd, 0x6a, 0x75, 0x68, 0xc1, 0xec, 0x2e, 0x97, 0x4e, 0xe7, 0xea, 0x9a, 0xbd, 0x20, 0xb4, 0xba, 0x6a, 0xfa, 0x1d, 0x25, 0x86, 0x63, 0xe4, 0x4f, 0x46, 0x73, 0x8e, 0xd1, 0x4a, 0xef, 0xd2, 0xde, 0xeb, 0xd3, 0x4c, 0xe1, 0xee, 0x32, 0x97, 0xab, 0xac, 0x3b, 0x6c, 0x4a, 0xbb, 0xbe, 0x77, 0xa9, 0x0f, 0xdb, 0x0b, 0x16, 0x5c, 0xf8, 0x9c, 0x69, 0x64, 0xbe, 0xc2, 0x36, 0xa5, 0x75, 0x27, 0x7d, 0x3c, 0xa7, 0x46, 0x02, 0xa1, 0x07, 0x52, 0x51, 0x46, 0x80, 0xb2, 0x90, 0x62, 0xf5, 0x30, 0x3d, 0xbe, 0x2a, 0x61, 0xa8, 0x1b, 0xf3, 0x40, 0xdf, 0x5c, 0x84, 0xd0, 0x70, 0xf1, 0x05, 0xb9, 0x1c, 0xb6, 0x03, 0x63, 0x15, 0x12, 0x8b, 0x41, 0x11, 0x5c, 0xa7, 0x03, 0x84, 0xae, 0x41, 0xd7, 0x50, 0x13, 0x0d, 0xe7, 0x06, 0xfc, 0x2e, 0xab, 0x54, 0x4c, 0x68, 0x81, 0x56, 0x2c,\n\t0x4c, 0xc8, 0x85, 0xc6, 0xaf, 0x5d, 0xa2, 0xdf, 0x03, 0x26, 0xcf, 0x89, 0xee, 0xf1, 0x78, 0xa5, 0xe9, 0x18, 0xa1, 0x8e, 0x90, 0x1f, 0xf6, 0xdf, 0xbe, 0xb8, 0xa0, 0x60, 0xf1, 0xed, 0xfd, 0x08, 0x5a, 0x05, 0xff, 0x25, 0x07, 0xd0, 0x36, 0x35, 0x45, 0x57, 0xf6, 0x38, 0x3b, 0x3b, 0xa7, 0x27, 0xcf, 0xda, 0x3b, 0xb7, 0x40, 0x56, 0xf8, 0xeb, 0x63, 0x7b, 0x3e, 0x39, 0xdc, 0x3d, 0xf3, 0xc1, 0x3f, 0xec, 0xb9, 0xfd, 0xd3, 0x07, 0x3b, 0x35, 0x59, 0x6d, 0xdb, 0x4e, 0x6e, 0x48, 0x6d, 0xeb, 0xe9, 0xf1, 0x44, 0x6a, 0xd3, 0x54, 0xe0, 0xb1, 0xec, 0xd9, 0xbb, 0xbb, 0xba, 0x6e, 0x9c, 0x9b, 0x9b, 0xd1, 0xb1, 0x79, 0xc6, 0x9c, 0x3b, 0x17, 0x85, 0x99, 0x46, 0x99, 0xc6, 0x24, 0xcb, 0x69, 0xca, 0xb3, 0x40, 0x2a, 0xec, 0x9f, 0x75, 0x70, 0xf9, 0xfc, 0xa1, 0x96, 0x9b, 0xce, 0xae, 0xb9, 0xe6,\n\t0xed, 0x03, 0x6d, 0xb3, 0x9e, 0xb9, 0xf0, 0xc0, 0xd2, 0x1f, 0x1c, 0xdb, 0x33, 0x3f, 0x8c, 0xe9, 0xb5, 0xdb, 0xc2, 0xd1, 0x5d, 0x2f, 0x1c, 0x6a, 0x2d, 0x8e, 0x59, 0xed, 0x8f, 0x7a, 0xf9, 0xa9, 0x18, 0x16, 0xa0, 0x7d, 0x4d, 0x50, 0x5c, 0x68, 0x47, 0x3c, 0x81, 0x01, 0x14, 0xe6, 0x20, 0x4d, 0x67, 0x57, 0xab, 0x50, 0x66, 0x65, 0xee, 0xbe, 0x31, 0x91, 0xff, 0xe0, 0x60, 0x26, 0x76, 0xba, 0x96, 0xed, 0x7c, 0xef, 0x7b, 0xfe, 0x7c, 0x87, 0x12, 0x94, 0xa8, 0x75, 0x12, 0xca, 0x58, 0x38, 0xa7, 0xfe, 0x91, 0xf7, 0xc0, 0x51, 0xea, 0xaf, 0xe7, 0x35, 0xd4, 0x5f, 0xc5, 0x46, 0x4f, 0xb2, 0x4c, 0x67, 0x94, 0x85, 0x9a, 0x72, 0x92, 0x00, 0xc9, 0xb2, 0xf8, 0xfd, 0x5b, 0xd8, 0xe5, 0xcc, 0x67, 0xd4, 0xd7, 0x44, 0x13, 0xf1, 0xe4, 0xf3, 0x8d, 0x99, 0x31, 0x9e, 0xeb, 0x1b, 0xe3, 0xb9, 0x99,\n\t0x09, 0x5c, 0x91, 0xcb, 0x94, 0xd8, 0x37, 0x9e, 0xe7, 0xfa, 0x71, 0x12, 0x50, 0x8e, 0x93, 0xce, 0x1f, 0x5f, 0x07, 0x27, 0x57, 0x44, 0x1f, 0xb9, 0xd5, 0x8c, 0x73, 0xdf, 0x40, 0x22, 0xf7, 0xbd, 0x74, 0x1d, 0x3a, 0xc6, 0x87, 0x9b, 0x88, 0x26, 0xa7, 0xde, 0xa9, 0xf7, 0x4c, 0xe6, 0xc3, 0x9e, 0x84, 0x79, 0x30, 0xa2, 0xe5, 0x35, 0xc4, 0xf8, 0xb0, 0x27, 0x91, 0x0d, 0x1b, 0xe2, 0x5c, 0x18, 0x07, 0x08, 0x50, 0x33, 0x9f, 0x05, 0x46, 0x7e, 0x78, 0x4f, 0x4a, 0x65, 0x55, 0xa5, 0xb5, 0xb1, 0x3f, 0xa4, 0x05, 0x98, 0x4a, 0x59, 0x5b, 0xf6, 0xac, 0xb0, 0x94, 0x44, 0xcb, 0x2c, 0xfd, 0x5b, 0x5a, 0x1c, 0xc9, 0x25, 0xd5, 0x2d, 0x19, 0x0b, 0x36, 0x5b, 0x8d, 0xd5, 0x9d, 0xf3, 0xb2, 0x67, 0x6c, 0xe9, 0xca, 0x3c, 0x33, 0x7f, 0x96, 0xbf, 0xb1, 0xc0, 0x71, 0x66, 0x76, 0x6f, 0xe9, 0x50, 0x06,\n\t0xf5, 0xf5, 0xf9, 0xc1, 0xa1, 0x7b, 0x16, 0x04, 0x21, 0x03, 0x01, 0x22, 0xc4, 0x7f, 0x21, 0x61, 0x4f, 0xaf, 0x0b, 0x25, 0x03, 0xf4, 0x40, 0x95, 0xd5, 0x59, 0xdd, 0x6a, 0x8f, 0xf8, 0x0c, 0x83, 0xbd, 0xe1, 0xe6, 0x6c, 0x53, 0x68, 0xe0, 0xa6, 0x3e, 0x14, 0xad, 0x7c, 0xe5, 0x1a, 0x6b, 0x61, 0x67, 0x01, 0xfa, 0xb4, 0x66, 0x65, 0x45, 0x01, 0xf9, 0x25, 0xb7, 0x07, 0xa6, 0xb3, 0x0f, 0x53, 0x6f, 0xd0, 0x02, 0xc2, 0x8d, 0x72, 0x76, 0x23, 0x95, 0x57, 0xa9, 0x51, 0x43, 0x06, 0xec, 0x8a, 0x33, 0x60, 0x4b, 0x54, 0xa3, 0x06, 0x0c, 0xa9, 0x81, 0x54, 0x3a, 0xf6, 0x10, 0x43, 0x3d, 0x1c, 0x53, 0x33, 0xbb, 0x70, 0x3c, 0x41, 0x74, 0x4a, 0xec, 0x47, 0xe4, 0x9e, 0x91, 0xd9, 0x40, 0xf0, 0xa8, 0xb0, 0x58, 0x01, 0x8e, 0xd7, 0xb9, 0x09, 0xb7, 0xcf, 0xeb, 0x71, 0x26, 0xf0, 0xba, 0x98, 0xeb,\n\t0x14, 0x22, 0x92, 0x63, 0xcc, 0x8e, 0x93, 0x5d, 0xa8, 0x37, 0xce, 0xf6, 0xdd, 0x13, 0xed, 0x84, 0xfb, 0xf8, 0x7b, 0x47, 0x2d, 0x7e, 0x2d, 0x90, 0x6a, 0x8d, 0x32, 0x7f, 0xa9, 0x4f, 0xeb, 0x8c, 0x76, 0xe7, 0x85, 0xb7, 0x36, 0x53, 0x5f, 0x7f, 0xfb, 0x04, 0xe9, 0x37, 0xea, 0xb2, 0x96, 0x1c, 0xdd, 0xf4, 0xce, 0xfb, 0x0c, 0xd5, 0x84, 0xd8, 0x5d, 0xa0, 0x61, 0x41, 0x41, 0xdb, 0xaa, 0x5a, 0xbb, 0x4a, 0x4d, 0x7e, 0x0f, 0xae, 0xba, 0xfa, 0xc2, 0x17, 0xd4, 0x3f, 0x69, 0x09, 0xa1, 0x84, 0x8b, 0xfa, 0x07, 0xee, 0x82, 0x50, 0x59, 0x05, 0x80, 0x48, 0x4b, 0x41, 0x25, 0x23, 0x0f, 0x40, 0xc5, 0x1c, 0x45, 0x4d, 0x82, 0x4f, 0xc4, 0x09, 0x4f, 0x78, 0x64, 0x4b, 0x9a, 0x04, 0xb9, 0x9c, 0x32, 0x84, 0x10, 0x71, 0x2d, 0x8a, 0x64, 0x28, 0x74, 0x7d, 0x2b, 0xea, 0x95, 0x8a, 0x49, 0x91, 0x28,\n\t0xcc, 0x45, 0x3e, 0x45, 0xde, 0xf5, 0xb9, 0x64, 0xec, 0x46, 0x22, 0x63, 0x52, 0x05, 0x14, 0x8d, 0x2b, 0xb3, 0x01, 0x57, 0x23, 0x26, 0x55, 0x8a, 0x66, 0x8f, 0x2b, 0x4f, 0x4f, 0x55, 0x9e, 0xa6, 0x03, 0x5c, 0x25, 0x02, 0xd7, 0x81, 0x1b, 0x34, 0x55, 0xa5, 0x02, 0x84, 0xaa, 0x49, 0xd5, 0x38, 0xad, 0xbc, 0x20, 0x92, 0x95, 0xe1, 0xf7, 0x79, 0xdc, 0x4e, 0x7b, 0xb2, 0x19, 0x36, 0xa3, 0x04, 0x4a, 0x99, 0x90, 0xbb, 0x48, 0x1f, 0x8b, 0x59, 0x91, 0xe8, 0xec, 0x9a, 0x49, 0x63, 0x76, 0x9a, 0x78, 0x13, 0x3c, 0xc1, 0x8f, 0xa1, 0x14, 0x53, 0x6f, 0xf0, 0xcf, 0xe6, 0xa5, 0x7e, 0xff, 0xaa, 0x86, 0x74, 0x38, 0xd7, 0xda, 0xb4, 0x28, 0x19, 0x50, 0x07, 0x6d, 0x59, 0xa1, 0xac, 0xd9, 0x37, 0xcd, 0xc9, 0x69, 0x2c, 0xcc, 0x4c, 0xf7, 0x9b, 0xfd, 0x95, 0xd2, 0xbb, 0x75, 0xbb, 0xd6, 0xe6, 0xcf,\n\t0xa8, 0x6b, 0x09, 0x87, 0xea, 0x33, 0x0d, 0xd6, 0x92, 0x43, 0x0b, 0x67, 0x6c, 0x68, 0x4d, 0x4b, 0x6b, 0xbb, 0xb6, 0x7d, 0xf6, 0xc3, 0xd3, 0x18, 0x21, 0x23, 0x10, 0x2b, 0x4c, 0x7a, 0xf2, 0x28, 0x5c, 0xd7, 0xb0, 0x36, 0xc5, 0xa3, 0xd1, 0xb8, 0x53, 0xb4, 0xa0, 0x39, 0x34, 0x94, 0x57, 0x7b, 0x7c, 0xe1, 0xbc, 0xa3, 0x5b, 0xea, 0x74, 0x56, 0xa7, 0x55, 0x17, 0x29, 0xdb, 0x71, 0x9b, 0x3f, 0xc7, 0x9f, 0xd9, 0xbe, 0xba, 0x66, 0x79, 0x4f, 0x5e, 0x79, 0x5a, 0x65, 0x4f, 0x56, 0x56, 0x4f, 0x95, 0xbf, 0x20, 0x2c, 0xd6, 0x4a, 0x14, 0x7a, 0xb9, 0x10, 0xed, 0xd7, 0xca, 0x0b, 0x9f, 0x53, 0x73, 0x68, 0x11, 0x51, 0x81, 0x78, 0xb1, 0x1d, 0xc0, 0xed, 0x38, 0x89, 0x17, 0x87, 0xc7, 0xf1, 0x62, 0x8f, 0xf3, 0xd2, 0xbc, 0x78, 0x4a, 0x56, 0x6c, 0x40, 0x9c, 0xf8, 0x25, 0xa3, 0x35, 0x6d, 0xfa,\n\t0xba, 0xe9, 0xf5, 0x6b, 0x5b, 0xd3, 0x33, 0xea, 0xfa, 0xe7, 0xf5, 0xd7, 0x65, 0xac, 0x1a, 0xac, 0x9c, 0x5d, 0x15, 0xd4, 0xa7, 0x6a, 0x32, 0x52, 0xda, 0x16, 0xac, 0x2a, 0x9d, 0x05, 0x89, 0x77, 0x66, 0xfd, 0xec, 0xf9, 0xb3, 0xeb, 0x33, 0xdb, 0x2b, 0x9c, 0x11, 0xaf, 0x5e, 0xad, 0x56, 0x90, 0x3b, 0x53, 0x6b, 0xfd, 0xbe, 0xae, 0xea, 0x4c, 0x7f, 0xdd, 0x40, 0x41, 0x69, 0x4f, 0x45, 0xd0, 0xe7, 0x0a, 0x44, 0x3c, 0x15, 0x33, 0x2c, 0xf6, 0x64, 0x6b, 0x97, 0x25, 0xd3, 0xae, 0x09, 0xcc, 0x18, 0xa9, 0x29, 0xea, 0x2c, 0xcb, 0xf4, 0xba, 0x33, 0x8b, 0xd3, 0x0b, 0x2b, 0x34, 0xa9, 0x3e, 0x83, 0x29, 0x55, 0xac, 0x52, 0x0b, 0x38, 0x1e, 0xfc, 0x4f, 0x48, 0x93, 0x57, 0xc3, 0x81, 0x38, 0xb9, 0x88, 0x41, 0x12, 0x28, 0x6d, 0xb8, 0x1d, 0x5a, 0x9a, 0x86, 0x3c, 0xb8, 0x9e, 0x8e, 0x3b, 0xa8,\n\t0x84, 0xb9, 0x6c, 0x43, 0x3d, 0x9c, 0xec, 0xe8, 0x72, 0xb9, 0x3c, 0x2e, 0x8f, 0xd3, 0xef, 0xf4, 0xa8, 0xd0, 0x39, 0x4a, 0x03, 0x91, 0x50, 0x8c, 0x03, 0x87, 0x13, 0x58, 0xb0, 0x81, 0xe7, 0xc1, 0xc0, 0x29, 0x06, 0xf4, 0xea, 0x73, 0xdb, 0xe7, 0x01, 0xb0, 0x4c, 0x9c, 0xb1, 0x38, 0x1c, 0xce, 0xcc, 0x71, 0xd7, 0x57, 0x97, 0x5b, 0xc4, 0x12, 0x4b, 0x79, 0x75, 0xbd, 0x2b, 0x94, 0x91, 0x17, 0x5e, 0x92, 0x21, 0x02, 0x43, 0xdf, 0x67, 0x7f, 0xcf, 0xfe, 0xfe, 0x3e, 0x32, 0xaa, 0xa8, 0xaa, 0x1a, 0x52, 0x6b, 0x94, 0xae, 0xa2, 0x74, 0xa5, 0x32, 0xbd, 0xc8, 0x05, 0x09, 0xc4, 0x50, 0x55, 0x95, 0x7c, 0xf4, 0x35, 0xf0, 0x1a, 0x5b, 0x8e, 0xf9, 0xf1, 0xca, 0x0b, 0x5f, 0xd2, 0x65, 0xcc, 0xbb, 0x84, 0x9a, 0x98, 0x46, 0x2c, 0x3f, 0xe9, 0xe2, 0xf9, 0x31, 0x32, 0xc1, 0x39, 0x50, 0x67, 0x05,\n\t0xbd, 0xc8, 0x6f, 0x14, 0xb3, 0x12, 0x4c, 0x57, 0x11, 0xb5, 0xe5, 0x7d, 0x0b, 0x73, 0xb1, 0xfb, 0x61, 0x8c, 0x50, 0x24, 0x16, 0x4e, 0x2c, 0xd2, 0x13, 0x35, 0x02, 0xa2, 0xac, 0xa4, 0xb8, 0x30, 0x27, 0xe8, 0xf3, 0xd8, 0x52, 0xac, 0x16, 0xc8, 0x85, 0xd5, 0x40, 0x3d, 0x99, 0x0b, 0x1b, 0xc6, 0x98, 0xb0, 0x67, 0x4a, 0x1e, 0xac, 0x89, 0x7b, 0x0f, 0x47, 0xc8, 0xae, 0xaa, 0xa5, 0xb5, 0x1e, 0x4f, 0xed, 0xd2, 0xaa, 0xba, 0xe5, 0x75, 0xee, 0xdb, 0xc0, 0x3f, 0x15, 0x2a, 0x21, 0xa9, 0x09, 0xb6, 0x55, 0x64, 0xcf, 0xf2, 0xd6, 0x0c, 0x4f, 0xcf, 0x16, 0xe6, 0x9e, 0xd8, 0xd5, 0xf7, 0xc0, 0xba, 0xaa, 0x9a, 0xad, 0x27, 0x96, 0xed, 0x7d, 0x69, 0x65, 0x56, 0xe6, 0xb2, 0xe7, 0x6e, 0xc8, 0x98, 0x13, 0x76, 0x67, 0x25, 0x4b, 0xc1, 0x8d, 0x79, 0xb3, 0xb6, 0x35, 0x36, 0x6e, 0xea, 0x0a, 0x66,\n\t0xb5, 0x2e, 0x2b, 0x3d, 0x7d, 0x86, 0xa9, 0x95, 0x28, 0x35, 0x62, 0x5f, 0xa9, 0xdf, 0x20, 0x8c, 0xac, 0x3b, 0x7d, 0x43, 0xff, 0xb2, 0xba, 0xed, 0xcf, 0x2c, 0x59, 0xf2, 0xc2, 0xee, 0xe6, 0x45, 0xcf, 0x7c, 0xba, 0xe3, 0x29, 0xe0, 0x7d, 0x6f, 0x9d, 0x50, 0xa0, 0x30, 0xaa, 0x39, 0x8c, 0x34, 0x7b, 0x8c, 0x3a, 0x82, 0x79, 0x2e, 0xb2, 0xfd, 0xf0, 0x3c, 0x17, 0x73, 0x5a, 0x12, 0x4b, 0x1e, 0xc8, 0xe5, 0x18, 0x1f, 0xf8, 0xe0, 0x15, 0x71, 0x5d, 0xea, 0x08, 0x7b, 0xe4, 0xec, 0xd2, 0xf1, 0x5c, 0x77, 0xd5, 0x59, 0x30, 0x93, 0xea, 0x38, 0xd7, 0x49, 0x1f, 0x8d, 0x73, 0xdd, 0x2a, 0xbf, 0x1a, 0x45, 0xfe, 0xc2, 0xfe, 0x5c, 0xb9, 0x42, 0x1d, 0x83, 0x62, 0x61, 0x44, 0x08, 0x47, 0x34, 0x15, 0xd9, 0x08, 0x48, 0x02, 0x59, 0x22, 0xe1, 0xd6, 0xea, 0xe2, 0x51, 0xe6, 0x24, 0x68, 0x09, 0x04,\n\t0x02, 0x1e, 0xde, 0xe4, 0x85, 0xc4, 0x16, 0x64, 0x59, 0xa4, 0x11, 0xbd, 0x88, 0xe8, 0x52, 0xe0, 0xf7, 0x52, 0x1a, 0x41, 0x46, 0x50, 0xfa, 0x84, 0x19, 0xa5, 0x2b, 0x0f, 0x9d, 0xfe, 0xcd, 0xba, 0x6b, 0x3e, 0x3c, 0x7d, 0x68, 0xb8, 0xb4, 0x74, 0xf8, 0xd0, 0xe9, 0x0f, 0xaf, 0x41, 0x9f, 0x57, 0x96, 0x36, 0xe5, 0x2f, 0xbc, 0xf9, 0xa9, 0xb7, 0x96, 0x2d, 0x7b, 0xeb, 0xa9, 0x9b, 0x17, 0xe6, 0x27, 0x7e, 0x26, 0x6f, 0x5f, 0xf7, 0x9b, 0xef, 0xc3, 0x02, 0xb0, 0xe2, 0xf7, 0x13, 0x2b, 0xfe, 0x66, 0x3d, 0xfc, 0xfd, 0x16, 0x54, 0xf6, 0x16, 0x54, 0xf6, 0xcd, 0xe3, 0x5c, 0xbd, 0xe3, 0x6f, 0x72, 0x7c, 0x6a, 0xe0, 0xc2, 0xe7, 0x22, 0x26, 0x16, 0x83, 0xd9, 0x01, 0x18, 0x22, 0x92, 0x4b, 0x0a, 0x84, 0x5c, 0x94, 0x1f, 0x09, 0x88, 0xe7, 0x72, 0x43, 0x81, 0x38, 0x97, 0x8b, 0x71, 0x26, 0x2e,\n\t0x14, 0xf4, 0xcb, 0x86, 0xb9, 0x79, 0x3c, 0xda, 0x4f, 0x75, 0x65, 0x79, 0x99, 0x53, 0xeb, 0x42, 0x00, 0x40, 0x9f, 0x4b, 0x8a, 0x63, 0x18, 0x8d, 0x4b, 0x0d, 0x91, 0x98, 0xb9, 0x8d, 0x43, 0xf8, 0xc5, 0xd1, 0x7f, 0xa4, 0x5a, 0xa5, 0xc1, 0x3c, 0x28, 0xa4, 0x46, 0x57, 0x45, 0x1a, 0xb5, 0x2a, 0x76, 0xc9, 0xe0, 0xa5, 0x7f, 0x90, 0x5c, 0xd1, 0xdc, 0x97, 0xbf, 0xfb, 0xf5, 0x4d, 0x05, 0x0d, 0xfb, 0x7f, 0xba, 0x73, 0xdb, 0xcf, 0xda, 0xda, 0x7e, 0xb6, 0x6d, 0xe7, 0x4f, 0xf7, 0x37, 0x14, 0x6c, 0x3c, 0xb3, 0x7b, 0xf9, 0x5d, 0xf9, 0x01, 0xa9, 0x56, 0xa1, 0xb0, 0x65, 0x4d, 0xcb, 0xbe, 0xef, 0xc8, 0xa9, 0xa7, 0x7b, 0x6f, 0x2b, 0x78, 0xbf, 0xe0, 0xd6, 0xde, 0x67, 0x5e, 0x3a, 0x72, 0x5f, 0x70, 0x5a, 0x96, 0x1d, 0xf9, 0x2e, 0x31, 0x59, 0x96, 0x0c, 0xbb, 0x76, 0xe5, 0x19, 0xf6, 0xdb,\n\t0x3b, 0x8e, 0xb3, 0x7f, 0x3e, 0xbd, 0xa0, 0xaf, 0xa3, 0xa3, 0x6f, 0xc1, 0x69, 0x60, 0x38, 0x7e, 0x07, 0x10, 0x9c, 0x59, 0x59, 0x1d, 0x5e, 0xa2, 0x96, 0x1a, 0x93, 0x8d, 0xec, 0xa7, 0xec, 0xdf, 0xd9, 0xbf, 0xb2, 0x7f, 0xaa, 0x29, 0x03, 0x7f, 0x60, 0xcd, 0x65, 0x35, 0xc0, 0x04, 0x34, 0x40, 0x0e, 0xf4, 0xd8, 0xe1, 0x87, 0xcf, 0x79, 0x72, 0xe1, 0x73, 0x61, 0x29, 0x94, 0xdf, 0x23, 0xc4, 0x2d, 0x27, 0x8d, 0x28, 0x1e, 0x64, 0x3d, 0x77, 0xab, 0x9e, 0x1d, 0x87, 0x21, 0x49, 0x81, 0x04, 0x48, 0x25, 0xc3, 0x22, 0x40, 0x8b, 0x01, 0x90, 0x22, 0x47, 0x67, 0x04, 0x8e, 0xe4, 0x43, 0xf5, 0x4a, 0x24, 0x09, 0x3e, 0x38, 0x05, 0x97, 0xa8, 0x83, 0x4b, 0x0b, 0x85, 0xb1, 0x18, 0xd7, 0xd8, 0x29, 0x04, 0x55, 0x8e, 0x39, 0x7f, 0x69, 0xc2, 0xb9, 0x99, 0x01, 0x9f, 0x57, 0xe7, 0x74, 0xbb, 0x50,\n\t0xa6, 0x50, 0x07, 0x72, 0x4a, 0x75, 0xf3, 0x97, 0x07, 0xbc, 0x37, 0x08, 0xa6, 0x47, 0x89, 0xd8, 0x4a, 0x84, 0x87, 0x48, 0x49, 0xb8, 0x59, 0x10, 0x96, 0x76, 0xfc, 0xfd, 0xd8, 0x4d, 0xff, 0x77, 0x6c, 0x81, 0x84, 0xfd, 0xc9, 0xfb, 0xef, 0x83, 0x5c, 0xc5, 0xb2, 0xe3, 0x7f, 0xde, 0x7b, 0xfb, 0xc7, 0x1d, 0x08, 0x4e, 0xa9, 0xc9, 0x6e, 0x5e, 0xdd, 0xd9, 0x77, 0xef, 0x35, 0x0d, 0x32, 0xf2, 0xba, 0xd1, 0xf5, 0xe2, 0xa6, 0xf5, 0xf7, 0xf5, 0x14, 0xce, 0x6a, 0xae, 0x72, 0x62, 0xfc, 0xe5, 0x5b, 0x8b, 0x46, 0xe6, 0x1e, 0xff, 0xea, 0xc0, 0xe8, 0x5a, 0xe6, 0xde, 0xd1, 0x9b, 0x6e, 0xfa, 0xcb, 0x63, 0xfd, 0x03, 0xed, 0x1c, 0x8e, 0xb2, 0x74, 0xcd, 0xd1, 0xa1, 0xc3, 0xab, 0x9e, 0xdd, 0x54, 0x1e, 0xbf, 0x49, 0x40, 0xf4, 0xf6, 0x5b, 0x48, 0x66, 0xae, 0xc3, 0xf7, 0xaf, 0x66, 0x84, 0x9c,\n\t0xa0, 0x51, 0xd4, 0xb8, 0x7a, 0x21, 0x22, 0x47, 0xc8, 0x02, 0x3c, 0x17, 0x67, 0xe0, 0xe5, 0x82, 0xff, 0x21, 0x7d, 0x07, 0xa5, 0x44, 0xe6, 0xb1, 0x15, 0x62, 0x74, 0x9d, 0x2a, 0x42, 0x41, 0x33, 0x29, 0xee, 0x2e, 0x8d, 0xe2, 0x7c, 0x49, 0x31, 0xda, 0x83, 0xf3, 0xc9, 0x0c, 0x51, 0xd7, 0x5c, 0x2f, 0x35, 0xcb, 0xa4, 0x49, 0xb2, 0x5d, 0xd4, 0xa6, 0xa3, 0xc9, 0x2e, 0xd1, 0xff, 0xde, 0xfa, 0xe6, 0xfe, 0xff, 0x15, 0xb9, 0x2c, 0xc7, 0xc8, 0x39, 0x6f, 0x93, 0x5f, 0x81, 0x16, 0xeb, 0xf4, 0xcc, 0xac, 0xe9, 0x29, 0xec, 0xb3, 0xa3, 0xd2, 0x64, 0x03, 0xe9, 0x1f, 0x7d, 0x88, 0xec, 0x1b, 0x7d, 0x5f, 0x9b, 0x0a, 0x7b, 0x43, 0xe2, 0x3c, 0x99, 0xff, 0x83, 0xfb, 0xe5, 0x40, 0x58, 0x18, 0x1a, 0x81, 0x5a, 0xeb, 0xc5, 0x52, 0x92, 0x10, 0xd0, 0x24, 0xee, 0x19, 0xc2, 0x13, 0x26, 0x35, 0x08,\n\t0x19, 0x24, 0x91, 0xe1, 0xbe, 0x25, 0xa6, 0x6d, 0x4e, 0xec, 0xa3, 0xec, 0x92, 0x7d, 0xe4, 0xd7, 0x03, 0x84, 0x98, 0x9f, 0x5c, 0xa4, 0xaf, 0x80, 0x60, 0xc3, 0xef, 0xbf, 0x4f, 0x4a, 0x41, 0xea, 0x25, 0xfa, 0x0c, 0xff, 0x7e, 0x08, 0x4e, 0x78, 0x0f, 0xf9, 0x08, 0xec, 0xbb, 0x81, 0x20, 0x04, 0x83, 0x38, 0x9e, 0x7f, 0x3e, 0x8a, 0xb8, 0xc3, 0xa0, 0x64, 0xb2, 0xf5, 0xf0, 0x20, 0xc2, 0x9f, 0x04, 0xe4, 0x30, 0x37, 0xb3, 0x60, 0x39, 0x8e, 0x0d, 0x89, 0xc3, 0xaf, 0xc6, 0xe6, 0x57, 0xad, 0xd6, 0x7b, 0xcb, 0xb5, 0x5e, 0xbb, 0x05, 0x87, 0x17, 0x4b, 0xa1, 0x8c, 0xa5, 0x54, 0x04, 0x1e, 0x5b, 0x2e, 0xba, 0x1c, 0x95, 0x0e, 0x84, 0xb8, 0xdf, 0x5e, 0xbc, 0x5d, 0xb8, 0xdb, 0x4a, 0xae, 0x00, 0x2c, 0x49, 0x7e, 0xdf, 0xe4, 0x4d, 0x35, 0x88, 0x84, 0xc6, 0x54, 0xaf, 0x09, 0x28, 0xcf, 0xff,\n\t0x99, 0x3e, 0x71, 0xd4, 0xe2, 0x16, 0xdd, 0xa6, 0xf5, 0xe5, 0xb7, 0x14, 0x96, 0x91, 0xf4, 0x5b, 0x80, 0x2c, 0x2e, 0x6c, 0xc9, 0xf7, 0x69, 0x6f, 0x13, 0xb9, 0x2d, 0x47, 0x5f, 0x4e, 0xae, 0xec, 0xdb, 0x30, 0x83, 0x05, 0xcc, 0x1b, 0x2c, 0xd1, 0xba, 0xb1, 0xbf, 0x32, 0x99, 0x7a, 0x21, 0x25, 0x27, 0x33, 0xc3, 0x6c, 0xce, 0xc8, 0x84, 0xc4, 0xa0, 0xe1, 0xdb, 0xd1, 0x54, 0x2d, 0x78, 0x28, 0x5c, 0x9d, 0xa6, 0x26, 0x47, 0xd7, 0x92, 0x37, 0x92, 0xea, 0xb4, 0xea, 0x30, 0xdb, 0xa7, 0x4d, 0x05, 0x7f, 0xae, 0x1d, 0x6e, 0xc9, 0x64, 0xc8, 0x75, 0xa3, 0x37, 0x30, 0x19, 0xd3, 0x87, 0x6b, 0xb9, 0x3c, 0xe3, 0x04, 0x21, 0x7a, 0x1d, 0x8f, 0xb5, 0x04, 0x45, 0x4f, 0x80, 0x63, 0x15, 0x83, 0x7a, 0x28, 0xb5, 0xe1, 0x65, 0x12, 0x93, 0x28, 0x2c, 0x8c, 0xa8, 0x67, 0xc2, 0x5a, 0x71, 0x88, 0x30,\n\t0x78, 0x32, 0xb8, 0xd1, 0xca, 0xae, 0x78, 0xb4, 0x20, 0x12, 0x5b, 0x2e, 0x3c, 0x68, 0x26, 0xd9, 0xe4, 0xb5, 0xc5, 0x06, 0xad, 0x80, 0x83, 0x3e, 0x79, 0xcc, 0xe2, 0x16, 0x1e, 0xc0, 0x83, 0x2e, 0x25, 0x99, 0x37, 0x01, 0x59, 0x93, 0x59, 0x5b, 0x94, 0xa1, 0xbd, 0x03, 0x2d, 0xe3, 0x29, 0x7d, 0x47, 0xfe, 0xe8, 0xa9, 0xf7, 0xdf, 0xa7, 0x32, 0xe0, 0xc0, 0x7f, 0x78, 0x45, 0x03, 0x57, 0xf9, 0xf9, 0x81, 0xff, 0x31, 0xbf, 0xd5, 0x32, 0xba, 0x1a, 0xae, 0xef, 0x6e, 0xf2, 0x9a, 0xf8, 0xe0, 0x01, 0x91, 0xc4, 0x2e, 0xa3, 0x46, 0x21, 0x4d, 0x1e, 0x20, 0x55, 0x51, 0x49, 0x08, 0x08, 0x44, 0xa5, 0x38, 0xbb, 0x1c, 0x27, 0x2c, 0xe7, 0x23, 0x62, 0x2c, 0x10, 0x32, 0x90, 0xb9, 0x11, 0x28, 0x38, 0x2b, 0x0e, 0x58, 0x87, 0x84, 0x58, 0x1b, 0xbe, 0xb0, 0x11, 0xf7, 0x4a, 0xa0, 0x68, 0x6b, 0xc6,\n\t0xe1, 0x35, 0x89, 0x5e, 0xe4, 0xde, 0x6c, 0x6d, 0x20, 0xe4, 0xf2, 0x54, 0x79, 0xcc, 0x39, 0xaa, 0xe2, 0xe2, 0xf5, 0x89, 0xb1, 0xea, 0x18, 0x60, 0x7a, 0x89, 0x96, 0x10, 0xf9, 0x8b, 0x4e, 0x6c, 0x09, 0x96, 0x84, 0xc5, 0xe4, 0x52, 0xe2, 0xb2, 0x6d, 0xc6, 0xdb, 0x41, 0x16, 0xb1, 0xd2, 0x2b, 0x6c, 0x47, 0xd2, 0x0b, 0xa9, 0x21, 0xdf, 0x0c, 0x31, 0xae, 0x95, 0xcc, 0x71, 0xad, 0xc8, 0x09, 0xf9, 0xaa, 0xab, 0x6c, 0x4a, 0x1c, 0xb3, 0xb8, 0x15, 0x4f, 0xd9, 0x0a, 0xdc, 0x8f, 0x12, 0x31, 0x29, 0x99, 0xba, 0xb5, 0x84, 0x36, 0xa2, 0xe5, 0x97, 0xac, 0x4e, 0xc8, 0xa4, 0x84, 0xac, 0x8b, 0xb8, 0x64, 0x1b, 0xbc, 0xbd, 0xd2, 0x30, 0x30, 0xb7, 0xa7, 0xab, 0xb3, 0xbd, 0xb9, 0xb1, 0xae, 0x06, 0x45, 0xf3, 0xf7, 0x39, 0x5d, 0x39, 0x0e, 0x05, 0xda, 0xcf, 0x9c, 0xc2, 0x01, 0x37, 0x33, 0x2f,\n\t0x83, 0xc6, 0x1c, 0xff, 0x84, 0xce, 0x4b, 0x06, 0xf7, 0xa7, 0xc6, 0x4c, 0x28, 0xbc, 0x97, 0x75, 0x38, 0x26, 0xc1, 0x41, 0x22, 0x96, 0x4e, 0x96, 0x34, 0x25, 0xf9, 0x32, 0xf2, 0xbd, 0x7f, 0x7c, 0xf7, 0x9e, 0xfd, 0xa9, 0x85, 0xe1, 0x3c, 0x4b, 0xc5, 0xc2, 0x1a, 0x57, 0x7a, 0xcb, 0x48, 0xed, 0x1b, 0xe0, 0x65, 0x9c, 0x07, 0xa0, 0x3e, 0x96, 0x07, 0x40, 0x2f, 0x89, 0xe5, 0x01, 0x58, 0xd0, 0x9f, 0xdb, 0x55, 0xe2, 0x28, 0xd9, 0x74, 0x6a, 0xb3, 0x23, 0x9c, 0xe1, 0xd3, 0x46, 0x72, 0x75, 0xd9, 0xad, 0x25, 0x55, 0xeb, 0x43, 0x55, 0x33, 0xc3, 0x06, 0x52, 0xac, 0x55, 0x45, 0xd8, 0x65, 0x61, 0x3f, 0x45, 0x53, 0x3b, 0x76, 0x6d, 0xd8, 0x21, 0x10, 0x08, 0xdc, 0x15, 0x33, 0xf3, 0x0a, 0xfb, 0x4a, 0x6d, 0x60, 0xca, 0x74, 0x01, 0x8b, 0x1f, 0x08, 0x1a, 0xca, 0x3b, 0x16, 0x95, 0xb6, 0x1d,\n\t0x5c, 0x53, 0xcd, 0x08, 0x18, 0xbf, 0xd7, 0xe4, 0x32, 0xc9, 0x25, 0xd6, 0x50, 0x6d, 0xba, 0xcc, 0xa0, 0x96, 0x5e, 0xb8, 0x40, 0xcc, 0x64, 0x8f, 0x49, 0x4a, 0x20, 0x0f, 0xf6, 0x10, 0x16, 0x1c, 0x9f, 0x68, 0x8f, 0xa0, 0x18, 0xd3, 0x89, 0x9e, 0x0b, 0x0f, 0x0a, 0xea, 0x98, 0x6f, 0x89, 0x54, 0xa2, 0x0c, 0x45, 0xe2, 0x53, 0x49, 0xa0, 0xd4, 0x65, 0x46, 0xd7, 0x15, 0xf5, 0xb1, 0x74, 0x27, 0x04, 0x0a, 0xe0, 0xd8, 0x85, 0x01, 0xc1, 0xe8, 0x72, 0xa9, 0x25, 0x33, 0x2d, 0x33, 0x80, 0x22, 0x7f, 0xb9, 0x63, 0x28, 0x26, 0x4e, 0x40, 0xe1, 0xee, 0xe9, 0xb1, 0x74, 0x82, 0xf4, 0x63, 0x21, 0xf7, 0x98, 0xb3, 0x10, 0xc7, 0xf3, 0x41, 0x51, 0x1f, 0xf4, 0xdf, 0xc1, 0x19, 0x98, 0x8c, 0x35, 0xe9, 0xe9, 0xd5, 0xc6, 0x59, 0x77, 0x2e, 0x2d, 0x28, 0x58, 0x7a, 0xe7, 0x6c, 0x63, 0xb5, 0x3f, 0xbd,\n\t0x9a, 0xbc, 0xae, 0xeb, 0xfe, 0x8f, 0x6e, 0x34, 0x34, 0x07, 0x83, 0x8d, 0x86, 0x3d, 0x1f, 0x3f, 0xd0, 0xdd, 0xfd, 0xc0, 0x27, 0x7b, 0x0c, 0x0d, 0xc1, 0x60, 0x93, 0xe1, 0xc6, 0x8f, 0x0e, 0x77, 0x1d, 0x57, 0x74, 0xed, 0x3d, 0xb5, 0x6a, 0xd5, 0xcb, 0x37, 0x76, 0x29, 0x6c, 0x2e, 0xb7, 0x4d, 0xd1, 0xb5, 0xe7, 0x95, 0x55, 0xab, 0x5f, 0xde, 0xd3, 0x25, 0xb7, 0xb9, 0xdd, 0x24, 0x71, 0xdb, 0xb9, 0xd7, 0x36, 0xa8, 0x3d, 0x99, 0x19, 0x1e, 0xd5, 0xba, 0xd7, 0xce, 0xdf, 0x7e, 0x60, 0xf4, 0xb5, 0xf5, 0x2a, 0x4f, 0x46, 0xa6, 0x47, 0xbd, 0xee, 0xb5, 0x73, 0x1c, 0x6e, 0x65, 0x3e, 0x92, 0xd3, 0x84, 0x4b, 0x08, 0x2d, 0xe1, 0x27, 0x56, 0x11, 0x3f, 0x8b, 0x2a, 0x92, 0xa0, 0xac, 0xd6, 0x02, 0xe4, 0xc2, 0x12, 0x20, 0x56, 0x20, 0x73, 0x3e, 0x32, 0xa3, 0xd7, 0x11, 0x42, 0x91, 0x9c, 0x11,\n\t0x2e, 0xd2, 0x00, 0x99, 0x5c, 0x29, 0x97, 0x29, 0x87, 0x09, 0xa5, 0x42, 0xae, 0x54, 0x2c, 0x47, 0xf2, 0x30, 0x8d, 0xcc, 0x71, 0xc8, 0x04, 0xc5, 0x20, 0x13, 0x94, 0x80, 0x60, 0x44, 0x02, 0x66, 0x40, 0x0d, 0xe4, 0x72, 0xa8, 0x68, 0x03, 0xb4, 0x09, 0x55, 0x40, 0xa1, 0xe0, 0xce, 0xa7, 0x1d, 0x6d, 0xe5, 0x7a, 0xd4, 0x96, 0x48, 0x28, 0x1f, 0xfe, 0xf7, 0x1b, 0xeb, 0x89, 0xda, 0x56, 0xae, 0x18, 0x5a, 0x32, 0x38, 0x7f, 0xde, 0xdc, 0xd9, 0xfd, 0x3d, 0x5d, 0xed, 0xad, 0x0d, 0x75, 0xe5, 0x65, 0x45, 0x05, 0x6e, 0x83, 0xcb, 0xa7, 0x77, 0x68, 0x9c, 0x2a, 0x2d, 0xda, 0xd8, 0xfc, 0xde, 0x74, 0xe2, 0x6d, 0x4d, 0x87, 0x40, 0x2e, 0x42, 0xf1, 0xe1, 0x45, 0xe0, 0xac, 0x16, 0x78, 0x03, 0x1b, 0x2f, 0x2d, 0x57, 0x26, 0x66, 0x04, 0x8e, 0x09, 0x96, 0xa1, 0x89, 0x62, 0x25, 0xf3, 0xe5, 0xec,\n\t0x03, 0xeb, 0x17, 0xe7, 0x96, 0xd5, 0xad, 0xbf, 0x6e, 0x4d, 0xb0, 0xbd, 0xa5, 0xa5, 0x73, 0x76, 0x01, 0x2b, 0x73, 0xd8, 0x1c, 0x24, 0x23, 0x17, 0xe6, 0xa4, 0x67, 0xa7, 0x87, 0x22, 0x86, 0x8c, 0xca, 0xac, 0x1f, 0x21, 0xd9, 0x33, 0xb2, 0xfb, 0xcc, 0x46, 0x2c, 0x7b, 0x6e, 0xfd, 0x59, 0x3b, 0x92, 0x3d, 0x7f, 0xc2, 0xc9, 0x9e, 0x91, 0xbe, 0xe6, 0x72, 0x6b, 0x06, 0x2f, 0x7d, 0x06, 0xef, 0x3b, 0xf2, 0xd2, 0x33, 0xab, 0xee, 0x0b, 0x3e, 0x10, 0x3c, 0xb4, 0xea, 0xe9, 0x53, 0x48, 0xfa, 0x0c, 0xda, 0x90, 0x43, 0xb9, 0x60, 0x4d, 0x7a, 0x6e, 0x7a, 0xcd, 0xb4, 0x35, 0x5b, 0xf5, 0xa9, 0xee, 0x54, 0x3d, 0xfb, 0xa0, 0x56, 0x28, 0x72, 0xb8, 0x48, 0x32, 0xd3, 0xe6, 0xc9, 0xae, 0x2c, 0x70, 0x45, 0xb3, 0x2c, 0x97, 0x94, 0x4e, 0xb5, 0xf6, 0x0c, 0xcb, 0x78, 0xf9, 0x74, 0xe5, 0x9c, 0xb9,\n\t0xc3, 0x53, 0xc8, 0xa6, 0xbd, 0xec, 0xc3, 0xf4, 0xb7, 0xf0, 0x5c, 0x64, 0x82, 0x45, 0x51, 0x89, 0x0a, 0xea, 0xed, 0x48, 0xe5, 0x23, 0xf9, 0xeb, 0x1d, 0x6f, 0x2c, 0x32, 0x60, 0x42, 0xe8, 0xfc, 0x98, 0x5f, 0x27, 0x0a, 0x92, 0x92, 0xe0, 0xb0, 0x28, 0xc3, 0x1e, 0x8e, 0xb1, 0xc8, 0xfb, 0xf1, 0xe2, 0xe8, 0x6a, 0x82, 0xf3, 0xf2, 0xc4, 0x1f, 0x13, 0x2a, 0xa8, 0x2f, 0x53, 0xc1, 0x3e, 0xb1, 0x82, 0xf6, 0x6a, 0xdf, 0xa0, 0xbf, 0xf4, 0x08, 0x9c, 0x13, 0x46, 0x60, 0xbc, 0x9a, 0x01, 0x5f, 0x71, 0xc3, 0x3c, 0x3d, 0x96, 0x38, 0x9d, 0x3e, 0xa8, 0xde, 0x64, 0xe3, 0xc0, 0x97, 0x97, 0x71, 0x65, 0x42, 0x74, 0x18, 0x6a, 0x91, 0x18, 0x51, 0x3e, 0x64, 0x8e, 0x68, 0xc6, 0xbc, 0x96, 0xfe, 0xda, 0x05, 0xc5, 0x6c, 0xb5, 0x36, 0xd4, 0xb6, 0xa1, 0x17, 0x79, 0x2d, 0xd5, 0x6d, 0x3f, 0xbe, 0x28,\n\t0x54, 0x9a, 0x96, 0xa2, 0x29, 0x4e, 0x4d, 0x5a, 0x2f, 0x24, 0xc9, 0x25, 0xdf, 0x07, 0xb2, 0xc9, 0x3e, 0x4a, 0x28, 0x6f, 0xb4, 0x58, 0x22, 0x66, 0x53, 0x92, 0x51, 0xdc, 0xd1, 0x95, 0x50, 0xae, 0x3e, 0x4e, 0x7d, 0x4d, 0x94, 0xa3, 0xf8, 0xb9, 0xb9, 0x2e, 0x25, 0x85, 0x2f, 0x12, 0x68, 0x8a, 0x42, 0x2e, 0xb9, 0x7c, 0x34, 0x13, 0x38, 0x86, 0x72, 0x22, 0x1a, 0xf0, 0xa4, 0x9b, 0x70, 0x4e, 0x35, 0xce, 0x2a, 0x25, 0xc4, 0xe4, 0x0c, 0x4b, 0xab, 0x48, 0xe8, 0xc1, 0x89, 0x10, 0x11, 0x8e, 0x1b, 0x87, 0xc8, 0x8b, 0x7d, 0x8e, 0x03, 0x40, 0xb1, 0x1f, 0xf9, 0x75, 0x3a, 0x63, 0x5a, 0xd3, 0x8a, 0xea, 0x55, 0x6a, 0xad, 0xbc, 0x6c, 0xc4, 0xe3, 0x1e, 0x89, 0xca, 0x14, 0xea, 0x75, 0x65, 0x8b, 0x9b, 0xfc, 0x3b, 0x52, 0x2d, 0x0b, 0x7a, 0x7d, 0xd5, 0x21, 0xeb, 0xce, 0x14, 0x8b, 0x25, 0xbb,\n\t0x26, 0xe0, 0xaf, 0x8f, 0xd8, 0xe4, 0x2a, 0xb9, 0x41, 0x47, 0x7d, 0xdd, 0xf6, 0xbd, 0xd6, 0xe1, 0xd7, 0x8f, 0xdd, 0x5e, 0x21, 0x57, 0x94, 0x9d, 0x5c, 0xb8, 0xf0, 0x64, 0x54, 0x21, 0x2b, 0xda, 0x7b, 0xf7, 0xa3, 0x5d, 0xe0, 0xa0, 0xcb, 0xc8, 0xbe, 0xb8, 0xff, 0xc3, 0x0e, 0xdf, 0xe0, 0x9a, 0x2d, 0x65, 0x60, 0x3b, 0xfc, 0x76, 0xba, 0xec, 0xda, 0xb5, 0x4b, 0x02, 0x69, 0x83, 0xd7, 0xde, 0x31, 0xb3, 0xac, 0xaf, 0x22, 0x43, 0xa9, 0xb6, 0x72, 0x31, 0xa8, 0xbf, 0x62, 0x8a, 0x68, 0x8a, 0x08, 0x83, 0xff, 0xe5, 0xa4, 0x03, 0x89, 0x19, 0x88, 0x90, 0x1f, 0x9e, 0x14, 0xe7, 0x4e, 0xe5, 0xbe, 0x50, 0x52, 0x1c, 0x01, 0x47, 0xc6, 0xfb, 0x91, 0x32, 0x22, 0xc8, 0x71, 0x65, 0x50, 0xf8, 0x85, 0x62, 0xbc, 0x74, 0x18, 0x6a, 0xa9, 0x28, 0x5e, 0x3d, 0x0a, 0x2b, 0x2c, 0x12, 0xc5, 0x82, 0x2b,\n\t0x13, 0x52, 0x29, 0x17, 0xfc, 0x8d, 0xcb, 0x7e, 0xae, 0xfe, 0x0e, 0x35, 0xb9, 0x74, 0xe8, 0xfa, 0xef, 0xfc, 0x4e, 0xf3, 0x77, 0x7e, 0x67, 0xf2, 0x77, 0x7e, 0x67, 0xe0, 0x3b, 0xbe, 0x33, 0x5a, 0x78, 0xa9, 0x4a, 0xb8, 0x38, 0xef, 0x72, 0x8b, 0x1d, 0xe7, 0xcd, 0x5c, 0x6d, 0x22, 0x96, 0xce, 0x1d, 0x9d, 0x98, 0x54, 0x40, 0x64, 0x67, 0x21, 0xc8, 0xac, 0xcb, 0x91, 0x6a, 0x45, 0x31, 0x1a, 0xb9, 0xa0, 0x81, 0x42, 0x06, 0x2e, 0x6d, 0x58, 0x8e, 0x93, 0x03, 0xf0, 0x4e, 0x81, 0xa4, 0x97, 0x0f, 0x14, 0x7e, 0x29, 0xe5, 0x35, 0x4c, 0xbf, 0xaf, 0x94, 0x36, 0x14, 0x3f, 0xb9, 0x7e, 0xc1, 0xc3, 0xeb, 0xea, 0xc4, 0xaf, 0xbe, 0xf2, 0xca, 0x6b, 0xb2, 0x96, 0x6b, 0x1f, 0x9e, 0xb7, 0xf4, 0xe1, 0xc2, 0x32, 0x46, 0xa3, 0x54, 0xd9, 0x73, 0x1a, 0x0a, 0xf2, 0xe7, 0xd4, 0x67, 0x8b, 0xc1, 0x51,\n\t0xb6, 0x43, 0x14, 0x6a, 0x9a, 0x1b, 0x76, 0x15, 0xe6, 0x04, 0x8c, 0xca, 0xcf, 0xa5, 0xad, 0x4d, 0x33, 0xa6, 0xad, 0x7b, 0x64, 0x01, 0x5b, 0x49, 0x7d, 0xcd, 0xb6, 0xce, 0x7b, 0x70, 0x75, 0xb4, 0xb6, 0xb8, 0x47, 0x24, 0x4f, 0xb2, 0x26, 0xb9, 0x6b, 0x17, 0x56, 0xec, 0xaf, 0x59, 0x56, 0xef, 0x15, 0x69, 0xac, 0x7a, 0x39, 0x92, 0x25, 0x84, 0x04, 0x41, 0xf7, 0x53, 0xdf, 0x5c, 0x42, 0x67, 0xb5, 0x5c, 0x4e, 0x67, 0x4d, 0x44, 0x82, 0x8d, 0xd7, 0x59, 0xc9, 0x67, 0xbb, 0x25, 0x7a, 0xa9, 0x58, 0x2f, 0xe9, 0x26, 0x1f, 0xbf, 0x33, 0x29, 0x45, 0x74, 0x70, 0xf0, 0x99, 0x79, 0x07, 0x05, 0x36, 0xd3, 0x41, 0xf0, 0xb3, 0x13, 0xa4, 0xf8, 0x8d, 0xa4, 0x2a, 0x5f, 0x5a, 0xa5, 0xf9, 0x07, 0xa3, 0xff, 0x32, 0x69, 0x41, 0x17, 0xbb, 0x19, 0x6c, 0x67, 0x1f, 0x53, 0x9b, 0x61, 0x5f, 0x70, 0x6e,\n\t0x0a, 0xa8, 0xf7, 0xf9, 0x71, 0xbf, 0x2e, 0xa1, 0xb3, 0x5a, 0xae, 0x58, 0x67, 0xbd, 0x58, 0x1f, 0xb5, 0xbc, 0x12, 0xa4, 0x0d, 0xd1, 0xdb, 0x50, 0x5f, 0x25, 0x7a, 0x49, 0x17, 0x79, 0xec, 0x4e, 0x53, 0xaa, 0xe8, 0xe0, 0xfc, 0x67, 0x06, 0xee, 0x14, 0xda, 0x4d, 0x07, 0x8f, 0xb3, 0xaf, 0xbf, 0xf2, 0x0a, 0xd8, 0xf4, 0xf1, 0x73, 0x17, 0xeb, 0x31, 0xfc, 0x7b, 0x33, 0xf5, 0x0d, 0xab, 0x02, 0x9f, 0xc3, 0x7e, 0x6b, 0x51, 0xbe, 0x79, 0x1c, 0x5f, 0x2c, 0x9f, 0x08, 0x46, 0x33, 0x42, 0x41, 0x06, 0x99, 0xfe, 0xeb, 0x69, 0x3e, 0x9b, 0x04, 0xf2, 0x4e, 0xc1, 0x41, 0xb7, 0xc6, 0x66, 0xd5, 0xc8, 0x69, 0x6e, 0x42, 0x2e, 0xd6, 0x05, 0xa4, 0x45, 0x65, 0x57, 0xaa, 0xa7, 0x26, 0xeb, 0x1d, 0x16, 0x9d, 0x40, 0xa0, 0xb3, 0x38, 0xf4, 0x87, 0x47, 0xff, 0x40, 0xed, 0x3c, 0x68, 0xb4, 0x89, 0x06,\n\t0x95, 0xf6, 0x40, 0x81, 0x2f, 0x15, 0x08, 0x9e, 0xa1, 0x40, 0xb2, 0xaf, 0x20, 0xdd, 0xae, 0x5c, 0x28, 0xb4, 0x1b, 0x0f, 0xee, 0x35, 0xe6, 0x4d, 0x6b, 0x8f, 0xb0, 0xbb, 0xe9, 0xbd, 0xec, 0x0d, 0xf9, 0x9d, 0xd3, 0xf2, 0x8c, 0xe4, 0xeb, 0x66, 0xbf, 0xd7, 0x67, 0x30, 0xf8, 0xbc, 0x7e, 0xf3, 0x53, 0xe7, 0x6f, 0x32, 0xab, 0x81, 0xca, 0x97, 0x9b, 0x2c, 0x05, 0xec, 0x34, 0xf0, 0x0a, 0x90, 0x26, 0xe7, 0xfa, 0xd8, 0xcf, 0xe1, 0xc8, 0x1a, 0xc2, 0xed, 0xa5, 0x1e, 0x11, 0x78, 0x9e, 0xad, 0x13, 0x7a, 0x4a, 0x3b, 0xc2, 0xfc, 0xba, 0xbc, 0x0b, 0xd7, 0x05, 0xe9, 0xa8, 0x50, 0x1f, 0xcf, 0x67, 0x48, 0xa4, 0xa4, 0x12, 0x93, 0x75, 0xd4, 0x84, 0xb5, 0x19, 0xa7, 0xa1, 0x4a, 0xe3, 0x1a, 0x6a, 0xd9, 0xd5, 0x69, 0xa8, 0xd4, 0xdf, 0xc6, 0x86, 0xfb, 0xbd, 0xd1, 0x3f, 0xa1, 0xe1, 0xda, 0x85,\n\t0x0b, 0x95, 0xf6, 0xf4, 0x42, 0xaf, 0x0d, 0x30, 0x70, 0xb8, 0x2e, 0x7b, 0x38, 0xdd, 0xa5, 0x5c, 0x2c, 0xb4, 0xc1, 0xe1, 0x2a, 0x8b, 0x3d, 0xec, 0x82, 0x57, 0x5e, 0x21, 0xa7, 0xb1, 0x7b, 0xe8, 0xfd, 0xec, 0xf5, 0x91, 0xce, 0xca, 0x5c, 0x34, 0xe4, 0x74, 0xaf, 0xcf, 0x68, 0xf4, 0x79, 0xd3, 0x2f, 0x31, 0xe4, 0x46, 0x4f, 0xbe, 0x8e, 0xad, 0x80, 0xeb, 0xd9, 0x08, 0x9e, 0x8d, 0x0d, 0x1b, 0xe7, 0x29, 0x1b, 0xa0, 0x52, 0x19, 0x86, 0x58, 0x4f, 0xde, 0xcc, 0x69, 0x4d, 0xda, 0xd5, 0x40, 0x21, 0x9b, 0x3b, 0x8b, 0x94, 0x28, 0xe0, 0x68, 0xc5, 0x5e, 0x40, 0xd1, 0xc8, 0x9b, 0x79, 0xd2, 0x53, 0x06, 0x5f, 0x70, 0x21, 0xc1, 0xa4, 0x84, 0x50, 0xc8, 0x24, 0x32, 0x85, 0x64, 0x98, 0x90, 0x48, 0x65, 0x12, 0xe9, 0x72, 0x39, 0x90, 0x11, 0x52, 0xb1, 0x4c, 0x3a, 0x40, 0xc0, 0x6d, 0x2a, 0x10,\n\t0x8b, 0x06, 0x70, 0x44, 0x44, 0xac, 0x74, 0xda, 0x1b, 0x70, 0xec, 0x3c, 0x24, 0x1b, 0x58, 0x11, 0xad, 0x49, 0x8d, 0x3b, 0xb2, 0x5f, 0x45, 0x23, 0xce, 0x29, 0x1b, 0x51, 0xff, 0x27, 0x7a, 0xa2, 0xff, 0x4f, 0xf4, 0xc4, 0xf8, 0x9f, 0xe8, 0x89, 0xff, 0x3f, 0xd1, 0x13, 0xb4, 0x9c, 0x45, 0x97, 0x6b, 0x04, 0x85, 0x5f, 0x40, 0x62, 0xdc, 0xf8, 0xd6, 0xb8, 0x26, 0xa2, 0x33, 0x08, 0xb9, 0x4c, 0x3e, 0x32, 0xa1, 0x09, 0xa4, 0x08, 0x33, 0xf4, 0x22, 0x62, 0x8a, 0xde, 0x60, 0xbe, 0xc1, 0xc7, 0xc0, 0xe4, 0xc5, 0x2f, 0x1e, 0x35, 0x10, 0xeb, 0x56, 0x0f, 0xcf, 0x52, 0xec, 0xd7, 0xac, 0x19, 0x19, 0x9e, 0x3f, 0xaf, 0xb7, 0x07, 0x29, 0xc6, 0x0d, 0x75, 0xd3, 0x20, 0x2d, 0x0c, 0xe7, 0x86, 0xb2, 0x33, 0xd2, 0x9d, 0xc9, 0x26, 0xe4, 0xe8, 0x8a, 0x88, 0x1b, 0xef, 0xa2, 0x12, 0x8f, 0x1f, 0x86,\n\t0xf5, 0x5d, 0xfe, 0x4a, 0x2a, 0xa6, 0xef, 0x22, 0x27, 0x67, 0xc1, 0x44, 0xb0, 0xcb, 0x45, 0x82, 0x47, 0x45, 0xbc, 0xf8, 0xc6, 0x14, 0x7b, 0x0d, 0x96, 0xf1, 0xee, 0xe9, 0x7a, 0x74, 0xbb, 0x47, 0x2a, 0x4a, 0x66, 0x45, 0x6d, 0x28, 0x5c, 0x54, 0xa8, 0x31, 0x94, 0x94, 0x3b, 0x6f, 0x5f, 0x4f, 0x46, 0x4b, 0x72, 0x5a, 0x46, 0x4b, 0x95, 0x21, 0x52, 0x54, 0x94, 0x54, 0xd5, 0x1b, 0x36, 0x50, 0x62, 0x8d, 0x2a, 0x1f, 0x28, 0xed, 0xb9, 0xde, 0x9c, 0x05, 0x59, 0x95, 0x6b, 0x3b, 0xb3, 0x53, 0x8a, 0xbb, 0x8b, 0x6c, 0x75, 0xce, 0x50, 0x4b, 0x38, 0x79, 0xed, 0xa6, 0x49, 0x01, 0xa8, 0x72, 0xf6, 0xce, 0xfa, 0xe9, 0x4a, 0x83, 0x55, 0xb6, 0x40, 0x20, 0x13, 0x30, 0x32, 0x61, 0x8b, 0xa1, 0xc4, 0xa9, 0x77, 0xa8, 0x75, 0x66, 0x97, 0x82, 0xfa, 0x56, 0x91, 0x3b, 0xad, 0xc5, 0x8f, 0xc3, 0x4e,\n\t0xa9, 0x42, 0x65, 0x75, 0xde, 0x8a, 0x91, 0xd6, 0x2c, 0x89, 0xd3, 0x95, 0x9d, 0x09, 0x85, 0x69, 0x6b, 0xa8, 0x26, 0x5d, 0x66, 0x54, 0x4b, 0x2d, 0x6e, 0x83, 0x44, 0x62, 0x8f, 0xce, 0x2e, 0xcd, 0x9a, 0x5e, 0x68, 0x17, 0x9b, 0x33, 0x8a, 0x1d, 0xcd, 0x5d, 0xe3, 0x62, 0x57, 0x05, 0xa3, 0xa2, 0xaf, 0xa4, 0xaa, 0xb5, 0x22, 0xad, 0x44, 0xa2, 0x15, 0x2d, 0xb4, 0x24, 0x89, 0x98, 0x3e, 0xb3, 0x0a, 0xc7, 0x51, 0x69, 0x61, 0x8f, 0x89, 0x96, 0xd0, 0x22, 0xa8, 0x5b, 0xaf, 0xc0, 0x3e, 0xa0, 0x7b, 0xe8, 0xc5, 0x7c, 0x0e, 0x80, 0x07, 0xe9, 0x23, 0xf4, 0x2c, 0xc2, 0x48, 0x44, 0x90, 0x6e, 0x8d, 0xdc, 0x66, 0x28, 0xcd, 0x65, 0x74, 0x6b, 0xbf, 0x8f, 0xd3, 0xad, 0x51, 0xb0, 0xff, 0x98, 0x6a, 0x0d, 0x70, 0x1c, 0xe6, 0xcb, 0x68, 0xd6, 0x9a, 0x85, 0x03, 0x0b, 0x16, 0x19, 0x5a, 0xb2, 0x73,\n\t0x9a, 0x75, 0x0b, 0x17, 0x0c, 0x0c, 0xea, 0xa6, 0x87, 0x42, 0xad, 0xe0, 0xd1, 0x82, 0x25, 0x07, 0x67, 0xeb, 0xa1, 0x46, 0xdd, 0xa4, 0x9f, 0x7d, 0xe7, 0xe2, 0x82, 0xfc, 0xc5, 0x77, 0xcc, 0xd2, 0x35, 0x87, 0x72, 0xa6, 0xeb, 0x67, 0xdd, 0xb9, 0x38, 0xff, 0x80, 0xe5, 0x85, 0xdb, 0xef, 0x78, 0xd1, 0xec, 0x0b, 0x06, 0x7d, 0xe6, 0x97, 0x6e, 0xbf, 0xfd, 0x79, 0x8b, 0x3f, 0x2f, 0x0f, 0x94, 0x2e, 0x3b, 0xb1, 0xab, 0x4d, 0xe6, 0xc9, 0xcc, 0xf4, 0xc8, 0xdb, 0xae, 0x3b, 0xb1, 0x6c, 0xe8, 0xd9, 0xeb, 0xda, 0xe5, 0xfe, 0x9c, 0x1c, 0xbf, 0xbc, 0x6d, 0xd7, 0xb3, 0x48, 0x8f, 0xee, 0x80, 0xf2, 0xe5, 0x0f, 0x98, 0x2f, 0x21, 0x6f, 0x4a, 0x23, 0x96, 0x93, 0x23, 0x51, 0x0d, 0xd2, 0xa3, 0x75, 0x40, 0xc4, 0xd4, 0x43, 0x5d, 0xba, 0x10, 0xea, 0xd2, 0x34, 0x1f, 0xdc, 0xe8, 0xdf, 0xd0, 0xa5,\n\t0x1d, 0x13, 0x74, 0x69, 0x8e, 0xd2, 0xfc, 0x87, 0x1a, 0x74, 0x8a, 0x63, 0xca, 0xd4, 0x7f, 0xb4, 0x87, 0x88, 0x8c, 0xfd, 0x3b, 0x2a, 0xff, 0xe4, 0x16, 0xcd, 0xff, 0xc1, 0x16, 0xb9, 0x41, 0x27, 0xff, 0x87, 0xfb, 0xf8, 0x9f, 0xec, 0x1e, 0x4f, 0xa2, 0x6c, 0x43, 0x4b, 0x16, 0x2e, 0x98, 0x3b, 0xbb, 0xbf, 0x6f, 0x66, 0x77, 0x7b, 0x6b, 0x4b, 0x53, 0x6d, 0x75, 0x69, 0x71, 0x7e, 0xd8, 0x69, 0x70, 0x99, 0x2e, 0x63, 0xe8, 0x10, 0x4c, 0xb4, 0x73, 0x8c, 0xcb, 0x01, 0x72, 0x91, 0xd8, 0x34, 0x1c, 0x65, 0xe3, 0x4d, 0x1c, 0x61, 0xfe, 0x92, 0x1d, 0xdf, 0x9c, 0xbd, 0xc9, 0x99, 0x38, 0x6a, 0x37, 0xec, 0x5a, 0x1d, 0x6c, 0x9f, 0xde, 0xd2, 0x31, 0x27, 0x9f, 0x95, 0x3b, 0x6c, 0x76, 0x52, 0xac, 0x0c, 0xf9, 0x83, 0x01, 0xce, 0xc2, 0x71, 0x8b, 0x7f, 0x65, 0xdb, 0xc0, 0xde, 0x1e, 0x5f, 0xee,\n\t0xfc, 0x3b, 0xe6, 0xce, 0xbc, 0xad, 0xb8, 0xf8, 0xd6, 0xde, 0x79, 0xb7, 0xcf, 0xcf, 0xf5, 0xf5, 0xec, 0x9d, 0x3f, 0x63, 0xc4, 0xef, 0x15, 0x6b, 0xa4, 0x52, 0x93, 0x2d, 0x3d, 0x75, 0xce, 0xe2, 0x15, 0x6b, 0x1b, 0x17, 0xd8, 0xf6, 0xdb, 0x16, 0x34, 0xae, 0x5d, 0xb1, 0x78, 0x4e, 0x4a, 0xc0, 0x66, 0x92, 0xca, 0x54, 0x12, 0x7a, 0x34, 0x3d, 0x2f, 0xbd, 0xb6, 0x62, 0xcd, 0x16, 0xce, 0xba, 0xf1, 0x90, 0x46, 0x28, 0x72, 0xba, 0xe8, 0xcc, 0x54, 0x6c, 0xdc, 0x28, 0xcb, 0xb2, 0x44, 0x7d, 0xb9, 0xd3, 0xf7, 0xbc, 0xb4, 0x64, 0xc3, 0xd9, 0x1b, 0xea, 0x4a, 0x0b, 0x0b, 0x4b, 0xeb, 0x6e, 0x38, 0xbb, 0x61, 0xc9, 0x4b, 0x7b, 0xa6, 0xe7, 0xfa, 0x66, 0x2b, 0xc5, 0x4a, 0x8d, 0xf2, 0xf8, 0xc9, 0x27, 0x9f, 0x6b, 0xa8, 0xad, 0x6d, 0x78, 0xee, 0xc9, 0x93, 0xc7, 0xe1, 0x57, 0xb1, 0x12, 0xdb,\n\t0x32, 0x5a, 0xd8, 0x87, 0xa8, 0xeb, 0x68, 0x14, 0x69, 0xf8, 0xfd, 0xa8, 0x44, 0x79, 0x39, 0x5b, 0x86, 0xe3, 0xa2, 0xb6, 0x8c, 0x29, 0x4d, 0x13, 0x8e, 0xab, 0x35, 0x4d, 0x38, 0x2e, 0x6a, 0x9a, 0xb8, 0x54, 0x5f, 0x26, 0x1a, 0x0f, 0x62, 0x96, 0x03, 0x3b, 0xb6, 0x1c, 0x08, 0x2e, 0x19, 0x63, 0x28, 0x6e, 0x36, 0x20, 0x67, 0xd8, 0x52, 0x67, 0x3f, 0xbc, 0xbe, 0xba, 0x6c, 0xe3, 0x89, 0xd5, 0xcb, 0x8e, 0x94, 0xe7, 0x8a, 0xd5, 0x2a, 0x95, 0x33, 0xaf, 0x21, 0x52, 0xbb, 0xbc, 0xce, 0xe3, 0xab, 0x5f, 0x52, 0x6e, 0x0f, 0xa4, 0x68, 0x04, 0xf5, 0xa9, 0xe6, 0x75, 0x52, 0x2a, 0x96, 0xb6, 0xa4, 0x3a, 0x5a, 0x2b, 0x45, 0x5a, 0x0d, 0xce, 0x5b, 0xb2, 0x67, 0x76, 0x36, 0xb2, 0x18, 0x14, 0x25, 0xdb, 0xf0, 0xbc, 0x1a, 0xc0, 0x63, 0x24, 0x43, 0x46, 0xe0, 0xa6, 0x4e, 0x8d, 0x26, 0x73, 0xc1,\n\t0xc1, 0x3b, 0x70, 0x98, 0xd8, 0x1e, 0xde, 0xc3, 0x79, 0x0c, 0xcf, 0xae, 0xb7, 0xe7, 0x91, 0x0c, 0xab, 0x26, 0x23, 0xfb, 0xf7, 0x73, 0x76, 0xc7, 0x6e, 0xfa, 0x76, 0xf2, 0x47, 0x82, 0x5d, 0x90, 0x5e, 0x7a, 0x89, 0x74, 0xa2, 0x86, 0x83, 0x91, 0xe9, 0x51, 0x4a, 0x46, 0x40, 0x33, 0x73, 0xd1, 0xb5, 0x26, 0xa7, 0x35, 0x0e, 0xa0, 0xcb, 0x4d, 0x4b, 0xec, 0x39, 0x85, 0x5f, 0xd2, 0x45, 0xe1, 0x58, 0xb4, 0x28, 0x07, 0x03, 0xd1, 0xd2, 0x13, 0x15, 0xab, 0x75, 0x3e, 0x9f, 0xcf, 0x85, 0x5c, 0x2e, 0xc0, 0x84, 0x50, 0x6a, 0xcc, 0x84, 0xef, 0x28, 0x70, 0x09, 0xa8, 0xd6, 0xd9, 0x03, 0x26, 0x93, 0xdf, 0xa6, 0xd5, 0xda, 0xfc, 0x26, 0x53, 0xc0, 0xae, 0x03, 0xdb, 0xb5, 0x36, 0xf8, 0x24, 0x80, 0x9e, 0x70, 0xff, 0x8e, 0x1e, 0x21, 0x2b, 0x47, 0x5f, 0x66, 0x24, 0xa6, 0x74, 0x9b, 0x46, 0x63,\n\t0x4b, 0x37, 0x25, 0x05, 0xec, 0x5a, 0xad, 0x3d, 0x90, 0x34, 0xe1, 0x3b, 0x18, 0xd8, 0x82, 0xc6, 0xd2, 0x0e, 0xc7, 0xf2, 0x63, 0xc1, 0xaf, 0xe0, 0x58, 0x5c, 0x50, 0x23, 0x59, 0x72, 0xd2, 0x8a, 0xa2, 0xa9, 0xf0, 0xc8, 0x38, 0x33, 0x0d, 0xb0, 0x2b, 0x24, 0x49, 0x90, 0x23, 0x02, 0xdc, 0x6d, 0x11, 0x23, 0x84, 0x5c, 0x6e, 0x00, 0x23, 0xcb, 0x13, 0x7e, 0xc4, 0x8f, 0x91, 0x93, 0x04, 0xf7, 0x3b, 0xe8, 0x43, 0x11, 0x9e, 0xc1, 0xf4, 0x9e, 0x68, 0x92, 0xc7, 0x0d, 0x88, 0x60, 0xa6, 0x3b, 0xdf, 0x93, 0xef, 0x72, 0x18, 0xe1, 0x39, 0xe6, 0x31, 0x8d, 0x12, 0x5d, 0xba, 0x76, 0x42, 0xec, 0x66, 0xb7, 0x93, 0xc2, 0x52, 0x85, 0xc1, 0x18, 0xe6, 0xdc, 0xc0, 0xa8, 0x09, 0x05, 0xde, 0x41, 0xc3, 0x4d, 0x18, 0x3e, 0x08, 0x3f, 0xf7, 0xd1, 0x0d, 0x32, 0xa3, 0x70, 0x83, 0x18, 0xfe, 0xb7, 0x51,\n\t0x68, 0x94, 0xed, 0xd8, 0x98, 0x38, 0x0d, 0xf0, 0x5f, 0x66, 0xc7, 0xc4, 0x71, 0xd7, 0x03, 0xa9, 0x58, 0xb0, 0x4d, 0x2c, 0x93, 0x89, 0xb7, 0x31, 0x12, 0xf6, 0xd8, 0xc4, 0x9f, 0xe3, 0x6b, 0xfb, 0x27, 0xbc, 0xb6, 0xd9, 0x44, 0x1b, 0x37, 0x11, 0x26, 0x01, 0x5c, 0x40, 0xe4, 0xed, 0x06, 0x98, 0x91, 0x09, 0xcb, 0x9b, 0x92, 0xf0, 0x53, 0xe2, 0x0a, 0xf7, 0xe1, 0x15, 0x86, 0x53, 0xa0, 0x4c, 0xf3, 0x65, 0x06, 0x7c, 0xd9, 0x69, 0xd9, 0x68, 0x9d, 0x85, 0x28, 0x00, 0xc3, 0xe5, 0xd6, 0x19, 0xcd, 0x02, 0xd6, 0x7b, 0xae, 0x64, 0xb5, 0xd9, 0x3a, 0x78, 0x56, 0x6e, 0x5b, 0x61, 0xb4, 0x2a, 0x3f, 0xbb, 0xfc, 0x92, 0xff, 0xc0, 0x60, 0xfa, 0x52, 0x8e, 0xbc, 0x7a, 0xc1, 0x85, 0xb7, 0xd8, 0x7b, 0xc0, 0x46, 0xe2, 0x00, 0x61, 0x20, 0xfa, 0x31, 0xbe, 0xee, 0xa4, 0x0c, 0x2f, 0xbc, 0x05, 0xfd,\n\t0x4b, 0x83, 0x18, 0xe8, 0xce, 0xc0, 0xfb, 0x83, 0x10, 0xf3, 0xc7, 0xb2, 0xf5, 0x0d, 0x93, 0x38, 0xae, 0x3e, 0x05, 0xf7, 0x35, 0x4e, 0xc2, 0x17, 0x2b, 0x00, 0x4f, 0x7b, 0xec, 0xf7, 0x9e, 0xe7, 0x51, 0x84, 0x68, 0x15, 0x23, 0x49, 0x4a, 0x0f, 0x39, 0x23, 0x53, 0x04, 0x5c, 0xfb, 0xd9, 0xbf, 0xfe, 0x72, 0x72, 0x62, 0xb8, 0xe3, 0x03, 0x2f, 0x71, 0x61, 0xd4, 0x5a, 0x92, 0x14, 0x8a, 0xce, 0x26, 0xe4, 0x6f, 0x71, 0x1a, 0xf6, 0x71, 0x25, 0x71, 0xd7, 0xff, 0x0f, 0x7d, 0xcc, 0xb3, 0x4f, 0xee, 0xe3, 0x0f, 0xaf, 0x03, 0x59, 0x13, 0xe3, 0x56, 0xdf, 0xf5, 0xda, 0x84, 0x3e, 0x12, 0x87, 0xd8, 0x7b, 0xc8, 0x16, 0xe2, 0x16, 0x42, 0x47, 0x94, 0xc3, 0x6e, 0x51, 0x18, 0x8d, 0xe4, 0xc0, 0xee, 0x62, 0xf0, 0xc7, 0x11, 0x44, 0x51, 0x30, 0x3a, 0x6c, 0x98, 0xc2, 0xee, 0x44, 0xf0, 0xb4, 0x8c,\n\t0xc4, 0xbc, 0x79, 0x62, 0xcf, 0x7b, 0x9e, 0x73, 0xdb, 0x9d, 0x2a, 0x04, 0x80, 0x41, 0x33, 0x65, 0xc0, 0xb7, 0x50, 0x86, 0x98, 0x19, 0x28, 0xef, 0xd0, 0xd1, 0x60, 0xd4, 0x96, 0x25, 0x97, 0x99, 0x05, 0xca, 0x8c, 0xc6, 0xb4, 0x86, 0x85, 0x51, 0xeb, 0x2d, 0x6f, 0x34, 0x75, 0x2a, 0x14, 0x49, 0x2d, 0x5a, 0x4d, 0x5e, 0xf7, 0xaa, 0xb2, 0xb1, 0x3e, 0x44, 0x60, 0x1f, 0xea, 0x4e, 0x4a, 0xd1, 0xea, 0xf2, 0x7d, 0xd0, 0xa0, 0x2c, 0x8a, 0xd4, 0x08, 0xda, 0x95, 0x63, 0xb3, 0x62, 0x80, 0x0f, 0x01, 0xe7, 0xdf, 0x3c, 0x42, 0x8c, 0xfd, 0xd0, 0x13, 0x45, 0xce, 0x29, 0x3a, 0x42, 0x07, 0x3b, 0x83, 0x62, 0x34, 0xb8, 0x27, 0x75, 0xa5, 0x04, 0x80, 0xda, 0x89, 0x7d, 0x89, 0x0c, 0x25, 0xf6, 0xa5, 0x1f, 0xc9, 0xc7, 0xec, 0x41, 0xba, 0x8f, 0x96, 0xc0, 0xb3, 0x13, 0x25, 0x4e, 0x72, 0x02, 0x8f,\n\t0x36, 0x1d, 0x48, 0x84, 0xd1, 0x1c, 0x52, 0x2a, 0x49, 0x02, 0x02, 0xa9, 0x18, 0xc1, 0xf5, 0x91, 0x26, 0x0c, 0x9f, 0x8a, 0x26, 0x3c, 0xe5, 0xb1, 0x8f, 0xc1, 0x78, 0x60, 0x2e, 0x29, 0x21, 0x60, 0xa4, 0x02, 0x94, 0xb3, 0x8e, 0x06, 0x28, 0x1e, 0xc7, 0x3c, 0x42, 0x22, 0x11, 0xf6, 0xa2, 0x98, 0x5e, 0x5c, 0x6c, 0x04, 0xc4, 0x67, 0x86, 0x01, 0x0e, 0xd1, 0x75, 0xf1, 0x2a, 0xd8, 0xf5, 0x12, 0xd5, 0x23, 0x26, 0x54, 0xeb, 0x89, 0x6a, 0x4a, 0x8b, 0xc3, 0xb9, 0xd9, 0x41, 0x97, 0xcf, 0xad, 0xd6, 0xb8, 0xf4, 0x2e, 0x1c, 0x20, 0x8a, 0x71, 0x72, 0x90, 0xda, 0x31, 0xbf, 0x46, 0xe4, 0xa4, 0x9c, 0x37, 0xe6, 0xbb, 0x8b, 0x43, 0xaf, 0xe1, 0xf0, 0x47, 0x89, 0x11, 0x9a, 0xc3, 0x11, 0xba, 0xef, 0x76, 0x4d, 0xcd, 0xf0, 0x3d, 0x0b, 0xae, 0x39, 0x51, 0xeb, 0x13, 0x25, 0x19, 0x34, 0x81, 0x8a,\n\t0x39, 0x55, 0x8b, 0x47, 0x8c, 0xec, 0x03, 0x60, 0x95, 0x6d, 0x5a, 0x43, 0x67, 0x6e, 0xff, 0x81, 0x85, 0x91, 0x92, 0x95, 0x0f, 0x0e, 0x0e, 0x5c, 0x1f, 0x96, 0xc8, 0x7c, 0x6b, 0x76, 0xb0, 0x2f, 0x65, 0xae, 0xac, 0xdc, 0x75, 0x00, 0x05, 0xeb, 0x6f, 0xdb, 0x18, 0x6e, 0x2b, 0x1b, 0xac, 0xf5, 0x95, 0x86, 0x9b, 0x15, 0xc6, 0x64, 0x7b, 0x72, 0x5d, 0xe9, 0xa6, 0xd3, 0x29, 0x81, 0x14, 0x45, 0xe1, 0xc8, 0x63, 0x2b, 0x06, 0x8e, 0x6e, 0xae, 0x2d, 0x2b, 0x28, 0xf3, 0x9e, 0xcf, 0x26, 0x3f, 0x09, 0x67, 0x3e, 0x7a, 0x4f, 0xeb, 0xaa, 0x5a, 0x7b, 0x45, 0x29, 0xd2, 0x51, 0x6a, 0xd9, 0xdd, 0xa2, 0x79, 0x82, 0x87, 0x08, 0x2f, 0xe3, 0x21, 0x37, 0x13, 0x67, 0x81, 0x80, 0x99, 0x4f, 0x12, 0x84, 0xe8, 0x69, 0x82, 0x3c, 0x7e, 0xf6, 0x78, 0x28, 0x9d, 0x18, 0x5f, 0xc6, 0x4b, 0x7e, 0x9d, 0x58,\n\t0x06, 0x4c, 0x55, 0xc6, 0x4f, 0x3e, 0x71, 0xd9, 0x32, 0x01, 0xf2, 0x85, 0xcb, 0x96, 0xc9, 0x24, 0x6f, 0xbe, 0x6c, 0x7f, 0xd2, 0xc9, 0xb7, 0x2e, 0xdb, 0x8e, 0x8f, 0x3c, 0x72, 0xd9, 0x76, 0xb2, 0xc8, 0x8f, 0x2e, 0xdb, 0x4e, 0x1a, 0xf9, 0x78, 0x62, 0x19, 0x8a, 0x2f, 0x03, 0xc9, 0x43, 0xac, 0x0c, 0xc2, 0xa8, 0xb5, 0xc3, 0xcd, 0x12, 0x8d, 0x96, 0x14, 0x70, 0x19, 0x29, 0x05, 0x34, 0x49, 0x0b, 0x48, 0x64, 0x90, 0xa3, 0x18, 0x84, 0x5a, 0x63, 0x08, 0x91, 0x90, 0x81, 0x7a, 0xbe, 0x90, 0xa0, 0x05, 0xc2, 0xb1, 0xe4, 0xdd, 0x70, 0x1f, 0x79, 0x9c, 0x01, 0x9f, 0x0f, 0xa1, 0xd8, 0x50, 0x98, 0x37, 0x6d, 0xae, 0xa6, 0x94, 0x74, 0x85, 0x72, 0xe8, 0x14, 0x12, 0x5f, 0xc9, 0x91, 0xb4, 0xd3, 0xe1, 0xca, 0x24, 0xc9, 0x89, 0x68, 0x36, 0x26, 0x22, 0x48, 0xa4, 0xfa, 0x58, 0x43, 0xe7, 0x0c,\n\t0x5b, 0xba, 0x98, 0xf2, 0x0d, 0xf7, 0x56, 0x6d, 0xfd, 0xf5, 0xaf, 0xfc, 0x11, 0x88, 0x6f, 0xba, 0x09, 0x88, 0xff, 0xf8, 0xca, 0xf5, 0xf5, 0xe8, 0x1b, 0xfb, 0xaf, 0x9b, 0x6e, 0x62, 0xff, 0x85, 0xbe, 0xcd, 0xac, 0xdc, 0xf8, 0xc4, 0xbb, 0x5f, 0xee, 0xd8, 0xf1, 0xe5, 0xbb, 0x4f, 0x6c, 0xac, 0x4c, 0xfc, 0x4c, 0xfd, 0x2a, 0x25, 0x2f, 0x1a, 0xec, 0xab, 0xcf, 0xc8, 0x68, 0xbf, 0xa6, 0xbe, 0x7a, 0xa4, 0x25, 0x5d, 0x65, 0xf5, 0x9b, 0xef, 0x55, 0x17, 0x38, 0x1e, 0x9c, 0x57, 0x5b, 0x90, 0x1a, 0x72, 0x6a, 0xeb, 0x8b, 0x0a, 0x1a, 0xc8, 0x3b, 0x50, 0xa3, 0xaf, 0xa2, 0x46, 0x5f, 0x4d, 0x68, 0x94, 0x7f, 0xe1, 0xf8, 0x46, 0x7f, 0xce, 0x7d, 0xfe, 0xf9, 0x97, 0xbf, 0xf5, 0x59, 0x1d, 0x35, 0x4b, 0x6b, 0x2b, 0xae, 0xe9, 0xce, 0xcd, 0x6a, 0x5f, 0x5b, 0x13, 0xec, 0xee, 0xe8, 0xc8, 0x60,\n\t0xbf, 0x49, 0x4d, 0x26, 0x1f, 0xad, 0x6d, 0x30, 0xa6, 0x45, 0xec, 0x55, 0x4d, 0x2d, 0xc4, 0x84, 0xb9, 0xf7, 0x50, 0x0f, 0x10, 0x67, 0xd1, 0xfe, 0x03, 0xd7, 0xc4, 0xd7, 0x40, 0x15, 0x5b, 0xcb, 0xa7, 0xc9, 0x29, 0xd7, 0xcb, 0x4b, 0xbb, 0xf8, 0x3a, 0x6f, 0x27, 0xd6, 0xe1, 0xca, 0x3e, 0x0d, 0xa6, 0xde, 0xbb, 0xd4, 0xe3, 0x53, 0xbd, 0xe7, 0x92, 0x75, 0x02, 0xd4, 0x89, 0xab, 0xae, 0x93, 0x39, 0xf5, 0x7b, 0x2e, 0x39, 0x9e, 0x74, 0xea, 0xd1, 0xab, 0x7e, 0x8f, 0x8f, 0x7a, 0xf2, 0xaa, 0xdf, 0x93, 0x45, 0xbd, 0x76, 0xd5, 0xef, 0x49, 0xa3, 0x0e, 0x4f, 0x55, 0x87, 0x3b, 0x23, 0x4f, 0x53, 0xb1, 0x3a, 0x70, 0xff, 0x4f, 0x3c, 0x2b, 0xc3, 0xc4, 0xdd, 0x51, 0xe9, 0xdc, 0x99, 0xa4, 0x48, 0x0a, 0x8f, 0x8c, 0x04, 0x29, 0x25, 0xc8, 0x52, 0x96, 0x4b, 0x88, 0xa4, 0x12, 0xa9, 0x48, 0x32,\n\t0x76, 0x72, 0xa4, 0x22, 0x46, 0xda, 0x45, 0x48, 0xe0, 0xb9, 0x91, 0xd0, 0x03, 0x32, 0x31, 0xc9, 0x08, 0x01, 0xf2, 0x51, 0x4f, 0x3c, 0x42, 0x96, 0x68, 0xde, 0xa4, 0x6a, 0x0c, 0xae, 0x38, 0x10, 0xaf, 0x08, 0xc4, 0xa8, 0x9e, 0x78, 0x5c, 0xbd, 0x9e, 0xa8, 0xa1, 0xa3, 0x63, 0xc5, 0xb2, 0x85, 0x0b, 0x3a, 0xe6, 0x75, 0xcc, 0x83, 0x24, 0x97, 0x3b, 0x87, 0xf2, 0xff, 0xc4, 0x39, 0xc4, 0xd1, 0xd3, 0x23, 0x42, 0x94, 0xef, 0x26, 0x0b, 0x88, 0xc1, 0xbf, 0x7f, 0x2a, 0xe9, 0xdf, 0x5e, 0xec, 0x54, 0xb2, 0x1f, 0x9f, 0xa6, 0x16, 0x49, 0x53, 0xac, 0x16, 0x51, 0x2e, 0x70, 0x92, 0x29, 0xff, 0x1f, 0x9d, 0x51, 0xea, 0x97, 0xe7, 0xd3, 0xc8, 0x3d, 0x99, 0x39, 0xf3, 0x24, 0x62, 0x20, 0x95, 0x95, 0x03, 0x11, 0xfb, 0xb3, 0x84, 0x43, 0x3b, 0xe1, 0xcc, 0x7e, 0x8b, 0xf7, 0x84, 0x1f, 0x04, 0x2e,\n\t0xb5, 0xf7, 0xa0, 0x10, 0x81, 0x82, 0x6c, 0xcc, 0x60, 0xce, 0x42, 0xe6, 0x9b, 0x14, 0x35, 0x20, 0x71, 0x67, 0xc1, 0x58, 0xc4, 0xa7, 0x44, 0x8f, 0x60, 0x30, 0xe3, 0x2c, 0x73, 0xf6, 0xdb, 0x62, 0x58, 0x92, 0x24, 0x06, 0x2f, 0x7c, 0x4e, 0x87, 0x99, 0x7b, 0xa1, 0x8c, 0x9d, 0x8d, 0x32, 0x20, 0x19, 0x79, 0x2f, 0x37, 0x3e, 0x9d, 0x36, 0x4d, 0xa3, 0xf8, 0x74, 0x63, 0x61, 0x53, 0xd1, 0x9d, 0x99, 0xdb, 0x69, 0x49, 0xe2, 0x54, 0x07, 0x81, 0x64, 0xb2, 0x3b, 0x14, 0x0a, 0x69, 0x34, 0x11, 0x7d, 0xcd, 0x07, 0xbf, 0x22, 0x2b, 0xaa, 0x86, 0xa7, 0x07, 0xd2, 0x9b, 0x86, 0x2a, 0xaa, 0x96, 0x37, 0xfb, 0x3d, 0xf5, 0x4b, 0x8d, 0x6a, 0xbb, 0x32, 0xb8, 0xa6, 0xb2, 0xe3, 0xee, 0x35, 0x95, 0xb5, 0x3b, 0x9e, 0x5b, 0xb1, 0xfc, 0xe9, 0x6b, 0x2b, 0xdb, 0x66, 0x82, 0x85, 0xca, 0xb0, 0xf3, 0xc9,\n\t0xdb, 0x32, 0x9a, 0x87, 0xca, 0xaa, 0x96, 0x35, 0xfa, 0xb2, 0x5a, 0x96, 0x14, 0x56, 0x2c, 0x6f, 0x0e, 0x90, 0x7f, 0x37, 0xa4, 0xe9, 0x52, 0x1d, 0xf9, 0x43, 0xf7, 0x2f, 0x1a, 0x78, 0x62, 0x4b, 0x5d, 0xf5, 0xb6, 0xe7, 0x87, 0xe7, 0xbc, 0xb7, 0x1e, 0x7c, 0xa4, 0xb3, 0x70, 0x7a, 0x60, 0x1f, 0x1c, 0x47, 0x80, 0x79, 0x1c, 0xeb, 0x0a, 0x35, 0x44, 0x59, 0xb4, 0x38, 0x1f, 0xc7, 0x99, 0x8a, 0x39, 0x7a, 0x09, 0x01, 0x6f, 0xb3, 0x5d, 0x8a, 0x3d, 0xd9, 0x30, 0x1e, 0x7d, 0x88, 0x6e, 0xd4, 0xeb, 0x00, 0x51, 0x5e, 0x96, 0x9d, 0x95, 0x6a, 0xd5, 0x79, 0xf5, 0x5e, 0x6e, 0x54, 0xa2, 0x29, 0x46, 0xa5, 0x4d, 0xd0, 0x81, 0xd1, 0x73, 0x6d, 0x0a, 0x48, 0x1c, 0x5e, 0xa2, 0x8b, 0x81, 0x80, 0xac, 0xac, 0x5c, 0x52, 0xef, 0xc9, 0x6c, 0x5e, 0x54, 0x58, 0xb4, 0xa8, 0x39, 0xc3, 0x53, 0xbf, 0xa4,\n\t0xb2, 0xb4, 0xbf, 0x34, 0xd5, 0x52, 0x34, 0xab, 0x72, 0xda, 0xec, 0x22, 0x4b, 0x6a, 0x69, 0xff, 0x5d, 0xbb, 0xf6, 0xd4, 0x6c, 0x3b, 0x31, 0x34, 0x74, 0x62, 0x5b, 0xcd, 0x9e, 0x5d, 0x2b, 0x86, 0xcb, 0x56, 0x3d, 0x30, 0x6f, 0xde, 0x03, 0xab, 0xca, 0x86, 0xf7, 0x78, 0xaa, 0xe6, 0x14, 0x54, 0x2f, 0x28, 0x4f, 0x4d, 0x2d, 0x5f, 0x50, 0x5d, 0x30, 0xa7, 0xca, 0x43, 0xef, 0x71, 0x47, 0xdb, 0x83, 0xc8, 0x15, 0xc2, 0x5f, 0xd5, 0x93, 0x15, 0x6c, 0x8f, 0xba, 0x47, 0x7f, 0xe9, 0x7b, 0xe6, 0x86, 0x59, 0x07, 0x97, 0x16, 0x16, 0x2e, 0x3d, 0x38, 0xeb, 0x86, 0x67, 0x7c, 0xfe, 0x47, 0x56, 0x4d, 0xdf, 0x33, 0x58, 0x58, 0x38, 0xb8, 0x67, 0xfa, 0xaa, 0x47, 0x30, 0x5d, 0xe8, 0xb8, 0xf0, 0x37, 0xe6, 0x5f, 0xcc, 0x31, 0x5e, 0x67, 0xaa, 0x82, 0xb2, 0xf6, 0x11, 0xce, 0x30, 0x85, 0x1c, 0xbd,\n\t0x08, 0x21, 0xb2, 0x89, 0x0a, 0x09, 0x91, 0x58, 0x28, 0xe2, 0x4e, 0x2e, 0x72, 0x2d, 0x58, 0x8a, 0x22, 0x09, 0x31, 0xbd, 0x02, 0x2e, 0x88, 0x0c, 0xef, 0xc2, 0x92, 0x7e, 0xa9, 0xe2, 0xb0, 0x20, 0xaa, 0x83, 0xcd, 0x08, 0x43, 0x02, 0x9c, 0xc3, 0x66, 0x62, 0x69, 0xb4, 0x73, 0x62, 0xb4, 0x61, 0x72, 0x0d, 0xe4, 0xf1, 0xda, 0xd9, 0xee, 0xf3, 0xb9, 0x9d, 0x1e, 0xa4, 0x8a, 0xa1, 0xb8, 0x69, 0x13, 0x55, 0x31, 0x61, 0xee, 0x78, 0xd3, 0x43, 0x42, 0xe8, 0x8b, 0xcb, 0x94, 0x24, 0x7f, 0x95, 0xd7, 0xbd, 0x26, 0x5a, 0xb5, 0xa6, 0x33, 0x3b, 0xbb, 0x73, 0x4d, 0x55, 0xd5, 0x9a, 0xae, 0xec, 0x83, 0x96, 0xcc, 0x52, 0xa7, 0xb3, 0x14, 0x01, 0x1e, 0xd1, 0xbf, 0x99, 0x16, 0x72, 0xaf, 0x34, 0x16, 0xfa, 0xe2, 0x16, 0xa6, 0x6e, 0xca, 0xe2, 0xae, 0x12, 0x54, 0xbc, 0xc4, 0x85, 0x8a, 0xd3, 0xe5,\n\t0xed, 0x3b, 0x7b, 0xb3, 0xb3, 0x7b, 0x77, 0xb6, 0x77, 0xee, 0xea, 0xcf, 0xce, 0xee, 0xdf, 0xd5, 0x19, 0xed, 0x89, 0x24, 0x25, 0x45, 0x7a, 0xa2, 0xa5, 0x5d, 0x61, 0x93, 0x29, 0xdc, 0x05, 0xd6, 0x73, 0x11, 0x2f, 0x40, 0x5b, 0x42, 0xc1, 0x60, 0x10, 0x15, 0xec, 0x46, 0x05, 0xbb, 0xa3, 0x65, 0x9d, 0xa8, 0x60, 0x27, 0xb6, 0x5b, 0x6f, 0x64, 0x8f, 0x81, 0xed, 0xb4, 0x08, 0x67, 0x6b, 0x42, 0x59, 0x86, 0x79, 0x45, 0x69, 0x79, 0x03, 0x0e, 0xd6, 0x80, 0xe6, 0x78, 0x11, 0xe7, 0x64, 0xa9, 0xd3, 0x20, 0x9c, 0x9e, 0x81, 0x81, 0xe7, 0x56, 0xab, 0x46, 0xd6, 0xe8, 0x10, 0x72, 0x88, 0xa5, 0x12, 0xc8, 0x23, 0x9a, 0x87, 0x87, 0x21, 0x49, 0x16, 0x5c, 0x07, 0xff, 0xd0, 0x1f, 0xeb, 0x9c, 0xc1, 0x64, 0x4b, 0xd0, 0xa5, 0xd7, 0xbb, 0x82, 0x96, 0xe4, 0xa0, 0x53, 0xc7, 0x1e, 0x23, 0x2d, 0x19,\n\t0x9d, 0x5d, 0xfd, 0xa1, 0x50, 0x7f, 0x57, 0x67, 0xc6, 0xe8, 0xef, 0xe9, 0x5f, 0xa3, 0xa7, 0xa8, 0x54, 0x32, 0x57, 0x0a, 0xd3, 0x9a, 0x6a, 0x6a, 0x27, 0xd9, 0x24, 0x58, 0x44, 0x09, 0xc1, 0xa3, 0x50, 0x6c, 0xdf, 0x49, 0x88, 0x21, 0x97, 0x7a, 0x81, 0xda, 0xc9, 0x91, 0x15, 0xf8, 0xfb, 0x34, 0x6a, 0x13, 0x59, 0x8b, 0x7f, 0x7f, 0x6c, 0xca, 0xdf, 0xe7, 0xc1, 0xfa, 0x11, 0xc1, 0x3c, 0xf8, 0xfb, 0x23, 0x53, 0xfe, 0xde, 0x0e, 0x37, 0xe6, 0x2a, 0xe6, 0x10, 0xe1, 0x05, 0xc7, 0xc9, 0x39, 0xf0, 0x91, 0x17, 0x3c, 0x72, 0xe1, 0x1f, 0xe4, 0x69, 0x20, 0x04, 0x47, 0x29, 0x04, 0x13, 0x12, 0x43, 0x6e, 0xf8, 0x02, 0x79, 0x3a, 0x5e, 0x1e, 0xce, 0x12, 0xd3, 0xc5, 0x97, 0xcf, 0xe7, 0xcb, 0xff, 0x13, 0x97, 0x7f, 0x94, 0x92, 0x4d, 0x51, 0xbe, 0x03, 0x96, 0xdf, 0xc1, 0x3c, 0x84, 0xcb, 0xff,\n\t0x3f, 0xea, 0xde, 0x03, 0x3e, 0xae, 0xe2, 0xea, 0x1b, 0xbe, 0x33, 0xb7, 0x6d, 0x97, 0xb6, 0xef, 0x6a, 0xb5, 0xab, 0xed, 0xbb, 0xea, 0x65, 0xb5, 0x5a, 0x75, 0xad, 0x7a, 0xb7, 0x2d, 0xb9, 0xca, 0x96, 0x71, 0x91, 0x2c, 0x37, 0xd9, 0x96, 0x85, 0x71, 0xa1, 0xd8, 0xd8, 0x18, 0x07, 0x30, 0xc5, 0x04, 0x43, 0x4c, 0x09, 0x21, 0x81, 0x90, 0xd0, 0x42, 0xc7, 0xa1, 0x85, 0x84, 0x38, 0x84, 0x04, 0x42, 0x48, 0x9e, 0x40, 0x08, 0x49, 0x48, 0x20, 0x10, 0x9e, 0x02, 0x21, 0x05, 0x02, 0x09, 0xd6, 0xd5, 0x77, 0x66, 0xee, 0xee, 0xaa, 0x78, 0x6d, 0xcb, 0x79, 0xf2, 0x7e, 0xbf, 0xf7, 0xb5, 0x2d, 0xaf, 0xf6, 0x4e, 0xb9, 0x33, 0x67, 0x66, 0xce, 0x9c, 0x33, 0x73, 0xce, 0xff, 0xec, 0xa4, 0xf9, 0xef, 0x61, 0x4c, 0x89, 0xfa, 0x3d, 0xb3, 0xf3, 0x13, 0x5f, 0x08, 0xe9, 0x76, 0xb6, 0x0c, 0xe8, 0x1f,\n\t0x62, 0x6a, 0xc8, 0xbd, 0x2f, 0x83, 0x78, 0x96, 0x47, 0x24, 0xb6, 0x07, 0xe6, 0x59, 0xbc, 0x15, 0xe6, 0x2a, 0x65, 0x0f, 0x5b, 0x53, 0x8e, 0x87, 0x63, 0x4c, 0x4f, 0x18, 0xe4, 0xca, 0x6c, 0x7a, 0x34, 0xc4, 0xa7, 0x94, 0x0f, 0xae, 0x01, 0x45, 0xac, 0x16, 0x1d, 0x37, 0x05, 0x2b, 0x64, 0x45, 0xb3, 0x86, 0x86, 0x2d, 0x73, 0xf7, 0x2c, 0xdf, 0x58, 0xd7, 0x77, 0xe5, 0x50, 0x65, 0x61, 0xcb, 0x82, 0x8e, 0x32, 0xde, 0x74, 0xb9, 0x96, 0xcb, 0x6d, 0xe9, 0x6b, 0x2b, 0x71, 0x57, 0x75, 0x17, 0xd4, 0x2e, 0xaa, 0x09, 0x6a, 0x1d, 0x19, 0xd2, 0xc6, 0xd9, 0xc3, 0xf6, 0x73, 0x67, 0x34, 0x64, 0x2d, 0x58, 0xb8, 0xbb, 0xbb, 0x67, 0x53, 0x4f, 0x45, 0x71, 0x89, 0xe7, 0xd8, 0xdd, 0x25, 0x4d, 0xe5, 0x45, 0x35, 0x0b, 0xaa, 0x73, 0x9b, 0x8b, 0xec, 0x4e, 0xaf, 0xd3, 0xce, 0xb1, 0x53, 0xd9, 0x89,\n\t0x13, 0x6d, 0x09, 0xbd, 0x17, 0x81, 0xb5, 0xaf, 0x78, 0x7d, 0xc6, 0xda, 0xdf, 0xc2, 0xec, 0x67, 0x9e, 0x92, 0xd7, 0x7f, 0x6a, 0x41, 0xab, 0x91, 0xa8, 0x41, 0xb3, 0x97, 0xb4, 0x16, 0x11, 0x16, 0xa0, 0x02, 0x51, 0x60, 0x1a, 0x0f, 0x28, 0x3e, 0x63, 0x11, 0xba, 0xa6, 0x49, 0x39, 0x61, 0x85, 0x0a, 0x25, 0xf8, 0x40, 0x24, 0x4d, 0x89, 0x34, 0x9c, 0x60, 0x46, 0x29, 0x62, 0x4d, 0xba, 0xf7, 0xe2, 0x1d, 0xe3, 0x9b, 0x36, 0xac, 0x3e, 0x6f, 0x1a, 0x4f, 0xd0, 0xfd, 0x5b, 0x79, 0x42, 0xe0, 0xff, 0x77, 0x9e, 0xc1, 0xee, 0x3a, 0x6b, 0x8d, 0xff, 0x3e, 0xb6, 0xd2, 0x70, 0x76, 0xb6, 0xc3, 0xa0, 0x49, 0x49, 0xba, 0x0f, 0xb4, 0x70, 0x22, 0x1f, 0x08, 0x8f, 0xc2, 0x0e, 0x5f, 0x92, 0xcf, 0x46, 0xf4, 0x3e, 0xcc, 0x71, 0xfc, 0x89, 0xcf, 0xde, 0x27, 0xfa, 0xd7, 0x7a, 0xb6, 0x08, 0x4f, 0xf0,\n\t0xcf, 0x30, 0x0a, 0x26, 0x87, 0x89, 0xc0, 0x2e, 0xba, 0x2a, 0x3e, 0xa8, 0x27, 0xd8, 0x34, 0x5d, 0x04, 0x5c, 0x5a, 0xe0, 0x58, 0x61, 0x4c, 0x9d, 0x30, 0x8d, 0x18, 0x22, 0x0e, 0x8b, 0x04, 0x9c, 0x0b, 0x24, 0x41, 0x81, 0x51, 0x0a, 0xca, 0x55, 0x14, 0x27, 0x91, 0x40, 0x2b, 0xad, 0x13, 0x7b, 0xa2, 0xe5, 0x1e, 0x37, 0xc8, 0x35, 0x4c, 0x43, 0x5d, 0x79, 0x7b, 0xb4, 0x3d, 0x3f, 0xd7, 0x1d, 0xf1, 0x44, 0x08, 0xc0, 0xba, 0xc5, 0xa4, 0xcc, 0x51, 0xe5, 0x88, 0xa0, 0xbc, 0x21, 0x85, 0x8c, 0x60, 0x5b, 0x41, 0xaf, 0x35, 0xcd, 0xb1, 0x84, 0x19, 0x30, 0x3d, 0x6c, 0x2b, 0xa6, 0xf8, 0xb5, 0x66, 0x9f, 0xde, 0x38, 0x7b, 0x13, 0x9e, 0x1d, 0x61, 0xee, 0xfe, 0xfc, 0x40, 0x28, 0xb7, 0xb0, 0x30, 0xbf, 0x36, 0xa0, 0xcf, 0x0b, 0x19, 0xc4, 0x05, 0xbd, 0x46, 0x55, 0x3d, 0xaf, 0x55, 0x3b, 0xfb,\n\t0x2e, 0xaf, 0x5a, 0xd3, 0x11, 0x0e, 0x77, 0xac, 0xa9, 0xaa, 0x5c, 0xd3, 0x9e, 0x9b, 0xdb, 0xbe, 0x26, 0xd6, 0xb6, 0x67, 0x20, 0x12, 0x19, 0xd8, 0xd3, 0xd6, 0xba, 0x67, 0x79, 0x24, 0xb2, 0x7c, 0x0f, 0x6c, 0xac, 0x59, 0x59, 0xee, 0x3d, 0x4f, 0xe8, 0x5d, 0xb9, 0xf6, 0x50, 0x8d, 0x4e, 0xa5, 0xbf, 0xc2, 0xb0, 0x4d, 0xc5, 0x1f, 0x41, 0x07, 0xa5, 0x50, 0x5e, 0xe7, 0xda, 0xca, 0xaa, 0xb5, 0x5d, 0x79, 0x79, 0x5d, 0x6b, 0xab, 0x2a, 0xd7, 0x76, 0xe6, 0xe1, 0x45, 0x91, 0x81, 0x5d, 0x2d, 0x2d, 0x20, 0xbf, 0x95, 0x2f, 0x23, 0x9f, 0x03, 0x11, 0x99, 0xe7, 0x5c, 0x84, 0xd7, 0xe2, 0x6d, 0xac, 0x82, 0x60, 0x58, 0xa2, 0x41, 0x59, 0xd7, 0x1d, 0x4c, 0xca, 0xf3, 0x8f, 0xe2, 0x11, 0xf6, 0x35, 0xfc, 0x31, 0x2b, 0xa0, 0x6e, 0x66, 0x76, 0xda, 0x3e, 0x3c, 0xc2, 0x7f, 0x1b, 0x7f, 0x0c, 0xe5,\n\t0x7a, 0x4e, 0x29, 0x37, 0x8a, 0xca, 0xd1, 0x8b, 0xdc, 0x0a, 0xe0, 0x5b, 0x4d, 0x20, 0x68, 0x3f, 0x26, 0xa7, 0x3e, 0x06, 0xa9, 0x90, 0x76, 0x18, 0xd2, 0xde, 0xa7, 0x69, 0xcd, 0x8c, 0x7e, 0x56, 0x1a, 0x94, 0xc3, 0x9f, 0x01, 0xcf, 0x0a, 0xc9, 0xe5, 0x48, 0x79, 0x54, 0x0d, 0x79, 0x32, 0x93, 0x79, 0x88, 0xb6, 0x31, 0x55, 0x0f, 0x6b, 0xa5, 0x79, 0x69, 0x3d, 0xa4, 0x3e, 0xd4, 0x78, 0x9a, 0xbc, 0x3b, 0x71, 0x06, 0x7a, 0x8c, 0x9d, 0x0f, 0x6d, 0x9d, 0xaf, 0x9d, 0xdd, 0xd6, 0xef, 0xa1, 0x7c, 0xf6, 0x87, 0x5c, 0x39, 0xf4, 0x71, 0x1e, 0x73, 0x2e, 0x69, 0xbb, 0xd1, 0xdf, 0x39, 0x37, 0xbb, 0x06, 0xd2, 0x06, 0xf9, 0x19, 0x69, 0xc0, 0x97, 0x6f, 0x85, 0x49, 0xfa, 0x35, 0xfe, 0x5e, 0x90, 0x62, 0xec, 0xc4, 0xcb, 0x93, 0x9a, 0x35, 0x11, 0x11, 0x8e, 0x4d, 0xa2, 0xbf, 0x25, 0xb7, 0xc7,\n\t0x61, 0xb2, 0x3d, 0x5a, 0x4c, 0x1a, 0x15, 0x01, 0x78, 0x31, 0x90, 0xed, 0x31, 0xa2, 0x37, 0x46, 0x8c, 0xa7, 0xec, 0x8c, 0xdf, 0xcb, 0x3a, 0xe8, 0xf8, 0xdd, 0x6c, 0xe6, 0x8a, 0x6b, 0xd1, 0x26, 0xe9, 0xa6, 0x89, 0x13, 0x7c, 0xf0, 0x54, 0x1e, 0x8a, 0x99, 0x25, 0x93, 0x7f, 0x66, 0x63, 0xd0, 0x06, 0x23, 0x13, 0x25, 0x36, 0x33, 0x51, 0x72, 0xcd, 0xd6, 0x95, 0x3c, 0xbc, 0xe4, 0x51, 0x02, 0xae, 0x92, 0x02, 0x10, 0xe2, 0x41, 0x68, 0xd5, 0x28, 0x96, 0x85, 0x62, 0x7f, 0x96, 0x6d, 0x4a, 0x28, 0x46, 0xb3, 0x94, 0x98, 0x69, 0x60, 0x73, 0x64, 0xcf, 0x98, 0x42, 0xa2, 0x8b, 0xa1, 0x8f, 0x92, 0x1b, 0x72, 0xa2, 0x31, 0xa8, 0xd0, 0xdd, 0xbb, 0x7c, 0x03, 0xdd, 0x31, 0x72, 0x3a, 0x76, 0x0d, 0x64, 0x1f, 0x32, 0x35, 0x6d, 0x5f, 0x54, 0xe2, 0xae, 0xec, 0x2e, 0x88, 0xf4, 0xc7, 0x4b, 0x0d,\n\t0xdc, 0xd7, 0xa0, 0xa1, 0xd9, 0xd3, 0x1b, 0xfe, 0xf9, 0x5b, 0xce, 0xf2, 0xb0, 0xb5, 0xa8, 0x7f, 0x47, 0x6b, 0xd3, 0xfa, 0x35, 0x9b, 0x5a, 0x4f, 0x7c, 0x5a, 0xb6, 0x78, 0xe1, 0xf2, 0x58, 0x5e, 0x53, 0xb1, 0xdd, 0xe2, 0xf6, 0x69, 0x29, 0xcd, 0x57, 0x4e, 0x3a, 0xd1, 0x7f, 0x0a, 0x83, 0x30, 0x8e, 0x0b, 0xc4, 0x0e, 0x99, 0xe6, 0x1d, 0xc9, 0xf1, 0x68, 0x87, 0xb4, 0xff, 0xa0, 0x69, 0x7d, 0x19, 0xb3, 0xd3, 0xbe, 0x37, 0xe9, 0xc5, 0x35, 0x42, 0x27, 0xa4, 0xf5, 0x9f, 0x92, 0xd6, 0x31, 0xe9, 0x45, 0xdf, 0xa7, 0x69, 0x0b, 0xb5, 0xb3, 0xd3, 0x3a, 0xa1, 0x5c, 0x80, 0xa6, 0x2d, 0x52, 0xcc, 0x4e, 0xeb, 0x81, 0xb4, 0x10, 0x4d, 0x5b, 0xac, 0x99, 0x95, 0x36, 0xf9, 0x21, 0x08, 0xf2, 0x04, 0x63, 0x5d, 0x44, 0x0f, 0x21, 0x82, 0xe1, 0x45, 0xf2, 0xaf, 0x9b, 0x3c, 0x22, 0x44, 0xf9, 0xd7,\n\t0x40, 0xb6, 0x20, 0x92, 0xc3, 0xa5, 0xf2, 0xc9, 0xd3, 0xa5, 0xa4, 0x04, 0x62, 0xd6, 0xc3, 0xbe, 0x7f, 0x94, 0xfa, 0xbd, 0x95, 0xc5, 0x8b, 0x2b, 0xbc, 0x59, 0x02, 0x47, 0xdd, 0x82, 0x13, 0xee, 0xa6, 0x20, 0xe9, 0x13, 0x40, 0x6e, 0xd9, 0xb7, 0x4d, 0x56, 0x82, 0x62, 0x4c, 0x2c, 0xcf, 0x98, 0x97, 0xe7, 0x13, 0x55, 0x76, 0x72, 0xa8, 0x2a, 0xf8, 0x3c, 0xfa, 0x29, 0x3c, 0x51, 0x19, 0xe5, 0xdf, 0x43, 0x70, 0x20, 0x3d, 0xd1, 0x59, 0xc0, 0xa2, 0x66, 0xfe, 0x68, 0xd8, 0x2d, 0x89, 0xf3, 0x2e, 0x5b, 0x1d, 0x6d, 0xba, 0xe0, 0xae, 0x35, 0x6b, 0xee, 0xdc, 0xd9, 0x54, 0xb1, 0xea, 0xe0, 0x3c, 0x49, 0xf4, 0x84, 0xd0, 0x6d, 0xab, 0x8f, 0x6d, 0xaa, 0x5a, 0xfb, 0xd0, 0xdf, 0x8e, 0x5c, 0xff, 0xb7, 0x87, 0xd6, 0x56, 0x6d, 0x3e, 0xb6, 0xfa, 0xd1, 0xad, 0xae, 0x10, 0x7a, 0x41, 0x57, 0x3f,\n\t0x74, 0xd5, 0xe0, 0xfa, 0xdb, 0x37, 0x55, 0x54, 0x6c, 0xba, 0x7d, 0xfd, 0xe0, 0x55, 0x43, 0xf5, 0x3a, 0xa9, 0x3a, 0xe4, 0xda, 0x7a, 0x97, 0x75, 0xf5, 0x95, 0xf7, 0x0f, 0xed, 0x7d, 0xfd, 0xd6, 0xa5, 0x4b, 0x6f, 0x7d, 0x7d, 0xef, 0xd0, 0xfd, 0x57, 0xae, 0xb6, 0xde, 0x45, 0xfa, 0xb9, 0x1c, 0xf4, 0x97, 0x3c, 0xe8, 0xbb, 0xc0, 0x5d, 0xf0, 0x31, 0xf9, 0x3e, 0x04, 0xdf, 0x23, 0xd0, 0x37, 0x81, 0xdb, 0x29, 0xd2, 0x79, 0x09, 0xfc, 0xf6, 0x59, 0x8a, 0x0b, 0x59, 0x45, 0xb0, 0x32, 0xa7, 0x43, 0x40, 0xea, 0x10, 0xc1, 0x80, 0x54, 0x81, 0xb0, 0xc2, 0xa8, 0x07, 0x32, 0x33, 0xb4, 0xac, 0x5a, 0x3d, 0x92, 0x84, 0x84, 0xe4, 0x38, 0xae, 0x8a, 0xab, 0xaa, 0x20, 0x30, 0xd4, 0xc5, 0x05, 0x79, 0x04, 0x18, 0xd2, 0xe3, 0xb3, 0xe8, 0x8d, 0x1e, 0xbf, 0x3e, 0x53, 0x4f, 0x41, 0x21, 0x59, 0x8f,\n\t0x6c, 0x6f, 0x4b, 0x2e, 0x7c, 0x32, 0x90, 0x8f, 0xce, 0xd3, 0x98, 0x31, 0x09, 0x0a, 0xe9, 0x0d, 0xc2, 0x7c, 0x35, 0xfa, 0x68, 0x70, 0x0b, 0x19, 0xb1, 0xd6, 0x63, 0x84, 0x8c, 0x22, 0xcb, 0x46, 0xa5, 0x37, 0xea, 0x50, 0x18, 0xfd, 0x20, 0x83, 0x0f, 0xe7, 0x5d, 0x5a, 0x7f, 0xaf, 0x2b, 0x5b, 0x54, 0xfe, 0x57, 0xff, 0x80, 0xce, 0x96, 0x29, 0x72, 0xcd, 0xd2, 0x1b, 0x2d, 0x62, 0x99, 0x7b, 0x69, 0xff, 0x95, 0x39, 0x0e, 0x51, 0xf9, 0x62, 0xfd, 0x1f, 0x74, 0x90, 0xe7, 0x86, 0x56, 0xa1, 0xd8, 0x3d, 0xd0, 0x8f, 0xc2, 0xfd, 0x4b, 0xdd, 0x7e, 0xa1, 0x95, 0xdd, 0x2c, 0xbd, 0x88, 0x5e, 0x5c, 0x98, 0xe3, 0x92, 0x5e, 0x0c, 0x14, 0x34, 0x48, 0x2b, 0xb5, 0x56, 0x97, 0x01, 0xcd, 0x97, 0xbe, 0x11, 0xf6, 0xa2, 0x3b, 0xfd, 0x85, 0x0d, 0xa8, 0xb2, 0xdf, 0xed, 0x42, 0x83, 0xee, 0x80, 0xb4,\n\t0x0a, 0x7d, 0x15, 0x28, 0xff, 0x0d, 0xd9, 0x0e, 0x64, 0xd2, 0xc2, 0xd9, 0x84, 0x8d, 0x8c, 0x80, 0x36, 0x7d, 0x42, 0xbe, 0xaf, 0x99, 0xb4, 0xb1, 0xef, 0x72, 0xef, 0xc3, 0xf7, 0xcd, 0xbf, 0x26, 0xdf, 0x09, 0x1e, 0xfd, 0x72, 0xfe, 0x3e, 0x2c, 0x20, 0x39, 0x2e, 0x51, 0x13, 0x7c, 0x27, 0x58, 0xe1, 0x5e, 0xa6, 0x2a, 0x5e, 0x91, 0x85, 0x18, 0x25, 0xf1, 0x46, 0x4b, 0xc4, 0xd8, 0x5c, 0x3b, 0x15, 0x33, 0x81, 0xdc, 0x90, 0x27, 0xc3, 0x25, 0x78, 0xdd, 0x26, 0x43, 0x32, 0x58, 0x42, 0xa6, 0x3a, 0x19, 0xa2, 0x40, 0x0e, 0x96, 0x40, 0x4e, 0x9e, 0xe1, 0x2f, 0x9a, 0x1d, 0xd9, 0x96, 0x0d, 0xa0, 0xa0, 0xf4, 0x30, 0xb4, 0xfe, 0xe1, 0x13, 0xf2, 0x07, 0x7c, 0x8d, 0x3c, 0x98, 0xed, 0x53, 0xa1, 0x5c, 0x93, 0x43, 0xa5, 0xc8, 0x32, 0xa2, 0x5c, 0x45, 0xc0, 0xf1, 0x10, 0x3e, 0x7f, 0xdb, 0xd6,\n\t0x31, 0xe9, 0x4d, 0x14, 0x1c, 0xdb, 0xba, 0x8d, 0xcd, 0xcd, 0xb2, 0x4e, 0xfc, 0x3e, 0xaf, 0xdd, 0xe7, 0x6f, 0xcb, 0xc3, 0x6e, 0xa3, 0x2b, 0x81, 0xc9, 0x00, 0xed, 0xbd, 0xe0, 0xdf, 0x1d, 0xdb, 0xe1, 0x3f, 0xb1, 0x73, 0xe2, 0x0f, 0xa8, 0x4b, 0x7a, 0xe2, 0xb5, 0xef, 0x7f, 0x9f, 0x5d, 0x7b, 0x6a, 0x6c, 0x07, 0xa0, 0xdb, 0x30, 0xbc, 0xf7, 0x3a, 0x90, 0x1b, 0x05, 0xce, 0x54, 0x4c, 0x74, 0xe9, 0x01, 0x58, 0x57, 0x6a, 0x8a, 0xeb, 0xaf, 0x06, 0x49, 0xe0, 0x5c, 0x70, 0xfd, 0x73, 0x5c, 0xd9, 0x32, 0xaa, 0xbf, 0xc9, 0xa8, 0x27, 0x11, 0xb8, 0x4f, 0xc1, 0xf5, 0x4f, 0x81, 0xce, 0xce, 0xc0, 0xf5, 0xe7, 0xac, 0x11, 0xbc, 0xe3, 0xd8, 0x7d, 0xfa, 0x89, 0xbf, 0x60, 0x83, 0xe6, 0x9e, 0xaf, 0x3d, 0xcd, 0xf6, 0x5f, 0xae, 0x5a, 0x70, 0xe8, 0x99, 0x9d, 0x4f, 0xbf, 0x78, 0xec, 0x18, 0xba,\n\t0x4c, 0x42, 0x0a, 0xed, 0x41, 0x7c, 0xe3, 0xc1, 0x8b, 0x26, 0xd1, 0xb6, 0x03, 0x17, 0x49, 0x37, 0x90, 0xf5, 0x26, 0x89, 0xec, 0xd1, 0x31, 0x74, 0xec, 0xd5, 0x17, 0x09, 0xdd, 0x96, 0x4e, 0xfe, 0x85, 0x3f, 0x8f, 0xfa, 0x08, 0x0f, 0xc6, 0x07, 0x40, 0x44, 0x61, 0xcb, 0x41, 0xf4, 0xc4, 0x5d, 0xa0, 0x8b, 0x10, 0x27, 0xe7, 0x31, 0x06, 0xc4, 0x50, 0x51, 0xa9, 0x18, 0xe3, 0x10, 0xa3, 0x45, 0xb4, 0x1b, 0x20, 0xb4, 0x80, 0x80, 0xaa, 0x14, 0xc4, 0xa1, 0xe4, 0x0d, 0xc4, 0x66, 0x62, 0x30, 0x4c, 0xbd, 0xae, 0x46, 0x55, 0x3d, 0x1d, 0xed, 0x8d, 0xf1, 0x86, 0xfa, 0xea, 0xca, 0x92, 0x62, 0xaf, 0xcf, 0xef, 0x33, 0xf8, 0xad, 0xfe, 0x4c, 0x22, 0x8d, 0x1a, 0x23, 0x32, 0x10, 0xf3, 0x34, 0x03, 0x07, 0x51, 0x0e, 0x5f, 0x21, 0x98, 0xb3, 0x91, 0x55, 0xfe, 0x55, 0xc6, 0x93, 0x9d, 0x06, 0xf5,\n\t0x13, 0x82, 0x2e, 0x06, 0xcb, 0xc9, 0x29, 0x81, 0x6f, 0xe9, 0xcb, 0xd6, 0xcd, 0x5f, 0xff, 0xf5, 0xa1, 0xe6, 0x8b, 0xb7, 0x9d, 0xe7, 0x2f, 0x33, 0xd8, 0x8c, 0x99, 0x25, 0xdd, 0x9b, 0xba, 0x1e, 0xfe, 0x63, 0x18, 0x5f, 0xe4, 0xca, 0x9a, 0xf8, 0x16, 0x8b, 0x70, 0x91, 0x2b, 0x4b, 0xb2, 0x78, 0x7f, 0x77, 0xdf, 0xd2, 0xed, 0x5d, 0x25, 0x16, 0x8d, 0x45, 0xdb, 0xe4, 0x5b, 0xbb, 0xfb, 0x70, 0xf7, 0xe5, 0xaf, 0xdd, 0x36, 0x64, 0x7c, 0xf1, 0x59, 0xd8, 0xf7, 0xbe, 0xc3, 0x1e, 0xbe, 0xe4, 0xc7, 0xd7, 0xf4, 0xd8, 0x8b, 0x5b, 0x0b, 0x62, 0x26, 0xa3, 0x37, 0xec, 0xfd, 0xce, 0xf1, 0x3a, 0xa3, 0x3b, 0x18, 0xca, 0xc8, 0xd6, 0xc1, 0xe7, 0x89, 0x1f, 0x84, 0x8a, 0x43, 0x4a, 0x75, 0x4d, 0xa4, 0xaf, 0xd2, 0x39, 0xff, 0x86, 0x9f, 0xed, 0x1f, 0xd3, 0x65, 0x67, 0x98, 0x82, 0x46, 0x59, 0xe7,\n\t0x21, 0x78, 0xc3, 0x56, 0xee, 0x3c, 0xca, 0x3f, 0xf6, 0x24, 0x2c, 0x16, 0x80, 0x71, 0xa8, 0xd5, 0x9a, 0x11, 0xca, 0x32, 0x08, 0xfb, 0x40, 0xea, 0x99, 0xd8, 0xb2, 0x09, 0x1e, 0xe2, 0x88, 0x07, 0x49, 0x4e, 0xcd, 0xf8, 0xd9, 0x32, 0x0e, 0xc4, 0x5d, 0x67, 0xe3, 0x37, 0x3e, 0x31, 0x22, 0xf3, 0x1b, 0x71, 0x1a, 0xbf, 0x69, 0x80, 0xc7, 0xd3, 0xf8, 0x4d, 0x4c, 0xe6, 0x37, 0x31, 0x19, 0xcb, 0xde, 0x48, 0x33, 0xe2, 0x5b, 0xff, 0xa3, 0xf2, 0x17, 0xe8, 0x51, 0x0d, 0x70, 0x92, 0xdd, 0xb1, 0x5b, 0x5d, 0x0e, 0x41, 0xf5, 0x56, 0xcb, 0x32, 0xca, 0x6d, 0xa2, 0xbf, 0x8c, 0x8a, 0x91, 0x9c, 0xe5, 0x9d, 0x97, 0xc0, 0x43, 0xcd, 0x77, 0x2a, 0xff, 0x83, 0x64, 0xb9, 0x2a, 0x46, 0x98, 0x4d, 0xfb, 0x9b, 0x8d, 0x4b, 0x72, 0xfc, 0x7c, 0x14, 0xdf, 0xfd, 0x11, 0xda, 0x07, 0xfc, 0xe4, 0x23, 0x7f,\n\t0x61, 0xbd, 0xf4, 0x06, 0xe1, 0x34, 0xbf, 0x78, 0x0b, 0xf8, 0x4c, 0xd8, 0x5f, 0xd0, 0xf0, 0x11, 0x3c, 0x7e, 0xc7, 0x13, 0x90, 0xde, 0x40, 0xe1, 0xdc, 0x9c, 0xdf, 0x93, 0xb9, 0xbf, 0x63, 0xd2, 0xc2, 0x3e, 0xc5, 0x37, 0x82, 0x0c, 0x6c, 0x64, 0xda, 0x98, 0x96, 0x78, 0x63, 0x5b, 0x1d, 0x68, 0x85, 0x46, 0x98, 0xe6, 0x7c, 0x81, 0x1f, 0xc3, 0x94, 0xea, 0x62, 0x40, 0x49, 0x64, 0x29, 0x56, 0x38, 0x99, 0x5d, 0xd4, 0x14, 0x87, 0x45, 0x2b, 0xa7, 0x01, 0x12, 0x37, 0xc5, 0x89, 0xa3, 0x67, 0x28, 0x48, 0x4c, 0x9c, 0xe9, 0x11, 0x99, 0x8c, 0x4d, 0x1b, 0x62, 0xe5, 0x7d, 0x3f, 0x27, 0x61, 0x03, 0x08, 0xbd, 0x8f, 0x15, 0xa1, 0x50, 0x8c, 0x3a, 0xba, 0x59, 0x53, 0x31, 0x85, 0x22, 0xd3, 0x21, 0x57, 0x71, 0xf3, 0xa6, 0xa1, 0xec, 0x92, 0xa6, 0x60, 0x67, 0xa4, 0xbd, 0xd0, 0x64, 0x2f, 0xa8,\n\t0xf5, 0x6d, 0xad, 0xdb, 0xbd, 0xba, 0x26, 0xb6, 0xee, 0xba, 0xa5, 0x99, 0xdb, 0x33, 0x37, 0x3c, 0x58, 0x9b, 0x67, 0x0e, 0xea, 0x42, 0x35, 0x7d, 0x55, 0x8e, 0xba, 0x9d, 0xe7, 0x55, 0x17, 0x9f, 0x77, 0xdd, 0xaa, 0xcc, 0xb1, 0xcc, 0xa5, 0x47, 0x4a, 0x0b, 0x15, 0xa6, 0x0c, 0xad, 0xb7, 0xb8, 0xb1, 0xe0, 0x72, 0xd5, 0xea, 0x16, 0x4f, 0xa9, 0x3f, 0x4b, 0x8d, 0x35, 0xbc, 0x2b, 0xbf, 0xc2, 0xe5, 0x2a, 0xf2, 0x39, 0xd4, 0x6e, 0x7d, 0x5e, 0xeb, 0x48, 0x6f, 0xfb, 0xc5, 0xab, 0x6a, 0x85, 0xd7, 0xdf, 0x50, 0x2f, 0x6a, 0x68, 0xf2, 0x65, 0xfb, 0x7d, 0x22, 0x1a, 0xce, 0xcc, 0x6f, 0xdf, 0xbc, 0xa0, 0x7a, 0xfb, 0xf2, 0x5a, 0xfe, 0x3f, 0x7e, 0xa9, 0x6e, 0x2e, 0xed, 0xd2, 0x66, 0x9a, 0xb3, 0xb3, 0x45, 0xe8, 0xe6, 0xee, 0xc9, 0x10, 0xfb, 0x22, 0xf7, 0x65, 0x46, 0x00, 0xad, 0x72, 0x6b,\n\t0xdc, 0x18, 0xce, 0x21, 0x01, 0xcb, 0x73, 0x33, 0x04, 0x58, 0xda, 0xb8, 0x2b, 0x1b, 0xa4, 0xb4, 0x4e, 0x79, 0x42, 0x79, 0x88, 0x15, 0x25, 0xcc, 0x08, 0xe2, 0x28, 0x89, 0x79, 0x86, 0xc6, 0x0a, 0xc5, 0x40, 0x9a, 0x44, 0xe4, 0xba, 0x51, 0x72, 0x47, 0x7f, 0x96, 0x3c, 0xdb, 0x88, 0x1f, 0xb9, 0x32, 0x37, 0xa4, 0xcf, 0xd2, 0x3b, 0xa8, 0x21, 0x86, 0x6c, 0x9c, 0x07, 0x4a, 0x37, 0x25, 0x57, 0x3a, 0x1a, 0xb1, 0xb2, 0x59, 0x3e, 0xae, 0x3d, 0x74, 0xf0, 0xfc, 0x0d, 0xe8, 0x69, 0xf7, 0xfc, 0xa5, 0x2b, 0x8b, 0x74, 0x17, 0xe8, 0x96, 0x1c, 0xd9, 0x58, 0x53, 0x77, 0xc1, 0x03, 0xdb, 0x32, 0x2e, 0xc8, 0xe8, 0xbb, 0xb8, 0xac, 0x48, 0x6d, 0xd1, 0xeb, 0x9c, 0x81, 0xf2, 0x40, 0x49, 0x65, 0x77, 0xb9, 0x3f, 0x33, 0xd3, 0xac, 0x62, 0x2b, 0x32, 0x1f, 0xbb, 0xf1, 0xda, 0xfb, 0xec, 0x38, 0x58,\n\t0xe1, 0x37, 0xb0, 0x3f, 0xf9, 0xa9, 0xba, 0xfb, 0x92, 0x7b, 0x37, 0xad, 0xfb, 0xd6, 0x65, 0xf3, 0xc5, 0x5f, 0xbc, 0xa1, 0x6e, 0x2c, 0x6c, 0xd2, 0x69, 0xf5, 0x56, 0xab, 0x30, 0x31, 0x9f, 0x73, 0xb8, 0xac, 0x6a, 0x35, 0xe5, 0xcf, 0xc0, 0x70, 0xd9, 0xbf, 0x70, 0xdb, 0x99, 0x12, 0x72, 0xbe, 0xa8, 0x05, 0x3e, 0x93, 0x1f, 0xc0, 0xa2, 0x30, 0x8d, 0xd1, 0x20, 0x86, 0x60, 0x75, 0x0f, 0x51, 0x03, 0x78, 0x99, 0x5f, 0x0a, 0x02, 0xe5, 0xd8, 0xc3, 0x62, 0x8f, 0x59, 0xef, 0xf7, 0x19, 0x03, 0x81, 0x80, 0x57, 0xbe, 0x98, 0x4a, 0x05, 0xb6, 0x49, 0xda, 0xd9, 0x10, 0x48, 0x16, 0x27, 0x4a, 0x86, 0xc3, 0xa1, 0xd1, 0x70, 0x3c, 0xd1, 0x7a, 0x12, 0x00, 0x06, 0x36, 0xa5, 0x45, 0x05, 0xab, 0x6e, 0xda, 0x7c, 0xe0, 0x81, 0xc2, 0x4a, 0xb5, 0x55, 0x97, 0x61, 0xb5, 0x39, 0x73, 0xab, 0xc3, 0xe3,\n\t0x5b, 0xd0, 0x8d, 0x6e, 0xbb, 0x74, 0xd7, 0xf2, 0x96, 0x16, 0x1c, 0x3c, 0x39, 0x54, 0xbf, 0xe0, 0x26, 0x6c, 0xce, 0x0e, 0x6f, 0x5f, 0x74, 0xcb, 0x8e, 0xd6, 0x4b, 0xb7, 0x15, 0x2a, 0x34, 0x66, 0xb7, 0xdf, 0x6d, 0xbe, 0xe2, 0xe2, 0xf1, 0x2e, 0x93, 0x7b, 0xfc, 0x8a, 0xc5, 0xfa, 0x2f, 0x5f, 0xa8, 0x5b, 0xb1, 0xf0, 0xeb, 0xf2, 0x3e, 0xd3, 0x40, 0x94, 0x3d, 0xe0, 0x05, 0x7a, 0xe2, 0x45, 0xc0, 0x88, 0xb0, 0xaf, 0x30, 0xa2, 0x62, 0xcd, 0xa9, 0x1b, 0xce, 0x19, 0x77, 0x19, 0xfa, 0xd7, 0x17, 0x4d, 0xec, 0x32, 0xcf, 0xa2, 0x67, 0xa5, 0x66, 0xe4, 0x93, 0x7e, 0x7b, 0xe2, 0xa9, 0xa7, 0x58, 0x91, 0x7d, 0x46, 0xfa, 0xf1, 0xd1, 0x6f, 0x8f, 0xbe, 0xf2, 0xca, 0x28, 0xeb, 0xff, 0x9a, 0xfc, 0xce, 0x3e, 0xa0, 0xdd, 0xa7, 0x40, 0xbb, 0x2a, 0x66, 0x49, 0x7c, 0x61, 0x16, 0x12, 0xc4, 0x0a,\n\t0xa0, 0x98, 0x06, 0x68, 0x97, 0x84, 0x1b, 0xe0, 0x29, 0x88, 0xc3, 0x10, 0x85, 0x1b, 0x60, 0x31, 0x47, 0xb6, 0x65, 0xac, 0x46, 0x48, 0x03, 0xca, 0xa6, 0x16, 0x04, 0x1c, 0xd9, 0x68, 0x80, 0x4a, 0x71, 0x55, 0x4c, 0x65, 0xa4, 0x94, 0xe0, 0x9d, 0x13, 0x72, 0x92, 0x78, 0x7e, 0x7a, 0xc2, 0x9d, 0x03, 0x49, 0x72, 0xcd, 0x0a, 0x1c, 0x34, 0x9b, 0xbe, 0x53, 0x21, 0x87, 0xc8, 0x39, 0x35, 0xfb, 0x29, 0x90, 0x6e, 0xfe, 0x4d, 0x37, 0xdd, 0xe4, 0xb6, 0xaf, 0x2c, 0x58, 0x7d, 0xd3, 0xa6, 0x03, 0x0f, 0x14, 0x55, 0xa9, 0x52, 0x34, 0x3e, 0x7f, 0x14, 0x5d, 0x2c, 0x1d, 0x44, 0x17, 0xbb, 0x6d, 0xd2, 0x33, 0xcb, 0xbd, 0xcd, 0xbe, 0x2f, 0x53, 0x2a, 0x36, 0x2d, 0xdf, 0x19, 0x34, 0xb9, 0xc3, 0x33, 0x29, 0xfd, 0x85, 0x4b, 0x72, 0x97, 0xef, 0x0c, 0x98, 0x3c, 0x19, 0x57, 0x2c, 0x52, 0x28, 0x80,\n\t0x27, 0xc4, 0x80, 0xc6, 0x39, 0x40, 0x63, 0x9e, 0x9e, 0xf2, 0x35, 0xc7, 0xe3, 0x8c, 0x12, 0x26, 0x87, 0x92, 0x1d, 0x22, 0x3b, 0x26, 0xd9, 0x3c, 0x41, 0x8b, 0x5e, 0x33, 0xb5, 0xaf, 0x26, 0xf6, 0x4f, 0x8f, 0x7b, 0x6a, 0xff, 0x4c, 0x1b, 0x17, 0x87, 0xec, 0x9f, 0x72, 0x5c, 0x1c, 0x34, 0x3b, 0x2e, 0xce, 0x9f, 0xf6, 0xec, 0xd2, 0x4a, 0x97, 0xa0, 0xcb, 0x79, 0x77, 0xdd, 0xca, 0xf8, 0x21, 0x7c, 0xfc, 0x32, 0xfd, 0x2f, 0x7e, 0x74, 0xe8, 0xe9, 0x9d, 0x3b, 0x51, 0xe3, 0xe8, 0xed, 0x1b, 0x63, 0xc2, 0x7e, 0xf4, 0xd9, 0x92, 0xd5, 0x4f, 0x20, 0x6f, 0xa4, 0x25, 0xcf, 0x20, 0xbd, 0x7d, 0xf3, 0x37, 0xa5, 0x1b, 0xf0, 0xb7, 0x46, 0x51, 0x4b, 0x6e, 0xdf, 0x85, 0x0b, 0xc8, 0xfe, 0xb0, 0x0c, 0xda, 0x7b, 0xe0, 0xff, 0xe1, 0xfd, 0xe1, 0xb3, 0x0f, 0x63, 0x1f, 0xa0, 0xe7, 0x75, 0x42, 0x38,\n\t0xef, 0xb2, 0xd8, 0xdd, 0x39, 0xc0, 0x3b, 0xfe, 0x1b, 0xf6, 0x07, 0x3b, 0xec, 0x0f, 0xe5, 0x1f, 0x54, 0x82, 0x30, 0x3a, 0xd0, 0x79, 0x05, 0xd9, 0x34, 0x5e, 0x8a, 0xfd, 0x9e, 0x64, 0x39, 0x5a, 0x09, 0xfb, 0xc3, 0xb2, 0xd6, 0x3f, 0xb5, 0x2e, 0x06, 0x59, 0x34, 0x36, 0xf7, 0xfd, 0x81, 0x9c, 0x4d, 0xc2, 0xfe, 0x70, 0x1b, 0xec, 0x0f, 0x02, 0xf7, 0xf5, 0x77, 0x64, 0x39, 0x3d, 0xc4, 0x3e, 0x4a, 0x78, 0x23, 0x77, 0xf7, 0xff, 0x24, 0x65, 0x29, 0x25, 0xcc, 0x73, 0x81, 0xfb, 0x86, 0x8d, 0x7c, 0x27, 0xf1, 0x39, 0x4a, 0x80, 0xae, 0x02, 0xda, 0xe6, 0x4b, 0x9c, 0x85, 0x72, 0x66, 0xf2, 0x9d, 0xfb, 0xa6, 0x99, 0x7c, 0x4f, 0xac, 0x0b, 0x2c, 0x70, 0xf7, 0x50, 0x59, 0x6c, 0x04, 0xd2, 0xe7, 0xd1, 0xf4, 0x7b, 0x8b, 0x65, 0xbd, 0xe0, 0x2f, 0xdc, 0x3a, 0x6e, 0x14, 0xca, 0x6f, 0xec, 0x26,\n\t0xeb, 0x68, 0x09, 0xb3, 0x96, 0xfd, 0x3d, 0xa7, 0x01, 0xc9, 0xac, 0xad, 0xfb, 0xa1, 0x32, 0x62, 0xeb, 0x06, 0x8b, 0x95, 0xe8, 0xc9, 0x2c, 0xb3, 0x26, 0x19, 0x90, 0x71, 0x04, 0xc9, 0x98, 0x93, 0x2c, 0xe2, 0x16, 0x4f, 0x4b, 0xe5, 0x38, 0x02, 0xe0, 0xc7, 0xa1, 0x5e, 0x62, 0xea, 0x96, 0x42, 0x17, 0x46, 0x09, 0xd1, 0x96, 0xa2, 0xca, 0xfc, 0x5e, 0xba, 0xea, 0x0e, 0xe9, 0x6a, 0xb4, 0xe3, 0x0e, 0xb4, 0x13, 0x7d, 0x28, 0x5d, 0x80, 0x0e, 0x1f, 0x45, 0x87, 0xa5, 0x0b, 0xc8, 0xfc, 0xb8, 0x0c, 0xf5, 0xb2, 0x8f, 0xb3, 0x01, 0x8a, 0x5f, 0x4c, 0xf0, 0x63, 0x52, 0xe8, 0xc5, 0x08, 0x91, 0xf3, 0x57, 0x8a, 0x0d, 0xc8, 0x10, 0xf0, 0x57, 0x3d, 0x35, 0x9f, 0x49, 0x62, 0x16, 0x5f, 0xc6, 0x96, 0x9d, 0x7c, 0x85, 0xfc, 0xa0, 0x77, 0x6e, 0x44, 0x6f, 0x1c, 0x95, 0x65, 0x91, 0x63, 0xc8, 0xc9,\n\t0x7e, 0x85, 0x1d, 0xa0, 0x77, 0x97, 0x2b, 0xe2, 0xcb, 0x4c, 0xc0, 0x76, 0x04, 0x10, 0x26, 0x4b, 0x10, 0x27, 0x7a, 0x81, 0x6f, 0x12, 0xd4, 0x7f, 0x58, 0x1d, 0x2c, 0x1e, 0x22, 0x60, 0x40, 0x24, 0x5e, 0xf7, 0x90, 0x12, 0x71, 0x02, 0xcf, 0x2d, 0x85, 0x77, 0x13, 0xa0, 0x17, 0xf2, 0x95, 0x23, 0xb7, 0x39, 0x1c, 0x3f, 0xdf, 0x99, 0x8d, 0x98, 0xf2, 0xb2, 0xfc, 0xdc, 0xa0, 0x3f, 0x3b, 0xe6, 0x8c, 0xd9, 0x2c, 0x19, 0x5a, 0x95, 0x82, 0x71, 0x20, 0x87, 0x2a, 0x11, 0x21, 0x29, 0x66, 0x9d, 0xe6, 0xae, 0x15, 0x92, 0x6f, 0xa6, 0x8c, 0xa7, 0x79, 0x8e, 0xdf, 0x72, 0x56, 0x14, 0xb8, 0x15, 0x59, 0xde, 0x6d, 0xb5, 0x25, 0x6b, 0xcf, 0x5b, 0x91, 0xeb, 0xac, 0x28, 0x74, 0x2b, 0x5c, 0xde, 0xb1, 0x78, 0xd9, 0xda, 0xf3, 0x06, 0x72, 0xcf, 0x90, 0x86, 0x3f, 0xd3, 0x9a, 0xcc, 0xca, 0x4b, 0x0a,\n\t0xf3, 0x5d, 0x01, 0x97, 0xd6, 0x6c, 0x53, 0xed, 0x8e, 0x14, 0xc3, 0x6f, 0xd2, 0x93, 0x3a, 0x93, 0x85, 0x3e, 0xf5, 0xbb, 0xb4, 0x26, 0xfa, 0x34, 0x27, 0x90, 0x03, 0x64, 0xba, 0x8c, 0xd9, 0x08, 0xb4, 0x9c, 0x04, 0x09, 0x63, 0x8d, 0x0c, 0x62, 0xea, 0xa1, 0x30, 0x3c, 0xeb, 0x15, 0x48, 0x50, 0x29, 0x61, 0x53, 0x14, 0xf8, 0xb5, 0x1c, 0xb9, 0xb5, 0xa2, 0xec, 0x18, 0x76, 0x8f, 0x11, 0x91, 0xa2, 0x25, 0x11, 0xfc, 0xe3, 0x33, 0x64, 0x91, 0x21, 0xeb, 0x8c, 0x8c, 0x31, 0xc5, 0xab, 0xa9, 0xfe, 0x42, 0x7c, 0xd4, 0x44, 0x5f, 0xcc, 0x17, 0xf5, 0x10, 0xd3, 0x99, 0x58, 0x44, 0x8c, 0x98, 0xf1, 0x97, 0x17, 0xa1, 0x51, 0xa9, 0x67, 0xeb, 0x35, 0x5b, 0xff, 0x82, 0xaa, 0x16, 0x4b, 0xe3, 0xe8, 0xf5, 0x8d, 0x87, 0x37, 0xfe, 0x0c, 0x5f, 0xff, 0xe0, 0x8d, 0xef, 0xbe, 0x7b, 0xe3, 0x83, 0x47,\n\t0xdf, 0x7c, 0xf3, 0xa8, 0xcc, 0xb3, 0xaf, 0x67, 0xbe, 0xc8, 0x6e, 0x63, 0x7f, 0xcf, 0xa8, 0x18, 0xe1, 0x51, 0xa5, 0x80, 0x4a, 0xf2, 0x81, 0x6d, 0xc3, 0x5e, 0x6c, 0x46, 0x51, 0x64, 0x46, 0x2f, 0x06, 0x23, 0x91, 0x20, 0xfa, 0xc6, 0x84, 0x17, 0xbf, 0x85, 0x97, 0x9b, 0x34, 0x1a, 0xd3, 0x2f, 0x1f, 0x46, 0xfb, 0xfa, 0xd0, 0xde, 0x87, 0xe4, 0x31, 0xbe, 0x13, 0xe6, 0xf5, 0x7e, 0xce, 0x0a, 0x23, 0x99, 0xc9, 0x38, 0xe3, 0x59, 0x09, 0xe7, 0x3a, 0x71, 0x06, 0x20, 0xb5, 0x0c, 0x6b, 0x1c, 0x23, 0xb6, 0x94, 0x14, 0x9c, 0x2c, 0x51, 0xf5, 0x9d, 0xf8, 0xad, 0x09, 0x2f, 0xaa, 0x30, 0x12, 0x8f, 0x27, 0x23, 0xfa, 0x26, 0x79, 0xc3, 0xd1, 0xa3, 0xf8, 0x6b, 0x0a, 0x0d, 0xcf, 0x6b, 0x15, 0x27, 0x1e, 0x42, 0x23, 0x7d, 0x68, 0xdd, 0x83, 0xe4, 0x1d, 0xc7, 0xe1, 0x1d, 0x37, 0x4e, 0x7f, 0x07,\n\t0x0d, 0x7c, 0x73, 0xda, 0x77, 0x40, 0xe5, 0x01, 0x12, 0x33, 0x04, 0x85, 0x02, 0xd1, 0xe3, 0xe4, 0x1d, 0xf4, 0x3d, 0xdf, 0x30, 0x12, 0x37, 0x23, 0xa3, 0x34, 0x00, 0xef, 0x78, 0xa4, 0x4f, 0xba, 0xe5, 0xa1, 0x13, 0x0a, 0x2d, 0xcf, 0x6b, 0x14, 0x2f, 0x3c, 0x48, 0x69, 0xf0, 0x23, 0xa0, 0xc1, 0x37, 0x80, 0x06, 0x6a, 0xa0, 0x81, 0x1a, 0x13, 0x1a, 0x24, 0xaa, 0x09, 0x42, 0x2d, 0xec, 0x37, 0x48, 0x05, 0xa6, 0xc2, 0xac, 0xd2, 0x3c, 0x69, 0x00, 0xaf, 0xed, 0x93, 0xf6, 0x3f, 0xf4, 0x86, 0x3a, 0x43, 0x50, 0x59, 0x5e, 0x7f, 0x28, 0xc1, 0x53, 0xd9, 0x77, 0x38, 0x72, 0x8a, 0x9e, 0xc1, 0x94, 0xc6, 0x8b, 0x14, 0x22, 0xe6, 0x49, 0x48, 0x4a, 0xe2, 0xa2, 0x28, 0x90, 0x43, 0x58, 0x19, 0xfc, 0x3b, 0xd1, 0x50, 0xe0, 0x8c, 0x19, 0x5c, 0x06, 0x19, 0x36, 0x83, 0x3e, 0x53, 0xa9, 0x72, 0x24,\n\t0xda, 0x3c, 0xb5, 0x3a, 0x97, 0xb1, 0x57, 0x9d, 0xdc, 0xc9, 0x5e, 0x95, 0x5c, 0xa1, 0xd0, 0xdc, 0x37, 0x8e, 0x12, 0x7d, 0xf3, 0x28, 0x5a, 0x2a, 0xdd, 0x43, 0xdb, 0x7a, 0x19, 0xfa, 0x90, 0x7d, 0x1c, 0xef, 0x4f, 0x60, 0x48, 0xcf, 0x5e, 0x99, 0x94, 0x10, 0xc6, 0xe4, 0x9a, 0xc4, 0xfb, 0x8f, 0xd2, 0x32, 0x07, 0x98, 0xb7, 0x69, 0x19, 0x8a, 0xef, 0xad, 0xa4, 0x26, 0x7c, 0xa4, 0xe0, 0xfa, 0xd9, 0xa8, 0xce, 0xd4, 0x62, 0x2e, 0x0d, 0xda, 0x73, 0x0a, 0xdf, 0x3b, 0x20, 0xe3, 0x3d, 0x3f, 0x7e, 0xf7, 0xc4, 0xf9, 0x6c, 0xe4, 0x6d, 0xa4, 0x49, 0xcc, 0xa1, 0xcd, 0xcc, 0x21, 0xf6, 0x25, 0xf6, 0x37, 0x94, 0x7e, 0x02, 0xa1, 0x5f, 0x40, 0x89, 0x42, 0x4a, 0x14, 0x53, 0x22, 0x2b, 0xec, 0xf3, 0x43, 0xd2, 0x93, 0xd2, 0xf1, 0x0d, 0xa8, 0x43, 0x3a, 0xb1, 0x01, 0xb6, 0xee, 0xea, 0x8d, 0xd2,\n\t0x0f, 0x50, 0xfb, 0x15, 0xa8, 0x5d, 0x3a, 0xbe, 0x11, 0x75, 0xa0, 0xda, 0x8d, 0xd2, 0x09, 0x54, 0xbd, 0x5e, 0xfa, 0x81, 0xf4, 0xa4, 0x7c, 0xc7, 0xbb, 0x14, 0xd6, 0xcd, 0x3b, 0x30, 0xbe, 0x2c, 0x63, 0x65, 0xf2, 0x99, 0x60, 0xdc, 0x37, 0x85, 0x9d, 0x4e, 0x78, 0xc1, 0xaa, 0xd4, 0x45, 0x1a, 0xdb, 0x13, 0x0e, 0x87, 0x03, 0x53, 0xe8, 0xe9, 0xb3, 0xaf, 0x65, 0xf4, 0xb3, 0xbe, 0x2f, 0x65, 0x0f, 0x9f, 0xbc, 0x00, 0xb5, 0x1a, 0x7d, 0xc5, 0x0e, 0x47, 0xb1, 0xcf, 0x6c, 0x96, 0x3f, 0x8d, 0xb3, 0xbf, 0x03, 0xcd, 0xd0, 0xcd, 0xf0, 0x8b, 0xc9, 0x24, 0x3f, 0x20, 0x9f, 0x13, 0x97, 0xa4, 0x1e, 0x14, 0x91, 0x12, 0x45, 0x30, 0xee, 0x11, 0x18, 0xfc, 0x0d, 0xf8, 0x37, 0x54, 0x0a, 0xd8, 0x23, 0x7b, 0x6b, 0xfc, 0x1f, 0xda, 0x4b, 0x63, 0x5c, 0xac, 0x9c, 0x04, 0x18, 0x2b, 0xcc, 0x0b, 0xd3,\n\t0x90, 0x1f, 0x3e, 0xa3, 0x67, 0xc6, 0x5e, 0x1a, 0x9b, 0xbe, 0x97, 0x8a, 0x74, 0xfb, 0x94, 0xb7, 0xd2, 0xd8, 0xa9, 0x5b, 0x29, 0xe4, 0xa6, 0xf9, 0xd0, 0xc1, 0x55, 0xd6, 0x55, 0x9f, 0xab, 0xb9, 0x6c, 0x67, 0xbe, 0xb5, 0xd1, 0x6c, 0xe0, 0xc5, 0x4d, 0x81, 0xb8, 0xd1, 0xce, 0x67, 0x9d, 0xe7, 0xe0, 0x7d, 0x96, 0x3a, 0x7f, 0xc4, 0x02, 0x8f, 0xce, 0xb3, 0x6e, 0x24, 0x19, 0x8a, 0x9d, 0x9c, 0xdb, 0xd2, 0x10, 0x58, 0xed, 0xaf, 0xb7, 0xd8, 0x39, 0x27, 0x7a, 0x60, 0xef, 0x7b, 0xb5, 0x66, 0xcb, 0xde, 0xac, 0x9c, 0x82, 0x1f, 0x7b, 0x6d, 0x47, 0xbe, 0x94, 0x6d, 0xfd, 0xb1, 0xdd, 0x5d, 0xb0, 0xb7, 0xd6, 0x62, 0xbe, 0xd9, 0x6a, 0x7b, 0xf1, 0x45, 0x87, 0xf9, 0x18, 0xd1, 0xd5, 0x99, 0xf3, 0x70, 0x2b, 0x5e, 0x09, 0xf3, 0x81, 0x8c, 0xdf, 0x69, 0xb7, 0xa8, 0x69, 0xfb, 0x93, 0x4f, 0x96,\n\t0x32, 0xa3, 0x11, 0x73, 0x04, 0xb7, 0x7e, 0x77, 0xdb, 0x73, 0xcf, 0x6d, 0xfb, 0x2e, 0xca, 0x7b, 0xf9, 0xe5, 0x8d, 0x3f, 0xfe, 0x31, 0x99, 0x5f, 0xa3, 0x28, 0x0f, 0x36, 0x8e, 0x1b, 0xce, 0x36, 0xe7, 0x47, 0xd1, 0x09, 0xa9, 0x16, 0xdd, 0x20, 0xfb, 0x0d, 0x8d, 0x32, 0xaf, 0x42, 0x99, 0x0f, 0xcf, 0x75, 0x2f, 0x93, 0xeb, 0x20, 0x3f, 0x95, 0x1b, 0x90, 0x73, 0xbd, 0x3c, 0xbf, 0x97, 0x4d, 0x6e, 0x65, 0x3e, 0x65, 0x88, 0xfd, 0x04, 0xbc, 0xdf, 0x08, 0xe3, 0xd5, 0x9e, 0x04, 0x87, 0x07, 0x61, 0xd5, 0x6f, 0x25, 0xef, 0xb7, 0x06, 0xa9, 0x27, 0x51, 0x11, 0x4a, 0x3a, 0x50, 0x08, 0xe2, 0x06, 0xa5, 0xde, 0x6c, 0xe6, 0xdd, 0xa1, 0x3c, 0x5f, 0x5e, 0xb8, 0xae, 0xea, 0x62, 0x85, 0x5a, 0x61, 0xca, 0xf2, 0x98, 0x70, 0xb1, 0x3b, 0x27, 0xaf, 0x22, 0x50, 0x76, 0x41, 0x81, 0x5c, 0xf7, 0x92,\n\t0xc9, 0x7f, 0x30, 0xff, 0x80, 0xba, 0xd5, 0x8c, 0x71, 0x2a, 0x52, 0x12, 0xb0, 0x0a, 0xbf, 0x97, 0xf2, 0xb4, 0x64, 0x6d, 0x30, 0x94, 0x4b, 0x8a, 0x7d, 0xde, 0xe2, 0x62, 0xaf, 0xaf, 0xb8, 0xcb, 0x57, 0x4c, 0x7f, 0xa5, 0xe5, 0x47, 0xa1, 0xb3, 0x95, 0x58, 0x0f, 0xab, 0xc5, 0x1f, 0xf7, 0xe8, 0x13, 0x96, 0x1d, 0x20, 0x78, 0x2e, 0xe5, 0x28, 0x98, 0x6f, 0x22, 0xca, 0x81, 0xc7, 0xe8, 0x33, 0x7b, 0x89, 0xe9, 0xad, 0x31, 0x61, 0xb7, 0x41, 0x6c, 0x6d, 0xe4, 0xe0, 0xa8, 0x3e, 0x7d, 0xa4, 0xcc, 0xfa, 0x8e, 0xa7, 0xb7, 0x2a, 0xbf, 0xb1, 0xc0, 0x7a, 0x65, 0x38, 0xd7, 0x59, 0x6e, 0xbd, 0xaa, 0x33, 0x4b, 0x8d, 0x9e, 0xf7, 0x15, 0xb8, 0xca, 0x3b, 0xf3, 0xa5, 0xc7, 0x51, 0x77, 0x5e, 0x91, 0xdd, 0x22, 0x5d, 0x8d, 0x95, 0x4e, 0x86, 0x00, 0xa3, 0xaf, 0xc5, 0xf5, 0xb8, 0x15, 0xd4, 0x05,\n\t0xaa, 0x21, 0xe5, 0xe5, 0x86, 0x7c, 0x1e, 0xb7, 0x80, 0xd8, 0x92, 0x62, 0x47, 0x96, 0xcd, 0x28, 0x80, 0xf6, 0xdc, 0x15, 0xf6, 0x62, 0xb6, 0xc3, 0x8e, 0x70, 0x7b, 0x0a, 0x81, 0x97, 0x5c, 0xb2, 0x2e, 0x4d, 0x18, 0xbf, 0x32, 0x78, 0x7e, 0x51, 0xc8, 0x22, 0xc7, 0x5c, 0x48, 0x59, 0x5b, 0x50, 0xaf, 0x11, 0x14, 0x22, 0xdd, 0x0c, 0x89, 0xa1, 0x18, 0x71, 0x43, 0x89, 0x85, 0x62, 0x56, 0xe8, 0xbc, 0x35, 0x66, 0x15, 0x29, 0x39, 0xad, 0x7f, 0xd7, 0xd9, 0x72, 0x0c, 0x06, 0xb7, 0x55, 0x17, 0xf1, 0x1b, 0x72, 0x6c, 0x3a, 0xc4, 0xf6, 0xe6, 0x97, 0x67, 0x15, 0x99, 0xe6, 0xb5, 0x74, 0x67, 0x69, 0xd5, 0xbd, 0x6d, 0x3d, 0xf9, 0xd1, 0x48, 0x5e, 0x4f, 0x5b, 0x8f, 0x1d, 0xbe, 0xa0, 0x45, 0x86, 0x1c, 0xab, 0x4e, 0x67, 0xcd, 0x31, 0xf8, 0x23, 0x3a, 0xab, 0x5b, 0x9a, 0xec, 0x49, 0x66, 0xc9,\n\t0x2a, 0x36, 0xf5, 0x42, 0x01, 0x3b, 0x7c, 0x29, 0x88, 0x40, 0xe9, 0x5e, 0xc2, 0x73, 0x5a, 0x26, 0x6f, 0xc0, 0xf3, 0x58, 0x72, 0x1e, 0xa0, 0x67, 0xba, 0x99, 0x7b, 0xe2, 0x86, 0xee, 0x26, 0xcc, 0xb3, 0xc5, 0x7a, 0x05, 0x8b, 0xf9, 0xa2, 0x00, 0x3d, 0x10, 0x48, 0x40, 0x10, 0xc3, 0x64, 0x66, 0xb9, 0x91, 0xd9, 0xa7, 0x03, 0x72, 0xb0, 0x04, 0xd0, 0x6e, 0x07, 0x13, 0x81, 0x2a, 0x64, 0xb3, 0xda, 0xc0, 0xe9, 0x72, 0xa3, 0xf3, 0xa7, 0x67, 0x8e, 0xfb, 0x13, 0xa1, 0x5d, 0xce, 0x98, 0x6d, 0x60, 0x20, 0x9e, 0xd1, 0xde, 0x5a, 0x5f, 0x5b, 0x55, 0x99, 0x17, 0xf6, 0xe4, 0x64, 0x3b, 0x4e, 0x39, 0x74, 0xb0, 0x4c, 0x9d, 0x39, 0x10, 0xf7, 0x0d, 0x7a, 0xec, 0x90, 0xc0, 0x23, 0x49, 0xe9, 0xd4, 0x44, 0x63, 0x9a, 0xae, 0x56, 0xa3, 0xc1, 0x8a, 0xea, 0x0c, 0xbb, 0xcf, 0x94, 0xed, 0xce, 0xb3,\n\t0xab, 0xca, 0xc3, 0x7d, 0xbe, 0x96, 0xa8, 0xc7, 0x13, 0x3f, 0xaf, 0x56, 0x30, 0x67, 0x46, 0x54, 0xb1, 0xb5, 0xde, 0x3c, 0x41, 0xa7, 0x56, 0x59, 0x9c, 0x81, 0x2c, 0xa3, 0xaf, 0xb9, 0x1c, 0x52, 0x56, 0xd6, 0xf2, 0xa6, 0xcc, 0x88, 0xb2, 0xac, 0x23, 0xcb, 0xab, 0xd0, 0xaa, 0x15, 0x99, 0x96, 0x6c, 0xe3, 0x26, 0xa1, 0xa2, 0xc0, 0xe8, 0x30, 0x67, 0x0a, 0xa8, 0x83, 0xcd, 0xb4, 0x39, 0x33, 0x03, 0xb9, 0x3a, 0xbb, 0xda, 0x91, 0xd7, 0x50, 0x54, 0xba, 0x24, 0x1e, 0x62, 0x9b, 0xb4, 0x96, 0xcd, 0xaa, 0x62, 0x4f, 0xa3, 0x42, 0xa1, 0x33, 0x9a, 0x84, 0x5f, 0xa8, 0xb2, 0x8b, 0x5a, 0x22, 0xe1, 0xde, 0xda, 0x00, 0xaa, 0xd1, 0x9a, 0xd7, 0xa9, 0xf3, 0xb2, 0x22, 0x6a, 0xa5, 0x52, 0xa3, 0xe5, 0xa1, 0xcf, 0x43, 0x30, 0x06, 0x71, 0x7c, 0x31, 0x6c, 0x9a, 0x65, 0x4c, 0x6d, 0xbc, 0x2a, 0xcf,\n\t0xe7, 0x66, 0x59, 0x94, 0x0f, 0xf3, 0x89, 0x23, 0xba, 0x37, 0xb1, 0xe0, 0x06, 0x36, 0x82, 0x88, 0x71, 0x39, 0x89, 0x1a, 0x44, 0xe8, 0x03, 0x93, 0x6b, 0x69, 0x62, 0x1d, 0x22, 0x66, 0x7e, 0x28, 0xe4, 0xcb, 0x2a, 0x24, 0x33, 0x3c, 0x75, 0x9a, 0x90, 0x0c, 0xe8, 0x3c, 0x23, 0x90, 0x73, 0xb2, 0xf3, 0x41, 0xf9, 0x48, 0xc1, 0x8a, 0x96, 0xd6, 0xb4, 0x54, 0x14, 0x22, 0x3e, 0xb8, 0xa6, 0x5c, 0xc0, 0x46, 0x7d, 0x99, 0xaa, 0xa0, 0xbb, 0x32, 0x87, 0x78, 0x30, 0x8a, 0xd8, 0x08, 0x34, 0x08, 0x37, 0x66, 0xfb, 0x78, 0x8d, 0x3a, 0xc3, 0xe7, 0x72, 0xda, 0xbd, 0x76, 0x93, 0x3a, 0x53, 0x89, 0xbe, 0xae, 0x9c, 0xdf, 0xd9, 0xdc, 0xa5, 0xcb, 0x2a, 0x0c, 0x70, 0xcd, 0x3a, 0xf3, 0x46, 0x45, 0x5e, 0xf3, 0x8a, 0xca, 0xd8, 0xaa, 0xf6, 0x7c, 0xb6, 0x5b, 0x6b, 0x1e, 0x57, 0xf8, 0xb2, 0x4a, 0x94,\n\t0x0a, 0xb3, 0x42, 0xfa, 0x1e, 0xab, 0xcd, 0x50, 0xab, 0x65, 0x3d, 0x1c, 0x0f, 0xe3, 0x77, 0x99, 0x42, 0xb2, 0x5a, 0x88, 0x3d, 0x7d, 0x38, 0xe7, 0xcc, 0xe7, 0x09, 0xc4, 0xc5, 0x9f, 0x9a, 0x4e, 0x93, 0xf3, 0x04, 0x9f, 0x5f, 0x6f, 0xf4, 0x85, 0x02, 0x99, 0xf4, 0x3c, 0x21, 0x32, 0x15, 0x25, 0x37, 0x75, 0x38, 0xe9, 0x44, 0x11, 0xb3, 0x2f, 0x71, 0x94, 0x40, 0x34, 0x5e, 0x59, 0x3d, 0x6e, 0xe8, 0x76, 0xd7, 0xad, 0xa8, 0x2d, 0x68, 0x89, 0x86, 0x74, 0x51, 0x55, 0x06, 0x68, 0xaf, 0x8e, 0xa0, 0xab, 0x3c, 0xf6, 0xeb, 0x5f, 0xe7, 0x14, 0x80, 0x68, 0xe3, 0x76, 0x48, 0x2e, 0xaf, 0xa7, 0x1b, 0x1d, 0x1a, 0x2f, 0x59, 0x12, 0x0f, 0x9a, 0x7c, 0xa5, 0x4e, 0x3f, 0x2f, 0x18, 0x6d, 0xc6, 0x78, 0xc5, 0xf8, 0x8a, 0x65, 0xf5, 0xb9, 0xea, 0x1a, 0x73, 0x68, 0xa9, 0x18, 0x0e, 0xed, 0x95, 0xf9,\n\t0x53, 0x1e, 0xb4, 0x7f, 0x1c, 0xf6, 0x39, 0x0f, 0x39, 0x5f, 0xb7, 0xd3, 0xf3, 0x75, 0x15, 0x52, 0x32, 0xca, 0xf1, 0x74, 0xa7, 0xec, 0xf2, 0x61, 0x82, 0x27, 0x67, 0xf6, 0xf9, 0x3a, 0x69, 0x23, 0xf9, 0x91, 0x99, 0x3c, 0xfc, 0xb0, 0x04, 0x9b, 0x35, 0xe5, 0xcf, 0x5a, 0x83, 0xd0, 0x1d, 0x5f, 0xb8, 0xf1, 0xc6, 0x1b, 0xaf, 0xbc, 0xe1, 0x86, 0x1b, 0x0e, 0xfd, 0x7c, 0x3c, 0xa0, 0xdd, 0xc2, 0xab, 0x78, 0x4e, 0xc9, 0x8f, 0xf2, 0x76, 0xc3, 0x05, 0x28, 0xde, 0x54, 0xdf, 0xb8, 0x6f, 0x5f, 0x63, 0x7d, 0x13, 0xba, 0xcd, 0x7b, 0x32, 0xd3, 0x6f, 0xb6, 0xf8, 0x33, 0x4e, 0xea, 0x4c, 0x74, 0xd0, 0xa1, 0x6d, 0x2b, 0xa1, 0x6d, 0xff, 0xf2, 0x19, 0x87, 0x79, 0x46, 0xc3, 0xc8, 0x19, 0x47, 0xcd, 0xfb, 0xef, 0x1f, 0x39, 0xf2, 0xa5, 0xc5, 0x8b, 0xd1, 0x93, 0x78, 0xe8, 0xb1, 0xad, 0x3b, 0xe3,\n\t0x87, 0x0f, 0xc7, 0xb1, 0x7e, 0x8f, 0x7c, 0xcf, 0x80, 0xd7, 0xc3, 0x38, 0x56, 0x30, 0x7d, 0xf1, 0x79, 0x64, 0x1c, 0x0b, 0xfd, 0x58, 0xa9, 0x48, 0x3b, 0x8e, 0x1a, 0x79, 0x1c, 0xd5, 0x20, 0xc6, 0x23, 0x51, 0x21, 0x88, 0x04, 0xe1, 0x82, 0x9e, 0xa8, 0x0f, 0x2b, 0x7b, 0xe4, 0x68, 0xa1, 0x05, 0x79, 0x01, 0x68, 0x02, 0x1d, 0x59, 0xed, 0x99, 0x47, 0x96, 0x8e, 0xae, 0x30, 0x6b, 0x78, 0x09, 0x0d, 0x9b, 0x4e, 0x19, 0xe2, 0x90, 0x2b, 0x12, 0x7b, 0x13, 0xfe, 0x64, 0x64, 0x26, 0x47, 0xd9, 0xe3, 0xed, 0xee, 0xee, 0x46, 0xc7, 0x1b, 0x67, 0x8f, 0x73, 0x23, 0x10, 0xd3, 0xe7, 0x2e, 0xb5, 0x24, 0x87, 0xba, 0xb3, 0xa9, 0x9e, 0xca, 0x5e, 0x2d, 0xd0, 0xc7, 0xfd, 0x40, 0x4f, 0x72, 0x27, 0xe0, 0x9c, 0xf3, 0x79, 0x86, 0x33, 0x3b, 0x4b, 0x3e, 0xcd, 0x30, 0xe8, 0x33, 0xd2, 0xdd, 0x07, 0xf8,\n\t0xcc, 0xd1, 0x08, 0xb9, 0x0f, 0xe0, 0xe9, 0x79, 0x86, 0x59, 0x8e, 0x3d, 0x47, 0xce, 0x6c, 0x22, 0xa8, 0xa6, 0xa6, 0x55, 0xf1, 0xec, 0x77, 0xc4, 0xa6, 0x86, 0x0a, 0x74, 0x51, 0xa3, 0xea, 0xc0, 0x9e, 0xe8, 0x17, 0x6a, 0x6a, 0x9e, 0xbd, 0xf4, 0x12, 0x45, 0x1c, 0x2d, 0x2d, 0xaf, 0xd9, 0xf6, 0x50, 0x55, 0xc9, 0xbd, 0xc3, 0x5b, 0x3f, 0x46, 0x2f, 0x34, 0xbe, 0xb6, 0x75, 0x3d, 0x19, 0xef, 0x82, 0xc9, 0x7f, 0xc0, 0x5c, 0x7c, 0x17, 0xd6, 0xd4, 0x70, 0x7c, 0x0d, 0x48, 0x96, 0xc8, 0x8a, 0x78, 0xc6, 0x83, 0x44, 0xa1, 0x18, 0xa9, 0x14, 0x5c, 0x57, 0x03, 0xe2, 0x51, 0xe7, 0xec, 0x0b, 0x81, 0x69, 0xe3, 0xc2, 0xcc, 0xbc, 0x17, 0x18, 0x4e, 0xde, 0x06, 0x0c, 0xab, 0x7a, 0x48, 0x20, 0x57, 0xe2, 0xc4, 0xed, 0xf1, 0x99, 0x7c, 0x06, 0x5f, 0xc0, 0x9f, 0x18, 0x96, 0x59, 0x60, 0x20, 0x42,\n\t0x22, 0x46, 0xab, 0x60, 0x22, 0x83, 0x43, 0x7e, 0x9b, 0xc2, 0x19, 0x46, 0xc9, 0x7b, 0x80, 0x68, 0x2d, 0x08, 0x5e, 0x05, 0xdd, 0xea, 0xb2, 0xee, 0x35, 0xd5, 0xed, 0xa3, 0xee, 0x52, 0x51, 0xad, 0x56, 0x1b, 0x1c, 0xe1, 0x9c, 0x86, 0xde, 0x0c, 0xc4, 0x9a, 0x0c, 0xef, 0xa2, 0xdf, 0x58, 0xf4, 0xdf, 0xb2, 0x5f, 0xec, 0xcb, 0xcf, 0x36, 0xa9, 0x35, 0xca, 0x1a, 0xdf, 0x8e, 0x8e, 0xf8, 0xda, 0xf6, 0x02, 0x65, 0x67, 0x33, 0x6a, 0x41, 0x3f, 0xaf, 0x5f, 0xd7, 0x11, 0x8a, 0x15, 0xc7, 0x14, 0x62, 0xa6, 0x31, 0x73, 0x5e, 0x77, 0x8e, 0xc6, 0xaa, 0x30, 0x28, 0x9c, 0x39, 0x6a, 0xcb, 0x1d, 0x06, 0xab, 0x41, 0x51, 0x55, 0x59, 0x1d, 0xee, 0x5a, 0xdf, 0x10, 0x77, 0xc2, 0x43, 0xba, 0x36, 0x2b, 0x27, 0x2f, 0x43, 0x36, 0xb6, 0x05, 0xe4, 0x12, 0xe1, 0x51, 0xad, 0x08, 0x72, 0xb7, 0x11, 0x18,\n\t0x9f, 0x45, 0xc8, 0x40, 0x54, 0x0c, 0x89, 0x59, 0x5d, 0xe4, 0x98, 0xe5, 0xa1, 0x92, 0x02, 0x8d, 0x56, 0x5d, 0xd7, 0x1d, 0x6f, 0xec, 0xaa, 0x53, 0x6b, 0x35, 0x05, 0x25, 0x68, 0x78, 0xe4, 0xc5, 0x25, 0x56, 0x9b, 0x18, 0x3a, 0xff, 0xc3, 0xfd, 0x97, 0xfe, 0x69, 0x3c, 0xa0, 0xb0, 0x5a, 0x97, 0xfd, 0x50, 0x8e, 0xff, 0x0d, 0xf5, 0x59, 0x66, 0xd4, 0x57, 0x1e, 0x0c, 0x05, 0x2b, 0x1a, 0x28, 0x7a, 0x8f, 0x20, 0x86, 0x8a, 0x88, 0x10, 0x79, 0x7b, 0x49, 0xa1, 0x46, 0xab, 0xa9, 0xef, 0x8a, 0xc7, 0xbb, 0xea, 0xe1, 0x97, 0x42, 0x52, 0xdf, 0x0f, 0x97, 0x59, 0xad, 0x8a, 0xc0, 0xf9, 0x1f, 0xec, 0xdf, 0xff, 0xe1, 0xf9, 0x21, 0xd1, 0x66, 0x5d, 0xf2, 0x22, 0x3d, 0xe7, 0x88, 0xb0, 0x07, 0xf1, 0x06, 0x61, 0x35, 0x2b, 0x72, 0xdf, 0x83, 0xe9, 0x45, 0x6d, 0xc6, 0xf0, 0x74, 0x9b, 0xb1, 0xa5,\n\t0xec, 0x3b, 0xb8, 0x95, 0x7f, 0x1b, 0xd2, 0x9f, 0x4f, 0xa6, 0xcf, 0xb0, 0x29, 0x1b, 0xe5, 0xbe, 0x85, 0x4b, 0x78, 0x2b, 0xa4, 0x7f, 0xff, 0x34, 0xe9, 0x8b, 0x20, 0x7d, 0x3b, 0xa4, 0x9f, 0x48, 0x5b, 0xff, 0x00, 0xfe, 0x2b, 0xf3, 0x19, 0xe7, 0x86, 0xf4, 0x1f, 0xc0, 0x76, 0x71, 0x6a, 0xf9, 0xc5, 0xec, 0x25, 0x89, 0xf4, 0x17, 0x26, 0x27, 0xd3, 0xa4, 0x57, 0xb3, 0x17, 0xe3, 0xb5, 0xd4, 0x26, 0xee, 0xee, 0xb4, 0xf5, 0x7b, 0xa0, 0x7f, 0x23, 0xa4, 0x7f, 0xe8, 0x5e, 0xd8, 0xc2, 0x4f, 0x4d, 0x9f, 0x07, 0xe5, 0x6b, 0x69, 0xfa, 0x7d, 0x69, 0xeb, 0x27, 0xe9, 0x8b, 0x69, 0xfa, 0xfd, 0xc9, 0xf6, 0xe1, 0x99, 0xed, 0x3b, 0x88, 0x17, 0xd2, 0xf4, 0x07, 0x40, 0x12, 0x38, 0xb5, 0x7c, 0x2f, 0x94, 0x9f, 0x4f, 0xdb, 0xf7, 0xad, 0x64, 0xfb, 0xd8, 0xe9, 0xe9, 0x0b, 0xa0, 0x7c, 0x33, 0x4d,\n\t0x7f, 0x30, 0xf9, 0xfe, 0x19, 0xf5, 0x0f, 0xb2, 0x7f, 0xc4, 0x0d, 0xfc, 0x8f, 0xa0, 0xff, 0x2f, 0xa6, 0x7d, 0x7f, 0x33, 0x6b, 0xc5, 0xbd, 0xc2, 0x0f, 0x20, 0xfd, 0x47, 0xc9, 0xf2, 0x33, 0xea, 0x1f, 0x82, 0xf4, 0x38, 0x68, 0xb9, 0x22, 0xf7, 0xe3, 0xb4, 0xf4, 0x69, 0x80, 0xf7, 0x0f, 0x93, 0xf7, 0x73, 0x2f, 0xa5, 0x1d, 0xbf, 0x3c, 0x48, 0x1f, 0xa7, 0xf3, 0xe3, 0xe5, 0xb4, 0xe9, 0xdd, 0x90, 0x3e, 0x40, 0xd3, 0x7f, 0x32, 0x79, 0x32, 0x4d, 0x7a, 0x13, 0xa4, 0xaf, 0xa7, 0xf5, 0xbf, 0x92, 0xb6, 0x7c, 0x1c, 0xd2, 0x2f, 0xa1, 0xe5, 0x7f, 0x9a, 0x2c, 0x3f, 0xa3, 0xfd, 0xb9, 0xec, 0x25, 0x78, 0x1b, 0x2d, 0xff, 0xea, 0xe4, 0x44, 0xda, 0xf1, 0x17, 0x51, 0x96, 0xf0, 0x22, 0xa4, 0xff, 0x2c, 0xad, 0xcd, 0x63, 0x04, 0xd2, 0x4d, 0x34, 0xfd, 0xe7, 0x93, 0x52, 0xba, 0xf4, 0x49, 0x17,\n\t0xde, 0x80, 0xfe, 0x29, 0xcf, 0xff, 0x49, 0x97, 0x4c, 0x9f, 0x49, 0xd7, 0xd4, 0xfc, 0x94, 0xae, 0x66, 0x3e, 0x9b, 0x7c, 0x4a, 0x9e, 0x9f, 0x72, 0x3a, 0x9a, 0x9e, 0xbe, 0x64, 0xd2, 0xca, 0xfc, 0x83, 0xa6, 0xbf, 0x90, 0x2c, 0x3f, 0x23, 0x7d, 0x1f, 0xd4, 0xdf, 0x8d, 0x8a, 0x91, 0xc8, 0xfd, 0x90, 0x31, 0xa6, 0x49, 0x1f, 0x9c, 0xbc, 0x14, 0xe4, 0x9e, 0x21, 0x79, 0x7c, 0xd3, 0xbc, 0xbf, 0x45, 0x7a, 0x18, 0xcf, 0xc3, 0xab, 0xc8, 0xf8, 0x26, 0xeb, 0x67, 0xa7, 0xa7, 0x0f, 0x43, 0x7a, 0x23, 0xba, 0x85, 0x8e, 0x6f, 0xba, 0xf2, 0x0d, 0xf0, 0xfe, 0x61, 0x8c, 0xe5, 0xf1, 0x4d, 0xf3, 0xfe, 0x3c, 0x48, 0x1f, 0xa7, 0xfd, 0x7f, 0x39, 0x6d, 0x7a, 0x27, 0xa4, 0x2f, 0xa5, 0xe9, 0x3f, 0x99, 0xfc, 0x67, 0x9a, 0xf4, 0x26, 0x48, 0x5f, 0x4f, 0xeb, 0x7f, 0x25, 0x6d, 0x79, 0xf2, 0xfe, 0x8b,\n\t0x69, 0xf9, 0x9f, 0x4e, 0x7e, 0x9e, 0xa6, 0xfd, 0xe1, 0x49, 0x2b, 0xde, 0x4a, 0xcb, 0xbf, 0x3a, 0x79, 0x32, 0x4d, 0xf9, 0x28, 0xfe, 0x2e, 0xde, 0xc4, 0xdf, 0x46, 0xc7, 0x07, 0xe3, 0xef, 0xca, 0xfd, 0x9b, 0x66, 0x73, 0xba, 0x94, 0x75, 0x01, 0x7f, 0x72, 0xca, 0xfc, 0x49, 0x4e, 0x9f, 0x61, 0x93, 0x3a, 0xca, 0xfe, 0x37, 0x2e, 0xe1, 0x16, 0xca, 0xfc, 0x29, 0x6d, 0xfa, 0x11, 0x48, 0x7f, 0x40, 0xe6, 0x4f, 0x69, 0xea, 0x5f, 0x86, 0x8b, 0x98, 0x4f, 0xd9, 0x41, 0x3a, 0xfe, 0xe9, 0xca, 0x2f, 0xc6, 0x4f, 0x32, 0x9f, 0xd1, 0x74, 0xe0, 0x4f, 0x69, 0xd2, 0xb7, 0x40, 0xfb, 0xab, 0xb8, 0x9f, 0xb1, 0x64, 0xfc, 0x51, 0x9a, 0xf4, 0x6a, 0x78, 0xdb, 0x5a, 0xfe, 0x2e, 0x99, 0x7f, 0xa5, 0x79, 0xff, 0x2a, 0x28, 0x5f, 0xce, 0xdf, 0x4e, 0x6c, 0x7a, 0xd3, 0xd6, 0xdf, 0x01, 0xe9, 0xf3, 0x69,\n\t0xf9, 0x6f, 0x82, 0x18, 0x7e, 0x6a, 0x7a, 0x1c, 0x6a, 0x6b, 0xa5, 0xe9, 0xf7, 0xa4, 0x2d, 0x6f, 0x86, 0xf2, 0xcb, 0x09, 0x7d, 0xd1, 0xbd, 0x93, 0x9f, 0xa5, 0x79, 0xff, 0x7c, 0xf8, 0x56, 0x47, 0xd3, 0xef, 0x4b, 0xdb, 0xff, 0x5e, 0x48, 0x5f, 0x44, 0xd3, 0xef, 0x4f, 0xdb, 0xfe, 0xf9, 0x50, 0x7f, 0x2f, 0x4d, 0x7f, 0x60, 0x72, 0xe2, 0x34, 0xe5, 0xe5, 0xf6, 0x7f, 0x2b, 0x59, 0x9e, 0x9d, 0x9e, 0xde, 0x0f, 0xe5, 0xe5, 0xf6, 0x3f, 0x98, 0xa4, 0xdf, 0x8c, 0xfa, 0x07, 0x59, 0x2f, 0xf0, 0x47, 0x5e, 0x5e, 0x3f, 0x69, 0xd2, 0x5b, 0xf0, 0x42, 0x3c, 0x0f, 0x74, 0x5f, 0xba, 0x7e, 0xd2, 0xd4, 0xbf, 0x16, 0xd2, 0x1b, 0xf8, 0x5a, 0xb2, 0x7e, 0x92, 0xf4, 0xc1, 0x33, 0xe9, 0xf7, 0x5d, 0xbc, 0x8e, 0xbc, 0x1f, 0xd6, 0x4f, 0xba, 0xf1, 0xcb, 0x83, 0xf4, 0x71, 0x3a, 0x3f, 0x5f, 0x4e, 0x4b,\n\t0x9f, 0x3e, 0x48, 0x5f, 0x45, 0xd3, 0x7f, 0x92, 0x9c, 0xbf, 0x28, 0x7d, 0xfd, 0xaf, 0x4c, 0x4a, 0x69, 0xd2, 0x5b, 0x20, 0x7d, 0x3f, 0x2d, 0xff, 0xd3, 0xb4, 0xed, 0xcf, 0xc3, 0x4f, 0xe2, 0x31, 0x5a, 0xfe, 0xd5, 0xb4, 0xe5, 0x2b, 0x70, 0x33, 0xb2, 0x80, 0xb4, 0x07, 0xfc, 0x31, 0x6d, 0x7a, 0x0c, 0xd2, 0x6d, 0x34, 0xfd, 0xe7, 0x69, 0xdb, 0x77, 0x0d, 0xbc, 0xf5, 0xaf, 0xfc, 0x09, 0x26, 0xc8, 0xed, 0x20, 0x77, 0x00, 0xa8, 0x1a, 0x1d, 0xc0, 0xfb, 0x12, 0x96, 0xdc, 0xfb, 0x68, 0x2e, 0x96, 0x59, 0x30, 0xd9, 0xc5, 0xbf, 0xc9, 0xbf, 0xc2, 0x58, 0x99, 0x52, 0xa6, 0x93, 0x69, 0x8d, 0x37, 0x15, 0xe4, 0x83, 0x4e, 0x98, 0x07, 0x7a, 0x9f, 0x07, 0x81, 0x5c, 0xd7, 0xd5, 0x60, 0xc5, 0x6c, 0x47, 0xa7, 0x16, 0x93, 0xd3, 0x06, 0x8e, 0xba, 0xd9, 0x92, 0xcb, 0x66, 0xd0, 0xa2, 0xf1, 0x76,\n\t0xe2, 0x6f, 0x48, 0xaf, 0x4a, 0x98, 0x9e, 0xd2, 0x92, 0xe2, 0xa2, 0x80, 0x2f, 0x27, 0xdb, 0x6e, 0xe3, 0x89, 0x54, 0xaa, 0xe3, 0xa9, 0x21, 0x98, 0x48, 0x54, 0xc3, 0x2c, 0x54, 0x11, 0x43, 0xbe, 0x44, 0xf0, 0x96, 0xc4, 0x85, 0x41, 0x54, 0x1f, 0x8a, 0x36, 0x20, 0x8f, 0x39, 0xc2, 0xd6, 0xf3, 0x54, 0xc3, 0x8e, 0x11, 0xd5, 0x9a, 0xc4, 0x62, 0xc5, 0x17, 0x2f, 0xbe, 0x6c, 0x75, 0x63, 0x50, 0x4f, 0x62, 0x49, 0x6b, 0x6a, 0xce, 0x6b, 0xf6, 0xb7, 0x5d, 0xf5, 0xd3, 0x2b, 0xd1, 0x77, 0xbf, 0x15, 0x89, 0x2a, 0xdd, 0x7a, 0x53, 0xd9, 0x78, 0xfd, 0xea, 0x4b, 0xe7, 0xb9, 0x87, 0x77, 0x0f, 0x23, 0xfc, 0xad, 0xab, 0x20, 0x67, 0x3c, 0x9c, 0x29, 0xe7, 0x5c, 0xd5, 0x44, 0x73, 0xf2, 0xcf, 0x57, 0x1d, 0xff, 0xcd, 0xc7, 0x1f, 0xfd, 0x66, 0xf1, 0xe2, 0x5d, 0xcb, 0x5b, 0xbc, 0x9a, 0xd8, 0x8e,\n\t0xc3, 0xf7, 0x8f, 0xdd, 0x82, 0xa2, 0xc8, 0xf1, 0xd7, 0x25, 0x13, 0xe5, 0xd2, 0xbd, 0xc1, 0x02, 0xc4, 0xbe, 0x6e, 0xb2, 0x14, 0x2d, 0x3f, 0xb8, 0x04, 0x15, 0x14, 0xbd, 0xa9, 0xf9, 0xf8, 0xe4, 0xe7, 0xe7, 0x55, 0x3d, 0xf1, 0xeb, 0x8f, 0xff, 0xf4, 0xe6, 0x92, 0x25, 0x7b, 0x96, 0xb7, 0x7a, 0x35, 0x95, 0x3b, 0xae, 0xbe, 0x7f, 0xeb, 0x2d, 0xd2, 0x4b, 0xd2, 0x7b, 0x7f, 0xa5, 0xf6, 0xbe, 0x3a, 0xc6, 0x3e, 0xf9, 0x53, 0xfe, 0x73, 0xfe, 0x61, 0x90, 0xd9, 0xac, 0x8c, 0x83, 0xc9, 0x61, 0x7c, 0x14, 0x23, 0xa1, 0x98, 0x89, 0x30, 0x31, 0xa6, 0x06, 0x24, 0xe5, 0x66, 0x66, 0x29, 0xf3, 0xf7, 0x78, 0x59, 0xa3, 0x1d, 0xb3, 0xb8, 0xc9, 0x81, 0x19, 0xb6, 0xb9, 0x2e, 0x8b, 0x55, 0x33, 0x0d, 0xf5, 0x39, 0x2e, 0x27, 0xcf, 0xab, 0x63, 0x15, 0xd1, 0x50, 0x90, 0x57, 0x71, 0x65, 0xf9, 0x01,\n\t0x16, 0xa9, 0x22, 0x79, 0x58, 0x44, 0xa5, 0xb9, 0x58, 0x10, 0x15, 0x09, 0xc4, 0x8b, 0x22, 0x78, 0x89, 0x1a, 0xf4, 0x81, 0x21, 0x85, 0x06, 0xf3, 0x5a, 0x25, 0xe6, 0x40, 0x31, 0x5b, 0xc3, 0xa8, 0x60, 0xb4, 0x54, 0x88, 0x38, 0x82, 0x08, 0xa2, 0x40, 0xee, 0xf5, 0x69, 0xec, 0xf9, 0x75, 0x29, 0x2c, 0xaa, 0xd2, 0x33, 0x96, 0x4a, 0x66, 0x27, 0x38, 0xf3, 0x14, 0x7b, 0x6d, 0x98, 0x98, 0x95, 0x9f, 0xe3, 0x9b, 0x06, 0x06, 0xe2, 0xae, 0xca, 0x4a, 0xb7, 0x7b, 0x51, 0x7f, 0x57, 0x47, 0x65, 0x4d, 0x65, 0x4d, 0x75, 0x55, 0x71, 0x51, 0x61, 0x81, 0xdb, 0xe7, 0xf6, 0x65, 0xe9, 0x4d, 0xc4, 0xb2, 0xdc, 0x9e, 0x3f, 0xfb, 0x44, 0x18, 0x45, 0xac, 0xbe, 0x80, 0x55, 0x0c, 0xf1, 0xf0, 0x83, 0xcc, 0x62, 0xd4, 0x28, 0x86, 0x62, 0x2c, 0xfc, 0x20, 0x5f, 0x28, 0xc2, 0x87, 0x62, 0xd6, 0x00, 0xfc,\n\t0xa0, 0x68, 0xcc, 0xcc, 0xc6, 0xac, 0xa2, 0x11, 0x7e, 0xd8, 0x69, 0xce, 0x40, 0xf4, 0x7c, 0x4a, 0xd9, 0x77, 0xf8, 0xe9, 0xcd, 0x1b, 0x9f, 0x3a, 0xdc, 0xd7, 0x77, 0xf8, 0xa9, 0x8d, 0x9b, 0x9f, 0x3e, 0xdc, 0x87, 0x7e, 0x34, 0xa6, 0xbc, 0x14, 0x7d, 0x61, 0xf5, 0xbc, 0x31, 0xf4, 0x85, 0xd8, 0x91, 0x46, 0x94, 0x75, 0xff, 0x50, 0xe5, 0xcd, 0xf1, 0xad, 0x6b, 0x56, 0x6e, 0x95, 0xde, 0x1a, 0x53, 0x5c, 0x2a, 0xed, 0x59, 0x33, 0x7f, 0x4c, 0xda, 0x13, 0x3b, 0x12, 0x97, 0xde, 0x97, 0x53, 0xd6, 0x0e, 0x6e, 0x8d, 0xd4, 0x8f, 0x1e, 0xe9, 0xef, 0xbf, 0x6e, 0x73, 0x7d, 0xfd, 0xe6, 0xeb, 0xfa, 0xfb, 0x8f, 0x8c, 0xd6, 0xe3, 0xef, 0x6f, 0x7a, 0x9a, 0x54, 0xf9, 0xf4, 0xa6, 0x44, 0xd5, 0xec, 0x52, 0xc8, 0x7c, 0x4b, 0x23, 0xc9, 0x2c, 0xfd, 0x6e, 0xbb, 0x62, 0xbf, 0xb4, 0x9b, 0x56, 0x53,\n\t0x79, 0x7d, 0xa3, 0xf4, 0xc7, 0x54, 0x35, 0xc8, 0x03, 0x29, 0xe8, 0x0a, 0x48, 0x41, 0x87, 0xaa, 0x20, 0xa5, 0xb8, 0xff, 0x08, 0xa9, 0x32, 0x55, 0x35, 0xc3, 0x68, 0xe7, 0x30, 0x37, 0x7e, 0x11, 0x2f, 0x68, 0xac, 0x23, 0xae, 0x06, 0xb8, 0xb9, 0xc9, 0x91, 0xc5, 0x31, 0x2c, 0x99, 0x17, 0x1c, 0xcf, 0x54, 0x84, 0x30, 0xe2, 0x62, 0x91, 0xb2, 0xfc, 0xbc, 0xa0, 0x20, 0xa2, 0x68, 0x69, 0x6e, 0x80, 0x03, 0xfa, 0x27, 0xe6, 0x44, 0x50, 0xa1, 0xc2, 0xbc, 0x1a, 0x46, 0x08, 0x91, 0x11, 0x4a, 0xdc, 0xde, 0x9d, 0x76, 0x2e, 0xe4, 0xa6, 0xcd, 0x9d, 0x7e, 0x0e, 0xcc, 0xb1, 0x66, 0x18, 0xfb, 0x2c, 0x32, 0xf6, 0x69, 0xc6, 0x5d, 0x93, 0x66, 0xdc, 0x8d, 0x11, 0xd6, 0x07, 0xaa, 0x62, 0x28, 0x60, 0xe5, 0x43, 0xbc, 0x39, 0x10, 0x05, 0x4e, 0x13, 0x33, 0x8a, 0x6c, 0x8c, 0xf5, 0x19, 0x23, 0x28,\n\t0x84, 0xe0, 0x69, 0xc0, 0x1a, 0x88, 0xf2, 0x66, 0x14, 0x43, 0xf0, 0xd4, 0x28, 0xe2, 0x4d, 0xf6, 0x82, 0x6a, 0x8f, 0xa7, 0xba, 0xc0, 0x9e, 0xfc, 0xdc, 0x30, 0x66, 0x6e, 0x43, 0x9b, 0x57, 0x4b, 0x9f, 0xd6, 0xe1, 0x8c, 0x98, 0xd4, 0xe9, 0xc7, 0x7e, 0x29, 0x13, 0x7d, 0xa3, 0x52, 0x5a, 0xe9, 0x7b, 0x72, 0xcd, 0x1f, 0x6b, 0xd7, 0x8f, 0x59, 0xda, 0xa4, 0x1b, 0xd7, 0x20, 0x55, 0xdd, 0xc4, 0x5f, 0x62, 0xe8, 0xb8, 0x7f, 0xe2, 0x37, 0xe8, 0xcf, 0xd2, 0x40, 0x25, 0xba, 0xd3, 0xf7, 0xe4, 0xda, 0xf7, 0x6a, 0xf1, 0x09, 0x4f, 0x4d, 0x7e, 0x56, 0x56, 0x7e, 0x8d, 0xc7, 0x53, 0x43, 0x6a, 0xac, 0x61, 0x75, 0x89, 0xc2, 0xfe, 0x6f, 0xaf, 0x7d, 0xaf, 0x6e, 0xfd, 0xf6, 0xa9, 0xc2, 0x95, 0xe8, 0xdb, 0xbe, 0x89, 0xdf, 0x26, 0x0a, 0xa7, 0x52, 0xd1, 0xe6, 0x35, 0xd2, 0xdf, 0xeb, 0xb0, 0xae,\n\t0x4a, 0xea, 0xf0, 0xc9, 0xf7, 0x6e, 0x51, 0xf6, 0x30, 0xeb, 0x13, 0x76, 0xc3, 0xb8, 0xfa, 0x08, 0x9a, 0x4a, 0xd2, 0xf1, 0x62, 0x69, 0x77, 0xd2, 0xc2, 0x66, 0x19, 0xd3, 0x13, 0x0c, 0x87, 0xfd, 0x9c, 0xd2, 0x76, 0x06, 0xf7, 0x0a, 0xc2, 0xf0, 0x58, 0x5f, 0xc5, 0xd0, 0x55, 0x8b, 0x16, 0x5d, 0x35, 0x54, 0x91, 0xfc, 0xbc, 0x25, 0xa7, 0xaa, 0x3f, 0x12, 0xe9, 0xaf, 0xca, 0xd9, 0xb9, 0x7e, 0xfd, 0x4e, 0x1e, 0x2d, 0xb8, 0x62, 0x5d, 0x55, 0xd5, 0xba, 0x2b, 0x16, 0x2c, 0xb8, 0x92, 0x7c, 0x5e, 0xb9, 0xa0, 0x6a, 0x45, 0x83, 0xd7, 0xdb, 0xb0, 0xa2, 0x6a, 0x7c, 0xff, 0x7e, 0xca, 0xc3, 0x4f, 0xaa, 0xb9, 0x7b, 0xd8, 0x4f, 0xf8, 0xf7, 0x18, 0x11, 0x17, 0x7c, 0xfe, 0x24, 0x93, 0x78, 0x06, 0x3a, 0xc5, 0x27, 0x22, 0x8f, 0xe8, 0x33, 0xe4, 0x96, 0xf9, 0x3e, 0x72, 0x27, 0x7c, 0x73, 0xd0,\n\t0xe4, 0x3f, 0xa4, 0x1b, 0x71, 0x88, 0xfd, 0x8c, 0xb1, 0x13, 0x44, 0x2f, 0x15, 0x3d, 0xb3, 0x16, 0x88, 0x0d, 0x36, 0x83, 0x39, 0x66, 0x0d, 0xc3, 0xf3, 0x23, 0xdd, 0xd3, 0x3c, 0x4e, 0xc9, 0x41, 0x49, 0x20, 0x90, 0x29, 0xaa, 0x1c, 0x24, 0xdc, 0xe8, 0x74, 0xd4, 0x88, 0x8a, 0x28, 0x35, 0x8d, 0x80, 0xbf, 0x38, 0x74, 0xbd, 0xa7, 0x7d, 0xfb, 0x02, 0x4f, 0x2c, 0x5b, 0xc1, 0x39, 0x82, 0xbd, 0xf1, 0x5b, 0x6f, 0xfd, 0xfe, 0xf5, 0xe8, 0x1e, 0xc9, 0xda, 0xb0, 0xa5, 0xaf, 0x48, 0xa5, 0xdc, 0x64, 0xe4, 0xda, 0xfa, 0xd0, 0x7f, 0x5d, 0x8b, 0xbe, 0x27, 0x35, 0x50, 0xfa, 0x55, 0xc0, 0x7f, 0x01, 0xfe, 0x49, 0xa0, 0x5f, 0x0e, 0xc1, 0xf5, 0x17, 0x51, 0xf2, 0xca, 0x4e, 0x91, 0xb4, 0xfd, 0x5e, 0x47, 0xac, 0x1d, 0x47, 0x08, 0x3d, 0x87, 0x59, 0x6a, 0xf2, 0x28, 0xe3, 0x58, 0xce, 0x44, 0x54,\n\t0x99, 0x6d, 0x01, 0x6e, 0xf4, 0x25, 0x8c, 0x35, 0xe0, 0x2f, 0x2a, 0x4e, 0xd9, 0x6f, 0x97, 0x06, 0x2d, 0x96, 0x60, 0xe9, 0x9b, 0x5f, 0x3c, 0x71, 0xf3, 0xcd, 0x27, 0xbe, 0xc8, 0xdd, 0x6f, 0x0e, 0x94, 0xc2, 0xb3, 0x80, 0x19, 0x3e, 0xb3, 0x1d, 0xf0, 0x79, 0x72, 0x42, 0x5a, 0x8a, 0xee, 0x49, 0x34, 0x0e, 0x4d, 0x4a, 0xd0, 0x36, 0x12, 0x5f, 0x41, 0xcd, 0x78, 0xe2, 0xae, 0x19, 0xb7, 0x26, 0x72, 0x1c, 0x69, 0x4a, 0x90, 0xd4, 0xb5, 0xc9, 0xd4, 0x0b, 0xf1, 0xc8, 0x8f, 0x5e, 0xff, 0x11, 0xfc, 0xc3, 0x5f, 0x99, 0x58, 0x83, 0xbf, 0xb2, 0x17, 0xef, 0x9b, 0xd8, 0x4f, 0x75, 0x7a, 0x02, 0x96, 0x28, 0xb1, 0xff, 0x48, 0x53, 0xdf, 0xc8, 0x19, 0xeb, 0x43, 0xd2, 0xe5, 0xdf, 0xb9, 0x1c, 0xfe, 0xa1, 0x97, 0xa5, 0x72, 0xf4, 0xf2, 0x18, 0x31, 0xfd, 0xa1, 0xf5, 0x2d, 0x96, 0x2e, 0xc0, 0x02,\n\t0xec, 0xd9, 0x36, 0xe6, 0x31, 0x19, 0x23, 0x44, 0x49, 0x43, 0x02, 0x39, 0xc8, 0x27, 0x46, 0x49, 0x44, 0xdc, 0x6c, 0xa8, 0x7f, 0x1d, 0x8d, 0x63, 0xc4, 0x2e, 0x27, 0x44, 0xec, 0xa6, 0x50, 0x3f, 0x2b, 0x64, 0x3f, 0xab, 0x84, 0xe7, 0xd1, 0xe9, 0xf3, 0x6c, 0x62, 0x92, 0x31, 0xba, 0xed, 0x32, 0x52, 0x10, 0xb3, 0x6a, 0x56, 0x5e, 0x96, 0x5e, 0x96, 0x13, 0x40, 0x1c, 0xba, 0xd7, 0x93, 0x41, 0x3d, 0x35, 0x4b, 0x32, 0xe6, 0xa6, 0x8d, 0xb1, 0xe9, 0x8d, 0x9e, 0x40, 0x20, 0x61, 0x11, 0x3e, 0x0b, 0x77, 0xa4, 0x0e, 0x11, 0x4c, 0x4b, 0x2c, 0xcc, 0x86, 0x47, 0xf9, 0xc5, 0x89, 0xa3, 0xbf, 0x27, 0xe0, 0x23, 0x7a, 0x13, 0x05, 0x1f, 0xe9, 0x19, 0xe4, 0x4f, 0xfc, 0xf3, 0x55, 0x79, 0xfd, 0xf5, 0x4b, 0xb7, 0xf2, 0x2e, 0xfe, 0x3e, 0xd8, 0x7d, 0xdb, 0x98, 0x8f, 0xe4, 0x86, 0xda, 0xac, 0xd0,\n\t0x98, 0x36, 0xc4, 0x28, 0x2b, 0x74, 0x0c, 0x4c, 0xe4, 0x28, 0x52, 0xa0, 0x02, 0x24, 0xf2, 0x7c, 0x97, 0x83, 0x24, 0x71, 0x69, 0x93, 0x12, 0x38, 0x94, 0xf9, 0x29, 0x14, 0x15, 0xea, 0xfd, 0x40, 0x4f, 0x0a, 0xb7, 0xa6, 0xc2, 0x82, 0x8d, 0xd2, 0x2e, 0xd1, 0x03, 0xe1, 0x31, 0x31, 0x49, 0x96, 0x33, 0x17, 0xd9, 0x36, 0xb3, 0x48, 0xbc, 0x0a, 0x24, 0x23, 0x25, 0xc7, 0x2a, 0xc7, 0x18, 0x41, 0x41, 0x00, 0xc4, 0xc6, 0x92, 0xa8, 0x2c, 0xe9, 0x0b, 0x33, 0x53, 0x65, 0x09, 0x01, 0x5b, 0x9a, 0xc2, 0x01, 0x0f, 0xfc, 0x0d, 0x05, 0xbd, 0xd4, 0x85, 0x73, 0x06, 0x04, 0x87, 0x7e, 0xba, 0xf9, 0x15, 0xc5, 0x39, 0xd4, 0x9f, 0x0a, 0x63, 0x32, 0x0b, 0x3a, 0x8c, 0xb5, 0x95, 0x6c, 0x6b, 0x3d, 0x74, 0x83, 0xa7, 0x61, 0xb0, 0x7a, 0xf1, 0xc5, 0x15, 0xb9, 0x8b, 0x0e, 0x0c, 0x94, 0x2e, 0x28, 0xb4,\n\t0x08, 0x36, 0x9d, 0x36, 0x1c, 0xe8, 0x5f, 0x34, 0x1b, 0xf1, 0x24, 0xb3, 0xf1, 0xeb, 0xa3, 0x4b, 0xaf, 0x19, 0xae, 0xa8, 0x1d, 0xff, 0xda, 0xc8, 0xe0, 0xfe, 0x08, 0x8b, 0x1b, 0xca, 0xbe, 0xf7, 0xe4, 0x9a, 0x2b, 0x97, 0xe6, 0xf6, 0xb4, 0xb2, 0x96, 0x85, 0x57, 0xad, 0xad, 0xd0, 0x1b, 0x97, 0xd8, 0x32, 0x74, 0xc3, 0x1b, 0x3e, 0xdf, 0x37, 0x1d, 0x1a, 0x65, 0xd1, 0xd6, 0xde, 0x95, 0x2d, 0x97, 0x3d, 0xbf, 0x77, 0xfb, 0xf3, 0xd7, 0xf6, 0xd5, 0xc6, 0x28, 0x4e, 0xca, 0xad, 0xdc, 0xcf, 0x39, 0x05, 0xa3, 0x80, 0x7d, 0xef, 0x97, 0x71, 0x55, 0x14, 0x91, 0x00, 0x43, 0xac, 0x90, 0x44, 0xf6, 0x2a, 0x65, 0x44, 0x9e, 0x98, 0x9d, 0x8c, 0x01, 0x3b, 0x62, 0x78, 0xe0, 0x08, 0x04, 0x38, 0x35, 0xe9, 0x22, 0x98, 0x08, 0x1f, 0x38, 0xda, 0x4d, 0xac, 0xb3, 0x53, 0xc8, 0x2e, 0xf2, 0x50, 0xcc,\n\t0xa5, 0xe0, 0xb6, 0x99, 0x05, 0x49, 0xf8, 0x0c, 0xb9, 0x0c, 0xa3, 0x64, 0x15, 0xac, 0x52, 0x71, 0xe6, 0xb2, 0xcc, 0x54, 0x51, 0xb2, 0xf1, 0x31, 0x4c, 0x5d, 0x4d, 0x35, 0x31, 0x8e, 0x2b, 0x20, 0xf1, 0xb2, 0x2c, 0x26, 0xad, 0x9a, 0x80, 0xea, 0xfa, 0xd5, 0xc4, 0xef, 0xbb, 0x5c, 0x3e, 0xa5, 0x4c, 0x51, 0x7e, 0x3a, 0xe1, 0xa9, 0xf7, 0x95, 0x2f, 0x01, 0x65, 0x4c, 0x8e, 0x2c, 0x53, 0x80, 0x33, 0x56, 0x36, 0xcf, 0x13, 0x1f, 0xac, 0xbd, 0xe8, 0x1a, 0x23, 0xfb, 0x4c, 0x82, 0xea, 0x95, 0xbb, 0xab, 0x37, 0x3e, 0x7a, 0x59, 0x67, 0xd3, 0x45, 0x8f, 0x6c, 0x5b, 0xf9, 0xe5, 0xf1, 0x46, 0x93, 0x63, 0x62, 0x84, 0x2d, 0xea, 0x1b, 0x6b, 0x6d, 0x5c, 0xd5, 0x5a, 0x6c, 0xb0, 0x69, 0x2b, 0x93, 0xa3, 0x84, 0xb7, 0x54, 0xaf, 0xed, 0x08, 0x5f, 0xbb, 0xf7, 0xe4, 0x42, 0x99, 0xec, 0x4d, 0x16,\n\t0x53, 0xfb, 0x95, 0x2f, 0x1d, 0xdc, 0x74, 0xfc, 0x8a, 0x79, 0x75, 0x3b, 0xee, 0xdd, 0x52, 0x98, 0xb3, 0xe2, 0x0b, 0xcb, 0x0b, 0x5c, 0x3e, 0x97, 0xa1, 0x43, 0x06, 0xd1, 0x91, 0xef, 0x14, 0x16, 0xc2, 0x58, 0x0c, 0xc3, 0x58, 0xcc, 0x67, 0x1e, 0x8f, 0x5b, 0x6c, 0x88, 0x45, 0x6a, 0xe0, 0xc0, 0xb5, 0x30, 0x22, 0x90, 0x26, 0xb4, 0x23, 0x95, 0x82, 0x4f, 0x00, 0xea, 0x54, 0xa6, 0xf0, 0xd0, 0x92, 0x04, 0xe3, 0x80, 0x4e, 0x1c, 0x9f, 0x32, 0xe9, 0xa6, 0x74, 0x92, 0x8d, 0x4a, 0x29, 0x8d, 0xe9, 0x79, 0xee, 0x98, 0x0a, 0x68, 0xdc, 0x70, 0x4a, 0x51, 0x02, 0x3e, 0x4c, 0x0e, 0x84, 0xcf, 0x50, 0x05, 0x33, 0x55, 0xc3, 0x40, 0xdc, 0xd6, 0xdd, 0xd9, 0xd2, 0xd4, 0xd8, 0x50, 0x5d, 0x19, 0x8d, 0x14, 0xe6, 0xe7, 0x85, 0xbd, 0x6e, 0xa7, 0xc3, 0x62, 0xf2, 0x12, 0x3a, 0x07, 0x52, 0x91, 0x0c,\n\t0x63, 0x53, 0xd1, 0x7b, 0x67, 0x20, 0xa9, 0x59, 0x6a, 0x90, 0x39, 0xb5, 0x4c, 0x66, 0x91, 0x3b, 0x05, 0x35, 0x84, 0x1f, 0x2d, 0x5b, 0x5f, 0xda, 0x7f, 0x74, 0x5b, 0xe3, 0xc8, 0xe2, 0xc2, 0x86, 0x90, 0xa1, 0x6c, 0xe8, 0xc6, 0xa1, 0xf1, 0xbb, 0xaa, 0x68, 0x44, 0xa9, 0x40, 0xac, 0xaf, 0x2a, 0x3a, 0x3f, 0x9a, 0xb5, 0x7b, 0xcb, 0xf8, 0xf8, 0x45, 0xbb, 0x72, 0xaa, 0x16, 0x46, 0x1a, 0x16, 0xd5, 0x84, 0x8d, 0xd3, 0x28, 0x9f, 0x5c, 0x1f, 0x36, 0x93, 0x3e, 0x6f, 0xfe, 0xf6, 0xf6, 0xa5, 0x7b, 0xdc, 0x86, 0xf2, 0xda, 0xc6, 0x9c, 0x8a, 0xa1, 0x9e, 0xc2, 0x96, 0x8a, 0x6e, 0x8a, 0xda, 0x6f, 0x09, 0x46, 0x9c, 0xf1, 0xbe, 0x03, 0x4b, 0xda, 0x03, 0x0d, 0x45, 0x59, 0x39, 0xfe, 0x9c, 0xe4, 0x20, 0xa4, 0x90, 0x8c, 0x28, 0x76, 0xff, 0xe4, 0x27, 0x14, 0x6f, 0xba, 0x86, 0x59, 0x15, 0xd7,\n\t0x94, 0xa9, 0x30, 0xc2, 0x61, 0x13, 0xe1, 0xaa, 0x89, 0x75, 0x61, 0xe3, 0x69, 0x5c, 0x3a, 0x12, 0xc5, 0x70, 0x44, 0x16, 0x2f, 0x88, 0x6b, 0x3d, 0xb5, 0xf2, 0x4d, 0x9f, 0x44, 0x8d, 0x7b, 0x8d, 0x04, 0x84, 0x2c, 0x3f, 0x37, 0xc7, 0x69, 0xd4, 0xeb, 0x34, 0x4c, 0x0d, 0xaa, 0x11, 0x61, 0xbb, 0xe4, 0x13, 0x53, 0x31, 0xa6, 0x4b, 0x44, 0xaf, 0xf3, 0x98, 0xa7, 0x9c, 0xa4, 0xa8, 0x96, 0x15, 0xf5, 0xc8, 0x71, 0xec, 0x82, 0x21, 0xf9, 0x26, 0x13, 0xaf, 0xdc, 0x78, 0xfc, 0x50, 0x6f, 0x6e, 0xe7, 0x48, 0xbd, 0xbb, 0xc9, 0x7d, 0xa7, 0xd7, 0x89, 0x2e, 0x28, 0x59, 0xd2, 0x10, 0x28, 0x5b, 0xbc, 0xbd, 0xa1, 0x61, 0x7c, 0x71, 0x59, 0xa0, 0x61, 0x49, 0x09, 0xda, 0xe1, 0xf4, 0x7e, 0xcd, 0xdd, 0xec, 0x21, 0xf1, 0x41, 0x7a, 0x0f, 0x3d, 0xa1, 0x6e, 0xbb, 0xe4, 0xde, 0x75, 0x9d, 0x07, 0x46,\n\t0x17, 0x58, 0x79, 0x7e, 0x6d, 0x96, 0xf7, 0x57, 0x8a, 0x9a, 0xc1, 0x9d, 0x4d, 0xbd, 0xe3, 0x3d, 0xc1, 0x60, 0xcf, 0x78, 0x6f, 0xd3, 0xce, 0xc1, 0x1a, 0xc5, 0xaf, 0xbc, 0x59, 0x6b, 0x05, 0xde, 0xda, 0x37, 0x7a, 0xa0, 0x73, 0xdd, 0xbd, 0x97, 0xb4, 0x31, 0x49, 0x6c, 0x6b, 0xf6, 0xab, 0x40, 0x03, 0x15, 0xe3, 0x21, 0x71, 0xf9, 0x72, 0xc8, 0xd5, 0x62, 0x17, 0xe9, 0x8c, 0x1c, 0x3e, 0x0d, 0x21, 0x8a, 0x2a, 0x30, 0xd2, 0x4d, 0xba, 0x3a, 0x4c, 0x7c, 0xc1, 0x6c, 0xb2, 0xf3, 0x83, 0x5a, 0x29, 0x32, 0x2a, 0xa4, 0x12, 0x13, 0x66, 0x68, 0xd4, 0xcf, 0x51, 0x0f, 0xed, 0x0f, 0xb1, 0x45, 0xb2, 0xe5, 0xa6, 0x27, 0xe9, 0xf3, 0x68, 0x45, 0x4f, 0x57, 0xcc, 0x8f, 0xda, 0xd7, 0x6f, 0xdc, 0x83, 0x07, 0xef, 0x29, 0xb1, 0xfe, 0x52, 0xed, 0xcc, 0xee, 0x7b, 0x06, 0x45, 0xd7, 0xdf, 0x78, 0x5e,\n\t0xe1, 0x8e, 0x51, 0xbf, 0x1d, 0x9b, 0xb3, 0x8a, 0x1b, 0x83, 0xbd, 0xfd, 0xd2, 0xc3, 0x13, 0xff, 0x13, 0x44, 0x2d, 0x86, 0x4c, 0x69, 0x07, 0xfb, 0x8f, 0xfc, 0x79, 0xa3, 0x8d, 0xeb, 0x6f, 0xf1, 0x98, 0x83, 0xb4, 0x8d, 0x23, 0x93, 0x9f, 0xb0, 0xf3, 0xd9, 0xb7, 0xa9, 0xdf, 0xef, 0x72, 0x79, 0x6c, 0xcc, 0x49, 0x29, 0x69, 0xa4, 0x7b, 0xba, 0xf9, 0xb5, 0x8c, 0xb8, 0x9e, 0x26, 0x71, 0x1b, 0x19, 0x35, 0x23, 0xd1, 0x90, 0x61, 0x7c, 0x87, 0xa6, 0x5b, 0x63, 0x0f, 0x3c, 0x41, 0xbc, 0x71, 0x39, 0x95, 0xed, 0xac, 0xde, 0xb8, 0xec, 0xfc, 0x86, 0x0d, 0x5f, 0xe8, 0xe8, 0x38, 0xb4, 0xbe, 0xbe, 0x7e, 0xfd, 0xa1, 0x8e, 0x8e, 0x2f, 0x6c, 0x68, 0xf8, 0xa1, 0xb3, 0xa4, 0xc1, 0xe7, 0xab, 0x27, 0xde, 0xe6, 0xf5, 0x3e, 0x5f, 0x43, 0x89, 0x13, 0x7d, 0xb0, 0xff, 0xd9, 0x4b, 0x6a, 0x6b, 0x2f,\n\t0x79, 0x76, 0xff, 0xfe, 0x67, 0x2e, 0xae, 0xad, 0xbd, 0xf8, 0x99, 0xfd, 0x23, 0x07, 0xba, 0x9d, 0xce, 0xee, 0x03, 0x23, 0xeb, 0x2f, 0xeb, 0xce, 0xce, 0xee, 0xbe, 0x2c, 0x79, 0xaf, 0x88, 0x3e, 0x60, 0x7f, 0x09, 0x5a, 0x4a, 0xe7, 0x13, 0x1a, 0x1e, 0x13, 0x19, 0x50, 0x8e, 0xe8, 0x63, 0x22, 0xb7, 0x77, 0x20, 0xa5, 0x8c, 0xb1, 0xf2, 0xc4, 0x4a, 0x5c, 0x92, 0xcf, 0x78, 0x9c, 0x34, 0x14, 0x1e, 0x88, 0x13, 0xa3, 0x6d, 0xe2, 0x3e, 0x9f, 0x08, 0x00, 0x3f, 0x0d, 0x41, 0x04, 0xa1, 0x0f, 0xa6, 0x81, 0x7c, 0x9c, 0x82, 0xc5, 0x41, 0x68, 0xba, 0x72, 0xf2, 0x13, 0xfc, 0xdf, 0xb4, 0x0d, 0xf9, 0xcc, 0x85, 0x8f, 0xcb, 0xc6, 0x13, 0x32, 0x69, 0xed, 0x09, 0x74, 0x8c, 0x61, 0x2a, 0x27, 0x4d, 0x47, 0xc7, 0x48, 0xc4, 0x1d, 0x3a, 0x4d, 0x86, 0x6d, 0x44, 0x30, 0xb1, 0x33, 0x1c, 0xe6, 0xc6,\n\t0x93, 0x19, 0xa6, 0xa7, 0x01, 0xff, 0xd6, 0x23, 0x86, 0x2c, 0x0c, 0xb3, 0x51, 0xe4, 0x19, 0x2d, 0xd2, 0xca, 0xf0, 0x1a, 0x15, 0x53, 0xc1, 0x29, 0x8d, 0x69, 0xb1, 0x35, 0xa8, 0x5f, 0x16, 0xba, 0xbb, 0x69, 0x41, 0x5f, 0xbd, 0x37, 0x16, 0x34, 0xf5, 0x44, 0x55, 0x06, 0xa5, 0xa3, 0xd6, 0x53, 0xb8, 0xa2, 0xb3, 0xb8, 0x78, 0xc9, 0x85, 0x5d, 0x3d, 0xbb, 0x17, 0x15, 0x54, 0x94, 0x1c, 0xd7, 0x57, 0x7b, 0x1f, 0x38, 0xb6, 0xa8, 0x7b, 0xde, 0x42, 0x7b, 0x61, 0xad, 0xaf, 0x75, 0x09, 0x7a, 0x47, 0x63, 0xd3, 0xe8, 0x8d, 0xfe, 0xce, 0x6d, 0xdd, 0xad, 0x17, 0xae, 0xac, 0x88, 0xac, 0xdc, 0x3f, 0xaf, 0xf3, 0xfa, 0x5e, 0x94, 0x93, 0xe3, 0x62, 0x58, 0x32, 0x9f, 0xf0, 0x07, 0x30, 0x9f, 0xf4, 0x30, 0xe7, 0xe3, 0xcc, 0x91, 0xc7, 0xcb, 0x28, 0x94, 0x86, 0xdc, 0xfb, 0x9c, 0x53, 0x10, 0x35,\n\t0x46, 0x66, 0x20, 0x6a, 0x24, 0xa6, 0xd8, 0x19, 0xb3, 0x6d, 0xe3, 0x28, 0x22, 0x1c, 0xec, 0x6a, 0x44, 0xb2, 0x1e, 0x4a, 0x66, 0x9d, 0x9e, 0x0e, 0xd4, 0xb0, 0x1a, 0x0d, 0x88, 0xa9, 0xa9, 0xca, 0xcf, 0x75, 0xd8, 0x0d, 0x1e, 0xa3, 0x47, 0x8e, 0xfd, 0x78, 0x2a, 0x38, 0x87, 0xc5, 0x38, 0xc5, 0x4b, 0x81, 0x54, 0x67, 0x40, 0xe6, 0x40, 0xf7, 0x06, 0x62, 0x7e, 0xbd, 0x2d, 0xb7, 0x3c, 0xdb, 0x59, 0x1e, 0xb6, 0x75, 0xb5, 0xd7, 0x35, 0x65, 0xb8, 0x4b, 0xdc, 0xee, 0x62, 0x77, 0x46, 0xd3, 0xd6, 0xbe, 0xf6, 0xe2, 0x45, 0xbb, 0x3a, 0x3a, 0x77, 0x2d, 0x2e, 0x6e, 0xef, 0xaf, 0xaf, 0x2b, 0x98, 0x37, 0x1a, 0x8f, 0x6f, 0x9e, 0x97, 0x7f, 0xbd, 0x25, 0x18, 0xcd, 0xf1, 0x47, 0x7d, 0x04, 0xdd, 0xd2, 0x5f, 0xdf, 0x8f, 0x9f, 0x6a, 0xab, 0x4c, 0x8a, 0xee, 0x95, 0x6d, 0xd2, 0xe3, 0x39, 0xbb,\n\t0x16, 0x34, 0x8f, 0xf6, 0xe6, 0xe6, 0xf6, 0x8e, 0x36, 0x2f, 0xd8, 0x95, 0x93, 0x33, 0xda, 0x5d, 0xb5, 0x96, 0xb8, 0x1b, 0xaf, 0xad, 0x3a, 0x26, 0xf3, 0xcf, 0x55, 0x30, 0x91, 0x3e, 0x05, 0x3a, 0x16, 0x31, 0x0b, 0xe3, 0x2a, 0x07, 0x8c, 0x78, 0x3e, 0xec, 0xe5, 0x38, 0x11, 0x67, 0xdd, 0xc2, 0x90, 0xe0, 0xda, 0x30, 0xf6, 0x84, 0x77, 0x4c, 0x99, 0x01, 0x92, 0xd9, 0xcc, 0x52, 0x3b, 0x8f, 0xa1, 0xe9, 0x8f, 0x07, 0xe2, 0x19, 0x88, 0xf1, 0xe4, 0x18, 0xf5, 0x3c, 0xc7, 0x14, 0xa1, 0x42, 0x9e, 0x92, 0x01, 0x18, 0xa2, 0x47, 0x46, 0x57, 0x61, 0x13, 0x93, 0x04, 0xe6, 0x77, 0xb1, 0x1c, 0xdb, 0x10, 0xcb, 0xe6, 0x1e, 0x30, 0x5d, 0xf0, 0x63, 0x39, 0xfe, 0x89, 0x0d, 0x19, 0x26, 0xc4, 0x81, 0xb2, 0x69, 0x6f, 0xa9, 0xb2, 0xe4, 0x7a, 0x6d, 0x82, 0x22, 0x3f, 0x38, 0xa2, 0xaa, 0x5b, 0xbe,\n\t0xbd, 0xbe, 0x79, 0x5b, 0x5f, 0x61, 0xa0, 0xa6, 0xc3, 0xff, 0x98, 0xaf, 0xd5, 0xf9, 0x54, 0xd0, 0xb9, 0xab, 0xc9, 0x54, 0x60, 0x40, 0xae, 0x40, 0x53, 0xbc, 0xd1, 0x5f, 0xdb, 0xa8, 0x73, 0xe4, 0x3a, 0xb2, 0xcc, 0xa2, 0xbd, 0x73, 0x4b, 0x87, 0x3f, 0xaf, 0x67, 0x43, 0x43, 0x74, 0x70, 0xe1, 0xbc, 0xf0, 0x8b, 0x6a, 0x2d, 0xb5, 0x4d, 0xfa, 0x04, 0xbf, 0x00, 0xeb, 0xa3, 0x84, 0xf9, 0x4a, 0x3c, 0xa3, 0x88, 0xc7, 0x3c, 0x2a, 0x44, 0x2c, 0x6f, 0x45, 0x98, 0x63, 0x13, 0x33, 0x25, 0xc0, 0xb0, 0x3c, 0xc7, 0x53, 0xc8, 0x3f, 0x86, 0x67, 0x65, 0x01, 0x86, 0xaa, 0xf3, 0x23, 0x29, 0xe8, 0xbf, 0x51, 0x9c, 0x5c, 0x33, 0x73, 0xc8, 0xbc, 0x8d, 0x88, 0x47, 0xbe, 0x54, 0x3e, 0x01, 0x88, 0x23, 0x10, 0x84, 0xe7, 0x44, 0xfe, 0xa9, 0x5c, 0x04, 0xd4, 0xd4, 0x14, 0xf6, 0x85, 0xc2, 0x3e, 0x2f,\n\t0xd5, 0x0c, 0xc9, 0x65, 0xec, 0xac, 0x75, 0x33, 0x05, 0x28, 0x97, 0x9c, 0x4a, 0x82, 0x18, 0x32, 0x7a, 0xf0, 0xd7, 0xcb, 0xeb, 0x5e, 0x73, 0x66, 0x95, 0x58, 0xdb, 0xb7, 0x74, 0x06, 0x23, 0xcb, 0x2f, 0xe9, 0x2a, 0xee, 0x6f, 0xaf, 0xb5, 0xd5, 0xa8, 0xec, 0x3a, 0xa3, 0x27, 0x14, 0x09, 0xba, 0x63, 0xb9, 0x56, 0xbd, 0xbf, 0x3a, 0xd7, 0x59, 0xe3, 0xdc, 0x3d, 0x0f, 0xfd, 0x94, 0xdd, 0x9f, 0x57, 0xf8, 0x0c, 0xcf, 0x13, 0x5e, 0xdc, 0x7b, 0xe9, 0x60, 0xb9, 0xc9, 0x57, 0x68, 0x5f, 0xac, 0xd3, 0x58, 0xec, 0x16, 0x4b, 0x6e, 0x4d, 0xd0, 0x53, 0x99, 0x6b, 0xd1, 0x68, 0x7d, 0xe8, 0x1f, 0xd0, 0xc0, 0x41, 0xa0, 0xd5, 0x5b, 0x30, 0x0f, 0xaa, 0x99, 0xfd, 0x71, 0x95, 0x16, 0xb1, 0x5c, 0x16, 0x4c, 0xfc, 0xe4, 0x2e, 0xea, 0x24, 0xae, 0xc5, 0x40, 0x35, 0x12, 0x76, 0x9b, 0x32, 0xdd, 0x29,\n\t0x0d, 0x77, 0x34, 0x15, 0x23, 0xe3, 0x0c, 0x99, 0xb6, 0x21, 0x0a, 0x6c, 0xca, 0x10, 0x18, 0x60, 0x42, 0x86, 0x44, 0xbe, 0xa9, 0x54, 0x20, 0x87, 0xd2, 0xaf, 0xb7, 0x14, 0x14, 0x51, 0xf8, 0x0a, 0x63, 0x72, 0x76, 0x08, 0x53, 0xd1, 0x80, 0x81, 0x1c, 0x15, 0x04, 0xe3, 0x3a, 0x69, 0x6f, 0x15, 0xa5, 0xe8, 0xd8, 0x84, 0x26, 0x3a, 0x36, 0x74, 0x81, 0xaa, 0x6a, 0xd1, 0x68, 0x7d, 0xf3, 0x86, 0x8e, 0x60, 0x5f, 0xdb, 0xa2, 0xfe, 0xfc, 0xbe, 0x9d, 0x3d, 0x9d, 0x1b, 0x7b, 0x22, 0xc6, 0x25, 0xde, 0x32, 0xb5, 0x60, 0xf6, 0x46, 0x83, 0xde, 0x88, 0xcf, 0xb0, 0x66, 0x6c, 0x68, 0xb0, 0xb1, 0xaa, 0xa8, 0x2b, 0x43, 0x50, 0x68, 0xad, 0x46, 0xfc, 0x1c, 0x99, 0x2f, 0xb9, 0x6d, 0x2b, 0x23, 0xab, 0xb7, 0xda, 0xed, 0x1b, 0x96, 0x35, 0x6c, 0xe9, 0x2f, 0x0e, 0xb4, 0xae, 0xa9, 0x0d, 0xea, 0x74,\n\t0x36, 0x5d, 0x28, 0x98, 0x65, 0x0b, 0x95, 0x3b, 0xda, 0xe2, 0xd7, 0xa2, 0xf6, 0x96, 0xea, 0xba, 0x8a, 0x88, 0x5a, 0xaf, 0xc6, 0xac, 0xbc, 0xd7, 0x0e, 0xc2, 0x7f, 0xaf, 0x02, 0x9d, 0xb4, 0x4c, 0x01, 0xd3, 0x2c, 0x77, 0xdc, 0x46, 0x12, 0x38, 0x06, 0x0f, 0x25, 0x41, 0x1a, 0x47, 0x12, 0xbe, 0x8f, 0x0e, 0x58, 0x40, 0x29, 0x13, 0xb2, 0x44, 0x16, 0x9a, 0x30, 0x70, 0x1c, 0x84, 0xdf, 0x20, 0x35, 0x68, 0x9b, 0x81, 0x13, 0x65, 0x94, 0x51, 0x8c, 0xd3, 0xa2, 0x4b, 0x59, 0xa6, 0x50, 0x9e, 0xee, 0x50, 0xe8, 0x14, 0xa7, 0x41, 0x86, 0x9a, 0x86, 0xab, 0x26, 0x5d, 0xae, 0x36, 0xaa, 0xd2, 0x23, 0x3b, 0x41, 0x3f, 0xaa, 0x81, 0xab, 0x3b, 0x61, 0x6d, 0xf0, 0x8c, 0x85, 0x59, 0x1d, 0x57, 0xc3, 0x3a, 0xe6, 0x8c, 0x22, 0x96, 0x97, 0x3e, 0x99, 0xec, 0x56, 0x10, 0x3b, 0xd9, 0x84, 0xf1, 0xb6,\n\t0xbc, 0x49, 0x30, 0x54, 0x78, 0x70, 0xc4, 0xad, 0xc4, 0x31, 0x67, 0x7c, 0x46, 0x32, 0x4d, 0x01, 0x6e, 0x08, 0x82, 0x28, 0x23, 0x58, 0x04, 0x90, 0x2e, 0xa8, 0x29, 0xb5, 0x92, 0xb8, 0xbe, 0x13, 0x6e, 0x88, 0xf4, 0xc0, 0x01, 0x58, 0xd9, 0xf8, 0xc0, 0xec, 0x8b, 0x7a, 0x08, 0x2c, 0x3c, 0x8a, 0xe8, 0xd1, 0xc7, 0x2c, 0x37, 0x81, 0x73, 0x4c, 0x86, 0xa1, 0x3b, 0xa4, 0xab, 0xf5, 0x2e, 0xce, 0x88, 0xee, 0x3c, 0x8e, 0x76, 0x22, 0x6d, 0x56, 0x8d, 0x5b, 0xda, 0x3b, 0x9a, 0x69, 0xfd, 0xc3, 0x1f, 0x6c, 0x86, 0x11, 0x3c, 0x3c, 0xf1, 0x15, 0x86, 0xda, 0x3c, 0xe2, 0x9f, 0x41, 0x7b, 0x0d, 0x4c, 0x95, 0xdc, 0x40, 0x3d, 0x41, 0x4c, 0x1f, 0x98, 0xb9, 0xc9, 0x66, 0xb0, 0x09, 0xec, 0x87, 0x35, 0xd3, 0xf7, 0x57, 0x03, 0x63, 0x30, 0x85, 0xe8, 0xfe, 0x4a, 0x66, 0x94, 0x0c, 0xc5, 0x41, 0x82,\n\t0x41, 0x10, 0x2f, 0x6a, 0xfc, 0xb3, 0x0c, 0x85, 0xf4, 0x82, 0xb6, 0x24, 0x7c, 0x35, 0x6a, 0xd6, 0xb9, 0xf4, 0xd2, 0xf9, 0x06, 0x07, 0xfb, 0xcb, 0x25, 0xa1, 0x22, 0xfd, 0x44, 0xc8, 0x11, 0xc2, 0x27, 0xb2, 0x8b, 0x4c, 0xd9, 0xfa, 0x2b, 0xc8, 0xb9, 0xc6, 0xfb, 0xd2, 0x85, 0x8c, 0x5d, 0x20, 0x56, 0xff, 0x41, 0x19, 0xab, 0x44, 0x4d, 0x01, 0x3b, 0xa1, 0x11, 0x9b, 0xc8, 0xe4, 0x56, 0x26, 0xbf, 0x6d, 0x1c, 0x78, 0x4c, 0xb6, 0xe8, 0x24, 0xb8, 0x15, 0xf6, 0xb2, 0x32, 0xa1, 0xeb, 0xb3, 0x12, 0x52, 0xbe, 0x01, 0xca, 0xbf, 0x20, 0xae, 0x05, 0x9d, 0x3b, 0x2f, 0x4e, 0x89, 0xa3, 0x52, 0x2a, 0x44, 0x81, 0xc5, 0x48, 0xc3, 0x74, 0xd0, 0x0a, 0x1f, 0x4f, 0x1c, 0x1c, 0x3c, 0x0a, 0x9f, 0x1b, 0x07, 0x1e, 0x35, 0x21, 0x02, 0xa8, 0x63, 0x15, 0x43, 0x20, 0x13, 0x88, 0x21, 0x62, 0x4c, 0x18,\n\t0xb3, 0xb6, 0xef, 0x6b, 0xdd, 0x50, 0x36, 0xdc, 0xb2, 0x6f, 0x1f, 0xfc, 0x6b, 0x15, 0x6e, 0xdf, 0xd7, 0xb2, 0xe1, 0xb3, 0x98, 0xf8, 0x03, 0xf2, 0xa0, 0x15, 0xfe, 0xc9, 0xfc, 0xfc, 0x36, 0xac, 0x62, 0x6f, 0xc3, 0xc7, 0xce, 0x66, 0x6b, 0x7a, 0x1b, 0xcb, 0x4c, 0x30, 0xf8, 0xd8, 0xb5, 0xf2, 0x99, 0x08, 0x7b, 0x1f, 0xea, 0xe1, 0x4f, 0xc2, 0x5e, 0x2a, 0x3c, 0xaa, 0xd7, 0x10, 0xfb, 0x71, 0x6a, 0x79, 0xe1, 0x42, 0x56, 0x17, 0xca, 0x40, 0x45, 0x18, 0xb8, 0xb7, 0xd5, 0xac, 0xd1, 0x79, 0x4c, 0x9a, 0x80, 0x5d, 0xc9, 0xe9, 0x6b, 0x9b, 0x16, 0xd8, 0x72, 0x0a, 0xf8, 0x9f, 0x28, 0xfc, 0xd6, 0x8a, 0xb1, 0x8d, 0x03, 0x2e, 0x65, 0x8e, 0x3a, 0x58, 0x75, 0xfd, 0x97, 0xbf, 0xda, 0x29, 0xdf, 0xf9, 0xdf, 0x87, 0x2f, 0x83, 0xba, 0x82, 0x3c, 0xf1, 0x0e, 0x16, 0xf9, 0x72, 0x14, 0xa3, 0xeb,\n\t0x66, 0x18, 0x6d, 0xc2, 0xcb, 0xd8, 0x6e, 0x6a, 0xcf, 0xaa, 0x78, 0x5c, 0x04, 0x7e, 0x88, 0x4b, 0xf2, 0x8d, 0x01, 0x33, 0xaf, 0x87, 0x9f, 0x61, 0xf4, 0xb1, 0xa4, 0xa1, 0x3f, 0x7f, 0x1c, 0xbf, 0x78, 0x1c, 0x6d, 0x83, 0xff, 0x48, 0x5d, 0x77, 0x70, 0xbb, 0xf0, 0x26, 0xa1, 0x11, 0x0b, 0xd8, 0x42, 0xda, 0x89, 0xc2, 0xdc, 0x1a, 0x6c, 0xe4, 0xbf, 0x03, 0x33, 0xb6, 0xe6, 0x71, 0x3e, 0x11, 0xc9, 0x59, 0x4f, 0xa7, 0x02, 0x39, 0x41, 0x59, 0x9f, 0xb4, 0x3e, 0x8d, 0x90, 0xa9, 0x90, 0x49, 0x2c, 0x35, 0xcf, 0x9f, 0xf6, 0x68, 0xe0, 0x71, 0x8b, 0x3f, 0xc4, 0x8a, 0xd6, 0xfc, 0xf4, 0x51, 0xd1, 0x50, 0x4d, 0x6e, 0x30, 0x80, 0x05, 0xad, 0xa2, 0xb6, 0xac, 0xaa, 0xbc, 0xb6, 0x29, 0x2b, 0xda, 0x1f, 0xe3, 0xae, 0xb2, 0x29, 0x14, 0x81, 0x30, 0xc6, 0xb1, 0x40, 0x61, 0x75, 0x5f, 0x73, 0x5e,\n\t0x57, 0x45, 0x0e, 0x93, 0x68, 0xc7, 0x3a, 0x68, 0xc7, 0xf3, 0xd0, 0x8e, 0xfe, 0x64, 0x03, 0x88, 0x85, 0xe8, 0xfa, 0x24, 0x43, 0x8b, 0xe0, 0x64, 0x40, 0xc5, 0x4c, 0xd2, 0xf5, 0xf3, 0xa7, 0x3f, 0x97, 0x41, 0x5d, 0xcf, 0x9f, 0x0d, 0xfa, 0x3f, 0x30, 0xf0, 0x78, 0x79, 0x30, 0x93, 0x36, 0x2f, 0x15, 0x63, 0x5e, 0x36, 0x9b, 0x0d, 0xc1, 0x30, 0x58, 0xcc, 0x98, 0xa9, 0xec, 0x8b, 0x66, 0x35, 0xd5, 0x96, 0x57, 0x95, 0xd5, 0x2a, 0xb4, 0x02, 0x17, 0xf4, 0xe5, 0x72, 0xeb, 0x7c, 0x35, 0xbd, 0x79, 0xcd, 0xad, 0xd5, 0x85, 0x81, 0x18, 0x42, 0x81, 0xa0, 0x42, 0x61, 0x83, 0xfa, 0x7a, 0xb8, 0xcd, 0xb8, 0x92, 0x7f, 0x14, 0xb6, 0x9e, 0x04, 0xbe, 0x1a, 0x65, 0xc5, 0x11, 0x02, 0x46, 0x01, 0xcf, 0x04, 0x0f, 0x2b, 0x82, 0x9e, 0x2d, 0xfb, 0xc7, 0xa3, 0x9e, 0x86, 0x8b, 0x9c, 0x66, 0xd5, 0x76,\n\t0x6e, 0x33, 0xea, 0x08, 0xe4, 0x48, 0x27, 0xe9, 0x5c, 0xf8, 0x3d, 0x7c, 0x7b, 0xf9, 0xf4, 0xe5, 0x7d, 0xb4, 0x3c, 0x1b, 0xac, 0xa8, 0x41, 0x46, 0xb4, 0x62, 0x4c, 0x6d, 0x76, 0x5e, 0xd4, 0x00, 0x25, 0xb8, 0x9c, 0x80, 0xf4, 0x6d, 0x5a, 0x7e, 0x03, 0x77, 0x1f, 0x7e, 0x96, 0xbf, 0x8e, 0x71, 0x30, 0xf9, 0xf1, 0xb0, 0x40, 0xe3, 0xfe, 0x30, 0x78, 0x15, 0x55, 0x56, 0x89, 0xbe, 0x95, 0xcf, 0x52, 0xf5, 0x83, 0x98, 0x5a, 0xa9, 0x14, 0x1c, 0x4b, 0xbc, 0x60, 0xc4, 0x44, 0x18, 0xf8, 0xc8, 0x54, 0x74, 0x45, 0xd1, 0x97, 0xc4, 0x36, 0x96, 0xbc, 0x01, 0xb4, 0xcb, 0x51, 0xd2, 0x92, 0xeb, 0xab, 0xab, 0x28, 0xb5, 0x78, 0x02, 0x68, 0x8f, 0xa3, 0xac, 0x39, 0xd7, 0x5f, 0x57, 0x51, 0xc2, 0x57, 0x84, 0x0b, 0xca, 0xfa, 0x6b, 0xdc, 0xd9, 0xde, 0xec, 0xbc, 0xfc, 0xd2, 0x85, 0xd5, 0x9e, 0x6c,\n\t0x0f, 0xe1, 0x6b, 0x77, 0xc3, 0x1c, 0x79, 0x1c, 0xe6, 0x88, 0x8d, 0xc9, 0x61, 0xee, 0x95, 0xd1, 0x98, 0x55, 0x02, 0x81, 0x56, 0x26, 0xed, 0xe8, 0x4a, 0x6c, 0x55, 0x89, 0x27, 0x1c, 0x43, 0xe3, 0x61, 0xc1, 0x17, 0x56, 0xfe, 0x32, 0x30, 0x90, 0x00, 0xb2, 0xa6, 0xf3, 0x86, 0x06, 0xd4, 0x89, 0x50, 0xad, 0x29, 0xf9, 0x05, 0x27, 0x37, 0x3b, 0x17, 0xb0, 0xf3, 0xc4, 0xf4, 0x4a, 0x64, 0x23, 0x76, 0xe1, 0x89, 0xdf, 0x39, 0xba, 0xdb, 0xa5, 0x32, 0x30, 0x89, 0x64, 0x39, 0x98, 0x71, 0x84, 0x0a, 0x8e, 0xba, 0x2c, 0xbb, 0xcb, 0x69, 0xcf, 0xc9, 0xca, 0xb1, 0x04, 0x6d, 0x02, 0x8c, 0xba, 0x11, 0x18, 0xe4, 0x14, 0xf3, 0x9f, 0x9a, 0x95, 0x64, 0x9c, 0x7c, 0xc6, 0x27, 0x8d, 0xd6, 0x40, 0x80, 0x55, 0x67, 0xba, 0xf2, 0xb3, 0x34, 0xd5, 0x91, 0xba, 0x46, 0x32, 0x3b, 0xd1, 0x8f, 0x9d, 0x66,\n\t0xf5, 0xd6, 0xed, 0x0d, 0xdc, 0x55, 0x5a, 0x1d, 0x0f, 0xd3, 0x94, 0xcb, 0xb0, 0x7b, 0x0d, 0xc9, 0x79, 0x8a, 0xfa, 0x61, 0x40, 0x25, 0x94, 0xd0, 0x0f, 0xaf, 0x07, 0x9a, 0x7c, 0x15, 0x68, 0x62, 0x67, 0xdc, 0xcc, 0xed, 0x67, 0xa1, 0x09, 0x9b, 0xa2, 0x09, 0x27, 0x7f, 0x49, 0xd2, 0xc4, 0x46, 0xfb, 0x42, 0x90, 0x4d, 0x22, 0x34, 0x48, 0x6a, 0xe2, 0xf7, 0x14, 0x45, 0x80, 0xf8, 0x6c, 0xa2, 0xc3, 0x72, 0x26, 0x3a, 0xe6, 0xf4, 0x57, 0x96, 0xba, 0x7a, 0xa5, 0x92, 0x99, 0x44, 0x2a, 0x95, 0xa3, 0x23, 0x44, 0xab, 0x38, 0xee, 0xd3, 0x5b, 0x82, 0x61, 0x5e, 0xb4, 0x27, 0xe9, 0x90, 0x3a, 0xa0, 0x48, 0x12, 0x22, 0xe0, 0xa3, 0x73, 0xee, 0x2e, 0x4a, 0x08, 0x58, 0xa5, 0x32, 0x25, 0xe4, 0x75, 0x8a, 0x26, 0xb6, 0x6f, 0x85, 0x89, 0xb8, 0x27, 0x49, 0x09, 0x8c, 0xa7, 0x93, 0x42, 0x83, 0x70,\n\t0x4e, 0x40, 0xa6, 0xc3, 0x21, 0xa0, 0xc3, 0xaf, 0x85, 0x97, 0x60, 0xdd, 0x96, 0x31, 0x5b, 0x66, 0x70, 0x10, 0xbf, 0xcc, 0x41, 0x94, 0x0a, 0x2c, 0x30, 0x1c, 0x2b, 0x70, 0x43, 0xc0, 0xb9, 0x40, 0x9f, 0x10, 0xd9, 0xa1, 0x19, 0x4c, 0xc5, 0x47, 0x99, 0xca, 0x99, 0x73, 0x81, 0x8a, 0x64, 0xb5, 0x5a, 0xcb, 0xac, 0x65, 0x3e, 0xbf, 0xc1, 0x17, 0x00, 0x9e, 0xa3, 0x12, 0xb3, 0x4f, 0xc7, 0x73, 0xd2, 0xcc, 0x78, 0x72, 0x2a, 0x99, 0x86, 0x17, 0xa1, 0x3b, 0xd2, 0x2e, 0x02, 0x0b, 0x2c, 0x8f, 0x34, 0x6c, 0x0a, 0x0f, 0x97, 0xf5, 0xc1, 0xca, 0xf0, 0xc0, 0xca, 0x80, 0x25, 0xe2, 0x81, 0x25, 0x12, 0x2e, 0x80, 0xa6, 0xdf, 0x01, 0x7c, 0xeb, 0x5e, 0xca, 0xb7, 0x9c, 0xcc, 0x66, 0xf9, 0x10, 0x3b, 0x8b, 0x99, 0x9a, 0xdc, 0xb2, 0x8c, 0x9f, 0xf8, 0xc2, 0x24, 0x59, 0x98, 0x35, 0xc5, 0xbd, 0x68,\n\t0x7a, 0x62, 0x12, 0x33, 0x94, 0x93, 0xc9, 0x97, 0xd5, 0x43, 0x33, 0x9e, 0x93, 0xc9, 0x6d, 0xb3, 0x66, 0x3b, 0xac, 0x4e, 0x9b, 0x13, 0x58, 0x9a, 0x70, 0x5a, 0x96, 0x96, 0x98, 0xdb, 0x68, 0xf7, 0x29, 0x9c, 0x0d, 0x31, 0x84, 0x2d, 0xc1, 0xd4, 0x3e, 0x95, 0xc3, 0xa1, 0x00, 0xe1, 0x54, 0xa8, 0x23, 0x31, 0x9e, 0xeb, 0x52, 0xe3, 0xf9, 0xa5, 0xe4, 0x40, 0x52, 0x4e, 0x9c, 0x6e, 0x88, 0x4e, 0x61, 0xce, 0x3e, 0xca, 0x89, 0xcf, 0x92, 0x35, 0x1e, 0x3e, 0x6d, 0xae, 0x53, 0x58, 0xf8, 0xf4, 0x91, 0xcf, 0x87, 0xbe, 0xd3, 0x91, 0x4f, 0xdb, 0x77, 0xe3, 0x69, 0x46, 0x3e, 0x0d, 0x9b, 0xff, 0xf5, 0xe9, 0x07, 0xfe, 0x54, 0xf2, 0xe0, 0x58, 0x9a, 0x81, 0xa7, 0xb4, 0xba, 0x16, 0x68, 0x75, 0x5b, 0x62, 0xec, 0x57, 0xcb, 0x63, 0x6f, 0x4b, 0x01, 0xa5, 0x91, 0x15, 0x9d, 0x5a, 0xb8, 0xa9, 0x91,\n\t0xb7, 0x4c, 0x8d, 0x3c, 0x9b, 0x54, 0x7b, 0x23, 0x89, 0xb3, 0x0c, 0x79, 0xe0, 0xa7, 0x3f, 0x26, 0xab, 0xd8, 0x0a, 0x9d, 0x26, 0xab, 0x38, 0x7d, 0xa7, 0x79, 0x79, 0x0d, 0xa3, 0x91, 0x53, 0x07, 0xbc, 0x62, 0x3b, 0xdd, 0x4a, 0xd2, 0xf4, 0xc8, 0x47, 0xf6, 0x16, 0xe0, 0xcf, 0x1a, 0x6e, 0x0b, 0xab, 0xa3, 0xfb, 0x52, 0x16, 0xe8, 0xaa, 0xf3, 0x12, 0x3c, 0x89, 0xf0, 0x66, 0x79, 0xe6, 0xe5, 0x77, 0x0b, 0xd3, 0x36, 0x2b, 0x90, 0xbc, 0x89, 0xed, 0x34, 0xa2, 0x1e, 0x9a, 0xd3, 0x13, 0xa8, 0x03, 0x62, 0x7e, 0xae, 0x27, 0xc7, 0x6a, 0xd6, 0xaa, 0xe9, 0x86, 0x28, 0x4e, 0x6d, 0x88, 0x81, 0xb3, 0x21, 0xed, 0x7b, 0x1b, 0xf6, 0x10, 0xa6, 0x8b, 0x2e, 0x3a, 0x25, 0x86, 0xc2, 0x07, 0xb3, 0x91, 0xf7, 0xb9, 0x2d, 0xa8, 0x8d, 0xf0, 0xe0, 0x2f, 0x9f, 0x05, 0x63, 0x9f, 0xf9, 0x3f, 0xd8, 0x37,\n\t0x9f, 0x38, 0xb5, 0x59, 0x9f, 0xb5, 0x6f, 0x57, 0x50, 0x1e, 0xda, 0x80, 0xcc, 0x73, 0xea, 0x1b, 0xf0, 0x54, 0xe9, 0xa9, 0xb9, 0xf4, 0x4d, 0x8e, 0x8f, 0xf0, 0x12, 0xc8, 0x03, 0xc5, 0x4c, 0x33, 0xb3, 0x4d, 0xee, 0x9b, 0x1b, 0x44, 0x01, 0xd9, 0xac, 0x59, 0x45, 0x25, 0x04, 0x91, 0x21, 0x7e, 0xb4, 0xc4, 0x6f, 0x40, 0x89, 0x44, 0x31, 0x9f, 0x5e, 0xa5, 0xa7, 0xc9, 0x02, 0x89, 0x90, 0x67, 0x29, 0xc9, 0x23, 0x0c, 0x42, 0x7e, 0x51, 0x58, 0x30, 0x10, 0x77, 0x20, 0x86, 0x84, 0xb0, 0x2a, 0xc8, 0xf3, 0xba, 0x67, 0xca, 0x15, 0xea, 0x33, 0xc8, 0x15, 0xec, 0x59, 0xa8, 0x81, 0xb9, 0xd3, 0xca, 0x1d, 0xdf, 0x3c, 0x7b, 0x8c, 0x05, 0x61, 0x3b, 0x88, 0x26, 0xb3, 0xd6, 0xa1, 0x74, 0xf3, 0xd9, 0x88, 0xf5, 0x7f, 0x8d, 0x7c, 0xcb, 0x6c, 0xe5, 0x5e, 0xc2, 0x8f, 0xf0, 0x5d, 0x67, 0xd3, 0x21,\n\t0xb6, 0xd2, 0xb8, 0x21, 0x5d, 0xfb, 0x68, 0x99, 0x5d, 0xdc, 0xd5, 0xf8, 0x1e, 0xfe, 0x36, 0xc6, 0x4c, 0xee, 0x69, 0x41, 0xf6, 0x21, 0x1c, 0x62, 0x15, 0x8d, 0x7a, 0x81, 0x40, 0xe2, 0xd3, 0x67, 0x6a, 0x54, 0x02, 0xcf, 0x98, 0x91, 0x99, 0x4f, 0x5e, 0x3c, 0x47, 0x92, 0xe7, 0x61, 0x64, 0x7c, 0xd0, 0x91, 0xf9, 0x9b, 0x9b, 0x9c, 0x57, 0x69, 0x3d, 0xb1, 0xbc, 0xbc, 0x98, 0x47, 0x7b, 0x95, 0xb3, 0x69, 0x33, 0x77, 0x75, 0x7e, 0xf7, 0xda, 0x4a, 0x77, 0x45, 0xc8, 0x6c, 0x0e, 0x55, 0xb8, 0x2b, 0xd7, 0x76, 0xcb, 0xf8, 0xc1, 0x43, 0xd2, 0x4e, 0x74, 0xde, 0xe4, 0x93, 0x4c, 0x06, 0xd3, 0xfa, 0xb8, 0x08, 0x6b, 0x20, 0x79, 0xec, 0x6a, 0x4c, 0x59, 0x4e, 0x25, 0x62, 0x14, 0x94, 0x11, 0xe6, 0x6d, 0x9b, 0x7a, 0x0a, 0xb2, 0xce, 0xe2, 0x29, 0x17, 0xae, 0x81, 0xc7, 0x03, 0x3e, 0x2a, 0x6e,\n\t0x5b, 0x23, 0xf2, 0x6d, 0x87, 0x7c, 0xad, 0x1a, 0x1d, 0xfa, 0xa2, 0xa7, 0xd0, 0x91, 0x99, 0x1d, 0x30, 0xf5, 0x76, 0xb6, 0x5f, 0x5d, 0x12, 0x72, 0xe8, 0xb3, 0xf4, 0xca, 0xee, 0x3e, 0xd0, 0xdf, 0xfe, 0xcc, 0x35, 0xb3, 0x25, 0xfc, 0xe5, 0x20, 0x43, 0xad, 0x97, 0xbd, 0xa3, 0x80, 0x30, 0x2c, 0x0b, 0x32, 0x3f, 0xf1, 0xea, 0x01, 0x49, 0x89, 0x28, 0xc1, 0x43, 0x29, 0x61, 0xc8, 0x44, 0xa6, 0xfe, 0xf9, 0xb3, 0xd3, 0x88, 0x50, 0x48, 0x3c, 0x81, 0xe4, 0x34, 0x10, 0x8f, 0xc8, 0xee, 0xc1, 0x0e, 0xd2, 0x00, 0x0b, 0x0b, 0x06, 0xe4, 0x88, 0x0a, 0x76, 0xc6, 0xe6, 0x09, 0x7b, 0x48, 0x44, 0x05, 0xa3, 0x39, 0x35, 0x23, 0x3d, 0xd1, 0xd4, 0xc1, 0xd0, 0x9d, 0x55, 0xb6, 0x02, 0xaf, 0xc9, 0xe8, 0x2d, 0xc8, 0xc2, 0x86, 0xc4, 0xaf, 0x85, 0x76, 0xee, 0x2b, 0x83, 0x3a, 0x67, 0x9e, 0x33, 0xa7,\n\t0x20, 0x5b, 0x0b, 0xbf, 0xe4, 0x67, 0x93, 0x5f, 0xc8, 0xa1, 0x13, 0x77, 0x00, 0xda, 0xfc, 0x45, 0xc6, 0xca, 0x84, 0xe3, 0x01, 0x32, 0x26, 0x40, 0xaf, 0x55, 0xa9, 0xf3, 0xdc, 0x21, 0x06, 0x06, 0xc6, 0x68, 0xc8, 0xd4, 0x11, 0x45, 0x94, 0xb1, 0x22, 0xab, 0x8c, 0x0a, 0xa7, 0xe3, 0x7c, 0xd1, 0xb2, 0x7a, 0x8e, 0xcc, 0x1b, 0x5f, 0x79, 0x11, 0xc6, 0x9e, 0xbc, 0xae, 0xae, 0xde, 0xc1, 0x6d, 0x6d, 0xb5, 0xc3, 0x4b, 0xfb, 0x16, 0x2e, 0xaf, 0x38, 0x74, 0xe1, 0xd5, 0x16, 0x7f, 0x31, 0x6f, 0xb3, 0x78, 0x83, 0x5e, 0xcb, 0x6e, 0x2b, 0xb4, 0xd5, 0x7a, 0xcd, 0x65, 0x79, 0x55, 0xbe, 0xcc, 0x19, 0x7a, 0x51, 0x79, 0x5a, 0xbd, 0x68, 0x1d, 0xa6, 0x13, 0x77, 0xba, 0x4a, 0x04, 0x8f, 0x64, 0xcd, 0x47, 0xf5, 0xbf, 0xd4, 0x7c, 0xce, 0x41, 0x3f, 0x5c, 0x77, 0xea, 0xfa, 0x59, 0x97, 0x5c, 0x3f,\n\t0xaa, 0x7f, 0xc7, 0xfa, 0x29, 0x9a, 0xfc, 0x33, 0x7f, 0x80, 0x62, 0x9c, 0x0a, 0x8f, 0x66, 0xf0, 0xa0, 0x4f, 0x2b, 0x11, 0x2f, 0x22, 0x36, 0x64, 0x44, 0x31, 0x25, 0x8e, 0x21, 0xa3, 0x95, 0xe5, 0x45, 0xf6, 0x41, 0xe9, 0x73, 0x34, 0xb6, 0x5a, 0xba, 0xe6, 0x4f, 0x77, 0xfe, 0x59, 0xba, 0x62, 0x35, 0xba, 0x10, 0xf1, 0xd2, 0x95, 0xf0, 0xf1, 0xa7, 0xbb, 0xfe, 0x0c, 0x8f, 0xd9, 0x85, 0xd2, 0xe5, 0x13, 0xd7, 0x23, 0x46, 0xba, 0x7b, 0x0b, 0x1a, 0x44, 0xec, 0x11, 0x10, 0x79, 0x2e, 0x42, 0xf8, 0x7a, 0x28, 0xb2, 0x7c, 0x8b, 0x74, 0x97, 0x74, 0x84, 0xbc, 0x47, 0xc1, 0xac, 0x9c, 0xcc, 0x53, 0xac, 0x17, 0x4a, 0x41, 0x6f, 0xf7, 0x31, 0x51, 0xa6, 0x9d, 0x19, 0x60, 0x36, 0x33, 0x97, 0x30, 0xd7, 0x31, 0xaf, 0xc5, 0x7f, 0x2e, 0x22, 0x5e, 0xb0, 0x09, 0xbc, 0x6d, 0x2c, 0xc7, 0xe9, 0x60,\n\t0xed, 0x59, 0x8a, 0x2c, 0xbb, 0x62, 0x2c, 0x43, 0xab, 0x66, 0x95, 0xaa, 0x4c, 0x95, 0x32, 0x73, 0xcc, 0x6a, 0x36, 0xb2, 0x7a, 0x03, 0x63, 0xd0, 0x93, 0xfb, 0x08, 0x98, 0x15, 0xe7, 0x7b, 0x40, 0xff, 0x11, 0x78, 0x4e, 0x18, 0x0a, 0x65, 0x07, 0x59, 0x9b, 0x0b, 0x65, 0xd9, 0x6d, 0x59, 0x43, 0x3e, 0x8d, 0x97, 0x55, 0xe8, 0x90, 0x4a, 0xa9, 0x50, 0x0d, 0x05, 0x4c, 0x7e, 0x36, 0xd3, 0x82, 0x0c, 0xfa, 0x4c, 0xc3, 0x90, 0x1b, 0x51, 0x87, 0x48, 0x37, 0x4a, 0x2d, 0xa7, 0x7d, 0x7b, 0xb7, 0x8c, 0xae, 0x58, 0xde, 0xd9, 0x11, 0xab, 0x08, 0xf8, 0xc9, 0x91, 0xf8, 0xe1, 0xab, 0xae, 0x38, 0x74, 0xf0, 0xb2, 0xbd, 0xd7, 0xed, 0xbb, 0x6e, 0xcf, 0xee, 0x9d, 0x3b, 0xc6, 0xb7, 0x8f, 0x5e, 0xb2, 0xe5, 0x92, 0xf5, 0x23, 0xc3, 0x6b, 0x57, 0xaf, 0x5a, 0xbe, 0x79, 0xc5, 0xe6, 0xc5, 0x8b, 0xfa,\n\t0x17, 0xcc, 0xeb, 0xed, 0x18, 0xe8, 0x1c, 0x68, 0x6e, 0x8a, 0xd7, 0xd7, 0xd6, 0x54, 0xb4, 0xc7, 0xda, 0x4b, 0x4b, 0x8a, 0x0a, 0xf2, 0x72, 0xfd, 0xd1, 0x40, 0x94, 0xe0, 0x73, 0xd9, 0xac, 0x06, 0x9f, 0xd1, 0xa7, 0xd5, 0xa8, 0x14, 0xc0, 0x35, 0xf4, 0x48, 0x1f, 0xa6, 0xb1, 0x6e, 0x61, 0x09, 0xf8, 0xe8, 0x39, 0x99, 0x99, 0xf0, 0x71, 0xe3, 0xac, 0xef, 0x68, 0xd6, 0x77, 0xcf, 0xbf, 0x39, 0x9d, 0x5b, 0x5b, 0x37, 0x58, 0x9f, 0x73, 0x55, 0x71, 0x5d, 0x5d, 0xd1, 0x55, 0x39, 0x75, 0x83, 0x75, 0x33, 0xbe, 0x4d, 0x14, 0xce, 0xf8, 0x2a, 0xac, 0x84, 0x0c, 0x39, 0x57, 0xc2, 0xd7, 0xe2, 0x2b, 0xe1, 0xeb, 0x3f, 0x7f, 0x3b, 0x23, 0x95, 0xfb, 0xed, 0x8c, 0xd4, 0xcf, 0xbf, 0x7c, 0xa6, 0xd4, 0x2c, 0x5f, 0xc3, 0xb2, 0x8a, 0xea, 0x9a, 0x9a, 0xea, 0x8a, 0x65, 0x0d, 0x3e, 0xc1, 0x3a, 0xfd,\n\t0xdb, 0xc9, 0x4f, 0x7c, 0x0d, 0x03, 0x15, 0x35, 0xf0, 0xa7, 0x62, 0xa0, 0xc1, 0x37, 0xfd, 0x77, 0xa9, 0x8e, 0x7c, 0xa3, 0xf9, 0x12, 0x29, 0xc9, 0xdf, 0xd9, 0x43, 0xa7, 0x4b, 0x91, 0xe7, 0x54, 0xbb, 0x74, 0x50, 0xd1, 0x24, 0x5c, 0xca, 0xb8, 0x98, 0x6a, 0x98, 0x4f, 0xbb, 0x98, 0x9b, 0x98, 0xc7, 0x98, 0x57, 0x99, 0x0f, 0xf0, 0x6a, 0x39, 0xc0, 0x66, 0xa9, 0xd1, 0x80, 0x45, 0xc5, 0x2e, 0xa4, 0x41, 0x2e, 0xc4, 0x68, 0x3e, 0xa8, 0xc6, 0x6c, 0xe6, 0x00, 0x52, 0xf1, 0xaf, 0x22, 0x41, 0x35, 0xaf, 0x17, 0x2b, 0xb5, 0x62, 0x57, 0x31, 0xca, 0x7c, 0x1b, 0x24, 0x93, 0xce, 0x7b, 0x90, 0xa2, 0xe3, 0x2a, 0xa4, 0x6c, 0x77, 0xc8, 0xae, 0xa7, 0xe7, 0x5a, 0x50, 0xd7, 0xee, 0x90, 0xcb, 0xa8, 0xcf, 0xa5, 0x0c, 0x51, 0x56, 0x49, 0x33, 0x17, 0x31, 0xa2, 0x02, 0x29, 0x44, 0x34, 0xc6, 0x20,\n\t0x8d, 0x02, 0x69, 0xb6, 0x32, 0x8c, 0x06, 0x6b, 0x18, 0xd8, 0x06, 0xf8, 0x0c, 0x55, 0x06, 0xaf, 0x1a, 0x63, 0x04, 0x95, 0x56, 0x25, 0x68, 0xc7, 0xc8, 0xe9, 0x04, 0x9b, 0x81, 0x81, 0x43, 0x67, 0xea, 0x51, 0x06, 0x9f, 0x99, 0x31, 0xc4, 0xa8, 0x74, 0x06, 0xac, 0x54, 0x29, 0x57, 0x31, 0x1a, 0x8d, 0x62, 0x85, 0x51, 0x8d, 0x15, 0x0a, 0x7b, 0x37, 0xa3, 0xd5, 0x66, 0x69, 0x7b, 0x12, 0x3d, 0x59, 0x31, 0xc7, 0xba, 0x19, 0xad, 0x52, 0xa5, 0x55, 0x6e, 0x65, 0x74, 0x4a, 0xdd, 0xf9, 0xe9, 0xde, 0x63, 0x40, 0x4a, 0x9d, 0x4a, 0x39, 0x34, 0xed, 0x3d, 0x1a, 0xf2, 0x0a, 0x3f, 0xbc, 0x62, 0x15, 0x23, 0xaa, 0x91, 0x5a, 0x7e, 0x85, 0xfa, 0xdf, 0xf0, 0x0a, 0xda, 0x07, 0x8d, 0x46, 0xbd, 0xc2, 0x88, 0xd4, 0x6a, 0xf2, 0x9a, 0xf8, 0xca, 0x7f, 0xe1, 0x0d, 0x50, 0x98, 0xc4, 0x1e, 0xd5, 0x0c,\n\t0x9d, 0xe5, 0x55, 0x0a, 0x6a, 0xb9, 0x54, 0x74, 0xec, 0x4b, 0x7b, 0x76, 0xbf, 0xf7, 0x87, 0xdf, 0xfe, 0xfa, 0xb5, 0xff, 0x78, 0xe1, 0x07, 0xdf, 0x3e, 0x7e, 0xc7, 0xed, 0x5f, 0x7a, 0xec, 0xd8, 0x63, 0xfb, 0xf7, 0xed, 0xbe, 0x69, 0xcf, 0x4d, 0x5b, 0x46, 0x57, 0x0e, 0x2e, 0x59, 0xd8, 0xdc, 0x14, 0x29, 0xcd, 0xcf, 0x0d, 0xf8, 0x1c, 0x36, 0xab, 0x49, 0x30, 0x93, 0x33, 0x47, 0x1a, 0x56, 0xdd, 0x4b, 0x5c, 0xb6, 0x62, 0xf5, 0x6c, 0x0e, 0xb2, 0x08, 0xc4, 0x26, 0x41, 0xc7, 0x8a, 0xb2, 0x41, 0xa4, 0xbc, 0x2b, 0xd0, 0x8b, 0x00, 0x39, 0xdc, 0xa5, 0xd5, 0x58, 0x44, 0xce, 0x71, 0xeb, 0x41, 0x91, 0xb4, 0x92, 0xbc, 0x6c, 0x31, 0x22, 0x25, 0x51, 0xa4, 0x9e, 0x25, 0x17, 0x8e, 0x64, 0xf7, 0x30, 0xd1, 0xcb, 0xd4, 0x50, 0x11, 0xdb, 0x80, 0x2a, 0xac, 0x2e, 0x64, 0x86, 0x42, 0xa9, 0x5d,\n\t0x26, 0x71, 0xba, 0x4e, 0xbc, 0xc2, 0xc8, 0xa1, 0x03, 0x94, 0x81, 0x7a, 0xa6, 0xc9, 0x81, 0xd4, 0xff, 0x0c, 0x2a, 0x60, 0xc9, 0x91, 0x31, 0x54, 0x12, 0x2c, 0x97, 0x6f, 0x20, 0x32, 0x90, 0x00, 0x65, 0xa2, 0x45, 0xc0, 0xcf, 0x4d, 0x72, 0xc8, 0xc1, 0xa4, 0xef, 0xa3, 0x20, 0xc7, 0xe4, 0x0c, 0x09, 0x7b, 0x0c, 0x99, 0x08, 0x76, 0xd6, 0x70, 0x5e, 0xae, 0x21, 0x4f, 0x1b, 0x76, 0xf5, 0xaf, 0x19, 0xad, 0x44, 0x98, 0x17, 0xb9, 0x4c, 0x85, 0xae, 0x30, 0x5a, 0x69, 0xff, 0xe7, 0x2f, 0x40, 0xee, 0xcb, 0x2a, 0x6c, 0x98, 0x5f, 0x95, 0x37, 0xb8, 0x62, 0xb1, 0x3f, 0x5b, 0x93, 0x29, 0xe8, 0x04, 0x95, 0xb7, 0xb0, 0xc2, 0xf5, 0xe3, 0x64, 0xc1, 0x3c, 0x28, 0x98, 0x2b, 0x17, 0x44, 0x1c, 0x14, 0x54, 0xea, 0x0a, 0xa2, 0xb1, 0xac, 0x80, 0x21, 0xb7, 0x20, 0xdf, 0xe0, 0xf6, 0x9b, 0x8b, 0x8b,\n\t0x8b, 0x4c, 0xae, 0x92, 0x1c, 0xad, 0x90, 0xab, 0x57, 0xf3, 0x20, 0x3f, 0xa8, 0x4c, 0x06, 0xf4, 0x67, 0x7b, 0xae, 0x2b, 0xb3, 0x21, 0xe2, 0x2a, 0x74, 0x65, 0xd8, 0x8b, 0x5a, 0xf2, 0x5d, 0x0a, 0x01, 0x29, 0x04, 0xa5, 0xcb, 0x65, 0xe7, 0x61, 0x3f, 0x47, 0x7a, 0x57, 0xbe, 0xdd, 0x55, 0xe0, 0xca, 0xb0, 0x15, 0x37, 0xd3, 0x24, 0x9d, 0xd2, 0xe9, 0xb2, 0x0b, 0xe8, 0x6f, 0x50, 0x63, 0x9e, 0xc1, 0xed, 0xcb, 0x5f, 0x9b, 0xeb, 0x2a, 0x76, 0x6b, 0xf8, 0xbc, 0x54, 0x7d, 0x1f, 0x35, 0x47, 0x8a, 0x1a, 0xcc, 0x81, 0xb2, 0xec, 0xd9, 0x6d, 0xe4, 0x0e, 0x1b, 0xf2, 0xf2, 0xf3, 0x0d, 0x99, 0x99, 0x06, 0x43, 0xaa, 0x94, 0x4a, 0x23, 0x72, 0x50, 0x4c, 0x6d, 0x32, 0x48, 0x99, 0xd0, 0x0c, 0x7d, 0x3c, 0x52, 0x53, 0x47, 0x1a, 0x91, 0xa3, 0x55, 0x0a, 0xf4, 0x45, 0x13, 0xef, 0x9c, 0xb6, 0x90,\n\t0xca, 0x6c, 0xe0, 0x5a, 0xf4, 0xa4, 0xdf, 0xee, 0x81, 0x80, 0x59, 0xcf, 0xdb, 0x4d, 0xae, 0xfe, 0xb5, 0xa4, 0xdf, 0x6a, 0x4e, 0x0f, 0xf4, 0x2a, 0xaf, 0x4a, 0xd2, 0x2b, 0x9e, 0x68, 0xcd, 0x12, 0x7f, 0xb6, 0xa8, 0x51, 0x26, 0x9b, 0xc3, 0x4b, 0x2d, 0x11, 0x6b, 0xc8, 0xa5, 0x9f, 0x91, 0xa8, 0xd1, 0xa9, 0x3d, 0x90, 0xf6, 0xcf, 0x97, 0xf5, 0x7a, 0x4c, 0xeb, 0xa5, 0xd4, 0x9c, 0xaa, 0xb5, 0x00, 0x46, 0x01, 0x67, 0x94, 0x35, 0xc4, 0x53, 0xe4, 0x4a, 0xb5, 0x14, 0xf6, 0xb3, 0x6f, 0x4d, 0xaa, 0xf8, 0x62, 0xc1, 0xc0, 0xe4, 0x81, 0x36, 0x16, 0x8a, 0xfb, 0xf3, 0xbc, 0x1e, 0xb7, 0xcd, 0xa4, 0xd5, 0xa8, 0x59, 0x15, 0x81, 0x6d, 0x99, 0x29, 0x0e, 0x13, 0x8c, 0x2f, 0x4c, 0x04, 0x27, 0x98, 0x43, 0x30, 0x7f, 0x91, 0x8e, 0x06, 0xff, 0x10, 0x85, 0x60, 0x08, 0x11, 0x01, 0xc6, 0xac, 0x97,\n\t0x11, 0x38, 0x73, 0xe0, 0x21, 0x99, 0x3e, 0x64, 0x56, 0x12, 0x80, 0x2f, 0x7c, 0x93, 0x42, 0xcc, 0x0c, 0xdb, 0xa5, 0xbf, 0x19, 0xf3, 0x2d, 0xad, 0xb8, 0x11, 0xd7, 0xb7, 0x5a, 0xf2, 0x4d, 0xd2, 0xdf, 0x23, 0x2e, 0x51, 0xa1, 0x73, 0x9b, 0x90, 0xc6, 0x04, 0x8f, 0x27, 0x9e, 0x9b, 0x78, 0x9e, 0x3c, 0x46, 0x2a, 0x93, 0x5b, 0x27, 0x55, 0x70, 0x2d, 0x9f, 0x3f, 0xc3, 0xe9, 0x1a, 0xf6, 0x54, 0x98, 0x0b, 0xb3, 0xa4, 0x8f, 0x4d, 0x0a, 0x73, 0x0b, 0x6e, 0x9c, 0xf8, 0x5e, 0x8b, 0x59, 0x01, 0x19, 0x22, 0xe1, 0x8a, 0xdd, 0x0d, 0x13, 0x21, 0xbd, 0xdf, 0x84, 0xd4, 0x90, 0xd2, 0x3c, 0xf1, 0x1c, 0x6e, 0x68, 0xb6, 0x28, 0x4d, 0xd2, 0xa7, 0x26, 0x9f, 0x5e, 0x5a, 0x7b, 0xad, 0x2c, 0x97, 0x7c, 0x8a, 0x3f, 0xc5, 0xab, 0xb8, 0x1b, 0x40, 0x3e, 0xf2, 0xc7, 0x3d, 0xb2, 0x80, 0x94, 0x08, 0xeb,\n\t0x35, 0x13, 0xdf, 0xc0, 0x9a, 0x4f, 0xe5, 0xb1, 0x24, 0xb6, 0x35, 0x05, 0x2a, 0x4b, 0x5c, 0xc4, 0x7d, 0x5a, 0xd0, 0x56, 0x92, 0xa5, 0x33, 0xe8, 0x22, 0x15, 0xc3, 0x82, 0x58, 0xbc, 0xe2, 0xd0, 0x32, 0x76, 0xbe, 0xd1, 0x5b, 0xe4, 0xc8, 0xb4, 0xd9, 0x5c, 0x96, 0x50, 0xbe, 0xa9, 0x22, 0xbb, 0x75, 0xbc, 0xbf, 0x90, 0xc4, 0x78, 0x78, 0x79, 0xd2, 0xc2, 0xbd, 0x22, 0x6c, 0x64, 0x54, 0x8c, 0x8e, 0x31, 0x80, 0x54, 0x5b, 0x4d, 0x7c, 0x5e, 0xfd, 0x30, 0x99, 0xe1, 0x9d, 0x5a, 0x85, 0x76, 0x9c, 0x51, 0x29, 0x55, 0xe7, 0x0b, 0x88, 0x20, 0x74, 0x82, 0x7a, 0x37, 0x24, 0x66, 0x62, 0x9e, 0x57, 0xac, 0xd0, 0x20, 0x85, 0x62, 0xa8, 0x3b, 0x83, 0xd5, 0xb1, 0xc4, 0xb0, 0x4f, 0x8d, 0xa8, 0xcf, 0x71, 0x46, 0x86, 0x5a, 0x8d, 0x98, 0xea, 0x4a, 0xea, 0x7a, 0x5c, 0x9c, 0x9f, 0x47, 0x2c, 0x59,\n\t0x4d, 0xc6, 0x0c, 0x43, 0x06, 0x08, 0x23, 0x6a, 0x9d, 0x5a, 0xa7, 0xd5, 0x28, 0xa8, 0x1d, 0x8b, 0x3e, 0x75, 0xef, 0x1e, 0x94, 0x71, 0xc7, 0xec, 0x38, 0xa2, 0x37, 0xca, 0x51, 0x74, 0xa3, 0x89, 0x98, 0xc6, 0x9c, 0x9e, 0x46, 0x2f, 0x36, 0x53, 0x1b, 0x1e, 0x8f, 0x9e, 0x38, 0x24, 0xd7, 0x20, 0xfc, 0xab, 0xbe, 0xf3, 0x3b, 0xbd, 0x47, 0x6f, 0x55, 0xee, 0x7d, 0xf6, 0xd9, 0xbd, 0x5f, 0xd8, 0xbf, 0xff, 0x0b, 0x17, 0x3e, 0xb8, 0x3d, 0xea, 0x6e, 0x1a, 0x6e, 0x41, 0x55, 0x2d, 0x07, 0xbe, 0xb3, 0x07, 0x21, 0x97, 0xb5, 0x43, 0xba, 0x10, 0x1d, 0x22, 0x9f, 0xf7, 0x04, 0x9b, 0x56, 0x54, 0x6c, 0xbe, 0x48, 0xf2, 0xa0, 0xdf, 0x49, 0x1e, 0xae, 0x47, 0xca, 0x43, 0xaf, 0x4b, 0x05, 0xca, 0x8b, 0x87, 0xcf, 0xdf, 0x2e, 0x7c, 0x83, 0x8f, 0xad, 0xf9, 0xc2, 0xa2, 0xf2, 0xd5, 0x0b, 0x9b, 0x2c,\n\t0xf5, 0xd2, 0xa7, 0x83, 0x5f, 0xda, 0x5a, 0xfb, 0x84, 0xc9, 0xfd, 0xdf, 0xfc, 0x6d, 0x37, 0x9b, 0xdc, 0xb2, 0xdd, 0xf0, 0xfb, 0x50, 0xc9, 0x5f, 0xc4, 0xe5, 0x40, 0x93, 0x96, 0xb8, 0x06, 0xcb, 0xc8, 0xd1, 0x2a, 0x25, 0xc6, 0xf2, 0x05, 0x50, 0x5c, 0x47, 0xc4, 0x54, 0x60, 0xad, 0x6b, 0x92, 0x97, 0x4a, 0x66, 0x19, 0x44, 0x81, 0x08, 0xaf, 0x04, 0xcd, 0x86, 0x58, 0x8d, 0x60, 0x86, 0xa2, 0xd9, 0x18, 0xa9, 0xa0, 0x2a, 0x86, 0x68, 0x44, 0x73, 0x4f, 0x28, 0x86, 0xfe, 0xf2, 0x5c, 0xfd, 0x46, 0xe9, 0x99, 0x32, 0x74, 0xc1, 0x86, 0x7a, 0xe1, 0xd6, 0xe7, 0x1a, 0x36, 0x7c, 0xfa, 0xa9, 0xa2, 0x66, 0x7d, 0x3d, 0x83, 0xa4, 0x0c, 0x72, 0x6f, 0x45, 0xdf, 0xd9, 0x11, 0xcf, 0x24, 0x08, 0x56, 0x3c, 0x47, 0x14, 0xa2, 0x2e, 0x85, 0x38, 0xe3, 0xbd, 0xc9, 0x4b, 0xb3, 0x4d, 0xf2, 0xc1, 0x5e,\n\t0x7a, 0x14, 0x1d, 0x8b, 0x8c, 0xa2, 0x63, 0x84, 0x57, 0x5a, 0xe1, 0xdd, 0x56, 0xd1, 0x63, 0x2f, 0x93, 0x9e, 0xd9, 0x58, 0xff, 0xdc, 0x73, 0xf5, 0x1b, 0xd0, 0x05, 0xd2, 0x85, 0x0a, 0xe5, 0x86, 0x06, 0xf8, 0x7d, 0x3d, 0x81, 0xee, 0x3b, 0x28, 0xdd, 0x88, 0x0e, 0x0b, 0x4b, 0xa8, 0xbd, 0x4f, 0x0d, 0x33, 0x9f, 0xc4, 0x6d, 0x61, 0x04, 0x46, 0xe4, 0x08, 0x9e, 0xa9, 0x8c, 0x65, 0x32, 0x34, 0x2d, 0x88, 0x41, 0x42, 0x0c, 0x1f, 0x43, 0x04, 0x14, 0x87, 0xfc, 0xf1, 0x2b, 0x54, 0xd9, 0xf9, 0xd6, 0xb3, 0x40, 0xe2, 0x9c, 0xed, 0xfb, 0xc1, 0xd9, 0xb0, 0xda, 0xe7, 0xfa, 0xfd, 0x3f, 0x13, 0x11, 0x28, 0xb2, 0x13, 0x89, 0x78, 0xf9, 0x2c, 0x38, 0xee, 0x53, 0x1f, 0x0c, 0xcc, 0x2a, 0x42, 0x86, 0xac, 0x4d, 0xba, 0x52, 0xb1, 0x3a, 0x11, 0x07, 0xc9, 0x49, 0x2f, 0x17, 0x64, 0xc3, 0xac, 0x29,\n\t0x23, 0x71, 0x12, 0x84, 0x88, 0x22, 0x8a, 0xcc, 0x31, 0x08, 0x51, 0xdb, 0xbf, 0x14, 0x50, 0xe8, 0x5f, 0x8a, 0x0e, 0x04, 0x53, 0x61, 0xaa, 0xfd, 0x59, 0x71, 0x2b, 0x8d, 0x53, 0x39, 0x2e, 0x37, 0x1b, 0x31, 0x19, 0x5a, 0x72, 0xd4, 0xc2, 0x52, 0x0b, 0xb2, 0xd9, 0x8d, 0x8e, 0xd2, 0xce, 0x70, 0x0b, 0xd3, 0x36, 0x52, 0x7e, 0xa9, 0x70, 0x57, 0xda, 0xa6, 0x24, 0x9a, 0x49, 0x14, 0xe5, 0x64, 0x8c, 0x21, 0x32, 0x8f, 0x9a, 0x49, 0x24, 0x0c, 0xe0, 0x19, 0xf0, 0x9c, 0x84, 0x13, 0x4e, 0xd9, 0xa6, 0x24, 0x2d, 0xdc, 0xc6, 0xf8, 0x9e, 0xdc, 0x70, 0x2c, 0x1a, 0x6e, 0xce, 0x6d, 0x4e, 0x05, 0xcf, 0x9c, 0x65, 0xff, 0x15, 0x9a, 0x75, 0xd0, 0xc3, 0x9e, 0xa6, 0xd5, 0xfc, 0x4f, 0xce, 0x6a, 0x27, 0xf6, 0xf0, 0x19, 0xfa, 0x85, 0x1f, 0x4a, 0xda, 0x8e, 0x25, 0x6d, 0xc9, 0x12, 0xb6, 0x63, 0xeb,\n\t0x13, 0xb6, 0x64, 0xec, 0xb5, 0x67, 0xec, 0x38, 0x4e, 0xf5, 0x5b, 0xcb, 0xe4, 0x12, 0x1b, 0x7f, 0x05, 0xb5, 0x1e, 0x03, 0x8a, 0x60, 0x72, 0xc3, 0x3d, 0x26, 0x20, 0x96, 0x27, 0x42, 0x18, 0x5e, 0x93, 0x44, 0x12, 0x1f, 0xe3, 0x7a, 0x32, 0x74, 0x0c, 0xe3, 0x74, 0xe8, 0x72, 0x33, 0x72, 0xa9, 0x49, 0x99, 0x49, 0x54, 0x59, 0x40, 0xf3, 0xb4, 0xba, 0x70, 0x45, 0x03, 0x12, 0xcc, 0xfa, 0x88, 0xfe, 0x74, 0x9d, 0xe5, 0x5a, 0xa5, 0xdf, 0x96, 0x2b, 0x1c, 0x4e, 0x97, 0x7a, 0x03, 0xfb, 0xdd, 0xeb, 0xce, 0xd0, 0x2d, 0xee, 0x56, 0xe9, 0xb3, 0x46, 0x90, 0x17, 0x95, 0xaa, 0xb5, 0x65, 0x45, 0x13, 0x17, 0xb0, 0xbf, 0xc4, 0xca, 0x33, 0x8f, 0xdf, 0x54, 0x3f, 0x8a, 0x98, 0x2e, 0x82, 0xc8, 0x60, 0xa4, 0xd6, 0x7b, 0xe4, 0x5e, 0x49, 0x24, 0xa8, 0x58, 0x98, 0x93, 0x4d, 0xaa, 0xe8, 0x89, 0x0d,\n\t0xb5, 0xf4, 0x4b, 0x0e, 0x64, 0x49, 0x31, 0x62, 0xea, 0x6b, 0x8b, 0xbb, 0x4a, 0xba, 0xf2, 0x72, 0x9d, 0x0e, 0x98, 0x66, 0x45, 0xa8, 0x90, 0x9a, 0x12, 0x78, 0x05, 0x31, 0x36, 0x05, 0x88, 0x2e, 0x5a, 0x2d, 0x44, 0x76, 0x4b, 0x68, 0xe9, 0x64, 0xfb, 0xa5, 0xf6, 0x46, 0x41, 0xdf, 0x69, 0xa7, 0xe3, 0x97, 0x9d, 0xad, 0xbe, 0xc7, 0xfc, 0x1d, 0x35, 0x81, 0xc2, 0xbe, 0x6d, 0xcd, 0xf5, 0xdb, 0x97, 0xd7, 0xa9, 0x46, 0x82, 0xf9, 0x0a, 0xc1, 0xe6, 0xcd, 0xb5, 0x54, 0xb5, 0xd8, 0xf3, 0x6b, 0x3c, 0xd2, 0x49, 0x53, 0x06, 0x3e, 0xe6, 0xcf, 0x91, 0x3e, 0x3e, 0x03, 0x25, 0xd0, 0x5e, 0xad, 0xfa, 0xc5, 0xf0, 0xbc, 0x85, 0x83, 0xd1, 0x86, 0x0d, 0x3d, 0x79, 0xfe, 0x8e, 0x2d, 0x9d, 0x76, 0xd1, 0x9c, 0xe5, 0xc8, 0x75, 0xe8, 0x1a, 0x6b, 0xfd, 0x8d, 0xf1, 0xa6, 0x80, 0xf4, 0x8e, 0xa1, 0xc0,\n\t0xd4, 0xb4, 0xcb, 0x19, 0xe4, 0x83, 0x67, 0x26, 0xd1, 0x34, 0x1a, 0x55, 0x33, 0x4b, 0x80, 0x4b, 0xb7, 0x56, 0xc3, 0x96, 0x58, 0x08, 0x1c, 0xd7, 0x4d, 0xfc, 0x03, 0xba, 0x14, 0x48, 0x60, 0x08, 0x96, 0x1e, 0x65, 0x9b, 0x1c, 0xa6, 0xf6, 0x9c, 0x49, 0xf3, 0x1a, 0x8e, 0x4b, 0x5a, 0xba, 0xd7, 0xd6, 0x74, 0x75, 0xd4, 0x2c, 0xa9, 0x5d, 0x52, 0x54, 0x10, 0xd4, 0x9b, 0x42, 0x4a, 0xe2, 0x0c, 0x61, 0x49, 0x46, 0x86, 0x27, 0x56, 0x0f, 0xe6, 0xc4, 0x31, 0x06, 0x91, 0x9f, 0x8b, 0x50, 0x06, 0x4a, 0x19, 0xd2, 0x84, 0x64, 0x0c, 0x1e, 0x4a, 0xcb, 0xd3, 0xd1, 0x8c, 0xbd, 0xc1, 0x68, 0xd5, 0x2a, 0x84, 0x8c, 0xae, 0xa2, 0xaa, 0xc6, 0xc1, 0xa1, 0xb1, 0x35, 0x06, 0x5f, 0x04, 0xc4, 0x5e, 0xaf, 0x59, 0x50, 0x97, 0x79, 0x97, 0x18, 0x23, 0x3d, 0x1b, 0x3b, 0x7b, 0x76, 0xf6, 0xe5, 0xf7, 0x2f,\n\t0x6a, 0xeb, 0x0b, 0x76, 0x6c, 0x68, 0xae, 0x1f, 0x5d, 0x54, 0xa5, 0x42, 0xe1, 0x33, 0x10, 0x8f, 0xdd, 0xc6, 0x62, 0xb5, 0x5e, 0x1d, 0xa9, 0xa8, 0xab, 0x6e, 0x69, 0x47, 0xd7, 0xc6, 0xdb, 0x1c, 0xe5, 0x21, 0x5b, 0x56, 0x30, 0xa4, 0xb3, 0xe9, 0x74, 0xc1, 0xda, 0x35, 0xad, 0x81, 0xe2, 0xfe, 0x2d, 0x0d, 0xcb, 0x36, 0xd8, 0xed, 0x5b, 0x57, 0x47, 0x56, 0xb6, 0xe5, 0x12, 0xea, 0xb2, 0x9e, 0x33, 0x52, 0x71, 0x8a, 0x4f, 0xf0, 0xf4, 0x36, 0xe8, 0x50, 0x9c, 0x98, 0xa4, 0xc3, 0x30, 0x61, 0x6a, 0xd0, 0x42, 0xf0, 0x0b, 0x83, 0x4a, 0x5e, 0xc1, 0x92, 0x8d, 0x0c, 0xb4, 0x1c, 0xe2, 0x2e, 0xc3, 0xe2, 0x11, 0x15, 0x90, 0x16, 0x31, 0x02, 0x6c, 0x7c, 0x2c, 0x2b, 0x0e, 0x26, 0xdd, 0x0d, 0x42, 0xb3, 0x32, 0xc2, 0xbf, 0xad, 0xe9, 0x72, 0x0e, 0xc4, 0x73, 0x6c, 0xd4, 0xe2, 0x25, 0xe8, 0xb7,\n\t0x96, 0xd9, 0xca, 0x88, 0xdd, 0x0b, 0x08, 0x24, 0x19, 0x3a, 0x22, 0x8d, 0xf0, 0x0c, 0xaf, 0x26, 0x93, 0xd5, 0xa8, 0x43, 0x64, 0xe1, 0xf9, 0x88, 0x25, 0x45, 0xc4, 0x63, 0x26, 0xb8, 0x21, 0x15, 0x75, 0xe8, 0xb4, 0x74, 0xbe, 0x76, 0x82, 0x63, 0xef, 0x38, 0x2e, 0xad, 0x34, 0x72, 0x2e, 0x3d, 0xda, 0x71, 0xc7, 0x90, 0xc1, 0x24, 0x7d, 0xf3, 0x4c, 0x5c, 0xa6, 0x1a, 0x1d, 0x70, 0xd7, 0x64, 0x49, 0x7f, 0xc3, 0x6b, 0x26, 0x6e, 0x1b, 0x31, 0xd8, 0xfe, 0xf0, 0x07, 0x6b, 0xe6, 0x28, 0xb7, 0x69, 0xce, 0xf3, 0xad, 0x84, 0xe9, 0x61, 0xfa, 0xe3, 0xf3, 0xf3, 0x61, 0x1f, 0xe2, 0x61, 0x51, 0x22, 0x3b, 0x88, 0x63, 0x2c, 0x10, 0x93, 0x5e, 0x2d, 0x8c, 0x81, 0x14, 0xcb, 0x30, 0x82, 0x48, 0xc4, 0x11, 0x72, 0x76, 0x88, 0x87, 0x92, 0x41, 0xb9, 0xe9, 0xc4, 0xa3, 0xce, 0x16, 0x63, 0x8a, 0x9e,\n\t0xb2, 0xd2, 0x78, 0x7d, 0x69, 0x4f, 0x59, 0x8f, 0x2f, 0x1c, 0x36, 0x86, 0xfd, 0x99, 0x2a, 0x62, 0xcc, 0xe6, 0x61, 0xad, 0x33, 0x4d, 0xd9, 0x7c, 0x5e, 0x61, 0x6a, 0xca, 0xc9, 0x27, 0xf1, 0x31, 0xe2, 0xff, 0x74, 0x3a, 0x42, 0xf0, 0xdb, 0xa4, 0xd2, 0x79, 0xbb, 0x9d, 0x35, 0xce, 0xdc, 0x6a, 0xbf, 0xde, 0x9a, 0x1b, 0x73, 0x07, 0x23, 0x21, 0x8f, 0x51, 0x67, 0x57, 0xd5, 0xd8, 0x6a, 0xdb, 0xfb, 0x8b, 0xbb, 0x2e, 0x59, 0x1e, 0x09, 0x76, 0x6e, 0x69, 0xb7, 0x96, 0x64, 0x39, 0x5f, 0xab, 0x2b, 0x97, 0xfe, 0x78, 0x66, 0x96, 0x25, 0xfa, 0xb4, 0x1a, 0x4b, 0x6e, 0xa5, 0x27, 0x58, 0x93, 0x6b, 0xb1, 0xd8, 0x2d, 0x1a, 0xdd, 0x62, 0x7b, 0xa1, 0xcf, 0x54, 0x3e, 0x78, 0x69, 0x6f, 0xe3, 0xe8, 0xbc, 0x7c, 0x9e, 0x7f, 0xa6, 0x30, 0x0f, 0xaf, 0x9a, 0xeb, 0x3e, 0x44, 0x6c, 0x6d, 0xdb, 0x09,\n\t0xde, 0x7c, 0x58, 0x96, 0x65, 0x41, 0x80, 0x05, 0xe2, 0x8c, 0x29, 0x10, 0x0f, 0x44, 0x22, 0x86, 0xa2, 0xa0, 0x03, 0x10, 0x37, 0x19, 0x62, 0x9f, 0x4c, 0xa9, 0x35, 0x26, 0xf4, 0x14, 0x16, 0x10, 0x23, 0xd1, 0x82, 0xf6, 0xc2, 0xf6, 0xa0, 0x3f, 0x3b, 0x2b, 0x53, 0xa7, 0x14, 0x89, 0xe9, 0xac, 0xec, 0x82, 0x95, 0x50, 0x1f, 0xc9, 0x22, 0x35, 0x12, 0xba, 0xb0, 0x04, 0xfe, 0x69, 0xa6, 0xd1, 0x1f, 0x68, 0x10, 0xc6, 0xd3, 0x71, 0xb3, 0x9e, 0x96, 0x1e, 0x53, 0x30, 0xe6, 0xad, 0xef, 0x5b, 0x70, 0xff, 0x03, 0xde, 0x6a, 0xfd, 0xf1, 0x92, 0x8a, 0x82, 0x45, 0xbb, 0x7b, 0xba, 0x2e, 0x5c, 0x52, 0x5c, 0xdc, 0xb9, 0xa2, 0xd0, 0x53, 0xeb, 0x50, 0x1a, 0x54, 0xb6, 0x33, 0xf1, 0xb1, 0xc1, 0x25, 0xad, 0xbe, 0xda, 0x42, 0xfb, 0xc2, 0x79, 0xdd, 0x8b, 0xd8, 0x06, 0x57, 0x8e, 0xf4, 0x76, 0xef,\n\t0xf5, 0x9d, 0xf3, 0xf6, 0xaf, 0x8c, 0x54, 0xac, 0xbc, 0xb0, 0xb5, 0x7b, 0x5b, 0xa7, 0xdf, 0xa8, 0xd7, 0xd8, 0x34, 0xec, 0xc8, 0x9c, 0xe7, 0x94, 0x01, 0x38, 0x7d, 0x45, 0x3c, 0x82, 0xa8, 0x37, 0xd5, 0xb4, 0x6d, 0x8a, 0xf2, 0x2b, 0x20, 0xd9, 0xa0, 0xbc, 0x57, 0x99, 0x8c, 0x0c, 0xe3, 0x75, 0x1b, 0x8b, 0x4c, 0x45, 0xc4, 0x3c, 0xcb, 0xef, 0x13, 0x65, 0xf3, 0x2c, 0x4b, 0xc4, 0x43, 0x94, 0x28, 0x7a, 0x09, 0x4e, 0xa0, 0x82, 0x4e, 0xbb, 0x52, 0x2a, 0x1c, 0x06, 0x74, 0x8d, 0xde, 0xa5, 0x93, 0x9e, 0xbd, 0x3a, 0x5c, 0xa2, 0x45, 0xd5, 0x8a, 0x0c, 0xe9, 0xce, 0x33, 0xce, 0x82, 0x2b, 0xf4, 0xd9, 0xa6, 0xa2, 0xec, 0x89, 0xda, 0x90, 0x03, 0xff, 0x4a, 0x5f, 0x14, 0x5a, 0x72, 0xb6, 0x9d, 0x6b, 0x7a, 0xac, 0x57, 0xd9, 0xc6, 0x78, 0x90, 0x59, 0x10, 0xef, 0x2d, 0xa5, 0x66, 0xc6, 0x84,\n\t0x1d, 0x70, 0x98, 0x5c, 0x06, 0x23, 0x05, 0x62, 0x78, 0x79, 0xb4, 0xf1, 0x0a, 0x60, 0x37, 0x24, 0x40, 0xda, 0x94, 0xff, 0x51, 0x53, 0x23, 0x39, 0x0c, 0x5d, 0x30, 0xaf, 0x71, 0xb0, 0x69, 0xb0, 0xba, 0x32, 0x2f, 0x2c, 0x5b, 0x09, 0xc3, 0xf0, 0xeb, 0x91, 0x5e, 0x3d, 0x7d, 0xf8, 0xe5, 0xa5, 0xc2, 0x4e, 0x31, 0x69, 0xd0, 0xb9, 0x8c, 0x15, 0xd3, 0x0c, 0x88, 0xad, 0xd3, 0xa7, 0x45, 0xf0, 0xb4, 0x1b, 0xf9, 0x92, 0xf6, 0x2e, 0x5b, 0xb8, 0xdc, 0x99, 0x5d, 0x9e, 0x6b, 0xd3, 0xfb, 0x63, 0x81, 0xda, 0xa6, 0x0c, 0x77, 0xb1, 0xdb, 0x5d, 0xe2, 0xce, 0x68, 0x7a, 0xff, 0xc2, 0xfc, 0x79, 0x9b, 0xe3, 0xf1, 0xd1, 0x79, 0x05, 0x75, 0xf5, 0xfd, 0xed, 0xc5, 0x8b, 0x77, 0x75, 0x76, 0xec, 0x5a, 0x54, 0xdc, 0x7e, 0xf2, 0x4c, 0x73, 0x63, 0x71, 0x7f, 0x7d, 0xd2, 0xb0, 0x38, 0x27, 0x1a, 0xb4,\n\t0xcc, 0x36, 0x2d, 0xae, 0x3f, 0x96, 0xb4, 0x25, 0xee, 0x1e, 0xcd, 0x99, 0x61, 0x67, 0xcc, 0x4e, 0x9e, 0x85, 0xb8, 0xd3, 0xd7, 0x53, 0x01, 0x28, 0xd5, 0x0d, 0xf1, 0xda, 0x5c, 0x58, 0x4e, 0x64, 0x3d, 0x01, 0xf3, 0xe1, 0xf0, 0x98, 0x08, 0xeb, 0x89, 0x65, 0xf8, 0xa9, 0xdd, 0x8e, 0x46, 0x3a, 0x13, 0x06, 0xe5, 0x05, 0x55, 0x54, 0x58, 0x5b, 0x5d, 0xd8, 0x51, 0xd4, 0x11, 0x2e, 0xf0, 0x06, 0xbd, 0x0a, 0xea, 0x32, 0x9b, 0x3a, 0xa8, 0xf7, 0x06, 0x59, 0x32, 0x7d, 0x8c, 0x33, 0x83, 0xa6, 0x44, 0xca, 0x88, 0x76, 0x7e, 0x3a, 0xba, 0xb1, 0x6f, 0x76, 0x57, 0xd5, 0x74, 0x19, 0x7d, 0x91, 0x9c, 0xaa, 0x8e, 0xb5, 0x77, 0x7a, 0xab, 0xf4, 0xb7, 0x65, 0xe5, 0x39, 0x33, 0xf3, 0xe7, 0x8f, 0xb7, 0x75, 0xed, 0x5a, 0x54, 0x58, 0xd8, 0x35, 0x58, 0x12, 0x8f, 0x2a, 0x74, 0x8a, 0xc0, 0x99, 0xf6,\n\t0xb4, 0xd1, 0x8e, 0xf9, 0xbd, 0xad, 0x9e, 0x58, 0xae, 0xb5, 0x7b, 0xe2, 0x8e, 0xec, 0x1c, 0x24, 0x16, 0x2e, 0x5e, 0xbc, 0xac, 0xa4, 0x7d, 0xe7, 0xa2, 0xe2, 0xf2, 0x65, 0xbb, 0x9a, 0x3a, 0x36, 0xb7, 0x7b, 0x9d, 0x2a, 0xa3, 0x9a, 0xdb, 0x7c, 0x66, 0xc2, 0x70, 0x33, 0xe4, 0xdd, 0x28, 0xd3, 0xc7, 0xbc, 0xfa, 0x44, 0x49, 0x2e, 0xe6, 0xa8, 0x69, 0x3b, 0xb9, 0x58, 0x2a, 0x52, 0x01, 0x57, 0x16, 0xc7, 0x95, 0x02, 0xd1, 0xa1, 0xc6, 0x19, 0x0e, 0x24, 0x04, 0xa0, 0x16, 0x0f, 0x9a, 0x9a, 0x02, 0x23, 0xc5, 0xd8, 0x34, 0x99, 0x98, 0x72, 0x67, 0x47, 0x22, 0xc4, 0x6a, 0xda, 0x52, 0x0c, 0x71, 0x5b, 0xe0, 0xc9, 0x11, 0x20, 0x29, 0xbb, 0xf5, 0x94, 0xb2, 0xf1, 0x4a, 0xb9, 0x18, 0x31, 0xfc, 0x1a, 0x57, 0x22, 0x81, 0x15, 0xe6, 0x5a, 0x94, 0x58, 0xc6, 0xc7, 0x2a, 0xc2, 0xe1, 0xd6, 0xe6,\n\t0x8a, 0xbe, 0x58, 0x5f, 0x38, 0x1a, 0x8e, 0x5a, 0x6c, 0x44, 0x22, 0x57, 0x13, 0xb9, 0xe4, 0x2c, 0x12, 0xf9, 0x0c, 0x89, 0xf5, 0x74, 0x7c, 0x4f, 0xf8, 0xcb, 0x59, 0xc5, 0xf3, 0x93, 0xb7, 0x4c, 0x13, 0x6a, 0xff, 0xfa, 0xbf, 0x91, 0xd5, 0xd1, 0xe5, 0xe7, 0x28, 0xf5, 0xce, 0x9c, 0xdf, 0x44, 0xeb, 0xeb, 0x89, 0x77, 0x5a, 0x32, 0x14, 0xc4, 0xc6, 0x8c, 0x32, 0x0f, 0x2c, 0x8c, 0x13, 0x21, 0x03, 0x84, 0x93, 0x71, 0x98, 0xf4, 0x8c, 0x08, 0x9b, 0xc6, 0x18, 0xb1, 0xa5, 0x48, 0xf2, 0x0d, 0x67, 0xb6, 0x4e, 0x47, 0xae, 0xf2, 0x09, 0x5c, 0xb4, 0xce, 0xa1, 0x73, 0x64, 0xd9, 0x8d, 0x72, 0x94, 0x45, 0x93, 0x7a, 0xb6, 0x4c, 0xef, 0x99, 0x0b, 0xb9, 0xf8, 0xed, 0xd3, 0x68, 0x31, 0xa1, 0x98, 0xf6, 0xe5, 0xf6, 0x73, 0x91, 0xf6, 0xcf, 0x8d, 0x0c, 0xec, 0x34, 0xd9, 0xbf, 0x96, 0x59, 0xc6,\n\t0xdc, 0x1c, 0xd7, 0xc4, 0x4a, 0x8c, 0x44, 0x84, 0xa5, 0xf2, 0xbf, 0x3c, 0x33, 0x0b, 0xd4, 0xc0, 0xee, 0xc5, 0x71, 0x95, 0x40, 0x8e, 0x43, 0x60, 0x7a, 0x61, 0x62, 0x26, 0x0d, 0xa2, 0x47, 0x4a, 0x25, 0x20, 0xf6, 0x0f, 0x49, 0x59, 0xc3, 0x11, 0x2f, 0x91, 0xb3, 0x33, 0x48, 0x40, 0xe3, 0x32, 0x1d, 0xcf, 0x52, 0x64, 0x20, 0xee, 0xa9, 0xaf, 0x2b, 0x06, 0x5d, 0xa2, 0xa7, 0xab, 0x6e, 0x59, 0xfd, 0xb2, 0xe2, 0xda, 0xe2, 0xda, 0x9a, 0xea, 0xf2, 0xc8, 0x94, 0x4e, 0xa1, 0x39, 0x07, 0x9d, 0x62, 0x4e, 0x53, 0x93, 0xbf, 0x6d, 0xae, 0x0a, 0xc6, 0xc9, 0xe1, 0x39, 0xce, 0xd0, 0xb9, 0x2b, 0x1b, 0xac, 0xf3, 0x5f, 0x1d, 0xa3, 0x6a, 0xe0, 0xc2, 0xc3, 0xcc, 0xc7, 0xf1, 0xcc, 0xe6, 0xda, 0x6a, 0x56, 0x98, 0xa6, 0x7f, 0xc8, 0x7c, 0xa7, 0x42, 0x83, 0x94, 0xbc, 0x72, 0x5c, 0xad, 0xc0, 0x20,\n\t0xda, 0x8e, 0x33, 0xb2, 0x34, 0x0c, 0x5c, 0x9a, 0x63, 0x55, 0x2c, 0xa7, 0x1a, 0x4b, 0xa3, 0x9b, 0xc8, 0x7e, 0x8c, 0xf2, 0x28, 0xd7, 0xa6, 0x2d, 0xcd, 0x88, 0x2c, 0xc1, 0x56, 0x19, 0x63, 0x38, 0x52, 0x07, 0x89, 0xb2, 0xc1, 0x8a, 0xe9, 0xea, 0x88, 0xc7, 0xe5, 0xe2, 0x0c, 0xaf, 0xe0, 0xc7, 0xd5, 0x48, 0xc1, 0x28, 0xce, 0xb5, 0x0a, 0xe0, 0x47, 0xf6, 0xae, 0xce, 0x9a, 0x9a, 0x65, 0x4b, 0x3a, 0x87, 0xbb, 0x86, 0x6b, 0x3a, 0x6a, 0x3a, 0x2c, 0x76, 0x59, 0x53, 0xd2, 0x12, 0x18, 0xc5, 0x73, 0xd7, 0x94, 0xe6, 0x34, 0x13, 0xb8, 0xeb, 0xce, 0x59, 0x6d, 0x92, 0x6e, 0x9d, 0xe3, 0x94, 0xf8, 0x17, 0x54, 0x28, 0x64, 0x3b, 0xb7, 0xb9, 0xc1, 0xcd, 0xd0, 0xa9, 0xfc, 0x20, 0x01, 0x6d, 0x8a, 0xaf, 0xcf, 0xb1, 0x21, 0x56, 0x48, 0xe8, 0x55, 0x5a, 0xe0, 0xfd, 0x4a, 0x01, 0x36, 0x06, 0xe2,\n\t0xe8, 0xa2, 0x14, 0x98, 0xad, 0x22, 0x4c, 0x18, 0x15, 0x66, 0x55, 0x63, 0x3a, 0xa4, 0xd4, 0xf0, 0x6a, 0x58, 0xe5, 0x4a, 0x66, 0x0d, 0x31, 0x63, 0x4a, 0x3a, 0xa5, 0x06, 0x03, 0x56, 0xaa, 0x31, 0x95, 0x97, 0x05, 0xe2, 0xc1, 0xb8, 0xd5, 0x6f, 0xf5, 0xfb, 0xbc, 0xd9, 0x8e, 0xd9, 0x9a, 0x53, 0xc6, 0xe9, 0x35, 0xa7, 0xb9, 0xd1, 0xfd, 0xde, 0x53, 0xd4, 0xa8, 0xcf, 0x3f, 0x9f, 0xeb, 0x66, 0x90, 0x4e, 0xa5, 0xc2, 0x6b, 0xce, 0x75, 0x03, 0x60, 0xa7, 0xe9, 0x58, 0xf5, 0xcc, 0x72, 0xe6, 0x57, 0x09, 0xb3, 0x90, 0xaa, 0x32, 0xcc, 0x0b, 0x44, 0xdf, 0x12, 0x93, 0xfa, 0x16, 0xd7, 0xe5, 0x38, 0xf5, 0xb1, 0x02, 0x1e, 0x0f, 0xc8, 0x45, 0x6a, 0x89, 0xbd, 0x21, 0x4f, 0x2e, 0xea, 0x12, 0x6a, 0x19, 0xec, 0x22, 0x58, 0x8d, 0x39, 0xf5, 0x98, 0x16, 0xa9, 0x34, 0x4a, 0xcc, 0x08, 0xaa, 0xb4,\n\t0x1a, 0x9a, 0x5a, 0x3d, 0xa6, 0x86, 0xa5, 0xd3, 0x34, 0xbb, 0x38, 0x03, 0x75, 0x63, 0x05, 0x59, 0x31, 0xa4, 0x92, 0xad, 0xb3, 0x2a, 0x51, 0xa4, 0xa9, 0x64, 0x20, 0x9e, 0x15, 0x6f, 0x28, 0x2d, 0x9d, 0xd7, 0xd3, 0xb0, 0x3c, 0xbe, 0xbc, 0xb4, 0xbe, 0xb4, 0xde, 0x62, 0x4d, 0x28, 0x7b, 0x3a, 0x39, 0x3a, 0xdb, 0x1c, 0x95, 0xbd, 0xc0, 0x9c, 0x36, 0xf6, 0x79, 0xe7, 0xa2, 0xf9, 0x9d, 0xdc, 0x39, 0xc7, 0x61, 0x9d, 0x9b, 0x16, 0xb8, 0xe4, 0x9c, 0xf7, 0x79, 0x6e, 0x86, 0x5e, 0x58, 0xc5, 0x2c, 0x66, 0xbe, 0x16, 0x57, 0x97, 0x17, 0x62, 0x1e, 0x13, 0xf5, 0x30, 0xe9, 0x46, 0x57, 0xac, 0x81, 0x11, 0x55, 0x8c, 0xab, 0x45, 0x0c, 0x09, 0xe3, 0x04, 0x06, 0x1e, 0xb6, 0x2d, 0xc4, 0x8d, 0x83, 0x7a, 0x44, 0x10, 0x4a, 0x95, 0x20, 0x46, 0xa9, 0x12, 0x4a, 0xa3, 0x52, 0x39, 0xa6, 0x24, 0xc1,\n\t0xed, 0x4f, 0x53, 0x22, 0x81, 0xc9, 0x0f, 0xa3, 0x49, 0xca, 0x6d, 0xa5, 0xe5, 0x84, 0x54, 0xb9, 0x81, 0xb8, 0xaf, 0xa6, 0xba, 0x00, 0x94, 0xcd, 0xce, 0xf6, 0xea, 0xc5, 0x35, 0x8b, 0x0b, 0xaa, 0x0a, 0xaa, 0x2a, 0x63, 0xa5, 0x25, 0xd3, 0x95, 0x4e, 0xed, 0x39, 0x28, 0x9d, 0x73, 0xdb, 0xee, 0x16, 0xcf, 0x41, 0x03, 0x9d, 0xd8, 0x3b, 0xd7, 0x9d, 0x6e, 0x4e, 0xea, 0x28, 0x5a, 0xf9, 0xaf, 0xaf, 0x47, 0x03, 0xe3, 0x06, 0x69, 0x04, 0x34, 0x39, 0xa2, 0xa1, 0x3a, 0x4c, 0x98, 0x88, 0x22, 0x09, 0x27, 0xad, 0x31, 0x90, 0x28, 0x64, 0xb1, 0x4c, 0x48, 0x28, 0xac, 0xc4, 0x1e, 0x36, 0x79, 0xdc, 0xe3, 0xf5, 0x18, 0x41, 0x67, 0x2d, 0x29, 0xf2, 0xd4, 0x7a, 0x6b, 0x8d, 0x6e, 0xa3, 0x3b, 0xc7, 0x65, 0xb3, 0xca, 0xba, 0xab, 0x3a, 0xbd, 0xee, 0x3a, 0x27, 0xc9, 0x8c, 0x33, 0x9f, 0xa2, 0xc8,\n\t0x9e, 0x8c, 0xcc, 0x79, 0x52, 0xcf, 0x56, 0x6a, 0xcf, 0x79, 0xfe, 0xf2, 0xb3, 0x74, 0xdc, 0x79, 0xcc, 0x26, 0xc4, 0xc7, 0xd5, 0x9d, 0x4d, 0x58, 0xc0, 0x44, 0xd5, 0x4d, 0xce, 0xe0, 0x4a, 0xe0, 0xe8, 0x9c, 0x72, 0x5c, 0x4b, 0x98, 0x07, 0x99, 0x85, 0x98, 0xc5, 0x30, 0x0b, 0x89, 0x92, 0xa6, 0x62, 0x88, 0xb5, 0x00, 0x52, 0x4f, 0x53, 0x83, 0x35, 0xb2, 0x1a, 0x3c, 0x5d, 0x00, 0xa8, 0x4f, 0x5b, 0x9e, 0x21, 0xec, 0x5e, 0x24, 0x61, 0xb6, 0x48, 0x2d, 0x5b, 0x69, 0x2d, 0x62, 0xda, 0x5a, 0xe2, 0x4d, 0x72, 0x05, 0x0c, 0xa7, 0xe0, 0xc6, 0xb5, 0x74, 0x6d, 0x9c, 0x73, 0x25, 0x20, 0x04, 0xe4, 0x2e, 0x98, 0xdf, 0x48, 0x55, 0xf2, 0xf3, 0x06, 0xe7, 0x6f, 0x5a, 0xb0, 0xa9, 0x71, 0x5e, 0xe3, 0xbc, 0xde, 0x9e, 0xb6, 0xd6, 0xd9, 0xaa, 0x79, 0xc6, 0xff, 0x42, 0x35, 0x9f, 0xdb, 0xa2, 0xe9,\n\t0x3e, 0x67, 0x3d, 0x7d, 0xce, 0x2b, 0xe8, 0x5f, 0x56, 0xda, 0xd1, 0xdf, 0xff, 0x55, 0xf9, 0x80, 0xe8, 0xf0, 0xe4, 0xec, 0xfa, 0xcb, 0x71, 0x75, 0xb4, 0x08, 0x44, 0x3c, 0xa2, 0xca, 0x27, 0x05, 0xfc, 0x08, 0x08, 0x6c, 0xac, 0x62, 0x5c, 0x25, 0x12, 0x5c, 0x63, 0xe0, 0x64, 0xc4, 0x2c, 0x11, 0x76, 0xa3, 0x84, 0x9a, 0x3f, 0xa5, 0xdd, 0x0b, 0x30, 0x52, 0x14, 0xca, 0x85, 0xf2, 0xbf, 0x98, 0x5c, 0x0a, 0xa4, 0x39, 0x76, 0x3c, 0xa1, 0x84, 0xce, 0xa9, 0xe4, 0x40, 0xdc, 0x56, 0x5b, 0x03, 0x0a, 0x3b, 0x3d, 0x0b, 0x2f, 0xac, 0x2e, 0xac, 0xb6, 0xd8, 0xe9, 0x19, 0x81, 0x86, 0x1c, 0x4b, 0xce, 0xed, 0x8c, 0x60, 0x6e, 0x22, 0xc6, 0x3b, 0x73, 0x3a, 0x30, 0x98, 0x68, 0x9a, 0xab, 0x38, 0x37, 0xa7, 0xd3, 0x03, 0xbc, 0xf6, 0x5c, 0x17, 0xf8, 0xcc, 0xf3, 0x84, 0x25, 0xa0, 0xfb, 0xdf, 0x12,\n\t0x57, 0xd5, 0x80, 0xd4, 0x9e, 0x8f, 0xf0, 0xd4, 0xf6, 0x24, 0xcb, 0xd4, 0x3c, 0x71, 0x83, 0x02, 0x6a, 0x13, 0x47, 0x25, 0xd8, 0x99, 0x58, 0xea, 0xf1, 0x99, 0xfc, 0x55, 0x04, 0x4e, 0x38, 0x35, 0x3c, 0x15, 0xd3, 0x4b, 0x80, 0xf2, 0xaa, 0x14, 0x91, 0x72, 0xec, 0x34, 0x25, 0x81, 0x7b, 0x4e, 0x8d, 0x8e, 0x63, 0xd9, 0xd2, 0xdc, 0xf0, 0xc8, 0xf0, 0xd2, 0xf1, 0x65, 0xe3, 0xfd, 0x7d, 0xad, 0xcd, 0xb1, 0x68, 0x78, 0x49, 0xee, 0x62, 0x72, 0x32, 0xa0, 0x99, 0xc3, 0x5d, 0xdd, 0x5c, 0xd5, 0xb4, 0xd3, 0x0d, 0x9a, 0xd8, 0x75, 0xf6, 0x43, 0x83, 0x9b, 0xe7, 0xaa, 0xbc, 0x5d, 0xf0, 0xbf, 0x39, 0x51, 0x90, 0x36, 0xfc, 0x9b, 0x6e, 0x8f, 0xa8, 0x3f, 0x32, 0xb7, 0x88, 0xfd, 0x8c, 0xfa, 0x55, 0x12, 0x2c, 0x35, 0x96, 0x86, 0x46, 0x4d, 0xf8, 0x5e, 0x0f, 0xa4, 0x10, 0xb2, 0x12, 0x41, 0x42,\n\t0xf4, 0x9e, 0x18, 0xfc, 0x0c, 0xb2, 0x9f, 0x9d, 0x54, 0xec, 0xc3, 0xff, 0x9c, 0x10, 0xc8, 0x2f, 0x97, 0xe2, 0xcf, 0x60, 0x69, 0x1d, 0x44, 0x87, 0xf1, 0xfd, 0xec, 0x63, 0x67, 0xb6, 0xf9, 0xd6, 0x7b, 0x0e, 0xe2, 0xf0, 0xc4, 0x1b, 0xec, 0x63, 0x13, 0xbf, 0x24, 0x67, 0xbe, 0x53, 0x65, 0xe4, 0x18, 0x25, 0xf2, 0xbd, 0xf6, 0x9a, 0xd9, 0x86, 0x03, 0xb3, 0x5f, 0x4f, 0xeb, 0xb8, 0x14, 0x85, 0x25, 0x5a, 0xd1, 0x7e, 0x14, 0x22, 0xe6, 0x06, 0x5b, 0x98, 0x9d, 0x5c, 0x33, 0xd7, 0x23, 0xc7, 0x28, 0xa1, 0xef, 0x5f, 0x9a, 0xb0, 0x0a, 0x60, 0xd0, 0xfc, 0xb0, 0x9f, 0xbe, 0x7f, 0xd6, 0xf5, 0xfe, 0x96, 0xde, 0xcb, 0x1f, 0x19, 0x19, 0x79, 0xf4, 0x50, 0x6f, 0xef, 0xa1, 0x47, 0x47, 0x46, 0x1e, 0xb9, 0xbc, 0x17, 0xaf, 0x4e, 0x7d, 0x7b, 0xf4, 0x60, 0x6f, 0xef, 0xc1, 0x47, 0xa1, 0x8d, 0x7b,\n\t0xd1, 0x41, 0xfc, 0x08, 0xfb, 0x14, 0x9d, 0xff, 0x53, 0x6d, 0x1c, 0xa2, 0x6d, 0x5c, 0x9a, 0xb8, 0x81, 0xc7, 0xf0, 0x86, 0x04, 0x7e, 0xc8, 0xec, 0x77, 0xc4, 0x66, 0x61, 0x28, 0xee, 0x2d, 0xe8, 0x19, 0xa9, 0xa9, 0xde, 0xd0, 0x53, 0x58, 0xd8, 0xb3, 0xa1, 0xba, 0x66, 0xa4, 0xa7, 0xe0, 0x62, 0x5b, 0x5e, 0xa5, 0xdb, 0x5d, 0x95, 0x67, 0xb7, 0xe7, 0x55, 0xb9, 0xdd, 0x95, 0x79, 0x36, 0xfc, 0x95, 0x54, 0xf2, 0xfa, 0xde, 0x82, 0x82, 0xde, 0xf5, 0x35, 0xe4, 0xe9, 0xb4, 0x5c, 0xd4, 0x16, 0x84, 0xe0, 0xce, 0xc1, 0xf6, 0xfb, 0x1e, 0xc8, 0x7f, 0x91, 0xc7, 0x04, 0x1e, 0x33, 0xed, 0xb2, 0x55, 0xb9, 0x7a, 0x96, 0x91, 0x32, 0x71, 0xcb, 0x99, 0x16, 0x25, 0x62, 0xe0, 0x31, 0x2b, 0x1d, 0x0a, 0x3d, 0x8d, 0x08, 0x56, 0xe1, 0xf7, 0xdc, 0x30, 0xf1, 0xfe, 0x9b, 0x63, 0xe5, 0x3f, 0x45, 0x9f,\n\t0xa0, 0x52, 0xbe, 0xdf, 0x92, 0xdf, 0x90, 0x7b, 0x60, 0xc9, 0x30, 0xb5, 0xf5, 0x61, 0x12, 0xb8, 0x76, 0xa4, 0x7e, 0x8e, 0xc5, 0x28, 0x55, 0x7f, 0x82, 0x6f, 0xae, 0x43, 0xb2, 0x2d, 0xf6, 0x4c, 0x42, 0xa7, 0xea, 0x77, 0x73, 0x04, 0x5d, 0xd4, 0x87, 0x4a, 0xd1, 0x27, 0x3f, 0x8d, 0x6c, 0xff, 0xd5, 0xfb, 0x13, 0x47, 0xf9, 0xf7, 0x86, 0x97, 0x1c, 0xc8, 0x6d, 0xc8, 0xb7, 0xc8, 0xed, 0xcf, 0xe3, 0xee, 0x84, 0xf6, 0xff, 0x11, 0xe8, 0xda, 0x12, 0x57, 0x19, 0xa9, 0x95, 0xbd, 0xec, 0x3c, 0x6e, 0xa3, 0x6e, 0xaf, 0xd4, 0x70, 0x25, 0x71, 0x22, 0xb3, 0x8e, 0x99, 0x69, 0xcb, 0x42, 0xc8, 0x4e, 0xda, 0x80, 0xa1, 0x3f, 0x8f, 0xfb, 0x0d, 0x7e, 0x62, 0x53, 0xa2, 0x87, 0x97, 0x25, 0xec, 0x6c, 0xa9, 0x2d, 0x5d, 0xed, 0x45, 0x07, 0x0e, 0xf7, 0xdc, 0x7c, 0xed, 0x57, 0x2a, 0xc7, 0x1f, 0xd8,\n\t0xd9, 0x75, 0xc5, 0xbe, 0x8b, 0xea, 0xb8, 0xff, 0x32, 0x06, 0x5d, 0xc6, 0xc5, 0x2b, 0x7a, 0x77, 0x2f, 0xcc, 0xcf, 0x74, 0xf8, 0x8c, 0x72, 0x1f, 0xaf, 0x64, 0x5f, 0xe7, 0x5f, 0x22, 0x32, 0x5d, 0xdc, 0xa9, 0x24, 0x67, 0xa0, 0xc4, 0xa5, 0xb1, 0x8b, 0x49, 0x40, 0xae, 0xc1, 0x9b, 0x71, 0x8f, 0x21, 0xd7, 0x4b, 0x6d, 0x65, 0x12, 0xb6, 0x83, 0x51, 0xa2, 0x98, 0x54, 0x44, 0x23, 0xec, 0xeb, 0xef, 0xfc, 0x0f, 0xad, 0xb7, 0xee, 0xa2, 0xfd, 0x57, 0xf5, 0xdc, 0x7c, 0xdd, 0x57, 0xf8, 0x97, 0x6e, 0xf9, 0x66, 0x66, 0x96, 0xcf, 0x78, 0x9b, 0xfc, 0x1a, 0x7a, 0xa7, 0x41, 0x7c, 0x59, 0x3f, 0x14, 0xde, 0x66, 0x1c, 0x4c, 0x80, 0xa9, 0x8f, 0xd7, 0x10, 0xb3, 0x2e, 0xd8, 0x88, 0x04, 0x24, 0x90, 0xe0, 0x11, 0xd4, 0xb1, 0x75, 0x75, 0xca, 0xb1, 0x75, 0x88, 0xed, 0xc9, 0xce, 0x46, 0x4c, 0x76,\n\t0x20, 0xdb, 0xef, 0xc9, 0x99, 0xe9, 0x88, 0xa2, 0x52, 0x9d, 0xc1, 0xc1, 0x95, 0x3a, 0xf7, 0x93, 0xd3, 0x87, 0x33, 0xb8, 0xba, 0x22, 0xfe, 0x43, 0x9d, 0xd3, 0x7a, 0xc1, 0x0d, 0x3a, 0xaf, 0x2f, 0x9d, 0xd7, 0x2b, 0xba, 0x4f, 0x9a, 0xd0, 0x6b, 0xff, 0x0a, 0xe2, 0x28, 0xb4, 0xb9, 0x07, 0xa4, 0xf9, 0x95, 0x8a, 0xa5, 0x8c, 0x1a, 0xf4, 0x91, 0x8e, 0x78, 0xab, 0x01, 0x61, 0xde, 0x4b, 0xa2, 0x48, 0x74, 0x09, 0x48, 0x36, 0xf5, 0xe2, 0x99, 0x71, 0x91, 0x20, 0x60, 0xc0, 0x30, 0xf0, 0x0c, 0xc7, 0xf2, 0x1c, 0x85, 0x3f, 0x21, 0xc7, 0xb7, 0x98, 0x9d, 0xaf, 0xd5, 0x30, 0x4c, 0x38, 0xe8, 0x74, 0xd8, 0x2c, 0x9a, 0x7c, 0x6d, 0x3e, 0x54, 0xa2, 0xf2, 0x29, 0x54, 0xe6, 0x7c, 0x25, 0x75, 0x9a, 0x27, 0xb0, 0x0c, 0x6c, 0xd2, 0x63, 0x23, 0x85, 0x15, 0x95, 0x72, 0xa9, 0x59, 0x29, 0x3d, 0xad,\n\t0x77, 0x5a, 0xaf, 0x7e, 0x47, 0x99, 0x69, 0xca, 0xd2, 0x9f, 0x6f, 0xf5, 0x5a, 0x35, 0xbb, 0xec, 0x25, 0x6d, 0x45, 0x45, 0x1d, 0x75, 0x15, 0x0e, 0xab, 0xd7, 0xa2, 0xd9, 0x63, 0x2f, 0x6d, 0x2b, 0x2c, 0xee, 0xa8, 0x8b, 0x2a, 0x96, 0x4a, 0xef, 0x64, 0x88, 0x48, 0xaf, 0xd1, 0x89, 0x58, 0x2a, 0xd3, 0x67, 0xfb, 0x0c, 0x85, 0xfd, 0x0d, 0x41, 0x77, 0xc8, 0x63, 0x70, 0xfa, 0xf5, 0x85, 0x0b, 0xe3, 0x41, 0x4f, 0xc8, 0x4d, 0xe9, 0x4f, 0xfc, 0x50, 0x3e, 0x14, 0x9e, 0x87, 0x39, 0x0c, 0x12, 0x46, 0x3c, 0x97, 0x4b, 0xf4, 0x00, 0xc3, 0x9e, 0x43, 0xee, 0x6f, 0x09, 0x8b, 0x21, 0x58, 0x79, 0x98, 0x9d, 0xc7, 0x30, 0xc4, 0xa3, 0x9e, 0x40, 0x64, 0xf9, 0x78, 0x02, 0x24, 0x36, 0x45, 0x55, 0x62, 0x6b, 0xf7, 0x61, 0x8a, 0x7c, 0x52, 0x03, 0xf1, 0x59, 0x11, 0x9e, 0x97, 0x24, 0x20, 0x98, 0xd5,\n\t0x2a, 0x5d, 0xb1, 0x8f, 0x54, 0xb7, 0x9e, 0xf8, 0xbb, 0x24, 0xde, 0x53, 0x18, 0xcf, 0xe3, 0x12, 0x16, 0x2e, 0xe4, 0x40, 0x72, 0xd6, 0x7b, 0x10, 0x7d, 0x8f, 0xc0, 0x31, 0x4a, 0xa4, 0xa4, 0x9e, 0x2c, 0x04, 0x0e, 0x8b, 0x46, 0x63, 0xa1, 0x21, 0xbc, 0x72, 0x80, 0x22, 0x37, 0x6c, 0xb3, 0x3a, 0x75, 0x1f, 0x8a, 0xf2, 0x7b, 0xac, 0xd6, 0xbf, 0x6a, 0xf5, 0x08, 0x93, 0xf7, 0x4c, 0x4e, 0x32, 0x3b, 0x84, 0x12, 0x76, 0x40, 0x91, 0x8d, 0x43, 0xcc, 0x03, 0x4c, 0x25, 0xf3, 0x16, 0x12, 0x18, 0xe2, 0x33, 0x4d, 0xe3, 0xcb, 0xbf, 0x25, 0x83, 0x4b, 0x62, 0x46, 0x2d, 0x94, 0xe0, 0xfb, 0x15, 0x4e, 0x20, 0x7d, 0xc6, 0x59, 0xda, 0x82, 0x19, 0x82, 0x23, 0xa0, 0x10, 0x18, 0x35, 0x56, 0x93, 0xb6, 0x18, 0x69, 0x88, 0x5e, 0xd2, 0x18, 0x44, 0x1a, 0xf3, 0x6b, 0xbd, 0xdd, 0x64, 0x50, 0xbe, 0x7d,\n\t0x8d, 0xd5, 0xa1, 0x97, 0x5e, 0xd8, 0x88, 0x2b, 0x27, 0x5e, 0x54, 0x38, 0xb1, 0x42, 0xab, 0x91, 0x3e, 0x12, 0x74, 0xc8, 0x2d, 0x1d, 0x3a, 0x5f, 0x3e, 0xa7, 0x1e, 0x86, 0x39, 0xfe, 0x0b, 0xe1, 0x78, 0xc2, 0x3f, 0xab, 0x2e, 0x5e, 0x0d, 0xb3, 0x5c, 0x81, 0x04, 0x98, 0xea, 0x09, 0xc7, 0xab, 0xe9, 0xde, 0xdb, 0x43, 0xc4, 0x7b, 0xfb, 0x34, 0xde, 0x56, 0xaa, 0x7f, 0xdd, 0xdb, 0xea, 0x0c, 0x53, 0xff, 0xa6, 0xb3, 0x7b, 0x5b, 0xa5, 0x5d, 0x12, 0x0a, 0x5b, 0x7e, 0x8e, 0xd1, 0x98, 0x33, 0xdd, 0xdb, 0x6a, 0xc6, 0x77, 0x46, 0xf6, 0x4d, 0x7b, 0x09, 0xbf, 0x08, 0x7d, 0x37, 0x52, 0x5c, 0xd9, 0x60, 0xdc, 0x47, 0x7d, 0x21, 0xa0, 0xd3, 0xa0, 0x3d, 0x70, 0x3c, 0xcf, 0x2d, 0x66, 0x38, 0x8e, 0x1f, 0x20, 0xda, 0x77, 0xaf, 0xde, 0x44, 0x76, 0x08, 0x0a, 0x32, 0x79, 0xb6, 0xce, 0x90, 0x89,\n\t0xd0, 0x76, 0xf6, 0x66, 0x4f, 0xdc, 0x4d, 0xa7, 0x48, 0xfd, 0x59, 0x1a, 0x2a, 0xfd, 0x6d, 0x9f, 0xac, 0xbf, 0xc2, 0xbc, 0x78, 0x43, 0x7c, 0x3d, 0xd1, 0xd6, 0xd6, 0x24, 0xd6, 0x14, 0x0d, 0x2a, 0xb7, 0x12, 0x53, 0xef, 0x4d, 0xe2, 0x6d, 0xb5, 0x91, 0xf0, 0xda, 0xac, 0xd3, 0xf7, 0x83, 0x84, 0xd5, 0x9c, 0x73, 0x57, 0x78, 0xd2, 0x95, 0x12, 0xa3, 0x3b, 0xdf, 0x66, 0xcd, 0x25, 0x8d, 0xca, 0xb5, 0xda, 0xf2, 0xdd, 0x46, 0xf4, 0x4d, 0xe8, 0x94, 0x15, 0x3a, 0x67, 0x30, 0x40, 0xe7, 0xac, 0xd0, 0xc9, 0x89, 0xdb, 0xc8, 0xf4, 0x12, 0xd7, 0xd8, 0x72, 0xc9, 0xb3, 0xdc, 0xa9, 0x8e, 0xcf, 0xfc, 0xfe, 0x3a, 0x61, 0xff, 0x0b, 0x79, 0x89, 0x6d, 0x16, 0xaf, 0xa1, 0x51, 0xdb, 0x17, 0xca, 0xbb, 0x85, 0x9d, 0x43, 0x49, 0x24, 0xcc, 0x84, 0x6b, 0x10, 0xbd, 0x4c, 0xda, 0x48, 0xbc, 0x85, 0x5c,\n\t0xb3, 0xd2, 0x88, 0x35, 0xc6, 0xd2, 0x44, 0x0c, 0x3d, 0x16, 0xcf, 0xa7, 0x00, 0x99, 0xd9, 0x59, 0x86, 0x4c, 0xca, 0xaa, 0xf8, 0x19, 0xac, 0x6a, 0x76, 0x6f, 0xd8, 0xe6, 0xe9, 0x0c, 0x4a, 0xfa, 0x93, 0xd9, 0x5f, 0xec, 0xb0, 0x17, 0x91, 0xc8, 0x79, 0x45, 0x76, 0x47, 0xb1, 0xdf, 0x2c, 0x96, 0x49, 0xef, 0xe8, 0x14, 0xc8, 0xa0, 0xd1, 0x8a, 0x38, 0x9c, 0x55, 0xe4, 0x35, 0x9b, 0xbd, 0x45, 0x59, 0x24, 0x01, 0x32, 0xca, 0x3e, 0xb4, 0x8b, 0xb8, 0xeb, 0xf1, 0xcb, 0xc2, 0x09, 0x18, 0x03, 0x3f, 0xb3, 0xf4, 0x71, 0x17, 0xb1, 0x0d, 0x49, 0x00, 0xe4, 0x58, 0x49, 0xd8, 0x16, 0xbc, 0x9e, 0x41, 0xbc, 0x7c, 0x8e, 0x23, 0x70, 0xb0, 0x58, 0x87, 0x58, 0x8a, 0x00, 0x43, 0xfd, 0xde, 0x67, 0x27, 0x0c, 0xc4, 0xcd, 0x26, 0x13, 0x62, 0x4c, 0x7e, 0x93, 0x8f, 0xa0, 0xb2, 0xca, 0xa0, 0xac, 0x62,\n\t0x1a, 0x50, 0x56, 0x9e, 0xf5, 0xb1, 0x14, 0x74, 0xcf, 0x62, 0xad, 0x20, 0xb1, 0x86, 0x22, 0xe8, 0x3a, 0x47, 0x09, 0x41, 0x5f, 0x2d, 0x71, 0x38, 0xca, 0x02, 0x16, 0x4b, 0xa0, 0x0c, 0x79, 0xdf, 0x7e, 0xe2, 0xed, 0x2b, 0x34, 0x56, 0xf1, 0x42, 0x25, 0xfc, 0xb9, 0x48, 0xb4, 0x6a, 0xf8, 0xe3, 0x24, 0x39, 0xbb, 0x8c, 0x64, 0x2b, 0xcb, 0x26, 0xd9, 0x1d, 0xd2, 0x27, 0x48, 0xad, 0x14, 0x0e, 0x28, 0x35, 0x1a, 0xe5, 0x01, 0x50, 0x94, 0x31, 0xd3, 0x26, 0xa8, 0xf0, 0x9b, 0x0a, 0x17, 0xf4, 0x25, 0xc8, 0xac, 0x95, 0x3b, 0xe1, 0x26, 0x8d, 0xa3, 0xb0, 0x4e, 0xe4, 0x3c, 0x1f, 0xb6, 0xed, 0x29, 0xe1, 0x83, 0x18, 0x0b, 0x33, 0xf3, 0x1d, 0xf1, 0x9c, 0xe9, 0x59, 0xf0, 0xf6, 0x53, 0x72, 0x24, 0xbb, 0x15, 0x34, 0x05, 0xe6, 0xd8, 0xad, 0x54, 0x10, 0xa5, 0x08, 0xba, 0x76, 0x16, 0xd1, 0x51,\n\t0xe9, 0x47, 0x4f, 0x7c, 0x74, 0xad, 0xd6, 0xa7, 0x1b, 0x67, 0x05, 0x16, 0xfe, 0x8d, 0xeb, 0x7c, 0x5a, 0x31, 0x7b, 0x5a, 0x06, 0x07, 0x29, 0x80, 0xa4, 0x8f, 0x90, 0x5e, 0x30, 0x5e, 0xcb, 0x2b, 0x39, 0x4e, 0xc9, 0x5f, 0x63, 0x12, 0x64, 0x5b, 0xdb, 0xdf, 0x73, 0x03, 0x6c, 0x9c, 0xef, 0x62, 0x9c, 0xc4, 0x1f, 0x91, 0xc0, 0xc2, 0x80, 0xdc, 0x21, 0x43, 0xaf, 0x11, 0x39, 0x85, 0x84, 0xbc, 0x85, 0xa4, 0x6c, 0x6b, 0x16, 0x27, 0x58, 0x88, 0x70, 0x40, 0x62, 0x6d, 0x11, 0x54, 0x1a, 0x9f, 0x38, 0xf3, 0xb3, 0x08, 0x45, 0xd9, 0x38, 0x8b, 0x4b, 0x59, 0xbd, 0x41, 0xcf, 0xba, 0xde, 0xf3, 0xc0, 0x67, 0x26, 0x9b, 0xf3, 0xbe, 0x9b, 0xcb, 0x84, 0xef, 0x45, 0x98, 0xe5, 0xbb, 0x34, 0x99, 0xea, 0x47, 0x34, 0xf0, 0x67, 0xe7, 0xce, 0xa9, 0xff, 0x1f, 0x51, 0x1a, 0x34, 0x24, 0x6e, 0x25, 0xca,\n\t0xc7, 0xd5, 0xec, 0x2a, 0x72, 0x64, 0xf7, 0x28, 0xc8, 0x47, 0xc4, 0x0f, 0x8c, 0x84, 0x9c, 0x42, 0x95, 0xfb, 0xa4, 0x1f, 0xb2, 0xab, 0x24, 0x57, 0x3f, 0x7a, 0x47, 0xc6, 0xdc, 0x90, 0xee, 0xc5, 0xcb, 0x99, 0x6c, 0x68, 0x50, 0x6e, 0x3c, 0x48, 0xe4, 0x24, 0x07, 0xbd, 0x21, 0x4b, 0xda, 0x87, 0x0e, 0x13, 0xfb, 0x58, 0xba, 0x24, 0x36, 0xb0, 0x3d, 0x61, 0xbd, 0x1c, 0x7b, 0x8e, 0x97, 0x3d, 0xc6, 0xa9, 0x5c, 0x1a, 0x4b, 0x09, 0xac, 0xc1, 0x50, 0xac, 0x02, 0x19, 0x78, 0x8d, 0x31, 0xdb, 0x52, 0x5a, 0xa1, 0x75, 0x95, 0x05, 0x33, 0xaa, 0xcf, 0x6b, 0xf6, 0x3b, 0xcb, 0xbb, 0x8a, 0xca, 0xcf, 0xcb, 0x71, 0xf1, 0x3f, 0x11, 0x45, 0xb1, 0xbe, 0xc8, 0x9a, 0xe7, 0x31, 0x65, 0x3b, 0x23, 0xcd, 0xc1, 0x70, 0x4b, 0x69, 0x76, 0xb6, 0xb5, 0x53, 0x4b, 0x63, 0x25, 0x08, 0x22, 0x7e, 0x5b, 0x61,\n\t0x84, 0xbd, 0xe9, 0x09, 0x86, 0x34, 0x40, 0x60, 0x1e, 0x23, 0xe0, 0xaa, 0x04, 0xf1, 0x1f, 0x39, 0xc8, 0xe6, 0x44, 0xe2, 0x09, 0x70, 0x57, 0xb3, 0xbc, 0xe0, 0xc4, 0x41, 0xe6, 0xfe, 0x16, 0x82, 0x6d, 0xfd, 0xbd, 0xc9, 0x7e, 0x66, 0x25, 0xec, 0x5f, 0x08, 0x3d, 0xb4, 0x52, 0xde, 0xbf, 0x90, 0xf4, 0xc7, 0xc9, 0x1b, 0x38, 0x2f, 0xff, 0x5b, 0x12, 0x3b, 0x51, 0xf6, 0x32, 0x57, 0xcb, 0xc6, 0xc4, 0x20, 0xd1, 0xca, 0x38, 0x39, 0xf2, 0x1e, 0xce, 0x6c, 0x1c, 0x78, 0x2c, 0x40, 0x43, 0x04, 0x8a, 0x32, 0x1e, 0x0f, 0x5b, 0x83, 0xe6, 0x59, 0xe3, 0xee, 0xc5, 0xdc, 0x0e, 0xb5, 0xc1, 0x64, 0x33, 0x6c, 0x29, 0x73, 0x3b, 0x04, 0x53, 0x86, 0x59, 0x23, 0xc0, 0x58, 0x7e, 0x71, 0x32, 0xca, 0x5e, 0xc3, 0x9d, 0x80, 0xfd, 0x59, 0x4f, 0xd6, 0x7b, 0x02, 0x68, 0xc7, 0x47, 0x8b, 0xcb, 0xe1, 0xb7,\n\t0x48, 0x1d, 0xf8, 0x1f, 0x19, 0x41, 0x47, 0xcb, 0xc9, 0x63, 0x19, 0xb9, 0xd6, 0x16, 0xee, 0x8b, 0x56, 0xc7, 0x3f, 0xef, 0xb4, 0x3a, 0xe4, 0xb9, 0x70, 0x12, 0x5f, 0x81, 0xbb, 0x59, 0x2f, 0x8c, 0x03, 0x68, 0x48, 0x32, 0x22, 0xef, 0x62, 0x0a, 0x6d, 0x32, 0x40, 0x2a, 0xeb, 0xa5, 0xfc, 0x95, 0xd5, 0xb3, 0x44, 0x70, 0x30, 0x7b, 0xa2, 0xb8, 0x7b, 0xe2, 0x61, 0xd6, 0x7b, 0xcb, 0x2d, 0x89, 0x18, 0x12, 0x42, 0x26, 0xf0, 0xdd, 0xe3, 0x40, 0x17, 0xd8, 0xab, 0x91, 0x09, 0xe8, 0xf2, 0x84, 0x4c, 0x17, 0xf4, 0x6d, 0x64, 0x4a, 0xd0, 0x05, 0xf2, 0xb0, 0x9d, 0x8a, 0x7e, 0xba, 0xaf, 0x87, 0x4f, 0x93, 0x87, 0xf8, 0x41, 0x7f, 0x20, 0xfc, 0x27, 0xe4, 0xb9, 0x9f, 0xc9, 0x47, 0xb5, 0x90, 0xe7, 0xf1, 0x54, 0x9e, 0xda, 0x44, 0x9e, 0x36, 0x78, 0xd7, 0x9b, 0x8a, 0x62, 0xc8, 0xf3, 0xf0, 0xe9,\n\t0xde, 0x35, 0xf9, 0x3e, 0x69, 0x0f, 0x7d, 0xd7, 0x7d, 0x93, 0x2f, 0x9e, 0xe6, 0x5d, 0x3b, 0x84, 0x2c, 0x7c, 0xbf, 0xf8, 0x9b, 0x44, 0x9b, 0xab, 0x20, 0xcf, 0xf3, 0xa9, 0x3c, 0x55, 0x89, 0x3c, 0x5b, 0xb9, 0x47, 0x40, 0xe6, 0xb9, 0x1c, 0xf2, 0x1c, 0x87, 0x3c, 0x35, 0x90, 0xe7, 0x7b, 0xa9, 0x3c, 0x35, 0x74, 0x30, 0xf1, 0xe4, 0x1d, 0xc0, 0x23, 0xae, 0x10, 0x1d, 0x40, 0x77, 0x23, 0x91, 0x45, 0x78, 0x90, 0x1a, 0xa9, 0xbe, 0x40, 0x7f, 0x91, 0x37, 0x1c, 0xd0, 0x19, 0xd4, 0x20, 0x27, 0x64, 0xea, 0x54, 0x46, 0xb5, 0x51, 0x96, 0x8b, 0x84, 0x69, 0x72, 0x11, 0x2c, 0xa4, 0xd4, 0x6f, 0xe8, 0x16, 0x5f, 0xbe, 0xee, 0x8b, 0x2b, 0xad, 0xd9, 0x99, 0xaf, 0xfc, 0xd1, 0x57, 0xa0, 0x7f, 0x72, 0xa3, 0xd5, 0xa3, 0xff, 0x5c, 0x74, 0x58, 0xad, 0x7f, 0xc8, 0xd4, 0xfd, 0xcd, 0x66, 0xf9, 0x43,\n\t0x46, 0xc6, 0xdf, 0x60, 0x34, 0x56, 0x0a, 0x4a, 0xfc, 0xbc, 0x68, 0x04, 0xe9, 0x27, 0x2f, 0x1e, 0x92, 0x7d, 0x13, 0x39, 0xd9, 0xdd, 0x90, 0x9b, 0x72, 0x37, 0x24, 0x62, 0x98, 0x82, 0x84, 0xe9, 0xca, 0x40, 0x19, 0x09, 0x31, 0x4c, 0xf6, 0xd4, 0xa3, 0xf2, 0x68, 0x05, 0x3a, 0x72, 0xe4, 0x6b, 0x37, 0xb5, 0x2e, 0x2d, 0xa8, 0x0d, 0x64, 0xde, 0x74, 0xa7, 0x68, 0x3c, 0xbc, 0xaf, 0xb5, 0xd7, 0x14, 0x88, 0x79, 0xaf, 0x38, 0x90, 0x90, 0xe9, 0x9f, 0x15, 0x2e, 0xa7, 0x78, 0xf2, 0xb1, 0x78, 0x39, 0xb1, 0x49, 0x47, 0x82, 0xb8, 0x46, 0x91, 0x5e, 0xd6, 0x21, 0xc0, 0xd9, 0x33, 0xe5, 0x1c, 0xe5, 0x99, 0x84, 0x79, 0xb2, 0x5f, 0x9e, 0x5e, 0x96, 0x91, 0x0e, 0x51, 0x87, 0xe9, 0x74, 0xe2, 0xca, 0x7c, 0x2a, 0x1f, 0xf6, 0x90, 0x35, 0x28, 0x3e, 0x9d, 0x18, 0x37, 0xdb, 0xd4, 0x1a, 0x84, 0x31,\n\t0xb1, 0xc9, 0x63, 0xc2, 0x74, 0x71, 0x1f, 0xb3, 0xb7, 0x0b, 0xc7, 0xa8, 0xce, 0xdd, 0x20, 0xef, 0x9f, 0xc6, 0x64, 0xc4, 0xb8, 0x24, 0xc4, 0x3c, 0xdd, 0x78, 0x6c, 0xa9, 0xa7, 0x29, 0xb9, 0x71, 0x80, 0xc8, 0x8d, 0xbd, 0x03, 0x4f, 0x4c, 0x0f, 0x1a, 0x4a, 0xfe, 0x76, 0xb1, 0x8b, 0x4e, 0xde, 0x4f, 0x7e, 0x84, 0x63, 0xfb, 0xee, 0xde, 0x27, 0xfb, 0x8a, 0x7c, 0x55, 0x1a, 0xc5, 0x1b, 0x27, 0xbf, 0x4a, 0x4c, 0x4f, 0x1f, 0x85, 0x61, 0x28, 0xc9, 0xe7, 0x89, 0xc5, 0x7f, 0x0c, 0x6f, 0x7c, 0xf7, 0xdd, 0x05, 0x47, 0x8f, 0x3e, 0xf4, 0xee, 0xbb, 0x7d, 0x37, 0xdf, 0x3c, 0x3b, 0x1f, 0x47, 0x78, 0x1c, 0x22, 0x01, 0x30, 0xad, 0xd8, 0x7e, 0xf4, 0xe8, 0x82, 0x77, 0xdf, 0x95, 0x46, 0x6f, 0xbe, 0xb9, 0xef, 0xdd, 0x77, 0x21, 0xdf, 0x5b, 0x13, 0x9f, 0x62, 0xc3, 0xe4, 0x77, 0xe5, 0x7c, 0x34,\n\t0x46, 0x31, 0x75, 0x21, 0x40, 0x17, 0x1e, 0x83, 0x6c, 0x0b, 0xa4, 0x5f, 0x43, 0xee, 0xf7, 0x16, 0xc0, 0xec, 0x52, 0x4d, 0xfc, 0x1d, 0xd7, 0x4f, 0x3e, 0x47, 0xf3, 0xf1, 0xe4, 0xbd, 0x88, 0xa2, 0x5f, 0xe1, 0xfa, 0x77, 0x17, 0x1c, 0x3b, 0x06, 0xf9, 0xde, 0xeb, 0x83, 0x8a, 0x81, 0x0e, 0xcf, 0x4b, 0x1e, 0xbc, 0x6a, 0xf2, 0x76, 0x8a, 0x81, 0x7e, 0x06, 0xbd, 0xde, 0x1f, 0x3c, 0x9d, 0x5e, 0x6f, 0x89, 0x24, 0x60, 0x2b, 0x85, 0xe7, 0x3d, 0x95, 0xdd, 0xb9, 0x79, 0xdd, 0x55, 0x5e, 0x6f, 0x55, 0x77, 0x5e, 0x6e, 0x77, 0xa5, 0x67, 0x4b, 0x79, 0x51, 0x41, 0x34, 0x5a, 0x50, 0x54, 0x2e, 0xbd, 0x95, 0xdf, 0x16, 0xc9, 0xce, 0x8e, 0xb4, 0xe5, 0xe7, 0xb5, 0x95, 0xc1, 0x7e, 0xdb, 0x96, 0x97, 0x5f, 0x51, 0x91, 0x5f, 0x50, 0x51, 0x21, 0xd3, 0xe8, 0x18, 0x77, 0x08, 0x8f, 0x0b, 0x5d, 0xd0,\n\t0x56, 0x57, 0xdc, 0x91, 0xd6, 0x57, 0x23, 0x11, 0x77, 0x58, 0x8e, 0x5f, 0x8e, 0xc7, 0xa5, 0x87, 0x0f, 0xa3, 0x37, 0xf9, 0x97, 0xa4, 0xa7, 0xd1, 0x09, 0xb9, 0xfc, 0xe5, 0xd3, 0xca, 0xa7, 0xf3, 0xb9, 0x48, 0x96, 0xa7, 0x71, 0x8b, 0xf1, 0xf8, 0x61, 0xe9, 0x61, 0xf4, 0x26, 0x77, 0x39, 0x6a, 0x93, 0x7d, 0xee, 0x8f, 0x91, 0xd8, 0x86, 0x50, 0x15, 0x4f, 0x4f, 0x7e, 0x88, 0x8e, 0x40, 0x77, 0xb8, 0xe5, 0x32, 0xf8, 0x19, 0x3d, 0xde, 0xe7, 0xf5, 0x14, 0x59, 0x34, 0x60, 0x26, 0xd1, 0x99, 0xa1, 0x01, 0xc1, 0xc3, 0xfb, 0xf6, 0xa1, 0x13, 0xd2, 0xd3, 0xb4, 0xfc, 0x51, 0x28, 0xbf, 0x33, 0x59, 0x9e, 0xdc, 0x0f, 0x62, 0xc2, 0x58, 0xd3, 0x95, 0x47, 0x34, 0xbe, 0x33, 0xde, 0x29, 0xb9, 0xd0, 0x52, 0x12, 0x5d, 0x76, 0x1f, 0x6a, 0x85, 0xf2, 0x5d, 0xd2, 0x51, 0xee, 0xd8, 0xe4, 0x53, 0x30,\n\t0x13, 0x57, 0x75, 0x3f, 0xa4, 0x23, 0x33, 0x91, 0x9c, 0x34, 0x40, 0xe3, 0x47, 0x98, 0x44, 0x33, 0x36, 0xa4, 0xf0, 0x5c, 0x0d, 0x34, 0x89, 0x68, 0x31, 0x53, 0x29, 0x71, 0x6b, 0xea, 0x61, 0x92, 0x6c, 0xcb, 0x09, 0xd9, 0xe6, 0x25, 0x7c, 0xe1, 0x45, 0x46, 0x84, 0xa9, 0x4a, 0x7c, 0xe1, 0x79, 0x3d, 0xb4, 0x1f, 0x78, 0x33, 0x77, 0xec, 0xf3, 0x47, 0xd6, 0xb0, 0x57, 0xb7, 0x49, 0x6f, 0xa2, 0xe0, 0xdd, 0x77, 0x33, 0xd3, 0xda, 0xc0, 0x33, 0x83, 0x72, 0x1b, 0x0c, 0x14, 0x97, 0x65, 0x24, 0x45, 0x89, 0xa9, 0x26, 0xe8, 0x67, 0x92, 0x48, 0x6e, 0x41, 0xf2, 0x19, 0x69, 0x40, 0x32, 0x49, 0x6e, 0x81, 0x7a, 0x3a, 0x01, 0x78, 0x42, 0x40, 0x33, 0x7d, 0xfd, 0x07, 0x97, 0xc2, 0xbb, 0x29, 0xfd, 0xde, 0x95, 0xcc, 0xac, 0x6b, 0x72, 0x07, 0xf0, 0xc7, 0x8a, 0xe3, 0xb0, 0xb1, 0x77, 0x80, 0xcc,\n\t0xdd, 0x9e, 0x04, 0x87, 0x93, 0x77, 0x17, 0xd9, 0x9f, 0x46, 0x3e, 0xc6, 0x59, 0xcc, 0xa4, 0x76, 0x9c, 0xe4, 0x31, 0x0b, 0x30, 0x8c, 0x40, 0xb0, 0x3c, 0x06, 0xa3, 0xc3, 0xba, 0xa4, 0x8f, 0xa4, 0x4f, 0x5c, 0x2e, 0xa4, 0x46, 0x7a, 0xe9, 0xc2, 0x75, 0x57, 0x66, 0x46, 0x32, 0x0e, 0xae, 0x97, 0x31, 0x6e, 0x16, 0xe3, 0xdd, 0xc2, 0x4a, 0x1a, 0x03, 0xa3, 0x3d, 0x01, 0x75, 0x40, 0x50, 0x05, 0x40, 0xaa, 0x5c, 0x39, 0xe3, 0xac, 0x28, 0x8b, 0xc0, 0x08, 0x60, 0x76, 0x31, 0x79, 0x17, 0x34, 0x64, 0x88, 0x42, 0xac, 0x0f, 0x90, 0x7c, 0x20, 0xf4, 0x6b, 0x4c, 0x26, 0x93, 0xd5, 0x64, 0x35, 0x87, 0xfd, 0x3c, 0x3d, 0x0c, 0x99, 0x29, 0x19, 0xc7, 0x60, 0x76, 0xa2, 0xa3, 0x96, 0x60, 0x69, 0x76, 0x52, 0xb4, 0x24, 0xa0, 0xff, 0xef, 0xee, 0xe3, 0x97, 0x38, 0x64, 0xa0, 0xff, 0xa4, 0x2c, 0xf9,\n\t0x3f, 0x13, 0x9f, 0x61, 0x85, 0x2c, 0x0b, 0xff, 0x80, 0x0b, 0xe3, 0x7f, 0x08, 0x7d, 0xb4, 0x5d, 0xbe, 0xb8, 0xdb, 0x4a, 0xbd, 0xc9, 0x88, 0xb7, 0x7e, 0xfb, 0xec, 0x33, 0x2b, 0xf9, 0xf0, 0xee, 0x14, 0x5d, 0x03, 0x85, 0x10, 0xfa, 0x39, 0x88, 0xaf, 0x8e, 0xe9, 0xe2, 0x2c, 0x0a, 0x49, 0x47, 0x06, 0xd0, 0x18, 0xff, 0xa3, 0x54, 0x43, 0xe4, 0x17, 0xf7, 0x4a, 0x47, 0x96, 0x23, 0xaa, 0x02, 0x5c, 0xcd, 0x5d, 0x82, 0x8f, 0x0a, 0x63, 0xf4, 0xbd, 0xf9, 0xf1, 0x30, 0x81, 0x58, 0x48, 0x98, 0xdb, 0x62, 0xd2, 0xf9, 0x54, 0x9f, 0x11, 0x33, 0x15, 0xec, 0x80, 0x4f, 0x23, 0x80, 0x5a, 0x61, 0x42, 0x4f, 0x89, 0xd2, 0x89, 0x80, 0x06, 0xff, 0x45, 0xfa, 0xc7, 0xaf, 0xb5, 0x24, 0xa4, 0xe6, 0x44, 0x03, 0x2c, 0xef, 0x5d, 0x2a, 0xaf, 0xf7, 0x7a, 0x58, 0xaf, 0xaf, 0xf2, 0x0f, 0xc2, 0xac, 0xc8,\n\t0x8e, 0xdb, 0xe5, 0x53, 0xa6, 0xf3, 0xc8, 0x9c, 0x59, 0x87, 0x4f, 0x5d, 0x2c, 0x51, 0xfc, 0xea, 0xc4, 0x56, 0x2c, 0xf2, 0x0f, 0x4a, 0xaf, 0xef, 0xbd, 0x9f, 0xae, 0x75, 0x2f, 0xf7, 0x1b, 0x61, 0x2d, 0xcc, 0x95, 0xac, 0xb8, 0x55, 0xa9, 0xe0, 0xa1, 0xd9, 0x02, 0xf5, 0x26, 0x94, 0x85, 0x19, 0xa3, 0x81, 0x12, 0x29, 0x60, 0xf6, 0x45, 0x03, 0x30, 0x1a, 0x3c, 0xf7, 0x1b, 0xa9, 0xf0, 0x2e, 0xe9, 0x97, 0x77, 0x71, 0x2d, 0xdc, 0xcb, 0x5b, 0x9e, 0x79, 0xa7, 0x55, 0xda, 0x8b, 0xe3, 0x12, 0x5d, 0xf3, 0x93, 0x5b, 0xb9, 0xdf, 0xe0, 0x1d, 0x89, 0x7a, 0x04, 0x1e, 0x93, 0x0b, 0xe0, 0xf6, 0xa9, 0x7a, 0x8c, 0x98, 0x2e, 0xf7, 0x00, 0x2c, 0x77, 0x3e, 0x1a, 0xd1, 0x73, 0xbf, 0xf9, 0xfc, 0x99, 0xbb, 0x50, 0xee, 0xd7, 0xc5, 0x9b, 0x25, 0xac, 0x90, 0x36, 0xb7, 0xfe, 0xb7, 0xf4, 0x91, 0x2c,\n\t0xd7, 0x6c, 0xe5, 0x76, 0xe2, 0xef, 0x0b, 0x57, 0xe3, 0x10, 0x5f, 0x39, 0x79, 0x01, 0xf3, 0x0a, 0x13, 0xe2, 0xab, 0x99, 0xc3, 0xcc, 0x2b, 0xb0, 0xe7, 0x1c, 0x67, 0xee, 0x63, 0xec, 0xe4, 0x4c, 0xe2, 0x15, 0xd8, 0x72, 0x88, 0x6c, 0x47, 0x3f, 0x31, 0xfa, 0xf6, 0xe4, 0x7d, 0x29, 0xd9, 0x61, 0x27, 0xc8, 0x0e, 0x72, 0xd9, 0x21, 0x5a, 0xb6, 0x86, 0x79, 0xee, 0x1c, 0xca, 0x7e, 0x5f, 0x38, 0x02, 0x65, 0xab, 0xfe, 0xc5, 0xf7, 0xca, 0x65, 0x57, 0x9e, 0xe3, 0x7b, 0x77, 0x71, 0x25, 0xf0, 0xde, 0x27, 0x40, 0x76, 0x7d, 0x92, 0xb9, 0x8b, 0x91, 0x7b, 0xfd, 0x19, 0x12, 0xe9, 0xdb, 0x3f, 0xa3, 0x65, 0xbf, 0x3d, 0x79, 0x57, 0xa2, 0xf0, 0x67, 0x72, 0x61, 0xfa, 0x99, 0x2c, 0x7b, 0xcf, 0x8c, 0xb2, 0xab, 0x68, 0xd9, 0x1a, 0x90, 0x99, 0xe6, 0x52, 0xf6, 0x41, 0xe1, 0xa9, 0x54, 0xd9, 0xaa,\n\t0xc9, 0x35, 0x89, 0xf7, 0xee, 0x3a, 0x6b, 0xd9, 0xfc, 0xc9, 0x3f, 0x73, 0xbf, 0xe3, 0xef, 0x67, 0x04, 0xdc, 0x7c, 0x92, 0x8c, 0x70, 0xb1, 0x74, 0x23, 0xfb, 0x09, 0xff, 0x34, 0x53, 0xc0, 0x74, 0xc6, 0xdb, 0x32, 0x74, 0x98, 0xc8, 0xb0, 0xa2, 0xe0, 0x71, 0x63, 0x8e, 0x67, 0x53, 0xda, 0x02, 0x0d, 0xfd, 0xc1, 0x0c, 0x10, 0x73, 0xc2, 0x91, 0x6e, 0x05, 0x12, 0xc5, 0xe1, 0xee, 0xa4, 0xa3, 0xdd, 0x18, 0x0d, 0x22, 0x5b, 0xc0, 0x14, 0x18, 0x2b, 0x02, 0xc6, 0x80, 0xcf, 0xa2, 0x54, 0x39, 0xf2, 0x23, 0xfa, 0x50, 0x11, 0xaa, 0x43, 0x11, 0x19, 0xea, 0xc2, 0x4a, 0x7d, 0xac, 0x05, 0x27, 0x6c, 0x58, 0xa9, 0x38, 0x13, 0xb8, 0x8c, 0x86, 0x2a, 0xf1, 0xe8, 0x7f, 0xb2, 0xc9, 0xea, 0xbc, 0xfd, 0x96, 0xab, 0xed, 0x21, 0xa3, 0x2b, 0xab, 0xa5, 0x01, 0x6f, 0xf2, 0x74, 0x6c, 0x9f, 0xef, 0x89,\n\t0x65, 0x8b, 0x58, 0x91, 0x61, 0x37, 0xf6, 0xc6, 0xa5, 0xd5, 0xec, 0x32, 0x2d, 0x6f, 0xb5, 0xf4, 0xed, 0xff, 0xfa, 0x03, 0xbc, 0xb0, 0x59, 0xaf, 0x5a, 0xbe, 0x7e, 0xff, 0xe7, 0x6f, 0x24, 0x42, 0x98, 0xa8, 0x94, 0x5c, 0xfb, 0x02, 0xf6, 0x96, 0x93, 0x77, 0x27, 0xfa, 0x21, 0x6c, 0x83, 0x7e, 0x34, 0x33, 0xdf, 0x93, 0x63, 0xec, 0x98, 0xfc, 0x99, 0x19, 0x2c, 0x11, 0xba, 0x54, 0xca, 0x28, 0x12, 0x15, 0x6c, 0x97, 0x0f, 0xb8, 0xa9, 0x23, 0x6e, 0x82, 0x0f, 0x6e, 0x66, 0x12, 0xb5, 0x8b, 0x21, 0x45, 0xa2, 0xd0, 0x29, 0x19, 0xb0, 0x6a, 0xa8, 0x3b, 0x85, 0x63, 0x35, 0xd4, 0x4d, 0x5c, 0x46, 0x99, 0x01, 0x01, 0x64, 0x01, 0xe8, 0xbd, 0x56, 0x83, 0x55, 0xaa, 0x61, 0x62, 0x93, 0x3a, 0x15, 0x4c, 0x22, 0x92, 0x24, 0xc6, 0xba, 0x14, 0x3a, 0xed, 0x59, 0x4b, 0x0d, 0x50, 0x61, 0xaa, 0x99,\n\t0x69, 0x6e, 0x6a, 0x8c, 0x37, 0xd4, 0xd7, 0x05, 0x08, 0xf1, 0xcc, 0xd1, 0x80, 0x85, 0xd8, 0xbf, 0x4c, 0xd1, 0x8f, 0xf0, 0x16, 0xab, 0xa8, 0x63, 0x89, 0x14, 0x2a, 0x83, 0x1e, 0x9f, 0x86, 0xa0, 0x28, 0x41, 0x4f, 0x5f, 0x92, 0xa6, 0x65, 0x2b, 0x0f, 0xf6, 0x37, 0xd7, 0xf2, 0x48, 0x67, 0xf5, 0x18, 0x0b, 0xbb, 0xca, 0xb3, 0xd1, 0xb3, 0xb7, 0x5c, 0x6d, 0x0b, 0x1b, 0x9c, 0x59, 0xad, 0x84, 0xca, 0xd3, 0x03, 0xc3, 0x48, 0xab, 0xbe, 0x2f, 0x75, 0x26, 0xc8, 0xdc, 0xb3, 0xf4, 0x8a, 0x55, 0xa5, 0xa6, 0x21, 0x8d, 0x56, 0x40, 0x96, 0xf2, 0xc5, 0x0d, 0x6d, 0xe9, 0xc8, 0x4e, 0x22, 0xc7, 0x10, 0xaa, 0xb3, 0xcb, 0x09, 0xe5, 0x09, 0xff, 0xbc, 0x10, 0xf4, 0x90, 0xbb, 0xf9, 0xcb, 0xe8, 0x39, 0x52, 0xb9, 0x8c, 0xc6, 0xa4, 0x9d, 0x3a, 0x3e, 0x1a, 0xa2, 0x10, 0xeb, 0x2c, 0x55, 0x91, 0x96,\n\t0xb2, 0x14, 0x5b, 0x0a, 0xcb, 0x8a, 0xfd, 0x69, 0x11, 0xd6, 0x4f, 0x39, 0xff, 0xda, 0x70, 0xca, 0xd9, 0x57, 0xfd, 0x29, 0x47, 0x76, 0xaa, 0xb3, 0x22, 0x47, 0x91, 0x9b, 0x09, 0x15, 0xe8, 0x28, 0x56, 0xfe, 0xbb, 0xd0, 0xd6, 0x69, 0xb1, 0xe5, 0x61, 0xb3, 0x4b, 0xbf, 0xa3, 0x60, 0xeb, 0xec, 0xdd, 0x84, 0xaf, 0x9c, 0xb5, 0x7f, 0x81, 0xfe, 0xf4, 0x6d, 0xe9, 0x46, 0x5c, 0xc2, 0xdf, 0xc6, 0x04, 0x99, 0xf5, 0x93, 0x44, 0xc2, 0x78, 0x68, 0x72, 0x98, 0xf0, 0xc3, 0xc9, 0xff, 0x96, 0x6e, 0x65, 0xcb, 0xc8, 0x73, 0xfc, 0x1e, 0x45, 0xba, 0x7c, 0xc8, 0x20, 0xf3, 0xfc, 0x47, 0x26, 0xff, 0xc2, 0xc7, 0xe1, 0x79, 0x11, 0x73, 0x54, 0xd6, 0x67, 0x55, 0xf9, 0x88, 0x17, 0xb5, 0xd4, 0x36, 0xc2, 0x91, 0xfc, 0x02, 0x33, 0x87, 0xcc, 0x4b, 0x92, 0x5c, 0x40, 0x40, 0x8e, 0x79, 0x86, 0x18, 0x58,\n\t0x11, 0x57, 0xdb, 0xad, 0x0c, 0x81, 0x0f, 0x67, 0xb7, 0x12, 0xa7, 0x80, 0x01, 0x98, 0x4d, 0x43, 0x14, 0x16, 0x71, 0x90, 0xc0, 0x76, 0x11, 0xe4, 0xe4, 0x78, 0xc9, 0x59, 0xb3, 0x0b, 0xc2, 0xb0, 0x5c, 0x46, 0x06, 0x5b, 0x06, 0xb9, 0x44, 0x4f, 0x02, 0x45, 0x99, 0xc3, 0x99, 0xc4, 0x45, 0x36, 0x11, 0x33, 0x3d, 0x35, 0xb1, 0xa6, 0x6e, 0xab, 0x48, 0x8c, 0x82, 0x98, 0x2c, 0x78, 0x12, 0xb3, 0x46, 0x76, 0xe3, 0xde, 0x47, 0xb7, 0x47, 0x97, 0xdf, 0xf2, 0xd2, 0xf6, 0x8e, 0x03, 0xf5, 0x3e, 0xde, 0x6e, 0xd4, 0xe4, 0x14, 0xc4, 0xfc, 0x8b, 0x2e, 0x5d, 0x56, 0x18, 0x5c, 0x7c, 0xe5, 0xd0, 0x17, 0x73, 0xd0, 0xe0, 0xc4, 0xed, 0xaf, 0x71, 0x6d, 0x5a, 0x13, 0xbb, 0x9c, 0x6f, 0x58, 0x7f, 0xb8, 0x6f, 0xc7, 0xa3, 0x17, 0xc5, 0xb3, 0xb3, 0xf7, 0x98, 0x74, 0x4a, 0x8d, 0xb2, 0x60, 0xde, 0xa6,\n\t0x86, 0xd8, 0xf2, 0xb8, 0x7f, 0x10, 0xb4, 0x99, 0xeb, 0x3e, 0xd7, 0xf3, 0xb7, 0xcd, 0x37, 0x84, 0x2c, 0x30, 0x97, 0x56, 0x33, 0x0c, 0xf7, 0x0d, 0xa0, 0x8d, 0x48, 0x6e, 0x1b, 0x08, 0x50, 0x9e, 0x8c, 0x07, 0xbc, 0x86, 0x1e, 0x37, 0x92, 0x18, 0x2e, 0x43, 0x09, 0xd0, 0x60, 0x85, 0x42, 0xa1, 0x56, 0xa8, 0x49, 0x50, 0xed, 0x4c, 0x12, 0xc4, 0x86, 0xe8, 0x1d, 0xa4, 0x5d, 0x44, 0xdb, 0x5e, 0xcd, 0xb5, 0x4b, 0x1d, 0xaf, 0x49, 0x6d, 0x5c, 0xfb, 0xe7, 0x4f, 0x72, 0xf3, 0x1e, 0x39, 0x39, 0xcc, 0xde, 0x86, 0x99, 0x47, 0x1e, 0x61, 0xe4, 0x1d, 0x8d, 0xe1, 0xdc, 0x50, 0xbf, 0x8f, 0x78, 0x40, 0xaa, 0x10, 0xc7, 0xa3, 0x2e, 0x10, 0xb3, 0x68, 0x5c, 0x6c, 0xbc, 0x26, 0x79, 0x7b, 0x41, 0x62, 0x1e, 0x29, 0x07, 0x18, 0xa5, 0x72, 0x28, 0x11, 0xee, 0xc8, 0xe7, 0xf5, 0xea, 0x0d, 0x1e, 0x7f,\n\t0x50, 0x6f, 0xcc, 0xa4, 0x01, 0x5f, 0x3c, 0x2e, 0x64, 0x8d, 0x98, 0x7d, 0x3a, 0x44, 0xc2, 0x18, 0xf8, 0xbc, 0x21, 0x44, 0x82, 0x1b, 0x10, 0x73, 0xc2, 0x18, 0x6c, 0xd3, 0xf4, 0x77, 0x0f, 0xe7, 0x96, 0x6e, 0x6c, 0x68, 0x51, 0xff, 0xf6, 0x77, 0xe6, 0x5b, 0xf7, 0x95, 0x78, 0xd0, 0xd1, 0xef, 0x54, 0x66, 0x4b, 0xb7, 0xeb, 0xc3, 0xb9, 0x0f, 0x3c, 0x77, 0xe8, 0xab, 0x59, 0x13, 0x12, 0x16, 0xcd, 0x5f, 0x39, 0xfc, 0x02, 0x7b, 0x3f, 0xcf, 0xfa, 0xd7, 0x35, 0xdc, 0xbc, 0xe1, 0xb6, 0x80, 0xbd, 0x74, 0xe2, 0x67, 0x85, 0xe8, 0xaf, 0x76, 0xf3, 0x0d, 0x9b, 0x97, 0xde, 0xbc, 0x72, 0x5d, 0x02, 0x9f, 0x98, 0x5b, 0x08, 0x6d, 0xcd, 0x27, 0xde, 0x2f, 0xb9, 0x01, 0xbf, 0x28, 0xf0, 0x24, 0x22, 0x3a, 0xeb, 0xcb, 0x71, 0xa9, 0x39, 0xf9, 0x56, 0x8a, 0xe0, 0x25, 0x33, 0x63, 0x04, 0x79, 0x89,\n\t0x1c, 0xe8, 0xe0, 0x41, 0x99, 0x36, 0xce, 0x40, 0xb0, 0x80, 0xae, 0xab, 0x80, 0xd9, 0x24, 0xf2, 0x66, 0xfa, 0xbf, 0x5e, 0x1e, 0xc4, 0x8a, 0x04, 0x2e, 0x95, 0x47, 0x2f, 0x46, 0xcb, 0x1b, 0x50, 0x94, 0xfe, 0xaf, 0x8f, 0xa0, 0x3f, 0xa0, 0xfa, 0x6c, 0xe9, 0x2d, 0xfa, 0xdf, 0xba, 0xde, 0xbd, 0x03, 0xa5, 0x6e, 0xd3, 0x81, 0xd6, 0xcb, 0xbf, 0xbf, 0x57, 0x7a, 0xe1, 0x49, 0xc7, 0xed, 0xf0, 0xef, 0x35, 0xf6, 0xbe, 0xbb, 0x8e, 0x78, 0xb5, 0x37, 0x5f, 0x7e, 0xd7, 0xf5, 0x3e, 0xf5, 0x2d, 0xd2, 0xdf, 0xf3, 0x16, 0xec, 0xe8, 0x34, 0x65, 0x95, 0x5f, 0xf0, 0xd8, 0x45, 0x71, 0x74, 0xde, 0x79, 0x37, 0x38, 0xb5, 0x0b, 0xaf, 0x38, 0xef, 0x06, 0x97, 0x7a, 0x21, 0x5e, 0xc8, 0xa0, 0xc9, 0xa7, 0xa4, 0x5b, 0xd1, 0x66, 0xd0, 0x04, 0x2c, 0xcc, 0x4a, 0x39, 0x1e, 0x92, 0x86, 0x1e, 0x6b, 0x3a,\n\t0xc8, 0x27, 0x47, 0xe3, 0x21, 0x79, 0x29, 0x14, 0x60, 0xe2, 0xd8, 0x66, 0xb8, 0x3b, 0x15, 0xba, 0x87, 0x86, 0x82, 0x71, 0xca, 0x09, 0x2c, 0xc1, 0xf4, 0xe6, 0xc6, 0x68, 0x86, 0x24, 0xca, 0x39, 0x89, 0xf7, 0x72, 0xdc, 0x13, 0x08, 0xe8, 0x33, 0x09, 0xce, 0xf5, 0xff, 0xc7, 0xde, 0x9b, 0xc0, 0x47, 0x55, 0x9d, 0xfd, 0xe3, 0xe7, 0xdc, 0x75, 0x96, 0x64, 0x26, 0x93, 0x49, 0x32, 0x49, 0x26, 0xdb, 0x64, 0x92, 0xc9, 0x9e, 0x90, 0x3d, 0x21, 0x09, 0x19, 0x02, 0x04, 0x48, 0xd8, 0x11, 0x30, 0x82, 0x22, 0xab, 0x68, 0x58, 0x02, 0x58, 0x15, 0xf1, 0x15, 0x11, 0x54, 0x40, 0xc4, 0x05, 0xb5, 0x0a, 0xa8, 0xb8, 0xe0, 0x06, 0x28, 0x88, 0xa8, 0x88, 0x5a, 0xb6, 0x57, 0x5b, 0xb1, 0xb5, 0xb6, 0x62, 0xad, 0xb5, 0xad, 0x5a, 0x6b, 0xdf, 0xd6, 0xda, 0xaa, 0xd5, 0xba, 0x90, 0xb9, 0xf3, 0x3f, 0xcf,\n\t0x39, 0xf7, 0xde, 0xb9, 0x77, 0x32, 0x09, 0x8b, 0xf4, 0x7d, 0x3f, 0xbf, 0xcf, 0xe7, 0x6f, 0x3f, 0x55, 0xf8, 0xce, 0xd9, 0xee, 0x39, 0xcf, 0x79, 0xce, 0xf7, 0x39, 0xcb, 0xf3, 0x54, 0xfb, 0xeb, 0xab, 0xfb, 0xc4, 0x2e, 0xaa, 0x3d, 0xdc, 0x39, 0x61, 0x47, 0x74, 0xe0, 0xa2, 0x3b, 0x5f, 0x84, 0xb0, 0x45, 0x89, 0x6e, 0x1a, 0xb6, 0x68, 0x2c, 0xc8, 0xc1, 0x15, 0xca, 0x46, 0x6e, 0x3e, 0x6d, 0xe3, 0xf8, 0xfd, 0x0e, 0x70, 0x19, 0xd0, 0xd1, 0xa7, 0x55, 0x40, 0xc3, 0xb4, 0x35, 0xce, 0xd0, 0x2a, 0xb6, 0x53, 0x49, 0x5b, 0x15, 0xf9, 0xbd, 0xeb, 0xf9, 0x7c, 0x9f, 0xdf, 0xd8, 0xaa, 0xe8, 0xc0, 0x26, 0xfb, 0x5b, 0x27, 0xdc, 0x3b, 0x28, 0x98, 0x53, 0xee, 0xb0, 0xa7, 0xcb, 0x5a, 0x9c, 0x92, 0x3b, 0xdf, 0x65, 0xb1, 0x47, 0x92, 0x5c, 0x91, 0xd8, 0x23, 0x57, 0x28, 0x5b, 0xb9, 0x95, 0xa7,\n\t0xd3, 0x77, 0xcc, 0x16, 0xe8, 0xdb, 0x77, 0x5a, 0xb7, 0xe9, 0x09, 0x62, 0xf7, 0x5d, 0x11, 0xae, 0xf7, 0xf5, 0xed, 0x3b, 0xfc, 0x96, 0xb2, 0x63, 0x02, 0xde, 0x7f, 0xaa, 0xee, 0x23, 0x63, 0xfc, 0x3a, 0x19, 0xe3, 0xff, 0x8d, 0x76, 0x56, 0xfb, 0x6b, 0x63, 0xb4, 0xf3, 0xad, 0x79, 0xd8, 0x79, 0x8a, 0x46, 0x12, 0xae, 0x43, 0x38, 0x81, 0xf0, 0x96, 0x78, 0x90, 0x0b, 0x88, 0x3f, 0xa1, 0x96, 0xdf, 0x53, 0x9c, 0x48, 0x79, 0x6a, 0x05, 0x51, 0x90, 0xdd, 0xe2, 0xab, 0x84, 0x3f, 0x75, 0x51, 0xfc, 0x19, 0x7e, 0x2e, 0xc3, 0x95, 0x95, 0x42, 0x9a, 0xf8, 0x82, 0x8e, 0xff, 0x37, 0xe7, 0xa3, 0x78, 0xb9, 0xb2, 0x52, 0x9c, 0x2c, 0xee, 0x23, 0xf8, 0x74, 0x15, 0xdf, 0xc5, 0xf0, 0xf0, 0xe7, 0xe2, 0xab, 0xb4, 0x9c, 0xe9, 0x6a, 0x39, 0x3f, 0xa1, 0x7a, 0xff, 0x24, 0x99, 0xb7, 0xb3, 0xc5, 0xfb,\n\t0x51, 0x01, 0xde, 0x83, 0x7f, 0x4f, 0xa3, 0x78, 0x3e, 0x16, 0xde, 0x4a, 0x63, 0x7d, 0x62, 0x53, 0xac, 0xcf, 0x69, 0xe1, 0x6f, 0xc5, 0x0b, 0x58, 0x3a, 0xae, 0x81, 0x40, 0x05, 0x24, 0xdd, 0x37, 0xdc, 0x21, 0x92, 0xfe, 0x09, 0x3e, 0x89, 0xee, 0xd2, 0xf4, 0x4d, 0xdf, 0x10, 0x33, 0xfd, 0x4e, 0xee, 0x64, 0x3f, 0xe9, 0xbb, 0x62, 0xa6, 0xdf, 0xc5, 0x8b, 0xfd, 0xa4, 0x9f, 0x10, 0x33, 0xfd, 0x53, 0x40, 0xfd, 0xfa, 0xa4, 0x9f, 0x42, 0xd2, 0xb7, 0x8b, 0x8f, 0xd0, 0xf4, 0x57, 0xd0, 0xf4, 0x4f, 0xa0, 0x24, 0xd6, 0x1e, 0xde, 0xda, 0x4f, 0xfa, 0x0b, 0x63, 0xa6, 0x7f, 0x8a, 0x77, 0xc4, 0x48, 0x3f, 0x9c, 0xa4, 0x5f, 0x4a, 0xf4, 0x1f, 0xa4, 0x5f, 0x4f, 0xd3, 0x3f, 0x89, 0x0a, 0xd4, 0xf4, 0xb9, 0x2c, 0xbd, 0x29, 0x76, 0xec, 0x54, 0x92, 0xfe, 0x7a, 0x35, 0xfd, 0x2c, 0x9a, 0x7e, 0x27,\n\t0x92, 0xd5, 0xef, 0x2d, 0x8f, 0x51, 0x3e, 0xa4, 0x5f, 0x11, 0x33, 0xfd, 0x53, 0x7c, 0x71, 0x8c, 0xf4, 0x33, 0x48, 0x7a, 0x81, 0xa5, 0xc7, 0x9f, 0xd1, 0xf4, 0xbb, 0x91, 0x8d, 0xa5, 0xe7, 0xf6, 0x47, 0xa7, 0x27, 0x7a, 0xa2, 0x4b, 0x79, 0x4c, 0xfc, 0x94, 0x70, 0x6d, 0x37, 0x0a, 0xa2, 0x6b, 0xb5, 0x30, 0x22, 0xea, 0xdb, 0xfa, 0x6e, 0x7d, 0x03, 0x9e, 0x46, 0x17, 0xa3, 0x92, 0xbf, 0x80, 0xfa, 0xfa, 0x8b, 0x8b, 0x9d, 0x6c, 0xa1, 0x29, 0xd9, 0x29, 0x0b, 0x82, 0x60, 0x10, 0x83, 0x1b, 0x0a, 0x93, 0x03, 0x70, 0x2c, 0x07, 0x21, 0x01, 0xa2, 0xe2, 0x76, 0x6a, 0xbe, 0xe8, 0xea, 0xd9, 0x55, 0xa6, 0x3a, 0x70, 0x10, 0x91, 0x92, 0x48, 0x6f, 0x3d, 0x41, 0x04, 0xa2, 0x14, 0x16, 0xa2, 0xc9, 0x83, 0xab, 0xda, 0xaf, 0x7f, 0x7e, 0xe9, 0xd2, 0xe7, 0x57, 0xb7, 0xb7, 0xaf, 0x86, 0xff, 0x5e,\n\t0xdf, 0xce, 0x1d, 0xcf, 0xb9, 0xb0, 0x76, 0xfa, 0xbc, 0x61, 0x75, 0xf7, 0x9e, 0x7c, 0x76, 0xce, 0x82, 0x83, 0x58, 0x7e, 0x60, 0x3b, 0x96, 0x5e, 0xba, 0xe4, 0xfc, 0xed, 0x1f, 0xdd, 0xec, 0xce, 0xcf, 0x4a, 0xac, 0x28, 0x48, 0xc9, 0x48, 0x8a, 0x13, 0xe3, 0x65, 0xee, 0x17, 0xab, 0x8f, 0x6f, 0xea, 0xec, 0xdc, 0x74, 0x7c, 0xf5, 0x75, 0x6f, 0x6c, 0x1a, 0x33, 0x66, 0xd3, 0x1b, 0x27, 0x37, 0x7a, 0x32, 0xc6, 0xb7, 0xd5, 0xce, 0x0c, 0x88, 0x3d, 0x87, 0xb1, 0xf5, 0xbe, 0xed, 0xd8, 0x71, 0x74, 0xd1, 0xa2, 0xa3, 0xca, 0x97, 0xdb, 0xef, 0xec, 0x7d, 0x65, 0x45, 0x82, 0x3d, 0x2b, 0xbf, 0xd8, 0xe3, 0x2f, 0x96, 0x65, 0x39, 0x9e, 0xce, 0xa1, 0x5d, 0xe1, 0xaf, 0xb8, 0x6c, 0xc2, 0x29, 0x03, 0xe8, 0x77, 0x74, 0x6e, 0xed, 0x0f, 0x9f, 0x47, 0xf5, 0x63, 0x0e, 0x99, 0x5b, 0x98, 0xfa, 0x84,\n\t0x6c, 0x0e, 0x36, 0x4a, 0x58, 0x80, 0xf7, 0x01, 0x02, 0x3f, 0xcb, 0x82, 0x39, 0x2b, 0x21, 0x77, 0xe0, 0x70, 0x04, 0x28, 0x82, 0x1d, 0xdb, 0x6c, 0x86, 0x3d, 0xa7, 0x64, 0x04, 0xb1, 0x89, 0xb4, 0x7f, 0xe2, 0xc8, 0x0a, 0x0e, 0x9b, 0x57, 0xfe, 0xda, 0xea, 0x5a, 0x35, 0xb2, 0x5f, 0xb2, 0x3f, 0x99, 0xfc, 0xdf, 0x25, 0xe0, 0xde, 0xd7, 0x77, 0x92, 0x7f, 0x4e, 0xbc, 0x49, 0xfe, 0xd9, 0xb7, 0x0f, 0x1f, 0xdb, 0xb2, 0x7c, 0x0b, 0x57, 0x19, 0x7a, 0x93, 0xfc, 0x87, 0xda, 0xb8, 0x08, 0xde, 0x55, 0x21, 0x41, 0x22, 0xf5, 0x67, 0xa2, 0xa1, 0xc1, 0x21, 0x4e, 0xb2, 0x70, 0x64, 0xf0, 0x70, 0x77, 0xb0, 0x83, 0xd0, 0x07, 0x35, 0xb6, 0x96, 0x40, 0x88, 0x98, 0x2c, 0xd0, 0x78, 0x9e, 0x73, 0xa8, 0xb1, 0x64, 0x68, 0x48, 0x26, 0xca, 0xcc, 0x4b, 0xcc, 0x75, 0x25, 0x25, 0xb9, 0xc0, 0x4e, 0x82,\n\t0x46, 0x10, 0x0a, 0x01, 0x5b, 0xbd, 0xf5, 0xa4, 0x15, 0x34, 0xda, 0x2e, 0xdb, 0x03, 0x2e, 0x70, 0x09, 0x52, 0xef, 0xeb, 0x99, 0xd9, 0x78, 0x63, 0x56, 0x6d, 0x47, 0xe9, 0x89, 0x9c, 0xb4, 0x82, 0x12, 0xbc, 0x21, 0xbb, 0x61, 0xdc, 0xa0, 0x1c, 0xdf, 0xbe, 0x7d, 0xdc, 0x3b, 0x62, 0x71, 0xa0, 0x72, 0x62, 0xb3, 0x9f, 0xe7, 0xea, 0x43, 0xd7, 0x26, 0x14, 0x95, 0x55, 0x9f, 0xd7, 0xec, 0xb3, 0x2b, 0xa5, 0x54, 0xe6, 0xc6, 0x2b, 0x8f, 0x09, 0x3e, 0xc1, 0x42, 0xd8, 0x53, 0x03, 0xda, 0xa0, 0x9e, 0xc1, 0x69, 0xa2, 0xb2, 0xd8, 0x20, 0x4c, 0x40, 0xa5, 0x0c, 0x42, 0x97, 0x1a, 0x3b, 0xdd, 0x12, 0x73, 0xba, 0x60, 0x01, 0x92, 0x78, 0x91, 0x87, 0x70, 0x79, 0x31, 0x92, 0x9a, 0xa5, 0x2f, 0xae, 0xbe, 0xb6, 0x6a, 0x50, 0x61, 0x72, 0x5e, 0x5e, 0xae, 0xac, 0x85, 0xa4, 0x50, 0xf7, 0x46, 0x0d,\n\t0xb2, 0xc7, 0x9b, 0x82, 0x52, 0x98, 0x04, 0x2f, 0xf5, 0xd6, 0x3b, 0x6e, 0xdf, 0xb4, 0xe9, 0xf6, 0x3b, 0x6e, 0xc5, 0x5f, 0x65, 0x5f, 0x54, 0x43, 0x04, 0xae, 0xe1, 0xd2, 0xc7, 0xaf, 0x6c, 0x1d, 0xb1, 0x6a, 0xff, 0xd2, 0x9e, 0xfd, 0xab, 0x86, 0xd7, 0xcd, 0xbb, 0x7d, 0x7a, 0x52, 0x20, 0xc7, 0x4d, 0xc4, 0x2d, 0xd3, 0x1d, 0x27, 0x3a, 0x45, 0xdc, 0xbb, 0xe7, 0xc8, 0x91, 0x3d, 0x7b, 0x8e, 0x1e, 0xed, 0x2d, 0x07, 0x31, 0xab, 0x9b, 0x19, 0x90, 0xc6, 0xdd, 0x74, 0xf0, 0xf2, 0xab, 0x0e, 0xaf, 0x1f, 0x3d, 0x7a, 0xfd, 0xe1, 0xab, 0xba, 0xf7, 0xae, 0x3d, 0xcf, 0x69, 0xcf, 0xce, 0x2f, 0x49, 0xd5, 0x64, 0x0c, 0x7c, 0x92, 0x2a, 0x5f, 0x73, 0xcf, 0x84, 0x2f, 0x1f, 0xe8, 0x7e, 0x9a, 0x47, 0xf3, 0x49, 0xba, 0x51, 0xdd, 0xc3, 0xfe, 0x44, 0x79, 0x90, 0xbb, 0x21, 0x7c, 0x98, 0xed, 0x95,\n\t0xe8, 0x7e, 0x4b, 0x16, 0x80, 0xdf, 0x12, 0x76, 0x54, 0x01, 0x7e, 0x4b, 0x44, 0xfd, 0x0a, 0x07, 0x7e, 0x40, 0xbd, 0xbe, 0xe1, 0xfc, 0xac, 0x55, 0xbd, 0xb8, 0xc1, 0xca, 0x39, 0xa6, 0x3c, 0xc4, 0x2d, 0x08, 0xc3, 0xfd, 0x10, 0xe6, 0x13, 0x9f, 0x91, 0x8e, 0x05, 0x54, 0x4a, 0xe0, 0xca, 0x09, 0x9c, 0x1c, 0x89, 0xfa, 0x95, 0x13, 0x6e, 0x81, 0x7e, 0xdd, 0x64, 0x88, 0x7a, 0xcf, 0x04, 0xec, 0x08, 0xa5, 0x03, 0xb7, 0xd2, 0x93, 0x26, 0xd5, 0x96, 0xe9, 0x62, 0x5e, 0x7e, 0x58, 0xd3, 0x9b, 0xb0, 0xcb, 0xff, 0xcc, 0x2d, 0xb7, 0x28, 0x1d, 0x54, 0x77, 0xed, 0x55, 0xe2, 0xc4, 0xbb, 0xc5, 0x6d, 0x64, 0xad, 0x82, 0xb0, 0x12, 0x32, 0x27, 0xa0, 0xdf, 0x7c, 0x77, 0x90, 0x68, 0x2c, 0x0e, 0xbf, 0xf0, 0xdd, 0x41, 0x75, 0x6f, 0x60, 0x92, 0x12, 0xc7, 0xbf, 0x2f, 0x1e, 0x23, 0x69, 0xea, 0xd5,\n\t0x34, 0x37, 0xf5, 0x49, 0x33, 0x57, 0x79, 0x9d, 0x3b, 0x10, 0x7e, 0x8a, 0x97, 0xd1, 0xbe, 0x70, 0xef, 0xf7, 0xd9, 0xec, 0x24, 0xe1, 0xfb, 0x6c, 0x4d, 0xe7, 0x85, 0xef, 0x0e, 0x7f, 0x29, 0x24, 0x8a, 0xc7, 0x50, 0x1c, 0xb1, 0x6d, 0xbf, 0x50, 0x03, 0x56, 0xd6, 0x61, 0xab, 0x9c, 0x87, 0x25, 0x31, 0x3e, 0x0e, 0x6e, 0xc5, 0x43, 0x28, 0x31, 0xa1, 0x63, 0x18, 0xe1, 0xdc, 0xa3, 0xbd, 0x7d, 0x7f, 0x13, 0xb4, 0xdf, 0xd4, 0x48, 0x90, 0x65, 0x70, 0x55, 0x57, 0x94, 0x64, 0x71, 0x0e, 0xb2, 0xda, 0xb1, 0xc4, 0x59, 0x25, 0xf0, 0x07, 0x37, 0xaf, 0x53, 0xf5, 0x91, 0xcd, 0xa9, 0x02, 0x08, 0xec, 0x82, 0x45, 0xa2, 0xca, 0x3d, 0xb3, 0x4c, 0x34, 0x3a, 0x55, 0xe5, 0xa9, 0xd3, 0x0b, 0x42, 0xe4, 0xc8, 0x94, 0x45, 0xad, 0x4a, 0x6c, 0x0b, 0x36, 0x37, 0x35, 0xd6, 0x27, 0xd6, 0x24, 0x26, 0x05,\n\t0x0a, 0xf3, 0xf3, 0x72, 0xa9, 0x5a, 0xc9, 0xc2, 0xba, 0x98, 0xcb, 0xb5, 0x51, 0xb1, 0x77, 0x64, 0xa9, 0x04, 0xbb, 0x68, 0xa8, 0x48, 0xf5, 0x74, 0x27, 0xc5, 0x53, 0x5b, 0x9d, 0x6c, 0x9c, 0xf5, 0xb8, 0x73, 0x50, 0x4f, 0xdb, 0xba, 0xcd, 0xd7, 0x5f, 0x79, 0xde, 0xca, 0xda, 0xd6, 0xed, 0xf3, 0xbb, 0x6e, 0x9d, 0x5b, 0xd7, 0xb2, 0xf4, 0xa1, 0x79, 0x95, 0x93, 0x46, 0x0c, 0x4e, 0xb7, 0x5a, 0x8a, 0xaf, 0x15, 0x6d, 0x62, 0xa0, 0x04, 0x6f, 0xcc, 0x69, 0x1c, 0x57, 0x61, 0x89, 0x97, 0x8f, 0x26, 0x26, 0x68, 0x6a, 0xc1, 0xed, 0xf9, 0xbe, 0xb5, 0xea, 0xc8, 0xb1, 0xfd, 0x4f, 0x8c, 0x69, 0xbf, 0xbd, 0x7d, 0xea, 0x88, 0xd5, 0x2f, 0x5c, 0xbe, 0xf2, 0xf5, 0xdb, 0xc6, 0xbb, 0xf3, 0x6a, 0x7c, 0x53, 0x8a, 0x84, 0xa7, 0x30, 0x2e, 0x29, 0x05, 0x1d, 0x81, 0xf1, 0xfa, 0xf7, 0x25, 0xa6, 0x2e,\n\t0x44, 0x1a, 0xb3, 0x93, 0x8c, 0xd5, 0x9b, 0x64, 0xac, 0x1c, 0xa8, 0x0d, 0x6d, 0x0d, 0x26, 0xb7, 0x0c, 0xe6, 0x6c, 0x96, 0x32, 0xcc, 0x49, 0xa5, 0x18, 0x89, 0x19, 0x34, 0x30, 0xa7, 0xa0, 0xb2, 0xe2, 0xf2, 0x38, 0x3b, 0x67, 0x41, 0x12, 0x67, 0x21, 0x1d, 0x63, 0x93, 0x89, 0xb1, 0x64, 0xe3, 0xe0, 0x7d, 0xc8, 0x3c, 0xe8, 0x12, 0xea, 0x5d, 0x85, 0x06, 0xcb, 0x64, 0x3d, 0x4a, 0x03, 0x91, 0x56, 0x9d, 0x46, 0x06, 0x88, 0x6f, 0xaa, 0xe9, 0x11, 0x08, 0x7d, 0x15, 0x4c, 0x71, 0x3a, 0x9d, 0x6d, 0xce, 0xb6, 0x60, 0x6b, 0x73, 0x53, 0x5e, 0x62, 0x5e, 0x61, 0x5e, 0x6e, 0x7d, 0x20, 0x37, 0xbe, 0x4f, 0x7c, 0x4d, 0xac, 0xb2, 0x41, 0x97, 0x3f, 0xb7, 0x02, 0x9b, 0xc3, 0x68, 0xba, 0x02, 0x91, 0xce, 0xd5, 0xfb, 0xd6, 0x1c, 0x5b, 0x13, 0x3f, 0x0f, 0xfd, 0x65, 0x71, 0x58, 0xae, 0x28, 0xb2,\n\t0xb9, 0xcc, 0x71, 0x34, 0x13, 0xe3, 0xb5, 0xce, 0x4d, 0x71, 0x1d, 0xb3, 0xc5, 0x91, 0xbe, 0x35, 0x46, 0xd6, 0x14, 0x52, 0x59, 0x17, 0x9e, 0x7c, 0xb2, 0xe0, 0x47, 0xc6, 0x38, 0x9a, 0xd8, 0x2d, 0xb2, 0xde, 0x15, 0x6e, 0xfe, 0x23, 0x5f, 0x54, 0x46, 0xe7, 0x1a, 0x91, 0x93, 0xbf, 0xd0, 0xfd, 0x80, 0x64, 0x1a, 0xaf, 0xf9, 0x30, 0xbe, 0x33, 0xf4, 0x1b, 0xc6, 0x0e, 0x42, 0xbf, 0x51, 0xe7, 0xd1, 0xb5, 0xe1, 0xcf, 0xf9, 0x77, 0xc4, 0x5b, 0xc9, 0x5c, 0xbb, 0x91, 0xae, 0x6f, 0xfb, 0xd0, 0x76, 0xaa, 0x17, 0x2a, 0x95, 0x47, 0xf9, 0x41, 0x44, 0x7f, 0x77, 0xa1, 0x47, 0x83, 0xe9, 0xf5, 0x58, 0xb2, 0x0c, 0x27, 0x36, 0xaa, 0x9b, 0xb4, 0x64, 0x0c, 0x06, 0xbf, 0xbf, 0x08, 0x4f, 0xc3, 0x56, 0x24, 0xa9, 0x4e, 0x68, 0xeb, 0x11, 0x31, 0x09, 0x25, 0x78, 0xa8, 0x40, 0xd6, 0x40, 0x81, 0xe3,\n\t0x7b, 0xc0, 0x80, 0x25, 0x36, 0xff, 0x1c, 0x62, 0xe1, 0xd3, 0xd7, 0xaa, 0xb9, 0x9d, 0x5a, 0x48, 0x47, 0x9f, 0x1e, 0xd7, 0x34, 0x93, 0x5e, 0x86, 0x3f, 0xfd, 0x9c, 0x7e, 0x63, 0xce, 0xae, 0xa0, 0x63, 0xca, 0xe4, 0x7c, 0x7f, 0xc0, 0x17, 0xf0, 0x07, 0x46, 0xe4, 0xd9, 0xa4, 0xcc, 0xc8, 0xa5, 0x81, 0x40, 0x81, 0x94, 0xab, 0xfb, 0x52, 0xd4, 0xdf, 0x2e, 0x30, 0xb3, 0x58, 0xa3, 0x1d, 0xf4, 0xd0, 0x36, 0x32, 0x2d, 0xd4, 0x50, 0x4c, 0x7a, 0x44, 0x26, 0x7a, 0xd5, 0x60, 0xa8, 0x7a, 0xd5, 0x20, 0xab, 0x40, 0xb2, 0x8b, 0x83, 0xe6, 0xcd, 0x3e, 0xdf, 0xdf, 0x10, 0x9f, 0xea, 0x2e, 0x6a, 0x9a, 0x3c, 0xa4, 0x76, 0x72, 0x63, 0xd6, 0x15, 0x2b, 0x97, 0x2f, 0x5f, 0x78, 0x55, 0x7a, 0xed, 0xf8, 0x9a, 0xc1, 0x13, 0x1a, 0xf2, 0xe3, 0x1d, 0x6e, 0x7b, 0x59, 0xe3, 0xa3, 0x97, 0x5f, 0xb8, 0x69,\n\t0x56, 0xa5, 0xbb, 0x78, 0x44, 0xf5, 0x45, 0x8b, 0x4b, 0xc7, 0x2e, 0x68, 0x6e, 0x18, 0xa2, 0xdf, 0x4e, 0x78, 0x8b, 0xde, 0x4e, 0xf0, 0x37, 0x3b, 0x70, 0x62, 0xa0, 0xb9, 0x64, 0x54, 0x62, 0x76, 0x5e, 0x76, 0x7a, 0xf9, 0x90, 0xfc, 0x51, 0x53, 0xaf, 0x9f, 0x18, 0xcc, 0xa8, 0x2e, 0x48, 0xf1, 0x64, 0x78, 0xec, 0xae, 0xce, 0xba, 0xe1, 0x65, 0x9d, 0x17, 0xd7, 0x64, 0x0d, 0x6d, 0xae, 0x76, 0x65, 0x5e, 0x7b, 0xd1, 0xe0, 0x59, 0x9d, 0x35, 0x71, 0x69, 0x93, 0xab, 0xf5, 0xab, 0x0c, 0xf4, 0xc8, 0x81, 0x8c, 0xcb, 0x6d, 0x64, 0x5c, 0x86, 0xa3, 0xf5, 0xc1, 0xc4, 0x62, 0x2c, 0x92, 0xce, 0xe1, 0x24, 0x08, 0x8f, 0xe7, 0x80, 0xa0, 0x1f, 0xea, 0x78, 0x94, 0x23, 0x41, 0x94, 0x45, 0x41, 0xee, 0x81, 0xde, 0x95, 0x25, 0xd8, 0x72, 0xa1, 0x0a, 0x23, 0x17, 0xb6, 0x5c, 0xa8, 0x26, 0xf1, 0x75,\n\t0x6a, 0x97, 0x65, 0x33, 0x11, 0x0d, 0xf0, 0x7e, 0xaa, 0x0c, 0x7e, 0x63, 0x86, 0xae, 0xa0, 0xdd, 0x5f, 0xe8, 0xcf, 0x2f, 0xcc, 0x2f, 0x2a, 0xb6, 0x48, 0x19, 0x10, 0x73, 0xd3, 0xd4, 0x75, 0xd5, 0x91, 0xa1, 0x30, 0xce, 0x0a, 0x53, 0x14, 0x4e, 0x2d, 0xf8, 0xa6, 0x87, 0xbf, 0xad, 0xf6, 0x96, 0x09, 0x75, 0x83, 0xf5, 0x9e, 0x72, 0x6a, 0xdd, 0x1e, 0x88, 0x9f, 0xb9, 0x63, 0x45, 0x7b, 0xeb, 0xca, 0x67, 0x2f, 0x5f, 0xf4, 0xe8, 0xd0, 0x1a, 0xab, 0x0b, 0x9e, 0x7d, 0x74, 0xd6, 0x8f, 0x5a, 0x3c, 0x3a, 0x50, 0xd8, 0x71, 0xd9, 0xd0, 0xd6, 0x49, 0x75, 0x79, 0xee, 0xd4, 0xf8, 0xdb, 0x87, 0x8e, 0x74, 0xa4, 0x4d, 0xaa, 0xd4, 0xba, 0x88, 0xf5, 0x72, 0x93, 0xa3, 0xfd, 0xc6, 0xa3, 0xd7, 0x2c, 0x3d, 0x74, 0xf3, 0xf8, 0xf6, 0xe0, 0x28, 0x7b, 0x7c, 0x5a, 0x66, 0x5a, 0xcd, 0xc5, 0x1b, 0xa6,\n\t0x76, 0xdd, 0x3c, 0xb3, 0x12, 0x22, 0x6d, 0x22, 0x75, 0x1d, 0x7a, 0x84, 0x7b, 0x5d, 0xc2, 0x84, 0x3b, 0x8f, 0xc4, 0x10, 0x8d, 0x99, 0x1e, 0x34, 0x10, 0x5c, 0x8d, 0x31, 0xc4, 0x49, 0x62, 0x35, 0xe3, 0xfe, 0xca, 0x30, 0xfe, 0xfc, 0xf0, 0x76, 0x14, 0xc0, 0x63, 0x71, 0x0b, 0x61, 0xd8, 0x63, 0x89, 0xcd, 0x39, 0x1b, 0xb9, 0x60, 0x3f, 0xbe, 0x85, 0x6d, 0x6d, 0xbf, 0x10, 0x9e, 0xad, 0xce, 0xa5, 0xa3, 0xfc, 0xcf, 0xc5, 0x5c, 0xa9, 0x03, 0x05, 0xf8, 0xeb, 0x61, 0x2e, 0xf1, 0x6b, 0xf0, 0x0d, 0xb4, 0x8c, 0x06, 0x49, 0x12, 0xde, 0x97, 0xb6, 0x20, 0x19, 0xf7, 0x72, 0x1b, 0x58, 0x1c, 0x6e, 0xb4, 0x21, 0xfc, 0x05, 0x9f, 0x05, 0x73, 0x13, 0xd3, 0x58, 0x42, 0xb8, 0x06, 0x6f, 0xa4, 0xe3, 0x1b, 0x50, 0x1e, 0x15, 0xfc, 0xe2, 0x4e, 0x74, 0x3e, 0x7a, 0x32, 0x98, 0x42, 0xd6, 0x00, 0xb9,\n\t0x0a, 0x8b, 0x42, 0x32, 0xe6, 0x45, 0x3f, 0x21, 0x76, 0x39, 0xe0, 0xe3, 0x4e, 0x9f, 0x73, 0x56, 0x8b, 0x6c, 0xb1, 0xca, 0x40, 0xf4, 0x44, 0x49, 0x10, 0xe1, 0xb1, 0x90, 0x24, 0xc8, 0x74, 0xc5, 0xa0, 0xe3, 0x94, 0xd3, 0xa9, 0x8d, 0xa2, 0x4f, 0xdf, 0x0e, 0xce, 0xc4, 0x74, 0xce, 0x9d, 0x76, 0x4e, 0xbf, 0x31, 0x27, 0x51, 0x8c, 0x53, 0xcf, 0x9b, 0x38, 0x7e, 0xe4, 0x88, 0xe1, 0x6d, 0xcd, 0x83, 0xeb, 0x6b, 0x07, 0x95, 0x17, 0x15, 0x64, 0x65, 0xe4, 0xda, 0xa4, 0xe4, 0x12, 0xb7, 0x36, 0x95, 0x24, 0x59, 0xf5, 0x45, 0xd8, 0xaf, 0x38, 0x18, 0xf6, 0xf2, 0xe8, 0x6c, 0x94, 0x09, 0xf3, 0x35, 0xd8, 0x03, 0x90, 0xe0, 0xa2, 0x49, 0xbf, 0x5b, 0xdf, 0xf3, 0xec, 0xb5, 0xc3, 0x2f, 0xb9, 0x18, 0x1c, 0x01, 0x37, 0x74, 0xdf, 0x37, 0xaf, 0xa6, 0x31, 0x86, 0x78, 0x58, 0xb6, 0xf4, 0x9e, 0xdf,\n\t0x62, 0x49, 0x77, 0xa6, 0x34, 0x5f, 0xb0, 0x6a, 0xfa, 0xbd, 0x8f, 0x97, 0x4c, 0x58, 0x36, 0xea, 0xd5, 0x83, 0x10, 0x6c, 0xb4, 0x60, 0x74, 0xf7, 0xf0, 0xf1, 0x4b, 0xc6, 0x55, 0x27, 0xba, 0x52, 0x6c, 0x62, 0xca, 0xa8, 0xb1, 0xf5, 0xb3, 0xd7, 0x4d, 0xbc, 0xec, 0xe1, 0x41, 0xa9, 0x6d, 0x93, 0x67, 0xd5, 0x9d, 0x77, 0xf7, 0x95, 0x13, 0x1c, 0x69, 0x13, 0x07, 0x45, 0x0b, 0xcc, 0xfc, 0xa9, 0xf3, 0xe3, 0x12, 0x4a, 0x6b, 0x4b, 0x6f, 0xbe, 0xae, 0xee, 0x82, 0xa0, 0x1f, 0x3f, 0x9d, 0x59, 0x3f, 0xb1, 0xa6, 0x62, 0x5c, 0x7d, 0xb6, 0xaf, 0xc8, 0x97, 0xe0, 0x82, 0x71, 0xb9, 0x40, 0x79, 0x94, 0xd4, 0xbd, 0x0b, 0xb5, 0xe3, 0x92, 0xa0, 0xb3, 0x88, 0xcc, 0x3b, 0x17, 0x1c, 0xef, 0xc2, 0xa4, 0xd3, 0xe2, 0xed, 0xf5, 0x37, 0x87, 0x72, 0x62, 0xcf, 0x21, 0xef, 0xc0, 0x53, 0x35, 0xa7, 0x9f,\n\t0xa9, 0xca, 0x28, 0xf2, 0x99, 0xd7, 0x95, 0x7e, 0x16, 0x75, 0x9d, 0x69, 0x35, 0x5d, 0xe0, 0x1b, 0xd7, 0x1e, 0x00, 0xcd, 0x90, 0x7c, 0x4a, 0xcd, 0x10, 0xb1, 0xf7, 0x62, 0x6a, 0x06, 0x2a, 0x25, 0x1e, 0xd1, 0x39, 0xee, 0xbd, 0xbb, 0xca, 0xab, 0xfa, 0x8c, 0x7e, 0x46, 0xde, 0x5d, 0x5f, 0x3c, 0x79, 0xe1, 0x25, 0x2f, 0x62, 0xfe, 0xbe, 0x7b, 0xff, 0x71, 0x7e, 0xbb, 0x9c, 0xec, 0x72, 0x57, 0x4f, 0xbe, 0x7a, 0x7a, 0xf7, 0x33, 0xab, 0x47, 0x76, 0x5c, 0xbf, 0x67, 0xfe, 0x90, 0x39, 0x93, 0x3b, 0xf2, 0x2c, 0x89, 0xb6, 0xc4, 0xf8, 0xd7, 0x2f, 0x5c, 0x62, 0x4f, 0x1f, 0x5b, 0x66, 0x1a, 0xee, 0xdc, 0xc1, 0x4e, 0x89, 0x98, 0x7e, 0x96, 0xfb, 0x1f, 0xc2, 0x8e, 0x23, 0x0b, 0xe7, 0x4e, 0x9e, 0x63, 0x77, 0x04, 0x2a, 0x02, 0x9d, 0xb7, 0xfc, 0x7c, 0xf5, 0x9a, 0x37, 0x36, 0x75, 0x38, 0xb3,\n\t0x2a, 0x7c, 0xb2, 0xd5, 0x01, 0x73, 0x74, 0x7c, 0xf8, 0x4b, 0xd0, 0xb5, 0x64, 0x6d, 0xac, 0x64, 0xeb, 0x27, 0xda, 0xdb, 0xfb, 0x2b, 0xb6, 0x7e, 0xf6, 0xfe, 0x4a, 0x9d, 0xf3, 0x65, 0x24, 0xcd, 0x62, 0xa2, 0x8f, 0x03, 0xdc, 0x9e, 0xef, 0xd9, 0xbd, 0xb1, 0x6f, 0xfa, 0xa4, 0xb9, 0x20, 0xfc, 0x39, 0x95, 0x9d, 0x00, 0x58, 0x6d, 0x74, 0x1d, 0xbe, 0x25, 0xb4, 0x5f, 0x5d, 0x87, 0xf7, 0x47, 0x9d, 0x87, 0x05, 0xe0, 0x3c, 0x8c, 0xd6, 0xb5, 0xab, 0x4f, 0x9a, 0xbb, 0xf0, 0x4f, 0xf0, 0x36, 0xa2, 0x1b, 0x0a, 0xf0, 0x60, 0x54, 0x8a, 0x7f, 0x41, 0xb4, 0x11, 0xf9, 0xaf, 0xf0, 0x0c, 0x4a, 0xa4, 0xb7, 0x68, 0xd4, 0xe3, 0xc1, 0x17, 0x84, 0x67, 0x28, 0x09, 0x26, 0xe9, 0x7d, 0xdc, 0x36, 0xde, 0xca, 0xef, 0xe6, 0x65, 0x71, 0x3b, 0x5a, 0xdd, 0x7b, 0x07, 0xbb, 0xf1, 0xd6, 0x7b, 0x87, 0xbe,\n\t0x8f, 0x00, 0x9e, 0xd9, 0x2b, 0xb8, 0x6f, 0x78, 0x99, 0x27, 0x6b, 0x7f, 0xc8, 0xc5, 0x38, 0x74, 0xc8, 0xa5, 0xff, 0x3e, 0x0b, 0xaf, 0xc0, 0x83, 0xb8, 0x7f, 0x93, 0xdf, 0x89, 0x1e, 0x0b, 0x25, 0xa8, 0xbf, 0x27, 0xa8, 0x1c, 0x1b, 0xa3, 0x46, 0xe5, 0x7a, 0xfe, 0x6a, 0xf2, 0xed, 0x41, 0x74, 0x2c, 0x68, 0xcf, 0x77, 0x71, 0x58, 0xca, 0x20, 0x26, 0xa8, 0x16, 0x58, 0xb1, 0x02, 0x59, 0x64, 0x51, 0xb6, 0xc0, 0xeb, 0x45, 0xb2, 0xc0, 0x13, 0xe1, 0x21, 0x16, 0xa8, 0xea, 0xed, 0x46, 0x92, 0x58, 0x7c, 0x45, 0xf3, 0xd6, 0x26, 0xa3, 0x78, 0xa7, 0xce, 0xb6, 0x24, 0x6a, 0x47, 0xb4, 0x2e, 0x3a, 0x87, 0xf6, 0x1c, 0x3c, 0x46, 0x4e, 0xe3, 0x56, 0x29, 0xb1, 0x0d, 0xc9, 0x2a, 0x56, 0x94, 0xef, 0x23, 0x14, 0xcf, 0x4a, 0xe8, 0x9d, 0x3b, 0x12, 0xb8, 0x93, 0x70, 0xe0, 0xe4, 0x18, 0xc1, 0xd2,\n\t0xfb, 0x44, 0xad, 0xa4, 0x29, 0x1b, 0xfd, 0xd3, 0x66, 0x77, 0xd7, 0x6b, 0x8b, 0xd5, 0x85, 0x63, 0xa2, 0xc3, 0x40, 0xe3, 0xfe, 0x16, 0x2f, 0xfe, 0xd2, 0xe2, 0x96, 0x40, 0x62, 0xfb, 0x4d, 0x64, 0xad, 0xfa, 0xc9, 0xc6, 0x71, 0xe9, 0x17, 0x18, 0x23, 0x40, 0x3f, 0x87, 0x47, 0xc6, 0xb1, 0x95, 0x6b, 0x3d, 0xac, 0x5c, 0x55, 0x6c, 0xe5, 0xc2, 0xa8, 0x96, 0x70, 0x3a, 0x51, 0xdc, 0x87, 0x9a, 0xd1, 0x8c, 0x60, 0x57, 0x76, 0x16, 0xa1, 0x4a, 0x09, 0x98, 0x93, 0xcb, 0x9d, 0x9c, 0x85, 0xe3, 0x3b, 0x9a, 0x30, 0xc6, 0xa3, 0xc1, 0x81, 0x01, 0xdc, 0x8e, 0x9a, 0x8b, 0x2c, 0x36, 0x8c, 0xed, 0x16, 0xac, 0x3b, 0x23, 0xed, 0x86, 0x07, 0x6b, 0x7c, 0x17, 0x7b, 0xbb, 0x16, 0x87, 0xed, 0xf6, 0xb9, 0x76, 0x30, 0xf3, 0x9a, 0x51, 0xf3, 0xe0, 0x86, 0x9a, 0xea, 0x5c, 0x57, 0x72, 0x6d, 0x7e, 0x5a,\n\t0x52, 0x62, 0x25, 0x50, 0x5d, 0x9f, 0x91, 0xc2, 0x12, 0xfb, 0xa0, 0x9f, 0x83, 0xc0, 0x64, 0x9f, 0x79, 0xb7, 0x00, 0xe7, 0x46, 0x2c, 0x03, 0xc9, 0x2e, 0xb1, 0x03, 0xc0, 0x35, 0xc4, 0x6c, 0x10, 0x22, 0x07, 0x80, 0x99, 0xca, 0x5f, 0x93, 0x5d, 0x9a, 0xc1, 0xe0, 0xf1, 0xe0, 0x2f, 0x38, 0xcd, 0x2a, 0x78, 0x8f, 0x9e, 0xfd, 0xcd, 0xa0, 0x67, 0x7f, 0xb3, 0xe3, 0xd5, 0xb3, 0xbf, 0xa9, 0x9b, 0x94, 0x5f, 0x5b, 0x54, 0x63, 0x41, 0x99, 0x4b, 0xad, 0x4c, 0x3f, 0x59, 0x30, 0x6f, 0x24, 0x72, 0x17, 0x87, 0x3c, 0x68, 0x34, 0x4e, 0xec, 0xdc, 0xe3, 0x86, 0x18, 0x5d, 0x75, 0x18, 0xdb, 0x9a, 0x3d, 0x64, 0xb9, 0xaa, 0x4c, 0x00, 0x4f, 0x19, 0x23, 0x4b, 0x38, 0x24, 0xe7, 0xe7, 0x7a, 0x79, 0x11, 0x89, 0x1d, 0xde, 0x60, 0x6e, 0xe4, 0x67, 0x1c, 0xcf, 0x25, 0x20, 0x4e, 0x8e, 0x57, 0x53, 0x70,\n\t0x56, 0xe4, 0xc5, 0xa2, 0x55, 0x86, 0xbd, 0x62, 0x28, 0xa8, 0xd0, 0x11, 0xcf, 0x91, 0x1f, 0x48, 0x8a, 0x39, 0x84, 0x6f, 0x62, 0x1a, 0xd6, 0x13, 0x8e, 0x0b, 0x6d, 0xd3, 0x89, 0x2d, 0x61, 0xb3, 0xcd, 0xef, 0xb4, 0x48, 0x1c, 0x0b, 0x81, 0xc9, 0xae, 0xac, 0xd4, 0x39, 0x48, 0x81, 0x32, 0x17, 0x2f, 0x43, 0x18, 0x73, 0x11, 0x59, 0x81, 0xcb, 0x6a, 0xd9, 0xd1, 0x00, 0xb9, 0x83, 0x83, 0x4f, 0x99, 0x11, 0x41, 0x06, 0xc8, 0x6d, 0x9f, 0x0e, 0xc3, 0xb5, 0x58, 0xcf, 0x0c, 0xc1, 0xe6, 0x53, 0x53, 0x53, 0x47, 0xa7, 0x8e, 0x6e, 0x0b, 0x92, 0xb1, 0xab, 0x2a, 0x2f, 0x73, 0xb9, 0xdd, 0x3e, 0x4f, 0x7e, 0xb2, 0x3f, 0xd1, 0x09, 0x86, 0x4a, 0x16, 0x8c, 0x15, 0xbb, 0x33, 0x48, 0x4c, 0x41, 0x8f, 0x6a, 0x08, 0x8a, 0x64, 0x7d, 0x06, 0xdf, 0xc1, 0xd4, 0x68, 0x21, 0x16, 0x20, 0xfc, 0x1b, 0xde,\n\t0x25, 0xd5, 0xd5, 0xbb, 0x20, 0x0a, 0x3a, 0xdd, 0xd5, 0xf6, 0xb0, 0x49, 0x90, 0x89, 0xeb, 0x6a, 0x85, 0xe6, 0x8b, 0x8e, 0xf5, 0xcc, 0x99, 0x59, 0x3c, 0xa6, 0xd1, 0x17, 0xda, 0xb9, 0xec, 0xd8, 0xf4, 0x8b, 0xa6, 0xb7, 0x2e, 0x2c, 0x13, 0x1f, 0xb8, 0xf2, 0xbf, 0x8e, 0x09, 0x4b, 0x8f, 0x4c, 0x3f, 0x76, 0xd1, 0xd1, 0x9e, 0xa3, 0x0b, 0xee, 0xbd, 0x76, 0xcd, 0x8f, 0x8a, 0x6c, 0x8e, 0x86, 0xf5, 0x33, 0xe6, 0x5d, 0x9b, 0x99, 0xd2, 0x3e, 0x75, 0x56, 0xd5, 0xc4, 0x55, 0xe7, 0x97, 0x4f, 0xe7, 0xf2, 0xb2, 0x4b, 0x9f, 0x5a, 0x76, 0x79, 0xe6, 0xe0, 0xa9, 0x8d, 0x7e, 0x5c, 0x98, 0xe9, 0xbf, 0xa2, 0xa7, 0xad, 0x71, 0xee, 0x15, 0xf7, 0xe5, 0x2a, 0x8f, 0xe1, 0xb6, 0x40, 0x86, 0x72, 0x0d, 0x3e, 0x96, 0x5d, 0xc6, 0x85, 0xfe, 0x81, 0xbf, 0x2d, 0x5a, 0xb6, 0x62, 0x7b, 0x0e, 0x9e, 0x5d,\n\t0x30, 0x6b, 0xd8, 0x94, 0x25, 0x33, 0xeb, 0xc6, 0x55, 0xa5, 0x56, 0xcf, 0xbe, 0x6d, 0xc6, 0xa6, 0x92, 0xcb, 0x60, 0x9c, 0xc3, 0x3f, 0x56, 0x76, 0x0a, 0x6e, 0xc1, 0x4e, 0xec, 0xc2, 0x54, 0xd4, 0x8e, 0x7e, 0x13, 0x4c, 0xa2, 0xde, 0x7c, 0x13, 0x89, 0xfd, 0xe1, 0x26, 0x3c, 0xa8, 0x7a, 0x10, 0x27, 0x59, 0x04, 0x6d, 0xf1, 0xb5, 0xc5, 0x71, 0x3c, 0xb2, 0x48, 0xbc, 0x65, 0x0e, 0xe2, 0xac, 0x84, 0x36, 0x71, 0xd2, 0x1c, 0x6a, 0xd3, 0xd9, 0xb1, 0xba, 0x39, 0x44, 0xad, 0xbd, 0x85, 0x30, 0x03, 0x16, 0xc8, 0xfa, 0x82, 0x78, 0x7a, 0xb9, 0x96, 0x68, 0xb9, 0x82, 0x55, 0xb1, 0x32, 0xd8, 0xed, 0xf3, 0x3b, 0x4d, 0xfb, 0x50, 0xa6, 0x4c, 0x64, 0xa8, 0x32, 0x9c, 0xce, 0x11, 0xc3, 0x86, 0x0e, 0x19, 0xdc, 0x58, 0x5f, 0x57, 0x55, 0x59, 0x51, 0x56, 0x58, 0x90, 0x9d, 0xe9, 0x4c, 0x75, 0xa6,\n\t0x16, 0x82, 0x55, 0xe9, 0xd1, 0x6d, 0x75, 0x76, 0xdf, 0xd2, 0x4d, 0x86, 0x45, 0xb5, 0x17, 0x23, 0xea, 0xa8, 0x04, 0xc3, 0x8c, 0x2b, 0x48, 0xf6, 0xd7, 0x9a, 0xcd, 0x76, 0x17, 0x6c, 0x50, 0x8d, 0x89, 0x98, 0x95, 0xff, 0x55, 0xfb, 0x5c, 0xe3, 0xb4, 0x00, 0x35, 0xc7, 0x57, 0xe5, 0x8c, 0x3e, 0x6f, 0x66, 0x1d, 0xb1, 0x2a, 0xeb, 0x5b, 0x96, 0x3e, 0x3c, 0xdf, 0xc5, 0xe5, 0xd4, 0x8f, 0x2b, 0x77, 0x7b, 0x8e, 0x9a, 0x2d, 0x77, 0x32, 0x74, 0xdf, 0xeb, 0x96, 0x65, 0x7b, 0x28, 0x27, 0xae, 0xb6, 0xf0, 0x00, 0x31, 0xcc, 0xf9, 0x79, 0x81, 0xd6, 0xb2, 0xb4, 0xe1, 0x6b, 0x89, 0x69, 0x79, 0x78, 0xd3, 0xc4, 0xca, 0x89, 0x8d, 0x39, 0xe2, 0xd2, 0x57, 0x23, 0xc6, 0x3b, 0xff, 0x7d, 0x01, 0xbb, 0x7b, 0xfc, 0x1d, 0x19, 0xa4, 0x3a, 0x32, 0x3e, 0x35, 0xe8, 0x4b, 0xd6, 0x9f, 0x49, 0xf0, 0x10,\n\t0xab, 0xc2, 0xc5, 0x09, 0x30, 0x48, 0x42, 0x6e, 0x36, 0xf8, 0x85, 0xd7, 0x62, 0xf0, 0xc1, 0x6f, 0xb6, 0x3e, 0xbf, 0x01, 0xcc, 0xf5, 0x81, 0x21, 0xd4, 0x01, 0x94, 0x97, 0x67, 0xc5, 0x02, 0x02, 0x02, 0x32, 0x07, 0xf1, 0x16, 0x2c, 0x4a, 0xbc, 0x38, 0x87, 0x85, 0x6d, 0xb4, 0x61, 0x55, 0xad, 0xcf, 0x95, 0xb4, 0x1b, 0x70, 0x85, 0x7d, 0xd3, 0xd2, 0xe9, 0xa3, 0xc7, 0x79, 0xd4, 0xd3, 0x93, 0x25, 0x06, 0x5e, 0x08, 0x63, 0xa1, 0xa7, 0x9f, 0x2c, 0xea, 0x1b, 0x3e, 0x3d, 0x07, 0x19, 0xc2, 0x84, 0xaa, 0x41, 0x65, 0xa5, 0x89, 0xee, 0xc4, 0xbc, 0xc4, 0x40, 0x6e, 0x52, 0xae, 0x1d, 0xe6, 0x18, 0x9b, 0x2e, 0xd4, 0x31, 0x3e, 0x7d, 0xb2, 0x6b, 0xda, 0x41, 0x21, 0x33, 0xcb, 0xb8, 0x07, 0xe0, 0x82, 0xa4, 0xf8, 0xf1, 0xca, 0x0d, 0xb3, 0x7c, 0x4d, 0x29, 0xf1, 0x72, 0xba, 0xa3, 0x21, 0xa7,\n\t0x62, 0x54, 0x63, 0xa9, 0xdb, 0x15, 0xa7, 0x29, 0xc2, 0xe4, 0x84, 0xa3, 0x71, 0xba, 0xdd, 0x9f, 0xe0, 0xea, 0xc9, 0xf1, 0x88, 0x7c, 0xed, 0xdc, 0x65, 0x4e, 0xe7, 0x66, 0xaf, 0xdd, 0x5b, 0x3b, 0xb6, 0x72, 0xbb, 0xc8, 0x74, 0xa0, 0xa0, 0xec, 0xc3, 0x0f, 0x0a, 0x6c, 0x28, 0x78, 0xfc, 0x33, 0x4f, 0x26, 0x19, 0x87, 0x5f, 0x20, 0xc4, 0xfd, 0x4c, 0xb0, 0xa2, 0x41, 0x68, 0x4b, 0xe7, 0x9e, 0x00, 0xdc, 0xa2, 0xb3, 0xd0, 0x5b, 0x0e, 0x51, 0x5d, 0xed, 0xb6, 0xd0, 0x95, 0xc1, 0xdc, 0xd3, 0x2c, 0x83, 0xbf, 0xbf, 0x8e, 0x36, 0xf5, 0x5b, 0xf1, 0x00, 0xfd, 0x16, 0xdd, 0x65, 0x41, 0x47, 0x05, 0xeb, 0x2f, 0xbf, 0x2f, 0x3f, 0x0f, 0xce, 0xaa, 0xdd, 0x46, 0x2b, 0x90, 0xf4, 0x4d, 0x26, 0xee, 0xbf, 0xbf, 0x52, 0x3c, 0x47, 0x8b, 0xce, 0xbb, 0xbe, 0xab, 0x72, 0x42, 0x59, 0x8a, 0x94, 0xea,\n\t0x88, 0x2f, 0xcc, 0x7f, 0xd4, 0x15, 0xaf, 0x75, 0x54, 0x4a, 0xc2, 0xb1, 0x38, 0xbb, 0x2e, 0xc3, 0x4e, 0x0b, 0xb7, 0x79, 0xf2, 0x86, 0x39, 0x75, 0x89, 0xee, 0xa9, 0x24, 0xe1, 0xf1, 0xe7, 0xf4, 0x5e, 0xda, 0x8a, 0x5f, 0xe4, 0x35, 0x81, 0xa5, 0xfb, 0x19, 0xe1, 0xcf, 0xf9, 0x5c, 0xb1, 0x05, 0x0d, 0x41, 0x53, 0x82, 0x93, 0xd2, 0xb1, 0x20, 0xe5, 0x27, 0x71, 0x16, 0x1e, 0xa2, 0x2c, 0x55, 0x61, 0x3b, 0x27, 0x74, 0x10, 0xee, 0x20, 0x2e, 0xb3, 0xc2, 0xd6, 0x06, 0x07, 0x21, 0x8d, 0xc9, 0xd2, 0xc9, 0xd9, 0x2d, 0xdc, 0x1c, 0x99, 0x28, 0x02, 0x2d, 0x0e, 0xb6, 0xdd, 0x0e, 0x2f, 0x92, 0xd1, 0x42, 0x34, 0xa6, 0xbe, 0x16, 0x7c, 0xb5, 0xe7, 0xba, 0x5c, 0x85, 0xee, 0xa4, 0xc4, 0x64, 0xb6, 0xe3, 0x46, 0x3f, 0xab, 0x05, 0x9b, 0x76, 0x7e, 0x28, 0xc2, 0x02, 0xc4, 0xbb, 0xa2, 0xd7, 0x4a,\n\t0x7d, 0x8b, 0x39, 0xc5, 0xc3, 0xe7, 0x0e, 0x5a, 0x3b, 0x72, 0xe5, 0x0d, 0x71, 0x71, 0xda, 0x67, 0xb9, 0x9c, 0x57, 0xb8, 0x3c, 0x3b, 0x4a, 0x05, 0x4f, 0xe2, 0x1c, 0x9c, 0xa3, 0x7c, 0x60, 0xfc, 0xf8, 0xa6, 0x72, 0x6f, 0x41, 0x46, 0x92, 0xc5, 0x66, 0x97, 0xc6, 0x94, 0x0e, 0xda, 0x70, 0xdd, 0xbf, 0xd5, 0x8f, 0xe4, 0x7f, 0x9f, 0x9c, 0x3c, 0xde, 0x83, 0x2b, 0x5c, 0x6e, 0x65, 0xe7, 0x26, 0xe5, 0x97, 0x5a, 0x37, 0xdc, 0xd9, 0xdc, 0xe4, 0x70, 0x39, 0xac, 0x36, 0xc6, 0xd7, 0x88, 0x56, 0xe5, 0xd7, 0xf1, 0xdf, 0xa2, 0x6a, 0x34, 0x35, 0x38, 0x39, 0x37, 0x8d, 0x93, 0x2d, 0xd5, 0x84, 0x35, 0x40, 0xec, 0x24, 0xc4, 0x77, 0x20, 0x8b, 0x20, 0x0b, 0x16, 0xb2, 0x16, 0xf1, 0x9c, 0x95, 0x03, 0xbf, 0x2d, 0x02, 0x02, 0x77, 0x78, 0x73, 0xc8, 0x8a, 0x64, 0x45, 0xb2, 0x95, 0xba, 0xce, 0x51,\n\t0x3b, 0x82, 0x94, 0x75, 0x01, 0x7b, 0x7d, 0x5d, 0x59, 0x91, 0x54, 0xe0, 0x72, 0xe7, 0x91, 0x7f, 0xd1, 0xfb, 0x08, 0xf9, 0xe4, 0x23, 0x69, 0x40, 0x74, 0x50, 0x53, 0xfa, 0xfb, 0xc9, 0x14, 0x0f, 0xdc, 0x46, 0xa0, 0x17, 0x35, 0x40, 0xd5, 0xe9, 0x8f, 0x2c, 0x03, 0x05, 0x78, 0x3c, 0x97, 0xd5, 0x1b, 0x72, 0xc4, 0x63, 0x6b, 0x82, 0x37, 0xce, 0x91, 0x95, 0xea, 0xba, 0x27, 0x67, 0xf0, 0xc4, 0xaa, 0xe2, 0x09, 0xf9, 0xcf, 0x87, 0xfe, 0xce, 0xfd, 0xdb, 0x19, 0xf7, 0x57, 0x87, 0x37, 0x2e, 0x3e, 0xc3, 0xe3, 0x5c, 0x9f, 0x56, 0xd5, 0x59, 0x55, 0x3c, 0x3e, 0xff, 0xde, 0x7b, 0x27, 0x39, 0x08, 0xc9, 0x98, 0x29, 0xc9, 0xf6, 0x94, 0x9c, 0x94, 0xea, 0x29, 0x2d, 0xbe, 0x14, 0xd7, 0xbf, 0xee, 0x9d, 0x94, 0x5c, 0xe8, 0x50, 0x8e, 0x8b, 0xb2, 0x2d, 0x19, 0xb0, 0x66, 0x5f, 0x4a, 0x02, 0xe1,\n\t0xae, 0xad, 0xe1, 0x6c, 0xf4, 0x29, 0xe7, 0x22, 0x4c, 0xfa, 0x1e, 0x84, 0x4e, 0x6e, 0x64, 0xdc, 0xf7, 0xe4, 0x46, 0x9d, 0xdb, 0x8e, 0x0f, 0x67, 0xe3, 0x5b, 0xc9, 0xd8, 0xcb, 0xe8, 0xc1, 0x70, 0x98, 0xfd, 0x8e, 0x8d, 0xbf, 0x77, 0x84, 0x3d, 0x5c, 0x0a, 0x2e, 0xe4, 0x65, 0xf4, 0x88, 0x96, 0xdf, 0xf4, 0xbb, 0x25, 0x9c, 0xcd, 0x65, 0xe1, 0x42, 0x92, 0x7f, 0x07, 0xc2, 0x31, 0x7e, 0x9f, 0xa0, 0xfc, 0x88, 0x6b, 0x26, 0x5d, 0x2b, 0xf3, 0x63, 0x62, 0xd6, 0xef, 0x52, 0xae, 0xe2, 0x1a, 0x70, 0x19, 0xf9, 0x7d, 0x2c, 0xe2, 0x63, 0xe4, 0x8f, 0x53, 0x16, 0x71, 0x76, 0x5c, 0x41, 0x7e, 0x9f, 0xd0, 0xf7, 0x77, 0xb2, 0x0c, 0x96, 0x93, 0xb1, 0xfc, 0x5c, 0xbc, 0x1f, 0x95, 0xa0, 0xa9, 0x70, 0x63, 0x2e, 0xe0, 0xb1, 0xf2, 0x3c, 0x9a, 0xdc, 0x5e, 0xcf, 0x4b, 0x22, 0xd7, 0x61, 0x83, 0x97,\n\t0x4c, 0x22, 0x21, 0x8a, 0x3d, 0x56, 0x0b, 0x27, 0x4a, 0x44, 0xb6, 0x17, 0x83, 0x6f, 0x6d, 0x34, 0xa7, 0x53, 0xc6, 0x74, 0x7a, 0x22, 0x34, 0xae, 0xb3, 0x75, 0x48, 0x4b, 0x53, 0x55, 0xe5, 0xa0, 0x72, 0x52, 0x44, 0xb1, 0xab, 0xa4, 0xc5, 0x65, 0x87, 0xab, 0xe4, 0xf0, 0x70, 0xc9, 0xe3, 0xa6, 0x0f, 0x97, 0x98, 0xdc, 0x56, 0x99, 0xfe, 0x06, 0xab, 0x10, 0x1f, 0x28, 0x20, 0x23, 0x29, 0xf9, 0xc5, 0x28, 0xa0, 0x04, 0xeb, 0x99, 0xeb, 0xa2, 0xf2, 0x7e, 0x77, 0x7c, 0xa9, 0xcb, 0xc3, 0xcf, 0x17, 0xad, 0xa2, 0x18, 0x67, 0xb9, 0x5c, 0x48, 0x72, 0xd4, 0xe7, 0x5a, 0x96, 0xca, 0x36, 0x91, 0x00, 0xdd, 0x42, 0x8a, 0x63, 0xe1, 0x2f, 0x16, 0x25, 0x5a, 0xae, 0xb1, 0x4a, 0x92, 0xf5, 0x5a, 0xab, 0x07, 0x7f, 0x17, 0x8d, 0x5c, 0xa6, 0xe7, 0xb6, 0x39, 0xcd, 0x99, 0x79, 0x9e, 0xbb, 0xd7, 0x95,\n\t0xa0, 0xac, 0xf5, 0x56, 0xa5, 0xa5, 0x55, 0x79, 0xf1, 0x75, 0x0e, 0x57, 0x8e, 0xb2, 0x3a, 0xbd, 0x32, 0xd5, 0x53, 0x99, 0x8e, 0xaf, 0x75, 0xba, 0x42, 0x97, 0xa4, 0xe3, 0xfb, 0xf3, 0xb2, 0xfd, 0xb9, 0xca, 0xdc, 0xf4, 0x9b, 0x13, 0x4c, 0x7f, 0x25, 0xf9, 0x5c, 0x90, 0x2f, 0xb5, 0xa2, 0x0e, 0x5f, 0xe7, 0x4c, 0x80, 0x6c, 0x83, 0x20, 0x1b, 0xb3, 0x8b, 0x94, 0x11, 0xb8, 0x22, 0x7c, 0x84, 0xd9, 0x45, 0xdf, 0xbd, 0xcf, 0xfa, 0xfe, 0xbb, 0xf7, 0x23, 0x76, 0x11, 0xf9, 0x7d, 0x10, 0xfd, 0xfd, 0x86, 0x58, 0xbf, 0x2b, 0x4b, 0x38, 0x1b, 0xbe, 0x9d, 0xbb, 0x07, 0xc9, 0xb8, 0x33, 0xf4, 0x12, 0xea, 0x07, 0x83, 0x3b, 0x16, 0xc2, 0x46, 0x2e, 0x99, 0xd8, 0x7c, 0xf4, 0x0c, 0x87, 0xde, 0xb1, 0x87, 0xdb, 0x6a, 0xdd, 0xc8, 0x74, 0x86, 0x13, 0x79, 0x86, 0x8b, 0x2b, 0xf4, 0x33, 0x1c, 0x71,\n\t0x57, 0xe4, 0x10, 0x07, 0xb3, 0xb7, 0x7b, 0xe2, 0x36, 0x94, 0x00, 0xef, 0xc1, 0x6c, 0x2c, 0xf6, 0x05, 0xdc, 0xb8, 0xe7, 0xe1, 0x16, 0xe5, 0x1c, 0x1a, 0xde, 0x38, 0x01, 0x39, 0xd5, 0x0b, 0xbc, 0xd1, 0x6f, 0xee, 0xb8, 0x37, 0xfa, 0x3c, 0xb1, 0xdb, 0x16, 0xf5, 0xa2, 0x8e, 0xd6, 0xa1, 0xdc, 0xc3, 0xbd, 0x11, 0x7e, 0x98, 0x14, 0xe4, 0x0d, 0xa6, 0xca, 0xd4, 0x03, 0x2e, 0x3c, 0x57, 0x59, 0x06, 0xda, 0xb5, 0x07, 0x8d, 0x71, 0x95, 0xa8, 0x97, 0xf9, 0x61, 0x63, 0x95, 0xc8, 0x83, 0x93, 0x3d, 0x55, 0x24, 0xa5, 0xaf, 0x89, 0xf3, 0xc4, 0xff, 0xc8, 0x62, 0xb5, 0x5a, 0xae, 0xb4, 0xa5, 0xc5, 0xad, 0xfb, 0xf0, 0x39, 0xe5, 0x1e, 0x4b, 0xfc, 0x35, 0x96, 0xb8, 0x38, 0xcb, 0x35, 0x76, 0x1b, 0xb6, 0xb3, 0xf8, 0x7a, 0xca, 0x36, 0xee, 0x89, 0xf0, 0x2e, 0x94, 0x0c, 0xb1, 0x3b, 0xe8, 0xbb,\n\t0x18, 0x7a, 0x95, 0x7e, 0xba, 0xc0, 0xca, 0x3e, 0xab, 0x10, 0x7b, 0xca, 0xb6, 0x18, 0x21, 0xf6, 0x20, 0x86, 0xb3, 0xf2, 0x32, 0xf7, 0x72, 0xf8, 0x41, 0xe4, 0x85, 0x57, 0xd7, 0x7a, 0x1c, 0x46, 0xe6, 0xa7, 0x1d, 0xdc, 0xb9, 0x2d, 0xe0, 0xfa, 0x06, 0x71, 0xa6, 0x27, 0x69, 0x67, 0x1c, 0xc4, 0xf9, 0x85, 0x18, 0x31, 0x9c, 0x71, 0xf8, 0x46, 0x7c, 0x23, 0x57, 0xc5, 0x2d, 0x45, 0x19, 0xf0, 0x26, 0x17, 0x9e, 0xb1, 0x0a, 0xd3, 0x44, 0xcc, 0x7c, 0x34, 0xcd, 0x21, 0xfc, 0x91, 0xde, 0x49, 0x14, 0xd0, 0xf8, 0x44, 0x88, 0xb3, 0x6a, 0x7a, 0xc8, 0x1a, 0x15, 0x4e, 0xb5, 0xb6, 0x9a, 0xab, 0xca, 0xac, 0xe9, 0x2c, 0x2f, 0xed, 0x1c, 0xd6, 0x92, 0x95, 0x13, 0xc0, 0x37, 0x66, 0xd6, 0x75, 0x56, 0x94, 0x74, 0xb6, 0xb5, 0x64, 0x67, 0x17, 0xae, 0xe5, 0xba, 0x41, 0x0f, 0x66, 0xf8, 0x33, 0x8a,\n\t0xcb, 0x88, 0x92, 0xcc, 0xcd, 0xcc, 0xcd, 0x2c, 0x2a, 0xa3, 0x63, 0x78, 0x27, 0x19, 0xc3, 0x07, 0xc8, 0x18, 0x36, 0xec, 0xb7, 0xa9, 0x31, 0xe4, 0x80, 0x3a, 0xc5, 0x83, 0xa0, 0xe8, 0x07, 0x7f, 0xde, 0xa0, 0x3d, 0xf2, 0xf7, 0x4b, 0xd9, 0x5b, 0x01, 0x5d, 0x7c, 0xc4, 0x53, 0x8b, 0xcf, 0xac, 0x28, 0xe9, 0x81, 0xf1, 0x7d, 0x82, 0x8c, 0xef, 0x8b, 0x64, 0x7c, 0x73, 0x83, 0xd9, 0x02, 0xbb, 0xc3, 0xcf, 0x51, 0xab, 0x68, 0x41, 0xdf, 0x00, 0x8a, 0x22, 0x0b, 0x4d, 0x66, 0x78, 0x81, 0x1f, 0x63, 0x74, 0xdb, 0x4b, 0x3b, 0xe6, 0xd6, 0x6b, 0x83, 0x5b, 0x3f, 0xb7, 0xa3, 0x14, 0xe6, 0x58, 0xe8, 0x29, 0x49, 0xe2, 0x26, 0xc9, 0x2b, 0xb8, 0x00, 0xee, 0xa5, 0xb7, 0x5d, 0x20, 0xea, 0xf7, 0x1f, 0xd9, 0x1b, 0xbe, 0x3f, 0x6a, 0x7b, 0x22, 0x55, 0xc2, 0x34, 0xee, 0x5d, 0x62, 0x92, 0xc9, 0x9c,\n\t0x8b, 0x10, 0xf5, 0x9d, 0x6c, 0xee, 0x8a, 0x3b, 0x75, 0xbd, 0x8a, 0x42, 0x1f, 0x08, 0xeb, 0x88, 0x9c, 0x6b, 0x7e, 0x3f, 0x58, 0x3c, 0x8f, 0x59, 0x7d, 0x4e, 0x65, 0xd5, 0x67, 0x46, 0x74, 0x59, 0x27, 0xff, 0x17, 0xd6, 0x9d, 0xbc, 0x0a, 0xfe, 0xaf, 0x5c, 0x7e, 0x27, 0x3e, 0x7a, 0x27, 0xa9, 0xe7, 0x80, 0xc2, 0x71, 0x97, 0x84, 0x5f, 0x20, 0x0c, 0x43, 0x21, 0x3a, 0xe2, 0x32, 0xa6, 0xff, 0xbf, 0xbb, 0x4c, 0xd7, 0x21, 0xf7, 0x84, 0x3e, 0xe3, 0x96, 0x85, 0xf7, 0x92, 0x76, 0x58, 0xc8, 0xef, 0x97, 0xa8, 0x3a, 0xe4, 0x12, 0xfd, 0xf7, 0xed, 0xa1, 0x6f, 0xb9, 0xcb, 0x40, 0xc7, 0x40, 0x7c, 0xf8, 0xef, 0x56, 0xab, 0xbf, 0xaf, 0xd6, 0x7f, 0xef, 0x0e, 0x67, 0xe1, 0x9b, 0xd0, 0xbf, 0xc8, 0xef, 0xf5, 0x08, 0x7d, 0xff, 0x8a, 0x7a, 0xfe, 0xf9, 0x8a, 0xbe, 0x37, 0xb3, 0x5c, 0xd9, 0x2a,\n\t0x8e, 0x86, 0x3b, 0x22, 0x68, 0x23, 0xdb, 0x32, 0xb4, 0xe7, 0xc0, 0x41, 0x6a, 0x22, 0xf5, 0x97, 0xe0, 0x8d, 0xfc, 0x4d, 0xa4, 0xb7, 0x3b, 0x21, 0x41, 0x2e, 0xb2, 0x20, 0xb8, 0xd6, 0x37, 0xcb, 0x66, 0xe5, 0xe0, 0x76, 0xa6, 0x44, 0xa6, 0x20, 0x9a, 0xdb, 0x29, 0x52, 0xd7, 0x37, 0x88, 0xe7, 0x7b, 0xe0, 0x3c, 0xad, 0x08, 0x5e, 0x65, 0x23, 0xd8, 0x33, 0x8e, 0x99, 0x58, 0xdb, 0x20, 0xec, 0xe1, 0x59, 0xc4, 0x56, 0x52, 0x7d, 0x81, 0xcb, 0x95, 0x92, 0x97, 0x54, 0x48, 0x3a, 0x8c, 0xb2, 0x66, 0x7a, 0x33, 0xd8, 0xdf, 0xdf, 0xa6, 0x60, 0xbd, 0x1f, 0xdc, 0xbe, 0xba, 0xc4, 0xd1, 0x27, 0x42, 0xee, 0xe6, 0xa4, 0x0b, 0x27, 0xfa, 0x9a, 0x26, 0x57, 0x16, 0x8d, 0xce, 0x49, 0x94, 0xdc, 0x52, 0x42, 0x72, 0x56, 0x52, 0x41, 0xd1, 0xc4, 0xb1, 0xe5, 0xc5, 0xef, 0x70, 0x9f, 0x89, 0xdb, 0xbe,\n\t0x9f, 0xcb, 0xdd, 0x14, 0x5a, 0x31, 0x32, 0x69, 0x64, 0x9d, 0xaf, 0x26, 0x2f, 0xc9, 0xe9, 0x68, 0x71, 0xcb, 0xb2, 0x9c, 0x93, 0x9a, 0x97, 0x69, 0xdb, 0x20, 0x6e, 0x0b, 0xdd, 0xc8, 0x5d, 0x4d, 0xfa, 0x68, 0xb9, 0xf2, 0x35, 0xf7, 0xa6, 0x60, 0xe7, 0x02, 0xe8, 0x47, 0xb0, 0xc3, 0x2f, 0x7e, 0x24, 0xb2, 0xbe, 0x5b, 0xaf, 0x6c, 0xe3, 0x3f, 0xa4, 0xe7, 0xcb, 0x33, 0x61, 0xef, 0x5d, 0x4a, 0x41, 0x0f, 0xd0, 0x3e, 0x4b, 0x23, 0x02, 0xf0, 0x7b, 0xf1, 0x18, 0xca, 0x81, 0x3b, 0x99, 0x19, 0x18, 0xcb, 0xd9, 0x64, 0xa8, 0x1d, 0x76, 0x8e, 0x13, 0x78, 0xea, 0x62, 0x02, 0xb8, 0x2f, 0xb1, 0xcd, 0xe1, 0x8a, 0x05, 0x02, 0x62, 0x24, 0xcf, 0x53, 0xaf, 0x65, 0x12, 0x16, 0xe8, 0x27, 0xff, 0x67, 0xb7, 0x56, 0x4d, 0xa4, 0xd6, 0x68, 0xaf, 0x79, 0xe0, 0x6e, 0x05, 0xfe, 0x37, 0x21, 0x79, 0x77,\n\t0xf9, 0x06, 0x4f, 0xac, 0x4c, 0x4c, 0x38, 0x26, 0xc7, 0x4b, 0x81, 0x42, 0x7c, 0x8f, 0xaf, 0x79, 0xe2, 0x20, 0x57, 0xe2, 0xb1, 0x38, 0x7e, 0x78, 0x21, 0xa5, 0x6d, 0x7c, 0x68, 0x14, 0x1f, 0xc7, 0xc1, 0xb6, 0x08, 0x61, 0x38, 0x3c, 0x57, 0x18, 0x5a, 0xc3, 0xd3, 0x76, 0x67, 0x87, 0x3f, 0xe7, 0x8e, 0x48, 0xcd, 0xa4, 0xdd, 0xd7, 0xd0, 0x7d, 0xc4, 0xfd, 0xe1, 0xd7, 0xd0, 0x01, 0x90, 0x6f, 0x6e, 0xcf, 0x01, 0x55, 0xbe, 0x43, 0x53, 0x85, 0x8d, 0xca, 0xd7, 0x64, 0x4d, 0x91, 0xd1, 0x93, 0xbd, 0x1f, 0xb0, 0xb5, 0xa7, 0x37, 0x2c, 0xd9, 0xc2, 0x16, 0x79, 0x08, 0xc1, 0x76, 0x6a, 0x58, 0xa8, 0x57, 0xd8, 0x18, 0x7e, 0x90, 0xa6, 0xdb, 0xa5, 0x63, 0x7f, 0x93, 0xc8, 0x6c, 0xa5, 0xe9, 0x76, 0xeb, 0x58, 0x8d, 0x70, 0x7b, 0x78, 0x17, 0xbd, 0x07, 0xfb, 0x94, 0x8e, 0x95, 0x92, 0xf2, 0x5e,\n\t0x94, 0xbd, 0x04, 0x7b, 0x3a, 0x46, 0xba, 0x3d, 0x3a, 0x16, 0xd0, 0xd3, 0xed, 0xd5, 0xb1, 0x51, 0xc2, 0xce, 0xf0, 0x7d, 0xe2, 0xad, 0x70, 0xd2, 0x68, 0x28, 0x4f, 0x0e, 0x1f, 0x96, 0xbe, 0x20, 0xd8, 0xb3, 0x3a, 0xd6, 0x20, 0xdc, 0x15, 0x7e, 0x5c, 0x5c, 0x03, 0x37, 0x6e, 0x74, 0xac, 0x50, 0x4a, 0x08, 0xbf, 0x20, 0x7d, 0x4b, 0xb0, 0xe7, 0x74, 0x6c, 0x9c, 0x70, 0x3c, 0x7c, 0x87, 0xd8, 0x41, 0xb0, 0xe7, 0x75, 0xec, 0x3c, 0x69, 0x50, 0x78, 0xa3, 0xf4, 0x30, 0xc1, 0x5e, 0xd0, 0xb1, 0x69, 0xe4, 0x7b, 0xd7, 0xd3, 0xf6, 0x1d, 0xd0, 0xb1, 0x16, 0xc9, 0x1a, 0x7e, 0x48, 0x76, 0x13, 0xec, 0x45, 0x1d, 0x7b, 0x48, 0xb8, 0x34, 0xdc, 0x2a, 0x7e, 0x42, 0xb0, 0x83, 0x3a, 0xf6, 0x94, 0xf8, 0x65, 0xb8, 0x0a, 0xee, 0x2c, 0xa3, 0x97, 0x74, 0xec, 0x0e, 0x61, 0x23, 0xaa, 0xa0, 0xfd, 0xf7,\n\t0x13, 0x1d, 0xbb, 0x86, 0xf4, 0xdf, 0x1c, 0xfa, 0xbd, 0x87, 0x22, 0x7d, 0x2a, 0x3c, 0xa3, 0x7c, 0x23, 0x1e, 0x22, 0xd8, 0x61, 0x1d, 0xfb, 0xa7, 0x94, 0xae, 0x7c, 0x21, 0x67, 0x12, 0xec, 0x88, 0x8e, 0xbd, 0xa9, 0x6c, 0x0d, 0x0f, 0x25, 0xab, 0x82, 0x8c, 0x8e, 0xea, 0xd8, 0x21, 0xe5, 0xc9, 0x70, 0x25, 0x8a, 0x27, 0xd8, 0x31, 0x1d, 0xab, 0x13, 0x56, 0x87, 0x15, 0xf1, 0x03, 0x82, 0x7d, 0xa6, 0x63, 0xc3, 0x89, 0xc6, 0xda, 0x06, 0xdf, 0x86, 0x2b, 0x23, 0x98, 0xf8, 0x5d, 0x78, 0x9b, 0x4c, 0xb4, 0x18, 0xae, 0xd6, 0x30, 0x65, 0x9d, 0xf2, 0x48, 0x38, 0x47, 0x02, 0x17, 0x72, 0x23, 0xc1, 0xc9, 0x11, 0x4d, 0xf7, 0xaa, 0xf2, 0x60, 0x78, 0x5e, 0xf8, 0x30, 0x31, 0xe7, 0xfe, 0xa4, 0xe7, 0x7d, 0x44, 0x79, 0x28, 0x3c, 0x2a, 0x7c, 0x84, 0x60, 0x1f, 0x33, 0x0c, 0x61, 0x65, 0x61, 0x78,\n\t0x07, 0xbe, 0x53, 0x28, 0x23, 0x5c, 0x25, 0xa0, 0x7b, 0xf3, 0x61, 0x6f, 0x9f, 0x17, 0x47, 0xbf, 0x7d, 0xf6, 0x1b, 0xdf, 0x3e, 0x13, 0x1a, 0xf8, 0x2b, 0x77, 0x7d, 0xce, 0xf9, 0xdc, 0xa5, 0xae, 0x4a, 0xff, 0x05, 0x09, 0xfe, 0x42, 0x21, 0x98, 0x53, 0x08, 0xf2, 0xa2, 0xdc, 0x19, 0xde, 0x45, 0xd6, 0x22, 0x59, 0x4a, 0x8b, 0xc8, 0x90, 0x72, 0x0f, 0xc1, 0xc8, 0xb8, 0x49, 0xc9, 0x91, 0x71, 0x53, 0xb6, 0x85, 0xd7, 0x13, 0x6e, 0x40, 0x66, 0x69, 0x44, 0x86, 0x94, 0x97, 0xc3, 0xf7, 0x91, 0x35, 0x5c, 0x96, 0x3c, 0x11, 0x39, 0x50, 0xbe, 0x0e, 0xdf, 0x11, 0xbe, 0x9c, 0xb4, 0xf9, 0x23, 0xfd, 0x7b, 0x2d, 0xc2, 0x2c, 0xe5, 0x5f, 0xe2, 0x2b, 0x04, 0x6b, 0x30, 0x60, 0xf3, 0x08, 0x06, 0xdf, 0xd6, 0xa8, 0x63, 0xa5, 0x42, 0x77, 0x38, 0x55, 0xdc, 0x47, 0xb0, 0xc1, 0x91, 0xbe, 0x17, 0xba,\n\t0x95, 0x5d, 0x14, 0x6b, 0xea, 0x2b, 0xbb, 0x62, 0xb3, 0x8e, 0xdd, 0x28, 0xcc, 0x0a, 0xdf, 0x45, 0xeb, 0x68, 0xd1, 0xb1, 0xa5, 0x04, 0x5b, 0x4d, 0xb1, 0x21, 0x3a, 0x36, 0x9f, 0x60, 0x07, 0xa5, 0xe3, 0x04, 0x6b, 0xd5, 0xb1, 0xeb, 0x84, 0x79, 0xe1, 0x0d, 0xb4, 0x2d, 0x41, 0x1d, 0x5b, 0x4c, 0xb0, 0x6b, 0x28, 0xd6, 0x66, 0xc8, 0x3b, 0x4f, 0xcd, 0x3b, 0x54, 0x9f, 0xd3, 0x7f, 0x17, 0x16, 0x85, 0xff, 0x41, 0xdb, 0x37, 0x2c, 0x06, 0x36, 0xdc, 0x3c, 0x8f, 0x68, 0xde, 0x11, 0xfa, 0xf7, 0x1e, 0x57, 0xae, 0x08, 0xbf, 0x1a, 0x3e, 0x40, 0xb0, 0xd1, 0xca, 0x02, 0x95, 0x8b, 0x3e, 0x48, 0xec, 0x89, 0x5f, 0x12, 0x19, 0xb2, 0x43, 0x3c, 0x5d, 0x1b, 0xcf, 0xb1, 0x00, 0x6a, 0x98, 0x90, 0x22, 0x42, 0x06, 0x38, 0x7a, 0xab, 0x9b, 0x5d, 0x1d, 0xb3, 0x23, 0xbb, 0x2f, 0x91, 0x3e, 0x5c, 0x04,\n\t0x5d, 0x8e, 0x89, 0x65, 0x57, 0x95, 0x8d, 0x6b, 0xf9, 0x5f, 0xde, 0xaf, 0xfc, 0x44, 0xd9, 0x83, 0x7b, 0xf2, 0x53, 0x3f, 0x06, 0xe5, 0xcc, 0xff, 0x13, 0xa7, 0x6d, 0x4e, 0x7f, 0xed, 0x23, 0x53, 0xd9, 0x71, 0x50, 0xb6, 0x7d, 0x80, 0xb2, 0xe3, 0x50, 0x5c, 0x74, 0xd9, 0xc4, 0xa0, 0x70, 0x41, 0xe1, 0x4f, 0x2b, 0x87, 0x70, 0x4f, 0x5a, 0x91, 0xf5, 0x1d, 0xaa, 0xfa, 0x0f, 0x72, 0x63, 0x37, 0xa7, 0x27, 0x2b, 0xeb, 0xf1, 0x63, 0xe7, 0xaa, 0xfc, 0xc7, 0x94, 0x9f, 0xe2, 0x9e, 0xac, 0x32, 0xe1, 0x57, 0x50, 0x3e, 0xbe, 0x96, 0xdf, 0xb0, 0x39, 0x2f, 0x23, 0xf4, 0x1e, 0x04, 0xd6, 0x3d, 0xdb, 0xf2, 0x6b, 0x4d, 0xe5, 0x3f, 0xa4, 0xfc, 0x9c, 0x94, 0x5f, 0x2e, 0xbc, 0x05, 0xe5, 0x0f, 0x15, 0x5e, 0xdb, 0x9c, 0x9f, 0x19, 0xf2, 0xf3, 0x39, 0xb4, 0x7f, 0x16, 0x92, 0x75, 0xe7, 0x62, 0xaa,\n\t0x9b, 0x08, 0xe3, 0x90, 0x44, 0x81, 0x17, 0xa0, 0x06, 0x8e, 0xbd, 0xff, 0xd1, 0xca, 0x86, 0x07, 0xa3, 0xf4, 0x19, 0x3f, 0xb4, 0xbc, 0xde, 0x53, 0xcb, 0x5d, 0x7c, 0xbf, 0xf2, 0xe4, 0xa5, 0x9f, 0xa9, 0x9d, 0x5d, 0xb2, 0xe4, 0xcd, 0x8f, 0xb4, 0xb2, 0x68, 0x5b, 0x9d, 0xc0, 0x6f, 0x1d, 0x10, 0xd8, 0x8f, 0x2c, 0x57, 0xd0, 0x5c, 0x88, 0xb1, 0x04, 0x11, 0x71, 0x4d, 0x0d, 0x76, 0x22, 0x67, 0xbe, 0xfa, 0xae, 0xcf, 0xef, 0x72, 0x72, 0x12, 0xdc, 0xfd, 0xa9, 0xc7, 0xf9, 0x30, 0x9c, 0x7f, 0xe5, 0x38, 0x4f, 0x66, 0x96, 0x47, 0xb9, 0xed, 0x52, 0xdc, 0x8c, 0x7d, 0x50, 0x8d, 0xf0, 0xd8, 0x1b, 0x98, 0x4b, 0x4c, 0xc4, 0x6d, 0x4b, 0x94, 0xbf, 0x87, 0x8a, 0x0d, 0x75, 0xd9, 0xe1, 0x3d, 0x3b, 0x04, 0x5d, 0xe3, 0xa9, 0x51, 0x00, 0xc6, 0x01, 0x7d, 0xa2, 0x69, 0x96, 0x9a, 0x24, 0x9f, 0xde,\n\t0xf3, 0x3e, 0x5a, 0x8d, 0x8f, 0x76, 0xcc, 0x1f, 0x59, 0x1d, 0xd3, 0x31, 0x47, 0x3f, 0xe5, 0x55, 0x5a, 0xfe, 0x2f, 0xf1, 0x30, 0x53, 0xf9, 0xa4, 0x5f, 0x6c, 0xfd, 0xf4, 0x0b, 0x29, 0xd9, 0xd0, 0x2f, 0x38, 0x0b, 0x67, 0x63, 0x28, 0x37, 0x34, 0xf8, 0x52, 0xbc, 0x48, 0x10, 0x79, 0x2a, 0x8d, 0xdc, 0x6e, 0x6e, 0xd1, 0x12, 0xe5, 0x10, 0x27, 0xf2, 0xaf, 0x71, 0x79, 0xc8, 0xd4, 0x4f, 0xac, 0x6c, 0x49, 0x3c, 0x65, 0xd9, 0x56, 0x52, 0xb8, 0x36, 0x98, 0xdb, 0x95, 0x2d, 0xa4, 0xf4, 0x44, 0x0b, 0x15, 0x46, 0xbc, 0x82, 0x5b, 0x80, 0x1b, 0x49, 0xf1, 0x71, 0x6e, 0x65, 0x3d, 0xf7, 0x57, 0x43, 0xd9, 0x71, 0x50, 0xb6, 0xbd, 0x9f, 0xb2, 0x89, 0xac, 0x68, 0x65, 0xd7, 0x5a, 0x69, 0xc3, 0xd5, 0xc2, 0xb7, 0x2a, 0x0f, 0x90, 0xc2, 0xe3, 0x12, 0x38, 0x2a, 0x8a, 0xcd, 0xfc, 0x13, 0xb8, 0x96,\n\t0x14, 0x6e, 0x49, 0x73, 0x86, 0xde, 0xe3, 0x9f, 0xa0, 0x6d, 0x9f, 0x71, 0xe6, 0xf2, 0xe2, 0x76, 0x81, 0xbc, 0x6c, 0xd9, 0xf0, 0xbe, 0x3a, 0x7d, 0x96, 0x8d, 0x56, 0x56, 0x91, 0xc9, 0x43, 0xcb, 0x3a, 0x33, 0x79, 0xc9, 0xd3, 0xe5, 0x85, 0xa7, 0x5b, 0x5e, 0x05, 0xe0, 0x4c, 0x17, 0x04, 0xe6, 0x37, 0xd6, 0xc2, 0xb4, 0xf4, 0x42, 0xab, 0x72, 0xf7, 0x06, 0xa2, 0xf8, 0x99, 0xc0, 0x14, 0x2b, 0xeb, 0x92, 0xd2, 0xd3, 0x93, 0xb9, 0xab, 0x47, 0x87, 0xbe, 0xc6, 0xdf, 0xd7, 0x23, 0x43, 0x7d, 0x0e, 0xa8, 0x0f, 0x1c, 0x4e, 0x0d, 0x58, 0x9f, 0x03, 0x39, 0xfc, 0x7a, 0x7d, 0x2c, 0x06, 0x29, 0xc8, 0x27, 0xf4, 0xd3, 0x9f, 0x3d, 0xf9, 0x6a, 0x6d, 0x41, 0x1c, 0x47, 0x45, 0x67, 0xde, 0x4f, 0xd3, 0x58, 0x5d, 0x6f, 0x7e, 0x8a, 0x17, 0x1a, 0xeb, 0x8a, 0x03, 0xf9, 0xb4, 0x5a, 0x06, 0x92, 0x4f,\n\t0x32, 0x1a, 0xc9, 0x46, 0xf9, 0xa4, 0xf5, 0x54, 0x33, 0x01, 0x55, 0xab, 0x99, 0xfe, 0x05, 0xed, 0xbb, 0xb5, 0xac, 0x8e, 0x07, 0xb9, 0x1b, 0x90, 0xb1, 0x0e, 0x26, 0x47, 0x16, 0xf9, 0xd4, 0x32, 0x4a, 0x8b, 0xf6, 0xd0, 0xa2, 0x9f, 0x74, 0xca, 0x50, 0x72, 0xf7, 0x87, 0x54, 0x8e, 0xba, 0x71, 0x49, 0x7c, 0x02, 0x94, 0xbd, 0xf6, 0x18, 0x3f, 0xdf, 0x58, 0x76, 0x3c, 0x94, 0x1d, 0xd7, 0x4f, 0xd9, 0xf1, 0x28, 0x5e, 0x97, 0x23, 0x56, 0xb6, 0x26, 0xa5, 0xf7, 0x89, 0x02, 0x94, 0xbe, 0x48, 0xe2, 0xa9, 0x9c, 0xd6, 0x73, 0x8b, 0x24, 0x2b, 0x14, 0xbf, 0xda, 0x22, 0x2b, 0xeb, 0x05, 0xd5, 0x4e, 0x98, 0x76, 0xb6, 0xb2, 0x74, 0xd7, 0xe6, 0x77, 0x55, 0x55, 0x79, 0xa0, 0x36, 0xf4, 0x33, 0xf0, 0x0f, 0x04, 0x65, 0x9d, 0x23, 0x59, 0xfa, 0x95, 0x50, 0x96, 0x95, 0x59, 0x2a, 0x91, 0x4a, 0x70,\n\t0x01, 0x93, 0x25, 0xfe, 0xf1, 0xd0, 0x7b, 0x19, 0x79, 0xbe, 0x74, 0xfe, 0xc5, 0xda, 0xde, 0x93, 0xdc, 0xb7, 0x2d, 0xe8, 0x9c, 0xd5, 0x07, 0x7d, 0xf5, 0x8e, 0xb5, 0x28, 0x4d, 0xad, 0xaf, 0x16, 0xbb, 0xe9, 0x38, 0xff, 0x8f, 0xb2, 0x3e, 0x39, 0x9d, 0xd5, 0x77, 0x02, 0x7f, 0x84, 0x57, 0x18, 0xea, 0xfb, 0xc1, 0xb2, 0xfb, 0x71, 0x6a, 0xbe, 0x5a, 0xdb, 0x28, 0x8c, 0x68, 0x6d, 0xfe, 0xd7, 0xd4, 0xba, 0x1e, 0xfa, 0x80, 0x7b, 0xca, 0xf8, 0x6d, 0x3f, 0x50, 0x76, 0xd5, 0x6a, 0x2e, 0xfa, 0x1b, 0x1d, 0xab, 0x36, 0x56, 0xc7, 0xa5, 0xfc, 0x6b, 0xc8, 0x58, 0x87, 0x9d, 0xee, 0x1b, 0xc9, 0x3c, 0x3f, 0xb0, 0xe8, 0xd6, 0x9a, 0x44, 0x37, 0x89, 0x16, 0x7c, 0xd9, 0x1f, 0xa0, 0xe0, 0x22, 0x5c, 0xe2, 0xa4, 0x25, 0x77, 0x1c, 0x11, 0x1e, 0x67, 0x72, 0x35, 0xe5, 0x0c, 0xe5, 0xaa, 0x56, 0x93,\n\t0xab, 0xcd, 0xf7, 0x9c, 0x60, 0x4b, 0x64, 0xa8, 0x30, 0x94, 0x02, 0x0b, 0x24, 0x2d, 0x4b, 0x1d, 0xe7, 0xfc, 0x60, 0xae, 0x23, 0x1e, 0xfa, 0x1d, 0xf6, 0x9f, 0x58, 0x7f, 0xc3, 0x06, 0xd4, 0xa9, 0x05, 0xea, 0x2d, 0xbe, 0x3c, 0x3b, 0xa7, 0x9c, 0x53, 0xee, 0xbc, 0x07, 0xe7, 0xa9, 0x02, 0x95, 0x13, 0xf2, 0x67, 0x06, 0x02, 0x99, 0xc2, 0xc9, 0xc2, 0x5e, 0x8e, 0xff, 0x2a, 0xf8, 0xc3, 0xeb, 0x71, 0xa9, 0x82, 0xab, 0xd6, 0x53, 0x81, 0x53, 0xe8, 0xd0, 0xce, 0x07, 0xc1, 0xa5, 0xf5, 0x9c, 0x7c, 0x9f, 0xfb, 0x1d, 0x5e, 0xa5, 0xf7, 0xcf, 0x0f, 0xad, 0x0b, 0x84, 0x56, 0xad, 0xab, 0x19, 0x5b, 0xe9, 0x00, 0x3f, 0x0a, 0x42, 0xcb, 0xea, 0xda, 0x85, 0xdf, 0xe4, 0x0e, 0x9a, 0xeb, 0x72, 0x40, 0x5d, 0xf1, 0x71, 0x36, 0x6b, 0xec, 0xba, 0x8c, 0x02, 0x5b, 0xab, 0x0b, 0x6c, 0xbd, 0x2a, 0xb0,\n\t0x6a, 0x4d, 0xe3, 0xbe, 0x81, 0x8a, 0x3e, 0x7c, 0x4d, 0xad, 0x65, 0xf1, 0xbb, 0xfc, 0xe7, 0xa6, 0x3a, 0x6c, 0xe0, 0xe7, 0x89, 0xc6, 0x62, 0xa5, 0xfe, 0x2a, 0xd5, 0x39, 0x81, 0xa9, 0x32, 0x53, 0xeb, 0xb1, 0x21, 0x5b, 0xb2, 0x4f, 0x75, 0x26, 0x10, 0x11, 0x56, 0x65, 0xa8, 0x5a, 0xc3, 0x2c, 0xba, 0x64, 0xb3, 0xe2, 0xcb, 0x44, 0x2b, 0xf5, 0x9f, 0x7a, 0x86, 0x3a, 0x4a, 0x2e, 0xc0, 0xc0, 0x8f, 0x3e, 0x5b, 0x80, 0xa7, 0x30, 0xe2, 0xf2, 0xe6, 0x12, 0x5c, 0x52, 0x8c, 0x98, 0x2f, 0x56, 0x4d, 0xe6, 0x03, 0x41, 0x3f, 0x38, 0x27, 0xd5, 0xb8, 0x5c, 0xd4, 0xec, 0xb5, 0x23, 0x8b, 0x4b, 0xef, 0x78, 0x1f, 0xd1, 0x42, 0x75, 0xd5, 0x3e, 0xca, 0x72, 0x15, 0x65, 0xc7, 0x02, 0xbc, 0xc4, 0x93, 0xc5, 0xa4, 0x48, 0xb4, 0x28, 0xbf, 0x5c, 0x82, 0xdb, 0x12, 0xb1, 0xb1, 0xec, 0x78, 0xe8, 0xe7,\n\t0x38, 0x68, 0xa8, 0x08, 0xc5, 0xb3, 0x6d, 0x58, 0x93, 0xc6, 0x0e, 0xe8, 0x45, 0xe7, 0xd3, 0xa2, 0x35, 0x0a, 0xfd, 0x47, 0xe5, 0x18, 0x2d, 0x5c, 0x67, 0xd1, 0x21, 0xe5, 0xef, 0x50, 0x3c, 0x30, 0xe9, 0x48, 0xf9, 0x6c, 0x1c, 0xfb, 0x2d, 0x9f, 0x8c, 0x63, 0xa4, 0x7c, 0x2b, 0x2b, 0x5f, 0x5b, 0x13, 0x5e, 0x57, 0x7e, 0x4b, 0x2b, 0x30, 0x30, 0xe9, 0x6c, 0x45, 0xa1, 0x55, 0xa8, 0x74, 0xfa, 0x2c, 0xeb, 0xc1, 0xa2, 0xa9, 0x9e, 0x97, 0x95, 0x4f, 0x68, 0x3d, 0x06, 0x46, 0x3d, 0xf1, 0x1b, 0xa8, 0x46, 0x63, 0xd5, 0x67, 0x59, 0x4f, 0x6d, 0x54, 0x3d, 0xfb, 0x95, 0x7f, 0xb0, 0x7a, 0x74, 0x66, 0x7d, 0xd3, 0xe7, 0x50, 0x8d, 0xca, 0xae, 0x23, 0xdc, 0x3d, 0x1e, 0xf4, 0x68, 0x1c, 0x3f, 0x90, 0x1e, 0x85, 0x95, 0x34, 0x5f, 0xd7, 0xa3, 0xc0, 0x86, 0xc1, 0x8f, 0x86, 0xce, 0x85, 0x95, 0xdb,\n\t0xf0, 0x44, 0x1c, 0x8c, 0x10, 0xe1, 0xcd, 0x38, 0xad, 0x38, 0xda, 0x76, 0x22, 0x75, 0x68, 0xb6, 0x93, 0x1a, 0x77, 0xb8, 0x2f, 0x0f, 0xee, 0x6b, 0x3d, 0xb9, 0xa2, 0xad, 0x27, 0x6e, 0x37, 0xb5, 0x9e, 0x34, 0xae, 0xfa, 0xa0, 0x71, 0x2d, 0xb0, 0x0f, 0x58, 0xfe, 0xe9, 0x5a, 0x50, 0x84, 0xb4, 0x32, 0x0b, 0x8a, 0x10, 0xd6, 0x1f, 0x54, 0x47, 0x6d, 0xff, 0x56, 0x54, 0xb3, 0x6a, 0x44, 0x11, 0xd6, 0x7a, 0x76, 0x36, 0x8e, 0xcb, 0x60, 0xe3, 0x90, 0x2e, 0x21, 0x36, 0x0e, 0xf4, 0x48, 0x84, 0x5f, 0x9f, 0xf6, 0x3a, 0x1c, 0xa5, 0x42, 0x4d, 0x94, 0x95, 0x99, 0x1f, 0x44, 0xa8, 0x22, 0x8c, 0x95, 0x9a, 0x20, 0x0a, 0x97, 0x53, 0x6f, 0xa8, 0x8b, 0x7a, 0x69, 0x25, 0x55, 0x59, 0x07, 0xac, 0x8b, 0x88, 0x90, 0x79, 0xcd, 0x37, 0xd2, 0x55, 0x93, 0x31, 0x05, 0x6c, 0x55, 0x35, 0xa5, 0x08, 0x59,\n\t0xfd, 0x8f, 0xd8, 0x52, 0xdc, 0x5a, 0x66, 0x4b, 0x11, 0xa6, 0x7a, 0x0e, 0x6d, 0x29, 0xdc, 0xad, 0xdb, 0x52, 0xc0, 0x52, 0xcf, 0xc6, 0x96, 0xaa, 0xed, 0xd7, 0x96, 0xaa, 0x37, 0x98, 0x52, 0xc0, 0x50, 0x7f, 0xb8, 0xad, 0x43, 0x04, 0x1d, 0x6c, 0x1d, 0x6a, 0x97, 0xcd, 0x38, 0xa7, 0xfc, 0x34, 0xbd, 0xc8, 0x02, 0xf4, 0x3a, 0x03, 0x0f, 0x8a, 0xf0, 0x53, 0x6f, 0x32, 0xb7, 0x62, 0xb4, 0xe2, 0xe0, 0x33, 0x5b, 0xd0, 0x39, 0xab, 0x4f, 0x5b, 0xea, 0xd5, 0xfa, 0x54, 0xdb, 0x8a, 0xf1, 0x53, 0x5a, 0x1f, 0xd8, 0x56, 0x94, 0x9f, 0xce, 0x38, 0x87, 0xfc, 0x54, 0xad, 0x4d, 0xb5, 0xad, 0x80, 0x9f, 0xb2, 0xba, 0xde, 0xfc, 0x94, 0xf1, 0xd3, 0x73, 0x65, 0x5b, 0xb1, 0x6a, 0x98, 0x6d, 0x85, 0xdb, 0x58, 0x1d, 0x0f, 0xaa, 0xfc, 0xf4, 0x4c, 0x6d, 0x2b, 0x33, 0x41, 0x4d, 0x90, 0x22, 0xb6, 0x15,\n\t0x21, 0xa8, 0xf1, 0x2e, 0x28, 0x7a, 0xed, 0x31, 0x4a, 0x50, 0xcf, 0xdc, 0xee, 0xa9, 0x8d, 0xb2, 0x7b, 0x9a, 0xa9, 0xd9, 0x03, 0x06, 0xb9, 0xd1, 0x0e, 0xa1, 0x5c, 0x0e, 0xc6, 0xf9, 0x6c, 0xf8, 0xa9, 0xca, 0xd5, 0x33, 0x70, 0x69, 0x84, 0x9f, 0x52, 0xc2, 0x1e, 0xf2, 0x08, 0xde, 0xe0, 0x0f, 0xaf, 0xc7, 0x15, 0xd3, 0xb0, 0x62, 0xfc, 0x54, 0x37, 0xac, 0x34, 0x7e, 0x7a, 0x0e, 0xea, 0xea, 0x6b, 0x54, 0x31, 0x7e, 0xaa, 0x1b, 0x55, 0x1a, 0x3f, 0x9d, 0x66, 0xe6, 0xa7, 0xfd, 0x71, 0xe1, 0xd8, 0xfc, 0x34, 0xb6, 0x41, 0xf5, 0x61, 0xc4, 0x9e, 0x02, 0x82, 0x1a, 0xa9, 0xc3, 0x06, 0xbc, 0x4f, 0xa6, 0x21, 0xf9, 0xce, 0x88, 0x9c, 0x9a, 0x0c, 0x29, 0xd5, 0x8c, 0x12, 0xad, 0xe8, 0xec, 0xf6, 0x63, 0x78, 0xc6, 0x4f, 0xdf, 0xdf, 0x80, 0xe7, 0xab, 0xab, 0xce, 0xaa, 0xd1, 0xdc, 0xf2, 0x7a,\n\t0xf3, 0xbc, 0x1a, 0x98, 0x9f, 0xc6, 0x21, 0x6b, 0x84, 0x9f, 0xfa, 0xc9, 0x60, 0x0e, 0xc1, 0x8c, 0xa0, 0x7e, 0xa1, 0xec, 0xd8, 0x80, 0x2f, 0xb3, 0x14, 0xa5, 0x6b, 0x04, 0x35, 0xf4, 0xe0, 0x68, 0x6e, 0x45, 0xb2, 0x17, 0x23, 0x64, 0xde, 0x7f, 0x39, 0x15, 0xe7, 0x2a, 0x30, 0x71, 0x54, 0xb8, 0xed, 0xa6, 0x92, 0xd4, 0xaf, 0x94, 0x43, 0xac, 0x06, 0x9d, 0xa5, 0xfe, 0x2d, 0xf4, 0x4b, 0x5a, 0x07, 0xdd, 0xf0, 0x35, 0xea, 0x3d, 0x90, 0x9d, 0x7e, 0xeb, 0x20, 0xb2, 0x53, 0x60, 0xe2, 0xa9, 0xec, 0x46, 0x1d, 0x5b, 0x16, 0xfe, 0xa8, 0x9c, 0x60, 0x95, 0x44, 0x98, 0x2a, 0xfe, 0x2e, 0xf4, 0x35, 0xab, 0x46, 0xa3, 0xaa, 0xe7, 0xa8, 0xae, 0x5f, 0x2a, 0x1f, 0xb3, 0xba, 0x0c, 0x6c, 0x35, 0x53, 0x71, 0xd0, 0xba, 0x8c, 0x7c, 0xf5, 0x2c, 0xea, 0xaa, 0x8d, 0xae, 0xeb, 0x35, 0xe5, 0x33, 0xb5,\n\t0x2e, 0x9d, 0xb1, 0x8e, 0x56, 0xb2, 0x69, 0x55, 0x3a, 0x67, 0x3d, 0x1b, 0x7b, 0xc7, 0x65, 0xb0, 0x77, 0xf8, 0x79, 0x60, 0xef, 0xb0, 0x3d, 0xb0, 0x45, 0xa6, 0xbd, 0xc8, 0x7e, 0x74, 0xa8, 0x61, 0x2f, 0x92, 0xf0, 0x5e, 0x0c, 0x52, 0xaf, 0xd2, 0x5e, 0xe5, 0x36, 0x42, 0xaf, 0x45, 0x3c, 0x51, 0xa7, 0xbd, 0xca, 0x2b, 0x84, 0x5e, 0x0b, 0xb8, 0xa0, 0xd8, 0x64, 0x4b, 0x91, 0x35, 0x40, 0x93, 0xd5, 0x7e, 0x79, 0x6f, 0x9e, 0x2b, 0xb2, 0x06, 0x30, 0x7b, 0xca, 0xd5, 0xd7, 0x9e, 0xe2, 0x5f, 0x55, 0xed, 0xa9, 0x61, 0x26, 0x7b, 0x0a, 0xb8, 0x97, 0xde, 0xdf, 0xfd, 0x73, 0xaf, 0x18, 0x66, 0x95, 0x2b, 0x86, 0x59, 0xc5, 0xed, 0xd6, 0xcd, 0x2a, 0x42, 0x28, 0x8d, 0x76, 0x08, 0xac, 0x9b, 0xa7, 0xaa, 0xe7, 0x4c, 0xcc, 0x2b, 0xc2, 0x3e, 0x0c, 0xe6, 0x95, 0xc6, 0xb5, 0xcf, 0xbe, 0xbe, 0xda,\n\t0x53, 0x98, 0x59, 0xcd, 0x06, 0x2b, 0x8b, 0xad, 0x4d, 0xd1, 0xbc, 0x7e, 0xe0, 0x75, 0xda, 0x95, 0xa7, 0x8f, 0x11, 0x28, 0x73, 0xcd, 0xfe, 0x01, 0x9e, 0x4c, 0xcc, 0x9f, 0xa0, 0x2a, 0x07, 0x94, 0x24, 0x6f, 0xe6, 0xc6, 0xd5, 0xc7, 0xb0, 0x7d, 0x06, 0xe6, 0xad, 0xe0, 0xfe, 0x4f, 0x2d, 0x5f, 0x66, 0xe6, 0x95, 0xca, 0x8d, 0x23, 0xc6, 0x15, 0x10, 0x63, 0x62, 0x5a, 0x81, 0xf4, 0xfe, 0x47, 0x6c, 0x2b, 0xdc, 0x4d, 0x6d, 0x2b, 0x8d, 0xbb, 0x9e, 0x1b, 0xbb, 0xc7, 0x64, 0x5b, 0xd5, 0xab, 0xa6, 0x15, 0x21, 0xb0, 0x3f, 0xdc, 0xee, 0x81, 0x5d, 0xe1, 0x25, 0x6f, 0xb2, 0xfd, 0xe0, 0x73, 0x60, 0xf7, 0x88, 0x3a, 0x7d, 0x65, 0xa6, 0x42, 0x3a, 0x1e, 0x16, 0x61, 0xaf, 0x60, 0x2e, 0x7c, 0xc3, 0x4f, 0x6c, 0x39, 0x67, 0x36, 0x96, 0xc6, 0x02, 0x4c, 0x36, 0x16, 0x63, 0xae, 0x9a, 0x8d, 0x45,\n\t0x88, 0xab, 0xc9, 0x86, 0xf8, 0xa1, 0x76, 0x16, 0x61, 0x02, 0x26, 0x3b, 0x0b, 0x98, 0xab, 0x6a, 0x67, 0x11, 0xe2, 0xfa, 0x1f, 0xb1, 0xb3, 0x40, 0x5d, 0x81, 0x9d, 0x45, 0x58, 0x6b, 0xa4, 0x7c, 0x2b, 0x8c, 0xb7, 0xa5, 0x9f, 0xf1, 0xb6, 0x92, 0xc5, 0x3b, 0xc2, 0x2b, 0x0d, 0x56, 0xd6, 0x32, 0xee, 0xaf, 0x94, 0xae, 0x82, 0x89, 0xf5, 0x12, 0x7e, 0x43, 0xe5, 0xaa, 0x33, 0xce, 0x96, 0xab, 0xaa, 0x36, 0x50, 0x3d, 0x35, 0x81, 0x74, 0x7b, 0xea, 0x5c, 0x70, 0x55, 0x95, 0xb7, 0x27, 0xe2, 0xc1, 0x11, 0xae, 0xca, 0x8c, 0x9f, 0x1c, 0xa1, 0x23, 0xf8, 0xc3, 0xeb, 0x71, 0xc5, 0x34, 0xb2, 0x18, 0x57, 0xd5, 0x8d, 0x2c, 0x8d, 0xab, 0xce, 0x38, 0x37, 0x5c, 0xd5, 0x6c, 0x60, 0x31, 0xae, 0xaa, 0x1b, 0x58, 0x1a, 0x57, 0x9d, 0x71, 0x2e, 0xb8, 0xaa, 0xd9, 0xb8, 0xfa, 0x30, 0x62, 0x5b, 0x31,\n\t0xae, 0x3a, 0xe3, 0x07, 0x72, 0x55, 0x93, 0x51, 0xa5, 0x9a, 0x54, 0x1a, 0x57, 0x9d, 0x76, 0x96, 0x5c, 0xf5, 0xdd, 0xcd, 0xb8, 0x5b, 0xd5, 0x14, 0x3f, 0xab, 0xe5, 0x0f, 0xb4, 0x98, 0xcf, 0x28, 0xce, 0x92, 0xab, 0xfe, 0x4d, 0x79, 0x88, 0x14, 0x2b, 0x95, 0x66, 0x6a, 0x5c, 0xb5, 0xf7, 0xd2, 0x5a, 0xfe, 0xc5, 0x74, 0x1f, 0x8e, 0x65, 0x17, 0x9c, 0x0d, 0x57, 0x0d, 0x23, 0xe5, 0x05, 0x56, 0x83, 0xce, 0x55, 0x3f, 0xe8, 0x7d, 0x88, 0xd6, 0xa1, 0x72, 0xd5, 0x69, 0xe7, 0x80, 0x3f, 0x7e, 0xa6, 0x1c, 0x67, 0x95, 0x18, 0xb8, 0xea, 0x87, 0xbd, 0x27, 0x58, 0x35, 0x06, 0xae, 0x3a, 0xed, 0x9c, 0xf0, 0xe2, 0xdf, 0xb2, 0xba, 0x22, 0x5c, 0x95, 0xfb, 0xb6, 0xf7, 0x24, 0xad, 0xcb, 0xc8, 0x55, 0xa7, 0x9d, 0x03, 0xae, 0xfa, 0xb6, 0xf2, 0xb1, 0x5a, 0x97, 0xce, 0x55, 0xd3, 0x43, 0x29, 0xb4,\n\t0x2a, 0x9d, 0xab, 0x9e, 0x8d, 0xed, 0xe3, 0x32, 0xd8, 0x3e, 0x64, 0x35, 0x00, 0xdb, 0xc7, 0xb4, 0x7f, 0x71, 0xda, 0x67, 0xf2, 0x32, 0xac, 0x29, 0x8c, 0xab, 0x7e, 0xa8, 0xdc, 0x45, 0x78, 0xb5, 0x9c, 0xa4, 0x51, 0xd5, 0x63, 0xa1, 0xb5, 0x84, 0x54, 0xbb, 0x9d, 0xc0, 0x54, 0xfb, 0xec, 0x57, 0x0c, 0xcc, 0x55, 0xc9, 0x3a, 0x9f, 0x1f, 0xe1, 0xaa, 0x9a, 0xbc, 0xba, 0xfa, 0xda, 0x56, 0xfc, 0xab, 0x9a, 0x6d, 0x35, 0x0c, 0xf5, 0x3d, 0xdb, 0x3e, 0x0d, 0x5e, 0x17, 0x4b, 0x6c, 0x5d, 0xb1, 0x4c, 0x2c, 0x6e, 0x77, 0xc4, 0xc4, 0x62, 0x7b, 0xa0, 0xe6, 0xbd, 0xa5, 0x53, 0xd5, 0x75, 0x66, 0xa6, 0x16, 0x5e, 0x61, 0x32, 0xb5, 0x62, 0xec, 0x9d, 0x9d, 0x49, 0x7d, 0xb5, 0xa7, 0x34, 0xb7, 0x9a, 0x4d, 0xd6, 0x16, 0xe3, 0xad, 0x3f, 0xd4, 0x06, 0xe2, 0xfc, 0x60, 0x03, 0xb1, 0xbd, 0xaa, 0x45,\n\t0x67, 0x7a, 0x46, 0xcf, 0x4b, 0x44, 0xb2, 0xd4, 0x2d, 0x62, 0xd9, 0xa5, 0xdc, 0xb1, 0x00, 0xcf, 0xc3, 0x17, 0x6b, 0xd4, 0x37, 0xc1, 0xa1, 0x1c, 0x5a, 0x82, 0x1b, 0xb9, 0x4b, 0xeb, 0xcf, 0xca, 0xbe, 0x92, 0xa1, 0x6c, 0xa2, 0xaa, 0x29, 0xf1, 0x95, 0x04, 0x28, 0x5c, 0x33, 0xb0, 0x08, 0xf5, 0x95, 0x78, 0x28, 0x1c, 0x0c, 0x2c, 0x4a, 0x80, 0xff, 0x23, 0x36, 0x16, 0xb7, 0x96, 0xd9, 0x58, 0x74, 0x5f, 0xf8, 0x3f, 0x65, 0x63, 0xe1, 0x6e, 0xdd, 0xc6, 0x22, 0xe4, 0xf5, 0x07, 0xd9, 0x3c, 0xa7, 0xb0, 0xb1, 0xea, 0x8d, 0x26, 0x16, 0xe5, 0xdc, 0xe7, 0xc4, 0xe6, 0x01, 0xf6, 0x41, 0xac, 0x92, 0x06, 0xdc, 0x15, 0x21, 0xc8, 0x9b, 0xf9, 0x0d, 0x2d, 0xe7, 0xa2, 0x7c, 0x8d, 0x71, 0x44, 0x6c, 0x2a, 0x46, 0x8a, 0x89, 0x4d, 0xa5, 0xf1, 0xe1, 0x73, 0x61, 0x57, 0x11, 0xa6, 0x11, 0xb1, 0xab,\n\t0x80, 0x08, 0x13, 0xbb, 0x0a, 0x66, 0x04, 0x8a, 0x71, 0x2e, 0x36, 0x80, 0x5c, 0x91, 0x41, 0x8f, 0xb6, 0x7b, 0xb2, 0xf9, 0x88, 0x5d, 0x95, 0xe9, 0xe1, 0x54, 0xd6, 0x4a, 0x0c, 0xab, 0x44, 0x8e, 0xb2, 0xd6, 0x33, 0xb7, 0x7b, 0x6a, 0xa3, 0xec, 0x9e, 0x22, 0x30, 0x7b, 0x54, 0xfe, 0xbb, 0xf0, 0xb4, 0x39, 0x57, 0x7f, 0x06, 0x0f, 0x50, 0x56, 0xc6, 0xd9, 0x13, 0x71, 0x67, 0x84, 0xb1, 0x02, 0x6f, 0xff, 0xa7, 0xb0, 0x2e, 0xf8, 0x83, 0xeb, 0x70, 0xc5, 0x32, 0xaa, 0x18, 0x5b, 0x55, 0x8d, 0x2a, 0x8d, 0xab, 0xfe, 0x90, 0x7a, 0xfa, 0x31, 0xa8, 0x18, 0x53, 0xd5, 0x0c, 0x2a, 0xee, 0x60, 0x94, 0x3d, 0x05, 0x67, 0xd1, 0xf6, 0xfe, 0xce, 0xfc, 0x8d, 0x86, 0x54, 0xed, 0x80, 0x86, 0xd4, 0x87, 0xba, 0x1d, 0x45, 0x48, 0xaa, 0xd1, 0xce, 0x61, 0xdc, 0xaf, 0x3f, 0x8e, 0x4a, 0x4c, 0x9d, 0x24,\n\t0x9d, 0xa3, 0x6a, 0x16, 0x94, 0x32, 0xd4, 0x64, 0x40, 0x31, 0xf3, 0x09, 0x18, 0xea, 0x99, 0xdf, 0x1b, 0xd1, 0xf8, 0xe9, 0x89, 0x7b, 0xf0, 0x22, 0x75, 0x60, 0x53, 0x0a, 0x05, 0x25, 0x68, 0xbc, 0x93, 0x10, 0x07, 0x7d, 0x20, 0xe1, 0x33, 0xa6, 0xa7, 0x1f, 0x2b, 0x0f, 0xdc, 0x83, 0x17, 0x12, 0xd1, 0xd1, 0xe8, 0xe9, 0xc9, 0xf2, 0x42, 0xe1, 0x64, 0x66, 0x3e, 0x36, 0xdd, 0xa9, 0xc8, 0x0b, 0xfa, 0xe2, 0x25, 0xb5, 0x9d, 0x03, 0x52, 0xd3, 0x02, 0x13, 0x35, 0xfd, 0x46, 0x79, 0x86, 0x15, 0xae, 0x33, 0xd3, 0x77, 0x4f, 0x2e, 0xa1, 0xc5, 0xb3, 0x6b, 0xb3, 0xa6, 0x3b, 0x22, 0xa4, 0x0e, 0x47, 0x7f, 0x75, 0x0c, 0xb8, 0xb6, 0x7f, 0xa3, 0x1c, 0x63, 0xb5, 0x18, 0xa8, 0xe9, 0x9b, 0x27, 0x77, 0xb1, 0x7a, 0x18, 0x35, 0x3d, 0x27, 0xf5, 0xfc, 0x4d, 0x79, 0x8b, 0xd5, 0x63, 0xa0, 0xa5, 0xbf,\n\t0x3b, 0xf9, 0x7b, 0x5a, 0x8f, 0x4a, 0x4b, 0xcf, 0xa6, 0x9e, 0xda, 0xbe, 0x5c, 0xe5, 0x7d, 0xb5, 0x1e, 0x8d, 0x92, 0xf2, 0xff, 0xea, 0xe5, 0x68, 0x35, 0xda, 0x85, 0xda, 0xb3, 0xb3, 0x71, 0x5c, 0x06, 0x1b, 0x87, 0x4c, 0x5c, 0xb0, 0x71, 0xc8, 0x94, 0x35, 0xda, 0x38, 0xbe, 0x60, 0x96, 0x5d, 0x8a, 0x79, 0x47, 0xca, 0xb4, 0xbc, 0xd3, 0x06, 0x33, 0x4e, 0xfa, 0x07, 0xe5, 0x6e, 0x52, 0x22, 0xef, 0xb2, 0x6b, 0xa4, 0xf4, 0x48, 0x6f, 0x07, 0x61, 0xcf, 0x0e, 0x8f, 0x85, 0xed, 0x9f, 0x4e, 0x3b, 0x17, 0x9c, 0x34, 0xca, 0x86, 0xe2, 0x5f, 0xd5, 0x6c, 0xa8, 0x61, 0x51, 0x36, 0xd4, 0x0f, 0xe4, 0xa4, 0x7d, 0x4c, 0x29, 0x6e, 0x77, 0xc4, 0x94, 0x62, 0x9c, 0x74, 0xda, 0xb9, 0xe3, 0xa4, 0x7d, 0x4c, 0x2a, 0xc2, 0x49, 0x8d, 0x26, 0x15, 0xe5, 0xa4, 0xd3, 0xce, 0x1d, 0x27, 0xed, 0x63, 0x56,\n\t0x35, 0x9b, 0xac, 0x2a, 0xc6, 0x49, 0x7f, 0xa8, 0xad, 0x43, 0x14, 0x35, 0xd8, 0x3a, 0x44, 0x43, 0x9f, 0xf9, 0xdd, 0x4e, 0xc6, 0x49, 0x35, 0x6b, 0xe7, 0x37, 0x3c, 0x21, 0x8e, 0x84, 0x44, 0xf3, 0x32, 0x9e, 0xad, 0xf1, 0x52, 0x8b, 0x18, 0xba, 0x8e, 0x90, 0x68, 0x8b, 0x95, 0x5b, 0x54, 0x8f, 0x62, 0x9c, 0x9f, 0x9e, 0xbe, 0x3d, 0xe5, 0xea, 0x63, 0x4f, 0xf1, 0xf3, 0x22, 0xf6, 0x54, 0x8c, 0xbb, 0xb5, 0xe7, 0xc8, 0x9e, 0xe2, 0xd6, 0xaa, 0xf6, 0x54, 0xd4, 0xdd, 0xda, 0x73, 0x6f, 0x4f, 0xe1, 0xee, 0x88, 0x3d, 0x65, 0xbe, 0x6b, 0x7b, 0x4e, 0x64, 0x29, 0xca, 0x9e, 0xaa, 0x37, 0x99, 0x53, 0x6c, 0x1f, 0xee, 0x4c, 0xed, 0x9b, 0xda, 0x28, 0xfb, 0xe6, 0x43, 0x30, 0x6f, 0xd4, 0xbb, 0x77, 0x66, 0x1b, 0xc4, 0x6a, 0x39, 0xa5, 0x0d, 0x42, 0x08, 0x85, 0x6e, 0xe0, 0xfc, 0x8a, 0x4b, 0x88,\n\t0x53, 0x36, 0x2f, 0xc0, 0x17, 0xe3, 0x79, 0x1a, 0xd1, 0x75, 0xa6, 0x59, 0xc0, 0x0a, 0xa9, 0xe5, 0x9f, 0x68, 0x41, 0x3f, 0xc4, 0x7e, 0xa2, 0x6c, 0xc5, 0x92, 0x08, 0xa5, 0xab, 0xf6, 0x13, 0xd0, 0x5c, 0x77, 0x9c, 0x6a, 0x3f, 0x51, 0x9b, 0x7f, 0x91, 0x69, 0x1e, 0xf4, 0xd3, 0x76, 0xe3, 0x3c, 0x90, 0x69, 0xdb, 0x55, 0x03, 0xea, 0x63, 0x5e, 0x14, 0xa0, 0xf8, 0x25, 0x3c, 0x9e, 0xac, 0x92, 0x5c, 0x5e, 0xe4, 0xa8, 0x09, 0xc5, 0xe1, 0x22, 0x8d, 0xeb, 0xfe, 0x07, 0x6c, 0x28, 0xdc, 0xc6, 0x6c, 0x28, 0xba, 0xe7, 0xbb, 0xe8, 0x4c, 0x65, 0x27, 0x62, 0xdb, 0x68, 0x36, 0x14, 0x6f, 0xb2, 0xa1, 0x22, 0x94, 0x5a, 0x35, 0xa2, 0x54, 0x5a, 0x1d, 0xe3, 0x2d, 0x0a, 0xd8, 0x05, 0xea, 0x37, 0xc0, 0x93, 0xe9, 0x08, 0xb3, 0xeb, 0xdf, 0xb2, 0x01, 0x32, 0x4c, 0xec, 0x82, 0x6a, 0x7c, 0x51, 0x84,\n\t0x09, 0x6f, 0x16, 0x7e, 0x16, 0x44, 0xe7, 0xa0, 0x7c, 0x57, 0x1f, 0xcb, 0x89, 0xb1, 0x60, 0x62, 0x39, 0x01, 0x03, 0x3e, 0x27, 0xe5, 0x9b, 0x2d, 0x27, 0xc6, 0x7e, 0x89, 0xe5, 0x04, 0xc4, 0xb7, 0xef, 0x3b, 0xa6, 0x7e, 0xcb, 0x37, 0x59, 0x4d, 0xb5, 0xfd, 0x59, 0x4d, 0x1f, 0x52, 0xa3, 0x09, 0xe6, 0x19, 0xbc, 0x9f, 0x0b, 0xa3, 0x70, 0x8e, 0x74, 0x21, 0x66, 0xef, 0xe7, 0x66, 0xb0, 0xe8, 0xd6, 0x33, 0xe0, 0xe5, 0x25, 0x0e, 0xfd, 0x23, 0xbc, 0x83, 0x03, 0x7f, 0xc3, 0x56, 0xe6, 0x03, 0x59, 0x0f, 0x0b, 0xca, 0x1e, 0xc3, 0x89, 0xfa, 0x63, 0x38, 0xe5, 0xcd, 0xd4, 0xd6, 0xfc, 0x79, 0xfc, 0xb8, 0xf8, 0x9a, 0xbc, 0xa5, 0x09, 0x25, 0x39, 0xe2, 0x9f, 0x53, 0xf2, 0x68, 0xd9, 0xea, 0xfb, 0x3a, 0x4e, 0x92, 0x46, 0xd0, 0x77, 0x5b, 0x6a, 0x79, 0xe4, 0xef, 0x7f, 0xf9, 0x4f, 0xbc, 0xeb,\n\t0xc4, 0x19, 0xc2, 0x46, 0xee, 0xb0, 0xb8, 0x8b, 0x93, 0x10, 0x8b, 0x21, 0x90, 0xcd, 0x6d, 0xe3, 0x0a, 0xf9, 0x5f, 0xf2, 0xa4, 0x2c, 0x84, 0x98, 0xaf, 0x38, 0x6c, 0xf0, 0x15, 0x87, 0x33, 0xb9, 0x6d, 0x82, 0x00, 0xbe, 0xe4, 0xd0, 0xa1, 0x58, 0xbe, 0xe4, 0x14, 0x41, 0x59, 0xa9, 0xbc, 0x19, 0x7e, 0x08, 0xa2, 0x12, 0x0c, 0xf8, 0x36, 0x2e, 0xd6, 0x1b, 0xba, 0x18, 0x6f, 0xed, 0x62, 0xbd, 0xc9, 0x8b, 0xf9, 0x76, 0xaf, 0xcf, 0x1b, 0x3f, 0x32, 0x16, 0x56, 0x6e, 0x7f, 0xf8, 0xe7, 0xfc, 0x03, 0xc8, 0x8b, 0xaa, 0x82, 0x15, 0x12, 0x3c, 0xf1, 0x47, 0xd3, 0xfa, 0x3e, 0xf5, 0xa7, 0xb1, 0x36, 0xfb, 0xbe, 0xf4, 0xef, 0x2f, 0x00, 0xa6, 0xf2, 0x89, 0xf6, 0x70, 0xb7, 0x68, 0x54, 0x6b, 0x7d, 0x9a, 0xf6, 0x6e, 0xb7, 0x78, 0x64, 0x6b, 0x9d, 0xf6, 0x6e, 0x37, 0xc3, 0x9f, 0xc1, 0xde, 0xec,\n\t0x92, 0x3f, 0xa8, 0xfe, 0x03, 0x85, 0x5c, 0xe9, 0x06, 0x2e, 0x80, 0x96, 0x80, 0x32, 0x17, 0x1f, 0x42, 0xf7, 0xd2, 0x39, 0x56, 0x85, 0x8a, 0xb9, 0x77, 0x71, 0x1d, 0xe9, 0xab, 0x46, 0xf6, 0xf4, 0xda, 0x89, 0x98, 0x07, 0x80, 0x59, 0x1c, 0x13, 0x4f, 0x2f, 0xb8, 0xe2, 0xa6, 0x32, 0xc4, 0x63, 0x4c, 0x23, 0xbf, 0xc1, 0xb3, 0x73, 0x1e, 0x1b, 0xe2, 0x5b, 0xe6, 0x43, 0x3c, 0x0a, 0x08, 0xbc, 0xf8, 0xee, 0x0d, 0xca, 0xdc, 0x1b, 0xb8, 0x47, 0x8b, 0xb7, 0x6c, 0xc1, 0x71, 0xff, 0xc9, 0xb2, 0xff, 0x1f, 0x78, 0xd7, 0x18, 0x91, 0x85, 0xf6, 0xfe, 0xdf, 0x3a, 0x92, 0xbc, 0x4d, 0xe2, 0xd6, 0xf0, 0x7e, 0xf9, 0x65, 0x74, 0x09, 0x7a, 0xb6, 0xf7, 0x5f, 0xf8, 0xbc, 0x96, 0xe9, 0xb5, 0x5e, 0xf2, 0xe7, 0xc3, 0xa1, 0x0b, 0xb8, 0x41, 0xe5, 0x2f, 0x94, 0x6f, 0xc5, 0x23, 0xc9, 0x9f, 0x2f, 0xe4,\n\t0x37, 0xc1, 0x9f, 0x91, 0x97, 0xfa, 0x56, 0x3c, 0x4f, 0xf5, 0xad, 0xc8, 0x0d, 0x52, 0x63, 0xaf, 0xf1, 0x9b, 0x98, 0x4f, 0xc6, 0x50, 0xa9, 0xf8, 0x52, 0xf8, 0xb0, 0xfc, 0x10, 0x2a, 0x80, 0xb7, 0xcb, 0xe1, 0xfd, 0x98, 0xbd, 0x61, 0xde, 0x4b, 0x3d, 0xc4, 0xbe, 0x10, 0xde, 0xaf, 0x46, 0x3f, 0xdb, 0xab, 0xcd, 0x93, 0x50, 0x83, 0xf2, 0x8b, 0xf0, 0xe3, 0xe1, 0x97, 0x30, 0x7d, 0xd7, 0xfc, 0x7d, 0x23, 0x9b, 0x47, 0xdf, 0x37, 0xea, 0xbf, 0xef, 0x16, 0x2e, 0x0e, 0x67, 0x13, 0x3d, 0x22, 0xe3, 0x5f, 0xeb, 0xdf, 0xfa, 0xb8, 0xf8, 0x45, 0xb8, 0x50, 0xce, 0x23, 0xd8, 0xdb, 0x3a, 0xf6, 0xbd, 0xb2, 0x59, 0xf9, 0x6b, 0x78, 0x0d, 0xc1, 0xfe, 0xac, 0xc9, 0x7d, 0xef, 0xaf, 0xc4, 0x2f, 0xd0, 0x56, 0x39, 0x9f, 0xd9, 0x57, 0x5a, 0xcc, 0x4b, 0x2d, 0x3a, 0x23, 0x0b, 0x58, 0x48, 0xd7, 0x1f,\n\t0x87, 0x6b, 0x18, 0xac, 0x3f, 0x6e, 0xea, 0xa3, 0x03, 0x7c, 0xf3, 0xd4, 0x0f, 0xe1, 0xab, 0xb7, 0x2a, 0x2f, 0xba, 0x32, 0x3c, 0xb7, 0x60, 0x65, 0x2c, 0x97, 0x78, 0xbd, 0xd5, 0x95, 0x94, 0xee, 0x92, 0xf3, 0x69, 0xd0, 0xf0, 0xe5, 0xf7, 0x43, 0xd4, 0xf0, 0x33, 0x78, 0xcb, 0xac, 0xa4, 0x0a, 0xeb, 0x88, 0xae, 0x82, 0xf7, 0xd7, 0xaf, 0x46, 0x30, 0xf1, 0x03, 0xe5, 0x6b, 0xe9, 0x24, 0xa6, 0x18, 0x3e, 0x5f, 0x8d, 0xfc, 0x7a, 0xbe, 0xe6, 0xaf, 0xa0, 0xd7, 0x45, 0xbe, 0xf1, 0x00, 0x69, 0x7b, 0x3c, 0x8b, 0x37, 0x6a, 0x0a, 0x9c, 0x39, 0x9d, 0x06, 0x14, 0x70, 0xfb, 0x83, 0xe0, 0x62, 0x84, 0xf7, 0x79, 0xe8, 0x69, 0x1a, 0xf5, 0x42, 0xe1, 0x1b, 0xa9, 0x5c, 0x8c, 0x37, 0x7a, 0xbc, 0x2e, 0xe5, 0xd5, 0x5f, 0xe6, 0xe6, 0x25, 0x5e, 0x8f, 0x15, 0xf1, 0x4b, 0x2c, 0x39, 0x71, 0xb6, 0xdd,\n\t0x73, 0x3f, 0x2b, 0xf7, 0x17, 0xa4, 0x4f, 0x6a, 0xf5, 0x72, 0x63, 0xc6, 0x21, 0x75, 0xe7, 0x40, 0xb9, 0x6e, 0xea, 0xba, 0x04, 0x36, 0xb7, 0xb2, 0x38, 0x4f, 0x2d, 0x94, 0xf9, 0x92, 0x92, 0xc7, 0x35, 0x38, 0x93, 0x13, 0x13, 0x2c, 0xe2, 0x17, 0x92, 0x73, 0xd7, 0x72, 0x5e, 0x8e, 0xa7, 0xfe, 0x4a, 0x7a, 0xaf, 0x23, 0x6d, 0xfd, 0x22, 0xd2, 0x56, 0x2d, 0x36, 0xea, 0xb4, 0x48, 0x6c, 0xd4, 0x7c, 0x7f, 0x02, 0x6b, 0xab, 0xac, 0x45, 0x6c, 0xf7, 0x39, 0x15, 0xff, 0x51, 0xe8, 0xe0, 0x8f, 0xac, 0x2e, 0x77, 0x9a, 0x8b, 0x6b, 0x90, 0x9e, 0xd9, 0xa9, 0x45, 0x64, 0x27, 0x65, 0x9e, 0xbc, 0x9f, 0xe8, 0xe8, 0x35, 0x44, 0x47, 0x67, 0x42, 0xfc, 0x45, 0xb7, 0xc8, 0xa9, 0x9b, 0x35, 0xaa, 0x87, 0x95, 0x4b, 0x1b, 0xfc, 0x75, 0x39, 0x34, 0xd6, 0x2b, 0x6d, 0x25, 0x2d, 0x55, 0xef, 0x84, 0x7a,\n\t0x08, 0x30, 0x4d, 0xd8, 0xe7, 0x1a, 0x68, 0xf4, 0xbb, 0x7f, 0x24, 0x95, 0xdc, 0xaf, 0xf7, 0xc8, 0x23, 0x8f, 0xd0, 0xa1, 0xfc, 0x13, 0xf9, 0xa3, 0x64, 0x93, 0x9c, 0xff, 0x7d, 0xcc, 0x61, 0x61, 0xdd, 0xf3, 0xda, 0x6b, 0x50, 0xb3, 0xdd, 0x03, 0xdf, 0x93, 0x49, 0xea, 0x0e, 0x91, 0xba, 0xb3, 0xa1, 0xee, 0x54, 0x4b, 0x74, 0xdd, 0x85, 0xb5, 0x81, 0x2a, 0xa8, 0x9b, 0x67, 0xb5, 0xaa, 0xd5, 0xbb, 0x59, 0xad, 0x6a, 0xf5, 0xa3, 0x5d, 0x19, 0x29, 0x9b, 0x3c, 0x69, 0xac, 0x7a, 0xf8, 0x46, 0xb5, 0xd2, 0x2d, 0x5b, 0xe9, 0x1f, 0xdf, 0x97, 0x72, 0xa0, 0x62, 0xa8, 0x9e, 0x7d, 0xb2, 0xdd, 0xf3, 0xd2, 0x4b, 0xec, 0xd3, 0x49, 0xfd, 0xdf, 0xf0, 0x8d, 0xe1, 0xbf, 0x08, 0x7e, 0xa2, 0xaf, 0x6f, 0x66, 0xde, 0xfc, 0x92, 0xc1, 0xd5, 0x02, 0x12, 0xd0, 0x4c, 0xea, 0xcc, 0x9d, 0x30, 0x36, 0x9e,\n\t0x87, 0x57, 0xe6, 0x2c, 0x3a, 0x5e, 0xaa, 0x01, 0xec, 0x04, 0xa5, 0x46, 0x1d, 0xef, 0xcd, 0xa7, 0x5e, 0x6e, 0xf3, 0xfa, 0xcf, 0x4c, 0x46, 0x8a, 0x7a, 0x5b, 0x01, 0xa0, 0x8f, 0xbb, 0x15, 0x70, 0x5c, 0x0b, 0x91, 0x5f, 0xbc, 0xc8, 0x4b, 0x1d, 0xaf, 0x40, 0xa8, 0x08, 0x3e, 0xb6, 0xe3, 0x95, 0xfa, 0x34, 0xba, 0x06, 0x4c, 0x99, 0x30, 0x22, 0xb2, 0x06, 0x4c, 0x19, 0x3f, 0x3c, 0x8d, 0xac, 0x0e, 0x42, 0x66, 0xf4, 0x2a, 0x50, 0x58, 0x46, 0xf5, 0x8d, 0xd0, 0x18, 0xde, 0x27, 0xed, 0x67, 0xfa, 0x26, 0xbc, 0xa3, 0xa5, 0xb0, 0x71, 0x2d, 0xd5, 0x37, 0x0d, 0xe8, 0xaa, 0xea, 0x11, 0xd5, 0x15, 0x54, 0xdf, 0x34, 0x70, 0x19, 0xf0, 0x67, 0x94, 0x4e, 0xf5, 0xc6, 0x0e, 0x55, 0x6f, 0x5c, 0xa5, 0xaa, 0x1b, 0x2e, 0x43, 0xf3, 0xef, 0x30, 0x4a, 0x68, 0x0a, 0xdf, 0x27, 0x55, 0x10, 0x7d, 0xb3,\n\t0x8f, 0xe8, 0x9b, 0xdb, 0x30, 0xf3, 0xa3, 0xb0, 0x5d, 0xd5, 0x37, 0xb7, 0xa9, 0xf9, 0xb6, 0xeb, 0xf3, 0xea, 0x0d, 0x61, 0x23, 0x1a, 0x4e, 0xf8, 0x40, 0x7c, 0x24, 0xae, 0xe7, 0x4c, 0x20, 0xa4, 0xdd, 0x1c, 0x23, 0xd6, 0x71, 0xaa, 0x2e, 0xe0, 0x23, 0xba, 0x00, 0x57, 0x0f, 0xff, 0xcc, 0x99, 0xe1, 0xb9, 0x02, 0x2b, 0xa5, 0x9c, 0xaf, 0xdd, 0xe1, 0xf3, 0x8b, 0xbb, 0x20, 0xd6, 0x03, 0x5e, 0xb5, 0xcc, 0xe3, 0xa1, 0x65, 0x56, 0x12, 0x8e, 0x71, 0x3f, 0x2d, 0x33, 0x25, 0xe8, 0xa6, 0xa2, 0x4f, 0x3b, 0xbb, 0x1b, 0x8f, 0x31, 0xcf, 0x51, 0xe6, 0x29, 0xc6, 0x37, 0x5b, 0xa9, 0xc4, 0xd4, 0x6b, 0xd1, 0x01, 0x7f, 0xae, 0x63, 0x04, 0x97, 0x21, 0xdc, 0x82, 0xc1, 0x75, 0x91, 0xc7, 0x43, 0xb4, 0x53, 0xef, 0x9f, 0x49, 0xfb, 0x5c, 0xa4, 0x2c, 0x3b, 0xc4, 0x9f, 0xd0, 0x78, 0x13, 0x75, 0x2d,\n\t0x4c, 0x8a, 0xf3, 0x45, 0x4f, 0xcd, 0x14, 0x8f, 0x0b, 0x4a, 0xba, 0x2a, 0xa4, 0x70, 0xed, 0xa4, 0x30, 0x61, 0x63, 0xbc, 0x6b, 0xcd, 0x2a, 0x88, 0x41, 0xd1, 0xfb, 0x00, 0x69, 0xd3, 0x71, 0xbd, 0x1c, 0x3a, 0x27, 0x59, 0x48, 0x6d, 0xae, 0x1b, 0x8d, 0xf1, 0x9b, 0xa6, 0x63, 0x3d, 0xdd, 0xdf, 0x53, 0x84, 0xab, 0xe0, 0x23, 0xef, 0x24, 0xdf, 0xc7, 0xb5, 0x8b, 0x65, 0x6b, 0x58, 0x30, 0x0b, 0xfa, 0x7d, 0x4d, 0xa4, 0x4d, 0xf1, 0xa4, 0x2c, 0x2f, 0xcc, 0x6f, 0x75, 0x2e, 0x92, 0x99, 0xc0, 0xa1, 0xe5, 0x6a, 0xcf, 0xd5, 0xc5, 0x9c, 0x8d, 0xbc, 0x3a, 0x1b, 0x31, 0x9d, 0x8d, 0xf1, 0xd0, 0xd0, 0xcd, 0x77, 0x90, 0x3a, 0xd6, 0x6b, 0xdf, 0x3e, 0x6f, 0x3e, 0xa9, 0xec, 0xa8, 0xda, 0xee, 0x07, 0x1e, 0x70, 0xc5, 0xb3, 0x6e, 0x78, 0xec, 0x31, 0x8f, 0x87, 0x7e, 0xc3, 0x44, 0x52, 0x6f, 0x09,\n\t0xad, 0x97, 0xe8, 0x6f, 0x8f, 0xd5, 0x50, 0x2f, 0x7d, 0x68, 0xce, 0x86, 0xcc, 0x8b, 0xd2, 0xab, 0x03, 0xd5, 0xc0, 0x5b, 0xdd, 0xe6, 0x09, 0xa9, 0x56, 0x4c, 0x5b, 0x50, 0x5d, 0x02, 0x23, 0x78, 0xb3, 0xd6, 0x02, 0xfa, 0x95, 0x50, 0xf1, 0xfc, 0x4b, 0xf4, 0xe1, 0x64, 0x2d, 0xf8, 0x12, 0xaa, 0x7e, 0xfc, 0x71, 0x52, 0x3d, 0xf5, 0xa5, 0x71, 0x45, 0xf8, 0x61, 0x69, 0x23, 0x44, 0x01, 0xed, 0x9d, 0xc2, 0xe2, 0x97, 0x86, 0xba, 0xd1, 0x2f, 0x30, 0xf5, 0xad, 0x11, 0x1e, 0x30, 0x0a, 0x29, 0xd2, 0xf2, 0xdf, 0xa1, 0xe6, 0x1f, 0xc6, 0x62, 0x98, 0x86, 0x1e, 0x38, 0xc3, 0xfc, 0x0f, 0x4b, 0xb7, 0x41, 0x24, 0xd1, 0x1f, 0x50, 0x3f, 0xcb, 0xdf, 0x72, 0x16, 0xf5, 0x4f, 0x13, 0x06, 0x91, 0xfa, 0x9f, 0x23, 0x73, 0xeb, 0x00, 0x49, 0xff, 0x88, 0xda, 0x0f, 0x34, 0xa2, 0x29, 0x69, 0xc7, 0x80,\n\t0x11, 0x4d, 0xf5, 0xfc, 0xeb, 0xa3, 0xf2, 0xb7, 0xb2, 0x68, 0xaa, 0xa1, 0x07, 0x4f, 0x33, 0xff, 0xad, 0xd2, 0x8b, 0x86, 0xfc, 0x8d, 0xbd, 0x43, 0xd5, 0xfa, 0xa7, 0x9d, 0x76, 0xfd, 0xe6, 0xfc, 0x4d, 0xa7, 0x5f, 0x3f, 0xe1, 0x59, 0xb3, 0xc2, 0xff, 0x90, 0xae, 0x24, 0xf9, 0x08, 0xf7, 0x0a, 0x7f, 0xc5, 0xfa, 0x0d, 0x97, 0x81, 0x7f, 0x69, 0xfe, 0x85, 0xf0, 0x57, 0x90, 0x9e, 0x27, 0x8b, 0x76, 0x99, 0xaa, 0x8b, 0xd4, 0xf4, 0x27, 0x0c, 0xe9, 0x49, 0xbd, 0xb8, 0x31, 0x3a, 0x7d, 0xa3, 0x39, 0x3d, 0x94, 0x3f, 0xfc, 0xcc, 0xca, 0x67, 0xe5, 0x62, 0x99, 0xe5, 0x53, 0xfd, 0x5d, 0x37, 0xd2, 0xef, 0x50, 0x33, 0x52, 0x1b, 0x86, 0x68, 0x22, 0x71, 0xa2, 0x3c, 0x84, 0xf0, 0x6d, 0x9e, 0x6e, 0x9e, 0xec, 0xc4, 0xf1, 0x31, 0xf1, 0xdd, 0x26, 0xdc, 0xab, 0xe3, 0x4f, 0xe3, 0xb4, 0x08, 0x2e,\n\t0x7d, 0xa1, 0xe3, 0xcf, 0x9a, 0xf0, 0x6f, 0x75, 0xfc, 0x39, 0x13, 0xfe, 0xb0, 0x8e, 0xbf, 0x60, 0xc4, 0x65, 0xb7, 0x8e, 0xbf, 0x68, 0xc2, 0xbb, 0x74, 0xfc, 0x25, 0x9c, 0x1e, 0xc1, 0x2d, 0x41, 0x1d, 0x7f, 0x05, 0x7b, 0xa9, 0x4f, 0x2a, 0x8a, 0xd3, 0xbd, 0xa2, 0x64, 0x54, 0x11, 0x2c, 0x85, 0x78, 0x28, 0xb8, 0x43, 0x54, 0xfd, 0x68, 0xcd, 0x26, 0xcb, 0x58, 0x09, 0x75, 0x12, 0x5c, 0x0a, 0x9e, 0xde, 0x20, 0xc0, 0x94, 0x83, 0x18, 0x34, 0xb0, 0x77, 0x24, 0xc9, 0xc4, 0x9c, 0xe1, 0x03, 0x05, 0x0e, 0x2c, 0xf3, 0xcc, 0x85, 0x9c, 0x8f, 0xaa, 0x0c, 0x5c, 0xcd, 0xef, 0x3a, 0xe1, 0xf1, 0xd8, 0x3d, 0xf6, 0xb7, 0xf9, 0x27, 0x1e, 0xc9, 0xc8, 0xb3, 0xac, 0x0a, 0xdd, 0xb4, 0x4a, 0x0e, 0x78, 0x1f, 0xe1, 0x9a, 0x7f, 0xc3, 0x79, 0xb8, 0xb2, 0xc6, 0x69, 0x25, 0x1d, 0x99, 0xa1, 0x13, 0xa1,\n\t0xbf, 0x66, 0xa4, 0xe0, 0xb1, 0xca, 0x3e, 0x77, 0x36, 0xa9, 0x5b, 0x6f, 0x1f, 0x8d, 0x3f, 0xc7, 0x53, 0xff, 0x43, 0x7f, 0x0f, 0x97, 0x86, 0x7f, 0xcb, 0xe2, 0xf2, 0x84, 0x7f, 0x4b, 0x07, 0x81, 0x23, 0xa9, 0x90, 0x38, 0x9e, 0xa4, 0xb7, 0xa0, 0x14, 0x68, 0xab, 0xd0, 0xa7, 0xad, 0x69, 0xb4, 0xad, 0xe9, 0xd0, 0xd6, 0x94, 0xe4, 0xa4, 0x44, 0xa7, 0xc3, 0x6e, 0x25, 0x89, 0x2d, 0x92, 0x04, 0x6d, 0x2d, 0xc7, 0xb1, 0x1a, 0xfb, 0xc4, 0x09, 0xd2, 0x54, 0xd6, 0xda, 0x1d, 0x19, 0x7e, 0xeb, 0xaa, 0xd0, 0xba, 0x55, 0x96, 0x7c, 0xef, 0x0e, 0xae, 0xf9, 0x5d, 0x68, 0x6d, 0xc6, 0xe8, 0xe2, 0x92, 0xd1, 0x7d, 0x9a, 0x4b, 0xdb, 0xab, 0x6c, 0x86, 0x7e, 0xd3, 0xfa, 0x13, 0xff, 0x19, 0xa7, 0x18, 0xfa, 0x3f, 0x4f, 0xc7, 0xdf, 0x36, 0xf6, 0xbf, 0xfc, 0x90, 0x8e, 0xbf, 0x63, 0x1a, 0x2f, 0x7d,\n\t0x7c, 0xf1, 0xbb, 0x26, 0xfc, 0x73, 0x1d, 0x7f, 0xcf, 0x88, 0x5b, 0xda, 0x75, 0xfc, 0x7d, 0x0d, 0x87, 0xf6, 0xe8, 0xf2, 0x56, 0xc0, 0xe4, 0x2d, 0xba, 0x5d, 0x96, 0x80, 0x9e, 0xef, 0x0f, 0xa6, 0xf2, 0xf2, 0x75, 0xfc, 0x03, 0x13, 0x1e, 0xf9, 0x8e, 0x8f, 0xfa, 0xa9, 0xff, 0x63, 0x53, 0xfd, 0x6e, 0xbd, 0xfe, 0x17, 0x63, 0xd5, 0x6f, 0x98, 0x0f, 0x7b, 0x4d, 0xdf, 0xf9, 0xbc, 0x9e, 0x8f, 0xc8, 0x37, 0x4e, 0xc2, 0xaa, 0xfc, 0xb3, 0xf1, 0xc7, 0x49, 0xaa, 0x8f, 0x7a, 0x96, 0xf6, 0x7d, 0x53, 0x5a, 0x32, 0x73, 0xd1, 0x11, 0x43, 0xda, 0x46, 0x53, 0x5a, 0xbd, 0x3e, 0x71, 0x7b, 0xec, 0x79, 0x23, 0x3e, 0x68, 0xc2, 0x33, 0x74, 0xf9, 0x3b, 0x82, 0x53, 0x09, 0xca, 0xe4, 0x2f, 0x4c, 0xe5, 0x8f, 0x27, 0x12, 0x08, 0x63, 0xfe, 0x7b, 0x92, 0xd6, 0x8e, 0xf2, 0xd0, 0xd2, 0xa0, 0x2d, 0x2f,\n\t0xc3, 0x22, 0x62, 0x11, 0x49, 0xe0, 0xec, 0x2e, 0x87, 0x46, 0x17, 0x13, 0x38, 0x61, 0x39, 0x26, 0x2c, 0x17, 0xf6, 0x05, 0xf8, 0xd9, 0xcc, 0x8d, 0x97, 0x24, 0xcd, 0xe9, 0x14, 0x31, 0x0d, 0x5a, 0xea, 0xed, 0x9b, 0x04, 0x7e, 0x25, 0xe9, 0xb8, 0xe9, 0x6a, 0x92, 0xae, 0x20, 0x61, 0x0a, 0x7e, 0x9f, 0x37, 0x3d, 0x2d, 0xd5, 0x93, 0x9c, 0xe8, 0x72, 0xc4, 0x09, 0x10, 0x8e, 0x93, 0xb3, 0xc2, 0xf6, 0x81, 0x1d, 0xfb, 0xab, 0x71, 0x01, 0x9d, 0x74, 0xaa, 0x18, 0x33, 0x33, 0xcb, 0x8f, 0xab, 0xbd, 0x18, 0xa8, 0x32, 0xe6, 0x77, 0xcd, 0x3f, 0xf6, 0xde, 0x60, 0x5c, 0xd6, 0x40, 0xa7, 0x20, 0x77, 0x82, 0xce, 0x40, 0xa5, 0x4c, 0x39, 0xea, 0x09, 0xe6, 0x4c, 0x99, 0x70, 0x3e, 0x99, 0x84, 0xd7, 0x7c, 0x66, 0x4f, 0x4c, 0x4a, 0x4d, 0x5c, 0xa4, 0xac, 0xe5, 0x3c, 0xd8, 0xae, 0x7c, 0x8d, 0xb7,\n\t0xde, 0x41, 0xe7, 0xe4, 0xc9, 0x57, 0xa8, 0x88, 0x8f, 0xcf, 0xf1, 0x2e, 0x12, 0xb7, 0x29, 0x3f, 0xc5, 0xc3, 0x9c, 0xc9, 0x71, 0x52, 0xe8, 0xbb, 0xc8, 0xdc, 0x7c, 0x45, 0xef, 0xb3, 0x86, 0xb0, 0x8b, 0xc6, 0xaf, 0x1b, 0x17, 0x85, 0xb7, 0x28, 0x8f, 0x53, 0xbc, 0x31, 0x0a, 0x1f, 0xa2, 0xe2, 0xf7, 0x53, 0x5d, 0x76, 0x5c, 0xc7, 0x5b, 0xc3, 0xa9, 0x86, 0xb9, 0x7f, 0x44, 0xc7, 0x1b, 0x19, 0x1e, 0x1e, 0x15, 0x85, 0x07, 0xd5, 0x72, 0xea, 0xa2, 0xf0, 0xb6, 0x7e, 0xca, 0x1f, 0x6a, 0x2a, 0x7f, 0x9f, 0x8e, 0x0f, 0x56, 0xcb, 0xff, 0x36, 0x0a, 0x6f, 0x32, 0xa6, 0x3f, 0x13, 0x9d, 0xab, 0x5c, 0x61, 0xd4, 0x05, 0xe2, 0x68, 0xf0, 0x0e, 0xa8, 0xe3, 0x5a, 0x3f, 0x14, 0xb0, 0x7e, 0x8b, 0xfc, 0x1e, 0x1e, 0x17, 0xf5, 0x3b, 0xed, 0x3f, 0xc3, 0xef, 0x8d, 0x51, 0xbf, 0x0f, 0x89, 0xfa, 0xfd,\n\t0x7e, 0xf8, 0x5d, 0xff, 0xde, 0x02, 0xd6, 0x9f, 0x7d, 0xea, 0x3f, 0xa2, 0xff, 0xde, 0x68, 0xfe, 0x3d, 0x3c, 0x2a, 0xea, 0xf7, 0x60, 0x54, 0xf9, 0x75, 0x51, 0xbf, 0xb7, 0x9d, 0xa2, 0xfe, 0xa1, 0x51, 0xf5, 0x83, 0xbb, 0xf2, 0xf1, 0x32, 0x8f, 0xc8, 0xef, 0x0a, 0xe8, 0x82, 0x6a, 0x55, 0x17, 0x50, 0x5c, 0xfa, 0x56, 0xc3, 0xc9, 0x5c, 0x57, 0x75, 0x84, 0x52, 0x69, 0xec, 0x47, 0xce, 0x89, 0xd9, 0x38, 0xfd, 0x1b, 0x21, 0xe9, 0x0b, 0xba, 0xc6, 0x8a, 0x6c, 0x8d, 0xe5, 0x87, 0x47, 0x70, 0x3a, 0x4e, 0x0c, 0x7f, 0x81, 0x9f, 0x40, 0xe3, 0xb3, 0x7d, 0x45, 0xf0, 0x7f, 0x10, 0x45, 0x2d, 0xa2, 0x54, 0x34, 0x2e, 0xd8, 0x89, 0xb1, 0x48, 0xd6, 0x09, 0x24, 0x41, 0x28, 0x1a, 0x79, 0x96, 0x15, 0xd6, 0x0b, 0x0b, 0x82, 0x40, 0xc8, 0xa2, 0xd0, 0x45, 0x17, 0x0d, 0x1b, 0xb6, 0x58, 0x58, 0x1c,\n\t0x6f, 0xb2, 0x74, 0x48, 0x12, 0xc9, 0x9d, 0x2a, 0xa5, 0x7a, 0xc8, 0x0a, 0xe2, 0x4e, 0x74, 0x25, 0x38, 0xe3, 0x6d, 0x56, 0x8b, 0x4c, 0xca, 0x12, 0xed, 0x74, 0x19, 0x21, 0x73, 0xcf, 0x8a, 0x65, 0x9f, 0xb6, 0x82, 0xf8, 0x92, 0x7d, 0x10, 0x96, 0xd9, 0xcd, 0x3f, 0x38, 0xc3, 0x91, 0xe5, 0x54, 0xde, 0x16, 0x13, 0x70, 0xef, 0xbf, 0x2b, 0x42, 0xef, 0x3f, 0x69, 0x2f, 0xca, 0x7c, 0x90, 0xfb, 0xa7, 0x60, 0x0b, 0xe5, 0x36, 0x70, 0xb9, 0xa1, 0x7f, 0x0d, 0x26, 0xcb, 0xc9, 0x27, 0xa5, 0x63, 0x72, 0x43, 0xcf, 0x2a, 0x77, 0xef, 0xc6, 0xab, 0x94, 0x67, 0x52, 0xbc, 0xe2, 0xb6, 0xdd, 0x4a, 0xe3, 0x63, 0x34, 0xa6, 0x21, 0x0f, 0xf1, 0xb4, 0x84, 0x7d, 0xf4, 0x5e, 0x2e, 0x44, 0x18, 0x1f, 0x1e, 0x1c, 0x9a, 0x85, 0x31, 0x17, 0xb9, 0x96, 0x23, 0x63, 0x9e, 0x17, 0xa6, 0x5b, 0x30, 0xac, 0xc7,\n\t0xb0, 0xcb, 0x48, 0xdd, 0xc0, 0x97, 0x8a, 0x63, 0x92, 0x93, 0xec, 0x76, 0x8c, 0x02, 0x79, 0x49, 0x05, 0xc9, 0x05, 0x76, 0xb7, 0x3d, 0xd1, 0x11, 0x67, 0x95, 0x91, 0x0d, 0xdb, 0xac, 0x64, 0x79, 0xce, 0x67, 0xd1, 0xa9, 0xfc, 0xbe, 0x34, 0xd5, 0x05, 0xa2, 0xbf, 0x56, 0x8b, 0x49, 0x25, 0xb8, 0x58, 0x7c, 0x64, 0xee, 0x99, 0x89, 0xcb, 0x47, 0xe7, 0xde, 0xb9, 0x55, 0x79, 0xfb, 0xeb, 0xfb, 0xee, 0xbd, 0x63, 0xcb, 0x4d, 0x87, 0xaf, 0x69, 0xca, 0x69, 0x9b, 0x3b, 0x1c, 0x37, 0x0e, 0xbf, 0xfe, 0x95, 0x15, 0xa1, 0x93, 0x4f, 0x04, 0xda, 0xa6, 0xd7, 0x75, 0xaf, 0x54, 0x7c, 0xc2, 0x18, 0xa5, 0x78, 0xd5, 0xc2, 0x95, 0x3d, 0x8f, 0xd5, 0xcc, 0xbe, 0xf9, 0xfc, 0x9a, 0x8b, 0x27, 0xb7, 0xa5, 0x0c, 0x51, 0xbe, 0x99, 0xf1, 0xe3, 0xc5, 0xcd, 0xa4, 0xc5, 0x67, 0xd0, 0xf6, 0xb4, 0x48, 0xdb,\n\t0xd3, 0x07, 0x68, 0xbb, 0xf4, 0xbf, 0xd8, 0x76, 0x2b, 0x69, 0xfb, 0x31, 0x7a, 0x0e, 0xe8, 0x41, 0x15, 0x68, 0x62, 0x70, 0x5c, 0x2e, 0xc6, 0x20, 0x2d, 0x10, 0x7b, 0x5a, 0xc0, 0x73, 0xac, 0x98, 0xb3, 0x60, 0xe6, 0xa5, 0x53, 0x14, 0xa5, 0xe9, 0x76, 0x0c, 0xea, 0x1a, 0x3c, 0xc4, 0xd3, 0x18, 0xf7, 0x73, 0xe5, 0x31, 0x69, 0xa9, 0x18, 0x95, 0x97, 0x95, 0x96, 0x14, 0x17, 0xa6, 0x56, 0xa4, 0x55, 0x78, 0x92, 0x5d, 0x4e, 0xb8, 0x78, 0x43, 0x3e, 0xc4, 0x81, 0x1d, 0x71, 0x36, 0xc3, 0x87, 0x40, 0xf0, 0xcd, 0x64, 0x17, 0xfb, 0x18, 0xa2, 0xb2, 0xa3, 0xbf, 0x06, 0x82, 0x74, 0x72, 0x47, 0xb5, 0x2f, 0x3a, 0x7c, 0x98, 0x7e, 0x53, 0x38, 0x1c, 0xfd, 0x55, 0x07, 0x0e, 0xa8, 0xdf, 0x75, 0xdf, 0x96, 0xc7, 0xb9, 0x2b, 0x62, 0x7e, 0x16, 0x9e, 0xb8, 0x85, 0xdf, 0x8b, 0xd4, 0x18, 0x6d, 0xc2,\n\t0x3e, 0xd9, 0x4f, 0xe6, 0x87, 0xa4, 0xc6, 0x98, 0x39, 0x8a, 0xe7, 0x90, 0x35, 0x0d, 0x88, 0xf0, 0x1c, 0x75, 0x9d, 0xdc, 0xab, 0x6c, 0x86, 0xb1, 0x63, 0x69, 0x60, 0xbd, 0x46, 0x5f, 0xa9, 0x31, 0xac, 0xbe, 0x36, 0xe2, 0xe2, 0x47, 0x2a, 0xde, 0x15, 0xfe, 0x5c, 0x74, 0xc8, 0x43, 0x20, 0xde, 0x4c, 0x98, 0xf1, 0xdd, 0x5b, 0x0d, 0xb8, 0x57, 0xc7, 0x9f, 0xc6, 0x5b, 0x63, 0xe2, 0x7b, 0x4d, 0x78, 0x06, 0xc3, 0xe9, 0x7a, 0xbb, 0x85, 0xae, 0xb7, 0x58, 0x5f, 0x6f, 0xb1, 0x1e, 0xdb, 0xa6, 0x0c, 0x8d, 0x08, 0xb6, 0xb9, 0xb1, 0xc0, 0xf1, 0x64, 0xb1, 0xe5, 0x3a, 0x10, 0x2f, 0x20, 0xb2, 0x28, 0xf6, 0x10, 0x59, 0x82, 0x48, 0x16, 0x8b, 0xb5, 0xa0, 0xca, 0x34, 0xb4, 0x14, 0x0b, 0x04, 0x07, 0xae, 0x5f, 0x0b, 0xf2, 0x33, 0xbd, 0xa9, 0x29, 0x2e, 0xa7, 0x2c, 0xa2, 0x32, 0x5c, 0x26, 0xc3,\n\t0xe4, 0xad, 0x52, 0xe3, 0xad, 0xe0, 0x53, 0x85, 0x07, 0x12, 0xb6, 0x25, 0xc6, 0x9f, 0x77, 0x7e, 0xe8, 0x99, 0x6d, 0xa1, 0x7d, 0xb3, 0x4f, 0x15, 0x09, 0x08, 0xd7, 0x38, 0x66, 0x2c, 0x58, 0xb6, 0xf0, 0x08, 0x76, 0x3c, 0x34, 0x40, 0xd0, 0x1f, 0xe0, 0xda, 0x39, 0x84, 0x3f, 0xcc, 0x20, 0xfc, 0xc1, 0x8e, 0xda, 0xd0, 0xc6, 0x60, 0x72, 0x73, 0x63, 0x25, 0x4f, 0xb4, 0x0a, 0xe6, 0xe4, 0x40, 0x3a, 0x87, 0xb9, 0x1c, 0xcc, 0xd3, 0x20, 0x6b, 0x39, 0x34, 0x9a, 0x92, 0x0c, 0xf1, 0x3a, 0xb8, 0x1e, 0x4a, 0x6d, 0x31, 0xf9, 0x44, 0x5e, 0x58, 0x4e, 0xa8, 0x42, 0x24, 0xb6, 0x60, 0x37, 0x0b, 0x46, 0x88, 0x58, 0x48, 0x48, 0x92, 0x41, 0x12, 0xa5, 0x65, 0x31, 0x73, 0xc5, 0xca, 0xd0, 0x15, 0xb4, 0x17, 0x14, 0x14, 0xe6, 0xe7, 0x05, 0x8a, 0x73, 0xa9, 0x5f, 0x51, 0xd5, 0xa7, 0x7a, 0x12, 0xb1,\n\t0xf0, 0x99, 0x1b, 0xf5, 0x7a, 0x76, 0xc0, 0xcd, 0x1e, 0x32, 0xb0, 0x3d, 0xb9, 0x40, 0xa4, 0xd3, 0xe8, 0xb6, 0x9c, 0x9c, 0x85, 0x59, 0xef, 0x15, 0xf0, 0x5f, 0x16, 0x74, 0x8f, 0x82, 0x5e, 0x29, 0x2d, 0x9e, 0xd2, 0x7a, 0xdf, 0xf4, 0x48, 0x84, 0x24, 0xe8, 0xc2, 0x6b, 0xde, 0x9a, 0xb2, 0x02, 0xc8, 0xc7, 0x27, 0xe7, 0x75, 0xd1, 0x9e, 0x9c, 0xf9, 0xf0, 0x88, 0x6a, 0xc6, 0x40, 0x36, 0xd9, 0x93, 0xed, 0xd0, 0xa9, 0x8e, 0x14, 0xe1, 0x67, 0x89, 0x69, 0xd0, 0x5d, 0xf3, 0x1e, 0x6f, 0x9b, 0xdf, 0x30, 0x58, 0x8d, 0x92, 0x44, 0x3a, 0x75, 0x78, 0xf0, 0xd1, 0x1c, 0x2f, 0x1e, 0x3c, 0x8b, 0x8c, 0x07, 0xed, 0xda, 0x42, 0x7f, 0x3b, 0xb0, 0x92, 0x23, 0x56, 0xb7, 0x8d, 0xf4, 0xb1, 0xe3, 0x2c, 0x64, 0xa4, 0x5a, 0x97, 0x91, 0x9a, 0x18, 0x32, 0x22, 0xff, 0xdf, 0xcb, 0x48, 0x97, 0xb2, 0x95,\n\t0xce, 0x2f, 0x3b, 0x3a, 0x0f, 0x0b, 0xea, 0x29, 0x4b, 0x3d, 0xb6, 0xca, 0x45, 0x09, 0x9c, 0xc0, 0x79, 0x31, 0x2f, 0xf0, 0x1d, 0x5e, 0x33, 0x22, 0xf2, 0x1d, 0x6a, 0x1c, 0xd1, 0x46, 0xea, 0x99, 0x18, 0xc9, 0x3d, 0xc8, 0x6e, 0xb1, 0x59, 0xec, 0xb6, 0x1e, 0x70, 0xa3, 0x6b, 0xc7, 0x16, 0x88, 0x4a, 0x49, 0xf5, 0x15, 0x91, 0x01, 0x9b, 0x8d, 0x9b, 0x2e, 0x11, 0xa6, 0xb9, 0xd0, 0xec, 0x7c, 0x97, 0xd5, 0x74, 0x26, 0x05, 0x2c, 0x89, 0xf2, 0xde, 0x1b, 0xec, 0x93, 0x57, 0xe0, 0x44, 0x0e, 0xbc, 0xf9, 0x0e, 0x54, 0x86, 0xd1, 0xa9, 0x6f, 0x57, 0x30, 0x71, 0xf2, 0xc4, 0xce, 0xd1, 0x43, 0x5b, 0xf3, 0x0b, 0xc1, 0xab, 0xaf, 0x3b, 0x9f, 0x06, 0x3f, 0xc0, 0xfa, 0x86, 0xb0, 0xdb, 0x81, 0x9d, 0xb8, 0x3f, 0xe7, 0xbe, 0xa7, 0x15, 0xf2, 0x8b, 0xbf, 0x30, 0xb2, 0x83, 0xfc, 0x7e, 0xf7, 0xc4,\n\t0x3f, 0x6d, 0x4b, 0x88, 0xe9, 0x06, 0xb8, 0xe8, 0xd6, 0xff, 0x79, 0xa4, 0xeb, 0x34, 0x02, 0x80, 0xc1, 0xc6, 0x33, 0xdb, 0x72, 0xfe, 0x6e, 0xe3, 0xcc, 0xa5, 0xd6, 0x86, 0x18, 0x0e, 0x83, 0xaf, 0xb1, 0x5d, 0x7e, 0x08, 0xf3, 0x5b, 0x07, 0x8c, 0x06, 0xa6, 0xe9, 0x6a, 0xf1, 0x6e, 0x6a, 0xaf, 0x58, 0x55, 0xfb, 0xc8, 0x6b, 0xc0, 0x33, 0xb4, 0x98, 0xb6, 0x44, 0x4f, 0x7a, 0xcd, 0x76, 0x09, 0xd5, 0xd5, 0xd7, 0x1a, 0xe3, 0xde, 0x12, 0x9b, 0x2b, 0x3b, 0xfc, 0xa9, 0x9a, 0xe6, 0x53, 0x3d, 0xcd, 0x07, 0xc6, 0x34, 0xe2, 0x47, 0x31, 0xd3, 0xac, 0x31, 0xa6, 0x91, 0x92, 0x63, 0xa5, 0x41, 0xc8, 0xb6, 0x8a, 0xc6, 0xfd, 0x64, 0xed, 0x2c, 0x95, 0x64, 0xad, 0x9d, 0xd6, 0x61, 0x06, 0x7c, 0xa3, 0xf8, 0x6f, 0x7d, 0x7f, 0xe1, 0x31, 0xe6, 0x3f, 0x1e, 0xb5, 0x06, 0x9b, 0x65, 0xcc, 0x49, 0xea,\n\t0x7a, 0x0a, 0x51, 0x6d, 0xac, 0x44, 0x84, 0x20, 0x80, 0xb4, 0xaa, 0xa3, 0xe6, 0x8a, 0x63, 0x12, 0x5d, 0x18, 0xe5, 0x64, 0x67, 0x65, 0x66, 0xa4, 0xbb, 0x7c, 0x89, 0x3e, 0x27, 0xbc, 0xb8, 0xb2, 0xa2, 0x04, 0x9c, 0x60, 0xd3, 0xd7, 0xd2, 0x72, 0x58, 0x2e, 0xc1, 0x35, 0x36, 0x66, 0xd1, 0xbc, 0x39, 0x49, 0xd0, 0xd6, 0xcf, 0x3f, 0x68, 0x41, 0xbc, 0x95, 0x17, 0x71, 0x86, 0xf2, 0x31, 0x6e, 0xa7, 0x61, 0xbb, 0x2f, 0x79, 0x49, 0xf9, 0x7e, 0x7b, 0xe8, 0xe3, 0x43, 0x87, 0x76, 0x75, 0xdc, 0xf2, 0xfa, 0xea, 0xeb, 0x8e, 0xdf, 0xd2, 0xa1, 0xe4, 0x5e, 0xa3, 0xa4, 0x08, 0x9f, 0x2f, 0x78, 0x59, 0xf9, 0x66, 0xfb, 0x83, 0xca, 0xb7, 0x2f, 0x2f, 0xe0, 0xee, 0xbe, 0x86, 0x46, 0x4f, 0xfc, 0x7f, 0xac, 0xbd, 0xea, 0x1a, 0x5f, 0x4a, 0xb9, 0xb1, 0x9d, 0xed, 0x4b, 0xa1, 0x3f, 0xc6, 0xc4, 0x77,\n\t0x9b, 0x70, 0xaf, 0x8e, 0x3f, 0x8d, 0x3e, 0x8d, 0x89, 0xef, 0x35, 0xe2, 0x74, 0x5f, 0x8a, 0xe1, 0xcf, 0x99, 0xf0, 0x87, 0x75, 0xfc, 0x05, 0x53, 0x39, 0x6e, 0x1d, 0x7f, 0xd1, 0x84, 0x67, 0x30, 0x1c, 0xe4, 0x18, 0x7d, 0xda, 0x67, 0xbd, 0xa7, 0x69, 0xe8, 0xfd, 0x8a, 0x8a, 0x60, 0x29, 0xe1, 0x66, 0x82, 0xc8, 0x0b, 0xb3, 0xd4, 0xc3, 0x34, 0x5c, 0x42, 0xc3, 0x74, 0xc3, 0x19, 0x18, 0x2a, 0xd5, 0x2f, 0x59, 0xc0, 0x3f, 0xb2, 0x9c, 0x56, 0x92, 0x2f, 0xfb, 0x34, 0x6f, 0xe9, 0x2e, 0xa1, 0x14, 0xf7, 0xde, 0xc8, 0x5f, 0x1d, 0x9a, 0xc1, 0xe5, 0x84, 0x3e, 0xd8, 0xbd, 0x5b, 0x63, 0xd9, 0xa4, 0x36, 0xc2, 0x64, 0x84, 0x9f, 0x8b, 0xfb, 0x08, 0x47, 0xb5, 0xc3, 0x5d, 0x0e, 0xd8, 0x65, 0x52, 0x9e, 0xa1, 0xbb, 0x4c, 0x58, 0xdf, 0x65, 0x3a, 0x65, 0x3b, 0xd2, 0x22, 0xed, 0x48, 0x37, 0xb7,\n\t0x43, 0x3a, 0xdd, 0x76, 0x0c, 0x38, 0x66, 0xb1, 0xfa, 0x9a, 0x70, 0xb4, 0x52, 0x3a, 0x2f, 0xed, 0xea, 0x9e, 0x0a, 0x32, 0xf4, 0x69, 0x9e, 0x8e, 0xbf, 0x8d, 0x3e, 0x33, 0x94, 0xf3, 0x85, 0x5e, 0xce, 0xb3, 0x86, 0x31, 0xf8, 0x8c, 0xee, 0x41, 0xb1, 0xf4, 0xef, 0xa8, 0xb8, 0x95, 0x96, 0xa3, 0x8f, 0x25, 0x7e, 0xd7, 0x90, 0x7e, 0x26, 0xdd, 0x83, 0x62, 0xf8, 0x7b, 0xc6, 0xb1, 0xa4, 0x7b, 0x40, 0x0c, 0x7f, 0xdf, 0xd8, 0x4e, 0x5d, 0x86, 0x0a, 0x98, 0x6c, 0x19, 0xda, 0x7b, 0xb3, 0x59, 0xc6, 0xc4, 0xed, 0xb1, 0x65, 0x46, 0x7c, 0x90, 0xe6, 0x23, 0xe3, 0xa0, 0x6c, 0xa5, 0xe3, 0x50, 0x80, 0xb6, 0xa9, 0x7e, 0xe6, 0xd3, 0x21, 0xfa, 0x5e, 0x1c, 0xf5, 0xfe, 0xe6, 0x8d, 0xfc, 0x8d, 0xd3, 0xfd, 0xcc, 0x17, 0x83, 0x95, 0x67, 0x21, 0x56, 0x9e, 0x66, 0xdc, 0xcd, 0xe9, 0x44, 0x16, 0x0b,\n\t0xdf, 0x65, 0xb3, 0x72, 0x10, 0x89, 0x59, 0x8f, 0x3b, 0xd4, 0x03, 0x77, 0x15, 0x2a, 0x11, 0xe6, 0x09, 0x5d, 0x20, 0x74, 0x69, 0xc0, 0x4c, 0x5a, 0xf8, 0xa1, 0x1e, 0x64, 0xf4, 0x3b, 0xef, 0x62, 0xae, 0xe7, 0xc1, 0xef, 0xbc, 0xaf, 0x5f, 0x8f, 0xf3, 0x11, 0x61, 0xf0, 0xc9, 0xdc, 0x6b, 0xfd, 0xf8, 0x9c, 0x57, 0x2e, 0xd0, 0x84, 0x84, 0xdb, 0x81, 0xfb, 0x71, 0x3a, 0xcf, 0x44, 0x67, 0x37, 0xe2, 0xc3, 0xaf, 0x12, 0x0e, 0xc9, 0xd1, 0x3d, 0x28, 0x09, 0x65, 0xa3, 0x2b, 0x9f, 0xcf, 0x76, 0x21, 0xb8, 0x37, 0xac, 0xf2, 0xc6, 0x22, 0xc2, 0x76, 0xc4, 0xe5, 0x16, 0x8c, 0xad, 0x70, 0x0a, 0x89, 0x66, 0xb1, 0x0d, 0x28, 0x8e, 0xa3, 0xd1, 0x75, 0xe6, 0x80, 0x47, 0x79, 0xfa, 0x81, 0x34, 0x44, 0x5c, 0x11, 0x6c, 0xe2, 0x2e, 0x8b, 0xce, 0x10, 0x2b, 0x6d, 0x57, 0xd0, 0x91, 0x95, 0xe9, 0xca,\n\t0x4f, 0xcc, 0xa3, 0x9f, 0x0d, 0xc1, 0x78, 0x70, 0x3d, 0xd1, 0x5f, 0x18, 0x3e, 0xcb, 0x57, 0xcb, 0xd8, 0xa1, 0xcb, 0x47, 0x49, 0x21, 0xae, 0x4e, 0xf6, 0xf1, 0xf8, 0x8e, 0xae, 0xae, 0xb7, 0xf1, 0xd8, 0xd0, 0x1f, 0xc9, 0x07, 0xf5, 0xde, 0x58, 0x0c, 0xec, 0xef, 0xdf, 0xfc, 0x15, 0x16, 0x75, 0xdf, 0x49, 0xd8, 0xa5, 0xbc, 0xf7, 0x3d, 0x27, 0x5f, 0xfd, 0x18, 0x7e, 0xed, 0xe4, 0x2b, 0xbb, 0xe5, 0x46, 0xc2, 0xf0, 0x26, 0x08, 0x07, 0xec, 0x74, 0xbb, 0xa9, 0xf3, 0x31, 0x65, 0xa7, 0x41, 0xb6, 0x2d, 0x99, 0xba, 0x4c, 0x6c, 0x30, 0xc8, 0xca, 0x08, 0x4b, 0x86, 0x2e, 0x63, 0xbb, 0x71, 0x1e, 0xfa, 0x03, 0x56, 0xf5, 0x0f, 0x8b, 0xc7, 0xf0, 0x07, 0x6d, 0xcf, 0x7e, 0xaf, 0x72, 0x8f, 0x71, 0xde, 0x90, 0xf5, 0x4c, 0x8b, 0xcf, 0xfb, 0x7a, 0x04, 0x87, 0x53, 0x4e, 0xc4, 0xa2, 0xbc, 0x63,\n\t0x3d, 0xca, 0x3b, 0xc7, 0x64, 0x4f, 0x76, 0x23, 0x17, 0x6a, 0x44, 0x6f, 0xa8, 0xd2, 0x57, 0xea, 0xe6, 0x44, 0x32, 0xd6, 0x82, 0x48, 0xa5, 0x4f, 0xfb, 0x9b, 0xa4, 0x4b, 0x5f, 0xa3, 0x03, 0xe2, 0xb6, 0xb2, 0xdb, 0x05, 0x16, 0x0e, 0xcd, 0x21, 0x06, 0xb1, 0x3d, 0xce, 0x66, 0x9f, 0x45, 0x98, 0x8f, 0xa5, 0x8b, 0x88, 0x14, 0xe9, 0xd4, 0xb8, 0x38, 0xb9, 0xcb, 0x19, 0xcf, 0x11, 0xd3, 0x91, 0xaa, 0x91, 0x48, 0xa0, 0xc9, 0xa0, 0x96, 0x57, 0x94, 0x21, 0xd0, 0x64, 0xcf, 0xe9, 0x95, 0x41, 0x46, 0x4a, 0x0f, 0x39, 0x19, 0xcc, 0x4b, 0x24, 0xd2, 0x99, 0xd8, 0x98, 0xd8, 0xd8, 0x50, 0x4f, 0xc4, 0xaf, 0xba, 0xaa, 0x72, 0x50, 0x45, 0x79, 0x59, 0x41, 0xbe, 0x2f, 0x27, 0x23, 0x9d, 0x7c, 0x86, 0x2b, 0x2f, 0x29, 0x37, 0x01, 0x6e, 0xa4, 0x25, 0x49, 0xfe, 0x48, 0x90, 0x93, 0xba, 0x5a, 0xfe,\n\t0xb4, 0xa4, 0x97, 0xdf, 0xfd, 0xd0, 0x6d, 0xa3, 0x96, 0x8d, 0x2f, 0xbe, 0x3b, 0x21, 0xbf, 0xb9, 0x74, 0xda, 0x88, 0x09, 0xa7, 0x23, 0xcb, 0xb2, 0x7b, 0xd5, 0xcd, 0x60, 0xbb, 0xfa, 0xeb, 0xf2, 0x93, 0xc6, 0x8e, 0xf8, 0xf6, 0xb3, 0x81, 0x65, 0x3b, 0x1c, 0x0e, 0x67, 0x51, 0xbd, 0xfb, 0x8a, 0x3e, 0xe6, 0xed, 0xa1, 0x7f, 0xd3, 0xfb, 0x1d, 0xd5, 0x51, 0x78, 0x4b, 0xe8, 0x16, 0x8a, 0x47, 0xa7, 0x1f, 0xc2, 0xf0, 0x70, 0x3e, 0xc5, 0x8f, 0xe8, 0x78, 0x63, 0x28, 0x44, 0xd3, 0x97, 0x45, 0xe1, 0x41, 0xb5, 0x1c, 0x6f, 0x14, 0xde, 0xa6, 0x96, 0x33, 0x8e, 0xe0, 0x95, 0x64, 0xbd, 0x20, 0xb8, 0x48, 0xf7, 0x0d, 0x15, 0x4e, 0xdb, 0xdf, 0x24, 0xe9, 0xf7, 0xe9, 0xe9, 0x9b, 0x94, 0x2e, 0x83, 0x1e, 0xe3, 0x75, 0xbd, 0x58, 0x6d, 0x90, 0xd9, 0x12, 0x6a, 0x87, 0xc7, 0xab, 0x76, 0xf8, 0x27,\n\t0xd4, 0x0e, 0xc7, 0x06, 0x3b, 0x1c, 0xec, 0xe1, 0x11, 0x54, 0x37, 0x3a, 0xd4, 0xf3, 0xa2, 0x5d, 0x28, 0x82, 0xbb, 0x75, 0xfc, 0x45, 0x13, 0x9e, 0xc1, 0x70, 0xca, 0x0b, 0x77, 0x9a, 0xd7, 0x53, 0x48, 0xa3, 0xac, 0x14, 0x47, 0x88, 0xbb, 0xf4, 0xbc, 0xff, 0x8d, 0xa7, 0xa2, 0x58, 0x75, 0xed, 0x35, 0x95, 0x39, 0x44, 0xc7, 0x77, 0xe3, 0xed, 0x11, 0x9c, 0xae, 0xf5, 0x0e, 0x75, 0x3f, 0x74, 0x97, 0xce, 0x4d, 0x47, 0xd3, 0x72, 0x9c, 0x6a, 0x9b, 0x97, 0x6a, 0xeb, 0x27, 0x8d, 0x0f, 0x62, 0x47, 0x05, 0xc1, 0x3c, 0xd8, 0x49, 0x41, 0x02, 0x9e, 0x45, 0x2f, 0x4b, 0x94, 0xd0, 0x4b, 0x15, 0x7d, 0xd7, 0x6f, 0x35, 0x74, 0x47, 0x24, 0x40, 0xc7, 0x3b, 0x86, 0x40, 0x1c, 0x5a, 0xcc, 0x8d, 0xf0, 0x65, 0xa4, 0xdc, 0x71, 0x74, 0x3c, 0x9c, 0x22, 0x5b, 0xbd, 0x53, 0xa2, 0x56, 0xef, 0x81, 0xea,\n\t0x4e, 0xa3, 0x75, 0xf7, 0x5d, 0xb3, 0x4f, 0xab, 0xee, 0x3e, 0xdf, 0xba, 0x17, 0xbe, 0x55, 0xc7, 0x33, 0x18, 0x4e, 0xc7, 0x61, 0x69, 0x9f, 0x71, 0x20, 0xeb, 0x22, 0xb4, 0x49, 0xcb, 0x4b, 0xd6, 0xc3, 0xe5, 0x91, 0xbc, 0x74, 0xbd, 0x77, 0xaa, 0x67, 0x7e, 0x6a, 0x99, 0xca, 0x36, 0x63, 0x7a, 0x29, 0x05, 0xae, 0xc5, 0xb3, 0xf9, 0x41, 0xf0, 0x57, 0x34, 0xdc, 0x38, 0x3f, 0x4c, 0xb8, 0x61, 0x7e, 0x98, 0x70, 0x75, 0x7e, 0x28, 0x6b, 0x68, 0xbd, 0xc7, 0x75, 0xbc, 0x95, 0xcd, 0x0f, 0x98, 0x37, 0x24, 0xfd, 0x11, 0x1d, 0x37, 0xcc, 0x1b, 0x13, 0x6e, 0x98, 0x37, 0x26, 0xbc, 0xad, 0x9f, 0xf2, 0x87, 0xaa, 0xe5, 0x8f, 0x33, 0x8e, 0x9f, 0x61, 0x3e, 0x55, 0xd2, 0x72, 0xf6, 0xe9, 0xe9, 0x9b, 0x94, 0x89, 0x6a, 0x3f, 0x5c, 0x61, 0xec, 0x07, 0x71, 0x34, 0x77, 0x3e, 0xeb, 0x07, 0x8a, 0x6b,\n\t0xdf, 0x55, 0xc0, 0xfa, 0x21, 0xf2, 0xbb, 0x52, 0x1d, 0xf5, 0x3b, 0xed, 0x0f, 0xc3, 0xef, 0xd1, 0xf9, 0x87, 0x44, 0xfd, 0xbe, 0x06, 0x7e, 0xd7, 0xdb, 0x5f, 0xc0, 0xfa, 0xc7, 0x50, 0x7f, 0x3e, 0xcd, 0x7f, 0x44, 0xff, 0xbd, 0xd1, 0xfc, 0xbb, 0x52, 0x16, 0xf5, 0x7b, 0x30, 0xaa, 0x7c, 0x6f, 0xd4, 0xef, 0x6d, 0xa7, 0xa8, 0x7f, 0x68, 0x54, 0xfd, 0x0f, 0x11, 0x49, 0xdb, 0x49, 0xe7, 0x29, 0x9c, 0x27, 0x48, 0x68, 0xe7, 0x1a, 0xb6, 0xae, 0x91, 0x52, 0xb8, 0x47, 0x0c, 0xf8, 0x6e, 0x86, 0x87, 0x7f, 0x47, 0xf0, 0x4b, 0xa9, 0xec, 0x32, 0xfc, 0xe9, 0x5b, 0x23, 0x78, 0x0f, 0xe5, 0x89, 0x0c, 0x7f, 0x56, 0xc5, 0x7f, 0x43, 0xf0, 0x4b, 0xa8, 0x5c, 0x32, 0xfc, 0x39, 0x86, 0xc3, 0xae, 0x3c, 0xd7, 0x44, 0xf5, 0x00, 0xc3, 0x5f, 0x50, 0xd3, 0xff, 0x9d, 0xe0, 0xec, 0x5c, 0x84, 0xe1, 0x2f,\n\t0xaa, 0xe9, 0xef, 0x27, 0xed, 0xdc, 0x4e, 0xe7, 0x06, 0x84, 0x39, 0x97, 0xd0, 0x91, 0x5b, 0xcd, 0x8c, 0x5f, 0x9d, 0xaf, 0xf8, 0x26, 0xba, 0x13, 0x0b, 0x77, 0x9b, 0x81, 0xe6, 0x33, 0x82, 0xef, 0x4a, 0xe0, 0xe4, 0x94, 0x12, 0x1f, 0x99, 0x96, 0xf8, 0xa6, 0x77, 0xde, 0x21, 0x09, 0x48, 0x3d, 0x53, 0x68, 0xda, 0x7d, 0x6a, 0x79, 0x30, 0xff, 0xb1, 0x79, 0xfe, 0xf7, 0xd7, 0xf6, 0x18, 0xf5, 0xa4, 0x75, 0x32, 0x02, 0x4f, 0xea, 0x91, 0xa2, 0xeb, 0xe9, 0xef, 0xfb, 0x89, 0x96, 0xc7, 0xbf, 0xa5, 0x7c, 0x9b, 0xe2, 0xf8, 0xed, 0xdb, 0x19, 0xbe, 0x43, 0xd9, 0x8c, 0xef, 0xa4, 0x72, 0xca, 0xf0, 0x3f, 0xdf, 0xcc, 0xfa, 0xe5, 0x44, 0x54, 0xbf, 0xef, 0x55, 0xfb, 0xab, 0x82, 0xe0, 0x9e, 0x08, 0x2e, 0x6e, 0x8f, 0xdd, 0x8f, 0xe2, 0x83, 0x2a, 0xfe, 0xa5, 0xf2, 0x3a, 0x37, 0x52, 0x2b, 0x1f,\n\t0xf8, 0x4a, 0x78, 0x83, 0x99, 0xaf, 0xa8, 0x6d, 0x7e, 0xd7, 0x32, 0x49, 0xcd, 0x4b, 0x78, 0x51, 0xf8, 0x79, 0x9c, 0x84, 0x59, 0xdb, 0xd9, 0x4a, 0x93, 0xa4, 0xdd, 0xc5, 0x08, 0x3b, 0x68, 0x5f, 0xbc, 0xa2, 0xa6, 0x05, 0x3d, 0xf2, 0x09, 0x95, 0x3b, 0x7f, 0x14, 0xde, 0x12, 0xfa, 0x2f, 0x8a, 0x47, 0xa7, 0x1f, 0xa2, 0xe2, 0xcb, 0x01, 0xa7, 0x72, 0xea, 0x52, 0xf5, 0x08, 0xb5, 0x3f, 0xc2, 0xc9, 0x34, 0xfd, 0x11, 0x1d, 0x6f, 0x64, 0xb8, 0x92, 0x19, 0x85, 0x07, 0xd5, 0x72, 0xec, 0x51, 0x78, 0x5b, 0x3f, 0xe5, 0x0f, 0x55, 0xcb, 0x6f, 0x34, 0xca, 0x01, 0xe8, 0x11, 0x15, 0xcf, 0x8e, 0xc2, 0x9b, 0x94, 0xd6, 0x33, 0x97, 0xdb, 0x33, 0x91, 0x95, 0x33, 0x93, 0x2b, 0xb4, 0x97, 0xac, 0xa3, 0xd9, 0x74, 0x8f, 0x84, 0xb6, 0x0f, 0xb9, 0x39, 0xa6, 0xef, 0x3d, 0xe1, 0xcf, 0xf9, 0x5b, 0xa8,\n\t0x3c, 0xb8, 0x55, 0x9b, 0x7c, 0x1f, 0x6d, 0x07, 0xc1, 0xb9, 0xa7, 0x48, 0xfa, 0x64, 0x34, 0xa9, 0x73, 0x4f, 0xc6, 0x84, 0xf3, 0xf7, 0xcb, 0xf4, 0x9d, 0xa9, 0x77, 0x3f, 0x8b, 0x91, 0xd7, 0x45, 0xc1, 0x20, 0x18, 0x00, 0x69, 0x11, 0xd3, 0xc6, 0x07, 0xa6, 0x4d, 0xaa, 0x6e, 0xda, 0xc0, 0x6f, 0x9a, 0x05, 0x43, 0x7e, 0xea, 0x7a, 0x2e, 0x39, 0x37, 0x29, 0x4f, 0x90, 0x52, 0xd5, 0xd8, 0x6f, 0x2c, 0xec, 0x38, 0x8d, 0x16, 0x5a, 0xeb, 0xaa, 0xe6, 0x9e, 0x6a, 0x5e, 0xbe, 0x73, 0xc9, 0xdc, 0xcb, 0xe2, 0x38, 0x8f, 0xc7, 0xd5, 0x34, 0x28, 0x38, 0x67, 0xb8, 0xff, 0x04, 0xfe, 0xea, 0xaa, 0x43, 0x37, 0x8c, 0xcc, 0xb8, 0x36, 0xd1, 0xe3, 0x0a, 0x4c, 0xbc, 0xf6, 0x7c, 0x7e, 0x37, 0xd2, 0xda, 0xc6, 0xcf, 0x20, 0x6d, 0xcb, 0x44, 0xdd, 0xac, 0x6d, 0x56, 0x7a, 0xe6, 0xe3, 0x85, 0xff, 0xf2,\n\t0x7a, 0xdb, 0xbc, 0x32, 0x9c, 0xbd, 0x21, 0x4e, 0x24, 0x96, 0x05, 0x18, 0x15, 0x70, 0xc7, 0x8d, 0x85, 0x67, 0x87, 0x5b, 0x93, 0xb9, 0x6a, 0x04, 0xb4, 0x9e, 0xa8, 0x54, 0x70, 0x6f, 0x5c, 0x4d, 0xd4, 0x15, 0x84, 0x85, 0x9a, 0xb4, 0x39, 0x9f, 0x05, 0xc0, 0xf2, 0x27, 0x47, 0x37, 0xbb, 0x05, 0xc3, 0x56, 0x0a, 0xf9, 0x1f, 0x3f, 0xa3, 0x6f, 0xeb, 0xdf, 0x78, 0xe3, 0xc4, 0x53, 0xdc, 0xba, 0x3b, 0x4d, 0x5f, 0x70, 0xef, 0x16, 0xee, 0xea, 0xd0, 0x8d, 0x6c, 0x7d, 0x59, 0x29, 0x0e, 0xa1, 0xf3, 0x2a, 0x49, 0xe5, 0x47, 0x92, 0xce, 0x5f, 0x08, 0x4e, 0xfa, 0x8b, 0x70, 0x88, 0x6c, 0xfd, 0x3c, 0x88, 0x30, 0x89, 0x39, 0x22, 0x36, 0x90, 0x98, 0x7c, 0x9f, 0xcb, 0x55, 0x94, 0x23, 0xc9, 0xe9, 0x64, 0x9c, 0x09, 0xa5, 0x2e, 0xc0, 0xe5, 0x3c, 0x65, 0x13, 0xd5, 0x70, 0xcc, 0x53, 0x4f, 0x9f,\n\t0x64, 0x60, 0x07, 0x96, 0x53, 0x3c, 0xe2, 0x90, 0x03, 0x49, 0x99, 0xc9, 0x2e, 0x59, 0x29, 0xb0, 0x25, 0xa5, 0xe7, 0x7a, 0xa6, 0x9d, 0x38, 0xd1, 0x1e, 0xa8, 0x70, 0xe3, 0x9f, 0xa5, 0x94, 0xe7, 0x3e, 0x17, 0xfa, 0x7b, 0x52, 0x20, 0xa5, 0xbe, 0x48, 0xb2, 0x27, 0xd8, 0xb9, 0x41, 0xf1, 0x89, 0x76, 0x31, 0xf4, 0x23, 0x42, 0x3a, 0x36, 0xbb, 0x3d, 0x9c, 0xdb, 0x9b, 0x1c, 0xda, 0x96, 0xe6, 0xb3, 0xbb, 0x07, 0xab, 0x5c, 0x61, 0x08, 0x95, 0x91, 0x24, 0x95, 0x7f, 0x0c, 0xd2, 0x39, 0xc4, 0x10, 0xaa, 0xf3, 0x93, 0x54, 0xce, 0x96, 0xa7, 0xd9, 0xe2, 0xc6, 0x6f, 0x23, 0x9c, 0x43, 0xd2, 0xce, 0x75, 0x8c, 0xb8, 0xf8, 0x91, 0x8a, 0xdf, 0x83, 0x10, 0xff, 0x17, 0x5a, 0x4e, 0x32, 0x5b, 0x3b, 0x36, 0x69, 0xb6, 0xd2, 0x4a, 0xfe, 0x2f, 0x34, 0x7d, 0x32, 0xeb, 0x23, 0xb4, 0x83, 0xf6, 0x11,\n\t0x91, 0x54, 0xfe, 0x3b, 0xfa, 0xb6, 0xaa, 0x2c, 0x58, 0x2c, 0x80, 0x4b, 0x76, 0x2c, 0x71, 0x78, 0x16, 0x82, 0xd7, 0x30, 0x10, 0x08, 0x14, 0x5d, 0x60, 0x7a, 0x61, 0x45, 0xff, 0xb1, 0xd8, 0xd2, 0x4b, 0xf2, 0x93, 0xd9, 0xde, 0x17, 0xf9, 0x5f, 0xb2, 0xdf, 0xc5, 0x7f, 0xd7, 0xfb, 0xfa, 0x9e, 0x3d, 0x27, 0x5e, 0x7f, 0x7d, 0xdf, 0x3e, 0x6e, 0x1d, 0x1d, 0x97, 0x2d, 0x8a, 0x66, 0xbb, 0x6d, 0x36, 0xd6, 0x8b, 0xff, 0x0c, 0xf5, 0x12, 0xdc, 0x01, 0x38, 0x9d, 0xcb, 0x80, 0x17, 0x30, 0x1c, 0xe6, 0xf4, 0x16, 0xad, 0xbd, 0x5f, 0x1b, 0xf3, 0x89, 0x1f, 0xa9, 0xf9, 0x88, 0x2d, 0x68, 0xc4, 0xa5, 0x64, 0x0d, 0x0f, 0x7f, 0x2e, 0xfd, 0x9e, 0xce, 0x49, 0xf6, 0x7d, 0x6e, 0xa1, 0x42, 0x4d, 0x7f, 0x97, 0x78, 0x8f, 0x78, 0x40, 0xc7, 0xe7, 0x0b, 0x59, 0x9a, 0x6c, 0x48, 0x3f, 0x26, 0xe9, 0x73,\n\t0xe0, 0xbb, 0xd3, 0xe3, 0x39, 0x10, 0x76, 0x32, 0xd9, 0xc0, 0x78, 0xee, 0x11, 0x85, 0x28, 0x8a, 0x9b, 0x83, 0xb2, 0x7d, 0xc9, 0x75, 0x2e, 0x49, 0x4e, 0xa5, 0x72, 0x01, 0xd1, 0x6b, 0xa5, 0x12, 0x9c, 0x5b, 0x80, 0x53, 0x92, 0x41, 0x4c, 0x20, 0x6e, 0x33, 0x8d, 0x68, 0x0a, 0x4f, 0xfc, 0xa4, 0x1f, 0xbf, 0xc8, 0x73, 0x4a, 0x6e, 0x5a, 0x4d, 0x56, 0x4d, 0xaa, 0x92, 0x26, 0x1d, 0xbc, 0x3f, 0x23, 0xdb, 0x81, 0x3f, 0x70, 0xa4, 0xda, 0x93, 0x33, 0xf0, 0x6f, 0xe2, 0xb3, 0x33, 0xe8, 0x7b, 0x2a, 0xc5, 0x53, 0xe3, 0xed, 0xdd, 0x5c, 0x59, 0xc9, 0xf7, 0x34, 0x54, 0xf6, 0x72, 0xe2, 0x36, 0x7b, 0x5a, 0xef, 0x23, 0xe9, 0x83, 0x33, 0x9b, 0xea, 0xf9, 0xe9, 0x69, 0xf6, 0xd3, 0x6b, 0x9f, 0x91, 0x06, 0x6b, 0xed, 0x93, 0xfe, 0x97, 0xda, 0xc7, 0xe4, 0x55, 0xfa, 0x31, 0x95, 0xb3, 0x54, 0x26,\n\t0xaf, 0x9c, 0x11, 0xcf, 0x60, 0x38, 0xf0, 0x68, 0xce, 0x13, 0x8b, 0x47, 0xc3, 0xb7, 0x69, 0x79, 0xf1, 0x9f, 0x39, 0xb7, 0x81, 0x83, 0xb7, 0x10, 0x3c, 0x8d, 0xe6, 0xdd, 0x8d, 0x17, 0xf7, 0xcd, 0x4b, 0xd3, 0xa4, 0xeb, 0x69, 0xf6, 0xe2, 0xab, 0x63, 0xa7, 0x91, 0x3e, 0xd7, 0xd3, 0x3c, 0x1b, 0x2b, 0x0d, 0xd1, 0x19, 0x8c, 0x93, 0xa6, 0xa9, 0x3a, 0xe3, 0x72, 0x93, 0xcd, 0x93, 0x8c, 0x32, 0x83, 0xe9, 0xf4, 0x4a, 0x6d, 0x09, 0x75, 0x85, 0xc0, 0x04, 0x21, 0x19, 0x25, 0xfb, 0x3c, 0x3e, 0x51, 0xa6, 0x0f, 0xc2, 0xe0, 0x72, 0x3d, 0xb1, 0xb9, 0xb5, 0x1e, 0x2e, 0xc7, 0xb5, 0xc4, 0xee, 0x58, 0x98, 0xe6, 0x73, 0xf5, 0x9e, 0xe0, 0xf8, 0x83, 0x8b, 0x33, 0x32, 0x5c, 0x7c, 0x19, 0xcf, 0x53, 0xe7, 0x05, 0x49, 0x42, 0x9a, 0xb7, 0xc6, 0xd3, 0x5b, 0x20, 0x6e, 0x8b, 0xf7, 0x9c, 0xfc, 0x24,\n\t0xb3, 0x3e, 0x95, 0xff, 0x95, 0xfe, 0x2d, 0x13, 0xf4, 0x76, 0x3e, 0x49, 0x56, 0xf7, 0x47, 0xd4, 0x55, 0xfe, 0x11, 0xd3, 0xf7, 0x7a, 0xf5, 0x34, 0x47, 0xf0, 0x8a, 0xb0, 0xa2, 0x7e, 0x8b, 0xd2, 0xc7, 0x2e, 0xd1, 0xee, 0x6a, 0x2d, 0xd4, 0x75, 0x84, 0x01, 0x27, 0x3a, 0x62, 0x91, 0x36, 0x87, 0x8c, 0xb8, 0x94, 0xac, 0xe1, 0xe1, 0xcf, 0x2d, 0x3f, 0xa1, 0x73, 0x88, 0xf5, 0x89, 0x5b, 0x72, 0x69, 0x73, 0x48, 0xbe, 0x9a, 0xce, 0x21, 0x86, 0xcf, 0x97, 0x54, 0x1e, 0x15, 0xfe, 0x42, 0xfc, 0x94, 0xca, 0x80, 0x57, 0xbd, 0x4b, 0xb9, 0x2e, 0x26, 0xbe, 0xdb, 0x84, 0x7b, 0x75, 0xfc, 0x69, 0x7c, 0x67, 0x04, 0xa7, 0xfc, 0xd5, 0xab, 0xde, 0xa5, 0x34, 0xe2, 0xdf, 0xea, 0xf8, 0x73, 0x26, 0xfc, 0x61, 0x1d, 0x7f, 0xc1, 0x88, 0x53, 0x1e, 0xe0, 0x55, 0x6d, 0xec, 0x3b, 0x63, 0xd6, 0x7b, 0x08,\n\t0x70, 0x38, 0xa3, 0x03, 0x5c, 0xdc, 0x45, 0x6f, 0x3b, 0x64, 0x07, 0x33, 0x90, 0xba, 0xa6, 0x55, 0xc3, 0xc2, 0x45, 0x17, 0xda, 0x1a, 0x34, 0xa6, 0xb0, 0xb0, 0x30, 0x4f, 0x80, 0x79, 0x4f, 0xf7, 0xfb, 0x73, 0xf3, 0xf4, 0xd3, 0x53, 0x21, 0x25, 0x51, 0xae, 0x31, 0x1f, 0x4e, 0x89, 0x9f, 0xd2, 0x2d, 0xff, 0x07, 0x94, 0xef, 0x0e, 0x2e, 0x58, 0x70, 0x10, 0xcb, 0x0f, 0xd0, 0x63, 0x80, 0xf7, 0xe0, 0x60, 0x60, 0xe9, 0xf3, 0xd7, 0xb7, 0xb7, 0x5f, 0x0f, 0xff, 0x5d, 0xdd, 0xce, 0xfd, 0xe2, 0x41, 0xe5, 0x5f, 0x47, 0x17, 0x2e, 0x3c, 0x8a, 0xe3, 0x1f, 0xdc, 0x8e, 0x1d, 0x47, 0x17, 0x2d, 0x3a, 0xaa, 0x7c, 0xb9, 0xfd, 0xba, 0x37, 0x36, 0x8d, 0x19, 0xb3, 0xe9, 0x8d, 0xeb, 0x56, 0x1f, 0xdf, 0xd4, 0xd9, 0xb9, 0xe9, 0x38, 0xf0, 0x9a, 0x9b, 0x48, 0xfb, 0xfe, 0x46, 0xed, 0x2c, 0x6f, 0x98,\n\t0xf1, 0xe4, 0xea, 0xe8, 0xbb, 0x94, 0xfd, 0x7d, 0x43, 0x8e, 0xfe, 0x0d, 0x3e, 0xf5, 0x1b, 0xa4, 0xff, 0x93, 0x6f, 0x40, 0x5d, 0x44, 0x36, 0x3f, 0xa5, 0x7b, 0x17, 0x5e, 0x55, 0x36, 0x37, 0x1b, 0xc6, 0x24, 0x4f, 0xc7, 0xdf, 0xc6, 0x77, 0x19, 0xf0, 0x87, 0x74, 0xfc, 0x1d, 0xd3, 0x18, 0xea, 0x63, 0x8e, 0xdf, 0x35, 0xe1, 0x9f, 0xeb, 0xf8, 0x7b, 0x46, 0x9c, 0xee, 0x6d, 0x7b, 0xd5, 0xfb, 0x95, 0x2a, 0x0e, 0xed, 0xd1, 0x65, 0xa1, 0x80, 0xc9, 0x60, 0x9f, 0x76, 0x45, 0x64, 0x65, 0x2f, 0xfd, 0x9d, 0x27, 0xf9, 0x9e, 0x04, 0x99, 0x23, 0x7f, 0xf2, 0xa0, 0xe1, 0xb8, 0x9e, 0x1d, 0xd4, 0x16, 0xc2, 0x63, 0x09, 0x09, 0xb6, 0x5b, 0x79, 0x5e, 0x9a, 0x4e, 0x38, 0x4f, 0x37, 0x70, 0x34, 0x7a, 0xa4, 0xb4, 0xa4, 0xd3, 0x82, 0x65, 0x99, 0x6e, 0xea, 0x2d, 0x10, 0xe0, 0x5c, 0xd6, 0x3e, 0x70,\n\t0xfa, 0xb9, 0xd1, 0xe9, 0xe3, 0xce, 0xb0, 0x7c, 0xc7, 0x19, 0x96, 0x9f, 0x7a, 0x46, 0xe5, 0x07, 0x2b, 0x90, 0x45, 0x94, 0x45, 0x88, 0xfd, 0x3e, 0x40, 0x16, 0x14, 0xc9, 0xd1, 0xd5, 0x45, 0xdf, 0xcb, 0x0c, 0x1b, 0x3a, 0xa4, 0xb9, 0x30, 0x39, 0x50, 0x98, 0xef, 0x4a, 0xb0, 0xda, 0xbc, 0x25, 0xf0, 0x40, 0x03, 0x6b, 0x51, 0x99, 0x55, 0xc9, 0x63, 0x97, 0x13, 0x20, 0x24, 0x7c, 0xe4, 0xec, 0x97, 0x1d, 0xb0, 0x11, 0xce, 0xe5, 0xe0, 0x93, 0x93, 0x28, 0x3d, 0xac, 0xae, 0xf2, 0x08, 0xc1, 0xd0, 0x4f, 0xb9, 0x86, 0xde, 0x2f, 0x35, 0x19, 0xd4, 0x64, 0x92, 0x7b, 0x26, 0xfb, 0xa2, 0x9a, 0xe9, 0xf3, 0x86, 0xd6, 0x6d, 0xfe, 0xd7, 0xae, 0x99, 0x11, 0x99, 0xbd, 0xf0, 0xc9, 0x7f, 0xde, 0x91, 0xe8, 0xf3, 0x26, 0x54, 0x14, 0xa4, 0x64, 0xba, 0xe3, 0x44, 0xa7, 0x28, 0x0d, 0x5a, 0xde, 0x5b,\n\t0xa2, 0x8a, 0xe6, 0x6a, 0x55, 0x54, 0x4f, 0xde, 0xea, 0xc9, 0x18, 0xdf, 0x56, 0x3d, 0x33, 0x60, 0x5b, 0x7e, 0x18, 0xf3, 0x5b, 0x22, 0xa2, 0x7c, 0xaf, 0xa2, 0x1c, 0xfa, 0x91, 0xdd, 0x9e, 0xe9, 0x2f, 0x48, 0xf1, 0x17, 0xcb, 0xb2, 0x1c, 0xdf, 0x57, 0x36, 0xc4, 0xed, 0xb1, 0xf5, 0x8e, 0xf8, 0xa0, 0x09, 0x7f, 0x5e, 0x97, 0x35, 0xa2, 0xa7, 0xd4, 0x3b, 0xb1, 0x77, 0xf6, 0xb9, 0x13, 0xcb, 0xd2, 0x1e, 0x34, 0xa5, 0x4d, 0xa5, 0x6b, 0x17, 0x44, 0x0a, 0x4e, 0xa4, 0x69, 0x53, 0xd5, 0xdb, 0xef, 0x74, 0x11, 0xd3, 0xf3, 0x64, 0xb0, 0x3c, 0x74, 0x6d, 0xd8, 0xdc, 0xe7, 0x4c, 0x99, 0xa5, 0x79, 0xdf, 0x54, 0x2e, 0xbb, 0x6b, 0x7b, 0x67, 0x9f, 0xbb, 0xb6, 0x6c, 0xce, 0x4c, 0xd5, 0xca, 0x13, 0x6f, 0xa4, 0x75, 0x93, 0x34, 0x5c, 0x54, 0x79, 0x16, 0xb7, 0x5e, 0x1e, 0xf9, 0x16, 0xec, 0xc5,\n\t0xaa, 0xce, 0x66, 0x69, 0xb1, 0xd7, 0x94, 0x36, 0x53, 0xef, 0x97, 0x0d, 0xa6, 0xb9, 0x99, 0xa1, 0x97, 0xb1, 0x1b, 0xff, 0x9c, 0xed, 0xfd, 0xd3, 0x32, 0x2c, 0xf0, 0xe0, 0x40, 0xdb, 0xfb, 0x0f, 0x0f, 0xa5, 0xfa, 0xed, 0x15, 0xbd, 0x8c, 0x76, 0x85, 0xde, 0xd5, 0x54, 0xa6, 0x46, 0xe1, 0x2d, 0xa1, 0x3d, 0x14, 0x8f, 0x4e, 0x3f, 0x84, 0xe1, 0xe1, 0xd1, 0x14, 0x3f, 0xa2, 0xe3, 0x8d, 0x8a, 0x8f, 0xa6, 0x9f, 0x10, 0x85, 0x07, 0xd5, 0x72, 0x86, 0x44, 0xe1, 0x6d, 0x6a, 0x39, 0x8b, 0x28, 0xbe, 0x4f, 0xc7, 0x07, 0xb3, 0x72, 0xd4, 0xf2, 0x23, 0x78, 0x93, 0x72, 0xe9, 0x29, 0xd6, 0x30, 0xd0, 0x43, 0x70, 0xff, 0x2a, 0x03, 0xe9, 0xf7, 0xaf, 0xe0, 0xbc, 0x02, 0x21, 0x61, 0x35, 0xbd, 0x83, 0x97, 0x06, 0x2f, 0x93, 0xe1, 0x56, 0x3c, 0x2f, 0x20, 0x7e, 0x0e, 0x7d, 0xf1, 0x04, 0x77, 0x2d,\n\t0x4a, 0x3a, 0xc9, 0x04, 0x2b, 0x15, 0xc6, 0xc4, 0xd9, 0x31, 0x4a, 0xf5, 0xa4, 0x24, 0xd9, 0xd3, 0xe2, 0xd2, 0xd8, 0x7d, 0x3b, 0x76, 0xed, 0x85, 0x5e, 0x53, 0x23, 0xf4, 0xc4, 0xad, 0xde, 0x4c, 0xa3, 0x8c, 0x90, 0x9b, 0x3b, 0x71, 0xe5, 0xe4, 0xe2, 0x87, 0x1f, 0xfd, 0xc3, 0x1f, 0x36, 0xbc, 0x71, 0xe3, 0xd0, 0xf6, 0x75, 0xc7, 0xd7, 0xfe, 0xe1, 0x04, 0x77, 0xa0, 0x78, 0x6c, 0xf7, 0xd0, 0x35, 0x77, 0x87, 0x8e, 0x71, 0x7f, 0x0a, 0xfe, 0xe8, 0xd1, 0x79, 0xf3, 0x9e, 0xb8, 0x7a, 0x58, 0xe8, 0x9f, 0xf4, 0x5e, 0xfc, 0xe9, 0xb4, 0x23, 0x0d, 0xda, 0x91, 0x1e, 0xb3, 0x1d, 0xd2, 0xb9, 0x6a, 0x87, 0xba, 0xe7, 0xbe, 0x9a, 0x72, 0x89, 0x2c, 0xf5, 0xfc, 0xfb, 0x39, 0x03, 0x9e, 0xc1, 0x70, 0x7a, 0x0e, 0x7d, 0x38, 0xea, 0x9e, 0x37, 0x47, 0x52, 0x23, 0x61, 0x33, 0xbd, 0x13, 0xe8, 0x43,\n\t0x3f, 0xea, 0xdc, 0xe3, 0x21, 0x1a, 0x2f, 0x00, 0xd7, 0x46, 0x45, 0x09, 0x89, 0x73, 0xe8, 0x3d, 0x00, 0x1b, 0xbd, 0x07, 0x00, 0x17, 0x1b, 0xb9, 0x2e, 0x0b, 0xf9, 0xa8, 0xf9, 0x70, 0x12, 0x33, 0x57, 0x22, 0xfa, 0x2e, 0x8f, 0xfc, 0x55, 0x66, 0x37, 0x06, 0x62, 0x65, 0x61, 0xc9, 0xba, 0x82, 0x99, 0x09, 0x4e, 0xf5, 0xde, 0x80, 0x37, 0x3d, 0xd5, 0xe9, 0x4b, 0xf0, 0x45, 0x6e, 0x0d, 0xda, 0x6d, 0x86, 0x6e, 0xa0, 0xb7, 0x06, 0x4d, 0x5d, 0x41, 0x2f, 0x0e, 0x5c, 0xa1, 0x76, 0xc7, 0x2b, 0xaf, 0x18, 0x3a, 0xe4, 0xa5, 0x97, 0xb4, 0x2e, 0x79, 0x6b, 0xcb, 0x5b, 0xc6, 0x3e, 0xe1, 0x37, 0x6c, 0xc1, 0x57, 0xe9, 0xdf, 0x3e, 0x5f, 0xfb, 0x76, 0xb1, 0x11, 0xbd, 0x41, 0x79, 0x23, 0xa7, 0xf1, 0x46, 0xc3, 0xf8, 0xc5, 0xa3, 0x6c, 0xd4, 0x12, 0x1c, 0x0c, 0x0e, 0x6f, 0x31, 0x4a, 0x4b, 0xe1,\n\t0x78, 0x9c, 0xea, 0xe1, 0x04, 0x9e, 0xef, 0x80, 0xf7, 0x8d, 0x02, 0x26, 0x03, 0x0a, 0x4f, 0xe0, 0x44, 0xc3, 0x80, 0x3a, 0x1d, 0x70, 0x0b, 0xc2, 0x91, 0xed, 0xcc, 0xf6, 0xe5, 0x4b, 0x52, 0x4a, 0x09, 0x31, 0x1a, 0xd8, 0x48, 0x56, 0x57, 0xd5, 0x17, 0xd4, 0xf3, 0xf4, 0x1b, 0x24, 0xd9, 0x23, 0x17, 0x48, 0xcc, 0xeb, 0x42, 0x75, 0xf3, 0x10, 0x18, 0xd0, 0x6c, 0xef, 0xdc, 0xeb, 0xa6, 0xc2, 0x47, 0x5c, 0xb1, 0xfc, 0x82, 0x55, 0x4b, 0x3a, 0xa6, 0x92, 0x81, 0xfd, 0x2c, 0xb0, 0x72, 0x1c, 0x8c, 0x2b, 0xbf, 0x65, 0x12, 0xfe, 0x0a, 0x3e, 0xe3, 0x86, 0xe3, 0x4d, 0x37, 0x4f, 0xda, 0xe5, 0x64, 0xa3, 0x6b, 0x94, 0x31, 0x2f, 0xaa, 0x0f, 0xd6, 0xc8, 0x58, 0xbd, 0x68, 0x2a, 0xe9, 0xc2, 0x26, 0x8a, 0x46, 0x71, 0x87, 0xab, 0xf4, 0x44, 0xd0, 0xbc, 0x71, 0x5e, 0x26, 0x68, 0x96, 0xfe, 0x05,\n\t0xbe, 0x3a, 0xa6, 0xa8, 0x9d, 0xc0, 0xcf, 0x15, 0x8f, 0xe9, 0x1e, 0xba, 0xf6, 0xae, 0xd0, 0x7f, 0x93, 0x7e, 0xbd, 0x02, 0xfa, 0x75, 0xc5, 0x70, 0xe5, 0x5f, 0xe2, 0x36, 0x25, 0xa4, 0xc9, 0xd4, 0x27, 0x54, 0xd6, 0x7c, 0xaa, 0xac, 0xbd, 0x8c, 0x22, 0xb8, 0x57, 0xc7, 0xf7, 0xa2, 0x9f, 0x69, 0x36, 0xb5, 0xf0, 0x09, 0xe5, 0xd1, 0x3e, 0xd5, 0xa6, 0x0e, 0x53, 0xfc, 0x52, 0x73, 0x7a, 0x71, 0xbb, 0x96, 0x9e, 0xe2, 0x6e, 0x1d, 0x7f, 0xd0, 0x84, 0x67, 0x30, 0x9c, 0xca, 0xf2, 0x4f, 0x63, 0xdc, 0x0d, 0xda, 0x6c, 0xac, 0x8b, 0xd8, 0xcb, 0xdf, 0xe8, 0x67, 0xf5, 0x9f, 0x50, 0x2e, 0xec, 0x53, 0xed, 0xe8, 0x6f, 0xd4, 0x7b, 0x1c, 0x3f, 0xd3, 0xef, 0x7f, 0x1a, 0xf2, 0x11, 0x3b, 0xfa, 0x5b, 0x8a, 0xb7, 0x84, 0x3f, 0xe7, 0xff, 0x46, 0xbf, 0x35, 0x57, 0xfd, 0xd6, 0x67, 0x0c, 0xb8, 0x57,\n\t0xc7, 0x9f, 0x46, 0xaf, 0xc4, 0xc4, 0xf7, 0x6a, 0xb8, 0xb2, 0x92, 0xff, 0x1b, 0xe5, 0x77, 0xb9, 0xd4, 0x7e, 0xff, 0xef, 0x2b, 0xd9, 0xbe, 0x12, 0x4d, 0x4f, 0x78, 0x69, 0x2b, 0x1a, 0x12, 0x6c, 0x6a, 0xc5, 0x58, 0xcc, 0xc1, 0xc4, 0x9a, 0xea, 0x40, 0xe0, 0x46, 0x00, 0xf1, 0x3d, 0x54, 0xf6, 0x84, 0xc5, 0x64, 0x46, 0x51, 0xea, 0x90, 0xd3, 0xa9, 0x5d, 0xec, 0xf3, 0x71, 0x63, 0x5a, 0x9a, 0x8a, 0x0b, 0xf3, 0xfd, 0x19, 0xe9, 0xfe, 0x5c, 0x2a, 0x7e, 0xa6, 0x4b, 0x60, 0x52, 0xb2, 0xfa, 0xe2, 0x96, 0xed, 0x1c, 0xe9, 0x4c, 0x42, 0xaa, 0xa5, 0xaf, 0x6f, 0x53, 0x3c, 0xfc, 0x3d, 0xb6, 0x14, 0x57, 0x62, 0xf9, 0x88, 0x8b, 0x87, 0xb5, 0xce, 0x0c, 0xfa, 0x9a, 0x2e, 0xbe, 0xfa, 0xba, 0xab, 0x2f, 0x6e, 0x1a, 0x7a, 0xcd, 0xfe, 0xe5, 0x23, 0xae, 0xbf, 0x7c, 0x5e, 0x61, 0x8b, 0x35, 0x2d,\n\t0x21, 0xb9, 0x7e, 0xe2, 0xd2, 0x89, 0x6d, 0x0b, 0x46, 0x06, 0x06, 0xd3, 0x1f, 0x07, 0x37, 0x2f, 0x7f, 0x7c, 0xe1, 0x8a, 0xe3, 0x9d, 0xc2, 0x33, 0xae, 0x04, 0x5f, 0x91, 0xcf, 0xd7, 0x38, 0xb6, 0x6c, 0xf0, 0x98, 0xba, 0xc2, 0x92, 0x86, 0x29, 0x2b, 0xbb, 0x66, 0x3e, 0x7a, 0xcd, 0x48, 0x6f, 0xe5, 0x88, 0x92, 0xf9, 0x71, 0x09, 0xa5, 0xb5, 0xa5, 0xfe, 0xa1, 0x33, 0x1a, 0x5a, 0x27, 0xd4, 0x05, 0x8a, 0xea, 0xa6, 0xad, 0xb9, 0x78, 0xec, 0x6d, 0x4b, 0x86, 0x8d, 0x1d, 0x85, 0x0c, 0x7d, 0x93, 0xc1, 0xfa, 0x80, 0x8e, 0xdf, 0xcb, 0x7d, 0xec, 0xcd, 0x16, 0x65, 0xb3, 0xb1, 0x9f, 0xf0, 0x9f, 0xaf, 0xd4, 0xf3, 0x0a, 0x58, 0xbe, 0x45, 0xeb, 0x57, 0x71, 0x93, 0xb1, 0xbf, 0xe9, 0xda, 0x49, 0xcb, 0x14, 0x6f, 0x43, 0xaf, 0xb0, 0x32, 0xb9, 0xa8, 0x32, 0xb5, 0x7a, 0x51, 0x00, 0xca, 0x34,\n\t0xd4, 0x1e, 0xd1, 0x84, 0x90, 0x16, 0xce, 0x58, 0xd7, 0xd2, 0xf1, 0xcb, 0x53, 0xc7, 0xef, 0x18, 0xc3, 0x89, 0x0c, 0xaf, 0xa5, 0xf2, 0x91, 0xa7, 0xca, 0xf0, 0x31, 0x3a, 0x7e, 0x34, 0x3d, 0x7d, 0x4f, 0xe6, 0x0d, 0xa6, 0xc2, 0x4e, 0x03, 0xdf, 0x85, 0x60, 0x53, 0x04, 0xd1, 0x37, 0x64, 0xd4, 0x0b, 0x04, 0x58, 0x45, 0x70, 0xe0, 0x46, 0x38, 0x9d, 0xb0, 0x56, 0x69, 0x78, 0x5b, 0xa9, 0x13, 0xe6, 0x0b, 0x7f, 0x3b, 0x99, 0x22, 0xfc, 0xed, 0x19, 0x34, 0x40, 0x19, 0x69, 0x50, 0x46, 0xba, 0x5a, 0x86, 0x74, 0xca, 0x32, 0x94, 0xad, 0xb4, 0x0c, 0x3f, 0xba, 0xfe, 0x34, 0xef, 0x8e, 0x64, 0x49, 0x44, 0x43, 0x8b, 0x5d, 0x44, 0xaa, 0xe6, 0x74, 0x5a, 0xe4, 0x18, 0xf7, 0x45, 0xf2, 0xb5, 0x4d, 0xd5, 0xbe, 0x09, 0x4d, 0x77, 0x44, 0x12, 0xc8, 0x1f, 0xfc, 0xc8, 0xaf, 0xde, 0x10, 0x01, 0xfa,\n\t0xda, 0xff, 0x0d, 0x11, 0xfa, 0x05, 0xc9, 0x3e, 0x17, 0x77, 0x73, 0x3f, 0x27, 0xea, 0xd5, 0xf0, 0x65, 0x4a, 0x43, 0xcc, 0xb3, 0x73, 0xf2, 0xb1, 0xcf, 0x9c, 0x4c, 0xa1, 0xeb, 0x6e, 0xf8, 0x38, 0xe1, 0x05, 0x32, 0xbd, 0x17, 0x92, 0x8e, 0x96, 0x04, 0xe3, 0xd3, 0x30, 0x12, 0xe2, 0x65, 0x81, 0x83, 0x6d, 0x55, 0xf5, 0x6e, 0x48, 0x3e, 0x51, 0x91, 0xdc, 0x72, 0x19, 0xdc, 0xcc, 0xb1, 0xdb, 0x6b, 0xf3, 0x3a, 0xd9, 0x5f, 0xb4, 0x3b, 0x2f, 0x18, 0xcf, 0x85, 0x5d, 0xd9, 0x2c, 0x9a, 0x8e, 0x5e, 0x9b, 0x9d, 0x16, 0x23, 0x41, 0x57, 0xd0, 0xc9, 0xf3, 0x7c, 0x3a, 0x9f, 0x9e, 0xef, 0x4a, 0xcc, 0x4b, 0x4a, 0x80, 0x3d, 0x3d, 0x0c, 0x3e, 0xd6, 0x20, 0xbc, 0x00, 0x7d, 0x11, 0xe1, 0x62, 0x4e, 0x1f, 0x9a, 0xb0, 0x9c, 0xcc, 0xef, 0xff, 0x07, 0xde, 0xa4, 0x2c, 0x7b, 0x5b, 0x79, 0x04, 0xee,\n\t0x80, 0x70, 0x85, 0xe4, 0x5b, 0x1c, 0xea, 0x35, 0x90, 0xab, 0x84, 0xbf, 0x29, 0x2f, 0xe1, 0xe1, 0xa1, 0x0f, 0x43, 0xb5, 0xf8, 0x09, 0x25, 0x3f, 0xc7, 0xcb, 0x7d, 0xc1, 0xcd, 0x7f, 0x86, 0xde, 0x02, 0x79, 0x64, 0xbc, 0x2e, 0x77, 0x19, 0x4c, 0xbe, 0xa8, 0x74, 0x1e, 0xed, 0x33, 0x37, 0xb2, 0x88, 0x0e, 0x33, 0xc8, 0x20, 0xd1, 0x61, 0x9a, 0x6c, 0x7e, 0x6d, 0xc4, 0x89, 0xee, 0xd2, 0xf0, 0x7b, 0x8c, 0xb8, 0x94, 0xac, 0xe2, 0x0f, 0x84, 0xff, 0x29, 0xfa, 0xa9, 0x4e, 0x0b, 0xa8, 0xfb, 0x11, 0x23, 0x62, 0xe2, 0xbb, 0x4d, 0xb8, 0x57, 0xc7, 0x9f, 0xc6, 0x13, 0x23, 0x38, 0xdd, 0x8f, 0x08, 0xa8, 0xfb, 0x11, 0x46, 0xfc, 0x5b, 0x1d, 0x7f, 0xce, 0x84, 0x3f, 0xac, 0xe3, 0x2f, 0x18, 0x71, 0xaa, 0xef, 0x03, 0xea, 0x7e, 0x84, 0x11, 0xef, 0xd2, 0xf1, 0x97, 0xf0, 0xe4, 0x98, 0xed, 0x39,\n\t0xa4, 0xa5, 0x27, 0x36, 0xab, 0x9f, 0x7e, 0x6f, 0x40, 0xb5, 0x55, 0x27, 0x18, 0xd2, 0xe7, 0xe9, 0xf8, 0xdb, 0xfd, 0x94, 0xb3, 0xd7, 0x54, 0xef, 0xf3, 0x2a, 0x0e, 0xb6, 0xc0, 0x44, 0xd5, 0x1e, 0x99, 0x88, 0x4c, 0xa7, 0x4b, 0x5a, 0x5a, 0x7a, 0x0e, 0x15, 0x50, 0x39, 0xfa, 0x8a, 0x53, 0xa4, 0xad, 0xd0, 0xd3, 0xee, 0x3d, 0x83, 0x72, 0x77, 0x12, 0x55, 0x30, 0x60, 0xda, 0xc8, 0x77, 0x10, 0x7b, 0x2b, 0x66, 0xbf, 0x12, 0x7b, 0x4b, 0xeb, 0xa7, 0xd7, 0x23, 0xfd, 0x04, 0xe7, 0x6b, 0x78, 0x7c, 0xf4, 0xf9, 0x1a, 0x49, 0x73, 0x8f, 0xb1, 0x2f, 0xa5, 0x64, 0x63, 0x99, 0xd4, 0xf6, 0x09, 0xa8, 0xb6, 0xcf, 0xc4, 0x3e, 0xfa, 0x96, 0xd5, 0xfb, 0x8e, 0x5e, 0xef, 0x2d, 0x6a, 0xde, 0xc8, 0x5b, 0xe0, 0x42, 0x55, 0x5e, 0x32, 0xa2, 0xde, 0x96, 0x16, 0xaa, 0xe3, 0xc6, 0xde, 0xa5, 0x11, 0x4b,\n\t0xc0, 0x22, 0x50, 0x79, 0x2c, 0x62, 0x72, 0xca, 0x2d, 0x8b, 0x89, 0xef, 0x36, 0xe1, 0x5e, 0x1d, 0x7f, 0x9a, 0xbb, 0x36, 0x82, 0x53, 0x79, 0x64, 0xf8, 0x73, 0x46, 0x9c, 0xce, 0xb9, 0x22, 0x75, 0x0f, 0xf6, 0xda, 0x3e, 0x73, 0xce, 0xab, 0x6c, 0xb6, 0x08, 0xb4, 0x6d, 0x45, 0xea, 0x1e, 0xec, 0xb5, 0x54, 0xdf, 0x3a, 0xc9, 0xb7, 0xd8, 0x89, 0xbe, 0xf5, 0xa2, 0x9c, 0x60, 0xa6, 0xd7, 0x1d, 0x4f, 0xd4, 0x87, 0xea, 0xb5, 0x55, 0xdf, 0x07, 0x2d, 0xcc, 0x2d, 0xcc, 0x01, 0xe5, 0xef, 0xa3, 0x3b, 0xa0, 0x92, 0x4c, 0xd5, 0x85, 0x95, 0x3a, 0xb7, 0xc3, 0xda, 0x71, 0x89, 0x68, 0xff, 0xb5, 0x27, 0xc3, 0xa2, 0xdc, 0x62, 0xb1, 0x2b, 0x3f, 0xb6, 0xa5, 0x27, 0xbd, 0x86, 0x3f, 0x55, 0x8a, 0x7f, 0xed, 0x49, 0xb1, 0xe0, 0x6e, 0x8b, 0x03, 0x9f, 0x67, 0x4d, 0x71, 0x1d, 0x57, 0x0a, 0xd2, 0x1c,\n\t0xdc, 0xf8, 0xb4, 0xc4, 0xd0, 0xfb, 0x8e, 0x34, 0xee, 0x4f, 0xdc, 0x01, 0x87, 0x23, 0xf4, 0xf3, 0xf4, 0x14, 0x1c, 0x4e, 0x48, 0x08, 0x4d, 0x18, 0xb0, 0x1d, 0x69, 0xb4, 0x1d, 0xe9, 0x6a, 0x3b, 0xa4, 0xff, 0x64, 0x3b, 0x48, 0x3f, 0xd1, 0x76, 0xd0, 0xbe, 0x2c, 0x56, 0xf5, 0x57, 0xa8, 0x4f, 0x5f, 0xd2, 0x34, 0x74, 0x1c, 0x8a, 0xd5, 0xfb, 0x9e, 0x0a, 0xb5, 0x09, 0xc9, 0xbf, 0x85, 0x7f, 0xd0, 0xf1, 0x2c, 0x51, 0xef, 0x87, 0xbe, 0x1f, 0x13, 0xdf, 0x6d, 0xc2, 0xbd, 0x3a, 0xfe, 0x34, 0xfa, 0x9f, 0x08, 0x4e, 0xcb, 0x2f, 0x51, 0xcb, 0xff, 0x1f, 0x18, 0x2b, 0x86, 0x93, 0x3e, 0x4a, 0x82, 0xbd, 0xea, 0x38, 0x1e, 0xe9, 0x7e, 0x47, 0xb5, 0xc3, 0xf7, 0xd2, 0x5c, 0x17, 0x2f, 0xab, 0xa1, 0x6e, 0xb4, 0x53, 0x00, 0x70, 0x3c, 0x0a, 0x5d, 0xc3, 0x7d, 0xf0, 0x76, 0xe8, 0xcb, 0x83, 0x19,\n\t0xb9, 0x76, 0xdc, 0xe0, 0xce, 0x8e, 0xb3, 0x67, 0xba, 0x71, 0xbd, 0xcd, 0xef, 0x7d, 0x89, 0x6b, 0x80, 0x4d, 0x16, 0x7e, 0xae, 0x37, 0x25, 0xf4, 0x97, 0xfc, 0xb6, 0x9c, 0x9c, 0xb6, 0x7c, 0x2e, 0x2d, 0x31, 0x9b, 0xf9, 0xe7, 0xf9, 0x84, 0xd6, 0x07, 0xfb, 0x91, 0x25, 0xec, 0xdc, 0x3e, 0x74, 0x47, 0x9f, 0x73, 0xfb, 0x98, 0x6d, 0x05, 0x9c, 0xe8, 0xf8, 0x7f, 0x50, 0x79, 0x2b, 0x51, 0x75, 0xfc, 0xc7, 0x86, 0x6f, 0xfb, 0x42, 0x4f, 0xff, 0xac, 0xf1, 0x9b, 0xa9, 0x6e, 0x2b, 0x51, 0xef, 0xc4, 0xfe, 0xd5, 0x90, 0xfe, 0x61, 0x3d, 0xfd, 0x0b, 0xa6, 0xf4, 0x19, 0x9c, 0xd6, 0xb6, 0x23, 0xe8, 0x2f, 0xd1, 0xe3, 0xa4, 0x1c, 0xa3, 0xed, 0x3f, 0x82, 0xd4, 0xbc, 0x62, 0x63, 0x88, 0xbe, 0x59, 0x0f, 0xed, 0x8b, 0xc2, 0x83, 0x21, 0x7a, 0x1e, 0x11, 0x3a, 0x10, 0x85, 0xb7, 0x85, 0xe8, 0x9e,\n\t0x84, 0x92, 0x4b, 0xdb, 0x70, 0x5c, 0xc7, 0x87, 0xb2, 0x72, 0x94, 0x5f, 0x1a, 0xfb, 0x87, 0x9e, 0x67, 0xaf, 0xa5, 0xf8, 0xdb, 0x51, 0x78, 0x53, 0xe8, 0xab, 0xd3, 0xf8, 0x16, 0xb7, 0x8e, 0xbf, 0xa8, 0x8e, 0x77, 0x2f, 0xc1, 0x3f, 0x8d, 0x35, 0xde, 0xda, 0x61, 0x35, 0x8c, 0xb7, 0xd4, 0xdf, 0x78, 0xff, 0xe1, 0x44, 0xe8, 0x5f, 0x07, 0x33, 0x7c, 0x64, 0xbc, 0x93, 0xd4, 0xf1, 0xb6, 0xc2, 0x78, 0x37, 0x86, 0x5e, 0xe3, 0x1a, 0xf9, 0x39, 0x31, 0xc6, 0x1b, 0x55, 0x91, 0xfa, 0xae, 0xa2, 0x72, 0x5a, 0xaa, 0xca, 0xe9, 0x5b, 0x06, 0xdc, 0xab, 0xe3, 0x7b, 0xd1, 0xef, 0x0d, 0x78, 0x06, 0xc3, 0xe9, 0x18, 0xbc, 0xdf, 0xe7, 0x6e, 0x38, 0x4d, 0xa3, 0xf9, 0xb6, 0x96, 0xc9, 0x4c, 0x86, 0xf7, 0x85, 0x9c, 0x46, 0x2e, 0x49, 0x8a, 0x2e, 0x95, 0x61, 0x26, 0xbb, 0xdc, 0x6c, 0xdf, 0x5d, 0x86,\n\t0xb7, 0x99, 0xb0, 0x3d, 0x08, 0x9b, 0x87, 0xc2, 0x55, 0x29, 0xbd, 0x7f, 0xe1, 0x7d, 0x27, 0x7f, 0x6a, 0xb7, 0xf2, 0xde, 0xde, 0xef, 0x84, 0x2c, 0x71, 0x6c, 0x9e, 0xef, 0xe4, 0x8e, 0xdd, 0xe7, 0xb9, 0xb2, 0x1c, 0xc2, 0x45, 0xbb, 0x51, 0xcc, 0xf6, 0x3d, 0xad, 0xb5, 0x8f, 0xc8, 0xe0, 0x55, 0x54, 0x06, 0x4b, 0x55, 0x19, 0xfc, 0x48, 0xc5, 0xbf, 0x36, 0xe2, 0x84, 0x67, 0x7c, 0xa4, 0x73, 0xf0, 0xcb, 0x28, 0x67, 0x2f, 0xa3, 0xb6, 0xcd, 0x93, 0x33, 0x50, 0x4c, 0x7c, 0x97, 0x09, 0xdf, 0xa6, 0xe3, 0x4f, 0x99, 0xf0, 0x5b, 0x75, 0x7c, 0x9f, 0x09, 0x5f, 0xa3, 0xe3, 0xfb, 0x4d, 0x78, 0x87, 0x8e, 0x3f, 0xdf, 0x4f, 0xf9, 0x07, 0x4c, 0xf8, 0x27, 0x3a, 0x7e, 0xf0, 0x42, 0x03, 0x2e, 0xb7, 0xe9, 0xf8, 0xcb, 0x17, 0xb2, 0xbd, 0x1d, 0x8a, 0x0b, 0x76, 0xa2, 0xb7, 0x1a, 0xd1, 0xd2, 0xe7,\n\t0xb2, 0x9c, 0xe0, 0xeb, 0x8d, 0x90, 0xcb, 0x2c, 0xd8, 0x1f, 0x21, 0x4b, 0xa2, 0x28, 0xc9, 0x62, 0x0f, 0x3c, 0xc5, 0xc5, 0x22, 0x9a, 0x83, 0x24, 0x89, 0xda, 0x65, 0xb9, 0xec, 0xd9, 0x19, 0xb8, 0x49, 0x4c, 0x87, 0x67, 0x42, 0xc5, 0x03, 0x24, 0x24, 0x49, 0x3a, 0xe9, 0x5e, 0x09, 0xa1, 0x9b, 0x3e, 0xb8, 0xd1, 0x6a, 0xf7, 0xfb, 0x53, 0x0b, 0xf2, 0x0b, 0x0a, 0x13, 0x2c, 0x52, 0x06, 0x31, 0xe8, 0x78, 0xfd, 0x35, 0x0f, 0x66, 0x46, 0x5c, 0xb2, 0x8b, 0x3a, 0xc9, 0x71, 0xf0, 0xf4, 0x46, 0x2b, 0xb1, 0xe4, 0xea, 0xe1, 0xa9, 0x65, 0x2e, 0x23, 0xda, 0xdc, 0xce, 0x2b, 0x1f, 0x5d, 0x50, 0x9e, 0x56, 0x32, 0x38, 0xb7, 0xac, 0xb3, 0xad, 0x39, 0x33, 0x74, 0x6c, 0xca, 0x6b, 0x57, 0x4e, 0xbb, 0x71, 0x46, 0xc5, 0xb4, 0xcc, 0x2c, 0x6b, 0x72, 0xc1, 0x98, 0xc9, 0x17, 0x35, 0x36, 0x5f, 0x3a,\n\t0xae, 0x6c, 0xe8, 0xe6, 0xcf, 0x76, 0xcf, 0x9e, 0x19, 0x9c, 0xd6, 0x5a, 0x91, 0x96, 0x94, 0x69, 0xc5, 0x47, 0x85, 0xcc, 0x41, 0x43, 0x0b, 0x03, 0xf5, 0xfe, 0x84, 0x44, 0xdf, 0xa0, 0x6c, 0x6e, 0xc9, 0xc4, 0x09, 0x8d, 0xf3, 0x37, 0x4d, 0x0d, 0x5d, 0xe5, 0x4e, 0xef, 0xca, 0xab, 0x2f, 0x48, 0xf2, 0x0d, 0x9f, 0x3f, 0xbc, 0x79, 0xc9, 0xf9, 0x0d, 0x42, 0xc7, 0xf2, 0x65, 0x39, 0x05, 0x39, 0x29, 0x4e, 0xa4, 0xd9, 0x53, 0xa4, 0x5f, 0xb4, 0xfe, 0xc2, 0x7f, 0x9e, 0x66, 0xec, 0xdf, 0x63, 0x3a, 0xfe, 0xeb, 0x48, 0xff, 0x0a, 0x33, 0xa5, 0x46, 0x1d, 0x3f, 0xc1, 0xf0, 0xf0, 0x35, 0x24, 0x7d, 0xb7, 0xd4, 0x48, 0xe6, 0x7b, 0x19, 0xdd, 0x2c, 0xff, 0xcd, 0x45, 0x91, 0x72, 0xde, 0x92, 0x7a, 0xf4, 0xf4, 0xbf, 0x35, 0x8e, 0x93, 0xf4, 0x53, 0x1d, 0xff, 0x9d, 0x86, 0x43, 0x7b, 0xf4, 0xf1,\n\t0x0e, 0xd0, 0xf6, 0x50, 0xa9, 0xd2, 0xf3, 0x3c, 0xac, 0xe7, 0xf9, 0xbd, 0x51, 0x16, 0x0c, 0xf8, 0x1f, 0x4d, 0xf8, 0x9f, 0x74, 0xfc, 0xc3, 0x19, 0xb1, 0xeb, 0xfe, 0xd3, 0x8c, 0x81, 0xea, 0x3e, 0x30, 0x23, 0x96, 0x1c, 0xee, 0x31, 0x95, 0x75, 0xa3, 0x86, 0x0b, 0xd3, 0x4c, 0xf8, 0x0d, 0x2a, 0x5e, 0x80, 0x9e, 0x47, 0x33, 0x88, 0x42, 0x92, 0xd0, 0xe1, 0x19, 0xda, 0x0e, 0x74, 0x93, 0x6e, 0xa7, 0xb2, 0xb2, 0x0f, 0xe9, 0x65, 0x43, 0x1a, 0x32, 0x9d, 0x51, 0x45, 0xb8, 0x56, 0x28, 0x16, 0x8e, 0x11, 0xe9, 0x75, 0x10, 0xfd, 0xd7, 0x81, 0xb6, 0x06, 0xd3, 0x46, 0x60, 0xc9, 0xd2, 0x8a, 0x65, 0xa9, 0x06, 0xb6, 0xfa, 0x32, 0x93, 0xe0, 0xe2, 0x75, 0x09, 0xb1, 0xec, 0x44, 0xd5, 0x4e, 0x1a, 0x84, 0xac, 0x16, 0xeb, 0x32, 0x22, 0xa6, 0x48, 0x92, 0x89, 0x41, 0x27, 0xf2, 0x22, 0xbc, 0xa1,\n\t0x84, 0x3d, 0x26, 0x90, 0x55, 0xcb, 0x74, 0x64, 0xb1, 0x2c, 0x06, 0x83, 0x8f, 0x09, 0xf5, 0x5c, 0x10, 0xea, 0x9a, 0xa8, 0x2c, 0x42, 0xcc, 0x2c, 0xaa, 0xa1, 0x48, 0xc5, 0x7b, 0x21, 0xbd, 0x55, 0xdf, 0x31, 0x2a, 0xdf, 0x5f, 0x92, 0x57, 0x5f, 0x9e, 0xa7, 0xde, 0xaa, 0x97, 0xeb, 0x93, 0xc1, 0x45, 0x09, 0x3d, 0xb8, 0xa8, 0x2f, 0x70, 0x10, 0x9b, 0xd1, 0x43, 0x8f, 0xe2, 0x35, 0x21, 0x57, 0x9f, 0x62, 0xd6, 0x97, 0x63, 0x10, 0xf6, 0x56, 0xac, 0xc9, 0x7a, 0x85, 0xea, 0x23, 0x98, 0xba, 0x69, 0xe2, 0x76, 0x65, 0x66, 0x66, 0xd5, 0xa7, 0x1f, 0x4f, 0x4c, 0xa6, 0x72, 0xff, 0xcf, 0x4b, 0xa7, 0xfb, 0xb8, 0x40, 0x49, 0x44, 0xea, 0x5d, 0xbe, 0x84, 0x0b, 0x9c, 0x45, 0x9e, 0xe1, 0x9b, 0x06, 0x8f, 0xa8, 0xea, 0x79, 0xf6, 0xfa, 0xeb, 0x8b, 0xd7, 0x68, 0xd2, 0xef, 0x27, 0x33, 0x64, 0xd2,\n\t0xea, 0xb2, 0xcd, 0xce, 0x80, 0x77, 0x38, 0xd7, 0x5d, 0x8e, 0x57, 0x62, 0x81, 0x53, 0x0e, 0xf1, 0x30, 0x13, 0x9e, 0xf2, 0x4c, 0xaa, 0x1f, 0x92, 0xc7, 0xed, 0xee, 0x5a, 0xae, 0xcf, 0x05, 0x9e, 0xdb, 0xe4, 0xf1, 0x7e, 0x90, 0x73, 0xf9, 0xd4, 0x9a, 0xb9, 0x93, 0x5b, 0x1c, 0x3f, 0xef, 0xa6, 0xf3, 0xa1, 0x75, 0xe2, 0x84, 0xaa, 0xf2, 0xbf, 0x78, 0x98, 0x6f, 0x99, 0x16, 0x65, 0xa3, 0x68, 0xa3, 0xfa, 0x62, 0x1c, 0x6e, 0xeb, 0xdc, 0xe3, 0x06, 0x2b, 0x7c, 0x30, 0xe9, 0x78, 0xaa, 0x39, 0xc0, 0x0a, 0x77, 0xc0, 0xdf, 0x9c, 0xd8, 0x8a, 0xb2, 0x30, 0xb6, 0xd2, 0x67, 0x8c, 0x90, 0xa6, 0x2a, 0x86, 0x8a, 0x50, 0xfb, 0xd0, 0x8a, 0x35, 0x65, 0x32, 0xb7, 0xd3, 0x8e, 0xe1, 0x19, 0x21, 0xe9, 0xd0, 0x1e, 0x0e, 0xce, 0xa5, 0xb2, 0xe8, 0xfb, 0x45, 0x2d, 0xa7, 0x95, 0x2c, 0x19, 0x56, 0x4c,\n\t0x4b, 0xb0, 0x9a, 0x4a, 0x40, 0xfd, 0x16, 0x90, 0x4b, 0x0a, 0x68, 0x39, 0x8d, 0x02, 0xe8, 0x30, 0xaa, 0x5a, 0x6a, 0xa1, 0xb9, 0x90, 0xe0, 0xf0, 0x3e, 0xf9, 0xed, 0x02, 0xe9, 0x01, 0xdb, 0xa9, 0xcb, 0x41, 0x91, 0x62, 0xe0, 0x00, 0x2c, 0x71, 0x4c, 0xc7, 0xe8, 0x91, 0xc3, 0x87, 0xe5, 0x6b, 0x0a, 0x90, 0xbd, 0x84, 0x34, 0x28, 0x40, 0xb6, 0xbb, 0xd5, 0x82, 0xfb, 0x57, 0x80, 0x15, 0xba, 0x92, 0xac, 0xa6, 0x67, 0x61, 0x34, 0xcc, 0x49, 0x94, 0x52, 0xe4, 0x66, 0x96, 0x8d, 0x29, 0xea, 0xbc, 0x24, 0x98, 0xd9, 0x3e, 0x80, 0x52, 0xf4, 0xab, 0x8a, 0xf3, 0xde, 0x41, 0xc1, 0x9c, 0x72, 0x87, 0x3d, 0x5d, 0x8e, 0xd2, 0x92, 0xa1, 0xe7, 0x92, 0x5c, 0xb5, 0xe7, 0x2f, 0x6f, 0xad, 0xed, 0x4f, 0x49, 0xb6, 0x32, 0x2d, 0xaa, 0xc4, 0xbd, 0x3b, 0x76, 0xaa, 0xc3, 0x91, 0x16, 0x6b, 0x4d, 0xc2,\n\t0x95, 0xa7, 0xb5, 0xb6, 0xed, 0xd4, 0x70, 0x8e, 0x57, 0xf1, 0x2a, 0xf3, 0x9a, 0x8a, 0xc3, 0xba, 0x1e, 0xaa, 0x34, 0xea, 0x64, 0xce, 0xd9, 0xc5, 0xf0, 0x60, 0xf8, 0x73, 0x09, 0xd1, 0xf4, 0x15, 0x74, 0x8d, 0xdf, 0x85, 0x6f, 0x31, 0xe0, 0x1d, 0x3a, 0xfe, 0x3c, 0xe0, 0x84, 0x29, 0x51, 0x9c, 0xc8, 0x70, 0x3c, 0x4a, 0x25, 0xda, 0x47, 0xee, 0xdc, 0x93, 0x4e, 0xc4, 0x24, 0x6e, 0x62, 0x27, 0x67, 0xe3, 0x2a, 0x0a, 0x38, 0x4c, 0x9f, 0x82, 0xe8, 0x7f, 0x85, 0x97, 0x21, 0x44, 0x88, 0x5d, 0x24, 0x49, 0x2d, 0xb2, 0x71, 0x3c, 0x67, 0xe3, 0x61, 0xe4, 0x31, 0x12, 0x71, 0x8f, 0xc5, 0xc1, 0xf1, 0xce, 0x78, 0x8e, 0xe8, 0x13, 0x04, 0x5e, 0x05, 0x38, 0xfb, 0xf4, 0x38, 0x6c, 0xb7, 0xe7, 0x76, 0x0a, 0x44, 0xa4, 0xa5, 0xe9, 0x70, 0x65, 0xca, 0x27, 0x81, 0x18, 0xa6, 0x9f, 0x5d, 0x66, 0x3f,\n\t0x1c, 0x3e, 0xb4, 0x1a, 0xf2, 0x09, 0x44, 0x0d, 0xf5, 0x9b, 0x8f, 0x88, 0x9c, 0x9a, 0x0d, 0x44, 0x50, 0x2f, 0x81, 0x08, 0x5e, 0x5e, 0x5a, 0x1a, 0x19, 0xa2, 0x19, 0x69, 0xd3, 0xa7, 0x4c, 0x1e, 0x3f, 0x76, 0x54, 0xfb, 0xb0, 0xa1, 0x43, 0x5a, 0x6a, 0xab, 0xcb, 0x4a, 0xf2, 0x72, 0xb3, 0x33, 0x1d, 0xa9, 0x8e, 0xd4, 0xa2, 0x40, 0x42, 0x02, 0x30, 0x45, 0xfd, 0x7c, 0xb5, 0x36, 0x5f, 0x3d, 0x8e, 0x75, 0xe2, 0x2c, 0x9e, 0x1d, 0xb8, 0xa6, 0x64, 0xab, 0xca, 0x6a, 0x00, 0xb1, 0x4c, 0xf1, 0xa8, 0xc2, 0x99, 0x24, 0xf9, 0xb9, 0xdd, 0x57, 0x3e, 0x7a, 0x49, 0xf9, 0xcc, 0x71, 0xf5, 0x33, 0xdb, 0x8b, 0xb8, 0x1d, 0x59, 0x83, 0xa7, 0xd4, 0x35, 0x4d, 0x6f, 0x2b, 0x92, 0x39, 0xb1, 0xac, 0x73, 0xfe, 0x90, 0x11, 0x17, 0x34, 0x07, 0x5c, 0x4e, 0xb7, 0x54, 0xe3, 0xef, 0x9a, 0xd7, 0x5d, 0xb3,\n\t0xfc, 0x95, 0xc6, 0x8c, 0x69, 0x97, 0x5d, 0xd9, 0x3c, 0x72, 0xf9, 0xe4, 0xb2, 0x60, 0x94, 0x90, 0xbe, 0xb0, 0xec, 0xca, 0x3b, 0xfc, 0x75, 0x4f, 0x5d, 0x39, 0xf9, 0xb6, 0xcb, 0x9a, 0x13, 0xbd, 0xf8, 0x8f, 0xa2, 0xaf, 0x76, 0x44, 0xe1, 0xe4, 0xce, 0xdc, 0x91, 0xdd, 0xa3, 0x8f, 0xb6, 0x5c, 0x3a, 0xae, 0xb4, 0xb0, 0xa3, 0x7b, 0xd8, 0x8a, 0xa9, 0xd7, 0x9d, 0x57, 0x9c, 0x91, 0x9b, 0x61, 0xb3, 0x0c, 0x2b, 0x6e, 0x09, 0x24, 0x2e, 0x5a, 0xda, 0x3c, 0xa5, 0x2e, 0x2d, 0x6f, 0x64, 0xf7, 0xc8, 0xe6, 0xe5, 0x17, 0xb6, 0x08, 0xe5, 0xcb, 0xaf, 0xca, 0x2d, 0xca, 0x25, 0xf2, 0x3a, 0x61, 0xe2, 0x9c, 0x69, 0x53, 0x66, 0x0f, 0x5d, 0xb9, 0xa7, 0xa7, 0x2c, 0x9b, 0xc8, 0xc6, 0xfa, 0xf0, 0x97, 0x82, 0x9b, 0xae, 0xe3, 0x83, 0xa8, 0x6c, 0x1c, 0x56, 0xdf, 0xd9, 0xad, 0x27, 0xbc, 0xd0, 0x80,\n\t0x13, 0x5e, 0xf8, 0x98, 0x8a, 0x7f, 0x6d, 0xc4, 0x09, 0x2f, 0x7c, 0x8c, 0xea, 0xc3, 0xf5, 0xca, 0x56, 0xc0, 0x51, 0x1c, 0xe1, 0x4f, 0xbf, 0x62, 0x0a, 0x27, 0x31, 0x3e, 0x0e, 0xe8, 0x78, 0x75, 0x69, 0x2a, 0x2f, 0x21, 0x9f, 0xfa, 0xbc, 0x3b, 0x59, 0x05, 0x53, 0x39, 0x19, 0x95, 0x12, 0x03, 0x95, 0xe0, 0xa2, 0xa0, 0x3d, 0xf2, 0x0e, 0x10, 0xed, 0x31, 0xaf, 0x53, 0x73, 0x64, 0xb8, 0x18, 0xb8, 0x2f, 0x1b, 0xbf, 0x3e, 0x2f, 0xba, 0x73, 0x07, 0x4a, 0x1d, 0xfd, 0x7c, 0xbb, 0x12, 0x09, 0x44, 0x73, 0xc1, 0x73, 0xed, 0xa8, 0x0c, 0xf4, 0x99, 0x11, 0xe4, 0x42, 0x90, 0xc9, 0xfc, 0x5e, 0x3b, 0xce, 0x15, 0xc8, 0xf3, 0xe5, 0x97, 0xe6, 0xe7, 0xe5, 0x5a, 0x89, 0x7e, 0xca, 0x07, 0xd7, 0x01, 0xd4, 0x57, 0x47, 0xae, 0x24, 0xd7, 0xea, 0xe3, 0x2b, 0xeb, 0x3b, 0x9f, 0xea, 0x9d, 0xcd, 0xba,\n\t0x16, 0x4c, 0x9f, 0x20, 0x15, 0xc8, 0x70, 0x12, 0x54, 0x8d, 0xc7, 0x0c, 0xea, 0x69, 0x5b, 0xb7, 0xf9, 0xfa, 0x2b, 0xcf, 0x5b, 0x59, 0xdb, 0xba, 0x7d, 0x7e, 0xd7, 0xad, 0x73, 0xeb, 0xe6, 0x4c, 0xcf, 0x0c, 0x5e, 0xd2, 0x59, 0x34, 0xa6, 0xcc, 0x29, 0xa5, 0xc7, 0xc5, 0x57, 0xe4, 0x04, 0x07, 0x05, 0x0a, 0x2a, 0x27, 0x8d, 0x18, 0x9c, 0x6e, 0xb5, 0x14, 0x5f, 0x7b, 0xf4, 0xfb, 0xd6, 0xaa, 0x23, 0xc7, 0xf6, 0x3f, 0x31, 0xa6, 0xfd, 0xf6, 0xf6, 0xa9, 0x23, 0x56, 0xbf, 0x70, 0xf9, 0x03, 0x5f, 0x8c, 0xb8, 0xa4, 0x75, 0xf9, 0xf9, 0xb5, 0x89, 0xee, 0xf1, 0x44, 0x76, 0xa7, 0x8e, 0x2d, 0x93, 0xdc, 0x79, 0x35, 0xbe, 0x29, 0x45, 0xe2, 0x31, 0xe6, 0x27, 0x99, 0xbf, 0x8d, 0xce, 0xf7, 0x4a, 0x36, 0xdf, 0xd1, 0x7d, 0x08, 0xe9, 0xf8, 0x36, 0x1d, 0x7f, 0xaa, 0x1f, 0x7c, 0x8f, 0x09, 0x3f,\n\t0xa4, 0xe3, 0x87, 0x01, 0x07, 0xaf, 0xb7, 0x80, 0x0b, 0x16, 0x62, 0x01, 0x74, 0x07, 0x6d, 0xa5, 0x18, 0x8b, 0xe9, 0x98, 0x4c, 0xc1, 0x0e, 0xa6, 0x04, 0xf2, 0x22, 0xc7, 0x16, 0x1c, 0x61, 0x18, 0xfa, 0xb1, 0x45, 0xae, 0xce, 0x03, 0x7c, 0x70, 0x47, 0xe2, 0xd4, 0xc9, 0xfc, 0x40, 0x17, 0xac, 0x85, 0x01, 0x7f, 0x21, 0x1c, 0x6e, 0xa4, 0x47, 0x1d, 0x6e, 0x70, 0x6c, 0xde, 0x65, 0x1b, 0xd6, 0x01, 0x7a, 0xa4, 0x31, 0xd1, 0xea, 0x4a, 0x48, 0xf0, 0xd7, 0x76, 0xd6, 0x8f, 0x5a, 0x3c, 0x3a, 0x50, 0xd8, 0x71, 0xd9, 0xd0, 0xd6, 0x49, 0x75, 0x79, 0xee, 0xd4, 0xf8, 0x06, 0xff, 0xb4, 0xd9, 0xdd, 0xf5, 0x33, 0x77, 0xac, 0x68, 0x6f, 0x5d, 0xf9, 0xec, 0xe5, 0x8b, 0x1e, 0x1d, 0xca, 0x0f, 0xb6, 0xc7, 0xa7, 0x65, 0xa6, 0xd5, 0x5c, 0xbc, 0x61, 0x6a, 0xd7, 0xcd, 0x33, 0x2b, 0xb3, 0xf3, 0xb2,\n\t0x13, 0x47, 0x95, 0x34, 0x07, 0x12, 0xdb, 0x6f, 0x3c, 0x7a, 0xcd, 0xd2, 0x43, 0x37, 0x8f, 0x6f, 0x0f, 0xd2, 0x3d, 0xe6, 0x8f, 0xc2, 0xb5, 0xfc, 0xef, 0x05, 0xf0, 0x43, 0xde, 0x84, 0x6e, 0x0b, 0xa6, 0xd5, 0x54, 0x95, 0xf2, 0x48, 0x6c, 0x22, 0x06, 0x1b, 0x51, 0x2d, 0x72, 0x6e, 0x12, 0x87, 0xb9, 0x0c, 0xf2, 0x1d, 0xc0, 0xa3, 0xac, 0xd4, 0x87, 0xc5, 0xa9, 0x5c, 0x52, 0x2c, 0x3e, 0x53, 0x1f, 0x16, 0x91, 0x0c, 0x4b, 0xa8, 0x0f, 0x8b, 0x40, 0x5e, 0x61, 0x3e, 0xe9, 0x13, 0x1f, 0xbd, 0x1a, 0x1c, 0x60, 0xbd, 0x91, 0x8d, 0x53, 0x8c, 0xdd, 0xa1, 0x79, 0xaf, 0x60, 0x94, 0xa9, 0xba, 0x8a, 0x71, 0x24, 0x5e, 0x75, 0x12, 0x40, 0xac, 0x84, 0x8d, 0xbe, 0x72, 0xe8, 0x1e, 0x6f, 0xed, 0x98, 0xd5, 0xa6, 0xee, 0x19, 0xb3, 0xae, 0xe1, 0x76, 0xa0, 0x49, 0xbf, 0xaf, 0x6d, 0x82, 0x5e, 0x9a,\n\t0x39, 0xfe, 0x32, 0xa0, 0x45, 0x3b, 0x8a, 0xfd, 0x35, 0xa4, 0x57, 0x1d, 0x59, 0x49, 0xfc, 0x02, 0x2b, 0xf4, 0xd7, 0xa5, 0x63, 0x66, 0x5f, 0xa8, 0xf7, 0x57, 0x59, 0xe9, 0xc7, 0x1e, 0x2f, 0x9e, 0x31, 0xec, 0xb9, 0xe5, 0xd0, 0x6b, 0x19, 0x8f, 0x7a, 0xbc, 0x4a, 0xaf, 0xd7, 0x3f, 0xca, 0x1e, 0xef, 0x8e, 0x33, 0xcb, 0xca, 0xe0, 0x60, 0x7d, 0x44, 0x56, 0xfa, 0x19, 0xfd, 0x3a, 0x7d, 0xf4, 0x6b, 0x84, 0x31, 0xea, 0xd0, 0xcb, 0xff, 0x37, 0x43, 0x0f, 0xf2, 0xaf, 0x6c, 0x55, 0xe7, 0x51, 0x95, 0x69, 0x1e, 0x4d, 0x22, 0xdf, 0xf4, 0x3e, 0xd5, 0x75, 0xf5, 0x8c, 0x77, 0x5f, 0xc2, 0xd2, 0x4f, 0x22, 0x76, 0x40, 0x04, 0x07, 0xdd, 0xf8, 0x84, 0x8a, 0x7f, 0x6d, 0xc4, 0x89, 0x6e, 0xdc, 0xa9, 0xe2, 0xf7, 0x18, 0x71, 0x29, 0x19, 0x70, 0x22, 0x09, 0x93, 0x88, 0xce, 0x5c, 0x4d, 0x74, 0xa6,\n\t0x03, 0x0d, 0x46, 0x8f, 0x32, 0x9d, 0x96, 0x50, 0x8f, 0x91, 0x5c, 0xe0, 0x80, 0x2b, 0xad, 0xa9, 0xa4, 0x03, 0x41, 0x63, 0x9a, 0x21, 0x81, 0x52, 0xc9, 0x5c, 0x7a, 0x51, 0x89, 0x6a, 0x33, 0xd5, 0x5d, 0xcf, 0xe2, 0x4e, 0x9b, 0x95, 0x83, 0xde, 0x85, 0xa7, 0x97, 0x73, 0x3b, 0x81, 0x05, 0x46, 0xa8, 0x5b, 0x35, 0xe2, 0x25, 0x41, 0xe2, 0x85, 0x9e, 0xa8, 0x2c, 0xf4, 0x0e, 0x14, 0xcd, 0xa7, 0xa9, 0x40, 0xf5, 0xc4, 0x11, 0x98, 0x5a, 0x30, 0xd1, 0xe9, 0x74, 0x0e, 0x76, 0x0e, 0x76, 0x17, 0xe6, 0xf9, 0x7d, 0xf9, 0x85, 0x81, 0x5c, 0x78, 0x0f, 0x4c, 0xbd, 0xa9, 0x48, 0x6c, 0x70, 0xea, 0xea, 0xc5, 0x18, 0xea, 0xcf, 0x9f, 0x5b, 0xa1, 0x0e, 0xa3, 0x36, 0x60, 0xae, 0x6a, 0x17, 0x9f, 0x3a, 0x68, 0xc9, 0x88, 0x1b, 0x37, 0xfb, 0x5a, 0x67, 0x0c, 0x9e, 0x72, 0x4d, 0x1d, 0xbe, 0x34, 0x5a,\n\t0x05, 0x2e, 0x2d, 0xb2, 0xb9, 0x86, 0xee, 0x58, 0x38, 0xed, 0x96, 0xb9, 0x75, 0xcd, 0xcb, 0x1e, 0x9a, 0x3f, 0x63, 0x75, 0xf5, 0x31, 0x9e, 0x6b, 0xad, 0x3a, 0x7c, 0x60, 0xd6, 0xfa, 0x69, 0x45, 0x63, 0x46, 0x6c, 0x7c, 0xd1, 0xa8, 0x03, 0x6b, 0x0b, 0x7e, 0x34, 0xf6, 0xc2, 0xe1, 0x6b, 0x8e, 0x5c, 0xbb, 0xf4, 0xc8, 0xa6, 0x89, 0xcd, 0xf5, 0x5c, 0xe9, 0xf7, 0xbf, 0x64, 0x36, 0xbc, 0x3a, 0x5e, 0xb0, 0x8f, 0x82, 0x6e, 0x0f, 0xc6, 0xe5, 0x61, 0x24, 0x24, 0xd1, 0x7e, 0x03, 0x9d, 0x05, 0xc7, 0x60, 0x19, 0xd0, 0x39, 0x74, 0x63, 0x88, 0xca, 0x5e, 0x6e, 0xa7, 0x1e, 0xd6, 0x2a, 0x5d, 0xa7, 0xc9, 0xb9, 0x90, 0x46, 0x05, 0xfb, 0x4b, 0x19, 0xcc, 0x89, 0xfc, 0xc0, 0x92, 0x23, 0x9a, 0x5a, 0x9d, 0xc0, 0x7e, 0xba, 0x80, 0x38, 0x48, 0xf7, 0xe5, 0x3b, 0xf3, 0x0b, 0xf3, 0xf2, 0x02, 0xb9,\n\t0xf4, 0x2d, 0x9e, 0xa9, 0xeb, 0xdc, 0xae, 0x18, 0x1d, 0x65, 0xee, 0xa6, 0x63, 0x57, 0xf4, 0xe9, 0x15, 0x63, 0xa7, 0x08, 0x8f, 0x7c, 0xdf, 0x1c, 0xdd, 0x13, 0x48, 0x93, 0x5b, 0xf9, 0x75, 0xd2, 0x0f, 0xaa, 0xbc, 0xa1, 0x8d, 0xc2, 0x7f, 0xe9, 0x7a, 0xfe, 0x3d, 0x2a, 0xe7, 0x4d, 0x14, 0x7f, 0x12, 0x3c, 0x05, 0xc4, 0xc0, 0x77, 0x99, 0xf0, 0x6d, 0x3a, 0xfe, 0x54, 0x3f, 0xf8, 0x1e, 0x13, 0xbe, 0x46, 0xc7, 0xf7, 0x9b, 0xf0, 0x0e, 0x1d, 0x7f, 0xbe, 0x9f, 0x72, 0x0e, 0x98, 0xf0, 0x43, 0x3a, 0x7e, 0x18, 0x70, 0x70, 0x65, 0x0e, 0x38, 0xd1, 0x31, 0x16, 0xc2, 0x7b, 0x17, 0xb3, 0x55, 0x28, 0x40, 0x4c, 0x6a, 0x91, 0xac, 0xee, 0x3d, 0xb0, 0x6d, 0x26, 0x48, 0x58, 0x80, 0xbb, 0x1b, 0x74, 0x10, 0x72, 0x41, 0xba, 0xb5, 0xe3, 0x73, 0xef, 0x69, 0x25, 0xf4, 0x83, 0xd4, 0x27, 0x21, 0x54,\n\t0x5a, 0x5c, 0x90, 0xef, 0xcb, 0x4e, 0xf3, 0x38, 0xe3, 0xc1, 0xc3, 0x66, 0x9e, 0x45, 0x4a, 0x2e, 0xc1, 0x35, 0xcc, 0xa1, 0xb5, 0x49, 0x17, 0x31, 0x8a, 0xe7, 0xd3, 0xb8, 0xa1, 0x87, 0x2f, 0xf6, 0x05, 0x67, 0x34, 0xaf, 0xbc, 0xc5, 0xcd, 0xed, 0xcf, 0xbb, 0xe8, 0xb2, 0xa5, 0xf5, 0x97, 0xee, 0x5b, 0x33, 0xba, 0x6d, 0xe5, 0x33, 0x4b, 0x2e, 0xbc, 0x6f, 0xd9, 0xd0, 0x24, 0x6f, 0x68, 0x3e, 0x5f, 0x3e, 0xb1, 0x67, 0xc4, 0xd0, 0x99, 0x23, 0x2a, 0x12, 0x53, 0xe3, 0xb9, 0x45, 0x83, 0x67, 0x8f, 0x2a, 0xdc, 0x74, 0xad, 0x92, 0x07, 0x64, 0x6d, 0xe4, 0xfa, 0xe3, 0x6b, 0x2f, 0x7b, 0x7e, 0xdd, 0xb8, 0x96, 0xcb, 0x9f, 0x5c, 0x54, 0x96, 0x3d, 0xfd, 0xa6, 0x0b, 0x4a, 0xb3, 0xfc, 0x59, 0x89, 0xa7, 0x1e, 0xb3, 0x18, 0x7d, 0x4d, 0x74, 0x13, 0xe9, 0x23, 0x0d, 0x27, 0xba, 0xe9, 0x51, 0x43,\n\t0xfa, 0x63, 0x3a, 0xfe, 0x6b, 0xf4, 0x90, 0x01, 0xbf, 0x55, 0x2f, 0x67, 0x5f, 0xa4, 0x7c, 0xe1, 0x11, 0xba, 0x8f, 0xc3, 0xd2, 0x9f, 0x60, 0xe9, 0xc3, 0x87, 0x20, 0xbd, 0x01, 0xff, 0x4d, 0xa4, 0x1c, 0x21, 0x85, 0xee, 0xe3, 0x30, 0xfc, 0xb7, 0xc6, 0xf2, 0xe9, 0x5e, 0x0a, 0xc3, 0x7f, 0xa7, 0xe1, 0xd0, 0x4e, 0x7d, 0xec, 0x0b, 0x98, 0x6c, 0x69, 0xed, 0x85, 0xb1, 0x26, 0x3a, 0x99, 0x8d, 0xf5, 0x28, 0xf4, 0x95, 0xea, 0x2b, 0xa8, 0x08, 0x0b, 0xe2, 0xa8, 0x0a, 0xce, 0x22, 0x11, 0xd3, 0xda, 0x42, 0x7d, 0x05, 0x19, 0x11, 0xab, 0xee, 0x2b, 0xa8, 0x92, 0xd8, 0x04, 0x02, 0xa1, 0x95, 0x3d, 0x36, 0x08, 0x5e, 0x21, 0x6a, 0x17, 0x7a, 0x18, 0xe7, 0x03, 0xeb, 0x00, 0x01, 0xa3, 0xb4, 0x62, 0x8b, 0x85, 0xea, 0xc1, 0x1e, 0x59, 0xbb, 0xfb, 0x79, 0x3a, 0x19, 0x97, 0x98, 0x33, 0x06, 0x1b,\n\t0xb4, 0x3c, 0xc8, 0x22, 0x59, 0x25, 0x8b, 0x75, 0xe0, 0xbc, 0x9a, 0xa3, 0x20, 0x92, 0x95, 0xa8, 0x88, 0x74, 0x84, 0x86, 0x0d, 0x6d, 0x69, 0x6e, 0xa8, 0x83, 0xb7, 0xec, 0xb9, 0x39, 0x19, 0xe9, 0x49, 0x89, 0x54, 0xe2, 0xec, 0xb6, 0x88, 0xc4, 0xb9, 0xcb, 0xf9, 0x98, 0xd2, 0x06, 0xcb, 0x62, 0xbf, 0x2e, 0x83, 0x74, 0x49, 0xfc, 0xd3, 0x85, 0xf7, 0x2d, 0x6d, 0xed, 0x4f, 0x06, 0x1b, 0x72, 0x26, 0xce, 0x98, 0x53, 0xe9, 0x8a, 0x79, 0x38, 0xaf, 0xc9, 0x67, 0x68, 0x9d, 0x6d, 0xc2, 0xba, 0x43, 0x57, 0xf7, 0x15, 0xce, 0x51, 0x81, 0xfa, 0x82, 0x14, 0xbe, 0x29, 0xc6, 0xd9, 0x3d, 0xdd, 0x9b, 0x4a, 0x0d, 0xd7, 0x0a, 0x6e, 0xc2, 0xa7, 0x78, 0xf2, 0x41, 0x09, 0x28, 0x88, 0x9e, 0x08, 0xa6, 0x36, 0x61, 0xce, 0x0a, 0xc4, 0xc7, 0x82, 0x25, 0xec, 0x4f, 0xe3, 0x44, 0x69, 0x50, 0x31, 0x27,\n\t0x8b, 0x1a, 0xa5, 0xaa, 0x42, 0x36, 0xab, 0x6d, 0x19, 0xb1, 0x72, 0x45, 0x2c, 0x01, 0x53, 0x97, 0x2d, 0xcb, 0x79, 0x3b, 0x87, 0x88, 0x15, 0x28, 0x21, 0x3c, 0x97, 0x74, 0xa3, 0x75, 0x3a, 0xe9, 0x3c, 0xba, 0x66, 0xd1, 0x1e, 0x5c, 0x08, 0x9d, 0x7f, 0xa6, 0x99, 0x96, 0xc8, 0x70, 0x3f, 0x0d, 0xa1, 0xe0, 0x90, 0xc6, 0xfa, 0x8a, 0xb2, 0xa2, 0x02, 0x5f, 0x76, 0x46, 0x7a, 0x6a, 0x4a, 0x82, 0x33, 0xde, 0x2e, 0x0a, 0xa4, 0xa9, 0x3c, 0x78, 0xb5, 0xc3, 0x35, 0x05, 0x4e, 0xec, 0xcf, 0xc2, 0x1e, 0xa6, 0xb0, 0x89, 0x85, 0x02, 0x9d, 0x4c, 0x7a, 0x9e, 0x37, 0x91, 0xaf, 0x28, 0xee, 0xa5, 0x6e, 0x50, 0xf1, 0xa5, 0xa5, 0x97, 0x1e, 0x3e, 0xca, 0x65, 0xa4, 0xe2, 0x25, 0x19, 0x6d, 0x05, 0x64, 0x00, 0xb0, 0x1d, 0xd7, 0xb4, 0xb6, 0x27, 0x79, 0x95, 0xfb, 0x7e, 0x32, 0x66, 0xb9, 0xd6, 0xef,\n\t0x54, 0x3b, 0xdc, 0xb3, 0xf4, 0x06, 0xe0, 0x60, 0xc7, 0x47, 0x8c, 0x85, 0xf1, 0x69, 0x5e, 0x54, 0x71, 0x15, 0xdd, 0x9b, 0x5a, 0x34, 0x7b, 0xd8, 0x8e, 0x15, 0x23, 0x96, 0x14, 0x73, 0x6d, 0x09, 0xae, 0x4d, 0xd7, 0xe2, 0x8a, 0xa6, 0xa7, 0x96, 0x97, 0x65, 0x2b, 0x6f, 0x37, 0xd3, 0x3e, 0xa7, 0xba, 0xe2, 0x57, 0x84, 0x87, 0x0d, 0x1d, 0xf1, 0xf3, 0xf5, 0x30, 0x26, 0x69, 0xe9, 0x2f, 0x7b, 0xbc, 0x91, 0x79, 0x76, 0x44, 0x9b, 0x67, 0xe2, 0x3a, 0xa3, 0x9e, 0x30, 0xe0, 0x37, 0xe9, 0x7a, 0xe2, 0x1e, 0xa3, 0x9e, 0x20, 0x9c, 0x44, 0xd5, 0x13, 0xca, 0xeb, 0x11, 0x9c, 0xfa, 0x8f, 0x78, 0x88, 0x9e, 0x17, 0x73, 0xba, 0xff, 0x08, 0x9e, 0xcd, 0x4d, 0xfa, 0x1e, 0x24, 0x0b, 0x5d, 0x84, 0x4b, 0xd4, 0xd9, 0xd9, 0x8a, 0x2d, 0xd6, 0x8b, 0x46, 0x70, 0x71, 0xb6, 0x09, 0xd8, 0x1e, 0x47, 0x67,\n\t0xa7, 0x11, 0x89, 0xd7, 0x67, 0x67, 0x10, 0x59, 0x65, 0x8b, 0x6c, 0xb5, 0x50, 0x37, 0x10, 0x12, 0x87, 0xe6, 0x38, 0xb1, 0x88, 0x64, 0xab, 0x28, 0xcf, 0x85, 0xdd, 0x4a, 0x08, 0x5f, 0xa5, 0xce, 0x96, 0xc5, 0xe0, 0xaa, 0xc4, 0x36, 0x1d, 0xd9, 0x6c, 0x0b, 0x3b, 0xe3, 0x71, 0x5c, 0x9c, 0x7d, 0x3a, 0xb2, 0xdb, 0x7b, 0xec, 0xda, 0x64, 0x3d, 0x8b, 0x72, 0x96, 0x98, 0xcb, 0x09, 0x8e, 0xd4, 0x8b, 0x88, 0xb3, 0xc5, 0xdb, 0xe2, 0xe2, 0xcf, 0xa8, 0x28, 0x14, 0x1f, 0xaf, 0x95, 0x04, 0x7b, 0x0b, 0x29, 0x29, 0x08, 0x75, 0x4d, 0x9b, 0x3c, 0x69, 0xdc, 0x98, 0xe1, 0xc3, 0x5a, 0x9a, 0x1a, 0xea, 0xaa, 0x06, 0x15, 0x17, 0xa6, 0x64, 0xa5, 0x64, 0x65, 0xa4, 0xc3, 0x0b, 0x99, 0xbc, 0xa4, 0x3c, 0xe6, 0xa0, 0x82, 0xdd, 0xd4, 0x52, 0x3d, 0x54, 0x0c, 0xe1, 0x6a, 0xdd, 0x3f, 0x68, 0x9a, 0x77,\n\t0x64, 0xb6, 0x75, 0x8f, 0x1f, 0xdf, 0xdd, 0x96, 0xb9, 0x21, 0xde, 0x57, 0x5f, 0x5c, 0x5c, 0xef, 0x8b, 0xbf, 0xec, 0x87, 0x4e, 0x7c, 0x71, 0x5b, 0xc3, 0xec, 0xce, 0x92, 0x92, 0xce, 0xd9, 0x0d, 0x39, 0x75, 0x05, 0xc9, 0xc9, 0x05, 0x75, 0x39, 0xbd, 0x6f, 0xfd, 0x10, 0x55, 0xd0, 0x77, 0x9d, 0xc7, 0x95, 0xa6, 0x35, 0x6c, 0xa7, 0x86, 0x73, 0x7c, 0x6c, 0x3e, 0x82, 0xc3, 0x2a, 0x5e, 0x4e, 0x14, 0xea, 0xd3, 0x72, 0x2b, 0xc1, 0x5b, 0x54, 0x5f, 0x13, 0xdd, 0x78, 0x95, 0x7a, 0x3f, 0x62, 0x95, 0x7a, 0x96, 0x56, 0xae, 0x6c, 0xe5, 0x9e, 0x16, 0xf7, 0xa1, 0x1a, 0xf4, 0x38, 0xe3, 0x73, 0x4e, 0xd8, 0x0a, 0xb7, 0x06, 0x88, 0xf5, 0x91, 0x46, 0x16, 0x0b, 0x2a, 0x97, 0x46, 0x44, 0xd2, 0xf9, 0x74, 0x39, 0xb1, 0x51, 0x48, 0x1b, 0xe4, 0x1e, 0xb8, 0x73, 0x01, 0x6a, 0x83, 0xde, 0xe2, 0xc7,\n\t0x5d, 0x16, 0x8c, 0xf1, 0x7c, 0xb6, 0x57, 0x60, 0x76, 0x6b, 0x52, 0xab, 0x67, 0xd0, 0xfc, 0x9a, 0xf4, 0x9b, 0xd1, 0xe4, 0xcb, 0xc4, 0x51, 0x5d, 0x99, 0xe2, 0xf6, 0xe5, 0xe7, 0xbb, 0x5c, 0xc9, 0xd5, 0x36, 0xb6, 0xf7, 0x09, 0x16, 0x4f, 0x26, 0x9c, 0xe9, 0xc1, 0x7e, 0x66, 0x5f, 0x4a, 0xed, 0x2a, 0x28, 0xc7, 0x2d, 0xb8, 0x5a, 0xb5, 0xf2, 0xb8, 0x9d, 0xd8, 0xe1, 0xf1, 0xb9, 0xcb, 0x3a, 0x6a, 0x32, 0x70, 0xa6, 0xf2, 0xd7, 0x1d, 0xd1, 0x64, 0xfa, 0x27, 0x97, 0x79, 0x32, 0xef, 0xaf, 0xba, 0x70, 0xcd, 0xa4, 0x11, 0x83, 0xc5, 0x96, 0xf8, 0x78, 0x09, 0xa7, 0xd4, 0x4c, 0x69, 0x9d, 0xba, 0x29, 0x34, 0xd8, 0xcc, 0xa2, 0xf9, 0xf3, 0xe3, 0x45, 0x4f, 0xca, 0xc4, 0x19, 0xd3, 0xd6, 0xcd, 0xac, 0x4c, 0xa2, 0xfd, 0x5b, 0xa1, 0x6c, 0x16, 0xec, 0x94, 0x23, 0x0c, 0x53, 0xef, 0x3f, 0x70,\n\t0x2a, 0xfe, 0xba, 0x70, 0x50, 0xc3, 0xe9, 0x1d, 0x12, 0x25, 0xca, 0xa7, 0x0c, 0x86, 0x9d, 0x45, 0xe1, 0x66, 0xc2, 0x39, 0x0b, 0xd1, 0xe8, 0x60, 0x7b, 0x72, 0x12, 0xb1, 0x53, 0x88, 0x4a, 0x26, 0xc4, 0xdb, 0x6e, 0xe3, 0x24, 0x2b, 0x96, 0x31, 0xb8, 0x20, 0x52, 0xf7, 0x64, 0xa8, 0x05, 0xc2, 0x75, 0x89, 0xf4, 0x6e, 0x31, 0x74, 0xd2, 0x5c, 0x70, 0x6a, 0x4e, 0x72, 0x16, 0x16, 0x04, 0xe0, 0x41, 0x6c, 0x4d, 0x7e, 0x8a, 0xcb, 0x45, 0x37, 0x85, 0xa9, 0xef, 0x0a, 0xe3, 0xb7, 0xab, 0xa6, 0x2d, 0xed, 0x2c, 0xfa, 0xc8, 0x12, 0xee, 0x0c, 0xf3, 0x95, 0xca, 0xc5, 0xc7, 0xe0, 0x9b, 0x9b, 0xae, 0xdc, 0x7b, 0x65, 0xe0, 0xbc, 0x4c, 0x99, 0x2b, 0x2f, 0x9a, 0x7e, 0xdd, 0xa4, 0x00, 0x77, 0xd9, 0xdd, 0x77, 0x1f, 0xbb, 0x8b, 0xab, 0xc7, 0xfe, 0xde, 0x47, 0xd5, 0x8f, 0xad, 0x24, 0xb3, 0xa1,\n\t0xd5, 0x66, 0x9b, 0x9f, 0xc4, 0xe5, 0x8d, 0x5a, 0x34, 0xaa, 0x44, 0x19, 0xbf, 0x49, 0x99, 0x86, 0x9f, 0xd8, 0x04, 0xdf, 0x48, 0xda, 0x7f, 0x54, 0x3c, 0x48, 0x38, 0x73, 0x27, 0xe3, 0xc0, 0xda, 0xb7, 0x13, 0xbc, 0x8d, 0x7e, 0x7b, 0x27, 0xe3, 0x4d, 0x44, 0x4a, 0x23, 0x7d, 0x75, 0x50, 0xc7, 0xcd, 0x7d, 0xa5, 0xe2, 0x03, 0xf6, 0xd5, 0x41, 0x94, 0x07, 0x7d, 0xe5, 0x4e, 0x3c, 0x8b, 0xbe, 0xca, 0x43, 0x79, 0xfe, 0x5c, 0xd2, 0x57, 0xee, 0x7c, 0x7f, 0xcc, 0xbe, 0xa2, 0xfb, 0xe1, 0xa0, 0x47, 0x72, 0xa5, 0x98, 0x3d, 0xb5, 0x65, 0x63, 0x5a, 0x81, 0x3b, 0x2b, 0x7d, 0x78, 0xab, 0xda, 0x47, 0x6d, 0x38, 0x55, 0xef, 0xa3, 0xd5, 0x3b, 0x76, 0x8b, 0x52, 0xb7, 0xcb, 0x76, 0xc1, 0x25, 0xab, 0x95, 0x0b, 0x36, 0x29, 0x63, 0xf0, 0xb3, 0x9b, 0xd8, 0xf7, 0x4a, 0xeb, 0x69, 0x3f, 0x8c, 0x61,\n\t0xdf, 0x2b, 0x5c, 0xa7, 0x7d, 0xaf, 0xdc, 0xa8, 0xe1, 0xf0, 0xbd, 0xc2, 0x35, 0xb1, 0xbe, 0x57, 0x96, 0x89, 0x6c, 0x0c, 0x45, 0x0b, 0x82, 0xf3, 0xca, 0xb0, 0x68, 0x29, 0xf7, 0x70, 0x56, 0x31, 0x15, 0x4b, 0x56, 0x2b, 0xb6, 0x23, 0xa1, 0x23, 0xc1, 0xc9, 0xd9, 0x1d, 0x38, 0x8e, 0x2c, 0x1b, 0xd4, 0x15, 0xd0, 0x74, 0x66, 0xa5, 0x4a, 0x12, 0xdd, 0x2a, 0x98, 0xc3, 0x62, 0xd5, 0x74, 0xd9, 0x64, 0x4e, 0x10, 0xe6, 0x77, 0xc6, 0x83, 0x42, 0x66, 0x9d, 0x30, 0x14, 0x0d, 0x0d, 0xb6, 0x0e, 0x69, 0x69, 0x6e, 0x1a, 0xdc, 0xd8, 0x50, 0x5f, 0x55, 0x91, 0x9f, 0x5c, 0x0b, 0x82, 0x03, 0x5e, 0x9c, 0xb4, 0xee, 0x88, 0x16, 0x1f, 0x22, 0x3d, 0xda, 0x54, 0x1b, 0x40, 0x9e, 0xc4, 0x5d, 0xca, 0xcc, 0xa3, 0xca, 0xe8, 0x63, 0x6c, 0x1a, 0xad, 0x9d, 0x34, 0xac, 0x59, 0x8c, 0x4c, 0xb8, 0x97, 0x9b,\n\t0xae, 0x78, 0xe6, 0xca, 0xc0, 0x64, 0x10, 0xb2, 0xc2, 0xe9, 0xab, 0x41, 0xc8, 0xee, 0xb9, 0xe7, 0xe8, 0x9d, 0xaa, 0x90, 0x5d, 0xa0, 0x77, 0xe2, 0x18, 0x3a, 0xab, 0xe6, 0xc4, 0xa9, 0xb3, 0xaf, 0xbd, 0x1f, 0xc1, 0x43, 0x9a, 0x8c, 0xc9, 0x43, 0xa9, 0xcc, 0x9c, 0xc7, 0x64, 0x4f, 0xeb, 0x5b, 0xb2, 0x18, 0x1d, 0xa2, 0x76, 0xdc, 0x79, 0x4c, 0xf6, 0x84, 0xd5, 0x9a, 0xec, 0x49, 0xeb, 0x22, 0xe9, 0xc9, 0x58, 0xac, 0xd2, 0xc7, 0xa2, 0x41, 0xc3, 0xe9, 0x58, 0xac, 0xec, 0x67, 0x2c, 0x0e, 0x12, 0x0d, 0x7a, 0x98, 0x85, 0x05, 0x4a, 0x28, 0x4d, 0xf5, 0xf0, 0x56, 0x11, 0x46, 0x82, 0xeb, 0x28, 0xc1, 0xe2, 0x28, 0x6f, 0x30, 0x81, 0xfc, 0xc7, 0x12, 0x81, 0xa9, 0x86, 0x84, 0xa4, 0x75, 0xe6, 0x81, 0x12, 0xa7, 0x5b, 0x30, 0x8c, 0x0f, 0x1d, 0x29, 0xf6, 0xc7, 0x98, 0x43, 0xe5, 0x0d, 0xd6,\n\t0x9c, 0xcd, 0x08, 0x77, 0x05, 0xe1, 0x75, 0x43, 0x0b, 0x52, 0x07, 0x18, 0xdc, 0x3e, 0x0d, 0x2a, 0xf7, 0x9f, 0xe1, 0x20, 0xf7, 0x33, 0x11, 0x06, 0x1e, 0xe2, 0x2d, 0x1b, 0x53, 0x0b, 0x13, 0x33, 0xd3, 0x47, 0xb4, 0x9e, 0xe6, 0xe0, 0x1a, 0x67, 0x8c, 0x3e, 0xb0, 0x6c, 0xfc, 0xc4, 0x56, 0x7a, 0x57, 0xa4, 0x4b, 0xbd, 0xbb, 0x96, 0x45, 0xf1, 0x26, 0xe5, 0x4e, 0xfe, 0x53, 0xba, 0x1e, 0x5e, 0xc8, 0xee, 0x44, 0x5c, 0x81, 0x62, 0xe2, 0x07, 0x4c, 0xf8, 0x21, 0x1d, 0x3f, 0x6c, 0xc2, 0x1f, 0xd6, 0xf1, 0x57, 0xfb, 0x29, 0x67, 0x8f, 0x09, 0xdf, 0xa5, 0xe3, 0xbb, 0x4c, 0x78, 0x87, 0x8e, 0x3f, 0x7f, 0x05, 0x32, 0xec, 0x5b, 0x41, 0xf9, 0x17, 0xd1, 0xf6, 0xbf, 0xaa, 0xbe, 0x2b, 0x67, 0xf8, 0x36, 0x1d, 0x7f, 0xca, 0x84, 0x1f, 0xd2, 0xf1, 0xc3, 0xfd, 0xa4, 0x3f, 0x40, 0xdf, 0xb5, 0x73,\n\t0x0c, 0x17, 0x6c, 0xc8, 0x81, 0x9a, 0xd1, 0x0e, 0x76, 0x3a, 0xe4, 0x6e, 0xc4, 0x48, 0x72, 0xc0, 0xfe, 0x68, 0x01, 0xe1, 0xf4, 0xb0, 0xdf, 0x25, 0x90, 0x15, 0x1b, 0x50, 0x39, 0x0a, 0xed, 0x62, 0x19, 0x8a, 0x88, 0xad, 0x05, 0x3e, 0x0c, 0x7b, 0xe8, 0x3e, 0xbe, 0x45, 0xe6, 0x28, 0x49, 0x53, 0xb7, 0x19, 0xe7, 0x1a, 0x37, 0xb4, 0xbc, 0xc1, 0x32, 0x2d, 0x2d, 0x3c, 0xe3, 0x9b, 0xaf, 0xef, 0xfc, 0xf7, 0x93, 0xbe, 0x2b, 0x98, 0xe0, 0x74, 0x3a, 0x9b, 0x9d, 0x4d, 0x85, 0x45, 0x7e, 0xd8, 0xfe, 0xa2, 0x6f, 0xf5, 0xa2, 0xf6, 0x70, 0x8c, 0x6b, 0x35, 0x23, 0x74, 0x2d, 0x51, 0xbb, 0x95, 0x84, 0xaf, 0xf1, 0xa9, 0xe5, 0x4b, 0x87, 0xc3, 0xae, 0xce, 0x85, 0x4d, 0x93, 0xae, 0xa9, 0x3b, 0x36, 0x74, 0xe5, 0x33, 0xcb, 0x56, 0xed, 0x6f, 0x2e, 0xb3, 0xa4, 0xb9, 0xdd, 0xc5, 0x4d, 0xe7, 0xb5,\n\t0x8e, 0x5a, 0x38, 0x2a, 0xcf, 0x37, 0xac, 0x73, 0x4a, 0xf5, 0x85, 0x77, 0x5e, 0x52, 0x0f, 0xfb, 0x3c, 0xb3, 0xd7, 0xd5, 0xc6, 0xd9, 0x8a, 0x78, 0xa1, 0xb9, 0xfa, 0xc5, 0x3d, 0x33, 0x6e, 0x98, 0x5a, 0x34, 0x66, 0x04, 0xf7, 0x4a, 0x6f, 0xfb, 0x8c, 0xad, 0x3d, 0xad, 0xa3, 0xeb, 0x3a, 0x1d, 0xce, 0x0c, 0x5f, 0x46, 0xd1, 0xe8, 0x39, 0x8d, 0x97, 0xe5, 0xd7, 0xe7, 0x25, 0x0e, 0xbf, 0xfe, 0xe5, 0xab, 0x17, 0xbe, 0xb4, 0x61, 0xfc, 0xf0, 0x96, 0x51, 0x05, 0xe8, 0xff, 0xef, 0xd3, 0xff, 0x5c, 0x9f, 0x8a, 0x37, 0xd1, 0x3e, 0x9d, 0xc4, 0x0d, 0x61, 0xc6, 0x47, 0xd2, 0x58, 0x8c, 0x6c, 0xb4, 0xf7, 0x9a, 0x48, 0xef, 0x95, 0xa6, 0x72, 0x1c, 0x4f, 0x3a, 0x95, 0x75, 0x9f, 0xf1, 0xb7, 0x38, 0xc3, 0x6f, 0x59, 0xea, 0x6f, 0xf6, 0x18, 0xbf, 0xe5, 0xc6, 0xfc, 0xcd, 0x02, 0x03, 0xd5, 0x17,\n\t0x86, 0x91, 0x22, 0xff, 0xb0, 0x96, 0x94, 0x13, 0xa3, 0x8e, 0x17, 0x65, 0x1e, 0x06, 0xcb, 0x36, 0x1d, 0x8e, 0xec, 0x17, 0x77, 0xc6, 0xc7, 0xd1, 0xad, 0x60, 0x2b, 0xdd, 0x0a, 0xb6, 0x80, 0x67, 0x04, 0xf6, 0x3e, 0x8d, 0x5d, 0x06, 0x80, 0x36, 0x36, 0xc4, 0xc8, 0x85, 0x22, 0x79, 0xc0, 0x4c, 0xea, 0x37, 0x3f, 0x7c, 0x47, 0xb3, 0x9e, 0xdf, 0x6e, 0xa7, 0xa3, 0x4e, 0x8d, 0xa2, 0xd3, 0x2f, 0x03, 0xbe, 0xb7, 0xfd, 0xcc, 0xca, 0x60, 0x5b, 0xda, 0xb4, 0x08, 0xb0, 0xc2, 0x8c, 0xa5, 0x15, 0x92, 0xd2, 0xda, 0xf4, 0xd2, 0x78, 0x90, 0xc7, 0xc5, 0xa7, 0xd9, 0x30, 0x0c, 0xc2, 0xa9, 0x95, 0x44, 0x6c, 0xca, 0x53, 0x15, 0x42, 0x09, 0xbe, 0x5a, 0x46, 0x17, 0xea, 0x53, 0x04, 0x7b, 0xe2, 0x9b, 0x4a, 0x84, 0x7c, 0x92, 0x73, 0xd2, 0xc4, 0xf1, 0xe0, 0xf1, 0xd9, 0x9f, 0x9f, 0xe7, 0xa6, 0xfb,\n\t0xe7, 0x8e, 0xd3, 0xda, 0x3f, 0xf7, 0xb1, 0x93, 0x9d, 0x01, 0xc5, 0xbf, 0x09, 0xbb, 0xcc, 0x13, 0x80, 0x5b, 0x12, 0x6d, 0x04, 0x28, 0x27, 0xed, 0xa3, 0x57, 0x3c, 0xb6, 0xe0, 0x34, 0x26, 0xc5, 0x15, 0xc6, 0x59, 0xf1, 0xa8, 0xd9, 0x46, 0x98, 0xb0, 0x76, 0x66, 0xed, 0x80, 0x13, 0xa4, 0x77, 0x5b, 0x0c, 0xfd, 0xbe, 0xc7, 0xa4, 0xf7, 0x77, 0xe9, 0xf8, 0x2e, 0x13, 0xde, 0xa1, 0xe3, 0xcf, 0x33, 0x3c, 0x4c, 0xfe, 0xcd, 0x7f, 0x48, 0xef, 0x28, 0xce, 0x64, 0x77, 0x28, 0xc3, 0x33, 0xd9, 0x99, 0x33, 0xe0, 0x94, 0x63, 0xce, 0x54, 0xd7, 0x95, 0x7f, 0x68, 0x67, 0xd4, 0x46, 0x1c, 0xff, 0x19, 0xe2, 0xc4, 0x92, 0x72, 0x9e, 0x80, 0xf4, 0xf4, 0xbe, 0x2d, 0x4b, 0xff, 0x5c, 0x78, 0x16, 0x3d, 0xcf, 0x6c, 0x57, 0xb6, 0xf2, 0x1f, 0x10, 0x3e, 0x55, 0x89, 0xee, 0x66, 0x73, 0xc7, 0x0d, 0xf7,\n\t0x98, 0x5c, 0x18, 0x73, 0x65, 0x49, 0x9c, 0x88, 0xb3, 0x89, 0x7d, 0x48, 0x35, 0x63, 0x34, 0x2a, 0x09, 0xda, 0x3b, 0x9a, 0x5c, 0x46, 0x5c, 0xd4, 0x17, 0x31, 0x8b, 0x3b, 0x65, 0xca, 0x55, 0xa2, 0xec, 0xc2, 0x22, 0x44, 0xe8, 0x3c, 0x06, 0x7b, 0x30, 0x66, 0x62, 0x93, 0x2d, 0x18, 0x47, 0xdf, 0xd1, 0xb8, 0xfd, 0xc9, 0xf4, 0x94, 0x39, 0x72, 0xf5, 0xcf, 0xc5, 0x4e, 0x9a, 0x5d, 0xfe, 0x01, 0x5e, 0xd7, 0x54, 0xe3, 0xce, 0xe0, 0xd6, 0x79, 0xe7, 0xad, 0x9a, 0x5a, 0x7a, 0x6c, 0xee, 0x25, 0x9d, 0x6b, 0x1a, 0xca, 0xfa, 0x79, 0x66, 0x13, 0x38, 0xca, 0x5f, 0x39, 0x74, 0x42, 0xc3, 0xbc, 0x4d, 0x53, 0x43, 0x2b, 0xb8, 0x9b, 0x16, 0xad, 0x18, 0xd9, 0x12, 0xf2, 0xc4, 0xf6, 0x57, 0x79, 0x0c, 0x69, 0x67, 0xfc, 0xc6, 0x7e, 0x15, 0x3f, 0x42, 0x5b, 0xe9, 0x5d, 0xdb, 0x2f, 0x48, 0xbf, 0x42,\n\t0xff, 0x65, 0xa2, 0xf9, 0x41, 0x9b, 0xd6, 0x49, 0xda, 0xd9, 0x4a, 0x8e, 0x4c, 0x48, 0x23, 0x86, 0x9b, 0x19, 0xe0, 0xe8, 0x28, 0xe2, 0x98, 0xc9, 0xab, 0xc5, 0xad, 0xf2, 0x9a, 0x92, 0xe8, 0xbf, 0x92, 0xc4, 0xb8, 0x4b, 0x4d, 0x02, 0xfd, 0x01, 0xff, 0xd0, 0xfe, 0x90, 0x62, 0xf6, 0x07, 0xbc, 0x11, 0xad, 0xad, 0x4e, 0x26, 0xa6, 0x32, 0x1e, 0x13, 0xdc, 0xa2, 0x7e, 0xfd, 0x7c, 0xf2, 0xf5, 0xc7, 0x7e, 0xfc, 0xe3, 0x63, 0x38, 0x57, 0xf9, 0x03, 0x7f, 0x71, 0xdb, 0x38, 0xfa, 0xad, 0xb7, 0x73, 0x4b, 0x16, 0xad, 0x68, 0x1f, 0x12, 0xaa, 0x10, 0xae, 0xbb, 0xe6, 0xa7, 0x3f, 0xbd, 0x86, 0x7c, 0xd7, 0x22, 0xe5, 0x2e, 0xfe, 0x5a, 0xea, 0xb3, 0x63, 0x36, 0xf3, 0xd9, 0xc1, 0x09, 0x54, 0xbf, 0x2f, 0x22, 0x1f, 0x07, 0xbe, 0x3c, 0xc0, 0x8f, 0x01, 0x78, 0x56, 0x84, 0xfb, 0x6f, 0xc4, 0xf6,\n\t0xca, 0xa1, 0x57, 0x50, 0xbc, 0x9d, 0x9a, 0x37, 0xe4, 0xa4, 0x44, 0x9b, 0x05, 0x36, 0x09, 0x5d, 0xa2, 0xc4, 0x42, 0xaa, 0xbb, 0xb5, 0xdd, 0x1c, 0x75, 0xe3, 0x06, 0x4f, 0x39, 0xfa, 0x3f, 0x29, 0xf9, 0x55, 0x5e, 0xef, 0xa0, 0xfc, 0xe4, 0xe4, 0xfc, 0x41, 0x5e, 0x6f, 0x55, 0x7e, 0x0a, 0xff, 0x6d, 0xaf, 0x85, 0xff, 0x16, 0x0f, 0xf6, 0x56, 0xfe, 0x7f, 0xec, 0xbd, 0x09, 0x80, 0x94, 0xc5, 0x95, 0x38, 0x5e, 0xf5, 0x9d, 0x7d, 0xf7, 0xf4, 0x7d, 0x4d, 0xcf, 0x74, 0x4f, 0x5f, 0x33, 0xdd, 0xd3, 0x73, 0xf5, 0xdc, 0x67, 0x0f, 0x37, 0x33, 0x03, 0x33, 0x20, 0xd7, 0xc8, 0xcd, 0x0c, 0x97, 0x22, 0x0c, 0xa8, 0x88, 0x17, 0xa8, 0x88, 0x0a, 0x22, 0xa8, 0x40, 0x44, 0xc5, 0x8d, 0x89, 0x46, 0x57, 0x21, 0x04, 0x45, 0x34, 0x26, 0xc6, 0x28, 0xb0, 0xbb, 0xd9, 0x98, 0xc4, 0xe4, 0x67, 0xd6, 0xb8,\n\t0x26, 0xba, 0x9a, 0x78, 0x65, 0xa3, 0x59, 0xe3, 0x15, 0xaf, 0xf9, 0xe6, 0x5f, 0xc7, 0xf7, 0x7d, 0x7d, 0xcc, 0x0c, 0xe8, 0x26, 0xd9, 0x24, 0xbb, 0x7f, 0x50, 0xba, 0xfb, 0x7d, 0xef, 0xab, 0x7a, 0xf5, 0xaa, 0x5e, 0xd5, 0xab, 0xaa, 0x77, 0x60, 0x58, 0xb5, 0xaf, 0x90, 0x7e, 0x12, 0x3e, 0x5f, 0x20, 0xed, 0xc3, 0xf5, 0x32, 0x32, 0x3d, 0xf0, 0xf5, 0x91, 0x15, 0x64, 0xfc, 0xfe, 0xab, 0xf4, 0x43, 0xa6, 0x48, 0x81, 0x93, 0x98, 0x68, 0xcb, 0xf3, 0xce, 0xe0, 0x18, 0x30, 0x20, 0xed, 0x66, 0xde, 0x46, 0x34, 0xdb, 0x40, 0x12, 0x6c, 0xa5, 0xf3, 0x29, 0x0e, 0x90, 0x8b, 0xa7, 0xad, 0x21, 0x1c, 0xc3, 0x9b, 0x44, 0xbc, 0x58, 0x89, 0xd7, 0xde, 0x55, 0xd4, 0x1c, 0x0b, 0x1b, 0x46, 0x64, 0x96, 0xed, 0x2a, 0x05, 0x17, 0x88, 0xac, 0xc0, 0x8a, 0xc2, 0xd8, 0xef, 0x80, 0xcc, 0x2b, 0xfd, 0x69,\n\t0x17, 0x04, 0x89, 0xb2, 0xd2, 0x68, 0x28, 0x88, 0x5d, 0x7b, 0xdd, 0x4e, 0xbd, 0x16, 0xd8, 0xa0, 0x0d, 0xa7, 0x6e, 0xb2, 0xe5, 0x5c, 0x88, 0xc8, 0xc1, 0x0b, 0x88, 0xfd, 0x96, 0x25, 0x65, 0x69, 0xc8, 0x32, 0xd0, 0x7a, 0x2b, 0x9b, 0x31, 0x88, 0x51, 0xf0, 0xb7, 0xb2, 0x85, 0xd6, 0xf1, 0x53, 0x50, 0x35, 0xc0, 0xe2, 0x8e, 0x64, 0xb1, 0xa9, 0x10, 0xb3, 0xed, 0x53, 0x5e, 0xb6, 0xc1, 0x42, 0xbc, 0xbc, 0x83, 0xc9, 0xd8, 0x59, 0x8d, 0xfc, 0x07, 0x22, 0x79, 0x2b, 0x7f, 0x04, 0xf5, 0xe7, 0x20, 0xc9, 0xbf, 0xf1, 0xe0, 0x08, 0xf5, 0x2f, 0xdf, 0x81, 0x18, 0x14, 0xa7, 0x70, 0x3a, 0xef, 0x50, 0xf8, 0xc8, 0xf7, 0x10, 0xbc, 0x8e, 0xc4, 0x72, 0xa1, 0xf8, 0x47, 0x65, 0xf8, 0xcf, 0x10, 0x3c, 0xca, 0xef, 0x55, 0xe1, 0xc7, 0x65, 0xf8, 0x6f, 0x10, 0xdc, 0xcc, 0x6f, 0x57, 0xe0, 0xfc, 0xd3,\n\t0x32, 0x1c, 0xc7, 0xa3, 0xf3, 0xf1, 0x5d, 0x2a, 0xfe, 0x63, 0x32, 0xfc, 0x15, 0x04, 0xb7, 0x66, 0x95, 0xff, 0xb8, 0x0c, 0xff, 0x31, 0x82, 0x5b, 0x28, 0xfe, 0x47, 0x14, 0x7f, 0xe9, 0x99, 0xca, 0xc7, 0xb7, 0x76, 0xf0, 0x01, 0xb2, 0xef, 0x23, 0x70, 0xf8, 0x1c, 0x8e, 0x0e, 0x3a, 0x06, 0xfd, 0xc7, 0x14, 0x7a, 0xd0, 0x78, 0x29, 0x67, 0x71, 0xce, 0xa1, 0x41, 0x13, 0x1d, 0x2f, 0x1b, 0x46, 0xc5, 0xd0, 0x7b, 0x1a, 0x27, 0x05, 0x16, 0xde, 0x92, 0xdf, 0x8d, 0x21, 0x9e, 0xec, 0x87, 0xad, 0x38, 0x9b, 0x32, 0x2e, 0x43, 0x3e, 0x43, 0x6b, 0x95, 0xf7, 0x88, 0x3a, 0xf4, 0xcf, 0x27, 0xa8, 0x3c, 0x3d, 0x08, 0xa6, 0x8b, 0x78, 0xc8, 0x62, 0x5b, 0x68, 0x16, 0x2c, 0xa7, 0xe3, 0x82, 0xec, 0xcd, 0x88, 0x94, 0x16, 0x08, 0xd4, 0x3f, 0x2e, 0xa4, 0x04, 0xbd, 0x82, 0x9f, 0x1c, 0x38, 0x8d, 0x8f,\n\t0x13, 0xe0, 0x03, 0x64, 0x0f, 0x04, 0x9f, 0xc6, 0x31, 0xea, 0x50, 0x79, 0x68, 0xfe, 0x86, 0x3d, 0xa8, 0x3c, 0x16, 0xe7, 0x18, 0x65, 0xe8, 0xa9, 0x98, 0x12, 0x40, 0x0b, 0xcb, 0x13, 0xab, 0xa3, 0xf2, 0x04, 0x7b, 0x4e, 0x51, 0x71, 0xc1, 0xf1, 0xb4, 0xb1, 0x6c, 0x28, 0x6d, 0x22, 0xb2, 0xb1, 0x31, 0x8b, 0xc7, 0x87, 0x15, 0x1e, 0x30, 0xac, 0xcc, 0x03, 0x54, 0x13, 0xfc, 0x55, 0x66, 0x2c, 0xc0, 0x11, 0xd2, 0x2e, 0x66, 0xe4, 0xdb, 0xd2, 0x01, 0x22, 0xdb, 0x16, 0x10, 0x01, 0xf3, 0x4f, 0x68, 0x49, 0x90, 0xb9, 0xee, 0x63, 0x15, 0x38, 0x7e, 0x1b, 0x8e, 0x02, 0x8d, 0x27, 0xe2, 0x00, 0xc9, 0x60, 0xe6, 0xeb, 0x96, 0xb3, 0x3d, 0xa3, 0xe9, 0x8d, 0x46, 0x99, 0x23, 0x39, 0x5f, 0xf3, 0x90, 0xb0, 0x20, 0x98, 0x01, 0x28, 0x09, 0xb8, 0x9d, 0x38, 0xee, 0x70, 0x84, 0x7a, 0x83, 0xe7, 0xe8,\n\t0xac, 0xf5, 0x75, 0x63, 0x4c, 0x0c, 0xc1, 0xa9, 0x1b, 0xfb, 0x82, 0x0d, 0x85, 0x1a, 0xce, 0x17, 0x9d, 0x91, 0x7e, 0xcb, 0x19, 0x45, 0x23, 0x5b, 0x96, 0x85, 0xc2, 0xea, 0x28, 0x9a, 0x24, 0x3e, 0xfb, 0x41, 0xc7, 0x05, 0xb3, 0x2a, 0x74, 0xda, 0xf3, 0x6c, 0xdc, 0x94, 0x59, 0x5c, 0xe3, 0x18, 0xf3, 0x05, 0x6a, 0xcb, 0x8b, 0xd2, 0x01, 0x34, 0x5e, 0xa8, 0xcc, 0x4f, 0x4d, 0x4f, 0x2a, 0x82, 0x2c, 0x07, 0xbb, 0x34, 0x50, 0x40, 0x94, 0x71, 0x02, 0x43, 0x7c, 0xf2, 0x15, 0x11, 0x26, 0xba, 0x78, 0xc6, 0x06, 0x0a, 0x02, 0x9c, 0xc6, 0xa7, 0xac, 0x34, 0x86, 0xc4, 0xb7, 0xd0, 0xeb, 0xb0, 0x53, 0xe1, 0xc5, 0x71, 0xfc, 0x61, 0x9e, 0xf0, 0xda, 0x42, 0xf9, 0x8d, 0x51, 0x3a, 0xd7, 0x96, 0x4d, 0x31, 0x6a, 0xc1, 0x2b, 0x07, 0x73, 0x1a, 0xb5, 0x7f, 0xff, 0xa9, 0x83, 0xa3, 0x65, 0xf7, 0xf3,\n\t0x61, 0xc9, 0x95, 0xd5, 0x32, 0xf8, 0x5b, 0x3a, 0x2a, 0x98, 0x91, 0xa3, 0xa8, 0x5f, 0x86, 0x48, 0x5b, 0x62, 0xb0, 0x52, 0xed, 0x17, 0x6d, 0x76, 0xbf, 0xa4, 0x08, 0xcb, 0x2b, 0xd4, 0x7e, 0x69, 0x04, 0x4a, 0xcc, 0x98, 0x71, 0x51, 0xaa, 0x80, 0x12, 0x26, 0xe6, 0x2c, 0xa5, 0x58, 0xce, 0x5e, 0x8a, 0xed, 0xec, 0xa5, 0x38, 0xce, 0x5e, 0x4a, 0xc5, 0xd9, 0x4a, 0x19, 0x35, 0xd2, 0x64, 0x24, 0x59, 0x97, 0xec, 0x27, 0xe3, 0x2d, 0x5c, 0xe2, 0x75, 0x23, 0x56, 0xd9, 0xea, 0x23, 0x82, 0x98, 0x33, 0xde, 0x98, 0x9a, 0xb1, 0x07, 0x5c, 0x4f, 0x70, 0xda, 0xc6, 0xde, 0x92, 0x7a, 0xbf, 0x86, 0xd1, 0x98, 0x3d, 0x36, 0x3c, 0xe4, 0x46, 0xad, 0x4b, 0xea, 0x90, 0xd3, 0x69, 0xb9, 0xa9, 0x7d, 0x63, 0x8e, 0x39, 0x24, 0x57, 0x48, 0x7e, 0x98, 0x2a, 0x32, 0xe7, 0xac, 0x96, 0xe7, 0xcc, 0x41, 0xa2,\n\t0x0b, 0xfc, 0x0b, 0xea, 0xbf, 0xcf, 0x90, 0x7c, 0xfa, 0x40, 0x45, 0x3a, 0xa1, 0xd7, 0xe1, 0xf8, 0xde, 0x5d, 0x02, 0xe4, 0xb0, 0xb1, 0x05, 0x07, 0x70, 0xb4, 0xf9, 0x55, 0xdd, 0x4a, 0xdc, 0xa5, 0x21, 0x32, 0x5f, 0x20, 0xda, 0x0b, 0x44, 0xbc, 0xdd, 0x0b, 0x8d, 0xa2, 0x5e, 0x19, 0x61, 0x9f, 0xdd, 0x86, 0xa9, 0x46, 0x23, 0x4a, 0x94, 0xa9, 0xde, 0xbf, 0xff, 0xf4, 0x6d, 0x68, 0x32, 0x71, 0x65, 0x13, 0xaa, 0x0c, 0x21, 0xa2, 0xa7, 0x5c, 0xce, 0x0e, 0x13, 0x3d, 0x65, 0x0d, 0xf5, 0xb3, 0xdf, 0x0a, 0x94, 0x18, 0xb2, 0xec, 0x30, 0xd1, 0x23, 0xd7, 0xc8, 0x7a, 0xe4, 0x22, 0x55, 0x8f, 0x1c, 0x26, 0xe7, 0x31, 0x14, 0xff, 0x9b, 0xd7, 0x00, 0x55, 0x8f, 0xcc, 0x2a, 0x07, 0xbe, 0xbe, 0x39, 0xa3, 0x07, 0x65, 0xc1, 0xf9, 0x5f, 0x6f, 0xa1, 0xfe, 0xd7, 0xd8, 0xd6, 0x71, 0x06, 0xd1, 0x23,\n\t0xf7, 0xd3, 0x95, 0x57, 0xe7, 0x81, 0x90, 0x8b, 0x41, 0x51, 0x83, 0x2d, 0x66, 0x95, 0x1f, 0x5a, 0x46, 0xb9, 0x59, 0x28, 0xc3, 0x11, 0x16, 0x05, 0x0e, 0x0e, 0xd0, 0x03, 0x5d, 0xc2, 0x1b, 0x1c, 0x45, 0x10, 0x1f, 0x7b, 0x0d, 0xe6, 0x5d, 0x27, 0x57, 0x01, 0x0d, 0xd0, 0x02, 0x8d, 0x76, 0xe8, 0x8c, 0xef, 0x64, 0x5f, 0x23, 0xa7, 0x4d, 0x95, 0xc9, 0x48, 0xc4, 0x85, 0x03, 0x36, 0x46, 0x0a, 0xf0, 0x7d, 0x42, 0x30, 0x14, 0x8d, 0xa1, 0x7d, 0xc6, 0xa8, 0x70, 0x8d, 0x02, 0xce, 0x6a, 0x04, 0x47, 0x5f, 0x30, 0xd4, 0xb1, 0xf7, 0xac, 0x0c, 0x3b, 0xa4, 0x7f, 0x36, 0x17, 0x15, 0xd5, 0x9e, 0x3a, 0x55, 0xe1, 0x28, 0x34, 0xc3, 0x2a, 0x53, 0x89, 0xf7, 0x61, 0xe9, 0x76, 0x7f, 0xd0, 0xe6, 0x37, 0x41, 0xc3, 0xc9, 0xfc, 0xcd, 0x05, 0x17, 0x84, 0x07, 0x5d, 0x46, 0xa9, 0x98, 0x3f, 0xfd, 0xf9,\n\t0xd7, 0x0c, 0x56, 0xd8, 0x6b, 0xb3, 0x49, 0x97, 0x44, 0xec, 0xc6, 0x12, 0xbb, 0xf4, 0xb5, 0x9c, 0xfd, 0x83, 0xc2, 0x73, 0x34, 0x4e, 0x04, 0x40, 0xd7, 0x36, 0xb4, 0xf2, 0x31, 0x9b, 0x71, 0x1f, 0x70, 0x17, 0xd1, 0x33, 0x31, 0x1c, 0xf9, 0x16, 0xaf, 0xd9, 0xd2, 0xe5, 0x70, 0x16, 0xe6, 0xb5, 0x0c, 0xff, 0x27, 0x59, 0x67, 0xf7, 0x23, 0x7c, 0x03, 0xe2, 0xf5, 0xe8, 0xb5, 0x68, 0xe5, 0x19, 0xd7, 0x22, 0xc6, 0x70, 0xd7, 0xe9, 0x3d, 0x7b, 0x4e, 0xdf, 0xc5, 0xdc, 0x31, 0xbc, 0x8a, 0xb9, 0x63, 0x0f, 0x73, 0x68, 0x78, 0x90, 0xd4, 0x73, 0x39, 0x5a, 0x57, 0xce, 0xcb, 0xd4, 0x83, 0xd6, 0x95, 0xe5, 0x64, 0xcc, 0x3c, 0x27, 0xed, 0x63, 0xf4, 0xd8, 0x47, 0x84, 0xc0, 0x63, 0x14, 0x8e, 0xfd, 0xcf, 0xe4, 0xb5, 0xfa, 0x59, 0xe9, 0x43, 0xc6, 0x96, 0x79, 0x8f, 0xff, 0xb5, 0xfc, 0xde, 0x09,\n\t0xe9, 0x20, 0x93, 0xcc, 0xc0, 0x05, 0x87, 0x4c, 0x37, 0x5a, 0x8f, 0x98, 0x0a, 0x44, 0xb7, 0x0d, 0xd4, 0xa5, 0x6b, 0xd0, 0x1c, 0xad, 0xd3, 0x32, 0x3c, 0x1a, 0x42, 0xcb, 0x39, 0x9c, 0x8b, 0x00, 0x7b, 0x4f, 0xa8, 0xf9, 0x0b, 0x06, 0x49, 0x7a, 0x6a, 0x24, 0xdc, 0x16, 0xe5, 0x0f, 0x31, 0xb4, 0x72, 0x28, 0x67, 0x95, 0xa9, 0x3a, 0x25, 0xa6, 0x24, 0xbc, 0xe5, 0x2e, 0xdc, 0x28, 0xdc, 0x2c, 0xb6, 0xe0, 0xe6, 0x3d, 0x92, 0x09, 0xbe, 0xb7, 0xe7, 0xe6, 0x3d, 0x4c, 0x74, 0xf8, 0x45, 0x7a, 0xde, 0x78, 0x13, 0xd2, 0x6f, 0x2f, 0xc5, 0x7a, 0x83, 0xcc, 0xc3, 0x55, 0x70, 0x44, 0x59, 0x7f, 0xf9, 0x3f, 0x72, 0x1a, 0x10, 0x07, 0x0b, 0xd3, 0x7a, 0x1e, 0x29, 0xe0, 0x65, 0x7a, 0x86, 0xe5, 0x18, 0xd9, 0xbd, 0xc9, 0x89, 0x5d, 0xfe, 0x71, 0x42, 0x77, 0x06, 0x80, 0x55, 0xdd, 0x1a, 0xb4, 0x01,\n\t0x96, 0x3d, 0x3f, 0xbc, 0x00, 0x03, 0xf0, 0x53, 0xb8, 0x10, 0xaf, 0xda, 0xeb, 0x33, 0x0f, 0x69, 0x20, 0x80, 0x38, 0x88, 0x87, 0x1c, 0x21, 0x47, 0x34, 0x1c, 0xc4, 0xe7, 0x38, 0x78, 0xa8, 0x15, 0x2b, 0x06, 0xd0, 0x6c, 0xb6, 0xde, 0x6e, 0xca, 0xd6, 0xe0, 0x77, 0x5e, 0x5c, 0xa6, 0x33, 0x35, 0xee, 0x5c, 0xb4, 0x72, 0xab, 0xdf, 0x39, 0x65, 0xde, 0xf2, 0x9a, 0x59, 0xdb, 0x16, 0x54, 0x9c, 0x1e, 0x58, 0x1a, 0xef, 0x69, 0x0a, 0x9e, 0x5e, 0xb2, 0xb0, 0x63, 0x5d, 0x92, 0xfd, 0x38, 0xb6, 0x7c, 0xe2, 0xdc, 0x0d, 0x4b, 0xeb, 0x67, 0xd6, 0xb8, 0x53, 0x2b, 0x6e, 0x5e, 0x84, 0x37, 0x2d, 0x9b, 0x2e, 0xf2, 0x37, 0xcf, 0x6b, 0xc2, 0xdf, 0x36, 0x0f, 0x4d, 0x68, 0x1a, 0x96, 0xf3, 0x0a, 0x91, 0x76, 0x91, 0xfd, 0xe5, 0x3a, 0xd9, 0xde, 0xfd, 0x9f, 0xb2, 0xe0, 0x4f, 0xa9, 0xf0, 0xa7, 0x15,\n\t0xb8, 0xb4, 0x0f, 0xf3, 0x41, 0x81, 0xc3, 0xd7, 0xe1, 0xc3, 0x8a, 0x3c, 0x0b, 0x47, 0x10, 0x7f, 0x3a, 0xc0, 0x4f, 0xe5, 0x3b, 0x43, 0x2f, 0x0e, 0xce, 0x61, 0x63, 0x34, 0xb0, 0x0e, 0x6a, 0x75, 0xe4, 0xce, 0x30, 0x1b, 0xa2, 0x27, 0x27, 0xe2, 0x98, 0x77, 0x11, 0xbc, 0x71, 0xe1, 0x17, 0x8a, 0x02, 0x43, 0x04, 0x54, 0xa3, 0x01, 0xfd, 0x1c, 0xbe, 0x08, 0xa2, 0x0e, 0x18, 0xe4, 0xac, 0x60, 0x48, 0xab, 0x9c, 0x77, 0x94, 0x11, 0x29, 0x66, 0x55, 0xb3, 0xf6, 0xf5, 0xe3, 0xbf, 0x80, 0xa6, 0x01, 0x1d, 0x1a, 0xf2, 0x3a, 0xfd, 0xd0, 0x19, 0xdf, 0x01, 0x7a, 0xbd, 0xf2, 0x0a, 0xf6, 0xab, 0x68, 0x6b, 0x69, 0x6e, 0x4c, 0x55, 0xe3, 0xfe, 0x40, 0x1b, 0xa8, 0x10, 0xf1, 0xab, 0x08, 0x8e, 0xd1, 0x03, 0xa1, 0x31, 0x3a, 0x6a, 0x8c, 0x59, 0x41, 0x60, 0x9e, 0xcd, 0xee, 0x96, 0x53, 0x63, 0xf4,\n\t0xdb, 0x89, 0xfc, 0x89, 0x61, 0x74, 0x4f, 0xe5, 0xf7, 0xa6, 0x64, 0xcc, 0x99, 0x21, 0xc8, 0xfe, 0xeb, 0xc6, 0x91, 0x3a, 0xfe, 0x13, 0x0e, 0xcf, 0xa7, 0xf5, 0xe0, 0x59, 0xca, 0x58, 0x47, 0x31, 0x64, 0x78, 0x13, 0x5a, 0x4c, 0xea, 0x53, 0xe5, 0x65, 0xa5, 0x76, 0x11, 0xa0, 0xfd, 0x09, 0x31, 0x1f, 0x47, 0x70, 0x76, 0x14, 0x5c, 0xe9, 0x0d, 0xf4, 0x4b, 0x73, 0x21, 0x4e, 0x82, 0xd6, 0x8f, 0x7a, 0x84, 0xec, 0xb5, 0xb1, 0x09, 0x0e, 0x89, 0x58, 0xb9, 0xaa, 0x9b, 0x82, 0x20, 0xee, 0x0d, 0x9a, 0x4e, 0x24, 0x1f, 0x99, 0xa3, 0xc1, 0x8e, 0x64, 0xb3, 0xb0, 0xf5, 0x99, 0x17, 0xc6, 0xc0, 0x05, 0x2a, 0x2a, 0x3e, 0x96, 0xca, 0xe0, 0x62, 0xc3, 0xf1, 0xb0, 0xd3, 0x11, 0x72, 0xe2, 0x3e, 0x20, 0x5b, 0xfa, 0xb1, 0xb9, 0xde, 0x41, 0xa6, 0x64, 0x91, 0x86, 0xca, 0x44, 0xdb, 0x79, 0x88, 0x6f,\n\t0xe7, 0x48, 0x88, 0x89, 0x06, 0x13, 0x74, 0x30, 0xff, 0x91, 0xcf, 0x72, 0xc7, 0xa4, 0x73, 0x96, 0x56, 0x2f, 0xc0, 0x06, 0x22, 0xdb, 0x2e, 0xda, 0x7a, 0x7a, 0xda, 0x64, 0xe9, 0xb3, 0xd3, 0x4f, 0x63, 0xeb, 0x11, 0xc6, 0xbd, 0xb7, 0x7d, 0x16, 0x9c, 0x01, 0x9b, 0x73, 0xb9, 0x5d, 0x37, 0xa3, 0xc6, 0x03, 0x77, 0xb9, 0x7c, 0x3f, 0xf0, 0x7f, 0xef, 0x4e, 0xdc, 0x17, 0xcb, 0x87, 0xcc, 0xd2, 0xa0, 0x54, 0x77, 0x9b, 0xf4, 0x53, 0x97, 0x8f, 0x9d, 0xf1, 0xaa, 0x6d, 0xfd, 0xc2, 0xcc, 0xb9, 0x0a, 0x96, 0x9f, 0x0b, 0xe4, 0xf3, 0x99, 0xfb, 0xb3, 0xce, 0x5b, 0x0e, 0xa9, 0xf0, 0x63, 0x39, 0xf0, 0xbd, 0x2a, 0xfc, 0xb8, 0xea, 0x13, 0x70, 0x39, 0xfb, 0x2a, 0x91, 0xab, 0x0b, 0xe4, 0x78, 0x29, 0xf7, 0x80, 0xb1, 0xca, 0x7f, 0x30, 0xa7, 0x9c, 0xa7, 0x54, 0xf8, 0xd3, 0x6a, 0x39, 0xfb, 0xb2,\n\t0xcb, 0x81, 0xaf, 0x83, 0x3b, 0x33, 0xe7, 0x11, 0x19, 0x38, 0xff, 0x6b, 0xd9, 0x3e, 0x77, 0xa7, 0x74, 0x30, 0x1b, 0x2e, 0x38, 0x64, 0xbb, 0x75, 0xbc, 0x3e, 0x7f, 0x05, 0xc9, 0x73, 0x05, 0xbe, 0xe3, 0xc2, 0x92, 0xa7, 0x0f, 0x15, 0x32, 0x1a, 0x4e, 0xab, 0xc4, 0x47, 0x51, 0x7e, 0xd1, 0xf8, 0x28, 0x78, 0xe4, 0x84, 0x54, 0xa7, 0x91, 0x55, 0x64, 0x3d, 0x66, 0xfb, 0x79, 0x38, 0x2a, 0x48, 0x0a, 0x2d, 0x2b, 0x06, 0x30, 0x12, 0xc2, 0x97, 0x6d, 0x68, 0xc7, 0x45, 0x4f, 0x57, 0x64, 0x72, 0xf0, 0x8c, 0xfb, 0x46, 0x76, 0x70, 0x95, 0xfe, 0x34, 0x0e, 0x9d, 0x5d, 0x01, 0x2a, 0xa2, 0x68, 0xec, 0x60, 0x03, 0x01, 0x9d, 0xae, 0x30, 0x11, 0x19, 0xd3, 0x1e, 0x20, 0x77, 0x4c, 0xc9, 0x32, 0xcc, 0x7d, 0x25, 0x5f, 0x1c, 0x9f, 0x25, 0xe7, 0x42, 0x78, 0x18, 0x99, 0x83, 0xd3, 0x66, 0x2d, 0xae,\n\t0xc3, 0xa7, 0x25, 0xfb, 0x73, 0x4f, 0xf8, 0x94, 0x03, 0x21, 0x34, 0x72, 0x56, 0x85, 0x9a, 0xcb, 0x5c, 0xf8, 0xe8, 0x44, 0x32, 0x2a, 0xfa, 0xcf, 0x01, 0xfe, 0xb7, 0xe4, 0xbc, 0xe4, 0x02, 0x39, 0x4e, 0xf0, 0x06, 0xd5, 0xd6, 0xaf, 0x84, 0xf4, 0xeb, 0x06, 0xb9, 0x5f, 0x0f, 0x8f, 0x09, 0x3f, 0x92, 0x03, 0x3f, 0xa4, 0xc2, 0x8f, 0xe6, 0xc0, 0xf7, 0xaa, 0xf0, 0xe3, 0x39, 0xf0, 0xed, 0x2a, 0xfc, 0x44, 0x0e, 0xbc, 0x4b, 0x85, 0x3f, 0x36, 0x4e, 0xf9, 0x8f, 0x8f, 0x43, 0xcf, 0xf7, 0x65, 0xbb, 0x6b, 0x02, 0x47, 0xe3, 0xc3, 0x06, 0x8a, 0x71, 0x24, 0x61, 0x12, 0x15, 0x14, 0xad, 0xcb, 0xa0, 0x9e, 0x68, 0xde, 0x4a, 0x06, 0x45, 0x87, 0x1d, 0x02, 0x9f, 0xc7, 0x5e, 0xec, 0x28, 0xa6, 0xbb, 0x25, 0x92, 0x15, 0x5e, 0xde, 0x25, 0x29, 0xba, 0xb6, 0x4d, 0xf1, 0x09, 0x71, 0xd8, 0x9d, 0x4c,\n\t0xf3, 0xd0, 0x89, 0x6d, 0x93, 0x26, 0x6d, 0x3b, 0x31, 0xb4, 0xf1, 0xc4, 0x55, 0x93, 0x27, 0x5f, 0x75, 0x62, 0xe3, 0xcd, 0x7b, 0xf6, 0xdc, 0x7c, 0xeb, 0xde, 0xbd, 0x9c, 0x66, 0xfa, 0xce, 0xa7, 0xb7, 0x6c, 0x39, 0x79, 0xc3, 0xf4, 0xe9, 0x37, 0x9c, 0xdc, 0xb2, 0xe5, 0xe9, 0x9d, 0xd3, 0x3f, 0xbf, 0xe6, 0xe4, 0xb1, 0x63, 0xa7, 0x4e, 0x1d, 0x3b, 0x76, 0x32, 0x8b, 0xce, 0x17, 0x55, 0x3a, 0xdf, 0x1e, 0x83, 0xce, 0x5e, 0xba, 0x67, 0x71, 0xa9, 0xc4, 0x96, 0x64, 0x88, 0x0d, 0xe2, 0x39, 0x6a, 0xcc, 0x27, 0x21, 0x7c, 0xa6, 0x66, 0x1b, 0xd5, 0x12, 0xe1, 0x2f, 0xd0, 0x12, 0x6a, 0xd3, 0x89, 0xe9, 0x55, 0xda, 0x81, 0xe4, 0x37, 0xbb, 0x1f, 0x4e, 0xab, 0xf0, 0xe7, 0xc0, 0x11, 0x15, 0x7e, 0x94, 0xf8, 0x04, 0x6f, 0x90, 0x6d, 0x4c, 0x09, 0x7c, 0xe4, 0x87, 0x18, 0x9f, 0xd8, 0x98, 0x6e,\n\t0x90, 0x6d, 0x4c, 0x33, 0xf8, 0x25, 0xc4, 0xc6, 0x74, 0x83, 0x6c, 0x63, 0x9a, 0x0d, 0xff, 0x81, 0x0a, 0xff, 0xa5, 0x02, 0xc7, 0xf4, 0xa8, 0xe3, 0x22, 0x46, 0xe9, 0x19, 0x35, 0xfe, 0x32, 0xe3, 0xe6, 0x18, 0x79, 0x8e, 0xed, 0xdb, 0x1e, 0xc4, 0xe3, 0x0c, 0x7d, 0x33, 0x83, 0x56, 0x39, 0xc6, 0xd2, 0x09, 0x0f, 0x8e, 0x01, 0xde, 0xe5, 0x43, 0x9f, 0x22, 0x8d, 0x4f, 0xef, 0x26, 0xe6, 0xc7, 0x0c, 0x2b, 0xb0, 0x8c, 0x40, 0x22, 0x80, 0xf2, 0x34, 0x02, 0xa8, 0xec, 0xcd, 0x81, 0x27, 0x13, 0x6e, 0x91, 0x12, 0x2a, 0xb4, 0x1c, 0x21, 0x8a, 0x2c, 0x23, 0x0e, 0xa1, 0x69, 0x8a, 0x15, 0x85, 0xf5, 0xa3, 0xf1, 0x41, 0x06, 0xbd, 0x3f, 0x6d, 0x6c, 0x69, 0xaa, 0xaf, 0xad, 0x08, 0x87, 0x43, 0x16, 0x1a, 0x84, 0x88, 0x84, 0x08, 0x75, 0xaa, 0x1e, 0x48, 0x59, 0xe1, 0x41, 0xd9, 0xec, 0xcd, 0x7b,\n\t0x4e, 0x68, 0x50, 0x76, 0xf1, 0xf0, 0x13, 0xcc, 0xa4, 0xe1, 0x27, 0xf6, 0xde, 0x4a, 0x7b, 0x0f, 0xfe, 0x86, 0x84, 0x04, 0x9d, 0xd0, 0xb0, 0xf2, 0xeb, 0x1b, 0xdb, 0x70, 0xa7, 0xe2, 0x4e, 0x6e, 0xbe, 0xe0, 0xce, 0xe5, 0xd6, 0xb0, 0xcf, 0xa2, 0x06, 0x04, 0xe5, 0x9e, 0xd9, 0xf6, 0xf9, 0xc3, 0xc7, 0x4e, 0x92, 0x5e, 0xfd, 0xbc, 0x1a, 0x07, 0x02, 0xad, 0x5d, 0x1a, 0xd5, 0xf6, 0x5d, 0xff, 0xed, 0x8d, 0xb8, 0xbb, 0x71, 0xf7, 0x6f, 0x78, 0x74, 0xc7, 0x6c, 0xbd, 0xc1, 0x1f, 0x2a, 0x93, 0x83, 0x80, 0x82, 0xac, 0x3e, 0xb8, 0x4e, 0xe1, 0x25, 0x37, 0x3f, 0x87, 0xc7, 0x4f, 0xa9, 0x3c, 0x7e, 0x3a, 0x1b, 0x4e, 0xfc, 0x9f, 0x37, 0xc8, 0xfe, 0xcf, 0x87, 0xf1, 0x82, 0x48, 0x9f, 0x67, 0x7b, 0x40, 0xab, 0xb8, 0xaf, 0x2a, 0x65, 0xf0, 0x3b, 0x72, 0xca, 0x78, 0x4c, 0x85, 0xdf, 0x98, 0x03,\n\t0x3f, 0xa9, 0xc2, 0x6f, 0x18, 0x07, 0x7e, 0x7d, 0x0e, 0x8d, 0x4f, 0xaa, 0xf0, 0x29, 0xb9, 0x70, 0x65, 0x7c, 0xf2, 0x6d, 0xe3, 0xe0, 0xb7, 0xe7, 0xc0, 0x4f, 0xaa, 0xf8, 0x4d, 0xe3, 0xc0, 0xd3, 0xb9, 0x70, 0xb5, 0x9c, 0x09, 0x39, 0xf0, 0xbc, 0xf9, 0x40, 0x85, 0x1f, 0x57, 0xf1, 0x5b, 0xbe, 0xd0, 0x7c, 0x79, 0x58, 0x81, 0x33, 0xec, 0xd8, 0xf3, 0x22, 0xda, 0x25, 0x50, 0xf8, 0xe4, 0x91, 0x47, 0xb8, 0x4e, 0x72, 0x86, 0x36, 0x24, 0xcf, 0xdf, 0x0f, 0xc8, 0xbe, 0x7d, 0x87, 0x39, 0x1b, 0xa7, 0x07, 0x26, 0xd4, 0x4f, 0xd7, 0xa4, 0xf1, 0x5d, 0x24, 0x40, 0x73, 0x0e, 0x0b, 0x14, 0x57, 0x30, 0x1f, 0x71, 0x8e, 0xc0, 0x93, 0x4e, 0x89, 0xaa, 0x3e, 0x05, 0xf1, 0x82, 0xe7, 0xe7, 0x94, 0xfb, 0xc6, 0xb1, 0x50, 0x42, 0x0a, 0x4a, 0xba, 0x18, 0x49, 0x80, 0x4f, 0x75, 0xcc, 0x1b, 0x8d, 0x81,\n\t0x96, 0x46, 0x6d, 0xd0, 0x56, 0x1a, 0x8b, 0x12, 0x07, 0x31, 0xc5, 0x17, 0x8f, 0x1a, 0x4e, 0xc6, 0xe4, 0xe5, 0x4f, 0x5e, 0x26, 0xc9, 0x9a, 0xe8, 0x82, 0x3d, 0x19, 0x47, 0x8a, 0x2b, 0xeb, 0x74, 0x81, 0xe9, 0x73, 0x96, 0xd6, 0xcf, 0xbf, 0x69, 0xb0, 0xa1, 0x6d, 0xe3, 0x3d, 0xab, 0x16, 0x5e, 0x93, 0xc2, 0x2b, 0xe2, 0xa7, 0xaa, 0x27, 0xc5, 0x94, 0x1d, 0xd1, 0x8e, 0xa4, 0x67, 0xd2, 0xb5, 0x27, 0xb7, 0x6e, 0x7c, 0x7a, 0xcf, 0xac, 0xd6, 0x7a, 0x69, 0x2a, 0x3f, 0x23, 0x46, 0xd7, 0x3f, 0xd4, 0x6e, 0xc2, 0x8f, 0x4d, 0xd4, 0x5e, 0xa2, 0x4d, 0x59, 0x17, 0x31, 0xfc, 0x29, 0x19, 0x8e, 0xc7, 0xec, 0x9d, 0xe4, 0x7c, 0xee, 0x23, 0x95, 0x4f, 0x95, 0xe0, 0x1b, 0x79, 0x7c, 0xc2, 0x27, 0x5b, 0x11, 0x0d, 0xe4, 0x44, 0x88, 0x3d, 0x11, 0x97, 0x93, 0xb6, 0x62, 0xaf, 0xd5, 0xf5, 0x6a, 0x63,\n\t0xd7, 0xe1, 0x29, 0x60, 0x8d, 0xea, 0x27, 0x7b, 0x66, 0xe4, 0x0d, 0x0a, 0x72, 0xba, 0x2c, 0x0b, 0x4f, 0xab, 0x5d, 0x95, 0xeb, 0x0f, 0x99, 0x83, 0x8b, 0x7d, 0x52, 0x2a, 0xca, 0xc9, 0xfd, 0x0a, 0x66, 0xa5, 0x2e, 0xcb, 0xad, 0x71, 0x4c, 0x56, 0x92, 0xf8, 0x9c, 0x21, 0xba, 0xfb, 0x3c, 0x2b, 0x4b, 0x6f, 0xbf, 0xfd, 0xd4, 0xbe, 0x7d, 0x67, 0x64, 0xeb, 0x91, 0x3d, 0xdb, 0xb6, 0xed, 0xe1, 0xd2, 0xf2, 0x9d, 0x3a, 0xf1, 0x17, 0x25, 0xbc, 0x6a, 0x85, 0x7e, 0xaa, 0x84, 0x15, 0x14, 0x9a, 0xb0, 0x6b, 0x68, 0x3d, 0x14, 0x40, 0x84, 0x7a, 0x8b, 0xca, 0x3e, 0x51, 0xd9, 0x70, 0x0d, 0xf1, 0x22, 0xcd, 0x05, 0xe1, 0x2c, 0xc1, 0xb2, 0xe9, 0x42, 0x28, 0x97, 0x57, 0x54, 0xa7, 0x1b, 0x94, 0xfd, 0x41, 0x35, 0x50, 0x71, 0x1f, 0x2d, 0x22, 0x8a, 0xdc, 0x28, 0x76, 0x8d, 0x87, 0x8e, 0xa9, 0x48,\n\t0x8c, 0x8f, 0x8e, 0xb6, 0x64, 0x6b, 0xf2, 0x5c, 0x4e, 0xeb, 0x01, 0x27, 0xf2, 0x22, 0x76, 0x39, 0xcd, 0x7b, 0x8b, 0xe0, 0xcb, 0x0e, 0x58, 0x1b, 0xe8, 0x9b, 0x39, 0x7e, 0xa7, 0xa8, 0x8f, 0x5a, 0x9a, 0x6c, 0x41, 0xa4, 0xfe, 0x95, 0x9f, 0xb9, 0x8f, 0xc6, 0xf4, 0x3d, 0x0d, 0x09, 0x67, 0x97, 0x81, 0xc6, 0xfa, 0x7c, 0x35, 0xb1, 0xb2, 0xbe, 0xf9, 0x0c, 0x42, 0x71, 0xc1, 0x13, 0x53, 0x1f, 0xcf, 0x51, 0x19, 0x4d, 0x8a, 0x88, 0x64, 0xcf, 0x0d, 0x36, 0x34, 0xe6, 0x6f, 0x4a, 0x3b, 0x6d, 0x1a, 0x51, 0xe0, 0x91, 0xa8, 0xc0, 0xb2, 0x70, 0x10, 0xe9, 0x23, 0xa1, 0x12, 0x12, 0x57, 0xf5, 0x7f, 0x74, 0x9a, 0x48, 0xc4, 0x12, 0x99, 0x69, 0xa2, 0x21, 0xd6, 0xe0, 0xc2, 0xb1, 0x5a, 0x47, 0x31, 0x0f, 0xc7, 0x6a, 0xcd, 0xe3, 0x55, 0x91, 0xeb, 0xbc, 0xab, 0x36, 0x26, 0xab, 0x46, 0x31, 0x6c,\n\t0xf5, 0x92, 0x95, 0xdb, 0x36, 0xd6, 0xd4, 0x65, 0x58, 0xc4, 0xdd, 0x3b, 0xfb, 0x5b, 0x55, 0xb7, 0xad, 0xc9, 0xe3, 0xd3, 0x81, 0xb7, 0x27, 0x1f, 0x9a, 0xfd, 0x2d, 0x43, 0xf6, 0xfc, 0x81, 0x18, 0xf4, 0x3c, 0x99, 0x67, 0x2f, 0xa6, 0xf3, 0x87, 0x83, 0xce, 0x1f, 0x6b, 0x10, 0xfc, 0x15, 0x72, 0xa6, 0x7a, 0xf1, 0x08, 0xb1, 0xcf, 0xb2, 0x53, 0xf8, 0xd5, 0xd2, 0xe5, 0xcc, 0xb3, 0xc4, 0xaf, 0xff, 0x62, 0xf9, 0x0c, 0x6c, 0x31, 0xcd, 0x47, 0x83, 0xf0, 0x7f, 0x8f, 0x78, 0x1c, 0x00, 0xdf, 0xa6, 0x6c, 0xd2, 0x09, 0x68, 0x9f, 0x61, 0x81, 0x2c, 0xde, 0xce, 0x74, 0x1f, 0x2b, 0x97, 0x21, 0x1a, 0x19, 0x82, 0x7f, 0x30, 0xf2, 0x0f, 0x45, 0x2e, 0x0a, 0x45, 0xc8, 0x0a, 0x90, 0x24, 0x7b, 0xa5, 0x9b, 0x14, 0x7c, 0xdf, 0x47, 0x1d, 0x00, 0xf9, 0x1e, 0xb9, 0x8c, 0x40, 0x06, 0x07, 0x8d, 0xcb,\n\t0x55, 0x99, 0xdd, 0x8c, 0x8a, 0x87, 0x64, 0x06, 0x7b, 0x75, 0x42, 0x9c, 0xd5, 0x26, 0x07, 0x35, 0x73, 0xc9, 0x4d, 0x31, 0xf1, 0x36, 0x38, 0x68, 0xa1, 0xd9, 0x6d, 0x32, 0x37, 0xdb, 0x4e, 0x97, 0x88, 0x79, 0x8e, 0x8f, 0x23, 0xc4, 0xcc, 0xf1, 0x16, 0xcd, 0x14, 0xb1, 0xac, 0x7a, 0xd7, 0xf2, 0x60, 0x8b, 0xd3, 0x28, 0x7a, 0x4d, 0x8d, 0x81, 0xca, 0x69, 0x4d, 0xe5, 0xb6, 0x3b, 0xef, 0x3c, 0x75, 0xcb, 0x2d, 0x43, 0x01, 0x17, 0xcf, 0xd6, 0x0d, 0x6e, 0x32, 0x9b, 0xf7, 0xf9, 0xf4, 0xbe, 0xba, 0x19, 0xd5, 0x93, 0xf7, 0xc8, 0x77, 0x4b, 0x2e, 0xbf, 0xb2, 0x97, 0x64, 0x9e, 0x25, 0xfa, 0x05, 0xe5, 0xf1, 0xd3, 0x32, 0x8f, 0x2f, 0x91, 0xf6, 0x65, 0xf3, 0x12, 0xbe, 0x8e, 0x79, 0xa9, 0xc0, 0xc9, 0x1e, 0x02, 0xc3, 0xa3, 0xe0, 0x31, 0x87, 0xfa, 0x94, 0xf0, 0xba, 0x4f, 0xba, 0x93, 0xf9,\n\t0x09, 0xe2, 0x75, 0x12, 0xc6, 0x29, 0xe7, 0x4c, 0x0a, 0xaf, 0x0b, 0xa9, 0xf9, 0x38, 0x9d, 0x0d, 0x4c, 0x0a, 0xbf, 0x55, 0x68, 0x79, 0x1e, 0x54, 0xc0, 0xf3, 0x94, 0x49, 0xe9, 0x09, 0x0a, 0xe8, 0x57, 0xba, 0xa3, 0x24, 0xa7, 0x13, 0x58, 0x56, 0x3c, 0x77, 0xb4, 0x7d, 0x79, 0xc6, 0xc9, 0x3d, 0xb7, 0x2b, 0xc6, 0xc3, 0xc6, 0x04, 0x24, 0x55, 0x53, 0xf4, 0x71, 0xdf, 0xca, 0x32, 0x3f, 0xc0, 0xc1, 0x5d, 0xe4, 0xfe, 0xcc, 0x79, 0x2f, 0xab, 0x37, 0xc7, 0x7a, 0xad, 0x9f, 0xf4, 0x2e, 0xde, 0xa0, 0x8e, 0xdb, 0xbb, 0xe3, 0x98, 0xb1, 0x93, 0x9e, 0x4e, 0x8f, 0xea, 0xe9, 0x47, 0x47, 0xed, 0x5b, 0x47, 0x75, 0xbb, 0xe4, 0xce, 0x33, 0x5e, 0xff, 0x58, 0xee, 0xff, 0x1b, 0x50, 0xff, 0xff, 0x84, 0xdc, 0x07, 0x12, 0x59, 0x62, 0x58, 0x2a, 0x4b, 0x23, 0xff, 0x49, 0xe0, 0x47, 0x14, 0x38, 0x1c,\n\t0x91, 0x65, 0xac, 0x7d, 0xe4, 0x5d, 0xd6, 0x47, 0x64, 0x72, 0x33, 0x95, 0xc9, 0x9a, 0x6c, 0xf8, 0x21, 0x15, 0x7e, 0x74, 0x1c, 0xf8, 0x31, 0x05, 0x2e, 0x5d, 0xce, 0xfa, 0xc8, 0x5e, 0x87, 0xc2, 0xff, 0xc9, 0x49, 0xc7, 0x0f, 0xc1, 0x47, 0x7b, 0xb6, 0x36, 0x1c, 0xe3, 0xb7, 0x0d, 0x42, 0xbe, 0x08, 0x32, 0xdc, 0xb8, 0x31, 0x7e, 0x4b, 0xb2, 0x63, 0xfc, 0xb6, 0x34, 0x95, 0x92, 0xeb, 0xb9, 0x33, 0xc4, 0xf8, 0x8d, 0x8e, 0x17, 0xe2, 0x97, 0x79, 0x45, 0x63, 0x35, 0x15, 0xc4, 0x1a, 0xba, 0x52, 0xf1, 0xc9, 0x55, 0xde, 0xe4, 0xf4, 0xc5, 0xcb, 0x17, 0x4f, 0x4f, 0xa6, 0x06, 0x6e, 0x5d, 0xb2, 0xf6, 0xe1, 0xd6, 0x0a, 0x8d, 0xdb, 0x6e, 0x2b, 0x6d, 0xec, 0x6b, 0xad, 0xe9, 0xaa, 0x76, 0x27, 0xa7, 0x2f, 0x59, 0xb1, 0x64, 0x7a, 0xb2, 0x7a, 0xf1, 0xce, 0x05, 0x2b, 0xef, 0x69, 0x66, 0xa7,\n\t0x1b, 0xf5, 0x4e, 0xaf, 0xd3, 0x11, 0x49, 0xf9, 0xa3, 0x35, 0x61, 0x7f, 0xa0, 0xac, 0x6d, 0x5e, 0xfb, 0xd4, 0x4b, 0x17, 0xd4, 0x4c, 0xa1, 0x36, 0x3f, 0x3e, 0x4f, 0xa2, 0xb1, 0xb8, 0xb4, 0x2e, 0x5a, 0x18, 0x88, 0xa7, 0x17, 0x4d, 0x68, 0x59, 0x37, 0xbb, 0x3a, 0xdd, 0xa8, 0xf2, 0xe4, 0x29, 0xb5, 0xed, 0x4f, 0xab, 0x3c, 0xd9, 0x97, 0xcd, 0x13, 0xf8, 0xba, 0x33, 0xc3, 0xc3, 0x06, 0xc1, 0x2f, 0xc3, 0xa3, 0xd8, 0xee, 0x14, 0x47, 0x3a, 0xba, 0x76, 0x31, 0x8d, 0x6b, 0xbf, 0x58, 0xc9, 0x69, 0x4b, 0xca, 0x15, 0x4e, 0x2b, 0xef, 0xf3, 0x7b, 0xb3, 0xcb, 0x55, 0xeb, 0x8b, 0x92, 0x72, 0x69, 0xad, 0x88, 0xdf, 0xd2, 0x9d, 0xec, 0x76, 0xc4, 0xef, 0x73, 0xe0, 0x14, 0x59, 0x32, 0x9b, 0xa1, 0x56, 0xf4, 0xa1, 0xe9, 0x09, 0x1f, 0xf7, 0xb0, 0x34, 0x10, 0x8f, 0x0a, 0x60, 0x54, 0x5b, 0xe6,\n\t0x1a, 0xa0, 0xd1, 0xf2, 0x5a, 0x0d, 0x0e, 0xc4, 0x23, 0x68, 0x79, 0xb4, 0x21, 0x93, 0x6f, 0x54, 0xd6, 0x77, 0x63, 0x2b, 0x7c, 0x41, 0x89, 0xa3, 0x93, 0x77, 0x00, 0x54, 0x44, 0x4c, 0xe7, 0xd4, 0x37, 0x75, 0x5a, 0x5e, 0xb7, 0x5e, 0x0f, 0x75, 0x82, 0x56, 0x97, 0x5d, 0x02, 0x18, 0xf7, 0xfd, 0x12, 0x62, 0x3a, 0x77, 0xd6, 0xf7, 0x65, 0xdb, 0x0b, 0x39, 0x7c, 0x4e, 0xee, 0xa9, 0xd2, 0xc4, 0xf1, 0x5e, 0x87, 0x38, 0x22, 0x2e, 0x33, 0x34, 0x6e, 0x31, 0x39, 0x47, 0x4d, 0xfd, 0x69, 0xdc, 0x37, 0xe7, 0x80, 0x73, 0x26, 0x4d, 0xe8, 0x68, 0x6b, 0xac, 0x0f, 0x45, 0x4a, 0xb0, 0x3c, 0x1b, 0x74, 0xbe, 0xb1, 0x0f, 0x9c, 0x68, 0x3c, 0x81, 0x71, 0xc6, 0x9e, 0x98, 0x3f, 0x52, 0x45, 0x76, 0x7b, 0xbe, 0x44, 0x3f, 0x51, 0x3c, 0x31, 0x7a, 0xe6, 0xa1, 0x98, 0x18, 0x63, 0x00, 0x27, 0xf2, 0x0e,\n\t0xab, 0x34, 0x9a, 0x33, 0x0c, 0xcc, 0xa9, 0xa3, 0x87, 0xf2, 0xa2, 0x2e, 0xc5, 0x0e, 0x9b, 0x79, 0x98, 0xf8, 0x0d, 0x5d, 0x2e, 0xfb, 0x0d, 0x5d, 0x92, 0xeb, 0x37, 0x84, 0x70, 0x62, 0x68, 0xed, 0x7d, 0x0a, 0xed, 0xf0, 0xa2, 0xe0, 0x0a, 0x89, 0xc8, 0x73, 0x15, 0x95, 0xe7, 0x38, 0x5a, 0x0f, 0x4e, 0x21, 0x78, 0x3b, 0xbe, 0xeb, 0xc3, 0x5b, 0x7e, 0x4b, 0x0c, 0xb2, 0x7c, 0x7b, 0x91, 0x9f, 0xe3, 0xa0, 0x68, 0x96, 0x87, 0x58, 0x1e, 0x8c, 0x8e, 0x32, 0x37, 0x09, 0x92, 0xc1, 0xf1, 0xdc, 0x26, 0x20, 0xb2, 0x90, 0x15, 0xe1, 0x90, 0x80, 0x86, 0x04, 0x31, 0x1a, 0x94, 0xa7, 0xe6, 0x45, 0x4a, 0x9f, 0xc6, 0x73, 0xd0, 0xf0, 0x9c, 0x0c, 0x99, 0xf5, 0x59, 0xd8, 0xb8, 0xeb, 0x16, 0x29, 0x21, 0x98, 0xf5, 0x21, 0x8b, 0xa5, 0xd4, 0x1b, 0xb6, 0x27, 0x70, 0x64, 0x88, 0x88, 0x09, 0x8e, 0xeb,\n\t0x1d, 0x86, 0x43, 0x69, 0xe1, 0xf8, 0x5a, 0x6d, 0xb0, 0xc1, 0x86, 0x4f, 0x9b, 0x49, 0xba, 0x63, 0xe5, 0x78, 0xc0, 0x59, 0x0c, 0x99, 0x53, 0x65, 0xe7, 0xb5, 0x14, 0x8c, 0x69, 0x33, 0x16, 0x5f, 0xb8, 0x62, 0xb3, 0xc5, 0xf5, 0x8d, 0x72, 0xce, 0x65, 0x1d, 0x80, 0x01, 0xe9, 0x95, 0x96, 0x0a, 0x5f, 0xac, 0xd0, 0xae, 0xd1, 0xe9, 0x85, 0xe6, 0x9e, 0x48, 0x52, 0x6c, 0x1e, 0xc3, 0x7a, 0xec, 0x2a, 0xcb, 0x75, 0x17, 0x30, 0xcb, 0x1c, 0x8e, 0x5e, 0x17, 0xac, 0xb4, 0xd8, 0xa4, 0xc3, 0x7b, 0x86, 0xbf, 0xd9, 0xda, 0x62, 0xb2, 0x98, 0xb4, 0xba, 0x25, 0x98, 0xbf, 0x65, 0x23, 0xef, 0x32, 0xff, 0x49, 0xf6, 0x4c, 0x57, 0xc8, 0x7b, 0xa6, 0xe7, 0x48, 0xdf, 0x94, 0xa1, 0xf5, 0xf8, 0x24, 0x8f, 0xf3, 0x5b, 0x5d, 0x41, 0xe7, 0x0c, 0x59, 0xe6, 0xcb, 0xa4, 0x0f, 0x99, 0xd7, 0x32, 0x70, 0xfe,\n\t0xd7, 0x2a, 0xfc, 0x20, 0x23, 0x65, 0xe0, 0x82, 0xa3, 0x86, 0xc6, 0x88, 0x7e, 0x70, 0xa4, 0x8e, 0xfd, 0x06, 0xea, 0xa7, 0x72, 0xd4, 0xdb, 0x93, 0xd2, 0x9d, 0x02, 0xea, 0x85, 0xa4, 0x1d, 0x47, 0xcc, 0x8f, 0x05, 0x19, 0x9e, 0xc3, 0xa1, 0xfd, 0x59, 0xb8, 0x09, 0xb0, 0x0c, 0xbb, 0x09, 0x47, 0xe2, 0xb8, 0x50, 0x84, 0xd8, 0xad, 0x86, 0x9e, 0xe2, 0x73, 0x1c, 0xbf, 0x08, 0xb1, 0x79, 0x1d, 0xdf, 0x63, 0x8d, 0xc4, 0xc3, 0x21, 0x4b, 0xa9, 0x05, 0x73, 0xd6, 0x96, 0xcb, 0x3a, 0xe2, 0xdd, 0x09, 0x1d, 0x59, 0xec, 0xa3, 0x32, 0x41, 0x0f, 0xed, 0x6d, 0xa1, 0x17, 0x33, 0xfc, 0xd2, 0xac, 0xc3, 0xe7, 0xf4, 0xc3, 0x1f, 0x67, 0x31, 0xad, 0xea, 0xda, 0xa9, 0xfd, 0x97, 0xf8, 0x1e, 0xc6, 0x27, 0xf6, 0xf0, 0xfd, 0xa3, 0x47, 0xa1, 0x9d, 0x99, 0x92, 0xe1, 0xd4, 0x83, 0x2e, 0xdf, 0xe7, 0x3f,\n\t0xde, 0xa5, 0x30, 0xab, 0xbc, 0xaa, 0x6b, 0xb2, 0xf4, 0x96, 0xcb, 0xc7, 0x5a, 0xa1, 0x8d, 0xf2, 0x8d, 0xdb, 0x42, 0xe6, 0xbe, 0xab, 0xc9, 0x9e, 0xff, 0x24, 0xb3, 0x1c, 0xc8, 0xfc, 0xe4, 0x36, 0x93, 0x75, 0xec, 0x6a, 0x7a, 0x06, 0x2b, 0xc3, 0x63, 0x23, 0xef, 0xf2, 0x01, 0xb2, 0xee, 0x5d, 0x2d, 0x51, 0x3f, 0xa6, 0xa5, 0x0a, 0x3e, 0x9f, 0x24, 0xeb, 0x18, 0xc5, 0x3f, 0x9a, 0x29, 0x87, 0x17, 0xc9, 0xd9, 0x01, 0x2d, 0xff, 0xe9, 0x2c, 0xb8, 0x8d, 0xe8, 0x49, 0x14, 0xff, 0xb1, 0xac, 0xf2, 0x0b, 0x89, 0xad, 0x14, 0x2d, 0xff, 0x78, 0x56, 0xf9, 0xba, 0xac, 0xf2, 0x1f, 0xcf, 0x2a, 0x27, 0xbb, 0xde, 0x63, 0x4a, 0x39, 0xd2, 0x0f, 0x79, 0x17, 0x19, 0x0f, 0xb8, 0x9c, 0x18, 0x6a, 0xd7, 0x52, 0x6a, 0xeb, 0xc6, 0x9c, 0x9b, 0x6b, 0xeb, 0xa6, 0xe2, 0xb6, 0x51, 0xdc, 0x2c, 0x9c, 0xec,\n\t0x18, 0xc6, 0x98, 0xae, 0x6e, 0x62, 0xdf, 0x44, 0xca, 0x43, 0xed, 0xde, 0x45, 0xed, 0x9b, 0x70, 0xb9, 0x39, 0xf6, 0x4d, 0x0c, 0xe1, 0xdd, 0x5b, 0xa8, 0x6e, 0x1b, 0x48, 0x83, 0xfb, 0xd3, 0x3a, 0xb4, 0x8b, 0xd4, 0xc7, 0x91, 0xe4, 0x29, 0x17, 0xa2, 0xb5, 0x40, 0x87, 0xe4, 0x5a, 0x07, 0x86, 0x0c, 0x38, 0x75, 0x23, 0x23, 0xf2, 0xcc, 0x72, 0x63, 0xc6, 0xb4, 0x46, 0x8b, 0xb6, 0x7c, 0xfa, 0x7e, 0x6a, 0x18, 0x2c, 0x8a, 0xec, 0x22, 0x8d, 0x12, 0x28, 0xaf, 0xf1, 0x0b, 0xbf, 0x46, 0xe6, 0x65, 0x51, 0xd4, 0x2c, 0x42, 0xda, 0xd6, 0x3a, 0x0d, 0x12, 0xe9, 0x20, 0x04, 0xc4, 0x93, 0xa9, 0xb9, 0xa6, 0xba, 0xa2, 0xbc, 0x24, 0x80, 0x13, 0x67, 0xe0, 0xb4, 0x0e, 0x8a, 0x9d, 0x8e, 0x69, 0x6c, 0x3b, 0x1d, 0xaa, 0x3d, 0xe7, 0x88, 0x34, 0x3d, 0x17, 0xcc, 0x1d, 0xb9, 0x96, 0x14, 0xfb, 0x6e,\n\t0x9e, 0xe1, 0xdd, 0x4b, 0x87, 0x4e, 0xef, 0xdd, 0x2b, 0x31, 0xb9, 0x03, 0xf4, 0xf2, 0x1d, 0x68, 0x08, 0xdf, 0x97, 0xc0, 0x43, 0x98, 0x39, 0x79, 0x88, 0x7b, 0x98, 0x58, 0x82, 0xd4, 0xe0, 0xf7, 0x6a, 0xa8, 0x29, 0xcf, 0x1f, 0xa9, 0xe6, 0x1d, 0xca, 0x08, 0x76, 0x79, 0xd5, 0xae, 0xab, 0xb2, 0x65, 0x5e, 0xea, 0x25, 0x73, 0x26, 0xe5, 0x2f, 0x96, 0xc5, 0xcb, 0xd2, 0xba, 0x12, 0xc8, 0x69, 0x9d, 0x10, 0x07, 0x13, 0x53, 0xa2, 0x69, 0x6a, 0xb4, 0x9a, 0x4d, 0x3a, 0x72, 0x93, 0xcf, 0xb3, 0x60, 0xb9, 0x88, 0xf6, 0xcd, 0xda, 0x7e, 0xba, 0x4d, 0xe6, 0x79, 0xb8, 0x48, 0x80, 0xf2, 0xa5, 0x5b, 0xfc, 0x0c, 0x88, 0xe4, 0x0a, 0x8e, 0xe7, 0x85, 0x45, 0xd8, 0x93, 0x1f, 0xe7, 0x1c, 0x29, 0x20, 0xe6, 0x4d, 0xb6, 0x78, 0x88, 0x18, 0x03, 0x90, 0x0b, 0xf4, 0x2f, 0xc1, 0x20, 0xee, 0xad, 0xb3,\n\t0x33, 0x44, 0x31, 0x6a, 0x3b, 0x5b, 0xf3, 0x55, 0x59, 0x38, 0xac, 0x8c, 0x79, 0xa4, 0x61, 0x67, 0x64, 0xf6, 0xe7, 0x19, 0x99, 0x85, 0x23, 0x19, 0xb8, 0xf0, 0x0e, 0x91, 0x85, 0x1d, 0x54, 0xc6, 0xb9, 0xe7, 0x55, 0xf8, 0xef, 0x88, 0x2c, 0xef, 0xa0, 0x32, 0x2e, 0xc3, 0xd1, 0x58, 0x17, 0x0f, 0x50, 0x38, 0x95, 0x71, 0xee, 0xe7, 0x0a, 0xbe, 0xf8, 0x75, 0xb2, 0xaf, 0xa4, 0xf8, 0x47, 0x33, 0xe5, 0x88, 0x57, 0x10, 0x3b, 0x43, 0x5a, 0xfe, 0xd3, 0x59, 0xf0, 0x1b, 0x88, 0x5d, 0x22, 0xc5, 0x7f, 0x2c, 0xab, 0xfc, 0x5b, 0x88, 0x8c, 0xd3, 0xf2, 0x8f, 0x67, 0x95, 0xbf, 0x2d, 0xab, 0xfc, 0xc7, 0xb3, 0xca, 0xc9, 0xae, 0xf7, 0x98, 0x52, 0x8e, 0xf4, 0x43, 0x71, 0x0f, 0x6d, 0x17, 0x91, 0xc9, 0xe3, 0xdc, 0xcf, 0x3e, 0x2d, 0x86, 0xb8, 0x7d, 0x3f, 0x57, 0x64, 0x32, 0x5b, 0xc6, 0x11, 0x6e,\n\t0x1b, 0xc5, 0x25, 0xbe, 0x6b, 0x3f, 0x1b, 0x4b, 0xc6, 0xc5, 0xa7, 0x89, 0x8c, 0xd3, 0xf2, 0x8e, 0xf0, 0x80, 0xca, 0x78, 0xa6, 0xbc, 0x6c, 0x19, 0x17, 0x97, 0x12, 0x19, 0x5f, 0x04, 0x9e, 0x48, 0xeb, 0xbb, 0xa1, 0x60, 0xea, 0x88, 0x33, 0x19, 0x21, 0x6f, 0x32, 0x43, 0x24, 0x9d, 0xd0, 0x08, 0x86, 0x2c, 0xaa, 0xb8, 0x5a, 0x33, 0xe2, 0x6a, 0xd0, 0x22, 0x25, 0xd0, 0xd4, 0x5f, 0x00, 0x4d, 0xa6, 0x55, 0xdd, 0x3a, 0x88, 0x05, 0x5d, 0xaf, 0x61, 0x64, 0x49, 0x6f, 0xfb, 0x12, 0xef, 0x12, 0x61, 0xc7, 0x05, 0x68, 0x16, 0xe9, 0xa1, 0x2c, 0xee, 0x09, 0xb4, 0xf4, 0x2f, 0x3c, 0xb7, 0x7f, 0xc1, 0xbc, 0x73, 0x66, 0xcf, 0xea, 0x9d, 0x3a, 0x65, 0x62, 0x67, 0x43, 0xdd, 0xd8, 0x82, 0x6f, 0xfb, 0xb2, 0x82, 0x7f, 0xd6, 0xb1, 0xae, 0x0e, 0x79, 0x61, 0x65, 0xde, 0x9c, 0xf0, 0x1f, 0x77, 0x9c,\n\t0xbe, 0xe5, 0x16, 0xc9, 0xd9, 0x5c, 0x49, 0x44, 0x40, 0x6b, 0x40, 0x22, 0xb0, 0x03, 0x89, 0x80, 0xd4, 0x30, 0xae, 0x50, 0xc0, 0x9f, 0x26, 0x59, 0x97, 0x75, 0x90, 0x39, 0x7a, 0xc7, 0x97, 0x98, 0x2c, 0xc6, 0x97, 0x1e, 0x58, 0xad, 0xca, 0x10, 0x9d, 0x43, 0x50, 0xff, 0xb5, 0x81, 0x69, 0x60, 0x6f, 0x5a, 0xdf, 0x00, 0x39, 0x43, 0xc2, 0xc9, 0x64, 0x26, 0x91, 0x84, 0x11, 0xea, 0x0d, 0xfa, 0x4d, 0x66, 0x75, 0x72, 0x20, 0xbe, 0x83, 0x86, 0x7e, 0x13, 0x34, 0x18, 0xb0, 0x9f, 0x2c, 0x9e, 0x48, 0xb4, 0xea, 0xf5, 0x7d, 0xe5, 0x19, 0xb1, 0xc9, 0x64, 0x82, 0x5f, 0x11, 0x16, 0xe1, 0x49, 0x9a, 0x4c, 0x27, 0xde, 0x69, 0x53, 0xa7, 0x4c, 0x46, 0xaa, 0x71, 0x7b, 0x5b, 0x4b, 0xaa, 0xa6, 0x32, 0x19, 0x52, 0x26, 0x96, 0x82, 0xb3, 0x4d, 0x2c, 0x5f, 0xbc, 0x03, 0xc4, 0xa5, 0x7f, 0x02, 0xc3,\n\t0xc7, 0x9d, 0x8c, 0xce, 0xce, 0x5e, 0x55, 0x8e, 0x0f, 0x2b, 0xf2, 0xca, 0xb0, 0x59, 0x72, 0x3c, 0x3d, 0x33, 0xdf, 0xc0, 0x11, 0x19, 0xbe, 0x15, 0xed, 0xcb, 0xe8, 0x39, 0xd6, 0x75, 0xf2, 0x7d, 0xef, 0xdd, 0x63, 0xc2, 0x8f, 0xe4, 0xc0, 0x0f, 0xa9, 0xf0, 0xa3, 0x39, 0xf0, 0xed, 0x2a, 0xfc, 0x44, 0x0e, 0xbc, 0x4b, 0x85, 0x3f, 0x36, 0x4e, 0x39, 0x8f, 0xe7, 0xc0, 0xdf, 0x50, 0xe1, 0xdf, 0x95, 0xe3, 0x03, 0x60, 0xf8, 0x7f, 0x11, 0xfa, 0xaf, 0x93, 0xef, 0x7b, 0x73, 0xca, 0x07, 0xa3, 0xca, 0x47, 0xfb, 0xca, 0xe7, 0xd9, 0x8f, 0x95, 0x72, 0xe0, 0xeb, 0x39, 0xf8, 0xa7, 0x55, 0xf8, 0x73, 0x59, 0xe5, 0x67, 0xd3, 0x73, 0x2c, 0x1b, 0x9f, 0xdc, 0x7d, 0x5d, 0x27, 0xdf, 0x7d, 0x65, 0xc3, 0xdf, 0x92, 0xe1, 0x68, 0xbe, 0x02, 0xcf, 0xd0, 0xf9, 0x0a, 0x3f, 0xcf, 0x9e, 0xaf, 0x54, 0xdc,\n\t0x17, 0xd4, 0x32, 0x16, 0x8c, 0x59, 0x86, 0xc8, 0xf5, 0x83, 0x7b, 0x65, 0xda, 0xbf, 0x92, 0xa1, 0x9d, 0x94, 0xf9, 0xe0, 0xa7, 0x90, 0xe6, 0x66, 0xf8, 0x14, 0x2a, 0x65, 0x4a, 0x3f, 0xcc, 0xc1, 0x39, 0x0e, 0xee, 0x1e, 0x35, 0xa7, 0x6e, 0x95, 0x0e, 0x66, 0xf3, 0x40, 0x70, 0xc8, 0xf1, 0x79, 0x68, 0xbd, 0xaf, 0x2a, 0x70, 0x7e, 0x47, 0x0e, 0x3d, 0x8f, 0xa9, 0xf0, 0xdd, 0xa4, 0x2d, 0x10, 0x95, 0xb3, 0x9b, 0xdf, 0xcc, 0x7e, 0x0c, 0x2a, 0xc0, 0xfe, 0x47, 0x03, 0x46, 0x86, 0x63, 0x95, 0xe8, 0xd9, 0xd8, 0x68, 0x8f, 0xcd, 0x36, 0x23, 0xa3, 0x59, 0x17, 0xf3, 0x36, 0xc5, 0x25, 0x14, 0x0b, 0x50, 0x6f, 0x1a, 0xf9, 0x4c, 0x64, 0x5d, 0x2e, 0x26, 0x36, 0xc3, 0x61, 0x44, 0x46, 0x23, 0x0e, 0x8d, 0x8d, 0x0c, 0x32, 0xb8, 0xe4, 0x84, 0x2a, 0x84, 0xfd, 0x48, 0xa2, 0x11, 0x7a, 0x42, 0x95,\n\t0x89, 0x29, 0xab, 0x86, 0x94, 0xb5, 0xa4, 0x88, 0xb0, 0xd6, 0x37, 0x10, 0xe3, 0x3a, 0xd5, 0x4b, 0x81, 0xdf, 0x2c, 0x7b, 0x25, 0x0c, 0x96, 0x1a, 0x4c, 0xc1, 0x69, 0xb3, 0x17, 0xd5, 0x29, 0x2e, 0x36, 0xd7, 0x34, 0x9d, 0x52, 0xdd, 0x14, 0xa4, 0x87, 0x64, 0xa7, 0x84, 0x8c, 0xd9, 0x04, 0x73, 0xfd, 0xf0, 0xa5, 0x17, 0x5c, 0x3a, 0xb5, 0x9d, 0x79, 0xeb, 0xf3, 0x43, 0xd4, 0x4b, 0x41, 0x1d, 0x33, 0x87, 0x15, 0x7e, 0x31, 0xac, 0xcc, 0xc7, 0xcd, 0xb9, 0xb2, 0x03, 0x47, 0x64, 0x38, 0xce, 0x3d, 0xfd, 0x19, 0xb1, 0x89, 0xb8, 0x81, 0xc6, 0x45, 0xbf, 0x88, 0xea, 0x14, 0x36, 0x34, 0x56, 0x3f, 0x23, 0xfd, 0x74, 0x03, 0xdd, 0x27, 0x5d, 0x4c, 0xe7, 0x49, 0xab, 0x74, 0x27, 0xfb, 0x29, 0xe2, 0x7b, 0x0c, 0x5c, 0x21, 0xdb, 0xa2, 0x16, 0xa3, 0x39, 0x4e, 0x47, 0x1c, 0x73, 0x7c, 0xea, 0x0f,\n\t0x56, 0xb5, 0x45, 0x2d, 0x06, 0x38, 0x84, 0x33, 0xe0, 0x86, 0xf0, 0xe9, 0x21, 0xd9, 0xfc, 0x0c, 0x66, 0x32, 0x97, 0x0f, 0x41, 0x12, 0x29, 0x4b, 0xc6, 0x00, 0xa8, 0x17, 0x39, 0x86, 0xcd, 0xc6, 0x54, 0xb2, 0x97, 0x0f, 0x61, 0xbb, 0x02, 0x5d, 0x39, 0x39, 0x04, 0x24, 0x56, 0xbd, 0x91, 0x31, 0x0f, 0xfc, 0xc8, 0xa9, 0xa0, 0x8d, 0x06, 0xdc, 0x27, 0x13, 0x1f, 0x73, 0xc7, 0xb1, 0xfc, 0x93, 0x81, 0xf7, 0xa4, 0xc1, 0xaf, 0xb9, 0x8a, 0xf8, 0xf7, 0x8d, 0x36, 0x8d, 0xc6, 0x6e, 0xfa, 0x48, 0x28, 0x72, 0xdc, 0xbe, 0x3f, 0xff, 0xac, 0xcf, 0x69, 0x19, 0xbe, 0x39, 0x36, 0x23, 0x1a, 0xed, 0x29, 0x65, 0x86, 0x2c, 0x4e, 0xc2, 0x0f, 0x3f, 0x62, 0x82, 0x89, 0xf0, 0x6f, 0x27, 0x9d, 0x93, 0xe4, 0x7c, 0xba, 0xf9, 0xf0, 0x23, 0x39, 0xf0, 0x43, 0x2a, 0xfc, 0x68, 0x0e, 0x7c, 0xbb, 0x0a, 0x3f,\n\t0x91, 0x03, 0x7f, 0x4a, 0x85, 0x3f, 0xad, 0xc0, 0xa5, 0x7d, 0x82, 0x89, 0xfd, 0x4c, 0x81, 0xc3, 0xd7, 0xe1, 0xb5, 0x59, 0xf8, 0x6f, 0xa8, 0xf8, 0xdf, 0x85, 0x3b, 0xd5, 0x5c, 0xe2, 0x2f, 0xa1, 0xfe, 0x29, 0xc4, 0x39, 0x3b, 0x0a, 0xed, 0xa6, 0x4c, 0xce, 0x0e, 0x5f, 0x26, 0x67, 0x47, 0x59, 0x26, 0x67, 0x07, 0x8b, 0x83, 0x64, 0x67, 0x92, 0x76, 0xd8, 0x30, 0xe7, 0xea, 0xd1, 0xce, 0x93, 0x7d, 0xe9, 0x09, 0x97, 0x4f, 0xf3, 0x21, 0xaf, 0xd3, 0xbc, 0xaa, 0xf3, 0x3a, 0x8e, 0xc2, 0x15, 0xd2, 0x91, 0x27, 0x5c, 0x0e, 0xcd, 0x1f, 0x78, 0x83, 0xee, 0x59, 0x6b, 0xd1, 0x71, 0xe9, 0x88, 0xc7, 0x04, 0xb7, 0x9b, 0x0b, 0x0d, 0xd2, 0x23, 0x26, 0x0f, 0xa3, 0x87, 0xef, 0x98, 0x4c, 0xd2, 0x4d, 0x66, 0x7f, 0x01, 0x4c, 0x05, 0xa4, 0x42, 0x65, 0x5c, 0xbd, 0x44, 0xda, 0xb3, 0x2b, 0x27, 0x96,\n\t0x21, 0x85, 0x6f, 0x57, 0xe1, 0x27, 0xd6, 0xa8, 0xe3, 0x8a, 0xab, 0x42, 0x74, 0x57, 0x83, 0xeb, 0xe8, 0xc0, 0x31, 0x56, 0x95, 0x96, 0x78, 0x38, 0x91, 0x57, 0xac, 0xa8, 0xb2, 0x7e, 0x33, 0xea, 0xe8, 0x2a, 0xa2, 0x63, 0x45, 0x43, 0x14, 0xa6, 0x31, 0x4e, 0xc0, 0xb2, 0xf3, 0x4c, 0xe5, 0x23, 0x8e, 0xca, 0x33, 0x55, 0x0d, 0xaa, 0x11, 0x6b, 0x42, 0x68, 0x88, 0x69, 0xc7, 0x3b, 0x97, 0x1a, 0x9f, 0x61, 0x5a, 0xc8, 0x55, 0xe5, 0x0f, 0xb5, 0x55, 0x67, 0xe6, 0x20, 0x04, 0x79, 0x03, 0xef, 0x0c, 0x2c, 0x95, 0xae, 0x42, 0xbc, 0xb3, 0x48, 0x87, 0x39, 0x48, 0xc6, 0xda, 0x8d, 0xf2, 0xba, 0x78, 0x0b, 0xe1, 0x69, 0x3e, 0xfc, 0x48, 0x0e, 0xfc, 0x90, 0x0a, 0x3f, 0x9a, 0x03, 0xdf, 0xae, 0xc2, 0x4f, 0x60, 0x38, 0xea, 0x03, 0x02, 0x47, 0x7d, 0xe0, 0x04, 0x25, 0xe9, 0x62, 0xb3, 0xc0, 0x60,\n\t0x1f, 0x09, 0x16, 0x89, 0x2a, 0xf5, 0x49, 0xf3, 0x13, 0xff, 0x19, 0x27, 0x70, 0x94, 0x84, 0x38, 0xc1, 0x99, 0xd0, 0x92, 0x54, 0x2f, 0xb6, 0xec, 0x1c, 0x17, 0x88, 0x17, 0x29, 0x0e, 0x0e, 0xff, 0x48, 0x5b, 0xe4, 0xbf, 0xe5, 0x3b, 0xd2, 0xd2, 0x07, 0x3d, 0x85, 0xf8, 0x3a, 0xc2, 0xcc, 0x8b, 0x05, 0xda, 0x4f, 0xc4, 0x22, 0x1b, 0xfb, 0xf1, 0xa7, 0xaf, 0x3a, 0xdd, 0xf0, 0x00, 0xfb, 0x6d, 0xb7, 0x79, 0xf8, 0x1f, 0x5c, 0x95, 0x2e, 0x77, 0xa5, 0x8b, 0x59, 0x2e, 0xcb, 0x57, 0x1e, 0xad, 0xb0, 0x5a, 0xa5, 0x75, 0x1f, 0xa6, 0x49, 0x85, 0xbf, 0x0e, 0x1f, 0xc8, 0xc2, 0xdf, 0xab, 0xb6, 0xe1, 0x78, 0x4e, 0xdb, 0x4e, 0xab, 0xf8, 0xcf, 0x81, 0x5b, 0xb3, 0xe0, 0x5d, 0x2a, 0xfe, 0x63, 0x39, 0xf8, 0x4f, 0xa9, 0xf0, 0xa7, 0x73, 0xe0, 0x6f, 0xa8, 0xf0, 0xef, 0x7e, 0xa1, 0x72, 0xf2, 0x78,\n\t0x3a, 0x46, 0xdf, 0x7c, 0x5f, 0x86, 0x37, 0x21, 0x39, 0x98, 0x49, 0x74, 0x87, 0xdd, 0x90, 0xdc, 0x0b, 0xcc, 0xa0, 0xf2, 0xd1, 0x88, 0xe0, 0x33, 0x08, 0x1f, 0x76, 0xd3, 0xf3, 0xff, 0x9e, 0x6c, 0xf8, 0x53, 0x2a, 0xfc, 0xe9, 0x9e, 0xb1, 0xf1, 0x8f, 0x2a, 0x70, 0x34, 0x7f, 0xcf, 0x20, 0x7c, 0xdb, 0x4d, 0xe7, 0xef, 0x7a, 0x05, 0xfe, 0x61, 0x36, 0x9c, 0xff, 0x75, 0x3d, 0x95, 0xbf, 0x46, 0x34, 0xaf, 0x3f, 0x84, 0xfa, 0xbe, 0x44, 0xf1, 0xee, 0xd3, 0x39, 0x20, 0x2b, 0x68, 0x64, 0xe1, 0x53, 0x7e, 0x64, 0x24, 0x2f, 0x00, 0xe4, 0xbc, 0x6d, 0xc4, 0x4f, 0x80, 0xe4, 0x0e, 0xc9, 0x97, 0xbd, 0x98, 0x6a, 0x8f, 0x38, 0x06, 0x6a, 0x8e, 0xf4, 0xe9, 0x1c, 0x16, 0x07, 0x9a, 0xda, 0xc3, 0x78, 0x66, 0xe7, 0xc7, 0x70, 0x51, 0x56, 0x32, 0x8f, 0xe0, 0x8b, 0x54, 0x18, 0x64, 0x1f, 0x52, 0x04,\n\t0x4d, 0xf4, 0xea, 0x4d, 0x15, 0x48, 0xd0, 0x86, 0xab, 0x4d, 0x46, 0xc6, 0x3d, 0xfc, 0x36, 0xf3, 0x91, 0xd9, 0x30, 0xfc, 0x3b, 0x66, 0x7f, 0x34, 0x47, 0xac, 0x66, 0x9b, 0x62, 0x16, 0xe6, 0x5f, 0x6e, 0x9f, 0xed, 0x28, 0x35, 0x0d, 0xb7, 0xe3, 0xbd, 0x5a, 0x29, 0x7b, 0x23, 0xfc, 0x0d, 0x7f, 0x1f, 0xd0, 0x83, 0x1a, 0x7c, 0x6b, 0xa2, 0x47, 0x44, 0x7b, 0xc8, 0xed, 0xe5, 0x78, 0xf9, 0x34, 0xce, 0x27, 0xce, 0xe0, 0x64, 0x25, 0x5a, 0xc5, 0xf6, 0x84, 0x42, 0xce, 0x58, 0x24, 0x1c, 0x2d, 0x20, 0x91, 0x72, 0x65, 0x0b, 0x28, 0x44, 0x5f, 0x7d, 0x5e, 0x16, 0x8d, 0x68, 0x7e, 0x12, 0x0d, 0xb8, 0x28, 0x35, 0xa9, 0xd4, 0x12, 0xf2, 0x87, 0x52, 0x5e, 0xe9, 0xb5, 0xc5, 0x57, 0x57, 0x4c, 0x4f, 0xf9, 0x3a, 0xec, 0x76, 0x51, 0x6f, 0x8f, 0xc4, 0x92, 0x85, 0x93, 0xe7, 0xf8, 0xa7, 0x5e, 0xd2,\n\t0x1f, 0x8f, 0xfa, 0x63, 0x7e, 0x4f, 0x81, 0xc9, 0x2e, 0x72, 0xe7, 0x33, 0x46, 0x9b, 0xc7, 0xec, 0xf7, 0xb8, 0xbd, 0xb0, 0x61, 0x76, 0x51, 0x7d, 0x77, 0x52, 0x7a, 0xdc, 0x60, 0x0d, 0x58, 0xbc, 0x56, 0xed, 0xb4, 0xa9, 0x85, 0xcd, 0x95, 0x01, 0xc6, 0x53, 0x95, 0x34, 0x16, 0x18, 0xcd, 0x7a, 0x6a, 0xdf, 0x50, 0x3a, 0xe2, 0x86, 0xbf, 0x81, 0x29, 0xd2, 0xa6, 0xdb, 0xd2, 0xba, 0x4c, 0x9b, 0xa8, 0x29, 0x48, 0x48, 0x6d, 0x1a, 0x03, 0x04, 0x91, 0x11, 0x06, 0x00, 0x44, 0x4d, 0x82, 0xec, 0x52, 0xd4, 0x2d, 0xa4, 0x1f, 0x36, 0xa8, 0xce, 0x4e, 0x67, 0x45, 0x5d, 0x87, 0x3b, 0xf7, 0x8b, 0x14, 0xd8, 0x4f, 0xb2, 0x8e, 0x64, 0x98, 0xc5, 0xff, 0xa5, 0x98, 0xa5, 0x19, 0xcd, 0x2b, 0xbd, 0x35, 0xa8, 0xf2, 0xaa, 0x98, 0xf1, 0x12, 0x5e, 0x99, 0x64, 0x5e, 0xf5, 0xb1, 0x37, 0x32, 0xf5, 0xc2,\n\t0xb5, 0xc0, 0x00, 0xc2, 0x38, 0xe7, 0xa9, 0x11, 0x29, 0x2f, 0x06, 0x6c, 0x3b, 0xe3, 0x87, 0x2c, 0x60, 0xbb, 0x00, 0xcf, 0xb0, 0xfc, 0x5c, 0xe5, 0xd6, 0x7f, 0x80, 0x74, 0x3d, 0x69, 0x11, 0xea, 0x7a, 0x4b, 0xa4, 0x34, 0x12, 0x2e, 0xc1, 0xbe, 0x1f, 0xb6, 0x31, 0x03, 0x74, 0x53, 0xda, 0x49, 0xa4, 0x3e, 0x4b, 0xea, 0x45, 0x7b, 0x85, 0x37, 0xd5, 0x5e, 0x57, 0x11, 0xa8, 0x71, 0x17, 0xf5, 0xa4, 0xe2, 0x53, 0x52, 0x85, 0x81, 0x96, 0xd9, 0x35, 0x55, 0xed, 0x5e, 0x96, 0x2d, 0x30, 0x2d, 0xdc, 0xc5, 0x15, 0xb9, 0x2c, 0x33, 0x16, 0xcc, 0x9b, 0xe2, 0x2b, 0x5c, 0x5e, 0x1c, 0x0e, 0x4d, 0x5a, 0x91, 0x6e, 0x1e, 0x9c, 0x5e, 0x16, 0x29, 0x0a, 0x98, 0x0d, 0xcc, 0x1f, 0xa8, 0x4c, 0x56, 0xa1, 0x71, 0xfa, 0x0e, 0x7f, 0x2f, 0x28, 0x03, 0x6b, 0xd3, 0xba, 0x32, 0x08, 0x79, 0x17, 0xe4, 0x88,\n\t0xff, 0x73, 0x98, 0xb8, 0x86, 0x2b, 0x57, 0x7c, 0xf2, 0xdd, 0xde, 0x40, 0x37, 0xb1, 0x22, 0x57, 0x2e, 0xf8, 0x56, 0x9d, 0x29, 0x1a, 0xf6, 0x40, 0x36, 0x1a, 0x8e, 0x86, 0x1d, 0x0b, 0x85, 0x43, 0xa4, 0x5d, 0xea, 0x35, 0xa0, 0x90, 0x73, 0xf6, 0x9c, 0x13, 0x10, 0x00, 0x9e, 0x16, 0xf5, 0x7a, 0x9d, 0xcd, 0x1d, 0xf4, 0x74, 0xb4, 0xa6, 0x1b, 0xfd, 0x21, 0xb7, 0xd5, 0xa8, 0x31, 0x72, 0xa5, 0xce, 0x54, 0x7d, 0x83, 0xaf, 0x6a, 0x5e, 0x67, 0x24, 0x98, 0x5e, 0xd6, 0xde, 0x7a, 0x6e, 0x88, 0x8f, 0x6a, 0xb4, 0x7a, 0x93, 0x7e, 0x6e, 0xcf, 0xcc, 0x39, 0x68, 0x8b, 0x28, 0x88, 0x29, 0x6f, 0x89, 0x5d, 0x13, 0x9e, 0x3c, 0x98, 0x6e, 0x5a, 0x31, 0xad, 0x2c, 0x1a, 0xa1, 0x7d, 0x51, 0x83, 0xfa, 0xc2, 0x4d, 0xfa, 0x22, 0x84, 0x73, 0xe4, 0x96, 0x40, 0xc0, 0x19, 0x70, 0xec, 0x09, 0x2b, 0xce,\n\t0x29, 0xd9, 0x85, 0x56, 0x6d, 0x8e, 0x41, 0x9d, 0x21, 0x47, 0xbf, 0x3d, 0x3f, 0xa3, 0x3a, 0xae, 0x62, 0x7a, 0x8c, 0x46, 0x63, 0xc8, 0x18, 0x2a, 0x0d, 0x87, 0xc3, 0x25, 0xa2, 0x2e, 0x13, 0xef, 0xd6, 0x39, 0x6e, 0xb8, 0x5b, 0x78, 0x93, 0x3d, 0xe9, 0x4d, 0x75, 0xd4, 0xd7, 0x04, 0xaa, 0x1c, 0x37, 0xce, 0x2d, 0x14, 0xc5, 0x40, 0x5f, 0x23, 0xe9, 0x96, 0xe6, 0xd9, 0xa9, 0x78, 0x8b, 0x8b, 0xb7, 0x3b, 0x69, 0x87, 0x78, 0x99, 0xb9, 0xc3, 0x66, 0x4f, 0x75, 0xb8, 0x22, 0x3c, 0x69, 0xb0, 0x03, 0xf7, 0x8a, 0xd7, 0x01, 0x8d, 0x88, 0x56, 0xd4, 0x1f, 0x8c, 0x05, 0xf5, 0x87, 0x06, 0x24, 0xc0, 0x96, 0x13, 0x76, 0xd4, 0x19, 0x50, 0xee, 0x8c, 0xb0, 0x08, 0xa1, 0x06, 0x0a, 0x2c, 0x14, 0x06, 0x94, 0xf8, 0xda, 0x63, 0x75, 0x47, 0x0c, 0xb0, 0x02, 0x23, 0xb0, 0xcc, 0xd0, 0x98, 0xe8, 0xd9,\n\t0x3d, 0xe2, 0xd6, 0x6a, 0xd1, 0x8e, 0x2d, 0xa1, 0x8d, 0x63, 0x4f, 0x3c, 0x6b, 0x81, 0x51, 0x4f, 0xe2, 0x74, 0x6a, 0x33, 0x71, 0x3a, 0xf1, 0x2d, 0xcc, 0x58, 0xf1, 0xaa, 0x69, 0x38, 0x3f, 0xf8, 0x15, 0x83, 0x27, 0xe6, 0xab, 0x69, 0x42, 0xfb, 0x97, 0xc9, 0x4d, 0xfe, 0x78, 0xc0, 0x6b, 0xb0, 0x8a, 0xa5, 0xce, 0xfa, 0xa6, 0x66, 0x5f, 0xfd, 0xd2, 0x29, 0xa5, 0xa1, 0xce, 0xc5, 0x2d, 0x35, 0x73, 0xda, 0x4a, 0x0c, 0x36, 0xee, 0xdf, 0x1c, 0x31, 0xbf, 0xb5, 0x31, 0x35, 0x67, 0x5a, 0xa7, 0xd1, 0x62, 0x34, 0xd2, 0x1e, 0x9a, 0xb2, 0x76, 0x72, 0xed, 0x92, 0x29, 0x65, 0x81, 0xb6, 0x05, 0x4d, 0x01, 0x07, 0xee, 0xa3, 0xaa, 0x11, 0x0b, 0x63, 0x81, 0x71, 0xd2, 0xee, 0xc9, 0xe9, 0x09, 0xb4, 0xe1, 0x4a, 0x53, 0xd4, 0xb9, 0x92, 0x01, 0x1c, 0xc3, 0x2d, 0x15, 0x89, 0xeb, 0x88, 0x06, 0x92,\n\t0xdc, 0xcc, 0xe3, 0x36, 0x22, 0xf2, 0x25, 0x1a, 0xd1, 0xa8, 0x55, 0x1b, 0x61, 0xd1, 0x8c, 0xd5, 0x88, 0x85, 0x8e, 0xa8, 0xdf, 0xda, 0x90, 0x9a, 0x4b, 0xda, 0x60, 0x48, 0xf9, 0x4a, 0x6c, 0xa8, 0x0d, 0x6b, 0x26, 0xd7, 0x29, 0x6d, 0x70, 0x62, 0x59, 0x0a, 0xb3, 0xfb, 0xe0, 0x15, 0xc2, 0x95, 0xc0, 0x03, 0xaa, 0xd3, 0x15, 0x1e, 0x44, 0x2c, 0x0f, 0xbb, 0x8c, 0x68, 0x8c, 0x4d, 0xc7, 0x77, 0x34, 0x17, 0x66, 0x1a, 0xc1, 0xc0, 0x7e, 0xec, 0x85, 0x3f, 0xc0, 0xf4, 0xe0, 0x48, 0x67, 0xb6, 0x8c, 0x4c, 0x08, 0x7e, 0x48, 0x4d, 0x48, 0xb2, 0x62, 0x9e, 0xb9, 0xe0, 0xa5, 0xd0, 0xe5, 0x8a, 0x55, 0x5c, 0x73, 0xe5, 0xae, 0x32, 0xb3, 0xbd, 0xe7, 0xbc, 0x25, 0xa1, 0xa0, 0x90, 0x34, 0xeb, 0x4a, 0xeb, 0x0b, 0x07, 0xa5, 0xc5, 0xf0, 0x1e, 0x91, 0x2b, 0x30, 0x37, 0x07, 0xcf, 0x5d, 0xa3, 0x05,\n\t0x2c, 0x88, 0x30, 0x2f, 0x33, 0x2e, 0xfe, 0x1b, 0x68, 0x7e, 0xf6, 0x80, 0x99, 0xb0, 0x28, 0x6d, 0x2e, 0x42, 0x4b, 0xeb, 0x24, 0xc8, 0x81, 0x76, 0x0b, 0xc3, 0xf0, 0xac, 0x3c, 0x4d, 0xc7, 0xb0, 0x4f, 0x2d, 0xde, 0x0c, 0x0d, 0xa0, 0x57, 0x04, 0x56, 0x58, 0x8a, 0x46, 0xba, 0xb8, 0x50, 0x87, 0xba, 0x51, 0x1c, 0xc0, 0x4b, 0x26, 0xb5, 0xdd, 0x65, 0x94, 0xa9, 0xfa, 0x0c, 0xe8, 0xe7, 0xe7, 0xa1, 0x1b, 0xbe, 0x5c, 0xe9, 0xb6, 0x2f, 0x53, 0x7a, 0x3a, 0x91, 0x8f, 0xa9, 0x83, 0x1a, 0x0d, 0x49, 0x72, 0x4a, 0xae, 0x86, 0x73, 0xb0, 0x89, 0x8b, 0xa9, 0xdf, 0xeb, 0x85, 0xc0, 0x3b, 0xd3, 0x3b, 0x73, 0x46, 0x77, 0x43, 0x5d, 0x45, 0x79, 0x24, 0x8c, 0x83, 0xa2, 0x8a, 0x3c, 0xd0, 0x43, 0x3d, 0x4d, 0xd9, 0x9d, 0x31, 0x0e, 0xc7, 0x01, 0x2b, 0x49, 0xfa, 0x1e, 0x2c, 0xd7, 0x36, 0x87, 0xdd,\n\t0x0c, 0x9d, 0xca, 0x3c, 0x8b, 0xe3, 0x9a, 0x70, 0x19, 0xa3, 0xf2, 0x7a, 0x92, 0xcb, 0xa7, 0xbe, 0x41, 0x0d, 0x4f, 0x0f, 0x75, 0x89, 0xb2, 0xb2, 0x04, 0xfa, 0xff, 0x5b, 0xd1, 0xe6, 0xe9, 0x25, 0x16, 0x47, 0xcd, 0xc4, 0x8e, 0xb6, 0x9d, 0xfe, 0xb8, 0xa6, 0xb8, 0xb1, 0xbb, 0xdc, 0xe4, 0x35, 0x3a, 0xaa, 0xbb, 0xe7, 0x75, 0x57, 0x97, 0x74, 0x2e, 0x6d, 0x6b, 0x5d, 0xd0, 0x5c, 0x58, 0x16, 0xb1, 0x39, 0x83, 0xa1, 0xd2, 0x8a, 0x40, 0xe3, 0x8c, 0xe4, 0xc4, 0x1a, 0xee, 0x9b, 0x65, 0x25, 0xa1, 0x32, 0xb4, 0x19, 0x88, 0x4b, 0x3f, 0xb7, 0x5b, 0xd0, 0xa6, 0x5f, 0xef, 0x2d, 0xf0, 0x46, 0xcb, 0x98, 0x68, 0x9d, 0x4b, 0xd4, 0xba, 0x7d, 0xb1, 0xf6, 0x72, 0x37, 0xcb, 0x18, 0xcd, 0x36, 0x03, 0xcb, 0xbb, 0x6b, 0x6b, 0x42, 0x13, 0x6a, 0x03, 0xae, 0x68, 0xb5, 0x2f, 0x54, 0x65, 0xd2, 0x47,\n\t0x0a, 0x5d, 0xb5, 0x16, 0xe7, 0xd4, 0xca, 0x58, 0x47, 0xb9, 0x0b, 0x7b, 0xb4, 0xfd, 0xff, 0x7d, 0xff, 0x7f, 0xb8, 0xef, 0x21, 0xe8, 0x67, 0xf7, 0x31, 0x51, 0xb4, 0xbe, 0x39, 0x40, 0x29, 0xde, 0x8c, 0x2a, 0x31, 0x4c, 0x00, 0xc7, 0x42, 0xa4, 0x30, 0x2d, 0x56, 0xd4, 0x60, 0x34, 0xdf, 0x90, 0x28, 0x24, 0x3c, 0x5a, 0xc8, 0x6c, 0x63, 0x44, 0x21, 0x49, 0xfd, 0xc6, 0x3f, 0xa5, 0x2a, 0xd1, 0x99, 0x74, 0xed, 0x2a, 0x2d, 0xf5, 0xd7, 0xb9, 0x76, 0xed, 0xe2, 0xd7, 0x7a, 0x83, 0x45, 0xb5, 0xd3, 0x13, 0xd2, 0x09, 0xd8, 0x1d, 0xaf, 0xf4, 0x38, 0xa5, 0x1b, 0xb1, 0xd6, 0xc0, 0x80, 0x4b, 0xd1, 0x3c, 0x17, 0x11, 0x76, 0xa0, 0xbe, 0xb0, 0x81, 0x59, 0x27, 0x38, 0x7c, 0xb5, 0x8f, 0xc6, 0x57, 0x1c, 0x87, 0x7b, 0x42, 0x30, 0xac, 0x04, 0x0c, 0x90, 0x0c, 0x7f, 0x64, 0x92, 0x03, 0xc4, 0xeb,\n\t0x52, 0x06, 0x73, 0xf8, 0x78, 0x00, 0xce, 0xc5, 0x0f, 0x70, 0xfc, 0x38, 0x08, 0x66, 0xf4, 0xa7, 0x4d, 0x00, 0x58, 0x0b, 0x94, 0x28, 0x24, 0x72, 0xd4, 0x84, 0x86, 0x0c, 0xd3, 0xd1, 0xaa, 0x0a, 0xad, 0xbb, 0xee, 0x32, 0xb9, 0x03, 0x56, 0x4b, 0xb1, 0xcb, 0x58, 0x1d, 0x0a, 0xd7, 0xf2, 0xd7, 0x4a, 0x66, 0xf8, 0x87, 0xc3, 0xd6, 0x62, 0x97, 0xc9, 0xe4, 0x2a, 0xb6, 0x86, 0x6b, 0xe4, 0xfb, 0xf2, 0xcf, 0x98, 0x97, 0xc1, 0x30, 0xa2, 0x0b, 0xc7, 0x45, 0x58, 0xf4, 0xa8, 0x4e, 0xcb, 0x50, 0x07, 0x7c, 0x4c, 0x98, 0x13, 0x70, 0x68, 0x12, 0xe6, 0xd8, 0x01, 0xea, 0x98, 0xbe, 0x0c, 0x9b, 0x63, 0x0e, 0xe0, 0xa1, 0x15, 0xe4, 0x31, 0xf9, 0x48, 0x73, 0x19, 0xca, 0xc1, 0x98, 0x0f, 0xa8, 0x2d, 0x03, 0x04, 0x7d, 0x39, 0xc1, 0x11, 0xa2, 0x0e, 0x41, 0xe7, 0x4c, 0xd8, 0xf2, 0xe3, 0x09, 0x34,\n\t0xe4, 0xf9, 0xaa, 0xff, 0xa7, 0xb5, 0x74, 0x62, 0x95, 0xb5, 0xd8, 0xc2, 0x33, 0x06, 0x5b, 0xc4, 0x8b, 0x88, 0x2f, 0xc6, 0xc4, 0x63, 0x6a, 0x2d, 0xd6, 0x62, 0xb7, 0x09, 0x35, 0x40, 0x0c, 0x75, 0x54, 0x16, 0xf2, 0x7c, 0xb7, 0x5e, 0xe3, 0x2f, 0x85, 0x9f, 0xa8, 0x6d, 0x41, 0x4f, 0x8d, 0x46, 0x77, 0xb1, 0x6c, 0xb7, 0x87, 0xfa, 0xb5, 0x1d, 0xf5, 0xab, 0x1f, 0xd4, 0xa4, 0x2b, 0x4d, 0x48, 0x71, 0xc4, 0xee, 0xe8, 0x88, 0x5e, 0xa2, 0xac, 0xb0, 0x0c, 0x60, 0x07, 0x38, 0x45, 0x55, 0x19, 0x20, 0x0e, 0xb7, 0x7e, 0xe0, 0xb7, 0x44, 0x5d, 0x51, 0x0b, 0x56, 0x55, 0x6c, 0xd8, 0x4b, 0x5a, 0x76, 0xc9, 0x33, 0x41, 0x11, 0x29, 0x58, 0x44, 0x11, 0xc6, 0x3e, 0xd4, 0x68, 0x89, 0x79, 0xd1, 0x65, 0x2a, 0x10, 0x2e, 0x12, 0xdc, 0x96, 0xad, 0x5f, 0xd1, 0x38, 0x8c, 0x2e, 0xf3, 0xd7, 0xaf, 0x2c,\n\t0xf0, 0xf0, 0x9b, 0x05, 0x8b, 0xd9, 0xbf, 0x4b, 0xb8, 0x56, 0x9a, 0x27, 0xea, 0x0f, 0x1a, 0xf5, 0x4f, 0x98, 0xec, 0x1a, 0xbd, 0xff, 0x33, 0x9d, 0xf9, 0x7b, 0x26, 0xe1, 0x3f, 0x15, 0x7d, 0x71, 0x3e, 0xbb, 0x0f, 0xbc, 0x8a, 0x68, 0x62, 0x41, 0x71, 0xba, 0x90, 0xa1, 0xdd, 0xc9, 0x64, 0xba, 0x33, 0x2b, 0xfa, 0x05, 0x52, 0x8f, 0x2c, 0xaf, 0xa2, 0xd2, 0x86, 0xcd, 0xca, 0xbb, 0xa8, 0x3d, 0x6c, 0x2d, 0xd2, 0x6d, 0x42, 0xa0, 0x36, 0x5d, 0x2d, 0xa0, 0xf6, 0xf8, 0x49, 0x3e, 0x0d, 0x9e, 0x28, 0xbf, 0x22, 0xf6, 0xd5, 0x1d, 0xe8, 0x16, 0x90, 0xf6, 0xc9, 0x28, 0xbf, 0x98, 0x1e, 0xec, 0x35, 0x56, 0x62, 0x0b, 0x97, 0x10, 0xeb, 0x85, 0x4c, 0x22, 0x22, 0x27, 0x19, 0xb8, 0x58, 0x80, 0x73, 0x5d, 0x40, 0x5d, 0xff, 0xea, 0x9f, 0x58, 0x55, 0xd5, 0x51, 0xe0, 0x5d, 0x58, 0xb3, 0x60, 0xf1,\n\t0xae, 0xde, 0x50, 0xd5, 0xae, 0x48, 0x29, 0x62, 0xc5, 0xae, 0xb9, 0x5e, 0x81, 0x5f, 0x18, 0x28, 0x4b, 0xc5, 0x6b, 0x12, 0xab, 0x97, 0xe2, 0xe1, 0xdc, 0x9f, 0x2c, 0xc7, 0x1f, 0x89, 0x0a, 0xa7, 0x5d, 0xba, 0x8e, 0xd1, 0x7a, 0x89, 0x9e, 0x88, 0x75, 0xaf, 0x26, 0x44, 0x9f, 0x0d, 0xf8, 0x72, 0x7c, 0xa8, 0x06, 0xba, 0x55, 0x13, 0xde, 0x55, 0xd4, 0x87, 0xca, 0xe3, 0xb2, 0xfb, 0x1c, 0x3e, 0xd9, 0xf3, 0x48, 0x37, 0x96, 0xe7, 0x51, 0x1d, 0xa2, 0x0e, 0x61, 0xd6, 0x35, 0x2f, 0x9b, 0x1c, 0x89, 0x4c, 0x5e, 0xd6, 0xdc, 0xb2, 0x6c, 0x52, 0x34, 0x3a, 0x69, 0x59, 0xcb, 0xe6, 0xcd, 0x97, 0xf0, 0xf7, 0x46, 0xa6, 0x0c, 0xb4, 0xb7, 0x0f, 0x4c, 0x89, 0x46, 0xe9, 0x67, 0x44, 0x3a, 0xe7, 0x6b, 0xe8, 0x0f, 0x50, 0xf4, 0xa0, 0x26, 0xa4, 0x07, 0x61, 0x1a, 0x90, 0x16, 0x81, 0xab, 0x27, 0x3d,\n\t0x8d, 0x2a, 0x47, 0x34, 0xcc, 0x57, 0xbc, 0xa0, 0x18, 0xd8, 0xfb, 0x27, 0xd3, 0x01, 0xe3, 0x67, 0xa0, 0xa3, 0x8f, 0x79, 0x9b, 0xa9, 0x47, 0xfb, 0x57, 0x9c, 0x77, 0x62, 0x50, 0xb6, 0xfb, 0x2f, 0x96, 0xed, 0xfe, 0xab, 0x90, 0x40, 0x05, 0x55, 0x96, 0x9c, 0xdf, 0x0d, 0x94, 0xcd, 0x0b, 0xd5, 0x2f, 0x09, 0x90, 0xda, 0x36, 0xcb, 0x1b, 0x9c, 0x3c, 0x14, 0xaa, 0x8c, 0x92, 0x4d, 0x41, 0xd0, 0x56, 0x1a, 0x89, 0xe6, 0x6c, 0x76, 0x14, 0xab, 0xe6, 0x9c, 0xdd, 0x8e, 0x83, 0x74, 0xee, 0x8b, 0xf6, 0x4a, 0xb4, 0xd9, 0x31, 0x79, 0x42, 0xce, 0x68, 0xb5, 0xcb, 0x10, 0x98, 0xd5, 0x14, 0x9f, 0x4c, 0xf7, 0x3b, 0x89, 0x66, 0xf7, 0xae, 0xb9, 0x7e, 0x81, 0xee, 0x76, 0x12, 0xad, 0x91, 0x02, 0xbf, 0x6f, 0x4e, 0x04, 0x69, 0xd6, 0x03, 0x64, 0xbf, 0xe3, 0x71, 0xfe, 0x84, 0x39, 0xe6, 0xa6, 0xe3,\n\t0x0f, 0xde, 0x8c, 0xda, 0xe4, 0x00, 0x2b, 0x68, 0x23, 0x74, 0x3c, 0x1a, 0xb8, 0x26, 0xc5, 0xc2, 0x18, 0xfd, 0xe0, 0xe8, 0x8f, 0x7e, 0xfa, 0xd8, 0x4d, 0xcf, 0x1a, 0x70, 0x1f, 0xc8, 0x2d, 0x20, 0x5f, 0xf1, 0x75, 0xa9, 0x53, 0x3d, 0x86, 0x20, 0x4f, 0xc8, 0xce, 0x61, 0x80, 0xed, 0xe9, 0x7f, 0x2c, 0x68, 0x0b, 0x86, 0x32, 0x33, 0xac, 0x62, 0x3e, 0x2a, 0x0f, 0x4f, 0xa7, 0xeb, 0x27, 0x9e, 0x09, 0xc9, 0x12, 0xb7, 0x96, 0xb3, 0x6a, 0x8a, 0x4c, 0xd1, 0x64, 0xc1, 0xae, 0x59, 0x0e, 0x33, 0xcf, 0x77, 0x56, 0xd6, 0x17, 0x9c, 0x67, 0xe3, 0xcb, 0x22, 0xd2, 0x29, 0x46, 0x6b, 0xb6, 0x13, 0x59, 0xa9, 0x46, 0xfb, 0xb2, 0xef, 0xa1, 0xb1, 0x98, 0x02, 0x8d, 0xe9, 0xba, 0x14, 0xda, 0x52, 0x79, 0x72, 0x6d, 0x2e, 0xf3, 0x36, 0x64, 0x72, 0xe6, 0x19, 0xb4, 0x63, 0x49, 0x86, 0xed, 0x49, 0xa4,\n\t0x22, 0x62, 0x95, 0x52, 0x50, 0x77, 0x59, 0xca, 0x32, 0x96, 0x63, 0x4d, 0x55, 0xc1, 0xa9, 0x9b, 0xad, 0xdb, 0x75, 0x16, 0x9d, 0xc3, 0x57, 0xe2, 0x0c, 0x46, 0x23, 0x0d, 0xe9, 0x86, 0x88, 0xaf, 0xbe, 0xb7, 0xb6, 0x7e, 0xa0, 0x38, 0x68, 0x70, 0x19, 0x1c, 0xbe, 0xb0, 0xaf, 0x2c, 0x14, 0x69, 0x4c, 0x37, 0x46, 0x3c, 0xa9, 0xae, 0x9a, 0x86, 0x85, 0x7e, 0xbe, 0xb2, 0x40, 0xa7, 0xd7, 0x79, 0x5d, 0x0e, 0x97, 0xcd, 0x1e, 0xac, 0x8d, 0x47, 0x3b, 0x2b, 0xbd, 0xe1, 0xc2, 0x7a, 0xbb, 0xd1, 0x6c, 0x08, 0xda, 0x9d, 0x6e, 0x9b, 0x2d, 0xd4, 0x5c, 0x19, 0x6c, 0x4e, 0x7a, 0x23, 0x7e, 0xd2, 0x8e, 0x20, 0x6a, 0xc7, 0x2e, 0xa1, 0x01, 0x14, 0x83, 0xd6, 0x74, 0x93, 0x16, 0x42, 0xd6, 0x0f, 0xd1, 0xe6, 0xb7, 0x0b, 0x20, 0xc1, 0xdf, 0x84, 0x97, 0x01, 0x72, 0x54, 0x83, 0xc4, 0x1e, 0xca, 0x7b,\n\t0x94, 0x55, 0xa0, 0x07, 0x02, 0x97, 0xc3, 0x6a, 0x29, 0x30, 0x9b, 0x0c, 0x3c, 0x07, 0x8a, 0x61, 0xb1, 0x48, 0xe2, 0x31, 0x29, 0x97, 0x8e, 0x1d, 0xb0, 0xbe, 0x85, 0x06, 0x12, 0x50, 0x6e, 0x37, 0xf0, 0xa5, 0xa4, 0x34, 0xa5, 0xbb, 0x46, 0x6f, 0x3e, 0xa7, 0x90, 0xf7, 0x4e, 0xbd, 0xfe, 0x7a, 0xa7, 0xcd, 0x6e, 0xd5, 0x09, 0x22, 0x5f, 0x56, 0x38, 0x9d, 0xbd, 0xb1, 0x6f, 0x32, 0x74, 0x9a, 0x4d, 0x8d, 0x05, 0x3b, 0x5c, 0x77, 0x0d, 0x4a, 0x1f, 0x38, 0x3c, 0x68, 0x93, 0x38, 0xc9, 0xe5, 0x22, 0xb4, 0x75, 0x21, 0x79, 0x77, 0xf2, 0x87, 0x80, 0x0b, 0xa4, 0xd2, 0x55, 0x4e, 0x9c, 0x52, 0x12, 0xb1, 0x96, 0xe9, 0x82, 0xc4, 0x8e, 0x8a, 0xc7, 0x13, 0xd1, 0x00, 0x39, 0xcf, 0x26, 0x06, 0xf9, 0xab, 0xc8, 0xd1, 0xa4, 0x0b, 0xb8, 0x42, 0x8e, 0x30, 0x62, 0xaf, 0x1b, 0xaf, 0x53, 0x99, 0xed,\n\t0x5f, 0xe6, 0xde, 0x85, 0x71, 0xce, 0xf5, 0x68, 0xc5, 0x40, 0x57, 0x5d, 0x7c, 0x42, 0xb9, 0x6b, 0x67, 0x59, 0xa9, 0xbf, 0xd6, 0xc5, 0x1f, 0x1a, 0xfe, 0xa3, 0x27, 0x1a, 0x88, 0xe1, 0xb5, 0x14, 0x76, 0x4b, 0x27, 0xe2, 0x95, 0x5e, 0x27, 0xbc, 0x88, 0xce, 0x89, 0x22, 0x9a, 0xe3, 0xfd, 0x88, 0x06, 0x2b, 0x8e, 0x05, 0xa1, 0x27, 0x21, 0x63, 0x30, 0xf8, 0x42, 0x72, 0x26, 0x3a, 0x40, 0x62, 0x02, 0x5b, 0x81, 0xc5, 0x62, 0xe1, 0xd0, 0xb2, 0x03, 0xd9, 0x10, 0x4b, 0xda, 0x4b, 0x8e, 0x42, 0xf1, 0xdc, 0x9e, 0x62, 0xfc, 0x3f, 0xbe, 0xf2, 0x47, 0x9b, 0xcc, 0x4e, 0x66, 0xb1, 0xa0, 0xe7, 0x05, 0x83, 0xb8, 0x84, 0xb5, 0x9b, 0x70, 0x75, 0x8c, 0xd6, 0x64, 0x18, 0xf6, 0xd7, 0x7a, 0xbd, 0x75, 0xfe, 0xcf, 0x0d, 0x26, 0x6c, 0x6f, 0x8f, 0xe6, 0xde, 0x16, 0xfe, 0x2e, 0x50, 0x8e, 0xa3, 0x81,\n\t0x45, 0xdc, 0x1a, 0xbc, 0x20, 0xe3, 0x96, 0x32, 0xe0, 0x42, 0x9e, 0x63, 0x59, 0xb2, 0x1a, 0x92, 0x64, 0xd2, 0x89, 0x56, 0x4b, 0x9c, 0xb6, 0x0f, 0x27, 0x04, 0x60, 0x2b, 0x60, 0x0c, 0x1f, 0x46, 0x0b, 0xe8, 0x67, 0x76, 0xd5, 0xa8, 0x0f, 0x6a, 0xb2, 0xe9, 0x60, 0x5b, 0xee, 0x5f, 0x67, 0x13, 0xe7, 0xf3, 0x68, 0xb7, 0x26, 0xf2, 0xfd, 0x82, 0xeb, 0xbc, 0x7b, 0x37, 0x9a, 0x5d, 0xcc, 0x24, 0x4e, 0xc3, 0xf3, 0x7a, 0x71, 0xa6, 0xd6, 0xdf, 0x10, 0xd0, 0xcc, 0x10, 0x74, 0x1c, 0xaf, 0xe1, 0xa7, 0xb2, 0x0e, 0x42, 0xa1, 0x07, 0x3a, 0x0a, 0x8a, 0x0b, 0x2c, 0xc5, 0x16, 0xe9, 0x1d, 0x0f, 0x1a, 0xf5, 0x96, 0x0f, 0xbc, 0x15, 0x2e, 0x57, 0x85, 0xf7, 0x8f, 0x45, 0xc5, 0x1f, 0x79, 0x92, 0x2e, 0x67, 0xd2, 0xf3, 0x51, 0x81, 0x19, 0xd1, 0x5d, 0x8c, 0xf8, 0xd3, 0xa8, 0xe6, 0x07, 0x57, 0xee,\n\t0x1a, 0x48, 0x17, 0x91, 0xd4, 0x35, 0x48, 0xbf, 0x28, 0xb5, 0xc6, 0x0b, 0x38, 0x4c, 0x30, 0x3d, 0xe9, 0x81, 0x66, 0x7a, 0x6a, 0x1c, 0x23, 0xf4, 0xd6, 0x13, 0x5a, 0x45, 0xa6, 0x71, 0x87, 0xd9, 0xc6, 0xaf, 0x66, 0x05, 0x6e, 0x01, 0x6f, 0x33, 0x5d, 0x7e, 0xec, 0x81, 0x1d, 0x66, 0x93, 0xb0, 0x9a, 0xd7, 0xf5, 0x6a, 0x9d, 0xdb, 0x1e, 0x60, 0xf7, 0x99, 0xf5, 0x47, 0x75, 0x56, 0xcd, 0x2e, 0x5d, 0x01, 0x34, 0x7d, 0xa6, 0xd1, 0xfe, 0xa3, 0xd5, 0x79, 0xa5, 0xfd, 0x43, 0xda, 0x3f, 0xce, 0x91, 0x00, 0x53, 0x01, 0xcb, 0x50, 0xfd, 0xd1, 0x74, 0xc8, 0x97, 0x75, 0xd7, 0x81, 0x08, 0x98, 0x8f, 0x09, 0x00, 0x0b, 0x09, 0x17, 0x7b, 0x15, 0x2a, 0xf8, 0x33, 0x51, 0x51, 0xb1, 0xc3, 0x44, 0xa8, 0xe0, 0x17, 0xf0, 0x56, 0x99, 0x0a, 0x7e, 0x0d, 0xaf, 0x9b, 0xa9, 0x73, 0x6e, 0x7d, 0xe0, 0x15,\n\t0x44, 0x84, 0xde, 0xa2, 0xd9, 0xa5, 0x37, 0x43, 0xe3, 0xe7, 0x1a, 0xdd, 0xfd, 0x0a, 0x11, 0x88, 0x06, 0x34, 0x17, 0x57, 0x93, 0xdc, 0x04, 0x41, 0x7c, 0x1b, 0x41, 0xc7, 0x08, 0x80, 0x0b, 0xe9, 0x18, 0x21, 0xe3, 0xd2, 0x01, 0xec, 0xd6, 0x10, 0x1e, 0x23, 0xf4, 0xc8, 0xbc, 0x41, 0xed, 0xac, 0x7a, 0x3a, 0x4c, 0xaa, 0xa5, 0xdf, 0x69, 0x6d, 0xf6, 0x35, 0x03, 0x3f, 0xbb, 0xac, 0xc0, 0xca, 0x0d, 0xf2, 0x5a, 0x56, 0xab, 0x5f, 0xc1, 0x39, 0x8c, 0xa8, 0x23, 0x2e, 0x76, 0x14, 0xfc, 0x3f, 0xf8, 0xb2, 0x59, 0xff, 0xbe, 0xb9, 0xc8, 0x1c, 0x28, 0x7e, 0x57, 0x6f, 0xa6, 0xed, 0x4e, 0xa0, 0xb9, 0xf2, 0x5f, 0x50, 0x9d, 0x66, 0x50, 0x96, 0x8e, 0x62, 0xeb, 0x4d, 0x0d, 0x6e, 0xa6, 0x9a, 0xc3, 0x99, 0x2c, 0x89, 0x24, 0x04, 0xf0, 0x2a, 0x92, 0xc3, 0xd9, 0x4e, 0x3a, 0xc0, 0x2e, 0x88, 0x6c,\n\t0x8a, 0x26, 0x71, 0xb6, 0x85, 0xea, 0x82, 0xf0, 0x5f, 0x74, 0xfa, 0x37, 0x3f, 0x92, 0xce, 0xd3, 0x19, 0xde, 0x7a, 0x17, 0xee, 0xe1, 0x57, 0x98, 0x8b, 0x0c, 0xd2, 0xf3, 0xeb, 0x5a, 0xb4, 0x7e, 0x33, 0xac, 0x38, 0x1f, 0xab, 0x59, 0x48, 0xe6, 0x7b, 0xc9, 0xd8, 0xf7, 0xa5, 0xdd, 0xf8, 0xe4, 0x97, 0xe4, 0x88, 0xa6, 0x32, 0x37, 0x08, 0x7a, 0x2c, 0xe5, 0x01, 0x56, 0xe7, 0x92, 0xd3, 0xbe, 0xd3, 0x71, 0x48, 0x1a, 0x07, 0x53, 0x7c, 0xef, 0xa3, 0x85, 0x21, 0xad, 0x74, 0x85, 0xc9, 0xa7, 0xd7, 0xb9, 0x4d, 0xd2, 0x95, 0x62, 0xc4, 0xf7, 0x55, 0x66, 0xda, 0xf7, 0x0b, 0x9d, 0xec, 0x4f, 0xc3, 0xf3, 0x2a, 0x2b, 0xe7, 0x85, 0x3f, 0xaf, 0xb2, 0x15, 0xa3, 0x82, 0x51, 0x1d, 0x9d, 0x72, 0x1e, 0xea, 0x08, 0xa8, 0x4f, 0xa7, 0xf0, 0xd4, 0x59, 0x84, 0x4a, 0xb7, 0x91, 0x83, 0x1f, 0xb2, 0xb6,\n\t0xaa, 0x8d, 0x21, 0x96, 0x93, 0x83, 0x0c, 0x9a, 0x7d, 0xc2, 0x21, 0x8f, 0xdb, 0xe5, 0x00, 0x11, 0x18, 0xe1, 0x89, 0xad, 0x4a, 0x34, 0x86, 0x63, 0xcc, 0x14, 0xb1, 0x0e, 0x27, 0xc9, 0x3d, 0x2f, 0x22, 0x7e, 0xca, 0x99, 0xaa, 0xb5, 0x10, 0xef, 0xd3, 0x83, 0x0e, 0xf8, 0x83, 0xea, 0x99, 0xb1, 0xc4, 0x24, 0x3f, 0x34, 0x5b, 0x1c, 0x06, 0x0e, 0xe9, 0x57, 0xd2, 0x0f, 0x8b, 0xe2, 0x8e, 0xe8, 0x44, 0x3f, 0xf3, 0xaf, 0x9f, 0xfd, 0xab, 0xd3, 0x02, 0x7f, 0x2a, 0x95, 0xe8, 0x4d, 0x5c, 0x03, 0xf7, 0xa1, 0xa8, 0x71, 0xd5, 0x96, 0x48, 0xdf, 0xb2, 0xfb, 0xdd, 0x76, 0xad, 0xab, 0xa6, 0x54, 0xba, 0x2e, 0x54, 0x6a, 0xe4, 0xf9, 0xfb, 0xfb, 0xdc, 0x95, 0x56, 0x26, 0xc4, 0x34, 0x18, 0x02, 0x96, 0x45, 0xf7, 0x53, 0xfe, 0x2f, 0x03, 0x00, 0xcd, 0x60, 0x98, 0xee, 0x44, 0xba, 0x54, 0xc0, 0xa7,\n\t0x21, 0x00, 0x6d, 0xe6, 0x06, 0x68, 0xb4, 0x12, 0x0f, 0x26, 0xd8, 0x4b, 0x26, 0x87, 0x08, 0x08, 0x5b, 0x2c, 0x2e, 0x1c, 0x77, 0x5f, 0x2b, 0xf8, 0x68, 0x14, 0x25, 0xbc, 0xd6, 0x54, 0xb0, 0x75, 0x16, 0xa2, 0x26, 0xd9, 0x8b, 0x18, 0x9c, 0xac, 0xaa, 0x1d, 0xfd, 0x46, 0xba, 0xb4, 0x20, 0xf6, 0x1e, 0x7a, 0xf3, 0xe0, 0xbf, 0x1d, 0x7c, 0xe3, 0xce, 0xde, 0x3d, 0x25, 0x91, 0xe4, 0xf2, 0xdb, 0xd7, 0xfd, 0xdb, 0xba, 0x3b, 0x56, 0x24, 0x23, 0x25, 0x68, 0x20, 0x8c, 0x5c, 0xf5, 0x93, 0x03, 0x73, 0x05, 0xe9, 0x1e, 0xb8, 0x58, 0x98, 0xb7, 0xff, 0xd9, 0x6d, 0x0c, 0x8c, 0x17, 0x4b, 0xd3, 0x16, 0xdf, 0xb2, 0xaa, 0x89, 0x67, 0xf7, 0x7d, 0x7e, 0x01, 0xdf, 0xb4, 0xea, 0x96, 0xc5, 0xf0, 0xdb, 0xc5, 0xf1, 0x91, 0x91, 0x91, 0x27, 0x50, 0xbf, 0xbd, 0x43, 0xf2, 0x9c, 0xff, 0x74, 0x98, 0xe4,\n\t0x87, 0x97, 0xd6, 0xe4, 0xe6, 0x87, 0x47, 0xf4, 0x9f, 0x8f, 0x70, 0x3e, 0xe6, 0x0f, 0x83, 0x16, 0x1c, 0x2b, 0xc6, 0x2b, 0x20, 0x1d, 0xbb, 0x31, 0xcc, 0xe0, 0xd9, 0x55, 0x49, 0xa1, 0x7a, 0x7e, 0xb7, 0xc0, 0x33, 0x78, 0x4d, 0x65, 0xa0, 0x12, 0x37, 0xad, 0x05, 0x34, 0x27, 0x42, 0xf1, 0x78, 0x08, 0xab, 0xaf, 0x11, 0x92, 0x31, 0xa2, 0x0e, 0xd1, 0x5d, 0x9b, 0x49, 0x9e, 0xe6, 0x72, 0x04, 0xf1, 0x12, 0x10, 0x44, 0x4b, 0x56, 0x9e, 0x93, 0x30, 0xea, 0x13, 0xfe, 0xe3, 0xd2, 0xc0, 0xf0, 0x07, 0x33, 0x6f, 0x18, 0x68, 0x9a, 0x79, 0xdd, 0xb1, 0xe5, 0xcb, 0x8f, 0xed, 0x98, 0xd9, 0x34, 0x70, 0xc3, 0xcc, 0xe1, 0x0f, 0x02, 0xa5, 0xb0, 0x20, 0x76, 0x4e, 0xe9, 0xc2, 0x3b, 0x36, 0x74, 0x5c, 0xf0, 0xbd, 0xe1, 0x5b, 0x6e, 0x96, 0x9e, 0xb8, 0xa0, 0x63, 0xc3, 0x1d, 0x0b, 0x4b, 0xcf, 0x89,\n\t0x1d, 0x5f, 0x5f, 0x14, 0xfb, 0xd0, 0xb4, 0x64, 0xef, 0x63, 0xab, 0x2f, 0x7d, 0xf4, 0xb2, 0xd6, 0xd6, 0xcb, 0x1e, 0xbd, 0x74, 0xf5, 0x63, 0x7b, 0x97, 0x98, 0x3e, 0x8c, 0x15, 0xad, 0xd7, 0x08, 0xc5, 0x9b, 0xef, 0xfe, 0xe7, 0xa1, 0xfd, 0x1f, 0xe1, 0x92, 0x3e, 0xda, 0x3f, 0xf4, 0xcf, 0x77, 0x6f, 0x2e, 0x16, 0x34, 0xa8, 0xed, 0x5b, 0x50, 0xbb, 0xde, 0x25, 0x7e, 0xb2, 0x3f, 0xa5, 0x7e, 0xb5, 0x52, 0x1f, 0xc9, 0xfd, 0x7e, 0x53, 0x1e, 0xbc, 0x6d, 0xf8, 0x4d, 0x02, 0xcf, 0xc7, 0x6f, 0x97, 0xe1, 0x2f, 0x61, 0xb8, 0xf0, 0x8c, 0x0a, 0xef, 0x90, 0xe6, 0x13, 0x1f, 0x8f, 0x6d, 0x04, 0xff, 0xa4, 0x0a, 0x6f, 0xa2, 0x70, 0xe9, 0xfa, 0x3c, 0x78, 0x5a, 0x2e, 0xe7, 0xe2, 0x3c, 0xf8, 0x84, 0x71, 0xca, 0xef, 0x94, 0xcb, 0xbf, 0x87, 0xe0, 0x1f, 0x57, 0xe1, 0xcd, 0x32, 0xfc, 0x32, 0x04,\n\t0xff, 0x2f, 0xda, 0xa7, 0x24, 0x6e, 0x5f, 0x8b, 0x74, 0x07, 0xb9, 0xcb, 0x19, 0x94, 0x36, 0x23, 0xfc, 0xc3, 0x2a, 0xfe, 0x74, 0x66, 0x3b, 0xc1, 0xdf, 0x42, 0xe0, 0x4a, 0xbb, 0x62, 0x94, 0x0f, 0x99, 0xe7, 0xd2, 0x4d, 0x79, 0xcf, 0x09, 0x3f, 0xb2, 0x9e, 0xe7, 0xbf, 0xdf, 0x9e, 0xf7, 0xfc, 0x25, 0xfc, 0x5c, 0xa5, 0x3f, 0x46, 0xf9, 0x93, 0x55, 0xff, 0x36, 0xf2, 0xfe, 0x49, 0xf5, 0x79, 0x53, 0xee, 0x73, 0xe9, 0xfa, 0xbc, 0xe7, 0xe9, 0xbc, 0xf2, 0x2f, 0xce, 0x7b, 0x3e, 0xe1, 0x2c, 0xf5, 0x77, 0xe6, 0x96, 0x0f, 0xfa, 0x46, 0xde, 0xe3, 0xee, 0x20, 0xfe, 0xcc, 0x3f, 0x93, 0xfd, 0x99, 0xb3, 0xe1, 0x4f, 0x2a, 0x70, 0xbe, 0x71, 0x1c, 0x78, 0xdb, 0x38, 0xf0, 0xf6, 0x6c, 0x38, 0xa9, 0x9f, 0xc2, 0x3b, 0x72, 0xf0, 0x4f, 0xaa, 0xf0, 0xa6, 0x71, 0xe0, 0xe9, 0x71, 0xe0, 0x13, 0xc6,\n\t0x29, 0xbf, 0x13, 0x7c, 0x91, 0x76, 0x1d, 0x57, 0xf1, 0x5b, 0x72, 0xe0, 0x7b, 0x55, 0x78, 0x6b, 0x0e, 0xbc, 0x4b, 0x2d, 0xe7, 0xb1, 0x1c, 0xf8, 0x21, 0x15, 0xfe, 0xb8, 0x02, 0x97, 0x36, 0x73, 0x77, 0x10, 0xdf, 0x36, 0x5a, 0xce, 0x74, 0xb8, 0x39, 0x03, 0x57, 0xf9, 0x13, 0xa3, 0xf0, 0x6c, 0xbe, 0xe6, 0x3d, 0x27, 0x7c, 0x3d, 0xc3, 0xfb, 0xed, 0x63, 0x3d, 0x57, 0xf9, 0x10, 0xa3, 0x7c, 0x1e, 0xf5, 0xfe, 0x49, 0xf5, 0x79, 0xd3, 0x59, 0x9e, 0xa7, 0xcf, 0xf2, 0x7c, 0xc2, 0x59, 0xea, 0xef, 0x1c, 0xf3, 0xfd, 0xe3, 0xea, 0xf3, 0xe6, 0xb3, 0x3c, 0x6f, 0x19, 0xf3, 0xf9, 0xde, 0x51, 0xfc, 0x53, 0xfa, 0x69, 0xf6, 0xc8, 0xfb, 0xec, 0x22, 0xd2, 0xdf, 0xcf, 0x93, 0xbb, 0xdd, 0xb7, 0x17, 0x83, 0x2c, 0xf8, 0x93, 0x0a, 0x9c, 0x9f, 0x32, 0x0e, 0xbc, 0x6d, 0x1c, 0x78, 0x7b, 0x0e, 0xfc,\n\t0xa4, 0x0a, 0x6f, 0x1a, 0x07, 0x9e, 0x1e, 0x07, 0x3e, 0x21, 0x07, 0x3e, 0x1e, 0x9d, 0xc7, 0x55, 0xfc, 0x16, 0x19, 0x6e, 0x95, 0x0e, 0x73, 0x4e, 0x82, 0xff, 0x02, 0xc5, 0xdf, 0x48, 0xd7, 0xd5, 0x52, 0x04, 0x2f, 0xe7, 0x34, 0x20, 0x80, 0x63, 0xfc, 0x15, 0xa0, 0xb5, 0xc8, 0xad, 0x41, 0x5a, 0x14, 0xd3, 0x85, 0xc3, 0x51, 0x71, 0x0b, 0xb1, 0xc3, 0x33, 0xd9, 0x4d, 0x11, 0x87, 0xe6, 0x35, 0xa0, 0x27, 0x1c, 0x09, 0xd9, 0x42, 0x4a, 0x20, 0x36, 0xf5, 0xa0, 0xa1, 0x36, 0x9a, 0x50, 0x53, 0x64, 0xc9, 0x1b, 0x55, 0x0e, 0x87, 0xec, 0xed, 0xb9, 0xa6, 0xf1, 0x74, 0xba, 0x23, 0xa9, 0xf7, 0xc4, 0x0a, 0x67, 0x5f, 0xee, 0x99, 0xf2, 0xad, 0x0b, 0xb0, 0x95, 0x95, 0x74, 0x98, 0xfd, 0x15, 0x8d, 0x47, 0xc3, 0xbc, 0xdc, 0x3d, 0xb5, 0xd7, 0xe8, 0xb6, 0xe9, 0x7b, 0x66, 0x4d, 0x3f, 0x17, 0x5b,\n\t0x57, 0xa9, 0x74, 0x3e, 0x29, 0xd3, 0x89, 0xe3, 0x34, 0x7c, 0x35, 0x8b, 0xfe, 0x0c, 0xbc, 0x0d, 0xec, 0x19, 0x13, 0xde, 0x2e, 0xc7, 0x25, 0x22, 0x70, 0x32, 0x8e, 0x5e, 0x90, 0xe7, 0x8b, 0xdd, 0x59, 0xf8, 0x27, 0x55, 0x78, 0x53, 0x4e, 0xf9, 0x19, 0x78, 0x1a, 0x7c, 0x65, 0x4c, 0xf8, 0x04, 0xf0, 0x8f, 0x63, 0x96, 0xdf, 0x99, 0x53, 0x7e, 0x1e, 0x9f, 0x55, 0xf8, 0x71, 0x15, 0xbf, 0x05, 0xbc, 0x95, 0x05, 0xdf, 0xab, 0xc2, 0x5b, 0xc1, 0x83, 0x32, 0x7c, 0x33, 0xe7, 0x24, 0x7e, 0x76, 0xa4, 0x1c, 0x7e, 0xfa, 0x66, 0x90, 0x81, 0xab, 0xed, 0x8d, 0x51, 0xfe, 0x9c, 0xe1, 0x39, 0xe1, 0xd3, 0x19, 0x9e, 0x13, 0x7e, 0xe5, 0x3f, 0x57, 0xdb, 0x15, 0xa3, 0x7c, 0x1b, 0xf5, 0xfe, 0x49, 0xf5, 0x79, 0xd3, 0x98, 0xf5, 0x67, 0x9e, 0x13, 0x3e, 0x9e, 0xe1, 0x39, 0xe1, 0xe7, 0x19, 0xea, 0xef,\n\t0x1c, 0xb3, 0x7e, 0x85, 0x8f, 0x51, 0xbe, 0xf9, 0x52, 0xf9, 0xe9, 0xa8, 0x67, 0x31, 0xca, 0xe3, 0x51, 0xef, 0xee, 0x55, 0x9f, 0x13, 0x5e, 0x67, 0x3d, 0xbf, 0x7a, 0xe4, 0x03, 0xa6, 0x98, 0xf4, 0xdd, 0x2f, 0xe9, 0x5c, 0x4f, 0xe3, 0x16, 0x8e, 0x3c, 0x88, 0xe0, 0x9b, 0xf8, 0x57, 0x54, 0xf8, 0x3b, 0x23, 0x73, 0x88, 0xec, 0x10, 0x7c, 0xf6, 0x63, 0x60, 0x01, 0x3d, 0xf4, 0x3a, 0xa1, 0x80, 0x9e, 0xe8, 0xc8, 0xa7, 0x3c, 0x1b, 0xd4, 0x8b, 0x80, 0x5c, 0xf8, 0x3a, 0x7c, 0xce, 0x3a, 0x0a, 0xb5, 0xbf, 0xff, 0x44, 0x24, 0x54, 0x80, 0x15, 0x7c, 0x1b, 0xde, 0x3b, 0xb7, 0x40, 0xf5, 0xdc, 0xea, 0xea, 0xd3, 0x1d, 0x53, 0xe6, 0x7a, 0xcb, 0x5b, 0x02, 0xed, 0x4b, 0xd3, 0x01, 0xf6, 0xe3, 0xe1, 0xf0, 0xf4, 0x19, 0xad, 0x8e, 0x80, 0x53, 0x1f, 0xef, 0x5e, 0x4b, 0x63, 0xef, 0x76, 0x22, 0x3a,\n\t0x26, 0x20, 0x3a, 0x3c, 0xe0, 0x12, 0x39, 0xbc, 0x2a, 0x07, 0xd1, 0xde, 0x1d, 0x07, 0xb3, 0xc1, 0xc1, 0x67, 0x56, 0x91, 0x38, 0x35, 0x59, 0x16, 0x07, 0x86, 0x33, 0xa1, 0x10, 0x4b, 0x83, 0x33, 0x15, 0x40, 0xa3, 0x95, 0xa2, 0xca, 0xdc, 0xc4, 0xf9, 0x3b, 0x82, 0x83, 0xd7, 0x44, 0x14, 0x62, 0xdb, 0xa0, 0x12, 0xc8, 0x30, 0x84, 0x6f, 0x10, 0x98, 0x09, 0x0a, 0xdd, 0x03, 0x03, 0xa7, 0x7f, 0xf0, 0x83, 0x8e, 0x29, 0xd7, 0xa9, 0x94, 0x1f, 0x24, 0x21, 0x3e, 0xf7, 0xdc, 0x34, 0x7d, 0x06, 0xe1, 0xfd, 0x95, 0x84, 0xf7, 0x4f, 0x2a, 0x3c, 0xe6, 0xa7, 0xc8, 0xbc, 0xff, 0x94, 0xc2, 0x81, 0x02, 0x6f, 0xc3, 0xbc, 0x47, 0xf0, 0xd7, 0xf3, 0xe0, 0xed, 0x32, 0xfc, 0x97, 0x08, 0x5e, 0x45, 0xc6, 0x0f, 0x85, 0x77, 0xc8, 0xb1, 0x27, 0x69, 0xf9, 0x27, 0x55, 0x78, 0x93, 0x5c, 0xfe, 0x07, 0x14,\n\t0xae, 0x96, 0x93, 0x96, 0xcb, 0xf9, 0x75, 0x1e, 0x7c, 0xc2, 0x38, 0xe5, 0x77, 0x9e, 0x69, 0x8c, 0x20, 0xf8, 0x32, 0x04, 0x5f, 0x41, 0xf4, 0x48, 0x8a, 0x3f, 0x49, 0x86, 0x1f, 0xc1, 0xe5, 0x0b, 0xcf, 0xa8, 0xf0, 0xc9, 0x14, 0x2e, 0x8f, 0xc1, 0xe3, 0x6a, 0xf9, 0xcd, 0x32, 0xfd, 0x75, 0x79, 0xf0, 0x16, 0xb9, 0xde, 0x27, 0x08, 0x7c, 0xaf, 0x5a, 0x4e, 0xab, 0x5c, 0xfe, 0x49, 0x02, 0xef, 0x52, 0xe0, 0xe0, 0x31, 0x19, 0xfe, 0x0c, 0x81, 0x1f, 0x52, 0xe1, 0x8f, 0xcb, 0x63, 0xf9, 0x18, 0x9a, 0x87, 0x9e, 0x23, 0xb1, 0x98, 0x8f, 0x52, 0xf7, 0x75, 0x7d, 0x40, 0xcb, 0x70, 0xac, 0x19, 0x02, 0x81, 0xc4, 0x53, 0x93, 0x7f, 0xa1, 0x21, 0xa1, 0xe4, 0xf8, 0x0b, 0xc9, 0x16, 0xba, 0x38, 0xb0, 0x24, 0xde, 0xa1, 0xae, 0x93, 0x47, 0x09, 0xfd, 0x8e, 0x06, 0xf5, 0x1a, 0x35, 0x13, 0x45, 0x3e,\n\t0xea, 0x86, 0x2c, 0xd4, 0x0d, 0x0a, 0x2a, 0xbe, 0x7a, 0x90, 0xb1, 0xc8, 0x11, 0xfe, 0x60, 0xd6, 0xa8, 0x93, 0x71, 0xe4, 0xa1, 0x17, 0x05, 0x11, 0x5b, 0xc8, 0x16, 0x8d, 0x86, 0xe4, 0xa1, 0x47, 0xb3, 0xb1, 0x53, 0x5f, 0x3d, 0x12, 0x6d, 0x0f, 0x1f, 0x8e, 0x65, 0x19, 0xfe, 0xa2, 0x2f, 0xdc, 0x73, 0x93, 0xda, 0xe3, 0x33, 0xd2, 0x15, 0xfa, 0xe6, 0xaf, 0x2c, 0x99, 0x76, 0x5e, 0x44, 0xe4, 0x97, 0xc7, 0x93, 0xa7, 0x57, 0xae, 0xea, 0xbf, 0x26, 0x71, 0xba, 0xa7, 0xe3, 0x86, 0x99, 0xde, 0xb8, 0x3b, 0xd5, 0x53, 0xb7, 0x60, 0x45, 0xa2, 0x2c, 0x3e, 0x37, 0x22, 0xbd, 0x9f, 0x28, 0xe3, 0x3e, 0x19, 0xbe, 0x6b, 0xdd, 0x55, 0xcb, 0xe7, 0x31, 0x07, 0x87, 0x4b, 0xba, 0xa7, 0x92, 0x98, 0xa2, 0x87, 0x39, 0x0f, 0x19, 0x9f, 0xbf, 0x96, 0xf5, 0xad, 0x5b, 0xe5, 0x58, 0xa3, 0x18, 0x7e, 0x52,\n\t0x85, 0x37, 0xc9, 0x70, 0x6c, 0x13, 0xfc, 0x9f, 0x64, 0x2e, 0x79, 0x43, 0xd6, 0x1b, 0x6f, 0xca, 0x82, 0x6f, 0x57, 0xe1, 0x27, 0x72, 0xe0, 0xaf, 0xa8, 0xf0, 0x77, 0x72, 0xe0, 0x4f, 0x2a, 0x70, 0x34, 0xdf, 0x8f, 0x0d, 0x6f, 0x1b, 0x07, 0xde, 0x9e, 0x0d, 0x27, 0xe3, 0xf6, 0x0d, 0x79, 0x3d, 0xcc, 0xc6, 0x3f, 0xa9, 0xc2, 0x9b, 0xc6, 0x81, 0xa7, 0xc7, 0x81, 0x4f, 0x18, 0xa7, 0xfc, 0xce, 0x1c, 0xfc, 0xe3, 0x2a, 0x7c, 0xe2, 0x38, 0xf0, 0x49, 0xe3, 0x94, 0x33, 0x79, 0x1c, 0xfc, 0xe6, 0x71, 0xe0, 0x2d, 0x39, 0xf0, 0xbd, 0x2a, 0xbc, 0x35, 0x07, 0xde, 0xa5, 0xf2, 0xf9, 0xb1, 0x1c, 0xf8, 0x21, 0x15, 0xfe, 0x38, 0x86, 0x03, 0x06, 0xcc, 0x90, 0x8e, 0xf0, 0xd7, 0x21, 0xfd, 0xc8, 0x08, 0x1a, 0xc1, 0x82, 0x13, 0x71, 0x08, 0x19, 0x25, 0x86, 0x75, 0x61, 0x26, 0xe2, 0x8b, 0x40, 0x0e,\n\t0x45, 0xf1, 0xf0, 0x5d, 0xd7, 0xad, 0x44, 0x03, 0x1b, 0xf3, 0xf1, 0x86, 0x6e, 0x25, 0xfa, 0x97, 0xbe, 0xb1, 0xc1, 0x62, 0x71, 0xc7, 0x4a, 0x0b, 0x44, 0x3c, 0x86, 0x95, 0x6d, 0xbd, 0xe0, 0x08, 0x65, 0xef, 0xe2, 0xe9, 0xc1, 0x05, 0xb6, 0xd2, 0x72, 0x15, 0xe1, 0x93, 0x16, 0x7c, 0x2d, 0x8b, 0x76, 0xfd, 0x6c, 0xe7, 0x92, 0x9b, 0x57, 0xd4, 0x24, 0xa6, 0x9c, 0x5b, 0xd5, 0x31, 0xed, 0xb1, 0xc4, 0xec, 0xcd, 0xdd, 0x03, 0xdf, 0xb8, 0xb8, 0xf3, 0x9c, 0xdb, 0x7e, 0x71, 0xed, 0x63, 0xdb, 0x7f, 0x7e, 0x60, 0x56, 0x6a, 0xe9, 0x8e, 0x59, 0x35, 0x22, 0x23, 0x9a, 0x34, 0x4b, 0x06, 0xab, 0x97, 0xde, 0xb4, 0xe8, 0x5a, 0xd8, 0xbc, 0xf6, 0xc0, 0xe2, 0x99, 0xdb, 0x16, 0xd5, 0xf4, 0x2d, 0x99, 0x73, 0x69, 0x6f, 0xa4, 0x67, 0xc7, 0x89, 0x35, 0x57, 0xfe, 0xf0, 0xe6, 0x3e, 0x28, 0x7d, 0x07,\n\t0x4e, 0x81, 0xbd, 0x37, 0x7e, 0x7f, 0xe3, 0xc2, 0xaf, 0x5e, 0xbb, 0x2a, 0xd8, 0x6b, 0xf0, 0xba, 0xac, 0x6c, 0xcd, 0x77, 0x2e, 0x9d, 0xb5, 0x73, 0xa0, 0x19, 0x92, 0x39, 0xe1, 0x52, 0xd4, 0x76, 0xb4, 0x37, 0x01, 0x49, 0x7c, 0x1e, 0x1c, 0x0f, 0xf8, 0x59, 0xc8, 0xe8, 0x88, 0x71, 0x22, 0xc0, 0x47, 0x2e, 0xe4, 0x40, 0x98, 0x84, 0x6a, 0xf1, 0x66, 0x4c, 0x55, 0x93, 0xa0, 0xbc, 0xd0, 0x66, 0xf1, 0x09, 0x82, 0x3b, 0x81, 0x4f, 0x88, 0xe4, 0x46, 0x84, 0x01, 0x3e, 0x7d, 0xc1, 0xd7, 0xab, 0x99, 0xe3, 0x17, 0x7c, 0xcd, 0x5c, 0x5b, 0x9f, 0xe2, 0x07, 0x0c, 0x0e, 0x93, 0x66, 0xe1, 0x9d, 0x3f, 0xde, 0x74, 0x4a, 0xfa, 0x9d, 0xf4, 0xf6, 0xf5, 0x06, 0x57, 0x81, 0xae, 0x7a, 0xd1, 0xb5, 0x73, 0x4e, 0xf5, 0x5e, 0x3f, 0xd0, 0x68, 0xb4, 0x5a, 0xf9, 0x90, 0x9d, 0xfd, 0xb8, 0xe3, 0xa2, 0x4d,\n\t0x17, 0xa5, 0x0f, 0xfc, 0xe8, 0xea, 0xb4, 0x56, 0xfa, 0x36, 0x9c, 0x6a, 0x85, 0xcc, 0x2f, 0x19, 0xa7, 0xd9, 0xe9, 0x33, 0x48, 0xf5, 0xdd, 0x17, 0xcf, 0xa9, 0xd5, 0xf1, 0x86, 0x4f, 0xdf, 0x17, 0xab, 0x16, 0xdf, 0x7a, 0xde, 0xf4, 0x0d, 0x8b, 0xe7, 0x54, 0x44, 0xfc, 0xb8, 0x3f, 0xe7, 0x8c, 0xbc, 0xcb, 0x3f, 0x4c, 0xe4, 0xef, 0x77, 0x54, 0xfe, 0xe0, 0x26, 0x90, 0x81, 0x3f, 0xa9, 0xc0, 0xf9, 0x29, 0xe3, 0xc0, 0xdb, 0xc6, 0x81, 0xb7, 0x67, 0xc3, 0xc9, 0x38, 0xa5, 0xf0, 0x8e, 0x1c, 0xfc, 0x93, 0x2a, 0xbc, 0x69, 0x1c, 0x78, 0x7a, 0x1c, 0xf8, 0x84, 0x71, 0xca, 0xef, 0xcc, 0xc1, 0x3f, 0xae, 0xc2, 0x9b, 0xc7, 0x81, 0xb7, 0xc0, 0x0b, 0xb3, 0xe0, 0x7b, 0x55, 0x78, 0xab, 0x82, 0x8f, 0xf6, 0xf3, 0x0f, 0x13, 0x9b, 0xd4, 0xdf, 0xc9, 0xfb, 0xf8, 0xf9, 0x19, 0xb8, 0xda, 0xde, 0x18,\n\t0xe5, 0xcf, 0x19, 0x9e, 0xb7, 0x9d, 0xe5, 0x79, 0xfb, 0x58, 0xcf, 0xd5, 0x76, 0xc5, 0x28, 0xdf, 0x46, 0xbd, 0x7f, 0x52, 0x7d, 0xde, 0x74, 0x96, 0xe7, 0xe9, 0xb3, 0x3c, 0x9f, 0x70, 0x96, 0xfa, 0x3b, 0xc7, 0x7c, 0xff, 0xb8, 0xfa, 0xbc, 0xf9, 0x2c, 0xcf, 0x5b, 0xc6, 0x7c, 0xbe, 0x57, 0x7d, 0xde, 0x9a, 0xfd, 0x1c, 0xcd, 0x27, 0x0f, 0x01, 0xc0, 0xed, 0x45, 0x32, 0x65, 0x40, 0x02, 0xd3, 0x94, 0xae, 0xc7, 0xf7, 0xba, 0xf8, 0xa0, 0x77, 0x00, 0xf0, 0x3c, 0xd7, 0x8f, 0x2f, 0xcd, 0xe4, 0xd9, 0x02, 0x10, 0x3f, 0x44, 0x93, 0x11, 0x02, 0xe2, 0x2f, 0xe8, 0x34, 0xfa, 0x4d, 0x7e, 0xbd, 0x16, 0x18, 0xa0, 0x41, 0xa3, 0xb3, 0x27, 0x22, 0x34, 0x3c, 0x03, 0x13, 0x0a, 0x5a, 0xd4, 0x2b, 0xce, 0x20, 0xf1, 0xfd, 0x67, 0x6e, 0x99, 0xb5, 0x69, 0x5a, 0x30, 0x38, 0x75, 0xd3, 0x2c, 0xe9, 0x03,\n\t0x68, 0xd8, 0xf1, 0xd4, 0x95, 0x2d, 0x93, 0xb6, 0x3f, 0x79, 0xa9, 0x14, 0x60, 0x8f, 0x0c, 0x97, 0x3d, 0x10, 0xee, 0x3c, 0xb7, 0xbe, 0xe9, 0xdc, 0xf6, 0xa0, 0xe4, 0x61, 0x6e, 0x6e, 0x59, 0xb3, 0x77, 0xce, 0xc0, 0xd7, 0x36, 0xb5, 0xf1, 0x87, 0xee, 0x97, 0x26, 0x51, 0xfd, 0x17, 0xd3, 0xe6, 0x22, 0xb1, 0xd3, 0xff, 0x40, 0xe3, 0x76, 0x83, 0x67, 0x08, 0xdc, 0x04, 0x80, 0xa6, 0x48, 0x64, 0x11, 0xfc, 0x03, 0x62, 0xdf, 0x9d, 0x62, 0xae, 0xcf, 0xc0, 0x49, 0x0e, 0x9e, 0x0f, 0x68, 0x0e, 0x1e, 0x19, 0x1e, 0x1d, 0x79, 0x8f, 0x0b, 0x11, 0xf8, 0x87, 0x14, 0x0e, 0x0e, 0x2a, 0xe5, 0xf3, 0xd3, 0x45, 0x06, 0xc1, 0x3f, 0xc2, 0xbe, 0x4a, 0x30, 0x05, 0x2f, 0x42, 0x50, 0x7a, 0x4e, 0x3a, 0x22, 0xfb, 0x2a, 0x51, 0x9c, 0x36, 0x05, 0x07, 0x1c, 0x86, 0x6b, 0xc6, 0xc6, 0x11, 0xbe, 0xae, 0xe2,\n\t0x7c, 0x7b, 0xbc, 0x72, 0x84, 0x3f, 0xaa, 0x38, 0x8f, 0x2a, 0x38, 0x4c, 0x2e, 0x4e, 0x3b, 0x69, 0xef, 0x1f, 0x69, 0x7b, 0x61, 0x92, 0xdc, 0xd7, 0xf7, 0x8f, 0xfc, 0x81, 0xc7, 0x3e, 0xb9, 0x3a, 0xe0, 0x00, 0x65, 0xd8, 0x42, 0x92, 0x44, 0x42, 0xc2, 0x41, 0xbd, 0x97, 0x93, 0x8b, 0x45, 0x9c, 0x0d, 0x2a, 0xd5, 0xad, 0x58, 0x11, 0xd6, 0xf2, 0x3d, 0x2e, 0xa7, 0x5e, 0x0f, 0x40, 0xb0, 0xd8, 0x59, 0xe6, 0x2a, 0xd3, 0x3b, 0xf4, 0x0e, 0x8b, 0x19, 0xbd, 0xab, 0x0b, 0x6b, 0x45, 0x07, 0x9e, 0x05, 0xb1, 0xb5, 0x5d, 0x43, 0xac, 0x82, 0x24, 0x2c, 0x14, 0x61, 0x0d, 0xe7, 0xb4, 0x3a, 0xec, 0x8c, 0xc0, 0x85, 0x4a, 0xc2, 0x51, 0xd4, 0x89, 0xd6, 0xfa, 0x30, 0xac, 0xd3, 0xce, 0xb8, 0xea, 0xe8, 0xda, 0xb5, 0x47, 0xb7, 0xcd, 0xd0, 0x32, 0x86, 0xde, 0xad, 0x0f, 0xae, 0x5e, 0xf5, 0xe0, 0xb6,\n\t0x3e, 0x03, 0xfc, 0xdd, 0xdd, 0x50, 0x78, 0x62, 0xf5, 0xea, 0x27, 0xa4, 0x4f, 0xef, 0xfe, 0xaa, 0xf4, 0xc9, 0x77, 0xd7, 0xac, 0xf9, 0x2e, 0x14, 0x99, 0x5d, 0x1b, 0x8f, 0x5f, 0xd1, 0xd9, 0x79, 0xc5, 0xf1, 0x8d, 0x5f, 0x3b, 0xff, 0xc1, 0xcd, 0xed, 0xed, 0x9b, 0x1f, 0x3c, 0x9f, 0xb9, 0xfa, 0x82, 0x53, 0xd2, 0x7b, 0x77, 0x7f, 0x4d, 0x7a, 0xff, 0xd4, 0xba, 0x75, 0xa7, 0xa0, 0xf1, 0x6b, 0x77, 0x43, 0xd3, 0xa9, 0x0b, 0x50, 0xfb, 0x18, 0xd4, 0x0f, 0xef, 0x91, 0x7e, 0x1b, 0xa6, 0xfd, 0x06, 0x24, 0xd2, 0x0f, 0x04, 0x8e, 0xe3, 0xa0, 0x53, 0x38, 0xf8, 0x36, 0xd2, 0x4e, 0x32, 0xf0, 0x8f, 0x55, 0xf8, 0xa3, 0xd9, 0x70, 0x12, 0x6b, 0x9f, 0xc2, 0x9f, 0x92, 0xe1, 0x0b, 0xd0, 0x78, 0xb9, 0x0a, 0xe3, 0xe3, 0xdb, 0x1f, 0x82, 0xff, 0x96, 0xd2, 0xcf, 0xc2, 0x52, 0x01, 0xe9, 0x92, 0x88,\n\t0xef, 0xd8, 0x27, 0xce, 0xc2, 0xbd, 0x40, 0x9f, 0xc3, 0xcf, 0xc9, 0xf3, 0xda, 0x91, 0x77, 0xb9, 0xdf, 0xe2, 0xbe, 0x81, 0x1a, 0xda, 0x37, 0xe0, 0x91, 0xfc, 0xbe, 0x41, 0xbf, 0x01, 0xbf, 0x9a, 0xd4, 0x29, 0x11, 0x9f, 0x2a, 0x00, 0x7d, 0xa4, 0x6f, 0x70, 0x5c, 0xe1, 0x03, 0x48, 0x4f, 0xd5, 0x01, 0x17, 0x28, 0xc7, 0x51, 0x20, 0x4a, 0xc8, 0x92, 0x0c, 0x64, 0x31, 0x42, 0x3d, 0xc5, 0xd2, 0x0e, 0x5a, 0x95, 0xb9, 0x43, 0x1d, 0xe4, 0x7b, 0x3c, 0x6e, 0xbd, 0x1e, 0xe7, 0xb6, 0x71, 0x97, 0x7b, 0xca, 0xf5, 0x2e, 0xbd, 0xd3, 0x64, 0xd0, 0x8a, 0x40, 0x07, 0x75, 0x5a, 0x22, 0x4c, 0xe4, 0x9a, 0x3d, 0x01, 0x3d, 0x4a, 0xd8, 0x13, 0x26, 0xd4, 0xa0, 0x2c, 0xc1, 0x72, 0xdc, 0x0d, 0x24, 0x58, 0x8e, 0x25, 0xeb, 0xed, 0x55, 0x33, 0x9b, 0x9e, 0xfb, 0x6e, 0x7c, 0x6a, 0xca, 0x6f, 0x4b, 0x76,\n\t0x35, 0x08, 0x4b, 0x6e, 0x58, 0x50, 0x66, 0x2d, 0xef, 0x6e, 0x1e, 0xba, 0xb2, 0x6d, 0xcd, 0xee, 0x99, 0xd2, 0x85, 0x3b, 0xfb, 0x7b, 0x82, 0x4d, 0x71, 0x97, 0xf4, 0x14, 0xf3, 0x8e, 0xf4, 0xac, 0x3b, 0xd1, 0x16, 0xf6, 0xd5, 0x94, 0xba, 0xaf, 0x89, 0x4c, 0x58, 0x90, 0x0a, 0x4e, 0xeb, 0xac, 0x37, 0xdb, 0xb7, 0x0c, 0x74, 0x6f, 0xe8, 0x0a, 0x23, 0xe2, 0xe5, 0xf8, 0xc8, 0x21, 0xec, 0xa3, 0x00, 0xad, 0x34, 0x46, 0x51, 0x94, 0xca, 0xa0, 0x6b, 0x64, 0x44, 0x08, 0x60, 0x3d, 0x04, 0x3a, 0xa8, 0x4f, 0x06, 0xbc, 0x31, 0x0b, 0xbe, 0x5d, 0x81, 0x83, 0x13, 0x18, 0x8e, 0xef, 0xc5, 0x47, 0xde, 0x63, 0xab, 0x48, 0x2c, 0xa2, 0xeb, 0xd2, 0x3a, 0x23, 0xe4, 0x78, 0x2f, 0x64, 0x19, 0xc5, 0x02, 0x3d, 0x99, 0x31, 0x18, 0xa7, 0x6e, 0x5e, 0x80, 0x07, 0x1c, 0xc3, 0x73, 0xd8, 0xc8, 0x3e, 0x13,\n\t0xfd, 0x89, 0x68, 0xdb, 0xeb, 0x20, 0x49, 0xf4, 0xf7, 0x85, 0xf1, 0x37, 0x60, 0xef, 0x30, 0x2b, 0x09, 0x61, 0x5a, 0x9e, 0x28, 0x0b, 0x05, 0x8b, 0x0a, 0x9d, 0xf6, 0x12, 0x0d, 0x36, 0x73, 0xc9, 0x58, 0x2a, 0xa8, 0x79, 0xad, 0xd0, 0x52, 0xaf, 0xdc, 0xb3, 0x63, 0xfe, 0xe2, 0xd3, 0x22, 0xd5, 0xb6, 0x81, 0x5e, 0xc3, 0x4f, 0x6f, 0xba, 0xef, 0xa2, 0xc5, 0x7b, 0x96, 0x57, 0xdb, 0xe2, 0x93, 0x53, 0x4b, 0xd6, 0x77, 0xae, 0xbf, 0x79, 0x66, 0xd5, 0xca, 0x15, 0x0b, 0x42, 0x8d, 0x46, 0xb7, 0xad, 0xac, 0xe5, 0x9c, 0xf6, 0xba, 0x73, 0x9a, 0x8a, 0x36, 0x5f, 0x7e, 0xe1, 0x85, 0xeb, 0xb6, 0x78, 0xeb, 0x7a, 0x6b, 0x9b, 0xfb, 0x1a, 0x23, 0x46, 0x93, 0x4d, 0xcf, 0xee, 0xa9, 0x9f, 0x94, 0xec, 0x5e, 0x56, 0x5b, 0xd4, 0xd9, 0x9a, 0xb2, 0xf8, 0xb7, 0x2e, 0x99, 0xba, 0xa9, 0x37, 0x6e, 0x8d,\n\t0xb6, 0x26, 0xa6, 0x59, 0x8b, 0xc3, 0xc5, 0xde, 0x8a, 0xf6, 0xc8, 0xb4, 0x79, 0xd7, 0xcc, 0x4a, 0x17, 0xa6, 0x62, 0x4e, 0x57, 0xa1, 0x4b, 0x6f, 0x21, 0xfc, 0x6a, 0x92, 0xee, 0x64, 0x1b, 0x11, 0xbf, 0xfa, 0xc0, 0x7b, 0x69, 0xab, 0x11, 0x8a, 0x9a, 0x72, 0x28, 0xf0, 0x6e, 0xb4, 0xaf, 0x09, 0xe1, 0xd8, 0x3a, 0x32, 0xdf, 0x1a, 0x81, 0x4e, 0xab, 0xd1, 0xea, 0x34, 0x59, 0x21, 0xb3, 0xd0, 0x14, 0xae, 0x11, 0x07, 0x80, 0x56, 0xab, 0xf0, 0x41, 0x10, 0x28, 0xdf, 0x88, 0x79, 0x74, 0x5e, 0x40, 0xaf, 0x2f, 0xf1, 0xfe, 0x86, 0xdc, 0xf7, 0xd3, 0x1d, 0xa3, 0x5e, 0x65, 0xf1, 0xe5, 0x1c, 0x73, 0xc6, 0x22, 0x40, 0xa6, 0x04, 0x9c, 0x99, 0x6e, 0x66, 0xcf, 0xf4, 0xa9, 0x9d, 0x1d, 0xed, 0xad, 0xf5, 0xb5, 0xd5, 0x95, 0xb1, 0x48, 0xa0, 0xc8, 0xef, 0x43, 0x7d, 0xa3, 0x1f, 0xa7, 0x6f, 0xa2,\n\t0x31, 0x47, 0xb6, 0xe1, 0x00, 0xdd, 0xc4, 0x9f, 0xad, 0xbb, 0x66, 0x8d, 0xee, 0xae, 0x55, 0xd5, 0x55, 0xe9, 0x40, 0xa5, 0xd1, 0xe0, 0x15, 0xcc, 0xb2, 0x6f, 0x25, 0xfc, 0xf2, 0xbd, 0x67, 0xb1, 0xf7, 0x10, 0xa7, 0xca, 0x5e, 0x9b, 0x15, 0x3b, 0x5e, 0x3e, 0x0a, 0xc7, 0xef, 0x4a, 0x24, 0x13, 0x64, 0xec, 0x13, 0x99, 0x70, 0x52, 0xbf, 0xb6, 0x42, 0x39, 0x76, 0xe7, 0xc8, 0x08, 0xfb, 0x19, 0x91, 0x21, 0x97, 0xec, 0xd7, 0xf4, 0x64, 0x16, 0xfc, 0x88, 0x02, 0x07, 0x0f, 0x62, 0x38, 0x8e, 0x25, 0x8e, 0xe1, 0x48, 0x2c, 0xbd, 0x20, 0x9c, 0x0e, 0xda, 0x05, 0x06, 0x5f, 0xbc, 0xca, 0x01, 0xe5, 0xa1, 0x7a, 0x19, 0xe7, 0x05, 0x1e, 0x4b, 0xdc, 0xc2, 0xe3, 0x04, 0xef, 0xf8, 0xc4, 0xb3, 0xbe, 0x41, 0xb9, 0x7e, 0xc5, 0x1b, 0x4c, 0x41, 0x24, 0x09, 0x38, 0x52, 0xec, 0x67, 0xa7, 0x39, 0x4e,\n\t0x67, 0xd3, 0x49, 0x49, 0x7d, 0xd8, 0xb5, 0xf9, 0x14, 0xc7, 0xd9, 0x6d, 0xf0, 0x39, 0x7d, 0xc4, 0x85, 0x53, 0x1e, 0x31, 0x07, 0xed, 0xd5, 0x1e, 0x47, 0xc4, 0x34, 0xbc, 0xdd, 0x1a, 0x60, 0x3f, 0x19, 0x5e, 0x6d, 0xaf, 0x76, 0x97, 0xfb, 0x98, 0xad, 0x96, 0x40, 0x16, 0x6d, 0x5d, 0x2a, 0x6d, 0x8f, 0xe5, 0xd0, 0xbc, 0x5d, 0x85, 0x9f, 0xc8, 0xc0, 0xb1, 0x8f, 0x13, 0x9a, 0x63, 0xdd, 0xb2, 0xff, 0xd9, 0x6e, 0x35, 0x0f, 0x04, 0x60, 0x3f, 0x03, 0x61, 0x7c, 0x9e, 0xeb, 0x37, 0x0b, 0x2c, 0x64, 0x21, 0x0e, 0x8c, 0x83, 0x86, 0x11, 0x18, 0xe2, 0x71, 0x8a, 0xc6, 0x55, 0xdd, 0x99, 0x1b, 0xc6, 0x30, 0x08, 0x05, 0xdd, 0x31, 0x8b, 0x6c, 0xbe, 0x81, 0x5b, 0x45, 0x9a, 0x84, 0x2f, 0x98, 0x69, 0xd8, 0xfa, 0x2c, 0x4f, 0x33, 0xdc, 0x3e, 0x1e, 0x1c, 0x13, 0x45, 0xe9, 0x88, 0xb6, 0xd0, 0xe6,\n\t0xb4, 0xfa, 0xb5, 0xd2, 0xfd, 0x82, 0xe6, 0xd8, 0x3f, 0xd8, 0x4b, 0x4d, 0xb0, 0xcc, 0xe8, 0xd4, 0xe9, 0x1c, 0x46, 0x18, 0x31, 0x95, 0xda, 0xd9, 0xcf, 0x3e, 0xe7, 0x99, 0xeb, 0x8a, 0x7a, 0x02, 0xc3, 0xf7, 0x59, 0x6c, 0x36, 0x0b, 0xb3, 0x28, 0x30, 0xa3, 0x78, 0xf8, 0x32, 0xf6, 0x33, 0xab, 0x57, 0xd2, 0xb9, 0xeb, 0x7d, 0xbe, 0x7a, 0x37, 0xfc, 0xc8, 0x67, 0x91, 0x69, 0x65, 0x5f, 0x25, 0x39, 0xa8, 0x70, 0x46, 0x36, 0x0e, 0x41, 0x38, 0xb8, 0x9c, 0xdc, 0x82, 0x66, 0xd3, 0xa8, 0x07, 0x7a, 0x92, 0x31, 0x83, 0xf8, 0x1b, 0xc8, 0xb9, 0x80, 0xb1, 0x63, 0x3e, 0xfb, 0xea, 0x69, 0xa9, 0xf2, 0xd4, 0x29, 0xf8, 0x33, 0xcc, 0x5c, 0xf8, 0x73, 0xa9, 0x9c, 0xfd, 0x58, 0x1a, 0x82, 0x37, 0x23, 0xde, 0xcc, 0x44, 0xe5, 0x6e, 0x27, 0x3c, 0x8b, 0xd0, 0x71, 0xb1, 0x22, 0x93, 0x4b, 0x22, 0x4c,\n\t0xe0, 0x65, 0xf2, 0x1c, 0xda, 0x41, 0x73, 0x71, 0xa1, 0x71, 0xb4, 0x85, 0xc0, 0x13, 0x14, 0xbf, 0x84, 0xe2, 0x23, 0x22, 0xd1, 0xde, 0x1e, 0x8f, 0x97, 0x20, 0xf1, 0xe7, 0x1a, 0xb9, 0x80, 0xfa, 0x4f, 0x74, 0x8d, 0xfc, 0x01, 0xce, 0x42, 0x3a, 0x9c, 0x11, 0x04, 0x09, 0xe5, 0xaa, 0x6d, 0x67, 0xb7, 0x92, 0x56, 0x6e, 0x1d, 0x8b, 0x28, 0x2f, 0x2a, 0xb4, 0x5b, 0x11, 0x8e, 0xd1, 0x49, 0xad, 0x38, 0xb1, 0xd0, 0x85, 0xf0, 0x3d, 0x34, 0x9b, 0xb5, 0xc5, 0xc3, 0xe2, 0x06, 0x93, 0x9c, 0xa0, 0x13, 0xae, 0x15, 0x74, 0x22, 0x17, 0xb7, 0x87, 0xaa, 0x0a, 0x0b, 0xab, 0xc2, 0x76, 0x7b, 0x18, 0x7f, 0x86, 0xec, 0xfc, 0xa1, 0xe1, 0xd3, 0xc9, 0x79, 0xf3, 0x17, 0xa5, 0x52, 0x8b, 0xe6, 0xcf, 0x4b, 0x32, 0xad, 0x9f, 0xfe, 0xbb, 0xaf, 0x2a, 0xec, 0x70, 0x84, 0xab, 0x7c, 0x32, 0x16, 0xa6, 0x73,\n\t0xbb, 0xf4, 0x7b, 0xb8, 0x8b, 0x7d, 0x09, 0x8d, 0x85, 0x86, 0x10, 0xd6, 0xab, 0x9a, 0x81, 0x97, 0x79, 0x8d, 0xea, 0x43, 0xcc, 0x6b, 0xf2, 0xfd, 0xf3, 0x85, 0xec, 0x31, 0x78, 0x1e, 0x5a, 0x11, 0x2d, 0x40, 0x38, 0xce, 0x03, 0x58, 0x95, 0xb0, 0x55, 0xa0, 0x0e, 0x6d, 0x70, 0x39, 0x05, 0xd1, 0xc4, 0x38, 0xf1, 0xc7, 0xf7, 0xca, 0x8b, 0xdc, 0x7d, 0x13, 0x5a, 0x2d, 0x9c, 0xd6, 0x13, 0x31, 0xd8, 0x03, 0x26, 0x83, 0x9d, 0x3d, 0x36, 0xfd, 0x6b, 0xff, 0x70, 0x73, 0x53, 0x44, 0x5f, 0xac, 0x2b, 0xea, 0x5f, 0x33, 0x54, 0xef, 0x0a, 0x6b, 0x08, 0x5f, 0x90, 0xb4, 0x71, 0x53, 0xf9, 0xcf, 0x41, 0x0c, 0xa6, 0x47, 0x4e, 0x72, 0x6f, 0x43, 0x01, 0x5c, 0xb0, 0x0a, 0xfb, 0xba, 0x03, 0xf8, 0x6d, 0xee, 0x6d, 0x59, 0xb7, 0x5a, 0xc9, 0x1e, 0x86, 0x8b, 0xf8, 0xcf, 0x11, 0x35, 0x69, 0xb4, 0xfe,\n\t0xbf, 0x9d, 0xfd, 0x14, 0xc8, 0xcf, 0x99, 0x7d, 0xb4, 0x0c, 0xfc, 0x1c, 0xe3, 0xc1, 0x69, 0x08, 0xcf, 0xaa, 0xe2, 0x61, 0xf2, 0x95, 0x17, 0x70, 0xbc, 0xff, 0x7b, 0x61, 0x10, 0xd1, 0xcf, 0x02, 0x1b, 0x3e, 0x3b, 0x85, 0x60, 0x13, 0x9a, 0xf9, 0xd6, 0xc0, 0x1e, 0x4b, 0x01, 0x83, 0x0d, 0x50, 0x53, 0x96, 0xd0, 0xce, 0x83, 0x07, 0x05, 0xf8, 0xf1, 0x3d, 0x38, 0x5e, 0xa0, 0x74, 0x2f, 0xbb, 0x05, 0xe1, 0x46, 0xe1, 0xd4, 0x5f, 0x60, 0xf9, 0x9f, 0xca, 0x54, 0x52, 0xff, 0x75, 0x46, 0xc7, 0x3f, 0xc6, 0x1c, 0x44, 0x65, 0xb8, 0xd3, 0x68, 0x15, 0x45, 0xb2, 0x3d, 0x97, 0xf4, 0x1d, 0x7a, 0x04, 0x67, 0xc8, 0x05, 0x21, 0x1d, 0x7a, 0x2b, 0xdf, 0xf4, 0xe9, 0xbf, 0x30, 0x07, 0xf7, 0x90, 0x77, 0x76, 0xb1, 0x37, 0xf0, 0x27, 0x39, 0x27, 0x7a, 0x27, 0x49, 0x73, 0x4a, 0xe8, 0xb3, 0x0c, 0x3d,\n\t0xc8, 0x31, 0x6e, 0x6e, 0x31, 0xfd, 0x8f, 0x64, 0x0a, 0xda, 0xc5, 0x37, 0x7e, 0xfa, 0x03, 0xce, 0xb9, 0x07, 0x97, 0x03, 0xa4, 0x57, 0x59, 0xfb, 0xc8, 0xc0, 0x17, 0xb0, 0x13, 0xe5, 0x1d, 0xc1, 0x3a, 0xd6, 0xfe, 0xf9, 0xdb, 0x77, 0x5d, 0x73, 0xcd, 0x9f, 0xf2, 0x1e, 0x58, 0xca, 0xda, 0xc1, 0xab, 0x5f, 0xe0, 0xbd, 0x88, 0xfc, 0xde, 0xab, 0x7f, 0x5a, 0x7d, 0xff, 0xc3, 0xef, 0xad, 0x85, 0xc7, 0xe1, 0xfd, 0xcc, 0xfb, 0xc0, 0xa6, 0xf6, 0xe5, 0x7c, 0x40, 0xa3, 0xb3, 0x00, 0xd8, 0x5b, 0x1a, 0x66, 0x44, 0xd4, 0x05, 0x79, 0x72, 0xb6, 0xd6, 0x93, 0x68, 0x0a, 0x04, 0x5b, 0xca, 0x3d, 0x9e, 0xf2, 0x96, 0x60, 0xa0, 0x29, 0xe1, 0x61, 0x66, 0x2b, 0xbf, 0x82, 0x4d, 0xf8, 0xb3, 0x09, 0xbd, 0x7c, 0x11, 0x5b, 0x0d, 0x1f, 0xe6, 0x36, 0x8e, 0x5b, 0xae, 0x6e, 0x74, 0xb9, 0x17, 0xa1, 0x72,\n\t0x83, 0xc1, 0x96, 0x84, 0xc7, 0x93, 0xc0, 0x25, 0x25, 0x3c, 0xec, 0x4f, 0xf3, 0xcb, 0xe5, 0xc0, 0xa4, 0x91, 0x77, 0x85, 0x95, 0xfc, 0x43, 0x40, 0x0b, 0x1a, 0x40, 0x37, 0x5a, 0xc0, 0xff, 0x90, 0xd6, 0xf9, 0x91, 0xe0, 0x18, 0xa1, 0x56, 0x54, 0xb2, 0x6b, 0x36, 0x00, 0x5e, 0x60, 0xd0, 0xf4, 0x37, 0x64, 0x80, 0x8c, 0x28, 0x30, 0xe2, 0x7a, 0x34, 0x45, 0xb1, 0x3a, 0x91, 0x45, 0x4b, 0x3e, 0xd0, 0xe9, 0xb5, 0xba, 0x41, 0xa2, 0x85, 0xc9, 0x06, 0xb8, 0x48, 0x9d, 0x45, 0x6a, 0xae, 0x92, 0xec, 0x04, 0x07, 0x61, 0x68, 0x39, 0xeb, 0xeb, 0xe4, 0x45, 0x39, 0x56, 0xe0, 0xf9, 0xb9, 0x45, 0x20, 0xbd, 0xe3, 0x4b, 0xbe, 0x4d, 0xc2, 0x33, 0xe9, 0xf5, 0x24, 0xcf, 0x3b, 0x8e, 0x78, 0xd3, 0x9f, 0xf6, 0xeb, 0x75, 0xe7, 0x2e, 0x98, 0xdd, 0x37, 0x6d, 0x4a, 0x7b, 0x2b, 0xd6, 0x3b, 0x4a, 0x02,\n\t0x3e, 0x8f, 0xc5, 0xac, 0x6b, 0xd0, 0x37, 0x84, 0x4a, 0x8c, 0xd8, 0x5a, 0x8f, 0x44, 0x57, 0x23, 0x06, 0x4b, 0x35, 0xc5, 0x79, 0x6e, 0x62, 0xb9, 0xe1, 0x05, 0x89, 0xde, 0xd1, 0xd0, 0x0e, 0x61, 0x9e, 0x15, 0xb9, 0xa8, 0x9a, 0xbe, 0x60, 0x85, 0x85, 0xfb, 0xa5, 0xbe, 0xd0, 0xbb, 0xe7, 0xb3, 0x5f, 0xeb, 0x8b, 0x1c, 0xb7, 0xc0, 0x7b, 0xf5, 0xda, 0xd6, 0xe4, 0xf6, 0x85, 0xb3, 0xb7, 0x2f, 0xaa, 0xae, 0x5b, 0xb6, 0x63, 0xd6, 0xac, 0x2b, 0xe3, 0x35, 0xbc, 0xd1, 0x60, 0xf0, 0x84, 0xeb, 0xe3, 0x15, 0x33, 0x1a, 0x8a, 0x83, 0x4d, 0x33, 0xca, 0xbd, 0xf1, 0x70, 0x71, 0x81, 0x60, 0xe0, 0x0c, 0xf5, 0x03, 0xbb, 0xe6, 0xcc, 0xd9, 0x35, 0x50, 0xaf, 0x7c, 0xde, 0x51, 0xdc, 0x34, 0x3b, 0x95, 0x9a, 0xdd, 0x54, 0xbc, 0x79, 0xf5, 0xea, 0xcd, 0xfc, 0x15, 0x46, 0xdb, 0xa7, 0xdb, 0x4d, 0x16,\n\t0x76, 0xbb, 0x76, 0x42, 0x53, 0x4b, 0xe3, 0xe0, 0xce, 0x59, 0xb3, 0x77, 0x0d, 0x36, 0xd4, 0x27, 0xa6, 0x8a, 0x3a, 0x8b, 0xc3, 0x12, 0x6c, 0x5f, 0xd4, 0xdc, 0xbc, 0xb0, 0x3d, 0xc8, 0x1b, 0x6c, 0x26, 0x5e, 0x18, 0xfe, 0x4d, 0xdf, 0x0d, 0x2b, 0x9b, 0x9a, 0x56, 0xde, 0xd0, 0xd7, 0xb7, 0x13, 0x7f, 0xee, 0xec, 0x6b, 0x5a, 0xd8, 0x51, 0x52, 0xd2, 0xb1, 0xb0, 0x69, 0xd3, 0xd5, 0x57, 0xa3, 0x01, 0x73, 0x2b, 0x78, 0x8d, 0x3d, 0xc4, 0x2d, 0x01, 0x05, 0x68, 0xce, 0x35, 0x68, 0xd1, 0x9c, 0x0b, 0x05, 0xd1, 0xe9, 0xe2, 0x8b, 0xa0, 0x1f, 0xc2, 0x3a, 0x48, 0x1c, 0x6b, 0x9f, 0x29, 0xab, 0xad, 0x2d, 0x83, 0x87, 0x1d, 0x96, 0xcf, 0x3f, 0x62, 0x51, 0x05, 0xcc, 0x49, 0x87, 0xc1, 0xe0, 0x78, 0x41, 0x5f, 0x68, 0xd9, 0x0d, 0x0f, 0xf4, 0xc1, 0x03, 0xbb, 0x2d, 0x85, 0x7a, 0x7a, 0x4f, 0xfb,\n\t0x36, 0x2a, 0xeb, 0x23, 0x54, 0x96, 0x09, 0x95, 0x65, 0x62, 0x70, 0x59, 0x0e, 0x58, 0x57, 0xdb, 0x10, 0xa9, 0x6f, 0x88, 0xc6, 0x22, 0xd1, 0x36, 0xc8, 0x7e, 0xf4, 0xf9, 0x47, 0x51, 0x78, 0xa4, 0xb4, 0xae, 0xae, 0x54, 0x9a, 0x13, 0x65, 0xfe, 0xb5, 0x4f, 0x3a, 0x7f, 0x77, 0xd8, 0xfe, 0x02, 0x29, 0xce, 0x1e, 0xa6, 0x77, 0x93, 0x68, 0x5f, 0x2b, 0x6c, 0x13, 0xdb, 0xd0, 0xbc, 0xf8, 0x06, 0xd9, 0x77, 0x7d, 0x13, 0xee, 0x24, 0xfb, 0x2e, 0x26, 0x6b, 0xdf, 0x9c, 0x8f, 0x73, 0x78, 0x5c, 0x9c, 0x90, 0x82, 0x03, 0x7f, 0x0e, 0xbf, 0x32, 0x36, 0x8e, 0xf0, 0xae, 0x5a, 0xce, 0x23, 0xf0, 0xc0, 0x68, 0x1c, 0x69, 0x1f, 0xc2, 0x89, 0x53, 0x1c, 0xe2, 0x67, 0x7e, 0x1b, 0xa1, 0xf3, 0xab, 0x23, 0xff, 0x25, 0x1c, 0xc1, 0x67, 0x00, 0xf0, 0x4d, 0x99, 0xce, 0xee, 0x51, 0xfb, 0xfb, 0x7c, 0x9c,\n\t0xc3, 0xe3, 0xe2, 0x84, 0x14, 0x1c, 0x44, 0x67, 0xff, 0xd8, 0x38, 0xc2, 0xbb, 0x6a, 0x39, 0x8f, 0xc0, 0xf9, 0xa3, 0x71, 0x10, 0x9d, 0x47, 0x84, 0x38, 0xc5, 0x21, 0x74, 0xf6, 0xab, 0x31, 0xf6, 0xdf, 0x24, 0xfa, 0xc1, 0x5b, 0xb2, 0x0e, 0xf6, 0xe0, 0x98, 0xf0, 0x07, 0x73, 0xe0, 0xa7, 0x15, 0x38, 0x7c, 0x2e, 0x2b, 0x56, 0xff, 0x9b, 0xf8, 0xcc, 0x48, 0xc6, 0x3f, 0xae, 0xe0, 0x4b, 0xfb, 0xb8, 0x37, 0xb9, 0x7d, 0x2a, 0xfe, 0xeb, 0x32, 0x7c, 0xeb, 0xc8, 0xbb, 0xbc, 0x9f, 0xff, 0x21, 0x82, 0xff, 0x96, 0xd0, 0x7c, 0x04, 0xec, 0x05, 0x45, 0x40, 0x83, 0x68, 0x3e, 0x56, 0xa4, 0xc4, 0x59, 0xcd, 0xc7, 0x79, 0x70, 0x5c, 0x9c, 0x5f, 0x2b, 0x38, 0x88, 0x9e, 0x9b, 0xc7, 0xc1, 0xf9, 0xa6, 0x5a, 0xce, 0xf1, 0xb1, 0xca, 0x91, 0xf6, 0xf1, 0x7e, 0x42, 0xe7, 0x6f, 0xa9, 0xdf, 0xfb, 0x15,\n\t0x64, 0xcc, 0x0e, 0x1f, 0x15, 0xaf, 0x65, 0x66, 0x6b, 0xdc, 0x67, 0x5a, 0x6f, 0x21, 0x5a, 0x26, 0x87, 0x8f, 0x72, 0xf7, 0x7e, 0xb6, 0x48, 0xe3, 0xde, 0x4f, 0xde, 0x11, 0x04, 0x66, 0xb6, 0x70, 0xc7, 0x17, 0x7b, 0x47, 0xb8, 0x63, 0xff, 0x7f, 0xb3, 0x1e, 0xd8, 0x25, 0x38, 0xe1, 0xf3, 0xe2, 0x8f, 0xe8, 0xba, 0x5e, 0x91, 0xbd, 0xae, 0xaf, 0x3d, 0xe3, 0xba, 0x0e, 0x91, 0xa6, 0x01, 0xbb, 0x76, 0xef, 0x16, 0x7f, 0x24, 0x75, 0x91, 0x72, 0xb8, 0x83, 0xf0, 0x79, 0x61, 0xe6, 0x19, 0xeb, 0x96, 0x5f, 0x11, 0x66, 0x4a, 0xc4, 0x4e, 0xf5, 0xcf, 0x54, 0x37, 0x03, 0x1e, 0x17, 0x9c, 0xcc, 0x6a, 0x52, 0x8e, 0x08, 0x6a, 0x69, 0x49, 0x46, 0x96, 0xac, 0x9d, 0x58, 0x7b, 0x26, 0x65, 0xd9, 0xb0, 0x9d, 0x24, 0x2a, 0x0c, 0x03, 0x48, 0x0a, 0x66, 0x5c, 0xdc, 0xa3, 0x38, 0xcc, 0x15, 0x36, 0x50,\n\t0xc5, 0x6a, 0x13, 0x2e, 0xf4, 0xf1, 0x9b, 0x6e, 0x82, 0xc1, 0x9b, 0x6e, 0xc2, 0xe5, 0xc2, 0x47, 0xe5, 0xb2, 0xb9, 0x83, 0xcc, 0x6a, 0xd2, 0x2e, 0x11, 0xf8, 0xd3, 0xde, 0x31, 0x8a, 0x19, 0xa7, 0x10, 0xdc, 0x4a, 0x52, 0xc8, 0xdf, 0x3c, 0x7d, 0x23, 0xcf, 0x73, 0xbb, 0x99, 0x0b, 0xd1, 0x1e, 0x4a, 0x0b, 0x1c, 0x20, 0xa2, 0xc4, 0xeb, 0xe6, 0x59, 0x8e, 0x05, 0xe0, 0x7c, 0xd8, 0xa3, 0xd3, 0x41, 0xa0, 0x73, 0xe8, 0x1c, 0xd6, 0x02, 0x81, 0x03, 0x5a, 0xa8, 0xa5, 0xfe, 0x24, 0xd4, 0x6f, 0x28, 0xc6, 0x86, 0xd0, 0x7a, 0x24, 0x7f, 0x85, 0xb7, 0x87, 0x42, 0xc6, 0xeb, 0x67, 0xb9, 0x8a, 0x8c, 0x3f, 0x78, 0xc4, 0xe2, 0xb1, 0x9a, 0x35, 0xc7, 0x17, 0xbb, 0xfc, 0xa6, 0x0f, 0xf9, 0x23, 0x2e, 0xd7, 0x7b, 0x46, 0x0b, 0x64, 0x04, 0x83, 0x45, 0x4f, 0xbe, 0x60, 0x9f, 0xac, 0xfb, 0x04, 0x1d,\n\t0xb3, 0x47, 0xf4, 0xa1, 0x3a, 0x6d, 0xd8, 0xa7, 0x86, 0x67, 0x50, 0x6d, 0x58, 0xc9, 0x20, 0x5f, 0xb0, 0x0d, 0x33, 0xa6, 0xbd, 0x57, 0x8f, 0xea, 0x2e, 0x30, 0xe9, 0x6c, 0x7a, 0xdb, 0xe8, 0xba, 0x2b, 0x61, 0x48, 0xfd, 0x06, 0xef, 0x0e, 0x25, 0x4c, 0xb7, 0x2e, 0x71, 0xf9, 0x0a, 0x7e, 0xf2, 0x66, 0x28, 0x69, 0x79, 0x7c, 0xad, 0x2b, 0x68, 0xf9, 0x4c, 0xf4, 0xb9, 0x5c, 0xbf, 0x29, 0x30, 0xbd, 0xef, 0x76, 0xfe, 0xc6, 0x6c, 0x7e, 0x1f, 0xf1, 0x6a, 0x2a, 0x6a, 0xe7, 0xbf, 0x0b, 0xb7, 0x90, 0xd3, 0x4c, 0xec, 0xc7, 0xa3, 0x1c, 0xea, 0x30, 0x38, 0x82, 0x2a, 0xd2, 0x13, 0x21, 0xb1, 0xac, 0x47, 0xfa, 0x72, 0xb8, 0xd0, 0x6b, 0x29, 0x30, 0xe8, 0x04, 0x1e, 0x38, 0xa0, 0x43, 0x54, 0x02, 0xd3, 0xa5, 0xe4, 0x15, 0x19, 0x7d, 0x31, 0x31, 0xa3, 0xb2, 0x90, 0xde, 0xbc, 0xf0, 0xca, 0x99,\n\t0xa1, 0x5d, 0x8e, 0x8a, 0xe9, 0xa9, 0xd4, 0xf4, 0x0a, 0xc7, 0xae, 0xd0, 0xcc, 0x2b, 0x63, 0xf6, 0x50, 0x12, 0x69, 0x3d, 0x41, 0xbb, 0x3d, 0x88, 0xb4, 0x9f, 0x64, 0xc8, 0xce, 0xed, 0x4e, 0x74, 0xaf, 0x68, 0x0c, 0xd4, 0xc7, 0x1c, 0x8e, 0x58, 0x7d, 0xa0, 0x71, 0x45, 0x77, 0x02, 0xde, 0xe0, 0x29, 0x2f, 0xb1, 0xdb, 0x4b, 0xd0, 0xf3, 0x0a, 0xfc, 0x59, 0x41, 0xef, 0xda, 0x90, 0xfe, 0xf1, 0x9c, 0x86, 0x41, 0x9c, 0x21, 0xd6, 0xc9, 0x3c, 0x76, 0xed, 0x40, 0x3b, 0x57, 0x92, 0x78, 0x07, 0xa9, 0x3d, 0x03, 0x88, 0x6c, 0x86, 0x9b, 0x4f, 0x7c, 0x6a, 0x04, 0xec, 0xfd, 0xd1, 0xeb, 0xb0, 0x07, 0x03, 0x45, 0x85, 0x5e, 0x8f, 0x3d, 0xe2, 0x88, 0x94, 0x86, 0x45, 0x2c, 0x22, 0x79, 0xe4, 0xb1, 0xb4, 0x01, 0x24, 0xad, 0x0e, 0x26, 0x9f, 0xb1, 0xe6, 0x13, 0x77, 0xcd, 0xc2, 0xcb, 0x7b, 0x82,\n\t0x5b, 0x97, 0xac, 0x5e, 0xbd, 0x64, 0x6b, 0xb0, 0xe7, 0x72, 0xf1, 0x3a, 0x4f, 0x12, 0x3f, 0x43, 0x38, 0x15, 0xf8, 0xb3, 0x42, 0x5a, 0x55, 0x36, 0x6d, 0x59, 0x63, 0x67, 0x4f, 0x4f, 0x67, 0xe3, 0xb2, 0x69, 0x65, 0x74, 0x2d, 0xbe, 0x44, 0xf0, 0x30, 0x0f, 0x88, 0x65, 0x88, 0x9f, 0xf1, 0x74, 0x0c, 0x67, 0x7a, 0x84, 0x17, 0x72, 0x38, 0x4e, 0x07, 0x98, 0xcf, 0x11, 0x3b, 0x7c, 0xd4, 0x14, 0xa6, 0x17, 0x6d, 0xb5, 0x54, 0x56, 0xf2, 0x8a, 0x2b, 0x52, 0x48, 0xd1, 0x60, 0xf0, 0x35, 0x1f, 0xbc, 0xb9, 0xf7, 0xfc, 0x09, 0xfe, 0x5d, 0xc6, 0x60, 0x43, 0x3c, 0xde, 0x10, 0x34, 0xee, 0xf2, 0x4f, 0x38, 0x5f, 0x2c, 0x4b, 0x74, 0x0f, 0x34, 0x28, 0x9c, 0x6a, 0x18, 0xe8, 0x26, 0x7b, 0xb7, 0x4b, 0xb8, 0x3b, 0x99, 0x07, 0xf8, 0xc3, 0xa8, 0xbe, 0x70, 0x3a, 0x48, 0xeb, 0x23, 0x3e, 0x8c, 0xc4,\n\t0xfb, 0x06, 0x5b, 0x68, 0xff, 0x37, 0x6a, 0xe2, 0x0f, 0x8f, 0xae, 0xe9, 0x7f, 0x79, 0xdb, 0x60, 0x98, 0x7f, 0x96, 0xb1, 0x89, 0x7b, 0x80, 0x07, 0xd4, 0x1c, 0xf7, 0x40, 0x30, 0x95, 0xaa, 0xdd, 0x7a, 0x59, 0xbf, 0x87, 0x6b, 0x01, 0x99, 0x7c, 0x55, 0x77, 0xc7, 0x85, 0x98, 0xbe, 0xde, 0xfe, 0x47, 0xc2, 0x5d, 0x64, 0xf2, 0x25, 0xb9, 0x98, 0xda, 0xd9, 0x06, 0xa1, 0x84, 0xe6, 0x65, 0xc2, 0xe6, 0xe4, 0x58, 0x85, 0x9b, 0x65, 0xd0, 0xf0, 0x1a, 0xb7, 0xc7, 0x85, 0xfe, 0xe5, 0x6b, 0xd3, 0xe9, 0xfa, 0xd6, 0xb6, 0xf9, 0x7d, 0xfc, 0x6f, 0xf5, 0x26, 0xde, 0x28, 0x68, 0x7d, 0xe1, 0x84, 0x07, 0x4e, 0xaa, 0xab, 0xec, 0x9c, 0x33, 0xa1, 0xf7, 0xb6, 0x89, 0x84, 0x06, 0x6e, 0x16, 0x63, 0x13, 0x0a, 0x10, 0x0d, 0x85, 0x69, 0x0f, 0x26, 0x22, 0xbf, 0xbe, 0xff, 0x46, 0x6d, 0xdc, 0xf9, 0xda,\n\t0x82, 0xb1, 0x6a, 0xfb, 0xab, 0xd4, 0xf7, 0x7f, 0x90, 0xc7, 0x26, 0xfe, 0x59, 0x38, 0x8c, 0xda, 0xec, 0xc3, 0xeb, 0xb9, 0x5b, 0x59, 0xcf, 0x17, 0xe6, 0xae, 0xe7, 0x59, 0xdb, 0xc8, 0xfe, 0x47, 0xa6, 0x44, 0x08, 0x01, 0xc4, 0x7f, 0x9a, 0xd4, 0x8a, 0x66, 0xad, 0x38, 0x8c, 0x15, 0xb1, 0x2e, 0x7c, 0x2c, 0x2b, 0xc2, 0x47, 0xfa, 0xe6, 0xb5, 0xb5, 0xd6, 0x75, 0x5a, 0x8a, 0x13, 0x1e, 0x5e, 0xcb, 0x8b, 0x6e, 0xaf, 0x5b, 0xc3, 0x8b, 0x7a, 0xfe, 0xd9, 0x89, 0xb7, 0xf5, 0x4e, 0x98, 0xd3, 0x59, 0xe9, 0x4d, 0x06, 0xac, 0xd0, 0x93, 0x08, 0xfb, 0xb4, 0x82, 0x91, 0xc7, 0x11, 0x56, 0x10, 0x0d, 0xdc, 0x2c, 0x38, 0x8c, 0xda, 0xec, 0xc3, 0xab, 0xa1, 0x6d, 0x8c, 0x36, 0x7b, 0xdd, 0x93, 0x18, 0x7c, 0x0e, 0x95, 0x5b, 0x95, 0x59, 0xa5, 0x01, 0x0e, 0xab, 0xb5, 0x79, 0x3c, 0xb8, 0xb6, 0x42,\n\t0x4a, 0x03, 0x7f, 0x77, 0x4e, 0x6d, 0x66, 0x9d, 0x97, 0x12, 0xf1, 0xb7, 0xd1, 0x6e, 0x70, 0x50, 0xd2, 0x30, 0x9b, 0x46, 0x7e, 0x84, 0xb4, 0x80, 0x92, 0x74, 0x31, 0x87, 0x56, 0x0b, 0xa4, 0x11, 0x2c, 0x26, 0x21, 0x25, 0xe8, 0xf9, 0x10, 0x51, 0xa8, 0x45, 0xa4, 0x0b, 0xe0, 0x93, 0x5b, 0xde, 0x12, 0xaa, 0x0b, 0xa2, 0xbf, 0xcc, 0xa6, 0x1b, 0xa5, 0x87, 0x60, 0x6f, 0xad, 0xd4, 0x7a, 0xcf, 0xd6, 0x7b, 0xe8, 0xbc, 0x97, 0x29, 0x07, 0x8d, 0x19, 0x7c, 0x9b, 0xc4, 0xc0, 0xc5, 0xd8, 0xc5, 0xb1, 0x9f, 0xda, 0xbd, 0x2a, 0xca, 0x04, 0xd2, 0x23, 0x43, 0x96, 0x94, 0x23, 0xc8, 0x6c, 0x92, 0x1e, 0xba, 0xf1, 0x46, 0xd8, 0x2b, 0x1d, 0xbe, 0x07, 0x9e, 0xbe, 0x07, 0xbf, 0x2f, 0x70, 0xcc, 0x26, 0xf1, 0x07, 0x68, 0x6d, 0xf5, 0xa4, 0x49, 0xf0, 0x8b, 0x0b, 0x15, 0x1f, 0x9a, 0xb5, 0x38, 0x7d,\n\t0x31, 0x31, 0xec, 0x83, 0x21, 0x0b, 0xaa, 0x9d, 0x56, 0xfe, 0xa2, 0xc0, 0xc1, 0xc9, 0xdb, 0xe4, 0xba, 0xb9, 0xeb, 0x98, 0x4d, 0x42, 0x17, 0x7a, 0xb7, 0x28, 0xed, 0xa3, 0xef, 0x62, 0xe7, 0xd6, 0xb9, 0x72, 0x33, 0x18, 0xac, 0xcb, 0x8c, 0x2e, 0x80, 0xbb, 0x8e, 0x16, 0xf0, 0xd7, 0xad, 0xfb, 0x56, 0xc4, 0xb7, 0x2d, 0x84, 0x6f, 0xd8, 0xd7, 0x9e, 0x81, 0xcc, 0x26, 0x8e, 0x65, 0xa8, 0x53, 0x3b, 0x8b, 0x8f, 0x73, 0xce, 0xc5, 0x48, 0x33, 0x73, 0x7a, 0x01, 0x3a, 0x82, 0xc4, 0x46, 0x90, 0xd9, 0x22, 0x79, 0xbf, 0xb9, 0x5b, 0xba, 0x6e, 0xeb, 0x56, 0x38, 0x45, 0xfa, 0x4e, 0x4e, 0x1f, 0x04, 0xd2, 0x7e, 0x3c, 0x62, 0x2e, 0x04, 0xb8, 0x3f, 0xe7, 0x92, 0x7e, 0x60, 0xf0, 0xd9, 0x9f, 0xaa, 0xd4, 0xf1, 0x34, 0x40, 0x2b, 0xa2, 0xe7, 0xfe, 0xdd, 0xf7, 0xc3, 0x17, 0x8f, 0x4b, 0xdf, 0x25,\n\t0x04, 0x65, 0xca, 0xd0, 0x93, 0x32, 0x38, 0x1c, 0x21, 0x69, 0x31, 0x71, 0xa8, 0x26, 0x3a, 0x27, 0xed, 0x49, 0x35, 0x95, 0x34, 0xcd, 0x7c, 0x55, 0x97, 0x72, 0xa4, 0x48, 0x39, 0xe8, 0x3f, 0xd4, 0x9f, 0x68, 0x48, 0xa8, 0x63, 0xe2, 0x30, 0x2a, 0xab, 0x4c, 0x39, 0x73, 0x04, 0xca, 0x98, 0xa2, 0xda, 0xb8, 0x0b, 0x6d, 0x29, 0x0e, 0xc2, 0x17, 0xa5, 0xe8, 0x2f, 0xb6, 0x22, 0xdc, 0xf5, 0xd2, 0x0d, 0x4c, 0xe7, 0xc8, 0xdb, 0xc0, 0x89, 0xcf, 0xb1, 0x74, 0xf8, 0x56, 0x9f, 0xa8, 0xa9, 0x9b, 0xb2, 0x12, 0xa4, 0xc7, 0x23, 0x84, 0x91, 0x7c, 0x6a, 0x54, 0x9e, 0x8f, 0xfa, 0x3a, 0x78, 0x74, 0x5f, 0x51, 0xeb, 0xa2, 0xb6, 0xee, 0x8b, 0x82, 0x8b, 0x74, 0x26, 0x4e, 0x67, 0x76, 0x04, 0x7c, 0xe5, 0x29, 0xfb, 0xda, 0xea, 0x85, 0x93, 0xe3, 0x3d, 0x73, 0xc3, 0x1c, 0x74, 0x78, 0x1d, 0xed, 0x0d,\n\t0x98, 0xa6, 0x67, 0x50, 0x3d, 0xff, 0x40, 0xea, 0x41, 0x1a, 0xab, 0x81, 0xfa, 0xbe, 0xb1, 0x90, 0xdd, 0x84, 0xd9, 0xb5, 0x09, 0xd0, 0x15, 0x9a, 0x19, 0x62, 0x7a, 0x1c, 0xe1, 0x54, 0x09, 0x61, 0x54, 0x5e, 0xac, 0x5a, 0x7c, 0xbb, 0x93, 0x82, 0x8b, 0x6b, 0x13, 0xbe, 0x80, 0xa3, 0x40, 0xc7, 0x19, 0x75, 0x8b, 0x83, 0x17, 0x77, 0xb7, 0x2f, 0x6c, 0xf5, 0xdf, 0x7a, 0x65, 0x43, 0x3b, 0xaa, 0x05, 0x72, 0xe1, 0xb9, 0x3d, 0xf1, 0xc9, 0x0b, 0xab, 0xd7, 0xd2, 0xb3, 0xee, 0x93, 0x52, 0x35, 0xb3, 0x64, 0xe4, 0x28, 0xc9, 0x4f, 0xd9, 0x41, 0xad, 0xf9, 0x6c, 0x8a, 0xb7, 0xbd, 0xd2, 0xb6, 0xf3, 0x20, 0x49, 0x71, 0xaf, 0x42, 0xb1, 0x63, 0x36, 0x50, 0xfd, 0xb2, 0xfb, 0x1f, 0x0d, 0x47, 0x4b, 0xc3, 0x44, 0x13, 0xcf, 0x3b, 0x38, 0x6b, 0xc8, 0x4a, 0x77, 0x78, 0x32, 0xd8, 0xd8, 0x55, 0x16,\n\t0xef, 0x6e, 0x2a, 0x29, 0x69, 0xea, 0x8e, 0x97, 0x75, 0x35, 0x06, 0xd7, 0xd5, 0x56, 0x26, 0xea, 0xeb, 0x13, 0x95, 0xb5, 0xd2, 0xef, 0x13, 0x53, 0x6b, 0x0a, 0x0b, 0x6b, 0xa6, 0x26, 0xe2, 0x53, 0xaa, 0x0b, 0x0b, 0xab, 0xa7, 0xa0, 0x75, 0xbe, 0x21, 0x9e, 0xac, 0xab, 0xa3, 0x7b, 0x29, 0xa9, 0x0e, 0x3e, 0x3f, 0xf2, 0x3b, 0xba, 0x97, 0x2a, 0x52, 0x96, 0x9a, 0x7e, 0x85, 0xaa, 0x71, 0xf7, 0x52, 0xbc, 0xbc, 0x97, 0x72, 0xd0, 0x3d, 0x19, 0xa8, 0x91, 0x8e, 0x30, 0x2f, 0x8c, 0x7c, 0x1b, 0x8d, 0x3d, 0x2c, 0x43, 0x48, 0x27, 0xc7, 0xb7, 0xfd, 0x99, 0x21, 0x23, 0x3b, 0x54, 0xd6, 0x61, 0xf1, 0x0f, 0x32, 0x2f, 0xec, 0x90, 0x06, 0x77, 0x30, 0xf7, 0x49, 0x47, 0x6e, 0xbf, 0x1d, 0x1a, 0xc0, 0x9f, 0xe9, 0xfd, 0x67, 0xc9, 0xfb, 0x01, 0x70, 0xe1, 0x09, 0x11, 0xbf, 0x2c, 0x1f, 0x0a, 0x3a,\n\t0x45, 0x01, 0x09, 0x12, 0xcb, 0x32, 0xab, 0xc8, 0x28, 0x5e, 0x04, 0x69, 0x91, 0xbe, 0xee, 0x63, 0x85, 0x38, 0x85, 0x32, 0x7d, 0xca, 0x6c, 0xca, 0x7d, 0x98, 0xf6, 0x65, 0xc1, 0x51, 0xb7, 0xcc, 0x57, 0x1f, 0xb3, 0xa0, 0x4f, 0x36, 0xa2, 0x0c, 0x80, 0x40, 0xc8, 0x16, 0xb2, 0x85, 0x89, 0x11, 0x25, 0x4f, 0x8c, 0x28, 0xa3, 0xd4, 0x86, 0xb2, 0x0d, 0xe7, 0x8f, 0x77, 0xa2, 0xc1, 0x49, 0xbf, 0xb8, 0x9c, 0xf5, 0x6d, 0x90, 0x79, 0x61, 0xed, 0x9c, 0xea, 0x1e, 0x8f, 0xa7, 0xa7, 0x7a, 0xce, 0xda, 0x1b, 0x83, 0x25, 0xc5, 0x81, 0xdd, 0x81, 0xe2, 0x92, 0xe0, 0x34, 0xe7, 0xba, 0xd5, 0xe1, 0x60, 0x30, 0xbc, 0x7a, 0x9d, 0xd3, 0x59, 0x96, 0x84, 0x30, 0x19, 0x73, 0x3a, 0x63, 0xf8, 0xb3, 0xcc, 0x49, 0xdb, 0x74, 0xb7, 0xcc, 0x13, 0x34, 0x72, 0x4c, 0x78, 0xe4, 0xe0, 0x39, 0x01, 0x0d, 0x8c,\n\t0x55, 0x58, 0xc5, 0x3b, 0x17, 0xc8, 0xc4, 0x5a, 0x09, 0x14, 0x6e, 0xca, 0x02, 0xf6, 0xa7, 0x0d, 0x79, 0x13, 0x77, 0x10, 0xcf, 0xba, 0x75, 0xcc, 0x0b, 0xc3, 0xe7, 0xee, 0x80, 0x87, 0xa6, 0x49, 0x6f, 0x41, 0xf7, 0x7d, 0xf7, 0xe1, 0xf1, 0xa9, 0xcc, 0x3f, 0x2c, 0x5d, 0x01, 0xf0, 0x84, 0x41, 0x72, 0xc7, 0xe3, 0x6a, 0xe6, 0xca, 0xd3, 0x20, 0x64, 0xb2, 0xe6, 0x0d, 0x47, 0x0a, 0xed, 0x91, 0x82, 0xf0, 0x93, 0xb7, 0xde, 0xda, 0x26, 0x79, 0xe1, 0x1b, 0xdf, 0x7c, 0x6e, 0x0b, 0x3c, 0x8d, 0x68, 0xad, 0x97, 0x7e, 0xcc, 0xfc, 0x7c, 0xe4, 0x51, 0xe0, 0x06, 0xfd, 0x69, 0xa3, 0x0b, 0x71, 0xca, 0x6a, 0xc1, 0x57, 0xe0, 0x24, 0x98, 0x1b, 0xe6, 0xb4, 0x85, 0xe3, 0x19, 0x39, 0xab, 0xfb, 0x80, 0x62, 0xb0, 0xea, 0xc5, 0x45, 0x5f, 0x88, 0x1f, 0xe0, 0x75, 0x0e, 0x7f, 0xaa, 0x1b, 0xb8, 0xfe,\n\t0xb4, 0x05, 0x02, 0xa7, 0xbd, 0xc0, 0xa4, 0xd7, 0x89, 0x3c, 0x70, 0x43, 0x37, 0xde, 0xc1, 0xf1, 0xf8, 0xa4, 0x33, 0x1a, 0x32, 0x41, 0x3f, 0x1a, 0x09, 0xb5, 0xd1, 0x58, 0x09, 0x75, 0xeb, 0x77, 0xd5, 0x33, 0xbe, 0x69, 0x03, 0xa6, 0x1b, 0x84, 0x56, 0xc2, 0xd6, 0x56, 0xe1, 0x06, 0xd3, 0xc0, 0xb4, 0x81, 0x54, 0xaa, 0xab, 0x67, 0x56, 0x78, 0x12, 0xac, 0xc0, 0x3c, 0xad, 0x80, 0x93, 0xc2, 0xb3, 0x7a, 0x26, 0x4f, 0xa6, 0x63, 0xe5, 0x6e, 0xfe, 0x43, 0xe6, 0x3c, 0xf1, 0xfb, 0x68, 0x8e, 0x13, 0x8e, 0x6b, 0xc8, 0x59, 0xa0, 0x4b, 0x8c, 0x89, 0x31, 0x9c, 0x07, 0xad, 0xc1, 0x05, 0xff, 0xed, 0x40, 0xdf, 0x01, 0xe5, 0x3f, 0xe1, 0x45, 0xfa, 0x6d, 0xff, 0xac, 0x03, 0x07, 0x66, 0xd1, 0x77, 0xb9, 0x4b, 0x98, 0xf3, 0x84, 0xce, 0x2f, 0xf0, 0x2e, 0xbf, 0x68, 0xd4, 0xbb, 0x7f, 0x9d, 0x7a,\n\t0x61, 0x90, 0xdb, 0xc1, 0x70, 0xc2, 0x2f, 0x91, 0x9e, 0x81, 0x7b, 0x98, 0x74, 0x30, 0xea, 0x04, 0x96, 0x61, 0xd8, 0xf9, 0x68, 0x69, 0xc0, 0x33, 0x1e, 0xcb, 0xf4, 0x5a, 0x7c, 0x16, 0x0f, 0x11, 0xb2, 0x5a, 0x79, 0xf7, 0xe7, 0xa0, 0xd6, 0x92, 0x64, 0xb2, 0xa9, 0x6b, 0x87, 0xf0, 0xf2, 0xc2, 0x92, 0xc2, 0x60, 0xf3, 0xec, 0x9a, 0x44, 0xbc, 0x30, 0x88, 0xc3, 0x8f, 0x55, 0x97, 0x97, 0xf2, 0x93, 0x9d, 0x95, 0xf5, 0x6d, 0xe1, 0xd2, 0xc9, 0xd5, 0x85, 0x97, 0xc1, 0x48, 0xd0, 0x59, 0x55, 0xdf, 0x1e, 0x2a, 0x9b, 0x54, 0xe5, 0xbb, 0x04, 0x5f, 0x1c, 0xa2, 0x7a, 0xf9, 0xdf, 0x33, 0x9c, 0xa6, 0xe0, 0xcf, 0x5f, 0xaf, 0x70, 0xaf, 0x33, 0x12, 0x4f, 0x85, 0x4b, 0x27, 0x24, 0x3d, 0x97, 0x41, 0x5f, 0xd0, 0x19, 0x8d, 0xd7, 0x86, 0xca, 0x3a, 0x93, 0xae, 0x4b, 0x20, 0x59, 0x82, 0xa7, 0xf1,\n\t0x0f, 0x31, 0x2f, 0x89, 0xdb, 0x41, 0x09, 0x98, 0x90, 0xee, 0xf0, 0x7b, 0x19, 0x8e, 0xd5, 0x6b, 0xb0, 0x46, 0xd2, 0x55, 0xe8, 0x63, 0xd8, 0x69, 0x38, 0x8e, 0xcb, 0x54, 0xbc, 0x1f, 0xe6, 0xe6, 0xe3, 0xbb, 0x52, 0x32, 0xd3, 0x0c, 0x10, 0xd3, 0x6a, 0x34, 0xdd, 0x70, 0x00, 0xc7, 0x56, 0x2f, 0x01, 0x25, 0xd1, 0xb0, 0x35, 0x16, 0x26, 0x57, 0xa6, 0x4a, 0x80, 0x3c, 0x9c, 0x2b, 0x06, 0xfb, 0xeb, 0x84, 0xe4, 0x33, 0xf7, 0x06, 0x97, 0x48, 0x0c, 0xa4, 0x99, 0x97, 0x7c, 0x55, 0x93, 0xca, 0x02, 0x13, 0x02, 0x03, 0x8b, 0x96, 0x5a, 0x83, 0xa6, 0x60, 0x04, 0x5e, 0xe8, 0xab, 0x99, 0x58, 0x16, 0x9a, 0x1c, 0x1c, 0x5c, 0xb4, 0x34, 0xe8, 0x2e, 0x89, 0x40, 0x51, 0x53, 0x33, 0xbb, 0x39, 0x60, 0x37, 0xdd, 0x99, 0xda, 0xaf, 0xd1, 0x56, 0x25, 0xaa, 0xcf, 0x69, 0x0e, 0xba, 0x4c, 0x77, 0xd6,\n\t0x1c, 0x30, 0x55, 0x94, 0x93, 0xbe, 0x9d, 0xc6, 0xa5, 0x98, 0x97, 0xd0, 0x1e, 0xad, 0x04, 0xc7, 0x34, 0x18, 0x8f, 0x5e, 0x42, 0x1c, 0x0e, 0x69, 0xc4, 0x2e, 0x24, 0x57, 0xbc, 0xd4, 0x97, 0xff, 0xcf, 0x4c, 0x29, 0xbf, 0xab, 0x66, 0x76, 0x4b, 0xc0, 0x91, 0x47, 0x69, 0x6a, 0x3f, 0xa6, 0xf4, 0xef, 0x8f, 0xaf, 0x7e, 0xc9, 0xc1, 0x75, 0x8e, 0x5c, 0x04, 0xcc, 0xa0, 0x29, 0xad, 0x33, 0x1b, 0x18, 0x38, 0x4d, 0xe4, 0x18, 0xbc, 0xa5, 0x2a, 0xcc, 0x3e, 0x33, 0x3c, 0x2f, 0xb3, 0xa5, 0x9a, 0x0b, 0x32, 0x71, 0x84, 0x1e, 0x71, 0x39, 0x88, 0xae, 0xed, 0xb4, 0x8b, 0x3c, 0x5a, 0x76, 0x22, 0xd1, 0xfa, 0x06, 0x7c, 0xd3, 0xc7, 0x85, 0x8a, 0x8a, 0xa4, 0x0f, 0xa5, 0x0a, 0xe9, 0x23, 0xec, 0x0e, 0xaf, 0x83, 0xff, 0x4f, 0x7a, 0xbb, 0x20, 0x65, 0xde, 0xb1, 0x72, 0xe5, 0x4e, 0xf4, 0x71, 0xed,\n\t0xea, 0xd5, 0x78, 0xdc, 0x5f, 0x35, 0xfc, 0x3a, 0xf3, 0xf2, 0xc8, 0xc3, 0x40, 0x0b, 0x26, 0xd2, 0xba, 0xcc, 0x00, 0x9f, 0x5d, 0x81, 0xc5, 0x44, 0xa5, 0x5b, 0x83, 0xd7, 0x55, 0x2f, 0x99, 0xb3, 0x71, 0xd0, 0xc0, 0x21, 0xfc, 0x0f, 0x59, 0xef, 0x71, 0xcd, 0x0c, 0x8e, 0x60, 0x84, 0xe7, 0x6e, 0x2d, 0xd0, 0x5a, 0x15, 0x75, 0x0f, 0x69, 0x59, 0xb6, 0x7a, 0xa7, 0xcb, 0xc6, 0x5c, 0x72, 0xeb, 0xca, 0x1b, 0x70, 0x35, 0xd2, 0x0d, 0xf7, 0xdc, 0x03, 0xf5, 0x88, 0x00, 0xe9, 0x43, 0x4c, 0xec, 0xc7, 0xfc, 0xc7, 0x4c, 0xb9, 0xf8, 0x34, 0xd2, 0x41, 0x85, 0xe3, 0x3c, 0xc4, 0x73, 0x03, 0x99, 0x18, 0x98, 0xf2, 0xd7, 0xfa, 0x0e, 0x1e, 0xec, 0x13, 0x7e, 0xf5, 0x5a, 0xdf, 0xfe, 0xfd, 0xb3, 0x30, 0x1e, 0x77, 0x19, 0x53, 0x2e, 0x4c, 0x1c, 0x07, 0x8f, 0x5f, 0xa2, 0xe2, 0x7d, 0xc1, 0xf2, 0xde,\n\t0x13, 0x0a, 0xe0, 0xf3, 0xe2, 0xe3, 0xc0, 0x42, 0x74, 0x7e, 0xb2, 0x75, 0x58, 0xaa, 0xe8, 0x34, 0x6b, 0x99, 0x1e, 0xbb, 0xc5, 0x4d, 0x97, 0x6d, 0xe5, 0x3c, 0xc9, 0x41, 0x43, 0x1d, 0xc2, 0xe7, 0x53, 0x73, 0x5a, 0x83, 0xc1, 0xd6, 0x39, 0xa9, 0x44, 0x63, 0x63, 0x42, 0x28, 0x28, 0x6a, 0xec, 0xad, 0xaa, 0x9a, 0xd9, 0x58, 0xb4, 0xba, 0xb1, 0xbe, 0x9e, 0xe8, 0x68, 0xef, 0x71, 0xb7, 0xc2, 0xe7, 0x85, 0x16, 0x54, 0x2e, 0x9e, 0x37, 0x70, 0xae, 0x28, 0xc8, 0x0c, 0x90, 0xf2, 0xe7, 0xcb, 0x71, 0x5f, 0x58, 0xd0, 0xfb, 0xc5, 0x4a, 0xe7, 0x6e, 0xcd, 0x2b, 0x1d, 0xfc, 0xc5, 0xe8, 0x66, 0x40, 0x27, 0xff, 0x1a, 0xf3, 0xb2, 0x78, 0x27, 0xd2, 0xf5, 0x62, 0x60, 0x31, 0x0d, 0xb2, 0x58, 0x98, 0x73, 0x08, 0x07, 0x51, 0x3d, 0xf2, 0xe9, 0x1b, 0xb3, 0x16, 0x5b, 0x2b, 0x95, 0xa8, 0x8f, 0x11,\n\t0x08, 0xc9, 0x0e, 0xc3, 0x0d, 0x90, 0x59, 0x32, 0x7b, 0x6f, 0x9f, 0xb6, 0x38, 0xec, 0xa1, 0x12, 0x72, 0x4c, 0x17, 0x73, 0xc4, 0xc6, 0x39, 0xa6, 0xa3, 0xc7, 0x3a, 0x51, 0xf5, 0x54, 0x87, 0xd1, 0xd8, 0x82, 0xe5, 0x1e, 0x77, 0x22, 0x68, 0xb3, 0x05, 0x13, 0x6e, 0x4f, 0x79, 0xd0, 0xb6, 0xe5, 0xdc, 0xad, 0xb3, 0x22, 0xdb, 0x56, 0x9e, 0x5f, 0xd7, 0x9b, 0xf2, 0x6c, 0x8d, 0xcc, 0xda, 0x26, 0x2c, 0x74, 0x97, 0x07, 0x6c, 0xb6, 0x40, 0xb9, 0xdb, 0x43, 0xb1, 0x60, 0x2c, 0x39, 0x6b, 0xc3, 0x84, 0x85, 0x1b, 0xfc, 0x75, 0xdd, 0xc9, 0x09, 0x1b, 0x66, 0x25, 0xa9, 0xfe, 0xda, 0xc9, 0xad, 0x64, 0x5e, 0x16, 0xfc, 0xa4, 0x4d, 0xd9, 0x67, 0x8a, 0xe3, 0xd2, 0xfb, 0x17, 0x21, 0x96, 0x7b, 0xc9, 0x5d, 0x8e, 0x9f, 0xe6, 0x13, 0xbb, 0xde, 0x5f, 0xab, 0x12, 0xfb, 0xbf, 0x91, 0xff, 0x10, 0xbc,\n\t0x3c, 0xfc, 0x47, 0xc6, 0x3a, 0xf2, 0x14, 0x91, 0x45, 0x4e, 0x59, 0xf7, 0xd1, 0x8a, 0x7f, 0xd9, 0xc1, 0xbe, 0xd7, 0x5e, 0xeb, 0x93, 0x7e, 0xb9, 0xbf, 0xef, 0xb5, 0xd7, 0xfb, 0x10, 0xb5, 0xba, 0xe1, 0x8f, 0x98, 0xf6, 0x91, 0xef, 0x8f, 0x92, 0xd9, 0x76, 0x22, 0xb3, 0xd2, 0x2f, 0x5f, 0x9f, 0xb5, 0x7f, 0x7f, 0x1f, 0xe2, 0x91, 0x6d, 0xf8, 0x23, 0x36, 0x40, 0xf0, 0xf4, 0x40, 0x73, 0x42, 0x87, 0x8d, 0xb5, 0xaa, 0x12, 0xc5, 0x04, 0x19, 0xe2, 0xb9, 0xd8, 0x35, 0xf0, 0x1a, 0x7e, 0x83, 0xf9, 0x1e, 0x42, 0x7f, 0xed, 0xb5, 0xce, 0xd7, 0xb1, 0xac, 0x4b, 0x3f, 0xbd, 0xfd, 0xf6, 0x59, 0xaf, 0xbd, 0x26, 0xdf, 0xbd, 0x84, 0x99, 0x0a, 0xf1, 0xc7, 0x48, 0x76, 0xda, 0x69, 0x3a, 0x4d, 0x2b, 0x35, 0x31, 0x58, 0xaa, 0xb8, 0x6b, 0xac, 0xa5, 0x9b, 0x19, 0xc5, 0x2c, 0x1b, 0x0b, 0xec, 0x7c,\n\t0x39, 0x09, 0x2d, 0x60, 0xd1, 0x66, 0xc6, 0x6d, 0xb1, 0x53, 0xe9, 0xa2, 0x3b, 0x97, 0x3a, 0x65, 0x3f, 0x03, 0xbb, 0xb0, 0x54, 0x29, 0x12, 0x26, 0xdc, 0xd8, 0x50, 0x5f, 0xdf, 0xb8, 0xba, 0xa8, 0x71, 0x66, 0x55, 0x55, 0x6f, 0x63, 0x11, 0xe5, 0xc5, 0x16, 0xee, 0x3e, 0xb8, 0x48, 0xe8, 0x95, 0xe7, 0x85, 0x71, 0x6a, 0x50, 0xca, 0xb7, 0xe5, 0x95, 0xbf, 0x25, 0xd1, 0xd4, 0xa4, 0x16, 0xcf, 0x1b, 0x73, 0x8b, 0xc7, 0xf7, 0x50, 0xf7, 0x31, 0x15, 0x5f, 0xb4, 0xec, 0x33, 0xd3, 0x9e, 0x5f, 0xf8, 0x5f, 0x9d, 0x6f, 0xe7, 0x49, 0x1b, 0xe1, 0xbf, 0x8d, 0xbc, 0x03, 0x2a, 0xc1, 0xc4, 0xb4, 0xad, 0xb2, 0x22, 0x51, 0x1a, 0x0a, 0x14, 0xbb, 0x5d, 0xb6, 0x02, 0xbd, 0x28, 0x98, 0x68, 0x48, 0xbb, 0xf0, 0x17, 0x58, 0x10, 0x4f, 0xc4, 0xa2, 0x45, 0xf8, 0x04, 0x8c, 0xa7, 0xd1, 0xdf, 0x44, 0xa4,\n\t0x54, 0xc7, 0x9c, 0x44, 0x13, 0xc7, 0xb6, 0x7c, 0x66, 0x88, 0xb7, 0xe3, 0x0d, 0xd1, 0x4a, 0x6c, 0x13, 0xe5, 0xa2, 0x7b, 0x20, 0x41, 0xac, 0xef, 0x80, 0x2e, 0x78, 0x83, 0xd1, 0x6b, 0xf2, 0xbb, 0x67, 0x84, 0x66, 0x14, 0xb8, 0xb4, 0xa6, 0x69, 0xbc, 0xa8, 0x75, 0x9a, 0xd0, 0x0f, 0xb3, 0xcf, 0x5c, 0xe4, 0x9b, 0x1e, 0x9a, 0xee, 0xb7, 0x62, 0x98, 0xb5, 0x70, 0x46, 0xe8, 0x49, 0x8d, 0x8e, 0x61, 0x2d, 0xe5, 0x6d, 0xe5, 0x5a, 0xbb, 0xa9, 0xb0, 0xa4, 0x7f, 0x81, 0xa5, 0xd0, 0x68, 0xb0, 0x6a, 0x92, 0xed, 0xe5, 0x04, 0x9e, 0x68, 0x8b, 0x17, 0xf8, 0x0a, 0x4b, 0xce, 0xed, 0xb7, 0xf8, 0x4d, 0xee, 0x82, 0xf2, 0x56, 0xc4, 0x96, 0xaf, 0x4b, 0x7b, 0x18, 0x69, 0xe4, 0x39, 0x34, 0x92, 0x5d, 0xa0, 0x01, 0x4c, 0x49, 0x4f, 0xac, 0x83, 0x90, 0x43, 0x4a, 0x0c, 0x60, 0xba, 0x44, 0x1d, 0x4e,\n\t0xaf, 0x81, 0x0d, 0xe2, 0x06, 0xb4, 0x8c, 0x86, 0xc5, 0x86, 0xcc, 0x38, 0x9a, 0xfe, 0x10, 0xb6, 0x64, 0x36, 0xa2, 0x6d, 0x7f, 0xaa, 0xba, 0x2c, 0x16, 0x0a, 0xba, 0x1b, 0x3c, 0x0d, 0x36, 0x8b, 0xc1, 0x65, 0x74, 0x8d, 0x1d, 0xcb, 0x31, 0x94, 0xf5, 0x3d, 0x92, 0x15, 0x3e, 0x2c, 0xd7, 0xf8, 0xa2, 0x1d, 0x32, 0x33, 0x8b, 0xc3, 0xe1, 0xe2, 0x40, 0x38, 0xfc, 0xab, 0x40, 0x28, 0x14, 0x40, 0x9f, 0x30, 0x1a, 0x6d, 0x4f, 0xb8, 0x5c, 0x89, 0xf6, 0x68, 0xd5, 0x24, 0x9b, 0x7d, 0x62, 0x55, 0xb4, 0xbd, 0xdc, 0xed, 0x2e, 0x47, 0xbf, 0x26, 0xda, 0x6d, 0x93, 0xa4, 0xdf, 0x87, 0xfd, 0xfe, 0x70, 0xf6, 0xff, 0xaf, 0x7b, 0xca, 0x5b, 0x4a, 0x4a, 0x5a, 0xcb, 0x3d, 0xb1, 0x40, 0x20, 0xe6, 0x29, 0x6f, 0x2d, 0x29, 0x69, 0x29, 0xf7, 0x44, 0x03, 0x81, 0x28, 0xed, 0xbf, 0x67, 0xf8, 0x1f, 0x31,\n\t0x97, 0x88, 0xc3, 0xc0, 0x08, 0xe6, 0xd0, 0x38, 0x9a, 0x45, 0x80, 0xec, 0x68, 0xc9, 0xde, 0x7c, 0x35, 0x0e, 0x61, 0x0d, 0xd9, 0xb9, 0x24, 0xda, 0xf7, 0xb9, 0x38, 0x9c, 0xd7, 0x4c, 0xec, 0x3c, 0x85, 0x37, 0xaf, 0xe4, 0x38, 0x6a, 0xf4, 0x63, 0xaa, 0x60, 0x18, 0x81, 0x31, 0x68, 0x0b, 0x12, 0x05, 0x03, 0xc7, 0xb2, 0xee, 0x80, 0x21, 0x1b, 0x6a, 0x8c, 0x19, 0x32, 0x97, 0x6c, 0x59, 0xe1, 0x30, 0x69, 0x26, 0x7e, 0x7a, 0xc9, 0x0a, 0xa7, 0x51, 0x9c, 0x28, 0x06, 0xa5, 0xc3, 0x6e, 0xdb, 0x43, 0x70, 0xae, 0xc7, 0xfa, 0x10, 0xa1, 0x85, 0x9b, 0xc9, 0x5c, 0x22, 0x6c, 0x43, 0xaf, 0x4f, 0xa3, 0xb4, 0xb8, 0xb3, 0x69, 0xc1, 0xea, 0x69, 0x3f, 0xae, 0x6a, 0x00, 0x8f, 0x66, 0x67, 0x86, 0x8a, 0xec, 0x07, 0x5f, 0xaa, 0x7e, 0xfe, 0x9e, 0xbc, 0xfa, 0xff, 0x86, 0x78, 0x31, 0x5b, 0xaa, 0xd1,\n\t0xb4, 0x8e, 0xac, 0x47, 0x32, 0xdd, 0xf1, 0xa8, 0xd1, 0x20, 0xf0, 0x1c, 0xe6, 0x09, 0xd6, 0xf7, 0x0c, 0x8c, 0x92, 0xe9, 0x8a, 0x1c, 0xa2, 0x58, 0xe9, 0xed, 0xea, 0x7c, 0x05, 0x4a, 0xf6, 0xb7, 0x7a, 0x08, 0x74, 0x1a, 0x60, 0x81, 0x16, 0x96, 0x0c, 0x3a, 0xec, 0xa3, 0x26, 0x70, 0xc1, 0x40, 0x38, 0xd6, 0x50, 0xc4, 0x72, 0x53, 0xf7, 0x0d, 0xbf, 0xf9, 0xe2, 0x50, 0xed, 0xb3, 0x92, 0x5e, 0x7a, 0x16, 0xfd, 0xd5, 0x3f, 0x9b, 0x1a, 0x7a, 0xf1, 0xcd, 0x61, 0xe9, 0xb4, 0x33, 0x91, 0x2e, 0xdb, 0x3e, 0x6f, 0x60, 0x60, 0xde, 0xf6, 0xb2, 0x74, 0xc2, 0x49, 0xe2, 0x15, 0x08, 0x26, 0x4d, 0xab, 0xd8, 0xc5, 0x8a, 0x4c, 0x0c, 0x6d, 0xf8, 0x7f, 0x45, 0xed, 0x04, 0xc5, 0x5f, 0xa9, 0x76, 0x82, 0xb3, 0xb9, 0x9b, 0x35, 0xad, 0xfc, 0x8f, 0x20, 0x79, 0x2e, 0x2c, 0xa1, 0xcf, 0x85, 0x25, 0x99,\n\t0xe7, 0xf4, 0x7d, 0x38, 0xde, 0xfb, 0x6b, 0x84, 0xb9, 0x9a, 0xa8, 0xf0, 0x16, 0x2a, 0x3f, 0x3e, 0xf6, 0x73, 0xee, 0x17, 0x9a, 0x28, 0x7f, 0x1e, 0x24, 0xcf, 0xc7, 0x28, 0x5f, 0x7e, 0x1f, 0x8e, 0xf9, 0x3e, 0x62, 0xc5, 0x1a, 0xe9, 0x52, 0x4d, 0x74, 0xc4, 0x40, 0xcf, 0x9f, 0x0a, 0xbf, 0xf8, 0xf9, 0x13, 0x3e, 0x3d, 0x5c, 0x23, 0x3e, 0xf9, 0xf1, 0x84, 0x0f, 0xf6, 0x91, 0x72, 0x36, 0x0a, 0xa2, 0xc6, 0x2f, 0x0e, 0x82, 0x22, 0xd0, 0x4f, 0xa3, 0xc1, 0x7a, 0xf1, 0xd1, 0x0d, 0xe4, 0xc8, 0x1e, 0x04, 0x00, 0x72, 0xed, 0xa9, 0xec, 0x44, 0x7c, 0xe9, 0x52, 0xc0, 0xb3, 0x90, 0xe5, 0x21, 0x36, 0xd4, 0x47, 0x5b, 0x2b, 0xa4, 0x1d, 0xa8, 0xb8, 0x8c, 0x82, 0x0b, 0x30, 0x6a, 0x7f, 0x5a, 0x6b, 0x8d, 0x84, 0xad, 0x11, 0x1a, 0x53, 0x99, 0x78, 0xca, 0x72, 0x59, 0x6e, 0x86, 0x1c, 0xb9, 0x17,\n\t0xd5, 0xf8, 0x7f, 0xfd, 0xbb, 0x35, 0x8f, 0x3e, 0x70, 0xf7, 0xbd, 0xdf, 0x5c, 0x7e, 0xfb, 0x9e, 0xaf, 0x36, 0x6e, 0xfa, 0xe6, 0x66, 0xf2, 0xeb, 0xc8, 0xf2, 0xdb, 0xf7, 0x7e, 0x55, 0x9c, 0x7e, 0xc7, 0x3f, 0x16, 0x25, 0x6b, 0x93, 0x45, 0x73, 0x17, 0xce, 0xd8, 0x72, 0x4e, 0xa2, 0x28, 0x59, 0x87, 0xbf, 0xd2, 0xb6, 0x6f, 0xe4, 0x76, 0x6a, 0xfc, 0xfc, 0x1b, 0x88, 0xe6, 0x21, 0x4a, 0xb3, 0x3d, 0x67, 0x9b, 0x87, 0x0f, 0x9d, 0x56, 0x12, 0xf3, 0x34, 0x37, 0x49, 0x4a, 0xa3, 0x90, 0x8a, 0x9b, 0x03, 0x70, 0xcc, 0xfa, 0x95, 0xdd, 0x04, 0x0f, 0x50, 0xb4, 0xb4, 0x7f, 0x74, 0x63, 0x54, 0x4c, 0x92, 0x6e, 0xfc, 0x4f, 0x6c, 0x0a, 0xff, 0xcc, 0x98, 0x4d, 0xf9, 0xfb, 0xe4, 0xfd, 0x6c, 0x21, 0x86, 0xc6, 0xfd, 0x00, 0x92, 0xdd, 0x68, 0x3a, 0x44, 0x85, 0x37, 0xfb, 0xca, 0x07, 0x4b, 0x2c,\n\t0xe8, 0xcd, 0x11, 0x51, 0xec, 0x7d, 0x14, 0xab, 0x0f, 0x07, 0x03, 0x9c, 0x4b, 0xac, 0x40, 0x22, 0xba, 0x1f, 0x8b, 0x68, 0xea, 0x59, 0xf8, 0x01, 0xac, 0x81, 0xd5, 0xf0, 0xc3, 0x67, 0x6b, 0xb1, 0x88, 0x0a, 0x3f, 0x75, 0x26, 0x3a, 0xca, 0xae, 0x99, 0x37, 0x38, 0x38, 0xef, 0x9a, 0xb2, 0x8e, 0x84, 0x53, 0x1e, 0xe3, 0x0e, 0x8d, 0x1d, 0xed, 0x43, 0xb5, 0xa0, 0xfe, 0x31, 0x2d, 0x84, 0xd3, 0x38, 0xf8, 0x85, 0x37, 0xa1, 0x16, 0x79, 0x13, 0x2a, 0xe0, 0x4d, 0x28, 0xfa, 0x2b, 0x7e, 0x88, 0x77, 0x7d, 0x1f, 0x7d, 0x72, 0xa5, 0xb0, 0x5d, 0xde, 0x78, 0xee, 0x5b, 0x4d, 0x74, 0xdf, 0x05, 0xfc, 0x2f, 0xe0, 0x2b, 0xe2, 0x71, 0xb4, 0x16, 0x56, 0x82, 0x96, 0x74, 0xe3, 0x19, 0xf2, 0x43, 0x28, 0x39, 0x0f, 0xe4, 0x3c, 0x11, 0x6b, 0x85, 0x9e, 0x50, 0x89, 0x33, 0xea, 0x18, 0x95, 0x1c, 0x82,\n\t0xcd, 0xc9, 0x77, 0x00, 0x33, 0xf9, 0x0e, 0xd4, 0x74, 0x07, 0xab, 0xcb, 0x5b, 0x42, 0x26, 0xbf, 0xcf, 0x5f, 0xee, 0xfa, 0xa4, 0xef, 0xc2, 0xb2, 0xce, 0xa4, 0xbb, 0xd1, 0x62, 0x13, 0x74, 0x25, 0xe9, 0x8a, 0xce, 0x6e, 0x6f, 0xfb, 0xda, 0x99, 0x93, 0xbd, 0x41, 0xaf, 0xd3, 0x6c, 0xb4, 0xf2, 0xc2, 0x21, 0x46, 0x6f, 0x71, 0x1a, 0xbc, 0x76, 0xbb, 0x13, 0x5a, 0xa7, 0xfb, 0xaa, 0x26, 0xc4, 0xa4, 0xff, 0xd0, 0x59, 0x7c, 0xfe, 0x40, 0xba, 0xdd, 0x93, 0x8a, 0x17, 0x32, 0xce, 0x3e, 0xbd, 0x49, 0x6f, 0xd4, 0xd2, 0x76, 0x70, 0xfd, 0xf0, 0x15, 0xa1, 0x8e, 0xb4, 0xa3, 0x33, 0xdd, 0x3e, 0x46, 0x3b, 0x94, 0xdc, 0x0d, 0x6a, 0x7b, 0xd0, 0x64, 0x3e, 0x9f, 0x08, 0x02, 0x69, 0x58, 0xef, 0x5f, 0xba, 0x35, 0x7c, 0x11, 0x6d, 0x8d, 0xc3, 0x91, 0xd7, 0x9a, 0x8e, 0x8e, 0x9c, 0xd6, 0xfc, 0xef,\n\t0xe9, 0x93, 0x73, 0x50, 0x3b, 0x24, 0xf1, 0x61, 0x20, 0x80, 0x32, 0x1c, 0x4b, 0xdf, 0x9a, 0x13, 0x4b, 0x3f, 0x2b, 0x2d, 0x00, 0x8d, 0xa6, 0xaf, 0xf8, 0xf5, 0xad, 0x05, 0x3d, 0xa2, 0x88, 0xe6, 0xfc, 0x32, 0xb1, 0x14, 0x47, 0x3b, 0x2e, 0x30, 0xe9, 0xb5, 0xa8, 0x04, 0xa1, 0x84, 0x26, 0x04, 0x88, 0x9e, 0x3d, 0x94, 0xfe, 0xde, 0x44, 0x45, 0x79, 0xb5, 0x86, 0x11, 0xdb, 0xaa, 0x3d, 0x91, 0x42, 0x97, 0xde, 0xa4, 0x09, 0xdb, 0x2b, 0x6b, 0x6a, 0xdd, 0x55, 0x73, 0xda, 0xc3, 0xc5, 0xcd, 0xe7, 0xd4, 0x26, 0xbb, 0xea, 0x8b, 0xf4, 0x16, 0xe1, 0xd3, 0x70, 0x53, 0x55, 0xb2, 0xbb, 0xbd, 0xc9, 0x60, 0x36, 0x18, 0x2a, 0xdc, 0x45, 0x16, 0x31, 0xd0, 0xbe, 0xa8, 0xad, 0xe2, 0x9c, 0x8e, 0xb0, 0xbf, 0x7e, 0x66, 0x8d, 0xdf, 0x46, 0xe8, 0x47, 0x63, 0x4a, 0x12, 0x52, 0x84, 0xfe, 0xcb, 0x4f,\n\t0x58, 0xe5, 0x1c, 0x08, 0x45, 0x24, 0xf7, 0xf4, 0xd8, 0x19, 0x01, 0x70, 0x2e, 0x00, 0xd8, 0x8f, 0xf3, 0x02, 0x0c, 0x08, 0x24, 0xcd, 0x6a, 0x1e, 0x5a, 0x76, 0xa3, 0xd1, 0x86, 0x72, 0xbe, 0xec, 0x40, 0xc4, 0x70, 0x68, 0xd2, 0x72, 0xff, 0x0f, 0xb4, 0x9a, 0xbf, 0x22, 0xbf, 0xd5, 0xc5, 0xed, 0x8b, 0x51, 0xab, 0xdb, 0xc3, 0x85, 0x72, 0xab, 0xff, 0x37, 0xf4, 0xdb, 0x0a, 0xfe, 0x65, 0xf0, 0xb9, 0x66, 0x0b, 0x5a, 0x1f, 0x2c, 0x59, 0x71, 0xc1, 0x0b, 0xc7, 0x8c, 0x0b, 0xbe, 0xf6, 0x8b, 0xc4, 0x05, 0x2f, 0x30, 0x65, 0xc5, 0x05, 0xb7, 0xa9, 0x71, 0xc1, 0x65, 0xdb, 0x85, 0x77, 0xae, 0xb8, 0xd1, 0xe0, 0xf0, 0x17, 0x14, 0x27, 0x93, 0xc5, 0x81, 0x0a, 0xf1, 0x56, 0xa9, 0x07, 0x3e, 0x72, 0x7b, 0x41, 0xa1, 0xc3, 0x90, 0x0c, 0x04, 0x92, 0x49, 0x42, 0x0f, 0xb7, 0x0c, 0x7c, 0x2e, 0x7c,\n\t0x4a, 0xe8, 0x21, 0xb1, 0x94, 0x31, 0x41, 0xe3, 0x57, 0xf9, 0xa5, 0xea, 0x13, 0xec, 0x63, 0xd4, 0xf7, 0x37, 0xd6, 0x7e, 0x34, 0x9e, 0x98, 0x20, 0x1a, 0x4f, 0x36, 0xe0, 0xc7, 0xd6, 0x4d, 0x3c, 0x24, 0xd7, 0xfc, 0x4b, 0xd5, 0x48, 0xc6, 0x6b, 0x59, 0x12, 0xcc, 0xda, 0xe7, 0xb1, 0xfb, 0x1d, 0xfe, 0x33, 0x05, 0x91, 0xa6, 0xbb, 0x2a, 0x84, 0xdb, 0x52, 0x3b, 0x17, 0xef, 0x5b, 0xe7, 0xd6, 0xd6, 0xce, 0x6d, 0x2b, 0x29, 0x69, 0x9b, 0x5b, 0x5b, 0x57, 0x5d, 0x5d, 0xb7, 0x46, 0x7c, 0x38, 0xd8, 0xbe, 0xa0, 0xbe, 0x61, 0x41, 0x7b, 0x10, 0x7d, 0x36, 0xd4, 0xa3, 0x4f, 0xe9, 0xba, 0x29, 0xe8, 0xcf, 0xee, 0xdd, 0xf2, 0xb8, 0xe6, 0xfa, 0x99, 0x20, 0x92, 0x67, 0x4c, 0xc7, 0xd9, 0x63, 0x5a, 0xff, 0xc9, 0xe4, 0x08, 0xa9, 0x60, 0x5b, 0x36, 0x39, 0x6d, 0x41, 0xe9, 0x7a, 0x99, 0x9c, 0xbf,\n\t0x15, 0x9e, 0xa0, 0xad, 0x0f, 0x92, 0xf5, 0x11, 0xf1, 0x41, 0xe0, 0xc6, 0x7e, 0x6b, 0x2e, 0x34, 0x06, 0x04, 0x12, 0x7b, 0x98, 0x9e, 0x9a, 0x66, 0x45, 0x20, 0x5e, 0x4b, 0xc2, 0xf2, 0xba, 0x81, 0x3b, 0xe4, 0x88, 0x2a, 0x7e, 0x6b, 0xca, 0x62, 0x92, 0x13, 0x77, 0x18, 0x8e, 0xcc, 0xd0, 0x9b, 0x04, 0xd1, 0xd7, 0x59, 0x11, 0x6d, 0x2a, 0xb5, 0x5f, 0x51, 0x12, 0xf2, 0x26, 0xed, 0xe2, 0x83, 0x52, 0xad, 0x41, 0x5f, 0xe4, 0x0b, 0x7a, 0x2b, 0x3a, 0xa3, 0x30, 0x2c, 0xfd, 0x2a, 0x52, 0xea, 0xb4, 0xc3, 0xa9, 0xa4, 0x7e, 0x34, 0xc7, 0x8e, 0x08, 0xe5, 0xa8, 0xe4, 0x54, 0xba, 0x2a, 0x53, 0x3f, 0xae, 0x13, 0x8d, 0xc9, 0xb9, 0x99, 0xd3, 0x5b, 0xf9, 0x16, 0xf5, 0xbf, 0x4f, 0x84, 0x50, 0x8e, 0x88, 0xd0, 0x15, 0x8f, 0x22, 0xe2, 0xaf, 0xcf, 0x03, 0x3c, 0xdf, 0xbe, 0x8c, 0xc6, 0x42, 0x14,\n\t0x67, 0x68, 0x8a, 0x42, 0xc8, 0x3b, 0x49, 0xee, 0xa3, 0xfc, 0x7c, 0x46, 0xf2, 0x74, 0x2b, 0x47, 0xdc, 0x5e, 0x0b, 0x7b, 0x4a, 0xc3, 0x67, 0xc8, 0x64, 0x94, 0xef, 0xea, 0x01, 0x1f, 0xe7, 0xf5, 0x3a, 0xad, 0xc5, 0x51, 0xe8, 0x6c, 0xa8, 0x6d, 0xac, 0xf2, 0x14, 0x39, 0x2c, 0x7a, 0xb3, 0x26, 0x5c, 0xba, 0xa2, 0x2a, 0xde, 0xd3, 0x54, 0xe2, 0x6f, 0x9e, 0xd3, 0x58, 0xd7, 0x1b, 0x10, 0xd3, 0xa2, 0x46, 0x67, 0xd4, 0x75, 0x4f, 0x98, 0x3c, 0xdd, 0x60, 0x36, 0x1a, 0x2a, 0x2a, 0x8b, 0x71, 0x52, 0x99, 0x9a, 0x79, 0xe9, 0x48, 0x28, 0x88, 0xe9, 0x44, 0x7d, 0xf5, 0x32, 0x92, 0x9f, 0x28, 0xf6, 0xcd, 0x1f, 0x9f, 0x4e, 0x1e, 0xa1, 0xf2, 0x70, 0xd4, 0x0a, 0xf7, 0x67, 0xa7, 0x96, 0x3f, 0x39, 0x0e, 0xb5, 0xe1, 0x92, 0x20, 0xf8, 0xfb, 0xe1, 0x2b, 0x9d, 0x0b, 0x18, 0xcd, 0x25, 0x48, 0xdf,\n\t0x0b, 0x81, 0xe6, 0x74, 0x03, 0xce, 0x0b, 0xa5, 0x1f, 0x9d, 0x17, 0x0a, 0x6b, 0x80, 0x90, 0x59, 0xaa, 0xe4, 0x87, 0x42, 0x13, 0xb7, 0xc1, 0x60, 0x08, 0x19, 0x42, 0xa5, 0x51, 0x7b, 0x38, 0x48, 0x6e, 0xc6, 0xa2, 0xb9, 0x39, 0xa1, 0xa2, 0xf9, 0x49, 0xa1, 0xea, 0xe0, 0x75, 0xc1, 0xca, 0xf2, 0x86, 0x64, 0x34, 0x50, 0x6e, 0xbf, 0xa2, 0xc7, 0x60, 0x12, 0xb4, 0x85, 0x53, 0xaa, 0xc2, 0xed, 0x49, 0x4f, 0x61, 0xed, 0xf4, 0xf2, 0x68, 0xca, 0x21, 0x56, 0x97, 0x4c, 0x9a, 0xd1, 0xdd, 0xea, 0x71, 0x31, 0x86, 0xe1, 0xd5, 0x06, 0x7d, 0xb4, 0x28, 0x1a, 0x68, 0x9d, 0xdf, 0x58, 0xbb, 0x20, 0x1d, 0x71, 0xda, 0xde, 0x91, 0xe7, 0x4f, 0x46, 0xf8, 0x84, 0xd0, 0x99, 0x4e, 0xb7, 0x8d, 0x43, 0x27, 0xda, 0xb9, 0xe1, 0x08, 0xc1, 0xc4, 0x12, 0x60, 0x3e, 0x39, 0xa5, 0x24, 0x84, 0xf7, 0xfe, 0xb9,\n\t0xa9, 0xe5, 0x8f, 0x67, 0x53, 0xab, 0x8b, 0xe5, 0x52, 0x0b, 0xfe, 0x6e, 0xf8, 0x8a, 0xfd, 0x83, 0x5f, 0x66, 0x34, 0x88, 0xce, 0xb3, 0xe4, 0x4d, 0x59, 0x7b, 0xb6, 0xbc, 0x29, 0x6f, 0x7b, 0x5b, 0xe3, 0xd1, 0x66, 0x34, 0xe1, 0x84, 0x42, 0x5e, 0x44, 0xc9, 0x15, 0xe2, 0x56, 0x97, 0xdf, 0x5b, 0xd9, 0x19, 0x95, 0x7e, 0x05, 0xc3, 0x91, 0x52, 0x87, 0x4d, 0x7a, 0x8c, 0xb9, 0x1d, 0xcb, 0xc5, 0x10, 0xb7, 0x8c, 0xd1, 0xa0, 0x7e, 0x74, 0xe0, 0xf9, 0x2e, 0xbb, 0x3e, 0xd4, 0x71, 0xf8, 0xc8, 0x04, 0x5f, 0x2c, 0xe2, 0x1b, 0x58, 0x62, 0xd1, 0xcf, 0xc1, 0x19, 0x5f, 0xae, 0x56, 0x01, 0xb8, 0x0a, 0xbd, 0x95, 0xe9, 0xbc, 0x5a, 0xc1, 0x5f, 0xa1, 0x9d, 0x1b, 0x50, 0x7d, 0x58, 0x8f, 0x0d, 0xe3, 0x5d, 0x94, 0x41, 0x60, 0x38, 0x10, 0x82, 0x2c, 0xc7, 0x74, 0xe1, 0xbc, 0xc6, 0x78, 0xab, 0xce,\n\t0xa0, 0xba, 0xba, 0x69, 0x24, 0x6b, 0xe5, 0x27, 0x4b, 0xbd, 0xb3, 0xc3, 0x24, 0xdb, 0x47, 0xd4, 0x82, 0x93, 0xa3, 0xe2, 0x04, 0x26, 0xce, 0x62, 0x78, 0xe6, 0xa4, 0x1f, 0x1b, 0x66, 0xe8, 0xcd, 0x82, 0xe0, 0x6a, 0x8c, 0x26, 0x1b, 0x4d, 0xae, 0x73, 0x92, 0xdd, 0xb3, 0xaf, 0x9c, 0x54, 0x14, 0xbf, 0x22, 0x58, 0xe4, 0x8a, 0x59, 0xf8, 0x97, 0xe1, 0x8f, 0x0c, 0x3a, 0x9f, 0x27, 0x90, 0x8c, 0x26, 0xa3, 0x8b, 0xe6, 0x60, 0x22, 0x67, 0xc4, 0x08, 0xad, 0xa5, 0x11, 0x9b, 0x45, 0x3a, 0x4e, 0x79, 0xb3, 0x01, 0xf5, 0x09, 0xde, 0x6b, 0x84, 0x71, 0x8e, 0x15, 0x01, 0x30, 0x4a, 0x52, 0x12, 0x1c, 0xa8, 0x86, 0x87, 0x44, 0x4d, 0x21, 0xb9, 0x48, 0x98, 0x7e, 0x9c, 0x99, 0x04, 0x30, 0xb8, 0x53, 0xbe, 0x4c, 0x46, 0x12, 0xa7, 0xeb, 0x37, 0xae, 0x86, 0x31, 0xa8, 0xbb, 0x02, 0x13, 0xce, 0x7f,\n\t0x8a, 0xa8, 0x8b, 0x94, 0x47, 0x17, 0x8e, 0xa6, 0x0e, 0xd3, 0xfe, 0xf7, 0xc6, 0xcb, 0xf3, 0x11, 0xda, 0xf5, 0x68, 0xff, 0xec, 0x20, 0x9e, 0x1e, 0x6a, 0x6a, 0x8d, 0x4c, 0x16, 0x8d, 0xb5, 0xdd, 0xd9, 0x7a, 0xd6, 0x59, 0x52, 0x65, 0xbc, 0xe2, 0x6c, 0x8c, 0x16, 0xdb, 0x35, 0x5c, 0x81, 0xe8, 0xd3, 0x07, 0x63, 0xa6, 0x2b, 0xa7, 0xdb, 0x4d, 0xac, 0xb8, 0x34, 0x96, 0x34, 0x2f, 0x2d, 0xe0, 0x42, 0xc5, 0xd2, 0x9b, 0xf0, 0x47, 0x26, 0x8b, 0x5c, 0x2f, 0xb7, 0x0c, 0x5e, 0x2f, 0xd4, 0x51, 0x1b, 0xfe, 0x4c, 0xbd, 0xd8, 0x8e, 0x1f, 0x12, 0x1b, 0x16, 0x25, 0xd2, 0x3b, 0x60, 0x67, 0xfc, 0x37, 0x2a, 0xe5, 0x5f, 0x1d, 0x55, 0xe9, 0xff, 0xad, 0xb6, 0xa6, 0xd1, 0x7a, 0xbe, 0x55, 0x53, 0x03, 0x8a, 0x71, 0x04, 0x27, 0x9c, 0xc3, 0xa3, 0x28, 0x93, 0xc3, 0x03, 0xf0, 0x48, 0x69, 0xe3, 0xc1,\n\t0x32, 0x35, 0x97, 0xc7, 0x5a, 0xec, 0x59, 0xe3, 0xb0, 0xe7, 0x27, 0xf0, 0x80, 0xd8, 0xce, 0x2e, 0x37, 0x81, 0x87, 0xc3, 0xae, 0x5a, 0x6a, 0xa2, 0xd1, 0xdc, 0x31, 0x21, 0xa1, 0x33, 0x4d, 0xf7, 0x08, 0xce, 0xf4, 0xe6, 0xcd, 0x11, 0xad, 0x51, 0xa7, 0x15, 0x04, 0x03, 0xeb, 0xaa, 0xe3, 0x7f, 0x31, 0xb5, 0xed, 0x03, 0xa3, 0x21, 0x65, 0xba, 0xc8, 0xb1, 0xab, 0xff, 0xad, 0x18, 0xcf, 0xf3, 0x82, 0x06, 0xed, 0xef, 0x29, 0x5d, 0x48, 0x2f, 0xda, 0x2a, 0x3c, 0x82, 0xe8, 0xaa, 0x4a, 0x27, 0xf5, 0x90, 0x44, 0x7e, 0x20, 0x34, 0xb1, 0x88, 0x1a, 0x1e, 0x47, 0x2f, 0x42, 0xdb, 0x7f, 0x7e, 0x3e, 0xce, 0x16, 0xba, 0x08, 0x87, 0x89, 0xe8, 0xb3, 0x5a, 0x2c, 0x31, 0x9b, 0x9a, 0x1b, 0x65, 0x7c, 0x82, 0x5c, 0x70, 0x6b, 0xdd, 0x64, 0x42, 0x50, 0x97, 0x3b, 0x97, 0x20, 0x6e, 0x7b, 0x7c, 0x6a,\n\t0xdb, 0xfb, 0x26, 0x4a, 0xcf, 0xb9, 0x6f, 0x52, 0x7a, 0x72, 0x79, 0x84, 0xfa, 0x25, 0x9b, 0x16, 0x4c, 0x42, 0x2e, 0x7b, 0xfe, 0x74, 0x2a, 0x04, 0x18, 0x1f, 0xcd, 0x15, 0xca, 0x93, 0x36, 0x34, 0x5f, 0x38, 0x90, 0x4e, 0x6d, 0x19, 0x2b, 0x9f, 0xc8, 0x5a, 0x62, 0x83, 0x64, 0x01, 0x05, 0xa3, 0xf3, 0x89, 0xc8, 0x79, 0x22, 0x1c, 0x8f, 0x0c, 0x3d, 0xb2, 0xda, 0x64, 0x63, 0x7a, 0x34, 0x7a, 0x5e, 0x5b, 0x30, 0x93, 0xb1, 0x19, 0xb0, 0xfe, 0x8c, 0x84, 0x5f, 0xff, 0x62, 0xb0, 0xbd, 0xb8, 0x65, 0xe2, 0x8b, 0x3a, 0xa3, 0x5c, 0x0f, 0x9a, 0x37, 0x1d, 0x68, 0xff, 0x60, 0xc1, 0xf6, 0xbf, 0xb4, 0x1e, 0x5c, 0x05, 0x35, 0xca, 0x5d, 0xfb, 0xa5, 0x6b, 0xc1, 0x9b, 0x84, 0xbc, 0x5a, 0xfe, 0xe7, 0xda, 0xd2, 0x89, 0xea, 0x29, 0x44, 0xf5, 0xd0, 0x1c, 0x23, 0x36, 0x63, 0x7e, 0x8e, 0x11, 0xa4,\n\t0x9a, 0x94, 0x59, 0xcb, 0xb2, 0x72, 0x8c, 0x08, 0x34, 0xb9, 0x47, 0x43, 0x4c, 0x9e, 0x55, 0xe5, 0xec, 0x1e, 0x85, 0x97, 0x98, 0x0a, 0xf8, 0x7e, 0x4e, 0xd3, 0xc3, 0x17, 0x18, 0x36, 0xdc, 0x79, 0x60, 0x0b, 0x1a, 0xff, 0xfd, 0xac, 0xc0, 0x4f, 0xd2, 0xda, 0x36, 0xee, 0xe7, 0x5f, 0x36, 0x69, 0x6f, 0xb3, 0x98, 0xb6, 0x68, 0x4d, 0xbf, 0x7f, 0x59, 0xd4, 0xde, 0xaa, 0xb5, 0x6a, 0xd7, 0x59, 0xff, 0x1d, 0xd7, 0x8d, 0xf8, 0x58, 0x88, 0xf8, 0x48, 0xf3, 0x8b, 0x28, 0x75, 0x8f, 0x91, 0x5f, 0xe4, 0x4f, 0xa6, 0x80, 0x5b, 0x36, 0x16, 0x05, 0x7f, 0xdd, 0xf6, 0xb3, 0xa0, 0x82, 0xbf, 0x9a, 0x79, 0x4f, 0xfc, 0x16, 0xfa, 0xe6, 0x02, 0x09, 0x1c, 0x5d, 0x04, 0xa9, 0x26, 0x38, 0x1d, 0x0d, 0x09, 0xbb, 0x28, 0x9b, 0x80, 0xc8, 0x41, 0x46, 0x90, 0x7e, 0x52, 0x8a, 0xfe, 0x10, 0x63, 0x81, 0x06,\n\t0x28, 0x46, 0xf2, 0x3d, 0xf3, 0xf2, 0x7e, 0xdf, 0x33, 0x00, 0xb7, 0x0f, 0x4a, 0x7f, 0xb4, 0x07, 0xcb, 0xdd, 0xee, 0x38, 0xb6, 0xdc, 0x88, 0xbb, 0xdd, 0xe5, 0x41, 0x3b, 0x7c, 0x1e, 0xdb, 0x70, 0x28, 0xb6, 0x1c, 0xf8, 0x53, 0x0c, 0x0d, 0x4a, 0x5b, 0x57, 0xce, 0x73, 0x27, 0x02, 0x56, 0x6b, 0x80, 0x1a, 0x7f, 0xd8, 0x82, 0xe5, 0x30, 0xe6, 0x4e, 0x14, 0xdb, 0x6c, 0xc5, 0x2a, 0x80, 0xe6, 0x59, 0xac, 0xe0, 0x58, 0xe6, 0x3d, 0xa1, 0x5a, 0xa6, 0x17, 0xcd, 0xfd, 0xd9, 0xf4, 0x2a, 0x87, 0x3c, 0x79, 0xae, 0x28, 0x7f, 0x11, 0xaa, 0xf9, 0x6f, 0x0c, 0x4a, 0x57, 0x0e, 0x7e, 0x01, 0xaa, 0xff, 0x0e, 0x79, 0x9c, 0x4f, 0x2f, 0x36, 0x41, 0x25, 0x2b, 0x2b, 0x43, 0x8d, 0xd7, 0xc9, 0x79, 0x0d, 0x3d, 0x79, 0x67, 0x33, 0xf4, 0xc6, 0xa0, 0x6b, 0x54, 0xa8, 0x99, 0xbc, 0xdf, 0x9f, 0x0d, 0xc2,\n\t0xed, 0x03, 0x97, 0xe6, 0x93, 0x2b, 0xc5, 0x47, 0x31, 0xf7, 0xee, 0x95, 0xf0, 0x9a, 0x41, 0xe9, 0x39, 0x99, 0x2c, 0x8f, 0x4c, 0x37, 0x5c, 0x90, 0x01, 0x10, 0xba, 0xc7, 0x19, 0x13, 0xd9, 0xf4, 0x32, 0x78, 0x54, 0xb0, 0x03, 0xa3, 0x42, 0x6b, 0xfc, 0x05, 0xa8, 0xe6, 0x4a, 0x06, 0x71, 0x77, 0x7c, 0x01, 0xaa, 0xff, 0xde, 0x78, 0x8c, 0xfd, 0x26, 0x2f, 0x67, 0x1e, 0xe0, 0x1f, 0x03, 0x4e, 0xd0, 0x42, 0xef, 0x57, 0xad, 0x64, 0xab, 0xc9, 0xe0, 0xf3, 0x83, 0x95, 0x58, 0xd5, 0x1a, 0xc0, 0x69, 0xd9, 0x1c, 0x40, 0xb1, 0x1e, 0xcb, 0x3c, 0x84, 0x3d, 0xfd, 0x8f, 0xda, 0xc3, 0xf6, 0x30, 0xcd, 0x50, 0x94, 0xe5, 0xda, 0x4b, 0x06, 0x72, 0x0a, 0x42, 0x5b, 0x71, 0xd4, 0x16, 0xe9, 0xac, 0x2e, 0xdc, 0x55, 0x39, 0xff, 0xf2, 0x19, 0x75, 0x73, 0x5a, 0x02, 0xbb, 0xf8, 0x0b, 0xc3, 0x49, 0xb7,\n\t0xd6, 0x5d, 0x39, 0xb1, 0xbc, 0xf3, 0xc2, 0x79, 0x35, 0xbe, 0x96, 0x25, 0x93, 0xfe, 0x66, 0x68, 0x78, 0x99, 0xff, 0x98, 0xb1, 0xca, 0xb6, 0x9e, 0xa3, 0xed, 0xcb, 0x84, 0x5f, 0x61, 0xfb, 0x32, 0x6c, 0xeb, 0xf9, 0x32, 0x77, 0x19, 0x63, 0x95, 0x6d, 0x47, 0x47, 0xe3, 0xf1, 0x4b, 0x54, 0xbc, 0x2f, 0x54, 0x5e, 0xbe, 0x1d, 0x9a, 0x56, 0xcc, 0xb2, 0x43, 0xe3, 0xf1, 0x0b, 0x0d, 0xd4, 0x0e, 0x8d, 0x35, 0xbe, 0x86, 0x2d, 0xd0, 0xa8, 0x1d, 0x5a, 0xe7, 0xeb, 0xaf, 0x23, 0x10, 0xb5, 0x2b, 0xa8, 0x1a, 0xf9, 0x03, 0xd7, 0x89, 0xe3, 0x1b, 0x32, 0x8b, 0x88, 0xa7, 0xc3, 0x43, 0xe0, 0x7e, 0x9a, 0x7f, 0x1c, 0xc3, 0xf9, 0x43, 0xa0, 0x06, 0xb4, 0xa7, 0x5b, 0x2a, 0x21, 0xc7, 0xc7, 0x10, 0xeb, 0xcc, 0x78, 0x7e, 0x42, 0xc3, 0x90, 0x63, 0x39, 0x7a, 0x5e, 0xc4, 0xe1, 0xf3, 0x22, 0x8e, 0xe3,\n\t0xfb, 0x69, 0xca, 0x3b, 0xb4, 0xfe, 0x2f, 0xa2, 0x31, 0xfc, 0x2c, 0x8e, 0xd2, 0xca, 0x52, 0xea, 0xdd, 0x44, 0xc3, 0xef, 0xd2, 0xe0, 0x7b, 0x74, 0xa3, 0x43, 0x43, 0x51, 0xd2, 0x58, 0x87, 0xd8, 0xea, 0x09, 0x06, 0xeb, 0x82, 0xd8, 0xca, 0x89, 0x59, 0xb9, 0xed, 0xc4, 0x85, 0x75, 0x0b, 0xef, 0x78, 0x66, 0xe3, 0xf4, 0x5d, 0x97, 0xaf, 0x2d, 0x9b, 0xad, 0xb7, 0x09, 0x06, 0xbb, 0xad, 0xa0, 0x6e, 0xc6, 0x60, 0xc7, 0x9c, 0xab, 0x16, 0x24, 0xa3, 0x73, 0x76, 0x0e, 0x1c, 0x36, 0x59, 0xe0, 0x65, 0xc3, 0xeb, 0xd8, 0xef, 0xe9, 0x9d, 0xec, 0x16, 0xbe, 0x73, 0xdd, 0x9e, 0x59, 0x17, 0x7d, 0xe7, 0x9a, 0x29, 0x45, 0x4d, 0xb3, 0xeb, 0x96, 0x18, 0x38, 0x4d, 0x81, 0xb5, 0x3c, 0xe6, 0xad, 0x99, 0x37, 0xd4, 0xd1, 0xb0, 0x78, 0x52, 0x6c, 0x91, 0x25, 0x6c, 0x81, 0x1b, 0xbf, 0xd9, 0x6b, 0x2d,\n\t0xb3, 0x23, 0x3e, 0xcd, 0x96, 0x76, 0xf3, 0x57, 0x70, 0x7a, 0x60, 0x02, 0xad, 0xe0, 0x34, 0xf5, 0x1f, 0x32, 0x94, 0x23, 0x0d, 0xb9, 0xd0, 0x84, 0x87, 0x05, 0x0e, 0x2d, 0x8e, 0x7f, 0x0a, 0xca, 0xcf, 0x7e, 0x39, 0x60, 0x38, 0x50, 0x2c, 0x9e, 0xd6, 0x77, 0xe3, 0x5b, 0x2c, 0x72, 0x37, 0xca, 0x0e, 0x76, 0x6b, 0xa1, 0x46, 0xa3, 0x78, 0x38, 0xc9, 0xb1, 0xf6, 0x62, 0x40, 0x10, 0x56, 0xa9, 0xc1, 0x38, 0xcf, 0x80, 0x9e, 0xae, 0x01, 0x5a, 0x4e, 0xc3, 0x69, 0x35, 0x43, 0x79, 0x6f, 0xe0, 0x50, 0xab, 0xe4, 0x35, 0x72, 0xee, 0xb2, 0xa1, 0x1b, 0x64, 0x5e, 0xea, 0xef, 0x4f, 0x9b, 0x9a, 0x1b, 0x43, 0x96, 0x70, 0x69, 0x38, 0x12, 0x89, 0x96, 0xe8, 0x74, 0x7e, 0x35, 0xe5, 0x39, 0xf1, 0xdb, 0x6a, 0x50, 0x7d, 0xaa, 0x46, 0xa7, 0x3e, 0x6f, 0x40, 0x3a, 0x80, 0x25, 0xa5, 0x06, 0xd7, 0x73,\n\t0xb1, 0xee, 0xca, 0x8d, 0x13, 0xaf, 0xdb, 0x17, 0xec, 0x58, 0xd8, 0x3c, 0xf7, 0x8a, 0x7a, 0x66, 0x50, 0x8e, 0x92, 0xb7, 0xb2, 0x4c, 0x67, 0x49, 0xdf, 0xb7, 0x6e, 0xfe, 0x4d, 0x83, 0xf5, 0xad, 0x9b, 0xbe, 0xbe, 0x6a, 0xc5, 0x0d, 0x75, 0x06, 0x5d, 0xd9, 0xe6, 0xdb, 0xab, 0xd2, 0x81, 0x0a, 0x93, 0xde, 0x2b, 0xb2, 0x6c, 0x7b, 0xcd, 0xd3, 0x8f, 0x2f, 0xdf, 0x39, 0xbf, 0xac, 0x67, 0xf2, 0xf0, 0x2d, 0x76, 0x0b, 0x0e, 0x8b, 0x57, 0x17, 0xbb, 0x78, 0xc6, 0xe2, 0x49, 0xdb, 0x4f, 0x6e, 0xdd, 0x78, 0x72, 0xcf, 0xac, 0xc9, 0x6d, 0xd3, 0x62, 0x9f, 0x1f, 0x7a, 0x81, 0x84, 0xcd, 0x43, 0xe3, 0x27, 0x35, 0xf2, 0x1e, 0x7b, 0x11, 0xa7, 0x01, 0xe5, 0xe0, 0xfc, 0xb4, 0x0e, 0xc7, 0x82, 0x2c, 0xc7, 0x19, 0x52, 0xe5, 0xb8, 0x86, 0x61, 0x7c, 0xcf, 0xc0, 0x10, 0x51, 0xc4, 0xe7, 0xfc, 0xeb,\n\t0x95, 0xb8, 0x81, 0xeb, 0xbb, 0x95, 0x53, 0xc7, 0x75, 0x3c, 0xc9, 0x60, 0x7f, 0x36, 0xb4, 0x0d, 0x3c, 0xc9, 0x60, 0x1f, 0x0d, 0x95, 0xd2, 0xf3, 0x49, 0xd5, 0x93, 0x4d, 0x0e, 0x9f, 0x49, 0x6e, 0x73, 0x2b, 0x61, 0x3b, 0x9b, 0x9d, 0xb4, 0x72, 0x93, 0xd6, 0x52, 0x50, 0x10, 0xaa, 0xeb, 0x6e, 0x98, 0xb6, 0x7e, 0x7a, 0xb4, 0xb4, 0xeb, 0xbc, 0xce, 0x8e, 0xd9, 0xf5, 0x61, 0x9b, 0xdb, 0xd8, 0x18, 0x9a, 0xbf, 0xe2, 0xfc, 0x86, 0xa5, 0xdf, 0xb8, 0x74, 0x4a, 0xc7, 0xe5, 0x8f, 0x5c, 0x74, 0xc1, 0x7d, 0x9d, 0xdf, 0x37, 0x18, 0x3d, 0x7e, 0x4f, 0xed, 0xb2, 0x9d, 0xf3, 0xfa, 0x6f, 0x5c, 0x5a, 0x53, 0x1c, 0x2e, 0xb6, 0x4e, 0x8b, 0xb7, 0x45, 0xad, 0x53, 0xae, 0x3f, 0x75, 0xc5, 0xc6, 0xef, 0xef, 0x9e, 0x39, 0x25, 0x8d, 0xda, 0x99, 0x44, 0xed, 0x5c, 0x4f, 0xda, 0xd9, 0x9c, 0x6e, 0xc8,\n\t0xb4, 0x73, 0x1c, 0xca, 0xeb, 0x55, 0xca, 0x6b, 0xf9, 0x1e, 0x99, 0x6c, 0xf1, 0x0b, 0x92, 0xbd, 0xee, 0xcf, 0x47, 0x36, 0x80, 0x23, 0xbb, 0xa5, 0xdb, 0x98, 0xe7, 0xf8, 0x07, 0x41, 0x12, 0xdc, 0x48, 0xc7, 0xaf, 0x0e, 0x27, 0x92, 0x2b, 0x86, 0x3c, 0x09, 0xb3, 0x8f, 0x7e, 0x30, 0xf8, 0x87, 0x48, 0x24, 0x01, 0x3f, 0x0e, 0x6a, 0x21, 0xab, 0x81, 0x9c, 0xc0, 0x72, 0xcb, 0xb3, 0x52, 0x6c, 0xe2, 0xc8, 0xf8, 0xa4, 0x39, 0x43, 0xb8, 0xbf, 0x2a, 0x71, 0x3e, 0x3a, 0xa4, 0x69, 0xa1, 0x81, 0xcd, 0x89, 0x9c, 0x20, 0x0e, 0x65, 0xde, 0x51, 0xce, 0xb2, 0xce, 0xef, 0x06, 0xa2, 0xa8, 0xbc, 0x81, 0x06, 0x75, 0xb2, 0xdc, 0x16, 0x8c, 0x44, 0x2c, 0xe8, 0x9f, 0x30, 0x1e, 0xd4, 0xb6, 0xec, 0x38, 0x4c, 0xe4, 0x98, 0xd1, 0x42, 0x32, 0x4a, 0x66, 0xf9, 0x29, 0x12, 0x57, 0x3d, 0x4b, 0xa8, 0x2e,\n\t0xf5, 0x93, 0xb2, 0x39, 0x57, 0xf7, 0xd7, 0xf4, 0x26, 0x1d, 0xa2, 0xcb, 0x64, 0x2a, 0x8d, 0xcc, 0x9a, 0x7b, 0xe0, 0x40, 0xd9, 0x9c, 0x6b, 0xfa, 0xab, 0x11, 0x44, 0x70, 0x9b, 0x8c, 0x65, 0x08, 0x72, 0xdb, 0x6d, 0x5c, 0xed, 0x39, 0xbb, 0x06, 0xea, 0xad, 0xb6, 0x79, 0x6e, 0xb3, 0x69, 0x70, 0xf5, 0xf0, 0xdb, 0x7b, 0xa4, 0xf3, 0xcf, 0xd9, 0xbd, 0xb2, 0x49, 0x01, 0xc0, 0xe3, 0x7b, 0x10, 0x2f, 0xa6, 0x4a, 0xb7, 0xb1, 0x10, 0xf1, 0xa2, 0x05, 0xdc, 0x49, 0x1b, 0xab, 0xaf, 0x82, 0x1a, 0xd1, 0xaf, 0x25, 0x8a, 0x98, 0x0f, 0xff, 0xd2, 0x92, 0x5f, 0x8c, 0xca, 0x8d, 0x08, 0x96, 0x68, 0x39, 0xc7, 0xb5, 0x1e, 0xea, 0x74, 0x64, 0x0b, 0x39, 0x48, 0x32, 0xa7, 0x29, 0xe7, 0x0c, 0x43, 0xf8, 0x22, 0x31, 0x05, 0x34, 0x5a, 0x9d, 0x56, 0xa3, 0x1b, 0xe2, 0xd1, 0x64, 0x80, 0xcd, 0xef, 0x87,\n\t0x80, 0x56, 0x3b, 0xc6, 0x7b, 0x50, 0x09, 0x35, 0x30, 0x84, 0x7d, 0xce, 0xec, 0x24, 0xe7, 0x5a, 0x4b, 0x63, 0x7d, 0x24, 0x86, 0xf8, 0x82, 0x19, 0x64, 0x40, 0xbc, 0x89, 0x38, 0xf2, 0xd9, 0xd0, 0x06, 0x83, 0xf8, 0xda, 0x38, 0x87, 0x31, 0xa3, 0x19, 0xc8, 0x42, 0x7f, 0x7a, 0x75, 0x77, 0x59, 0x4f, 0xd2, 0x2c, 0x78, 0x0d, 0xc6, 0xca, 0x40, 0xba, 0x4a, 0xfa, 0x90, 0x4d, 0xcc, 0xd9, 0x36, 0x3f, 0x9b, 0x53, 0xf9, 0xbc, 0xdc, 0xff, 0x9d, 0x8e, 0x0b, 0x17, 0xd4, 0x59, 0x6d, 0xbd, 0x1e, 0x93, 0x69, 0xde, 0x8c, 0xba, 0xde, 0x1d, 0xcb, 0xea, 0x14, 0x9e, 0x71, 0xed, 0xd9, 0x2c, 0xfd, 0x7c, 0x3a, 0xd1, 0x03, 0x46, 0x86, 0x91, 0xf2, 0x72, 0x29, 0x7f, 0x1f, 0x08, 0xe2, 0xbc, 0x84, 0x56, 0x33, 0x43, 0x36, 0xda, 0xd8, 0x37, 0x83, 0xc5, 0x06, 0x4a, 0x6a, 0xe7, 0x93, 0x28, 0x5f, 0xa1,\n\t0x52, 0x2f, 0x59, 0x71, 0xd9, 0xcc, 0x00, 0xc7, 0x67, 0x1f, 0x38, 0x18, 0x7b, 0x94, 0x8e, 0xfd, 0x18, 0x1b, 0x5e, 0xbc, 0x66, 0x43, 0xfd, 0x79, 0x27, 0xae, 0xed, 0xae, 0x1d, 0xb8, 0x79, 0xf1, 0xa9, 0x95, 0xfb, 0x96, 0x55, 0xdc, 0x73, 0xf3, 0x84, 0x65, 0x53, 0xaa, 0xad, 0x6e, 0x23, 0x2f, 0xe2, 0xe1, 0xdc, 0xbe, 0xe5, 0xa1, 0x8b, 0x16, 0xdc, 0x75, 0xf5, 0x52, 0xaf, 0x14, 0x66, 0x26, 0x19, 0x27, 0x0d, 0x5e, 0xdd, 0xfd, 0xb5, 0xfb, 0x8a, 0x42, 0x45, 0x56, 0x44, 0xcb, 0x2e, 0x44, 0x8b, 0x80, 0x68, 0x49, 0x60, 0xcb, 0x17, 0x1b, 0xea, 0x90, 0x12, 0x4c, 0x06, 0xd1, 0xa9, 0x59, 0xa4, 0x01, 0x0c, 0x69, 0x44, 0x06, 0x6d, 0xd5, 0x39, 0x1e, 0x8f, 0x4b, 0xd9, 0x53, 0x15, 0x91, 0x46, 0xe2, 0xf3, 0xa2, 0xdf, 0x09, 0x90, 0xb0, 0x58, 0x2c, 0xde, 0x68, 0x28, 0x4e, 0x4f, 0xe8, 0x32,\n\t0xa9, 0xee, 0x72, 0x65, 0x52, 0x24, 0x87, 0x02, 0xd8, 0x73, 0xf7, 0x49, 0x4c, 0x5e, 0xbc, 0x77, 0xe3, 0xb4, 0x09, 0xcb, 0xa6, 0x62, 0x02, 0x1b, 0x42, 0x94, 0xf8, 0x1d, 0x84, 0xf8, 0x7d, 0xfb, 0x4e, 0x1f, 0x84, 0x13, 0x21, 0x24, 0x34, 0xce, 0xba, 0x6c, 0x76, 0x1c, 0x53, 0x39, 0x2d, 0xd3, 0x84, 0xab, 0x96, 0x79, 0x6f, 0xdf, 0x73, 0xe2, 0xc4, 0x1e, 0xaa, 0x4f, 0x15, 0x23, 0xda, 0xef, 0x24, 0xb4, 0xb7, 0xa4, 0x1b, 0xcd, 0x68, 0x43, 0x10, 0x04, 0x32, 0xed, 0x54, 0xb4, 0x48, 0x08, 0x68, 0x4a, 0x7a, 0x86, 0xab, 0x84, 0x74, 0xec, 0x4f, 0xec, 0x0d, 0x3b, 0xcb, 0x88, 0xa5, 0x4b, 0x26, 0x0d, 0x1f, 0x39, 0x5e, 0xca, 0x4a, 0xd5, 0x67, 0x51, 0xa8, 0x4e, 0xc1, 0x7b, 0x16, 0xdf, 0x3c, 0x50, 0xdb, 0xbd, 0xe3, 0xc4, 0x79, 0xf5, 0x1b, 0xd6, 0x2c, 0x0e, 0x35, 0x18, 0xdd, 0xd6, 0xea,\n\t0xa9, 0xcb, 0x26, 0x4c, 0xdb, 0xd8, 0x1b, 0xaf, 0x58, 0xb6, 0x6f, 0xe5, 0x9e, 0x3d, 0xa7, 0xef, 0xba, 0x0b, 0xfe, 0xca, 0xbb, 0xec, 0xaa, 0xbb, 0x16, 0x5c, 0xf4, 0xd0, 0x96, 0x76, 0x6b, 0xb4, 0x2d, 0x3e, 0xcd, 0x8a, 0x88, 0x8f, 0xcf, 0xbe, 0x6c, 0x56, 0xf7, 0xd5, 0x83, 0x93, 0x8c, 0x92, 0xb4, 0xe7, 0x91, 0x47, 0xf6, 0xd0, 0xbb, 0x64, 0x1c, 0x43, 0x73, 0x31, 0xfb, 0x31, 0xd0, 0x20, 0xbd, 0xb5, 0x26, 0x5d, 0xc9, 0xe3, 0xd3, 0x2e, 0x0e, 0x7b, 0xe1, 0xe2, 0x0b, 0x0f, 0x3c, 0xbe, 0x49, 0x42, 0x8d, 0x41, 0xae, 0x47, 0xa7, 0x85, 0xc0, 0xe9, 0xb0, 0x5b, 0xb5, 0x2e, 0x1d, 0xb6, 0x16, 0xd6, 0x20, 0x49, 0x53, 0xad, 0x85, 0x13, 0xd0, 0x62, 0x93, 0xb9, 0x4b, 0x42, 0x6c, 0xc2, 0xe7, 0xd6, 0xae, 0x5c, 0xb9, 0x76, 0xcf, 0x9e, 0x55, 0xfb, 0x97, 0x57, 0x56, 0x0f, 0xec, 0x1b, 0xd8,\n\t0xf3, 0x04, 0xfc, 0x74, 0x70, 0xee, 0xac, 0x65, 0xd2, 0x57, 0xa0, 0x54, 0x35, 0x6f, 0xcb, 0xd4, 0xae, 0xcb, 0x17, 0x54, 0x4b, 0x77, 0xa2, 0x5a, 0x19, 0x60, 0x66, 0xf7, 0x31, 0xaf, 0x91, 0x00, 0xb7, 0x4e, 0x50, 0x99, 0x2e, 0xc7, 0xee, 0x53, 0xb0, 0x0b, 0x53, 0x81, 0x0f, 0xef, 0x57, 0xa0, 0xaa, 0x7b, 0xbb, 0x71, 0x7c, 0x99, 0x3e, 0x7c, 0x3a, 0x81, 0xab, 0x37, 0x63, 0x73, 0x0c, 0x0d, 0xd0, 0x08, 0x5a, 0x54, 0x79, 0x8c, 0x64, 0xb1, 0x44, 0xdc, 0x26, 0xbb, 0xe8, 0xa0, 0x48, 0xb3, 0x59, 0xc2, 0x37, 0x7a, 0x45, 0xb3, 0x46, 0x34, 0x8b, 0xbd, 0xf0, 0x17, 0x17, 0xd9, 0xdd, 0x42, 0xb5, 0xf4, 0xef, 0xd5, 0x9c, 0xd7, 0xba, 0x19, 0x16, 0xdd, 0xc1, 0x3d, 0xf8, 0xa2, 0xb5, 0xca, 0xef, 0xaf, 0xb2, 0xbe, 0x28, 0xfd, 0xd6, 0x6e, 0xda, 0xb9, 0xd3, 0xe8, 0x60, 0x5e, 0xa2, 0x7b, 0x8e,\n\t0x41, 0x44, 0xc7, 0x6e, 0x44, 0x87, 0x8e, 0x44, 0x8f, 0x99, 0x94, 0xee, 0x2c, 0x1c, 0x27, 0x2e, 0x74, 0x6f, 0x26, 0x2e, 0x74, 0x1f, 0xdf, 0xe3, 0xb0, 0xe3, 0xb8, 0xd0, 0xe1, 0x12, 0x1c, 0x41, 0x46, 0x6f, 0xd3, 0x5b, 0xd5, 0xb8, 0xd0, 0x5a, 0x6a, 0xd4, 0x4a, 0x98, 0xe3, 0xb0, 0x38, 0x52, 0xd9, 0x56, 0xeb, 0x82, 0xe8, 0x94, 0x83, 0x42, 0xc3, 0x2b, 0xc2, 0x55, 0x7e, 0x7d, 0xe3, 0xe4, 0xab, 0x07, 0xd3, 0x93, 0x5b, 0xd3, 0xd3, 0xd7, 0x4c, 0x28, 0x6e, 0x99, 0x78, 0x4b, 0x78, 0xf2, 0x60, 0xa7, 0xf4, 0x06, 0xa7, 0xb3, 0x16, 0x46, 0xec, 0xe5, 0xd5, 0xa7, 0xe1, 0xbb, 0x27, 0xe3, 0xf5, 0x0d, 0x89, 0xcd, 0x85, 0xa9, 0x69, 0xc9, 0xd4, 0x39, 0xee, 0x92, 0xad, 0x95, 0x7d, 0x2d, 0x41, 0x44, 0x36, 0x43, 0x68, 0xfe, 0x00, 0xd1, 0x6c, 0x00, 0x1e, 0x7c, 0x6a, 0xa4, 0xb8, 0xf0, 0xf4,\n\t0xaa, 0xd9, 0xa1, 0xfb, 0x40, 0x4f, 0xb0, 0x34, 0x18, 0xe6, 0xb4, 0x6e, 0xea, 0xb1, 0x11, 0xb4, 0x04, 0xe5, 0x30, 0x78, 0x38, 0xec, 0x2c, 0x22, 0x8f, 0xf9, 0x00, 0x07, 0xb1, 0x93, 0xde, 0x84, 0x1e, 0x35, 0x90, 0xdd, 0x35, 0xd7, 0xe0, 0x50, 0x76, 0x3c, 0xec, 0xbb, 0x6e, 0x79, 0x03, 0xf3, 0x52, 0xc3, 0xf2, 0xeb, 0x49, 0x50, 0x3a, 0xc9, 0x85, 0xf4, 0x0e, 0x3c, 0xce, 0x71, 0x9d, 0x75, 0xa8, 0x4e, 0x3d, 0xee, 0x2d, 0x40, 0x97, 0xc9, 0xe5, 0x58, 0xd1, 0x22, 0xd1, 0xe7, 0x7b, 0xbb, 0x95, 0x84, 0xa6, 0x7d, 0x6c, 0x4e, 0xec, 0x55, 0xad, 0x27, 0x61, 0x23, 0x72, 0x87, 0x63, 0xcc, 0x07, 0x1d, 0x9f, 0x7d, 0xf8, 0x21, 0x6c, 0x96, 0x2a, 0xe1, 0xcf, 0xf8, 0x3f, 0x3e, 0x7e, 0xf1, 0x13, 0x97, 0x31, 0x2f, 0x5d, 0x8a, 0xcb, 0xae, 0x63, 0x6f, 0x64, 0x9e, 0x16, 0xb6, 0xa0, 0xb5, 0xad,\n\t0x21, 0x5d, 0x6b, 0x45, 0x13, 0x6f, 0x29, 0x92, 0x18, 0xb4, 0x6a, 0x71, 0x58, 0x77, 0x05, 0x3c, 0x07, 0xf8, 0xe5, 0xca, 0x1e, 0x6a, 0xbe, 0x9a, 0xe6, 0x65, 0x01, 0xec, 0xb1, 0x95, 0xc6, 0x4b, 0x43, 0x05, 0x82, 0xd6, 0x8b, 0x23, 0x5c, 0x8d, 0x0a, 0x0c, 0x28, 0x47, 0x4e, 0x57, 0x34, 0xae, 0x3a, 0x6c, 0xef, 0x01, 0xff, 0xe9, 0xd3, 0xc6, 0x1d, 0x0b, 0xfb, 0xae, 0x1f, 0x68, 0xac, 0x1f, 0xdc, 0xb3, 0x60, 0xe1, 0xb5, 0xc9, 0x84, 0x3e, 0x60, 0xb3, 0x96, 0xfc, 0x7f, 0xcc, 0x9d, 0x07, 0x7c, 0x14, 0xe5, 0xfa, 0xef, 0xdf, 0xd9, 0x94, 0xdd, 0xd9, 0x40, 0x20, 0x24, 0x54, 0x43, 0x58, 0x7a, 0x87, 0x50, 0x42, 0x09, 0x2d, 0xf4, 0xde, 0x91, 0x22, 0x45, 0x52, 0x16, 0x12, 0x48, 0x23, 0x09, 0x20, 0x08, 0x22, 0xa0, 0x18, 0x51, 0xb0, 0x71, 0x00, 0x2b, 0xa8, 0x88, 0xe2, 0x51, 0x8f, 0xbd,\n\t0x1d, 0x3d, 0x47, 0xb1, 0x82, 0x82, 0xa2, 0x21, 0x31, 0x01, 0x12, 0x10, 0x36, 0x65, 0x03, 0xa4, 0x90, 0x00, 0xc9, 0x2e, 0x79, 0xef, 0x77, 0x66, 0x27, 0x10, 0x50, 0xcf, 0xd1, 0xfb, 0xbf, 0xf7, 0x73, 0xaf, 0x7c, 0xbe, 0xce, 0xec, 0xec, 0xcc, 0x5b, 0x7f, 0xcf, 0xf3, 0x3e, 0xcf, 0x64, 0x77, 0xb6, 0x63, 0x68, 0x48, 0x9f, 0x99, 0x83, 0x5a, 0xb5, 0x19, 0x32, 0xb3, 0x77, 0x97, 0xa1, 0xc1, 0xb3, 0xfc, 0x1b, 0xfa, 0x58, 0x6b, 0x7e, 0xe8, 0xdc, 0xbe, 0xf6, 0x29, 0x7e, 0xfd, 0xbb, 0x8c, 0x69, 0x68, 0xa9, 0xe7, 0xd7, 0xa8, 0xbe, 0xb9, 0x6d, 0xc4, 0xfc, 0xfe, 0x83, 0x17, 0x45, 0xb4, 0xf1, 0xaf, 0xbf, 0xba, 0x61, 0x3d, 0x51, 0x3b, 0x2e, 0x99, 0xfa, 0xb8, 0xdc, 0xfa, 0x2c, 0xda, 0xa9, 0xfa, 0xb3, 0x68, 0xa7, 0x89, 0x5b, 0xc7, 0xa3, 0xee, 0xb3, 0x68, 0x4d, 0x99, 0xbb, 0x6a, 0x3e,\n\t0xd9, 0xb5, 0x4b, 0x19, 0xe5, 0x9b, 0x7c, 0xad, 0x2d, 0x23, 0xf3, 0xb5, 0xe9, 0x54, 0xcd, 0x61, 0xa5, 0x1f, 0xa5, 0x44, 0x7b, 0x3d, 0x21, 0xaa, 0xb5, 0xa7, 0x38, 0xeb, 0xcf, 0x10, 0xd0, 0x27, 0x57, 0x2f, 0x2c, 0xa0, 0xa1, 0x49, 0x6d, 0xd2, 0x35, 0x90, 0xcb, 0xab, 0x77, 0xed, 0xa2, 0xee, 0x53, 0x9c, 0xdb, 0xdc, 0xeb, 0x21, 0x65, 0x3d, 0xe7, 0x06, 0x6a, 0xf7, 0xf7, 0xcc, 0xc6, 0x77, 0xfb, 0xf5, 0xfa, 0x8d, 0x85, 0x7f, 0xae, 0x98, 0x14, 0xd8, 0xba, 0xdd, 0x0d, 0x3d, 0xb4, 0xa9, 0xbb, 0x02, 0xf5, 0x51, 0xd6, 0x87, 0x0c, 0x5d, 0x30, 0xa4, 0xff, 0x00, 0x55, 0x69, 0xd8, 0xc0, 0x72, 0x5b, 0x50, 0xff, 0x7e, 0xbb, 0xbc, 0x9f, 0x1e, 0x1a, 0x33, 0xb6, 0x63, 0xfd, 0x05, 0xf5, 0x1a, 0xfa, 0x0e, 0x9b, 0xa2, 0x64, 0xd7, 0xf6, 0x33, 0x8f, 0x3a, 0x82, 0xb5, 0x7e, 0xfa, 0x69, 0x77,\n\t0xc8, 0x27, 0x88, 0xeb, 0x1f, 0x3f, 0xd1, 0x9a, 0xe7, 0x8d, 0xcf, 0x98, 0x66, 0xc2, 0xab, 0xb5, 0xef, 0xd8, 0xce, 0xa6, 0xcd, 0x49, 0x60, 0x9f, 0xde, 0xc3, 0xf4, 0x67, 0x37, 0x7a, 0xf9, 0x9a, 0x43, 0x94, 0xa6, 0x81, 0xfa, 0x33, 0xaf, 0x7a, 0x28, 0x7a, 0xff, 0xfb, 0x54, 0x87, 0xb4, 0x0f, 0xf8, 0xd8, 0xbf, 0x65, 0xd3, 0x4d, 0x45, 0x8d, 0x5b, 0x04, 0xb4, 0xac, 0x5f, 0x7a, 0x7f, 0x8b, 0x16, 0xea, 0xa7, 0xd6, 0xdb, 0x9a, 0x76, 0xd9, 0xb9, 0xd3, 0x67, 0x64, 0xd3, 0xcb, 0x8d, 0xfc, 0x6b, 0x32, 0x82, 0xfd, 0xcd, 0x4d, 0x03, 0x6b, 0x5e, 0x6d, 0xe0, 0xaf, 0xf8, 0xfa, 0xfb, 0xd5, 0x7c, 0xa9, 0x1b, 0xac, 0xa7, 0x1d, 0x8d, 0x7d, 0xb5, 0x0f, 0xa4, 0xb5, 0xd2, 0x7f, 0x2a, 0x65, 0xaa, 0xfe, 0x1c, 0x6c, 0xfd, 0xfb, 0xdf, 0x9e, 0xa1, 0xf6, 0x11, 0x3e, 0x01, 0x01, 0xde, 0x8c, 0x91,\n\t0x82, 0xe2, 0xfa, 0x04, 0x98, 0x1a, 0xd7, 0x4c, 0xdd, 0xe9, 0xdd, 0x68, 0x83, 0xe9, 0xd4, 0xb5, 0x17, 0x8c, 0xeb, 0xbd, 0xb6, 0x72, 0x7d, 0x6b, 0xed, 0x6f, 0x87, 0x2d, 0xea, 0xf9, 0xfc, 0xf6, 0x39, 0xc7, 0x75, 0xe7, 0xad, 0xb5, 0xb0, 0xb5, 0x6e, 0x12, 0x16, 0xe0, 0xab, 0x1a, 0xcf, 0x39, 0xee, 0xaf, 0xfd, 0x80, 0x33, 0xab, 0xdd, 0x8d, 0x87, 0x1c, 0x07, 0x7a, 0x1e, 0x72, 0xac, 0xfd, 0x65, 0xc0, 0x6b, 0xeb, 0xfd, 0x5e, 0x3f, 0x35, 0x6c, 0x1f, 0xd4, 0x2e, 0x20, 0xc3, 0x64, 0xba, 0x2f, 0x25, 0x28, 0xc8, 0x7a, 0x54, 0x6d, 0x68, 0xb1, 0x04, 0xa8, 0xdf, 0xab, 0xd8, 0xbe, 0x36, 0xc1, 0xff, 0x6c, 0xd5, 0xa1, 0x26, 0xa5, 0x75, 0x6b, 0xe5, 0x91, 0xc0, 0x76, 0x0d, 0x6a, 0x46, 0x9b, 0x4e, 0x99, 0x03, 0x6a, 0xd6, 0x07, 0x74, 0x0a, 0x6a, 0xdc, 0xa9, 0x91, 0xb2, 0x31, 0xc0, 0x7c,\n\t0x93, 0x9e, 0x82, 0x44, 0xdb, 0x08, 0x9b, 0xaf, 0x72, 0xfd, 0x91, 0xd2, 0x53, 0xf5, 0x47, 0x4a, 0x7b, 0x5a, 0x15, 0x24, 0x82, 0x5a, 0x37, 0x0d, 0xf0, 0x51, 0x9b, 0x7a, 0x3e, 0xc0, 0xd1, 0x51, 0x69, 0x72, 0xfd, 0x91, 0xcb, 0x3d, 0x94, 0x30, 0x44, 0x35, 0x25, 0xa0, 0xb9, 0x5f, 0xcd, 0xe3, 0x5e, 0xf7, 0x4d, 0x09, 0x6a, 0x54, 0x5f, 0x49, 0x36, 0x99, 0xb4, 0xca, 0xeb, 0xf9, 0x2b, 0xdf, 0x77, 0x68, 0x55, 0x73, 0xa7, 0xe9, 0x94, 0xa5, 0x61, 0x4d, 0xef, 0xa0, 0xf6, 0x01, 0xca, 0x33, 0xc2, 0xf0, 0x25, 0x77, 0xeb, 0x7e, 0xf8, 0x0f, 0xd6, 0x81, 0xa9, 0x9a, 0xc5, 0x4d, 0xfb, 0xdd, 0x75, 0x40, 0xbd, 0xb1, 0x0e, 0x34, 0xbe, 0xb1, 0x0e, 0x10, 0xff, 0x29, 0x77, 0x8c, 0x1b, 0x31, 0x72, 0xec, 0xe2, 0xc5, 0x13, 0x13, 0xc6, 0xb6, 0x69, 0x3b, 0x2e, 0x61, 0xfc, 0xe2, 0x9d, 0x3e, 0x3e,\n\t0x23, 0x06, 0xf7, 0x1b, 0x5e, 0xa9, 0x2c, 0x6f, 0x37, 0x6c, 0x4e, 0x9f, 0x7e, 0xf3, 0x23, 0xda, 0xb9, 0xf4, 0xf9, 0xf4, 0xd4, 0xff, 0xaa, 0x5e, 0x7f, 0x2b, 0xed, 0x7b, 0x76, 0x2d, 0x75, 0x65, 0xf9, 0xd6, 0x7e, 0xb2, 0xa9, 0x36, 0xfa, 0xbe, 0x2e, 0x2f, 0xed, 0xcb, 0xf1, 0x81, 0x8d, 0x02, 0x1a, 0xf8, 0xa9, 0xbf, 0xd3, 0x06, 0x3d, 0x99, 0xaa, 0x55, 0x58, 0xad, 0xc7, 0x6d, 0xaa, 0x8c, 0x9b, 0x30, 0x72, 0xf4, 0xd8, 0xa9, 0xca, 0x9b, 0x0f, 0xb4, 0x0f, 0x7c, 0xd8, 0xd2, 0x24, 0xa8, 0xcf, 0x4e, 0xc7, 0xa4, 0x84, 0x31, 0xb6, 0xa9, 0x13, 0x5b, 0x06, 0xf9, 0x34, 0x19, 0xdd, 0xa7, 0xcf, 0xc0, 0x73, 0x35, 0xeb, 0x43, 0x72, 0x91, 0x58, 0xb1, 0xe9, 0x94, 0x6d, 0xe0, 0xd4, 0x9e, 0xe3, 0x13, 0x5b, 0x04, 0x84, 0xe8, 0x73, 0xd1, 0x82, 0xb6, 0x2d, 0xa4, 0x6d, 0x66, 0xed, 0x77, 0x95,\n\t0x4d, 0xb5, 0xbf, 0x72, 0x3c, 0x55, 0x8b, 0x8a, 0xa6, 0x29, 0x9e, 0xa7, 0x33, 0x68, 0xc2, 0xa8, 0x7d, 0xa4, 0xc8, 0xc2, 0xcc, 0x5d, 0x99, 0xa6, 0x91, 0x3e, 0x97, 0xae, 0xed, 0x35, 0x2d, 0x5e, 0xaf, 0x5d, 0x7f, 0x87, 0xee, 0xd7, 0x92, 0xaf, 0x3f, 0xa3, 0x4a, 0xb7, 0x12, 0x23, 0x80, 0x99, 0xab, 0xf5, 0xa5, 0x51, 0x40, 0x3d, 0x2b, 0xee, 0x4d, 0x7b, 0x46, 0x95, 0xd1, 0x0f, 0xed, 0x33, 0x38, 0xc6, 0xdd, 0x0c, 0xfd, 0xe3, 0x38, 0xca, 0xf6, 0x89, 0x33, 0x76, 0x76, 0x9d, 0x9a, 0x32, 0x76, 0x5c, 0xca, 0xd4, 0xae, 0x3b, 0x67, 0x7a, 0x37, 0x5c, 0x30, 0x4d, 0x79, 0xb7, 0x66, 0xd2, 0xc8, 0xe4, 0xe9, 0xdd, 0xbb, 0x4f, 0x4f, 0x1e, 0xa9, 0xed, 0x4f, 0x5b, 0xa0, 0x7f, 0xe7, 0xd7, 0xeb, 0x09, 0xef, 0xc1, 0xd4, 0xd5, 0x51, 0xbb, 0xff, 0x6d, 0x0b, 0xd4, 0x9f, 0x45, 0xee, 0xf9, 0x41,\n\t0xf2, 0xba, 0xca, 0xe1, 0xdd, 0xf0, 0xd6, 0xcd, 0x3c, 0x7a, 0xf6, 0x6a, 0x5b, 0xfb, 0xa3, 0xe4, 0xda, 0x1d, 0x7f, 0x5d, 0xc8, 0xfd, 0x34, 0x1d, 0x0f, 0x52, 0x34, 0x59, 0x37, 0xa9, 0x55, 0xb5, 0xf7, 0xe0, 0x5f, 0x1f, 0xdc, 0xa9, 0xe5, 0x04, 0xbe, 0xde, 0xbb, 0xd3, 0xcf, 0xde, 0xd3, 0xd9, 0x9a, 0xe2, 0x63, 0xf6, 0xb1, 0xd4, 0xbb, 0xdf, 0xa7, 0x79, 0x50, 0xb7, 0xa0, 0xa6, 0xe6, 0xfb, 0xea, 0x59, 0x48, 0x8e, 0x53, 0xbd, 0x6e, 0x0b, 0xd4, 0x15, 0x9e, 0xe3, 0xd7, 0xcc, 0xdf, 0xbf, 0x99, 0x5f, 0x4d, 0x07, 0xd3, 0xa9, 0x36, 0x35, 0xcb, 0x1a, 0x75, 0x6a, 0xda, 0xbd, 0x9d, 0xb2, 0xb3, 0x7e, 0xe3, 0xc0, 0x06, 0x35, 0xcb, 0xda, 0x74, 0x6d, 0xdc, 0x31, 0x40, 0xd9, 0xe9, 0x1f, 0xa4, 0x8f, 0xed, 0x17, 0x5e, 0x47, 0x4c, 0x8d, 0x7c, 0x27, 0x08, 0x55, 0x7b, 0xfe, 0xa1, 0xfe, 0xa9,\n\t0x73, 0xed, 0xc1, 0xcc, 0x71, 0x0a, 0x2b, 0xbc, 0xf6, 0xe0, 0x3a, 0xcf, 0x97, 0x43, 0x9a, 0x98, 0xbd, 0xf4, 0x1f, 0xff, 0x56, 0xbe, 0xe9, 0xd8, 0xae, 0xe1, 0x47, 0xbe, 0xcd, 0x02, 0x6f, 0xdf, 0xe4, 0x3b, 0xa1, 0x5f, 0x87, 0x1a, 0xef, 0xfa, 0xcd, 0x4c, 0xeb, 0x3d, 0x71, 0x0c, 0xe5, 0x78, 0x3d, 0xab, 0x97, 0x13, 0xa8, 0x59, 0x8c, 0xe7, 0xb9, 0x78, 0x22, 0x45, 0x1b, 0xed, 0x38, 0xed, 0x69, 0x78, 0x8d, 0x1a, 0x6a, 0x4f, 0xc3, 0xf3, 0x14, 0xea, 0x7b, 0x53, 0xa1, 0xad, 0x7f, 0xaf, 0x78, 0x53, 0xfd, 0xdf, 0xa9, 0xe9, 0x46, 0x8d, 0x8a, 0x88, 0xf4, 0x8e, 0x53, 0x42, 0x7d, 0xf2, 0x3d, 0xdf, 0x67, 0xf3, 0xdc, 0xbb, 0xd2, 0x8c, 0x54, 0xff, 0xfc, 0x85, 0xe7, 0x2b, 0x09, 0x42, 0xff, 0x3e, 0x9b, 0xe7, 0x79, 0x12, 0x75, 0x3f, 0x45, 0xa2, 0x9d, 0x55, 0xf7, 0xfb, 0x6c, 0x9e, 0xcf,\n\t0x64, 0x34, 0xae, 0x5d, 0xb4, 0x94, 0xd0, 0x1e, 0x7d, 0xfb, 0xf6, 0xe8, 0x32, 0x71, 0x60, 0xeb, 0xd6, 0x03, 0x27, 0x76, 0xf1, 0x49, 0xef, 0xd7, 0xad, 0x6b, 0xbf, 0x05, 0xda, 0x53, 0x4b, 0xba, 0x8e, 0xe9, 0x13, 0xec, 0x89, 0x35, 0xff, 0x5f, 0xd6, 0x3d, 0xc8, 0x6b, 0x87, 0xa9, 0xb9, 0xef, 0x6a, 0xac, 0xb4, 0x57, 0x44, 0x8f, 0xfa, 0xac, 0xfe, 0x2d, 0x6f, 0x8e, 0x73, 0xa9, 0x7d, 0x85, 0xd0, 0x9f, 0xf7, 0x26, 0xae, 0x3f, 0xee, 0xad, 0x59, 0xdb, 0x0e, 0x1d, 0xf5, 0xbb, 0x9d, 0x3d, 0x94, 0xdf, 0x44, 0xb7, 0xbe, 0x9e, 0xe0, 0xb6, 0xed, 0xe5, 0xf9, 0x8b, 0x3b, 0x8f, 0x8d, 0x1c, 0xd0, 0x7c, 0xe0, 0x80, 0xb0, 0x26, 0x9d, 0x2c, 0x01, 0xf5, 0x5a, 0xb4, 0xee, 0x1a, 0x12, 0x31, 0x2a, 0xa8, 0xfb, 0xd8, 0xbe, 0x5b, 0xbd, 0xb7, 0xd8, 0xd2, 0x67, 0x0e, 0x5e, 0x30, 0xd4, 0x66, 0x09,\n\t0x6a, 0xd3, 0xa2, 0x4f, 0x7d, 0xff, 0x86, 0xfe, 0x63, 0xc6, 0xd9, 0xc2, 0x7b, 0xb6, 0x31, 0xd7, 0x1c, 0xd2, 0xef, 0x85, 0x49, 0xed, 0x23, 0x2f, 0x67, 0xb4, 0xdf, 0xd4, 0xf1, 0x7a, 0x56, 0x7f, 0xc6, 0xe8, 0xf9, 0x6b, 0xaf, 0xdd, 0xfc, 0xfb, 0xd9, 0xda, 0xef, 0x5f, 0x68, 0xe7, 0x68, 0xbf, 0x35, 0xa2, 0x9d, 0xa3, 0xff, 0xd6, 0xc8, 0x45, 0xed, 0xda, 0x6b, 0x9f, 0xeb, 0xd7, 0x1e, 0xac, 0x3d, 0xee, 0x13, 0x71, 0xad, 0xb5, 0x7e, 0xfc, 0xbd, 0x5b, 0x8e, 0x8f, 0xb8, 0xd6, 0x51, 0xff, 0x1d, 0xe3, 0x50, 0xbd, 0x9c, 0xef, 0xae, 0x1f, 0x1f, 0x7e, 0x4d, 0x7f, 0xa6, 0x6a, 0x8d, 0xb3, 0x6e, 0x1b, 0xb4, 0xdf, 0x55, 0xba, 0xf6, 0x9c, 0x7e, 0x3c, 0xe3, 0x96, 0xe3, 0x83, 0xae, 0x55, 0x88, 0x1b, 0xed, 0x79, 0xf1, 0x7a, 0x7b, 0x3e, 0xf4, 0xb4, 0xc7, 0x73, 0xdc, 0x1c, 0x78, 0xfd, 0xf8,\n\t0xc7, 0x9e, 0xe3, 0x35, 0x3f, 0xdd, 0xd2, 0x9e, 0x81, 0x5a, 0xbd, 0xcc, 0xc7, 0x5b, 0x35, 0x2f, 0xf9, 0xb6, 0xd6, 0x7f, 0xf3, 0xbd, 0x4f, 0x44, 0x28, 0x8b, 0x9e, 0xc9, 0xec, 0x63, 0x8a, 0xd4, 0x3e, 0xcc, 0x10, 0x3d, 0xd1, 0xa2, 0x98, 0xcd, 0xca, 0x1d, 0x9a, 0x05, 0xd4, 0xfe, 0xfa, 0x2a, 0xff, 0x6f, 0x84, 0xb3, 0xd1, 0xff, 0x6b, 0xab, 0x65, 0x49, 0xed, 0x03, 0x82, 0x7c, 0x6f, 0x0a, 0x44, 0xfa, 0x04, 0xf8, 0xb6, 0xee, 0x10, 0x72, 0x4f, 0xf1, 0xb5, 0xc0, 0xcc, 0x4c, 0xd3, 0x85, 0xe3, 0x2f, 0xd7, 0x0c, 0x0e, 0x6e, 0xa3, 0xcc, 0x37, 0x3d, 0x70, 0x6d, 0x8d, 0xcf, 0x33, 0xd7, 0xb6, 0x98, 0xd6, 0xba, 0xfc, 0x68, 0xe3, 0x4c, 0x59, 0xe6, 0x33, 0x59, 0x1f, 0xcb, 0x9f, 0x8c, 0xdf, 0x65, 0x69, 0x5c, 0xfb, 0x7c, 0x60, 0x9f, 0x62, 0xfd, 0x78, 0x86, 0x71, 0x7c, 0x97, 0xe7, 0x79,\n\t0xf7, 0x35, 0xff, 0xf4, 0x5e, 0xe3, 0x4d, 0xd0, 0x2e, 0x86, 0x8b, 0x13, 0x11, 0xfe, 0x5d, 0x14, 0x5f, 0x9f, 0xfe, 0x58, 0x7a, 0x23, 0x6d, 0xb5, 0x35, 0xee, 0x2c, 0xf5, 0x12, 0xbe, 0x3e, 0xde, 0x3e, 0xbe, 0xde, 0xc9, 0xc2, 0xdb, 0xaa, 0x7f, 0x6d, 0x31, 0x12, 0x6f, 0xaf, 0x27, 0xdc, 0x89, 0x13, 0x6b, 0x55, 0x1d, 0x7f, 0xe3, 0x7e, 0x5c, 0xec, 0xf5, 0xdb, 0x77, 0x7f, 0xe6, 0xc2, 0xa4, 0x9b, 0x2f, 0x8c, 0x18, 0x70, 0xfd, 0x1a, 0xd5, 0xcb, 0xe2, 0xa5, 0xdd, 0xd0, 0xfb, 0x4f, 0xd7, 0x8a, 0x1b, 0x97, 0xce, 0x9b, 0x17, 0xd1, 0x42, 0x88, 0x61, 0x43, 0x06, 0x87, 0x87, 0xf6, 0xe8, 0xd4, 0xa1, 0x6d, 0xeb, 0x96, 0xb7, 0x35, 0x0e, 0xac, 0xef, 0xa7, 0xa5, 0x23, 0xed, 0xf4, 0x9f, 0xc7, 0xb8, 0xf5, 0xa6, 0x9e, 0xaf, 0x27, 0x14, 0xed, 0xd7, 0xa7, 0xb5, 0x27, 0x06, 0xad, 0x9b, 0x88,\n\t0xfa, 0x9a, 0x6f, 0xdc, 0xda, 0xab, 0x6a, 0x1d, 0xb1, 0x70, 0xd0, 0xdd, 0xdb, 0x1b, 0x29, 0xf1, 0xc6, 0x4d, 0xbd, 0x45, 0x69, 0x0b, 0x9f, 0x4d, 0x89, 0x08, 0xbc, 0xcd, 0xf4, 0x94, 0x57, 0x8f, 0xe9, 0xc9, 0xa3, 0x87, 0x2f, 0x1a, 0x1d, 0x4a, 0x7e, 0x3a, 0xa0, 0xdd, 0xa2, 0x65, 0x2b, 0xfa, 0xc7, 0xbd, 0xb3, 0x79, 0x7c, 0xef, 0xd0, 0xda, 0x1f, 0xcb, 0x50, 0xb6, 0x85, 0x47, 0x8d, 0xeb, 0xb4, 0xfd, 0x9e, 0x6b, 0x33, 0x3d, 0x3f, 0x79, 0xd1, 0xb6, 0xeb, 0x90, 0xb4, 0x03, 0x09, 0x3d, 0x5a, 0xcd, 0x4f, 0x9f, 0xd7, 0xed, 0x7a, 0xc2, 0x3a, 0x76, 0xeb, 0x77, 0xf7, 0x2d, 0x7c, 0x61, 0xc4, 0x27, 0x9e, 0x9b, 0x7c, 0xfa, 0x5c, 0x4d, 0x90, 0xe5, 0x5e, 0x19, 0xda, 0x6f, 0x16, 0x78, 0x0b, 0xe3, 0x77, 0x21, 0xee, 0xbf, 0xfe, 0x2c, 0xe1, 0x36, 0xfa, 0x71, 0x93, 0x71, 0xfc, 0xef, 0xfa,\n\t0x7d, 0x82, 0x52, 0xef, 0x91, 0x5e, 0xa1, 0x3e, 0xf7, 0x93, 0x69, 0x2c, 0xf5, 0xdc, 0x62, 0x6d, 0xac, 0x7f, 0x45, 0x77, 0xa9, 0xfe, 0xd5, 0x0d, 0xdc, 0x4c, 0x0c, 0x23, 0xd4, 0x5c, 0x9f, 0x95, 0x6e, 0xfa, 0xe7, 0xb3, 0x71, 0x3e, 0xa9, 0xb7, 0xbe, 0x17, 0x71, 0x9b, 0xfe, 0x80, 0x2f, 0xe3, 0xbd, 0xda, 0xaf, 0xad, 0x2c, 0xd0, 0xbf, 0xfb, 0xa1, 0x3d, 0x56, 0xa8, 0x9e, 0xe7, 0x67, 0x41, 0x49, 0x59, 0x7c, 0x7c, 0x9b, 0x92, 0x2f, 0x5c, 0x0f, 0xe4, 0x5b, 0x87, 0x5d, 0xbf, 0xa1, 0xf6, 0xe2, 0xc0, 0x66, 0xdd, 0xda, 0x04, 0x05, 0xb6, 0xe9, 0xd6, 0xc2, 0xd4, 0xc8, 0xd8, 0xed, 0xde, 0xdc, 0x7b, 0xcf, 0x02, 0xff, 0x96, 0x5d, 0x5a, 0xb6, 0xea, 0x16, 0x5c, 0x9f, 0x9d, 0xae, 0xc1, 0xda, 0x8e, 0xf6, 0xe1, 0x4d, 0x5f, 0xe1, 0x15, 0x6a, 0x6e, 0x88, 0x4d, 0x69, 0x9f, 0x0f, 0xf3, 0xf2,\n\t0xd1, 0x9e, 0xa4, 0x20, 0xea, 0x3e, 0x5f, 0xca, 0x5b, 0xcb, 0xf1, 0xa6, 0x2a, 0x22, 0xb0, 0x51, 0x43, 0x7f, 0xd5, 0x62, 0xf6, 0x15, 0x4d, 0x95, 0xa6, 0xbe, 0x9e, 0xef, 0x3a, 0x79, 0x93, 0xab, 0x0d, 0xf5, 0xd6, 0x3e, 0xd8, 0xa3, 0x3d, 0x2d, 0xd2, 0xd4, 0xba, 0xcb, 0x84, 0x09, 0x93, 0x17, 0x24, 0x8d, 0x19, 0x1c, 0x33, 0x67, 0xfa, 0xcc, 0x3b, 0xfa, 0x6d, 0x59, 0xfb, 0x70, 0x93, 0x76, 0x3d, 0x7d, 0x77, 0x36, 0x69, 0xd3, 0xa1, 0x4d, 0x93, 0xbb, 0x9a, 0xd2, 0xe2, 0xa6, 0xdb, 0x36, 0x77, 0x19, 0xd8, 0x56, 0x7f, 0xca, 0x17, 0x99, 0xca, 0x26, 0xc6, 0xea, 0x71, 0xea, 0xd5, 0x9f, 0x69, 0xa6, 0xd7, 0x72, 0xa7, 0x4f, 0xed, 0xcf, 0x72, 0x35, 0x17, 0x93, 0x6e, 0xa9, 0xd1, 0xf7, 0x4f, 0xd7, 0xe8, 0xd3, 0xec, 0xb7, 0x35, 0xfe, 0x3f, 0xeb, 0xa7, 0xd2, 0xc9, 0xe7, 0xac, 0x29, 0xd0,\n\t0x1c, 0x41, 0xe6, 0xce, 0x3a, 0x14, 0xa0, 0x3d, 0x6c, 0x4a, 0xf7, 0xfc, 0x4b, 0x6f, 0x5d, 0x70, 0xb4, 0xbf, 0xe1, 0xe0, 0x06, 0x52, 0x7f, 0xb3, 0x10, 0xbd, 0xd7, 0xb7, 0x83, 0xe7, 0xd9, 0x70, 0x86, 0x99, 0xe8, 0xcf, 0x4f, 0xf4, 0xfc, 0x0a, 0x67, 0xd3, 0x26, 0x8d, 0x4d, 0x62, 0xc0, 0xf4, 0xb0, 0x16, 0x23, 0x06, 0xf7, 0x1d, 0xd8, 0x7b, 0xb0, 0xa5, 0xbe, 0xaf, 0x77, 0x87, 0xb6, 0x9d, 0x7d, 0xce, 0xb6, 0x1d, 0x34, 0xb9, 0xcb, 0xc8, 0xd1, 0xe1, 0xdd, 0xdb, 0xf7, 0x57, 0x94, 0xf6, 0x1d, 0x2c, 0x96, 0x66, 0x5a, 0x3b, 0xbc, 0xed, 0xa6, 0x40, 0x9f, 0x83, 0xb4, 0x63, 0x86, 0xa7, 0x1d, 0x01, 0x46, 0x3b, 0x8c, 0x84, 0xd8, 0xa6, 0xeb, 0xb2, 0x87, 0xe7, 0x87, 0x74, 0xb5, 0x76, 0xd4, 0x39, 0xfe, 0x47, 0x4d, 0xf3, 0xb4, 0xcd, 0xf7, 0x2f, 0xb4, 0xcd, 0xdb, 0xfe, 0xbb, 0x6d, 0xfb,\n\t0xff, 0x65, 0x8c, 0x7c, 0xf2, 0x68, 0xc7, 0x60, 0xda, 0x31, 0xfa, 0x3d, 0x1f, 0xc5, 0xf3, 0xad, 0x77, 0x4f, 0x73, 0xb4, 0x4f, 0x46, 0x2c, 0xbd, 0xf5, 0x4f, 0xec, 0x5a, 0x73, 0x58, 0xba, 0x53, 0x7f, 0xf3, 0xa4, 0xcd, 0xf7, 0x9a, 0xb4, 0xeb, 0xa8, 0x37, 0xa7, 0xaf, 0xf6, 0x75, 0x77, 0xe3, 0x2b, 0x58, 0xd7, 0x9f, 0xc5, 0xa8, 0x0c, 0xea, 0xdc, 0xa1, 0xbd, 0xc9, 0xb7, 0xbe, 0x65, 0x70, 0xef, 0x81, 0x7d, 0x07, 0x8f, 0x68, 0x11, 0x36, 0xa3, 0xbf, 0xaf, 0xa5, 0x99, 0xc5, 0xd2, 0xa1, 0xa3, 0xc9, 0xd4, 0xbf, 0x7d, 0xf7, 0xf0, 0xe9, 0x23, 0xbb, 0x4c, 0xe8, 0xd7, 0x4a, 0xd7, 0x8e, 0x77, 0x24, 0x73, 0xf6, 0x2f, 0xed, 0x6f, 0x7f, 0x37, 0xb5, 0x27, 0xc0, 0x68, 0x8f, 0xf1, 0xfd, 0x61, 0x9b, 0xe7, 0x7b, 0x81, 0x7a, 0x53, 0x6e, 0x1c, 0xf2, 0xb4, 0xc2, 0xf7, 0x2f, 0xb4, 0xc2, 0x7b,\n\t0x2b, 0xad, 0x68, 0xdf, 0xe9, 0xe6, 0x56, 0x88, 0xff, 0xdf, 0xc6, 0x05, 0xff, 0x1b, 0x2d, 0x4b, 0x2d, 0x3e, 0xbe, 0x17, 0xf1, 0xbf, 0xda, 0xed, 0x7e, 0xb3, 0xcf, 0x63, 0xa6, 0x17, 0x95, 0x7d, 0x9e, 0x58, 0x46, 0xd9, 0x67, 0xc4, 0x32, 0x04, 0x58, 0x3e, 0x6f, 0x6a, 0xbf, 0xf5, 0xe3, 0x3d, 0x51, 0x8f, 0x05, 0x1e, 0x53, 0xd6, 0xd6, 0xfe, 0x6e, 0x9a, 0x75, 0x83, 0xf9, 0x36, 0xd1, 0x41, 0xa8, 0x7a, 0x8c, 0xdf, 0xcd, 0xd7, 0xec, 0xf9, 0xdb, 0xa0, 0xef, 0x39, 0xe3, 0xb7, 0xdd, 0xcb, 0xcd, 0x87, 0x7d, 0xbe, 0xd4, 0x3e, 0x47, 0xae, 0xbf, 0xff, 0xb0, 0xf7, 0x7a, 0xfd, 0xfd, 0x37, 0xbd, 0x0f, 0xd5, 0x5e, 0xaf, 0x8e, 0xd4, 0x7f, 0xdb, 0xd7, 0x73, 0xfd, 0xc3, 0x3e, 0x97, 0x3d, 0xef, 0xfb, 0x8e, 0xd0, 0xfd, 0x9a, 0x4d, 0x3e, 0xe1, 0xfb, 0xbd, 0xcf, 0x29, 0x31, 0x5c, 0x59, 0xe8,\n\t0x59, 0x03, 0x9a, 0x84, 0x33, 0xa2, 0xe6, 0xfe, 0x8d, 0x83, 0x48, 0xb4, 0x4d, 0x4d, 0x14, 0x45, 0x6d, 0x85, 0xc7, 0xf7, 0x9e, 0x70, 0xdb, 0x4d, 0x6f, 0xf8, 0xdc, 0x78, 0x63, 0xde, 0xc4, 0x37, 0x1b, 0x73, 0x59, 0xb8, 0xf0, 0xb5, 0x0a, 0xab, 0xaf, 0x60, 0xfd, 0x45, 0xe2, 0xaa, 0xc2, 0xfa, 0xab, 0x78, 0xa7, 0x6a, 0xf7, 0xd5, 0xed, 0x13, 0x2d, 0x3e, 0x26, 0xe3, 0xfe, 0x68, 0xa2, 0x67, 0xdf, 0x3c, 0x8f, 0xf5, 0x78, 0x89, 0x7e, 0x13, 0xd0, 0xf3, 0x5b, 0x15, 0x5a, 0xc5, 0x43, 0x7f, 0xb7, 0x04, 0xe1, 0xe7, 0x67, 0x9f, 0x28, 0xfe, 0x5c, 0x29, 0x36, 0xfd, 0x17, 0x2f, 0xae, 0x97, 0xe2, 0xa3, 0xf8, 0xfc, 0xb6, 0x14, 0x71, 0xa3, 0x0c, 0x85, 0xc0, 0xe0, 0xe6, 0x22, 0x22, 0x86, 0xff, 0xd1, 0xd5, 0xfa, 0xc7, 0x8d, 0xb5, 0x98, 0xeb, 0xbf, 0x95, 0x31, 0x8f, 0x35, 0xaf, 0xd1, 0xf0,\n\t0x61, 0x03, 0x07, 0x90, 0xef, 0x05, 0x74, 0x6a, 0xdc, 0x39, 0xa8, 0x6d, 0xe3, 0xd6, 0xda, 0x5f, 0x0c, 0x94, 0x7e, 0x37, 0x7d, 0x56, 0xb8, 0x81, 0x16, 0xa0, 0x79, 0x35, 0xd5, 0x6e, 0x74, 0xea, 0x9f, 0x12, 0xd2, 0x72, 0x7b, 0xfd, 0x23, 0x6e, 0x9e, 0x2c, 0x4d, 0xff, 0xd9, 0xc6, 0x20, 0xf2, 0x5b, 0x82, 0x37, 0xa2, 0x8b, 0x41, 0x8a, 0x8f, 0x32, 0x60, 0xe8, 0xac, 0x0d, 0xb3, 0xbb, 0x7d, 0x19, 0xb3, 0x74, 0xf4, 0x9a, 0xb0, 0xc0, 0x2f, 0x8a, 0x43, 0x5b, 0xcf, 0xea, 0x69, 0x6b, 0x1a, 0x61, 0xbb, 0x7d, 0xc2, 0xdc, 0x85, 0xab, 0x02, 0x9a, 0xbe, 0xd4, 0xcd, 0xbb, 0x69, 0xa3, 0x68, 0xc5, 0x56, 0x73, 0xba, 0x5f, 0x57, 0xe5, 0xf1, 0x2f, 0x94, 0x25, 0x7e, 0x8d, 0x82, 0x9a, 0x35, 0x4a, 0xf0, 0xba, 0x12, 0x30, 0xc0, 0xbe, 0x7d, 0xf6, 0xb5, 0x35, 0xa6, 0x07, 0x12, 0xd6, 0x0c, 0xee,\n\t0xdb, 0xe2, 0x5a, 0x4b, 0x25, 0xbb, 0xe6, 0xb3, 0xc9, 0x21, 0x5d, 0xac, 0xdd, 0x6c, 0xb7, 0xd9, 0x83, 0xee, 0x5b, 0x66, 0x5a, 0xdc, 0xb8, 0xf1, 0xd4, 0xa6, 0x4a, 0xcf, 0x80, 0xc0, 0x9a, 0xbf, 0x6f, 0xbf, 0xf6, 0xfa, 0xc0, 0xc1, 0x26, 0x53, 0x3b, 0xaf, 0x86, 0xd7, 0xaa, 0x95, 0xa2, 0x06, 0x8d, 0xeb, 0xf9, 0x0a, 0x5f, 0xd1, 0x53, 0xee, 0xf5, 0x09, 0xf0, 0xc9, 0x15, 0x56, 0xed, 0xbb, 0x40, 0x62, 0x88, 0x58, 0x28, 0x36, 0x2a, 0xde, 0xef, 0xb5, 0x52, 0x7c, 0xcd, 0xb5, 0xdf, 0x37, 0x1c, 0x68, 0xd5, 0xee, 0xe8, 0x7b, 0x99, 0x62, 0x2d, 0x8a, 0xb7, 0x9f, 0x1a, 0x40, 0x62, 0x4a, 0x9e, 0x16, 0xdd, 0x50, 0x4b, 0x4c, 0xcd, 0x8a, 0x88, 0x6e, 0x44, 0xf0, 0xee, 0x5b, 0xdf, 0xec, 0x1b, 0x2d, 0xea, 0x8b, 0x06, 0xf5, 0x1b, 0xdc, 0x29, 0xea, 0xd5, 0xf3, 0x9f, 0x2f, 0xfc, 0xfd, 0xed,\n\t0xf5, 0xb4, 0x29, 0xeb, 0x44, 0x01, 0xc3, 0x6a, 0x0b, 0x10, 0xfe, 0xa2, 0x9e, 0xb7, 0x7f, 0xbd, 0xe8, 0xff, 0x5a, 0x50, 0x83, 0x06, 0xf5, 0xe7, 0x88, 0xfa, 0xf5, 0x1b, 0xcc, 0xd7, 0x4a, 0xc4, 0x7e, 0x23, 0x8c, 0x12, 0x98, 0xaf, 0xff, 0xbd, 0x22, 0x98, 0xb4, 0x1e, 0x21, 0x21, 0xda, 0x0f, 0x36, 0xae, 0x4a, 0x8b, 0x89, 0x9a, 0x35, 0x63, 0xd4, 0x08, 0xe2, 0xc1, 0x01, 0xda, 0x6f, 0xa5, 0x85, 0x74, 0x09, 0xe9, 0xd2, 0xbe, 0xad, 0x5f, 0x4b, 0xbf, 0x96, 0xcd, 0x9a, 0x04, 0x06, 0x34, 0xa8, 0xaf, 0xff, 0x88, 0x63, 0x60, 0xed, 0x43, 0x73, 0x35, 0xff, 0xdd, 0x51, 0x77, 0xdd, 0x61, 0xfa, 0xec, 0x69, 0xb7, 0x62, 0x5b, 0x2a, 0x81, 0x37, 0x7e, 0xf9, 0x5c, 0xff, 0x23, 0x9a, 0xf6, 0x07, 0x75, 0xcf, 0x97, 0xbd, 0x39, 0x4d, 0x31, 0xfe, 0x80, 0xd1, 0x52, 0xd1, 0x1f, 0x08, 0x57, 0xfb,\n\t0x97, 0x46, 0x68, 0x6f, 0xe4, 0x51, 0x2d, 0xb5, 0xa2, 0x29, 0xc2, 0x5b, 0xfb, 0x72, 0xb8, 0xf6, 0xf7, 0x8e, 0x30, 0x2f, 0xdf, 0x86, 0xc1, 0xed, 0x1b, 0x37, 0x6e, 0x1f, 0xdc, 0x70, 0x70, 0xbb, 0x16, 0x2d, 0xda, 0x86, 0x76, 0xe9, 0xa4, 0x04, 0x06, 0xb6, 0x6a, 0xec, 0x77, 0x25, 0xa0, 0xeb, 0xf8, 0x01, 0x03, 0xc6, 0x75, 0x09, 0xa8, 0xf4, 0x6b, 0xdc, 0x2a, 0x50, 0x09, 0xec, 0xd4, 0x25, 0xb4, 0x6d, 0x8b, 0x16, 0xed, 0x62, 0x95, 0x0f, 0xc7, 0x6e, 0xfa, 0x70, 0xc5, 0x8a, 0x0f, 0x37, 0x8d, 0x6d, 0xde, 0xb2, 0x79, 0x44, 0xf2, 0x53, 0xf3, 0xe6, 0x3d, 0xb9, 0x22, 0x82, 0x5d, 0xd7, 0xb3, 0xb7, 0x3f, 0x5f, 0xf8, 0xc4, 0x13, 0x85, 0xcf, 0xdf, 0xde, 0xa4, 0x45, 0x93, 0x16, 0x03, 0xe6, 0xac, 0x7b, 0xde, 0x6e, 0x7f, 0x7e, 0xdd, 0x9c, 0x01, 0xbc, 0x68, 0xa2, 0x7c, 0xd7, 0xb8, 0xc3,\n\t0x6d, 0x0d, 0x1b, 0xde, 0xd6, 0xa1, 0xf1, 0x47, 0x2d, 0xda, 0xb5, 0x6b, 0xd1, 0xab, 0xdd, 0x6d, 0xbe, 0x8d, 0x5a, 0x35, 0xb7, 0xd5, 0xfc, 0xad, 0x69, 0xc3, 0x76, 0xad, 0x82, 0x82, 0x5a, 0xb5, 0x6b, 0xd8, 0x54, 0x79, 0xa8, 0x79, 0xab, 0x46, 0xbe, 0xb7, 0xb5, 0xeb, 0xa5, 0x9d, 0xa0, 0x34, 0x49, 0xd8, 0x97, 0x34, 0x60, 0x40, 0xd2, 0xbe, 0x84, 0x97, 0x6d, 0x53, 0x63, 0xd6, 0x4e, 0x1c, 0x77, 0xf7, 0x1d, 0xbd, 0x7b, 0xdf, 0x71, 0xf7, 0xb8, 0x89, 0x6b, 0x63, 0xa6, 0xda, 0x5e, 0xde, 0x9c, 0xb9, 0x7b, 0xe6, 0xcc, 0xdd, 0x99, 0x9b, 0x5f, 0x0e, 0x9f, 0x3f, 0x67, 0xf1, 0xd0, 0xee, 0xb1, 0xf6, 0x85, 0xe3, 0xba, 0x74, 0x19, 0xb7, 0xd0, 0xbe, 0xb4, 0xc7, 0xd0, 0xc5, 0x73, 0xe6, 0x87, 0x0b, 0xfd, 0xbf, 0x36, 0xca, 0x73, 0xfa, 0xaf, 0x12, 0x69, 0xff, 0x7d, 0xa1, 0x7b, 0x23, 0x4f,\n\t0x3e, 0xea, 0xcd, 0x2b, 0xcf, 0xbe, 0x09, 0x05, 0x7e, 0x63, 0xec, 0x7b, 0xe1, 0xcf, 0x8f, 0x18, 0xfb, 0xde, 0xc2, 0x4f, 0x9c, 0x35, 0xf6, 0x7d, 0x44, 0x5f, 0xf2, 0x29, 0xcf, 0xbe, 0xaf, 0xf0, 0x53, 0xda, 0x18, 0xfb, 0x66, 0x11, 0xaa, 0x74, 0x37, 0xf6, 0x2d, 0xa2, 0x99, 0xb2, 0xd0, 0xd8, 0x57, 0x45, 0x7f, 0x65, 0xa5, 0xb1, 0x6f, 0xf5, 0x4e, 0x55, 0x5e, 0x33, 0xf6, 0xfd, 0x44, 0x33, 0xdf, 0x56, 0xc6, 0x7e, 0x3d, 0xd1, 0xdc, 0xb7, 0xbf, 0xb1, 0x5f, 0xbf, 0x4e, 0xdb, 0xfc, 0x45, 0x0b, 0xdf, 0x69, 0xc6, 0x7e, 0xc3, 0x3a, 0xed, 0x0c, 0xd0, 0xdb, 0xa9, 0x7d, 0xe7, 0x1f, 0x2f, 0xab, 0x6c, 0xf1, 0x5d, 0x66, 0xec, 0x2b, 0xa2, 0x89, 0xb9, 0xd4, 0xd8, 0x37, 0x09, 0x7f, 0x8b, 0xaf, 0xb1, 0xef, 0x25, 0xba, 0x59, 0x82, 0x8c, 0x7d, 0xef, 0x3a, 0xe7, 0xf8, 0x88, 0x58, 0x4b, 0x84,\n\t0xb1, 0xef, 0x2b, 0x9a, 0x58, 0x5e, 0x31, 0xf6, 0xcd, 0x62, 0xb1, 0xe5, 0x5f, 0xc6, 0xbe, 0x45, 0x84, 0xaa, 0x21, 0xc6, 0xbe, 0x2a, 0x12, 0xd5, 0x29, 0xc6, 0xbe, 0xd5, 0x92, 0xaf, 0x7e, 0x62, 0xec, 0xfb, 0x89, 0xd0, 0x46, 0x2f, 0x18, 0xfb, 0xf5, 0x44, 0xef, 0x46, 0x3f, 0x19, 0xfb, 0xf5, 0xeb, 0xb4, 0xcd, 0x5f, 0xf4, 0x0d, 0xf4, 0x36, 0xf6, 0x1b, 0x0a, 0x4b, 0xe0, 0x00, 0x63, 0x3f, 0x40, 0xd4, 0x0b, 0x8c, 0x18, 0x99, 0x94, 0xbc, 0x26, 0x25, 0x6e, 0x69, 0x6c, 0x9a, 0xad, 0x53, 0x74, 0x67, 0x5b, 0xef, 0xd0, 0x5e, 0xbd, 0xba, 0xf3, 0xbf, 0x30, 0x5b, 0xd4, 0x1a, 0x5b, 0xda, 0x9a, 0x69, 0x49, 0xf1, 0x91, 0x89, 0x31, 0xb6, 0x49, 0x2b, 0x97, 0x47, 0xa6, 0xae, 0xb5, 0x8d, 0x5a, 0x1b, 0x67, 0x8f, 0x59, 0x1b, 0x17, 0x6d, 0xeb, 0x14, 0x9b, 0x96, 0x96, 0x1c, 0xde, 0xb3, 0xe7,\n\t0xea, 0xd5, 0xab, 0x7b, 0xa4, 0xad, 0x49, 0xd6, 0x4f, 0xea, 0x11, 0x9d, 0x94, 0xd0, 0xb3, 0xb3, 0x6d, 0x75, 0x5c, 0x5a, 0xac, 0x6d, 0x86, 0x3d, 0xd5, 0x9e, 0xb2, 0xca, 0x1e, 0x63, 0x1b, 0x93, 0x94, 0x98, 0x66, 0x9b, 0x12, 0x99, 0x60, 0xb7, 0xb5, 0x99, 0x14, 0x99, 0x96, 0xd4, 0xa6, 0x87, 0x6d, 0x52, 0x5c, 0xb4, 0x3d, 0x31, 0x95, 0xb7, 0x56, 0x26, 0xc6, 0xd8, 0x53, 0x6c, 0x69, 0xb1, 0x76, 0xdb, 0xcc, 0xf1, 0x93, 0x6c, 0x53, 0x93, 0xed, 0x89, 0x9e, 0xb3, 0x8d, 0x13, 0xba, 0xd9, 0x66, 0xdb, 0x53, 0x52, 0xe3, 0x92, 0x12, 0x6d, 0xbd, 0x7a, 0xf4, 0xba, 0x5e, 0x61, 0x6a, 0x74, 0x4a, 0x5c, 0x72, 0x5a, 0x6a, 0x8f, 0xd4, 0xb8, 0xf8, 0x1e, 0x49, 0x29, 0x4b, 0x7b, 0x4e, 0x1d, 0x33, 0xa9, 0x33, 0x65, 0x52, 0xf4, 0x64, 0x7b, 0x4c, 0xdc, 0xca, 0x84, 0xde, 0x3d, 0x68, 0xfa, 0x20,\n\t0xda, 0x3d, 0x69, 0x90, 0x76, 0xb0, 0xbb, 0xe7, 0xa8, 0xb6, 0x6b, 0xf3, 0xec, 0xd6, 0x16, 0xea, 0x39, 0x51, 0xeb, 0x6e, 0x58, 0xf7, 0xd0, 0x01, 0xdd, 0x43, 0xfb, 0x0d, 0xb2, 0xd5, 0xe9, 0x53, 0x3c, 0x17, 0x2c, 0xa1, 0x31, 0xa9, 0x7a, 0xa7, 0x6e, 0x2d, 0x29, 0x2e, 0xd5, 0x16, 0x69, 0x4b, 0x4b, 0x89, 0x8c, 0xb1, 0x27, 0x44, 0xa6, 0x2c, 0xb7, 0x25, 0x2d, 0xf9, 0xc3, 0x81, 0xea, 0xf1, 0x47, 0x6f, 0xdc, 0x3a, 0xa0, 0xfa, 0xa8, 0x0d, 0x8f, 0x89, 0x4c, 0xb0, 0xcd, 0x5a, 0x1d, 0x99, 0x12, 0x93, 0x14, 0x1d, 0x6b, 0xd3, 0xae, 0x1a, 0x91, 0x94, 0x16, 0x97, 0x64, 0x9b, 0x12, 0xb7, 0x3c, 0x29, 0x3e, 0x2d, 0x3a, 0xd6, 0xbe, 0xea, 0x46, 0xf5, 0xa9, 0x91, 0x8c, 0x51, 0x4a, 0x9c, 0x56, 0x75, 0xb2, 0x7d, 0x49, 0x64, 0xb4, 0xdd, 0xb6, 0x24, 0x32, 0x21, 0x2e, 0x7e, 0x8d, 0x2d, 0xc6,\n\t0x9e, 0x1a, 0xb7, 0x34, 0x91, 0xf1, 0x8d, 0x4b, 0xf4, 0x0c, 0xee, 0xca, 0x84, 0x04, 0xc6, 0x99, 0x8e, 0x86, 0xea, 0x45, 0xda, 0xef, 0x4a, 0xb3, 0x33, 0xf2, 0xbf, 0xf3, 0x7e, 0x1f, 0x6d, 0xca, 0xe7, 0x44, 0xa6, 0xa4, 0x46, 0xae, 0xee, 0x1e, 0x15, 0xa9, 0x4d, 0x91, 0x51, 0x56, 0xca, 0x6f, 0xe7, 0xdf, 0x33, 0x9b, 0xb6, 0x04, 0x3b, 0xcd, 0xb0, 0xb5, 0xf1, 0x94, 0xd1, 0x46, 0x2b, 0x92, 0xee, 0xc6, 0xa5, 0xc6, 0x32, 0x27, 0xe3, 0xd3, 0x18, 0xa2, 0x38, 0x7b, 0xaa, 0x8d, 0x16, 0x47, 0x47, 0xa6, 0xd8, 0x97, 0xac, 0x8c, 0xa7, 0x75, 0x51, 0x91, 0x8c, 0x06, 0x8d, 0x4d, 0x4d, 0x42, 0x12, 0xc9, 0x49, 0x34, 0x25, 0x2d, 0x2e, 0x52, 0x7b, 0x23, 0x3a, 0x29, 0x71, 0x49, 0x7c, 0x5c, 0x74, 0x5a, 0x5c, 0xe2, 0x52, 0x5b, 0x72, 0x4a, 0x5c, 0x52, 0x4a, 0x5c, 0x1a, 0x17, 0x87, 0xdb, 0xe2,\n\t0xd2, 0x6c, 0xa9, 0xb1, 0x49, 0x2b, 0xe3, 0x63, 0x6c, 0xa9, 0x76, 0x7b, 0x82, 0x6d, 0xc5, 0xca, 0xb8, 0x34, 0xb4, 0xc4, 0xe0, 0x27, 0xa6, 0x26, 0x53, 0x6a, 0x62, 0x5a, 0x1b, 0xdb, 0xea, 0x58, 0xa4, 0xb3, 0x32, 0xd5, 0xd3, 0xa5, 0xa8, 0xa4, 0x18, 0x74, 0x4b, 0x27, 0x6d, 0x51, 0x2b, 0xd3, 0x6c, 0xab, 0xf5, 0x2b, 0x63, 0xe2, 0x52, 0x93, 0xe3, 0x23, 0xd7, 0x78, 0x2a, 0xa5, 0xe4, 0xa5, 0x71, 0x89, 0x91, 0xf1, 0xda, 0x04, 0xc6, 0xa5, 0xa5, 0xde, 0x7c, 0x75, 0x7c, 0x64, 0xca, 0x52, 0xba, 0x9b, 0x1a, 0xb7, 0xd6, 0x9e, 0xda, 0xc3, 0x36, 0x8b, 0xe1, 0x89, 0x8e, 0x8f, 0x4c, 0x4d, 0x8d, 0x8b, 0xe6, 0xfc, 0xe4, 0x94, 0xa4, 0xe4, 0xa4, 0x14, 0xe6, 0x23, 0x31, 0xb5, 0x9b, 0x8d, 0xba, 0xd3, 0xe2, 0xa2, 0x57, 0x72, 0x3e, 0x6d, 0x5f, 0x15, 0x97, 0x1a, 0x17, 0x15, 0x6f, 0xaf, 0x1d,\n\t0xd1, 0x95, 0xc9, 0xc9, 0xf6, 0x94, 0xe8, 0x48, 0x4d, 0xc2, 0x4b, 0xe3, 0x56, 0xd9, 0xf5, 0x63, 0xf1, 0xf6, 0xb4, 0x34, 0x7b, 0xca, 0x92, 0xa4, 0x94, 0x84, 0x54, 0xcf, 0x44, 0xc5, 0x45, 0xa6, 0xd8, 0x62, 0x23, 0x53, 0x12, 0x92, 0x12, 0xd7, 0x78, 0xa6, 0x25, 0xde, 0xbe, 0x54, 0x1b, 0x99, 0x1e, 0xb6, 0xe1, 0x69, 0xfa, 0x15, 0xa9, 0x9a, 0xd1, 0xa4, 0xc5, 0x25, 0x50, 0x8a, 0xd6, 0xcc, 0xd4, 0x78, 0xbb, 0x7d, 0xf9, 0x8d, 0x59, 0x8f, 0x4f, 0x4a, 0x5a, 0x6e, 0x4b, 0x88, 0x5c, 0xce, 0xf8, 0xda, 0x57, 0xc5, 0xc5, 0x30, 0x0e, 0xfa, 0x45, 0x08, 0x41, 0xdb, 0x89, 0x4c, 0xd3, 0x4d, 0xc2, 0xb6, 0x3a, 0x32, 0xf5, 0x37, 0x7a, 0xd0, 0x84, 0x40, 0x07, 0xec, 0xab, 0xec, 0xda, 0xeb, 0xa4, 0x95, 0x4b, 0x63, 0xb5, 0x31, 0x8e, 0x49, 0xa2, 0xa4, 0xc4, 0xa4, 0x34, 0xdb, 0x92, 0xa4, 0xf8,\n\t0xf8, 0xa4, 0xd5, 0x34, 0x89, 0x29, 0x59, 0x99, 0x92, 0xa2, 0x17, 0xcc, 0xff, 0x63, 0x3c, 0xa3, 0x91, 0x6a, 0x4f, 0x88, 0xeb, 0x9e, 0x92, 0xb4, 0x52, 0x17, 0x50, 0x8c, 0x3d, 0x2d, 0x32, 0x2e, 0x3e, 0x55, 0xd7, 0xff, 0xf5, 0x2e, 0xa6, 0x7a, 0xfa, 0xac, 0x57, 0x1f, 0x69, 0x5b, 0x62, 0xb7, 0xc7, 0x6b, 0x33, 0xca, 0x29, 0xc8, 0x3a, 0x21, 0x2d, 0xb6, 0x1b, 0xe3, 0x1d, 0x17, 0xef, 0x19, 0x93, 0xd4, 0xb4, 0x94, 0x24, 0xde, 0x63, 0xb3, 0x32, 0x3a, 0x6d, 0x65, 0x8a, 0x5d, 0x1b, 0x61, 0xad, 0x2f, 0x74, 0x36, 0x2d, 0x32, 0x8a, 0x21, 0x4a, 0xf3, 0x0c, 0x8d, 0xd6, 0xe3, 0xa4, 0x95, 0xa9, 0x89, 0xf6, 0x54, 0xe6, 0x64, 0x7c, 0xa2, 0x2e, 0x55, 0xcd, 0x45, 0xf5, 0xed, 0x66, 0xf4, 0x59, 0xd7, 0xbd, 0xd6, 0xd7, 0xa5, 0x29, 0xf6, 0xc8, 0x34, 0xf6, 0xaf, 0x6b, 0xbc, 0x93, 0x6e, 0x57,\n\t0xda, 0x59, 0xb1, 0xf6, 0xf8, 0x64, 0xad, 0x19, 0xff, 0xdd, 0xc6, 0x3a, 0xeb, 0x8a, 0x4d, 0x5a, 0x85, 0x0e, 0xfa, 0x84, 0x86, 0x86, 0x76, 0xb5, 0x2d, 0x8d, 0x5f, 0x93, 0x1c, 0x4b, 0x37, 0xb5, 0x23, 0x89, 0x71, 0x89, 0x76, 0xdb, 0x6a, 0xbb, 0xe6, 0x2e, 0x53, 0x3d, 0x46, 0x1b, 0x97, 0x16, 0x89, 0x6e, 0x53, 0x75, 0xc1, 0x27, 0x32, 0x72, 0xa9, 0x4c, 0x3f, 0x32, 0x49, 0xb5, 0xf5, 0xd2, 0xae, 0x65, 0x1c, 0xe2, 0x12, 0x0d, 0x6b, 0x42, 0xf9, 0x4b, 0x57, 0x46, 0x2e, 0xb5, 0x33, 0xfa, 0x61, 0xbc, 0x35, 0x12, 0xaf, 0x1b, 0xcf, 0xa5, 0xb7, 0xbe, 0x6b, 0xa3, 0x23, 0xab, 0xed, 0xf1, 0xf1, 0xda, 0x76, 0x6c, 0x8a, 0x36, 0xeb, 0x5a, 0x2b, 0xc7, 0x4f, 0x1b, 0x6e, 0x4b, 0x8e, 0x4d, 0x4a, 0xb4, 0xa7, 0xe9, 0x95, 0x69, 0x93, 0xa1, 0x8f, 0xb1, 0xee, 0xa5, 0x6c, 0x58, 0x82, 0x2d, 0x72,\n\t0x15, 0xb3, 0x11, 0xa9, 0xe9, 0x70, 0x09, 0x57, 0x69, 0x7d, 0x8d, 0x8e, 0xd5, 0xe4, 0xfc, 0xdf, 0x1c, 0x2d, 0xa7, 0x27, 0x25, 0xfc, 0xb1, 0xf3, 0xfb, 0x23, 0x4f, 0xff, 0xdf, 0x2e, 0xf8, 0x1d, 0x4f, 0x2d, 0x46, 0x8a, 0x24, 0xe2, 0xed, 0x35, 0x22, 0x45, 0xc4, 0x91, 0x42, 0xc7, 0x8a, 0x34, 0x61, 0x13, 0x9d, 0x44, 0xb4, 0xe8, 0xcc, 0xb6, 0xb7, 0x08, 0x15, 0xbd, 0xf8, 0xd7, 0xdd, 0xd8, 0x0b, 0xe3, 0x58, 0x14, 0xe7, 0xda, 0x38, 0x6b, 0x8d, 0x98, 0xc6, 0x95, 0xf1, 0x22, 0x52, 0x24, 0x8a, 0x18, 0x8e, 0x4c, 0x12, 0x2b, 0xc5, 0x72, 0x5e, 0xa5, 0x8a, 0xb5, 0xbc, 0x1a, 0xc5, 0xff, 0xe3, 0x84, 0x9d, 0x77, 0xb4, 0x6d, 0xb4, 0x5e, 0xa6, 0x56, 0x76, 0x1a, 0x75, 0x85, 0x8b, 0x9e, 0xfc, 0x5b, 0xad, 0xff, 0xeb, 0xa1, 0x97, 0x94, 0x5c, 0xa7, 0xa4, 0x1e, 0x9c, 0x9d, 0x24, 0x12, 0x38,\n\t0x43, 0x6b, 0xc1, 0x6a, 0xae, 0x4e, 0xe3, 0x4a, 0x9b, 0x98, 0x41, 0x69, 0xa9, 0x90, 0x22, 0x56, 0xe9, 0xe5, 0xda, 0xc4, 0x18, 0xce, 0x4b, 0xd4, 0xdb, 0x3b, 0x85, 0x6b, 0x13, 0x38, 0x6a, 0x13, 0x6d, 0x68, 0x47, 0x24, 0xc7, 0x92, 0xd8, 0xeb, 0xa1, 0xb7, 0x4a, 0xab, 0xdd, 0xce, 0x79, 0xa9, 0xc6, 0x55, 0x2b, 0xf5, 0x5a, 0xb4, 0x72, 0x6c, 0x7a, 0xc9, 0xda, 0x55, 0x33, 0xc5, 0x78, 0xce, 0xb4, 0x89, 0xa9, 0xb4, 0x44, 0x3b, 0xb7, 0x6e, 0xd9, 0x37, 0x97, 0xd0, 0x8d, 0x23, 0xb3, 0xf5, 0xab, 0x53, 0x39, 0x9e, 0xa4, 0x9f, 0xdb, 0x8b, 0x9a, 0x7a, 0xfd, 0x4e, 0x0f, 0x53, 0xb9, 0x4e, 0x1b, 0xd5, 0x64, 0x8e, 0xa5, 0x72, 0x8e, 0x76, 0x45, 0x3c, 0xdb, 0x24, 0x8e, 0x2e, 0xe5, 0xfd, 0xa9, 0xd4, 0x32, 0x89, 0x5e, 0x7a, 0xda, 0xe9, 0x69, 0xb5, 0x4d, 0x4c, 0xd6, 0xdb, 0x19, 0x47, 0x3b,\n\t0x13, 0xf4, 0x3e, 0x2f, 0x65, 0x4f, 0x1b, 0x9b, 0x14, 0xe6, 0xa0, 0x87, 0x31, 0x0b, 0x83, 0x8c, 0xf1, 0x9f, 0xc4, 0x5e, 0xed, 0x95, 0xdd, 0x6f, 0xba, 0xf2, 0xd6, 0x36, 0xd6, 0xbd, 0xd6, 0x76, 0x7d, 0x36, 0xbb, 0xb3, 0x1d, 0xa0, 0xff, 0xbf, 0x9f, 0x7e, 0xfc, 0xf7, 0x67, 0x28, 0xde, 0xa8, 0x61, 0x89, 0x31, 0x26, 0xa9, 0x75, 0xe6, 0xe8, 0xf7, 0x6b, 0xbf, 0xd1, 0x9b, 0x38, 0xce, 0xb6, 0xf1, 0x4a, 0x1b, 0xeb, 0x14, 0xb6, 0xda, 0xc8, 0x27, 0xe8, 0xbd, 0x59, 0xce, 0x31, 0xad, 0xcc, 0xbf, 0xae, 0xa5, 0x1e, 0x7f, 0xf9, 0x8a, 0xff, 0xa6, 0xcd, 0x1b, 0x2a, 0x1b, 0xce, 0x51, 0x4d, 0x4b, 0x36, 0x31, 0x8b, 0xa3, 0x5a, 0x3b, 0x63, 0xa8, 0x27, 0x5a, 0x7f, 0xaf, 0xb6, 0xae, 0x11, 0x1c, 0x49, 0xd3, 0x47, 0x56, 0x53, 0x5e, 0x1c, 0x25, 0x6b, 0x2d, 0x49, 0xd3, 0xcf, 0xb2, 0xa3, 0xce,\n\t0xdf, 0xeb, 0x7d, 0xaa, 0x7e, 0xb5, 0x47, 0xbf, 0x71, 0xd7, 0x7b, 0xad, 0xa9, 0x6d, 0x09, 0xef, 0x44, 0xeb, 0x2a, 0x5c, 0xa2, 0xd7, 0xac, 0x69, 0x44, 0xb3, 0xb0, 0x18, 0x5d, 0xef, 0x9a, 0x4d, 0x26, 0x1a, 0xca, 0x8d, 0xd3, 0x67, 0xf2, 0x86, 0x66, 0xb5, 0x91, 0x4e, 0x30, 0x94, 0xec, 0x99, 0xd1, 0xd0, 0x3a, 0xad, 0xb4, 0x8b, 0xbb, 0x38, 0xd7, 0x6e, 0xa8, 0xfd, 0xcf, 0x5d, 0xdf, 0xe7, 0xba, 0x7d, 0xcf, 0xd1, 0xfb, 0xae, 0xb5, 0x7a, 0x35, 0x73, 0x1b, 0xa5, 0x8f, 0x9d, 0xa7, 0x94, 0x9b, 0xdb, 0x95, 0xf2, 0xa7, 0x2c, 0xbf, 0xae, 0x55, 0xda, 0xf4, 0x3a, 0x3d, 0xa3, 0xa1, 0xd9, 0x6b, 0xdd, 0x76, 0xb4, 0xb9, 0xde, 0x4a, 0xcf, 0xec, 0x6a, 0xe3, 0x17, 0x6b, 0x58, 0xc8, 0x78, 0xdd, 0x1a, 0xd3, 0xf4, 0xf1, 0xb3, 0xeb, 0xd7, 0x7a, 0xc6, 0x38, 0x5a, 0x6f, 0xa9, 0x36, 0x8e, 0x9a,\n\t0x9d, 0x78, 0xc6, 0x4e, 0x6b, 0xaf, 0x47, 0x1b, 0x9e, 0x91, 0x4d, 0xd5, 0xd5, 0xaa, 0xed, 0x25, 0xeb, 0x73, 0x67, 0xd7, 0x75, 0x1c, 0xa7, 0x9f, 0xe5, 0xb9, 0x22, 0x5a, 0xd7, 0xf6, 0x12, 0xbd, 0xce, 0x68, 0xfd, 0xbd, 0x44, 0x7a, 0xa8, 0x9d, 0x9f, 0xa2, 0xcf, 0x74, 0x8a, 0xae, 0x10, 0x4f, 0xcd, 0xe1, 0x7a, 0x2b, 0xd3, 0xf4, 0x72, 0x63, 0x79, 0x4f, 0xab, 0x37, 0x46, 0x7f, 0x65, 0xd7, 0xd5, 0x6d, 0x13, 0x2b, 0x38, 0x16, 0xa7, 0xd7, 0xa3, 0xf5, 0xd0, 0xa3, 0x7c, 0xad, 0xbf, 0xc9, 0x46, 0x5b, 0xb5, 0xda, 0xdb, 0xe8, 0xba, 0x8b, 0x35, 0xfc, 0xcd, 0xca, 0xeb, 0xe3, 0xeb, 0xe9, 0x7f, 0x14, 0xe5, 0xc6, 0x18, 0x9e, 0xd6, 0x33, 0x93, 0xda, 0xb1, 0x95, 0xfa, 0x76, 0x75, 0x9d, 0x3a, 0x63, 0xf4, 0x31, 0x4a, 0xd6, 0x7b, 0xbb, 0xe6, 0xa6, 0x9e, 0x26, 0x19, 0x1e, 0x5d, 0x2b, 0x4f,\n\t0xeb, 0x67, 0xad, 0x05, 0xc6, 0xe9, 0x16, 0xfc, 0x9f, 0xea, 0xf6, 0x78, 0x9b, 0xa5, 0xc6, 0xec, 0x6a, 0x73, 0xbd, 0x56, 0xef, 0x77, 0x0f, 0xdd, 0x2a, 0x3c, 0xea, 0x89, 0xd6, 0xcf, 0x4a, 0xd5, 0xdf, 0x8d, 0x36, 0xca, 0xd7, 0xc6, 0x2a, 0x49, 0x1f, 0xe1, 0x14, 0xc3, 0x3e, 0xb4, 0x3e, 0x77, 0xd3, 0xdf, 0x89, 0x34, 0x8e, 0x45, 0x5f, 0xf7, 0x66, 0x9e, 0x71, 0x5f, 0xa5, 0xb7, 0x3f, 0x8e, 0xbe, 0xc5, 0xeb, 0xe5, 0xde, 0xac, 0xd1, 0x95, 0x5c, 0x99, 0xac, 0xb7, 0x23, 0xda, 0x50, 0xa0, 0x56, 0x9a, 0xd6, 0xa7, 0x55, 0xfa, 0xfb, 0xb5, 0xe7, 0x69, 0xd7, 0xa6, 0xe9, 0x23, 0x95, 0xa2, 0x7b, 0xa9, 0x14, 0xc6, 0x20, 0xf5, 0x26, 0x8b, 0x8a, 0xd3, 0xeb, 0xd4, 0x3c, 0x5c, 0xa4, 0xfe, 0xae, 0xd6, 0xb6, 0x35, 0x37, 0x59, 0x4b, 0xbc, 0xee, 0x6b, 0x6b, 0x35, 0xd3, 0x43, 0xf7, 0x05, 0x69,\n\t0x75, 0xea, 0x48, 0xbd, 0xbe, 0xc6, 0x68, 0xfd, 0x48, 0x30, 0xda, 0x52, 0x3b, 0x9a, 0xa9, 0xfa, 0xf5, 0x76, 0xdd, 0xab, 0xfd, 0xd6, 0xd6, 0xe3, 0xa9, 0x2f, 0x49, 0x7f, 0x4f, 0xf3, 0x7d, 0xcb, 0x0d, 0xfd, 0xda, 0xf5, 0xde, 0xc7, 0x18, 0x7a, 0xb8, 0x51, 0x93, 0xc7, 0x23, 0xd4, 0x1e, 0x89, 0x34, 0x56, 0xa1, 0x5a, 0x9f, 0xb2, 0x5a, 0x1f, 0x89, 0xff, 0xee, 0x1f, 0x6a, 0x3d, 0x82, 0x67, 0x06, 0xec, 0xfa, 0x88, 0xd5, 0xbe, 0xaf, 0xe9, 0x67, 0xa9, 0xee, 0xd3, 0x3c, 0x3a, 0xd6, 0x7c, 0x9c, 0xa7, 0x4d, 0x89, 0xba, 0x7d, 0xd8, 0xf4, 0x51, 0x8c, 0xd7, 0xdb, 0xbd, 0xda, 0x18, 0x25, 0x8f, 0x95, 0xac, 0xa4, 0x4f, 0x29, 0x75, 0x5a, 0x9c, 0x62, 0x78, 0x98, 0xba, 0xda, 0x48, 0xd5, 0xad, 0x20, 0x0e, 0xbf, 0x91, 0xa2, 0xd7, 0x74, 0xc3, 0x03, 0xc5, 0xe8, 0xf3, 0x14, 0xa9, 0xcf, 0x48,\n\t0x6a, 0x1d, 0xff, 0xff, 0xdb, 0x59, 0x4c, 0xbd, 0x69, 0x9e, 0x6f, 0xf4, 0x3e, 0x52, 0x6f, 0x9b, 0x5d, 0x9f, 0xaf, 0x5a, 0x1b, 0xf5, 0x94, 0xb2, 0xda, 0x98, 0x59, 0xad, 0xb4, 0x6e, 0x86, 0xbe, 0xe3, 0x0c, 0x55, 0xdd, 0x98, 0xc3, 0x34, 0xbd, 0x4d, 0x9e, 0xeb, 0x3c, 0xaf, 0x56, 0xea, 0x63, 0xbd, 0x52, 0xef, 0x49, 0xad, 0x86, 0x6b, 0xe7, 0x25, 0xd5, 0x38, 0x2b, 0x12, 0x7d, 0x7a, 0x54, 0x94, 0x76, 0x93, 0x6a, 0x6a, 0xe7, 0x38, 0x49, 0xb7, 0xa1, 0x44, 0xfd, 0x8a, 0x54, 0xc3, 0x5b, 0x25, 0xd6, 0xf1, 0xaa, 0xb5, 0xf1, 0x53, 0x5f, 0xbd, 0x65, 0x75, 0xe7, 0xf9, 0x86, 0xbf, 0xaf, 0x9d, 0xd7, 0xa5, 0x7a, 0x4b, 0xb4, 0xfe, 0x7a, 0x8e, 0xff, 0xd6, 0x8f, 0x77, 0xaa, 0xb3, 0x5e, 0xd5, 0x96, 0x15, 0xab, 0x8f, 0x48, 0xf2, 0xf5, 0xd1, 0xf8, 0x3f, 0xb1, 0x8e, 0x75, 0xae, 0xe3, 0x63,\n\t0x93, 0xf4, 0x99, 0xd0, 0x2c, 0xa8, 0x0f, 0x3d, 0xd1, 0xfe, 0x75, 0xd5, 0xdb, 0x1a, 0xaf, 0xaf, 0x62, 0xb1, 0xc6, 0x6c, 0xd6, 0x9e, 0x93, 0xa8, 0xcf, 0x8d, 0x5d, 0xef, 0x95, 0xfd, 0x7a, 0x5c, 0x99, 0x7a, 0xd3, 0x4a, 0x1b, 0xa7, 0x8f, 0xab, 0xc7, 0xdf, 0xa6, 0xd6, 0xf1, 0xf0, 0x89, 0x86, 0xe6, 0x52, 0x0d, 0xeb, 0xf7, 0x78, 0x93, 0x54, 0x3d, 0xce, 0xaa, 0xad, 0xd7, 0xa3, 0x07, 0xad, 0x8e, 0x9b, 0xd7, 0x26, 0x8f, 0xcf, 0xd7, 0x22, 0xa6, 0x48, 0xdd, 0x7f, 0x79, 0xb4, 0x1f, 0x66, 0x5c, 0x35, 0xd2, 0x88, 0x72, 0xe3, 0x8d, 0x5a, 0xff, 0xdb, 0xb5, 0x36, 0x63, 0x46, 0x56, 0xeb, 0x63, 0x1b, 0x7f, 0xfd, 0xf5, 0x58, 0x7d, 0x86, 0x3c, 0xb6, 0x5e, 0x3b, 0x96, 0xe3, 0x59, 0xb1, 0x86, 0xeb, 0xfa, 0x89, 0xd5, 0xf5, 0x65, 0x37, 0xbc, 0xdd, 0xcd, 0x5e, 0xf3, 0x86, 0x8e, 0x6f, 0xc4,\n\t0x52, 0x36, 0x63, 0x4d, 0xd0, 0xb6, 0xab, 0x0c, 0xdb, 0x88, 0xbc, 0xee, 0x0f, 0x97, 0x18, 0x75, 0xd5, 0xce, 0x6b, 0xb4, 0xe1, 0xc1, 0x96, 0x1a, 0xfe, 0xf1, 0x7f, 0x12, 0xcb, 0x7a, 0x4a, 0x4f, 0xd2, 0x55, 0xf2, 0xd7, 0x23, 0xbf, 0xbf, 0x1a, 0xcd, 0xff, 0x4f, 0x6b, 0xf8, 0x73, 0xd1, 0x74, 0xed, 0x08, 0xd7, 0x8d, 0x46, 0xb5, 0x7b, 0x97, 0xfa, 0x7f, 0x35, 0xa1, 0xda, 0x97, 0xec, 0x7f, 0xe7, 0x3f, 0x45, 0x28, 0x52, 0x8a, 0x06, 0xfa, 0xdd, 0x44, 0x2b, 0xe7, 0xec, 0x15, 0xde, 0xa3, 0xc6, 0x4c, 0x9a, 0x25, 0x5a, 0x44, 0xaf, 0x49, 0x89, 0x17, 0x9d, 0x48, 0x61, 0x97, 0x8b, 0x7e, 0x64, 0x54, 0x89, 0x44, 0x37, 0xfa, 0x1f, 0xf7, 0x39, 0xdb, 0xa4, 0xdf, 0x07, 0xbd, 0xf1, 0x4a, 0x7b, 0xc4, 0xc0, 0x8d, 0x57, 0xda, 0x9d, 0xd3, 0x1b, 0xaf, 0xb4, 0x5f, 0xc2, 0xb1, 0x2c, 0xb7, 0xa7,\n\t0x24, 0x8a, 0xde, 0xbf, 0xfd, 0xbf, 0x76, 0xbf, 0x4a, 0x0c, 0xf8, 0xed, 0xff, 0xaf, 0xdf, 0xf5, 0xd4, 0x3e, 0xf9, 0xaa, 0x95, 0xe1, 0x4d, 0x0d, 0xf5, 0xc4, 0x56, 0xf1, 0x94, 0x78, 0x55, 0x7c, 0xac, 0xff, 0x3d, 0xa9, 0x9e, 0x08, 0x11, 0x1d, 0x18, 0x83, 0x7e, 0x62, 0x28, 0xbd, 0x9f, 0x42, 0xd4, 0xbf, 0x88, 0x91, 0x4c, 0x44, 0x47, 0x8a, 0xde, 0xbe, 0xbd, 0x9e, 0xed, 0x81, 0x65, 0xfa, 0x56, 0x59, 0x92, 0xee, 0xd9, 0x9e, 0xda, 0xaf, 0x6f, 0x4d, 0x41, 0xdb, 0x3d, 0xdb, 0x39, 0xf9, 0x9e, 0xed, 0xba, 0xc7, 0x3d, 0xdb, 0x87, 0x23, 0x3c, 0xdb, 0xa7, 0x5e, 0xf3, 0x6c, 0x5f, 0xab, 0xe7, 0xd9, 0xfe, 0xcb, 0xe4, 0xd9, 0xfe, 0xf8, 0x89, 0x5e, 0xbb, 0x22, 0x2c, 0xfa, 0xdd, 0x62, 0x53, 0x6e, 0xf5, 0xcd, 0xaf, 0x2f, 0x3f, 0x75, 0xd3, 0x6b, 0xaf, 0xa0, 0xaf, 0x6f, 0x7e, 0xdd, 0xe4,\n\t0xa0, 0x50, 0x4c, 0x0d, 0xf5, 0xa7, 0x01, 0x79, 0x99, 0xa6, 0xf9, 0x7c, 0xed, 0x3b, 0x2e, 0x70, 0x8b, 0x6f, 0xae, 0x39, 0x98, 0x7f, 0xb3, 0xcd, 0xb3, 0x03, 0xb7, 0x98, 0xbf, 0xb5, 0xb4, 0xb0, 0xec, 0x68, 0x54, 0x6e, 0xf9, 0x57, 0xa3, 0xf2, 0x86, 0x5f, 0x36, 0x74, 0x06, 0x74, 0x0a, 0xd8, 0xc4, 0xbf, 0x8a, 0x46, 0xe5, 0xda, 0xbf, 0xc0, 0x20, 0xfe, 0x6d, 0x09, 0xcc, 0x08, 0x6a, 0xd3, 0xec, 0x95, 0xe6, 0x6d, 0x9a, 0x3f, 0xcc, 0xbf, 0xf7, 0x6f, 0xeb, 0xd6, 0xb6, 0x37, 0xff, 0xee, 0x6a, 0xb7, 0xaa, 0xfd, 0xdc, 0xf6, 0x07, 0x3b, 0x7a, 0x77, 0x5c, 0xd6, 0xf1, 0x93, 0x81, 0xef, 0x87, 0x7b, 0x77, 0x6a, 0xd4, 0xa9, 0xd1, 0x80, 0xd7, 0xfa, 0x26, 0x0e, 0xdb, 0x3d, 0x6c, 0x77, 0xa7, 0x49, 0x9d, 0xd6, 0x76, 0x8d, 0xe9, 0xfa, 0xf6, 0xc0, 0xf7, 0x07, 0xbe, 0x3f, 0xec, 0xd5, 0x70,\n\t0xef, 0x70, 0xef, 0xee, 0xb3, 0x06, 0xbc, 0x36, 0xe0, 0xb5, 0x88, 0xa1, 0xdd, 0x8f, 0x76, 0x2f, 0xed, 0xf1, 0x53, 0xcf, 0xc2, 0xd0, 0x3b, 0x42, 0x77, 0x44, 0x0c, 0xd5, 0xfe, 0x85, 0x66, 0x86, 0x5e, 0xed, 0x95, 0xd9, 0xfb, 0x7c, 0x9f, 0x45, 0x7d, 0x76, 0x7b, 0x8e, 0x44, 0x0c, 0xed, 0x9b, 0xd8, 0x37, 0xb1, 0x4f, 0x4e, 0x9f, 0x1c, 0xad, 0xac, 0xbe, 0xf5, 0xfa, 0x76, 0xd1, 0xae, 0xe5, 0xea, 0x76, 0x7d, 0xa7, 0x45, 0xb4, 0xd3, 0xfe, 0x69, 0xef, 0xf7, 0xdd, 0xdb, 0x37, 0xc7, 0x73, 0x7c, 0x40, 0xf5, 0xc0, 0x69, 0x5a, 0x0b, 0xc2, 0xbd, 0x23, 0xe6, 0x86, 0x2f, 0x0a, 0xdf, 0x11, 0xbe, 0x43, 0xbb, 0x2e, 0xfc, 0xe8, 0x90, 0xf4, 0x61, 0xbb, 0x87, 0x54, 0xb3, 0xff, 0x2a, 0xd7, 0x0c, 0xad, 0xdd, 0x46, 0xcc, 0x8d, 0xd8, 0x12, 0xf1, 0x61, 0x84, 0x73, 0x78, 0xf0, 0xf0, 0x31, 0xc3,\n\t0xef, 0x1a, 0xfe, 0xd4, 0xe8, 0xbd, 0xe3, 0x8e, 0x8e, 0x7f, 0x77, 0x52, 0xfe, 0xe4, 0xb4, 0xc9, 0x3f, 0x4d, 0x3b, 0x3d, 0xe3, 0xe3, 0xdb, 0x5f, 0x9b, 0xdb, 0x7b, 0x6e, 0xfc, 0xdc, 0x37, 0xe6, 0x56, 0xdc, 0xb1, 0x75, 0xfe, 0xa4, 0xf9, 0xcf, 0x2d, 0x1a, 0xbc, 0x68, 0xd1, 0xa2, 0x75, 0x51, 0x8f, 0x2e, 0x0e, 0x89, 0x7a, 0x34, 0xea, 0xd7, 0x98, 0x20, 0x7b, 0x9b, 0x25, 0x19, 0xcb, 0x42, 0x63, 0xbb, 0xc4, 0x2e, 0x88, 0xab, 0x59, 0x16, 0xba, 0x6c, 0xd9, 0xb2, 0xcf, 0xe2, 0x6b, 0x12, 0xc6, 0x25, 0x6c, 0x4a, 0xfa, 0x31, 0xe9, 0xc7, 0xb4, 0xea, 0xe4, 0x55, 0xc9, 0x9f, 0xad, 0x12, 0x2b, 0xc2, 0x57, 0x89, 0x35, 0x5f, 0xaf, 0xf9, 0x7a, 0xe5, 0x5a, 0xf6, 0xef, 0x4b, 0x19, 0x9a, 0xb2, 0x38, 0xad, 0x7a, 0x95, 0xd0, 0xfe, 0xa5, 0x55, 0xaf, 0xf9, 0x5a, 0x7b, 0x6f, 0xe5, 0xda, 0x95,\n\t0xb3, 0xb4, 0x77, 0x57, 0x85, 0xdf, 0x15, 0xba, 0xe6, 0xeb, 0xb5, 0x93, 0xd6, 0xd6, 0xac, 0xeb, 0x7d, 0xf7, 0xee, 0xbb, 0x8f, 0xae, 0x73, 0xae, 0xab, 0xb7, 0xae, 0xf7, 0x3d, 0xa6, 0x75, 0xf7, 0xdd, 0x63, 0x5a, 0x1f, 0x7a, 0x8f, 0x49, 0xfb, 0xff, 0xfa, 0x37, 0x79, 0xfd, 0xea, 0xba, 0xd3, 0xeb, 0xdf, 0x5c, 0xe7, 0xd4, 0x8e, 0xf0, 0xca, 0xa9, 0xbd, 0xa7, 0xbd, 0xb3, 0xfe, 0x1e, 0xed, 0xdd, 0x7b, 0xda, 0xdd, 0x73, 0x70, 0x83, 0xe5, 0xbe, 0x26, 0x5b, 0xea, 0x6d, 0x71, 0x3e, 0x74, 0x75, 0x7b, 0xbd, 0x6d, 0xa6, 0xed, 0xf5, 0xb6, 0xbf, 0xf0, 0x88, 0xed, 0x91, 0xe7, 0x1e, 0xf9, 0x51, 0xe3, 0xd1, 0x31, 0xcf, 0x9d, 0xdb, 0xd3, 0xe8, 0xa5, 0x69, 0xfb, 0x2f, 0xbe, 0xa2, 0x3d, 0xf5, 0xce, 0xaa, 0x7d, 0x62, 0x15, 0x95, 0x2c, 0x11, 0x0f, 0x63, 0xe9, 0xdf, 0x88, 0xb3, 0x28, 0xdd,\n\t0x21, 0x8a, 0xc5, 0xcb, 0xa2, 0x54, 0x09, 0x15, 0x6f, 0x28, 0xfd, 0x95, 0x70, 0x51, 0xa2, 0x0c, 0x56, 0xc6, 0x8a, 0x4b, 0xca, 0x78, 0x65, 0x82, 0x90, 0xca, 0x24, 0xfe, 0x29, 0xca, 0x54, 0xfe, 0x99, 0xc4, 0x29, 0xe1, 0x25, 0x3f, 0x15, 0xde, 0xe0, 0x23, 0xdf, 0x15, 0x81, 0xf2, 0x6b, 0xd1, 0x44, 0x16, 0x8b, 0x76, 0xf2, 0x4b, 0xd1, 0x5e, 0x7e, 0x23, 0x3a, 0xc9, 0x0f, 0x44, 0x67, 0x59, 0x24, 0xba, 0xca, 0xb7, 0xc4, 0x32, 0xf9, 0xb6, 0x58, 0x2f, 0x2f, 0x89, 0x7b, 0x64, 0xb9, 0x48, 0x97, 0x3f, 0x8a, 0x07, 0x65, 0x96, 0x78, 0x48, 0x1e, 0x15, 0xdf, 0xca, 0xcf, 0xc5, 0x61, 0xae, 0xff, 0x41, 0x9e, 0x37, 0x0d, 0x97, 0x07, 0x4d, 0xa3, 0x61, 0x26, 0xdc, 0x21, 0xdf, 0x32, 0xc5, 0xca, 0x48, 0xd3, 0x16, 0xf9, 0xab, 0xe9, 0x01, 0x79, 0xca, 0xb4, 0x43, 0x6e, 0xf3, 0x7a, 0x56, 0x7e,\n\t0xee, 0xd3, 0x57, 0x96, 0xfa, 0x84, 0xc1, 0x97, 0xf2, 0x94, 0xcf, 0x69, 0x99, 0x6f, 0xee, 0x2a, 0x3f, 0x35, 0x77, 0x83, 0xee, 0xd0, 0x03, 0x7a, 0x42, 0x28, 0xf4, 0x82, 0xde, 0xd0, 0x07, 0xfa, 0x42, 0x18, 0xf4, 0x87, 0x01, 0x30, 0x10, 0xc2, 0x61, 0x10, 0x0c, 0x86, 0x21, 0x30, 0x14, 0x86, 0x41, 0x04, 0x0c, 0x87, 0x11, 0x30, 0x12, 0x46, 0xc1, 0x68, 0x18, 0x03, 0x63, 0x61, 0x1c, 0x4c, 0x00, 0xed, 0x5b, 0x64, 0x93, 0x44, 0x23, 0xf3, 0x64, 0xf6, 0xa7, 0xc0, 0x54, 0x5e, 0x4f, 0x13, 0xcd, 0xcd, 0xd3, 0xd9, 0x9f, 0x01, 0x33, 0x61, 0x16, 0xdc, 0x0e, 0xb3, 0x61, 0x0e, 0xcc, 0xe5, 0x9c, 0x79, 0x5c, 0x73, 0x07, 0xfb, 0xf3, 0x61, 0x01, 0xaf, 0x17, 0x72, 0xcd, 0x22, 0xf6, 0x23, 0x21, 0x4a, 0xbe, 0x6b, 0x8e, 0x86, 0xfb, 0xe5, 0x9d, 0xe6, 0xa7, 0x44, 0x03, 0xf3, 0xd3, 0xe2, 0x47,\n\t0xf3, 0x33, 0x22, 0xdf, 0xfc, 0xac, 0x08, 0x34, 0x3f, 0x27, 0xb2, 0xcc, 0x7b, 0x44, 0x91, 0x79, 0xaf, 0xbc, 0x68, 0x7e, 0x5e, 0x78, 0x99, 0xdf, 0xe5, 0xfd, 0xf7, 0x78, 0xff, 0x7d, 0xde, 0xff, 0x40, 0x4c, 0x36, 0x7f, 0xc8, 0x39, 0x1f, 0x71, 0xce, 0xc7, 0x9c, 0xf3, 0x4f, 0x5e, 0x7f, 0xc2, 0x79, 0x9f, 0x72, 0xce, 0xbf, 0xe1, 0x33, 0xce, 0xfb, 0x9c, 0xf3, 0x0e, 0x72, 0xfc, 0x0b, 0xce, 0xfb, 0x92, 0xf3, 0xbe, 0xe2, 0xbc, 0xaf, 0x79, 0x7d, 0x42, 0x34, 0x35, 0x9f, 0x14, 0xa7, 0xcd, 0xa7, 0xc4, 0x65, 0x73, 0xae, 0x98, 0x63, 0xce, 0x13, 0xad, 0xcc, 0xa7, 0x45, 0x81, 0xf9, 0x8c, 0xa8, 0x32, 0xff, 0x2a, 0xe6, 0x99, 0xcf, 0xca, 0x2a, 0xf3, 0x39, 0xd1, 0xd8, 0xec, 0x94, 0x5f, 0x9b, 0xcf, 0xcb, 0xaf, 0x2d, 0x4d, 0xe4, 0xb7, 0x96, 0xae, 0xd2, 0x69, 0xe9, 0x26, 0x5e, 0xb7, 0x74,\n\t0x17, 0x07, 0x2d, 0x3d, 0x64, 0x81, 0xa5, 0xa7, 0x78, 0xc7, 0x12, 0x2a, 0xbe, 0xb2, 0xf4, 0x92, 0x87, 0x2c, 0xbd, 0x65, 0x89, 0x65, 0x9a, 0xfc, 0xd2, 0x32, 0x1d, 0x66, 0xc0, 0x2c, 0x98, 0x0d, 0x73, 0x60, 0x2e, 0xcc, 0x83, 0x64, 0xf9, 0x81, 0x65, 0x05, 0xa4, 0xc8, 0x22, 0x4b, 0x2a, 0xa4, 0xc1, 0x4a, 0x58, 0x05, 0xab, 0x61, 0x9d, 0x7c, 0xcb, 0xb2, 0x1e, 0xee, 0x81, 0x0d, 0x70, 0x2f, 0x6c, 0x14, 0x5d, 0x2d, 0x9b, 0xd8, 0x6e, 0x86, 0xfb, 0xe0, 0x7e, 0xd8, 0x02, 0x0f, 0x40, 0xba, 0x88, 0xb0, 0x3c, 0xa8, 0x4c, 0xb7, 0x6c, 0x55, 0x26, 0x5a, 0x1e, 0x12, 0xbb, 0x2c, 0x0f, 0x8b, 0xde, 0x96, 0x6d, 0x9c, 0xbf, 0x9d, 0xf7, 0x1e, 0x91, 0x6f, 0xa9, 0x3d, 0x65, 0x89, 0x3a, 0x18, 0x86, 0xcb, 0xcf, 0xd4, 0xfb, 0xd8, 0xee, 0x92, 0x97, 0xd4, 0x67, 0x65, 0x81, 0x9a, 0x29, 0x7f, 0x54,\n\t0xb3, 0x20, 0x5b, 0x66, 0xa9, 0x39, 0x70, 0x02, 0x4e, 0xc2, 0x29, 0xc8, 0x85, 0x3c, 0x38, 0x27, 0x8f, 0xaa, 0x0e, 0xc8, 0x87, 0x02, 0x70, 0x42, 0x31, 0x9c, 0x87, 0x0b, 0x70, 0x11, 0x4a, 0xe4, 0x51, 0x6b, 0x4b, 0xf1, 0x88, 0x35, 0x44, 0x6c, 0xb3, 0xb6, 0x12, 0x36, 0xab, 0x4d, 0x16, 0x58, 0x5b, 0xf3, 0xba, 0x8d, 0x78, 0xde, 0xda, 0x96, 0xd7, 0x9d, 0xd8, 0xef, 0xcc, 0x7b, 0x5d, 0xd8, 0xef, 0xca, 0x7b, 0xdd, 0x78, 0xdd, 0x9d, 0xf7, 0x88, 0x51, 0xac, 0x33, 0x65, 0xb9, 0xf5, 0x17, 0xf9, 0xa4, 0xdf, 0x28, 0x99, 0xe3, 0xf7, 0x86, 0xa8, 0xe7, 0xf7, 0x0f, 0xf9, 0xb9, 0xdf, 0x9b, 0xca, 0x08, 0xbf, 0xb7, 0x94, 0x29, 0x7e, 0x6f, 0x8b, 0x74, 0xbf, 0x77, 0x44, 0x73, 0xbf, 0x77, 0x45, 0x17, 0xbf, 0xf7, 0x38, 0xfe, 0x3e, 0x7c, 0x40, 0x4c, 0x6b, 0x13, 0x26, 0x2c, 0xa6, 0x89, 0x74,\n\t0x61, 0x65, 0x1b, 0x44, 0xb8, 0x2c, 0x14, 0x76, 0xd8, 0x26, 0x9f, 0x13, 0xdb, 0xe5, 0x63, 0xe2, 0x11, 0xf9, 0xae, 0xd2, 0x4f, 0x66, 0x2b, 0xe3, 0xe5, 0x36, 0x65, 0xa6, 0x3c, 0xa9, 0xdc, 0x2e, 0x4b, 0x95, 0xd9, 0xf2, 0x11, 0x25, 0x52, 0x9e, 0x57, 0xa2, 0x21, 0x46, 0x6e, 0x52, 0xec, 0x72, 0xaf, 0x52, 0x22, 0x9d, 0x4a, 0xb9, 0x74, 0x9b, 0xc6, 0xc9, 0x33, 0x26, 0xbb, 0x3c, 0x66, 0xda, 0x22, 0xba, 0x61, 0x69, 0xaf, 0x98, 0x3e, 0x90, 0x65, 0xde, 0x9b, 0xe4, 0x13, 0xde, 0x4f, 0xc8, 0x72, 0xac, 0x6d, 0x1d, 0xd6, 0xb6, 0x0e, 0x6b, 0x7b, 0xc5, 0x9a, 0x2b, 0x5f, 0xf7, 0xdb, 0x26, 0xab, 0xfc, 0xb6, 0xcb, 0x2a, 0xd1, 0xfe, 0x77, 0x5b, 0xb0, 0x84, 0x75, 0xf0, 0xd6, 0x56, 0x44, 0x88, 0x26, 0xca, 0x70, 0xd0, 0x5a, 0x33, 0x5d, 0xf8, 0x29, 0x33, 0x45, 0x23, 0xe5, 0x76, 0xd1, 0xf0,\n\t0x7f, 0xaf, 0x45, 0x42, 0xf1, 0xfe, 0x9b, 0xf0, 0xfb, 0xc3, 0x56, 0x35, 0x30, 0x5a, 0x54, 0x4c, 0x8b, 0xca, 0x68, 0xd1, 0x05, 0xfa, 0x7f, 0x9e, 0xfe, 0x97, 0x50, 0x5a, 0x15, 0x25, 0x39, 0x4d, 0x6f, 0xca, 0x2f, 0x29, 0xed, 0x22, 0x7d, 0xfb, 0xc5, 0xfb, 0x6f, 0xb2, 0x8c, 0x12, 0x9c, 0x6a, 0x88, 0xf0, 0x56, 0x7b, 0x09, 0xed, 0x2f, 0x83, 0xe1, 0xf2, 0x22, 0x71, 0x4c, 0x73, 0x11, 0x23, 0x5d, 0xca, 0x6c, 0x61, 0x51, 0x62, 0x44, 0x7d, 0xae, 0x3a, 0xcb, 0x55, 0xe5, 0x9c, 0x79, 0x96, 0x33, 0x9b, 0xa9, 0xad, 0x44, 0x27, 0xd5, 0x26, 0x7a, 0xaa, 0xad, 0xc5, 0x6d, 0x6a, 0x1b, 0xe1, 0xcf, 0x95, 0x2d, 0x45, 0xb0, 0xb0, 0xca, 0x4a, 0xd1, 0x10, 0x9a, 0x50, 0x42, 0x7b, 0x79, 0x4a, 0x2f, 0xc9, 0xce, 0xb8, 0xf7, 0x97, 0x47, 0x95, 0x31, 0xb2, 0x40, 0x99, 0xce, 0x48, 0xcc, 0x94, 0x47,\n\t0x68, 0xcb, 0x71, 0xda, 0x72, 0xc5, 0xb4, 0x54, 0x56, 0x52, 0xaa, 0x53, 0x6f, 0xcb, 0x63, 0x32, 0x8b, 0xf6, 0x1c, 0xa1, 0x3d, 0x59, 0x3e, 0x21, 0xb2, 0xd2, 0x27, 0x0f, 0x4e, 0xcb, 0x4a, 0x33, 0xe7, 0x98, 0xd7, 0xc2, 0xdd, 0x50, 0x29, 0x2b, 0x2d, 0x03, 0x65, 0x25, 0x3d, 0x3d, 0x43, 0x4f, 0xcf, 0x88, 0x20, 0x6a, 0xf8, 0x99, 0x76, 0xe6, 0x53, 0x8b, 0x8b, 0x71, 0x6f, 0x2a, 0xd6, 0xca, 0x42, 0xc6, 0x4d, 0xeb, 0xe5, 0x2f, 0x5a, 0x7b, 0x29, 0xd9, 0x41, 0x9b, 0x7f, 0xb1, 0xbc, 0x24, 0x1a, 0x5a, 0x72, 0x65, 0xae, 0x1a, 0x4c, 0xdb, 0x5b, 0xca, 0x4a, 0xfa, 0xd0, 0x8a, 0x3e, 0x34, 0xa2, 0x0f, 0x8d, 0x68, 0xbf, 0x45, 0xed, 0x20, 0x3a, 0xd0, 0x87, 0x76, 0x44, 0x34, 0x26, 0xf9, 0x13, 0xa5, 0xee, 0x12, 0x91, 0xc4, 0x4e, 0x31, 0xf2, 0x0d, 0x4a, 0xfc, 0x96, 0xf6, 0x4f, 0x51, 0x06,\n\t0xc8, 0x12, 0x65, 0xa0, 0xbc, 0x48, 0x3f, 0x5e, 0x54, 0x4a, 0xe5, 0x69, 0xa5, 0x0c, 0xca, 0x65, 0x3e, 0xb5, 0x5d, 0xa1, 0xb6, 0x3c, 0x6a, 0xdb, 0x4b, 0x6d, 0xcf, 0x50, 0x5b, 0x9e, 0xe5, 0x25, 0xf9, 0xab, 0x51, 0x5b, 0x6b, 0x6a, 0xcb, 0xa1, 0xb6, 0x4e, 0xd4, 0xd6, 0x82, 0xda, 0x5a, 0x30, 0x62, 0xbe, 0xd4, 0x18, 0x40, 0x8d, 0x3d, 0xa8, 0xb1, 0x9b, 0x1a, 0x85, 0x75, 0x6d, 0x62, 0xd5, 0xb0, 0x52, 0x6b, 0x05, 0xfd, 0xa8, 0x66, 0x84, 0xca, 0x28, 0xb1, 0x88, 0x12, 0x0b, 0x29, 0xb1, 0x82, 0x51, 0xb9, 0x44, 0xa9, 0x45, 0x94, 0xa0, 0x50, 0x82, 0xc5, 0xa4, 0x08, 0x33, 0x63, 0x6c, 0x01, 0x7f, 0xb8, 0x0d, 0x82, 0x81, 0x5e, 0x09, 0x1b, 0x74, 0x66, 0x65, 0xe9, 0x2e, 0x4f, 0x8a, 0x1e, 0xd0, 0x13, 0x42, 0x51, 0x64, 0x2f, 0xf9, 0x8b, 0xe8, 0x0d, 0x7d, 0xa0, 0x2f, 0x84, 0x41, 0x3f,\n\t0xe8, 0x2f, 0x73, 0xc4, 0x00, 0x18, 0x08, 0xe1, 0x32, 0x57, 0x0c, 0xe2, 0xd8, 0x60, 0x18, 0x22, 0x2f, 0x88, 0xa1, 0x30, 0x0c, 0x22, 0x60, 0x38, 0x8c, 0x80, 0x91, 0x30, 0x0a, 0x46, 0xc3, 0x18, 0x18, 0x0b, 0xe3, 0x60, 0x3c, 0x4c, 0x80, 0x89, 0x30, 0x09, 0x26, 0xc3, 0x14, 0x98, 0x0a, 0xd3, 0x60, 0x3a, 0xcc, 0x80, 0x99, 0x30, 0x0b, 0x6e, 0x87, 0xd9, 0x30, 0x07, 0xe6, 0xc2, 0x3c, 0xb8, 0x03, 0xe6, 0xc3, 0x02, 0x58, 0x28, 0x33, 0xc5, 0x22, 0x99, 0x2d, 0xee, 0xa4, 0xed, 0x8b, 0x21, 0x12, 0xa2, 0x58, 0x41, 0xa3, 0x21, 0x06, 0xec, 0xb2, 0x44, 0x2c, 0x61, 0xbb, 0x14, 0x62, 0x79, 0x2f, 0x0e, 0x96, 0xc1, 0x72, 0x88, 0x87, 0x04, 0x48, 0x84, 0x24, 0xfa, 0x92, 0x0c, 0x2b, 0x20, 0x85, 0xd7, 0xa9, 0x90, 0x46, 0x5f, 0x57, 0xb2, 0x5d, 0xc5, 0xd8, 0xac, 0x86, 0xbb, 0x60, 0x0d, 0xa0,\n\t0x1c, 0x71, 0x37, 0x75, 0xaf, 0x63, 0x7f, 0x3d, 0xdc, 0x03, 0x1b, 0xe0, 0x5e, 0xd8, 0x08, 0x9b, 0x60, 0x33, 0xdc, 0x07, 0xf7, 0xc3, 0x16, 0xe9, 0x10, 0x0f, 0x40, 0x3a, 0x71, 0xf1, 0x83, 0x44, 0x0f, 0x5b, 0x89, 0x28, 0x1f, 0x22, 0xc6, 0x7c, 0x58, 0x9e, 0x55, 0xf2, 0x65, 0xa5, 0x52, 0x28, 0x7f, 0x51, 0x8a, 0xa4, 0xc3, 0x34, 0x0a, 0x8d, 0x4f, 0x84, 0xe9, 0x70, 0x27, 0x24, 0x33, 0xab, 0x2b, 0x20, 0x15, 0x85, 0xd2, 0x16, 0xd3, 0x5d, 0xec, 0xaf, 0x81, 0x75, 0x40, 0x9d, 0x26, 0xea, 0x34, 0x6d, 0xc4, 0xda, 0xb6, 0xc8, 0x4c, 0x54, 0x50, 0x6a, 0x4a, 0xe7, 0x9c, 0xad, 0xbc, 0x7e, 0x94, 0xe3, 0x4f, 0xb0, 0xbf, 0x03, 0x05, 0x3c, 0xc9, 0xb9, 0x4f, 0xc1, 0xd3, 0x1c, 0xdf, 0x2b, 0x2f, 0x98, 0x9e, 0x87, 0x17, 0xe0, 0x45, 0xd8, 0x07, 0x2f, 0xc1, 0x7e, 0x78, 0x19, 0x5e, 0x81, 0x03,\n\t0xf0, 0x2a, 0xd7, 0xff, 0x1d, 0xde, 0x94, 0xc5, 0xa8, 0xea, 0x9c, 0x37, 0xe3, 0xeb, 0x9d, 0x26, 0x0b, 0x7d, 0x82, 0xe0, 0xdf, 0xf2, 0x82, 0xcf, 0x67, 0xf0, 0x85, 0x2c, 0x42, 0x69, 0xa5, 0x3e, 0x47, 0xd8, 0x3f, 0x0a, 0x3f, 0xc0, 0x8f, 0x70, 0x0c, 0x4e, 0x61, 0x8f, 0x67, 0xe4, 0x2f, 0x3e, 0x05, 0x32, 0xc7, 0xe7, 0xbc, 0x74, 0xf8, 0xb6, 0x95, 0x85, 0xbe, 0xed, 0xa0, 0x83, 0x3c, 0xe9, 0x5b, 0x25, 0x7f, 0x31, 0x2f, 0xc7, 0x3e, 0xe3, 0x21, 0x01, 0x12, 0x21, 0x05, 0xf6, 0xc1, 0x4b, 0xb0, 0x1f, 0x5e, 0x86, 0x57, 0xe0, 0x00, 0xbc, 0x8a, 0x1d, 0xd7, 0x07, 0xf4, 0x6b, 0x69, 0x00, 0xf8, 0x0c, 0x4b, 0x00, 0x34, 0x82, 0x40, 0x08, 0x82, 0x66, 0xd0, 0x1c, 0x5a, 0x00, 0x1a, 0xb7, 0xa0, 0x71, 0x0b, 0x1a, 0xb7, 0xe0, 0x1b, 0x2c, 0xad, 0x00, 0xad, 0x5b, 0x5a, 0x43, 0x1b, 0x68, 0x0b,\n\t0xed, 0xa0, 0x3d, 0x74, 0x80, 0x8e, 0xd0, 0x09, 0x3a, 0x43, 0x17, 0xe8, 0x0b, 0x29, 0xb2, 0x9c, 0x55, 0xb6, 0x9c, 0x55, 0xb6, 0x9c, 0x55, 0xb6, 0x9c, 0x55, 0xb6, 0x9c, 0x55, 0xb6, 0xdc, 0xb2, 0x5b, 0x9e, 0xb4, 0x3c, 0x09, 0x4f, 0xc1, 0xd3, 0xf0, 0x0c, 0x3c, 0x0b, 0xcf, 0xc1, 0x1e, 0xd8, 0x0b, 0x2f, 0xc0, 0x8b, 0xb0, 0x0f, 0x5e, 0x82, 0xfd, 0xf0, 0x32, 0xbc, 0x02, 0x07, 0x80, 0xb1, 0xb5, 0x30, 0xb6, 0x96, 0xd7, 0xe0, 0x75, 0x78, 0x03, 0xfe, 0x01, 0x6f, 0xc2, 0x5b, 0xf0, 0x36, 0xbc, 0x0f, 0x1f, 0xc0, 0x87, 0xf0, 0x11, 0x7c, 0x0c, 0x9f, 0xc8, 0x42, 0xcb, 0xa7, 0xf0, 0x2f, 0xf8, 0x0c, 0x2f, 0xf5, 0x39, 0x1c, 0x84, 0x2f, 0xe0, 0x1b, 0xf8, 0x56, 0xe6, 0x58, 0x0e, 0xc1, 0x61, 0xf8, 0x0e, 0x8e, 0xc2, 0x0f, 0x1c, 0xff, 0x11, 0x8e, 0xc1, 0x4f, 0xf0, 0x33, 0x64, 0xc0, 0x71,\n\t0xc8, 0x84, 0x1c, 0x38, 0x01, 0x27, 0xe1, 0x14, 0xe4, 0x42, 0x1e, 0x9c, 0x06, 0xe6, 0xcf, 0xf2, 0x2b, 0x9c, 0x03, 0x07, 0xe4, 0x43, 0x01, 0xa0, 0x55, 0x8b, 0x13, 0x8a, 0xe1, 0xbc, 0xbc, 0x60, 0xb9, 0x08, 0x25, 0x50, 0x0a, 0x65, 0x50, 0x0e, 0x97, 0xa0, 0x02, 0x2a, 0xe1, 0x32, 0x5c, 0x81, 0xab, 0x50, 0x05, 0xd5, 0xe0, 0x02, 0x37, 0x5c, 0x83, 0x1a, 0x90, 0x32, 0x53, 0x15, 0xa0, 0x80, 0x09, 0xbc, 0xc0, 0x1b, 0x7c, 0xc0, 0x57, 0x66, 0xab, 0x66, 0xb0, 0x80, 0x0a, 0xf5, 0xc1, 0x1f, 0x1a, 0x40, 0x43, 0x59, 0xa8, 0x06, 0x40, 0x23, 0x08, 0x04, 0xf4, 0xa9, 0x36, 0x86, 0xa6, 0x78, 0xc0, 0xe6, 0xd0, 0x02, 0x82, 0xa1, 0x25, 0x84, 0xc8, 0x2a, 0xb5, 0x15, 0x5b, 0x1b, 0xb4, 0x86, 0x36, 0xd0, 0x1e, 0x3a, 0x40, 0x27, 0xe8, 0x06, 0xdd, 0xa1, 0x27, 0xf4, 0x92, 0x35, 0x6a, 0x1f, 0xca,\n\t0xe9, 0x0b, 0x61, 0xd0, 0x0f, 0xfa, 0x03, 0xab, 0xb6, 0x3a, 0x08, 0x06, 0xc3, 0x10, 0x18, 0x0a, 0xc3, 0x20, 0x02, 0x86, 0xc3, 0x08, 0x18, 0x05, 0xa3, 0x61, 0x0c, 0x8c, 0x87, 0x09, 0x30, 0x11, 0x26, 0xc1, 0x64, 0x98, 0x02, 0x53, 0x61, 0x1a, 0x4c, 0x87, 0x99, 0x30, 0x4b, 0xfe, 0xa2, 0xde, 0x0e, 0xb3, 0x61, 0x0e, 0xcc, 0x85, 0x79, 0x70, 0x07, 0xcc, 0x87, 0x3b, 0x61, 0x31, 0x44, 0x42, 0x14, 0x44, 0x43, 0x0c, 0xd8, 0x61, 0x09, 0x2c, 0x85, 0x58, 0x88, 0x83, 0x65, 0xb0, 0x1c, 0xe2, 0x21, 0x01, 0x12, 0xe1, 0x2e, 0x58, 0x03, 0x6b, 0x01, 0xdf, 0xa1, 0xae, 0x87, 0x8d, 0xb0, 0x09, 0x36, 0xc3, 0x7d, 0x70, 0x3f, 0x6c, 0x81, 0x07, 0xe0, 0x41, 0xd8, 0x0a, 0x0f, 0xc9, 0x93, 0xea, 0xc3, 0xb0, 0x0d, 0xb6, 0x03, 0x7e, 0x45, 0x7d, 0x0c, 0x1e, 0x87, 0x27, 0x60, 0x07, 0xec, 0x02, 0xec,\n\t0x42, 0xc5, 0x2e, 0x54, 0xec, 0x42, 0xc5, 0x2e, 0x54, 0xec, 0x82, 0x68, 0xf1, 0xa4, 0x8a, 0x5d, 0xa8, 0xd8, 0x85, 0x8a, 0x5d, 0xa8, 0xcf, 0x03, 0xb6, 0xa1, 0x62, 0x1b, 0x2a, 0xb6, 0xa1, 0x62, 0x1b, 0x2a, 0xb6, 0xa1, 0x62, 0x1b, 0x2a, 0xb6, 0xa1, 0x62, 0x1b, 0x2a, 0xb6, 0xa1, 0x62, 0x1b, 0x2a, 0xb6, 0xa1, 0x62, 0x1b, 0x2a, 0xb6, 0xa1, 0x62, 0x1b, 0x2a, 0xb6, 0xa1, 0x62, 0x1b, 0x2a, 0xb6, 0xa1, 0xbe, 0x03, 0xef, 0xc2, 0x7b, 0x80, 0x9d, 0xa8, 0xd8, 0x89, 0x8a, 0x9d, 0xa8, 0xd8, 0x89, 0x8a, 0x9d, 0xa8, 0xff, 0x84, 0x4f, 0xe0, 0x53, 0xf8, 0x97, 0x74, 0xa8, 0xff, 0x86, 0xcf, 0xe0, 0x73, 0x38, 0x08, 0x5f, 0xc0, 0x97, 0xf0, 0x15, 0x7c, 0x03, 0xdf, 0xc2, 0x21, 0x38, 0x0c, 0xdf, 0xc1, 0xf7, 0x70, 0x04, 0x8e, 0xc2, 0x0f, 0xf0, 0x23, 0x1c, 0x83, 0x9f, 0x20, 0x03, 0x8e, 0x43,\n\t0xa6, 0xf0, 0x51, 0xb3, 0x20, 0x5b, 0x98, 0xd4, 0x1c, 0x38, 0x01, 0x27, 0xe1, 0x14, 0xe4, 0x42, 0x1e, 0x9c, 0x21, 0x46, 0xfa, 0x15, 0xce, 0x11, 0x31, 0x38, 0x20, 0x1f, 0x0a, 0xc0, 0x09, 0xc5, 0x70, 0x1e, 0x2e, 0xc0, 0x45, 0x28, 0x81, 0x4b, 0x44, 0x4b, 0x15, 0x50, 0x09, 0x97, 0xe1, 0x0a, 0x5c, 0x95, 0x67, 0x89, 0x74, 0x0b, 0xad, 0x4e, 0x59, 0x69, 0x2d, 0x86, 0xf3, 0x70, 0x01, 0x2e, 0x42, 0x85, 0xfc, 0xc5, 0x5a, 0x09, 0x97, 0xe1, 0x0a, 0x5c, 0x85, 0x2a, 0xe9, 0xb0, 0x56, 0x83, 0x0b, 0xdc, 0x70, 0x4d, 0x3a, 0xfc, 0xf0, 0x05, 0x44, 0x6a, 0xda, 0x8a, 0xad, 0xaf, 0x84, 0x42, 0xd1, 0x57, 0x0a, 0xc3, 0xb3, 0x6b, 0x1e, 0x5c, 0xb7, 0x0c, 0x14, 0x4f, 0x2c, 0x18, 0xce, 0x3a, 0x1a, 0xa3, 0x47, 0xa6, 0x17, 0x88, 0x63, 0xce, 0x13, 0xbf, 0x5c, 0xe0, 0x6c, 0x2d, 0xee, 0xca, 0xe3,\n\t0xec, 0x93, 0x46, 0x74, 0x51, 0x89, 0x5f, 0x3b, 0x8b, 0x4d, 0x15, 0x72, 0xa5, 0xc4, 0x7e, 0x6a, 0x88, 0x4d, 0xbc, 0x45, 0x13, 0xae, 0xfe, 0x90, 0x2b, 0xaf, 0xb2, 0x8a, 0x1e, 0x21, 0x4e, 0xcd, 0x24, 0x4e, 0xcd, 0x22, 0x1e, 0xf4, 0x27, 0xea, 0x39, 0x4b, 0x04, 0x57, 0x41, 0x6c, 0x1a, 0x4a, 0x69, 0x8f, 0x51, 0xd2, 0x09, 0x4a, 0xf9, 0x84, 0x38, 0x6b, 0x00, 0x1e, 0xc7, 0x45, 0xe4, 0x33, 0x9c, 0x58, 0xc5, 0x9f, 0x68, 0xa7, 0x3e, 0xd1, 0x4e, 0x2f, 0xa2, 0x9d, 0x29, 0xa8, 0xbc, 0x1c, 0xb5, 0x1e, 0x21, 0x56, 0xfd, 0x89, 0x58, 0xd1, 0x44, 0x76, 0x1c, 0x2e, 0x0f, 0x52, 0xfa, 0x0f, 0x44, 0xcb, 0x7d, 0x89, 0x96, 0xfb, 0x10, 0x2d, 0xf7, 0x21, 0x5a, 0xce, 0x23, 0x4a, 0x4e, 0x51, 0xa6, 0xd6, 0x9c, 0x25, 0x3a, 0xee, 0x4d, 0xad, 0xa7, 0xa9, 0xf5, 0x34, 0xd1, 0x71, 0x2f, 0xa2, 0xe3,\n\t0xde, 0x44, 0xc7, 0x55, 0xd4, 0x5e, 0x48, 0xed, 0x5f, 0x51, 0xbb, 0x95, 0xda, 0xa7, 0xd1, 0x97, 0xab, 0xb4, 0xc0, 0x49, 0x74, 0xdc, 0xdb, 0x7b, 0xab, 0x8c, 0xf5, 0xde, 0x25, 0x2f, 0x12, 0x1d, 0xf7, 0x27, 0x3a, 0xee, 0x4b, 0xab, 0xa6, 0x51, 0x63, 0xb8, 0x18, 0xa6, 0xd7, 0xd8, 0x4e, 0x26, 0x12, 0x99, 0x26, 0x92, 0x93, 0xef, 0x26, 0x52, 0xda, 0x43, 0x4e, 0xbe, 0xfb, 0x0f, 0x5b, 0x31, 0x44, 0x4e, 0x52, 0x86, 0xc1, 0x78, 0xb9, 0xc6, 0x68, 0xcd, 0x14, 0x65, 0xa1, 0x9c, 0xa5, 0x2c, 0x82, 0x1b, 0xad, 0x5a, 0x71, 0x53, 0xab, 0xee, 0x90, 0xbb, 0xf5, 0x96, 0xc5, 0xb2, 0xfd, 0xcf, 0xad, 0x9b, 0x41, 0xeb, 0xa6, 0x6a, 0xad, 0x23, 0x4f, 0x4c, 0x24, 0x4f, 0x4c, 0x24, 0x47, 0x4c, 0x24, 0x47, 0x4c, 0x24, 0x47, 0x4c, 0x24, 0x47, 0x4c, 0x24, 0x47, 0x4c, 0x24, 0x47, 0xdc, 0x4d, 0x8e,\n\t0xb8, 0x9b, 0xd5, 0x6b, 0x0f, 0xab, 0xd7, 0x1e, 0x56, 0xaf, 0x3d, 0xac, 0x5e, 0x7b, 0x58, 0xbd, 0xf6, 0xb0, 0x7a, 0xed, 0x21, 0x47, 0xdc, 0x4d, 0x8e, 0xb8, 0x9b, 0x1c, 0x71, 0x37, 0x39, 0xe2, 0x6e, 0xf2, 0xc2, 0xdd, 0xe4, 0x85, 0xbb, 0xc9, 0x0b, 0x77, 0x93, 0x17, 0xee, 0x26, 0x2f, 0xdc, 0xad, 0xf7, 0xde, 0x52, 0xab, 0x96, 0x3f, 0x54, 0x4a, 0xdd, 0xe8, 0xbd, 0x84, 0x31, 0xca, 0xe5, 0x8a, 0x12, 0xae, 0x28, 0xab, 0x13, 0xbd, 0xe7, 0x10, 0x9b, 0xfe, 0x40, 0xf4, 0x9e, 0x75, 0x4b, 0xf4, 0x5e, 0x42, 0xf4, 0xfe, 0x0b, 0x4a, 0x3a, 0xfa, 0x27, 0xa3, 0xf7, 0x5f, 0x89, 0xde, 0x7f, 0x15, 0x81, 0x37, 0x45, 0xef, 0xff, 0xd3, 0xc8, 0x3d, 0x90, 0xf9, 0x3d, 0xa4, 0x67, 0x3e, 0xe1, 0xf2, 0x80, 0xd0, 0x9e, 0x6c, 0x1a, 0x23, 0x2f, 0xd3, 0xf6, 0x91, 0xb4, 0x7d, 0xbf, 0x16, 0x53, 0x2b,\n\t0x77, 0x52, 0x6a, 0xac, 0x1e, 0x57, 0x57, 0x51, 0xfa, 0x69, 0xda, 0x9b, 0x43, 0x7b, 0x2f, 0x19, 0xd1, 0x79, 0x00, 0xa5, 0x74, 0xaf, 0xcd, 0xa1, 0x94, 0xd6, 0xc2, 0x8b, 0xb6, 0x79, 0x43, 0x20, 0x39, 0x40, 0x1b, 0xe9, 0x16, 0x6d, 0xa1, 0x1d, 0x4a, 0x69, 0x0f, 0x9d, 0x64, 0x86, 0x7e, 0x47, 0xa7, 0x8b, 0xfc, 0x18, 0x05, 0x1d, 0x10, 0xdd, 0x78, 0xdd, 0x9d, 0x9a, 0x7b, 0x40, 0x4f, 0x08, 0x85, 0x85, 0x70, 0x27, 0x2c, 0x86, 0x48, 0x88, 0x82, 0x68, 0x88, 0xd1, 0x32, 0x15, 0x58, 0x0a, 0xb1, 0x10, 0x07, 0xcb, 0x60, 0x39, 0xc4, 0x43, 0x02, 0x24, 0x42, 0x0a, 0xa4, 0xc2, 0x4a, 0x7d, 0x6c, 0x5c, 0xc4, 0x9b, 0x6e, 0xe2, 0x4d, 0xb7, 0xd8, 0x2a, 0xab, 0x89, 0x31, 0xdd, 0x4a, 0x98, 0x3e, 0x33, 0x5f, 0x29, 0xe1, 0xf2, 0x53, 0x65, 0x10, 0x44, 0xc8, 0x6f, 0x94, 0xe1, 0x30, 0x86, 0x5c,\n\t0x77, 0xba, 0x9e, 0xf3, 0xfd, 0xc2, 0x4c, 0x95, 0xa3, 0xd0, 0x4b, 0xc4, 0xa1, 0x6e, 0x94, 0x79, 0xc0, 0x34, 0x5f, 0x66, 0x98, 0x62, 0x20, 0x96, 0xfd, 0x78, 0xb6, 0xc9, 0xd2, 0x45, 0x2c, 0xea, 0x22, 0x06, 0x75, 0x11, 0x83, 0xba, 0x88, 0x41, 0x5d, 0xc4, 0x9e, 0x6e, 0x62, 0x4f, 0x17, 0x31, 0xa7, 0x9b, 0x38, 0xd3, 0x45, 0x9c, 0xe9, 0x22, 0xce, 0x74, 0x13, 0x2b, 0xba, 0x98, 0xe5, 0x62, 0x23, 0x67, 0xbc, 0x44, 0xdc, 0xe8, 0x42, 0xc5, 0xe5, 0xa8, 0xb8, 0x9c, 0xb8, 0xd1, 0x45, 0x4c, 0xe8, 0x26, 0x26, 0x74, 0x11, 0x13, 0xba, 0xcc, 0x5d, 0xe5, 0xcf, 0xe6, 0x6e, 0xd0, 0x1d, 0x7a, 0x40, 0x4f, 0x08, 0x85, 0x5e, 0xd0, 0x1b, 0xfa, 0x40, 0x7f, 0x18, 0x00, 0x03, 0x01, 0x1d, 0x98, 0x07, 0xc1, 0x60, 0x18, 0x02, 0x43, 0x61, 0x18, 0x44, 0xc0, 0x70, 0x18, 0x01, 0x23, 0x61, 0x14, 0x8c,\n\t0x86, 0x31, 0x30, 0x16, 0xc6, 0x41, 0x24, 0x38, 0xe5, 0x1b, 0xe6, 0xf3, 0xf2, 0x0d, 0xcb, 0x18, 0xe9, 0xb6, 0x8c, 0x85, 0x71, 0x30, 0x1e, 0x26, 0xc2, 0x24, 0x98, 0x0c, 0x53, 0x60, 0x2a, 0x4c, 0x93, 0x07, 0xb1, 0xb6, 0x83, 0x58, 0xdb, 0x41, 0xac, 0xed, 0x20, 0xd6, 0x76, 0x10, 0x6b, 0x3b, 0x88, 0xb5, 0x1d, 0xc4, 0xda, 0x32, 0xb0, 0xb6, 0x8c, 0x3f, 0xbc, 0x23, 0xb3, 0x56, 0x7e, 0x6c, 0xb9, 0x1b, 0xd6, 0xc9, 0x03, 0x58, 0xdd, 0x01, 0xac, 0xee, 0x00, 0x56, 0x77, 0x00, 0xab, 0x3b, 0x80, 0xd5, 0x1d, 0xc0, 0xea, 0x0e, 0x60, 0x75, 0x07, 0xb0, 0xba, 0x03, 0x96, 0xc7, 0x28, 0xe7, 0x71, 0x78, 0x02, 0xfe, 0x06, 0x3b, 0x61, 0x17, 0xec, 0x96, 0x2e, 0xe2, 0x4d, 0x17, 0xf1, 0xa6, 0x8b, 0x78, 0xd3, 0x45, 0xbc, 0xe9, 0x22, 0xde, 0x74, 0x11, 0x6f, 0xba, 0x88, 0x37, 0x5d, 0xc4, 0x9b,\n\t0x2e, 0xe2, 0x4d, 0x17, 0xf1, 0xa6, 0x8b, 0x78, 0xd3, 0x85, 0x5f, 0x76, 0x11, 0x6f, 0xba, 0x88, 0x37, 0x5d, 0xc4, 0x9b, 0x2e, 0xe2, 0x4d, 0x17, 0xf1, 0xa6, 0x8b, 0x78, 0xd3, 0x45, 0xbc, 0xe9, 0x22, 0xde, 0x74, 0x11, 0x6f, 0xba, 0x88, 0x37, 0x5d, 0xc4, 0x9b, 0x2e, 0xe2, 0x4d, 0x17, 0xf1, 0xa6, 0x8b, 0x78, 0xd3, 0x45, 0xbc, 0xe9, 0x22, 0xde, 0x74, 0x11, 0x6f, 0xba, 0x88, 0x37, 0x5d, 0xc4, 0x9b, 0x2e, 0xe2, 0x4d, 0x17, 0xf1, 0xa6, 0x8b, 0xf8, 0xcc, 0x45, 0x7c, 0xe6, 0x22, 0x3e, 0x73, 0x11, 0x9f, 0xb9, 0x88, 0xcf, 0x5c, 0xc4, 0x67, 0x2e, 0xe2, 0x33, 0x17, 0x31, 0x98, 0x8b, 0x18, 0xcc, 0x45, 0x0c, 0xe6, 0x22, 0x06, 0x73, 0x11, 0x83, 0xb9, 0x88, 0xc1, 0x5c, 0xc4, 0x60, 0x2e, 0x62, 0x30, 0x17, 0x31, 0x18, 0x1e, 0x1e, 0x5a, 0x42, 0x08, 0xb4, 0x02, 0x1b, 0xb4, 0x86, 0x36,\n\t0xd0, 0x1e, 0x3a, 0x40, 0x27, 0xe8, 0x06, 0xd8, 0x06, 0x31, 0x98, 0x0b, 0x3f, 0xe3, 0x22, 0x06, 0x73, 0x11, 0x83, 0xb9, 0x88, 0xc1, 0x5c, 0xc4, 0x60, 0x2e, 0x62, 0x30, 0x17, 0x31, 0x98, 0x8b, 0x18, 0xcc, 0x45, 0x0c, 0xe6, 0x22, 0x06, 0x73, 0x11, 0x83, 0xb9, 0x88, 0xc1, 0x5c, 0xc4, 0x60, 0x2e, 0x62, 0x30, 0x17, 0x31, 0x98, 0x8b, 0x18, 0xcc, 0x45, 0x0c, 0xe6, 0x22, 0x06, 0x73, 0x11, 0x83, 0xb9, 0x88, 0xc1, 0x5c, 0xc4, 0x60, 0x2e, 0x62, 0x30, 0x17, 0x31, 0x98, 0x8b, 0x18, 0xcc, 0x45, 0x0c, 0xe6, 0x22, 0x06, 0x73, 0x11, 0x83, 0xb9, 0x88, 0xc1, 0x5c, 0xc4, 0x45, 0x2e, 0xe2, 0x22, 0x17, 0x71, 0x91, 0x8b, 0xb8, 0xc8, 0x45, 0x5c, 0xe4, 0x22, 0x2e, 0x72, 0x11, 0x17, 0xb9, 0x88, 0x8b, 0x5c, 0xc4, 0x45, 0x2e, 0xe2, 0x22, 0x17, 0x71, 0x91, 0x8b, 0xb8, 0xc2, 0x4d, 0x5c, 0xe1,\n\t0x26, 0xae, 0x70, 0x13, 0x57, 0xb8, 0x89, 0x2b, 0xdc, 0xc4, 0x15, 0x6e, 0xe2, 0x0a, 0x37, 0x71, 0x85, 0x9b, 0xb8, 0xc2, 0x4d, 0x5c, 0xe1, 0x26, 0xae, 0x70, 0x13, 0x57, 0xb8, 0x89, 0x2b, 0xdc, 0xc4, 0x15, 0x6e, 0xe2, 0x0a, 0x37, 0x71, 0x85, 0x9b, 0xb8, 0xc2, 0x4d, 0x5c, 0xe1, 0x26, 0xae, 0x70, 0x13, 0x57, 0xb8, 0x89, 0x2b, 0xdc, 0xc4, 0x15, 0x6e, 0xf5, 0x8c, 0xac, 0x56, 0x7f, 0x85, 0x4b, 0xec, 0x57, 0x40, 0x25, 0x5c, 0x86, 0x2b, 0x70, 0x55, 0xba, 0x89, 0x05, 0x5c, 0x78, 0xe8, 0x52, 0xd6, 0x79, 0x37, 0xeb, 0xbc, 0x9b, 0x75, 0xde, 0xcd, 0x3a, 0xef, 0x66, 0x9d, 0x77, 0x8b, 0x90, 0xff, 0xe8, 0x93, 0x23, 0x64, 0x35, 0x16, 0x5f, 0x6d, 0xf8, 0xe6, 0x73, 0x58, 0x7c, 0x35, 0x16, 0xef, 0xfa, 0x03, 0xdf, 0x5c, 0x84, 0xd5, 0x9e, 0xff, 0xd3, 0xbe, 0xb9, 0x05, 0x35, 0x5f, 0xa5,\n\t0xe6, 0xab, 0xd4, 0x7c, 0x95, 0x9a, 0x7f, 0xa1, 0xe6, 0x8f, 0xa9, 0xf9, 0x84, 0x16, 0x09, 0xe0, 0xa7, 0x4b, 0xa9, 0xe5, 0x02, 0xb5, 0x5c, 0x65, 0x95, 0xeb, 0x64, 0xf8, 0xec, 0xf3, 0xd4, 0x76, 0x86, 0x1a, 0xae, 0x6a, 0x7e, 0x9b, 0x5a, 0xae, 0x52, 0xcb, 0x55, 0x6a, 0xb9, 0x4a, 0x2d, 0x57, 0xa9, 0xe5, 0x2a, 0xb5, 0x5c, 0xa5, 0x96, 0xab, 0x68, 0xe6, 0x1a, 0xde, 0x56, 0xd1, 0xa2, 0x01, 0x61, 0xa5, 0x06, 0x37, 0xa5, 0xbb, 0x28, 0xbd, 0x8a, 0x3e, 0x94, 0x1b, 0x77, 0x53, 0x0e, 0xe9, 0xf7, 0xbb, 0x9e, 0xd0, 0xef, 0x39, 0xe5, 0xe1, 0xed, 0x7d, 0xc5, 0x42, 0x23, 0x66, 0x98, 0x2f, 0x46, 0xca, 0x8d, 0x62, 0x94, 0x7c, 0x40, 0x4c, 0x60, 0x7b, 0x3b, 0xcc, 0x83, 0x48, 0x62, 0x9d, 0x18, 0x39, 0x4a, 0x2b, 0x05, 0x7f, 0xb9, 0x87, 0x11, 0x4a, 0x53, 0x06, 0xc8, 0xa7, 0x94, 0x81, 0x72,\n\t0x17, 0x23, 0xb4, 0x09, 0xef, 0x7f, 0x58, 0x59, 0x2c, 0x5f, 0x61, 0xe5, 0x3e, 0xc7, 0xca, 0x7d, 0x8e, 0x28, 0xc6, 0xac, 0x94, 0xca, 0xbf, 0x29, 0x65, 0x72, 0x87, 0x52, 0x2e, 0x1f, 0xa7, 0xd6, 0x71, 0xd4, 0xda, 0x91, 0x5a, 0x1b, 0xb3, 0x42, 0x17, 0x52, 0xeb, 0x4b, 0xe4, 0xc0, 0x1b, 0xc9, 0x81, 0x37, 0x62, 0xb3, 0xa3, 0xb0, 0xd7, 0xa9, 0xd8, 0xeb, 0x50, 0xec, 0x75, 0x1a, 0xf6, 0xda, 0x19, 0x7b, 0x1d, 0x88, 0x7d, 0x4e, 0xc1, 0x3e, 0x0b, 0xb0, 0xcf, 0x29, 0xd8, 0xe7, 0x14, 0xec, 0x73, 0x2a, 0xf6, 0x19, 0x87, 0x7d, 0xc6, 0x61, 0x9f, 0x71, 0xd8, 0x67, 0x1c, 0xf6, 0x39, 0x10, 0xfb, 0x9c, 0x4f, 0x6e, 0xd7, 0x83, 0xdc, 0x2e, 0x94, 0xfc, 0xad, 0x25, 0xb9, 0x5b, 0x27, 0x72, 0xb7, 0xae, 0xe4, 0x6e, 0x9d, 0xc9, 0xd3, 0x9a, 0x92, 0xa7, 0x75, 0x64, 0x8d, 0x7b, 0x85, 0x3c, 0xad,\n\t0x23, 0x79, 0x5a, 0x47, 0xf2, 0xb4, 0x4e, 0xe4, 0x60, 0x1b, 0xc9, 0xc1, 0x36, 0x92, 0x83, 0x6d, 0x24, 0x9f, 0xda, 0x88, 0xbd, 0x46, 0x60, 0xaf, 0xed, 0xb1, 0xd3, 0x11, 0xe4, 0x4e, 0x9d, 0xc8, 0x99, 0xba, 0xb0, 0x26, 0xf6, 0xc1, 0x06, 0x3f, 0x60, 0x05, 0x1b, 0xca, 0x0a, 0xd6, 0x8d, 0x51, 0xea, 0x40, 0xc4, 0xd5, 0x8c, 0x75, 0xb1, 0xbb, 0x1e, 0x71, 0xf5, 0x12, 0x23, 0xc9, 0x43, 0x9a, 0x90, 0x83, 0xd8, 0xc8, 0x3f, 0x5a, 0x93, 0x6b, 0xb4, 0x22, 0x0a, 0xdb, 0x4b, 0xae, 0xd1, 0x8a, 0x5c, 0xa3, 0x15, 0xb9, 0x86, 0x8d, 0x5c, 0xa3, 0x2d, 0xb6, 0xf1, 0x02, 0xb6, 0x30, 0x97, 0xbc, 0x20, 0x9e, 0xbc, 0xe0, 0x7e, 0x74, 0xba, 0x1c, 0x4d, 0xfe, 0x40, 0x2c, 0xda, 0x44, 0x7b, 0x6a, 0x93, 0xfc, 0x86, 0xd5, 0x70, 0x03, 0xab, 0xe1, 0x06, 0x61, 0x96, 0x79, 0xc2, 0x02, 0xfe, 0x70, 0x1b,\n\t0x04, 0x43, 0x4b, 0xb0, 0x41, 0x77, 0x39, 0x8e, 0x15, 0x70, 0x1c, 0x2b, 0xe0, 0x38, 0xd1, 0x4b, 0x4e, 0x16, 0xbd, 0xa1, 0x0f, 0xf4, 0x85, 0x30, 0xe8, 0x07, 0xfd, 0xe5, 0x14, 0x31, 0x00, 0x06, 0x82, 0x36, 0x93, 0x83, 0x38, 0x36, 0x18, 0x86, 0xc8, 0xe7, 0xc5, 0x50, 0x18, 0x06, 0x11, 0x30, 0x1c, 0x46, 0x80, 0x67, 0xa6, 0x9f, 0x16, 0xa3, 0xe5, 0x7e, 0xc1, 0x3a, 0x2e, 0xc6, 0xc2, 0x38, 0x18, 0x0f, 0xda, 0xec, 0x4f, 0x64, 0x3b, 0x89, 0xf3, 0x26, 0xc3, 0x14, 0x98, 0x0a, 0xd3, 0x60, 0x3a, 0xcc, 0x80, 0x99, 0x30, 0x0b, 0x34, 0x95, 0xcc, 0x66, 0x3b, 0x07, 0xe6, 0xc2, 0x3c, 0xca, 0xbc, 0x83, 0xed, 0x7c, 0x58, 0x00, 0x0b, 0xe5, 0x4c, 0xb1, 0x48, 0x4e, 0xbb, 0x49, 0x45, 0x71, 0x32, 0x8a, 0x15, 0x39, 0x8a, 0x15, 0x39, 0x8a, 0x15, 0x39, 0x4a, 0x24, 0xd1, 0xce, 0x64, 0x58, 0x01,\n\t0x29, 0xbc, 0x4e, 0x93, 0xab, 0x58, 0x9d, 0xa3, 0xc4, 0x2a, 0xb9, 0x50, 0xac, 0x86, 0xbb, 0x60, 0x0d, 0xa0, 0x3e, 0x71, 0x37, 0x65, 0xae, 0x93, 0x4f, 0x89, 0xf5, 0x70, 0x0f, 0x6c, 0x80, 0x7b, 0x61, 0x23, 0x6c, 0x82, 0xcd, 0x70, 0x1f, 0xdc, 0x0f, 0x5b, 0x64, 0x3c, 0x2b, 0x7b, 0xbc, 0x48, 0x97, 0xeb, 0xc4, 0x83, 0xb4, 0x73, 0xab, 0x4c, 0x12, 0x0f, 0xc9, 0xb5, 0xac, 0xf2, 0x73, 0x0d, 0x15, 0x7f, 0x8c, 0x8a, 0x3f, 0x54, 0x46, 0xc8, 0xcd, 0xca, 0x48, 0xd4, 0x3a, 0x8a, 0xed, 0x68, 0xb6, 0x63, 0xe4, 0x76, 0x65, 0x82, 0xdc, 0xab, 0x4c, 0x82, 0x1b, 0xea, 0xbe, 0x84, 0xba, 0x2f, 0xe9, 0xea, 0xce, 0x27, 0x86, 0x2d, 0x94, 0x93, 0x59, 0xfd, 0xe3, 0x6f, 0x52, 0xfa, 0x28, 0xec, 0x6b, 0x22, 0x4c, 0x87, 0x3b, 0x21, 0x55, 0x4e, 0x36, 0xa5, 0xc9, 0x29, 0x44, 0x01, 0x51, 0x44, 0x00,\n\t0x51, 0x26, 0xda, 0x6b, 0xa2, 0xbd, 0x44, 0x02, 0x73, 0x89, 0x04, 0x66, 0xea, 0x96, 0x91, 0xce, 0xfb, 0x5b, 0x79, 0xfd, 0xa8, 0x5c, 0x68, 0x7a, 0x82, 0xfd, 0x1d, 0x72, 0x2d, 0x51, 0xc1, 0x5c, 0xd3, 0x5e, 0xb9, 0xdf, 0xf4, 0x3c, 0xbc, 0x20, 0x5f, 0x32, 0xbd, 0xc8, 0x76, 0x1f, 0xbc, 0x24, 0x9f, 0x37, 0xed, 0x87, 0x97, 0xe1, 0x15, 0x38, 0x00, 0xaf, 0x52, 0xde, 0xdf, 0xa1, 0xd6, 0xc2, 0x18, 0x6b, 0xef, 0xcd, 0xf2, 0x0d, 0xef, 0xfb, 0xe5, 0x2b, 0xde, 0x5b, 0xe4, 0x47, 0xde, 0x0f, 0xc8, 0x83, 0xde, 0xe9, 0x6c, 0x1f, 0x64, 0xbb, 0x4b, 0xbf, 0x23, 0xb5, 0xdf, 0xe7, 0x33, 0xf9, 0xbc, 0x6e, 0x85, 0x47, 0xd8, 0x3f, 0x2a, 0x9f, 0xc6, 0x12, 0x9f, 0xf6, 0xf9, 0x91, 0x63, 0xc7, 0xe0, 0x94, 0xcc, 0xf3, 0x39, 0x23, 0x27, 0xfb, 0x14, 0xc8, 0x29, 0x44, 0x1e, 0xf1, 0x44, 0x1e, 0x51,\n\t0xbe, 0x1d, 0xe4, 0x53, 0xbe, 0x55, 0x72, 0x32, 0xd1, 0xc7, 0x06, 0xa2, 0x8f, 0x0d, 0x44, 0x1f, 0x1b, 0x88, 0x3e, 0x36, 0x10, 0x7d, 0x6c, 0x20, 0xfa, 0xd8, 0x40, 0xf4, 0xb1, 0x81, 0xe8, 0x63, 0x03, 0xd1, 0xc7, 0x06, 0xa2, 0x8f, 0x0d, 0x44, 0x1f, 0x1b, 0x88, 0x3e, 0x36, 0x10, 0x7d, 0x6c, 0x20, 0xfa, 0xd8, 0x40, 0xf4, 0xb1, 0x81, 0xe8, 0x63, 0x03, 0xd1, 0xc7, 0x06, 0xa2, 0x8f, 0x0d, 0x44, 0x1f, 0x1b, 0x88, 0x3e, 0x36, 0x10, 0x7d, 0x6c, 0x20, 0xfa, 0xd8, 0x40, 0xf4, 0xb1, 0x81, 0xe8, 0x63, 0x03, 0xd1, 0xc7, 0x06, 0xa2, 0x8f, 0x0d, 0x44, 0x1f, 0x1b, 0x88, 0x3e, 0x36, 0x98, 0x97, 0xcb, 0x3c, 0x73, 0x3c, 0x24, 0x40, 0x22, 0xa4, 0xc0, 0x3e, 0x78, 0x09, 0xf6, 0xc3, 0xcb, 0xf0, 0x0a, 0x1c, 0x80, 0x57, 0x65, 0x9e, 0xa5, 0x3e, 0x60, 0x3f, 0x96, 0x06, 0xd0, 0x10, 0x02, 0xa0,\n\t0x11, 0x04, 0x42, 0x10, 0x34, 0x83, 0xe6, 0xd0, 0x02, 0xb0, 0x31, 0x0b, 0x36, 0x66, 0xc1, 0xc6, 0x2c, 0x21, 0xd0, 0x0a, 0xb0, 0x35, 0x4b, 0x6b, 0x68, 0x03, 0x6d, 0xa1, 0x1d, 0xb4, 0x87, 0x0e, 0xd0, 0x11, 0x3a, 0x41, 0x67, 0xe8, 0x02, 0x7d, 0x41, 0xf3, 0x5e, 0x4f, 0xca, 0x71, 0xbf, 0xeb, 0xc1, 0xf6, 0x70, 0x7c, 0x2f, 0xbc, 0x00, 0x2f, 0xc2, 0x5f, 0xf1, 0x68, 0xff, 0xe0, 0xfc, 0x37, 0xe1, 0x2d, 0x78, 0x1b, 0xde, 0x87, 0x0f, 0xe0, 0x43, 0xf8, 0x08, 0x3e, 0x86, 0xcf, 0xe4, 0xe4, 0xeb, 0x9e, 0xef, 0x0b, 0xf6, 0xbf, 0x81, 0x6f, 0x29, 0xf7, 0x10, 0x1c, 0x86, 0xef, 0xe0, 0x28, 0x68, 0x5e, 0xf1, 0x47, 0xde, 0xab, 0xeb, 0x19, 0x33, 0x78, 0x7d, 0x1c, 0x32, 0x21, 0x07, 0x4e, 0xc0, 0x1f, 0x79, 0xcb, 0x5f, 0x79, 0xef, 0x1c, 0x38, 0x20, 0x1f, 0x0a, 0x00, 0xed, 0x5b, 0x9c, 0x50,\n\t0x0c, 0xe7, 0xe5, 0xf3, 0x37, 0x79, 0xd4, 0x32, 0xb9, 0xdf, 0x52, 0x0e, 0x97, 0xa0, 0x02, 0x2a, 0xe1, 0x32, 0xe7, 0x5c, 0x81, 0xab, 0x50, 0x05, 0xd5, 0xe0, 0x02, 0x37, 0x5c, 0x83, 0x1a, 0xf9, 0xf4, 0x75, 0x2f, 0xac, 0xc8, 0x99, 0x44, 0x4d, 0x33, 0x75, 0x6f, 0xec, 0xcd, 0xd6, 0x07, 0x7c, 0xe5, 0x34, 0xdd, 0x33, 0x5b, 0xd8, 0xaa, 0xa0, 0x79, 0x68, 0x7f, 0xb6, 0x0d, 0xe0, 0xcf, 0x78, 0xea, 0x51, 0x32, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x8a, 0x08, 0x27, 0x4a, 0xf7, 0xee, 0xb7, 0xcb, 0xc9, 0xba, 0x87, 0x9f, 0xc3, 0x56, 0xf3, 0xf2, 0xf3, 0xd8, 0xde, 0x01, 0xf3, 0xe1, 0x4e, 0x58, 0x0c, 0x7f, 0xe4, 0xf9, 0x97,\n\t0xf2, 0x5e, 0x2c, 0xc4, 0xc1, 0x32, 0x58, 0x0e, 0xf1, 0x90, 0x00, 0x89, 0x70, 0x17, 0xac, 0x81, 0xb5, 0x80, 0x6f, 0x20, 0x9a, 0x8a, 0x22, 0x9a, 0x8a, 0xd2, 0x57, 0x8c, 0xcd, 0x6c, 0xef, 0x83, 0xfb, 0x61, 0x0b, 0x68, 0x2b, 0xc8, 0x83, 0x6c, 0xb7, 0xc2, 0x43, 0x72, 0xe1, 0xf5, 0xd5, 0x64, 0x3b, 0xfb, 0xf8, 0x0d, 0xf5, 0x31, 0x78, 0x1c, 0x9e, 0x80, 0x1d, 0xb0, 0x4b, 0x3e, 0xa5, 0xee, 0x86, 0x27, 0xe1, 0x29, 0x78, 0x1a, 0x9e, 0x81, 0x67, 0xe1, 0x39, 0xd8, 0x03, 0x7b, 0xe1, 0x79, 0x78, 0x01, 0x5e, 0x84, 0x7d, 0xf0, 0x12, 0xec, 0x87, 0x97, 0xe1, 0x15, 0x38, 0x00, 0xf8, 0x17, 0x15, 0xff, 0xa2, 0xbe, 0x06, 0xaf, 0xc3, 0x1b, 0xf0, 0x0f, 0x78, 0x13, 0xde, 0x82, 0xb7, 0xe1, 0x1d, 0x78, 0x17, 0xde, 0x83, 0xf7, 0xe1, 0x03, 0xf8, 0x10, 0x3e, 0x82, 0x8f, 0xe1, 0x9f, 0xf0, 0x09,\n\t0x7c, 0x0a, 0xff, 0xa2, 0xed, 0xff, 0x86, 0xcf, 0xe0, 0x73, 0x38, 0x08, 0x5f, 0xc0, 0x97, 0xf0, 0x15, 0x7c, 0x03, 0xdf, 0xc2, 0x21, 0x38, 0x0c, 0xdf, 0xc1, 0xf7, 0x70, 0x04, 0x8e, 0xc2, 0x0f, 0xf0, 0x23, 0x1c, 0x83, 0x9f, 0x20, 0x03, 0x8e, 0x43, 0xa6, 0x5c, 0xa7, 0x66, 0x41, 0xb6, 0xdc, 0xa8, 0xe6, 0xc0, 0x09, 0x38, 0x09, 0xa7, 0x20, 0x17, 0xf2, 0xe0, 0x8c, 0x4c, 0x22, 0x62, 0x4c, 0x52, 0xcf, 0xc9, 0xb5, 0xaa, 0x03, 0xf2, 0xa1, 0x00, 0x9c, 0x50, 0x0c, 0xe7, 0xe1, 0x02, 0x5c, 0x84, 0x12, 0xb8, 0xc4, 0xb8, 0xb3, 0x62, 0x13, 0x59, 0xce, 0x25, 0xb2, 0x9c, 0x4b, 0x64, 0x39, 0x97, 0xc8, 0x72, 0x2e, 0x91, 0x65, 0x94, 0xf5, 0x94, 0xdc, 0xcb, 0x4a, 0x9e, 0x63, 0x75, 0xca, 0x3c, 0x6b, 0x31, 0x9c, 0x87, 0x0b, 0x70, 0x11, 0x2a, 0xe4, 0x64, 0x6d, 0x85, 0xb7, 0x5e, 0x66, 0x7b,\n\t0x05, 0xae, 0x42, 0x95, 0x8c, 0x27, 0x0a, 0x8d, 0x27, 0x0a, 0x8d, 0x27, 0x0a, 0x8d, 0x27, 0x0a, 0x8d, 0xf7, 0xc3, 0x46, 0x45, 0x80, 0x11, 0xa5, 0x69, 0xf9, 0xfa, 0x19, 0x56, 0x47, 0x27, 0xab, 0xdc, 0x19, 0x56, 0xa7, 0x0c, 0x56, 0xa1, 0x7c, 0xe3, 0x7e, 0xd2, 0x49, 0x3c, 0x7b, 0x96, 0x11, 0xb1, 0x69, 0xf7, 0x93, 0xce, 0xa0, 0xf8, 0x33, 0x37, 0xdd, 0x4f, 0xd2, 0xee, 0xc1, 0x7c, 0x48, 0x49, 0xd5, 0x94, 0x74, 0x37, 0x6b, 0x6d, 0x00, 0xa5, 0x3d, 0x41, 0x49, 0x1f, 0x50, 0xd2, 0x72, 0xd6, 0xb9, 0x33, 0xac, 0x73, 0xa7, 0x29, 0xf1, 0x1e, 0x65, 0xbc, 0x50, 0x95, 0xe9, 0xa2, 0x81, 0x32, 0x53, 0x04, 0xea, 0x7f, 0x27, 0xbd, 0x93, 0x4c, 0x77, 0xb1, 0xfc, 0x8e, 0xf5, 0xcd, 0xc9, 0xfa, 0xe6, 0x64, 0x7d, 0x6b, 0xc3, 0x9a, 0xf6, 0x6f, 0xd6, 0xb4, 0x4f, 0x59, 0xd3, 0xbe, 0x23, 0x22,\n\t0x2d, 0xa0, 0x15, 0x3f, 0xd1, 0x8a, 0x74, 0x5a, 0x91, 0xa8, 0xdd, 0xd5, 0x62, 0x1d, 0x71, 0xea, 0x2d, 0xd9, 0x2d, 0x1f, 0xc3, 0xe7, 0x6d, 0xc0, 0xdf, 0xdd, 0x6b, 0x79, 0x49, 0xdc, 0x86, 0x3f, 0xdb, 0x87, 0x3f, 0xdb, 0x87, 0x3f, 0xdb, 0x87, 0x3f, 0xdb, 0x87, 0x3f, 0xbb, 0x17, 0x7f, 0xf6, 0x1c, 0x3e, 0x6a, 0x13, 0x7e, 0x28, 0x19, 0xff, 0xb3, 0x1e, 0xff, 0x52, 0x8d, 0x9d, 0xdf, 0x85, 0x7d, 0xef, 0xc4, 0x8e, 0xd7, 0x63, 0xbf, 0xb3, 0xe8, 0xcd, 0x31, 0xe3, 0xee, 0x83, 0x0d, 0xfb, 0xed, 0x85, 0xfd, 0xf6, 0xc2, 0x7e, 0x47, 0xaa, 0xed, 0x45, 0x03, 0x6c, 0x38, 0x8e, 0x1e, 0xb6, 0xd7, 0xef, 0x71, 0x2d, 0x91, 0x69, 0xd8, 0x47, 0x2e, 0xf6, 0xf0, 0x1a, 0x36, 0xb0, 0x11, 0x1b, 0x38, 0xc8, 0xfc, 0x7c, 0x29, 0x06, 0xd0, 0xfb, 0x22, 0xe2, 0xea, 0x72, 0xe2, 0xea, 0x72, 0x46, 0xa1,\n\t0x9c, 0x51, 0x48, 0x67, 0x14, 0xfc, 0x18, 0x85, 0xd7, 0x8c, 0xb8, 0xf5, 0xdf, 0x8c, 0xc4, 0x0e, 0x46, 0xe2, 0x02, 0x23, 0xa1, 0xdd, 0xab, 0xd3, 0x56, 0xf6, 0xd3, 0xf4, 0x5c, 0xeb, 0x71, 0x43, 0xa5, 0x44, 0x5e, 0xa5, 0xd7, 0x99, 0xf4, 0xfa, 0x38, 0xbd, 0x3e, 0xa3, 0xdf, 0x2f, 0xb1, 0x33, 0xf6, 0x4b, 0xf5, 0xa8, 0xd9, 0x41, 0xef, 0x5f, 0xa5, 0xf7, 0x3b, 0x88, 0xc1, 0xb5, 0x39, 0xb8, 0x44, 0x0c, 0x5e, 0x4e, 0x0c, 0x5e, 0x4e, 0x0c, 0x5e, 0x4e, 0x0c, 0x5e, 0x4e, 0x0c, 0x5e, 0x4e, 0x0c, 0x5e, 0x4e, 0x0c, 0x5e, 0x6e, 0x8c, 0xc4, 0x7e, 0x46, 0x62, 0x3f, 0x23, 0xb1, 0x9f, 0x91, 0xd8, 0xcf, 0x28, 0xec, 0xa1, 0xe7, 0x57, 0xe9, 0xf5, 0xdf, 0xe8, 0xf1, 0x08, 0x7a, 0x9c, 0x41, 0x8f, 0x83, 0xe9, 0x71, 0x10, 0x3d, 0x6e, 0x47, 0x8f, 0x5b, 0xd2, 0xe3, 0xde, 0xf4, 0x76, 0x2a, 0xbd,\n\t0xb5, 0xd1, 0xdb, 0x32, 0x7a, 0x7a, 0x52, 0xef, 0xe9, 0x36, 0xf9, 0x19, 0x59, 0x43, 0xb8, 0x7c, 0x8f, 0xde, 0x14, 0xd3, 0x9b, 0x72, 0x62, 0xa5, 0x83, 0xf4, 0xe8, 0x02, 0x73, 0x96, 0xcb, 0x9c, 0xe5, 0xd2, 0x83, 0x46, 0xb4, 0x5a, 0xbb, 0x4f, 0x76, 0x41, 0x6f, 0xf5, 0x16, 0x11, 0x42, 0xab, 0x9f, 0xa6, 0xd5, 0x95, 0x9a, 0x72, 0x68, 0xf1, 0x21, 0x5a, 0x15, 0x4e, 0xcd, 0xa3, 0xa8, 0xf9, 0x02, 0x35, 0x06, 0x51, 0x63, 0x20, 0x35, 0xf6, 0xa5, 0xc6, 0xe9, 0xd4, 0x76, 0x15, 0x3f, 0x74, 0x50, 0xcb, 0x96, 0xc4, 0x34, 0xc6, 0xf2, 0x4d, 0xc6, 0xb0, 0x8a, 0x1a, 0x17, 0x13, 0xcd, 0xfd, 0x8d, 0x5a, 0x6f, 0x17, 0xcb, 0x64, 0x05, 0x35, 0x3e, 0xcb, 0x18, 0x2e, 0x62, 0x0c, 0xdf, 0x63, 0x0c, 0xdf, 0x61, 0x0c, 0x97, 0xa3, 0x26, 0xeb, 0x2d, 0x6a, 0xfa, 0x07, 0x63, 0xfa, 0x02, 0x2d, 0xfb,\n\t0x82, 0x96, 0x7d, 0x61, 0xa8, 0x69, 0x1b, 0xe3, 0xfa, 0x30, 0x2d, 0x7c, 0x8c, 0x16, 0x9e, 0xa2, 0x65, 0x7f, 0xa3, 0x65, 0xe3, 0x69, 0xd9, 0x70, 0x4d, 0xd3, 0xda, 0x3d, 0x0f, 0x14, 0xf5, 0x15, 0xad, 0x3c, 0x4d, 0x34, 0xb2, 0x8b, 0x68, 0x64, 0x17, 0xca, 0x4a, 0x65, 0x45, 0xed, 0x8d, 0xba, 0xe6, 0xb2, 0xa2, 0x8e, 0x42, 0x61, 0x51, 0xac, 0xa2, 0x3d, 0xe8, 0x85, 0x0f, 0x63, 0xbb, 0x85, 0xb1, 0xdd, 0xc2, 0xd8, 0x6e, 0x61, 0x6c, 0xb7, 0xa0, 0xb2, 0x28, 0xc6, 0xf7, 0x5e, 0x54, 0x66, 0x47, 0x65, 0x33, 0x50, 0xd9, 0x62, 0x56, 0xb9, 0xfe, 0xac, 0x70, 0x23, 0x18, 0xf3, 0x53, 0xac, 0x2e, 0xbb, 0x50, 0x5c, 0x34, 0x63, 0x7f, 0x2f, 0xab, 0xc7, 0x08, 0x54, 0xb7, 0xd8, 0x50, 0xdd, 0x07, 0x8c, 0x7f, 0x20, 0xa3, 0xd1, 0x91, 0xd1, 0x68, 0xcf, 0x68, 0x4c, 0x34, 0x14, 0xb7, 0x9c, 0x15,\n\t0x22, 0x81, 0x15, 0x60, 0x22, 0x5e, 0x3f, 0x14, 0x8f, 0x1f, 0xce, 0x08, 0x1d, 0x47, 0x7d, 0x73, 0x99, 0x93, 0x23, 0xcc, 0xc9, 0x4e, 0xd4, 0x37, 0x9c, 0x79, 0x79, 0x01, 0x6f, 0xb6, 0x04, 0x4f, 0x95, 0x8a, 0x0a, 0x5f, 0x67, 0xf4, 0xbe, 0xc6, 0xea, 0x27, 0x8a, 0xe6, 0x86, 0x45, 0x1f, 0x47, 0x81, 0xbe, 0x8c, 0x9e, 0x83, 0x39, 0x73, 0x6b, 0x77, 0xe1, 0x18, 0x95, 0x52, 0x46, 0x45, 0xcb, 0xf0, 0xae, 0x32, 0x0a, 0xdf, 0x33, 0x0a, 0x6e, 0x46, 0xa1, 0x80, 0x9e, 0x7f, 0x4f, 0xcf, 0x5a, 0xd3, 0xda, 0x0b, 0xb4, 0xac, 0x23, 0x2d, 0x2b, 0x47, 0x1d, 0x7e, 0x86, 0x3a, 0x5a, 0xd1, 0xba, 0x7a, 0xb4, 0xae, 0x29, 0x2d, 0xeb, 0x8b, 0x3a, 0x1a, 0xd2, 0x9a, 0x73, 0x22, 0x48, 0x6c, 0x93, 0x65, 0x62, 0x3b, 0xfa, 0x0d, 0x93, 0xc7, 0x94, 0x7e, 0xf2, 0x07, 0x65, 0xbc, 0x7c, 0x8d, 0x6c, 0xf5,\n\t0x14, 0x99, 0xde, 0x57, 0x64, 0xab, 0x47, 0x94, 0xd9, 0xe8, 0x39, 0x46, 0xfe, 0xa8, 0x68, 0x9f, 0x13, 0x28, 0x45, 0xf3, 0x65, 0x50, 0x2e, 0x2f, 0x52, 0x73, 0xb5, 0x4f, 0x5f, 0x79, 0xd4, 0x27, 0x0c, 0xbe, 0x94, 0xd5, 0xd6, 0x99, 0xb2, 0xc4, 0x6f, 0x94, 0x7c, 0x52, 0x34, 0x16, 0x4b, 0xc4, 0xc8, 0xff, 0x50, 0xaa, 0x83, 0x52, 0x1d, 0x7f, 0xb9, 0x54, 0xed, 0x53, 0x0f, 0x45, 0x94, 0x56, 0x4c, 0x69, 0x4e, 0x4a, 0xfb, 0x82, 0xd2, 0x72, 0x29, 0xed, 0x6b, 0xa3, 0x8d, 0x15, 0x94, 0x76, 0x8a, 0x92, 0xae, 0x52, 0xd2, 0x55, 0x4a, 0x38, 0x43, 0x09, 0x67, 0xb8, 0xf2, 0x2d, 0xe1, 0xc7, 0xd1, 0x72, 0x8e, 0x96, 0x6b, 0xe5, 0xfb, 0x7c, 0x21, 0x9a, 0x31, 0x46, 0x41, 0x8c, 0x4b, 0x63, 0xc6, 0x21, 0x50, 0xed, 0x24, 0x02, 0xd4, 0xee, 0x62, 0x19, 0xe3, 0xd1, 0x42, 0xdd, 0x2a, 0x02, 0xc5,\n\t0xc7, 0xc2, 0x84, 0x95, 0x84, 0x8a, 0xbb, 0xc5, 0x10, 0x32, 0x8d, 0xa1, 0x30, 0x0c, 0x22, 0x60, 0x38, 0x8c, 0x80, 0x91, 0x30, 0x0a, 0x46, 0x8b, 0x66, 0x62, 0x0c, 0x8c, 0x85, 0x71, 0x30, 0x1e, 0x26, 0x70, 0x7c, 0x22, 0xdb, 0x49, 0x6c, 0x27, 0xc3, 0x14, 0x98, 0x0a, 0xd3, 0x00, 0x7d, 0x8b, 0x19, 0x30, 0x13, 0x66, 0xc1, 0xed, 0x30, 0x1b, 0xe6, 0xc0, 0x5c, 0x98, 0x07, 0x77, 0xc0, 0x7c, 0x58, 0x00, 0x77, 0xd2, 0x86, 0xc5, 0x42, 0xf3, 0xc2, 0x77, 0x0b, 0x72, 0x18, 0x11, 0x0d, 0x31, 0xb0, 0x04, 0x96, 0x42, 0x2c, 0xc7, 0x97, 0xc1, 0x72, 0x48, 0x85, 0xb5, 0x70, 0x37, 0xd7, 0xa5, 0x8b, 0x8e, 0xe2, 0x41, 0xd1, 0x46, 0x6c, 0x85, 0x87, 0x44, 0x67, 0xb1, 0x4d, 0xac, 0x16, 0xdb, 0xc5, 0x52, 0xa5, 0xaf, 0x88, 0x51, 0xc2, 0xc4, 0x7a, 0xa5, 0x9f, 0x78, 0x5c, 0x19, 0x2c, 0x92, 0x94,\n\t0x21, 0x22, 0x5d, 0x19, 0xca, 0x76, 0x18, 0xdb, 0xb1, 0x22, 0x0a, 0x1b, 0x64, 0x86, 0xc4, 0x3e, 0x6c, 0xf0, 0x45, 0x6c, 0x70, 0xaf, 0x32, 0x5b, 0xdc, 0xab, 0x2c, 0x14, 0x0f, 0x29, 0x8b, 0x20, 0x46, 0x7c, 0xa5, 0xd8, 0xc5, 0xa2, 0xba, 0x23, 0x69, 0x4a, 0x16, 0x77, 0x9b, 0x56, 0xc0, 0x1a, 0xd8, 0x21, 0x3a, 0x9b, 0x9e, 0x64, 0xfb, 0x14, 0xec, 0x15, 0xcd, 0x4c, 0xcf, 0xc3, 0x0b, 0xa2, 0x81, 0xe9, 0x45, 0xb6, 0xfb, 0xe0, 0x25, 0xf6, 0xf7, 0xc3, 0xcb, 0xf0, 0x0a, 0x1c, 0x10, 0x0d, 0xbc, 0xd3, 0xc4, 0xdd, 0x3e, 0x41, 0xd0, 0x57, 0x3c, 0xe4, 0x13, 0x06, 0xff, 0x16, 0xcd, 0x7c, 0x3e, 0x13, 0x0d, 0xb4, 0x19, 0xf2, 0x39, 0x02, 0x47, 0xd9, 0xff, 0x01, 0x7e, 0x84, 0x63, 0x50, 0x21, 0x62, 0x7c, 0xdb, 0x89, 0xbb, 0xb5, 0xd9, 0xb3, 0x7c, 0xc2, 0xf6, 0x53, 0xf8, 0x17, 0x9c, 0x17,\n\t0x0d, 0x2c, 0x17, 0xa1, 0x04, 0x4a, 0xa1, 0x8c, 0x19, 0x2e, 0x87, 0x4b, 0x50, 0x01, 0x95, 0x70, 0x99, 0xe3, 0x57, 0xe0, 0x2a, 0x54, 0x41, 0x35, 0xb8, 0xc0, 0x0d, 0xd7, 0xa0, 0x06, 0x7b, 0x6d, 0x28, 0xee, 0x56, 0x03, 0xa0, 0x11, 0x04, 0x02, 0x6d, 0x53, 0x1b, 0x43, 0x53, 0xb1, 0x4a, 0x6d, 0x0e, 0x2d, 0x20, 0x18, 0x5a, 0x82, 0xa6, 0x9e, 0x56, 0x6c, 0x6d, 0xd0, 0x1a, 0xda, 0x40, 0x7b, 0xa8, 0x55, 0x54, 0x37, 0xf6, 0x35, 0x55, 0xf5, 0x64, 0xab, 0x29, 0xab, 0x0f, 0xe5, 0xf4, 0x85, 0x30, 0xe8, 0x07, 0xfd, 0x21, 0x1c, 0x06, 0xc1, 0x60, 0x18, 0x02, 0x43, 0x61, 0x18, 0x44, 0xc0, 0x70, 0x18, 0x01, 0x28, 0x52, 0xcd, 0xc4, 0x92, 0xb3, 0x20, 0x5b, 0xb4, 0x51, 0x73, 0xe0, 0x04, 0x9c, 0x84, 0x53, 0x90, 0x0b, 0x79, 0x70, 0x06, 0x7e, 0x85, 0x73, 0xa2, 0xb3, 0xea, 0x80, 0x7c, 0x28,\n\t0x00, 0x27, 0x14, 0xc3, 0x79, 0xb8, 0x00, 0x17, 0xa1, 0x04, 0x2a, 0xd0, 0x4f, 0x20, 0xaa, 0xa8, 0x8f, 0x22, 0x54, 0xd4, 0x60, 0x46, 0x09, 0x66, 0x66, 0xbc, 0x19, 0x33, 0x1d, 0x7c, 0x93, 0xbd, 0xf4, 0x15, 0xf5, 0x98, 0x9d, 0x7a, 0xff, 0xd5, 0x6e, 0x62, 0xc5, 0x10, 0x7c, 0xfd, 0x50, 0x18, 0x06, 0x11, 0x30, 0x1c, 0x46, 0xc0, 0x48, 0x18, 0x05, 0xa3, 0x61, 0x0c, 0x8c, 0x05, 0xd6, 0x45, 0x31, 0x1e, 0x26, 0xc0, 0x44, 0x98, 0x04, 0x93, 0x61, 0x0a, 0x4c, 0x85, 0x69, 0x30, 0x1d, 0x66, 0xc0, 0x4c, 0x98, 0x05, 0xb7, 0xc3, 0x6c, 0x98, 0x03, 0x73, 0x61, 0x1e, 0xdc, 0x01, 0xf3, 0x61, 0x01, 0xdc, 0x0d, 0xe9, 0xf2, 0x32, 0xd9, 0xf9, 0x59, 0xb2, 0xf3, 0x4a, 0xb2, 0xf3, 0x0a, 0xfc, 0xc5, 0x25, 0xfd, 0x2f, 0x45, 0xda, 0x1d, 0xb8, 0xf1, 0x78, 0x9c, 0xe9, 0x30, 0x53, 0x1e, 0xc5, 0x67,\n\t0x64, 0xe0, 0x2f, 0x2e, 0x93, 0x41, 0x57, 0x90, 0x35, 0x57, 0x90, 0x2d, 0x57, 0x92, 0x2d, 0x57, 0x90, 0x2d, 0x57, 0x91, 0x2d, 0x57, 0x91, 0x2d, 0x57, 0x91, 0x2d, 0x57, 0x91, 0x2d, 0x57, 0x91, 0x2d, 0x57, 0x91, 0x2d, 0x57, 0x91, 0x2d, 0x57, 0x91, 0x2d, 0x57, 0x91, 0x2d, 0x57, 0x91, 0xfd, 0x56, 0x91, 0xfd, 0x56, 0x91, 0xf9, 0x56, 0xb1, 0xd6, 0x54, 0xb1, 0xd6, 0x54, 0x91, 0xf9, 0x56, 0x91, 0xf9, 0x56, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0x91, 0xc9, 0x54, 0xb1, 0xd6, 0x54, 0x11, 0x89, 0x5e, 0x26, 0x12, 0xbd, 0x4c, 0xb4,\n\t0x79, 0x96, 0x68, 0xf3, 0x2c, 0xd1, 0x66, 0x25, 0xd1, 0x66, 0x25, 0xd1, 0x66, 0x25, 0xd1, 0x66, 0x25, 0xd1, 0x66, 0x25, 0xd1, 0x66, 0x25, 0xd1, 0x66, 0x25, 0xd1, 0x66, 0x25, 0xd1, 0x66, 0x25, 0xd1, 0x66, 0x25, 0xd1, 0x66, 0x05, 0xeb, 0x48, 0x05, 0xd1, 0x66, 0x05, 0xd1, 0x66, 0x05, 0xd1, 0x66, 0x05, 0xd1, 0x66, 0x85, 0xfe, 0xc9, 0xa9, 0x13, 0x78, 0xd1, 0x2f, 0x59, 0x7d, 0x7f, 0x64, 0x44, 0x3e, 0xc7, 0xda, 0x2d, 0x58, 0x7b, 0x7d, 0xac, 0x5d, 0x65, 0xde, 0x2d, 0xcc, 0x7b, 0x21, 0xf3, 0x5e, 0xc8, 0xbc, 0x6b, 0x7f, 0xdd, 0x71, 0x33, 0xe7, 0x73, 0x99, 0xf3, 0x08, 0xcb, 0x07, 0xa2, 0x91, 0x25, 0x97, 0xf5, 0x22, 0x58, 0x0c, 0x61, 0xfe, 0x55, 0x94, 0x1f, 0x8a, 0xf2, 0x07, 0xa1, 0xfc, 0xce, 0x28, 0x3f, 0x0c, 0x3d, 0xcc, 0x44, 0x0f, 0x93, 0x51, 0x7d, 0x07, 0x34, 0x71, 0x08,\n\t0x4d, 0xf8, 0xab, 0x51, 0xc2, 0x82, 0x2e, 0xa6, 0x5a, 0x7f, 0x11, 0xad, 0xf4, 0x92, 0xaf, 0x2b, 0x8a, 0x12, 0xac, 0x5c, 0xad, 0x70, 0x45, 0x2b, 0xce, 0x9e, 0xc4, 0xd9, 0x0d, 0x88, 0xbc, 0xb4, 0xef, 0x26, 0xde, 0x09, 0x8b, 0xf5, 0x6f, 0x3a, 0xac, 0xd5, 0xbf, 0x03, 0xa2, 0x7d, 0x2e, 0xdd, 0xf3, 0x8d, 0x29, 0x1b, 0x47, 0xac, 0xb7, 0x78, 0x1f, 0x1b, 0xde, 0xc7, 0x86, 0xf7, 0xb1, 0xe1, 0x79, 0x6c, 0x78, 0x1e, 0x1b, 0x1e, 0xc5, 0x86, 0x47, 0xb1, 0xe1, 0x25, 0x6c, 0x96, 0xa7, 0x44, 0x43, 0xbc, 0x84, 0x0d, 0x2f, 0x61, 0xc3, 0x4b, 0xd8, 0x2c, 0x92, 0xf6, 0x34, 0x24, 0x22, 0x0a, 0x80, 0x46, 0x10, 0x08, 0x9c, 0x8b, 0x85, 0xdb, 0xb0, 0xe8, 0x40, 0x5a, 0xf5, 0x1e, 0xfd, 0xda, 0x4a, 0xcb, 0x62, 0xe8, 0xd7, 0x32, 0xfa, 0xd5, 0xa3, 0x4e, 0x0b, 0x3f, 0xc2, 0x82, 0x6d, 0x58, 0xb0,\n\t0x0d, 0x0b, 0xb6, 0x61, 0xc1, 0x36, 0x2c, 0xd8, 0x86, 0x05, 0xdb, 0xb0, 0x60, 0x1b, 0x16, 0x6c, 0xc3, 0x82, 0x6d, 0x58, 0xb0, 0x0d, 0x0b, 0xb6, 0x61, 0xc1, 0x36, 0x2c, 0xd8, 0x86, 0x05, 0xdb, 0xd4, 0x87, 0x45, 0x77, 0xc6, 0x20, 0x82, 0xd5, 0x22, 0x54, 0x98, 0xe9, 0xa1, 0x99, 0x1e, 0x9a, 0xe9, 0x21, 0x1e, 0x57, 0xd4, 0x17, 0xda, 0x63, 0x77, 0x62, 0xe8, 0xe5, 0x12, 0xb6, 0xda, 0x93, 0xaf, 0x62, 0x79, 0xcf, 0xd3, 0x6b, 0x33, 0xbd, 0x36, 0xd3, 0x6b, 0xe5, 0x96, 0x5e, 0x9b, 0xe9, 0xb5, 0x99, 0x5e, 0x9b, 0xe9, 0xb5, 0x99, 0x5e, 0x9b, 0xe9, 0xb5, 0x99, 0x5e, 0x9b, 0x99, 0xad, 0xfa, 0xf4, 0xdc, 0x4c, 0xaf, 0xcd, 0xf4, 0xda, 0x4c, 0xaf, 0xcd, 0xf4, 0xd8, 0x4c, 0x8f, 0xcd, 0xf4, 0xd8, 0x4c, 0x8f, 0xcd, 0xf4, 0xd8, 0x4c, 0x8f, 0xcd, 0xf8, 0xb4, 0xfa, 0xf8, 0xb4, 0xfa, 0xf8,\n\t0xb4, 0xfa, 0xcc, 0xea, 0x0a, 0x46, 0x40, 0x61, 0x04, 0xfa, 0x32, 0x02, 0x71, 0x8c, 0x40, 0x02, 0x23, 0xb0, 0x99, 0x11, 0xd8, 0x88, 0x4f, 0xab, 0xcf, 0xec, 0xd6, 0xd7, 0x47, 0xa2, 0x1b, 0x5b, 0x6d, 0x34, 0x7a, 0xb2, 0xed, 0x25, 0x06, 0x30, 0x22, 0x66, 0x46, 0xc4, 0xcc, 0x88, 0x98, 0x19, 0x11, 0x33, 0x23, 0x62, 0x66, 0x44, 0xcc, 0x8c, 0x88, 0x99, 0x11, 0x31, 0x33, 0x22, 0x66, 0x46, 0xc4, 0xcc, 0x88, 0x98, 0x19, 0x11, 0x33, 0x23, 0x62, 0x66, 0x44, 0xcc, 0xea, 0x26, 0xd1, 0x55, 0xdd, 0x26, 0x02, 0x19, 0x95, 0x29, 0x22, 0x98, 0x91, 0x98, 0xc3, 0x48, 0x04, 0x31, 0x12, 0x41, 0xc6, 0x48, 0x04, 0x69, 0x23, 0x71, 0xcb, 0x9a, 0x1d, 0x44, 0x8b, 0x83, 0x68, 0x71, 0x10, 0x2d, 0x0e, 0xa2, 0xc5, 0xe1, 0x46, 0x8b, 0x17, 0xd3, 0xe2, 0xbb, 0x68, 0x71, 0x22, 0x2d, 0x5e, 0x47, 0x8b,\n\t0x17, 0xd2, 0xe2, 0x20, 0x5a, 0x1c, 0x64, 0xb4, 0x38, 0xc8, 0x68, 0x71, 0x10, 0x2d, 0xb6, 0x53, 0x63, 0x18, 0x71, 0x44, 0xa4, 0x18, 0x79, 0x93, 0x1e, 0x83, 0x45, 0x3f, 0x4a, 0xb2, 0x53, 0xd2, 0x66, 0x4a, 0x4a, 0xa3, 0xa4, 0x7b, 0x29, 0x29, 0xbe, 0xce, 0xec, 0xc7, 0x71, 0x65, 0x6f, 0xd1, 0x90, 0x2b, 0x87, 0xdc, 0x72, 0xe5, 0x52, 0xae, 0xec, 0xc2, 0x95, 0x33, 0xb8, 0x72, 0x36, 0x57, 0xc6, 0x73, 0x65, 0x42, 0x9d, 0x2b, 0x7b, 0xd2, 0x5b, 0x1b, 0xbd, 0xb5, 0x50, 0xc2, 0xc8, 0xdf, 0xd8, 0x81, 0xe5, 0x16, 0x3b, 0xa8, 0x2f, 0xfa, 0xa3, 0x92, 0x10, 0x54, 0x42, 0xcf, 0x40, 0xfb, 0xce, 0x66, 0x2c, 0x5b, 0x8f, 0x22, 0x42, 0x50, 0x44, 0x08, 0x8a, 0xb0, 0xdc, 0xa2, 0x88, 0x10, 0x14, 0x11, 0x82, 0x22, 0x42, 0x50, 0x44, 0x08, 0x8a, 0x08, 0x41, 0x11, 0x21, 0x28, 0x22, 0x04, 0x35,\n\t0x84, 0x60, 0x07, 0xfe, 0x28, 0x22, 0x04, 0x45, 0x84, 0xa0, 0x88, 0x10, 0x14, 0x11, 0x82, 0x22, 0x42, 0x50, 0x44, 0x08, 0x8a, 0x08, 0x41, 0x11, 0x21, 0x28, 0x22, 0x84, 0xf1, 0x0c, 0xa0, 0x45, 0xef, 0xd0, 0x97, 0x74, 0x5a, 0x15, 0x45, 0x5f, 0xe2, 0xe8, 0x4b, 0xb7, 0x3a, 0xad, 0xfb, 0x90, 0x19, 0x0f, 0x61, 0xc6, 0x43, 0x98, 0xf1, 0x10, 0x66, 0x3c, 0x84, 0x19, 0x0f, 0x61, 0xc6, 0x43, 0x98, 0xf1, 0x10, 0x66, 0x3c, 0x84, 0x19, 0x0f, 0x61, 0xc6, 0x43, 0x98, 0xf1, 0x10, 0x66, 0x3c, 0x84, 0x19, 0x0f, 0x61, 0xc6, 0x43, 0xb0, 0x81, 0x6e, 0xf4, 0x7f, 0xa8, 0x6e, 0x03, 0x2a, 0xbd, 0x53, 0xe9, 0x9d, 0x6a, 0xd8, 0x80, 0x3f, 0x33, 0xef, 0x6f, 0xcc, 0xbc, 0xbf, 0x61, 0x03, 0xaa, 0xd1, 0x63, 0x95, 0x1e, 0xab, 0xbf, 0x63, 0x03, 0x2a, 0x3d, 0x56, 0xe9, 0xb1, 0x4a, 0x8f, 0x55, 0x7a,\n\t0xac, 0xd2, 0x63, 0x95, 0x1e, 0xab, 0x28, 0xc5, 0x9f, 0x5e, 0xab, 0xf4, 0x58, 0xa5, 0xc7, 0x2a, 0x3d, 0x56, 0xe9, 0xb1, 0x4a, 0x8f, 0x55, 0x7a, 0xac, 0xd2, 0x63, 0x95, 0x1e, 0xab, 0xf4, 0x58, 0x45, 0x51, 0xfe, 0x28, 0xca, 0x1f, 0x45, 0xf9, 0x33, 0x93, 0xa9, 0x86, 0xa2, 0xc2, 0x18, 0x81, 0x65, 0x86, 0x0d, 0xdc, 0xc7, 0x08, 0x6c, 0x42, 0x51, 0xfe, 0x28, 0xca, 0xdf, 0x50, 0x94, 0xbf, 0xa1, 0x28, 0xed, 0x13, 0xb5, 0xe1, 0x8c, 0x88, 0xca, 0x88, 0xa8, 0x8c, 0x88, 0xca, 0x88, 0xa8, 0x8c, 0x88, 0xca, 0x88, 0xa8, 0x8c, 0x88, 0xca, 0x88, 0xa8, 0x8c, 0x88, 0xca, 0x88, 0xa8, 0x8c, 0x88, 0xca, 0x88, 0xa8, 0x8c, 0x88, 0xca, 0x88, 0xa8, 0xa8, 0xa2, 0x1b, 0xaa, 0x08, 0x62, 0x54, 0xa6, 0xfe, 0x8f, 0x6d, 0x20, 0x92, 0x16, 0xa7, 0x19, 0x36, 0x70, 0x17, 0x2d, 0x9e, 0xfd, 0xa7, 0x6c,\n\t0x60, 0xd4, 0x2d, 0x4a, 0xee, 0x4f, 0x49, 0xb1, 0x94, 0xf4, 0x00, 0x25, 0xdd, 0x65, 0xd8, 0x7f, 0x52, 0x9d, 0xd9, 0x4f, 0xe0, 0xca, 0xbe, 0xba, 0x0d, 0x0c, 0xbd, 0xe5, 0xca, 0x58, 0xae, 0xec, 0xca, 0x95, 0xb3, 0xb9, 0x72, 0x2e, 0x57, 0x26, 0x71, 0xe5, 0x8a, 0x3a, 0x57, 0x86, 0xd2, 0xdb, 0x36, 0xf4, 0xd6, 0x4a, 0x09, 0xa3, 0x44, 0x3d, 0x65, 0xaa, 0xfc, 0xd7, 0x5f, 0x8a, 0xc8, 0xcd, 0x7a, 0xe4, 0x3f, 0x5e, 0x9e, 0xe3, 0x2a, 0x27, 0x57, 0x15, 0x1b, 0xeb, 0xd3, 0x35, 0xa2, 0xfb, 0x1f, 0x59, 0xb9, 0x6e, 0xe4, 0x04, 0xdf, 0xb2, 0xb6, 0x5f, 0x60, 0x5d, 0x3f, 0x5b, 0xb7, 0x7c, 0xce, 0xfa, 0x8e, 0x32, 0x96, 0x88, 0x0e, 0x37, 0xb5, 0xdb, 0x66, 0x78, 0x35, 0xda, 0x28, 0xea, 0x51, 0xc3, 0xe7, 0x5c, 0x9f, 0xc5, 0xf5, 0x99, 0xc4, 0x06, 0x5a, 0x19, 0x05, 0x9c, 0xed, 0xe6, 0x6c,\n\t0x37, 0x59, 0x70, 0x1b, 0x6a, 0x3b, 0xaf, 0x3e, 0xab, 0xfb, 0xac, 0x86, 0x94, 0xf7, 0x3a, 0x23, 0x68, 0x92, 0x1f, 0x91, 0xcd, 0x56, 0xfd, 0xe5, 0xde, 0x54, 0x90, 0x5f, 0x74, 0xc4, 0x0e, 0xd2, 0xc9, 0x2f, 0x82, 0xb1, 0x89, 0x60, 0xf2, 0x8b, 0x60, 0xd6, 0x87, 0x60, 0xf2, 0x0b, 0x32, 0x7a, 0x18, 0x09, 0xa3, 0x60, 0x34, 0xe7, 0x8d, 0x81, 0xb1, 0x30, 0x0e, 0xc6, 0xc3, 0x04, 0x8e, 0x4f, 0x64, 0x3b, 0x89, 0xed, 0x64, 0xd0, 0x3c, 0xa8, 0xa6, 0xa0, 0x69, 0x30, 0x1d, 0x66, 0xc0, 0x4c, 0x98, 0x05, 0xb7, 0xc3, 0x6c, 0x98, 0x03, 0x73, 0x61, 0x1e, 0xdc, 0x01, 0xf3, 0x61, 0x01, 0xdc, 0x49, 0x1b, 0x16, 0x0b, 0xed, 0xfe, 0x46, 0x3a, 0xea, 0xdb, 0x8c, 0xfa, 0x36, 0xa3, 0xbe, 0xcd, 0x8c, 0xd4, 0x66, 0xd4, 0xb7, 0x19, 0x3b, 0x4c, 0xc7, 0x0e, 0xd3, 0xb1, 0xc3, 0x74, 0xec, 0x30, 0x1d,\n\t0x3b, 0x4c, 0x27, 0xbf, 0x08, 0x16, 0xeb, 0xe8, 0xc5, 0x7a, 0xb8, 0x07, 0x36, 0xc0, 0xbd, 0xb0, 0x11, 0x36, 0xc1, 0x66, 0xb8, 0x0f, 0xee, 0x87, 0x74, 0x94, 0xf6, 0xa0, 0xe8, 0x49, 0x1e, 0xd2, 0x93, 0x3c, 0xa4, 0x3f, 0x79, 0xc8, 0x7d, 0x44, 0x9c, 0x69, 0xe4, 0x21, 0x2b, 0x88, 0x3a, 0xb7, 0x92, 0x87, 0xec, 0x21, 0xf2, 0x5c, 0x47, 0x1e, 0xf2, 0x37, 0xa2, 0xcf, 0x75, 0xe4, 0x21, 0x7f, 0x23, 0x0f, 0x49, 0x26, 0x0f, 0x79, 0x4f, 0x1f, 0xd5, 0xe9, 0xe4, 0x23, 0x33, 0xc5, 0x9b, 0x44, 0x27, 0xaf, 0x13, 0x99, 0x6e, 0x27, 0x17, 0xd9, 0x4d, 0x2e, 0xb2, 0x9b, 0x48, 0xe5, 0x08, 0xb9, 0xc8, 0xf2, 0x5b, 0x7c, 0x42, 0x3a, 0x3e, 0x21, 0x1d, 0x9f, 0x90, 0x6e, 0xa2, 0x5d, 0x26, 0xda, 0x45, 0x4e, 0xd2, 0x1f, 0xff, 0x90, 0x8e, 0x7f, 0x48, 0x27, 0x27, 0xe9, 0x48, 0x4e, 0xd2, 0x91, 0x9c,\n\t0xa4, 0x2d, 0x39, 0x49, 0x47, 0x72, 0x92, 0x8e, 0xe4, 0x24, 0xc1, 0xe4, 0x24, 0xc1, 0xe4, 0x24, 0xc1, 0xe4, 0x24, 0xc1, 0xe4, 0x24, 0xc1, 0xa6, 0x57, 0xb9, 0xee, 0xef, 0x22, 0x10, 0x7f, 0x92, 0x8e, 0x3f, 0x49, 0x27, 0xfa, 0xdd, 0x4d, 0xf4, 0xbb, 0x9b, 0xdc, 0xa4, 0x23, 0xb9, 0x49, 0xb0, 0x91, 0x9b, 0x74, 0x24, 0x37, 0x09, 0x26, 0x37, 0x09, 0x26, 0x37, 0x09, 0x26, 0x37, 0x09, 0x26, 0x37, 0x59, 0x81, 0xdf, 0x49, 0xf7, 0x65, 0xc6, 0x8d, 0xfc, 0x24, 0x1d, 0xff, 0x93, 0x8e, 0xff, 0x49, 0xb7, 0x1c, 0x24, 0x8a, 0x3a, 0x2f, 0x82, 0xc9, 0x51, 0x82, 0xc9, 0x51, 0x82, 0xc9, 0x51, 0x82, 0xc9, 0x51, 0x3a, 0x92, 0xa3, 0x74, 0x24, 0x47, 0xe9, 0x48, 0x8e, 0xd2, 0x91, 0x1c, 0xa5, 0x23, 0x39, 0x4a, 0x30, 0x39, 0x4a, 0x30, 0x39, 0x4a, 0x30, 0x39, 0x4a, 0x30, 0x39, 0x4a, 0x30, 0x39,\n\t0x4a, 0x30, 0x39, 0x4a, 0x30, 0x39, 0x4a, 0x30, 0x39, 0x4a, 0x30, 0xbe, 0x2c, 0x1d, 0x5f, 0x96, 0x8e, 0x2f, 0x4b, 0xc7, 0x97, 0xa5, 0xe3, 0xcb, 0xd2, 0xf1, 0x65, 0xe9, 0x78, 0x86, 0xcd, 0x78, 0x86, 0xcd, 0x78, 0x86, 0xcd, 0x58, 0xe4, 0x66, 0x3c, 0xc3, 0x66, 0x23, 0x47, 0xd1, 0xd6, 0xb4, 0xcd, 0x86, 0x3d, 0x6f, 0xc6, 0x33, 0x6c, 0xae, 0x93, 0xa3, 0x6c, 0x36, 0x72, 0x94, 0xcd, 0x46, 0x8e, 0x92, 0x8e, 0x2f, 0x4b, 0xc7, 0x97, 0xa5, 0xe3, 0xcb, 0xd2, 0xf1, 0x65, 0xe9, 0xf8, 0xb2, 0x74, 0x7c, 0x59, 0x3a, 0xbe, 0x2c, 0x1d, 0x5f, 0x96, 0x8e, 0x2f, 0x4b, 0xc7, 0x97, 0xa5, 0xe3, 0xcb, 0xd2, 0xf1, 0x65, 0xe9, 0xf8, 0xb2, 0x74, 0x75, 0x02, 0x56, 0xae, 0xe5, 0x29, 0xdb, 0xc4, 0x0e, 0x75, 0x17, 0xdb, 0xdd, 0xf0, 0x24, 0x3c, 0x05, 0x4f, 0xc3, 0x33, 0x80, 0xed, 0xa8, 0xcf, 0xc1,\n\t0x1e, 0xd8, 0x0b, 0xcf, 0xc3, 0x0b, 0xf0, 0x22, 0xec, 0x83, 0x97, 0x60, 0x3f, 0xbc, 0x0c, 0xaf, 0xc0, 0x01, 0x60, 0x2e, 0x54, 0xe6, 0x42, 0x7d, 0x0d, 0x5e, 0x87, 0x37, 0xe0, 0x1f, 0xf0, 0x26, 0xbc, 0x05, 0x6f, 0xc3, 0x3b, 0xf0, 0x2e, 0xbc, 0x07, 0xef, 0xc3, 0x07, 0xf0, 0x21, 0x7c, 0x04, 0x1f, 0xc3, 0x3f, 0xe1, 0x13, 0xf8, 0x54, 0xcf, 0xa3, 0xc2, 0xc8, 0xa3, 0xc2, 0xc8, 0xa3, 0x7a, 0x92, 0x47, 0xf5, 0x24, 0x8f, 0xea, 0x49, 0x1e, 0xd5, 0x93, 0x3c, 0xaa, 0x27, 0x79, 0x54, 0x4f, 0xf2, 0xa8, 0x9e, 0xe4, 0x51, 0x3d, 0xc9, 0xa3, 0x7a, 0x92, 0x47, 0xf5, 0x27, 0x8f, 0xea, 0x4f, 0x1e, 0xd5, 0x9f, 0x3c, 0xaa, 0x3f, 0x79, 0x54, 0x7f, 0xf2, 0xa8, 0xfe, 0xe4, 0x51, 0xfd, 0xc9, 0xa3, 0xfa, 0x93, 0x47, 0xf5, 0x27, 0x8f, 0xea, 0x4f, 0x1e, 0xa5, 0x29, 0x7e, 0xbb, 0x3c, 0x8f, 0x17,\n\t0xfa, 0xe9, 0x96, 0xfb, 0x1c, 0x5f, 0xd7, 0xb9, 0x7b, 0x72, 0x4c, 0xb1, 0xa3, 0xd4, 0x1b, 0xf7, 0x39, 0xb4, 0x4f, 0xf8, 0x55, 0xf9, 0xf4, 0x95, 0x3f, 0xf8, 0x84, 0xc1, 0x97, 0xb2, 0xca, 0xb8, 0xcf, 0xf1, 0x9c, 0x68, 0x2c, 0xb6, 0xc9, 0x0b, 0x94, 0xf8, 0x0b, 0x25, 0x7e, 0x41, 0x89, 0x5f, 0x52, 0xe2, 0x3e, 0x4a, 0xfc, 0x92, 0x12, 0xff, 0x49, 0x89, 0x5f, 0x50, 0xe2, 0x61, 0x4a, 0x3c, 0x44, 0x89, 0x67, 0x28, 0xd1, 0x41, 0x89, 0x0e, 0x4a, 0x3c, 0x4f, 0x89, 0x97, 0xb4, 0x6f, 0x24, 0x50, 0xea, 0x67, 0x94, 0xfa, 0x99, 0x76, 0x7f, 0x91, 0x52, 0x8b, 0x28, 0xf5, 0x41, 0xd1, 0xdc, 0x28, 0xb5, 0xf2, 0x7a, 0xa9, 0x83, 0x89, 0xf3, 0x87, 0xc2, 0xef, 0x95, 0xbe, 0x90, 0x92, 0x17, 0xc1, 0x7f, 0xae, 0xe5, 0x14, 0xb5, 0x9c, 0xba, 0xa9, 0x16, 0x6d, 0x24, 0xf2, 0xa8, 0xe1, 0x28, 0x35,\n\t0x1c, 0xa5, 0xe4, 0xd7, 0x29, 0xf9, 0x27, 0x4a, 0x3e, 0x48, 0xc9, 0xdf, 0x50, 0xf2, 0x31, 0x4a, 0x3c, 0x62, 0xdc, 0xf1, 0xd1, 0x3c, 0xb9, 0x53, 0xbf, 0xdb, 0xe8, 0xb9, 0xe3, 0xf3, 0x2d, 0xa5, 0x7d, 0x6b, 0xdc, 0xf1, 0xb9, 0x44, 0x69, 0x3b, 0x44, 0x13, 0xda, 0x7c, 0x8e, 0x12, 0x73, 0x28, 0xf1, 0x20, 0x25, 0x7e, 0x41, 0xce, 0x72, 0x9e, 0x52, 0x0f, 0x50, 0xea, 0xd7, 0x94, 0xfa, 0x29, 0xa5, 0x7e, 0x65, 0x8c, 0xc6, 0xb7, 0x94, 0x7a, 0x9a, 0x52, 0x0b, 0x28, 0xb5, 0xc0, 0xb8, 0x8f, 0xe4, 0xd2, 0x3e, 0xf1, 0x40, 0xc9, 0x9f, 0x52, 0xf2, 0xa7, 0x94, 0xec, 0xa2, 0x64, 0x6d, 0x35, 0xb8, 0x8b, 0x38, 0xcb, 0x24, 0x33, 0xf1, 0xf9, 0xda, 0xbd, 0xdc, 0x7f, 0x50, 0xaa, 0xd6, 0x4e, 0xcd, 0xf7, 0x7f, 0x4f, 0x89, 0x3f, 0x53, 0x4a, 0x3e, 0xa5, 0xe4, 0x1b, 0xab, 0x4c, 0x05, 0x3e, 0xbf,\n\t0x09, 0x57, 0x39, 0x85, 0x3f, 0xed, 0xc8, 0xa7, 0x1d, 0x0e, 0xda, 0xf0, 0x29, 0x57, 0x64, 0x70, 0xc5, 0x97, 0xc6, 0x1c, 0x6b, 0x9f, 0xe2, 0xca, 0xe1, 0xca, 0x22, 0xa3, 0x7e, 0xed, 0x1b, 0x49, 0x79, 0xd4, 0x9b, 0xc7, 0x95, 0xff, 0x10, 0x6f, 0x90, 0x1b, 0x3b, 0xc9, 0x8d, 0x9d, 0xe4, 0xc6, 0x4e, 0x72, 0x63, 0x27, 0xb9, 0xb1, 0x93, 0xdc, 0xd8, 0x49, 0x6e, 0xec, 0x14, 0x5a, 0xd9, 0xa3, 0x61, 0x0c, 0x8c, 0x85, 0x71, 0x30, 0x1e, 0x26, 0xc0, 0x44, 0x98, 0x04, 0x93, 0x61, 0x0a, 0x4c, 0x85, 0x69, 0x30, 0x1d, 0x66, 0xc0, 0x4c, 0x98, 0x05, 0xb7, 0xc3, 0x6c, 0x98, 0x03, 0x73, 0x61, 0x1e, 0xdc, 0x01, 0xf3, 0x61, 0x01, 0x2c, 0x94, 0x57, 0xc4, 0x2a, 0xf2, 0xe3, 0xd5, 0x70, 0x17, 0xac, 0xd1, 0xf3, 0x65, 0xa7, 0x58, 0x27, 0x8b, 0xc5, 0x7a, 0xb8, 0x07, 0x36, 0xc0, 0xbd, 0xb0, 0x11,\n\t0x36, 0xc1, 0x66, 0xb8, 0x0f, 0xee, 0x87, 0x74, 0x79, 0x46, 0x3c, 0x28, 0xcf, 0x93, 0x5b, 0x97, 0x90, 0x5b, 0xe7, 0x32, 0x02, 0x4e, 0xe3, 0xf3, 0x6b, 0xa5, 0x26, 0xae, 0x35, 0x71, 0xad, 0x69, 0x8b, 0xbc, 0x62, 0x7a, 0x94, 0xf9, 0xdc, 0x21, 0x73, 0xc9, 0xa3, 0x9d, 0xe4, 0xd1, 0x4e, 0xf2, 0x68, 0x27, 0x79, 0xb4, 0x93, 0x3c, 0xda, 0x49, 0x1e, 0xed, 0x24, 0x8f, 0x76, 0x92, 0x47, 0x3b, 0xc9, 0xa3, 0x9d, 0xe4, 0xd1, 0x4e, 0xd3, 0xab, 0x5c, 0xf7, 0x77, 0x59, 0x4c, 0x3e, 0xed, 0x24, 0x9f, 0x76, 0x92, 0x4f, 0x3b, 0xc9, 0xa7, 0x9d, 0xe4, 0xd3, 0x4e, 0xf2, 0x69, 0x27, 0xf9, 0xb4, 0xd3, 0xb7, 0x83, 0x2c, 0x26, 0xa7, 0x76, 0x92, 0x53, 0x3b, 0xc9, 0xa9, 0x9d, 0xe4, 0xd4, 0x4e, 0x72, 0x6a, 0x27, 0x39, 0xb5, 0x93, 0x9c, 0xda, 0x49, 0x4e, 0xed, 0x24, 0xa7, 0x76, 0x92, 0x53, 0x3b,\n\t0xc9, 0xa9, 0x9d, 0xe4, 0xd4, 0x4e, 0x72, 0x6a, 0x27, 0x39, 0xb5, 0x93, 0x9c, 0xda, 0x49, 0x4e, 0xed, 0x24, 0xa7, 0x76, 0x92, 0x53, 0x3b, 0x2d, 0x52, 0x5e, 0x51, 0x05, 0x28, 0x60, 0x02, 0x2f, 0xf0, 0x06, 0x1f, 0x78, 0x88, 0x9c, 0xfb, 0x61, 0xd8, 0x06, 0xdb, 0x81, 0xbe, 0xa8, 0x8f, 0xc1, 0xe3, 0xf0, 0x04, 0xec, 0x80, 0x5d, 0xb2, 0x58, 0xdd, 0x0d, 0x4f, 0xc2, 0x53, 0xf0, 0x34, 0x3c, 0x03, 0xcf, 0xc2, 0x73, 0xb0, 0x07, 0xf6, 0xc2, 0xf3, 0xf0, 0x02, 0xbc, 0x08, 0xfb, 0xe0, 0x25, 0xd8, 0x0f, 0x2f, 0xc3, 0x2b, 0x70, 0x00, 0xe8, 0xbb, 0x4a, 0xdf, 0xd5, 0xd7, 0xe0, 0x75, 0x78, 0x03, 0xfe, 0x01, 0x6f, 0xc2, 0x5b, 0xf0, 0x36, 0xbc, 0x03, 0xef, 0xc2, 0x7b, 0xf0, 0x3e, 0x7c, 0x00, 0x1f, 0xc2, 0x47, 0xf0, 0x31, 0xfc, 0x13, 0x3e, 0x81, 0x4f, 0x21, 0x53, 0x9e, 0x51, 0xb3, 0x20,\n\t0x9b, 0x58, 0x25, 0x07, 0x4e, 0xc0, 0x49, 0x38, 0x05, 0xb9, 0x90, 0x07, 0x67, 0x64, 0x89, 0xfa, 0x2b, 0x9c, 0x93, 0xb9, 0xaa, 0x03, 0xf2, 0xa1, 0x00, 0x9c, 0x50, 0x0c, 0xe7, 0xe1, 0x02, 0x5c, 0x84, 0x12, 0x99, 0xcb, 0x6a, 0x1f, 0x05, 0xd1, 0xe0, 0x89, 0x4b, 0x83, 0x7f, 0x27, 0x2e, 0x0d, 0x66, 0xf5, 0x09, 0x66, 0xf5, 0x09, 0x66, 0xf5, 0x09, 0x66, 0xf5, 0xd9, 0x6d, 0xc4, 0xa5, 0x93, 0x59, 0x7d, 0x62, 0x8d, 0x8c, 0x2a, 0x8a, 0xd5, 0xe7, 0x23, 0x56, 0x9f, 0x60, 0x56, 0x9f, 0x60, 0x56, 0x9f, 0x60, 0x56, 0x9f, 0x60, 0x56, 0x9f, 0x60, 0x56, 0x9f, 0x60, 0x56, 0x9f, 0x19, 0xc4, 0x88, 0x61, 0x58, 0xda, 0x42, 0xca, 0x0f, 0x25, 0x6e, 0x08, 0x97, 0x97, 0x89, 0x4f, 0xc2, 0x88, 0x4f, 0xc2, 0x88, 0x4f, 0xc2, 0x68, 0x45, 0x28, 0xad, 0x08, 0xa5, 0x15, 0xa1, 0xb4, 0x22, 0x54, 0x3f,\n\t0x2b, 0x96, 0xe3, 0xcb, 0x60, 0x39, 0xa4, 0xc2, 0x5a, 0x78, 0x88, 0x7c, 0x61, 0x1b, 0xd1, 0xd4, 0x76, 0xd1, 0x9b, 0x38, 0xa3, 0x0b, 0x71, 0xc6, 0x68, 0xe2, 0x8c, 0x79, 0xc4, 0x19, 0x03, 0x89, 0x33, 0xa6, 0x10, 0x67, 0x0c, 0x24, 0xce, 0x98, 0x42, 0x9c, 0xd1, 0x99, 0x38, 0x23, 0x92, 0x18, 0xc3, 0x4e, 0x8c, 0xb1, 0x8c, 0x18, 0x63, 0x09, 0x31, 0x46, 0x04, 0x31, 0xc6, 0x74, 0x62, 0x8c, 0xe9, 0xc4, 0x18, 0x89, 0xc4, 0x18, 0x9d, 0x89, 0x2b, 0xc2, 0x88, 0x2b, 0xc2, 0x88, 0x2b, 0xc2, 0x88, 0x03, 0x1b, 0x12, 0x53, 0x68, 0x39, 0x47, 0x18, 0x31, 0x45, 0x18, 0x31, 0x42, 0x18, 0x31, 0x42, 0x18, 0x31, 0xc2, 0x54, 0x62, 0x84, 0xa9, 0x8c, 0x44, 0x28, 0x71, 0x40, 0x17, 0xe2, 0x80, 0x30, 0xd6, 0xff, 0x30, 0xd6, 0xff, 0x30, 0xd6, 0xff, 0x30, 0xd6, 0x7f, 0x5f, 0xcb, 0x4f, 0x8c, 0x48,\n\t0x43, 0xd6, 0x9e, 0x00, 0x68, 0x04, 0x81, 0xc0, 0xb5, 0xac, 0xdd, 0x61, 0x8c, 0x5e, 0x28, 0xa3, 0x17, 0xca, 0xe8, 0x85, 0x32, 0x7a, 0xa1, 0xc6, 0xe8, 0x85, 0x1a, 0x77, 0x59, 0x42, 0x19, 0xbd, 0x50, 0x46, 0x2f, 0x94, 0xd1, 0x0b, 0x65, 0xf4, 0x42, 0x19, 0xbd, 0x50, 0x46, 0x2f, 0x94, 0xd1, 0x0b, 0x65, 0xf4, 0x42, 0xf5, 0x08, 0xbb, 0x0f, 0xe5, 0xf4, 0x85, 0x30, 0xe8, 0x07, 0xfd, 0x21, 0x1c, 0x06, 0xc1, 0x60, 0x18, 0x02, 0x43, 0x61, 0x18, 0x44, 0xc0, 0x70, 0x18, 0x01, 0xdb, 0xc4, 0x70, 0xd6, 0x3a, 0x95, 0xb5, 0x4e, 0x65, 0xad, 0x53, 0x59, 0xeb, 0x54, 0xd6, 0x3a, 0x95, 0xb5, 0x4e, 0x65, 0xad, 0x53, 0x59, 0xeb, 0x54, 0xd6, 0x3a, 0x95, 0xb5, 0x4e, 0xc5, 0x93, 0x1d, 0x13, 0xde, 0xda, 0xcc, 0x60, 0xfd, 0xe7, 0xb5, 0xd1, 0xd0, 0x8f, 0xfc, 0x9f, 0xba, 0xab, 0x14, 0xf8, 0x27,\n\t0xee, 0x2a, 0x35, 0xbd, 0xe9, 0xae, 0x92, 0xef, 0x1f, 0xc6, 0xf3, 0xb7, 0xbe, 0x73, 0x3d, 0xc7, 0x16, 0x7e, 0xf8, 0xf0, 0xf3, 0xd7, 0xb3, 0x85, 0xe9, 0x9c, 0x31, 0x53, 0x7e, 0x87, 0x17, 0xfb, 0xc9, 0xc8, 0x1a, 0x2e, 0x71, 0xd5, 0x25, 0xae, 0xd2, 0xd6, 0xe2, 0x23, 0xe4, 0x05, 0x4b, 0xc4, 0xe0, 0xdf, 0xb9, 0x22, 0x97, 0x2b, 0xf2, 0xfe, 0xe0, 0x0a, 0x13, 0x39, 0x49, 0x38, 0xab, 0x48, 0x7f, 0xf9, 0x11, 0xa3, 0xf1, 0x0e, 0x57, 0xfc, 0x7c, 0x3d, 0x16, 0x28, 0x65, 0x2d, 0xf5, 0x7c, 0x2b, 0xf1, 0x02, 0x23, 0x51, 0xcc, 0x15, 0x85, 0xfa, 0x15, 0x59, 0x5c, 0x91, 0xcf, 0x15, 0xc7, 0xb8, 0xe2, 0x90, 0xf1, 0x29, 0x6e, 0xed, 0x1e, 0x65, 0x96, 0xb1, 0xa2, 0x14, 0x71, 0xc5, 0x65, 0xae, 0xb8, 0xca, 0x15, 0x45, 0xfa, 0xf7, 0x10, 0xbf, 0xa7, 0x35, 0xc5, 0x46, 0xb6, 0x72, 0xb1, 0xf6,\n\t0xaf, 0x1e, 0x46, 0xa6, 0x72, 0x51, 0x8b, 0xb6, 0x38, 0xf3, 0x9c, 0x5e, 0xf6, 0x0f, 0x46, 0x6b, 0xde, 0xa3, 0xec, 0x77, 0x8d, 0xfb, 0x9f, 0x87, 0xb8, 0xea, 0x47, 0xae, 0x3a, 0xcb, 0x55, 0x67, 0xf5, 0xd5, 0x92, 0xfc, 0x46, 0x6f, 0x8d, 0xf6, 0x29, 0x74, 0x6d, 0x7d, 0x3b, 0xcb, 0x59, 0x3f, 0x73, 0xd6, 0x2f, 0x75, 0x5a, 0xa0, 0xad, 0xca, 0xf9, 0x8a, 0x22, 0xbe, 0x95, 0x63, 0xc5, 0x21, 0xf9, 0xa9, 0x38, 0x2c, 0x47, 0x8b, 0xa3, 0x64, 0x41, 0x3f, 0xca, 0x4f, 0xc4, 0xb1, 0x9a, 0x3d, 0xe2, 0x27, 0xb9, 0x5b, 0xfc, 0x2c, 0x13, 0x44, 0x86, 0x6c, 0x2a, 0x8e, 0xcb, 0x75, 0x22, 0xb3, 0xe6, 0xa8, 0xc8, 0x92, 0xa7, 0xc4, 0x2f, 0x72, 0xb8, 0xc8, 0x96, 0xf7, 0x8b, 0x1c, 0x39, 0x44, 0x9c, 0x90, 0x1d, 0xc5, 0x49, 0x5a, 0x76, 0x4a, 0xb6, 0x16, 0xda, 0xa7, 0xde, 0xf3, 0x58, 0x87, 0x4e,\n\t0xcb, 0x5d, 0xe2, 0x8c, 0x6c, 0x2f, 0x7e, 0xad, 0x79, 0x52, 0x9c, 0xad, 0xd9, 0x2b, 0xce, 0x81, 0x43, 0x76, 0x10, 0xf9, 0xb2, 0x8b, 0x28, 0x60, 0xbf, 0xb0, 0xe6, 0x5f, 0xa2, 0x48, 0x8e, 0x12, 0x4e, 0xd9, 0x4d, 0x14, 0xd7, 0x14, 0xe9, 0x9f, 0x18, 0x1f, 0x20, 0xd7, 0x2a, 0x03, 0xe5, 0x3d, 0x4a, 0xb8, 0x1c, 0xa4, 0x0c, 0x82, 0x08, 0x39, 0x56, 0x19, 0x0e, 0x23, 0x64, 0x77, 0x65, 0xa4, 0x9c, 0xa2, 0x8c, 0x62, 0x3b, 0x9a, 0xed, 0x18, 0x19, 0xa5, 0x4c, 0x90, 0x8b, 0x95, 0x49, 0x72, 0xb1, 0xd7, 0x8b, 0xf2, 0x53, 0xaf, 0x7d, 0x32, 0xc1, 0xeb, 0xa5, 0x9a, 0xbd, 0x5e, 0xfb, 0xa5, 0xb7, 0xd7, 0xcb, 0x72, 0x88, 0xd7, 0xab, 0x35, 0x4f, 0x7a, 0xfd, 0x1d, 0x5e, 0xe3, 0xd8, 0x1b, 0xf0, 0x76, 0xcd, 0x5e, 0xef, 0xcd, 0x72, 0xa9, 0xf7, 0xfd, 0xb0, 0x45, 0x26, 0x79, 0x3f, 0x20, 0x9f,\n\t0xf1, 0x4e, 0x67, 0xfb, 0xa0, 0x7c, 0xc6, 0x27, 0x17, 0x6f, 0x77, 0xa5, 0x66, 0xaf, 0xcf, 0xd5, 0x9a, 0x6a, 0x9f, 0x2a, 0xfd, 0xdb, 0xfa, 0xa3, 0xcd, 0x61, 0x30, 0x01, 0x26, 0xca, 0x37, 0xcc, 0x93, 0x60, 0x32, 0xfb, 0x53, 0x60, 0x2a, 0xfb, 0xd3, 0x60, 0x3a, 0xfb, 0x33, 0x60, 0x26, 0xcc, 0x82, 0xdb, 0x61, 0x36, 0xcc, 0x81, 0xb9, 0xbc, 0x3f, 0x0f, 0xee, 0x60, 0x7f, 0x3e, 0x2c, 0x60, 0x7f, 0x21, 0x2c, 0x62, 0x7f, 0x85, 0xfc, 0xd4, 0xd2, 0x18, 0x9a, 0x40, 0x57, 0xe8, 0x26, 0x33, 0x2d, 0x3d, 0xd8, 0xf6, 0x64, 0x1b, 0x0a, 0xbd, 0xd8, 0xef, 0x0d, 0x5f, 0xd7, 0xec, 0x55, 0x07, 0xca, 0xd6, 0xea, 0x02, 0xb6, 0x0b, 0x21, 0x09, 0x92, 0x6b, 0xbe, 0x56, 0x57, 0xd4, 0x1c, 0x53, 0x53, 0xd8, 0x4f, 0xad, 0xf9, 0x46, 0x4d, 0xab, 0xf9, 0x45, 0x5d, 0xc9, 0xfe, 0xaa, 0x9a, 0xbd, 0xd6,\n\t0x16, 0xf2, 0x13, 0x6b, 0x30, 0xb4, 0x94, 0x39, 0xd6, 0x10, 0x68, 0x05, 0x36, 0x5e, 0xb7, 0x66, 0xdb, 0x06, 0xda, 0x42, 0x3b, 0x5e, 0xb7, 0x87, 0x0e, 0xd0, 0x11, 0x3a, 0x71, 0xac, 0x33, 0x74, 0x81, 0xae, 0xbc, 0xee, 0xc6, 0xb6, 0x3b, 0xf4, 0x80, 0x9e, 0x35, 0x7b, 0xac, 0xa1, 0xd0, 0xab, 0xa6, 0xc8, 0xda, 0xbb, 0xa6, 0xc2, 0xda, 0x87, 0xfd, 0xbe, 0x10, 0xc6, 0xeb, 0x7e, 0x35, 0x2e, 0x6b, 0x7f, 0xf6, 0x07, 0xc0, 0xc0, 0x9a, 0x4f, 0xad, 0xe1, 0xd2, 0x6c, 0x1d, 0x54, 0x73, 0xc9, 0x3a, 0x58, 0x06, 0x5a, 0x87, 0x70, 0x6c, 0x28, 0x0c, 0xe3, 0xbc, 0x08, 0xae, 0x1b, 0xce, 0xfe, 0x08, 0x18, 0xc9, 0xeb, 0x51, 0x5c, 0x37, 0x9a, 0xfd, 0x31, 0x30, 0x96, 0xeb, 0xc6, 0x71, 0xdd, 0xf8, 0x9a, 0xa3, 0xd6, 0x09, 0x30, 0x51, 0xfa, 0x59, 0x27, 0xc9, 0xdb, 0xac, 0x93, 0xd9, 0x9f, 0xc2,\n\t0xfe, 0x54, 0xd9, 0xd2, 0x3a, 0x8d, 0xfd, 0xe9, 0x35, 0xb9, 0xd6, 0x19, 0x72, 0xb8, 0x75, 0x16, 0xdc, 0x0e, 0xb3, 0x61, 0x0e, 0xcc, 0x85, 0x79, 0x70, 0x07, 0xcc, 0x87, 0x05, 0xb0, 0x10, 0x16, 0xc1, 0x9d, 0xb0, 0x18, 0x22, 0x21, 0x0a, 0xa2, 0x21, 0x06, 0xec, 0xb0, 0x04, 0x96, 0x42, 0x2c, 0xc4, 0xc1, 0x32, 0x58, 0x2e, 0x47, 0x5a, 0xe3, 0x89, 0x07, 0x93, 0xe4, 0x76, 0x6b, 0xb2, 0x68, 0x68, 0x5d, 0x21, 0xda, 0x5b, 0x53, 0xe4, 0x23, 0xd6, 0x54, 0x48, 0x13, 0x4d, 0xad, 0x2b, 0x45, 0x67, 0xeb, 0x2a, 0xf6, 0x57, 0x73, 0xce, 0x5d, 0x62, 0x91, 0x75, 0x8d, 0xbc, 0x68, 0x5d, 0x2b, 0xc7, 0x5a, 0xef, 0x96, 0x3f, 0x59, 0xd7, 0xc9, 0x93, 0xd6, 0xf5, 0xf2, 0x5b, 0xeb, 0x3d, 0x62, 0xb8, 0xf5, 0xde, 0x9a, 0x27, 0xad, 0x1b, 0x61, 0x93, 0xec, 0x62, 0xdd, 0x2c, 0xfb, 0x59, 0xef, 0x93,\n\t0x03, 0xad, 0xf7, 0xb3, 0xbf, 0x05, 0x1e, 0x80, 0x74, 0x78, 0x10, 0xb6, 0xc2, 0x43, 0xf0, 0x30, 0x6c, 0x93, 0x29, 0xd6, 0xed, 0xf0, 0x08, 0xe7, 0x3f, 0xca, 0xeb, 0xc7, 0xe0, 0x71, 0x78, 0x02, 0x76, 0xc0, 0x2e, 0xc6, 0x6d, 0x37, 0x3c, 0x09, 0x4f, 0xc1, 0xd3, 0xf0, 0x0c, 0x3c, 0x0b, 0xcf, 0xc1, 0x1e, 0xd8, 0x0b, 0xcf, 0xc3, 0x0b, 0x35, 0xd9, 0xd6, 0x17, 0xd9, 0xee, 0x83, 0x97, 0x60, 0x3f, 0xbc, 0x0c, 0xaf, 0xc0, 0x01, 0x78, 0x15, 0xfe, 0x0e, 0xaf, 0xc1, 0xeb, 0xf0, 0x06, 0xe7, 0x7f, 0x24, 0x3f, 0xb5, 0x9e, 0x92, 0x8b, 0xad, 0xb9, 0xf2, 0xb0, 0xdf, 0x63, 0x35, 0xd5, 0xe2, 0x3b, 0x3c, 0xc0, 0x19, 0xac, 0x3f, 0x4f, 0xfc, 0x20, 0x5f, 0x14, 0xc7, 0x88, 0x0a, 0x7f, 0x92, 0x6e, 0xac, 0x3f, 0x0f, 0xeb, 0xdf, 0x89, 0xf5, 0x97, 0x8a, 0x4c, 0xe9, 0xc2, 0xfa, 0x2f, 0x60, 0xfd,\n\t0x05, 0x58, 0x7f, 0x16, 0xd6, 0x7f, 0x10, 0xeb, 0xaf, 0xc6, 0xf2, 0xdd, 0x58, 0xfe, 0x7b, 0x58, 0xfe, 0x05, 0x2c, 0xff, 0xa2, 0x38, 0xcb, 0xf6, 0x1c, 0x38, 0xe4, 0x33, 0x58, 0x7c, 0x85, 0x28, 0x60, 0xbf, 0x90, 0x88, 0xb3, 0x88, 0xb5, 0x85, 0xa8, 0x44, 0x14, 0xcb, 0x2a, 0xe3, 0xaf, 0x38, 0x27, 0x94, 0x21, 0x72, 0x97, 0x32, 0x0c, 0xc6, 0xcb, 0xc7, 0xf1, 0x4f, 0x25, 0xc6, 0x13, 0x03, 0x76, 0x92, 0xaf, 0xec, 0x20, 0x5f, 0xd9, 0x81, 0x85, 0x9f, 0xc1, 0xc2, 0xf3, 0xbc, 0x5e, 0x92, 0x17, 0xb0, 0xee, 0x83, 0x5e, 0xaf, 0xb1, 0x7d, 0x03, 0xde, 0x96, 0x17, 0xb0, 0xe6, 0x32, 0x2c, 0xd9, 0xf3, 0x79, 0xe5, 0x5c, 0x32, 0x8e, 0x2b, 0xf2, 0x02, 0x56, 0x7c, 0x06, 0x4b, 0x3b, 0x83, 0xa5, 0x9d, 0xc1, 0xd2, 0xce, 0x60, 0x69, 0x67, 0xb0, 0xb4, 0xcb, 0x58, 0xda, 0x19, 0x2c, 0xed, 0x32,\n\t0x96, 0x76, 0x19, 0x4b, 0x3b, 0x83, 0xa5, 0x9d, 0xb1, 0xcc, 0x90, 0xab, 0x2d, 0xf7, 0xc2, 0x46, 0x79, 0xcc, 0xb2, 0x89, 0x6d, 0x3a, 0xdb, 0x87, 0x61, 0x1b, 0x6c, 0xe7, 0xf5, 0x23, 0xf0, 0xb5, 0xbc, 0x80, 0x35, 0xba, 0xd5, 0x05, 0x6c, 0x17, 0x42, 0x12, 0x24, 0xc3, 0x0a, 0x48, 0x81, 0x54, 0x48, 0x83, 0x95, 0xb0, 0x4a, 0x5e, 0xb0, 0xf6, 0x94, 0x25, 0xd6, 0x50, 0xe8, 0x05, 0xbd, 0xa1, 0x0f, 0xf4, 0x85, 0x30, 0xe8, 0x07, 0xfd, 0x61, 0x00, 0x0c, 0x84, 0x70, 0x18, 0x04, 0x83, 0x61, 0x08, 0x0c, 0x85, 0x61, 0x10, 0x01, 0xc3, 0x61, 0x04, 0x8c, 0x84, 0x51, 0x30, 0x1a, 0xc6, 0xc0, 0x58, 0x18, 0x07, 0xe3, 0xc9, 0x7d, 0x26, 0xc0, 0x44, 0x98, 0x04, 0x93, 0x61, 0x0a, 0x4c, 0x85, 0x69, 0x30, 0x1d, 0x66, 0xc8, 0x02, 0xac, 0xa7, 0x00, 0xeb, 0x29, 0xc0, 0x7a, 0x0a, 0xb0, 0x9e, 0x02,\n\t0xac, 0xa7, 0x00, 0xeb, 0x29, 0xc0, 0x7a, 0x0a, 0xb0, 0x9e, 0x02, 0xac, 0xa7, 0x00, 0xeb, 0x29, 0xc0, 0x7a, 0x0a, 0xb0, 0x9e, 0x02, 0xac, 0xa7, 0x00, 0xeb, 0x29, 0xc0, 0x7a, 0x0a, 0xb0, 0x9e, 0x02, 0xac, 0xa7, 0x00, 0xeb, 0x29, 0xc0, 0x7a, 0x0a, 0xb0, 0x9e, 0x02, 0xac, 0xa7, 0x00, 0xeb, 0x29, 0xc0, 0x7a, 0x0a, 0xb0, 0x9e, 0x6a, 0xac, 0xa7, 0x1a, 0xeb, 0xa9, 0xb6, 0x26, 0xc3, 0x0a, 0x48, 0x81, 0x54, 0x48, 0x83, 0x95, 0xb0, 0x0a, 0x56, 0xc3, 0x5d, 0xb0, 0x06, 0xd6, 0xc2, 0xdd, 0xb0, 0x0e, 0xd6, 0xc3, 0x3d, 0xb0, 0x09, 0xeb, 0xda, 0x0c, 0xf7, 0xc1, 0xfd, 0xb0, 0x05, 0x1e, 0x80, 0x74, 0x78, 0x10, 0xb6, 0xc2, 0x43, 0xf0, 0x30, 0x6c, 0x83, 0xed, 0xf0, 0x08, 0x3c, 0x0a, 0x8f, 0xc1, 0xe3, 0xf0, 0x04, 0xec, 0x80, 0x5d, 0xe4, 0xdd, 0xbb, 0xe1, 0x49, 0x78, 0x0a, 0x9e, 0x86,\n\t0x67, 0xe0, 0x59, 0x78, 0x0e, 0xf6, 0xc0, 0x5e, 0x78, 0x1e, 0x5e, 0x80, 0x17, 0x61, 0x1f, 0xbc, 0x04, 0xfb, 0xe1, 0x65, 0x78, 0x05, 0x0e, 0xc0, 0xab, 0xf0, 0x77, 0x78, 0x0d, 0x5e, 0x87, 0x37, 0xe0, 0x23, 0x79, 0x06, 0x8b, 0x79, 0x4b, 0x0c, 0x64, 0xcd, 0xcc, 0x63, 0xbd, 0xcc, 0x16, 0xdf, 0xc9, 0x5f, 0xc4, 0x11, 0x99, 0x83, 0xb5, 0x5c, 0xc0, 0x5a, 0xaa, 0xb0, 0x94, 0x12, 0xac, 0xa4, 0x14, 0x0b, 0xa9, 0x62, 0x5d, 0xdc, 0x83, 0x65, 0xb8, 0xb1, 0x8c, 0x12, 0x2c, 0xa3, 0x84, 0x35, 0xb1, 0x04, 0x4b, 0x28, 0xc7, 0x0a, 0x7e, 0xf7, 0x1b, 0x5e, 0x28, 0xbd, 0x8a, 0x75, 0xac, 0xa0, 0xee, 0x37, 0xbb, 0x58, 0x93, 0xb2, 0x59, 0x93, 0xb2, 0x59, 0x93, 0xb2, 0x59, 0x93, 0x2e, 0xb3, 0x26, 0x5d, 0x66, 0x4d, 0xca, 0x66, 0x4d, 0xca, 0x66, 0x4d, 0xba, 0xcc, 0x9a, 0x74, 0x99, 0x35, 0x29,\n\t0x9b, 0x35, 0x29, 0x9b, 0x35, 0x29, 0x9b, 0x35, 0x29, 0x9b, 0x35, 0x29, 0x9b, 0x35, 0x29, 0x9b, 0x35, 0x29, 0x9b, 0x35, 0xe9, 0x32, 0x6b, 0xd2, 0x65, 0xd6, 0xa4, 0x6c, 0xd6, 0xa4, 0x6c, 0xd6, 0xa4, 0xcb, 0xac, 0x49, 0x97, 0x59, 0x93, 0xb2, 0xb1, 0x80, 0x2f, 0x2c, 0x77, 0xc9, 0xc3, 0x58, 0x40, 0x11, 0xea, 0x2f, 0x42, 0xfd, 0x45, 0xa8, 0xbf, 0xc8, 0xb2, 0x43, 0x9e, 0x66, 0xc6, 0xa4, 0xf8, 0x1e, 0x9f, 0x90, 0x8d, 0x4f, 0xc8, 0xc2, 0x27, 0xec, 0xc2, 0x27, 0x14, 0x19, 0x3e, 0xe1, 0x67, 0x7c, 0xc2, 0xa3, 0xf4, 0xb4, 0x08, 0x9f, 0x50, 0x46, 0x6f, 0x1d, 0xf8, 0x04, 0x07, 0x3d, 0xfe, 0x0e, 0x9f, 0xf0, 0x01, 0x3e, 0xa1, 0xcc, 0xf0, 0x09, 0x6f, 0xd2, 0xf3, 0x7c, 0x7a, 0x5e, 0x80, 0x4f, 0x70, 0xe0, 0x13, 0x1c, 0xf8, 0x84, 0xdd, 0xf8, 0x04, 0x07, 0x3e, 0xc1, 0xc1, 0x48, 0x9c,\n\t0xc1, 0x27, 0x1c, 0x67, 0x34, 0x7e, 0xc2, 0x27, 0x38, 0xf5, 0x67, 0x76, 0x0c, 0x91, 0x8f, 0xe2, 0x0f, 0x1e, 0xfd, 0xcd, 0x13, 0x44, 0x16, 0xf2, 0x7a, 0x91, 0xdc, 0x86, 0x3f, 0xc8, 0x66, 0x94, 0x7e, 0xc6, 0x1f, 0x38, 0xf0, 0x07, 0x1f, 0xe0, 0x0f, 0x1c, 0xf8, 0x03, 0x07, 0xfe, 0xc0, 0xc1, 0x2a, 0x5f, 0xc2, 0x2a, 0x5f, 0x82, 0x5f, 0xc8, 0xc2, 0x2f, 0x64, 0x19, 0x7e, 0xa1, 0x0c, 0xbf, 0xe0, 0xc0, 0x2f, 0x64, 0xe3, 0x17, 0xb2, 0xf1, 0x0b, 0xd9, 0xf8, 0x85, 0x6c, 0xfc, 0x42, 0xb6, 0xe1, 0x17, 0xb2, 0xeb, 0xf8, 0x85, 0x6c, 0xfc, 0x82, 0x36, 0x2a, 0xa9, 0xf8, 0x85, 0x14, 0xc3, 0x2f, 0xa4, 0xdc, 0xe2, 0x17, 0x52, 0xf0, 0x0b, 0x29, 0xf8, 0x05, 0x87, 0xe1, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f,\n\t0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xa1, 0x08, 0xbf, 0x50, 0x84, 0x5f, 0x60, 0x55, 0x85, 0x3e, 0xd0, 0x17, 0xc2, 0xa0, 0x1f, 0xf4, 0x87, 0x01, 0x30, 0x10, 0xc2, 0x61, 0x10, 0x0c, 0x86, 0x21, 0x30, 0x14, 0x86, 0x41, 0x04, 0x0c, 0x87, 0x11, 0x30, 0x12, 0x88, 0x1c, 0xf1, 0x0b, 0x45, 0xf8, 0x85, 0x22, 0xfc, 0x42, 0x11, 0x7e, 0xa1, 0x08, 0xbf, 0x50, 0x86, 0x5f, 0x28, 0xc3, 0x2f, 0x94, 0xe1, 0x17, 0xca, 0xf0, 0x0b, 0x65, 0xf8, 0x85, 0x32, 0xfc, 0x42, 0x19, 0x7e, 0xa1, 0x0c, 0xbf, 0x50, 0x86, 0x5f, 0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f,\n\t0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x28, 0xc3, 0x2f, 0x94, 0xe1, 0x17, 0xca, 0xf0, 0x0b, 0x65, 0xf8, 0x85, 0x32, 0xfc, 0x42, 0x19, 0x7e, 0xa1, 0x0c, 0xbf, 0x50, 0x86, 0x5f, 0x28, 0xc3, 0x2f, 0x94, 0xe1, 0x17, 0xca, 0x50, 0x59, 0x19, 0x7e, 0xa1, 0x0c, 0xbf, 0x50, 0x86, 0x5f, 0x28, 0xc3, 0x2f, 0x94, 0xe1, 0x17, 0xca, 0xf0, 0x0b, 0x65, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x70, 0xe0, 0x17, 0x1c, 0xf8, 0x05, 0x07, 0x7e, 0xc1, 0x81, 0x5f, 0x70, 0xe0, 0x17, 0x9c, 0xf8, 0x05,\n\t0x27, 0x7e, 0xc1, 0x89, 0x5f, 0x70, 0xe2, 0x17, 0x9c, 0xf8, 0x05, 0x27, 0x7e, 0xc1, 0x89, 0x5f, 0x70, 0xe2, 0x17, 0x9c, 0xf8, 0x05, 0x27, 0x7e, 0xc1, 0x89, 0x5f, 0x70, 0xe2, 0x17, 0x9c, 0xf8, 0x05, 0x27, 0x7e, 0xc1, 0x89, 0x5f, 0x70, 0xe2, 0x17, 0x9c, 0xf8, 0x05, 0x27, 0x7e, 0xc1, 0x89, 0x5f, 0x70, 0xe2, 0x17, 0x9c, 0xf8, 0x05, 0x27, 0x7e, 0xc1, 0x89, 0x5f, 0x70, 0xe2, 0x17, 0xb2, 0xb5, 0xe7, 0xc1, 0x88, 0xb6, 0xf8, 0x83, 0x72, 0x2c, 0xe6, 0x34, 0x96, 0x52, 0x84, 0xa5, 0x7c, 0x83, 0xa5, 0x7c, 0x8a, 0xa5, 0x64, 0x60, 0x25, 0x67, 0xb1, 0x90, 0x6f, 0xb0, 0x90, 0x8f, 0xb1, 0x8c, 0xe3, 0x58, 0xc6, 0x15, 0x2c, 0xe3, 0x0c, 0x3e, 0xa1, 0x12, 0xab, 0xf8, 0x1a, 0x6b, 0x38, 0x8a, 0x35, 0x38, 0xb1, 0x86, 0xef, 0x50, 0xf8, 0x37, 0xf8, 0x81, 0x0a, 0x14, 0xfe, 0xb1, 0x4f, 0xae,\n\t0xb0, 0xa1, 0xd4, 0x4b, 0xa8, 0xf4, 0x12, 0x2a, 0xbd, 0x64, 0x8d, 0x17, 0x6d, 0x8d, 0x51, 0x75, 0x31, 0x9a, 0xe5, 0xc4, 0x28, 0x26, 0xeb, 0x6a, 0x8e, 0xdd, 0x25, 0x16, 0x58, 0xd7, 0x08, 0x9b, 0x75, 0x9d, 0xf0, 0xf7, 0x78, 0x56, 0xa1, 0xfd, 0x96, 0xd9, 0x4f, 0xd8, 0xe2, 0xcf, 0xd8, 0x5f, 0x06, 0xf6, 0x76, 0x5c, 0x9e, 0xa4, 0x15, 0xa7, 0x69, 0xc5, 0x39, 0x5a, 0x91, 0x8b, 0x77, 0xfa, 0x85, 0x96, 0x14, 0xd1, 0x92, 0x02, 0x5a, 0x92, 0x4b, 0x4b, 0x0a, 0x68, 0x49, 0x11, 0x2d, 0xc9, 0xa5, 0x15, 0x0e, 0x5a, 0x51, 0x40, 0x2b, 0xce, 0xd3, 0x8a, 0x5c, 0x5a, 0x61, 0xa2, 0x66, 0x1f, 0x6a, 0xf2, 0xa1, 0xa6, 0xa1, 0xd4, 0x64, 0x12, 0x5f, 0xe0, 0x1d, 0x4e, 0xd0, 0xd7, 0x9f, 0xf1, 0x0c, 0x19, 0xd4, 0xe4, 0xa4, 0xa6, 0xaf, 0xa8, 0xe9, 0x63, 0x6a, 0xca, 0xc4, 0x33, 0xe4, 0x53, 0x5b,\n\t0x3e, 0x9e, 0xa1, 0x90, 0x1a, 0x0f, 0x51, 0xe3, 0x3e, 0x3c, 0x43, 0x2e, 0x9e, 0xc1, 0x41, 0xad, 0x3f, 0x50, 0x6b, 0x35, 0xb5, 0x3a, 0xa8, 0xb5, 0x42, 0xfc, 0xca, 0x39, 0x67, 0x89, 0x0e, 0xce, 0x81, 0x43, 0x7e, 0x86, 0x87, 0xc8, 0xc0, 0x43, 0x1c, 0xa3, 0x25, 0xdf, 0x33, 0x26, 0xc5, 0xb4, 0xe6, 0x6b, 0x3c, 0xc4, 0x71, 0x72, 0x81, 0x52, 0xf2, 0x80, 0x52, 0xe2, 0xff, 0x4b, 0xc4, 0xff, 0x97, 0xf0, 0x06, 0x27, 0x68, 0xe5, 0x57, 0x78, 0x83, 0x63, 0xb4, 0xd4, 0x4d, 0x4b, 0xf7, 0x79, 0xbd, 0x2a, 0x0b, 0xbd, 0xfe, 0x0e, 0xaf, 0x71, 0xec, 0x0d, 0x78, 0x5b, 0x1e, 0xc3, 0x23, 0x5c, 0xc0, 0x23, 0x5c, 0xa0, 0x17, 0xed, 0xf1, 0x06, 0xc7, 0x7c, 0xae, 0x92, 0xb3, 0x56, 0xc9, 0x13, 0x78, 0x84, 0x13, 0x78, 0x84, 0x13, 0x78, 0x84, 0x13, 0x78, 0x84, 0x13, 0x8c, 0xf3, 0x79, 0x3c, 0xc2,\n\t0x09, 0xc6, 0xfa, 0x3c, 0x63, 0x7d, 0x1e, 0x8f, 0x70, 0x02, 0x8f, 0x70, 0x02, 0x6b, 0x3f, 0x86, 0xb5, 0x3b, 0xb0, 0xf6, 0x63, 0x58, 0xfb, 0x31, 0xac, 0xfd, 0x18, 0xd6, 0x7e, 0x0c, 0x6b, 0x27, 0x26, 0x87, 0x54, 0x48, 0x83, 0x95, 0xb0, 0x4a, 0x1e, 0xc3, 0xda, 0x33, 0xb0, 0xf6, 0x0c, 0xac, 0x3d, 0x03, 0x6b, 0xcf, 0xc0, 0xda, 0x33, 0xb0, 0xf6, 0x0c, 0xac, 0x3d, 0x03, 0x6b, 0xcf, 0xc0, 0xda, 0x33, 0xb0, 0xf6, 0x0c, 0xac, 0x3d, 0x03, 0x6b, 0xcf, 0xc0, 0xda, 0x33, 0xb0, 0xf6, 0x0c, 0xac, 0x3d, 0x03, 0x6b, 0xcf, 0xc0, 0xda, 0x33, 0xb0, 0xf6, 0x0c, 0xac, 0x3d, 0x03, 0x6b, 0xcf, 0xc0, 0xda, 0x33, 0xb0, 0xf6, 0x0c, 0xac, 0x3d, 0x03, 0x6b, 0xcf, 0xc0, 0xda, 0x33, 0xb0, 0xf6, 0x0c, 0xac, 0x3d, 0x1f, 0x6b, 0xcf, 0xc7, 0xda, 0xf3, 0xb1, 0xf6, 0x7c, 0xac, 0x3d, 0x1f, 0x6b, 0xcf,\n\t0xc7, 0xda, 0xf3, 0xb1, 0xf6, 0x7c, 0xac, 0x3d, 0x1f, 0x6b, 0x2f, 0xc4, 0xda, 0x0b, 0xb1, 0xf6, 0x42, 0xac, 0xbd, 0x10, 0x6b, 0x2f, 0xc4, 0xda, 0x0b, 0xb1, 0xf6, 0x42, 0xac, 0xbd, 0x10, 0x6b, 0x2f, 0xc4, 0xda, 0x0b, 0xb1, 0xf6, 0x42, 0xac, 0xbd, 0x10, 0x6b, 0x2f, 0xc4, 0xda, 0x0b, 0xb1, 0xf6, 0x42, 0xac, 0xbd, 0x10, 0x6b, 0x2f, 0xc4, 0xda, 0x0b, 0xb1, 0xf6, 0x42, 0xac, 0xbd, 0x10, 0x6b, 0x2f, 0xc4, 0xda, 0x0b, 0xb1, 0xf6, 0x42, 0xac, 0xbd, 0x10, 0x6b, 0xcf, 0x45, 0x19, 0x9d, 0xb0, 0xf6, 0x5c, 0x74, 0x59, 0x89, 0x2e, 0x73, 0xb1, 0xf6, 0x5c, 0xac, 0x3d, 0x17, 0x7d, 0x56, 0xa2, 0x4f, 0x33, 0xd6, 0x9e, 0x8b, 0x72, 0x3a, 0xa1, 0x9c, 0x48, 0x94, 0xd3, 0x1e, 0x6b, 0xcf, 0xc5, 0xda, 0x73, 0xd1, 0x6a, 0x20, 0x5a, 0x95, 0x68, 0x35, 0xd0, 0x7a, 0x2f, 0x65, 0x6d, 0x84, 0x4d,\n\t0xf4, 0x6b, 0x33, 0xdc, 0x07, 0xf7, 0xc3, 0x16, 0x78, 0x00, 0xd2, 0xe1, 0x41, 0xd8, 0x0a, 0x0f, 0xc1, 0xc3, 0xb0, 0x0d, 0xb6, 0xc3, 0x23, 0xf0, 0x28, 0x3c, 0x06, 0x8f, 0xc3, 0x13, 0xb0, 0x03, 0x76, 0xc9, 0xe3, 0x58, 0xfd, 0x71, 0xac, 0xfe, 0x38, 0x56, 0x7f, 0x1c, 0xab, 0x3f, 0x8e, 0xd5, 0x1f, 0xc7, 0xea, 0x8f, 0x63, 0xf5, 0xc7, 0xb1, 0xfa, 0xe3, 0x58, 0xfd, 0x71, 0xac, 0xfe, 0x38, 0x56, 0x7f, 0x1c, 0xab, 0x3f, 0x8e, 0xd5, 0x1f, 0xc7, 0xea, 0x8f, 0x63, 0xf5, 0xc7, 0xb1, 0xfa, 0xe3, 0x58, 0xfd, 0x71, 0xac, 0xfe, 0x38, 0x56, 0x7f, 0x1c, 0xab, 0x3f, 0x8e, 0xd5, 0x1f, 0xc7, 0xea, 0x8f, 0x63, 0xf5, 0xc7, 0xb1, 0xfa, 0x13, 0xc4, 0xd0, 0x97, 0xfc, 0x1e, 0x63, 0xb5, 0x5b, 0x45, 0x44, 0x90, 0x4b, 0x44, 0x90, 0x85, 0x07, 0xc8, 0x24, 0x22, 0x38, 0x86, 0x45, 0x54, 0x60, 0x09,\n\t0x97, 0xb0, 0x84, 0x4a, 0x2c, 0xa1, 0x12, 0xf5, 0xbb, 0xb1, 0xb9, 0x67, 0xb0, 0x80, 0x4b, 0xa8, 0xff, 0x12, 0xea, 0xbf, 0x64, 0xa8, 0xbf, 0x04, 0xc5, 0xbb, 0x51, 0xb9, 0x9b, 0xa8, 0xe0, 0x08, 0x19, 0xf0, 0x11, 0x32, 0xe0, 0x23, 0x64, 0xc0, 0x39, 0x64, 0xc0, 0x39, 0xda, 0xa7, 0xbd, 0x8d, 0xa7, 0x38, 0x69, 0x51, 0x42, 0x36, 0x4a, 0x2f, 0x46, 0xe5, 0x25, 0xa8, 0xbc, 0xf6, 0x7b, 0x86, 0x3f, 0x12, 0x29, 0xe4, 0xb0, 0xd6, 0xb9, 0x51, 0x76, 0x25, 0x11, 0x43, 0x16, 0x11, 0x43, 0x16, 0x11, 0x43, 0x56, 0x9d, 0x88, 0x21, 0x8b, 0x88, 0x21, 0xab, 0x4e, 0xc4, 0x90, 0x45, 0xc4, 0x90, 0x45, 0xc4, 0x90, 0x45, 0xc4, 0x90, 0x45, 0xc4, 0x90, 0x45, 0xc4, 0x90, 0x45, 0xc4, 0x90, 0x55, 0x27, 0x62, 0xc8, 0x22, 0x62, 0xc8, 0xaa, 0x13, 0x31, 0x64, 0xb1, 0x36, 0x7e, 0x4e, 0xc4, 0xf0, 0x19,\n\t0xeb, 0xe3, 0x3f, 0xf4, 0xa8, 0x61, 0x13, 0xdb, 0xba, 0x91, 0xc3, 0x76, 0x5e, 0x3f, 0x02, 0x3b, 0x64, 0x0e, 0x16, 0x73, 0x09, 0x85, 0x56, 0xa2, 0xd0, 0x4a, 0x14, 0x5a, 0x89, 0x42, 0x2b, 0x51, 0x68, 0x25, 0x0a, 0xad, 0x44, 0xa1, 0x95, 0x28, 0xb4, 0x12, 0x85, 0x56, 0xa2, 0x20, 0x37, 0xeb, 0x85, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x9b, 0xf5, 0xc2, 0x8d, 0x82, 0xdc, 0xac, 0x17, 0x6e, 0xd6, 0x0b, 0x37, 0xeb, 0x85, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x9b, 0xf5, 0xc2, 0x8d, 0x82, 0xdc, 0xac, 0x17, 0x6e, 0x14, 0x54, 0x82, 0x82, 0x4a, 0x50, 0x90, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x1b, 0x05, 0xb9, 0x51, 0x90,\n\t0x1b, 0x05, 0xb9, 0x51, 0x90, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x1b, 0x05, 0xb9, 0x51, 0x90, 0x9b, 0x99, 0xad, 0x14, 0x9f, 0x30, 0xb3, 0x7b, 0x99, 0xd9, 0x9d, 0xe2, 0x47, 0x7c, 0xf6, 0x31, 0x79, 0x98, 0x99, 0x3d, 0x87, 0xaf, 0xd3, 0x3c, 0xea, 0x21, 0x66, 0x37, 0x4b, 0xf7, 0x73, 0xd9, 0xf8, 0xa9, 0x1c, 0x62, 0xbe, 0x13, 0x78, 0xd1, 0x93, 0xf8, 0xc5, 0x53, 0xf8, 0xfb, 0xd3, 0xe0, 0x99, 0xe1, 0x8f, 0xf0, 0x6f, 0x47, 0xf0, 0x6f, 0x47, 0x98, 0xe9, 0x22, 0x7c, 0xdb, 0x11, 0x7c, 0xdb, 0x21, 0x66, 0xbc, 0x18, 0xbf, 0x96, 0xc9, 0xac, 0xdf, 0xce, 0xac, 0x4f, 0x62, 0xd6, 0x27, 0x31, 0xeb, 0xf3, 0x98, 0xf5, 0x79, 0xcc, 0xfa, 0xdf, 0xf1, 0x73, 0x4e, 0xfc, 0x9c, 0x13, 0x1f, 0xe7, 0xc0, 0xc7, 0x1d, 0x61, 0xe6, 0x2b, 0xf1, 0x71, 0x55, 0xcc, 0xfe, 0x47, 0xcc, 0xfe, 0x47, 0xf8, 0xb8,\n\t0x23, 0xf8, 0xb8, 0x23, 0xf8, 0xb8, 0x23, 0x44, 0x3f, 0x65, 0x44, 0x3f, 0x65, 0x86, 0x8f, 0x3b, 0x82, 0x0a, 0x76, 0xa2, 0x82, 0x9d, 0xa8, 0x60, 0x27, 0x2a, 0xc8, 0x46, 0x05, 0xd9, 0xa8, 0x60, 0x27, 0x2a, 0xd8, 0x89, 0x0a, 0xb2, 0x51, 0x41, 0x36, 0x2a, 0xd8, 0x89, 0x0a, 0x76, 0xa2, 0x82, 0x9d, 0xa8, 0x60, 0x27, 0x2a, 0xd8, 0x89, 0x0a, 0x76, 0xa2, 0x82, 0x9d, 0xa8, 0x20, 0x1b, 0x15, 0x64, 0xa3, 0x82, 0x9d, 0xa8, 0x60, 0x27, 0x2a, 0xc8, 0x46, 0x05, 0xd9, 0xa8, 0x60, 0x27, 0xfe, 0xf0, 0x08, 0xb3, 0x7b, 0x16, 0x7f, 0x78, 0x04, 0x7f, 0x78, 0x04, 0x7f, 0x78, 0x04, 0x7f, 0x78, 0x04, 0x7f, 0x78, 0x04, 0x7f, 0x78, 0x04, 0x7f, 0x78, 0x04, 0x7f, 0x78, 0x04, 0x7f, 0x78, 0x04, 0x7f, 0x78, 0xc4, 0xda, 0x42, 0x5e, 0xb1, 0x06, 0x83, 0x0d, 0xda, 0x41, 0x7b, 0xe8, 0x00, 0x1d, 0xa1,\n\t0x2b, 0xf4, 0x94, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0xf1, 0x97, 0x87, 0x51, 0x63, 0x16, 0x6a, 0xcc, 0x42, 0x8d, 0x59, 0xa8, 0x31, 0x0b, 0x35, 0x66, 0xa1, 0xc6, 0x2c, 0xd4, 0x98, 0x85, 0x1a, 0xb3, 0x50, 0x63, 0x16, 0x6a, 0x2c, 0x30, 0xfc, 0x59, 0x81, 0xe1, 0xcf, 0x0a, 0x50, 0x63, 0x01, 0x6a, 0x2c, 0xa8, 0xe3, 0xcf, 0x0a, 0x0c, 0x7f, 0x16, 0x67, 0xf8, 0xb3, 0x02, 0xd4,\n\t0x58, 0xe0, 0xf1, 0x67, 0xbc, 0x7f, 0x8f, 0x50, 0x51, 0xe3, 0x47, 0xa8, 0xf1, 0x23, 0xd4, 0x58, 0x84, 0x1a, 0x8b, 0x50, 0x63, 0x11, 0x6a, 0x2c, 0x42, 0x8d, 0x45, 0xa8, 0xb1, 0x08, 0x35, 0x16, 0xa1, 0xc6, 0x22, 0xd4, 0x58, 0x84, 0x1a, 0x8b, 0x50, 0x63, 0x11, 0x6a, 0x2c, 0x42, 0x8d, 0x45, 0xa8, 0xb1, 0x08, 0x35, 0x16, 0xa1, 0xc6, 0x22, 0xd4, 0x58, 0x84, 0x1a, 0x8b, 0x50, 0x63, 0x11, 0xfe, 0x2c, 0x13, 0x7f, 0x96, 0x89, 0x3f, 0xcb, 0xc4, 0x9f, 0x65, 0xe2, 0xcf, 0x32, 0xf1, 0x67, 0x99, 0xf8, 0xb3, 0x4c, 0xfc, 0x59, 0x26, 0xfe, 0x2c, 0x13, 0x7f, 0x96, 0x89, 0x3f, 0xcb, 0xc4, 0x9f, 0x65, 0xe2, 0xcf, 0x32, 0xf1, 0x67, 0x99, 0xf8, 0xb3, 0x4c, 0xfc, 0x59, 0x26, 0xfe, 0x2c, 0x13, 0x7f, 0x96, 0x89, 0x3f, 0xcb, 0xc4, 0x9f, 0x65, 0xe2, 0xcf, 0x32, 0xf1, 0x67, 0x99, 0xf8, 0xb3,\n\t0x4c, 0xfc, 0x59, 0x26, 0xbe, 0xcc, 0x49, 0x14, 0x73, 0x49, 0x3c, 0x8f, 0xe2, 0xdd, 0xf8, 0xb1, 0x2a, 0xe2, 0xfe, 0xab, 0x28, 0xbe, 0x14, 0xc5, 0x57, 0xa1, 0xf8, 0x0b, 0xac, 0xee, 0xe5, 0xa8, 0xfe, 0x3c, 0xaa, 0xaf, 0xd2, 0xef, 0x05, 0x64, 0xb3, 0x9f, 0xc3, 0x39, 0x5a, 0xcc, 0x7f, 0x92, 0xfd, 0x53, 0xec, 0x13, 0x73, 0xe3, 0xdf, 0xce, 0xa3, 0xfe, 0x0b, 0x28, 0xbf, 0x0c, 0xe5, 0x5f, 0x44, 0xf9, 0x17, 0x51, 0x7e, 0x09, 0xca, 0xbf, 0x88, 0xf2, 0x2f, 0xa0, 0xfc, 0xf3, 0x28, 0xbf, 0xd4, 0xf8, 0xab, 0x53, 0x09, 0x0a, 0xbf, 0x80, 0xc2, 0x2f, 0xa2, 0xf0, 0xab, 0x28, 0xfc, 0x2a, 0x0a, 0x2f, 0x43, 0xe1, 0x65, 0x28, 0xfc, 0x22, 0x0a, 0xbf, 0x88, 0xc2, 0x2f, 0x1a, 0xb1, 0xfc, 0x45, 0x6d, 0xf5, 0xc6, 0x0f, 0x7d, 0x86, 0x1f, 0xaa, 0x36, 0xfc, 0x90, 0xd3, 0xf0, 0x43, 0x4e, 0xfc,\n\t0x90, 0x13, 0x3f, 0xe4, 0xbc, 0xee, 0x87, 0xbe, 0x96, 0x17, 0x55, 0xed, 0xdb, 0xcf, 0x0b, 0xd8, 0x2e, 0x84, 0x24, 0x48, 0x86, 0x15, 0x90, 0x02, 0xa9, 0x90, 0x06, 0x2b, 0x61, 0x95, 0xbc, 0x88, 0x12, 0x4b, 0x51, 0x62, 0x29, 0x4a, 0x2c, 0x45, 0x89, 0xa5, 0x28, 0xb1, 0x14, 0x25, 0x96, 0xa2, 0xc4, 0x52, 0x94, 0x58, 0x8a, 0x12, 0x4b, 0x51, 0x62, 0x29, 0x4a, 0x2c, 0x45, 0x89, 0xa5, 0x28, 0xb1, 0x14, 0x25, 0x96, 0xa2, 0xc4, 0x52, 0x94, 0x58, 0x8a, 0x12, 0x4b, 0x51, 0x62, 0x29, 0x4a, 0x2c, 0x45, 0x89, 0xa5, 0x28, 0xb1, 0x14, 0x25, 0x96, 0xa2, 0xc4, 0x52, 0x94, 0x58, 0x8a, 0x12, 0x4b, 0x51, 0x62, 0x29, 0x4a, 0xac, 0x42, 0x89, 0x55, 0x28, 0xb1, 0x0a, 0x25, 0x56, 0xa1, 0xc4, 0x2a, 0x94, 0x58, 0x85, 0x12, 0xab, 0x50, 0x62, 0x15, 0x4a, 0xac, 0xfa, 0x8b, 0x71, 0xf4, 0xd5, 0x3f,\n\t0x8c, 0xa3, 0xef, 0x85, 0x8d, 0x7a, 0x3c, 0x5d, 0x82, 0x12, 0x4b, 0x50, 0x62, 0x09, 0x4a, 0x2c, 0x41, 0x89, 0x25, 0x28, 0xb1, 0x04, 0x25, 0x96, 0xa0, 0xc4, 0x12, 0x94, 0x58, 0x82, 0x12, 0x4b, 0x50, 0x62, 0x09, 0x4a, 0x2c, 0x41, 0x89, 0x25, 0x28, 0xb1, 0x04, 0x25, 0x96, 0xa0, 0xc4, 0x12, 0x94, 0x58, 0x82, 0x12, 0x4b, 0x50, 0x62, 0x09, 0x4a, 0x2c, 0x45, 0x89, 0xa5, 0x28, 0xb1, 0x14, 0x25, 0x96, 0xa2, 0xc4, 0x52, 0x94, 0x58, 0x8a, 0x12, 0x4b, 0x51, 0x62, 0x29, 0x4a, 0x2c, 0x45, 0x89, 0xa5, 0x28, 0xb1, 0x14, 0x25, 0x96, 0xa2, 0xc4, 0x52, 0x94, 0x58, 0x8a, 0x12, 0x4b, 0x51, 0x62, 0x29, 0x4a, 0x2c, 0x45, 0x89, 0xa5, 0x28, 0xb1, 0x14, 0x25, 0x96, 0xa2, 0xc4, 0x52, 0x94, 0x58, 0x8a, 0x12, 0x4b, 0x51, 0x62, 0xa9, 0xbe, 0xa2, 0xfa, 0xa3, 0xb6, 0x32, 0x14, 0x76, 0x59, 0x57,\n\t0x58, 0x2e, 0x9e, 0xf8, 0xb4, 0xbc, 0x46, 0x7c, 0x78, 0x19, 0xf5, 0x5c, 0x53, 0xc2, 0x58, 0x19, 0x89, 0xa5, 0xf4, 0xbf, 0x1e, 0x7b, 0xee, 0x7f, 0x7f, 0x4f, 0xa6, 0x98, 0xab, 0xa9, 0x87, 0xc8, 0x37, 0x83, 0xf5, 0x37, 0x07, 0x9d, 0x9d, 0x24, 0x4b, 0xcf, 0x95, 0xbf, 0xe2, 0x85, 0x2f, 0x72, 0xe5, 0x09, 0xa2, 0xc9, 0xc3, 0xfa, 0xe7, 0x8e, 0x3c, 0x59, 0xb7, 0xf6, 0x54, 0xc4, 0x9f, 0xd0, 0x5c, 0x29, 0x57, 0x5d, 0x40, 0x57, 0x85, 0x58, 0x74, 0x2f, 0xea, 0x2e, 0x14, 0x01, 0x94, 0xf0, 0x2d, 0x25, 0x68, 0x2b, 0x76, 0x26, 0x25, 0x9c, 0xa3, 0x84, 0x22, 0x4a, 0xc8, 0xd0, 0x4b, 0xf0, 0xfc, 0xcd, 0xe0, 0xb8, 0x76, 0xa7, 0x9e, 0xab, 0x2f, 0x72, 0xb5, 0x1b, 0xbf, 0x6b, 0x31, 0x4a, 0x18, 0x85, 0x4f, 0xb0, 0xe8, 0xa5, 0xd8, 0xb1, 0x1d, 0x27, 0xf6, 0xf2, 0xeb, 0xf5, 0x3c, 0xf9, 0xa4,\n\t0x7c, 0x1e, 0xdb, 0x28, 0xa7, 0x27, 0x65, 0xd8, 0x46, 0x11, 0xb6, 0x51, 0x8c, 0x6d, 0x14, 0x63, 0x17, 0xc5, 0xd8, 0x45, 0xa1, 0x7e, 0x6f, 0xac, 0xbf, 0x7c, 0x9f, 0xd5, 0xe0, 0x43, 0x56, 0x83, 0x0f, 0x59, 0x0d, 0xde, 0x61, 0x35, 0xd0, 0xbe, 0x51, 0xf3, 0x21, 0xb5, 0x1e, 0xaf, 0xfd, 0xdb, 0x06, 0xb6, 0xa2, 0xc5, 0x00, 0x45, 0xd8, 0x48, 0x11, 0x36, 0x52, 0x8c, 0x8d, 0x14, 0x63, 0x23, 0xc5, 0xd8, 0x47, 0x31, 0x9a, 0x2f, 0x46, 0xef, 0xc5, 0xe8, 0xbd, 0x18, 0xbd, 0x17, 0xa3, 0xf7, 0x62, 0xf4, 0x5e, 0x8c, 0xde, 0x8b, 0xd1, 0x7b, 0x31, 0x7a, 0x2f, 0x46, 0xef, 0xc5, 0xe8, 0xbd, 0x18, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b,\n\t0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0x13, 0xbd, 0x3b, 0xd1, 0xbb, 0xf3, 0x4f, 0xe5, 0xa5, 0xf7, 0xe2, 0xe1, 0x36, 0xea, 0x5e, 0xee, 0xff, 0xea, 0x3d, 0x1c, 0x11, 0xca, 0xdc, 0xbe, 0x43, 0x5e, 0x52, 0xa1, 0xaf, 0xd7, 0x27, 0x65, 0x0e, 0xf3, 0xfb, 0xb3, 0x91, 0xfd, 0x1c, 0x64, 0x7e, 0x0f, 0xa2, 0xad, 0x52, 0xb4, 0x55, 0xaa, 0x0c, 0x21, 0xf2, 0x1a, 0x06, 0xe3, 0xe5, 0x79, 0x46, 0xbf, 0x94, 0xd1, 0xcf, 0x60, 0xf4, 0xcf, 0xa3, 0xb3, 0x6f, 0x95, 0x85, 0xb2, 0x52, 0x59, 0xc4, 0x7a, 0xbc, 0x5f, 0xbf, 0x33, 0x59, 0xc5, 0xdc, 0x17, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b,\n\t0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x10, 0x6b, 0x57, 0x18, 0xea, 0x2c, 0x10, 0x41, 0xf8, 0xe2, 0x4a, 0x7a, 0xe1, 0x42, 0x5b, 0x4e, 0x74, 0x55, 0xac, 0xdf, 0x6d, 0xd2, 0xac, 0xe4, 0x24, 0xd6, 0x91, 0x0b, 0xb5, 0x77, 0x9c, 0x0a, 0x65, 0x81, 0xf1, 0x69, 0x3a, 0xed, 0xf3, 0x76, 0x9f, 0xd7, 0xf9, 0x86, 0x8d, 0x66, 0x2d, 0x15, 0xf8, 0xdd, 0x4a, 0xdd, 0x62, 0x5e, 0x46, 0xa9, 0x59, 0x94, 0xfa, 0x1d, 0xa5, 0xbe, 0x4d, 0xa9, 0xa7, 0x75, 0xc5, 0xfe, 0x42, 0x8e, 0xe6, 0xc9, 0xdd, 0xde, 0xc4, 0xc3, 0x5f, 0xa1, 0xe4, 0xcf,\n\t0x28, 0xf5, 0x1c, 0xaa, 0x3d, 0x84, 0x6a, 0x0f, 0x31, 0x5e, 0x6f, 0xe2, 0xd5, 0xf3, 0x50, 0xef, 0x21, 0x6a, 0xfa, 0x0c, 0xbb, 0x3c, 0x8c, 0x82, 0x73, 0xc8, 0xd3, 0x9e, 0x55, 0x50, 0x02, 0xb9, 0xda, 0xb3, 0x0a, 0x4a, 0x50, 0xc6, 0x08, 0x3f, 0x62, 0x99, 0x47, 0x89, 0x65, 0x1e, 0x55, 0x66, 0x8b, 0xfa, 0xd4, 0xfa, 0x1d, 0x0a, 0x3e, 0x44, 0xcd, 0x6f, 0xa2, 0xde, 0x43, 0xa8, 0xf7, 0x10, 0xea, 0x3d, 0x84, 0x0d, 0xa5, 0xa0, 0xe0, 0x43, 0x28, 0xf8, 0x10, 0x0a, 0x3e, 0x84, 0x82, 0x0f, 0xa1, 0xe0, 0x43, 0x28, 0xf8, 0x10, 0x0a, 0x3e, 0x84, 0x82, 0x0f, 0xa1, 0xe0, 0x43, 0x28, 0xf8, 0x10, 0x0a, 0x3e, 0x84, 0x82, 0x0f, 0xa1, 0xe0, 0x2c, 0x14, 0x9c, 0x85, 0x82, 0xb3, 0x50, 0x70, 0x16, 0x0a, 0xce, 0x42, 0xc1, 0x59, 0x28, 0x38, 0x0b, 0x05, 0x67, 0xa1, 0xe0, 0x2c, 0x14, 0x9c, 0x85,\n\t0x82, 0xb3, 0x50, 0x70, 0x16, 0x0a, 0xce, 0x42, 0xc1, 0x59, 0x28, 0x38, 0x0b, 0x05, 0x67, 0xa1, 0xe0, 0x2c, 0x14, 0x9c, 0x85, 0x82, 0xb3, 0x50, 0x70, 0x16, 0x0a, 0xce, 0x42, 0xc1, 0x59, 0x28, 0x38, 0x0b, 0x05, 0x67, 0xa1, 0xe0, 0x2c, 0x14, 0x9c, 0xf5, 0x27, 0xef, 0xac, 0x54, 0x33, 0xff, 0xd5, 0xcc, 0x7f, 0x35, 0xf3, 0x5f, 0xcd, 0xfc, 0x57, 0x33, 0xff, 0xd5, 0xcc, 0x7f, 0x35, 0xf3, 0x5f, 0xcd, 0xfc, 0x57, 0x33, 0xff, 0xd5, 0xcc, 0x7f, 0x35, 0xf3, 0x5f, 0xcd, 0xfc, 0x57, 0x33, 0xff, 0xd5, 0xcc, 0x7f, 0x35, 0xf3, 0x5f, 0xcd, 0xfc, 0x57, 0x33, 0xff, 0xd5, 0xcc, 0x7f, 0x35, 0xf3, 0x5f, 0xcd, 0xfc, 0x57, 0x33, 0xff, 0xd5, 0xcc, 0x7f, 0x35, 0xf3, 0x5f, 0xcd, 0x8a, 0x70, 0x85, 0xd8, 0x64, 0x09, 0x2b, 0xc2, 0x15, 0x6b, 0xb2, 0x08, 0xb7, 0xae, 0x10, 0xd3, 0x58, 0x11, 0xae,\n\t0xb0, 0x22, 0x5c, 0xb1, 0xa6, 0x89, 0x31, 0xc4, 0x26, 0x73, 0x59, 0x11, 0xae, 0x10, 0x9b, 0x2c, 0x41, 0x2b, 0xff, 0xc2, 0x0f, 0xa5, 0xb0, 0x22, 0x5c, 0x61, 0x45, 0xb8, 0x42, 0x6c, 0x32, 0x9d, 0xd8, 0x64, 0x16, 0xb1, 0xc9, 0x52, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0x56, 0x82, 0x3c, 0xac, 0x35, 0x07, 0x6b, 0xcd, 0xc1, 0x5a, 0x73, 0xb0, 0xd6, 0x1c, 0xac, 0x35, 0x07, 0x6b, 0xcd, 0xc1, 0x5a, 0x73, 0xb0, 0xd6, 0x1c, 0xac, 0x35, 0x07, 0x6b, 0xcd, 0xc1, 0x5a, 0x73, 0xb0, 0xd6, 0x1c, 0xac,\n\t0x35, 0x07, 0x6b, 0xcd, 0xc1, 0x5a, 0x73, 0xb0, 0xd6, 0x1c, 0xac, 0x35, 0x07, 0x6b, 0xcd, 0xc1, 0x5a, 0x73, 0xb0, 0xd6, 0x1c, 0xac, 0x35, 0x07, 0x6b, 0xcd, 0xc1, 0x5a, 0x73, 0xb0, 0xd6, 0x1c, 0x62, 0x92, 0x47, 0x85, 0x05, 0x55, 0x9e, 0x42, 0x7d, 0x4e, 0x14, 0x57, 0x88, 0x85, 0x5e, 0x34, 0x3e, 0x9b, 0xf5, 0xa3, 0xfe, 0xd9, 0xac, 0xd9, 0x78, 0x68, 0x33, 0xca, 0xff, 0x18, 0x2f, 0xf9, 0x2b, 0x47, 0x0a, 0x51, 0xf9, 0x2f, 0x46, 0xb6, 0x74, 0x9c, 0x71, 0x68, 0x2d, 0x62, 0x51, 0x77, 0x3e, 0xaa, 0xce, 0x31, 0xfc, 0xf0, 0x69, 0xce, 0x7e, 0xee, 0x7a, 0x0e, 0xf6, 0xab, 0x3c, 0x83, 0xa2, 0x0b, 0x50, 0x74, 0x01, 0x4a, 0x2e, 0x40, 0xc9, 0xe7, 0x50, 0x71, 0x25, 0x7e, 0xf8, 0x1b, 0xfc, 0xf0, 0x61, 0xfc, 0xf0, 0xe1, 0xeb, 0x4f, 0x7a, 0x1a, 0xa1, 0xab, 0x1a, 0x45, 0xcb, 0x0f, 0xf4,\n\t0xd8, 0xc5, 0xf3, 0xd7, 0xd7, 0x5a, 0x9f, 0x5c, 0x80, 0x4f, 0x3e, 0x83, 0x4f, 0x3e, 0x83, 0xaa, 0x0b, 0x50, 0x75, 0x01, 0xaa, 0x2e, 0x40, 0xd1, 0x05, 0x28, 0xba, 0x00, 0x45, 0x17, 0xa0, 0xe8, 0x02, 0x14, 0x5d, 0x80, 0xa2, 0x0b, 0x50, 0x74, 0x01, 0x8a, 0x2e, 0x40, 0xd1, 0x05, 0x28, 0xba, 0x00, 0x45, 0x17, 0xa8, 0x5a, 0x64, 0xd9, 0x93, 0xac, 0x3d, 0x14, 0x7a, 0x41, 0x6f, 0xe8, 0x03, 0x7d, 0x21, 0x0c, 0xfa, 0x41, 0x7f, 0x18, 0x00, 0x03, 0x21, 0x1c, 0x06, 0xc1, 0x60, 0xc0, 0x5b, 0xa1, 0xe8, 0x7c, 0x14, 0x9d, 0x8f, 0xa2, 0xf3, 0x51, 0x74, 0x3e, 0x8a, 0xce, 0x47, 0xd1, 0xf9, 0x28, 0x3a, 0x1f, 0x45, 0xe7, 0xa3, 0xe8, 0x7c, 0x14, 0x9d, 0x8f, 0xa2, 0xf3, 0xff, 0xa4, 0x4f, 0x3e, 0x83, 0x4f, 0x3e, 0xc3, 0x2c, 0x57, 0x32, 0xcb, 0x95, 0xcc, 0x72, 0x25, 0xb3, 0x5c, 0xc9, 0x2c,\n\t0x57, 0x32, 0xcb, 0x95, 0xcc, 0x72, 0x25, 0xb3, 0x5c, 0xc9, 0x2c, 0xff, 0x2f, 0xee, 0xee, 0x03, 0xbe, 0xa9, 0xba, 0xff, 0xfb, 0xff, 0x37, 0x27, 0x2d, 0x39, 0x27, 0x75, 0x31, 0xc4, 0xc5, 0x90, 0x21, 0x32, 0x04, 0x04, 0x71, 0x82, 0xca, 0x12, 0x15, 0xd9, 0x4b, 0x50, 0x04, 0xdc, 0x28, 0x8a, 0x38, 0x58, 0x0a, 0x88, 0xc8, 0x12, 0x04, 0x2a, 0x22, 0x7b, 0x8f, 0xb6, 0x4c, 0x15, 0x90, 0x55, 0xca, 0x6a, 0xe9, 0x4a, 0x9b, 0xae, 0xb4, 0xa5, 0x05, 0x52, 0x04, 0x12, 0xda, 0x92, 0x6e, 0x4a, 0x0b, 0x04, 0x3f, 0xf7, 0x2b, 0x69, 0x2f, 0xe5, 0xfa, 0x5d, 0xd7, 0x7d, 0xdd, 0xd7, 0x7d, 0xff, 0x7f, 0xf7, 0xf5, 0x7f, 0xfc, 0xff, 0x0f, 0x1f, 0x4f, 0xcf, 0x49, 0x9a, 0x9c, 0x9c, 0x7c, 0xf7, 0x3b, 0x09, 0x49, 0x39, 0xb5, 0x5c, 0x4e, 0x2d, 0x97, 0x53, 0xcb, 0xe5, 0xd4, 0x72, 0x39, 0xb5, 0x5c,\n\t0x4e, 0x2d, 0x97, 0x53, 0xcb, 0xe5, 0xd4, 0x72, 0x39, 0xb5, 0x5c, 0x4e, 0x2d, 0x97, 0x53, 0xcb, 0xe5, 0xd4, 0x72, 0x39, 0xb5, 0x5c, 0x4e, 0x2d, 0x97, 0x53, 0xcb, 0xe5, 0x6a, 0x35, 0x35, 0xe4, 0x61, 0xfc, 0x39, 0x43, 0x4d, 0x4f, 0xa7, 0xa6, 0x0a, 0xa8, 0xa9, 0xca, 0xea, 0x57, 0x96, 0x2b, 0x18, 0x83, 0x12, 0x18, 0x83, 0x8e, 0xd2, 0x02, 0x56, 0x53, 0x6b, 0x39, 0xd4, 0xda, 0x39, 0x6a, 0x2c, 0x97, 0x1a, 0xcb, 0xa5, 0x45, 0xac, 0xad, 0x7e, 0x97, 0x29, 0xb7, 0xfa, 0x15, 0x65, 0xdf, 0xeb, 0x45, 0x19, 0xd4, 0x60, 0x51, 0xf5, 0xbf, 0x54, 0x8c, 0x64, 0x1c, 0x5f, 0xc4, 0x38, 0xbe, 0x88, 0xda, 0x4b, 0xa0, 0xf6, 0x7c, 0xef, 0xb4, 0x8f, 0x63, 0x3c, 0x3a, 0xc9, 0x78, 0x74, 0x92, 0xda, 0x4b, 0xf6, 0xbf, 0x77, 0x3e, 0x44, 0xe6, 0x33, 0xa6, 0x2f, 0x62, 0x4c, 0x5f, 0xc4, 0xf8, 0x74,\n\t0x86, 0xda, 0xcc, 0x65, 0x7c, 0x3a, 0x4a, 0x4d, 0xe6, 0x52, 0x93, 0xb9, 0xd4, 0x64, 0x2e, 0x35, 0x99, 0x4b, 0x4d, 0xe6, 0x52, 0x93, 0xb9, 0xd4, 0x64, 0x2e, 0x35, 0x99, 0x4b, 0x4d, 0xe6, 0x52, 0x93, 0xb9, 0xd4, 0x64, 0x2e, 0x35, 0x99, 0x4b, 0x4d, 0xe6, 0x52, 0x93, 0xb9, 0xd4, 0x64, 0x2e, 0x35, 0xe9, 0xa1, 0x26, 0x3d, 0xd4, 0xa4, 0x87, 0x9a, 0xf4, 0x50, 0x93, 0x1e, 0x6a, 0xd2, 0x43, 0x4d, 0x7a, 0xa8, 0x49, 0x0f, 0x35, 0xe9, 0xa1, 0x26, 0x3d, 0xd4, 0xa4, 0x87, 0x9a, 0xf4, 0x50, 0x93, 0x1e, 0x6a, 0xd2, 0x43, 0x4d, 0x7a, 0xa8, 0x49, 0x0f, 0x35, 0xe9, 0xa1, 0x26, 0x3d, 0xd4, 0xa4, 0x87, 0x9a, 0xf4, 0x50, 0x93, 0x1e, 0x6a, 0xd2, 0x43, 0x4d, 0x7a, 0xa8, 0x49, 0x0f, 0x35, 0xe9, 0xa1, 0x26, 0x3d, 0xd4, 0x64, 0x25, 0x35, 0x59, 0x49, 0x4d, 0x56, 0x52, 0x93, 0x95, 0xd4, 0x64,\n\t0x25, 0x35, 0x59, 0x49, 0x4d, 0x56, 0x52, 0x93, 0x95, 0xd4, 0x64, 0x25, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0x05, 0x63, 0x53, 0xc5, 0x7f, 0xf3, 0xbb, 0x38, 0x45, 0xb4, 0xb6, 0x22, 0x5a, 0x5b, 0x11, 0xad, 0xad, 0x88, 0xd6, 0x56, 0x44, 0x6b, 0x2b, 0xa2, 0xb5, 0x15, 0xd1, 0xda, 0x8a, 0x68, 0x6d, 0x45, 0xb4, 0xb6, 0x22, 0x5a, 0x5b, 0x11, 0xad, 0xad, 0x88, 0xd6, 0x56, 0x44, 0x6b, 0x2b, 0xa2, 0xb5, 0x15,\n\t0xd1, 0xda, 0x8a, 0x68, 0x6d, 0x45, 0xb4, 0xb6, 0x22, 0x5a, 0x5b, 0x11, 0xad, 0xad, 0x88, 0xd6, 0x56, 0x44, 0x6b, 0x2b, 0xa2, 0xb5, 0x15, 0xd1, 0xda, 0x8a, 0x18, 0x53, 0x4e, 0xfa, 0xe7, 0xd0, 0x4a, 0x5a, 0x9b, 0x93, 0xd6, 0x76, 0x9d, 0x96, 0x76, 0x95, 0x56, 0x56, 0xe1, 0x5f, 0x33, 0x3a, 0x69, 0x61, 0x55, 0x6b, 0xb4, 0x32, 0x5a, 0xd7, 0x39, 0x5a, 0x95, 0x6f, 0xc5, 0x59, 0x41, 0x6b, 0x72, 0x54, 0x7f, 0x0a, 0x72, 0x29, 0xad, 0x26, 0x9e, 0x56, 0x63, 0xa3, 0xd5, 0x24, 0xd1, 0x5a, 0x7c, 0x99, 0xa5, 0x40, 0xf5, 0xa2, 0x0d, 0x17, 0x70, 0x34, 0x17, 0x6d, 0xb7, 0x8c, 0x23, 0xe6, 0x32, 0xca, 0x6c, 0xe1, 0x48, 0x57, 0x38, 0x52, 0x29, 0xa3, 0xcc, 0xe5, 0x3f, 0x93, 0x50, 0x55, 0x0a, 0xba, 0xcc, 0x08, 0x73, 0xd8, 0xe4, 0xfb, 0xcc, 0x62, 0x47, 0x74, 0x96, 0x83, 0x8c, 0x30, 0x07,\n\t0xab, 0x57, 0x7a, 0xbe, 0x4f, 0x98, 0xc4, 0xf2, 0x08, 0x49, 0xfe, 0x54, 0xb4, 0x8d, 0xd5, 0xdd, 0x76, 0xdc, 0x9a, 0x86, 0x48, 0x42, 0xfe, 0x74, 0xf3, 0xef, 0x27, 0x9b, 0x02, 0xda, 0x62, 0x01, 0x6d, 0xb1, 0x80, 0xb6, 0x58, 0x40, 0x5b, 0x2c, 0xa0, 0x2d, 0x16, 0xd0, 0x16, 0x0b, 0x68, 0x8b, 0x05, 0xb4, 0xc5, 0x02, 0xda, 0x62, 0x01, 0x6d, 0xb1, 0x80, 0xb6, 0x58, 0x40, 0x5b, 0x2c, 0xa0, 0x2d, 0x16, 0xd0, 0x16, 0x0b, 0x68, 0x8b, 0x05, 0xb4, 0xc5, 0x02, 0xda, 0x62, 0x01, 0x6d, 0xb1, 0x80, 0xb6, 0x58, 0x40, 0x5b, 0x2c, 0xa0, 0x2d, 0x16, 0xd0, 0x16, 0x0b, 0x68, 0x8b, 0x05, 0xb4, 0xc5, 0x02, 0xda, 0x62, 0x01, 0x6d, 0xb1, 0x8c, 0xb6, 0x58, 0x46, 0x5b, 0x2c, 0xa3, 0x2d, 0x96, 0xd1, 0x16, 0xcb, 0x68, 0x8b, 0x65, 0xb4, 0xc5, 0x32, 0xda, 0x62, 0x19, 0x6d, 0xb1, 0x8c, 0x51, 0xe5,\n\t0xb2, 0xd5, 0xf7, 0x99, 0xc4, 0x6e, 0x94, 0x98, 0xd7, 0xbf, 0xca, 0x4f, 0xf7, 0xf7, 0xf6, 0x6b, 0x94, 0x7d, 0x85, 0xbf, 0xb4, 0x2e, 0xb0, 0xd2, 0xbf, 0xe8, 0x5f, 0xed, 0xdf, 0xa0, 0xb4, 0x6e, 0x52, 0x5a, 0x37, 0xe8, 0xbd, 0x1e, 0x7a, 0xaf, 0x87, 0x12, 0xb9, 0x49, 0x49, 0xdc, 0xa4, 0x24, 0x6e, 0x52, 0x12, 0x37, 0x59, 0x35, 0x8c, 0xa4, 0x34, 0x6e, 0x52, 0x1a, 0x37, 0x29, 0x8d, 0x9b, 0x94, 0xc6, 0x4d, 0x4a, 0xe3, 0x26, 0xa5, 0x71, 0x93, 0xd2, 0xb8, 0x49, 0x69, 0xdc, 0xa4, 0x34, 0x6e, 0x52, 0x1a, 0x37, 0x29, 0x8d, 0x9b, 0x94, 0xc6, 0x4d, 0x4a, 0xc3, 0x4b, 0x69, 0x78, 0x29, 0x0d, 0x2f, 0xa5, 0xe1, 0xa5, 0x34, 0xbc, 0x94, 0x86, 0x97, 0xd2, 0xf0, 0x52, 0x1a, 0x5e, 0x4a, 0xc3, 0x4b, 0x69, 0x78, 0x29, 0x0d, 0x2f, 0xa5, 0xe1, 0xa5, 0x34, 0xbc, 0x94, 0x86, 0x97, 0xd2, 0xf0,\n\t0x52, 0x1a, 0x5e, 0x4a, 0xc3, 0x4b, 0x69, 0x78, 0x29, 0x0d, 0x2f, 0xa5, 0xe1, 0xa5, 0x34, 0xbc, 0x94, 0x86, 0x97, 0xd2, 0xf0, 0x52, 0x1a, 0x5e, 0x4a, 0xc3, 0x4b, 0x69, 0x78, 0x99, 0xad, 0xdf, 0x61, 0xa6, 0x6e, 0xc7, 0x4c, 0xdd, 0x91, 0x19, 0xba, 0x1d, 0x33, 0x74, 0x37, 0x66, 0xe7, 0x77, 0x98, 0x95, 0x56, 0x31, 0x3b, 0x8f, 0x64, 0x56, 0xee, 0xc2, 0xac, 0xfc, 0x0c, 0xb3, 0x72, 0x2f, 0xf5, 0x91, 0xff, 0x5d, 0xf7, 0xaa, 0x95, 0x9d, 0xd3, 0xbf, 0xb2, 0xcb, 0xf0, 0xb7, 0x4c, 0xdf, 0x7b, 0x89, 0x65, 0xb4, 0xcc, 0x72, 0x4a, 0x27, 0x97, 0xf6, 0xe4, 0xad, 0x5e, 0x83, 0x55, 0xb5, 0x25, 0xd7, 0x9f, 0xed, 0xc9, 0xf7, 0xde, 0x41, 0x05, 0xe3, 0x5e, 0x09, 0xad, 0x32, 0xdf, 0xbf, 0xb2, 0xdb, 0xe2, 0xcf, 0x26, 0xe5, 0x7f, 0x9f, 0xa2, 0xd5, 0xb0, 0xff, 0x83, 0xb6, 0xf3, 0x9f, 0x7a,\n\t0x57, 0xfb, 0x3a, 0x6d, 0xe7, 0x3a, 0x6d, 0xe7, 0x3a, 0x6d, 0xe7, 0x3a, 0x6d, 0xe7, 0x3a, 0x6d, 0xe7, 0x3a, 0x6d, 0xe7, 0x3a, 0x6d, 0xe7, 0x3a, 0x6d, 0xe7, 0x3a, 0x25, 0xfa, 0x06, 0x25, 0xda, 0x92, 0x12, 0x7d, 0x9c, 0x12, 0x6d, 0x49, 0x89, 0x76, 0xa2, 0x44, 0xdf, 0xa0, 0x44, 0x7f, 0xa2, 0x44, 0x87, 0x51, 0xa2, 0x1d, 0x29, 0xd1, 0x0e, 0x94, 0x68, 0x77, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6, 0x91, 0x12, 0xc6,\n\t0x91, 0x12, 0x35, 0xd8, 0xff, 0x9e, 0x68, 0x3a, 0xb3, 0x4e, 0x55, 0xb6, 0xf3, 0xad, 0xbb, 0xcb, 0xfd, 0xd9, 0xee, 0x6f, 0xb3, 0x53, 0xd5, 0xac, 0x74, 0xc1, 0x5f, 0x2b, 0x5d, 0xe5, 0x34, 0xed, 0xf7, 0x34, 0xe3, 0x87, 0x8b, 0xd9, 0xe7, 0x2a, 0xb3, 0xcf, 0xd5, 0xbf, 0xad, 0x52, 0xfc, 0xb3, 0xcd, 0xff, 0xb3, 0x99, 0xe6, 0x3f, 0xf3, 0xfe, 0xe2, 0xff, 0xe5, 0x12, 0x65, 0x64, 0xbe, 0xaa, 0x6e, 0xa3, 0x24, 0x4f, 0x2a, 0x97, 0xba, 0x93, 0xf1, 0xf1, 0x92, 0xc9, 0xf7, 0x39, 0x3a, 0x56, 0x38, 0x8c, 0x8f, 0x97, 0x18, 0x1f, 0x2f, 0x31, 0x3e, 0xa6, 0xdf, 0xf2, 0x9b, 0x06, 0x69, 0xbe, 0x3c, 0xe1, 0x5f, 0xdf, 0x39, 0xa8, 0x87, 0xa8, 0xea, 0x91, 0xd7, 0xee, 0x3f, 0x42, 0xd5, 0xfa, 0xce, 0xf7, 0x1a, 0x94, 0x6f, 0xb5, 0x90, 0x49, 0x7d, 0x64, 0x52, 0x1f, 0x99, 0xd4, 0x47, 0xb2, 0xff,\n\t0xfd, 0xe6, 0x27, 0xa9, 0x93, 0xce, 0xd4, 0x45, 0x17, 0x74, 0xa5, 0x1e, 0xba, 0xa3, 0x87, 0x5c, 0xa4, 0x6e, 0xb2, 0xa8, 0x9b, 0x2c, 0x1e, 0xc5, 0x53, 0xfd, 0xa9, 0x3d, 0x5f, 0xfd, 0x64, 0x32, 0x0a, 0x9f, 0x63, 0x14, 0x3e, 0x47, 0x3d, 0x65, 0x52, 0x4f, 0x99, 0xd4, 0x53, 0x26, 0xf5, 0x94, 0x49, 0x3d, 0x65, 0x52, 0x4f, 0x99, 0xd4, 0x53, 0x26, 0xf5, 0x94, 0x49, 0x3d, 0x65, 0x52, 0x4f, 0x99, 0xd4, 0x53, 0x26, 0xf5, 0x94, 0x49, 0x3d, 0x65, 0x52, 0x4f, 0x99, 0xd4, 0x53, 0xe6, 0x7f, 0xf0, 0x9d, 0xa1, 0x7f, 0x67, 0x14, 0x3e, 0xc7, 0x28, 0x7c, 0xee, 0xff, 0xfa, 0x7b, 0xa3, 0x67, 0x25, 0x8b, 0x3a, 0x75, 0x30, 0x8a, 0x9f, 0x91, 0x68, 0x72, 0xb6, 0xef, 0xb5, 0x9b, 0x53, 0xfe, 0x77, 0xfb, 0x7b, 0xf8, 0x53, 0x69, 0x14, 0x25, 0x9d, 0x58, 0xfd, 0x6f, 0x0a, 0xe2, 0x19, 0xbb, 0xae,\n\t0x92, 0xa9, 0x6f, 0xfa, 0x5f, 0xfd, 0xb1, 0x71, 0x0f, 0x47, 0xf5, 0xab, 0x2f, 0x05, 0xd5, 0xaf, 0xdf, 0xd8, 0xff, 0xd5, 0xbf, 0xa2, 0xe0, 0x9e, 0x45, 0xea, 0x6e, 0xee, 0x19, 0xc3, 0x3d, 0x93, 0xb9, 0xe7, 0x39, 0xee, 0xe9, 0x5b, 0x23, 0xa6, 0x72, 0xcf, 0x58, 0xee, 0x79, 0x98, 0x7b, 0x86, 0xb3, 0x1e, 0x3c, 0xce, 0x7a, 0xf0, 0x78, 0xf5, 0xbf, 0x21, 0x5f, 0xcf, 0x51, 0x8e, 0x73, 0x94, 0x83, 0x1c, 0xe5, 0x28, 0x47, 0x39, 0xcc, 0x3a, 0xf0, 0x24, 0xeb, 0xc0, 0x93, 0xbe, 0x77, 0x3f, 0xc9, 0xf5, 0x79, 0x64, 0xee, 0x3c, 0xb5, 0x88, 0x36, 0x96, 0xca, 0xe8, 0xec, 0x9b, 0xab, 0x62, 0x68, 0x67, 0x19, 0xb4, 0xb3, 0x58, 0x7f, 0xee, 0x3e, 0xcd, 0x1c, 0x75, 0x86, 0xd5, 0xe9, 0x59, 0x46, 0xeb, 0x1c, 0x32, 0xc6, 0x39, 0x49, 0xa7, 0xbd, 0xd9, 0x69, 0x6f, 0x76, 0x56, 0xa6, 0xbe, 0xf9,\n\t0xcb, 0x5e, 0xfd, 0x6a, 0xbf, 0x97, 0x76, 0xe7, 0x34, 0x75, 0x56, 0xba, 0xa9, 0x0b, 0xfe, 0xd6, 0xe6, 0x5e, 0x26, 0xcf, 0xf4, 0x94, 0x2b, 0xb4, 0xb9, 0x2b, 0xb4, 0x66, 0x83, 0x91, 0xbb, 0x84, 0xf6, 0x66, 0xf7, 0xbf, 0x16, 0xba, 0x83, 0xed, 0x2e, 0xec, 0x16, 0x7b, 0xa0, 0x53, 0x6e, 0xd0, 0xde, 0xec, 0xb4, 0x37, 0xbb, 0xf1, 0xb4, 0x5c, 0xa7, 0xcd, 0xd9, 0x69, 0x73, 0x76, 0xda, 0x9c, 0x9d, 0x36, 0x67, 0xa7, 0xcd, 0xd9, 0x69, 0x73, 0x76, 0xda, 0x9c, 0x9d, 0x36, 0x67, 0xa7, 0xcd, 0xd9, 0x69, 0x73, 0x76, 0xda, 0x5c, 0x2a, 0x6d, 0x2e, 0x95, 0x36, 0x97, 0x4a, 0x9b, 0x4b, 0xa5, 0xcd, 0xa5, 0xd2, 0xe6, 0x52, 0x69, 0x73, 0xa9, 0xb4, 0xb9, 0x54, 0xda, 0x5c, 0x2a, 0x6d, 0x2e, 0x95, 0x36, 0x97, 0x4a, 0x9b, 0x4b, 0xa5, 0xcd, 0xa5, 0xd2, 0xe6, 0x52, 0x69, 0x73, 0xa9, 0xb4, 0xb9,\n\t0x54, 0xda, 0x5c, 0x2a, 0x6d, 0x2e, 0x95, 0x36, 0x97, 0x4a, 0x9b, 0x4b, 0xa5, 0xcd, 0xa5, 0xd2, 0xe6, 0x52, 0x69, 0x73, 0xa9, 0xb4, 0xb9, 0x54, 0xda, 0x5c, 0x2a, 0x6d, 0x2e, 0x95, 0x36, 0x97, 0x41, 0x9b, 0xcb, 0xa0, 0xcd, 0x65, 0xd0, 0xe6, 0x32, 0x68, 0x73, 0x19, 0xb4, 0xb9, 0x0c, 0xda, 0x5c, 0x06, 0x6d, 0x2e, 0x83, 0x36, 0x97, 0x41, 0x82, 0xbd, 0x61, 0xfd, 0x08, 0x9f, 0x60, 0x1c, 0x7c, 0xef, 0x62, 0x7f, 0x86, 0xcf, 0xfd, 0xef, 0x66, 0xdf, 0xb0, 0x8e, 0xc7, 0x04, 0x4c, 0xc4, 0x24, 0x4c, 0xc6, 0x97, 0xf8, 0x0a, 0x53, 0x30, 0x15, 0xd3, 0x30, 0x03, 0xdf, 0x62, 0x26, 0x66, 0x61, 0x36, 0xe6, 0x60, 0x2e, 0xbe, 0xc3, 0x3c, 0xcc, 0xc7, 0xf7, 0x58, 0x80, 0x85, 0x58, 0x84, 0x60, 0xfc, 0x80, 0xc5, 0xf8, 0x11, 0x4b, 0xb0, 0x4c, 0x9c, 0xb4, 0x7f, 0x27, 0xed, 0xdf, 0x49, 0xfb,\n\t0x77, 0xd2, 0xfe, 0x9d, 0xb4, 0x7f, 0x27, 0xed, 0xdf, 0x49, 0xfb, 0x77, 0xd2, 0xfe, 0x9d, 0xb4, 0x7f, 0x27, 0xed, 0xdf, 0x49, 0xfb, 0x77, 0xd2, 0xfe, 0x9d, 0xb4, 0x7f, 0x27, 0xed, 0xdf, 0x49, 0xfb, 0x77, 0xd2, 0xfe, 0x9d, 0xb4, 0x7f, 0x27, 0xed, 0xdf, 0x49, 0xfb, 0x77, 0xd2, 0xfe, 0x9d, 0xb4, 0x7f, 0x27, 0xed, 0xdf, 0x49, 0xfb, 0x77, 0xd2, 0xfe, 0xaf, 0xa8, 0x5a, 0xb4, 0xc9, 0xeb, 0xb4, 0x92, 0x63, 0xb4, 0xc9, 0xeb, 0xb4, 0x49, 0x6f, 0x75, 0x82, 0xf5, 0x7d, 0x8e, 0xb7, 0x8c, 0xf6, 0x78, 0x95, 0xf6, 0x78, 0xd5, 0xff, 0x4e, 0x5f, 0xd5, 0xab, 0x34, 0x71, 0xb4, 0xc7, 0x63, 0xd5, 0xff, 0xc6, 0xa6, 0x8c, 0x96, 0x50, 0xe6, 0x7b, 0xd5, 0xfb, 0xcf, 0x57, 0x45, 0xdd, 0xd5, 0xef, 0xdd, 0x97, 0xf8, 0xdf, 0x5d, 0x72, 0xb1, 0x5e, 0xca, 0x63, 0x5e, 0x79, 0x9c, 0xb6, 0x54, 0xf5,\n\t0xef, 0x95, 0x7c, 0x9f, 0x0a, 0x8e, 0xe7, 0x08, 0x47, 0xab, 0x8f, 0xe0, 0xf4, 0x7d, 0x9a, 0x40, 0xfd, 0xa8, 0xca, 0x78, 0xec, 0x3f, 0x78, 0xbc, 0x20, 0x29, 0x36, 0xdd, 0x21, 0x05, 0xa6, 0x3b, 0xc9, 0x48, 0x77, 0x71, 0x2e, 0x35, 0xd9, 0xd6, 0x42, 0x6d, 0xd4, 0x61, 0x04, 0xbc, 0x9b, 0xa3, 0xd5, 0x95, 0x33, 0xa6, 0x7b, 0xb8, 0x7c, 0x2f, 0xee, 0xa3, 0x9f, 0xde, 0x8f, 0x07, 0xd8, 0xaf, 0x87, 0xfa, 0x68, 0xc0, 0xfd, 0x1a, 0xb2, 0x7d, 0x90, 0xf3, 0x6d, 0x24, 0x99, 0xa6, 0xc6, 0x5c, 0x6e, 0xc2, 0xe5, 0xa6, 0x78, 0x88, 0x91, 0xb3, 0x19, 0xdb, 0x87, 0xd1, 0x5c, 0xa2, 0x4d, 0x2d, 0xd8, 0xb6, 0x44, 0x2b, 0x39, 0x6b, 0x7a, 0x84, 0xdb, 0xb5, 0x66, 0xbf, 0x0d, 0x59, 0xfd, 0x51, 0xb1, 0x99, 0xa3, 0xe4, 0xba, 0xf9, 0xa4, 0xdc, 0x30, 0xc7, 0xb3, 0x4e, 0xb1, 0x21, 0x93, 0xfd, 0x53,\n\t0x22, 0xe6, 0x0b, 0x52, 0x64, 0xbe, 0x08, 0x17, 0xdc, 0xb8, 0x24, 0xa7, 0xcd, 0xb9, 0x6c, 0xf3, 0x90, 0x8f, 0xcb, 0x72, 0xdc, 0xec, 0x61, 0x5b, 0x80, 0x42, 0x14, 0x89, 0xd7, 0x5c, 0xcc, 0x75, 0x25, 0xe2, 0x30, 0x97, 0xa2, 0x8c, 0x0c, 0x77, 0x85, 0xcb, 0xe5, 0xac, 0x18, 0xaf, 0xa2, 0x82, 0xdb, 0x54, 0xe2, 0x1a, 0xae, 0xe3, 0x86, 0xe4, 0x99, 0xbd, 0x6c, 0x6f, 0xe2, 0x0f, 0xfe, 0x2e, 0x52, 0x14, 0xa0, 0xc4, 0x1b, 0x60, 0x12, 0x67, 0x80, 0xc6, 0xd6, 0xcc, 0xe5, 0x00, 0x04, 0xca, 0x99, 0x80, 0x1a, 0xe2, 0x09, 0xb0, 0x70, 0x9d, 0x55, 0xf2, 0x02, 0x82, 0xb8, 0xae, 0xab, 0xe4, 0x07, 0xbc, 0xc2, 0x75, 0xbd, 0xd8, 0xef, 0xcd, 0xdf, 0xfb, 0xb0, 0xed, 0x2b, 0xee, 0x80, 0x7e, 0x6c, 0xfb, 0x4b, 0x7a, 0xc0, 0x00, 0x6e, 0x3b, 0x10, 0x83, 0xe4, 0x46, 0xc0, 0x60, 0xf1, 0x06, 0x16,\n\t0xc8, 0x99, 0xc0, 0x42, 0xf1, 0x5a, 0x9e, 0x90, 0xcb, 0x96, 0x91, 0x18, 0x85, 0x77, 0xe4, 0x94, 0x4e, 0xeb, 0xd6, 0x83, 0xe5, 0xba, 0xbe, 0x81, 0xed, 0x5e, 0xfc, 0x86, 0x70, 0x44, 0x89, 0x57, 0x4f, 0x44, 0x26, 0xb2, 0x90, 0x27, 0x5e, 0xc3, 0x8a, 0x7b, 0xe9, 0xf5, 0x94, 0xb1, 0xd1, 0x94, 0x6d, 0x1b, 0xb0, 0x8e, 0x32, 0x46, 0x70, 0xfd, 0x44, 0x7c, 0xc5, 0xfe, 0x74, 0x2c, 0x92, 0x3c, 0x23, 0x5a, 0x8a, 0x8d, 0x73, 0x72, 0xc6, 0xc8, 0x95, 0x54, 0x23, 0x0f, 0xc5, 0x28, 0x41, 0x29, 0xbd, 0x74, 0x29, 0xeb, 0xac, 0xe3, 0x8c, 0xfe, 0x91, 0x6c, 0xa3, 0xe4, 0xb4, 0xf5, 0x24, 0x62, 0xe5, 0x8c, 0x35, 0x8e, 0xcb, 0xf1, 0x48, 0x40, 0x22, 0xec, 0x20, 0x93, 0x5b, 0x53, 0xd9, 0xa6, 0xc9, 0x59, 0xab, 0x43, 0x32, 0x83, 0x0e, 0xd3, 0x06, 0x23, 0x10, 0x47, 0x56, 0x6f, 0x41, 0x6b, 0xfa,\n\t0x50, 0x89, 0xec, 0xa3, 0x35, 0x6d, 0xa3, 0x35, 0x65, 0xd0, 0x9a, 0xde, 0xa7, 0x35, 0x2d, 0x35, 0xd5, 0xf9, 0x63, 0x2a, 0xb5, 0xfe, 0x94, 0xa9, 0xcd, 0x1f, 0xfb, 0x4c, 0x6d, 0x55, 0x7d, 0x6a, 0x79, 0x18, 0xad, 0xbc, 0x87, 0xe9, 0x29, 0x99, 0x62, 0x7a, 0x5a, 0xbe, 0xa6, 0x95, 0xbf, 0x4d, 0x29, 0x3f, 0x4a, 0x29, 0xbe, 0x18, 0xd0, 0xfb, 0x8f, 0xe1, 0x94, 0xdc, 0x13, 0x94, 0xda, 0x02, 0x4a, 0xab, 0x01, 0xa5, 0xd2, 0xd8, 0xe2, 0xfb, 0xee, 0x40, 0x56, 0x81, 0x94, 0x48, 0x2f, 0x4a, 0xa4, 0x03, 0x25, 0xa0, 0x28, 0x01, 0x0b, 0xcf, 0xdc, 0x6e, 0x34, 0x55, 0x8d, 0x8d, 0x89, 0x7f, 0x54, 0x1a, 0x8b, 0xfe, 0xc8, 0xe6, 0x59, 0x0e, 0xe5, 0xd9, 0xb4, 0xe5, 0xec, 0xbf, 0xe0, 0x4c, 0xfb, 0x72, 0x96, 0x6f, 0x72, 0x96, 0x11, 0xfe, 0x4f, 0xb4, 0x1e, 0x96, 0xc7, 0x82, 0x22, 0xfe, 0xa8,\n\t0xa4, 0xdf, 0x95, 0xa9, 0x3b, 0x39, 0xcb, 0x10, 0xce, 0x6e, 0x27, 0x67, 0x77, 0xcc, 0x54, 0x47, 0x59, 0x39, 0xbb, 0x1f, 0x38, 0xab, 0xcd, 0xe6, 0xfd, 0x72, 0xcd, 0x1c, 0x21, 0xd7, 0x38, 0x9b, 0x39, 0x3c, 0xfa, 0x61, 0x1e, 0xc1, 0xcb, 0x23, 0x98, 0x28, 0xc3, 0x52, 0x8e, 0x1e, 0xc5, 0xd1, 0xf7, 0x70, 0xc4, 0x54, 0xab, 0xef, 0xf3, 0x3a, 0x0d, 0x78, 0xbe, 0x57, 0x4d, 0x81, 0x72, 0x8d, 0xe7, 0x5b, 0xc6, 0xd1, 0xf2, 0x38, 0x5a, 0x19, 0xbd, 0x25, 0x81, 0xa3, 0x15, 0xd0, 0x9a, 0x93, 0x38, 0x62, 0x21, 0x7d, 0xae, 0xd0, 0xf7, 0x0d, 0xe0, 0x1c, 0xb9, 0x92, 0x23, 0x57, 0xd2, 0x92, 0x4b, 0x39, 0x7a, 0x31, 0x2d, 0xa8, 0x98, 0xe7, 0x5b, 0x12, 0xd0, 0x5d, 0x2a, 0x03, 0x7a, 0xc8, 0x75, 0x5a, 0x4d, 0x82, 0xbf, 0xc5, 0xf8, 0x5a, 0xcb, 0x20, 0x6e, 0x53, 0xfd, 0xbd, 0xe8, 0x3c, 0x7f,\n\t0x37, 0xcf, 0xff, 0x1a, 0x67, 0x90, 0xc3, 0x19, 0x14, 0x70, 0x06, 0x1e, 0xff, 0x73, 0xb8, 0x9d, 0xe7, 0xb0, 0xb9, 0xfa, 0x39, 0x1c, 0xe5, 0x39, 0xe8, 0x3c, 0x6a, 0x30, 0x8f, 0xb8, 0xe9, 0x96, 0xe7, 0x30, 0xb7, 0xea, 0x39, 0x28, 0x33, 0xcf, 0x21, 0x80, 0x23, 0x94, 0x55, 0x3f, 0x87, 0xdf, 0x78, 0x0e, 0x0e, 0xff, 0x73, 0x68, 0xc3, 0x73, 0x18, 0xcf, 0x91, 0x62, 0x79, 0x0e, 0x91, 0x1c, 0x6d, 0x15, 0x47, 0xdb, 0x41, 0x7d, 0x95, 0x73, 0xb4, 0x28, 0x9e, 0xc3, 0x0b, 0x1c, 0xf1, 0xb8, 0xe9, 0x09, 0x65, 0xa1, 0xbe, 0x86, 0x50, 0x5f, 0x76, 0xea, 0xcb, 0x46, 0x7d, 0x7d, 0x62, 0x7a, 0x99, 0xd5, 0x58, 0x7f, 0x75, 0xb7, 0x69, 0xa0, 0xba, 0xcf, 0x34, 0x58, 0xdd, 0xcd, 0xa3, 0x85, 0xf3, 0x7c, 0xa6, 0xf8, 0x9f, 0x4f, 0xef, 0x3f, 0x4e, 0xf1, 0x5c, 0x36, 0xf2, 0x5c, 0xe2, 0x39, 0x83,\n\t0x01, 0x01, 0x3f, 0x28, 0xbd, 0xea, 0xdb, 0xbb, 0x94, 0x85, 0xe7, 0xd3, 0x97, 0xe7, 0x33, 0x86, 0xfa, 0xcc, 0xa6, 0x3e, 0x67, 0x50, 0x9f, 0x93, 0xa8, 0xcf, 0x57, 0xa9, 0xcf, 0x51, 0x9c, 0xe9, 0xb3, 0x9c, 0x69, 0x7b, 0x5a, 0x6f, 0x5f, 0xce, 0x76, 0x30, 0x67, 0xbb, 0x81, 0xb3, 0x9d, 0x49, 0x7d, 0xee, 0xa6, 0x2e, 0x37, 0x58, 0x1d, 0x2a, 0x88, 0x7a, 0x1c, 0x4f, 0x8b, 0xeb, 0xab, 0x74, 0xce, 0x7c, 0x32, 0x67, 0x7e, 0x84, 0x33, 0x3f, 0xc2, 0x99, 0xcf, 0xe3, 0xac, 0x9d, 0x9c, 0xf5, 0x02, 0xce, 0xba, 0x2b, 0x47, 0xec, 0xa3, 0x42, 0xb8, 0xc5, 0x66, 0x75, 0x45, 0x42, 0x54, 0xb9, 0x24, 0xa9, 0x4a, 0xd9, 0xab, 0xae, 0xe1, 0xa6, 0x44, 0x30, 0xe2, 0x65, 0x50, 0x6f, 0x11, 0x26, 0x5d, 0x92, 0xb9, 0xb7, 0xd3, 0x74, 0x1b, 0xfb, 0xb7, 0xe3, 0x4e, 0xb9, 0xce, 0xf3, 0xf7, 0xfc, 0x97,\n\t0xd1, 0x6f, 0x29, 0xa3, 0x9f, 0x93, 0xd1, 0x2f, 0xf7, 0x96, 0xd1, 0xef, 0x27, 0x46, 0xbf, 0x9f, 0xfe, 0xcb, 0xe8, 0x57, 0xe6, 0x1f, 0xfd, 0x1a, 0xb3, 0xfd, 0xdb, 0xa8, 0xf7, 0xb7, 0x11, 0xef, 0xaf, 0xd1, 0xee, 0x32, 0xa3, 0x5d, 0x59, 0xf5, 0x68, 0x77, 0xd1, 0xff, 0x3a, 0xfc, 0x93, 0x94, 0xf3, 0x33, 0x94, 0x7f, 0x47, 0x74, 0x66, 0xd5, 0xd3, 0x05, 0x3d, 0x28, 0xe7, 0xaa, 0x7f, 0x7b, 0xe8, 0x7b, 0x1d, 0x31, 0x8d, 0x1a, 0x2d, 0x33, 0x1f, 0x92, 0x10, 0x6a, 0xb5, 0xcc, 0x7c, 0x44, 0x22, 0xcc, 0x91, 0x88, 0x92, 0x70, 0x46, 0xc9, 0xdd, 0xe6, 0x68, 0xf6, 0x13, 0x65, 0xaf, 0x39, 0x4d, 0x52, 0x18, 0x29, 0x77, 0xd3, 0xbe, 0x32, 0xcd, 0x67, 0xb9, 0xfc, 0x8f, 0xa3, 0xa5, 0xf3, 0xef, 0x46, 0xcb, 0xbf, 0x1f, 0x29, 0xcb, 0x18, 0x1d, 0x2f, 0xfa, 0x47, 0xc4, 0xaa, 0x91, 0xf0, 0xa7,\n\t0x3f, 0x47, 0xc2, 0xaa, 0x51, 0xb0, 0x8c, 0x11, 0xb0, 0xec, 0x96, 0x11, 0xf0, 0x22, 0xed, 0xb7, 0x80, 0x11, 0xb0, 0x8c, 0x11, 0xf0, 0xa7, 0xea, 0x11, 0x30, 0x86, 0xba, 0xb7, 0xd3, 0x96, 0xe3, 0x19, 0x09, 0xbd, 0xd5, 0x23, 0xe1, 0xf2, 0xea, 0x91, 0x30, 0xa3, 0x7a, 0x24, 0x2c, 0x64, 0x24, 0x2c, 0x63, 0x24, 0x2c, 0xa3, 0x5d, 0x5c, 0x61, 0x24, 0x2c, 0x0b, 0xf8, 0x41, 0xd2, 0x68, 0x1b, 0x36, 0xda, 0xba, 0x83, 0x51, 0x31, 0x97, 0x51, 0xb1, 0x2c, 0x90, 0xfa, 0x62, 0x64, 0x4c, 0x60, 0x64, 0x4c, 0x60, 0x64, 0x4c, 0xa0, 0xcd, 0x6c, 0xa1, 0xcd, 0xfc, 0x40, 0x9b, 0x29, 0xd3, 0x07, 0x4a, 0x04, 0xa3, 0xe4, 0x6e, 0x46, 0xc9, 0x9d, 0x8c, 0x92, 0x17, 0x69, 0x43, 0x17, 0x69, 0x43, 0x17, 0x19, 0x25, 0x2f, 0x32, 0x4a, 0x96, 0x31, 0x4a, 0x96, 0x31, 0x4a, 0x96, 0xd1, 0x02, 0xca, 0x68,\n\t0x53, 0x65, 0x8c, 0x92, 0x65, 0x8c, 0x92, 0xc5, 0xd5, 0xa3, 0x64, 0x31, 0xa3, 0x64, 0x71, 0xf5, 0x28, 0x59, 0x46, 0x3b, 0x2b, 0xbb, 0x65, 0x94, 0xf4, 0xf5, 0x8e, 0x52, 0x46, 0xc9, 0x8b, 0xb4, 0xb9, 0x2b, 0xd6, 0x5f, 0x25, 0xc4, 0xba, 0x1b, 0x7b, 0x24, 0xc9, 0x7a, 0x88, 0x31, 0x24, 0x1c, 0x87, 0x11, 0x81, 0x63, 0x92, 0xcc, 0x88, 0x99, 0x51, 0x3d, 0x62, 0x3a, 0x19, 0x31, 0x9d, 0xb4, 0xd1, 0xdc, 0x7f, 0x3a, 0x62, 0x56, 0x8d, 0x96, 0x97, 0x69, 0xb7, 0x65, 0xb4, 0xdb, 0x32, 0x46, 0x4a, 0xaf, 0xaa, 0x4b, 0xbb, 0xb5, 0xd3, 0x02, 0x1d, 0xd5, 0xa3, 0x64, 0x38, 0xad, 0xce, 0x46, 0xdb, 0x0d, 0xa1, 0xb7, 0xfd, 0xcc, 0x6c, 0x7d, 0x89, 0x19, 0xfa, 0x14, 0xb5, 0x5e, 0x4a, 0x8d, 0x97, 0x52, 0xd3, 0xc7, 0x03, 0xba, 0xaa, 0xdb, 0x29, 0x31, 0x7b, 0x60, 0x07, 0x39, 0x15, 0xc8, 0x5a,\n\t0xd9, 0xf2, 0x8e, 0xba, 0x8d, 0x33, 0xae, 0xe0, 0x8c, 0x93, 0xad, 0xf7, 0x49, 0x34, 0x67, 0xec, 0x1b, 0xe5, 0xd2, 0x94, 0xc1, 0x91, 0x93, 0x68, 0xd3, 0xe5, 0x1c, 0x35, 0x95, 0xa3, 0xe6, 0x73, 0x54, 0x3b, 0x6d, 0xcd, 0x43, 0xdf, 0xba, 0x83, 0xbe, 0xd5, 0x94, 0x7b, 0xb8, 0x55, 0x23, 0x7a, 0x46, 0x34, 0x8f, 0x1f, 0xcf, 0x2d, 0xf3, 0xb9, 0xe5, 0x35, 0x6e, 0x59, 0x4c, 0x4b, 0x0f, 0xe1, 0x96, 0xe7, 0xfe, 0xe9, 0xe7, 0x90, 0xf7, 0x33, 0x0f, 0x47, 0x20, 0x4a, 0x4e, 0xd0, 0xd2, 0xce, 0xd3, 0xca, 0x7c, 0x2d, 0x20, 0x9f, 0x5a, 0x3f, 0x45, 0xad, 0xe7, 0x50, 0xeb, 0x59, 0xd4, 0xf6, 0x16, 0x7f, 0x4d, 0xf7, 0xe7, 0xfa, 0x41, 0xfe, 0x9a, 0xfd, 0xeb, 0x33, 0xcb, 0xef, 0xc8, 0x11, 0x6a, 0xf0, 0x10, 0xe7, 0x5c, 0xcc, 0x19, 0x94, 0x70, 0xbe, 0xa5, 0xea, 0x0e, 0x1e, 0xf9, 0x12, 0x8f,\n\t0x7c, 0x86, 0x47, 0x76, 0x73, 0x9e, 0x97, 0x79, 0x74, 0x37, 0x25, 0x90, 0xcf, 0x58, 0xe2, 0xe1, 0x68, 0x4e, 0x8e, 0x76, 0x95, 0xa3, 0xe5, 0x71, 0xb4, 0x8b, 0xdc, 0xf3, 0x22, 0xf7, 0x2c, 0xe4, 0x9e, 0x2e, 0x35, 0x95, 0x5e, 0x5d, 0x46, 0x4f, 0x0e, 0x33, 0x69, 0xf4, 0xa2, 0x40, 0x59, 0xec, 0x7f, 0xc6, 0xb7, 0xc9, 0x5c, 0x7a, 0xf1, 0x5c, 0x8e, 0xea, 0x5b, 0xbf, 0x78, 0xe9, 0xc1, 0x5e, 0x7a, 0xb0, 0x97, 0xa3, 0x7b, 0xe9, 0xc1, 0xe7, 0xe9, 0xc1, 0x97, 0xe9, 0xc1, 0x5e, 0x7a, 0xb0, 0x97, 0x9e, 0xeb, 0xa5, 0xe7, 0x7a, 0xe9, 0xb9, 0xbe, 0x35, 0x8b, 0x97, 0x35, 0xcb, 0x22, 0x7a, 0xad, 0x97, 0x5e, 0xeb, 0x65, 0xad, 0x72, 0x9d, 0x9e, 0xeb, 0xa5, 0xe7, 0x7a, 0x39, 0xab, 0xd5, 0xf4, 0x5e, 0x2f, 0xbd, 0xd7, 0x4b, 0xef, 0xf5, 0xd0, 0x73, 0xbd, 0x9c, 0x65, 0x71, 0xf5, 0xbf, 0x17,\n\t0xcb, 0x36, 0x75, 0x92, 0x5f, 0x58, 0xab, 0xfd, 0x66, 0x7a, 0x8e, 0xed, 0xf3, 0x6c, 0x7d, 0xdf, 0x59, 0xe7, 0xfb, 0x7e, 0x0a, 0xdf, 0x6f, 0x3e, 0x0c, 0x61, 0x16, 0x7c, 0x83, 0xeb, 0x47, 0xc8, 0x2f, 0xf4, 0x5e, 0x5f, 0xcf, 0x9d, 0x4b, 0xcf, 0x9d, 0x4b, 0xaf, 0x2d, 0xa2, 0xd7, 0xce, 0x35, 0xc7, 0xd0, 0xe3, 0x62, 0x91, 0x8c, 0x4c, 0xae, 0x3b, 0x85, 0x0b, 0xac, 0x59, 0x2e, 0xc2, 0x05, 0x37, 0x2e, 0x51, 0xd6, 0xb9, 0x6c, 0x99, 0xef, 0xe9, 0xb5, 0x5e, 0xd6, 0x38, 0x8b, 0xe8, 0xb9, 0x5e, 0x7a, 0xae, 0x97, 0x9e, 0xeb, 0x5b, 0xdf, 0x2c, 0xa2, 0xe7, 0x66, 0xb1, 0xae, 0x59, 0xc4, 0xba, 0xe6, 0x3a, 0xeb, 0x9a, 0xeb, 0xf4, 0x62, 0x2f, 0xbd, 0xd8, 0x4b, 0x0f, 0xf6, 0xd2, 0x83, 0xbd, 0xac, 0x65, 0xae, 0xd3, 0x8b, 0x7d, 0xeb, 0x17, 0x2f, 0xbd, 0xd7, 0x4b, 0xef, 0xcd, 0xa2, 0xee,\n\t0xb2, 0xe8, 0xb5, 0xbe, 0x5e, 0xea, 0xa5, 0x87, 0x7a, 0xe9, 0x9d, 0x5e, 0xea, 0xaa, 0x88, 0xf6, 0xf5, 0x33, 0xed, 0xeb, 0x67, 0x7a, 0xe2, 0x65, 0x7a, 0x60, 0x25, 0x3d, 0xb0, 0x92, 0x1e, 0x58, 0x49, 0xaf, 0x9b, 0x4b, 0xaf, 0x2b, 0xf2, 0xcf, 0x87, 0x6d, 0xd0, 0xcd, 0xbf, 0xbe, 0xf0, 0xd2, 0x73, 0xbc, 0xf4, 0x98, 0x2c, 0xd6, 0x15, 0xd1, 0xac, 0x2b, 0xa2, 0x59, 0x57, 0x44, 0xb3, 0xae, 0x88, 0x66, 0x5d, 0x11, 0x4d, 0x0f, 0x2a, 0xa3, 0x07, 0x95, 0xd1, 0x7b, 0xc2, 0xe8, 0x3d, 0x61, 0xf4, 0x9e, 0x30, 0x7a, 0x4f, 0x98, 0xf5, 0x08, 0x3d, 0x2c, 0x52, 0xbc, 0xf4, 0x9c, 0xf3, 0xf4, 0x9c, 0xf3, 0xf4, 0x9c, 0xcb, 0xf4, 0x1c, 0x2f, 0x3d, 0xc7, 0x4b, 0xcf, 0xf1, 0xd2, 0x73, 0xbc, 0xf4, 0x1c, 0x2f, 0x33, 0xf8, 0x75, 0x7a, 0x8f, 0x97, 0xde, 0xe3, 0xa1, 0x6d, 0xef, 0x57, 0xef, 0x52,\n\t0xe3, 0x27, 0xa8, 0xf1, 0x5c, 0x6a, 0x7c, 0x01, 0xb5, 0x3d, 0x8d, 0xda, 0x9e, 0x46, 0x6d, 0xdf, 0xf8, 0xbb, 0xda, 0xfe, 0x9f, 0xd7, 0xf0, 0x86, 0x5b, 0x6a, 0xf8, 0xca, 0x2d, 0x35, 0xbc, 0xed, 0xcf, 0x1a, 0xf6, 0xd5, 0x6e, 0x5b, 0xff, 0x4a, 0xbc, 0xd8, 0xff, 0xaf, 0x01, 0x3b, 0xb1, 0x6e, 0x7e, 0x56, 0x0e, 0x50, 0xbb, 0x7b, 0xa9, 0xdd, 0x03, 0xd4, 0xee, 0xe1, 0xbf, 0xcd, 0xe7, 0xd4, 0xee, 0x4e, 0x6a, 0x77, 0x3f, 0xb5, 0xbb, 0x9f, 0x9a, 0x9d, 0x46, 0xcd, 0x4e, 0xa3, 0x56, 0xa7, 0x51, 0xab, 0xb9, 0xd4, 0x6a, 0x2e, 0xb5, 0x9a, 0xfb, 0x0f, 0xb5, 0xf9, 0xf7, 0x35, 0xb9, 0xe1, 0xbf, 0xd4, 0xe4, 0x06, 0x6a, 0x71, 0x03, 0xb5, 0x78, 0x85, 0x5a, 0xbc, 0xf2, 0x4f, 0x6a, 0xf1, 0xca, 0xdf, 0xd5, 0xe2, 0x3f, 0xd6, 0x5e, 0x19, 0xb5, 0xb7, 0x9d, 0xda, 0xdb, 0x4e, 0x6d, 0x4d, 0x33,\n\t0xea, 0x52, 0x33, 0xff, 0xac, 0xb6, 0xa2, 0x91, 0x2b, 0xe1, 0xd4, 0x56, 0x38, 0xb5, 0x15, 0x4e, 0x6d, 0x85, 0x53, 0x5b, 0xe1, 0xd4, 0xd2, 0x09, 0x6a, 0xe9, 0x04, 0xb5, 0x74, 0x82, 0x5a, 0x3a, 0x41, 0x2d, 0xe5, 0xfa, 0x6b, 0xe9, 0x9f, 0xd7, 0xcc, 0x15, 0x7f, 0xcd, 0x38, 0x99, 0x4b, 0x1b, 0x51, 0x1b, 0xa3, 0xe9, 0x7f, 0x15, 0x8c, 0x65, 0x5f, 0xfb, 0xfb, 0x5e, 0x73, 0x59, 0xee, 0x1b, 0x71, 0xe8, 0xc9, 0x3b, 0xab, 0x33, 0x8d, 0xad, 0xfa, 0x5f, 0xf4, 0x97, 0x54, 0x7f, 0x46, 0xc2, 0xf7, 0x09, 0xfe, 0x49, 0x8c, 0x25, 0x6b, 0x68, 0xf3, 0xe5, 0xfe, 0xf5, 0x75, 0xd5, 0x6a, 0xa8, 0xac, 0x7a, 0x25, 0xe4, 0xa1, 0xe7, 0x5f, 0xa4, 0xe7, 0x9f, 0xe6, 0x59, 0xa5, 0x33, 0x7e, 0xf8, 0xfe, 0xa5, 0xfd, 0x48, 0x9e, 0xd9, 0x60, 0xc6, 0x91, 0x7c, 0x46, 0x02, 0xff, 0xb3, 0x60, 0xdc, 0x2b,\n\t0x62, 0x34, 0xf0, 0x9d, 0xc5, 0x77, 0xea, 0x11, 0x7a, 0xf9, 0x59, 0x7a, 0x79, 0x3a, 0xbd, 0x3c, 0x9f, 0xf9, 0xf9, 0x22, 0xf3, 0xf3, 0x45, 0xea, 0x3c, 0x85, 0x24, 0x92, 0xc3, 0x19, 0xa5, 0xfb, 0x7b, 0x6f, 0x1b, 0xea, 0xfd, 0x51, 0x46, 0xdc, 0x1e, 0xfe, 0x5f, 0x66, 0xf1, 0xfd, 0xdb, 0xa2, 0x32, 0xce, 0x24, 0x8f, 0x5e, 0x96, 0x4e, 0x7d, 0xa4, 0x50, 0x07, 0x29, 0xa4, 0x85, 0x33, 0xa4, 0x85, 0x33, 0xf4, 0xaa, 0x64, 0xea, 0x23, 0x85, 0xb9, 0xf0, 0xa2, 0x7f, 0x3c, 0x0a, 0x94, 0x64, 0xff, 0x9c, 0x67, 0xe5, 0x72, 0x6f, 0xf4, 0x65, 0xd4, 0xeb, 0x2f, 0x39, 0xf4, 0x94, 0x7c, 0xcb, 0x25, 0xc9, 0xd1, 0x1f, 0x93, 0x12, 0x7a, 0x42, 0x32, 0x65, 0x7b, 0x8a, 0xb2, 0x3d, 0x45, 0xd9, 0x9e, 0xa2, 0x6c, 0x4f, 0x51, 0xb6, 0xa7, 0x68, 0xe9, 0xe9, 0xb4, 0xf4, 0x74, 0x5a, 0x7a, 0xbe, 0xbf,\n\t0x35, 0x3b, 0x24, 0x47, 0x35, 0xe3, 0x8c, 0x7f, 0xe7, 0x8c, 0x93, 0x38, 0xe3, 0x4b, 0x9c, 0xb1, 0x9b, 0x33, 0x76, 0x73, 0xc6, 0xfb, 0x38, 0xdb, 0x23, 0x9c, 0x6d, 0x2e, 0x67, 0x5b, 0xc4, 0x59, 0x5e, 0xf6, 0xfd, 0x66, 0x28, 0x67, 0x99, 0xcd, 0x59, 0x26, 0x71, 0x96, 0xfb, 0x38, 0xcb, 0x7d, 0x9c, 0xa5, 0x9d, 0xb3, 0xb4, 0x73, 0x96, 0x71, 0x9c, 0xe5, 0x3e, 0x72, 0x8c, 0x97, 0x1c, 0xe3, 0xe5, 0x6c, 0xdd, 0x9c, 0xed, 0x79, 0xce, 0x36, 0x8e, 0xb3, 0x8d, 0xe3, 0x6c, 0xdd, 0x9c, 0xe1, 0x25, 0xca, 0xec, 0x3a, 0x67, 0x17, 0xc7, 0xd9, 0xc5, 0x72, 0x76, 0xb1, 0x9c, 0x5d, 0x2c, 0x67, 0x17, 0xcb, 0xd9, 0xc5, 0x72, 0x76, 0x49, 0x9c, 0x5d, 0x12, 0x67, 0x77, 0x89, 0xb3, 0xcb, 0x55, 0xb7, 0x33, 0x26, 0x1f, 0xe2, 0xec, 0x66, 0x71, 0x06, 0x36, 0x66, 0x83, 0x45, 0x94, 0xd7, 0xaa, 0xea,\n\t0x4f, 0x3c, 0xf8, 0xd6, 0x24, 0x31, 0x9c, 0x91, 0x9d, 0x32, 0xf8, 0xca, 0x37, 0x2e, 0xf3, 0xdc, 0x2f, 0x73, 0xf4, 0x1b, 0xac, 0x06, 0xff, 0x77, 0xef, 0xd5, 0x84, 0x95, 0x7b, 0x53, 0xd5, 0xce, 0x7f, 0x6f, 0x83, 0x96, 0x53, 0xcc, 0x11, 0x32, 0xfd, 0xdf, 0xe0, 0x57, 0xfd, 0xef, 0x52, 0xb9, 0x65, 0x0e, 0xb7, 0x2c, 0xa1, 0x6c, 0xcf, 0x50, 0xd3, 0xd7, 0x54, 0x1d, 0x8e, 0x7f, 0x8d, 0xf2, 0xb9, 0xc2, 0x63, 0x5c, 0xa3, 0x26, 0xaf, 0x56, 0x7f, 0x0f, 0x45, 0x62, 0xf5, 0x37, 0x72, 0x24, 0xdd, 0x92, 0x70, 0xb3, 0x28, 0x87, 0x1b, 0x94, 0xc1, 0x35, 0x1e, 0xb3, 0x84, 0xda, 0x2a, 0xa7, 0xb6, 0x4a, 0x68, 0x47, 0xa9, 0xb4, 0xa3, 0x54, 0x8e, 0x7a, 0x81, 0xa3, 0x5e, 0xfe, 0xa7, 0x8f, 0x9b, 0xf5, 0x0f, 0x8f, 0xeb, 0x2b, 0x91, 0x28, 0x1e, 0xdb, 0xd7, 0xae, 0x7d, 0x9f, 0xcd, 0xdc, 0xca,\n\t0x73, 0x0b, 0xab, 0x7e, 0x6e, 0xe9, 0xd5, 0xef, 0xfc, 0xa4, 0xf0, 0x38, 0xbe, 0xc4, 0xe2, 0xe6, 0x9e, 0x1e, 0x5f, 0x1b, 0x55, 0x1a, 0xf7, 0xf0, 0xad, 0x46, 0x93, 0x55, 0x4d, 0x1e, 0xc5, 0xe5, 0x4f, 0x07, 0xcd, 0xb9, 0xff, 0xa3, 0xb4, 0xd4, 0xaa, 0x77, 0x8e, 0x7c, 0xe7, 0xbd, 0x9a, 0x73, 0x4d, 0xe5, 0x5c, 0xaf, 0x06, 0xf4, 0x56, 0x16, 0xdf, 0xbc, 0xc9, 0x39, 0x26, 0x73, 0x8e, 0xc9, 0x1c, 0xe7, 0x2c, 0x67, 0x10, 0x4e, 0x5b, 0xbf, 0xc1, 0x59, 0xb8, 0x55, 0x6d, 0xee, 0xed, 0x2b, 0xdd, 0x4a, 0x8e, 0xb0, 0x91, 0x23, 0x1c, 0xe3, 0x08, 0x7b, 0xfc, 0xbf, 0x8b, 0xd5, 0x9f, 0x75, 0xec, 0x40, 0x5a, 0x4d, 0xd5, 0x33, 0x1f, 0xcd, 0xd1, 0xb2, 0x79, 0xe6, 0x15, 0x9c, 0xd1, 0xd5, 0xea, 0x39, 0xd4, 0xc5, 0x51, 0xdf, 0xe6, 0xa8, 0x6f, 0x73, 0x54, 0x27, 0x47, 0xcd, 0x51, 0xb7, 0xf9,\n\t0x47, 0xce, 0xbb, 0xfc, 0xb3, 0xee, 0xf5, 0x5b, 0xbe, 0x5f, 0xe9, 0x04, 0x47, 0x3b, 0x73, 0xeb, 0x77, 0xae, 0x72, 0xcf, 0x73, 0xdc, 0xf3, 0x9c, 0xbf, 0xf4, 0xcf, 0x72, 0x0e, 0x67, 0xb9, 0x47, 0x39, 0xe7, 0x70, 0xfe, 0x5f, 0xbd, 0xee, 0xc6, 0x39, 0x94, 0x70, 0x0e, 0xbe, 0x35, 0xe0, 0x79, 0xce, 0xe1, 0x1c, 0xe7, 0x70, 0xe1, 0x6f, 0xdf, 0x5a, 0xc2, 0x39, 0xfc, 0xce, 0x39, 0x94, 0x92, 0x59, 0xaa, 0xe6, 0xd1, 0xcb, 0x1c, 0x21, 0xae, 0xfa, 0x33, 0x54, 0xfe, 0xef, 0xe7, 0xa8, 0x2e, 0xfd, 0x02, 0xf5, 0x30, 0x8f, 0x79, 0x9d, 0x5e, 0x92, 0x47, 0x2f, 0xa9, 0xa4, 0x77, 0x24, 0xf1, 0xf8, 0x0e, 0x7a, 0x87, 0xef, 0xdf, 0x0b, 0x46, 0x71, 0xcf, 0x13, 0x8c, 0xd1, 0xbe, 0x77, 0x73, 0x4f, 0x32, 0x46, 0x47, 0x32, 0x46, 0x9f, 0xe4, 0x48, 0x9b, 0x6e, 0x79, 0xb7, 0xdf, 0xc1, 0xb9, 0x1c,\n\t0x61, 0x9c, 0x8e, 0x63, 0x9c, 0x8e, 0xa3, 0x07, 0xe5, 0xd1, 0x83, 0x92, 0xe8, 0x41, 0x49, 0xf4, 0x9c, 0x0b, 0xf4, 0x9c, 0x24, 0x7a, 0xca, 0x05, 0xce, 0xd3, 0x77, 0x6e, 0x07, 0x39, 0xb7, 0x83, 0xf4, 0x96, 0x4a, 0x7a, 0xca, 0x05, 0x7a, 0x4a, 0x26, 0x3d, 0x25, 0x93, 0x9e, 0x92, 0x49, 0x4f, 0xc9, 0xa4, 0xa7, 0x64, 0xd2, 0x53, 0xf2, 0xe8, 0x29, 0x79, 0xf4, 0x94, 0x4a, 0xab, 0xef, 0x5f, 0x76, 0xd5, 0xac, 0x6e, 0x17, 0x11, 0xf4, 0xdf, 0x78, 0xfa, 0x6f, 0xfc, 0xbf, 0x6a, 0x1f, 0xf4, 0xcd, 0x78, 0xfa, 0x63, 0xfc, 0x7f, 0x6d, 0x27, 0xa6, 0x6e, 0xca, 0x42, 0x3e, 0xd1, 0x71, 0x07, 0x1e, 0x40, 0x3d, 0xd4, 0x07, 0xcf, 0x57, 0x35, 0x25, 0x9f, 0x3d, 0x84, 0x66, 0xa4, 0xb5, 0x87, 0xd1, 0x5c, 0xc6, 0xa8, 0x16, 0xf2, 0x93, 0x6a, 0x25, 0xa3, 0xd4, 0x5c, 0x39, 0xa8, 0xbe, 0x93, 0x54,\n\t0x35, 0x9f, 0x5c, 0x13, 0xc7, 0x6d, 0xed, 0x62, 0x57, 0x49, 0x32, 0x50, 0x39, 0x64, 0x85, 0xca, 0x96, 0x33, 0xca, 0xc9, 0xdf, 0x5d, 0x72, 0x48, 0xb1, 0xe6, 0x57, 0x37, 0xf8, 0xfb, 0x4d, 0xb1, 0xb1, 0x3e, 0x3c, 0xc9, 0x1c, 0xda, 0x91, 0x51, 0x7b, 0x96, 0xc9, 0xa0, 0x8c, 0x6e, 0x93, 0xf1, 0xcc, 0xa3, 0xe3, 0x29, 0xdb, 0xed, 0xcc, 0x8b, 0x9b, 0xfc, 0xa3, 0x4f, 0x27, 0x69, 0x41, 0x99, 0xb6, 0xa0, 0x4c, 0x5b, 0x50, 0xa6, 0x2d, 0x28, 0xbf, 0xf6, 0x94, 0x5f, 0x7b, 0xd3, 0x17, 0xb2, 0xcb, 0xe4, 0xfb, 0x2e, 0xe9, 0x29, 0xb4, 0x94, 0x39, 0xcc, 0x83, 0x73, 0x65, 0x8b, 0xc9, 0xf7, 0xfd, 0xbf, 0x6e, 0x8e, 0xc3, 0x18, 0xaa, 0x75, 0x91, 0x29, 0x5a, 0x77, 0x49, 0xd2, 0x5e, 0x60, 0xfb, 0x92, 0x14, 0x6a, 0x3d, 0x95, 0x55, 0x7b, 0x85, 0xcb, 0xf4, 0x4c, 0x6d, 0x20, 0xd7, 0xbd, 0x26,\n\t0xa3, 0xb4, 0x91, 0xec, 0xbf, 0x8b, 0xd1, 0xec, 0x7f, 0xc0, 0x7d, 0x7c, 0xbf, 0x84, 0xb6, 0x84, 0xbc, 0xb2, 0x46, 0xc6, 0x98, 0xd7, 0xc9, 0x97, 0xe6, 0x4d, 0xd4, 0x4d, 0x28, 0xe3, 0xef, 0x11, 0x19, 0x6f, 0x3e, 0xc1, 0x7e, 0x24, 0xdb, 0x28, 0xf9, 0x8c, 0xb9, 0x75, 0x3c, 0x73, 0x6b, 0x47, 0xe6, 0xd6, 0x8e, 0xe6, 0x78, 0x19, 0x67, 0xb6, 0x21, 0x99, 0xfd, 0x54, 0x29, 0x34, 0x3b, 0xfc, 0x23, 0xe3, 0x76, 0xea, 0x75, 0x3b, 0x23, 0xe3, 0x3e, 0x46, 0xc6, 0x7d, 0xd4, 0xed, 0x76, 0xe6, 0xd2, 0x4d, 0xcc, 0xa5, 0x9b, 0x18, 0x1d, 0xb7, 0x33, 0x3a, 0x6e, 0x67, 0x0e, 0xdd, 0xe4, 0x1f, 0xcb, 0x5f, 0xa4, 0xde, 0x5f, 0x42, 0x4f, 0x49, 0xa2, 0xde, 0x5b, 0x50, 0xef, 0x0f, 0xf8, 0x7f, 0x71, 0xf5, 0x2c, 0x97, 0xaf, 0xe2, 0x1a, 0xf9, 0xe3, 0x15, 0xd5, 0xc8, 0xd2, 0x4b, 0x3d, 0x62, 0xe9,\n\t0xcb, 0xb6, 0x9f, 0x7a, 0xcc, 0x32, 0x94, 0xed, 0x30, 0x2e, 0x0f, 0x67, 0xfb, 0x06, 0x97, 0xc7, 0x70, 0x9b, 0x8f, 0xf0, 0x31, 0xc6, 0xe2, 0x13, 0x7c, 0x8a, 0xcf, 0xb0, 0x92, 0xdb, 0xfc, 0xf5, 0x7b, 0xe9, 0x8d, 0xfe, 0xfc, 0xbd, 0xf4, 0x0d, 0xaa, 0xa6, 0x65, 0x33, 0x7f, 0xdf, 0x82, 0x10, 0x84, 0x22, 0x0c, 0x5b, 0xb1, 0x0d, 0x7b, 0xb9, 0xed, 0x5f, 0xbf, 0xa3, 0xfe, 0xba, 0xe5, 0x00, 0x97, 0xff, 0xfa, 0x1d, 0xf5, 0xd7, 0x2d, 0x11, 0xaa, 0xbe, 0xe5, 0x28, 0xd7, 0xfd, 0xf5, 0x1b, 0xea, 0xaf, 0x5b, 0x22, 0xb9, 0xfc, 0xd7, 0x6f, 0xa8, 0xbf, 0x6e, 0x39, 0xad, 0x5a, 0xdf, 0xf2, 0x1b, 0xea, 0xef, 0x5b, 0x72, 0xb8, 0xfc, 0xd7, 0x6f, 0xa8, 0xbf, 0x6f, 0xb9, 0xa0, 0x6e, 0xb3, 0x5c, 0x54, 0x4d, 0xf4, 0xdb, 0x25, 0x49, 0xa7, 0xbd, 0xe9, 0x77, 0xe2, 0x2e, 0xd4, 0x44, 0x2d, 0xd4,\n\t0x46, 0x1d, 0x30, 0x33, 0xe9, 0x75, 0x71, 0x0f, 0xee, 0xc5, 0x7d, 0xb8, 0x1f, 0xb4, 0x4f, 0x9d, 0xf6, 0xa9, 0xd3, 0x3e, 0xf5, 0x06, 0x68, 0x08, 0xda, 0xa9, 0xde, 0x08, 0x8d, 0xd1, 0x04, 0x4d, 0xf1, 0x10, 0x9a, 0xe1, 0x61, 0x34, 0x47, 0x0b, 0xb4, 0x84, 0xff, 0xdf, 0xdf, 0xfe, 0xf9, 0x7b, 0xed, 0xbf, 0xeb, 0x6d, 0xd5, 0x3c, 0xfd, 0x51, 0xb5, 0x5a, 0x6f, 0xc7, 0xdf, 0xda, 0x4b, 0x3e, 0xbd, 0x3e, 0x49, 0xef, 0x80, 0x7e, 0x32, 0x5e, 0xef, 0x8f, 0x01, 0x18, 0x88, 0x41, 0x18, 0x82, 0x57, 0x31, 0x14, 0xc3, 0xf0, 0x9a, 0xa4, 0xeb, 0xaf, 0x63, 0x38, 0xde, 0xc0, 0x08, 0x8c, 0xc4, 0x28, 0xbc, 0x89, 0xb7, 0xf0, 0x36, 0xde, 0xc1, 0xbb, 0x78, 0x0f, 0xef, 0x63, 0x34, 0x68, 0x7b, 0xfa, 0x87, 0x18, 0x83, 0x8f, 0xf0, 0x31, 0xc6, 0xe2, 0x13, 0x8c, 0x93, 0x31, 0xfa, 0xa7, 0xf8, 0x4c,\n\t0x7e, 0xd2, 0x3f, 0xc7, 0x17, 0x18, 0x8f, 0x09, 0x98, 0x88, 0x29, 0x32, 0x4a, 0x9f, 0x8a, 0x69, 0xf8, 0x1a, 0xd3, 0xf1, 0x8d, 0xaa, 0xa7, 0xcf, 0x60, 0xfb, 0x2d, 0x66, 0x62, 0x16, 0x66, 0x63, 0x0e, 0xfe, 0xfe, 0x37, 0xe1, 0x97, 0xea, 0xdf, 0xab, 0xc7, 0xf4, 0x05, 0xaa, 0xa5, 0xbe, 0x90, 0xbf, 0x2d, 0x42, 0xb0, 0xbc, 0x65, 0x64, 0xc8, 0x41, 0x23, 0x13, 0x59, 0x92, 0x6a, 0x64, 0xe3, 0x34, 0xce, 0xe0, 0x2c, 0x9c, 0xc8, 0xc1, 0x45, 0xd9, 0x6b, 0xb8, 0xe0, 0xc6, 0x25, 0xe4, 0x22, 0x0f, 0xf9, 0xb8, 0x0c, 0x0f, 0x0a, 0x50, 0x88, 0x22, 0x14, 0xa3, 0x04, 0xa5, 0xb2, 0xb7, 0xfa, 0x37, 0xe1, 0x57, 0xfa, 0x7f, 0x13, 0xfe, 0x1f, 0x7f, 0x0f, 0x7e, 0xa5, 0xff, 0xf7, 0xe0, 0x6f, 0xfd, 0x2d, 0xf8, 0x83, 0xfe, 0xdc, 0x6b, 0x63, 0x4d, 0x68, 0x63, 0x4d, 0x68, 0x63, 0x4d, 0x68, 0x63,\n\t0x4d, 0xd8, 0x91, 0xb5, 0xdf, 0x26, 0x6b, 0x3e, 0x7f, 0x63, 0x1c, 0xb5, 0x7a, 0x50, 0x80, 0x42, 0x14, 0xb1, 0xbe, 0x29, 0x46, 0x09, 0x4a, 0x51, 0x26, 0xe9, 0x41, 0xdd, 0xe5, 0xd1, 0xa0, 0x5d, 0x4a, 0x0b, 0xfa, 0x59, 0xc6, 0xfc, 0x4f, 0x7e, 0x47, 0x7e, 0x4c, 0xd0, 0x3e, 0xec, 0x57, 0xed, 0x83, 0x0e, 0x4a, 0x61, 0xd0, 0x21, 0xc6, 0xa8, 0xa9, 0x8c, 0x78, 0x2b, 0x18, 0xf1, 0x0e, 0x30, 0xd2, 0xe5, 0x30, 0xd2, 0x79, 0x18, 0xe9, 0x7c, 0xaf, 0xda, 0xf8, 0x72, 0xde, 0x56, 0x46, 0xab, 0x15, 0x8c, 0x56, 0x2b, 0x18, 0x49, 0xf6, 0x32, 0x82, 0xf8, 0x46, 0x8d, 0x95, 0x8c, 0x14, 0x2b, 0x18, 0x25, 0x56, 0x30, 0x4a, 0xfc, 0xc6, 0x28, 0xb1, 0x82, 0x9e, 0x5b, 0x8b, 0x9e, 0x5b, 0x9f, 0x9e, 0x5b, 0x8b, 0x9e, 0xdb, 0x94, 0x9e, 0x5b, 0x8b, 0x9e, 0x5b, 0x9f, 0x9e, 0x5b, 0x8b, 0x9e, 0xdb,\n\t0x94, 0xde, 0x59, 0x8b, 0xde, 0x19, 0x4e, 0xef, 0x4c, 0xa0, 0x77, 0xd6, 0xa2, 0x77, 0x86, 0xd3, 0x3b, 0x13, 0xe9, 0x7d, 0xb5, 0xe8, 0x7d, 0xe1, 0xf4, 0xbe, 0x04, 0x7a, 0x5f, 0x2f, 0x7a, 0x5f, 0x2d, 0x7a, 0x5f, 0x38, 0xbd, 0x2f, 0x91, 0xde, 0xd7, 0x8b, 0xde, 0x77, 0x07, 0xbd, 0xaf, 0x16, 0xbd, 0x2f, 0x9c, 0xde, 0x97, 0x40, 0xef, 0xeb, 0x45, 0xef, 0xab, 0x45, 0xef, 0x0b, 0xa7, 0xf7, 0x25, 0xd2, 0xfb, 0x7a, 0xd1, 0xfb, 0x1a, 0xd0, 0xfb, 0x62, 0xe8, 0x7d, 0x67, 0xe8, 0x7d, 0x43, 0xe9, 0x7d, 0x0d, 0xe8, 0x7d, 0x89, 0xf4, 0xbe, 0x1c, 0x7a, 0xdf, 0x50, 0x7a, 0x5e, 0x1d, 0x5a, 0xff, 0x72, 0x5a, 0x7f, 0x18, 0x2d, 0x7f, 0x39, 0x2d, 0x7f, 0x1b, 0x2d, 0x7d, 0x05, 0x2d, 0x7d, 0x05, 0x2d, 0x7d, 0x05, 0x2d, 0x7d, 0x05, 0x2d, 0x7d, 0x05, 0x2d, 0x7d, 0x05, 0x2d, 0x7d, 0x05, 0x2d,\n\t0x7d, 0x05, 0x2d, 0x7d, 0x05, 0x2d, 0x32, 0x87, 0x16, 0x99, 0x43, 0x8b, 0xf4, 0xd0, 0x22, 0x3d, 0xb4, 0x48, 0x0f, 0x2d, 0xd2, 0x43, 0x8b, 0xf4, 0xd0, 0x22, 0x3d, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0x26, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0xbd, 0xb4, 0xc8, 0xf6, 0xb4, 0xc8, 0x27, 0x69, 0x91, 0xed, 0x68, 0x91, 0x53, 0x69, 0x91, 0x2d, 0x68, 0x91, 0x8d, 0x69, 0x91, 0x7b, 0x69, 0x91, 0x7b, 0x69, 0x91, 0xbf, 0xd1, 0x62, 0xa6, 0xd3, 0x62, 0xe6, 0xd3, 0x62, 0x6a, 0xd2, 0x62, 0xa6, 0xd3, 0x62, 0x16, 0xd3, 0x62, 0x6a, 0xd2, 0x62, 0xa6, 0xd3, 0x62, 0xe6, 0xd3, 0x62, 0x6a, 0xd2, 0x62, 0xa6, 0xd3, 0x62, 0x16, 0xd3, 0x62, 0x6a, 0xd2, 0x5a, 0x2e,\n\t0xd2, 0x5a, 0x2e, 0xd2, 0x5a, 0x2e, 0xd2, 0x5a, 0x2e, 0x52, 0xfb, 0x97, 0x82, 0x76, 0xc9, 0x55, 0x6a, 0x7f, 0x25, 0xb5, 0xdf, 0x9c, 0xda, 0xef, 0x40, 0xed, 0x8f, 0x0d, 0xda, 0x23, 0x42, 0xed, 0xd7, 0xa1, 0xf6, 0x57, 0x52, 0xfb, 0x2b, 0xa9, 0xfd, 0x7b, 0xd5, 0x93, 0xd4, 0xfa, 0x52, 0x6a, 0x7d, 0xff, 0x2d, 0xb5, 0xbe, 0xa7, 0xba, 0xd6, 0x43, 0xa8, 0xf5, 0xa5, 0xd4, 0xfa, 0x52, 0x6a, 0x7d, 0x0f, 0xb5, 0xbe, 0x87, 0x1a, 0x5f, 0x4a, 0x8d, 0x2f, 0xad, 0xae, 0xf1, 0xa5, 0x94, 0xe0, 0x52, 0x4a, 0x70, 0x29, 0x25, 0xb8, 0x94, 0x12, 0x5c, 0x4a, 0x09, 0x2e, 0xa5, 0x04, 0x97, 0x52, 0x82, 0x4b, 0x29, 0xc1, 0xa5, 0x94, 0xe0, 0xd2, 0x7f, 0xa3, 0x04, 0xf7, 0x50, 0x82, 0x7b, 0x28, 0xc1, 0x3d, 0x94, 0xe0, 0x1e, 0x4a, 0x70, 0x0f, 0x25, 0xd8, 0x8e, 0x12, 0xdc, 0x43, 0x09, 0xee, 0xa1,\n\t0x04, 0xf7, 0x50, 0x82, 0x7b, 0x28, 0xc1, 0x3d, 0x94, 0xe0, 0x1e, 0x7d, 0xae, 0xe4, 0xea, 0xdf, 0x63, 0x01, 0x16, 0x72, 0x79, 0x11, 0x7c, 0xa5, 0xf6, 0x8f, 0xa5, 0xf0, 0xbb, 0x7f, 0x86, 0x77, 0x30, 0xc3, 0x3b, 0x98, 0xe1, 0x1d, 0xcc, 0xf0, 0x0e, 0x66, 0x78, 0x07, 0x33, 0xbc, 0x83, 0x19, 0xde, 0x71, 0xcb, 0x0c, 0x9f, 0xc5, 0x0c, 0x9f, 0x45, 0x09, 0x8c, 0xa5, 0x04, 0x96, 0x51, 0x02, 0xc3, 0x99, 0xe1, 0x0f, 0x33, 0xc3, 0xa7, 0x57, 0xcf, 0xf0, 0x0e, 0x66, 0xf8, 0x04, 0x66, 0xf8, 0x5e, 0xcc, 0xf0, 0x2b, 0x99, 0xe1, 0x7d, 0x9f, 0x64, 0x3f, 0xcc, 0x0c, 0x7f, 0x98, 0x19, 0xbe, 0x80, 0x19, 0xde, 0x41, 0x89, 0x45, 0x33, 0xc3, 0xc7, 0x30, 0xc3, 0x77, 0xa0, 0xe4, 0x66, 0x32, 0xc3, 0x3b, 0x6e, 0x99, 0xe1, 0x77, 0x30, 0xc3, 0x6f, 0x60, 0x86, 0x3f, 0xfa, 0x2f, 0x66, 0xf8, 0x5f,\n\t0x98, 0xe1, 0x53, 0x98, 0xe1, 0xdd, 0xcc, 0xf0, 0xc5, 0xcc, 0xf0, 0x21, 0xa6, 0x05, 0x6c, 0x17, 0x92, 0x47, 0xdc, 0x1c, 0xeb, 0x92, 0x64, 0x55, 0xcf, 0xf2, 0x8e, 0xea, 0x59, 0xbe, 0x94, 0x19, 0xde, 0xc1, 0x0c, 0xef, 0xa8, 0x9e, 0xe1, 0x87, 0x33, 0xc3, 0x3b, 0x98, 0xe1, 0xd3, 0xa8, 0xa9, 0xe1, 0xcc, 0xf0, 0x59, 0xcc, 0xf0, 0xf6, 0xea, 0x19, 0xfe, 0x43, 0x66, 0xf8, 0xa9, 0xcc, 0xf0, 0x0e, 0x66, 0xf8, 0x9c, 0xea, 0x19, 0xde, 0x51, 0x3d, 0xc3, 0x7f, 0x52, 0x3d, 0xc3, 0x77, 0x60, 0x86, 0xef, 0xc0, 0x0c, 0xff, 0x39, 0x33, 0xfc, 0xe7, 0xcc, 0xf0, 0x1d, 0x98, 0xe1, 0x4b, 0x99, 0xe1, 0x1d, 0xcc, 0xf0, 0x3b, 0x98, 0xe1, 0x77, 0x30, 0xc3, 0x1f, 0x62, 0x86, 0x3f, 0xc4, 0x0c, 0xbf, 0x83, 0x19, 0x7e, 0x03, 0x33, 0xfc, 0x06, 0x66, 0xf8, 0x9d, 0xcc, 0xf0, 0x3b, 0x99, 0xe1, 0x37,\n\t0x30, 0xc3, 0xc7, 0x31, 0xc3, 0x3b, 0x98, 0xe1, 0x1d, 0xcc, 0xf0, 0x8e, 0xea, 0x19, 0xbe, 0x0e, 0x33, 0xbc, 0x9d, 0x19, 0xde, 0xc1, 0x0c, 0xef, 0x60, 0x86, 0x77, 0xfc, 0x1b, 0x33, 0xbc, 0x83, 0x19, 0xde, 0xc1, 0x0c, 0xef, 0x60, 0x86, 0x77, 0x30, 0xc3, 0x3b, 0x98, 0xe1, 0x1d, 0xcc, 0xf0, 0x8e, 0xff, 0xc5, 0x0c, 0xef, 0x60, 0x86, 0x77, 0x30, 0xc3, 0x3b, 0x98, 0xe1, 0x1d, 0xcc, 0xf0, 0x0e, 0x66, 0x78, 0x07, 0x33, 0xbc, 0xe3, 0x3f, 0x3c, 0xc3, 0x3b, 0x98, 0xe1, 0x1d, 0xcc, 0xf0, 0x0e, 0x66, 0x78, 0x07, 0x33, 0xbc, 0x83, 0x19, 0xde, 0xc1, 0x0c, 0xef, 0x60, 0x86, 0x77, 0x30, 0xc3, 0x3b, 0x98, 0xe1, 0x1d, 0xcc, 0xf0, 0x0e, 0x66, 0x78, 0x07, 0x33, 0xbc, 0x83, 0x19, 0xde, 0xc1, 0x0c, 0xef, 0x60, 0x86, 0x77, 0x30, 0xc3, 0x3b, 0x98, 0xe1, 0x1d, 0xcc, 0xf0, 0x0e, 0x66, 0x78,\n\t0x07, 0x33, 0xbc, 0x83, 0x19, 0xde, 0xc1, 0x0c, 0xef, 0x60, 0x86, 0x77, 0x30, 0xc3, 0x3b, 0x98, 0xe1, 0x1d, 0xcc, 0xf0, 0x0e, 0x66, 0x78, 0x07, 0x33, 0xbc, 0x83, 0x19, 0xde, 0xc1, 0x0c, 0xef, 0xbe, 0x65, 0x86, 0x77, 0x33, 0xce, 0x2d, 0x64, 0x9c, 0x5b, 0xcf, 0x0c, 0xef, 0x60, 0x86, 0x2f, 0x64, 0x86, 0x77, 0x30, 0xc3, 0x3b, 0xfe, 0xcd, 0x19, 0x3e, 0x8b, 0x19, 0x3e, 0x8b, 0x19, 0x3e, 0x8b, 0x19, 0x3e, 0x4b, 0xf7, 0x7d, 0x47, 0xc1, 0x48, 0x8c, 0xc2, 0x9b, 0x78, 0x0b, 0x6f, 0xe3, 0x1d, 0xbc, 0x8b, 0xf7, 0xf0, 0x3e, 0x46, 0x83, 0xb6, 0xc7, 0x0c, 0x9f, 0xc5, 0x0c, 0x9f, 0xc5, 0x0c, 0x9f, 0xc5, 0x0c, 0x9f, 0xc5, 0x0c, 0x9f, 0xc5, 0x0c, 0x9f, 0xc5, 0x68, 0x30, 0x96, 0xd1, 0x60, 0x2c, 0xa3, 0xc1, 0x32, 0x46, 0x83, 0x65, 0x8c, 0x06, 0xcb, 0x18, 0x0d, 0x96, 0x31, 0x1a, 0x2c,\n\t0x63, 0x34, 0x58, 0xc6, 0x68, 0x30, 0x9c, 0xd1, 0x60, 0x38, 0xa3, 0xc1, 0x70, 0x46, 0x83, 0xe1, 0x8c, 0x06, 0xc3, 0xab, 0x67, 0xf8, 0xe1, 0x8c, 0x06, 0xc3, 0x19, 0x0d, 0x86, 0x33, 0x1a, 0x0c, 0x67, 0x34, 0x18, 0xce, 0x68, 0x30, 0xfc, 0x5f, 0xcc, 0xf0, 0xc3, 0x19, 0x19, 0x86, 0x33, 0x32, 0x8c, 0x64, 0x86, 0x3f, 0xcc, 0x0c, 0x7f, 0x98, 0x19, 0x3e, 0x9d, 0x19, 0x3e, 0x9d, 0x19, 0x3e, 0x9d, 0x19, 0x3e, 0x9d, 0x19, 0x3e, 0x9d, 0x19, 0x3e, 0x9d, 0x19, 0x3e, 0xfd, 0x3f, 0x3c, 0xc3, 0x3b, 0x18, 0xad, 0xa2, 0x19, 0xad, 0xa2, 0x19, 0xad, 0xa2, 0x19, 0xad, 0xa2, 0x99, 0xe1, 0x3b, 0x30, 0xc3, 0x6f, 0x60, 0x86, 0x77, 0x30, 0xc3, 0x3b, 0x98, 0xe1, 0x1d, 0xcc, 0xf0, 0x0e, 0x66, 0x78, 0x07, 0x33, 0x7c, 0x16, 0x33, 0x7c, 0x16, 0x33, 0x7c, 0x16, 0x33, 0x7c, 0x16, 0x33, 0x7c, 0x16,\n\t0xa3, 0x5b, 0xf3, 0xea, 0x19, 0xfe, 0xc3, 0xff, 0xc9, 0x0c, 0xff, 0x21, 0x63, 0xfc, 0x87, 0xd5, 0x33, 0x7c, 0x29, 0x33, 0xbc, 0x43, 0x75, 0x55, 0xcf, 0x90, 0x43, 0x46, 0xa9, 0x27, 0x54, 0xac, 0x7c, 0xa7, 0xe2, 0x65, 0x96, 0x4a, 0x67, 0x24, 0x63, 0xcd, 0xa3, 0x72, 0xe5, 0x37, 0x55, 0x46, 0x2e, 0xb9, 0x8b, 0x64, 0x5f, 0x47, 0x7e, 0xf5, 0x65, 0x67, 0xd2, 0x54, 0x0b, 0x46, 0x8b, 0x54, 0x73, 0x94, 0x32, 0x05, 0x46, 0xaa, 0x67, 0x02, 0x9d, 0xea, 0x1e, 0x4b, 0x07, 0x99, 0x65, 0x79, 0x5c, 0x96, 0x59, 0x7a, 0xb2, 0x7d, 0x85, 0x34, 0xdf, 0x0b, 0xbd, 0xd9, 0xef, 0x83, 0xbe, 0xec, 0xf7, 0x43, 0x7f, 0xf6, 0x07, 0x60, 0x20, 0x06, 0x61, 0x30, 0x86, 0xe0, 0x55, 0x0c, 0xe5, 0xef, 0xc3, 0xf0, 0x1a, 0xfb, 0xaf, 0x63, 0x38, 0xfb, 0x6f, 0x60, 0x04, 0xfb, 0xef, 0x48, 0x4f, 0xcb, 0x4e,\n\t0x35, 0xda, 0x12, 0xa7, 0xee, 0xb3, 0xc4, 0xab, 0x87, 0x2c, 0xc9, 0x6a, 0xb2, 0xe5, 0x94, 0xaa, 0x63, 0xb9, 0x4c, 0x6b, 0xac, 0xab, 0x7a, 0xd2, 0x0a, 0x92, 0xf5, 0x2d, 0xaa, 0x9b, 0xbe, 0x5f, 0x2a, 0x75, 0xa7, 0x6a, 0xa0, 0x5f, 0x66, 0x5d, 0x56, 0x5b, 0x35, 0x34, 0xea, 0xa9, 0x0e, 0xfe, 0x6f, 0x38, 0x6b, 0xac, 0xea, 0x1b, 0xcd, 0xd4, 0xe3, 0x46, 0x73, 0x15, 0x64, 0xb4, 0x56, 0x6b, 0x8c, 0x76, 0xea, 0x5e, 0xe3, 0x39, 0xff, 0x77, 0xe5, 0xdf, 0x63, 0xcc, 0x53, 0x1d, 0x49, 0x7c, 0x67, 0xac, 0xf7, 0xab, 0x87, 0xac, 0x1f, 0xf9, 0xbf, 0x09, 0xf8, 0xbf, 0xa7, 0x24, 0x66, 0xfd, 0x7f, 0xbe, 0x24, 0x1e, 0x52, 0x9a, 0x14, 0x53, 0x1a, 0xa9, 0x94, 0x46, 0x43, 0xf5, 0xa6, 0xff, 0xdd, 0xbd, 0x59, 0x3c, 0xf3, 0xed, 0xfe, 0x57, 0x93, 0xda, 0xfa, 0x3f, 0xf9, 0xd5, 0x82, 0x54, 0x1d,\n\t0x6c, 0xa2, 0xf7, 0x9b, 0x46, 0x49, 0x81, 0x36, 0xce, 0xff, 0x7b, 0x15, 0x8f, 0x71, 0x96, 0xdd, 0x38, 0x3b, 0x9d, 0xb3, 0x9a, 0xc0, 0xd9, 0x34, 0xe1, 0x6c, 0x9c, 0xba, 0x53, 0xc4, 0xff, 0x4d, 0xf8, 0xf5, 0x54, 0x13, 0xce, 0xe4, 0x69, 0xa3, 0xa1, 0x6a, 0x6e, 0x3c, 0xa8, 0x5a, 0x19, 0x8d, 0x78, 0x64, 0xdf, 0x6f, 0xe3, 0x34, 0x51, 0xf5, 0x8c, 0xa6, 0x5c, 0x6e, 0xe6, 0xff, 0xfe, 0xff, 0x67, 0x8d, 0x47, 0x54, 0x03, 0xce, 0x70, 0x3e, 0x67, 0xf8, 0x9c, 0xf1, 0x96, 0x54, 0x70, 0x76, 0xcd, 0x38, 0xbb, 0x34, 0xce, 0xa4, 0xae, 0x94, 0x33, 0xe7, 0x9e, 0x61, 0xce, 0x1d, 0xc5, 0x9c, 0xbb, 0x88, 0xba, 0xf1, 0xfd, 0xdb, 0xa0, 0xbd, 0xcc, 0xb9, 0xbf, 0x32, 0xe7, 0x5e, 0xf0, 0xbf, 0xdb, 0x12, 0x28, 0xdf, 0x33, 0xa7, 0xee, 0x23, 0xed, 0x3e, 0xa4, 0xf5, 0x53, 0xf7, 0x33, 0xf7, 0x9d,\n\t0x62, 0xce, 0x3b, 0x49, 0x5d, 0x65, 0x33, 0xaf, 0x4d, 0x66, 0x3e, 0x3a, 0xce, 0x1c, 0xd4, 0x9a, 0x39, 0xa8, 0x39, 0x73, 0xd0, 0x49, 0xfd, 0x11, 0xc6, 0xc0, 0xb6, 0x78, 0x14, 0x03, 0x64, 0x9a, 0x7f, 0x5c, 0x99, 0x2b, 0x51, 0xac, 0x26, 0xa2, 0x58, 0x4d, 0x44, 0x19, 0x6b, 0xd4, 0x1d, 0xf4, 0xab, 0x76, 0xff, 0xb1, 0x47, 0xbf, 0xed, 0x9f, 0x3e, 0xfa, 0x6d, 0xac, 0x49, 0x7e, 0xe4, 0xe8, 0x53, 0x38, 0xca, 0x66, 0x8e, 0x50, 0xc2, 0x11, 0x4a, 0x28, 0xe5, 0x02, 0xee, 0x35, 0x86, 0x7b, 0x35, 0xe6, 0x5e, 0xd9, 0xdc, 0x2b, 0x9b, 0x7b, 0x65, 0x73, 0x8f, 0xcf, 0x54, 0x7d, 0xee, 0x31, 0x43, 0xd9, 0x58, 0x89, 0x24, 0x4a, 0x3c, 0xe7, 0x1b, 0xa5, 0xce, 0x48, 0x0c, 0xe7, 0xeb, 0x51, 0xbf, 0x53, 0xb7, 0x2e, 0xff, 0xf7, 0x3d, 0xa5, 0x52, 0xaf, 0x27, 0x39, 0xea, 0x27, 0xa6, 0x20, 0x49,\n\t0xa7, 0x7e, 0x8f, 0x73, 0xee, 0xb4, 0x68, 0x09, 0xae, 0x7e, 0x47, 0xa9, 0x98, 0x47, 0xfa, 0x85, 0x47, 0xfa, 0x85, 0x7a, 0xcd, 0xe3, 0xd1, 0x7e, 0xe6, 0xd1, 0x46, 0xea, 0x93, 0x24, 0x96, 0x47, 0xac, 0xcf, 0x23, 0xc6, 0xf2, 0x88, 0xb1, 0x3c, 0x62, 0xac, 0xbe, 0x84, 0xd1, 0xa4, 0xbb, 0x0c, 0x34, 0x87, 0x2a, 0xb3, 0x2c, 0x50, 0x01, 0x08, 0x94, 0x0f, 0x59, 0x67, 0x79, 0x58, 0x67, 0x79, 0x58, 0x67, 0x79, 0x54, 0x6d, 0x4a, 0xec, 0x01, 0xb6, 0xf5, 0x50, 0x1f, 0x0f, 0xa2, 0xb9, 0x32, 0x54, 0x2b, 0x65, 0x55, 0xad, 0xe5, 0x67, 0xd5, 0x06, 0x6d, 0xd1, 0x4e, 0x36, 0xab, 0xf6, 0x78, 0x0c, 0x1d, 0xf0, 0x38, 0x9e, 0xc0, 0x93, 0x78, 0x0a, 0x4f, 0xe3, 0x19, 0x89, 0x50, 0x1d, 0xd9, 0x76, 0xc2, 0xff, 0xfb, 0xdf, 0xf3, 0xba, 0x5d, 0x8d, 0x90, 0x2d, 0xea, 0x03, 0x4a, 0xf7, 0x23, 0x7c,\n\t0x8c, 0xb1, 0xf8, 0x84, 0x73, 0x1b, 0x87, 0x4f, 0xf1, 0x19, 0x97, 0xbf, 0x60, 0x3b, 0x9e, 0xed, 0x04, 0x5a, 0xcc, 0x44, 0x4c, 0xc2, 0x64, 0x54, 0x7d, 0x27, 0x6c, 0xae, 0x9a, 0x8a, 0x69, 0xf8, 0x1a, 0xd3, 0xf1, 0x0d, 0x66, 0xe0, 0x5b, 0xcc, 0xc4, 0x2c, 0xcc, 0x66, 0xbd, 0x39, 0x07, 0xf3, 0xa8, 0xbd, 0xef, 0x19, 0x9b, 0x62, 0xe5, 0x07, 0xe5, 0xfb, 0xac, 0x47, 0x3c, 0xe5, 0x6d, 0xe7, 0x38, 0xc9, 0x72, 0x49, 0x91, 0x08, 0xab, 0xbf, 0xeb, 0x23, 0x83, 0x5a, 0xff, 0x9d, 0x31, 0x2c, 0x49, 0x65, 0xc8, 0x2f, 0xea, 0x14, 0xfb, 0x59, 0x1c, 0x23, 0x5b, 0xe2, 0xd4, 0x69, 0x5a, 0xc4, 0x59, 0xb6, 0xe7, 0xb8, 0xfc, 0xbb, 0x9c, 0x56, 0xe7, 0xb9, 0xcf, 0x05, 0xce, 0xef, 0x22, 0x7c, 0xdf, 0x30, 0xe2, 0xe6, 0x31, 0x2e, 0xb1, 0x9f, 0x2b, 0xeb, 0xab, 0xbf, 0xf3, 0x24, 0x41, 0x31, 0xdf,\n\t0xd1, 0x5a, 0x56, 0xa8, 0x4a, 0x59, 0xa7, 0xae, 0xe1, 0x06, 0x8f, 0xeb, 0xfb, 0x14, 0xa0, 0x48, 0x3e, 0xeb, 0x5a, 0x0f, 0x2d, 0xe8, 0xa2, 0xe9, 0x4e, 0x5a, 0xd1, 0x5d, 0x72, 0xd6, 0x54, 0x93, 0x35, 0x6f, 0x2d, 0xd4, 0x46, 0x1d, 0xf9, 0xdc, 0x74, 0xb7, 0x64, 0x98, 0xea, 0xd2, 0xba, 0xee, 0xe1, 0xf2, 0xbd, 0xb8, 0x4f, 0x3e, 0x36, 0xdd, 0x8f, 0x07, 0xd8, 0xaf, 0x87, 0xfa, 0x68, 0x20, 0x9b, 0x4d, 0x0d, 0xd9, 0xd2, 0x2e, 0x4c, 0x8d, 0xd9, 0x6f, 0xc2, 0x7e, 0x53, 0x3c, 0x24, 0x2e, 0x53, 0x33, 0xb6, 0x0f, 0xc3, 0xf7, 0xae, 0x64, 0x0b, 0xb6, 0x2d, 0xd1, 0x4a, 0x4e, 0x98, 0x1e, 0xe1, 0x76, 0xad, 0xd9, 0x6f, 0x23, 0x1b, 0x4d, 0x3d, 0xfe, 0x78, 0xd6, 0xf4, 0xb9, 0x1c, 0x62, 0xcd, 0x1c, 0x67, 0x1a, 0xcf, 0xdf, 0x26, 0xf0, 0x78, 0x13, 0xe5, 0x0b, 0xd3, 0x24, 0xd9, 0x67, 0x9a,\n\t0x4c, 0x56, 0x9d, 0xc2, 0x98, 0x3d, 0x9f, 0xf5, 0xb4, 0x9b, 0xe3, 0xe7, 0x72, 0xbf, 0x3c, 0x49, 0x30, 0x15, 0xcb, 0x19, 0x53, 0x09, 0xe7, 0x5b, 0x2a, 0x79, 0xac, 0xa1, 0x3d, 0xac, 0x9d, 0x3d, 0xac, 0x9d, 0x3d, 0xda, 0x6b, 0xca, 0xca, 0xba, 0xd9, 0xa3, 0x8d, 0x56, 0x26, 0xed, 0x73, 0xd9, 0xac, 0x51, 0x77, 0xda, 0x24, 0x89, 0xd1, 0xa6, 0x80, 0x3a, 0xd2, 0xa8, 0x23, 0xed, 0x1b, 0xc9, 0xd1, 0x66, 0xc9, 0x41, 0x6d, 0xb6, 0x6c, 0xd7, 0xe6, 0xf2, 0xf7, 0x79, 0x5c, 0x0e, 0x26, 0x07, 0xff, 0xc8, 0xfe, 0x2a, 0xf6, 0xff, 0xfd, 0xef, 0xe3, 0xcd, 0xd5, 0xb6, 0xe3, 0x37, 0x39, 0xc8, 0x5a, 0xdc, 0x63, 0xde, 0x2c, 0x19, 0xe6, 0x2d, 0xb2, 0xd9, 0x1c, 0x22, 0x89, 0x8c, 0x1a, 0x71, 0xe6, 0x6d, 0xb2, 0xc9, 0xbc, 0x1d, 0x3b, 0xb8, 0x6e, 0x17, 0x76, 0xe3, 0x04, 0xb7, 0x8b, 0x52, 0x9a,\n\t0x39, 0x51, 0xd6, 0xb1, 0x16, 0xf7, 0x98, 0xb3, 0xe4, 0x57, 0x73, 0x36, 0xce, 0x72, 0xf9, 0x82, 0xc4, 0x98, 0x2f, 0xc2, 0x05, 0x37, 0x2e, 0x71, 0xbc, 0x5c, 0xb6, 0x79, 0xc8, 0xc7, 0x65, 0x6e, 0xef, 0x61, 0x5b, 0x80, 0x42, 0x14, 0x71, 0xbc, 0x62, 0xae, 0x2b, 0x91, 0x02, 0xd6, 0xf1, 0x05, 0xe6, 0x32, 0xb9, 0xcc, 0x5a, 0xde, 0xc3, 0x5a, 0xde, 0xc5, 0x5a, 0xde, 0x65, 0xae, 0xe0, 0x36, 0x95, 0x72, 0x94, 0xf5, 0xfc, 0x51, 0xf3, 0x75, 0xf6, 0x6f, 0xc8, 0xc7, 0x66, 0x2f, 0xdb, 0x9b, 0xf8, 0x83, 0xbf, 0x93, 0x6f, 0x02, 0x94, 0x1c, 0x64, 0x64, 0xcb, 0x0b, 0xd0, 0x64, 0x73, 0x80, 0x99, 0xcb, 0x01, 0x08, 0x94, 0xcb, 0x8c, 0x20, 0x97, 0x03, 0x2c, 0x5c, 0x67, 0x95, 0x8f, 0x03, 0x82, 0xb8, 0xee, 0x45, 0xf1, 0x90, 0x03, 0x3c, 0xe4, 0x00, 0xdf, 0x67, 0xb3, 0x62, 0x02, 0xfa, 0xa0,\n\t0x1f, 0x06, 0x70, 0x9b, 0x81, 0x18, 0x0c, 0xfa, 0x52, 0xc0, 0x0a, 0x46, 0x9d, 0x66, 0xb2, 0x2d, 0xf0, 0x61, 0x39, 0x10, 0xd8, 0x5c, 0xbe, 0x0f, 0x6c, 0x21, 0x3f, 0x07, 0xb6, 0xe4, 0xba, 0x56, 0xb2, 0x2b, 0xf0, 0x11, 0xb4, 0x96, 0xfd, 0x81, 0x6d, 0x64, 0x76, 0x60, 0x5b, 0xb9, 0xf0, 0xe7, 0xf7, 0x18, 0x47, 0xaa, 0xce, 0xff, 0xec, 0xbb, 0x8c, 0xc9, 0x18, 0x1e, 0xe6, 0xe6, 0xfa, 0x81, 0xbf, 0x33, 0x6e, 0xd2, 0xa6, 0x03, 0x3d, 0x92, 0x10, 0x58, 0xc0, 0x28, 0x5c, 0xc8, 0xfe, 0x55, 0xfe, 0x56, 0xc1, 0xb6, 0x52, 0x22, 0xc9, 0x20, 0x9e, 0x1a, 0xb4, 0xb9, 0x1a, 0xcd, 0xe4, 0x66, 0x8d, 0x6b, 0xb2, 0xd9, 0xd2, 0x4a, 0x16, 0x58, 0x1e, 0x41, 0x6b, 0xb4, 0x41, 0x5b, 0x3c, 0x8a, 0x76, 0x68, 0x8f, 0xc7, 0xd0, 0x01, 0x8f, 0xcb, 0x1a, 0xcb, 0x13, 0x12, 0x6c, 0x79, 0x92, 0xfd, 0xa7,\n\t0xf0, 0x34, 0x9e, 0x41, 0x47, 0x74, 0xc2, 0xb3, 0x78, 0x0e, 0xcf, 0xa3, 0x33, 0xba, 0xa0, 0x2b, 0xba, 0xa1, 0x3b, 0x5e, 0x40, 0x0f, 0xbc, 0x88, 0x97, 0xd0, 0x53, 0xa2, 0xc9, 0x42, 0x0b, 0xc8, 0x42, 0x1b, 0x59, 0x3b, 0x44, 0xb3, 0x76, 0x38, 0x41, 0x26, 0x5a, 0x44, 0x26, 0xda, 0xc0, 0xda, 0xe1, 0x04, 0x6b, 0x87, 0xb5, 0xac, 0x1d, 0xfe, 0x60, 0xed, 0xb0, 0x80, 0xb5, 0xc3, 0x02, 0xd6, 0x0e, 0x0b, 0x58, 0x3b, 0x44, 0x93, 0x97, 0x16, 0x90, 0x97, 0x36, 0xb2, 0x76, 0x88, 0x66, 0xed, 0x70, 0x82, 0xdc, 0xb4, 0x88, 0xdc, 0xb4, 0x81, 0xb5, 0xc3, 0x09, 0xcb, 0x48, 0xce, 0x6f, 0x14, 0xde, 0xe4, 0xb6, 0x6f, 0xc9, 0x87, 0x96, 0xb7, 0xf1, 0x8e, 0x7c, 0x44, 0xa6, 0xf2, 0x90, 0xa9, 0x3c, 0x64, 0x2a, 0x0f, 0x99, 0xca, 0x43, 0xa6, 0xf2, 0x90, 0xa9, 0x3c, 0x64, 0x2a, 0x0f, 0x99, 0x2a,\n\t0xc2, 0xb2, 0xca, 0x14, 0x66, 0x59, 0x6d, 0x8a, 0x20, 0x53, 0xfd, 0x6a, 0x59, 0x6b, 0xda, 0x66, 0x59, 0x67, 0x3a, 0x6c, 0x59, 0x4f, 0xa6, 0xd9, 0xa0, 0xb6, 0x93, 0xab, 0x3c, 0xe4, 0x2a, 0x0f, 0xb9, 0xca, 0x43, 0xae, 0xf2, 0x90, 0xab, 0x3c, 0xe4, 0x2a, 0x0f, 0xb9, 0xca, 0xc3, 0x3a, 0xe5, 0x03, 0xb2, 0x55, 0x84, 0xe5, 0x37, 0xee, 0xbf, 0x8f, 0xfb, 0xef, 0x57, 0xfb, 0xc8, 0x56, 0xbf, 0x5a, 0x0e, 0x72, 0x8c, 0x43, 0x1c, 0x23, 0x9c, 0xfd, 0xc3, 0x1c, 0x27, 0x42, 0xed, 0x21, 0x5f, 0x45, 0x58, 0x8e, 0x71, 0xbb, 0xe3, 0xdc, 0xee, 0x04, 0xb7, 0x8b, 0xe4, 0x6f, 0x51, 0xdc, 0xee, 0x24, 0xb7, 0x8b, 0x66, 0x3f, 0x59, 0x7d, 0x49, 0xc6, 0x4a, 0xb4, 0x9c, 0x31, 0x1d, 0xb0, 0x9c, 0x35, 0x25, 0x92, 0xb1, 0xa2, 0xc9, 0x58, 0xc7, 0x2d, 0xe7, 0x4c, 0x87, 0x2c, 0xbf, 0x9b, 0x12, 0xc8,\n\t0x58, 0xc7, 0xc9, 0x58, 0x5f, 0x91, 0xb1, 0x4e, 0x5a, 0xf2, 0x65, 0x11, 0xb3, 0xd4, 0x22, 0x8b, 0x47, 0x16, 0x91, 0xb7, 0x3c, 0xe4, 0x2d, 0x0f, 0x79, 0xcb, 0x43, 0xde, 0xf2, 0x90, 0xb7, 0x3c, 0xe4, 0x2d, 0x0f, 0x79, 0xcb, 0x43, 0xde, 0xf2, 0x90, 0xb7, 0x3c, 0xac, 0x9b, 0xba, 0x91, 0xb7, 0x3c, 0xe4, 0x2d, 0x0f, 0x79, 0xcb, 0x43, 0xde, 0xf2, 0x90, 0xb7, 0x3c, 0xe4, 0x2d, 0x0f, 0x79, 0xcb, 0x43, 0xde, 0xf2, 0x90, 0xb7, 0x3c, 0xe4, 0x2d, 0x0f, 0x79, 0xcb, 0x43, 0xde, 0xf2, 0x90, 0xb7, 0x3c, 0xe4, 0x2d, 0x0f, 0x79, 0xcb, 0x43, 0xde, 0xf2, 0x90, 0xb7, 0x3c, 0xe4, 0x2d, 0x0f, 0x79, 0xcb, 0x43, 0xde, 0xf2, 0xe8, 0xad, 0xd4, 0x4a, 0xfd, 0x11, 0xd3, 0x4c, 0xbd, 0xb5, 0x69, 0x85, 0xde, 0x86, 0xac, 0xd5, 0xd6, 0x34, 0x5b, 0x7f, 0xd4, 0xb4, 0x5c, 0x6f, 0xa7, 0x7a, 0xeb, 0xed,\n\t0xd5, 0x6a, 0xf2, 0x96, 0x87, 0xbc, 0xe5, 0xd1, 0xc7, 0x29, 0x43, 0xff, 0x14, 0x53, 0x94, 0x55, 0x9f, 0x8a, 0x69, 0xf8, 0x1a, 0xd3, 0xf1, 0x8d, 0x3a, 0xa5, 0xcf, 0x60, 0xfb, 0x2d, 0x66, 0x62, 0x16, 0x66, 0x63, 0x0e, 0xe6, 0x9a, 0x6a, 0xeb, 0xdf, 0x69, 0x4d, 0xf4, 0x79, 0x5a, 0x7d, 0x7d, 0x3e, 0xfb, 0xdf, 0xab, 0x4b, 0xfa, 0x02, 0x53, 0x4d, 0x7d, 0x21, 0x7f, 0x5b, 0x84, 0x60, 0x56, 0x10, 0xcb, 0x99, 0xa9, 0x57, 0x60, 0x25, 0x56, 0x61, 0x35, 0xd6, 0x60, 0x2d, 0xd6, 0x61, 0x3d, 0x36, 0x60, 0x23, 0x36, 0x61, 0x33, 0xb6, 0xa8, 0x36, 0x7a, 0x08, 0xdb, 0x50, 0x84, 0x61, 0x2b, 0xb6, 0x61, 0x3b, 0x76, 0x60, 0x27, 0x76, 0xe1, 0x67, 0xfc, 0x82, 0x5f, 0xb1, 0x1b, 0x7b, 0xf1, 0x1b, 0xf6, 0x61, 0x3f, 0xcf, 0xeb, 0x00, 0xdb, 0x83, 0x38, 0x84, 0x70, 0x1c, 0x93, 0xcd, 0xfa, 0x71,\n\t0x9c, 0x40, 0x24, 0x58, 0xbf, 0xe8, 0xd1, 0x88, 0x41, 0x2c, 0xe2, 0x10, 0x0f, 0x1b, 0x12, 0x61, 0x47, 0x12, 0x92, 0x91, 0x82, 0x54, 0xa4, 0xc1, 0x81, 0x74, 0x64, 0x20, 0x13, 0x59, 0xc8, 0xc6, 0x69, 0x9c, 0xc1, 0x59, 0x38, 0x95, 0x45, 0xcf, 0x61, 0x7b, 0x0e, 0xf4, 0x77, 0xfd, 0x3c, 0x98, 0xd3, 0x74, 0x17, 0xdc, 0xa0, 0xff, 0xeb, 0x8c, 0xfd, 0x7a, 0x1e, 0xf2, 0x71, 0x99, 0x15, 0xd8, 0x7f, 0xdf, 0xf7, 0x9c, 0x6f, 0x37, 0x14, 0x4c, 0xd0, 0x60, 0x46, 0x00, 0x02, 0x51, 0x43, 0xb6, 0x18, 0x16, 0xe8, 0x30, 0x60, 0x95, 0xcd, 0xc6, 0xed, 0x6c, 0xef, 0xc0, 0x9d, 0xf0, 0xfd, 0x16, 0x8c, 0xef, 0xdb, 0x94, 0x1b, 0xb1, 0x4a, 0xf6, 0xad, 0xd3, 0x9b, 0xb0, 0x46, 0x6f, 0xea, 0xff, 0x1d, 0xa8, 0x8e, 0xfe, 0x6f, 0xee, 0x6e, 0xad, 0x8e, 0x1a, 0x4f, 0x4b, 0x9c, 0xd1, 0x4d, 0x62, 0x8c,\n\t0xee, 0x78, 0x01, 0x3d, 0xf0, 0x32, 0x7a, 0xe2, 0x15, 0x30, 0x9e, 0x1a, 0xbd, 0xc1, 0x98, 0x6a, 0xf4, 0x05, 0xe3, 0xaa, 0xd1, 0x1f, 0x03, 0x31, 0x88, 0xc7, 0x63, 0x6c, 0x35, 0x86, 0xe0, 0x55, 0x0c, 0xc5, 0x30, 0xbc, 0x86, 0xd7, 0x31, 0x1c, 0x6f, 0x60, 0x04, 0x46, 0x62, 0x14, 0xde, 0xc4, 0x5b, 0xac, 0xdc, 0xdf, 0x66, 0xfb, 0x0e, 0xde, 0xc5, 0x7b, 0x78, 0x1f, 0xa3, 0xf1, 0x01, 0x3e, 0xc4, 0x18, 0x7c, 0x84, 0x8f, 0x31, 0x16, 0xac, 0x7b, 0x0c, 0xd6, 0x3d, 0x06, 0xeb, 0x1e, 0xe3, 0x33, 0x30, 0x7f, 0x1a, 0xcc, 0x9f, 0xc6, 0x78, 0x4c, 0xc0, 0x44, 0x4c, 0xc2, 0x64, 0x89, 0x30, 0xbe, 0x64, 0xfb, 0x15, 0xe7, 0xc7, 0xbc, 0x6a, 0x4c, 0xc5, 0x74, 0x7c, 0x83, 0x19, 0x92, 0x66, 0x7c, 0xcb, 0x76, 0x26, 0x66, 0x61, 0x36, 0xe6, 0xe0, 0x3b, 0xcc, 0x53, 0x2d, 0x8d, 0xf9, 0x64, 0xec,\n\t0xef, 0xb1, 0x00, 0x0b, 0xb1, 0x08, 0xcc, 0xbd, 0xc6, 0x0f, 0x58, 0x8c, 0x1f, 0xb1, 0x04, 0xcb, 0x24, 0xd7, 0x58, 0x8e, 0x15, 0x58, 0x89, 0x55, 0x58, 0x8d, 0x35, 0x58, 0x8b, 0x75, 0x58, 0x8f, 0x0d, 0xd8, 0x88, 0x4d, 0xd8, 0x8c, 0x2d, 0x08, 0x41, 0x28, 0xc2, 0xb0, 0x15, 0xcc, 0xd3, 0x06, 0xf3, 0xb4, 0xb1, 0x03, 0x3b, 0xb1, 0x0b, 0x3f, 0xe3, 0x17, 0xfc, 0x8a, 0xdd, 0xd8, 0x83, 0xbd, 0xf8, 0x0d, 0xfb, 0xb0, 0x1f, 0x07, 0x70, 0x10, 0x87, 0x10, 0x8e, 0xc3, 0x88, 0xc0, 0x11, 0x49, 0x30, 0x8e, 0xe2, 0x18, 0x8e, 0xe3, 0x04, 0x22, 0x11, 0x85, 0x93, 0x88, 0x16, 0xb7, 0x11, 0xc3, 0x36, 0x16, 0x71, 0x88, 0x87, 0x0d, 0x09, 0x48, 0x84, 0x1d, 0x49, 0x48, 0x46, 0x0a, 0x52, 0xe1, 0x40, 0xba, 0x64, 0x18, 0xe7, 0xe4, 0xb2, 0xf1, 0x3b, 0xce, 0xa3, 0x4c, 0x72, 0x8c, 0x2b, 0x28, 0xc7,\n\t0x55, 0x54, 0xa0, 0x52, 0x72, 0xc8, 0x7a, 0xad, 0xac, 0x0f, 0x88, 0xdb, 0x5a, 0x4f, 0xbd, 0x6d, 0xad, 0x6f, 0xea, 0x6d, 0x6d, 0x60, 0x7a, 0xdb, 0xda, 0x50, 0x8d, 0xb0, 0x3e, 0xa8, 0x86, 0x59, 0x1b, 0x99, 0xfa, 0x5a, 0x1b, 0x9b, 0xde, 0xb4, 0x36, 0x61, 0xbf, 0xa9, 0x7a, 0xdc, 0xfa, 0x90, 0xfa, 0xd4, 0xda, 0x4c, 0x2e, 0x59, 0x1f, 0xe6, 0xb6, 0xcd, 0xb9, 0x6d, 0x0b, 0x6e, 0xdb, 0x92, 0xdb, 0xb6, 0xe2, 0xef, 0x8f, 0x70, 0xdb, 0xd6, 0xdc, 0xb6, 0x0d, 0xfb, 0x6d, 0x65, 0x93, 0xf5, 0x51, 0xb4, 0x43, 0x7b, 0x3c, 0x86, 0x0e, 0x78, 0x1c, 0x4f, 0xe0, 0x49, 0x3c, 0x85, 0xa7, 0xf1, 0x0c, 0x3a, 0xa2, 0x13, 0x9e, 0xc5, 0x73, 0x78, 0x1e, 0x9d, 0xd1, 0x05, 0x5d, 0xd1, 0x0d, 0xdd, 0xf1, 0x02, 0x7a, 0xe0, 0x45, 0xbc, 0x84, 0x97, 0xe5, 0x17, 0x6b, 0x4f, 0xbc, 0x82, 0x5e, 0xe8, 0x8d,\n\t0x3e, 0xe8, 0x8b, 0x7e, 0xe8, 0x8f, 0x01, 0xf2, 0xbb, 0x75, 0x20, 0x06, 0x61, 0x30, 0x86, 0xe0, 0x55, 0x0c, 0xc5, 0x30, 0xbc, 0x86, 0xd7, 0x31, 0x1c, 0x6f, 0x60, 0x04, 0x46, 0x62, 0x14, 0xde, 0xc4, 0x5b, 0x78, 0x1b, 0xef, 0xe0, 0x5d, 0xbc, 0x87, 0xf7, 0x31, 0x1a, 0x1f, 0xe0, 0x43, 0x8c, 0x91, 0x78, 0xf2, 0xf2, 0xfd, 0xd6, 0x4f, 0xd8, 0x8e, 0x93, 0x0a, 0xeb, 0xa7, 0x4a, 0xb3, 0x7e, 0xc6, 0xfe, 0xe7, 0xa8, 0xfa, 0xee, 0xbf, 0x00, 0xeb, 0x04, 0xf6, 0x27, 0x72, 0x9b, 0xaa, 0xef, 0x22, 0xaa, 0x6f, 0xfd, 0x92, 0xcb, 0x5f, 0x49, 0x96, 0x75, 0x0a, 0xb7, 0x9f, 0xaa, 0xee, 0xb6, 0x4e, 0x53, 0xad, 0xad, 0xd3, 0x79, 0x4e, 0xdf, 0x60, 0x86, 0x24, 0x58, 0xbf, 0xc5, 0x4c, 0xcc, 0x02, 0xeb, 0x7d, 0x2b, 0xeb, 0x7d, 0xeb, 0x5c, 0x7c, 0x87, 0x79, 0x98, 0x8f, 0xef, 0xb1, 0x00, 0x0b,\n\t0xb1, 0x08, 0xc1, 0xf8, 0x01, 0x8b, 0xf1, 0x23, 0x96, 0x60, 0x99, 0xec, 0xb5, 0x2e, 0xc7, 0x0a, 0xac, 0xc4, 0x2a, 0xac, 0xc6, 0x1a, 0xac, 0xc5, 0x3a, 0xac, 0xc7, 0x06, 0x6c, 0xc4, 0x26, 0x6c, 0xc6, 0x16, 0x84, 0x20, 0x14, 0x61, 0xd8, 0x8a, 0x6d, 0xd8, 0x8e, 0x1d, 0xd8, 0x89, 0x5d, 0x38, 0x28, 0x1e, 0xeb, 0x21, 0x75, 0x87, 0x35, 0x1c, 0x87, 0x11, 0x81, 0x48, 0x89, 0xb1, 0x46, 0x49, 0x86, 0xf5, 0x24, 0x62, 0xe5, 0xb8, 0x35, 0x8e, 0xcb, 0xf1, 0x48, 0x40, 0x22, 0xec, 0x48, 0x11, 0x97, 0x35, 0x95, 0x6d, 0x9a, 0x9c, 0xb0, 0x9e, 0x92, 0x22, 0x6b, 0x3e, 0xc7, 0x61, 0x4d, 0x6a, 0xf5, 0xa0, 0x00, 0x85, 0xb8, 0x22, 0x9b, 0xad, 0xe5, 0xb8, 0x0a, 0xd6, 0x67, 0xd6, 0x4a, 0x5c, 0xe3, 0x39, 0x5d, 0xc7, 0x0d, 0x78, 0x71, 0x53, 0x12, 0x82, 0x7e, 0x90, 0xc8, 0xa0, 0x5d, 0x6a, 0x4f,\n\t0xd0, 0x2f, 0xda, 0xdd, 0x41, 0xbf, 0x6a, 0x8d, 0x82, 0x76, 0x9b, 0x02, 0x83, 0xf6, 0xa8, 0xc4, 0xa0, 0xbd, 0xa6, 0x9a, 0x41, 0xfb, 0xd9, 0x3f, 0x24, 0x9e, 0xa0, 0xc3, 0x72, 0x30, 0x28, 0x42, 0x36, 0x07, 0x31, 0xbf, 0xa8, 0x20, 0x35, 0x4a, 0xdd, 0x43, 0x36, 0x6f, 0x45, 0x36, 0x6f, 0xc1, 0x8a, 0x31, 0x88, 0x59, 0xef, 0x29, 0x66, 0x8d, 0xbb, 0xfd, 0xbf, 0x0c, 0xd7, 0x5a, 0x8d, 0xf0, 0xfd, 0x22, 0x9c, 0xf1, 0x16, 0xd6, 0xa8, 0xbb, 0x4c, 0x8b, 0xc8, 0xaf, 0x2e, 0xf2, 0xab, 0x8b, 0xfc, 0xea, 0x22, 0xbb, 0xba, 0xc8, 0xae, 0x2e, 0xb2, 0xab, 0x8b, 0xec, 0xea, 0x52, 0x4d, 0x65, 0x3a, 0x09, 0xfb, 0x7b, 0xd5, 0x4c, 0xdc, 0xea, 0x61, 0x34, 0x97, 0x69, 0xaa, 0x05, 0x79, 0xa9, 0x95, 0x8c, 0x21, 0x93, 0xba, 0xc9, 0xa4, 0x6e, 0x32, 0xa9, 0x9b, 0x4c, 0xea, 0x26, 0x93, 0xba, 0xc9,\n\t0xa4, 0x6e, 0x32, 0xa9, 0x9b, 0x4c, 0xea, 0x26, 0x93, 0xba, 0xc9, 0xa4, 0x6e, 0x32, 0xa9, 0x9b, 0x4c, 0xea, 0x26, 0x93, 0xba, 0xc9, 0xa4, 0x6e, 0x32, 0xa9, 0x9b, 0x4c, 0xea, 0x26, 0x93, 0xba, 0xc9, 0xa4, 0x6e, 0x32, 0xa9, 0x9b, 0x4c, 0xea, 0x26, 0x93, 0xba, 0xc9, 0xa4, 0x6e, 0x32, 0xa9, 0x9b, 0x4c, 0xea, 0x26, 0x93, 0xba, 0xc9, 0xa4, 0x6e, 0x32, 0xa9, 0x9b, 0x4c, 0xea, 0x26, 0x93, 0xba, 0xc9, 0xa4, 0x6e, 0x32, 0xa9, 0x9b, 0x4c, 0xea, 0x26, 0x53, 0xba, 0xc9, 0x94, 0x4e, 0x32, 0xa5, 0x93, 0x4c, 0xe9, 0x24, 0x53, 0x3a, 0xc9, 0x94, 0x4e, 0x32, 0xa5, 0x93, 0x4c, 0xe9, 0x24, 0x53, 0x3a, 0xc9, 0x94, 0x4e, 0x32, 0xa5, 0x53, 0xcd, 0x95, 0x3d, 0xea, 0x3b, 0xb2, 0xe0, 0x7c, 0x39, 0x40, 0x96, 0x74, 0x91, 0x23, 0x2f, 0xaa, 0x24, 0x32, 0x6d, 0x1a, 0xc7, 0x70, 0x90, 0x6b, 0x4f,\n\t0xf9, 0xbf, 0x3b, 0xed, 0x3c, 0xb9, 0x31, 0x5a, 0x39, 0xb9, 0xad, 0xef, 0x3b, 0x45, 0x72, 0xc9, 0x99, 0xf9, 0xdc, 0xf6, 0x06, 0x6e, 0x92, 0x2f, 0x45, 0x12, 0x4d, 0x9a, 0xac, 0x31, 0x05, 0xca, 0x22, 0xb2, 0xa0, 0xcb, 0x74, 0x9b, 0x4c, 0x37, 0xdd, 0x0e, 0xdf, 0xe7, 0x6c, 0x1e, 0x94, 0x30, 0x32, 0xdc, 0x11, 0xb2, 0x9b, 0xef, 0xd3, 0x7b, 0xeb, 0x4d, 0xcf, 0xe3, 0x0d, 0x6e, 0x3b, 0x02, 0x5f, 0xc8, 0x1e, 0xd3, 0x97, 0x52, 0x6c, 0x9a, 0x43, 0x86, 0x9c, 0x4b, 0x46, 0x5b, 0xc8, 0xbe, 0x9b, 0xfb, 0x5c, 0x12, 0xb7, 0xd6, 0x85, 0x1c, 0xd5, 0x5d, 0x5c, 0xda, 0x0b, 0x6c, 0x7b, 0xaa, 0x6e, 0x64, 0x33, 0x17, 0xd9, 0xcc, 0xa5, 0x91, 0x13, 0xb4, 0xd7, 0x64, 0x0c, 0xf9, 0xcc, 0xa5, 0xbd, 0x2b, 0x67, 0xb5, 0xd1, 0xec, 0x7f, 0xc0, 0xed, 0x79, 0x9e, 0xe4, 0x32, 0xa7, 0x36, 0x5b, 0xdd,\n\t0xae, 0xcd, 0x21, 0xcf, 0x2d, 0x91, 0x03, 0x64, 0x30, 0x37, 0x19, 0xcc, 0x4d, 0x06, 0x73, 0x93, 0xc1, 0xdc, 0x64, 0x30, 0x37, 0x19, 0xcc, 0x4d, 0x06, 0x73, 0x93, 0xc1, 0xdc, 0x64, 0x30, 0x37, 0x19, 0xcc, 0x4d, 0x06, 0x73, 0x92, 0xc1, 0x9c, 0xe4, 0x2f, 0xdf, 0xb7, 0x6a, 0xba, 0xc9, 0x5d, 0xd1, 0xe6, 0x23, 0x32, 0x9d, 0x9c, 0xe5, 0x32, 0x47, 0xb2, 0x8d, 0x92, 0x79, 0xe6, 0x68, 0xb6, 0x31, 0xb2, 0xc6, 0x1c, 0x8b, 0x78, 0xd9, 0x6b, 0xb6, 0x21, 0x99, 0x7d, 0x07, 0xb7, 0xb9, 0x2c, 0x61, 0x64, 0xa8, 0x30, 0x32, 0xd4, 0x6f, 0x64, 0xa8, 0xdf, 0xc8, 0x4f, 0x61, 0xe4, 0xa7, 0x23, 0xe4, 0xa7, 0x23, 0x64, 0xa7, 0x08, 0xb2, 0x53, 0x04, 0x59, 0xe9, 0x88, 0x3f, 0x23, 0xbd, 0x28, 0x2e, 0x32, 0x90, 0x8b, 0x0c, 0xe4, 0x22, 0xdf, 0xe4, 0x04, 0x76, 0x90, 0xe0, 0xc0, 0xc7, 0x71, 0x54,\n\t0xdc, 0xe4, 0x18, 0x77, 0x60, 0x94, 0xe4, 0x91, 0x63, 0xdc, 0xe4, 0x18, 0x37, 0x39, 0xc6, 0x4d, 0x8e, 0x71, 0x93, 0x63, 0xdc, 0xe4, 0x18, 0x17, 0x79, 0xc5, 0xf7, 0x4d, 0xb9, 0x2e, 0x32, 0x8a, 0x93, 0xb5, 0xbb, 0x8b, 0xb5, 0xbb, 0x8b, 0xb5, 0xbb, 0x8b, 0xb5, 0xbb, 0x8b, 0xb5, 0xbb, 0x8b, 0xb5, 0xbb, 0x8b, 0xb5, 0xbb, 0x8b, 0xb5, 0xb9, 0x8b, 0xb5, 0xb9, 0x8b, 0xb5, 0xb9, 0x8b, 0xb5, 0xb9, 0x8b, 0xb5, 0xb9, 0x8b, 0xb5, 0xb9, 0x8b, 0xb5, 0xb9, 0x8b, 0x75, 0xb1, 0x8b, 0x75, 0xb1, 0x8b, 0x75, 0xb1, 0x8b, 0x75, 0xb1, 0x8b, 0x75, 0xb1, 0x8b, 0x75, 0xb1, 0x8b, 0x75, 0xb1, 0x8b, 0x75, 0xb1, 0x8b, 0x75, 0xb1, 0x4b, 0xaf, 0x8b, 0x7b, 0x70, 0x2f, 0xee, 0xc3, 0xfd, 0xa0, 0xfd, 0xb3, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e,\n\t0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xb1, 0x2e, 0x76, 0xe9, 0xad, 0xd0, 0x06, 0xed, 0xd0, 0x1e, 0x8f, 0xa1, 0x03, 0xfa, 0xc9, 0x74, 0xbd, 0x3f, 0x06, 0x60, 0x20, 0x06, 0x61, 0x08, 0x5e, 0xc5, 0x50, 0x0c, 0x03, 0x6d, 0x5b, 0xa7, 0x6d, 0xeb, 0xb4, 0x6d, 0xfd, 0x0d, 0x8c, 0xc0, 0x48, 0x8c, 0xc2, 0x9b, 0x78, 0x0b, 0x6f, 0xe3, 0x1d, 0xbc, 0x8b, 0xf7, 0xf0, 0x3e, 0x46, 0x83, 0xb6, 0xa1, 0x7f, 0x88, 0x31, 0xf8, 0x08, 0x1f, 0x63, 0x2c, 0x3e, 0xc1, 0x38, 0x99, 0xa6, 0x7f, 0x8a, 0xcf, 0x64, 0xbd, 0xfe, 0x39, 0xbe, 0xc0, 0x78, 0x4c, 0xc0, 0x44, 0x4c, 0x91, 0x31, 0xfa, 0x54, 0x4c, 0xc3, 0xd7, 0x98, 0xee, 0x7f, 0xad, 0x4d, 0xd3, 0x67, 0xb0, 0xfd, 0x16, 0x33, 0x31,\n\t0x0b, 0xb3, 0x31, 0x07, 0x73, 0x25, 0x51, 0xff, 0x1e, 0x0b, 0xb0, 0x90, 0xcb, 0x8b, 0x10, 0x2c, 0x1f, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0xc6, 0x74, 0xb3, 0x9e, 0x71, 0xb2, 0x9e, 0x71, 0xb2, 0x9e, 0x71, 0xb2, 0x9e, 0x71, 0xb2, 0x9e, 0x71, 0xb2, 0x9e, 0x71, 0x32, 0x5a, 0x35, 0x66, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64,\n\t0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x64, 0x3d, 0xe3, 0x34, 0x32, 0x64, 0x8f, 0x91, 0x89, 0x2c, 0xd6, 0xa9, 0xd9, 0x38, 0x8d, 0x33, 0x38, 0x0b, 0x27, 0x72, 0x70, 0x51, 0x0e, 0x18, 0x2e, 0xb8, 0x71, 0x09, 0xb9, 0xc8, 0x43, 0x3e, 0x2e, 0xc3, 0x83, 0x02, 0x14, 0xa2, 0x08, 0xc5, 0x28, 0x41, 0xa9, 0x1c, 0x60, 0x3e, 0x77, 0x33, 0x9f, 0xbb, 0x99, 0xcf, 0xdd, 0xcc, 0xe7, 0x6e, 0xe6, 0x73, 0x37, 0xf3, 0xb9, 0x9b, 0xf9, 0xdc, 0xcd, 0x7c, 0xee, 0x66, 0x3e, 0x77, 0x33, 0x9f, 0xbb,\n\t0x99, 0xcf, 0xdd, 0xcc, 0xe7, 0x6e, 0xe6, 0x73, 0x37, 0xf3, 0xb9, 0x9b, 0xf9, 0xdc, 0xcd, 0x7c, 0xee, 0x66, 0x3e, 0x77, 0x33, 0x9f, 0xbb, 0x99, 0xcf, 0xdd, 0xcc, 0xe7, 0x6e, 0xe6, 0x73, 0x37, 0xf3, 0xb9, 0x9b, 0xf9, 0xdc, 0xcd, 0x7c, 0xee, 0x66, 0x3e, 0x77, 0x33, 0xa7, 0xb9, 0xac, 0x87, 0x24, 0xc9, 0x1a, 0x8e, 0xc3, 0x88, 0xc0, 0x11, 0x59, 0xc3, 0x9c, 0x75, 0x84, 0x79, 0xca, 0xc5, 0x3c, 0xe5, 0x62, 0x9e, 0x72, 0x31, 0x4f, 0xb9, 0x98, 0xa7, 0x5c, 0x56, 0xea, 0xd3, 0x4a, 0x7d, 0x5a, 0xa9, 0x4f, 0x2b, 0xf5, 0x69, 0xa5, 0x3e, 0x83, 0xba, 0xcb, 0x0c, 0xe6, 0x1d, 0x97, 0x7a, 0x9f, 0xd9, 0x61, 0x5d, 0xf5, 0xeb, 0xaf, 0x29, 0x8c, 0xa8, 0xf9, 0xd5, 0xff, 0x2e, 0xd0, 0x51, 0xfd, 0x6f, 0x02, 0x5d, 0xbe, 0xef, 0xc9, 0x51, 0x65, 0x72, 0x80, 0x51, 0x73, 0x99, 0xa9, 0x8e, 0x1c,\n\t0x66, 0x84, 0xcc, 0x33, 0x4d, 0x14, 0x0f, 0x23, 0xe2, 0xcf, 0xa6, 0x05, 0x12, 0xc5, 0x28, 0xe6, 0xfb, 0x84, 0xff, 0x72, 0xf3, 0x29, 0x29, 0x66, 0xe4, 0x28, 0x0f, 0xa8, 0x21, 0x57, 0xff, 0xfc, 0x44, 0x78, 0x94, 0x94, 0xff, 0x2f, 0xdf, 0x31, 0x65, 0xe5, 0xf2, 0x2f, 0xdf, 0x19, 0xfd, 0x0f, 0xbe, 0xfb, 0x49, 0x2a, 0x5f, 0xf2, 0xe7, 0xbb, 0x90, 0x6d, 0x55, 0xa8, 0xfe, 0xa8, 0x3a, 0x48, 0x1a, 0xb6, 0xd0, 0xeb, 0x67, 0xeb, 0x93, 0x24, 0xb9, 0xea, 0xf5, 0xe4, 0xbf, 0x7b, 0xd7, 0x6e, 0x59, 0xf5, 0xbb, 0x76, 0xad, 0xf4, 0x25, 0x52, 0xfe, 0xbf, 0xfb, 0x6e, 0x1a, 0xb5, 0xd0, 0xdb, 0xff, 0x4e, 0xd8, 0x2f, 0xa6, 0x2e, 0x41, 0xbf, 0x9a, 0x7a, 0xff, 0xdd, 0xbb, 0x60, 0xfb, 0x55, 0xfb, 0xff, 0xd6, 0xda, 0x29, 0xaa, 0xae, 0x9d, 0xf2, 0xff, 0x1f, 0xd7, 0x4e, 0x2d, 0x6a, 0xa7, 0xd1,\n\t0x7f, 0xa9, 0x9d, 0x7b, 0xa9, 0x9d, 0x9a, 0xff, 0xe7, 0xb5, 0x23, 0xd7, 0xff, 0x49, 0xed, 0xdc, 0xe3, 0xaf, 0x9d, 0x9a, 0xea, 0x43, 0x39, 0xa2, 0xc6, 0xb0, 0x6a, 0x98, 0x28, 0x05, 0x94, 0xf8, 0xaf, 0xac, 0x0e, 0x0a, 0x28, 0xf5, 0x98, 0x80, 0x2f, 0xe4, 0x48, 0x60, 0x1d, 0x39, 0x62, 0x3c, 0x83, 0x8e, 0xe8, 0x84, 0x67, 0xf1, 0x1c, 0x9e, 0x47, 0x67, 0x74, 0x41, 0x57, 0xee, 0x6f, 0x32, 0xe5, 0xaa, 0x00, 0xa5, 0x54, 0x91, 0xb9, 0x65, 0xcd, 0x8f, 0x1a, 0x9f, 0xe8, 0x70, 0xdb, 0x33, 0x0d, 0x3a, 0x76, 0xea, 0xf4, 0xda, 0x73, 0x0f, 0x3e, 0x37, 0xa3, 0x73, 0x58, 0xe7, 0x23, 0x9d, 0x1d, 0x9d, 0xcf, 0x77, 0x2e, 0xee, 0xfc, 0x47, 0x97, 0x4e, 0x5d, 0xfa, 0x74, 0x19, 0xdd, 0x65, 0x61, 0x97, 0xe5, 0x5d, 0x8e, 0x74, 0x39, 0xd7, 0xc5, 0xdd, 0xa5, 0xb8, 0x6b, 0x83, 0xae, 0x4d, 0xbb,\n\t0xf6, 0xe9, 0x3a, 0xae, 0xeb, 0xbc, 0xae, 0xa7, 0xba, 0xfe, 0xd1, 0xad, 0xf9, 0x2b, 0x75, 0x07, 0x8c, 0x7b, 0x6d, 0xe5, 0x9b, 0x3b, 0x46, 0x9f, 0xf8, 0xc4, 0x31, 0x79, 0xde, 0xb8, 0x5a, 0xe3, 0x0e, 0x4f, 0x9e, 0xf7, 0x69, 0x9b, 0x89, 0x17, 0x27, 0x8d, 0x98, 0x74, 0x71, 0xb2, 0x75, 0xf2, 0xe8, 0xc9, 0xf3, 0x26, 0x7b, 0xbf, 0xec, 0xf9, 0xe5, 0xd0, 0x2f, 0x3f, 0x5b, 0xfc, 0xc5, 0x57, 0x7b, 0xa7, 0x7e, 0xf6, 0x6d, 0xd8, 0xe2, 0x2f, 0xbe, 0x3d, 0xf4, 0xc3, 0x8e, 0x79, 0x67, 0x7e, 0x78, 0xef, 0x87, 0x1d, 0x8b, 0xeb, 0x2e, 0xfe, 0x62, 0x59, 0xbf, 0x65, 0xfd, 0x16, 0x67, 0x2f, 0xe9, 0xbc, 0x64, 0xec, 0x92, 0x99, 0x4b, 0x16, 0x2f, 0xab, 0xb3, 0xac, 0x07, 0xd7, 0x6c, 0x5b, 0x76, 0x6c, 0x59, 0xea, 0xb2, 0x2b, 0xcb, 0xad, 0x1b, 0x3f, 0x5c, 0x7e, 0xef, 0xf2, 0x21, 0xab, 0xc6,\n\t0xad, 0x9a, 0xb1, 0x3a, 0x61, 0xd5, 0xdc, 0x55, 0x27, 0x56, 0x07, 0xac, 0x7e, 0x62, 0x75, 0xf7, 0xd5, 0x4b, 0x57, 0x27, 0xac, 0x2e, 0x5d, 0x37, 0x73, 0xcd, 0x6d, 0x6b, 0xf2, 0xd7, 0xde, 0xbb, 0x76, 0xc8, 0xba, 0x99, 0x6b, 0x57, 0xaf, 0x75, 0xae, 0xbb, 0x6d, 0x5d, 0xd7, 0x75, 0x33, 0xd7, 0xcd, 0x0c, 0xbd, 0xbe, 0x6e, 0xed, 0xba, 0x1d, 0xeb, 0x0e, 0xad, 0x8b, 0xdd, 0xd8, 0x27, 0x34, 0x37, 0x74, 0xf1, 0xc6, 0xe1, 0x1b, 0x3f, 0xdc, 0x78, 0x6c, 0x63, 0xf6, 0x66, 0xc7, 0xe6, 0xc2, 0xcd, 0xde, 0xd0, 0xc3, 0x5b, 0xac, 0x5b, 0x9a, 0x6e, 0x79, 0x6e, 0x4b, 0xaf, 0x90, 0x4e, 0x5b, 0x76, 0x6c, 0x79, 0x6f, 0xcb, 0x17, 0x5b, 0x37, 0x6f, 0x99, 0xbd, 0x65, 0xc9, 0x96, 0xb5, 0x5b, 0x76, 0x84, 0xe6, 0x6e, 0x39, 0xb4, 0xc5, 0xb1, 0xa5, 0x30, 0x44, 0x0f, 0xa9, 0x1b, 0xf2, 0x60, 0x48,\n\t0x9b, 0xd0, 0x5d, 0x21, 0x9d, 0x42, 0xfa, 0x84, 0x0c, 0x0f, 0xf9, 0x30, 0x64, 0x66, 0xc8, 0xe2, 0x90, 0xf5, 0x21, 0x87, 0x42, 0xa2, 0x42, 0xec, 0x21, 0xa7, 0x42, 0x4a, 0x43, 0x03, 0x42, 0x6b, 0x85, 0x36, 0x0f, 0x7d, 0x22, 0xb4, 0x7b, 0xe8, 0x6b, 0xa1, 0x5f, 0x84, 0xce, 0x08, 0x9d, 0x1b, 0xba, 0x38, 0xf4, 0x54, 0xe8, 0xfa, 0xd0, 0xf8, 0xd0, 0x5d, 0xa1, 0x87, 0xf9, 0xff, 0xa9, 0xd0, 0xf3, 0xa1, 0xb9, 0xdb, 0x8e, 0x85, 0x0d, 0x09, 0xbd, 0x1e, 0xa6, 0x87, 0x35, 0x0e, 0xeb, 0xc4, 0x7f, 0x43, 0xc2, 0x46, 0x87, 0x4d, 0x08, 0x9b, 0x19, 0xb6, 0x36, 0xec, 0x97, 0xb0, 0x13, 0xfc, 0x77, 0x26, 0xec, 0xea, 0x56, 0x7d, 0x6b, 0xdd, 0xad, 0x4d, 0xb7, 0x3e, 0xb7, 0xf5, 0x9d, 0xad, 0xd3, 0xb6, 0x6e, 0xe6, 0xbf, 0xdd, 0x5b, 0x4f, 0x6d, 0x2d, 0xdd, 0x5a, 0xba, 0x4d, 0x6d, 0xb3, 0x6e,\n\t0x7b, 0x74, 0xdb, 0x90, 0x6d, 0xa3, 0xb7, 0xcd, 0xd8, 0x16, 0xbc, 0x6d, 0xe5, 0xb6, 0x63, 0xdb, 0x52, 0xb7, 0x79, 0xb6, 0xd7, 0xda, 0xfe, 0xc8, 0xf6, 0x67, 0xb6, 0x0f, 0xda, 0x3e, 0x76, 0xfb, 0x92, 0xed, 0xbb, 0xb6, 0x1f, 0xde, 0x1e, 0xbf, 0xe3, 0xcc, 0xcf, 0xbb, 0x77, 0xff, 0xb2, 0x3b, 0x7b, 0xef, 0x84, 0xbd, 0x9d, 0x51, 0xf5, 0xdf, 0x2f, 0xbf, 0xb9, 0x0f, 0x0c, 0x3a, 0x90, 0x1d, 0xfe, 0xa8, 0xd2, 0xd4, 0xe3, 0xa6, 0x7e, 0xa6, 0x7e, 0x4a, 0x99, 0x06, 0x98, 0x06, 0x50, 0xeb, 0x83, 0x4c, 0x83, 0x94, 0x66, 0x1a, 0x62, 0x1a, 0xa2, 0xcc, 0xa6, 0x37, 0x4c, 0xa3, 0x54, 0x80, 0xe9, 0x5d, 0xd3, 0x7b, 0x4a, 0x37, 0x7d, 0x6e, 0x9a, 0xa2, 0xac, 0xa6, 0x39, 0xa6, 0x39, 0xaa, 0x8e, 0xe9, 0x3b, 0xd3, 0x42, 0x75, 0xb7, 0xc9, 0x6d, 0xca, 0x53, 0x0f, 0x98, 0x0a, 0x4c, 0xa5, 0xaa,\n\t0xa1, 0xd6, 0x45, 0xeb, 0xa2, 0x1e, 0xd2, 0xba, 0x69, 0x2f, 0xa8, 0x66, 0xda, 0x4b, 0x5a, 0x2f, 0xd5, 0x42, 0xeb, 0xa3, 0xf5, 0x51, 0x6d, 0xb4, 0x7e, 0x5a, 0x7f, 0xd5, 0x56, 0x1b, 0xa8, 0x0d, 0x54, 0xed, 0xb4, 0xa1, 0xda, 0xeb, 0xaa, 0xbd, 0x36, 0x52, 0x1b, 0xa9, 0x9e, 0xd0, 0xde, 0xd4, 0xde, 0x54, 0x4f, 0x6a, 0x6f, 0x6b, 0xef, 0xaa, 0xa7, 0xb4, 0xf7, 0xb5, 0x8f, 0x54, 0x47, 0x6d, 0x9c, 0xf6, 0xa9, 0xea, 0xa2, 0x7d, 0xae, 0x8d, 0x67, 0xb5, 0x3a, 0x51, 0xfb, 0x52, 0xf5, 0xd0, 0xa6, 0x68, 0x53, 0x54, 0x4f, 0x6d, 0x9a, 0xf6, 0xb5, 0x7a, 0x45, 0xfb, 0x46, 0xfb, 0x56, 0xf5, 0xd6, 0x66, 0x69, 0xf3, 0x54, 0x3f, 0x2d, 0x58, 0x0b, 0x56, 0x43, 0xb4, 0x1f, 0xb5, 0x25, 0xea, 0x55, 0x6d, 0x99, 0xb6, 0x4c, 0x0d, 0xd3, 0x56, 0x68, 0xab, 0xd5, 0x6b, 0xda, 0x7a, 0x2d, 0x42, 0x8d,\n\t0xd0, 0x8e, 0x6a, 0x47, 0xd5, 0x14, 0xed, 0xb8, 0x76, 0x42, 0x4d, 0xd5, 0xa2, 0xb4, 0x28, 0xf5, 0xb5, 0x16, 0xa3, 0x25, 0xaa, 0xe9, 0x5a, 0x92, 0x76, 0x51, 0xcd, 0xd1, 0x2e, 0x69, 0x05, 0x6a, 0x8d, 0x56, 0xac, 0x95, 0xaa, 0xcd, 0xda, 0x15, 0xad, 0x42, 0x85, 0x6a, 0xd7, 0xb4, 0x1b, 0x6a, 0xbb, 0x76, 0xd3, 0xdc, 0x4c, 0xed, 0x32, 0x0f, 0x34, 0x0f, 0x56, 0xa7, 0xcc, 0xc3, 0xcc, 0xc3, 0xd5, 0x69, 0xf3, 0x1a, 0xf3, 0x1a, 0x95, 0x63, 0x5e, 0x67, 0x5e, 0xa7, 0xce, 0x99, 0x37, 0x99, 0x43, 0xd5, 0xef, 0xe6, 0x6d, 0xe6, 0x1d, 0xca, 0x6d, 0xde, 0x65, 0xde, 0xa5, 0xf2, 0xcc, 0xbb, 0xcd, 0xbb, 0x55, 0xbe, 0x79, 0x9f, 0xf9, 0xa0, 0xba, 0x6c, 0x0e, 0x26, 0xe9, 0x64, 0x92, 0x74, 0x32, 0x49, 0x3a, 0x99, 0x24, 0x9d, 0x4c, 0x92, 0x4e, 0x26, 0x49, 0x27, 0x93, 0xa4, 0x93, 0xa9, 0x9a,\n\t0xab, 0x3b, 0x55, 0x2b, 0xb4, 0x96, 0x6c, 0xd5, 0x06, 0x6d, 0xd1, 0x4e, 0xa2, 0x54, 0x7b, 0x3c, 0x86, 0x0e, 0x78, 0x1c, 0x4f, 0xe0, 0x49, 0x89, 0x55, 0x4f, 0xe1, 0x69, 0x3c, 0x23, 0x76, 0xd5, 0x91, 0xeb, 0x3a, 0xe1, 0x59, 0xc9, 0x21, 0x11, 0xe5, 0x90, 0x88, 0x72, 0x48, 0x44, 0x39, 0x24, 0xa2, 0x1c, 0x12, 0x51, 0x0e, 0x89, 0x28, 0x87, 0x44, 0x94, 0x43, 0x22, 0xca, 0x21, 0x11, 0xe5, 0x90, 0x88, 0x72, 0x48, 0x44, 0x39, 0x24, 0xa2, 0x1c, 0x12, 0x51, 0x0e, 0x89, 0x28, 0x87, 0x44, 0x94, 0x43, 0x22, 0xca, 0x21, 0x11, 0xe5, 0x90, 0x88, 0x72, 0x48, 0x44, 0x39, 0x24, 0xa2, 0x1c, 0x12, 0x51, 0x0e, 0x89, 0x28, 0x87, 0x44, 0x94, 0x43, 0x22, 0xca, 0x21, 0x11, 0xe5, 0x90, 0x88, 0x72, 0x48, 0x44, 0x39, 0x24, 0xa2, 0x1c, 0x12, 0x51, 0x0e, 0x89, 0x28, 0x87, 0x44, 0x94, 0xa3, 0x46,\n\t0x48, 0x29, 0xd9, 0xaf, 0xb1, 0xef, 0x37, 0x89, 0x19, 0xfb, 0x9b, 0xa9, 0x0f, 0xb8, 0xfc, 0x11, 0x3e, 0xc6, 0x58, 0x7c, 0xc2, 0x39, 0x8e, 0xc3, 0xa7, 0xf8, 0x8c, 0xcb, 0x5f, 0x70, 0xfe, 0xe3, 0xd9, 0x4e, 0x90, 0xd3, 0x6a, 0x22, 0x26, 0x61, 0x32, 0xbe, 0xe2, 0x58, 0x53, 0x24, 0x8b, 0x64, 0x95, 0x45, 0xb2, 0xca, 0x22, 0x59, 0x65, 0x91, 0xac, 0xb2, 0x48, 0x56, 0x59, 0x24, 0xab, 0x2c, 0x92, 0x55, 0x16, 0xc9, 0x2a, 0x8b, 0x64, 0x95, 0xa5, 0x66, 0x33, 0x9b, 0xcc, 0xc1, 0x5c, 0x49, 0x23, 0x61, 0x65, 0x93, 0xb0, 0x0a, 0x49, 0x58, 0x99, 0x24, 0xac, 0x0c, 0x95, 0x42, 0x9a, 0x4a, 0x93, 0x74, 0x66, 0x9d, 0xe4, 0xea, 0x6f, 0xe3, 0x4f, 0x22, 0x69, 0x65, 0x90, 0xb4, 0x4e, 0x91, 0xb4, 0xe2, 0xd5, 0x69, 0x6e, 0x77, 0x96, 0xc7, 0xf7, 0xfd, 0x2b, 0xc2, 0x73, 0x72, 0x56, 0x5d, 0xe0,\n\t0xbc, 0x2e, 0xc2, 0xf7, 0x4d, 0x19, 0x6e, 0xae, 0xbb, 0xc4, 0x7e, 0xae, 0x1c, 0x27, 0x85, 0xd9, 0xd5, 0x65, 0x6e, 0x7f, 0x83, 0xdb, 0xdf, 0x54, 0xb5, 0x49, 0x62, 0xa9, 0x24, 0xb0, 0x4c, 0x92, 0x97, 0xc3, 0x74, 0x97, 0x14, 0x99, 0x6a, 0x4a, 0xa9, 0xa9, 0x16, 0x6a, 0xa3, 0xae, 0x38, 0x4d, 0xf7, 0xb0, 0xbd, 0x17, 0x0f, 0xa0, 0x1e, 0xea, 0xa3, 0x81, 0x44, 0x99, 0x1a, 0xb2, 0x7d, 0x50, 0xd2, 0x4d, 0x8d, 0xd9, 0x6f, 0xc2, 0x7e, 0x53, 0x3c, 0x24, 0x36, 0x53, 0x33, 0xb6, 0x0f, 0xc3, 0xf7, 0x2f, 0x25, 0x5a, 0xb0, 0x6d, 0x89, 0x56, 0x72, 0xc6, 0xf4, 0x08, 0xb7, 0x6b, 0xcd, 0xfe, 0xe7, 0x12, 0x4f, 0x8a, 0x3b, 0xc6, 0x38, 0x9d, 0x66, 0x9a, 0x2c, 0x49, 0xa6, 0x29, 0x52, 0xe8, 0xff, 0xa4, 0xda, 0x7c, 0x8e, 0xe5, 0xe6, 0x3c, 0x72, 0xb9, 0x5d, 0x9e, 0x38, 0x48, 0x72, 0x99, 0xa4,\n\t0xb8, 0xa1, 0xa4, 0xb8, 0x4c, 0xfa, 0x56, 0x43, 0xf2, 0xf7, 0x00, 0xd2, 0x5c, 0xa6, 0x36, 0x40, 0x32, 0xb4, 0xd7, 0xd4, 0x9d, 0xa4, 0xb9, 0xcc, 0xea, 0x77, 0xdb, 0xa2, 0x34, 0xca, 0x5e, 0x9b, 0x24, 0xa5, 0xda, 0x57, 0x12, 0xa9, 0x4d, 0x61, 0x4b, 0x39, 0x93, 0xec, 0xb2, 0xb4, 0x59, 0x92, 0x4c, 0xba, 0xd3, 0xb5, 0x39, 0x64, 0xf8, 0xb9, 0xdc, 0x26, 0x58, 0x4e, 0x6b, 0x3f, 0xb2, 0x5d, 0x22, 0x85, 0xda, 0x6a, 0x39, 0x4e, 0xda, 0xcb, 0x21, 0xed, 0xe5, 0x90, 0xf6, 0x72, 0x48, 0x7b, 0x39, 0xa4, 0xbd, 0x1c, 0xd2, 0x5e, 0x0e, 0x69, 0x2f, 0x87, 0xb4, 0x97, 0x43, 0xda, 0xcb, 0x21, 0xed, 0xe5, 0x90, 0xf6, 0xb2, 0x48, 0x7b, 0x59, 0xda, 0x0e, 0xce, 0x6b, 0x27, 0xf7, 0xdf, 0xc5, 0x63, 0xb0, 0xea, 0xd5, 0x7e, 0x95, 0x38, 0x6d, 0xb7, 0x44, 0x6b, 0x7b, 0xb8, 0x6e, 0xaf, 0xa4, 0x6a,\n\t0xbf, 0xf1, 0x78, 0xfb, 0x24, 0x45, 0xdb, 0x2f, 0x49, 0xda, 0x01, 0xee, 0x77, 0x90, 0xf3, 0x39, 0xc4, 0x6d, 0xc3, 0xe5, 0x84, 0x76, 0x98, 0x6d, 0x84, 0x9c, 0xd2, 0x8e, 0x70, 0x8c, 0xe3, 0xdc, 0x36, 0x8a, 0xed, 0x49, 0x44, 0x73, 0x7d, 0x0c, 0xa3, 0x40, 0x2c, 0xdb, 0x38, 0xc4, 0xf3, 0x7c, 0x6c, 0xdc, 0x2f, 0x41, 0x4e, 0x6a, 0xa9, 0xa4, 0xd5, 0x34, 0xc9, 0xd6, 0x1c, 0x5c, 0x9f, 0x8e, 0x4c, 0xf5, 0x96, 0x76, 0x4a, 0x2d, 0xd2, 0xb2, 0xd4, 0x4f, 0xda, 0x19, 0x89, 0xd1, 0xce, 0xf2, 0x78, 0x4e, 0x8e, 0x71, 0x5e, 0xd2, 0x34, 0x97, 0x7a, 0x40, 0xbb, 0xa4, 0xa6, 0x69, 0xf9, 0x52, 0xa0, 0x5d, 0xe6, 0xf1, 0x3d, 0xfc, 0xad, 0x80, 0xc7, 0x2d, 0xe4, 0xb6, 0xc5, 0xdc, 0xb7, 0x84, 0xf3, 0x2c, 0xe5, 0x3c, 0xcb, 0xd8, 0x5e, 0xe1, 0xbe, 0xe5, 0x9c, 0xcb, 0x55, 0x54, 0xa0, 0x52, 0xce,\n\t0x68, 0x5e, 0x8e, 0x7d, 0x53, 0xbd, 0x65, 0x56, 0x92, 0x62, 0x36, 0x89, 0xc3, 0xac, 0x49, 0xa4, 0xd9, 0x2c, 0xa5, 0xe6, 0x00, 0x04, 0xa2, 0x86, 0x9c, 0x31, 0x5b, 0xd8, 0x1a, 0xb0, 0x4a, 0x9a, 0x39, 0x48, 0x4e, 0x98, 0x6f, 0x93, 0xb3, 0xe6, 0xdb, 0xe5, 0x98, 0xf9, 0x0e, 0x39, 0x6e, 0xbe, 0x53, 0x92, 0xcd, 0x77, 0xa1, 0x26, 0xf7, 0xad, 0x25, 0xb1, 0xe6, 0xda, 0x92, 0x6a, 0xae, 0xc3, 0x6d, 0xeb, 0x4a, 0x96, 0xf9, 0x1e, 0x39, 0x6d, 0xbe, 0x97, 0xe3, 0xde, 0x27, 0x65, 0xe6, 0xfb, 0x25, 0xce, 0x5c, 0x8f, 0xdb, 0xd4, 0x97, 0x22, 0xf3, 0x83, 0x72, 0xca, 0xdc, 0x98, 0xdb, 0xd0, 0x76, 0xcc, 0x0f, 0x49, 0x82, 0x79, 0x20, 0xd7, 0x0f, 0x92, 0x78, 0xf3, 0x60, 0x6e, 0x33, 0x8c, 0xc7, 0x7f, 0x4d, 0xa2, 0x48, 0xd8, 0xbe, 0x5f, 0xd1, 0xf1, 0x7d, 0x5f, 0x4f, 0x14, 0x29, 0x3b, 0xde,\n\t0xbc, 0x83, 0xed, 0x2e, 0xec, 0xc6, 0x09, 0xfe, 0x16, 0xa5, 0x2c, 0x24, 0xea, 0x4c, 0x73, 0x16, 0xe7, 0x97, 0x8d, 0x0b, 0x1c, 0xeb, 0x22, 0x5c, 0x70, 0x23, 0x17, 0x79, 0xc8, 0xc7, 0x65, 0x8e, 0xe3, 0x61, 0x5b, 0x80, 0x42, 0x14, 0x71, 0x8c, 0x62, 0xae, 0x2b, 0x91, 0x0c, 0x52, 0x78, 0x06, 0x29, 0x3c, 0x9d, 0x14, 0x6e, 0x23, 0x85, 0xdb, 0xcc, 0x15, 0xfc, 0xfd, 0xaf, 0x77, 0x31, 0x4b, 0xcd, 0x5e, 0xdc, 0xc4, 0x1f, 0xfc, 0x4d, 0xa4, 0x34, 0x40, 0x49, 0x72, 0x80, 0x49, 0xd5, 0x0e, 0xd0, 0x24, 0x2a, 0x80, 0x72, 0x0a, 0xa0, 0x9c, 0x02, 0x2c, 0xec, 0x07, 0xb1, 0x7d, 0x51, 0x32, 0x49, 0xec, 0x99, 0x24, 0xf6, 0xcc, 0x80, 0x5e, 0x5c, 0xee, 0x83, 0x7e, 0x18, 0xc0, 0xdf, 0x07, 0x62, 0x30, 0x18, 0x5f, 0x02, 0x56, 0x48, 0x4a, 0x20, 0x7d, 0x2a, 0xb0, 0x21, 0xdb, 0x46, 0x12, 0x1d,\n\t0xd8, 0x58, 0x22, 0x03, 0x9b, 0x88, 0x9d, 0x64, 0x9f, 0x43, 0xb2, 0xcf, 0x09, 0x8c, 0x54, 0x2f, 0x05, 0x46, 0xa9, 0x07, 0x48, 0xf7, 0x39, 0xa4, 0xfb, 0x1c, 0xd2, 0x7d, 0x0e, 0xe9, 0x3e, 0x87, 0x74, 0x9f, 0x43, 0xba, 0xcf, 0xf4, 0x7f, 0x33, 0xfc, 0xef, 0x12, 0x15, 0x78, 0x49, 0x62, 0x03, 0xf3, 0x54, 0xb3, 0xc0, 0x7c, 0xb6, 0x1e, 0xff, 0xbf, 0xc3, 0x76, 0x06, 0x16, 0x72, 0xfd, 0x55, 0xff, 0xf7, 0x19, 0x45, 0x05, 0x5e, 0x93, 0xcc, 0x1a, 0x4a, 0x52, 0x6b, 0x98, 0x24, 0xbe, 0x86, 0xa6, 0x86, 0xd7, 0x30, 0xb3, 0x0d, 0x90, 0xdf, 0x6b, 0x04, 0x8a, 0xbd, 0x46, 0x0d, 0xc9, 0xaf, 0x41, 0xff, 0xad, 0xf1, 0x90, 0xa4, 0xd7, 0x68, 0x26, 0xe7, 0x6b, 0x5c, 0x93, 0x28, 0xcb, 0x18, 0xc9, 0xb4, 0x7c, 0x84, 0x8f, 0x31, 0x16, 0x9f, 0xe0, 0x53, 0x7c, 0x86, 0xcd, 0xd8, 0x82, 0x10, 0x84,\n\t0x22, 0x0c, 0x5b, 0xb1, 0x0d, 0x3b, 0xd5, 0x48, 0x4b, 0x3c, 0x2b, 0xd1, 0x64, 0xf5, 0x85, 0x25, 0x8b, 0xd5, 0xe0, 0xed, 0x92, 0xa9, 0x33, 0x3f, 0xe8, 0x77, 0xe2, 0x2e, 0xd4, 0x44, 0x2d, 0xd4, 0x46, 0x1d, 0xdc, 0x8d, 0xba, 0xea, 0x09, 0xfd, 0x1e, 0xb6, 0xf7, 0xe2, 0x3e, 0xdc, 0x0f, 0xe6, 0x13, 0x9d, 0xf9, 0x44, 0x67, 0x3e, 0xd1, 0x1b, 0xa0, 0x21, 0x98, 0x57, 0xf4, 0x46, 0x68, 0x8c, 0x26, 0x68, 0x8a, 0x87, 0xd0, 0x0c, 0x0f, 0xa3, 0x39, 0x5a, 0xa0, 0x25, 0x5a, 0xc1, 0xf7, 0x39, 0x99, 0x36, 0x6c, 0xff, 0xf6, 0x59, 0x99, 0x76, 0xec, 0xb7, 0xc7, 0x63, 0xe8, 0x80, 0x71, 0xea, 0x4e, 0xfd, 0x53, 0x4c, 0xc1, 0x54, 0x4c, 0xc3, 0xd7, 0x98, 0x8e, 0x6f, 0xd4, 0x61, 0x7d, 0x06, 0xdb, 0x6f, 0x31, 0x13, 0xb3, 0x30, 0x1b, 0x73, 0xb0, 0x10, 0x8b, 0x10, 0xcc, 0x4a, 0x76, 0xb9, 0x64,\n\t0xeb, 0x2b, 0xb0, 0x12, 0xab, 0xb0, 0x1a, 0x6b, 0xb0, 0x16, 0xeb, 0xb0, 0x1e, 0x1b, 0xb0, 0x11, 0x9b, 0xb0, 0x19, 0x5b, 0xd4, 0xa3, 0x7a, 0x08, 0xdb, 0x50, 0x84, 0x61, 0x2b, 0xb6, 0x61, 0x3b, 0x76, 0x60, 0x27, 0x76, 0xe1, 0x67, 0xfc, 0x82, 0x5f, 0xb1, 0x5b, 0xd5, 0xd0, 0xf7, 0x48, 0x96, 0xbe, 0x97, 0xfd, 0xdf, 0xb0, 0x0f, 0xfb, 0xe5, 0xa6, 0x7e, 0x80, 0xed, 0x41, 0x1c, 0x42, 0x38, 0x8e, 0x49, 0x94, 0x7e, 0x1c, 0x27, 0x10, 0x89, 0x28, 0x44, 0x23, 0x06, 0xb1, 0x12, 0xab, 0xc7, 0x21, 0x1e, 0x36, 0x24, 0x48, 0xb4, 0x9e, 0xc8, 0xf5, 0x76, 0xf6, 0x93, 0xd8, 0x26, 0x23, 0x05, 0xa9, 0x48, 0x83, 0x03, 0xe9, 0xc8, 0x40, 0x26, 0xb2, 0x90, 0x8d, 0xd3, 0x38, 0x83, 0xb3, 0x70, 0xaa, 0x40, 0x3d, 0x87, 0xed, 0x39, 0xd0, 0x0e, 0xf5, 0xf3, 0x60, 0xce, 0xd1, 0x5d, 0x70, 0x83, 0x39,\n\t0x47, 0x67, 0x3c, 0xd7, 0xf3, 0x90, 0x8f, 0xcb, 0x24, 0x03, 0x8f, 0xe4, 0xe8, 0x85, 0x28, 0x42, 0x31, 0x4a, 0x50, 0x8a, 0x32, 0x5c, 0x41, 0x39, 0xae, 0xa2, 0x02, 0x95, 0xb8, 0x86, 0xeb, 0xb8, 0x01, 0x2f, 0x6e, 0xe2, 0x0f, 0xc9, 0x31, 0x6a, 0x48, 0xa9, 0xc1, 0x78, 0x64, 0xe8, 0x60, 0x4c, 0x32, 0xac, 0x12, 0x65, 0xd0, 0xf7, 0x8c, 0xdb, 0x70, 0x3b, 0xee, 0xc0, 0x9d, 0xa8, 0xad, 0x82, 0x8c, 0xfb, 0xd5, 0x03, 0xfe, 0x77, 0xcc, 0x1a, 0xa8, 0xdb, 0x8c, 0x86, 0xca, 0x6a, 0x3c, 0xa8, 0xea, 0x19, 0x8d, 0xd4, 0xbd, 0x46, 0x63, 0xd5, 0xcc, 0x68, 0xa2, 0xee, 0x34, 0x9a, 0xfa, 0x7f, 0xf3, 0xb6, 0x9b, 0xd1, 0x5c, 0xb5, 0x32, 0x98, 0xaf, 0x8c, 0xd6, 0xea, 0x67, 0xa3, 0x0d, 0x7f, 0x6b, 0xab, 0xea, 0x1a, 0xed, 0xd8, 0x3e, 0xcd, 0x75, 0xcf, 0xab, 0xfa, 0x46, 0x37, 0xb6, 0xdd, 0xf1,\n\t0x02, 0x7a, 0xe0, 0x45, 0xbc, 0x8c, 0x9e, 0x78, 0x05, 0xf4, 0x75, 0xa3, 0x37, 0xe8, 0xef, 0x46, 0x5f, 0xd0, 0xe7, 0x8d, 0xfe, 0x18, 0x80, 0x81, 0x18, 0xc4, 0x39, 0xd2, 0xf7, 0x8d, 0x21, 0x78, 0x15, 0x43, 0x31, 0x0c, 0x8c, 0x73, 0xc6, 0xeb, 0x18, 0x8e, 0x37, 0x30, 0x02, 0x23, 0x31, 0x0a, 0x6f, 0xe2, 0x2d, 0xb9, 0x69, 0xbc, 0xcd, 0xf6, 0x1d, 0xbc, 0x8b, 0xf7, 0xf0, 0x3e, 0x46, 0xe3, 0x03, 0x7c, 0x88, 0x31, 0xf8, 0x08, 0x1f, 0x63, 0x2c, 0x58, 0x9f, 0x18, 0xac, 0x4f, 0x0c, 0xd6, 0x27, 0xc6, 0x67, 0x60, 0x9e, 0x34, 0xbe, 0xc0, 0x78, 0x4c, 0xc0, 0x44, 0x4c, 0xc2, 0x64, 0x7c, 0x89, 0xaf, 0x38, 0x3f, 0xe6, 0x4e, 0x63, 0x2a, 0xa6, 0xe3, 0x1b, 0xcc, 0xc0, 0xb7, 0x98, 0x89, 0x59, 0x98, 0x8d, 0x39, 0xf8, 0x0e, 0xf3, 0xd4, 0xa3, 0xc6, 0x7c, 0x39, 0x6d, 0x7c, 0x8f, 0x05, 0x58,\n\t0x88, 0x45, 0x60, 0x8e, 0x35, 0x7e, 0xc0, 0x62, 0xfc, 0x88, 0x25, 0xf8, 0x09, 0xcb, 0x24, 0xcb, 0x58, 0x8e, 0x15, 0x58, 0x89, 0x55, 0x58, 0x8d, 0x35, 0x6a, 0x98, 0xb1, 0x96, 0xed, 0x3a, 0xac, 0xc7, 0x06, 0x6c, 0xc4, 0x26, 0x6c, 0xc6, 0x16, 0x84, 0x20, 0x14, 0x61, 0xd8, 0x0a, 0xe6, 0x63, 0x83, 0xf9, 0xd8, 0xd8, 0x81, 0x9d, 0xd8, 0x85, 0x9f, 0xf1, 0x0b, 0x7e, 0xc5, 0x6e, 0xd0, 0x5f, 0x8c, 0xbd, 0xf8, 0x0d, 0xfb, 0xb0, 0x1f, 0x07, 0x70, 0x10, 0x87, 0x10, 0x8e, 0xc3, 0x88, 0x00, 0x73, 0xb2, 0x71, 0x14, 0xc7, 0x70, 0x1c, 0x27, 0x10, 0x09, 0xe6, 0x68, 0x83, 0x39, 0xda, 0x88, 0x96, 0xb3, 0x46, 0x0c, 0xdb, 0x58, 0xc4, 0x21, 0x1e, 0x36, 0x24, 0x20, 0x11, 0x76, 0x24, 0x21, 0x19, 0x29, 0x48, 0x45, 0x1a, 0x1c, 0x48, 0x47, 0x86, 0xa4, 0x19, 0x99, 0x38, 0x25, 0xe9, 0x46, 0x96,\n\t0x64, 0x1b, 0xd9, 0x38, 0x8d, 0x33, 0x38, 0x0b, 0x27, 0x72, 0x70, 0x51, 0x0a, 0x0d, 0x17, 0xdc, 0xb8, 0x84, 0x5c, 0xe4, 0x21, 0x1f, 0x97, 0xe1, 0x41, 0x01, 0x0a, 0x51, 0x84, 0x62, 0x94, 0xa0, 0x54, 0x0a, 0xad, 0xf7, 0xab, 0xb6, 0xd6, 0xb6, 0x12, 0x6d, 0x7d, 0x14, 0xed, 0xd0, 0x1e, 0x8f, 0xa1, 0x03, 0x1e, 0xc7, 0x13, 0x78, 0x12, 0x4f, 0xe1, 0x69, 0x3c, 0x83, 0x8e, 0xe8, 0x84, 0x67, 0xf1, 0x1c, 0x9e, 0x47, 0x67, 0x74, 0x41, 0x57, 0x74, 0x43, 0x77, 0xbc, 0x80, 0x1e, 0x78, 0x11, 0x2f, 0xe1, 0x65, 0x49, 0xb2, 0xf6, 0xc4, 0x2b, 0xe8, 0x85, 0xde, 0xe8, 0x83, 0xbe, 0xe8, 0x87, 0xfe, 0x60, 0x9d, 0x66, 0x1d, 0x88, 0x41, 0x18, 0x8c, 0x21, 0x78, 0x15, 0x43, 0x31, 0x0c, 0xaf, 0xe1, 0x75, 0x0c, 0xc7, 0x1b, 0x18, 0x81, 0x91, 0x18, 0x85, 0x37, 0xf1, 0x16, 0xde, 0xc6, 0x3b, 0x78,\n\t0x17, 0xef, 0xe1, 0x7d, 0x8c, 0xc6, 0x07, 0xf8, 0xd0, 0xff, 0xdd, 0x63, 0x99, 0xd6, 0x8f, 0x54, 0x4b, 0x2b, 0xf3, 0x94, 0x75, 0xac, 0xd8, 0xac, 0xcc, 0x53, 0xd6, 0x71, 0x60, 0xae, 0xb2, 0x32, 0x57, 0x59, 0x3f, 0xc7, 0x17, 0x18, 0x0f, 0xdf, 0x77, 0xf5, 0x4d, 0xc4, 0x24, 0x4c, 0xc6, 0x97, 0xf8, 0x0a, 0x53, 0x30, 0x15, 0xd3, 0x30, 0x43, 0xd2, 0xac, 0xdf, 0x62, 0x26, 0x66, 0x61, 0x36, 0xe6, 0x80, 0xf5, 0xb8, 0xf5, 0x3b, 0xcc, 0xc3, 0x7c, 0x7c, 0x8f, 0x05, 0x58, 0x88, 0x45, 0x08, 0xc6, 0x0f, 0x58, 0x8c, 0x1f, 0xb1, 0x04, 0x3f, 0xc9, 0x71, 0xeb, 0x32, 0x89, 0xb7, 0x2e, 0xc7, 0x0a, 0xac, 0xc4, 0x2a, 0xac, 0xc6, 0x1a, 0xac, 0xc5, 0x3a, 0xac, 0xc7, 0x06, 0x6c, 0xc4, 0x26, 0x6c, 0xc6, 0x16, 0x84, 0x80, 0xf5, 0x8e, 0x35, 0x0c, 0x5b, 0xb1, 0x0d, 0xdb, 0xb1, 0x03, 0x3b, 0xb1,\n\t0x0b, 0x07, 0x39, 0xe7, 0x43, 0xaa, 0xb6, 0x35, 0x1c, 0x87, 0x11, 0x81, 0x13, 0x52, 0x6a, 0x8d, 0x44, 0xb4, 0xff, 0x3b, 0x4d, 0x9c, 0x56, 0xd6, 0x94, 0xd6, 0x78, 0xd8, 0x90, 0x80, 0x44, 0xd8, 0x91, 0x84, 0x64, 0xa4, 0x50, 0x6e, 0xa9, 0x6c, 0xd3, 0xe4, 0x8c, 0xf5, 0x94, 0xd2, 0xac, 0xf9, 0x1c, 0xf3, 0x32, 0x3c, 0x28, 0x40, 0x21, 0xae, 0x48, 0x94, 0xb5, 0x1c, 0x57, 0xc1, 0x7a, 0xc2, 0x5a, 0x89, 0x6b, 0xe2, 0xb0, 0x5e, 0xc7, 0x0d, 0x78, 0x71, 0x53, 0x1c, 0x41, 0x8b, 0x24, 0x3a, 0x68, 0xb1, 0x7a, 0x26, 0xe8, 0x47, 0xf5, 0x56, 0xd0, 0x4f, 0xea, 0x89, 0xa0, 0x65, 0xfe, 0x4f, 0x8c, 0x67, 0x06, 0x85, 0x4b, 0x72, 0xd0, 0x61, 0x44, 0x48, 0x54, 0x10, 0x73, 0x4f, 0x50, 0xa2, 0x5c, 0x0e, 0x18, 0xac, 0xcc, 0x24, 0x9c, 0x00, 0x04, 0x4a, 0x22, 0x69, 0xd2, 0x4e, 0x9a, 0xb4, 0x93,\n\t0x26, 0xed, 0xaa, 0x2e, 0xa9, 0xe7, 0x01, 0xb6, 0xf5, 0x50, 0x1f, 0x0f, 0xa2, 0xb1, 0x14, 0xa9, 0x26, 0x68, 0x4e, 0x62, 0x69, 0x85, 0xd6, 0x72, 0x92, 0x64, 0x79, 0x92, 0x64, 0x79, 0x92, 0x64, 0x19, 0x4e, 0xb2, 0x0c, 0x27, 0x59, 0x86, 0x93, 0x2c, 0xc3, 0x49, 0x96, 0xe1, 0x24, 0xcb, 0x70, 0x92, 0x65, 0x04, 0xc9, 0x32, 0x82, 0x64, 0x19, 0xe1, 0xfb, 0xed, 0x6b, 0x92, 0x65, 0x38, 0xc9, 0x32, 0x9c, 0x64, 0x99, 0x42, 0xb2, 0x4c, 0x21, 0x59, 0xa6, 0x90, 0x2c, 0x53, 0x48, 0x96, 0x29, 0x24, 0xcb, 0x14, 0x92, 0x65, 0x8a, 0xf2, 0xfd, 0x5a, 0xf6, 0x0b, 0xe8, 0x81, 0x17, 0xf1, 0x12, 0x5e, 0x46, 0x4f, 0xbc, 0x82, 0x5e, 0xe8, 0x8d, 0x3e, 0xe8, 0x8b, 0x7e, 0xe8, 0x8f, 0x01, 0x18, 0x88, 0x41, 0x18, 0x8c, 0x21, 0x78, 0x15, 0x43, 0x31, 0x0c, 0xaf, 0xe1, 0x75, 0x0c, 0xc7, 0x08, 0x29,\n\t0x20, 0x59, 0x0e, 0x55, 0xef, 0x92, 0xd6, 0xde, 0x53, 0x6d, 0x48, 0x97, 0x6d, 0x48, 0x97, 0x36, 0xd2, 0xa5, 0x8d, 0x74, 0x69, 0x23, 0x5d, 0xda, 0x48, 0x97, 0xe1, 0xa4, 0xcb, 0x70, 0xd2, 0x65, 0x38, 0xe9, 0xd2, 0x46, 0xba, 0x8c, 0x20, 0x5d, 0xda, 0x48, 0x97, 0x51, 0xa4, 0xcb, 0x28, 0xd2, 0x65, 0x14, 0xe9, 0x32, 0x8a, 0x74, 0x99, 0x42, 0xba, 0xb4, 0x91, 0x2e, 0x6d, 0xa4, 0x4b, 0x1b, 0xe9, 0xd2, 0x46, 0xba, 0xb4, 0x91, 0x2e, 0x6d, 0xa4, 0x4b, 0x1b, 0xe9, 0xd2, 0x46, 0xba, 0xb4, 0x91, 0x2e, 0x6d, 0xa4, 0xcb, 0x18, 0xd2, 0x65, 0x0c, 0xe9, 0x32, 0x9a, 0x74, 0x69, 0x57, 0xf3, 0x48, 0x8f, 0xf3, 0x49, 0x9b, 0xb4, 0x66, 0x15, 0x4b, 0xfa, 0x8c, 0xe3, 0xba, 0x78, 0xea, 0xc3, 0x4e, 0xb2, 0x4c, 0x66, 0x9b, 0x22, 0x87, 0x49, 0x9c, 0x09, 0xfe, 0xdf, 0xcd, 0x48, 0x67, 0x9b, 0x21,\n\t0xc7, 0x54, 0xa6, 0xe4, 0x93, 0x3a, 0x63, 0x48, 0x9d, 0x49, 0xa4, 0xce, 0x28, 0x52, 0x67, 0x2c, 0xa9, 0x33, 0x81, 0xd4, 0x19, 0xa3, 0x72, 0xa4, 0x98, 0xe4, 0x99, 0xa4, 0x7e, 0xa7, 0x3e, 0x2f, 0x70, 0xde, 0x17, 0xe1, 0xe2, 0xef, 0x6e, 0xfe, 0x76, 0x89, 0xfd, 0x5c, 0x39, 0x48, 0xfa, 0x8c, 0x22, 0x7d, 0x1e, 0x55, 0xe5, 0x3c, 0xf7, 0x1b, 0x3c, 0xde, 0x4d, 0x75, 0x0f, 0x09, 0xd4, 0x66, 0xd2, 0xa5, 0x84, 0x14, 0x6a, 0x27, 0x85, 0xc6, 0x93, 0x42, 0x53, 0x48, 0xa1, 0x36, 0x52, 0xa8, 0x8d, 0x14, 0x6a, 0x33, 0xdd, 0x4d, 0x52, 0xac, 0x2b, 0xd1, 0x24, 0x51, 0x1b, 0x49, 0xd4, 0x66, 0xba, 0x8f, 0xdb, 0xdd, 0x8f, 0x07, 0xd8, 0xaf, 0x87, 0xfa, 0x68, 0x20, 0xe1, 0x24, 0x52, 0x1b, 0x89, 0x34, 0x9e, 0x44, 0x1a, 0x4e, 0x22, 0xb5, 0x91, 0x48, 0x6d, 0x24, 0xd2, 0x93, 0x24, 0x52, 0x1b,\n\t0x89, 0xd4, 0xf7, 0xfd, 0x3c, 0xf1, 0x24, 0x52, 0x1b, 0x89, 0xd4, 0x46, 0x22, 0x8d, 0x26, 0x91, 0x86, 0x93, 0x48, 0x6d, 0xa6, 0x36, 0x5c, 0xff, 0xb9, 0x9c, 0x20, 0x95, 0x86, 0x9b, 0xc6, 0x4b, 0x9e, 0x69, 0x82, 0x14, 0x90, 0x4e, 0x8f, 0x98, 0x26, 0x91, 0x86, 0x29, 0x63, 0xff, 0xfb, 0x8d, 0x5f, 0x91, 0x92, 0xa7, 0x88, 0x87, 0xa4, 0x9a, 0x6a, 0x9a, 0x2b, 0xd9, 0xa6, 0xef, 0xa4, 0xcc, 0x34, 0x8f, 0xe4, 0x3a, 0x9f, 0x73, 0xfd, 0x9e, 0x54, 0x5b, 0xf5, 0x3e, 0xa4, 0x9d, 0xf4, 0x1a, 0x4e, 0x7a, 0x8d, 0x31, 0x15, 0x4b, 0x96, 0xa9, 0x04, 0xa5, 0xfe, 0x7f, 0x55, 0x5d, 0x4a, 0x9a, 0xb5, 0x6b, 0xac, 0x1a, 0xb4, 0x97, 0xa4, 0x48, 0x7b, 0x99, 0xc4, 0xd5, 0x53, 0x8d, 0x21, 0xd9, 0xda, 0x49, 0xb6, 0x4d, 0x48, 0xb6, 0x1f, 0x90, 0x6c, 0xed, 0x24, 0x5b, 0xbb, 0xc6, 0x2a, 0x81, 0x74,\n\t0x5b, 0x9b, 0x74, 0x6b, 0xd7, 0xde, 0x66, 0xbf, 0x2a, 0xe1, 0x86, 0x93, 0x70, 0x23, 0xb4, 0xf1, 0x52, 0x4c, 0xca, 0xb5, 0x91, 0x72, 0x0f, 0x91, 0x72, 0x6d, 0xa4, 0x5c, 0x1b, 0x29, 0xd7, 0xa6, 0x7d, 0x43, 0xfa, 0x9b, 0x45, 0x62, 0x9c, 0x43, 0x4a, 0x9e, 0xcb, 0xed, 0xbe, 0xe3, 0x76, 0x8c, 0x54, 0xa4, 0xdd, 0x28, 0xd2, 0x6e, 0x04, 0x69, 0xd7, 0xa1, 0x2d, 0x93, 0x04, 0x6d, 0x15, 0xd7, 0xad, 0xe6, 0xf2, 0x7a, 0x12, 0xea, 0x06, 0x6c, 0xc4, 0x26, 0x6c, 0xc6, 0x16, 0x84, 0x20, 0x14, 0x61, 0xd8, 0x8a, 0x6d, 0x1c, 0x7b, 0x3b, 0x76, 0x90, 0x16, 0x77, 0xca, 0x11, 0x52, 0xaf, 0x4d, 0xfb, 0x99, 0xf3, 0xff, 0x85, 0x04, 0xf9, 0x2b, 0xe9, 0x79, 0x37, 0xe7, 0xb5, 0x87, 0xe3, 0xed, 0x25, 0x65, 0xfe, 0xc6, 0xe3, 0xef, 0x63, 0xbb, 0x5f, 0x8e, 0x91, 0x7c, 0x63, 0x48, 0xbe, 0x87, 0x48,\n\t0xbe, 0x05, 0x24, 0xdf, 0x43, 0x24, 0xdf, 0x42, 0x92, 0x6f, 0x22, 0xc9, 0x37, 0x46, 0x3b, 0xca, 0xfd, 0x8f, 0x71, 0xf9, 0x38, 0xc7, 0x8a, 0xe2, 0xf2, 0x49, 0x52, 0x6e, 0x34, 0xfb, 0x31, 0xa4, 0xfb, 0x58, 0xb6, 0x71, 0x9c, 0x67, 0x3c, 0xc7, 0xb5, 0x71, 0xbf, 0x04, 0x24, 0x92, 0xb0, 0xed, 0x24, 0xd9, 0x24, 0xfe, 0x96, 0xca, 0xe3, 0xd2, 0x1e, 0x49, 0xc3, 0x09, 0xa4, 0xe1, 0x04, 0xd2, 0xf0, 0x04, 0xd2, 0xf0, 0x1c, 0x7f, 0x1a, 0xce, 0xa6, 0xac, 0x4e, 0x4b, 0x2e, 0xa9, 0xf8, 0x18, 0xa9, 0x38, 0x8a, 0x54, 0x1c, 0xa3, 0xe5, 0x70, 0x4e, 0xe7, 0xb8, 0xdf, 0xef, 0xec, 0x9f, 0xe7, 0x71, 0x2e, 0x90, 0xba, 0x2f, 0xfa, 0x93, 0x72, 0x43, 0x92, 0x72, 0x3f, 0x2d, 0x97, 0xf3, 0xcb, 0xa3, 0x9c, 0xf3, 0x49, 0xf6, 0x97, 0xb9, 0x8d, 0x87, 0xe7, 0x54, 0x20, 0x07, 0xfd, 0x89, 0xb9, 0x48,\n\t0x32, 0x49, 0xcd, 0x09, 0xa4, 0xe6, 0x70, 0x52, 0x73, 0x04, 0xa9, 0x39, 0x9c, 0xd4, 0x7c, 0x98, 0xd4, 0x9c, 0x40, 0x6a, 0xb6, 0x91, 0x9a, 0x6d, 0xa4, 0x66, 0xbb, 0x76, 0x43, 0xca, 0x48, 0xce, 0x43, 0x49, 0xce, 0x43, 0xb5, 0x3f, 0x78, 0x5c, 0x21, 0xf9, 0x2a, 0x92, 0xab, 0x09, 0x9a, 0x84, 0x93, 0xa0, 0x13, 0x48, 0xd0, 0x09, 0x24, 0xe8, 0x04, 0x12, 0x74, 0x34, 0x09, 0x3a, 0xd7, 0xac, 0x93, 0x62, 0x0d, 0x2e, 0x5b, 0x49, 0xd0, 0x41, 0x72, 0x88, 0x14, 0x1d, 0x4d, 0x8a, 0x3e, 0x48, 0x8a, 0x3e, 0x44, 0x8a, 0x3e, 0x49, 0x8a, 0x8e, 0x24, 0x45, 0x47, 0x91, 0xa2, 0xa3, 0x49, 0xd1, 0x71, 0xa4, 0xe8, 0x04, 0xf3, 0xdd, 0x5c, 0x5f, 0x97, 0xfd, 0x7b, 0x24, 0x89, 0x24, 0x7d, 0x92, 0x24, 0x1d, 0x4f, 0x92, 0x3e, 0x6a, 0x7e, 0x80, 0x44, 0x5a, 0x8f, 0xc7, 0xac, 0x4f, 0xba, 0x6e, 0x40,\n\t0xe2, 0x6e, 0xc8, 0x6d, 0x1f, 0xe4, 0x7e, 0x8d, 0x24, 0x86, 0x64, 0x9d, 0x60, 0x6e, 0xc2, 0x71, 0x9a, 0xb2, 0x7d, 0x88, 0x6d, 0x33, 0xae, 0x1b, 0xc8, 0xdf, 0x06, 0x91, 0xd8, 0x07, 0x73, 0xdf, 0x61, 0x12, 0x41, 0xc2, 0x8e, 0x20, 0x61, 0xdb, 0x49, 0xd8, 0x09, 0x24, 0xec, 0x70, 0x12, 0x76, 0x14, 0x09, 0x3b, 0x9c, 0x84, 0x1d, 0x4e, 0xc2, 0x0e, 0x27, 0x61, 0xdb, 0x49, 0xd8, 0x41, 0xe6, 0x78, 0x92, 0xba, 0x0d, 0xa9, 0xa4, 0x76, 0x07, 0xd7, 0x65, 0x49, 0x1a, 0x69, 0x3b, 0x8d, 0xb4, 0x6d, 0x23, 0x6d, 0xdb, 0x48, 0xdb, 0x36, 0xd2, 0xb6, 0xcd, 0x7c, 0x89, 0xeb, 0x72, 0xd9, 0xe6, 0xc1, 0xf7, 0xbb, 0x97, 0x97, 0x39, 0x4f, 0x0f, 0xdb, 0x02, 0x14, 0xa2, 0x88, 0x63, 0x16, 0x73, 0x5d, 0x09, 0x4a, 0x51, 0xe6, 0x4f, 0xdd, 0xf1, 0xa4, 0xee, 0x93, 0xa4, 0xee, 0x93, 0xa4, 0x6e, 0xdb,\n\t0x9f, 0xef, 0x7f, 0x5f, 0x67, 0x9f, 0x31, 0x82, 0xe4, 0x6d, 0x23, 0x79, 0xdb, 0x48, 0xde, 0x27, 0x49, 0xde, 0x36, 0x92, 0x77, 0x24, 0xc9, 0xfb, 0x1e, 0x92, 0x77, 0x38, 0xc9, 0xdb, 0x46, 0xf2, 0xb6, 0x05, 0x04, 0x4a, 0x46, 0x40, 0x0d, 0x58, 0xb8, 0xce, 0x2a, 0x76, 0x52, 0xb8, 0x8d, 0x14, 0x6e, 0x27, 0x85, 0xdb, 0x49, 0xe1, 0x76, 0x52, 0xb8, 0x8d, 0x14, 0x6e, 0x23, 0x85, 0xdb, 0x48, 0xe1, 0xe1, 0xa4, 0xf0, 0x70, 0x52, 0x78, 0x38, 0x29, 0xbc, 0x80, 0x14, 0x1e, 0x13, 0xb0, 0x52, 0x0a, 0x49, 0xe2, 0xc5, 0x81, 0xf5, 0xd9, 0x36, 0x24, 0x85, 0x37, 0x92, 0x70, 0xd2, 0xf8, 0x21, 0xd2, 0xf8, 0x51, 0xd2, 0x78, 0x0a, 0x69, 0x3c, 0x85, 0x34, 0xde, 0x8b, 0x34, 0xde, 0x90, 0x34, 0x9e, 0x42, 0x1a, 0x4f, 0x21, 0x8d, 0xa7, 0x90, 0xc6, 0x53, 0x48, 0xe3, 0x29, 0xa4, 0x71, 0x3b, 0x69,\n\t0xbc, 0x01, 0x69, 0x3c, 0x9c, 0x34, 0x1e, 0x41, 0x12, 0x8f, 0x20, 0x89, 0xc7, 0x90, 0xc4, 0xa3, 0x49, 0xe2, 0xe1, 0x81, 0x8c, 0x77, 0xa4, 0x71, 0x3b, 0x69, 0x3c, 0x9c, 0x34, 0x6e, 0x27, 0x8d, 0xc7, 0x93, 0xc6, 0x8f, 0x91, 0xc6, 0xc7, 0x90, 0xc6, 0x8f, 0x92, 0xc6, 0x9d, 0xa4, 0xf1, 0x68, 0xd2, 0x78, 0x22, 0x69, 0xdc, 0x46, 0x1a, 0x4f, 0x21, 0x8d, 0x17, 0x93, 0xc6, 0xc3, 0x2d, 0xad, 0x24, 0xdb, 0xf2, 0x08, 0x5a, 0xa3, 0x0d, 0xda, 0xe2, 0x51, 0xb4, 0x43, 0x7b, 0x3c, 0x86, 0x0e, 0x78, 0x1c, 0x4f, 0x48, 0xa1, 0xe5, 0x49, 0xb6, 0x4f, 0xe1, 0x69, 0x3c, 0x83, 0x8e, 0xe8, 0x84, 0x67, 0xf1, 0x1c, 0x9e, 0x47, 0x67, 0x74, 0x41, 0x57, 0x74, 0x43, 0x77, 0xbc, 0x80, 0x1e, 0x78, 0x11, 0x2f, 0xa1, 0x27, 0x5e, 0xe1, 0x78, 0xbd, 0xd0, 0x9b, 0xfd, 0x3e, 0xe8, 0xcb, 0x7e, 0x3f, 0xf4,\n\t0x67, 0x7f, 0x00, 0x06, 0x62, 0x10, 0x06, 0x63, 0x08, 0x5e, 0xc5, 0x50, 0xfe, 0x3e, 0x0c, 0xaf, 0xb1, 0xff, 0x3a, 0x86, 0xb3, 0xff, 0x06, 0x46, 0xb0, 0x3f, 0x92, 0xed, 0x28, 0xbc, 0xc9, 0xfe, 0x5b, 0x92, 0x68, 0x79, 0x1b, 0xef, 0x48, 0xb2, 0x65, 0x8c, 0xd8, 0x2d, 0x1f, 0xe1, 0x63, 0x8c, 0xc5, 0x27, 0xf8, 0x14, 0x9f, 0x61, 0x33, 0xb6, 0x20, 0x04, 0xa1, 0x08, 0xc3, 0x56, 0x6c, 0xc3, 0x4e, 0xf5, 0xa9, 0x25, 0x4e, 0x75, 0xb4, 0xc4, 0xab, 0x67, 0x2c, 0x36, 0xd5, 0xc4, 0x92, 0xa0, 0xee, 0xb1, 0x24, 0xab, 0x19, 0x96, 0x14, 0xf6, 0xd3, 0x70, 0x4a, 0xb5, 0xb1, 0x64, 0xa9, 0xfb, 0x2c, 0xd9, 0xec, 0x57, 0xa8, 0x20, 0xfd, 0x76, 0xb1, 0xeb, 0xac, 0x31, 0xf4, 0x3b, 0x71, 0x17, 0x6a, 0xa2, 0x16, 0x6a, 0xa3, 0x0e, 0xee, 0x46, 0xd5, 0x2b, 0x12, 0x76, 0xfd, 0x5e, 0x30, 0xd7, 0xe8,\n\t0xcc, 0x35, 0x3a, 0xeb, 0x11, 0x9d, 0xf5, 0x88, 0xce, 0x7a, 0x44, 0x6f, 0x80, 0x86, 0x60, 0x5d, 0xa2, 0x37, 0x42, 0x63, 0x34, 0x41, 0x53, 0x3c, 0x84, 0x66, 0x78, 0x18, 0xcd, 0xd1, 0x02, 0x2d, 0xd1, 0x0a, 0x8f, 0x48, 0xbe, 0xde, 0x86, 0x6d, 0x5b, 0xb6, 0x8f, 0xa2, 0x1d, 0xfb, 0xed, 0xf1, 0x18, 0x3a, 0xa0, 0x87, 0x14, 0xe9, 0x2f, 0x82, 0x39, 0x42, 0x7f, 0x19, 0x3d, 0xf1, 0x0a, 0x7a, 0xa1, 0x37, 0xfa, 0xa0, 0x2f, 0xc6, 0xa9, 0xda, 0xfa, 0xa7, 0x98, 0x82, 0xa9, 0x98, 0x86, 0xaf, 0x31, 0x1d, 0xdf, 0xa8, 0x78, 0x7d, 0x06, 0xdb, 0x6f, 0x31, 0x13, 0xb3, 0x30, 0x1b, 0x73, 0xb0, 0x10, 0x8b, 0x10, 0xac, 0xea, 0xea, 0xcb, 0xe5, 0xa4, 0xbe, 0x02, 0x2b, 0xb1, 0x0a, 0xab, 0xb1, 0x06, 0x6b, 0xb1, 0x0e, 0xeb, 0xb1, 0x01, 0x1b, 0xb1, 0x09, 0x9b, 0xb1, 0x45, 0x8d, 0xd0, 0x43, 0xd8,\n\t0x86, 0x22, 0x0c, 0x5b, 0xb1, 0x0d, 0xdb, 0xb1, 0x03, 0x3b, 0xb1, 0x0b, 0x3f, 0xe3, 0x17, 0xfc, 0x8a, 0xdd, 0xca, 0xa4, 0xef, 0x21, 0xf9, 0xef, 0x65, 0xff, 0x37, 0xec, 0x83, 0xef, 0xdf, 0x9b, 0x1d, 0x60, 0x7b, 0x10, 0x87, 0x10, 0x8e, 0x63, 0x12, 0xae, 0x1f, 0xc7, 0x09, 0x44, 0x22, 0x0a, 0xd1, 0x88, 0x41, 0xac, 0x44, 0xe8, 0x71, 0x88, 0x87, 0x0d, 0x09, 0x5c, 0x97, 0x08, 0x3b, 0xfb, 0x49, 0x6c, 0x93, 0x91, 0x82, 0x54, 0xa4, 0xc1, 0x81, 0x74, 0x64, 0x20, 0x13, 0x59, 0xc8, 0xc6, 0x69, 0x9c, 0xc1, 0x59, 0x38, 0xd5, 0x53, 0x7a, 0x0e, 0xdb, 0x73, 0xa0, 0xcf, 0xea, 0xe7, 0xc1, 0x7a, 0x45, 0x77, 0xc1, 0x0d, 0xd6, 0x2b, 0x3a, 0x73, 0xb9, 0x9e, 0x87, 0x7c, 0x5c, 0x96, 0x14, 0xdd, 0x03, 0xd2, 0x97, 0x5e, 0xc8, 0xb6, 0x08, 0xc5, 0x28, 0x41, 0x29, 0xca, 0x70, 0x05, 0xe5, 0xb8,\n\t0x8a, 0x0a, 0x54, 0xe2, 0x1a, 0xae, 0xe3, 0x06, 0xbc, 0xb8, 0x89, 0x3f, 0x24, 0xc5, 0xa8, 0x21, 0x05, 0x86, 0x05, 0x3a, 0x0c, 0x58, 0x25, 0xdc, 0x08, 0x62, 0x7b, 0x1b, 0x6e, 0xc7, 0x1d, 0xb8, 0x13, 0xb5, 0xd5, 0xf3, 0xc6, 0xfd, 0xaa, 0xb5, 0x51, 0x4f, 0x75, 0x36, 0x1a, 0x2a, 0xdd, 0x78, 0x50, 0xd5, 0x37, 0x1a, 0xa9, 0x7a, 0x46, 0x63, 0xd5, 0xd2, 0x68, 0xa2, 0x02, 0x8c, 0xa6, 0xfe, 0x7f, 0xa3, 0xf7, 0x62, 0xf5, 0x2b, 0x17, 0x09, 0xd5, 0xaf, 0x5c, 0xb4, 0x31, 0xda, 0x72, 0x7d, 0x3b, 0xb6, 0x4f, 0x73, 0xdd, 0x73, 0xaa, 0xad, 0xf1, 0xbc, 0x7a, 0xc0, 0xe8, 0xac, 0x9e, 0x36, 0xba, 0x89, 0xcd, 0xe8, 0x8e, 0x17, 0xd0, 0x03, 0x2f, 0xe2, 0x65, 0xf4, 0xc4, 0x2b, 0x60, 0x9c, 0x34, 0x7a, 0x83, 0xb1, 0xd2, 0xe8, 0x0b, 0xc6, 0x4b, 0xa3, 0x3f, 0x06, 0x60, 0x20, 0x06, 0x71, 0x9e,\n\t0x8c, 0x9b, 0xc6, 0x10, 0xbc, 0x8a, 0xa1, 0x18, 0x86, 0xd7, 0xf0, 0x3a, 0x86, 0xe3, 0x0d, 0x8c, 0xc0, 0x48, 0x8c, 0xc2, 0x9b, 0x78, 0x4b, 0xb5, 0x33, 0xde, 0x66, 0xfb, 0x0e, 0xde, 0xc5, 0x7b, 0x78, 0x1f, 0xa3, 0xf1, 0x01, 0x3e, 0xc4, 0x18, 0x7c, 0x84, 0x8f, 0x31, 0x16, 0xac, 0x81, 0x0d, 0xd6, 0xc0, 0x06, 0x6b, 0x60, 0xe3, 0x33, 0xb0, 0x0e, 0x32, 0x58, 0xa3, 0x19, 0xe3, 0x31, 0x01, 0x13, 0x31, 0x09, 0x93, 0x25, 0xce, 0xf8, 0x92, 0xed, 0x57, 0x9c, 0x1f, 0xeb, 0x22, 0x83, 0xb5, 0xb0, 0xc1, 0x1a, 0xd8, 0x60, 0x0d, 0x6c, 0xcc, 0x90, 0x4c, 0x83, 0x35, 0xb0, 0xc1, 0x1a, 0xd8, 0x60, 0x0d, 0x6c, 0xcc, 0xc6, 0x1c, 0xcc, 0xa5, 0x6c, 0xbf, 0x63, 0x3b, 0x8f, 0x32, 0x9a, 0x2f, 0x51, 0xc6, 0xf7, 0xf0, 0xfd, 0xeb, 0xb9, 0x85, 0x58, 0x04, 0xd6, 0x4e, 0xc6, 0x0f, 0x58, 0x8c, 0x1f,\n\t0xb1, 0x04, 0x3f, 0xc9, 0x49, 0x63, 0x19, 0xf7, 0x59, 0x8e, 0x15, 0x58, 0x89, 0x55, 0x58, 0x8d, 0x35, 0xea, 0x55, 0x63, 0x2d, 0xdb, 0x75, 0x58, 0x8f, 0x0d, 0xd8, 0x88, 0x4d, 0xd8, 0x8c, 0x2d, 0x08, 0x41, 0x28, 0xc2, 0xb0, 0x15, 0xac, 0xaf, 0x0c, 0xd6, 0x57, 0xc6, 0x0e, 0xec, 0x04, 0xeb, 0x2b, 0xe3, 0x67, 0xfc, 0x82, 0x5f, 0xb1, 0x1b, 0x7b, 0xb0, 0x17, 0xbf, 0x61, 0x1f, 0xf6, 0xe3, 0x00, 0x0e, 0xe2, 0x10, 0xc2, 0x71, 0x18, 0x11, 0x60, 0x7d, 0x65, 0x1c, 0xc5, 0x31, 0x1c, 0xc7, 0x09, 0x44, 0x82, 0x75, 0x96, 0x71, 0x12, 0xd1, 0x92, 0x6c, 0xc4, 0xb0, 0x8d, 0x45, 0x1c, 0xe2, 0x61, 0x43, 0x02, 0x12, 0x61, 0x47, 0x12, 0x92, 0x91, 0x82, 0x54, 0xa4, 0x49, 0xb4, 0xe1, 0x60, 0x9b, 0x2e, 0xe9, 0x46, 0x06, 0xfb, 0x99, 0x60, 0xfd, 0x6f, 0x64, 0x89, 0xdd, 0xc8, 0xc6, 0x69, 0x9c,\n\t0x01, 0xf3, 0x9f, 0xe1, 0x44, 0x0e, 0xce, 0x49, 0x86, 0xf1, 0x3b, 0xce, 0xe3, 0x82, 0xff, 0xdf, 0x44, 0x3b, 0x0c, 0x17, 0xdc, 0xb8, 0x84, 0x5c, 0xe4, 0x21, 0x1f, 0x97, 0xe1, 0x41, 0x01, 0x0a, 0x51, 0x84, 0x62, 0x94, 0xa0, 0x14, 0x65, 0x92, 0x66, 0x5c, 0x41, 0x39, 0xae, 0xa2, 0x02, 0x95, 0xb8, 0x26, 0xa9, 0xd6, 0xfb, 0x55, 0x63, 0x6b, 0x3d, 0xc9, 0xb6, 0xd6, 0x97, 0x22, 0x6b, 0x03, 0x34, 0xc4, 0x83, 0x5c, 0x6e, 0xc4, 0x96, 0xbc, 0x68, 0x25, 0x2f, 0x5a, 0x9b, 0x72, 0xf9, 0x21, 0x34, 0xc3, 0xc3, 0x68, 0xce, 0x75, 0x2d, 0xd0, 0x12, 0xcc, 0xab, 0xd6, 0x47, 0xd8, 0xb6, 0x46, 0x1b, 0xb4, 0x95, 0xc3, 0xd6, 0x47, 0xd1, 0x0e, 0xed, 0xf1, 0x18, 0x3a, 0xe0, 0x71, 0x3c, 0x81, 0x27, 0xf1, 0x14, 0x9e, 0xc6, 0x33, 0xe8, 0x88, 0x4e, 0x78, 0x16, 0xcf, 0xe1, 0x79, 0x74, 0x46, 0x17,\n\t0x74, 0x45, 0x37, 0x74, 0xc7, 0x0b, 0xe8, 0x81, 0x17, 0xf1, 0x12, 0x5e, 0x96, 0x63, 0xd6, 0x9e, 0x78, 0x05, 0xbd, 0xd0, 0x1b, 0x7d, 0xd0, 0x17, 0xfd, 0xd0, 0x1f, 0x03, 0x24, 0xc6, 0x3a, 0x10, 0x83, 0x30, 0x18, 0x43, 0xf0, 0x2a, 0x86, 0x62, 0x18, 0x5e, 0xc3, 0xeb, 0x18, 0x8e, 0x37, 0x30, 0x02, 0x23, 0x31, 0x0a, 0x6f, 0xe2, 0x2d, 0xbc, 0x8d, 0x77, 0xf0, 0x2e, 0xde, 0xc3, 0xfb, 0x18, 0x8d, 0x0f, 0xf0, 0x21, 0xc6, 0x48, 0xac, 0xff, 0xb7, 0xc7, 0x3f, 0x66, 0x3b, 0x56, 0x8e, 0x5a, 0x3f, 0x61, 0x3b, 0x0e, 0x9f, 0xe2, 0x33, 0x7c, 0x8e, 0x2f, 0x30, 0x1e, 0x13, 0x30, 0x11, 0x93, 0x30, 0x19, 0x5f, 0xe2, 0x2b, 0x4c, 0xc1, 0x54, 0x4c, 0xc3, 0x0c, 0x8e, 0xf9, 0x2d, 0x66, 0x62, 0x16, 0xc8, 0x9b, 0x56, 0xf2, 0xa6, 0x75, 0x2e, 0xbe, 0xc3, 0x3c, 0xcc, 0xc7, 0xf7, 0x58, 0x80, 0x85,\n\t0x58, 0x84, 0x60, 0xfc, 0x80, 0xc5, 0xf8, 0x11, 0x4b, 0xf0, 0x93, 0x1c, 0xb4, 0x2e, 0xe3, 0x9c, 0x96, 0x63, 0x05, 0x56, 0x62, 0x15, 0x56, 0x63, 0x0d, 0xd6, 0x62, 0x1d, 0xd6, 0x63, 0x03, 0x36, 0x62, 0x13, 0x36, 0x63, 0x0b, 0x42, 0x10, 0x8a, 0x30, 0x6c, 0xc5, 0x36, 0x6c, 0xc7, 0x0e, 0xec, 0xc4, 0x2e, 0xec, 0x91, 0x52, 0xeb, 0x41, 0xb1, 0x5b, 0x0f, 0xa9, 0x7b, 0xac, 0xe1, 0x38, 0x8c, 0x08, 0x1c, 0x93, 0x12, 0xeb, 0x09, 0x49, 0xb0, 0x46, 0x8a, 0xcd, 0x1a, 0x25, 0x69, 0xd6, 0x93, 0x88, 0x96, 0x68, 0x6b, 0x2c, 0xe2, 0xb8, 0x2e, 0x1e, 0x36, 0x24, 0x20, 0x11, 0x76, 0x24, 0x71, 0xfb, 0x64, 0xa4, 0xc8, 0x49, 0x6b, 0x2a, 0x97, 0xe9, 0x37, 0xd6, 0x53, 0x72, 0xc3, 0x9a, 0xcf, 0xf1, 0x2f, 0xc3, 0x83, 0x02, 0x14, 0xe2, 0x8a, 0x84, 0x5b, 0xcb, 0x71, 0x15, 0xac, 0x07, 0xad, 0x95,\n\t0xb8, 0xc6, 0x73, 0xbe, 0x8e, 0x1b, 0xf0, 0xe2, 0xa6, 0xc4, 0x04, 0x2d, 0x92, 0xc3, 0x41, 0x8b, 0x55, 0xef, 0xa0, 0x1f, 0xd5, 0x84, 0xa0, 0x9f, 0x54, 0xc3, 0xa0, 0xa5, 0x52, 0x18, 0x44, 0x8e, 0x0b, 0x3a, 0x28, 0x45, 0x41, 0x87, 0xc4, 0x1e, 0x14, 0x2e, 0x91, 0x41, 0x87, 0x11, 0x21, 0xe1, 0x41, 0xcc, 0x8b, 0x41, 0x89, 0x92, 0x1a, 0x30, 0x40, 0x99, 0xa5, 0x50, 0x05, 0x20, 0x50, 0x92, 0x95, 0x45, 0xd2, 0x95, 0x8e, 0x3b, 0x50, 0x5b, 0xca, 0x54, 0x5d, 0x12, 0xfa, 0x03, 0xec, 0xd7, 0x43, 0x7d, 0x3c, 0x88, 0xbf, 0x5e, 0x59, 0xb9, 0x4b, 0xb5, 0x42, 0x6b, 0xd2, 0x7c, 0x1b, 0xb4, 0x45, 0x3b, 0x89, 0x54, 0xed, 0xf1, 0x18, 0x3a, 0xe0, 0x71, 0x3c, 0x81, 0x27, 0xe5, 0xa4, 0x7a, 0x0a, 0x4f, 0xe3, 0x19, 0x89, 0x57, 0x1d, 0xb9, 0xae, 0x13, 0x9e, 0x95, 0x4c, 0xf5, 0x1c, 0x9e, 0x47,\n\t0x67, 0x74, 0x41, 0x57, 0x74, 0x43, 0x77, 0xbc, 0x80, 0x1e, 0x78, 0x11, 0x2f, 0xe1, 0x65, 0xf4, 0xc4, 0x2b, 0xe8, 0x85, 0xde, 0xe8, 0x83, 0xbe, 0xe8, 0x87, 0xfe, 0x18, 0x80, 0x81, 0x18, 0x84, 0xc1, 0x18, 0x82, 0x57, 0x31, 0x14, 0xc3, 0xf0, 0x1a, 0x5e, 0xc7, 0x70, 0x8c, 0xe0, 0x79, 0x8c, 0x52, 0x83, 0xd4, 0x7b, 0xaa, 0xa5, 0x7a, 0x1f, 0x1f, 0x48, 0x9a, 0xfa, 0x08, 0x1f, 0x63, 0x2c, 0x3e, 0xe1, 0x1c, 0xc7, 0xe1, 0x53, 0x7c, 0xc6, 0xe5, 0x2f, 0x38, 0xff, 0xf1, 0x6c, 0x27, 0x48, 0x9c, 0x9a, 0x88, 0x49, 0x60, 0x36, 0x51, 0x5f, 0x71, 0xac, 0x29, 0xe2, 0x50, 0x53, 0x31, 0x0d, 0x5f, 0x63, 0x3a, 0xbe, 0xc1, 0x0c, 0x7c, 0x8b, 0x99, 0x98, 0x85, 0xd9, 0x62, 0x57, 0x73, 0x30, 0x57, 0x12, 0xd5, 0x77, 0xdc, 0x6f, 0x1e, 0x65, 0x3f, 0x5f, 0xb2, 0xd5, 0xf7, 0xec, 0xc7, 0xfa, 0xdf,\n\t0xbf, 0x4f, 0x57, 0xf1, 0x6c, 0xed, 0x6c, 0x93, 0xa5, 0x54, 0xa5, 0x48, 0x94, 0x4a, 0x93, 0x94, 0xea, 0xf7, 0xf1, 0x53, 0x54, 0x86, 0xc4, 0xaa, 0x4c, 0xfe, 0x7e, 0x4a, 0x92, 0x54, 0x16, 0xb7, 0xc9, 0x16, 0x9b, 0x3a, 0xcd, 0xfe, 0x59, 0xce, 0x8b, 0x11, 0xb5, 0xfa, 0x37, 0x4f, 0x7c, 0x9f, 0x32, 0x4b, 0x53, 0x17, 0x38, 0xef, 0x8b, 0x70, 0xf1, 0x77, 0x37, 0x2e, 0xb1, 0x9f, 0x2b, 0x47, 0x15, 0x49, 0x4b, 0x91, 0x60, 0xab, 0x5f, 0x55, 0x49, 0x57, 0x37, 0x55, 0x1d, 0xff, 0xfb, 0xfa, 0x55, 0xaf, 0xaa, 0xa4, 0x9b, 0xee, 0x94, 0x14, 0xd3, 0x5d, 0x72, 0xca, 0x54, 0x53, 0xd2, 0x4c, 0xb5, 0x50, 0x1b, 0x77, 0x73, 0xb9, 0xae, 0x24, 0x98, 0xee, 0x61, 0xff, 0x5e, 0xfc, 0xf5, 0xaa, 0x4a, 0x9a, 0xa9, 0x1e, 0xea, 0xa3, 0x81, 0x44, 0x9a, 0x1a, 0xb2, 0xf5, 0x7d, 0x0f, 0x67, 0x63, 0xf6,\n\t0x9b, 0xb0, 0xdf, 0x14, 0x0f, 0x49, 0xa2, 0xa9, 0x19, 0xdb, 0x87, 0xd1, 0x9c, 0xbf, 0xb5, 0x60, 0xdb, 0x12, 0xad, 0xb8, 0xfe, 0x11, 0x6e, 0xd7, 0x9a, 0xfd, 0x36, 0xec, 0x57, 0xbd, 0xd7, 0x7f, 0xd2, 0x34, 0x5e, 0xf2, 0x4d, 0x13, 0xa4, 0xd0, 0x34, 0x51, 0xa2, 0x4c, 0x93, 0xa4, 0xd4, 0x34, 0x99, 0xc7, 0xfd, 0x92, 0x73, 0xfb, 0x4a, 0x4e, 0x9b, 0xa6, 0x48, 0x91, 0x69, 0x8e, 0x64, 0x99, 0xe6, 0xf2, 0xf7, 0x79, 0x5c, 0x37, 0x9f, 0xfd, 0xef, 0xa5, 0xcc, 0xe4, 0xe6, 0xbc, 0x73, 0x39, 0x96, 0xef, 0xf7, 0x41, 0x8a, 0xb9, 0xbe, 0x04, 0xa5, 0x92, 0x5d, 0xfd, 0x6a, 0x4a, 0x7a, 0xf5, 0xab, 0x29, 0x25, 0xda, 0xcb, 0x52, 0xac, 0xf5, 0x54, 0xef, 0x6b, 0xaf, 0x70, 0x5d, 0x2f, 0xf5, 0xa0, 0xd6, 0x4f, 0xbd, 0xab, 0xf5, 0x67, 0x7f, 0x00, 0x49, 0xbf, 0xea, 0xd5, 0x94, 0xbb, 0xb4, 0x91,\n\t0x5c, 0xae, 0x7a, 0x25, 0x25, 0x52, 0xe3, 0x7c, 0xb4, 0xf1, 0x5c, 0x3f, 0x89, 0xbf, 0x7f, 0x25, 0x27, 0xb4, 0x29, 0x6c, 0xa9, 0x63, 0x8d, 0x3a, 0xd6, 0xbe, 0x21, 0xf5, 0xcf, 0x22, 0xe1, 0xcf, 0x51, 0x0f, 0x68, 0x73, 0xb9, 0xdd, 0x77, 0xa4, 0xfb, 0x79, 0x5c, 0x17, 0x2c, 0x71, 0xda, 0x8f, 0x5c, 0x5e, 0xc2, 0xe3, 0x2f, 0x93, 0x64, 0x6d, 0x15, 0xd7, 0xb1, 0x62, 0xd6, 0xd6, 0xb3, 0xdd, 0x80, 0x8d, 0xd8, 0x84, 0xcd, 0xd8, 0x82, 0x10, 0x84, 0x22, 0x0c, 0x5b, 0xb1, 0x8d, 0x63, 0x6f, 0xc7, 0x0e, 0xb1, 0x6b, 0x3b, 0x25, 0x5a, 0xdb, 0xc5, 0x63, 0xfe, 0xec, 0xff, 0x0c, 0x41, 0xa2, 0xf6, 0xab, 0xc4, 0x6a, 0xbb, 0x39, 0xaf, 0x3d, 0x1c, 0x6f, 0xaf, 0xc4, 0x68, 0xbf, 0xf1, 0xf8, 0xcc, 0xf4, 0xda, 0x7e, 0xae, 0x3f, 0xc0, 0xdf, 0xab, 0x3e, 0x43, 0x50, 0x78, 0xcb, 0x67, 0x08, 0x1c,\n\t0xda, 0x11, 0x8e, 0x73, 0x94, 0x7d, 0x46, 0xaa, 0xea, 0xcf, 0x12, 0xd8, 0xb5, 0x93, 0xdc, 0x36, 0x9a, 0xfd, 0x18, 0xd5, 0x57, 0x8b, 0x65, 0x1b, 0xc7, 0x63, 0xc4, 0x73, 0xdf, 0xaa, 0xcf, 0x12, 0x9c, 0xd0, 0x12, 0x25, 0x5e, 0x23, 0xb5, 0x6a, 0x49, 0x6c, 0x53, 0xb9, 0x6d, 0x1a, 0xc7, 0x71, 0x70, 0x9b, 0x74, 0x64, 0xaa, 0xcf, 0xb5, 0x53, 0xea, 0x5b, 0x2d, 0x4b, 0xfd, 0xa8, 0x9d, 0x96, 0xfc, 0xea, 0xcf, 0x16, 0x24, 0x6a, 0x4e, 0x49, 0xd2, 0x72, 0x38, 0xaf, 0x73, 0x1c, 0xff, 0x77, 0xca, 0xe0, 0x3c, 0xe7, 0x76, 0x41, 0x32, 0xb4, 0x8b, 0x3c, 0x27, 0x97, 0xaa, 0xa7, 0x5d, 0x52, 0xfd, 0xb5, 0x5c, 0xca, 0x3f, 0x8f, 0xdb, 0xe5, 0x4b, 0x9e, 0xc6, 0x48, 0xa7, 0x79, 0xb8, 0x5d, 0xd5, 0xe7, 0x0e, 0x16, 0x6b, 0x45, 0x52, 0xa4, 0x15, 0x73, 0xfc, 0x12, 0xce, 0xa1, 0x94, 0xe3, 0x94,\n\t0x71, 0xfd, 0x15, 0xf6, 0xcb, 0x79, 0xec, 0xab, 0x9c, 0x63, 0x05, 0x2a, 0xa9, 0x1b, 0xaf, 0x1a, 0xac, 0xdd, 0xc4, 0x1f, 0x94, 0x8d, 0x48, 0x9c, 0x59, 0x49, 0x82, 0xd9, 0x44, 0xe2, 0xd7, 0xe4, 0x84, 0xd9, 0x2c, 0x69, 0xe6, 0x00, 0x04, 0x82, 0x74, 0x6c, 0xb6, 0x88, 0xa7, 0xfa, 0x15, 0x94, 0x34, 0xb3, 0x95, 0xdb, 0x54, 0x7d, 0x0e, 0x21, 0xc1, 0x7c, 0xbb, 0x1c, 0x37, 0xdf, 0xc1, 0xfe, 0x9d, 0xdc, 0xe6, 0x2e, 0x2e, 0xd7, 0x44, 0x2d, 0x6e, 0x57, 0x5b, 0x92, 0xcc, 0x75, 0xb8, 0xed, 0xdd, 0x1c, 0xb7, 0xae, 0xa4, 0x98, 0xef, 0x91, 0x0c, 0x33, 0xc9, 0xce, 0x7c, 0x9f, 0x24, 0x9b, 0xef, 0x97, 0x68, 0x33, 0xa9, 0xce, 0x5c, 0x5f, 0x32, 0xcd, 0x0d, 0xe4, 0x94, 0xb9, 0x21, 0x7f, 0x7f, 0x90, 0xfb, 0x37, 0xe2, 0xb6, 0x8d, 0xb9, 0x4f, 0x13, 0xfe, 0x4e, 0x7b, 0xf7, 0x7f, 0x36, 0xa1,\n\t0x19, 0xd7, 0x0d, 0xe4, 0xb6, 0x7f, 0x7d, 0x3e, 0x21, 0xca, 0xfc, 0x9a, 0x44, 0x9a, 0x37, 0x49, 0xba, 0x79, 0x33, 0xf7, 0xdb, 0xc2, 0x3e, 0xab, 0x3b, 0xf3, 0x0e, 0xb6, 0xbb, 0x40, 0x9d, 0x9a, 0x4f, 0xf0, 0xb7, 0x28, 0xa5, 0x9b, 0xe3, 0xa5, 0xd8, 0x6c, 0x43, 0xaa, 0x94, 0x98, 0x1d, 0x5c, 0x97, 0x25, 0xd9, 0xe6, 0x6c, 0x5c, 0xe0, 0xd8, 0x17, 0xe1, 0x82, 0x1b, 0x97, 0x38, 0x87, 0x5c, 0xb6, 0x79, 0xc8, 0x87, 0xef, 0x3b, 0x6d, 0x3d, 0x6c, 0x0b, 0x50, 0x88, 0x22, 0x8e, 0x59, 0xf5, 0x1d, 0xb7, 0x29, 0x66, 0x52, 0x87, 0xb9, 0x4c, 0x0a, 0xfd, 0xdf, 0x71, 0x5b, 0xce, 0x39, 0x5f, 0x05, 0xab, 0x23, 0x73, 0x25, 0xe7, 0x75, 0x0d, 0xd7, 0xd9, 0xaf, 0x7a, 0xf5, 0x24, 0xcd, 0x7c, 0x13, 0x7f, 0xf0, 0x77, 0x91, 0xb4, 0x00, 0xca, 0x36, 0xc0, 0xa4, 0xea, 0x04, 0x68, 0x12, 0x19, 0x40,\n\t0xd9, 0x06, 0x50, 0xb6, 0x01, 0x81, 0x52, 0x18, 0x50, 0x03, 0x16, 0xae, 0xab, 0x7a, 0xf5, 0x24, 0x2d, 0xe0, 0x45, 0x49, 0x0f, 0x78, 0x09, 0x3d, 0xd1, 0x8b, 0xcb, 0x7d, 0xd0, 0x0f, 0x03, 0xb8, 0xcd, 0x40, 0x0c, 0x06, 0xe3, 0x6d, 0xc0, 0x0a, 0x6e, 0xbf, 0x52, 0x4a, 0xfc, 0x9f, 0x63, 0xa8, 0xcf, 0xb6, 0xa1, 0xc4, 0x05, 0x36, 0x92, 0xc8, 0xc0, 0xc6, 0x72, 0x22, 0xb0, 0x89, 0xc4, 0x04, 0x1e, 0x95, 0xcc, 0xc0, 0x63, 0x88, 0x54, 0x2f, 0x07, 0x46, 0xa9, 0x7a, 0x81, 0x89, 0xec, 0xdb, 0x91, 0x84, 0x64, 0xa4, 0xe0, 0xac, 0xa4, 0x07, 0x3a, 0x55, 0x93, 0xc0, 0xdf, 0xb9, 0xdf, 0x25, 0x39, 0x19, 0x98, 0x0f, 0x66, 0xcc, 0xc0, 0x02, 0x49, 0x08, 0x2c, 0xe4, 0xba, 0xaa, 0x57, 0x4f, 0xd2, 0x03, 0x2b, 0xfc, 0xff, 0xea, 0x3a, 0xbd, 0xfa, 0xb3, 0x0c, 0x71, 0x35, 0x34, 0xf5, 0xfe, 0x2d,\n\t0x9f, 0x65, 0x48, 0xaa, 0x51, 0x43, 0x52, 0x6a, 0x30, 0x46, 0x55, 0x7f, 0x96, 0xc1, 0xf7, 0xea, 0x49, 0xa4, 0xa5, 0x95, 0x14, 0x5a, 0x1e, 0x41, 0x6b, 0xb4, 0x41, 0x5b, 0x3c, 0x8a, 0x76, 0x68, 0x8f, 0xc7, 0xd0, 0x01, 0x8f, 0xa3, 0xea, 0xd5, 0x93, 0x42, 0xcb, 0x53, 0x78, 0x1a, 0xcf, 0xa0, 0x23, 0x3a, 0xe1, 0x59, 0x3c, 0x87, 0xe7, 0xd1, 0x19, 0x5d, 0xd0, 0x15, 0xdd, 0xd0, 0x1d, 0x2f, 0xa0, 0x07, 0x5e, 0xc4, 0x4b, 0xe8, 0x89, 0xbf, 0x5e, 0x3d, 0x29, 0xb4, 0xf4, 0xc1, 0x5f, 0xaf, 0x9e, 0x14, 0x5a, 0x06, 0x60, 0x20, 0x06, 0x61, 0x30, 0x86, 0xe0, 0x55, 0xfc, 0xf5, 0xea, 0x49, 0xa1, 0xe5, 0x75, 0xfc, 0xf5, 0xea, 0x49, 0xe1, 0x2d, 0xaf, 0x9e, 0x14, 0x5a, 0xde, 0x92, 0x64, 0xcb, 0xdb, 0x78, 0x47, 0x52, 0x2d, 0x63, 0x24, 0xdd, 0xf2, 0x11, 0x3e, 0xc6, 0x58, 0x7c, 0x82, 0x4f,\n\t0xf1, 0x19, 0x36, 0x63, 0x0b, 0x42, 0x10, 0x8a, 0x30, 0x6c, 0xc5, 0x36, 0xec, 0x54, 0x1f, 0x5b, 0xe2, 0xd4, 0x93, 0x96, 0x78, 0xf5, 0x84, 0xc5, 0xa6, 0x1e, 0xb4, 0x24, 0xa8, 0xda, 0x96, 0x64, 0x35, 0xcd, 0x92, 0xc2, 0x7e, 0x1a, 0x4e, 0xa9, 0x96, 0x96, 0x2c, 0x55, 0xd7, 0x92, 0xcd, 0x7e, 0xbe, 0x94, 0x59, 0x2e, 0xc3, 0x83, 0x0a, 0xa5, 0xeb, 0xb7, 0x4b, 0xba, 0xce, 0xba, 0x42, 0xbf, 0x13, 0x77, 0xa1, 0x26, 0x6a, 0xa1, 0x36, 0xea, 0xe0, 0x6e, 0xd4, 0x25, 0x65, 0xdf, 0xc3, 0xf6, 0x5e, 0xdc, 0x87, 0xfb, 0xc1, 0xfa, 0x43, 0x67, 0xfd, 0xa1, 0xb3, 0xfe, 0xd0, 0x1b, 0xa0, 0x21, 0x58, 0x87, 0xe8, 0x8d, 0xd0, 0x18, 0x4d, 0xd0, 0x14, 0xd4, 0xa1, 0xde, 0x0c, 0x0f, 0xa3, 0x39, 0x5a, 0xa0, 0x25, 0x5a, 0xa1, 0xea, 0xb3, 0x1d, 0xe9, 0xb7, 0x7c, 0xb6, 0x23, 0x5d, 0x6f, 0x8f, 0xc7,\n\t0xd0, 0x01, 0xff, 0xfe, 0x2b, 0x29, 0x77, 0xe9, 0x9f, 0x62, 0x0a, 0xa6, 0x62, 0x1a, 0xbe, 0xc6, 0x74, 0x7c, 0xa3, 0xa2, 0xf5, 0x19, 0x6c, 0xbf, 0xc5, 0x4c, 0xcc, 0xc2, 0x6c, 0xcc, 0xc1, 0x42, 0x2c, 0x42, 0xb0, 0xaa, 0xa5, 0x2f, 0x97, 0x04, 0x7d, 0x05, 0x56, 0x62, 0x15, 0x56, 0x63, 0x0d, 0xd6, 0x62, 0x1d, 0xd6, 0x63, 0x03, 0x36, 0x62, 0x13, 0x36, 0xa3, 0xea, 0x95, 0x94, 0x04, 0x3d, 0x14, 0x61, 0xd8, 0x8a, 0x6d, 0xd8, 0x8e, 0x1d, 0xd8, 0x89, 0x5d, 0xf8, 0x19, 0xbf, 0xe0, 0x57, 0x54, 0xbd, 0x92, 0x92, 0xa0, 0xef, 0x05, 0x73, 0x84, 0xbe, 0x0f, 0xfb, 0xa5, 0x42, 0x3f, 0xc0, 0xf6, 0x20, 0x0e, 0x21, 0x1c, 0xc7, 0x24, 0x52, 0x3f, 0x8e, 0x13, 0x88, 0x44, 0x14, 0xa2, 0x11, 0x83, 0x58, 0x39, 0xa9, 0xc7, 0x21, 0x1e, 0x36, 0x24, 0x70, 0x5d, 0x22, 0xec, 0xec, 0x27, 0xb1, 0x4d,\n\t0x46, 0x0a, 0x52, 0x91, 0x06, 0x07, 0xd2, 0x91, 0x81, 0x4c, 0x64, 0x21, 0x1b, 0xa7, 0x71, 0x06, 0x67, 0xe1, 0x54, 0xcf, 0xe8, 0x39, 0x6c, 0xcf, 0x81, 0xfe, 0xab, 0x9f, 0x07, 0x6b, 0x14, 0xdd, 0x05, 0x37, 0x58, 0xa3, 0xe8, 0xcc, 0xe3, 0x7a, 0x1e, 0xf2, 0x71, 0x59, 0xd2, 0x74, 0x8f, 0x64, 0xea, 0x05, 0x52, 0xa2, 0x17, 0xb2, 0x2d, 0x42, 0x31, 0x4a, 0x50, 0x8a, 0x32, 0x5c, 0x41, 0x39, 0xae, 0xc2, 0xf7, 0x7b, 0x6c, 0x95, 0xb8, 0x86, 0xeb, 0xb8, 0x01, 0x2f, 0x6e, 0xe2, 0x0f, 0xd2, 0x7d, 0x0d, 0x29, 0x32, 0x2c, 0xd0, 0x61, 0xc0, 0x2a, 0x91, 0x46, 0x10, 0xdb, 0xdb, 0x70, 0x3b, 0xee, 0xc0, 0x9d, 0xa8, 0xad, 0x3a, 0x1a, 0xf7, 0xab, 0x16, 0x46, 0x3d, 0xd5, 0xe9, 0x96, 0x57, 0x52, 0x1e, 0xa8, 0xfe, 0x0c, 0x88, 0x5e, 0xfd, 0x4a, 0x4a, 0xf7, 0xea, 0x57, 0x52, 0xd2, 0x8c, 0xd6,\n\t0x6a, 0x9b, 0xd1, 0x46, 0xb5, 0x34, 0xda, 0xaa, 0xfb, 0x8d, 0x76, 0x6c, 0x9f, 0xe6, 0xba, 0xe7, 0xd4, 0x23, 0xc6, 0xf3, 0xea, 0x1e, 0xa3, 0xb3, 0x7a, 0xdc, 0xe8, 0xc6, 0xe5, 0xee, 0x78, 0x01, 0x3d, 0xf0, 0xa2, 0xa4, 0x1a, 0x2f, 0xb3, 0xed, 0x89, 0x57, 0xc0, 0x98, 0x69, 0xf4, 0x06, 0xe3, 0xa6, 0xd1, 0x17, 0x8c, 0x9d, 0x46, 0x7f, 0x0c, 0xe0, 0x76, 0x03, 0xd9, 0x0e, 0xe2, 0x3c, 0x19, 0x43, 0x8d, 0x21, 0x78, 0x15, 0x43, 0x31, 0x0c, 0xcc, 0x29, 0xc6, 0xeb, 0x18, 0x8e, 0x37, 0x30, 0x02, 0x23, 0x31, 0x0a, 0x6f, 0xe2, 0x2d, 0xd5, 0xde, 0x78, 0x9b, 0xed, 0x3b, 0x78, 0x17, 0xef, 0xe1, 0x7d, 0x8c, 0xc6, 0x07, 0xf8, 0x10, 0x63, 0xf0, 0x11, 0x3e, 0xc6, 0x58, 0xb0, 0xee, 0x35, 0x58, 0xf7, 0x1a, 0xac, 0x7b, 0x8d, 0xcf, 0xc0, 0x3a, 0xc8, 0xf8, 0x02, 0xe3, 0x31, 0x01, 0x13, 0x31,\n\t0x09, 0x93, 0xc5, 0x66, 0x7c, 0xc9, 0xf6, 0x2b, 0xce, 0x8f, 0x75, 0x91, 0x31, 0x15, 0xd3, 0xf1, 0x0d, 0xaa, 0xfe, 0x85, 0x75, 0x9a, 0x31, 0x13, 0xb3, 0x30, 0x1b, 0x73, 0x30, 0x57, 0x8a, 0x8d, 0xef, 0xd8, 0xce, 0x53, 0x6d, 0x8d, 0xf9, 0x12, 0x67, 0x7c, 0x8f, 0x05, 0x58, 0x88, 0x45, 0x60, 0xed, 0x64, 0xfc, 0x80, 0xc5, 0xf8, 0x11, 0x4b, 0xf0, 0x13, 0x96, 0x91, 0xee, 0x97, 0x63, 0x05, 0x56, 0x62, 0x15, 0x56, 0x63, 0x8d, 0x1a, 0x60, 0xac, 0x65, 0xbb, 0x0e, 0xeb, 0xb1, 0x01, 0x1b, 0xb1, 0x09, 0x9b, 0xb1, 0x05, 0x21, 0x08, 0x45, 0x18, 0xb6, 0x82, 0xf5, 0x95, 0xc1, 0xfa, 0xca, 0xd8, 0x81, 0x9d, 0xd8, 0x85, 0x9f, 0xf1, 0x0b, 0x7e, 0xc5, 0x6e, 0xec, 0xc1, 0x5e, 0xfc, 0x86, 0x7d, 0xd8, 0x8f, 0x03, 0x38, 0x88, 0x43, 0x08, 0xc7, 0x61, 0xb0, 0xbe, 0x32, 0x58, 0x5f, 0x19, 0x47,\n\t0x71, 0x0c, 0xc7, 0x71, 0x02, 0x91, 0x60, 0x9d, 0x65, 0x9c, 0x44, 0xb4, 0x64, 0x18, 0x31, 0x6c, 0x63, 0x11, 0x87, 0x78, 0xd8, 0x90, 0x80, 0x44, 0xd8, 0x91, 0x84, 0x64, 0xa4, 0x20, 0x15, 0x69, 0x92, 0x68, 0x38, 0xd8, 0xfa, 0xfe, 0xb5, 0x75, 0x06, 0xfb, 0x99, 0x60, 0xcd, 0x6f, 0x64, 0xd1, 0x86, 0xb3, 0x71, 0x1a, 0x67, 0x70, 0x16, 0x4e, 0xe4, 0xe0, 0x9c, 0x14, 0x1a, 0xbf, 0xe3, 0x3c, 0x2e, 0xe0, 0xa2, 0x64, 0x1b, 0x2e, 0xb8, 0x71, 0x09, 0xb9, 0xc8, 0x43, 0x3e, 0x2e, 0xc3, 0x83, 0x02, 0x14, 0xa2, 0x08, 0xc5, 0x28, 0x01, 0xeb, 0x66, 0x83, 0x7e, 0x65, 0xd0, 0xaf, 0x0c, 0xfa, 0x95, 0x41, 0xbf, 0x32, 0xe8, 0x57, 0x06, 0xfd, 0xca, 0xa0, 0x5f, 0x59, 0xef, 0x57, 0x4d, 0xac, 0xcc, 0xdf, 0xd6, 0xfa, 0x68, 0x80, 0x86, 0x78, 0x10, 0x8d, 0xd0, 0x18, 0x4d, 0xd0, 0x14, 0x0f, 0xa1,\n\t0x19, 0x1e, 0x46, 0x73, 0xb4, 0x40, 0x4b, 0xb4, 0xc2, 0x23, 0x68, 0x8d, 0x36, 0x68, 0x2b, 0x51, 0xd6, 0x47, 0xd1, 0x0e, 0xed, 0xf1, 0x18, 0x3a, 0xe0, 0x71, 0x3c, 0x81, 0x27, 0xf1, 0x14, 0x9e, 0xc6, 0x33, 0xe8, 0x88, 0x4e, 0x78, 0x16, 0xcf, 0xe1, 0x79, 0x74, 0x46, 0x17, 0x74, 0x45, 0x37, 0x74, 0xc7, 0x0b, 0xe8, 0x81, 0x17, 0xf1, 0x12, 0x5e, 0x96, 0x58, 0x6b, 0x4f, 0xbc, 0x82, 0x5e, 0xe8, 0x8d, 0x3e, 0xe8, 0x8b, 0x7e, 0xe8, 0x8f, 0x01, 0x92, 0x64, 0x1d, 0x88, 0x41, 0x18, 0x8c, 0x21, 0x78, 0x15, 0x43, 0x31, 0x0c, 0xaf, 0xe1, 0x75, 0x0c, 0xc7, 0x1b, 0x18, 0x81, 0x91, 0x18, 0x85, 0x37, 0xf1, 0x16, 0xde, 0xc6, 0x3b, 0x78, 0x17, 0xef, 0xe1, 0x7d, 0x8c, 0xc6, 0x07, 0xf8, 0x10, 0x63, 0xf0, 0x91, 0x6a, 0x6e, 0xfd, 0x98, 0xed, 0x58, 0x92, 0xff, 0x27, 0x6c, 0xc7, 0xe1, 0x53,\n\t0x7c, 0x86, 0xcf, 0xf1, 0x05, 0xc6, 0x63, 0x02, 0x26, 0x62, 0x12, 0x26, 0xe3, 0x4b, 0x7c, 0x85, 0x29, 0x98, 0x8a, 0x69, 0x98, 0x81, 0x6f, 0x31, 0x13, 0xb3, 0x30, 0x1b, 0x73, 0x30, 0x17, 0xdf, 0x61, 0x1e, 0xe6, 0xe3, 0x7b, 0x2c, 0xc0, 0x42, 0x2c, 0x42, 0x30, 0x7e, 0xc0, 0x62, 0xfc, 0x88, 0x25, 0xa8, 0xfa, 0x1c, 0x4a, 0x8c, 0x75, 0x39, 0x56, 0x60, 0x25, 0x56, 0x61, 0x35, 0xd6, 0x60, 0x2d, 0xd6, 0x61, 0x3d, 0x36, 0x60, 0x23, 0x36, 0x61, 0x33, 0xb6, 0x20, 0x04, 0xa1, 0x08, 0xc3, 0x56, 0x6c, 0xc3, 0x76, 0xec, 0xc0, 0x4e, 0xec, 0x42, 0xd5, 0x2b, 0x29, 0xe9, 0xd6, 0x43, 0xaa, 0x8e, 0x35, 0x1c, 0x87, 0x11, 0x81, 0xaa, 0x57, 0x52, 0xd2, 0xac, 0x91, 0x88, 0x92, 0x53, 0xd6, 0x93, 0x88, 0x96, 0x04, 0x6b, 0x2c, 0xc8, 0x27, 0xd6, 0x78, 0xd8, 0x90, 0x80, 0x44, 0xd8, 0x91, 0x84,\n\t0x64, 0xa4, 0x48, 0xa2, 0x35, 0x95, 0x2d, 0xfd, 0xc6, 0x7a, 0x4a, 0xbc, 0xd6, 0x7c, 0x8e, 0x7f, 0x19, 0x1e, 0x14, 0xa0, 0x10, 0x64, 0x09, 0x6b, 0x39, 0xae, 0x82, 0xb5, 0xa1, 0xb5, 0x12, 0xd7, 0xc4, 0x6e, 0xbd, 0x0e, 0xd6, 0xbe, 0x56, 0x2f, 0x6e, 0x8a, 0x3d, 0x68, 0x91, 0x44, 0x06, 0x2d, 0x56, 0x3d, 0x83, 0x7e, 0x54, 0x9f, 0x07, 0xfd, 0xa4, 0x1e, 0x0c, 0x5a, 0x2a, 0x25, 0x41, 0xcb, 0x24, 0x2d, 0xe8, 0x20, 0xdb, 0x43, 0x92, 0x1e, 0x14, 0x2e, 0xb6, 0xa0, 0xc3, 0x92, 0x10, 0x14, 0xc1, 0xed, 0x98, 0x17, 0x83, 0x12, 0xc9, 0xa0, 0x33, 0x95, 0x59, 0x82, 0x55, 0x00, 0x02, 0x65, 0xb0, 0xaa, 0x2d, 0xe3, 0x55, 0x6b, 0xc9, 0x52, 0x6d, 0xd0, 0x16, 0xed, 0x24, 0x5e, 0xb5, 0xc7, 0x63, 0xe8, 0x80, 0xc7, 0xf1, 0x04, 0x9e, 0x24, 0x91, 0x3f, 0x85, 0xa7, 0xf1, 0x8c, 0xc4, 0xa9, 0x8e,\n\t0x5c, 0xd7, 0x09, 0x6f, 0xf8, 0x5f, 0x9d, 0xb0, 0xab, 0x37, 0x49, 0xe6, 0x9f, 0x70, 0x79, 0x1c, 0x3e, 0x05, 0xa3, 0xb0, 0x9a, 0x20, 0x67, 0xd4, 0x44, 0x4c, 0xc2, 0x64, 0xc4, 0xca, 0x4f, 0x2a, 0x9e, 0xc7, 0x4d, 0xe1, 0xfe, 0xe9, 0x72, 0x4e, 0x65, 0xc8, 0x69, 0x95, 0x29, 0xe5, 0x2a, 0x5b, 0x9c, 0xea, 0x8c, 0xff, 0xd7, 0x4f, 0x13, 0xd4, 0x05, 0xee, 0x7b, 0x11, 0x97, 0x90, 0x2b, 0x11, 0xbe, 0x5f, 0xa1, 0x54, 0x65, 0xf2, 0x9d, 0xaa, 0x94, 0x85, 0xea, 0x9a, 0x2c, 0x24, 0xed, 0x5f, 0x31, 0xd5, 0x91, 0x9d, 0x24, 0xfc, 0x2b, 0x24, 0xfb, 0x4d, 0x24, 0xfb, 0x4d, 0xa4, 0x79, 0xdf, 0x67, 0x23, 0xe2, 0x49, 0xe9, 0x57, 0x48, 0xe9, 0xbe, 0xef, 0xba, 0x4f, 0x37, 0x31, 0xbb, 0x91, 0xb2, 0xe3, 0xb5, 0x71, 0xea, 0x1e, 0xd2, 0x71, 0x3c, 0xe9, 0x38, 0x92, 0x04, 0x7c, 0x5e, 0x9b, 0x4d,\n\t0xc2, 0x9b, 0xcb, 0x7e, 0xb0, 0x9c, 0x21, 0xf9, 0x46, 0x92, 0x4a, 0xcf, 0x93, 0x70, 0xe2, 0x49, 0x38, 0x4e, 0x33, 0x2b, 0x15, 0x33, 0x2b, 0x15, 0x92, 0x4e, 0x3c, 0x49, 0x27, 0x9e, 0xa4, 0x13, 0x6f, 0x4e, 0x94, 0x85, 0xa4, 0x9a, 0xe5, 0xa4, 0x9a, 0xe5, 0xe6, 0xb3, 0xec, 0x17, 0x71, 0x5d, 0xa5, 0xe4, 0x90, 0x44, 0x72, 0x48, 0x21, 0x9b, 0x48, 0x1d, 0xe7, 0x49, 0x1c, 0xf1, 0x24, 0x0c, 0xdf, 0x77, 0xe8, 0x6f, 0x22, 0x45, 0xc4, 0x93, 0x22, 0xe2, 0x49, 0x11, 0xf1, 0xa4, 0x08, 0x3b, 0xe9, 0xc0, 0x42, 0x02, 0x78, 0x99, 0x04, 0x10, 0x4f, 0x02, 0x88, 0x64, 0xe5, 0x7f, 0x85, 0x95, 0x7f, 0x3c, 0x2b, 0xfe, 0x78, 0x56, 0xf1, 0xf1, 0xac, 0xe2, 0x83, 0x59, 0xc5, 0x07, 0xb3, 0x8a, 0x0f, 0x66, 0x15, 0x1f, 0xcc, 0x2a, 0x3e, 0x98, 0x55, 0x7c, 0x30, 0xab, 0xf8, 0x60, 0x56, 0xf1, 0xc1,\n\t0xac, 0xe2, 0x83, 0x59, 0xc5, 0x07, 0xb3, 0x8a, 0xdf, 0xc1, 0x2a, 0xfe, 0x47, 0x56, 0xf1, 0xc1, 0xac, 0xe2, 0x83, 0x59, 0xc5, 0x07, 0xb3, 0x8a, 0x0f, 0x66, 0x15, 0x1f, 0xcc, 0x2a, 0x3e, 0x98, 0x55, 0x7c, 0x30, 0xab, 0xf8, 0xff, 0x41, 0xdd, 0x9d, 0xc0, 0xc7, 0x59, 0xd6, 0x7b, 0xff, 0xbf, 0x27, 0x4d, 0xda, 0x2c, 0xb2, 0xc9, 0x26, 0x1c, 0x76, 0x04, 0xb1, 0x22, 0x54, 0x05, 0x0a, 0x88, 0xec, 0x16, 0xd9, 0x0a, 0x88, 0xa0, 0xe0, 0x02, 0x08, 0x28, 0x22, 0xb2, 0x56, 0x40, 0x04, 0x05, 0xb1, 0x2c, 0x0a, 0x6d, 0x01, 0x15, 0xaa, 0x82, 0x58, 0x2d, 0x8a, 0x50, 0x05, 0x8f, 0xc8, 0x62, 0x2b, 0x95, 0x96, 0x92, 0x06, 0xda, 0x49, 0x53, 0x92, 0x12, 0x0a, 0x6d, 0xda, 0x69, 0x66, 0xa6, 0x99, 0xb9, 0x67, 0x32, 0xcd, 0x42, 0x33, 0x99, 0x70, 0xff, 0xdf, 0x33, 0x4c, 0x7b, 0x2a, 0x0f, 0x9c,\n\t0xa3, 0xcf, 0x73, 0xb6, 0xff, 0x8b, 0xd7, 0x97, 0x99, 0x24, 0x33, 0x73, 0x2f, 0xd7, 0xef, 0xfa, 0x7d, 0x3e, 0xd7, 0xdd, 0x64, 0x66, 0x1a, 0x8b, 0x9f, 0xc6, 0xe2, 0xa7, 0xb1, 0xf8, 0x69, 0x2c, 0x7e, 0x1a, 0x8b, 0x9f, 0xc6, 0xe2, 0xa7, 0xb1, 0xf8, 0x69, 0x2c, 0x7e, 0x1a, 0x8b, 0x9f, 0xc6, 0xe2, 0xa7, 0xb1, 0xf8, 0x69, 0x2c, 0xfe, 0x65, 0x16, 0xff, 0x32, 0x8b, 0x9f, 0xc6, 0xe2, 0xa7, 0xb1, 0xf8, 0x97, 0x59, 0xfc, 0xcb, 0x2c, 0x7e, 0x1a, 0x8b, 0x9f, 0xc6, 0xe2, 0xa7, 0xb1, 0xf8, 0x69, 0x2c, 0x7e, 0x1a, 0x8b, 0x9f, 0xc6, 0xe2, 0xa7, 0xb1, 0xf8, 0x97, 0x59, 0xfc, 0xcb, 0x2c, 0x7e, 0x1a, 0x8b, 0x9f, 0xc6, 0xe2, 0x5f, 0x66, 0xf1, 0x2f, 0xb3, 0xf8, 0x69, 0x2c, 0xfe, 0x1e, 0x16, 0x7f, 0x0f, 0x8b, 0x9f, 0xc6, 0xe2, 0xcf, 0x60, 0xf1, 0xe5, 0xcf, 0x45, 0xf9, 0xec, 0x98, 0xc9,\n\t0x41, 0x23, 0x23, 0xff, 0x16, 0x03, 0xbf, 0x83, 0x6d, 0x7f, 0xb3, 0xfc, 0x3e, 0x8d, 0x6c, 0xbb, 0xfc, 0x5e, 0x8d, 0xe7, 0xb0, 0xd1, 0xf5, 0x4c, 0xb3, 0x93, 0x69, 0x76, 0x32, 0xcd, 0x4e, 0xa6, 0xd9, 0xc9, 0x34, 0x3b, 0x99, 0x66, 0x27, 0xd3, 0xec, 0x64, 0x9a, 0x9d, 0x4c, 0xb3, 0x93, 0x69, 0x76, 0x32, 0xcd, 0x4e, 0xa6, 0xd9, 0xc9, 0x34, 0x3b, 0xeb, 0x67, 0xca, 0x43, 0xf2, 0x1b, 0xf9, 0xad, 0x3c, 0x2c, 0xbf, 0x93, 0x47, 0xe4, 0x51, 0x99, 0x25, 0xbf, 0x97, 0x3f, 0xc8, 0x63, 0xf2, 0xb8, 0xfc, 0xb1, 0xf2, 0x9b, 0xc6, 0x9d, 0x2c, 0xb3, 0x93, 0x65, 0x76, 0xb2, 0xcc, 0x4e, 0x96, 0xd9, 0xc9, 0x32, 0x3b, 0x59, 0x66, 0x27, 0xcb, 0xec, 0x64, 0x99, 0x2d, 0x2c, 0xb3, 0x85, 0x65, 0xb6, 0xb0, 0xcc, 0x16, 0x96, 0xd9, 0xc2, 0x32, 0x5b, 0x58, 0x66, 0x0b, 0xcb, 0x9c, 0xc7, 0x32, 0xe7,\n\t0xb1, 0xcc, 0x79, 0x2c, 0xb3, 0x6c, 0x98, 0x2d, 0x0c, 0x73, 0x1e, 0xc3, 0x6c, 0x61, 0x98, 0x2d, 0x0c, 0xb3, 0x85, 0x61, 0xb6, 0x30, 0xcc, 0x16, 0x86, 0xd9, 0xc2, 0x30, 0x5b, 0x18, 0x66, 0x0b, 0xc3, 0x6c, 0x61, 0x98, 0x2d, 0x0c, 0xb3, 0x85, 0x61, 0xb6, 0x30, 0xcc, 0x16, 0x86, 0xd9, 0x52, 0xbf, 0x42, 0x56, 0x4a, 0x97, 0xa8, 0x0f, 0x86, 0xd9, 0xc2, 0x30, 0x5b, 0x18, 0x66, 0x0b, 0xc3, 0x6c, 0x61, 0x98, 0x2d, 0x0c, 0xb3, 0x85, 0x61, 0xb6, 0x30, 0xcc, 0x16, 0x86, 0xd9, 0x52, 0x1f, 0x21, 0x5b, 0x20, 0x31, 0xa9, 0x91, 0x51, 0x52, 0x2b, 0x75, 0x15, 0x63, 0x5c, 0xcc, 0x18, 0x17, 0x33, 0xc6, 0xc5, 0x8c, 0x71, 0x31, 0x63, 0x6c, 0x61, 0x8a, 0x8b, 0x99, 0xe2, 0x62, 0xa6, 0xb8, 0xb8, 0x61, 0xbb, 0x60, 0xeb, 0x86, 0x5d, 0x82, 0x2d, 0x58, 0xe2, 0x1e, 0x2c, 0x71, 0x2c, 0x4b, 0xdc,\n\t0x8e, 0x25, 0x6e, 0xce, 0x12, 0xff, 0x85, 0x25, 0x8e, 0x65, 0x88, 0x87, 0x35, 0xec, 0xcb, 0x02, 0x3f, 0x1c, 0x7c, 0x92, 0x19, 0x6e, 0xc3, 0xe4, 0x5a, 0x98, 0x5c, 0x0b, 0x93, 0x6b, 0x61, 0x72, 0x2d, 0x4c, 0xae, 0x85, 0xc9, 0xb5, 0x30, 0xb9, 0x16, 0x26, 0xd7, 0xc2, 0xe4, 0x5a, 0x98, 0x5c, 0x0b, 0x93, 0x6b, 0x61, 0x72, 0x2d, 0x4c, 0xae, 0x85, 0xc9, 0xb5, 0x34, 0x7c, 0x59, 0xce, 0x97, 0x0b, 0xe4, 0x42, 0xf9, 0x8a, 0x7c, 0x55, 0x2e, 0x92, 0xaf, 0xc9, 0xc5, 0xf2, 0x75, 0xb9, 0x44, 0xbe, 0x21, 0x97, 0x8a, 0xde, 0xc1, 0xe4, 0x5a, 0x98, 0x5c, 0x0b, 0x93, 0x6b, 0x61, 0x72, 0x2d, 0x4c, 0xae, 0x85, 0xc9, 0xb5, 0x30, 0xb9, 0x16, 0x26, 0xd7, 0xc2, 0xe4, 0x5a, 0x98, 0x5c, 0x0b, 0x93, 0x6b, 0x61, 0x64, 0xaf, 0x31, 0xb2, 0xd7, 0x18, 0xd9, 0x6b, 0x8c, 0xec, 0xb5, 0xf2, 0x7b, 0x76,\n\t0x32, 0xb2, 0xd7, 0x18, 0xd9, 0x6b, 0x8c, 0xec, 0x35, 0x46, 0xf6, 0x1a, 0x23, 0x2b, 0xbf, 0x8f, 0xe7, 0x71, 0xa8, 0xbd, 0x10, 0xb5, 0x17, 0xa2, 0xf6, 0x42, 0xd4, 0x5e, 0x88, 0xda, 0x0b, 0x51, 0x7b, 0x21, 0x6a, 0x2f, 0x44, 0xed, 0x85, 0xa8, 0xbd, 0x10, 0xb5, 0x17, 0xa2, 0xf6, 0x42, 0xd4, 0x5e, 0x88, 0xda, 0x0b, 0x51, 0x7b, 0x21, 0x6a, 0x2f, 0x44, 0xed, 0x85, 0xa8, 0xbd, 0x10, 0xb5, 0x17, 0xa2, 0xf6, 0x42, 0xd4, 0x5e, 0x88, 0xda, 0x0b, 0x51, 0x7b, 0x21, 0x6a, 0x2f, 0x44, 0xed, 0x85, 0xa8, 0xbd, 0x10, 0xb5, 0x17, 0xa2, 0xf6, 0x72, 0xd4, 0x5e, 0x8e, 0xda, 0xcb, 0x51, 0x7b, 0x39, 0x6a, 0x2f, 0x47, 0xed, 0xe5, 0xa8, 0xbd, 0x1c, 0xb5, 0x97, 0xa3, 0xf6, 0x72, 0x34, 0x3d, 0xa1, 0xf1, 0x46, 0x94, 0xb8, 0xa9, 0xf2, 0xbe, 0x24, 0xff, 0xb5, 0x9f, 0xe6, 0xda, 0x1c, 0xf5, 0xa3,\n\t0x4c, 0x3f, 0x9a, 0xb4, 0xa0, 0x49, 0x0b, 0x9a, 0xb4, 0xa0, 0x49, 0x0b, 0x9a, 0x94, 0x3f, 0x75, 0x72, 0x35, 0x2a, 0xb4, 0xa0, 0xc2, 0xbc, 0xe0, 0xb8, 0xca, 0xfb, 0x9b, 0x36, 0x47, 0x77, 0xeb, 0xce, 0x53, 0x74, 0xe6, 0x94, 0x8e, 0x9c, 0xd7, 0x7d, 0x17, 0xe8, 0xbc, 0xb7, 0xea, 0xb6, 0x7f, 0xd6, 0x51, 0x53, 0xb1, 0xf1, 0xd1, 0x47, 0x63, 0x13, 0xa2, 0x07, 0x62, 0xe7, 0x44, 0xaf, 0xc5, 0xae, 0x8e, 0xd6, 0xc5, 0xae, 0x89, 0xae, 0x8d, 0x5d, 0x1b, 0x65, 0x63, 0xdf, 0x8a, 0x16, 0xc5, 0x7e, 0x18, 0xcd, 0xd1, 0x41, 0xcb, 0xd7, 0x4c, 0x96, 0xea, 0x78, 0x07, 0xe8, 0x78, 0x87, 0xea, 0x5a, 0x53, 0x74, 0xad, 0x1f, 0xeb, 0x34, 0x53, 0x74, 0x9a, 0x65, 0x3a, 0xcd, 0x32, 0x9d, 0x66, 0x8a, 0x4e, 0x33, 0x45, 0xa7, 0x59, 0xa6, 0xd3, 0x2c, 0xd3, 0x69, 0xa6, 0xe8, 0x34, 0x53, 0x74, 0x9a,\n\t0x29, 0x3a, 0xcd, 0x14, 0x9d, 0x66, 0x8a, 0x4e, 0x33, 0x45, 0xa7, 0x99, 0xa2, 0xd3, 0x2c, 0xd3, 0x69, 0x96, 0xe9, 0x34, 0x53, 0x74, 0x9a, 0x29, 0x3a, 0xcd, 0x32, 0x9d, 0x66, 0x99, 0x4e, 0x33, 0x45, 0x57, 0x39, 0xb3, 0xf2, 0x37, 0x19, 0xad, 0xc1, 0x55, 0xba, 0xc9, 0x24, 0x9d, 0x64, 0x82, 0x4e, 0xd2, 0x6e, 0xfd, 0xb9, 0x45, 0xe5, 0x9d, 0xb7, 0x56, 0x44, 0xeb, 0xac, 0x87, 0xf6, 0x52, 0xed, 0x1f, 0x51, 0xed, 0x3b, 0x55, 0x7f, 0x2f, 0xbe, 0xfc, 0x8e, 0x52, 0xef, 0x55, 0xed, 0xef, 0xa9, 0xfe, 0x5e, 0xfc, 0xfe, 0x2a, 0x7e, 0x3f, 0x15, 0xff, 0x5e, 0x15, 0x7f, 0x83, 0x8a, 0x3f, 0x50, 0xe5, 0x66, 0xf8, 0xfe, 0xbe, 0xaa, 0x29, 0x54, 0x39, 0xfb, 0x19, 0xad, 0x4f, 0xfc, 0x97, 0x9e, 0x9d, 0x29, 0xff, 0xbf, 0x3f, 0x3b, 0x57, 0x04, 0xa3, 0x82, 0x03, 0x82, 0x5a, 0xa9, 0x0b, 0xc6,\n\t0x07, 0x5b, 0x07, 0xdb, 0x06, 0xef, 0x8f, 0xee, 0x0f, 0xf6, 0x8a, 0x1e, 0x0d, 0xf6, 0x89, 0x1e, 0x09, 0x3e, 0x18, 0x3d, 0x17, 0x8c, 0x0d, 0xf6, 0x0d, 0x3e, 0xe4, 0xec, 0xed, 0xeb, 0xa7, 0xb7, 0x39, 0x73, 0x3f, 0x08, 0xf6, 0x2c, 0xff, 0xfd, 0x5f, 0xec, 0x13, 0xd1, 0xca, 0xd8, 0x11, 0xa2, 0x83, 0xc4, 0x74, 0x90, 0x9a, 0xa3, 0x2a, 0xef, 0x70, 0x52, 0x7e, 0x57, 0x93, 0xee, 0x9a, 0xb3, 0xa3, 0xbb, 0x6b, 0x3e, 0x1f, 0x6c, 0x5d, 0x73, 0x81, 0x5c, 0x18, 0xf5, 0xd4, 0x5c, 0xe4, 0xeb, 0x4b, 0xdc, 0xbf, 0x25, 0x18, 0x57, 0x73, 0x6b, 0x14, 0x96, 0xff, 0xce, 0xad, 0xee, 0x80, 0xe8, 0x6f, 0x75, 0x07, 0xca, 0xfc, 0x28, 0x1c, 0xf3, 0xa1, 0xe0, 0x80, 0x31, 0xfb, 0xca, 0x87, 0x65, 0x3f, 0xd9, 0x5f, 0xc6, 0xc9, 0x47, 0xe4, 0xa3, 0xf2, 0x31, 0x19, 0x2f, 0x07, 0xcb, 0x21, 0x72, 0xa8,\n\t0x7c, 0x5c, 0x0e, 0x93, 0x4f, 0xc8, 0xe1, 0x72, 0x84, 0x1c, 0x29, 0x47, 0xc9, 0xd1, 0x72, 0x8c, 0x1c, 0x2b, 0x9f, 0x94, 0x09, 0x72, 0x9c, 0x7c, 0x4a, 0xce, 0x93, 0x2f, 0x07, 0xe3, 0xc7, 0x9c, 0x2f, 0x3d, 0xc1, 0xb6, 0x63, 0xb2, 0xc1, 0xb6, 0xf5, 0xa7, 0x46, 0xf7, 0xd7, 0x9f, 0x26, 0x9f, 0x91, 0x33, 0xe5, 0xb3, 0xf2, 0x39, 0x39, 0x4b, 0x2e, 0x8f, 0x1e, 0xa9, 0xbf, 0x42, 0xae, 0x8c, 0x9e, 0xab, 0xbf, 0x4a, 0x26, 0xc9, 0x37, 0xe5, 0x6a, 0xb9, 0x46, 0xae, 0x0b, 0xf6, 0xad, 0xff, 0xb6, 0x5c, 0x1f, 0xdd, 0x5d, 0x7f, 0x83, 0x7c, 0x47, 0xbe, 0x2b, 0x37, 0xcb, 0xf7, 0x65, 0xb2, 0xdc, 0x22, 0xb7, 0xca, 0x5d, 0xc1, 0xd6, 0xf5, 0x77, 0xcb, 0x3d, 0xf2, 0x63, 0xf9, 0x89, 0xdc, 0xab, 0xab, 0xdf, 0x1f, 0xec, 0x66, 0xed, 0x95, 0xb7, 0xf6, 0xca, 0x37, 0xac, 0x0a, 0xf6, 0x6c, 0x58,\n\t0x2d, 0x6f, 0xff, 0x9d, 0xfb, 0x77, 0xf9, 0x5d, 0xfb, 0xa6, 0x63, 0xa3, 0x19, 0xc1, 0xfb, 0x8c, 0xda, 0x3c, 0xa3, 0x36, 0xcf, 0xa8, 0xf5, 0x18, 0xad, 0xd9, 0x46, 0x60, 0xb6, 0xb3, 0x3e, 0xdb, 0x91, 0xcd, 0x73, 0x64, 0xf3, 0x1c, 0xd9, 0x3c, 0x47, 0x36, 0xcf, 0x91, 0xcd, 0x73, 0x64, 0xf3, 0x1c, 0xd9, 0x3c, 0x47, 0xd6, 0xe3, 0xc8, 0x7a, 0xec, 0xf9, 0x6c, 0x7b, 0x3e, 0xdb, 0x9e, 0xcf, 0xb6, 0xe7, 0xb3, 0xed, 0xf9, 0x6c, 0x7b, 0x3e, 0xdb, 0x9e, 0xcf, 0xb6, 0xe7, 0xb3, 0xed, 0xf9, 0xec, 0xe0, 0x76, 0xd6, 0x39, 0x93, 0x75, 0xce, 0x64, 0x9d, 0x97, 0xb3, 0xce, 0x6b, 0x98, 0x66, 0x2f, 0xd3, 0xec, 0x65, 0x9a, 0xbd, 0x4c, 0xb3, 0x97, 0x69, 0xf6, 0x32, 0xcd, 0x5e, 0xa6, 0xb9, 0x8a, 0x69, 0xae, 0x62, 0x9a, 0xab, 0xcc, 0xbc, 0x15, 0x4c, 0xb3, 0x97, 0x69, 0xf6, 0xb2, 0xcb, 0x5e,\n\t0x76, 0xd9, 0xcb, 0x2e, 0x7b, 0xd9, 0xe5, 0xaa, 0x58, 0xf9, 0xfa, 0xfc, 0x55, 0xe2, 0x3e, 0xa3, 0x5b, 0xc5, 0xe6, 0x56, 0x99, 0x5d, 0xbb, 0x31, 0xad, 0x5e, 0xa6, 0xb5, 0x8a, 0x5d, 0xf5, 0xb2, 0xab, 0x99, 0xec, 0x6a, 0x26, 0xbb, 0x9a, 0xc9, 0xae, 0x66, 0xb2, 0xab, 0x99, 0xec, 0x6a, 0x26, 0xbb, 0x9a, 0xc9, 0xae, 0x66, 0xb2, 0xab, 0x99, 0x8c, 0x6a, 0x26, 0xa3, 0x9a, 0xc9, 0xa8, 0x66, 0x32, 0xaa, 0x99, 0x8c, 0x6a, 0x26, 0xa3, 0x9a, 0xc9, 0xa8, 0x66, 0x32, 0xaa, 0x99, 0x8c, 0x6a, 0x26, 0xa3, 0x9a, 0xc9, 0xa8, 0x66, 0x32, 0xaa, 0x99, 0x8c, 0x6a, 0x26, 0xa3, 0x9a, 0xc9, 0xa8, 0x66, 0x32, 0xaa, 0x99, 0x8c, 0x6a, 0x26, 0xa3, 0x9a, 0xc9, 0x7a, 0x66, 0xb2, 0x9e, 0xcb, 0x59, 0xcf, 0xe5, 0x2c, 0xe7, 0x1a, 0x86, 0x73, 0x0d, 0x9b, 0xe8, 0x65, 0x13, 0xbd, 0x6c, 0xa2, 0x97, 0x4d,\n\t0xf4, 0xb2, 0x88, 0x5e, 0x16, 0xb1, 0x8a, 0x45, 0xac, 0x62, 0x11, 0xab, 0x58, 0xc4, 0x2a, 0x06, 0xb1, 0x8a, 0x41, 0xf4, 0x32, 0x88, 0x5e, 0x06, 0xd1, 0xcb, 0x20, 0x7a, 0x19, 0x44, 0x2f, 0x83, 0xe8, 0x65, 0x10, 0xbd, 0x0c, 0xa2, 0x97, 0x39, 0xf4, 0x32, 0x87, 0x5e, 0xe6, 0xd0, 0xcb, 0x1c, 0x7a, 0xcd, 0xe0, 0x5e, 0xe6, 0xd0, 0xcb, 0x1c, 0x7a, 0x99, 0x43, 0x2f, 0x73, 0xe8, 0x65, 0x0e, 0xbd, 0xcc, 0xa1, 0x97, 0x39, 0xf4, 0x32, 0x87, 0x5e, 0xe6, 0xd0, 0xcb, 0x1a, 0x7a, 0x59, 0x43, 0xaf, 0xd9, 0xde, 0x68, 0xb6, 0xef, 0x6c, 0xb6, 0x8f, 0x31, 0xdb, 0xc7, 0x98, 0xdd, 0xff, 0x62, 0x76, 0xef, 0x60, 0x66, 0x5f, 0x64, 0x66, 0xef, 0x81, 0xf4, 0xbd, 0x48, 0xdf, 0x8b, 0xf4, 0xbd, 0x48, 0xdf, 0x8b, 0xf4, 0xbd, 0x48, 0xdf, 0x8b, 0xf4, 0xbd, 0x48, 0xdf, 0x8b, 0xee, 0xbd, 0xe8, 0xde,\n\t0x8b, 0xee, 0xbd, 0xba, 0x40, 0x2f, 0xba, 0xf7, 0xa2, 0x7b, 0x2f, 0xba, 0xf7, 0xa2, 0x7b, 0x2f, 0xba, 0xf7, 0xa2, 0x7b, 0x2f, 0xba, 0xf7, 0xa2, 0x7b, 0x2f, 0xba, 0xf7, 0xa2, 0x7b, 0x2f, 0xba, 0xf7, 0xa2, 0x7b, 0x2f, 0x72, 0xf7, 0x22, 0x77, 0x2f, 0x72, 0xf7, 0xea, 0x20, 0x5b, 0x21, 0x52, 0x2f, 0x22, 0xf5, 0x22, 0x52, 0x2f, 0x22, 0xf5, 0x22, 0x52, 0x2f, 0x12, 0xad, 0x0a, 0xea, 0xaa, 0xbd, 0xf3, 0x3b, 0xfa, 0x66, 0x9b, 0xbe, 0x39, 0x4f, 0xcf, 0x4c, 0xfb, 0xee, 0xf1, 0xd1, 0x33, 0xd5, 0x4f, 0x1a, 0x7f, 0x2e, 0xc6, 0x48, 0x62, 0xd7, 0x45, 0x7d, 0xc1, 0x28, 0xdf, 0x2d, 0x7f, 0x1e, 0xd8, 0x2b, 0xbe, 0x93, 0xab, 0x7c, 0xf5, 0x57, 0x5f, 0xf5, 0xf8, 0x2a, 0x53, 0xf9, 0x6a, 0xc3, 0xe7, 0x5d, 0xe6, 0x83, 0x2d, 0x7c, 0xf5, 0x9b, 0xd8, 0x09, 0x51, 0x3e, 0x76, 0x92, 0x9c, 0xe2,\n\t0xbb, 0xa7, 0x55, 0x3e, 0xc1, 0xae, 0xcd, 0x4f, 0xdb, 0xf5, 0x9f, 0x36, 0xfd, 0xa7, 0x2d, 0xf6, 0x15, 0x5d, 0x7c, 0x92, 0x8e, 0x6d, 0x5f, 0xab, 0x9f, 0x25, 0x55, 0x68, 0x7c, 0xdd, 0xb3, 0x6b, 0x3d, 0x7b, 0x6d, 0xf5, 0x53, 0xf9, 0x0a, 0x1e, 0x91, 0x0b, 0x46, 0xfb, 0x4e, 0x7e, 0xe3, 0xa7, 0x69, 0x7e, 0xd1, 0xe3, 0xbf, 0x24, 0x5f, 0xf1, 0xd8, 0x06, 0x1c, 0xf8, 0x6d, 0xec, 0xd0, 0xe8, 0xd1, 0xd8, 0xc7, 0x65, 0x42, 0xf4, 0x84, 0x2d, 0xf5, 0x55, 0x3f, 0x2b, 0xaf, 0xfc, 0xaf, 0x84, 0xcf, 0x38, 0xae, 0xbe, 0xa0, 0xa6, 0xfa, 0x79, 0x6e, 0xcb, 0x2b, 0x8f, 0x7f, 0xdd, 0xe3, 0xbb, 0x3d, 0xbe, 0xdb, 0xe3, 0xcb, 0x9f, 0xf6, 0xf6, 0x62, 0xf5, 0x48, 0xe7, 0x7b, 0xc4, 0x8b, 0x9e, 0x93, 0x0f, 0xea, 0x3d, 0x2a, 0xf4, 0xa8, 0x5e, 0x8f, 0xea, 0xf5, 0xa8, 0xb5, 0x1e, 0xd1, 0xeb, 0x11,\n\t0x4b, 0xca, 0x9f, 0x09, 0x17, 0xbb, 0xd3, 0x2b, 0xc6, 0x9c, 0xab, 0x7c, 0xe5, 0x75, 0x2b, 0x9f, 0x01, 0x19, 0x34, 0x55, 0x3f, 0xe3, 0x6b, 0xc3, 0x5e, 0xf6, 0xd9, 0xcb, 0xac, 0xbd, 0xcc, 0xda, 0xcb, 0x6c, 0x4c, 0x17, 0x8e, 0xdd, 0xee, 0x58, 0xee, 0xf4, 0xb3, 0x29, 0x95, 0x67, 0xdf, 0xe6, 0xff, 0x8d, 0xb6, 0x72, 0x89, 0xad, 0x5c, 0x6a, 0x2b, 0x97, 0xda, 0xca, 0x0d, 0xce, 0xd8, 0x02, 0x67, 0x6c, 0x81, 0x33, 0xd6, 0xec, 0xf5, 0xff, 0x50, 0x5b, 0x7e, 0xff, 0xb4, 0xd7, 0x71, 0xaf, 0xbc, 0x3f, 0x3f, 0xf4, 0xc8, 0xa9, 0x1e, 0x59, 0xfe, 0x34, 0xbd, 0xdf, 0x6c, 0x18, 0x05, 0x8f, 0x2a, 0xff, 0xed, 0x67, 0x5f, 0x30, 0x3a, 0xa8, 0x71, 0x66, 0xc6, 0x47, 0xf7, 0xc5, 0x0e, 0x8e, 0xd2, 0xb1, 0x43, 0x64, 0x42, 0xf4, 0x3b, 0x6c, 0x4c, 0x62, 0x40, 0x8d, 0x33, 0x73, 0x50, 0xe5, 0xc8,\n\t0x2f, 0xf4, 0xd3, 0x47, 0xfc, 0xf4, 0x21, 0x3f, 0xbd, 0x2a, 0x76, 0x7c, 0xb0, 0x4d, 0xec, 0xb4, 0x60, 0xeb, 0xd8, 0xe9, 0xc1, 0xf6, 0xb1, 0x33, 0xdc, 0x3f, 0xd3, 0x1e, 0x9d, 0x13, 0xcd, 0x89, 0x9d, 0x17, 0xbd, 0x10, 0x3b, 0x5f, 0x2e, 0x08, 0xc6, 0xd5, 0xde, 0x15, 0x6c, 0x5e, 0x7b, 0x8f, 0xfc, 0x38, 0x78, 0x4f, 0xe3, 0x8a, 0x68, 0x6e, 0xd0, 0xe0, 0xd5, 0x5e, 0x08, 0xee, 0x0c, 0x36, 0x0f, 0xa6, 0x78, 0xc6, 0x78, 0xa3, 0x39, 0xa1, 0x32, 0xee, 0xe5, 0xb3, 0x50, 0xa8, 0x3b, 0x20, 0x68, 0xac, 0x3b, 0x30, 0x68, 0xf4, 0x5f, 0x4d, 0x34, 0xdf, 0xa3, 0xde, 0xeb, 0x51, 0xef, 0xf3, 0xa8, 0x36, 0x8f, 0xfa, 0x6b, 0x75, 0x44, 0xd7, 0xd9, 0x4e, 0xbd, 0x47, 0x6e, 0xe6, 0x91, 0x9b, 0xc5, 0x86, 0x75, 0xa9, 0x01, 0x5d, 0x6a, 0xa0, 0xf2, 0x5b, 0x05, 0xef, 0x8f, 0x0a, 0x7a, 0x62, 0x41,\n\t0x4f, 0xcc, 0x21, 0xd9, 0xba, 0x60, 0x6c, 0xb4, 0x56, 0x6f, 0x6c, 0xb7, 0x5e, 0xce, 0x58, 0x2f, 0x67, 0xac, 0x97, 0x33, 0xc1, 0x38, 0xdd, 0xe8, 0x23, 0x6e, 0x3f, 0x2a, 0xe5, 0xcf, 0xed, 0x3b, 0x40, 0x0e, 0x94, 0x83, 0x64, 0xbc, 0x1c, 0x2c, 0x87, 0xc8, 0xc7, 0xe5, 0x30, 0xf9, 0x84, 0xc7, 0x1f, 0x2e, 0x47, 0xc8, 0x91, 0x72, 0x94, 0x1c, 0x2d, 0xc7, 0xc8, 0xb1, 0xf2, 0x49, 0x99, 0x20, 0xc7, 0xc9, 0xa7, 0xe4, 0x78, 0x39, 0x41, 0x4e, 0x94, 0x93, 0xe4, 0x64, 0x99, 0x28, 0xa7, 0xc8, 0xa9, 0xa2, 0x12, 0x82, 0x4f, 0xcb, 0xe9, 0x62, 0x16, 0x07, 0x66, 0x71, 0x60, 0x16, 0x07, 0x66, 0x71, 0x60, 0x16, 0x07, 0x66, 0x71, 0x60, 0x16, 0x07, 0x66, 0x71, 0xf0, 0x05, 0xf9, 0x62, 0x94, 0xb0, 0x5e, 0xcf, 0x04, 0x66, 0x74, 0x60, 0x46, 0x07, 0x66, 0x74, 0x60, 0x46, 0x07, 0x66, 0x74, 0x60,\n\t0x46, 0x07, 0x66, 0x73, 0x60, 0x36, 0x07, 0x66, 0x73, 0xf0, 0x35, 0x35, 0x65, 0x36, 0x07, 0x66, 0x73, 0x70, 0x89, 0xfb, 0xdf, 0x90, 0x4b, 0xe5, 0x32, 0xcf, 0xbf, 0x5c, 0xae, 0x90, 0x2b, 0x7d, 0x7d, 0x55, 0xa5, 0x23, 0x67, 0x82, 0x6f, 0xba, 0x7f, 0x35, 0x3f, 0xba, 0x46, 0xae, 0x95, 0x6f, 0x89, 0x19, 0x1f, 0x7c, 0x5b, 0xae, 0x77, 0xfe, 0x6e, 0x90, 0xef, 0xc8, 0x77, 0xe5, 0x46, 0xb9, 0x49, 0xbe, 0x27, 0x37, 0xcb, 0xf7, 0x65, 0xb2, 0xdc, 0xe2, 0x35, 0x6e, 0x95, 0xdb, 0xa2, 0xe1, 0xe0, 0x07, 0xce, 0xf7, 0x0f, 0xdd, 0xde, 0x51, 0xf9, 0x34, 0xea, 0xf2, 0x67, 0xf0, 0xbd, 0x5a, 0x99, 0x83, 0x69, 0x5f, 0xaf, 0x8d, 0xf2, 0x18, 0xd5, 0x8e, 0x51, 0xed, 0x35, 0xa8, 0x50, 0x73, 0x45, 0x85, 0x06, 0x19, 0x34, 0xc8, 0xd4, 0x5c, 0xeb, 0x67, 0xba, 0x4d, 0xcd, 0xf5, 0x6e, 0x6d, 0xaf,\n\t0xc6, 0xf6, 0x6a, 0x6e, 0xf2, 0xfd, 0x5b, 0xa2, 0x04, 0x52, 0x64, 0x6a, 0x7e, 0x20, 0xd3, 0xa2, 0x14, 0x62, 0x64, 0x98, 0xc4, 0x70, 0xcd, 0x74, 0x8f, 0xfd, 0xa9, 0xfc, 0xcc, 0xd7, 0x0f, 0xba, 0xfd, 0xa5, 0xcc, 0x90, 0x5f, 0xc9, 0xaf, 0x65, 0xa6, 0x3c, 0x24, 0xbf, 0x91, 0xdf, 0xca, 0xc3, 0xf2, 0x3b, 0xaf, 0xf9, 0x88, 0x6a, 0x77, 0x2e, 0x6b, 0x27, 0x45, 0xbd, 0xb5, 0x77, 0x45, 0x7d, 0xb5, 0xf7, 0x44, 0xcb, 0x6a, 0x7f, 0x1c, 0xad, 0xa8, 0xdb, 0x06, 0x81, 0x9e, 0x15, 0xdd, 0xbf, 0x4e, 0xd7, 0xaf, 0x5b, 0x24, 0x8b, 0x45, 0x97, 0xaf, 0xd3, 0xe5, 0xeb, 0x74, 0x79, 0x94, 0xca, 0xa0, 0x54, 0xa6, 0x2e, 0x1b, 0xe5, 0x47, 0xef, 0x29, 0xef, 0x8f, 0x7a, 0x47, 0xef, 0x1d, 0xad, 0x43, 0xad, 0x0c, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6,\n\t0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x00, 0x6a, 0x0d, 0xa0, 0xd6, 0x40, 0xe5, 0x5f, 0xc0, 0xb2, 0x51, 0x1f, 0xd6, 0x17, 0xb0, 0xbe, 0x80, 0xf5, 0x05, 0xac, 0x2f, 0x60, 0x7d, 0x01, 0xeb, 0x0b, 0x58, 0x5f, 0xc0, 0xfa, 0x1c, 0xd6, 0xe7, 0x58, 0xcc, 0x3a, 0x16, 0xb3, 0x8e, 0xc5, 0xac, 0x63, 0x31, 0xeb, 0x58, 0xcc, 0x3a, 0x16, 0xb3, 0xae, 0xfe, 0xba, 0x68, 0x6d, 0xfd, 0xb7, 0xe5, 0xfa, 0xa8, 0x9d, 0x0b, 0xb4, 0x73, 0x81, 0x76, 0x2e, 0xd0, 0xce, 0x05, 0xda, 0xb9, 0x40, 0x3b, 0x17, 0x68, 0xe7, 0x02, 0xed, 0x5c,\n\t0xa0, 0xdd, 0x7a, 0x3f, 0x63, 0xbd, 0x9f, 0xb1, 0xde, 0xcf, 0x58, 0xef, 0x67, 0xac, 0xf7, 0x33, 0xd6, 0xfb, 0x19, 0xeb, 0xfd, 0x8c, 0xf5, 0x7e, 0xc6, 0x7a, 0x3f, 0x63, 0xad, 0x9f, 0xb1, 0xd6, 0xcf, 0x58, 0xeb, 0x67, 0xac, 0xf5, 0x33, 0xd6, 0xfa, 0x19, 0x6b, 0xfd, 0x8c, 0xb5, 0x7e, 0xc6, 0x5a, 0x3f, 0x63, 0xad, 0x9f, 0xb1, 0xd6, 0xcf, 0x58, 0xeb, 0x67, 0xac, 0xf5, 0x33, 0xd6, 0xfa, 0x19, 0x6b, 0xfd, 0x8c, 0xb5, 0x7e, 0xc6, 0x5a, 0x3f, 0x63, 0xad, 0x9f, 0xb1, 0xc6, 0xcf, 0xf0, 0xdd, 0x8c, 0x35, 0x7e, 0xc6, 0x1a, 0x3f, 0x63, 0x8d, 0x9f, 0xa9, 0x9f, 0x8d, 0x88, 0x73, 0xe4, 0xaf, 0x32, 0xd7, 0xd7, 0x7f, 0x93, 0xe7, 0x64, 0x9e, 0xbc, 0x20, 0xcd, 0xb2, 0x50, 0x5a, 0xe4, 0x45, 0x59, 0x2c, 0x71, 0x69, 0x95, 0x25, 0xd2, 0x26, 0x4b, 0xe5, 0x65, 0x69, 0x97, 0x0e, 0x79, 0x55,\n\t0x96, 0xcb, 0x6b, 0xf2, 0xba, 0xac, 0x90, 0x95, 0xd2, 0x25, 0xc6, 0x19, 0x9d, 0x33, 0xe8, 0x9c, 0x41, 0xe7, 0x0c, 0x3a, 0x67, 0xd0, 0x39, 0x83, 0xce, 0x19, 0x74, 0xce, 0xa0, 0x73, 0xa6, 0x3e, 0x6b, 0x5f, 0x72, 0x92, 0x97, 0x5e, 0x29, 0xc8, 0x3a, 0xe9, 0x13, 0xa4, 0xac, 0x47, 0xca, 0x7a, 0xa4, 0xac, 0x47, 0xca, 0x7a, 0xa4, 0xac, 0x67, 0x36, 0xf5, 0x45, 0x19, 0x96, 0x92, 0x8c, 0xc8, 0x9b, 0x12, 0x45, 0x89, 0x86, 0x40, 0x62, 0x52, 0x23, 0xa3, 0xa4, 0x56, 0xea, 0x64, 0x34, 0x77, 0x1f, 0x23, 0xf5, 0xd2, 0x20, 0x9b, 0xc9, 0xe6, 0xb2, 0x85, 0x6c, 0x89, 0xca, 0x5b, 0xc9, 0x7b, 0x65, 0x6b, 0x51, 0xbf, 0x0d, 0xdb, 0xca, 0xf6, 0xb2, 0x83, 0xec, 0x58, 0x36, 0x08, 0xd9, 0x59, 0x76, 0x91, 0x5d, 0x65, 0x37, 0xd9, 0x5d, 0xf6, 0x90, 0xbd, 0x64, 0x6f, 0xd9, 0x47, 0xf6, 0x95, 0x0f,\n\t0xcb, 0xfe, 0xc2, 0xf0, 0x1a, 0xd8, 0x5d, 0x03, 0xbb, 0x6b, 0x60, 0x77, 0x0d, 0xec, 0xae, 0x61, 0xbc, 0x20, 0x59, 0x03, 0x92, 0x35, 0xb0, 0xba, 0x06, 0xfd, 0xb0, 0x41, 0x3f, 0x6c, 0xd0, 0x0f, 0x1b, 0xf4, 0xc3, 0x06, 0xfd, 0xb0, 0x41, 0x3f, 0x6c, 0x38, 0x96, 0xc9, 0x7e, 0x52, 0x26, 0x08, 0xda, 0x36, 0xa0, 0x77, 0xc3, 0x89, 0x82, 0xe0, 0x0d, 0x27, 0xcb, 0x44, 0x39, 0x45, 0x4e, 0x15, 0x9c, 0x6b, 0xd0, 0xcd, 0x59, 0x4c, 0x86, 0xc5, 0x64, 0x58, 0x4c, 0x86, 0xc5, 0x64, 0x58, 0x4c, 0x86, 0xc5, 0x64, 0x58, 0x4c, 0x86, 0xc5, 0x64, 0x58, 0x4c, 0x86, 0xc5, 0x64, 0x58, 0x4c, 0xa6, 0xb2, 0x96, 0x39, 0x5f, 0x2e, 0x90, 0x0b, 0xe5, 0x2b, 0xf2, 0x55, 0xb9, 0x48, 0xbe, 0x26, 0x17, 0xcb, 0xd7, 0xe5, 0x12, 0xf9, 0x86, 0x5c, 0x2a, 0xd7, 0xca, 0xb7, 0xe4, 0x3a, 0xd1, 0x5b, 0x1a, 0x6e,\n\t0x90, 0x9b, 0xe4, 0x7b, 0x72, 0xb3, 0x7c, 0x5f, 0x26, 0x8b, 0x1e, 0xd6, 0xa0, 0x87, 0x35, 0xdc, 0x2e, 0x3f, 0x90, 0x1f, 0x46, 0xa9, 0x86, 0x3b, 0xe4, 0x4e, 0x99, 0x22, 0x7a, 0x4f, 0xc3, 0x5d, 0x72, 0xb7, 0xdc, 0x23, 0x3f, 0x92, 0x7b, 0xad, 0xc9, 0xee, 0x93, 0xe9, 0xf2, 0x53, 0xf9, 0x99, 0xfc, 0x5c, 0xee, 0x97, 0x07, 0xe4, 0x17, 0xf2, 0xa0, 0xfc, 0x52, 0x66, 0xc8, 0xaf, 0xe4, 0xd7, 0x32, 0x53, 0x1e, 0x92, 0xdf, 0xc8, 0x6f, 0xe5, 0x61, 0xd1, 0x9b, 0x1a, 0xf4, 0xa6, 0x86, 0x47, 0x65, 0x96, 0xfc, 0x5e, 0xfe, 0x20, 0x8f, 0xc9, 0xe3, 0xf2, 0x47, 0xf9, 0x57, 0xf9, 0x93, 0x3c, 0x21, 0x7f, 0x96, 0x27, 0xe5, 0x29, 0x79, 0x5a, 0x9e, 0x91, 0xbf, 0xc8, 0x6c, 0x99, 0x23, 0x7f, 0x75, 0x0c, 0xcf, 0xca, 0x5c, 0xf9, 0x9b, 0x3c, 0x27, 0xf3, 0x64, 0xbe, 0x3c, 0x2f, 0x2f, 0x48, 0xb3,\n\t0x2c, 0x94, 0x16, 0x79, 0x51, 0x5e, 0x92, 0x45, 0xb2, 0x58, 0xe2, 0xd2, 0x2a, 0x4b, 0xa4, 0x4d, 0x5e, 0x96, 0x76, 0xe9, 0x88, 0x86, 0xad, 0x58, 0x86, 0x1b, 0x56, 0x45, 0x6b, 0x1b, 0x56, 0xcb, 0x1a, 0xf7, 0xbb, 0x25, 0x29, 0x29, 0xe9, 0x91, 0x8c, 0x64, 0x25, 0x94, 0x9c, 0xe4, 0xa5, 0xcf, 0xf9, 0xef, 0x97, 0x01, 0x19, 0x94, 0x37, 0x64, 0x7d, 0x94, 0xa9, 0xbc, 0x87, 0xaa, 0xef, 0x33, 0xcb, 0x0c, 0xb3, 0xcc, 0x30, 0xcb, 0x4c, 0x63, 0xf9, 0xfb, 0x43, 0xbe, 0x5f, 0x94, 0x61, 0x29, 0xc9, 0x48, 0x94, 0x67, 0x9b, 0x99, 0x58, 0x07, 0xc2, 0x87, 0x08, 0x1f, 0x56, 0x56, 0x3d, 0x1f, 0x74, 0xfb, 0xa1, 0x68, 0x11, 0xba, 0x87, 0xe8, 0x1e, 0xa2, 0x7b, 0x88, 0xee, 0x45, 0x74, 0x4f, 0xa3, 0x7b, 0x1a, 0xdd, 0xd3, 0xe8, 0x9e, 0x46, 0xf7, 0x34, 0xba, 0xa7, 0xd1, 0x7d, 0x2d, 0xba, 0xaf,\n\t0x45, 0xf7, 0xb5, 0xe8, 0x9e, 0x46, 0xf7, 0xf4, 0xff, 0x82, 0x4f, 0xe0, 0xe8, 0x46, 0xf7, 0x34, 0xba, 0x17, 0xd1, 0xbd, 0x88, 0xee, 0x45, 0x74, 0x2f, 0xa2, 0x7b, 0x11, 0xdd, 0x8b, 0xe8, 0x5e, 0x44, 0xf7, 0x22, 0xba, 0x17, 0xd1, 0xbd, 0x88, 0xee, 0x45, 0x74, 0x2f, 0xa2, 0x7b, 0x11, 0xdd, 0x8b, 0xe8, 0x5e, 0x44, 0xf7, 0x34, 0xba, 0xa7, 0xd1, 0x3d, 0x8d, 0xee, 0x45, 0x74, 0x2f, 0xa2, 0xfb, 0x5a, 0x74, 0x2f, 0xa2, 0x7b, 0x16, 0xdd, 0xb3, 0xe8, 0x9e, 0x45, 0xf7, 0x2c, 0xba, 0x17, 0xab, 0x9f, 0xda, 0x91, 0x41, 0xf7, 0x0c, 0xba, 0x67, 0xd0, 0x3d, 0x83, 0xee, 0x19, 0x74, 0xcf, 0xa0, 0x7b, 0x06, 0xdd, 0x33, 0xe8, 0x9e, 0x41, 0xf7, 0x0c, 0xba, 0x17, 0xd0, 0xbd, 0x80, 0xee, 0xbd, 0xc1, 0xed, 0x9e, 0x5b, 0xb6, 0xd6, 0x3b, 0x2a, 0x44, 0x4f, 0x23, 0x7a, 0x01, 0xd1, 0x17, 0x21,\n\t0xfa, 0x22, 0x44, 0x2f, 0x22, 0x7a, 0x11, 0xd1, 0xd3, 0x88, 0xbe, 0x16, 0xd1, 0x8b, 0x88, 0x5e, 0x44, 0xf4, 0x22, 0xa2, 0x67, 0x10, 0x3d, 0x83, 0xe8, 0x05, 0x44, 0xef, 0x46, 0xf4, 0xb5, 0x88, 0x5e, 0x40, 0xf4, 0x2c, 0xa2, 0x97, 0xdf, 0xed, 0x34, 0x8f, 0xe8, 0x45, 0x44, 0x2f, 0x22, 0x7a, 0xe1, 0x9f, 0xf8, 0xf4, 0x89, 0x0c, 0xa2, 0x67, 0x10, 0x3d, 0x8d, 0xe8, 0x45, 0x14, 0x2f, 0xfe, 0xdb, 0x27, 0x2a, 0xb8, 0xff, 0x4e, 0x9f, 0xa8, 0xb0, 0x2a, 0x4a, 0xa3, 0xf8, 0x5a, 0x14, 0x2f, 0xa0, 0x78, 0x11, 0xc5, 0x8b, 0x28, 0x9e, 0x41, 0xf1, 0x34, 0x9a, 0x86, 0x68, 0x1a, 0xa2, 0x69, 0x88, 0xa6, 0x21, 0x9a, 0x86, 0x68, 0x1a, 0xa2, 0x69, 0xb8, 0x71, 0xe5, 0x7c, 0xa5, 0xfb, 0x57, 0xc9, 0x24, 0xf9, 0xa6, 0x5c, 0x2d, 0xd7, 0xc8, 0xf5, 0xd1, 0x22, 0x14, 0x5d, 0x84, 0xa2, 0x8b, 0x50,\n\t0x74, 0x11, 0x8a, 0x2e, 0x42, 0xd1, 0x45, 0x28, 0xba, 0x08, 0x45, 0x17, 0xa1, 0xe8, 0x22, 0x14, 0x0d, 0x51, 0x34, 0x44, 0xd1, 0x10, 0x45, 0x43, 0x14, 0x0d, 0x51, 0x34, 0x44, 0xd1, 0x10, 0x45, 0x43, 0x14, 0x0d, 0x51, 0x34, 0x44, 0xd1, 0x10, 0x45, 0x43, 0x14, 0x0d, 0x51, 0x34, 0x44, 0xd1, 0x10, 0x45, 0x43, 0x14, 0x0d, 0x51, 0x34, 0x44, 0xd1, 0x10, 0x45, 0x43, 0x14, 0x0d, 0x51, 0x34, 0x44, 0xd1, 0x10, 0x45, 0x43, 0x14, 0x0d, 0x51, 0x34, 0x44, 0xd1, 0x10, 0x45, 0x43, 0x14, 0x0d, 0x51, 0x34, 0x44, 0xd1, 0x10, 0x45, 0x8b, 0x28, 0x5a, 0x44, 0xd1, 0x22, 0x8a, 0xa6, 0x51, 0x34, 0x8d, 0xa2, 0x69, 0x14, 0x4d, 0xa3, 0x68, 0x1a, 0x45, 0xd7, 0xa2, 0xe8, 0x5a, 0x14, 0x5d, 0x8b, 0xa2, 0x6b, 0x51, 0x74, 0x2d, 0x8a, 0xa6, 0x51, 0x34, 0x8d, 0xa2, 0x69, 0x14, 0x4d, 0xa3, 0x68, 0x1a,\n\t0x45, 0xd3, 0x28, 0x9a, 0x46, 0xd1, 0x34, 0x8a, 0xa6, 0x51, 0x34, 0x8d, 0xa2, 0x69, 0x14, 0x4d, 0xa3, 0x68, 0x1a, 0x45, 0xd3, 0x28, 0x9a, 0x46, 0xd1, 0x34, 0x8a, 0xa6, 0x51, 0x34, 0x8d, 0xa2, 0x69, 0x14, 0x4d, 0xa3, 0x68, 0x1a, 0x45, 0xd3, 0x28, 0x9a, 0x46, 0xd1, 0xf4, 0x7f, 0xe2, 0xbb, 0xd7, 0x77, 0xa3, 0x68, 0x37, 0x8a, 0x76, 0xa3, 0x68, 0x37, 0x8a, 0x76, 0xa3, 0x68, 0x37, 0x8a, 0x76, 0xa3, 0x68, 0x1a, 0x45, 0xd3, 0x28, 0x9a, 0x46, 0xd1, 0x34, 0x8a, 0xa6, 0x51, 0x34, 0x8d, 0xa2, 0x69, 0x14, 0x2d, 0xa2, 0x68, 0x11, 0x45, 0x8b, 0x28, 0x5a, 0x44, 0xd1, 0x22, 0x8a, 0x16, 0x51, 0xb4, 0x88, 0xa2, 0x45, 0x14, 0x2d, 0xa2, 0x68, 0x11, 0x45, 0x8b, 0x28, 0x5a, 0x44, 0xd1, 0x22, 0x8a, 0x16, 0x51, 0xb4, 0x88, 0xa2, 0x45, 0x14, 0x2d, 0xa2, 0x68, 0x11, 0x45, 0x8b, 0x28, 0x5a,\n\t0x44, 0xd1, 0x22, 0x8a, 0x16, 0x51, 0xb4, 0x88, 0xa2, 0x45, 0x14, 0x2d, 0xa2, 0x68, 0x11, 0x45, 0x8b, 0x28, 0x5a, 0x44, 0xd1, 0x22, 0x8a, 0x16, 0x51, 0xb4, 0x88, 0xa2, 0x45, 0x14, 0x2d, 0xa2, 0x68, 0x11, 0x45, 0x8b, 0x28, 0x5a, 0x44, 0xd1, 0x22, 0x8a, 0x16, 0x51, 0xb4, 0x88, 0xa2, 0x45, 0x14, 0x2d, 0xa2, 0x68, 0x11, 0x45, 0x8b, 0x28, 0x5a, 0x44, 0xd1, 0x22, 0x8a, 0x16, 0x51, 0xb4, 0x88, 0xa2, 0x45, 0x14, 0x2d, 0xa2, 0x68, 0x11, 0x45, 0xd3, 0x28, 0x9a, 0x46, 0xd1, 0x34, 0x8a, 0xa6, 0x51, 0x34, 0x8d, 0xa2, 0x69, 0x14, 0x4d, 0xa3, 0x68, 0x1a, 0x45, 0xd3, 0x28, 0x9a, 0x46, 0xd1, 0x34, 0x8a, 0xa6, 0x51, 0x34, 0x8d, 0xa2, 0x69, 0x14, 0x4d, 0xa3, 0x68, 0x1a, 0x45, 0xd3, 0x28, 0x9a, 0x46, 0xd1, 0x34, 0x8a, 0xa6, 0x51, 0x34, 0x8d, 0xa2, 0x69, 0x14, 0x4d, 0xa3, 0x68, 0x1a,\n\t0x45, 0xd3, 0x28, 0x9a, 0x46, 0xd1, 0x34, 0x8a, 0x16, 0x51, 0xb4, 0x88, 0xa2, 0x45, 0x14, 0x2d, 0xa2, 0x68, 0x11, 0x45, 0x8b, 0x28, 0x5a, 0x44, 0xd1, 0x22, 0x8a, 0x16, 0x51, 0xb4, 0x88, 0xa2, 0x45, 0x14, 0xcd, 0xa2, 0x68, 0x16, 0x45, 0xb3, 0x28, 0x9a, 0x45, 0xd1, 0x2c, 0x8a, 0x66, 0x51, 0x34, 0x8b, 0xa2, 0x59, 0x14, 0xcd, 0xa2, 0x68, 0x06, 0x45, 0x33, 0x28, 0x9a, 0x41, 0xd1, 0x0c, 0x8a, 0x66, 0x50, 0x34, 0x83, 0xa2, 0x19, 0x14, 0xcd, 0xa0, 0x68, 0x06, 0x45, 0x33, 0x28, 0x9a, 0x41, 0xd1, 0x0c, 0x8a, 0x66, 0x50, 0x34, 0x83, 0xa2, 0x19, 0x14, 0xcd, 0xa0, 0x68, 0x06, 0x45, 0x33, 0x28, 0x9a, 0x41, 0xd1, 0x0c, 0x8a, 0x66, 0x50, 0x34, 0x83, 0xa2, 0x19, 0x14, 0xcd, 0xa0, 0x68, 0x06, 0x45, 0x33, 0x28, 0x9a, 0x41, 0xd1, 0x0c, 0x8a, 0x66, 0x50, 0x34, 0x83, 0xa2, 0x19, 0x14,\n\t0xcd, 0xa0, 0x68, 0x06, 0x45, 0x33, 0x28, 0x9a, 0x41, 0xd1, 0x0c, 0x8a, 0x66, 0x50, 0x34, 0x83, 0xa2, 0x19, 0x14, 0x2d, 0xa0, 0x68, 0x01, 0x45, 0x0b, 0x28, 0x5a, 0x40, 0xd1, 0x02, 0x8a, 0x16, 0x50, 0xb4, 0x80, 0xa2, 0x05, 0x14, 0x2d, 0xa0, 0x68, 0x01, 0x45, 0x0b, 0x28, 0x5a, 0x40, 0xd1, 0x02, 0x8a, 0x16, 0x50, 0xb4, 0x80, 0xa2, 0x05, 0x14, 0x2d, 0xa0, 0x68, 0x01, 0x45, 0x0b, 0x28, 0x5a, 0x40, 0xd1, 0x02, 0x8a, 0x16, 0x50, 0xb4, 0x17, 0x45, 0x7b, 0x1b, 0x3a, 0x9d, 0xa3, 0x57, 0x65, 0xb9, 0xbc, 0x26, 0xaf, 0xcb, 0x0a, 0x59, 0x29, 0x6b, 0xd0, 0xb6, 0x5b, 0x92, 0x92, 0x92, 0x1e, 0xc9, 0x88, 0xd5, 0x07, 0xb2, 0xe6, 0x91, 0x35, 0x8f, 0xac, 0x79, 0x64, 0x2d, 0x20, 0x6b, 0x01, 0x59, 0x0b, 0xc8, 0x5a, 0x40, 0xd6, 0x02, 0xb2, 0x16, 0x90, 0xb5, 0x88, 0xac, 0x69, 0x64, 0x4d,\n\t0x23, 0x6b, 0x1a, 0x59, 0xd3, 0xc8, 0x9a, 0x46, 0xd6, 0x02, 0xb2, 0x16, 0x90, 0xb5, 0x80, 0xac, 0x05, 0x64, 0x2d, 0x20, 0xeb, 0xda, 0x9a, 0x46, 0xeb, 0xe8, 0xa4, 0x75, 0xb4, 0xf5, 0x7e, 0xf4, 0x2a, 0xca, 0xf6, 0xa3, 0x6c, 0x3f, 0xca, 0x66, 0xab, 0xeb, 0xe8, 0x04, 0xd2, 0x2e, 0x0d, 0x54, 0x39, 0xda, 0xae, 0x45, 0xdb, 0xb5, 0x68, 0xbb, 0x16, 0x6d, 0xf3, 0x68, 0x1b, 0xa2, 0x6d, 0x18, 0x94, 0x3f, 0x63, 0xfd, 0x00, 0x39, 0x50, 0x0e, 0x92, 0xf1, 0x72, 0xb0, 0x1c, 0x22, 0x1f, 0x97, 0xc3, 0xe4, 0x13, 0xd6, 0xe8, 0x87, 0xcb, 0x11, 0x72, 0xa4, 0x1c, 0x25, 0x47, 0xcb, 0x31, 0x72, 0xac, 0x7c, 0x52, 0x26, 0xc8, 0x71, 0xf2, 0x29, 0x39, 0x5e, 0x4e, 0x90, 0x13, 0xe5, 0x24, 0x39, 0x59, 0x26, 0xca, 0x29, 0x72, 0xaa, 0x9c, 0x26, 0x9f, 0x96, 0xd3, 0xe5, 0x33, 0x72, 0x86, 0x9c, 0x29,\n\t0x9f, 0x95, 0xcf, 0xc9, 0x59, 0x72, 0xb6, 0x7c, 0x5e, 0xbe, 0x20, 0x5f, 0x8c, 0x56, 0xa1, 0x6d, 0x0e, 0x6d, 0xf3, 0x68, 0x9b, 0x47, 0xdb, 0x3c, 0xda, 0xe6, 0xd0, 0x36, 0x87, 0xb6, 0x39, 0xb4, 0xcd, 0xa1, 0x6d, 0x0e, 0x6d, 0xf3, 0x68, 0x9b, 0x43, 0xdb, 0x3c, 0xda, 0xe6, 0xd1, 0x36, 0x87, 0xb6, 0x39, 0xb4, 0xcd, 0xa1, 0x6d, 0x88, 0xb6, 0x21, 0xda, 0x86, 0x68, 0x9b, 0x43, 0xdb, 0x3c, 0xda, 0x86, 0x68, 0x9b, 0x7b, 0x87, 0xb5, 0x74, 0x1e, 0x6d, 0xfb, 0xd0, 0x76, 0x18, 0x6d, 0x87, 0xd1, 0x76, 0x18, 0x6d, 0x87, 0xd1, 0x76, 0x18, 0x6d, 0x87, 0xd1, 0x76, 0x18, 0x6d, 0x87, 0xd1, 0x76, 0x18, 0x6d, 0x87, 0xd1, 0x36, 0x8b, 0xb6, 0x59, 0xb4, 0x2d, 0x59, 0x4b, 0xa7, 0xd1, 0xb6, 0x84, 0xb6, 0x59, 0x6b, 0xe9, 0xcc, 0xc6, 0xab, 0x49, 0xd6, 0x88, 0x31, 0x6b, 0xc4, 0xea, 0x75, 0xaa,\n\t0x0d, 0xeb, 0xeb, 0x10, 0x8d, 0xb3, 0x68, 0xbc, 0xb4, 0xe6, 0xf3, 0x28, 0xca, 0x1c, 0x50, 0x79, 0x69, 0x0d, 0x4b, 0x40, 0xe6, 0x3c, 0x32, 0xe7, 0x91, 0x39, 0x44, 0xe6, 0x10, 0x99, 0x73, 0xc8, 0x9c, 0x47, 0xe6, 0x1c, 0x32, 0x0f, 0x23, 0xf3, 0x30, 0x32, 0x67, 0x91, 0xb9, 0x7c, 0x55, 0x36, 0x44, 0xe6, 0x6c, 0x75, 0xad, 0x5d, 0xbe, 0x6a, 0x5f, 0x42, 0xe6, 0x3c, 0x32, 0xe7, 0x91, 0x39, 0x8b, 0xcc, 0x7d, 0xc8, 0xdc, 0x87, 0xcc, 0x7d, 0xc8, 0xdc, 0x87, 0xcc, 0x7d, 0xc8, 0xdc, 0x87, 0xcc, 0x7d, 0xc8, 0xdc, 0x87, 0xcc, 0x7d, 0xc8, 0xdc, 0x87, 0xcc, 0xc3, 0xc8, 0x3c, 0x8c, 0xcc, 0x39, 0x64, 0xce, 0x5b, 0x6b, 0xaf, 0xab, 0xae, 0xb5, 0x0b, 0x28, 0x9d, 0x47, 0xe9, 0x3e, 0x94, 0xee, 0x43, 0xe9, 0x1c, 0x4a, 0xf7, 0xa1, 0x74, 0x1f, 0x4a, 0xf7, 0xa1, 0x74, 0x1f, 0x4a, 0xf7, 0xa1,\n\t0x74, 0x88, 0xd2, 0x21, 0x4a, 0x97, 0x3f, 0xd7, 0x28, 0x87, 0xd2, 0x79, 0x94, 0x1e, 0x46, 0xe9, 0xd0, 0x5a, 0x3b, 0x69, 0xad, 0x9d, 0xb4, 0xd6, 0x4e, 0x5a, 0x6b, 0x27, 0xad, 0xb5, 0x93, 0xd6, 0xda, 0x49, 0x6b, 0xed, 0xa4, 0xb5, 0x76, 0xd2, 0x5a, 0x3b, 0x69, 0xad, 0x9d, 0xb4, 0xd6, 0x4e, 0x5a, 0x6b, 0x27, 0xad, 0xb5, 0x93, 0xd6, 0xda, 0x49, 0x6b, 0xed, 0xa4, 0xb5, 0x76, 0xd2, 0x5a, 0x3b, 0x69, 0xad, 0x9d, 0xb4, 0xd6, 0x4e, 0x5a, 0x6b, 0x27, 0xad, 0xb5, 0x93, 0xd6, 0xda, 0x49, 0x6b, 0xed, 0xa4, 0xb5, 0x76, 0xd2, 0x5a, 0x3b, 0x69, 0xad, 0x9d, 0xb4, 0xd6, 0x4e, 0x5a, 0x6b, 0x27, 0xad, 0xb5, 0x5f, 0xb5, 0xd6, 0x7e, 0x95, 0x1d, 0xf4, 0xb3, 0x83, 0x7e, 0x76, 0xd0, 0xcf, 0x0e, 0xfa, 0xd9, 0x41, 0x3f, 0x3b, 0xe8, 0x67, 0x07, 0xfd, 0xec, 0x20, 0xcb, 0x0e, 0xb2, 0xff, 0xce,\n\t0x5a, 0x3b, 0x61, 0xad, 0x9d, 0x60, 0x09, 0x4b, 0x59, 0xc2, 0x52, 0x96, 0xb0, 0x94, 0x25, 0x2c, 0x65, 0x09, 0x4b, 0x59, 0xc2, 0x52, 0x96, 0xb0, 0x94, 0x25, 0x2c, 0x65, 0x09, 0x4b, 0xeb, 0xef, 0x42, 0xe8, 0xbb, 0xe5, 0x1e, 0xf9, 0xb1, 0xfc, 0x44, 0xee, 0x95, 0xfb, 0x10, 0x79, 0xba, 0xfc, 0x54, 0x7e, 0x26, 0x3f, 0x97, 0xfb, 0xe5, 0x01, 0xf9, 0x85, 0x3c, 0x28, 0x33, 0xe4, 0x57, 0xf2, 0x6b, 0x99, 0x29, 0x0f, 0xc9, 0x6f, 0xe4, 0xb7, 0xf2, 0xb0, 0xfc, 0x4e, 0x1e, 0x91, 0x47, 0x65, 0x96, 0xfc, 0x5e, 0xfe, 0x20, 0x8f, 0xc9, 0xe3, 0xf2, 0x47, 0xf9, 0xb3, 0x3c, 0x29, 0x4f, 0xc9, 0xd3, 0xf2, 0x8c, 0xcc, 0x8e, 0xf2, 0xec, 0x21, 0xcf, 0x1e, 0xf2, 0xec, 0x21, 0x64, 0x0f, 0x21, 0x7b, 0x08, 0xd9, 0x43, 0xc8, 0x1e, 0x42, 0xf6, 0x10, 0xb2, 0x87, 0x90, 0x3d, 0x84, 0xec, 0x21, 0x64,\n\t0x0f, 0x21, 0x7b, 0x08, 0xd9, 0x43, 0xc8, 0x1e, 0x42, 0xf6, 0x10, 0xb2, 0x87, 0x90, 0x3d, 0x84, 0xec, 0x21, 0x64, 0x0f, 0x21, 0x7b, 0x08, 0xd9, 0x43, 0xc8, 0x1e, 0x42, 0xf6, 0x10, 0xb2, 0x87, 0x90, 0x3d, 0x84, 0xec, 0x21, 0x64, 0x0f, 0x21, 0x7b, 0x08, 0xd9, 0x43, 0xc8, 0x1e, 0x42, 0xf6, 0x10, 0xb2, 0x87, 0x90, 0x3d, 0x84, 0xec, 0x21, 0xac, 0x2f, 0x7f, 0x76, 0x60, 0xf9, 0xfa, 0x47, 0x4e, 0xf2, 0xd2, 0x2b, 0x05, 0x59, 0x27, 0x7d, 0xd2, 0x2f, 0x03, 0x32, 0x28, 0x6f, 0xc8, 0x7a, 0x19, 0x92, 0xa2, 0x0c, 0x4b, 0x49, 0x46, 0xe4, 0x4d, 0x89, 0xa2, 0x55, 0xec, 0x61, 0x15, 0x7b, 0x58, 0xc5, 0x1e, 0x56, 0xb1, 0x87, 0x55, 0xec, 0x61, 0x15, 0x7b, 0x58, 0xc5, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xcf,\n\t0x1e, 0xf2, 0xec, 0x21, 0xcf, 0x1e, 0xf2, 0xec, 0x21, 0xcf, 0x1e, 0xf2, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0xf2, 0xec, 0x21, 0xcf, 0x1e, 0xf2, 0xec, 0x21, 0xcf, 0x1e, 0xf2, 0xec, 0x21, 0xcf, 0x1e, 0xf2, 0xec, 0x21, 0xcf, 0x1e, 0xf2, 0xec, 0x21, 0xcf, 0x1e, 0xf2, 0xec, 0x21, 0xcf, 0x1e, 0xf2, 0xec, 0x21, 0xcf, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0xc7, 0x1e, 0x72, 0xec, 0x21, 0x64, 0x0f, 0x21, 0x7b, 0x08,\n\t0xd9, 0x43, 0xc8, 0x1e, 0x42, 0xf6, 0x10, 0xb2, 0x87, 0x90, 0x3d, 0x84, 0xec, 0x21, 0x64, 0x0f, 0x21, 0x7b, 0x08, 0xd9, 0x43, 0xc8, 0x1e, 0x42, 0xf6, 0x10, 0xb2, 0x87, 0x90, 0x3d, 0x84, 0xec, 0x21, 0x64, 0x0f, 0x21, 0x7b, 0x08, 0xd9, 0x43, 0xc8, 0x1e, 0x42, 0xf6, 0x10, 0xb2, 0x87, 0x90, 0x3d, 0x84, 0xec, 0x21, 0x64, 0x0f, 0x21, 0x7b, 0x08, 0xd9, 0x43, 0x8e, 0x3d, 0xe4, 0xd8, 0x43, 0x8e, 0x3d, 0xe4, 0xd8, 0x43, 0x8e, 0x3d, 0xe4, 0xd8, 0x43, 0x8e, 0x3d, 0xe4, 0xd8, 0x43, 0x8e, 0x3d, 0xe4, 0xd8, 0x43, 0xee, 0x1f, 0x5c, 0x83, 0x0f, 0xb3, 0x87, 0x61, 0xf6, 0x30, 0xcc, 0x1e, 0x86, 0xd9, 0xc3, 0x30, 0x7b, 0x18, 0x66, 0x0f, 0xc3, 0xec, 0x61, 0x98, 0x3d, 0x0c, 0xb3, 0x87, 0x61, 0xf6, 0x30, 0xcc, 0x1e, 0x86, 0xd9, 0xc3, 0x30, 0x7b, 0x18, 0x66, 0x0f, 0xc3, 0xec, 0x61, 0x98,\n\t0x3d, 0x0c, 0xb3, 0x87, 0x61, 0xf6, 0x30, 0xcc, 0x1e, 0x86, 0xd9, 0xc3, 0x30, 0x7b, 0x18, 0x66, 0x0f, 0xc3, 0xec, 0x61, 0x98, 0x3d, 0x0c, 0xb3, 0x87, 0x61, 0xf6, 0x30, 0xcc, 0x1e, 0x86, 0xd9, 0xc3, 0x30, 0x7b, 0x18, 0x66, 0x0f, 0xc3, 0xec, 0x61, 0x98, 0x3d, 0x0c, 0xb3, 0x87, 0x61, 0xf6, 0x30, 0xcc, 0x1e, 0x86, 0xd9, 0xc3, 0x30, 0x7b, 0x18, 0x66, 0x0f, 0xc3, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0x21, 0xcb, 0x1e, 0xb2, 0xec, 0xa1, 0xc4, 0x1e, 0x4a, 0xd6, 0xe0, 0x69, 0x6b, 0xf0, 0x34, 0x53, 0x28, 0x31,\n\t0x85, 0x12, 0x53, 0x28, 0x31, 0x85, 0x12, 0x53, 0x28, 0x31, 0x85, 0x12, 0x53, 0x28, 0x31, 0x85, 0x12, 0x53, 0x28, 0x31, 0x85, 0x12, 0x53, 0xc8, 0x32, 0x85, 0x2c, 0x53, 0xc8, 0x32, 0x85, 0x2c, 0x53, 0xc8, 0x32, 0x85, 0x2c, 0x53, 0xc8, 0x31, 0x85, 0x90, 0x29, 0x84, 0x4c, 0x21, 0x64, 0x0a, 0x21, 0x53, 0x08, 0x99, 0x42, 0x96, 0x29, 0x64, 0x99, 0x42, 0x96, 0x29, 0x64, 0x99, 0x42, 0x96, 0x29, 0x84, 0xb1, 0xf9, 0x0c, 0x20, 0xcb, 0x00, 0xb2, 0x0c, 0x20, 0xcb, 0x00, 0xc2, 0x7f, 0xe7, 0x6a, 0x7a, 0x96, 0x01, 0x64, 0x19, 0x40, 0x76, 0x93, 0xab, 0xe9, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10,\n\t0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0x67, 0x00, 0x71, 0x06, 0x10, 0xaf, 0x1a, 0x40, 0x96, 0x01, 0x84, 0x0c, 0x20, 0x64, 0x00, 0x21, 0x03, 0xc8, 0x32, 0x80, 0x2c, 0x03, 0xc8, 0x32, 0x80, 0x2c, 0x03, 0xc8, 0x32, 0x80, 0x90, 0x01, 0x84, 0x0c, 0x20, 0x64, 0x00, 0x21, 0x03, 0x08, 0x19, 0x40, 0xc8, 0x00, 0xc2, 0xb7, 0x5d, 0x4d, 0x0f, 0x19, 0x40, 0xc8, 0x00, 0xb2, 0x0c, 0x20, 0x64, 0x00, 0x69, 0x06, 0x90, 0x66, 0x00, 0x69, 0x06, 0x90, 0x66, 0x00, 0x21, 0x03, 0x88, 0x33, 0x80, 0x76, 0x06, 0xd0, 0xce, 0x00, 0xda, 0x19, 0x40, 0x3b, 0x03, 0x68, 0x67, 0x00, 0xed, 0x0c, 0xa0, 0x9d, 0x01, 0xb4, 0x33, 0x80,\n\t0x76, 0x06, 0xd0, 0xbe, 0x89, 0x01, 0xbc, 0x68, 0xbd, 0xbd, 0x9c, 0x05, 0x94, 0x3f, 0xdd, 0x64, 0x41, 0xf9, 0x6f, 0xf8, 0x62, 0x07, 0x46, 0x1d, 0xb1, 0x83, 0xac, 0xbb, 0x8f, 0x8f, 0xfe, 0x86, 0xfe, 0xaf, 0xa2, 0xff, 0x22, 0xf4, 0x7f, 0x39, 0x86, 0x46, 0xb1, 0x0b, 0xa2, 0x15, 0xd5, 0xab, 0xec, 0x59, 0xc4, 0x0f, 0x11, 0x3f, 0xac, 0x5e, 0x5d, 0xcf, 0x22, 0x7e, 0x88, 0xf8, 0x21, 0xe2, 0x87, 0x88, 0xdf, 0x8e, 0xf8, 0xed, 0x95, 0xbf, 0x2f, 0x7b, 0x8b, 0xf8, 0xd9, 0xea, 0xdf, 0x95, 0xa5, 0x11, 0x3f, 0x8b, 0xf8, 0x0b, 0x10, 0x3f, 0x44, 0xfc, 0xb0, 0xf2, 0xb7, 0x65, 0x0f, 0x46, 0x71, 0xc4, 0x8f, 0x23, 0x7e, 0x1c, 0xf1, 0xe3, 0x88, 0x1f, 0x47, 0xfc, 0x38, 0xe2, 0xc7, 0x11, 0x3f, 0x8e, 0xf8, 0x71, 0xc4, 0x8f, 0x23, 0x7e, 0x3b, 0xe2, 0xb7, 0x23, 0x7e, 0x16, 0xf1, 0x43, 0x94,\n\t0x0f, 0xeb, 0x0e, 0x88, 0x3a, 0xea, 0xec, 0x33, 0xda, 0xc7, 0xd1, 0x3e, 0x8e, 0xf6, 0x59, 0xb4, 0x8f, 0xa3, 0x7d, 0x1c, 0xed, 0xe3, 0x68, 0x1f, 0x47, 0xfb, 0x78, 0xf5, 0xca, 0x7a, 0xb6, 0x4a, 0xfb, 0x10, 0xed, 0x43, 0xb4, 0x6f, 0x2f, 0x5f, 0x59, 0x47, 0xbd, 0x2c, 0xea, 0x65, 0x51, 0x2f, 0x8b, 0x7a, 0x59, 0xd4, 0xcb, 0xa2, 0x5e, 0x16, 0xf5, 0xb2, 0xa8, 0x97, 0x45, 0xbd, 0x2c, 0xea, 0x65, 0x51, 0x2f, 0x8b, 0x7a, 0x59, 0xd4, 0xcb, 0xa2, 0x5e, 0x16, 0xf5, 0xb2, 0xa8, 0x97, 0x45, 0xbd, 0x2c, 0xea, 0x65, 0x51, 0x2f, 0x8b, 0x7a, 0x59, 0xd4, 0xcb, 0xa2, 0x5e, 0x16, 0xf5, 0xb2, 0xa8, 0x97, 0x45, 0xbd, 0x2c, 0xea, 0x65, 0x51, 0x2f, 0x5b, 0xfd, 0x04, 0xb8, 0x2c, 0xea, 0x65, 0x51, 0x2f, 0x8b, 0x7a, 0x21, 0xea, 0x85, 0xa8, 0x17, 0xbe, 0xcb, 0x95, 0xe7, 0x2c, 0xea, 0x65, 0x51,\n\t0x2f, 0x8b, 0x7a, 0x59, 0xd4, 0xcb, 0xfe, 0x37, 0x5c, 0x79, 0x8e, 0xa3, 0x5e, 0x1c, 0xf5, 0xe2, 0xa8, 0x17, 0x47, 0xbd, 0x38, 0xea, 0xc5, 0x51, 0x2f, 0x8e, 0x7a, 0x71, 0xd4, 0x8b, 0xa3, 0x5e, 0x1c, 0xf5, 0xe2, 0xa8, 0x17, 0x47, 0xbd, 0x38, 0xea, 0xc5, 0x51, 0x2f, 0x8e, 0x7a, 0x71, 0xd4, 0x8b, 0xa3, 0x5e, 0xfc, 0x3f, 0xa0, 0x5e, 0x16, 0xf5, 0xb2, 0xa8, 0x97, 0x45, 0xbd, 0x2c, 0xea, 0x65, 0x51, 0x2f, 0x8b, 0x7a, 0x59, 0xd4, 0x0b, 0x51, 0x2f, 0x44, 0xbd, 0x10, 0xf5, 0x42, 0xd4, 0x0b, 0x51, 0x2f, 0x44, 0xbd, 0x2c, 0xea, 0x65, 0x51, 0x2f, 0x8b, 0x7a, 0x59, 0xd4, 0xcb, 0xa2, 0x5e, 0x16, 0xf5, 0xb2, 0xa8, 0x97, 0x45, 0xbd, 0x2c, 0xea, 0x65, 0x51, 0x2f, 0x8b, 0x7a, 0x59, 0xd4, 0xcb, 0xa2, 0x5e, 0x16, 0xf5, 0xb2, 0xa8, 0x97, 0x45, 0xbd, 0x2c, 0xea, 0x85, 0xa8, 0x17, 0xa2,\n\t0x5e, 0x88, 0x7a, 0x21, 0xea, 0x85, 0xa8, 0x17, 0xa2, 0x5e, 0x88, 0x7a, 0x21, 0xea, 0x85, 0xa8, 0x17, 0xa2, 0x5e, 0x88, 0x7a, 0x21, 0xea, 0x85, 0xa8, 0x17, 0xa2, 0x5e, 0x88, 0x7a, 0x21, 0xea, 0x85, 0xa8, 0x17, 0xa2, 0x5e, 0x88, 0x7a, 0x21, 0xea, 0x85, 0xa8, 0x17, 0xa2, 0x5e, 0x88, 0x7a, 0x21, 0xea, 0x85, 0xa8, 0x17, 0xa2, 0x5e, 0xf8, 0xdf, 0x7c, 0xe5, 0x39, 0x44, 0xbd, 0x10, 0xf5, 0x42, 0xd4, 0x0b, 0x51, 0x2f, 0x44, 0xbd, 0x10, 0xf5, 0x42, 0xd4, 0x0b, 0x51, 0xaf, 0xfc, 0x0e, 0x10, 0x21, 0xea, 0x85, 0xa8, 0x97, 0x46, 0xbd, 0x34, 0xea, 0xa5, 0x51, 0x2f, 0x8d, 0x7a, 0x69, 0xd4, 0x4b, 0xa3, 0x5e, 0x1a, 0xf5, 0xd2, 0xa8, 0x97, 0x46, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4,\n\t0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0x76, 0xd4, 0x6b, 0x47, 0xbd, 0xf6, 0xff, 0x42, 0xea, 0xbd, 0x88, 0x7a, 0x2f, 0x5a, 0x33, 0x2f, 0xb7, 0x66, 0x5e, 0x6e, 0xcd, 0xbc, 0xdc, 0x9a, 0x79, 0xb9, 0x35, 0xf3, 0x72, 0x6b, 0xe6, 0xe5, 0xd6, 0xcc, 0xcb, 0x11, 0x71, 0x21, 0x22, 0x96, 0x3f, 0xa9, 0x65, 0x01, 0x22, 0x2e, 0x40, 0xc4, 0x05, 0x88, 0xb8, 0x00, 0x11, 0x17, 0x20, 0xe2, 0x02, 0x44, 0x5c, 0x80, 0x88,\n\t0x0b, 0x10, 0x71, 0x01, 0x22, 0x2e, 0x78, 0xb7, 0xbf, 0x43, 0x40, 0xc4, 0xf0, 0x5d, 0xae, 0x4a, 0xbf, 0x13, 0x11, 0xb3, 0xb1, 0xe7, 0xdf, 0x61, 0x4d, 0x9c, 0x44, 0xc4, 0x24, 0x22, 0x26, 0x11, 0x31, 0x89, 0x88, 0x49, 0x44, 0x4c, 0x22, 0x62, 0x0a, 0x11, 0x53, 0x88, 0x98, 0x42, 0xc4, 0x24, 0x22, 0x26, 0xff, 0xc7, 0xdf, 0x03, 0xf0, 0x8b, 0xd1, 0x6a, 0x44, 0x4c, 0xbd, 0x6d, 0x4d, 0x9c, 0x47, 0xc4, 0x3c, 0x22, 0xe6, 0x83, 0xf2, 0x6f, 0x49, 0x7c, 0x55, 0xde, 0x5a, 0x13, 0xe7, 0x37, 0x59, 0x13, 0x6f, 0xfa, 0xef, 0xcb, 0x49, 0x44, 0x4c, 0x22, 0x62, 0xb2, 0xfa, 0xef, 0xcb, 0xe5, 0x35, 0x71, 0xaa, 0xfa, 0xef, 0xcb, 0x3d, 0x88, 0xd8, 0x83, 0x88, 0x3d, 0x88, 0xd8, 0x53, 0x5d, 0x13, 0x97, 0xdf, 0x2b, 0xb0, 0x0d, 0x11, 0xdb, 0x10, 0xb1, 0x0d, 0x11, 0xdb, 0x10, 0xb1, 0x0d, 0x11,\n\t0xdb, 0x10, 0xb1, 0x0d, 0x11, 0xdb, 0x10, 0xb1, 0x0d, 0x11, 0xdb, 0x36, 0x21, 0xe2, 0x73, 0x88, 0xd8, 0x81, 0x88, 0x29, 0x44, 0x9c, 0x83, 0x88, 0x09, 0x44, 0x5c, 0x5e, 0x21, 0xe2, 0x61, 0x72, 0x78, 0x85, 0x8c, 0xcf, 0x56, 0x68, 0xf8, 0xc5, 0x68, 0x5d, 0xec, 0x4b, 0x72, 0x41, 0xd4, 0x89, 0x8a, 0xc9, 0x2a, 0x15, 0x37, 0xac, 0x83, 0x93, 0xa8, 0x98, 0xaa, 0xfe, 0x9b, 0x73, 0xbe, 0xfa, 0x6f, 0xce, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x09, 0x54, 0x5c, 0x8d, 0x8a, 0x29, 0x54, 0x4c, 0xa0, 0x62, 0x0f, 0x2a, 0xa6, 0x50, 0x71, 0xce, 0x26, 0xeb, 0xe0, 0xc4, 0x3f, 0xf1, 0xbe, 0x75, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0xa9, 0xf2, 0x3a, 0xb8, 0xb2, 0xf6, 0x3d, 0x20, 0x5a, 0x8a, 0x8a, 0x4b, 0xff, 0xed, 0xbd, 0xbc, 0x7c, 0xef, 0x9d, 0xde, 0xc7, 0x6b, 0x55, 0x94, 0x44, 0xc5, 0x54, 0x95, 0x8a,\n\t0xf9, 0xea, 0x1a, 0xb8, 0x6d, 0x74, 0xf9, 0xf3, 0x95, 0xfe, 0xf7, 0xac, 0x05, 0x93, 0xa8, 0x98, 0x44, 0xc5, 0x24, 0x2a, 0x26, 0x51, 0x31, 0x89, 0x8a, 0x29, 0x54, 0x4c, 0xa1, 0x62, 0x0a, 0x15, 0x53, 0xa8, 0x98, 0x42, 0xc5, 0x24, 0x2a, 0x26, 0x51, 0x31, 0x89, 0x8a, 0x49, 0x54, 0x4c, 0xa2, 0x62, 0x12, 0x15, 0x93, 0xa8, 0x98, 0x44, 0xc5, 0x24, 0x2a, 0x26, 0x51, 0x31, 0x89, 0x8a, 0x49, 0x54, 0x4c, 0xa2, 0x62, 0x12, 0x15, 0x93, 0xa8, 0x98, 0x44, 0xc5, 0x24, 0x2a, 0x26, 0x51, 0x31, 0x89, 0x8a, 0x49, 0x54, 0x4c, 0xa2, 0x62, 0x12, 0x15, 0x93, 0xa8, 0x98, 0xac, 0xbc, 0x1f, 0xd2, 0x7f, 0xc2, 0x7b, 0x21, 0xa1, 0xe2, 0x6a, 0x54, 0x5c, 0x8d, 0x8a, 0xab, 0x51, 0x71, 0x35, 0x2a, 0xae, 0x46, 0xc5, 0xd5, 0xa8, 0xb8, 0x1a, 0x15, 0x53, 0xa8, 0x98, 0x42, 0xc5, 0x14, 0x2a, 0xa6, 0x50,\n\t0x31, 0x85, 0x8a, 0x29, 0x54, 0x4c, 0xfd, 0x3b, 0x6b, 0xc1, 0x3c, 0x2a, 0xe6, 0x51, 0x31, 0x8f, 0x8a, 0x79, 0x54, 0xcc, 0xa3, 0x62, 0x1e, 0x15, 0xf3, 0xa8, 0x98, 0x47, 0xc5, 0x3c, 0x2a, 0xe6, 0x51, 0x31, 0x8f, 0x8a, 0x79, 0x54, 0xcc, 0xa3, 0x62, 0x1e, 0x15, 0xf3, 0xa8, 0x98, 0x47, 0xc5, 0xfc, 0xff, 0xc3, 0x5a, 0xf0, 0xff, 0xe6, 0xdf, 0x63, 0x93, 0xa8, 0x98, 0x44, 0xc5, 0x24, 0x2a, 0x26, 0x51, 0x31, 0x89, 0x8a, 0x49, 0x54, 0x4c, 0xa2, 0x62, 0x12, 0x15, 0x93, 0xa8, 0x98, 0x44, 0xc5, 0x24, 0x2a, 0x26, 0x51, 0x31, 0x89, 0x8a, 0x49, 0x54, 0x4c, 0xa2, 0x62, 0x12, 0x15, 0x93, 0xa8, 0x98, 0x44, 0xc5, 0x24, 0x2a, 0x26, 0x51, 0x31, 0x89, 0x8a, 0x49, 0x54, 0x4c, 0xa2, 0x62, 0x12, 0x15, 0x93, 0xa8, 0x98, 0x44, 0xc5, 0xe4, 0x3f, 0xf9, 0xef, 0xb1, 0x3d, 0xa8, 0xd8, 0x83, 0x8a,\n\t0x3d, 0xa8, 0xd8, 0x83, 0x8a, 0x3d, 0xa8, 0xd8, 0x83, 0x8a, 0x3d, 0xa8, 0xd8, 0x83, 0x8a, 0x3d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0x86, 0x8a, 0x6d, 0xa8, 0xd8, 0xf6, 0x5f, 0x48, 0xc5, 0xe7, 0x50, 0xf1, 0x39, 0x54, 0xec, 0x40, 0xc5, 0x0e, 0x54, 0xec, 0x40,\n\t0xc5, 0x0e, 0x54, 0xec, 0x40, 0xc5, 0x0e, 0x54, 0x2c, 0xbf, 0xff, 0x51, 0x0a, 0x15, 0x53, 0xa8, 0x38, 0x07, 0x15, 0xe7, 0xa0, 0xe2, 0x1c, 0x54, 0x9c, 0x83, 0x8a, 0x73, 0x50, 0x71, 0x0e, 0x2a, 0xce, 0x41, 0xc5, 0x39, 0xa8, 0x38, 0x07, 0x15, 0xe7, 0xa0, 0x62, 0x02, 0x15, 0x13, 0xa8, 0x98, 0x40, 0xc5, 0x04, 0x2a, 0x26, 0x50, 0x31, 0x51, 0xfd, 0xb7, 0xda, 0x24, 0x2a, 0x26, 0x51, 0x31, 0x89, 0x8a, 0x49, 0x54, 0x4c, 0xbe, 0x0b, 0x15, 0x53, 0x95, 0x75, 0x62, 0x0f, 0x2a, 0xf6, 0xa0, 0x62, 0x4f, 0x75, 0x9d, 0xf8, 0x6e, 0x57, 0x8a, 0x73, 0xa8, 0x98, 0x43, 0xc5, 0xdc, 0x26, 0x57, 0x8a, 0xff, 0xa7, 0xa9, 0xd8, 0x55, 0xbd, 0x52, 0xbc, 0xe9, 0x3a, 0x31, 0x44, 0xc5, 0x10, 0x15, 0x43, 0x54, 0x0c, 0x51, 0x31, 0xfc, 0x0f, 0xd6, 0x89, 0x9b, 0x5e, 0x29, 0xde, 0xb0, 0x4e, 0xcc, 0x55,\n\t0xd7, 0x89, 0x6f, 0xbf, 0x52, 0x1c, 0x56, 0xa9, 0xd8, 0x81, 0x8a, 0x1d, 0xa8, 0xd8, 0x81, 0x8a, 0x1d, 0xa8, 0xd8, 0x81, 0x8a, 0x1d, 0xa8, 0xd8, 0x81, 0x8a, 0x1d, 0xa8, 0xd8, 0x81, 0x8a, 0x1d, 0xa8, 0x98, 0x41, 0xc5, 0x0c, 0x2a, 0x2e, 0x41, 0xc5, 0x55, 0xa8, 0xf8, 0x02, 0x2a, 0x2e, 0x2a, 0xbf, 0x83, 0xee, 0x26, 0xeb, 0xc4, 0x79, 0xd6, 0x89, 0xcb, 0xac, 0x13, 0x5f, 0xb4, 0x4e, 0x5c, 0x8a, 0x8c, 0x83, 0x88, 0xd8, 0x55, 0xbd, 0x5a, 0x9c, 0xd9, 0x64, 0x9d, 0x58, 0xbe, 0x32, 0x9c, 0x7b, 0xdb, 0x3a, 0xb1, 0x03, 0x11, 0x3b, 0x2a, 0xef, 0xe8, 0x7a, 0x4b, 0xd4, 0x85, 0x88, 0xb9, 0xea, 0x3b, 0xb9, 0x96, 0xaf, 0x0c, 0xe7, 0x10, 0x71, 0xd1, 0x26, 0xeb, 0xc4, 0xa5, 0xff, 0x04, 0x11, 0x3b, 0x10, 0xb1, 0xa3, 0x7a, 0x65, 0x78, 0xc3, 0x3a, 0xf1, 0x15, 0x44, 0x7c, 0x65, 0x13, 0x22,\n\t0x86, 0xef, 0x42, 0xc4, 0xf2, 0x55, 0xe1, 0x1c, 0x22, 0x66, 0x36, 0x59, 0x27, 0x76, 0x94, 0xaf, 0x0a, 0x23, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0x0f, 0x22, 0xf6, 0x20, 0x62, 0xcf, 0xdb, 0xd6, 0x89, 0xef, 0x74, 0x75, 0x34, 0x87, 0x88, 0x39, 0x44, 0xcc, 0x21, 0x62, 0x0e, 0x11, 0x73, 0xff, 0x0d, 0x57, 0x47, 0xff, 0xb3, 0x88, 0xd8, 0x85, 0x88, 0x5d, 0x88, 0xd8, 0x85, 0x88, 0x5d, 0x88,\n\t0xd8, 0x85, 0x88, 0x5d, 0x88, 0xd8, 0xf5, 0x1f, 0x5c, 0x1d, 0x7d, 0xb7, 0x75, 0x62, 0x88, 0x88, 0x21, 0x22, 0x86, 0x88, 0x18, 0x22, 0x62, 0x88, 0x88, 0x21, 0x22, 0x86, 0x88, 0x18, 0x22, 0x62, 0x88, 0x88, 0x21, 0x22, 0x86, 0x88, 0x18, 0x22, 0x62, 0x88, 0x88, 0x21, 0x22, 0x86, 0x88, 0x18, 0x22, 0x62, 0xf8, 0xdf, 0xbc, 0x4e, 0xfc, 0xef, 0xbc, 0x3a, 0xfa, 0xcf, 0xac, 0x13, 0xff, 0x91, 0xab, 0xa3, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8,\n\t0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0xd8, 0x81, 0x88, 0x1d, 0x88, 0x98, 0x41, 0xc4, 0x0c, 0x22, 0x66, 0x10, 0x31, 0x83, 0x88, 0x19, 0x44, 0xcc, 0x20, 0x62, 0x06, 0x11, 0x33, 0x88, 0x98, 0x41, 0xc4, 0x0c, 0x22, 0x66, 0x10, 0x31, 0x83, 0x88, 0x19, 0x44, 0xcc, 0x20, 0x62, 0x06, 0x11, 0x33, 0x88, 0x98, 0x41, 0xc4, 0x0c, 0x22, 0x66, 0x10, 0x31, 0x83, 0x88, 0x19, 0x44, 0xcc, 0x20, 0xe2, 0x12, 0x44, 0x5c, 0x82, 0x88, 0xab, 0x10, 0x71, 0x15, 0x22, 0xae, 0x42, 0xc4, 0x55, 0x88, 0xb8, 0x0a, 0x11, 0x57, 0x21, 0xe2, 0x2a, 0x44, 0x7c, 0x01, 0x11, 0x5f, 0x40, 0xc4, 0x45, 0x88, 0xb8, 0x08, 0x11, 0x17, 0x21, 0xe2, 0x22, 0x44, 0x5c, 0x84, 0x88,\n\t0x8b, 0x10, 0x71, 0x11, 0x22, 0x2e, 0x42, 0xc4, 0x45, 0x88, 0xb8, 0xe8, 0xdd, 0xde, 0xf9, 0xaf, 0xba, 0x4e, 0x7c, 0xa7, 0x2b, 0xa7, 0x19, 0x44, 0xcc, 0x20, 0x62, 0x06, 0x11, 0x33, 0x88, 0x98, 0x41, 0xc4, 0x5c, 0xb0, 0x45, 0xb0, 0x5d, 0x34, 0x1c, 0xec, 0xa5, 0x6b, 0x1f, 0x1a, 0x15, 0x02, 0x15, 0xa2, 0x33, 0x67, 0xcb, 0xbf, 0xef, 0x5e, 0x73, 0x61, 0x34, 0x54, 0x73, 0xab, 0xb5, 0xc6, 0x63, 0xd1, 0xfc, 0x9a, 0x27, 0x75, 0xc6, 0x7b, 0xa2, 0x57, 0x2a, 0xff, 0x56, 0x36, 0x9f, 0xd7, 0xec, 0x12, 0xd4, 0x36, 0x7c, 0x24, 0x68, 0x08, 0xc6, 0x6e, 0x7c, 0x5f, 0xb4, 0x43, 0xbd, 0xd6, 0x79, 0xc1, 0x0e, 0x38, 0x34, 0x1c, 0x3b, 0x2c, 0x38, 0x20, 0xf6, 0x89, 0xe0, 0xe4, 0xd8, 0xe1, 0x6e, 0x8f, 0x70, 0x7b, 0x5c, 0xf0, 0xf9, 0xd8, 0x69, 0xc1, 0x05, 0xb1, 0xd3, 0x83, 0x9f, 0xc5, 0xce,\n\t0x08, 0xee, 0x8b, 0x9d, 0x19, 0xc4, 0x62, 0x17, 0x04, 0xb5, 0x95, 0xf7, 0x9e, 0xba, 0x48, 0x6e, 0xb5, 0x7a, 0x79, 0x2c, 0x5a, 0x57, 0x7b, 0x57, 0x70, 0x47, 0xed, 0x3d, 0xc1, 0x2f, 0x6b, 0x7f, 0x1c, 0xfc, 0xa2, 0xee, 0x80, 0xe0, 0xdc, 0xba, 0x03, 0x65, 0x7e, 0x94, 0x78, 0xd7, 0xf7, 0x21, 0x79, 0x87, 0xf7, 0x1e, 0xb1, 0x67, 0xef, 0x6b, 0xd8, 0x35, 0xd8, 0xa7, 0x61, 0xb7, 0x60, 0xff, 0xea, 0xfb, 0x57, 0x6c, 0x6e, 0x4f, 0x77, 0x0e, 0x76, 0x0a, 0x1a, 0xa3, 0x81, 0x60, 0x4b, 0x29, 0xbf, 0x7f, 0xfe, 0x5e, 0xd1, 0xeb, 0x95, 0x3d, 0xbe, 0x30, 0xea, 0x8d, 0x8d, 0x8f, 0x16, 0xc7, 0x26, 0x70, 0x83, 0xd3, 0xac, 0xcb, 0xde, 0xba, 0x7a, 0xd9, 0xee, 0xd8, 0xdf, 0xa8, 0xf9, 0x6a, 0x34, 0x60, 0xaf, 0x7a, 0x2a, 0xc7, 0x7e, 0x57, 0xb4, 0xcc, 0xf1, 0x2f, 0x72, 0xfc, 0xcb, 0xea, 0x76,\n\t0x89, 0x06, 0xea, 0x56, 0x4a, 0x57, 0x34, 0x30, 0xc6, 0x63, 0xc6, 0x5c, 0x27, 0xdf, 0x96, 0x81, 0x68, 0xa0, 0xfe, 0x90, 0x68, 0xa0, 0xe9, 0xce, 0x68, 0x55, 0xd3, 0x94, 0x68, 0x55, 0x6c, 0x16, 0xd7, 0x28, 0x71, 0x8d, 0x12, 0xd7, 0x28, 0x55, 0x7f, 0x07, 0x2c, 0xc1, 0x35, 0x12, 0x5c, 0x23, 0xc1, 0x35, 0x12, 0x5c, 0x23, 0xc1, 0x35, 0x12, 0x5c, 0x23, 0xcd, 0x35, 0xd2, 0x5c, 0x23, 0xcd, 0x35, 0x12, 0x5c, 0x23, 0xf1, 0x3f, 0xfe, 0x5e, 0x71, 0x6f, 0xad, 0xc0, 0xd7, 0xbc, 0xed, 0x77, 0xc0, 0x86, 0xb9, 0xc6, 0x70, 0x79, 0x8c, 0xb9, 0xc6, 0x30, 0xd7, 0x18, 0xae, 0xfe, 0x0e, 0x58, 0xb8, 0xc9, 0xef, 0x80, 0x6d, 0xea, 0x1a, 0x09, 0xae, 0x91, 0xe0, 0x1a, 0x89, 0xaa, 0x6b, 0x94, 0x7f, 0x07, 0x2c, 0x5d, 0x75, 0x8d, 0x1c, 0xd7, 0xc8, 0x71, 0x8d, 0x1c, 0xd7, 0xc8, 0x55, 0x7f, 0x07,\n\t0x6c, 0xd9, 0x3f, 0x71, 0x4d, 0x3a, 0xc5, 0x35, 0x52, 0xd5, 0x6b, 0xd2, 0xcb, 0x78, 0xc6, 0x0b, 0x1c, 0x22, 0xc1, 0x21, 0x52, 0x9b, 0xfc, 0xde, 0x57, 0x82, 0x43, 0xa4, 0xab, 0x0e, 0x51, 0xfc, 0xbb, 0x6b, 0xcd, 0x6f, 0xad, 0xa8, 0xd3, 0xdc, 0x21, 0xc7, 0x1d, 0xd2, 0xdc, 0xe1, 0x85, 0x8d, 0xbf, 0xef, 0xf5, 0x8f, 0xbf, 0x6f, 0xd9, 0x86, 0xeb, 0xcb, 0x6b, 0x36, 0xf9, 0x5d, 0xaf, 0xea, 0xfb, 0x39, 0x45, 0xc3, 0xef, 0xf8, 0x5e, 0x4e, 0xab, 0xa2, 0x04, 0x5f, 0x48, 0xf3, 0x85, 0x54, 0xd5, 0x17, 0x8a, 0xd5, 0xeb, 0xca, 0x09, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50,\n\t0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0xe2, 0x0b, 0x25, 0xbe, 0x50, 0x7a, 0xdb, 0xef, 0x62, 0x25, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x9a, 0x2f, 0xa4, 0xf9, 0x42, 0x9a, 0x2f, 0xa4, 0xf9, 0x42, 0x9a, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0x82, 0x2f, 0x24, 0xf8, 0x42, 0xa2, 0xf2, 0x3e, 0x38, 0xff, 0x09, 0xef,\n\t0x81, 0xf3, 0x1f, 0xac, 0xa0, 0xd7, 0xf0, 0x85, 0x35, 0x7c, 0x61, 0x0d, 0x5f, 0x58, 0xc3, 0x17, 0xd6, 0xf0, 0x85, 0x35, 0x7c, 0x61, 0xcd, 0xbf, 0xf3, 0xbb, 0x58, 0xc3, 0x7c, 0x61, 0x98, 0x2f, 0x0c, 0xf3, 0x85, 0x61, 0xbe, 0x30, 0xcc, 0x17, 0x86, 0xf9, 0xc2, 0x30, 0x5f, 0x18, 0xe6, 0x0b, 0xc3, 0x7c, 0x61, 0x98, 0x2f, 0x0c, 0xf3, 0x85, 0x61, 0xbe, 0x30, 0xcc, 0x17, 0x86, 0xf9, 0xc2, 0x30, 0x5f, 0x18, 0xe6, 0x0b, 0xc3, 0xff, 0x0f, 0xbf, 0x8b, 0xf5, 0x7f, 0xe3, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09,\n\t0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x09, 0xbe, 0x90, 0xe0, 0x0b, 0x89, 0x7f, 0xd2, 0x17, 0x72, 0x7c, 0x21, 0xc7, 0x17, 0x72, 0x7c, 0x21, 0xc7, 0x17, 0x72, 0x7c, 0x21, 0xc7, 0x17, 0x72, 0x7c, 0x21, 0xc7, 0x17, 0x72, 0xff, 0xcb, 0xaf, 0x2b, 0xa7, 0xf8, 0x42, 0x8a, 0x2f, 0xa4, 0xf8, 0x42, 0x8a, 0x2f, 0xa4, 0xf8, 0x42, 0x8a, 0x2f, 0xa4, 0xf8, 0x42, 0x8a, 0x2f, 0xa4, 0xf8, 0x42, 0x8a, 0x2f, 0xa4, 0xf8, 0x42, 0x8a, 0x2f, 0xa4, 0xf8, 0x42, 0x8a, 0x2f, 0xa4, 0xf8, 0x42, 0x8a, 0x2f, 0xa4, 0xf8, 0x42, 0x8a, 0x2f, 0xa4, 0xf8, 0x42, 0x8a, 0x2f, 0xa4, 0xf8, 0x42, 0x6a, 0x93, 0xeb, 0xca, 0xef, 0xfe, 0xde, 0x37, 0x6b, 0xb8, 0x42, 0xb7, 0x24, 0x25, 0x25, 0x3d, 0x92, 0x91, 0xac, 0x84, 0x92, 0x93, 0x7c, 0xf4, 0x42, 0xd5, 0x07, 0x12, 0x7c, 0x20, 0xc1, 0x07, 0x12,\n\t0x7c, 0x20, 0xd1, 0x58, 0x5e, 0x39, 0x0f, 0x45, 0x29, 0x3e, 0x90, 0xe2, 0x03, 0x29, 0x3e, 0x90, 0xe2, 0x03, 0x29, 0x3e, 0x90, 0x0e, 0x76, 0x09, 0x6a, 0xa2, 0x36, 0x6c, 0xbc, 0x57, 0xc7, 0x8f, 0x74, 0xfa, 0xdf, 0xeb, 0xcc, 0xcd, 0x18, 0x39, 0x31, 0x76, 0x70, 0x94, 0x8f, 0x59, 0x0d, 0x63, 0xe5, 0xaf, 0x62, 0xbd, 0x56, 0x6c, 0x05, 0x59, 0x17, 0x25, 0x6b, 0x3e, 0x85, 0x95, 0xb7, 0x46, 0x2b, 0xb1, 0xf2, 0x41, 0xac, 0xfc, 0x39, 0x62, 0xaf, 0xd4, 0x99, 0x56, 0x9b, 0xed, 0x2b, 0x1a, 0x76, 0x0a, 0x76, 0x37, 0x3b, 0x5e, 0x45, 0xe5, 0x7d, 0x50, 0x79, 0x47, 0x54, 0xde, 0x11, 0x95, 0x47, 0xa3, 0xf2, 0x56, 0x0d, 0x7b, 0x07, 0xfb, 0x21, 0xf3, 0xbe, 0x2a, 0x6e, 0x99, 0x4a, 0xf9, 0x53, 0xb0, 0x7b, 0xf0, 0x21, 0x6b, 0xf2, 0x43, 0xa3, 0x7e, 0x54, 0x2e, 0x72, 0x88, 0xed, 0x38, 0xc4,\n\t0xfe, 0x1c, 0x62, 0x3b, 0x0e, 0xb1, 0x3f, 0x87, 0x38, 0x9c, 0x43, 0x1c, 0xc7, 0x21, 0x2e, 0xe7, 0x10, 0xdf, 0xae, 0x39, 0xbb, 0xf2, 0xf7, 0xbc, 0x3d, 0xb6, 0xbc, 0xd6, 0x96, 0xd3, 0xb6, 0xdc, 0xcf, 0x1f, 0x2e, 0xe3, 0x0f, 0xd7, 0xf0, 0x87, 0x9b, 0xf8, 0xc3, 0x71, 0xfc, 0xe1, 0x38, 0x7b, 0x53, 0xfe, 0x6b, 0x92, 0x9e, 0xfa, 0x1b, 0xe4, 0x3b, 0xf2, 0x5d, 0xb9, 0x59, 0xbe, 0x2f, 0x93, 0xe5, 0x16, 0x61, 0x39, 0xf6, 0x2e, 0x66, 0xef, 0xea, 0x2b, 0x7f, 0x51, 0x96, 0x8c, 0x1d, 0x1a, 0xad, 0x89, 0x7d, 0x5c, 0x4e, 0x0b, 0x76, 0xb3, 0xc5, 0xbd, 0x6c, 0x71, 0x77, 0xaf, 0xbe, 0x8d, 0x57, 0x7f, 0xaf, 0x57, 0xdf, 0x3a, 0xd8, 0xde, 0x59, 0x7a, 0xc4, 0xbe, 0x3e, 0x65, 0x5f, 0xd7, 0x63, 0xdc, 0xa2, 0xd8, 0x79, 0xd6, 0xb7, 0xe7, 0x5b, 0xd7, 0x5e, 0x10, 0x6c, 0xee, 0x8c, 0x24, 0x18,\n\t0x44, 0x7f, 0xf5, 0xef, 0x8c, 0xef, 0xb2, 0x6f, 0xcb, 0xed, 0xc7, 0xec, 0xfa, 0x99, 0xc1, 0xc1, 0xce, 0x8a, 0x9e, 0x11, 0x1c, 0x65, 0x5b, 0x9b, 0x3b, 0x13, 0x9b, 0x39, 0x13, 0x1f, 0x71, 0x26, 0x26, 0x3a, 0x0b, 0xeb, 0xcc, 0x9f, 0x45, 0x8d, 0x2b, 0x9c, 0xfd, 0xfa, 0xca, 0x5f, 0xac, 0x5e, 0xc8, 0xc1, 0x6e, 0x8d, 0x7a, 0x1d, 0x5d, 0xc6, 0x2b, 0xac, 0xf1, 0x0a, 0xe5, 0xbf, 0x9b, 0x18, 0xd2, 0x3d, 0xde, 0xfc, 0x3b, 0x9b, 0xc9, 0xb3, 0x99, 0x15, 0x9e, 0x91, 0xf7, 0x8c, 0xc2, 0x26, 0x36, 0x53, 0xfe, 0xb7, 0xd8, 0x38, 0x9b, 0x59, 0xf6, 0x36, 0x9b, 0x29, 0xff, 0xe6, 0xd3, 0x2b, 0x6c, 0x66, 0xf1, 0x3f, 0x68, 0x33, 0xab, 0xd9, 0xcc, 0xea, 0xca, 0x5f, 0xdc, 0x2d, 0xac, 0xb8, 0xe2, 0xa1, 0xd1, 0xc3, 0x4c, 0xaf, 0x4e, 0x6d, 0x0c, 0xda, 0xda, 0x31, 0xb6, 0xf6, 0x90, 0x2d, 0x15,\n\t0x62, 0xe7, 0x94, 0x3f, 0x8f, 0xa5, 0x32, 0x1a, 0x43, 0xb6, 0xd2, 0x65, 0x0b, 0xaf, 0xda, 0x42, 0x5f, 0x75, 0xec, 0xb7, 0x32, 0xd6, 0x1f, 0xf6, 0x6a, 0x43, 0x5e, 0x6d, 0x28, 0x18, 0xe5, 0x99, 0x4f, 0x3a, 0xcb, 0xb3, 0x9d, 0xe5, 0xd9, 0xc1, 0xe8, 0xbf, 0xfb, 0x4b, 0xc0, 0xd3, 0x2b, 0xbf, 0x97, 0xd5, 0xe9, 0xb9, 0xeb, 0x82, 0x53, 0x6d, 0xb5, 0xc1, 0x56, 0x87, 0x6c, 0xf5, 0x5c, 0x8e, 0xf2, 0x63, 0x5b, 0x3d, 0x83, 0x6b, 0xf4, 0xab, 0xca, 0xfb, 0x3d, 0xeb, 0x4b, 0xaa, 0xf2, 0x09, 0x55, 0xf9, 0xaf, 0xf6, 0xe2, 0xeb, 0xb1, 0xe3, 0x79, 0xe5, 0x69, 0x5e, 0xed, 0xf4, 0xa0, 0xd1, 0x88, 0x8d, 0xb6, 0x47, 0x7f, 0x88, 0x9d, 0x1b, 0xcd, 0x30, 0x36, 0xf3, 0x8c, 0xcd, 0x3c, 0x63, 0xf3, 0x3e, 0x95, 0x7b, 0xa7, 0xca, 0xbd, 0x43, 0xe5, 0xde, 0x65, 0x9c, 0x5e, 0x77, 0x86, 0x7f, 0x6c,\n\t0x8f, 0x8f, 0xb7, 0xc7, 0x47, 0xd9, 0xea, 0xba, 0xf2, 0x1e, 0xd7, 0xde, 0x1b, 0x3d, 0xef, 0x6c, 0x77, 0x61, 0xf7, 0xbd, 0xd8, 0x7d, 0x2f, 0x2e, 0x5f, 0x85, 0xc7, 0x1f, 0xc5, 0xe3, 0xcf, 0xe1, 0xf1, 0xb1, 0x78, 0xfc, 0x65, 0x0c, 0xde, 0xcf, 0x78, 0xd6, 0x61, 0xee, 0x2d, 0x98, 0x7b, 0x0b, 0xe6, 0xde, 0x82, 0xb9, 0xb7, 0x60, 0xee, 0x97, 0x31, 0xf7, 0x46, 0xec, 0xbc, 0x10, 0x1f, 0x3f, 0x8d, 0x8b, 0xe7, 0xe2, 0xe2, 0x78, 0x4c, 0x3c, 0xda, 0xd8, 0xbf, 0x8e, 0x47, 0xf7, 0x62, 0xd1, 0xf9, 0x18, 0x74, 0x23, 0xde, 0x1c, 0x8d, 0x37, 0xe7, 0xaa, 0x87, 0xcf, 0x98, 0x25, 0x4f, 0x3a, 0x4b, 0x5b, 0xab, 0x8b, 0x0f, 0xa8, 0x8b, 0xbd, 0xd4, 0xc5, 0x89, 0x0d, 0x7b, 0x05, 0x5b, 0xa8, 0x8d, 0xaf, 0xeb, 0xf1, 0xdf, 0xd0, 0xc3, 0x4f, 0xd4, 0xb7, 0xc7, 0xe9, 0xd9, 0x87, 0xaa, 0x95, 0x76,\n\t0x7d, 0xf9, 0x73, 0x66, 0xcd, 0x22, 0xfd, 0xf4, 0x27, 0x7a, 0xe8, 0x51, 0x7a, 0xe8, 0x0c, 0xfd, 0xe8, 0x2b, 0x7a, 0xcd, 0x55, 0xd6, 0x05, 0xb3, 0xd4, 0xd1, 0x02, 0x73, 0xfe, 0xc4, 0xe0, 0x32, 0x67, 0x70, 0x31, 0xf3, 0x1c, 0x61, 0x9e, 0x23, 0xcc, 0x73, 0x84, 0x79, 0x8e, 0x30, 0xcf, 0x11, 0xe6, 0x39, 0xc2, 0x3c, 0x4b, 0xcc, 0xb3, 0xc4, 0x3c, 0x4b, 0x95, 0x99, 0xf7, 0x71, 0xb5, 0x75, 0x98, 0xef, 0x7f, 0xc9, 0xd7, 0x17, 0x56, 0x7e, 0x8b, 0x7f, 0x44, 0x75, 0x8f, 0x30, 0xb8, 0x11, 0xe6, 0x56, 0x7a, 0x6b, 0x9c, 0x83, 0x7a, 0xa6, 0x35, 0xc2, 0xae, 0x46, 0xd8, 0x55, 0xa9, 0x32, 0x03, 0x6f, 0x73, 0x7b, 0x8f, 0x6c, 0x98, 0x89, 0x9e, 0xef, 0x6c, 0xf6, 0x95, 0x67, 0x1f, 0xe3, 0x19, 0x61, 0x3c, 0x25, 0x86, 0x33, 0xc2, 0x2c, 0x46, 0x98, 0xc5, 0x88, 0xb3, 0x33, 0xc2, 0x2c, 0x46,\n\t0x98, 0xc5, 0x08, 0xb3, 0x28, 0x31, 0x8b, 0x12, 0xb3, 0x28, 0x31, 0x8b, 0x12, 0xb3, 0x28, 0x39, 0x73, 0x23, 0xcc, 0x62, 0x84, 0x59, 0x8c, 0x38, 0x83, 0x23, 0xce, 0xe0, 0x08, 0xb3, 0x18, 0x71, 0x16, 0x47, 0x98, 0xc5, 0x08, 0xb3, 0x18, 0x61, 0x16, 0x23, 0xcc, 0x62, 0x84, 0x59, 0x8c, 0x38, 0xb3, 0x23, 0xcc, 0x62, 0x84, 0x59, 0x8c, 0x30, 0x8b, 0x11, 0x66, 0x31, 0xc2, 0x2c, 0x46, 0x98, 0xc5, 0x08, 0xb3, 0x18, 0x61, 0x16, 0x23, 0xcc, 0x62, 0x84, 0x59, 0x8c, 0x30, 0x8b, 0x11, 0xd4, 0x2f, 0xa1, 0x7e, 0x09, 0xf5, 0x4b, 0x46, 0xa1, 0x64, 0x14, 0x4a, 0xa8, 0x5f, 0x42, 0xfd, 0xd2, 0x86, 0x4e, 0xe0, 0x8c, 0x8f, 0xa0, 0xe6, 0x08, 0x6a, 0x8e, 0xa0, 0xe6, 0x88, 0xb3, 0x3f, 0x82, 0x9a, 0x23, 0x46, 0x60, 0x04, 0x35, 0x47, 0x50, 0x73, 0x04, 0x35, 0x47, 0x50, 0x73, 0xa4, 0xfa, 0x09,\n\t0x84, 0x23, 0xa8, 0x39, 0x82, 0x9a, 0x23, 0x46, 0x67, 0x04, 0x35, 0x47, 0x50, 0x73, 0x04, 0x35, 0x47, 0x50, 0x73, 0x04, 0x35, 0x47, 0x50, 0x73, 0x04, 0x35, 0x47, 0x50, 0x73, 0x04, 0x35, 0x47, 0x50, 0x73, 0xc4, 0xac, 0x1f, 0xd1, 0xa1, 0x47, 0x8c, 0xd6, 0x88, 0x0e, 0x3d, 0xa2, 0x43, 0x8f, 0xe8, 0xd0, 0x23, 0xba, 0x71, 0x29, 0x76, 0x67, 0x30, 0x2a, 0x7a, 0x20, 0xa8, 0x95, 0xad, 0xa3, 0xeb, 0x83, 0x3d, 0x8c, 0xca, 0x9e, 0xc2, 0x19, 0xcd, 0xf9, 0x62, 0xb0, 0x4f, 0xd4, 0x1d, 0x7c, 0x30, 0x1a, 0x0c, 0xc6, 0x46, 0x2f, 0xe9, 0x9d, 0x1d, 0xc1, 0xbe, 0xd1, 0x4a, 0x6b, 0x8e, 0xb8, 0x35, 0x47, 0xdc, 0x9a, 0x23, 0x6e, 0xcd, 0x91, 0x36, 0xf2, 0xad, 0x46, 0xbe, 0xd5, 0xc8, 0xb7, 0x1a, 0xf9, 0x56, 0x23, 0xdf, 0x6a, 0xe4, 0x5b, 0x8d, 0x7c, 0xdc, 0xc8, 0xc7, 0x8d, 0x7c, 0xdc, 0xa8,\n\t0xb7, 0x1a, 0xf5, 0x56, 0xce, 0xbf, 0xd4, 0xc8, 0xb7, 0x71, 0xfe, 0x34, 0xe7, 0x4f, 0x23, 0x40, 0x9a, 0xf3, 0xa7, 0x38, 0x7f, 0xca, 0xbc, 0x4b, 0x71, 0xfe, 0x14, 0xe7, 0x4f, 0x71, 0xfe, 0x34, 0xe7, 0xef, 0x32, 0x0f, 0xd3, 0x9c, 0x3f, 0xcd, 0xf9, 0xbb, 0x38, 0x7f, 0x17, 0xe7, 0xef, 0x52, 0x31, 0xad, 0x2a, 0xa6, 0x55, 0xc5, 0xb4, 0x72, 0xfe, 0x2e, 0xce, 0x9f, 0x56, 0x39, 0x71, 0xce, 0xdf, 0xc5, 0xf9, 0x57, 0x70, 0xfe, 0x15, 0x9c, 0x7f, 0x05, 0xe7, 0x5f, 0x61, 0x0e, 0xa7, 0x37, 0x7a, 0xfc, 0x0f, 0xcc, 0xf1, 0x3b, 0x10, 0x66, 0x7c, 0x34, 0x49, 0x27, 0xb8, 0x41, 0x27, 0xb8, 0x21, 0x76, 0xa4, 0xae, 0x70, 0x94, 0x4c, 0x30, 0x8f, 0x4f, 0xab, 0xfc, 0xe5, 0xe6, 0xd2, 0xca, 0xdf, 0x2a, 0xa7, 0xa3, 0xd6, 0x8a, 0xe7, 0x9f, 0x1d, 0x75, 0xd4, 0x7c, 0x1e, 0x79, 0x2e, 0x90, 0x8b,\n\t0xdc, 0xbf, 0xc4, 0xed, 0xe5, 0x2a, 0xf0, 0x0a, 0xb9, 0x2a, 0x6a, 0x55, 0x9d, 0x71, 0xee, 0xdf, 0xc5, 0xfd, 0xd3, 0xdc, 0xbf, 0xab, 0xe6, 0x26, 0x1d, 0xf5, 0x96, 0x68, 0xa9, 0x6a, 0x8d, 0xd7, 0xfc, 0xc0, 0xfd, 0x69, 0xd1, 0x0a, 0x55, 0x1b, 0xe7, 0xfd, 0x69, 0xde, 0x9f, 0xae, 0xf9, 0x99, 0xde, 0xe8, 0xf8, 0xb9, 0x7c, 0x5a, 0x8f, 0x0c, 0x37, 0xf6, 0xc8, 0x6d, 0xf8, 0x3a, 0xae, 0xab, 0xe4, 0x56, 0x95, 0x1c, 0xaf, 0xba, 0x7b, 0x17, 0x77, 0x4f, 0xab, 0xea, 0xd6, 0x31, 0x1f, 0x8a, 0x1e, 0x18, 0xb3, 0xaf, 0x7c, 0x58, 0xf6, 0x93, 0xfd, 0x65, 0x9c, 0x7c, 0x44, 0x3e, 0x2a, 0x1f, 0x93, 0xf1, 0x72, 0xb0, 0x1c, 0x22, 0x87, 0xca, 0xc7, 0xe5, 0x30, 0xf9, 0x84, 0x1c, 0x2e, 0x47, 0xc8, 0x91, 0x72, 0x94, 0x1c, 0x2d, 0xc7, 0xc8, 0xb1, 0xf2, 0x49, 0x99, 0x20, 0xc7, 0xc9, 0xa7, 0xe4,\n\t0x3c, 0xe9, 0x89, 0xae, 0x1f, 0x93, 0x8d, 0xae, 0xaf, 0x9f, 0x60, 0xa6, 0x1c, 0x27, 0x9f, 0x92, 0xe3, 0xe5, 0x44, 0x39, 0x49, 0x4e, 0x96, 0x89, 0x72, 0x8a, 0x9c, 0xca, 0xe7, 0x4f, 0x93, 0xcf, 0xc8, 0x99, 0xf2, 0x59, 0xf9, 0x9c, 0x9c, 0x25, 0x97, 0x47, 0xdd, 0xf5, 0x57, 0xc8, 0x95, 0xd1, 0x60, 0xfd, 0x55, 0x32, 0x49, 0xbe, 0x29, 0x57, 0xcb, 0x35, 0x72, 0x5d, 0xf4, 0x52, 0xfd, 0xb7, 0xe5, 0xfa, 0xa8, 0x03, 0x3f, 0x3b, 0xf0, 0xb3, 0x03, 0x3f, 0x3b, 0xf0, 0xb3, 0x03, 0x3f, 0x3b, 0xf0, 0xb3, 0x03, 0x3f, 0x3b, 0xf0, 0xb3, 0xa3, 0xfe, 0x2e, 0xd4, 0xbf, 0x5b, 0xee, 0x91, 0x1f, 0xcb, 0x4f, 0xe4, 0x5e, 0xb9, 0x2f, 0x8a, 0x5b, 0xd3, 0xc4, 0xad, 0x69, 0xe2, 0x7a, 0x68, 0x5c, 0x0f, 0x8d, 0xeb, 0xa1, 0x71, 0x3d, 0x34, 0x6e, 0x4d, 0x13, 0xb7, 0xa6, 0x89, 0x5b, 0xd3, 0xc4, 0xf5,\n\t0xd3, 0xb8, 0x35, 0x4d, 0x9c, 0x39, 0xc4, 0xad, 0x69, 0xe2, 0xd6, 0x34, 0x71, 0x6b, 0x9a, 0xb8, 0xfe, 0x1a, 0xd7, 0x5f, 0xe3, 0xfa, 0x6b, 0x5c, 0x7f, 0x8d, 0xeb, 0xaf, 0x71, 0xfd, 0x35, 0x6e, 0x4d, 0x13, 0xb7, 0xa6, 0x89, 0x5b, 0xd3, 0xc4, 0xad, 0x69, 0xe2, 0xd6, 0x34, 0x71, 0x6b, 0x9a, 0xb8, 0x35, 0x4d, 0xdc, 0x9a, 0x26, 0x6e, 0x4d, 0x13, 0xb7, 0xa6, 0x49, 0x5b, 0xd3, 0xa4, 0xad, 0x69, 0xd2, 0x3a, 0x4f, 0xab, 0xce, 0xd3, 0xaa, 0xf3, 0xb4, 0xea, 0x3c, 0xad, 0x3a, 0x4f, 0xab, 0xce, 0x13, 0xd7, 0x79, 0xe2, 0x3a, 0x4f, 0x5c, 0xe7, 0x89, 0xeb, 0x3c, 0x71, 0x9d, 0xa7, 0x55, 0xe7, 0x69, 0xd5, 0x79, 0x5a, 0x75, 0x9e, 0x56, 0x9d, 0xa7, 0x55, 0xe7, 0x69, 0xd5, 0x79, 0x5a, 0x75, 0x9e, 0x56, 0x9d, 0xa7, 0x55, 0xe7, 0x69, 0xd5, 0x79, 0x5a, 0x75, 0x9e, 0x56, 0x9d, 0xa7, 0x55,\n\t0xe7, 0x69, 0xd5, 0x79, 0x5a, 0x75, 0x9e, 0x56, 0x9d, 0xa7, 0x55, 0xe7, 0x69, 0xd5, 0x79, 0x5a, 0x75, 0x9e, 0x56, 0x9d, 0xa7, 0x55, 0xe7, 0x69, 0xd5, 0x79, 0x5a, 0x2b, 0x9f, 0xef, 0x1a, 0x45, 0x4b, 0xf5, 0xff, 0xa5, 0xd6, 0x22, 0x4b, 0xad, 0x45, 0x96, 0xe2, 0xc0, 0x52, 0x6b, 0x91, 0xa5, 0xd6, 0x22, 0x4b, 0x75, 0xa5, 0x36, 0x5d, 0xa9, 0x4d, 0x57, 0x6a, 0xd3, 0x95, 0xda, 0x74, 0xa5, 0x36, 0x5d, 0xa9, 0x4d, 0x57, 0x6a, 0xb3, 0x16, 0x49, 0x5b, 0x8b, 0xa4, 0xad, 0x45, 0xd2, 0xd6, 0x22, 0x69, 0x6b, 0x91, 0xb4, 0xb5, 0x48, 0xda, 0x5a, 0x24, 0x65, 0x2d, 0x92, 0xb2, 0x16, 0x49, 0x59, 0x8b, 0xa4, 0x70, 0x24, 0xc5, 0x12, 0x52, 0xd6, 0x22, 0x29, 0x6b, 0x91, 0x94, 0xb5, 0x48, 0xca, 0x5a, 0x24, 0x65, 0x2d, 0x92, 0xb2, 0x16, 0x49, 0x59, 0x8b, 0xa4, 0xac, 0x45, 0x52, 0xd6, 0x22,\n\t0x29, 0x6b, 0x91, 0x14, 0x9b, 0x48, 0x59, 0x8b, 0xa4, 0xad, 0x45, 0xd2, 0xd6, 0x22, 0x69, 0x6b, 0x91, 0xb4, 0xb5, 0x48, 0xda, 0x5a, 0x24, 0x6d, 0x2d, 0x92, 0xb6, 0x16, 0x49, 0x5b, 0x8b, 0xa4, 0xad, 0x45, 0xd2, 0xd6, 0x22, 0x69, 0x6b, 0x91, 0xb4, 0xb5, 0x48, 0xda, 0x5a, 0x24, 0x6d, 0x2d, 0xd2, 0x65, 0x2d, 0xd2, 0x65, 0x2d, 0xd2, 0x65, 0x2d, 0xd2, 0x85, 0x53, 0x5d, 0xd6, 0x22, 0x5d, 0xd6, 0x22, 0x5d, 0xd6, 0x22, 0x5d, 0xd6, 0x22, 0x5d, 0xd6, 0x22, 0x5d, 0xd6, 0x22, 0x5d, 0xd6, 0x22, 0x5d, 0xd6, 0x22, 0x5d, 0xba, 0x6a, 0xab, 0xae, 0xda, 0xaa, 0xab, 0xb6, 0xea, 0xaa, 0xad, 0xba, 0x6a, 0xab, 0xae, 0xda, 0xaa, 0xab, 0xb6, 0xea, 0xaa, 0xad, 0xba, 0x6a, 0xab, 0xae, 0xda, 0xaa, 0xab, 0xb6, 0xea, 0xaa, 0xad, 0xba, 0x6a, 0xab, 0xae, 0xda, 0xaa, 0xab, 0xb6, 0xea, 0xaa, 0xad,\n\t0xba, 0x6a, 0xab, 0xae, 0xda, 0xaa, 0xab, 0xb6, 0xea, 0xaa, 0xad, 0xba, 0x6a, 0xab, 0xae, 0xda, 0xaa, 0xab, 0xb6, 0xea, 0xaa, 0xad, 0xba, 0x6a, 0xab, 0xae, 0xda, 0xaa, 0xab, 0xb6, 0x5a, 0x8b, 0x74, 0x59, 0x8b, 0x74, 0x59, 0x8b, 0x74, 0x61, 0x65, 0x97, 0xb5, 0x48, 0x97, 0xb5, 0x48, 0x97, 0xb5, 0x48, 0x97, 0xb5, 0x48, 0x17, 0x76, 0x76, 0x59, 0x8b, 0x74, 0x59, 0x8b, 0x74, 0x59, 0x8b, 0xac, 0xc0, 0xd1, 0x15, 0x38, 0xba, 0xc2, 0x5a, 0x64, 0x85, 0xb5, 0xc8, 0x0a, 0x6b, 0x91, 0x15, 0xd6, 0x22, 0x2b, 0xac, 0x45, 0x56, 0x58, 0x8b, 0xac, 0xf8, 0x2f, 0xf3, 0xfd, 0x55, 0xac, 0x6e, 0xb5, 0xf4, 0x45, 0x79, 0xec, 0xce, 0x37, 0x0c, 0xc8, 0xa0, 0xbc, 0x21, 0xeb, 0xa3, 0x3c, 0x87, 0xef, 0x42, 0x88, 0x56, 0x84, 0x68, 0x45, 0x88, 0x56, 0x84, 0x68, 0x45, 0x88, 0xd6, 0x77, 0x71, 0xf8,\n\t0x78, 0x50, 0x5b, 0x7d, 0xa7, 0x87, 0x82, 0x2e, 0x5a, 0x28, 0x5b, 0x4d, 0xac, 0x19, 0x47, 0x96, 0xe0, 0xc8, 0x92, 0x60, 0x4c, 0xf4, 0x46, 0x50, 0x2f, 0x9b, 0xcb, 0xd6, 0xd1, 0x5c, 0x6e, 0x55, 0x0a, 0xfe, 0xc5, 0xfd, 0x9d, 0x64, 0x67, 0xd9, 0x4d, 0xf6, 0xc0, 0x94, 0x3d, 0xe5, 0x83, 0xfc, 0x72, 0x6c, 0xd4, 0x87, 0x2b, 0x03, 0xb8, 0xd2, 0x8c, 0x2b, 0xcd, 0xb8, 0xd2, 0x8c, 0x2b, 0xdd, 0x6c, 0x61, 0x69, 0xf0, 0x89, 0x28, 0x17, 0x1c, 0x2e, 0x47, 0xc8, 0x91, 0x72, 0x94, 0x1c, 0x2d, 0xc7, 0xc8, 0xb1, 0xf2, 0x49, 0x99, 0x20, 0xc7, 0xc9, 0xa7, 0xe4, 0x78, 0x39, 0x41, 0x4e, 0x94, 0x93, 0xe4, 0x64, 0x99, 0x28, 0xa7, 0xc8, 0xa9, 0x72, 0x9a, 0x7c, 0x5a, 0x4e, 0x97, 0xcf, 0x48, 0xf9, 0x1d, 0x39, 0xce, 0x94, 0xcf, 0xca, 0xe7, 0xe4, 0x2c, 0x39, 0x5b, 0x3e, 0x2f, 0x5f, 0xa8, 0xfc,\n\t0x3b, 0x58, 0x37, 0x4e, 0x75, 0xe3, 0x54, 0x37, 0x4e, 0xad, 0xc1, 0xa9, 0x35, 0x38, 0xb5, 0x8a, 0xb9, 0xf4, 0x60, 0xd5, 0x1a, 0xac, 0x5a, 0x83, 0x55, 0xdd, 0x58, 0xd5, 0x89, 0x55, 0xdd, 0x58, 0xd5, 0x8d, 0x55, 0x9d, 0x58, 0xd5, 0x89, 0x55, 0x9d, 0xf8, 0xd4, 0x89, 0x4f, 0xdd, 0xd8, 0xd4, 0x89, 0x45, 0xab, 0x82, 0x6f, 0x7b, 0xcd, 0xeb, 0x1d, 0xff, 0x0d, 0xf2, 0x1d, 0xf9, 0xae, 0xdc, 0x28, 0x37, 0xc9, 0xf7, 0xe4, 0x66, 0xf9, 0xbe, 0x4c, 0x96, 0x5b, 0x3c, 0xe7, 0x56, 0xb9, 0xcd, 0xb6, 0x6e, 0x8f, 0x7a, 0xf1, 0x6b, 0x55, 0xf0, 0x43, 0xf7, 0xef, 0xb0, 0x0e, 0x28, 0x3b, 0xb8, 0xf3, 0xe3, 0xec, 0x2f, 0xc5, 0xb0, 0x4e, 0x0c, 0xeb, 0xc4, 0xb0, 0xd7, 0x63, 0xc9, 0xe8, 0x0d, 0xdc, 0xea, 0xac, 0x39, 0x96, 0x8f, 0x9f, 0x28, 0xa7, 0xc9, 0xe7, 0x79, 0xf9, 0x39, 0x6e, 0x2f, 0x70,\n\t0x7b, 0x89, 0xe8, 0xc9, 0xf8, 0xd5, 0x8d, 0x5b, 0x9d, 0xb8, 0xd5, 0x8d, 0x5b, 0x9d, 0x35, 0xf6, 0xa5, 0xc6, 0xbe, 0xe0, 0x57, 0x07, 0xdb, 0x1a, 0xc0, 0xae, 0x8e, 0x9a, 0x1f, 0x71, 0xf9, 0xe9, 0x7e, 0xfe, 0x53, 0xf9, 0x99, 0xaf, 0x1f, 0x8c, 0x72, 0x35, 0xbf, 0x94, 0x19, 0xf2, 0x2b, 0xf9, 0xb5, 0xcc, 0x94, 0x87, 0xe4, 0x37, 0xf2, 0x5b, 0x79, 0x58, 0x7e, 0xe7, 0x75, 0x1e, 0x91, 0xc7, 0xa2, 0xd7, 0x98, 0xda, 0x32, 0xac, 0xeb, 0x2e, 0x57, 0x08, 0xc6, 0x75, 0xd7, 0x3d, 0x1b, 0xe5, 0xea, 0xe6, 0xca, 0xbc, 0xca, 0x6a, 0x63, 0xa0, 0x6e, 0x91, 0xfb, 0x8b, 0x25, 0x2e, 0xad, 0xb2, 0x44, 0x5e, 0x8f, 0xde, 0xc0, 0xbf, 0x4e, 0xfc, 0xeb, 0xc4, 0xbf, 0xee, 0xd1, 0x7b, 0x47, 0x6f, 0xe0, 0xdf, 0x12, 0xfc, 0x5b, 0x82, 0x7f, 0x4b, 0xf0, 0x6f, 0x09, 0xfe, 0x2d, 0xc1, 0xbf, 0x25, 0xf8,\n\t0xb7, 0x04, 0xff, 0x96, 0xe0, 0xdf, 0x12, 0xfc, 0x5b, 0x82, 0x7f, 0x4b, 0xf0, 0x6f, 0x09, 0xfe, 0x2d, 0xc1, 0xbf, 0x25, 0xf8, 0xb7, 0x04, 0xff, 0x96, 0xe0, 0xdf, 0x12, 0xfc, 0x5b, 0x82, 0x7f, 0x4b, 0xf0, 0x6f, 0x09, 0xfe, 0x2d, 0xc1, 0xbf, 0x25, 0xf8, 0xb7, 0x04, 0xff, 0x96, 0xe0, 0xdf, 0x12, 0xfc, 0x5b, 0x82, 0x7f, 0x4b, 0xf0, 0x6f, 0xc9, 0x98, 0xaf, 0xdb, 0xe6, 0x25, 0xf2, 0x0d, 0xb9, 0x54, 0xae, 0x94, 0x5f, 0xcb, 0x4c, 0x79, 0x48, 0x7e, 0x23, 0xbf, 0x95, 0x87, 0xc5, 0xf1, 0xe2, 0xe5, 0x5c, 0xbc, 0x9c, 0x5b, 0xbf, 0x59, 0xf4, 0x46, 0xbd, 0xba, 0xaf, 0xdf, 0x42, 0xb6, 0x94, 0xad, 0xe4, 0xbd, 0xb2, 0xb5, 0x6c, 0x23, 0xef, 0x93, 0x1d, 0x64, 0x47, 0x31, 0x27, 0xea, 0xcd, 0x89, 0x7a, 0x73, 0xa2, 0x7e, 0x17, 0xd9, 0x55, 0xcc, 0x8d, 0xfa, 0xdd, 0x65, 0x0f, 0xd9, 0x53,\n\t0xde, 0x2f, 0x7b, 0x89, 0x73, 0x50, 0xff, 0x01, 0xd9, 0x47, 0x3e, 0x28, 0x63, 0xe5, 0x00, 0x99, 0x80, 0xa1, 0xc7, 0xc9, 0xa7, 0xe4, 0x78, 0x39, 0x51, 0x4e, 0x92, 0x93, 0x65, 0xa2, 0x9c, 0x22, 0x57, 0x5a, 0x67, 0x5d, 0x25, 0x93, 0xe4, 0x9b, 0x72, 0xb5, 0x5c, 0x23, 0xd7, 0x45, 0x7d, 0xd8, 0xdb, 0x87, 0xab, 0x03, 0xb8, 0x3a, 0x80, 0xab, 0x03, 0xb8, 0x3a, 0x80, 0xab, 0x03, 0xb8, 0x3a, 0x80, 0xab, 0xcd, 0xb8, 0xda, 0x8c, 0xab, 0xcd, 0xb8, 0xda, 0x8c, 0xab, 0xcd, 0xb8, 0xda, 0x8c, 0xab, 0xcd, 0xb8, 0xda, 0x8c, 0xab, 0xcd, 0xb8, 0xda, 0x8c, 0xab, 0xcd, 0xb8, 0xda, 0x8c, 0xab, 0xab, 0x70, 0xb5, 0x19, 0x57, 0x9b, 0x71, 0xb5, 0x19, 0x57, 0x9b, 0x71, 0xb5, 0x19, 0x57, 0x9b, 0x71, 0xb5, 0x19, 0x57, 0x9b, 0x71, 0xb5, 0x19, 0x57, 0x9b, 0x71, 0xb5, 0x19, 0x57, 0x9b, 0x71, 0xb5,\n\t0x19, 0x57, 0x9b, 0x71, 0xb5, 0x19, 0x57, 0x9b, 0x71, 0xb5, 0x19, 0x57, 0x9b, 0x71, 0xb5, 0x1b, 0x57, 0xbb, 0x71, 0xb5, 0xbb, 0x3e, 0x5b, 0xf9, 0xc4, 0xaf, 0x5c, 0x7d, 0x5e, 0x7a, 0xa5, 0x20, 0xeb, 0xa4, 0x4f, 0xfa, 0x65, 0x40, 0x06, 0xe5, 0x0d, 0x59, 0x2f, 0x43, 0x52, 0x94, 0x61, 0x29, 0xc9, 0x88, 0xbc, 0x59, 0xf9, 0xb7, 0xb9, 0x6e, 0x7c, 0xeb, 0xc6, 0xb7, 0x6e, 0x7c, 0xeb, 0xc6, 0xb7, 0x6e, 0x7c, 0xeb, 0xc6, 0xb7, 0x35, 0xf8, 0xb6, 0x06, 0xdf, 0xd6, 0xe0, 0xdb, 0x1a, 0x7c, 0x5b, 0x85, 0x6f, 0x11, 0xbe, 0xad, 0xc1, 0xb7, 0x35, 0xf8, 0xb6, 0x06, 0xdf, 0xd6, 0xe0, 0xdb, 0x1a, 0x7c, 0x7b, 0x13, 0xdf, 0xd6, 0xe0, 0xdb, 0x1a, 0x7c, 0x5b, 0x83, 0x6f, 0x6b, 0xac, 0x3a, 0x6b, 0xf1, 0xad, 0x1b, 0xdf, 0xba, 0xf1, 0xad, 0x1b, 0xdf, 0xba, 0xf1, 0xad, 0x1b, 0xdf, 0xba, 0xf1,\n\t0xad, 0x1b, 0xdf, 0xba, 0xf1, 0xad, 0x1b, 0xdf, 0xba, 0xf1, 0xad, 0x1b, 0xdf, 0xba, 0xf1, 0xad, 0x1b, 0xdf, 0xba, 0xf1, 0xad, 0x13, 0xdf, 0x3a, 0xf1, 0xad, 0x13, 0xdf, 0x3a, 0xf1, 0xad, 0x13, 0xdf, 0x3a, 0xf1, 0xad, 0x13, 0xdf, 0x3a, 0xf1, 0xad, 0x13, 0xdf, 0x3a, 0xf1, 0xad, 0x13, 0xdf, 0x3a, 0xf1, 0xad, 0x13, 0x73, 0x3a, 0x31, 0xa7, 0x13, 0x73, 0x3a, 0x31, 0xa7, 0x13, 0x73, 0x3a, 0x31, 0xa7, 0x13, 0x73, 0x3a, 0x31, 0xa7, 0x13, 0x73, 0x3a, 0x31, 0xa7, 0x13, 0x73, 0x3a, 0x1b, 0xee, 0x8d, 0xde, 0x68, 0xb8, 0x4f, 0xa6, 0xcb, 0x4f, 0xe5, 0x67, 0xf2, 0x73, 0xb9, 0x5f, 0x1e, 0x90, 0x5f, 0xc8, 0x83, 0xf2, 0x4b, 0x99, 0x21, 0xbf, 0x12, 0x75, 0xde, 0xa0, 0xce, 0x1b, 0xd4, 0x79, 0x83, 0x3a, 0x6f, 0x50, 0xe7, 0x0d, 0xea, 0xbc, 0x41, 0x9d, 0x37, 0x98, 0xd7, 0x0d, 0x8f, 0xca,\n\t0x2c, 0xf9, 0xbd, 0xfc, 0x41, 0x1e, 0x93, 0xc7, 0xe5, 0x8f, 0xf2, 0xaf, 0xf2, 0x27, 0x79, 0x42, 0xfe, 0x2c, 0x4f, 0xca, 0x53, 0xf2, 0xb4, 0x3c, 0x23, 0x7f, 0x91, 0xd9, 0x32, 0x47, 0xfe, 0x6a, 0xff, 0x9e, 0x95, 0xb9, 0xf2, 0x37, 0x79, 0x4e, 0xe6, 0xc9, 0x7c, 0x79, 0x5e, 0x5e, 0x90, 0x66, 0x59, 0x28, 0x2d, 0xf2, 0xa2, 0xbc, 0x24, 0x8b, 0x64, 0xb1, 0xc4, 0xa5, 0x55, 0x96, 0x48, 0x9b, 0xbc, 0x2c, 0xed, 0xd2, 0x11, 0xf5, 0x34, 0x2c, 0x93, 0xce, 0xa8, 0xb7, 0xe1, 0x55, 0x59, 0x2e, 0xaf, 0xc9, 0xeb, 0xb2, 0x42, 0x56, 0xca, 0x2a, 0x63, 0xbc, 0x5a, 0xd6, 0x78, 0x5c, 0xb7, 0x24, 0x25, 0x25, 0x3d, 0x92, 0x91, 0xac, 0x84, 0x92, 0x93, 0xbc, 0xf4, 0x45, 0x1d, 0xb8, 0xd9, 0x81, 0x9b, 0x1d, 0xb8, 0xd9, 0x81, 0x9b, 0x1d, 0xb8, 0xd9, 0x81, 0x9b, 0x9d, 0x8d, 0x3d, 0xd1, 0x1b, 0x8d,\n\t0x19, 0xc9, 0x4a, 0x28, 0x39, 0x19, 0xf2, 0xfd, 0xa2, 0x0c, 0x4b, 0x49, 0x46, 0xf4, 0xe7, 0x19, 0xd6, 0xc9, 0xe7, 0x54, 0xae, 0x34, 0x7c, 0x38, 0x3a, 0x05, 0xe9, 0x4e, 0x41, 0xba, 0x53, 0xac, 0x9e, 0xc6, 0x5a, 0x3d, 0x8d, 0xb5, 0x7a, 0x1a, 0x6b, 0xf5, 0x34, 0xd6, 0xea, 0x69, 0xac, 0xd5, 0xd3, 0x58, 0xab, 0xa7, 0xf1, 0x56, 0x4f, 0xe3, 0xad, 0x9e, 0xc6, 0x57, 0xae, 0x4c, 0x7c, 0xdc, 0xf7, 0x0e, 0x93, 0x4f, 0x44, 0x09, 0x44, 0x4c, 0x20, 0x62, 0x02, 0x11, 0x13, 0x88, 0x98, 0x40, 0xc4, 0x04, 0x22, 0x26, 0x10, 0x31, 0x81, 0x88, 0x09, 0x44, 0x4c, 0x20, 0x62, 0x02, 0x11, 0x13, 0x88, 0x98, 0x40, 0xc4, 0x04, 0x22, 0x26, 0x10, 0x31, 0x81, 0x88, 0x09, 0x44, 0x4c, 0x20, 0x62, 0x02, 0x11, 0x13, 0x88, 0x98, 0x40, 0xc4, 0x04, 0x22, 0x26, 0x10, 0x31, 0x81, 0x88, 0x09, 0x44, 0x4c,\n\t0x20, 0x62, 0x02, 0x11, 0x13, 0x95, 0x2b, 0x22, 0x67, 0xbb, 0xfd, 0xbc, 0x7c, 0x41, 0xbe, 0x18, 0x9d, 0x6a, 0x05, 0x77, 0x48, 0xe5, 0x2a, 0xc9, 0xd7, 0xac, 0x1a, 0xcb, 0x57, 0x4a, 0x2e, 0x71, 0xfb, 0x0d, 0xb9, 0x54, 0x2e, 0xb3, 0x8f, 0x97, 0xcb, 0x15, 0x72, 0xa5, 0xaf, 0x27, 0xd9, 0xff, 0x6f, 0xba, 0xbd, 0xda, 0xe3, 0xaf, 0x91, 0x6b, 0xe5, 0x5b, 0x72, 0x5d, 0x74, 0x3f, 0x1a, 0x26, 0xd0, 0x30, 0x87, 0x86, 0x39, 0x34, 0xcc, 0xa1, 0x61, 0x0e, 0x0d, 0x73, 0x68, 0x98, 0x43, 0xc3, 0x1c, 0x1a, 0xe6, 0xd0, 0x30, 0x87, 0x86, 0x39, 0x34, 0x9c, 0x81, 0x86, 0x33, 0xd0, 0x30, 0x87, 0x86, 0x79, 0x34, 0xec, 0xad, 0xfe, 0x55, 0xfe, 0xd3, 0xef, 0x72, 0x95, 0x26, 0x16, 0x3b, 0x5d, 0xce, 0x90, 0x7f, 0xbb, 0x4a, 0xb3, 0x28, 0x76, 0x3e, 0x72, 0x5e, 0x10, 0xd4, 0x58, 0xe1, 0x8d, 0x45,\n\t0xca, 0x19, 0xff, 0xc7, 0xd5, 0x9a, 0xab, 0xa2, 0xb1, 0x56, 0x75, 0xe3, 0xd1, 0xf1, 0x01, 0x64, 0x7c, 0x00, 0x19, 0x73, 0xc8, 0x98, 0x43, 0xc6, 0xa7, 0xad, 0xec, 0x4e, 0xad, 0x5c, 0xcd, 0xb9, 0xcd, 0xcf, 0x7f, 0xe0, 0xeb, 0x69, 0xd1, 0x19, 0x56, 0x77, 0xe3, 0x2b, 0x7f, 0xc9, 0xff, 0x33, 0x5f, 0x3f, 0x18, 0x25, 0x10, 0x32, 0x81, 0x90, 0x09, 0x84, 0x4c, 0x20, 0x64, 0x02, 0x21, 0x13, 0x08, 0x99, 0x40, 0xc8, 0x04, 0x42, 0x26, 0x10, 0x32, 0x81, 0x90, 0x39, 0x84, 0xcc, 0x6d, 0xbc, 0x2a, 0xe4, 0x7c, 0xfe, 0xdd, 0x95, 0xa1, 0x67, 0xa3, 0x04, 0x4a, 0x26, 0x2a, 0x57, 0x88, 0x16, 0xb9, 0xad, 0x5e, 0x25, 0x42, 0xc8, 0x04, 0x42, 0x26, 0xac, 0x12, 0xc7, 0x5a, 0x25, 0x8e, 0x47, 0xc9, 0x19, 0x28, 0xf9, 0x00, 0x42, 0xe6, 0xac, 0x12, 0xc7, 0x56, 0xae, 0x22, 0x4d, 0x8f, 0x4e, 0xd1,\n\t0xb1, 0x4f, 0xf9, 0x3f, 0xae, 0x26, 0xfd, 0xc2, 0xf7, 0x1e, 0x94, 0x19, 0x52, 0xbe, 0xb2, 0xf4, 0x6b, 0xb7, 0xe5, 0xab, 0x4b, 0x0f, 0xb9, 0xfd, 0x8d, 0xfc, 0x56, 0xde, 0xed, 0x4a, 0xd3, 0x1f, 0xfc, 0xec, 0x31, 0x79, 0x5c, 0xfe, 0x28, 0x7f, 0x96, 0x27, 0xe5, 0x29, 0x79, 0x5a, 0x9e, 0x91, 0xb9, 0xb6, 0xff, 0x37, 0x29, 0x5f, 0x95, 0x9a, 0xe7, 0xf6, 0x05, 0x69, 0x8e, 0xc6, 0x5b, 0xfd, 0x8c, 0xb7, 0xfa, 0x19, 0x6f, 0xf5, 0x33, 0xde, 0xea, 0x67, 0x7c, 0xe5, 0x8a, 0x55, 0xab, 0x9f, 0x2d, 0x91, 0x0d, 0x57, 0xae, 0x5e, 0x76, 0xbf, 0x7c, 0xf5, 0xaa, 0xc3, 0xed, 0xab, 0xb2, 0x5c, 0x5e, 0x93, 0xd7, 0xa5, 0x7c, 0x45, 0x6b, 0xa5, 0xdb, 0x2e, 0x71, 0xdc, 0x56, 0x3f, 0x63, 0xad, 0x7e, 0xc6, 0x5a, 0xfd, 0x8c, 0xb5, 0xfa, 0x19, 0x6b, 0xf5, 0x33, 0xd6, 0xea, 0x67, 0xac, 0xd5, 0xcf,\n\t0x58, 0xab, 0x9f, 0xb1, 0x68, 0x91, 0x40, 0x8b, 0x04, 0x5a, 0x24, 0xd0, 0x22, 0x81, 0x16, 0x09, 0xb4, 0x48, 0xa0, 0x45, 0x02, 0x2d, 0x12, 0x68, 0x91, 0x40, 0x8b, 0x04, 0x5a, 0x24, 0xd0, 0x22, 0x51, 0x5f, 0xfe, 0x57, 0xb1, 0xa2, 0x0c, 0x4b, 0x49, 0x46, 0xe4, 0xcd, 0xe8, 0x5e, 0xab, 0xa8, 0x53, 0x2b, 0x57, 0xd1, 0x62, 0x6e, 0x6b, 0xa4, 0x7c, 0x35, 0xad, 0xd6, 0x6d, 0x9d, 0x8c, 0x8e, 0x0e, 0xb1, 0x8a, 0x3a, 0xc4, 0x2a, 0xea, 0x90, 0x8d, 0x57, 0xd8, 0x36, 0x77, 0x7f, 0x0b, 0xf9, 0x8f, 0xae, 0xb4, 0x59, 0x71, 0xeb, 0xf8, 0x0f, 0xe8, 0xf8, 0x0f, 0xe8, 0xf8, 0x0f, 0x54, 0xae, 0xbc, 0x9d, 0xe8, 0xf6, 0x24, 0x39, 0x59, 0x26, 0xca, 0x29, 0x72, 0xaa, 0x9c, 0x26, 0xa7, 0x4b, 0xf9, 0xca, 0xdc, 0x19, 0xd1, 0x58, 0x2b, 0x9a, 0xb1, 0x56, 0x34, 0x63, 0x2b, 0x57, 0xe9, 0xce, 0x72,\n\t0x5b, 0xbe, 0x52, 0xf7, 0x79, 0xb7, 0xe7, 0xc8, 0xb9, 0x72, 0x9e, 0x94, 0xaf, 0xdc, 0x9d, 0xef, 0xf6, 0x02, 0xb9, 0x50, 0xca, 0x57, 0xf1, 0xbe, 0xea, 0xf6, 0x22, 0xf9, 0x9a, 0x5c, 0x2c, 0x5f, 0x97, 0x4b, 0xe4, 0x1b, 0x72, 0xa9, 0x5c, 0x2b, 0xdf, 0x92, 0xeb, 0x44, 0xcd, 0xa3, 0xcb, 0x03, 0xe8, 0xf2, 0x40, 0xe5, 0xea, 0xdf, 0xcd, 0x6e, 0xbf, 0x2f, 0x93, 0xe5, 0x16, 0x29, 0x5f, 0x0d, 0xbc, 0xdd, 0xed, 0x0f, 0xe4, 0x87, 0xd1, 0x19, 0x1b, 0xaf, 0x0c, 0x4e, 0x71, 0xdf, 0x7c, 0xb0, 0xa2, 0x39, 0xc3, 0x8a, 0xe6, 0x0c, 0x2b, 0x9a, 0x33, 0xac, 0x68, 0xce, 0x40, 0xa0, 0x1c, 0x02, 0xe5, 0x10, 0x28, 0x87, 0x40, 0x39, 0x04, 0xca, 0x21, 0x50, 0x0e, 0x81, 0x72, 0x08, 0x94, 0x43, 0xa0, 0x1c, 0x02, 0xe5, 0x10, 0x28, 0x87, 0x40, 0x39, 0x04, 0xca, 0x21, 0x50, 0x0e, 0x81, 0x72, 0x08,\n\t0x94, 0x43, 0xa0, 0x1c, 0x02, 0xe5, 0x10, 0x28, 0x87, 0x40, 0x39, 0x04, 0xca, 0x21, 0x50, 0x0e, 0x81, 0x72, 0x08, 0x94, 0x43, 0xa0, 0x1c, 0x02, 0xe5, 0x10, 0x28, 0x87, 0x40, 0x39, 0x04, 0xca, 0x21, 0x50, 0x0e, 0x81, 0x72, 0x08, 0x94, 0x43, 0xa0, 0x1c, 0x02, 0xe5, 0x10, 0x28, 0x87, 0x40, 0x39, 0x04, 0xca, 0x21, 0x50, 0x0e, 0x81, 0x72, 0x95, 0xab, 0x99, 0xcf, 0xda, 0xf7, 0xb9, 0xf2, 0x37, 0x79, 0x4e, 0xe6, 0xc9, 0x7c, 0x79, 0x5e, 0x5e, 0x90, 0x66, 0x29, 0x5f, 0xf1, 0x6c, 0x71, 0xfb, 0xa2, 0xbc, 0x24, 0x8b, 0x64, 0xb1, 0xc4, 0xa5, 0x55, 0x96, 0x48, 0x9b, 0xbc, 0x2c, 0xed, 0xd2, 0xe1, 0xb5, 0x97, 0x49, 0xa7, 0xd5, 0xd5, 0xab, 0xb2, 0x5c, 0x5e, 0x93, 0xd7, 0x65, 0x85, 0xac, 0x2c, 0xbf, 0xfb, 0x25, 0x0a, 0xad, 0x96, 0x7f, 0xfc, 0x2f, 0xde, 0x9f, 0x2e, 0x5f, 0x75, 0x45,\n\t0xa0, 0xa7, 0x11, 0xe8, 0x69, 0x04, 0x7a, 0x1a, 0x81, 0x9e, 0x46, 0xa0, 0x07, 0x2a, 0x57, 0x62, 0xfb, 0xa3, 0xb1, 0xe5, 0xab, 0xb1, 0x56, 0x6f, 0x63, 0xad, 0xde, 0xc6, 0x5a, 0xbd, 0x8d, 0x45, 0xa1, 0x19, 0x28, 0x34, 0x03, 0x85, 0x66, 0xa0, 0xd0, 0x0c, 0x14, 0x9a, 0x61, 0xf5, 0x36, 0x3e, 0xd8, 0xaa, 0xb2, 0x26, 0x2b, 0xaf, 0xaf, 0x36, 0xac, 0x65, 0xac, 0x4d, 0x74, 0xd1, 0x97, 0x75, 0xcf, 0x64, 0xc5, 0xff, 0x37, 0xb8, 0x7b, 0xd9, 0xdb, 0x79, 0x7a, 0xd9, 0xed, 0x36, 0x7a, 0x51, 0xd9, 0x81, 0x38, 0x4f, 0xb0, 0x63, 0xd0, 0x18, 0xad, 0x0f, 0xb6, 0x94, 0xed, 0x64, 0xaf, 0xe8, 0x15, 0xaf, 0xf8, 0x8c, 0x57, 0x5b, 0x5e, 0xfe, 0xd7, 0x0a, 0xbd, 0xb4, 0xb7, 0xe6, 0xc2, 0x28, 0xac, 0xf9, 0x6a, 0xb4, 0xbe, 0xe6, 0x96, 0x60, 0x1f, 0xaf, 0xfa, 0x8a, 0x57, 0xcd, 0x7a, 0xd5, 0x55,\n\t0x75, 0xbb, 0x44, 0xeb, 0xbd, 0xea, 0x2b, 0x75, 0x2b, 0xdd, 0x76, 0x45, 0xeb, 0xc7, 0x78, 0xcc, 0x98, 0xeb, 0xe4, 0xdb, 0x32, 0x10, 0xad, 0xaf, 0x3f, 0x24, 0x5a, 0x6f, 0x4b, 0x23, 0xb6, 0x12, 0x2b, 0xff, 0x8b, 0x45, 0xe5, 0xdf, 0x42, 0x6e, 0x7f, 0x97, 0x7f, 0x0b, 0x89, 0xfd, 0x3f, 0xff, 0x5b, 0xc8, 0x0e, 0xd5, 0xb3, 0xd1, 0x1e, 0x9c, 0x17, 0x8c, 0x76, 0x46, 0xba, 0x6d, 0xa5, 0x54, 0xbe, 0x72, 0x68, 0x2b, 0xbd, 0xb6, 0x52, 0x3e, 0x8e, 0xf5, 0x5e, 0xf9, 0x25, 0xfb, 0x5f, 0xf2, 0xea, 0x29, 0xaf, 0x5e, 0xfe, 0x04, 0x99, 0xdd, 0xcb, 0xbf, 0x9d, 0xe6, 0xd5, 0x3f, 0xe0, 0xcc, 0xac, 0x6b, 0xd8, 0x25, 0x68, 0x32, 0xe7, 0xb7, 0xb1, 0xa5, 0x5d, 0x6d, 0xe9, 0x3d, 0xb6, 0xb4, 0xbd, 0x2d, 0x1d, 0xe0, 0x18, 0xb6, 0x6c, 0x28, 0xaf, 0x1c, 0xcf, 0x0a, 0xc6, 0x05, 0x97, 0xd9, 0xca,\n\t0xda, 0xe0, 0x1c, 0xb7, 0xe7, 0xca, 0x79, 0xf2, 0xe5, 0xe0, 0x0b, 0xc1, 0xf9, 0x72, 0x81, 0x7c, 0x45, 0xbe, 0x2a, 0x17, 0xf9, 0xfe, 0xc5, 0xfe, 0xfb, 0xba, 0x5c, 0xe5, 0xfe, 0x75, 0x72, 0xa7, 0xff, 0x4f, 0x09, 0xa6, 0xc4, 0x0e, 0x08, 0xce, 0x8b, 0x1d, 0x18, 0x3c, 0x11, 0x3b, 0x28, 0x78, 0x2c, 0x76, 0x58, 0x70, 0x77, 0xec, 0x13, 0xc1, 0x6d, 0xb1, 0xc3, 0xdd, 0x1e, 0xe1, 0xf6, 0xb8, 0xe0, 0x02, 0xe4, 0x7b, 0x04, 0xf9, 0x7e, 0x85, 0x7c, 0xb7, 0x21, 0xdf, 0xf7, 0x63, 0x67, 0x06, 0x3f, 0x8c, 0x7d, 0x31, 0xf8, 0x79, 0xec, 0x4b, 0x72, 0x41, 0xf0, 0x78, 0xec, 0xc2, 0x60, 0x12, 0xe2, 0xad, 0x47, 0xbc, 0xf5, 0x35, 0x97, 0x07, 0x97, 0xd5, 0x5c, 0x21, 0xdf, 0x92, 0xe9, 0xf2, 0xd3, 0xe0, 0xb2, 0xda, 0x49, 0xc1, 0xc5, 0x75, 0xdb, 0xc8, 0x01, 0xc1, 0xc3, 0x75, 0x07, 0xca, 0xbc,\n\t0xe0, 0x0b, 0x75, 0xfd, 0xc1, 0x79, 0xa3, 0xdf, 0x1f, 0x5c, 0x56, 0x3f, 0x5b, 0xe6, 0xc8, 0x5f, 0x83, 0xcb, 0x1a, 0xb6, 0x94, 0xad, 0xe4, 0xbd, 0xb2, 0xb5, 0x6c, 0x23, 0xdb, 0xca, 0xf6, 0xc1, 0x17, 0x1a, 0x76, 0x90, 0x1d, 0x65, 0x27, 0xd9, 0x59, 0x76, 0x91, 0x5d, 0x65, 0x37, 0xd9, 0x5d, 0xf6, 0x90, 0xbd, 0x64, 0x6f, 0xd9, 0x47, 0xf6, 0x95, 0x0f, 0xcb, 0xfe, 0xf2, 0x11, 0xf9, 0x98, 0xd7, 0x39, 0x40, 0x0e, 0x94, 0x83, 0x64, 0xbc, 0x1c, 0x1a, 0x5c, 0xdc, 0xf0, 0x71, 0x39, 0x4c, 0x3e, 0x21, 0x87, 0xcb, 0x11, 0x72, 0xa4, 0x1c, 0x25, 0x47, 0x07, 0x17, 0x37, 0x1d, 0x1b, 0x3d, 0x1e, 0x34, 0x39, 0xba, 0x75, 0x8e, 0x6e, 0x1d, 0x9e, 0x5b, 0x65, 0x06, 0xef, 0x33, 0x4e, 0xdb, 0xd8, 0x83, 0x6d, 0x6d, 0x6d, 0x6b, 0x5b, 0xdb, 0xca, 0x96, 0x2e, 0xb6, 0x95, 0x1d, 0x1b, 0x7e, 0x10,\n\t0x6c, 0x1d, 0xd4, 0xa9, 0xf9, 0xd5, 0xd6, 0xd1, 0x79, 0xeb, 0xe8, 0xfc, 0x86, 0x77, 0x63, 0x0c, 0x46, 0xc5, 0x4e, 0x33, 0x13, 0x4e, 0x8f, 0x16, 0xf8, 0x6a, 0x51, 0xf0, 0x20, 0x5b, 0xeb, 0x63, 0x6b, 0x7d, 0x6c, 0xad, 0x8f, 0x7d, 0x0d, 0xb2, 0xaf, 0x41, 0xf6, 0x35, 0xc8, 0xbe, 0x06, 0xd9, 0xd7, 0x20, 0xfb, 0x1a, 0x64, 0x5f, 0x83, 0xec, 0x6b, 0x90, 0x7d, 0x0d, 0xb2, 0xaf, 0x41, 0xf6, 0x35, 0xc8, 0xbe, 0x06, 0xd9, 0xd7, 0x20, 0xfb, 0x1a, 0x64, 0x5f, 0x83, 0xec, 0x6b, 0x90, 0x7d, 0x0d, 0xb2, 0xaf, 0x41, 0xf6, 0x35, 0xc8, 0xbe, 0x06, 0xd9, 0xd7, 0x20, 0xfb, 0x1a, 0x64, 0x5f, 0x83, 0xec, 0x6b, 0x90, 0x7d, 0x0d, 0xb2, 0xaf, 0x41, 0xf6, 0x35, 0xc8, 0xbe, 0x06, 0xd9, 0xd7, 0x20, 0xfb, 0x1a, 0x64, 0x5f, 0x83, 0xec, 0x6b, 0x90, 0x31, 0x0d, 0x56, 0x0d, 0x68, 0x88, 0x01, 0xbd,\n\t0xcc, 0x80, 0x32, 0x0c, 0xa8, 0x27, 0x76, 0x60, 0xd4, 0x1c, 0x3b, 0xc8, 0xbc, 0x28, 0xbf, 0x67, 0xe4, 0xa1, 0xd1, 0xab, 0x8e, 0xe7, 0xd5, 0xd8, 0x61, 0x51, 0x32, 0xf6, 0x89, 0x68, 0x20, 0x76, 0xb8, 0xdb, 0x23, 0xdc, 0x1e, 0x69, 0xbe, 0x1c, 0x25, 0x13, 0xa2, 0x96, 0xd8, 0xf1, 0xd1, 0x93, 0x8e, 0x72, 0x8e, 0xa3, 0x7c, 0xca, 0x51, 0xce, 0x8d, 0x9d, 0x19, 0x75, 0x6d, 0x7c, 0x7f, 0xd0, 0x0b, 0xa2, 0x57, 0xd9, 0x4e, 0x0f, 0xc3, 0xe9, 0x61, 0x36, 0x19, 0x66, 0xd3, 0xc3, 0x6c, 0x06, 0x99, 0xcd, 0x20, 0xb3, 0x19, 0x64, 0x36, 0x83, 0xcc, 0x66, 0x90, 0xd9, 0x0c, 0x32, 0x9b, 0x41, 0x66, 0x33, 0xc8, 0x6c, 0x06, 0x99, 0xcd, 0xe0, 0x26, 0xbf, 0xd3, 0x3a, 0xc8, 0x60, 0x06, 0xd9, 0xcb, 0x20, 0x7b, 0x19, 0x64, 0x2f, 0x83, 0xec, 0x65, 0x90, 0xbd, 0x0c, 0xb2, 0x94, 0x3e, 0x96, 0xd2,\n\t0xc7, 0x52, 0xfa, 0x58, 0x4a, 0x1f, 0x4b, 0xe9, 0x63, 0x29, 0x7d, 0x2c, 0xa5, 0x8f, 0xa5, 0xf4, 0xb1, 0x94, 0x3e, 0x96, 0xd2, 0xc7, 0x52, 0xfa, 0x58, 0x4a, 0x9f, 0xde, 0xd3, 0xc7, 0x52, 0xfa, 0x58, 0x4a, 0x1f, 0x4b, 0xe9, 0x63, 0x29, 0x7d, 0x2c, 0xa5, 0x8f, 0xa5, 0xf4, 0xb1, 0x94, 0x3e, 0x96, 0xd2, 0xc7, 0x52, 0xfa, 0x58, 0x4a, 0x1f, 0x4b, 0xe9, 0x63, 0x29, 0x7d, 0x2c, 0xa5, 0x8f, 0xa5, 0xf4, 0xb1, 0x94, 0x3e, 0x96, 0xd2, 0xc7, 0x52, 0xfa, 0x58, 0x4a, 0x1f, 0x3b, 0x18, 0x64, 0x07, 0x83, 0xec, 0x60, 0x90, 0x1d, 0x0c, 0xb2, 0x83, 0x41, 0x76, 0x30, 0xc8, 0x0e, 0x06, 0xd9, 0xc1, 0x20, 0x3b, 0x18, 0x64, 0x07, 0x83, 0xec, 0x60, 0x90, 0x1d, 0x0c, 0xb2, 0x83, 0x41, 0x76, 0x30, 0xc8, 0x0e, 0x06, 0xd9, 0xc1, 0x20, 0x3b, 0x18, 0x64, 0x07, 0x83, 0x9b, 0x74, 0xf8, 0x21, 0x1d,\n\t0x7e, 0x48, 0x87, 0x1f, 0xd2, 0xe1, 0x87, 0x74, 0xf8, 0x21, 0x1d, 0x7e, 0x48, 0x87, 0x1f, 0xd2, 0xe1, 0x5f, 0xd6, 0xe1, 0x5f, 0xd6, 0xe1, 0x33, 0x3a, 0x7c, 0x46, 0x87, 0xcf, 0xe8, 0xf0, 0x19, 0x1d, 0x3e, 0xa3, 0xc3, 0x67, 0x74, 0xf8, 0x8c, 0x0e, 0x9f, 0xd1, 0xe1, 0x33, 0x3a, 0x7c, 0x46, 0x87, 0xef, 0xd1, 0xe1, 0x7b, 0x74, 0xf8, 0x1e, 0x1d, 0xbe, 0x47, 0x87, 0xef, 0xd1, 0xe1, 0x7b, 0x82, 0xf7, 0xe8, 0x1a, 0x7f, 0x33, 0x62, 0xe5, 0xdf, 0x68, 0xee, 0x30, 0x5a, 0xa1, 0x11, 0x4a, 0xa9, 0xf3, 0x92, 0x3a, 0x2f, 0xe9, 0x7a, 0x7b, 0xe8, 0x49, 0xd9, 0x86, 0xfb, 0x83, 0xad, 0x1b, 0x5f, 0x09, 0xb6, 0x34, 0x0b, 0x66, 0x55, 0xde, 0x5f, 0xb5, 0x5c, 0xbd, 0x0b, 0x82, 0xed, 0x82, 0x3b, 0xf5, 0x9e, 0x29, 0xaa, 0xe1, 0xc0, 0xe8, 0x39, 0x15, 0x32, 0xcf, 0xe8, 0x67, 0xbd, 0xd6, 0xc3,\n\t0x46, 0x7f, 0x81, 0x47, 0xcd, 0xf1, 0xa8, 0xe7, 0x8d, 0x7e, 0x8b, 0xd7, 0x6c, 0x8e, 0x5d, 0xa8, 0x0a, 0x7a, 0xbd, 0x76, 0x41, 0xcc, 0x1f, 0x3d, 0x6f, 0xb8, 0xdc, 0xb3, 0x8d, 0xea, 0x1c, 0xa3, 0x3a, 0x47, 0xdf, 0x1b, 0x6e, 0x3c, 0xbd, 0xf2, 0x4e, 0xcc, 0xd7, 0x06, 0x75, 0x7a, 0x72, 0xf9, 0x37, 0xfa, 0x06, 0xcb, 0xef, 0xe0, 0x6a, 0x2f, 0xca, 0x5b, 0x5e, 0x82, 0x0a, 0x6f, 0xff, 0x4e, 0xf9, 0x5f, 0x9a, 0xbb, 0x7d, 0x27, 0x51, 0xfd, 0xb7, 0x95, 0x57, 0x6c, 0x61, 0xad, 0x2d, 0xac, 0xb5, 0x85, 0x3e, 0x8f, 0x48, 0x9a, 0x85, 0xd5, 0x7f, 0xa5, 0xd5, 0xb9, 0x76, 0xd0, 0xb9, 0x76, 0xd3, 0xb9, 0x76, 0xaa, 0xcc, 0xc2, 0xf2, 0x6f, 0xcb, 0xb5, 0xc4, 0xca, 0xbf, 0xb3, 0xbe, 0x85, 0xad, 0x15, 0x2a, 0xdd, 0xf3, 0x2b, 0xc1, 0xa1, 0xc1, 0x0f, 0x82, 0x7d, 0x62, 0x13, 0x82, 0xad, 0xbd,\n\t0x6a, 0xf9, 0xdf, 0xcf, 0x37, 0xf3, 0xf8, 0x31, 0x5e, 0xb5, 0xc7, 0xab, 0x66, 0xbc, 0xea, 0x3a, 0xe7, 0x63, 0xa4, 0x61, 0x55, 0xb0, 0x4f, 0xc3, 0xea, 0x60, 0x1f, 0x5b, 0x68, 0x0d, 0x16, 0x58, 0x65, 0x15, 0xac, 0xb2, 0x0a, 0x56, 0x59, 0x05, 0xab, 0xac, 0x82, 0x55, 0x56, 0xc1, 0x2a, 0xab, 0x60, 0x95, 0xb5, 0xde, 0x2a, 0x6b, 0xbd, 0x55, 0xd6, 0x7a, 0x2b, 0xac, 0x82, 0x15, 0x56, 0xc1, 0x1c, 0x1f, 0x32, 0xc7, 0x87, 0xcc, 0xf1, 0x21, 0x73, 0x7c, 0xc8, 0x1c, 0x1f, 0x32, 0xc7, 0x87, 0xcc, 0xf1, 0x21, 0x73, 0x7c, 0xc8, 0x1c, 0x1f, 0x32, 0xc7, 0x87, 0xcc, 0xf1, 0x21, 0x73, 0x7c, 0xc8, 0x1c, 0x1f, 0x32, 0xc7, 0x87, 0xcc, 0xf1, 0x21, 0x73, 0x7c, 0xc8, 0x1c, 0x1f, 0x32, 0xc7, 0x87, 0xcc, 0xf1, 0x21, 0x73, 0x7c, 0xc8, 0x1c, 0x1f, 0x32, 0xc7, 0x87, 0xcc, 0xf1, 0x21, 0x73, 0x7c,\n\t0xc8, 0x1c, 0x1f, 0x32, 0xc7, 0x87, 0xcc, 0xf1, 0x21, 0x73, 0x7c, 0xc8, 0x1c, 0x1f, 0x32, 0xc7, 0x87, 0xcc, 0xf1, 0x21, 0x73, 0x7c, 0xc8, 0xea, 0x6a, 0xc0, 0x2a, 0xaa, 0x80, 0x73, 0x05, 0xab, 0xa8, 0x82, 0x15, 0xd4, 0x7a, 0xf3, 0x7e, 0x28, 0x28, 0xbf, 0xf7, 0xed, 0xed, 0xd1, 0x88, 0x39, 0xbf, 0xce, 0x48, 0x66, 0x63, 0x47, 0x47, 0x2b, 0x63, 0xc7, 0x4a, 0xf9, 0xef, 0xa2, 0x4f, 0x30, 0x6f, 0x4f, 0xaa, 0xcc, 0xdd, 0xd7, 0xac, 0x6c, 0x0a, 0x56, 0x31, 0x05, 0xab, 0x98, 0xf5, 0x56, 0x2a, 0xeb, 0xad, 0x50, 0xd6, 0x9b, 0xc7, 0xeb, 0xcc, 0xe1, 0x21, 0x73, 0x78, 0xc8, 0x1c, 0x1e, 0x32, 0x87, 0x87, 0xcc, 0xe1, 0x21, 0x73, 0x78, 0xc8, 0x1c, 0x1e, 0x32, 0x87, 0x87, 0xcc, 0xe1, 0x21, 0x73, 0x78, 0xc8, 0x6a, 0x64, 0xc0, 0xfc, 0x1d, 0x32, 0x7f, 0x87, 0xcc, 0xdf, 0x21, 0xf3, 0x77,\n\t0xc8, 0xfc, 0x1d, 0x32, 0x7f, 0x87, 0xcc, 0xdf, 0x21, 0xab, 0x8f, 0x82, 0xd5, 0xc7, 0x7a, 0x2b, 0x8e, 0x02, 0xeb, 0x2f, 0xb0, 0xfe, 0x02, 0xeb, 0x2f, 0xb0, 0xfe, 0x02, 0xeb, 0x2f, 0xb0, 0xfe, 0xf5, 0xac, 0x7f, 0x3d, 0xeb, 0x5f, 0xcf, 0xfa, 0xd7, 0xb3, 0xfe, 0xf5, 0xac, 0xbf, 0xc0, 0xfa, 0x0b, 0xac, 0xbf, 0xc0, 0xfa, 0x0b, 0xac, 0xbf, 0xc0, 0xfa, 0x0b, 0xac, 0xbf, 0xc0, 0xfa, 0x0b, 0xac, 0xbf, 0xc0, 0xfa, 0x0b, 0xac, 0xbf, 0xc0, 0xfa, 0x0b, 0xc8, 0x5a, 0x60, 0xfd, 0x05, 0xd6, 0x5f, 0x60, 0xfd, 0x05, 0xd6, 0x5f, 0x60, 0xfd, 0x05, 0xd6, 0x5f, 0x60, 0xfd, 0x05, 0xd6, 0x5f, 0x60, 0xfd, 0x05, 0xd6, 0x5f, 0x60, 0xfd, 0x05, 0xf3, 0x7a, 0xc8, 0xbc, 0x1e, 0x32, 0xaf, 0x87, 0xcc, 0xeb, 0x21, 0xf3, 0x7a, 0xc8, 0xbc, 0x1e, 0x32, 0xaf, 0x87, 0xcc, 0xeb, 0x21, 0xf3, 0x7a, 0xc8,\n\t0xbc, 0x1e, 0x32, 0xaf, 0x87, 0xcc, 0xeb, 0x21, 0xf3, 0x7a, 0xc8, 0xbc, 0x1e, 0x32, 0xaf, 0x87, 0xcc, 0xeb, 0x21, 0xf3, 0x7a, 0xc8, 0xbc, 0x1e, 0x62, 0xf6, 0x03, 0xcc, 0x7e, 0x80, 0xd9, 0x0f, 0x30, 0xfb, 0x01, 0x66, 0x3f, 0xc0, 0xec, 0x07, 0x98, 0xfd, 0x00, 0x0b, 0x2f, 0xb0, 0xf0, 0x02, 0x0b, 0x2f, 0xb0, 0xf0, 0x02, 0x0b, 0x2f, 0xb0, 0xf0, 0x02, 0x0b, 0x2f, 0xb0, 0xf0, 0x02, 0x0b, 0x2f, 0xb0, 0xf0, 0x02, 0x0b, 0x2f, 0x20, 0x7e, 0x81, 0x85, 0x17, 0x58, 0x78, 0x81, 0x85, 0x17, 0x58, 0x78, 0x81, 0x85, 0x17, 0x58, 0x78, 0x81, 0x85, 0x17, 0x58, 0x78, 0x81, 0x85, 0x17, 0x58, 0x78, 0x81, 0x85, 0x17, 0x58, 0x78, 0x81, 0x85, 0x17, 0x58, 0x78, 0x81, 0x97, 0x94, 0xdf, 0x2b, 0xa9, 0x4f, 0x7f, 0xe9, 0xd3, 0x5f, 0x46, 0xf4, 0x97, 0x11, 0xfd, 0x65, 0x44, 0x7f, 0x19, 0xd1, 0x5f,\n\t0x46, 0xf4, 0x97, 0x11, 0xfd, 0x65, 0x44, 0x5f, 0x59, 0xa7, 0xaf, 0xac, 0xd3, 0x57, 0xd6, 0xe9, 0x2b, 0xeb, 0xf4, 0x95, 0x75, 0xfa, 0xca, 0x3a, 0x7d, 0x65, 0x9d, 0xbe, 0xb2, 0x4e, 0x5f, 0x59, 0xa7, 0xaf, 0xac, 0x6b, 0x7c, 0x3d, 0xea, 0x65, 0x87, 0x05, 0x76, 0x58, 0x60, 0x87, 0x05, 0x76, 0x58, 0x60, 0x87, 0xe5, 0xf7, 0x3f, 0x5a, 0x5f, 0xbe, 0x8e, 0x1f, 0x6c, 0x67, 0x0e, 0x9d, 0x64, 0xde, 0x9d, 0x64, 0x1e, 0x9d, 0x50, 0x5e, 0x35, 0x5b, 0x59, 0x6f, 0xae, 0x5f, 0x24, 0x55, 0x59, 0x79, 0xe6, 0xce, 0x31, 0x13, 0x57, 0xfa, 0x6e, 0xca, 0x4c, 0x4c, 0xe9, 0x15, 0xe5, 0xbf, 0x2f, 0x7c, 0xb5, 0x3a, 0x8b, 0xcb, 0x7d, 0x62, 0x9d, 0xfe, 0xb0, 0x52, 0x7f, 0x58, 0x69, 0xae, 0xfd, 0x21, 0xd8, 0xd2, 0x33, 0xb3, 0x9e, 0xd9, 0xe3, 0x95, 0xf7, 0x8f, 0x1d, 0x1c, 0x6c, 0x1f, 0x3b, 0x32,\n\t0x38, 0x39, 0x76, 0x54, 0xe5, 0x77, 0x74, 0xb7, 0xf2, 0x6a, 0xcd, 0xb6, 0x76, 0xa0, 0xad, 0x1d, 0x62, 0x6b, 0x87, 0x7a, 0xa5, 0x84, 0x57, 0xea, 0xf3, 0x4a, 0x7d, 0x5e, 0x29, 0xef, 0x15, 0x16, 0xe9, 0x77, 0x35, 0xd1, 0x7d, 0x65, 0x3b, 0x45, 0xb3, 0x27, 0xf4, 0xab, 0x3f, 0xd9, 0x7e, 0x87, 0xed, 0x2f, 0xb4, 0xfd, 0x56, 0x8f, 0x4e, 0x78, 0x74, 0xa2, 0xd2, 0x9f, 0xf4, 0x3d, 0xcf, 0x48, 0x57, 0x7a, 0x45, 0xf9, 0x11, 0xcd, 0xb1, 0xf2, 0xfb, 0x20, 0x6c, 0xe3, 0xf9, 0xbf, 0xd7, 0xf3, 0xb2, 0xf6, 0xa4, 0xcd, 0x9e, 0xc4, 0x6d, 0xf5, 0x51, 0x8f, 0xe8, 0xf6, 0x88, 0x15, 0x1e, 0xb1, 0xc2, 0x31, 0x74, 0xd8, 0xf2, 0x12, 0xfd, 0x6e, 0x9d, 0xd7, 0xcb, 0x7a, 0xbd, 0xac, 0xd7, 0x0b, 0xf5, 0xbb, 0x21, 0xc7, 0x12, 0x77, 0x2c, 0x71, 0xbd, 0x6e, 0x48, 0xaf, 0x2b, 0xef, 0xd1, 0x03, 0xc1,\n\t0x66, 0x5e, 0xf1, 0xea, 0x4d, 0xba, 0x70, 0xfa, 0x1f, 0xea, 0xc2, 0xe5, 0xf7, 0x7c, 0xee, 0xfd, 0x0f, 0xbb, 0x5f, 0xf9, 0x37, 0x53, 0x7e, 0xaf, 0x03, 0xfe, 0x41, 0x07, 0x2c, 0xff, 0x1b, 0xf4, 0xd2, 0x6a, 0xef, 0x5e, 0x1c, 0x8c, 0x67, 0x8c, 0x4d, 0x6c, 0xb1, 0x89, 0x2d, 0x36, 0xb1, 0xc5, 0xdd, 0x98, 0x61, 0x13, 0x27, 0x8c, 0x31, 0xc3, 0x26, 0x66, 0xd8, 0xc4, 0x09, 0x63, 0x9b, 0xfa, 0x0e, 0xa3, 0x6b, 0x62, 0x74, 0x4d, 0x8c, 0xae, 0x89, 0xd1, 0x35, 0x31, 0xba, 0x26, 0x46, 0xd7, 0xc4, 0xe8, 0x9a, 0x18, 0x5c, 0x13, 0x83, 0x6b, 0x62, 0x70, 0x4d, 0x0c, 0xae, 0x89, 0xc1, 0x35, 0x31, 0xb8, 0x26, 0x06, 0xd7, 0xc4, 0xe0, 0x9a, 0x18, 0x5c, 0x13, 0x83, 0x6b, 0x62, 0x6d, 0xdf, 0xe4, 0x4b, 0x9b, 0x31, 0xb6, 0x71, 0x8c, 0xed, 0x93, 0x8c, 0xed, 0x18, 0xc6, 0xf6, 0x3d, 0xee, 0xb4,\n\t0x2b, 0x77, 0x3a, 0x89, 0x3b, 0x6d, 0xc5, 0xd0, 0x9a, 0x18, 0x5a, 0x13, 0x43, 0x6b, 0x62, 0x68, 0x4d, 0x0c, 0xad, 0x89, 0xa1, 0x35, 0x31, 0xb4, 0x26, 0x86, 0xd6, 0xc4, 0xd0, 0x9a, 0x18, 0x5a, 0x13, 0x43, 0x6b, 0x62, 0x68, 0x4d, 0x0c, 0xad, 0x89, 0xa1, 0x35, 0x35, 0x7c, 0x2f, 0xd8, 0xbf, 0xe1, 0xce, 0x60, 0x7b, 0x67, 0xe8, 0xe4, 0xca, 0x11, 0x7d, 0x70, 0xd3, 0xbd, 0xb7, 0xd5, 0x33, 0x6d, 0xf5, 0xe3, 0xb6, 0xba, 0xb7, 0xad, 0xee, 0xb9, 0xc9, 0x16, 0x3f, 0xaf, 0xff, 0x9f, 0x17, 0x7c, 0xf9, 0xef, 0x1e, 0xbd, 0x53, 0xe5, 0x37, 0xb1, 0xef, 0xf2, 0x8c, 0x9b, 0x3c, 0xe3, 0x1c, 0xcf, 0xb8, 0xda, 0x7e, 0x1e, 0xb3, 0xc9, 0xb3, 0x7e, 0xd2, 0x70, 0x47, 0xb0, 0xb9, 0x6d, 0xed, 0x66, 0xbd, 0x73, 0x6e, 0xf0, 0xb8, 0x57, 0xf8, 0xc2, 0xdb, 0x5e, 0xe1, 0x28, 0xaf, 0x70, 0xab, 0x57,\n\t0xf8, 0x96, 0x57, 0x38, 0xcf, 0x2b, 0x9c, 0xee, 0x15, 0x3e, 0xbe, 0xc9, 0x2b, 0xfc, 0xd0, 0x51, 0xed, 0xe3, 0x55, 0xc6, 0x78, 0x95, 0x5d, 0x83, 0x2d, 0xcb, 0xbf, 0x7d, 0xfe, 0xb6, 0x57, 0xb8, 0xdc, 0x2b, 0xd4, 0x7b, 0x85, 0x0f, 0x79, 0x85, 0x23, 0xbd, 0xc2, 0xe1, 0x5e, 0xe1, 0x86, 0x4d, 0x5e, 0x61, 0x33, 0xc7, 0x3c, 0xd6, 0x31, 0xbf, 0xd7, 0x2b, 0x1c, 0x5f, 0x39, 0xe6, 0x8f, 0xbc, 0xed, 0x98, 0xbf, 0xe8, 0xd9, 0xc7, 0x78, 0xf6, 0x87, 0x3d, 0x7b, 0xec, 0x26, 0xcf, 0xfc, 0xb2, 0xaa, 0x3b, 0x2f, 0xf8, 0xdc, 0xdb, 0x1e, 0x5d, 0xde, 0xdb, 0x6b, 0x3c, 0xfa, 0x0c, 0x8f, 0xbe, 0xc4, 0xb6, 0x0e, 0xd9, 0xe4, 0x19, 0x77, 0xd8, 0xc6, 0x76, 0xf6, 0xf2, 0xad, 0x63, 0xfd, 0xfc, 0xdb, 0xf6, 0xf4, 0x70, 0xcf, 0xbe, 0xc5, 0xb3, 0xaf, 0xad, 0x9e, 0xad, 0xd3, 0x3c, 0xfb, 0xe0, 0xb7,\n\t0x1d, 0xeb, 0xde, 0x5e, 0x61, 0x67, 0x15, 0xb9, 0xe9, 0x33, 0x77, 0xb3, 0x06, 0xab, 0x3e, 0xaa, 0x32, 0xcf, 0xd6, 0x6d, 0xf8, 0xbb, 0xaa, 0xca, 0x57, 0xcd, 0x1b, 0x1c, 0x62, 0xe3, 0x57, 0xcf, 0x56, 0xbc, 0xe3, 0x97, 0xff, 0xe3, 0xef, 0x30, 0xfa, 0xd6, 0xbb, 0x7d, 0xfe, 0x63, 0xd7, 0x16, 0x6f, 0xe3, 0x48, 0xb7, 0x23, 0xed, 0x5b, 0x46, 0xbd, 0x92, 0x51, 0x97, 0xdf, 0x79, 0x7f, 0xbe, 0xa3, 0x99, 0xed, 0x68, 0xe6, 0x6f, 0x72, 0x0d, 0xb0, 0xfc, 0x3e, 0x61, 0xe5, 0xf7, 0x07, 0x5b, 0xc9, 0x8a, 0xc3, 0x7f, 0xe2, 0x1d, 0x3b, 0x2b, 0xd7, 0xfb, 0x36, 0xbe, 0x4b, 0xe7, 0x3b, 0xbc, 0x43, 0x67, 0xf9, 0x1a, 0xde, 0x7f, 0xd6, 0x3b, 0x43, 0xfe, 0xaf, 0xbe, 0xe6, 0xd2, 0x11, 0xad, 0x41, 0xb6, 0x35, 0xc8, 0x56, 0x40, 0xb6, 0x02, 0xb2, 0x15, 0x90, 0xad, 0x80, 0x6c, 0x05, 0x64, 0x2b,\n\t0x20, 0x5b, 0x61, 0x13, 0x73, 0x5e, 0x89, 0x70, 0x2b, 0x11, 0x6e, 0x25, 0xc2, 0xad, 0x44, 0xb8, 0x95, 0x08, 0xb7, 0x12, 0xe1, 0x56, 0x22, 0xdc, 0x4a, 0x84, 0x5b, 0x89, 0x70, 0x2b, 0x99, 0x73, 0xc8, 0x9c, 0x43, 0xe6, 0x1c, 0x32, 0xe7, 0x90, 0x39, 0x87, 0xcc, 0x39, 0xdc, 0xe8, 0x90, 0x2f, 0x54, 0xfa, 0x69, 0xf9, 0xab, 0xf2, 0x7b, 0xee, 0xff, 0xc5, 0x57, 0xf3, 0x82, 0x6d, 0x99, 0x71, 0x88, 0x12, 0xaf, 0xa0, 0xc4, 0x3c, 0x94, 0x98, 0xaf, 0x4b, 0xff, 0xba, 0x3a, 0xea, 0x95, 0x47, 0x54, 0xad, 0x78, 0x21, 0x4a, 0xac, 0x32, 0x23, 0xba, 0xcd, 0x88, 0x6e, 0x33, 0x22, 0x8b, 0x12, 0x7d, 0xe5, 0xdf, 0x42, 0x43, 0x8a, 0xb9, 0x48, 0x31, 0x17, 0x29, 0xfa, 0x90, 0x62, 0xad, 0x6e, 0x7e, 0x7b, 0xa5, 0x9b, 0xff, 0x4d, 0x37, 0x9f, 0xab, 0x9b, 0xcf, 0xf5, 0x6a, 0x7f, 0xf1, 0x6a, 0xcf,\n\t0x54, 0xb6, 0xf7, 0x9d, 0x7f, 0xe7, 0xfd, 0x82, 0xf2, 0x1c, 0x34, 0xcf, 0x41, 0xf3, 0x1b, 0xdf, 0x2f, 0xe8, 0x8b, 0x51, 0x91, 0x07, 0xfe, 0xfd, 0x7b, 0xee, 0x4c, 0xaa, 0xbc, 0xdb, 0xfc, 0xa0, 0x0a, 0x2d, 0xbf, 0x0b, 0xde, 0x8a, 0x2a, 0x27, 0x5e, 0x2a, 0xbf, 0xff, 0x4d, 0xf5, 0x3d, 0x6f, 0xca, 0xbf, 0x7b, 0x54, 0xe4, 0x7c, 0x79, 0xce, 0x97, 0x57, 0xa5, 0x03, 0x5c, 0x2e, 0xac, 0xbe, 0xcf, 0x4c, 0xbe, 0xf2, 0xbe, 0x32, 0xef, 0xfc, 0x7e, 0x2e, 0x79, 0xbe, 0x96, 0xe7, 0x6b, 0x79, 0xbe, 0x96, 0xe7, 0x6b, 0xf9, 0xff, 0xf2, 0xf7, 0x73, 0x89, 0xa2, 0x62, 0x43, 0x20, 0x31, 0xa9, 0x91, 0x51, 0x52, 0x2b, 0x75, 0x32, 0xda, 0xe8, 0x8d, 0x91, 0x7a, 0x69, 0x90, 0xcd, 0x64, 0x73, 0xd9, 0xe2, 0xbf, 0xf9, 0xfd, 0x4b, 0x3a, 0xac, 0xf3, 0x96, 0xc9, 0x1a, 0xee, 0xd7, 0x2d, 0x49, 0x49,\n\t0x49, 0x8f, 0x64, 0x24, 0x2b, 0xa1, 0xe4, 0x24, 0x1f, 0x0d, 0xbc, 0xd3, 0x7b, 0x67, 0x70, 0xac, 0x7c, 0xa5, 0x26, 0x9a, 0xd5, 0x44, 0xb3, 0x9a, 0x60, 0x3f, 0x7a, 0xca, 0x86, 0x9a, 0x28, 0x57, 0x64, 0xab, 0xaf, 0xfe, 0xe6, 0xab, 0x85, 0xe5, 0xaf, 0xf4, 0xfb, 0xd3, 0x83, 0xd3, 0x99, 0xd1, 0x29, 0x95, 0x67, 0x2d, 0xf4, 0xac, 0xe7, 0x3d, 0xeb, 0xf9, 0x6a, 0xdf, 0x7d, 0xeb, 0x33, 0x33, 0xca, 0x3f, 0x59, 0xe0, 0x27, 0x2f, 0xf8, 0xc9, 0x0b, 0x7e, 0xf2, 0xca, 0x86, 0x77, 0x44, 0xda, 0xd8, 0x9f, 0x17, 0x56, 0x3c, 0xa8, 0xfc, 0xb8, 0x95, 0x1e, 0xb7, 0xd2, 0xe3, 0x56, 0x56, 0x3f, 0x89, 0xa3, 0xfc, 0x19, 0x1b, 0xbd, 0x95, 0xc7, 0x95, 0x3f, 0x91, 0xe4, 0xf9, 0x72, 0xfd, 0x54, 0x1c, 0xf0, 0x80, 0xea, 0x6f, 0x3e, 0x9f, 0x65, 0xdb, 0x67, 0x54, 0x7e, 0xbe, 0x71, 0x1e, 0x54, 0x56,\n\t0x93, 0xe5, 0x4f, 0xf0, 0x58, 0x56, 0xf9, 0xfe, 0xf3, 0x7f, 0xb7, 0xf7, 0x1b, 0x68, 0xd0, 0x56, 0xd9, 0xda, 0x43, 0xb6, 0x36, 0xd3, 0xd6, 0x66, 0x56, 0x7f, 0x37, 0xf8, 0xad, 0x67, 0xbd, 0xfd, 0x27, 0xbd, 0x1b, 0xfe, 0xfe, 0xab, 0xf2, 0x93, 0x39, 0x7e, 0xf2, 0x57, 0x3f, 0xf9, 0x6b, 0xf5, 0x39, 0x2f, 0x6d, 0x3c, 0x92, 0xd7, 0x37, 0x5e, 0x83, 0xa9, 0xa9, 0xee, 0xeb, 0xc2, 0x8d, 0x33, 0x7a, 0x61, 0x65, 0x55, 0xb8, 0xc1, 0xfb, 0x5e, 0xa8, 0x1c, 0x6f, 0xf9, 0x38, 0x26, 0x3a, 0x8e, 0x2f, 0x3b, 0x8e, 0xab, 0x1d, 0xc7, 0x55, 0x95, 0x33, 0x7a, 0x97, 0xaf, 0x6e, 0xf5, 0xd5, 0xcd, 0x1b, 0xaf, 0xeb, 0x94, 0x2d, 0xb1, 0xb5, 0xb2, 0xed, 0xf9, 0xb6, 0x3d, 0xcf, 0xb6, 0xe7, 0x55, 0x3f, 0x81, 0xe4, 0xad, 0xbd, 0x2a, 0x3f, 0x6e, 0x71, 0xf5, 0x13, 0x5c, 0x5e, 0xd8, 0x38, 0x46, 0xf3,\n\t0x2b, 0x7b, 0x52, 0x7e, 0x56, 0xaf, 0x67, 0xad, 0xf3, 0xac, 0x75, 0xd5, 0xb3, 0xf4, 0x16, 0xff, 0xca, 0xfb, 0x38, 0x6f, 0xe3, 0xbd, 0x17, 0x2b, 0x1d, 0xa7, 0xa6, 0xfa, 0xd9, 0x2d, 0x2f, 0x57, 0x9e, 0xf7, 0x80, 0xe7, 0xdd, 0xef, 0x79, 0xf7, 0x57, 0xf7, 0xe3, 0xf9, 0xca, 0x2b, 0x96, 0xf7, 0xfa, 0x28, 0xfb, 0x79, 0x86, 0xfd, 0xbc, 0xd0, 0x7e, 0x7e, 0xb9, 0xb2, 0xc5, 0x57, 0xaa, 0x5b, 0x6c, 0xa9, 0x5c, 0xa3, 0xba, 0xc7, 0x33, 0xef, 0xf6, 0xcc, 0xbb, 0x37, 0x1d, 0xc1, 0xe0, 0x3b, 0x9e, 0x71, 0xaa, 0x67, 0x9c, 0x56, 0x79, 0xc6, 0x0b, 0x7e, 0xf6, 0xd7, 0x32, 0xad, 0x2a, 0xeb, 0xe9, 0xab, 0x3c, 0xfa, 0x2a, 0x8f, 0xd9, 0xd2, 0x63, 0xb6, 0xf6, 0x98, 0x2d, 0x2b, 0x7b, 0xd0, 0xe1, 0x27, 0xaf, 0xf8, 0xc9, 0x2b, 0x1e, 0x1f, 0xaf, 0x9e, 0x89, 0x7f, 0xeb, 0x8b, 0x6f, 0x8d, 0x6a,\n\t0xf9, 0x5f, 0xce, 0xf6, 0xad, 0xec, 0x79, 0x79, 0xe5, 0xfd, 0x62, 0x65, 0x4b, 0x53, 0xab, 0xe7, 0xf0, 0x7b, 0x1b, 0xf7, 0x6d, 0xde, 0xc6, 0x8a, 0x9d, 0xe2, 0x67, 0x93, 0xff, 0xee, 0x67, 0x6f, 0x8d, 0xd9, 0x86, 0xb1, 0x79, 0x7e, 0xe3, 0x08, 0x56, 0xfc, 0xb7, 0xb2, 0xbe, 0xe8, 0xab, 0x1c, 0xf5, 0x7e, 0x9e, 0x7d, 0x94, 0x67, 0x7f, 0xba, 0x52, 0xef, 0xa3, 0xaa, 0xee, 0xfb, 0x56, 0x4d, 0x8e, 0xae, 0xee, 0x61, 0xd9, 0x26, 0x5e, 0xa8, 0xbd, 0x2b, 0x5a, 0x52, 0x7b, 0x4f, 0xf4, 0x6c, 0xed, 0x8f, 0x9d, 0xdd, 0xd1, 0x9b, 0xf4, 0xbe, 0x45, 0xd5, 0x4f, 0xb3, 0x78, 0xc1, 0x4f, 0x16, 0x55, 0x7e, 0xf2, 0xb7, 0xea, 0x15, 0xad, 0xbf, 0xf9, 0xc9, 0x73, 0x7e, 0xf2, 0x94, 0x9f, 0x3c, 0x6b, 0x6b, 0x6f, 0x8d, 0x43, 0xf9, 0x7a, 0x76, 0xbe, 0xfc, 0x17, 0x86, 0x95, 0xad, 0x2d, 0xf2, 0xdd,\n\t0xb9, 0x1b, 0xc7, 0x78, 0x5d, 0xd5, 0xeb, 0xb3, 0x95, 0xd7, 0x79, 0x79, 0x43, 0x55, 0x79, 0x9d, 0x97, 0x3d, 0x6b, 0x81, 0x67, 0x2d, 0xae, 0xbc, 0x4e, 0xe5, 0xf3, 0x63, 0x7c, 0x27, 0x57, 0x79, 0x9d, 0xda, 0xea, 0x79, 0x7a, 0xc9, 0x77, 0x3a, 0x7c, 0xe7, 0xad, 0x67, 0x3f, 0xe7, 0xbb, 0x4f, 0xbf, 0x6d, 0x2f, 0xe6, 0x56, 0x46, 0xa0, 0x60, 0x04, 0xfa, 0x8c, 0x40, 0x9f, 0x47, 0xcd, 0xdd, 0xb0, 0xaf, 0x95, 0xdf, 0xa6, 0xea, 0xab, 0xee, 0x7d, 0x79, 0x14, 0x9e, 0xab, 0xec, 0x51, 0xe1, 0xef, 0x6a, 0xf0, 0xf9, 0x0d, 0x36, 0xb2, 0x71, 0xff, 0xe6, 0x57, 0xb6, 0x7b, 0x97, 0xed, 0xde, 0x13, 0xcd, 0xb7, 0x85, 0x17, 0x2b, 0x7f, 0x59, 0x70, 0x93, 0x2d, 0xdc, 0x68, 0x0b, 0x37, 0x56, 0x7d, 0xac, 0x7c, 0x9e, 0x5a, 0x3c, 0x6a, 0x81, 0x47, 0x3d, 0x5f, 0x79, 0x54, 0xf9, 0xf9, 0x6d, 0x1b,\n\t0xba, 0x84, 0x9f, 0xb4, 0xfb, 0xc9, 0x8b, 0x7e, 0xd2, 0x5a, 0x79, 0xfe, 0x2c, 0xcf, 0x7f, 0xc4, 0xf3, 0x1f, 0xa9, 0xee, 0x4f, 0xc5, 0xe7, 0x3c, 0x6a, 0x8e, 0x47, 0xcd, 0xf6, 0xa8, 0x7f, 0x9b, 0xf7, 0x2f, 0x55, 0x2c, 0xb0, 0xe1, 0x6d, 0x73, 0xf8, 0xb5, 0xea, 0xdf, 0x04, 0xb4, 0x57, 0xcf, 0x5c, 0xf9, 0x2f, 0x1a, 0xdb, 0x2b, 0xdb, 0x5c, 0x52, 0x1d, 0xdd, 0xc5, 0xd5, 0xf1, 0x9c, 0x5f, 0x19, 0xb5, 0x0d, 0x23, 0x31, 0xaf, 0x32, 0xee, 0x35, 0xd5, 0x4f, 0x46, 0x0a, 0x2b, 0xaf, 0xbb, 0xe9, 0xba, 0x68, 0xc3, 0xcc, 0x2d, 0x3f, 0xfb, 0x45, 0xcf, 0x9e, 0x57, 0x79, 0x76, 0xf9, 0x51, 0x2f, 0x7a, 0xd4, 0x8b, 0x1e, 0xf5, 0x62, 0x75, 0x16, 0x57, 0xba, 0x4e, 0xf5, 0xb8, 0x2a, 0xbf, 0x5d, 0xbb, 0x71, 0xfc, 0x3b, 0x37, 0x8e, 0xdb, 0xe8, 0x4d, 0x3b, 0x47, 0xf5, 0x1c, 0xbe, 0x35, 0xc6,\n\t0xe5, 0xfd, 0x59, 0x5e, 0xdd, 0xd3, 0x17, 0x2b, 0xfb, 0xf3, 0x42, 0xa5, 0xd6, 0xcb, 0x5b, 0xba, 0xdb, 0x96, 0xee, 0xb1, 0xa5, 0x7b, 0xaa, 0x8f, 0x59, 0x5c, 0x3d, 0xce, 0xf2, 0xd1, 0xb4, 0x78, 0xf6, 0xd2, 0xca, 0x96, 0xe6, 0x57, 0xce, 0xd8, 0x3d, 0xd1, 0x52, 0xdf, 0x59, 0x5b, 0xd9, 0xd2, 0xc6, 0xb3, 0x55, 0x7d, 0x47, 0xd8, 0xd6, 0xca, 0x5e, 0x95, 0x5f, 0xf1, 0x69, 0xaf, 0xf8, 0xb4, 0x57, 0x7c, 0xda, 0xa3, 0x5e, 0xda, 0x50, 0xfd, 0x1e, 0xf5, 0x82, 0x47, 0x3d, 0xe7, 0x51, 0x0b, 0x37, 0x3e, 0xbf, 0xd2, 0x65, 0x37, 0x79, 0x7e, 0x47, 0x65, 0x4f, 0xdb, 0x36, 0xd6, 0x48, 0xb9, 0xba, 0x56, 0x78, 0xb5, 0x15, 0x5e, 0x6d, 0x45, 0xb5, 0x33, 0x3d, 0x5b, 0xa9, 0xa5, 0xf2, 0x4f, 0x3a, 0x37, 0x5e, 0x15, 0x7e, 0x6b, 0xae, 0x3f, 0x5b, 0xa9, 0xbb, 0xf2, 0x1e, 0x2c, 0xf3, 0x93, 0x65,\n\t0x7e, 0xb2, 0xac, 0xfa, 0x93, 0x72, 0x37, 0x9b, 0x5f, 0xad, 0xdb, 0xbf, 0x54, 0xc6, 0x7b, 0x74, 0xf5, 0xaa, 0xf2, 0x5b, 0xbf, 0x6d, 0xf6, 0x56, 0x75, 0xbf, 0xd5, 0x69, 0xca, 0xf3, 0xff, 0x3e, 0x33, 0x78, 0xaa, 0x19, 0x7c, 0x47, 0x65, 0x7f, 0x96, 0x6d, 0xec, 0xc6, 0xc7, 0x06, 0xcd, 0xd6, 0xcc, 0x2d, 0xd1, 0x55, 0xc1, 0xe2, 0xe8, 0xc9, 0xa0, 0x35, 0x7a, 0x2a, 0x68, 0x8b, 0x7e, 0x13, 0x2c, 0xe5, 0x48, 0x2f, 0x47, 0x1f, 0x0a, 0xda, 0xa3, 0x29, 0xc1, 0xb2, 0xa8, 0x3b, 0xe8, 0x8c, 0xa6, 0x06, 0xaf, 0x46, 0xc7, 0x05, 0xaf, 0x39, 0x53, 0x2b, 0xa2, 0xb3, 0x83, 0xae, 0xe8, 0xb7, 0xc1, 0xaa, 0xe8, 0xf0, 0xa0, 0x3b, 0x3a, 0x39, 0x48, 0xbf, 0xd9, 0x1b, 0xac, 0x8d, 0x3e, 0x13, 0xf4, 0x44, 0xe3, 0x2b, 0x9f, 0xf8, 0x74, 0xb0, 0xce, 0x39, 0x21, 0xba, 0x6e, 0xcc, 0x01, 0xd1, 0x55,\n\t0x63, 0x0e, 0x94, 0x13, 0xe4, 0xc4, 0x28, 0x3e, 0xe6, 0x24, 0x39, 0xd9, 0xfd, 0x89, 0x72, 0x8a, 0xfb, 0xa7, 0xca, 0x69, 0xee, 0x7f, 0x5a, 0x4e, 0x97, 0xcf, 0xc8, 0x19, 0x72, 0xa6, 0x7c, 0x56, 0x3e, 0xe7, 0xe7, 0x67, 0xc9, 0xd9, 0xee, 0x7f, 0x5e, 0xbe, 0xe0, 0xfe, 0x17, 0xe5, 0x4b, 0xd1, 0x55, 0xf5, 0xfb, 0x46, 0xaf, 0xd4, 0xef, 0x2f, 0xe3, 0xa2, 0x57, 0x1a, 0x77, 0x8c, 0x9e, 0x6a, 0xdc, 0x49, 0x76, 0x76, 0x7f, 0x17, 0xd9, 0x55, 0x76, 0xf3, 0xf5, 0xee, 0x6e, 0xf7, 0x90, 0x3d, 0xe5, 0xfd, 0xbe, 0xde, 0x4b, 0xf6, 0x96, 0x0f, 0xc8, 0x3e, 0xbe, 0xf7, 0x41, 0x19, 0x2b, 0x1f, 0xf2, 0xb5, 0xd7, 0x6b, 0xfc, 0xb0, 0xec, 0xa7, 0xf3, 0x3d, 0xe1, 0x8c, 0xfc, 0xd9, 0x19, 0x79, 0x34, 0x78, 0x11, 0xbb, 0x16, 0xa9, 0x96, 0x25, 0xd1, 0xeb, 0xce, 0x4a, 0xd2, 0x59, 0xc9, 0x38, 0x23,\n\t0xad, 0x41, 0x47, 0x94, 0x70, 0x56, 0xda, 0x9d, 0x95, 0x7c, 0xb0, 0xdc, 0x19, 0x79, 0x2d, 0x9a, 0x1c, 0xbc, 0xee, 0x2c, 0xad, 0x8c, 0x56, 0x38, 0x33, 0x2b, 0x9d, 0x99, 0x75, 0xc1, 0x6a, 0x55, 0x9f, 0x70, 0x9f, 0x1b, 0x07, 0xcc, 0x2a, 0xe0, 0xc5, 0x41, 0xda, 0xeb, 0xf4, 0x98, 0x33, 0x19, 0x86, 0x3a, 0x3e, 0xba, 0xce, 0x58, 0x5d, 0x6f, 0xac, 0xae, 0x77, 0xb6, 0x9e, 0x1a, 0x35, 0x33, 0x5a, 0x39, 0xea, 0x77, 0xd1, 0xa2, 0x51, 0x8f, 0xc8, 0xa3, 0xee, 0xff, 0x5e, 0xfe, 0x18, 0xad, 0xac, 0x5b, 0x11, 0xad, 0xad, 0x7b, 0x23, 0x5a, 0xe9, 0x6c, 0x3e, 0x5a, 0xf9, 0xcc, 0xde, 0x13, 0xe4, 0xc4, 0x68, 0xb5, 0xb3, 0xb9, 0xda, 0xd9, 0x7c, 0xd4, 0xd9, 0x7c, 0xd4, 0xd9, 0x5c, 0xed, 0x6c, 0xae, 0x76, 0x36, 0x1f, 0x75, 0x36, 0x1f, 0x75, 0x36, 0x1f, 0x75, 0x36, 0x1f, 0x75, 0x36, 0x1f,\n\t0x75, 0x36, 0x1f, 0x75, 0x36, 0x1f, 0x75, 0x36, 0x57, 0x3b, 0x9b, 0xab, 0x9d, 0xcd, 0x47, 0x9d, 0xcd, 0x47, 0x9d, 0xcd, 0xd5, 0xce, 0xe6, 0x6a, 0x67, 0xf3, 0xd1, 0xfa, 0x4f, 0x47, 0xd9, 0xfa, 0x6b, 0xa3, 0x39, 0xf5, 0x37, 0x46, 0x2d, 0xf5, 0x37, 0x45, 0x7d, 0xf5, 0xdf, 0x73, 0x7b, 0x9b, 0xdb, 0x3b, 0xe4, 0x4e, 0x99, 0xe2, 0xeb, 0xa9, 0xf2, 0xa3, 0xa8, 0xad, 0x7e, 0x01, 0x8f, 0x3f, 0x24, 0xea, 0x6e, 0xf8, 0x82, 0xdb, 0x2f, 0xca, 0x65, 0x72, 0xb9, 0x5c, 0x21, 0x57, 0xca, 0x55, 0x32, 0x49, 0xbe, 0x29, 0x57, 0x47, 0x2b, 0x1b, 0xf7, 0x8f, 0x5e, 0x6f, 0x1c, 0x27, 0x1f, 0x91, 0x8f, 0xca, 0xc7, 0xe4, 0x00, 0x39, 0x50, 0x0e, 0x92, 0xf1, 0x72, 0xb0, 0x1c, 0x22, 0x87, 0xca, 0xc7, 0xe5, 0x30, 0xf9, 0x84, 0x1c, 0x2e, 0x47, 0xc8, 0x91, 0x72, 0x94, 0x1c, 0x2d, 0xc7, 0xc8, 0xb1,\n\t0xf2, 0x49, 0x99, 0x20, 0xc7, 0xc9, 0xa7, 0xe4, 0xf8, 0x28, 0xd1, 0x78, 0x82, 0x9c, 0x28, 0x27, 0xc9, 0xc9, 0x32, 0x51, 0x4e, 0x91, 0x53, 0xe5, 0x34, 0xf9, 0x7a, 0xb4, 0xb6, 0xf1, 0x12, 0xb9, 0x4c, 0x2e, 0x97, 0x2b, 0xe4, 0x4a, 0xb9, 0x4a, 0x26, 0xc9, 0x37, 0xe5, 0x6a, 0xb9, 0x46, 0xae, 0x95, 0x6f, 0xc9, 0x75, 0xf2, 0x6d, 0xb9, 0x5e, 0x6e, 0x90, 0xef, 0xc8, 0x8d, 0xd1, 0xa2, 0xc6, 0x9b, 0xe4, 0x7b, 0xec, 0xf1, 0x66, 0xf9, 0xbe, 0x4c, 0x96, 0x5b, 0xe4, 0x56, 0xb9, 0x4d, 0x6e, 0x97, 0x1f, 0xc8, 0x0f, 0xe5, 0x0e, 0xb9, 0x53, 0xa6, 0xc8, 0x54, 0x99, 0x26, 0x77, 0xc9, 0xdd, 0x72, 0x8f, 0xfc, 0x48, 0xee, 0x8d, 0xba, 0x1b, 0xef, 0x93, 0xe9, 0xf2, 0x53, 0xf9, 0x99, 0xfc, 0x5c, 0xee, 0x97, 0x07, 0xe4, 0x17, 0xf2, 0xa0, 0xfc, 0x52, 0x66, 0xc8, 0xaf, 0xe4, 0xd7, 0x32, 0x53,\n\t0x1e, 0x92, 0xdf, 0xc8, 0x6f, 0xe5, 0x61, 0xf9, 0x9d, 0x3c, 0x22, 0x8f, 0xca, 0x2c, 0xf9, 0xbd, 0xda, 0x7c, 0x36, 0x58, 0xa8, 0x6b, 0x2e, 0xd6, 0x0d, 0x96, 0x98, 0xcb, 0x6d, 0x2a, 0x71, 0xa9, 0x39, 0xfc, 0x72, 0xf4, 0x23, 0x15, 0xfd, 0xac, 0x8a, 0x7e, 0x3c, 0x78, 0x25, 0x6a, 0x56, 0xd1, 0x4f, 0x98, 0xe7, 0xdf, 0x57, 0xd5, 0xb3, 0x55, 0xf4, 0x12, 0x73, 0xfd, 0x77, 0x2a, 0xfa, 0x45, 0x15, 0xbd, 0x56, 0x45, 0xb7, 0xaa, 0xe8, 0xc9, 0x2a, 0x7a, 0xb2, 0x79, 0xff, 0x53, 0x55, 0x3d, 0x43, 0x55, 0x4f, 0x56, 0xd5, 0xdf, 0x36, 0xff, 0xd7, 0xa9, 0xec, 0x69, 0x2a, 0x7b, 0xba, 0xf9, 0x3f, 0x10, 0x3b, 0x21, 0x7a, 0x30, 0x76, 0x52, 0xf4, 0xe0, 0xa8, 0x5f, 0x45, 0x8b, 0x55, 0xf6, 0x64, 0x95, 0xdd, 0xaa, 0xb2, 0x5b, 0x55, 0xf6, 0x64, 0x95, 0x3d, 0x59, 0x65, 0x4f, 0xae, 0xbd, 0x39,\n\t0x7a, 0xa8, 0x76, 0x72, 0xf4, 0x90, 0x0a, 0x9f, 0xad, 0xc2, 0x27, 0xd7, 0x0d, 0x45, 0x8b, 0xc7, 0x5c, 0x11, 0x2d, 0xae, 0xdf, 0x56, 0xb6, 0x93, 0x0f, 0xc9, 0xbe, 0xd1, 0xda, 0xfa, 0xfd, 0xdc, 0xee, 0xef, 0x76, 0x9c, 0x7c, 0xc4, 0xfd, 0x8f, 0xca, 0x8d, 0xc1, 0x56, 0xf5, 0xdf, 0x93, 0x29, 0x32, 0x55, 0x16, 0x44, 0x93, 0x55, 0xe5, 0x12, 0x55, 0x39, 0x59, 0x55, 0x4e, 0x56, 0x95, 0x93, 0x55, 0xe5, 0x64, 0x55, 0x39, 0x59, 0x55, 0x4e, 0x56, 0x95, 0x93, 0x55, 0xe5, 0x64, 0x55, 0x39, 0x59, 0x55, 0x4e, 0x56, 0x95, 0x53, 0x55, 0xe5, 0x54, 0x55, 0x39, 0x55, 0x55, 0x4e, 0x55, 0x95, 0x53, 0x55, 0xe5, 0x54, 0x55, 0x39, 0x55, 0x55, 0x4e, 0x55, 0x95, 0x53, 0x55, 0xe5, 0x54, 0x55, 0x39, 0x55, 0x55, 0x4e, 0x55, 0x95, 0x53, 0x55, 0xe5, 0x54, 0x55, 0x39, 0x55, 0x55, 0x4e, 0x55, 0x95,\n\t0x53, 0x55, 0xe5, 0x54, 0x55, 0x39, 0x55, 0x55, 0x4e, 0x55, 0x95, 0x53, 0x55, 0xe5, 0x54, 0x55, 0x39, 0x55, 0x55, 0x4e, 0x55, 0x95, 0x53, 0x55, 0xe5, 0x54, 0x55, 0xf9, 0xb8, 0xaa, 0x7c, 0x5c, 0x55, 0x3e, 0xae, 0x2a, 0x1f, 0x57, 0x95, 0x8f, 0xab, 0xca, 0xc7, 0x55, 0xe5, 0xe3, 0xaa, 0xf2, 0x71, 0x55, 0xf9, 0x78, 0xe3, 0xa7, 0xa3, 0xe6, 0xc6, 0xcf, 0xc8, 0x19, 0x72, 0xa6, 0x7c, 0x56, 0x3e, 0x27, 0x67, 0xc9, 0xd9, 0xf2, 0x79, 0xf9, 0x82, 0x7c, 0x51, 0xbe, 0x24, 0xe7, 0xc8, 0xb9, 0x72, 0x9e, 0x7c, 0x59, 0xce, 0x97, 0x0b, 0xe4, 0x42, 0xf9, 0x8a, 0x7c, 0x55, 0x2e, 0x92, 0xaf, 0xc9, 0xc5, 0xf2, 0xf5, 0x68, 0xb6, 0xaa, 0x9f, 0xad, 0xea, 0x67, 0xab, 0xfa, 0xd9, 0xaa, 0x7e, 0xb6, 0xaa, 0x9f, 0xad, 0xea, 0x67, 0xab, 0xfa, 0xd9, 0xaa, 0x7e, 0xb6, 0xaa, 0x9f, 0xad, 0xea, 0x67,\n\t0xab, 0xfa, 0xd9, 0xaa, 0x7e, 0xb6, 0xaa, 0x9f, 0xad, 0xea, 0x67, 0xab, 0xfa, 0xd9, 0xaa, 0x7e, 0xb6, 0xaa, 0x9f, 0xad, 0xea, 0x5b, 0x55, 0x7d, 0xab, 0xaa, 0x9f, 0xa1, 0xea, 0x67, 0xa8, 0xfa, 0x19, 0xaa, 0x7e, 0x86, 0xaa, 0x9f, 0xa1, 0xea, 0x67, 0xa8, 0xfa, 0x19, 0xaa, 0x7e, 0x86, 0xaa, 0x9f, 0xa1, 0xea, 0x67, 0xa8, 0xfa, 0x19, 0xaa, 0x7e, 0x86, 0xaa, 0x9f, 0xa1, 0xea, 0x67, 0xa8, 0xfa, 0x19, 0xaa, 0x7e, 0x86, 0xaa, 0x9f, 0xa1, 0xea, 0x67, 0xa8, 0xfa, 0x19, 0xaa, 0x7e, 0xba, 0xaa, 0x9f, 0xae, 0xea, 0xa7, 0xab, 0xfa, 0xe9, 0xaa, 0x7e, 0xba, 0xaa, 0x9f, 0xae, 0xea, 0xa7, 0xab, 0xfa, 0xe9, 0xaa, 0x7e, 0xba, 0xaa, 0x9f, 0xae, 0xea, 0xa7, 0xab, 0xfa, 0xe9, 0xaa, 0x7e, 0xba, 0xaa, 0x9f, 0xae, 0xea, 0xa7, 0xab, 0xfa, 0xe9, 0xaa, 0x7e, 0xba, 0xaa, 0x9f, 0xae, 0xea, 0xa7,\n\t0xab, 0xfa, 0xe9, 0xaa, 0x7e, 0xba, 0xaa, 0x9f, 0xae, 0xea, 0xa7, 0xab, 0xfa, 0xe9, 0x8d, 0x4f, 0x47, 0x8b, 0x1b, 0x5f, 0x8f, 0x1e, 0x0c, 0x1a, 0x55, 0x7a, 0xb3, 0xca, 0x2e, 0xe9, 0xd5, 0x1d, 0xaa, 0x7a, 0x4d, 0xa5, 0xa2, 0xbb, 0x19, 0xff, 0x5a, 0x5e, 0xf8, 0x16, 0xb9, 0xdb, 0x2b, 0x9f, 0xfb, 0x78, 0x96, 0xf9, 0x51, 0x30, 0x37, 0xd6, 0x7b, 0xc6, 0x90, 0xb9, 0x91, 0x33, 0x37, 0xfa, 0x75, 0xfb, 0x7c, 0xe5, 0x53, 0x7a, 0x57, 0xba, 0xdf, 0xe5, 0xe7, 0x09, 0xf7, 0xd7, 0x48, 0xaa, 0xf2, 0xc9, 0xbd, 0x59, 0x75, 0xdf, 0xaf, 0xce, 0xf3, 0xea, 0x3b, 0xaf, 0xbe, 0xf3, 0xea, 0x3b, 0xaf, 0xa6, 0xf3, 0xea, 0x32, 0xaf, 0x26, 0xf3, 0x6a, 0x32, 0xaf, 0x26, 0xf3, 0x6a, 0x32, 0xaf, 0x26, 0xf3, 0x6a, 0x32, 0xaf, 0x26, 0xf3, 0x6a, 0x32, 0xaf, 0x26, 0xf3, 0x6a, 0x32, 0xaf, 0x26, 0x0b,\n\t0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0x0b, 0x6a, 0xb2, 0xa0, 0x26, 0xfb, 0xd5, 0x64, 0xbf, 0x9a, 0xec, 0x57, 0x93, 0xfd, 0x6a, 0xb2, 0x5f, 0x4d, 0xf6, 0xab, 0xc9, 0x7e, 0x35, 0xd9, 0xaf, 0x26, 0xfb, 0x8d, 0x4b, 0xbf, 0x71, 0xe9, 0x37, 0x2e, 0xfd, 0xc6, 0xa5, 0xdf, 0xb8, 0xf4, 0x1b, 0x97, 0x7e, 0xe3, 0xd2, 0x6f, 0x5c, 0xfa, 0x8d, 0x4b, 0xbf, 0x71, 0xe9, 0x37, 0x2e, 0xfd, 0xc6, 0xa5, 0xdf, 0xb8, 0xf4, 0x1b, 0x97, 0x7e, 0xe3, 0xd2, 0x6f, 0x5c, 0xfa, 0x8d,\n\t0x4b, 0xbf, 0x71, 0xe9, 0x37, 0x2e, 0xfd, 0xc6, 0xa5, 0xdf, 0xb8, 0xf4, 0x1b, 0x97, 0x7e, 0xe3, 0xd2, 0x6f, 0x5c, 0xfa, 0x83, 0xcd, 0x9c, 0xd9, 0x3e, 0x67, 0x75, 0xd0, 0x78, 0x3c, 0xe9, 0x0c, 0x0e, 0xe1, 0xe1, 0x4b, 0x78, 0xb8, 0x18, 0x0f, 0x17, 0xc7, 0x8e, 0x74, 0xff, 0x28, 0x99, 0x50, 0xfe, 0xb7, 0xc6, 0x8a, 0xc1, 0x55, 0xfe, 0x7a, 0x35, 0xd8, 0xdc, 0x98, 0xbc, 0xe8, 0x19, 0x2f, 0x57, 0x47, 0x30, 0x34, 0x82, 0xcb, 0x8d, 0xe0, 0xe2, 0x7f, 0xef, 0xda, 0xd0, 0xa8, 0x87, 0x8c, 0xd1, 0xc9, 0x46, 0x35, 0x6b, 0x9b, 0xab, 0x2a, 0x36, 0x93, 0x70, 0x7f, 0x8d, 0xa4, 0x24, 0x8d, 0xe5, 0x99, 0xa8, 0xa4, 0x63, 0xbd, 0xa2, 0x63, 0xbd, 0x62, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46,\n\t0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x14, 0xb3, 0x46, 0x31, 0x6b, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0x84, 0x4a,\n\t0x46, 0xa8, 0x64, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0x84, 0x4a, 0x46, 0xa8, 0x64, 0xd6, 0xbc, 0x12, 0xfc, 0x2c, 0xe8, 0x8b, 0x8a, 0x41, 0xbf, 0x79, 0x30, 0xec, 0x1c, 0x8e, 0x44, 0xc3, 0x41, 0x64, 0x5d, 0x5b, 0x13, 0x0d, 0xc7, 0x1a, 0x18, 0x7c, 0x53, 0x34, 0x18, 0xdb, 0x82, 0x71, 0x6e, 0x69, 0x2d, 0xb1, 0x55, 0xd4, 0x15, 0x7b, 0xaf, 0x6c, 0x2d, 0xdb, 0x18, 0xb1, 0x6d, 0xdd, 0x6e, 0x67, 0x46, 0x6d, 0xef, 0xf6, 0x7d, 0xb2, 0x43, 0xb4, 0x3a, 0xb6, 0xa3, 0xfc, 0x8b, 0xfb, 0x3b, 0xc9, 0xce, 0xb2, 0x8b, 0xf5, 0xc4, 0xae, 0x6e, 0x77, 0xf3, 0xf8, 0x3d, 0xdc, 0xdf, 0xd3, 0xfd, 0xf7, 0xcb, 0x5e, 0x46, 0x7b, 0x6f, 0xb7, 0x1f, 0x90, 0x7d, 0x98, 0xf0, 0x07, 0xdd, 0x8e, 0x95, 0x0f, 0x59, 0x09, 0xec, 0xeb, 0x71, 0x1f, 0x76, 0x7f, 0x3f, 0xaf, 0x3d, 0xae, 0xfc, 0x6f, 0x57, 0xd6, 0x63,\n\t0x1b, 0x3e, 0x71, 0xe2, 0xad, 0xeb, 0x2e, 0xbd, 0xa3, 0x9e, 0x89, 0x86, 0x46, 0x3d, 0x67, 0x0e, 0xbe, 0x10, 0x0d, 0x8f, 0x6a, 0x96, 0x56, 0x79, 0xd9, 0xd7, 0x89, 0xa8, 0x6b, 0xd4, 0x1a, 0xe9, 0x96, 0xa4, 0xa4, 0x24, 0x2d, 0x6b, 0xa5, 0x47, 0x32, 0xd1, 0xf2, 0x51, 0x59, 0xb7, 0xa1, 0xe4, 0x24, 0xcf, 0xc4, 0x7a, 0x7d, 0xaf, 0x2f, 0x4a, 0x8d, 0xea, 0x77, 0x3b, 0x10, 0xc5, 0x47, 0x0d, 0xca, 0x1b, 0x7e, 0x56, 0x94, 0xe1, 0x68, 0xf5, 0xa8, 0x92, 0xdb, 0x11, 0x79, 0xd3, 0xf7, 0xa3, 0xa8, 0xab, 0x36, 0x16, 0x65, 0x6b, 0x6b, 0xac, 0xa5, 0x46, 0xb9, 0x5f, 0x2b, 0x75, 0x51, 0xaa, 0x76, 0xb4, 0x8c, 0xf1, 0xbd, 0xc6, 0x68, 0x75, 0x6d, 0x93, 0xef, 0x1d, 0x67, 0x6d, 0xfb, 0x29, 0x39, 0x41, 0x4e, 0xf2, 0xf5, 0xc9, 0xd1, 0x8a, 0xda, 0x89, 0x6e, 0x4f, 0x89, 0x06, 0x6b, 0x4f, 0x75,\n\t0x7b, 0x5a, 0xb4, 0xb6, 0xf6, 0xd3, 0x1e, 0x7f, 0xba, 0x7c, 0x26, 0x5a, 0x53, 0x5b, 0x5e, 0x3f, 0xdf, 0x13, 0x85, 0x1c, 0xbf, 0xb7, 0x2e, 0x8c, 0xda, 0xeb, 0x72, 0xd1, 0xa2, 0xba, 0xc1, 0x28, 0x3f, 0xe6, 0xa0, 0x68, 0x78, 0xcc, 0x39, 0x72, 0xae, 0xe8, 0x2d, 0xf5, 0xdb, 0xcb, 0xc7, 0xe4, 0x97, 0x2c, 0xed, 0x4f, 0xf2, 0x84, 0xfc, 0x45, 0xe6, 0x47, 0x8b, 0xea, 0x17, 0xc9, 0x32, 0xe9, 0x94, 0xb5, 0xd1, 0xa2, 0x86, 0x46, 0x71, 0xbe, 0x1b, 0x8e, 0x91, 0x2f, 0xb9, 0x7f, 0x8d, 0x7c, 0xdb, 0xfd, 0x1b, 0x65, 0x6a, 0xb4, 0xa6, 0x61, 0x41, 0x94, 0x6b, 0xe8, 0x8a, 0x52, 0x0d, 0xe9, 0x68, 0x59, 0xc3, 0x5a, 0xe9, 0x95, 0x82, 0xac, 0x8b, 0x96, 0x35, 0xfe, 0x84, 0x51, 0x3c, 0x1e, 0x0d, 0x35, 0xfe, 0x51, 0x9e, 0x89, 0x86, 0x1b, 0xff, 0x22, 0xb3, 0x65, 0x8e, 0xfc, 0x55, 0xe6, 0x45,\n\t0x5d, 0x8d, 0xf3, 0xe5, 0x79, 0x69, 0x8e, 0xda, 0x1b, 0x17, 0xba, 0x6d, 0x91, 0x97, 0x64, 0x91, 0x2c, 0x96, 0x25, 0x51, 0xbc, 0xb1, 0xcd, 0xed, 0xd2, 0xa8, 0xa3, 0xe9, 0x99, 0x28, 0xdf, 0x34, 0x87, 0x2d, 0xef, 0x1e, 0xab, 0x8b, 0x2e, 0x52, 0x55, 0x6f, 0xc4, 0x36, 0x8f, 0xbe, 0xab, 0xb2, 0x4a, 0x46, 0xff, 0x3e, 0x23, 0x9d, 0x35, 0xd2, 0xb3, 0xaa, 0xff, 0x46, 0xf8, 0x62, 0xf5, 0x77, 0x22, 0x0a, 0xd5, 0x7e, 0xdd, 0x6b, 0x86, 0x5f, 0x3b, 0x6a, 0x7e, 0x74, 0xff, 0xa8, 0x57, 0xa2, 0x01, 0x67, 0x7f, 0x85, 0xb3, 0xdd, 0x5b, 0x7b, 0x74, 0xd4, 0x57, 0x3b, 0x21, 0x2a, 0x3a, 0xb3, 0x59, 0x67, 0x75, 0x8d, 0x33, 0xba, 0xdc, 0x19, 0x6c, 0x2f, 0xff, 0x1d, 0x79, 0xdd, 0x01, 0xd1, 0x39, 0x75, 0x07, 0x46, 0x67, 0x8c, 0xb9, 0x20, 0xea, 0x71, 0xa4, 0x25, 0x47, 0x5a, 0x6a, 0xdc, 0x41,\n\t0xf7, 0xfd, 0x89, 0xdb, 0x15, 0x56, 0x3d, 0x3f, 0x56, 0xf3, 0x17, 0xab, 0xf3, 0x3f, 0xdb, 0x93, 0xdf, 0xd9, 0x93, 0x0e, 0x7b, 0x72, 0xa9, 0x1a, 0xff, 0x89, 0x1a, 0x1f, 0xa7, 0xc6, 0xc7, 0xa9, 0xf1, 0x71, 0xb1, 0x6d, 0xde, 0x7c, 0x40, 0x8d, 0x1f, 0xaa, 0xc6, 0x37, 0x57, 0xe3, 0xe3, 0xd4, 0xf8, 0xb8, 0xd8, 0x0e, 0x6f, 0x4e, 0x8f, 0xed, 0x28, 0xff, 0xe2, 0xfe, 0x4e, 0xb2, 0xb3, 0xec, 0xf2, 0x66, 0x4e, 0x8d, 0x8f, 0x53, 0xe3, 0x27, 0xc4, 0xf6, 0x78, 0xb3, 0xa0, 0xc6, 0xc7, 0xa9, 0xf1, 0x71, 0x6a, 0xfc, 0x08, 0x35, 0x3e, 0x4e, 0x8d, 0x8f, 0x73, 0x94, 0x27, 0xa8, 0xf1, 0x71, 0x6a, 0x7c, 0x9c, 0x1a, 0x6f, 0x8c, 0xed, 0xeb, 0x39, 0x1f, 0x76, 0x7f, 0xbf, 0x37, 0xfb, 0x62, 0xfb, 0x07, 0x3b, 0x3b, 0xfa, 0xb3, 0xd4, 0xf9, 0x04, 0x5e, 0x35, 0x35, 0x76, 0x48, 0x34, 0x2d, 0x76,\n\t0x74, 0x74, 0x46, 0xec, 0x98, 0xe8, 0xe2, 0xd8, 0xb1, 0x6e, 0x3f, 0xe9, 0x76, 0x42, 0x74, 0xbe, 0xee, 0x75, 0xad, 0xee, 0x75, 0xf5, 0xa8, 0xce, 0x68, 0xe2, 0xa8, 0x57, 0x25, 0x11, 0x8d, 0x53, 0xeb, 0xe3, 0xd4, 0xfa, 0xb1, 0x6a, 0x7d, 0x9c, 0x5a, 0x3f, 0x54, 0xad, 0x8f, 0x53, 0xeb, 0xe3, 0xd4, 0xfa, 0x38, 0xb5, 0xfe, 0x51, 0xb5, 0x3e, 0x4e, 0xad, 0x8f, 0x53, 0xeb, 0xe3, 0x46, 0xe5, 0xdf, 0xcc, 0xa9, 0xf5, 0x13, 0x46, 0x15, 0xa2, 0x53, 0x46, 0xad, 0x93, 0xbe, 0xe8, 0x78, 0x35, 0x7f, 0x82, 0x9a, 0x3f, 0x42, 0xcd, 0x1f, 0xa1, 0xe6, 0xc7, 0xa9, 0xf9, 0x71, 0xa3, 0x86, 0xdf, 0x9c, 0xae, 0xe6, 0xc7, 0xa9, 0xf9, 0x71, 0x6a, 0xfe, 0x08, 0x35, 0x3f, 0xae, 0x36, 0x88, 0x62, 0xce, 0xfc, 0xb8, 0xda, 0x9a, 0x37, 0x73, 0xea, 0x7e, 0x9c, 0xba, 0x1f, 0xa7, 0xee, 0x8f, 0x37, 0x12,\n\t0xc7, 0xd7, 0x8e, 0xf1, 0xbd, 0xc6, 0x37, 0xa7, 0xab, 0xfb, 0x71, 0x46, 0xe5, 0x38, 0xf5, 0x3e, 0xae, 0xf6, 0xe4, 0x37, 0xbf, 0xa0, 0xde, 0xc7, 0x19, 0x99, 0x83, 0xd4, 0xfb, 0x38, 0xa3, 0x73, 0x67, 0xed, 0xa7, 0x3d, 0xee, 0x74, 0xf9, 0x4c, 0xb4, 0x4b, 0xed, 0x19, 0x6e, 0x6f, 0x8e, 0x6e, 0xe6, 0x86, 0x37, 0xd6, 0xde, 0x12, 0xdd, 0x5e, 0x7b, 0x5b, 0x74, 0xbb, 0xba, 0xdf, 0xbc, 0x2e, 0xf7, 0x66, 0xce, 0xa8, 0xed, 0x31, 0x26, 0x13, 0x9d, 0x5c, 0x7f, 0x42, 0x54, 0xac, 0xff, 0xe5, 0x9b, 0xeb, 0xd4, 0xf9, 0x49, 0xea, 0xfc, 0x80, 0xfa, 0xbf, 0xb8, 0x3f, 0xff, 0xcd, 0x5c, 0xfd, 0x22, 0x59, 0x26, 0x9d, 0xd1, 0x89, 0xea, 0x7c, 0x4c, 0x43, 0xe3, 0x9b, 0xb9, 0x86, 0x3d, 0x83, 0x9d, 0x1a, 0xde, 0x1f, 0xec, 0xa1, 0xd6, 0xc7, 0x35, 0x7c, 0xc9, 0xd7, 0xd7, 0x44, 0x9f, 0x54, 0xeb,\n\t0xe3, 0xd4, 0xfa, 0xb8, 0x86, 0xa9, 0x6f, 0xbe, 0xaa, 0x02, 0xce, 0x53, 0xeb, 0xc7, 0xab, 0xf5, 0x93, 0xd5, 0xfa, 0xd7, 0xd4, 0xfa, 0x99, 0x6a, 0xfd, 0x02, 0xb5, 0x7e, 0xb2, 0xaa, 0xd8, 0x5f, 0x3d, 0x8f, 0x53, 0xcf, 0x87, 0xaa, 0xe7, 0x43, 0xd5, 0xf3, 0x24, 0xf5, 0x7c, 0x8e, 0x7a, 0x3e, 0x50, 0x3d, 0x1f, 0xa8, 0x9e, 0xc7, 0xa9, 0xe7, 0x71, 0xea, 0xf9, 0x14, 0xf5, 0x3c, 0x4e, 0x3d, 0x9f, 0xd7, 0xf8, 0x72, 0x34, 0x47, 0xf7, 0xbc, 0x5a, 0x35, 0xb5, 0x34, 0xcd, 0x8e, 0x3e, 0xd6, 0x34, 0xe7, 0xcd, 0xf5, 0xc1, 0x0d, 0xba, 0xe7, 0x3a, 0x55, 0xb5, 0x5e, 0xf7, 0x1c, 0x50, 0xe7, 0xc9, 0xd8, 0x7b, 0xa2, 0x35, 0xb1, 0xcd, 0x64, 0x0b, 0xf5, 0xbe, 0xa5, 0x5a, 0xdf, 0x2a, 0x2a, 0xaa, 0xae, 0xa2, 0xea, 0x2a, 0xaa, 0xaa, 0x92, 0xaa, 0x2a, 0xaa, 0xaa, 0xa2, 0x6a, 0x2a, 0xaa, 0xa6,\n\t0xa2, 0x6a, 0x2a, 0xea, 0x98, 0x25, 0xd5, 0x54, 0x54, 0x4d, 0x33, 0x74, 0xcc, 0x92, 0x6a, 0x2a, 0xaa, 0xa6, 0xa2, 0x6a, 0xea, 0x56, 0x4d, 0x45, 0xd5, 0x54, 0x54, 0x4d, 0xbf, 0x53, 0x4d, 0x45, 0xd5, 0x54, 0xd4, 0x2d, 0x4b, 0x2a, 0xa9, 0x18, 0x63, 0x09, 0xb1, 0x4f, 0x44, 0x99, 0x18, 0x4b, 0x88, 0x1d, 0xe1, 0xf6, 0xcc, 0x28, 0xb1, 0xe1, 0x3d, 0x88, 0x47, 0xfd, 0x35, 0x5a, 0x33, 0x6a, 0x9e, 0xcc, 0x67, 0xe7, 0x0b, 0xdc, 0xbe, 0x10, 0x0d, 0xe8, 0x9a, 0x03, 0xa3, 0x5a, 0xa2, 0xd7, 0x46, 0xbd, 0x28, 0xad, 0xee, 0x27, 0xa2, 0xa2, 0x6a, 0x2a, 0xaa, 0xa6, 0xa2, 0x6a, 0x2a, 0xaa, 0xa4, 0xa2, 0x4a, 0x2a, 0xaa, 0xa4, 0xa2, 0x4a, 0x9a, 0xa1, 0x92, 0x8a, 0x2a, 0xa9, 0xa8, 0x92, 0x8a, 0xba, 0x66, 0x49, 0x25, 0xcd, 0x50, 0x49, 0x7f, 0x51, 0x49, 0x7f, 0x51, 0x45, 0x33, 0x54, 0x51,\n\t0xb7, 0x2a, 0xea, 0x56, 0x45, 0xc5, 0x51, 0xeb, 0xa3, 0xc4, 0xa8, 0x21, 0x29, 0xba, 0x5f, 0x92, 0x11, 0x79, 0xd3, 0xcf, 0x22, 0xf3, 0x35, 0x88, 0x4a, 0x2a, 0xa9, 0x5d, 0x07, 0x2d, 0xa9, 0xa4, 0xa2, 0x4a, 0x2a, 0xea, 0x9c, 0x25, 0xd5, 0x53, 0x54, 0x39, 0x45, 0x55, 0x53, 0x54, 0x31, 0x45, 0xdd, 0xb1, 0xa4, 0x3b, 0x96, 0x74, 0xc6, 0x92, 0xca, 0x28, 0xe9, 0x88, 0xa5, 0xfa, 0xd3, 0xa3, 0x35, 0xf5, 0xd3, 0xa2, 0x56, 0xdd, 0xae, 0xa4, 0xdb, 0x95, 0x74, 0xbb, 0x92, 0x2a, 0x28, 0xa9, 0x82, 0x92, 0x6e, 0x57, 0xd2, 0xed, 0x8a, 0x2a, 0xa0, 0xa8, 0xdb, 0x95, 0x54, 0x40, 0x49, 0x05, 0x14, 0x55, 0x40, 0xd1, 0xe8, 0x0f, 0x19, 0xf9, 0x27, 0x8d, 0xfc, 0x93, 0x46, 0xfe, 0x49, 0x23, 0xff, 0xa4, 0x91, 0x7f, 0x52, 0x67, 0x5b, 0xa7, 0xb3, 0xad, 0xd3, 0xd9, 0xd6, 0xe9, 0x6c, 0xeb, 0x74,\n\t0xb6, 0x01, 0x95, 0x50, 0x54, 0x01, 0x25, 0x15, 0x50, 0x54, 0x01, 0x45, 0x15, 0x50, 0x54, 0x01, 0x45, 0x15, 0x50, 0x54, 0x01, 0xdd, 0x2a, 0xa0, 0x68, 0xd4, 0x07, 0x8d, 0x7a, 0x49, 0x47, 0x2b, 0x05, 0xb1, 0xd8, 0x82, 0xa0, 0x36, 0x08, 0x82, 0x15, 0x35, 0x3f, 0x19, 0x75, 0x49, 0xed, 0xde, 0xa3, 0x77, 0x1b, 0xbd, 0x5b, 0x53, 0x76, 0xab, 0xfb, 0x46, 0x5f, 0x3c, 0xe6, 0xb0, 0xfa, 0xef, 0x34, 0xbc, 0xbf, 0xe9, 0xec, 0xa6, 0x6c, 0x53, 0x76, 0xbb, 0x1f, 0xbd, 0x67, 0xc2, 0x66, 0xbb, 0xf9, 0x6f, 0xe2, 0x16, 0xfb, 0x6e, 0xf7, 0xa3, 0xb7, 0xb2, 0xc7, 0x45, 0x5b, 0xdc, 0xbd, 0xc7, 0x45, 0x5b, 0xdd, 0xf7, 0xde, 0xc3, 0xb7, 0xf9, 0xd3, 0xb6, 0x67, 0x6f, 0xf7, 0xa3, 0xed, 0x16, 0x6f, 0x5f, 0xbb, 0x7d, 0xed, 0x4e, 0xbb, 0x6d, 0x7f, 0xf8, 0xce, 0x63, 0xb7, 0xbf, 0xe3, 0x7d, 0xef,\n\t0x7d, 0xdf, 0x61, 0xef, 0xbb, 0xf8, 0x7d, 0xd9, 0xf7, 0x65, 0x77, 0x3a, 0x7a, 0x87, 0xe4, 0x0e, 0xef, 0xdd, 0xe1, 0xe7, 0x3b, 0x24, 0x77, 0xdc, 0x69, 0xc7, 0x09, 0x3b, 0xde, 0xb7, 0xd3, 0xd1, 0xfe, 0xdb, 0x6d, 0xc7, 0x8e, 0x7f, 0xf9, 0x8c, 0xff, 0x1e, 0x28, 0xdf, 0x7f, 0x2b, 0x7b, 0xd7, 0xee, 0x74, 0xdb, 0xde, 0xb5, 0x3b, 0x8f, 0xf5, 0xdf, 0xb9, 0x3b, 0x4f, 0xd9, 0xe5, 0x7d, 0xe5, 0xff, 0xf6, 0xc8, 0xed, 0x32, 0x61, 0x97, 0x4b, 0xfc, 0x77, 0x8b, 0xff, 0xee, 0xdb, 0xed, 0xa1, 0x3d, 0x2e, 0xda, 0x23, 0xb7, 0x67, 0xfd, 0x5e, 0xbb, 0xec, 0xb5, 0xcf, 0x5e, 0x67, 0xfb, 0xef, 0xa2, 0xbd, 0x2e, 0xdd, 0xeb, 0xda, 0xbd, 0x5a, 0xf6, 0xae, 0xdd, 0xfb, 0xcc, 0xbd, 0x5f, 0xfa, 0xc0, 0x1e, 0xe7, 0x8f, 0xfe, 0xc0, 0x49, 0x1f, 0x78, 0xf5, 0x63, 0x7f, 0x3a, 0xf0, 0xe8, 0x83, 0x5a,\n\t0xc7, 0x37, 0x96, 0x33, 0x7e, 0xfe, 0xc1, 0x87, 0x1e, 0x7a, 0xea, 0x11, 0xfb, 0x1d, 0xb3, 0xdb, 0x31, 0x57, 0x1f, 0x73, 0xdf, 0x31, 0x33, 0x26, 0xec, 0x36, 0x61, 0xbf, 0x09, 0x47, 0x9e, 0xfc, 0xc7, 0x93, 0x5f, 0x3a, 0x79, 0xc5, 0xc9, 0xbd, 0x13, 0x6b, 0x26, 0xd6, 0x4f, 0xdc, 0x7c, 0xe2, 0x36, 0x13, 0x77, 0x9c, 0xb8, 0xdb, 0xc4, 0xbd, 0x27, 0xee, 0x3b, 0xf1, 0xa0, 0x89, 0x87, 0x4d, 0x9c, 0xf8, 0xe9, 0xeb, 0x2f, 0x3f, 0xf6, 0xcc, 0xdf, 0xf9, 0x6f, 0xfe, 0x67, 0x17, 0x9f, 0x9d, 0x3e, 0x6f, 0xbf, 0x2f, 0xbf, 0xe7, 0xfc, 0xd1, 0xe7, 0x1f, 0x7c, 0xfe, 0x09, 0xe7, 0xbf, 0x74, 0xc1, 0xe1, 0x17, 0xfc, 0xfa, 0x82, 0x5f, 0x5f, 0xf9, 0xc7, 0x0b, 0xb7, 0xbb, 0xf0, 0xb6, 0x0b, 0xff, 0x7c, 0xe1, 0xfc, 0x0b, 0xdb, 0xbe, 0xf1, 0xf2, 0xa5, 0x35, 0x97, 0x7e, 0xe6, 0xd2, 0x29, 0x97,\n\t0xd5, 0x5f, 0x36, 0xf1, 0xb2, 0x8b, 0x2e, 0x9b, 0x71, 0xf9, 0xb1, 0x57, 0x8c, 0xbd, 0xe2, 0xe0, 0x2b, 0x26, 0x5c, 0x71, 0xee, 0x15, 0x57, 0x5e, 0x71, 0xc7, 0x15, 0x7f, 0xbc, 0x62, 0xf6, 0x15, 0x2d, 0x57, 0xbc, 0x72, 0x45, 0xf1, 0xca, 0x83, 0xaf, 0xbc, 0xe5, 0xca, 0x07, 0xaf, 0xfc, 0xe3, 0x55, 0x57, 0xfe, 0x1f, 0xff, 0xf5, 0xfb, 0xaf, 0xfe, 0x1d, 0xbe, 0xff, 0xce, 0x8f, 0x7c, 0x97, 0xff, 0x82, 0x9a, 0x60, 0x8f, 0x51, 0xcf, 0x8c, 0x7a, 0x35, 0x08, 0x46, 0xbd, 0x3e, 0x6a, 0x45, 0xb0, 0xfb, 0xa8, 0x44, 0xed, 0x98, 0x60, 0xcf, 0xda, 0xc6, 0xda, 0xa6, 0xe0, 0x53, 0xb5, 0x47, 0xd6, 0x9e, 0x11, 0x9c, 0x50, 0xfb, 0xa5, 0xda, 0x2f, 0x05, 0xe7, 0xd6, 0x4e, 0xaa, 0x9d, 0x14, 0x9c, 0x57, 0x7b, 0x6d, 0xed, 0xb5, 0xc1, 0x97, 0x6b, 0xbf, 0x5b, 0xfb, 0xdd, 0xe0, 0xfc, 0xda, 0x9b,\n\t0x6b, 0x6f, 0x0e, 0x2e, 0xa8, 0x9d, 0x5c, 0x7b, 0x7b, 0x70, 0x61, 0xed, 0xd4, 0xda, 0x69, 0xc1, 0xc5, 0xb5, 0x77, 0xd7, 0xde, 0x1d, 0x5c, 0x52, 0xfb, 0xa3, 0xda, 0x1f, 0x05, 0xdf, 0xa8, 0xbd, 0xb7, 0xf6, 0xde, 0xe0, 0xd2, 0xda, 0xe9, 0xb5, 0x3f, 0x0d, 0x2e, 0xab, 0xdb, 0xa6, 0x6e, 0x9b, 0xe0, 0x8a, 0xba, 0x9d, 0xea, 0x76, 0x0d, 0xae, 0xac, 0xdb, 0xbd, 0x6e, 0xcf, 0xe0, 0xea, 0xba, 0xbd, 0xeb, 0xf6, 0x0f, 0xbe, 0x55, 0x77, 0x40, 0xdd, 0x81, 0xc1, 0xcd, 0x75, 0x7f, 0xad, 0x9b, 0x1b, 0x4c, 0xae, 0x9b, 0x57, 0xf7, 0x7c, 0x70, 0x5b, 0xdd, 0xa2, 0xba, 0x25, 0xc1, 0x0f, 0xeb, 0x5e, 0xaf, 0x5b, 0x15, 0x4c, 0xab, 0x4b, 0xd6, 0xa5, 0x82, 0x1f, 0xd7, 0xad, 0xad, 0xcb, 0x05, 0xf7, 0xd6, 0x0d, 0xd4, 0x15, 0x83, 0xfb, 0xeb, 0xa2, 0xd1, 0xa3, 0x83, 0x5f, 0x8d, 0xde, 0x7c, 0xf4,\n\t0xe6, 0xc1, 0x23, 0xa3, 0xf7, 0x18, 0xbd, 0x77, 0xf0, 0xe8, 0xe8, 0xa1, 0xd1, 0x43, 0xc1, 0xe3, 0x63, 0x3e, 0x34, 0xe6, 0x53, 0xc1, 0x1f, 0xc7, 0x9c, 0x30, 0xe6, 0xb3, 0x41, 0x6b, 0x70, 0x60, 0xd0, 0x17, 0x6c, 0x11, 0xf4, 0x07, 0x3b, 0x04, 0x03, 0x3c, 0x7c, 0x7d, 0xb0, 0x4b, 0x30, 0x24, 0x51, 0xf4, 0x50, 0xac, 0x29, 0xd8, 0x4d, 0x3f, 0x9a, 0xa5, 0x1f, 0xcd, 0x8d, 0x6d, 0x13, 0x34, 0xc6, 0xb6, 0x0d, 0xc6, 0xe8, 0x45, 0x51, 0x6c, 0x87, 0x60, 0xcb, 0xd8, 0x8e, 0xb2, 0x4f, 0x74, 0x57, 0x6c, 0xbf, 0x60, 0x1b, 0x44, 0xfa, 0xf5, 0xa8, 0x27, 0x59, 0xd6, 0x33, 0xc1, 0x0e, 0xa3, 0xe6, 0xb8, 0x7d, 0x3e, 0xd8, 0x71, 0xd4, 0xa2, 0x60, 0x97, 0x51, 0xcb, 0xdc, 0xbe, 0x22, 0xaf, 0xbb, 0x9f, 0x0a, 0xc6, 0x8c, 0xea, 0x0b, 0xb6, 0x1a, 0x35, 0x1c, 0x6c, 0x69, 0x4e, 0xdf, 0x5a, 0x5b,\n\t0x17, 0x6c, 0x55, 0x3b, 0x5a, 0x1a, 0x7d, 0xfd, 0x19, 0x2b, 0xfe, 0x30, 0x8a, 0xea, 0x6c, 0x7f, 0xcc, 0x41, 0xc1, 0x9e, 0x63, 0xce, 0x91, 0x73, 0x83, 0x3d, 0xeb, 0xbf, 0x15, 0xec, 0x68, 0x9e, 0x96, 0x74, 0xeb, 0x18, 0x36, 0xaf, 0x33, 0x37, 0xe7, 0x37, 0x74, 0x05, 0x5b, 0xe9, 0xc2, 0xff, 0xda, 0xf8, 0x78, 0xb0, 0x43, 0xe3, 0x1f, 0xe5, 0x5f, 0x83, 0xcd, 0x1a, 0xe7, 0x07, 0x63, 0x1a, 0x9f, 0x97, 0xe6, 0x28, 0xd2, 0x6d, 0xdb, 0xcc, 0xb9, 0xf6, 0x60, 0x3f, 0x47, 0xd5, 0xe8, 0xa8, 0xb6, 0x71, 0x54, 0xf5, 0x8e, 0x6a, 0x27, 0x47, 0xb5, 0x93, 0xa3, 0xfa, 0xb5, 0xa3, 0xda, 0xa9, 0x7a, 0x54, 0xcf, 0x3a, 0xaa, 0x98, 0xa3, 0x69, 0x74, 0x34, 0x8d, 0x8e, 0x66, 0x9a, 0xa3, 0xd9, 0xc2, 0xd1, 0xfc, 0xaa, 0x7a, 0x34, 0xdb, 0x54, 0x8f, 0x66, 0x5b, 0x47, 0xb3, 0x93, 0xa3, 0xd9, 0xd6,\n\t0xd1, 0x6c, 0xeb, 0x68, 0x76, 0x72, 0x24, 0x9b, 0x39, 0x92, 0x46, 0x47, 0x72, 0x9b, 0x23, 0xd9, 0xcc, 0x91, 0x6c, 0xe6, 0x48, 0x1a, 0x2b, 0x47, 0x62, 0x7b, 0x8e, 0x62, 0x57, 0x47, 0xb1, 0xab, 0xa3, 0xd8, 0xd5, 0x51, 0x6c, 0x8b, 0x39, 0xa3, 0x1c, 0x45, 0xad, 0xa3, 0xe8, 0xab, 0x1e, 0xc5, 0x66, 0x8e, 0xe2, 0x09, 0x47, 0xb1, 0x8d, 0xa3, 0xd8, 0xc6, 0x51, 0xd4, 0xdb, 0xf3, 0x97, 0x2b, 0x7b, 0xfe, 0x1d, 0x76, 0x3d, 0xd7, 0x9e, 0xce, 0x64, 0xd5, 0x73, 0xed, 0xe9, 0xc3, 0xf6, 0xf4, 0x69, 0x3c, 0x48, 0xe1, 0x41, 0x0a, 0x0f, 0x52, 0xc6, 0xa0, 0x0f, 0x0f, 0x52, 0x78, 0x90, 0xc2, 0x83, 0x14, 0x1e, 0xa4, 0xf0, 0x20, 0x85, 0x07, 0xb3, 0xf0, 0x20, 0x85, 0x07, 0xb7, 0xe0, 0xc1, 0x2c, 0x3c, 0x48, 0xe1, 0x41, 0x0a, 0x0f, 0x6e, 0xc0, 0x83, 0x14, 0x1e, 0xa4, 0x1c, 0xe5, 0xdd, 0x78,\n\t0x90, 0xc2, 0x83, 0x14, 0xbb, 0x28, 0x60, 0xc2, 0x2c, 0x4c, 0x48, 0xb1, 0x88, 0x05, 0x0c, 0x62, 0x01, 0x73, 0x68, 0x65, 0x0e, 0xad, 0x8c, 0x79, 0xee, 0xa8, 0xb6, 0x68, 0x2d, 0x53, 0x9e, 0xcb, 0x22, 0xb2, 0x2c, 0x22, 0xab, 0xef, 0xa7, 0xf4, 0xfd, 0x94, 0xbe, 0x9f, 0xd2, 0xf7, 0x53, 0xfa, 0x7e, 0x4a, 0xdf, 0x4f, 0xe9, 0xfb, 0x29, 0x7d, 0xff, 0x16, 0x7d, 0x3f, 0xa5, 0xef, 0xa7, 0xf4, 0xfd, 0x94, 0xbe, 0x3f, 0x4b, 0xdf, 0xbf, 0x45, 0xdf, 0xbf, 0x5b, 0xdf, 0xbf, 0x5b, 0xdf, 0xbf, 0x45, 0xdf, 0xbf, 0x41, 0xdf, 0xbf, 0x41, 0xdf, 0x4f, 0xe9, 0xf7, 0x29, 0xfd, 0x3e, 0xa5, 0xdf, 0xa7, 0xf4, 0xfb, 0x1b, 0xf4, 0xfb, 0x94, 0x7e, 0xff, 0xbc, 0x5e, 0x3f, 0x4b, 0xaf, 0x4f, 0xe9, 0xf5, 0x65, 0x4b, 0x9e, 0xa5, 0xd7, 0xa7, 0x18, 0xf2, 0x5c, 0x86, 0x3c, 0x97, 0x21, 0xcf, 0xd5, 0xf7,\n\t0x53, 0xfa, 0x7e, 0x4a, 0xdf, 0x4f, 0xe9, 0xfb, 0xb3, 0xf4, 0xfd, 0x59, 0xfa, 0xfe, 0x2c, 0x86, 0xd0, 0xca, 0x10, 0x5a, 0x19, 0xc2, 0x53, 0x0c, 0xe1, 0x29, 0xf5, 0xd4, 0x87, 0x03, 0xb3, 0x98, 0xf1, 0x5c, 0x36, 0x3c, 0x97, 0x0d, 0xcf, 0x65, 0xc3, 0x73, 0xd9, 0x70, 0x96, 0x25, 0x64, 0x59, 0x42, 0x96, 0x0d, 0x67, 0xf1, 0x61, 0x16, 0x3e, 0xcc, 0xc2, 0x87, 0x59, 0xf8, 0x30, 0x0b, 0x1f, 0x66, 0xe1, 0xc3, 0x2c, 0x75, 0xf7, 0x46, 0xc3, 0x7e, 0xd1, 0x00, 0x46, 0xa4, 0x30, 0x62, 0x16, 0x46, 0xcc, 0xc2, 0x88, 0x14, 0x46, 0xa4, 0x8c, 0xe0, 0x33, 0x18, 0x71, 0x17, 0x46, 0xdc, 0x85, 0x11, 0x77, 0x61, 0xc4, 0x5d, 0x18, 0x71, 0x17, 0x1e, 0xa4, 0xd4, 0x60, 0x1f, 0x1e, 0xa4, 0xf0, 0x20, 0x85, 0x07, 0x29, 0x3c, 0x48, 0xe1, 0x41, 0x0a, 0x0f, 0x6e, 0xc0, 0x83, 0x14, 0x23, 0x28, 0xb0,\n\t0x81, 0x56, 0x23, 0xbd, 0xa4, 0xe9, 0xe9, 0x68, 0x2d, 0xdb, 0x9d, 0x8b, 0x0f, 0xcf, 0xe3, 0xc3, 0xac, 0xe0, 0xbd, 0x6a, 0x76, 0xb3, 0x4a, 0x8d, 0xfe, 0x5b, 0x7d, 0xd6, 0x57, 0xea, 0x72, 0x43, 0x4d, 0xaa, 0xc7, 0x4a, 0xcd, 0xa9, 0xb3, 0xb7, 0xd7, 0x54, 0xa5, 0x9e, 0x36, 0xd4, 0xd0, 0x01, 0xfc, 0xe2, 0x09, 0x6e, 0xf1, 0x3c, 0xb7, 0xb8, 0x94, 0x5b, 0x9c, 0xc5, 0x2d, 0xce, 0xf2, 0xaa, 0xc3, 0x6a, 0xe3, 0x26, 0xf5, 0xd0, 0x53, 0x99, 0xbb, 0x07, 0x5a, 0x21, 0x1d, 0x14, 0x2d, 0xe3, 0x03, 0xe7, 0xf0, 0x81, 0xaf, 0xf3, 0x81, 0x73, 0xf8, 0xc0, 0xd7, 0x39, 0xf5, 0xfd, 0x9c, 0xe0, 0x72, 0x4e, 0x70, 0x25, 0x27, 0xb8, 0x92, 0x13, 0x9c, 0xc5, 0x09, 0xce, 0xe2, 0x03, 0x67, 0xf1, 0x81, 0xe7, 0xf9, 0xc0, 0xf3, 0x7c, 0xa0, 0x85, 0x0f, 0xb4, 0xf0, 0x81, 0xe7, 0x8d, 0xfd, 0x4d, 0xc6,\n\t0xfa, 0x26, 0x63, 0x7c, 0x93, 0x31, 0xee, 0x31, 0xc6, 0x3d, 0xb8, 0x9e, 0xc4, 0xf5, 0xa4, 0xb1, 0xed, 0xb1, 0xc7, 0x2d, 0x3c, 0x7b, 0x22, 0xcf, 0x3e, 0x11, 0x97, 0xcf, 0x2a, 0x3b, 0xb6, 0xf3, 0xf7, 0xb0, 0xf3, 0xf7, 0xb0, 0xf3, 0xf7, 0xb0, 0xf3, 0xf7, 0xb0, 0xf3, 0xf7, 0x30, 0xc6, 0x3e, 0x81, 0xb1, 0x4f, 0x60, 0xec, 0x13, 0x18, 0xfb, 0x04, 0xc6, 0x3e, 0xef, 0xbc, 0xf5, 0x38, 0xa2, 0x5b, 0x83, 0x53, 0xcd, 0xe1, 0x06, 0x73, 0xb8, 0xc1, 0xec, 0xc8, 0x39, 0xba, 0x66, 0xe7, 0x29, 0xed, 0x08, 0xe3, 0x8e, 0xf0, 0x66, 0x33, 0x25, 0xe7, 0x28, 0x2f, 0x71, 0x94, 0x97, 0x38, 0xca, 0x65, 0xce, 0x5d, 0x68, 0x36, 0xac, 0x75, 0xb4, 0x4f, 0x98, 0x09, 0x6b, 0x1d, 0xf1, 0x53, 0x8e, 0xf8, 0x19, 0xd5, 0xbe, 0xd6, 0xd1, 0x5c, 0xa2, 0xba, 0x73, 0x8e, 0xe8, 0x12, 0x47, 0x74, 0x89, 0x23,\n\t0x8a, 0x3b, 0xa2, 0xb8, 0x23, 0xea, 0x76, 0x44, 0xdd, 0xe6, 0x7a, 0x83, 0xa3, 0x8a, 0xab, 0xfe, 0xf2, 0x3a, 0x31, 0x67, 0xbe, 0x37, 0x38, 0xc2, 0x27, 0x54, 0xf4, 0x5a, 0x47, 0xf9, 0x84, 0xa3, 0x7c, 0xc2, 0x51, 0x3e, 0xe5, 0x28, 0x9f, 0x72, 0x94, 0xf3, 0x1c, 0xe5, 0x3c, 0x47, 0xf9, 0x94, 0xea, 0xed, 0x73, 0xa4, 0xe5, 0x0a, 0x5e, 0xab, 0x72, 0xd7, 0xaa, 0xda, 0x9c, 0xaa, 0xcd, 0xa9, 0xda, 0x9c, 0x4a, 0x5d, 0xab, 0x52, 0xd7, 0xaa, 0x54, 0xdd, 0x59, 0x06, 0xa3, 0x9c, 0xaa, 0xcc, 0xa9, 0xca, 0x9c, 0xaa, 0xcc, 0x39, 0x2b, 0x97, 0xd4, 0x97, 0xdf, 0x8f, 0x6c, 0x91, 0x2c, 0x93, 0x4e, 0x59, 0x1b, 0xad, 0x55, 0x89, 0x6b, 0x55, 0xdf, 0x5a, 0xd5, 0xb7, 0xd6, 0x59, 0x5b, 0xeb, 0xac, 0x3d, 0xe6, 0xac, 0x3d, 0xe6, 0xac, 0x3d, 0xe6, 0xac, 0x3d, 0xe6, 0xac, 0x3d, 0xe6, 0xac, 0x35,\n\t0x3b, 0x6b, 0xcd, 0xce, 0x5a, 0xb3, 0xb3, 0xd6, 0xec, 0xac, 0xc5, 0x9d, 0xb5, 0xa7, 0x54, 0xd7, 0xb0, 0xea, 0xca, 0xa9, 0xae, 0x3e, 0xd5, 0xb5, 0x36, 0xf8, 0xa0, 0x95, 0xcc, 0x0f, 0x9c, 0xb5, 0xbf, 0x5a, 0xc9, 0xcc, 0xae, 0xae, 0x64, 0xae, 0x77, 0xa6, 0x1e, 0xb2, 0x42, 0x2f, 0xf7, 0xf2, 0xb3, 0xac, 0xad, 0x76, 0xb4, 0xc2, 0xd8, 0x5e, 0xb5, 0x7d, 0xa5, 0xf2, 0x6e, 0x3b, 0x07, 0x47, 0x3f, 0xb5, 0xc2, 0xb8, 0xd7, 0x8a, 0xe2, 0x7b, 0x8e, 0xec, 0x38, 0xc6, 0x7e, 0xa5, 0x35, 0x54, 0x03, 0x53, 0x3f, 0x8a, 0xa5, 0xff, 0x54, 0x15, 0x1e, 0xc4, 0xc0, 0x4f, 0x66, 0xe0, 0xd7, 0x32, 0xf0, 0xe1, 0xaa, 0x7d, 0x9f, 0x6a, 0xef, 0x3f, 0x68, 0xef, 0x77, 0x35, 0x87, 0x16, 0xab, 0xd0, 0xbd, 0xed, 0xfd, 0xee, 0xaa, 0x74, 0x17, 0x47, 0xf0, 0x0d, 0x55, 0xfa, 0x11, 0x73, 0x64, 0xb2, 0x3d,\n\t0x3c, 0xdb, 0x5c, 0xb8, 0xba, 0x62, 0xc7, 0x2b, 0xa2, 0xb8, 0xbd, 0x3c, 0xd6, 0x5e, 0xee, 0x1e, 0xdc, 0x59, 0xd9, 0xcb, 0xf5, 0xd1, 0xf4, 0x60, 0x48, 0x86, 0xa3, 0x79, 0xf6, 0xf8, 0x2f, 0xc6, 0x77, 0x9e, 0xbd, 0x7e, 0xd2, 0x1e, 0xff, 0xd0, 0x1e, 0xcf, 0xd2, 0x0d, 0x27, 0xe9, 0x86, 0x93, 0x74, 0xc3, 0x49, 0xf6, 0x7e, 0x4f, 0xdd, 0x70, 0x92, 0x6e, 0x38, 0x29, 0xb6, 0x43, 0xb4, 0x7b, 0x6c, 0x47, 0xf9, 0x17, 0xf7, 0x77, 0x92, 0x9d, 0x65, 0x97, 0xe8, 0x6c, 0x5d, 0x71, 0x92, 0x3a, 0x38, 0x5b, 0x47, 0x9c, 0xa4, 0x23, 0x4e, 0x52, 0x0f, 0x37, 0xea, 0x88, 0x93, 0x74, 0xc4, 0x49, 0x8e, 0xfc, 0xa7, 0x3a, 0xe2, 0x24, 0x1d, 0x71, 0x92, 0xfa, 0x38, 0x5b, 0x37, 0x9c, 0xe4, 0x4c, 0x1c, 0xed, 0x0c, 0x5c, 0xe1, 0x0c, 0x3c, 0xe9, 0x0c, 0x3c, 0x11, 0x3b, 0x34, 0xba, 0x2c, 0xf6, 0x71,\n\t0x39, 0x32, 0xba, 0x26, 0x76, 0x94, 0x1c, 0x6d, 0x4e, 0x1e, 0x13, 0xfd, 0x4a, 0xc7, 0x9c, 0x66, 0xcd, 0xf5, 0x2b, 0x67, 0xe8, 0x87, 0xb1, 0xe3, 0x83, 0x1a, 0xdd, 0xf3, 0x3e, 0xdd, 0xf3, 0xbe, 0xd8, 0x69, 0x48, 0x79, 0x7a, 0xd0, 0x14, 0x3b, 0x23, 0xa8, 0x57, 0x6b, 0xf3, 0x46, 0x2d, 0x8a, 0xa6, 0xab, 0xa5, 0x79, 0x3a, 0xe9, 0x2f, 0x74, 0xd2, 0x5f, 0x8c, 0x7a, 0xdd, 0xd7, 0x89, 0x68, 0x92, 0x6e, 0x3a, 0x49, 0x37, 0xbd, 0x43, 0x37, 0x9d, 0xa4, 0x9b, 0x4e, 0xd2, 0x4d, 0x27, 0xe9, 0xa6, 0x93, 0x74, 0xd2, 0x49, 0x3a, 0xe9, 0x24, 0x9d, 0x74, 0x92, 0xba, 0x3b, 0x5b, 0xbd, 0xdd, 0xa8, 0xde, 0x6e, 0xd4, 0x39, 0x27, 0xe9, 0x9c, 0x93, 0x46, 0x0d, 0xff, 0x7f, 0xec, 0xbd, 0x09, 0x78, 0x53, 0xe5, 0xda, 0xb6, 0xfd, 0x24, 0x1d, 0xb2, 0x56, 0x4a, 0x99, 0x41, 0xc1, 0x32, 0x0f, 0xa2,\n\t0xcc, 0x08, 0x45, 0x19, 0x54, 0x10, 0x51, 0x14, 0x04, 0x65, 0x10, 0x10, 0x05, 0x04, 0x15, 0x07, 0x70, 0xa0, 0x0a, 0x28, 0x4e, 0x20, 0x88, 0x38, 0x55, 0x61, 0x6f, 0x15, 0x70, 0x64, 0x10, 0x10, 0x1c, 0x50, 0x51, 0x26, 0x0b, 0x14, 0x0a, 0x04, 0x02, 0x14, 0x02, 0x1d, 0xa0, 0x2d, 0xb4, 0x49, 0x49, 0x9a, 0x0e, 0xc9, 0x6a, 0x13, 0xda, 0x06, 0x78, 0xfe, 0x73, 0xad, 0x06, 0xac, 0x88, 0xfb, 0xdd, 0xef, 0xf1, 0xbe, 0xff, 0xfe, 0xbf, 0xff, 0xf8, 0x3c, 0x38, 0x4e, 0x56, 0x92, 0x26, 0x6b, 0x78, 0x9e, 0xfb, 0xbe, 0xee, 0xeb, 0x5e, 0x19, 0x96, 0x6c, 0x81, 0x7a, 0x26, 0xa0, 0x9e, 0x09, 0xc4, 0xde, 0x6b, 0xa8, 0x67, 0x02, 0xf1, 0xf7, 0x00, 0xb1, 0x37, 0x16, 0xf5, 0x4c, 0x40, 0x3d, 0x13, 0x88, 0xc1, 0xb1, 0x91, 0x56, 0xd9, 0x02, 0x05, 0x4d, 0x20, 0x16, 0x93, 0x89, 0xc5, 0x64, 0x62,\n\t0x31, 0x19, 0x05, 0x4d, 0x40, 0x41, 0x13, 0x50, 0xd0, 0x04, 0xe2, 0x72, 0x2c, 0x71, 0x39, 0x96, 0xb8, 0x1c, 0x8b, 0x82, 0x7e, 0x85, 0x82, 0x7e, 0x86, 0x82, 0xae, 0x89, 0x7c, 0x53, 0xa6, 0xa2, 0xa2, 0x6b, 0x22, 0xdf, 0x32, 0xde, 0x23, 0x35, 0xbe, 0xe1, 0x4a, 0xdc, 0x8e, 0x25, 0x6e, 0x93, 0x2d, 0xf1, 0xf2, 0x5d, 0xcb, 0x78, 0x98, 0x00, 0x4f, 0x73, 0xdf, 0x2b, 0x9f, 0x24, 0x8e, 0x93, 0x89, 0xe3, 0x64, 0xd4, 0x75, 0x28, 0x51, 0x30, 0x94, 0x28, 0x18, 0x8a, 0xba, 0x0e, 0x25, 0xa6, 0xc7, 0x12, 0xd3, 0x63, 0x89, 0xe9, 0xb1, 0x44, 0xc5, 0x87, 0x44, 0xc5, 0x58, 0x62, 0x7a, 0x2c, 0xda, 0xd5, 0x1c, 0x65, 0x4d, 0x20, 0xb6, 0xc7, 0x12, 0x1d, 0x63, 0x51, 0xd6, 0x04, 0x94, 0x35, 0x81, 0x08, 0xf9, 0x27, 0x2a, 0xaa, 0xf7, 0x54, 0x4b, 0x50, 0xd0, 0x04, 0x14, 0x34, 0x01, 0x05, 0x4d,\n\t0x40, 0x41, 0x13, 0x88, 0x98, 0xd7, 0x50, 0xd0, 0x04, 0xd4, 0xf3, 0x63, 0x22, 0x66, 0x2f, 0xb1, 0x9d, 0x4c, 0xd4, 0x3c, 0x40, 0xd4, 0x8c, 0x15, 0xad, 0x51, 0x4e, 0x13, 0xd5, 0x3e, 0x06, 0x95, 0xa8, 0x87, 0x4a, 0xd4, 0x23, 0x6a, 0xbe, 0xa3, 0xd2, 0xd7, 0x23, 0x62, 0xbe, 0x27, 0x62, 0x76, 0x84, 0x2b, 0xbd, 0x85, 0x4a, 0x6f, 0x61, 0xc6, 0x97, 0x12, 0xe3, 0x6b, 0xa8, 0xf0, 0x31, 0x54, 0xf7, 0x1a, 0x64, 0x7c, 0x3d, 0xaa, 0x7b, 0x0d, 0xaa, 0x7b, 0x0d, 0xb2, 0xbd, 0x1e, 0x95, 0xdd, 0x42, 0xbc, 0x2f, 0xa6, 0xa2, 0x5b, 0x88, 0xf1, 0xcd, 0x54, 0xf3, 0x86, 0x54, 0xf3, 0x86, 0x54, 0xf3, 0x86, 0x54, 0xf3, 0x1a, 0xc4, 0x75, 0x19, 0x71, 0x5d, 0x3f, 0xec, 0x49, 0x76, 0x86, 0xfd, 0x48, 0x0c, 0x95, 0x3c, 0x86, 0x78, 0x3e, 0xc3, 0xde, 0xf9, 0x44, 0x43, 0xf6, 0xe0, 0x20, 0xda, 0xe4,\n\t0x08, 0x67, 0xda, 0x16, 0xf6, 0x62, 0x3f, 0x5b, 0x5e, 0xc5, 0x96, 0xbf, 0x43, 0x61, 0xf5, 0x4f, 0x64, 0xa7, 0xa3, 0xe9, 0x1a, 0x9a, 0xae, 0xd1, 0x6d, 0xed, 0x88, 0xec, 0x8f, 0x87, 0x18, 0x21, 0x0f, 0x5e, 0xfc, 0x2e, 0x8e, 0x65, 0x32, 0x5b, 0x7a, 0x9f, 0x2a, 0x94, 0x42, 0xb5, 0x68, 0x24, 0x53, 0xd8, 0x8a, 0x9e, 0x29, 0x47, 0x45, 0x7c, 0x58, 0xdb, 0x73, 0x59, 0xfb, 0x73, 0xa8, 0xde, 0x38, 0x54, 0x6f, 0x9c, 0x71, 0x7e, 0xa4, 0xb9, 0x5c, 0x47, 0x64, 0xeb, 0x3d, 0xdf, 0xcf, 0x61, 0x6d, 0xf7, 0xa0, 0xed, 0x8b, 0xd0, 0xf6, 0x4f, 0xd0, 0xf6, 0x45, 0x68, 0xfb, 0x27, 0x6c, 0xf9, 0xdb, 0xf0, 0xa7, 0x51, 0xfc, 0xec, 0xc1, 0x32, 0x34, 0xfe, 0x73, 0x34, 0xfe, 0x73, 0x54, 0x71, 0x1c, 0x8a, 0x38, 0x8e, 0x3d, 0x59, 0x8a, 0x2a, 0x8e, 0x43, 0x15, 0x73, 0x51, 0xc5, 0x5c, 0x94, 0x30,\n\t0x17, 0xf5, 0x5b, 0x87, 0xf2, 0xad, 0xa3, 0x96, 0xef, 0xa6, 0x96, 0xef, 0x46, 0x01, 0xd7, 0x11, 0x91, 0x95, 0x44, 0xa4, 0xde, 0xab, 0x55, 0x12, 0x21, 0x7e, 0xf6, 0x7a, 0x06, 0x7b, 0xfd, 0x02, 0x4a, 0x36, 0x8e, 0xbe, 0x6b, 0x72, 0x58, 0xe3, 0xb7, 0xa3, 0x56, 0xdb, 0x51, 0xab, 0xed, 0xa8, 0xd5, 0x76, 0xd4, 0x6a, 0xfb, 0x15, 0x34, 0x3e, 0x97, 0x99, 0xd5, 0xfb, 0xa4, 0x9f, 0x98, 0xbd, 0x52, 0xf6, 0x3e, 0x4a, 0x96, 0x19, 0x67, 0x7d, 0x6a, 0xc9, 0x20, 0x63, 0xe6, 0x21, 0xbf, 0x03, 0xe4, 0xa3, 0xfe, 0xeb, 0xd3, 0x25, 0xfa, 0xe7, 0xa8, 0xf4, 0xad, 0xb1, 0xf6, 0x72, 0x31, 0x03, 0x75, 0x28, 0x63, 0x94, 0xcf, 0xa0, 0x0e, 0x65, 0x3c, 0x3b, 0x9d, 0x67, 0xfb, 0x50, 0x06, 0x37, 0xca, 0xe0, 0x46, 0x19, 0xdc, 0xa6, 0x06, 0xbc, 0xa2, 0x21, 0x5c, 0xc5, 0xed, 0xab, 0xe1, 0x1a, 0x88,\n\t0x83, 0x26, 0xd0, 0x94, 0x35, 0x36, 0x63, 0xa9, 0xd7, 0xc3, 0x96, 0xdc, 0x6e, 0xc5, 0xed, 0xd6, 0xd0, 0x86, 0x99, 0x6a, 0xcb, 0xf2, 0x5a, 0xd0, 0x6b, 0xe4, 0x75, 0x2c, 0xaf, 0x87, 0xf6, 0x3c, 0xa7, 0x03, 0x74, 0xe4, 0x76, 0x27, 0x59, 0x46, 0x56, 0x97, 0x91, 0xd1, 0x65, 0x64, 0xb1, 0x9b, 0x2c, 0x76, 0x93, 0xc5, 0x6e, 0xb2, 0xd8, 0x1d, 0x71, 0x46, 0x96, 0x90, 0xc9, 0x6e, 0x32, 0xd9, 0x4d, 0x26, 0xbb, 0x8d, 0xda, 0x58, 0xc8, 0xb2, 0x08, 0x8a, 0xa1, 0x44, 0x16, 0x19, 0xb5, 0xb2, 0x94, 0x59, 0xaf, 0xaa, 0x97, 0x5b, 0x18, 0xc7, 0x2d, 0x64, 0xb6, 0x9b, 0xcc, 0x76, 0x93, 0xd5, 0x6e, 0xb2, 0xda, 0xcd, 0xb8, 0x6e, 0x21, 0xab, 0xdd, 0x64, 0xb5, 0x8f, 0xac, 0x2e, 0x22, 0xab, 0xdd, 0x64, 0xb5, 0x3b, 0x32, 0x8a, 0x11, 0x88, 0x06, 0x0b, 0x8f, 0xc5, 0x70, 0xff, 0x0e, 0x59, 0x46,\n\t0x66, 0x97, 0x91, 0xd9, 0x65, 0x64, 0xb6, 0x9b, 0xcc, 0x76, 0x93, 0xd9, 0x6e, 0x32, 0xbb, 0x88, 0xcc, 0x2e, 0x22, 0xb3, 0x8b, 0xf0, 0x42, 0x25, 0x64, 0x6f, 0x11, 0xd9, 0x5b, 0x46, 0xc6, 0x96, 0x91, 0xad, 0x65, 0x64, 0x6b, 0x19, 0xd9, 0x5a, 0x41, 0xb6, 0x56, 0x90, 0xad, 0x15, 0x64, 0x6b, 0x05, 0xd9, 0x5a, 0x44, 0xb6, 0x16, 0x91, 0xad, 0x45, 0x64, 0x6b, 0x11, 0xd9, 0x5a, 0x44, 0xb6, 0x16, 0x11, 0xef, 0x6e, 0xb2, 0xd5, 0x4d, 0xb6, 0x16, 0x91, 0xad, 0x45, 0x64, 0xab, 0x9b, 0x6c, 0x75, 0x33, 0x0b, 0x4e, 0xf5, 0x14, 0x39, 0xe0, 0x96, 0x4b, 0x98, 0xe7, 0x25, 0xcc, 0xf3, 0x12, 0xe6, 0x79, 0x09, 0xf3, 0xbc, 0x84, 0x2c, 0x76, 0x5b, 0x77, 0xc9, 0x12, 0xeb, 0x6e, 0xd8, 0x0b, 0xfb, 0xb8, 0x6f, 0x83, 0x03, 0x60, 0x87, 0x83, 0x90, 0x2a, 0xb7, 0x90, 0xd1, 0x6e, 0xea, 0x40, 0x91,\n\t0xfe, 0x5d, 0x58, 0x32, 0xba, 0x8c, 0x8c, 0xf6, 0x91, 0xd1, 0x45, 0x74, 0x23, 0xff, 0xd3, 0xfc, 0x89, 0x17, 0x26, 0xb2, 0xd6, 0x44, 0xd6, 0x9a, 0xfe, 0x32, 0x97, 0x5e, 0x27, 0xe2, 0x82, 0xfa, 0x19, 0x6d, 0x22, 0xae, 0x90, 0xad, 0x14, 0xb1, 0x95, 0x00, 0x31, 0xe4, 0x21, 0x86, 0x3c, 0xc4, 0x90, 0x1e, 0x7d, 0xbb, 0x88, 0xa3, 0x2d, 0xc4, 0xd1, 0x3e, 0xe2, 0xc8, 0x43, 0x1c, 0x79, 0xa8, 0x32, 0x7b, 0xa9, 0x32, 0x7b, 0x89, 0x27, 0x0f, 0xf1, 0xe4, 0x21, 0x9e, 0x3c, 0xc4, 0x53, 0x80, 0x78, 0xd2, 0x1d, 0xc7, 0x77, 0xc4, 0x53, 0x80, 0x78, 0xf2, 0x10, 0x4f, 0xba, 0xf3, 0x28, 0x22, 0x9e, 0x3c, 0xc4, 0x93, 0x87, 0xbd, 0xff, 0x89, 0x78, 0xf2, 0x10, 0x4f, 0x1e, 0xe2, 0xc9, 0x4e, 0x3c, 0x05, 0x88, 0x27, 0x8f, 0x7e, 0xf6, 0xda, 0x38, 0x4b, 0xbd, 0x4d, 0x96, 0x47, 0xec, 0x96, 0xe7,\n\t0x70, 0x22, 0x7e, 0x9c, 0x88, 0x3f, 0x22, 0x8d, 0xdb, 0xe9, 0x90, 0x87, 0xf3, 0x70, 0x82, 0x0b, 0xf2, 0xe1, 0x0c, 0xb1, 0xe1, 0x66, 0x89, 0x43, 0x20, 0xc6, 0x3c, 0xc4, 0xd8, 0x77, 0xc4, 0x98, 0x87, 0x18, 0xf3, 0x10, 0x63, 0x1e, 0x62, 0x2c, 0x40, 0x8c, 0x7d, 0x47, 0x8c, 0x6d, 0x24, 0xc6, 0xbe, 0x23, 0xc6, 0x8a, 0x88, 0xb1, 0x22, 0x62, 0xcc, 0x83, 0x63, 0x29, 0xc1, 0xb1, 0x94, 0x10, 0x6b, 0x1e, 0xaa, 0xc8, 0x5e, 0xe2, 0xcd, 0x43, 0xbc, 0x79, 0x88, 0xb7, 0x22, 0xe2, 0xcd, 0x13, 0x76, 0x31, 0x07, 0x89, 0xb9, 0x00, 0x31, 0xe7, 0x21, 0xe6, 0x3c, 0xc4, 0xdc, 0x46, 0x62, 0x6e, 0x23, 0x31, 0x17, 0xa0, 0xa2, 0xec, 0x25, 0xee, 0x3c, 0xc4, 0x9a, 0x87, 0x58, 0xf3, 0x10, 0x6b, 0xfa, 0xd9, 0xe9, 0x00, 0xb1, 0x16, 0x20, 0xd6, 0x02, 0xc4, 0xda, 0x3e, 0x62, 0x2d, 0x40, 0x95, 0xc8,\n\t0xa7, 0x4a, 0xe4, 0x53, 0x25, 0xf2, 0x95, 0x59, 0xf2, 0xdc, 0x15, 0x7c, 0x77, 0x80, 0x58, 0x0b, 0x10, 0x6b, 0x01, 0x62, 0x2d, 0x40, 0xac, 0x05, 0x88, 0xb5, 0x00, 0xb1, 0xe6, 0x21, 0xd6, 0x74, 0xd7, 0x13, 0x20, 0xd6, 0x02, 0xc4, 0x9a, 0x87, 0x58, 0xd3, 0xdd, 0x4f, 0x21, 0xb1, 0xb6, 0x91, 0x58, 0xdb, 0x41, 0xac, 0xed, 0x20, 0xd6, 0x76, 0x10, 0x6b, 0x3b, 0x88, 0xb5, 0x1d, 0x97, 0xce, 0x3e, 0x27, 0x4b, 0x0f, 0x31, 0xb7, 0x85, 0x98, 0xdb, 0x42, 0xcc, 0xed, 0x23, 0xe6, 0x3c, 0xc4, 0x9c, 0x87, 0x98, 0xf3, 0x10, 0x73, 0x1e, 0x62, 0xce, 0x43, 0xcc, 0x15, 0x11, 0x73, 0x1e, 0x62, 0xce, 0x1e, 0x76, 0x46, 0x01, 0xc3, 0x19, 0x5d, 0x7e, 0x8e, 0xf7, 0x31, 0xe3, 0x1c, 0x6f, 0xfd, 0x0b, 0x2f, 0x33, 0x6b, 0x37, 0x9a, 0x3a, 0x5d, 0xd8, 0x78, 0xd9, 0xb9, 0xd7, 0xd9, 0xf8, 0x82, 0x57,\n\t0xf5, 0x73, 0xad, 0xc6, 0xb9, 0x4e, 0xfd, 0x5c, 0xa6, 0x7e, 0x1e, 0x53, 0x3f, 0x87, 0xa9, 0x9f, 0xbf, 0x1c, 0x21, 0x9b, 0xfe, 0xe1, 0xdc, 0xe4, 0xc5, 0xf3, 0x92, 0x19, 0x52, 0x18, 0xe7, 0x21, 0xab, 0x9c, 0x51, 0x4b, 0x75, 0xc6, 0x85, 0xf2, 0xf0, 0x39, 0xc7, 0xd1, 0xc6, 0xb9, 0xc5, 0xbd, 0x46, 0x9d, 0x1b, 0x7a, 0xe9, 0xbc, 0x61, 0xf5, 0x73, 0x86, 0x9f, 0xb2, 0x97, 0x33, 0x70, 0x46, 0x0b, 0x70, 0x46, 0x0b, 0xfe, 0xe2, 0x8c, 0x74, 0x3c, 0x71, 0x1b, 0x4f, 0xdc, 0xc6, 0xb3, 0xe7, 0x87, 0x88, 0xdb, 0xbe, 0xc4, 0x6d, 0x5d, 0xe2, 0x36, 0x9e, 0xb8, 0x8d, 0x37, 0x35, 0xba, 0x70, 0xc4, 0xd4, 0x18, 0xae, 0xe1, 0x76, 0x1c, 0x34, 0x81, 0xa6, 0x17, 0x4a, 0x89, 0xdb, 0x78, 0xe2, 0x76, 0xb0, 0xa9, 0xe5, 0x85, 0x20, 0x71, 0x1b, 0x4f, 0xdc, 0xc6, 0x13, 0xb7, 0xfd, 0x88, 0xdb, 0x78,\n\t0xe2, 0x36, 0x9e, 0x11, 0x18, 0x44, 0xdc, 0xc6, 0x13, 0xb7, 0xf1, 0xc4, 0x6d, 0x2d, 0x53, 0x07, 0x5e, 0xd3, 0x91, 0xdb, 0x9d, 0x2e, 0x84, 0xaa, 0x8d, 0xca, 0x68, 0x46, 0x65, 0x11, 0xa3, 0xa2, 0x7f, 0xea, 0x71, 0x34, 0x6e, 0x69, 0x34, 0x6e, 0x69, 0x12, 0x6e, 0x69, 0x12, 0x6e, 0x69, 0x14, 0x6e, 0xe9, 0x29, 0xdc, 0xd2, 0x28, 0xdc, 0xd2, 0x53, 0x8c, 0xda, 0x4c, 0x9c, 0xd2, 0x2c, 0x9c, 0xd2, 0x0c, 0x9c, 0xd1, 0x02, 0xdc, 0xd0, 0x02, 0x62, 0x3c, 0x9e, 0x18, 0x8f, 0x27, 0xc6, 0xe3, 0x89, 0xf1, 0x78, 0x62, 0xbc, 0x2f, 0x31, 0x1e, 0x4f, 0x8c, 0xc7, 0x13, 0xe3, 0xf1, 0xc4, 0xf8, 0x60, 0x62, 0x3c, 0x9e, 0x18, 0x8f, 0x27, 0xc6, 0xe3, 0x23, 0x4a, 0x2e, 0x94, 0x12, 0xe3, 0x83, 0x89, 0xf1, 0xbb, 0x88, 0xf1, 0xc1, 0xc4, 0x78, 0x3f, 0x62, 0xbc, 0x1f, 0x31, 0x1e, 0x4f, 0x6c, 0xc7,\n\t0x47, 0x84, 0x2e, 0x1c, 0x21, 0xb6, 0xe3, 0x89, 0xed, 0x78, 0x62, 0xbb, 0x1f, 0xb1, 0x1d, 0x1f, 0x3e, 0x2b, 0x5d, 0x4a, 0x5c, 0xc7, 0x13, 0xd7, 0xf1, 0xc4, 0xf5, 0x5d, 0xc4, 0xf5, 0x5d, 0x91, 0x16, 0x1e, 0xb3, 0x5e, 0x38, 0x42, 0x5c, 0xc7, 0x87, 0xcf, 0x4a, 0xc7, 0x87, 0xcf, 0x4a, 0xc7, 0x87, 0xcf, 0x4a, 0xc7, 0x87, 0xcf, 0x4a, 0x97, 0x46, 0x0e, 0x87, 0xaa, 0xb3, 0xd2, 0xa5, 0xd5, 0xce, 0x4a, 0x2f, 0xc4, 0x31, 0x2d, 0xc7, 0x31, 0x2d, 0xc4, 0x31, 0x2d, 0x27, 0x07, 0xea, 0x46, 0x15, 0x5f, 0x28, 0x25, 0x07, 0xc6, 0x93, 0x03, 0xe3, 0xc9, 0x81, 0xf1, 0x7f, 0x3c, 0x53, 0x2d, 0x4d, 0xbf, 0x9f, 0xa9, 0xe6, 0xf6, 0xae, 0x0b, 0xa5, 0x8a, 0x1d, 0xd2, 0x20, 0x83, 0xe7, 0x54, 0x9d, 0xa9, 0x2e, 0xbd, 0x14, 0x25, 0xb7, 0xc9, 0x78, 0xf5, 0x21, 0xee, 0xeb, 0xd1, 0xf2, 0x12, 0xb7,\n\t0x5f, 0x83, 0x70, 0xd4, 0x90, 0x13, 0x77, 0x85, 0xcf, 0x54, 0x0f, 0x21, 0x27, 0x86, 0x90, 0x13, 0x43, 0xaa, 0x9d, 0xa9, 0x8e, 0x27, 0x1f, 0xfa, 0x92, 0x0f, 0x7d, 0xc3, 0x67, 0xaa, 0x27, 0x92, 0x0f, 0x37, 0x91, 0x0f, 0xf1, 0xe4, 0x43, 0x3c, 0xf9, 0x10, 0x1f, 0x3e, 0x53, 0x1d, 0x5f, 0xed, 0x4c, 0xf5, 0x8c, 0x3f, 0x44, 0xdd, 0x75, 0x61, 0x67, 0x55, 0x1b, 0x67, 0x75, 0x0d, 0xce, 0xea, 0x9a, 0xb0, 0xb3, 0xba, 0xea, 0x2f, 0x9d, 0x55, 0x27, 0x7c, 0x6f, 0x95, 0xbb, 0xaa, 0x8d, 0xbb, 0xaa, 0x83, 0xbb, 0xba, 0x06, 0x77, 0x55, 0x07, 0x77, 0x55, 0x07, 0x77, 0x75, 0x4d, 0x44, 0x29, 0x9e, 0xf8, 0xa2, 0xc3, 0x8a, 0x12, 0x4a, 0x64, 0x34, 0xfc, 0xee, 0xb4, 0x1a, 0xa3, 0xd9, 0x8d, 0xd1, 0xec, 0xc6, 0x38, 0xad, 0x3a, 0xf8, 0xc4, 0x9a, 0xd5, 0x9d, 0x96, 0x7a, 0x4a, 0x28, 0x61, 0xb7,\n\t0x55, 0x1b, 0xb7, 0x55, 0xfb, 0x92, 0xdb, 0xba, 0xc7, 0xd8, 0xcb, 0x72, 0xa8, 0x80, 0x90, 0xcc, 0x63, 0x2f, 0xd3, 0xf0, 0x05, 0x79, 0xec, 0xe5, 0xbe, 0x6a, 0x7b, 0x69, 0x62, 0x2f, 0x4d, 0x68, 0xf5, 0x01, 0xe2, 0x7d, 0x2b, 0x3a, 0x7d, 0x80, 0x38, 0xdf, 0xc8, 0x5e, 0x27, 0xa3, 0xc5, 0x07, 0xf4, 0xbd, 0x26, 0x56, 0xf3, 0x88, 0xd3, 0xbc, 0xf0, 0x37, 0x33, 0x4b, 0xa8, 0xf3, 0x79, 0x1c, 0x81, 0x89, 0x5a, 0x9f, 0xc7, 0xde, 0x9b, 0x88, 0xc3, 0xad, 0xe8, 0xeb, 0x01, 0x62, 0x6f, 0x2b, 0x71, 0xb7, 0x95, 0xb8, 0xdb, 0x48, 0xdc, 0x6d, 0xe4, 0x88, 0x4c, 0xc4, 0xd9, 0x46, 0xe3, 0xa8, 0xcc, 0xf2, 0x00, 0x5a, 0x79, 0x80, 0xa3, 0x32, 0x51, 0x9f, 0xf3, 0xa8, 0xcf, 0x79, 0xd4, 0xe7, 0x3c, 0x74, 0xf2, 0x00, 0x3a, 0x79, 0x40, 0x3f, 0xd2, 0x48, 0xfd, 0xf3, 0x82, 0x73, 0xd1, 0xda, 0x79,\n\t0xd2, 0x4f, 0xfc, 0xb8, 0x89, 0x1d, 0x37, 0xba, 0x79, 0x80, 0x1a, 0x9d, 0x47, 0x8d, 0xce, 0xa3, 0x46, 0xe7, 0x51, 0xa3, 0xf3, 0x14, 0xfd, 0x37, 0x0b, 0xec, 0x90, 0x06, 0x19, 0xe0, 0x91, 0x07, 0xd0, 0xc9, 0x03, 0x97, 0x46, 0xe6, 0x21, 0x6e, 0xcf, 0x80, 0x8b, 0x23, 0xe4, 0x96, 0xc9, 0xc4, 0x42, 0x32, 0xb1, 0x90, 0x4c, 0x2c, 0x24, 0x13, 0x0b, 0xc9, 0xc6, 0x88, 0xa5, 0xca, 0x8d, 0xc6, 0x68, 0x65, 0x51, 0x8b, 0xb3, 0x65, 0x05, 0xb5, 0x36, 0x0f, 0xed, 0x3b, 0x20, 0x6a, 0x32, 0x42, 0x67, 0x8c, 0xf7, 0x6c, 0xeb, 0xcb, 0x7c, 0x46, 0xc2, 0x4b, 0x35, 0xca, 0xd7, 0xdf, 0x4b, 0x35, 0xde, 0xbb, 0xd4, 0xdf, 0x8b, 0xd4, 0xdf, 0x87, 0xd4, 0xdf, 0x83, 0x1c, 0x41, 0xb5, 0x0f, 0xbf, 0x17, 0xa8, 0xbf, 0xe7, 0x27, 0x62, 0x8d, 0xce, 0xbb, 0x9d, 0x7c, 0x4b, 0xf7, 0x43, 0xe1, 0x6b, 0x1b,\n\t0x1e, 0xa5, 0x32, 0x7f, 0x87, 0x53, 0x3b, 0x81, 0x53, 0x2b, 0xa5, 0x42, 0x3f, 0x8b, 0x5b, 0xcb, 0xa6, 0x22, 0x3f, 0x48, 0x45, 0x7e, 0x90, 0xed, 0x4e, 0x66, 0x7b, 0xff, 0xcd, 0x57, 0xe9, 0xef, 0xca, 0x19, 0xaf, 0xac, 0xc7, 0xab, 0xe6, 0xf1, 0xaa, 0x72, 0xf6, 0xee, 0x2b, 0x5e, 0xb9, 0x9d, 0x57, 0xfe, 0xc8, 0x2b, 0x67, 0x85, 0x3f, 0xe9, 0xad, 0x7f, 0xb6, 0x71, 0x0f, 0xaf, 0x9e, 0xc2, 0x9e, 0x67, 0x92, 0xd7, 0x67, 0xd9, 0xfb, 0x60, 0x78, 0xef, 0x5d, 0xac, 0x6d, 0x12, 0x6b, 0x9b, 0x64, 0x39, 0x23, 0xb3, 0x19, 0xd7, 0x1c, 0xd1, 0xc2, 0xf0, 0x97, 0xcd, 0x99, 0xe9, 0xaa, 0xb3, 0x21, 0x4e, 0xd6, 0xe8, 0x61, 0x8d, 0xb9, 0x38, 0x66, 0x2f, 0x8e, 0xb9, 0x08, 0xc7, 0xec, 0xc5, 0x31, 0x17, 0xb1, 0x85, 0xef, 0x59, 0xeb, 0x49, 0x9c, 0x72, 0x01, 0x4e, 0xb9, 0x80, 0x08, 0xc8, 0x63,\n\t0xf6, 0xf3, 0x70, 0xc3, 0x39, 0xb8, 0xe1, 0x1c, 0xa2, 0x20, 0xaf, 0xda, 0x59, 0x8f, 0xa3, 0x54, 0xd7, 0xa3, 0xe1, 0xb3, 0x1e, 0xfa, 0xd5, 0x13, 0xf3, 0xd9, 0x6a, 0x3e, 0xb3, 0x72, 0x92, 0x59, 0x39, 0xc9, 0xac, 0x9c, 0x64, 0x56, 0x4e, 0x32, 0x2b, 0x27, 0xf5, 0x33, 0x1b, 0xc2, 0xca, 0x5e, 0xf8, 0x18, 0xfd, 0x34, 0xb2, 0x46, 0x61, 0x4b, 0xfa, 0x67, 0x5b, 0x4f, 0x73, 0x1c, 0x39, 0x8c, 0x76, 0x8e, 0x45, 0xff, 0xb6, 0xec, 0x0d, 0x3c, 0xf3, 0x9f, 0xb2, 0x82, 0x9c, 0xfa, 0xfd, 0x99, 0x6a, 0xb5, 0x67, 0x66, 0xe8, 0xf9, 0xf4, 0xa7, 0x67, 0xeb, 0xe7, 0x6d, 0x0b, 0x79, 0x76, 0x26, 0xb1, 0x9e, 0x49, 0x9c, 0x67, 0x12, 0xdf, 0x99, 0xc4, 0x76, 0x2a, 0xb1, 0x9d, 0xca, 0xab, 0x53, 0x89, 0x6f, 0x8d, 0xf8, 0xd6, 0xc2, 0x9f, 0xa5, 0x38, 0x4a, 0x4c, 0x67, 0x52, 0xfb, 0x4b, 0x88, 0xdd,\n\t0x4c, 0x62, 0x37, 0x93, 0x58, 0xcd, 0x24, 0x56, 0x33, 0x89, 0xd3, 0x4c, 0xe2, 0x32, 0x93, 0x38, 0xcc, 0x24, 0x0e, 0x33, 0x89, 0xc3, 0x4c, 0xe2, 0x30, 0x93, 0x38, 0xcc, 0x24, 0x0e, 0x33, 0x89, 0xbf, 0x4c, 0xe2, 0x4f, 0xd7, 0xa2, 0x0a, 0x62, 0x4b, 0x43, 0x37, 0xf4, 0x77, 0x6f, 0x33, 0xd9, 0xc7, 0x8b, 0xfb, 0x5b, 0xb5, 0xaf, 0xc6, 0xef, 0xf3, 0xfe, 0x69, 0x3f, 0x5b, 0xf2, 0xac, 0x52, 0x66, 0x61, 0x26, 0xb3, 0x90, 0xc4, 0x2c, 0xcc, 0x67, 0x16, 0x52, 0x98, 0x85, 0x2d, 0xcc, 0xc2, 0x14, 0x66, 0xe1, 0x71, 0x66, 0x61, 0x0a, 0xb3, 0xf0, 0x38, 0x6b, 0x79, 0x9a, 0x7d, 0x0e, 0xb0, 0xcf, 0x01, 0x66, 0x63, 0x12, 0xb3, 0xf1, 0x38, 0xb3, 0xf1, 0x38, 0xb3, 0x31, 0x93, 0xd9, 0x98, 0xc9, 0x2c, 0xcc, 0x64, 0x16, 0x92, 0x98, 0x85, 0x24, 0x66, 0xe1, 0x67, 0x66, 0xe1, 0x67, 0x66, 0x21,\n\t0x89, 0x59, 0x48, 0x62, 0x16, 0x26, 0x32, 0x0b, 0x13, 0x99, 0x85, 0x45, 0xcc, 0xc2, 0x22, 0x66, 0x61, 0x11, 0xb3, 0xb0, 0x88, 0x59, 0x58, 0xc4, 0x2c, 0x24, 0xb1, 0xdf, 0x01, 0x51, 0x97, 0xbd, 0xf8, 0x9c, 0xbd, 0xd0, 0xd8, 0x8b, 0xd5, 0xac, 0xf5, 0x73, 0xd6, 0xfa, 0x39, 0x6b, 0xfd, 0x9c, 0xb5, 0x6a, 0xac, 0x55, 0x63, 0xad, 0x41, 0xd6, 0x1a, 0x64, 0xad, 0x1a, 0x6b, 0xdd, 0xc7, 0xda, 0x36, 0xb1, 0xb6, 0x4d, 0xac, 0x6d, 0x13, 0x6b, 0xdb, 0xc4, 0xda, 0x36, 0xb1, 0x36, 0x8d, 0xbc, 0xa8, 0x8d, 0x67, 0xac, 0x6f, 0xbc, 0x57, 0xad, 0xff, 0xe2, 0xe3, 0x1a, 0xea, 0xdd, 0x6a, 0xfd, 0xbb, 0xf5, 0xc4, 0xe9, 0xb1, 0x8b, 0xdf, 0x8c, 0x27, 0x36, 0x75, 0x97, 0x90, 0xcf, 0x68, 0x14, 0xea, 0x11, 0x4e, 0x24, 0x54, 0xe5, 0xe0, 0x97, 0xbc, 0xea, 0xb4, 0xf1, 0x1b, 0xe8, 0x03, 0xe9, 0xe2,\n\t0x06, 0x19, 0xdf, 0x68, 0x3b, 0x7e, 0xf1, 0x55, 0x11, 0x9a, 0xa8, 0x25, 0xea, 0xff, 0x5b, 0xcf, 0xf4, 0x8b, 0x5a, 0xfa, 0xb3, 0x89, 0x0e, 0x15, 0x95, 0x55, 0x51, 0x59, 0x15, 0xf5, 0x54, 0x55, 0xb7, 0xa8, 0xad, 0x7a, 0xc0, 0x07, 0x7e, 0xd0, 0x50, 0xf6, 0x5a, 0xc6, 0x2c, 0xd4, 0xc6, 0x6b, 0xeb, 0x2a, 0x59, 0x15, 0x5f, 0xde, 0x70, 0x7c, 0x15, 0xb3, 0x16, 0x95, 0xb5, 0x58, 0x58, 0x8b, 0x85, 0xb5, 0xe8, 0x3a, 0x9d, 0xc9, 0x5e, 0x57, 0x32, 0x87, 0xa7, 0x59, 0xa3, 0x45, 0x34, 0x63, 0xe4, 0x66, 0x31, 0x72, 0xb9, 0x8c, 0xdc, 0x9b, 0xcc, 0xdf, 0x2e, 0xe6, 0x6f, 0x33, 0xf3, 0x37, 0x91, 0xf9, 0x7b, 0x94, 0xf9, 0x9b, 0xc8, 0xfc, 0x3d, 0xca, 0x1a, 0x67, 0x5e, 0xfc, 0xfe, 0x01, 0xf3, 0x37, 0x81, 0xf9, 0x9b, 0xc4, 0xfc, 0x4d, 0x62, 0xa4, 0x67, 0x31, 0xd2, 0xb3, 0xc8, 0xa6, 0x75,\n\t0x64, 0xd3, 0x3a, 0x46, 0x7c, 0x16, 0x23, 0x9e, 0xcb, 0x88, 0xe7, 0x32, 0xd2, 0xb9, 0xcc, 0xdd, 0x18, 0xe6, 0x6e, 0x0c, 0xa3, 0xbd, 0x82, 0xd1, 0x5e, 0xc1, 0x68, 0xaf, 0x60, 0xb4, 0x57, 0x30, 0xda, 0x2b, 0x18, 0xed, 0x5c, 0xe6, 0xad, 0x3e, 0xee, 0xbd, 0x1d, 0xb9, 0xdc, 0x85, 0x9e, 0xb1, 0x07, 0x3d, 0x43, 0x3c, 0x0c, 0x92, 0xeb, 0xab, 0x7f, 0xca, 0x9a, 0x2d, 0xa6, 0x32, 0x67, 0x95, 0xa8, 0xc2, 0x05, 0x46, 0xbe, 0x54, 0x57, 0x05, 0xd6, 0xbc, 0x97, 0x35, 0xef, 0xe5, 0x58, 0x9c, 0x1c, 0x4b, 0xa5, 0x91, 0x33, 0x7a, 0xc7, 0x59, 0x61, 0x78, 0x79, 0xdd, 0xc3, 0xb7, 0x91, 0xe7, 0x0d, 0x8f, 0x3e, 0x48, 0xee, 0x37, 0x3c, 0x75, 0x40, 0x9e, 0x67, 0xbf, 0xce, 0xb3, 0x5f, 0xe7, 0x0d, 0x7f, 0xac, 0xfb, 0xe1, 0xea, 0xde, 0x17, 0xdf, 0xfb, 0x97, 0xbe, 0xf6, 0xa2, 0x9f, 0x75, 0xcb,\n\t0x4a, 0x8e, 0xa3, 0x92, 0xe3, 0xa8, 0xe4, 0x38, 0x2a, 0x39, 0x0e, 0xfd, 0xbd, 0xc2, 0xf3, 0x86, 0x0f, 0x55, 0xc2, 0xdf, 0xc1, 0xf6, 0xb2, 0xc5, 0x7d, 0xd5, 0x3f, 0x7f, 0x1e, 0xce, 0x99, 0x22, 0x51, 0x87, 0x7d, 0x74, 0xb1, 0x8f, 0xa5, 0x1c, 0xf1, 0x71, 0x8e, 0x38, 0x8b, 0x57, 0x38, 0x8c, 0x5f, 0x10, 0x19, 0x44, 0x2f, 0x3f, 0x4a, 0x1e, 0xe1, 0x28, 0x83, 0x91, 0x43, 0x8c, 0x59, 0x2a, 0xe5, 0x08, 0x0f, 0x73, 0x84, 0x87, 0x79, 0x75, 0x16, 0xaf, 0xde, 0x42, 0x8e, 0x86, 0xc8, 0xba, 0x7c, 0xd1, 0x8e, 0xb5, 0x68, 0xac, 0x25, 0xc8, 0x91, 0xfa, 0x39, 0x52, 0x3f, 0x47, 0x5a, 0xca, 0x91, 0xfa, 0xff, 0xea, 0xf7, 0x09, 0x38, 0x7a, 0x3f, 0x47, 0x5f, 0xca, 0xd1, 0x97, 0x92, 0x07, 0x39, 0xe4, 0x41, 0x0e, 0xa3, 0x50, 0xca, 0x28, 0xf8, 0x19, 0x05, 0x3f, 0xa3, 0xe0, 0x67, 0x14, 0xfc,\n\t0x8c, 0x82, 0x9f, 0x51, 0xf0, 0x33, 0x0a, 0x7e, 0x46, 0xc1, 0xcf, 0x28, 0xf8, 0x19, 0x05, 0x3f, 0xa3, 0xe0, 0x67, 0x14, 0xfc, 0x8c, 0x82, 0x9f, 0x51, 0xf0, 0x33, 0x0a, 0x1a, 0xa3, 0xa0, 0x31, 0x0a, 0x1a, 0xa3, 0xa0, 0x31, 0x0a, 0x1a, 0xa3, 0x50, 0xaa, 0x7f, 0xe7, 0x9d, 0x91, 0xf0, 0x1b, 0x39, 0xb4, 0x99, 0x99, 0xd5, 0xf5, 0x7e, 0x3f, 0x31, 0xfe, 0x3e, 0x31, 0xbe, 0x34, 0x9c, 0x43, 0x17, 0xbf, 0xe3, 0x71, 0x90, 0x99, 0x7c, 0x49, 0xaf, 0x4a, 0x16, 0xfd, 0xd7, 0x39, 0xde, 0x97, 0x21, 0x43, 0x23, 0xab, 0xc7, 0xb1, 0x12, 0x8e, 0xe3, 0xe3, 0x17, 0xe3, 0xb8, 0x7a, 0xec, 0x1a, 0xda, 0x23, 0x2f, 0x3d, 0xbb, 0xa9, 0x2c, 0x61, 0x24, 0x4a, 0x18, 0x85, 0x12, 0x46, 0xc0, 0xc7, 0x08, 0xf8, 0x8c, 0x57, 0xdf, 0xc5, 0x28, 0x0d, 0x36, 0x3e, 0x4d, 0x54, 0xb5, 0x96, 0x12, 0x3c, 0x81,\n\t0xbe, 0x26, 0x33, 0x5a, 0x69, 0x81, 0xfb, 0x60, 0x38, 0x8c, 0x30, 0xb4, 0x52, 0xef, 0xb3, 0x4b, 0x2e, 0x6e, 0x81, 0x51, 0x28, 0x61, 0x14, 0x4a, 0x18, 0x85, 0x12, 0x46, 0xa1, 0x84, 0x51, 0x28, 0x61, 0x14, 0x4a, 0x18, 0x85, 0x12, 0x46, 0xa1, 0x44, 0xd7, 0x1d, 0x8e, 0xb6, 0x84, 0xfd, 0x36, 0xde, 0x49, 0xa3, 0xb2, 0xf5, 0x40, 0x05, 0xe3, 0xe5, 0x26, 0xb6, 0xfc, 0x7e, 0xf8, 0x9b, 0x17, 0x7a, 0xc6, 0xd8, 0x98, 0xd9, 0x79, 0xcc, 0xe6, 0x5c, 0x66, 0x73, 0xae, 0x50, 0xf1, 0x36, 0x87, 0xf0, 0xfe, 0x81, 0xf0, 0xa7, 0xad, 0xf4, 0xea, 0x75, 0x50, 0xff, 0x5c, 0x4c, 0xd8, 0x13, 0xb4, 0x66, 0x9e, 0xf3, 0x45, 0x34, 0x8e, 0xa8, 0x19, 0xcf, 0xdc, 0x4b, 0xbd, 0x9d, 0xc3, 0x33, 0x0f, 0x73, 0x94, 0x8d, 0x79, 0xe6, 0x47, 0x22, 0x92, 0xbf, 0xc4, 0x18, 0xeb, 0xa8, 0x85, 0x76, 0xb4, 0x93,\n\t0x0b, 0xc5, 0x5c, 0x3a, 0x8b, 0x0a, 0xba, 0x60, 0xfd, 0x33, 0x5d, 0x45, 0x3c, 0x5f, 0xef, 0x86, 0x35, 0x53, 0x0d, 0xf6, 0x27, 0x16, 0x6a, 0x51, 0x17, 0xeb, 0xb0, 0x95, 0xba, 0x50, 0x0f, 0xea, 0xb3, 0xb5, 0x06, 0x64, 0x7b, 0x43, 0xea, 0xf5, 0x55, 0xdc, 0xbf, 0x1a, 0x1a, 0xa1, 0xef, 0x8d, 0xe1, 0x1a, 0x6e, 0xc7, 0x41, 0x13, 0x68, 0xca, 0x3a, 0x9a, 0xb1, 0x6c, 0xce, 0xac, 0xb5, 0xe4, 0x76, 0x2b, 0x6e, 0xb7, 0x86, 0xaa, 0x8e, 0xb8, 0x80, 0xce, 0x42, 0xdf, 0xf3, 0x22, 0x3a, 0x8b, 0x02, 0x3a, 0x8b, 0x02, 0x3a, 0x8b, 0x93, 0x8c, 0xbe, 0x46, 0x67, 0x51, 0xc0, 0xd1, 0x1c, 0xa4, 0x23, 0x2e, 0x89, 0xf8, 0x8d, 0x8e, 0x38, 0xd9, 0xe8, 0x8a, 0x0b, 0x23, 0x52, 0x58, 0xa6, 0xb1, 0x4c, 0x37, 0xde, 0x89, 0x2a, 0xa0, 0x5b, 0x28, 0xa0, 0x5b, 0x28, 0xa0, 0x5b, 0x28, 0xa0, 0x5b, 0xc8,\n\t0xa5, 0x5b, 0x28, 0xa0, 0x5b, 0x28, 0xa0, 0x5b, 0xd0, 0x6b, 0x74, 0x21, 0xdd, 0x42, 0x01, 0xdd, 0x42, 0x01, 0xdd, 0x42, 0x01, 0xb3, 0xa6, 0xa1, 0x32, 0x85, 0x74, 0x0b, 0x79, 0x28, 0x4c, 0x61, 0xb5, 0x8e, 0xb8, 0x80, 0x6e, 0xa1, 0x80, 0x4e, 0xf8, 0x28, 0xdd, 0x42, 0x01, 0xdd, 0x42, 0x41, 0xb8, 0x13, 0x2e, 0x60, 0x86, 0x35, 0x3a, 0x85, 0x02, 0x3a, 0x85, 0x02, 0x3a, 0x85, 0x3c, 0xb4, 0x23, 0x8f, 0x19, 0xd7, 0xe8, 0x80, 0x8f, 0xd2, 0x29, 0x14, 0xd0, 0x25, 0x14, 0xd0, 0x21, 0x14, 0xd0, 0x1d, 0x14, 0x10, 0x05, 0x5a, 0xa4, 0x7e, 0x75, 0x8a, 0x91, 0x52, 0xc3, 0xfd, 0x9f, 0x20, 0x0a, 0x34, 0xdc, 0xbf, 0x86, 0xfb, 0xd7, 0x70, 0xff, 0x9a, 0x32, 0x5c, 0x96, 0xd3, 0x05, 0x17, 0xe2, 0xfc, 0x7d, 0x38, 0x7f, 0x1f, 0xce, 0xdf, 0x87, 0xf3, 0xf7, 0x11, 0x21, 0x1a, 0x11, 0xa2, 0x11,\n\t0x21, 0x1a, 0x11, 0xa2, 0x29, 0x7a, 0x4e, 0x58, 0x81, 0xb1, 0xc2, 0xf5, 0x17, 0x10, 0x29, 0x1a, 0x91, 0xa2, 0xe1, 0xfa, 0x0b, 0x70, 0xfd, 0x05, 0xb8, 0xfd, 0x3c, 0x72, 0xa7, 0x44, 0xd5, 0x23, 0xc9, 0x07, 0x7e, 0xd0, 0x88, 0xa4, 0x1f, 0x60, 0x03, 0x6c, 0xa6, 0xbb, 0xdd, 0x02, 0x5b, 0x61, 0x1b, 0x24, 0xcb, 0x02, 0x3a, 0x80, 0x5c, 0x3a, 0x80, 0x5c, 0x3a, 0x80, 0x13, 0x74, 0x00, 0x05, 0x74, 0x00, 0x05, 0x74, 0x00, 0x05, 0x74, 0x00, 0x05, 0x74, 0x00, 0x05, 0xe1, 0x8e, 0xb8, 0x80, 0x0e, 0xe0, 0x24, 0xd1, 0xa8, 0x89, 0x67, 0x84, 0x4f, 0x7a, 0x85, 0x1f, 0x34, 0x28, 0x95, 0x6f, 0x11, 0x19, 0x4b, 0x45, 0x40, 0xee, 0x10, 0x41, 0xee, 0x9f, 0x85, 0x8b, 0x67, 0xe7, 0x2b, 0xb9, 0x1d, 0xa2, 0x76, 0x9d, 0x63, 0x79, 0x9e, 0x3a, 0x27, 0xc8, 0x17, 0x13, 0x44, 0x40, 0x24, 0x44, 0xc9,\n\t0xf1, 0xa6, 0x68, 0x96, 0x16, 0x50, 0xc8, 0x1f, 0x55, 0x9e, 0x33, 0x59, 0xb9, 0x1d, 0x83, 0xaa, 0x5d, 0x7c, 0x4f, 0xaa, 0xb6, 0xcc, 0x0e, 0xd7, 0xb2, 0xdc, 0x2b, 0xfd, 0x6e, 0x44, 0xc4, 0x46, 0xe9, 0x8d, 0xf8, 0x05, 0x7e, 0x85, 0x4d, 0xb0, 0x59, 0x2e, 0x8d, 0xd8, 0xc2, 0x72, 0x2b, 0x6c, 0x03, 0xfd, 0xbd, 0xa9, 0x24, 0x96, 0xdb, 0x61, 0x07, 0xec, 0x94, 0xe7, 0x8c, 0xf7, 0xaa, 0x76, 0xcb, 0x95, 0xc6, 0xfb, 0x55, 0xfb, 0x78, 0xec, 0x00, 0xe8, 0x67, 0xe0, 0x0f, 0xb2, 0x3c, 0x04, 0xa9, 0xe0, 0xe0, 0x79, 0xc7, 0x58, 0x1e, 0x87, 0x34, 0x9e, 0x9b, 0x0e, 0xfa, 0x59, 0xf9, 0x6c, 0xee, 0x6b, 0xa2, 0x7e, 0x64, 0x3f, 0xe9, 0x8d, 0xbc, 0x0d, 0x6e, 0x87, 0x3b, 0xe4, 0x39, 0x3c, 0xfc, 0x39, 0x3c, 0xfc, 0x39, 0x34, 0xe7, 0x2b, 0x72, 0xdd, 0x13, 0xc5, 0x78, 0xe0, 0xd5, 0xcf, 0x31,\n\t0xcb, 0xeb, 0x99, 0xe5, 0xf5, 0xcc, 0xf2, 0x7a, 0xcb, 0xa3, 0xd2, 0x8b, 0x77, 0x3f, 0x67, 0x99, 0xcf, 0x72, 0x01, 0x7c, 0x05, 0xdf, 0xc2, 0x11, 0x38, 0x0a, 0xe8, 0x94, 0xc5, 0x0d, 0xe7, 0xa5, 0x17, 0x7f, 0x7f, 0x0e, 0x8d, 0x38, 0xa7, 0xa0, 0xf6, 0x4a, 0x6f, 0x18, 0x2e, 0xc7, 0x10, 0x21, 0x2b, 0xd1, 0xb1, 0x62, 0xeb, 0xf7, 0xd2, 0xcb, 0x8c, 0x2e, 0x65, 0x46, 0x97, 0x5a, 0x7f, 0x94, 0x3b, 0xac, 0x3f, 0x71, 0xff, 0x67, 0x60, 0x2c, 0xac, 0x8c, 0x85, 0x95, 0xb1, 0x60, 0xa6, 0xd7, 0x30, 0xd3, 0x6b, 0x98, 0xe9, 0x35, 0xcc, 0xf4, 0x1a, 0x2b, 0x63, 0x60, 0xdd, 0x6e, 0x7c, 0x7a, 0xee, 0x9c, 0x68, 0xc1, 0xac, 0xa5, 0x30, 0xfa, 0x36, 0x46, 0xba, 0x80, 0xfc, 0xad, 0x30, 0xce, 0x8c, 0xd6, 0x97, 0xab, 0x18, 0xe5, 0x53, 0x57, 0xba, 0x0e, 0x0c, 0x23, 0x1c, 0x60, 0x34, 0x03, 0x11,\n\t0xbb, 0xe4, 0xce, 0x88, 0xa3, 0xe4, 0x52, 0xba, 0x74, 0x12, 0xef, 0x05, 0x74, 0xc3, 0xe9, 0x91, 0xd4, 0x82, 0xc8, 0x81, 0x78, 0xb7, 0x21, 0x72, 0x25, 0x75, 0xf3, 0x38, 0x6e, 0xba, 0x40, 0xaf, 0x2e, 0xd5, 0xaf, 0x15, 0x43, 0x77, 0xfb, 0x1b, 0xdd, 0xed, 0x66, 0xf6, 0xde, 0x87, 0xfa, 0xf8, 0xa9, 0x32, 0x9a, 0xae, 0x40, 0x32, 0xdd, 0xf8, 0x6c, 0x53, 0x0c, 0x5b, 0xaf, 0x45, 0x75, 0xa9, 0x2f, 0x37, 0xe8, 0x9e, 0x45, 0xcc, 0xe3, 0x2f, 0x19, 0x44, 0x54, 0x39, 0x91, 0x94, 0x47, 0x24, 0xe5, 0x11, 0x45, 0x0e, 0x14, 0x69, 0x3f, 0x51, 0x52, 0x41, 0x94, 0x38, 0x78, 0x45, 0x31, 0xaf, 0x38, 0x80, 0xee, 0xd8, 0xd0, 0x1d, 0x1b, 0xba, 0x63, 0x33, 0xf6, 0xbf, 0x81, 0xf1, 0x69, 0xa8, 0x43, 0xe8, 0x8e, 0x0d, 0xdd, 0xb1, 0xa1, 0x3b, 0xeb, 0xd0, 0x9d, 0x75, 0xe8, 0x8e, 0x0d, 0xdd, 0xb1,\n\t0xa1, 0x3b, 0x36, 0x74, 0x67, 0x31, 0xba, 0x63, 0x43, 0x77, 0x34, 0x74, 0x67, 0x31, 0xba, 0x63, 0x43, 0x77, 0x6c, 0xe8, 0x4e, 0x36, 0xba, 0x63, 0x43, 0x77, 0x6c, 0xe8, 0x8e, 0x86, 0xee, 0xd8, 0xd0, 0x1d, 0x5b, 0xf8, 0x4c, 0xdc, 0x62, 0x74, 0xc7, 0xc6, 0xde, 0x6d, 0x20, 0x82, 0x1c, 0x44, 0x4b, 0x1e, 0x11, 0xe2, 0x20, 0x22, 0xf2, 0xd0, 0x1a, 0x1b, 0x5a, 0x63, 0x43, 0x6b, 0x6c, 0x68, 0x8d, 0x0d, 0xad, 0xd1, 0x3f, 0xf1, 0x64, 0x43, 0x6b, 0x6c, 0x68, 0x8d, 0x0d, 0xad, 0xd1, 0xd0, 0x1a, 0x1b, 0x5a, 0x63, 0x43, 0x6b, 0x6c, 0x68, 0xcd, 0x62, 0xb4, 0x46, 0x43, 0x6b, 0x2a, 0xd1, 0x1a, 0x0d, 0xad, 0xc9, 0x46, 0x6b, 0xb2, 0xd1, 0x1a, 0x1b, 0x5a, 0x63, 0x43, 0x6b, 0xd6, 0xa1, 0x35, 0x36, 0xb4, 0xc6, 0x86, 0xd6, 0x64, 0xa3, 0x35, 0x36, 0xb4, 0x66, 0x31, 0x5a, 0x63, 0x43, 0x6b,\n\t0x6c, 0x68, 0x8d, 0xee, 0x53, 0xf4, 0x4f, 0x3a, 0x2d, 0x46, 0x6b, 0xd6, 0xa1, 0x35, 0x36, 0x22, 0xd0, 0x41, 0x04, 0x3a, 0x88, 0x40, 0x07, 0xba, 0x63, 0x43, 0x77, 0x6c, 0xe8, 0x8e, 0x0d, 0xdd, 0x59, 0x8c, 0xee, 0x2c, 0x46, 0x77, 0x16, 0xa3, 0x3b, 0x87, 0xd0, 0x9d, 0xc5, 0x44, 0x66, 0x39, 0x91, 0xe9, 0x20, 0x32, 0x73, 0x88, 0xcc, 0x1c, 0x22, 0x33, 0x87, 0xa8, 0x74, 0x10, 0x71, 0x0e, 0x22, 0xce, 0x81, 0x06, 0x6d, 0x46, 0x83, 0x36, 0xa3, 0x41, 0x9b, 0xd1, 0xa0, 0xcd, 0x68, 0xd0, 0x62, 0x34, 0x68, 0x31, 0x1a, 0xb4, 0x18, 0x0d, 0x5a, 0x8c, 0x06, 0x2d, 0x46, 0x83, 0x16, 0xa3, 0x41, 0x36, 0x34, 0xc8, 0x86, 0x06, 0x2d, 0x46, 0x83, 0x16, 0xa3, 0x41, 0x36, 0x34, 0xc8, 0x86, 0x06, 0x55, 0xa2, 0x41, 0x15, 0x68, 0x50, 0x05, 0x1a, 0x54, 0x81, 0x06, 0x55, 0xa0, 0x41, 0x15, 0x44,\n\t0x6a, 0x39, 0x11, 0xa8, 0x9f, 0x85, 0xb3, 0xa1, 0x39, 0x95, 0x68, 0x8e, 0xfe, 0xe9, 0xa8, 0x43, 0x68, 0x8e, 0x0d, 0xcd, 0xb1, 0xa1, 0x39, 0x36, 0x34, 0xc7, 0x86, 0xe6, 0xd8, 0xd0, 0x9c, 0x6c, 0x34, 0xc7, 0x66, 0x9c, 0x85, 0xdb, 0x2c, 0x1d, 0xe8, 0xce, 0x62, 0x61, 0x36, 0xce, 0xb5, 0x76, 0x92, 0x41, 0x51, 0xc3, 0x78, 0xa7, 0xba, 0xb6, 0xd1, 0x8b, 0x56, 0x52, 0x13, 0xbd, 0xc6, 0xef, 0xd2, 0x0c, 0xc2, 0xcb, 0x55, 0x7d, 0x4f, 0xd1, 0xf8, 0x0e, 0x29, 0x35, 0xb1, 0x8c, 0x9a, 0x78, 0x8a, 0x9a, 0x78, 0x4a, 0x44, 0xf0, 0x8a, 0x83, 0x54, 0x38, 0xfd, 0x7d, 0xcc, 0x65, 0x54, 0xf3, 0x5a, 0x28, 0x92, 0x59, 0xff, 0x9f, 0xc7, 0x2c, 0x38, 0xe6, 0xfa, 0xd4, 0xb1, 0x06, 0x46, 0xbf, 0x57, 0xce, 0x33, 0xca, 0x59, 0x6f, 0x05, 0xf3, 0x18, 0x64, 0xee, 0xca, 0x99, 0xab, 0x72, 0xe6, 0xaa,\n\t0x84, 0xb9, 0x2a, 0x67, 0xec, 0x4b, 0x18, 0xfb, 0x12, 0x8e, 0xb1, 0x84, 0x63, 0xf4, 0xa8, 0xfa, 0x7b, 0xb0, 0x3e, 0xf0, 0x83, 0x66, 0x9c, 0x5d, 0x0c, 0x72, 0x5c, 0x41, 0xba, 0xd8, 0xff, 0x4a, 0xb7, 0x74, 0x0d, 0x09, 0x6b, 0x85, 0x9e, 0xf7, 0x7a, 0xae, 0xeb, 0xb9, 0x6d, 0xec, 0x4b, 0x16, 0xfb, 0x90, 0xc5, 0x2b, 0x03, 0x38, 0xb8, 0xdc, 0x7f, 0xf5, 0x59, 0x75, 0xdc, 0x9c, 0x5f, 0xdf, 0x1f, 0xd6, 0x94, 0x4b, 0xee, 0xe9, 0x9f, 0x05, 0xce, 0xbb, 0xf8, 0xfb, 0x05, 0xac, 0xf5, 0x34, 0x6b, 0xd5, 0x44, 0x13, 0xd6, 0xe8, 0xe4, 0xe8, 0x72, 0xc8, 0x0c, 0x1f, 0x19, 0x71, 0x86, 0x8c, 0xd0, 0x3f, 0x03, 0xa2, 0x77, 0xf3, 0x1e, 0xe3, 0x33, 0x1e, 0x38, 0x0b, 0x8e, 0x36, 0x87, 0xa3, 0xcd, 0xe7, 0x68, 0xf3, 0x39, 0xda, 0x4c, 0x8e, 0x36, 0x9f, 0x48, 0x3c, 0xc3, 0x11, 0xeb, 0xbd, 0x72,\n\t0x26, 0x91, 0x76, 0x86, 0x08, 0xf2, 0x71, 0xe4, 0x99, 0x1c, 0xb9, 0x93, 0x23, 0x77, 0x72, 0xe4, 0x4e, 0x8e, 0xdc, 0xc9, 0x91, 0x3b, 0x39, 0xf2, 0x1c, 0x8e, 0x3c, 0x87, 0x19, 0xf5, 0xe9, 0x9f, 0x61, 0x10, 0x0d, 0xd8, 0xea, 0x59, 0x72, 0xcd, 0x4d, 0x8e, 0xb9, 0xc9, 0x1f, 0xfd, 0x5d, 0x91, 0x73, 0xc4, 0xbe, 0x9b, 0x58, 0x76, 0x13, 0xbb, 0xfa, 0x3b, 0x10, 0x6e, 0x62, 0xd3, 0x4d, 0x6c, 0xea, 0x67, 0x36, 0xdc, 0xc4, 0x99, 0x9b, 0x38, 0x73, 0x13, 0x67, 0x6e, 0xe2, 0xcc, 0x4d, 0x9c, 0xb9, 0x89, 0x33, 0xfd, 0x5d, 0x05, 0x37, 0xf1, 0xe5, 0x26, 0x06, 0xdc, 0xc2, 0x2a, 0xcc, 0x46, 0x27, 0x7e, 0x71, 0xc6, 0xf7, 0x1a, 0xef, 0x55, 0x55, 0xfd, 0xda, 0xd0, 0xa5, 0xdf, 0x36, 0x89, 0x19, 0x20, 0xf7, 0x8b, 0x56, 0xa2, 0xb5, 0x7c, 0x59, 0xb4, 0x91, 0x9f, 0x8a, 0x76, 0x72, 0x9f, 0xb8,\n\t0x4e, 0x3a, 0x45, 0x7b, 0xb9, 0xd2, 0x7c, 0x97, 0x68, 0x6f, 0x1e, 0x26, 0xae, 0x33, 0x8f, 0xe5, 0xf6, 0x14, 0xb9, 0x5e, 0x19, 0x26, 0x5f, 0x56, 0xee, 0x85, 0x11, 0x30, 0x0a, 0xee, 0x87, 0xd1, 0x30, 0x06, 0x9e, 0x91, 0xfb, 0x94, 0x67, 0xe1, 0x39, 0xfc, 0xff, 0x74, 0x48, 0x80, 0xe7, 0xe1, 0x05, 0x98, 0x01, 0xb3, 0xe5, 0x4a, 0xe5, 0x65, 0x78, 0x05, 0x5e, 0x85, 0xb9, 0xf0, 0x06, 0xcc, 0x83, 0xf9, 0xf0, 0x26, 0x6a, 0xfd, 0xa9, 0x68, 0xc8, 0xde, 0x7c, 0x64, 0x0e, 0x8a, 0x08, 0x7a, 0x91, 0x48, 0x88, 0x22, 0x1a, 0xa3, 0x71, 0xea, 0x16, 0x69, 0x13, 0x0a, 0xa8, 0xdc, 0xb6, 0xa2, 0x6e, 0x31, 0x2c, 0x6b, 0x40, 0x2c, 0xd4, 0xe4, 0xf1, 0x5a, 0x2c, 0xf1, 0x9e, 0xa2, 0x0e, 0xcb, 0xba, 0x50, 0x4f, 0x9e, 0x10, 0xf5, 0x59, 0x36, 0x80, 0x86, 0x1c, 0xd1, 0x55, 0x2c, 0xaf, 0xd6, 0xdf,\n\t0x07, 0x81, 0xc6, 0x80, 0xc2, 0x09, 0x14, 0x4e, 0xa0, 0x70, 0xa2, 0x29, 0xf7, 0x9b, 0x41, 0x73, 0x6e, 0xb7, 0x60, 0xd9, 0x92, 0x68, 0x6f, 0x05, 0xad, 0xe5, 0x48, 0x46, 0x64, 0x9a, 0x68, 0x2b, 0xf7, 0x8a, 0x6b, 0xa1, 0x9d, 0x7c, 0x8f, 0x91, 0x59, 0x21, 0xae, 0x47, 0x61, 0xdb, 0xf3, 0x78, 0x07, 0x7c, 0xe1, 0x1f, 0xaf, 0x02, 0x54, 0x20, 0xba, 0xca, 0xed, 0xa2, 0x1b, 0xdc, 0x00, 0x44, 0x96, 0x20, 0xb2, 0x44, 0x3c, 0xf4, 0x94, 0xc9, 0xe2, 0x46, 0xb8, 0x09, 0x7a, 0xc9, 0x6d, 0xa2, 0x37, 0x8f, 0xf5, 0x81, 0xff, 0xef, 0xaf, 0xec, 0x50, 0x20, 0x26, 0xc0, 0x44, 0x78, 0x18, 0x26, 0xc1, 0x64, 0x78, 0x44, 0x1e, 0x14, 0x8f, 0x8a, 0x1a, 0xe2, 0x31, 0x98, 0xc2, 0xfd, 0xc7, 0xe1, 0x09, 0x78, 0x12, 0x9e, 0x82, 0xa9, 0x30, 0x0d, 0x9e, 0xe6, 0x18, 0x9e, 0x81, 0x67, 0xe1, 0x39, 0xee,\n\t0x4f, 0x87, 0x04, 0x8e, 0xf1, 0x79, 0x96, 0x2f, 0x48, 0xbb, 0x98, 0x01, 0x33, 0x61, 0x16, 0xbc, 0x68, 0xfc, 0x1e, 0x8d, 0x7e, 0xe5, 0x87, 0x0c, 0xf1, 0x32, 0xbc, 0x02, 0xaf, 0xc2, 0x6b, 0xf0, 0x3a, 0xcc, 0x81, 0xb9, 0xf0, 0x06, 0xcc, 0x83, 0xf9, 0xec, 0xc3, 0x9b, 0x50, 0x75, 0x95, 0xf3, 0x74, 0xb1, 0x90, 0x39, 0xa9, 0xfa, 0xad, 0x6b, 0x8f, 0x89, 0xca, 0x61, 0x3a, 0x43, 0x3c, 0xbb, 0xe5, 0x76, 0x93, 0xfe, 0x0d, 0x95, 0x22, 0xe2, 0xba, 0x98, 0x4a, 0x57, 0x62, 0xfc, 0xb6, 0x54, 0x71, 0xf8, 0xb7, 0xac, 0x8a, 0xcd, 0xfd, 0x64, 0x92, 0x79, 0x80, 0xb4, 0x99, 0x6f, 0x67, 0x79, 0xa7, 0x3c, 0x40, 0x44, 0xdf, 0x62, 0xbe, 0x9b, 0xfb, 0xf7, 0xc8, 0x22, 0x22, 0xbb, 0x87, 0xf9, 0x5e, 0x6e, 0x0f, 0xe7, 0x6f, 0x63, 0xe5, 0x34, 0xf3, 0x03, 0x32, 0xdf, 0x3c, 0x9e, 0xfb, 0x13, 0xf9,\n\t0xdb, 0x64, 0x6e, 0x3f, 0x22, 0xb7, 0x99, 0x1f, 0x93, 0x0e, 0x22, 0x7f, 0x9a, 0xf9, 0x71, 0xb9, 0xd7, 0xfc, 0x04, 0x8f, 0x3f, 0x09, 0x4f, 0xf1, 0xb7, 0x67, 0x64, 0x81, 0xf9, 0x59, 0x98, 0x2e, 0xb7, 0x9b, 0x39, 0x5e, 0xf3, 0x4c, 0x6e, 0xcf, 0x82, 0xd9, 0xc0, 0x71, 0x99, 0x39, 0x2e, 0xf3, 0xeb, 0xd2, 0x63, 0x9e, 0xc7, 0x36, 0xdf, 0x14, 0xb5, 0xcc, 0x0b, 0x78, 0xce, 0x42, 0xee, 0x27, 0x4a, 0xbb, 0x79, 0x11, 0xb7, 0xf5, 0xdf, 0xca, 0xfe, 0x84, 0xe7, 0x2e, 0x81, 0xa5, 0x3c, 0xfe, 0xef, 0x5f, 0x55, 0x22, 0xc3, 0xfc, 0x0d, 0xfc, 0x2c, 0x0f, 0x44, 0x26, 0xc8, 0x82, 0xa8, 0xfa, 0xd0, 0x54, 0x3a, 0x7e, 0xbf, 0xa2, 0x84, 0xa8, 0x11, 0xb5, 0x4b, 0xd4, 0x8b, 0xda, 0x6d, 0x5c, 0x45, 0xfd, 0x4a, 0x57, 0x95, 0xb0, 0x45, 0xe5, 0xf0, 0xfc, 0x53, 0x70, 0x1a, 0xe5, 0xcb, 0x37, 0xae,\n\t0xaa, 0x9e, 0x1c, 0xe5, 0x65, 0x59, 0x28, 0x0f, 0x46, 0xb7, 0x94, 0x45, 0xd1, 0xb8, 0xe5, 0xe8, 0xd6, 0xc6, 0x6f, 0xf1, 0x64, 0x44, 0x57, 0xa0, 0x8c, 0xed, 0x65, 0xae, 0xa5, 0x03, 0x74, 0x04, 0xf4, 0xd9, 0xd2, 0x19, 0x50, 0x5a, 0x4b, 0x57, 0xe8, 0x06, 0x37, 0x40, 0x4f, 0xb8, 0x11, 0x6e, 0x82, 0x5e, 0xd0, 0x1b, 0xfa, 0x40, 0x5f, 0xb8, 0x19, 0x6e, 0x81, 0x5b, 0xa1, 0x1f, 0xf4, 0x87, 0xdb, 0x60, 0x00, 0xdc, 0x0e, 0x03, 0xe1, 0x0e, 0xb8, 0x13, 0x26, 0xc2, 0xc3, 0xf2, 0x94, 0x65, 0x12, 0x30, 0xf6, 0x96, 0x29, 0xb2, 0xc8, 0xf2, 0x38, 0x30, 0xf6, 0x96, 0x27, 0xa5, 0xcd, 0xf2, 0x14, 0x4c, 0x85, 0x69, 0xf0, 0x1c, 0x4c, 0xe7, 0xf1, 0x04, 0x78, 0x1e, 0x5e, 0x80, 0x19, 0x30, 0x13, 0x5e, 0xe4, 0xb5, 0x2f, 0xc1, 0x6c, 0x6e, 0xbf, 0x0c, 0xaf, 0xc0, 0xab, 0xf0, 0x1a, 0xbc, 0x0e,\n\t0x73, 0x60, 0x2e, 0xbc, 0x05, 0x0b, 0xe1, 0x6d, 0x78, 0x07, 0xde, 0x85, 0xf7, 0xe0, 0x7d, 0x48, 0x84, 0x0f, 0xe0, 0x43, 0x58, 0x04, 0xff, 0x80, 0x7f, 0xc2, 0x47, 0xf0, 0x31, 0x7c, 0x02, 0xcb, 0x61, 0x05, 0xfb, 0xb1, 0x12, 0x56, 0xc1, 0xd7, 0xb0, 0x1a, 0xd6, 0xc0, 0x5a, 0xf8, 0x86, 0xbf, 0x7f, 0x07, 0xdf, 0xc3, 0x0f, 0xb0, 0x01, 0x7e, 0x84, 0x3d, 0xb0, 0x17, 0xf6, 0x81, 0x0d, 0xf6, 0xc3, 0x01, 0xb0, 0xc3, 0x41, 0x70, 0xc0, 0x31, 0x38, 0x0e, 0x69, 0x90, 0x0e, 0x19, 0x90, 0x09, 0x1e, 0x28, 0x90, 0x27, 0x2c, 0x85, 0x40, 0xdc, 0x5b, 0x4a, 0xc0, 0x07, 0x7e, 0xd0, 0xa0, 0x14, 0xca, 0x20, 0xc0, 0xf1, 0xd3, 0x95, 0x59, 0xce, 0x42, 0x39, 0x54, 0x40, 0x25, 0xd0, 0x91, 0x59, 0xa4, 0x2c, 0x52, 0x04, 0x98, 0xc0, 0x0c, 0x11, 0x10, 0x09, 0x68, 0xad, 0x62, 0x01, 0x05, 0xd0, 0x5a,\n\t0xc5, 0x0a, 0x68, 0xad, 0x12, 0x2b, 0x6d, 0x0a, 0x3a, 0xab, 0xd4, 0x82, 0xda, 0x80, 0x93, 0x54, 0x70, 0x92, 0x0a, 0x4e, 0x52, 0xa9, 0x0f, 0xb8, 0x47, 0xa5, 0x11, 0x34, 0x06, 0xb4, 0x55, 0x41, 0x5b, 0x15, 0xb4, 0x55, 0x69, 0x0a, 0xb8, 0x47, 0x05, 0x6d, 0x55, 0x5a, 0x40, 0x4b, 0xc0, 0x09, 0x29, 0x38, 0x48, 0xa5, 0x0d, 0xe0, 0x20, 0x15, 0x1c, 0xa4, 0xd2, 0x0e, 0x70, 0x90, 0x0a, 0x0e, 0x52, 0xe9, 0x0e, 0x3d, 0xd9, 0xe6, 0x8d, 0x70, 0x13, 0x0e, 0xab, 0x2f, 0xcb, 0x9b, 0xe1, 0x16, 0xb8, 0x15, 0xfa, 0x41, 0x7f, 0xb8, 0x0d, 0x06, 0xc0, 0xed, 0x30, 0x10, 0x4f, 0x70, 0x07, 0xdc, 0x09, 0x83, 0xe0, 0x6e, 0x18, 0x0c, 0x43, 0xe0, 0x1e, 0x18, 0x0a, 0xc3, 0xe4, 0x48, 0xaa, 0xd7, 0x48, 0xaa, 0xd7, 0x48, 0xaa, 0xd7, 0x48, 0xaa, 0xd7, 0x48, 0xaa, 0xd7, 0x48, 0xaa, 0xd7, 0x48, 0x65,\n\t0xac, 0xdc, 0xab, 0x3c, 0x00, 0xe3, 0xe0, 0x41, 0x78, 0x08, 0xc6, 0xc3, 0x04, 0x98, 0x08, 0x0f, 0xc3, 0x24, 0x98, 0x0c, 0x8f, 0xc0, 0xa3, 0xf0, 0x18, 0x4c, 0x01, 0xb4, 0x41, 0x79, 0x02, 0x9e, 0x84, 0xa7, 0x60, 0x2a, 0x4c, 0x83, 0xa7, 0xe1, 0x19, 0xf9, 0x1e, 0x55, 0xf1, 0x3d, 0xaa, 0xe2, 0x0a, 0xaa, 0xe2, 0x0a, 0xaa, 0xe2, 0x0a, 0xaa, 0xe2, 0x0a, 0xaa, 0xe2, 0x0a, 0xaa, 0xe2, 0x0a, 0xe5, 0x45, 0x99, 0xa7, 0xbc, 0x04, 0xb3, 0xe5, 0x34, 0xaa, 0xe3, 0x34, 0xaa, 0xe3, 0x34, 0xaa, 0xe3, 0x34, 0xaa, 0xe3, 0x34, 0xaa, 0xe3, 0x34, 0xaa, 0xe3, 0x34, 0xaa, 0xe3, 0x34, 0xaa, 0xe3, 0x34, 0xe5, 0x03, 0x99, 0xaf, 0x7c, 0x08, 0x8b, 0xe0, 0x1f, 0xf0, 0x4f, 0xf8, 0x08, 0xfe, 0x33, 0x57, 0xfe, 0x2a, 0xfd, 0x8b, 0x2b, 0x7f, 0x15, 0x28, 0xdb, 0xe0, 0x37, 0xd8, 0x2e, 0xb7, 0x2b, 0x3b,\n\t0x60, 0x27, 0x24, 0xc3, 0x1e, 0xd8, 0x2b, 0x93, 0x95, 0x7d, 0x60, 0x83, 0xfd, 0x70, 0x10, 0x0e, 0xf1, 0xf8, 0x61, 0x48, 0x85, 0x23, 0x70, 0x14, 0x1c, 0x70, 0x0c, 0x8e, 0x43, 0x26, 0x9c, 0x80, 0x93, 0x90, 0x05, 0xd9, 0x90, 0x03, 0xa7, 0x00, 0xcd, 0x52, 0x72, 0xc1, 0x09, 0x2e, 0xc8, 0x87, 0x33, 0x40, 0x1d, 0x50, 0x0a, 0xc0, 0x0b, 0xff, 0x7b, 0x57, 0x4a, 0x29, 0x50, 0xeb, 0x40, 0x5d, 0xa8, 0x07, 0x68, 0xad, 0xda, 0x00, 0xae, 0x82, 0x46, 0xd0, 0x58, 0xd4, 0x54, 0xe3, 0x58, 0x36, 0xd1, 0xaf, 0xd3, 0xae, 0x5f, 0xd9, 0x14, 0x9a, 0x43, 0x0b, 0x68, 0x09, 0x6d, 0xa0, 0x2d, 0xb4, 0x83, 0x0e, 0xd0, 0x11, 0x3a, 0xe3, 0x5b, 0xbb, 0x8a, 0x1a, 0xea, 0x0d, 0xdc, 0xee, 0x0e, 0x3d, 0x00, 0x6f, 0xa6, 0xf6, 0x84, 0x5e, 0xd0, 0x1b, 0xfa, 0x40, 0x5f, 0xb8, 0x19, 0x6e, 0x11, 0x75, 0xd4,\n\t0x5b, 0x59, 0xf6, 0x83, 0xfe, 0x30, 0x00, 0x6e, 0x87, 0x81, 0x30, 0x08, 0xee, 0x82, 0xbb, 0x61, 0x30, 0x0c, 0x81, 0x7b, 0x60, 0x28, 0x0c, 0x03, 0x3a, 0x4b, 0x75, 0x38, 0x8c, 0x90, 0xdb, 0xd5, 0x91, 0x30, 0x0a, 0xee, 0x87, 0xd1, 0x30, 0x06, 0xc6, 0xc2, 0x03, 0x30, 0x1e, 0x26, 0xc0, 0x44, 0x78, 0x18, 0x26, 0xc1, 0x64, 0x78, 0x04, 0x1e, 0x85, 0xc7, 0x60, 0x0a, 0x3c, 0x0e, 0x4f, 0xc0, 0x93, 0xf0, 0x14, 0x4c, 0x85, 0x69, 0x30, 0x13, 0x66, 0xc1, 0x8b, 0x40, 0xfd, 0x53, 0x5f, 0x86, 0xd7, 0x61, 0x0e, 0xcc, 0x85, 0x37, 0x60, 0x1e, 0xcc, 0x07, 0xfd, 0x0a, 0xb0, 0x6f, 0xc1, 0x42, 0x78, 0x5b, 0xda, 0xd5, 0x77, 0xe0, 0x5d, 0x78, 0x0f, 0xa8, 0x8d, 0xea, 0x07, 0xf0, 0x21, 0x2c, 0x82, 0xc5, 0xf0, 0x91, 0xcc, 0x50, 0x3f, 0x86, 0x4f, 0x60, 0x09, 0x2c, 0x85, 0x65, 0xf0, 0xa9, 0xb8,\n\t0x43, 0xfd, 0x8c, 0xe5, 0xe7, 0xf0, 0x05, 0x7c, 0x09, 0x5f, 0xc1, 0x72, 0x58, 0x01, 0x2b, 0x61, 0x15, 0x7c, 0x0d, 0xab, 0x61, 0x0d, 0x50, 0x3b, 0x55, 0x6a, 0xa7, 0xba, 0x0e, 0xd6, 0xc3, 0xb7, 0xf0, 0x1d, 0x7c, 0x0f, 0x3f, 0xc0, 0x06, 0xf8, 0x11, 0x7e, 0x82, 0x9f, 0x61, 0x23, 0xfc, 0x02, 0xbf, 0xc2, 0x26, 0xd8, 0x0c, 0x5b, 0x60, 0x2b, 0x6c, 0x83, 0xdf, 0xe4, 0x41, 0x35, 0x09, 0xb6, 0xc3, 0x0e, 0xd8, 0x09, 0xc9, 0xb0, 0x0b, 0x76, 0xc3, 0x1e, 0xd8, 0x0b, 0xfb, 0xc0, 0x06, 0xfb, 0xe1, 0x00, 0xd8, 0xe1, 0x20, 0x1c, 0x82, 0xc3, 0x90, 0x0a, 0x47, 0xc0, 0x01, 0xc7, 0xe0, 0xb8, 0x4c, 0x55, 0xd3, 0x20, 0x43, 0xa6, 0xab, 0x99, 0x70, 0x02, 0x4e, 0x42, 0x16, 0x64, 0x43, 0x0e, 0x9c, 0x96, 0x5e, 0x35, 0x17, 0xfe, 0xfd, 0xdf, 0xcd, 0xf7, 0xa8, 0x65, 0x10, 0x80, 0x20, 0x9c, 0x85,\n\t0x72, 0x3a, 0xb0, 0xe1, 0xf2, 0x84, 0x35, 0x5d, 0x16, 0x58, 0xe9, 0xbc, 0xad, 0x5e, 0xa0, 0xf3, 0xb6, 0xd2, 0x79, 0x5b, 0xe9, 0xbc, 0xad, 0x25, 0x72, 0xaf, 0xd5, 0x07, 0x7e, 0xd0, 0xa0, 0x14, 0xca, 0xe4, 0x76, 0x6b, 0x00, 0x82, 0x70, 0x16, 0xca, 0xa1, 0x42, 0x1e, 0xb4, 0x56, 0x42, 0x08, 0xce, 0xc1, 0x79, 0x79, 0x10, 0x17, 0x3f, 0x3d, 0xe6, 0x5d, 0x99, 0x1f, 0xf3, 0x1e, 0xfc, 0x2a, 0x8b, 0x62, 0xa8, 0x71, 0x31, 0xe4, 0xbf, 0x98, 0x84, 0xa3, 0xfe, 0x56, 0xd8, 0x70, 0x71, 0xfb, 0xe9, 0x7a, 0xec, 0xf2, 0x88, 0x38, 0xc4, 0xb2, 0x54, 0xfe, 0x6a, 0x8a, 0x92, 0x9f, 0x46, 0xec, 0x92, 0x5f, 0x45, 0xa4, 0xcb, 0x52, 0x4b, 0x77, 0x59, 0x62, 0xe9, 0x01, 0x77, 0xc1, 0xdd, 0xa2, 0xae, 0x65, 0xb0, 0x68, 0x62, 0x19, 0xc2, 0xed, 0x7b, 0x60, 0x28, 0xf7, 0x87, 0x89, 0xd6, 0x96, 0x7b,\n\t0xb9, 0x7d, 0x1f, 0x0c, 0x87, 0x11, 0x30, 0x12, 0x46, 0xc1, 0xfd, 0x30, 0x9a, 0xe7, 0x8c, 0xe1, 0x35, 0x63, 0xb9, 0xfd, 0x00, 0x8c, 0xe3, 0xfe, 0x83, 0xbc, 0xe6, 0x21, 0x6e, 0x4f, 0x96, 0x27, 0x2d, 0x4b, 0xb8, 0xbf, 0x54, 0x6c, 0xb1, 0x2c, 0x13, 0x07, 0x2c, 0x9f, 0x72, 0xfb, 0x33, 0x6e, 0x7f, 0x2e, 0xec, 0x96, 0x9f, 0xb8, 0xfd, 0x33, 0xb7, 0x37, 0xf2, 0xf8, 0x2f, 0x62, 0xb0, 0xe5, 0x57, 0xee, 0x6f, 0xe2, 0xfe, 0x66, 0xfe, 0xb6, 0x85, 0xfb, 0xdb, 0x44, 0x4d, 0x4b, 0x12, 0x8f, 0x6d, 0xe7, 0xb1, 0x1d, 0x3c, 0x67, 0x27, 0x8f, 0x25, 0x73, 0x7f, 0x17, 0xf7, 0x77, 0xf3, 0x9c, 0x14, 0xee, 0x9f, 0x10, 0x4d, 0x2d, 0x27, 0xc5, 0x1e, 0x4b, 0x96, 0x38, 0x69, 0xc9, 0x16, 0xa3, 0x2d, 0x39, 0xdc, 0x3f, 0xc5, 0xdf, 0x4e, 0x8b, 0x1c, 0x4b, 0x2e, 0xf7, 0x9d, 0xa2, 0xbe, 0xc5, 0x2b,\n\t0xff, 0xa1, 0x74, 0x10, 0x1f, 0x2b, 0x1d, 0xc5, 0x6a, 0xa5, 0x33, 0xcb, 0x2e, 0x62, 0xad, 0x72, 0x9f, 0x7c, 0x5b, 0x99, 0x29, 0x53, 0x95, 0xd7, 0x45, 0x8c, 0xb2, 0x40, 0x5c, 0xab, 0xbc, 0x65, 0x8a, 0x57, 0x16, 0x9a, 0xba, 0x28, 0x6f, 0x8b, 0x97, 0x95, 0x77, 0x44, 0x63, 0xe5, 0x5d, 0x51, 0xc7, 0xda, 0x44, 0xbc, 0x66, 0x6d, 0x2a, 0xde, 0xb6, 0x36, 0xe3, 0x76, 0x0b, 0x6e, 0xb7, 0x14, 0x1f, 0x5a, 0x5b, 0x71, 0xbb, 0x1d, 0xb7, 0xaf, 0xe3, 0xf1, 0xeb, 0xb9, 0xdd, 0x81, 0xdb, 0x1d, 0x79, 0xbc, 0x93, 0xa8, 0xc3, 0x2c, 0x6c, 0x8f, 0xf9, 0x56, 0x6a, 0x31, 0xdf, 0x9b, 0xda, 0xc5, 0xfc, 0x60, 0xea, 0x1e, 0xb3, 0x41, 0x4c, 0x8b, 0xf9, 0x51, 0xca, 0x98, 0x9f, 0x44, 0xed, 0x98, 0x5f, 0xc4, 0xd5, 0xc6, 0x6c, 0xac, 0xfe, 0x17, 0xb3, 0xf1, 0x19, 0xb3, 0xe1, 0xff, 0x7b, 0x36, 0x18,\n\t0xfd, 0x3f, 0xce, 0x46, 0x1d, 0x66, 0x23, 0xe6, 0x7f, 0x7d, 0x36, 0x6a, 0x32, 0x1b, 0x3b, 0x18, 0x7d, 0x1b, 0xa3, 0xbf, 0x81, 0xd1, 0x4f, 0x65, 0x74, 0x3c, 0x96, 0xf5, 0x8c, 0xd4, 0x61, 0x71, 0x23, 0x7b, 0xb9, 0x46, 0x69, 0x28, 0x6a, 0xb3, 0x67, 0x6b, 0xd9, 0xab, 0x69, 0xca, 0x02, 0x5c, 0x0f, 0x8e, 0x55, 0xd1, 0x7f, 0xbf, 0xb1, 0x13, 0xaf, 0xfc, 0x55, 0xec, 0x65, 0xee, 0x6c, 0xf2, 0x38, 0x73, 0xe9, 0x65, 0x2e, 0x7f, 0x63, 0x4d, 0xab, 0x58, 0xd3, 0x07, 0x26, 0xfc, 0x1b, 0x6b, 0x5b, 0x13, 0x71, 0x54, 0x96, 0x32, 0x9f, 0x6e, 0xe6, 0xf3, 0x38, 0xf3, 0x79, 0x9c, 0xf9, 0x3c, 0x6e, 0xb9, 0x9b, 0xf9, 0x1d, 0x0c, 0x43, 0xb8, 0x7d, 0x0f, 0x0c, 0xe5, 0xf6, 0x30, 0xb8, 0x97, 0xdb, 0xf7, 0xc1, 0x70, 0x18, 0x01, 0x23, 0x61, 0x14, 0xdc, 0x0f, 0xa3, 0xf9, 0xfb, 0x18, 0x18, 0xcb,\n\t0xed, 0x07, 0x60, 0x1c, 0xb7, 0x1f, 0x84, 0x87, 0xb8, 0x3d, 0x59, 0x6e, 0x61, 0x4f, 0xdf, 0x64, 0x2f, 0xdf, 0x60, 0xfc, 0xb6, 0xb2, 0xa7, 0xf5, 0xd8, 0xd3, 0x4c, 0xf6, 0x34, 0x93, 0x3d, 0xcd, 0x54, 0x16, 0x57, 0xfd, 0xba, 0x31, 0xda, 0x50, 0x8a, 0x36, 0x94, 0x8a, 0x26, 0x74, 0xd9, 0x39, 0xec, 0x7d, 0x0e, 0xdd, 0xf5, 0x09, 0xba, 0x6a, 0x07, 0x1d, 0x5b, 0x06, 0xdd, 0x5a, 0x06, 0x5d, 0x59, 0x06, 0x5d, 0x99, 0xc3, 0xb8, 0x7a, 0xc6, 0x14, 0x5c, 0xe0, 0x30, 0x99, 0x83, 0x7b, 0xcb, 0xc1, 0xbd, 0xe5, 0xe0, 0xde, 0x72, 0x70, 0x6f, 0x39, 0xb8, 0xb7, 0x1c, 0xdc, 0x5b, 0x0e, 0x2e, 0xeb, 0x04, 0x2e, 0xeb, 0x04, 0x2e, 0xca, 0x81, 0x8b, 0x72, 0xe0, 0xa2, 0x1c, 0xb8, 0x28, 0x07, 0x2e, 0xca, 0x81, 0x8b, 0x72, 0xe0, 0xa2, 0x1c, 0xb8, 0x28, 0x07, 0x2e, 0xca, 0xc1, 0xd6, 0xfd, 0x62,\n\t0x9e, 0xb0, 0x48, 0x87, 0x50, 0xa0, 0x26, 0x34, 0x64, 0x3f, 0xae, 0x61, 0x19, 0x07, 0x4d, 0xa0, 0x39, 0xec, 0x83, 0x83, 0x50, 0x75, 0x26, 0xf5, 0xb0, 0x71, 0x16, 0x35, 0x9f, 0xbd, 0x19, 0x00, 0x83, 0x64, 0x29, 0x7d, 0xe4, 0x1d, 0xf4, 0x91, 0x0e, 0xf3, 0x60, 0x51, 0x8f, 0x3e, 0xb2, 0x0f, 0x7d, 0xa4, 0xc3, 0x7c, 0x9f, 0x3c, 0x46, 0xff, 0xe8, 0x88, 0x30, 0xc9, 0xf4, 0x08, 0xb3, 0xdc, 0x15, 0x11, 0x21, 0xb5, 0x88, 0x48, 0x88, 0x02, 0x15, 0xac, 0xf2, 0x58, 0x44, 0x8c, 0x4c, 0x8e, 0xa8, 0xc1, 0x3c, 0xd4, 0xe1, 0x76, 0x5d, 0x99, 0x12, 0x51, 0x4f, 0x1e, 0x8f, 0xa8, 0xcf, 0xdf, 0xae, 0xe2, 0x75, 0x57, 0xcb, 0xd4, 0x88, 0x38, 0xb9, 0x3f, 0xa2, 0x09, 0x7f, 0x6b, 0xc9, 0x63, 0xad, 0xa1, 0x8d, 0xdc, 0x13, 0x31, 0x46, 0xee, 0x8c, 0x58, 0xce, 0xdf, 0xf5, 0x33, 0xa9, 0x36, 0xe9,\n\t0x8b, 0xd8, 0x0f, 0xfa, 0xd9, 0xd4, 0x0c, 0xfe, 0x9e, 0x29, 0xb5, 0xea, 0x67, 0x33, 0xa3, 0x9a, 0xc9, 0x54, 0x7a, 0x3c, 0x87, 0x7e, 0xc6, 0x32, 0xaa, 0x42, 0x3a, 0xa2, 0x23, 0xa5, 0x93, 0xbe, 0xc9, 0x41, 0xdf, 0xe4, 0xa0, 0x6f, 0x72, 0xd0, 0x37, 0x39, 0xf4, 0xb3, 0x97, 0x96, 0x67, 0xe1, 0x39, 0x58, 0x01, 0x2b, 0x61, 0x15, 0x7c, 0x0d, 0xab, 0x61, 0x0d, 0xac, 0x85, 0xf5, 0x62, 0x8a, 0x65, 0x9f, 0xe8, 0x64, 0xb1, 0x89, 0xee, 0x96, 0xfd, 0x22, 0xce, 0x72, 0x40, 0x58, 0x89, 0xc4, 0x59, 0x96, 0x54, 0x6e, 0x1f, 0x85, 0x74, 0xd1, 0xd6, 0x92, 0x29, 0xe2, 0xe8, 0x0d, 0x1c, 0xf4, 0x06, 0x0e, 0x7a, 0x03, 0x07, 0xbd, 0x81, 0x83, 0xde, 0xc0, 0x41, 0x6f, 0xe0, 0xa0, 0x37, 0x70, 0xd0, 0x1b, 0x38, 0x94, 0x06, 0xd0, 0x50, 0x5c, 0x67, 0x9c, 0x31, 0xbd, 0x1a, 0x1a, 0x41, 0x63, 0x60,\n\t0xcc, 0xe9, 0x13, 0x1c, 0xf4, 0x09, 0x0e, 0xfa, 0x04, 0x07, 0x7d, 0x82, 0x83, 0x3e, 0xc1, 0x41, 0x9f, 0xe0, 0xa0, 0x4f, 0x70, 0xd0, 0x27, 0x38, 0xe8, 0x13, 0x1c, 0xf4, 0x09, 0x0e, 0xfa, 0x04, 0x07, 0x7d, 0x82, 0x83, 0x3e, 0xc1, 0x41, 0x9f, 0xe0, 0xa0, 0x4f, 0x70, 0x28, 0x44, 0x8b, 0xd2, 0x81, 0x0c, 0xe8, 0xc4, 0xb2, 0x33, 0xcb, 0x2e, 0xd0, 0x95, 0xdb, 0xdd, 0xc2, 0x67, 0x66, 0xbb, 0xc3, 0xeb, 0x62, 0x87, 0xb5, 0xb1, 0x68, 0x6d, 0xdd, 0x24, 0x1d, 0xd6, 0x43, 0x52, 0xa3, 0xce, 0x39, 0xa8, 0x73, 0x0e, 0xea, 0x9c, 0x83, 0x3a, 0xe7, 0xa0, 0xce, 0x39, 0x62, 0x3e, 0x22, 0x27, 0x37, 0x33, 0xbf, 0x3d, 0x45, 0x84, 0xf4, 0x89, 0x48, 0x88, 0x92, 0xc5, 0x44, 0x88, 0x9d, 0x08, 0xb1, 0x13, 0x21, 0x76, 0x22, 0x44, 0x3f, 0x63, 0x64, 0x27, 0x42, 0xec, 0x44, 0x88, 0x9d, 0x08, 0xb1,\n\t0x8b, 0x96, 0x3c, 0xaf, 0x15, 0xb4, 0x95, 0x9a, 0xb8, 0x16, 0xda, 0x71, 0xbb, 0x3d, 0xec, 0x45, 0x4d, 0xf7, 0xf1, 0x77, 0x66, 0x8a, 0x08, 0x3a, 0x24, 0x0e, 0xf3, 0xb7, 0x00, 0x84, 0x78, 0xec, 0x3c, 0x91, 0x56, 0x75, 0x5e, 0x5e, 0x23, 0xa2, 0xec, 0x44, 0x94, 0xdd, 0x74, 0x46, 0x6a, 0xc4, 0xbc, 0x9f, 0xc8, 0xb2, 0x13, 0xf7, 0x7e, 0xe3, 0x8a, 0x31, 0x83, 0xe4, 0x71, 0x22, 0x6c, 0x2c, 0x11, 0x66, 0x27, 0xc2, 0xea, 0x98, 0x87, 0x12, 0x71, 0xc3, 0xc4, 0x08, 0xa2, 0xcc, 0x4e, 0x94, 0xd9, 0xc9, 0x0d, 0xbf, 0x79, 0x34, 0x8f, 0x8d, 0xe5, 0xb9, 0xe3, 0xb9, 0x3f, 0x89, 0xfb, 0x8f, 0x18, 0x57, 0x85, 0xf7, 0x99, 0x1f, 0x67, 0x79, 0x41, 0x1e, 0x35, 0x4b, 0x99, 0x46, 0x24, 0xa6, 0x10, 0x89, 0x9b, 0x88, 0xc4, 0xc3, 0x44, 0xe2, 0x61, 0x22, 0xf1, 0x70, 0x84, 0x42, 0x74, 0xa9, 0x2c,\n\t0xad, 0xfc, 0x2d, 0x46, 0xfe, 0x4a, 0x34, 0xee, 0x21, 0x1a, 0x93, 0x89, 0xc6, 0xdd, 0x44, 0xe3, 0x7e, 0xa2, 0xf1, 0x30, 0xd1, 0x78, 0x80, 0x68, 0xdc, 0x45, 0x34, 0x26, 0x13, 0x8d, 0xf6, 0x88, 0xa6, 0xb2, 0x24, 0xa2, 0x19, 0x8f, 0xb5, 0xe4, 0x6f, 0xad, 0xe4, 0x51, 0x22, 0xf3, 0x30, 0x91, 0xb9, 0x23, 0xa2, 0xad, 0x3c, 0x42, 0x74, 0x6e, 0x25, 0x3a, 0xed, 0x44, 0xa7, 0x1d, 0x95, 0xf1, 0x11, 0xa1, 0x99, 0x44, 0x68, 0x66, 0xc4, 0x11, 0x23, 0x4a, 0xed, 0x44, 0xe9, 0x51, 0xa2, 0xf4, 0x28, 0x51, 0x6a, 0x27, 0x4a, 0xed, 0x44, 0xa9, 0x9d, 0x28, 0xdd, 0x4d, 0x94, 0xda, 0xa3, 0x18, 0x17, 0x22, 0xd5, 0x4e, 0xa4, 0xda, 0x89, 0xd4, 0x93, 0x16, 0xc6, 0xcf, 0xd2, 0x01, 0x3a, 0x42, 0x27, 0xe8, 0x0c, 0x5d, 0xa0, 0x2b, 0x74, 0x83, 0x1b, 0xa0, 0x3b, 0xf4, 0x80, 0x78, 0xe8, 0x09, 0x37,\n\t0xc2, 0x4d, 0xd0, 0x0b, 0x7a, 0x43, 0x1f, 0xe8, 0x0b, 0x37, 0xc3, 0x2d, 0x70, 0x2b, 0xf4, 0x83, 0xfe, 0x70, 0x1b, 0x0c, 0x80, 0xdb, 0x61, 0x20, 0xdc, 0x01, 0x8c, 0x37, 0x4a, 0xe8, 0x43, 0x09, 0x7d, 0x28, 0xa1, 0x0f, 0x25, 0xf4, 0xa1, 0x84, 0x3e, 0x94, 0xd0, 0x87, 0x12, 0xfa, 0x50, 0x42, 0x1f, 0x4a, 0xe8, 0x43, 0x09, 0x7d, 0x28, 0xa1, 0x0f, 0x25, 0xf4, 0xa1, 0x84, 0x3e, 0x94, 0xd0, 0x87, 0x12, 0xfa, 0x50, 0x42, 0x1f, 0x4a, 0xe8, 0x43, 0x09, 0x7d, 0x28, 0xa1, 0x0f, 0x25, 0xf4, 0xa1, 0x84, 0x3e, 0xcb, 0x78, 0x98, 0x00, 0x13, 0xe1, 0x61, 0x59, 0x6c, 0x99, 0x24, 0xf5, 0xef, 0xd7, 0x17, 0x93, 0x8d, 0x76, 0xb2, 0xd1, 0x4e, 0x36, 0xda, 0xc9, 0x46, 0x3b, 0xd9, 0x68, 0x27, 0x1b, 0xed, 0x64, 0xa3, 0x9d, 0x6c, 0xb4, 0x93, 0x8d, 0x76, 0xb2, 0xd1, 0x4e, 0x36, 0xda, 0xc9, 0x46,\n\t0x3b, 0xd9, 0x68, 0x27, 0x1b, 0xed, 0xe1, 0x6c, 0xbc, 0x81, 0x6c, 0xec, 0x45, 0x36, 0xf6, 0x20, 0x1b, 0x6b, 0x85, 0xb3, 0xb1, 0x07, 0xd9, 0xd8, 0xc3, 0x92, 0x26, 0xda, 0x19, 0x19, 0x99, 0x41, 0x96, 0x66, 0x8a, 0x1e, 0x64, 0xa5, 0x9d, 0xac, 0xb4, 0x93, 0x95, 0x76, 0xb2, 0xd2, 0x4e, 0x56, 0xda, 0xc9, 0x4a, 0x3b, 0x59, 0x69, 0x27, 0x2b, 0xed, 0x64, 0xa5, 0x9d, 0xac, 0x6c, 0x47, 0x56, 0xda, 0xc9, 0x4a, 0x3b, 0x59, 0x69, 0x27, 0x2b, 0xed, 0x64, 0xa5, 0x9d, 0xac, 0xb4, 0x93, 0x95, 0x76, 0xb2, 0xd2, 0x4e, 0x56, 0xda, 0xc9, 0x4a, 0x3b, 0x59, 0x69, 0x27, 0x2b, 0xed, 0x64, 0xa5, 0x9d, 0xac, 0xb4, 0x93, 0x95, 0x76, 0xb2, 0xd2, 0x4e, 0x56, 0xda, 0xc9, 0x4a, 0x3b, 0x59, 0x69, 0x27, 0x2b, 0xed, 0x64, 0xa5, 0x9d, 0xac, 0x2c, 0x24, 0x2b, 0xed, 0x64, 0x65, 0x21, 0x59, 0x59, 0x48,\n\t0x56, 0xda, 0xc9, 0x4a, 0x3b, 0x59, 0x69, 0x27, 0x2b, 0xed, 0x74, 0xeb, 0x3e, 0xba, 0x75, 0x1f, 0xdd, 0xba, 0x8f, 0x6e, 0xdd, 0xa7, 0x30, 0xfe, 0x74, 0xec, 0x3e, 0x3a, 0x76, 0x1f, 0x1d, 0xbb, 0x8f, 0x8e, 0xdd, 0x47, 0xc7, 0xee, 0xa3, 0x2b, 0xd7, 0xe8, 0xca, 0x35, 0xba, 0x72, 0x8d, 0xae, 0x5c, 0xa3, 0x2b, 0xd7, 0xe8, 0xca, 0x35, 0x45, 0x7f, 0x0f, 0x78, 0x22, 0x3c, 0x0c, 0x93, 0x60, 0x32, 0x10, 0xff, 0x74, 0xe5, 0x1a, 0x5d, 0xb9, 0x46, 0x57, 0xae, 0xd1, 0x95, 0x6b, 0x74, 0xe5, 0x1a, 0x5d, 0xb9, 0x46, 0x57, 0xae, 0xd1, 0x95, 0x6b, 0x74, 0xe5, 0x1a, 0x5d, 0xb9, 0x46, 0xbd, 0xf0, 0x51, 0x2f, 0x7c, 0xd4, 0x0b, 0x1f, 0xf5, 0xc2, 0x47, 0xbd, 0xf0, 0x51, 0x2f, 0x7c, 0xca, 0x6b, 0xf0, 0xba, 0xd8, 0xa0, 0xcc, 0x61, 0x39, 0x17, 0xde, 0x80, 0x79, 0x30, 0x1f, 0xde, 0x84, 0x05,\n\t0xf0, 0x0e, 0xbc, 0x0b, 0xef, 0xc1, 0xfb, 0x90, 0x28, 0x7d, 0x28, 0x4c, 0x43, 0x6b, 0x1c, 0xea, 0xd2, 0x04, 0x9a, 0x42, 0x33, 0x68, 0x0e, 0x2d, 0x00, 0x25, 0xb7, 0xb6, 0x02, 0xd4, 0xdc, 0xda, 0x06, 0xd0, 0x0b, 0x2b, 0x7a, 0x61, 0x6d, 0x07, 0xd7, 0xc1, 0xf5, 0xd0, 0x1e, 0x3a, 0x40, 0x47, 0xe8, 0x04, 0x3f, 0xc2, 0x26, 0x69, 0xb7, 0x6e, 0x96, 0xa5, 0xd6, 0x2d, 0xb0, 0x15, 0xb6, 0xc1, 0x76, 0x1e, 0x3f, 0x24, 0x0f, 0xa3, 0x62, 0x76, 0x54, 0xcc, 0x8e, 0x8a, 0xd9, 0x51, 0x31, 0x3b, 0x2a, 0x66, 0xb7, 0xea, 0xd7, 0x38, 0xf0, 0x81, 0x1f, 0xf4, 0xcf, 0x7f, 0x94, 0xa2, 0x6a, 0x1f, 0xc9, 0xc3, 0x31, 0x9b, 0xa4, 0x0f, 0x75, 0xb3, 0x8b, 0x73, 0xa8, 0x9b, 0x86, 0xba, 0x69, 0xa8, 0x9b, 0xef, 0xb2, 0xfa, 0x57, 0xfc, 0xa7, 0xfa, 0x77, 0x51, 0xdd, 0xda, 0xa1, 0x58, 0xec, 0x1d, 0xaa,\n\t0xa6, 0x19, 0x35, 0xd1, 0xc6, 0xf2, 0xa0, 0x3c, 0x16, 0x56, 0x34, 0xbd, 0x36, 0x1e, 0x41, 0xcd, 0xfc, 0x97, 0xea, 0x63, 0x3f, 0xd4, 0x47, 0xaf, 0x91, 0xb7, 0xb3, 0xbc, 0x13, 0x06, 0xc9, 0x93, 0x28, 0xd9, 0xfd, 0xe1, 0x5a, 0x59, 0x17, 0x15, 0xbb, 0x2f, 0x5c, 0x2b, 0x1d, 0xa8, 0x98, 0x86, 0x82, 0x69, 0x7a, 0xcd, 0x44, 0xc1, 0x74, 0xf5, 0xd2, 0x95, 0xcb, 0x83, 0x72, 0x15, 0xa0, 0x5c, 0xfb, 0x51, 0xae, 0x1d, 0x28, 0x57, 0x1a, 0xca, 0x95, 0x86, 0x72, 0xa5, 0xa1, 0x5c, 0x05, 0x28, 0x57, 0x1a, 0xca, 0x75, 0x00, 0xe5, 0xda, 0x8e, 0x72, 0x1d, 0x40, 0xb9, 0xf6, 0xa3, 0x5c, 0xfb, 0x51, 0xae, 0x54, 0x94, 0x2b, 0x2d, 0x5c, 0x47, 0x0f, 0xa0, 0x5c, 0x76, 0x94, 0xeb, 0x38, 0xca, 0xe5, 0x47, 0xb9, 0x52, 0x51, 0xae, 0x34, 0x94, 0xcb, 0x83, 0x72, 0xa5, 0xa1, 0x5c, 0xfb, 0x50, 0xae,\n\t0x63, 0x28, 0xd7, 0xae, 0x4b, 0x75, 0x75, 0x17, 0xb5, 0xf4, 0xe2, 0xf7, 0x04, 0x8e, 0x70, 0xbb, 0xaa, 0xbe, 0x66, 0xa2, 0x5c, 0x99, 0x97, 0xd5, 0xd7, 0x83, 0x46, 0x7d, 0xad, 0x52, 0xae, 0x8b, 0x35, 0xf6, 0x14, 0xca, 0xa5, 0xa1, 0x5c, 0x1a, 0xca, 0xa5, 0xa1, 0x5c, 0x1a, 0xca, 0xa5, 0xa1, 0x5c, 0x1a, 0xca, 0xa5, 0xa1, 0x5c, 0x1a, 0xca, 0xa5, 0xa1, 0x5c, 0x1a, 0xca, 0x55, 0xf5, 0x49, 0x86, 0x9e, 0x70, 0x23, 0xdc, 0x04, 0xbd, 0xa0, 0x37, 0xf4, 0x81, 0xbe, 0x70, 0x33, 0xdc, 0x02, 0xb7, 0x02, 0xe3, 0x89, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86,\n\t0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0x97, 0x86, 0x72, 0x69, 0x28, 0xd7, 0xa5, 0x4f, 0x59, 0xa0, 0x5c, 0x1a, 0xca, 0xe5, 0x43, 0xb9, 0x7c, 0x28, 0x97, 0xef, 0x7f, 0xe0, 0x23, 0x1e, 0x45, 0xb9, 0xba, 0xa0, 0x5c, 0x3d, 0x50, 0xae, 0x6e, 0x28, 0x57, 0x0d, 0x94, 0x6b, 0x06, 0xca, 0xd5, 0x0d, 0xe5, 0xea, 0x86, 0x72, 0xb5, 0x41, 0xb9, 0x5a, 0xa1, 0x5c, 0x0a, 0xca, 0xd5, 0xed, 0xdf, 0xf4, 0x13, 0xed, 0xff, 0x5f, 0xf2, 0x13, 0x25, 0x61, 0x3f, 0x51, 0x82, 0x72, 0x95, 0xfc, 0xc9, 0x4f, 0xfc, 0xbb, 0xca, 0xf5, 0x8c, 0x2c, 0x45, 0x61, 0x4a, 0x51, 0x18, 0x0d, 0x85, 0xd1, 0x50, 0x18, 0x0d, 0x85, 0xd1, 0x50, 0x18, 0x2d, 0xac, 0x30, 0x1a, 0x0a, 0xa3, 0xa1, 0x30, 0x1a, 0x0a, 0xa3, 0xa1, 0x30, 0x1a, 0x0a, 0xa3,\n\t0xa1, 0x30, 0x1a, 0x0a, 0xa3, 0xa1, 0x30, 0x1a, 0x0a, 0xa3, 0xa1, 0x30, 0x1a, 0x0a, 0xa3, 0xa1, 0x30, 0xad, 0xc2, 0xaa, 0xe0, 0x40, 0x05, 0xfc, 0xa8, 0x40, 0xda, 0x5f, 0x78, 0x99, 0x34, 0x32, 0xde, 0xf0, 0x33, 0xa2, 0x01, 0xde, 0x5a, 0xc3, 0x5b, 0x6b, 0x64, 0xb0, 0x8b, 0x4c, 0x73, 0x91, 0x61, 0x2e, 0x7c, 0xb4, 0x86, 0x8f, 0xd6, 0xf0, 0xd1, 0x1a, 0x3e, 0x5a, 0xc3, 0x47, 0x6b, 0xf8, 0x68, 0x0d, 0x1f, 0xad, 0xb1, 0xb7, 0x2e, 0xf6, 0xd6, 0xc5, 0xde, 0xba, 0xd8, 0x5b, 0x17, 0x7b, 0xe8, 0x62, 0x0f, 0x5d, 0xec, 0xa1, 0x8b, 0x3d, 0x74, 0xb1, 0x87, 0x2e, 0xe3, 0x53, 0x60, 0xbe, 0xf0, 0xaf, 0x41, 0x95, 0x9a, 0x1e, 0x64, 0xf9, 0x10, 0x3c, 0x2a, 0x0b, 0x4d, 0x0b, 0x64, 0x8a, 0xe9, 0x5d, 0xb4, 0xc4, 0x7c, 0xe9, 0x1a, 0x62, 0x9f, 0x0b, 0xb3, 0xdc, 0x2f, 0xfa, 0xca, 0xf3, 0xe2,\n\t0x66, 0xb8, 0x05, 0x6e, 0x85, 0x7e, 0xd0, 0x1f, 0x6e, 0x83, 0x01, 0x70, 0x3b, 0x0c, 0x84, 0x3b, 0xe0, 0x4e, 0x18, 0x04, 0x77, 0xc1, 0xdd, 0x30, 0x18, 0x86, 0xc0, 0x3d, 0x30, 0x14, 0x86, 0xc1, 0xbd, 0x70, 0x1f, 0x0c, 0x87, 0x11, 0x30, 0x12, 0x46, 0xc1, 0xfd, 0x30, 0x1a, 0xc6, 0xc0, 0x58, 0x78, 0x00, 0xc6, 0xc1, 0x4b, 0x30, 0x5b, 0x9e, 0x13, 0x2f, 0xc3, 0x2b, 0xf0, 0x2a, 0xbc, 0x06, 0xaf, 0xc3, 0x1c, 0x98, 0x0b, 0x6f, 0xc0, 0x3c, 0x58, 0x28, 0x2b, 0xc5, 0x3b, 0xb2, 0x4c, 0xbc, 0x27, 0x83, 0xe1, 0xab, 0x89, 0xa5, 0x99, 0x7a, 0xca, 0xaf, 0x4c, 0xbd, 0xe4, 0x0a, 0x53, 0x6f, 0xa8, 0xba, 0x9a, 0x58, 0x7e, 0xf8, 0x6a, 0x62, 0xf9, 0xa6, 0x5b, 0xe5, 0xc7, 0xa6, 0x7e, 0x30, 0xd0, 0xf8, 0xec, 0xf4, 0xde, 0xf0, 0xf5, 0xa4, 0xf4, 0x4f, 0x99, 0xed, 0x37, 0x8d, 0x92, 0x1e, 0xc6,\n\t0xa7, 0x90, 0xf1, 0x29, 0x34, 0x4d, 0x96, 0xa7, 0xcc, 0x6c, 0xdb, 0xcc, 0xb6, 0xcd, 0xaf, 0xcb, 0x32, 0xf3, 0x42, 0x58, 0x0a, 0x5f, 0xc8, 0xf3, 0xe6, 0x2f, 0xe1, 0x2b, 0x58, 0x0e, 0x2b, 0x60, 0x25, 0xac, 0x82, 0xaf, 0x61, 0x35, 0xac, 0x81, 0xb5, 0xbc, 0xee, 0x1b, 0x79, 0xee, 0xe2, 0x67, 0x10, 0xa3, 0x92, 0xe4, 0xf9, 0xa8, 0xed, 0x60, 0x87, 0x83, 0x70, 0x08, 0x0e, 0x43, 0xaa, 0x3c, 0x1f, 0xdd, 0x56, 0x9e, 0x53, 0x0a, 0xe5, 0x79, 0xa5, 0x18, 0x4a, 0xc0, 0x07, 0x7e, 0xd0, 0xa0, 0x14, 0xca, 0x20, 0x00, 0x41, 0x38, 0x0b, 0xe5, 0x50, 0x01, 0x95, 0x10, 0x82, 0x73, 0x70, 0x1e, 0x2e, 0xc8, 0xf3, 0xea, 0x47, 0xf2, 0x9c, 0xfa, 0x31, 0x7c, 0x02, 0x4b, 0x60, 0x29, 0x2c, 0x83, 0x4f, 0xe1, 0x33, 0xf8, 0x1c, 0xbe, 0x80, 0x2f, 0xe1, 0x2b, 0x58, 0x0e, 0x2b, 0x60, 0x25, 0xac, 0x82,\n\t0xaf, 0x61, 0x35, 0xac, 0x01, 0x8e, 0x41, 0xe5, 0x18, 0xd4, 0x75, 0xb0, 0x1e, 0xbe, 0x85, 0xef, 0xe0, 0x7b, 0xf8, 0x01, 0x36, 0xc0, 0x8f, 0xf0, 0x13, 0xfc, 0x0c, 0x1b, 0xe1, 0x17, 0xf8, 0x15, 0x36, 0xc1, 0x66, 0xd8, 0x02, 0x5b, 0x61, 0x1b, 0x9c, 0x96, 0x95, 0x6a, 0x2e, 0x94, 0xca, 0x32, 0xb5, 0x0c, 0x02, 0x10, 0x84, 0xb3, 0x50, 0xce, 0x1c, 0x46, 0x84, 0x7f, 0x23, 0x5b, 0xff, 0xad, 0xea, 0x4c, 0x11, 0x79, 0xe9, 0x37, 0xa7, 0xc3, 0xbf, 0x64, 0x66, 0x3a, 0x49, 0x15, 0x0c, 0x50, 0x05, 0x03, 0x54, 0xc1, 0x00, 0x15, 0x30, 0x40, 0x05, 0x0c, 0x50, 0x01, 0x03, 0x54, 0xc0, 0x80, 0xa0, 0x36, 0x8b, 0x8e, 0xf2, 0xa4, 0xe8, 0x04, 0x9d, 0xa1, 0x8b, 0x74, 0x8b, 0xae, 0xd0, 0x0d, 0x6e, 0x80, 0xee, 0xd0, 0x03, 0xe2, 0xa1, 0x97, 0xcc, 0x16, 0xbd, 0x59, 0xf6, 0x81, 0xbe, 0x6c, 0xeb,\n\t0x66, 0xb8, 0x05, 0x6e, 0x85, 0x7e, 0xd0, 0x1f, 0x6e, 0x83, 0x01, 0x70, 0x3b, 0x0c, 0x84, 0x3b, 0xe0, 0x4e, 0x18, 0x04, 0x77, 0xc1, 0xdd, 0x30, 0x18, 0x86, 0xc0, 0x3d, 0x30, 0x14, 0x86, 0xc1, 0xbd, 0x70, 0x1f, 0x0c, 0x87, 0x11, 0xa0, 0x1f, 0xcb, 0x28, 0xb8, 0x1f, 0x46, 0xc3, 0x18, 0x18, 0x0b, 0x0f, 0xc0, 0x38, 0x78, 0x48, 0xbf, 0xb6, 0x22, 0xfb, 0x31, 0x01, 0x26, 0xc2, 0xc3, 0xdc, 0x9f, 0x04, 0x93, 0xe1, 0x11, 0x7a, 0x93, 0x47, 0x59, 0x3e, 0x06, 0x53, 0xf8, 0xdb, 0xe3, 0xf0, 0x04, 0x3c, 0x09, 0x4f, 0xc1, 0x54, 0x98, 0x06, 0x4f, 0xc3, 0x33, 0xf0, 0x2c, 0x3c, 0x07, 0xd3, 0xe1, 0x79, 0x78, 0x11, 0x5e, 0x62, 0x1b, 0xb3, 0x65, 0x90, 0x6c, 0x0a, 0x92, 0x4d, 0x41, 0xb2, 0x29, 0x48, 0x36, 0x05, 0xc9, 0xa6, 0x20, 0xd9, 0x14, 0x24, 0x9b, 0x82, 0x64, 0x53, 0x90, 0x6c, 0x0a,\n\t0x0a, 0x34, 0x43, 0xe8, 0x9a, 0xb1, 0x40, 0xe6, 0x8a, 0xb7, 0x78, 0x6d, 0xd5, 0xd5, 0x8a, 0x73, 0xc9, 0xb0, 0x3c, 0xdc, 0x42, 0xc0, 0xe4, 0x96, 0x6e, 0x93, 0x07, 0x5d, 0x1a, 0x20, 0x03, 0x38, 0x84, 0x00, 0xce, 0x20, 0x80, 0x1b, 0x08, 0x98, 0xd9, 0xb6, 0x99, 0x6d, 0x9b, 0xd9, 0xae, 0x79, 0x26, 0xcc, 0x82, 0xd9, 0xc0, 0xf6, 0xc8, 0xa0, 0x20, 0x19, 0x94, 0x67, 0xc6, 0x8f, 0x91, 0x45, 0x79, 0xe6, 0xc5, 0x32, 0xd7, 0xfc, 0x09, 0x7f, 0x5b, 0x02, 0x4b, 0xb9, 0xff, 0x85, 0xcc, 0x24, 0xa3, 0x32, 0xc9, 0xa8, 0x4c, 0x32, 0x2a, 0x93, 0x8c, 0xca, 0x24, 0xa3, 0x32, 0xc9, 0xa8, 0x4c, 0x32, 0x2a, 0x93, 0x8c, 0xca, 0x24, 0xa3, 0x32, 0xc9, 0xa8, 0x20, 0x19, 0x15, 0x34, 0x7f, 0x2f, 0xbd, 0xe6, 0x5f, 0xa4, 0x33, 0x92, 0x71, 0x8b, 0x4c, 0x90, 0xee, 0xa8, 0xfa, 0x90, 0x24, 0x33, 0xc9,\n\t0xae, 0xcc, 0xa8, 0x64, 0xe9, 0x89, 0xa2, 0xa7, 0x21, 0xcb, 0x32, 0xc9, 0xb2, 0x4c, 0xb2, 0x2c, 0x93, 0x2c, 0xcb, 0x24, 0xcb, 0x32, 0x71, 0x01, 0x81, 0xa8, 0xd3, 0x3c, 0xb7, 0x50, 0xba, 0xa2, 0x5b, 0x49, 0x77, 0x74, 0x6b, 0x68, 0x2b, 0x83, 0xd1, 0x15, 0xd2, 0x4d, 0xa5, 0x0c, 0x50, 0x29, 0x03, 0x54, 0xca, 0x00, 0x95, 0x32, 0x40, 0x85, 0x0c, 0x50, 0x21, 0x03, 0x54, 0xc8, 0x00, 0x15, 0x32, 0x40, 0x85, 0x0c, 0x50, 0x21, 0x03, 0x54, 0xc8, 0x00, 0x15, 0x32, 0x40, 0xc5, 0x0b, 0x50, 0xf1, 0x02, 0x54, 0xbc, 0x00, 0x15, 0x2f, 0x40, 0xc5, 0x0b, 0x50, 0xf1, 0x02, 0x54, 0xbc, 0x00, 0x15, 0x2f, 0x40, 0x95, 0x0b, 0x50, 0xe5, 0x02, 0x54, 0xb9, 0x00, 0x55, 0x2e, 0x40, 0x95, 0x0b, 0x50, 0xe5, 0x02, 0x54, 0xb9, 0x00, 0x55, 0x2e, 0x40, 0x95, 0x0b, 0x50, 0xe5, 0x02, 0x54, 0xb9, 0x00,\n\t0x55, 0x2e, 0x40, 0x95, 0x0b, 0x50, 0xe5, 0x02, 0x54, 0xb9, 0x00, 0x55, 0x2e, 0x40, 0x95, 0x0b, 0x50, 0xe5, 0x02, 0x54, 0xb9, 0x00, 0x55, 0x2c, 0xa0, 0x3c, 0x87, 0xd6, 0x4f, 0x87, 0x04, 0x78, 0x1e, 0x5e, 0x80, 0x19, 0xf0, 0xb1, 0x3c, 0xa9, 0x7c, 0x02, 0x4b, 0x60, 0x29, 0x2c, 0x83, 0x4f, 0xe1, 0x33, 0xf8, 0x1c, 0xbe, 0x80, 0xaf, 0x60, 0x39, 0xac, 0x80, 0x95, 0xb0, 0x0a, 0xbe, 0x86, 0xd5, 0xb0, 0x06, 0xd6, 0xc2, 0x37, 0xb0, 0x0e, 0xd6, 0xc3, 0xb7, 0xf0, 0x1d, 0x7c, 0x0f, 0x3f, 0xc0, 0x06, 0xd8, 0x08, 0xbf, 0xc0, 0xaf, 0xb0, 0x09, 0x36, 0xc3, 0x56, 0xe9, 0x56, 0xb6, 0xc1, 0x6f, 0xb0, 0x1d, 0x76, 0xc0, 0x4e, 0x48, 0x86, 0x3d, 0x70, 0x08, 0x0e, 0x43, 0x2a, 0x1c, 0x81, 0xa3, 0xe0, 0x80, 0x63, 0x70, 0x1c, 0x32, 0xe1, 0x04, 0x9c, 0x84, 0x2c, 0xc8, 0x86, 0x1c, 0x38, 0x05,\n\t0xcc, 0x93, 0x92, 0x0b, 0x4e, 0x70, 0x41, 0x3e, 0x9c, 0x01, 0xe2, 0x4f, 0x29, 0x00, 0x2f, 0x14, 0xca, 0x4c, 0x45, 0xff, 0x66, 0x46, 0x09, 0xf8, 0xc0, 0x0f, 0x1a, 0x94, 0x42, 0x19, 0x04, 0x20, 0x08, 0x67, 0xa1, 0x1c, 0x2a, 0xa0, 0x12, 0x42, 0x70, 0x0e, 0xce, 0xc3, 0x05, 0x99, 0xa9, 0x46, 0x4b, 0x8f, 0x6a, 0x01, 0x05, 0x54, 0x88, 0x85, 0x9a, 0x50, 0x0b, 0x6a, 0x4b, 0xb7, 0x5a, 0x07, 0xea, 0x42, 0x3d, 0x20, 0xd6, 0xd4, 0x06, 0x70, 0x15, 0x7f, 0x6b, 0x04, 0x8d, 0x21, 0x0e, 0x9a, 0x40, 0x53, 0x59, 0xa1, 0x36, 0x63, 0xd9, 0x1c, 0x5a, 0x40, 0x4b, 0x68, 0x03, 0x6d, 0xa1, 0x1d, 0x74, 0x80, 0x8e, 0xd0, 0x19, 0xba, 0xca, 0x0b, 0x2a, 0x9a, 0xa4, 0xa2, 0x49, 0x2a, 0x9a, 0xa4, 0xa2, 0x49, 0x6a, 0x4f, 0xe8, 0x05, 0xe8, 0x92, 0x8a, 0x2e, 0xa9, 0x7d, 0xe1, 0x66, 0xb8, 0x05, 0x6e,\n\t0x85, 0x7e, 0xd0, 0x1f, 0x06, 0xc0, 0xed, 0x30, 0x10, 0x06, 0xc1, 0x5d, 0x70, 0x37, 0x0c, 0x86, 0x21, 0x70, 0x0f, 0x0c, 0x85, 0x61, 0x70, 0x2f, 0x0c, 0x87, 0x11, 0x30, 0x12, 0x46, 0xc1, 0xfd, 0x30, 0x1a, 0xc6, 0xc0, 0x58, 0x78, 0x00, 0xd0, 0x1f, 0x15, 0xfd, 0x51, 0xd1, 0x1f, 0xf5, 0x61, 0x98, 0x04, 0x93, 0xe1, 0x11, 0x78, 0x14, 0x1e, 0x03, 0xf4, 0x47, 0x45, 0x7f, 0x54, 0xf4, 0x47, 0x45, 0x7f, 0x54, 0xf4, 0x47, 0x45, 0x7f, 0x54, 0xf4, 0x47, 0x25, 0xe7, 0x55, 0x72, 0x5e, 0x45, 0x6f, 0x54, 0xf2, 0x5e, 0x7d, 0x19, 0x5e, 0x87, 0x39, 0x30, 0x17, 0xde, 0x80, 0x79, 0x30, 0x1f, 0xde, 0x04, 0xb4, 0x45, 0x5d, 0x08, 0x1f, 0xc9, 0x20, 0xd5, 0x2a, 0x48, 0xb5, 0x0a, 0x52, 0xad, 0x82, 0x54, 0xab, 0x20, 0xd5, 0x2a, 0x48, 0xb5, 0x0a, 0x52, 0xad, 0x82, 0x54, 0xab, 0x20, 0xd5, 0x2a,\n\t0x48, 0xb5, 0x0a, 0x52, 0xad, 0x82, 0x54, 0xab, 0x20, 0xd5, 0x2a, 0x48, 0xb5, 0x0a, 0x52, 0xad, 0x82, 0x54, 0xab, 0x20, 0xd5, 0x2a, 0x48, 0xb5, 0x0a, 0x52, 0xad, 0x82, 0x54, 0xab, 0x20, 0xd5, 0x2a, 0x48, 0xb5, 0x0a, 0x52, 0xad, 0x82, 0x54, 0xab, 0x20, 0xd5, 0x2a, 0x48, 0xb5, 0x0a, 0x52, 0xad, 0x82, 0x54, 0xab, 0x20, 0xd5, 0x2a, 0x48, 0xb5, 0x0a, 0x52, 0xad, 0x82, 0x54, 0xab, 0x20, 0xd5, 0x2a, 0x48, 0xb5, 0x0a, 0x52, 0xad, 0x82, 0x54, 0xab, 0x20, 0xd5, 0x2a, 0x48, 0xb5, 0x0a, 0xaa, 0xbf, 0x49, 0x97, 0x9a, 0x04, 0xdb, 0x61, 0x07, 0xec, 0x84, 0x64, 0xd8, 0x05, 0xbb, 0x61, 0x0f, 0xec, 0x85, 0x7d, 0x60, 0x83, 0xfd, 0x70, 0x00, 0xec, 0x70, 0x10, 0x0e, 0xc1, 0x61, 0x48, 0x85, 0x23, 0xe0, 0x80, 0x63, 0x70, 0x5c, 0xe6, 0xaa, 0x69, 0x90, 0xc1, 0xf1, 0x93, 0x03, 0x2a, 0x39,\n\t0xa0, 0x92, 0x03, 0x2a, 0x39, 0xa0, 0x92, 0x03, 0x2a, 0x39, 0x50, 0xed, 0x2a, 0xcb, 0xb9, 0xaa, 0x0b, 0xf2, 0xe1, 0x0c, 0x14, 0x80, 0x17, 0x0a, 0xa1, 0x08, 0x8a, 0xa1, 0x04, 0x4a, 0x65, 0x1e, 0x15, 0x35, 0x8f, 0x8a, 0x9a, 0x47, 0x45, 0xcd, 0xa3, 0xa2, 0xe6, 0x51, 0x51, 0xf3, 0xac, 0xe9, 0xd2, 0x8d, 0xeb, 0x0c, 0xe0, 0x3a, 0x03, 0xb8, 0xce, 0x00, 0xae, 0x33, 0x80, 0xeb, 0xd4, 0xaf, 0xf9, 0xe2, 0xb6, 0x06, 0x20, 0x08, 0x67, 0xa1, 0x1c, 0x2a, 0xa4, 0xcb, 0x5a, 0x09, 0x21, 0x38, 0x07, 0xe7, 0xa9, 0x03, 0xd1, 0xd5, 0x3e, 0x85, 0xbf, 0x2f, 0xf2, 0x03, 0x79, 0x24, 0x7c, 0x35, 0x86, 0x43, 0x97, 0xae, 0x84, 0xa1, 0x5f, 0x63, 0x63, 0xbe, 0x71, 0x1d, 0x0d, 0xfd, 0x91, 0x3b, 0x78, 0xe4, 0x01, 0x1e, 0x79, 0x82, 0x47, 0x1e, 0x33, 0x1e, 0x19, 0xcb, 0x23, 0xd3, 0x78, 0xe4, 0x15,\n\t0x1e, 0xd1, 0xaf, 0xfb, 0x36, 0x48, 0xae, 0x35, 0xfe, 0xdf, 0x6b, 0xfc, 0xff, 0xa3, 0xf1, 0xff, 0x77, 0xc6, 0xff, 0x1b, 0x8c, 0xff, 0x53, 0x8c, 0xff, 0x7f, 0xc6, 0x93, 0x0e, 0x94, 0xc7, 0xb9, 0xb5, 0xc9, 0xb8, 0xbf, 0x8e, 0x75, 0x0d, 0x34, 0xae, 0x63, 0x77, 0x3a, 0xaa, 0x9d, 0xf4, 0x47, 0x75, 0xa2, 0x83, 0x8d, 0xa1, 0x3f, 0x4e, 0xa4, 0x3f, 0x4e, 0xa4, 0x3f, 0x1e, 0x2e, 0xea, 0xc9, 0x17, 0xa8, 0xfe, 0xc5, 0x54, 0xff, 0x62, 0xaa, 0x7f, 0x31, 0x95, 0xdf, 0x41, 0xe5, 0x77, 0x50, 0xf9, 0x1d, 0x54, 0x7e, 0x07, 0x95, 0xdf, 0x41, 0xe5, 0x77, 0x88, 0x9e, 0x6c, 0xf9, 0x46, 0xb8, 0x09, 0x7a, 0x71, 0x1c, 0xbd, 0x79, 0xac, 0x0f, 0xd0, 0x4b, 0x51, 0x89, 0xd3, 0xa9, 0xa4, 0x0e, 0x2a, 0xa9, 0x83, 0x4a, 0xea, 0x10, 0x09, 0x3c, 0xe7, 0x05, 0x7c, 0xc9, 0x0c, 0x98, 0x09, 0xb3, 0xa0,\n\t0xea, 0xd7, 0x59, 0xde, 0x17, 0x15, 0xf2, 0x7d, 0xe3, 0x1b, 0x24, 0xf5, 0xe5, 0x26, 0x53, 0x43, 0x96, 0x8d, 0xe4, 0x7a, 0x53, 0x63, 0xa0, 0x8f, 0x31, 0xd1, 0xbb, 0x98, 0xda, 0xf3, 0x58, 0x07, 0x96, 0xb8, 0x11, 0xfc, 0xe8, 0x75, 0x78, 0x99, 0xeb, 0xf0, 0x32, 0xd7, 0xe1, 0x3f, 0x3b, 0xe2, 0x3f, 0x3b, 0x9a, 0xfa, 0xcb, 0xdd, 0xa6, 0x01, 0x30, 0x50, 0x7e, 0x61, 0xba, 0x0b, 0x1f, 0x3a, 0x18, 0xc6, 0xe3, 0x7c, 0xdc, 0xf4, 0xd6, 0xd3, 0x81, 0x6d, 0x9b, 0xe9, 0x33, 0xcc, 0xf4, 0x19, 0xe6, 0x05, 0xdc, 0x4e, 0xc4, 0x7b, 0x2e, 0x62, 0xf9, 0x33, 0xbd, 0xae, 0x5d, 0xbe, 0x4f, 0xaf, 0xfb, 0x11, 0xbd, 0xee, 0x47, 0x11, 0x59, 0xdc, 0x2e, 0xa1, 0xf7, 0x0d, 0xc9, 0xf5, 0x91, 0x42, 0x6a, 0x91, 0x66, 0xfa, 0x5e, 0x0b, 0x58, 0xb9, 0x4f, 0xcf, 0x1e, 0x39, 0x1c, 0x46, 0x02, 0xc7, 0x16,\n\t0x95, 0x2c, 0xba, 0x51, 0x01, 0x1d, 0x51, 0x67, 0xe4, 0xde, 0xa8, 0x22, 0x19, 0x8c, 0xa2, 0xff, 0xa0, 0xfa, 0x39, 0xe8, 0x85, 0x13, 0xe9, 0x85, 0x13, 0xe9, 0x85, 0x13, 0xe9, 0x85, 0x13, 0xe9, 0x85, 0x13, 0xe9, 0x85, 0x13, 0xe9, 0x85, 0x13, 0xe9, 0x85, 0x13, 0xe9, 0x85, 0x13, 0xe9, 0x81, 0x3f, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x07, 0x4e, 0xa4, 0x5f, 0xfd, 0x90, 0x7e, 0xf5, 0x43, 0xfa, 0xd5, 0x44, 0xfa, 0xd5, 0xe1, 0xf4, 0xab, 0xc3, 0xe9, 0x57, 0x47, 0x5a, 0x0a, 0xe4, 0x0b, 0x16, 0x2f, 0x14,\n\t0xca, 0x17, 0xa8, 0x6c, 0xc5, 0x54, 0xb6, 0x62, 0x2a, 0x5b, 0x31, 0x95, 0xad, 0x98, 0xca, 0x56, 0x4c, 0x65, 0x2b, 0xa6, 0xb2, 0x15, 0x53, 0xd9, 0x8a, 0xa9, 0x6c, 0xc5, 0xca, 0x97, 0xf0, 0x15, 0x2c, 0x87, 0x15, 0xb0, 0x52, 0xd4, 0xa3, 0xba, 0x15, 0x53, 0xdd, 0x8a, 0xa9, 0x6e, 0xc5, 0x54, 0xb7, 0x62, 0xaa, 0x5b, 0x31, 0xd5, 0xad, 0x98, 0xea, 0x56, 0x4c, 0x75, 0x2b, 0xa6, 0xba, 0x15, 0x53, 0xdd, 0x8a, 0xa9, 0x6e, 0xc5, 0x54, 0xb7, 0x62, 0xaa, 0x5b, 0xb1, 0xf2, 0x13, 0xfc, 0x0c, 0x1b, 0xe1, 0x17, 0xf8, 0x15, 0x36, 0xc1, 0x66, 0xd8, 0x02, 0xdb, 0xe9, 0x23, 0x77, 0xc0, 0x4e, 0x48, 0x86, 0x5d, 0xb0, 0x07, 0xf6, 0xca, 0xbd, 0xca, 0x3e, 0xb0, 0xc1, 0x7e, 0xb0, 0xf3, 0xd8, 0x41, 0x96, 0x87, 0x58, 0x1e, 0x86, 0x54, 0x38, 0x02, 0x47, 0xc1, 0x01, 0xc7, 0xe0, 0x38, 0xa4, 0x41,\n\t0x06, 0x64, 0xc2, 0x09, 0x38, 0x09, 0x59, 0x90, 0xcd, 0xb6, 0x72, 0x58, 0x9e, 0x02, 0xe6, 0x89, 0x0a, 0xe8, 0xa0, 0x02, 0x3a, 0xa8, 0x80, 0x0e, 0x2a, 0xa0, 0x83, 0x0a, 0xe8, 0xa0, 0x02, 0x3a, 0x14, 0x0f, 0xd0, 0x4b, 0x52, 0x05, 0x1d, 0x8a, 0x94, 0x9a, 0xca, 0xbc, 0xab, 0x26, 0x30, 0x43, 0x04, 0x44, 0x42, 0x14, 0x44, 0xcb, 0x74, 0x2a, 0x5b, 0x3a, 0x95, 0x2d, 0x9d, 0xca, 0x96, 0xae, 0x5a, 0xa5, 0x83, 0xea, 0x96, 0x4e, 0x75, 0x4b, 0xa7, 0xba, 0xa5, 0xab, 0x71, 0xa2, 0xb9, 0xda, 0x54, 0x58, 0xd5, 0x96, 0xc6, 0x37, 0x8d, 0x15, 0xb5, 0xad, 0xe8, 0xa4, 0xb6, 0x13, 0x57, 0xa9, 0x1d, 0xc5, 0x2c, 0xb5, 0xab, 0xa8, 0x49, 0xd5, 0x70, 0x50, 0x35, 0x1c, 0x54, 0x0d, 0x07, 0x55, 0xc3, 0x41, 0xd5, 0x70, 0x50, 0x35, 0x1c, 0x54, 0x0d, 0x07, 0x55, 0xc3, 0xa1, 0x3e, 0x04, 0xe3, 0x61,\n\t0x02, 0x4c, 0x84, 0x87, 0x65, 0x3e, 0x95, 0xc3, 0x41, 0xe5, 0x70, 0x50, 0x39, 0x1c, 0x54, 0x0e, 0x07, 0x95, 0xc3, 0x41, 0xe5, 0x70, 0x50, 0x39, 0x1c, 0x54, 0x0e, 0x07, 0x95, 0xc3, 0x41, 0xe5, 0x70, 0x50, 0x39, 0x1c, 0x54, 0x0e, 0x87, 0x3a, 0x03, 0x66, 0xc2, 0x2c, 0x78, 0x11, 0x16, 0x8a, 0x76, 0xea, 0xdb, 0xf4, 0x03, 0xf4, 0x74, 0xea, 0xbb, 0xf0, 0x1e, 0xbc, 0x0f, 0xc4, 0xbf, 0xfa, 0x01, 0x7c, 0x08, 0x8b, 0x60, 0xb1, 0x2c, 0xb3, 0xee, 0x95, 0x41, 0xeb, 0x51, 0xc8, 0x32, 0xde, 0xe7, 0x76, 0xa0, 0x68, 0x0e, 0x14, 0xcd, 0x81, 0xa2, 0x39, 0x50, 0x34, 0x47, 0xcc, 0x56, 0xfa, 0xea, 0x6d, 0x2c, 0x99, 0x9b, 0xff, 0x5f, 0xa9, 0xc5, 0x35, 0xa8, 0x45, 0x7d, 0xd4, 0xa2, 0x3e, 0x6a, 0xd1, 0x0e, 0xb5, 0x68, 0xf7, 0xb7, 0x5a, 0xfc, 0xad, 0x16, 0x7f, 0xab, 0xc5, 0x7f, 0x4e, 0x2d,\n\t0xfe, 0xc5, 0xb5, 0x44, 0xfb, 0x8b, 0x2e, 0xa2, 0x91, 0x18, 0x0f, 0x13, 0x60, 0x22, 0x4c, 0x81, 0x27, 0xe0, 0x49, 0x98, 0x0e, 0x2f, 0xc2, 0xbb, 0xa2, 0x8e, 0xa9, 0xbb, 0x7e, 0x35, 0x62, 0x11, 0x6b, 0x8a, 0x17, 0xdd, 0x4c, 0x7d, 0x44, 0x3d, 0x53, 0x5f, 0xd1, 0xdd, 0x74, 0x33, 0xcb, 0x5b, 0x58, 0xde, 0xc1, 0xe3, 0x83, 0x8c, 0xeb, 0xa7, 0x0d, 0xc2, 0x1b, 0x0d, 0xd1, 0xaf, 0x60, 0x6c, 0x1a, 0x25, 0x54, 0xd3, 0x83, 0xa2, 0x87, 0xe9, 0x21, 0x98, 0x2c, 0x46, 0x5e, 0x76, 0x85, 0xdc, 0x46, 0xe6, 0x67, 0x61, 0x16, 0x7c, 0x02, 0x4b, 0x44, 0xa3, 0xc8, 0x04, 0xd1, 0x28, 0xaa, 0x3e, 0x74, 0x17, 0xfa, 0xaf, 0xa2, 0x76, 0x8f, 0x2a, 0x13, 0x35, 0xa3, 0x5b, 0x8b, 0x46, 0xca, 0x56, 0xd8, 0x06, 0xbf, 0x89, 0x46, 0x6a, 0x6d, 0xa8, 0x03, 0x75, 0xa1, 0x1e, 0xf0, 0x7c, 0xb5, 0x01, 0x34,\n\t0x17, 0xb1, 0x97, 0xae, 0xa1, 0x7a, 0x03, 0xf7, 0xbb, 0x43, 0x0f, 0x88, 0x87, 0x9e, 0xd0, 0x0b, 0x7a, 0x43, 0x1f, 0xe8, 0x0b, 0x37, 0xc3, 0x2d, 0x70, 0x2b, 0xf4, 0x83, 0xfe, 0x1c, 0xe3, 0xdf, 0x57, 0x27, 0xff, 0xfb, 0xea, 0xe4, 0x7f, 0x5f, 0x9d, 0xfc, 0x0a, 0x57, 0x27, 0x37, 0x7d, 0x80, 0xd7, 0x70, 0xe1, 0x35, 0x5c, 0xf8, 0x8c, 0x4a, 0xd1, 0x4e, 0xe6, 0x8b, 0xeb, 0x64, 0x50, 0x5c, 0xcf, 0xed, 0xf6, 0xd2, 0x89, 0xef, 0xf0, 0xe1, 0x3b, 0x7c, 0xf8, 0x0e, 0x9f, 0xe8, 0x22, 0x0b, 0xc9, 0x8c, 0x14, 0x32, 0x23, 0x85, 0xcc, 0x48, 0x21, 0x33, 0x52, 0xc8, 0x8c, 0x14, 0x32, 0x23, 0x85, 0xcc, 0x48, 0x21, 0x33, 0x52, 0xc8, 0x8c, 0x14, 0x32, 0x23, 0x85, 0xcc, 0x48, 0x21, 0x33, 0x52, 0x84, 0xde, 0x23, 0xdd, 0x05, 0x77, 0xc3, 0x60, 0x18, 0x02, 0xf7, 0xc0, 0x50, 0x18, 0x06, 0xf7,\n\t0xc2, 0x7d, 0x30, 0x1c, 0x46, 0x80, 0x7e, 0x5d, 0xe3, 0x51, 0x70, 0x3f, 0x8c, 0x86, 0x31, 0x30, 0x16, 0x1e, 0x80, 0x71, 0xf0, 0x20, 0xfb, 0x39, 0x9e, 0xfd, 0x98, 0x00, 0x13, 0xe1, 0x61, 0xf6, 0x6b, 0x12, 0x4c, 0x86, 0x47, 0xe1, 0x31, 0x98, 0xc2, 0xe3, 0x8f, 0xcb, 0x22, 0xf1, 0x04, 0xcb, 0x27, 0xe1, 0x29, 0x6e, 0x4f, 0x85, 0x69, 0xf0, 0x1c, 0x4c, 0xe7, 0xb1, 0xe7, 0x59, 0xbe, 0x20, 0xdd, 0xf8, 0x1f, 0x37, 0xfe, 0xc7, 0x8d, 0xff, 0xd1, 0xcf, 0x3f, 0x16, 0x92, 0x65, 0x29, 0x62, 0xb6, 0xb4, 0x89, 0x97, 0xe1, 0x15, 0x78, 0x15, 0x5e, 0x83, 0xd7, 0x61, 0x0e, 0xcc, 0x85, 0x37, 0x60, 0x1e, 0xcc, 0xc7, 0x8b, 0xbd, 0x69, 0x5c, 0xd9, 0x78, 0x57, 0xf8, 0x1b, 0x24, 0x9b, 0xc9, 0xcc, 0x24, 0xf1, 0x8e, 0x3c, 0x6c, 0xf2, 0xa0, 0x83, 0x63, 0xa5, 0xd3, 0x3c, 0x05, 0x9e, 0x91, 0x85,\n\t0xe6, 0x67, 0x61, 0xa6, 0x2c, 0x32, 0xcf, 0x62, 0x39, 0x9b, 0x25, 0xeb, 0x36, 0xb3, 0x6e, 0xf3, 0xeb, 0xf2, 0x30, 0x3e, 0xc8, 0x65, 0x5e, 0xc8, 0x32, 0x51, 0xba, 0xc9, 0xd2, 0x24, 0xf3, 0x27, 0x3c, 0x67, 0x09, 0x2c, 0xe5, 0xb1, 0x2f, 0x64, 0x0a, 0x19, 0x9b, 0x42, 0xc6, 0xa6, 0x90, 0xb1, 0x29, 0x64, 0x6c, 0x0a, 0x19, 0x9b, 0x42, 0xc6, 0xa6, 0x90, 0xb1, 0x29, 0x64, 0x6c, 0x0a, 0x19, 0x9b, 0x62, 0x5e, 0xcb, 0xba, 0xbe, 0x91, 0xb6, 0xc8, 0x04, 0x59, 0x18, 0x55, 0x1f, 0x92, 0x64, 0x0a, 0xd9, 0x9b, 0x12, 0x95, 0x6c, 0x9c, 0x5f, 0x4c, 0x21, 0x83, 0x53, 0xc8, 0xe0, 0x14, 0x32, 0x38, 0x85, 0x0c, 0x4e, 0x89, 0x2a, 0x94, 0xc5, 0xd1, 0xad, 0x64, 0x51, 0x74, 0x6b, 0x59, 0x18, 0xdd, 0x56, 0xda, 0xf0, 0x49, 0x2e, 0x7c, 0x92, 0x0b, 0x9f, 0xe4, 0xc2, 0x27, 0xb9, 0xf0, 0x49, 0x2e,\n\t0x7c, 0x92, 0x0b, 0x9f, 0xe4, 0xc2, 0x27, 0xb9, 0xf0, 0x49, 0x2e, 0x3c, 0x92, 0x0b, 0x8f, 0xe4, 0xc2, 0x23, 0xb9, 0xf0, 0x48, 0x2e, 0x3c, 0x92, 0x0b, 0x8f, 0xe4, 0xc2, 0x23, 0xb9, 0xf0, 0x48, 0x2e, 0x3c, 0x92, 0x0b, 0x8f, 0xe4, 0xc2, 0x23, 0xb9, 0xf0, 0x48, 0x2e, 0x3c, 0x92, 0x0b, 0x8f, 0xe4, 0xc2, 0x23, 0xb9, 0xf0, 0x48, 0x2e, 0x3c, 0x92, 0x0b, 0x8f, 0xe4, 0xc2, 0x1b, 0xb9, 0xf0, 0x43, 0x95, 0x78, 0xa1, 0x4a, 0xe5, 0x19, 0x99, 0xaf, 0x3c, 0x0b, 0xcf, 0xc9, 0xa0, 0x32, 0x1d, 0x12, 0xe0, 0x79, 0x78, 0x01, 0x66, 0xc0, 0x8b, 0x3c, 0xe7, 0x25, 0x98, 0x2d, 0x9d, 0xca, 0xcb, 0xf0, 0x0a, 0xbc, 0x0a, 0x73, 0xe1, 0x0d, 0x98, 0x07, 0xf3, 0xe1, 0x4d, 0xf8, 0x58, 0xfa, 0xf0, 0x55, 0x3e, 0x7c, 0x95, 0x0f, 0x5f, 0xe5, 0xc3, 0x57, 0xf9, 0xf0, 0x55, 0x3e, 0x7c, 0x95, 0x0f, 0x5f,\n\t0xe5, 0xc3, 0x57, 0xf9, 0xf0, 0x54, 0x3e, 0x3c, 0x95, 0x0f, 0x4f, 0xe5, 0x53, 0x56, 0xc2, 0x2a, 0xf8, 0x1a, 0x56, 0xc3, 0x1a, 0x58, 0x0b, 0xdf, 0xc0, 0x3a, 0x58, 0x0f, 0xdf, 0xc2, 0x77, 0xf0, 0x3d, 0xfc, 0x00, 0x1b, 0x60, 0x23, 0xfc, 0x02, 0xbf, 0xc2, 0x26, 0xd8, 0x0c, 0x5b, 0x65, 0xa1, 0xb2, 0x0d, 0x7e, 0x83, 0x42, 0x99, 0x82, 0x12, 0xa5, 0xa0, 0x44, 0x29, 0x28, 0x51, 0x0a, 0x4a, 0x94, 0x82, 0x12, 0xa5, 0xa0, 0x44, 0x29, 0x28, 0x51, 0x0a, 0x4a, 0x94, 0x82, 0x12, 0xa5, 0xa0, 0x44, 0x29, 0x28, 0x51, 0x0a, 0x4a, 0x94, 0x82, 0x12, 0xa5, 0xa0, 0x44, 0x29, 0x28, 0x51, 0x0a, 0x4a, 0x94, 0x82, 0x12, 0xa5, 0xe0, 0x7f, 0x5c, 0xf8, 0x1f, 0x17, 0xfe, 0xc7, 0x85, 0xff, 0x71, 0xe1, 0x7f, 0x5c, 0xf8, 0x1f, 0x17, 0xfe, 0xc7, 0xa5, 0xd6, 0x96, 0x85, 0x6a, 0x1d, 0xa8, 0x0b, 0xf5,\n\t0x80, 0x39, 0x57, 0x1b, 0xc0, 0x55, 0xd2, 0xa7, 0x36, 0x82, 0xc6, 0x10, 0x07, 0x4d, 0xa0, 0x29, 0x34, 0x83, 0xe6, 0xd0, 0x02, 0x5a, 0x42, 0x1b, 0x68, 0x0b, 0xed, 0xa0, 0x03, 0x90, 0xe7, 0x2a, 0x39, 0xae, 0x76, 0x85, 0x1b, 0x58, 0x4f, 0x77, 0xe8, 0x01, 0x54, 0x19, 0xb5, 0x27, 0xf4, 0x82, 0xde, 0xd0, 0x07, 0xfa, 0xc2, 0xcd, 0x70, 0x0b, 0xdc, 0x0a, 0xfd, 0xa0, 0x3f, 0x0c, 0x90, 0x45, 0xea, 0xed, 0x30, 0x10, 0x06, 0xc1, 0x5d, 0x70, 0x37, 0x0c, 0x86, 0x21, 0x70, 0x0f, 0x0c, 0x85, 0x61, 0x70, 0x2f, 0x0c, 0x07, 0x72, 0x41, 0x7d, 0x19, 0x5e, 0x87, 0x39, 0x30, 0x17, 0xde, 0x80, 0x79, 0x30, 0x1f, 0xde, 0x84, 0xb7, 0x60, 0x21, 0xbc, 0x2d, 0xdd, 0x78, 0x27, 0x37, 0xde, 0xc9, 0x8d, 0x77, 0x72, 0xe3, 0x9b, 0xdc, 0xf8, 0x26, 0x37, 0xbe, 0xc9, 0x8d, 0x6f, 0x72, 0xe3, 0x9b, 0xf4,\n\t0x73, 0x74, 0x36, 0xf5, 0x63, 0xf8, 0x04, 0x96, 0xc0, 0x52, 0x58, 0x06, 0x9f, 0xc2, 0x67, 0xf0, 0x39, 0x7c, 0x01, 0x5f, 0xc2, 0x57, 0xb0, 0x1c, 0x56, 0xc0, 0x4a, 0x58, 0x05, 0x5f, 0xc3, 0x6a, 0x58, 0x03, 0xe4, 0x94, 0x4a, 0x4e, 0xa9, 0xeb, 0x60, 0x3d, 0x7c, 0x0b, 0xdf, 0xc1, 0xf7, 0xf0, 0x03, 0x6c, 0x80, 0x1f, 0xe1, 0x27, 0xf8, 0x19, 0x36, 0xc2, 0x2f, 0xf0, 0x2b, 0x6c, 0x82, 0xcd, 0xb0, 0x05, 0xb6, 0xc2, 0x36, 0xf8, 0x0d, 0x77, 0x96, 0x04, 0xdb, 0x61, 0x07, 0xec, 0x84, 0x64, 0xd8, 0x05, 0xbb, 0x61, 0x0f, 0xec, 0x85, 0x7d, 0x60, 0x83, 0xfd, 0x70, 0x00, 0xec, 0x70, 0x10, 0x0e, 0xc1, 0x61, 0x48, 0x85, 0x23, 0xe0, 0x80, 0x63, 0xc6, 0xd5, 0xbe, 0x77, 0x51, 0x29, 0x76, 0xfd, 0x17, 0x9f, 0xe8, 0xde, 0xac, 0xe6, 0x82, 0x53, 0x26, 0x51, 0x31, 0x92, 0xa8, 0x18, 0x49, 0x54,\n\t0x8c, 0x24, 0x2a, 0x46, 0x12, 0x15, 0x23, 0x89, 0x8a, 0x91, 0x44, 0xc5, 0x48, 0xa2, 0x62, 0x24, 0x51, 0x31, 0x92, 0xd4, 0x52, 0x79, 0x58, 0x2d, 0x83, 0x00, 0x04, 0xe1, 0x2c, 0x94, 0xcb, 0xc3, 0xd6, 0x74, 0x59, 0x64, 0xad, 0x90, 0xc5, 0xd6, 0x4a, 0x08, 0xc1, 0x39, 0x38, 0x8f, 0x06, 0xf6, 0xc4, 0x69, 0xc6, 0xe1, 0x34, 0xe3, 0x70, 0x9a, 0x71, 0x38, 0xcd, 0x19, 0x38, 0xcd, 0x38, 0x9c, 0xa6, 0x09, 0xa7, 0x19, 0x87, 0xd3, 0x8c, 0xc3, 0x69, 0xc6, 0x5d, 0xe6, 0x12, 0xe3, 0x70, 0x89, 0x71, 0xb8, 0xc4, 0x38, 0x5c, 0x62, 0x1c, 0x2e, 0x31, 0x0e, 0x97, 0x18, 0x87, 0x4b, 0x8c, 0xc3, 0x19, 0xc6, 0x29, 0x4b, 0x44, 0x0d, 0xdc, 0x61, 0x1c, 0xee, 0x30, 0x0e, 0x77, 0x18, 0x87, 0x3b, 0x8c, 0xc3, 0x1d, 0xc6, 0xe1, 0x0e, 0xe3, 0x70, 0x87, 0x71, 0xb8, 0xc3, 0x38, 0xdc, 0x61, 0x9c, 0xda,\n\t0x04, 0x37, 0xdf, 0x54, 0x6c, 0x50, 0x9b, 0x89, 0x37, 0x71, 0x8a, 0x13, 0xd4, 0x16, 0x62, 0x0a, 0xae, 0xff, 0xfa, 0x4b, 0x8e, 0xb1, 0xab, 0xf8, 0x05, 0xd7, 0x18, 0x87, 0x6b, 0x8c, 0xc3, 0x35, 0xc6, 0xe1, 0x1a, 0xe3, 0x70, 0x8d, 0x71, 0xb8, 0xc6, 0x38, 0x5c, 0x63, 0x1c, 0xae, 0x31, 0x0e, 0xd7, 0x18, 0x87, 0x6b, 0x8c, 0xc3, 0x35, 0xc6, 0xe1, 0x1a, 0xe3, 0x70, 0x8d, 0x71, 0xb8, 0xc6, 0x38, 0xf5, 0x1d, 0x71, 0x9d, 0x35, 0x5d, 0xf4, 0x11, 0x37, 0x8b, 0x87, 0xc5, 0x5b, 0x62, 0x12, 0x4c, 0xe6, 0x88, 0x1e, 0x65, 0xf9, 0x98, 0x30, 0x99, 0x86, 0xca, 0xdf, 0xaa, 0x1f, 0x11, 0x3d, 0xe8, 0xd5, 0x51, 0x85, 0xa2, 0xa1, 0xf2, 0xb1, 0x98, 0xce, 0xde, 0xf7, 0x50, 0x96, 0x8a, 0xde, 0xca, 0x32, 0x31, 0x5e, 0xf9, 0x54, 0x0c, 0x52, 0x3e, 0x63, 0xf9, 0xb9, 0x68, 0x4c, 0x1f, 0x57, 0x5f,\n\t0xd9, 0x21, 0x1a, 0x28, 0x3b, 0xc5, 0x43, 0xca, 0x21, 0x31, 0x4c, 0x49, 0x15, 0xb5, 0x95, 0x23, 0x62, 0x8c, 0x72, 0x54, 0xf4, 0x51, 0x1c, 0xa2, 0x8d, 0x72, 0x4c, 0xf4, 0x56, 0xaf, 0x12, 0x6f, 0xa9, 0x8d, 0xa0, 0x31, 0xc4, 0x89, 0x00, 0x47, 0xd8, 0x8b, 0x23, 0x3c, 0xc2, 0x11, 0xe6, 0x72, 0x84, 0x67, 0xd4, 0x16, 0x26, 0xb3, 0xda, 0xd2, 0x54, 0x53, 0x6d, 0xc3, 0xdf, 0xdb, 0x8a, 0x7a, 0x1c, 0x69, 0x1d, 0xb5, 0x03, 0xb7, 0x3b, 0x8a, 0x27, 0xd4, 0xce, 0x2c, 0xbb, 0x8a, 0x34, 0xf5, 0x2e, 0x71, 0x9f, 0x7a, 0xb7, 0xa8, 0xa5, 0x8e, 0x10, 0x77, 0xaa, 0xa3, 0xe8, 0x7f, 0xee, 0x67, 0x94, 0x46, 0x8b, 0xee, 0xea, 0x18, 0x8e, 0x6a, 0x2c, 0xcb, 0x39, 0x8c, 0xd8, 0x42, 0x5e, 0xfb, 0x9b, 0x18, 0xa6, 0x6e, 0x17, 0xb5, 0xd5, 0x1d, 0xa2, 0x8f, 0xba, 0x53, 0xb4, 0x51, 0x93, 0xd9, 0x7e,\n\t0xbe, 0xa8, 0xaf, 0x9e, 0x11, 0xfd, 0x38, 0xf2, 0x23, 0xa2, 0xc6, 0x95, 0x8e, 0x52, 0x3f, 0x0a, 0xf6, 0xa8, 0xc1, 0xa5, 0xad, 0xeb, 0x5b, 0xee, 0x2a, 0x1a, 0xeb, 0x6b, 0x14, 0x91, 0xa2, 0x97, 0x0c, 0xea, 0xbf, 0xfe, 0x62, 0x9e, 0x2f, 0x6a, 0xc7, 0x0c, 0x90, 0xa9, 0xa2, 0xb9, 0xfe, 0x08, 0x23, 0xd8, 0x85, 0x11, 0xec, 0x12, 0x1e, 0xc1, 0x2e, 0xc6, 0x08, 0x86, 0x9f, 0xc5, 0x3a, 0xbb, 0x30, 0x6a, 0xd7, 0x30, 0x2a, 0xd1, 0x8c, 0x86, 0x89, 0x11, 0xe8, 0xc2, 0x08, 0x74, 0x61, 0x04, 0xba, 0x30, 0x02, 0x9f, 0x31, 0x02, 0x26, 0xb6, 0xf7, 0x04, 0x23, 0xf0, 0x2a, 0x23, 0x30, 0x87, 0x39, 0xfe, 0x8c, 0x39, 0x5e, 0xcb, 0x08, 0x74, 0x61, 0x1f, 0xba, 0xb0, 0x0f, 0x5d, 0x18, 0x81, 0x2e, 0xec, 0x47, 0x17, 0x46, 0xa0, 0x0b, 0xfb, 0x32, 0x8d, 0x23, 0x1c, 0xc3, 0x11, 0xbc, 0x68, 0xec,\n\t0x41, 0x9c, 0xb0, 0xe2, 0xa8, 0x6b, 0x43, 0x43, 0x59, 0x22, 0xda, 0xc8, 0x6c, 0xf6, 0xa8, 0x44, 0xe0, 0xca, 0xae, 0xf4, 0xfb, 0x0a, 0xe6, 0x47, 0xe4, 0x59, 0xf3, 0x63, 0x32, 0x60, 0xfe, 0x5e, 0x16, 0x98, 0x7f, 0x91, 0x25, 0xd5, 0x7f, 0x3b, 0x21, 0xaa, 0x29, 0xce, 0x38, 0x07, 0x4e, 0xc9, 0x80, 0x85, 0xe7, 0x58, 0x5e, 0x84, 0x97, 0x20, 0x20, 0x03, 0xca, 0x4d, 0x32, 0x10, 0xf3, 0xae, 0xcc, 0x8d, 0x79, 0x4f, 0xe6, 0xd2, 0x71, 0x54, 0x5d, 0x85, 0x2e, 0x5b, 0x1c, 0xc3, 0x49, 0xe9, 0xd7, 0x4a, 0xcb, 0x90, 0x67, 0x45, 0x26, 0xae, 0x23, 0x5b, 0xe6, 0x88, 0x1c, 0xa9, 0x89, 0x53, 0x78, 0x79, 0x97, 0x3c, 0x25, 0xdc, 0xfc, 0xad, 0x40, 0xff, 0x35, 0x24, 0x61, 0xc1, 0xd3, 0x57, 0x9a, 0xfa, 0xb2, 0x37, 0xb7, 0xc0, 0x20, 0xfd, 0x3a, 0xb0, 0x74, 0x65, 0xf4, 0x0c, 0xec, 0x55, 0x39,\n\t0x1d, 0x97, 0xc5, 0xf4, 0xa0, 0x94, 0xa6, 0x87, 0xa4, 0x8c, 0x58, 0x21, 0xcb, 0x23, 0xbe, 0x66, 0x5d, 0x71, 0xc2, 0x8c, 0xf7, 0xe8, 0x25, 0x77, 0x72, 0x2c, 0x87, 0xc4, 0xbb, 0xb2, 0xbb, 0x78, 0x4f, 0xde, 0x20, 0xde, 0x97, 0x37, 0xb0, 0x26, 0xbd, 0x2b, 0x78, 0xce, 0x34, 0xf4, 0x42, 0x9e, 0x69, 0x94, 0xec, 0x66, 0x9a, 0x28, 0x4f, 0x99, 0x26, 0xc1, 0x64, 0xd9, 0xd5, 0xf4, 0x08, 0xf7, 0x71, 0xc9, 0xe6, 0x3b, 0xf1, 0x1b, 0x8f, 0xc8, 0xdd, 0xcc, 0x80, 0xd5, 0xfc, 0xa6, 0x1c, 0xc6, 0xf1, 0x96, 0x73, 0xbc, 0x05, 0x91, 0x73, 0x64, 0xb7, 0xc8, 0x85, 0x72, 0x4a, 0xe4, 0x47, 0xcc, 0x76, 0x77, 0xd9, 0x33, 0xaa, 0x87, 0xec, 0x1e, 0xb5, 0x4b, 0x0e, 0xb3, 0x66, 0xcb, 0x5e, 0x7f, 0x18, 0xc9, 0x62, 0x46, 0x32, 0x8b, 0xad, 0x17, 0xb3, 0x75, 0x5f, 0xb5, 0x91, 0xcc, 0x08, 0x5f, 0x2b,\n\t0xfd, 0xd8, 0x65, 0x23, 0x59, 0xcc, 0x48, 0xa6, 0x85, 0xaf, 0x56, 0xfc, 0xef, 0x8c, 0xe4, 0x69, 0x46, 0xf2, 0xb4, 0x88, 0xf9, 0x6f, 0x45, 0x5f, 0xf5, 0xab, 0x74, 0xa7, 0x18, 0xd7, 0xce, 0x1d, 0x4b, 0xcf, 0x3a, 0x8e, 0x9e, 0x75, 0x9c, 0x59, 0x30, 0x5a, 0x47, 0x85, 0x85, 0x3e, 0x4a, 0x81, 0x9a, 0x70, 0x0d, 0xc4, 0x41, 0x13, 0xfd, 0x57, 0xd8, 0xa0, 0xea, 0x3b, 0xd9, 0x23, 0x45, 0x5b, 0x59, 0x26, 0xae, 0x85, 0x76, 0x72, 0x39, 0x6e, 0x38, 0x09, 0x27, 0x3c, 0x0b, 0xf7, 0x1b, 0xa2, 0x87, 0xf4, 0xd2, 0x43, 0x7a, 0xe9, 0x21, 0xbd, 0xf4, 0x90, 0x5e, 0x7a, 0x48, 0x2f, 0x3d, 0xa4, 0x97, 0x1e, 0xb2, 0x98, 0x1e, 0xb2, 0x98, 0x1e, 0xb2, 0x98, 0x1e, 0xd2, 0x4b, 0x0f, 0xe9, 0xc5, 0x29, 0x3b, 0x71, 0xca, 0x4e, 0x9c, 0xb2, 0x13, 0xa7, 0xec, 0xc4, 0x29, 0x3b, 0x71, 0xca, 0x4e, 0x9c,\n\t0xb2, 0x13, 0xa7, 0xec, 0xc4, 0x29, 0x3b, 0x71, 0xca, 0x4e, 0x9c, 0xb2, 0x13, 0xa7, 0xec, 0xc4, 0x29, 0x3b, 0x71, 0xca, 0x4e, 0x9c, 0xb2, 0x13, 0xa7, 0xec, 0xc4, 0x29, 0x3b, 0x71, 0xca, 0x4e, 0x9c, 0xb2, 0x13, 0xa7, 0xec, 0xc4, 0x29, 0x3b, 0x71, 0xca, 0x4e, 0x9c, 0xb2, 0x13, 0xa7, 0xec, 0xc4, 0x29, 0x3b, 0x71, 0xca, 0x4e, 0x9c, 0xb2, 0x13, 0xa7, 0xec, 0xc4, 0x29, 0x3b, 0x71, 0xca, 0x4e, 0x9c, 0xb2, 0x13, 0xa7, 0xec, 0xa4, 0x87, 0x2c, 0xc2, 0x29, 0x87, 0x70, 0xca, 0x21, 0x9c, 0x72, 0x08, 0xa7, 0x1c, 0xc2, 0x29, 0x87, 0x70, 0xca, 0x21, 0x9c, 0x72, 0x08, 0xa7, 0x1c, 0xc2, 0x29, 0x87, 0x70, 0xca, 0x21, 0x9c, 0x72, 0x08, 0xa7, 0x1c, 0xc2, 0x29, 0x87, 0x70, 0xca, 0x21, 0x9c, 0x72, 0x88, 0xfe, 0xd3, 0x4b, 0xff, 0xe9, 0xa5, 0xff, 0xf4, 0xe2, 0x9a, 0x43, 0xb8, 0xe6, 0x10,\n\t0x7d, 0x68, 0x31, 0xce, 0x39, 0x84, 0x53, 0x0e, 0xe1, 0x94, 0x9d, 0x38, 0x65, 0x37, 0x4e, 0xd9, 0x8d, 0x53, 0x76, 0xe3, 0x94, 0xdd, 0x38, 0x65, 0x37, 0x4e, 0xd9, 0x8d, 0x53, 0x76, 0xe3, 0x94, 0xdd, 0x38, 0x65, 0x37, 0x4e, 0xd9, 0x8d, 0x53, 0xf6, 0xe2, 0x94, 0xbd, 0x38, 0x65, 0x1b, 0x4e, 0x39, 0x17, 0x97, 0xbc, 0x87, 0x68, 0x2d, 0x20, 0x5a, 0x5d, 0x44, 0xab, 0xcf, 0xd4, 0x03, 0xfa, 0xc8, 0xbd, 0xc4, 0x7e, 0xb2, 0xe9, 0x66, 0x96, 0xb7, 0xb0, 0x1c, 0x24, 0xb7, 0x11, 0xb9, 0xfb, 0x88, 0xf9, 0x2c, 0x62, 0x3e, 0x8b, 0xc8, 0xdd, 0x49, 0xe4, 0x3a, 0x4d, 0xf9, 0xe4, 0xc3, 0x19, 0x59, 0x46, 0x8f, 0xeb, 0xc5, 0x65, 0x7b, 0xcd, 0xf4, 0xe3, 0x66, 0xfa, 0x6e, 0x33, 0x3d, 0x36, 0x8e, 0x7b, 0x96, 0x79, 0x3c, 0xcb, 0x47, 0x64, 0x19, 0xce, 0x7b, 0x96, 0xf9, 0x71, 0x96, 0xcf, 0xc8,\n\t0x10, 0xee, 0x3b, 0x44, 0x3f, 0xec, 0xa5, 0x1f, 0x2e, 0xc6, 0x85, 0x87, 0x70, 0xe1, 0x21, 0x5c, 0x78, 0x08, 0x17, 0xee, 0xc6, 0x85, 0xbb, 0xe9, 0x91, 0x8b, 0xe9, 0x91, 0x8b, 0x71, 0xdf, 0x7b, 0x70, 0xdf, 0x21, 0xdc, 0x77, 0x08, 0xe7, 0xed, 0xc4, 0x79, 0x3b, 0x71, 0xde, 0x4e, 0x9c, 0xb7, 0x13, 0xe7, 0xed, 0xc4, 0x79, 0x3b, 0x71, 0xde, 0x4e, 0x9c, 0xb7, 0x13, 0xe7, 0xed, 0xc4, 0x79, 0x3b, 0x71, 0xde, 0x6e, 0x9c, 0xb7, 0x9b, 0x9e, 0xb9, 0x08, 0xf7, 0x1d, 0x22, 0x7b, 0xb2, 0x71, 0xe0, 0x21, 0x32, 0xe7, 0x4b, 0x32, 0xe7, 0x4b, 0x9c, 0xb8, 0x13, 0x27, 0xee, 0xc4, 0x89, 0x87, 0x70, 0xe2, 0x4e, 0x9c, 0xb8, 0x13, 0x27, 0xee, 0xc4, 0x89, 0x3b, 0x71, 0xe2, 0xce, 0xa8, 0x2c, 0xa3, 0x9f, 0xf6, 0xd2, 0x4f, 0x17, 0xe3, 0xca, 0xbd, 0xb8, 0xf2, 0x10, 0xae, 0x3c, 0x84, 0x2b, 0x77,\n\t0xd3, 0x5f, 0x7b, 0x2d, 0x4f, 0xca, 0x0a, 0xcb, 0x53, 0x30, 0x15, 0xa6, 0xc1, 0x73, 0x40, 0xdf, 0x6e, 0xa1, 0x6f, 0xb7, 0xd0, 0xb7, 0x5b, 0xe8, 0xdb, 0x2d, 0xf4, 0xed, 0x16, 0xfa, 0x76, 0xcb, 0x5a, 0x7a, 0xd8, 0x58, 0x20, 0xb6, 0x95, 0x5a, 0x50, 0x1b, 0xea, 0x40, 0x5d, 0xa8, 0x07, 0xf5, 0xe1, 0x6a, 0x68, 0x04, 0x8d, 0x81, 0xf8, 0x57, 0x88, 0x7f, 0x85, 0xf8, 0x57, 0x9a, 0x42, 0x33, 0x20, 0x0f, 0x94, 0x16, 0xd0, 0x12, 0x5a, 0x41, 0x6b, 0x68, 0x03, 0x6d, 0xe1, 0x5a, 0x68, 0x07, 0xd7, 0xc1, 0xf5, 0xd0, 0x1d, 0xfe, 0xf5, 0xf7, 0x5e, 0xcb, 0x94, 0x07, 0x60, 0x1c, 0x3c, 0x08, 0x0f, 0xc1, 0x78, 0x98, 0x00, 0x13, 0xe1, 0x61, 0x98, 0x04, 0x93, 0x81, 0x39, 0x53, 0x1e, 0x85, 0xc7, 0x60, 0x0a, 0x30, 0x77, 0xca, 0x13, 0xf0, 0x24, 0x3c, 0x05, 0x53, 0x61, 0x1a, 0xe8, 0xbf, 0x89,\n\t0xfd, 0x8c, 0x5c, 0x4e, 0xd7, 0xb0, 0x9c, 0xae, 0x21, 0x89, 0xae, 0x21, 0x89, 0xae, 0x21, 0x89, 0xae, 0x21, 0x89, 0xae, 0x21, 0x89, 0xae, 0x21, 0x89, 0x6e, 0x61, 0x16, 0xdd, 0xc2, 0x2c, 0xba, 0x85, 0x59, 0x74, 0x0b, 0xb3, 0xe8, 0x16, 0x66, 0xd1, 0x2d, 0xcc, 0xa2, 0x5b, 0x98, 0x45, 0xb7, 0x30, 0x8b, 0x6e, 0x61, 0x16, 0x8e, 0x3d, 0x84, 0x63, 0x0f, 0xe1, 0xd8, 0x43, 0xca, 0x76, 0xe9, 0x55, 0x76, 0xc0, 0x4e, 0x48, 0x86, 0x3d, 0x80, 0x13, 0x53, 0x70, 0x62, 0x0a, 0x4e, 0x4c, 0xc1, 0x89, 0x29, 0x38, 0x30, 0xe5, 0x10, 0x8f, 0x1f, 0x86, 0x54, 0x38, 0x02, 0x47, 0xc1, 0x01, 0xc7, 0xe0, 0x38, 0x64, 0xc2, 0x09, 0x38, 0x09, 0x59, 0x90, 0x0d, 0x39, 0x70, 0x0a, 0x98, 0x63, 0x25, 0x17, 0x9c, 0xe0, 0x82, 0x7c, 0xd0, 0x7f, 0x6b, 0x84, 0x38, 0x56, 0x0a, 0xc0, 0x0b, 0x85, 0x74, 0x31,\n\t0xc5, 0x50, 0x02, 0x3e, 0xf0, 0x83, 0x06, 0xa5, 0x50, 0x06, 0x01, 0x08, 0xc2, 0x59, 0x28, 0x87, 0x0a, 0xa8, 0x84, 0x10, 0x9c, 0x83, 0xf3, 0x70, 0x41, 0x3a, 0xd5, 0x68, 0xdc, 0xb2, 0x05, 0x14, 0x50, 0x21, 0x16, 0x6a, 0x42, 0x2d, 0xa8, 0x2d, 0x43, 0x74, 0x0e, 0x21, 0x3a, 0x87, 0x10, 0x9d, 0x43, 0x88, 0xce, 0x21, 0x44, 0xe7, 0x10, 0xa2, 0x73, 0x08, 0xd1, 0x39, 0x84, 0xe8, 0x1c, 0x42, 0x74, 0x0e, 0x21, 0x3a, 0x87, 0x10, 0x9d, 0x43, 0x88, 0xce, 0x21, 0x44, 0xe7, 0x10, 0xa2, 0x73, 0x08, 0xd1, 0x39, 0x84, 0xe8, 0x1c, 0x42, 0x74, 0x0e, 0x21, 0x3a, 0x87, 0x10, 0x9d, 0x43, 0x88, 0xce, 0x21, 0x44, 0xe7, 0x10, 0xa2, 0x73, 0x08, 0xd1, 0x39, 0x84, 0xe8, 0x1c, 0x42, 0x74, 0x0e, 0x21, 0x3a, 0x87, 0x10, 0x9d, 0x43, 0x88, 0xce, 0x21, 0x44, 0xe7, 0x10, 0xa2, 0x73, 0x08, 0xd1, 0x39,\n\t0x84, 0xe8, 0x1c, 0x42, 0x74, 0x0e, 0x21, 0x3a, 0x87, 0x10, 0x9d, 0x43, 0x88, 0xce, 0x21, 0x44, 0xe7, 0x10, 0xa2, 0x73, 0x08, 0xd1, 0x39, 0x84, 0xe8, 0x1c, 0x42, 0x74, 0x0e, 0x21, 0x3a, 0x87, 0x10, 0x9d, 0x43, 0x88, 0xce, 0x21, 0x44, 0xe7, 0x10, 0xa2, 0x73, 0x08, 0xd1, 0x39, 0x84, 0xe8, 0x1c, 0x42, 0x74, 0x0e, 0x21, 0x75, 0x84, 0xf4, 0xaa, 0x23, 0x61, 0x14, 0xdc, 0x0f, 0xa3, 0x61, 0x0c, 0x8c, 0x85, 0x07, 0x60, 0x3c, 0x4c, 0x80, 0x89, 0xf0, 0x30, 0x4c, 0x82, 0xc9, 0xf0, 0x08, 0x3c, 0x0a, 0x8f, 0xc1, 0x14, 0x78, 0x1c, 0x9e, 0x80, 0x27, 0xe1, 0x29, 0x98, 0x0a, 0xd3, 0x60, 0x26, 0xcc, 0x82, 0x17, 0x01, 0xad, 0xa0, 0x4b, 0x09, 0xd1, 0xa5, 0x84, 0xe8, 0x52, 0x42, 0x74, 0x29, 0x21, 0xba, 0x94, 0x10, 0x5d, 0x4a, 0x88, 0x2e, 0x25, 0x44, 0x97, 0x12, 0xa2, 0x4b, 0x09, 0xd1,\n\t0xa5, 0x84, 0xe8, 0x40, 0xdc, 0x74, 0x20, 0x6e, 0x3a, 0x10, 0x37, 0x1d, 0x88, 0x9b, 0x0e, 0xc4, 0x4d, 0x07, 0xe2, 0xa6, 0x03, 0x71, 0xd3, 0x81, 0xb8, 0xe9, 0x40, 0xdc, 0x74, 0x20, 0x6e, 0x3a, 0x10, 0x37, 0x1d, 0x88, 0x9b, 0x0e, 0xc4, 0x4d, 0x07, 0xe2, 0xa6, 0x03, 0x71, 0xd3, 0x81, 0xb8, 0xe9, 0x40, 0xdc, 0x74, 0x20, 0x6e, 0x3a, 0x10, 0x37, 0x1d, 0x88, 0x9b, 0x0e, 0xc4, 0x4d, 0x07, 0xe2, 0xa6, 0x03, 0x71, 0xd3, 0x81, 0xb8, 0xe9, 0x40, 0xdc, 0x74, 0x20, 0x6e, 0x3a, 0x10, 0x37, 0x1d, 0x88, 0x9b, 0x0e, 0xc4, 0x4d, 0x07, 0xe2, 0xa6, 0x03, 0x71, 0xd3, 0x81, 0xb8, 0xe9, 0x40, 0xdc, 0x74, 0x20, 0x6e, 0x3a, 0x10, 0x37, 0x1d, 0x88, 0x9b, 0x0e, 0xc4, 0x4d, 0x07, 0xe2, 0xa6, 0x03, 0x71, 0xd3, 0x81, 0x78, 0xe9, 0x40, 0xbc, 0x74, 0x20, 0x5e, 0x3a, 0x10, 0x2f, 0x1d, 0x88, 0x97,\n\t0x0e, 0xc4, 0x4b, 0x07, 0xe2, 0xa5, 0x03, 0xf1, 0xd2, 0x81, 0x78, 0xe9, 0x40, 0xbc, 0x74, 0x20, 0x5e, 0x3a, 0x10, 0x2f, 0x1d, 0x88, 0x97, 0x0e, 0xc4, 0x4b, 0x07, 0xe2, 0xa5, 0x03, 0xf1, 0xd2, 0x81, 0x78, 0xe9, 0x40, 0xbc, 0x74, 0x20, 0x5e, 0x3a, 0x10, 0x2f, 0x1d, 0x88, 0x97, 0x0e, 0xc4, 0x4b, 0x07, 0x62, 0xa3, 0x03, 0xb1, 0xd1, 0x81, 0xe4, 0xd2, 0x81, 0xe4, 0xd2, 0x81, 0xe4, 0xd2, 0x81, 0xe4, 0xd2, 0x81, 0xe4, 0xd2, 0x81, 0xe4, 0xd2, 0x81, 0xe4, 0xd2, 0x79, 0xec, 0xa1, 0xf3, 0xd8, 0x43, 0xe7, 0xb1, 0x87, 0xce, 0x63, 0x0f, 0x9d, 0xc7, 0x1e, 0x3a, 0x8f, 0x3d, 0x74, 0x1e, 0x7b, 0xe8, 0x3c, 0xf6, 0xd0, 0x79, 0xec, 0xa1, 0xf3, 0xd8, 0x43, 0x87, 0x11, 0xc2, 0x69, 0xb8, 0xac, 0x05, 0xb2, 0xc2, 0xea, 0x85, 0x42, 0x28, 0x82, 0x62, 0x28, 0x91, 0x65, 0x56, 0x1f, 0xf8, 0x41,\n\t0x83, 0x52, 0x28, 0x93, 0x5e, 0x6b, 0x00, 0x82, 0x70, 0x16, 0xca, 0x01, 0xdd, 0xa4, 0x43, 0xf1, 0xd2, 0xa1, 0x78, 0xe9, 0x50, 0xbc, 0x74, 0x28, 0xde, 0x18, 0x72, 0x18, 0x2f, 0x51, 0xf5, 0x9b, 0x8d, 0x05, 0xe1, 0x4f, 0x53, 0xea, 0xbf, 0xd9, 0xb8, 0x1f, 0xa7, 0x70, 0x24, 0xfc, 0xab, 0x35, 0xa5, 0xf8, 0x8c, 0x52, 0x7c, 0x86, 0xf1, 0x2d, 0x32, 0xe3, 0xd7, 0x7f, 0xf4, 0x5f, 0xab, 0x2c, 0xd3, 0x7f, 0x81, 0xc8, 0xd4, 0xc5, 0xf8, 0xcc, 0xe6, 0xc1, 0xf0, 0xef, 0x37, 0xae, 0xe3, 0xd5, 0x87, 0x78, 0x75, 0x52, 0xf8, 0x17, 0x2b, 0x33, 0x22, 0x4d, 0x68, 0x7f, 0xb4, 0xac, 0x88, 0x1c, 0x22, 0xfd, 0x91, 0x43, 0x65, 0x20, 0xf2, 0x5e, 0xe3, 0x3a, 0x0b, 0x47, 0xa8, 0x01, 0x47, 0x2c, 0x67, 0x8c, 0xdf, 0x07, 0xf6, 0x1a, 0xbf, 0xdf, 0x7b, 0xce, 0x44, 0xef, 0x5e, 0xed, 0x57, 0x73, 0x92,\n\t0xc3, 0x9f, 0x23, 0xbc, 0xf4, 0x3b, 0x49, 0x91, 0x23, 0x8c, 0xdf, 0x4a, 0x3a, 0xcd, 0x2b, 0x4f, 0xf3, 0xca, 0x20, 0xaf, 0x2c, 0x14, 0x4d, 0xf5, 0xdf, 0xbe, 0x0f, 0xff, 0xda, 0x5f, 0xa9, 0xf1, 0x2b, 0x7f, 0xfa, 0xef, 0x4a, 0xd6, 0x97, 0x07, 0x8c, 0x5f, 0xe5, 0xeb, 0xc4, 0xbe, 0x74, 0x91, 0xc5, 0xe1, 0xcf, 0x1e, 0x6a, 0x11, 0xbf, 0xe0, 0x0f, 0xf5, 0xdf, 0xa7, 0x4f, 0x37, 0x7e, 0xfd, 0xd4, 0x17, 0xbe, 0xae, 0xa6, 0x3f, 0x72, 0x80, 0x2c, 0x0f, 0x5f, 0x5b, 0xf3, 0x00, 0xfb, 0x98, 0xcf, 0x3e, 0x1e, 0x63, 0x6b, 0xfa, 0x55, 0x1a, 0x32, 0xf5, 0xab, 0x86, 0x58, 0x26, 0xcb, 0x7c, 0x0b, 0x63, 0xae, 0xbe, 0x2f, 0x73, 0xd4, 0x14, 0x3a, 0xbd, 0x7f, 0xb2, 0xe5, 0x3a, 0xc6, 0xa7, 0xf0, 0x63, 0xd8, 0x72, 0x2d, 0x79, 0x82, 0xad, 0x86, 0xd8, 0x62, 0x06, 0x5b, 0x3c, 0x6b, 0xea, 0x2c,\n\t0x9a, 0xb3, 0xd5, 0x93, 0x38, 0x53, 0x85, 0xad, 0x64, 0xb1, 0xb6, 0xf2, 0xc8, 0x11, 0xc6, 0xb7, 0x2e, 0x4b, 0xd5, 0x56, 0xe2, 0x1a, 0xb5, 0xb5, 0xe8, 0xcc, 0x5a, 0x7c, 0xc6, 0xaf, 0x58, 0x46, 0xe3, 0x87, 0xcf, 0xe3, 0x85, 0xbd, 0x78, 0xe1, 0x42, 0xfc, 0xaf, 0x0f, 0xff, 0xeb, 0xc3, 0xfb, 0x7a, 0xfe, 0x07, 0xd7, 0x05, 0x6e, 0x27, 0x0e, 0xca, 0x4c, 0x71, 0x58, 0x9e, 0x13, 0x47, 0xf0, 0xda, 0x47, 0x65, 0x3a, 0x6b, 0xda, 0xc9, 0x36, 0x4a, 0xc2, 0x7e, 0x3b, 0x03, 0xbf, 0xfd, 0x0b, 0x6b, 0x3d, 0xc1, 0xf6, 0xce, 0xb1, 0xbd, 0x4a, 0xd6, 0x1e, 0x62, 0xed, 0x7b, 0xd8, 0xae, 0x8b, 0x2d, 0x9c, 0xc1, 0x77, 0xe7, 0x2a, 0x1d, 0xa8, 0x27, 0x9d, 0xa1, 0x0b, 0xb1, 0xd4, 0x58, 0x9e, 0xb3, 0xc6, 0x41, 0x13, 0x68, 0x0a, 0xcd, 0xa0, 0x39, 0xb4, 0x80, 0x96, 0xd0, 0x0a, 0x5a, 0x43, 0x1b,\n\t0x68, 0x0b, 0xd7, 0x42, 0x3b, 0xb8, 0x0e, 0xae, 0x87, 0xf6, 0xd0, 0x01, 0x3a, 0x42, 0x27, 0xb6, 0x79, 0x93, 0xd8, 0x8b, 0xdb, 0xb7, 0xb1, 0x27, 0xfb, 0xd9, 0x3b, 0x3b, 0x7b, 0x7b, 0x84, 0xe3, 0x3b, 0x6a, 0x5c, 0x9b, 0x5a, 0xdf, 0x4b, 0x1f, 0x7b, 0x59, 0xc1, 0xb1, 0x7f, 0xce, 0x5e, 0x9e, 0x63, 0x2f, 0x4b, 0xd8, 0xcb, 0x12, 0xf6, 0x52, 0xbf, 0x2e, 0xb5, 0x7e, 0x4d, 0xf6, 0x2b, 0xf6, 0x27, 0xb8, 0xff, 0x0a, 0x8e, 0xff, 0xcc, 0x1f, 0x7e, 0xd3, 0xad, 0xbb, 0xcc, 0xb0, 0xf4, 0x80, 0xbb, 0xe0, 0x6e, 0x19, 0xb4, 0x0c, 0x86, 0x21, 0xdc, 0xbe, 0x07, 0x86, 0x72, 0x7b, 0x18, 0xe0, 0xcc, 0x2d, 0xf7, 0xc1, 0x70, 0x18, 0x01, 0x23, 0x81, 0xc8, 0xb5, 0xdc, 0x0f, 0xa3, 0xf9, 0xfb, 0x18, 0x18, 0xcb, 0xed, 0x07, 0x60, 0x1c, 0xb7, 0x1f, 0x84, 0x87, 0x64, 0x86, 0x72, 0x9f, 0x4c, 0x56,\n\t0x66, 0x4a, 0x9b, 0xf2, 0xba, 0xf4, 0x28, 0x0b, 0xe0, 0x1d, 0x78, 0x17, 0x16, 0xcb, 0x53, 0xd6, 0x99, 0x52, 0x1a, 0x9e, 0x7b, 0x37, 0x7b, 0xb7, 0x55, 0x9f, 0x1d, 0xee, 0xf5, 0xc4, 0xa9, 0xf5, 0x92, 0x3b, 0x4c, 0xbd, 0xe5, 0x0e, 0x11, 0xcd, 0xbd, 0x7c, 0xee, 0xa5, 0x73, 0x2f, 0x9d, 0xe7, 0x25, 0x87, 0x73, 0x66, 0xbb, 0xfe, 0x79, 0x1b, 0x22, 0xb8, 0xea, 0x13, 0xcd, 0xdb, 0x78, 0x64, 0xb7, 0xf1, 0xdc, 0xed, 0x3c, 0xf7, 0x37, 0x9e, 0xfb, 0x5b, 0xf8, 0x17, 0x61, 0xf5, 0xdf, 0xc7, 0x3d, 0x24, 0x54, 0xfe, 0x62, 0xe3, 0x2f, 0x3e, 0xfe, 0xe2, 0x0b, 0x3b, 0xfc, 0xdd, 0xfa, 0x6f, 0x6d, 0x32, 0x06, 0x36, 0xc6, 0x60, 0x0f, 0x63, 0x60, 0x37, 0x3e, 0x19, 0x7e, 0x50, 0xcf, 0x66, 0x63, 0x8f, 0xbc, 0xe1, 0x2e, 0x24, 0xd5, 0xd8, 0x23, 0x8d, 0x57, 0x6b, 0xbc, 0x5a, 0x13, 0x8a, 0xf1,\n\t0x79, 0xda, 0x47, 0x64, 0x89, 0xf1, 0x19, 0xcf, 0xf0, 0xe7, 0x33, 0xf5, 0xcf, 0x61, 0x1a, 0x9f, 0x89, 0xeb, 0x2a, 0x2f, 0x88, 0x5a, 0xf4, 0x09, 0xc7, 0x79, 0x56, 0x12, 0xaf, 0xfb, 0xce, 0x74, 0xab, 0xdc, 0x68, 0xea, 0x07, 0x03, 0x8d, 0x5f, 0xa9, 0x4d, 0xbb, 0xf8, 0x2b, 0xaf, 0xa8, 0x45, 0x3e, 0x6a, 0x91, 0x8f, 0x5a, 0x68, 0xac, 0xa1, 0x8c, 0x5e, 0x53, 0xff, 0x75, 0xa9, 0x02, 0x7a, 0x90, 0xf7, 0x8c, 0xfc, 0xd6, 0xaf, 0x78, 0x7b, 0x28, 0xac, 0x14, 0x59, 0xd5, 0xf2, 0xfb, 0x38, 0x5a, 0x93, 0x8a, 0x93, 0xd5, 0x58, 0x43, 0x61, 0xf8, 0x97, 0x84, 0x8a, 0xd8, 0x97, 0x0a, 0x72, 0xfe, 0x10, 0x39, 0x7f, 0x88, 0x7d, 0xa9, 0xb0, 0x0e, 0x37, 0x34, 0xe8, 0x33, 0x63, 0x4c, 0xf6, 0xb3, 0xef, 0xfb, 0xd9, 0xf7, 0xfd, 0xac, 0x29, 0x9d, 0x35, 0x1d, 0x66, 0x4d, 0xe9, 0x17, 0xfb, 0x6c,\n\t0x61, 0xba, 0xd4, 0x67, 0x37, 0x10, 0xfa, 0xb7, 0x75, 0xdf, 0xe3, 0x39, 0xff, 0x22, 0x73, 0xd8, 0xfa, 0x3e, 0xb6, 0x7e, 0x9a, 0xad, 0xbb, 0xd8, 0xba, 0x8b, 0xad, 0x17, 0xb2, 0xf5, 0x52, 0x46, 0xc2, 0x7d, 0xf1, 0xd7, 0xca, 0xd8, 0x83, 0x52, 0xf6, 0xc0, 0xc3, 0x5a, 0xdf, 0x12, 0x8d, 0x45, 0x29, 0x48, 0x8e, 0x3a, 0x4a, 0x2e, 0x30, 0xd5, 0x94, 0x8b, 0xd1, 0x81, 0xa3, 0xc6, 0x2f, 0x99, 0xd6, 0x17, 0x0d, 0x8c, 0xeb, 0x31, 0x75, 0x91, 0xab, 0xd9, 0xda, 0x09, 0xb6, 0x96, 0xc8, 0x96, 0x7c, 0xe1, 0x2b, 0xfb, 0x7e, 0x18, 0xb1, 0x4b, 0xbe, 0x8b, 0x2e, 0xac, 0x8c, 0x1c, 0x88, 0x3e, 0xdc, 0x6b, 0xfc, 0xee, 0xb5, 0x47, 0xbf, 0x3e, 0x11, 0x5b, 0x79, 0x85, 0xad, 0xbc, 0xa2, 0x5f, 0x23, 0xcb, 0xda, 0x48, 0x7e, 0x82, 0x3e, 0x1c, 0x45, 0xf1, 0xbf, 0x15, 0xcd, 0x19, 0xf7, 0x6d, 0xf4,\n\t0x95, 0x21, 0x7a, 0xb0, 0x57, 0x39, 0x3a, 0x37, 0xb3, 0xe4, 0xe6, 0x98, 0x3e, 0xe3, 0x98, 0x3e, 0xa0, 0x4f, 0xf8, 0x89, 0xad, 0x64, 0xb0, 0x95, 0x77, 0xd9, 0xca, 0xc9, 0xf0, 0x56, 0xde, 0xa7, 0xb3, 0x2d, 0xa4, 0xb3, 0xd5, 0x3f, 0x03, 0x3f, 0x87, 0xe3, 0xfa, 0x82, 0xce, 0xb6, 0x80, 0x63, 0x3a, 0x47, 0x77, 0x7b, 0x9a, 0x3e, 0x20, 0x95, 0xd1, 0xe9, 0xc0, 0xf1, 0xad, 0x66, 0x8e, 0xfc, 0x78, 0xf3, 0x45, 0xe1, 0x3d, 0x98, 0xcd, 0x1e, 0xcc, 0xe6, 0x38, 0x57, 0xb3, 0xe5, 0xf5, 0xf4, 0x9a, 0x15, 0xf4, 0x9a, 0x15, 0xe2, 0x80, 0xd8, 0x47, 0xae, 0x1e, 0x94, 0x69, 0xe2, 0x90, 0xfc, 0x48, 0xa4, 0xa2, 0x4e, 0x47, 0xc8, 0xcb, 0xa3, 0x74, 0x8d, 0x0e, 0x99, 0x48, 0xce, 0x7a, 0xc4, 0x71, 0xe9, 0x37, 0xae, 0x42, 0x9e, 0x0e, 0x19, 0xe8, 0x96, 0xae, 0x30, 0x27, 0x78, 0x2c, 0x8b, 0xe7,\n\t0x65, 0xcb, 0xef, 0xc9, 0xe1, 0x7c, 0x72, 0xf8, 0x8c, 0xc8, 0xe3, 0xef, 0x4e, 0x70, 0xc9, 0x8f, 0x45, 0x3e, 0xcb, 0x33, 0xe0, 0xa6, 0x9b, 0xf5, 0xc8, 0x63, 0xe4, 0xf5, 0x11, 0xe1, 0x65, 0x2f, 0xf5, 0xa3, 0xe9, 0xcb, 0x98, 0xdd, 0x02, 0x97, 0x1f, 0xd5, 0x83, 0xdc, 0x7f, 0x48, 0xbe, 0x1b, 0xb1, 0x5c, 0x66, 0x90, 0xef, 0x47, 0x23, 0x56, 0x4a, 0x17, 0x1d, 0xff, 0x2f, 0x11, 0xeb, 0x58, 0x7e, 0x0b, 0x1b, 0xa4, 0x2b, 0x72, 0xae, 0x2c, 0x89, 0x9c, 0x07, 0xf3, 0xe9, 0xaa, 0x17, 0x18, 0x9d, 0xb5, 0x16, 0x95, 0x4d, 0xd5, 0x39, 0x2b, 0x5d, 0x51, 0x15, 0xe4, 0xf0, 0xb3, 0xe4, 0x6e, 0x03, 0x68, 0x08, 0xed, 0xa1, 0x03, 0xb5, 0xa4, 0x13, 0xcb, 0xce, 0x2c, 0xa9, 0x66, 0x4a, 0x57, 0x6e, 0x77, 0x33, 0xf2, 0x7b, 0xba, 0xf2, 0x9a, 0x7c, 0x8e, 0xfc, 0x4e, 0x55, 0xe6, 0xb0, 0x5c, 0xc0,\n\t0xf2, 0x1d, 0x78, 0x17, 0xde, 0xe3, 0xfe, 0xfb, 0x90, 0x22, 0x5d, 0xea, 0x4d, 0xf2, 0x9c, 0x3a, 0x8e, 0xe5, 0x83, 0xf0, 0x34, 0x3c, 0x03, 0xcf, 0xc2, 0x73, 0x30, 0x1d, 0x12, 0xe0, 0x79, 0x78, 0x81, 0xea, 0xdd, 0x99, 0xb9, 0xed, 0x02, 0x5d, 0xa1, 0x1b, 0xdc, 0x00, 0xdd, 0xa1, 0x07, 0xc4, 0x43, 0x4f, 0xb8, 0x11, 0x6e, 0x82, 0x5e, 0xd0, 0x1b, 0xfa, 0x40, 0x5f, 0xb8, 0x19, 0x6e, 0x81, 0x5b, 0xa1, 0x1f, 0xf4, 0x87, 0xdb, 0x60, 0x00, 0xdc, 0x0e, 0x03, 0xe1, 0x0e, 0xb8, 0x13, 0x06, 0x49, 0xbf, 0xf5, 0x2e, 0xb8, 0x1b, 0x06, 0x03, 0xd5, 0xd7, 0x7a, 0x0f, 0x0c, 0x85, 0x61, 0x40, 0x15, 0xb6, 0xde, 0xc7, 0xfe, 0x8c, 0x80, 0x91, 0x30, 0x0a, 0xee, 0x87, 0xd1, 0x30, 0x06, 0xc6, 0xc2, 0x03, 0xc0, 0x71, 0x59, 0x39, 0x2e, 0xeb, 0x43, 0x30, 0x1e, 0x26, 0xc0, 0x44, 0x78, 0x18, 0x26,\n\t0xc1, 0x64, 0x78, 0x04, 0x1e, 0x85, 0xc7, 0x60, 0x0a, 0x3c, 0x0e, 0x4f, 0xc0, 0x93, 0x6c, 0xe3, 0x29, 0x78, 0x1a, 0x9e, 0x81, 0x67, 0xe1, 0x39, 0x98, 0x0e, 0x09, 0xf0, 0x3c, 0xbc, 0x00, 0x33, 0x60, 0x26, 0xcc, 0x82, 0x17, 0xe1, 0x25, 0x98, 0x0d, 0x2f, 0xc3, 0x2b, 0x30, 0x87, 0x75, 0xcd, 0x85, 0x37, 0x60, 0x1e, 0xcc, 0x87, 0x37, 0x61, 0x01, 0xbc, 0x05, 0x0b, 0xe1, 0x6d, 0x78, 0x07, 0xde, 0x05, 0xba, 0x67, 0xeb, 0xfb, 0x90, 0x08, 0x1f, 0xc0, 0x87, 0xb0, 0x08, 0x16, 0xc3, 0x47, 0xb2, 0xc0, 0xfa, 0x31, 0x7c, 0x02, 0x4b, 0x60, 0x29, 0x2c, 0x83, 0x4f, 0xe1, 0x33, 0xf8, 0x1c, 0xbe, 0x80, 0x2f, 0xe1, 0x2b, 0x58, 0x0e, 0x2b, 0x60, 0x25, 0xac, 0x82, 0xaf, 0x61, 0x35, 0xac, 0x81, 0xb5, 0xf0, 0x0d, 0xac, 0x83, 0xf5, 0xf0, 0x2d, 0x6c, 0x92, 0x19, 0x7a, 0xe6, 0xa0, 0x3e, 0x33,\n\t0xf5, 0xab, 0xe4, 0x9a, 0x7a, 0x9a, 0xbf, 0xa8, 0xfe, 0x2f, 0xea, 0x48, 0xd4, 0x91, 0xe8, 0x3e, 0x35, 0xd7, 0xd6, 0x5c, 0x5b, 0x6b, 0x7e, 0xf4, 0x6f, 0xd6, 0xab, 0x6b, 0x6c, 0xac, 0xfa, 0x17, 0x7b, 0xb2, 0xea, 0x5f, 0x8d, 0xb2, 0xd8, 0x5e, 0xb1, 0x27, 0x6b, 0xde, 0x78, 0xf1, 0x5f, 0xfc, 0xc2, 0x9a, 0x0d, 0x8d, 0x5b, 0x6b, 0x2f, 0xfb, 0x57, 0x5e, 0xb3, 0xbc, 0xd6, 0xfc, 0x5a, 0xf3, 0xff, 0xf4, 0xf8, 0x15, 0x9e, 0x57, 0xfd, 0x1f, 0xaf, 0xd9, 0x5e, 0xbb, 0x57, 0xf5, 0x7f, 0xcd, 0xc7, 0x36, 0x3b, 0xc7, 0xbf, 0x9d, 0xcd, 0xc7, 0x5e, 0xfc, 0x67, 0xdc, 0xff, 0x2f, 0xff, 0xe9, 0xcf, 0xac, 0x3d, 0xb9, 0xf6, 0xaa, 0xba, 0x93, 0x6b, 0x1f, 0xbe, 0xf8, 0xaa, 0x3a, 0xd1, 0xcd, 0x76, 0xd6, 0x99, 0x59, 0xb5, 0x96, 0x3a, 0x29, 0x75, 0x7c, 0x75, 0xdb, 0xd6, 0x9d, 0xfc, 0x97, 0x6b,\n\t0xd8, 0xc9, 0x36, 0x67, 0xd7, 0x5d, 0x52, 0xb7, 0xbc, 0x41, 0x74, 0xd3, 0x60, 0x5c, 0x8d, 0xa6, 0xc1, 0xaa, 0x7f, 0xcd, 0x86, 0x55, 0xff, 0xd7, 0x7c, 0x76, 0xf3, 0xcd, 0x7f, 0xdc, 0xbb, 0xaa, 0x6d, 0x55, 0xbb, 0xc7, 0x33, 0x5a, 0xde, 0xfa, 0xc7, 0x7f, 0xcd, 0x1d, 0xcd, 0x1d, 0x2d, 0xfe, 0xf4, 0xe8, 0x95, 0xff, 0xe9, 0xcf, 0xad, 0xfe, 0x4f, 0x7f, 0x5d, 0x2b, 0xd1, 0x2a, 0xbb, 0xe5, 0x06, 0xfd, 0x9f, 0x7e, 0xab, 0xf5, 0x80, 0xcb, 0xff, 0xb5, 0xfd, 0xb8, 0xea, 0x5f, 0xeb, 0x6f, 0x2f, 0xde, 0x6a, 0xfb, 0x71, 0xfb, 0x27, 0xda, 0x3f, 0xd1, 0x76, 0xe7, 0xf5, 0xbb, 0xf4, 0x65, 0xd5, 0xbf, 0x0e, 0xa7, 0xfe, 0xfd, 0x7f, 0x1d, 0xdb, 0x76, 0x6c, 0xdb, 0xa9, 0xf5, 0xef, 0xff, 0x3a, 0x47, 0x77, 0x9b, 0xd2, 0x6d, 0x6d, 0xb7, 0xb5, 0x37, 0xd4, 0xaf, 0xfa, 0xd7, 0x7d, 0x94, 0xfe,\n\t0xef, 0xe2, 0xbd, 0x8b, 0xf7, 0x7f, 0xff, 0x17, 0xdf, 0x21, 0x7e, 0xa1, 0xfe, 0x4f, 0x98, 0x45, 0xb4, 0x65, 0xb4, 0xe5, 0x69, 0x21, 0x2c, 0xcf, 0x5a, 0xe6, 0x8b, 0xab, 0x2d, 0x0b, 0x2c, 0x8b, 0x44, 0x27, 0xcb, 0x3f, 0x94, 0xde, 0xa2, 0x97, 0xd2, 0x57, 0x19, 0x21, 0x4e, 0x2b, 0xa3, 0x94, 0x45, 0xe2, 0x6f, 0x45, 0xff, 0x5b, 0xd1, 0xff, 0x56, 0xf4, 0xff, 0x9e, 0xa2, 0xff, 0xdf, 0xe4, 0xf7, 0x8e, 0xd3, 0x9f, 0xf9, 0xe8, 0xcf, 0xbc, 0xc6, 0x2f, 0x14, 0xe9, 0xd7, 0x03, 0x39, 0xc2, 0xed, 0xa3, 0xec, 0x85, 0x83, 0xae, 0xf1, 0x18, 0xf7, 0x8f, 0xcb, 0x62, 0xd4, 0x41, 0x43, 0x1d, 0xca, 0x51, 0x87, 0x7c, 0xd4, 0xe1, 0x00, 0xea, 0x50, 0x48, 0xcf, 0xb6, 0x1b, 0x85, 0xf0, 0xa2, 0x10, 0x1e, 0x14, 0xa2, 0x14, 0x85, 0x28, 0xa3, 0x6f, 0xcb, 0x16, 0xb9, 0x74, 0x00, 0x79, 0xac, 0xcb,\n\t0x09, 0x2e, 0x99, 0x85, 0x52, 0x14, 0xa1, 0x14, 0x7e, 0x94, 0xc2, 0x87, 0x52, 0xe4, 0xa1, 0x14, 0x05, 0x28, 0x85, 0x7e, 0xde, 0xa1, 0x90, 0x23, 0x2a, 0x41, 0x09, 0xdc, 0x28, 0x81, 0x9f, 0x7e, 0x2e, 0x1d, 0x35, 0x38, 0x10, 0xc1, 0xcc, 0x44, 0x30, 0x33, 0xa8, 0x82, 0x1f, 0x55, 0xf0, 0xa3, 0x0a, 0x7e, 0x8e, 0x20, 0x9d, 0xfe, 0xc6, 0x8f, 0x12, 0x54, 0xa2, 0x04, 0xfe, 0xa8, 0x72, 0x69, 0xa3, 0xdf, 0xf3, 0xd2, 0xef, 0x79, 0xe9, 0xf7, 0xbc, 0xf4, 0x7b, 0x95, 0xf4, 0x7b, 0x95, 0xf4, 0x7b, 0x5e, 0xfa, 0x3d, 0x2f, 0xfd, 0x5e, 0x25, 0xfd, 0x5e, 0x25, 0xfd, 0x9e, 0x97, 0x7e, 0xcf, 0x4b, 0xbf, 0xe7, 0xa5, 0xdf, 0xf3, 0xd2, 0xef, 0x79, 0xe9, 0xf7, 0xbc, 0xf4, 0x7b, 0x5e, 0xfa, 0xbd, 0x4a, 0xfa, 0xbd, 0x4a, 0xfa, 0x3d, 0x2f, 0xfd, 0x9e, 0x97, 0x7e, 0xaf, 0x92, 0x7e, 0xaf, 0x92,\n\t0x7e, 0xcf, 0x8b, 0x7a, 0xe4, 0xd3, 0xef, 0x79, 0x51, 0x90, 0x54, 0x14, 0xc4, 0x8f, 0x82, 0xa4, 0xa2, 0x20, 0x7e, 0x14, 0xc4, 0x8f, 0x82, 0xf8, 0x51, 0x90, 0x54, 0x14, 0x24, 0x15, 0x05, 0xf1, 0xa3, 0x20, 0x5e, 0x14, 0xc4, 0x8f, 0x82, 0xf8, 0x51, 0x10, 0x3f, 0x0a, 0xe2, 0x47, 0x41, 0xfc, 0x28, 0x88, 0x1f, 0x05, 0xf1, 0xa3, 0x20, 0x7e, 0x14, 0xc4, 0xaf, 0xea, 0xd9, 0xd2, 0x59, 0x6a, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x68, 0x28, 0x88, 0x86, 0x82, 0x14,\n\t0xa3, 0x20, 0xc5, 0x28, 0x48, 0x31, 0x0a, 0x52, 0x8c, 0x82, 0x14, 0xa3, 0x20, 0xc5, 0x28, 0x48, 0x31, 0x0a, 0x52, 0x8c, 0x82, 0x14, 0xa3, 0x20, 0xe5, 0x28, 0x48, 0x39, 0x0a, 0x52, 0x8e, 0x82, 0x94, 0xa3, 0x20, 0xe5, 0x28, 0x48, 0x39, 0x0a, 0x52, 0x8e, 0x82, 0x94, 0xa3, 0x20, 0xe5, 0x28, 0x48, 0x39, 0x0a, 0x52, 0x8e, 0x82, 0x94, 0xa3, 0x20, 0xe5, 0x28, 0x48, 0x39, 0x0a, 0x52, 0x8e, 0x82, 0x94, 0xa3, 0x20, 0xe5, 0x28, 0x48, 0x39, 0x0a, 0x52, 0x8e, 0x82, 0x94, 0xa3, 0x20, 0xe5, 0x28, 0x48, 0x39, 0x0a, 0x52, 0x8e, 0x82, 0x94, 0xa3, 0x20, 0x85, 0x28, 0xc8, 0x59, 0x14, 0xa4, 0x10, 0x05, 0x29, 0x44, 0x41, 0x0a, 0x51, 0x90, 0x42, 0x14, 0xa4, 0x10, 0x05, 0x29, 0x44, 0x41, 0x0a, 0x51, 0x90, 0x42, 0x14, 0xe4, 0xac, 0x75, 0xa6, 0xe8, 0x89, 0x82, 0x54, 0xa2, 0x20, 0x85, 0x28,\n\t0x48, 0x21, 0x0a, 0x52, 0x81, 0x82, 0x14, 0xa2, 0x20, 0x85, 0xd6, 0xd7, 0xc8, 0xcc, 0xd7, 0x61, 0x8e, 0x2c, 0x42, 0x49, 0x8a, 0x50, 0x92, 0x22, 0x94, 0xa4, 0x08, 0x25, 0x29, 0x42, 0x49, 0x8a, 0x50, 0x92, 0x22, 0x94, 0xa4, 0x08, 0x25, 0x29, 0x42, 0x49, 0x8a, 0x50, 0x92, 0x22, 0x94, 0xa4, 0x08, 0x25, 0x29, 0x42, 0x49, 0x8a, 0x50, 0x92, 0x22, 0x94, 0xa4, 0x08, 0x25, 0x29, 0x42, 0x49, 0x8a, 0x50, 0x92, 0x22, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0x43, 0x49, 0x34, 0x94, 0x44, 0xb3, 0xea, 0xbf, 0x40,\n\t0x45, 0x4f, 0x2e, 0xbe, 0x16, 0xa5, 0x32, 0x20, 0xca, 0x8c, 0x6b, 0x0d, 0x78, 0xc4, 0x05, 0x79, 0x06, 0x35, 0x29, 0x36, 0xce, 0x5d, 0xd5, 0xa0, 0x67, 0x8e, 0x85, 0x5a, 0xd2, 0x8d, 0xaa, 0x68, 0xa6, 0x3a, 0x74, 0xea, 0x75, 0xa1, 0x9e, 0xfe, 0xfb, 0xdf, 0xa8, 0x4e, 0x03, 0xba, 0xe5, 0x86, 0x74, 0xcf, 0x57, 0x71, 0xff, 0x6a, 0xf8, 0xfd, 0x6a, 0x15, 0x5e, 0x53, 0x1c, 0x34, 0x01, 0xfd, 0x4a, 0x28, 0xcd, 0x58, 0x36, 0xa7, 0x8f, 0x6d, 0x21, 0x3d, 0xc6, 0x55, 0x51, 0x5a, 0x71, 0xbf, 0x35, 0xb4, 0x61, 0xbd, 0x6d, 0x59, 0x5e, 0x0b, 0xed, 0x64, 0x9e, 0xe9, 0x3a, 0x96, 0xd7, 0x43, 0x7b, 0xd6, 0xa1, 0x5f, 0x35, 0xa5, 0xa3, 0xf1, 0x4b, 0xe5, 0xfb, 0x51, 0x31, 0xe7, 0xa5, 0x2c, 0xdc, 0x6c, 0x5c, 0x9b, 0x20, 0x3f, 0x22, 0x19, 0x76, 0x51, 0x9b, 0x77, 0x73, 0x3f, 0x85, 0xdb, 0x69,\n\t0x2c, 0xd3, 0xf9, 0x7b, 0x1e, 0x4b, 0x27, 0xb8, 0x20, 0x1f, 0xce, 0xc8, 0xac, 0x08, 0x37, 0x4b, 0x0f, 0x14, 0x80, 0x57, 0x9e, 0x8e, 0x28, 0x64, 0x59, 0x04, 0xc5, 0xa0, 0x5f, 0x81, 0xc5, 0xc7, 0x63, 0x7e, 0xb2, 0x5b, 0x83, 0x52, 0x9e, 0x5f, 0xc6, 0xfd, 0x00, 0xb7, 0x83, 0x70, 0x96, 0xe7, 0x94, 0x93, 0xf1, 0x15, 0x50, 0xc9, 0xed, 0xaa, 0x2b, 0x5a, 0x78, 0x23, 0xce, 0xc3, 0x05, 0xfe, 0x2e, 0xa5, 0xd7, 0xf8, 0xc4, 0xbb, 0x49, 0xe6, 0x1b, 0x57, 0x6d, 0x89, 0xe0, 0x7e, 0x24, 0x44, 0xc9, 0xac, 0xc8, 0x68, 0x7c, 0x82, 0x7e, 0x15, 0x97, 0xaa, 0x2b, 0x5b, 0x78, 0x23, 0xfb, 0x43, 0xd5, 0x79, 0xbd, 0xe2, 0xc8, 0xbb, 0x79, 0xfe, 0x60, 0xee, 0x0f, 0x91, 0x87, 0x22, 0x51, 0x82, 0xc8, 0xa1, 0x32, 0x37, 0x72, 0x18, 0xcb, 0x7b, 0xe5, 0xee, 0x4b, 0x57, 0x7d, 0x19, 0x51, 0x75, 0xe5,\n\t0x97, 0x4b, 0xaa, 0x52, 0x24, 0x8f, 0xe8, 0x57, 0x81, 0xb1, 0xc4, 0xcb, 0x22, 0xcb, 0x78, 0x98, 0x00, 0x93, 0xe5, 0x09, 0x8b, 0xd7, 0xb8, 0x12, 0x86, 0x7e, 0x3d, 0x48, 0xaf, 0x92, 0x28, 0x8f, 0x5e, 0xe1, 0x6a, 0x18, 0x57, 0xbe, 0x6a, 0xcc, 0xd5, 0xfa, 0xb5, 0x4d, 0x50, 0x85, 0xd6, 0x2c, 0xf5, 0xeb, 0x9c, 0xdc, 0xc6, 0xed, 0x8b, 0x57, 0x92, 0x79, 0x89, 0xdb, 0xaf, 0x19, 0xd7, 0x7f, 0xc9, 0x08, 0x5f, 0x23, 0x32, 0x4b, 0x75, 0x4b, 0xb7, 0xaa, 0xff, 0xba, 0xb8, 0x0f, 0x18, 0x2f, 0x95, 0xf1, 0xa2, 0x42, 0xe8, 0xd7, 0x54, 0xf0, 0x5a, 0x37, 0x18, 0xd7, 0x4e, 0xf0, 0x58, 0xb7, 0xc0, 0x56, 0xd8, 0x06, 0x3b, 0xe4, 0x19, 0x6b, 0x32, 0x8f, 0xef, 0x92, 0x59, 0xd6, 0xdd, 0xb0, 0x57, 0x1e, 0xb1, 0xee, 0xe3, 0x3e, 0x2a, 0x6e, 0x3d, 0x00, 0x76, 0x38, 0x08, 0xa9, 0xac, 0x07, 0x35,\n\t0xb7, 0xe2, 0xf5, 0xac, 0x0e, 0xe9, 0x09, 0x7f, 0x62, 0xda, 0x1f, 0xb3, 0x0f, 0x15, 0xaf, 0x15, 0xae, 0x3a, 0x5e, 0xaa, 0x8e, 0x9f, 0xaa, 0x53, 0x74, 0x31, 0x12, 0xa8, 0x20, 0x15, 0x54, 0x8f, 0x02, 0xf3, 0xf7, 0x72, 0x97, 0xf1, 0x8e, 0xf5, 0xc5, 0x51, 0xda, 0xa5, 0xff, 0x0a, 0xa7, 0x88, 0x54, 0xbb, 0x0a, 0xf5, 0x7f, 0xe9, 0x8c, 0xe8, 0xff, 0xf9, 0x67, 0x2f, 0x6b, 0x1a, 0xef, 0xed, 0xeb, 0x9f, 0x1a, 0x9f, 0xcc, 0x31, 0x72, 0x4c, 0xa6, 0xc9, 0x22, 0x96, 0xd1, 0xc9, 0x63, 0x74, 0x34, 0x46, 0x24, 0x8f, 0x11, 0xb9, 0x5a, 0x6d, 0x26, 0xda, 0xa9, 0xcd, 0x39, 0xae, 0x16, 0x1c, 0x5f, 0x4b, 0x51, 0x93, 0x11, 0x6a, 0x62, 0x9c, 0x63, 0x73, 0x51, 0xb9, 0xf3, 0xc2, 0xd7, 0x12, 0xd3, 0x7f, 0x35, 0xdb, 0x63, 0xf2, 0x83, 0x26, 0x4b, 0x63, 0x06, 0x70, 0xf4, 0xff, 0xf9, 0xcf, 0x11,\n\t0xd4, 0x63, 0x0b, 0x47, 0x39, 0x92, 0x7c, 0xb6, 0xa2, 0xbf, 0x83, 0xed, 0xc6, 0x31, 0xe8, 0x73, 0x9d, 0xae, 0x1f, 0x0d, 0x6b, 0x75, 0x71, 0x44, 0xe9, 0xca, 0x4a, 0x51, 0x5b, 0xc9, 0x96, 0xd9, 0x6a, 0x1c, 0x47, 0xd6, 0x44, 0x06, 0x38, 0xc2, 0x66, 0x1c, 0x61, 0x5d, 0x8e, 0xb0, 0x2e, 0x47, 0xa7, 0x7f, 0x8f, 0xa0, 0x2d, 0x47, 0xd8, 0x5a, 0xb4, 0xc2, 0x31, 0xe8, 0xbf, 0x55, 0x73, 0x8a, 0xd9, 0xf3, 0x30, 0x7b, 0x7b, 0x98, 0xbd, 0x6d, 0xcc, 0x9e, 0x83, 0xd9, 0xcb, 0x63, 0xf6, 0xf6, 0x30, 0x7b, 0x9b, 0x99, 0xbd, 0x63, 0xcc, 0xde, 0x59, 0x66, 0xef, 0x34, 0xb3, 0x17, 0x60, 0xf6, 0x52, 0x98, 0xbd, 0x83, 0xcc, 0x5e, 0x01, 0xb3, 0xb7, 0x9f, 0xea, 0xbf, 0x87, 0xca, 0x5f, 0x46, 0xe5, 0xdf, 0x1c, 0x95, 0x2d, 0x9a, 0x33, 0x9b, 0xa5, 0xcc, 0x66, 0x29, 0xb3, 0x59, 0x6a, 0x7d, 0x4a,\n\t0xb4, 0xa2, 0x72, 0xf8, 0xa8, 0x1c, 0x21, 0x2a, 0x86, 0xcf, 0xfa, 0xbc, 0x30, 0x5b, 0x67, 0xf0, 0xd8, 0x4c, 0x31, 0xce, 0x3a, 0x4b, 0x34, 0xb7, 0xce, 0x16, 0x35, 0xa9, 0x12, 0x95, 0xd6, 0x57, 0x18, 0xed, 0x9a, 0x44, 0x64, 0x06, 0x5e, 0x2d, 0x48, 0x44, 0xee, 0x26, 0x22, 0x4f, 0x10, 0x91, 0x0e, 0x22, 0x31, 0x8d, 0x28, 0x4c, 0x25, 0x0a, 0xf5, 0xf7, 0x14, 0x8e, 0x91, 0x95, 0x41, 0x22, 0xb0, 0x6e, 0xf8, 0xba, 0x1f, 0xe9, 0x44, 0xa1, 0x4d, 0x34, 0xc5, 0x83, 0x1d, 0x61, 0x64, 0x3e, 0x12, 0x13, 0xa5, 0x64, 0x74, 0xbe, 0x65, 0x64, 0xf6, 0x32, 0x07, 0xf7, 0x98, 0x6e, 0x94, 0x25, 0xa6, 0x9b, 0xd0, 0xec, 0x81, 0x72, 0x39, 0xb3, 0x77, 0x8a, 0xd9, 0x3b, 0xc5, 0xec, 0xe5, 0x33, 0x6a, 0x67, 0x19, 0xb5, 0x1c, 0x46, 0xed, 0x0b, 0x46, 0x6d, 0x19, 0xa3, 0x96, 0xa3, 0xac, 0x24, 0x12,\n\t0xab, 0x46, 0xad, 0x05, 0xa3, 0x96, 0xc9, 0xa8, 0xb5, 0x63, 0xd4, 0x1a, 0x33, 0x6a, 0x8d, 0x89, 0x8b, 0x68, 0xe3, 0x5b, 0x18, 0xfa, 0x37, 0x30, 0xba, 0x8a, 0x0e, 0xea, 0xc3, 0x32, 0x4d, 0x9d, 0x23, 0x7f, 0x12, 0x56, 0xb6, 0x5a, 0xc6, 0x5c, 0x54, 0x9a, 0xf4, 0xdf, 0x1b, 0x7b, 0x53, 0x7a, 0xf4, 0x33, 0x90, 0xfa, 0x99, 0x54, 0x66, 0xb6, 0x94, 0xb5, 0x7a, 0x58, 0x83, 0x89, 0x35, 0x28, 0xa2, 0xf6, 0xc5, 0x33, 0xb6, 0xa6, 0x7b, 0x45, 0x6d, 0xd3, 0x70, 0x31, 0xd0, 0x34, 0x52, 0xf4, 0xaf, 0x7e, 0xf6, 0x36, 0xf2, 0x03, 0x71, 0x53, 0xe4, 0x22, 0x71, 0x73, 0xe4, 0x3f, 0x44, 0xef, 0xa8, 0xee, 0x22, 0x36, 0xaa, 0x07, 0x54, 0x3f, 0xa3, 0x6b, 0xbd, 0xd2, 0x39, 0x5f, 0x5e, 0xd1, 0x8a, 0x57, 0x34, 0xff, 0xc3, 0x33, 0x63, 0x2f, 0x6d, 0x6b, 0xb8, 0x88, 0x63, 0x3b, 0x57, 0x5f, 0xb6,\n\t0x9d, 0x5a, 0xbc, 0xaa, 0x3e, 0xaf, 0xaa, 0xf3, 0x87, 0x57, 0xc5, 0x11, 0x05, 0x7e, 0xa2, 0xe0, 0x0c, 0x51, 0xe0, 0x22, 0x0a, 0x4e, 0x12, 0x05, 0xa7, 0x88, 0x02, 0x27, 0x51, 0x90, 0x8d, 0x57, 0x4c, 0x0f, 0xfb, 0xc4, 0x33, 0x44, 0x42, 0x36, 0x91, 0x70, 0x86, 0x48, 0xf0, 0x10, 0x09, 0xd9, 0x44, 0x81, 0x8b, 0x2d, 0xb5, 0x63, 0x4b, 0x6d, 0x88, 0x86, 0x33, 0x44, 0x43, 0x21, 0xd1, 0x90, 0xcd, 0x96, 0x9a, 0xb3, 0xa5, 0x5e, 0x6c, 0xa9, 0x27, 0x91, 0x61, 0x26, 0x1a, 0xa2, 0x98, 0xfd, 0x28, 0x66, 0xff, 0x66, 0x66, 0xdf, 0x6c, 0x5c, 0x2b, 0xfd, 0x8a, 0x57, 0x82, 0xbc, 0xb8, 0xb6, 0x2b, 0x5d, 0x11, 0xb2, 0xfa, 0x5a, 0xff, 0x70, 0x75, 0x48, 0x6b, 0xb5, 0xa3, 0x8e, 0xe5, 0xd5, 0xea, 0x5f, 0x9e, 0x1b, 0xaf, 0x3e, 0x3e, 0xdd, 0x78, 0x66, 0xe7, 0xcb, 0xc6, 0xa7, 0x3d, 0xeb, 0x6f,\n\t0xcf, 0xfa, 0xdb, 0x5d, 0x76, 0x46, 0xfd, 0xe2, 0xab, 0x06, 0xd2, 0x43, 0xdc, 0xcb, 0x36, 0x86, 0x8b, 0x5a, 0xbc, 0x3a, 0xe6, 0xb2, 0x57, 0xd7, 0xe6, 0xd5, 0x35, 0x79, 0x75, 0xec, 0x5f, 0x6e, 0xd3, 0x38, 0xb6, 0xcb, 0x5e, 0xf5, 0xfb, 0x48, 0x55, 0x7f, 0xd5, 0x55, 0xbc, 0x2a, 0x83, 0x88, 0x76, 0x1b, 0xfa, 0xde, 0x13, 0x7d, 0x1f, 0xc8, 0xf2, 0x0e, 0x11, 0xc3, 0xf6, 0x1b, 0xb2, 0xa6, 0xc1, 0xac, 0xe9, 0x4e, 0xd6, 0xa4, 0xab, 0x4a, 0x0e, 0x6b, 0x3a, 0xc9, 0x9a, 0x6e, 0x63, 0x4d, 0x83, 0x59, 0xd3, 0x9d, 0x44, 0x51, 0x5d, 0xa2, 0xa8, 0x6e, 0x94, 0x7e, 0x85, 0xb8, 0x95, 0x28, 0x5d, 0x13, 0x2a, 0x53, 0x53, 0x29, 0xd5, 0xb6, 0xf2, 0x02, 0x51, 0x1c, 0x69, 0x5c, 0x85, 0x2b, 0x57, 0x94, 0xa3, 0xd4, 0x15, 0x64, 0x5d, 0x8c, 0x71, 0x4d, 0xf3, 0x53, 0xc6, 0x35, 0x1c, 0xab, 0x5f,\n\t0xd3, 0xbc, 0xbe, 0xdc, 0x88, 0x9f, 0xc9, 0xc3, 0xcf, 0x64, 0x5c, 0xba, 0xae, 0x79, 0x23, 0xb9, 0x09, 0x3f, 0xb3, 0xe9, 0xb2, 0xeb, 0x9b, 0x67, 0x85, 0xaf, 0x6f, 0xae, 0x5f, 0x05, 0x27, 0xab, 0xda, 0xf5, 0xcd, 0x3d, 0xd5, 0xae, 0x6f, 0xee, 0xaf, 0x76, 0x7d, 0xf3, 0x13, 0x78, 0x99, 0xac, 0xf0, 0xf5, 0xcd, 0x53, 0x8c, 0xa3, 0xa3, 0x92, 0x99, 0x7a, 0xc3, 0xad, 0xec, 0x4f, 0x3f, 0xe0, 0x68, 0x23, 0xec, 0x32, 0x18, 0x91, 0x05, 0x7f, 0xbe, 0xee, 0x79, 0xde, 0x65, 0xd7, 0x3d, 0xd7, 0x2e, 0xbb, 0xee, 0x79, 0x96, 0x71, 0x55, 0x1c, 0x3f, 0x3e, 0x46, 0x83, 0x52, 0xd6, 0x55, 0x75, 0x75, 0x1c, 0x0f, 0xfe, 0xc5, 0x73, 0xe9, 0xfa, 0xe7, 0x21, 0xb9, 0xa9, 0xda, 0x35, 0xd0, 0x3d, 0xe1, 0x6b, 0xa0, 0xbb, 0xf0, 0x2c, 0x59, 0xd5, 0xae, 0x81, 0x5e, 0x84, 0x67, 0x29, 0xc2, 0xb3, 0x64,\n\t0xe1, 0x59, 0x36, 0x19, 0xd7, 0x41, 0xff, 0xe3, 0xb5, 0xcf, 0xb3, 0xf0, 0x25, 0x59, 0x78, 0x92, 0x2c, 0x23, 0xf3, 0x8b, 0x64, 0x06, 0x7e, 0x24, 0xeb, 0x0f, 0x7e, 0xc4, 0x8b, 0xc6, 0x7c, 0x29, 0x33, 0xf0, 0x1f, 0x19, 0xf8, 0x8f, 0x0c, 0xfc, 0x47, 0x06, 0xfe, 0x23, 0x0b, 0xff, 0x91, 0x85, 0xff, 0xc8, 0xc2, 0x7f, 0x64, 0xe1, 0x3f, 0xb2, 0xf0, 0x1f, 0x59, 0xc6, 0xf5, 0xcf, 0x3b, 0xc9, 0x92, 0xf0, 0x35, 0xd0, 0xb3, 0xf0, 0x1d, 0x59, 0x97, 0xae, 0x81, 0xfe, 0xbe, 0x3c, 0xae, 0xea, 0xe7, 0x3d, 0x4e, 0xc9, 0x22, 0x7c, 0x87, 0x5f, 0xd5, 0x3d, 0x8b, 0x0f, 0x38, 0x4e, 0x7c, 0x87, 0x3f, 0x7c, 0x1d, 0xf4, 0x3c, 0x7c, 0x45, 0x1e, 0xbe, 0x22, 0xe3, 0x2f, 0xae, 0x83, 0xee, 0x09, 0x5f, 0x07, 0xfd, 0x04, 0x9e, 0xc2, 0x85, 0xa7, 0xc8, 0x32, 0xed, 0x10, 0x11, 0x44, 0x68, 0x24, 0x58,\n\t0x50, 0x7b, 0x05, 0x6a, 0x42, 0x3d, 0xaa, 0xc1, 0x35, 0x2c, 0xe3, 0xa0, 0x09, 0x34, 0x87, 0x96, 0xd4, 0xfa, 0x56, 0x70, 0x1d, 0xda, 0x77, 0x3d, 0x15, 0xa1, 0x03, 0x8f, 0x75, 0x94, 0xa9, 0xa2, 0x13, 0x74, 0x86, 0x2e, 0xd4, 0xa7, 0xae, 0x54, 0x90, 0x6e, 0x70, 0x03, 0x74, 0x87, 0x1e, 0x10, 0x0f, 0x7a, 0x3c, 0xf7, 0x66, 0xd9, 0x07, 0xc6, 0xf3, 0xbc, 0x09, 0x30, 0x11, 0x1e, 0x46, 0x4f, 0x26, 0x41, 0x38, 0xd6, 0xc5, 0xa3, 0xdc, 0x7e, 0x0c, 0xa6, 0xf0, 0xb7, 0xc7, 0xd1, 0xa1, 0x27, 0x58, 0x3e, 0x09, 0x4f, 0x71, 0x7b, 0x2a, 0x4c, 0x83, 0xa7, 0x59, 0xc7, 0x33, 0xf0, 0x2c, 0x3c, 0xc7, 0xfd, 0xe9, 0xfc, 0xfd, 0x79, 0x96, 0x2f, 0xb2, 0x9c, 0x4d, 0x7d, 0x7c, 0x19, 0x5e, 0x81, 0x57, 0xe1, 0x35, 0x78, 0x1d, 0xe6, 0xc0, 0x5c, 0x78, 0x03, 0xe6, 0xc1, 0x7c, 0x74, 0xee, 0x4d, 0x58,\n\t0x80, 0x96, 0xbd, 0x45, 0x7f, 0xbb, 0x10, 0xbd, 0x7b, 0x9b, 0x88, 0xad, 0xca, 0x35, 0x97, 0x29, 0x1f, 0x47, 0xe4, 0x26, 0xfa, 0x3d, 0xf2, 0xa4, 0x79, 0x00, 0x55, 0xe3, 0x6e, 0xb8, 0x17, 0x1e, 0x80, 0xf1, 0x30, 0x19, 0xe8, 0x91, 0xcc, 0xcf, 0x50, 0x55, 0x9e, 0x85, 0xe9, 0x38, 0x8b, 0x99, 0xf2, 0x94, 0x79, 0x16, 0xb7, 0x67, 0x1b, 0xbf, 0x68, 0x14, 0x32, 0xb3, 0x7d, 0x23, 0x47, 0x17, 0x53, 0x1f, 0x3e, 0xe1, 0xf1, 0x25, 0xb0, 0x96, 0xc7, 0xbe, 0x81, 0x8b, 0x79, 0x9b, 0x80, 0xeb, 0xd5, 0x23, 0x07, 0x25, 0x8c, 0x4a, 0x96, 0x67, 0xf4, 0x9c, 0x8d, 0xca, 0x92, 0x67, 0xa3, 0x4e, 0xcb, 0xbc, 0xa8, 0x42, 0x79, 0x32, 0xba, 0x95, 0x3c, 0x15, 0xdd, 0x5a, 0xe6, 0x47, 0xb7, 0x95, 0xa1, 0xe8, 0x0a, 0x99, 0x67, 0x69, 0x2f, 0xb3, 0x2d, 0x1d, 0xa0, 0x23, 0x74, 0x82, 0xce, 0xd0, 0x05,\n\t0xba, 0x42, 0x37, 0xb8, 0x01, 0x7a, 0xc2, 0x8d, 0x70, 0x13, 0xa0, 0x3e, 0x96, 0xde, 0xd0, 0x07, 0xfa, 0xc2, 0xcd, 0x70, 0x0b, 0xdc, 0x0a, 0xfd, 0xa0, 0x3f, 0xdc, 0x06, 0x03, 0xe0, 0x76, 0x18, 0x08, 0x77, 0xc0, 0x9d, 0x30, 0x11, 0x9e, 0x94, 0x67, 0x2d, 0x1c, 0xa7, 0x65, 0x2a, 0x4c, 0x83, 0xe7, 0x60, 0x05, 0xac, 0x84, 0x55, 0xf0, 0x35, 0xac, 0x86, 0x35, 0xb0, 0x16, 0x0a, 0xa4, 0xc3, 0x52, 0x28, 0x1d, 0x4a, 0xac, 0x3c, 0xab, 0x10, 0x47, 0x4a, 0x2d, 0xa8, 0x0d, 0x75, 0xa0, 0x2e, 0xd4, 0x83, 0xfa, 0x70, 0x35, 0x34, 0x82, 0xc6, 0x40, 0x9c, 0x29, 0xc4, 0x99, 0x42, 0x9c, 0x29, 0x4d, 0xa1, 0x19, 0x10, 0x6f, 0x4a, 0x0b, 0x68, 0x09, 0xad, 0xa0, 0x35, 0xb4, 0x81, 0xb6, 0x70, 0x2d, 0xb4, 0x83, 0xeb, 0xe0, 0x7a, 0xe8, 0x0e, 0x03, 0x65, 0xb9, 0x72, 0x07, 0xdc, 0x09, 0x83, 0xe0,\n\t0x6e, 0x18, 0x0c, 0x43, 0xe0, 0x1e, 0x18, 0x0a, 0xcf, 0xe1, 0x35, 0xa7, 0x43, 0x02, 0x3c, 0x0f, 0x2f, 0xc0, 0x0c, 0xc0, 0x75, 0x29, 0xb8, 0x2e, 0xe5, 0x03, 0xd6, 0xf3, 0x21, 0x2c, 0x82, 0x7f, 0xc0, 0x3f, 0xe1, 0x23, 0xf8, 0x58, 0xa6, 0x2a, 0x9f, 0xc0, 0x12, 0x58, 0x0a, 0xcb, 0xe0, 0x53, 0xf8, 0x0c, 0x3e, 0x87, 0x2f, 0xe0, 0x2b, 0x58, 0x0e, 0x2b, 0x00, 0xcd, 0x55, 0x56, 0xb1, 0xfc, 0x1a, 0x56, 0xc3, 0x1a, 0x58, 0x0b, 0xdf, 0xc0, 0x3a, 0x58, 0x0f, 0xdf, 0xc2, 0x77, 0xf0, 0x3d, 0xfc, 0x00, 0x1b, 0x60, 0x23, 0xfc, 0x02, 0xbf, 0xc2, 0x26, 0xd8, 0x0c, 0x5b, 0xe9, 0x62, 0xb6, 0x01, 0x1d, 0x9e, 0xb2, 0x9d, 0xf5, 0xee, 0x80, 0x9d, 0x90, 0x0c, 0x7b, 0xe0, 0x10, 0x1c, 0x86, 0x54, 0x38, 0x02, 0x47, 0xc1, 0x01, 0xc7, 0xe0, 0x38, 0x64, 0xc2, 0x09, 0x38, 0x09, 0x59, 0x90, 0x0d,\n\t0x39, 0x70, 0x0a, 0x88, 0x31, 0x25, 0x17, 0x9c, 0xe0, 0x82, 0x7c, 0xd0, 0x3f, 0xed, 0x41, 0xdc, 0x2b, 0x05, 0xe0, 0xa5, 0x76, 0xd4, 0x96, 0xf9, 0x6a, 0x1d, 0xa8, 0x0b, 0xf5, 0x80, 0x38, 0x55, 0x1b, 0xc0, 0x55, 0xf2, 0x8c, 0xda, 0x08, 0x1a, 0x43, 0x1c, 0x5c, 0xac, 0x31, 0xcd, 0xb8, 0xdd, 0x1c, 0x5a, 0x40, 0x4b, 0x68, 0x03, 0x7a, 0xdd, 0x69, 0xc7, 0xb2, 0x03, 0x74, 0x84, 0xce, 0x40, 0x1d, 0x52, 0x6f, 0x60, 0x3d, 0xdd, 0x41, 0xbf, 0x6e, 0x71, 0x3c, 0xf4, 0x84, 0x5e, 0xd0, 0x1b, 0xfa, 0x40, 0x5f, 0xb8, 0x19, 0x6e, 0x81, 0x5b, 0xa1, 0x1f, 0xf4, 0x87, 0x01, 0xf2, 0x94, 0x7a, 0x3b, 0x0c, 0x84, 0x41, 0x70, 0x17, 0xdc, 0x0d, 0x83, 0x61, 0x08, 0xdc, 0x03, 0x43, 0x61, 0x18, 0xdc, 0x0b, 0xc3, 0x61, 0x04, 0xc7, 0x32, 0x12, 0x46, 0xc1, 0xfd, 0x30, 0x1a, 0xc6, 0xc0, 0x58, 0x78,\n\t0x00, 0xc6, 0xc3, 0x04, 0x98, 0x08, 0x0f, 0xc3, 0x24, 0x98, 0x0c, 0x8f, 0xc0, 0xa3, 0xf0, 0x18, 0x4c, 0x81, 0xc7, 0xe1, 0x09, 0x78, 0x12, 0x9e, 0x82, 0xa9, 0x30, 0x0d, 0x66, 0xc2, 0x2c, 0x78, 0x11, 0xc8, 0x7f, 0xf5, 0x65, 0x78, 0x1d, 0xe6, 0xc0, 0x5c, 0x78, 0x03, 0xe6, 0xc1, 0x7c, 0x78, 0x13, 0xde, 0x82, 0x85, 0xf0, 0x91, 0x0c, 0xa9, 0x1f, 0xc3, 0x27, 0xb0, 0x04, 0x96, 0xc2, 0x32, 0xf8, 0x14, 0x3e, 0x83, 0xcf, 0xe1, 0x0b, 0xf8, 0x12, 0xbe, 0x82, 0xe5, 0xb0, 0x02, 0x56, 0xc2, 0x2a, 0xf8, 0x1a, 0x56, 0xc3, 0x1a, 0x40, 0x5b, 0x54, 0xb4, 0x45, 0x5d, 0x07, 0xeb, 0xe1, 0x5b, 0xf8, 0x0e, 0xbe, 0x87, 0x1f, 0x60, 0x03, 0xfc, 0x08, 0x3f, 0xc1, 0xcf, 0xb0, 0x11, 0x7e, 0x81, 0x5f, 0x61, 0x13, 0x6c, 0x86, 0x2d, 0xb0, 0x15, 0xb6, 0xc1, 0x6f, 0xf2, 0xa4, 0x9a, 0x04, 0xdb, 0x61,\n\t0x07, 0xec, 0x84, 0x64, 0xd8, 0x05, 0xbb, 0x61, 0x0f, 0xec, 0x85, 0x7d, 0x60, 0x83, 0xfd, 0x70, 0x00, 0xec, 0x70, 0x10, 0x0e, 0xc1, 0x61, 0x48, 0x85, 0x23, 0xe0, 0x00, 0xfc, 0xa5, 0x7a, 0x1c, 0x7f, 0x9c, 0x06, 0x19, 0x38, 0x9e, 0x4c, 0x38, 0x01, 0x27, 0x21, 0x0b, 0xb2, 0x21, 0x07, 0x4e, 0xe3, 0xf0, 0x72, 0xc1, 0xc9, 0xf3, 0xf0, 0x9b, 0x6a, 0x3e, 0x9c, 0x81, 0x02, 0xf0, 0x42, 0x21, 0x14, 0x41, 0x31, 0x94, 0x50, 0xd5, 0xd2, 0xe5, 0x29, 0x6b, 0x81, 0x3c, 0x6b, 0xf5, 0x42, 0x21, 0x14, 0x41, 0x31, 0x94, 0x51, 0x0d, 0x03, 0x10, 0x84, 0xb3, 0xa0, 0xff, 0x56, 0x4b, 0x85, 0x3c, 0x69, 0xad, 0x84, 0x10, 0x9c, 0x83, 0xf3, 0xd4, 0x81, 0xcd, 0x62, 0x9f, 0x5c, 0x4f, 0x4f, 0xf4, 0x85, 0x48, 0x95, 0xbf, 0xe1, 0x86, 0x7f, 0xc4, 0x0d, 0xcf, 0xc4, 0x0d, 0x6f, 0x11, 0xc7, 0xe9, 0x62,\n\t0xd3, 0x64, 0x9a, 0x48, 0xa7, 0xcf, 0xcb, 0x90, 0x1b, 0x70, 0xc5, 0xef, 0x89, 0x13, 0x54, 0xcb, 0x6c, 0xb9, 0x04, 0x57, 0x5c, 0x84, 0x2b, 0xde, 0x2e, 0xf2, 0xe8, 0x09, 0x9c, 0xe0, 0x92, 0x0b, 0x44, 0xbe, 0xdc, 0x2f, 0xce, 0x70, 0xdb, 0xcd, 0xfa, 0x3c, 0x54, 0xbd, 0x02, 0x3a, 0x61, 0xaf, 0x4c, 0x32, 0xf5, 0x97, 0x7b, 0x4c, 0x03, 0x20, 0xfc, 0xab, 0x02, 0x11, 0xcb, 0xe5, 0x7a, 0x5c, 0xf3, 0x8f, 0x11, 0x2b, 0xe5, 0x4f, 0xb8, 0xe6, 0xf7, 0x22, 0xd6, 0xb1, 0xfc, 0x16, 0x36, 0xc8, 0x9f, 0x22, 0xe7, 0xca, 0x3d, 0x91, 0xf3, 0x60, 0xbe, 0xfc, 0x39, 0x72, 0x81, 0xfc, 0x19, 0x17, 0xdd, 0x22, 0xea, 0xac, 0xfc, 0x29, 0xaa, 0x42, 0xae, 0xb7, 0x3c, 0x2b, 0xd7, 0x2b, 0x0d, 0xa0, 0x21, 0xb4, 0x87, 0x0e, 0xa8, 0x6d, 0x27, 0x96, 0x9d, 0x59, 0x76, 0x81, 0xae, 0xdc, 0xee, 0x06, 0x29,\n\t0xf2, 0x27, 0x75, 0x1c, 0x3c, 0x08, 0x4f, 0xc3, 0x33, 0xf0, 0x2c, 0x3c, 0x07, 0xd3, 0x21, 0x01, 0x9e, 0x87, 0x17, 0xe4, 0x4f, 0xd6, 0xce, 0xf2, 0x37, 0x6b, 0x17, 0xe8, 0x0a, 0xdd, 0xe0, 0x06, 0xe8, 0x0e, 0x3d, 0x20, 0x1e, 0x7a, 0xc2, 0x8d, 0x70, 0x13, 0xf4, 0x82, 0xde, 0xd0, 0x07, 0xfa, 0xc2, 0xcd, 0x70, 0x0b, 0xdc, 0x0a, 0xfd, 0xa0, 0x3f, 0xdc, 0x06, 0x03, 0xe0, 0x76, 0x18, 0x08, 0x77, 0xc0, 0x9d, 0x30, 0x48, 0x9e, 0xb0, 0xde, 0x05, 0x77, 0xc3, 0x60, 0x18, 0x02, 0xf7, 0xc0, 0x50, 0x18, 0x06, 0xf7, 0x02, 0x9e, 0xca, 0x3a, 0x02, 0xf0, 0x54, 0xd6, 0x51, 0x70, 0x3f, 0x8c, 0x86, 0x31, 0x30, 0x16, 0x1e, 0x80, 0x71, 0xf0, 0x20, 0xe0, 0x91, 0xac, 0xe3, 0x61, 0x02, 0x4c, 0x84, 0x87, 0x61, 0x12, 0x4c, 0x86, 0x47, 0xe0, 0x51, 0x78, 0x0c, 0xa6, 0xc0, 0xe3, 0xf0, 0x04, 0x3c,\n\t0x29, 0xb3, 0xe9, 0x48, 0xda, 0x5a, 0x9f, 0x66, 0xf9, 0x8c, 0xa8, 0x67, 0x7d, 0x56, 0x34, 0xb5, 0x3e, 0xc7, 0xed, 0xe9, 0x90, 0x20, 0x6a, 0xd0, 0xab, 0x36, 0xb5, 0xbe, 0xc0, 0xed, 0x19, 0x3c, 0x67, 0xa6, 0x78, 0x90, 0x8e, 0xa5, 0x85, 0xf5, 0x45, 0xee, 0x57, 0xbd, 0x3f, 0x52, 0x69, 0x7d, 0x99, 0xde, 0xf5, 0x15, 0xd1, 0xd7, 0x3a, 0x47, 0xee, 0xb7, 0xce, 0x85, 0x37, 0x60, 0x1e, 0xcc, 0x87, 0x37, 0x61, 0x01, 0xbc, 0x05, 0x0b, 0xe1, 0x6d, 0x78, 0x07, 0xde, 0x85, 0xf7, 0xe0, 0x7d, 0x48, 0x84, 0x0f, 0xe0, 0x43, 0x58, 0x04, 0x8b, 0xe1, 0x23, 0x99, 0x64, 0xfd, 0x18, 0x3e, 0x81, 0x25, 0xb0, 0x14, 0x96, 0xc1, 0xa7, 0xf0, 0x19, 0x7c, 0x0e, 0x5f, 0xc0, 0x97, 0xf0, 0x15, 0x2c, 0x87, 0x15, 0xb0, 0x12, 0x56, 0xc1, 0xd7, 0xb0, 0x1a, 0xd6, 0xc0, 0x5a, 0xf8, 0x06, 0xd6, 0xc1, 0x7a,\n\t0xf8, 0x16, 0x36, 0xc9, 0xf5, 0xc6, 0xb7, 0xf1, 0xb3, 0xe9, 0x97, 0x1b, 0xe2, 0xc5, 0x7e, 0xc5, 0x6b, 0x95, 0xe3, 0xa1, 0xec, 0xa6, 0x89, 0xf2, 0xb8, 0x69, 0x92, 0x4c, 0x33, 0x4d, 0x16, 0x35, 0xe9, 0x8e, 0xf3, 0x8c, 0x4f, 0x9f, 0xcf, 0x17, 0x5d, 0xf0, 0x2d, 0x1f, 0xe0, 0x4f, 0x4e, 0xe0, 0x47, 0xb6, 0x2a, 0x2b, 0xc5, 0x8d, 0xd4, 0x8d, 0x10, 0x1d, 0x72, 0x3f, 0x7a, 0xda, 0x9a, 0x74, 0xc5, 0xb1, 0x74, 0xc5, 0x5d, 0xe9, 0x8a, 0xef, 0x41, 0x2b, 0x35, 0x34, 0xcf, 0x6e, 0xac, 0xf9, 0x3f, 0xff, 0x8d, 0x8e, 0x9a, 0x7f, 0xd5, 0x49, 0x5e, 0xa9, 0x83, 0xfc, 0x43, 0xd7, 0x78, 0xd5, 0xff, 0xa4, 0xeb, 0xad, 0xde, 0xed, 0x5e, 0xb1, 0xc3, 0xfd, 0x77, 0x3e, 0xa7, 0x75, 0x85, 0x0e, 0xef, 0x0f, 0x1d, 0x5d, 0xd5, 0x99, 0x84, 0x2b, 0x77, 0x70, 0x97, 0xff, 0x6a, 0xc2, 0xa5, 0xdf, 0x18,\n\t0xf8, 0xbf, 0xe4, 0x53, 0x7b, 0xff, 0x67, 0x5c, 0x77, 0xf6, 0x3f, 0xff, 0xcd, 0xac, 0x7a, 0x64, 0xd8, 0x3e, 0xe3, 0xfc, 0x6f, 0x2f, 0xb9, 0x46, 0x4c, 0x14, 0x51, 0x44, 0x50, 0x90, 0xad, 0xdd, 0xc6, 0xd6, 0x56, 0xe9, 0xe7, 0xa2, 0x4c, 0xe3, 0x8d, 0x5f, 0x8b, 0xd6, 0xcf, 0x47, 0x55, 0xb0, 0x95, 0x53, 0x17, 0x3f, 0x1d, 0x1b, 0x3e, 0xab, 0x55, 0x87, 0xe8, 0xe9, 0x78, 0xe9, 0x1d, 0xc4, 0x9e, 0xc4, 0xca, 0x4a, 0x62, 0x65, 0x19, 0x31, 0xe2, 0x23, 0x46, 0x02, 0xc4, 0xc8, 0x36, 0x62, 0x24, 0x35, 0x1c, 0x23, 0x3f, 0x85, 0xbf, 0xeb, 0x55, 0x40, 0x6c, 0xa4, 0x10, 0x1b, 0x95, 0xd5, 0xb7, 0x44, 0x4c, 0x04, 0x88, 0x89, 0x8a, 0x8b, 0x5b, 0x20, 0x0f, 0x1a, 0x12, 0x13, 0xcb, 0x88, 0x89, 0x65, 0xc4, 0xc4, 0x32, 0x62, 0x22, 0x83, 0x98, 0xc8, 0x20, 0x26, 0x96, 0x11, 0x13, 0xcb, 0x88,\n\t0x89, 0x0c, 0x62, 0x22, 0x83, 0x98, 0x58, 0x46, 0x4c, 0x2c, 0x23, 0x26, 0x96, 0x11, 0x13, 0xcb, 0x88, 0x89, 0x65, 0xc4, 0xc4, 0x32, 0x62, 0x62, 0x19, 0x31, 0x91, 0x41, 0x4c, 0x64, 0x10, 0x13, 0xcb, 0x88, 0x89, 0x65, 0xc4, 0x44, 0x06, 0x31, 0x91, 0x41, 0x4c, 0x2c, 0x23, 0x1e, 0xdc, 0xc4, 0x43, 0x88, 0x78, 0x08, 0x11, 0x0f, 0x21, 0xe2, 0x21, 0x44, 0xde, 0xd5, 0x41, 0xbf, 0xa3, 0xc9, 0xbd, 0x3a, 0xe4, 0xde, 0x7d, 0xe4, 0x5e, 0x43, 0xeb, 0x6c, 0xd1, 0xd8, 0xfa, 0x32, 0x31, 0xd2, 0x88, 0x18, 0x99, 0x1e, 0xfe, 0xc4, 0x71, 0x90, 0xf8, 0x38, 0x4c, 0x7c, 0xdc, 0x47, 0x7c, 0xec, 0x35, 0x75, 0x16, 0x8d, 0xfe, 0x70, 0x24, 0x64, 0x07, 0xf1, 0x10, 0x24, 0x16, 0x16, 0x13, 0x0b, 0x0e, 0xe2, 0x60, 0x20, 0x71, 0x50, 0x49, 0x0c, 0x1c, 0xaf, 0xf6, 0xe9, 0xe2, 0x87, 0x98, 0xff, 0x07,\n\t0xe9, 0xd0, 0xcf, 0x12, 0x03, 0x6e, 0x62, 0xa0, 0x82, 0x18, 0xa8, 0x14, 0x8d, 0x89, 0x81, 0x72, 0x62, 0xa0, 0x9c, 0x59, 0x29, 0x27, 0x06, 0xd2, 0x99, 0x99, 0xcd, 0xc4, 0xc0, 0x09, 0x5d, 0x5d, 0x8d, 0x2b, 0x16, 0xe8, 0x57, 0xe9, 0x78, 0x0c, 0x2d, 0x9b, 0x2f, 0xda, 0x85, 0xcf, 0xd8, 0x16, 0x32, 0x33, 0xa7, 0x99, 0xf3, 0x72, 0xfd, 0xac, 0x2d, 0xf3, 0x5e, 0xce, 0xbc, 0x97, 0x33, 0xef, 0xe5, 0xcc, 0x7b, 0x39, 0xf3, 0x5e, 0xce, 0xbc, 0x97, 0x33, 0xef, 0xe5, 0xe4, 0xfc, 0x79, 0x66, 0xcc, 0xa4, 0x2b, 0xac, 0x78, 0x91, 0xe3, 0xa9, 0xe4, 0x78, 0x4a, 0x8c, 0xab, 0xcd, 0xd6, 0x96, 0xe7, 0x2e, 0x7b, 0xf7, 0x29, 0xdb, 0xd4, 0x40, 0x1e, 0x33, 0x35, 0x44, 0xcb, 0x7f, 0x7f, 0xf7, 0xc9, 0x69, 0x6a, 0x0c, 0x7f, 0x7c, 0xf7, 0x29, 0x14, 0x7e, 0xf7, 0x69, 0xab, 0xa9, 0x25, 0xb7, 0xaf,\n\t0xfc, 0xce, 0xd3, 0xce, 0x6a, 0xef, 0x3c, 0xa5, 0x99, 0x3a, 0xf0, 0xbc, 0xaa, 0x77, 0x9e, 0xf4, 0x68, 0xd6, 0x22, 0x76, 0xcb, 0xca, 0x88, 0x34, 0x48, 0x87, 0x3f, 0xbf, 0xbb, 0x74, 0xec, 0xb2, 0x77, 0x97, 0xb6, 0x5e, 0xf6, 0xee, 0x52, 0x28, 0xc2, 0xc7, 0x63, 0xa5, 0xf2, 0x70, 0x44, 0x19, 0xcb, 0xea, 0xef, 0x2a, 0x55, 0xbd, 0x9b, 0xe4, 0xfc, 0xd3, 0xbb, 0x49, 0x66, 0x19, 0xaa, 0xf6, 0x2e, 0xd2, 0x61, 0xf2, 0xf6, 0x70, 0xa4, 0x85, 0xc7, 0xac, 0xe4, 0xb0, 0xfe, 0x2e, 0x92, 0xfe, 0xae, 0x91, 0xfe, 0x8e, 0x91, 0xfe, 0x6e, 0xd1, 0x7d, 0x3c, 0x3e, 0x1c, 0x46, 0xc2, 0x22, 0xe3, 0x1a, 0xe9, 0x69, 0x51, 0xc5, 0x32, 0x64, 0x89, 0x97, 0x6e, 0xcb, 0x78, 0x98, 0x00, 0x5e, 0x79, 0x4e, 0x99, 0x25, 0x2b, 0x95, 0x2f, 0xa5, 0xa6, 0xfc, 0x04, 0x3f, 0xc3, 0x16, 0xd8, 0x45, 0x54, 0xd9,\n\t0x21, 0x0d, 0x32, 0xc0, 0x43, 0xcd, 0xb3, 0x82, 0x7e, 0xee, 0xb9, 0x13, 0xb3, 0x51, 0xf5, 0x6e, 0x50, 0x48, 0x9d, 0x01, 0xbf, 0xbf, 0x1b, 0x94, 0x1f, 0x7e, 0x37, 0xe8, 0xb0, 0xea, 0x96, 0x07, 0x54, 0x0f, 0xf8, 0xc0, 0x0f, 0x9a, 0x3c, 0x10, 0x7e, 0xb7, 0xe7, 0x98, 0x75, 0x37, 0xec, 0x95, 0x69, 0xff, 0xc5, 0xbb, 0x3d, 0x69, 0x31, 0xf8, 0x6e, 0x61, 0x25, 0x96, 0xce, 0x11, 0x47, 0x21, 0xe2, 0xa8, 0x42, 0x1f, 0xf1, 0xf0, 0x39, 0xeb, 0x7d, 0xc6, 0xe7, 0x02, 0x16, 0x19, 0xef, 0x5f, 0xe4, 0xa0, 0xfa, 0xd1, 0x26, 0x41, 0x06, 0xbf, 0x80, 0x73, 0xdd, 0x45, 0x16, 0x27, 0xe0, 0x5e, 0x77, 0x88, 0xc3, 0xb8, 0xd1, 0x54, 0x19, 0x4b, 0x46, 0xaf, 0x22, 0xa3, 0x17, 0x50, 0xdd, 0x6e, 0x24, 0xab, 0x3f, 0xc1, 0xc5, 0x36, 0x30, 0x2a, 0x5c, 0xba, 0x9c, 0x4a, 0x76, 0xff, 0x93, 0x2a, 0x77,\n\t0x2f, 0x2e, 0xb6, 0x2f, 0x59, 0xee, 0x16, 0x59, 0xb2, 0x33, 0xd5, 0x60, 0x38, 0x99, 0xbe, 0x8a, 0x4a, 0xd0, 0x53, 0xe4, 0xca, 0x68, 0x1c, 0x6d, 0x2c, 0x8e, 0x36, 0x96, 0xaa, 0x77, 0x3f, 0x8e, 0x36, 0x1e, 0x47, 0x1b, 0x8b, 0x0a, 0xd4, 0xc0, 0xd1, 0x4e, 0x44, 0x09, 0xba, 0xe0, 0x68, 0xaf, 0x21, 0x87, 0x12, 0x4c, 0x37, 0xca, 0x25, 0xa6, 0x9b, 0xe4, 0x47, 0xa6, 0x5e, 0xf2, 0x79, 0x53, 0x6f, 0xb8, 0x55, 0xbe, 0x62, 0xea, 0x07, 0xfd, 0xe5, 0x04, 0xd3, 0x6d, 0xf2, 0x29, 0x1c, 0xef, 0x04, 0xd3, 0xed, 0x2c, 0x07, 0xca, 0x39, 0x38, 0xdf, 0xf9, 0x38, 0xdf, 0xf9, 0x38, 0xdf, 0x5d, 0xa8, 0xc7, 0x02, 0x9c, 0x6f, 0x2c, 0x0a, 0xd2, 0x89, 0x2a, 0x7a, 0x6f, 0xc4, 0x5a, 0x19, 0x1d, 0xf1, 0x0d, 0xac, 0xe3, 0xb1, 0x6f, 0x61, 0x83, 0x8c, 0xc5, 0x05, 0xbf, 0x83, 0x0b, 0x7e, 0x07, 0x17,\n\t0xfc, 0x46, 0xe4, 0x9b, 0x72, 0x2d, 0x4e, 0xf8, 0x8d, 0xc8, 0xb7, 0xe4, 0xda, 0xa8, 0x6c, 0x9c, 0xc0, 0x59, 0x19, 0x1b, 0x55, 0x2e, 0x3b, 0xe2, 0x88, 0x77, 0xa1, 0x3a, 0x09, 0xa8, 0x4e, 0x02, 0xaa, 0x93, 0x80, 0xea, 0xec, 0x43, 0x75, 0xf6, 0xa1, 0x3a, 0x09, 0xa8, 0x4e, 0x02, 0xaa, 0xb3, 0x0f, 0xd5, 0xd9, 0x87, 0xea, 0x24, 0xa0, 0x3a, 0x09, 0xa8, 0x4e, 0x02, 0xaa, 0x93, 0x80, 0xea, 0x24, 0xa0, 0x3a, 0x09, 0xa8, 0x4e, 0x02, 0xaa, 0xb3, 0x0f, 0xd5, 0xd9, 0x87, 0xea, 0x24, 0xa0, 0x3a, 0x09, 0xa8, 0xce, 0x3e, 0x54, 0x67, 0x1f, 0xaa, 0x93, 0x80, 0xdb, 0xde, 0x85, 0xdb, 0xde, 0x85, 0xdb, 0xde, 0x85, 0xdb, 0xde, 0x85, 0xdb, 0x4e, 0xc7, 0x6d, 0xef, 0xc2, 0x6d, 0xa7, 0xe3, 0xb6, 0xd3, 0x71, 0xdb, 0xbb, 0x70, 0xdb, 0xbb, 0x70, 0xdb, 0xb1, 0xea, 0x4d, 0xb2, 0x33, 0x8e, 0x3b,\n\t0x16, 0xc7, 0x1d, 0x8b, 0xe3, 0x8e, 0xc5, 0x71, 0xc7, 0xe2, 0xb8, 0x63, 0x71, 0xdc, 0xb1, 0x38, 0xee, 0x58, 0x1c, 0x77, 0x2c, 0x8e, 0x3b, 0x16, 0xc7, 0x1d, 0x6b, 0x6d, 0x2c, 0xb7, 0x5b, 0xe3, 0xa0, 0x89, 0x4c, 0xb7, 0x36, 0x85, 0x66, 0xd0, 0x9c, 0xfb, 0x2d, 0x58, 0xb6, 0x84, 0x56, 0xd0, 0x9a, 0xfb, 0x6d, 0xa0, 0x2d, 0x5c, 0x0b, 0xed, 0x78, 0xec, 0x3a, 0xb8, 0x1e, 0xda, 0x73, 0x9f, 0x7d, 0xb1, 0x76, 0x84, 0x4e, 0xd0, 0x99, 0x75, 0x76, 0x81, 0xae, 0xb2, 0x21, 0x0e, 0xbe, 0x05, 0x0e, 0x3e, 0x16, 0x07, 0x1f, 0x8b, 0x83, 0x6f, 0x88, 0x83, 0x6f, 0x87, 0x83, 0x8f, 0xc5, 0xc1, 0xc7, 0xe2, 0xe0, 0x63, 0x71, 0xf0, 0x3d, 0x70, 0xf0, 0xcd, 0x71, 0xf0, 0xed, 0x71, 0xf0, 0xb1, 0x38, 0xf8, 0x58, 0x1c, 0x7c, 0x43, 0x1c, 0x7c, 0x0b, 0x1c, 0x7c, 0x2c, 0x0e, 0x3e, 0x16, 0x07, 0xdf,\n\t0x10, 0x07, 0xdf, 0x0e, 0x07, 0x1f, 0x8b, 0x83, 0x8f, 0xc5, 0xc1, 0xc7, 0xe2, 0xe0, 0x7b, 0xe0, 0xe0, 0x1b, 0xe0, 0xe0, 0x1b, 0xe0, 0xe0, 0xdb, 0xe0, 0xe0, 0xbb, 0xe0, 0xe0, 0x1b, 0xe0, 0xe0, 0xdb, 0xe0, 0xe0, 0x7b, 0xe2, 0xe0, 0x1b, 0xe0, 0xe0, 0x1b, 0xe0, 0xe0, 0xa7, 0xe2, 0xe0, 0xa7, 0xe2, 0xe0, 0xa7, 0xe2, 0xe0, 0xa7, 0xe2, 0xe0, 0xa7, 0xe2, 0xe0, 0xa7, 0xe2, 0xe0, 0xa7, 0xe2, 0xe0, 0xa7, 0xe2, 0xe0, 0xa7, 0xe2, 0xe0, 0xa7, 0xfe, 0x3f, 0xe4, 0xbd, 0x07, 0x78, 0x14, 0x55, 0x1b, 0xf6, 0x7f, 0x66, 0x53, 0x76, 0x66, 0x37, 0xf4, 0x84, 0x24, 0x84, 0x34, 0x08, 0x49, 0x28, 0xd2, 0x09, 0x0a, 0xa1, 0x47, 0x44, 0x8a, 0x80, 0x58, 0xb0, 0x21, 0xf6, 0x8a, 0x85, 0xa2, 0xa8, 0xa8, 0xd8, 0x10, 0x7d, 0x01, 0x1b, 0x36, 0xb0, 0x22, 0x22, 0xa2, 0x08, 0x2f, 0x16, 0x34, 0xaf, 0x20,\n\t0x28, 0x04, 0x24, 0xb4, 0x44, 0x5c, 0x96, 0xb0, 0x10, 0x43, 0x12, 0xb2, 0x09, 0x0b, 0x84, 0xc0, 0x46, 0x08, 0xc8, 0xf9, 0xff, 0xe6, 0x64, 0x12, 0x37, 0x01, 0x6c, 0xff, 0xf7, 0xfd, 0xae, 0xef, 0xba, 0xbe, 0xcc, 0x75, 0xef, 0x4e, 0x76, 0x67, 0xcf, 0x9c, 0x73, 0x9f, 0xe7, 0x9c, 0xfb, 0x7e, 0x66, 0x67, 0x67, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0x13, 0x70, 0xf0, 0xfd, 0x1d, 0x77, 0xcb, 0x63, 0x38, 0xf8, 0x17, 0x70, 0xf0, 0xa6, 0x02, 0x24, 0xe3, 0xe0, 0x5f, 0xc0, 0xc1, 0xbf, 0x80, 0x83, 0x8f, 0xc4, 0xc1, 0xb7, 0xc5, 0xc1, 0xbf, 0xe0, 0x78, 0x90, 0x6d, 0x94, 0x83,\n\t0xc7, 0xf3, 0x3d, 0x2c, 0x07, 0xe3, 0xe0, 0x7f, 0xc2, 0xc1, 0x7b, 0x50, 0x87, 0x8d, 0x38, 0xf8, 0x01, 0x8e, 0xe9, 0x32, 0xd4, 0xf1, 0x04, 0x78, 0x52, 0xa6, 0xe1, 0xe4, 0xd3, 0x70, 0xf2, 0x69, 0x38, 0xf9, 0x34, 0x9c, 0x7c, 0x1a, 0x4e, 0x3e, 0x0d, 0x27, 0x9f, 0x86, 0x93, 0x4f, 0xc3, 0xc9, 0xa7, 0xe1, 0xe4, 0xd3, 0x70, 0xf2, 0x69, 0x38, 0xf9, 0xbb, 0x70, 0xf2, 0x77, 0xe1, 0xe4, 0xd3, 0x70, 0xf2, 0x69, 0x38, 0xf9, 0x34, 0x9c, 0x7c, 0x1a, 0x4e, 0x3e, 0x0d, 0x27, 0x9f, 0x86, 0x93, 0x8f, 0xc1, 0xc9, 0xc7, 0xe0, 0xe4, 0x63, 0x70, 0xf2, 0x31, 0x38, 0xf9, 0x18, 0x9c, 0x7c, 0x0c, 0x4e, 0x3e, 0x06, 0x27, 0x1f, 0x83, 0x93, 0x8f, 0xc1, 0xc9, 0xc7, 0xe0, 0xe4, 0x63, 0x70, 0xf2, 0x31, 0x38, 0xf9, 0x18, 0x9c, 0x7c, 0x0c, 0x4e, 0x3e, 0x06, 0x27, 0x1f, 0x83, 0x93, 0x8f, 0xc1, 0xc9,\n\t0xc7, 0xe0, 0xe4, 0x63, 0x70, 0xf2, 0x31, 0x38, 0xf9, 0x18, 0x9c, 0x7c, 0x0c, 0x4e, 0x3e, 0x06, 0x27, 0x1f, 0x83, 0x93, 0x5f, 0x87, 0x93, 0x9f, 0x81, 0xfb, 0xdd, 0xe6, 0x7c, 0x49, 0x9e, 0x27, 0xda, 0xaa, 0x2b, 0xdf, 0x49, 0xb9, 0x1a, 0x65, 0xf8, 0x56, 0x6b, 0x88, 0x9b, 0x6f, 0x24, 0xa7, 0xa1, 0x0e, 0x8b, 0x50, 0x04, 0xf3, 0x1e, 0xe5, 0x57, 0x31, 0x6b, 0xb7, 0x40, 0xf1, 0x22, 0x71, 0xc5, 0xb7, 0xd6, 0x19, 0xb1, 0x8c, 0x48, 0x5c, 0xf2, 0x45, 0xa8, 0xde, 0x44, 0x14, 0xcf, 0x40, 0xf1, 0x06, 0xe0, 0x7c, 0xe6, 0xa1, 0x7a, 0x69, 0xa8, 0xdd, 0x08, 0x66, 0xc9, 0xa9, 0xfa, 0x50, 0x66, 0xc1, 0x2f, 0xe4, 0x70, 0x66, 0xc8, 0x51, 0xcc, 0x88, 0x6d, 0x99, 0x11, 0xe3, 0x99, 0x0d, 0xb7, 0x1a, 0x49, 0x22, 0x99, 0x59, 0x30, 0x91, 0xd9, 0x2f, 0x8e, 0xd9, 0x6f, 0x02, 0x4a, 0xd8, 0x85,\n\t0xd9, 0xed, 0x19, 0x66, 0xb2, 0xab, 0x99, 0xc5, 0x1e, 0x70, 0xec, 0x90, 0xab, 0x54, 0x0d, 0xbf, 0x95, 0x19, 0xcc, 0x68, 0x89, 0xe2, 0x3a, 0x2b, 0x33, 0xb8, 0x46, 0x0c, 0x92, 0x4f, 0x88, 0x0c, 0xf9, 0xac, 0x18, 0xca, 0xf3, 0xe5, 0xe0, 0x2a, 0x70, 0x03, 0x6e, 0xf8, 0x66, 0x99, 0x61, 0xce, 0x76, 0xe2, 0x61, 0xf9, 0x6e, 0xfd, 0x5a, 0xe2, 0x69, 0x36, 0x69, 0xe3, 0xe5, 0x62, 0xb2, 0x86, 0x22, 0xb2, 0x86, 0x22, 0x72, 0x15, 0x3b, 0xfe, 0xf7, 0x55, 0xfc, 0xef, 0x5c, 0xfc, 0xef, 0xcb, 0xcc, 0x8e, 0x43, 0x98, 0x1d, 0x53, 0x98, 0x1d, 0x23, 0xc8, 0x12, 0xbc, 0xcc, 0x8e, 0x1f, 0x86, 0x6c, 0x95, 0x4f, 0x84, 0x6c, 0x93, 0x4f, 0xe8, 0x6f, 0xc8, 0x0c, 0x7d, 0x9e, 0x1c, 0xa9, 0xcf, 0x97, 0x7d, 0xf5, 0xb7, 0x68, 0xc5, 0xdb, 0xb4, 0xe2, 0x1d, 0x79, 0x81, 0xbe, 0x50, 0x5e, 0x82, 0xb3,\n\t0x2e, 0xd1, 0x17, 0xf1, 0xfc, 0x11, 0x58, 0xcc, 0x36, 0x1f, 0xcb, 0x3b, 0xf4, 0x25, 0xe0, 0x13, 0xf0, 0x29, 0x58, 0xca, 0x76, 0x9f, 0xc9, 0x6b, 0xf4, 0xb5, 0xb2, 0xa3, 0xfe, 0xbd, 0xec, 0xac, 0x6f, 0x93, 0xb1, 0x7a, 0x8e, 0x4c, 0xd5, 0x73, 0x65, 0x7b, 0xfd, 0x27, 0xca, 0xf1, 0xc8, 0x48, 0x7d, 0x8f, 0x4c, 0x21, 0x37, 0x5a, 0xac, 0xe7, 0xf3, 0xfc, 0x0b, 0x28, 0xe0, 0xfd, 0x43, 0xec, 0xf7, 0x30, 0x28, 0x07, 0xa7, 0x81, 0x94, 0xfd, 0x0d, 0x21, 0xdb, 0x18, 0x41, 0x72, 0xa0, 0x61, 0x97, 0xa9, 0x46, 0x03, 0xd9, 0x8e, 0x5c, 0xaa, 0x1b, 0xae, 0x7e, 0x25, 0xbe, 0xac, 0x2f, 0xbe, 0xac, 0x03, 0xb3, 0x79, 0x32, 0x79, 0x55, 0x14, 0x79, 0xd5, 0x79, 0x2a, 0xaf, 0xea, 0x22, 0x06, 0x19, 0x97, 0xc9, 0xe6, 0xc6, 0x15, 0x32, 0xc1, 0x18, 0x0b, 0xd3, 0x37, 0xc0, 0xfc, 0x8d, 0xf2, 0x3d,\n\t0xe3, 0x26, 0x9e, 0x6f, 0x06, 0xb7, 0xf0, 0xfa, 0xad, 0xb2, 0xb5, 0xf1, 0xa4, 0x5c, 0x60, 0x3c, 0x2b, 0xc7, 0x1a, 0xb3, 0xe4, 0xdd, 0xc6, 0x6c, 0xf9, 0x8c, 0x71, 0x8c, 0xd8, 0x84, 0x79, 0x87, 0x5f, 0x36, 0x17, 0x4d, 0x2c, 0x1d, 0x31, 0xbf, 0x39, 0x2e, 0x80, 0xdd, 0x32, 0xd8, 0x2d, 0x80, 0xdd, 0x1d, 0xb0, 0xba, 0xdf, 0xca, 0x35, 0x3c, 0xb0, 0xb6, 0xd3, 0xd2, 0x14, 0x33, 0xd7, 0x28, 0xa0, 0x56, 0x05, 0x75, 0x72, 0x8d, 0x7e, 0xf4, 0xdd, 0xd7, 0x94, 0x54, 0x45, 0x49, 0x8f, 0xd0, 0x57, 0x4d, 0x28, 0xed, 0x15, 0x4a, 0x5a, 0x49, 0x49, 0x77, 0xd1, 0x4f, 0x05, 0xf4, 0xd3, 0x2f, 0x94, 0xf8, 0x98, 0x76, 0xb1, 0x30, 0xb4, 0xd1, 0xa2, 0x91, 0x36, 0x46, 0x34, 0xd3, 0x2e, 0x17, 0x8d, 0xe9, 0xb7, 0xf5, 0xf4, 0x5b, 0x36, 0xfd, 0x56, 0x46, 0xbf, 0x95, 0xd1, 0x6f, 0xad, 0xe8, 0xb7,\n\t0xef, 0xe8, 0xb7, 0x55, 0xf4, 0x5b, 0x36, 0xee, 0xa8, 0x84, 0x5a, 0xe4, 0x52, 0x8b, 0x99, 0xd4, 0xe2, 0x1e, 0x33, 0xe3, 0xa1, 0xff, 0xca, 0x54, 0x4d, 0xde, 0x90, 0x2f, 0xd1, 0x5f, 0x8f, 0xd3, 0x57, 0xd3, 0xc9, 0x3f, 0x63, 0xe8, 0x9b, 0x85, 0xf4, 0xcd, 0x42, 0xfa, 0x66, 0x21, 0x7d, 0xb3, 0x90, 0xbe, 0x99, 0x4e, 0xdf, 0xbc, 0x43, 0xbf, 0x3c, 0x49, 0xbf, 0xdc, 0x47, 0x9f, 0x3c, 0x4a, 0x3f, 0x54, 0xc1, 0xf3, 0x54, 0x78, 0x7e, 0x0d, 0x8e, 0x1f, 0x85, 0xe3, 0xcb, 0x68, 0x4d, 0x8e, 0xf5, 0x3d, 0x78, 0x02, 0x1c, 0x77, 0x81, 0xe3, 0x2e, 0x70, 0x3c, 0xc8, 0x68, 0x23, 0x1a, 0xc1, 0xf3, 0x1d, 0xb4, 0xb0, 0x8d, 0xca, 0x61, 0x6f, 0x95, 0x93, 0xe1, 0x72, 0x2f, 0x5c, 0x7e, 0x0a, 0x97, 0x4f, 0xc0, 0xe5, 0xf7, 0x70, 0xb9, 0x4e, 0x9c, 0x4f, 0xeb, 0x4b, 0xf1, 0x78, 0x15, 0x78, 0xbc,\n\t0x0a, 0x58, 0xa8, 0x80, 0x85, 0x99, 0xb0, 0xe0, 0x84, 0x85, 0x4f, 0xad, 0x88, 0x35, 0x7f, 0x6b, 0x33, 0x17, 0x26, 0x0e, 0xc2, 0x84, 0x4f, 0x5d, 0x39, 0xf2, 0x7a, 0x18, 0x19, 0xaf, 0x5a, 0xdc, 0x98, 0xdc, 0xf6, 0x38, 0xad, 0x76, 0xd1, 0xea, 0x9f, 0x69, 0x75, 0x81, 0xfa, 0xe6, 0xfe, 0x16, 0xb8, 0xbf, 0x4d, 0xe9, 0x7a, 0x31, 0xad, 0x5f, 0x42, 0xeb, 0xe7, 0xe2, 0x07, 0xcd, 0x3e, 0x38, 0x8a, 0x1f, 0xac, 0xc0, 0x0f, 0x56, 0xe0, 0x07, 0x2b, 0xf0, 0x83, 0x15, 0xf8, 0xc1, 0x0a, 0xfc, 0x60, 0x05, 0x7e, 0xb0, 0xc2, 0x62, 0x62, 0x11, 0x4c, 0x2c, 0x82, 0x89, 0x45, 0x30, 0xb1, 0x08, 0x16, 0xde, 0xa5, 0xe5, 0xc7, 0x69, 0xf5, 0xab, 0xb4, 0x78, 0x20, 0x2d, 0xde, 0x41, 0x8b, 0x5b, 0xd2, 0xe2, 0x70, 0x5a, 0x9c, 0x44, 0x8b, 0x63, 0x69, 0x71, 0x57, 0x5a, 0x3b, 0x92, 0xd6, 0x26, 0xa8,\n\t0x6b, 0x7b, 0x3d, 0x29, 0x3d, 0xaa, 0xa5, 0xb3, 0x71, 0x0b, 0x6e, 0xfc, 0xc3, 0x06, 0xbc, 0xc3, 0x2a, 0xbc, 0x43, 0x15, 0xde, 0x21, 0xd3, 0x3a, 0x8f, 0x70, 0x05, 0xde, 0xe1, 0x59, 0xbc, 0xc3, 0x57, 0x78, 0x87, 0x9d, 0x78, 0x07, 0x0f, 0xde, 0x21, 0x17, 0xef, 0xf0, 0x29, 0xde, 0x61, 0x16, 0xde, 0x61, 0x3b, 0xbe, 0xa1, 0x0c, 0xdf, 0xb0, 0xd0, 0x3a, 0x4b, 0x60, 0x3d, 0xde, 0xe1, 0x04, 0xde, 0xa1, 0x1c, 0xef, 0xb0, 0x1c, 0xef, 0xb0, 0x1c, 0xef, 0xf0, 0x0a, 0xde, 0x61, 0x35, 0xde, 0x61, 0x39, 0xde, 0xe1, 0x23, 0xbc, 0xc3, 0x4f, 0x78, 0x87, 0xcf, 0xf1, 0x0e, 0x99, 0x01, 0x47, 0xc3, 0xb6, 0xe3, 0x09, 0xb6, 0xe3, 0x09, 0x36, 0xe0, 0x09, 0x56, 0xe0, 0x09, 0x96, 0xe3, 0x07, 0x66, 0xe1, 0x07, 0xca, 0xf1, 0x03, 0xe5, 0xf8, 0x81, 0xe5, 0xf8, 0x81, 0xe5, 0xf8, 0x81, 0xe5, 0xf8,\n\t0x81, 0x1c, 0xfc, 0x40, 0x0e, 0x7e, 0xe0, 0x5b, 0xbc, 0xc0, 0xb7, 0x64, 0x1c, 0xad, 0xf0, 0x01, 0xcb, 0xf1, 0x00, 0x1b, 0xd0, 0xe9, 0x0d, 0xe8, 0xf4, 0x06, 0x74, 0x7a, 0x03, 0x3a, 0xbd, 0x01, 0x9d, 0x2e, 0x41, 0xa7, 0x37, 0xa0, 0xd3, 0x25, 0xe8, 0x74, 0x09, 0x3a, 0xbd, 0x01, 0x9d, 0xde, 0x80, 0x4e, 0x2f, 0x47, 0xa7, 0xcb, 0xd0, 0xe9, 0xe5, 0xe8, 0xf4, 0x72, 0x74, 0x7a, 0x39, 0x3a, 0xbd, 0x1c, 0x9d, 0x5e, 0x8e, 0x4e, 0x2f, 0x47, 0xa7, 0x97, 0xa3, 0xd3, 0xcb, 0xd1, 0xe9, 0xe5, 0xe8, 0xf4, 0x72, 0x74, 0xba, 0x0a, 0x9d, 0xae, 0x42, 0xa7, 0xab, 0xd0, 0xe9, 0x2a, 0x74, 0xba, 0x0a, 0x9d, 0xae, 0x42, 0xa7, 0xab, 0xd0, 0xe9, 0x2a, 0x74, 0xba, 0x0a, 0x9d, 0xae, 0x42, 0xa7, 0xab, 0xd0, 0xe9, 0x2a, 0x74, 0xba, 0x0a, 0x9d, 0xae, 0x42, 0xa7, 0xab, 0xd0, 0xe9, 0x2a, 0x74, 0xba,\n\t0x0a, 0x9d, 0xae, 0x42, 0xa7, 0xab, 0xd0, 0xe9, 0x2a, 0x74, 0x3a, 0x13, 0x9d, 0xce, 0x44, 0xa7, 0x33, 0xd1, 0xe9, 0x4c, 0x74, 0x3a, 0x13, 0x9d, 0xce, 0x44, 0xa7, 0x33, 0xd1, 0xe9, 0x4c, 0x74, 0x3a, 0x13, 0x9d, 0xce, 0x44, 0xa7, 0x33, 0xd1, 0xe9, 0x4c, 0x74, 0x3a, 0x13, 0x9d, 0xce, 0x44, 0xa7, 0x33, 0xd1, 0xe9, 0x4c, 0x74, 0x3a, 0x13, 0x9d, 0xce, 0x44, 0xa7, 0x33, 0xd1, 0xe9, 0x4c, 0x74, 0x3a, 0x13, 0x9d, 0xce, 0x44, 0xa7, 0x33, 0xd1, 0xe9, 0x4c, 0x74, 0x3a, 0x13, 0x9d, 0xce, 0x44, 0xa7, 0x77, 0xa2, 0xd3, 0x3b, 0xd1, 0xe9, 0x9d, 0xe8, 0xf4, 0x4e, 0x74, 0x7a, 0x27, 0x3a, 0xbd, 0x13, 0x9d, 0xde, 0x89, 0x4e, 0xef, 0x44, 0xa7, 0x77, 0xa2, 0xd3, 0xb9, 0xe8, 0x74, 0x2e, 0x3a, 0x9d, 0x8b, 0x4e, 0xe7, 0xa2, 0xd3, 0xb9, 0xe8, 0x74, 0x2e, 0x3a, 0x9d, 0x8b, 0x4e, 0xe7, 0xa2,\n\t0xd3, 0xb9, 0xe8, 0x74, 0x2e, 0x3a, 0x9d, 0x8b, 0x4e, 0xe7, 0xa2, 0xd3, 0xb9, 0xe8, 0x74, 0x2e, 0x3a, 0x9d, 0x8b, 0x4e, 0xe7, 0xa2, 0xd3, 0xb9, 0xe8, 0x74, 0x2e, 0x3a, 0x9d, 0x8b, 0x4e, 0xe7, 0xa2, 0xd3, 0xb9, 0xe8, 0x74, 0x2e, 0x3a, 0x9d, 0x8b, 0x4e, 0xe7, 0xa2, 0xd3, 0xdb, 0xc9, 0xd0, 0x52, 0xd0, 0xe9, 0xed, 0xe8, 0x74, 0x63, 0x74, 0x3a, 0x06, 0x9d, 0xde, 0x8e, 0x4e, 0x6f, 0x47, 0xa7, 0x0d, 0x74, 0x3a, 0x06, 0x9d, 0xde, 0x4e, 0xf6, 0x96, 0x82, 0x4e, 0xdf, 0x44, 0xf6, 0xd6, 0x0a, 0x9d, 0xde, 0x8e, 0x4e, 0x1f, 0x42, 0xa7, 0x4f, 0x39, 0x1e, 0x15, 0x8d, 0xd0, 0xe9, 0x74, 0x74, 0xba, 0x1c, 0x9d, 0x2e, 0x47, 0xa7, 0x57, 0xa3, 0xd3, 0xab, 0xd1, 0xe9, 0xd5, 0xe8, 0xf4, 0x6a, 0x74, 0x7a, 0x35, 0x3a, 0xbd, 0x1a, 0x9d, 0x5e, 0x8d, 0x4e, 0xaf, 0x46, 0xa7, 0x57, 0xa3, 0xd3,\n\t0xab, 0xd1, 0xe9, 0xd5, 0xe8, 0xf4, 0x6a, 0x74, 0x7a, 0x35, 0x3a, 0xbd, 0x1a, 0x9d, 0x5e, 0x8d, 0x4e, 0xaf, 0x46, 0xa7, 0x57, 0xa3, 0xd3, 0xab, 0xd1, 0xe9, 0xd5, 0xe8, 0x74, 0x26, 0x3a, 0x9d, 0x89, 0x4e, 0x67, 0xa2, 0xd3, 0x99, 0xe8, 0x74, 0x26, 0x3a, 0x9d, 0x89, 0x4e, 0x67, 0xa2, 0xd3, 0x99, 0xe8, 0x74, 0x26, 0x3a, 0x9d, 0x89, 0x4e, 0x67, 0xa2, 0xd3, 0x99, 0xe8, 0x74, 0x26, 0x3a, 0x9d, 0x89, 0x4e, 0x67, 0xa2, 0xd3, 0x99, 0xe8, 0x74, 0x26, 0x3a, 0x9d, 0x89, 0x4e, 0x67, 0xa2, 0xd3, 0x99, 0xe8, 0x74, 0x26, 0x3a, 0x9d, 0x89, 0x4e, 0x67, 0xa2, 0xd3, 0x99, 0xe8, 0xf4, 0x06, 0x74, 0x7a, 0x3b, 0x73, 0x71, 0xb9, 0x68, 0x2c, 0x8e, 0xa2, 0x70, 0x52, 0x2e, 0x43, 0x9b, 0x97, 0xa3, 0xcd, 0x6b, 0xb5, 0x70, 0xe1, 0x40, 0x9b, 0xe7, 0xa3, 0xc9, 0x1f, 0xa3, 0xc1, 0x73, 0xd1, 0xdc,\n\t0x4c, 0xa3, 0xb5, 0x68, 0x88, 0xae, 0x86, 0xa3, 0xa9, 0x15, 0x68, 0xea, 0xf7, 0x68, 0xea, 0xe7, 0xe8, 0x68, 0x89, 0x2a, 0xa1, 0x05, 0xb3, 0xce, 0x97, 0xcc, 0x38, 0x07, 0x98, 0x71, 0x2a, 0xc8, 0x2c, 0xbf, 0x67, 0xd6, 0x39, 0xc8, 0xbc, 0xba, 0x97, 0x79, 0x75, 0x2f, 0xb3, 0x4c, 0x53, 0x66, 0x16, 0xf3, 0x08, 0xda, 0x41, 0x35, 0xb3, 0xcc, 0x10, 0x71, 0xcc, 0x2c, 0xf3, 0x99, 0x59, 0xfc, 0xe6, 0xec, 0xce, 0xac, 0xf2, 0x23, 0x33, 0x47, 0x2f, 0x66, 0x87, 0x0c, 0x66, 0x87, 0x83, 0xcc, 0x0a, 0xe1, 0xcc, 0x0a, 0xcd, 0x98, 0x15, 0xba, 0x33, 0x2b, 0x8c, 0x66, 0x46, 0x38, 0x4e, 0x86, 0xf9, 0xbd, 0xda, 0xd3, 0x28, 0xe6, 0xbb, 0xe5, 0xcc, 0x73, 0x27, 0xd8, 0xe3, 0x78, 0xd4, 0xf9, 0x55, 0xf6, 0x7a, 0xb9, 0xb8, 0x53, 0x1e, 0x63, 0x8f, 0x6f, 0x33, 0xcf, 0x8d, 0x63, 0x9e, 0xfb, 0x92,\n\t0x79, 0xee, 0x73, 0xe6, 0xb9, 0xbb, 0x98, 0xf1, 0x1d, 0xf5, 0x66, 0xfc, 0x65, 0xcc, 0x7b, 0x0b, 0xa8, 0xd9, 0x0f, 0xd4, 0xec, 0x07, 0x6b, 0xc6, 0x9f, 0xcd, 0xdc, 0x37, 0x8b, 0x1a, 0xbe, 0x44, 0x0d, 0xf7, 0x50, 0xb3, 0x57, 0xa9, 0xd9, 0xc5, 0xd4, 0x6c, 0x80, 0xa9, 0x3b, 0x66, 0x76, 0xcd, 0xac, 0xbf, 0x9e, 0x5a, 0xfe, 0x82, 0x6a, 0xbf, 0x8e, 0x6a, 0xbf, 0xce, 0xec, 0x3f, 0x09, 0xc5, 0xee, 0x8a, 0x02, 0x8c, 0x45, 0xb1, 0x33, 0x50, 0x81, 0x1b, 0xf5, 0x0f, 0x50, 0xe1, 0x0f, 0x45, 0x08, 0xf3, 0xdf, 0x0c, 0xe6, 0xbf, 0x19, 0xcc, 0x7f, 0x33, 0x98, 0xff, 0x66, 0xa0, 0x04, 0x37, 0x32, 0x07, 0x4e, 0x47, 0x09, 0x6e, 0x41, 0x09, 0x2e, 0x45, 0x09, 0xc6, 0xa3, 0xce, 0x3d, 0xf5, 0x9f, 0xe5, 0x40, 0xe6, 0xc5, 0x3d, 0x28, 0xf0, 0xeb, 0xa8, 0xc2, 0x4d, 0xcc, 0x8f, 0xd3, 0x0d, 0x03,\n\t0x05, 0x6e, 0x20, 0xc7, 0x5b, 0xca, 0xb0, 0x92, 0x39, 0xb2, 0x19, 0x6c, 0xa4, 0xc0, 0x46, 0x1b, 0xd8, 0x18, 0x66, 0xa9, 0xc2, 0x5d, 0xc6, 0x50, 0x39, 0x01, 0xf5, 0x1d, 0x86, 0xf2, 0x76, 0x36, 0xae, 0x96, 0xbd, 0x60, 0xe8, 0x67, 0x14, 0x62, 0x2c, 0xf3, 0xe6, 0x16, 0xe6, 0xcd, 0xd7, 0x50, 0x88, 0x01, 0xcc, 0x9d, 0x0b, 0x8c, 0xd5, 0xf2, 0x56, 0xe3, 0x47, 0x39, 0x09, 0xa5, 0x58, 0x0a, 0x7b, 0x59, 0xa8, 0xee, 0x30, 0x31, 0x45, 0xe5, 0x64, 0x9b, 0xe4, 0x44, 0xe6, 0xd4, 0xcf, 0x98, 0x53, 0x97, 0x31, 0x9f, 0xbe, 0xc7, 0x7c, 0xfa, 0x38, 0xf3, 0xe9, 0x63, 0xcc, 0xa7, 0xb3, 0xd5, 0x2f, 0x36, 0x76, 0xc9, 0x79, 0xcc, 0xa3, 0xd7, 0x92, 0x7f, 0x95, 0x32, 0x87, 0xbe, 0xcc, 0xfc, 0xf9, 0x2e, 0xf3, 0xe7, 0x6d, 0xcc, 0x99, 0xcf, 0x30, 0x57, 0xb6, 0x60, 0xae, 0xfc, 0x84, 0xb9, 0x72,\n\t0xcc, 0x9f, 0x31, 0xce, 0x9c, 0xf9, 0x38, 0x39, 0xd4, 0x38, 0xe6, 0xcc, 0x6b, 0x6b, 0xd8, 0x64, 0x5e, 0xec, 0x4f, 0x4e, 0x34, 0x91, 0x9c, 0x68, 0x22, 0x39, 0xd1, 0x44, 0x72, 0xa2, 0x1c, 0x72, 0xa2, 0x1c, 0x72, 0xa2, 0x89, 0xe4, 0x44, 0x13, 0xc9, 0x89, 0x72, 0xc8, 0x89, 0x72, 0xc8, 0x89, 0x26, 0x92, 0x13, 0x4d, 0x24, 0x27, 0x9a, 0x48, 0x4e, 0x34, 0x91, 0x9c, 0x68, 0x22, 0x39, 0xd1, 0x44, 0x72, 0xa2, 0x89, 0xe4, 0x44, 0x39, 0xe4, 0x44, 0x39, 0xe4, 0x44, 0x13, 0xc9, 0x89, 0x26, 0x92, 0x13, 0xe5, 0x90, 0x13, 0xe5, 0x90, 0x13, 0x4d, 0x64, 0x6e, 0x2d, 0x65, 0x5e, 0x2d, 0xd5, 0xcd, 0x5f, 0x54, 0xb4, 0x90, 0xcb, 0x98, 0x1f, 0x97, 0x31, 0x3f, 0x96, 0x31, 0x3f, 0x96, 0x31, 0x3f, 0x96, 0x31, 0x3f, 0x2e, 0x63, 0x7e, 0x2c, 0x63, 0x7e, 0x2c, 0x63, 0x7e, 0x2c, 0x63, 0x7e, 0x5c,\n\t0xc6, 0xfc, 0xb8, 0x8c, 0xf9, 0x71, 0x19, 0xf3, 0xe3, 0x32, 0xe6, 0xc7, 0x32, 0xe6, 0xc7, 0x32, 0xe6, 0xc7, 0x32, 0xe6, 0xc7, 0x65, 0xcc, 0x8f, 0x65, 0xcc, 0x8f, 0x65, 0xcc, 0x8f, 0x65, 0xcc, 0x8b, 0xfd, 0x98, 0x17, 0x87, 0x32, 0x1f, 0x5e, 0xc0, 0x7c, 0x38, 0x8c, 0x39, 0xb0, 0x23, 0x73, 0x60, 0x7f, 0xe6, 0xc0, 0x71, 0xcc, 0x7d, 0xfd, 0x98, 0xfb, 0x86, 0x32, 0xe7, 0x5d, 0xc0, 0x9c, 0x37, 0x8c, 0x79, 0xae, 0x23, 0xf3, 0xdb, 0xd5, 0xcc, 0x6f, 0xb7, 0x30, 0xb7, 0x5d, 0xc6, 0xdc, 0x76, 0x2b, 0x73, 0xce, 0xbd, 0xcc, 0x39, 0xe9, 0xcc, 0x39, 0xef, 0x33, 0xe7, 0x24, 0x30, 0xe7, 0xf4, 0x60, 0xce, 0x79, 0x9f, 0x39, 0x67, 0x1e, 0x73, 0x4e, 0x02, 0x73, 0x4e, 0x57, 0xe6, 0x9c, 0x79, 0xcc, 0x39, 0xe9, 0xcc, 0x39, 0xb3, 0x98, 0x73, 0xfa, 0x33, 0xe7, 0xdc, 0xc3, 0x9c, 0x53, 0xee,\n\t0x98, 0x26, 0x9a, 0x33, 0xe7, 0xf4, 0x64, 0xce, 0x19, 0xcf, 0xfc, 0x31, 0x87, 0xf9, 0x63, 0x0e, 0x73, 0xc5, 0x75, 0x66, 0xcf, 0x8a, 0x48, 0x7c, 0xf6, 0xfd, 0x8c, 0xe1, 0xa5, 0xf8, 0xec, 0x95, 0x8c, 0xe3, 0x87, 0x18, 0xc7, 0xef, 0x69, 0xe1, 0xa7, 0x7f, 0x53, 0xbf, 0x2a, 0xe8, 0x28, 0xbb, 0xd1, 0x53, 0xe3, 0xe9, 0xa9, 0x95, 0xf4, 0xd4, 0x97, 0xf4, 0xd4, 0x3d, 0xf4, 0x54, 0x18, 0x3d, 0xd5, 0x84, 0x9e, 0x6a, 0x4e, 0x4f, 0x35, 0xad, 0xe9, 0x1d, 0x7c, 0xf5, 0x5d, 0x78, 0xe9, 0x5e, 0x8c, 0x77, 0xf3, 0x7c, 0xca, 0xd7, 0x28, 0x7d, 0xa3, 0x88, 0xb6, 0x9c, 0xda, 0xcf, 0x38, 0x8b, 0x50, 0x46, 0x5c, 0x31, 0xe3, 0xfc, 0x94, 0x79, 0x9e, 0x1f, 0x23, 0xa9, 0x9c, 0x91, 0x64, 0x1e, 0x45, 0x3a, 0xce, 0xc8, 0xd9, 0xcc, 0xc8, 0x39, 0xc5, 0xc8, 0x31, 0xcf, 0x13, 0xd8, 0xcc, 0x68, 0x48,\n\t0x24, 0xc2, 0x0f, 0x12, 0xcd, 0x29, 0x44, 0x73, 0x05, 0xaa, 0xef, 0xb4, 0x54, 0x3f, 0x9e, 0x88, 0x0e, 0x23, 0xa2, 0x23, 0x89, 0xe6, 0xee, 0xa8, 0x7e, 0x63, 0x22, 0xb8, 0x48, 0x68, 0x41, 0x1e, 0xf5, 0x7b, 0xb7, 0xd2, 0xe0, 0xe1, 0xf6, 0x4b, 0xcc, 0xc5, 0xc8, 0x3b, 0x63, 0x79, 0xcf, 0x7c, 0xb4, 0x7f, 0x61, 0xe4, 0xe9, 0xdf, 0x9f, 0xe5, 0x5d, 0x73, 0xe9, 0x60, 0xcc, 0x61, 0xab, 0xf7, 0xaa, 0xff, 0x6b, 0x30, 0x8e, 0x25, 0x3c, 0x31, 0xd4, 0x5c, 0x1c, 0x1d, 0x1c, 0xbd, 0x1c, 0x9f, 0x39, 0x26, 0x03, 0xaf, 0xb3, 0x95, 0x33, 0xdd, 0xf9, 0x40, 0xf5, 0x92, 0x76, 0xfc, 0x82, 0x8e, 0x6a, 0xbb, 0xc0, 0x25, 0x9c, 0x45, 0xad, 0x39, 0x17, 0x36, 0x18, 0x17, 0xf6, 0xd9, 0x59, 0xde, 0x37, 0x1f, 0x3f, 0x6d, 0x98, 0xdc, 0x23, 0xaa, 0x47, 0x54, 0x5a, 0x46, 0xc3, 0xee, 0x8d, 0x9a, 0x57,\n\t0xaf, 0x55, 0x3f, 0x76, 0xfa, 0xa2, 0x51, 0xff, 0xea, 0xb5, 0xd8, 0xa6, 0x8d, 0x32, 0xeb, 0x2c, 0x7b, 0xab, 0x97, 0xb4, 0xe3, 0x8d, 0xdc, 0xd5, 0x6b, 0x71, 0x13, 0x7f, 0x5f, 0x1a, 0x07, 0xc7, 0xad, 0x89, 0x3e, 0x14, 0xb7, 0xa6, 0x71, 0xc7, 0x9e, 0x2d, 0x78, 0xbc, 0xb9, 0xc9, 0x03, 0x4d, 0xa7, 0x37, 0x73, 0x45, 0x74, 0x88, 0x98, 0x13, 0x51, 0xde, 0xfc, 0xd2, 0xb8, 0x35, 0xcd, 0x17, 0x46, 0x9e, 0x8e, 0x1e, 0x1f, 0x7d, 0x4f, 0x34, 0x5b, 0x45, 0x1f, 0x6f, 0xd1, 0x3c, 0xa6, 0x65, 0xed, 0x72, 0x49, 0x6c, 0xd3, 0xd8, 0xa6, 0x2d, 0x3d, 0x3c, 0x66, 0xc4, 0x3e, 0x16, 0xbb, 0x2e, 0x2e, 0x34, 0x6e, 0x4d, 0x5c, 0x7a, 0x60, 0xd9, 0x75, 0x96, 0x35, 0x09, 0x97, 0x06, 0x2e, 0x71, 0x79, 0x03, 0x07, 0x0f, 0x1c, 0x9c, 0x20, 0xcc, 0xf5, 0xf8, 0xce, 0x60, 0x41, 0xdd, 0xf7, 0x6b, 0x16,\n\t0x73, 0xab, 0xc0, 0xa5, 0xfa, 0x13, 0x09, 0x8b, 0x13, 0xa7, 0x2b, 0x8e, 0xc7, 0x27, 0x4e, 0x64, 0x2d, 0xb7, 0x55, 0x87, 0x56, 0x2e, 0x6b, 0x79, 0xbe, 0xd5, 0x1a, 0xf3, 0xb9, 0x75, 0x58, 0x52, 0x58, 0xeb, 0x5c, 0x30, 0x38, 0xc9, 0x5c, 0x7b, 0xc3, 0x5c, 0x6f, 0xa3, 0xb7, 0xd1, 0x93, 0x06, 0x9b, 0x8f, 0x6d, 0x5a, 0xb4, 0xe9, 0x7e, 0xde, 0xa1, 0xd4, 0xc1, 0xa9, 0xb7, 0xb7, 0xbd, 0xa4, 0x5d, 0xe7, 0xf6, 0x7d, 0xdb, 0x4f, 0xed, 0xf0, 0x72, 0x87, 0x1d, 0xe7, 0x1d, 0xea, 0x11, 0xd5, 0x31, 0x2c, 0x2d, 0x03, 0x36, 0x5b, 0x75, 0x1a, 0xdf, 0xbd, 0xaa, 0xd3, 0xcb, 0x9d, 0xbe, 0xe8, 0x3c, 0xaf, 0xcb, 0xd4, 0xae, 0x33, 0xba, 0xae, 0xe9, 0xe6, 0xea, 0x1e, 0xd5, 0xbd, 0x0a, 0x86, 0xbb, 0x9a, 0xef, 0xa7, 0xdd, 0x98, 0xf6, 0x56, 0xcf, 0x0e, 0x81, 0x4b, 0xda, 0xa6, 0xb4, 0xe3, 0x75,\n\t0x5f, 0x09, 0x58, 0x5a, 0xa8, 0xc7, 0xab, 0x59, 0x66, 0xf5, 0x5c, 0x54, 0x67, 0x71, 0x9f, 0x6f, 0x63, 0xb9, 0xd5, 0x5a, 0xde, 0x60, 0xe9, 0x50, 0xfb, 0x5f, 0xf5, 0xff, 0xb9, 0x17, 0x84, 0x5d, 0xd0, 0xb1, 0x76, 0x19, 0xd5, 0x5b, 0xef, 0xb5, 0xaf, 0xb7, 0xfe, 0x57, 0x96, 0x3e, 0x73, 0xfe, 0xc1, 0xb2, 0xb1, 0xfe, 0xd2, 0xff, 0xad, 0xbe, 0x2d, 0xfa, 0xbf, 0xf5, 0x77, 0x96, 0x01, 0xc7, 0xfa, 0xaf, 0x1e, 0xd0, 0x79, 0x40, 0xaf, 0x01, 0xc7, 0xea, 0x2d, 0x43, 0x06, 0xbc, 0x13, 0xf8, 0xbf, 0xea, 0xcf, 0xe9, 0x7f, 0x69, 0x59, 0x31, 0x70, 0xdd, 0xa0, 0xe4, 0xbf, 0xb7, 0x08, 0x9b, 0x68, 0xaa, 0xcf, 0xd5, 0xd7, 0x09, 0xa1, 0x67, 0xe9, 0xd9, 0xa2, 0x8b, 0xbe, 0x45, 0xdf, 0x29, 0x7a, 0xea, 0xbb, 0xf4, 0x7d, 0x62, 0xa0, 0x5e, 0x64, 0x38, 0xc5, 0x70, 0xa3, 0x01, 0x73, 0xc1, 0x64,\n\t0x23, 0xd5, 0x48, 0x15, 0x73, 0x8c, 0x76, 0x46, 0x3b, 0xf1, 0x02, 0x23, 0xb9, 0x93, 0x78, 0xd1, 0xe8, 0xc2, 0xfc, 0x30, 0xd7, 0xe8, 0x66, 0xf4, 0x14, 0xaf, 0x1a, 0x17, 0x18, 0x83, 0xc5, 0x3c, 0xe3, 0x62, 0x63, 0xb4, 0x58, 0x6c, 0x8c, 0x31, 0xe6, 0x8a, 0x7f, 0x1b, 0xaf, 0x1b, 0xfb, 0xc4, 0x51, 0xa3, 0xc8, 0x38, 0xae, 0xf5, 0x73, 0x44, 0x3b, 0x1e, 0xd3, 0x2e, 0x73, 0x4c, 0x77, 0x7c, 0xa6, 0x65, 0x8a, 0x35, 0x64, 0x0d, 0xf9, 0x28, 0x9c, 0x9b, 0x8c, 0xc1, 0x65, 0x9d, 0x47, 0xfc, 0x3d, 0x0a, 0xb7, 0x14, 0x85, 0x73, 0x91, 0x31, 0x94, 0xa0, 0x72, 0x5e, 0x32, 0x86, 0x02, 0x94, 0x6e, 0x23, 0x4a, 0xf7, 0x0e, 0x19, 0xc3, 0x6e, 0x32, 0x86, 0x62, 0xd4, 0x6e, 0x3d, 0x19, 0x43, 0x15, 0x8a, 0x67, 0x5e, 0x31, 0xa3, 0x82, 0x8c, 0xc1, 0x4b, 0xc6, 0x90, 0x43, 0xc6, 0x90, 0x83, 0xfa,\n\t0x7d, 0x41, 0xc6, 0x90, 0x43, 0xc6, 0x90, 0x83, 0x0a, 0x6e, 0x46, 0x05, 0x8b, 0x51, 0xc1, 0xef, 0xc9, 0x18, 0x5c, 0x64, 0x0c, 0x15, 0x64, 0x0c, 0x15, 0x64, 0x0c, 0x7e, 0x32, 0x06, 0x3f, 0x19, 0x43, 0x3e, 0xea, 0xf7, 0x3d, 0x19, 0x43, 0x0e, 0xea, 0xf7, 0x0e, 0x19, 0x83, 0x97, 0x8c, 0xc1, 0x4b, 0xc6, 0x90, 0x43, 0xc6, 0x90, 0x43, 0xc6, 0x60, 0x66, 0x0a, 0x87, 0xc8, 0x14, 0x0e, 0xa1, 0x88, 0x1d, 0xc9, 0x14, 0x72, 0xc8, 0x14, 0xf2, 0xc9, 0x14, 0xf2, 0xc9, 0x14, 0xf2, 0xc9, 0x14, 0xf2, 0xc9, 0x14, 0xf2, 0x51, 0xb3, 0x23, 0x64, 0x0a, 0xf9, 0x28, 0xda, 0x11, 0x14, 0xed, 0x08, 0x99, 0x42, 0x3e, 0x99, 0x42, 0x3e, 0x99, 0x42, 0x0e, 0x99, 0x42, 0x31, 0x99, 0x42, 0x0e, 0x99, 0x42, 0x0e, 0x99, 0x42, 0x0e, 0x99, 0x42, 0x0e, 0x99, 0x42, 0x0e, 0x99, 0x42, 0x0e, 0x99, 0x42, 0x0e,\n\t0x99, 0x42, 0x0e, 0x99, 0x42, 0x0e, 0x99, 0x42, 0x0e, 0xce, 0xde, 0x85, 0xb3, 0x77, 0xa1, 0x60, 0x2e, 0x14, 0xcc, 0x85, 0xb3, 0x77, 0xe1, 0xec, 0x5d, 0x28, 0x99, 0x0b, 0x25, 0x73, 0xe1, 0xec, 0x5d, 0x38, 0x7b, 0x17, 0xce, 0xde, 0x85, 0xaa, 0xb9, 0x50, 0x35, 0x17, 0xaa, 0xe6, 0xc2, 0xd9, 0xbb, 0x70, 0xf6, 0x2e, 0xd4, 0xcd, 0x85, 0xba, 0xb9, 0x70, 0xf6, 0x2e, 0x9c, 0xbd, 0x0b, 0x95, 0x73, 0xa1, 0x72, 0x2e, 0x9c, 0xbd, 0x0b, 0x67, 0xef, 0xc2, 0xd9, 0xbb, 0x50, 0x3c, 0x17, 0xce, 0xbe, 0x04, 0x67, 0x5f, 0x82, 0xf2, 0x95, 0xa0, 0x7c, 0x25, 0x38, 0xfb, 0x12, 0xd4, 0xaf, 0x04, 0xf5, 0x2b, 0xc1, 0xd9, 0x97, 0xe0, 0xec, 0x4b, 0x70, 0xf6, 0x05, 0x38, 0xfb, 0x02, 0x9c, 0x7d, 0x01, 0xce, 0xbe, 0x00, 0x67, 0x5f, 0x80, 0xb3, 0x2f, 0xc0, 0xd9, 0x17, 0xe0, 0xec, 0x0b, 0x70, 0xf6,\n\t0x05, 0x38, 0xfb, 0x02, 0x9c, 0x7d, 0x01, 0xce, 0xbe, 0x00, 0x67, 0x5f, 0x80, 0xb3, 0x2f, 0xc0, 0xd9, 0x17, 0xe0, 0xec, 0x0b, 0x70, 0xf6, 0x05, 0x38, 0xfb, 0x02, 0x9c, 0x7d, 0x01, 0xce, 0xbe, 0x00, 0x67, 0x5f, 0x80, 0xb3, 0x2f, 0xc0, 0xd9, 0x17, 0xe0, 0xec, 0x0b, 0x50, 0xd9, 0xdd, 0xa8, 0x6c, 0x37, 0x54, 0x76, 0xb7, 0xe3, 0x3e, 0x70, 0xbf, 0x70, 0xa2, 0xb2, 0xbb, 0x51, 0xd9, 0xdd, 0x8e, 0xc9, 0x60, 0x8a, 0x68, 0x8a, 0xca, 0xee, 0x46, 0x65, 0xbb, 0xa1, 0xb2, 0x0f, 0xa2, 0xb2, 0x1d, 0x51, 0xd9, 0xdd, 0xa8, 0xec, 0x6e, 0x54, 0xb6, 0xa9, 0xe5, 0xec, 0x13, 0x70, 0xf6, 0x5e, 0x9c, 0xbd, 0x17, 0x67, 0x9f, 0x83, 0xb3, 0xcf, 0xc1, 0xd9, 0xe7, 0xe0, 0xec, 0x73, 0x70, 0xf6, 0x39, 0x38, 0xfb, 0x1c, 0x9c, 0x7d, 0x0e, 0xce, 0x3e, 0x07, 0x67, 0x9f, 0x83, 0xb3, 0xcf, 0xc1, 0xd9,\n\t0xe7, 0xa0, 0xcc, 0x39, 0x28, 0x73, 0x0e, 0xce, 0x3e, 0x07, 0x67, 0x9f, 0x83, 0xb3, 0xcf, 0xc1, 0xd9, 0xe7, 0xe0, 0xec, 0x73, 0x50, 0xeb, 0x1c, 0x9c, 0xbd, 0x0b, 0x67, 0xef, 0xc2, 0xd9, 0xbb, 0x70, 0xf6, 0x2e, 0x9c, 0xbd, 0x0b, 0x67, 0xef, 0xc2, 0xd9, 0xbb, 0x70, 0xf6, 0x2e, 0x9c, 0xbd, 0x0b, 0x67, 0xef, 0xc2, 0xd9, 0xbb, 0x70, 0xf6, 0x2e, 0x9c, 0xbd, 0x0b, 0x67, 0xef, 0xc2, 0xd9, 0xbb, 0x70, 0xf6, 0x2e, 0x9c, 0xbd, 0x0b, 0x67, 0xef, 0xc2, 0xd9, 0xbb, 0x70, 0xf6, 0x2e, 0x9c, 0xbd, 0x0b, 0x67, 0xef, 0xc2, 0xd9, 0xbb, 0x70, 0xf6, 0x2e, 0x9c, 0x7d, 0x3e, 0xce, 0xde, 0xff, 0x7f, 0x48, 0xb3, 0x07, 0x89, 0xce, 0xe4, 0x0f, 0xd7, 0x83, 0xf1, 0xe0, 0x06, 0x70, 0x3b, 0xb8, 0x13, 0xdc, 0x05, 0x26, 0x81, 0x87, 0xc1, 0x6c, 0x79, 0x44, 0xcc, 0x91, 0x65, 0x5a, 0x0f, 0x99, 0xa3,\n\t0xa5, 0x89, 0x20, 0x2d, 0x5d, 0x9e, 0xd2, 0xfa, 0xe0, 0x3f, 0xfa, 0xf2, 0xdc, 0x8f, 0xe7, 0x8b, 0x44, 0x37, 0xfc, 0x48, 0x3b, 0xfc, 0xc8, 0x79, 0xf8, 0x91, 0xab, 0xf1, 0x23, 0x57, 0xab, 0xab, 0x79, 0x5c, 0x87, 0x37, 0x19, 0x07, 0x6e, 0x16, 0xd1, 0x9a, 0xf9, 0xfb, 0x85, 0xdf, 0xaf, 0xea, 0x61, 0x5e, 0xe3, 0xb4, 0xb1, 0xed, 0x7e, 0xf0, 0x10, 0x78, 0x56, 0x56, 0xd9, 0xde, 0xe4, 0x79, 0x9e, 0x68, 0x1c, 0x3c, 0x59, 0x34, 0x0e, 0x09, 0x07, 0xdd, 0x45, 0x9b, 0x90, 0x1e, 0x60, 0x9d, 0xac, 0x0a, 0x4d, 0x12, 0x8d, 0xf5, 0x6f, 0xc1, 0x2a, 0xb0, 0x9a, 0x9a, 0x37, 0x06, 0x4d, 0x40, 0x53, 0xd0, 0x0c, 0xb0, 0xbd, 0x11, 0x01, 0xba, 0x81, 0xee, 0xa0, 0x07, 0x48, 0x03, 0x3d, 0x41, 0x2f, 0xd0, 0x1b, 0xa4, 0x83, 0x3e, 0xa0, 0x2f, 0xe8, 0x07, 0xfa, 0x83, 0x01, 0x60, 0x20, 0x99, 0x63,\n\t0xf5, 0x15, 0x45, 0xde, 0x24, 0x0f, 0xaa, 0xdb, 0xd2, 0x60, 0x5a, 0xba, 0x8f, 0x96, 0xda, 0x68, 0xe9, 0x3e, 0x5a, 0x6a, 0xa3, 0x95, 0x0d, 0x69, 0x65, 0x04, 0xad, 0x8c, 0xa0, 0x95, 0x11, 0x56, 0x2b, 0x1b, 0xd3, 0xca, 0xc6, 0xb4, 0xb2, 0xd9, 0x19, 0xad, 0xa4, 0x65, 0x21, 0xdd, 0xe5, 0xc9, 0x90, 0x1e, 0x80, 0x96, 0xd4, 0xee, 0x29, 0xaa, 0x7a, 0x4f, 0xc2, 0x60, 0x4f, 0x7b, 0xd5, 0x2f, 0x46, 0xd3, 0x65, 0x15, 0x7b, 0xa9, 0x32, 0xef, 0x94, 0x64, 0x5d, 0x15, 0x65, 0xbd, 0x75, 0x55, 0x94, 0x42, 0xed, 0x3a, 0x78, 0x1e, 0x07, 0x6e, 0x96, 0x25, 0xe7, 0xd8, 0x43, 0x15, 0x7b, 0xa8, 0xaa, 0xb3, 0x07, 0xf3, 0x9e, 0x4d, 0x37, 0x51, 0xd7, 0x07, 0xa9, 0xeb, 0x73, 0xd4, 0x75, 0x06, 0x35, 0x37, 0xcf, 0x60, 0x30, 0xaf, 0x85, 0xa4, 0x5a, 0x57, 0xe7, 0x0a, 0x2c, 0x35, 0xfb, 0x72, 0x91,\n\t0x2f, 0x9a, 0x57, 0x58, 0xda, 0x4a, 0x79, 0x5b, 0xed, 0xe6, 0x35, 0xd8, 0xcc, 0x6b, 0x33, 0x85, 0xd7, 0xe5, 0xe5, 0xec, 0x9f, 0xa4, 0x76, 0xdb, 0xcf, 0x51, 0x3b, 0x55, 0x5a, 0x9d, 0xda, 0x99, 0x57, 0xa1, 0xd9, 0xca, 0xa7, 0x37, 0xf2, 0xe9, 0xad, 0xea, 0xd7, 0x34, 0xa5, 0x01, 0xd7, 0x7d, 0xda, 0xc7, 0xbb, 0x3e, 0xde, 0x2d, 0xe1, 0xdd, 0xfd, 0xe6, 0x75, 0x9f, 0x28, 0xfb, 0x30, 0xe5, 0x1e, 0xa7, 0xdc, 0xe3, 0x35, 0xd7, 0x7f, 0xa2, 0x9c, 0x7f, 0x9f, 0xf1, 0xc9, 0x5d, 0xd6, 0x15, 0xa3, 0xf6, 0xf2, 0xc9, 0x3d, 0xd6, 0x27, 0x8b, 0xff, 0xd2, 0x27, 0xcf, 0xb8, 0xd6, 0x14, 0x9f, 0xdc, 0x73, 0xf6, 0x4f, 0xfe, 0xe3, 0x2b, 0x55, 0xfd, 0xd1, 0x95, 0x9e, 0xea, 0xd6, 0xa6, 0xc0, 0xba, 0x4a, 0xcf, 0x7e, 0xca, 0x2b, 0xb2, 0x6a, 0x73, 0xe8, 0xac, 0xb5, 0xf9, 0x7b, 0xd7, 0x00, 0xfd,\n\t0x6b, 0x77, 0xbd, 0x98, 0x23, 0xf3, 0xa9, 0xcb, 0x4e, 0x46, 0x80, 0x93, 0xb8, 0x3c, 0xc9, 0x08, 0x68, 0x4a, 0x6c, 0x9e, 0x64, 0x04, 0x34, 0x65, 0xac, 0xf7, 0x61, 0x14, 0x74, 0x23, 0xb2, 0xba, 0x12, 0x59, 0x37, 0x12, 0x59, 0x37, 0x52, 0xbf, 0x1c, 0x46, 0x41, 0x38, 0xa3, 0x20, 0x9c, 0x51, 0x90, 0x60, 0x45, 0x41, 0x19, 0xb5, 0x2a, 0x53, 0x47, 0x0e, 0x02, 0xef, 0x7a, 0x51, 0x3d, 0xd6, 0xeb, 0xdf, 0xf9, 0xa2, 0x2d, 0x63, 0xbd, 0xad, 0x35, 0xd6, 0xff, 0xda, 0x9d, 0x2f, 0xfe, 0xe1, 0xdd, 0x2e, 0x88, 0x40, 0xf3, 0x57, 0x56, 0x73, 0x6b, 0x5b, 0xe9, 0xa1, 0x95, 0x0d, 0x68, 0x65, 0x29, 0xad, 0x0c, 0xa6, 0x95, 0xa5, 0xb4, 0x32, 0x98, 0x16, 0x46, 0xd1, 0xc2, 0x18, 0x5a, 0x18, 0x4b, 0x0b, 0x63, 0x69, 0x61, 0x3e, 0x2d, 0x6c, 0x44, 0x0b, 0x1b, 0xd1, 0xc2, 0x98, 0x33, 0x5a, 0x58,\n\t0x1d, 0xe7, 0x1b, 0xe9, 0x95, 0x8d, 0x56, 0x9c, 0x57, 0xef, 0xa5, 0xa9, 0x75, 0x9d, 0xb4, 0x4a, 0xc6, 0xdd, 0xaf, 0xd6, 0x35, 0xd2, 0xb6, 0xd2, 0xbf, 0x4b, 0xad, 0x6b, 0x38, 0x7d, 0x6f, 0x5d, 0x23, 0x2d, 0x87, 0x71, 0x57, 0x15, 0x1c, 0x2a, 0x4f, 0x07, 0x8f, 0x90, 0x47, 0xcd, 0xb3, 0x8a, 0x6a, 0x4a, 0x23, 0x76, 0x8a, 0x88, 0x9d, 0x2a, 0x75, 0xed, 0xa4, 0xfc, 0x3f, 0x2a, 0x81, 0x08, 0xd9, 0xf2, 0x97, 0xeb, 0x65, 0xfe, 0xb6, 0x69, 0x37, 0x31, 0xb7, 0x8e, 0xbc, 0x72, 0xbb, 0xba, 0x23, 0xdb, 0x68, 0xa1, 0xd7, 0xfc, 0xc2, 0x85, 0x16, 0xea, 0x94, 0xe2, 0xa5, 0x14, 0xaf, 0x75, 0x0d, 0xa7, 0x53, 0x44, 0xd6, 0x58, 0x22, 0xab, 0xbf, 0xbe, 0x12, 0x27, 0xb8, 0x97, 0x79, 0xb3, 0xa5, 0xe8, 0x43, 0x94, 0x35, 0x43, 0x5d, 0x3a, 0xa3, 0x2e, 0xbd, 0x51, 0x97, 0xb6, 0xa8, 0x4b, 0x0f,\n\t0xa2, 0x6e, 0x0c, 0x51, 0x37, 0xc2, 0xe8, 0x20, 0x92, 0x89, 0xbc, 0x1f, 0x89, 0xbc, 0x48, 0xe3, 0x46, 0xa1, 0x13, 0x7d, 0x23, 0x1d, 0x6e, 0x11, 0x5f, 0xef, 0x8a, 0x53, 0xe7, 0x13, 0x8f, 0x89, 0xc4, 0x63, 0x22, 0xf1, 0x98, 0x48, 0x3c, 0x26, 0x12, 0x8f, 0x89, 0xd6, 0xb5, 0xb1, 0x13, 0x89, 0xc7, 0x44, 0x75, 0xaf, 0xb9, 0xba, 0xd7, 0xc6, 0x4e, 0x24, 0x96, 0x12, 0x89, 0xa5, 0x44, 0xe2, 0x28, 0x91, 0x38, 0x4a, 0x24, 0x8e, 0x12, 0x89, 0xa3, 0x44, 0x62, 0x27, 0x51, 0x7f, 0x43, 0xd8, 0x89, 0x9f, 0x44, 0xe2, 0x27, 0x91, 0xf8, 0x49, 0x24, 0x7e, 0x12, 0x89, 0x9f, 0x44, 0xe2, 0x27, 0x91, 0xf8, 0x49, 0x24, 0x7e, 0x12, 0x89, 0x9f, 0x44, 0xea, 0x3f, 0xd7, 0xaa, 0xfb, 0x10, 0xea, 0x9e, 0x41, 0xdd, 0xa7, 0x04, 0x5c, 0x17, 0xdb, 0x49, 0x7c, 0x25, 0x12, 0x5f, 0x89, 0xc4, 0x57, 0x22,\n\t0xf1, 0x95, 0x48, 0x7c, 0x25, 0x12, 0x5f, 0x89, 0xc4, 0x57, 0x22, 0xf1, 0x95, 0x48, 0x7c, 0x25, 0x12, 0x5f, 0x89, 0xc4, 0x57, 0x22, 0xf1, 0x95, 0x48, 0x7c, 0x25, 0x12, 0x5f, 0x89, 0xc6, 0x93, 0x70, 0x31, 0x5b, 0xb4, 0x36, 0x8e, 0x89, 0x86, 0xb4, 0xf7, 0x1a, 0xe1, 0xa8, 0x73, 0x2e, 0x55, 0x4b, 0xf5, 0xab, 0x40, 0x07, 0x7b, 0x8d, 0xb1, 0xce, 0x73, 0x8b, 0xa8, 0x3d, 0xb7, 0xea, 0xbf, 0xd1, 0x27, 0xcd, 0xe8, 0x13, 0x4d, 0x9d, 0x89, 0x93, 0x40, 0x1d, 0x12, 0x19, 0xf5, 0xad, 0x44, 0xec, 0x59, 0xfa, 0x44, 0xab, 0xd3, 0x27, 0x76, 0x35, 0xfb, 0x5c, 0xcc, 0x4c, 0x53, 0x1d, 0x3b, 0x07, 0xac, 0x3d, 0xfc, 0x46, 0xac, 0x6c, 0x87, 0xff, 0x31, 0xf2, 0xa0, 0x52, 0xaa, 0x03, 0xb5, 0xd7, 0x07, 0xe4, 0x15, 0xeb, 0xba, 0x80, 0xb5, 0x6d, 0x63, 0xdb, 0x6c, 0x75, 0xdc, 0xb1, 0x98, 0x2d,\n\t0xb3, 0xd9, 0xf2, 0x47, 0xb6, 0xfc, 0xb8, 0xde, 0x15, 0xbe, 0x36, 0x11, 0x8d, 0xab, 0x89, 0xc6, 0xd5, 0xb4, 0xaa, 0xa7, 0xb0, 0x6b, 0x8c, 0x4c, 0x8d, 0x91, 0xa9, 0x0d, 0x16, 0x6d, 0x69, 0x6d, 0x02, 0xad, 0x4d, 0xa0, 0xb5, 0xf1, 0xe7, 0x3c, 0xff, 0x2c, 0x83, 0x78, 0x49, 0x21, 0x5e, 0x52, 0x88, 0x97, 0x14, 0xe2, 0x25, 0x85, 0x78, 0x49, 0x21, 0x5e, 0x52, 0x88, 0x97, 0x14, 0xe2, 0x25, 0x85, 0x78, 0x49, 0x11, 0xb3, 0x99, 0xa3, 0x99, 0x1b, 0x18, 0xd9, 0xdd, 0xb5, 0x74, 0xd1, 0x82, 0x91, 0xdd, 0x43, 0xeb, 0xcb, 0x73, 0x3f, 0x9e, 0x2f, 0xe2, 0xf9, 0x62, 0x71, 0x29, 0x7b, 0x1b, 0xc3, 0xde, 0xae, 0x61, 0x6f, 0x63, 0xd5, 0xef, 0x37, 0xaf, 0x13, 0xbd, 0x18, 0xdd, 0xbd, 0xe0, 0x79, 0x44, 0xbd, 0x78, 0x4b, 0x21, 0xde, 0x52, 0x88, 0xb7, 0x14, 0xe2, 0x2d, 0x85, 0x78, 0x4b, 0x21,\n\t0xde, 0x52, 0x88, 0xb7, 0x14, 0xe6, 0xad, 0xde, 0xcc, 0x5b, 0xbd, 0x43, 0x8e, 0x89, 0x68, 0x62, 0x2f, 0x85, 0xb8, 0x4b, 0x21, 0xee, 0x52, 0x88, 0xbb, 0x14, 0xe2, 0x2e, 0x85, 0xb8, 0x4b, 0x21, 0xee, 0x52, 0x88, 0xbb, 0x14, 0xe2, 0x2e, 0x85, 0xb8, 0x4b, 0xa9, 0x77, 0xc7, 0x9e, 0x14, 0x62, 0x2c, 0x85, 0x18, 0x4b, 0x21, 0xc6, 0x52, 0x88, 0xb1, 0x14, 0x62, 0x2c, 0x85, 0x18, 0x4b, 0x21, 0xc6, 0x52, 0x88, 0xb1, 0x14, 0x62, 0x2c, 0x85, 0x18, 0x4b, 0x21, 0xc6, 0x52, 0x88, 0xb1, 0x14, 0x62, 0x2c, 0x85, 0x18, 0x1b, 0x40, 0x8c, 0xb5, 0x25, 0xc6, 0xc2, 0xd5, 0x8c, 0x9e, 0x00, 0x23, 0x09, 0x30, 0x92, 0x00, 0x23, 0x09, 0x30, 0x92, 0x00, 0x23, 0x09, 0x30, 0x92, 0x00, 0x23, 0x09, 0x30, 0x92, 0x00, 0x23, 0x8d, 0x71, 0x1b, 0x23, 0x60, 0x25, 0x42, 0xeb, 0x81, 0x23, 0x4b, 0x63, 0x4e,\n\t0x4b, 0x17, 0x17, 0xc1, 0x4c, 0x38, 0xcc, 0x5c, 0x04, 0x33, 0xe1, 0x30, 0xd3, 0xcc, 0xfa, 0x8e, 0x2d, 0x12, 0x46, 0xa2, 0x61, 0xa4, 0x37, 0x8c, 0xf4, 0x86, 0x91, 0x58, 0xed, 0x16, 0xd1, 0xba, 0x1e, 0x2b, 0x09, 0xb0, 0x92, 0x00, 0x2b, 0x09, 0xb0, 0x92, 0x00, 0x2b, 0x09, 0xb0, 0x92, 0x00, 0x2b, 0x09, 0xb0, 0x92, 0x01, 0x2b, 0x19, 0xb0, 0x12, 0x01, 0x2b, 0x09, 0xb0, 0x92, 0x00, 0x2b, 0x09, 0xb0, 0x92, 0x00, 0x2b, 0x09, 0xb0, 0x92, 0x00, 0x2b, 0x09, 0xb0, 0x92, 0x00, 0x2b, 0x09, 0xb0, 0x92, 0x50, 0x8f, 0x95, 0x04, 0x58, 0x49, 0x80, 0x95, 0x04, 0x58, 0x49, 0x80, 0x95, 0x04, 0x58, 0x49, 0x80, 0x95, 0x04, 0x58, 0x49, 0x80, 0x95, 0x04, 0x58, 0x49, 0x80, 0x95, 0x04, 0x58, 0x49, 0x80, 0x95, 0x04, 0x58, 0x49, 0x10, 0x97, 0xc3, 0x84, 0x13, 0x26, 0x9c, 0x30, 0xe1, 0x54, 0xdf,\n\t0xa1, 0xdd, 0x48, 0xab, 0x6f, 0x02, 0x37, 0x83, 0x5b, 0xc1, 0x6d, 0xca, 0xdf, 0x3a, 0x61, 0xc7, 0x09, 0x3b, 0x4e, 0xd8, 0x71, 0xc2, 0x8e, 0x13, 0x76, 0x5a, 0xc2, 0x8e, 0xc9, 0x4c, 0xaa, 0x15, 0x33, 0x51, 0x30, 0x93, 0x0c, 0x33, 0x51, 0x30, 0x93, 0x6c, 0xe9, 0x5d, 0x3a, 0xf1, 0xd2, 0x9f, 0x78, 0x49, 0x87, 0x9d, 0xd6, 0xb0, 0x93, 0x0a, 0x3b, 0xa9, 0xb0, 0x33, 0x00, 0x76, 0x1a, 0xd4, 0x63, 0xc7, 0x09, 0x3b, 0x4e, 0xd8, 0x71, 0xc2, 0x8e, 0x13, 0x76, 0x9c, 0xb0, 0xe3, 0x84, 0x1d, 0x27, 0xec, 0x74, 0x80, 0x9d, 0x0e, 0x8c, 0xdd, 0xc6, 0xb0, 0xe3, 0x84, 0x1d, 0x27, 0xec, 0x38, 0x61, 0xc7, 0x09, 0x3b, 0x4e, 0xd8, 0x71, 0xc2, 0x8e, 0x13, 0x76, 0x9c, 0xb0, 0xe3, 0x84, 0x1d, 0xa7, 0x11, 0xc9, 0xd8, 0x8e, 0x06, 0x2d, 0xd4, 0x18, 0x6f, 0x6c, 0xc4, 0x82, 0x38, 0x10, 0x0f, 0x4c,\n\t0xe6, 0x12, 0x79, 0x6e, 0x05, 0xda, 0x80, 0x64, 0x60, 0x32, 0xd9, 0x81, 0x67, 0x93, 0xcd, 0x4e, 0x3c, 0x77, 0x51, 0xde, 0xd8, 0x09, 0xab, 0x4e, 0x58, 0x75, 0xc2, 0xaa, 0x13, 0x56, 0x9d, 0xb0, 0xea, 0x84, 0x55, 0x27, 0xac, 0x3a, 0x61, 0xd5, 0x09, 0xab, 0x4e, 0x58, 0x75, 0xc2, 0xaa, 0x13, 0x56, 0x9d, 0xb0, 0xea, 0x54, 0xac, 0x3a, 0x60, 0xd5, 0x01, 0xab, 0x0e, 0x58, 0x75, 0xc0, 0x6a, 0x14, 0xac, 0x46, 0xc1, 0x6a, 0x14, 0xac, 0x46, 0xc1, 0x6a, 0x14, 0xac, 0x3a, 0x60, 0xd5, 0x01, 0xab, 0x0e, 0x58, 0x75, 0xc0, 0xaa, 0x03, 0x56, 0x9b, 0xc3, 0x6a, 0x07, 0x58, 0xed, 0x06, 0xab, 0xad, 0x60, 0xb5, 0x03, 0xac, 0x36, 0x81, 0xd5, 0x0e, 0xb0, 0xda, 0x04, 0x56, 0xcd, 0xdf, 0x3b, 0xa6, 0xc2, 0x6a, 0x5b, 0x58, 0x6d, 0x0b, 0xab, 0x3d, 0x60, 0x35, 0x19, 0x56, 0x93, 0x61, 0xb5, 0x17,\n\t0xac, 0x46, 0xd7, 0x63, 0xd5, 0x01, 0xab, 0x0e, 0x58, 0x75, 0xc0, 0xaa, 0x03, 0x56, 0x1d, 0xb0, 0xea, 0x80, 0x55, 0x07, 0xac, 0xa6, 0xc1, 0x6a, 0x9a, 0xe9, 0x7f, 0x60, 0xd5, 0x01, 0xab, 0x0e, 0x58, 0x75, 0xc0, 0xaa, 0x03, 0x56, 0x1d, 0xb0, 0xea, 0x80, 0x55, 0x07, 0xac, 0x3a, 0x60, 0xd5, 0x01, 0xab, 0x0e, 0x58, 0x8d, 0x82, 0xd5, 0x28, 0x58, 0x8d, 0xaa, 0xfe, 0x4d, 0x33, 0xa8, 0xfe, 0xd5, 0x76, 0x94, 0xc5, 0xaa, 0xf9, 0x7d, 0x79, 0x14, 0xac, 0x46, 0xc1, 0x6a, 0x94, 0xc5, 0x6a, 0x94, 0xc5, 0x6a, 0x14, 0xac, 0x46, 0xc1, 0xaa, 0x03, 0x56, 0x1d, 0xb0, 0xea, 0x80, 0x55, 0x07, 0xac, 0x3a, 0x60, 0xd5, 0x01, 0xab, 0x0e, 0x58, 0x75, 0xc0, 0xaa, 0x03, 0x56, 0x1d, 0xb0, 0xea, 0x80, 0x55, 0x07, 0xac, 0x3a, 0x60, 0xd5, 0x61, 0xfa, 0x7f, 0xb8, 0x9d, 0x03, 0x2b, 0x3d, 0x44, 0x27,\n\t0xd8, 0x89, 0x87, 0x9d, 0x58, 0xd8, 0x69, 0x08, 0x3b, 0xb1, 0xb0, 0xd3, 0x10, 0x76, 0x1a, 0xc1, 0x4e, 0x6b, 0xd8, 0x49, 0x86, 0x9d, 0x64, 0xd8, 0x49, 0x84, 0x9d, 0xa6, 0xb0, 0xd3, 0x14, 0x76, 0xda, 0xd4, 0x71, 0x7d, 0xdd, 0x45, 0x2b, 0x5a, 0xdf, 0xaa, 0xce, 0x4c, 0x69, 0xee, 0xa1, 0x09, 0x7b, 0x70, 0xb2, 0x87, 0x78, 0xf6, 0xd0, 0x96, 0x3d, 0x34, 0x61, 0x0f, 0x2d, 0xd9, 0x43, 0x13, 0xf6, 0xd0, 0x92, 0x3d, 0xa4, 0xb2, 0x87, 0x2e, 0xec, 0xa1, 0x07, 0x7b, 0xe8, 0x62, 0x8d, 0xf9, 0x58, 0xf6, 0x10, 0xcb, 0x1e, 0xce, 0xff, 0xf3, 0x3d, 0x68, 0x9d, 0x98, 0x47, 0x7b, 0x88, 0x0b, 0x28, 0x3d, 0x81, 0xd2, 0x5b, 0x51, 0x7a, 0x33, 0x4a, 0x6f, 0x45, 0xe9, 0xcd, 0xac, 0xde, 0x8d, 0xb4, 0x7e, 0xcd, 0xda, 0x8c, 0xd2, 0x93, 0x29, 0x3d, 0x92, 0xd2, 0x23, 0x29, 0x2d, 0x99, 0xd2, 0x92,\n\t0xed, 0xe6, 0x7d, 0xaa, 0xba, 0x91, 0xad, 0x36, 0x17, 0xc3, 0x8c, 0x28, 0x61, 0x18, 0xad, 0xc5, 0x9b, 0x46, 0x92, 0x78, 0xda, 0xe8, 0x28, 0x0c, 0x87, 0x79, 0xd4, 0x3a, 0xfc, 0x9f, 0xc4, 0x4e, 0x4d, 0x2c, 0x50, 0xf2, 0x21, 0x4a, 0x8d, 0xa2, 0xd4, 0xa7, 0x29, 0xf5, 0x7e, 0x4a, 0x8d, 0x12, 0x57, 0x10, 0xcd, 0x71, 0x44, 0x73, 0x1c, 0xd1, 0x1c, 0x47, 0x34, 0xc7, 0x11, 0xcd, 0x06, 0xd1, 0x6c, 0x10, 0xcd, 0x06, 0xd1, 0x6c, 0x10, 0xcd, 0x06, 0xd1, 0x1c, 0x47, 0x34, 0xc7, 0x11, 0xcd, 0x71, 0x44, 0x73, 0x1c, 0xd1, 0x1c, 0x67, 0x46, 0x33, 0xb3, 0x67, 0x33, 0x6a, 0xd4, 0x84, 0x1a, 0xf5, 0xa4, 0x46, 0x91, 0x96, 0xae, 0x44, 0x5a, 0xba, 0x62, 0xd6, 0x6a, 0x30, 0xb5, 0xba, 0x84, 0x5a, 0x5d, 0x4a, 0xad, 0x46, 0x52, 0xab, 0x86, 0x01, 0xba, 0x72, 0x55, 0xbd, 0x68, 0x8e, 0x23, 0x9a,\n\t0xe3, 0x88, 0xe6, 0x38, 0xa2, 0x39, 0x8e, 0x68, 0x8e, 0x23, 0x9a, 0xe3, 0x88, 0xe6, 0xb8, 0x80, 0x68, 0x36, 0x98, 0x45, 0x9b, 0x11, 0xd1, 0x71, 0x44, 0x74, 0x1c, 0x11, 0x1d, 0x47, 0x44, 0xc7, 0x11, 0xd1, 0x71, 0x44, 0x74, 0x1c, 0x11, 0x1d, 0x47, 0x44, 0xc7, 0x11, 0xd1, 0x71, 0x44, 0x74, 0x1c, 0x11, 0x6d, 0x10, 0xd1, 0x06, 0x11, 0x6d, 0x10, 0xd1, 0x06, 0x11, 0x6d, 0x10, 0xd1, 0x06, 0x11, 0x6d, 0x58, 0x11, 0x6d, 0x10, 0xd1, 0x06, 0x11, 0x6d, 0x10, 0xd1, 0x86, 0x15, 0xd1, 0x86, 0x15, 0xd1, 0x86, 0x79, 0x05, 0x07, 0x22, 0x3a, 0x8e, 0x88, 0x8e, 0x23, 0xa2, 0xe3, 0x88, 0xe8, 0x38, 0x22, 0x3a, 0x8e, 0x88, 0x8e, 0x23, 0xa2, 0xe3, 0x88, 0xe8, 0x38, 0x22, 0x3a, 0x8e, 0x88, 0x8e, 0x23, 0xa2, 0xe3, 0x88, 0xe8, 0x38, 0x22, 0x3a, 0x8e, 0x88, 0x8e, 0x13, 0x63, 0xeb, 0xdd, 0xe5,\n\t0xa4, 0x25, 0xcc, 0xb6, 0x83, 0xd9, 0x76, 0x30, 0xdb, 0x0e, 0x66, 0xdb, 0xc1, 0x6c, 0x3b, 0xeb, 0xce, 0x27, 0x2d, 0x03, 0xef, 0x7c, 0x02, 0xb3, 0xa9, 0xc4, 0x69, 0x5f, 0xd8, 0x6d, 0x02, 0xbb, 0x17, 0x5a, 0x33, 0x70, 0x5f, 0xd8, 0x6d, 0x0d, 0xbb, 0x7d, 0x61, 0xb7, 0x35, 0xec, 0x36, 0x86, 0xdd, 0x14, 0xd8, 0x4d, 0x83, 0xdd, 0x34, 0xd8, 0xed, 0x09, 0xbb, 0x17, 0xc1, 0xee, 0xf9, 0xb0, 0x7b, 0x3e, 0xec, 0x0e, 0x67, 0xbe, 0x68, 0xff, 0x57, 0xef, 0xa2, 0x02, 0xc3, 0x43, 0x60, 0x78, 0x08, 0x0c, 0xb7, 0x83, 0xe1, 0x26, 0xea, 0xae, 0x2a, 0x7f, 0xe5, 0x8e, 0x2a, 0x91, 0xa2, 0x1d, 0x0c, 0xb7, 0x83, 0x61, 0xf3, 0x1c, 0x9b, 0x76, 0x30, 0xdc, 0x0e, 0x86, 0xdb, 0xc1, 0x70, 0x3b, 0x8b, 0xe1, 0x76, 0xea, 0x0e, 0x2b, 0x6d, 0x40, 0xb2, 0x75, 0xa7, 0x95, 0x0e, 0x3c, 0x57, 0x33, 0xdc,\n\t0x0e, 0x86, 0xdb, 0xfd, 0xd3, 0x3b, 0xae, 0xa8, 0x9c, 0xb9, 0xa2, 0xe6, 0x1a, 0xab, 0x28, 0xff, 0x1c, 0xd1, 0x11, 0xbe, 0x62, 0xe1, 0x4b, 0x87, 0xaf, 0x54, 0xb8, 0x32, 0xc7, 0xb3, 0x03, 0x6e, 0xec, 0x70, 0xd3, 0x2a, 0x60, 0x2c, 0x27, 0xc3, 0x8d, 0xb3, 0xde, 0x78, 0x56, 0x19, 0x57, 0x9d, 0xf1, 0x6c, 0xce, 0x47, 0x8d, 0x29, 0xc9, 0x49, 0x49, 0xf5, 0xb7, 0xb6, 0xb3, 0xb5, 0xbd, 0xce, 0xd6, 0x36, 0x35, 0xbe, 0x92, 0x44, 0x03, 0xdc, 0xa3, 0x4d, 0x5d, 0x33, 0xf5, 0xec, 0x8e, 0x6d, 0x00, 0x71, 0x11, 0x43, 0x5c, 0xc4, 0x10, 0x17, 0x31, 0xc4, 0x45, 0x0c, 0x31, 0x10, 0x43, 0x0c, 0xc4, 0x10, 0x03, 0x31, 0xc4, 0x40, 0x0c, 0x31, 0x10, 0x63, 0xcd, 0x86, 0x43, 0x88, 0x81, 0xc6, 0xd6, 0x08, 0x8b, 0xa2, 0x26, 0x03, 0x89, 0x81, 0xc6, 0xd4, 0x66, 0x20, 0x31, 0xd0, 0x98, 0x18, 0x30,\n\t0x8f, 0xbd, 0x34, 0xa5, 0x6d, 0xe1, 0xb4, 0xad, 0x27, 0x6d, 0xeb, 0x49, 0xdb, 0xa2, 0x68, 0x5b, 0x7c, 0xbd, 0x7e, 0x8f, 0xa1, 0xdf, 0x63, 0xe8, 0xf7, 0x18, 0xfa, 0x3d, 0x86, 0x7e, 0x8f, 0xa1, 0xdf, 0x63, 0xe8, 0xf7, 0x18, 0x5a, 0xd2, 0x8f, 0x96, 0xf4, 0xa3, 0xcf, 0x4d, 0xf5, 0x8d, 0xa1, 0xcf, 0x63, 0xe8, 0xf3, 0x18, 0xfa, 0x3c, 0x86, 0x3e, 0x8f, 0xa1, 0xcf, 0x63, 0xe8, 0xf3, 0x18, 0xfa, 0x3c, 0x86, 0x3e, 0x8f, 0xa1, 0xcf, 0x63, 0xea, 0x79, 0x93, 0x18, 0xfa, 0x2e, 0x86, 0xbe, 0x8b, 0xa1, 0xef, 0x62, 0xe8, 0xbb, 0x18, 0xfa, 0x2e, 0x86, 0xbe, 0x8b, 0xa1, 0xef, 0x62, 0xe8, 0xbb, 0x18, 0xfa, 0x2e, 0x86, 0xbe, 0x8b, 0xa1, 0xef, 0x62, 0xe8, 0xbb, 0x18, 0xfa, 0x2e, 0x46, 0x84, 0x89, 0x5e, 0xea, 0xae, 0xd7, 0xe6, 0x35, 0x72, 0x5d, 0xf4, 0xdf, 0x41, 0x75, 0x2c, 0xa7, 0x5c,\n\t0x9e, 0xa2, 0xd6, 0xa7, 0x6c, 0x33, 0x44, 0x2b, 0xdc, 0xb6, 0xcf, 0x78, 0x5b, 0x34, 0xc3, 0x8f, 0x9b, 0x57, 0xac, 0x5d, 0xca, 0xc8, 0xc9, 0x91, 0x5b, 0xc4, 0x4f, 0xe4, 0x48, 0x3f, 0xcb, 0x0d, 0xc2, 0xa5, 0x8e, 0x19, 0xfc, 0x28, 0x76, 0x91, 0x09, 0xe6, 0xc9, 0x22, 0xeb, 0x97, 0x23, 0xf9, 0xa2, 0x90, 0xd7, 0x8a, 0x40, 0x09, 0xf0, 0xca, 0x1f, 0xc4, 0x01, 0xf6, 0x30, 0x10, 0x7f, 0x9e, 0x01, 0x2e, 0x26, 0x5f, 0x1c, 0x2a, 0x77, 0x68, 0xc3, 0xc1, 0x18, 0xb9, 0x8b, 0xbd, 0x1e, 0x0a, 0x5a, 0x28, 0x2b, 0x82, 0x3e, 0x94, 0x3f, 0x06, 0x7d, 0x24, 0x8b, 0x82, 0x3e, 0xe5, 0xf9, 0x33, 0xb0, 0x42, 0xfe, 0x18, 0xf2, 0xab, 0xfc, 0x51, 0xcf, 0x92, 0x3f, 0x1a, 0xd7, 0x82, 0xeb, 0xc0, 0xbd, 0xe0, 0x3e, 0x70, 0x3f, 0x98, 0x08, 0x26, 0x81, 0xc9, 0x60, 0x0a, 0x78, 0x40, 0xfe, 0xe8, 0xe8,\n\t0x24, 0xb7, 0x38, 0x3a, 0x83, 0x2e, 0xa0, 0x2b, 0xe8, 0x06, 0xba, 0x83, 0x1e, 0x20, 0x0d, 0xf4, 0x04, 0xe7, 0x83, 0x0b, 0x40, 0x2f, 0xd0, 0x1b, 0xa4, 0x83, 0x3e, 0xa0, 0x2f, 0xe8, 0x07, 0xfa, 0x83, 0x01, 0x60, 0x20, 0x18, 0x04, 0x32, 0xc0, 0x85, 0x60, 0x30, 0xb8, 0x08, 0x0c, 0x01, 0x17, 0xcb, 0x03, 0x8e, 0xa1, 0x60, 0x18, 0x18, 0x0e, 0x46, 0x80, 0x4b, 0xc0, 0x48, 0x30, 0x0a, 0x8c, 0x06, 0xaf, 0xcb, 0x9d, 0x8e, 0x37, 0xc0, 0x9b, 0x60, 0x1e, 0x98, 0x0f, 0xde, 0x02, 0x6f, 0x83, 0x77, 0xc0, 0xbb, 0xe0, 0x3d, 0xf0, 0x3e, 0x58, 0x00, 0x3e, 0x00, 0x0b, 0xc1, 0x87, 0x60, 0x11, 0xf8, 0x08, 0x2c, 0x06, 0x1f, 0x83, 0x25, 0xe0, 0x13, 0xf0, 0x29, 0x58, 0x0a, 0x3e, 0x03, 0x7b, 0xe4, 0x0e, 0xa2, 0x9c, 0xdc, 0xec, 0x6f, 0xdf, 0xef, 0xe7, 0xef, 0xdf, 0x21, 0xa8, 0xa1, 0xfa, 0xc4,\n\t0x18, 0x3c, 0xc1, 0xe5, 0x28, 0xdd, 0xdf, 0xf9, 0x64, 0x13, 0x72, 0xa9, 0x04, 0x72, 0xa9, 0x04, 0x55, 0xc2, 0x68, 0xc6, 0xff, 0x18, 0xc6, 0xc5, 0xe5, 0x22, 0xe6, 0x6f, 0x95, 0xd2, 0xb8, 0x4e, 0x29, 0x63, 0x44, 0x1f, 0x4a, 0xb8, 0xe0, 0x6f, 0x95, 0x60, 0x32, 0xb5, 0xf8, 0x6f, 0xb7, 0xbb, 0xc1, 0x9f, 0xe5, 0x8d, 0x41, 0x47, 0x64, 0x61, 0x50, 0x85, 0x2c, 0x34, 0xaf, 0xd9, 0x5e, 0x9b, 0x43, 0xfe, 0xb7, 0xaf, 0x27, 0x7d, 0xae, 0x39, 0xec, 0x6c, 0x57, 0x8f, 0x5e, 0x65, 0x5d, 0x3d, 0xfa, 0x47, 0xf6, 0x95, 0xfd, 0x8f, 0xae, 0x1e, 0xdd, 0xb2, 0x5e, 0xa9, 0xfb, 0xb5, 0x74, 0x6a, 0xdc, 0x87, 0xb9, 0xa1, 0x2f, 0xcf, 0xfd, 0xd4, 0x15, 0x39, 0x4c, 0x1f, 0x15, 0x42, 0x6f, 0xda, 0x7e, 0x57, 0x3d, 0xf6, 0x74, 0x9d, 0x2c, 0xd7, 0xc6, 0xa9, 0xfb, 0x99, 0xca, 0x3f, 0xd8, 0xe3, 0x6f,\n\t0xec, 0xf1, 0xb7, 0x3a, 0x7b, 0x8c, 0xac, 0xb7, 0xc7, 0x42, 0xda, 0xe1, 0xa5, 0x1d, 0x65, 0xd6, 0xb5, 0x0a, 0x8f, 0x58, 0xa5, 0x17, 0x52, 0x7a, 0xa1, 0x3a, 0xe6, 0x7a, 0xee, 0xd2, 0x5d, 0x94, 0xee, 0xaa, 0x53, 0xba, 0x79, 0x4f, 0x80, 0x3d, 0xf4, 0xe3, 0x1e, 0xad, 0xa3, 0xf4, 0x6b, 0x9d, 0xe5, 0xbe, 0x3f, 0xba, 0xd6, 0x36, 0xfd, 0x78, 0x24, 0x38, 0x54, 0x1e, 0x0e, 0x1e, 0x21, 0xf7, 0x05, 0x8f, 0x94, 0xbf, 0x04, 0x8f, 0x96, 0x85, 0x35, 0x2c, 0xe1, 0x0b, 0x0b, 0x50, 0x97, 0x8a, 0xff, 0xd1, 0x55, 0xbb, 0x6b, 0x58, 0xf0, 0xd6, 0x96, 0x9a, 0xce, 0xd8, 0xee, 0xab, 0xae, 0xda, 0xf8, 0x77, 0x4b, 0xdf, 0x4e, 0xe9, 0xdb, 0xeb, 0x94, 0xde, 0x9c, 0xd2, 0x8b, 0x28, 0x3d, 0x8f, 0xd2, 0xbf, 0xa7, 0xf4, 0x1f, 0xb4, 0xc1, 0xc4, 0x5d, 0x75, 0x44, 0xd7, 0x5e, 0xcf, 0xdd, 0x2a, 0x79,\n\t0x23, 0x25, 0xff, 0x42, 0xc9, 0x25, 0x94, 0x5c, 0x62, 0x1d, 0x2f, 0x37, 0xaf, 0xdd, 0xe0, 0xa3, 0xe4, 0x55, 0x94, 0xbc, 0x8a, 0x92, 0x4f, 0x52, 0xb2, 0x79, 0x6c, 0x65, 0x6a, 0x9d, 0xab, 0xc2, 0x9b, 0xd7, 0x93, 0x5f, 0xa7, 0x1c, 0x41, 0xed, 0xf5, 0xb9, 0x14, 0xff, 0x1e, 0xf8, 0xf7, 0xaa, 0xeb, 0x6d, 0x75, 0x96, 0x07, 0xa8, 0xc1, 0x06, 0x6a, 0x60, 0x2a, 0xc1, 0x92, 0xc0, 0xeb, 0xd0, 0xb3, 0xf7, 0x9f, 0xac, 0x7b, 0x32, 0x54, 0x58, 0xfc, 0x17, 0xc2, 0xbf, 0xd9, 0x9e, 0x6c, 0xf6, 0x9a, 0x6d, 0xdd, 0x93, 0xa1, 0x8a, 0xb6, 0xd4, 0x5c, 0xed, 0x9d, 0xdc, 0x46, 0x5d, 0xf1, 0x9d, 0x2c, 0x11, 0x2d, 0x76, 0xaa, 0x2b, 0xbe, 0x5f, 0x4c, 0x46, 0x52, 0x7d, 0x06, 0x4a, 0x38, 0x91, 0x19, 0x1e, 0xf0, 0x3d, 0x48, 0x72, 0xfd, 0x2b, 0xc0, 0xd7, 0x5c, 0x79, 0xa8, 0xf6, 0x4a, 0xf0, 0x91,\n\t0x01, 0x25, 0x87, 0x59, 0x25, 0xdb, 0x29, 0xd9, 0x6e, 0x95, 0x1c, 0x4e, 0xc9, 0x61, 0x94, 0xec, 0x34, 0xaf, 0x84, 0x43, 0xc9, 0x06, 0x25, 0x1b, 0xea, 0x48, 0xc4, 0x99, 0x25, 0xeb, 0x94, 0xac, 0x1b, 0x4f, 0x8a, 0xc6, 0xb5, 0xa5, 0x37, 0xa8, 0x73, 0x95, 0xfa, 0xea, 0xab, 0xd3, 0x17, 0xd0, 0xfa, 0x5f, 0x68, 0xfd, 0xbe, 0x73, 0x5e, 0x9d, 0x3e, 0x84, 0xad, 0x77, 0x6b, 0xbd, 0x40, 0x6f, 0x50, 0x7d, 0x5d, 0xcd, 0xa3, 0x67, 0x2d, 0xeb, 0xcf, 0xaf, 0x74, 0xdf, 0x10, 0xee, 0xf7, 0xc3, 0xbd, 0x79, 0xa5, 0xaf, 0x9f, 0xf9, 0x44, 0x3e, 0x9f, 0xd8, 0xcd, 0x27, 0x3c, 0x70, 0x5f, 0x61, 0x1d, 0x39, 0x2b, 0xb5, 0x7a, 0xdd, 0xbc, 0x06, 0x67, 0x3e, 0xbc, 0xe7, 0xf3, 0xc9, 0x65, 0xaa, 0x17, 0xab, 0xe8, 0xc1, 0xca, 0xda, 0x12, 0xd2, 0x59, 0xef, 0xc3, 0x88, 0xea, 0xcb, 0x73, 0x3f, 0x9e,\n\t0xab, 0xe7, 0x1e, 0x53, 0xd3, 0xd7, 0x59, 0xf3, 0x5c, 0x6d, 0x09, 0x86, 0x97, 0x6c, 0xaa, 0x14, 0x94, 0x83, 0x23, 0x80, 0xf9, 0xae, 0xb6, 0x2e, 0x27, 0xf8, 0xe4, 0x09, 0x78, 0x0d, 0xe2, 0x93, 0xb2, 0xe6, 0x93, 0xd6, 0xd9, 0xee, 0x81, 0x75, 0x39, 0x48, 0x49, 0x07, 0x55, 0x5d, 0x02, 0x5b, 0xb1, 0xd9, 0xda, 0x67, 0xee, 0xef, 0x9f, 0x24, 0xc6, 0xcf, 0xd5, 0x8a, 0xc0, 0x4f, 0x9e, 0x51, 0xdb, 0x3f, 0xfc, 0x64, 0x67, 0xeb, 0x8e, 0x78, 0xe9, 0x38, 0xa0, 0x74, 0x72, 0x87, 0x74, 0x72, 0x87, 0x74, 0x72, 0x87, 0x74, 0x3c, 0x62, 0x3f, 0x3c, 0xe2, 0x30, 0x3c, 0xa2, 0x99, 0x35, 0x8f, 0x25, 0x72, 0x86, 0xe2, 0x11, 0x47, 0x10, 0x39, 0x7d, 0xf0, 0x88, 0x23, 0x88, 0x9e, 0x3e, 0xcc, 0x98, 0x89, 0x44, 0x4f, 0x5f, 0x5a, 0x39, 0xc2, 0xca, 0xc2, 0x46, 0xe3, 0x17, 0xaf, 0x20, 0x82, 0x2e,\n\t0x26, 0x82, 0x2e, 0xa6, 0xb5, 0xd7, 0xe2, 0x17, 0x7b, 0xa9, 0x3b, 0xeb, 0x75, 0x17, 0x63, 0x89, 0x9c, 0xb1, 0x68, 0x53, 0x3a, 0x7e, 0xb0, 0x15, 0xde, 0x3e, 0x1d, 0x6f, 0x9f, 0x8e, 0xb7, 0x4f, 0xc7, 0xdb, 0xdf, 0x61, 0xdd, 0x59, 0x2f, 0x1d, 0x6f, 0x9f, 0x8e, 0x1a, 0xa4, 0xe3, 0xed, 0xd3, 0xf1, 0xf6, 0xe9, 0x78, 0xfb, 0x74, 0x34, 0x2c, 0x1d, 0x75, 0x48, 0xc7, 0xdb, 0xa7, 0xa3, 0x10, 0xe9, 0x78, 0xfb, 0x74, 0xb4, 0x2c, 0x5d, 0xdd, 0x6b, 0xe0, 0xcc, 0xbb, 0xfc, 0x85, 0xd6, 0xbc, 0x42, 0x9d, 0x5a, 0x51, 0xa7, 0xb8, 0xda, 0x77, 0xd6, 0xa9, 0xd6, 0xf6, 0x61, 0x3c, 0x90, 0x47, 0xd2, 0xbe, 0x48, 0xd1, 0x1f, 0x0c, 0x00, 0x03, 0xc1, 0x20, 0x90, 0x01, 0x2e, 0x04, 0x83, 0xc1, 0x45, 0x60, 0x08, 0xb8, 0x18, 0x0c, 0x05, 0xc3, 0xc0, 0x70, 0x30, 0x02, 0x5c, 0x02, 0x46, 0x82, 0x51,\n\t0x80, 0xbc, 0x5b, 0x5c, 0x0a, 0xc6, 0x80, 0xcb, 0xc0, 0xe5, 0xe0, 0x0a, 0x70, 0x25, 0x18, 0x0b, 0xae, 0x02, 0x57, 0x83, 0x6b, 0xc0, 0xb5, 0xe0, 0x46, 0xf6, 0x72, 0x13, 0xb8, 0x19, 0xdc, 0x0a, 0x6e, 0x03, 0x8f, 0xf0, 0xfa, 0x34, 0x14, 0xf6, 0x51, 0xf0, 0x18, 0x78, 0x1c, 0x4c, 0x07, 0x4f, 0x80, 0x27, 0xc1, 0x53, 0xe0, 0x69, 0xf0, 0x0c, 0x98, 0x29, 0x3a, 0x89, 0xe7, 0xc8, 0xee, 0x9e, 0x17, 0xed, 0xc5, 0xbf, 0x44, 0x57, 0x7a, 0xaa, 0x3d, 0x3d, 0xf5, 0x08, 0x3d, 0x75, 0x3e, 0x3d, 0x35, 0x9c, 0x9e, 0x1a, 0x41, 0x4f, 0x4d, 0xa1, 0xa7, 0x7a, 0xd2, 0x53, 0x53, 0xe8, 0xa9, 0x9e, 0xf4, 0x54, 0x4f, 0x7a, 0xea, 0x7c, 0x7a, 0x2a, 0x03, 0x56, 0x22, 0x61, 0x25, 0x9a, 0x9e, 0x1a, 0x4e, 0x4f, 0x5d, 0x4f, 0x4f, 0x5d, 0x4f, 0x4f, 0x8d, 0xa2, 0xa7, 0x46, 0xd9, 0xd8, 0xb7, 0x8d, 0x7d,\n\t0x9b, 0x8c, 0xd9, 0xe6, 0x8a, 0xae, 0xb6, 0xf7, 0x44, 0xa4, 0xed, 0x7d, 0xb0, 0x00, 0x7c, 0x00, 0x16, 0x82, 0x0f, 0xc1, 0x22, 0xf0, 0x11, 0x58, 0x0c, 0x3e, 0x06, 0x4b, 0xf8, 0xcc, 0x27, 0xa2, 0x19, 0xbd, 0xfc, 0x20, 0xbd, 0xfc, 0x60, 0xc8, 0x77, 0x22, 0x32, 0x64, 0x0d, 0xf8, 0x41, 0x64, 0x84, 0x6c, 0xe1, 0x79, 0x2b, 0xd8, 0x06, 0xb6, 0x83, 0x1c, 0x70, 0x4c, 0x9c, 0x1f, 0x8a, 0x33, 0xd1, 0x7d, 0x22, 0x52, 0x3f, 0x04, 0x0e, 0x83, 0x72, 0x70, 0x04, 0x54, 0x80, 0xa3, 0xe0, 0x18, 0xf0, 0x83, 0x4a, 0xf0, 0x2b, 0x38, 0x0e, 0x4e, 0x80, 0x2a, 0x70, 0x12, 0x9c, 0x02, 0xbf, 0x81, 0xd3, 0x22, 0x92, 0x68, 0xca, 0x20, 0x9a, 0x32, 0x88, 0xa6, 0x8c, 0xea, 0x33, 0x63, 0x41, 0x1c, 0x88, 0x07, 0x09, 0xa0, 0xfa, 0x3b, 0x87, 0x0c, 0xa2, 0x29, 0x83, 0x68, 0xca, 0x20, 0x9a, 0x32, 0x88,\n\t0xa6, 0x0c, 0xa2, 0x29, 0x83, 0x68, 0xca, 0x20, 0x9a, 0x32, 0x8c, 0xd7, 0x71, 0x4a, 0x6f, 0x80, 0x37, 0xc1, 0x3c, 0x30, 0x1f, 0xbc, 0x05, 0xc8, 0x13, 0x8c, 0x77, 0xc0, 0xbb, 0xe0, 0x3d, 0xf0, 0x3e, 0x58, 0x00, 0x3e, 0x00, 0x0b, 0xc1, 0x87, 0x60, 0x11, 0xf8, 0x08, 0x2c, 0x06, 0x1f, 0x03, 0xf8, 0x30, 0xe0, 0xc3, 0xf8, 0x14, 0x2c, 0x05, 0x9f, 0x81, 0x65, 0x60, 0x39, 0xf8, 0x37, 0x58, 0x01, 0x3e, 0x07, 0x5f, 0x80, 0x2f, 0xc1, 0x57, 0x60, 0x25, 0xf8, 0x1a, 0x7c, 0x03, 0x32, 0xc1, 0x7f, 0xc0, 0xb7, 0x60, 0x15, 0x70, 0x89, 0x4e, 0xc6, 0x4e, 0xb0, 0x8b, 0x8c, 0x36, 0x0f, 0xec, 0x06, 0x1e, 0xb0, 0x07, 0xec, 0x05, 0xf9, 0xa0, 0x40, 0xb4, 0x37, 0xf6, 0x81, 0x22, 0xd1, 0xd5, 0x28, 0x06, 0xfb, 0x41, 0x09, 0x28, 0x03, 0x07, 0x80, 0x0f, 0x1c, 0x04, 0x87, 0xc0, 0x61, 0xd1, 0x55,\n\t0x8d, 0x08, 0xbd, 0x8e, 0x0b, 0x8b, 0x13, 0x71, 0xb0, 0xa5, 0x05, 0x7c, 0x33, 0xd3, 0x5a, 0x5c, 0xc0, 0x1c, 0x91, 0x4a, 0x46, 0x99, 0x4a, 0x46, 0x99, 0x4a, 0x46, 0x99, 0x4a, 0x46, 0x99, 0x6a, 0x7d, 0x67, 0x94, 0x4a, 0x46, 0x99, 0x7a, 0x96, 0xef, 0x8c, 0x52, 0xc9, 0x08, 0x53, 0xc9, 0x08, 0x53, 0xc9, 0x08, 0x53, 0xc9, 0x08, 0x53, 0xc9, 0x08, 0x53, 0xc9, 0x08, 0x53, 0xc9, 0x02, 0x53, 0xf5, 0x37, 0x44, 0x43, 0x32, 0xc1, 0x54, 0x32, 0xc1, 0x54, 0x32, 0xc1, 0x54, 0x32, 0xc1, 0x54, 0x32, 0xc1, 0x54, 0x32, 0xc1, 0x54, 0x32, 0xc1, 0x54, 0x32, 0xc1, 0x54, 0x32, 0xc1, 0x54, 0xfa, 0x71, 0x3e, 0x35, 0x6a, 0x40, 0x1f, 0xf6, 0xa4, 0x56, 0x23, 0xe9, 0xc3, 0xe1, 0xf4, 0xe1, 0xb4, 0x80, 0xda, 0x35, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43,\n\t0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x25, 0x43, 0x4c, 0x45, 0xbf, 0x06, 0x1a, 0xb3, 0xe1, 0xec, 0x98, 0x88, 0x40, 0x45, 0x6e, 0x54, 0xdf, 0x8c, 0x05, 0x1e, 0xd7, 0x7f, 0xc4, 0x3a, 0xae, 0xaf, 0x05, 0x1c, 0xd7, 0x77, 0xfe, 0xd5, 0x63, 0xf2, 0xea, 0x38, 0xfc, 0x3c, 0xd1, 0x24, 0xf0, 0x58, 0xbc, 0x2e, 0x85, 0x71, 0xce, 0xe3, 0xf1, 0xb1, 0xea, 0x9b, 0xa4, 0xaf, 0x68, 0xe9, 0xbf, 0x68, 0xe9, 0x2d, 0xb4, 0xf4, 0x6e, 0x5a, 0xda, 0x29, 0xa0, 0xa5, 0xff, 0xf9, 0xa7, 0xc7, 0xe9, 0x8d, 0x59, 0xa2, 0x23, 0x2d, 0x1c, 0xa0, 0xce, 0x3d, 0x09, 0x3c, 0x5e, 0x7f, 0x2d, 0xad, 0x8e, 0x66, 0x1e, 0x8a, 0xb6, 0xee, 0x83, 0x1a, 0x6d, 0xde, 0x07, 0xd5, 0x3a, 0x5e, 0xaf, 0x05,\n\t0x1c, 0xaf, 0xd7, 0xfe, 0xf2, 0xb1, 0xf6, 0x1f, 0xd4, 0xf7, 0x32, 0x7f, 0xf5, 0x18, 0x7b, 0x34, 0xe3, 0x35, 0x9a, 0xf1, 0x1a, 0x4d, 0x3f, 0xf7, 0xb3, 0x66, 0xff, 0x5b, 0x60, 0x60, 0x2a, 0x0c, 0x4c, 0x82, 0x81, 0x47, 0x60, 0xe0, 0x1a, 0xc6, 0x6b, 0x34, 0xe3, 0x35, 0xda, 0x3a, 0xb2, 0x13, 0x6d, 0x1d, 0xd9, 0x89, 0x86, 0x91, 0x3b, 0xff, 0xe9, 0x31, 0x76, 0xd8, 0xe8, 0x25, 0x1a, 0xc2, 0xc0, 0x45, 0xf5, 0xbe, 0x2b, 0xec, 0x4d, 0x0d, 0xee, 0xa6, 0x06, 0xcf, 0x53, 0x83, 0x47, 0xa8, 0xc1, 0xb3, 0xd4, 0x60, 0x52, 0x40, 0x1f, 0xdc, 0xcf, 0x27, 0x7b, 0xa2, 0x0c, 0x9d, 0x45, 0x18, 0x3c, 0x86, 0xc1, 0x63, 0x18, 0xa5, 0x0c, 0x83, 0xc7, 0x26, 0xf0, 0xd8, 0xc4, 0xe2, 0xb1, 0x89, 0xc5, 0x63, 0x98, 0xc5, 0x63, 0x18, 0x3c, 0x86, 0x9d, 0x85, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30,\n\t0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x34, 0x8f, 0x90, 0x99, 0xf7, 0x1c, 0x0e, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x26, 0xf0, 0xd8, 0x04, 0x1e, 0x9b, 0xd0, 0x82, 0x07, 0x2c, 0x1e, 0xcf, 0xa7, 0x15, 0xf7, 0x59, 0x3c, 0x3e, 0x4f, 0x2b, 0x66, 0xc2, 0xa3, 0x79, 0xdd, 0xcb, 0x26, 0x16, 0x8f, 0x4d, 0x2c, 0x1e, 0xcd, 0x2b, 0x08, 0xf4, 0x81, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x83, 0xc7, 0x30, 0x78, 0x0c, 0x63, 0x0c, 0x75, 0x66, 0x0c, 0x45, 0x31, 0x86, 0xec, 0x30, 0x33, 0x46, 0x9d, 0xd1, 0x34, 0xa0, 0x1e, 0xa7,\n\t0x77, 0x51, 0x9b, 0x4e, 0xd4, 0xe6, 0x6a, 0x6a, 0x73, 0x0d, 0xb5, 0x99, 0x54, 0xef, 0x9b, 0x5f, 0xf3, 0xfe, 0xbf, 0x6d, 0x28, 0xc5, 0xf4, 0xaa, 0x43, 0x14, 0xb7, 0xf1, 0x70, 0x1b, 0x0f, 0xb7, 0xf1, 0x94, 0xd6, 0x0e, 0x6e, 0x1d, 0x70, 0xeb, 0xb0, 0xb8, 0x75, 0x58, 0xdc, 0xc6, 0x5b, 0xdc, 0xc6, 0xc3, 0x6d, 0xfc, 0x59, 0xb8, 0x8d, 0x87, 0xdb, 0x78, 0xb8, 0x8d, 0x87, 0xdb, 0x78, 0xb8, 0x8d, 0x87, 0xdb, 0x78, 0xb8, 0x8d, 0x87, 0x5b, 0x07, 0xdc, 0xc6, 0xc3, 0x6d, 0x3c, 0xdc, 0xc6, 0xc3, 0x6d, 0x3c, 0xdc, 0xc6, 0xc3, 0x6d, 0x3c, 0xdc, 0xc6, 0xc3, 0x6d, 0x3c, 0xdc, 0xc6, 0xc3, 0x6d, 0x3c, 0xdc, 0x3a, 0xe0, 0xd6, 0x01, 0xb7, 0x0e, 0x5a, 0xf2, 0x9c, 0xc5, 0xad, 0x83, 0xd6, 0xf4, 0xa5, 0x35, 0x97, 0xd3, 0x9a, 0x31, 0xb4, 0xe6, 0x35, 0xb8, 0x75, 0xc0, 0xad, 0xc3, 0xe2, 0xd6,\n\t0x61, 0x71, 0xeb, 0xa0, 0x75, 0xcd, 0xe0, 0x36, 0x1e, 0x6e, 0xe3, 0xe1, 0x36, 0x1e, 0x6e, 0xe3, 0xe1, 0x36, 0x1e, 0x6e, 0xe3, 0xe1, 0x36, 0x1e, 0x6e, 0xe3, 0xe1, 0x36, 0x1e, 0x6e, 0xe3, 0xe1, 0x36, 0x1e, 0x6e, 0xe3, 0xe1, 0x36, 0x1e, 0x6e, 0xe3, 0x61, 0x65, 0x10, 0xac, 0xb4, 0x87, 0xdb, 0x16, 0x30, 0x73, 0x83, 0x72, 0x8d, 0xbf, 0xf3, 0x1a, 0x4f, 0x24, 0x9b, 0xbf, 0xfb, 0xa8, 0xc9, 0x98, 0x2f, 0x84, 0xb7, 0x58, 0x78, 0x8b, 0x85, 0xb7, 0xc1, 0x6c, 0x7d, 0x0f, 0xbc, 0xb5, 0x87, 0xb7, 0xf6, 0x16, 0x6f, 0xed, 0x2d, 0xde, 0x62, 0x2d, 0xde, 0x62, 0xe1, 0x2d, 0xf6, 0x2c, 0xbc, 0xc5, 0xc2, 0x5b, 0x2c, 0xbc, 0xc5, 0xc2, 0x5b, 0x2c, 0xbc, 0xc5, 0xc2, 0x5b, 0x2c, 0xbc, 0xc5, 0xc2, 0x5b, 0x7b, 0x78, 0x8b, 0xd5, 0xdf, 0x52, 0xdf, 0xf6, 0xc4, 0xc2, 0x5d, 0x2c, 0xdc, 0xc5, 0xc2,\n\t0x5d, 0x2c, 0xdc, 0xc5, 0xc2, 0x5d, 0x2c, 0xdc, 0xc5, 0xc2, 0x5d, 0x2c, 0xdc, 0xc5, 0xc2, 0x5d, 0x7b, 0xb8, 0x6b, 0x0f, 0x77, 0xed, 0xe1, 0x6e, 0xb4, 0xc5, 0xdd, 0x83, 0xd4, 0x7c, 0x1e, 0x35, 0x7f, 0x19, 0xee, 0xde, 0x86, 0xbb, 0xc7, 0xe0, 0xae, 0x3d, 0xdc, 0xb5, 0xb7, 0xb8, 0x6b, 0x6f, 0x71, 0xd7, 0x1e, 0xee, 0xa6, 0xc1, 0x5d, 0x2c, 0xdc, 0xc5, 0xc2, 0x5d, 0x2c, 0xdc, 0xc5, 0xc2, 0x5d, 0x2c, 0xdc, 0xc5, 0xc2, 0x5d, 0x2c, 0xdc, 0xc5, 0xc2, 0x5d, 0x2c, 0xdc, 0xc5, 0xc2, 0x5d, 0x2c, 0xdc, 0xc5, 0xc2, 0x5d, 0x2c, 0xdc, 0xc5, 0xc2, 0x9d, 0x19, 0x4d, 0xc3, 0x45, 0x23, 0x98, 0xb8, 0xa9, 0x5e, 0x3c, 0x9a, 0xc7, 0x44, 0x66, 0x51, 0x8b, 0xa7, 0xa8, 0xc5, 0x0d, 0xd4, 0xe2, 0x21, 0x6a, 0x31, 0x24, 0x20, 0x1e, 0x5f, 0x62, 0xbe, 0x34, 0xf8, 0x74, 0xa2, 0x1a, 0xdb, 0x3d, 0xea,\n\t0xa9, 0xe3, 0x8d, 0x7c, 0xf2, 0x22, 0x3e, 0xd9, 0x95, 0x4f, 0x76, 0xe2, 0x93, 0xf6, 0x80, 0x4f, 0xde, 0x76, 0x86, 0x96, 0xb6, 0xa8, 0xa7, 0xa5, 0xf1, 0x4a, 0x4b, 0x93, 0xe8, 0xa7, 0x24, 0xfa, 0x29, 0x89, 0xf2, 0x93, 0xe8, 0x93, 0x24, 0xab, 0x4f, 0x92, 0xe8, 0x93, 0xa4, 0xb3, 0xf4, 0x49, 0x12, 0x7d, 0x92, 0x44, 0x9f, 0x24, 0xd1, 0x27, 0x49, 0xf4, 0x49, 0x12, 0x7d, 0x92, 0x44, 0x9f, 0x24, 0xd1, 0x1f, 0x49, 0x68, 0xa9, 0x39, 0xdf, 0x26, 0xd1, 0x1f, 0x49, 0xf4, 0x47, 0x12, 0xfd, 0x91, 0x44, 0x7f, 0x24, 0xd1, 0x1f, 0x49, 0xf4, 0x47, 0x12, 0xfd, 0x91, 0x44, 0x7f, 0x24, 0xd1, 0xf2, 0x37, 0xac, 0xd8, 0xed, 0x4e, 0xad, 0x86, 0x53, 0xff, 0x21, 0xd4, 0xff, 0xa1, 0x80, 0xda, 0x35, 0x84, 0xef, 0x24, 0xf8, 0x4e, 0x82, 0xef, 0x24, 0xf8, 0x4e, 0x82, 0xef, 0x24, 0xf8, 0x4e, 0x82,\n\t0xef, 0x24, 0xf8, 0x4e, 0x82, 0xef, 0x24, 0xf8, 0x4e, 0x82, 0xef, 0x24, 0xf8, 0x4e, 0x82, 0xef, 0x24, 0xf8, 0x4e, 0x82, 0xef, 0xbe, 0xc4, 0x6a, 0x32, 0xb1, 0xda, 0x04, 0xe6, 0xc6, 0xa9, 0x3b, 0xb0, 0xd7, 0x44, 0x63, 0x2c, 0xad, 0x9c, 0x7a, 0x96, 0xc8, 0xb3, 0xff, 0xd5, 0xc8, 0x53, 0x51, 0x37, 0x4f, 0x34, 0xf8, 0x4b, 0x51, 0x57, 0xfd, 0x4d, 0xed, 0xe7, 0xb4, 0x72, 0xa6, 0xd5, 0xbf, 0x77, 0xd0, 0xca, 0xf6, 0x01, 0xad, 0xfc, 0xfa, 0x1f, 0x47, 0xd5, 0x2c, 0xd1, 0x9e, 0xd6, 0xf5, 0x51, 0x3a, 0x6a, 0xa7, 0x75, 0x76, 0x5a, 0x67, 0xa7, 0x75, 0x63, 0x19, 0x6b, 0xcd, 0x19, 0x6b, 0xcd, 0xad, 0xb1, 0xd6, 0xdc, 0x1a, 0x6b, 0x76, 0xab, 0xc5, 0x76, 0x5a, 0x6c, 0x3f, 0x4b, 0xbf, 0xda, 0x69, 0xb1, 0x9d, 0x16, 0xdb, 0x69, 0xb1, 0x9d, 0x16, 0xdb, 0x69, 0xb1, 0x9d, 0x16, 0xdb, 0x19,\n\t0x6b, 0xcd, 0x69, 0xb5, 0x79, 0x5e, 0x8d, 0x9d, 0x16, 0xdb, 0x69, 0xb1, 0x9d, 0x16, 0xdb, 0x69, 0xb1, 0x9d, 0x16, 0xdb, 0x69, 0xb1, 0x9d, 0x16, 0xdb, 0x69, 0xb1, 0x9d, 0x71, 0xd6, 0x9c, 0x71, 0xd6, 0x9c, 0x71, 0xd6, 0x5c, 0x29, 0x58, 0xf5, 0x38, 0xbb, 0x01, 0x06, 0x26, 0xc3, 0xc0, 0xbd, 0x30, 0x30, 0x15, 0x06, 0xc6, 0x32, 0xce, 0x9a, 0x33, 0xce, 0x9a, 0x5b, 0xe3, 0xac, 0xb9, 0x35, 0xce, 0x9a, 0xc3, 0xc8, 0xad, 0x30, 0x62, 0x87, 0x11, 0xbb, 0x61, 0x7e, 0xe7, 0x90, 0x06, 0x7a, 0x82, 0x5e, 0xa0, 0x37, 0x48, 0x07, 0x7d, 0x40, 0x5f, 0xd0, 0x0f, 0xf4, 0x07, 0x03, 0xc0, 0x40, 0x35, 0xe7, 0xa7, 0x29, 0x1d, 0xcd, 0xa8, 0x37, 0xc6, 0x7a, 0x52, 0x83, 0x3b, 0xa8, 0xc1, 0xb3, 0xd4, 0x60, 0x2a, 0x35, 0x78, 0x9a, 0x1a, 0xdc, 0x17, 0xd0, 0x07, 0x13, 0xf8, 0x64, 0x77, 0x35, 0x67,\n\t0xe9, 0xf0, 0xa8, 0xc3, 0xa3, 0x4e, 0x29, 0x43, 0xe0, 0xb1, 0x21, 0x3c, 0x36, 0xb4, 0x78, 0x6c, 0x68, 0xf1, 0xa8, 0x5b, 0x3c, 0xea, 0xf0, 0xa8, 0x9f, 0x85, 0x47, 0x1d, 0x1e, 0x75, 0x78, 0xd4, 0xe1, 0x51, 0x87, 0x47, 0x1d, 0x1e, 0x75, 0x78, 0xd4, 0xe1, 0xb1, 0x21, 0x3c, 0xea, 0xf0, 0xa8, 0xc3, 0xa3, 0x0e, 0x8f, 0x3a, 0x3c, 0xea, 0xf0, 0xa8, 0xc3, 0xa3, 0x0e, 0x8f, 0x3a, 0x3c, 0xea, 0xf0, 0xa8, 0xc3, 0x63, 0x43, 0x78, 0x6c, 0x08, 0x8f, 0x0d, 0x69, 0xc1, 0x24, 0x8b, 0xc7, 0x1e, 0xb4, 0x62, 0x02, 0xad, 0xb8, 0xdf, 0x72, 0x03, 0xcf, 0xc0, 0x63, 0x43, 0x78, 0x6c, 0x68, 0xf1, 0xd8, 0xd0, 0xe2, 0xd1, 0xbc, 0xd6, 0x78, 0x2f, 0x78, 0xd4, 0xe1, 0x51, 0x37, 0xcc, 0xe3, 0x23, 0x69, 0xa0, 0x27, 0xe8, 0x05, 0x7a, 0x83, 0x74, 0xd0, 0x07, 0xf4, 0x05, 0xfd, 0x40, 0x7f, 0x30, 0x00,\n\t0x0c, 0x54, 0xc7, 0x52, 0x3a, 0x30, 0x7e, 0xc2, 0x61, 0x65, 0xa4, 0xd2, 0xd0, 0xbe, 0xf5, 0xf8, 0xbc, 0x9d, 0x9a, 0xb4, 0xa7, 0x26, 0x57, 0x50, 0x93, 0xb1, 0xd4, 0xe4, 0x3e, 0x6a, 0x72, 0x7f, 0x00, 0x9f, 0x9d, 0x29, 0xa1, 0x15, 0x25, 0x38, 0x28, 0x21, 0x43, 0x39, 0xd9, 0xc0, 0x6f, 0x80, 0x92, 0xad, 0x6f, 0x80, 0xb4, 0x80, 0x6f, 0x80, 0xb4, 0xbf, 0xfa, 0x0d, 0xce, 0x5f, 0xfe, 0xd6, 0xa6, 0x25, 0xdc, 0x54, 0x9f, 0xfd, 0xdc, 0x9b, 0x5a, 0x8e, 0xa6, 0x96, 0xa3, 0xa8, 0xe5, 0x2b, 0x01, 0xb5, 0x6c, 0xfc, 0x4f, 0xbf, 0xcd, 0xa1, 0x75, 0xfd, 0x68, 0x5d, 0x0a, 0xf3, 0x4b, 0x73, 0x35, 0xbf, 0xd4, 0xd7, 0xc2, 0xba, 0xdf, 0x94, 0xd5, 0x3f, 0xae, 0xac, 0xd5, 0x39, 0x9b, 0xa9, 0xe6, 0x6c, 0xcc, 0x41, 0x30, 0x73, 0x27, 0x11, 0x97, 0x4a, 0xc4, 0xa5, 0x5a, 0x11, 0x97, 0x6a, 0x45,\n\t0x5c, 0xb4, 0xc5, 0x56, 0xcd, 0x19, 0x9a, 0xf5, 0xd9, 0xfa, 0xfd, 0xec, 0xca, 0xfa, 0x67, 0x56, 0xfe, 0xa0, 0x32, 0x9c, 0xbf, 0x76, 0x46, 0x65, 0x24, 0x59, 0x48, 0x34, 0x68, 0xa1, 0x32, 0x9d, 0x11, 0x56, 0xc4, 0x4d, 0xa2, 0x3d, 0xaf, 0x51, 0xeb, 0x17, 0x60, 0x70, 0x1e, 0x0c, 0x3e, 0x42, 0xc4, 0xa5, 0x12, 0x71, 0xa9, 0x56, 0xc4, 0xa5, 0x5a, 0x11, 0x97, 0x0a, 0xa3, 0x53, 0xff, 0xe9, 0x59, 0x99, 0x30, 0x6a, 0x28, 0xbf, 0xc5, 0x1c, 0x25, 0x4f, 0x9c, 0x93, 0x2f, 0x73, 0x6c, 0x8f, 0xaf, 0x17, 0x8b, 0x4d, 0xa8, 0xe3, 0x73, 0xd4, 0x71, 0x3a, 0x5b, 0xde, 0x48, 0x1d, 0x1f, 0x50, 0x59, 0xf5, 0xef, 0xbd, 0x3c, 0x87, 0x72, 0x63, 0x55, 0x7e, 0xd1, 0xb5, 0x9e, 0x1a, 0x8e, 0xb3, 0x72, 0xf1, 0x8e, 0x7c, 0x2a, 0x70, 0x46, 0xbe, 0xa9, 0xce, 0xbd, 0x70, 0x7f, 0xb2, 0xbe, 0x75, 0xdd,\n\t0x71, 0xce, 0x7b, 0xe1, 0xea, 0xd6, 0xd6, 0x07, 0xd8, 0xfa, 0xc7, 0xc0, 0xef, 0x68, 0x6b, 0xce, 0x6f, 0x50, 0xe7, 0x62, 0x5f, 0xab, 0x8d, 0x16, 0xf7, 0x6b, 0x63, 0xc4, 0x93, 0xda, 0xe5, 0xe2, 0xf1, 0xbf, 0x79, 0xb7, 0xdd, 0x30, 0x61, 0x93, 0xdb, 0xcd, 0x2b, 0x2d, 0x68, 0x3d, 0xe5, 0x37, 0xda, 0x60, 0xf9, 0x39, 0x9f, 0xf8, 0xa9, 0xf6, 0x7b, 0x8e, 0x72, 0x59, 0x60, 0x5d, 0x81, 0xfe, 0xa0, 0x6d, 0xa5, 0x3c, 0xc0, 0x27, 0xbc, 0xea, 0xde, 0x98, 0x87, 0xb4, 0x5e, 0xf2, 0xa0, 0xd6, 0x1b, 0x8c, 0xa6, 0xac, 0xea, 0x23, 0xfc, 0x47, 0x55, 0x59, 0x3b, 0x29, 0x6b, 0x3f, 0x5b, 0xe4, 0x50, 0xd6, 0x8f, 0xd6, 0x55, 0xc4, 0xcc, 0xbb, 0x83, 0xee, 0x0c, 0xb8, 0x17, 0x41, 0x25, 0x65, 0x1d, 0xa7, 0xac, 0x52, 0xe1, 0xd0, 0x1a, 0xf1, 0xf9, 0xc6, 0x30, 0xc0, 0xdc, 0x44, 0x7d, 0x0f, 0x58,\n\t0xdf, 0x61, 0x1e, 0x0a, 0xaa, 0x10, 0x46, 0xf0, 0x65, 0x32, 0x8f, 0x76, 0x56, 0xd1, 0xce, 0x02, 0x75, 0xad, 0xf4, 0xcd, 0x81, 0x5b, 0xd4, 0x9c, 0xb1, 0x6c, 0x7d, 0xc3, 0x79, 0xc8, 0x3c, 0x72, 0x41, 0x99, 0x45, 0xf4, 0xa4, 0x4d, 0x6e, 0xb3, 0x5a, 0xf4, 0xa5, 0xd6, 0x5f, 0x7e, 0xa7, 0x0d, 0x00, 0x83, 0xe5, 0x17, 0xd4, 0xc6, 0x65, 0x7d, 0xab, 0xb2, 0x9d, 0x4f, 0x17, 0xf2, 0xe9, 0x42, 0x15, 0xe5, 0x2b, 0xa5, 0x4f, 0xb5, 0x2c, 0xac, 0xce, 0x27, 0xff, 0xca, 0x27, 0x1a, 0x52, 0xf7, 0xbd, 0x5a, 0xb8, 0x7c, 0x5f, 0xeb, 0x28, 0xf7, 0x9d, 0xed, 0x53, 0xb4, 0x23, 0x3c, 0x78, 0x84, 0x5c, 0x60, 0xde, 0x95, 0xc9, 0x3a, 0xe7, 0xfd, 0x94, 0xf1, 0x82, 0x3c, 0x74, 0xce, 0x4f, 0xfa, 0xf9, 0x64, 0x25, 0x9f, 0xac, 0x3c, 0xe7, 0x27, 0x03, 0xef, 0xf2, 0x90, 0x77, 0xd6, 0xbb, 0x3c, 0xfc,\n\t0xf9, 0x7d, 0x20, 0x6e, 0x16, 0x47, 0xe5, 0xd3, 0xe2, 0x98, 0x3c, 0x2e, 0x8e, 0xcb, 0xd7, 0xc4, 0x09, 0xf9, 0x9a, 0xe6, 0xe4, 0xdd, 0x46, 0x7c, 0xaa, 0x09, 0xb5, 0x69, 0x0a, 0x9a, 0x81, 0x70, 0x79, 0x9d, 0x16, 0xc1, 0x98, 0x69, 0x2e, 0x8f, 0x68, 0x91, 0xfc, 0x1f, 0x05, 0xa2, 0xe5, 0x65, 0x5a, 0x0b, 0x10, 0xc3, 0x7a, 0x4b, 0x10, 0x0b, 0xe2, 0x88, 0x94, 0x78, 0x9e, 0x5b, 0xf1, 0xdc, 0x9a, 0xe7, 0x24, 0x90, 0x0c, 0x52, 0x40, 0x5b, 0xd0, 0x0e, 0xb4, 0xa7, 0x65, 0x1d, 0x78, 0xff, 0x3c, 0xd6, 0x3b, 0xca, 0xef, 0x83, 0x32, 0xe5, 0xf1, 0xa0, 0x2d, 0xf2, 0xb5, 0xa0, 0x3d, 0xa0, 0x50, 0xee, 0x0b, 0x2a, 0x02, 0xc5, 0x60, 0x3f, 0x28, 0x91, 0x27, 0x82, 0xbc, 0x3c, 0x97, 0x82, 0x32, 0xe0, 0x03, 0x07, 0xc1, 0x21, 0x70, 0x58, 0x6e, 0x09, 0xfa, 0x95, 0xe7, 0x2a, 0x70, 0x52, 0x5e,\n\t0x16, 0x74, 0x8a, 0xe7, 0xdf, 0x80, 0x94, 0xfb, 0x82, 0x6d, 0x72, 0x4b, 0x70, 0x10, 0xcf, 0xc1, 0xc0, 0xce, 0xba, 0x43, 0x5e, 0x16, 0xec, 0x64, 0x7d, 0x38, 0xb8, 0x44, 0xdd, 0x93, 0x65, 0x5f, 0xf0, 0xa5, 0xbc, 0x3e, 0x06, 0x10, 0xdd, 0x21, 0x07, 0xe5, 0x91, 0x90, 0x43, 0x72, 0x8b, 0x3d, 0x4d, 0xbe, 0x69, 0xbf, 0x1e, 0x8c, 0x97, 0x6f, 0xea, 0xef, 0x4b, 0x97, 0xfe, 0x05, 0xf8, 0x12, 0xfc, 0x07, 0xac, 0x93, 0x5b, 0xf4, 0x2d, 0x60, 0x27, 0xd8, 0x05, 0x4a, 0xe5, 0x16, 0xc3, 0x01, 0x68, 0xa7, 0x31, 0x08, 0x8c, 0x63, 0xfd, 0x41, 0xf0, 0x08, 0xeb, 0xd3, 0xe5, 0x3e, 0xc7, 0xbf, 0xe5, 0x71, 0xc7, 0x0a, 0xf0, 0x03, 0xeb, 0xe6, 0x37, 0x80, 0xeb, 0xc1, 0x46, 0x79, 0xc4, 0xf1, 0x23, 0xff, 0x6f, 0x02, 0x9b, 0xc1, 0x16, 0xb0, 0x15, 0xe4, 0x82, 0x9f, 0xa4, 0xdf, 0xb9, 0x8a, 0x71,\n\t0x68, 0xe8, 0x97, 0xca, 0x1d, 0xfa, 0x74, 0xf9, 0x9d, 0xfe, 0x84, 0x3c, 0xa8, 0x3f, 0xc9, 0xf3, 0x4c, 0x9e, 0x67, 0x81, 0xd9, 0x60, 0x0e, 0xff, 0xbf, 0x20, 0xbf, 0x13, 0xef, 0x8b, 0x8d, 0xf2, 0x94, 0xc8, 0x96, 0x27, 0xc4, 0x36, 0xfa, 0x2e, 0x47, 0x96, 0x8b, 0x5c, 0xd6, 0x7f, 0x62, 0x1e, 0xd8, 0xa1, 0xbe, 0xcd, 0xf7, 0x09, 0x17, 0xff, 0xef, 0xe4, 0xff, 0x5d, 0xac, 0xe7, 0xb1, 0x8d, 0x79, 0x4f, 0x3d, 0x0f, 0xeb, 0x7b, 0x58, 0xdf, 0xcb, 0x7a, 0x3e, 0xeb, 0xbf, 0xf0, 0xfe, 0x3e, 0xd6, 0x0b, 0x89, 0xa6, 0x22, 0xb0, 0x5f, 0x1e, 0x16, 0x25, 0x3c, 0x7b, 0x79, 0xbd, 0x8c, 0xf7, 0x0f, 0x30, 0x9e, 0x2f, 0x56, 0xdf, 0xdc, 0x99, 0x77, 0xca, 0x3a, 0x18, 0xf4, 0x21, 0xe3, 0x71, 0x11, 0xfd, 0xf5, 0x11, 0x58, 0x22, 0x8f, 0x04, 0x7d, 0x02, 0x3e, 0xe5, 0xb5, 0xcf, 0xc0, 0x0a, 0xf3,\n\t0x37, 0x6a, 0xea, 0x5e, 0x79, 0x87, 0x42, 0x8e, 0xcb, 0x53, 0xb4, 0x62, 0x8d, 0x3e, 0x95, 0x31, 0x3b, 0x5d, 0x2e, 0xa3, 0x25, 0x65, 0xb4, 0x64, 0x19, 0x2d, 0x29, 0xa3, 0x25, 0x65, 0xb4, 0xa4, 0x8c, 0x96, 0x2c, 0xa3, 0x25, 0xcb, 0xf4, 0x2c, 0x46, 0xac, 0x79, 0x9d, 0xb8, 0x6b, 0x79, 0xbe, 0x0e, 0xdc, 0x0b, 0xee, 0x03, 0xf7, 0x83, 0x89, 0x60, 0x12, 0x98, 0x0c, 0xa6, 0x80, 0x07, 0xe4, 0x21, 0x47, 0x27, 0x59, 0xee, 0xe8, 0x0c, 0xba, 0x80, 0xae, 0xa0, 0x1b, 0xe8, 0x0e, 0x7a, 0x80, 0x34, 0xd0, 0x13, 0x9c, 0x0f, 0x2e, 0x00, 0xbd, 0x40, 0x6f, 0x90, 0x0e, 0xfa, 0x80, 0xbe, 0xa0, 0x1f, 0xe8, 0x0f, 0x06, 0x80, 0x81, 0x60, 0x10, 0xc8, 0x00, 0x17, 0x82, 0xc1, 0xe0, 0x22, 0x30, 0x04, 0x5c, 0x4c, 0x7f, 0x0d, 0x05, 0xc3, 0xc0, 0x70, 0x30, 0x02, 0x5c, 0x02, 0x46, 0x82, 0x51, 0x60,\n\t0x34, 0xf8, 0x6f, 0xdd, 0xa7, 0x6e, 0x3a, 0x78, 0x42, 0xdd, 0xaf, 0xee, 0xb0, 0xe3, 0x29, 0xf0, 0x34, 0x78, 0x06, 0xcc, 0x00, 0xcf, 0x82, 0x99, 0xe0, 0x39, 0xf0, 0x3c, 0xf8, 0x17, 0x98, 0x05, 0x66, 0x83, 0x39, 0xe0, 0x05, 0xf0, 0x22, 0x78, 0x09, 0xbc, 0x0c, 0x5e, 0x01, 0x73, 0xc1, 0xeb, 0xb4, 0xe1, 0x0d, 0xf0, 0x26, 0x98, 0x07, 0xe6, 0x83, 0xb7, 0xc0, 0xdb, 0xe0, 0x1d, 0xf0, 0x2e, 0x78, 0x0f, 0xbc, 0x0f, 0x16, 0x80, 0x0f, 0xc0, 0x42, 0xf0, 0x21, 0x58, 0x04, 0x3e, 0x02, 0x8b, 0xc1, 0xc7, 0x60, 0x09, 0xf8, 0x04, 0x7c, 0x0a, 0x96, 0x82, 0xcf, 0x64, 0xb9, 0xf3, 0x25, 0x75, 0x87, 0x9a, 0x1d, 0x44, 0xcf, 0x2e, 0x59, 0xa9, 0x22, 0x6c, 0xaf, 0xf4, 0x13, 0x51, 0xbf, 0x89, 0x62, 0xfe, 0x2f, 0x93, 0xbf, 0xa1, 0x3e, 0x79, 0xa8, 0xcf, 0x0e, 0xf5, 0xbd, 0x64, 0xf5, 0x2c, 0xb8,\n\t0x59, 0xbb, 0x42, 0xee, 0x35, 0xa3, 0x47, 0x84, 0xab, 0x6b, 0x35, 0xee, 0x90, 0x27, 0x89, 0xd5, 0x32, 0xe2, 0xf4, 0x80, 0xba, 0x5e, 0xa3, 0x59, 0x8a, 0x87, 0x4f, 0xef, 0x05, 0x35, 0xd7, 0xf5, 0xf4, 0xca, 0x12, 0xeb, 0xac, 0x70, 0xf3, 0xec, 0xf1, 0xb5, 0x01, 0xbf, 0x81, 0x31, 0x4b, 0x3b, 0xa6, 0xae, 0xe1, 0x68, 0x96, 0xf8, 0x9e, 0xa0, 0x87, 0x05, 0x3d, 0x2c, 0xe8, 0x61, 0x41, 0x0f, 0x0b, 0x7a, 0x58, 0xd0, 0xc3, 0x82, 0x1e, 0x16, 0xf4, 0xb0, 0xa0, 0x87, 0x05, 0x3d, 0x2c, 0xe8, 0x61, 0x41, 0x0f, 0x8b, 0x8b, 0xc1, 0x50, 0x30, 0x0c, 0x0c, 0x07, 0x23, 0xc0, 0x25, 0x60, 0xa4, 0x79, 0x0d, 0x09, 0x30, 0x1a, 0x5c, 0x0a, 0x50, 0x35, 0x71, 0x19, 0xb8, 0x1c, 0x5c, 0x01, 0xae, 0x04, 0x63, 0xc1, 0x55, 0xe0, 0x6a, 0x70, 0x0d, 0xb8, 0x16, 0x3c, 0x02, 0xa6, 0x31, 0xfa, 0x1e, 0x05,\n\t0x8f, 0x81, 0xc7, 0xc1, 0x74, 0xf0, 0x04, 0x78, 0x12, 0x3c, 0x05, 0x9e, 0x06, 0xcf, 0x00, 0x46, 0x82, 0x78, 0x4e, 0x56, 0x89, 0x7f, 0xc9, 0x92, 0x80, 0xf3, 0x0b, 0xb6, 0x6b, 0xe9, 0xd2, 0xa3, 0xf5, 0x61, 0x66, 0xec, 0xcb, 0x73, 0x3f, 0x9e, 0xcd, 0xf3, 0x0d, 0xd4, 0xef, 0xbf, 0x18, 0x85, 0xe3, 0xcc, 0xab, 0xf1, 0x54, 0x9f, 0x6b, 0x60, 0xa3, 0x7c, 0x1b, 0xe5, 0xdb, 0xe6, 0xca, 0x12, 0x1b, 0xbd, 0x68, 0xa3, 0x17, 0x6d, 0xf4, 0xa2, 0x8d, 0x5e, 0xb4, 0xd1, 0x8b, 0x36, 0x7a, 0xd1, 0x46, 0x2f, 0xda, 0xe8, 0x45, 0x1b, 0xbd, 0x68, 0xa3, 0x17, 0x6d, 0x4b, 0xd8, 0xfe, 0x13, 0xf5, 0x4d, 0x58, 0xf5, 0x79, 0x09, 0xdf, 0xc9, 0xf2, 0x90, 0x35, 0x60, 0x0b, 0xd8, 0x0a, 0xb6, 0x81, 0xed, 0x80, 0xd9, 0x24, 0x34, 0x59, 0x56, 0xe8, 0x3e, 0x59, 0xae, 0x1f, 0x02, 0x87, 0x41, 0x39, 0x38,\n\t0x02, 0x2a, 0xc0, 0x51, 0x70, 0x0c, 0xf8, 0x41, 0x25, 0xf8, 0x15, 0x1c, 0x07, 0x27, 0x40, 0x15, 0x38, 0x09, 0x4e, 0x81, 0xdf, 0xc0, 0x69, 0x59, 0x6e, 0xbc, 0x2e, 0x2b, 0x8c, 0x37, 0xc0, 0x9b, 0x60, 0x1e, 0x98, 0x0f, 0xde, 0x02, 0x6f, 0x83, 0x77, 0xc0, 0xbb, 0xe0, 0x3d, 0xf0, 0x3e, 0x58, 0x00, 0x3e, 0x00, 0x0b, 0xc1, 0x87, 0x60, 0x11, 0xf8, 0x08, 0x2c, 0x06, 0x1f, 0x03, 0xda, 0x60, 0xd0, 0x06, 0xe3, 0x53, 0xb0, 0x14, 0x7c, 0x06, 0x96, 0x81, 0xe5, 0xe0, 0xdf, 0x60, 0x05, 0xf8, 0x1c, 0x7c, 0x01, 0xbe, 0x04, 0x5f, 0x81, 0x95, 0xe0, 0x6b, 0xf0, 0x0d, 0xc8, 0x04, 0xff, 0x01, 0xdf, 0x82, 0x55, 0xc0, 0x25, 0xcb, 0x8c, 0x9d, 0x60, 0x97, 0xac, 0x32, 0xf2, 0xc0, 0x6e, 0xe0, 0x01, 0x7b, 0x80, 0x79, 0x2d, 0xa6, 0x7c, 0x50, 0x24, 0x4b, 0x8c, 0x62, 0xb0, 0x1f, 0x94, 0x80, 0x32,\n\t0x70, 0x00, 0xf8, 0xc0, 0x41, 0x70, 0x08, 0x1c, 0xa6, 0x1f, 0x75, 0xe2, 0x79, 0x0f, 0xb1, 0x5b, 0xc6, 0x08, 0xf0, 0x8a, 0x52, 0xf5, 0x1b, 0xb8, 0xea, 0x5e, 0xb5, 0x7a, 0x51, 0xb4, 0x24, 0xea, 0x8f, 0xb3, 0xd5, 0x5e, 0xa2, 0xbe, 0x4a, 0xec, 0x14, 0xf1, 0x44, 0xfd, 0xaf, 0x44, 0xfd, 0x41, 0xe1, 0x11, 0xad, 0xf9, 0x64, 0xbe, 0xc8, 0x17, 0x29, 0x44, 0xfd, 0x51, 0x4a, 0xf8, 0x85, 0xc8, 0x37, 0xc7, 0xd1, 0xaf, 0xea, 0x57, 0x06, 0x3d, 0xc4, 0x28, 0x2d, 0x4d, 0xb4, 0xd7, 0xfa, 0xa8, 0xb3, 0xc5, 0xa3, 0xb4, 0x8b, 0x45, 0x1c, 0x5e, 0xaf, 0x9f, 0x75, 0x6e, 0x6a, 0xaa, 0x76, 0x85, 0xe8, 0xa5, 0x5d, 0x27, 0xba, 0x69, 0xe3, 0x44, 0x37, 0x46, 0x84, 0x39, 0x43, 0x1f, 0x34, 0x7f, 0x31, 0xa0, 0xee, 0xc9, 0x6e, 0xde, 0xc3, 0x3d, 0x5b, 0x7d, 0x8f, 0xef, 0xb3, 0x7e, 0x4b, 0xf7, 0xa3,\n\t0x88, 0xf8, 0x47, 0x35, 0xe9, 0xc1, 0x68, 0xae, 0xfe, 0x65, 0xd0, 0x6b, 0x35, 0xe5, 0xd2, 0xae, 0x6d, 0x35, 0x7b, 0x3c, 0xa3, 0xd4, 0xc4, 0x80, 0x52, 0xdb, 0x58, 0xa5, 0xb6, 0xfd, 0xdb, 0xa5, 0x86, 0xd7, 0x2d, 0x55, 0xdd, 0x9d, 0xab, 0xba, 0x54, 0x55, 0xa2, 0xba, 0xbe, 0xeb, 0xdf, 0x2b, 0xd1, 0x9c, 0xb7, 0xb2, 0x99, 0x69, 0x76, 0x50, 0x82, 0xf9, 0x0b, 0xee, 0x83, 0x7c, 0x7a, 0x37, 0x3d, 0xb6, 0xf5, 0x8f, 0xce, 0x01, 0x41, 0xf9, 0x0e, 0xe3, 0x0c, 0x77, 0x30, 0xc3, 0x79, 0x64, 0x16, 0x9f, 0x32, 0x67, 0x38, 0xb7, 0xba, 0x47, 0xe6, 0x60, 0x35, 0x37, 0xad, 0xe3, 0x13, 0x5b, 0xac, 0x5f, 0x4b, 0x6d, 0xe2, 0x13, 0x95, 0x7c, 0xe2, 0x37, 0x75, 0x46, 0xc5, 0x11, 0xde, 0x59, 0xcb, 0x3b, 0x99, 0xbc, 0xf3, 0x3d, 0xbd, 0x17, 0x4e, 0x4c, 0x44, 0x30, 0xa7, 0x99, 0x7e, 0x2a, 0x9a,\n\t0xba, 0xb6, 0x00, 0xed, 0xe5, 0x31, 0xf3, 0x1b, 0x79, 0x3c, 0xcf, 0x81, 0xa0, 0xa3, 0xe8, 0xe9, 0x49, 0xb9, 0x23, 0x38, 0x44, 0x1e, 0x0a, 0x0e, 0x05, 0x0e, 0xb9, 0xc3, 0xf4, 0x28, 0xc6, 0x2f, 0x68, 0x20, 0x6d, 0x34, 0x4a, 0x41, 0x39, 0x38, 0x02, 0x70, 0xd1, 0xf8, 0x8b, 0x03, 0xf8, 0x8b, 0x03, 0xca, 0x5f, 0xfc, 0x24, 0x8f, 0xa9, 0xf6, 0xed, 0xb7, 0xae, 0x00, 0x7d, 0x84, 0x9a, 0x1e, 0xa3, 0x7d, 0x15, 0xb4, 0x6f, 0x37, 0x35, 0xde, 0x66, 0x9d, 0xc7, 0x64, 0x7a, 0xcc, 0x4d, 0xd4, 0xe9, 0x3b, 0xeb, 0xb7, 0x5d, 0x7b, 0xcd, 0x3b, 0x61, 0x91, 0x01, 0x7e, 0x6f, 0x5e, 0x5f, 0x83, 0x4c, 0xc2, 0xa6, 0x2d, 0x66, 0xa9, 0x08, 0xbe, 0xa2, 0x7a, 0xb1, 0xdd, 0x6d, 0xfb, 0x2a, 0xe8, 0xad, 0xea, 0xc5, 0xfc, 0xbf, 0x55, 0x5e, 0xf0, 0x8b, 0xc1, 0x2b, 0x82, 0xd7, 0x04, 0x57, 0x06, 0x57,\n\t0x86, 0xb4, 0x0c, 0x69, 0x17, 0x72, 0x7e, 0x88, 0x9b, 0x65, 0x93, 0x7a, 0x7c, 0x3e, 0x64, 0x79, 0xf5, 0x5a, 0xeb, 0x7b, 0x42, 0xaa, 0x42, 0x83, 0x43, 0x1d, 0xa1, 0x63, 0xed, 0x95, 0x8e, 0x54, 0x6b, 0x19, 0xec, 0x18, 0x5f, 0xbb, 0x7c, 0x56, 0xbb, 0xec, 0xa8, 0x5d, 0x4e, 0x37, 0x19, 0xd2, 0x64, 0x48, 0x74, 0x8b, 0xe8, 0x0e, 0xd1, 0xb7, 0x46, 0x4f, 0x8e, 0x7e, 0x3e, 0xfa, 0x8d, 0xe8, 0xd5, 0x67, 0x2e, 0x2d, 0xb6, 0xb7, 0xca, 0x6b, 0x95, 0xd7, 0x7a, 0x7c, 0xeb, 0x7b, 0x58, 0xd6, 0xb4, 0xce, 0x6b, 0x5d, 0x94, 0x34, 0x34, 0xe9, 0xee, 0xa4, 0x25, 0xc2, 0x26, 0x1c, 0x8e, 0xe5, 0x8e, 0x9f, 0x85, 0x70, 0xb8, 0xc9, 0xca, 0x92, 0x1d, 0x7b, 0x1c, 0x7b, 0x45, 0x8a, 0xa3, 0xcc, 0xf1, 0x9b, 0x68, 0xeb, 0xcc, 0x70, 0x66, 0x88, 0x3e, 0xce, 0xd9, 0xce, 0x17, 0x44, 0x5f, 0xe7, 0x4b,\n\t0xce, 0x97, 0xc5, 0x00, 0xe7, 0xab, 0xce, 0xd7, 0xc5, 0x20, 0xe7, 0x67, 0xce, 0x55, 0x62, 0xb0, 0x73, 0xa3, 0x73, 0x8b, 0xb8, 0x42, 0x5d, 0x8d, 0xf0, 0x4e, 0x21, 0xe5, 0x57, 0x38, 0xe1, 0x25, 0xd6, 0xd5, 0x08, 0x6f, 0xc3, 0xa3, 0xbf, 0xa6, 0x85, 0x9f, 0x7e, 0x54, 0x4b, 0x95, 0xe7, 0x6b, 0x1d, 0x4f, 0x7f, 0xa5, 0x75, 0x12, 0xb1, 0x5a, 0x67, 0x79, 0x15, 0x7d, 0x3b, 0x58, 0x3b, 0x5f, 0x4e, 0xd3, 0x2e, 0x90, 0x8f, 0x13, 0x05, 0x37, 0x05, 0x6b, 0xb2, 0x73, 0xf0, 0x40, 0x79, 0x51, 0xf0, 0x88, 0xd3, 0xd7, 0x06, 0x8f, 0x94, 0x69, 0xc1, 0xa3, 0xe5, 0x6c, 0x7c, 0x7b, 0x9c, 0xfd, 0x66, 0xd9, 0xca, 0x7e, 0x40, 0x8e, 0xd0, 0x87, 0xe2, 0x88, 0xaa, 0xaf, 0x46, 0xd8, 0x1d, 0x17, 0x29, 0x70, 0x91, 0x76, 0xeb, 0x6a, 0x84, 0xad, 0x8c, 0x07, 0x4f, 0x1f, 0x37, 0x5e, 0x38, 0x9d, 0x67,\n\t0x64, 0xc9, 0xb1, 0x8e, 0xd7, 0x64, 0x27, 0x7a, 0x73, 0xb2, 0x23, 0x47, 0x8e, 0xa4, 0x47, 0x6f, 0xb0, 0xae, 0x46, 0xb8, 0xc9, 0xf9, 0xad, 0xec, 0xe6, 0x5c, 0x75, 0xfa, 0xb8, 0x68, 0x6a, 0x5d, 0x8f, 0x69, 0x11, 0xb5, 0x5b, 0x4a, 0xed, 0xd6, 0x58, 0xd7, 0x63, 0x7a, 0x89, 0x5a, 0x2d, 0x0c, 0x5a, 0x89, 0x6f, 0x5e, 0x25, 0x4f, 0x50, 0x9b, 0x67, 0xd9, 0xfb, 0xb7, 0xec, 0xe1, 0x14, 0x7b, 0xd0, 0xac, 0xeb, 0x32, 0xad, 0xb3, 0xae, 0xcb, 0x94, 0xeb, 0x30, 0xef, 0x8f, 0x16, 0x47, 0x7b, 0x2b, 0xb5, 0x10, 0xdc, 0x7d, 0xf5, 0x75, 0x86, 0x4b, 0x29, 0xed, 0xa8, 0xba, 0x13, 0x64, 0x2a, 0x59, 0x5d, 0x47, 0x62, 0xc5, 0xfc, 0x35, 0xef, 0x18, 0x70, 0xb9, 0xac, 0xa0, 0xe4, 0xe3, 0x94, 0x7c, 0x3c, 0xc8, 0xad, 0xee, 0x8e, 0x58, 0x4e, 0x74, 0x96, 0xd3, 0xde, 0x23, 0xd6, 0x1d, 0x10, 0xab,\n\t0xc8, 0x53, 0x36, 0xd3, 0xee, 0xfd, 0xb4, 0xfb, 0x67, 0xf6, 0x5c, 0x11, 0x70, 0xed, 0xe1, 0xfd, 0xb4, 0xff, 0x04, 0x35, 0xc8, 0xa7, 0x06, 0x07, 0xa9, 0x81, 0x4f, 0xb5, 0xa1, 0x01, 0x6d, 0x58, 0x68, 0xb5, 0xe1, 0x3b, 0x95, 0xfb, 0xa5, 0xca, 0x17, 0xd9, 0xe3, 0x07, 0x01, 0x6d, 0x98, 0x59, 0xdd, 0x06, 0x11, 0x44, 0x1b, 0x82, 0x29, 0xe1, 0xa8, 0xd5, 0x86, 0x2f, 0x69, 0xc3, 0x0e, 0xd5, 0x86, 0xff, 0x37, 0xae, 0x18, 0xde, 0x91, 0x9e, 0x9a, 0x02, 0x5f, 0x1b, 0xe9, 0xa9, 0x1f, 0xe0, 0x6c, 0x3e, 0x9c, 0x7d, 0x4a, 0x54, 0xfa, 0xe1, 0x6c, 0x1d, 0x3d, 0x75, 0x21, 0xbc, 0xad, 0x45, 0x25, 0xec, 0xb4, 0xe6, 0x0a, 0xa2, 0x72, 0x2b, 0x51, 0x99, 0x4d, 0xab, 0xee, 0xb5, 0x7e, 0xe7, 0x61, 0xfe, 0xa2, 0x3c, 0xda, 0xfc, 0x45, 0x39, 0x9c, 0xfe, 0x87, 0x5e, 0x9b, 0xa6, 0x7a, 0x6d, 0xc4,\n\t0x69, 0x37, 0x3d, 0xb6, 0x80, 0x1e, 0xdb, 0x04, 0xcf, 0x97, 0x06, 0xbf, 0x24, 0xf4, 0xea, 0xeb, 0xfc, 0x08, 0x3b, 0xbd, 0x36, 0x52, 0x5d, 0xeb, 0x67, 0xa8, 0xcc, 0x23, 0x6a, 0x9f, 0x24, 0x6a, 0xa7, 0x12, 0xb5, 0x57, 0x12, 0xb5, 0xe3, 0xe9, 0x8f, 0x3e, 0xf4, 0x47, 0x57, 0x72, 0x9e, 0x91, 0xf4, 0xc9, 0xe5, 0xf4, 0xc9, 0xfb, 0xf4, 0xc9, 0xd3, 0x44, 0xed, 0x0a, 0x22, 0xf6, 0x7d, 0xc7, 0x0e, 0xe1, 0x24, 0x5a, 0xa7, 0x90, 0xd3, 0x8c, 0xfc, 0xff, 0x71, 0x8d, 0x7b, 0x9d, 0x36, 0x3f, 0x64, 0x5d, 0x1b, 0x74, 0x35, 0xa5, 0x3c, 0x4f, 0x7b, 0xf7, 0x52, 0xc2, 0x6c, 0x4a, 0x18, 0x48, 0x5d, 0x2e, 0x51, 0xba, 0xb6, 0xad, 0x66, 0x1e, 0x13, 0x0d, 0xd8, 0x4b, 0x26, 0x7b, 0x79, 0x46, 0xdd, 0x63, 0xb4, 0xa7, 0x7c, 0x81, 0xf6, 0xcf, 0x67, 0xb6, 0xab, 0x64, 0xab, 0x92, 0x9a, 0x5f, 0x7b,\n\t0xb3, 0xc7, 0x47, 0xcc, 0x3d, 0x99, 0xd9, 0x34, 0x7b, 0x3b, 0x29, 0x0c, 0x4a, 0x2e, 0xe7, 0x93, 0x3b, 0xd9, 0xd2, 0x55, 0x93, 0x2b, 0xb3, 0x45, 0xbe, 0x75, 0x74, 0xc5, 0x43, 0x5d, 0x4e, 0xd4, 0xee, 0x69, 0x0d, 0xef, 0x6e, 0xac, 0xfd, 0x6f, 0xad, 0xd2, 0xd3, 0x70, 0xeb, 0x37, 0xb8, 0xe6, 0x1c, 0x7e, 0x82, 0x96, 0x55, 0x5a, 0xbf, 0xa2, 0xdd, 0x62, 0x9d, 0x31, 0xba, 0x2d, 0x60, 0xa6, 0xdd, 0x65, 0x9d, 0x17, 0x77, 0x82, 0x7a, 0x1c, 0xa1, 0xe5, 0x7e, 0x5a, 0x7e, 0x04, 0x57, 0x96, 0x8b, 0x2b, 0xcb, 0xb5, 0xce, 0x8b, 0x3b, 0x70, 0xd6, 0x3a, 0xed, 0x3a, 0xa3, 0x4e, 0xa1, 0x81, 0xc7, 0x82, 0x88, 0x54, 0x73, 0xc4, 0x6d, 0x37, 0x23, 0xb5, 0xde, 0x99, 0xfc, 0x7f, 0x7e, 0xfc, 0xc8, 0x46, 0x0b, 0x4c, 0x56, 0xab, 0x7f, 0x8b, 0x79, 0xf4, 0xbf, 0x7c, 0xde, 0xeb, 0x6d, 0xa2, 0x0d,\n\t0xa3, 0x2f, 0x9b, 0xfd, 0x6c, 0x91, 0x39, 0xe4, 0xac, 0x65, 0x96, 0x42, 0xed, 0xb0, 0xd4, 0xc9, 0xbc, 0xa3, 0xe6, 0x21, 0xfa, 0xfa, 0x6b, 0x66, 0xa2, 0xd7, 0xa9, 0xc9, 0xb7, 0x70, 0x59, 0xaa, 0x3d, 0x48, 0xa9, 0x0f, 0xcb, 0x65, 0xda, 0x6c, 0xb9, 0xce, 0xbc, 0xd6, 0x67, 0xd0, 0x3a, 0xf9, 0x86, 0x79, 0x3f, 0x58, 0xf8, 0xf3, 0xc3, 0x9f, 0x9f, 0x3d, 0x2d, 0x63, 0x4f, 0xcb, 0xcc, 0xab, 0x6d, 0xda, 0x87, 0x89, 0x44, 0xfb, 0x70, 0xd1, 0xc1, 0x3e, 0x92, 0xe7, 0x51, 0xa2, 0x9b, 0x7d, 0x2c, 0xcf, 0x57, 0xf1, 0xff, 0xb5, 0x3c, 0xe3, 0x8c, 0x88, 0xe5, 0x02, 0xfb, 0x3c, 0xd6, 0xe7, 0x8b, 0xed, 0xf6, 0xb7, 0xc4, 0x7e, 0xfb, 0xdb, 0xac, 0xbf, 0x23, 0x76, 0xda, 0xdf, 0x15, 0xa5, 0xf6, 0xf7, 0x45, 0x13, 0xfb, 0x17, 0xfc, 0xff, 0x25, 0xef, 0x7d, 0xc5, 0x7b, 0x2b, 0xc5, 0x35, 0xf6,\n\t0xaf, 0xf9, 0xff, 0x1b, 0xde, 0xcf, 0xe4, 0xfd, 0xff, 0xf0, 0xff, 0x2a, 0x11, 0x6b, 0xff, 0x8e, 0xd7, 0xd6, 0xb0, 0xcd, 0x5a, 0xb6, 0xf9, 0x9e, 0xd7, 0x7e, 0xe0, 0xff, 0x75, 0x6c, 0xb3, 0x9e, 0x6d, 0xb2, 0xf8, 0x7f, 0xb7, 0x38, 0xcf, 0xee, 0x11, 0xbf, 0xd8, 0xf7, 0x88, 0x4a, 0xfb, 0x5e, 0x71, 0x9b, 0x3d, 0x9f, 0xff, 0x7f, 0x11, 0x25, 0xf6, 0x02, 0x71, 0xc2, 0xbe, 0x8f, 0xff, 0x0b, 0x45, 0x98, 0xbd, 0x48, 0xb4, 0x66, 0x4c, 0xcd, 0xd5, 0x3b, 0x88, 0xa5, 0xfa, 0x79, 0xe2, 0x7b, 0xbd, 0x93, 0xf8, 0x48, 0xef, 0x2c, 0xbe, 0xd1, 0xbb, 0x0a, 0x3b, 0x33, 0xc0, 0x0c, 0x66, 0x80, 0xed, 0xfa, 0x13, 0xa2, 0xa9, 0x3e, 0x53, 0x24, 0xea, 0xcf, 0x69, 0xa3, 0xf5, 0xe7, 0xb5, 0x61, 0xfa, 0xbf, 0xc4, 0xeb, 0xfa, 0x2c, 0x11, 0xa5, 0xcf, 0x16, 0x4d, 0x98, 0x0d, 0xfc, 0x8e, 0x58, 0xf1,\n\t0x82, 0x23, 0x4e, 0xcc, 0x73, 0xc4, 0x8b, 0x04, 0x47, 0x22, 0xeb, 0xad, 0xc4, 0xfb, 0x8e, 0xd6, 0xac, 0xa7, 0xb2, 0xde, 0x96, 0xd7, 0xdb, 0xb1, 0xde, 0x81, 0xf5, 0xf3, 0x78, 0xbd, 0xa3, 0x48, 0xa0, 0x07, 0x46, 0x38, 0x3f, 0x93, 0x55, 0xce, 0xe5, 0xda, 0x00, 0xe7, 0xbf, 0xb5, 0x11, 0xce, 0x15, 0x62, 0xa6, 0xf3, 0x73, 0x11, 0xed, 0xfc, 0x42, 0x44, 0x3a, 0x57, 0x8a, 0xae, 0x62, 0x96, 0x08, 0x92, 0x4b, 0x45, 0x30, 0x08, 0x91, 0x2f, 0x8a, 0x66, 0xf2, 0x01, 0x91, 0x24, 0xb7, 0xd2, 0x63, 0x79, 0xa2, 0x1d, 0x73, 0x67, 0x7b, 0xdc, 0xce, 0x46, 0xb9, 0x9c, 0xf9, 0x75, 0xa9, 0xba, 0x4f, 0x37, 0xf9, 0x02, 0x3d, 0x78, 0x94, 0xde, 0x9a, 0x2d, 0x8e, 0x31, 0xfb, 0x1e, 0x97, 0x2f, 0x88, 0x13, 0xe0, 0x37, 0xa2, 0xdf, 0x06, 0x42, 0xc8, 0xd0, 0xc2, 0x88, 0xfe, 0x06, 0x72, 0xab, 0xed,\n\t0x6a, 0x99, 0x65, 0xbb, 0x5d, 0x66, 0x05, 0x65, 0xca, 0x9f, 0x83, 0x56, 0xcb, 0xad, 0x41, 0x3f, 0x80, 0x75, 0x72, 0x63, 0xd0, 0x7a, 0x59, 0x1e, 0x94, 0xc5, 0xfa, 0x06, 0x32, 0xb8, 0x8d, 0x60, 0x8b, 0x7c, 0x21, 0x68, 0x3b, 0xcf, 0x3f, 0xe1, 0x80, 0x98, 0xaf, 0xd5, 0x75, 0xd9, 0x77, 0xc9, 0xaf, 0x82, 0xf2, 0xc0, 0x1e, 0xf9, 0x82, 0xbd, 0xbd, 0x5c, 0x6a, 0xef, 0x00, 0xce, 0x03, 0x1d, 0x41, 0x27, 0xd0, 0x19, 0x74, 0x01, 0x5d, 0x41, 0x37, 0xd0, 0x1d, 0xf4, 0x00, 0x69, 0xf2, 0x33, 0x7b, 0x4f, 0x9e, 0xcf, 0x07, 0x17, 0x80, 0x5e, 0xa0, 0x37, 0x48, 0x07, 0x7d, 0x40, 0x5f, 0xd0, 0x0f, 0xf4, 0x07, 0x03, 0xc0, 0x40, 0x30, 0x08, 0x64, 0x80, 0x0b, 0xc1, 0x60, 0x70, 0x11, 0x18, 0x02, 0x86, 0x82, 0x61, 0xb2, 0x90, 0x79, 0xbe, 0x90, 0x79, 0x7e, 0x29, 0xf3, 0xfc, 0x52, 0xe6, 0xf9,\n\t0x42, 0xe6, 0xf9, 0x42, 0xe6, 0xf9, 0xa5, 0xcc, 0xf3, 0x4b, 0x99, 0xe7, 0x97, 0x32, 0xcf, 0x2f, 0x65, 0x9e, 0x5f, 0xca, 0x3c, 0xbf, 0x94, 0x79, 0x7e, 0x29, 0xf3, 0x7c, 0x21, 0xf3, 0x7c, 0x21, 0xf3, 0xfc, 0x52, 0xe6, 0xf9, 0xa5, 0xcc, 0xf3, 0x85, 0xcc, 0xf3, 0x85, 0xcc, 0xf3, 0x4b, 0xed, 0xd7, 0x53, 0xbf, 0xf1, 0xe0, 0x06, 0xd6, 0x6f, 0x94, 0x2f, 0xda, 0x6f, 0x02, 0x37, 0xcb, 0x97, 0xec, 0x65, 0xf2, 0x01, 0x22, 0xe3, 0x01, 0xbb, 0x4f, 0x3e, 0xa0, 0x8f, 0x92, 0x5b, 0xf5, 0xd1, 0xe0, 0x52, 0x30, 0x06, 0x5c, 0x06, 0xae, 0x00, 0x57, 0x82, 0xb1, 0xe0, 0x2a, 0x30, 0x95, 0xfc, 0xea, 0x21, 0xf0, 0x30, 0x20, 0xf7, 0xd4, 0xa7, 0xc9, 0x2c, 0xfd, 0x51, 0xf0, 0x18, 0x78, 0x1c, 0x4c, 0x07, 0x4f, 0xc8, 0x02, 0xfd, 0x49, 0x9e, 0x9f, 0x02, 0x4f, 0x83, 0x67, 0xc0, 0x0c, 0xf0, 0x2c,\n\t0x98, 0xc9, 0x7b, 0xb3, 0xc0, 0x6c, 0x30, 0x87, 0xff, 0x5f, 0x00, 0x2f, 0xca, 0x8d, 0x8e, 0x7f, 0xcb, 0x9f, 0x1d, 0x2b, 0x40, 0xa6, 0x3c, 0xe6, 0xf8, 0x0f, 0xf8, 0x16, 0xac, 0x02, 0xab, 0xe5, 0x31, 0xe7, 0x6c, 0x59, 0xe9, 0x9c, 0x83, 0xcb, 0x36, 0x7f, 0x8f, 0x53, 0xc1, 0xfc, 0xfa, 0x06, 0x3a, 0xe3, 0x45, 0x67, 0xbc, 0xcc, 0xb3, 0x4b, 0xb4, 0xeb, 0x99, 0xd5, 0x6f, 0xe6, 0xbd, 0xd0, 0x73, 0xbd, 0xab, 0xee, 0xfe, 0xf0, 0x29, 0x1a, 0x65, 0xf0, 0xee, 0x2d, 0xbc, 0xfb, 0x09, 0xef, 0x2e, 0xe2, 0xdd, 0x49, 0xd6, 0xf9, 0xb8, 0xcd, 0xac, 0xf3, 0xf4, 0xc2, 0xc9, 0x68, 0x1c, 0x7c, 0x62, 0x95, 0x76, 0x03, 0x73, 0xe6, 0x4d, 0xe0, 0x66, 0xd1, 0x19, 0x6d, 0x6a, 0x68, 0xdd, 0xa1, 0x32, 0x0c, 0xdd, 0x5f, 0x23, 0x0c, 0x4a, 0xdb, 0x60, 0xfe, 0x12, 0x5b, 0xcc, 0xe1, 0x13, 0x3d, 0xe5,\n\t0xcf, 0x94, 0xf4, 0x83, 0xe5, 0x55, 0x98, 0x51, 0x85, 0x23, 0xa4, 0x87, 0x70, 0xb0, 0x98, 0x57, 0x6e, 0x9e, 0x8d, 0xdf, 0x98, 0x83, 0xf7, 0xee, 0xc9, 0x8c, 0x36, 0xd8, 0xfc, 0xdd, 0x81, 0x3c, 0x6c, 0x3a, 0x1a, 0xf3, 0x77, 0xd9, 0x35, 0x67, 0x0e, 0x6b, 0x2f, 0xb3, 0xe5, 0x66, 0x71, 0x9e, 0x7c, 0x5c, 0x74, 0x04, 0x9d, 0x40, 0x17, 0x14, 0xb7, 0x2b, 0xe8, 0x06, 0xba, 0x83, 0x1e, 0x20, 0x0d, 0xf4, 0x94, 0xe3, 0xc4, 0xf9, 0xe0, 0x02, 0xd0, 0x9b, 0xff, 0xd3, 0x41, 0x1f, 0xe9, 0x11, 0xe4, 0xed, 0xa2, 0x1f, 0xe8, 0x0f, 0x06, 0x80, 0x81, 0x60, 0x10, 0xc8, 0x00, 0x17, 0x82, 0xc1, 0xe0, 0x22, 0x30, 0x04, 0x5c, 0x0c, 0x86, 0x82, 0x61, 0x60, 0x38, 0x18, 0x01, 0x2e, 0x01, 0x23, 0xc1, 0x28, 0x30, 0x1a, 0x5c, 0x0a, 0xc6, 0x80, 0xcb, 0xc0, 0xe5, 0xe0, 0x0a, 0x70, 0x25, 0x18, 0x0b,\n\t0xae, 0x02, 0x57, 0x83, 0x6b, 0xc0, 0xb5, 0xe0, 0x3a, 0xf9, 0xb4, 0x18, 0x27, 0x1f, 0x13, 0x77, 0xc8, 0x95, 0xe2, 0x6e, 0x30, 0x01, 0xdc, 0x03, 0xee, 0xa5, 0x6e, 0xf7, 0x81, 0xfb, 0xc1, 0x44, 0xfe, 0x9f, 0x4c, 0x9d, 0xa7, 0xf0, 0xfc, 0x80, 0x7c, 0x4e, 0x3c, 0x08, 0xa6, 0x82, 0x87, 0xc0, 0x23, 0x94, 0x31, 0x8d, 0x7c, 0xe8, 0x51, 0xf0, 0x18, 0x78, 0x1c, 0x4c, 0x07, 0x4f, 0x80, 0x27, 0xc1, 0x53, 0xe0, 0x69, 0xf0, 0x0c, 0x98, 0x01, 0xfb, 0xcf, 0x82, 0x99, 0x72, 0x9f, 0x78, 0x4e, 0x16, 0x8a, 0xe7, 0x99, 0x2f, 0xfe, 0xc5, 0xfa, 0x2c, 0x75, 0x65, 0x81, 0xce, 0xf4, 0xec, 0x4e, 0x7a, 0x76, 0x8b, 0xd6, 0x4b, 0xa6, 0x6a, 0xbd, 0x41, 0x7f, 0xd9, 0x45, 0x1b, 0x00, 0x06, 0xe2, 0x9f, 0x07, 0xc9, 0xeb, 0xb4, 0x0c, 0x9e, 0x2f, 0xe4, 0x79, 0xb0, 0x7c, 0x58, 0x1b, 0x2a, 0xfb, 0x6b,\n\t0xc3, 0xc1, 0xf5, 0xea, 0x5e, 0x3e, 0xd5, 0xd7, 0x59, 0xf6, 0xca, 0x29, 0x5a, 0xa9, 0x5c, 0x63, 0x9b, 0x24, 0xa7, 0xd8, 0xa8, 0xaf, 0x6d, 0xaa, 0x5c, 0x69, 0x9b, 0x06, 0xa8, 0x97, 0x8d, 0x7a, 0xd9, 0x9e, 0x40, 0x11, 0x66, 0xc8, 0xa7, 0x6d, 0x33, 0x79, 0xef, 0x79, 0xd6, 0x5f, 0x94, 0xcf, 0xd9, 0x5e, 0x61, 0x7d, 0xae, 0xdc, 0x67, 0x9b, 0xcf, 0xff, 0xef, 0x49, 0x8f, 0xed, 0x7d, 0xb0, 0x00, 0x7c, 0x00, 0x16, 0x82, 0x0f, 0xc1, 0x22, 0xf0, 0x11, 0x58, 0x0c, 0x3e, 0x06, 0x4b, 0x28, 0xeb, 0x13, 0x59, 0x14, 0x0c, 0x6f, 0xc1, 0x4f, 0xc9, 0x37, 0x83, 0x9f, 0x01, 0x33, 0xe4, 0x77, 0xc1, 0x33, 0xe5, 0x77, 0x21, 0xdf, 0x49, 0x4f, 0xc8, 0x1a, 0xb0, 0x05, 0x6c, 0x05, 0xdb, 0xc0, 0x76, 0x90, 0x03, 0x0a, 0xe4, 0x94, 0x90, 0x12, 0x39, 0x2e, 0xc4, 0x27, 0xd7, 0x84, 0xb6, 0x96, 0x2b,\n\t0x43, 0x93, 0x65, 0x51, 0xe8, 0x09, 0x39, 0x45, 0x7f, 0x43, 0x3e, 0xae, 0xbf, 0x09, 0xe6, 0x81, 0xf9, 0xc0, 0xbc, 0xfe, 0xf3, 0xdb, 0xea, 0x1a, 0xd0, 0x8f, 0xeb, 0xef, 0x82, 0xf7, 0xc0, 0x02, 0xf0, 0x01, 0x58, 0x08, 0x3e, 0x04, 0x8b, 0xc0, 0x47, 0x60, 0x31, 0xf8, 0x18, 0x2c, 0x01, 0x9f, 0x80, 0x4f, 0xc1, 0x52, 0xf0, 0x19, 0x58, 0x06, 0x96, 0x83, 0x7f, 0x83, 0x15, 0xe0, 0x2b, 0xb0, 0x12, 0x7c, 0x0d, 0xbe, 0x01, 0x99, 0x60, 0x0d, 0xfb, 0x5f, 0x0b, 0xbe, 0x07, 0x3f, 0x80, 0x0d, 0x60, 0xa3, 0x1c, 0xa7, 0xff, 0x08, 0x36, 0x81, 0x6c, 0xb0, 0x15, 0x6c, 0xe3, 0xf5, 0xed, 0x20, 0x07, 0xe4, 0x82, 0x9f, 0xc0, 0x0e, 0xf0, 0x33, 0x70, 0x81, 0x3c, 0xb0, 0x1b, 0x78, 0xc0, 0x1e, 0xb0, 0x17, 0xe4, 0x83, 0x5f, 0x00, 0xed, 0xd6, 0xf7, 0x81, 0x22, 0x50, 0x0c, 0xf6, 0x83, 0x12, 0x40,\n\t0x7f, 0xe9, 0x65, 0xe0, 0x00, 0xf0, 0x49, 0x8f, 0x7e, 0x08, 0x1c, 0x06, 0xe5, 0xe0, 0x08, 0xa8, 0x00, 0x47, 0xc1, 0x31, 0xe0, 0x07, 0x95, 0xe0, 0x57, 0x70, 0x1c, 0x9c, 0x00, 0x55, 0xe0, 0x24, 0x38, 0x05, 0x7e, 0x03, 0xa7, 0x81, 0x94, 0x4f, 0x1b, 0x02, 0x68, 0xc0, 0x06, 0x82, 0x40, 0x30, 0x08, 0x01, 0xa1, 0xf2, 0x31, 0xc3, 0x0e, 0x74, 0x60, 0x80, 0x06, 0xa0, 0x21, 0x68, 0x04, 0x32, 0xe4, 0x4a, 0xe3, 0x42, 0x30, 0x18, 0x5c, 0x0c, 0x86, 0x82, 0x61, 0x60, 0x38, 0x18, 0x01, 0x2e, 0x01, 0x23, 0xc1, 0x28, 0x30, 0x1a, 0x8c, 0x01, 0x97, 0xc9, 0x29, 0xc6, 0xe5, 0xe0, 0x0a, 0x70, 0x25, 0x18, 0x0b, 0xae, 0x02, 0x57, 0x83, 0x6b, 0xc0, 0xf5, 0x60, 0x3c, 0xb8, 0x01, 0xdc, 0x08, 0x6e, 0x02, 0x37, 0x83, 0x5b, 0xc0, 0xad, 0xe0, 0x36, 0x70, 0x3b, 0xb8, 0x03, 0xdc, 0x09, 0xee, 0x02,\n\t0x77, 0x83, 0x09, 0xe0, 0x1e, 0x30, 0x15, 0x3c, 0x04, 0x1e, 0x06, 0xc4, 0xb1, 0xf1, 0x28, 0x78, 0x02, 0x3c, 0x09, 0x9e, 0x02, 0x4f, 0x83, 0x67, 0xc0, 0x0c, 0xf0, 0x2c, 0x78, 0x0e, 0x3c, 0x0f, 0xfe, 0x25, 0x9f, 0x33, 0x66, 0x81, 0xd9, 0x60, 0x0e, 0x20, 0xce, 0x8d, 0x97, 0xc0, 0xcb, 0xe0, 0x15, 0x30, 0x17, 0xbc, 0x8e, 0x5f, 0x7e, 0x03, 0xbc, 0x09, 0xe6, 0x81, 0xf9, 0xe0, 0x2d, 0xf0, 0x36, 0x78, 0x07, 0xbc, 0x0b, 0xde, 0x03, 0xef, 0x83, 0x05, 0xe0, 0x03, 0xb0, 0x10, 0x7c, 0x08, 0x16, 0x81, 0x8f, 0xc0, 0x62, 0xf0, 0x31, 0x60, 0x3c, 0x18, 0x8c, 0x07, 0xe3, 0x53, 0xb0, 0x14, 0x7c, 0x06, 0x96, 0x81, 0xe5, 0xe0, 0xdf, 0x60, 0x05, 0xf8, 0x1c, 0x7c, 0x01, 0xbe, 0x04, 0x5f, 0x81, 0x95, 0xe0, 0x6b, 0xf0, 0x0d, 0xc8, 0x04, 0xff, 0x01, 0xdf, 0x82, 0x55, 0x60, 0xb5, 0x5c, 0x63,\n\t0x7c, 0x07, 0xd6, 0x80, 0xb5, 0xe0, 0x7b, 0xf0, 0x03, 0x58, 0x07, 0xd6, 0x83, 0x0d, 0x60, 0x23, 0xf8, 0x11, 0x6c, 0x02, 0xd9, 0x60, 0x33, 0xd8, 0x02, 0xb6, 0x82, 0x6d, 0x60, 0x3b, 0xc8, 0x01, 0xb9, 0x60, 0x07, 0xf8, 0x19, 0xb8, 0xe4, 0x3e, 0x63, 0x27, 0xd8, 0x25, 0x0b, 0x8d, 0x3c, 0xb0, 0x1b, 0x78, 0xc0, 0x1e, 0xb0, 0x17, 0xe4, 0x83, 0x02, 0xf2, 0xea, 0x7d, 0xa0, 0x88, 0xed, 0x8a, 0xc1, 0x7e, 0x50, 0x02, 0xca, 0xc0, 0x01, 0xe0, 0x03, 0x07, 0xc1, 0x21, 0x70, 0x18, 0x1c, 0x95, 0xeb, 0xcc, 0xeb, 0xa5, 0x1b, 0x7e, 0x50, 0x09, 0x7e, 0x05, 0xc7, 0xc9, 0x34, 0xdd, 0x72, 0xa5, 0x63, 0x8f, 0xec, 0xef, 0x38, 0x26, 0xa7, 0x38, 0xfc, 0xa0, 0x12, 0xfc, 0x0a, 0x8e, 0x83, 0x13, 0x72, 0x8d, 0xa3, 0x0a, 0x9c, 0x04, 0xa7, 0xc0, 0x6f, 0x72, 0x8d, 0x93, 0x71, 0xa6, 0x1d, 0xc3, 0x51,\n\t0x15, 0xe1, 0xa8, 0x8a, 0x70, 0x53, 0xbf, 0x8a, 0x54, 0xfc, 0x6e, 0x5b, 0x79, 0x1c, 0x37, 0x75, 0x0a, 0x37, 0x55, 0x82, 0xc2, 0xf8, 0x50, 0x18, 0x1f, 0x0a, 0xe3, 0x13, 0x9d, 0x41, 0x17, 0xe9, 0x47, 0x65, 0xfc, 0xa8, 0x8c, 0x1f, 0x95, 0xf1, 0xa3, 0x32, 0x7e, 0x54, 0xc6, 0x8f, 0xca, 0x54, 0xa2, 0x32, 0x95, 0xa8, 0x4c, 0x25, 0x2a, 0xe3, 0x47, 0x65, 0xfc, 0xa8, 0x4c, 0x16, 0x2a, 0x93, 0x85, 0xca, 0x64, 0xa1, 0x32, 0x59, 0xa8, 0x4c, 0x16, 0x2a, 0x93, 0x85, 0xca, 0x64, 0xa1, 0x32, 0x59, 0xa8, 0x4c, 0x16, 0x2a, 0x93, 0x85, 0xca, 0x64, 0xa1, 0x32, 0x59, 0xa8, 0x4c, 0x16, 0x2a, 0x93, 0x85, 0xca, 0x64, 0xa1, 0x32, 0x59, 0xa8, 0x4c, 0x16, 0x2a, 0x93, 0x85, 0xca, 0x64, 0xa1, 0x32, 0x59, 0xa8, 0x4c, 0x16, 0x2a, 0x93, 0x85, 0xca, 0x64, 0xa1, 0x32, 0x59, 0xa8, 0x4c, 0x16, 0x2a,\n\t0x93, 0x85, 0xca, 0x64, 0xa1, 0x32, 0x59, 0xa8, 0x4c, 0x16, 0x2a, 0x83, 0xbb, 0x05, 0xd7, 0x02, 0x5c, 0x0c, 0x2a, 0x53, 0x29, 0xae, 0xa7, 0xde, 0xe3, 0xc1, 0x0d, 0xe0, 0x46, 0x5c, 0xe1, 0x4d, 0xe0, 0x66, 0x70, 0x2b, 0xb8, 0x0d, 0xdc, 0xce, 0xeb, 0x77, 0xc8, 0x52, 0x71, 0x27, 0xcf, 0x77, 0x81, 0xbb, 0x59, 0x9f, 0x00, 0xee, 0x01, 0xf7, 0xd2, 0x8e, 0xfb, 0xc0, 0xfd, 0x60, 0x22, 0xff, 0x4f, 0xe2, 0xfd, 0xc9, 0x94, 0x39, 0x85, 0xf5, 0x07, 0x70, 0x09, 0x0f, 0x82, 0xa9, 0xe0, 0x21, 0xf0, 0x30, 0xef, 0x3d, 0xc2, 0x7e, 0xa7, 0xc9, 0x6c, 0x94, 0x29, 0x1b, 0x65, 0xca, 0x46, 0x99, 0xb2, 0x51, 0xa6, 0x6c, 0x94, 0x29, 0x1b, 0x65, 0xca, 0x46, 0x99, 0xb2, 0x51, 0xa6, 0x6c, 0x94, 0x29, 0x1b, 0x65, 0xf2, 0xa1, 0x4c, 0x3e, 0x94, 0x29, 0x0b, 0x65, 0xca, 0x43, 0x99, 0x56, 0xa2, 0x4c,\n\t0x6b, 0x51, 0xa6, 0xcd, 0xa8, 0x8a, 0x1f, 0x55, 0xf1, 0xe1, 0x4a, 0x4b, 0x70, 0xa5, 0x25, 0xb6, 0xfb, 0x58, 0xbf, 0x1f, 0x4c, 0x92, 0x7e, 0x54, 0xa6, 0x12, 0x95, 0x29, 0xb5, 0x3d, 0xc4, 0xff, 0xd3, 0x78, 0x66, 0x3f, 0x28, 0x4d, 0x36, 0x4a, 0xb3, 0x19, 0xa5, 0x29, 0x44, 0x69, 0x2a, 0x51, 0x9a, 0xcd, 0x28, 0xcd, 0x7e, 0x94, 0xa6, 0x12, 0xa5, 0x59, 0x6b, 0x7b, 0x93, 0x6d, 0xe7, 0x81, 0xf9, 0xbc, 0xfe, 0x1e, 0x4e, 0xf7, 0x7d, 0xb0, 0x00, 0x7c, 0x00, 0x16, 0x82, 0x0f, 0xc1, 0x22, 0xf0, 0x11, 0x58, 0x0c, 0x3e, 0x06, 0x4b, 0x28, 0xf3, 0x13, 0x99, 0x8d, 0xe2, 0x54, 0x06, 0x4f, 0x96, 0xbe, 0x90, 0x70, 0xf0, 0x9d, 0xcc, 0x42, 0x69, 0xb2, 0x42, 0x7e, 0xc0, 0xb5, 0x6c, 0xe1, 0x79, 0x2b, 0xd8, 0x06, 0xb6, 0x83, 0x1c, 0x50, 0x40, 0xae, 0x53, 0x22, 0x2b, 0x51, 0x1b, 0x1f, 0x6a,\n\t0x53, 0x1a, 0x9a, 0xc4, 0x73, 0xb2, 0xcc, 0x46, 0x71, 0xfc, 0x38, 0xe3, 0x22, 0x9c, 0x71, 0x11, 0xce, 0xb8, 0x08, 0x67, 0x5c, 0x84, 0x33, 0x2e, 0xc2, 0x19, 0x17, 0xe1, 0x8c, 0x8b, 0x70, 0xc6, 0x45, 0x38, 0xe3, 0x22, 0xdc, 0x70, 0x11, 0x6e, 0xb8, 0x08, 0x37, 0x5c, 0x84, 0x1b, 0x2e, 0xc2, 0x0d, 0x17, 0xe1, 0x86, 0x8b, 0x70, 0xc3, 0x45, 0xb8, 0xe1, 0x22, 0xdc, 0x70, 0x11, 0x6e, 0xb8, 0x08, 0x37, 0x5c, 0x84, 0x1b, 0x2e, 0xc2, 0x0d, 0x17, 0xe1, 0x86, 0x8b, 0x70, 0xc3, 0x45, 0xb8, 0xe1, 0x22, 0xdc, 0x70, 0x11, 0x6e, 0xb8, 0x08, 0xc7, 0x5a, 0x84, 0x4b, 0xfd, 0x15, 0x87, 0xfa, 0xab, 0x7e, 0x9f, 0x2c, 0xd3, 0xef, 0x07, 0x13, 0xe5, 0x71, 0x7d, 0x12, 0x98, 0x0c, 0xa6, 0x80, 0x07, 0xc0, 0x83, 0xe0, 0x61, 0x79, 0x0a, 0x57, 0x7a, 0x0a, 0x57, 0x5a, 0x82, 0x2b, 0x2d, 0xc1, 0x95,\n\t0x96, 0xe0, 0x4a, 0x4b, 0x70, 0xa2, 0x25, 0x38, 0xd1, 0x12, 0x9c, 0x68, 0x09, 0x4e, 0xb4, 0x04, 0x27, 0x5a, 0x82, 0x6a, 0xfa, 0x50, 0x4d, 0x1f, 0xaa, 0xe9, 0x43, 0x35, 0x7d, 0xa8, 0xa6, 0x0f, 0xd5, 0xf4, 0xa1, 0x9a, 0x3e, 0x54, 0xd3, 0x87, 0x6a, 0xfa, 0x50, 0x4d, 0x1f, 0xaa, 0xe9, 0x43, 0x35, 0x7d, 0xa8, 0xa6, 0x0f, 0xd5, 0xf4, 0xa1, 0x9a, 0x3e, 0x54, 0xd3, 0x87, 0x6a, 0xfa, 0x50, 0x4d, 0x1f, 0xaa, 0xe9, 0x43, 0x35, 0x7d, 0xa8, 0xa6, 0x0f, 0xd5, 0xf4, 0xa1, 0x9a, 0x3e, 0x54, 0xd3, 0x87, 0x6a, 0xfa, 0x50, 0x4d, 0x1f, 0xaa, 0xe9, 0x43, 0x35, 0x7d, 0xa8, 0xa6, 0x0f, 0xd5, 0xf4, 0xa1, 0x9a, 0x3e, 0xfd, 0x5b, 0xb0, 0x0a, 0xac, 0x06, 0x6b, 0xa4, 0x1f, 0x05, 0xf5, 0xa3, 0xa0, 0x7e, 0x14, 0xd4, 0x8f, 0x82, 0xfa, 0x51, 0xd0, 0x4a, 0x14, 0xb4, 0x12, 0x05, 0xad, 0x44, 0x41,\n\t0x2b, 0x51, 0xd0, 0x4a, 0x14, 0xd4, 0x8f, 0x82, 0xfa, 0x51, 0x50, 0x3f, 0x0a, 0xea, 0x47, 0x41, 0xfd, 0x28, 0xa8, 0x1f, 0x05, 0xf5, 0xa3, 0xa0, 0x7e, 0x14, 0xd4, 0x8f, 0x82, 0xfa, 0x51, 0x50, 0x3f, 0x0a, 0xea, 0x47, 0x41, 0xfd, 0x28, 0xa8, 0x1f, 0x05, 0xf5, 0xa3, 0xa0, 0x7e, 0x14, 0xd4, 0x8f, 0x82, 0xfa, 0x51, 0x50, 0x3f, 0x0a, 0xea, 0x47, 0x41, 0xfd, 0x28, 0xa8, 0x1f, 0x05, 0xf5, 0xa3, 0xa0, 0x7e, 0x14, 0x34, 0x0b, 0x05, 0xcd, 0x42, 0x41, 0xb3, 0x50, 0xd0, 0x2c, 0x14, 0x34, 0x0b, 0x05, 0xcd, 0x42, 0x41, 0xb3, 0x50, 0xd0, 0x2c, 0x14, 0x34, 0x0b, 0x05, 0xcd, 0x42, 0x41, 0xb3, 0x50, 0xd0, 0x2c, 0x14, 0x34, 0x0b, 0x05, 0xcd, 0x42, 0x41, 0xb3, 0x50, 0xd0, 0x2c, 0x14, 0x34, 0x0b, 0x05, 0xcd, 0x42, 0x41, 0x0b, 0x51, 0xd0, 0x42, 0x14, 0xb4, 0x10, 0x05, 0x2d, 0x44, 0x41,\n\t0x0b, 0x51, 0xd0, 0x42, 0x14, 0xb4, 0x10, 0x05, 0xad, 0x44, 0x41, 0x2b, 0x51, 0xd0, 0x4a, 0x14, 0xb4, 0x12, 0x05, 0xad, 0x44, 0x41, 0x2b, 0x51, 0xd0, 0x4a, 0xa3, 0xb1, 0xf4, 0x19, 0x4d, 0x40, 0x53, 0xd0, 0x0c, 0x10, 0xa3, 0x46, 0x04, 0x88, 0x94, 0x47, 0x8c, 0x68, 0xd0, 0x02, 0xb4, 0x04, 0xb1, 0x20, 0x0e, 0xc4, 0x83, 0x04, 0x90, 0x08, 0x5a, 0x81, 0x36, 0x20, 0x19, 0xa4, 0x82, 0x0e, 0xe0, 0x3c, 0xd0, 0x09, 0x74, 0x01, 0xdd, 0x28, 0xa7, 0x3b, 0xe8, 0x01, 0xd2, 0x40, 0x4f, 0xd0, 0x0b, 0xf4, 0x06, 0xe9, 0xa0, 0x0f, 0xe8, 0x0b, 0xfa, 0x81, 0xfe, 0x60, 0x00, 0x18, 0x08, 0x32, 0x64, 0x29, 0xaa, 0x5e, 0x8a, 0xaa, 0x97, 0xa2, 0xea, 0xa5, 0xa8, 0x7a, 0x29, 0xaa, 0x5e, 0x8a, 0xaa, 0x97, 0xa2, 0xea, 0xa5, 0xa8, 0x7a, 0x29, 0xaa, 0x5e, 0x8a, 0xaa, 0x97, 0xa2, 0xea, 0xa5, 0xa8,\n\t0x7a, 0x29, 0xaa, 0xee, 0x47, 0xd5, 0xfd, 0xa8, 0xba, 0x1f, 0x55, 0xf7, 0xa3, 0xea, 0x7e, 0x54, 0xdd, 0x8f, 0xaa, 0xfb, 0x51, 0x75, 0x3f, 0xaa, 0xee, 0x47, 0xd5, 0xfd, 0xa8, 0xba, 0x1f, 0x55, 0xf7, 0xa3, 0xea, 0x7e, 0x54, 0xdd, 0x8f, 0xaa, 0xfb, 0x51, 0x75, 0x3f, 0xaa, 0xee, 0x47, 0xd5, 0xfd, 0xa8, 0xba, 0x1f, 0x55, 0xf7, 0xa3, 0xea, 0x7e, 0x54, 0xdd, 0x8f, 0xaa, 0xfb, 0x51, 0x75, 0x3f, 0xaa, 0xee, 0x47, 0xd5, 0xfd, 0xa8, 0xba, 0x1f, 0x55, 0x2f, 0x45, 0xd5, 0x4b, 0x51, 0xf5, 0x52, 0x54, 0xbd, 0x14, 0x55, 0x2f, 0x45, 0xd5, 0x4b, 0x51, 0xf5, 0x52, 0x54, 0xbd, 0x14, 0x55, 0x2f, 0x45, 0xd5, 0x4b, 0x51, 0xf5, 0x52, 0x54, 0x7d, 0x3f, 0xaa, 0xbe, 0x1f, 0x55, 0xdf, 0x8f, 0xaa, 0xef, 0x47, 0xd5, 0xf7, 0xa3, 0xea, 0xfb, 0x51, 0xf5, 0xfd, 0xa8, 0xfa, 0x7e, 0x54, 0x7d, 0x3f,\n\t0xaa, 0x9e, 0x8d, 0xaa, 0x67, 0xa3, 0xea, 0xd9, 0xa8, 0x7a, 0x36, 0xaa, 0x9e, 0x8d, 0xaa, 0x67, 0xa3, 0xea, 0xd9, 0xa8, 0x7a, 0x36, 0xaa, 0x9e, 0x8d, 0xaa, 0x67, 0xa3, 0xea, 0xd9, 0xa8, 0x7a, 0x36, 0xaa, 0x9e, 0x8d, 0xaa, 0x67, 0xa3, 0xea, 0xd9, 0xa8, 0x7a, 0x36, 0xaa, 0x9e, 0x8d, 0xaa, 0x67, 0xa3, 0xea, 0xd9, 0xa8, 0x7a, 0x36, 0xaa, 0x9e, 0x8d, 0xaa, 0x67, 0xa3, 0xea, 0xd9, 0xa8, 0x7a, 0x36, 0xaa, 0x9e, 0x8d, 0xaa, 0x67, 0xa3, 0xea, 0xd9, 0xa8, 0x7a, 0x36, 0xaa, 0x9e, 0x8d, 0xaa, 0x67, 0xa3, 0xea, 0xd9, 0xa8, 0x7a, 0x36, 0xaa, 0x9e, 0x8d, 0xaa, 0x67, 0xa3, 0xea, 0xd9, 0xa8, 0x7a, 0x36, 0xaa, 0x9e, 0x8d, 0xaa, 0x67, 0xa3, 0xea, 0xd9, 0xa8, 0xba, 0x0f, 0x55, 0xf7, 0xa1, 0xea, 0x3e, 0x54, 0xdd, 0x87, 0xaa, 0xfb, 0x50, 0x75, 0x1f, 0xaa, 0xee, 0x43, 0xd5, 0x7d, 0xa8,\n\t0xba, 0x0f, 0x55, 0xf7, 0xa1, 0xea, 0x3e, 0x54, 0xdd, 0x87, 0xaa, 0xfb, 0x50, 0x75, 0x1f, 0xaa, 0xee, 0x43, 0xd5, 0x7d, 0xa8, 0xba, 0x0f, 0x55, 0xf7, 0xa1, 0xea, 0x3e, 0x54, 0xdd, 0x87, 0xaa, 0xfb, 0x50, 0x75, 0x1f, 0xaa, 0x9e, 0x85, 0xaa, 0x67, 0xa1, 0xea, 0x79, 0xa8, 0x7a, 0x1e, 0xaa, 0x9e, 0x87, 0xaa, 0xe7, 0xa1, 0xea, 0x79, 0xa8, 0x7a, 0x1e, 0xaa, 0x9e, 0x87, 0xaa, 0xaf, 0x44, 0xd5, 0x57, 0xa2, 0xea, 0x6b, 0x51, 0xf5, 0xb5, 0xa8, 0xfa, 0x5a, 0x54, 0x7d, 0x2d, 0xaa, 0xbe, 0x16, 0x55, 0x5f, 0x8b, 0xaa, 0xaf, 0x45, 0xd5, 0xd7, 0xa2, 0xea, 0x6b, 0x51, 0xf5, 0xb5, 0xa8, 0xfa, 0x66, 0x54, 0x7d, 0x33, 0xaa, 0xbe, 0x19, 0x55, 0xdf, 0x8c, 0xaa, 0x6f, 0x46, 0xd5, 0x37, 0xa3, 0xea, 0xa5, 0x28, 0xba, 0x1f, 0x45, 0xf7, 0xa3, 0xe8, 0x7e, 0x14, 0xdd, 0x8f, 0xa2, 0xfb, 0x51,\n\t0x74, 0x1f, 0x8a, 0xee, 0x43, 0xd1, 0x7d, 0x28, 0xba, 0x0f, 0x45, 0xf7, 0xa1, 0xe8, 0x95, 0xb5, 0xe7, 0x57, 0xdd, 0x57, 0x7b, 0x7e, 0xd5, 0x3f, 0xff, 0x16, 0x29, 0x88, 0x72, 0x86, 0x52, 0xce, 0x08, 0xca, 0x19, 0xaa, 0x7e, 0x13, 0xba, 0x96, 0x4c, 0x69, 0x3d, 0x99, 0xd2, 0xfa, 0x9a, 0xec, 0x55, 0x6d, 0xd3, 0x9b, 0x6d, 0x5a, 0xb3, 0x4d, 0x92, 0xca, 0x97, 0x97, 0xb2, 0xcd, 0x27, 0x6c, 0xf3, 0x89, 0xf5, 0x6d, 0x92, 0x79, 0x3c, 0x31, 0x2b, 0xf8, 0x25, 0xb9, 0x2a, 0xf8, 0x15, 0xf9, 0x6d, 0xf0, 0xab, 0xf2, 0x07, 0x91, 0x61, 0x5d, 0xb7, 0x7f, 0x92, 0xd8, 0x8a, 0xea, 0x6d, 0x97, 0x5f, 0x8b, 0x5c, 0xf9, 0x91, 0xf8, 0x89, 0xdc, 0x6e, 0x87, 0x6c, 0x2f, 0x7e, 0x96, 0x73, 0xac, 0xeb, 0xf6, 0xbf, 0x20, 0xf2, 0xe4, 0x45, 0xd6, 0x75, 0xfb, 0xaf, 0x16, 0xbf, 0xc8, 0xc5, 0xd4, 0xbe,\n\t0x2f, 0xb5, 0x1f, 0x21, 0xbc, 0xa7, 0xcb, 0x69, 0xc1, 0x65, 0xa2, 0x4c, 0xf6, 0x64, 0x8f, 0x77, 0x93, 0xc7, 0xbd, 0x6d, 0xe6, 0x68, 0xf6, 0xee, 0x72, 0x92, 0xbd, 0x07, 0x18, 0x0a, 0x86, 0xc9, 0x6d, 0xf6, 0xe1, 0x60, 0x04, 0xeb, 0x97, 0x80, 0x91, 0xac, 0x8f, 0x02, 0xa3, 0x59, 0xbf, 0x14, 0x8c, 0x01, 0x97, 0x81, 0xcb, 0xc1, 0x15, 0xe0, 0x4a, 0x30, 0x96, 0xf7, 0xaf, 0x02, 0x57, 0xb3, 0x7e, 0x0d, 0xb8, 0x96, 0xf5, 0xeb, 0xc0, 0x38, 0x39, 0x49, 0xdd, 0x8f, 0xcc, 0xba, 0x17, 0x99, 0xa3, 0x85, 0xfc, 0xda, 0xd1, 0x12, 0xd4, 0xbd, 0xa7, 0xd8, 0xd7, 0xf5, 0xee, 0x29, 0xf6, 0xb5, 0xa3, 0x0d, 0x48, 0x06, 0x29, 0xa0, 0xee, 0x3d, 0xc5, 0xbe, 0x0e, 0xbc, 0xa7, 0x98, 0xcd, 0x46, 0x46, 0xff, 0x8d, 0xb0, 0xe3, 0x33, 0x74, 0xd0, 0x10, 0xc4, 0x80, 0x96, 0x20, 0x16, 0x24, 0x80, 0xb6,\n\t0xb2, 0x02, 0x3f, 0xe6, 0xc1, 0x8f, 0x79, 0xf0, 0x63, 0x1e, 0xfc, 0x98, 0x17, 0x3f, 0xe6, 0xc6, 0x8f, 0xb9, 0xf1, 0x63, 0x6e, 0xfc, 0x98, 0x1b, 0x3f, 0xe6, 0xc6, 0x8f, 0xb9, 0xf1, 0x63, 0x79, 0xf8, 0xb1, 0x3c, 0xfc, 0x58, 0x9e, 0xba, 0x3b, 0x6a, 0x6f, 0x5e, 0x4b, 0x07, 0x7d, 0xf8, 0xbf, 0x2f, 0xe8, 0x07, 0xfa, 0x83, 0x01, 0x60, 0x20, 0x18, 0x04, 0x32, 0xc0, 0x85, 0x60, 0x30, 0xb8, 0x08, 0x0c, 0x01, 0x17, 0x83, 0xa1, 0x60, 0x18, 0x18, 0x0e, 0x46, 0x80, 0x4b, 0xc0, 0x48, 0x30, 0x0a, 0x8c, 0x06, 0x97, 0x82, 0x31, 0xe0, 0x32, 0x70, 0x39, 0xb8, 0x02, 0x5c, 0x09, 0xc6, 0x82, 0xab, 0xc0, 0xd5, 0xe0, 0x1a, 0x70, 0x2d, 0xb8, 0x4e, 0xba, 0xf0, 0x64, 0xbb, 0xf0, 0x64, 0x5e, 0x3c, 0x99, 0x17, 0x4f, 0xe6, 0xc5, 0x93, 0x95, 0xe2, 0xc9, 0x4a, 0xf1, 0x64, 0xa5, 0xe6, 0x5d, 0x5c,\n\t0xf1, 0x65, 0xa5, 0xf8, 0xb2, 0x52, 0x7c, 0x99, 0x17, 0x5f, 0xe6, 0xc5, 0x97, 0x79, 0xf1, 0x65, 0x5e, 0x7c, 0x99, 0x17, 0x5f, 0xe6, 0xc5, 0x97, 0x79, 0xf1, 0x65, 0x6e, 0x7c, 0x99, 0x1b, 0x5f, 0xe6, 0xc6, 0x97, 0x79, 0xf1, 0x65, 0x5e, 0x7c, 0x59, 0x1e, 0xbe, 0xcc, 0x8b, 0x2f, 0xf3, 0xe0, 0xcb, 0x3c, 0xf8, 0x32, 0x0f, 0xbe, 0xcc, 0x63, 0x5e, 0x25, 0x18, 0x5f, 0x96, 0x87, 0x2f, 0xf3, 0xe0, 0xcb, 0x3c, 0xf8, 0x32, 0x0f, 0xbe, 0xcc, 0x83, 0x2f, 0xf3, 0xe0, 0xcb, 0x3c, 0xf8, 0x32, 0x0f, 0xbe, 0xcc, 0x83, 0x2f, 0xf3, 0xe0, 0xcb, 0x3c, 0xf8, 0xb2, 0x62, 0x7c, 0x59, 0x31, 0xbe, 0xac, 0x00, 0x5f, 0xe6, 0xc5, 0x97, 0x95, 0x5b, 0x47, 0x0c, 0x0a, 0x35, 0x34, 0x10, 0x6f, 0xe6, 0xc6, 0x9b, 0x15, 0xdb, 0x32, 0xf0, 0x62, 0xc3, 0xc0, 0x68, 0xc0, 0xfc, 0x8c, 0x47, 0xf3, 0xe2, 0xd1,\n\t0xbc, 0x78, 0x34, 0x37, 0x1e, 0x2d, 0x0f, 0x8f, 0xe6, 0xc5, 0xa3, 0x79, 0xf1, 0x68, 0x5e, 0x3c, 0x9a, 0x07, 0x8f, 0xe6, 0xc1, 0xa3, 0x15, 0xe2, 0xd1, 0x5c, 0xea, 0x4e, 0xb5, 0x33, 0xd9, 0xe6, 0x79, 0xfe, 0x7f, 0x91, 0xd7, 0x5f, 0x61, 0xdd, 0x3c, 0x22, 0xf0, 0x26, 0xdb, 0xce, 0x03, 0xf3, 0x79, 0xfd, 0x3d, 0x5e, 0x7b, 0x1f, 0x2c, 0x00, 0x1f, 0x80, 0x85, 0xe0, 0x43, 0xb0, 0x08, 0x7c, 0x04, 0x16, 0x83, 0x8f, 0xc1, 0x12, 0x3e, 0xff, 0x09, 0xb0, 0xee, 0x7c, 0x8b, 0x5f, 0xdb, 0x85, 0x5f, 0xf3, 0xe2, 0xd7, 0xbc, 0xf8, 0xb5, 0x3c, 0xfc, 0x5a, 0x1e, 0x7e, 0xad, 0xd4, 0xbc, 0x23, 0x2e, 0x9e, 0x2d, 0x0f, 0xcf, 0x96, 0x87, 0x67, 0xcb, 0xc3, 0xb3, 0xe5, 0xe1, 0xd9, 0xf2, 0x42, 0xd0, 0x7d, 0x7c, 0x9b, 0x1b, 0xdf, 0x96, 0x87, 0x6f, 0x2b, 0xc6, 0xb7, 0x79, 0xf1, 0x6d, 0x5e, 0x7c,\n\t0x9b, 0x07, 0xdf, 0xe6, 0xb6, 0xa3, 0x25, 0x76, 0xb4, 0xc4, 0x8e, 0x96, 0xd8, 0xd1, 0x12, 0xfb, 0x44, 0xb0, 0x10, 0x7c, 0x08, 0x16, 0x81, 0x8f, 0xc0, 0x62, 0xf0, 0x31, 0x58, 0x82, 0x27, 0x68, 0x00, 0x88, 0x5f, 0xbd, 0x11, 0x68, 0x0c, 0x9a, 0x80, 0xa6, 0xa0, 0x19, 0x08, 0x07, 0x51, 0x20, 0x1a, 0xb4, 0x00, 0xc4, 0xb8, 0x4e, 0x8c, 0xeb, 0xc4, 0xb8, 0x1e, 0x07, 0xe2, 0x01, 0xb1, 0xae, 0x27, 0x82, 0x56, 0xa0, 0x35, 0x48, 0x02, 0x6d, 0x40, 0x32, 0x48, 0x01, 0xa9, 0xa0, 0x2d, 0x68, 0x07, 0xc8, 0x41, 0xf0, 0x75, 0x15, 0xf8, 0xba, 0x0a, 0x7c, 0x5d, 0x05, 0xbe, 0xae, 0x02, 0x5f, 0x57, 0x81, 0xaf, 0xab, 0xc0, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc,\n\t0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x1b, 0xaf, 0xe6, 0xc6, 0xab, 0xb9, 0xf1, 0x6a, 0x6e, 0xbc, 0x9a, 0x1b, 0xaf, 0x96, 0x87, 0x57, 0xcb, 0xc3, 0xab, 0xe5, 0xe1, 0xd5, 0xf2, 0xf0, 0x6a, 0x79, 0x78, 0x35, 0x37, 0x5e, 0xcd, 0x8d, 0x57, 0x73, 0xe3, 0xd5, 0xdc, 0x78, 0x35, 0x37, 0x5e, 0xcd, 0x8d, 0x57, 0x73, 0xe3, 0xd5, 0xdc, 0x78, 0x35, 0x37, 0x5e, 0xcd, 0x8d, 0x57, 0x73, 0xe3, 0xd5, 0xdc, 0x78, 0x35, 0x37,\n\t0x5e, 0xcd, 0x8d, 0x57, 0x73, 0xe3, 0xd5, 0xdc, 0x78, 0x35, 0x37, 0x5e, 0xcd, 0x8d, 0x57, 0x73, 0xe3, 0xd5, 0xdc, 0x78, 0x35, 0x37, 0x5e, 0xcd, 0x8d, 0x57, 0x73, 0xe3, 0xd5, 0xdc, 0x78, 0xb5, 0x3c, 0xbc, 0x5a, 0x1e, 0x5e, 0x2d, 0x0f, 0xaf, 0x96, 0x87, 0x57, 0xcb, 0xc3, 0xab, 0xe5, 0xe1, 0xd5, 0xf2, 0xf0, 0x6a, 0x79, 0x78, 0xb5, 0x3c, 0xbc, 0x5a, 0x1e, 0x5e, 0x2d, 0x0f, 0xaf, 0x96, 0x87, 0x57, 0xcb, 0xc3, 0xab, 0xe5, 0xe1, 0xd5, 0xf2, 0xf0, 0x6a, 0x79, 0x78, 0xb5, 0x3c, 0xbc, 0x5a, 0x1e, 0x5e, 0xcd, 0x85, 0x57, 0x73, 0xe1, 0xd5, 0x5c, 0x78, 0x35, 0x17, 0x5e, 0xcd, 0x85, 0x57, 0x73, 0xe1, 0xd5, 0x5c, 0x78, 0xb5, 0x5d, 0x78, 0xb5, 0x5d, 0x78, 0xb5, 0x5d, 0x78, 0xb5, 0x5d, 0x78, 0xb5, 0x5d, 0x78, 0xb5, 0x5d, 0x78, 0xb5, 0x5d, 0x78, 0x35, 0x2f, 0x5e, 0xcd, 0x8b, 0x57,\n\t0xf3, 0xe2, 0xd5, 0xbc, 0x78, 0x35, 0x2f, 0x5e, 0xcd, 0x8b, 0x57, 0x2b, 0xc5, 0xab, 0x95, 0xe2, 0xd5, 0x4a, 0xf1, 0x6a, 0xa5, 0x78, 0xb5, 0x52, 0x75, 0xe7, 0xe6, 0x78, 0x9e, 0x13, 0x40, 0x22, 0x68, 0x05, 0xda, 0x80, 0x64, 0x90, 0x0a, 0x3a, 0x80, 0xf3, 0x40, 0x27, 0xd0, 0x45, 0x9e, 0xc6, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc6, 0xab, 0xb9, 0xf1, 0x6a,\n\t0x6e, 0xbc, 0x9a, 0x1b, 0xaf, 0xe6, 0xc6, 0xab, 0xb9, 0xf1, 0x6a, 0x6e, 0xbc, 0x9a, 0x1b, 0xaf, 0xe6, 0xc6, 0xab, 0xb9, 0xf1, 0x6a, 0x6e, 0xbc, 0x9a, 0x1b, 0xaf, 0xe6, 0xc6, 0xab, 0xb9, 0xf1, 0x6a, 0x6e, 0xbc, 0x9a, 0x1b, 0xaf, 0xe6, 0xc6, 0xab, 0xb9, 0xf1, 0x6a, 0x6e, 0xbc, 0x9a, 0x1b, 0xaf, 0xe6, 0xc6, 0xab, 0xb9, 0xf1, 0x6a, 0x6e, 0xbc, 0x9a, 0x1b, 0xaf, 0xe6, 0xc6, 0xab, 0xb9, 0xf1, 0x6a, 0x6e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab,\n\t0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0x1e, 0xbc, 0x9a, 0x07, 0xaf, 0xe6, 0xc1, 0xab, 0x79, 0xf0, 0x6a, 0xc5, 0x78, 0xb5, 0x62, 0xbc, 0x5a, 0x31, 0x5e, 0xad, 0x18, 0xaf, 0x56, 0x8c, 0x57, 0x2b, 0xc6, 0xab, 0x15, 0xe3, 0xd5, 0x8a, 0xf1, 0x6a, 0xc5, 0x78, 0xb5, 0x62,\n\t0xbc, 0x5a, 0x31, 0x5e, 0xad, 0x18, 0xaf, 0x56, 0x8c, 0x57, 0x2b, 0xc6, 0xab, 0x15, 0xe3, 0xd5, 0x8a, 0xf1, 0x6a, 0xc5, 0x78, 0xb5, 0x62, 0xbc, 0x5a, 0x31, 0x5e, 0xad, 0x18, 0xaf, 0x56, 0x8c, 0x57, 0x2b, 0xc6, 0xab, 0x15, 0xe0, 0xd5, 0x0a, 0xf0, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x79, 0xf1, 0x6a, 0x5e, 0xbc, 0x9a, 0x17, 0xaf, 0xe6, 0xc5, 0xab, 0x95, 0xe3, 0xd5, 0xca, 0xff, 0xc6, 0x11, 0x98, 0x42, 0xbc, 0x5a, 0x21, 0x5e, 0xad, 0x10, 0xaf, 0x56, 0x88, 0x57, 0x2b, 0xc4, 0xab, 0x15, 0xe2, 0xd5, 0xbc, 0x0e, 0x72, 0x23, 0x07, 0xb9, 0x91, 0xc3, 0x07, 0x0e, 0x82, 0x43, 0xe0, 0x18, 0x2a, 0xef, 0x07, 0x95, 0xe0, 0x57, 0x70, 0x1c, 0x9c, 0x90, 0xc5, 0xf8, 0xb7, 0x62, 0xfc, 0x5b, 0x31, 0xfe, 0xad, 0x18, 0xff, 0x56, 0x8c, 0x7f, 0xcb, 0xfb, 0xbf, 0xe4, 0x7e,\n\t0xdb, 0xa6, 0xab, 0x6b, 0x81, 0xab, 0x4b, 0xc5, 0xd5, 0xb5, 0xf9, 0x1f, 0x5c, 0xcd, 0x26, 0x94, 0x56, 0xba, 0x69, 0xe5, 0x7e, 0x5a, 0x59, 0x4e, 0x2b, 0x8f, 0xb0, 0x87, 0x15, 0x94, 0x5e, 0xa0, 0xbe, 0xdf, 0x35, 0xcf, 0x12, 0xa8, 0xfc, 0x3f, 0x74, 0xd5, 0xff, 0x3f, 0x3f, 0xf7, 0xbc, 0xd1, 0x1f, 0x6d, 0x11, 0xf2, 0x83, 0xe8, 0xc4, 0x3e, 0xcd, 0xdf, 0xf7, 0x9a, 0x57, 0x30, 0x6e, 0xa0, 0x7e, 0x2f, 0x79, 0x9e, 0x98, 0x6a, 0x3c, 0x2f, 0x62, 0xd5, 0xa7, 0x6d, 0xd6, 0xf9, 0xff, 0x79, 0xc2, 0x66, 0x7f, 0xcf, 0x3c, 0x67, 0x49, 0xdf, 0xe4, 0x0c, 0x17, 0xcd, 0x45, 0x07, 0x21, 0xe4, 0x29, 0x79, 0x50, 0x4e, 0x94, 0x7b, 0xe5, 0x7e, 0xf9, 0xb2, 0x5c, 0x27, 0x97, 0xc8, 0xd9, 0x3c, 0xef, 0x90, 0x5e, 0x5e, 0x7f, 0x11, 0x1c, 0x96, 0x93, 0xe4, 0x62, 0x9e, 0xcb, 0xe4, 0x2e, 0xf9, 0xbc,\n\t0xdc, 0x29, 0x97, 0xb1, 0x4d, 0xb1, 0xf8, 0x0b, 0x7f, 0xd2, 0x27, 0x2b, 0x64, 0x0e, 0xcf, 0x47, 0x64, 0x91, 0x2c, 0xc4, 0xc3, 0x98, 0xaf, 0x15, 0xf2, 0xea, 0x01, 0x9e, 0x0f, 0x82, 0xfd, 0xbc, 0x7f, 0x10, 0xef, 0x5e, 0xbd, 0xb5, 0x57, 0x56, 0xb2, 0x65, 0x85, 0x3c, 0x20, 0x77, 0x03, 0x72, 0x1a, 0xe9, 0x91, 0xe5, 0xf2, 0x97, 0x3f, 0x28, 0xff, 0x10, 0xd8, 0x87, 0xaf, 0x34, 0xd7, 0x8b, 0xd9, 0xf6, 0x64, 0x9d, 0x77, 0xcb, 0x61, 0xd5, 0x7c, 0xce, 0x97, 0xa5, 0xd2, 0xa7, 0xd6, 0x4a, 0xd5, 0x63, 0xc5, 0x39, 0xcb, 0x3b, 0x28, 0x8f, 0xcb, 0xe5, 0x3c, 0x1f, 0x95, 0x3f, 0xd3, 0xde, 0x13, 0xea, 0xb5, 0xe3, 0x94, 0xe3, 0xb3, 0xf6, 0xf5, 0x3d, 0x25, 0x1d, 0xaa, 0xf9, 0x3c, 0x31, 0x40, 0x59, 0x32, 0x53, 0x6e, 0xe0, 0x55, 0x37, 0x5b, 0x65, 0xca, 0x02, 0x5a, 0x64, 0xb2, 0xb4, 0xa3,\n\t0xba, 0x4e, 0xb5, 0xe5, 0x9e, 0xaa, 0x6e, 0x85, 0xfc, 0x09, 0xfc, 0x2c, 0x77, 0xaa, 0x75, 0x37, 0x4c, 0xee, 0x37, 0xcb, 0xb7, 0xb6, 0x39, 0xce, 0xff, 0x05, 0x6a, 0xed, 0x67, 0x6a, 0x9c, 0x53, 0xcd, 0x95, 0xd9, 0x0a, 0xb5, 0x56, 0x59, 0x5b, 0x56, 0x45, 0x9d, 0x72, 0x5f, 0x56, 0xcf, 0x8b, 0xc1, 0x0e, 0xbc, 0xa1, 0xb9, 0x9e, 0x2b, 0xbf, 0x92, 0x9f, 0xf0, 0x7c, 0xd8, 0xfa, 0xe4, 0x61, 0xf9, 0x91, 0x3c, 0xaa, 0xd6, 0xf6, 0xc9, 0x12, 0xfa, 0x71, 0x18, 0x6b, 0xef, 0xca, 0x59, 0xf2, 0x43, 0x79, 0xa5, 0xdc, 0x24, 0x27, 0xcb, 0xcf, 0xe5, 0x48, 0x39, 0x58, 0x7d, 0x6e, 0xa7, 0xd9, 0x4b, 0x6a, 0xcb, 0x13, 0xf2, 0x98, 0xdc, 0xc3, 0xf3, 0x31, 0xda, 0x53, 0x40, 0x8e, 0x66, 0xbe, 0xf6, 0x4b, 0x75, 0x89, 0x66, 0x7d, 0xe5, 0x49, 0x6a, 0x7b, 0x5c, 0x1e, 0xb3, 0x6a, 0xb1, 0x87, 0x1e,\n\t0x55, 0xeb, 0xf4, 0xda, 0x51, 0x96, 0x72, 0xb6, 0x3c, 0x89, 0x83, 0x3e, 0x93, 0xdf, 0x23, 0x56, 0x8f, 0xec, 0x53, 0x71, 0x50, 0x66, 0xd5, 0xea, 0x90, 0x19, 0x01, 0xb5, 0x51, 0x70, 0xa4, 0xba, 0x1d, 0x66, 0x6f, 0x51, 0x52, 0x35, 0x23, 0xf9, 0x16, 0x17, 0x55, 0x7c, 0xea, 0xc0, 0x59, 0xca, 0x3d, 0x5c, 0xd3, 0xd3, 0xea, 0x53, 0xaa, 0x24, 0xda, 0x5a, 0x64, 0x46, 0x9c, 0xd9, 0x6f, 0xd5, 0xb1, 0x62, 0xb6, 0xc8, 0xda, 0x43, 0x15, 0x75, 0xce, 0x57, 0x4c, 0xfb, 0x68, 0xb5, 0x87, 0xc7, 0x5d, 0x44, 0x7f, 0x65, 0x4d, 0x1d, 0x02, 0x4a, 0xde, 0xaa, 0x1e, 0x57, 0x82, 0x2f, 0xe5, 0x1b, 0xaa, 0x97, 0xb6, 0xca, 0x2d, 0xd6, 0x7b, 0x1b, 0xac, 0xe7, 0x1f, 0xe4, 0x52, 0xf5, 0xfe, 0x9b, 0x72, 0xb9, 0xfc, 0xa2, 0xf6, 0x93, 0x55, 0xbf, 0x3f, 0xfe, 0xbe, 0xb5, 0xdc, 0x68, 0xfd, 0xf7, 0xb3,\n\t0x1c, 0x24, 0xb7, 0xc9, 0x35, 0x72, 0x34, 0x3d, 0x72, 0x91, 0xec, 0x25, 0xef, 0x92, 0xab, 0xc8, 0x8d, 0x85, 0x3c, 0x1f, 0xdc, 0x26, 0x07, 0xcb, 0xc7, 0x78, 0xde, 0x2c, 0xd7, 0xca, 0xf3, 0x79, 0x67, 0x28, 0xbd, 0xb4, 0xaa, 0xb6, 0x9c, 0xca, 0x7a, 0x35, 0xfc, 0x48, 0x96, 0xf0, 0x38, 0x59, 0x2e, 0x50, 0x6d, 0x3c, 0x2e, 0x57, 0xa8, 0xf8, 0x75, 0x05, 0xc4, 0xef, 0x11, 0x35, 0xd6, 0x0e, 0xa9, 0x9a, 0xd6, 0x8f, 0xdf, 0xa3, 0x44, 0xed, 0x26, 0x15, 0xb3, 0xe5, 0xf2, 0x5b, 0xfa, 0xba, 0x84, 0x3e, 0xcc, 0x93, 0x3f, 0xd5, 0x1d, 0x75, 0xf4, 0xe6, 0x11, 0xf3, 0x15, 0xb9, 0xa5, 0x86, 0x4d, 0xab, 0xe4, 0x43, 0xaa, 0x4f, 0xaa, 0xc7, 0x56, 0x95, 0xdc, 0x1c, 0xf0, 0xde, 0x16, 0x79, 0x1d, 0xe3, 0x79, 0x97, 0x7c, 0x8b, 0xc7, 0x6b, 0xcd, 0xe8, 0x01, 0x03, 0x64, 0x2f, 0x73, 0x4e, 0xa8,\n\t0x8e, 0xfe, 0xea, 0x58, 0x66, 0x4f, 0x59, 0xf2, 0x57, 0xea, 0xb5, 0x8b, 0x1e, 0xd9, 0x63, 0xc5, 0xc3, 0x4e, 0xb3, 0x86, 0x66, 0xcc, 0xf2, 0xae, 0x97, 0x1a, 0x6e, 0xb6, 0x22, 0xd9, 0x9c, 0x9f, 0x56, 0x57, 0xef, 0xb9, 0x76, 0x5c, 0xd4, 0xf6, 0x58, 0x75, 0x89, 0xb5, 0x35, 0x3b, 0xa9, 0x62, 0x0c, 0x4d, 0xa3, 0x8c, 0xcd, 0xd6, 0xb8, 0xa8, 0x9e, 0x77, 0x0e, 0x5b, 0x11, 0x7e, 0xb8, 0x66, 0xb6, 0xa0, 0x1f, 0xf2, 0xd9, 0xf2, 0x14, 0x2d, 0xd8, 0xc7, 0xf6, 0xc5, 0x8c, 0xa4, 0xed, 0xd4, 0x2c, 0xff, 0x2c, 0x71, 0x76, 0x42, 0x26, 0xa8, 0xe7, 0x86, 0xe0, 0x29, 0xb2, 0x7e, 0x73, 0xfd, 0x45, 0xd9, 0x43, 0xb6, 0x55, 0x31, 0x38, 0xcb, 0x8a, 0xc5, 0xc6, 0x72, 0x1d, 0xcf, 0x4f, 0xcb, 0x31, 0xf2, 0x52, 0xd9, 0x40, 0x4e, 0x65, 0xbd, 0x01, 0xfd, 0x13, 0x2b, 0x87, 0xc9, 0x51, 0x32, 0x4e,\n\t0xf6, 0x97, 0x8f, 0xc9, 0x29, 0xbc, 0x36, 0x5e, 0xde, 0xcd, 0x5e, 0x67, 0xc8, 0x25, 0x6a, 0x9e, 0xac, 0x8e, 0x73, 0x46, 0x1a, 0x7d, 0x51, 0x61, 0xc5, 0x6f, 0x81, 0xf9, 0xaa, 0xd9, 0x77, 0xd6, 0xdc, 0xb4, 0xbb, 0x66, 0x06, 0xa0, 0xa6, 0x79, 0x2a, 0x5a, 0xb6, 0xc3, 0x49, 0x8e, 0x5c, 0xcf, 0x67, 0x72, 0x88, 0xe2, 0x5f, 0x98, 0xdb, 0xeb, 0xd7, 0xf8, 0x51, 0xf5, 0x78, 0x0f, 0x58, 0x2f, 0x73, 0xd5, 0xfa, 0x8f, 0x72, 0x9e, 0x7c, 0x51, 0xf5, 0xd7, 0x2e, 0xab, 0xdf, 0xee, 0x21, 0x1b, 0x16, 0x44, 0xc1, 0x76, 0x96, 0xdb, 0xe5, 0x03, 0xac, 0xdf, 0xc1, 0xfc, 0x3f, 0x89, 0x1a, 0x66, 0x11, 0x7d, 0x1f, 0xca, 0xa9, 0xea, 0xf3, 0xf3, 0x88, 0x8f, 0x7c, 0x66, 0x40, 0x9f, 0xe2, 0xf7, 0x75, 0xf5, 0xd9, 0x97, 0x55, 0x1d, 0xac, 0xb9, 0x4d, 0xae, 0x90, 0x1f, 0xf3, 0xec, 0xb7, 0xc6, 0x9f,\n\t0x5f, 0xbe, 0x62, 0x8e, 0x70, 0x7a, 0xf0, 0x17, 0x5a, 0x32, 0x5b, 0x3e, 0xcf, 0xfa, 0x1c, 0xa2, 0xfd, 0x15, 0x39, 0x85, 0xde, 0x9e, 0x4d, 0x69, 0xef, 0x9a, 0xa5, 0xc8, 0x95, 0xb4, 0xe1, 0x68, 0xcd, 0x7c, 0x29, 0x7f, 0x54, 0x8f, 0x66, 0x0c, 0xaf, 0x90, 0x1f, 0x58, 0xa3, 0x6b, 0xad, 0x2a, 0xa7, 0xca, 0x9a, 0x13, 0xab, 0xe4, 0x77, 0xe6, 0x58, 0xe2, 0xf3, 0x0b, 0xe5, 0x52, 0x73, 0xb6, 0x36, 0xe7, 0xa9, 0x9a, 0x79, 0xb1, 0x3a, 0x2a, 0x02, 0xc6, 0xdb, 0x76, 0xeb, 0xbf, 0x8e, 0xea, 0x31, 0x05, 0xcc, 0x57, 0xb5, 0x3e, 0x41, 0x64, 0x5e, 0x29, 0x2f, 0x57, 0xe5, 0xcd, 0xb5, 0xca, 0x4d, 0x56, 0xfb, 0x7d, 0x4d, 0xbe, 0x24, 0x5f, 0x95, 0xad, 0xe5, 0xed, 0xe6, 0x68, 0x44, 0x15, 0xdb, 0xc9, 0x3e, 0xfc, 0x9f, 0x08, 0x4b, 0xb7, 0xca, 0xeb, 0x78, 0xed, 0x66, 0xea, 0x9e, 0x2b, 0xa7,\n\t0xcb, 0xef, 0xd5, 0xfc, 0x5b, 0x3d, 0xe7, 0xee, 0x50, 0x11, 0xbf, 0xae, 0x7a, 0x8f, 0x30, 0x51, 0xfc, 0xfb, 0xc8, 0xa7, 0xdc, 0x9d, 0x6a, 0xae, 0x39, 0x84, 0x6a, 0x6e, 0xb5, 0xda, 0x50, 0x52, 0x1b, 0xbf, 0x55, 0x75, 0xe7, 0x75, 0xe9, 0xe7, 0xc1, 0x26, 0xba, 0x88, 0x20, 0x11, 0xc7, 0x5a, 0x02, 0xea, 0xdc, 0xd2, 0x36, 0xc0, 0x36, 0x40, 0xb4, 0xb5, 0x0d, 0xb2, 0x5d, 0x28, 0xda, 0xd9, 0x86, 0xd8, 0x86, 0x88, 0xf3, 0x6c, 0x43, 0x6d, 0xc3, 0x44, 0x47, 0xdb, 0x25, 0xb6, 0x4b, 0x44, 0x67, 0xdb, 0x28, 0xdb, 0x68, 0xd1, 0xc5, 0x36, 0xc6, 0x36, 0x46, 0x74, 0xb3, 0x5d, 0x6d, 0xbb, 0x46, 0x74, 0xb7, 0x5d, 0x6f, 0xbb, 0x5e, 0xa4, 0xd9, 0x6e, 0xb6, 0xdd, 0x22, 0x7a, 0xda, 0x6e, 0xb3, 0xdd, 0x2d, 0x2e, 0x08, 0x89, 0x0b, 0x89, 0x13, 0xfd, 0x42, 0xf6, 0x84, 0xec, 0x11, 0xfd, 0x43,\n\t0xf2, 0x43, 0x7e, 0x11, 0x03, 0x42, 0xf6, 0x87, 0xec, 0x17, 0x83, 0x42, 0x5b, 0x85, 0xb6, 0x12, 0x19, 0xf6, 0xf6, 0xf6, 0x6e, 0xe2, 0x42, 0x7b, 0x4f, 0xfb, 0x10, 0x71, 0x89, 0xfd, 0x06, 0xfb, 0x4d, 0x62, 0xbc, 0xfd, 0x36, 0xfb, 0x3d, 0xe2, 0x26, 0xfb, 0x44, 0xfb, 0x54, 0x71, 0x97, 0xfd, 0x61, 0xfb, 0x53, 0x62, 0xa2, 0xfd, 0x39, 0xfb, 0x2b, 0x62, 0x9a, 0xfd, 0x55, 0xfb, 0x9b, 0xe2, 0x59, 0xfb, 0x07, 0xf6, 0x4f, 0xc4, 0x2c, 0xfb, 0x32, 0xfb, 0xe7, 0xe2, 0x55, 0xfb, 0x06, 0xfb, 0x56, 0x31, 0xcf, 0xbe, 0xc3, 0x9e, 0x27, 0x16, 0xd8, 0x4b, 0xed, 0x65, 0xe2, 0x63, 0xbb, 0xcf, 0x7e, 0x50, 0x7c, 0x62, 0x3f, 0x6c, 0xaf, 0x12, 0x4b, 0xed, 0xa7, 0xf5, 0x60, 0xf1, 0x8d, 0x1e, 0xaa, 0x3b, 0xc5, 0x1a, 0xbd, 0x81, 0x1e, 0x2e, 0xb2, 0xf4, 0x28, 0xbd, 0x9d, 0xd8, 0xaa, 0x77, 0xd7,\n\t0xbb, 0x8b, 0x02, 0xbd, 0xa7, 0x7e, 0x81, 0xd8, 0xa7, 0xf7, 0xd1, 0x2f, 0x16, 0xc5, 0xfa, 0x30, 0x7d, 0xb4, 0xa8, 0xd0, 0x2f, 0xd3, 0x2f, 0x13, 0x27, 0xf4, 0x2b, 0xf4, 0x07, 0x45, 0x95, 0xfe, 0xb0, 0xfe, 0xb8, 0xd6, 0x52, 0x7f, 0x4a, 0x7f, 0x56, 0x6b, 0xa5, 0xbf, 0xa4, 0xbf, 0xa2, 0xa5, 0xe8, 0xaf, 0xea, 0xaf, 0x6b, 0xed, 0x9c, 0x5f, 0x3b, 0xbf, 0xd6, 0xce, 0x73, 0x6e, 0x72, 0x6e, 0xd2, 0x3a, 0xc2, 0xd4, 0x0d, 0x22, 0x84, 0x25, 0x18, 0x5f, 0x16, 0x2a, 0x34, 0x61, 0xc7, 0x45, 0xd9, 0x84, 0x21, 0x1c, 0xf0, 0xe7, 0x14, 0x61, 0xbc, 0xde, 0x80, 0x25, 0x44, 0x34, 0x64, 0x09, 0xc5, 0x3f, 0x35, 0x65, 0x8b, 0x66, 0x2c, 0xba, 0x08, 0x67, 0x31, 0x44, 0x84, 0x88, 0x54, 0xd7, 0xfd, 0x6e, 0xc1, 0xeb, 0x31, 0xa2, 0x25, 0x9f, 0x89, 0x65, 0x09, 0x86, 0xfb, 0x38, 0x3e, 0x9d, 0xc0,\n\t0xe2, 0xc4, 0x07, 0x27, 0x52, 0x46, 0x2b, 0xd1, 0x9a, 0x32, 0x92, 0xf0, 0xa0, 0x8d, 0x44, 0xb2, 0x48, 0x11, 0x8d, 0x45, 0x2a, 0x4b, 0x13, 0xd1, 0x96, 0xa5, 0xa9, 0x68, 0xc7, 0xd2, 0x4c, 0xb4, 0x67, 0x09, 0xa7, 0xc7, 0x3a, 0x88, 0x08, 0xd5, 0x67, 0x1a, 0x7d, 0x36, 0x48, 0x38, 0x6d, 0x19, 0xb6, 0x0c, 0x61, 0xb3, 0x5d, 0x48, 0xff, 0x05, 0xa9, 0xfe, 0x73, 0xd2, 0x7f, 0x43, 0x45, 0x88, 0x6d, 0x18, 0xbd, 0x18, 0xaa, 0x7a, 0xd1, 0xa0, 0x17, 0x47, 0x09, 0xbb, 0x6d, 0x34, 0x7d, 0xe9, 0x54, 0x7d, 0x19, 0x46, 0x5f, 0x5e, 0x2d, 0xc2, 0x6d, 0xd7, 0xd0, 0xa3, 0x11, 0xaa, 0x47, 0x43, 0xe9, 0xd1, 0x9b, 0x59, 0xbf, 0x85, 0x7e, 0x6d, 0x4c, 0xbf, 0xde, 0x26, 0x1a, 0xd8, 0x6e, 0xb7, 0xdd, 0xce, 0x36, 0x77, 0xd8, 0xee, 0xe0, 0x95, 0x3b, 0x6d, 0x77, 0xf2, 0xca, 0x5d, 0xb6, 0xbb, 0x28,\n\t0xed, 0x6e, 0x7a, 0x3d, 0x42, 0xf5, 0xba, 0x5d, 0xf5, 0xba, 0x53, 0xf5, 0xba, 0x43, 0xf5, 0x7a, 0x90, 0xea, 0x75, 0xbb, 0xfd, 0x46, 0x7a, 0x3a, 0x98, 0x9e, 0xbe, 0x53, 0x68, 0xf6, 0xbb, 0xe8, 0x6f, 0x1b, 0xfd, 0x3d, 0x91, 0xc7, 0x49, 0xf6, 0x07, 0x45, 0x90, 0x7d, 0x2a, 0x7d, 0x1f, 0x41, 0xdf, 0x3f, 0xc2, 0xfa, 0x34, 0x22, 0x20, 0x58, 0x45, 0x40, 0xb0, 0x8a, 0x80, 0x60, 0x22, 0xe0, 0x03, 0x11, 0x62, 0x5f, 0x68, 0x5f, 0x22, 0x42, 0xed, 0x9f, 0x10, 0x0d, 0x76, 0x15, 0x0d, 0x76, 0x15, 0x0d, 0x76, 0x15, 0x0d, 0x76, 0x15, 0x0d, 0x3a, 0xd1, 0xe0, 0xe3, 0xf1, 0x20, 0x31, 0x61, 0x10, 0x13, 0x15, 0x3c, 0x1e, 0xb5, 0x9f, 0x10, 0x0e, 0x7b, 0x15, 0xf1, 0xa1, 0xab, 0xf8, 0xb0, 0x13, 0x1f, 0x0e, 0x1e, 0x9d, 0x44, 0x89, 0xae, 0xa2, 0xc4, 0xa9, 0xa2, 0xc4, 0xa9, 0xa2, 0xc4, 0xa9,\n\t0xa2, 0x24, 0x8c, 0x28, 0xb9, 0x50, 0x34, 0xd0, 0x07, 0x13, 0x2b, 0x0d, 0x89, 0x95, 0x91, 0x3c, 0x8e, 0x22, 0x62, 0x1a, 0xa9, 0x88, 0x69, 0x44, 0xc4, 0x5c, 0xc5, 0xe3, 0xd5, 0xfa, 0xbd, 0xa2, 0xb1, 0x7e, 0x9f, 0x7e, 0xbf, 0x68, 0xa2, 0x4f, 0x24, 0x86, 0x9a, 0x12, 0x43, 0x8f, 0x88, 0x66, 0xfa, 0x34, 0xfd, 0x71, 0x11, 0x6e, 0x46, 0x12, 0x8f, 0x44, 0x92, 0x88, 0x30, 0x23, 0x49, 0x44, 0x98, 0x91, 0x24, 0xec, 0x66, 0x24, 0x11, 0x07, 0x36, 0xb1, 0x9e, 0x98, 0x31, 0x7b, 0xde, 0x8c, 0xa7, 0x04, 0x15, 0x49, 0x11, 0x2a, 0x6e, 0x22, 0x54, 0xc4, 0xc4, 0xb0, 0xc4, 0xb2, 0x6e, 0xc6, 0x44, 0x84, 0x8a, 0x86, 0xb6, 0x2a, 0x1a, 0x9a, 0xa8, 0x68, 0x08, 0x56, 0xd1, 0x10, 0x1a, 0x10, 0x0d, 0x2d, 0x55, 0x34, 0x04, 0xa9, 0x68, 0x48, 0x16, 0xe7, 0x89, 0x4e, 0x7c, 0xa6, 0x33, 0x4b, 0x33,\n\t0xc6, 0x76, 0x1a, 0xf1, 0xd6, 0x53, 0x5c, 0x40, 0xac, 0xf4, 0x16, 0xe9, 0xac, 0xf7, 0x11, 0xd7, 0x12, 0x67, 0xd7, 0xb1, 0xc4, 0x8a, 0x71, 0x2c, 0x21, 0xe2, 0x7a, 0xe2, 0xba, 0x99, 0xb8, 0xd1, 0xfa, 0xc5, 0x79, 0xf5, 0xef, 0xcd, 0x6f, 0xe7, 0x95, 0x3b, 0x58, 0x1a, 0x88, 0x3b, 0xc5, 0x5d, 0x44, 0xe1, 0xdd, 0xe2, 0x1e, 0xd6, 0xef, 0x15, 0xf7, 0x53, 0xc2, 0x44, 0x96, 0x06, 0x62, 0x12, 0x4b, 0x33, 0x31, 0x99, 0x25, 0x5c, 0x4c, 0x61, 0x69, 0x20, 0x1e, 0x10, 0x0f, 0xa9, 0x2b, 0xdf, 0x3c, 0xcc, 0xeb, 0x8f, 0xb0, 0x38, 0xc5, 0x34, 0xf1, 0x0c, 0x6d, 0x9b, 0x21, 0x9e, 0x25, 0xbe, 0x67, 0xb2, 0x44, 0x89, 0xe7, 0x58, 0xa2, 0xc5, 0xf3, 0x2c, 0x89, 0xe2, 0x5f, 0x2c, 0xba, 0x98, 0xc5, 0xd2, 0x5a, 0xeb, 0xa5, 0xf5, 0x16, 0x6d, 0xb4, 0x74, 0x2d, 0x5d, 0x34, 0xd7, 0xfa, 0x54, 0x5f,\n\t0x05, 0x5f, 0xeb, 0xcb, 0x7a, 0x3f, 0x75, 0x25, 0xfc, 0xfe, 0xda, 0x00, 0x91, 0xa4, 0x0d, 0xd4, 0x06, 0x8a, 0x14, 0x6d, 0x90, 0x36, 0x88, 0xfc, 0x2c, 0x43, 0xcb, 0x60, 0xfd, 0x42, 0xed, 0x42, 0xd6, 0x87, 0x6a, 0x43, 0x45, 0x3b, 0x6d, 0xb8, 0x36, 0x9c, 0xc7, 0xeb, 0xd4, 0x55, 0x22, 0xf7, 0x6b, 0xfb, 0x45, 0x84, 0x56, 0xa2, 0x95, 0x88, 0x60, 0xcd, 0xab, 0x79, 0xc9, 0xe9, 0x4a, 0xb5, 0x52, 0xa2, 0xdc, 0x1c, 0x27, 0x0e, 0x35, 0x42, 0x22, 0xd4, 0x08, 0x71, 0xa8, 0x51, 0x11, 0xa1, 0x46, 0x42, 0x84, 0x1a, 0x09, 0x0e, 0x35, 0x12, 0x82, 0xd4, 0x48, 0x48, 0x56, 0x23, 0x21, 0x42, 0x8d, 0x84, 0x64, 0x35, 0x12, 0x82, 0xd5, 0x18, 0x08, 0x52, 0x63, 0x20, 0x58, 0xc5, 0x7d, 0xb2, 0xed, 0x3e, 0xdb, 0xfd, 0xa2, 0x99, 0x6d, 0x92, 0x6d, 0x92, 0x68, 0x61, 0x9b, 0x6c, 0x83, 0x0d, 0xdb,\n\t0x54, 0xdb, 0x54, 0xc6, 0xc6, 0x43, 0xb6, 0x87, 0x78, 0x7d, 0x9a, 0x6d, 0x1a, 0xeb, 0x8f, 0xd9, 0x1e, 0x67, 0xbc, 0x3d, 0x61, 0x7b, 0x42, 0xb4, 0xb6, 0x3d, 0x63, 0x7b, 0x86, 0xf1, 0x39, 0xc3, 0x36, 0x43, 0xc4, 0xda, 0x66, 0xda, 0x66, 0xb2, 0xfd, 0xf3, 0xb6, 0xe7, 0x79, 0xfd, 0x45, 0xdb, 0x8b, 0x22, 0xde, 0xf6, 0x8a, 0xed, 0x15, 0x5e, 0x99, 0x6b, 0x9b, 0x6b, 0x5e, 0x3b, 0xc2, 0x36, 0x8f, 0x12, 0xe6, 0xdb, 0xe6, 0xf3, 0xee, 0x7b, 0xb6, 0x8f, 0x19, 0xab, 0x4b, 0x6c, 0x44, 0xbf, 0xed, 0x4b, 0xdb, 0x97, 0xc2, 0x16, 0x3c, 0x2e, 0x98, 0xbe, 0x0b, 0x9e, 0x1c, 0x3c, 0x59, 0x34, 0x0a, 0x7e, 0x2a, 0xf8, 0x29, 0xd1, 0x38, 0xf8, 0x99, 0xe0, 0x67, 0x78, 0x9c, 0x11, 0x3c, 0x43, 0x44, 0x06, 0x3f, 0x1b, 0xfc, 0xac, 0x68, 0x1f, 0x3c, 0x33, 0x78, 0x26, 0xeb, 0xcf, 0x05, 0x3f, 0x27,\n\t0xda, 0x87, 0x84, 0x87, 0x84, 0x8b, 0x46, 0x21, 0xdf, 0x85, 0xac, 0x31, 0xaf, 0x8a, 0x45, 0xfe, 0xa6, 0x85, 0x6c, 0x09, 0xc9, 0x61, 0xdd, 0x1c, 0xb1, 0x11, 0x21, 0x05, 0x21, 0x05, 0xa2, 0x45, 0x48, 0x49, 0x48, 0x89, 0x08, 0x0f, 0xf1, 0x85, 0xf8, 0x44, 0x58, 0x68, 0xeb, 0xd0, 0xd6, 0xa2, 0x41, 0xa8, 0x79, 0x45, 0x97, 0x66, 0xa1, 0xc9, 0xa1, 0xc9, 0xc2, 0x1e, 0x7a, 0x22, 0xf4, 0x84, 0x68, 0xa1, 0xe6, 0xef, 0x38, 0x35, 0x7f, 0xc7, 0x31, 0x7f, 0xdf, 0xc0, 0xa3, 0x39, 0xb6, 0x13, 0xd4, 0xa8, 0x8e, 0x50, 0xa3, 0x3a, 0x42, 0x8d, 0xd5, 0x08, 0x7b, 0x19, 0x63, 0x32, 0x46, 0x8d, 0xc9, 0x18, 0x35, 0xd2, 0x22, 0xd4, 0x48, 0x8b, 0x50, 0x23, 0x2d, 0x42, 0x8d, 0xae, 0xb6, 0x6a, 0x74, 0xb5, 0x55, 0xa3, 0xab, 0x89, 0x1a, 0x5d, 0x4d, 0xd4, 0xe8, 0x6a, 0xa2, 0x46, 0x57, 0xb0, 0x1a,\n\t0x5d, 0xa1, 0x01, 0xa3, 0xab, 0xa5, 0x1a, 0x5d, 0x41, 0x6a, 0x74, 0x05, 0xa9, 0xd1, 0x95, 0xac, 0x46, 0x57, 0xb2, 0xfe, 0x86, 0xfe, 0x9e, 0x68, 0xa5, 0x2f, 0xd0, 0x57, 0xf0, 0xf8, 0x95, 0x9e, 0xc9, 0xe3, 0xb7, 0xfa, 0x6a, 0x46, 0xe3, 0x1a, 0xfd, 0x07, 0xd1, 0x42, 0xdf, 0xa0, 0x6f, 0xe0, 0x71, 0xa3, 0x9e, 0xcd, 0x98, 0xdc, 0xaa, 0x6f, 0xe5, 0x71, 0x9b, 0xee, 0xe2, 0x95, 0x3c, 0x7d, 0x1f, 0x8f, 0x45, 0x3a, 0x11, 0xa2, 0x97, 0xe9, 0x07, 0x78, 0xf4, 0xe9, 0x3e, 0x66, 0x81, 0x43, 0xfa, 0x69, 0x1e, 0xa5, 0x11, 0x22, 0x62, 0x8d, 0x50, 0xc3, 0x10, 0x21, 0x46, 0x03, 0xa3, 0x11, 0x8f, 0xe6, 0x3d, 0xe6, 0x9a, 0x19, 0xe6, 0x95, 0xfd, 0x34, 0xc3, 0xbc, 0x4e, 0x98, 0x66, 0xb4, 0x24, 0xfb, 0xd5, 0x8c, 0x36, 0xe4, 0xbf, 0x9a, 0xba, 0xf3, 0xa5, 0x66, 0x74, 0x20, 0x0f, 0xd6, 0x8c,\n\t0x4e, 0x46, 0x27, 0x1e, 0xbb, 0xa8, 0xfb, 0xec, 0x98, 0x77, 0xbe, 0x6c, 0x66, 0xf4, 0x32, 0x06, 0x8a, 0x46, 0x46, 0x86, 0x31, 0x98, 0x6c, 0xd9, 0xbc, 0xff, 0x65, 0x03, 0x63, 0x8c, 0x31, 0x86, 0xc7, 0xcb, 0x8c, 0x6b, 0x44, 0x0b, 0xe3, 0x7a, 0xe3, 0x1e, 0x1e, 0xa7, 0x1a, 0x0f, 0xf3, 0x38, 0xcd, 0x78, 0x94, 0xd7, 0x9f, 0x30, 0x9e, 0xe5, 0xf1, 0x39, 0x32, 0xea, 0x06, 0xc6, 0xbf, 0x8c, 0x39, 0xe4, 0xf1, 0x2f, 0x1a, 0x73, 0x79, 0x7c, 0xdd, 0x58, 0x25, 0xec, 0xc6, 0x6a, 0x63, 0x3d, 0x59, 0xfd, 0x06, 0x23, 0x97, 0xc7, 0x1d, 0xc6, 0xcf, 0x3c, 0xba, 0x8c, 0x9d, 0x22, 0xca, 0xd8, 0x65, 0xe4, 0x8b, 0x68, 0xa3, 0xc0, 0xd8, 0x27, 0x12, 0x8d, 0x22, 0xa3, 0x44, 0xe8, 0x46, 0x99, 0x71, 0x98, 0xc7, 0xa3, 0xc6, 0x71, 0xd1, 0x5a, 0xfd, 0xe6, 0xa6, 0x81, 0x63, 0x8f, 0x63, 0x8f, 0x68,\n\t0xe7, 0x28, 0x73, 0x1c, 0x12, 0x11, 0x8e, 0xc3, 0x8e, 0xa3, 0x22, 0xd8, 0x71, 0xcc, 0x71, 0x5c, 0xb4, 0x70, 0x9c, 0x70, 0xfc, 0x26, 0xc2, 0x9c, 0xd9, 0x4e, 0x58, 0x12, 0xb6, 0x90, 0x85, 0x66, 0xd6, 0x6e, 0xbf, 0xd3, 0x71, 0xa3, 0x9a, 0x81, 0xcc, 0xfc, 0xf6, 0x04, 0x6e, 0xbd, 0x00, 0x87, 0xd5, 0x01, 0x67, 0x7c, 0x40, 0x2e, 0xc0, 0x63, 0xec, 0x96, 0x8f, 0xe0, 0x06, 0x0f, 0xe3, 0x16, 0xf3, 0xa4, 0xa3, 0x3a, 0xef, 0xfb, 0xc3, 0x0c, 0xfd, 0x30, 0x39, 0x1e, 0xce, 0x8a, 0x7c, 0xa4, 0x3b, 0xce, 0xb7, 0x10, 0xdf, 0x57, 0x8c, 0x1f, 0xbe, 0x97, 0x32, 0xbf, 0xc0, 0xc9, 0x78, 0xf0, 0xb2, 0x47, 0xd9, 0xc6, 0x8d, 0x0b, 0x2b, 0xfa, 0x93, 0x4c, 0x9f, 0xbc, 0x44, 0x8e, 0x32, 0xf3, 0x13, 0xf9, 0x99, 0xf2, 0xe7, 0xb3, 0x6b, 0xb3, 0xc3, 0x0e, 0x81, 0x19, 0x3b, 0xf5, 0xaa, 0x60, 0x29,\n\t0x3f, 0x5b, 0x5d, 0x6a, 0x1c, 0x11, 0xd9, 0x86, 0x5f, 0x95, 0x51, 0xa5, 0xfc, 0x13, 0xf9, 0x4b, 0x4d, 0x36, 0x49, 0x8b, 0x4f, 0x9d, 0xb3, 0x0e, 0x7e, 0x16, 0x33, 0xb3, 0xf3, 0xe0, 0xb5, 0x8b, 0xc9, 0xfe, 0x9e, 0xe5, 0xd1, 0x85, 0xa3, 0x2d, 0xc5, 0xb7, 0x1e, 0xe0, 0xd5, 0x16, 0xaa, 0xcc, 0x8a, 0xdf, 0x33, 0xa0, 0x3f, 0xfc, 0x4b, 0x56, 0x19, 0x52, 0xb8, 0x72, 0x68, 0xac, 0x33, 0xaf, 0xd7, 0xf1, 0xd5, 0x38, 0xd9, 0x02, 0xea, 0x65, 0x66, 0x4c, 0xfb, 0xf0, 0xf1, 0xbf, 0xe2, 0xab, 0x7f, 0x0a, 0x78, 0xbf, 0xda, 0xcd, 0x4d, 0x51, 0xcc, 0x6c, 0x32, 0x33, 0x31, 0xe5, 0x2d, 0xcd, 0x1c, 0xa3, 0x44, 0xa6, 0x07, 0xe4, 0x55, 0xe5, 0xd5, 0xdb, 0xaa, 0xe7, 0xdf, 0xce, 0x3c, 0xba, 0xc1, 0xe3, 0xe5, 0x8a, 0x8f, 0x25, 0x8a, 0xdf, 0x17, 0x55, 0x8e, 0xed, 0x63, 0x8f, 0xa9, 0xbf, 0x1f,\n\t0x03, 0xf8, 0xc3, 0x7e, 0x39, 0x14, 0x90, 0x7b, 0x1f, 0x0f, 0x38, 0x8a, 0x70, 0x94, 0x52, 0x4e, 0xfc, 0x39, 0xa7, 0xea, 0xfd, 0xea, 0x3c, 0xe1, 0xd5, 0xea, 0xbc, 0x55, 0x3d, 0x7e, 0x57, 0x7b, 0xc4, 0x66, 0x54, 0xc0, 0x76, 0x1b, 0x59, 0xb6, 0x49, 0xf3, 0x3b, 0xde, 0x9a, 0x57, 0xca, 0xac, 0xe3, 0x30, 0x55, 0xd4, 0x7a, 0x1f, 0x71, 0xd9, 0x89, 0xd6, 0xfb, 0x54, 0x9c, 0x7a, 0x54, 0x9c, 0x96, 0x5b, 0x71, 0xfa, 0xa7, 0xfd, 0x61, 0x66, 0xf5, 0xf4, 0x9c, 0x8b, 0x38, 0x6d, 0x4d, 0x6f, 0x16, 0x90, 0x49, 0xec, 0x63, 0x5f, 0xb7, 0x13, 0xb1, 0x2b, 0x88, 0xd3, 0x3c, 0xe9, 0xa4, 0xa4, 0x83, 0x38, 0xef, 0x7a, 0x71, 0xfa, 0xbb, 0xbf, 0xae, 0xf3, 0xea, 0x7c, 0x15, 0x89, 0x5e, 0x15, 0x5f, 0x6e, 0xe5, 0xf9, 0xd7, 0xd3, 0x37, 0x63, 0xac, 0x77, 0x6f, 0x67, 0x14, 0xe4, 0x11, 0x3b, 0x1e,\n\t0xb5, 0x94, 0x53, 0xe3, 0x85, 0xf2, 0xdf, 0x01, 0x8e, 0xfe, 0x90, 0xe9, 0xd2, 0x65, 0x3a, 0xfb, 0x2b, 0x24, 0x87, 0x39, 0x45, 0xc4, 0x3f, 0xc7, 0x56, 0xf9, 0x8c, 0x93, 0xdd, 0x32, 0xb1, 0x26, 0x4b, 0xaf, 0x3b, 0xf6, 0x6a, 0xb8, 0xae, 0x57, 0x8f, 0x39, 0x35, 0x47, 0x2d, 0xcc, 0xfc, 0xcc, 0x7a, 0xed, 0x98, 0x1c, 0xf9, 0x67, 0xf5, 0xaf, 0x13, 0x1f, 0x57, 0xa8, 0xbe, 0x5d, 0x2a, 0x7f, 0xe5, 0x79, 0xae, 0x8a, 0x37, 0x33, 0x3e, 0x3a, 0xfc, 0xd1, 0x7e, 0x03, 0x8f, 0x20, 0xa9, 0xc7, 0x97, 0x14, 0xc3, 0xbf, 0xa8, 0xf1, 0x41, 0xc6, 0x24, 0x3f, 0xa0, 0x27, 0x2b, 0x6a, 0xf9, 0xb8, 0x57, 0x2e, 0x53, 0x47, 0xed, 0xcc, 0x23, 0x30, 0x45, 0x6c, 0x57, 0x22, 0xbf, 0x94, 0xab, 0x68, 0x71, 0x9d, 0x23, 0x31, 0x66, 0x7c, 0x98, 0xc7, 0x6b, 0x14, 0xa7, 0x66, 0x19, 0x4b, 0x89, 0x84, 0x2a,\n\t0x79, 0xa9, 0xf5, 0xee, 0x33, 0x64, 0x3f, 0xd6, 0x51, 0x1e, 0x6a, 0x7b, 0x8c, 0xf8, 0xdb, 0x4e, 0x5f, 0x9e, 0x30, 0x6b, 0xad, 0xde, 0x2f, 0xa8, 0x2d, 0x83, 0xbc, 0x54, 0x1d, 0x99, 0xc8, 0xaa, 0x89, 0xa1, 0x3a, 0x31, 0x46, 0x36, 0xcf, 0x6c, 0xf4, 0x4b, 0x75, 0x1c, 0xfe, 0x3e, 0x6b, 0x04, 0xb4, 0xe5, 0x75, 0x35, 0x46, 0x8a, 0x54, 0x5b, 0xd8, 0x8a, 0xbe, 0xcb, 0x66, 0x3f, 0x57, 0x59, 0xdb, 0x4c, 0x90, 0x9f, 0x9a, 0x47, 0x9e, 0xcc, 0x28, 0xa1, 0x87, 0x0f, 0xd0, 0x9a, 0x15, 0xf2, 0x1b, 0x73, 0x4e, 0xa8, 0x39, 0x66, 0xa8, 0x1e, 0x1f, 0x52, 0x65, 0x64, 0xa9, 0x7a, 0x7c, 0x5e, 0x53, 0x43, 0xf3, 0x28, 0x59, 0xc0, 0x91, 0xc2, 0x43, 0xb4, 0xe3, 0x68, 0xbd, 0x79, 0xcc, 0x26, 0x86, 0xe1, 0xf5, 0x2e, 0x60, 0xad, 0xb7, 0x18, 0x8b, 0xff, 0xba, 0x06, 0x07, 0xd7, 0x1e, 0x07, 0x77,\n\t0x87, 0xe8, 0x81, 0x5f, 0x7b, 0x88, 0x77, 0xa6, 0xe1, 0xad, 0x2e, 0x52, 0x0e, 0x65, 0x2c, 0x0e, 0x65, 0xb2, 0xb8, 0x5a, 0xb9, 0x92, 0x6b, 0x95, 0x2b, 0xb9, 0x4e, 0xb9, 0x92, 0x71, 0xca, 0x95, 0x8c, 0xc7, 0x95, 0xcc, 0x10, 0x37, 0x28, 0x27, 0x72, 0x93, 0x72, 0x22, 0x37, 0xe3, 0x44, 0xe6, 0x8a, 0x5b, 0xf0, 0x20, 0xf3, 0xc5, 0x6d, 0xb8, 0x8f, 0x4f, 0xc4, 0x9d, 0xca, 0x77, 0x3c, 0xa0, 0x7c, 0xc7, 0x83, 0xca, 0x47, 0x4c, 0x55, 0x3e, 0xe2, 0x61, 0x7c, 0xc4, 0x16, 0xf1, 0x48, 0xc8, 0x76, 0xdc, 0xc4, 0x34, 0xe5, 0x23, 0x1e, 0x53, 0x3e, 0xe2, 0x71, 0xe5, 0x23, 0xa6, 0xe3, 0x23, 0x92, 0xc4, 0x13, 0xca, 0x41, 0x3c, 0xa5, 0x1c, 0xc4, 0xd3, 0xf6, 0x87, 0xec, 0x0f, 0x89, 0x67, 0xec, 0x27, 0xed, 0x27, 0xc5, 0x0c, 0x3d, 0x4c, 0x0f, 0x13, 0xcf, 0x2a, 0xf5, 0x9e, 0xa9, 0xd4, 0xfb,\n\t0x25, 0xa5, 0xde, 0x0b, 0x94, 0x7a, 0x7f, 0xa4, 0xd4, 0x7b, 0x09, 0xea, 0x9d, 0x2d, 0x3e, 0x43, 0xb7, 0x5d, 0xe2, 0x73, 0xa5, 0xd8, 0xdf, 0x2a, 0xc5, 0x5e, 0x8f, 0x62, 0xfb, 0xc4, 0x26, 0xb4, 0xfa, 0x37, 0xb1, 0x05, 0xad, 0x36, 0xc4, 0x1e, 0x54, 0x3a, 0x42, 0x78, 0x95, 0x3e, 0x1f, 0x51, 0xfa, 0x5c, 0xa1, 0xf4, 0xf9, 0x98, 0xd2, 0xe7, 0x93, 0x4a, 0x9f, 0x7f, 0x53, 0xfa, 0x7c, 0xda, 0xd4, 0x67, 0x4d, 0x98, 0xfa, 0xac, 0x29, 0x7d, 0xd6, 0x6c, 0xc6, 0x40, 0x63, 0xa0, 0x66, 0x37, 0xf5, 0x59, 0xd3, 0x4d, 0x7d, 0xd6, 0x9c, 0xe8, 0xf3, 0x35, 0x5a, 0xb8, 0xa9, 0xcc, 0x5a, 0xac, 0xa9, 0xcc, 0xda, 0x79, 0xa6, 0x32, 0x6b, 0x9d, 0x4d, 0x65, 0xd6, 0xba, 0xa2, 0xcc, 0x73, 0xb4, 0x0b, 0x4c, 0x4d, 0xd6, 0xfa, 0xa1, 0xc9, 0xeb, 0xb5, 0x0c, 0x53, 0x8d, 0xb5, 0x49, 0xa8, 0xf1, 0x4e,\n\t0xed, 0x71, 0x53, 0x87, 0xb5, 0xa7, 0x4c, 0x1d, 0xd6, 0x9e, 0x37, 0x75, 0x58, 0x9b, 0x65, 0xea, 0xb0, 0xf6, 0xa2, 0xa9, 0xc3, 0xda, 0x6b, 0xa6, 0x0e, 0x6b, 0x6f, 0xa1, 0xb4, 0x9b, 0xb5, 0xb7, 0xe9, 0xc5, 0xc7, 0xf0, 0xeb, 0x9d, 0x50, 0x5b, 0xd3, 0xb1, 0x6b, 0x38, 0xf6, 0xae, 0xbc, 0xd6, 0x8d, 0xc5, 0x21, 0xba, 0xb3, 0x18, 0xf4, 0xa6, 0x79, 0x4d, 0x33, 0xd3, 0xc3, 0x07, 0x29, 0x0f, 0x1f, 0x8c, 0x87, 0xef, 0x83, 0x6f, 0xef, 0x2b, 0xfa, 0xb1, 0x7d, 0x7f, 0x96, 0x10, 0x31, 0x40, 0x98, 0xf7, 0x94, 0x1a, 0x24, 0xae, 0xc0, 0x51, 0x5f, 0x49, 0x34, 0x18, 0x44, 0xc3, 0xb5, 0x7c, 0xca, 0xf4, 0xf9, 0xa1, 0xca, 0xe7, 0xdb, 0x95, 0xcf, 0x77, 0x28, 0x9f, 0xaf, 0x2b, 0x9f, 0xaf, 0xe3, 0xf2, 0xef, 0x60, 0x4b, 0xd3, 0xdb, 0x3b, 0xf0, 0xf6, 0xf7, 0xe1, 0xd8, 0xef, 0x67, 0x09, 0xc6,\n\t0xdf, 0x4f, 0xa2, 0x64, 0xd3, 0xdb, 0x37, 0x52, 0xde, 0x3e, 0x0c, 0x6f, 0xff, 0x20, 0x11, 0x36, 0x95, 0xa8, 0x6a, 0x48, 0x54, 0x3d, 0xc6, 0xe3, 0xe3, 0x2c, 0x21, 0x62, 0xba, 0x78, 0x82, 0x72, 0x9e, 0x64, 0x69, 0x28, 0x9e, 0x62, 0x09, 0x11, 0x4f, 0xe3, 0xf9, 0x75, 0xe5, 0xf9, 0x1b, 0x29, 0xcf, 0xdf, 0x58, 0x79, 0xfe, 0x26, 0xca, 0xf3, 0x37, 0x55, 0x9e, 0xbf, 0x99, 0xf2, 0xfc, 0xe1, 0x2a, 0x2e, 0x35, 0xe5, 0x9c, 0x6d, 0xca, 0x39, 0x07, 0xa9, 0xe8, 0x34, 0x54, 0x74, 0x6a, 0x2a, 0x3a, 0x1b, 0xaa, 0xe8, 0x0c, 0x57, 0x9e, 0xd9, 0xa9, 0x3c, 0x73, 0xa8, 0x8a, 0xd1, 0x70, 0x15, 0xa3, 0x0d, 0x94, 0x5b, 0x6e, 0xa4, 0xdc, 0x72, 0x33, 0x22, 0x55, 0xdd, 0x11, 0x0c, 0xcf, 0x6c, 0x28, 0xcf, 0x1c, 0xae, 0xa2, 0x56, 0x57, 0x51, 0xeb, 0x54, 0x51, 0x6b, 0x57, 0x51, 0xab, 0xab, 0xa8,\n\t0xd5, 0x55, 0xd4, 0xea, 0x2a, 0x6a, 0x1b, 0xaa, 0xa8, 0x75, 0xaa, 0xa8, 0x0d, 0x52, 0x51, 0xdb, 0x48, 0xb9, 0xdf, 0x30, 0xe5, 0x7e, 0x1d, 0x2a, 0x76, 0x1b, 0xaa, 0xd8, 0x75, 0xaa, 0xd8, 0x0d, 0x57, 0xb1, 0xab, 0xab, 0xd8, 0xd5, 0xf5, 0x6f, 0x88, 0xd7, 0x60, 0x15, 0xaf, 0x9a, 0x8a, 0x57, 0x9b, 0x72, 0x9b, 0x36, 0xe5, 0x36, 0x83, 0x02, 0xdc, 0x66, 0xb0, 0x8a, 0xdd, 0x60, 0x15, 0xbb, 0xc1, 0xca, 0x6d, 0x06, 0x2b, 0xb7, 0x19, 0x42, 0x04, 0x9f, 0xa0, 0x9c, 0x2a, 0xbd, 0x8a, 0xf5, 0x93, 0x44, 0xb3, 0xae, 0x9c, 0x67, 0xa8, 0x72, 0x9e, 0x76, 0xe5, 0x3c, 0xed, 0xca, 0x79, 0x3a, 0x54, 0x64, 0xeb, 0x2a, 0xb2, 0x75, 0x15, 0xd9, 0xba, 0x8a, 0x6c, 0x5d, 0x45, 0xb6, 0xae, 0x22, 0x5b, 0x57, 0xce, 0x53, 0x57, 0xce, 0x53, 0x57, 0xce, 0xd3, 0x30, 0x23, 0x9b, 0x75, 0xd3, 0x79, 0x3a,\n\t0x94, 0xf3, 0x74, 0x28, 0xe7, 0xa9, 0x2b, 0xe7, 0xe9, 0x54, 0xce, 0xd3, 0xa9, 0x9c, 0xa7, 0x53, 0x39, 0x4f, 0x4d, 0x39, 0xcf, 0x30, 0xe5, 0x3c, 0xc3, 0x94, 0xf3, 0x6c, 0xa0, 0x9c, 0x67, 0x03, 0xa2, 0xfc, 0x6d, 0xd1, 0xd0, 0x78, 0x07, 0xff, 0xa9, 0x2b, 0xff, 0xd9, 0x48, 0xf9, 0xcf, 0x46, 0xca, 0x7f, 0x36, 0x52, 0xfe, 0xb3, 0xb1, 0xf2, 0x9f, 0x4d, 0x94, 0xff, 0x6c, 0xaa, 0xfc, 0x67, 0x33, 0xe5, 0x3f, 0x9b, 0x29, 0xff, 0x19, 0xae, 0xfc, 0xa7, 0xc3, 0x8c, 0x7b, 0xd3, 0x61, 0x8a, 0xa5, 0x2a, 0x07, 0x6e, 0xae, 0x8e, 0xa6, 0xe8, 0x2a, 0x07, 0x0e, 0x22, 0x1a, 0x1b, 0xf0, 0x6c, 0x66, 0xc2, 0x41, 0xea, 0x08, 0x8a, 0xae, 0xf2, 0xe1, 0x08, 0xb6, 0xa7, 0xcd, 0x2a, 0x2b, 0x36, 0x8f, 0x55, 0xc5, 0xb3, 0x6e, 0xe6, 0xc6, 0x41, 0xea, 0x78, 0x89, 0xae, 0x32, 0x64, 0x47, 0x40, 0x86,\n\t0x5c, 0x7d, 0xbc, 0x24, 0x4c, 0x65, 0xc8, 0x86, 0xca, 0x90, 0x1b, 0xaa, 0x0c, 0x39, 0x54, 0x65, 0xc8, 0x8d, 0x54, 0x86, 0xdc, 0x52, 0xe5, 0xc6, 0x91, 0x6a, 0x5c, 0x45, 0xab, 0x71, 0x15, 0xa9, 0x72, 0x63, 0x2d, 0x20, 0x37, 0x8e, 0x51, 0x19, 0x6f, 0xa4, 0x1a, 0x09, 0xd1, 0x2a, 0xbf, 0x4d, 0x54, 0x99, 0xad, 0xa6, 0x32, 0xdb, 0xa6, 0x2a, 0xbe, 0x1b, 0xa8, 0xf8, 0xb6, 0xa9, 0xf8, 0x0e, 0x57, 0xf1, 0x6d, 0x57, 0xf1, 0xdd, 0x4c, 0xe5, 0xb4, 0xf1, 0x2a, 0xa7, 0x75, 0xaa, 0x9c, 0x36, 0x58, 0xe5, 0xb4, 0x4e, 0x95, 0xd3, 0x06, 0xab, 0x9c, 0x36, 0x4e, 0xe5, 0xb4, 0x51, 0x2a, 0x9b, 0x8d, 0x52, 0x79, 0x6c, 0x0b, 0x95, 0xc7, 0xb6, 0x50, 0x79, 0x6c, 0x88, 0xca, 0x63, 0x83, 0x54, 0x1e, 0xdb, 0x58, 0xe5, 0xb1, 0x91, 0x2a, 0x77, 0x0d, 0x52, 0x47, 0x74, 0x74, 0x95, 0xbb, 0x06, 0xa9,\n\t0x23, 0x3a, 0xba, 0x3a, 0xa2, 0xa3, 0xab, 0x3c, 0x36, 0x48, 0x65, 0xb0, 0xa1, 0x2a, 0x83, 0x6d, 0xa4, 0x32, 0xd8, 0x20, 0xdb, 0x0d, 0xb6, 0x1b, 0x78, 0xd7, 0xcc, 0x63, 0x1b, 0x05, 0x1c, 0xd1, 0xd1, 0x55, 0x36, 0x1b, 0x5a, 0x7b, 0x44, 0xe7, 0x2e, 0x5e, 0x31, 0x73, 0xda, 0x46, 0x6a, 0x4c, 0x46, 0xaa, 0x31, 0x19, 0xad, 0xc6, 0x61, 0x53, 0x35, 0x0e, 0x9b, 0xa9, 0x71, 0x98, 0x10, 0x90, 0xbb, 0x46, 0xab, 0xd1, 0xd8, 0x4c, 0x8d, 0xc6, 0x44, 0x35, 0x1a, 0xa3, 0xd5, 0x68, 0xb4, 0xab, 0x11, 0xd8, 0x4c, 0x65, 0xad, 0x9a, 0xca, 0x5a, 0x9b, 0xaa, 0x71, 0x98, 0xa0, 0xc6, 0x61, 0x8c, 0x3a, 0x56, 0xa4, 0xab, 0xd1, 0xa8, 0x85, 0xac, 0x0f, 0x59, 0xaf, 0x46, 0x63, 0x0e, 0xeb, 0x66, 0x2e, 0x1a, 0xa4, 0x8e, 0x1e, 0xe9, 0x6a, 0x4c, 0x46, 0xaa, 0x63, 0x48, 0xba, 0x1a, 0x99, 0xd1, 0x21,\n\t0x07, 0x42, 0x0e, 0x08, 0x5d, 0x1d, 0x4f, 0xd2, 0xd5, 0x98, 0x6c, 0xaa, 0xc6, 0x64, 0xa4, 0xca, 0x48, 0x9b, 0xab, 0x8c, 0xb4, 0xb9, 0xca, 0x48, 0x9b, 0xab, 0xe3, 0x4c, 0xba, 0xca, 0x48, 0x83, 0x54, 0x46, 0x1a, 0x64, 0x9f, 0x64, 0x9f, 0xca, 0x2b, 0xe6, 0xd1, 0x45, 0x5d, 0x1d, 0x5b, 0xd2, 0xd5, 0xb1, 0x25, 0x5d, 0x1d, 0x5b, 0xd2, 0x55, 0xbe, 0x1a, 0xa4, 0x8e, 0x2d, 0xe9, 0xea, 0xd8, 0x92, 0xae, 0x8e, 0x2d, 0xe9, 0xea, 0xd8, 0x92, 0x6e, 0x2f, 0xb5, 0x97, 0xf2, 0x68, 0x66, 0xb3, 0x11, 0x2a, 0x9b, 0x8d, 0x50, 0x47, 0x98, 0x74, 0x75, 0xd4, 0xb1, 0xfa, 0xa8, 0x92, 0xae, 0x8e, 0x3a, 0x56, 0x1f, 0x4f, 0x0a, 0x52, 0x59, 0x6e, 0x90, 0xca, 0x72, 0x83, 0xd4, 0xf1, 0x24, 0x5d, 0x1d, 0x4f, 0xd2, 0x55, 0xc6, 0xeb, 0x50, 0x19, 0xaf, 0xe3, 0x1c, 0x19, 0x6f, 0xf5, 0xf1, 0xa4, 0x30,\n\t0x95, 0xf1, 0x1a, 0x2a, 0xe3, 0x6d, 0xa8, 0x32, 0xde, 0x50, 0x95, 0xf1, 0x86, 0xaa, 0x8c, 0xb7, 0x91, 0xca, 0x78, 0x1b, 0x29, 0xcd, 0x6c, 0xa9, 0x34, 0xb3, 0xa5, 0xd2, 0xcc, 0x96, 0x6a, 0xf6, 0x89, 0x54, 0xb3, 0x4f, 0xa4, 0x9a, 0x7d, 0xa2, 0xd5, 0xec, 0x13, 0xad, 0x66, 0x9f, 0x48, 0x35, 0xfb, 0x44, 0xaa, 0xd9, 0x27, 0x52, 0xcd, 0x3e, 0x91, 0x6a, 0xf6, 0xd1, 0x54, 0xae, 0xab, 0x05, 0xe4, 0xba, 0x31, 0x6a, 0xc6, 0x89, 0x51, 0xb3, 0x43, 0xa4, 0x9a, 0x1d, 0x22, 0xd5, 0xec, 0x10, 0xa9, 0xe6, 0x82, 0x44, 0x35, 0x17, 0x24, 0xaa, 0x2c, 0xb4, 0xa9, 0x1a, 0xf3, 0x0d, 0xd4, 0x98, 0xb7, 0xa9, 0x31, 0x1f, 0xae, 0xc6, 0xbc, 0x5d, 0x8d, 0x79, 0xbb, 0x1a, 0xf3, 0xcd, 0x54, 0xb6, 0xd9, 0x42, 0x65, 0x9b, 0x41, 0x2a, 0xdb, 0x6c, 0xac, 0xb2, 0xcd, 0x48, 0x75, 0x3c, 0x4c, 0x57, 0xc7,\n\t0xc3, 0x74, 0x95, 0x73, 0x46, 0x53, 0x86, 0xfa, 0xa6, 0xd8, 0x29, 0x1a, 0x5c, 0x21, 0xa2, 0xd0, 0x3f, 0xd3, 0xe1, 0xed, 0xa9, 0xfe, 0x3e, 0xe9, 0x7f, 0xf9, 0x57, 0x93, 0xa7, 0xe0, 0xcb, 0x7c, 0x81, 0xdf, 0x38, 0xfd, 0x97, 0xf7, 0xb2, 0xef, 0xf7, 0x1c, 0xe5, 0x7f, 0xd8, 0x16, 0x37, 0x59, 0xc1, 0x7e, 0x33, 0x87, 0xc2, 0x85, 0x56, 0xfd, 0x99, 0x1f, 0xff, 0xc7, 0x7b, 0x39, 0x5a, 0xef, 0x5b, 0xe2, 0x93, 0xff, 0xa3, 0xfd, 0x74, 0x91, 0x37, 0xd7, 0xf9, 0x3f, 0x4a, 0xf6, 0x25, 0x17, 0xc8, 0x97, 0xf7, 0xcb, 0x51, 0xa7, 0x17, 0xcb, 0xb7, 0x4f, 0x1f, 0xa2, 0x95, 0x7d, 0xe5, 0x30, 0x39, 0xdc, 0x3c, 0x67, 0xe2, 0xf4, 0xa3, 0xa7, 0x77, 0x49, 0xbb, 0xec, 0x2a, 0x3b, 0xcb, 0x7e, 0xf2, 0x4e, 0x32, 0xbe, 0xae, 0xb2, 0x97, 0x4c, 0x92, 0x03, 0xa4, 0x26, 0x83, 0x65, 0xda, 0x39, 0xf7,\n\t0xb1, 0x93, 0xcc, 0x61, 0x4f, 0x9d, 0xef, 0xf3, 0xcc, 0xef, 0x2f, 0x77, 0xe3, 0xe9, 0x37, 0x99, 0x79, 0x01, 0x51, 0xe1, 0xc6, 0x7f, 0xbf, 0xcf, 0x1b, 0x3a, 0xb1, 0xe8, 0xab, 0x66, 0x56, 0x7d, 0x03, 0xbb, 0xc0, 0xfa, 0x86, 0xff, 0x6d, 0xeb, 0x3b, 0x9e, 0xd7, 0xc9, 0x64, 0x32, 0x65, 0x2e, 0x19, 0xc5, 0x4f, 0x94, 0x98, 0x55, 0xf3, 0x8d, 0x6d, 0xcd, 0x37, 0x44, 0x72, 0xdb, 0x19, 0x67, 0x13, 0xac, 0x61, 0xeb, 0x6f, 0xac, 0x6c, 0xfd, 0x47, 0x4a, 0x98, 0x57, 0x9b, 0x65, 0xe8, 0xea, 0x78, 0x8b, 0x9f, 0xbc, 0xff, 0x4d, 0xb9, 0x15, 0xc5, 0x32, 0x73, 0x9a, 0x47, 0x55, 0x26, 0xfd, 0xa0, 0x7c, 0xd3, 0xda, 0x6a, 0xdd, 0x5f, 0x60, 0xf0, 0x40, 0xdd, 0xa3, 0x04, 0xe6, 0xf7, 0xa7, 0x2a, 0xfb, 0xaf, 0xfe, 0xbe, 0xd8, 0x45, 0x8b, 0x3c, 0xd5, 0xdf, 0x7d, 0x5b, 0x67, 0x4b, 0x98, 0x99,\n\t0x46, 0x91, 0xdc, 0xcb, 0x9a, 0x39, 0xf6, 0x8e, 0x5b, 0x47, 0x6d, 0x0e, 0xa9, 0x1c, 0xa4, 0xfc, 0x9c, 0x7b, 0x09, 0xf8, 0x26, 0x5b, 0x7d, 0x8b, 0x58, 0x44, 0xb9, 0x65, 0x01, 0x47, 0x61, 0x8a, 0xd4, 0xb9, 0x07, 0x45, 0x56, 0x86, 0x7e, 0x44, 0xe5, 0x8c, 0x55, 0x64, 0xc4, 0xf9, 0x67, 0xfb, 0x7e, 0x3d, 0x80, 0xb1, 0xad, 0x75, 0xcf, 0xb0, 0x30, 0x8f, 0x05, 0x04, 0x30, 0x66, 0x66, 0x5a, 0x6f, 0xfc, 0x9e, 0x97, 0xa9, 0x63, 0x0e, 0x15, 0xf2, 0x63, 0xc5, 0x58, 0x98, 0x62, 0xec, 0x61, 0x95, 0x1b, 0x3f, 0x50, 0xfd, 0xfd, 0x21, 0xeb, 0x6b, 0xcf, 0xb2, 0x97, 0x19, 0x66, 0xb6, 0x1d, 0xf0, 0xff, 0x83, 0xf2, 0x6a, 0xb2, 0xbe, 0x9d, 0xf2, 0x6b, 0x72, 0xb7, 0x21, 0x8c, 0xa5, 0x1b, 0xd5, 0x99, 0x18, 0xb7, 0xca, 0x27, 0x45, 0x84, 0x2c, 0x3a, 0x7d, 0x50, 0x8e, 0x20, 0xab, 0x7b, 0x5c,\n\t0xbe, 0xc0, 0x6b, 0x59, 0xf2, 0x69, 0xf9, 0x3e, 0xb5, 0x9c, 0x2f, 0x3f, 0x27, 0x6b, 0xbd, 0x5f, 0x66, 0x5a, 0x25, 0x14, 0xd6, 0x39, 0x4a, 0xe4, 0x3b, 0x6b, 0xdb, 0x6e, 0x0a, 0xc8, 0xc1, 0x07, 0x59, 0xcf, 0xaf, 0x81, 0xc7, 0xcd, 0xb5, 0xd3, 0xf9, 0xf2, 0x3c, 0x79, 0x49, 0xed, 0xb6, 0xff, 0x92, 0x4f, 0xc8, 0x17, 0xe5, 0xc3, 0xf2, 0x65, 0x39, 0xfa, 0x5c, 0xe3, 0x51, 0x1d, 0xaf, 0x79, 0x44, 0xe5, 0xf3, 0x53, 0xeb, 0x9c, 0xb1, 0x51, 0x51, 0x3f, 0x03, 0x97, 0x5f, 0xab, 0xed, 0x4f, 0x05, 0x44, 0xe1, 0x09, 0x33, 0xbf, 0xe6, 0xd9, 0x43, 0xab, 0xcc, 0xa3, 0x73, 0x07, 0xe1, 0x6c, 0xbd, 0xbc, 0x56, 0x5e, 0x26, 0xef, 0x22, 0x12, 0x5e, 0xe3, 0xd5, 0x5d, 0x7f, 0x74, 0xcc, 0x44, 0x8d, 0x09, 0xf3, 0x1b, 0x77, 0xb3, 0x8f, 0xf7, 0xaa, 0xfe, 0x3e, 0x55, 0xe7, 0xe8, 0xd4, 0xa9, 0xba,\n\t0x67, 0x11, 0xd0, 0x6f, 0xdf, 0x9e, 0x79, 0x66, 0x41, 0xbd, 0x32, 0xab, 0x8f, 0x68, 0x15, 0xfd, 0x49, 0x74, 0x9f, 0xe5, 0x7d, 0xeb, 0xbc, 0x9f, 0x4a, 0x15, 0xed, 0x07, 0x02, 0xce, 0xc3, 0xc9, 0x3f, 0x6b, 0x09, 0x5b, 0xaa, 0xbf, 0xa7, 0x0e, 0x78, 0xe5, 0xa5, 0xda, 0xb5, 0x1d, 0xb5, 0x6b, 0x4f, 0x5b, 0xcf, 0x33, 0xcf, 0x55, 0xeb, 0x9a, 0x23, 0x0b, 0x67, 0x7d, 0xcf, 0x23, 0x4b, 0x64, 0x59, 0x60, 0x54, 0x9c, 0x79, 0x1c, 0xf2, 0xf7, 0xef, 0x8e, 0x03, 0xde, 0xd9, 0x5b, 0x53, 0x37, 0xe6, 0x93, 0x4d, 0x35, 0xdf, 0xf6, 0xfe, 0x7e, 0x8c, 0xec, 0xcc, 0xb3, 0x47, 0xce, 0xde, 0xc6, 0x9a, 0xf3, 0x15, 0xce, 0x5e, 0xf7, 0x33, 0x8f, 0xf9, 0x9c, 0x3d, 0x62, 0xff, 0xd2, 0x5e, 0x76, 0x9d, 0x73, 0x2f, 0x27, 0xfe, 0xe6, 0x5e, 0xb6, 0xd5, 0x9c, 0x7f, 0x50, 0xfb, 0xca, 0xa7, 0xb5, 0x6b,\n\t0xb5, 0xe7, 0x1d, 0xc8, 0x77, 0xad, 0xe7, 0xb7, 0x6a, 0xce, 0x6b, 0x3a, 0x97, 0xb6, 0xff, 0x03, 0xed, 0xc9, 0x3d, 0xe3, 0x95, 0x97, 0x98, 0xb5, 0xce, 0x76, 0x24, 0xf9, 0xf8, 0x1f, 0x96, 0x73, 0xb7, 0x3a, 0xaa, 0x74, 0xf7, 0x9f, 0xec, 0x6d, 0xe1, 0x99, 0xfd, 0x62, 0x9e, 0x67, 0xa5, 0x22, 0xf9, 0x41, 0x6b, 0xfe, 0xcc, 0x91, 0x9f, 0xa9, 0x57, 0xee, 0xfc, 0xbb, 0xed, 0xac, 0x3d, 0xab, 0xe3, 0x1f, 0xb3, 0x61, 0x1d, 0x6f, 0xea, 0x25, 0x72, 0x84, 0x79, 0x4e, 0x81, 0x8b, 0x45, 0x13, 0x6e, 0x16, 0x9b, 0xd8, 0xcd, 0x12, 0x24, 0xf6, 0xb0, 0x04, 0x8b, 0x03, 0x2c, 0x21, 0xe2, 0x88, 0xa8, 0x22, 0xd3, 0x3a, 0x25, 0x4e, 0x93, 0xb5, 0x08, 0xcd, 0x4e, 0x26, 0x64, 0x68, 0xf8, 0x4a, 0xcd, 0xa9, 0x39, 0x45, 0x4b, 0xad, 0xa1, 0xd6, 0x50, 0xc4, 0x6a, 0x4d, 0xb4, 0xe6, 0x64, 0x3f, 0x51,\n\t0x5a, 0x94, 0x48, 0xd2, 0x5a, 0x68, 0x2d, 0x44, 0x1b, 0x2d, 0x56, 0x8b, 0x15, 0xc9, 0x5a, 0x82, 0x96, 0x28, 0x52, 0xfe, 0x3f, 0xf6, 0xde, 0x06, 0xce, 0xa6, 0x6a, 0xfd, 0x03, 0x5f, 0x6b, 0xef, 0x7d, 0xce, 0x7e, 0x3b, 0xef, 0xef, 0xe7, 0x0c, 0x63, 0x9a, 0x19, 0x63, 0x30, 0xc6, 0x18, 0x43, 0xf2, 0x32, 0x5e, 0x43, 0xd2, 0x24, 0x4d, 0x92, 0x24, 0x57, 0x92, 0x24, 0x69, 0x92, 0x24, 0x49, 0x92, 0x24, 0xc9, 0x75, 0x25, 0x49, 0x92, 0x24, 0x57, 0x92, 0x5c, 0x57, 0x48, 0x92, 0x24, 0x49, 0xd2, 0x24, 0x49, 0x92, 0x5c, 0x49, 0xd2, 0x24, 0x49, 0x92, 0x9c, 0xff, 0xb3, 0xbe, 0xfb, 0xcc, 0x38, 0x33, 0xa8, 0xe9, 0x76, 0xbb, 0xf7, 0xff, 0xfb, 0x7f, 0xfe, 0xf3, 0x7c, 0xf6, 0xb3, 0xd7, 0x79, 0xf6, 0xda, 0x6b, 0xaf, 0xbd, 0xd6, 0xb3, 0xd6, 0x5e, 0xcf, 0x77, 0x3f, 0xcf, 0x1e, 0x9e, 0xc1,\n\t0x33, 0x58, 0x5d, 0x5e, 0x87, 0x67, 0xb3, 0x7a, 0x9c, 0x88, 0xe5, 0x70, 0x22, 0xd6, 0x80, 0xe7, 0xf1, 0x3c, 0x96, 0x2b, 0x2f, 0x97, 0x57, 0xb0, 0x86, 0xf2, 0x2a, 0xf9, 0x15, 0x96, 0x2f, 0xbf, 0x2a, 0xaf, 0x65, 0x05, 0xf2, 0x06, 0x79, 0x23, 0x6b, 0x26, 0xbf, 0x2b, 0xbf, 0xcf, 0x5a, 0xc8, 0x1f, 0xca, 0xdb, 0x59, 0x1b, 0xf9, 0x63, 0xf9, 0x63, 0xd6, 0x4e, 0xde, 0x27, 0x7f, 0xc1, 0xda, 0xcb, 0x5f, 0xca, 0x07, 0xd8, 0x85, 0xf2, 0x41, 0xf9, 0x1b, 0xd6, 0x49, 0x3e, 0x2c, 0x1f, 0x66, 0x17, 0xcb, 0x47, 0xe5, 0x1f, 0x58, 0x57, 0xf9, 0x67, 0xf9, 0x67, 0x56, 0x24, 0xff, 0x22, 0xff, 0xc2, 0x2e, 0x95, 0xe3, 0x72, 0x9c, 0x75, 0x53, 0x64, 0x45, 0x61, 0x97, 0x29, 0x6d, 0x95, 0xb6, 0xec, 0x72, 0xa5, 0xab, 0xd2, 0x95, 0x15, 0xdb, 0x76, 0xdb, 0x76, 0xb3, 0x2b, 0x6c, 0xdf, 0xd8, 0xbe,\n\t0x61, 0x3d, 0x6c, 0x3f, 0xd8, 0x7e, 0x60, 0x57, 0xaa, 0x8b, 0xd5, 0xc5, 0xac, 0xa7, 0x5a, 0xaa, 0x7e, 0xc0, 0xae, 0x52, 0xbf, 0x54, 0x0f, 0xb0, 0xab, 0xd5, 0x5f, 0xd4, 0x5f, 0xd8, 0x35, 0x46, 0x43, 0xa3, 0x3b, 0xeb, 0x63, 0x14, 0x1b, 0x83, 0xd9, 0x58, 0xe3, 0x16, 0x63, 0x34, 0x7b, 0xc2, 0x78, 0xcc, 0x58, 0xcc, 0x9e, 0x37, 0x96, 0x18, 0x2b, 0xd8, 0x1b, 0xc6, 0x2a, 0xe3, 0x35, 0xb6, 0xd9, 0x78, 0xdd, 0x78, 0x9d, 0x95, 0x1a, 0x6f, 0x18, 0x6f, 0xb2, 0x0f, 0x8c, 0x8d, 0xc6, 0x46, 0xb6, 0xdd, 0xd8, 0x62, 0x6c, 0x61, 0x1f, 0x89, 0xef, 0xaa, 0xa1, 0x2d, 0xaf, 0x3b, 0x47, 0xcb, 0xca, 0x68, 0x59, 0x85, 0x5a, 0xf6, 0x08, 0xb5, 0xef, 0xf7, 0x44, 0x76, 0x76, 0x94, 0x48, 0x65, 0x3f, 0x10, 0x69, 0xec, 0x18, 0x91, 0xce, 0x7e, 0x24, 0x32, 0xd8, 0x71, 0x22, 0x9d, 0xfd, 0x44, 0x7d,\n\t0xe0, 0xa4, 0x3e, 0x38, 0x49, 0xe9, 0x5f, 0x88, 0x4c, 0xea, 0x8d, 0x53, 0xcc, 0x41, 0xfd, 0xc1, 0x98, 0x9d, 0x73, 0x4e, 0x96, 0x36, 0x57, 0xb8, 0x42, 0x69, 0x1b, 0xb7, 0x31, 0x27, 0xb7, 0x73, 0x3b, 0x49, 0x54, 0xea, 0x2d, 0x27, 0x7a, 0xcb, 0x85, 0xde, 0xd2, 0xd1, 0x5b, 0x4e, 0xea, 0x2d, 0x2f, 0x73, 0x73, 0x1f, 0x17, 0xff, 0x1d, 0x34, 0xc0, 0x03, 0xcc, 0xcb, 0x83, 0x3c, 0xc8, 0x7c, 0x3c, 0x44, 0xbd, 0xe8, 0x46, 0x2f, 0xfa, 0xd1, 0x8b, 0x21, 0xf4, 0x62, 0x88, 0x7a, 0x31, 0x8d, 0x05, 0xf8, 0x79, 0xd4, 0x97, 0x41, 0xf4, 0xa5, 0x97, 0xfa, 0xb2, 0x0e, 0xf1, 0x6c, 0xea, 0xd1, 0x10, 0x7a, 0x34, 0x84, 0x1e, 0x0d, 0xa3, 0x47, 0x03, 0xd4, 0xa3, 0xcb, 0x99, 0x2e, 0xbf, 0x2c, 0xbf, 0xcc, 0x9c, 0xf2, 0x0a, 0xea, 0x5d, 0x1b, 0xf5, 0xee, 0x2a, 0xa6, 0xca, 0xaf, 0x50, 0x1f, 0x1b,\n\t0xd4, 0xc7, 0x6b, 0x88, 0xbf, 0x26, 0xbf, 0xc6, 0xec, 0xf2, 0x5a, 0xea, 0x6f, 0x1b, 0xf5, 0xf7, 0x5b, 0x94, 0xde, 0x48, 0xbd, 0xae, 0x53, 0xaf, 0xbf, 0x4b, 0xe9, 0x2d, 0xf2, 0x16, 0x4a, 0xbf, 0x27, 0xbf, 0x47, 0xe9, 0xad, 0xf2, 0x56, 0x4a, 0xbf, 0x4f, 0xda, 0x60, 0x87, 0x36, 0xd8, 0xa0, 0x0d, 0x3a, 0x69, 0xc3, 0x3e, 0x16, 0x92, 0xbf, 0x20, 0x9d, 0xf0, 0x90, 0x4e, 0x7c, 0xc9, 0x7c, 0xf2, 0x01, 0xd2, 0x0c, 0x3f, 0x69, 0xc6, 0xd7, 0xc4, 0x0f, 0xc9, 0x87, 0x98, 0x57, 0xfe, 0x86, 0xb4, 0x24, 0x00, 0x2d, 0x09, 0x40, 0x4b, 0xbc, 0xd0, 0x12, 0x2f, 0xb4, 0xc4, 0x0b, 0x2d, 0xf1, 0x42, 0x4b, 0x3c, 0xd0, 0x12, 0x17, 0xb4, 0x24, 0x0c, 0x2d, 0x91, 0xa1, 0x25, 0x6e, 0x68, 0x89, 0x06, 0x2d, 0xd1, 0xa1, 0x25, 0x3a, 0xb4, 0x44, 0x87, 0x96, 0xe8, 0xc6, 0x45, 0xc6, 0x65, 0x8c, 0x1b,\n\t0xdd, 0x49, 0x57, 0x24, 0xd2, 0x95, 0x41, 0xc4, 0x6f, 0x22, 0x8d, 0x91, 0xa1, 0x31, 0x32, 0x34, 0x46, 0x21, 0x8d, 0x59, 0xc2, 0x6c, 0xc6, 0x4b, 0xc6, 0x52, 0xa6, 0x1a, 0xff, 0x30, 0xc8, 0x1a, 0x35, 0x96, 0x19, 0x2f, 0xd3, 0xb9, 0x2b, 0x48, 0x93, 0x0c, 0xd2, 0xa4, 0x57, 0x99, 0x69, 0xac, 0x21, 0x7d, 0xd2, 0xa1, 0x4f, 0x0e, 0xd2, 0xa7, 0x37, 0xc8, 0xaa, 0x5a, 0x4f, 0x5a, 0xe5, 0x83, 0x56, 0xb9, 0xa1, 0x55, 0x7e, 0x68, 0x55, 0x10, 0x38, 0x8b, 0x18, 0xb5, 0x2a, 0xfb, 0x17, 0xdb, 0x47, 0x7a, 0xb3, 0x9f, 0x89, 0x2f, 0x4f, 0x7f, 0x49, 0x64, 0x4f, 0x8c, 0x57, 0xa1, 0x49, 0x79, 0xd0, 0xa4, 0x7c, 0xd2, 0x9d, 0x9f, 0x58, 0x1a, 0xfb, 0x99, 0xc8, 0x01, 0xbd, 0xc9, 0x81, 0xde, 0x34, 0xe0, 0x12, 0x97, 0x58, 0x2e, 0xd7, 0xb8, 0xc6, 0x1a, 0x41, 0x3f, 0x1c, 0xdc, 0xc1, 0x9d, 0x34,\n\t0x46, 0xbd, 0xa4, 0x13, 0x06, 0xb4, 0xe1, 0x3c, 0x68, 0x43, 0x0a, 0x0f, 0x93, 0x36, 0x18, 0x3c, 0x4a, 0xda, 0x10, 0xe5, 0x29, 0xa4, 0x0d, 0x06, 0x4f, 0xe5, 0xa9, 0xa4, 0x37, 0xb5, 0x78, 0x2d, 0x4a, 0x0b, 0xcd, 0x48, 0x87, 0x66, 0xd4, 0xe1, 0xe9, 0x3c, 0x9d, 0xe4, 0x19, 0x3c, 0x93, 0xe4, 0xb5, 0x79, 0x6d, 0x96, 0xc1, 0xb3, 0x48, 0x4b, 0x0c, 0x5e, 0x97, 0xf4, 0xc3, 0xe0, 0xf5, 0x79, 0x7d, 0x9a, 0x15, 0x84, 0x96, 0x78, 0x78, 0x03, 0xde, 0x80, 0x24, 0x0d, 0x79, 0x43, 0xd2, 0x18, 0x81, 0xaa, 0x98, 0x40, 0x55, 0xea, 0x01, 0x55, 0xe1, 0x40, 0x55, 0xea, 0x01, 0x55, 0xe1, 0x40, 0x55, 0x82, 0x40, 0x55, 0x24, 0x78, 0x0a, 0xb8, 0x81, 0xad, 0x48, 0xf0, 0x14, 0x70, 0x03, 0x61, 0x91, 0x81, 0xb0, 0xc8, 0x40, 0x58, 0x14, 0xf9, 0x59, 0xf9, 0x59, 0xd2, 0x92, 0x45, 0xf2, 0x22, 0xe2,\n\t0x8b, 0xe5, 0xc5, 0xc4, 0x97, 0xca, 0x4b, 0x89, 0x0b, 0xfd, 0xcb, 0x93, 0xd7, 0x90, 0xe6, 0xd5, 0x95, 0xd7, 0xc9, 0xeb, 0x98, 0x43, 0x7e, 0x43, 0x7e, 0x83, 0xd2, 0xeb, 0xe5, 0xf5, 0x2c, 0x5b, 0x7e, 0x53, 0x7e, 0x93, 0x66, 0xa0, 0x0d, 0xf2, 0x06, 0x92, 0xbc, 0x45, 0x5a, 0x98, 0x2b, 0x6f, 0x92, 0xdf, 0x61, 0xf5, 0xa1, 0x8b, 0x69, 0xd0, 0xbf, 0x5c, 0xb9, 0x54, 0x2e, 0x65, 0x11, 0x79, 0x9b, 0xbc, 0x8d, 0xce, 0xfd, 0x48, 0xde, 0x41, 0xf9, 0x3f, 0x96, 0x77, 0xb2, 0x1a, 0xf2, 0xa7, 0xf2, 0xa7, 0x94, 0xe7, 0x5f, 0xf2, 0x7e, 0xd2, 0x69, 0xa1, 0x85, 0xe7, 0x91, 0x16, 0x1e, 0xa4, 0xf4, 0xd7, 0xa4, 0x85, 0xe9, 0xa4, 0x85, 0x65, 0x94, 0xfe, 0x56, 0xfe, 0x96, 0x74, 0x54, 0x68, 0x61, 0xba, 0xfc, 0x9d, 0x7c, 0x84, 0xa5, 0xca, 0xdf, 0xcb, 0xdf, 0xb3, 0x4c, 0xd2, 0xc8, 0xa3, 0x24,\n\t0xf9, 0x41, 0x3e, 0xc6, 0x32, 0xe4, 0x1f, 0x65, 0x1a, 0xed, 0xf2, 0x71, 0xf9, 0x27, 0x96, 0x25, 0x9f, 0x90, 0x4f, 0x50, 0x5a, 0x68, 0x6a, 0x54, 0x3e, 0x49, 0x9a, 0x6a, 0xc8, 0xa7, 0xe4, 0x53, 0x94, 0x47, 0xe8, 0xab, 0xa1, 0x08, 0xa3, 0xda, 0xa7, 0x48, 0x8a, 0x44, 0x5a, 0x2b, 0x74, 0xd7, 0x50, 0x6c, 0x8a, 0x9d, 0x65, 0x2a, 0xaa, 0xa2, 0x92, 0xc4, 0x50, 0x0c, 0x16, 0x55, 0x4c, 0xc5, 0x24, 0x79, 0x1b, 0xa5, 0x0d, 0x73, 0x2a, 0x9d, 0x94, 0xce, 0xcc, 0xa1, 0x5c, 0xa4, 0x5c, 0x44, 0xe9, 0x2e, 0x4a, 0x17, 0x4a, 0x5f, 0xac, 0x5c, 0xcc, 0x6a, 0x42, 0xd7, 0x0d, 0xa5, 0x48, 0x29, 0x22, 0xde, 0x4d, 0xe9, 0x46, 0xbc, 0xbb, 0x72, 0x39, 0x95, 0x70, 0x85, 0x72, 0x05, 0x71, 0xe1, 0x83, 0x50, 0x0b, 0x3e, 0x08, 0xb5, 0xe0, 0x83, 0xe0, 0x82, 0x0f, 0x82, 0x17, 0x3e, 0x08, 0x2e, 0xf8,\n\t0x20, 0x78, 0x31, 0x42, 0x52, 0x6c, 0x65, 0xb6, 0x32, 0xe6, 0xc1, 0x38, 0xc9, 0xb7, 0x1d, 0xb3, 0x1d, 0x63, 0x0e, 0xdb, 0x8f, 0xb6, 0x1f, 0x99, 0xdd, 0x76, 0xdc, 0x46, 0x33, 0x97, 0xda, 0x54, 0x6d, 0xca, 0x42, 0xea, 0xb5, 0x6a, 0x5f, 0xe2, 0xb7, 0xa8, 0xb7, 0x30, 0x87, 0x16, 0xd6, 0xc2, 0xc4, 0x1b, 0x6b, 0x8d, 0x89, 0x5f, 0xae, 0x5d, 0xce, 0xea, 0x6a, 0x77, 0x6a, 0x77, 0xb2, 0x86, 0xda, 0x14, 0x6d, 0x0a, 0xcb, 0xd6, 0x9e, 0xd6, 0x9e, 0x66, 0x31, 0x6d, 0x99, 0xf6, 0x4f, 0xe2, 0xaf, 0x68, 0xaf, 0x10, 0x5f, 0xaf, 0xad, 0x67, 0x1e, 0x6d, 0x83, 0xb6, 0x81, 0xd9, 0xb5, 0x77, 0xb5, 0x77, 0x29, 0xfd, 0x91, 0xf6, 0x11, 0xf1, 0x8f, 0xb5, 0x8f, 0x89, 0x7f, 0xa5, 0x7d, 0xc5, 0x3c, 0xba, 0xa1, 0x1b, 0xc4, 0x43, 0x7a, 0x88, 0x85, 0xf5, 0x88, 0x4e, 0xf3, 0x97, 0x9e, 0xa1, 0x67,\n\t0x30, 0x43, 0xcf, 0xd4, 0x33, 0x29, 0x9d, 0xab, 0xe7, 0x12, 0x6f, 0xaf, 0xb7, 0x27, 0x49, 0x6f, 0xfd, 0x1a, 0x66, 0xd7, 0xfb, 0xe8, 0x7d, 0x28, 0xff, 0x2d, 0xfa, 0x70, 0x4a, 0xdf, 0xa1, 0xdf, 0x41, 0xe9, 0xbb, 0xf4, 0xbb, 0xe8, 0xe8, 0x18, 0x7d, 0x0c, 0xf1, 0x3d, 0xfa, 0x1e, 0x96, 0xa9, 0x1f, 0xd0, 0xbf, 0x62, 0x01, 0xfd, 0xb0, 0x7e, 0x84, 0x05, 0xe8, 0x69, 0xd0, 0x99, 0x46, 0xef, 0x58, 0x63, 0x1a, 0x8d, 0x5e, 0x31, 0xaa, 0xad, 0xf1, 0x9c, 0x87, 0xf1, 0x9c, 0x8f, 0x31, 0x9c, 0x43, 0x63, 0x78, 0x0d, 0xcb, 0x35, 0xd6, 0x1a, 0x6b, 0x59, 0x23, 0x8c, 0xe4, 0x06, 0x18, 0xc9, 0x06, 0x46, 0xf2, 0x79, 0x18, 0xc9, 0x29, 0xc6, 0xdb, 0xc6, 0x26, 0x92, 0x6c, 0xa6, 0xf1, 0x6c, 0x18, 0xef, 0x1b, 0xef, 0xb3, 0x0c, 0xa3, 0xd4, 0x28, 0xa5, 0xf4, 0x07, 0xc6, 0x07, 0xac, 0x36, 0x46,\n\t0x78, 0x1d, 0x20, 0x2c, 0xb2, 0xf9, 0x57, 0xf3, 0xaf, 0x4c, 0x37, 0x57, 0x9a, 0x2b, 0x59, 0xc4, 0x5c, 0x65, 0xae, 0x62, 0x0e, 0x73, 0xb5, 0xb9, 0x9a, 0xf9, 0xcc, 0x57, 0xcd, 0x57, 0x99, 0xc7, 0xdc, 0x68, 0x6e, 0x64, 0x4e, 0xf3, 0x6d, 0xf3, 0x6d, 0x56, 0x93, 0x49, 0x7a, 0x77, 0xa1, 0x12, 0xfa, 0x3c, 0xa3, 0x90, 0x2c, 0xcb, 0x4b, 0xf1, 0x2e, 0xf5, 0x23, 0xb2, 0x32, 0x36, 0x93, 0x45, 0xf3, 0x09, 0x59, 0xbb, 0xbb, 0xc8, 0x72, 0xda, 0x40, 0xb6, 0xd9, 0x6b, 0xf1, 0x31, 0xf1, 0xce, 0x64, 0x89, 0x3e, 0x40, 0xb2, 0x0d, 0x64, 0x11, 0xd6, 0x8d, 0x7f, 0x4e, 0xfb, 0xdb, 0x69, 0x5d, 0x62, 0x9c, 0x7b, 0x0d, 0xf8, 0xa7, 0xe0, 0x00, 0xef, 0xc5, 0x27, 0x26, 0xfc, 0x1d, 0xb7, 0xd0, 0x5a, 0x78, 0x14, 0xd5, 0xec, 0x43, 0xb2, 0xb9, 0x86, 0xc5, 0xdb, 0x90, 0x64, 0x34, 0xc9, 0x5e, 0xa3,\n\t0xfa, 0xd7, 0xc5, 0xf1, 0xe1, 0xc2, 0x52, 0xa7, 0xa3, 0x4b, 0xc8, 0x1a, 0x5c, 0x42, 0x56, 0x89, 0x16, 0xdf, 0x13, 0x6f, 0xc0, 0xfe, 0x47, 0x7f, 0xf1, 0x1b, 0x13, 0xfb, 0xf9, 0x49, 0xb2, 0x4d, 0x67, 0xe4, 0x7a, 0x8a, 0xee, 0xe1, 0x29, 0x6a, 0xf9, 0x97, 0xe2, 0xcb, 0xe2, 0x6d, 0xe2, 0x37, 0x10, 0x6d, 0xa1, 0x5f, 0xf9, 0x64, 0x03, 0x8e, 0xa6, 0x5e, 0x78, 0x9e, 0xd2, 0xf7, 0x51, 0x4f, 0x3c, 0x1f, 0x9f, 0x29, 0xde, 0x14, 0xfe, 0x1b, 0xb5, 0x38, 0x87, 0xed, 0x26, 0xde, 0xef, 0x57, 0x89, 0x47, 0x38, 0x1c, 0x7f, 0xe5, 0x2c, 0x56, 0xc8, 0x4d, 0xc9, 0xef, 0x90, 0xad, 0xb7, 0xc8, 0x48, 0x27, 0xe4, 0x62, 0x6d, 0x8a, 0xfd, 0xab, 0xff, 0x56, 0xed, 0x36, 0x9d, 0x55, 0xfa, 0x65, 0xfc, 0x86, 0x2a, 0x92, 0x17, 0xe3, 0xaf, 0xc4, 0x1f, 0x3c, 0x6d, 0x53, 0x25, 0xf6, 0x2f, 0xc7, 0xaf,\n\t0x15, 0xb8, 0x8a, 0x88, 0xb9, 0x88, 0x97, 0xc6, 0xfb, 0x5b, 0x78, 0x11, 0x59, 0x75, 0x6f, 0xc6, 0xaf, 0x4d, 0xd8, 0x23, 0x8b, 0xe2, 0x47, 0xb0, 0x9f, 0x49, 0xd2, 0x2d, 0x64, 0xad, 0x1f, 0x81, 0xe7, 0xc0, 0xce, 0x72, 0xbf, 0xfa, 0xdf, 0xa8, 0xdd, 0x59, 0xef, 0x89, 0x74, 0x6a, 0x6c, 0x15, 0xc9, 0x34, 0xaa, 0xdf, 0xdf, 0x2b, 0x7e, 0x1d, 0xad, 0x68, 0xbb, 0xf1, 0x15, 0x7e, 0xd4, 0x6f, 0x53, 0x1f, 0x8e, 0xa9, 0xf0, 0x5d, 0x18, 0x9f, 0x48, 0x2d, 0x4f, 0xec, 0xd7, 0x51, 0x99, 0x9f, 0x91, 0x9e, 0xff, 0x00, 0xbf, 0xe8, 0x32, 0xfa, 0xf5, 0x43, 0x79, 0xee, 0x73, 0xe2, 0x56, 0x7b, 0xe3, 0x93, 0xe8, 0x3e, 0xb6, 0xc1, 0x33, 0xe0, 0x1b, 0xea, 0x99, 0xed, 0x18, 0x1f, 0x73, 0x84, 0xa7, 0x78, 0x7c, 0x0a, 0xc9, 0xc4, 0xef, 0x7c, 0xb2, 0x1f, 0xb6, 0xd3, 0x48, 0x59, 0x54, 0x39, 0xc6,\n\t0x40, 0x1c, 0xf9, 0x93, 0x75, 0x5f, 0x20, 0x34, 0x2b, 0xcb, 0xd3, 0xd4, 0x77, 0x02, 0x77, 0x58, 0x51, 0x71, 0x74, 0xae, 0x85, 0x9c, 0x81, 0x3f, 0x5f, 0xe1, 0xd5, 0xf3, 0x5e, 0xb9, 0x37, 0x87, 0x65, 0xfb, 0x58, 0x76, 0xa3, 0xe5, 0xa5, 0xcd, 0xbc, 0x95, 0xf1, 0xb3, 0x24, 0xbf, 0x6b, 0x6f, 0x25, 0xc9, 0x4b, 0x56, 0x9f, 0xc5, 0xd7, 0x52, 0x2b, 0xbf, 0x1d, 0xdf, 0x4f, 0x9a, 0xf4, 0xce, 0x99, 0x08, 0x32, 0xe2, 0x52, 0xae, 0x48, 0xa4, 0x5b, 0xc7, 0x9f, 0x11, 0x68, 0x4b, 0xb9, 0x07, 0x02, 0xa5, 0xda, 0x9c, 0x1e, 0xbd, 0xe5, 0x78, 0x40, 0x7c, 0x46, 0xfc, 0xae, 0xf8, 0xb0, 0x44, 0x7a, 0x18, 0x4b, 0x2b, 0xd7, 0xfc, 0x04, 0xde, 0x92, 0x5f, 0xa1, 0x11, 0x49, 0xb5, 0x41, 0xfe, 0x46, 0x15, 0x3f, 0x53, 0xe1, 0x11, 0x70, 0x1f, 0x8e, 0x8c, 0xa0, 0x6b, 0x2e, 0x26, 0xad, 0x59, 0x1a,\n\t0xbf, 0x31, 0x3e, 0xfb, 0xdf, 0x6a, 0xdf, 0x73, 0x62, 0x23, 0xa2, 0xdf, 0x2b, 0xfe, 0xea, 0x27, 0xf6, 0xb5, 0xc1, 0xd5, 0x4a, 0x19, 0xcf, 0x36, 0x2f, 0xd6, 0x4e, 0xec, 0x43, 0x49, 0x1e, 0x48, 0xae, 0xdf, 0xc6, 0xcf, 0xab, 0xda, 0xf7, 0x67, 0xb1, 0x9e, 0x3f, 0x2c, 0xd7, 0xf4, 0x24, 0x61, 0x6e, 0x62, 0x8f, 0xb9, 0x9b, 0x6c, 0x94, 0xe4, 0xbf, 0xbc, 0xb3, 0x5c, 0xaa, 0x6e, 0x62, 0x1f, 0xa5, 0xfa, 0x95, 0xff, 0x55, 0xf2, 0x94, 0x3a, 0x95, 0x40, 0x15, 0x4e, 0x7d, 0x1f, 0x97, 0x7f, 0xa5, 0xc6, 0x37, 0xc7, 0x5d, 0xa7, 0x2a, 0x66, 0x45, 0xab, 0x47, 0x7e, 0xf5, 0x0e, 0x57, 0xff, 0x9b, 0x63, 0x60, 0x12, 0x3c, 0x77, 0x9a, 0xc4, 0xcf, 0xaf, 0x8c, 0x63, 0x9f, 0x1d, 0x35, 0x00, 0x8e, 0xf6, 0x4d, 0x25, 0x04, 0xe0, 0x60, 0x45, 0xbc, 0xd6, 0xb1, 0x72, 0xeb, 0xfd, 0xdc, 0x28, 0xec,\n\t0xd9, 0xbc, 0x6d, 0x12, 0x48, 0xfd, 0x6f, 0x9e, 0xf3, 0xeb, 0x18, 0xc6, 0x39, 0xce, 0x79, 0x2e, 0xf9, 0xec, 0x44, 0x1c, 0xc6, 0xe0, 0xf8, 0xa8, 0xca, 0xf3, 0x0c, 0xa5, 0xae, 0x8e, 0xf7, 0xb1, 0x66, 0xf0, 0x4a, 0x35, 0xdb, 0xfd, 0x5b, 0xef, 0x42, 0xe2, 0x57, 0x57, 0x07, 0xd5, 0xae, 0x3c, 0x22, 0x2a, 0x30, 0xd8, 0x67, 0x2a, 0xbc, 0x6b, 0xbe, 0x42, 0xdb, 0x21, 0x52, 0xe9, 0x4f, 0xfb, 0x93, 0xc8, 0x46, 0x6e, 0x49, 0x16, 0x06, 0x83, 0x85, 0x61, 0xc0, 0xc2, 0x30, 0x61, 0x61, 0x38, 0xf8, 0x7e, 0xfe, 0x15, 0x73, 0xc9, 0x4f, 0xca, 0x4f, 0x92, 0xbd, 0x29, 0xac, 0x04, 0xbf, 0xbc, 0x93, 0xec, 0x80, 0x20, 0xd9, 0x01, 0xbb, 0xc9, 0x1a, 0x15, 0xab, 0xfb, 0x48, 0xc5, 0x3b, 0xb2, 0x5f, 0x58, 0x8a, 0xb9, 0xd8, 0x7c, 0x99, 0x35, 0xa4, 0x12, 0xa3, 0x09, 0xeb, 0xe6, 0xb4, 0x5d, 0x23,\n\t0xc1, 0xae, 0x91, 0x61, 0xd7, 0x28, 0xb0, 0x6b, 0x64, 0xd8, 0x35, 0x0a, 0xae, 0x6a, 0xc3, 0x55, 0x6d, 0xb8, 0xaa, 0x1d, 0x6f, 0x8e, 0x55, 0xbc, 0x39, 0xd6, 0xf0, 0xe6, 0x58, 0x87, 0x07, 0xb4, 0x81, 0x7a, 0x98, 0xa8, 0x87, 0x03, 0xf5, 0x70, 0xa2, 0x1e, 0x4e, 0xd4, 0xc3, 0x85, 0x7a, 0xd8, 0xf0, 0xae, 0x4e, 0xc5, 0xbb, 0x3a, 0x0d, 0xef, 0xea, 0x74, 0x78, 0x86, 0x1a, 0xa8, 0x99, 0x49, 0xb5, 0xe8, 0x82, 0xf7, 0xf6, 0x3a, 0x7c, 0xd7, 0x5d, 0x78, 0x6f, 0x5f, 0x1b, 0x6f, 0xec, 0x6b, 0xe3, 0x5d, 0x7d, 0x18, 0x6f, 0xe9, 0x6b, 0xe3, 0xfd, 0x7c, 0x6d, 0xbc, 0x93, 0x6f, 0x88, 0x77, 0xf2, 0x79, 0x78, 0x27, 0x7f, 0x3e, 0xde, 0xc9, 0xa7, 0xe3, 0x9d, 0x7c, 0x4b, 0xbc, 0x93, 0xaf, 0x87, 0x77, 0xf2, 0x2d, 0xf0, 0x4e, 0xde, 0x8b, 0x77, 0xf2, 0x06, 0xde, 0xc9, 0x3b, 0xf0, 0x4e, 0xde,\n\t0xc0, 0x3b, 0xf9, 0x0e, 0x78, 0x27, 0x2f, 0xe1, 0x9d, 0xbc, 0x02, 0xbf, 0xf4, 0x4e, 0xf0, 0x5a, 0xe9, 0x84, 0xf7, 0xf3, 0x06, 0x3c, 0xd2, 0x3b, 0xe1, 0x2d, 0xbd, 0x03, 0xfe, 0x2a, 0x9d, 0xf0, 0xae, 0x5e, 0xc3, 0xbb, 0xfa, 0x0e, 0x78, 0x57, 0xdf, 0x1e, 0x1e, 0x29, 0xed, 0xf0, 0xc6, 0xbe, 0x0e, 0xde, 0xd8, 0xd7, 0xc7, 0x1b, 0xfb, 0xd6, 0x78, 0x63, 0xdf, 0x04, 0x6f, 0xec, 0x0b, 0xd9, 0xdb, 0x44, 0x39, 0xb0, 0x96, 0x6d, 0x40, 0x62, 0xec, 0x40, 0x62, 0x2e, 0x01, 0x12, 0xd3, 0x15, 0x48, 0xcc, 0xc5, 0x6c, 0x2f, 0x11, 0x87, 0x2d, 0x1d, 0x82, 0x2d, 0xdd, 0x05, 0xb6, 0x74, 0x08, 0xb6, 0x74, 0x10, 0xb6, 0x74, 0x73, 0x58, 0xd1, 0x32, 0xac, 0xe8, 0x7c, 0x58, 0xd1, 0x51, 0xd8, 0xcf, 0xd9, 0xb0, 0x9c, 0xf3, 0x61, 0x39, 0x67, 0xc0, 0x72, 0x2e, 0x82, 0xe5, 0x7c, 0x01, 0x2c, 0xe7,\n\t0x54, 0x58, 0xce, 0x45, 0xb0, 0x9c, 0x23, 0xb0, 0x9c, 0x8b, 0x60, 0x39, 0xfb, 0x60, 0x39, 0x17, 0xc1, 0x72, 0xce, 0x84, 0xcd, 0xec, 0x83, 0xcd, 0x5c, 0x04, 0x9b, 0xb9, 0x29, 0x6c, 0xe6, 0x22, 0xd8, 0xcc, 0x45, 0xb0, 0x99, 0xd3, 0x60, 0x33, 0xfb, 0x60, 0x33, 0x17, 0xc1, 0x66, 0xae, 0x05, 0x9b, 0x39, 0x00, 0x9b, 0xf9, 0x22, 0x68, 0x55, 0x2e, 0x6c, 0xe6, 0x8b, 0xa0, 0x5b, 0xb9, 0xd0, 0xad, 0xf3, 0xa0, 0x5b, 0x35, 0xa1, 0x5b, 0x35, 0xa0, 0x5b, 0x35, 0xa1, 0x5b, 0x35, 0xa0, 0x5b, 0x29, 0xd0, 0xad, 0x14, 0xe8, 0x56, 0x03, 0xe8, 0x56, 0x6d, 0xe8, 0x56, 0x1e, 0x74, 0xcb, 0x80, 0x6e, 0xb5, 0x83, 0x77, 0x7d, 0x63, 0x78, 0x28, 0xd4, 0x86, 0x77, 0x7d, 0x63, 0x78, 0x28, 0xd4, 0x86, 0x57, 0x42, 0xed, 0x8a, 0x98, 0xa1, 0x5e, 0xac, 0x1e, 0x7c, 0x13, 0x5a, 0xc0, 0x37, 0xa1, 0x36,\n\t0xbc, 0x12, 0x5a, 0xc0, 0x2b, 0x21, 0x0f, 0xfe, 0x08, 0xf5, 0xe0, 0x8f, 0x90, 0x07, 0x4f, 0x84, 0x16, 0xf0, 0x44, 0x30, 0xe0, 0x89, 0xe0, 0x80, 0x5f, 0x7d, 0x27, 0x78, 0x07, 0x75, 0x82, 0x57, 0x42, 0x7b, 0x78, 0x25, 0x14, 0x26, 0x79, 0x07, 0x49, 0xf0, 0x4a, 0x70, 0xc0, 0x2b, 0xa1, 0x10, 0x5e, 0x09, 0x1a, 0xbc, 0x12, 0x1c, 0xf0, 0x4a, 0x68, 0x02, 0xaf, 0x84, 0x42, 0x78, 0x25, 0x74, 0x80, 0x57, 0x42, 0x7b, 0xcb, 0x3b, 0x08, 0xa3, 0xa2, 0xad, 0xfc, 0x8c, 0xfc, 0x0c, 0xcb, 0x01, 0x22, 0x10, 0x92, 0x17, 0xca, 0xcf, 0x33, 0x0e, 0x5c, 0x20, 0x04, 0x5c, 0x20, 0x04, 0x5c, 0x20, 0x04, 0x5c, 0xa0, 0x39, 0x70, 0x81, 0x0c, 0xe0, 0x02, 0xf9, 0xc0, 0x05, 0x32, 0x80, 0x0b, 0xb8, 0x81, 0x0b, 0xb4, 0x02, 0x2e, 0x90, 0x01, 0x5c, 0x20, 0x1b, 0x23, 0xad, 0x00, 0xb8, 0x80, 0x0c, 0x5c,\n\t0x20, 0x1b, 0x88, 0x40, 0x3e, 0x10, 0x81, 0x56, 0x40, 0x04, 0x9c, 0x40, 0x04, 0x64, 0x20, 0x02, 0x45, 0x40, 0x04, 0x2e, 0x00, 0x22, 0x50, 0x04, 0x44, 0x20, 0x13, 0x88, 0x40, 0x11, 0x10, 0x01, 0x1f, 0x10, 0x81, 0x4c, 0x8c, 0xd5, 0x2c, 0x20, 0x02, 0xcd, 0x80, 0x08, 0x64, 0x02, 0x11, 0x68, 0x0a, 0x44, 0xa0, 0x08, 0x88, 0x80, 0x1f, 0x88, 0x40, 0x11, 0x10, 0x81, 0x08, 0x10, 0x81, 0x22, 0x20, 0x02, 0x4d, 0x81, 0x08, 0x14, 0x01, 0x11, 0x88, 0x01, 0x11, 0xf0, 0x01, 0x11, 0x28, 0x02, 0x22, 0xd0, 0x0c, 0x88, 0x80, 0x0f, 0x88, 0x40, 0x04, 0x88, 0x40, 0x11, 0xb0, 0x80, 0x7c, 0xa0, 0x00, 0xf9, 0xb0, 0xff, 0x8b, 0x60, 0xff, 0x17, 0xc1, 0xfe, 0x2f, 0x82, 0xfd, 0xef, 0x83, 0xfd, 0xef, 0x83, 0x67, 0x87, 0x02, 0x14, 0xa0, 0x33, 0x50, 0x80, 0xce, 0x40, 0x01, 0x2e, 0x04, 0x0a, 0xd0,\n\t0x11, 0x28, 0xc0, 0x85, 0x40, 0x01, 0x3a, 0xc2, 0xef, 0xa3, 0x03, 0x3c, 0x3e, 0x3a, 0xc0, 0xe3, 0xa3, 0x36, 0xf0, 0xb3, 0xae, 0xf0, 0xf8, 0x30, 0xe0, 0xeb, 0xe1, 0x80, 0x17, 0x56, 0x3b, 0xe0, 0x05, 0xa9, 0xc0, 0x0b, 0x7c, 0x40, 0x0a, 0xf2, 0x81, 0x14, 0x84, 0x80, 0x14, 0xb4, 0xb1, 0xfd, 0x64, 0xfb, 0x89, 0xe5, 0xc0, 0x53, 0xab, 0x13, 0xfc, 0x41, 0xda, 0xc3, 0x1f, 0xc4, 0x80, 0x3f, 0x88, 0x85, 0x23, 0x78, 0xe0, 0x15, 0xa2, 0x03, 0x4d, 0xf0, 0xc0, 0x37, 0x44, 0x47, 0xb4, 0x82, 0x0b, 0xbe, 0x21, 0xb5, 0x81, 0x2f, 0xe4, 0xab, 0xb7, 0xaa, 0xb7, 0xb2, 0x1c, 0xf8, 0x89, 0xd4, 0x86, 0x27, 0x48, 0x6d, 0xf8, 0x7a, 0x84, 0xe1, 0xeb, 0x11, 0x86, 0x4f, 0x47, 0x6d, 0x2d, 0xa8, 0x85, 0x58, 0x0e, 0x90, 0x88, 0x7c, 0xf8, 0x77, 0xd4, 0xd6, 0xea, 0x6b, 0xf5, 0x49, 0x92, 0xab, 0xe5,\n\t0x12, 0x6f, 0xa4, 0xe5, 0x13, 0x17, 0x08, 0x45, 0x3e, 0xfc, 0x3e, 0x6a, 0xc3, 0xbf, 0xa3, 0x21, 0xd0, 0x8a, 0x0c, 0x78, 0x79, 0x34, 0x84, 0x97, 0x47, 0x43, 0x78, 0x79, 0xe4, 0xc1, 0xcb, 0xe3, 0x7c, 0x78, 0x79, 0xa4, 0x03, 0xcb, 0x68, 0x05, 0x5f, 0x8f, 0x96, 0xf0, 0xf5, 0xa8, 0xa7, 0x8d, 0xd1, 0xc6, 0xb0, 0xba, 0xda, 0x58, 0x6d, 0x2c, 0x71, 0xe1, 0xf7, 0x51, 0x4f, 0x9b, 0xac, 0x3d, 0x42, 0x69, 0x81, 0x77, 0xb8, 0xe1, 0x03, 0xd2, 0x02, 0x3e, 0x20, 0x2d, 0xe0, 0x03, 0xe2, 0x05, 0x02, 0xa2, 0xc2, 0x13, 0xc4, 0x0b, 0x1c, 0x44, 0x85, 0x3f, 0x88, 0x17, 0x68, 0x88, 0x0a, 0xaf, 0x10, 0x03, 0x98, 0x88, 0x0f, 0x98, 0x48, 0x08, 0x1e, 0x22, 0x06, 0x3c, 0x44, 0x1c, 0xc0, 0x47, 0x7c, 0xf0, 0x13, 0x71, 0xc0, 0x4f, 0xc4, 0x00, 0x56, 0xe2, 0x03, 0x56, 0xe2, 0x83, 0xcf, 0x88, 0x01,\n\t0x9f, 0x11, 0x03, 0xb8, 0x89, 0x0f, 0x9e, 0x23, 0x06, 0x3c, 0x47, 0x3a, 0xc0, 0x73, 0xa4, 0x03, 0x3c, 0x47, 0x24, 0x78, 0x8e, 0x28, 0x40, 0x55, 0x7c, 0xf0, 0x1f, 0x51, 0x80, 0xad, 0xd4, 0x02, 0xaa, 0x52, 0xa4, 0x5f, 0xa0, 0x5f, 0xc0, 0x2e, 0x06, 0x9e, 0x52, 0x04, 0x3f, 0xb4, 0x4e, 0xf0, 0x43, 0xeb, 0x04, 0x3f, 0xb4, 0x4e, 0xf0, 0x34, 0xb1, 0x70, 0x96, 0x10, 0x70, 0x16, 0x1f, 0xbc, 0x4e, 0x0c, 0xa0, 0x2d, 0x21, 0xa0, 0x2d, 0x3e, 0x78, 0xa0, 0x18, 0xc0, 0x5c, 0x8a, 0xe0, 0xa5, 0xd6, 0x09, 0xc8, 0x4b, 0x11, 0x7c, 0xd5, 0x3a, 0xc1, 0x57, 0xad, 0x13, 0xfc, 0x53, 0x34, 0xf8, 0xa7, 0x68, 0xf0, 0x4f, 0x69, 0x0f, 0x2f, 0xb5, 0x76, 0xf0, 0x52, 0x6b, 0x07, 0x2f, 0xb5, 0x76, 0xf0, 0x58, 0xa9, 0x03, 0x8f, 0x95, 0xfa, 0x40, 0x6d, 0x9a, 0xc1, 0x6f, 0xa5, 0x35, 0xfc, 0x56, 0x9a,\n\t0x00, 0xc1, 0x69, 0x04, 0xef, 0x95, 0x26, 0xc0, 0x71, 0x1a, 0xc1, 0x87, 0xa5, 0x10, 0x68, 0x8e, 0x0d, 0xd8, 0xad, 0x1d, 0xd8, 0xed, 0x25, 0xc0, 0x6e, 0x2f, 0x01, 0x76, 0xdb, 0x15, 0xd8, 0x6d, 0x57, 0x63, 0x8c, 0x71, 0x2f, 0xe3, 0x40, 0x7c, 0xba, 0x00, 0xf1, 0x09, 0x02, 0xf1, 0x69, 0x6e, 0xac, 0x34, 0x56, 0xb2, 0x1c, 0x20, 0x3e, 0x51, 0x20, 0x3e, 0xd9, 0x40, 0x79, 0x8a, 0x80, 0xf2, 0x5c, 0x00, 0x94, 0x27, 0x15, 0x28, 0x4f, 0x11, 0x50, 0x9e, 0x22, 0xa0, 0x3c, 0x4d, 0x81, 0xf2, 0x14, 0x01, 0xe5, 0x49, 0x83, 0xd7, 0x5c, 0x27, 0x3c, 0x9b, 0x53, 0xf0, 0x6c, 0xae, 0x8d, 0x67, 0x73, 0x1e, 0x9e, 0xcd, 0x06, 0x9e, 0xcd, 0xed, 0x80, 0xfe, 0xb4, 0x31, 0x5f, 0x34, 0x5f, 0x64, 0x6d, 0xcd, 0x7f, 0x9a, 0xcb, 0x89, 0x0b, 0x0c, 0x28, 0x1f, 0x18, 0x50, 0x0c, 0x18, 0x90, 0x0f, 0x5e,\n\t0x36, 0x0e, 0xea, 0xab, 0x03, 0x62, 0xf8, 0x1b, 0x5b, 0x4c, 0xf1, 0x3f, 0x3e, 0x3a, 0xe2, 0x6d, 0xf0, 0x7d, 0xf1, 0x71, 0x64, 0x2f, 0x0a, 0xfe, 0x1a, 0xfb, 0x9f, 0xfe, 0x25, 0xbe, 0x08, 0xf0, 0x55, 0x85, 0xe7, 0xc0, 0x91, 0xf8, 0xe7, 0xf1, 0xaf, 0x11, 0x25, 0xbe, 0x82, 0x52, 0xa5, 0xb4, 0x22, 0x16, 0x5e, 0xd4, 0xfb, 0x44, 0x4c, 0xeb, 0x7f, 0xb1, 0x56, 0x93, 0xe2, 0xcf, 0xc5, 0x4f, 0xd2, 0x55, 0xcb, 0x5b, 0x27, 0x06, 0x6e, 0xd9, 0x80, 0xb7, 0xc2, 0x83, 0x7d, 0xc7, 0x69, 0x6c, 0xe2, 0x4f, 0xae, 0xcb, 0xa8, 0xf8, 0xfd, 0xf1, 0x6f, 0x4f, 0x7b, 0xa4, 0x27, 0xfe, 0x1c, 0xe5, 0x36, 0x58, 0xfc, 0x6f, 0xbf, 0xf6, 0x0d, 0x8b, 0xff, 0x48, 0x0d, 0x92, 0xbe, 0x11, 0x51, 0x39, 0x96, 0xa3, 0xdc, 0x8b, 0x3e, 0x11, 0x4b, 0xf3, 0xfd, 0x7f, 0xb5, 0x8f, 0x1e, 0x16, 0x76, 0x74, 0xf9,\n\t0xd7, 0x1c, 0xe8, 0xcf, 0x5d, 0xe5, 0xf8, 0xac, 0xff, 0xba, 0x2e, 0x7f, 0xce, 0xfe, 0xcf, 0xfc, 0x91, 0xad, 0xf9, 0x0d, 0x6d, 0x3f, 0x90, 0x9d, 0xf4, 0x6d, 0xfc, 0xa7, 0xf8, 0x77, 0x88, 0x1d, 0xfa, 0xb6, 0x5a, 0x91, 0x4b, 0xff, 0xce, 0xd5, 0x2c, 0x84, 0xe6, 0x7d, 0x78, 0xf8, 0x6d, 0x89, 0xbf, 0x02, 0x5f, 0x8d, 0x87, 0x2a, 0x50, 0xa0, 0x8f, 0xf1, 0xae, 0xfb, 0x3b, 0x78, 0xbe, 0x3c, 0x0a, 0xff, 0x23, 0x2b, 0x66, 0xfe, 0x93, 0xf8, 0xb4, 0xf8, 0xc4, 0xf8, 0xf4, 0xea, 0x7d, 0x0d, 0xa6, 0xda, 0x75, 0xf9, 0xf8, 0x2c, 0x5e, 0x7a, 0x0b, 0xcf, 0xf4, 0x52, 0x88, 0x2f, 0xb4, 0xf0, 0x3d, 0x0b, 0xbf, 0x88, 0x1f, 0x40, 0x44, 0xfe, 0x9b, 0xff, 0xe1, 0x76, 0x59, 0x8c, 0x58, 0xfe, 0xd5, 0xf0, 0xe3, 0x5b, 0x19, 0x7f, 0x1e, 0x5f, 0x22, 0x18, 0x97, 0x8c, 0x94, 0xc6, 0x57, 0xe3, 0x2b,\n\t0x23, 0xe3, 0xe2, 0x0f, 0xc0, 0x7b, 0x6b, 0x3a, 0x5a, 0x67, 0x15, 0xf6, 0x33, 0xfe, 0xd8, 0x78, 0x8b, 0x3f, 0x02, 0x2f, 0xb6, 0x49, 0xf1, 0xc9, 0xf1, 0x45, 0xd4, 0xfb, 0xfb, 0x2b, 0x7c, 0xa5, 0x02, 0xe0, 0x35, 0x2c, 0x74, 0x5d, 0x60, 0xd9, 0xf1, 0x5d, 0x56, 0x7f, 0xfc, 0x4a, 0x59, 0x77, 0x60, 0xee, 0xfe, 0x57, 0xfc, 0x1d, 0xea, 0xdf, 0x1f, 0x68, 0xde, 0xde, 0x41, 0x77, 0x76, 0x92, 0x68, 0x21, 0x7c, 0xe4, 0xfe, 0x51, 0xed, 0x3a, 0x7d, 0x18, 0xdf, 0x1d, 0xff, 0xf9, 0x0c, 0x4f, 0x11, 0x47, 0x02, 0x41, 0x38, 0x19, 0x7f, 0xeb, 0xb7, 0x3c, 0x84, 0x92, 0xca, 0xfa, 0xa4, 0xdc, 0x53, 0x0d, 0xef, 0x2e, 0xa2, 0x02, 0xbd, 0x10, 0xdf, 0xfe, 0xf9, 0x7f, 0xd5, 0x28, 0xfc, 0x81, 0xb4, 0x7f, 0x0f, 0x6d, 0x3f, 0xd2, 0xbd, 0xfd, 0x48, 0x3a, 0xf6, 0xd3, 0xaf, 0xf9, 0xc7, 0xfd, 0xc9,\n\t0x75, 0x39, 0x48, 0xad, 0xff, 0x39, 0xe9, 0xd8, 0xfe, 0xf8, 0x17, 0xe2, 0x0b, 0x41, 0x54, 0x9b, 0xed, 0xf4, 0x34, 0x3e, 0x7a, 0x46, 0xbe, 0xf7, 0x91, 0xe7, 0xfd, 0x33, 0xfd, 0x4b, 0xf0, 0x4d, 0x95, 0xef, 0x49, 0x07, 0xaa, 0x35, 0x0f, 0xd2, 0x35, 0x7e, 0x12, 0xcf, 0x0f, 0xd2, 0x98, 0xaf, 0x80, 0x6e, 0x9f, 0x4c, 0x60, 0xc8, 0x07, 0xce, 0x78, 0xd6, 0xfd, 0xea, 0x5b, 0x8d, 0x3f, 0xbd, 0x5d, 0x8e, 0x03, 0xa7, 0xfb, 0x1c, 0x5f, 0x99, 0xfa, 0x96, 0xf6, 0x5f, 0xe1, 0xfb, 0x1a, 0xc7, 0xfe, 0xe3, 0xd7, 0xa9, 0x16, 0x5e, 0x05, 0x7d, 0x16, 0x5f, 0xb5, 0xfa, 0x96, 0xe8, 0x7b, 0xa1, 0x31, 0x68, 0xc1, 0x0f, 0xe2, 0x3b, 0x19, 0x67, 0xb7, 0xb2, 0xab, 0x58, 0x2f, 0xc4, 0xef, 0xbf, 0xcd, 0xde, 0x61, 0x9b, 0xc9, 0xba, 0x33, 0xc8, 0xaa, 0x6b, 0xa3, 0xb4, 0x53, 0xda, 0x2b, 0x1d, 0x94,\n\t0x0b, 0x95, 0x8b, 0x94, 0x8b, 0x95, 0x4b, 0xc8, 0x9e, 0xbb, 0x94, 0xac, 0xb9, 0x61, 0x64, 0xb9, 0xdd, 0x4f, 0x16, 0xdb, 0x03, 0x64, 0xa9, 0x3d, 0x68, 0x5b, 0x63, 0xdb, 0x62, 0x7b, 0x8f, 0x2c, 0xae, 0x9f, 0x6c, 0x27, 0xc8, 0x8e, 0x22, 0xeb, 0x49, 0xed, 0x4f, 0xb6, 0xd2, 0xad, 0xea, 0x38, 0xf5, 0x7e, 0x75, 0xbc, 0x3a, 0x41, 0x9d, 0xa9, 0x3e, 0xa1, 0xce, 0x52, 0x9f, 0x54, 0x67, 0xab, 0x4f, 0xa9, 0x73, 0xd4, 0xa7, 0xd5, 0xb9, 0xea, 0x22, 0xf5, 0x05, 0x75, 0x99, 0xfa, 0x4f, 0x75, 0xb9, 0xfa, 0xb2, 0xba, 0x42, 0x5d, 0xa9, 0xae, 0x52, 0x5f, 0x51, 0x57, 0xab, 0xaf, 0xaa, 0x6b, 0xd4, 0xd7, 0xd4, 0xb5, 0xea, 0xeb, 0xea, 0x3a, 0xf5, 0x0d, 0x75, 0xbd, 0xfa, 0xa6, 0xba, 0x41, 0x7d, 0x4f, 0xdd, 0xaa, 0xbe, 0xaf, 0x7e, 0xa2, 0xee, 0x52, 0x3f, 0x55, 0x77, 0xab, 0x9f, 0xa9, 0x7b,\n\t0xd4, 0xcf, 0xd5, 0xbd, 0xea, 0xbf, 0xd4, 0x7d, 0xea, 0x17, 0xea, 0x7e, 0xf5, 0xa4, 0x66, 0x13, 0xb6, 0x16, 0x59, 0x57, 0x39, 0x5a, 0x03, 0xb2, 0xae, 0x1a, 0x6a, 0x79, 0xc2, 0xba, 0xd2, 0x4e, 0xe9, 0xcd, 0xf5, 0x16, 0x7a, 0x4b, 0xbd, 0x95, 0x5e, 0xa8, 0xb7, 0xd6, 0xdb, 0xe8, 0x6d, 0x8d, 0x95, 0xe6, 0x46, 0xf3, 0x6d, 0x26, 0xb1, 0x86, 0xb8, 0x4b, 0x15, 0xf7, 0xa9, 0x02, 0xc1, 0xf1, 0xd2, 0xdd, 0xbe, 0xc3, 0x5c, 0x6c, 0x33, 0x91, 0x07, 0xef, 0xb4, 0xb9, 0xb8, 0x67, 0x26, 0x89, 0xbb, 0x66, 0x32, 0xde, 0x6c, 0x73, 0xbc, 0xd3, 0x56, 0xc4, 0xfd, 0x33, 0x9b, 0x68, 0x01, 0x66, 0x47, 0x2c, 0xbd, 0x0a, 0x0b, 0x56, 0x83, 0x05, 0xab, 0xc1, 0x82, 0xd5, 0x61, 0xc1, 0x1a, 0xb0, 0x60, 0x75, 0x58, 0xb0, 0x06, 0xb5, 0xcf, 0x1a, 0xe6, 0x15, 0x6d, 0xc4, 0xd4, 0xc4, 0x1b, 0x6c, 0x61,\n\t0x8b, 0x3a, 0x6d, 0x27, 0x6c, 0x27, 0x98, 0x17, 0x96, 0xa7, 0x09, 0x9b, 0xd3, 0xa4, 0x76, 0xeb, 0xcf, 0xdc, 0xd6, 0x7b, 0x6c, 0xd8, 0x99, 0x4e, 0xd1, 0x86, 0x64, 0x7f, 0x8e, 0x57, 0xc7, 0x93, 0x7c, 0x82, 0x3a, 0x81, 0xf8, 0x4c, 0xf5, 0x69, 0x92, 0xcc, 0x55, 0xe7, 0x52, 0x9a, 0xda, 0x91, 0x2c, 0xd5, 0x65, 0xea, 0x06, 0xe2, 0xef, 0xa9, 0xef, 0x13, 0xff, 0x44, 0xdd, 0x4f, 0xfc, 0xa4, 0x7a, 0x92, 0x79, 0xa8, 0x6d, 0x6c, 0xc4, 0x85, 0x2d, 0xea, 0xa5, 0x16, 0xca, 0x27, 0x7e, 0x8a, 0x6c, 0x30, 0x95, 0xda, 0xa6, 0x2d, 0x53, 0x61, 0x69, 0x78, 0xf1, 0xa6, 0x97, 0xe3, 0x4d, 0xaf, 0xc2, 0x24, 0x9e, 0x01, 0xac, 0xee, 0x3c, 0x60, 0x75, 0xb5, 0x11, 0x69, 0x63, 0x7d, 0x6d, 0x22, 0x03, 0x91, 0x36, 0x69, 0xc0, 0xed, 0x32, 0x10, 0x69, 0x93, 0x06, 0xf4, 0xae, 0x16, 0x22, 0x6d, 0xd2,\n\t0x80, 0xe1, 0x65, 0x20, 0xd2, 0x26, 0x0d, 0x94, 0x81, 0x48, 0x9b, 0x34, 0x44, 0xda, 0xd4, 0x04, 0xaa, 0x97, 0x0a, 0x54, 0x2f, 0x06, 0x54, 0x2f, 0x0a, 0x54, 0xaf, 0x06, 0x50, 0xbd, 0x14, 0xa0, 0x7a, 0xe9, 0x40, 0xf5, 0x32, 0xd1, 0x1f, 0x96, 0xd7, 0x58, 0x0b, 0x20, 0x6a, 0xad, 0x80, 0xa8, 0x35, 0x03, 0xa2, 0x56, 0x08, 0x44, 0xad, 0x25, 0x10, 0xb5, 0x36, 0x40, 0xd4, 0x5a, 0x03, 0x51, 0xbb, 0x00, 0x88, 0x5a, 0x6b, 0x20, 0x6a, 0x6d, 0x81, 0xa8, 0x79, 0xe0, 0x9d, 0xe2, 0x03, 0xae, 0xe6, 0x05, 0xae, 0x16, 0x06, 0xae, 0x66, 0xc0, 0x3b, 0xa5, 0x09, 0xd0, 0xb5, 0x08, 0xbc, 0x53, 0x4c, 0x60, 0x6c, 0x61, 0x60, 0x6c, 0x01, 0x60, 0x6c, 0x1a, 0x30, 0x36, 0x0e, 0x8c, 0x2d, 0x08, 0x8c, 0x4d, 0x03, 0xc6, 0xe6, 0x02, 0xc6, 0xa6, 0x01, 0x63, 0xd3, 0x81, 0xb1, 0x69, 0xc0, 0xd8, 0xec,\n\t0xf0, 0x4e, 0x39, 0x1f, 0x48, 0x9b, 0x0e, 0xa4, 0x4d, 0x03, 0xd2, 0x16, 0x02, 0xd2, 0xa6, 0x01, 0x69, 0xd3, 0x80, 0xb4, 0xf9, 0x81, 0xb4, 0xe9, 0x40, 0xda, 0x34, 0x20, 0x6d, 0x8d, 0x81, 0xb4, 0x75, 0x00, 0xd2, 0x66, 0x03, 0xd2, 0x26, 0x03, 0x69, 0xb3, 0x01, 0x69, 0x93, 0x81, 0xb4, 0x5d, 0x08, 0xa4, 0xad, 0x1d, 0x30, 0xb6, 0x76, 0x40, 0xd4, 0x24, 0x20, 0x6a, 0x19, 0x40, 0xd4, 0x62, 0x89, 0xef, 0xef, 0x08, 0x14, 0x2d, 0x03, 0x28, 0x5a, 0x5d, 0x44, 0xfb, 0xa4, 0x01, 0x4b, 0xcb, 0x40, 0xb4, 0x4f, 0x1a, 0xa2, 0x7d, 0xd2, 0x80, 0xab, 0x65, 0x00, 0x57, 0xab, 0x0b, 0x5c, 0x2d, 0x1d, 0xb8, 0x5a, 0x26, 0x70, 0xb5, 0x0c, 0xc4, 0xfc, 0xa4, 0x01, 0x5d, 0xcb, 0x04, 0xba, 0x16, 0x43, 0xcc, 0x4f, 0x1a, 0x30, 0xb6, 0x74, 0x60, 0x6c, 0x31, 0xc4, 0xfc, 0xa4, 0x01, 0x69, 0xcb, 0x04,\n\t0x06, 0x56, 0x07, 0x18, 0x58, 0x73, 0x60, 0x60, 0xad, 0x81, 0x81, 0xb5, 0x01, 0x06, 0xd6, 0x1a, 0x18, 0x58, 0x6b, 0x60, 0x60, 0xad, 0x81, 0x81, 0x79, 0x80, 0x81, 0x05, 0x80, 0x81, 0x85, 0x81, 0x81, 0x05, 0x92, 0x7c, 0x63, 0x9c, 0xc0, 0xc0, 0x02, 0xc0, 0xc0, 0x22, 0xc0, 0xc0, 0x9a, 0x02, 0x03, 0xf3, 0x02, 0x03, 0x8b, 0xc0, 0x37, 0xa6, 0x3e, 0x90, 0xb0, 0x30, 0x90, 0x30, 0x27, 0x90, 0xb0, 0x5c, 0x20, 0x61, 0x5e, 0x20, 0x61, 0x1a, 0x90, 0x30, 0x0e, 0x24, 0x4c, 0x03, 0x12, 0x66, 0x07, 0x12, 0xa6, 0x01, 0x09, 0xd3, 0x81, 0x84, 0xd9, 0x81, 0x84, 0x35, 0x02, 0x12, 0xa6, 0x00, 0x09, 0xb3, 0x03, 0x09, 0x0b, 0x01, 0x09, 0xd3, 0x80, 0x84, 0x15, 0x00, 0x09, 0xd3, 0x80, 0x84, 0xb9, 0x80, 0x84, 0x69, 0x40, 0xc2, 0x42, 0x40, 0xc2, 0x34, 0x20, 0x61, 0xf5, 0x80, 0x84, 0xe9, 0x40,\n\t0xc2, 0x34, 0x20, 0x61, 0x0a, 0x90, 0x30, 0x1d, 0x48, 0x98, 0x0b, 0x48, 0x98, 0x86, 0x79, 0xa4, 0x21, 0xf0, 0xb0, 0x30, 0x66, 0x90, 0x86, 0x40, 0xc5, 0xc2, 0x98, 0x47, 0x72, 0x80, 0x8d, 0x69, 0xc0, 0xc6, 0x34, 0x60, 0x63, 0x1a, 0xb0, 0x31, 0x1d, 0xd8, 0x98, 0x8e, 0x39, 0xa5, 0x01, 0xe6, 0x94, 0x06, 0x98, 0x53, 0xf2, 0x30, 0x9b, 0xe4, 0x21, 0x0e, 0x2a, 0x0d, 0x11, 0x50, 0x69, 0x40, 0xc2, 0x32, 0x80, 0x84, 0x15, 0x22, 0x02, 0x2a, 0x0d, 0xb1, 0x4f, 0x69, 0x88, 0x7a, 0x4a, 0x03, 0x12, 0x16, 0x04, 0x12, 0xa6, 0xc3, 0x73, 0xc6, 0xc2, 0xc3, 0xc2, 0xc0, 0xc3, 0x5a, 0x03, 0x0f, 0x6b, 0x8f, 0x39, 0xa8, 0x39, 0xe2, 0xa3, 0xd2, 0x80, 0x81, 0x9d, 0x87, 0x99, 0xc8, 0x0d, 0x0c, 0xec, 0x3c, 0xcc, 0x47, 0x6e, 0x60, 0x60, 0xe7, 0x01, 0x03, 0xab, 0x8d, 0x28, 0x29, 0xeb, 0xbb, 0x1d,\n\t0x19, 0x98, 0xa1, 0xc2, 0x98, 0xa1, 0x9a, 0x03, 0x09, 0xcb, 0x40, 0xc4, 0x54, 0x1a, 0x22, 0xa6, 0xd2, 0x10, 0x31, 0x95, 0x86, 0x88, 0xa9, 0x34, 0x44, 0x4c, 0xa5, 0x01, 0x27, 0xcb, 0x40, 0xc4, 0x54, 0x1a, 0x22, 0xa6, 0xd2, 0x10, 0x31, 0x95, 0x86, 0x88, 0xa9, 0x34, 0x44, 0x4c, 0xa5, 0x01, 0x45, 0xab, 0x05, 0x14, 0xad, 0x16, 0x22, 0xa6, 0xd2, 0x10, 0x31, 0x95, 0x86, 0x88, 0xa9, 0x34, 0x44, 0x4c, 0xa5, 0x01, 0x5d, 0xcb, 0xc0, 0x8c, 0xd6, 0x1c, 0xe8, 0x5a, 0x18, 0xe8, 0x5a, 0x06, 0xd0, 0xb5, 0xe6, 0x40, 0xd7, 0x9a, 0x03, 0x5d, 0x6b, 0x0e, 0x74, 0x2d, 0x0c, 0x74, 0x2d, 0x03, 0x51, 0x55, 0x69, 0x88, 0xaa, 0x4a, 0x43, 0x54, 0x55, 0x4d, 0x44, 0x55, 0xd5, 0x04, 0xea, 0x96, 0x0a, 0xd4, 0x2d, 0x00, 0xd4, 0x2d, 0x15, 0xa8, 0x5b, 0x2a, 0x50, 0xb7, 0x18, 0x50, 0xb7, 0x28, 0x50,\n\t0xb7, 0x1a, 0x40, 0xdd, 0x9c, 0x40, 0xdd, 0x52, 0x80, 0xba, 0xa5, 0x03, 0x75, 0xcb, 0x02, 0xea, 0x96, 0x05, 0xd4, 0x2d, 0x1d, 0xa8, 0x5b, 0x56, 0xc2, 0xcb, 0x48, 0xa0, 0x6e, 0x99, 0x40, 0xdd, 0x32, 0x81, 0xb7, 0x39, 0x80, 0xb4, 0x39, 0x80, 0xb1, 0x39, 0x80, 0xae, 0xe9, 0x40, 0xd7, 0x5a, 0x03, 0x51, 0xd3, 0x81, 0xa2, 0xe9, 0x40, 0xd1, 0x74, 0x20, 0x67, 0x3a, 0xb0, 0x31, 0x1d, 0xa8, 0x58, 0x63, 0x78, 0x1c, 0xe5, 0x03, 0x1b, 0xd3, 0xe0, 0x71, 0x94, 0x0f, 0x8f, 0xa3, 0x7c, 0xe0, 0x64, 0x2d, 0x81, 0x93, 0x69, 0xc0, 0xc3, 0x5a, 0x03, 0x0f, 0xd3, 0x81, 0x84, 0xb5, 0x06, 0x12, 0xa6, 0x03, 0x03, 0xd3, 0x80, 0x7e, 0x69, 0x40, 0xb0, 0x14, 0xa0, 0x56, 0x2a, 0xf0, 0x2a, 0x15, 0x48, 0x55, 0x0b, 0x20, 0x55, 0xad, 0x80, 0x54, 0x35, 0x03, 0x52, 0xd5, 0x0c, 0x48, 0x55, 0x21, 0x90,\n\t0xaa, 0x42, 0x20, 0x55, 0x6d, 0x80, 0x54, 0x5d, 0x00, 0xa4, 0xaa, 0x2d, 0x90, 0x2a, 0x0f, 0x7c, 0x93, 0x7c, 0x78, 0x8a, 0x34, 0x07, 0x5e, 0x65, 0x00, 0xaf, 0x8a, 0xc0, 0x43, 0xc9, 0x84, 0x87, 0x52, 0x13, 0x60, 0x57, 0x1a, 0xb0, 0x2b, 0x0e, 0xec, 0x2a, 0x08, 0xec, 0x4a, 0x03, 0x76, 0xa5, 0x01, 0xbb, 0x0a, 0x01, 0xbb, 0xd2, 0x80, 0x5d, 0x59, 0x3e, 0x88, 0xe7, 0x03, 0xb5, 0xca, 0x00, 0x6a, 0x15, 0x03, 0x52, 0xd5, 0x1e, 0x48, 0x55, 0x1d, 0x20, 0x55, 0x75, 0x10, 0x09, 0x96, 0x06, 0xcf, 0xa5, 0xfa, 0x40, 0xad, 0xc2, 0x40, 0xad, 0xea, 0x01, 0xb5, 0xd2, 0xf1, 0x3c, 0x6b, 0x88, 0xe7, 0x59, 0x0e, 0xa2, 0xc5, 0xd2, 0x98, 0x44, 0x4f, 0x4a, 0xf1, 0x45, 0xd1, 0xfe, 0xfa, 0x0a, 0x7a, 0x1a, 0x5c, 0x80, 0xc8, 0x92, 0x9f, 0x68, 0x1d, 0xb6, 0x93, 0xe8, 0xd9, 0xf8, 0x97, 0xb4, 0xfa,\n\t0xf9, 0x84, 0x7e, 0x6f, 0x8a, 0xbf, 0x41, 0xdb, 0x32, 0xb2, 0x43, 0xbe, 0x8f, 0xbf, 0x4e, 0xbf, 0xc5, 0xd7, 0x33, 0x4e, 0x52, 0x8e, 0xcf, 0xe3, 0x1f, 0xff, 0xa7, 0x2d, 0x73, 0xf1, 0xa5, 0xc1, 0x73, 0x1e, 0x6b, 0x5b, 0xee, 0xc9, 0x40, 0x76, 0xee, 0x21, 0x5a, 0x3d, 0x6e, 0xa4, 0x95, 0xda, 0x1e, 0xb2, 0x88, 0x76, 0xd0, 0xaf, 0x77, 0xab, 0x8f, 0xd5, 0x88, 0x2f, 0xdd, 0x91, 0x2d, 0x24, 0xbe, 0x3d, 0xd7, 0x83, 0xce, 0x6f, 0x1e, 0x9f, 0x4d, 0x77, 0x53, 0xfe, 0x8d, 0xd3, 0x93, 0x54, 0xd2, 0xe7, 0xd6, 0x17, 0x19, 0x99, 0x21, 0xae, 0x28, 0xbe, 0x7f, 0x57, 0xd5, 0xcb, 0x5e, 0x5c, 0xd1, 0xb2, 0x5d, 0xab, 0x79, 0xc5, 0x7a, 0xf1, 0xb4, 0x78, 0x7d, 0xda, 0x5f, 0x12, 0x0f, 0xc7, 0x53, 0xe3, 0xb7, 0xc7, 0x87, 0xc7, 0x5b, 0x9d, 0xf6, 0xe7, 0x8f, 0x3b, 0x89, 0x17, 0xc3, 0xeb, 0xca,\n\t0x83, 0xef, 0x47, 0xce, 0xb6, 0xbe, 0x9c, 0x60, 0x7d, 0x97, 0x30, 0x91, 0x6b, 0x7c, 0xbc, 0x2f, 0xf6, 0x7d, 0xc8, 0x86, 0x18, 0x47, 0xfd, 0x70, 0x05, 0x95, 0x38, 0x38, 0xde, 0x89, 0xec, 0xc0, 0xae, 0x54, 0xea, 0xfa, 0xb3, 0xdc, 0xe3, 0xdb, 0x89, 0x75, 0xbd, 0x96, 0x40, 0x99, 0x16, 0x26, 0x1d, 0x5d, 0x02, 0xa4, 0xed, 0xb4, 0x45, 0xe4, 0x2c, 0xb7, 0x40, 0x92, 0xf2, 0x6c, 0x4d, 0x7c, 0x89, 0x4f, 0x7c, 0xd1, 0x75, 0x75, 0xbc, 0x34, 0x3e, 0x0f, 0x5f, 0x44, 0x1c, 0x0d, 0x8f, 0x98, 0x67, 0xc8, 0x5e, 0xfc, 0xd5, 0x58, 0x42, 0xf1, 0xc5, 0xbd, 0x73, 0x1e, 0x1b, 0x90, 0xd8, 0xf7, 0x88, 0x47, 0xe2, 0xd3, 0xe8, 0xce, 0xd3, 0xf1, 0xad, 0x94, 0xd6, 0xf1, 0x31, 0xf1, 0xfe, 0xf1, 0x0c, 0xab, 0x97, 0x85, 0x1d, 0x6e, 0x61, 0x51, 0xc9, 0x7e, 0x0e, 0xf1, 0x4b, 0xe3, 0x4b, 0xad, 0x2f,\n\t0xa7, 0xe2, 0xd7, 0x25, 0xf1, 0x46, 0xf1, 0x8b, 0x50, 0x1f, 0x99, 0xce, 0xbb, 0x56, 0xd8, 0xca, 0x49, 0x57, 0xa9, 0x2d, 0xbe, 0x4b, 0x11, 0xbf, 0x12, 0x88, 0xc8, 0x40, 0x58, 0xfa, 0x8f, 0x25, 0x97, 0x8c, 0xf4, 0x58, 0xcb, 0x37, 0x4a, 0xd4, 0x08, 0x5f, 0x09, 0x7d, 0x14, 0xa5, 0xdd, 0x16, 0x7f, 0x53, 0xf8, 0xd3, 0x90, 0xc6, 0xff, 0x6e, 0xdf, 0xbc, 0x72, 0x0f, 0xae, 0x6a, 0xe7, 0xaf, 0xd0, 0xa0, 0xf2, 0x6f, 0xdd, 0x96, 0xdb, 0xd8, 0x64, 0x81, 0xfc, 0xe6, 0xd8, 0xaa, 0x4e, 0x8c, 0x25, 0xd9, 0x34, 0x3b, 0xab, 0x5d, 0x9b, 0x3f, 0x64, 0x7b, 0x25, 0xf4, 0xec, 0x67, 0xb4, 0x78, 0xd9, 0xbf, 0x63, 0x0f, 0x9e, 0xf3, 0xc8, 0x17, 0xbf, 0xcf, 0x5e, 0x2d, 0x47, 0xbd, 0x61, 0x35, 0x1f, 0x4c, 0xf6, 0xe7, 0x89, 0xef, 0x2a, 0xff, 0x9a, 0xec, 0x6f, 0xd9, 0xd0, 0xff, 0x19, 0xac, 0x32,\n\t0xbe, 0x85, 0x6c, 0xff, 0xf7, 0xff, 0x4b, 0xf6, 0x74, 0x59, 0x05, 0xd6, 0xb3, 0xfd, 0xb4, 0x0f, 0x0c, 0xcd, 0x55, 0xff, 0xaa, 0xce, 0x3d, 0x26, 0xc7, 0x99, 0xfd, 0xda, 0x1b, 0x05, 0xa4, 0x76, 0x26, 0xf7, 0x48, 0xfc, 0xbd, 0xc4, 0x15, 0xbf, 0x49, 0x44, 0x0f, 0xee, 0x3a, 0xe7, 0x15, 0x2b, 0x7f, 0xe3, 0x67, 0xc7, 0xef, 0x18, 0x1d, 0xfb, 0x2b, 0xf5, 0xa3, 0xf8, 0xea, 0xaf, 0xf5, 0xf5, 0xe8, 0x6f, 0x7f, 0xe5, 0xec, 0x0f, 0xaa, 0xd1, 0x66, 0x7b, 0x92, 0xbf, 0x7e, 0xfb, 0xdb, 0x73, 0x3a, 0xe2, 0x22, 0xad, 0xb7, 0x03, 0x73, 0x69, 0x66, 0x5c, 0x79, 0xae, 0x16, 0xfa, 0x35, 0xd4, 0xa1, 0xaa, 0xb7, 0xce, 0xaf, 0x8e, 0x3a, 0xce, 0xae, 0x25, 0x9b, 0xee, 0x4b, 0xf6, 0x33, 0xd9, 0x64, 0xc2, 0xff, 0x3f, 0x9d, 0xec, 0xa5, 0x06, 0xf2, 0x7c, 0x61, 0x51, 0x90, 0x3d, 0xb1, 0x98, 0xec,\n\t0x85, 0xf5, 0x64, 0x27, 0x94, 0x92, 0x05, 0x40, 0xab, 0x7f, 0x5a, 0xbf, 0xd3, 0x4a, 0x9d, 0x56, 0xe2, 0x92, 0x58, 0x7b, 0x8b, 0x15, 0xb6, 0x58, 0x3b, 0xd3, 0x5a, 0xf7, 0x47, 0xdb, 0x71, 0x5a, 0x13, 0x36, 0xd6, 0x9a, 0x68, 0x4d, 0xb5, 0xe6, 0x5a, 0x0b, 0x5a, 0xd7, 0xdd, 0x49, 0xab, 0xb4, 0x7b, 0x69, 0x8d, 0x36, 0x41, 0x7b, 0x50, 0x9b, 0xa8, 0x3d, 0xa4, 0x4d, 0xd2, 0x1e, 0x16, 0xab, 0x34, 0x5a, 0xa3, 0x3d, 0x2d, 0xd6, 0x63, 0xb4, 0x1a, 0x5b, 0x4f, 0xab, 0xb0, 0x8f, 0x68, 0xdd, 0xf5, 0x15, 0xad, 0xb4, 0xda, 0x8b, 0x35, 0x14, 0xad, 0xa0, 0x6e, 0xd1, 0x87, 0xea, 0xb7, 0xea, 0x25, 0xfa, 0x6d, 0xfa, 0x30, 0xfd, 0x76, 0x7d, 0x38, 0xad, 0xa3, 0xee, 0xa2, 0xf5, 0xd3, 0x1e, 0xb1, 0x6e, 0xa2, 0x55, 0xd3, 0x77, 0xfa, 0x11, 0xb1, 0x22, 0xa2, 0x55, 0xce, 0x07, 0xb4, 0x36, 0x59,\n\t0x49, 0x2b, 0x90, 0xd5, 0xb4, 0xee, 0x90, 0xc8, 0x46, 0x15, 0x76, 0xa9, 0x03, 0xb6, 0xa8, 0x03, 0x56, 0xa2, 0x13, 0x36, 0xa1, 0x13, 0xb6, 0x9f, 0x13, 0x56, 0x9f, 0x93, 0xee, 0x69, 0x3e, 0x73, 0xd0, 0x7d, 0x2d, 0x22, 0x2e, 0x6c, 0x24, 0x2b, 0x4e, 0x40, 0x86, 0x2d, 0x64, 0x87, 0x2d, 0xa4, 0xc0, 0xc2, 0x51, 0x60, 0xa5, 0xb8, 0x61, 0x93, 0x58, 0x1e, 0xf9, 0x4e, 0x58, 0x1d, 0x4e, 0xd8, 0x1b, 0x6e, 0xba, 0xeb, 0x4e, 0xcc, 0x43, 0xf7, 0xdd, 0x9d, 0xf8, 0xe5, 0x64, 0x39, 0x38, 0xb1, 0xd6, 0xd7, 0xb0, 0xbe, 0xd7, 0xb1, 0xbe, 0x77, 0x50, 0x3b, 0x34, 0x61, 0x9c, 0xda, 0xa2, 0x29, 0x93, 0xa8, 0x3d, 0x9a, 0x53, 0xba, 0x85, 0xd6, 0x82, 0xd2, 0x62, 0xbd, 0x2b, 0x63, 0x45, 0xab, 0x50, 0xfb, 0x8c, 0x65, 0x36, 0x6a, 0x9f, 0x47, 0x88, 0x8b, 0x95, 0xab, 0x3d, 0xf1, 0x76, 0xd8, 0x7a,\n\t0x2f, 0x2c, 0x56, 0xab, 0xd6, 0xbb, 0x60, 0x0d, 0xab, 0x55, 0x6b, 0x9d, 0x6a, 0x60, 0x9d, 0x6a, 0xbd, 0xe1, 0x35, 0xb0, 0x42, 0x35, 0xb1, 0x06, 0x35, 0xb1, 0x06, 0x75, 0x60, 0x0d, 0xea, 0xc4, 0x1a, 0xd4, 0x81, 0x35, 0xa8, 0x13, 0x6b, 0x50, 0x17, 0xd6, 0xa0, 0x2e, 0xac, 0x41, 0xdd, 0x58, 0x83, 0x7a, 0xb0, 0x06, 0xf5, 0x60, 0x7d, 0xe9, 0xc0, 0xfa, 0xcf, 0x89, 0xd5, 0x9e, 0x03, 0x2d, 0xea, 0xa4, 0x36, 0x7d, 0x03, 0x78, 0x40, 0x01, 0xf0, 0x80, 0x54, 0xe0, 0x01, 0xb5, 0x81, 0x07, 0x34, 0x01, 0x1e, 0x50, 0x13, 0x78, 0x40, 0x2d, 0xb4, 0x7b, 0x0a, 0xf0, 0x80, 0x4c, 0xe0, 0x01, 0x31, 0xf4, 0x41, 0x26, 0xf0, 0x80, 0xf3, 0x80, 0x07, 0x78, 0x81, 0x07, 0x04, 0x80, 0x07, 0x44, 0x80, 0x07, 0x34, 0x02, 0x1e, 0xe0, 0x04, 0x1e, 0xa0, 0x00, 0x09, 0x08, 0x03, 0x09, 0x68, 0x04, 0x24,\n\t0xc0, 0x01, 0x24, 0xc0, 0x0f, 0x24, 0xc0, 0x06, 0x24, 0x80, 0x03, 0x09, 0xf0, 0x03, 0x09, 0xb0, 0x03, 0x09, 0xf0, 0x27, 0xc5, 0xa9, 0xf8, 0x81, 0x04, 0x34, 0x04, 0x12, 0x90, 0x97, 0x14, 0xa7, 0xe2, 0x07, 0x12, 0xd0, 0x00, 0x48, 0x80, 0x1f, 0x48, 0x80, 0x1f, 0xda, 0x20, 0x27, 0xc5, 0xa9, 0xf8, 0x81, 0x04, 0x04, 0x81, 0x04, 0x68, 0x40, 0x02, 0x9a, 0x02, 0x09, 0x68, 0x06, 0x24, 0xa0, 0x29, 0x90, 0x80, 0x66, 0x40, 0x02, 0x42, 0x40, 0x02, 0x32, 0xe0, 0x73, 0x93, 0x03, 0x3c, 0x20, 0x03, 0x3e, 0x37, 0x39, 0xf0, 0xb9, 0x49, 0x87, 0xcf, 0x4d, 0x3a, 0x10, 0x82, 0xf3, 0x61, 0x97, 0x17, 0xc0, 0x2e, 0xcf, 0x84, 0x5d, 0x9e, 0x02, 0xbb, 0x3c, 0x13, 0x3a, 0x97, 0x09, 0xbb, 0x3c, 0x13, 0x76, 0xb9, 0x17, 0x76, 0xb9, 0x03, 0x76, 0x79, 0x23, 0xe8, 0xa2, 0x03, 0xba, 0xe8, 0x82, 0x2e,\n\t0x9a, 0xb0, 0xcb, 0x1d, 0xb0, 0xc8, 0xeb, 0xc2, 0x22, 0xb7, 0x6c, 0xf1, 0x7c, 0xd8, 0xe2, 0x8d, 0xa0, 0xa9, 0x26, 0x6c, 0xf1, 0x2c, 0xd8, 0xe2, 0x11, 0xd8, 0xe2, 0x7e, 0xd8, 0xe2, 0x36, 0xd8, 0xe2, 0x7e, 0xd8, 0xe2, 0x0d, 0x61, 0x8b, 0xfb, 0x93, 0xe2, 0x54, 0x1a, 0xc2, 0x16, 0xaf, 0x07, 0x2d, 0x8f, 0xc2, 0x16, 0x6f, 0x08, 0x5b, 0xbc, 0x01, 0x6c, 0x71, 0x3f, 0xf4, 0xbe, 0x3e, 0x6c, 0x71, 0x3f, 0x6c, 0x71, 0x3b, 0x6c, 0x71, 0x3f, 0x6c, 0xf1, 0x06, 0xb0, 0xc5, 0xfd, 0x18, 0x15, 0x52, 0x52, 0x9c, 0x8a, 0x1f, 0x63, 0x23, 0x9a, 0x14, 0xa7, 0x62, 0x87, 0x2d, 0xee, 0x87, 0x2d, 0x5e, 0x07, 0xb6, 0x78, 0x23, 0xd8, 0xe2, 0x75, 0x60, 0x8b, 0x37, 0x82, 0x2d, 0x6e, 0xc0, 0x16, 0xf7, 0xc3, 0x16, 0xf7, 0xc3, 0x16, 0xf7, 0x9f, 0x11, 0xa7, 0x52, 0x03, 0xb6, 0x78, 0x0d, 0xd8, 0xe2,\n\t0xd9, 0xc0, 0xf7, 0x72, 0x61, 0x91, 0x67, 0x03, 0xdf, 0xcb, 0x85, 0x15, 0x5e, 0x13, 0x36, 0x37, 0x4f, 0x8a, 0x56, 0x09, 0xc0, 0xe6, 0x6e, 0x84, 0x31, 0x99, 0x89, 0x31, 0xd9, 0x18, 0x36, 0x77, 0x01, 0xec, 0x6c, 0xcb, 0xcb, 0x44, 0x87, 0x25, 0xdd, 0x08, 0x96, 0x74, 0x01, 0xec, 0xda, 0x02, 0xd8, 0xb5, 0x8d, 0x60, 0xd1, 0x16, 0xc0, 0xa2, 0x2d, 0x80, 0x45, 0x5b, 0x00, 0x8b, 0xb6, 0x11, 0x46, 0xaf, 0x03, 0xa3, 0xd7, 0x84, 0x0d, 0x9a, 0x06, 0x1b, 0x34, 0x0d, 0xd6, 0x67, 0x1a, 0xc6, 0xb0, 0xeb, 0x8c, 0x31, 0xac, 0x26, 0xc5, 0xb8, 0x64, 0x56, 0x23, 0xc6, 0x25, 0x08, 0x8b, 0xd3, 0x0d, 0x8b, 0xd3, 0x0f, 0x8b, 0xd3, 0x0d, 0x8b, 0xd3, 0x0d, 0x8b, 0xb3, 0x16, 0x46, 0xbb, 0x1f, 0xa3, 0x3d, 0x33, 0x29, 0xd2, 0x25, 0x33, 0x29, 0xd2, 0xc5, 0x8f, 0xd1, 0xee, 0xc7, 0x68, 0x8f, 0x62,\n\t0xb4, 0xfb, 0x30, 0xda, 0x7d, 0xb0, 0x38, 0x53, 0x61, 0x71, 0xd6, 0x86, 0xc5, 0xd9, 0x04, 0x16, 0x67, 0x13, 0x58, 0x9c, 0x35, 0x61, 0x71, 0xd6, 0xc4, 0x8c, 0x90, 0x02, 0x8b, 0x33, 0x06, 0x8b, 0xf3, 0x3c, 0x58, 0x9c, 0x5e, 0x58, 0x9c, 0x01, 0x58, 0x9c, 0x05, 0xb0, 0x38, 0x9d, 0xb0, 0x35, 0xc3, 0xb0, 0x35, 0x15, 0xd8, 0x9a, 0x7e, 0xd8, 0x9a, 0x36, 0xd8, 0x9a, 0x1c, 0xb6, 0xa6, 0x1f, 0xb6, 0xa6, 0x1f, 0xb6, 0x66, 0x03, 0xd8, 0x9a, 0x7e, 0xcc, 0x35, 0x32, 0x6c, 0xcd, 0x3c, 0xf8, 0x49, 0xa4, 0x63, 0xde, 0x69, 0x0c, 0x9b, 0x32, 0x1f, 0x36, 0x65, 0x23, 0xd8, 0x94, 0x52, 0x52, 0x34, 0x4c, 0x1d, 0xd8, 0x94, 0x06, 0x3d, 0xab, 0x1c, 0x6c, 0x13, 0xf5, 0xf3, 0x00, 0x75, 0x10, 0xcd, 0x50, 0xb5, 0xec, 0x75, 0xec, 0x2d, 0x19, 0xb3, 0xb7, 0xb6, 0xd3, 0xf8, 0xb4, 0x5f, 0x6c, 0xef,\n\t0xc9, 0xa2, 0xf6, 0x83, 0xf6, 0x6f, 0x58, 0x1d, 0xfb, 0x11, 0xfb, 0x8f, 0xac, 0xbe, 0xfd, 0xa4, 0xaa, 0x50, 0xef, 0xda, 0x55, 0x93, 0x35, 0x57, 0x9d, 0xaa, 0x87, 0xb5, 0x51, 0xc3, 0x6a, 0x84, 0x75, 0x50, 0x6b, 0xa9, 0xf5, 0x58, 0x47, 0x53, 0x36, 0x65, 0xd6, 0xdd, 0xb4, 0x9b, 0x76, 0x76, 0xb9, 0xa9, 0x9b, 0x3a, 0x2b, 0x36, 0xe9, 0x8f, 0x5d, 0x61, 0xba, 0x4c, 0x17, 0xeb, 0x61, 0xfa, 0x4d, 0x3f, 0xbb, 0xd2, 0x0c, 0x9b, 0x61, 0xd6, 0xd3, 0xcc, 0x35, 0x73, 0xd9, 0x55, 0x66, 0x23, 0xb3, 0x11, 0xeb, 0x65, 0x16, 0x98, 0x05, 0xec, 0x6a, 0xf3, 0x02, 0xf3, 0x02, 0xd6, 0xdb, 0x6c, 0x69, 0xb6, 0x64, 0xd7, 0x98, 0xad, 0xcd, 0xd6, 0xac, 0x8f, 0xd9, 0xd1, 0xec, 0xc8, 0xae, 0x35, 0x2f, 0x36, 0x2f, 0x66, 0x7d, 0xcd, 0xfb, 0xcc, 0xfb, 0xd8, 0x5f, 0xcc, 0xf1, 0xe6, 0x78, 0xd6, 0xcf,\n\t0x7c, 0xc8, 0x7c, 0x88, 0x5d, 0x67, 0xbe, 0x6e, 0xbe, 0xce, 0xfa, 0x9b, 0xeb, 0xcd, 0xf5, 0xec, 0x7a, 0xf3, 0x2d, 0xf3, 0x2d, 0x36, 0x80, 0x6a, 0xbf, 0x1e, 0xdf, 0x00, 0x66, 0xf8, 0x92, 0x58, 0x3d, 0x76, 0x3e, 0x6b, 0xce, 0xea, 0xe3, 0x5b, 0x61, 0x0d, 0xf1, 0x95, 0xb0, 0x3c, 0xd6, 0x9e, 0xa8, 0x11, 0xeb, 0x4a, 0x94, 0x0f, 0xd4, 0xbc, 0x31, 0x3d, 0xa7, 0xaf, 0xa3, 0xd9, 0x77, 0x00, 0x51, 0x73, 0x7c, 0xf5, 0xb7, 0x05, 0x70, 0xf4, 0x96, 0xf8, 0xba, 0x6f, 0x21, 0x1b, 0xc9, 0xee, 0x62, 0xad, 0xd9, 0xdd, 0x44, 0x6d, 0xd9, 0xc3, 0x6c, 0x32, 0x6b, 0xc7, 0xde, 0x62, 0x5b, 0x59, 0x07, 0x56, 0x4a, 0x54, 0xc4, 0x3e, 0x24, 0xba, 0x94, 0x7d, 0x44, 0xd4, 0x8d, 0x7d, 0xcc, 0x76, 0xb2, 0xcb, 0xd8, 0x2e, 0xa2, 0xcb, 0xd9, 0x67, 0x6c, 0x0f, 0x2b, 0x66, 0x07, 0x89, 0x7a, 0xb0, 0xc3,\n\t0xdc, 0xcd, 0xae, 0xc4, 0x2c, 0x7b, 0x07, 0xe6, 0xd1, 0x3b, 0x31, 0x3b, 0x8e, 0xe4, 0xb7, 0xf2, 0x5b, 0xd9, 0x5d, 0xfc, 0x75, 0xfe, 0x3a, 0x1b, 0xc5, 0xf7, 0xf3, 0x2f, 0xd9, 0xdd, 0x52, 0x5b, 0xe9, 0x0e, 0x76, 0x8f, 0x74, 0xa7, 0x34, 0x92, 0x2d, 0x87, 0x8f, 0xdf, 0x0a, 0xe9, 0x1e, 0xe9, 0x1e, 0xb6, 0x52, 0x9a, 0x20, 0x3d, 0xc8, 0x56, 0x49, 0x0f, 0x49, 0x0f, 0xb1, 0xd5, 0xd2, 0x64, 0x69, 0x32, 0x7b, 0x55, 0x7a, 0x54, 0x7a, 0x94, 0xad, 0xc1, 0xd7, 0x71, 0x5f, 0x93, 0x66, 0x4b, 0xb3, 0xd9, 0xeb, 0xd2, 0x8b, 0xd2, 0x8b, 0x6c, 0x9d, 0xb4, 0x54, 0xfa, 0x07, 0x7b, 0x43, 0x5a, 0x25, 0xbd, 0xc2, 0xde, 0x94, 0x5e, 0x93, 0xde, 0x60, 0x6f, 0x49, 0x6f, 0x4b, 0x6f, 0xb3, 0xcd, 0xd2, 0x16, 0x69, 0x0b, 0x7b, 0x57, 0xda, 0x26, 0x7d, 0xc8, 0xb6, 0x48, 0x1f, 0x49, 0x1f, 0xb3, 0xad,\n\t0xd2, 0x5e, 0x69, 0x2f, 0xfb, 0x40, 0x3a, 0x20, 0x7d, 0xc5, 0xb6, 0x49, 0x5f, 0x4b, 0x5f, 0xb3, 0xed, 0x52, 0x99, 0x54, 0xc6, 0x3e, 0x92, 0xbe, 0x93, 0x8e, 0xb2, 0x1d, 0xd2, 0x31, 0xe9, 0x18, 0xdb, 0x25, 0x1d, 0x97, 0xe2, 0xec, 0x53, 0x59, 0x92, 0x25, 0xf6, 0x85, 0x6c, 0x93, 0x6d, 0x6c, 0xbf, 0xac, 0xc9, 0x1a, 0xfb, 0x92, 0xba, 0xd8, 0xc5, 0x0e, 0xc8, 0x01, 0x39, 0xc2, 0x0e, 0xc9, 0x35, 0xe4, 0x54, 0xf6, 0x9d, 0x9c, 0x29, 0x67, 0xb2, 0xa3, 0x72, 0x96, 0x9c, 0xc5, 0x7e, 0x90, 0xaf, 0x92, 0xaf, 0x62, 0xc7, 0xe4, 0xab, 0xe5, 0xab, 0xd9, 0x8f, 0xf2, 0xf5, 0xf2, 0x00, 0x76, 0x5c, 0xbe, 0x45, 0xbe, 0x85, 0x9d, 0x90, 0xef, 0x90, 0xef, 0x60, 0x3f, 0xcb, 0x77, 0xcb, 0x77, 0xb3, 0x93, 0xf2, 0x93, 0xf2, 0x3c, 0xf6, 0x8b, 0xfc, 0x9c, 0xfc, 0x1c, 0xb7, 0x89, 0x59, 0x9c, 0xdb,\n\t0xe5, 0x25, 0xf2, 0x12, 0xae, 0xca, 0xff, 0x90, 0xff, 0xc1, 0x35, 0x79, 0xb9, 0xfc, 0x2f, 0xae, 0x8b, 0x39, 0x8f, 0x9f, 0xaf, 0x38, 0x14, 0x07, 0x6f, 0xa6, 0x78, 0x15, 0x1f, 0xbf, 0x40, 0x09, 0x2a, 0x41, 0xde, 0x42, 0x09, 0x2b, 0x11, 0xde, 0x52, 0x49, 0x51, 0x52, 0x78, 0xa1, 0x52, 0x4b, 0x49, 0xe7, 0xad, 0x95, 0x46, 0xca, 0xf9, 0xbc, 0xbd, 0xd2, 0x4a, 0x29, 0xe4, 0x5d, 0x68, 0x5e, 0xec, 0xc2, 0x69, 0xf6, 0x53, 0xba, 0xf1, 0x2b, 0x95, 0x62, 0xa5, 0x98, 0xf7, 0x16, 0xef, 0x34, 0xf8, 0x35, 0xe2, 0xdb, 0xbf, 0xbc, 0x8f, 0x2d, 0x6a, 0x8b, 0xf2, 0x6b, 0x6d, 0x35, 0x6d, 0xe7, 0xf1, 0xbe, 0xb6, 0xda, 0xb6, 0xda, 0xfc, 0x7a, 0xdb, 0x55, 0xb6, 0xab, 0xf8, 0x00, 0xf1, 0x36, 0x83, 0xdf, 0x60, 0x7b, 0xc3, 0xb6, 0x81, 0x0f, 0xb4, 0x7d, 0x6a, 0xdb, 0xc3, 0x07, 0xdb, 0xf6, 0xdb,\n\t0xbe, 0xe4, 0x43, 0x6d, 0x5f, 0xd9, 0x0e, 0xf1, 0x12, 0x9a, 0xf9, 0x8e, 0xf1, 0xe1, 0xe2, 0x4d, 0x10, 0x1f, 0x81, 0xcf, 0x9e, 0x8f, 0xb4, 0xbb, 0xec, 0x2e, 0x7e, 0x97, 0xc0, 0x19, 0xf9, 0x28, 0x7b, 0xa6, 0x3d, 0x8b, 0xdf, 0x2d, 0xfc, 0xee, 0xf8, 0x18, 0xb5, 0xbe, 0x7a, 0x05, 0xbf, 0x97, 0x66, 0xc1, 0x11, 0x7c, 0x91, 0x3a, 0x52, 0x7d, 0x95, 0x6f, 0x50, 0xdf, 0x52, 0x4f, 0x48, 0x86, 0x7a, 0x52, 0x33, 0xa5, 0x42, 0xcd, 0xa9, 0xcd, 0x92, 0x8a, 0xb4, 0xd9, 0xda, 0x1c, 0x69, 0xb7, 0xf6, 0x8c, 0xf6, 0x92, 0xf4, 0x39, 0xcd, 0x67, 0x2f, 0x4b, 0x87, 0xb5, 0x95, 0xda, 0x4a, 0xe9, 0xa8, 0xb6, 0x5a, 0x7b, 0x43, 0xfa, 0x41, 0x7b, 0x4b, 0xfb, 0x40, 0xfa, 0x45, 0xfb, 0x50, 0xdb, 0x2e, 0x1b, 0xda, 0x0e, 0xed, 0x63, 0xd9, 0xa1, 0x7d, 0xa2, 0x7d, 0x2e, 0xbb, 0xb4, 0x7d, 0xda, 0x17,\n\t0x72, 0x50, 0x3b, 0xa0, 0x7d, 0x23, 0x87, 0xb5, 0xb8, 0xae, 0xc8, 0x35, 0x75, 0x8f, 0x9e, 0x26, 0x67, 0xe8, 0xe9, 0x7a, 0xba, 0x5c, 0x40, 0xf3, 0x59, 0x96, 0xdc, 0x44, 0x7c, 0x03, 0x4d, 0x6e, 0xa6, 0xe7, 0xe8, 0x8d, 0xe4, 0x0b, 0xf4, 0xc6, 0x7a, 0x33, 0xb9, 0xb5, 0xf8, 0xe2, 0xae, 0x7c, 0xa1, 0xde, 0x41, 0xbf, 0x50, 0x2e, 0xd2, 0x2f, 0xd2, 0x2f, 0x96, 0xbb, 0xe9, 0x97, 0xe8, 0x45, 0xf2, 0xe5, 0xfa, 0xe5, 0x7a, 0x4f, 0xf9, 0x0a, 0xbd, 0x97, 0x4e, 0xbd, 0x44, 0xeb, 0xc3, 0x6b, 0xe4, 0x6b, 0xf4, 0xbe, 0xfa, 0x00, 0xb9, 0x8f, 0x3e, 0x50, 0x1f, 0x29, 0x5f, 0x2f, 0xbc, 0xcb, 0xe4, 0x11, 0xfa, 0xbd, 0xfa, 0x58, 0x79, 0xa4, 0x7e, 0xbf, 0x7e, 0xbf, 0x3c, 0x4a, 0x7f, 0x50, 0x7f, 0x58, 0xbe, 0x5b, 0x9f, 0xa2, 0x4f, 0x91, 0xc7, 0xea, 0x53, 0xf5, 0x69, 0xf2, 0x7d, 0xfa, 0x74,\n\t0x7d, 0xba, 0x3c, 0x5e, 0x7f, 0x5c, 0x7f, 0x5c, 0x7e, 0x40, 0x5f, 0xa3, 0xbf, 0x2e, 0x4f, 0xd0, 0xdf, 0xd0, 0xdf, 0x94, 0x27, 0xe9, 0x1b, 0xf5, 0x77, 0xe5, 0x47, 0xf4, 0xf7, 0xf5, 0x52, 0xf9, 0x51, 0x7d, 0x9b, 0xbe, 0x5d, 0x7e, 0x4c, 0xff, 0x58, 0xff, 0x54, 0x9e, 0xa9, 0x7f, 0xa6, 0x7f, 0x26, 0x3f, 0x25, 0x3c, 0xcd, 0xe4, 0x39, 0xc2, 0xd3, 0x4c, 0x9e, 0x4b, 0x2b, 0xcf, 0xaf, 0xe4, 0xf9, 0xfa, 0xd7, 0xfa, 0x21, 0xf9, 0x39, 0xbd, 0x4c, 0xff, 0x56, 0xfe, 0x3b, 0xad, 0x43, 0x8f, 0xc9, 0xcf, 0x1b, 0x61, 0xa3, 0xb6, 0xfc, 0x12, 0xcd, 0xa9, 0xcd, 0xe5, 0xb5, 0x46, 0x4b, 0xa3, 0xa5, 0xbc, 0xd9, 0x28, 0x34, 0xba, 0xcb, 0xef, 0xd2, 0x9c, 0xda, 0x47, 0xde, 0x6b, 0xf4, 0x35, 0x06, 0xcb, 0xdf, 0xd0, 0x9c, 0x3a, 0x4a, 0x3e, 0x61, 0x8c, 0x36, 0x46, 0x2b, 0x1a, 0xcd, 0xac, 0x53,\n\t0x15, 0xdd, 0x98, 0x66, 0x4c, 0x53, 0x6a, 0x18, 0xd3, 0x8d, 0xb9, 0x4a, 0x4d, 0x63, 0x9e, 0xf1, 0xba, 0x52, 0x4f, 0xc4, 0x98, 0x2b, 0x9d, 0x69, 0xd6, 0xdc, 0xa4, 0x5c, 0x6c, 0xbc, 0x6b, 0x6c, 0x51, 0x84, 0x5f, 0xd9, 0x36, 0xa5, 0x9b, 0xf0, 0x25, 0x53, 0x8a, 0x8d, 0x83, 0xc6, 0x8f, 0xca, 0x15, 0xc6, 0x4f, 0xc6, 0x49, 0xe5, 0x3a, 0xb3, 0x83, 0xd9, 0x41, 0xb9, 0xc1, 0xbc, 0xca, 0xbc, 0x4a, 0x19, 0x68, 0xf6, 0x36, 0x7b, 0x2b, 0x37, 0x9a, 0xfd, 0xcc, 0x7e, 0xca, 0x20, 0xf3, 0x7a, 0xf3, 0x7a, 0xe5, 0x26, 0x73, 0xa0, 0x39, 0x50, 0x19, 0x6c, 0xde, 0x64, 0xde, 0xa4, 0xdc, 0x6c, 0xde, 0x6a, 0xde, 0xaa, 0x0c, 0x31, 0x87, 0x99, 0xc3, 0x94, 0x5b, 0xcc, 0x87, 0xcd, 0xc9, 0xca, 0x50, 0x73, 0xaa, 0xf9, 0x98, 0x52, 0x62, 0x2e, 0x36, 0x5f, 0x54, 0x46, 0x98, 0x2b, 0xcc, 0x55, 0xca,\n\t0x48, 0xb1, 0xd2, 0x53, 0xee, 0x16, 0xf3, 0xab, 0x72, 0x8f, 0xb9, 0xc9, 0x7c, 0x47, 0x19, 0x63, 0xbe, 0x6b, 0xbe, 0xab, 0x8c, 0x65, 0x37, 0x90, 0x51, 0xb0, 0x8d, 0xb6, 0x85, 0x55, 0xf6, 0xf3, 0x7e, 0xc7, 0x7e, 0x36, 0x6d, 0xcb, 0x93, 0x7e, 0xaf, 0xa6, 0x6d, 0x5d, 0xe2, 0x77, 0x72, 0xde, 0x7f, 0x77, 0xab, 0x5a, 0xb7, 0x7f, 0x77, 0x5b, 0x52, 0xe5, 0x77, 0x79, 0x9d, 0x93, 0xeb, 0xbb, 0x91, 0xb6, 0x2d, 0xe7, 0x38, 0x7f, 0x67, 0x95, 0x6d, 0x4f, 0xd2, 0xb6, 0x9f, 0xb6, 0x43, 0x89, 0xed, 0x78, 0xd2, 0x76, 0x2a, 0xb1, 0x1d, 0x49, 0x92, 0x95, 0xa7, 0x0f, 0x25, 0xed, 0xcb, 0xb7, 0x23, 0x95, 0xce, 0xe5, 0xa7, 0x6e, 0x51, 0xfa, 0x12, 0x1f, 0x6a, 0x3b, 0x48, 0x7c, 0x14, 0xf8, 0x41, 0xfb, 0x14, 0x21, 0x47, 0x7a, 0x28, 0xad, 0x90, 0xf8, 0xa9, 0x5b, 0x6d, 0x5f, 0x23, 0xcf, 0x0a,\n\t0xe2, 0x1b, 0x95, 0x1d, 0x90, 0xe3, 0x2c, 0x5a, 0xab, 0x09, 0x5e, 0x8c, 0xa3, 0x8f, 0xd3, 0xda, 0xfa, 0x11, 0x71, 0x16, 0xbf, 0x1f, 0x7c, 0x4a, 0x82, 0x7f, 0xad, 0xdc, 0xe7, 0xdc, 0xee, 0xdc, 0xae, 0x6b, 0x8e, 0x43, 0x4e, 0x45, 0x77, 0xe9, 0xab, 0x9d, 0x21, 0x8f, 0xe1, 0xcc, 0x76, 0x37, 0x33, 0x6a, 0x78, 0x3c, 0x7a, 0xc0, 0xd9, 0xd1, 0x6c, 0xe9, 0xec, 0xee, 0xec, 0xa3, 0xc7, 0x8c, 0xed, 0xce, 0x41, 0xce, 0xe1, 0xce, 0xb1, 0x7a, 0x9a, 0x73, 0xb2, 0x6b, 0x84, 0x9e, 0xe5, 0xda, 0xed, 0x5c, 0xe4, 0x9c, 0x6c, 0xac, 0x70, 0x2e, 0xd5, 0x73, 0x9c, 0x6b, 0x8c, 0x90, 0x73, 0xab, 0x73, 0x2b, 0x59, 0x72, 0xf9, 0xce, 0xbd, 0xce, 0x03, 0xce, 0xa3, 0x2e, 0x87, 0xab, 0xc4, 0xbd, 0x5a, 0x6f, 0xa6, 0x17, 0xba, 0x32, 0x69, 0xac, 0x77, 0xd1, 0xbb, 0xe9, 0x3d, 0xf4, 0xde, 0xae, 0x01,\n\t0x44, 0x9d, 0x5d, 0x45, 0xa0, 0x5e, 0x7a, 0x3f, 0x57, 0x5f, 0x97, 0xc3, 0xdc, 0xa0, 0x0f, 0x74, 0x4d, 0x77, 0xa5, 0xea, 0x43, 0x9c, 0xd9, 0xfa, 0x30, 0x77, 0xbe, 0x6b, 0x99, 0x3e, 0xd2, 0xe3, 0x71, 0xad, 0xd2, 0xc7, 0xb8, 0xd6, 0xba, 0x46, 0x98, 0xbd, 0x9c, 0x2b, 0xf4, 0xf1, 0xfa, 0x24, 0x73, 0x00, 0x8d, 0xf1, 0x19, 0xfa, 0x6c, 0xb7, 0xe6, 0x0e, 0xb8, 0x67, 0x9b, 0x6b, 0xf5, 0x79, 0xfa, 0x42, 0xc7, 0x12, 0x7d, 0x89, 0x39, 0xd1, 0xdc, 0x61, 0x2e, 0x76, 0x67, 0xb9, 0xf3, 0xcd, 0x59, 0xfa, 0x72, 0x7d, 0xb5, 0xbe, 0xce, 0x9c, 0x65, 0xce, 0x72, 0x1e, 0xa0, 0x31, 0xbf, 0xd1, 0x7d, 0x5c, 0xdf, 0xe2, 0x6c, 0xa3, 0x6f, 0xa3, 0xfb, 0xda, 0xe9, 0x1e, 0xe9, 0x88, 0x39, 0x62, 0xee, 0x25, 0xae, 0xd1, 0xe6, 0x14, 0x5a, 0x2d, 0xed, 0x77, 0x75, 0xd6, 0x0f, 0x99, 0x83, 0xf5, 0x23,\n\t0xfa, 0x71, 0xa3, 0x80, 0xae, 0x7d, 0x8a, 0x96, 0xb1, 0x86, 0xe1, 0x31, 0x42, 0xee, 0x1c, 0xd7, 0x5c, 0x67, 0xb6, 0x51, 0xc3, 0x9d, 0x63, 0xa4, 0x1b, 0xd9, 0x9e, 0x5c, 0xe7, 0x58, 0x77, 0xbe, 0xa3, 0x9f, 0x91, 0x6b, 0xac, 0xf0, 0x28, 0x8e, 0x23, 0xce, 0x4d, 0xae, 0x52, 0xa3, 0xc0, 0x68, 0x6e, 0xb4, 0x71, 0xef, 0x71, 0xef, 0x74, 0xa4, 0x39, 0x34, 0x8f, 0xc7, 0x19, 0x72, 0xec, 0x34, 0x3a, 0x3a, 0x8f, 0x1a, 0x5d, 0x8d, 0x3e, 0x4e, 0xc3, 0xe8, 0xee, 0xdc, 0x6a, 0xac, 0x30, 0x23, 0xf4, 0xbb, 0xa7, 0xd1, 0x87, 0xee, 0xa3, 0xb3, 0xd1, 0xdf, 0x18, 0x64, 0x0c, 0x35, 0x33, 0xdd, 0xc3, 0x8c, 0xe1, 0xae, 0x01, 0xc6, 0x28, 0x5a, 0x6f, 0xcd, 0x31, 0xb6, 0xba, 0x4a, 0x8c, 0x32, 0x63, 0x82, 0x31, 0xd9, 0x98, 0x46, 0x2d, 0xd2, 0xcb, 0xac, 0x67, 0xcc, 0x71, 0x95, 0x38, 0xc6, 0x18,\n\t0x33, 0xa9, 0xfc, 0x39, 0x44, 0xf3, 0xa9, 0x95, 0x7a, 0x19, 0x8b, 0x8c, 0xa5, 0x54, 0x56, 0xa6, 0xfb, 0x90, 0xb1, 0xc6, 0x58, 0xef, 0x58, 0x6e, 0x6c, 0xa2, 0xf3, 0x36, 0x1b, 0xdb, 0x8d, 0x5d, 0xae, 0x12, 0x41, 0xee, 0xa9, 0x66, 0xa9, 0xb1, 0xd7, 0x38, 0x40, 0x25, 0x1d, 0x25, 0x3a, 0x61, 0x32, 0x47, 0x37, 0xd3, 0xee, 0x58, 0x62, 0x3a, 0xcc, 0x89, 0x8e, 0x6e, 0xce, 0xad, 0x1e, 0xc5, 0x99, 0xeb, 0xcc, 0x75, 0xaf, 0x33, 0x7d, 0x66, 0xc4, 0x4c, 0x35, 0x33, 0xcd, 0x7a, 0x66, 0x9e, 0xd9, 0x94, 0x7e, 0xb7, 0x34, 0xdb, 0x99, 0x9d, 0xcd, 0x22, 0xb3, 0xd8, 0x1c, 0xe0, 0xcc, 0x76, 0x6d, 0xa6, 0x36, 0x1e, 0x6e, 0xf6, 0x75, 0xed, 0xf0, 0x64, 0x9b, 0x03, 0xcc, 0xc1, 0x66, 0x89, 0x39, 0xc2, 0x9d, 0x65, 0x8e, 0x36, 0x37, 0x98, 0x6b, 0xcd, 0x71, 0x8e, 0x2e, 0xd4, 0xc2, 0x53, 0xcc,\n\t0xe9, 0x1e, 0xfa, 0xa3, 0x76, 0x55, 0x9c, 0x9b, 0xa8, 0x15, 0xf6, 0x9a, 0x73, 0xcd, 0x65, 0xe6, 0x32, 0x67, 0x1b, 0x73, 0x81, 0xb9, 0x80, 0x72, 0x2c, 0xc6, 0xd1, 0x65, 0xce, 0xe1, 0xee, 0x1c, 0xf7, 0x1e, 0x5a, 0xd7, 0xad, 0x35, 0x37, 0x50, 0x9e, 0xcd, 0x66, 0xa9, 0x59, 0xea, 0x9c, 0x49, 0x7c, 0x87, 0xc7, 0xe3, 0x20, 0xfd, 0x72, 0xcd, 0xa5, 0xbe, 0xda, 0x6d, 0xee, 0x33, 0x0f, 0x9a, 0x87, 0xcd, 0x63, 0xe6, 0x49, 0x67, 0x99, 0x43, 0x72, 0x04, 0xe8, 0x88, 0xcb, 0x11, 0x70, 0x2a, 0x9e, 0x5c, 0xf7, 0x3c, 0x67, 0x1b, 0xea, 0xa5, 0x9d, 0xa4, 0x49, 0xb9, 0xee, 0x61, 0xd4, 0xba, 0x59, 0x8e, 0x66, 0x8e, 0x1c, 0xda, 0xf2, 0x1d, 0xcd, 0x5c, 0xc5, 0x8e, 0x42, 0xe7, 0x64, 0x47, 0x07, 0xa7, 0xe2, 0xe8, 0xed, 0xe8, 0xe2, 0xe8, 0xe6, 0xe8, 0x41, 0xfb, 0x7e, 0x8e, 0x81, 0x8e, 0x21,\n\t0xf4, 0xd8, 0x73, 0x38, 0x86, 0x39, 0x46, 0xba, 0x3a, 0x3b, 0xc6, 0x38, 0x97, 0x3a, 0xc6, 0xbb, 0x25, 0x57, 0x91, 0x63, 0x92, 0x63, 0xaa, 0x63, 0x06, 0xe9, 0xd2, 0x31, 0xc7, 0x6c, 0xc7, 0x3c, 0xa7, 0xc7, 0xbd, 0x9a, 0x5a, 0xb9, 0xc4, 0xb1, 0xd0, 0x35, 0xcb, 0xb1, 0xc4, 0xb1, 0xdc, 0xd9, 0xdf, 0xb1, 0xda, 0x55, 0x4c, 0x7a, 0x94, 0x45, 0xbf, 0xd7, 0x39, 0x36, 0x7a, 0xb2, 0xc5, 0x08, 0x38, 0x93, 0x1c, 0x5b, 0xce, 0x2e, 0xaf, 0x92, 0x6b, 0xdb, 0x39, 0x8f, 0xec, 0xa4, 0x7b, 0xd9, 0xee, 0xd8, 0x43, 0xb4, 0xdf, 0x71, 0x88, 0xc6, 0x57, 0x99, 0xe3, 0x08, 0xe8, 0xb8, 0x45, 0x74, 0x2f, 0xa7, 0xa8, 0x45, 0x0d, 0xa7, 0xa7, 0x9c, 0x3c, 0x05, 0xce, 0x90, 0x33, 0xe4, 0x1e, 0x58, 0x99, 0x68, 0x3c, 0xd6, 0xf0, 0x18, 0x55, 0xa5, 0xe5, 0xe4, 0xcc, 0x76, 0xa6, 0x9f, 0x4e, 0x57, 0x3a,\n\t0xd2, 0x1d, 0x3c, 0xd7, 0x59, 0x90, 0x4c, 0xee, 0x2c, 0xd2, 0xd9, 0xe6, 0x1e, 0x0f, 0x8d, 0x99, 0x73, 0x90, 0xb3, 0x39, 0x6d, 0x6d, 0xaa, 0x50, 0xc7, 0x24, 0x5e, 0x1d, 0xea, 0x48, 0xb4, 0xd5, 0xd9, 0x95, 0xe6, 0x8e, 0x9e, 0xce, 0xfe, 0xce, 0x3e, 0xb4, 0x59, 0x34, 0xc8, 0x39, 0xc8, 0x95, 0x27, 0x38, 0x68, 0x28, 0xcd, 0x28, 0xc3, 0x9d, 0xa3, 0x04, 0x55, 0x5c, 0x7d, 0x6c, 0x52, 0x4d, 0x26, 0x78, 0x6a, 0x54, 0x26, 0xe7, 0x64, 0xe7, 0x34, 0xe7, 0xe4, 0xaa, 0x52, 0x77, 0x7e, 0x55, 0xc9, 0xd9, 0xc9, 0x39, 0xcd, 0xb5, 0x9b, 0xe6, 0xad, 0x39, 0x44, 0x33, 0x69, 0x9b, 0xef, 0x5c, 0xe4, 0x6e, 0x56, 0x95, 0x9c, 0x2b, 0x12, 0xb4, 0xb4, 0x22, 0xb5, 0xc2, 0xb9, 0x89, 0x68, 0x0d, 0xd1, 0x26, 0xe7, 0x7a, 0xa4, 0x05, 0x6d, 0xfd, 0x1d, 0x24, 0xf4, 0x61, 0x57, 0x12, 0xed, 0xb5, 0xa8,\n\t0xe2, 0x9a, 0x07, 0x9c, 0x65, 0x95, 0xea, 0x50, 0x76, 0x9a, 0x12, 0xbf, 0x4f, 0x80, 0x8e, 0x5a, 0x7b, 0xd7, 0xe0, 0xb3, 0x10, 0x3b, 0xab, 0x34, 0x99, 0xec, 0xee, 0xd5, 0x82, 0x68, 0x6e, 0xf6, 0x25, 0x28, 0x62, 0x49, 0x48, 0x46, 0xf3, 0x89, 0xa7, 0xb9, 0x27, 0xfd, 0xb7, 0xc9, 0x35, 0x2b, 0xb1, 0x4f, 0x75, 0x65, 0xba, 0xea, 0x25, 0xd1, 0xac, 0x04, 0xe5, 0xd1, 0xd6, 0xd9, 0xd5, 0x34, 0x31, 0xcb, 0xb7, 0x4c, 0xec, 0xcf, 0x46, 0xed, 0xf0, 0x2c, 0x28, 0xae, 0xa0, 0x5e, 0xf4, 0x3c, 0xe8, 0xeb, 0x3a, 0x0c, 0x2e, 0x68, 0x00, 0xd5, 0x59, 0xcc, 0x74, 0xb3, 0x2a, 0x68, 0x84, 0x27, 0xbb, 0x2a, 0xb9, 0x46, 0x9f, 0x29, 0x4b, 0x3e, 0xe6, 0x1a, 0x5d, 0x35, 0x07, 0xee, 0x77, 0x5c, 0x05, 0x4d, 0xac, 0x44, 0x53, 0xe8, 0x59, 0x74, 0xfa, 0x7a, 0xb3, 0xdc, 0xcb, 0x93, 0x7f, 0x55, 0xd0,\n\t0x5c, 0xd7, 0x82, 0x24, 0x5a, 0xec, 0x5a, 0xec, 0x1e, 0x76, 0x36, 0x72, 0xed, 0x4b, 0xd0, 0x32, 0xd7, 0x2a, 0x7a, 0x9a, 0x6d, 0x70, 0x6d, 0x76, 0x95, 0x9e, 0x41, 0x3b, 0x84, 0x4e, 0xfe, 0x2e, 0xda, 0x77, 0x06, 0x1d, 0xfc, 0x5d, 0x74, 0x18, 0x74, 0x8c, 0xe8, 0x5c, 0xfb, 0x93, 0xae, 0x93, 0x6e, 0xa9, 0x1a, 0xa4, 0xb9, 0x5d, 0xbf, 0x8b, 0x02, 0xee, 0x98, 0x3b, 0x8d, 0x68, 0x60, 0xc5, 0x18, 0xcf, 0x71, 0xe7, 0x57, 0xe8, 0x7d, 0xa1, 0xbb, 0x83, 0xbb, 0x8b, 0xbb, 0x9b, 0xbb, 0x87, 0xbb, 0x37, 0x51, 0xbf, 0xc4, 0x3c, 0x36, 0x84, 0x5a, 0x72, 0xa4, 0x7b, 0x8c, 0x7b, 0xbc, 0x7b, 0x92, 0x7b, 0x6a, 0x05, 0xcd, 0xa8, 0xa0, 0xd9, 0x09, 0x9a, 0x97, 0xa0, 0x85, 0xee, 0x25, 0xee, 0xe5, 0xf4, 0x7c, 0x5e, 0xed, 0x5e, 0xe7, 0xde, 0xe8, 0xde, 0xe2, 0xde, 0xe6, 0xde, 0x49, 0xbf, 0xf6,\n\t0xbb, 0x0f, 0xb9, 0x8f, 0xb8, 0x8f, 0xbb, 0x4f, 0x79, 0x14, 0x0f, 0x3d, 0xe8, 0xe9, 0x81, 0x15, 0xa2, 0x19, 0x21, 0x9d, 0xf4, 0x21, 0xd7, 0x53, 0x40, 0x9a, 0x2f, 0xbc, 0xd1, 0xf6, 0x88, 0x35, 0x91, 0x5c, 0x0b, 0xdc, 0x86, 0xf5, 0x51, 0x3d, 0xa4, 0x83, 0xb6, 0xaf, 0xe8, 0x68, 0x07, 0x48, 0x4a, 0x05, 0x57, 0x5c, 0x90, 0xdf, 0x25, 0xb8, 0x84, 0xd5, 0x99, 0x54, 0x86, 0xa3, 0x5f, 0x40, 0x9e, 0x0a, 0xbe, 0x0a, 0xfc, 0x43, 0xc8, 0x5b, 0x81, 0x2f, 0x06, 0x9f, 0x8a, 0xfc, 0x8b, 0xc0, 0x87, 0x20, 0x4f, 0x47, 0xc8, 0x3f, 0x10, 0x57, 0x91, 0x7a, 0x0a, 0x4e, 0x56, 0xa1, 0x90, 0x6c, 0x44, 0xfa, 0x27, 0xe4, 0xe9, 0x87, 0x3a, 0x84, 0x91, 0x56, 0x90, 0x13, 0xeb, 0x41, 0xe9, 0x79, 0x48, 0x02, 0xa8, 0xd5, 0xf9, 0x48, 0x4f, 0x82, 0xbc, 0x83, 0xc8, 0x23, 0x6f, 0x85, 0x44, 0x83, 0xe4,\n\t0x2d, 0xa4, 0xd3, 0x21, 0xaf, 0x8d, 0x12, 0xbe, 0x04, 0xbf, 0x10, 0xf2, 0x06, 0xe0, 0x69, 0xc8, 0xf9, 0x1e, 0xf8, 0xb5, 0x90, 0xb4, 0x44, 0x4d, 0x82, 0x90, 0xfc, 0x13, 0x7c, 0x07, 0xf8, 0x97, 0xe0, 0x77, 0x80, 0xdf, 0x0a, 0x3e, 0x1d, 0xfc, 0x08, 0xf8, 0x3b, 0xe0, 0x9f, 0xa0, 0x84, 0xcb, 0x90, 0xe6, 0x28, 0xa7, 0x1d, 0x24, 0xe3, 0x90, 0x9e, 0x01, 0x5e, 0x02, 0x8e, 0xfb, 0x62, 0x68, 0x43, 0x79, 0x0c, 0xd2, 0xfb, 0x91, 0xfe, 0x3b, 0x8e, 0xbe, 0x0c, 0xfe, 0x2c, 0xca, 0xf9, 0x01, 0x6d, 0x62, 0x5d, 0xe5, 0x2a, 0xe4, 0xec, 0x87, 0xa3, 0xb8, 0x53, 0x3e, 0x0b, 0x7c, 0x36, 0xf8, 0x05, 0x28, 0x61, 0x3d, 0xd2, 0xa8, 0x03, 0xdb, 0x87, 0xb3, 0x70, 0x2f, 0x0c, 0xd7, 0x95, 0xd0, 0x17, 0xca, 0x72, 0xa4, 0x07, 0x20, 0xbf, 0x0f, 0xe9, 0x2d, 0xe0, 0xd3, 0x20, 0x39, 0x88, 0xf4, 0x20,\n\t0xf0, 0x43, 0x90, 0x5c, 0x8e, 0x36, 0xac, 0x89, 0x92, 0x2d, 0x5e, 0x8c, 0xa3, 0x87, 0xd1, 0x9e, 0x3b, 0x91, 0xbe, 0x04, 0x69, 0xb4, 0xaa, 0x04, 0x1d, 0x90, 0x46, 0x83, 0xa3, 0x34, 0xf9, 0x31, 0x9c, 0xd5, 0x06, 0xfc, 0x3e, 0xd4, 0xc1, 0x6a, 0xe1, 0xb7, 0x71, 0x54, 0x07, 0xb7, 0x7a, 0x61, 0x2f, 0xd2, 0x56, 0x5f, 0x40, 0x67, 0xe4, 0xae, 0x90, 0x0f, 0x46, 0xba, 0x0e, 0x4a, 0x38, 0x06, 0x49, 0x6f, 0xf0, 0x57, 0xc0, 0xa1, 0x51, 0xb2, 0x55, 0x87, 0x1e, 0x48, 0x5b, 0xad, 0x51, 0x08, 0x9e, 0x0b, 0xde, 0x04, 0xbc, 0x1e, 0xf4, 0x0a, 0xe5, 0xc8, 0xd0, 0x52, 0x09, 0x2d, 0x2f, 0xa1, 0x8f, 0xa4, 0xf3, 0x50, 0x3e, 0xea, 0xac, 0x34, 0x86, 0x64, 0x0d, 0x2c, 0x8f, 0x99, 0xc8, 0x6f, 0x0a, 0x6e, 0x4b, 0xc7, 0x51, 0x94, 0x26, 0xcd, 0x85, 0x3c, 0x86, 0x3c, 0xe8, 0x47, 0x09, 0x75, 0x53,\n\t0x6a, 0xa0, 0xcd, 0xbf, 0x43, 0x69, 0x23, 0xc0, 0x91, 0x9f, 0x5f, 0x8e, 0xfc, 0xeb, 0xc0, 0xd1, 0xfe, 0x7c, 0x25, 0xd2, 0x12, 0xce, 0x7d, 0x00, 0x92, 0xa6, 0xe0, 0x2d, 0x20, 0x89, 0x80, 0x67, 0x83, 0x5f, 0x0f, 0xfe, 0x24, 0x8e, 0x62, 0x2c, 0x70, 0xab, 0x8f, 0xe6, 0xa3, 0x04, 0xb4, 0xad, 0xf4, 0x1c, 0xd2, 0xcf, 0xa0, 0x0e, 0xbb, 0x21, 0xc1, 0x15, 0xa5, 0x07, 0xc1, 0x71, 0x17, 0xd2, 0xcf, 0xc8, 0x93, 0x83, 0x74, 0x7f, 0xf0, 0xe3, 0xe0, 0x2f, 0x82, 0xff, 0x15, 0x1c, 0x7d, 0xc4, 0x7f, 0x41, 0xda, 0xba, 0xd3, 0x8f, 0x71, 0x16, 0x83, 0x1c, 0x77, 0xc7, 0x31, 0x6f, 0xf0, 0x05, 0x38, 0xda, 0x3e, 0x31, 0x06, 0x05, 0x5f, 0x0b, 0x0e, 0xcd, 0x94, 0x64, 0x9c, 0x05, 0x89, 0x6c, 0xd5, 0x6d, 0x1e, 0xb8, 0x81, 0x5e, 0x78, 0x09, 0xe9, 0x4c, 0x70, 0xb4, 0xbc, 0xd4, 0x19, 0xfc, 0x1a,\n\t0xf0, 0x2b, 0x50, 0xfe, 0x44, 0xa4, 0x8b, 0xc0, 0xad, 0xd1, 0x6a, 0xe9, 0xde, 0x04, 0x70, 0x6b, 0xac, 0x7d, 0x0e, 0x8e, 0xb1, 0xa3, 0xb8, 0x91, 0x9e, 0x0c, 0x8e, 0x96, 0x97, 0x6e, 0x07, 0xbf, 0x19, 0xfc, 0x6a, 0x94, 0x79, 0x14, 0x57, 0xcc, 0x42, 0x3a, 0x0f, 0x1c, 0x6d, 0xc5, 0x3f, 0x03, 0xef, 0x0b, 0x6e, 0xcd, 0x57, 0x06, 0xd2, 0xd0, 0x1f, 0xfe, 0x03, 0xfa, 0x14, 0x9c, 0x87, 0x90, 0x86, 0x9e, 0xb0, 0xef, 0x91, 0x13, 0x3d, 0xc8, 0xbe, 0x06, 0xff, 0x16, 0x79, 0x1a, 0x82, 0xe3, 0xa8, 0xdc, 0x1c, 0xbc, 0x3e, 0x72, 0x36, 0x83, 0x1c, 0x33, 0x21, 0x5f, 0x0a, 0x8e, 0xfb, 0xe2, 0x37, 0xe2, 0x28, 0xce, 0x92, 0xd4, 0xc4, 0x3c, 0x2c, 0xe4, 0x56, 0xef, 0x58, 0xed, 0x9c, 0x01, 0x79, 0x01, 0x38, 0xb4, 0x42, 0x6e, 0x9c, 0xd0, 0x6a, 0xc1, 0xeb, 0x22, 0x4f, 0x77, 0x9c, 0xb5, 0x01,\n\t0xe9, 0x2e, 0x48, 0x3b, 0xc1, 0x1d, 0x90, 0xe0, 0x5c, 0xa9, 0x5e, 0x62, 0x5e, 0x15, 0x1c, 0x7d, 0x24, 0x61, 0x86, 0x97, 0xa0, 0xc9, 0x0a, 0xee, 0x4e, 0xb2, 0x7a, 0x1f, 0xb3, 0x90, 0x8c, 0xeb, 0x4a, 0xc3, 0xc1, 0x1f, 0x87, 0xc4, 0x6a, 0xff, 0xa7, 0xc1, 0x5f, 0x45, 0xf9, 0x4f, 0x41, 0x9e, 0x82, 0xf4, 0xeb, 0x90, 0xb7, 0x05, 0xc7, 0xa8, 0x91, 0xec, 0xe0, 0xdb, 0x71, 0xf4, 0x5f, 0x48, 0x63, 0x26, 0x91, 0xfa, 0x25, 0x66, 0x18, 0xc1, 0x2f, 0x85, 0xe4, 0x06, 0xf0, 0x7b, 0x90, 0xd3, 0xaa, 0x1b, 0x9e, 0x4d, 0x12, 0x7a, 0x41, 0xca, 0x07, 0xc7, 0x9d, 0x72, 0x8c, 0x2f, 0x19, 0xf3, 0x00, 0xc7, 0x28, 0x90, 0xac, 0xb9, 0x02, 0xcf, 0x05, 0xbe, 0x02, 0xfc, 0x36, 0x48, 0x70, 0xef, 0x1c, 0x35, 0xe7, 0x0f, 0x43, 0xd2, 0x09, 0x1c, 0x4f, 0x34, 0x19, 0x73, 0xb5, 0xb4, 0x2d, 0xf1, 0xbc,\n\t0x10, 0x69, 0x2f, 0x38, 0xe6, 0x10, 0x05, 0x2d, 0x66, 0xc3, 0x13, 0x4a, 0x41, 0x8b, 0x29, 0x18, 0x6b, 0xcc, 0xc1, 0x9a, 0x0a, 0x9d, 0x94, 0x26, 0x51, 0xda, 0x2f, 0xb5, 0xb2, 0xb7, 0xb2, 0x17, 0xda, 0xdb, 0xdb, 0x3b, 0xd8, 0x3b, 0xda, 0x3b, 0xd9, 0x3b, 0xdb, 0x2f, 0xb2, 0x77, 0xb1, 0x5f, 0x65, 0xff, 0x4e, 0xb5, 0xa9, 0xa6, 0xd9, 0xd4, 0x6c, 0x63, 0xb6, 0x25, 0x1b, 0x74, 0x12, 0x93, 0xd8, 0x65, 0x4c, 0x66, 0xe2, 0x9b, 0x37, 0xe7, 0xb3, 0x56, 0x2c, 0x0f, 0x78, 0xf8, 0xf9, 0xc0, 0xc3, 0x9b, 0xb1, 0x8b, 0x59, 0x57, 0x76, 0x01, 0x2b, 0x26, 0x6a, 0x01, 0x54, 0xbc, 0x25, 0xbe, 0x36, 0x50, 0xc8, 0xae, 0x65, 0xfd, 0x59, 0x6b, 0x36, 0x80, 0xdd, 0xc1, 0x2e, 0x64, 0x23, 0xd9, 0x68, 0x76, 0x25, 0xbb, 0x97, 0xa8, 0x37, 0xbb, 0x9f, 0x4d, 0xa6, 0xe3, 0x4f, 0x12, 0xdd, 0xc0, 0x16,\n\t0x13, 0x0d, 0x64, 0x4b, 0x88, 0x6e, 0x64, 0x6f, 0xb1, 0x52, 0x36, 0x88, 0x6d, 0x63, 0x1f, 0xb3, 0xe1, 0xec, 0x13, 0xf6, 0x19, 0x1b, 0xc5, 0x3e, 0x67, 0x5f, 0xd2, 0x19, 0x5f, 0xb1, 0xaf, 0xd9, 0x04, 0x56, 0x46, 0xf4, 0x10, 0xf0, 0xf0, 0x49, 0xdc, 0xcb, 0xf3, 0xd8, 0x22, 0xa0, 0xdf, 0x9b, 0xf1, 0x7d, 0x88, 0x77, 0xa5, 0x86, 0x52, 0x43, 0xf6, 0xbe, 0xd4, 0x48, 0x6a, 0xc4, 0x4a, 0xa5, 0xa6, 0x52, 0x33, 0xf6, 0x81, 0xd4, 0x56, 0x7a, 0x8a, 0x6d, 0x97, 0x16, 0xc9, 0xf7, 0xf2, 0x26, 0xf2, 0x38, 0x79, 0x82, 0x64, 0xca, 0x0f, 0xc9, 0x0f, 0x4b, 0x1e, 0xf9, 0x6f, 0xf2, 0xdf, 0x24, 0xbf, 0xfc, 0x84, 0xfc, 0x84, 0x14, 0x90, 0x9f, 0x94, 0x9f, 0x95, 0x82, 0xf2, 0x73, 0xf2, 0x32, 0x29, 0x55, 0x5e, 0xae, 0xb8, 0xa5, 0x1c, 0x81, 0x0c, 0x4b, 0xe3, 0x95, 0x46, 0x4a, 0xa1, 0xf4, 0x80,\n\t0xd2, 0x46, 0xb9, 0x42, 0x7a, 0x54, 0x20, 0xc0, 0xf4, 0xec, 0x0e, 0xd8, 0x02, 0xb4, 0x12, 0xa8, 0x61, 0xcb, 0x90, 0x5e, 0xb0, 0x5d, 0x64, 0xbb, 0x88, 0x9e, 0xb0, 0x2f, 0xd9, 0x96, 0x49, 0xcb, 0x05, 0xf6, 0x2b, 0xad, 0x12, 0xd8, 0x2f, 0xcd, 0xe7, 0x9f, 0xda, 0xbe, 0x94, 0x5e, 0xb3, 0x7d, 0x65, 0x2b, 0x93, 0x36, 0xd9, 0x7e, 0xb0, 0x9d, 0x90, 0xb6, 0xda, 0xe2, 0x76, 0x97, 0xb4, 0xdd, 0xee, 0xb7, 0x07, 0xa4, 0xfd, 0xf6, 0x74, 0x7b, 0x96, 0x74, 0xc0, 0x5e, 0x66, 0x2f, 0x93, 0xbe, 0x11, 0x78, 0xaf, 0x54, 0xa6, 0xd6, 0xd7, 0xbe, 0x91, 0xbe, 0x15, 0xf1, 0xbf, 0xca, 0x52, 0xdd, 0xd4, 0x1d, 0xca, 0x4a, 0xdd, 0xa3, 0xa7, 0x2b, 0xaf, 0x08, 0x3c, 0x56, 0xd9, 0x22, 0xf0, 0x58, 0xe5, 0x7d, 0xbd, 0x9e, 0x5e, 0x4f, 0x29, 0x15, 0xa8, 0xac, 0xf2, 0x81, 0xde, 0x58, 0xef, 0xa4, 0x7c,\n\t0xac, 0x5f, 0xa4, 0x3f, 0xa9, 0x94, 0x89, 0xc8, 0x5c, 0x5b, 0x7b, 0xfd, 0x2d, 0xe3, 0x43, 0xdb, 0xc5, 0xc6, 0x47, 0xc6, 0x2e, 0x7b, 0x2f, 0xf1, 0xf5, 0x0b, 0x7b, 0x5f, 0x81, 0x46, 0xda, 0x87, 0x09, 0x1c, 0xd2, 0x7e, 0xbb, 0xc0, 0x21, 0xed, 0xc3, 0x05, 0xea, 0x68, 0xbf, 0x43, 0xa0, 0x8e, 0xf6, 0x11, 0x26, 0x91, 0xfd, 0x4e, 0xf3, 0x61, 0xf3, 0x31, 0xfb, 0x48, 0xf3, 0xef, 0xe6, 0x42, 0xfb, 0xfd, 0xe6, 0x0b, 0xe6, 0x8b, 0xf6, 0x07, 0xcc, 0x15, 0xe6, 0xab, 0xf6, 0x89, 0xe6, 0x46, 0xf3, 0x5d, 0xfb, 0x14, 0xe6, 0xa7, 0x3e, 0x16, 0xdf, 0x4e, 0xee, 0x55, 0x8d, 0xad, 0xb8, 0xca, 0x5e, 0x78, 0xab, 0x0d, 0xa8, 0xb4, 0x71, 0x7c, 0x53, 0x84, 0xc7, 0xfd, 0x82, 0x9f, 0x1a, 0x2a, 0xb8, 0x94, 0x27, 0x38, 0xbf, 0x3f, 0xbe, 0xd2, 0x3e, 0x3d, 0x38, 0x23, 0xb4, 0xdd, 0x99, 0x1b, 0x5c,\n\t0x1e, 0xdc, 0x16, 0xcc, 0x77, 0x16, 0x04, 0x0f, 0x05, 0x8f, 0x87, 0x8c, 0xd0, 0x1c, 0xf7, 0xc6, 0xe8, 0x09, 0x67, 0xf3, 0xd0, 0x1c, 0x67, 0x9b, 0x50, 0x6e, 0xa8, 0x20, 0x36, 0xda, 0x5b, 0x9c, 0xd2, 0x21, 0xd4, 0x27, 0x16, 0x09, 0x0d, 0x0a, 0x8d, 0x22, 0x6b, 0xb5, 0x6b, 0x68, 0x0e, 0x1d, 0xeb, 0x1e, 0x4b, 0x8d, 0x2c, 0xf4, 0x2e, 0x0e, 0x2d, 0x75, 0x15, 0x87, 0x36, 0x85, 0xd6, 0x07, 0xe7, 0x39, 0x7b, 0x86, 0x0e, 0xc4, 0x32, 0xc3, 0x2c, 0xec, 0x0b, 0x0f, 0x0e, 0x37, 0x8d, 0x1d, 0x0b, 0x77, 0x0e, 0xe6, 0x84, 0xfb, 0x86, 0x8b, 0x29, 0x47, 0xaf, 0xf0, 0x80, 0xf0, 0x88, 0xd0, 0x34, 0x8f, 0xb0, 0x6f, 0x85, 0x85, 0x3b, 0xc8, 0xdf, 0x91, 0x2c, 0xda, 0xad, 0xb1, 0xd1, 0xb1, 0xd1, 0xe1, 0x59, 0xe1, 0x05, 0xe1, 0xb5, 0xd8, 0xd6, 0xc6, 0x1c, 0x31, 0x87, 0x73, 0x78, 0x8a, 0x14,\n\t0x3e, 0x19, 0x1b, 0xed, 0x3f, 0x10, 0x49, 0x4b, 0x09, 0x38, 0x47, 0x45, 0x9a, 0x45, 0x9a, 0x05, 0x0e, 0x3a, 0xc7, 0x46, 0x68, 0x9d, 0x1b, 0xf2, 0x84, 0x0f, 0x3b, 0x27, 0x44, 0xc6, 0xc0, 0xb6, 0x9d, 0x19, 0xee, 0x1b, 0x38, 0x18, 0x59, 0xe8, 0x3e, 0x15, 0xd9, 0x18, 0xd9, 0x16, 0x5d, 0x2a, 0xac, 0xd4, 0x68, 0xf7, 0xe0, 0xd4, 0xe0, 0x54, 0xaa, 0xdb, 0xa2, 0x94, 0x61, 0xd1, 0x51, 0xce, 0xa5, 0xb1, 0x08, 0x95, 0xb7, 0x22, 0x3a, 0xd6, 0xb9, 0x26, 0x38, 0xc3, 0xbf, 0xc6, 0xb9, 0x3e, 0x7a, 0x40, 0x58, 0xa3, 0x91, 0x53, 0xce, 0xed, 0xd1, 0xf5, 0xb1, 0xd1, 0xce, 0x5d, 0x91, 0x8d, 0xc0, 0xe0, 0xca, 0x62, 0xc7, 0x5c, 0x13, 0x43, 0xf3, 0x3d, 0xa1, 0x68, 0x99, 0xf3, 0x68, 0x94, 0x2c, 0xc7, 0xd8, 0x82, 0x98, 0x5d, 0xdc, 0xa3, 0x8b, 0xc5, 0x7c, 0x29, 0x81, 0x58, 0x44, 0x20, 0x27,\n\t0xfe, 0xfe, 0x2e, 0x5f, 0xca, 0x30, 0x57, 0xc4, 0x95, 0x1a, 0x9c, 0x0d, 0x7b, 0x2e, 0x2f, 0xe6, 0xf3, 0x34, 0x77, 0x35, 0xf5, 0x0d, 0x8c, 0xe5, 0xc5, 0xec, 0x91, 0xb4, 0xe0, 0x36, 0x57, 0x4b, 0xef, 0xb2, 0x72, 0x4b, 0x2d, 0xd6, 0x2e, 0xbc, 0x2c, 0xbc, 0x2c, 0xb6, 0x23, 0x56, 0x14, 0x2b, 0x8e, 0x0d, 0x70, 0xf5, 0x72, 0xcf, 0x70, 0xf5, 0x8d, 0x8d, 0x88, 0x8d, 0x8e, 0xce, 0x4c, 0x19, 0x1f, 0x1b, 0xed, 0x1b, 0xe9, 0x29, 0x73, 0x0d, 0x88, 0xed, 0xf3, 0x1f, 0x48, 0x19, 0x16, 0xd9, 0x06, 0xdb, 0x6d, 0x44, 0xac, 0xd8, 0x35, 0x3a, 0xdc, 0xd9, 0x35, 0xce, 0xb3, 0xd4, 0x35, 0x31, 0xb6, 0x9b, 0xf2, 0x4f, 0xf1, 0xb4, 0x09, 0xac, 0x75, 0x4d, 0x8f, 0x1d, 0x8e, 0x1d, 0x8b, 0x9d, 0x4c, 0x91, 0x52, 0x34, 0xd7, 0xac, 0xc0, 0xdc, 0xd8, 0xe8, 0x94, 0xa9, 0xae, 0xb9, 0xd4, 0x4b, 0x6b,\n\t0xfc, 0xd9, 0xfe, 0xa1, 0xa1, 0xec, 0x80, 0x65, 0x55, 0x91, 0xd5, 0x14, 0x1a, 0x44, 0xb5, 0x5b, 0xeb, 0x9d, 0x15, 0x59, 0x1e, 0x99, 0xe7, 0xda, 0x10, 0x5d, 0x14, 0x9d, 0xe6, 0xda, 0x1c, 0x3a, 0x9a, 0xd2, 0x23, 0x25, 0xe0, 0x2a, 0x4d, 0x09, 0x50, 0xbe, 0x1d, 0xb0, 0x87, 0x0e, 0xba, 0xb5, 0x40, 0xaa, 0x3b, 0x4d, 0x58, 0x2f, 0xa1, 0xf5, 0xb0, 0x5d, 0x34, 0xaa, 0xd1, 0x80, 0xd0, 0x1c, 0xcf, 0x9a, 0x60, 0x1a, 0xb5, 0xc1, 0x89, 0x70, 0xdf, 0x98, 0xc3, 0xb2, 0x3f, 0x62, 0x0e, 0xcf, 0x28, 0x77, 0x5a, 0xa4, 0x99, 0xb7, 0x28, 0xdc, 0xae, 0xc2, 0xfe, 0x10, 0x96, 0xc7, 0x6c, 0xff, 0x2e, 0x8f, 0x11, 0x38, 0xe8, 0xe9, 0x49, 0xb6, 0x46, 0x17, 0xff, 0x81, 0x84, 0x1d, 0xd2, 0x2f, 0xbc, 0x21, 0xd6, 0x39, 0x70, 0xd0, 0x3d, 0x30, 0x58, 0x18, 0x8e, 0x08, 0x5b, 0x24, 0xb6, 0xcf, 0xb2,\n\t0x46, 0xc8, 0x7a, 0xd8, 0x4b, 0x16, 0xc9, 0xec, 0xd0, 0xd2, 0x94, 0x1e, 0xc1, 0xb4, 0x94, 0x34, 0xf7, 0xd4, 0xc0, 0xc1, 0x70, 0x5f, 0xd8, 0x23, 0xc2, 0x06, 0x21, 0x2b, 0xc4, 0xbf, 0xd7, 0x33, 0x93, 0x2c, 0x91, 0xd5, 0x81, 0x83, 0xa2, 0xdf, 0x53, 0xb2, 0xc2, 0x9b, 0x85, 0x45, 0x12, 0x68, 0x17, 0x3e, 0xe9, 0x3f, 0xe0, 0x3f, 0x10, 0x1b, 0x1d, 0x49, 0x13, 0xd6, 0x89, 0xb7, 0xa5, 0xb7, 0xa5, 0x7b, 0xa7, 0x67, 0xb8, 0x67, 0x78, 0x74, 0x28, 0x69, 0xc3, 0x9e, 0x14, 0xcd, 0x7f, 0xc2, 0x33, 0x9c, 0xf2, 0x92, 0xc5, 0xe2, 0xcb, 0x11, 0x36, 0x4b, 0xa0, 0x6f, 0x6c, 0x9c, 0xfb, 0x94, 0xbf, 0xab, 0x67, 0xbe, 0x47, 0x89, 0x2e, 0xf5, 0x18, 0xa1, 0x45, 0xe5, 0xd6, 0x8b, 0xaf, 0x5f, 0x4a, 0x07, 0xcf, 0x4c, 0x4f, 0xb6, 0x77, 0xb1, 0x37, 0x4f, 0xd8, 0x31, 0xa1, 0xe1, 0xc2, 0x92, 0xf1,\n\t0x74, 0xf4, 0x74, 0xf5, 0x74, 0x0f, 0x2e, 0x0c, 0x1e, 0xf1, 0xf4, 0xf4, 0xf4, 0xf1, 0xf4, 0x09, 0xef, 0xf0, 0xf4, 0x8f, 0x4e, 0xf3, 0x0c, 0xf2, 0x16, 0x87, 0x3b, 0x87, 0xeb, 0xa5, 0xf4, 0xf3, 0x0c, 0xa5, 0xf2, 0x17, 0x78, 0x46, 0x79, 0xc6, 0x7a, 0x26, 0x78, 0x26, 0x7b, 0xa6, 0x79, 0x66, 0x86, 0x46, 0x79, 0xe6, 0x78, 0xe6, 0x7b, 0x67, 0x79, 0x16, 0xa5, 0x74, 0x49, 0x49, 0x8b, 0x2c, 0x0c, 0xba, 0xa8, 0xcd, 0x96, 0x46, 0x67, 0x7a, 0x56, 0x78, 0xd6, 0x78, 0xd6, 0x7b, 0x36, 0x79, 0xb6, 0x7a, 0xb6, 0x7b, 0x76, 0x79, 0xf6, 0x7a, 0xca, 0x62, 0xa3, 0x3d, 0x07, 0x3c, 0x65, 0x9e, 0xa3, 0x9e, 0x13, 0x5e, 0xe6, 0xb5, 0xa7, 0x34, 0xf3, 0x3a, 0xbc, 0x0e, 0xdf, 0x46, 0x6f, 0x3d, 0xef, 0x66, 0xaf, 0xcf, 0x1b, 0xf1, 0xa6, 0x7a, 0x33, 0x29, 0x9d, 0x17, 0x28, 0xf6, 0x36, 0xa5, 0xfb,\n\t0x6a, 0xe7, 0xed, 0xec, 0x2d, 0xf2, 0x16, 0x47, 0x0e, 0x45, 0xbb, 0x07, 0x8a, 0x23, 0xa7, 0xbc, 0x1b, 0xbc, 0xbd, 0x7c, 0x52, 0xb4, 0xbb, 0xb7, 0xaf, 0x77, 0x40, 0x68, 0xbe, 0x77, 0x70, 0xa0, 0x5d, 0x4a, 0xa1, 0xb7, 0x84, 0xe4, 0x23, 0x62, 0x9d, 0xbd, 0xa3, 0xbd, 0xe3, 0xbc, 0x13, 0xbd, 0x53, 0xbc, 0xd3, 0xbd, 0xb3, 0xbc, 0x73, 0xbd, 0x0b, 0xe8, 0x8e, 0x96, 0xf9, 0x07, 0x79, 0x57, 0x05, 0x0e, 0x53, 0xfe, 0xb5, 0xd1, 0xe6, 0x74, 0xee, 0x66, 0x4a, 0x95, 0x7a, 0x0f, 0x7a, 0x77, 0x78, 0x77, 0x7b, 0xf7, 0xd1, 0xfe, 0xb0, 0xf7, 0x98, 0xf7, 0x64, 0xa0, 0x5d, 0xb4, 0x39, 0xd1, 0x8a, 0x70, 0x71, 0xac, 0x73, 0xa4, 0x9f, 0x4f, 0xf2, 0x69, 0x3e, 0x97, 0x2f, 0xe0, 0x8b, 0xf9, 0xd2, 0xa2, 0x3d, 0x7d, 0x59, 0xbe, 0x1c, 0x5f, 0xbe, 0xaf, 0x99, 0xaf, 0x30, 0xda, 0xc6, 0xd7, 0xc1,\n\t0xd7, 0x25, 0xb6, 0x20, 0x6a, 0x44, 0x8d, 0x94, 0xde, 0x29, 0xbd, 0x7d, 0xdd, 0x7c, 0x3d, 0x82, 0x93, 0x7c, 0xbd, 0xa3, 0x83, 0xfc, 0x34, 0x1e, 0x7c, 0xfd, 0x62, 0x23, 0x7c, 0x03, 0x7d, 0x43, 0x7c, 0xc3, 0x52, 0xc6, 0xfb, 0x46, 0xfa, 0xc6, 0xf8, 0xc6, 0xfb, 0x26, 0xf9, 0xa6, 0x12, 0xcd, 0xf0, 0xcd, 0x8e, 0x64, 0xf9, 0x87, 0xfb, 0xe6, 0xf9, 0x16, 0xfa, 0x96, 0xc4, 0x8e, 0xf9, 0x96, 0xfb, 0x56, 0xfb, 0xd6, 0xf9, 0x36, 0x86, 0xb6, 0xfb, 0xb6, 0xf8, 0xb6, 0xf9, 0x76, 0x46, 0xa4, 0x94, 0x85, 0x29, 0x03, 0x63, 0x11, 0xdf, 0x1e, 0xdf, 0x7e, 0xdf, 0xa1, 0xa0, 0xe6, 0x3b, 0xe2, 0x3b, 0xee, 0x3b, 0x15, 0xf3, 0xf9, 0x15, 0xbf, 0xe1, 0xf7, 0xf8, 0x43, 0x01, 0x5f, 0x68, 0x90, 0xbf, 0x86, 0x3f, 0x3d, 0x34, 0xdc, 0x9f, 0x9d, 0x12, 0x48, 0x19, 0xe6, 0xcf, 0xf5, 0x17, 0xf8, 0x9b,\n\t0xfb, 0xdb, 0xf8, 0x3b, 0xfa, 0xbb, 0xfa, 0xbb, 0xfb, 0x7b, 0xfa, 0xfb, 0xf8, 0xfb, 0x47, 0xb6, 0xf9, 0x07, 0xf9, 0x87, 0xfa, 0x87, 0xfb, 0x47, 0xf9, 0xc7, 0x86, 0x72, 0xfd, 0x13, 0xfc, 0x93, 0xfd, 0xd3, 0xfc, 0x33, 0xfd, 0x73, 0xfc, 0xf3, 0x63, 0xfb, 0x48, 0x6b, 0x16, 0xf9, 0x97, 0xfa, 0x57, 0x04, 0xc6, 0xf9, 0xd7, 0x44, 0x66, 0xa4, 0x0c, 0xf4, 0xaf, 0xf7, 0x6f, 0xf2, 0x6f, 0xf5, 0x6f, 0x27, 0xda, 0xe5, 0xdf, 0x4b, 0x33, 0x49, 0xc0, 0x5f, 0xe6, 0x3f, 0x1a, 0x2e, 0xf6, 0x9f, 0xa0, 0x71, 0x3a, 0x2c, 0xc0, 0x02, 0xf6, 0x98, 0x23, 0x3a, 0x21, 0xe0, 0x08, 0xf8, 0x02, 0x91, 0xe8, 0x89, 0xd0, 0xd2, 0x40, 0x6a, 0x74, 0x69, 0x20, 0x33, 0xb8, 0x3c, 0x50, 0x2f, 0x90, 0x17, 0x68, 0x1a, 0x68, 0x19, 0x5c, 0x18, 0xda, 0x14, 0x1e, 0x10, 0x68, 0x17, 0xe8, 0x1c, 0x28, 0x0a, 0x14,\n\t0xc7, 0x46, 0x07, 0x7a, 0x05, 0xfa, 0xa6, 0x4c, 0x0a, 0x0c, 0x08, 0x0c, 0x0e, 0x94, 0x04, 0x46, 0x04, 0x46, 0x07, 0xc6, 0x05, 0x26, 0x86, 0x46, 0x05, 0xa6, 0x04, 0xa6, 0x07, 0x68, 0x4c, 0x86, 0x8b, 0x03, 0x0b, 0x82, 0xab, 0x03, 0x8b, 0x03, 0xcb, 0x02, 0xab, 0x02, 0x6b, 0x03, 0x1b, 0x02, 0x87, 0x03, 0x9b, 0x03, 0xa5, 0xd1, 0x82, 0xc0, 0x8e, 0xc0, 0xee, 0xc0, 0x3e, 0xba, 0xde, 0x41, 0x2a, 0xeb, 0x70, 0xe0, 0x98, 0x98, 0x9b, 0x82, 0x53, 0x03, 0x27, 0x83, 0xcd, 0xc2, 0xa5, 0x91, 0x91, 0x41, 0x29, 0xa8, 0x85, 0xc6, 0x46, 0xb7, 0x07, 0x5d, 0x91, 0xa9, 0x91, 0xac, 0x60, 0x00, 0x14, 0x0b, 0xee, 0x8f, 0xe4, 0x07, 0xd3, 0xc2, 0x7d, 0x83, 0xdd, 0x22, 0xf3, 0x82, 0x59, 0xc1, 0x9c, 0x94, 0x40, 0x30, 0x3f, 0xdc, 0x32, 0xdc, 0x32, 0xd4, 0x3c, 0xd8, 0x2c, 0x58, 0x18, 0xec, 0x10,\n\t0xec, 0x12, 0x69, 0x16, 0x5d, 0x1f, 0x1d, 0x1a, 0xec, 0x16, 0xec, 0x11, 0xec, 0x1d, 0xec, 0x17, 0x1c, 0x18, 0x1c, 0x12, 0x1c, 0x16, 0x55, 0x82, 0x23, 0x83, 0x63, 0x30, 0xf7, 0x0d, 0x8a, 0x74, 0x89, 0xcc, 0x08, 0x8e, 0x0f, 0x4e, 0x0a, 0x4e, 0x4d, 0x19, 0x1f, 0xda, 0x5a, 0x95, 0x68, 0xbe, 0xdf, 0x1a, 0x9c, 0x1d, 0xda, 0x9e, 0x24, 0xdb, 0x7e, 0x96, 0x94, 0xc8, 0x39, 0xef, 0xcc, 0xb3, 0x2b, 0xf2, 0x55, 0x21, 0x1a, 0x41, 0x0b, 0x89, 0x2f, 0x09, 0x2e, 0x89, 0x6d, 0xa0, 0x67, 0xc9, 0xf2, 0x30, 0x0b, 0xae, 0x0e, 0xae, 0x23, 0xda, 0x98, 0xa0, 0x6d, 0xc1, 0x2d, 0xb4, 0xed, 0x0c, 0xee, 0x21, 0xda, 0x2f, 0x28, 0x65, 0x46, 0xca, 0x3c, 0x7a, 0xda, 0x1c, 0x8a, 0x0d, 0xae, 0x4c, 0xc1, 0xe3, 0xc1, 0x23, 0xc1, 0xe3, 0x22, 0x15, 0x52, 0x92, 0xe5, 0xd6, 0xaf, 0x90, 0x11, 0x3c, 0x65,\n\t0xfd, 0x22, 0x32, 0x2a, 0x1d, 0xf7, 0x60, 0x3f, 0x3a, 0x54, 0x03, 0x14, 0xb2, 0xf6, 0x31, 0xd1, 0xbb, 0xe9, 0xd1, 0x13, 0xf4, 0x1c, 0xa0, 0x67, 0x97, 0xb5, 0x55, 0xa6, 0x50, 0x3a, 0x9e, 0x6a, 0x55, 0x69, 0xce, 0xaf, 0x50, 0x76, 0x95, 0xfd, 0xb9, 0x68, 0x53, 0xb4, 0x0f, 0x3d, 0x3d, 0x73, 0x43, 0x6d, 0x42, 0x05, 0xa1, 0xe6, 0x44, 0x6d, 0x42, 0x6d, 0xe8, 0x29, 0xda, 0x35, 0xd4, 0x91, 0x36, 0x8b, 0xba, 0x87, 0x7a, 0x86, 0xfa, 0x24, 0xa8, 0x7f, 0xa2, 0x3e, 0x83, 0xca, 0xf7, 0xa0, 0xa1, 0xa1, 0xe1, 0x29, 0xc3, 0x2a, 0x53, 0x68, 0x54, 0x68, 0x32, 0x6d, 0x63, 0x93, 0x24, 0x94, 0x0e, 0x4d, 0xa8, 0x9a, 0xef, 0xec, 0x44, 0xe7, 0x8a, 0xba, 0xcd, 0x24, 0x9a, 0x46, 0x1b, 0xa5, 0x63, 0x99, 0xb1, 0xcc, 0x50, 0x99, 0xe0, 0x62, 0x0f, 0x9a, 0x0f, 0x5a, 0x14, 0x59, 0x28, 0xb8, 0x95,\n\t0x0e, 0xad, 0x09, 0xef, 0x0b, 0x2d, 0x0d, 0x2d, 0x8d, 0x2e, 0x0a, 0xad, 0x10, 0x69, 0x41, 0xf4, 0xd4, 0xaf, 0x4a, 0xeb, 0xcf, 0x22, 0xb1, 0x64, 0x42, 0x6b, 0x76, 0x55, 0xd0, 0xde, 0xd0, 0x01, 0x8b, 0xac, 0xeb, 0xe2, 0xda, 0x47, 0x4f, 0xd7, 0x43, 0xfc, 0x3a, 0x4d, 0xf8, 0x7d, 0x22, 0x6c, 0x07, 0x31, 0xda, 0x1c, 0x44, 0xf5, 0xce, 0x20, 0x5f, 0xf8, 0x18, 0xf6, 0x11, 0xf0, 0x63, 0x15, 0xf2, 0xd3, 0xa9, 0xd4, 0x70, 0x66, 0x92, 0x34, 0x8f, 0xa8, 0x69, 0xb8, 0x38, 0x92, 0x1f, 0xc9, 0x8f, 0xad, 0x12, 0x63, 0x0c, 0xd4, 0x39, 0xdc, 0x8e, 0xb6, 0x22, 0x4b, 0x1e, 0xc9, 0x0f, 0xf7, 0x0a, 0xf7, 0x4d, 0x99, 0x9d, 0x32, 0xa6, 0x32, 0x85, 0x07, 0x80, 0x97, 0x54, 0x92, 0x95, 0x84, 0x47, 0x84, 0x07, 0x27, 0x52, 0x94, 0x4e, 0x48, 0x47, 0x87, 0xc7, 0x85, 0x27, 0x56, 0xa2, 0x29, 0xe1,\n\t0xe9, 0x91, 0x79, 0x44, 0x33, 0x22, 0xf3, 0xa2, 0x7b, 0x23, 0x33, 0x68, 0xfd, 0x33, 0x97, 0x56, 0x3f, 0xa5, 0x44, 0x8b, 0xc3, 0xab, 0xce, 0x4a, 0xcb, 0xc0, 0xd7, 0x86, 0x37, 0x84, 0x37, 0x53, 0xae, 0xdd, 0xe1, 0x1d, 0x44, 0xbb, 0x89, 0xf6, 0xa5, 0x74, 0xa0, 0xb5, 0xd2, 0xc1, 0xe8, 0xd6, 0xf0, 0xc1, 0x04, 0x1d, 0xa6, 0xfb, 0x3a, 0x19, 0x91, 0x88, 0xb4, 0x88, 0x0b, 0x57, 0xc1, 0x75, 0xc0, 0x05, 0x05, 0x22, 0xb1, 0x94, 0xf1, 0x95, 0x89, 0x56, 0x59, 0xb4, 0x45, 0xb2, 0x88, 0xe7, 0x24, 0x24, 0x59, 0xd6, 0x56, 0x25, 0x5f, 0x8e, 0xd8, 0xca, 0xf3, 0x54, 0x48, 0x9b, 0xa1, 0x9d, 0x9a, 0x45, 0x0a, 0x63, 0xab, 0x22, 0x3d, 0x88, 0xba, 0x44, 0x3a, 0x80, 0x77, 0x89, 0x74, 0xc3, 0xef, 0x7e, 0xa0, 0x81, 0x91, 0xde, 0xe0, 0x56, 0x7a, 0x48, 0xd4, 0x13, 0x19, 0x16, 0x19, 0x19, 0x19,\n\t0x13, 0x19, 0x0f, 0x9a, 0x94, 0xa8, 0x69, 0x39, 0x4d, 0x4d, 0xd4, 0x79, 0x5e, 0xc5, 0x1d, 0xcc, 0x48, 0x48, 0x66, 0x83, 0x2f, 0x8c, 0x2c, 0xa1, 0x55, 0xce, 0xba, 0x0a, 0x5a, 0x4d, 0xdb, 0x46, 0xd0, 0x96, 0xc8, 0xce, 0x04, 0x6d, 0xab, 0x48, 0x25, 0x51, 0x74, 0xa9, 0x45, 0x91, 0x3d, 0x44, 0xfb, 0x23, 0x87, 0x22, 0x47, 0xa2, 0xdd, 0x23, 0xc7, 0x69, 0x3b, 0x15, 0x55, 0xe8, 0x89, 0xe7, 0x21, 0x0a, 0xc5, 0x66, 0x45, 0x6b, 0x44, 0xd3, 0xa3, 0xd9, 0xd1, 0x5c, 0x7a, 0x5a, 0x16, 0xd0, 0xd6, 0x26, 0xda, 0x31, 0xda, 0x35, 0xda, 0x3d, 0xda, 0x33, 0xda, 0x27, 0xda, 0x3f, 0x3a, 0x28, 0x3a, 0x34, 0x3a, 0x3c, 0x3a, 0x8a, 0x9e, 0x1f, 0x63, 0xa3, 0x13, 0xa2, 0x93, 0xa3, 0xd3, 0xce, 0xa0, 0x99, 0xd1, 0x39, 0x67, 0xd0, 0xfc, 0x5f, 0xa1, 0x45, 0xe7, 0xa0, 0xa5, 0x67, 0xd0, 0x9a, 0xe8,\n\t0x0a, 0xda, 0x7e, 0x0f, 0x6d, 0x25, 0x5a, 0x1f, 0xdd, 0x44, 0x7c, 0x3b, 0xd1, 0xd6, 0x73, 0xec, 0xb7, 0x47, 0x77, 0x45, 0xf7, 0x12, 0x1d, 0xa8, 0x16, 0x95, 0x45, 0x8f, 0x46, 0x4f, 0x9c, 0x9d, 0x62, 0xec, 0x1c, 0x44, 0xcf, 0xdb, 0x18, 0x2d, 0x35, 0x68, 0x86, 0x2e, 0x9f, 0x79, 0x53, 0x53, 0x86, 0x55, 0x8c, 0xfd, 0x7a, 0xb4, 0x82, 0x6e, 0x1a, 0x6b, 0x19, 0x6b, 0x17, 0xeb, 0x4c, 0xeb, 0x65, 0xb1, 0x62, 0xee, 0x15, 0xeb, 0x8b, 0xf9, 0x7c, 0x00, 0x78, 0x89, 0x58, 0x39, 0xc7, 0xc6, 0xc5, 0x26, 0xc6, 0xa6, 0xc4, 0xa6, 0xc7, 0x66, 0xd1, 0xea, 0x7c, 0x2e, 0x6d, 0x8b, 0x63, 0xcb, 0x62, 0xab, 0x62, 0x6b, 0x2d, 0xa2, 0xd5, 0xc5, 0x86, 0x04, 0x6d, 0x8e, 0x95, 0x26, 0x68, 0x47, 0x6c, 0x77, 0x82, 0xf6, 0xc5, 0x0e, 0x9e, 0x5e, 0x47, 0xa7, 0xb8, 0x68, 0x8d, 0x11, 0x4b, 0x49, 0x4b,\n\t0xc9, 0x4a, 0xc9, 0x49, 0xc9, 0x4f, 0x69, 0x96, 0x52, 0x48, 0xe3, 0xa8, 0x4b, 0x4a, 0x37, 0x5a, 0x2b, 0xf7, 0x4e, 0xe9, 0x47, 0x34, 0x30, 0x65, 0x08, 0xcd, 0x95, 0x23, 0x69, 0xfc, 0x8e, 0x4f, 0x99, 0x94, 0x32, 0x95, 0x9e, 0x55, 0xb3, 0x53, 0xe6, 0xa5, 0x2c, 0x14, 0x08, 0x2d, 0xec, 0xa7, 0x17, 0xe3, 0xcf, 0x0a, 0xdc, 0x1b, 0x56, 0x54, 0xcd, 0x53, 0x57, 0x93, 0xe4, 0x53, 0x91, 0x56, 0x26, 0x09, 0x2e, 0x77, 0x10, 0x12, 0xc5, 0x83, 0xf4, 0x54, 0xc1, 0xed, 0x48, 0xdb, 0xdd, 0x90, 0xbc, 0x88, 0xb3, 0x5a, 0x21, 0x7d, 0xb5, 0xe0, 0xec, 0x1b, 0x48, 0xd6, 0x81, 0xbf, 0x02, 0xf9, 0x61, 0xe4, 0xbf, 0x01, 0x92, 0x5b, 0xc0, 0x51, 0x8e, 0xf4, 0x3c, 0xf8, 0x10, 0xe4, 0xe9, 0x08, 0xde, 0x00, 0x92, 0x46, 0xe2, 0x8a, 0x7c, 0x31, 0x72, 0xfe, 0x88, 0xfa, 0x5c, 0x09, 0xf9, 0xfd, 0x90,\n\t0x7f, 0x09, 0xc9, 0xf5, 0x38, 0xfa, 0x33, 0x24, 0xbb, 0x05, 0x97, 0x39, 0x4a, 0xb0, 0xe3, 0xe8, 0x07, 0xc8, 0xff, 0x28, 0xee, 0xa2, 0x21, 0xd2, 0x7b, 0x91, 0xbf, 0x14, 0x79, 0x02, 0xe0, 0xcd, 0x90, 0x73, 0x2f, 0xee, 0xee, 0x61, 0x94, 0xb0, 0x0c, 0xf2, 0xee, 0xe0, 0x33, 0xc0, 0x9b, 0xe2, 0xdc, 0xbe, 0xe0, 0xb5, 0x21, 0x81, 0xdd, 0x29, 0x6d, 0x44, 0xfe, 0x71, 0x28, 0x01, 0xf5, 0x94, 0x3e, 0x42, 0xf9, 0x9f, 0x21, 0x6d, 0xf1, 0xf3, 0x90, 0xa7, 0x0e, 0xd2, 0x0e, 0x9c, 0xfb, 0x37, 0xf0, 0x25, 0x90, 0x3c, 0x83, 0xfc, 0x7f, 0x45, 0xfa, 0x5d, 0xd4, 0x73, 0x14, 0x78, 0x4f, 0x94, 0x89, 0x16, 0x93, 0xba, 0x59, 0x77, 0x8d, 0xb3, 0x0e, 0x21, 0xff, 0x22, 0x1c, 0xdd, 0x07, 0x3e, 0x16, 0x47, 0xad, 0xd2, 0xde, 0x06, 0x7f, 0x16, 0x57, 0xb4, 0xe1, 0x68, 0x18, 0x2d, 0x13, 0x83, 0x24,\n\t0x07, 0xe7, 0x3e, 0x82, 0xf4, 0x55, 0x90, 0xaf, 0xb0, 0xda, 0x0a, 0xf2, 0xe9, 0xe8, 0xb5, 0x05, 0x90, 0x97, 0x82, 0xa3, 0x5f, 0x58, 0x19, 0xd2, 0x0d, 0x71, 0xd6, 0x20, 0xe4, 0xbf, 0x09, 0x12, 0xeb, 0xde, 0x47, 0xe2, 0xdc, 0xf7, 0x70, 0xdd, 0x20, 0xae, 0xd8, 0x07, 0x47, 0x9f, 0x41, 0x5a, 0x81, 0xfc, 0x80, 0x65, 0x9d, 0x43, 0x92, 0x8a, 0xfc, 0xa7, 0xc0, 0x7f, 0x02, 0x7f, 0x01, 0x47, 0x07, 0x22, 0x8d, 0x6b, 0x49, 0xd0, 0x40, 0xe9, 0x56, 0x94, 0xdf, 0x09, 0x57, 0x3c, 0x1f, 0x92, 0x93, 0xc8, 0x73, 0x19, 0xca, 0xff, 0x0e, 0xe9, 0x8b, 0x90, 0xfe, 0x3b, 0x8e, 0x8e, 0x07, 0xef, 0x81, 0xfc, 0x21, 0x1c, 0xfd, 0x1b, 0x4a, 0x7b, 0x47, 0x70, 0x86, 0x3b, 0x95, 0xd0, 0xe3, 0x7c, 0x36, 0xee, 0xeb, 0x5f, 0x38, 0xb7, 0x0b, 0xf2, 0xf4, 0xc0, 0xb5, 0x9e, 0x42, 0xcb, 0x5b, 0xd7, 0xfa,\n\t0x0a, 0xbc, 0x05, 0xe4, 0x56, 0x0f, 0xde, 0x8e, 0x9c, 0x41, 0xc8, 0x8b, 0x91, 0xbe, 0x09, 0x69, 0x4b, 0xc3, 0xd1, 0xef, 0xec, 0x6b, 0xc8, 0x31, 0x2e, 0xf8, 0x72, 0xd4, 0xc4, 0x8b, 0xf4, 0x4b, 0x48, 0x47, 0x91, 0xbf, 0x0f, 0xd2, 0x57, 0x41, 0xbe, 0x07, 0x92, 0x4b, 0x91, 0xfe, 0x18, 0xe9, 0x6b, 0xc1, 0xa1, 0xc3, 0xd2, 0x0f, 0xe0, 0xd6, 0x48, 0x99, 0x09, 0xfe, 0x10, 0x24, 0x59, 0xb8, 0x96, 0xd5, 0xaa, 0xbd, 0xc1, 0x81, 0x85, 0xf0, 0x3b, 0xc1, 0x51, 0x73, 0x7e, 0x1d, 0xf8, 0xcd, 0xe0, 0x17, 0x20, 0xbf, 0xa5, 0x39, 0xc3, 0xc0, 0x55, 0xf0, 0x63, 0xe0, 0xb3, 0xc0, 0x1f, 0x04, 0x2f, 0xb2, 0x5a, 0x18, 0xbc, 0x1f, 0x78, 0x0b, 0xf0, 0x87, 0x71, 0x15, 0xe8, 0x0f, 0xb3, 0x7a, 0x4d, 0x87, 0xa4, 0x16, 0xd2, 0x17, 0x82, 0x37, 0x01, 0xc7, 0xc8, 0xe5, 0x8a, 0x35, 0x1b, 0xa0, 0x85,\n\t0x9f, 0x42, 0xeb, 0x75, 0x40, 0xfe, 0x2d, 0xe0, 0xb8, 0x8a, 0x94, 0x8a, 0xa3, 0x56, 0xbf, 0xff, 0x82, 0x76, 0x1b, 0x80, 0xf2, 0x4f, 0x41, 0x8e, 0x59, 0x85, 0xa1, 0x05, 0x18, 0x46, 0x16, 0xc3, 0x0c, 0xc3, 0x30, 0x76, 0x18, 0xda, 0x96, 0xad, 0x06, 0x5f, 0x08, 0xbe, 0x08, 0x1c, 0x7a, 0x28, 0x37, 0x42, 0x1a, 0xa3, 0x9e, 0x61, 0x06, 0xe3, 0xd0, 0x22, 0x8e, 0x3a, 0xf0, 0x96, 0xe0, 0x18, 0x8f, 0xec, 0x04, 0xd2, 0x1b, 0x91, 0x3e, 0x82, 0x34, 0xe6, 0x1f, 0xde, 0x06, 0x12, 0x8c, 0x5f, 0x9e, 0x81, 0xf4, 0x71, 0xa4, 0xd1, 0xe3, 0x1c, 0x38, 0x93, 0x9c, 0x0f, 0x5e, 0x0c, 0x9d, 0x31, 0x70, 0x47, 0x9f, 0xa0, 0xe6, 0x3f, 0x23, 0x3d, 0x1a, 0x1c, 0xbd, 0x2c, 0xf7, 0xc7, 0x59, 0x47, 0x70, 0x8f, 0x07, 0x91, 0xc7, 0x81, 0xf4, 0x4c, 0xf0, 0x9f, 0xc0, 0xd3, 0xad, 0xb1, 0x8c, 0xb6, 0x6a,\n\t0x8b, 0x34, 0x66, 0x21, 0x8e, 0xd1, 0xad, 0x40, 0xdf, 0x64, 0x13, 0xf2, 0xa3, 0x90, 0xdc, 0x02, 0x89, 0x35, 0xee, 0x30, 0x66, 0xa5, 0x55, 0x98, 0xc1, 0x5a, 0x83, 0x0f, 0x86, 0x04, 0x2d, 0xa6, 0xd4, 0xb0, 0x38, 0x24, 0xfb, 0x71, 0x56, 0x57, 0xf0, 0xd7, 0x20, 0x41, 0x4b, 0xf2, 0x12, 0xd4, 0x6a, 0x07, 0x24, 0xaf, 0x83, 0x63, 0xc6, 0x96, 0x6e, 0x43, 0xfd, 0x0b, 0x50, 0x42, 0x09, 0xd2, 0x6f, 0xe1, 0xdc, 0x6b, 0x90, 0xde, 0x80, 0x3c, 0x97, 0x83, 0x63, 0x1e, 0x90, 0x2c, 0xfd, 0x1f, 0x0f, 0x8e, 0x5e, 0x90, 0x3c, 0xc8, 0x6f, 0xcd, 0x66, 0x7f, 0x01, 0xbf, 0x08, 0x72, 0xcc, 0x72, 0x12, 0x74, 0x49, 0xee, 0x05, 0xf9, 0x1a, 0x48, 0x2e, 0x44, 0x5a, 0xc3, 0x59, 0xb8, 0x0b, 0xd9, 0x9a, 0x43, 0x32, 0x91, 0x13, 0x2d, 0x2f, 0x59, 0x33, 0xf6, 0x00, 0xf0, 0x26, 0xe0, 0x1f, 0x22, 0x27,\n\t0x5a, 0x95, 0xaf, 0x01, 0xc7, 0x4c, 0x2e, 0xe5, 0x42, 0x6e, 0xcd, 0x0c, 0x18, 0xef, 0x12, 0x46, 0x81, 0x84, 0xbe, 0x96, 0x6e, 0x44, 0x5b, 0x8d, 0x02, 0xd7, 0xac, 0x27, 0x20, 0xf2, 0x40, 0x9f, 0xe5, 0xce, 0xe0, 0x39, 0x28, 0xed, 0x13, 0x6b, 0xd6, 0x45, 0x9e, 0x9e, 0x48, 0x43, 0x33, 0xe5, 0x95, 0x90, 0xac, 0x45, 0xfb, 0x58, 0x5a, 0x51, 0x88, 0xf4, 0xb3, 0x90, 0x2b, 0xe2, 0x5c, 0x1b, 0x7a, 0x56, 0xc1, 0xe8, 0x90, 0xac, 0xb1, 0x60, 0x22, 0x0d, 0xed, 0x95, 0xdb, 0x82, 0x3f, 0x86, 0x32, 0x5f, 0x45, 0x4e, 0xcc, 0x39, 0x52, 0x73, 0xc8, 0x9d, 0xd0, 0x3d, 0x6b, 0xae, 0x1b, 0x01, 0x8e, 0x56, 0xe5, 0xd0, 0x3d, 0x1e, 0x43, 0x39, 0x57, 0xa0, 0x86, 0x5b, 0x30, 0xcb, 0xad, 0x45, 0x1a, 0x4f, 0x0a, 0xe9, 0x09, 0xf0, 0x07, 0xc0, 0xeb, 0x22, 0xff, 0x14, 0xe4, 0x39, 0x8e, 0x3c, 0x71,\n\t0x48, 0x76, 0x22, 0xfd, 0x15, 0x6a, 0x85, 0x36, 0x97, 0x9e, 0x84, 0x7c, 0x3d, 0xe4, 0xe3, 0x50, 0x07, 0xdc, 0xbb, 0x14, 0x81, 0xfc, 0x4d, 0x6b, 0x0c, 0xa2, 0x9c, 0xf7, 0x90, 0xa7, 0x31, 0xb8, 0x0f, 0xbc, 0x00, 0xdc, 0x7a, 0xf2, 0xba, 0x90, 0x1f, 0xbd, 0xcc, 0x07, 0x59, 0x57, 0x47, 0x39, 0xf3, 0xc1, 0xe7, 0x81, 0x63, 0xe4, 0x4a, 0xcf, 0xe1, 0x2a, 0x78, 0x0e, 0x4a, 0xb8, 0xa2, 0xf4, 0xa0, 0xc5, 0xad, 0x31, 0x82, 0xf4, 0x1c, 0xe4, 0x41, 0x1f, 0xc9, 0x2a, 0xe4, 0x18, 0x8f, 0x12, 0xee, 0x45, 0x7a, 0x04, 0x69, 0xeb, 0x19, 0x6a, 0x5d, 0xc5, 0xea, 0x4d, 0x6b, 0x1c, 0xd5, 0x03, 0x6f, 0x0f, 0xc9, 0xc7, 0x48, 0x63, 0xa6, 0x95, 0xad, 0x39, 0x13, 0xe3, 0x82, 0x5b, 0x47, 0xf1, 0x04, 0x94, 0x66, 0x59, 0x1c, 0x39, 0xcf, 0x43, 0x5a, 0x46, 0xfb, 0xa0, 0x97, 0x65, 0x09, 0x69, 0xd4,\n\t0x5f, 0x9e, 0x87, 0x3c, 0x98, 0xbb, 0x14, 0x6b, 0x86, 0xff, 0x1e, 0x47, 0x31, 0x63, 0xc8, 0xe9, 0x56, 0xda, 0x7a, 0x82, 0xe0, 0x5a, 0xb9, 0x28, 0xed, 0x1a, 0xeb, 0xba, 0x48, 0xa7, 0x59, 0x1c, 0xe5, 0x60, 0x26, 0xe1, 0x58, 0x6f, 0x48, 0xd6, 0x7a, 0xec, 0x73, 0xc8, 0x3f, 0x47, 0xda, 0x7a, 0xc6, 0xfd, 0x1d, 0xd7, 0xc2, 0xdc, 0xa8, 0xb8, 0x71, 0x74, 0x32, 0xe4, 0xc3, 0x91, 0xbe, 0x1d, 0x69, 0xcc, 0xf0, 0x12, 0x46, 0xab, 0x74, 0xb5, 0xc5, 0x71, 0x8f, 0xd6, 0xfc, 0x8f, 0xd9, 0x83, 0x7f, 0x83, 0xfc, 0x75, 0x21, 0xff, 0x1e, 0xb5, 0xc5, 0x33, 0x45, 0xda, 0x85, 0xa3, 0xbb, 0xc1, 0x31, 0x9f, 0xf0, 0x03, 0xd6, 0x7a, 0x06, 0xf9, 0xa1, 0x75, 0xd2, 0x0c, 0xa4, 0xaf, 0x40, 0x1a, 0xeb, 0x22, 0x7e, 0x08, 0x12, 0xaf, 0xf5, 0xec, 0xc6, 0x59, 0x58, 0x29, 0xf1, 0xa1, 0x90, 0x18, 0xd6,\n\t0x3a, 0x0d, 0xed, 0x60, 0xe5, 0x29, 0xb0, 0x46, 0x10, 0xb4, 0xc8, 0xaa, 0x4f, 0x1d, 0xa4, 0xbf, 0x86, 0x76, 0xa1, 0x3e, 0xec, 0x28, 0xca, 0x09, 0x41, 0x8e, 0x39, 0x93, 0xa1, 0x6d, 0x25, 0x09, 0xd7, 0x45, 0x2f, 0x48, 0x58, 0x09, 0xb0, 0x6f, 0xad, 0xf5, 0x09, 0xca, 0xb1, 0xda, 0xbf, 0x1d, 0xee, 0xc8, 0x1a, 0x41, 0xcd, 0x21, 0x99, 0x80, 0xfc, 0x77, 0x23, 0x5d, 0x1f, 0x69, 0x3c, 0xd7, 0xa4, 0x0b, 0x90, 0x6e, 0x86, 0x74, 0xbe, 0x35, 0x2e, 0x20, 0xb1, 0xb4, 0x02, 0xb3, 0x3a, 0x1f, 0x82, 0xb4, 0x75, 0x14, 0x6b, 0x54, 0x0e, 0x1d, 0xe6, 0x4b, 0x2d, 0x8e, 0xfc, 0x58, 0x2d, 0x73, 0xcc, 0x27, 0x7c, 0xa5, 0x95, 0xb6, 0x34, 0x1f, 0xe9, 0x7b, 0xad, 0xb9, 0x08, 0x57, 0xc1, 0x3a, 0x4a, 0x9a, 0x0a, 0x6e, 0xad, 0x48, 0x55, 0x8b, 0x43, 0x82, 0x79, 0x52, 0x0e, 0x5a, 0x1c, 0x25, 0x58,\n\t0x7a, 0xde, 0x00, 0x12, 0x3c, 0xc7, 0x25, 0x8c, 0x2f, 0xbe, 0x01, 0x7c, 0x9d, 0xd5, 0x4a, 0xc8, 0xd9, 0x1f, 0x69, 0x68, 0x3e, 0xb7, 0xf4, 0x0d, 0xba, 0xc7, 0xf0, 0x74, 0xe3, 0xd0, 0x34, 0x8e, 0x3b, 0x65, 0x58, 0xe7, 0xf0, 0x6c, 0xa4, 0xad, 0xa7, 0xff, 0x6b, 0xd6, 0x13, 0xdc, 0x1a, 0xc5, 0x90, 0x7f, 0x08, 0xfe, 0x23, 0xf8, 0x0e, 0x1c, 0x6d, 0x0c, 0xee, 0x03, 0x5f, 0x00, 0x5e, 0xdf, 0x2a, 0x19, 0x67, 0x61, 0x55, 0xcc, 0xac, 0x67, 0x1f, 0x8e, 0xca, 0xc8, 0x2f, 0xe3, 0x2a, 0x32, 0x66, 0x3f, 0xb9, 0x1e, 0x78, 0x5d, 0x2b, 0x8d, 0xfb, 0xc5, 0x1a, 0x5b, 0xea, 0x6e, 0xdd, 0x11, 0x4a, 0xb3, 0x56, 0x5f, 0x58, 0x95, 0x71, 0x1c, 0xe5, 0xd0, 0x6a, 0x8e, 0x99, 0x90, 0x63, 0xfd, 0x2c, 0x2d, 0xb6, 0xb4, 0xc8, 0x1a, 0xdd, 0x90, 0x58, 0xb6, 0x00, 0x56, 0x0e, 0xb2, 0x8c, 0xf2, 0x31,\n\t0x66, 0xa5, 0x4b, 0x70, 0x14, 0xf3, 0xa4, 0x82, 0x56, 0x92, 0x7e, 0xb1, 0x56, 0xc8, 0xd6, 0xa8, 0x01, 0x7f, 0x1c, 0xf9, 0x27, 0x20, 0xfd, 0x34, 0xf8, 0xab, 0xb8, 0x16, 0xc6, 0x1d, 0x47, 0x5b, 0xc9, 0x29, 0xd6, 0x6c, 0x09, 0xfe, 0x06, 0xea, 0xf6, 0x3a, 0x72, 0xb6, 0xb3, 0xe6, 0x19, 0x70, 0x6b, 0x56, 0xc7, 0x0c, 0x29, 0x59, 0xb3, 0x3d, 0xd6, 0xd5, 0xd2, 0x76, 0x9c, 0xf5, 0x2f, 0xa4, 0x6b, 0xa2, 0x95, 0xb0, 0xce, 0x97, 0xb0, 0xbe, 0x62, 0x96, 0xbd, 0x70, 0x9b, 0xd5, 0xe6, 0xa8, 0x33, 0xc3, 0x5d, 0xe0, 0xa9, 0x2a, 0x5f, 0x6a, 0x71, 0xc8, 0x61, 0x37, 0x49, 0x37, 0x20, 0x7d, 0x0f, 0xd2, 0xf7, 0xa0, 0x7f, 0xad, 0x75, 0x23, 0x5a, 0x5b, 0x42, 0xeb, 0xc9, 0x78, 0xc2, 0xb2, 0x6f, 0x51, 0x32, 0x9e, 0x32, 0x52, 0x57, 0x70, 0xcb, 0x66, 0xc1, 0xec, 0xcd, 0x61, 0x19, 0xf1, 0x77,\n\t0xad, 0xf5, 0x0c, 0x24, 0x8f, 0x83, 0x4f, 0x83, 0xa4, 0x96, 0x35, 0xef, 0xa1, 0x9c, 0x2f, 0x21, 0xe9, 0x02, 0x09, 0x66, 0x1e, 0x8e, 0x55, 0xb4, 0x74, 0x17, 0xae, 0x75, 0x39, 0xea, 0xb3, 0xcd, 0x9a, 0xf1, 0x2c, 0xfb, 0xc8, 0x9a, 0x0d, 0xac, 0xf1, 0x85, 0x96, 0x87, 0x46, 0xc9, 0x18, 0x4d, 0x36, 0xac, 0x7e, 0x15, 0x3c, 0xd3, 0x15, 0xb4, 0xa1, 0x8c, 0xfa, 0x33, 0x07, 0x6b, 0x23, 0x7c, 0x72, 0xf8, 0x1c, 0x26, 0x31, 0x0d, 0xf1, 0x5d, 0x0c, 0x91, 0x5d, 0x2e, 0x44, 0x76, 0x05, 0x54, 0x55, 0x35, 0x59, 0x4d, 0x35, 0xa2, 0x46, 0x58, 0x3a, 0x62, 0xba, 0x32, 0xcc, 0x37, 0xcc, 0xf5, 0xac, 0xa1, 0xb9, 0xc1, 0x7c, 0x8b, 0x35, 0xa2, 0x33, 0xc3, 0x4c, 0x66, 0x26, 0x73, 0x33, 0x2f, 0xbe, 0x73, 0xb5, 0x55, 0x7e, 0x52, 0x15, 0xd1, 0x7f, 0xe3, 0xd4, 0xf1, 0xea, 0x22, 0x75, 0xb1, 0xfa,\n\t0x9e, 0x5a, 0x2a, 0xfe, 0xdb, 0x9b, 0x16, 0xd4, 0xc2, 0xda, 0x18, 0x6d, 0x8a, 0x91, 0x22, 0xfe, 0x8b, 0x35, 0x13, 0x5f, 0x32, 0xd8, 0x93, 0xb4, 0xed, 0x4f, 0xda, 0xf6, 0x54, 0x49, 0x6f, 0x49, 0x6c, 0xdb, 0xaa, 0xc8, 0xcb, 0xb7, 0x9d, 0xd5, 0x38, 0x6f, 0xe7, 0x39, 0xce, 0x15, 0xbf, 0xc5, 0xd7, 0x1a, 0xc4, 0x97, 0x08, 0xc4, 0x57, 0x0b, 0x44, 0xbc, 0x80, 0x42, 0x9b, 0x41, 0x9b, 0x87, 0xb6, 0x10, 0x6d, 0x35, 0xaa, 0x6c, 0xe9, 0x89, 0x2d, 0x1b, 0x1b, 0x8f, 0xcf, 0x10, 0x1e, 0xff, 0xf1, 0x7c, 0xf8, 0xfd, 0x3f, 0x04, 0x3e, 0x0e, 0xfc, 0x28, 0x38, 0xb3, 0xe5, 0x32, 0xfe, 0x4b, 0x19, 0xf8, 0x4f, 0xe0, 0x9f, 0x0b, 0x4e, 0xf2, 0x9e, 0x94, 0x3e, 0x08, 0xfe, 0x05, 0xf8, 0x67, 0x82, 0x53, 0x69, 0xc5, 0xd4, 0xcf, 0xf3, 0xc4, 0xb9, 0xfc, 0x79, 0xe2, 0x61, 0xd6, 0x92, 0x75, 0x26,\n\t0x2a, 0x62, 0xc5, 0xac, 0x17, 0xcb, 0x63, 0x4d, 0xe9, 0x77, 0x3b, 0x48, 0x2c, 0xa9, 0x45, 0xc5, 0x38, 0xda, 0x57, 0xbc, 0x9d, 0x8d, 0xff, 0x8c, 0xfa, 0x14, 0x09, 0xce, 0x56, 0x83, 0xaf, 0x84, 0xe4, 0x69, 0xf0, 0xbf, 0x82, 0xbf, 0x09, 0xde, 0x06, 0xbc, 0x15, 0xf2, 0xc8, 0xe0, 0x0e, 0xf1, 0xbf, 0x16, 0xa5, 0x63, 0xca, 0x06, 0x4a, 0x5f, 0x67, 0xaf, 0x63, 0xaf, 0x6b, 0xaf, 0x6f, 0x6f, 0x60, 0x6f, 0x68, 0x6f, 0x64, 0x6f, 0x6c, 0x6f, 0x62, 0x3f, 0xdf, 0x7e, 0x81, 0xbd, 0x85, 0xbd, 0xb5, 0xbd, 0x0d, 0x69, 0x49, 0x57, 0xfb, 0x25, 0xf6, 0x22, 0xfb, 0xa5, 0xf6, 0x6e, 0xf6, 0xcb, 0xec, 0xdd, 0xed, 0x97, 0xdb, 0x8b, 0xed, 0x57, 0xd8, 0x7b, 0xd8, 0xaf, 0xb4, 0xf7, 0xb4, 0x1f, 0xb4, 0x1f, 0x22, 0xfd, 0xf9, 0xde, 0x7e, 0xd4, 0xfe, 0x83, 0xfd, 0x98, 0xfd, 0x47, 0xfb, 0x49, 0xfb,\n\t0x2f, 0xf6, 0x53, 0xf6, 0xb8, 0xca, 0x54, 0xae, 0x4a, 0xaa, 0xac, 0x2a, 0xaa, 0x9d, 0x74, 0x4a, 0x53, 0x75, 0xd5, 0x50, 0x4d, 0xd5, 0xa9, 0xba, 0x55, 0x8f, 0x88, 0x18, 0x24, 0xdd, 0x4a, 0x53, 0xcf, 0x53, 0xd3, 0xd5, 0x0c, 0x35, 0x53, 0xad, 0xad, 0x66, 0xa9, 0x75, 0xd4, 0x6c, 0xb5, 0xae, 0x5a, 0xcf, 0x94, 0x4c, 0x9b, 0xa9, 0x9a, 0x9a, 0x69, 0x98, 0x4e, 0xd3, 0x6d, 0xfa, 0xcc, 0x80, 0x19, 0x32, 0x6b, 0x9b, 0x0d, 0xcc, 0x86, 0x66, 0x9e, 0xd9, 0xd8, 0x6c, 0x62, 0x36, 0x35, 0x9b, 0x99, 0x2d, 0xcc, 0x42, 0xf3, 0x42, 0xb3, 0x8b, 0x39, 0xd6, 0xbc, 0xdf, 0x9c, 0x60, 0x4e, 0x34, 0x9f, 0x37, 0x17, 0x99, 0x6b, 0xcc, 0xb5, 0xa4, 0xa9, 0x1b, 0x48, 0xab, 0x7b, 0xfd, 0x2e, 0x3f, 0x87, 0xfe, 0xac, 0x10, 0x1e, 0x0e, 0x1d, 0xe1, 0xe1, 0xd0, 0x13, 0x1e, 0x0e, 0xd7, 0xb0, 0xfb, 0xd9,\n\t0x23, 0xac, 0x0f, 0xfb, 0x27, 0xd1, 0x6f, 0x79, 0x35, 0x08, 0x7f, 0x86, 0x87, 0xe0, 0xcf, 0xf0, 0x3c, 0xfc, 0x19, 0xde, 0xe1, 0xfb, 0xf9, 0x41, 0xb6, 0x59, 0xca, 0x4d, 0xf8, 0x33, 0x14, 0xb0, 0x0f, 0xa4, 0xa6, 0xd2, 0xf9, 0xec, 0x23, 0xa9, 0xad, 0xf4, 0x28, 0xfb, 0x58, 0x7a, 0x4c, 0x9a, 0xc3, 0x73, 0xa5, 0x67, 0xa5, 0xe7, 0x78, 0x33, 0x69, 0xa1, 0xb4, 0x90, 0xb7, 0x90, 0x16, 0x49, 0xfb, 0x79, 0x4b, 0xe9, 0x80, 0x9c, 0xc5, 0xef, 0x90, 0xdb, 0xca, 0xed, 0xf9, 0x72, 0xf9, 0x42, 0xb9, 0x0b, 0x5f, 0x29, 0x5f, 0x2a, 0x5f, 0xca, 0x5f, 0x93, 0x2f, 0x93, 0x7b, 0xf0, 0xb5, 0x72, 0x4f, 0xb9, 0x37, 0xdf, 0x20, 0xf7, 0x91, 0xfb, 0xf0, 0x77, 0xe4, 0xbe, 0x72, 0x5f, 0xbe, 0x59, 0xbe, 0x49, 0x1e, 0xc2, 0xdf, 0x95, 0x87, 0xca, 0x43, 0xf9, 0xfb, 0x72, 0x89, 0x5c, 0xc2, 0x4b, 0xe5,\n\t0xdb, 0xe5, 0xdb, 0xf9, 0x07, 0xf2, 0x08, 0x79, 0x04, 0xdf, 0x26, 0x8f, 0x94, 0x47, 0xf1, 0x0f, 0xe5, 0x27, 0xe5, 0x65, 0x7c, 0x87, 0xf0, 0x8b, 0xe0, 0x87, 0xe1, 0x11, 0xd1, 0x05, 0x1e, 0x11, 0x3d, 0xe1, 0x11, 0x31, 0x44, 0x29, 0x53, 0xca, 0xa4, 0x5b, 0x94, 0x53, 0xca, 0x29, 0x69, 0x28, 0xbc, 0x23, 0x6e, 0x85, 0x77, 0x44, 0x89, 0xad, 0xbd, 0xad, 0x83, 0x34, 0xd2, 0xb6, 0xc6, 0xb6, 0x56, 0x1a, 0x65, 0x7b, 0xc3, 0xf6, 0xa6, 0x74, 0x8f, 0xed, 0x53, 0xdb, 0xe7, 0xd2, 0x58, 0x11, 0x13, 0x27, 0x3d, 0x00, 0xef, 0x88, 0x07, 0xe1, 0x1d, 0xf1, 0x08, 0xbc, 0x23, 0x1e, 0x85, 0x5f, 0xc4, 0xb3, 0xf0, 0x88, 0x58, 0x28, 0x22, 0xe0, 0xa4, 0xe7, 0x45, 0x04, 0x9c, 0xb4, 0x5d, 0x44, 0xc0, 0x49, 0x87, 0x45, 0x04, 0x9c, 0x5c, 0x20, 0x22, 0xe0, 0xe4, 0x81, 0x9a, 0x53, 0xfb, 0x46, 0x1e,\n\t0x01, 0x7f, 0x89, 0xab, 0x74, 0x43, 0x77, 0x28, 0x7d, 0xe1, 0x2f, 0x71, 0x1d, 0xfc, 0x25, 0x86, 0xc3, 0x5f, 0xe2, 0x4e, 0xf8, 0x4b, 0x8c, 0x84, 0xbf, 0xc4, 0x5d, 0xf0, 0x97, 0xb8, 0x17, 0xfe, 0x12, 0xd3, 0x85, 0xbf, 0x84, 0xf2, 0xb5, 0xfe, 0x96, 0xfe, 0x93, 0xf2, 0xbd, 0x88, 0x11, 0xb3, 0x65, 0x19, 0x0d, 0x8d, 0x6d, 0xb6, 0x26, 0x22, 0x9e, 0xcb, 0xf6, 0x89, 0xf0, 0x9d, 0xb0, 0xed, 0x12, 0xbe, 0x13, 0xb6, 0xc3, 0xc2, 0x3b, 0xc2, 0xf6, 0x9d, 0x88, 0xc9, 0xb2, 0x9d, 0x14, 0x7e, 0x11, 0xb6, 0x53, 0xe6, 0x46, 0xf3, 0x1d, 0xbb, 0x22, 0xe2, 0xb0, 0xec, 0x1a, 0xbb, 0x8e, 0xc6, 0xf1, 0xfc, 0xdf, 0xd8, 0x26, 0x57, 0x23, 0xcf, 0x7f, 0x73, 0x9b, 0xf6, 0x1b, 0xc7, 0x67, 0xd2, 0x36, 0xe7, 0x1c, 0xc7, 0x16, 0x55, 0xd9, 0x96, 0x26, 0x6d, 0x2b, 0x68, 0x5b, 0x73, 0x7a, 0xf3, 0x4a,\n\t0xe7, 0xde, 0x90, 0x67, 0xbd, 0xb5, 0x55, 0x92, 0xad, 0x39, 0x2d, 0x2b, 0x2f, 0xa3, 0x6a, 0x99, 0x38, 0x6f, 0x93, 0xb5, 0x55, 0x29, 0xb7, 0x3c, 0xee, 0xca, 0x8a, 0xb5, 0xaa, 0x56, 0x64, 0x15, 0xe6, 0xca, 0xfb, 0x31, 0x7f, 0x6d, 0x54, 0xfa, 0xda, 0xf5, 0x40, 0xd3, 0x40, 0x53, 0x47, 0xc0, 0xdf, 0xd5, 0xdf, 0xdf, 0x11, 0x73, 0xd6, 0xf0, 0x0f, 0x0f, 0x6f, 0xf6, 0x4f, 0x08, 0xed, 0x72, 0x2e, 0x0d, 0x97, 0x3a, 0xd2, 0xfc, 0xf3, 0x1d, 0x59, 0xfe, 0xa5, 0xfe, 0x35, 0x8e, 0x1c, 0x77, 0x37, 0xff, 0x26, 0xff, 0x76, 0xff, 0x5e, 0x47, 0xbe, 0xbf, 0x2c, 0xd8, 0xc3, 0xd1, 0x2c, 0xd4, 0x35, 0xe0, 0xf0, 0x97, 0x39, 0x4f, 0x04, 0x7c, 0x8e, 0xc2, 0x40, 0xaa, 0x73, 0x51, 0x20, 0x2f, 0x90, 0xe7, 0x58, 0xee, 0xe8, 0x80, 0x77, 0xb6, 0xc5, 0x81, 0xbe, 0x81, 0x92, 0xc0, 0x44, 0xcf, 0xae,\n\t0xc0, 0xac, 0xc0, 0xac, 0xe0, 0x91, 0xe0, 0x10, 0x11, 0x07, 0x13, 0x58, 0x10, 0x58, 0x6c, 0xc5, 0xc2, 0xf8, 0x26, 0x39, 0x06, 0xfa, 0xa6, 0x3a, 0x86, 0x38, 0x86, 0x85, 0x8c, 0xc0, 0x8e, 0x60, 0x0e, 0x91, 0x16, 0x74, 0x05, 0x5d, 0x8e, 0x91, 0xb4, 0x8d, 0x09, 0xc6, 0x3c, 0x86, 0x63, 0x7c, 0x30, 0x2b, 0xd8, 0xcc, 0xb3, 0xd5, 0x33, 0x56, 0xbc, 0x63, 0x75, 0x4c, 0x0a, 0x0e, 0x0b, 0x4c, 0x09, 0x4f, 0x77, 0x1d, 0x0c, 0x4e, 0x0d, 0xae, 0xf3, 0x36, 0x75, 0x4c, 0x75, 0xb5, 0x0c, 0x2e, 0x77, 0xcc, 0x10, 0x11, 0x33, 0x8e, 0x85, 0xa1, 0x69, 0xc1, 0x3d, 0xee, 0xb4, 0xe0, 0x91, 0x90, 0xe2, 0x2a, 0x09, 0xac, 0x75, 0x2c, 0x71, 0x8d, 0xf3, 0x8d, 0xf7, 0x4f, 0x70, 0x2c, 0x0f, 0x6d, 0x0f, 0xd5, 0x70, 0xac, 0x0e, 0x97, 0x86, 0xd2, 0x1d, 0xeb, 0x42, 0xd9, 0xc1, 0x1e, 0xc1, 0x61, 0x9e,\n\t0x39, 0x54, 0x87, 0x48, 0x28, 0xe4, 0xd8, 0xe8, 0xd8, 0xe2, 0xd8, 0x16, 0x1a, 0xe4, 0xd8, 0x19, 0xd8, 0xe1, 0x9d, 0x28, 0x62, 0x5e, 0x3c, 0x2b, 0x1c, 0x87, 0xdc, 0xab, 0x3d, 0x93, 0x1d, 0x47, 0x42, 0x73, 0x1c, 0xc7, 0x43, 0xf3, 0x1d, 0xa7, 0x42, 0x2b, 0xc2, 0x83, 0xbd, 0x79, 0x22, 0xe6, 0xc5, 0xb7, 0xd1, 0xe9, 0xf1, 0x1c, 0xf5, 0x16, 0x79, 0x53, 0x43, 0x9b, 0x42, 0xdb, 0xbd, 0x76, 0x67, 0xc8, 0x59, 0xc3, 0x99, 0xee, 0xb5, 0x7b, 0xed, 0x81, 0xce, 0xce, 0x6c, 0x67, 0x76, 0x78, 0x95, 0x33, 0xd7, 0x3f, 0xc7, 0x59, 0xe0, 0xef, 0xef, 0x6c, 0x1e, 0xee, 0xec, 0xdd, 0xe1, 0xdd, 0xe1, 0x6c, 0x13, 0x1c, 0x18, 0x3a, 0xe1, 0x1b, 0xe3, 0x5d, 0xeb, 0xec, 0xe8, 0xed, 0x1b, 0x76, 0x84, 0x53, 0xbd, 0x73, 0xbd, 0xa5, 0xde, 0xd2, 0x70, 0xd3, 0x70, 0x4b, 0x5f, 0x87, 0x60, 0xef, 0x70,\n\t0x4b, 0xef, 0x66, 0x11, 0x6f, 0x22, 0xde, 0x77, 0x79, 0xa7, 0x3b, 0x7b, 0x12, 0xf5, 0x71, 0xf6, 0x0f, 0x9d, 0x08, 0xce, 0x08, 0x94, 0x38, 0x07, 0x79, 0x07, 0x04, 0x35, 0xe7, 0x50, 0xcf, 0x1a, 0x11, 0x6d, 0xe2, 0xeb, 0xe0, 0x1c, 0xeb, 0x5e, 0xe8, 0xd9, 0xee, 0x9c, 0xe0, 0xd9, 0xea, 0x4b, 0x73, 0x8d, 0xf0, 0x2e, 0x70, 0x4e, 0x0e, 0x8e, 0x74, 0x6e, 0x0d, 0xac, 0x15, 0xfe, 0x37, 0x56, 0x5c, 0x48, 0x68, 0xab, 0x77, 0x81, 0x7f, 0x82, 0x73, 0x69, 0x68, 0xab, 0x73, 0x85, 0x73, 0x4d, 0xf8, 0x98, 0x7f, 0x6f, 0x68, 0xbb, 0xaf, 0x8b, 0x73, 0xbd, 0xf3, 0x84, 0x73, 0x93, 0xbf, 0x7b, 0xa0, 0x5e, 0xa8, 0x39, 0xa2, 0x3a, 0x76, 0x85, 0xa7, 0x38, 0xf7, 0x7a, 0x0f, 0x7b, 0x3b, 0x87, 0x4b, 0xfd, 0xc3, 0xfd, 0xcd, 0x9d, 0x07, 0x02, 0xc5, 0xce, 0x32, 0x97, 0xc3, 0x3f, 0xc8, 0x79, 0x34,\n\t0x90, 0xe7, 0x3c, 0xe1, 0x62, 0x81, 0x62, 0xe1, 0x65, 0x13, 0x2e, 0x0d, 0x6a, 0x22, 0xda, 0x82, 0x5a, 0x33, 0x35, 0xdc, 0xce, 0x95, 0x19, 0xcc, 0x11, 0x9e, 0x36, 0xae, 0xa6, 0xc1, 0xde, 0xae, 0x55, 0xae, 0x5e, 0xae, 0x96, 0xee, 0x42, 0x4f, 0x81, 0x67, 0x5a, 0xf0, 0x88, 0x67, 0xbd, 0xab, 0x1d, 0xf5, 0xee, 0x02, 0x77, 0x4e, 0xb0, 0xd0, 0x3d, 0xd2, 0x55, 0xe2, 0xea, 0xec, 0x2a, 0x75, 0xbb, 0x10, 0x23, 0xd1, 0xcb, 0x9d, 0xe5, 0x2a, 0xa1, 0xde, 0x12, 0x51, 0x11, 0x73, 0x5d, 0x83, 0xa9, 0x77, 0x63, 0xc2, 0xbf, 0xc6, 0x35, 0xda, 0x35, 0x2e, 0xd8, 0x0f, 0x71, 0x0b, 0x53, 0xac, 0xd8, 0x85, 0xc0, 0x6e, 0xef, 0x38, 0xd7, 0xaa, 0xf0, 0xac, 0x90, 0x12, 0x2c, 0xf4, 0x8d, 0x14, 0xba, 0x12, 0x9a, 0x86, 0x78, 0x85, 0xc5, 0x81, 0x1d, 0xae, 0x65, 0xbe, 0xfd, 0xde, 0x71, 0xf4, 0x7b,\n\t0x55, 0x22, 0x1e, 0x61, 0x83, 0x6b, 0xb3, 0x77, 0x77, 0xb0, 0x99, 0x88, 0x43, 0x20, 0x9d, 0xe9, 0x2d, 0xbc, 0x69, 0xbc, 0xd3, 0x5d, 0xfb, 0x68, 0xb3, 0xe2, 0x04, 0x8e, 0x85, 0xe7, 0xba, 0x67, 0x78, 0x0f, 0x86, 0x17, 0x5b, 0x3e, 0x35, 0x96, 0x07, 0x8d, 0x77, 0x59, 0xc8, 0x70, 0xa7, 0x79, 0xe7, 0x7a, 0xa6, 0x25, 0x79, 0xf0, 0x17, 0xba, 0x3b, 0x84, 0x0a, 0xdc, 0x5d, 0xc2, 0xfb, 0xca, 0xfd, 0x66, 0x48, 0x43, 0x89, 0xc2, 0xd3, 0xc3, 0x7d, 0xdd, 0x03, 0xbd, 0xed, 0x2a, 0xbc, 0xf8, 0x13, 0x7e, 0xfc, 0xde, 0x89, 0xee, 0x85, 0xee, 0x19, 0xc1, 0x53, 0x1e, 0xc5, 0x37, 0x26, 0xe1, 0x31, 0x23, 0xbc, 0xf6, 0x57, 0xbb, 0xd7, 0x05, 0x76, 0x87, 0x4b, 0x84, 0xdf, 0x7e, 0x38, 0xd5, 0xd7, 0x23, 0xbc, 0x81, 0xae, 0xb4, 0x2d, 0x38, 0x32, 0xa4, 0x9c, 0xf6, 0xe1, 0xf7, 0xad, 0x13, 0x5e,\n\t0xfc, 0xe1, 0x7d, 0xc2, 0x8f, 0x3f, 0xb0, 0xa3, 0xb2, 0x1f, 0xbf, 0xef, 0xb8, 0xf0, 0xe5, 0xf7, 0xee, 0xf6, 0xb4, 0xf1, 0x87, 0x2c, 0x2f, 0x18, 0x78, 0xc0, 0xf4, 0xf7, 0x0c, 0x0a, 0x4d, 0x10, 0x5e, 0x2f, 0xde, 0x65, 0xe1, 0x0d, 0x9e, 0x51, 0xde, 0xdd, 0x81, 0x65, 0x9e, 0xb1, 0xbe, 0x34, 0x5f, 0x33, 0xcf, 0x04, 0xef, 0x44, 0xcb, 0x03, 0xc6, 0xb3, 0x88, 0xc6, 0x67, 0x81, 0x67, 0x8e, 0x7f, 0xbb, 0x67, 0x7e, 0xa8, 0x4d, 0xf8, 0x70, 0xa0, 0xc4, 0x3b, 0xce, 0xb3, 0xc8, 0xb3, 0xd7, 0xb3, 0xd4, 0xb3, 0x02, 0x5e, 0x30, 0x7b, 0x83, 0xfd, 0x92, 0x3d, 0x61, 0x42, 0x9b, 0x3c, 0x07, 0xbc, 0x4d, 0xbd, 0x79, 0x9e, 0x32, 0x6f, 0xc4, 0xf2, 0x86, 0x11, 0xef, 0x3a, 0xbd, 0x76, 0x7f, 0xff, 0x40, 0x3d, 0xd2, 0x8f, 0x76, 0x5e, 0x87, 0x37, 0xd3, 0x9b, 0xe9, 0x9f, 0xe3, 0xf5, 0x59, 0x7e,\n\t0x31, 0x38, 0x9a, 0xe9, 0xdf, 0x1e, 0xda, 0x1a, 0x9e, 0x22, 0x3c, 0x64, 0xbc, 0x4d, 0x29, 0x8f, 0xf0, 0x90, 0x69, 0xe7, 0x3f, 0x41, 0xbc, 0x88, 0x8e, 0x76, 0xf6, 0x77, 0xf5, 0x2e, 0x10, 0xfe, 0x32, 0xde, 0x5e, 0xde, 0x0d, 0xde, 0xb5, 0xc2, 0x4b, 0x86, 0x34, 0x7c, 0xb0, 0xb7, 0x84, 0xf4, 0x79, 0x04, 0x6d, 0xa3, 0xbd, 0x9b, 0x85, 0x8f, 0x4c, 0xf0, 0x14, 0xbc, 0x64, 0x16, 0xf8, 0xd6, 0x79, 0x67, 0xc1, 0x57, 0xa6, 0x14, 0x1a, 0xbf, 0x20, 0xdc, 0x34, 0x30, 0x2b, 0x3c, 0x97, 0x46, 0xf6, 0x48, 0xef, 0x62, 0xca, 0xb3, 0xcc, 0xbb, 0x8a, 0x52, 0x6b, 0xc5, 0x51, 0xe1, 0x3b, 0x13, 0xf2, 0x50, 0xea, 0x58, 0x78, 0x04, 0xd5, 0x68, 0x87, 0xbf, 0x79, 0x20, 0xcf, 0x3f, 0x99, 0x5a, 0x61, 0x87, 0xf0, 0xa3, 0x09, 0xec, 0x08, 0xb7, 0x13, 0xbe, 0x34, 0x3e, 0xcd, 0x7b, 0xd2, 0xa7, 0x09,\n\t0x0f, 0x9a, 0x60, 0xc0, 0xe7, 0xf2, 0x97, 0xf9, 0x02, 0xfe, 0xfe, 0xe1, 0x93, 0xc2, 0x93, 0xe6, 0xb4, 0x1f, 0x8d, 0xf0, 0xa2, 0x09, 0xcc, 0x12, 0xde, 0x33, 0xbe, 0xde, 0xbe, 0x7e, 0xbe, 0x81, 0x81, 0x29, 0xc2, 0x6b, 0x26, 0xa8, 0x91, 0x9e, 0x2d, 0x80, 0xdf, 0xcc, 0xf8, 0xd0, 0x4c, 0xe1, 0x3b, 0x13, 0x74, 0x09, 0xdf, 0x19, 0x9a, 0x2b, 0xc6, 0x5a, 0xbe, 0x33, 0xfe, 0xa1, 0xc1, 0x21, 0xa4, 0xb1, 0x85, 0xbe, 0xe5, 0xc1, 0x6d, 0x96, 0x0f, 0x8d, 0x6f, 0x8b, 0x78, 0xdf, 0xed, 0x5f, 0x2f, 0xfc, 0x68, 0xe8, 0x7a, 0x7b, 0x82, 0xc3, 0x84, 0x0f, 0x8d, 0xe5, 0x41, 0x53, 0xee, 0x3f, 0xe3, 0xaf, 0x11, 0x1a, 0x1a, 0x5a, 0x11, 0xda, 0x14, 0x1c, 0x13, 0xdc, 0xe6, 0x4f, 0xf7, 0x67, 0x53, 0xaf, 0x34, 0x3d, 0x1b, 0xf9, 0x73, 0xcf, 0x2e, 0xaf, 0x92, 0xab, 0xe0, 0x9c, 0x47, 0x9a, 0x53,\n\t0x8b, 0x34, 0xf5, 0xb7, 0x49, 0x78, 0xe6, 0x74, 0x0d, 0x14, 0xf9, 0xbb, 0x83, 0x7a, 0x26, 0xa8, 0xbf, 0xf0, 0xd4, 0x81, 0x9f, 0x4e, 0x82, 0x22, 0x12, 0x8d, 0xf6, 0xe1, 0x67, 0xbc, 0xab, 0xdf, 0xec, 0x1f, 0x15, 0xde, 0x7c, 0x96, 0x77, 0xf8, 0x20, 0xff, 0x04, 0xff, 0xd8, 0xd3, 0xe9, 0x4a, 0x47, 0x96, 0x82, 0x0b, 0xcf, 0x9f, 0x24, 0x0a, 0x6d, 0xa2, 0x39, 0x65, 0x26, 0xcd, 0xb4, 0x9b, 0xce, 0x45, 0xfe, 0x99, 0xb4, 0xcd, 0xa9, 0x42, 0xf3, 0x93, 0x78, 0x75, 0x68, 0xbe, 0x7f, 0x3e, 0x69, 0x03, 0xfc, 0x8c, 0xfc, 0xeb, 0xfd, 0x6b, 0x68, 0xb3, 0x68, 0x93, 0x7f, 0x53, 0x60, 0x9f, 0xe0, 0xa0, 0x72, 0xaf, 0x23, 0xa2, 0x8a, 0xab, 0xef, 0x4d, 0xaa, 0xc9, 0x01, 0xbc, 0xb9, 0x4f, 0x22, 0xe1, 0x99, 0xe4, 0x2f, 0xab, 0x2a, 0x0d, 0x6d, 0xaf, 0x2a, 0x39, 0x3b, 0xf9, 0x8f, 0x0a, 0x4f,\n\t0x92, 0x00, 0x0b, 0x30, 0xff, 0x09, 0xe1, 0xd7, 0x14, 0x70, 0x24, 0x79, 0x59, 0x24, 0x28, 0x10, 0x49, 0x90, 0xaf, 0x22, 0x15, 0x09, 0xd4, 0x23, 0x4a, 0x25, 0xaa, 0x17, 0xc8, 0x44, 0xba, 0x1e, 0x7c, 0x9f, 0xaa, 0x4f, 0x42, 0x1f, 0x5a, 0x26, 0x51, 0x3b, 0x8b, 0x2a, 0xae, 0xd9, 0x39, 0x50, 0x54, 0xa9, 0x0e, 0x45, 0xa7, 0x29, 0xf1, 0xbb, 0x17, 0xa8, 0xd8, 0xda, 0x07, 0xf3, 0xcb, 0x29, 0x30, 0x22, 0xb1, 0xef, 0x6b, 0xa5, 0x02, 0x03, 0x4e, 0x1f, 0xab, 0x4c, 0xc2, 0x1b, 0xeb, 0xf4, 0x59, 0x96, 0x57, 0x16, 0x8d, 0x1e, 0x22, 0x78, 0x66, 0x59, 0x34, 0x2b, 0xd8, 0x4d, 0xf8, 0x68, 0x59, 0x72, 0xa2, 0xc2, 0xe0, 0x91, 0x88, 0x56, 0xe1, 0x2f, 0x71, 0x30, 0xb0, 0x0a, 0x7c, 0xc1, 0xe9, 0x74, 0xd2, 0xb1, 0xc5, 0x81, 0x65, 0x96, 0x3c, 0xb0, 0x2a, 0xb8, 0x2d, 0x21, 0x13, 0xfe, 0x5d,\n\t0x9b, 0x93, 0x88, 0x9e, 0x06, 0xc2, 0xcf, 0x2b, 0xb8, 0xcd, 0xa2, 0xc0, 0x3e, 0xe2, 0x5a, 0xe0, 0xa0, 0x58, 0x4f, 0x04, 0x5d, 0x81, 0xc3, 0xd6, 0x1e, 0xe9, 0x63, 0x49, 0xe9, 0x93, 0x89, 0x94, 0x84, 0x95, 0x47, 0xa0, 0x82, 0x62, 0xc1, 0x34, 0x5a, 0x79, 0x64, 0x85, 0x86, 0x0b, 0x0e, 0xca, 0xa1, 0xbb, 0x13, 0x9e, 0x5f, 0xf0, 0xfd, 0x4a, 0x5c, 0x65, 0x4b, 0x82, 0x0b, 0xea, 0x16, 0xec, 0x11, 0x3e, 0x5c, 0x4e, 0xc1, 0x7e, 0xe0, 0xbd, 0xc5, 0x26, 0xd2, 0xc1, 0x81, 0x55, 0x8f, 0x25, 0x93, 0x38, 0x1a, 0x1c, 0x98, 0x9c, 0x07, 0xd2, 0x61, 0x68, 0xa7, 0x61, 0xa0, 0x49, 0x44, 0x63, 0x82, 0x23, 0xc1, 0xc7, 0xc0, 0xab, 0x6c, 0x52, 0x70, 0x36, 0x68, 0x06, 0xad, 0x85, 0x04, 0xb7, 0x7e, 0xad, 0x0b, 0xce, 0x0b, 0x2e, 0x0c, 0x2e, 0x09, 0x2e, 0x0f, 0xae, 0x06, 0xad, 0x2b, 0x6f, 0x8f,\n\t0x44, 0x5d, 0x37, 0x26, 0xf6, 0xa7, 0xa5, 0x5b, 0x2c, 0x09, 0xad, 0x9e, 0xb6, 0x59, 0x9e, 0x61, 0x21, 0x43, 0xf8, 0x83, 0x25, 0x68, 0x3f, 0x6d, 0x47, 0x82, 0xc7, 0x89, 0x4e, 0x85, 0xdb, 0x59, 0x14, 0x52, 0x68, 0x33, 0x90, 0x4a, 0xe6, 0xdd, 0x13, 0x44, 0x0f, 0x37, 0x78, 0x7d, 0xa5, 0x87, 0xb2, 0x85, 0xcf, 0x32, 0x3c, 0xae, 0x2a, 0x53, 0x9b, 0x0a, 0xbf, 0xab, 0xaa, 0xd4, 0xb1, 0x92, 0x57, 0x56, 0x65, 0xea, 0x7e, 0x06, 0xf5, 0x0f, 0xf5, 0xa4, 0xed, 0x6c, 0xd4, 0xe7, 0x1c, 0xf2, 0xe1, 0x44, 0xf0, 0xe5, 0x0a, 0x8d, 0x25, 0x1a, 0x7e, 0xd6, 0xfd, 0x28, 0xda, 0x26, 0x84, 0x26, 0x13, 0xcd, 0xfc, 0x4d, 0xb2, 0x3c, 0xb7, 0xe6, 0x0b, 0x7f, 0xac, 0xb3, 0xd2, 0xa2, 0x73, 0xc8, 0x57, 0x84, 0xd6, 0x08, 0x7f, 0xac, 0x70, 0xbd, 0x8a, 0xf9, 0x28, 0xd9, 0x2b, 0x4b, 0xf8, 0x64, 0x95,\n\t0x85, 0x8e, 0x86, 0x4e, 0xc0, 0xc7, 0x4a, 0x78, 0x59, 0xf9, 0x12, 0xbe, 0x54, 0x96, 0xdf, 0x94, 0xf0, 0x96, 0x6a, 0x59, 0xee, 0x1d, 0x25, 0xfc, 0xa2, 0x2a, 0x68, 0x40, 0x05, 0x0d, 0x4e, 0x90, 0xf0, 0x85, 0xb2, 0xc8, 0xf2, 0x7f, 0xa2, 0xd5, 0x73, 0xc2, 0xcf, 0x69, 0x31, 0xbc, 0x99, 0x2c, 0x5f, 0x26, 0xe1, 0xcd, 0x24, 0x3c, 0x99, 0xf6, 0x25, 0x79, 0x2e, 0x69, 0x11, 0xd7, 0x59, 0xe3, 0x0b, 0x6b, 0xfe, 0xbe, 0x28, 0x43, 0xfe, 0xb3, 0xed, 0xb3, 0xdf, 0x8a, 0x35, 0x64, 0x3f, 0xc1, 0x0a, 0xf9, 0x01, 0x16, 0x09, 0x22, 0xba, 0xe4, 0x3b, 0x45, 0x5a, 0x52, 0xc5, 0xb9, 0xbc, 0xaf, 0x48, 0xcb, 0xdf, 0x09, 0x6e, 0x1f, 0x00, 0x79, 0x1e, 0x72, 0xfe, 0x6a, 0x54, 0x22, 0x3f, 0x89, 0x9c, 0x67, 0xc4, 0x26, 0x4a, 0xb7, 0x42, 0x5e, 0x0a, 0x5e, 0x13, 0xe5, 0x6c, 0x46, 0xf9, 0x12, 0xf8,\n\t0x1f, 0x88, 0x59, 0x4c, 0xc4, 0xb8, 0xbc, 0x84, 0x32, 0x7f, 0x41, 0xf9, 0x61, 0x94, 0x79, 0x01, 0x78, 0x26, 0x24, 0xef, 0x81, 0xff, 0x0b, 0xfc, 0x10, 0xe4, 0xc9, 0x71, 0x8d, 0xb5, 0x94, 0xd1, 0x02, 0x77, 0x87, 0xbc, 0x37, 0xf2, 0xfc, 0x7b, 0x91, 0x8e, 0x9d, 0xce, 0x1e, 0xef, 0xc8, 0x0f, 0xa0, 0xcc, 0x33, 0xa3, 0x1e, 0xaf, 0x3a, 0x1d, 0x3b, 0x78, 0xae, 0x08, 0x48, 0x2b, 0x9a, 0xd0, 0x8a, 0x80, 0x94, 0x32, 0x70, 0x8f, 0x49, 0x71, 0x90, 0xfc, 0x1a, 0x48, 0xa6, 0xa3, 0x1f, 0x93, 0x62, 0x22, 0xe5, 0x07, 0x21, 0x07, 0x9e, 0x26, 0xf5, 0xc3, 0x51, 0x2b, 0x56, 0xcf, 0x3a, 0x6b, 0x17, 0xe4, 0x75, 0xc1, 0x2f, 0xc7, 0x51, 0xd4, 0x50, 0x9e, 0x89, 0xbe, 0xf6, 0x28, 0x33, 0x84, 0x0f, 0x0e, 0x8e, 0xa2, 0x77, 0xf8, 0x22, 0xf0, 0x87, 0x21, 0xb9, 0x1a, 0xdc, 0x09, 0x49, 0x52, 0xb4,\n\t0x25, 0xb3, 0xe2, 0x1d, 0x7b, 0xe1, 0x68, 0x07, 0x94, 0xd6, 0x18, 0x69, 0xe0, 0x7b, 0x56, 0x14, 0x26, 0x7f, 0x16, 0xe9, 0xad, 0xe0, 0x36, 0x5c, 0x37, 0x39, 0x22, 0xf3, 0x05, 0xc8, 0xaf, 0xc3, 0x59, 0x7f, 0x01, 0xef, 0x81, 0x72, 0x22, 0x90, 0x7f, 0x0a, 0x0e, 0xac, 0x92, 0x4f, 0x01, 0x4f, 0x8a, 0xe0, 0x94, 0x2e, 0x42, 0xfe, 0x6c, 0xc8, 0x11, 0x7b, 0xc4, 0x51, 0x7f, 0xf6, 0x25, 0x4a, 0x40, 0x64, 0xa7, 0x64, 0x59, 0xde, 0x68, 0xe1, 0x38, 0xb4, 0x3a, 0x39, 0xbe, 0x93, 0xe1, 0xee, 0x64, 0x4b, 0x07, 0x2c, 0x3d, 0xff, 0x1a, 0x25, 0x80, 0xf3, 0x69, 0xe0, 0x18, 0x2f, 0x3c, 0xf7, 0x34, 0x26, 0xc9, 0xbf, 0x40, 0x7a, 0x0b, 0xce, 0x1a, 0x0d, 0xc9, 0x1e, 0xf0, 0x1d, 0x28, 0xff, 0x46, 0xc8, 0x3d, 0x48, 0x97, 0x80, 0x73, 0x70, 0x6b, 0xc4, 0x41, 0x27, 0xf9, 0x2b, 0xd6, 0xbd, 0x40,\n\t0xce, 0xc0, 0x2d, 0x0d, 0x1c, 0x05, 0x5e, 0x1f, 0x47, 0x9f, 0x04, 0x7f, 0x02, 0x92, 0x74, 0xf0, 0x34, 0xf0, 0x4b, 0xc0, 0x2d, 0xed, 0xda, 0x86, 0x6b, 0xb5, 0x45, 0x1a, 0x6d, 0x25, 0xa5, 0x5a, 0xf7, 0x88, 0x73, 0x3f, 0x46, 0xda, 0x1a, 0xc5, 0x56, 0x04, 0xd8, 0x47, 0xc8, 0x8f, 0x9e, 0x92, 0xac, 0x9e, 0x6a, 0x8f, 0x9c, 0xef, 0x80, 0x7f, 0x06, 0x0e, 0x2d, 0x3a, 0x33, 0x32, 0x55, 0xb6, 0xfa, 0xa8, 0x25, 0x38, 0x22, 0xf9, 0xf8, 0x1c, 0xa4, 0xa1, 0x3f, 0xd2, 0xf9, 0xe0, 0xe8, 0x5f, 0xe9, 0x6e, 0xf0, 0x8e, 0x28, 0xed, 0x77, 0x46, 0xaf, 0x26, 0x22, 0x44, 0xab, 0x1f, 0xc3, 0xda, 0xaa, 0x6a, 0x24, 0x2b, 0x07, 0x56, 0x2c, 0xa7, 0xa0, 0x0e, 0x6e, 0xf0, 0xdb, 0xc0, 0x2d, 0xdd, 0xb6, 0x74, 0x20, 0x07, 0x5c, 0x01, 0xd7, 0x50, 0xcf, 0x6d, 0x96, 0xc6, 0xe2, 0x5c, 0xb4, 0xbf, 0x54,\n\t0x03, 0x12, 0xe4, 0xe7, 0x71, 0x48, 0x22, 0xd6, 0x0c, 0x83, 0xab, 0x3c, 0x07, 0x89, 0x0b, 0x47, 0xa1, 0xed, 0xd2, 0x3a, 0x70, 0xc4, 0x65, 0xca, 0xd6, 0x78, 0xb9, 0x0c, 0x47, 0x37, 0x82, 0x57, 0x3f, 0x46, 0x16, 0xf8, 0xbc, 0x04, 0xac, 0x5e, 0xb2, 0x46, 0xdf, 0x04, 0x5c, 0x17, 0xa3, 0x83, 0xbf, 0x2b, 0xb8, 0xd2, 0x02, 0xf2, 0xe6, 0x48, 0x27, 0xc5, 0xce, 0x4a, 0x97, 0x42, 0x8e, 0x16, 0x28, 0x8f, 0xa3, 0x45, 0xda, 0x8a, 0xa6, 0x8d, 0xa1, 0x1c, 0x44, 0xd3, 0xf2, 0xe5, 0xd6, 0x98, 0xb2, 0xcd, 0x12, 0xfe, 0x7a, 0x89, 0x19, 0xa0, 0x6f, 0x79, 0x7c, 0xad, 0x85, 0xc0, 0x57, 0x8a, 0xac, 0x6d, 0x66, 0xb5, 0x80, 0xf5, 0xf4, 0xc1, 0xd1, 0xaf, 0xac, 0xd1, 0x77, 0x46, 0xac, 0xad, 0x35, 0xfa, 0x96, 0x22, 0x4f, 0x19, 0xf8, 0x5b, 0xe0, 0xaf, 0x22, 0x7f, 0x2d, 0x8c, 0xaf, 0xbf, 0x81,\n\t0x5b, 0x63, 0x01, 0x7a, 0xc8, 0x7d, 0xe0, 0x05, 0xe0, 0xd6, 0x8c, 0xf7, 0xff, 0xc7, 0xec, 0xfe, 0x91, 0x98, 0x5d, 0x3c, 0xef, 0xac, 0xc8, 0x5d, 0xa9, 0x33, 0x5a, 0x1e, 0x23, 0x82, 0x7f, 0x8f, 0xde, 0xc9, 0xb2, 0x22, 0x7a, 0x91, 0xb6, 0x9e, 0xcb, 0x49, 0x71, 0xbd, 0x52, 0x03, 0x6b, 0x36, 0x40, 0xba, 0x11, 0xce, 0xb5, 0x9e, 0xa7, 0xe8, 0x1d, 0xc9, 0x8b, 0xa3, 0x67, 0x44, 0xfd, 0x4a, 0x06, 0x8e, 0x42, 0xdf, 0xa4, 0x6b, 0xad, 0x39, 0xb3, 0x6a, 0x1c, 0x30, 0xc3, 0xd5, 0x19, 0x46, 0xe2, 0xaf, 0xc7, 0x04, 0x4b, 0xd6, 0xbb, 0x9e, 0x33, 0x23, 0x83, 0xaf, 0x40, 0x9d, 0xad, 0xf8, 0x60, 0xe8, 0xbf, 0x8c, 0xe7, 0xbe, 0xe4, 0xb0, 0x46, 0x2e, 0xce, 0xb5, 0x46, 0x07, 0x56, 0x02, 0x56, 0xf4, 0x70, 0x22, 0x0a, 0xd6, 0x8f, 0xeb, 0xce, 0x07, 0x1f, 0x02, 0x3e, 0xde, 0x4a, 0xa3, 0x7c,\n\t0x8c, 0x5f, 0x6e, 0xe9, 0x6d, 0xa5, 0x38, 0x63, 0x48, 0xfa, 0x80, 0xdf, 0x68, 0xe9, 0x24, 0xd2, 0x8f, 0xa3, 0x7c, 0x2b, 0xca, 0xb6, 0x21, 0xd2, 0x49, 0xb1, 0xc8, 0x92, 0x8a, 0xfa, 0x04, 0x2d, 0x8e, 0xb3, 0x7e, 0xc4, 0x59, 0xc7, 0xad, 0xd9, 0xcc, 0x9a, 0x2b, 0xc0, 0xed, 0x90, 0x6f, 0x00, 0xff, 0x06, 0x92, 0xdf, 0x11, 0xbb, 0x8c, 0xfc, 0xc9, 0x11, 0xcc, 0x18, 0x47, 0x52, 0x17, 0x8b, 0xa3, 0x3d, 0xf1, 0xb4, 0xe2, 0xd6, 0x55, 0x12, 0x91, 0xcd, 0x48, 0x5b, 0xf1, 0xcd, 0xd7, 0x58, 0x3d, 0x6b, 0x45, 0x39, 0x23, 0x5d, 0xcf, 0xfa, 0x5e, 0x05, 0x6a, 0x9e, 0x88, 0x78, 0x46, 0xfa, 0x3f, 0x14, 0xf7, 0x2c, 0x75, 0xc5, 0xd5, 0x93, 0xa3, 0x9f, 0x77, 0x43, 0xb2, 0x13, 0xdc, 0x8a, 0x84, 0xc6, 0x9b, 0x41, 0xc9, 0x7a, 0xae, 0x25, 0x47, 0x45, 0x5b, 0xcf, 0x5f, 0xeb, 0x89, 0xf9, 0x7b,\n\t0x23, 0xa4, 0x6f, 0xc0, 0x59, 0xf7, 0x58, 0xd1, 0xd2, 0x28, 0x47, 0xae, 0x1a, 0x03, 0x2d, 0x61, 0xf5, 0xcb, 0xd7, 0x83, 0xaf, 0x01, 0xff, 0xd5, 0xa8, 0x68, 0xfe, 0x06, 0xca, 0x3c, 0x57, 0x54, 0x74, 0x96, 0x35, 0x5e, 0xaa, 0xc6, 0x46, 0xcb, 0x18, 0x29, 0x67, 0x44, 0x48, 0x8b, 0xef, 0x6f, 0x33, 0x66, 0xf0, 0xe1, 0xb6, 0x7c, 0xa6, 0x74, 0xe8, 0xd8, 0xb5, 0x98, 0xc5, 0xae, 0xbb, 0xb3, 0x64, 0x30, 0xeb, 0x7a, 0x43, 0xc9, 0xf5, 0x37, 0xb1, 0xf9, 0x83, 0xff, 0x32, 0x6c, 0x08, 0x2b, 0x15, 0x1f, 0xdb, 0x65, 0x2c, 0x1e, 0xc7, 0xff, 0xf7, 0x53, 0x99, 0x8b, 0xf9, 0x58, 0x94, 0xa5, 0xb1, 0x4c, 0x56, 0x9f, 0xe5, 0xb3, 0x0b, 0x58, 0x2b, 0xd6, 0x81, 0x5d, 0xcc, 0xba, 0xb3, 0xab, 0x58, 0x5f, 0x76, 0x03, 0x1b, 0xc2, 0x6e, 0x67, 0xa3, 0xc4, 0xb7, 0x52, 0x2f, 0xef, 0xde, 0x2e, 0x4d,\n\t0xbc, 0x5d, 0xa4, 0xf3, 0xbc, 0x74, 0x15, 0x8d, 0xf9, 0x59, 0x8c, 0xd5, 0x66, 0x39, 0xac, 0x31, 0x2b, 0x64, 0x17, 0xb2, 0xae, 0xec, 0x72, 0xd6, 0x8b, 0xfd, 0x85, 0x0d, 0x64, 0xb7, 0xb0, 0xe1, 0xec, 0xee, 0x44, 0x3e, 0x89, 0xe9, 0x74, 0x95, 0x14, 0x96, 0xc5, 0x1a, 0xb0, 0x02, 0xd6, 0x9a, 0x75, 0x64, 0x97, 0xb0, 0x62, 0x76, 0x35, 0xeb, 0xc7, 0x6e, 0x64, 0x43, 0xd9, 0x1d, 0x6c, 0x74, 0x45, 0x5d, 0xbc, 0x4c, 0xa6, 0xab, 0x04, 0x59, 0x0d, 0x56, 0x87, 0xe5, 0xb2, 0x26, 0xac, 0x0d, 0xeb, 0xc4, 0x8a, 0xd8, 0x15, 0xac, 0x37, 0xbb, 0x8e, 0x0d, 0x62, 0xb7, 0xb2, 0x11, 0xec, 0x1e, 0xe6, 0x61, 0x52, 0xf7, 0x4b, 0x2f, 0x49, 0x63, 0x85, 0xc5, 0xdd, 0x2f, 0x4e, 0x63, 0x83, 0x13, 0xf7, 0xa0, 0xe0, 0xad, 0x7c, 0x88, 0xd5, 0x64, 0xe7, 0xb1, 0x6c, 0xd6, 0x90, 0x35, 0x65, 0xcd, 0x59,\n\t0x5b, 0xd6, 0x99, 0x5d, 0xca, 0x7a, 0xe0, 0x2d, 0xe7, 0x4d, 0xac, 0x84, 0xdd, 0xc9, 0xc6, 0x24, 0x72, 0xdb, 0x98, 0x83, 0xca, 0x09, 0xb3, 0x54, 0x96, 0xce, 0xea, 0xb2, 0x3c, 0x76, 0x3e, 0x6b, 0xc1, 0xda, 0xb1, 0x8b, 0x58, 0x37, 0x76, 0x25, 0xeb, 0xc3, 0xae, 0xa7, 0x52, 0x6f, 0x63, 0x23, 0xd9, 0xbd, 0x89, 0xdc, 0x76, 0xe6, 0xa4, 0x9a, 0x45, 0x58, 0x2d, 0x96, 0xc1, 0xea, 0xb1, 0x46, 0xac, 0x19, 0x6b, 0xc9, 0xda, 0xb3, 0x2e, 0xec, 0x32, 0xd6, 0x93, 0x5d, 0xcb, 0x06, 0xb0, 0x9b, 0xd9, 0x30, 0x76, 0x17, 0x1b, 0xcb, 0xee, 0xbb, 0xee, 0x2f, 0x83, 0x87, 0xc9, 0x81, 0xea, 0xf1, 0xdb, 0xae, 0x97, 0x6b, 0x54, 0x87, 0xf7, 0x1f, 0x7c, 0xe3, 0x0d, 0x72, 0xfa, 0x59, 0xf8, 0x90, 0x5b, 0x6e, 0x96, 0xb3, 0xab, 0xc3, 0x07, 0x94, 0xfc, 0xe5, 0x3a, 0x39, 0xb7, 0x3a, 0x9c, 0x0a, 0xfe,\n\t0x8b, 0xdc, 0xf5, 0x0c, 0x5e, 0x3c, 0x78, 0xc8, 0xed, 0x37, 0xcb, 0xbd, 0xaa, 0xc3, 0x89, 0x95, 0xc8, 0x7d, 0xab, 0xc3, 0x6f, 0x11, 0xf9, 0x07, 0x54, 0x8b, 0x97, 0xf4, 0x1f, 0x22, 0x0f, 0x3e, 0x93, 0x0f, 0x15, 0x47, 0x4b, 0xaa, 0xc3, 0x6f, 0x13, 0x6d, 0x3e, 0x21, 0x89, 0x8f, 0x38, 0x43, 0x32, 0x26, 0x91, 0xbe, 0x71, 0xc8, 0x00, 0x79, 0x61, 0xb5, 0xf8, 0x6d, 0x79, 0x8d, 0xe4, 0xc9, 0xd5, 0xe4, 0xf9, 0xf2, 0xb4, 0x6a, 0xf2, 0xc6, 0xf2, 0xac, 0x6a, 0xf2, 0x02, 0x79, 0x5e, 0xb5, 0xf8, 0xed, 0xfd, 0x6e, 0xa3, 0xda, 0x56, 0x8b, 0x0f, 0xbd, 0x4d, 0x5e, 0x52, 0x1d, 0x3e, 0x4c, 0xb4, 0xea, 0xf2, 0xea, 0x70, 0x1a, 0xd6, 0x12, 0xcd, 0x10, 0x35, 0x30, 0x27, 0x49, 0xe0, 0x69, 0xe0, 0x01, 0xfc, 0xff, 0x16, 0x85, 0x46, 0xa2, 0x1d, 0xff, 0x8f, 0x4e, 0xa7, 0x71, 0x6f, 0xd2, 0xa8,\n\t0x74, 0xd2, 0x4c, 0xe4, 0xa1, 0xd1, 0x26, 0xce, 0x13, 0xff, 0x7d, 0x4e, 0xe4, 0xb5, 0x78, 0x08, 0xdc, 0x0f, 0x1e, 0x04, 0xaf, 0x09, 0x1e, 0x46, 0x5e, 0x4e, 0xe3, 0x9e, 0xe1, 0x0a, 0xe7, 0x41, 0x6a, 0xf1, 0x74, 0xc8, 0x32, 0x68, 0x56, 0x13, 0xfb, 0xda, 0x34, 0x03, 0x09, 0x69, 0x1d, 0x70, 0x1f, 0x78, 0x14, 0x3c, 0x42, 0xb3, 0x40, 0x31, 0xcd, 0x12, 0xc3, 0xd8, 0x38, 0x36, 0x8d, 0x6d, 0x66, 0xbb, 0xd8, 0x21, 0x76, 0x92, 0x3b, 0x78, 0x0d, 0x9e, 0xc3, 0x5b, 0xf2, 0xae, 0xbc, 0x37, 0x1f, 0xcc, 0x47, 0xf1, 0x49, 0x7c, 0x16, 0x5f, 0xc4, 0x57, 0xf3, 0xcd, 0x7c, 0x17, 0x3f, 0xc4, 0x4f, 0x4a, 0x0e, 0xa9, 0x86, 0xd4, 0x54, 0xea, 0x28, 0x0d, 0x93, 0xc6, 0x49, 0xd3, 0xa4, 0x79, 0xd2, 0x32, 0x69, 0xbd, 0xb4, 0x4d, 0xda, 0x27, 0x1d, 0x95, 0x15, 0x39, 0x20, 0x67, 0xd2, 0x7d, 0x31,\n\t0xcc, 0x91, 0x5c, 0xcc, 0xc7, 0x4a, 0x9f, 0x2a, 0xbf, 0x07, 0x56, 0xf9, 0xdd, 0xbf, 0xf2, 0x6f, 0x5b, 0x53, 0xfc, 0xb6, 0x51, 0x6b, 0x44, 0xa8, 0xcd, 0xb2, 0x69, 0x96, 0xe2, 0xd4, 0x56, 0xcc, 0x36, 0x2f, 0xb1, 0x3f, 0x6c, 0xed, 0xed, 0x2d, 0x13, 0xfb, 0xf1, 0x89, 0xfd, 0xd6, 0xa4, 0x72, 0xe8, 0xb7, 0x1a, 0xab, 0xf2, 0xbb, 0x4f, 0x95, 0xdf, 0x8b, 0x2b, 0xff, 0xd6, 0x58, 0x95, 0xdf, 0xc5, 0x55, 0x7e, 0x2f, 0xac, 0xfc, 0x5b, 0x97, 0xaa, 0xfc, 0xee, 0x5d, 0xe5, 0xf7, 0x8a, 0xca, 0xbf, 0x8d, 0x50, 0xe5, 0xfb, 0x34, 0x86, 0x57, 0x39, 0xbe, 0xaf, 0xf2, 0x6f, 0x33, 0xbf, 0x72, 0x7e, 0x73, 0x6c, 0x95, 0xdf, 0x87, 0x2a, 0xff, 0x76, 0xf4, 0xa8, 0xf2, 0x7b, 0x6d, 0xe5, 0xdf, 0xce, 0xde, 0x55, 0x7e, 0x6f, 0xa8, 0xfc, 0xdb, 0xd5, 0xaf, 0xca, 0xef, 0xcd, 0xf8, 0x2d, 0x91, 0x7e,\n\t0xfa, 0xac, 0x1a, 0x79, 0x3a, 0x27, 0xf6, 0xd3, 0x2b, 0xe7, 0xf4, 0x1c, 0xc5, 0x6f, 0x85, 0x34, 0x38, 0x84, 0xff, 0x8e, 0x88, 0x5c, 0xbe, 0x4c, 0x6b, 0xef, 0xef, 0x67, 0xed, 0x03, 0x73, 0xac, 0x7d, 0x70, 0x7f, 0xe5, 0xb3, 0xc3, 0xc9, 0xfa, 0x42, 0xcf, 0xc3, 0xf0, 0xf8, 0x2a, 0xbf, 0x67, 0x54, 0xfe, 0x9d, 0x52, 0x58, 0xf9, 0xfc, 0x94, 0x31, 0x55, 0x7e, 0xef, 0xae, 0xf2, 0x7b, 0x67, 0x95, 0xdf, 0xc7, 0xaa, 0xfc, 0x3e, 0x52, 0xe5, 0xf7, 0xd1, 0x2a, 0xbf, 0x0f, 0x63, 0x55, 0x21, 0x7e, 0x4b, 0x6c, 0x23, 0x3d, 0xe3, 0xfb, 0xf3, 0xef, 0xd9, 0x0d, 0xb6, 0x14, 0xbd, 0xae, 0xdd, 0x67, 0x7c, 0x6e, 0xcf, 0xb6, 0xd7, 0xb3, 0xe7, 0xd8, 0x73, 0xed, 0x79, 0xf6, 0x7c, 0x7b, 0x81, 0xbd, 0xa9, 0xbd, 0x99, 0xbd, 0xb9, 0xbd, 0xa5, 0xbd, 0xad, 0x7d, 0xbf, 0xfd, 0x80, 0xfd, 0x47, 0xfb,\n\t0x31, 0xfb, 0x0f, 0xf6, 0xa3, 0xf6, 0xef, 0xed, 0x47, 0xce, 0xf0, 0x8f, 0xb2, 0xd9, 0xbf, 0xb2, 0x7f, 0x6d, 0xff, 0x46, 0x0d, 0xa9, 0x86, 0xea, 0x52, 0x3d, 0xf0, 0x96, 0x72, 0xa8, 0x5e, 0xd5, 0xa7, 0xfa, 0xd5, 0x80, 0x1a, 0x54, 0xdf, 0xd7, 0xc6, 0xea, 0xf5, 0xf5, 0x3a, 0x7a, 0xbe, 0xc9, 0x4c, 0xd9, 0xb4, 0x9b, 0xba, 0x69, 0x9a, 0x2e, 0xd3, 0xaf, 0x2a, 0x66, 0xd8, 0xac, 0x61, 0xff, 0xd9, 0xcc, 0x35, 0x1b, 0x99, 0x05, 0xe6, 0x05, 0x66, 0x4b, 0xb3, 0xb5, 0xd9, 0xd1, 0xbc, 0xd8, 0xbc, 0xd4, 0xec, 0x6e, 0xf6, 0x30, 0xaf, 0x36, 0xfb, 0x98, 0x7f, 0x31, 0xfb, 0x9b, 0x37, 0x98, 0x83, 0xcc, 0x9b, 0xcd, 0xa1, 0xe6, 0x6d, 0xe6, 0x70, 0x73, 0xa4, 0x79, 0xb7, 0x39, 0xc6, 0xbc, 0xcf, 0x1c, 0x6f, 0x3e, 0x64, 0xbe, 0x6e, 0xae, 0x37, 0xdf, 0xa2, 0x7b, 0xf9, 0x0b, 0xad, 0x41, 0xae,\n\t0x63, 0x03, 0x6c, 0x31, 0x5b, 0x4d, 0xbb, 0xd7, 0x9e, 0x72, 0x0e, 0x1f, 0xb0, 0x36, 0xf6, 0x76, 0xf6, 0x0b, 0x7f, 0xd5, 0x0b, 0xec, 0x2a, 0xfb, 0x97, 0xf0, 0x04, 0x3b, 0xae, 0xea, 0xf0, 0xf1, 0x12, 0x1e, 0x5e, 0x51, 0x35, 0xa6, 0xa6, 0xa8, 0x35, 0xd4, 0x9a, 0x6a, 0xaa, 0xfa, 0x9e, 0x36, 0x46, 0x8f, 0xea, 0x31, 0xbd, 0xa1, 0x11, 0x87, 0x87, 0x97, 0xe5, 0xdf, 0x65, 0x79, 0x77, 0xa5, 0x98, 0x75, 0xcc, 0x06, 0xf0, 0xee, 0x3a, 0xed, 0xd9, 0x55, 0x64, 0x5e, 0x66, 0x5e, 0x61, 0xf6, 0x32, 0xaf, 0x31, 0xfb, 0x9a, 0xd7, 0x99, 0x03, 0xcc, 0x1b, 0xcd, 0xc1, 0xe6, 0x2d, 0x66, 0x89, 0x79, 0xbb, 0x79, 0xa7, 0x39, 0xca, 0xbc, 0x07, 0x9e, 0x5f, 0x13, 0x2b, 0x3c, 0xbe, 0x5c, 0x4c, 0xd1, 0x2e, 0xd2, 0x27, 0x6b, 0x97, 0xe9, 0x8f, 0x41, 0x37, 0x32, 0xd8, 0x1d, 0x5a, 0xb1, 0x3e, 0x03,\n\t0x7a, 0x26, 0xfa, 0x8e, 0x73, 0x37, 0xe5, 0x2a, 0xa1, 0x35, 0xd1, 0x23, 0xec, 0x79, 0xf6, 0x02, 0x7b, 0x91, 0xbd, 0xc4, 0x96, 0xb1, 0xe5, 0x6c, 0x05, 0x5b, 0xc5, 0x56, 0xb3, 0xb5, 0x6c, 0x5d, 0xf9, 0xff, 0x7d, 0x55, 0xee, 0x53, 0xc6, 0x29, 0xf7, 0x2b, 0x0f, 0x29, 0x13, 0x95, 0x29, 0xca, 0x5f, 0x95, 0xa9, 0xca, 0xdf, 0x94, 0x69, 0xca, 0xa3, 0xca, 0xc3, 0xca, 0x63, 0xfc, 0x01, 0x3e, 0x81, 0x3f, 0xc8, 0x27, 0xf2, 0x87, 0xf8, 0x24, 0xe5, 0x71, 0xfe, 0xb0, 0x32, 0x93, 0x4f, 0xe6, 0x8f, 0xf0, 0x29, 0xfc, 0xaf, 0x7c, 0x2a, 0xff, 0x1b, 0x9f, 0xa6, 0xdc, 0xce, 0x1f, 0x55, 0x86, 0xf3, 0xe9, 0xca, 0x64, 0xe5, 0x11, 0xdb, 0x61, 0x63, 0xb7, 0xb1, 0x9f, 0xae, 0xdb, 0x94, 0x3d, 0xcc, 0x16, 0xb2, 0x45, 0x6c, 0x31, 0x5b, 0xc2, 0xfe, 0xc1, 0xfe, 0xc9, 0x5e, 0x66, 0x2b, 0xd9, 0x2b,\n\t0xec, 0x35, 0xf6, 0x3a, 0x6f, 0xc7, 0xdb, 0xf3, 0x0e, 0xfc, 0x42, 0xde, 0x85, 0x5f, 0x4c, 0xb3, 0x6b, 0x11, 0xbf, 0x94, 0x77, 0xe3, 0x97, 0xf1, 0xee, 0xfc, 0x72, 0x5e, 0xcc, 0xaf, 0xa0, 0xd9, 0xb6, 0x2f, 0xbf, 0x8d, 0x0f, 0xe3, 0xb7, 0xf3, 0xe1, 0xfc, 0x0e, 0x3e, 0x82, 0xdf, 0xc9, 0x47, 0xf2, 0xbb, 0x68, 0xfe, 0xbd, 0x9b, 0x8f, 0xe6, 0xf7, 0xf0, 0x31, 0xfc, 0x5e, 0x3e, 0x96, 0xdf, 0xc7, 0xc7, 0xf1, 0xfb, 0xc9, 0xea, 0x1a, 0xa1, 0xdc, 0x63, 0x6b, 0x6c, 0x7c, 0x6a, 0x7c, 0x41, 0x77, 0xd8, 0x81, 0xd5, 0x52, 0x4e, 0x29, 0x27, 0x95, 0x5f, 0xf8, 0x12, 0x9b, 0xcf, 0xe6, 0xb7, 0xe9, 0x36, 0xaf, 0xcd, 0xb0, 0x99, 0x36, 0x87, 0xcd, 0xa9, 0x1c, 0x57, 0xe2, 0x36, 0x66, 0xe3, 0x36, 0xc9, 0x26, 0xdb, 0x14, 0x9b, 0xdd, 0xa6, 0xf1, 0x25, 0xca, 0x4f, 0xca, 0x09, 0xe5, 0x67, 0x9b,\n\t0xcb, 0xe6, 0xb6, 0x79, 0x6c, 0x36, 0x9b, 0xca, 0x97, 0xe0, 0x59, 0x73, 0x33, 0x3f, 0x9f, 0x37, 0xe7, 0x1d, 0x51, 0xa3, 0x1b, 0xf8, 0x40, 0x3e, 0x88, 0xdf, 0x44, 0xb3, 0xff, 0x10, 0x5e, 0x92, 0x7c, 0xbf, 0xfc, 0x51, 0x3e, 0x9d, 0x2f, 0xe1, 0xff, 0xe0, 0xcb, 0xf8, 0xcb, 0x8a, 0x5f, 0x09, 0x28, 0x21, 0xe5, 0x76, 0x65, 0xb8, 0x32, 0x9d, 0xd6, 0xaf, 0x62, 0x8c, 0x14, 0xd1, 0xde, 0x47, 0x54, 0x84, 0x5f, 0x35, 0x12, 0x65, 0xfe, 0x76, 0x89, 0x55, 0xca, 0x43, 0xdf, 0x75, 0xa4, 0xb2, 0xca, 0x4b, 0xe3, 0x28, 0xf1, 0x3f, 0x53, 0xa6, 0x28, 0xa5, 0x2b, 0xb5, 0x9a, 0x87, 0xf8, 0x7f, 0xa6, 0x44, 0xab, 0x2c, 0x8e, 0xf2, 0xfe, 0x33, 0x25, 0x72, 0x9a, 0x47, 0xc5, 0x5a, 0xc1, 0xda, 0x33, 0x48, 0x64, 0xea, 0x9b, 0x25, 0xd4, 0xd2, 0x7f, 0xa4, 0x7c, 0x39, 0xb1, 0x02, 0xe0, 0x68, 0x53,\n\t0xab, 0xdc, 0x3f, 0x56, 0xdb, 0x25, 0x89, 0x32, 0x03, 0xd4, 0x0a, 0xdd, 0xc8, 0x06, 0xfa, 0xe3, 0xa5, 0xd2, 0x9a, 0x46, 0x39, 0x6e, 0xb3, 0xd6, 0x3b, 0xa7, 0xcb, 0x0f, 0xd1, 0xbe, 0x3b, 0x51, 0xef, 0x3f, 0xed, 0x0a, 0x11, 0x9a, 0x41, 0x8a, 0x41, 0x7d, 0xfe, 0xb4, 0x6b, 0xc4, 0x68, 0x5d, 0xd3, 0x23, 0x41, 0x7d, 0xff, 0xb4, 0xab, 0xd4, 0xa0, 0xf9, 0xaf, 0x67, 0x05, 0xf5, 0xfb, 0xd3, 0xae, 0x93, 0x4a, 0x4f, 0xca, 0x5e, 0x49, 0xd4, 0xff, 0x4f, 0xbb, 0x52, 0x1a, 0x3d, 0x7d, 0x7b, 0x57, 0xa2, 0x01, 0x7f, 0xda, 0xb5, 0xd2, 0x69, 0x4d, 0xde, 0xa7, 0x0a, 0x0d, 0xfc, 0xd3, 0xae, 0x96, 0x49, 0xeb, 0xab, 0xbe, 0x67, 0xd0, 0xa0, 0x3f, 0xe1, 0x7a, 0x12, 0x6b, 0xc3, 0x6a, 0xda, 0x82, 0xca, 0x5b, 0xca, 0x9b, 0xca, 0x06, 0xe5, 0x7d, 0xa5, 0x54, 0xd9, 0xa8, 0x6c, 0x55, 0xde, 0x56,\n\t0x36, 0x29, 0xef, 0x28, 0x9b, 0x95, 0xd7, 0xf9, 0x7c, 0xfe, 0x1c, 0x5f, 0xc0, 0xff, 0xce, 0x17, 0xf2, 0xe7, 0xf9, 0x0b, 0xfc, 0x45, 0x65, 0x9d, 0xf2, 0x86, 0xb2, 0x5e, 0x79, 0x57, 0xd9, 0xa2, 0xbc, 0x47, 0xab, 0xff, 0xc5, 0xb0, 0x3b, 0xa4, 0x3f, 0x30, 0xf3, 0x58, 0xf3, 0x4e, 0x7a, 0x02, 0xa5, 0x11, 0x4f, 0x66, 0x89, 0xae, 0xb9, 0x84, 0x16, 0x8e, 0xaf, 0x2b, 0xa5, 0x64, 0x03, 0xfd, 0xb1, 0x79, 0xcd, 0x9a, 0x2d, 0xbb, 0xd1, 0xd6, 0x23, 0x51, 0xfe, 0x1f, 0x9c, 0xd9, 0x44, 0xfd, 0x2a, 0x5a, 0x50, 0x62, 0x85, 0xac, 0x86, 0x52, 0xa6, 0x1c, 0x52, 0xbe, 0xe1, 0xf3, 0xf8, 0xb3, 0xca, 0xb7, 0xca, 0x8f, 0xca, 0x61, 0xe5, 0x3b, 0xe5, 0x88, 0xf2, 0xbd, 0xf2, 0x35, 0x7f, 0x8c, 0xcf, 0xe0, 0x8f, 0xf3, 0x99, 0xfc, 0x09, 0xb2, 0x93, 0x66, 0xf3, 0x39, 0xfc, 0x69, 0x3e, 0x97, 0x3f,\n\t0xa3, 0x1c, 0x55, 0x7e, 0x50, 0x8e, 0xf1, 0x27, 0xf9, 0x53, 0x7f, 0xb0, 0x17, 0xc5, 0x95, 0xf1, 0x74, 0xff, 0xed, 0x67, 0x7b, 0xd5, 0x27, 0xfb, 0x7f, 0xe0, 0xca, 0xff, 0xbe, 0xb6, 0xfc, 0x91, 0x2b, 0x0f, 0x66, 0x8d, 0xf9, 0x8d, 0xca, 0xb3, 0xca, 0x7c, 0xe5, 0x39, 0x7e, 0x8b, 0x32, 0xaf, 0xd2, 0xaa, 0x68, 0x64, 0x95, 0x15, 0xd1, 0x38, 0x5a, 0x0d, 0x2d, 0x53, 0x5e, 0x55, 0x5e, 0x53, 0xd6, 0x2a, 0xff, 0x54, 0x5e, 0x56, 0x96, 0x2b, 0x2b, 0x94, 0x57, 0x94, 0xd5, 0xca, 0x4a, 0x65, 0x95, 0xb2, 0x46, 0x59, 0xa0, 0xfc, 0x5d, 0x59, 0x48, 0xab, 0xa6, 0xfb, 0x69, 0x35, 0x75, 0x97, 0xf2, 0xbc, 0xb2, 0x48, 0x79, 0x41, 0x59, 0xac, 0xbc, 0x48, 0x57, 0x7b, 0x49, 0x59, 0xaa, 0xfc, 0x43, 0xd8, 0x37, 0x54, 0xb7, 0x81, 0xa4, 0x94, 0x83, 0xf8, 0x60, 0x81, 0x64, 0xf3, 0x21, 0x4c, 0xa1,\n\t0x3a, 0x96, 0x50, 0xc3, 0x3e, 0xc0, 0xa7, 0x33, 0x3b, 0xd5, 0xee, 0x35, 0x16, 0x12, 0xb5, 0x63, 0x19, 0xe2, 0xf3, 0x41, 0xac, 0x36, 0xea, 0x98, 0xa5, 0x3c, 0xae, 0x3c, 0x43, 0xd6, 0xa9, 0x44, 0xcf, 0xa4, 0x2c, 0xe5, 0x19, 0x3e, 0x50, 0x99, 0xa5, 0x3c, 0xa9, 0xcc, 0x56, 0x9e, 0xe2, 0x43, 0x94, 0x27, 0xaa, 0xbd, 0x6a, 0x9c, 0xa3, 0x3c, 0xad, 0xcc, 0xa5, 0xab, 0xa1, 0x6d, 0xac, 0x16, 0xa0, 0x12, 0xed, 0x54, 0xa3, 0xc1, 0x54, 0xa3, 0x21, 0xfc, 0x16, 0xaa, 0x45, 0x09, 0x27, 0x8b, 0x08, 0xd7, 0xaf, 0x81, 0xeb, 0xa7, 0x2a, 0xf3, 0x94, 0x85, 0xb4, 0x5e, 0x43, 0x2b, 0x29, 0xcf, 0x28, 0xff, 0x28, 0xbf, 0x32, 0xdd, 0xd5, 0x13, 0x67, 0x5d, 0x3f, 0x26, 0xd5, 0x86, 0x3f, 0x4c, 0x35, 0x11, 0xed, 0xfd, 0x4f, 0xbe, 0x9c, 0xbf, 0xcc, 0x57, 0xf0, 0x95, 0x7c, 0x15, 0x7f, 0x85, 0x6c,\n\t0xfb, 0x57, 0xf9, 0x1a, 0xfe, 0x9a, 0x55, 0x1f, 0xba, 0xb3, 0x99, 0x15, 0x2d, 0x85, 0x76, 0x4a, 0xb4, 0x52, 0x72, 0x9d, 0x4a, 0xc8, 0x90, 0xb9, 0x9b, 0x6a, 0xa6, 0xd1, 0x7d, 0x4d, 0x67, 0x3e, 0xb4, 0x52, 0x0c, 0xb5, 0xac, 0x83, 0x5a, 0xd6, 0x45, 0x2b, 0xd5, 0x43, 0x5d, 0x73, 0xac, 0x56, 0x3a, 0xdb, 0x3a, 0xb6, 0xaa, 0x2e, 0x50, 0x7f, 0xd1, 0x79, 0xe5, 0x2d, 0x42, 0x6d, 0x89, 0x36, 0xa1, 0xd6, 0x9d, 0x57, 0xa1, 0x0d, 0xa2, 0x3f, 0x6f, 0x44, 0x2b, 0xdd, 0xc6, 0x47, 0x51, 0x8d, 0x1e, 0xe0, 0x93, 0x99, 0x41, 0xf9, 0xfc, 0xcc, 0x87, 0x3e, 0xf1, 0x53, 0xdd, 0x5f, 0xa4, 0x56, 0x7a, 0x89, 0x7a, 0x37, 0xc3, 0xb2, 0xd9, 0xcc, 0x19, 0xe6, 0xe3, 0xfc, 0xa8, 0x39, 0xd3, 0x7c, 0x82, 0xff, 0x60, 0xce, 0x32, 0x9f, 0x34, 0x67, 0x9b, 0x4f, 0x99, 0x73, 0xcc, 0xa7, 0xcd, 0xb9, 0xe6,\n\t0x33, 0xb6, 0xa8, 0x39, 0x8f, 0x1f, 0x33, 0x9f, 0xe5, 0x3f, 0x9a, 0xf3, 0xcd, 0xe7, 0xf8, 0x71, 0x73, 0x01, 0xff, 0x89, 0x9f, 0xe0, 0x3f, 0xb3, 0x29, 0xec, 0xaf, 0x6c, 0x2a, 0xfb, 0x1b, 0x9b, 0xc6, 0x1e, 0x65, 0xd3, 0xd9, 0x63, 0x6c, 0x06, 0x7b, 0x9c, 0xcd, 0x64, 0xb3, 0xd8, 0x93, 0x6c, 0x36, 0x7b, 0x8a, 0xcd, 0x61, 0x4f, 0xb3, 0xb9, 0xec, 0x19, 0x36, 0x8f, 0x3d, 0xcb, 0xe6, 0xb3, 0xe7, 0xd8, 0x02, 0xf6, 0x77, 0xe5, 0x2b, 0xe5, 0xa0, 0xf2, 0xb1, 0x72, 0x97, 0x72, 0xa7, 0x32, 0x52, 0xd9, 0xa9, 0x7c, 0xa2, 0xec, 0x52, 0x3e, 0x55, 0x76, 0x2b, 0x9f, 0xfd, 0xa6, 0xec, 0xd3, 0xb3, 0xfc, 0xde, 0xa6, 0x7c, 0xa8, 0x6c, 0x67, 0x4f, 0x50, 0xfe, 0xdd, 0x62, 0x83, 0xcd, 0x26, 0x03, 0x33, 0xd2, 0x69, 0xae, 0x14, 0x68, 0x91, 0x88, 0xc5, 0xf2, 0xd3, 0xac, 0x17, 0xa4, 0x95, 0x4b,\n\t0x94, 0xa5, 0xd0, 0xd3, 0x38, 0x8d, 0x9d, 0x47, 0xf3, 0x6b, 0x26, 0x59, 0xe0, 0xd9, 0xac, 0x2e, 0xab, 0xc7, 0xea, 0x53, 0xcb, 0x37, 0x60, 0x79, 0xac, 0x11, 0x70, 0xde, 0x56, 0xec, 0x1a, 0x76, 0x2d, 0xad, 0x06, 0x06, 0xd0, 0xd3, 0x6c, 0x30, 0xbb, 0x99, 0xdd, 0x42, 0x96, 0xd1, 0x30, 0x76, 0x3b, 0x1b, 0xce, 0x46, 0xb1, 0xf1, 0x6c, 0x02, 0x7b, 0x90, 0x4d, 0x64, 0x0f, 0xb1, 0x49, 0x18, 0xaf, 0xd5, 0xb4, 0x42, 0xce, 0xd0, 0xac, 0xb3, 0x8f, 0xec, 0x61, 0xb0, 0x11, 0x48, 0xab, 0x2a, 0x9e, 0x02, 0xdd, 0x12, 0x4f, 0x81, 0x6c, 0xf1, 0x54, 0x51, 0x9b, 0xa8, 0x17, 0xab, 0x5d, 0xd5, 0x4b, 0xd4, 0x4b, 0xd5, 0x6e, 0xea, 0x65, 0x6a, 0x77, 0xf5, 0x72, 0xf5, 0x7e, 0xf5, 0x09, 0x75, 0x96, 0x3a, 0x5b, 0x7d, 0x4a, 0x9d, 0xa3, 0x3e, 0xad, 0x85, 0xb4, 0x1c, 0xad, 0x81, 0xd6, 0x50, 0xcb,\n\t0x13, 0xff, 0x3f, 0x4e, 0xbb, 0xf7, 0xf4, 0xff, 0xc0, 0x14, 0xf3, 0xb4, 0xfa, 0x5e, 0x45, 0xa9, 0x03, 0x93, 0x4a, 0xad, 0xfb, 0x5b, 0xa5, 0xaa, 0x2f, 0xa8, 0xff, 0x54, 0x97, 0xab, 0x2f, 0xab, 0x2b, 0xd5, 0x55, 0xea, 0x2b, 0xea, 0x6a, 0xf5, 0xd5, 0xca, 0xd7, 0x31, 0x62, 0x46, 0x4d, 0x23, 0xd5, 0xa8, 0x65, 0x9c, 0x67, 0xa4, 0x1b, 0x19, 0x46, 0xa6, 0x51, 0x5b, 0x5c, 0x4d, 0x1b, 0x43, 0x1a, 0xb5, 0x95, 0x5d, 0xaf, 0x16, 0x9c, 0x93, 0x7a, 0x54, 0xa1, 0x71, 0x67, 0xd0, 0xa2, 0xb3, 0xd2, 0x9a, 0x2a, 0xf4, 0xde, 0xb9, 0x48, 0x0b, 0x9e, 0x41, 0x4d, 0xc4, 0x7f, 0xd0, 0xab, 0x4c, 0x54, 0xcb, 0xb3, 0x90, 0x91, 0x55, 0x99, 0xe4, 0x27, 0xe9, 0x7e, 0xfc, 0xd4, 0x56, 0x4d, 0x18, 0x53, 0xbb, 0xa8, 0x57, 0x50, 0x7b, 0x5e, 0xa9, 0xf6, 0x61, 0x4e, 0x6a, 0xab, 0xfb, 0x59, 0x50, 0x9d,\n\t0xa9, 0x3e, 0xcd, 0x42, 0xd4, 0x52, 0x2f, 0xb0, 0x54, 0x75, 0x99, 0xfa, 0x2a, 0xab, 0xa5, 0xbe, 0xa6, 0x6e, 0xa0, 0xb6, 0xdd, 0xaa, 0x6e, 0x65, 0x8d, 0xd4, 0x4f, 0xd4, 0xfd, 0x2c, 0x9f, 0x5a, 0x2d, 0xc4, 0x0a, 0xb5, 0xfa, 0x5a, 0x3e, 0x6b, 0x8d, 0xff, 0xce, 0xd9, 0x89, 0x7a, 0xe8, 0x5e, 0xd6, 0x19, 0xff, 0x8b, 0xf3, 0x22, 0x6a, 0xc5, 0x18, 0xbb, 0xcc, 0xa8, 0x41, 0xad, 0xd7, 0xdd, 0xa8, 0x63, 0xe4, 0xb2, 0xde, 0xe6, 0x62, 0x73, 0x31, 0xad, 0x14, 0x4f, 0x5b, 0x22, 0x13, 0xd0, 0x67, 0x29, 0xff, 0xa3, 0x7a, 0x48, 0x34, 0x93, 0x8a, 0xff, 0xed, 0xc6, 0xe4, 0x27, 0xe5, 0x67, 0x98, 0x21, 0xbe, 0x0b, 0xcb, 0xbc, 0xe2, 0xbf, 0x7e, 0x31, 0x1f, 0xf5, 0x65, 0x13, 0x16, 0xa0, 0xda, 0xf4, 0xa1, 0x6b, 0x5f, 0xaf, 0x5e, 0xcf, 0xea, 0xe3, 0xbf, 0x1b, 0xe6, 0x50, 0x0f, 0xde, 0xcf,\n\t0x1a, 0xa0, 0x4e, 0x0d, 0xa9, 0xdf, 0x5e, 0x60, 0xe7, 0x53, 0x9d, 0x36, 0xb0, 0x0b, 0xa8, 0x6f, 0xde, 0x67, 0x5d, 0x51, 0x9b, 0x4b, 0xd5, 0x32, 0xb5, 0x8c, 0x5d, 0xad, 0x9e, 0x54, 0x4f, 0xb2, 0xde, 0x9a, 0x4d, 0xb3, 0xb1, 0x6b, 0xf0, 0x3f, 0x11, 0xfb, 0xa0, 0x7e, 0x7d, 0xf1, 0x1f, 0x4d, 0x07, 0xa2, 0x96, 0x37, 0x6a, 0x2d, 0xb5, 0x96, 0x6c, 0x90, 0xd6, 0x5d, 0xeb, 0xce, 0x6e, 0xd2, 0x46, 0x68, 0x23, 0xd8, 0x60, 0xfc, 0x2f, 0xd3, 0x9b, 0x51, 0xef, 0xa1, 0xda, 0x34, 0x6d, 0x1a, 0x1b, 0x81, 0xda, 0xdf, 0x49, 0xb5, 0xcf, 0x65, 0x23, 0xf1, 0x5f, 0x03, 0x1f, 0x16, 0x71, 0x4e, 0x6c, 0x72, 0x85, 0xe6, 0x6f, 0x4d, 0x68, 0x7e, 0xca, 0xff, 0xf1, 0xfb, 0xf9, 0x5f, 0xea, 0xa2, 0xb0, 0x60, 0x27, 0xd2, 0xac, 0xff, 0xbf, 0xd4, 0xc6, 0xf2, 0x75, 0xe7, 0xff, 0x6d, 0x9d, 0x94, 0xa8,\n\t0x2d, 0x63, 0x22, 0xae, 0xbd, 0x42, 0x2b, 0xff, 0xbf, 0x70, 0x5f, 0xff, 0xab, 0xf9, 0xa9, 0x39, 0xb5, 0xe5, 0xef, 0x5e, 0x8b, 0xb0, 0x27, 0x80, 0x36, 0xfc, 0xee, 0xa7, 0xbf, 0x32, 0x0c, 0x2b, 0x77, 0x0b, 0xed, 0xb6, 0xd3, 0x2a, 0xa3, 0x2b, 0xf5, 0x67, 0x2b, 0x3a, 0xaf, 0x3d, 0xfd, 0xee, 0x87, 0x7e, 0x6c, 0xc5, 0xb8, 0xbc, 0x58, 0xac, 0x08, 0xa5, 0x96, 0xac, 0x35, 0x1b, 0x43, 0xe7, 0x4e, 0xa1, 0xfa, 0xcc, 0xa1, 0xab, 0x2e, 0x61, 0x2b, 0xd8, 0x5a, 0x5a, 0x6f, 0x6d, 0xa5, 0x9e, 0xdf, 0xc3, 0x0e, 0xb0, 0xc3, 0xec, 0xb8, 0x78, 0x64, 0x72, 0x0f, 0x8f, 0xf0, 0x34, 0x9e, 0xcd, 0xf3, 0xb8, 0xf8, 0xff, 0xbf, 0x9d, 0x69, 0x85, 0xd1, 0x93, 0xf7, 0xe5, 0x03, 0x68, 0x7d, 0x57, 0x42, 0xeb, 0x8b, 0xd1, 0xb4, 0x96, 0x98, 0x48, 0xeb, 0x86, 0xe9, 0x64, 0x3d, 0xcd, 0x25, 0x9b, 0x62,\n\t0x31, 0xad, 0x19, 0x56, 0xf1, 0xb5, 0x7c, 0x03, 0xdf, 0xcc, 0x4b, 0xf9, 0x0e, 0xbe, 0x9b, 0xef, 0xe3, 0x07, 0xf9, 0x61, 0x7e, 0x8c, 0x9f, 0x94, 0x24, 0x49, 0x93, 0x5c, 0x52, 0x40, 0x8a, 0x49, 0x69, 0x52, 0x96, 0x94, 0x43, 0xd7, 0x97, 0x11, 0xed, 0xdb, 0x0e, 0xfb, 0x6b, 0xd9, 0xe5, 0xd8, 0x5f, 0xc7, 0x8a, 0xb1, 0xef, 0x4f, 0xb6, 0xa0, 0xd8, 0x0f, 0xb0, 0xad, 0xc5, 0xfe, 0x06, 0xd6, 0x13, 0xfb, 0x81, 0xac, 0x37, 0xf6, 0xa3, 0xa4, 0x67, 0xc5, 0x9e, 0x7f, 0x8f, 0xd8, 0xe1, 0x56, 0xca, 0x30, 0xed, 0xb8, 0xd8, 0xdb, 0x6a, 0x6a, 0xc7, 0xc4, 0x5e, 0x8f, 0x6a, 0x3f, 0x62, 0x1f, 0x63, 0x97, 0x60, 0x5f, 0x43, 0xfb, 0x09, 0xfb, 0x9a, 0xc0, 0x39, 0x5b, 0xe9, 0xa9, 0xec, 0x52, 0xec, 0x6b, 0xd1, 0x7a, 0x46, 0xec, 0xd3, 0xf0, 0xad, 0xf5, 0x56, 0xfa, 0x79, 0xb4, 0xda, 0x15, 0xfb,\n\t0x74, 0xed, 0x04, 0xf6, 0xb5, 0xa5, 0xf9, 0xd8, 0x67, 0x69, 0x27, 0xb1, 0xaf, 0x23, 0xfd, 0x1d, 0xfb, 0x6c, 0xed, 0x17, 0xec, 0xeb, 0x6a, 0x3f, 0x63, 0x5f, 0x5f, 0x5a, 0x80, 0x7d, 0x8e, 0xf4, 0x1c, 0xf6, 0x0d, 0xc8, 0x02, 0x93, 0x10, 0xcb, 0x2c, 0x51, 0x6d, 0xdb, 0x12, 0xbf, 0x96, 0x75, 0x21, 0x7e, 0x1d, 0xbb, 0x98, 0x78, 0x7f, 0x76, 0x05, 0xf1, 0x01, 0xb6, 0xd7, 0x88, 0xdf, 0xc0, 0xae, 0x24, 0x3e, 0xd0, 0xb6, 0x85, 0xf8, 0x4d, 0xec, 0x6a, 0xe2, 0xa3, 0x6c, 0xef, 0x13, 0xbf, 0x5b, 0x9a, 0x43, 0x56, 0xf6, 0xf7, 0xec, 0x2a, 0x26, 0xd1, 0xdd, 0x1d, 0x66, 0x12, 0xdd, 0x5b, 0x19, 0x93, 0xe8, 0xce, 0xbe, 0x25, 0x1e, 0x63, 0x1d, 0x88, 0xd7, 0xd0, 0xbe, 0x23, 0x5e, 0x93, 0x5d, 0x48, 0x3c, 0x95, 0x75, 0x24, 0x5e, 0x8b, 0x75, 0x22, 0x9e, 0xc6, 0x3a, 0xff, 0x3f, 0x75, 0x9d,\n\t0x3d, 0x4c, 0x14, 0x51, 0x14, 0x85, 0xef, 0x9b, 0xdd, 0xc1, 0x39, 0x79, 0xa8, 0x89, 0x31, 0x11, 0x08, 0x2c, 0x2c, 0x11, 0x58, 0x14, 0x0a, 0x44, 0x29, 0x80, 0xca, 0xc2, 0xc4, 0x86, 0x8a, 0xca, 0xc0, 0x16, 0x20, 0x9d, 0x35, 0xb1, 0x20, 0x01, 0xfc, 0xab, 0xec, 0x6d, 0x04, 0x45, 0x05, 0xe5, 0x47, 0xf9, 0xdb, 0x05, 0x15, 0xec, 0x28, 0x21, 0x10, 0x7e, 0x0a, 0x0d, 0x09, 0x8d, 0x89, 0x0d, 0x95, 0x60, 0x43, 0x01, 0x9e, 0x7b, 0x91, 0x4d, 0x24, 0xda, 0x9c, 0xef, 0x65, 0x36, 0xf3, 0xde, 0xcd, 0x3d, 0x67, 0xde, 0x26, 0xf3, 0x8a, 0xa1, 0x26, 0xe5, 0x36, 0xb5, 0x3c, 0xfa, 0x49, 0xad, 0x08, 0x86, 0xa8, 0x95, 0xd1, 0x3e, 0xb5, 0x2a, 0x78, 0x43, 0x4d, 0x45, 0xbf, 0xa8, 0xd5, 0xd1, 0x1e, 0xf5, 0x6a, 0xf0, 0x9a, 0x5a, 0x13, 0xbc, 0xa2, 0xd6, 0x86, 0x2b, 0xd4, 0xba, 0xe8, 0x90, 0xda,\n\t0x18, 0xae, 0x52, 0x9b, 0xc2, 0x35, 0xea, 0x33, 0x3b, 0x6f, 0x6c, 0x63, 0xed, 0xf7, 0x98, 0xbe, 0x1e, 0x79, 0x24, 0x4f, 0x99, 0xe9, 0xe7, 0x4c, 0xee, 0x84, 0x64, 0x64, 0x51, 0x96, 0x64, 0x59, 0x36, 0x65, 0x5b, 0xbe, 0xcb, 0xae, 0xec, 0xcb, 0x01, 0xd3, 0x93, 0xe7, 0xf2, 0xdd, 0x05, 0xe6, 0x27, 0xe1, 0x2e, 0xbb, 0x2b, 0x4c, 0x50, 0x83, 0x6b, 0x76, 0x37, 0x99, 0xa1, 0x16, 0xd7, 0xea, 0xee, 0x1c, 0xa7, 0x48, 0x1e, 0xb2, 0x5b, 0x3d, 0xec, 0xd7, 0x07, 0x63, 0x07, 0x67, 0x55, 0x76, 0xca, 0x63, 0xe3, 0xdd, 0x60, 0x5c, 0xe9, 0xf6, 0xf0, 0x59, 0x19, 0x96, 0x60, 0x5e, 0x89, 0x22, 0x4c, 0x1a, 0x8b, 0x31, 0x65, 0x2c, 0xc1, 0xb4, 0x31, 0x81, 0x8c, 0xb1, 0x14, 0x33, 0xc6, 0x32, 0xcc, 0x1a, 0x93, 0xc8, 0x1a, 0xcb, 0x31, 0x67, 0xac, 0xc4, 0x47, 0x63, 0x15, 0x3e, 0x19, 0x53, 0x58,\n\t0x30, 0x56, 0x63, 0xd1, 0x58, 0x83, 0x2f, 0xc6, 0x5a, 0xe9, 0x55, 0xff, 0x30, 0x68, 0x4f, 0x50, 0x9f, 0xf9, 0xd7, 0x6f, 0xfe, 0x3d, 0x50, 0x9f, 0x82, 0x31, 0x75, 0x08, 0x63, 0xea, 0x0d, 0xde, 0xaa, 0x2b, 0x78, 0xa1, 0xae, 0xe0, 0xa5, 0xba, 0x02, 0xed, 0x78, 0x02, 0xda, 0xeb, 0x52, 0x68, 0x67, 0xcb, 0xa0, 0x5d, 0x4e, 0x62, 0x58, 0x5d, 0xc1, 0x88, 0xfa, 0x81, 0x77, 0xea, 0x07, 0x46, 0xd5, 0x0f, 0x8c, 0xab, 0x1f, 0x98, 0x50, 0x27, 0xf0, 0x5e, 0x9d, 0xb0, 0x9d, 0x97, 0x59, 0x27, 0x6f, 0xd9, 0x19, 0x5d, 0x4a, 0xae, 0x49, 0x33, 0x2b, 0x8b, 0x38, 0xbe, 0x28, 0xf5, 0x96, 0xaa, 0xeb, 0x9a, 0x1e, 0xb9, 0xa1, 0xf5, 0xd8, 0x49, 0x4a, 0x43, 0x6e, 0xd4, 0xa5, 0x19, 0xb3, 0xd1, 0xfd, 0xdc, 0xb5, 0x3a, 0xce, 0xd0, 0x21, 0xdd, 0xf6, 0xad, 0xf8, 0x42, 0x49, 0xcb, 0x86, 0x7c, 0xd3,\n\t0xe7, 0x3d, 0x9e, 0x8e, 0x0d, 0xe8, 0x5e, 0xe9, 0xe7, 0xfd, 0x94, 0x9f, 0xf6, 0x33, 0x7e, 0xd6, 0x67, 0x7c, 0xd6, 0xcf, 0xe1, 0x0c, 0x80, 0x08, 0x79, 0x38, 0x8b, 0x73, 0x38, 0xcf, 0x19, 0xf5, 0xf4, 0xb9, 0x5d, 0xd6, 0xe5, 0xab, 0xec, 0xc8, 0x8f, 0xe0, 0xc9, 0x7f, 0xbe, 0x6d, 0x7f, 0x04, 0x81, 0x43, 0x80, 0x18, 0xe2, 0x08, 0x71, 0x49, 0x4f, 0x75, 0xdc, 0x86, 0xed, 0x40, 0x45, 0x5c, 0xb9, 0x58, 0xfc, 0xbf, 0x57, 0xd3, 0xff, 0x19, 0xdb, 0xd5, 0xc5, 0x76, 0xd6, 0x98, 0xdd, 0xb7, 0xf9, 0xe7, 0xbe, 0x93, 0x93, 0xa1, 0xf8, 0xc9, 0xea, 0xf6, 0xeb, 0x56, 0x6e, 0xd6, 0x02, 0x7d, 0xf7, 0x17, 0x4f, 0x9f, 0xaa, 0xd8, 0xf1, 0x6a, 0x3b, 0xeb, 0xfc, 0xab, 0xa2, 0xdf, 0x7f, 0x02, 0x0c, 0xed\n};\n\n#include <zlib.h>\n\nuint8* extractCafeDefaultFont(sint32* size)\n{\n\tuint8* uncompressed = (uint8*)malloc(1024 * 1024 * 1);\n\tuLongf uncompressedSize = 1024 * 1024 * 1;\n\tuncompress(uncompressed, &uncompressedSize, cafeDefaultFontZLIB, sizeof(cafeDefaultFontZLIB));\n\t*size = uncompressedSize;\n\treturn uncompressed;\n}"
  },
  {
    "path": "src/resource/IconsFontAwesome5.h",
    "content": "// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for language C++11\n// from https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/metadata/icons.yml\n// for use with https://github.com/FortAwesome/Font-Awesome/blob/master/webfonts/fa-solid-900.ttf, https://github.com/FortAwesome/Font-Awesome/blob/master/webfonts/fa-regular-400.ttf, \n#pragma once\n\n#define FONT_ICON_FILE_NAME_FAR \"fa-regular-400.ttf\"\n#define FONT_ICON_FILE_NAME_FAS \"fa-solid-900.ttf\"\n\n#define ICON_MIN_FA 0xf000\n#define ICON_MAX_FA 0xf82f\n#define ICON_FA_NOTES_MEDICAL u8\"\\uf481\"\n#define ICON_FA_CLOUD_SHOWERS_HEAVY u8\"\\uf740\"\n#define ICON_FA_SMS u8\"\\uf7cd\"\n#define ICON_FA_COPY u8\"\\uf0c5\"\n#define ICON_FA_CHEVRON_CIRCLE_RIGHT u8\"\\uf138\"\n#define ICON_FA_CROSSHAIRS u8\"\\uf05b\"\n#define ICON_FA_BROADCAST_TOWER u8\"\\uf519\"\n#define ICON_FA_EXTERNAL_LINK_SQUARE_ALT u8\"\\uf360\"\n#define ICON_FA_SMOKING u8\"\\uf48d\"\n#define ICON_FA_KISS_BEAM u8\"\\uf597\"\n#define ICON_FA_CHESS_BISHOP u8\"\\uf43a\"\n#define ICON_FA_TV u8\"\\uf26c\"\n#define ICON_FA_CROP_ALT u8\"\\uf565\"\n#define ICON_FA_TH u8\"\\uf00a\"\n#define ICON_FA_RECYCLE u8\"\\uf1b8\"\n#define ICON_FA_SMILE u8\"\\uf118\"\n#define ICON_FA_FAX u8\"\\uf1ac\"\n#define ICON_FA_DRAFTING_COMPASS u8\"\\uf568\"\n#define ICON_FA_USER_INJURED u8\"\\uf728\"\n#define ICON_FA_SCREWDRIVER u8\"\\uf54a\"\n#define ICON_FA_DHARMACHAKRA u8\"\\uf655\"\n#define ICON_FA_PRINT u8\"\\uf02f\"\n#define ICON_FA_BABY_CARRIAGE u8\"\\uf77d\"\n#define ICON_FA_CARET_UP u8\"\\uf0d8\"\n#define ICON_FA_SCHOOL u8\"\\uf549\"\n#define ICON_FA_SORT_NUMERIC_UP u8\"\\uf163\"\n#define ICON_FA_TRUCK_LOADING u8\"\\uf4de\"\n#define ICON_FA_LIST u8\"\\uf03a\"\n#define ICON_FA_UPLOAD u8\"\\uf093\"\n#define ICON_FA_LAPTOP_MEDICAL u8\"\\uf812\"\n#define ICON_FA_EXPAND_ARROWS_ALT u8\"\\uf31e\"\n#define ICON_FA_ADJUST u8\"\\uf042\"\n#define ICON_FA_VENUS u8\"\\uf221\"\n#define ICON_FA_HEADING u8\"\\uf1dc\"\n#define ICON_FA_ARROW_DOWN u8\"\\uf063\"\n#define ICON_FA_BICYCLE u8\"\\uf206\"\n#define ICON_FA_TIRED u8\"\\uf5c8\"\n#define ICON_FA_AIR_FRESHENER u8\"\\uf5d0\"\n#define ICON_FA_BACON u8\"\\uf7e5\"\n#define ICON_FA_SYNC u8\"\\uf021\"\n#define ICON_FA_PAPER_PLANE u8\"\\uf1d8\"\n#define ICON_FA_VOLLEYBALL_BALL u8\"\\uf45f\"\n#define ICON_FA_RIBBON u8\"\\uf4d6\"\n#define ICON_FA_HAND_LIZARD u8\"\\uf258\"\n#define ICON_FA_CLOCK u8\"\\uf017\"\n#define ICON_FA_SUN u8\"\\uf185\"\n#define ICON_FA_FILE_POWERPOINT u8\"\\uf1c4\"\n#define ICON_FA_MICROCHIP u8\"\\uf2db\"\n#define ICON_FA_TRASH_RESTORE_ALT u8\"\\uf82a\"\n#define ICON_FA_GRADUATION_CAP u8\"\\uf19d\"\n#define ICON_FA_ANGLE_DOUBLE_DOWN u8\"\\uf103\"\n#define ICON_FA_INFO_CIRCLE u8\"\\uf05a\"\n#define ICON_FA_TAGS u8\"\\uf02c\"\n#define ICON_FA_FILE_ALT u8\"\\uf15c\"\n#define ICON_FA_EQUALS u8\"\\uf52c\"\n#define ICON_FA_DIRECTIONS u8\"\\uf5eb\"\n#define ICON_FA_FILE_INVOICE u8\"\\uf570\"\n#define ICON_FA_SEARCH u8\"\\uf002\"\n#define ICON_FA_BIBLE u8\"\\uf647\"\n#define ICON_FA_FLASK u8\"\\uf0c3\"\n#define ICON_FA_CALENDAR_TIMES u8\"\\uf273\"\n#define ICON_FA_GREATER_THAN_EQUAL u8\"\\uf532\"\n#define ICON_FA_SLIDERS_H u8\"\\uf1de\"\n#define ICON_FA_EYE_SLASH u8\"\\uf070\"\n#define ICON_FA_BIRTHDAY_CAKE u8\"\\uf1fd\"\n#define ICON_FA_FEATHER_ALT u8\"\\uf56b\"\n#define ICON_FA_DNA u8\"\\uf471\"\n#define ICON_FA_BASEBALL_BALL u8\"\\uf433\"\n#define ICON_FA_HOSPITAL u8\"\\uf0f8\"\n#define ICON_FA_COINS u8\"\\uf51e\"\n#define ICON_FA_HRYVNIA u8\"\\uf6f2\"\n#define ICON_FA_TEMPERATURE_HIGH u8\"\\uf769\"\n#define ICON_FA_FONT_AWESOME_LOGO_FULL u8\"\\uf4e6\"\n#define ICON_FA_PASSPORT u8\"\\uf5ab\"\n#define ICON_FA_TAG u8\"\\uf02b\"\n#define ICON_FA_SHOPPING_CART u8\"\\uf07a\"\n#define ICON_FA_AWARD u8\"\\uf559\"\n#define ICON_FA_WINDOW_RESTORE u8\"\\uf2d2\"\n#define ICON_FA_PHONE u8\"\\uf095\"\n#define ICON_FA_FLAG u8\"\\uf024\"\n#define ICON_FA_STETHOSCOPE u8\"\\uf0f1\"\n#define ICON_FA_DICE_D6 u8\"\\uf6d1\"\n#define ICON_FA_OUTDENT u8\"\\uf03b\"\n#define ICON_FA_LONG_ARROW_ALT_RIGHT u8\"\\uf30b\"\n#define ICON_FA_PIZZA_SLICE u8\"\\uf818\"\n#define ICON_FA_ADDRESS_CARD u8\"\\uf2bb\"\n#define ICON_FA_PARAGRAPH u8\"\\uf1dd\"\n#define ICON_FA_MALE u8\"\\uf183\"\n#define ICON_FA_HISTORY u8\"\\uf1da\"\n#define ICON_FA_HAMBURGER u8\"\\uf805\"\n#define ICON_FA_SEARCH_PLUS u8\"\\uf00e\"\n#define ICON_FA_FIRE_ALT u8\"\\uf7e4\"\n#define ICON_FA_LIFE_RING u8\"\\uf1cd\"\n#define ICON_FA_SHARE u8\"\\uf064\"\n#define ICON_FA_ALIGN_JUSTIFY u8\"\\uf039\"\n#define ICON_FA_TOILET_PAPER u8\"\\uf71e\"\n#define ICON_FA_BATTERY_THREE_QUARTERS u8\"\\uf241\"\n#define ICON_FA_OBJECT_UNGROUP u8\"\\uf248\"\n#define ICON_FA_BRIEFCASE u8\"\\uf0b1\"\n#define ICON_FA_OIL_CAN u8\"\\uf613\"\n#define ICON_FA_THERMOMETER_FULL u8\"\\uf2c7\"\n#define ICON_FA_PLANE u8\"\\uf072\"\n#define ICON_FA_HEARTBEAT u8\"\\uf21e\"\n#define ICON_FA_UNLINK u8\"\\uf127\"\n#define ICON_FA_WINDOW_MAXIMIZE u8\"\\uf2d0\"\n#define ICON_FA_HEADPHONES u8\"\\uf025\"\n#define ICON_FA_STEP_BACKWARD u8\"\\uf048\"\n#define ICON_FA_DRAGON u8\"\\uf6d5\"\n#define ICON_FA_MICROPHONE_SLASH u8\"\\uf131\"\n#define ICON_FA_USER_PLUS u8\"\\uf234\"\n#define ICON_FA_WRENCH u8\"\\uf0ad\"\n#define ICON_FA_AMBULANCE u8\"\\uf0f9\"\n#define ICON_FA_ETHERNET u8\"\\uf796\"\n#define ICON_FA_EGG u8\"\\uf7fb\"\n#define ICON_FA_WIND u8\"\\uf72e\"\n#define ICON_FA_UNIVERSAL_ACCESS u8\"\\uf29a\"\n#define ICON_FA_BURN u8\"\\uf46a\"\n#define ICON_FA_HAND_HOLDING_HEART u8\"\\uf4be\"\n#define ICON_FA_DICE_ONE u8\"\\uf525\"\n#define ICON_FA_KEYBOARD u8\"\\uf11c\"\n#define ICON_FA_CHECK_DOUBLE u8\"\\uf560\"\n#define ICON_FA_HEADPHONES_ALT u8\"\\uf58f\"\n#define ICON_FA_BATTERY_HALF u8\"\\uf242\"\n#define ICON_FA_PROJECT_DIAGRAM u8\"\\uf542\"\n#define ICON_FA_PRAY u8\"\\uf683\"\n#define ICON_FA_GOPURAM u8\"\\uf664\"\n#define ICON_FA_GRIN_TEARS u8\"\\uf588\"\n#define ICON_FA_SORT_AMOUNT_UP u8\"\\uf161\"\n#define ICON_FA_COFFEE u8\"\\uf0f4\"\n#define ICON_FA_TABLET_ALT u8\"\\uf3fa\"\n#define ICON_FA_GRIN_BEAM_SWEAT u8\"\\uf583\"\n#define ICON_FA_HAND_POINT_RIGHT u8\"\\uf0a4\"\n#define ICON_FA_MAGIC u8\"\\uf0d0\"\n#define ICON_FA_CHARGING_STATION u8\"\\uf5e7\"\n#define ICON_FA_GRIN_TONGUE u8\"\\uf589\"\n#define ICON_FA_VOLUME_OFF u8\"\\uf026\"\n#define ICON_FA_SAD_TEAR u8\"\\uf5b4\"\n#define ICON_FA_CARET_RIGHT u8\"\\uf0da\"\n#define ICON_FA_BONG u8\"\\uf55c\"\n#define ICON_FA_BONE u8\"\\uf5d7\"\n#define ICON_FA_ELLIPSIS_V u8\"\\uf142\"\n#define ICON_FA_BALANCE_SCALE u8\"\\uf24e\"\n#define ICON_FA_FISH u8\"\\uf578\"\n#define ICON_FA_SPIDER u8\"\\uf717\"\n#define ICON_FA_CAMPGROUND u8\"\\uf6bb\"\n#define ICON_FA_CARET_SQUARE_UP u8\"\\uf151\"\n#define ICON_FA_RUPEE_SIGN u8\"\\uf156\"\n#define ICON_FA_ASSISTIVE_LISTENING_SYSTEMS u8\"\\uf2a2\"\n#define ICON_FA_POUND_SIGN u8\"\\uf154\"\n#define ICON_FA_ANKH u8\"\\uf644\"\n#define ICON_FA_BATTERY_QUARTER u8\"\\uf243\"\n#define ICON_FA_HAND_PEACE u8\"\\uf25b\"\n#define ICON_FA_SURPRISE u8\"\\uf5c2\"\n#define ICON_FA_FILE_PDF u8\"\\uf1c1\"\n#define ICON_FA_VIDEO_SLASH u8\"\\uf4e2\"\n#define ICON_FA_SUBWAY u8\"\\uf239\"\n#define ICON_FA_HORSE u8\"\\uf6f0\"\n#define ICON_FA_WINE_BOTTLE u8\"\\uf72f\"\n#define ICON_FA_BOOK_READER u8\"\\uf5da\"\n#define ICON_FA_COOKIE u8\"\\uf563\"\n#define ICON_FA_MONEY_BILL u8\"\\uf0d6\"\n#define ICON_FA_CHEVRON_DOWN u8\"\\uf078\"\n#define ICON_FA_CAR_SIDE u8\"\\uf5e4\"\n#define ICON_FA_FILTER u8\"\\uf0b0\"\n#define ICON_FA_FOLDER_OPEN u8\"\\uf07c\"\n#define ICON_FA_SIGNATURE u8\"\\uf5b7\"\n#define ICON_FA_SNOWBOARDING u8\"\\uf7ce\"\n#define ICON_FA_THUMBTACK u8\"\\uf08d\"\n#define ICON_FA_DICE_TWO u8\"\\uf528\"\n#define ICON_FA_LAUGH_WINK u8\"\\uf59c\"\n#define ICON_FA_BREAD_SLICE u8\"\\uf7ec\"\n#define ICON_FA_TEXT_HEIGHT u8\"\\uf034\"\n#define ICON_FA_VOLUME_MUTE u8\"\\uf6a9\"\n#define ICON_FA_VOTE_YEA u8\"\\uf772\"\n#define ICON_FA_QRCODE u8\"\\uf029\"\n#define ICON_FA_MERCURY u8\"\\uf223\"\n#define ICON_FA_USER_ASTRONAUT u8\"\\uf4fb\"\n#define ICON_FA_SORT_AMOUNT_DOWN u8\"\\uf160\"\n#define ICON_FA_SORT_DOWN u8\"\\uf0dd\"\n#define ICON_FA_COMPACT_DISC u8\"\\uf51f\"\n#define ICON_FA_PERCENTAGE u8\"\\uf541\"\n#define ICON_FA_COMMENT_MEDICAL u8\"\\uf7f5\"\n#define ICON_FA_STORE u8\"\\uf54e\"\n#define ICON_FA_COMMENT_DOTS u8\"\\uf4ad\"\n#define ICON_FA_SMILE_WINK u8\"\\uf4da\"\n#define ICON_FA_HOTEL u8\"\\uf594\"\n#define ICON_FA_PEPPER_HOT u8\"\\uf816\"\n#define ICON_FA_USER_EDIT u8\"\\uf4ff\"\n#define ICON_FA_DUMPSTER_FIRE u8\"\\uf794\"\n#define ICON_FA_CLOUD_SUN_RAIN u8\"\\uf743\"\n#define ICON_FA_GLOBE_ASIA u8\"\\uf57e\"\n#define ICON_FA_VIAL u8\"\\uf492\"\n#define ICON_FA_STROOPWAFEL u8\"\\uf551\"\n#define ICON_FA_DATABASE u8\"\\uf1c0\"\n#define ICON_FA_TREE u8\"\\uf1bb\"\n#define ICON_FA_SHOWER u8\"\\uf2cc\"\n#define ICON_FA_DRUM_STEELPAN u8\"\\uf56a\"\n#define ICON_FA_FILE_UPLOAD u8\"\\uf574\"\n#define ICON_FA_MEDKIT u8\"\\uf0fa\"\n#define ICON_FA_MINUS u8\"\\uf068\"\n#define ICON_FA_SHEKEL_SIGN u8\"\\uf20b\"\n#define ICON_FA_BELL_SLASH u8\"\\uf1f6\"\n#define ICON_FA_MAIL_BULK u8\"\\uf674\"\n#define ICON_FA_MOUNTAIN u8\"\\uf6fc\"\n#define ICON_FA_COUCH u8\"\\uf4b8\"\n#define ICON_FA_CHESS u8\"\\uf439\"\n#define ICON_FA_FILE_EXPORT u8\"\\uf56e\"\n#define ICON_FA_SIGN_LANGUAGE u8\"\\uf2a7\"\n#define ICON_FA_SNOWFLAKE u8\"\\uf2dc\"\n#define ICON_FA_PLAY u8\"\\uf04b\"\n#define ICON_FA_HEADSET u8\"\\uf590\"\n#define ICON_FA_SQUARE_ROOT_ALT u8\"\\uf698\"\n#define ICON_FA_CHART_BAR u8\"\\uf080\"\n#define ICON_FA_CHART_AREA u8\"\\uf1fe\"\n#define ICON_FA_EURO_SIGN u8\"\\uf153\"\n#define ICON_FA_CHESS_KING u8\"\\uf43f\"\n#define ICON_FA_MOBILE u8\"\\uf10b\"\n#define ICON_FA_BOX_OPEN u8\"\\uf49e\"\n#define ICON_FA_DOG u8\"\\uf6d3\"\n#define ICON_FA_FUTBOL u8\"\\uf1e3\"\n#define ICON_FA_LIRA_SIGN u8\"\\uf195\"\n#define ICON_FA_LIGHTBULB u8\"\\uf0eb\"\n#define ICON_FA_BOMB u8\"\\uf1e2\"\n#define ICON_FA_MITTEN u8\"\\uf7b5\"\n#define ICON_FA_TRUCK_MONSTER u8\"\\uf63b\"\n#define ICON_FA_ARROWS_ALT_H u8\"\\uf337\"\n#define ICON_FA_CHESS_ROOK u8\"\\uf447\"\n#define ICON_FA_FIRE_EXTINGUISHER u8\"\\uf134\"\n#define ICON_FA_BOOKMARK u8\"\\uf02e\"\n#define ICON_FA_ARROWS_ALT_V u8\"\\uf338\"\n#define ICON_FA_ICICLES u8\"\\uf7ad\"\n#define ICON_FA_FONT u8\"\\uf031\"\n#define ICON_FA_CAMERA_RETRO u8\"\\uf083\"\n#define ICON_FA_BLENDER u8\"\\uf517\"\n#define ICON_FA_THUMBS_DOWN u8\"\\uf165\"\n#define ICON_FA_GAMEPAD u8\"\\uf11b\"\n#define ICON_FA_COPYRIGHT u8\"\\uf1f9\"\n#define ICON_FA_JEDI u8\"\\uf669\"\n#define ICON_FA_HOCKEY_PUCK u8\"\\uf453\"\n#define ICON_FA_STOP_CIRCLE u8\"\\uf28d\"\n#define ICON_FA_BEZIER_CURVE u8\"\\uf55b\"\n#define ICON_FA_FOLDER u8\"\\uf07b\"\n#define ICON_FA_RSS u8\"\\uf09e\"\n#define ICON_FA_COLUMNS u8\"\\uf0db\"\n#define ICON_FA_GLASS_CHEERS u8\"\\uf79f\"\n#define ICON_FA_GRIN_WINK u8\"\\uf58c\"\n#define ICON_FA_STOP u8\"\\uf04d\"\n#define ICON_FA_MONEY_CHECK_ALT u8\"\\uf53d\"\n#define ICON_FA_COMPASS u8\"\\uf14e\"\n#define ICON_FA_TOOLBOX u8\"\\uf552\"\n#define ICON_FA_LIST_OL u8\"\\uf0cb\"\n#define ICON_FA_WINE_GLASS u8\"\\uf4e3\"\n#define ICON_FA_HORSE_HEAD u8\"\\uf7ab\"\n#define ICON_FA_USER_ALT_SLASH u8\"\\uf4fa\"\n#define ICON_FA_USER_TAG u8\"\\uf507\"\n#define ICON_FA_MICROSCOPE u8\"\\uf610\"\n#define ICON_FA_BRUSH u8\"\\uf55d\"\n#define ICON_FA_BAN u8\"\\uf05e\"\n#define ICON_FA_BARS u8\"\\uf0c9\"\n#define ICON_FA_CAR_CRASH u8\"\\uf5e1\"\n#define ICON_FA_ARROW_ALT_CIRCLE_DOWN u8\"\\uf358\"\n#define ICON_FA_MONEY_BILL_ALT u8\"\\uf3d1\"\n#define ICON_FA_JOURNAL_WHILLS u8\"\\uf66a\"\n#define ICON_FA_CHALKBOARD_TEACHER u8\"\\uf51c\"\n#define ICON_FA_PORTRAIT u8\"\\uf3e0\"\n#define ICON_FA_HAMMER u8\"\\uf6e3\"\n#define ICON_FA_RETWEET u8\"\\uf079\"\n#define ICON_FA_HOURGLASS u8\"\\uf254\"\n#define ICON_FA_HAND_PAPER u8\"\\uf256\"\n#define ICON_FA_SUBSCRIPT u8\"\\uf12c\"\n#define ICON_FA_DONATE u8\"\\uf4b9\"\n#define ICON_FA_GLASS_MARTINI_ALT u8\"\\uf57b\"\n#define ICON_FA_CODE_BRANCH u8\"\\uf126\"\n#define ICON_FA_NOT_EQUAL u8\"\\uf53e\"\n#define ICON_FA_MEH u8\"\\uf11a\"\n#define ICON_FA_LIST_ALT u8\"\\uf022\"\n#define ICON_FA_USER_COG u8\"\\uf4fe\"\n#define ICON_FA_PRESCRIPTION u8\"\\uf5b1\"\n#define ICON_FA_TABLET u8\"\\uf10a\"\n#define ICON_FA_PENCIL_RULER u8\"\\uf5ae\"\n#define ICON_FA_CREDIT_CARD u8\"\\uf09d\"\n#define ICON_FA_ARCHWAY u8\"\\uf557\"\n#define ICON_FA_HARD_HAT u8\"\\uf807\"\n#define ICON_FA_MAP_MARKER_ALT u8\"\\uf3c5\"\n#define ICON_FA_COG u8\"\\uf013\"\n#define ICON_FA_HANUKIAH u8\"\\uf6e6\"\n#define ICON_FA_SHUTTLE_VAN u8\"\\uf5b6\"\n#define ICON_FA_MONEY_CHECK u8\"\\uf53c\"\n#define ICON_FA_BELL u8\"\\uf0f3\"\n#define ICON_FA_CALENDAR_DAY u8\"\\uf783\"\n#define ICON_FA_TINT_SLASH u8\"\\uf5c7\"\n#define ICON_FA_PLANE_DEPARTURE u8\"\\uf5b0\"\n#define ICON_FA_USER_CHECK u8\"\\uf4fc\"\n#define ICON_FA_CHURCH u8\"\\uf51d\"\n#define ICON_FA_SEARCH_MINUS u8\"\\uf010\"\n#define ICON_FA_PALLET u8\"\\uf482\"\n#define ICON_FA_TINT u8\"\\uf043\"\n#define ICON_FA_STAMP u8\"\\uf5bf\"\n#define ICON_FA_KAABA u8\"\\uf66b\"\n#define ICON_FA_ALIGN_RIGHT u8\"\\uf038\"\n#define ICON_FA_QUOTE_RIGHT u8\"\\uf10e\"\n#define ICON_FA_BEER u8\"\\uf0fc\"\n#define ICON_FA_GRIN_ALT u8\"\\uf581\"\n#define ICON_FA_SORT_NUMERIC_DOWN u8\"\\uf162\"\n#define ICON_FA_FIRE u8\"\\uf06d\"\n#define ICON_FA_FAST_FORWARD u8\"\\uf050\"\n#define ICON_FA_MAP_MARKED_ALT u8\"\\uf5a0\"\n#define ICON_FA_PENCIL_ALT u8\"\\uf303\"\n#define ICON_FA_USERS_COG u8\"\\uf509\"\n#define ICON_FA_CARET_SQUARE_DOWN u8\"\\uf150\"\n#define ICON_FA_CRUTCH u8\"\\uf7f7\"\n#define ICON_FA_OBJECT_GROUP u8\"\\uf247\"\n#define ICON_FA_ANCHOR u8\"\\uf13d\"\n#define ICON_FA_HAND_POINT_LEFT u8\"\\uf0a5\"\n#define ICON_FA_USER_TIMES u8\"\\uf235\"\n#define ICON_FA_CALCULATOR u8\"\\uf1ec\"\n#define ICON_FA_DIZZY u8\"\\uf567\"\n#define ICON_FA_KISS_WINK_HEART u8\"\\uf598\"\n#define ICON_FA_FILE_MEDICAL u8\"\\uf477\"\n#define ICON_FA_SWIMMING_POOL u8\"\\uf5c5\"\n#define ICON_FA_WEIGHT_HANGING u8\"\\uf5cd\"\n#define ICON_FA_VR_CARDBOARD u8\"\\uf729\"\n#define ICON_FA_FAST_BACKWARD u8\"\\uf049\"\n#define ICON_FA_SATELLITE u8\"\\uf7bf\"\n#define ICON_FA_USER u8\"\\uf007\"\n#define ICON_FA_MINUS_CIRCLE u8\"\\uf056\"\n#define ICON_FA_CHESS_PAWN u8\"\\uf443\"\n#define ICON_FA_CALENDAR_MINUS u8\"\\uf272\"\n#define ICON_FA_CHESS_BOARD u8\"\\uf43c\"\n#define ICON_FA_LANDMARK u8\"\\uf66f\"\n#define ICON_FA_SWATCHBOOK u8\"\\uf5c3\"\n#define ICON_FA_HOTDOG u8\"\\uf80f\"\n#define ICON_FA_SNOWMAN u8\"\\uf7d0\"\n#define ICON_FA_LAPTOP u8\"\\uf109\"\n#define ICON_FA_TORAH u8\"\\uf6a0\"\n#define ICON_FA_FROWN_OPEN u8\"\\uf57a\"\n#define ICON_FA_USER_LOCK u8\"\\uf502\"\n#define ICON_FA_AD u8\"\\uf641\"\n#define ICON_FA_USER_CIRCLE u8\"\\uf2bd\"\n#define ICON_FA_DIVIDE u8\"\\uf529\"\n#define ICON_FA_HANDSHAKE u8\"\\uf2b5\"\n#define ICON_FA_CUT u8\"\\uf0c4\"\n#define ICON_FA_HIKING u8\"\\uf6ec\"\n#define ICON_FA_STREET_VIEW u8\"\\uf21d\"\n#define ICON_FA_GREATER_THAN u8\"\\uf531\"\n#define ICON_FA_PASTAFARIANISM u8\"\\uf67b\"\n#define ICON_FA_MINUS_SQUARE u8\"\\uf146\"\n#define ICON_FA_SAVE u8\"\\uf0c7\"\n#define ICON_FA_COMMENT_DOLLAR u8\"\\uf651\"\n#define ICON_FA_TRASH_ALT u8\"\\uf2ed\"\n#define ICON_FA_PUZZLE_PIECE u8\"\\uf12e\"\n#define ICON_FA_MENORAH u8\"\\uf676\"\n#define ICON_FA_CLOUD_SUN u8\"\\uf6c4\"\n#define ICON_FA_USER_FRIENDS u8\"\\uf500\"\n#define ICON_FA_FILE_MEDICAL_ALT u8\"\\uf478\"\n#define ICON_FA_ARROW_LEFT u8\"\\uf060\"\n#define ICON_FA_BOXES u8\"\\uf468\"\n#define ICON_FA_THERMOMETER_EMPTY u8\"\\uf2cb\"\n#define ICON_FA_EXCLAMATION_TRIANGLE u8\"\\uf071\"\n#define ICON_FA_GIFT u8\"\\uf06b\"\n#define ICON_FA_COGS u8\"\\uf085\"\n#define ICON_FA_SIGNAL u8\"\\uf012\"\n#define ICON_FA_SHAPES u8\"\\uf61f\"\n#define ICON_FA_CLOUD_RAIN u8\"\\uf73d\"\n#define ICON_FA_ELLIPSIS_H u8\"\\uf141\"\n#define ICON_FA_LESS_THAN_EQUAL u8\"\\uf537\"\n#define ICON_FA_CHEVRON_CIRCLE_LEFT u8\"\\uf137\"\n#define ICON_FA_MORTAR_PESTLE u8\"\\uf5a7\"\n#define ICON_FA_SITEMAP u8\"\\uf0e8\"\n#define ICON_FA_BUS_ALT u8\"\\uf55e\"\n#define ICON_FA_ID_BADGE u8\"\\uf2c1\"\n#define ICON_FA_FIST_RAISED u8\"\\uf6de\"\n#define ICON_FA_BATTERY_FULL u8\"\\uf240\"\n#define ICON_FA_CROWN u8\"\\uf521\"\n#define ICON_FA_EXCHANGE_ALT u8\"\\uf362\"\n#define ICON_FA_SOCKS u8\"\\uf696\"\n#define ICON_FA_CASH_REGISTER u8\"\\uf788\"\n#define ICON_FA_REDO u8\"\\uf01e\"\n#define ICON_FA_EXCLAMATION_CIRCLE u8\"\\uf06a\"\n#define ICON_FA_COMMENTS u8\"\\uf086\"\n#define ICON_FA_BRIEFCASE_MEDICAL u8\"\\uf469\"\n#define ICON_FA_CARET_SQUARE_RIGHT u8\"\\uf152\"\n#define ICON_FA_PEN u8\"\\uf304\"\n#define ICON_FA_BACKSPACE u8\"\\uf55a\"\n#define ICON_FA_SLASH u8\"\\uf715\"\n#define ICON_FA_HOT_TUB u8\"\\uf593\"\n#define ICON_FA_SUITCASE_ROLLING u8\"\\uf5c1\"\n#define ICON_FA_BATTERY_EMPTY u8\"\\uf244\"\n#define ICON_FA_GLOBE_AFRICA u8\"\\uf57c\"\n#define ICON_FA_SLEIGH u8\"\\uf7cc\"\n#define ICON_FA_BOLT u8\"\\uf0e7\"\n#define ICON_FA_THERMOMETER_QUARTER u8\"\\uf2ca\"\n#define ICON_FA_EYE u8\"\\uf06e\"\n#define ICON_FA_TROPHY u8\"\\uf091\"\n#define ICON_FA_BRAILLE u8\"\\uf2a1\"\n#define ICON_FA_PLUS u8\"\\uf067\"\n#define ICON_FA_LIST_UL u8\"\\uf0ca\"\n#define ICON_FA_SMOKING_BAN u8\"\\uf54d\"\n#define ICON_FA_BATH u8\"\\uf2cd\"\n#define ICON_FA_VOLUME_DOWN u8\"\\uf027\"\n#define ICON_FA_QUESTION_CIRCLE u8\"\\uf059\"\n#define ICON_FA_FILE_CODE u8\"\\uf1c9\"\n#define ICON_FA_GAVEL u8\"\\uf0e3\"\n#define ICON_FA_CANDY_CANE u8\"\\uf786\"\n#define ICON_FA_NETWORK_WIRED u8\"\\uf6ff\"\n#define ICON_FA_CARET_SQUARE_LEFT u8\"\\uf191\"\n#define ICON_FA_PLANE_ARRIVAL u8\"\\uf5af\"\n#define ICON_FA_SHARE_SQUARE u8\"\\uf14d\"\n#define ICON_FA_MEDAL u8\"\\uf5a2\"\n#define ICON_FA_THERMOMETER_HALF u8\"\\uf2c9\"\n#define ICON_FA_QUESTION u8\"\\uf128\"\n#define ICON_FA_CAR_BATTERY u8\"\\uf5df\"\n#define ICON_FA_DOOR_CLOSED u8\"\\uf52a\"\n#define ICON_FA_LEAF u8\"\\uf06c\"\n#define ICON_FA_USER_MINUS u8\"\\uf503\"\n#define ICON_FA_MUSIC u8\"\\uf001\"\n#define ICON_FA_GLOBE_EUROPE u8\"\\uf7a2\"\n#define ICON_FA_HOUSE_DAMAGE u8\"\\uf6f1\"\n#define ICON_FA_CHEVRON_RIGHT u8\"\\uf054\"\n#define ICON_FA_GRIP_HORIZONTAL u8\"\\uf58d\"\n#define ICON_FA_DICE_FOUR u8\"\\uf524\"\n#define ICON_FA_DEAF u8\"\\uf2a4\"\n#define ICON_FA_REGISTERED u8\"\\uf25d\"\n#define ICON_FA_WINDOW_CLOSE u8\"\\uf410\"\n#define ICON_FA_LINK u8\"\\uf0c1\"\n#define ICON_FA_YEN_SIGN u8\"\\uf157\"\n#define ICON_FA_ATOM u8\"\\uf5d2\"\n#define ICON_FA_LESS_THAN u8\"\\uf536\"\n#define ICON_FA_OTTER u8\"\\uf700\"\n#define ICON_FA_INFO u8\"\\uf129\"\n#define ICON_FA_MARS_DOUBLE u8\"\\uf227\"\n#define ICON_FA_CLIPBOARD_CHECK u8\"\\uf46c\"\n#define ICON_FA_SKULL u8\"\\uf54c\"\n#define ICON_FA_GRIP_LINES u8\"\\uf7a4\"\n#define ICON_FA_HOSPITAL_SYMBOL u8\"\\uf47e\"\n#define ICON_FA_X_RAY u8\"\\uf497\"\n#define ICON_FA_ARROW_UP u8\"\\uf062\"\n#define ICON_FA_MONEY_BILL_WAVE u8\"\\uf53a\"\n#define ICON_FA_DOT_CIRCLE u8\"\\uf192\"\n#define ICON_FA_PAUSE_CIRCLE u8\"\\uf28b\"\n#define ICON_FA_IMAGES u8\"\\uf302\"\n#define ICON_FA_STAR_HALF u8\"\\uf089\"\n#define ICON_FA_SPLOTCH u8\"\\uf5bc\"\n#define ICON_FA_STAR_HALF_ALT u8\"\\uf5c0\"\n#define ICON_FA_SHIP u8\"\\uf21a\"\n#define ICON_FA_BOOK_DEAD u8\"\\uf6b7\"\n#define ICON_FA_CHECK u8\"\\uf00c\"\n#define ICON_FA_RAINBOW u8\"\\uf75b\"\n#define ICON_FA_POWER_OFF u8\"\\uf011\"\n#define ICON_FA_LEMON u8\"\\uf094\"\n#define ICON_FA_GLOBE_AMERICAS u8\"\\uf57d\"\n#define ICON_FA_PEACE u8\"\\uf67c\"\n#define ICON_FA_THERMOMETER_THREE_QUARTERS u8\"\\uf2c8\"\n#define ICON_FA_WAREHOUSE u8\"\\uf494\"\n#define ICON_FA_TRANSGENDER u8\"\\uf224\"\n#define ICON_FA_PLUS_SQUARE u8\"\\uf0fe\"\n#define ICON_FA_BULLSEYE u8\"\\uf140\"\n#define ICON_FA_COOKIE_BITE u8\"\\uf564\"\n#define ICON_FA_USERS u8\"\\uf0c0\"\n#define ICON_FA_TRANSGENDER_ALT u8\"\\uf225\"\n#define ICON_FA_ASTERISK u8\"\\uf069\"\n#define ICON_FA_STAR_OF_DAVID u8\"\\uf69a\"\n#define ICON_FA_PLUS_CIRCLE u8\"\\uf055\"\n#define ICON_FA_CART_ARROW_DOWN u8\"\\uf218\"\n#define ICON_FA_FLUSHED u8\"\\uf579\"\n#define ICON_FA_STORE_ALT u8\"\\uf54f\"\n#define ICON_FA_PEOPLE_CARRY u8\"\\uf4ce\"\n#define ICON_FA_LONG_ARROW_ALT_DOWN u8\"\\uf309\"\n#define ICON_FA_SAD_CRY u8\"\\uf5b3\"\n#define ICON_FA_DIGITAL_TACHOGRAPH u8\"\\uf566\"\n#define ICON_FA_FILE_EXCEL u8\"\\uf1c3\"\n#define ICON_FA_TEETH u8\"\\uf62e\"\n#define ICON_FA_HAND_SCISSORS u8\"\\uf257\"\n#define ICON_FA_FILE_INVOICE_DOLLAR u8\"\\uf571\"\n#define ICON_FA_STEP_FORWARD u8\"\\uf051\"\n#define ICON_FA_BACKWARD u8\"\\uf04a\"\n#define ICON_FA_SCROLL u8\"\\uf70e\"\n#define ICON_FA_IGLOO u8\"\\uf7ae\"\n#define ICON_FA_CODE u8\"\\uf121\"\n#define ICON_FA_TRAM u8\"\\uf7da\"\n#define ICON_FA_TORII_GATE u8\"\\uf6a1\"\n#define ICON_FA_SKIING u8\"\\uf7c9\"\n#define ICON_FA_CHAIR u8\"\\uf6c0\"\n#define ICON_FA_DUMBBELL u8\"\\uf44b\"\n#define ICON_FA_ANGLE_DOUBLE_UP u8\"\\uf102\"\n#define ICON_FA_ANGLE_DOUBLE_LEFT u8\"\\uf100\"\n#define ICON_FA_MOSQUE u8\"\\uf678\"\n#define ICON_FA_COMMENTS_DOLLAR u8\"\\uf653\"\n#define ICON_FA_FILE_PRESCRIPTION u8\"\\uf572\"\n#define ICON_FA_ANGLE_LEFT u8\"\\uf104\"\n#define ICON_FA_ATLAS u8\"\\uf558\"\n#define ICON_FA_PIGGY_BANK u8\"\\uf4d3\"\n#define ICON_FA_DOLLY_FLATBED u8\"\\uf474\"\n#define ICON_FA_RANDOM u8\"\\uf074\"\n#define ICON_FA_PEN_ALT u8\"\\uf305\"\n#define ICON_FA_PRAYING_HANDS u8\"\\uf684\"\n#define ICON_FA_VOLUME_UP u8\"\\uf028\"\n#define ICON_FA_CLIPBOARD_LIST u8\"\\uf46d\"\n#define ICON_FA_GRIN_STARS u8\"\\uf587\"\n#define ICON_FA_FOLDER_MINUS u8\"\\uf65d\"\n#define ICON_FA_DEMOCRAT u8\"\\uf747\"\n#define ICON_FA_MAGNET u8\"\\uf076\"\n#define ICON_FA_VIHARA u8\"\\uf6a7\"\n#define ICON_FA_GRIMACE u8\"\\uf57f\"\n#define ICON_FA_CHECK_CIRCLE u8\"\\uf058\"\n#define ICON_FA_SEARCH_DOLLAR u8\"\\uf688\"\n#define ICON_FA_LONG_ARROW_ALT_LEFT u8\"\\uf30a\"\n#define ICON_FA_CROW u8\"\\uf520\"\n#define ICON_FA_EYE_DROPPER u8\"\\uf1fb\"\n#define ICON_FA_CROP u8\"\\uf125\"\n#define ICON_FA_SIGN u8\"\\uf4d9\"\n#define ICON_FA_ARROW_CIRCLE_DOWN u8\"\\uf0ab\"\n#define ICON_FA_VIDEO u8\"\\uf03d\"\n#define ICON_FA_DOWNLOAD u8\"\\uf019\"\n#define ICON_FA_BOLD u8\"\\uf032\"\n#define ICON_FA_CARET_DOWN u8\"\\uf0d7\"\n#define ICON_FA_CHEVRON_LEFT u8\"\\uf053\"\n#define ICON_FA_HAMSA u8\"\\uf665\"\n#define ICON_FA_CART_PLUS u8\"\\uf217\"\n#define ICON_FA_CLIPBOARD u8\"\\uf328\"\n#define ICON_FA_SHOE_PRINTS u8\"\\uf54b\"\n#define ICON_FA_PHONE_SLASH u8\"\\uf3dd\"\n#define ICON_FA_REPLY u8\"\\uf3e5\"\n#define ICON_FA_HOURGLASS_HALF u8\"\\uf252\"\n#define ICON_FA_LONG_ARROW_ALT_UP u8\"\\uf30c\"\n#define ICON_FA_CHESS_KNIGHT u8\"\\uf441\"\n#define ICON_FA_BARCODE u8\"\\uf02a\"\n#define ICON_FA_DRAW_POLYGON u8\"\\uf5ee\"\n#define ICON_FA_WATER u8\"\\uf773\"\n#define ICON_FA_PAUSE u8\"\\uf04c\"\n#define ICON_FA_WINE_GLASS_ALT u8\"\\uf5ce\"\n#define ICON_FA_GLASS_WHISKEY u8\"\\uf7a0\"\n#define ICON_FA_BOX u8\"\\uf466\"\n#define ICON_FA_DIAGNOSES u8\"\\uf470\"\n#define ICON_FA_FILE_IMAGE u8\"\\uf1c5\"\n#define ICON_FA_ARROW_CIRCLE_RIGHT u8\"\\uf0a9\"\n#define ICON_FA_TASKS u8\"\\uf0ae\"\n#define ICON_FA_VECTOR_SQUARE u8\"\\uf5cb\"\n#define ICON_FA_QUOTE_LEFT u8\"\\uf10d\"\n#define ICON_FA_MOBILE_ALT u8\"\\uf3cd\"\n#define ICON_FA_USER_SHIELD u8\"\\uf505\"\n#define ICON_FA_BLOG u8\"\\uf781\"\n#define ICON_FA_MARKER u8\"\\uf5a1\"\n#define ICON_FA_USER_TIE u8\"\\uf508\"\n#define ICON_FA_TOOLS u8\"\\uf7d9\"\n#define ICON_FA_CLOUD u8\"\\uf0c2\"\n#define ICON_FA_HAND_HOLDING_USD u8\"\\uf4c0\"\n#define ICON_FA_CERTIFICATE u8\"\\uf0a3\"\n#define ICON_FA_CLOUD_DOWNLOAD_ALT u8\"\\uf381\"\n#define ICON_FA_ANGRY u8\"\\uf556\"\n#define ICON_FA_FROG u8\"\\uf52e\"\n#define ICON_FA_CAMERA u8\"\\uf030\"\n#define ICON_FA_DICE_THREE u8\"\\uf527\"\n#define ICON_FA_MEMORY u8\"\\uf538\"\n#define ICON_FA_PEN_SQUARE u8\"\\uf14b\"\n#define ICON_FA_SORT u8\"\\uf0dc\"\n#define ICON_FA_PLUG u8\"\\uf1e6\"\n#define ICON_FA_MOUSE_POINTER u8\"\\uf245\"\n#define ICON_FA_ENVELOPE u8\"\\uf0e0\"\n#define ICON_FA_LAYER_GROUP u8\"\\uf5fd\"\n#define ICON_FA_TRAIN u8\"\\uf238\"\n#define ICON_FA_BULLHORN u8\"\\uf0a1\"\n#define ICON_FA_BABY u8\"\\uf77c\"\n#define ICON_FA_CONCIERGE_BELL u8\"\\uf562\"\n#define ICON_FA_CIRCLE u8\"\\uf111\"\n#define ICON_FA_I_CURSOR u8\"\\uf246\"\n#define ICON_FA_CAR u8\"\\uf1b9\"\n#define ICON_FA_CAT u8\"\\uf6be\"\n#define ICON_FA_WALLET u8\"\\uf555\"\n#define ICON_FA_BOOK_MEDICAL u8\"\\uf7e6\"\n#define ICON_FA_H_SQUARE u8\"\\uf0fd\"\n#define ICON_FA_HEART u8\"\\uf004\"\n#define ICON_FA_LOCK_OPEN u8\"\\uf3c1\"\n#define ICON_FA_STREAM u8\"\\uf550\"\n#define ICON_FA_LOCK u8\"\\uf023\"\n#define ICON_FA_CARROT u8\"\\uf787\"\n#define ICON_FA_SMILE_BEAM u8\"\\uf5b8\"\n#define ICON_FA_USER_NURSE u8\"\\uf82f\"\n#define ICON_FA_MICROPHONE_ALT u8\"\\uf3c9\"\n#define ICON_FA_SPA u8\"\\uf5bb\"\n#define ICON_FA_CHEVRON_CIRCLE_DOWN u8\"\\uf13a\"\n#define ICON_FA_FOLDER_PLUS u8\"\\uf65e\"\n#define ICON_FA_CLOUD_MEATBALL u8\"\\uf73b\"\n#define ICON_FA_BOOK_OPEN u8\"\\uf518\"\n#define ICON_FA_MAP u8\"\\uf279\"\n#define ICON_FA_COCKTAIL u8\"\\uf561\"\n#define ICON_FA_CLONE u8\"\\uf24d\"\n#define ICON_FA_ID_CARD_ALT u8\"\\uf47f\"\n#define ICON_FA_CHECK_SQUARE u8\"\\uf14a\"\n#define ICON_FA_CHART_LINE u8\"\\uf201\"\n#define ICON_FA_FILE_ARCHIVE u8\"\\uf1c6\"\n#define ICON_FA_DOVE u8\"\\uf4ba\"\n#define ICON_FA_MARS_STROKE u8\"\\uf229\"\n#define ICON_FA_ENVELOPE_OPEN u8\"\\uf2b6\"\n#define ICON_FA_WHEELCHAIR u8\"\\uf193\"\n#define ICON_FA_ROBOT u8\"\\uf544\"\n#define ICON_FA_UNDO_ALT u8\"\\uf2ea\"\n#define ICON_FA_TICKET_ALT u8\"\\uf3ff\"\n#define ICON_FA_TRUCK u8\"\\uf0d1\"\n#define ICON_FA_WON_SIGN u8\"\\uf159\"\n#define ICON_FA_SUPERSCRIPT u8\"\\uf12b\"\n#define ICON_FA_TTY u8\"\\uf1e4\"\n#define ICON_FA_USER_MD u8\"\\uf0f0\"\n#define ICON_FA_ALIGN_LEFT u8\"\\uf036\"\n#define ICON_FA_TABLETS u8\"\\uf490\"\n#define ICON_FA_MOTORCYCLE u8\"\\uf21c\"\n#define ICON_FA_ANGLE_UP u8\"\\uf106\"\n#define ICON_FA_BROOM u8\"\\uf51a\"\n#define ICON_FA_DICE_D20 u8\"\\uf6cf\"\n#define ICON_FA_LEVEL_DOWN_ALT u8\"\\uf3be\"\n#define ICON_FA_PAPERCLIP u8\"\\uf0c6\"\n#define ICON_FA_USER_CLOCK u8\"\\uf4fd\"\n#define ICON_FA_SORT_ALPHA_UP u8\"\\uf15e\"\n#define ICON_FA_AUDIO_DESCRIPTION u8\"\\uf29e\"\n#define ICON_FA_FILE_CSV u8\"\\uf6dd\"\n#define ICON_FA_FILE_DOWNLOAD u8\"\\uf56d\"\n#define ICON_FA_SYNC_ALT u8\"\\uf2f1\"\n#define ICON_FA_KISS u8\"\\uf596\"\n#define ICON_FA_HANDS u8\"\\uf4c2\"\n#define ICON_FA_REPUBLICAN u8\"\\uf75e\"\n#define ICON_FA_EDIT u8\"\\uf044\"\n#define ICON_FA_UNIVERSITY u8\"\\uf19c\"\n#define ICON_FA_KHANDA u8\"\\uf66d\"\n#define ICON_FA_GLASSES u8\"\\uf530\"\n#define ICON_FA_SQUARE u8\"\\uf0c8\"\n#define ICON_FA_GRIN_SQUINT u8\"\\uf585\"\n#define ICON_FA_GLOBE u8\"\\uf0ac\"\n#define ICON_FA_RECEIPT u8\"\\uf543\"\n#define ICON_FA_STRIKETHROUGH u8\"\\uf0cc\"\n#define ICON_FA_UNLOCK u8\"\\uf09c\"\n#define ICON_FA_DICE_SIX u8\"\\uf526\"\n#define ICON_FA_GRIP_VERTICAL u8\"\\uf58e\"\n#define ICON_FA_PILLS u8\"\\uf484\"\n#define ICON_FA_EXCLAMATION u8\"\\uf12a\"\n#define ICON_FA_PERSON_BOOTH u8\"\\uf756\"\n#define ICON_FA_CALENDAR_PLUS u8\"\\uf271\"\n#define ICON_FA_SMOG u8\"\\uf75f\"\n#define ICON_FA_LOCATION_ARROW u8\"\\uf124\"\n#define ICON_FA_UMBRELLA u8\"\\uf0e9\"\n#define ICON_FA_QURAN u8\"\\uf687\"\n#define ICON_FA_UNDO u8\"\\uf0e2\"\n#define ICON_FA_DUMPSTER u8\"\\uf793\"\n#define ICON_FA_FUNNEL_DOLLAR u8\"\\uf662\"\n#define ICON_FA_INDENT u8\"\\uf03c\"\n#define ICON_FA_LANGUAGE u8\"\\uf1ab\"\n#define ICON_FA_ARROW_ALT_CIRCLE_UP u8\"\\uf35b\"\n#define ICON_FA_ROUTE u8\"\\uf4d7\"\n#define ICON_FA_USER_ALT u8\"\\uf406\"\n#define ICON_FA_TIMES u8\"\\uf00d\"\n#define ICON_FA_CLINIC_MEDICAL u8\"\\uf7f2\"\n#define ICON_FA_LEVEL_UP_ALT u8\"\\uf3bf\"\n#define ICON_FA_BLIND u8\"\\uf29d\"\n#define ICON_FA_CHEESE u8\"\\uf7ef\"\n#define ICON_FA_PHONE_SQUARE u8\"\\uf098\"\n#define ICON_FA_SHOPPING_BASKET u8\"\\uf291\"\n#define ICON_FA_ICE_CREAM u8\"\\uf810\"\n#define ICON_FA_RING u8\"\\uf70b\"\n#define ICON_FA_CITY u8\"\\uf64f\"\n#define ICON_FA_TEXT_WIDTH u8\"\\uf035\"\n#define ICON_FA_RSS_SQUARE u8\"\\uf143\"\n#define ICON_FA_PAINT_BRUSH u8\"\\uf1fc\"\n#define ICON_FA_PARACHUTE_BOX u8\"\\uf4cd\"\n#define ICON_FA_SIM_CARD u8\"\\uf7c4\"\n#define ICON_FA_CLOUD_UPLOAD_ALT u8\"\\uf382\"\n#define ICON_FA_SORT_UP u8\"\\uf0de\"\n#define ICON_FA_SIGN_OUT_ALT u8\"\\uf2f5\"\n#define ICON_FA_USER_NINJA u8\"\\uf504\"\n#define ICON_FA_SIGN_IN_ALT u8\"\\uf2f6\"\n#define ICON_FA_MUG_HOT u8\"\\uf7b6\"\n#define ICON_FA_SHARE_ALT u8\"\\uf1e0\"\n#define ICON_FA_CALENDAR_CHECK u8\"\\uf274\"\n#define ICON_FA_PEN_FANCY u8\"\\uf5ac\"\n#define ICON_FA_BIOHAZARD u8\"\\uf780\"\n#define ICON_FA_BED u8\"\\uf236\"\n#define ICON_FA_FILE_SIGNATURE u8\"\\uf573\"\n#define ICON_FA_TOGGLE_OFF u8\"\\uf204\"\n#define ICON_FA_TRAFFIC_LIGHT u8\"\\uf637\"\n#define ICON_FA_TRACTOR u8\"\\uf722\"\n#define ICON_FA_MEH_ROLLING_EYES u8\"\\uf5a5\"\n#define ICON_FA_COMMENT_ALT u8\"\\uf27a\"\n#define ICON_FA_RULER_HORIZONTAL u8\"\\uf547\"\n#define ICON_FA_PAINT_ROLLER u8\"\\uf5aa\"\n#define ICON_FA_HAT_WIZARD u8\"\\uf6e8\"\n#define ICON_FA_CALENDAR u8\"\\uf133\"\n#define ICON_FA_MICROPHONE u8\"\\uf130\"\n#define ICON_FA_FOOTBALL_BALL u8\"\\uf44e\"\n#define ICON_FA_ALLERGIES u8\"\\uf461\"\n#define ICON_FA_ID_CARD u8\"\\uf2c2\"\n#define ICON_FA_REDO_ALT u8\"\\uf2f9\"\n#define ICON_FA_PLAY_CIRCLE u8\"\\uf144\"\n#define ICON_FA_THERMOMETER u8\"\\uf491\"\n#define ICON_FA_DOLLAR_SIGN u8\"\\uf155\"\n#define ICON_FA_DUNGEON u8\"\\uf6d9\"\n#define ICON_FA_COMPRESS u8\"\\uf066\"\n#define ICON_FA_SEARCH_LOCATION u8\"\\uf689\"\n#define ICON_FA_BLENDER_PHONE u8\"\\uf6b6\"\n#define ICON_FA_ANGLE_RIGHT u8\"\\uf105\"\n#define ICON_FA_CHESS_QUEEN u8\"\\uf445\"\n#define ICON_FA_PAGER u8\"\\uf815\"\n#define ICON_FA_MEH_BLANK u8\"\\uf5a4\"\n#define ICON_FA_EJECT u8\"\\uf052\"\n#define ICON_FA_HOURGLASS_END u8\"\\uf253\"\n#define ICON_FA_TOOTH u8\"\\uf5c9\"\n#define ICON_FA_BUSINESS_TIME u8\"\\uf64a\"\n#define ICON_FA_PLACE_OF_WORSHIP u8\"\\uf67f\"\n#define ICON_FA_MOON u8\"\\uf186\"\n#define ICON_FA_GRIN_TONGUE_SQUINT u8\"\\uf58a\"\n#define ICON_FA_WALKING u8\"\\uf554\"\n#define ICON_FA_SHIPPING_FAST u8\"\\uf48b\"\n#define ICON_FA_CARET_LEFT u8\"\\uf0d9\"\n#define ICON_FA_DICE u8\"\\uf522\"\n#define ICON_FA_RUBLE_SIGN u8\"\\uf158\"\n#define ICON_FA_RULER_VERTICAL u8\"\\uf548\"\n#define ICON_FA_HAND_POINTER u8\"\\uf25a\"\n#define ICON_FA_TAPE u8\"\\uf4db\"\n#define ICON_FA_SHOPPING_BAG u8\"\\uf290\"\n#define ICON_FA_SKIING_NORDIC u8\"\\uf7ca\"\n#define ICON_FA_HIPPO u8\"\\uf6ed\"\n#define ICON_FA_CUBE u8\"\\uf1b2\"\n#define ICON_FA_CAPSULES u8\"\\uf46b\"\n#define ICON_FA_KIWI_BIRD u8\"\\uf535\"\n#define ICON_FA_CHEVRON_CIRCLE_UP u8\"\\uf139\"\n#define ICON_FA_MARS_STROKE_V u8\"\\uf22a\"\n#define ICON_FA_POO_STORM u8\"\\uf75a\"\n#define ICON_FA_JOINT u8\"\\uf595\"\n#define ICON_FA_MARS_STROKE_H u8\"\\uf22b\"\n#define ICON_FA_ADDRESS_BOOK u8\"\\uf2b9\"\n#define ICON_FA_PROCEDURES u8\"\\uf487\"\n#define ICON_FA_GEM u8\"\\uf3a5\"\n#define ICON_FA_RULER_COMBINED u8\"\\uf546\"\n#define ICON_FA_BRAIN u8\"\\uf5dc\"\n#define ICON_FA_STAR_AND_CRESCENT u8\"\\uf699\"\n#define ICON_FA_FIGHTER_JET u8\"\\uf0fb\"\n#define ICON_FA_SPACE_SHUTTLE u8\"\\uf197\"\n#define ICON_FA_MAP_PIN u8\"\\uf276\"\n#define ICON_FA_ALIGN_CENTER u8\"\\uf037\"\n#define ICON_FA_SORT_ALPHA_DOWN u8\"\\uf15d\"\n#define ICON_FA_PARKING u8\"\\uf540\"\n#define ICON_FA_MAP_SIGNS u8\"\\uf277\"\n#define ICON_FA_PALETTE u8\"\\uf53f\"\n#define ICON_FA_GLASS_MARTINI u8\"\\uf000\"\n#define ICON_FA_TIMES_CIRCLE u8\"\\uf057\"\n#define ICON_FA_MONUMENT u8\"\\uf5a6\"\n#define ICON_FA_GUITAR u8\"\\uf7a6\"\n#define ICON_FA_GRIN_BEAM u8\"\\uf582\"\n#define ICON_FA_KEY u8\"\\uf084\"\n#define ICON_FA_TH_LIST u8\"\\uf00b\"\n#define ICON_FA_SHARE_ALT_SQUARE u8\"\\uf1e1\"\n#define ICON_FA_DRUM u8\"\\uf569\"\n#define ICON_FA_FILE_CONTRACT u8\"\\uf56c\"\n#define ICON_FA_RESTROOM u8\"\\uf7bd\"\n#define ICON_FA_UNLOCK_ALT u8\"\\uf13e\"\n#define ICON_FA_MICROPHONE_ALT_SLASH u8\"\\uf539\"\n#define ICON_FA_USER_SECRET u8\"\\uf21b\"\n#define ICON_FA_ARROW_RIGHT u8\"\\uf061\"\n#define ICON_FA_FILE_VIDEO u8\"\\uf1c8\"\n#define ICON_FA_ARROW_ALT_CIRCLE_RIGHT u8\"\\uf35a\"\n#define ICON_FA_COMMENT u8\"\\uf075\"\n#define ICON_FA_CALENDAR_WEEK u8\"\\uf784\"\n#define ICON_FA_USER_GRADUATE u8\"\\uf501\"\n#define ICON_FA_HAND_MIDDLE_FINGER u8\"\\uf806\"\n#define ICON_FA_POO u8\"\\uf2fe\"\n#define ICON_FA_GRIP_LINES_VERTICAL u8\"\\uf7a5\"\n#define ICON_FA_TABLE u8\"\\uf0ce\"\n#define ICON_FA_POLL u8\"\\uf681\"\n#define ICON_FA_CAR_ALT u8\"\\uf5de\"\n#define ICON_FA_THUMBS_UP u8\"\\uf164\"\n#define ICON_FA_TRADEMARK u8\"\\uf25c\"\n#define ICON_FA_CLOUD_MOON u8\"\\uf6c3\"\n#define ICON_FA_VIALS u8\"\\uf493\"\n#define ICON_FA_FIRST_AID u8\"\\uf479\"\n#define ICON_FA_ERASER u8\"\\uf12d\"\n#define ICON_FA_MARS u8\"\\uf222\"\n#define ICON_FA_STAR_OF_LIFE u8\"\\uf621\"\n#define ICON_FA_FEATHER u8\"\\uf52d\"\n#define ICON_FA_SQUARE_FULL u8\"\\uf45c\"\n#define ICON_FA_DOLLY u8\"\\uf472\"\n#define ICON_FA_HOURGLASS_START u8\"\\uf251\"\n#define ICON_FA_GRIN_HEARTS u8\"\\uf584\"\n#define ICON_FA_CUBES u8\"\\uf1b3\"\n#define ICON_FA_HASHTAG u8\"\\uf292\"\n#define ICON_FA_SEEDLING u8\"\\uf4d8\"\n#define ICON_FA_HAYKAL u8\"\\uf666\"\n#define ICON_FA_TSHIRT u8\"\\uf553\"\n#define ICON_FA_LAUGH_SQUINT u8\"\\uf59b\"\n#define ICON_FA_HDD u8\"\\uf0a0\"\n#define ICON_FA_NEWSPAPER u8\"\\uf1ea\"\n#define ICON_FA_HOSPITAL_ALT u8\"\\uf47d\"\n#define ICON_FA_USER_SLASH u8\"\\uf506\"\n#define ICON_FA_FILE_WORD u8\"\\uf1c2\"\n#define ICON_FA_ENVELOPE_SQUARE u8\"\\uf199\"\n#define ICON_FA_GENDERLESS u8\"\\uf22d\"\n#define ICON_FA_DICE_FIVE u8\"\\uf523\"\n#define ICON_FA_SYNAGOGUE u8\"\\uf69b\"\n#define ICON_FA_PAW u8\"\\uf1b0\"\n#define ICON_FA_RADIATION u8\"\\uf7b9\"\n#define ICON_FA_CROSS u8\"\\uf654\"\n#define ICON_FA_ARCHIVE u8\"\\uf187\"\n#define ICON_FA_PHONE_VOLUME u8\"\\uf2a0\"\n#define ICON_FA_SOLAR_PANEL u8\"\\uf5ba\"\n#define ICON_FA_INFINITY u8\"\\uf534\"\n#define ICON_FA_HAND_POINT_DOWN u8\"\\uf0a7\"\n#define ICON_FA_MAP_MARKER u8\"\\uf041\"\n#define ICON_FA_CALENDAR_ALT u8\"\\uf073\"\n#define ICON_FA_AMERICAN_SIGN_LANGUAGE_INTERPRETING u8\"\\uf2a3\"\n#define ICON_FA_BINOCULARS u8\"\\uf1e5\"\n#define ICON_FA_STICKY_NOTE u8\"\\uf249\"\n#define ICON_FA_RUNNING u8\"\\uf70c\"\n#define ICON_FA_PEN_NIB u8\"\\uf5ad\"\n#define ICON_FA_MAP_MARKED u8\"\\uf59f\"\n#define ICON_FA_EXPAND u8\"\\uf065\"\n#define ICON_FA_TRUCK_PICKUP u8\"\\uf63c\"\n#define ICON_FA_HOLLY_BERRY u8\"\\uf7aa\"\n#define ICON_FA_PRESCRIPTION_BOTTLE u8\"\\uf485\"\n#define ICON_FA_LAPTOP_CODE u8\"\\uf5fc\"\n#define ICON_FA_GOLF_BALL u8\"\\uf450\"\n#define ICON_FA_SKULL_CROSSBONES u8\"\\uf714\"\n#define ICON_FA_TAXI u8\"\\uf1ba\"\n#define ICON_FA_ROCKET u8\"\\uf135\"\n#define ICON_FA_YIN_YANG u8\"\\uf6ad\"\n#define ICON_FA_FINGERPRINT u8\"\\uf577\"\n#define ICON_FA_ARROWS_ALT u8\"\\uf0b2\"\n#define ICON_FA_UNDERLINE u8\"\\uf0cd\"\n#define ICON_FA_ARROW_CIRCLE_UP u8\"\\uf0aa\"\n#define ICON_FA_BASKETBALL_BALL u8\"\\uf434\"\n#define ICON_FA_DESKTOP u8\"\\uf108\"\n#define ICON_FA_SPINNER u8\"\\uf110\"\n#define ICON_FA_TOGGLE_ON u8\"\\uf205\"\n#define ICON_FA_STOPWATCH u8\"\\uf2f2\"\n#define ICON_FA_ARROW_ALT_CIRCLE_LEFT u8\"\\uf359\"\n#define ICON_FA_GAS_PUMP u8\"\\uf52f\"\n#define ICON_FA_EXTERNAL_LINK_ALT u8\"\\uf35d\"\n#define ICON_FA_FROWN u8\"\\uf119\"\n#define ICON_FA_RULER u8\"\\uf545\"\n#define ICON_FA_FLAG_USA u8\"\\uf74d\"\n#define ICON_FA_GRIN u8\"\\uf580\"\n#define ICON_FA_THEATER_MASKS u8\"\\uf630\"\n#define ICON_FA_ARROW_CIRCLE_LEFT u8\"\\uf0a8\"\n#define ICON_FA_HIGHLIGHTER u8\"\\uf591\"\n#define ICON_FA_POLL_H u8\"\\uf682\"\n#define ICON_FA_SERVER u8\"\\uf233\"\n#define ICON_FA_TRASH_RESTORE u8\"\\uf829\"\n#define ICON_FA_SPRAY_CAN u8\"\\uf5bd\"\n#define ICON_FA_BOWLING_BALL u8\"\\uf436\"\n#define ICON_FA_LAUGH u8\"\\uf599\"\n#define ICON_FA_TERMINAL u8\"\\uf120\"\n#define ICON_FA_WINDOW_MINIMIZE u8\"\\uf2d1\"\n#define ICON_FA_HOME u8\"\\uf015\"\n#define ICON_FA_UTENSIL_SPOON u8\"\\uf2e5\"\n#define ICON_FA_QUIDDITCH u8\"\\uf458\"\n#define ICON_FA_APPLE_ALT u8\"\\uf5d1\"\n#define ICON_FA_UMBRELLA_BEACH u8\"\\uf5ca\"\n#define ICON_FA_CANNABIS u8\"\\uf55f\"\n#define ICON_FA_LAUGH_BEAM u8\"\\uf59a\"\n#define ICON_FA_TEETH_OPEN u8\"\\uf62f\"\n#define ICON_FA_DRUMSTICK_BITE u8\"\\uf6d7\"\n#define ICON_FA_CHART_PIE u8\"\\uf200\"\n#define ICON_FA_SD_CARD u8\"\\uf7c2\"\n#define ICON_FA_HANDS_HELPING u8\"\\uf4c4\"\n#define ICON_FA_PASTE u8\"\\uf0ea\"\n#define ICON_FA_OM u8\"\\uf679\"\n#define ICON_FA_LUGGAGE_CART u8\"\\uf59d\"\n#define ICON_FA_INDUSTRY u8\"\\uf275\"\n#define ICON_FA_SWIMMER u8\"\\uf5c4\"\n#define ICON_FA_RADIATION_ALT u8\"\\uf7ba\"\n#define ICON_FA_COMPRESS_ARROWS_ALT u8\"\\uf78c\"\n#define ICON_FA_ROAD u8\"\\uf018\"\n#define ICON_FA_IMAGE u8\"\\uf03e\"\n#define ICON_FA_CHILD u8\"\\uf1ae\"\n#define ICON_FA_ANGLE_DOUBLE_RIGHT u8\"\\uf101\"\n#define ICON_FA_CLOUD_MOON_RAIN u8\"\\uf73c\"\n#define ICON_FA_DOOR_OPEN u8\"\\uf52b\"\n#define ICON_FA_GRIN_TONGUE_WINK u8\"\\uf58b\"\n#define ICON_FA_REPLY_ALL u8\"\\uf122\"\n#define ICON_FA_TEMPERATURE_LOW u8\"\\uf76b\"\n#define ICON_FA_INBOX u8\"\\uf01c\"\n#define ICON_FA_FEMALE u8\"\\uf182\"\n#define ICON_FA_SYRINGE u8\"\\uf48e\"\n#define ICON_FA_CIRCLE_NOTCH u8\"\\uf1ce\"\n#define ICON_FA_WEIGHT u8\"\\uf496\"\n#define ICON_FA_SNOWPLOW u8\"\\uf7d2\"\n#define ICON_FA_TABLE_TENNIS u8\"\\uf45d\"\n#define ICON_FA_LOW_VISION u8\"\\uf2a8\"\n#define ICON_FA_FILE_IMPORT u8\"\\uf56f\"\n#define ICON_FA_ITALIC u8\"\\uf033\"\n#define ICON_FA_CLOSED_CAPTIONING u8\"\\uf20a\"\n#define ICON_FA_CHALKBOARD u8\"\\uf51b\"\n#define ICON_FA_BUILDING u8\"\\uf1ad\"\n#define ICON_FA_TACHOMETER_ALT u8\"\\uf3fd\"\n#define ICON_FA_BUS u8\"\\uf207\"\n#define ICON_FA_ANGLE_DOWN u8\"\\uf107\"\n#define ICON_FA_HAND_ROCK u8\"\\uf255\"\n#define ICON_FA_FORWARD u8\"\\uf04e\"\n#define ICON_FA_HELICOPTER u8\"\\uf533\"\n#define ICON_FA_PODCAST u8\"\\uf2ce\"\n#define ICON_FA_TRUCK_MOVING u8\"\\uf4df\"\n#define ICON_FA_BUG u8\"\\uf188\"\n#define ICON_FA_SHIELD_ALT u8\"\\uf3ed\"\n#define ICON_FA_FILL_DRIP u8\"\\uf576\"\n#define ICON_FA_COMMENT_SLASH u8\"\\uf4b3\"\n#define ICON_FA_SUITCASE u8\"\\uf0f2\"\n#define ICON_FA_SKATING u8\"\\uf7c5\"\n#define ICON_FA_TOILET u8\"\\uf7d8\"\n#define ICON_FA_ENVELOPE_OPEN_TEXT u8\"\\uf658\"\n#define ICON_FA_HAND_HOLDING u8\"\\uf4bd\"\n#define ICON_FA_VENUS_MARS u8\"\\uf228\"\n#define ICON_FA_HEART_BROKEN u8\"\\uf7a9\"\n#define ICON_FA_UTENSILS u8\"\\uf2e7\"\n#define ICON_FA_TH_LARGE u8\"\\uf009\"\n#define ICON_FA_AT u8\"\\uf1fa\"\n#define ICON_FA_FILE u8\"\\uf15b\"\n#define ICON_FA_TENGE u8\"\\uf7d7\"\n#define ICON_FA_FLAG_CHECKERED u8\"\\uf11e\"\n#define ICON_FA_FILM u8\"\\uf008\"\n#define ICON_FA_FILL u8\"\\uf575\"\n#define ICON_FA_GRIN_SQUINT_TEARS u8\"\\uf586\"\n#define ICON_FA_PERCENT u8\"\\uf295\"\n#define ICON_FA_BOOK u8\"\\uf02d\"\n#define ICON_FA_METEOR u8\"\\uf753\"\n#define ICON_FA_TRASH u8\"\\uf1f8\"\n#define ICON_FA_FILE_AUDIO u8\"\\uf1c7\"\n#define ICON_FA_SATELLITE_DISH u8\"\\uf7c0\"\n#define ICON_FA_POOP u8\"\\uf619\"\n#define ICON_FA_STAR u8\"\\uf005\"\n#define ICON_FA_GIFTS u8\"\\uf79c\"\n#define ICON_FA_GHOST u8\"\\uf6e2\"\n#define ICON_FA_PRESCRIPTION_BOTTLE_ALT u8\"\\uf486\"\n#define ICON_FA_MONEY_BILL_WAVE_ALT u8\"\\uf53b\"\n#define ICON_FA_NEUTER u8\"\\uf22c\"\n#define ICON_FA_BAND_AID u8\"\\uf462\"\n#define ICON_FA_WIFI u8\"\\uf1eb\"\n#define ICON_FA_MASK u8\"\\uf6fa\"\n#define ICON_FA_VENUS_DOUBLE u8\"\\uf226\"\n#define ICON_FA_CHEVRON_UP u8\"\\uf077\"\n#define ICON_FA_HAND_SPOCK u8\"\\uf259\"\n#define ICON_FA_HAND_POINT_UP u8\"\\uf0a6\"\n"
  },
  {
    "path": "src/resource/MacOSXBundleInfo.plist.in",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>English</string>\n\t<key>CFBundleExecutable</key>\n\t<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>\n\t<key>CFBundleIconFile</key>\n\t<string>${MACOSX_BUNDLE_ICON_FILE}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>\n\t<key>CSResourcesFileMapped</key>\n\t<true/>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>${MACOSX_BUNDLE_COPYRIGHT}</string>\n    \t<key>LSApplicationCategoryType</key>\n    \t<string>${MACOSX_BUNDLE_CATEGORY}</string>\n     \t<key>LSMinimumSystemVersion</key>\n    \t<string>${MACOSX_MINIMUM_SYSTEM_VERSION}</string>\n\t<key>CFBundleLocalizations</key>\n\t<array>\n \t\t<string>ca</string>\n   \t\t<string>de</string>\n     \t\t<string>en</string>\n       \t\t<string>es</string>\n\t\t<string>fr</string>\n\t\t<string>he</string>\n\t\t<string>hu</string>\n\t\t<string>it</string>\n\t\t<string>ja</string>\n\t\t<string>ko</string>\n\t\t<string>nb</string>\n\t\t<string>nl</string>\n\t\t<string>pl</string>\n  \t\t<string>pt</string>\n\t\t<string>ru</string>\n  \t\t<string>sv</string>\n    \t\t<string>tr</string>\n      \t\t<string>uk</string>\n\t\t<string>zh</string>\n\t</array>\n     \t<key>CFBundleDocumentTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t<string>${MACOSX_BUNDLE_TYPE_EXTENSION}</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>Wii U File</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "src/resource/cemu.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#include \"resource/resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#include \"winres.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// Neutral (Default) (unknown sub-lang: 0x8) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ZZZ)\nLANGUAGE LANG_NEUTRAL, 0x8\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Icon\n//\n\n// Icon with lowest ID value placed first to ensure application icon\n// remains consistent on all systems.\nM_WND_ICON128           ICON                    \"resource\\\\logo_icon.ico\"\n\nM_WND_ICON16            ICON                    \"resource\\\\logo_icon16.ico\"\n\nX_INPUT_CONTROLLER      ICON                    \"resource\\\\input\\\\icons8-game-controller-24.ico\"\n\nX_BOX                   ICON                    \"resource\\\\icons8_cardboard_box_filled.ico\"\n\nX_SETTINGS              ICON                    \"resource\\\\icons8_automatic_26_xQK_icon.ico\"\n\nX_GAME_PROFILE          ICON                    \"resource\\\\icons8-compose-filled-50.ico\"\n\nX_HOTKEY_SETTINGS       ICON                    \"resource\\\\icons8_hotkeys.ico\"\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n1 TEXTINCLUDE \nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE \nBEGIN\n    \"#include \"\"afxres.h\"\"\\r\\n\"\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE \nBEGIN\n    \"\\r\\n\"\n    \"\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Version\n//\n\n#define xstr(s) str(s)\n#define str(s) #s\n\nVS_VERSION_INFO VERSIONINFO\nFILEVERSION        EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH, 0\nPRODUCTVERSION     EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH, 0\n FILEFLAGSMASK 0x3fL\n#ifdef _DEBUG\n FILEFLAGS 0x1L\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS 0x0L\n FILETYPE 0x1L\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904b0\"\n        BEGIN\n            VALUE \"FileDescription\", \"Cemu Wii U emulator\"\n            VALUE \"InternalName\", \"Cemu\"\n            VALUE \"LegalCopyright\", \"Team Cemu\"\n            VALUE \"OriginalFilename\", \"Cemu.exe\"\n            VALUE \"ProductName\", \"Cemu\"\n        \tVALUE \"ProductVersion\", xstr(EMULATOR_VERSION_MAJOR) \".\" xstr(EMULATOR_VERSION_MINOR) \".\" xstr(EMULATOR_VERSION_PATCH) EMULATOR_VERSION_SUFFIX \"\\0\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x409, 1200\n    END\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// RCDATA\n//\n\nIDR_FONTAWESOME         RCDATA                  \"resource\\\\fontawesome-webfont.ttf\"\n\n#endif    // Neutral (Default) (unknown sub-lang: 0x8) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n\n#ifndef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 3 resource.\n//\n\n\n/////////////////////////////////////////////////////////////////////////////\n#endif    // not APSTUDIO_INVOKED\n\n"
  },
  {
    "path": "src/resource/embedded/DEBUGGER_BP.hpng",
    "content": "unsigned char DEBUGGER_BP_png[436] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,\n\t0x0D, 0xD6, 0x00, 0x00, 0x0D, 0xD6, 0x01, 0x90, 0x6F, 0x79, 0x9C, 0x00,\n\t0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77,\n\t0x61, 0x72, 0x65, 0x00, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x2E, 0x6E, 0x65,\n\t0x74, 0x20, 0x34, 0x2E, 0x30, 0x2E, 0x32, 0x31, 0xF1, 0x20, 0x69, 0x95,\n\t0x00, 0x00, 0x01, 0x24, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0x8D, 0xD3,\n\t0xBB, 0x4A, 0x03, 0x51, 0x14, 0x46, 0xE1, 0x41, 0xBC, 0x82, 0xE9, 0xB4,\n\t0xF1, 0x92, 0x60, 0x95, 0x28, 0x5E, 0xB0, 0x0C, 0x82, 0xF8, 0x0E, 0x1A,\n\t0x7C, 0x82, 0xA8, 0x5D, 0x48, 0xBA, 0x84, 0x58, 0x59, 0xF8, 0x48, 0xD6,\n\t0xDA, 0x88, 0xA5, 0x42, 0x6C, 0xD4, 0x42, 0x34, 0x28, 0x88, 0xD8, 0x88,\n\t0x8A, 0x22, 0xB8, 0xD6, 0x90, 0x04, 0x8C, 0x19, 0x73, 0x7E, 0xF8, 0x60,\n\t0xF6, 0xC0, 0xCC, 0x9C, 0xB3, 0xCF, 0x9E, 0x28, 0x21, 0xA3, 0xD8, 0xC0,\n\t0x2E, 0x76, 0xB0, 0x86, 0x11, 0xF4, 0x4D, 0x0A, 0x87, 0x78, 0xC0, 0x1B,\n\t0x9E, 0x5B, 0xDE, 0x71, 0x8B, 0x7D, 0x8C, 0xA1, 0x67, 0x66, 0x71, 0x81,\n\t0x26, 0xFC, 0xF2, 0x14, 0x86, 0x30, 0x8C, 0x34, 0xCA, 0x78, 0xC2, 0x29,\n\t0x26, 0xF0, 0x2B, 0xE3, 0x38, 0xC7, 0x19, 0x26, 0xBD, 0x91, 0x90, 0x19,\n\t0xF8, 0x91, 0x63, 0xF8, 0xE2, 0x4E, 0x5C, 0xF6, 0x3D, 0xFE, 0x7B, 0xB8,\n\t0x9D, 0x0C, 0x5E, 0x50, 0x89, 0x2B, 0xE2, 0x9E, 0x1E, 0x51, 0x8C, 0xAB,\n\t0xB0, 0x54, 0x71, 0x83, 0x01, 0x8B, 0x75, 0xD8, 0xA4, 0x69, 0x8B, 0xC0,\n\t0x2C, 0xE2, 0x1B, 0xCB, 0x16, 0x7B, 0xB0, 0xD3, 0x83, 0x16, 0x81, 0xF1,\n\t0x48, 0x3F, 0xB1, 0x65, 0x61, 0xC7, 0x7D, 0x81, 0x1D, 0x0F, 0x8D, 0xDB,\n\t0xFE, 0xC2, 0xA6, 0x45, 0x1E, 0x1F, 0xF0, 0xA8, 0x42, 0xB3, 0x0A, 0xB7,\n\t0xB0, 0x60, 0xE1, 0x72, 0xEE, 0x50, 0xB2, 0x08, 0xCC, 0x01, 0x2E, 0x11,\n\t0x37, 0xD1, 0xD4, 0xE1, 0x90, 0x38, 0x4C, 0xFD, 0x92, 0xC3, 0x2B, 0xEC,\n\t0x5D, 0x27, 0xEE, 0xC9, 0x09, 0x73, 0x48, 0xE6, 0xBC, 0x91, 0x90, 0x2C,\n\t0xAE, 0x70, 0x84, 0x3F, 0x4D, 0x77, 0x88, 0x4E, 0xE0, 0x90, 0xD4, 0xE0,\n\t0xFE, 0x9C, 0x36, 0x7F, 0xAC, 0x15, 0xB8, 0x6C, 0xBF, 0xEC, 0xC3, 0xFE,\n\t0x33, 0x3D, 0xE3, 0x03, 0xCE, 0xFC, 0x35, 0x6C, 0x92, 0x47, 0x65, 0xB7,\n\t0xBD, 0x6E, 0xC0, 0x65, 0x07, 0x1D, 0xB7, 0xCD, 0x59, 0xC2, 0x36, 0x0A,\n\t0x98, 0x6F, 0xDD, 0xEB, 0x4A, 0x14, 0xFD, 0x00, 0x3A, 0xD0, 0x36, 0x27,\n\t0xE1, 0xFD, 0x9A, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44,\n\t0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/DEBUGGER_BP_RED.hpng",
    "content": "unsigned char DEBUGGER_BP_RED_png[470] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00,\n\t0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61,\n\t0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0D,\n\t0xD5, 0x00, 0x00, 0x0D, 0xD5, 0x01, 0x3D, 0xD6, 0x58, 0xF1, 0x00, 0x00,\n\t0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61,\n\t0x72, 0x65, 0x00, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x2E, 0x6E, 0x65, 0x74,\n\t0x20, 0x34, 0x2E, 0x30, 0x2E, 0x32, 0x31, 0xF1, 0x20, 0x69, 0x95, 0x00,\n\t0x00, 0x01, 0x53, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0xA5, 0x93, 0xBD,\n\t0x2F, 0x04, 0x51, 0x14, 0xC5, 0x8F, 0x8F, 0x58, 0x12, 0x3A, 0x0A, 0x85,\n\t0x44, 0x25, 0x21, 0xA1, 0x23, 0x11, 0x89, 0x48, 0x24, 0x12, 0xB5, 0x15,\n\t0xAD, 0xCA, 0x6E, 0x4B, 0x4D, 0xBD, 0x7F, 0x8B, 0x52, 0xA5, 0x52, 0x90,\n\t0xC8, 0xD6, 0x24, 0x54, 0x14, 0xA2, 0xA0, 0x43, 0x7C, 0x16, 0xCC, 0xFA,\n\t0x9D, 0xF9, 0x48, 0xC6, 0x78, 0x63, 0x0A, 0x37, 0xF9, 0x65, 0x5F, 0xE6,\n\t0xDD, 0xF3, 0xDE, 0xBB, 0xF7, 0xDC, 0x55, 0x49, 0xF4, 0xC3, 0x12, 0x34,\n\t0x60, 0x0B, 0x16, 0xA0, 0x06, 0x95, 0x31, 0x04, 0xAD, 0x5E, 0xE9, 0x6E,\n\t0x42, 0x8A, 0x56, 0xA4, 0x8E, 0x19, 0x67, 0xDD, 0x23, 0xDD, 0xB0, 0xB7,\n\t0x07, 0x03, 0x4E, 0x0C, 0xC5, 0x58, 0x97, 0x74, 0xBE, 0x4C, 0xF2, 0xA9,\n\t0xF4, 0xF5, 0x0E, 0x1D, 0xC4, 0xE6, 0x8D, 0xF5, 0x11, 0xF0, 0x8C, 0x88,\n\t0xBC, 0x36, 0x0C, 0xC7, 0x8A, 0x5C, 0x0C, 0x22, 0x3E, 0xDB, 0x94, 0x3E,\n\t0x3F, 0x48, 0xCA, 0x84, 0x45, 0x5E, 0xD9, 0x5B, 0x23, 0x87, 0xFC, 0x63,\n\t0xE8, 0x8B, 0x95, 0x69, 0xB4, 0x7C, 0xF3, 0x5F, 0xE2, 0x8C, 0x17, 0x72,\n\t0x66, 0x01, 0xCD, 0x4E, 0x22, 0xA5, 0x26, 0x6A, 0xBE, 0xF7, 0xB3, 0x43,\n\t0x82, 0x10, 0x07, 0xE4, 0xF2, 0xE2, 0x6B, 0xB4, 0xDD, 0x3E, 0x60, 0xD1,\n\t0x0D, 0xCB, 0xD7, 0x5C, 0xC5, 0x33, 0x65, 0x8C, 0xF2, 0x8B, 0x76, 0xC6,\n\t0x07, 0x34, 0xDD, 0xE9, 0x62, 0x52, 0x15, 0x73, 0x80, 0xB6, 0xEE, 0x03,\n\t0x1A, 0xFF, 0x38, 0x80, 0x9E, 0x4A, 0xF3, 0xF6, 0xD9, 0x56, 0x15, 0x93,\n\t0xCA, 0x78, 0xA4, 0x04, 0x7C, 0x64, 0xA9, 0x29, 0x1F, 0x50, 0x63, 0x48,\n\t0x6E, 0xED, 0x73, 0x31, 0xB1, 0x8C, 0xFD, 0xA4, 0x89, 0x97, 0x68, 0xE3,\n\t0x26, 0x3A, 0x76, 0x3D, 0x24, 0xF6, 0x39, 0x24, 0xC8, 0xC3, 0xED, 0x11,\n\t0x9D, 0xB3, 0x8D, 0xCD, 0x44, 0x9A, 0x84, 0xC7, 0xB3, 0xED, 0x21, 0xB1,\n\t0xCF, 0x21, 0xA1, 0x79, 0x60, 0x6F, 0x35, 0x19, 0xA4, 0x43, 0xC0, 0xFD,\n\t0x9F, 0x31, 0x02, 0x27, 0x1E, 0x12, 0xFB, 0x6C, 0xAB, 0x32, 0xE1, 0x13,\n\t0x6B, 0x3F, 0x3B, 0xBD, 0xD9, 0x62, 0xFF, 0x67, 0x82, 0xE1, 0xF1, 0xDC,\n\t0xA6, 0xBE, 0x2B, 0xFB, 0xEC, 0x4E, 0x1B, 0x37, 0x8C, 0x6F, 0x17, 0xEC,\n\t0xF9, 0xD9, 0xBF, 0x6E, 0x0E, 0x85, 0x9B, 0x33, 0x0D, 0x1B, 0xB0, 0x0E,\n\t0x93, 0xE9, 0xB7, 0x42, 0x48, 0xDF, 0x8F, 0x4C, 0x23, 0xE8, 0x8D, 0x9D,\n\t0x99, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42,\n\t0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/DEBUGGER_GOTO.hpng",
    "content": "unsigned char DEBUGGER_GOTO_png[292] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,\n\t0x15, 0x9F, 0x00, 0x00, 0x15, 0x9F, 0x01, 0xDF, 0x87, 0xF6, 0x15, 0x00,\n\t0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77,\n\t0x61, 0x72, 0x65, 0x00, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x2E, 0x6E, 0x65,\n\t0x74, 0x20, 0x34, 0x2E, 0x30, 0x2E, 0x32, 0x31, 0xF1, 0x20, 0x69, 0x95,\n\t0x00, 0x00, 0x00, 0x94, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0xCD, 0xD0,\n\t0xB1, 0x0A, 0x82, 0x50, 0x18, 0x86, 0xE1, 0x63, 0x8E, 0x4E, 0x41, 0xE0,\n\t0x20, 0xDA, 0x8D, 0xB4, 0x05, 0x8E, 0xDE, 0x83, 0x4B, 0xD7, 0xA0, 0x82,\n\t0xE0, 0xE2, 0x50, 0x50, 0xF7, 0xD3, 0x20, 0x82, 0x93, 0x88, 0x5B, 0xD4,\n\t0xF5, 0xF8, 0xFE, 0x83, 0x20, 0x28, 0x9D, 0xE3, 0x20, 0xF8, 0xC2, 0xB3,\n\t0x79, 0x3E, 0xF0, 0x57, 0xBB, 0x2A, 0xC2, 0xCB, 0x50, 0x88, 0x59, 0x4F,\n\t0xBC, 0x91, 0x69, 0x54, 0xC8, 0x31, 0x4B, 0x06, 0xE4, 0x03, 0x5D, 0x05,\n\t0xB6, 0x1D, 0x38, 0x22, 0x86, 0x85, 0x31, 0x1B, 0x37, 0x38, 0xD0, 0x0E,\n\t0xF8, 0xF8, 0x21, 0x81, 0x74, 0xC0, 0x03, 0x3D, 0x4E, 0x30, 0xFA, 0x85,\n\t0x33, 0xBE, 0x48, 0x71, 0x47, 0x07, 0x17, 0x92, 0xF1, 0x0D, 0x02, 0x7C,\n\t0xD0, 0x62, 0x7C, 0x2C, 0xAD, 0x3A, 0xA2, 0x87, 0xE9, 0x63, 0x69, 0xD5,\n\t0xC0, 0x52, 0x7F, 0x07, 0x6A, 0x94, 0x1A, 0x0D, 0x16, 0x07, 0xAE, 0x90,\n\t0xA3, 0x99, 0xB8, 0x60, 0x17, 0x29, 0x35, 0x00, 0xD4, 0x45, 0x31, 0x14,\n\t0xD0, 0x14, 0xF5, 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44,\n\t0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/DEBUGGER_PAUSE.hpng",
    "content": "unsigned char DEBUGGER_PAUSE_png[211] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,\n\t0x0D, 0xD6, 0x00, 0x00, 0x0D, 0xD6, 0x01, 0x90, 0x6F, 0x79, 0x9C, 0x00,\n\t0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77,\n\t0x61, 0x72, 0x65, 0x00, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x2E, 0x6E, 0x65,\n\t0x74, 0x20, 0x34, 0x2E, 0x30, 0x2E, 0x32, 0x31, 0xF1, 0x20, 0x69, 0x95,\n\t0x00, 0x00, 0x00, 0x43, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0x63, 0x18,\n\t0x74, 0x40, 0x04, 0x88, 0x6B, 0x91, 0x30, 0x23, 0x10, 0xB3, 0xA2, 0x89,\n\t0x71, 0x01, 0x31, 0x4E, 0xA0, 0x09, 0xC4, 0xFF, 0x91, 0x30, 0x13, 0x10,\n\t0x83, 0x34, 0x20, 0x8B, 0x89, 0x02, 0x31, 0x4E, 0x30, 0x6A, 0xC0, 0xA8,\n\t0x01, 0x20, 0x40, 0xB1, 0x01, 0x42, 0x40, 0x5C, 0x80, 0x84, 0x61, 0x49,\n\t0x19, 0x59, 0x8C, 0x13, 0x88, 0x07, 0x0D, 0x60, 0x60, 0x00, 0x00, 0x3F,\n\t0x28, 0x44, 0x7C, 0x76, 0x8B, 0xE1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x49,\n\t0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/DEBUGGER_PLAY.hpng",
    "content": "unsigned char DEBUGGER_PLAY_png[306] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,\n\t0x0D, 0xD6, 0x00, 0x00, 0x0D, 0xD6, 0x01, 0x90, 0x6F, 0x79, 0x9C, 0x00,\n\t0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77,\n\t0x61, 0x72, 0x65, 0x00, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x2E, 0x6E, 0x65,\n\t0x74, 0x20, 0x34, 0x2E, 0x30, 0x2E, 0x32, 0x31, 0xF1, 0x20, 0x69, 0x95,\n\t0x00, 0x00, 0x00, 0xA2, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0xBD, 0xCF,\n\t0xB1, 0x0A, 0x82, 0x40, 0x1C, 0xC7, 0xF1, 0x0B, 0x85, 0x68, 0x15, 0x72,\n\t0x6C, 0x70, 0xEC, 0x19, 0xA2, 0x07, 0x68, 0xF2, 0x09, 0xDA, 0x7A, 0x05,\n\t0xC7, 0x1E, 0xA0, 0x37, 0x70, 0xF5, 0x35, 0xDA, 0xDB, 0x5A, 0x1A, 0x82,\n\t0x68, 0x68, 0x72, 0x72, 0x6A, 0x69, 0x8A, 0xF2, 0xAB, 0xF9, 0x87, 0x88,\n\t0xEB, 0x4E, 0x0F, 0xF1, 0x0B, 0x1F, 0xBC, 0x5B, 0x7E, 0x78, 0xAA, 0xEF,\n\t0x22, 0x8C, 0x3E, 0x47, 0xB7, 0x2E, 0x48, 0x31, 0xAD, 0x6F, 0x0E, 0xDD,\n\t0xF0, 0x46, 0x81, 0x0D, 0xC6, 0xE8, 0x94, 0x0C, 0x88, 0x23, 0x96, 0x68,\n\t0xFD, 0xAC, 0xDF, 0x81, 0xCA, 0x13, 0x19, 0x66, 0xB0, 0xA6, 0x1B, 0x10,\n\t0x77, 0x24, 0x30, 0x3E, 0xCB, 0x34, 0x20, 0xCE, 0x58, 0x41, 0x9B, 0x6D,\n\t0xE0, 0x85, 0x03, 0x16, 0xD0, 0x66, 0x1A, 0xC8, 0xB1, 0x86, 0x8F, 0xBF,\n\t0xE9, 0x06, 0x1E, 0xD8, 0x21, 0x80, 0xB5, 0xEF, 0x81, 0xEA, 0x77, 0xF7,\n\t0x98, 0xA3, 0x75, 0x32, 0x70, 0x45, 0x0C, 0x0F, 0x9D, 0x3A, 0x61, 0x8B,\n\t0x49, 0x7D, 0x73, 0x28, 0x6C, 0xBE, 0x43, 0xA5, 0x54, 0x09, 0x70, 0x17,\n\t0x44, 0x3D, 0x8C, 0x39, 0x0C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,\n\t0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/DEBUGGER_STEP_INTO.hpng",
    "content": "unsigned char DEBUGGER_STEP_INTO_png[297] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,\n\t0x15, 0x9F, 0x00, 0x00, 0x15, 0x9F, 0x01, 0xDF, 0x87, 0xF6, 0x15, 0x00,\n\t0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77,\n\t0x61, 0x72, 0x65, 0x00, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x2E, 0x6E, 0x65,\n\t0x74, 0x20, 0x34, 0x2E, 0x30, 0x2E, 0x32, 0x31, 0xF1, 0x20, 0x69, 0x95,\n\t0x00, 0x00, 0x00, 0x99, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0xD5, 0xD2,\n\t0x3B, 0x0A, 0xC2, 0x40, 0x14, 0x46, 0xE1, 0x91, 0xF8, 0xC0, 0x57, 0x2A,\n\t0x0D, 0xB8, 0x8B, 0xAC, 0x4C, 0x6C, 0xAC, 0xAC, 0xEC, 0x44, 0xB0, 0x8A,\n\t0xBD, 0x75, 0x5A, 0x37, 0x92, 0x2A, 0xB5, 0xBD, 0xB5, 0x60, 0x9B, 0xF3,\n\t0x83, 0x03, 0x97, 0x44, 0x70, 0x62, 0xA3, 0x39, 0xF0, 0x35, 0x33, 0x64,\n\t0x32, 0x24, 0xD7, 0xFD, 0x55, 0x53, 0x2C, 0xDF, 0x18, 0x23, 0xA8, 0x1D,\n\t0x6E, 0x35, 0x77, 0x6C, 0x10, 0xD4, 0x00, 0x93, 0x9A, 0x13, 0xB6, 0xF8,\n\t0xBA, 0x03, 0x3A, 0x7A, 0x40, 0x8A, 0x33, 0xF4, 0x0D, 0xF6, 0xB8, 0x60,\n\t0x85, 0xE0, 0x62, 0x5C, 0xF1, 0xC0, 0x13, 0x19, 0x86, 0x68, 0x95, 0xFE,\n\t0x7F, 0x8E, 0x23, 0xFA, 0x5A, 0xF8, 0xD4, 0x0C, 0xC9, 0xCB, 0x42, 0x0B,\n\t0xA4, 0xB7, 0x46, 0xE8, 0x41, 0x43, 0xE5, 0xF7, 0x35, 0x74, 0x8D, 0xEC,\n\t0x20, 0x15, 0xD0, 0x83, 0xBE, 0x39, 0x4A, 0xF8, 0xFD, 0x35, 0x1A, 0xE9,\n\t0x9A, 0x23, 0xC3, 0xA6, 0x1B, 0xD8, 0x3D, 0x7B, 0xF8, 0x4F, 0x73, 0xAE,\n\t0x02, 0x87, 0x0E, 0x17, 0xF0, 0xCD, 0xD1, 0x7E, 0x32, 0x00, 0x00, 0x00,\n\t0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/DEBUGGER_STEP_OUT.hpng",
    "content": "unsigned char DEBUGGER_STEP_OUT_png[308] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,\n\t0x15, 0x9F, 0x00, 0x00, 0x15, 0x9F, 0x01, 0xDF, 0x87, 0xF6, 0x15, 0x00,\n\t0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77,\n\t0x61, 0x72, 0x65, 0x00, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x2E, 0x6E, 0x65,\n\t0x74, 0x20, 0x34, 0x2E, 0x30, 0x2E, 0x32, 0x31, 0xF1, 0x20, 0x69, 0x95,\n\t0x00, 0x00, 0x00, 0xA4, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0x63, 0xA0,\n\t0x37, 0x90, 0x01, 0x62, 0x2E, 0x08, 0x93, 0x3C, 0x30, 0x01, 0x88, 0x37,\n\t0x00, 0x31, 0x07, 0x98, 0x47, 0x04, 0xF0, 0x00, 0xE2, 0x36, 0x24, 0xDC,\n\t0x0B, 0xC4, 0xDF, 0x80, 0x78, 0x39, 0x10, 0xB3, 0x00, 0x31, 0x41, 0xD0,\n\t0x01, 0xC4, 0xDB, 0x81, 0xB8, 0x1A, 0x8A, 0x9B, 0x81, 0xF8, 0x23, 0x10,\n\t0x83, 0x0C, 0x60, 0x06, 0x62, 0x82, 0x00, 0x64, 0x40, 0x29, 0x84, 0x09,\n\t0x06, 0x30, 0x2F, 0xB0, 0x81, 0x79, 0x44, 0x00, 0x74, 0x03, 0xA4, 0x81,\n\t0x98, 0x68, 0xFF, 0x83, 0x00, 0xBA, 0x01, 0x24, 0x83, 0x81, 0x37, 0xA0,\n\t0x16, 0x88, 0xB3, 0x21, 0x4C, 0xC2, 0x80, 0x07, 0x88, 0xC5, 0xA0, 0x58,\n\t0x04, 0x24, 0x00, 0x04, 0xA0, 0xD0, 0x66, 0x05, 0x62, 0x46, 0x20, 0x16,\n\t0x05, 0x62, 0x98, 0x3C, 0x37, 0x10, 0x63, 0x00, 0x50, 0x3C, 0xDF, 0x87,\n\t0xE2, 0xF3, 0x40, 0x8C, 0x1C, 0xCF, 0xBC, 0x40, 0x7C, 0x15, 0x88, 0x61,\n\t0xF2, 0x79, 0x40, 0x8C, 0x01, 0x40, 0x29, 0x8B, 0x1D, 0x09, 0x23, 0x03,\n\t0x90, 0x0B, 0x90, 0xE5, 0x88, 0x4A, 0x44, 0xF4, 0x00, 0x0C, 0x0C, 0x00,\n\t0xA1, 0x3A, 0x17, 0xFB, 0x69, 0xBB, 0x81, 0x1D, 0x00, 0x00, 0x00, 0x00,\n\t0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/DEBUGGER_STEP_OVER.hpng",
    "content": "unsigned char DEBUGGER_STEP_OVER_png[296] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,\n\t0x15, 0x9F, 0x00, 0x00, 0x15, 0x9F, 0x01, 0xDF, 0x87, 0xF6, 0x15, 0x00,\n\t0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77,\n\t0x61, 0x72, 0x65, 0x00, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x2E, 0x6E, 0x65,\n\t0x74, 0x20, 0x34, 0x2E, 0x30, 0x2E, 0x32, 0x31, 0xF1, 0x20, 0x69, 0x95,\n\t0x00, 0x00, 0x00, 0x98, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0x63, 0x18,\n\t0x54, 0x80, 0x1B, 0x88, 0x45, 0x89, 0xC0, 0x42, 0x40, 0xCC, 0x08, 0xC4,\n\t0x18, 0xA0, 0x1D, 0x88, 0x5F, 0x02, 0xF1, 0x7D, 0x3C, 0xF8, 0x21, 0x10,\n\t0xDF, 0x04, 0x62, 0x36, 0x20, 0xC6, 0x00, 0xBD, 0x40, 0x5C, 0x0F, 0xC4,\n\t0x5C, 0x78, 0xB0, 0x12, 0x10, 0xDF, 0x01, 0x62, 0x9C, 0x06, 0x54, 0x41,\n\t0x98, 0x38, 0x81, 0x24, 0x10, 0x0F, 0x51, 0x03, 0x98, 0x80, 0xB8, 0x07,\n\t0x88, 0x43, 0x80, 0x18, 0x64, 0x40, 0x24, 0x10, 0x17, 0x02, 0x31, 0x0A,\n\t0x20, 0xE4, 0x02, 0x2F, 0x20, 0x7E, 0x03, 0xC4, 0x3F, 0x81, 0x18, 0x14,\n\t0x1B, 0x06, 0x40, 0x8C, 0x02, 0x2C, 0x80, 0xD8, 0x10, 0xC2, 0xC4, 0x09,\n\t0x1C, 0x81, 0xF8, 0x0A, 0x10, 0x6B, 0x83, 0x79, 0x78, 0x00, 0xC8, 0xC9,\n\t0x62, 0x48, 0x18, 0x14, 0x85, 0x30, 0xC0, 0x01, 0xA5, 0xF1, 0x02, 0x01,\n\t0x20, 0x06, 0xF9, 0x15, 0x96, 0x80, 0x92, 0x81, 0x98, 0x24, 0x00, 0x4A,\n\t0xAA, 0xEC, 0x48, 0x98, 0x19, 0x88, 0x07, 0x25, 0x60, 0x60, 0x00, 0x00,\n\t0xBC, 0xCF, 0x1F, 0x7C, 0xB2, 0x98, 0xCD, 0xAE, 0x00, 0x00, 0x00, 0x00,\n\t0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/INPUT_CONNECTED.hpng",
    "content": "unsigned char INPUT_CONNECTED_png[400] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,\n\t0x1A, 0x9D, 0x00, 0x00, 0x1A, 0x9D, 0x01, 0x5D, 0x6D, 0x02, 0x48, 0x00,\n\t0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77,\n\t0x61, 0x72, 0x65, 0x00, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x2E, 0x6E, 0x65,\n\t0x74, 0x20, 0x34, 0x2E, 0x30, 0x2E, 0x32, 0x31, 0xF1, 0x20, 0x69, 0x95,\n\t0x00, 0x00, 0x01, 0x00, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0x9D, 0xD3,\n\t0xBB, 0x6A, 0x02, 0x41, 0x18, 0x86, 0xE1, 0x8D, 0xA7, 0x5B, 0xF0, 0x0E,\n\t0x24, 0x08, 0xDA, 0x59, 0x05, 0x3C, 0xB4, 0x96, 0x31, 0x45, 0x6E, 0x40,\n\t0xAC, 0x3D, 0x91, 0x2A, 0x88, 0x58, 0xD8, 0x0A, 0x16, 0xDE, 0x91, 0x58,\n\t0x0B, 0x29, 0x03, 0x16, 0x49, 0x13, 0x0F, 0x9D, 0x07, 0x3C, 0xBF, 0x9F,\n\t0x38, 0xB0, 0xB8, 0xB3, 0x2B, 0xF1, 0x83, 0xA7, 0x98, 0x65, 0xFF, 0x99,\n\t0xD9, 0xF9, 0x67, 0x9D, 0x07, 0xF3, 0x84, 0x2A, 0x26, 0x97, 0xD1, 0x3F,\n\t0x13, 0xC2, 0x07, 0x56, 0x28, 0xE9, 0x41, 0x50, 0xB4, 0xD2, 0x0B, 0xFA,\n\t0x18, 0xA0, 0x88, 0x26, 0x54, 0xFC, 0x06, 0x6B, 0xC2, 0xC8, 0x22, 0x8A,\n\t0x0E, 0x76, 0x38, 0x5D, 0x1D, 0xB1, 0xC5, 0x3B, 0xAC, 0x89, 0x20, 0x89,\n\t0x3F, 0x8C, 0xA1, 0x02, 0x53, 0x6C, 0x1C, 0x90, 0x81, 0x35, 0x5A, 0x79,\n\t0x8A, 0x3A, 0x66, 0xB8, 0x2D, 0x36, 0xDA, 0xB0, 0x26, 0x86, 0x2F, 0xCC,\n\t0x11, 0x34, 0xC9, 0x27, 0x3C, 0xD1, 0x81, 0x75, 0x61, 0xB6, 0xBD, 0x80,\n\t0x5A, 0xA5, 0xC9, 0xDC, 0xC5, 0x1B, 0x3C, 0xC3, 0x93, 0x1C, 0xF6, 0x70,\n\t0xBF, 0xAC, 0x1D, 0xA8, 0x65, 0xFA, 0x2C, 0x8D, 0x75, 0xA0, 0x15, 0x58,\n\t0xD3, 0x83, 0xBB, 0xD8, 0xD0, 0x24, 0x0D, 0x68, 0x47, 0x23, 0xA8, 0x3B,\n\t0xD6, 0xF8, 0x4D, 0x20, 0xFA, 0x8C, 0x1A, 0x7E, 0x91, 0x82, 0x35, 0x79,\n\t0xA8, 0x45, 0xB7, 0xC5, 0xDA, 0xF6, 0x10, 0x3F, 0x88, 0x43, 0x67, 0xE5,\n\t0x89, 0x1E, 0x6A, 0x9B, 0x7A, 0xD9, 0xDD, 0xFB, 0x35, 0xCA, 0xD0, 0xFD,\n\t0x48, 0xC3, 0xB7, 0x58, 0xD7, 0x73, 0x09, 0xDD, 0xB0, 0x02, 0xD4, 0x8D,\n\t0x16, 0x12, 0xB8, 0x1B, 0xAD, 0xAC, 0x95, 0x5E, 0x2F, 0xA3, 0x07, 0xF2,\n\t0x0D, 0xDF, 0x1F, 0x23, 0x38, 0x8E, 0x73, 0x06, 0xFB, 0x36, 0x5D, 0xD3,\n\t0x1C, 0xAF, 0x1A, 0x69, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44,\n\t0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/INPUT_DISCONNECTED.hpng",
    "content": "unsigned char INPUT_DISCONNECTED_png[410] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x1F, 0xF3, 0xFF, 0x61, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,\n\t0x1C, 0xD5, 0x00, 0x00, 0x1C, 0xD5, 0x01, 0xE1, 0x9B, 0x06, 0xCC, 0x00,\n\t0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77,\n\t0x61, 0x72, 0x65, 0x00, 0x70, 0x61, 0x69, 0x6E, 0x74, 0x2E, 0x6E, 0x65,\n\t0x74, 0x20, 0x34, 0x2E, 0x30, 0x2E, 0x32, 0x31, 0xF1, 0x20, 0x69, 0x95,\n\t0x00, 0x00, 0x01, 0x0A, 0x49, 0x44, 0x41, 0x54, 0x38, 0x4F, 0xB5, 0xD3,\n\t0x31, 0x4B, 0x42, 0x51, 0x18, 0xC6, 0xF1, 0x93, 0xA6, 0x10, 0xE2, 0xD0,\n\t0x52, 0x5F, 0x20, 0x08, 0x0B, 0x72, 0xCC, 0xA1, 0x31, 0xDA, 0x5B, 0x1B,\n\t0x05, 0x97, 0x08, 0x1D, 0xDB, 0xA3, 0x86, 0x86, 0xD4, 0xA5, 0x4D, 0x90,\n\t0xC6, 0x70, 0x70, 0x14, 0xFD, 0x00, 0x8E, 0xF5, 0x0D, 0x04, 0x45, 0x9A,\n\t0x42, 0x5C, 0x1D, 0x4C, 0xFF, 0x8F, 0xF6, 0x5E, 0xAF, 0x77, 0x38, 0x38,\n\t0xE8, 0x03, 0x3F, 0xB8, 0xF7, 0xC0, 0x7D, 0x38, 0xE7, 0xF5, 0xE8, 0x76,\n\t0x9D, 0x18, 0x8E, 0x50, 0xC7, 0x23, 0xE2, 0xFF, 0x6B, 0xF7, 0xD0, 0xBA,\n\t0x37, 0x37, 0xF8, 0xC4, 0x37, 0x66, 0xF8, 0x43, 0x15, 0x4F, 0x98, 0xE0,\n\t0x16, 0xDE, 0xE4, 0x30, 0x82, 0x3E, 0x36, 0x2A, 0x99, 0x22, 0x8F, 0x8D,\n\t0xF2, 0x80, 0x70, 0x81, 0x95, 0x54, 0xA0, 0xA3, 0x78, 0x73, 0x85, 0x31,\n\t0x5A, 0xF8, 0x45, 0xB4, 0xA4, 0x84, 0xB5, 0x5C, 0x23, 0xB3, 0x7C, 0x5C,\n\t0xE4, 0x1D, 0x0D, 0x24, 0xA1, 0xB2, 0xE8, 0x71, 0x5E, 0x10, 0x64, 0x1F,\n\t0x6D, 0x0C, 0x71, 0xAE, 0x05, 0xA2, 0x89, 0xEB, 0x63, 0xE5, 0x10, 0x5F,\n\t0xB0, 0x8F, 0xB5, 0xAB, 0x14, 0x82, 0x1C, 0xC3, 0xA6, 0x3D, 0xC0, 0x19,\n\t0x2C, 0x69, 0x74, 0xD1, 0xC3, 0x1D, 0x74, 0xAC, 0x1A, 0xF6, 0x10, 0xE4,\n\t0x03, 0xD6, 0x2E, 0x7D, 0xD8, 0x71, 0x12, 0x78, 0xC5, 0xC9, 0xE2, 0xCD,\n\t0xB9, 0x4B, 0x64, 0x97, 0x8F, 0xAB, 0xE8, 0x92, 0x68, 0x30, 0xE1, 0x12,\n\t0xED, 0x24, 0x3C, 0x13, 0x6F, 0x74, 0xDE, 0x32, 0xA2, 0x25, 0x3F, 0xD8,\n\t0xA8, 0x44, 0xBF, 0xA9, 0xA6, 0x1A, 0x2D, 0x10, 0x0D, 0xF6, 0x14, 0xDE,\n\t0xE8, 0x6E, 0xEB, 0x7A, 0x16, 0xF0, 0x06, 0x2B, 0xEA, 0xA0, 0x89, 0x0B,\n\t0x78, 0xA3, 0x3F, 0x86, 0xDD, 0x6D, 0xED, 0xA6, 0x88, 0x67, 0x1C, 0x60,\n\t0x6D, 0xDA, 0x5B, 0x8E, 0x73, 0x73, 0x3A, 0xF1, 0x4C, 0x89, 0x76, 0x54,\n\t0xC3, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42,\n\t0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/INPUT_LOW_BATTERY.hpng",
    "content": "unsigned char INPUT_LOW_BATTERY_png[340] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1E,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x3B, 0x30, 0xAE, 0xA2, 0x00, 0x00, 0x00,\n\t0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00,\n\t0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC,\n\t0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00,\n\t0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7, 0x6F, 0xA8, 0x64, 0x00,\n\t0x00, 0x00, 0xE9, 0x49, 0x44, 0x41, 0x54, 0x48, 0x4B, 0xED, 0xD4, 0xB1,\n\t0x0A, 0x01, 0x71, 0x1C, 0xC0, 0xF1, 0x63, 0xB0, 0x50, 0x32, 0x48, 0x19,\n\t0x24, 0x2F, 0x22, 0x92, 0x3C, 0x83, 0x32, 0x7A, 0x01, 0x93, 0xE2, 0x01,\n\t0x8C, 0x26, 0x1B, 0x8B, 0x78, 0x05, 0x83, 0xDD, 0x43, 0x28, 0x83, 0xC5,\n\t0xA2, 0xA4, 0x98, 0x24, 0x7C, 0x7F, 0xFF, 0xBB, 0xAB, 0xEB, 0xEE, 0xB2,\n\t0xDC, 0xFF, 0x6E, 0xB8, 0xFE, 0xDF, 0xFA, 0xD4, 0xFF, 0xEF, 0xAE, 0xFB,\n\t0xF5, 0xBF, 0x2B, 0x96, 0xC9, 0x94, 0xFA, 0x72, 0x28, 0x69, 0xF6, 0xB7,\n\t0x22, 0xB6, 0x78, 0xE1, 0xAB, 0xD9, 0x15, 0x43, 0x84, 0xB6, 0x84, 0xDC,\n\t0xF4, 0xC4, 0x49, 0xA3, 0x33, 0x3E, 0x8E, 0x26, 0x02, 0xDD, 0xF0, 0x46,\n\t0x55, 0xED, 0xF4, 0x36, 0x86, 0x1C, 0x6A, 0xAE, 0x76, 0xBE, 0xE4, 0xC2,\n\t0xDD, 0x5E, 0x5A, 0x59, 0x34, 0x1C, 0x35, 0xF9, 0x21, 0x62, 0x7D, 0xC8,\n\t0xF3, 0x37, 0x6A, 0xE7, 0xCB, 0x3B, 0x58, 0xBE, 0xB7, 0xEC, 0x85, 0xBC,\n\t0xAA, 0xA8, 0x79, 0x07, 0x17, 0x50, 0x47, 0x06, 0xAA, 0xA4, 0x06, 0xBB,\n\t0xEB, 0x09, 0x54, 0x49, 0x0F, 0x5E, 0x40, 0x65, 0x06, 0xC7, 0x35, 0xB8,\n\t0x87, 0x03, 0x5A, 0x50, 0x79, 0x07, 0xE7, 0xB1, 0x77, 0xC8, 0xCD, 0x51,\n\t0xF3, 0x0E, 0x0E, 0x24, 0xFF, 0x2C, 0x0F, 0x7B, 0xA9, 0x3D, 0x77, 0xF0,\n\t0x5A, 0xED, 0x7C, 0x1D, 0x21, 0x17, 0x47, 0xE8, 0x68, 0xD4, 0xC5, 0x0E,\n\t0xF2, 0xEC, 0x29, 0x02, 0x0D, 0x20, 0xA7, 0x96, 0x1B, 0xE2, 0x70, 0x41,\n\t0x19, 0xA1, 0xB5, 0xB1, 0x82, 0xFB, 0x7D, 0x75, 0x90, 0xD3, 0xCE, 0x50,\n\t0x81, 0xC9, 0x64, 0x4A, 0x55, 0x96, 0xF5, 0x03, 0x93, 0x37, 0xA5, 0x1A,\n\t0x4B, 0x52, 0x7C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44,\n\t0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/M_WND_ICON128.xpm",
    "content": "/* XPM */\nconst char* M_WND_ICON128_xpm[] = {\n\"128 128 2075 2\",\n\"  \tc None\",\n\". \tc #3B494D\",\n\"+ \tc #3C484C\",\n\"@ \tc #343B3C\",\n\"# \tc #2E3234\",\n\"$ \tc #2D3232\",\n\"% \tc #2E3232\",\n\"& \tc #303435\",\n\"* \tc #373F40\",\n\"= \tc #3F4D51\",\n\"- \tc #3C4D50\",\n\"; \tc #334247\",\n\"> \tc #2A3132\",\n\", \tc #2E3336\",\n\"' \tc #282C2D\",\n\") \tc #262727\",\n\"! \tc #28292A\",\n\"~ \tc #2C2D2D\",\n\"{ \tc #2E2D2D\",\n\"] \tc #2E2E2E\",\n\"^ \tc #2E2E2D\",\n\"/ \tc #2D2D2D\",\n\"( \tc #2B2D2D\",\n\"_ \tc #272929\",\n\": \tc #262728\",\n\"< \tc #2C3031\",\n\"[ \tc #2F3639\",\n\"} \tc #2E383A\",\n\"| \tc #3A4D52\",\n\"1 \tc #2F3637\",\n\"2 \tc #272A2B\",\n\"3 \tc #292C2C\",\n\"4 \tc #2B2C2C\",\n\"5 \tc #2C2C2C\",\n\"6 \tc #2F2F2E\",\n\"7 \tc #313131\",\n\"8 \tc #323232\",\n\"9 \tc #333333\",\n\"0 \tc #303030\",\n\"a \tc #2B2D2C\",\n\"b \tc #292F30\",\n\"c \tc #2A3031\",\n\"d \tc #344245\",\n\"e \tc #2C3336\",\n\"f \tc #272A2A\",\n\"g \tc #292A2B\",\n\"h \tc #2F2F2F\",\n\"i \tc #282A2B\",\n\"j \tc #272A2C\",\n\"k \tc #242B2D\",\n\"l \tc #2A3336\",\n\"m \tc #282B2B\",\n\"n \tc #313030\",\n\"o \tc #333332\",\n\"p \tc #333231\",\n\"q \tc #333131\",\n\"r \tc #34302E\",\n\"s \tc #352D2B\",\n\"t \tc #352D29\",\n\"u \tc #352D2A\",\n\"v \tc #342E2C\",\n\"w \tc #343130\",\n\"x \tc #333232\",\n\"y \tc #2A2A2A\",\n\"z \tc #25282A\",\n\"A \tc #273234\",\n\"B \tc #2A3536\",\n\"C \tc #323333\",\n\"D \tc #342F2E\",\n\"E \tc #342F2C\",\n\"F \tc #34302F\",\n\"G \tc #313637\",\n\"H \tc #2E3F46\",\n\"I \tc #294B57\",\n\"J \tc #265261\",\n\"K \tc #255666\",\n\"L \tc #255869\",\n\"M \tc #245869\",\n\"N \tc #255768\",\n\"O \tc #265565\",\n\"P \tc #27515F\",\n\"Q \tc #2A4853\",\n\"R \tc #2F3C41\",\n\"S \tc #323334\",\n\"T \tc #342F2D\",\n\"U \tc #302F2F\",\n\"V \tc #282929\",\n\"W \tc #313D41\",\n\"X \tc #25292A\",\n\"Y \tc #2A2B2B\",\n\"Z \tc #2C434C\",\n\"` \tc #215F75\",\n\" .\tc #177D9E\",\n\"..\tc #108EB9\",\n\"+.\tc #0A9ACF\",\n\"@.\tc #06A5E0\",\n\"#.\tc #05AAE5\",\n\"$.\tc #04ACE7\",\n\"%.\tc #04AEE8\",\n\"&.\tc #04ACE6\",\n\"*.\tc #07A2DE\",\n\"=.\tc #0C95C8\",\n\"-.\tc #1289B1\",\n\";.\tc #1B7290\",\n\">.\tc #265464\",\n\",.\tc #303B40\",\n\"'.\tc #34302D\",\n\").\tc #333130\",\n\"!.\tc #2F2E2E\",\n\"~.\tc #283134\",\n\"{.\tc #2F3C3F\",\n\"].\tc #282C2E\",\n\"^.\tc #31383A\",\n\"/.\tc #255867\",\n\"(.\tc #167EA2\",\n\"_.\tc #0A9FD1\",\n\":.\tc #03ADEA\",\n\"<.\tc #01B1F1\",\n\"[.\tc #00B2F1\",\n\"}.\tc #00B0F2\",\n\"|.\tc #00AEF0\",\n\"1.\tc #00ADEF\",\n\"2.\tc #00ADEE\",\n\"3.\tc #00AEF1\",\n\"4.\tc #00B1F2\",\n\"5.\tc #02B0EF\",\n\"6.\tc #05AAE3\",\n\"7.\tc #0E94C2\",\n\"8.\tc #1B718E\",\n\"9.\tc #294D58\",\n\"0.\tc #2B2B2B\",\n\"a.\tc #222526\",\n\"b.\tc #232626\",\n\"c.\tc #31393B\",\n\"d.\tc #225E72\",\n\"e.\tc #128DB5\",\n\"f.\tc #06A9E1\",\n\"g.\tc #01B2F0\",\n\"h.\tc #00B0F1\",\n\"i.\tc #00AEEF\",\n\"j.\tc #00ACEE\",\n\"k.\tc #00AFF0\",\n\"l.\tc #02B1ED\",\n\"m.\tc #08A4D7\",\n\"n.\tc #1682A3\",\n\"o.\tc #28505C\",\n\"p.\tc #272B2D\",\n\"q.\tc #313F42\",\n\"r.\tc #1A1A1A\",\n\"s.\tc #272727\",\n\"t.\tc #138BB2\",\n\"u.\tc #05ABE3\",\n\"v.\tc #01B1F0\",\n\"w.\tc #00AFEF\",\n\"x.\tc #01B1EE\",\n\"y.\tc #08A5D9\",\n\"z.\tc #197999\",\n\"A.\tc #2B464E\",\n\"B.\tc #27292A\",\n\"C.\tc #282F30\",\n\"D.\tc #1F1F21\",\n\"E.\tc #282828\",\n\"F.\tc #352E2C\",\n\"G.\tc #2E3F43\",\n\"H.\tc #197696\",\n\"I.\tc #07A6DB\",\n\"J.\tc #01B1EF\",\n\"K.\tc #00ACED\",\n\"L.\tc #00ADED\",\n\"M.\tc #0D99C8\",\n\"N.\tc #235E71\",\n\"O.\tc #323434\",\n\"P.\tc #2C3537\",\n\"Q.\tc #212323\",\n\"R.\tc #282727\",\n\"S.\tc #2A4A55\",\n\"T.\tc #128EB3\",\n\"U.\tc #03AFEA\",\n\"V.\tc #06A8DE\",\n\"W.\tc #1A7592\",\n\"X.\tc #2F3B3D\",\n\"Y.\tc #313F43\",\n\"Z.\tc #2A2F32\",\n\"`.\tc #323131\",\n\" +\tc #275361\",\n\".+\tc #0C9BC9\",\n\"++\tc #01B2ED\",\n\"@+\tc #00AEED\",\n\"#+\tc #04AFE7\",\n\"$+\tc #1682A4\",\n\"%+\tc #2E3F44\",\n\"&+\tc #352E2D\",\n\"*+\tc #262B2D\",\n\"=+\tc #09A0D4\",\n\"-+\tc #00B1F0\",\n\";+\tc #00AEEE\",\n\">+\tc #02B1EB\",\n\",+\tc #128CB3\",\n\"'+\tc #2C434A\",\n\")+\tc #222424\",\n\"!+\tc #252828\",\n\"~+\tc #265463\",\n\"{+\tc #0AA0D2\",\n\"]+\tc #118EB6\",\n\"^+\tc #2E4046\",\n\"/+\tc #352F2C\",\n\"(+\tc #2B3436\",\n\"_+\tc #2E393C\",\n\":+\tc #284E5B\",\n\"<+\tc #0B9DCD\",\n\"[+\tc #00B1EF\",\n\"}+\tc #1389AE\",\n\"|+\tc #303A3E\",\n\"1+\tc #262828\",\n\"2+\tc #2B3638\",\n\"3+\tc #272828\",\n\"4+\tc #2C434B\",\n\"5+\tc #0F93BD\",\n\"6+\tc #00ABED\",\n\"7+\tc #01AAEC\",\n\"8+\tc #02A9EC\",\n\"9+\tc #03A9EC\",\n\"0+\tc #03AAEC\",\n\"a+\tc #01ABED\",\n\"b+\tc #03B0EC\",\n\"c+\tc #187899\",\n\"d+\tc #262B2B\",\n\"e+\tc #333030\",\n\"f+\tc #313738\",\n\"g+\tc #1581A5\",\n\"h+\tc #01ABEC\",\n\"i+\tc #02AAEC\",\n\"j+\tc #09AAEC\",\n\"k+\tc #13ACEC\",\n\"l+\tc #1AAFED\",\n\"m+\tc #22B3EE\",\n\"n+\tc #32B7EF\",\n\"o+\tc #42BBEF\",\n\"p+\tc #4ABDF0\",\n\"q+\tc #4EBFF0\",\n\"r+\tc #4FC0F0\",\n\"s+\tc #4CBEF0\",\n\"t+\tc #47BDF0\",\n\"u+\tc #3DBAEF\",\n\"v+\tc #2DB6EF\",\n\"w+\tc #1EB1ED\",\n\"x+\tc #18ADED\",\n\"y+\tc #10AAEC\",\n\"z+\tc #05AAEC\",\n\"A+\tc #00ACEC\",\n\"B+\tc #215F73\",\n\"C+\tc #292A2A\",\n\"D+\tc #222727\",\n\"E+\tc #323231\",\n\"F+\tc #215F74\",\n\"G+\tc #05AAE1\",\n\"H+\tc #00ABEC\",\n\"I+\tc #05AAEB\",\n\"J+\tc #10ACEC\",\n\"K+\tc #2FB4ED\",\n\"L+\tc #4FC1F0\",\n\"M+\tc #70CCF2\",\n\"N+\tc #94D7F4\",\n\"O+\tc #AAE0F6\",\n\"P+\tc #BEE7F8\",\n\"Q+\tc #CEECF9\",\n\"R+\tc #D6F0F9\",\n\"S+\tc #DAF1FA\",\n\"T+\tc #DBF2FA\",\n\"U+\tc #DCF2FA\",\n\"V+\tc #D8F0FA\",\n\"W+\tc #D3EFF9\",\n\"X+\tc #C9EBF9\",\n\"Y+\tc #B7E4F7\",\n\"Z+\tc #A3DCF6\",\n\"`+\tc #89D3F4\",\n\" @\tc #63C7F1\",\n\".@\tc #44BCEF\",\n\"+@\tc #24B0EC\",\n\"@@\tc #0BABEC\",\n\"#@\tc #03A9EB\",\n\"$@\tc #01ABEB\",\n\"%@\tc #00B0EE\",\n\"&@\tc #0C99C7\",\n\"*@\tc #2C424A\",\n\"=@\tc #232525\",\n\"-@\tc #332F2D\",\n\";@\tc #2D4047\",\n\">@\tc #0D94C0\",\n\",@\tc #00AFEE\",\n\"'@\tc #01AAEB\",\n\")@\tc #06A9EB\",\n\"!@\tc #17ACEC\",\n\"~@\tc #35B7EE\",\n\"{@\tc #65C7F1\",\n\"]@\tc #97DAF5\",\n\"^@\tc #C2E8F8\",\n\"/@\tc #E3F3FA\",\n\"(@\tc #F1F8FB\",\n\"_@\tc #F6FAFC\",\n\":@\tc #F9FBFC\",\n\"<@\tc #FBFCFC\",\n\"[@\tc #FCFCFC\",\n\"}@\tc #FAFBFC\",\n\"|@\tc #F8FBFC\",\n\"1@\tc #F5FAFB\",\n\"2@\tc #EDF7FB\",\n\"3@\tc #DAF0F9\",\n\"4@\tc #B5E3F6\",\n\"5@\tc #89D3F3\",\n\"6@\tc #56C0EF\",\n\"7@\tc #29B1EC\",\n\"8@\tc #0DA9EB\",\n\"9@\tc #02A9EB\",\n\"0@\tc #02AFEB\",\n\"a@\tc #1A7391\",\n\"b@\tc #323030\",\n\"c@\tc #292929\",\n\"d@\tc #282829\",\n\"e@\tc #323130\",\n\"f@\tc #332F2E\",\n\"g@\tc #1B6E8B\",\n\"h@\tc #03AEE8\",\n\"i@\tc #08A9EB\",\n\"j@\tc #26B0ED\",\n\"k@\tc #5BC2F0\",\n\"l@\tc #99D8F4\",\n\"m@\tc #CCEBF8\",\n\"n@\tc #E7F4FA\",\n\"o@\tc #F7FAFC\",\n\"p@\tc #FBFBFC\",\n\"q@\tc #F4F9FB\",\n\"r@\tc #E0F2FA\",\n\"s@\tc #BBE4F6\",\n\"t@\tc #7ACCF1\",\n\"u@\tc #39B5EC\",\n\"v@\tc #0EA9EB\",\n\"w@\tc #01A9EB\",\n\"x@\tc #099FD2\",\n\"y@\tc #294A56\",\n\"z@\tc #332E2C\",\n\"A@\tc #282C2C\",\n\"B@\tc #2E3738\",\n\"C@\tc #0B9ACA\",\n\"D@\tc #00B0EF\",\n\"E@\tc #00AAEC\",\n\"F@\tc #05A9EB\",\n\"G@\tc #24B1ED\",\n\"H@\tc #67C6F1\",\n\"I@\tc #B1E1F6\",\n\"J@\tc #EFF7FB\",\n\"K@\tc #C9E9F7\",\n\"L@\tc #7FCDF0\",\n\"M@\tc #30B2EB\",\n\"N@\tc #09A9EA\",\n\"O@\tc #02B0EC\",\n\"P@\tc #17799A\",\n\"Q@\tc #29292A\",\n\"R@\tc #354346\",\n\"S@\tc #292C2D\",\n\"T@\tc #332D2B\",\n\"U@\tc #1E677F\",\n\"V@\tc #03ADE9\",\n\"W@\tc #00ABEB\",\n\"X@\tc #1CADEC\",\n\"Y@\tc #64C6F0\",\n\"Z@\tc #B9E4F6\",\n\"`@\tc #EBF6FA\",\n\" #\tc #F9FBFB\",\n\".#\tc #FBFBFB\",\n\"+#\tc #F1F7FA\",\n\"@#\tc #C5E6F5\",\n\"##\tc #6DC5ED\",\n\"$#\tc #1FABE9\",\n\"%#\tc #03A8EB\",\n\"&#\tc #099ED2\",\n\"*#\tc #294752\",\n\"=#\tc #332E2D\",\n\"-#\tc #303A3C\",\n\";#\tc #39454A\",\n\">#\tc #332F2F\",\n\",#\tc #2F383B\",\n\"'#\tc #0E8EB9\",\n\")#\tc #00ABEA\",\n\"!#\tc #01A9EA\",\n\"~#\tc #10A9EA\",\n\"{#\tc #4BBBEE\",\n\"]#\tc #A6DCF4\",\n\"^#\tc #E7F4F9\",\n\"/#\tc #F9FAFB\",\n\"(#\tc #FAFBFB\",\n\"_#\tc #E8F3F8\",\n\":#\tc #A7DAF0\",\n\"<#\tc #44B5E8\",\n\"[#\tc #09A7E9\",\n\"}#\tc #00AAEB\",\n\"|#\tc #02ADE9\",\n\"1#\tc #1B6C87\",\n\"2#\tc #26292A\",\n\"3#\tc #272C2D\",\n\"4#\tc #342D2B\",\n\"5#\tc #255363\",\n\"6#\tc #05A9E0\",\n\"7#\tc #03A8EA\",\n\"8#\tc #22AEEB\",\n\"9#\tc #7CCDF1\",\n\"0#\tc #D4EDF8\",\n\"a#\tc #F6F9FB\",\n\"b#\tc #F5F8FA\",\n\"c#\tc #CBE7F4\",\n\"d#\tc #62C0E8\",\n\"e#\tc #10A7E7\",\n\"f#\tc #0E8EBC\",\n\"g#\tc #2E3B3F\",\n\"h#\tc #394446\",\n\"i#\tc #2B3335\",\n\"j#\tc #187393\",\n\"k#\tc #01AFED\",\n\"l#\tc #07A8EA\",\n\"m#\tc #3CB7ED\",\n\"n#\tc #A5DCF5\",\n\"o#\tc #FAFAFB\",\n\"p#\tc #DFEFF6\",\n\"q#\tc #78C6E9\",\n\"r#\tc #16A7E5\",\n\"s#\tc #06A5DB\",\n\"t#\tc #264F5E\",\n\"u#\tc #262B2E\",\n\"v#\tc #2A2B2C\",\n\"w#\tc #303638\",\n\"x#\tc #0F90BA\",\n\"y#\tc #00AFED\",\n\"z#\tc #00AAEA\",\n\"A#\tc #09A8EA\",\n\"B#\tc #48BAEE\",\n\"C#\tc #BAE3F6\",\n\"D#\tc #F3F8FA\",\n\"E#\tc #E5F1F6\",\n\"F#\tc #7DC6E7\",\n\"G#\tc #15A6E5\",\n\"H#\tc #02ADEA\",\n\"I#\tc #1A6F8D\",\n\"J#\tc #322F2E\",\n\"K#\tc #39474C\",\n\"L#\tc #2A444E\",\n\"M#\tc #089FD3\",\n\"N#\tc #4CBCEE\",\n\"O#\tc #C0E6F6\",\n\"P#\tc #F4F8FA\",\n\"Q#\tc #FAFAFA\",\n\"R#\tc #E2F0F5\",\n\"S#\tc #70C1E4\",\n\"T#\tc #10A5E4\",\n\"U#\tc #1287AD\",\n\"V#\tc #313435\",\n\"W#\tc #33302F\",\n\"X#\tc #2C2E2E\",\n\"Y#\tc #384448\",\n\"Z#\tc #342D2A\",\n\"`#\tc #245668\",\n\" $\tc #04A8E4\",\n\".$\tc #05A8E9\",\n\"+$\tc #41B8EC\",\n\"@$\tc #C0E5F5\",\n\"#$\tc #F5F9FA\",\n\"$$\tc #F9F9F9\",\n\"%$\tc #F8F8F8\",\n\"&$\tc #F5F5F6\",\n\"*$\tc #ECEDED\",\n\"=$\tc #E4E6E8\",\n\"-$\tc #E1E4E6\",\n\";$\tc #DFE2E4\",\n\">$\tc #DEE2E4\",\n\",$\tc #E0E4E5\",\n\"'$\tc #E4E7E8\",\n\")$\tc #ECEDEE\",\n\"!$\tc #F6F6F6\",\n\"~$\tc #F8F9F9\",\n\"{$\tc #F9FAFA\",\n\"]$\tc #D7EAF2\",\n\"^$\tc #5AB6DF\",\n\"/$\tc #09A4E4\",\n\"($\tc #0E92BE\",\n\"_$\tc #2E3B40\",\n\":$\tc #33302E\",\n\"<$\tc #2E3131\",\n\"[$\tc #352C29\",\n\"}$\tc #205F77\",\n\"|$\tc #03ABE8\",\n\"1$\tc #02A8E9\",\n\"2$\tc #31B2EB\",\n\"3$\tc #B4E2F5\",\n\"4$\tc #F6F6F7\",\n\"5$\tc #EBECED\",\n\"6$\tc #D0D2D5\",\n\"7$\tc #ADB3B8\",\n\"8$\tc #909DA5\",\n\"9$\tc #707D88\",\n\"0$\tc #5D6F7C\",\n\"a$\tc #546C7B\",\n\"b$\tc #506A7B\",\n\"c$\tc #4F6A7C\",\n\"d$\tc #546E7F\",\n\"e$\tc #5D7382\",\n\"f$\tc #71838F\",\n\"g$\tc #94A4AD\",\n\"h$\tc #B5BDC2\",\n\"i$\tc #E0E1E2\",\n\"j$\tc #F2F3F3\",\n\"k$\tc #F7F8F9\",\n\"l$\tc #C3E0EC\",\n\"m$\tc #3EAADB\",\n\"n$\tc #03A6E6\",\n\"o$\tc #089DD4\",\n\"p$\tc #284854\",\n\"q$\tc #282625\",\n\"r$\tc #342C29\",\n\"s$\tc #1D6983\",\n\"t$\tc #02AEE9\",\n\"u$\tc #1BACEA\",\n\"v$\tc #9AD8F3\",\n\"w$\tc #F4F4F5\",\n\"x$\tc #D9DBDD\",\n\"y$\tc #A9AEB3\",\n\"z$\tc #6C7B85\",\n\"A$\tc #3D5668\",\n\"B$\tc #1E4760\",\n\"C$\tc #0E4F6E\",\n\"D$\tc #06587D\",\n\"E$\tc #04628B\",\n\"F$\tc #046A96\",\n\"G$\tc #036E9C\",\n\"H$\tc #03709F\",\n\"I$\tc #04709E\",\n\"J$\tc #056C99\",\n\"K$\tc #076690\",\n\"L$\tc #0F6085\",\n\"M$\tc #265C79\",\n\"N$\tc #537689\",\n\"O$\tc #91A0AB\",\n\"P$\tc #CFD4D7\",\n\"Q$\tc #F1F2F3\",\n\"R$\tc #F2F6F7\",\n\"S$\tc #A1D0E4\",\n\"T$\tc #1FA2DA\",\n\"U$\tc #00A9E9\",\n\"V$\tc #05A4DF\",\n\"W$\tc #245365\",\n\"X$\tc #282A2A\",\n\"Y$\tc #3C4A4D\",\n\"Z$\tc #272525\",\n\"`$\tc #332E2B\",\n\" %\tc #197391\",\n\".%\tc #01B0EC\",\n\"+%\tc #0AA8E9\",\n\"@%\tc #71C9F0\",\n\"#%\tc #E8F4F9\",\n\"$%\tc #DEE0E2\",\n\"%%\tc #989EA5\",\n\"&%\tc #485A6A\",\n\"*%\tc #18475F\",\n\"=%\tc #065478\",\n\"-%\tc #00719E\",\n\";%\tc #0088BC\",\n\">%\tc #0098D0\",\n\",%\tc #00A1DD\",\n\"'%\tc #00A6E4\",\n\")%\tc #00A9E7\",\n\"!%\tc #00AAE9\",\n\"~%\tc #00A9E8\",\n\"{%\tc #00A7E5\",\n\"]%\tc #00A0DD\",\n\"^%\tc #0096CE\",\n\"/%\tc #0281B3\",\n\"(%\tc #106B94\",\n\"_%\tc #3B6F8B\",\n\":%\tc #8EA2AE\",\n\"<%\tc #DDE1E3\",\n\"[%\tc #E9F0F3\",\n\"}%\tc #71B9D9\",\n\"|%\tc #0BA0DE\",\n\"1%\tc #05A6E1\",\n\"2%\tc #23586C\",\n\"3%\tc #342D29\",\n\"4%\tc #363A3D\",\n\"5%\tc #2F3537\",\n\"6%\tc #16799A\",\n\"7%\tc #04A8E8\",\n\"8%\tc #45BAEC\",\n\"9%\tc #D0EBF6\",\n\"0%\tc #EDEEEF\",\n\"a%\tc #B5BABE\",\n\"b%\tc #536472\",\n\"c%\tc #14455F\",\n\"d%\tc #026088\",\n\"e%\tc #0086B9\",\n\"f%\tc #009DD8\",\n\"g%\tc #00A4E1\",\n\"h%\tc #018EC6\",\n\"i%\tc #1373A0\",\n\"j%\tc #57859E\",\n\"k%\tc #B9C7CE\",\n\"l%\tc #F0F2F2\",\n\"m%\tc #C6DEE8\",\n\"n%\tc #3AA2D1\",\n\"o%\tc #02A4E4\",\n\"p%\tc #04A8E1\",\n\"q%\tc #225B6F\",\n\"r%\tc #2F3234\",\n\"s%\tc #157A9D\",\n\"t%\tc #01A8E8\",\n\"u%\tc #21AEE9\",\n\"v%\tc #A8DDF3\",\n\"w%\tc #F6F8F9\",\n\"x%\tc #E0E2E3\",\n\"y%\tc #8A939A\",\n\"z%\tc #2B485B\",\n\"A%\tc #055679\",\n\"B%\tc #00A2DE\",\n\"C%\tc #00A4E2\",\n\"D%\tc #0688BF\",\n\"E%\tc #367B9E\",\n\"F%\tc #A4B9C4\",\n\"G%\tc #EEF1F1\",\n\"H%\tc #EEF2F4\",\n\"I%\tc #8CC0D7\",\n\"J%\tc #139BD5\",\n\"K%\tc #00A9EA\",\n\"L%\tc #225B70\",\n\"M%\tc #313839\",\n\"N%\tc #157A9E\",\n\"O%\tc #0AA7E8\",\n\"P%\tc #66C6EE\",\n\"Q%\tc #E5F2F8\",\n\"R%\tc #F7F7F7\",\n\"S%\tc #D8DBDD\",\n\"T%\tc #737E88\",\n\"U%\tc #18455D\",\n\"V%\tc #016A94\",\n\"W%\tc #0099D2\",\n\"X%\tc #0495D0\",\n\"Y%\tc #2E83AC\",\n\"Z%\tc #A4BECB\",\n\"`%\tc #F2F4F4\",\n\" &\tc #D0E1E8\",\n\".&\tc #43A2CC\",\n\"+&\tc #01A2E3\",\n\"@&\tc #2E2F31\",\n\"#&\tc #32302F\",\n\"$&\tc #01AFEC\",\n\"%&\tc #2CB0EA\",\n\"&&\tc #B7E2F4\",\n\"*&\tc #F7F8F8\",\n\"=&\tc #D5D9DB\",\n\"-&\tc #6A7882\",\n\";&\tc #124862\",\n\">&\tc #0079A8\",\n\",&\tc #00A1DC\",\n\"'&\tc #039AD7\",\n\")&\tc #338BB4\",\n\"!&\tc #BBCFD9\",\n\"~&\tc #EFF2F4\",\n\"{&\tc #86BBD1\",\n\"]&\tc #0C97D3\",\n\"^&\tc #342C28\",\n\"/&\tc #313739\",\n\"(&\tc #00A8E8\",\n\"_&\tc #08A7E7\",\n\":&\tc #6FC8EE\",\n\"<&\tc #E5F2F6\",\n\"[&\tc #E1E4E5\",\n\"}&\tc #737F89\",\n\"|&\tc #134964\",\n\"1&\tc #007EAE\",\n\"2&\tc #0498D5\",\n\"3&\tc #539DBF\",\n\"4&\tc #D8E4E9\",\n\"5&\tc #F6F7F7\",\n\"6&\tc #C5D9E2\",\n\"7&\tc #2A97C5\",\n\"8&\tc #01A5E5\",\n\"9&\tc #04A7E0\",\n\"0&\tc #225A70\",\n\"a&\tc #2E2F2F\",\n\"b&\tc #00A7E8\",\n\"c&\tc #24AEE9\",\n\"d&\tc #B4E0F3\",\n\"e&\tc #F5F7F8\",\n\"f&\tc #EDEFEF\",\n\"g&\tc #8F9AA2\",\n\"h&\tc #1B4963\",\n\"i&\tc #017AA9\",\n\"j&\tc #1395CD\",\n\"k&\tc #8DBCD1\",\n\"l&\tc #EEF2F3\",\n\"m&\tc #E5ECEE\",\n\"n&\tc #60A4C3\",\n\"o&\tc #039BD8\",\n\"p&\tc #2C2F2F\",\n\"q&\tc #157A9C\",\n\"r&\tc #01AEEB\",\n\"s&\tc #04A6E7\",\n\"t&\tc #57C0EC\",\n\"u&\tc #E1F0F6\",\n\"v&\tc #F5F5F5\",\n\"w&\tc #B8BFC3\",\n\"x&\tc #2B4E63\",\n\"y&\tc #01709C\",\n\"z&\tc #00A8E7\",\n\"A&\tc #01A3E3\",\n\"B&\tc #369BC9\",\n\"C&\tc #C3DBE4\",\n\"D&\tc #99BFCF\",\n\"E&\tc #1191C8\",\n\"F&\tc #215A6F\",\n\"G&\tc #332B28\",\n\"H&\tc #14A9E7\",\n\"I&\tc #9BD6F0\",\n\"J&\tc #F1F5F7\",\n\"K&\tc #DFE2E3\",\n\"L&\tc #5E7280\",\n\"M&\tc #055C82\",\n\"N&\tc #009BD5\",\n\"O&\tc #0B9BD9\",\n\"P&\tc #7ABAD6\",\n\"Q&\tc #ECF1F3\",\n\"R&\tc #C9D9DF\",\n\"S&\tc #2F8FBC\",\n\"T&\tc #00A4E3\",\n\"U&\tc #04A7DF\",\n\"V&\tc #15799C\",\n\"W&\tc #02A5E6\",\n\"X&\tc #37B3E9\",\n\"Y&\tc #CCE8F3\",\n\"Z&\tc #F3F3F4\",\n\"`&\tc #A1ABB1\",\n\" *\tc #1A516D\",\n\".*\tc #008BC0\",\n\"+*\tc #01A4E4\",\n\"@*\tc #37A4D4\",\n\"#*\tc #CBE1E9\",\n\"$*\tc #E4E9EC\",\n\"%*\tc #529CBB\",\n\"&*\tc #0399D7\",\n\"**\tc #04A6DF\",\n\"=*\tc #313639\",\n\"-*\tc #01ADEA\",\n\";*\tc #07A5E6\",\n\">*\tc #6CC5EB\",\n\",*\tc #E8F1F5\",\n\"'*\tc #DCDFE0\",\n\")*\tc #4D6979\",\n\"!*\tc #036A95\",\n\"~*\tc #00A3E0\",\n\"{*\tc #00A7E7\",\n\"]*\tc #129FDB\",\n\"^*\tc #95C8DE\",\n\"/*\tc #EFF2F3\",\n\"(*\tc #EEF0F1\",\n\"_*\tc #7EABBF\",\n\":*\tc #0B8EC7\",\n\"<*\tc #15799B\",\n\"[*\tc #1AA8E6\",\n\"}*\tc #A0D8EF\",\n\"|*\tc #F3F5F6\",\n\"1*\tc #A8B4B9\",\n\"2*\tc #1A5471\",\n\"3*\tc #008FC5\",\n\"4*\tc #04A2E2\",\n\"5*\tc #56B2D9\",\n\"6*\tc #DFEAEF\",\n\"7*\tc #F4F4F4\",\n\"8*\tc #F0F0F0\",\n\"9*\tc #A4C0CC\",\n\"0*\tc #158ABC\",\n\"a*\tc #00A6E5\",\n\"b*\tc #15789B\",\n\"c*\tc #01ADE9\",\n\"d*\tc #00A7E6\",\n\"e*\tc #00A5E6\",\n\"f*\tc #35B2E8\",\n\"g*\tc #CAE6F2\",\n\"h*\tc #F4F5F5\",\n\"i*\tc #E8EAEA\",\n\"j*\tc #6D8390\",\n\"k*\tc #056791\",\n\"l*\tc #00A1DE\",\n\"m*\tc #00A5E5\",\n\"n*\tc #2BA4D9\",\n\"o*\tc #BCDBE8\",\n\"p*\tc #F3F4F5\",\n\"q*\tc #F1F1F1\",\n\"r*\tc #CCCED1\",\n\"s*\tc #B7BCC0\",\n\"t*\tc #A7B1B6\",\n\"u*\tc #8F9CA3\",\n\"v*\tc #5F7E8C\",\n\"w*\tc #0E7FAB\",\n\"x*\tc #04A5DE\",\n\"y*\tc #313638\",\n\"z*\tc #01ACE9\",\n\"A*\tc #04A3E5\",\n\"B*\tc #56BEEA\",\n\"C*\tc #DFEEF3\",\n\"D*\tc #CFD5D7\",\n\"E*\tc #37647B\",\n\"F*\tc #0183B7\",\n\"G*\tc #00A6E6\",\n\"H*\tc #12A2DF\",\n\"I*\tc #91CBE3\",\n\"J*\tc #E1E5E8\",\n\"K*\tc #D7D9DB\",\n\"L*\tc #CACFD2\",\n\"M*\tc #BDC5C8\",\n\"N*\tc #A0A8AD\",\n\"O*\tc #838E97\",\n\"P*\tc #6E818C\",\n\"Q*\tc #516F7D\",\n\"R*\tc #36586A\",\n\"S*\tc #274D63\",\n\"T*\tc #1C4E68\",\n\"U*\tc #0E516F\",\n\"V*\tc #065E83\",\n\"W*\tc #0189BB\",\n\"X*\tc #00A5E3\",\n\"Y*\tc #15789A\",\n\"Z*\tc #0BA5E5\",\n\"`*\tc #85CDEC\",\n\" =\tc #ECF2F4\",\n\".=\tc #F1F2F2\",\n\"+=\tc #A9B3B9\",\n\"@=\tc #175E80\",\n\"#=\tc #0099D4\",\n\"$=\tc #04A5E4\",\n\"%=\tc #3CA3CE\",\n\"&=\tc #628798\",\n\"*=\tc #4B6070\",\n\"==\tc #335669\",\n\"-=\tc #24556B\",\n\";=\tc #15516C\",\n\">=\tc #0E5171\",\n\",=\tc #095A7F\",\n\"'=\tc #036790\",\n\")=\tc #0074A1\",\n\"!=\tc #007FB0\",\n\"~=\tc #0088BD\",\n\"{=\tc #0092CA\",\n\"]=\tc #00A2E0\",\n\"^=\tc #215A6E\",\n\"/=\tc #312F2E\",\n\"(=\tc #01ACE8\",\n\"_=\tc #12A8E4\",\n\":=\tc #A6DAEE\",\n\"<=\tc #F2F3F4\",\n\"[=\tc #E9EAEB\",\n\"}=\tc #758D99\",\n\"|=\tc #076994\",\n\"1=\tc #0396D0\",\n\"2=\tc #05719D\",\n\"3=\tc #03658F\",\n\"4=\tc #0172A0\",\n\"5=\tc #007FB1\",\n\"6=\tc #008CC1\",\n\"7=\tc #0095CE\",\n\"8=\tc #009BD6\",\n\"9=\tc #04A4DD\",\n\"0=\tc #21596E\",\n\"a=\tc #00A4E4\",\n\"b=\tc #2AADE5\",\n\"c=\tc #BFE1EF\",\n\"d=\tc #F3F3F3\",\n\"e=\tc #DADCDE\",\n\"f=\tc #4D7285\",\n\"g=\tc #007EB0\",\n\"h=\tc #00A5E2\",\n\"i=\tc #00A2DF\",\n\"j=\tc #157799\",\n\"k=\tc #01ABE7\",\n\"l=\tc #00A3E4\",\n\"m=\tc #43B4E6\",\n\"n=\tc #D5E9F0\",\n\"o=\tc #F2F2F2\",\n\"p=\tc #BFC7CB\",\n\"q=\tc #326580\",\n\"r=\tc #008DC5\",\n\"s=\tc #04A4DC\",\n\"t=\tc #21596D\",\n\"u=\tc #56BDE6\",\n\"v=\tc #E2EDF1\",\n\"w=\tc #F0F1F1\",\n\"x=\tc #A1B3BA\",\n\"y=\tc #176486\",\n\"z=\tc #00A6E3\",\n\"A=\tc #312E2E\",\n\"B=\tc #01AAE6\",\n\"C=\tc #07A2E2\",\n\"D=\tc #76C8E8\",\n\"E=\tc #EBF0F1\",\n\"F=\tc #EEEEEE\",\n\"G=\tc #90A6AF\",\n\"H=\tc #0D6D96\",\n\"I=\tc #00A0DC\",\n\"J=\tc #04A3DB\",\n\"K=\tc #322A27\",\n\"L=\tc #11A3E1\",\n\"M=\tc #95D0EA\",\n\"N=\tc #E5E6E7\",\n\"O=\tc #76909E\",\n\"P=\tc #0974A2\",\n\"Q=\tc #312E2D\",\n\"R=\tc #157699\",\n\"S=\tc #18A5E1\",\n\"T=\tc #A7D7EB\",\n\"U=\tc #EFF1F1\",\n\"V=\tc #DADFE0\",\n\"W=\tc #5B7D91\",\n\"X=\tc #057AAC\",\n\"Y=\tc #21586D\",\n\"Z=\tc #303637\",\n\"`=\tc #01AAE5\",\n\" -\tc #00A3E2\",\n\".-\tc #1BA7E1\",\n\"+-\tc #B2DAEB\",\n\"@-\tc #EFF0F1\",\n\"#-\tc #D4DADD\",\n\"$-\tc #4B7990\",\n\"%-\tc #0382B7\",\n\"&-\tc #04A2DA\",\n\"*-\tc #21586C\",\n\"=-\tc #157698\",\n\"--\tc #00A3E1\",\n\";-\tc #20A9E1\",\n\">-\tc #BDDDEB\",\n\",-\tc #F0F0F1\",\n\"'-\tc #D0D8DB\",\n\")-\tc #427A94\",\n\"!-\tc #0289C0\",\n\"~-\tc #01A9E4\",\n\"{-\tc #29ACE0\",\n\"]-\tc #CBE3EC\",\n\"^-\tc #CCD6D9\",\n\"/-\tc #397A96\",\n\"(-\tc #04A2D9\",\n\"_-\tc #303537\",\n\":-\tc #302E2D\",\n\"<-\tc #157597\",\n\"[-\tc #01A1E0\",\n\"}-\tc #35AFE1\",\n\"|-\tc #D3E6EC\",\n\"1-\tc #F0EFEF\",\n\"2-\tc #C8D0D3\",\n\"3-\tc #307896\",\n\"4-\tc #0092CB\",\n\"5-\tc #04A1D9\",\n\"6-\tc #20576C\",\n\"7-\tc #01A8E3\",\n\"8-\tc #029FDF\",\n\"9-\tc #3FB1E1\",\n\"0-\tc #D6E7ED\",\n\"a-\tc #EFEFEF\",\n\"b-\tc #EFEEEE\",\n\"c-\tc #BFC8CC\",\n\"d-\tc #297495\",\n\"e-\tc #0095CF\",\n\"f-\tc #04A1D8\",\n\"g-\tc #2C2C2E\",\n\"h-\tc #029FDE\",\n\"i-\tc #44B2E1\",\n\"j-\tc #D7E7ED\",\n\"k-\tc #B9C4C8\",\n\"l-\tc #257496\",\n\"m-\tc #0097D1\",\n\"n-\tc #04A0D8\",\n\"o-\tc #157596\",\n\"p-\tc #01A8E2\",\n\"q-\tc #029EDE\",\n\"r-\tc #46B2E1\",\n\"s-\tc #D8E7EC\",\n\"t-\tc #EDEDED\",\n\"u-\tc #B7C2C7\",\n\"v-\tc #247497\",\n\"w-\tc #0097D2\",\n\"x-\tc #04A0D7\",\n\"y-\tc #2A2A2B\",\n\"z-\tc #2B2C2E\",\n\"A-\tc #029EDD\",\n\"B-\tc #46B2E0\",\n\"C-\tc #B6C2C7\",\n\"D-\tc #247598\",\n\"E-\tc #20576B\",\n\"F-\tc #2F3030\",\n\"G-\tc #01A7E1\",\n\"H-\tc #45B1DF\",\n\"I-\tc #D7E6EB\",\n\"J-\tc #ECECEC\",\n\"K-\tc #B7C3C7\",\n\"L-\tc #257699\",\n\"M-\tc #00A3DF\",\n\"N-\tc #312A27\",\n\"O-\tc #2F3536\",\n\"P-\tc #302D2D\",\n\"Q-\tc #157495\",\n\"R-\tc #01A6E1\",\n\"S-\tc #029EDC\",\n\"T-\tc #43B0DD\",\n\"U-\tc #D5E4EA\",\n\"V-\tc #ECECEB\",\n\"W-\tc #BAC6CA\",\n\"X-\tc #27789A\",\n\"Y-\tc #0096D1\",\n\"Z-\tc #049FD6\",\n\"`-\tc #20566A\",\n\" ;\tc #302D2C\",\n\".;\tc #01A6E0\",\n\"+;\tc #029DDC\",\n\"@;\tc #3EAEDD\",\n\"#;\tc #D4E3E9\",\n\"$;\tc #C2CCCF\",\n\"%;\tc #2D7C9D\",\n\"&;\tc #0094CE\",\n\"*;\tc #049FD5\",\n\"=;\tc #2F2D2C\",\n\"-;\tc #019DDC\",\n\";;\tc #35ABDB\",\n\">;\tc #D0E1E7\",\n\",;\tc #EBEBEB\",\n\"';\tc #C7D2D5\",\n\");\tc #347FA0\",\n\"!;\tc #0192CC\",\n\"~;\tc #312A26\",\n\"{;\tc #2F3436\",\n\"];\tc #157394\",\n\"^;\tc #01A6DF\",\n\"/;\tc #009EDB\",\n\"(;\tc #28A7DA\",\n\"_;\tc #C7DDE5\",\n\":;\tc #CAD4D8\",\n\"<;\tc #3D82A0\",\n\"[;\tc #028EC7\",\n\"};\tc #049ED5\",\n\"|;\tc #312926\",\n\"1;\tc #2F3435\",\n\"2;\tc #01A5DE\",\n\"3;\tc #00A0DB\",\n\"4;\tc #009FDB\",\n\"5;\tc #1FA2D8\",\n\"6;\tc #B8D6E3\",\n\"7;\tc #E9EAEA\",\n\"8;\tc #EAEAEA\",\n\"9;\tc #CDD5D8\",\n\"0;\tc #46829E\",\n\"a;\tc #038AC3\",\n\"b;\tc #049ED4\",\n\"c;\tc #205569\",\n\"d;\tc #1AA0D8\",\n\"e;\tc #ACD1E1\",\n\"f;\tc #E8E9EA\",\n\"g;\tc #D1D7DA\",\n\"h;\tc #51849D\",\n\"i;\tc #0486BC\",\n\"j;\tc #2F2C2C\",\n\"k;\tc #147293\",\n\"l;\tc #01A4DD\",\n\"m;\tc #009FDA\",\n\"n;\tc #179ED7\",\n\"o;\tc #A1CDDF\",\n\"p;\tc #E7E8E9\",\n\"q;\tc #E9E9E9\",\n\"r;\tc #D9DCDD\",\n\"s;\tc #6790A4\",\n\"t;\tc #0782B7\",\n\"u;\tc #049DD3\",\n\"v;\tc #009EDA\",\n\"w;\tc #109BD7\",\n\"x;\tc #8DC6DD\",\n\"y;\tc #E5E8E8\",\n\"z;\tc #E2E3E3\",\n\"A;\tc #82A4B3\",\n\"B;\tc #0B81B2\",\n\"C;\tc #009ED9\",\n\"D;\tc #147292\",\n\"E;\tc #01A3DD\",\n\"F;\tc #069BD7\",\n\"G;\tc #6FBBD9\",\n\"H;\tc #E1E5E7\",\n\"I;\tc #E8E8E8\",\n\"J;\tc #E5E6E6\",\n\"K;\tc #93B1BC\",\n\"L;\tc #107DAB\",\n\"M;\tc #009CD7\",\n\"N;\tc #019ED9\",\n\"O;\tc #11A2DA\",\n\"P;\tc #23A6DB\",\n\"Q;\tc #1DA1DA\",\n\"R;\tc #179ED9\",\n\"S;\tc #0C9CD9\",\n\"T;\tc #049CD9\",\n\"U;\tc #039CD9\",\n\"V;\tc #029CD9\",\n\"W;\tc #019CD9\",\n\"X;\tc #009DD9\",\n\"Y;\tc #049DD2\",\n\"Z;\tc #1F5568\",\n\"`;\tc #302926\",\n\" >\tc #019BD8\",\n\".>\tc #51AFD5\",\n\"+>\tc #D8E0E4\",\n\"@>\tc #E6E7E7\",\n\"#>\tc #A7BCC5\",\n\"$>\tc #227BA4\",\n\"%>\tc #0098D4\",\n\"&>\tc #069BD9\",\n\"*>\tc #53B6DE\",\n\"=>\tc #ACD3E4\",\n\"->\tc #A2CFE3\",\n\";>\tc #91C9E1\",\n\">>\tc #77C1E0\",\n\",>\tc #5FBADE\",\n\"'>\tc #52B4DE\",\n\")>\tc #43ADDC\",\n\"!>\tc #2EA5DA\",\n\"~>\tc #1EA2DA\",\n\"{>\tc #14A0DA\",\n\"]>\tc #0C9DD9\",\n\"^>\tc #089BD8\",\n\"/>\tc #049BD9\",\n\"(>\tc #019DD9\",\n\"_>\tc #049CD2\",\n\":>\tc #2E3435\",\n\"<>\tc #2E2C2B\",\n\"[>\tc #147192\",\n\"}>\tc #01A3DC\",\n\"|>\tc #009CD8\",\n\"1>\tc #40A7D4\",\n\"2>\tc #CBDBE2\",\n\"3>\tc #E7E7E7\",\n\"4>\tc #C3CCD1\",\n\"5>\tc #3C82A4\",\n\"6>\tc #0093CE\",\n\"7>\tc #0D9BD8\",\n\"8>\tc #74BFDF\",\n\"9>\tc #DDE4E7\",\n\"0>\tc #E4E6E7\",\n\"a>\tc #E2E6E7\",\n\"b>\tc #DFE5E7\",\n\"c>\tc #DBE3E6\",\n\"d>\tc #D5E1E6\",\n\"e>\tc #C7DCE5\",\n\"f>\tc #B4D6E4\",\n\"g>\tc #A5D1E3\",\n\"h>\tc #9ACEE2\",\n\"i>\tc #84C4E0\",\n\"j>\tc #67B9DE\",\n\"k>\tc #47B0DC\",\n\"l>\tc #12A2DA\",\n\"m>\tc #049CD1\",\n\"n>\tc #2E3335\",\n\"o>\tc #147191\",\n\"p>\tc #01A2DB\",\n\"q>\tc #009BD8\",\n\"r>\tc #279FD2\",\n\"s>\tc #B5D3DE\",\n\"t>\tc #E6E6E6\",\n\"u>\tc #D5D8DA\",\n\"v>\tc #558EA8\",\n\"w>\tc #028BC3\",\n\"x>\tc #189ED8\",\n\"y>\tc #96C9DF\",\n\"z>\tc #E2E5E6\",\n\"A>\tc #E6E6E7\",\n\"B>\tc #E3E5E6\",\n\"C>\tc #DBE3E5\",\n\"D>\tc #BAD3DC\",\n\"E>\tc #2D98C2\",\n\"F>\tc #049BD1\",\n\"G>\tc #1F5468\",\n\"H>\tc #2D3335\",\n\"I>\tc #119BD2\",\n\"J>\tc #9BC8D9\",\n\"K>\tc #E4E5E5\",\n\"L>\tc #DFE1E2\",\n\"M>\tc #84A7B8\",\n\"N>\tc #0C83B6\",\n\"O>\tc #009BD7\",\n\"P>\tc #26A4D8\",\n\"Q>\tc #B3D5E2\",\n\"R>\tc #E5E5E5\",\n\"S>\tc #B4BEC3\",\n\"T>\tc #226D8F\",\n\"U>\tc #0091C8\",\n\"V>\tc #049BD0\",\n\"W>\tc #302925\",\n\"X>\tc #01A1DA\",\n\"Y>\tc #0998D3\",\n\"Z>\tc #77B7D3\",\n\"`>\tc #DBE1E3\",\n\" ,\tc #E4E4E3\",\n\".,\tc #AFC1C9\",\n\"+,\tc #1E83AE\",\n\"@,\tc #0099D5\",\n\"#,\tc #48ADD9\",\n\"$,\tc #C6DBE3\",\n\"%,\tc #E1E2E2\",\n\"&,\tc #8C9DA5\",\n\"*,\tc #105F83\",\n\"=,\tc #0094CD\",\n\"-,\tc #049ACF\",\n\";,\tc #1F5467\",\n\">,\tc #292B2C\",\n\",,\tc #147090\",\n\"',\tc #01A1D9\",\n\"),\tc #009CD6\",\n\"!,\tc #0298D3\",\n\"~,\tc #4AA8CF\",\n\"{,\tc #CDDBDF\",\n\"],\tc #E4E4E4\",\n\"^,\tc #CCD4D7\",\n\"/,\tc #488EAE\",\n\"(,\tc #0291CA\",\n\"_,\tc #009DD7\",\n\":,\tc #089AD5\",\n\"<,\tc #72BBDB\",\n\"[,\tc #D9E0E3\",\n\"},\tc #DCDDDD\",\n\"|,\tc #6A8591\",\n\"1,\tc #046993\",\n\"2,\tc #049ACE\",\n\"3,\tc #2D3334\",\n\"4,\tc #009AD5\",\n\"5,\tc #2B9CCC\",\n\"6,\tc #B3CED8\",\n\"7,\tc #E3E3E3\",\n\"8,\tc #DFE0E0\",\n\"9,\tc #7FA9BC\",\n\"0,\tc #0A88BD\",\n\"a,\tc #1B9DD5\",\n\"b,\tc #9BCBDE\",\n\"c,\tc #E1E2E4\",\n\"d,\tc #C9CDCE\",\n\"e,\tc #476B7D\",\n\"f,\tc #0277A6\",\n\"g,\tc #0499CE\",\n\"h,\tc #1F5367\",\n\"i,\tc #302825\",\n\"j,\tc #2D2E2E\",\n\"k,\tc #146F8F\",\n\"l,\tc #01A0D8\",\n\"m,\tc #1295CD\",\n\"n,\tc #88BCD2\",\n\"o,\tc #B3C6CE\",\n\"p,\tc #2988B3\",\n\"q,\tc #0196D1\",\n\"r,\tc #0299D4\",\n\"s,\tc #40AAD7\",\n\"t,\tc #C3D8E0\",\n\"u,\tc #AEB8BB\",\n\"v,\tc #235B75\",\n\"w,\tc #0084B8\",\n\"x,\tc #2F2825\",\n\"y,\tc #2D3234\",\n\"z,\tc #2D2C2C\",\n\"A,\tc #2E2B2B\",\n\"B,\tc #019FD7\",\n\"C,\tc #009AD4\",\n\"D,\tc #0595D1\",\n\"E,\tc #56A5C9\",\n\"F,\tc #CFD9DD\",\n\"G,\tc #E2E2E2\",\n\"H,\tc #D6DADC\",\n\"I,\tc #639EB8\",\n\"J,\tc #088DC5\",\n\"K,\tc #0D99D4\",\n\"L,\tc #7DBFDB\",\n\"M,\tc #DADFE2\",\n\"N,\tc #DEDEDE\",\n\"O,\tc #88969D\",\n\"P,\tc #0F5B7E\",\n\"Q,\tc #0092C8\",\n\"R,\tc #0498CD\",\n\"S,\tc #1E5366\",\n\"T,\tc #2D2B2B\",\n\"U,\tc #136F8E\",\n\"V,\tc #0198D3\",\n\"W,\tc #2798C8\",\n\"X,\tc #AFCAD5\",\n\"Y,\tc #E1E1E1\",\n\"Z,\tc #ABC3CC\",\n\"`,\tc #288DBA\",\n\" '\tc #0197D2\",\n\".'\tc #0197D3\",\n\"+'\tc #2FA3D5\",\n\"@'\tc #E1E1E2\",\n\"#'\tc #D2D5D5\",\n\"$'\tc #547180\",\n\"%'\tc #056993\",\n\"&'\tc #0098D1\",\n\"*'\tc #1E5365\",\n\"='\tc #2C3233\",\n\"-'\tc #2D2B2A\",\n\";'\tc #136E8E\",\n\">'\tc #019ED6\",\n\",'\tc #0099D3\",\n\"''\tc #0C92CA\",\n\")'\tc #7AB2CA\",\n\"!'\tc #D8DCDD\",\n\"~'\tc #E0E0E0\",\n\"{'\tc #D4D9DB\",\n\"]'\tc #6EA7C1\",\n\"^'\tc #0A8EC6\",\n\"/'\tc #0B97D2\",\n\"('\tc #6FB8D8\",\n\"_'\tc #D6DDE0\",\n\":'\tc #B5BBBD\",\n\"<'\tc #2A566E\",\n\"['\tc #0497CC\",\n\"}'\tc #1E5265\",\n\"|'\tc #292B2B\",\n\"1'\tc #019ED5\",\n\"2'\tc #0295CF\",\n\"3'\tc #3B9AC3\",\n\"4'\tc #BECFD6\",\n\"5'\tc #DFDFE0\",\n\"6'\tc #DFDFDF\",\n\"7'\tc #BCCDD4\",\n\"8'\tc #4198BF\",\n\"9'\tc #0493CC\",\n\"0'\tc #0296D1\",\n\"a'\tc #3BA5D3\",\n\"b'\tc #B7D2DD\",\n\"c'\tc #DADBDB\",\n\"d'\tc #7C8A93\",\n\"e'\tc #0B5678\",\n\"f'\tc #0090C6\",\n\"g'\tc #009AD3\",\n\"h'\tc #0497CB\",\n\"i'\tc #136D8D\",\n\"j'\tc #019DD4\",\n\"k'\tc #128FC4\",\n\"l'\tc #84B4C7\",\n\"m'\tc #D8DBDC\",\n\"n'\tc #DCDEDE\",\n\"o'\tc #A3C2CF\",\n\"p'\tc #2D95C3\",\n\"q'\tc #0394CF\",\n\"r'\tc #0098D2\",\n\"s'\tc #0096D0\",\n\"t'\tc #1E9BD1\",\n\"u'\tc #96C5DA\",\n\"v'\tc #DADDDF\",\n\"w'\tc #C0C4C6\",\n\"x'\tc #3A5B6C\",\n\"y'\tc #026D99\",\n\"z'\tc #0496CA\",\n\"A'\tc #1E5165\",\n\"B'\tc #2F2824\",\n\"C'\tc #2C3133\",\n\"D'\tc #2D2A2A\",\n\"E'\tc #136D8C\",\n\"F'\tc #0097D0\",\n\"G'\tc #0292CC\",\n\"H'\tc #3D96BC\",\n\"I'\tc #B9CAD1\",\n\"J'\tc #DEDFDE\",\n\"K'\tc #D7DBDC\",\n\"L'\tc #90BBCE\",\n\"M'\tc #2695C7\",\n\"N'\tc #0294CF\",\n\"O'\tc #1196D0\",\n\"P'\tc #74B8D6\",\n\"Q'\tc #D1DADD\",\n\"R'\tc #D8D9D9\",\n\"S'\tc #88949A\",\n\"T'\tc #104D6A\",\n\"U'\tc #0088BB\",\n\"V'\tc #0099D1\",\n\"W'\tc #1E5164\",\n\"X'\tc #2F2724\",\n\"Y'\tc #2C2C2B\",\n\"Z'\tc #2C2A29\",\n\"`'\tc #136C8C\",\n\" )\tc #019CD3\",\n\".)\tc #0097CF\",\n\"+)\tc #108BC0\",\n\"@)\tc #78AAC0\",\n\"#)\tc #D4D8D9\",\n\"$)\tc #DDDDDE\",\n\"%)\tc #D3D8DB\",\n\"&)\tc #8DBACE\",\n\"*)\tc #2998C9\",\n\"=)\tc #0394CE\",\n\"-)\tc #0195CF\",\n\";)\tc #1196CF\",\n\">)\tc #63B1D4\",\n\",)\tc #C7D6DC\",\n\"')\tc #DDDDDD\",\n\"))\tc #BCC0C2\",\n\"!)\tc #425C6C\",\n\"~)\tc #02658D\",\n\"{)\tc #0095CC\",\n\"])\tc #0495C9\",\n\"^)\tc #2E2724\",\n\"/)\tc #2B3132\",\n\"()\tc #2C2B2B\",\n\"_)\tc #136C8B\",\n\":)\tc #019CD2\",\n\"<)\tc #0292CB\",\n\"[)\tc #2D8DB7\",\n\"})\tc #A9C0C9\",\n\"|)\tc #DCDCDC\",\n\"1)\tc #D4D9DA\",\n\"2)\tc #9AC1D2\",\n\"3)\tc #399DCB\",\n\"4)\tc #0893CC\",\n\"5)\tc #0096CF\",\n\"6)\tc #0294CE\",\n\"7)\tc #1A98CF\",\n\"8)\tc #6CB3D4\",\n\"9)\tc #C4D4DB\",\n\"0)\tc #D2D3D4\",\n\"a)\tc #78848C\",\n\"b)\tc #114A67\",\n\"c)\tc #0084B6\",\n\"d)\tc #0495C8\",\n\"e)\tc #1E5163\",\n\"f)\tc #29292B\",\n\"g)\tc #2B3133\",\n\"h)\tc #136B8A\",\n\"i)\tc #019BD1\",\n\"j)\tc #088BC1\",\n\"k)\tc #5798B4\",\n\"l)\tc #C7CFD2\",\n\"m)\tc #D6DADB\",\n\"n)\tc #ABC7D5\",\n\"o)\tc #55A7CD\",\n\"p)\tc #1695CC\",\n\"q)\tc #0294CD\",\n\"r)\tc #0195CE\",\n\"s)\tc #0993CE\",\n\"t)\tc #2F9ED0\",\n\"u)\tc #80BBD5\",\n\"v)\tc #C8D5DB\",\n\"w)\tc #DBDCDC\",\n\"x)\tc #DADADB\",\n\"y)\tc #A7ADB1\",\n\"z)\tc #2E4D60\",\n\"A)\tc #026690\",\n\"B)\tc #0094CB\",\n\"C)\tc #0494C7\",\n\"D)\tc #1E5063\",\n\"E)\tc #2C3234\",\n\"F)\tc #2D2927\",\n\"G)\tc #146884\",\n\"H)\tc #019BD0\",\n\"I)\tc #0094CC\",\n\"J)\tc #1484B5\",\n\"K)\tc #81A8BA\",\n\"L)\tc #D4D6D7\",\n\"M)\tc #D9DADB\",\n\"N)\tc #C3D1D8\",\n\"O)\tc #83B9D2\",\n\"P)\tc #349ECD\",\n\"Q)\tc #0D94CC\",\n\"R)\tc #0293CD\",\n\"S)\tc #0096CD\",\n\"T)\tc #0493CD\",\n\"U)\tc #1C98CE\",\n\"V)\tc #56ABD2\",\n\"W)\tc #A4C7D7\",\n\"X)\tc #D2D8DB\",\n\"Y)\tc #DBDBDB\",\n\"Z)\tc #C7C9CA\",\n\"`)\tc #586B76\",\n\" !\tc #084E6F\",\n\".!\tc #0087BB\",\n\"+!\tc #0493C7\",\n\"@!\tc #1E4F61\",\n\"#!\tc #2D2724\",\n\"$!\tc #262626\",\n\"%!\tc #2E3437\",\n\"&!\tc #2D2725\",\n\"*!\tc #176179\",\n\"=!\tc #029ACD\",\n\"-!\tc #0095CD\",\n\";!\tc #018FC7\",\n\">!\tc #2A83AB\",\n\",!\tc #A3B8C1\",\n\"'!\tc #D9DADA\",\n\")!\tc #B2CCD6\",\n\"!!\tc #77B7D2\",\n\"~!\tc #3FA3CE\",\n\"{!\tc #1998CD\",\n\"]!\tc #0992CC\",\n\"^!\tc #0392CC\",\n\"/!\tc #0093CC\",\n\"(!\tc #0093CD\",\n\"_!\tc #0492CC\",\n\":!\tc #0D93CC\",\n\"<!\tc #249BCE\",\n\"[!\tc #55ABD1\",\n\"}!\tc #94C1D6\",\n\"|!\tc #C7D3D9\",\n\"1!\tc #D1D2D3\",\n\"2!\tc #7F8990\",\n\"3!\tc #16455D\",\n\"4!\tc #0075A3\",\n\"5!\tc #0491C4\",\n\"6!\tc #1F4C5C\",\n\"7!\tc #242525\",\n\"8!\tc #30383A\",\n\"9!\tc #2E2624\",\n\"0!\tc #1B586C\",\n\"a!\tc #0297CB\",\n\"b!\tc #0488BE\",\n\"c!\tc #4286A6\",\n\"d!\tc #B5C1C7\",\n\"e!\tc #D9D9D9\",\n\"f!\tc #DBDBDA\",\n\"g!\tc #DADADA\",\n\"h!\tc #BED0D7\",\n\"i!\tc #9BC3D5\",\n\"j!\tc #6FB3D2\",\n\"k!\tc #4EA9D0\",\n\"l!\tc #36A0CE\",\n\"m!\tc #289ACD\",\n\"n!\tc #2198CD\",\n\"o!\tc #1D97CD\",\n\"p!\tc #1C96CD\",\n\"q!\tc #1E97CD\",\n\"r!\tc #2298CD\",\n\"s!\tc #2A9BCD\",\n\"t!\tc #3AA3CF\",\n\"u!\tc #55ACD1\",\n\"v!\tc #7CB8D3\",\n\"w!\tc #AAC9D6\",\n\"x!\tc #C9D4D9\",\n\"y!\tc #D8D9DA\",\n\"z!\tc #D6D6D6\",\n\"A!\tc #9BA1A5\",\n\"B!\tc #284558\",\n\"C!\tc #01638A\",\n\"D!\tc #0090C5\",\n\"E!\tc #058DC0\",\n\"F!\tc #214553\",\n\"G!\tc #2D2826\",\n\"H!\tc #2F3538\",\n\"I!\tc #2D2624\",\n\"J!\tc #1D4F62\",\n\"K!\tc #0393C9\",\n\"L!\tc #0882B5\",\n\"M!\tc #5088A3\",\n\"N!\tc #BAC3C8\",\n\"O!\tc #D8D8D8\",\n\"P!\tc #D7D8D9\",\n\"Q!\tc #D1D6D9\",\n\"R!\tc #CBD4D8\",\n\"S!\tc #BCCFD7\",\n\"T!\tc #ABC9D6\",\n\"U!\tc #A1C6D5\",\n\"V!\tc #9DC5D5\",\n\"W!\tc #9BC4D5\",\n\"X!\tc #9EC5D5\",\n\"Y!\tc #A3C7D6\",\n\"Z!\tc #ADCAD6\",\n\"`!\tc #BFD0D7\",\n\" ~\tc #CCD5D8\",\n\".~\tc #D3D7D9\",\n\"+~\tc #D7D7D7\",\n\"@~\tc #A9ADB0\",\n\"#~\tc #384F5D\",\n\"$~\tc #045577\",\n\"%~\tc #0097CE\",\n\"&~\tc #0984AE\",\n\"*~\tc #263940\",\n\"=~\tc #2C2927\",\n\"-~\tc #252728\",\n\";~\tc #40545B\",\n\">~\tc #354347\",\n\",~\tc #232424\",\n\"'~\tc #2C2826\",\n\")~\tc #22424E\",\n\"!~\tc #058DBF\",\n\"~~\tc #0A7DAE\",\n\"{~\tc #5788A0\",\n\"]~\tc #B9C1C5\",\n\"^~\tc #D6D7D7\",\n\"/~\tc #D8D8D9\",\n\"(~\tc #B0B3B5\",\n\"_~\tc #40525F\",\n\":~\tc #054C6B\",\n\"<~\tc #0082B3\",\n\"[~\tc #0198CC\",\n\"}~\tc #0E7A9C\",\n\"|~\tc #292F31\",\n\"1~\tc #2C2928\",\n\"2~\tc #2A2929\",\n\"3~\tc #252626\",\n\"4~\tc #37454A\",\n\"5~\tc #283236\",\n\"6~\tc #0B82A9\",\n\"7~\tc #0096CC\",\n\"8~\tc #0093CA\",\n\"9~\tc #0D7BA9\",\n\"0~\tc #518299\",\n\"a~\tc #B1BBBF\",\n\"b~\tc #D5D5D5\",\n\"c~\tc #D8D7D7\",\n\"d~\tc #D4D4D5\",\n\"e~\tc #ADB0B2\",\n\"f~\tc #445461\",\n\"g~\tc #074865\",\n\"h~\tc #007DAC\",\n\"i~\tc #0093C9\",\n\"j~\tc #0196CB\",\n\"k~\tc #136A87\",\n\"l~\tc #2B2A2A\",\n\"m~\tc #2B2A29\",\n\"n~\tc #2A2F30\",\n\"o~\tc #262A2C\",\n\"p~\tc #116E8E\",\n\"q~\tc #0092C9\",\n\"r~\tc #0090C7\",\n\"s~\tc #0B78A7\",\n\"t~\tc #4A7C95\",\n\"u~\tc #A6B2B7\",\n\"v~\tc #CFD0D1\",\n\"w~\tc #D0D1D1\",\n\"x~\tc #A2A6AA\",\n\"y~\tc #40515E\",\n\"z~\tc #074664\",\n\"A~\tc #007AA9\",\n\"B~\tc #0491C2\",\n\"C~\tc #1D4E5F\",\n\"D~\tc #2C2725\",\n\"E~\tc #2A3436\",\n\"F~\tc #282F32\",\n\"G~\tc #1B5165\",\n\"H~\tc #0394C5\",\n\"I~\tc #077BAA\",\n\"J~\tc #33718E\",\n\"K~\tc #8A9CA6\",\n\"L~\tc #C8C9CB\",\n\"M~\tc #C9C9CA\",\n\"N~\tc #8D9297\",\n\"O~\tc #304856\",\n\"P~\tc #054A68\",\n\"Q~\tc #007BAA\",\n\"R~\tc #0091C7\",\n\"S~\tc #0983AD\",\n\"T~\tc #25393F\",\n\"U~\tc #2D3336\",\n\"V~\tc #2C2726\",\n\"W~\tc #0884AF\",\n\"X~\tc #0094CA\",\n\"Y~\tc #037EB0\",\n\"Z~\tc #20698C\",\n\"`~\tc #6A8594\",\n\" {\tc #B2B9BC\",\n\".{\tc #D1D1D1\",\n\"+{\tc #B6B8BA\",\n\"@{\tc #70767E\",\n\"#{\tc #223E4F\",\n\"${\tc #025172\",\n\"%{\tc #007FAF\",\n\"&{\tc #0195C9\",\n\"*{\tc #126988\",\n\"={\tc #2B2929\",\n\"-{\tc #222425\",\n\";{\tc #3C494F\",\n\">{\tc #3A4A51\",\n\",{\tc #222525\",\n\"'{\tc #2B2928\",\n\"){\tc #136885\",\n\"!{\tc #0185B9\",\n\"~{\tc #0E6A92\",\n\"{{\tc #426D83\",\n\"]{\tc #95A0A7\",\n\"^{\tc #C5C6C7\",\n\"/{\tc #D3D3D3\",\n\"({\tc #D4D4D4\",\n\"_{\tc #C7C8C9\",\n\":{\tc #989C9F\",\n\"<{\tc #475561\",\n\"[{\tc #113A51\",\n\"}{\tc #015D82\",\n\"|{\tc #0084B5\",\n\"1{\tc #048EBE\",\n\"2{\tc #1E4B5B\",\n\"3{\tc #2C2625\",\n\"4{\tc #282D2E\",\n\"5{\tc #2B2625\",\n\"6{\tc #204552\",\n\"7{\tc #058CBA\",\n\"8{\tc #0474A2\",\n\"9{\tc #1E6080\",\n\"0{\tc #5C7887\",\n\"a{\tc #9FA6AB\",\n\"b{\tc #C7C8C8\",\n\"c{\tc #D2D2D2\",\n\"d{\tc #CACBCB\",\n\"e{\tc #A6A9AB\",\n\"f{\tc #646C75\",\n\"g{\tc #044865\",\n\"h{\tc #006F9A\",\n\"i{\tc #0089BE\",\n\"j{\tc #0D789D\",\n\"k{\tc #2B2827\",\n\"l{\tc #242323\",\n\"m{\tc #313D42\",\n\"n{\tc #2E3B3E\",\n\"o{\tc #232323\",\n\"p{\tc #2A2928\",\n\"q{\tc #0F7090\",\n\"r{\tc #0193C6\",\n\"s{\tc #008FC6\",\n\"t{\tc #0084B7\",\n\"u{\tc #066993\",\n\"v{\tc #215B77\",\n\"w{\tc #597381\",\n\"x{\tc #919BA1\",\n\"y{\tc #B7B9BB\",\n\"z{\tc #D0D0D0\",\n\"A{\tc #CDCECE\",\n\"B{\tc #C1C2C3\",\n\"C{\tc #9FA2A6\",\n\"D{\tc #676F77\",\n\"E{\tc #284050\",\n\"F{\tc #083F59\",\n\"G{\tc #006187\",\n\"H{\tc #0081B1\",\n\"I{\tc #008EC3\",\n\"J{\tc #048FBE\",\n\"K{\tc #1B5163\",\n\"L{\tc #2B2725\",\n\"M{\tc #2A2A29\",\n\"N{\tc #232627\",\n\"O{\tc #374B52\",\n\"P{\tc #242729\",\n\"Q{\tc #2B2624\",\n\"R{\tc #1F4451\",\n\"S{\tc #0689B4\",\n\"T{\tc #0091C6\",\n\"U{\tc #008FC4\",\n\"V{\tc #0081B2\",\n\"W{\tc #066892\",\n\"X{\tc #185877\",\n\"Y{\tc #3D6174\",\n\"Z{\tc #687B86\",\n\"`{\tc #969DA1\",\n\" ]\tc #B3B6B8\",\n\".]\tc #C5C6C6\",\n\"+]\tc #CECECE\",\n\"@]\tc #CBCBCB\",\n\"#]\tc #BDBEBF\",\n\"$]\tc #7D848A\",\n\"%]\tc #4E5D67\",\n\"&]\tc #233E50\",\n\"*]\tc #08415D\",\n\"=]\tc #015F84\",\n\"-]\tc #007CAB\",\n\";]\tc #008CC0\",\n\">]\tc #008EC4\",\n\",]\tc #0E7394\",\n\"']\tc #282E31\",\n\")]\tc #2A2827\",\n\"!]\tc #252525\",\n\"~]\tc #2B3337\",\n\"{]\tc #2A2828\",\n\"]]\tc #14637C\",\n\"^]\tc #0291C2\",\n\"/]\tc #008DC2\",\n\"(]\tc #0083B5\",\n\"_]\tc #02719D\",\n\":]\tc #095B80\",\n\"<]\tc #18526E\",\n\"[]\tc #33586B\",\n\"}]\tc #5A707C\",\n\"|]\tc #78888F\",\n\"1]\tc #939CA1\",\n\"2]\tc #A7ABAE\",\n\"3]\tc #B3B5B7\",\n\"4]\tc #C0C1C2\",\n\"5]\tc #C8C9CA\",\n\"6]\tc #C9CACB\",\n\"7]\tc #C9CBCB\",\n\"8]\tc #C6C7C8\",\n\"9]\tc #BFC0C1\",\n\"0]\tc #A1A6A9\",\n\"a]\tc #899296\",\n\"b]\tc #6B787F\",\n\"c]\tc #475864\",\n\"d]\tc #224253\",\n\"e]\tc #0F3D55\",\n\"f]\tc #034C6B\",\n\"g]\tc #00668E\",\n\"h]\tc #007EAD\",\n\"i]\tc #008BBF\",\n\"j]\tc #058AB7\",\n\"k]\tc #1F4654\",\n\"l]\tc #323D40\",\n\"m]\tc #2A2725\",\n\"n]\tc #24373E\",\n\"o]\tc #0A7CA1\",\n\"p]\tc #0091C4\",\n\"q]\tc #008EC2\",\n\"r]\tc #008ABD\",\n\"s]\tc #0080B1\",\n\"t]\tc #016F9B\",\n\"u]\tc #036186\",\n\"v]\tc #095475\",\n\"w]\tc #194F69\",\n\"x]\tc #275065\",\n\"y]\tc #305465\",\n\"z]\tc #41606E\",\n\"A]\tc #526A76\",\n\"B]\tc #5D707B\",\n\"C]\tc #63737C\",\n\"D]\tc #65747D\",\n\"E]\tc #66747D\",\n\"F]\tc #65737C\",\n\"G]\tc #63727A\",\n\"H]\tc #5E6E77\",\n\"I]\tc #526771\",\n\"J]\tc #3E5966\",\n\"K]\tc #2F4B5B\",\n\"L]\tc #234557\",\n\"M]\tc #124158\",\n\"N]\tc #054764\",\n\"O]\tc #025475\",\n\"P]\tc #00668D\",\n\"Q]\tc #0078A6\",\n\"R]\tc #0085B7\",\n\"S]\tc #0191C3\",\n\"T]\tc #13637E\",\n\"U]\tc #242425\",\n\"V]\tc #252A2C\",\n\"W]\tc #2B3437\",\n\"X]\tc #222323\",\n\"Y]\tc #292928\",\n\"Z]\tc #2A2625\",\n\"`]\tc #1C4A59\",\n\" ^\tc #0588B2\",\n\".^\tc #008FC3\",\n\"+^\tc #008DC1\",\n\"@^\tc #008ABE\",\n\"#^\tc #007CAC\",\n\"$^\tc #0174A1\",\n\"%^\tc #016B95\",\n\"&^\tc #026189\",\n\"*^\tc #05597E\",\n\"=^\tc #085376\",\n\"-^\tc #095070\",\n\";^\tc #094D6D\",\n\">^\tc #0A4C6A\",\n\",^\tc #094B6A\",\n\"'^\tc #094C6C\",\n\")^\tc #055274\",\n\"!^\tc #025A7E\",\n\"~^\tc #016C96\",\n\"{^\tc #0076A3\",\n\"]^\tc #0080B0\",\n\"^^\tc #0087BA\",\n\"/^\tc #008DC3\",\n\"(^\tc #0191C4\",\n\"_^\tc #0C789C\",\n\":^\tc #253339\",\n\"<^\tc #212425\",\n\"[^\tc #303E41\",\n\"}^\tc #292827\",\n\"|^\tc #292828\",\n\"1^\tc #17576D\",\n\"2^\tc #048CBA\",\n\"3^\tc #0089BD\",\n\"4^\tc #0088BA\",\n\"5^\tc #0086B8\",\n\"6^\tc #0085B8\",\n\"7^\tc #008FC2\",\n\"8^\tc #0884AC\",\n\"9^\tc #20414C\",\n\"0^\tc #2A2523\",\n\"a^\tc #2A3439\",\n\"b^\tc #2F3A41\",\n\"c^\tc #212324\",\n\"d^\tc #2A2726\",\n\"e^\tc #282B2C\",\n\"f^\tc #156179\",\n\"g^\tc #038EBC\",\n\"h^\tc #0688B3\",\n\"i^\tc #1B4E5E\",\n\"j^\tc #2A2624\",\n\"k^\tc #232729\",\n\"l^\tc #3A4F57\",\n\"m^\tc #222222\",\n\"n^\tc #272C2E\",\n\"o^\tc #13657F\",\n\"p^\tc #028EBF\",\n\"q^\tc #008EC1\",\n\"r^\tc #0589B5\",\n\"s^\tc #195367\",\n\"t^\tc #202223\",\n\"u^\tc #2B383B\",\n\"v^\tc #1F2123\",\n\"w^\tc #242424\",\n\"x^\tc #292524\",\n\"y^\tc #272D2F\",\n\"z^\tc #126580\",\n\"A^\tc #038DBD\",\n\"B^\tc #008BBE\",\n\"C^\tc #008EC0\",\n\"D^\tc #0684AD\",\n\"E^\tc #195164\",\n\"F^\tc #292727\",\n\"G^\tc #292626\",\n\"H^\tc #212222\",\n\"I^\tc #2B393C\",\n\"J^\tc #212527\",\n\"K^\tc #252524\",\n\"L^\tc #292625\",\n\"M^\tc #272B2B\",\n\"N^\tc #165B72\",\n\"O^\tc #008DBF\",\n\"P^\tc #018EBE\",\n\"Q^\tc #0A7B9F\",\n\"R^\tc #1D4552\",\n\"S^\tc #2A2524\",\n\"T^\tc #292726\",\n\"U^\tc #212121\",\n\"V^\tc #222728\",\n\"W^\tc #314348\",\n\"X^\tc #1C4A57\",\n\"Y^\tc #0A7A9E\",\n\"Z^\tc #018DBD\",\n\"`^\tc #008CBF\",\n\" /\tc #038AB7\",\n\"./\tc #106A87\",\n\"+/\tc #22393F\",\n\"@/\tc #272F33\",\n\"#/\tc #303E43\",\n\"$/\tc #202526\",\n\"%/\tc #282726\",\n\"&/\tc #292423\",\n\"*/\tc #22373E\",\n\"=/\tc #12637E\",\n\"-/\tc #0584AF\",\n\";/\tc #018CBD\",\n\">/\tc #0089BC\",\n\",/\tc #028BBC\",\n\"'/\tc #097CA1\",\n\")/\tc #195265\",\n\"!/\tc #262C2D\",\n\"~/\tc #292523\",\n\"{/\tc #282827\",\n\"]/\tc #1E2223\",\n\"^/\tc #324148\",\n\"//\tc #212729\",\n\"(/\tc #272829\",\n\"_/\tc #1E424D\",\n\":/\tc #0F6A88\",\n\"</\tc #018BBC\",\n\"[/\tc #008BBD\",\n\"}/\tc #008CBD\",\n\"|/\tc #028BBA\",\n\"1/\tc #0780A7\",\n\"2/\tc #145E76\",\n\"3/\tc #23363C\",\n\"4/\tc #272626\",\n\"5/\tc #364C54\",\n\"6/\tc #262D31\",\n\"7/\tc #202121\",\n\"8/\tc #282626\",\n\"9/\tc #1D434F\",\n\"0/\tc #11647F\",\n\"a/\tc #087DA6\",\n\"b/\tc #0389B7\",\n\"c/\tc #018ABD\",\n\"d/\tc #008ABC\",\n\"e/\tc #018BBB\",\n\"f/\tc #0486B2\",\n\"g/\tc #0A769B\",\n\"h/\tc #155A71\",\n\"i/\tc #213A43\",\n\"j/\tc #1F2223\",\n\"k/\tc #252F33\",\n\"l/\tc #273034\",\n\"m/\tc #1F2122\",\n\"n/\tc #282422\",\n\"o/\tc #213942\",\n\"p/\tc #175265\",\n\"q/\tc #0E6B8B\",\n\"r/\tc #077EA5\",\n\"s/\tc #0484B2\",\n\"t/\tc #0287B9\",\n\"u/\tc #018ABB\",\n\"v/\tc #008BBB\",\n\"w/\tc #008ABB\",\n\"x/\tc #018ABA\",\n\"y/\tc #0189BA\",\n\"z/\tc #0286B8\",\n\"A/\tc #0582AE\",\n\"B/\tc #09799E\",\n\"C/\tc #11627D\",\n\"D/\tc #1B4958\",\n\"E/\tc #243237\",\n\"F/\tc #292422\",\n\"G/\tc #1E2021\",\n\"H/\tc #2A393E\",\n\"I/\tc #242E33\",\n\"J/\tc #21383F\",\n\"K/\tc #1B4453\",\n\"L/\tc #16556B\",\n\"M/\tc #135E78\",\n\"N/\tc #11637E\",\n\"O/\tc #0F6784\",\n\"P/\tc #0D6A89\",\n\"Q/\tc #0D6B8A\",\n\"R/\tc #0D6A8A\",\n\"S/\tc #0E6988\",\n\"T/\tc #106682\",\n\"U/\tc #135C76\",\n\"V/\tc #174F64\",\n\"W/\tc #1E3F4B\",\n\"X/\tc #223338\",\n\"Y/\tc #282321\",\n\"Z/\tc #282523\",\n\"`/\tc #202021\",\n\" (\tc #22282A\",\n\".(\tc #2C383E\",\n\"+(\tc #384F57\",\n\"@(\tc #283237\",\n\"#(\tc #202324\",\n\"$(\tc #262525\",\n\"%(\tc #282524\",\n\"&(\tc #282423\",\n\"*(\tc #262829\",\n\"=(\tc #282525\",\n\"-(\tc #292322\",\n\";(\tc #272625\",\n\">(\tc #202425\",\n\",(\tc #2B353B\",\n\"'(\tc #304149\",\n\")(\tc #252E31\",\n\"!(\tc #2C383D\",\n\"~(\tc #35474D\",\n\"{(\tc #2B363B\",\n\"](\tc #232728\",\n\"^(\tc #1F2222\",\n\"/(\tc #252C2F\",\n\"((\tc #293439\",\n\"_(\tc #334147\",\n\":(\tc #2C393C\",\n\"<(\tc #232B2D\",\n\"[(\tc #202020\",\n\"}(\tc #222729\",\n\"|(\tc #282F33\",\n\"1(\tc #303E44\",\n\"2(\tc #374A52\",\n\"3(\tc #3B4F59\",\n\"4(\tc #2F3D44\",\n\"5(\tc #2C363A\",\n\"6(\tc #272D30\",\n\"7(\tc #232628\",\n\"8(\tc #232829\",\n\"9(\tc #242829\",\n\"0(\tc #242728\",\n\"a(\tc #2A3133\",\n\"b(\tc #2D393D\",\n\"c(\tc #2E3A40\",\n\"d(\tc #344248\",\n\"e(\tc #3E5861\",\n\"f(\tc #455D66\",\n\"g(\tc #465F69\",\n\"h(\tc #485F67\",\n\"i(\tc #485F69\",\n\"j(\tc #495F69\",\n\"k(\tc #465F67\",\n\"l(\tc #465F68\",\n\"                                                                                                                                                                                                                                                                \",\n\"                                                                                                                                                                                                                                                                \",\n\"                                                                                                                                                                                                                                                                \",\n\"                                                                                                                                                                                                                                                                \",\n\"                                                                  . + @ # $ % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % & * = -                                                                   \",\n\"                                                        ; > , ' ) ! ~ { ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ^ / ( _ : < [ } |                                                         \",\n\"                                                  1 2 3 4 5 6 7 8 8 8 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 8 8 8 8 0 / 4 a b c d                                                   \",\n\"                                              e f g h 7 8 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 8 0 ] i j k                                               \",\n\"                                          l m 5 n 9 9 9 9 o p q r s t t u t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t u t u v w p x 9 9 9 9 x h y z A                                           \",\n\"                                      B ' 5 7 9 9 9 C p D E F G H I J K L M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M N O P Q R S T T F x 9 9 9 9 U V b W                                       \",\n\"                                    X Y 7 9 9 9 x w v x Z `  ...+.@.#.$.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.&.#.*.=.-.;.>.,.'.E ).9 9 9 C !.) ~.                                    \",\n\"                                {.].{ 9 9 9 x F v ^./.(._.:.<.[.}.|.1.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.1.3.4.[.5.6.7.8.9.9 E q 9 9 9 8 0.a.                                  \",\n\"                              b._ 0 9 9 9 p v c.d.e.f.g.h.i.2.j.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.k.}.l.m.n.o.x D x 9 9 9 / p.q.                              \",\n\"                            r.s.7 9 9 o r C K t.u.v.w.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.1.w.x.y.z.A.T ).9 9 9 0 B.C.                            \",\n\"                          D.E.8 9 9 x F.G.H.I.J.i.K.L.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.2.L.L.w.l.M.N.O.r o 9 9 0 : P.                          \",\n\"                        Q.R.8 9 o x v S.T.U.w.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.v.V.W.X.T 9 C 9 0 i Y.                        \",\n\"                      Z.s.`.9 9 x E  +.+++@+L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.w.#+$+%+&+9 9 9 h *+                        \",\n\"                      m 7 9 9 p F.>.=+-+L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.;+>+,+'+F.9 9 9 5 )+                      \",\n\"                    !+] 9 9 x E ~+{+-+K.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.++]+^+/+9 9 8 Y (+                    \",\n\"                  _+0.9 9 o F.:+<+[+L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.K.L.++}+|+F 9 9 7 1+2+                  \",\n\"                  3+7 9 C T 4+5+J.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.K.K.K.6+7+8+9+0+0+0+9+9+8+a+K.K.K.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.@+b+c+C q 9 9 6 d+                  \",\n\"                !+/ 9 9 e+f+g+l.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.K.h+i+j+k+l+m+n+o+p+q+r+q+s+t+u+v+w+x+y+z+h+h+K.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.A+w.u.B+T x 9 x C+D+                \",\n\"                s.`.8 E+v F+G+;+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+H+7+I+J+K+L+M+N+O+P+Q+R+S+T+U+U+S+V+W+X+Y+Z+`+ @.@+@@@#@$@A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+%@&@*@T 8 8 U =@                \",\n\"              i / 8 8 -@;@>@,@A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+'@)@!@~@{@]@^@/@(@_@:@<@[@[@[@[@[@[@[@[@[@[@}@|@1@2@3@4@5@6@7@8@9@H+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+0@a@b@b@8 7 c@m               \",\n\"              d@7 8 e@f@g@h@A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+'@i@j@k@l@m@n@o@p@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@}@q@r@s@t@u@v@w@H+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+,@x@y@z@8 8 6 A@              \",\n\"            B@0.8 8 f@;@C@D@A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+E@F@G@H@I@/@1@<@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@}@J@K@L@M@N@E@A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+O@P@`.b@8 8 Q@R@            \",\n\"            S@U 8 `.T@U@V@A+W@A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+H+#@X@Y@Z@`@ #[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@[@.#+#@###$#%#W@A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+A+W@;+&#*#=#8 8 5 -#            \",\n\"          ;#g 7 8 >#,#'#,@)#W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@!#~#{#]#^#/#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#(#_#:#<#[#}#W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@H+|#1#-@`.8 0 2#            \",\n\"          3#/ 8 8 4#5#6#A+W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@}#7#8#9#0#a#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#b#c#d#e#}#W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@,@f#g#-@8 7 C+h#          \",\n\"          i#/ 8 `.f@j#k#W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@}#l#m#n#`@(#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#o#p#q#r#!#W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@L.s#t#T@8 8 5 u#          \",\n\"          v#0 8 f@w#x#y#z#W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@}#A#B#C#D#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#(#E#F#G#'@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@A+H#I#J#e@8 5 B@          \",\n\"        K#V 8 8 =#L#M#@+)#W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@}#l#N#O#P#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#Q#R#S#T#}#)#W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@W@)#k#U#V#W#8 h X#          \",\n\"        Y#y 8 8 Z#`# $A+)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#.$+$@$#$Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#$$%$&$*$=$-$;$>$,$'$)$!$~$Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#{$]$^$/$)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#y#($_$:$8 7 R.          \",\n\"        <$5 8 8 [$}$|$W@)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#1$2$3$b#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#4$5$6$7$8$9$0$a$b$c$d$e$f$g$h$i$j$$$Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#k$l$m$n$)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#@+o$p$=#8 7 3+          \",\n\"        q$] 8 8 r$s$t$)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#z#u$v$+#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#w$x$y$z$A$B$C$D$E$F$G$H$I$J$K$L$M$N$O$P$Q$$$Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#R$S$T$U$)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#K.V$W$Z#8 8 X$Y$        \",\n\"        Z$h 8 8 `$ %.%)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#z#+%@%#%Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#%$$%%%&%*%=%-%;%>%,%'%)%!%!%!%~%{%]%^%/%(%_%:%<%%$Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#Q#[%}%|%z#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#)#A+1%2%3%8 8 y 4%        \",\n\"        5%h 8 E+f@6%.%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%7%8%9%~$$$$$$$$$$$$$$$$$$$$$$$$$$$~$0%a%b%c%d%e%f%{%)#W@)#)#)#)#)#)#)#z#W@W@!%g%h%i%j%k%l%$$$$$$$$$$$$$$$$$$$$$$$$$$%$m%n%o%)#!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%)#p%q%r$8 8 4 r%        \",\n\"        ^.0 8 `.>#s%k#!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%t%u%v%w%$$$$$$$$$$$$$$$$$$$$$$$$$$%$x%y%z%A%e%B%!%)#)#!%!%~%!%!%!%!%!%!%!%U$!%!%)#W@C%D%E%F%G%$$$$$$$$$$$$$$$$$$$$$$$$$$H%I%J%K%U$!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%)#p%L%r$8 8 5 <$        \",\n\"        M%0 8 `.W#N%k#!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%U$O%P%Q%$$$$$$$$$$$$$$$$$$$$$$$$$$R%S%T%U%V%W%~%)#!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%)#!%X%Y%Z%`%$$$$$$$$$$$$$$$$$$$$$$$$%$ &.&+&z#!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%)#p%L%r$8 8 5 @&        \",\n\"        M%0 8 `.#&s%$&!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%U$t%%&&&k$$$$$$$$$$$$$$$$$$$$$$$$$*&=&-&;&>&,&z#!%~%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%~%!%z#'&)&!&4$$$$$$$$$$$$$$$$$$$$$$$$$~&{&]&z#~%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%)#p%L%^&8 8 5 @&        \",\n\"        /&0 8 `.#&s%$&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%(&_&:&<&%$%$%$%$%$%$%$%$%$%$%$%$*&[&}&|&1&g%!%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%z#2&3&4&*&%$%$%$%$%$%$%$%$%$%$%$5&6&7&8&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%!%9&0&^&8 8 5 a&        \",\n\"        /&0 8 `.#&s%$&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%b&c&d&e&%$%$%$%$%$%$%$%$%$%$%$%$f&g&h&i&g%z#~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%(&j&k&l&%$%$%$%$%$%$%$%$%$%$%$%$m&n&o&!%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%!%9&0&^&8 8 5 p&        \",\n\"        /&h 7 7 J#q&r&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%s&t&u&R%R%R%R%R%R%R%R%R%R%R%R%v&w&x&y&B%!%(&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%z&U$A&B&C&5&R%R%R%R%R%R%R%R%R%R%R%v&D&E&(&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%!%9&F&G&7 7 4 p&        \",\n\"        M%h 7 n J#q&r&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%(&H&I&J&R%R%R%R%R%R%R%R%R%R%R%R%K&L&M&N&!%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%z&~%O&P&Q&R%R%R%R%R%R%R%R%R%R%R%R%R&S&T&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%!%U&F&G&7 7 4 p&        \",\n\"        /&h 7 n J#V&r&(&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%W&X&Y&!$R%R%R%R%R%R%R%R%R%R%R%Z&`& *.*z&~%z&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%z&~%+*@*#*!$R%R%R%R%R%R%R%R%R%R%R%$*%*&*U$z&~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%z&~%**F&G&7 7 4 p&        \",\n\"        =*h 7 n J#V&-*z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&;*>*,*!$!$!$!$!$!$!$!$!$!$!$!$'*)*!*~*~%z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&{*]*^*/*!$!$!$!$!$!$!$!$!$!$!$(*_*:*~%z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&~%**F&G&7 7 4 p&        \",\n\"        /&h 7 n J#<*-*z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&{*[*}*|*!$!$!$!$!$!$!$!$!$!$!$v&1*2*3*~%z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&4*5*6*!$!$!$!$!$!$!$!$v&7*Z&8*9*0*a*z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&z&~%**F&G&7 7 4 p&        \",\n\"        f+h 7 n J#b*c*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*e*f*g*h*v&v&v&v&v&v&v&v&v&v&v&i*j*k*l*z&d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*m*n*o*p*v&v&v&q**$i*x%r*s*t*u*v*w*C%{*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*z&x*F&G&7 7 4 p&        \",\n\"        y*h 7 n J#b*z*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*A*B*C*v&v&v&v&v&v&v&v&v&v&v&v&D*E*F*{*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*G*H*I*J*K*L*M*N*O*P*Q*R*S*T*U*V*W*X*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*z&x*F&G&7 7 4 p&        \",\n\"        y*h 7 n J#Y*z*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*{%Z*`* =v&v&v&v&v&v&v&v&v&v&v&.=+=@=#=z&d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*a*$=%=&=*===-=;=>=,='=)=!=~={=N&]=a*a*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*d*z&x*^=G&7 7 4 p&        \",\n\"        y*h 7 n /=Y*(=a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*m*_=:=<=7*7*7*7*7*7*7*7*7*7*7*[=}=|=~*d*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*d*1=2=3=4=5=6=7=8=,%C%a*d*z&{*G*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*d*9=0=G&7 7 4 p&        \",\n\"        y*h 7 n /=Y*(=a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a=b=c=d=7*7*7*7*7*7*7*7*7*7*d=e=f=g=a*'%'%a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*'%'%h=i=~*X*{%d*d*d*d*{%{%a*a*'%'%a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*'%d*9=0=G&7 7 Y X#        \",\n\"        y*h 7 n /=j=k='%'%'%'%'%'%'%'%'%'%'%'%'%'%'%l=m=n=d=d=d=d=d=d=d=d=d=d=d=o=p=q=r=d*'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%{%{%a*'%'%X*'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%{%s=t=G&7 7 Y X#        \",\n\"        y*!.7 n /=j=k='%'%'%'%'%'%'%'%'%'%'%'%'%'%'%A&u=v=d=d=d=d=d=d=d=d=d=d=d=w=x=y=#=d*z='%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%'%{%s=t=G&7 7 Y X#        \",\n\"        y*] 0 U A=j=B=X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*C=D=E=o=o=o=o=o=o=o=o=o=o=o=F=G=H=I='%X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*'%J=t=K=0 0 Y X#        \",\n\"        y*] 0 U A=j=B=X*X*X*X*X*X*X*X*X*X*X*X*X*X*T&L=M=G%o=o=o=o=o=o=o=o=o=o=o=N=O=P=g%X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*'%J=t=K=0 0 Y X#        \",\n\"        w#] 0 U Q=R=B=X*X*X*X*X*X*X*X*X*X*X*X*X*X*C%S=T=U=o=o=o=o=o=o=o=o=o=o=o=V=W=X='%X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*'%J=Y=K=0 0 Y X#        \",\n\"        Z=] 0 U Q=R=`=C%C%C%C%C%C%C%C%C%C%C%C%C%C% -.-+-@-q*q*q*q*q*q*q*q*q*q*q*#-$-%-'%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%X*&-*-K=0 0 Y X#        \",\n\"        Z=] 0 U Q==-`=C%C%C%C%C%C%C%C%C%C%C%C%C%C%--;->-,-q*q*q*q*q*q*q*q*q*q*q*'-)-!-'%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%C%X*&-*-K=0 0 Y X#        \",\n\"        Z=] 0 U Q==-~-g%g%g%g%g%g%g%g%g%g%g%g%g%g%]={-]-8*8*8*8*8*8*8*8*8*8*8*8*^-/-h%X*g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%h=(-*-K=0 0 Y X#        \",\n\"        _-] 0 U :-<-~---g%g%g%g%g%g%g%g%g%g%g%g%g%[-}-|-8*8*8*8*8*8*8*8*8*8*8*1-2-3-4-h=~*g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%g%~*h=5-6-K=0 0 Y X#        \",\n\"        _-] 0 U :-<-7-~*~*~*~*~*~*~*~*~*~*~*~*~*~*8-9-0-a-a-a-a-a-a-a-a-a-a-a-b-c-d-e-C%~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*g%f-6-K=0 0 Y g-        \",\n\"        5%] 0 U :-<-7-]=~*~*~*~*~*~*~*~*~*~*~*~*~*h-i-j-a-a-a-a-a-a-a-a-a-a-a-F=k-l-m-g%i=~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*g%n-6-K=0 0 Y g-        \",\n\"        5%] 0 U :-o-p-i=i=i=i=i=i=i=i=i=i=i=i=i=i=q-r-s-F=F=F=F=F=F=F=F=F=F=F=t-u-v-w---i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=~*x-6-K=0 0 y-z-        \",\n\"        5%/ 0 U :-o-p-i=i=i=i=i=i=i=i=i=i=i=i=i=i=A-B-s-F=F=F=F=F=F=F=F=F=F=F=t-C-D-w---B%i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=i=~*x-E-K=F-h y z-        \",\n\"        5%/ h !.:-o-G-B%B%B%B%B%B%B%B%B%B%B%B%B%B%A-H-I-t-t-t-t-t-t-t-t-t-t-t-J-K-L-w-~*B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%B%M-x-E-N-h h y 4         \",\n\"        O-/ h !.P-Q-R-,%,%,%,%,%,%,%,%,%,%,%,%,%,%S-T-U-J-J-J-J-J-J-J-J-J-J-J-V-W-X-Y-i=,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%B%Z-`-N-h h C+4         \",\n\"        O-/ h !. ;Q-.;,%,%,%,%,%,%,%,%,%,%,%,%,%,%+;@;#;J-J-J-J-J-J-J-J-J-J-J-V-$;%;&;i=,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%,%B%*;`-N-h h C+4         \",\n\"        O-/ h !.=;Q-.;]%I=I=I=I=I=I=I=I=I=I=I=I=I=-;;;>;,;,;,;,;,;,;,;,;,;,;,;,;';);!;i=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=B%*;`-~;h h C+4         \",\n\"        {;/ h !.=;];^;I=I=I=I=I=I=I=I=I=I=I=I=I=I=/;(;_;,;,;,;,;,;,;,;,;,;,;,;,;:;<;[;l*I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=I=,%};`-|;h h Q@4         \",\n\"        1;/ h !.=;];2;3;3;3;3;3;3;3;3;3;3;3;3;3;3;4;5;6;7;8;8;8;8;8;8;8;8;8;8;8;9;0;a;,%3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;,&b;c;|;h h Q@4         \",\n\"        1;/ h !.=;];2;3;3;3;3;3;3;3;3;3;3;3;3;3;3;4;d;e;f;8;8;8;8;8;8;8;8;8;8;8;g;h;i;,%3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;3;,&b;c;|;h h Q@4         \",\n\"        1;/ h !.j;k;l;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;n;o;p;q;q;q;q;q;q;q;q;q;q;q;r;s;t;I=m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;3;u;c;|;h h Q@4         \",\n\"        1;/ h !.j;k;l;m;m;m;m;m;m;m;m;m;m;m;m;m;m;v;w;x;y;q;q;q;q;q;q;q;q;q;q;q;z;A;B;4;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;C;v;v;v;v;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;3;u;c;|;h h c@4         \",\n\"        1;5 ] { j;D;E;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;F;G;H;I;I;I;I;I;I;I;I;I;I;I;J;K;L;M;v;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;N;O;P;Q;R;S;T;U;V;W;W;X;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;m;Y;Z;`;] ] c@4         \",\n\"        1;5 ] { j;D;E;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C; >.>+>I;I;I;I;I;I;I;I;I;I;I;@>#>$>%>v;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;&>*>=>->;>>>,>'>)>!>~>{>]>^>/>(>C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;m;_>Z;`;] ] c@4         \",\n\"        :>5 ] { <>[>}>C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;|>1>2>3>3>3>3>3>3>3>3>3>3>3>3>4>5>6>m;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;X;7>8>9>0>a>b>c>d>e>f>g>h>i>j>k>l>f%C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;m;m>Z;`;] ] c@4         \",\n\"        n>5 ] { <>o>p>X;C;C;C;C;C;C;C;C;C;C;C;C;C;f%q>r>s>t>3>3>3>3>3>3>3>3>3>3>t>u>v>w>v;f%C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;f%x>y>z>3>3>3>3>3>3>3>3>A>B>C>D>E>Y-C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;C;f%C;F>G>`;] ] c@4         \",\n\"        H>5 ] { <>o>p>f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%|>I>J>K>t>t>t>t>t>t>t>t>t>t>t>L>M>N>C;f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%O>P>Q>t>t>t>t>t>t>t>t>t>t>t>R>S>T>U>C;f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%f%C;V>G>W>] ] V 4         \",\n\"        H>5 ] { <>o>X>M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;Y>Z>`>R>R>R>R>R>R>R>R>R>R>R> ,.,+,@,M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;&*#,$,R>R>R>R>R>R>R>R>R>R>R>%,&,*,=,f%M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;M;f%-,;,W>] ] V >,        \",\n\"        H>5 ] { <>,,',),),),),),),),),),),),),),),),),!,~,{,],],],],],],],],],],],],^,/,(,_,),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),:,<,[,],],],],],],],],],],],},|,1,W%M;),),),),),),),),),),),),),),),),_,2,;,W>] ] d@>,        \",\n\"        3,0.] { <>,,',),),),),),),),),),),),),),),),N&4,5,6,7,],],],],],],],],],],],8,9,0,8=),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),),4,a,b,c,],],],],],],],],],],],d,e,f,N&N&),),),),),),),),),),),),),),),),),g,h,i,j,/ E.>,        \",\n\"        3,0./ / <>k,l,N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&4,m,n,L>7,7,7,7,7,7,7,7,7,7,7,7,o,p,q,N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&r,s,t,z;7,7,7,7,7,7,7,7,7,7,7,u,v,w,),N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&N&),g,h,x,/ / E.>,        \",\n\"        y,0./ z,A,k,B,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,4,D,E,F,G,G,G,G,G,G,G,G,G,G,G,G,H,I,J,8=C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,#=K,L,M,G,G,G,G,G,G,G,G,G,G,G,N,O,P,Q,8=C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,N&R,S,x,/ / E.>,        \",\n\"        y,0./ z,T,U,B,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,V,W,X,Y,G,G,G,G,G,G,G,G,G,G,G,Y,Z,`, 'C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,.'+'s>@'G,G,G,G,G,G,G,G,G,G,G,#'$'%'&'C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,C,N&R,*'x,/ / E.>,        \",\n\"        ='0./ z,-';'>','W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%,''')'!'~'~'~'~'~'~'~'~'~'~'~'~'{']'^',','W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%/'('_'~'~'~'~'~'~'~'~'~'~'~'~':'<'!=C,,'W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%C,['}'x,/ / E.|'        \",\n\"        ='0./ z,-';'1'W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%2'3'4'5'~'~'~'~'~'~'~'~'~'~'~'6'7'8'9'W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%0'a'b'8,~'~'~'~'~'~'~'~'~'~'~'c'd'e'f','W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%W%g'h'}'x,/ / E.|'        \",\n\"        ='0./ z,-'i'j'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'m-k'l'm'6'6'6'6'6'6'6'6'6'6'6'6'n'o'p'q'r'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'s't'u'v'6'6'6'6'6'6'6'6'6'6'6'N,w'x'y'&'r'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'W%z'A'B'/ / E.|'        \",\n\"        C'y / z,D'E'j'm-&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'F'&'G'H'I'N,6'6'6'6'6'6'6'6'6'6'6'J'K'L'M'N'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'s'O'P'Q'N,6'6'6'6'6'6'6'6'6'6'6'R'S'T'U'W%&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'&'V'z'W'X'~ 5 3+|'        \",\n\"        C'y 5 Y'Z'`' )F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'.)F'+)@)#)$)N,N,N,N,N,N,N,N,N,N,N,N,%)&)*)=).).)F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'-);)>),)')N,N,N,N,N,N,N,N,N,N,N,},))!)~){)&'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'F'&'])W'^)5 5 s.|'        \",\n\"        /)y 5 ()Z'_):).).).).).).).).).).).).).).).).).).).).)<)[)})|)')')')')')')')')')')')')')1)2)3)4)5).).).).).).).).).).).).).).).).).).).).)5)6)7)8)9)},')')')')')')')')')')')')0)a)b)c)F'.).).).).).).).).).).).).).).).).).).).)>%d)e)^)5 5 s.f)        \",\n\"        g)y 5 ()Z'h)i)^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%5)j)k)l)|)|)|)|)|)|)|)|)|)|)|)|)|)|)m)n)o)p)q)^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%r)s)t)u)v)w)|)|)|)|)|)|)|)|)|)|)|)|)x)y)z)A)B).)^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%.)C)D)^)5 5 ) |'        \",\n\"        E)c@5 5 F)G)H)^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%I)J)K)L)|)|)|)|)|)|)|)|)|)|)|)|)|)|)M)N)O)P)Q)R)=,^%^%^%^%^%^%^%^%^%^%^%^%S)=,T)U)V)W)X)w)|)|)|)|)|)|)|)|)|)|)|)|)Y)Z)`) !.!.)S)^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%^%.)+!@!#!5 5 $!p&        \",\n\"        %!c@5 5 &!*!=!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!S);!>!,!'!Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)u>)!!!~!{!]!^!/!/!(!(!(!(!(!/!/!_!:!<![!}!|!M)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)1!2!3!4!{)^%-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!5)5!6!#!5 5 7!/&        \",\n\"        8!E.5 5 9!0!a!-!{)-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!{){)^%b!c!d!e!f!Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)x)x)g!#)h!i!j!k!l!m!n!o!p!q!r!s!t!u!v!w!x!y!g!g!Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)Y)z!A!B!C!D!^%{){)-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!{).)E!F!G!5 0.=@;#        \",\n\"        H!7!0.0.I!J!K!{)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)I)L!M!N!O!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!P!Q!R!S!T!U!V!W!X!Y!Z!`! ~.~R'e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!+~@~#~$~;%{)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)%~&~*~=~0.y -~;~        \",\n\"        >~,~0.0.'~)~!~-!B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B){=~~{~]~^~e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!R'/~/~/~/~/~R'e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!e!^~(~_~:~<~B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)B)[~}~|~1~0.2~3~          \",\n\"        4~7!y 0.1~5~6~7~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~U>9~0~a~b~c~O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!O!d~e~f~g~h~i~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~j~k~l~m~0.s.n~          \",\n\"          o~E.0.m~0.p~7~q~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~q~8~r~s~t~u~v~z!+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~+~z!w~x~y~z~A~U>8~q~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~8~B~C~D~0.0.$!E~          \",\n\"          F~$!0.0.D~G~H~i~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~f'I~J~K~L~b~z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!z!b~M~N~O~P~Q~R~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~q~B)S~T~D~0.0.3~U~          \",\n\"          e 3~y 0.V~T~W~X~U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>q~r~Y~Z~`~ {.{b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~b~.{+{@{#{${%{R~Q,U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>U>&{*{v#={0.c@-{;{          \",\n\"          >{,{2~y y '{){&{R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~U>!{~{{{]{^{/{({({({({({({({({({({({({({({({({({({({({({({({({({({({({({({({({/{_{:{<{[{}{|{U>U>R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~R~q~1{2{3{y y R.X             \",\n\"            4{$!y y 5{6{7{Q,f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'U>6=8{9{0{a{b{c{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{/{d{e{f{#{g{h{i{R~r~f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'f'i~j{~.k{y y l{m{            \",\n\"            n{o{y y p{S@q{r{3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*s{f't{u{v{w{x{y{d{z{c{c{c{c{c{c{c{c{c{c{c{c{c{c{c{c{c{c{c{c{c{c{.{A{B{C{D{E{F{G{H{I{f'3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*f'J{K{L{M{y E.N{O{            \",\n\"              P{s.y y Q{R{S{T{U{3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*U{U{3*D!I{V{W{X{Y{Z{`{ ].]+]w~.{.{c{c{c{c{c{c{c{c{c{c{c{.{.{z{@]#]e{$]%]&]*]=]-];]3*3*U{3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*3*U{>]r{,]'])]y y !]']              \",\n\"              ~],~c@y {]{]]]^]U{I{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{I{U{3*/](]_]:]<][]}]|]1]2]3]4]b{5]6]6]7]6]6]5]8]9](~0]a]b]c]d]e]f]g]h]i]3*U{I{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{U{I{D!j]k]Q{M{y c@Q.l]              \",\n\"                a.s.y 2~m]n]o]p]/]I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{q]/]I{>]I{r]s]t]u]v]w]x]y]z]A]B]C]D]E]F]G]H]I]J]K]L]M]N]O]P]Q]R];]I{I{/]/]I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{I{/]I{S]T]Q@{]y C+U]V]                \",\n\"                W]X]c@c@Y]Z]`] ^.^+^+^/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]+^+^/]I{I{/]@^t{#^$^%^&^*^=^-^;^>^,^'^ !)^!^C!~^{^]^^^.*/^I{/]+^+^/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]/]+^(^_^:^m]c@c@s.<^[^                \",\n\"                  k !]c@c@}^|^1^2^q]6=+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^q]I{/]6=i]3^4^5^R]c)c)c)6^^^3^i]6=q]q]/]+^6=+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^+^7^8^9^0^c@c@E.X]a^                  \",\n\"                  b^c^3+c@c@d^e^f^g^+^;];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];]+^+^/]/]/]/]/]/]/]/]/]+^;];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];];]7^h^i^j^|^c@c@!]k^l^                  \",\n\"                    a^m^c@c@c@Z]n^o^p^6=i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]q^r^s^Z]}^c@c@s.t^u^                    \",\n\"                      v^w^c@c@c@x^y^z^A^;]B^B^i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]i]B^B^C^D^E^F^G^V c@E.H^I^                      \",\n\"                        J^K^E.E.E.L^M^N^ ^O^r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]B^P^Q^R^S^T^E.E.E.U^V^                        \",\n\"                        W^J^U]E.E.E.L^R.X^Y^Z^B^3^3^r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]r]3^3^`^ /./+/x^R.E.E.E.m^@/                          \",\n\"                          #/$/U]E.E.E.%/&/*/=/-/;/r]>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>/B^,/'/)/!/~/{/3+E.s.U^]/                            \",\n\"                            ^///o{s.E.E.R.x^(/_/:/-/</[/>/U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'>/}/|/1/2/3/x^q$E.E.E.4/U^]/                              \",\n\"                              5/6/7/4/E.E.E.8/&/*+9/0/a/b/c/d/>/U'^^^^4^U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'U'4^^^^^U'>/r]e/f/g/h/i/R.~/R.E.E.E.!]j/k/                                \",\n\"                                  l/m/!]{/s.s.s.q$n/3+o/p/q/r/s/t/W*u/e/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/v/w/e/e/x/y/z/A/B/C/D/E/q$F/q$s.s.s.) o{G/H/                                  \",\n\"                                    I/J^H^$!s.s.s.s.q$n/n/*+J/K/L/M/N/O/P/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/Q/R/S/T/C/U/V/W/X/3+Y/Z/4/s.s.s.s.w^`/ (.(                                    \",\n\"                                      +(@(#(m^$(s.s.s.s.s.%(&(n/n/&(Z$s.*(2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#2#*(4/=(&(-(&(&(;(s.s.s.s.s.!]U^>(,(                                        \",\n\"                                          '()(j/H^w^s.s.s.s.s.s.4/4/4/4/;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(;(4/4/4/4/4/s.s.s.s.s.$!o{7/j/!(                                            \",\n\"                                              ~({(](^(m^w^!]s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.s.$!!]o{U^c^/(((                                                \",\n\"                                                    _(:(<(N{X][(7/m^w^!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]!]w^m^[(7/)+}(|(1(2(                                                    \",\n\"                                                          3(_(4(5(6(7(k^8(k^P{P{P{P{P{P{9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(9(P{P{P{P{P{P{k^P{a.0(a(b(c(d(e(                                                          \",\n\"                                                                      f(g(h(i(i(i(i(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(j(i(i(i(i(i(k(l(                                                                        \",\n\"                                                                                                                                                                                                                                                                \",\n\"                                                                                                                                                                                                                                                                \",\n\"                                                                                                                                                                                                                                                                \"};\n"
  },
  {
    "path": "src/resource/embedded/PNG_HELP.hpng",
    "content": "unsigned char PNG_HELP_png[492] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0xE0, 0x77, 0x3D, 0xF8, 0x00, 0x00, 0x00,\n\t0x06, 0x62, 0x4B, 0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0,\n\t0xBD, 0xA7, 0x93, 0x00, 0x00, 0x01, 0xA1, 0x49, 0x44, 0x41, 0x54, 0x48,\n\t0x89, 0xDD, 0x95, 0xB1, 0x4E, 0x02, 0x41, 0x10, 0x86, 0xBF, 0x80, 0x9C,\n\t0x85, 0xF2, 0x06, 0x68, 0x6B, 0x02, 0xBC, 0x83, 0x58, 0xD8, 0x1A, 0x24,\n\t0x86, 0x52, 0x4B, 0x22, 0x31, 0x88, 0x2F, 0x61, 0x88, 0xD1, 0xA7, 0x10,\n\t0x29, 0x0C, 0x89, 0x89, 0x89, 0x96, 0xB6, 0x16, 0xDA, 0x88, 0x46, 0x11,\n\t0xF5, 0x09, 0x8C, 0x26, 0x82, 0x85, 0x34, 0x9C, 0xC5, 0xCE, 0x86, 0xCD,\n\t0xB2, 0x77, 0x07, 0x94, 0xFC, 0xC9, 0xE4, 0x92, 0x7F, 0x66, 0xFE, 0xD9,\n\t0x9B, 0x9B, 0xD9, 0x83, 0x59, 0x87, 0x07, 0x14, 0x81, 0x06, 0xD0, 0x06,\n\t0x7E, 0xC5, 0xDA, 0xC0, 0x99, 0xF8, 0xBC, 0x69, 0xC5, 0x0B, 0xC0, 0x07,\n\t0xE0, 0x47, 0xD8, 0x3B, 0xB0, 0x39, 0x89, 0x70, 0x0C, 0x38, 0x32, 0x04,\n\t0x1E, 0x80, 0x0A, 0x90, 0x06, 0x16, 0xC4, 0x32, 0xC0, 0x3E, 0xD0, 0x32,\n\t0xE2, 0x6A, 0x92, 0x1B, 0x09, 0x2D, 0xFE, 0x07, 0x94, 0x22, 0x92, 0x62,\n\t0xC0, 0xAE, 0xC4, 0xEA, 0x22, 0xA1, 0x28, 0x18, 0xE2, 0xAB, 0x06, 0xBF,\n\t0x04, 0x34, 0x81, 0xAE, 0xD8, 0x05, 0xB0, 0x62, 0xF8, 0x73, 0x46, 0x91,\n\t0x7C, 0x90, 0xB8, 0xC7, 0xB0, 0xE7, 0x25, 0x4B, 0xFC, 0x8B, 0xD1, 0xDE,\n\t0x7F, 0x8B, 0x4F, 0xA3, 0x2C, 0xFC, 0x1B, 0x90, 0x70, 0x15, 0x28, 0x32,\n\t0xEC, 0xB9, 0xD9, 0x96, 0xA6, 0xF0, 0x57, 0x40, 0x4A, 0xEC, 0x5A, 0xB8,\n\t0x73, 0x23, 0x2E, 0x0E, 0x3C, 0x0A, 0xBF, 0xE5, 0x2A, 0xD0, 0x10, 0x67,\n\t0xC5, 0xE2, 0xBB, 0xC2, 0xA7, 0xAC, 0xB7, 0xF2, 0x81, 0x1F, 0x2B, 0xB6,\n\t0x2A, 0x7C, 0xDD, 0x55, 0xE0, 0x55, 0x9C, 0x69, 0x97, 0xD3, 0xC2, 0xB2,\n\t0xC4, 0x7E, 0x5A, 0x7C, 0x46, 0xF8, 0xB6, 0x2B, 0x49, 0x9F, 0x34, 0x19,\n\t0x21, 0x3E, 0x8F, 0x6A, 0x97, 0x0F, 0x1C, 0x5B, 0xBE, 0xA4, 0xF0, 0xDD,\n\t0x69, 0x0B, 0xCC, 0x01, 0x97, 0x12, 0x77, 0xC3, 0xE8, 0x16, 0x87, 0x16,\n\t0x18, 0xA7, 0x45, 0x27, 0x12, 0x73, 0x1B, 0x70, 0x90, 0x2C, 0x56, 0x8B,\n\t0xCC, 0x69, 0xB9, 0x97, 0xE7, 0x7A, 0x48, 0x81, 0x1D, 0x79, 0x6E, 0x03,\n\t0x3D, 0x87, 0x5F, 0xE7, 0xDE, 0xB9, 0x92, 0xF5, 0x98, 0xB6, 0x18, 0x73,\n\t0xE5, 0x2D, 0xC4, 0x81, 0x27, 0x42, 0xC6, 0xD4, 0x43, 0x5D, 0x5C, 0x3E,\n\t0x6A, 0xFD, 0x5D, 0xD0, 0x4B, 0xE6, 0xC2, 0x9E, 0xF8, 0x3A, 0x04, 0x2C,\n\t0x1A, 0xA8, 0x5B, 0x51, 0x5F, 0x15, 0xB9, 0x09, 0x0A, 0xAC, 0x01, 0x7D,\n\t0x60, 0x00, 0x6C, 0x04, 0x89, 0x6B, 0xD4, 0x8C, 0x22, 0x65, 0xD4, 0xAB,\n\t0x07, 0x21, 0x2E, 0x27, 0xEF, 0x4B, 0xCE, 0x61, 0x94, 0x38, 0xA8, 0xFE,\n\t0xEB, 0x22, 0x3E, 0x6A, 0xFD, 0xAB, 0xA8, 0x25, 0x5A, 0x14, 0xCB, 0x02,\n\t0x07, 0x0C, 0x7B, 0x3E, 0x10, 0xF1, 0x89, 0xBE, 0x5D, 0x1E, 0x75, 0x71,\n\t0x45, 0xFD, 0x70, 0x3A, 0x8C, 0xD1, 0x96, 0x20, 0x24, 0x50, 0x13, 0x51,\n\t0x07, 0x5E, 0x50, 0xA3, 0xD9, 0x03, 0x9E, 0x81, 0x53, 0xF1, 0x05, 0x7E,\n\t0xD0, 0xD9, 0xC0, 0x3F, 0xA0, 0xD8, 0x8F, 0x1F, 0xB8, 0x80, 0x0B, 0x45,\n\t0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/PNG_REFRESH.hpng",
    "content": "unsigned char PNG_REFRESH_png[449] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7A, 0x7A, 0xF4, 0x00, 0x00, 0x00,\n\t0x06, 0x62, 0x4B, 0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0,\n\t0xBD, 0xA7, 0x93, 0x00, 0x00, 0x01, 0x76, 0x49, 0x44, 0x41, 0x54, 0x58,\n\t0x85, 0xED, 0xD6, 0x3F, 0x4B, 0x1D, 0x41, 0x1C, 0x85, 0xE1, 0x47, 0x45,\n\t0x88, 0x36, 0x16, 0x2A, 0x01, 0x8D, 0x28, 0x9A, 0x90, 0x46, 0x53, 0xD8,\n\t0xFB, 0x11, 0x82, 0x88, 0x22, 0xA8, 0x85, 0x56, 0x36, 0x16, 0x16, 0x16,\n\t0xA9, 0x52, 0xD8, 0xD9, 0xA5, 0x0C, 0xC1, 0xCA, 0xC2, 0x10, 0x08, 0x5A,\n\t0x49, 0xD2, 0x99, 0xE0, 0x57, 0x10, 0xAC, 0x03, 0x82, 0x85, 0x7F, 0x8A,\n\t0xA4, 0x52, 0xBC, 0x57, 0x53, 0xCC, 0xAC, 0xAE, 0x8D, 0xD9, 0xD9, 0x2B,\n\t0x44, 0x70, 0x5F, 0x18, 0x58, 0xD8, 0x39, 0x73, 0xCE, 0xCC, 0xCE, 0xCE,\n\t0xFC, 0xA8, 0x78, 0xEA, 0x34, 0x25, 0xF6, 0xEF, 0xC3, 0x1C, 0xC6, 0xF0,\n\t0x06, 0x9D, 0xA8, 0xE1, 0x10, 0xBF, 0xB0, 0x83, 0x2D, 0x1C, 0x3F, 0x5C,\n\t0xC4, 0xC0, 0x0B, 0x7C, 0x8E, 0x66, 0xD7, 0xFF, 0x68, 0x35, 0xAC, 0xA3,\n\t0x2B, 0xA7, 0xCF, 0xDE, 0x95, 0x62, 0x12, 0x7F, 0xE2, 0x00, 0xE7, 0xD8,\n\t0xC4, 0x34, 0x06, 0xD0, 0x86, 0x0E, 0x8C, 0x08, 0x2B, 0xF3, 0x2D, 0x17,\n\t0xF2, 0x0C, 0xE3, 0x8D, 0x06, 0x58, 0xC2, 0x55, 0x14, 0x7F, 0x45, 0x6F,\n\t0x01, 0xCD, 0x4B, 0xFC, 0x8C, 0x9A, 0x4B, 0x2C, 0x94, 0x0D, 0x30, 0x81,\n\t0x7A, 0x6C, 0xCB, 0x89, 0xDA, 0x66, 0xAC, 0x46, 0xD3, 0x6C, 0x02, 0x49,\n\t0x01, 0x9E, 0xE3, 0x34, 0x8A, 0x56, 0x12, 0xCD, 0xF3, 0xAC, 0xB9, 0xBB,\n\t0x3F, 0x0A, 0xF3, 0x31, 0x0A, 0x76, 0x4A, 0x98, 0xDE, 0xB7, 0x41, 0x0B,\n\t0xD1, 0x8A, 0x03, 0x61, 0x33, 0xBD, 0xFA, 0x1F, 0x01, 0x08, 0xDF, 0x70,\n\t0xB4, 0x84, 0x79, 0x45, 0x45, 0xC5, 0xA3, 0x65, 0x54, 0xF8, 0xB5, 0x0B,\n\t0xF3, 0x20, 0x87, 0x49, 0xE4, 0xB5, 0x70, 0xA8, 0x1D, 0x08, 0x87, 0xDC,\n\t0x1D, 0x92, 0x52, 0x95, 0xA0, 0x09, 0x1F, 0xD0, 0x82, 0x5D, 0xE1, 0x76,\n\t0x2C, 0x44, 0x7E, 0xC6, 0xAB, 0x0D, 0x04, 0x78, 0x17, 0xC7, 0x38, 0x46,\n\t0x77, 0x8A, 0x30, 0x33, 0xCF, 0xAE, 0xD2, 0xF7, 0xD2, 0xCB, 0xB7, 0x95,\n\t0xA8, 0xAF, 0xE1, 0x6D, 0xA2, 0xF6, 0x26, 0xC0, 0xBC, 0xB0, 0x6C, 0xD7,\n\t0xF8, 0x81, 0xA1, 0x02, 0xDA, 0x7E, 0x6C, 0x47, 0x4D, 0x1D, 0x8B, 0xA9,\n\t0xE6, 0xF9, 0x00, 0x84, 0xF4, 0x59, 0x6D, 0x50, 0xC3, 0x77, 0xCC, 0x62,\n\t0x10, 0xCF, 0xD0, 0x1E, 0x9F, 0x67, 0xF0, 0x05, 0x17, 0xB1, 0xEF, 0x6F,\n\t0xB7, 0x25, 0x59, 0x43, 0x01, 0x08, 0xD5, 0xEF, 0x27, 0xB7, 0xAB, 0x71,\n\t0x5F, 0xBB, 0xC4, 0x06, 0x7A, 0x8A, 0x18, 0xA5, 0x7E, 0xD7, 0x2E, 0x4C,\n\t0x09, 0x33, 0x1B, 0x16, 0x36, 0x56, 0x1D, 0x27, 0xD8, 0xC7, 0x9E, 0x50,\n\t0xB4, 0x1E, 0x25, 0x8E, 0x5B, 0xF1, 0x84, 0xF9, 0x0B, 0x5F, 0xA6, 0x85,\n\t0x78, 0x5B, 0xF8, 0x93, 0x75, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E,\n\t0x44, 0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/X_BOX.xpm",
    "content": "/* XPM */\nconst char * X_BOX_xpm[] = {\n\"32 32 2 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"                                \",\n\"                                \",\n\"                                \",\n\"                                \",\n\"         .........  .......     \",\n\"        .........  .......      \",\n\"       .........  .......  ..   \",\n\"     ..........  .......  ...   \",\n\"    ..........  .......  ....   \",\n\"                        .....   \",\n\"   ...................  .....   \",\n\"   ...................  .....   \",\n\"   ...................  .....   \",\n\"   .......       .....  .....   \",\n\"   ...................  .....   \",\n\"   ...................  .....   \",\n\"   ...................  .....   \",\n\"   ...................  .....   \",\n\"   ...................  .....   \",\n\"   ...................  .....   \",\n\"   ...................  .....   \",\n\"   ...................  ....    \",\n\"   ...................  ....    \",\n\"   ...................  ...     \",\n\"   ...................  ..      \",\n\"   ................... ..       \",\n\"   ...................          \",\n\"   ...................          \",\n\"                                \",\n\"                                \",\n\"                                \",\n\"                                \"};\n"
  },
  {
    "path": "src/resource/embedded/X_GAME_PROFILE.xpm",
    "content": "/* XPM */\nconst char* X_GAME_PROFILE_xpm[] = {\n\"32 32 2 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"                                \",\n\" ......................         \",\n\" .......................        \",\n\" ..                             \",\n\" ..  .....................      \",\n\" .. .......................     \",\n\" .. ...                         \",\n\" .. ..                          \",\n\" .. ..  ......................  \",\n\" .. ..  ......................  \",\n\" .. ..  ......................  \",\n\" .. ..  ......................  \",\n\" .. ..  ......................  \",\n\" .. ..  ......................  \",\n\" .. ..  ......................  \",\n\" .. ..  ......................  \",\n\" .. ..  ......................  \",\n\" .. ..  ......................  \",\n\" .. ..  .......... ...........  \",\n\" .. ..  ............ .........  \",\n\" .. ..  ...........   ........  \",\n\" .. ..  ............   .......  \",\n\" .. ..  .............   ......  \",\n\"    ..  ..............   .....  \",\n\"    ..  ...............   ....  \",\n\"     .  ................   ...  \",\n\"        .................   ..  \",\n\"        ..................   .. \",\n\"        ...................  ...\",\n\"                          ......\",\n\"                           .... \",\n\"                            ..  \"};\n"
  },
  {
    "path": "src/resource/embedded/X_HOTKEY_SETTINGS.xpm",
    "content": "/* XPM */\nconst char *X_HOTKEY_SETTINGS_xpm[] = {\n\"64 64 2 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"                                   ...                          \",\n\"                                 ....                           \",\n\"                                ....                            \",\n\"                    ..         ....                             \",\n\"                   ..        ......                             \",\n\"                  ...        ......                             \",\n\"                 ...        ......                              \",\n\"                 ...        .......                             \",\n\"                ....       ........        ...                  \",\n\"               ....        .........        ...                 \",\n\"               ....        .........         ...                \",\n\"              ....         ..........        ....               \",\n\"              ....          .........        ....               \",\n\"              .....         ...........      .....              \",\n\"              .....          ..........      .....              \",\n\"             ........        ...........     ......             \",\n\"             ........        ... .......     ......             \",\n\"            ...........      ... .......     ......             \",\n\"            ...........    .....  ......     .......            \",\n\"            ...........    .....  ......    ........            \",\n\"           .............  ......  ......    .........           \",\n\"           ........ ....  ......   ....    ..... ....           \",\n\"           ........ .... .......   ....   ...... ....           \",\n\"           ......   .... ......    ..... ....... .....          \",\n\"           ......   ...........    ............   ....          \",\n\"           ......   ..........      ..........    ....          \",\n\"           .....    ..........      ..........    ....          \",\n\"           .....    ..........      .........    .....          \",\n\"           .....    ..........       ........    .....          \",\n\"           .....      ........       ........   ......          \",\n\"            .....      .....          .....     .....           \",\n\"            .....      .....           ....    ......           \",\n\"            .....                              .....            \",\n\"             ...                                ....            \",\n\"              .   ............................   ..             \",\n\"                ................................                \",\n\"                ................................                \",\n\"              ....................................              \",\n\"              ....................................              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........                ..........              \",\n\"              ..........                ..........              \",\n\"              ..........                ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ..........    ........    ..........              \",\n\"              ....................................              \",\n\"              ....................................              \",\n\"              ....................................              \",\n\"              ....................................              \",\n\"                ................................                \",\n\"                ................................                \",\n\"                  .............................                 \"\n};\n"
  },
  {
    "path": "src/resource/embedded/X_SETTINGS.xpm",
    "content": "/* XPM */\nconst char* X_SETTINGS_xpm[] = {\n\"64 64 2 1\",\n\" \tc None\",\n\".\tc #000000\",\n\"     .....................................................      \",\n\"     .....................................................      \",\n\"    .......................................................     \",\n\"   ..........................................................   \",\n\"  ...........................................................   \",\n\"..............................................................  \",\n\"..............................................................  \",\n\"..............................   .............................. \",\n\".............................     ..............................\",\n\".............................     ..............................\",\n\".............................      .............................\",\n\"............................       .............................\",\n\"............................       .............................\",\n\"...............  ...........       .............................\",\n\"..............     ........         ........     ...............\",\n\".............        .....            ....       ...............\",\n\".............         ..               ..         ..............\",\n\"..............                                   ...............\",\n\"..............                                   ...............\",\n\"...............                                 ................\",\n\"...............                                .................\",\n\"................            .......            .................\",\n\".................        .............         .................\",\n\".................       ...............        .................\",\n\"................       .................       .................\",\n\"................      ...................      .................\",\n\"...............       ...................      .................\",\n\"..............        ....................       ...............\",\n\"...........          .....................          ............\",\n\"........             .....................             .........\",\n\".......              .....................              ........\",\n\".......              .....................              ........\",\n\".......              .....................              ........\",\n\"........             .....................             .........\",\n\"..........           .....................           ...........\",\n\"..............        ....................       ...............\",\n\"...............       ...................       ................\",\n\"................      ..................       .................\",\n\"................       .................       .................\",\n\".................       ...............        .................\",\n\".................        ............          .................\",\n\"................           .........           .................\",\n\"...............                                .................\",\n\"...............                                 ................\",\n\"..............                                   ...............\",\n\"..............                                   ...............\",\n\"..............                                   ...............\",\n\"..............      ......           ......      ...............\",\n\"..............     ........         ........     ...............\",\n\"............................       .............................\",\n\"............................       .............................\",\n\"............................       .............................\",\n\".............................      .............................\",\n\".............................     ..............................\",\n\".............................     ..............................\",\n\"..............................   .............................. \",\n\"..............................................................  \",\n\"..............................................................  \",\n\"  ...........................................................   \",\n\"   ..........................................................   \",\n\"   .........................................................    \",\n\"     .....................................................      \",\n\"       .................................................        \",\n\"        ...............................................         \"};\n"
  },
  {
    "path": "src/resource/embedded/fontawesome.S",
    "content": ".section .rodata,\"\",%progbits\n.global g_fontawesome_data, g_fontawesome_size\n\ng_fontawesome_data:\n.incbin \"fontawesome-webfont.ttf\"\ng_fontawesome_size:\n.int g_fontawesome_size - g_fontawesome_data\n\n.section .note.GNU-stack,\"\",%progbits"
  },
  {
    "path": "src/resource/embedded/fontawesome_macos.S",
    "content": ".section __DATA, __const\n.global _g_fontawesome_data, _g_fontawesome_size\n\n_g_fontawesome_data:\n.incbin \"fontawesome-webfont.ttf\"\n_g_fontawesome_size:\n.int _g_fontawesome_size - _g_fontawesome_data\n\n"
  },
  {
    "path": "src/resource/embedded/icons8-checkmark-yes-32.hpng",
    "content": "\nunsigned char PNG_CHECK_YES_png[573] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7A, 0x7A, 0xF4, 0x00, 0x00, 0x00,\n\t0x06, 0x62, 0x4B, 0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0,\n\t0xBD, 0xA7, 0x93, 0x00, 0x00, 0x01, 0xF2, 0x49, 0x44, 0x41, 0x54, 0x58,\n\t0x85, 0xED, 0xD6, 0xBD, 0x6E, 0x13, 0x41, 0x10, 0x07, 0xF0, 0x1F, 0x35,\n\t0x89, 0xA0, 0xA0, 0x00, 0x4C, 0xC4, 0x97, 0xC1, 0x79, 0x14, 0xA4, 0x38,\n\t0xA1, 0x25, 0xF0, 0x04, 0x40, 0x28, 0x10, 0x79, 0x06, 0x2A, 0x1A, 0x3A,\n\t0x82, 0x78, 0x80, 0xC8, 0x24, 0x08, 0x10, 0xD0, 0x22, 0x51, 0x21, 0x1E,\n\t0x00, 0x41, 0x0A, 0x28, 0x80, 0x1A, 0x08, 0x05, 0x32, 0xC6, 0x32, 0xC5,\n\t0x8E, 0x39, 0x63, 0x11, 0xDF, 0xDE, 0x39, 0x5D, 0xF2, 0x97, 0xB6, 0xB8,\n\t0xDD, 0x99, 0xFF, 0xCC, 0xCE, 0xED, 0x7C, 0xB0, 0x8F, 0xBD, 0x8E, 0x03,\n\t0x15, 0xE5, 0xE7, 0x70, 0x11, 0x0B, 0x38, 0x15, 0xDF, 0xF0, 0x09, 0x1F,\n\t0xF1, 0x1C, 0x4F, 0xF0, 0x79, 0x97, 0xFC, 0xFB, 0x8B, 0x06, 0xD6, 0xD0,\n\t0xC3, 0xA0, 0x64, 0xF5, 0xD1, 0xC1, 0xC9, 0xDD, 0x32, 0xBE, 0x84, 0xED,\n\t0x20, 0xEF, 0x62, 0x1D, 0x97, 0xD0, 0xC2, 0xC1, 0x58, 0x2D, 0x2C, 0xC7,\n\t0x59, 0x37, 0x64, 0xB7, 0xB1, 0x38, 0xAD, 0xF1, 0x1B, 0xD2, 0x8D, 0x06,\n\t0xD2, 0xAD, 0x4E, 0x67, 0xE8, 0x9C, 0xC1, 0x86, 0x22, 0x1A, 0x2B, 0x75,\n\t0x8D, 0x2F, 0x05, 0xC1, 0x6F, 0xDC, 0xAC, 0xA1, 0x7F, 0x2B, 0x74, 0xFB,\n\t0x6A, 0x44, 0xA2, 0xA1, 0x08, 0x7B, 0x1D, 0xE3, 0xA3, 0x4E, 0x0C, 0xF0,\n\t0x1D, 0xC7, 0xAA, 0x28, 0x3E, 0x50, 0x84, 0x7D, 0x5A, 0x6C, 0x06, 0xD7,\n\t0x5A, 0xAE, 0xC2, 0x9C, 0x14, 0xBA, 0xAE, 0xBC, 0x7F, 0x5E, 0x86, 0xB3,\n\t0xC1, 0xD5, 0x93, 0x22, 0x5B, 0x8A, 0x15, 0xC9, 0xE3, 0xF5, 0x9A, 0x06,\n\t0xEF, 0x48, 0xA1, 0x1F, 0x45, 0x27, 0x38, 0xAF, 0xE5, 0x10, 0xBC, 0x08,\n\t0xE1, 0xE5, 0x9A, 0xC6, 0x07, 0xF8, 0xE9, 0xDF, 0x3A, 0x70, 0x25, 0xF6,\n\t0x9F, 0xE5, 0x90, 0x6C, 0x85, 0x70, 0xB3, 0xA2, 0xF1, 0xDB, 0x8A, 0x5A,\n\t0xD1, 0x1E, 0x3B, 0x6B, 0xC5, 0xD9, 0xBB, 0x1C, 0xA2, 0x1F, 0x21, 0x3C,\n\t0x33, 0xB6, 0x7F, 0x0E, 0x2F, 0xFD, 0xFF, 0x3F, 0x4E, 0x32, 0x2E, 0xB8,\n\t0x06, 0xC1, 0x5D, 0x8A, 0x61, 0xFA, 0xCD, 0x8E, 0xED, 0x3F, 0x56, 0xDC,\n\t0xE2, 0xF8, 0xC8, 0xFE, 0x68, 0xD8, 0x2F, 0xEC, 0xC0, 0x39, 0xAB, 0xA8,\n\t0x8E, 0xA5, 0x78, 0x1F, 0xC2, 0xE7, 0xC7, 0xF6, 0x0F, 0xE1, 0x75, 0x9C,\n\t0x6D, 0x49, 0x91, 0x28, 0xBB, 0xF9, 0x10, 0xF3, 0x21, 0xF7, 0x36, 0xC7,\n\t0x81, 0x49, 0x8F, 0xF0, 0x30, 0xDE, 0xC4, 0xF9, 0x57, 0xE5, 0x37, 0x1F,\n\t0xA2, 0xD2, 0x23, 0xBC, 0x6E, 0x72, 0x1A, 0x8E, 0x3A, 0x91, 0x63, 0x9C,\n\t0x22, 0x0D, 0xAF, 0xE6, 0x38, 0x70, 0x42, 0x2A, 0x1A, 0x5D, 0xA9, 0xB1,\n\t0xEC, 0xE4, 0xC4, 0xAB, 0x4C, 0xE3, 0x4D, 0x15, 0x0B, 0x11, 0xDC, 0x97,\n\t0x3C, 0xDE, 0x98, 0x20, 0x93, 0x3B, 0xCC, 0x3C, 0x0A, 0xAE, 0x7B, 0xB9,\n\t0xC6, 0x49, 0xAF, 0x7C, 0x98, 0x0D, 0xE3, 0x55, 0xAD, 0x0A, 0x56, 0x83,\n\t0xE3, 0x1B, 0x8E, 0x56, 0x55, 0x5E, 0x54, 0xB4, 0xE3, 0x3A, 0x4E, 0xAC,\n\t0x2A, 0xDA, 0xF1, 0x42, 0x0D, 0x7D, 0xA4, 0xBE, 0x30, 0x1C, 0x48, 0x36,\n\t0xA5, 0xC6, 0x52, 0x86, 0xA6, 0x22, 0xEC, 0x7D, 0xE9, 0x51, 0x4F, 0x85,\n\t0xB6, 0xD4, 0xCF, 0x87, 0xF9, 0xDE, 0xC1, 0x65, 0x29, 0xB7, 0x67, 0x62,\n\t0xCD, 0x4B, 0xA9, 0xF6, 0x10, 0xBF, 0x14, 0x61, 0xAF, 0x7D, 0xF3, 0x71,\n\t0x1C, 0xC1, 0x5D, 0x79, 0x43, 0x69, 0x4F, 0xEA, 0xFD, 0x59, 0x03, 0x48,\n\t0xD5, 0xB1, 0xBC, 0x21, 0x8D, 0x6A, 0x6D, 0x69, 0x56, 0x18, 0x1D, 0xCB,\n\t0x3F, 0x48, 0x63, 0xF9, 0x53, 0x7C, 0xA9, 0xC8, 0xBB, 0x8F, 0x3D, 0x8C,\n\t0x3F, 0x75, 0x73, 0xA4, 0xCD, 0x6F, 0x2F, 0x42, 0xB3, 0x00, 0x00, 0x00,\n\t0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/icons8-error-32.hpng",
    "content": "unsigned char PNG_ERROR_png[472] = {\n\t0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D,\n\t0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20,\n\t0x08, 0x06, 0x00, 0x00, 0x00, 0x73, 0x7A, 0x7A, 0xF4, 0x00, 0x00, 0x00,\n\t0x06, 0x62, 0x4B, 0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0,\n\t0xBD, 0xA7, 0x93, 0x00, 0x00, 0x01, 0x8D, 0x49, 0x44, 0x41, 0x54, 0x58,\n\t0x85, 0xED, 0x95, 0x4F, 0x28, 0x04, 0x71, 0x1C, 0xC5, 0x3F, 0xFE, 0x24,\n\t0xB4, 0x29, 0x29, 0x25, 0xA2, 0x94, 0x83, 0xE2, 0xE0, 0xA0, 0x28, 0x0E,\n\t0x14, 0x27, 0x4E, 0x14, 0x27, 0x7F, 0x8E, 0x9C, 0x38, 0x2B, 0x4E, 0xD6,\n\t0x95, 0x3B, 0x17, 0xE2, 0x66, 0x1D, 0x1D, 0x94, 0x72, 0x70, 0x50, 0x1C,\n\t0xC8, 0x65, 0x2F, 0x22, 0x91, 0x92, 0x92, 0xBF, 0x21, 0xD6, 0x61, 0xDF,\n\t0xB4, 0x63, 0xCD, 0xCC, 0xCE, 0xAC, 0x9D, 0xD9, 0xD4, 0xBE, 0xFA, 0xD6,\n\t0xF6, 0x7D, 0xEF, 0xF7, 0xDE, 0xDB, 0xDF, 0x4E, 0xB3, 0x90, 0xC3, 0x3F,\n\t0x47, 0xB3, 0x26, 0x6B, 0xD8, 0xD5, 0x64, 0x05, 0x83, 0x40, 0x4C, 0x33,\n\t0x10, 0x74, 0x78, 0x31, 0x70, 0x66, 0x2A, 0x70, 0x01, 0x94, 0x06, 0x59,\n\t0x60, 0x46, 0xC1, 0x27, 0x9A, 0x98, 0x76, 0x81, 0xA0, 0x1A, 0x78, 0x54,\n\t0x68, 0x2F, 0xD0, 0xAD, 0xCF, 0xCF, 0x40, 0x6D, 0x10, 0x05, 0xD6, 0x14,\n\t0x18, 0x31, 0xED, 0xB6, 0xB4, 0x5B, 0xF5, 0x3B, 0xBC, 0x0D, 0xF8, 0x02,\n\t0xDE, 0x80, 0x06, 0xD3, 0xBE, 0x1E, 0x78, 0x15, 0xD7, 0xE1, 0x57, 0x78,\n\t0x1E, 0x70, 0x40, 0xFC, 0x9B, 0x86, 0x2D, 0xF8, 0x05, 0x71, 0x87, 0x40,\n\t0xBE, 0x1F, 0x05, 0x46, 0x15, 0x70, 0x03, 0x94, 0x59, 0xF0, 0x21, 0xE0,\n\t0x5A, 0x9A, 0x91, 0x4C, 0x87, 0x87, 0x80, 0x2B, 0x99, 0x8F, 0x39, 0xE8,\n\t0xC6, 0x71, 0x2E, 0x99, 0x36, 0xC2, 0x32, 0x3E, 0xE2, 0xE7, 0xF5, 0x1A,\n\t0xEF, 0x01, 0x03, 0xF9, 0x24, 0x7E, 0xA6, 0xF9, 0x4C, 0x85, 0x9B, 0x1F,\n\t0xB0, 0xCE, 0x24, 0x2E, 0xB9, 0x00, 0x40, 0x3B, 0xD6, 0x0F, 0x6A, 0xDA,\n\t0x88, 0x28, 0x64, 0xDD, 0x82, 0xB3, 0x2A, 0x00, 0xB0, 0xA1, 0xFD, 0xE6,\n\t0x5F, 0xC3, 0xBB, 0x64, 0xF4, 0x02, 0xD4, 0x79, 0x28, 0x50, 0x03, 0x3C,\n\t0x89, 0xEB, 0x49, 0x37, 0xBC, 0x00, 0x38, 0x96, 0xC9, 0xAC, 0x8D, 0xC6,\n\t0xAE, 0x00, 0xC0, 0x9C, 0xB8, 0x53, 0xA0, 0x30, 0x9D, 0x02, 0x93, 0x32,\n\t0xB8, 0xC4, 0xFE, 0x8F, 0xC6, 0xA9, 0x40, 0x09, 0x70, 0x2E, 0x7E, 0xC2,\n\t0x6B, 0x78, 0x39, 0x70, 0xAB, 0xC3, 0x43, 0x5E, 0x0F, 0x9B, 0x30, 0x2C,\n\t0x8F, 0x3B, 0xA0, 0xC2, 0xCB, 0xC1, 0x25, 0x1D, 0xDC, 0x27, 0xFE, 0x06,\n\t0xB4, 0x83, 0xD3, 0x0D, 0x18, 0xD8, 0x93, 0x66, 0xD1, 0x6D, 0x78, 0x23,\n\t0xF0, 0x0E, 0x7C, 0x02, 0xAD, 0x29, 0xB4, 0x6E, 0x0A, 0xB4, 0xC8, 0xEB,\n\t0x03, 0x68, 0x72, 0x53, 0x60, 0x5B, 0xA6, 0xCB, 0x6E, 0xC4, 0x2E, 0xB1,\n\t0x22, 0xCF, 0x9D, 0x54, 0xC2, 0x7E, 0x09, 0x1F, 0x80, 0xAA, 0x0C, 0x16,\n\t0xA8, 0x04, 0xEE, 0xE5, 0xDD, 0x67, 0x27, 0x2A, 0x02, 0xA2, 0x24, 0xAE,\n\t0xD5, 0xAF, 0x89, 0x2A, 0xEB, 0x17, 0xA6, 0x03, 0x08, 0x37, 0x66, 0x2A,\n\t0xE5, 0x9D, 0xE5, 0x90, 0x43, 0x50, 0xF8, 0x06, 0xB0, 0x55, 0xA0, 0x4B,\n\t0x18, 0x99, 0x32, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44,\n\t0xAE, 0x42, 0x60, 0x82\n};\n"
  },
  {
    "path": "src/resource/embedded/resources.cpp",
    "content": "#include \"X_GAME_PROFILE.xpm\"\n#include \"M_WND_ICON128.xpm\"\n#include \"X_BOX.xpm\"\n#include \"X_SETTINGS.xpm\"\n#include \"X_HOTKEY_SETTINGS.xpm\"\n\n#include \"icons8-checkmark-yes-32.hpng\"\n#include \"icons8-error-32.hpng\"\n#include \"PNG_HELP.hpng\"\n#include \"PNG_REFRESH.hpng\"\n\n#include \"DEBUGGER_BP.hpng\"\n#include \"DEBUGGER_BP_RED.hpng\"\n#include \"DEBUGGER_PAUSE.hpng\"\n#include \"DEBUGGER_PLAY.hpng\"\n#include \"DEBUGGER_STEP_INTO.hpng\"\n#include \"DEBUGGER_STEP_OUT.hpng\"\n#include \"DEBUGGER_STEP_OVER.hpng\"\n#include \"DEBUGGER_GOTO.hpng\"\n\n#include \"INPUT_LOW_BATTERY.hpng\"\n#include \"INPUT_CONNECTED.hpng\"\n#include \"INPUT_DISCONNECTED.hpng\"\n"
  },
  {
    "path": "src/resource/embedded/resources.h",
    "content": "extern const char* X_GAME_PROFILE_xpm[];\nextern const char* M_WND_ICON128_xpm[];\nextern const char* X_BOX_xpm[];\nextern const char* X_SETTINGS_xpm[];\nextern const char* X_HOTKEY_SETTINGS_xpm[];\n\nextern unsigned char PNG_CHECK_YES_png[573];\nextern unsigned char PNG_ERROR_png[472];\nextern unsigned char PNG_HELP_png[492];\nextern unsigned char PNG_REFRESH_png[449];\n\nextern unsigned char DEBUGGER_BP_RED_png[470];\nextern unsigned char DEBUGGER_PAUSE_png[211];\nextern unsigned char DEBUGGER_PLAY_png[306];\nextern unsigned char DEBUGGER_STEP_INTO_png[297];\nextern unsigned char DEBUGGER_STEP_OUT_png[308];\nextern unsigned char DEBUGGER_STEP_OVER_png[296];\nextern unsigned char DEBUGGER_BP_png[436];\nextern unsigned char DEBUGGER_GOTO_png[292];\n\nextern unsigned char INPUT_CONNECTED_png[400];\nextern unsigned char INPUT_DISCONNECTED_png[410];\nextern unsigned char INPUT_LOW_BATTERY_png[340];"
  },
  {
    "path": "src/resource/installer.nsi",
    "content": "; Copyright Dolphin Emulator Project / Azahar Emulator Project / Team Cemu\n; Licensed under MPL 2.0 with permission from authors\n\n; Usage:\n;   get the latest nsis: https://nsis.sourceforge.io/Download\n;   probably also want vscode extension: https://marketplace.visualstudio.com/items?itemName=idleberg.nsis\n\n; Require /DPRODUCT_VERSION for makensis.\n!ifndef PRODUCT_VERSION\n  !error \"PRODUCT_VERSION must be defined\"\n!endif\n\nManifestDPIAware true\n\n!define PRODUCT_NAME \"Cemu\"\n!define PRODUCT_PUBLISHER \"Team Cemu\"\n!define PRODUCT_WEB_SITE \"https://cemu.info/\"\n!define PRODUCT_DIR_REGKEY \"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${PRODUCT_NAME}.exe\"\n!define PRODUCT_UNINST_KEY \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${PRODUCT_NAME}\"\n\n!define BINARY_SOURCE_DIR \"..\\..\\bin\"\n\nName \"${PRODUCT_NAME}\"\nOutFile \"cemu-${PRODUCT_VERSION}-windows-x64-installer.exe\"\nSetCompressor /SOLID lzma\nInstallDir \"$LOCALAPPDATA\\Cemu\" \nShowInstDetails show\nShowUnInstDetails show\n\n!include \"MUI2.nsh\"\n; Custom page plugin\n!include \"nsDialogs.nsh\"\n\n; MUI Settings\n!define MUI_ICON \"logo_icon.ico\"\n!define MUI_UNICON \"${NSISDIR}\\Contrib\\Graphics\\Icons\\modern-uninstall.ico\"\n\n; License page\n!insertmacro MUI_PAGE_LICENSE \"..\\..\\LICENSE.txt\"\n; Desktop Shortcut page\nPage custom desktopShortcutPageCreate desktopShortcutPageLeave\n; Directory page\n!insertmacro MUI_PAGE_DIRECTORY\n; Instfiles page\n!insertmacro MUI_PAGE_INSTFILES\n; Finish page\n!define MUI_FINISHPAGE_RUN \"$INSTDIR\\Cemu.exe\"\n!insertmacro MUI_PAGE_FINISH\n\n; Uninstaller pages\n!insertmacro MUI_UNPAGE_INSTFILES\n\n; Variables\nVar DesktopShortcutPageDialog\nVar DesktopShortcutCheckbox\nVar DesktopShortcut\n\n; Language files\n!insertmacro MUI_LANGUAGE \"English\"\n!insertmacro MUI_LANGUAGE \"SimpChinese\"\n!insertmacro MUI_LANGUAGE \"TradChinese\"\n!insertmacro MUI_LANGUAGE \"Danish\"\n!insertmacro MUI_LANGUAGE \"Dutch\"\n!insertmacro MUI_LANGUAGE \"French\"\n!insertmacro MUI_LANGUAGE \"German\"\n!insertmacro MUI_LANGUAGE \"Hungarian\"\n!insertmacro MUI_LANGUAGE \"Italian\"\n!insertmacro MUI_LANGUAGE \"Japanese\"\n!insertmacro MUI_LANGUAGE \"Korean\"\n!insertmacro MUI_LANGUAGE \"Lithuanian\"\n!insertmacro MUI_LANGUAGE \"Norwegian\"\n!insertmacro MUI_LANGUAGE \"Polish\"\n!insertmacro MUI_LANGUAGE \"PortugueseBR\"\n!insertmacro MUI_LANGUAGE \"Romanian\"\n!insertmacro MUI_LANGUAGE \"Russian\"\n!insertmacro MUI_LANGUAGE \"Spanish\"\n!insertmacro MUI_LANGUAGE \"Swedish\"\n!insertmacro MUI_LANGUAGE \"Turkish\"\n!insertmacro MUI_LANGUAGE \"Vietnamese\"\n\n; MUI end ------\n\nFunction .onInit\n  StrCpy $DesktopShortcut 1\n\n  !insertmacro MUI_LANGDLL_DISPLAY\nFunctionEnd\n\nFunction desktopShortcutPageCreate\n  !insertmacro MUI_HEADER_TEXT \"Create Desktop Shortcut\" \"Would you like to create a desktop shortcut?\"\n  nsDialogs::Create 1018\n  Pop $DesktopShortcutPageDialog\n  ${If} $DesktopShortcutPageDialog == error\n    Abort\n  ${EndIf}\n\n  ${NSD_CreateCheckbox} 0u 0u 100% 12u \"Create a desktop shortcut\"\n  Pop $DesktopShortcutCheckbox\n  ${NSD_SetState} $DesktopShortcutCheckbox $DesktopShortcut\n\n  nsDialogs::Show\nFunctionEnd\n\nFunction desktopShortcutPageLeave\n  ${NSD_GetState} $DesktopShortcutCheckbox $DesktopShortcut\nFunctionEnd\n\nSection \"Base\"\n  ExecWait '\"$INSTDIR\\uninst.exe\" /S _?=$INSTDIR'\n\n  SectionIn RO\n\n  SetOutPath \"$INSTDIR\"\n\n  ; The binplaced build output will be included verbatim.\n  File /r \"${BINARY_SOURCE_DIR}\\*\"\n\n  ; Create start menu and desktop shortcuts\n  CreateShortCut \"$SMPROGRAMS\\$(^Name).lnk\" \"$INSTDIR\\Cemu.exe\"\n  ${If} $DesktopShortcut == 1\n    CreateShortCut \"$DESKTOP\\$(^Name).lnk\" \"$INSTDIR\\Cemu.exe\"\n  ${EndIf}\nSectionEnd\n\n!include \"FileFunc.nsh\"\n\nSection -Post\n  WriteUninstaller \"$INSTDIR\\uninst.exe\"\n\n  WriteRegStr HKCU \"${PRODUCT_DIR_REGKEY}\" \"\" \"$INSTDIR\\Cemu.exe\"\n\n  ; Write metadata for add/remove programs applet\n  WriteRegStr HKCU \"${PRODUCT_UNINST_KEY}\" \"DisplayName\" \"$(^Name)\"\n  WriteRegStr HKCU \"${PRODUCT_UNINST_KEY}\" \"UninstallString\" \"$INSTDIR\\uninst.exe\"\n  WriteRegStr HKCU \"${PRODUCT_UNINST_KEY}\" \"DisplayIcon\" \"$INSTDIR\\Cemu.exe\"\n  WriteRegStr HKCU \"${PRODUCT_UNINST_KEY}\" \"URLInfoAbout\" \"${PRODUCT_WEB_SITE}\"\n  WriteRegStr HKCU \"${PRODUCT_UNINST_KEY}\" \"Publisher\" \"${PRODUCT_PUBLISHER}\"\n  WriteRegStr HKCU \"${PRODUCT_UNINST_KEY}\" \"InstallLocation\" \"$INSTDIR\"\n  ${GetSize} \"$INSTDIR\" \"/S=0K\" $0 $1 $2\n  IntFmt $0 \"0x%08X\" $0\n  WriteRegDWORD HKCU \"${PRODUCT_UNINST_KEY}\" \"EstimatedSize\" \"$0\"\n\n  WriteRegStr HKCU \"Software\\Classes\\.wud\" \"\" \"$(^Name)\"\n  WriteRegStr HKCU \"Software\\Classes\\.wux\" \"\" \"$(^Name)\"\n  WriteRegStr HKCU \"Software\\Classes\\.wua\" \"\" \"$(^Name)\"\n  WriteRegStr HKCU \"Software\\Classes\\$(^Name)\\DefaultIcon\" \"\" \"$INSTDIR\\Cemu.exe,0\"\n  WriteRegStr HKCU \"Software\\Classes\\$(^Name)\\Shell\\open\\command\" \"\" '\"$INSTDIR\\Cemu.exe\" %1'\nSectionEnd\n\nSection Uninstall\n  Delete \"$DESKTOP\\$(^Name).lnk\"\n  Delete \"$SMPROGRAMS\\$(^Name).lnk\"\n\n; Be a bit careful to not delete files a user may have put into the install directory\n  Delete \"$INSTDIR\\Cemu.exe\"\n  Delete \"$INSTDIR\\uninst.exe\"\n  RMDir /r \"$INSTDIR\\gameProfiles\"\n  RMDir /r \"$INSTDIR\\resources\"\n  RMDir \"$INSTDIR\"\n\n  DeleteRegKey HKCU \"Software\\Classes\\.wud\"\n  DeleteRegKey HKCU \"Software\\Classes\\.wux\"\n  DeleteRegKey HKCU \"Software\\Classes\\.wua\"\n  DeleteRegKey HKCU \"Software\\Classes\\$(^Name)\"\n\n  DeleteRegKey HKCU \"Software\\Classes\\discord-460807638964371468\"\n\n  DeleteRegKey HKCU \"${PRODUCT_UNINST_KEY}\"\n  DeleteRegKey HKCU \"${PRODUCT_DIR_REGKEY}\"\n\n  SetAutoClose true\nSectionEnd\n"
  },
  {
    "path": "src/resource/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by cemu.rc\n//\n#include \"Common/version.h\"\n#define IDI_ICON2                       102\n#define IDI_ICON3                       103\n#define IDR_FONTAWESOME                 116\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        118\n#define _APS_NEXT_COMMAND_VALUE         40001\n#define _APS_NEXT_CONTROL_VALUE         1001\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "src/resource/update.sh",
    "content": "#!/bin/sh\n\nAPP=$(cd \"$(dirname \"0\")\"/;pwd)\nhdiutil attach $TMPDIR/cemu_update/cemu.dmg\ncp -rf /Volumes/Cemu/Cemu.app \"$APP\"\nhdiutil detach /Volumes/Cemu/\n\nopen -n -a \"$APP/Cemu.app\"\n"
  },
  {
    "path": "src/tools/ShaderCacheMerger.cpp",
    "content": "#include \"Cemu/FileCache/FileCache.h\"\n#include \"Cafe/HW/Latte/Core/LatteShaderCache.h\"\n#include <regex>\n#include <cinttypes>\n\nvoid MergeShaderCacheFile(std::string fileName)\n{\n\t// parse titleId from fileName\n\tuint64 titleId = 0;\n\tif (sscanf(fileName.c_str(), \"%\" SCNx64, &titleId) != 1)\n\t\treturn;\n\n\tconst std::string mainPath = \"shaderCache/transferable/\" + fileName;\n\tconst std::string mergeSourcePath = \"shaderCache/transferable/merge/\" + fileName;\n\tif (!fs::exists(mainPath) || !fs::exists(mergeSourcePath))\n\t\treturn;\n\t// open both caches\n\tFileCache* mainCache = FileCache::Open(boost::nowide::widen(mainPath));\n\tFileCache* sourceCache = FileCache::Open(boost::nowide::widen(mergeSourcePath));\n\tif (!mainCache && !sourceCache)\n\t{\n\t\tprintf(\"Failed to open cache files for %s\\n\", fileName.c_str());\n\t\tif (mainCache)\n\t\t\tdelete mainCache;\n\t\tif (sourceCache)\n\t\t\tdelete sourceCache;\n\t\treturn;\n\t}\n\t// begin merging\n\tprintf(\"Merging shaders %\" PRIx64 \"...\", titleId);\n\tuint32 numMergedEntries = 0; // number of files added to the main cache file\n\tfor (sint32 i = 0; i < sourceCache->GetFileCount(); i++)\n\t{\n\t\tuint64 name1, name2;\n\t\tstd::vector<uint8> fileData;\n\t\tif (!sourceCache->GetFileByIndex(i, &name1, &name2, fileData))\n\t\t\tcontinue;\n\t\tstd::vector<uint8> existingfileData;\n\t\tif (mainCache->HasFile({ name1, name2 }))\n\t\t\tcontinue;\n\t\tmainCache->AddFile({ name1, name2 }, fileData.data(), (sint32)fileData.size());\n\t\tnumMergedEntries++;\n\t}\n\tprintf(\" -> Added %d new shaders for a total of %d\\n\", numMergedEntries, mainCache->GetFileCount());\n\n\tdelete mainCache;\n\tdelete sourceCache;\n\n\tfs::remove(mergeSourcePath);\n}\n\nvoid MergePipelineCacheFile(std::string fileName)\n{\n\t// parse titleId from fileName\n\tuint64 titleId = 0;\n\tif (sscanf(fileName.c_str(), \"%\" SCNx64, &titleId) != 1)\n\t\treturn;\n\n\tconst std::string mainPath = \"shaderCache/transferable/\" + fileName;\n\tconst std::string mergeSourcePath = \"shaderCache/transferable/merge/\" + fileName;\n\tif (!fs::exists(mainPath) || !fs::exists(mergeSourcePath))\n\t\treturn;\n\t// open both caches\n\tconst uint32 cacheFileVersion = 1;\n\tFileCache* mainCache = FileCache::Open(boost::nowide::widen(mainPath));\n\tFileCache* sourceCache = FileCache::Open(boost::nowide::widen(mergeSourcePath));\n\tif (!mainCache && !sourceCache)\n\t{\n\t\tprintf(\"Failed to open cache files for %s\\n\", fileName.c_str());\n\t\tif (mainCache)\n\t\t\tdelete mainCache;\n\t\tif (sourceCache)\n\t\t\tdelete sourceCache;\n\t\treturn;\n\t}\n\t// begin merging\n\tprintf(\"Merging pipelines %\" PRIx64 \"...\", titleId);\n\tuint32 numMergedEntries = 0; // number of files added to the main cache file\n\tfor (sint32 i = 0; i < sourceCache->GetFileCount(); i++)\n\t{\n\t\tuint64 name1, name2;\n\t\tstd::vector<uint8> fileData;\n\t\tif (!sourceCache->GetFileByIndex(i, &name1, &name2, fileData))\n\t\t\tcontinue;\n\t\tstd::vector<uint8> existingfileData;\n\t\tif (mainCache->HasFile({ name1, name2 }))\n\t\t\tcontinue;\n\t\tmainCache->AddFile({ name1, name2 }, fileData.data(), (sint32)fileData.size());\n\t\tnumMergedEntries++;\n\t}\n\tprintf(\" -> Added %d new pipelines for a total of %d\\n\", numMergedEntries, mainCache->GetFileCount());\n\n\tdelete mainCache;\n\tdelete sourceCache;\n\n\tfs::remove(mergeSourcePath);\n}\n\nvoid MergeShaderAndPipelineCacheFiles()\n{\n\tprintf(\"Scanning for shader cache files to merge...\\n\");\n\tfor (const auto& it : fs::directory_iterator(\"shaderCache/transferable/\"))\n\t{\n\t\tif (fs::is_directory(it))\n\t\t\tcontinue;\n\t\tauto filename = it.path().filename().generic_string();\n\t\tif (std::regex_match(filename, std::regex(\"^[0-9a-fA-F]{16}(?:_shaders.bin)\")))\n\t\t\tMergeShaderCacheFile(filename);\n\t\tif (std::regex_match(filename, std::regex(\"^[0-9a-fA-F]{16}(?:_mtlshaders.bin)\")))\n\t\t\tMergeShaderCacheFile(filename);\n\t}\n\tprintf(\"\\nScanning for pipeline cache files to merge...\\n\");\n\tfor (const auto& it : fs::directory_iterator(\"shaderCache/transferable/\"))\n\t{\n\t\tif (fs::is_directory(it))\n\t\t\tcontinue;\n\t\tauto filename = it.path().filename().generic_string();\n\t\tif (std::regex_match(filename, std::regex(\"^[0-9a-fA-F]{16}(?:_vkpipeline.bin)\")))\n\t\t\tMergePipelineCacheFile(filename);\n\t\tif (std::regex_match(filename, std::regex(\"^[0-9a-fA-F]{16}(?:_mtlpipeline.bin)\")))\n\t\t\tMergePipelineCacheFile(filename);\n\t}\n}\n\nvoid ToolShaderCacheMerger()\n{\n\tprintf(\"****************************************************\\n\");\n\tprintf(\"****************************************************\\n\");\n\tprintf(\"Shader and pipeline cache merging tool\\n\");\n\tprintf(\"This tool will merge any shader caches placed in:\\n\");\n\tprintf(\"shaderCache/transferable/merge/\\n\");\n\tprintf(\"into the files of the same name in:\\n\");\n\tprintf(\"shaderCache/transferable/\\n\");\n\tprintf(\"****************************************************\\n\");\n\tprintf(\"****************************************************\\n\");\n\tprintf(\"\\n\");\n\n\tMergeShaderAndPipelineCacheFiles();\n\n\n\tprintf(\"done!\\n\");\n\twhile (true)\n\t\tSleep(1000);\n\texit(0);\n}\n"
  },
  {
    "path": "src/util/CMakeLists.txt",
    "content": "add_library(CemuUtil\n  boost/bluetooth.h\n  bootSound/BootSoundReader.cpp\n  bootSound/BootSoundReader.h\n  ChunkedHeap/ChunkedHeap.h\n  containers/flat_hash_map.hpp\n  containers/IntervalBucketContainer.h\n  containers/LookupTableL3.h\n  containers/RangeStore.h\n  containers/robin_hood.h\n  containers/SmallBitset.h\n  crypto/aes128.cpp\n  crypto/aes128.h\n  crypto/crc32.cpp\n  crypto/crc32.h\n  crypto/md5.cpp\n  crypto/md5.h\n  DXGIWrapper/DXGIWrapper.h\n  EventService.h\n  Fiber/Fiber.h\n  helpers/ClassWrapper.h\n  helpers/ConcurrentQueue.h\n  helpers/enum_array.hpp\n  helpers/fixedSizeList.h\n  helpers/fspinlock.h\n  helpers/helpers.cpp\n  helpers/helpers.h\n  helpers/MapAdaptor.h\n  helpers/MemoryPool.h\n  helpers/ringbuffer.h\n  helpers/Semaphore.h\n  helpers/Serializer.cpp\n  helpers/Serializer.h\n  helpers/Singleton.h\n  helpers/StringBuf.h\n  helpers/StringHelpers.h\n  helpers/StringParser.h\n  helpers/SystemException.h\n  helpers/TempState.h\n  highresolutiontimer/HighResolutionTimer.cpp\n  highresolutiontimer/HighResolutionTimer.h\n  ImageWriter/bmp.h\n  ImageWriter/tga.h\n  IniParser/IniParser.cpp\n  IniParser/IniParser.h\n  libusbWrapper/libusbWrapper.cpp\n  libusbWrapper/libusbWrapper.h\n  math/glm.h\n  math/quaternion.h\n  math/vector2.h\n  math/vector3.h\n  MemMapper/MemMapper.h\n  SystemInfo/SystemInfo.cpp\n  SystemInfo/SystemInfo.h\n  ThreadPool/ThreadPool.h\n  tinyxml2/tinyxml2.cpp\n  tinyxml2/tinyxml2.h\n  VirtualHeap/VirtualHeap.cpp\n  VirtualHeap/VirtualHeap.h\n  Zir/Core/IR.cpp\n  Zir/Core/IR.h\n  Zir/Core/ZirUtility.h\n  Zir/Core/ZpIRBuilder.h\n  Zir/Core/ZpIRDebug.h\n  Zir/Core/ZpIRPasses.h\n  Zir/Core/ZpIRScheduler.h\n  Zir/EmitterGLSL/ZpIREmitGLSL.cpp\n  Zir/EmitterGLSL/ZpIREmitGLSL.h\n  Zir/Passes/RegisterAllocatorForGLSL.cpp\n  Zir/Passes/ZpIRRegisterAllocator.cpp\n)\n\nif(WIN32)\n\ttarget_sources(CemuUtil PRIVATE Fiber/FiberWin.cpp)\n\ttarget_sources(CemuUtil PRIVATE MemMapper/MemMapperWin.cpp)\n\ttarget_sources(CemuUtil PRIVATE SystemInfo/SystemInfoWin.cpp)\nelseif(UNIX)\n\ttarget_sources(CemuUtil PRIVATE Fiber/FiberUnix.cpp)\n\ttarget_sources(CemuUtil PRIVATE MemMapper/MemMapperUnix.cpp)\n\ttarget_sources(CemuUtil PRIVATE SystemInfo/SystemInfoUnix.cpp)\n\tif(NOT APPLE)\n\t\ttarget_sources(CemuUtil PRIVATE SystemInfo/SystemInfoLinux.cpp)\n\telse()\n\t\ttarget_sources(CemuUtil PRIVATE SystemInfo/SystemInfoMac.cpp)\n\tendif()\nelse()\n\ttarget_sources(CemuUtil PRIVATE SystemInfo/SystemInfoStub.cpp)\nendif()\n\nset_property(TARGET CemuUtil PROPERTY MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$<CONFIG:Debug>:Debug>\")\n\ntarget_include_directories(CemuUtil PUBLIC \"../\")\n\ntarget_link_libraries(CemuUtil PRIVATE\n  CemuCommon\n)\n"
  },
  {
    "path": "src/util/ChunkedHeap/ChunkedHeap.h",
    "content": "#pragma once\n\n#include <util/helpers/MemoryPool.h>\n\nstruct CHAddr\n{\n\tuint32 offset;\n\tuint32 chunkIndex;\n\tvoid* internal; // AllocRange\n\n\tCHAddr(uint32 _offset, uint32 _chunkIndex, void* internal = nullptr) : offset(_offset), chunkIndex(_chunkIndex), internal(internal) {};\n\tCHAddr() : offset(0xFFFFFFFF), chunkIndex(0xFFFFFFFF) {};\n\n\tbool isValid() { return chunkIndex != 0xFFFFFFFF; };\n\tstatic CHAddr getInvalid() { return CHAddr(0xFFFFFFFF, 0xFFFFFFFF); };\n};\n\ntemplate<uint32 TMinimumAlignment = 32>\nclass ChunkedHeap\n{\n\tstruct AllocRange\n\t{\n\t\tAllocRange* nextFree{};\n\t\tAllocRange* prevFree{};\n\t\tAllocRange* prevOrdered{};\n\t\tAllocRange* nextOrdered{};\n\t\tuint32 offset;\n\t\tuint32 chunkIndex;\n\t\tuint32 size;\n\t\tbool isFree;\n\t\tAllocRange(uint32 _offset, uint32 _chunkIndex, uint32 _size, bool _isFree) : offset(_offset), chunkIndex(_chunkIndex), size(_size), isFree(_isFree), nextFree(nullptr) {};\n\t};\n\n\tstruct Chunk\n\t{\n\t\tuint32 size;\n\t};\n\npublic:\n\tChunkedHeap()\n\t{\n\t}\n\n\tCHAddr alloc(uint32 size, uint32 alignment = 4)\n\t{\n\t\treturn _alloc(size, alignment);\n\t}\n\n\tvoid free(CHAddr addr)\n\t{\n\t\t_free(addr);\n\t}\n\n\tvirtual uint32 allocateNewChunk(uint32 chunkIndex, uint32 minimumAllocationSize) = 0;\n\nprivate:\n\tunsigned ulog2(uint32 v)\n\t{\n\t\tcemu_assert_debug(v != 0);\n\t\treturn 31 - std::countl_zero(v);\n\t}\n\n\tvoid trackFreeRange(AllocRange* range)\n\t{\n\t\t// get index of msb\n\t\tcemu_assert_debug(range->size != 0); // size of zero is not allowed\n\t\tuint32 bucketIndex = ulog2(range->size);\n\t\trange->nextFree = m_bucketFreeRange[bucketIndex];\n\t\tif (m_bucketFreeRange[bucketIndex])\n\t\t\tm_bucketFreeRange[bucketIndex]->prevFree = range;\n\t\trange->prevFree = nullptr;\n\t\tm_bucketFreeRange[bucketIndex] = range;\n\t\tm_bucketUseMask |= (1u << bucketIndex);\n\t}\n\n\tvoid forgetFreeRange(AllocRange* range, uint32 bucketIndex)\n\t{\n\t\tAllocRange* prevRange = range->prevFree;\n\t\tAllocRange* nextRange = range->nextFree;\n\t\tif (prevRange)\n\t\t{\n\t\t\tprevRange->nextFree = nextRange;\n\t\t\tif (nextRange)\n\t\t\t\tnextRange->prevFree = prevRange;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(m_bucketFreeRange[bucketIndex] == range);\n\t\t\tm_bucketFreeRange[bucketIndex] = nextRange;\n\t\t\tif (nextRange)\n\t\t\t\tnextRange->prevFree = nullptr;\n\t\t\telse\n\t\t\t\tm_bucketUseMask &= ~(1u << bucketIndex);\n\t\t}\n\t}\n\n\tbool allocateChunk(uint32 minimumAllocationSize)\n\t{\n\t\tuint32 chunkIndex = (uint32)m_chunks.size();\n\t\tm_chunks.emplace_back();\n\t\tuint32 chunkSize = allocateNewChunk(chunkIndex, minimumAllocationSize);\n\t\tcemu_assert_debug((chunkSize%TMinimumAlignment) == 0); // chunk size should be a multiple of the minimum alignment\n\t\tif (chunkSize == 0)\n\t\t\treturn false;\n\t\tcemu_assert_debug(chunkSize < 0x80000000u); // chunk size must be below 2GB\n\t\tAllocRange* range = m_allocEntriesPool.allocObj(0, chunkIndex, chunkSize, true);\n\t\ttrackFreeRange(range);\n\t\tm_numHeapBytes += chunkSize;\n\t\treturn true;\n\t}\n\n\tvoid _allocFrom(AllocRange* range, uint32 bucketIndex, uint32 allocOffset, uint32 allocSize)\n\t{\n\t\tcemu_assert_debug(allocSize > 0);\n\t\t// remove the range from the chain of free ranges\n\t\tforgetFreeRange(range, bucketIndex);\n\t\t// split head, allocation and tail into separate ranges\n\t\tuint32 headBytes = allocOffset - range->offset;\n\t\tif (headBytes > 0)\n\t\t{\n\t\t\t// alignment padding -> create free range\n\t\t\tcemu_assert_debug(headBytes >= TMinimumAlignment);\n\t\t\tAllocRange* head = m_allocEntriesPool.allocObj(range->offset, range->chunkIndex, headBytes, true);\n\t\t\ttrackFreeRange(head);\n\t\t\tif (range->prevOrdered)\n\t\t\t\trange->prevOrdered->nextOrdered = head;\n\t\t\thead->prevOrdered = range->prevOrdered;\n\t\t\thead->nextOrdered = range;\n\t\t\trange->prevOrdered = head;\n\t\t}\n\t\tuint32 tailBytes = (range->offset + range->size) - (allocOffset + allocSize);\n\t\tif (tailBytes > 0)\n\t\t{\n\t\t\t// tail -> create free range\n\t\t\tcemu_assert_debug(tailBytes >= TMinimumAlignment);\n\t\t\tAllocRange* tail = m_allocEntriesPool.allocObj((allocOffset + allocSize), range->chunkIndex, tailBytes, true);\n\t\t\ttrackFreeRange(tail);\n\t\t\tif (range->nextOrdered)\n\t\t\t\trange->nextOrdered->prevOrdered = tail;\n\t\t\ttail->prevOrdered = range;\n\t\t\ttail->nextOrdered = range->nextOrdered;\n\t\t\trange->nextOrdered = tail;\n\t\t}\n\t\trange->offset = allocOffset;\n\t\trange->size = allocSize;\n\t\trange->isFree = false;\n\t}\n\n\tCHAddr _alloc(uint32 size, uint32 alignment)\n\t{\n\t\tcemu_assert_debug(size <= (0x7FFFFFFFu-TMinimumAlignment));\n\t\t// make sure size is not zero and align it\n\t\tif(size == 0) [[unlikely]]\n\t\t\tsize = TMinimumAlignment;\n\t\telse\n\t\t\tsize = (size + (TMinimumAlignment - 1)) & ~(TMinimumAlignment - 1);\n\t\t// find smallest bucket to scan\n\t\tuint32 alignmentM1 = alignment - 1;\n\t\tuint32 bucketIndex = ulog2(size);\n\t\t// check if the bucket is available\n\t\tif( !(m_bucketUseMask & (1u << bucketIndex)) )\n\t\t{\n\t\t\t// skip to next non-empty bucket\n\t\t\tuint32 nextIndex = BSF(m_bucketUseMask>>bucketIndex);\n\t\t\tbucketIndex += nextIndex;\n\t\t}\n\t\twhile (bucketIndex < 31)\n\t\t{\n\t\t\tAllocRange* range = m_bucketFreeRange[bucketIndex];\n\t\t\twhile (range)\n\t\t\t{\n\t\t\t\tif (range->size >= size)\n\t\t\t\t{\n\t\t\t\t\t// verify if aligned allocation fits\n\t\t\t\t\tuint32 alignedOffset = (range->offset + alignmentM1) & ~alignmentM1;\n\t\t\t\t\tuint32 endOffset = alignedOffset + size;\n\t\t\t\t\tif((range->offset+range->size) >= endOffset)\n\t\t\t\t\t{\n\t\t\t\t\t\t_allocFrom(range, bucketIndex, alignedOffset, size);\n\t\t\t\t\t\tm_numAllocatedBytes += size;\n\t\t\t\t\t\treturn CHAddr(alignedOffset, range->chunkIndex, range);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trange = range->nextFree;\n\t\t\t}\n\t\t\t// check next non-empty bucket or skip to end\n\t\t\tbucketIndex++;\n\t\t\tuint32 emptyBuckets = BSF(m_bucketUseMask>>bucketIndex);\n\t\t\tbucketIndex += emptyBuckets;\n\t\t}\n\t\tif(m_allocationLimitReached)\n\t\t\treturn CHAddr(0xFFFFFFFF, 0xFFFFFFFF);\n\t\tif (!allocateChunk(size))\n\t\t{\n\t\t\tm_allocationLimitReached = true;\n\t\t\treturn CHAddr(0xFFFFFFFF, 0xFFFFFFFF);\n\t\t}\n\t\treturn _alloc(size, alignment);\n\t}\n\n\tvoid _free(CHAddr addr)\n\t{\n\t\tif(!addr.internal)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"Internal heap error. {:08x} {:08x}\", addr.chunkIndex, addr.offset);\n\t\t\treturn;\n\t\t}\n\t\tAllocRange* range = (AllocRange*)addr.internal;\n\t\tm_numAllocatedBytes -= range->size;\n\t\t// try merge left or right\n\t\tAllocRange* prevRange = range->prevOrdered;\n\t\tAllocRange* nextRange = range->nextOrdered;\n\t\tif (prevRange && prevRange->isFree)\n\t\t{\n\t\t\tif (nextRange && nextRange->isFree)\n\t\t\t{\n\t\t\t\tforgetFreeRange(nextRange, ulog2(nextRange->size));\n\t\t\t\tuint32 newSize = (nextRange->offset + nextRange->size) - prevRange->offset;\n\t\t\t\tprevRange->nextOrdered = nextRange->nextOrdered;\n\t\t\t\tif (nextRange->nextOrdered)\n\t\t\t\t\tnextRange->nextOrdered->prevOrdered = prevRange;\n\t\t\t\tforgetFreeRange(prevRange, ulog2(prevRange->size));\n\t\t\t\tprevRange->size = newSize;\n\t\t\t\ttrackFreeRange(prevRange);\n\t\t\t\tm_allocEntriesPool.freeObj(range);\n\t\t\t\tm_allocEntriesPool.freeObj(nextRange);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint32 newSize = (range->offset + range->size) - prevRange->offset;\n\t\t\t\tprevRange->nextOrdered = nextRange;\n\t\t\t\tif (nextRange)\n\t\t\t\t\tnextRange->prevOrdered = prevRange;\n\t\t\t\tforgetFreeRange(prevRange, ulog2(prevRange->size));\n\t\t\t\tprevRange->size = newSize;\n\t\t\t\ttrackFreeRange(prevRange);\n\t\t\t\tm_allocEntriesPool.freeObj(range);\n\t\t\t}\n\t\t}\n\t\telse if (nextRange && nextRange->isFree)\n\t\t{\n\t\t\tuint32 newOffset = range->offset;\n\t\t\tuint32 newSize = (nextRange->offset + nextRange->size) - newOffset;\n\t\t\tforgetFreeRange(nextRange, ulog2(nextRange->size));\n\t\t\tnextRange->offset = newOffset;\n\t\t\tnextRange->size = newSize;\n\t\t\tif (range->prevOrdered)\n\t\t\t\trange->prevOrdered->nextOrdered = nextRange;\n\t\t\tnextRange->prevOrdered = range->prevOrdered;\n\t\t\ttrackFreeRange(nextRange);\n\t\t\tm_allocEntriesPool.freeObj(range);\n\t\t}\n\t\telse\n\t\t{\n\t\t\trange->isFree = true;\n\t\t\ttrackFreeRange(range);\n\t\t}\n\t}\n\n\tvoid verifyHeap()\n\t{\n\t\t// check for collisions within bucketFreeRange\n\t\tstruct availableRange_t\n\t\t{\n\t\t\tuint32 chunkIndex;\n\t\t\tuint32 offset;\n\t\t\tuint32 size;\n\t\t};\n\n\t\tstd::vector<availableRange_t> availRanges;\n\n\t\tfor (uint32 i = 0; i < 32; i++)\n\t\t{\n\t\t\tAllocRange* ar = m_bucketFreeRange[i];\n\t\t\twhile (ar)\n\t\t\t{\n\t\t\t\tavailableRange_t dbgRange;\n\t\t\t\tdbgRange.chunkIndex = ar->chunkIndex;\n\t\t\t\tdbgRange.offset = ar->offset;\n\t\t\t\tdbgRange.size = ar->size;\n\n\t\t\t\tfor (auto& itr : availRanges)\n\t\t\t\t{\n\t\t\t\t\tif (itr.chunkIndex != dbgRange.chunkIndex)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (itr.offset < (dbgRange.offset + dbgRange.size) && (itr.offset + itr.size) > dbgRange.offset)\n\t\t\t\t\t\tcemu_assert_error();\n\t\t\t\t}\n\n\t\t\t\tavailRanges.emplace_back(dbgRange);\n\n\t\t\t\tar = ar->nextFree;\n\t\t\t}\n\t\t}\n\n\t}\n\nprivate:\n\tstd::vector<Chunk> m_chunks;\n\tuint32 m_bucketUseMask{0x80000000}; // bitmask indicating non-empty buckets. MSB always set to provide an upper bound for BSF instruction\n\tAllocRange* m_bucketFreeRange[32]{}; // we are only using 31 entries since the MSB is reserved (thus chunks equal or larger than 2^31 are not allowed)\n\tbool m_allocationLimitReached = false;\n\tMemoryPool<AllocRange> m_allocEntriesPool{64};\n\npublic:\n\t// statistics\n\tuint32 m_numHeapBytes{}; // total size of the heap\n\tuint32 m_numAllocatedBytes{};\n};\n\nclass VGenericHeap\n{\npublic:\n\tvirtual void* alloc(uint32 size, uint32 alignment) = 0;\n\tvirtual void free(void* addr) = 0;\n};\n\nclass VHeap : public VGenericHeap\n{\n\tstruct allocRange_t\n\t{\n\t\tallocRange_t* nextFree{};\n\t\tallocRange_t* prevFree{};\n\t\tallocRange_t* prevOrdered{};\n\t\tallocRange_t* nextOrdered{};\n\t\tuint32 offset;\n\t\tuint32 size;\n\t\tbool isFree;\n\t\tallocRange_t(uint32 _offset, uint32 _size, bool _isFree) : offset(_offset), size(_size), isFree(_isFree), nextFree(nullptr) {};\n\t};\n\n\tstruct chunk_t\n\t{\n\t\tstd::unordered_map<uint32, allocRange_t*> map_allocatedRange;\n\t};\n\npublic:\n\tVHeap(void* heapBase, uint32 heapSize) : m_heapBase((uint8*)heapBase), m_heapSize(heapSize)\n\t{\n\t\tallocRange_t* range = new allocRange_t(0, heapSize, true);\n\t\ttrackFreeRange(range);\n\t}\n\n\t~VHeap()\n\t{\n\t\tfor (auto freeRange : bucketFreeRange)\n\t\t{\n\t\t\twhile (freeRange)\n\t\t\t{\n\t\t\t\tauto temp = freeRange;\n\t\t\t\tfreeRange = freeRange->nextFree;\n\t\t\t\tdelete temp;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid setHeapBase(void* heapBase)\n\t{\n\t\tcemu_assert_debug(map_allocatedRange.empty()); // heap base can only be changed when there are no active allocations\n\t\tm_heapBase = (uint8*)heapBase;\n\t}\n\n\tvoid* alloc(uint32 size, uint32 alignment = 4) override\n\t{\n\t\tcemu_assert_debug(m_heapBase != nullptr); // if this is null, we cant use alloc() == nullptr to determine if an allocation failed\n\t\tuint32 allocOffset = 0;\n\t\tbool r = _alloc(size, alignment, allocOffset);\n\t\tif (!r)\n\t\t\treturn nullptr;\n\t\treturn m_heapBase + allocOffset;\n\t}\n\n\tvoid free(void* addr) override\n\t{\n\t\t_free((uint32)((uint8*)addr - (uint8*)m_heapBase));\n\t}\n\n\tbool allocOffset(uint32 size, uint32 alignment, uint32& offsetOut)\n\t{\n\t\tuint32 allocOffset = 0;\n\t\tbool r = _alloc(size, alignment, allocOffset);\n\t\tif (!r)\n\t\t\treturn false;\n\t\toffsetOut = allocOffset;\n\t\treturn true;\n\t}\n\n\tvoid freeOffset(uint32 offset)\n\t{\n\t\t_free((uint32)offset);\n\t}\n\n\tuint32 getAllocationSizeFromAddr(void* addr)\n\t{\n\t\tuint32 addrOffset = (uint32)((uint8*)addr - m_heapBase);\n\t\tauto it = map_allocatedRange.find(addrOffset);\n\t\tif (it == map_allocatedRange.end())\n\t\t\tassert_dbg();\n\t\treturn it->second->size;\n\t}\n\n\tbool hasAllocations()\n\t{\n\t\treturn !map_allocatedRange.empty();\n\t}\n\n\tvoid getStats(uint32& heapSize, uint32& allocationSize, uint32& allocNum)\n\t{\n\t\theapSize = m_heapSize;\n\t\tallocationSize = m_statsMemAllocated;\n\t\tallocNum = (uint32)map_allocatedRange.size();\n\t}\n\nprivate:\n\tunsigned ulog2(uint32 v)\n\t{\n\t\tstatic const unsigned MUL_DE_BRUIJN_BIT[] =\n\t\t{\n\t\t   0,  9,  1, 10, 13, 21,  2, 29, 11, 14, 16, 18, 22, 25,  3, 30,\n\t\t   8, 12, 20, 28, 15, 17, 24,  7, 19, 27, 23,  6, 26,  5,  4, 31\n\t\t};\n\n\t\tv |= v >> 1;\n\t\tv |= v >> 2;\n\t\tv |= v >> 4;\n\t\tv |= v >> 8;\n\t\tv |= v >> 16;\n\n\t\treturn MUL_DE_BRUIJN_BIT[(v * 0x07C4ACDDu) >> 27];\n\t}\n\n\tvoid trackFreeRange(allocRange_t* range)\n\t{\n\t\t// get index of msb\n\t\tif (range->size == 0)\n\t\t\tassert_dbg(); // not allowed\n\t\tuint32 bucketIndex = ulog2(range->size);\n\t\trange->nextFree = bucketFreeRange[bucketIndex];\n\t\tif (bucketFreeRange[bucketIndex])\n\t\t\tbucketFreeRange[bucketIndex]->prevFree = range;\n\t\trange->prevFree = nullptr;\n\t\tbucketFreeRange[bucketIndex] = range;\n\t}\n\n\tvoid forgetFreeRange(allocRange_t* range, uint32 bucketIndex)\n\t{\n\t\tallocRange_t* prevRange = range->prevFree;\n\t\tallocRange_t* nextRange = range->nextFree;\n\t\tif (prevRange)\n\t\t{\n\t\t\tprevRange->nextFree = nextRange;\n\t\t\tif (nextRange)\n\t\t\t\tnextRange->prevFree = prevRange;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (bucketFreeRange[bucketIndex] != range)\n\t\t\t\tassert_dbg();\n\t\t\tbucketFreeRange[bucketIndex] = nextRange;\n\t\t\tif (nextRange)\n\t\t\t\tnextRange->prevFree = nullptr;\n\t\t}\n\t}\n\n\tvoid _allocFrom(allocRange_t* range, uint32 bucketIndex, uint32 allocOffset, uint32 allocSize)\n\t{\n\t\t// remove the range from the chain of free ranges\n\t\tforgetFreeRange(range, bucketIndex);\n\t\t// split head, allocation and tail into separate ranges\n\t\tif (allocOffset > range->offset)\n\t\t{\n\t\t\t// alignment padding -> create free range\n\t\t\tallocRange_t* head = new allocRange_t(range->offset, allocOffset - range->offset, true);\n\t\t\ttrackFreeRange(head);\n\t\t\tif (range->prevOrdered)\n\t\t\t\trange->prevOrdered->nextOrdered = head;\n\t\t\thead->prevOrdered = range->prevOrdered;\n\t\t\thead->nextOrdered = range;\n\t\t\trange->prevOrdered = head;\n\t\t}\n\t\tif ((allocOffset + allocSize) < (range->offset + range->size)) // todo - create only if it's more than a couple of bytes?\n\t\t{\n\t\t\t// tail -> create free range\n\t\t\tallocRange_t* tail = new allocRange_t((allocOffset + allocSize), (range->offset + range->size) - (allocOffset + allocSize), true);\n\t\t\ttrackFreeRange(tail);\n\t\t\tif (range->nextOrdered)\n\t\t\t\trange->nextOrdered->prevOrdered = tail;\n\t\t\ttail->prevOrdered = range;\n\t\t\ttail->nextOrdered = range->nextOrdered;\n\t\t\trange->nextOrdered = tail;\n\t\t}\n\t\trange->offset = allocOffset;\n\t\trange->size = allocSize;\n\t\trange->isFree = false;\n\t\tm_statsMemAllocated += allocSize;\n\t}\n\n\tbool _alloc(uint32 size, uint32 alignment, uint32& allocOffsetOut)\n\t{\n\t\tif(size == 0)\n\t\t{\n\t\t\tsize = 1; // zero-sized allocations are not supported\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t\t// find smallest bucket to scan\n\t\tuint32 alignmentM1 = alignment - 1;\n\t\tuint32 bucketIndex = ulog2(size);\n\t\twhile (bucketIndex < 32)\n\t\t{\n\t\t\tallocRange_t* range = bucketFreeRange[bucketIndex];\n\t\t\twhile (range)\n\t\t\t{\n\t\t\t\tif (range->size >= size)\n\t\t\t\t{\n\t\t\t\t\t// verify if aligned allocation fits\n\t\t\t\t\tuint32 alignedOffset = (range->offset + alignmentM1) & ~alignmentM1;\n\t\t\t\t\tuint32 alignmentLoss = alignedOffset - range->offset;\n\t\t\t\t\tif (alignmentLoss < range->size && (range->size - alignmentLoss) >= size)\n\t\t\t\t\t{\n\t\t\t\t\t\t_allocFrom(range, bucketIndex, alignedOffset, size);\n\t\t\t\t\t\tmap_allocatedRange.emplace(alignedOffset, range);\n\t\t\t\t\t\tallocOffsetOut = alignedOffset;\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trange = range->nextFree;\n\t\t\t}\n\t\t\tbucketIndex++; // try higher bucket\n\t\t}\n\t\treturn false;\n\t}\n\n\tvoid _free(uint32 addrOffset)\n\t{\n\t\tauto it = map_allocatedRange.find(addrOffset);\n\t\tif (it == map_allocatedRange.end())\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"VHeap internal error\");\n\t\t\tcemu_assert(false);\n\t\t}\n\t\tallocRange_t* range = it->second;\n\t\tmap_allocatedRange.erase(it);\n\t\tm_statsMemAllocated -= range->size;\n\t\t// try merge left or right\n\t\tallocRange_t* prevRange = range->prevOrdered;\n\t\tallocRange_t* nextRange = range->nextOrdered;\n\t\tif (prevRange && prevRange->isFree)\n\t\t{\n\t\t\tif (nextRange && nextRange->isFree)\n\t\t\t{\n\t\t\t\tforgetFreeRange(nextRange, ulog2(nextRange->size));\n\t\t\t\tuint32 newSize = (nextRange->offset + nextRange->size) - prevRange->offset;\n\t\t\t\tprevRange->nextOrdered = nextRange->nextOrdered;\n\t\t\t\tif (nextRange->nextOrdered)\n\t\t\t\t\tnextRange->nextOrdered->prevOrdered = prevRange;\n\t\t\t\tforgetFreeRange(prevRange, ulog2(prevRange->size));\n\t\t\t\tprevRange->size = newSize;\n\t\t\t\ttrackFreeRange(prevRange);\n\t\t\t\tdelete range;\n\t\t\t\tdelete nextRange;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint32 newSize = (range->offset + range->size) - prevRange->offset;\n\t\t\t\tprevRange->nextOrdered = nextRange;\n\t\t\t\tif (nextRange)\n\t\t\t\t\tnextRange->prevOrdered = prevRange;\n\t\t\t\tforgetFreeRange(prevRange, ulog2(prevRange->size));\n\t\t\t\tprevRange->size = newSize;\n\t\t\t\ttrackFreeRange(prevRange);\n\t\t\t\tdelete range;\n\t\t\t}\n\t\t}\n\t\telse if (nextRange && nextRange->isFree)\n\t\t{\n\t\t\tuint32 newOffset = range->offset;\n\t\t\tuint32 newSize = (nextRange->offset + nextRange->size) - newOffset;\n\t\t\tforgetFreeRange(nextRange, ulog2(nextRange->size));\n\t\t\tnextRange->offset = newOffset;\n\t\t\tnextRange->size = newSize;\n\t\t\tif (range->prevOrdered)\n\t\t\t\trange->prevOrdered->nextOrdered = nextRange;\n\t\t\tnextRange->prevOrdered = range->prevOrdered;\n\t\t\ttrackFreeRange(nextRange);\n\t\t\tdelete range;\n\t\t}\n\t\telse\n\t\t{\n\t\t\trange->isFree = true;\n\t\t\ttrackFreeRange(range);\n\t\t}\n\t}\n\nprivate:\n\tallocRange_t* bucketFreeRange[32]{};\n\tstd::unordered_map<uint32, allocRange_t*> map_allocatedRange;\n\tuint8* m_heapBase;\n\tconst uint32 m_heapSize;\n\tuint32 m_statsMemAllocated{ 0 };\n};\n\ntemplate<uint32 TChunkSize>\nclass ChunkedFlatAllocator\n{\npublic:\n\tvoid setBaseAllocator(VGenericHeap* baseHeap)\n\t{\n\t\tm_currentBaseAllocator = baseHeap;\n\t}\n\n\tvoid* alloc(uint32 size, uint32 alignment = 4)\n\t{\n\t\tif (m_currentBlockPtr)\n\t\t{\n\t\t\tm_currentBlockOffset = (m_currentBlockOffset + alignment - 1) & ~(alignment - 1);\n\t\t\tif ((m_currentBlockOffset+size) <= TChunkSize)\n\t\t\t{\n\t\t\t\tvoid* allocPtr = m_currentBlockPtr + m_currentBlockOffset;\n\t\t\t\tm_currentBlockOffset += size;\n\t\t\t\treturn allocPtr;\n\t\t\t}\n\t\t}\n\t\tallocateAdditionalChunk();\n\t\treturn alloc(size, alignment);\n\t}\n\n\tvoid releaseAll()\n\t{\n\t\tfor (auto it : m_allocatedBlocks)\n\t\t\tm_currentBaseAllocator->free(it);\n\t\tm_allocatedBlocks.clear();\n\t\tm_currentBlockPtr = nullptr;\n\t\tm_currentBlockOffset = 0;\n\t}\n\n\tvoid forEachBlock(void(*funcCb)(void* mem, uint32 size))\n\t{\n\t\tfor (auto it : m_allocatedBlocks)\n\t\t\tfuncCb(it, TChunkSize);\n\t}\n\n\tuint32 getCurrentBlockOffset() const { return m_currentBlockOffset; }\n\tuint8* getCurrentBlockPtr() const { return m_currentBlockPtr; }\n\nprivate:\n\tvoid allocateAdditionalChunk()\n\t{\n\t\tm_currentBlockPtr = (uint8*)m_currentBaseAllocator->alloc(TChunkSize, 256);\n\t\tm_currentBlockOffset = 0;\n\t\tm_allocatedBlocks.emplace_back(m_currentBlockPtr);\n\t}\n\n\tVGenericHeap* m_currentBaseAllocator{};\n\tuint8* m_currentBlockPtr{};\n\tuint32 m_currentBlockOffset{};\n\tstd::vector<void*> m_allocatedBlocks;\n};\n"
  },
  {
    "path": "src/util/DXGIWrapper/DXGIWrapper.h",
    "content": "#pragma once\n\n#undef GetHwnd\n#include <dxgi1_4.h>\n#include <wrl/client.h>\n\nclass DXGIWrapper\n{\npublic:\n\tDXGIWrapper()\n\t\t: DXGIWrapper(nullptr)\n\t{}\n\t\n\tDXGIWrapper(uint8* deviceLUID)\n\t{\n\t\tm_moduleHandle = LoadLibraryA(\"dxgi.dll\");\n\t\tif (!m_moduleHandle)\n\t\t\tthrow std::runtime_error(\"can't load dxgi module\");\n\n\t\tconst auto pCreateDXGIFactory1 = (decltype(&CreateDXGIFactory1))GetProcAddress(m_moduleHandle, \"CreateDXGIFactory1\");\n\t\tif (!pCreateDXGIFactory1)\n\t\t{\n\t\t\tFreeLibrary(m_moduleHandle);\n\t\t\tthrow std::runtime_error(\"can't find CreateDXGIFactory1 in dxgi module\");\n\t\t}\n\n\t\tMicrosoft::WRL::ComPtr<IDXGIFactory1> dxgiFactory;\n\t\tpCreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));\n\n\t\tMicrosoft::WRL::ComPtr<IDXGIAdapter1> dxgiAdapter;\n\t\tUINT adapterIndex = 0;\n\t\twhile (dxgiFactory->EnumAdapters1(adapterIndex, &dxgiAdapter) != DXGI_ERROR_NOT_FOUND)\n\t\t{\n\t\t\tDXGI_ADAPTER_DESC1 desc;\n\t\t\tdxgiAdapter->GetDesc1(&desc);\n\n\t\t\tif (deviceLUID == nullptr || memcmp(&desc.AdapterLuid, deviceLUID, sizeof(LUID)) == 0)\n\t\t\t{\n\t\t\t\tif (FAILED(dxgiAdapter.As(&m_dxgiAdapter)))\n\t\t\t\t{\n\t\t\t\t\tCleanup();\n\t\t\t\t\tthrow std::runtime_error(\"can't create dxgi adapter\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t++adapterIndex;\n\t\t}\n\t}\n\n\t~DXGIWrapper()\n\t{\n\t\tCleanup();\n\t}\n\n\tbool QueryVideoMemoryInfo(DXGI_QUERY_VIDEO_MEMORY_INFO& info) const\n\t{\n\t\treturn m_dxgiAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info) == S_OK;\n\t}\n\nprivate:\n\tHMODULE m_moduleHandle = nullptr;\n\tMicrosoft::WRL::ComPtr<IDXGIAdapter3> m_dxgiAdapter;\n\n\tvoid Cleanup()\n\t{\n\t\tm_dxgiAdapter.Reset();\n\n\t\tif (m_moduleHandle)\n\t\t{\n\t\t\tFreeLibrary(m_moduleHandle);\n\t\t\tm_moduleHandle = nullptr;\n\t\t}\n\t}\n};\n"
  },
  {
    "path": "src/util/EventService.h",
    "content": "#pragma once\n\n#include \"util/helpers/Singleton.h\"\n\n#include <boost/signals2.hpp>\n#include <boost/bind/placeholders.hpp>\n\nenum class Events : int32_t\n{\n\tControllerChanged,\n};\n\nusing ControllerChangedFunc = void(void);\n\nclass EventService : public Singleton<EventService>\n{\n\tfriend class Singleton<EventService>;\n\tEventService() = default;\n\npublic:\n\ttemplate <Events event, typename TFunc, typename TClass>\n\tboost::signals2::connection connect(TFunc function, TClass thisptr)\n\t{\n\t\tusing namespace boost::placeholders;\n\t\tif constexpr (event == Events::ControllerChanged)\n\t\t\treturn m_controller_changed_signal.connect(boost::bind(function, thisptr));\n\t\telse\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t}\n\n\ttemplate <Events event>\n\tvoid disconnect(const boost::signals2::connection& slot)\n\t{\n\t\tusing namespace boost::placeholders;\n\t\tif constexpr (event == Events::ControllerChanged)\n\t\t\tm_controller_changed_signal.disconnect(slot);\n\t\telse\n\t\t{\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t}\n\n\ttemplate <Events event, typename ... TArgs>\n\tvoid signal(TArgs&&... args)\n\t{\n\t\ttry\n\t\t{\n\t\t\tif constexpr (event == Events::ControllerChanged)\n\t\t\t\tm_controller_changed_signal(std::forward<TArgs>(args)...);\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_suspicious();\n\t\t\t}\n\t\t}\n\t\tcatch (const std::exception& ex)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"error when signaling {}: {}\", event, ex.what());\n\t\t}\n\t}\n\nprivate:\n\tboost::signals2::signal<ControllerChangedFunc> m_controller_changed_signal;\n\n};\n"
  },
  {
    "path": "src/util/Fiber/Fiber.h",
    "content": "#pragma once\n\n#if BOOST_OS_WINDOWS\n\n#endif\n\nclass Fiber\n{\npublic:\n\tFiber(void(*FiberEntryPoint)(void* userParam), void* userParam, void* privateData);\n\t~Fiber();\n\n\tstatic Fiber* PrepareCurrentThread(void* privateData = nullptr);\n\tstatic void Switch(Fiber& targetFiber);\n\tstatic void* GetFiberPrivateData();\nprivate:\n\tFiber(void* privateData); // fiber from current thread\n\n\tvoid* m_implData{nullptr};\n\tvoid* m_privateData;\n\tvoid* m_stackPtr{ nullptr };\n};"
  },
  {
    "path": "src/util/Fiber/FiberUnix.cpp",
    "content": "#include \"Fiber.h\"\n#include <ucontext.h>\n#include <atomic>\n\nthread_local Fiber* sCurrentFiber{};\n\nFiber::Fiber(void(*FiberEntryPoint)(void* userParam), void* userParam, void* privateData) : m_privateData(privateData)\n{\n\tucontext_t* ctx = (ucontext_t*)malloc(sizeof(ucontext_t));\n\t\n\tconst size_t stackSize = 2 * 1024 * 1024;\n\tm_stackPtr = malloc(stackSize);\n\n\tgetcontext(ctx);\n\tctx->uc_stack.ss_sp = m_stackPtr;\n\tctx->uc_stack.ss_size = stackSize;\n\tctx->uc_link = &ctx[0];\n#ifdef __arm64__\n\t// https://www.man7.org/linux/man-pages/man3/makecontext.3.html#NOTES\n\tmakecontext(ctx, (void(*)())FiberEntryPoint, 2, (uint64) userParam >> 32, userParam);\n#else\n\tmakecontext(ctx, (void(*)())FiberEntryPoint, 1, userParam);\n#endif\n\tthis->m_implData = (void*)ctx;\n}\n\nFiber::Fiber(void* privateData) : m_privateData(privateData)\n{\n\tucontext_t* ctx = (ucontext_t*)malloc(sizeof(ucontext_t));\n\tgetcontext(ctx);\n\tthis->m_implData = (void*)ctx;\n\tm_stackPtr = nullptr;\n}\n\nFiber::~Fiber()\n{\n\tif(m_stackPtr)\n\t\tfree(m_stackPtr);\n\tfree(m_implData);\n}\n\nFiber* Fiber::PrepareCurrentThread(void* privateData)\n{\n\tcemu_assert_debug(sCurrentFiber == nullptr);\n    sCurrentFiber = new Fiber(privateData);\n\treturn sCurrentFiber;\n}\n\nvoid Fiber::Switch(Fiber& targetFiber)\n{\n    Fiber* leavingFiber = sCurrentFiber;\n    sCurrentFiber = &targetFiber;\n\tstd::atomic_thread_fence(std::memory_order_seq_cst);\n\tswapcontext((ucontext_t*)(leavingFiber->m_implData), (ucontext_t*)(targetFiber.m_implData));\n\tstd::atomic_thread_fence(std::memory_order_seq_cst);\n}\n\nvoid* Fiber::GetFiberPrivateData()\n{\n\treturn sCurrentFiber->m_privateData;\n}\n"
  },
  {
    "path": "src/util/Fiber/FiberWin.cpp",
    "content": "#include \"Fiber.h\"\n#include <Windows.h>\n\nthread_local Fiber* sCurrentFiber{};\n\nFiber::Fiber(void(*FiberEntryPoint)(void* userParam), void* userParam, void* privateData) : m_privateData(privateData)\n{\n\tHANDLE fiberHandle = CreateFiber(2 * 1024 * 1024, (LPFIBER_START_ROUTINE)FiberEntryPoint, userParam);\n\tthis->m_implData = (void*)fiberHandle;\n}\n\nFiber::Fiber(void* privateData) : m_privateData(privateData)\n{\n\tthis->m_implData = (void*)ConvertThreadToFiber(nullptr);\n\tthis->m_stackPtr = nullptr;\n}\n\nFiber::~Fiber()\n{\n\tDeleteFiber((HANDLE)m_implData);\n}\n\nFiber* Fiber::PrepareCurrentThread(void* privateData)\n{\n\tcemu_assert_debug(sCurrentFiber == nullptr); // thread already prepared\n\tFiber* currentFiber = new Fiber(privateData);\n\tsCurrentFiber = currentFiber;\n\treturn currentFiber;\n}\n\nvoid Fiber::Switch(Fiber& targetFiber)\n{\n\tsCurrentFiber = &targetFiber;\n\tSwitchToFiber((HANDLE)targetFiber.m_implData);\n}\n\nvoid* Fiber::GetFiberPrivateData()\n{\n\treturn sCurrentFiber->m_privateData;\n}\n"
  },
  {
    "path": "src/util/ImageWriter/bmp.h",
    "content": "#include \"Common/FileStream.h\"\n\nstatic void _bmp_write(FileStream* fs, sint32 width, sint32 height, uint32 bits, void* pixelData)\n{\n\tBITMAPFILEHEADER bmp_fh;\n\tBITMAPINFOHEADER bmp_ih;\n\n\tbmp_fh.bfType = 0x4d42;\n\tbmp_fh.bfSize = 0;\n\tbmp_fh.bfReserved1 = 0;\n\tbmp_fh.bfReserved2 = 0;\n\tbmp_fh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);\n\n\tbmp_ih.biSize = sizeof(bmp_ih);\n\tbmp_ih.biWidth = width;\n\tbmp_ih.biHeight = height;\n\tbmp_ih.biPlanes = 1;\n\tbmp_ih.biBitCount = bits;\n\tbmp_ih.biCompression = 0;\n\tbmp_ih.biSizeImage = 0;\n\tbmp_ih.biXPelsPerMeter = 0;\n\tbmp_ih.biYPelsPerMeter = 0;\n\tbmp_ih.biClrUsed = 0;\n\tbmp_ih.biClrImportant = 0;\n\n\tsint32 rowPitch = (width * bits / 8);\n\trowPitch = (rowPitch + 3)&~3;\n\n\tuint8 padding[4] = { 0 };\n\tsint32 paddingLength = rowPitch - (width * bits / 8);\n\n\tbmp_ih.biSize = sizeof(BITMAPINFOHEADER);\n\tbmp_fh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + rowPitch * height;\n\n\tfs->writeData(&bmp_fh, sizeof(BITMAPFILEHEADER));\n\tfs->writeData(&bmp_ih, sizeof(BITMAPINFOHEADER));\n\n\tif (bits == 24 || bits == 32)\n\t{\n\t\tfor (sint32 y = 0; y < height; y++)\n\t\t{\n\t\t\tvoid* rowInput = ((uint8*)pixelData) + rowPitch * (height - y - 1);\n\t\t\tfs->writeData(rowInput, width*bits/8);\n\t\t\t// write padding\n\t\t\tif(paddingLength > 0)\n\t\t\t\tfs->writeData(padding, paddingLength);\n\t\t}\n\t}\t\n}\n\nstatic bool bmp_store8BitAs24(wchar_t* path, sint32 width, sint32 height, sint32 bytesPerRow, void* pixelData)\n{\n\tFileStream* fs = FileStream::createFile(path);\n\tif (fs == nullptr)\n\t\treturn false;\n\n\tuint8* pixelI = (uint8*)pixelData;\n\tuint8* pixelRGB = (uint8*)malloc(width * height * 3);\n\tfor (sint32 y = 0; y < height; y++)\n\t{\n\t\tsint32 srcIdx = y * bytesPerRow;\n\t\tfor (sint32 x = 0; x < width; x++)\n\t\t{\n\t\t\tsint32 dstIdx = x + y * width;\n\t\t\tpixelRGB[dstIdx * 3 + 0] = pixelI[srcIdx];\n\t\t\tpixelRGB[dstIdx * 3 + 1] = pixelI[srcIdx];\n\t\t\tpixelRGB[dstIdx * 3 + 2] = pixelI[srcIdx];\n\t\t\tsrcIdx++;\n\t\t}\n\t}\n\t_bmp_write(fs, width, height, 24, pixelRGB);\n\tfree(pixelRGB);\n\tdelete fs;\n\treturn true;\n}\n\nstatic bool bmp_store16BitAs24(wchar_t* path, sint32 width, sint32 height, sint32 bytesPerRow, void* pixelData)\n{\n\tFileStream* fs = FileStream::createFile(path);\n\tif (fs == nullptr)\n\t\treturn false;\n\n\tuint8* pixelI = (uint8*)pixelData;\n\tuint8* pixelRGB = (uint8*)malloc(width * height * 3);\n\tfor (sint32 y = 0; y < height; y++)\n\t{\n\t\tsint32 srcIdx = y * bytesPerRow;\n\t\tfor (sint32 x = 0; x < width; x++)\n\t\t{\n\t\t\tsint32 dstIdx = x + y * width;\n\t\t\tpixelRGB[dstIdx * 3 + 0] = pixelI[srcIdx + 0];\n\t\t\tpixelRGB[dstIdx * 3 + 1] = pixelI[srcIdx + 1];\n\t\t\tpixelRGB[dstIdx * 3 + 2] = 0;\n\t\t\tsrcIdx += 2;\n\t\t}\n\t}\n\t_bmp_write(fs, width, height, 24, pixelRGB);\n\tfree(pixelRGB);\n\tdelete fs;\n\treturn true;\n}\n\nstatic bool bmp_store24BitAs24(wchar_t* path, sint32 width, sint32 height, sint32 bytesPerRow, void* pixelData)\n{\n\tFileStream* fs = FileStream::createFile(path);\n\tif (fs == nullptr)\n\t\treturn false;\n\n\tuint8* pixelI = (uint8*)pixelData;\n\tuint8* pixelRGB = (uint8*)malloc(width * height * 3);\n\tfor (sint32 y = 0; y < height; y++)\n\t{\n\t\tsint32 srcIdx = y * bytesPerRow;\n\t\tfor (sint32 x = 0; x < width; x++)\n\t\t{\n\t\t\tsint32 dstIdx = x + y * width;\n\t\t\tpixelRGB[dstIdx * 3 + 0] = pixelI[srcIdx + 0];\n\t\t\tpixelRGB[dstIdx * 3 + 1] = pixelI[srcIdx + 1];\n\t\t\tpixelRGB[dstIdx * 3 + 2] = pixelI[srcIdx + 2];\n\t\t\tsrcIdx += 3;\n\t\t}\n\t}\n\t_bmp_write(fs, width, height, 24, pixelRGB);\n\tfree(pixelRGB);\n\tdelete fs;\n\treturn true;\n}"
  },
  {
    "path": "src/util/ImageWriter/tga.h",
    "content": "#include \"Common/FileStream.h\"\n#include <vector>\n\nstatic bool tga_write_rgba(const fs::path& path, sint32 width, sint32 height, uint8* pixelData)\n{\n\tFileStream* fs = FileStream::createFile2(path);\n\tif (fs == nullptr)\n\t\treturn false;\n\n\tuint8_t header[18] = {0,0,2,0,0,0,0,0,0,0,0,0, (uint8)(width % 256), (uint8)(width / 256), (uint8)(height % 256), (uint8)(height / 256), 32, 0x20};\n\tfs->writeData(&header, sizeof(header));\n\n\tstd::vector<uint8> tempPixelData;\n\ttempPixelData.resize(width * height * 4);\n\n\t// write one row at a time\n\tuint8* pOut = tempPixelData.data();\n\tfor (sint32 y = 0; y < height; y++)\n\t{\n\t\tconst uint8* rowIn = pixelData + y * width*4;\n\t\tfor (sint32 x = 0; x < width; x++)\n\t\t{\n\t\t\tpOut[0] = rowIn[2];\n\t\t\tpOut[1] = rowIn[1];\n\t\t\tpOut[2] = rowIn[0];\n\t\t\tpOut[3] = rowIn[3];\n\t\t\tpOut += 4;\n\t\t\trowIn += 4;\n\t\t}\n\t}\n\tfs->writeData(tempPixelData.data(), width * height * 4);\n\tdelete fs;\n\treturn true;\n}\n"
  },
  {
    "path": "src/util/IniParser/IniParser.cpp",
    "content": "#include \"util/IniParser/IniParser.h\"\n\nIniParser::IniParser(std::span<char> iniContents, std::string_view name) : m_name(name)\n{\n\t// we dont support utf8 but still skip the byte order mark in case the user saved the document with the wrong encoding\n\tif (iniContents.size() >= 3 && (uint8)iniContents[0] == 0xEF && (uint8)iniContents[1] == 0xBB && (uint8)iniContents[2] == 0xBF)\n\t\tiniContents = iniContents.subspan(3);\n\n\tm_iniFileData.assign(iniContents.begin(), iniContents.end());\n\tm_isValid = parse();\n}\n\nbool IniParser::ReadNextLine(std::string_view& lineString)\n{\n\tif (m_parseOffset >= m_iniFileData.size())\n\t\treturn false;\n\t// skip \\r and \\n\n\tfor (; m_parseOffset < m_iniFileData.size(); m_parseOffset++)\n\t{\n\t\tchar c = m_iniFileData[m_parseOffset];\n\t\tif (c == '\\r' || c == '\\n')\n\t\t\tcontinue;\n\t\tbreak;\n\t}\n\tif (m_parseOffset >= m_iniFileData.size())\n\t\treturn false;\n\tsize_t lineStart = m_parseOffset;\n\t// parse until end of line/file\n\tfor (; m_parseOffset < m_iniFileData.size(); m_parseOffset++)\n\t{\n\t\tchar c = m_iniFileData[m_parseOffset];\n\t\tif (c == '\\r' || c == '\\n')\n\t\t\tbreak;\n\t}\n\tsize_t lineEnd = m_parseOffset;\n\tlineString = { m_iniFileData.data() + lineStart, lineEnd - lineStart };\n\treturn true;\n}\n\nvoid IniParser::TrimWhitespaces(std::string_view& str)\n{\n\twhile (!str.empty())\n\t{\n\t\tchar c = str[0];\n\t\tif (c != ' ' && c != '\\t')\n\t\t\tbreak;\n\t\tstr.remove_prefix(1);\n\t}\n\twhile (!str.empty())\n\t{\n\t\tchar c = str.back();\n\t\tif (c != ' ' && c != '\\t')\n\t\t\tbreak;\n\t\tstr.remove_suffix(1);\n\t}\n}\n\nbool IniParser::parse()\n{\n\tsint32 lineNumber = 0;\n\tstd::string_view lineView;\n\twhile (ReadNextLine(lineView))\n\t{\n\t\tlineNumber++;\n\t\t// skip whitespaces\n\t\twhile (!lineView.empty())\n\t\t{\n\t\t\tchar c = lineView[0];\n\t\t\tif (c != ' ' && c != '\\t')\n\t\t\t\tbreak;\n\t\t\tlineView.remove_prefix(1);\n\t\t}\n\t\tif (lineView.empty())\n\t\t\tcontinue;\n\t\t// cut off comments (starting with # or ;)\n\t\tbool isInQuote = false;\n\t\tfor (size_t i = 0; i < lineView.size(); i++)\n\t\t{\n\t\t\tif (lineView[i] == '\\\"')\n\t\t\t\tisInQuote = !isInQuote;\n\t\t\tif ((lineView[i] == '#' || lineView[i] == ';') && !isInQuote)\n\t\t\t{\n\t\t\t\tlineView.remove_suffix(lineView.size() - i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif(lineView.empty())\n\t\t\tcontinue;\n\t\t// handle section headers\n\t\tif (lineView[0] == '[')\n\t\t{\n\t\t\tisInQuote = false;\n\t\t\tbool endsWithBracket = false;\n\t\t\tfor (size_t i = 1; i < lineView.size(); i++)\n\t\t\t{\n\t\t\t\tif (lineView[i] == '\\\"')\n\t\t\t\t\tisInQuote = !isInQuote;\n\t\t\t\tif (lineView[i] == ']')\n\t\t\t\t{\n\t\t\t\t\tlineView.remove_suffix(lineView.size() - i);\n\t\t\t\t\tlineView.remove_prefix(1);\n\t\t\t\t\tendsWithBracket = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!endsWithBracket)\n\t\t\t\tPrintWarning(lineNumber, \"Section doesn't end with a ]\", lineView);\n\t\t\tStartSection(lineView, lineNumber);\n\t\t\tcontinue;\n\t\t}\n\t\t// otherwise try to parse it as an option in the form name = value\n\t\t// find and split at = character\n\t\tstd::string_view option_name;\n\t\tstd::string_view option_value;\n\t\tbool invalidName = true;\n\t\tfor (size_t i = 0; i < lineView.size(); i++)\n\t\t{\n\t\t\tif (lineView[i] == '=')\n\t\t\t{\n\t\t\t\toption_name = lineView.substr(0, i);\n\t\t\t\toption_value = lineView.substr(i+1);\n\t\t\t\tinvalidName = false;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t}\n\t\tif (invalidName)\n\t\t{\n\t\t\tTrimWhitespaces(lineView);\n\t\t\tif (!lineView.empty())\n\t\t\t\tPrintWarning(lineNumber, \"Not a valid section header or name-value pair\", lineView);\n\t\t\tcontinue;\n\t\t}\n\t\t// validate\n\t\tTrimWhitespaces(option_name);\n\t\tTrimWhitespaces(option_value);\n\t\tif (option_name.empty())\n\t\t{\n\t\t\tPrintWarning(lineNumber, \"Empty option name is not allowed\", lineView);\n\t\t\tcontinue;\n\t\t}\n\t\tbool invalidCharacter = false;\n\t\tfor (auto& _c : option_name)\n\t\t{\n\t\t\tuint8 c = (uint8)_c;\n\t\t\tif (c == ']' || c == '[')\n\t\t\t{\n\t\t\t\tPrintWarning(lineNumber, \"Option name may not contain [ or ]\", lineView);\n\t\t\t\tinvalidCharacter = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (c < 32 || c > 128 || c == ' ')\n\t\t\t{\n\t\t\t\tPrintWarning(lineNumber, \"Option name may only contain ANSI characters and no spaces\", lineView);\n\t\t\t\tinvalidCharacter = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif(invalidCharacter)\n\t\t\tcontinue;\n\t\t// remove quotes from value\n\t\tif (!option_value.empty() && option_value.front() == '\\\"')\n\t\t{\n\t\t\toption_value.remove_prefix(1);\n\t\t\tif (option_value.size() >= 2 && option_value.back() == '\\\"')\n\t\t\t{\n\t\t\t\toption_value.remove_suffix(1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tPrintWarning(lineNumber, \"Option value starts with a quote character \\\" but does not end with one\", lineView);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tif (m_sectionList.empty())\n\t\t{\n\t\t\t// no current section\n\t\t\tPrintWarning(lineNumber, \"Option defined without first defining a section\", lineView);\n\t\t\tcontinue;\n\t\t}\n\t\t// convert name to lower case\n\t\tm_sectionList.back().m_optionPairs.emplace_back(option_name, option_value);\n\t}\n\treturn true;\n}\n\nvoid IniParser::StartSection(std::string_view sectionName, size_t lineNumber)\n{\n\tm_sectionList.emplace_back(sectionName, lineNumber);\n}\n\nbool IniParser::NextSection()\n{\n\tif (m_currentSectionIndex == std::numeric_limits<size_t>::max())\n\t{\n\t\tm_currentSectionIndex = 0;\n\t\treturn m_currentSectionIndex < m_sectionList.size();\n\t}\n\tif (m_currentSectionIndex >= m_sectionList.size())\n\t\treturn false;\n\tm_currentSectionIndex++;\n\treturn m_currentSectionIndex < m_sectionList.size();\n}\n\nstd::string_view IniParser::GetCurrentSectionName()\n{\n\tif (m_currentSectionIndex == std::numeric_limits<size_t>::max() || m_currentSectionIndex >= m_sectionList.size())\n\t\treturn \"\";\n\treturn m_sectionList[m_currentSectionIndex].m_sectionName;\n}\n\nsize_t IniParser::GetCurrentSectionLineNumber()\n{\n\tif (m_currentSectionIndex == std::numeric_limits<size_t>::max() || m_currentSectionIndex >= m_sectionList.size())\n\t\treturn 0;\n\treturn m_sectionList[m_currentSectionIndex].m_lineNumber;\n}\n\nstd::optional<std::string_view> IniParser::FindOption(std::string_view optionName)\n{\n\tif (m_currentSectionIndex == std::numeric_limits<size_t>::max() || m_currentSectionIndex >= m_sectionList.size())\n\t\treturn std::nullopt;\n\tauto& optionPairsList = m_sectionList[m_currentSectionIndex].m_optionPairs;\n\tfor (auto& itr : optionPairsList)\n\t{\n\t\tauto& itrOptionName = itr.first;\n\t\t// case insensitive ANSI string comparison\n\t\tif(itrOptionName.size() != optionName.size())\n\t\t\tcontinue;\n\t\tbool isMatch = true;\n\t\tfor (size_t i = 0; i < itrOptionName.size(); i++)\n\t\t{\n\t\t\tchar c0 = itrOptionName[i];\n\t\t\tchar c1 = optionName[i];\n\t\t\tif (c0 >= 'A' && c0 <= 'Z')\n\t\t\t\tc0 -= ('A' - 'a');\n\t\t\tif (c1 >= 'A' && c1 <= 'Z')\n\t\t\t\tc1 -= ('A' - 'a');\n\t\t\tif (c0 != c1)\n\t\t\t{\n\t\t\t\tisMatch = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!isMatch)\n\t\t\tcontinue;\n\t\treturn itr.second;\n\t}\n\treturn std::nullopt;\n}\n\nstd::span<std::pair<std::string_view, std::string_view>> IniParser::GetAllOptions()\n{\n\tif (m_currentSectionIndex == std::numeric_limits<size_t>::max() || m_currentSectionIndex >= m_sectionList.size())\n\t\treturn {};\n\treturn m_sectionList[m_currentSectionIndex].m_optionPairs;\n}\n\nvoid IniParser::PrintWarning(int lineNumber, std::string_view msg, std::string_view lineView)\n{\n\t// INI logging is silenced\n\t// cemuLog_log(LogType::Force, \"File: {} Line {}: {}\", m_name, lineNumber, msg);\n}"
  },
  {
    "path": "src/util/IniParser/IniParser.h",
    "content": "#pragma once\n\n#include <vector>\n#include <span>\n#include <string>\n#include <optional>\n\nclass IniParser\n{\nprivate:\n\tclass IniSection\n\t{\n\tpublic:\n\t\tIniSection(std::string_view sectionName, size_t lineNumber) : m_sectionName(sectionName), m_lineNumber(lineNumber) {}\n\t\tstd::string_view m_sectionName;\n\t\tsize_t m_lineNumber;\n\t\tstd::vector<std::pair<std::string_view, std::string_view>> m_optionPairs;\n\t};\n\npublic:\n\tIniParser(std::span<char> iniContents, std::string_view name = {});\n\tIniParser(std::span<unsigned char> iniContents, std::string_view name = {}) : IniParser(std::span<char>((char*)iniContents.data(), iniContents.size()), name) {};\n\n\t// section and option iterating\n\tbool NextSection();\n\tstd::string_view GetCurrentSectionName();\n\tsize_t GetCurrentSectionLineNumber();\n\tstd::optional<std::string_view> FindOption(std::string_view optionName);\n\tstd::span<std::pair<std::string_view, std::string_view>> GetAllOptions();\n\nprivate:\n\t// parsing\n\tbool parse();\n\tbool ReadNextLine(std::string_view& lineString);\n\tvoid TrimWhitespaces(std::string_view& str);\n\tvoid StartSection(std::string_view sectionName, size_t lineNumber);\n\tvoid PrintWarning(int lineNumber, std::string_view msg, std::string_view lineView);\n\n\tstd::vector<char> m_iniFileData;\n\tstd::string m_name;\n\tbool m_isValid{ false };\n\tsize_t m_parseOffset{ 0 };\n\tstd::vector<IniSection> m_sectionList;\n\tsize_t m_currentSectionIndex{std::numeric_limits<size_t>::max()};\n};"
  },
  {
    "path": "src/util/MemMapper/MemMapper.h",
    "content": "#pragma once\n\nnamespace MemMapper\n{\n\tenum class PAGE_PERMISSION : uint32\n\t{\n\t\tP_READ = (0x01),\n\t\tP_WRITE = (0x02),\n\t\tP_EXECUTE = (0x04),\n\t\t// combined\n\t\tP_NONE = 0,\n\t\tP_RW = (0x03),\n\t\tP_RWX = (0x07)\n\t};\n\tDEFINE_ENUM_FLAG_OPERATORS(PAGE_PERMISSION);\n\n\tsize_t GetPageSize();\n\n\tvoid* ReserveMemory(void* baseAddr, size_t size, PAGE_PERMISSION permissionFlags);\n\tvoid FreeReservation(void* baseAddr, size_t size);\n\n\tvoid* AllocateMemory(void* baseAddr, size_t size, PAGE_PERMISSION permissionFlags, bool fromReservation = false);\n\tvoid FreeMemory(void* baseAddr, size_t size, bool fromReservation = false);\n};"
  },
  {
    "path": "src/util/MemMapper/MemMapperUnix.cpp",
    "content": "#include \"util/MemMapper/MemMapper.h\"\n\n#include <unistd.h>\n#include <sys/mman.h>\n\nnamespace MemMapper\n{\n\tconst size_t sPageSize{ []()\n\t\t{\n\t\treturn (size_t)getpagesize();\n\t}()\n\t};\n\n\tsize_t GetPageSize()\n\t{\n\t\treturn sPageSize;\n\t}\n\n\tint GetProt(PAGE_PERMISSION permissionFlags)\n\t{\n\t\tint  p = 0;\n\t\tif (HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_READ) && HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_WRITE) && HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_EXECUTE))\n\t\t\tp = PROT_READ | PROT_WRITE | PROT_EXEC;\n\t\telse if (HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_READ) && HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_WRITE) && !HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_EXECUTE))\n\t\t\tp = PROT_READ | PROT_WRITE;\n\t\telse if (HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_READ) && !HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_WRITE) && !HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_EXECUTE))\n\t\t\tp = PROT_READ;\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t\treturn p;\n\t}\n\n\tvoid* ReserveMemory(void* baseAddr, size_t size, PAGE_PERMISSION permissionFlags)\n\t{\n\t\treturn mmap(baseAddr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);\n\t}\n\n\tvoid FreeReservation(void* baseAddr, size_t size)\n\t{\n\t\tmunmap(baseAddr, size);\n\t}\n\n\tvoid* AllocateMemory(void* baseAddr, size_t size, PAGE_PERMISSION permissionFlags, bool fromReservation)\n\t{\n\t\tvoid* r;\n\t\tif(fromReservation)\n\t\t{\n\t\t    uint64 page_size = sysconf(_SC_PAGESIZE);\n\t\t    void* page = baseAddr;\n\t\t    if ( (uint64) baseAddr % page_size != 0 )\n\t\t        page = (void*) ((uint64)baseAddr & ~(page_size - 1));\n\t\t\tif( mprotect(page, size, GetProt(permissionFlags)) == 0 )\n                r = baseAddr;\n\t\t\telse\n                r = nullptr;\n\t\t}\n\t\telse\n\t\t\tr = mmap(baseAddr, size, GetProt(permissionFlags), MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);\n\t\treturn r;\n\t}\n\n\tvoid FreeMemory(void* baseAddr, size_t size, bool fromReservation)\n\t{\n\t\tif (fromReservation)\n\t\t\tmprotect(baseAddr, size, PROT_NONE);\n\t\telse\n\t\t\tmunmap(baseAddr, size);\n\t}\n\n};\n"
  },
  {
    "path": "src/util/MemMapper/MemMapperWin.cpp",
    "content": "#include \"util/MemMapper/MemMapper.h\"\n\n#include <Windows.h>\n\nnamespace MemMapper\n{\n\tconst size_t sPageSize{ []()\n\t\t{\n\t\tSYSTEM_INFO si;\n\t\tGetSystemInfo(&si);\n\t\treturn (size_t)si.dwPageSize;\n\t}()\n\t};\n\n\tsize_t GetPageSize()\n\t{\n\t\treturn sPageSize;\n\t}\n\n\tDWORD GetPageProtection(PAGE_PERMISSION permissionFlags)\n\t{\n\t\tDWORD p = 0;\n\t\tif (HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_READ) && HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_WRITE) && HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_EXECUTE))\n\t\t\tp = PAGE_EXECUTE_READWRITE;\n\t\telse if (HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_READ) && HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_WRITE) && !HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_EXECUTE))\n\t\t\tp = PAGE_READWRITE;\n\t\telse if (HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_READ) && !HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_WRITE) && !HAS_FLAG(permissionFlags, PAGE_PERMISSION::P_EXECUTE))\n\t\t\tp = PAGE_READONLY;\n\t\telse\n\t\t\tcemu_assert_unimplemented();\n\t\treturn p;\n\t}\n\n\tvoid* ReserveMemory(void* baseAddr, size_t size, PAGE_PERMISSION permissionFlags)\n\t{\n\t\tvoid* r = VirtualAlloc(baseAddr, size, MEM_RESERVE, GetPageProtection(permissionFlags));\n\t\treturn r;\n\t}\n\n\tvoid FreeReservation(void* baseAddr, size_t size)\n\t{\n\t\tVirtualFree(baseAddr, size, MEM_RELEASE);\n\t}\n\n\tvoid* AllocateMemory(void* baseAddr, size_t size, PAGE_PERMISSION permissionFlags, bool fromReservation)\n\t{\n\t\tvoid* r;\n\t\tif(fromReservation)\n\t\t\tr = VirtualAlloc(baseAddr, size, MEM_COMMIT, GetPageProtection(permissionFlags));\n\t\telse\n\t\t\tr = VirtualAlloc(baseAddr, size, MEM_RESERVE | MEM_COMMIT, GetPageProtection(permissionFlags));\n\t\treturn r;\n\t}\n\n\tvoid FreeMemory(void* baseAddr, size_t size, bool fromReservation)\n\t{\n\t\tif(fromReservation)\n\t\t\tVirtualFree(baseAddr, size, MEM_DECOMMIT);\n\t\telse\n\t\t\tVirtualFree(baseAddr, size, MEM_RELEASE);\n\t}\n\n};\n"
  },
  {
    "path": "src/util/ScreenSaver/ScreenSaver.h",
    "content": "#include \"Cemu/Logging/CemuLogging.h\"\n#include <SDL2/SDL.h>\n\nclass ScreenSaver\n{\npublic:\n  static void SetInhibit(bool inhibit)\n  {\n\t  // temporary workaround because feature crashes on macOS\n#if BOOST_OS_MACOS\n\t  return;\n#endif\n    // Initialize video subsystem if necessary\n    if (SDL_WasInit(SDL_INIT_VIDEO) == 0)\n    {\n      int initErr = SDL_InitSubSystem(SDL_INIT_VIDEO);\n      if (initErr)\n      {\n        cemuLog_log(LogType::Force, \"Could not disable screen saver (SDL video subsystem initialization error)\");\n      }\n    }\n    // Toggle SDL's screen saver inhibition\n    if (inhibit)\n    {\n      SDL_DisableScreenSaver();\n      if (SDL_IsScreenSaverEnabled() == SDL_TRUE)\n      {\n        cemuLog_log(LogType::Force, \"Could not verify if screen saver was disabled (`SDL_IsScreenSaverEnabled()` returned SDL_TRUE)\");\n      }\n    }\n    else\n    {\n      SDL_EnableScreenSaver();\n      if (SDL_IsScreenSaverEnabled() == SDL_FALSE)\n      {\n        cemuLog_log(LogType::Force, \"Could not verify if screen saver was re-enabled (`SDL_IsScreenSaverEnabled()` returned SDL_FALSE)\");\n      }\n    }\n  };\n};\n"
  },
  {
    "path": "src/util/SystemInfo/SystemInfo.cpp",
    "content": "#include \"util/SystemInfo/SystemInfo.h\"\n\nuint64 ProcessorTime::work()\n{\n\treturn user + kernel;\n}\n\nuint64 ProcessorTime::total()\n{\n\treturn idle + user + kernel;\n}\n\ndouble ProcessorTime::Compare(ProcessorTime &last, ProcessorTime &now)\n{\n\tauto dwork = now.work() - last.work();\n\tauto dtotal = now.total() - last.total();\n\n\treturn (double)dwork / dtotal;\n}\n\nuint32 GetProcessorCount()\n{\n\treturn std::thread::hardware_concurrency();\n}\n\nvoid QueryProcTime(ProcessorTime &out)\n{\n\tuint64 now, user, kernel;\n\tQueryProcTime(now, user, kernel);\n\n\tout.idle = now - (user + kernel);\n\tout.kernel = kernel;\n\tout.user = user;\n}"
  },
  {
    "path": "src/util/SystemInfo/SystemInfo.h",
    "content": "#pragma once\n\nstruct ProcessorTime\n{\n\tuint64 idle{}, kernel{}, user{};\n\t\n\tuint64 work();\n\tuint64 total();\n\n\tstatic double Compare(ProcessorTime &last, ProcessorTime &now);\n};\n\nuint32 GetProcessorCount();\nuint64 QueryRamUsage();\nvoid QueryProcTime(uint64 &out_now, uint64 &out_user, uint64 &out_kernel);\nvoid QueryProcTime(ProcessorTime &out);\nvoid QueryCoreTimes(uint32 count, std::vector<ProcessorTime>& out);\n"
  },
  {
    "path": "src/util/SystemInfo/SystemInfoLinux.cpp",
    "content": "#include \"util/SystemInfo/SystemInfo.h\"\n\n#include <unistd.h>\n\nuint64 QueryRamUsage()\n{\n\tstatic long page_size = sysconf(_SC_PAGESIZE);\n\tif (page_size == -1)\n\t{\n\t\treturn 0;\n\t}\n\n\tstd::ifstream file(\"/proc/self/statm\");\n\tif (file)\n\t{\n\t\tfile.ignore(std::numeric_limits<std::streamsize>::max(), ' ');\n\t\tuint64 pages;\n\t\tfile >> pages;\n\n\t\treturn pages * page_size;\n\t}\n\treturn 0;\n}\n\nvoid QueryCoreTimes(uint32 count, std::vector<ProcessorTime>& out)\n{\n\tstd::ifstream file(\"/proc/stat\");\n\tif (file)\n\t{\n\t\tfile.ignore(std::numeric_limits<std::streamsize>::max(), '\\n');\n\n\t\tfor (auto i = 0; i < out.size(); ++i)\n\t\t{\n\t\t\tuint64 user, nice, kernel, idle;\n\t\t\tfile.ignore(std::numeric_limits<std::streamsize>::max(), ' ');\n\t\t\tfile >> user >> nice >> kernel >> idle;\n\t\t\tfile.ignore(std::numeric_limits<std::streamsize>::max(), '\\n');\n\n\t\t\tout[i].idle = idle;\n\t\t\tout[i].kernel = kernel;\n\t\t\tout[i].user = user + nice;\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (auto i = 0; i < count; ++i) out[i] = { };\n\t}\n}\n"
  },
  {
    "path": "src/util/SystemInfo/SystemInfoMac.cpp",
    "content": "#include \"util/SystemInfo/SystemInfo.h\"\n\n#include <unistd.h>\n#include <sys/resource.h>\n#include <sys/sysctl.h>\n#include <sys/types.h>\n#include <mach/mach.h>\n\n#include <mach/processor_info.h>\n#include <mach/mach_host.h>\n#include <mach/kern_return.h>\n\n// borrowed from https://en.wikichip.org/wiki/resident_set_size#OS_X\nuint64 QueryRamUsage()\n{\n\tmach_task_basic_info info;\n\tmach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;\n\tif (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count) == KERN_SUCCESS)\n\t\treturn info.resident_size;\n\treturn 0;\n}\n\n// apple official documentation is non-existsent.\n// based on https://github.com/giampaolo/psutil/blob/master/psutil/_psutil_osx.c#L623\nvoid QueryCoreTimes(uint32 count, std::vector<ProcessorTime>& out)\n{\n\t// initialize default\n\tfor (auto i = 0; i < out.size(); ++i)\n\t{\n\t\tout[i] = {};\n\t}\n\n\tnatural_t cpu_count;\n\tprocessor_info_array_t info_array;\n\tmach_msg_type_number_t info_count;\n\tkern_return_t error;\n\n\tmach_port_t host_port = mach_host_self();\n\terror = host_processor_info(host_port, PROCESSOR_CPU_LOAD_INFO, &cpu_count, &info_array, &info_count);\n\tmach_port_deallocate(mach_task_self(), host_port);\n\n\tif (error != KERN_SUCCESS)\n\t\treturn;\n\n\tprocessor_cpu_load_info_data_t* cpuLoad = (processor_cpu_load_info_data_t*) info_array;\n\n\tfor (auto i = 0; i < cpu_count; ++i)\n\t{\n\t\tuint64 system = cpuLoad[i].cpu_ticks[CPU_STATE_SYSTEM];\n\t\tuint64 user = cpuLoad[i].cpu_ticks[CPU_STATE_USER] + cpuLoad[i].cpu_ticks[CPU_STATE_NICE];\n\t\tuint64 idle = cpuLoad[i].cpu_ticks[CPU_STATE_IDLE];\n\n\t\tout[i].idle = idle;\n\t\tout[i].kernel = system;\n\t\tout[i].user = user;\n\t}\n\n\tint ret = vm_deallocate(mach_task_self(), (vm_address_t) info_array,\n\t\t\t\t\t\tinfo_count * sizeof(int));\n\tif (ret != KERN_SUCCESS)\n\t\tcemuLog_log(LogType::Force, \"vm_deallocate() failed\");\n}\n"
  },
  {
    "path": "src/util/SystemInfo/SystemInfoStub.cpp",
    "content": "#include \"util/SystemInfo/SystemInfo.h\"\n\nuint64 QueryRamUsage()\n{\n\treturn 0;\n}\n\nvoid QueryProcTime(uint64 &out_now, uint64 &out_user, uint64 &out_kernel)\n{\n\tout_now = 0;\n\tout_user = 0;\n\tout_kernel = 0;\n}\n\nvoid QueryCoreTimes(uint32 count, std::vector<ProcessorTime>& out)\n{\n\tfor (auto i = 0; i < out.size(); ++i)\n\t{\n\t\tout[i] = { };\n\t}\n}\n"
  },
  {
    "path": "src/util/SystemInfo/SystemInfoUnix.cpp",
    "content": "#include \"util/SystemInfo/SystemInfo.h\"\n\n#include <sys/times.h>\n\nvoid QueryProcTime(uint64 &out_now, uint64 &out_user, uint64 &out_kernel)\n{\n\tstruct tms time_info;\n\tclock_t clock_now = times(&time_info);\n\tclock_t clock_user = time_info.tms_utime;\n\tclock_t clock_kernel = time_info.tms_stime;\n\tout_now = static_cast<uint64>(clock_now);\n\tout_user = static_cast<uint64>(clock_user);\n\tout_kernel = static_cast<uint64>(clock_kernel);\n}\n\n"
  },
  {
    "path": "src/util/SystemInfo/SystemInfoWin.cpp",
    "content": "#include \"util/SystemInfo/SystemInfo.h\"\n\n#include <Psapi.h>\n#include <winternl.h>\n#pragma comment(lib, \"ntdll.lib\")\n\nuint64 QueryRamUsage()\n{\n\tPROCESS_MEMORY_COUNTERS pmc{};\n\tpmc.cb = sizeof(pmc);\n\tif (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))\n\t{\n\t\treturn pmc.WorkingSetSize;\n\t}\n\telse\n\t{\n\t\treturn 0;\n\t}\n}\n\nvoid QueryProcTime(uint64 &out_now, uint64 &out_user, uint64 &out_kernel)\n{\n\tFILETIME ftime, fkernel, fuser;\n\tLARGE_INTEGER now, kernel, user;\n\tGetSystemTimeAsFileTime(&ftime);\n\tnow.LowPart = ftime.dwLowDateTime;\n\tnow.HighPart = ftime.dwHighDateTime;\n\n\tif (GetProcessTimes(GetCurrentProcess(), &ftime, &ftime, &fkernel, &fuser))\n\t{\n\t\tkernel.LowPart = fkernel.dwLowDateTime;\n\t\tkernel.HighPart = fkernel.dwHighDateTime;\n\n\t\tuser.LowPart = fuser.dwLowDateTime;\n\t\tuser.HighPart = fuser.dwHighDateTime;\n\n\t\tout_now = now.QuadPart;\n\t\tout_user = user.QuadPart;\n\t\tout_kernel = kernel.QuadPart;\n\t}\n\telse\n\t{\n\t\tout_now = 0;\n\t\tout_user = 0;\n\t\tout_kernel = 0;\n\t}\n}\n\nvoid QueryCoreTimes(uint32 count, std::vector<ProcessorTime>& out)\n{\n\tstd::vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> sppi(count);\n\tif (NT_SUCCESS(NtQuerySystemInformation(SystemProcessorPerformanceInformation, sppi.data(), sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * count, nullptr)))\n\t{\n\t\tfor (auto i = 0; i < out.size(); ++i)\n\t\t{\n\t\t\tout[i].idle = sppi[i].IdleTime.QuadPart;\n\t\t\tout[i].kernel = sppi[i].KernelTime.QuadPart;\n\t\t\tout[i].kernel -= out[i].idle;\n\t\t\tout[i].user = sppi[i].UserTime.QuadPart;\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (auto i = 0; i < count; ++i)\n\t\t{\n\t\t\tout[i] = { };\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/util/ThreadPool/ThreadPool.h",
    "content": "#include <thread>\n\nclass ThreadPool\n{\npublic:\n\ttemplate<class TFunction, class... TArgs>\n\tstatic void FireAndForget(TFunction&& f, TArgs&&... args)\n\t{\n\t\t// todo - find a way to use std::async here so we can utilize thread pooling?\n\t\tstd::thread t(std::forward<TFunction>(f), std::forward<TArgs>(args)...);\n\t\tt.detach();\n\t}\n\n\n};"
  },
  {
    "path": "src/util/VirtualHeap/VirtualHeap.cpp",
    "content": "#include \"VirtualHeap.h\"\n\nVirtualBufferHeap_t* virtualBufferHeap_create(uint32 virtualHeapSize, void* baseAddr)\n{\n\tVirtualBufferHeap_t* bufferHeap = (VirtualBufferHeap_t*)malloc(sizeof(VirtualBufferHeap_t));\n\tmemset(bufferHeap, 0, sizeof(VirtualBufferHeap_t));\n\tbufferHeap->firstEntry = nullptr;\n\tvirtualHeapSize = (virtualHeapSize + 31)&~31;\n\tbufferHeap->virtualSize = virtualHeapSize;\n\tbufferHeap->baseAddress = baseAddr;\n\tbufferHeap->updateTrackIndex = 0;\n\t// create pool of unused entries\n\tsint32 unusedEntryPoolSize = 1024 * 16;\n\tVirtualBufferHeapEntry_t* unusedEntryPool = (VirtualBufferHeapEntry_t*)malloc(sizeof(VirtualBufferHeapEntry_t)*unusedEntryPoolSize);\n\tfor (sint32 i = 0; i < unusedEntryPoolSize - 1; i++)\n\t{\n\t\tunusedEntryPool[i].next = unusedEntryPool + i + 1;\n\t}\n\tunusedEntryPool[unusedEntryPoolSize - 1].next = nullptr;\n\tbufferHeap->firstUnusedEntry = unusedEntryPool + 0;\n\treturn bufferHeap;\n}\n\nVirtualBufferHeapEntry_t* virtualBufferHeap_createEntry(VirtualBufferHeap_t* bufferHeap)\n{\n\tVirtualBufferHeapEntry_t* newEntry = bufferHeap->firstUnusedEntry;\n\tif (newEntry == nullptr)\n\t{\n\t\tcemuLog_log(LogType::Force, \"virtualBufferHeap_createEntry: Pool empty\");\n\t\tcemu_assert_suspicious();\n\t}\n\tbufferHeap->firstUnusedEntry = newEntry->next;\n\tnewEntry->previous = NULL;\n\tnewEntry->next = NULL;\n\treturn newEntry;\n}\n\nvoid virtualBufferHeap_releaseEntry(VirtualBufferHeap_t* bufferHeap, VirtualBufferHeapEntry_t* entry)\n{\n\tbufferHeap->stats.allocatedMemory -= (entry->endOffset - entry->startOffset);\n\tbufferHeap->stats.numActiveAllocs--;\n\tentry->next = bufferHeap->firstUnusedEntry;\n\tbufferHeap->firstUnusedEntry = entry;\n}\n\n// Allocate memory region from virtual heap. Always allocates memory at the lowest possible address\nVirtualBufferHeapEntry_t* virtualBufferHeap_allocate(VirtualBufferHeap_t* bufferHeap, uint32 size)\n{\n\t// align size\n\tsize = (size + 255)&~255;\n\t// iterate already allocated entries and try to find free space between them\n\tVirtualBufferHeapEntry_t* entryItr = bufferHeap->firstEntry;\n\tif (entryItr == NULL)\n\t{\n\t\t// entire heap is unallocated\n\t\tVirtualBufferHeapEntry_t* newEntry = virtualBufferHeap_createEntry(bufferHeap);\n\t\tnewEntry->startOffset = 0;\n\t\tnewEntry->endOffset = size;\n\t\tnewEntry->previous = NULL;\n\t\tnewEntry->next = NULL;\n\t\tbufferHeap->firstEntry = newEntry;\n\t\tbufferHeap->stats.allocatedMemory += size;\n\t\tbufferHeap->stats.numActiveAllocs++;\n\t\treturn newEntry;\n\t}\n\telse\n\t{\n\t\tuint32 currentAllocationOffset = 0;\n\t\tVirtualBufferHeapEntry_t* entryPrev = nullptr;\n\t\twhile (entryItr)\n\t\t{\n\t\t\tif ((currentAllocationOffset + size) > entryItr->startOffset)\n\t\t\t{\n\t\t\t\t// space occupied\n\t\t\t\tcurrentAllocationOffset = entryItr->endOffset;\n\t\t\t\tcurrentAllocationOffset = (currentAllocationOffset + 255)&~255;\n\t\t\t\t// next\n\t\t\t\tentryPrev = entryItr;\n\t\t\t\tentryItr = entryItr->next;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif ((currentAllocationOffset + size) > bufferHeap->virtualSize)\n\t\t\t\t\treturn nullptr; // out of heap memory\n\t\t\t\t// free space found\n\t\t\t\tVirtualBufferHeapEntry_t* newEntry = virtualBufferHeap_createEntry(bufferHeap);\n\t\t\t\tnewEntry->startOffset = currentAllocationOffset;\n\t\t\t\tnewEntry->endOffset = currentAllocationOffset + size;\n\t\t\t\t// insert between previous entry and entryItr\n\t\t\t\tnewEntry->previous = entryItr->previous;\n\t\t\t\tnewEntry->next = entryItr;\n\t\t\t\tif (entryItr->previous)\n\t\t\t\t\tentryItr->previous->next = newEntry;\n\t\t\t\telse\n\t\t\t\t\tbufferHeap->firstEntry = newEntry;\n\t\t\t\tentryItr->previous = newEntry;\n\t\t\t\tbufferHeap->stats.allocatedMemory += size;\n\t\t\t\tbufferHeap->stats.numActiveAllocs++;\n\t\t\t\treturn newEntry;\n\t\t\t}\n\t\t}\n\t\t// add after entryPrev\n\t\tif ((currentAllocationOffset + size) > bufferHeap->virtualSize)\n\t\t\treturn NULL; // out of heap memory\n\t\tVirtualBufferHeapEntry_t* newEntry = virtualBufferHeap_createEntry(bufferHeap);\n\t\tnewEntry->startOffset = currentAllocationOffset;\n\t\tnewEntry->endOffset = currentAllocationOffset + size;\n\t\t// insert after previous entry\n\t\tcemu_assert_debug(entryPrev);\n\t\tcemu_assert_debug(entryPrev->next == nullptr);\n\t\tnewEntry->previous = entryPrev;\n\t\tnewEntry->next = entryPrev->next;\n\t\tentryPrev->next = newEntry;\n\t\tbufferHeap->stats.allocatedMemory += size;\n\t\tbufferHeap->stats.numActiveAllocs++;\n\t\treturn newEntry;\n\t}\n\treturn NULL;\n}\n\nvoid virtualBufferHeap_free(VirtualBufferHeap_t* bufferHeap, VirtualBufferHeapEntry_t* entry)\n{\n\tif (entry->previous == NULL)\n\t{\n\t\t// make the next entry the first one\n\t\tif (entry->next)\n\t\t\tentry->next->previous = NULL;\n\t\tbufferHeap->firstEntry = entry->next;\n\t}\n\telse\n\t\tentry->previous->next = entry->next;\n\n\tif (entry->next)\n\t\tentry->next->previous = entry->previous;\n\t// release entry\n\tvirtualBufferHeap_releaseEntry(bufferHeap, entry);\n}\n\nvoid* virtualBufferHeap_allocateAddr(VirtualBufferHeap_t* bufferHeap, uint32 size)\n{\n\tVirtualBufferHeapEntry_t* heapEntry = virtualBufferHeap_allocate(bufferHeap, size);\n\treturn ((uint8*)bufferHeap->baseAddress + heapEntry->startOffset);\n}\n\nvoid virtualBufferHeap_freeAddr(VirtualBufferHeap_t* bufferHeap, void* addr)\n{\n\tauto entry = bufferHeap->firstEntry;\n\twhile(entry)\n\t{\n\t\tconst auto entry_address = (uint8*)bufferHeap->baseAddress + entry->startOffset;\n\t\tif(entry_address == (uint8*)addr)\n\t\t{\n\t\t\tvirtualBufferHeap_free(bufferHeap, entry);\n\t\t\treturn;\n\t\t}\n\t\tentry = entry->next;\n\t}\n\tcemu_assert_suspicious();\n}\n"
  },
  {
    "path": "src/util/VirtualHeap/VirtualHeap.h",
    "content": "#pragma once\n\n// virtual heap\n\nstruct VirtualBufferHeapEntry_t\n{\n\tuint32 startOffset;\n\tuint32 endOffset;\n\tVirtualBufferHeapEntry_t* next;\n\tVirtualBufferHeapEntry_t* previous;\n};\n\nstruct VirtualBufferHeap_t\n{\n\tuint32 virtualSize;\n\tvoid* baseAddress; // base address for _allocateAddr and _freeAddr\n\tVirtualBufferHeapEntry_t* firstEntry;\n\t// unused entries\n\tVirtualBufferHeapEntry_t* firstUnusedEntry;\n\t// update tracking\n\tuint32 updateTrackIndex;\n\t// stats\n\tstruct  \n\t{\n\t\tuint32 numActiveAllocs;\n\t\tuint32 allocatedMemory;\n\t}stats;\n};\n\nVirtualBufferHeap_t* virtualBufferHeap_create(uint32 virtualHeapSize, void* baseAddr = nullptr);\nVirtualBufferHeapEntry_t* virtualBufferHeap_allocate(VirtualBufferHeap_t* bufferHeap, uint32 size);\nvoid virtualBufferHeap_free(VirtualBufferHeap_t* bufferHeap, VirtualBufferHeapEntry_t* entry);\n\nvoid* virtualBufferHeap_allocateAddr(VirtualBufferHeap_t* bufferHeap, uint32 size);\nvoid virtualBufferHeap_freeAddr(VirtualBufferHeap_t* bufferHeap, void* addr);"
  },
  {
    "path": "src/util/Zir/Core/IR.cpp",
    "content": "#include \"util/Zir/Core/IR.h\"\n#include \"util/Zir/Core/ZpIRDebug.h\"\n\n#include <cinttypes>\n\nnamespace ZpIR\n{\n\n\tconst char* getOpcodeName(IR::OpCode opcode)\n\t{\n\t\tswitch (opcode)\n\t\t{\n\t\tcase IR::OpCode::ADD:\n\t\t\treturn \"ADD\";\n\t\tcase IR::OpCode::MOV:\n\t\t\treturn \"MOV\";\n\t\tcase IR::OpCode::MUL:\n\t\t\treturn \"MUL\";\n\t\tcase IR::OpCode::DIV:\n\t\t\treturn \"DIV\";\n\n\t\tcase IR::OpCode::BITCAST:\n\t\t\treturn \"BITCAST\";\n\t\tcase IR::OpCode::SWAP_ENDIAN:\n\t\t\treturn \"SWAP_ENDIAN\";\n\t\tcase IR::OpCode::CONVERT_INT_TO_FLOAT:\n\t\t\treturn \"CONV_I2F\";\n\t\tcase IR::OpCode::CONVERT_FLOAT_TO_INT:\n\t\t\treturn \"CONV_F2I\";\n\n\t\tcase IR::OpCode::IMPORT_SINGLE:\n\t\t\treturn \"IMPORT_S\";\n\t\tcase IR::OpCode::EXPORT:\n\t\t\treturn \"EXPORT\";\n\t\tcase IR::OpCode::IMPORT:\n\t\t\treturn \"IMPORT\";\n\t\tdefault:\n\t\t\tcemu_assert_debug(false);\n\t\t\treturn \"UKN\";\n\t\t}\n\t\treturn \"\";\n\t}\n\n\tconst char* getTypeName(DataType t)\n\t{\n\t\tswitch (t)\n\t\t{\n\t\tcase DataType::S64:\n\t\t\treturn \"s64\";\n\t\tcase DataType::U64:\n\t\t\treturn \"u64\";\n\t\tcase DataType::S32:\n\t\t\treturn \"s32\";\n\t\tcase DataType::U32:\n\t\t\treturn \"u32\";\n\t\tcase DataType::S16:\n\t\t\treturn \"s16\";\n\t\tcase DataType::U16:\n\t\t\treturn \"u16\";\n\t\tcase DataType::S8:\n\t\t\treturn \"s8\";\n\t\tcase DataType::U8:\n\t\t\treturn \"u8\";\n\t\tcase DataType::BOOL:\n\t\t\treturn \"bool\";\n\t\tcase DataType::POINTER:\n\t\t\treturn \"ptr\";\n\t\t}\n\t\treturn \"\";\n\t}\n\n\tstd::string DebugPrinter::getRegisterName(ZpIRBasicBlock* block, IRReg r)\n\t{\n\t\tstd::string s;\n\n\t\tif ((uint16)r < 0x8000 && m_showPhysicalRegisters)\n\t\t{\n\t\t\tauto& reg = block->m_regs[(uint16)r];\n\t\t\tif (!reg.hasAssignedPhysicalRegister())\n\t\t\t\treturn \"UNASSIGNED\";\n\t\t\ts = m_getPhysicalRegisterNameCustom(block, reg.physicalRegister);\n\t\t\treturn s;\n\t\t}\n\n\t\tif ((uint16)r < 0x8000 && m_getRegisterNameCustom)\n\t\t{\n\t\t\treturn m_getRegisterNameCustom(block, r);\n\t\t}\n\n\t\tif ((uint16)r >= 0x8000)\n\t\t{\n\t\t\tauto& reg = block->m_consts[(uint16)r & 0x7FFF];\n\t\t\tswitch (reg.type)\n\t\t\t{\n\t\t\tcase DataType::POINTER:\n\t\t\t\treturn fmt::format(\"ptr:{}\", reg.value_ptr);\n\t\t\tcase DataType::U64:\n\t\t\t{\n\t\t\t\tif(reg.value_u64 >= 0x1000)\n\t\t\t\t\treturn fmt::format(\"u64:0x{0:x}\", reg.value_u64);\n\t\t\t\treturn fmt::format(\"u64:{}\", reg.value_u64);\n\t\t\t}\n\t\t\tcase DataType::U32:\n\t\t\t\treturn fmt::format(\"u32:{}\", reg.value_u32);\n\t\t\tcase DataType::S32:\n\t\t\t\treturn fmt::format(\"s32:{}\", reg.value_u32);\n\t\t\tcase DataType::F32:\n\t\t\t\treturn fmt::format(\"f32:{}\", reg.value_f32);\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn \"ukn_const_type\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tauto& reg = block->m_regs[(uint16)r];\n\t\t\t\n\t\t\tconst char* regLetter = \"r\";\n\t\t\tswitch (reg.type)\n\t\t\t{\n\t\t\tcase DataType::U64:\n\t\t\t\tregLetter = \"uq\"; // quad-word\n\t\t\t\tbreak;\n\t\t\tcase DataType::U32:\n\t\t\t\tregLetter = \"ud\"; // double-word\n\t\t\t\tbreak;\n\t\t\tcase DataType::U16:\n\t\t\t\tregLetter = \"uw\"; // word\n\t\t\t\tbreak;\n\t\t\tcase DataType::U8:\n\t\t\t\tregLetter = \"uc\"; // char\n\t\t\t\tbreak;\n\t\t\tcase DataType::S64:\n\t\t\t\tregLetter = \"sq\"; // signed quad-word\n\t\t\t\tbreak;\n\t\t\tcase DataType::S32:\n\t\t\t\tregLetter = \"sd\"; // signed double-word\n\t\t\t\tbreak;\n\t\t\tcase DataType::S16:\n\t\t\t\tregLetter = \"sw\"; // signed word\n\t\t\t\tbreak;\n\t\t\tcase DataType::S8:\n\t\t\t\tregLetter = \"sc\"; // signed char\n\t\t\t\tbreak;\n\t\t\tcase DataType::F32:\n\t\t\t\tregLetter = \"fv\"; // 32bit float\n\t\t\t\tbreak;\n\t\t\tcase DataType::POINTER:\n\t\t\t\tregLetter = \"ptr\";\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t\tif (reg.elementCount != 1)\n\t\t\t\tassert_dbg();\n\t\t\ts = fmt::format(\"{}{}\", regLetter, (uint16)r);\n\t\t}\n\t\treturn s;\n\t}\n\n\tstd::string DebugPrinter::getInstructionHRF(ZpIRBasicBlock* block, IR::__InsBase* cmd)\n\t{\n\t\tif (auto ins = IR::InsRR::getIfForm(cmd))\n\t\t{\n\t\t\treturn fmt::format(\"{:<10} {}, {}\", getOpcodeName(cmd->opcode), getRegisterName(block, ins->rA), getRegisterName(block, ins->rB));\n\t\t}\n\t\telse if (auto ins = IR::InsRRR::getIfForm(cmd))\n\t\t{\n\t\t\treturn fmt::format(\"{:<10} {}, {}, {}\", getOpcodeName(cmd->opcode), getRegisterName(block, ins->rA), getRegisterName(block, ins->rB), getRegisterName(block, ins->rC));\n\t\t}\n\t\telse if (auto ins = IR::InsEXPORT::getIfForm(cmd))\n\t\t{\n\t\t\tif (ins->count == 4)\n\t\t\t\treturn fmt::format(\"{:<10} {}, {}, {}, {}, loc: {}\", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), getRegisterName(block, ins->regArray[2]), getRegisterName(block, ins->regArray[3]), ins->exportSymbol);\n\t\t\telse if (ins->count == 3)\n\t\t\t\treturn fmt::format(\"{:<10} {}, {}, {}, loc: {}\", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), getRegisterName(block, ins->regArray[2]), ins->exportSymbol);\n\t\t\telse if (ins->count == 2)\n\t\t\t\treturn fmt::format(\"{:<10} {}, {}, loc: {}\", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), ins->exportSymbol);\n\t\t\telse if (ins->count == 1)\n\t\t\t\treturn fmt::format(\"{:<10} {}, loc: {}\", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), ins->exportSymbol);\n\t\t\tassert_dbg();\n\t\t}\n\t\telse if (auto ins = IR::InsIMPORT::getIfForm(cmd))\n\t\t{\n\t\t\tShaderSubset::ShaderImportLocation importLocation = ins->importSymbol;\n\t\t\tstd::string locDebugName = importLocation.GetDebugName();\n\n\t\t\tif (ins->count == 4)\n\t\t\t\treturn fmt::format(\"{:<10} {}, {}, {}, {}, loc: {}\", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), getRegisterName(block, ins->regArray[2]), getRegisterName(block, ins->regArray[3]), locDebugName);\n\t\t\telse if (ins->count == 3)\n\t\t\t\treturn fmt::format(\"{:<10} {}, {}, {}, loc: {}\", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), getRegisterName(block, ins->regArray[2]), locDebugName);\n\t\t\telse if (ins->count == 2)\n\t\t\t\treturn fmt::format(\"{:<10} {}, {}, loc: {}\", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), getRegisterName(block, ins->regArray[1]), locDebugName);\n\t\t\telse if (ins->count == 1)\n\t\t\t\treturn fmt::format(\"{:<10} {}, loc: {}\", getOpcodeName(cmd->opcode), getRegisterName(block, ins->regArray[0]), locDebugName);\n\t\t\tassert_dbg();\n\t\t}\n\t\telse\n\t\t\tassert_dbg();\n\t\treturn \"\";\n\t}\n\n\tvoid DebugPrinter::debugPrintBlock(ZpIRBasicBlock* block)\n\t{\n\t\t// print name\n\t\tprintf(\"IRBasicBlock %\" PRIxPTR \"\\n\", (uintptr_t)block);\n\t\t// print imports\n\t\tprintf(\"Imports:\\n\");\n\t\tfor(auto itr : block->m_imports)\n\t\t\tprintf(\"   reg: %s sym:0x%llx\\n\", getRegisterName(block, itr.reg).c_str(), itr.name);\n\t\t// print exports\n\t\tprintf(\"Exports:\\n\");\n\t\tfor (auto itr : block->m_exports)\n\t\t\tprintf(\"   reg: %s sym:0x%llx\\n\", getRegisterName(block, itr.reg).c_str(), itr.name);\n\t\t// print instructions\n\t\tprintf(\"Assembly:\\n\");\n\t\tIR::__InsBase* instruction = block->m_instructionFirst;\n\t\tsize_t i = 0;\n\t\twhile(instruction)\n\t\t{\n\t\t\tstd::string s = getInstructionHRF(block, instruction);\n\t\t\tprintf(\"%04x %s\\n\", (unsigned int)i, s.c_str());\n\t\t\ti++;\n\t\t\tinstruction = instruction->next;\n\t\t}\n\t}\n\n\tvoid DebugPrinter::debugPrint(ZpIRFunction* irFunction)\n\t{\n\t\tprintf(\"--- Print IR function assembly ---\\n\");\n\t\tfor (auto& itr : irFunction->m_basicBlocks)\n\t\t{\n\t\t\tdebugPrintBlock(itr);\n\t\t\tprintf(\"\\n\");\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "src/util/Zir/Core/IR.h",
    "content": "#pragma once\n#include <optional>\n\nusing f32 = float;\nusing f64 = double;\n\ninline void zpir_debug_assert(bool _cond) \n{\n\tif(!_cond)\n\t\tassert_dbg();\n}\n\nnamespace ZpIR\n{\n\t//enum class ZpIRCmdForm : uint8\n\t//{\n\t//\tFORM_VOID, // no-op\n\t//\tFORM_ZERO, // opcode without operands\n\t//\tFORM_1OP, // op0\n\t//\tFORM_2OP, // op0, op1\n\t//\tFORM_3OP, // op0, op1, op2\n\t//\tFORM_4OP,  // op0, op1, op2, op3\n\t//\t// todo - memory read + memory store\n\t//\tFORM_MEM, // op0, opEA, offset, type\n\t//\t// todo - function calls\n\n\t//};\n\n\t//enum class ZpIROpcodeDepr : uint8\n\t//{\n\t//\tOP_VOID,\n\t//\t// FORM_1OP\n\t//\tOP_CALL,\n\t//\t// FORM_2OP\n\t//\tOP_ASSIGN, // copy/assignment\n\t//\tOP_CAST_ZEROEXT, // cast type to another. If broadening then zero-extend (unsigned cast)\n\t//\tOP_CAST_SIGNEXT, // cast type to another. If broadening then sign-extend (signed cast)\n\t//\t// FORM_3OP\n\t//\tOP_ADD, // op0 = op1 + op2\n\t//\tOP_SUB, // op0 = op1 - op2\n\t//\tOP_MUL, // op0 = op1 * op2\n\t//\tOP_DIV, // op0 = op1 / op2\n\t//\t// memory\n\t//\tOP_MEM_READ,\n\t//\tOP_MEM_WRITE,\n\t//};\n\n\tenum class DataType : uint8\n\t{\n\t\tNONE = 0x00,\n\t\t// integer\n\t\tU8 = 1,\n\t\tS8 = 2,\n\t\tU16 = 3,\n\t\tS16 = 4,\n\t\tU32 = 5,\n\t\tS32 = 6,\n\t\tU64 = 7,\n\t\tS64 = 8,\n\t\t// floating-point\n\t\tF32 = 0x10 + 0,\n\t\tF64 = 0x10 + 1,\n\t\t// special\n\t\tPOINTER = 0x20, // dynamic width based on pointer width of target architecture\n\t\t// boolean\n\t\tBOOL = 0x30, // can hold false/true. Size depends on target architecture\n\t};\n\n\ttypedef uint16 IRReg;\n\ttypedef uint64 LocationSymbolName;\n\ttypedef uint32 ZpIRPhysicalReg;\n\n\tinline bool isRegVar(IRReg r) { return r < 0x8000; };\n\tinline bool isConstVar(IRReg r) { return r >= 0x8000; };\n\tinline uint16 getRegIndex(IRReg r) { return (uint16)r & 0x7FFF; };\n\n\tnamespace IR\n\t{\n\t\tenum class OpCode : uint8\n\t\t{\n\t\t\tUNDEF = 0, // undefined \n\t\t\t// basic opcodes\n\t\t\tMOV,\n\n\t\t\t// basic arithmetic opcodes\n\t\t\tADD, // addition\n\t\t\tSUB, // subtraction\n\t\t\tMUL, // multiplication\n\t\t\tDIV, // division\n\n\t\t\t// conversion\n\t\t\tBITCAST, // like MOV, but allows registers of different types. No value conversion happens, raw bit copy\n\t\t\tSWAP_ENDIAN, // swap endianness\n\t\t\tCONVERT_INT_TO_FLOAT,\n\t\t\tCONVERT_FLOAT_TO_INT,\n\n\t\t\t// misc\n\t\t\tIMPORT_SINGLE, // import into a single IRReg. Depr: Make this like EXPORT where there is a 1-4 regs variant and one for more\n\t\t\tIMPORT, // import from external/custom resource into 1-4 IRReg\n\t\t\t\n\t\t\tEXPORT, // export 1-4 registers to external/custom resource\n\t\t\t// EXPORT_MANY // for when more than 4 registers are needed\n\t\t\t\n\n\n\t\t\t// vector\n\t\t\tEXTRACT_ELEMENT, // extract a scalar type from a vector type\n\t\t\t// some notes: We need this for texture read instructions. Where the result is a vec4 (f32x4) and this is how we can extract individual registers from that\n\t\t\t//             update -> We may also instead just let the texture sample instruction specify 4 output registers\n\t\t};\n\n\t\tenum class OpForm : uint8\n\t\t{\n\t\t\tNONE = 0,\n\t\t\tRR = 1,\n\t\t\tRRR = 2,\n\t\t\tIMPORT_SINGLE = 3, // deprecated\n\t\t\tIMPORT = 4,\n\t\t\tEXPORT = 5,\n\t\t};\n\n\t\t// instruction base class\n\t\tclass __InsBase\n\t\t{\n\t\tpublic:\n\n\t\t\tOpCode opcode;\n\t\t\tOpForm opform;\n\t\t\t__InsBase* next;\n\t\tprotected:\n\t\t\t__InsBase(OpCode opcode, OpForm opform) : opcode(opcode), opform(opform) { };\n\t\t};\n\n\t\t// adapted base class, instruction forms inherit from this\n\t\ttemplate<typename TInstr, OpForm TOpForm>\n\t\tclass __InsBaseWithForm : public __InsBase\n\t\t{\n\t\tpublic:\n\n\t\t\t//OpCode opcode;\n\t\t\t//OpForm opform;\n\t\t\t//__InsBase* next;\n\n\t\t\tstatic const OpForm getForm()\n\t\t\t{\n\t\t\t\treturn TOpForm;\n\t\t\t}\n\n\t\t\tstatic TInstr* getIfForm(__InsBase* instructionBase)\n\t\t\t{\n\t\t\t\tif (instructionBase->opform != TOpForm)\n\t\t\t\t\treturn nullptr;\n\t\t\t\treturn (TInstr*)instructionBase;\n\t\t\t}\n\n\t\tprotected:\n\t\t\t__InsBaseWithForm(OpCode opcode) : __InsBase(opcode, TOpForm) { };\n\t\t};\n\n\t\tclass InsRR : public __InsBaseWithForm<InsRR, OpForm::RR>\n\t\t{\n\t\tpublic:\n\t\t\tInsRR(OpCode opcode, IRReg rA, IRReg rB) : __InsBaseWithForm(opcode), rA(rA), rB(rB) {};\n\n\t\t\tIRReg rA;\n\t\t\tIRReg rB;\n\t\t};\n\n\t\tclass InsRRR : public __InsBaseWithForm<InsRRR, OpForm::RRR>\n\t\t{\n\t\tpublic:\n\t\t\tInsRRR(OpCode opcode, IRReg rA, IRReg rB, IRReg rC) : __InsBaseWithForm(opcode), rA(rA), rB(rB), rC(rC) {};\n\n\t\t\tIRReg rA;\n\t\t\tIRReg rB;\n\t\t\tIRReg rC;\n\t\t};\n\n\t\t// should we support RRI format with 32bit signed integer as a way to avoid having to generate dozens of IR const regs for stuff like shift and other logical instructions with constant rhs?\n\t\t// and if we do, should it be a 32bit signed integer or should the type match the instruction type?\n\n\t\tclass InsEXPORT : public __InsBaseWithForm<InsEXPORT, OpForm::EXPORT>\n\t\t{\n\t\tpublic:\n\t\t\tInsEXPORT(LocationSymbolName exportSymbol, IRReg r) : __InsBaseWithForm(OpCode::EXPORT), exportSymbol(exportSymbol)\n\t\t\t{\n\t\t\t\tregArray[0] = r;\n\t\t\t\tcount = 1;\n\t\t\t};\n\n\t\t\tInsEXPORT(LocationSymbolName exportSymbol, IRReg r0, IRReg r1) : __InsBaseWithForm(OpCode::EXPORT), exportSymbol(exportSymbol)\n\t\t\t{\n\t\t\t\tregArray[0] = r0; regArray[1] = r1;\n\t\t\t\tcount = 2;\n\t\t\t};\n\n\t\t\tInsEXPORT(LocationSymbolName exportSymbol, IRReg r0, IRReg r1, IRReg r2) : __InsBaseWithForm(OpCode::EXPORT), exportSymbol(exportSymbol)\n\t\t\t{\n\t\t\t\tregArray[0] = r0; regArray[1] = r1; regArray[2] = r2;\n\t\t\t\tcount = 3;\n\t\t\t};\n\n\t\t\tInsEXPORT(LocationSymbolName exportSymbol, IRReg r0, IRReg r1, IRReg r2, IRReg r3) : __InsBaseWithForm(OpCode::EXPORT), exportSymbol(exportSymbol)\n\t\t\t{\n\t\t\t\tregArray[0] = r0;\n\t\t\t\tregArray[1] = r1;\n\t\t\t\tregArray[2] = r2;\n\t\t\t\tregArray[3] = r3;\n\t\t\t\tcount = 4;\n\t\t\t};\n\n\t\t\tInsEXPORT(LocationSymbolName exportSymbol, std::span<IRReg> regs) : __InsBaseWithForm(OpCode::EXPORT), exportSymbol(exportSymbol)\n\t\t\t{\n\t\t\t\tzpir_debug_assert(regs.size() <= 4);\n\t\t\t\tfor(size_t i=0; i<regs.size(); i++)\n\t\t\t\t\tregArray[i] = regs[i];\n\t\t\t\tcount = (uint16)regs.size();\n\t\t\t};\n\n\t\t\tuint16 count;\n\t\t\tIRReg regArray[4]; // up to 4 registers\n\t\t\tLocationSymbolName exportSymbol;\n\t\t};\n\n\t\tclass InsIMPORT : public __InsBaseWithForm<InsIMPORT, OpForm::IMPORT>\n\t\t{\n\t\tpublic:\n\t\t\tInsIMPORT(LocationSymbolName importSymbol, IRReg r) : __InsBaseWithForm(OpCode::IMPORT), importSymbol(importSymbol)\n\t\t\t{\n\t\t\t\tregArray[0] = r;\n\t\t\t\tcount = 1;\n\t\t\t};\n\n\t\t\tInsIMPORT(LocationSymbolName importSymbol, IRReg r0, IRReg r1) : __InsBaseWithForm(OpCode::IMPORT), importSymbol(importSymbol)\n\t\t\t{\n\t\t\t\tregArray[0] = r0; regArray[1] = r1;\n\t\t\t\tcount = 2;\n\t\t\t};\n\n\t\t\tInsIMPORT(LocationSymbolName importSymbol, IRReg r0, IRReg r1, IRReg r2) : __InsBaseWithForm(OpCode::IMPORT), importSymbol(importSymbol)\n\t\t\t{\n\t\t\t\tregArray[0] = r0; regArray[1] = r1; regArray[2] = r2;\n\t\t\t\tcount = 3;\n\t\t\t};\n\n\t\t\tInsIMPORT(LocationSymbolName importSymbol, IRReg r0, IRReg r1, IRReg r2, IRReg r3) : __InsBaseWithForm(OpCode::IMPORT), importSymbol(importSymbol)\n\t\t\t{\n\t\t\t\tregArray[0] = r0;\n\t\t\t\tregArray[1] = r1;\n\t\t\t\tregArray[2] = r2;\n\t\t\t\tregArray[3] = r3;\n\t\t\t\tcount = 4;\n\t\t\t};\n\n\t\t\tInsIMPORT(LocationSymbolName importSymbol, std::span<IRReg> regs) : __InsBaseWithForm(OpCode::IMPORT), importSymbol(importSymbol)\n\t\t\t{\n\t\t\t\tzpir_debug_assert(regs.size() <= 4);\n\t\t\t\tfor (size_t i = 0; i < regs.size(); i++)\n\t\t\t\t\tregArray[i] = regs[i];\n\t\t\t\tcount = (uint16)regs.size();\n\t\t\t};\n\n\t\t\tuint16 count;\n\t\t\tIRReg regArray[4]; // up to 4 registers\n\t\t\tLocationSymbolName importSymbol;\n\t\t};\n\t};\n\n\t// IR register definition stored in basic block\n\tstruct IRRegDef \n\t{\n\t\tIRRegDef(DataType type, uint8 elementCount) : type(type), elementCount(elementCount) {};\n\n\t\tDataType type;\n\t\tuint8 elementCount; // 1 = scalar\n\t\tZpIRPhysicalReg physicalRegister{ std::numeric_limits<ZpIRPhysicalReg>::max()};\n\t\t// todo - information about spilling location? (it depends on the architecture so we should keep this out of the core IR)\n\t\tbool hasAssignedPhysicalRegister() const\n\t\t{\n\t\t\treturn physicalRegister != std::numeric_limits<ZpIRPhysicalReg>::max();\n\t\t}\n\n\t\tvoid assignPhysicalRegister(ZpIRPhysicalReg physReg)\n\t\t{\n\t\t\tphysicalRegister = physReg;\n\t\t}\n\t};\n\n\t// IR register constant definition stored in basic block\n\tstruct IRRegConstDef\n\t{\n\t\tIRRegConstDef() = default;\n\t\t// todo - support for constants with more than one element?\n\n\t\tIRRegConstDef& setU32(uint32 v) { value_u32 = v; type = DataType::U32; return *this; };\n\t\tIRRegConstDef& setS32(sint32 v) { value_s32 = v; type = DataType::S32; return *this; };\n\t\tIRRegConstDef& setF32(f32 v) { value_f32 = v; type = DataType::F32; return *this; };\n\t\tIRRegConstDef& setPtr(void* v) { value_ptr = v; type = DataType::POINTER; return *this; };\n\t\tIRRegConstDef& setRaw(uint32 v, DataType regType) { value_u32 = v; type = regType; return *this; };\n\n\t\tDataType type{ DataType::NONE };\n\t\tunion\n\t\t{\n\t\t\tuint32 value_u32;\n\t\t\tsint32 value_s32;\n\t\t\tsint64 value_s64;\n\t\t\tuint64 value_u64;\n\t\t\tvoid* value_ptr;\n\t\t\tf32 value_f32;\n\t\t\tf64 value_f64;\n\t\t};\n\t};\n\n\tstruct ZpIRBasicBlock\n\t{\n\t\tfriend class ZpIRBuilder;\n\n\t\tstruct IRBBImport\n\t\t{\n\t\t\tIRBBImport(IRReg reg, LocationSymbolName name) : reg(reg), name(name) {};\n\n\t\t\tIRReg reg;\n\t\t\tLocationSymbolName name;\n\t\t};\n\n\t\tstruct IRBBExport\n\t\t{\n\t\t\tIRBBExport(IRReg reg, LocationSymbolName name) : reg(reg), name(name) {};\n\n\t\t\tIRReg reg;\n\t\t\tLocationSymbolName name;\n\t\t};\n\n\t\tIR::__InsBase* m_instructionFirst{};\n\t\tIR::__InsBase* m_instructionLast{};\n\t\tstd::vector<IRRegDef> m_regs;\n\t\tstd::vector<IRRegConstDef> m_consts;\n\t\tstd::vector<IRBBImport> m_imports;\n\t\tstd::vector<IRBBExport> m_exports;\n\t\tZpIRBasicBlock* m_branchNotTaken{ nullptr }; // next block if branch not taken or no branch present\n\t\tZpIRBasicBlock* m_branchTaken{ nullptr }; // next block if branch is taken\n\n\t\tvoid* m_workbuffer{}; // can be used as temporary storage for information\n\n\t\tvoid appendInstruction(IR::__InsBase* ins)\n\t\t{\n\t\t\tif (m_instructionFirst == nullptr)\n\t\t\t{\n\t\t\t\tm_instructionFirst = ins;\n\t\t\t\tm_instructionLast = ins;\n\t\t\t\tins->next = nullptr;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tm_instructionLast->next = ins;\n\t\t\tm_instructionLast = ins;\n\t\t\tins->next = nullptr;\n\t\t}\n\n\t\tIRReg createRegister(DataType type, uint8 elementCount = 1)\n\t\t{\n\t\t\tuint32 index = (uint32)m_regs.size();\n\t\t\tcemu_assert_debug(index < 0x8000);\n\t\t\tm_regs.emplace_back(type, elementCount);\n\t\t\treturn (IRReg)index;\n\t\t}\n\n\t\tIRReg createConstantU32(uint32 value)\n\t\t{\n\t\t\tuint32 index = (uint32)m_consts.size();\n\t\t\tcemu_assert_debug(index < 0x8000);\n\t\t\tm_consts.emplace_back().setU32(value);\n\t\t\treturn (IRReg)((uint16)index + 0x8000);\n\t\t}\n\n\t\tIRReg createTypedConstant(uint32 value, DataType type)\n\t\t{\n\t\t\tuint32 index = (uint32)m_consts.size();\n\t\t\tcemu_assert_debug(index < 0x8000);\n\t\t\tm_consts.emplace_back().setRaw(value, type);\n\t\t\treturn (IRReg)((uint16)index + 0x8000);\n\t\t}\n\n\t\tIRReg createConstantS32(uint32 value)\n\t\t{\n\t\t\tuint32 index = (uint32)m_consts.size();\n\t\t\tcemu_assert_debug(index < 0x8000);\n\t\t\tm_consts.emplace_back().setS32(value);\n\t\t\treturn (IRReg)((uint16)index + 0x8000);\n\t\t}\n\n\t\tIRReg createConstantF32(f32 value)\n\t\t{\n\t\t\tuint32 index = (uint32)m_consts.size();\n\t\t\tcemu_assert_debug(index < 0x8000);\n\t\t\tm_consts.emplace_back().setF32(value);\n\t\t\treturn (IRReg)((uint16)index + 0x8000);\n\t\t}\n\n\t\tIRReg createConstantPointer(void* value)\n\t\t{\n\t\t\tuint32 index = (uint32)m_consts.size();\n\t\t\tcemu_assert_debug(index < 0x8000);\n\t\t\tm_consts.emplace_back().setPtr(value);\n\t\t\treturn (IRReg)((uint16)index + 0x8000);\n\t\t}\n\n\t\tvoid addImport(IRReg reg, LocationSymbolName importName)\n\t\t{\n\t\t\tm_imports.emplace_back(reg, importName);\n\t\t}\n\n\t\tvoid addExport(IRReg reg, LocationSymbolName importName)\n\t\t{\n\t\t\tm_exports.emplace_back(reg, importName);\n\t\t}\n\n\t\tvoid setWorkbuffer(void* buffer)\n\t\t{\n\t\t\tif (buffer != nullptr)\n\t\t\t{\n\t\t\t\tif (m_workbuffer)\n\t\t\t\t\tassert_dbg();\n\t\t\t}\n\t\t\tm_workbuffer = buffer;\n\t\t}\n\n\t\tvoid* getWorkbuffer()\n\t\t{\n\t\t\treturn m_workbuffer;\n\t\t}\n\n\n\t\tDataType getRegType(IRReg reg)\n\t\t{\n\t\t\tuint32 index = (uint32)reg;\n\t\t\tif (index >= 0x8000)\n\t\t\t{\n\t\t\t\tindex -= 0x8000;\n\t\t\t\tcemu_assert_debug(index < m_consts.size());\n\t\t\t\treturn m_consts[index].type;\n\t\t\t}\n\t\t\treturn m_regs[index].type;\n\t\t}\n\n\t\tIRRegConstDef* getConstant(IRReg reg)\n\t\t{\n\t\t\tuint32 index = (uint32)reg;\n\t\t\tif (index < 0x8000)\n\t\t\t\treturn nullptr;\n\t\t\tindex -= 0x8000;\n\t\t\tif (index >= m_consts.size())\n\t\t\t\treturn nullptr;\n\t\t\treturn m_consts.data() + index;\n\t\t}\n\n\t\tstd::optional<sint32> getConstantS32(IRReg reg)\n\t\t{\n\t\t\tuint32 index = (uint32)reg;\n\t\t\tif (index < 0x8000)\n\t\t\t\treturn std::nullopt;\n\t\t\tindex -= 0x8000;\n\t\t\tif (index >= m_consts.size())\n\t\t\t\treturn std::nullopt;\n\t\t\tif (m_consts[index].type == DataType::U32)\n\t\t\t\treturn (sint32)m_consts[index].value_u32;\n\t\t\telse if (m_consts[index].type == DataType::POINTER)\n\t\t\t\tassert_dbg();\n\t\t\telse if (m_consts[index].type == DataType::U64)\n\t\t\t{\n\t\t\t\tif (m_consts[index].value_u64 >= 0x80000000ull)\n\t\t\t\t\tassert_dbg();\n\t\t\t\treturn (sint32)m_consts[index].value_u64;\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t\treturn std::nullopt;\n\t\t}\n\n\t\tstd::optional<uint64> getConstantU64(IRReg reg)\n\t\t{\n\t\t\tauto constReg = getConstant(reg);\n\t\t\tif (!constReg)\n\t\t\t\treturn std::nullopt;\n\t\t\tif (constReg->type == DataType::U64)\n\t\t\t\treturn constReg->value_u64;\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t\treturn std::nullopt;\n\t\t}\n\t};\n\n\tstruct ZpIRFunction\n\t{\n\t\tstd::vector<ZpIRBasicBlock*> m_basicBlocks;\n\t\tstd::vector<ZpIRBasicBlock*> m_entryBlocks;\n\t\tstd::vector<ZpIRBasicBlock*> m_exitBlocks;\n\n\t\tstruct  \n\t\t{\n\t\t\tbool registersAllocated{false};\n\t\t}state;\n\t};\n\n\t// helpers for shader code\n\tnamespace ShaderSubset\n\t{\n\t\tclass ShaderImportLocation\n\t\t{\n\t\t\tenum LOC_TYPE : uint8\n\t\t\t{\n\t\t\t\tLOC_TYPE_UNIFORM_REGISTER = 1,\n\t\t\t\tLOC_TYPE_UNIFORM_BUFFER = 2,\n\t\t\t\tLOC_TYPE_ATTRIBUTE = 3,\n\t\t\t};\n\t\tpublic:\n\t\t\tShaderImportLocation() = default;\n\t\t\tShaderImportLocation(LocationSymbolName loc) \n\t\t\t{\n\t\t\t\tuint64 v = (uint64)loc;\n\n\t\t\t\tm_locType = (LOC_TYPE)(v >> 56);\n\t\t\t\tm_indexA = (uint16)(v >> 0);\n\t\t\t\tm_indexB = (uint16)(v >> 16);\n\t\t\t}\n\n\t\t\tShaderImportLocation& SetUniformRegister(uint16 index)\n\t\t\t{\n\t\t\t\tm_locType = LOC_TYPE_UNIFORM_REGISTER;\n\t\t\t\tm_indexA = index;\n\t\t\t\tm_indexB = 0;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tShaderImportLocation& SetVertexAttribute(uint16 attributeIndex, uint16 channelIndex)\n\t\t\t{\n\t\t\t\tm_locType = LOC_TYPE_ATTRIBUTE;\n\t\t\t\tm_indexA = attributeIndex;\n\t\t\t\tm_indexB = channelIndex;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tbool IsUniformRegister() const\n\t\t\t{\n\t\t\t\treturn m_locType == LOC_TYPE_UNIFORM_REGISTER;\n\t\t\t}\n\n\t\t\tbool IsVertexAttribute() const\n\t\t\t{\n\t\t\t\treturn m_locType == LOC_TYPE_ATTRIBUTE;\n\t\t\t}\n\n\t\t\tvoid GetUniformRegister(uint16& index)\n\t\t\t{\n\t\t\t\tindex = m_indexA;\n\t\t\t}\n\n\t\t\tvoid GetVertexAttribute(uint16& attributeIndex, uint16& channelIndex) const\n\t\t\t{\n\t\t\t\tattributeIndex = m_indexA;\n\t\t\t\tchannelIndex = m_indexB;\n\t\t\t}\n\n\t\t\toperator LocationSymbolName() const \n\t\t\t{ \n\t\t\t\tuint64 v = 0;\n\t\t\t\tv |= ((uint64)m_locType << 56);\n\t\t\t\tv |= ((uint64)m_indexA << 0);\n\t\t\t\tv |= ((uint64)m_indexB << 16);\n\n\t\t\t\treturn (LocationSymbolName)v;\n\t\t\t}\n\n\t\t\tstd::string GetDebugName()\n\t\t\t{\n\t\t\t\tconst char elementTable[] = { 'x' , 'y', 'z', 'w' };\n\n\t\t\t\tif (m_locType == LOC_TYPE_UNIFORM_REGISTER)\n\t\t\t\t\treturn fmt::format(\"UniformReg[{0}].{1}\", m_indexA >> 2, elementTable[m_indexA & 3]);\n\t\t\t\tif (m_locType == LOC_TYPE_ATTRIBUTE)\n\t\t\t\t\treturn fmt::format(\"VertexAttribute[{0}].{1}\", m_indexA, elementTable[m_indexB]);\n\n\t\t\t\treturn \"Unknown\";\n\t\t\t}\n\n\t\tprivate:\n\t\t\tLOC_TYPE m_locType{};\n\t\t\tuint16 m_indexA{};\n\t\t\tuint16 m_indexB{};\n\t\t\t//LocationSymbolName m_symbolName{};\n\t\t\tstatic_assert(sizeof(LocationSymbolName) == 8);\n\t\t};\n\n\t\tclass ShaderExportLocation\n\t\t{\n\t\t\tenum LOC_TYPE : uint8\n\t\t\t{\n\t\t\t\tLOC_TYPE_POSITION = 1,\n\t\t\t\tLOC_TYPE_OUTPUT = 2,\n\t\t\t};\n\t\tpublic:\n\t\t\tShaderExportLocation() = default;\n\t\t\tShaderExportLocation(LocationSymbolName loc)\n\t\t\t{\n\t\t\t\tuint64 v = (uint64)loc;\n\n\t\t\t\tm_locType = (LOC_TYPE)(v >> 56);\n\t\t\t\tm_indexA = (uint16)(v >> 0);\n\t\t\t\tm_indexB = (uint16)(v >> 16);\n\t\t\t}\n\n\t\t\tShaderExportLocation& SetPosition()\n\t\t\t{\n\t\t\t\tm_locType = LOC_TYPE_POSITION;\n\t\t\t\tm_indexA = 0;\n\t\t\t\tm_indexB = 0;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tShaderExportLocation& SetOutputAttribute(uint16 attributeIndex) // todo - channel mask?\n\t\t\t{\n\t\t\t\tm_locType = LOC_TYPE_OUTPUT;\n\t\t\t\tm_indexA = attributeIndex;\n\t\t\t\tm_indexB = 0;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tbool IsPosition() const\n\t\t\t{\n\t\t\t\treturn m_locType == LOC_TYPE_POSITION;\n\t\t\t}\n\n\t\t\tbool IsOutputAttribute() const\n\t\t\t{\n\t\t\t\treturn m_locType == LOC_TYPE_OUTPUT;\n\t\t\t}\n\n\t\t\tvoid GetOutputAttribute(uint16& attributeIndex) const\n\t\t\t{\n\t\t\t\tattributeIndex = m_indexA;\n\t\t\t}\n\n\t\t\toperator LocationSymbolName() const\n\t\t\t{\n\t\t\t\tuint64 v = 0;\n\t\t\t\tv |= ((uint64)m_locType << 56);\n\t\t\t\tv |= ((uint64)m_indexA << 0);\n\t\t\t\tv |= ((uint64)m_indexB << 16);\n\n\t\t\t\treturn (LocationSymbolName)v;\n\t\t\t}\n\n\t\t\tstd::string GetDebugName()\n\t\t\t{\n\t\t\t\tconst char elementTable[] = { 'x' , 'y', 'z', 'w' };\n\n\t\t\t\t//if (m_locType == LOC_TYPE_UNIFORM_REGISTER)\n\t\t\t\t//\treturn fmt::format(\"UniformReg[{0}].{1}\", m_indexA >> 2, elementTable[m_indexA & 3]);\n\t\t\t\t//if (m_locType == LOC_TYPE_ATTRIBUTE)\n\t\t\t\t//\treturn fmt::format(\"VertexAttribute[{0}].{1}\", m_indexA, elementTable[m_indexB]);\n\n\t\t\t\treturn \"Unknown\";\n\t\t\t}\n\n\t\tprivate:\n\t\t\tLOC_TYPE m_locType{};\n\t\t\tuint16 m_indexA{};\n\t\t\tuint16 m_indexB{};\n\t\t\tstatic_assert(sizeof(LocationSymbolName) == 8);\n\t\t};\n\n\t};\n}\n"
  },
  {
    "path": "src/util/Zir/Core/ZirUtility.h",
    "content": "#pragma once\n#include \"util/Zir/Core/IR.h\"\n\nnamespace ZpIR\n{\n\n\tstruct ZpIRCmdUtil\n\t{\n\t\ttemplate<typename TFuncRegRead, typename TFuncRegWrite>\n\t\tstatic void forEachAccessedReg(ZpIRBasicBlock& block, IR::__InsBase* instruction, TFuncRegRead funcRegRead, TFuncRegWrite funcRegWrite)\n\t\t{\n\t\t\tif (auto ins = IR::InsRR::getIfForm(instruction))\n\t\t\t{\n\t\t\t\tswitch (ins->opcode)\n\t\t\t\t{\n\t\t\t\tcase ZpIR::IR::OpCode::MOV:\n\t\t\t\tcase ZpIR::IR::OpCode::BITCAST:\n\t\t\t\tcase ZpIR::IR::OpCode::SWAP_ENDIAN:\n\t\t\t\tcase ZpIR::IR::OpCode::CONVERT_FLOAT_TO_INT:\n\t\t\t\tcase ZpIR::IR::OpCode::CONVERT_INT_TO_FLOAT:\n\t\t\t\t\tif (isRegVar(ins->rB))\n\t\t\t\t\t\tfuncRegRead(ins->rB);\n\t\t\t\t\tcemu_assert_debug(isRegVar(ins->rA));\n\t\t\t\t\tfuncRegWrite(ins->rA);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (auto ins = IR::InsRRR::getIfForm(instruction))\n\t\t\t{\n\t\t\t\tswitch (ins->opcode)\n\t\t\t\t{\n\t\t\t\tcase ZpIR::IR::OpCode::ADD:\n\t\t\t\tcase ZpIR::IR::OpCode::SUB:\n\t\t\t\tcase ZpIR::IR::OpCode::MUL:\n\t\t\t\tcase ZpIR::IR::OpCode::DIV:\n\t\t\t\t\tif (isRegVar(ins->rB))\n\t\t\t\t\t\tfuncRegRead(ins->rB);\n\t\t\t\t\tif (isRegVar(ins->rC))\n\t\t\t\t\t\tfuncRegRead(ins->rC);\n\t\t\t\t\tcemu_assert_debug(isRegVar(ins->rA));\n\t\t\t\t\tfuncRegWrite(ins->rA);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (auto ins = IR::InsIMPORT::getIfForm(instruction))\n\t\t\t{\n\t\t\t\tfor (uint16 i = 0; i < ins->count; i++)\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(isRegVar(ins->regArray[i]));\n\t\t\t\t\tfuncRegWrite(ins->regArray[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (auto ins = IR::InsEXPORT::getIfForm(instruction))\n\t\t\t{\n\t\t\t\tfor (uint16 i = 0; i < ins->count; i++)\n\t\t\t\t{\n\t\t\t\t\tif (isRegVar(ins->regArray[i]))\n\t\t\t\t\t\tfuncRegRead(ins->regArray[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t}\n\t\t}\n\n\t\tstatic void replaceRegisters(IR::__InsBase& ins, std::unordered_map<IRReg, IRReg>& translationTable)\n\t\t{\n\t\t\tcemu_assert_unimplemented();\n\t\t}\n\t};\n}"
  },
  {
    "path": "src/util/Zir/Core/ZpIRBuilder.h",
    "content": "#pragma once\n#include \"util/Zir/Core/IR.h\"\n\nnamespace ZpIR\n{\n\n\t// helper class for building a single basic block\n\tclass BasicBlockBuilder\n\t{\n\tpublic:\n\t\tBasicBlockBuilder(ZpIRBasicBlock* basicBlock) : m_basicBlock(basicBlock) {};\n\n\t\tIRReg createReg(DataType type, uint8 elementCount = 1)\n\t\t{\n\t\t\treturn m_basicBlock->createRegister(type, elementCount);\n\t\t}\n\n\t\tIRReg createReg(IRReg& r, DataType type, uint8 elementCount = 1)\n\t\t{\n\t\t\tr = m_basicBlock->createRegister(type, elementCount);\n\t\t\treturn r;\n\t\t}\n\n\t\t// append a single instruction at the end\n\t\tvoid append(IR::__InsBase* ins)\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\n\t\tvoid emit_EXPORT(LocationSymbolName exportSymbolName, IRReg r0)\n\t\t{\n\t\t\tm_basicBlock->appendInstruction(new IR::InsEXPORT(exportSymbolName, r0));\n\t\t}\n\n\t\tvoid emit_EXPORT(LocationSymbolName exportSymbolName, std::span<IRReg> regs)\n\t\t{\n\t\t\tm_basicBlock->appendInstruction(new IR::InsEXPORT(exportSymbolName, regs));\n\t\t}\n\n\t\tvoid emit_IMPORT(LocationSymbolName importSymbolName, IRReg r0)\n\t\t{\n\t\t\tm_basicBlock->appendInstruction(new IR::InsIMPORT(importSymbolName, r0));\n\t\t}\n\n\t\t// result is rA, operand is rB\n\t\t// for some opcodes both can be operands\n\t\tvoid emit_RR(IR::OpCode opcode, IRReg rA, IRReg rB)\n\t\t{\n\t\t\tm_basicBlock->appendInstruction(new IR::InsRR(opcode, rA, rB));\n\t\t}\n\n\t\tIRReg emit_RR(IR::OpCode opcode, DataType resultType, IRReg rB)\n\t\t{\n\t\t\tIRReg resultReg = m_basicBlock->createRegister(resultType);\n\t\t\temit_RR(opcode, resultReg, rB);\n\t\t\treturn resultReg;\n\t\t}\n\n\t\t// result is rA, operands are rB and rC\n\t\t// for some opcodes all three can be operands\n\t\tvoid emit_RRR(IR::OpCode opcode, IRReg rA, IRReg rB, IRReg rC)\n\t\t{\n\t\t\tm_basicBlock->appendInstruction(new IR::InsRRR(opcode, rA, rB, rC));\n\t\t}\n\n\t\tIRReg emit_RRR(IR::OpCode opcode, DataType resultType, IRReg rB, IRReg rC)\n\t\t{\n\t\t\tIRReg resultReg = m_basicBlock->createRegister(resultType);\n\t\t\tm_basicBlock->appendInstruction(new IR::InsRRR(opcode, resultReg, rB, rC));\n\t\t\treturn resultReg;\n\t\t}\n\n\t\tvoid emit(IR::__InsBase* ins)\n\t\t{\n\t\t\tm_basicBlock->appendInstruction(ins);\n\t\t}\n\t\t\n\t\t// constant var creation\n\n\t\tIRReg createConstU32(uint32 v)\n\t\t{\n\t\t\treturn m_basicBlock->createConstantU32(v);\n\t\t}\n\n\t\tIRReg createTypedConst(uint32 v, DataType type)\n\t\t{\n\t\t\treturn m_basicBlock->createTypedConstant(v, type);\n\t\t}\n\n\t\tIRReg createConstS32(uint32 v)\n\t\t{\n\t\t\treturn m_basicBlock->createConstantS32(v);\n\t\t}\n\n\t\tIRReg createConstF32(f32 v)\n\t\t{\n\t\t\treturn m_basicBlock->createConstantF32(v);\n\t\t}\n\n\t\tIRReg createConstPointer(void* v)\n\t\t{\n\t\t\treturn m_basicBlock->createConstantPointer(v);\n\t\t}\n\n\t\t// use templates to compact other types?\n\n\t\tDataType getRegType(IRReg reg)\n\t\t{\n\t\t\treturn m_basicBlock->getRegType(reg);\n\t\t}\n\n\t\tvoid addImport(IRReg reg, LocationSymbolName importSymbolName)\n\t\t{\n\t\t\tm_basicBlock->addImport(reg, importSymbolName);\n\t\t}\n\n\n\tprivate:\n\t\tZpIRBasicBlock* m_basicBlock;\n\t};\n\n\t// helper class for constructing multiple basic blocks with control flow\n\tclass ZpIRBuilder\n\t{\n\tpublic:\n\t\ttypedef uint64 BlockBranchTarget;\n\n\t\tstatic const inline BlockBranchTarget INVALID_BLOCK_NAME = 0xFFFFFFFFFFFFFFFFull;\n\n\t\tstruct BasicBlockWorkbuffer\n\t\t{\n\t\t\tBlockBranchTarget name{ INVALID_BLOCK_NAME };\n\t\t\tBlockBranchTarget targetBranchNotTaken{ INVALID_BLOCK_NAME };\n\t\t\tBlockBranchTarget targetBranchTaken{ INVALID_BLOCK_NAME };\n\t\t};\n\n\t\tvoid beginBlock(BlockBranchTarget name)\n\t\t{\n\t\t\tm_currentBasicBlock = new ZpIRBasicBlock();\n\t\t\tBasicBlockWorkbuffer* wb = new BasicBlockWorkbuffer();\n\t\t\tm_currentBasicBlock->setWorkbuffer(wb);\n\t\t\twb->name = name;\n\t\t\tm_blocks.emplace_back(m_currentBasicBlock);\n\t\t\tm_blocksByName.emplace(name, m_currentBasicBlock);\n\t\t}\n\n\t\tZpIRBasicBlock* endBlock()\n\t\t{\n\t\t\tZpIRBasicBlock* block = m_currentBasicBlock;\n\t\t\tm_currentBasicBlock = nullptr;\n\t\t\tBasicBlockWorkbuffer* wb = (BasicBlockWorkbuffer*)block->getWorkbuffer();\n\t\t\twb->targetBranchNotTaken = m_targetBranchNotTaken;\n\t\t\twb->targetBranchTaken = m_targetBranchTaken;\n\t\t\tm_targetBranchNotTaken = INVALID_BLOCK_NAME;\n\t\t\tm_targetBranchTaken = INVALID_BLOCK_NAME;\n\t\t\treturn block;\n\t\t}\n\n\t\tZpIRFunction* finish()\n\t\t{\n\t\t\tif (m_currentBasicBlock)\n\t\t\t\tassert_dbg();\n\t\t\t// create function\n\t\t\tZpIRFunction* func = new ZpIRFunction();\n\t\t\t// link all blocks\n\t\t\t// and also collect a list of entry and exit nodes\n\t\t\tfor (auto& itr : m_blocks)\n\t\t\t{\n\t\t\t\tBasicBlockWorkbuffer* wb = (BasicBlockWorkbuffer*)itr->getWorkbuffer();\n\t\t\t\tif (wb->targetBranchNotTaken != INVALID_BLOCK_NAME)\n\t\t\t\t{\n\t\t\t\t\tauto target = m_blocksByName.find(wb->targetBranchNotTaken);\n\t\t\t\t\tif (target == m_blocksByName.end())\n\t\t\t\t\t{\n\t\t\t\t\t\tassert_dbg();\n\t\t\t\t\t}\n\t\t\t\t\titr->m_branchNotTaken = target->second;\n\t\t\t\t}\n\t\t\t\tif (wb->targetBranchTaken != INVALID_BLOCK_NAME)\n\t\t\t\t{\n\t\t\t\t\tauto target = m_blocksByName.find(wb->targetBranchTaken);\n\t\t\t\t\tif (target == m_blocksByName.end())\n\t\t\t\t\t{\n\t\t\t\t\t\tassert_dbg();\n\t\t\t\t\t}\n\t\t\t\t\titr->m_branchTaken = target->second;\n\t\t\t\t}\n\t\t\t\tdelete wb;\n\t\t\t\titr->setWorkbuffer(nullptr);\n\t\t\t\tfunc->m_basicBlocks.emplace_back(itr);\n\t\t\t\t// todo - track entry and exit blocks (set block flags for entry/exit during block gen)\n\t\t\t}\n\t\t\treturn func;\n\t\t}\n\n\t\tIRReg createBlockRegister(DataType type, uint8 elementCount = 1)\n\t\t{\n\t\t\treturn m_currentBasicBlock->createRegister(type, elementCount);\n\t\t}\n\n\t\tIRReg createConstU32(uint32 v)\n\t\t{\n\t\t\treturn m_currentBasicBlock->createConstantU32(v);\n\t\t}\n\n\t\tIRReg createConstPointer(void* v)\n\t\t{\n\t\t\treturn m_currentBasicBlock->createConstantPointer(v);\n\t\t}\n\n\t\tIRReg createConstPointerV(size_t v)\n\t\t{\n\t\t\treturn m_currentBasicBlock->createConstantPointer((void*)v);\n\t\t}\n\n\t\tvoid addImport(IRReg reg, LocationSymbolName importName)\n\t\t{\n\t\t\tm_currentBasicBlock->addImport(reg, importName);\n\t\t}\n\n\t\tvoid addExport(IRReg reg, LocationSymbolName importName)\n\t\t{\n\t\t\tm_currentBasicBlock->addExport(reg, importName);\n\t\t}\n\n\t\tvoid setBlockTargetBranchTaken(BlockBranchTarget target)\n\t\t{\n\t\t\tif (m_targetBranchTaken != INVALID_BLOCK_NAME)\n\t\t\t\tassert_dbg();\n\t\t\tm_targetBranchTaken = target;\n\t\t}\n\n\t\tvoid setBlockTargetBranchNotTaken(BlockBranchTarget target)\n\t\t{\n\t\t\tif (m_targetBranchNotTaken != INVALID_BLOCK_NAME)\n\t\t\t\tassert_dbg();\n\t\t\tm_targetBranchNotTaken = target;\n\t\t}\n\n\tprivate:\n\t\tZpIRBasicBlock* m_currentBasicBlock{};\n\t\tstd::vector<ZpIRBasicBlock*> m_blocks;\n\t\tstd::unordered_map<BlockBranchTarget, ZpIRBasicBlock*> m_blocksByName;\n\n\t\tBlockBranchTarget m_targetBranchNotTaken{ INVALID_BLOCK_NAME };\n\t\tBlockBranchTarget m_targetBranchTaken{ INVALID_BLOCK_NAME };\n\n\t};\n\n}\n"
  },
  {
    "path": "src/util/Zir/Core/ZpIRDebug.h",
    "content": "#pragma once\n#include \"util/Zir/Core/IR.h\"\n\nnamespace ZpIR\n{\n\n\tclass DebugPrinter\n\t{\n\n\tpublic:\n\t\tvoid debugPrint(ZpIRFunction* irFunction);\n\n\t\tvoid setShowPhysicalRegisters(bool showPhys)\n\t\t{\n\t\t\tm_showPhysicalRegisters = showPhys;\n\t\t}\n\n\t\tvoid setVirtualRegisterNameSource(std::string(*getRegisterNameCustom)(ZpIRBasicBlock* block, IRReg r))\n\t\t{\n\t\t\tm_getRegisterNameCustom = getRegisterNameCustom;\n\t\t}\n\n\t\tvoid setPhysicalRegisterNameSource(std::string(*getRegisterNameCustom)(ZpIRBasicBlock* block, ZpIRPhysicalReg r))\n\t\t{\n\t\t\tm_getPhysicalRegisterNameCustom = getRegisterNameCustom;\n\t\t}\n\n\tprivate:\n\t\tstd::string getRegisterName(ZpIRBasicBlock* block, IRReg r);\n\t\tstd::string getInstructionHRF(ZpIRBasicBlock* block, IR::__InsBase* cmd);\n\t\tvoid debugPrintBlock(ZpIRBasicBlock* block);\n\n\t\tstd::string(*m_getRegisterNameCustom)(ZpIRBasicBlock* block, IRReg r) { nullptr };\n\t\tstd::string(*m_getPhysicalRegisterNameCustom)(ZpIRBasicBlock* block, ZpIRPhysicalReg r) { nullptr };\n\n\t\tbool m_showPhysicalRegisters{}; // show global/physical register mapping instead of local IRReg indices\n\t};\n\n}"
  },
  {
    "path": "src/util/Zir/Core/ZpIRPasses.h",
    "content": "#pragma once\n#include \"util/Zir/Core/IR.h\"\n\nnamespace ZirPass\n{\n\tclass ZpIRPass\n\t{\n\tpublic:\n\t\tZpIRPass(ZpIR::ZpIRFunction* irFunction) : m_irFunction(irFunction) { };\n\n\t\tvirtual void applyPass() = 0;\n\n\tprotected:\n\t\tZpIR::ZpIRFunction* m_irFunction;\n\t};\n\n\tstruct RALivenessRange_t\n\t{\n\t\tRALivenessRange_t(struct RABlock_t* block, ZpIR::IRReg irReg, sint32 start, sint32 end, ZpIR::DataType irDataType);\n\t\t~RALivenessRange_t();\n\n\t\tenum class SOURCE\n\t\t{\n\t\t\tNONE,\n\t\t\tINSTRUCTION, // instruction initializes value\n\t\t\tPREVIOUS_BLOCK, // imported from previous block(s)\n\t\t\tPREVIOUS_RANGE, // from previous range within same block\n\t\t};\n\n\t\tenum class LOCATION\n\t\t{\n\t\t\tUNASSIGNED,\n\t\t\tPHYSICAL_REGISTER,\n\t\t\tSPILLED,\n\t\t};\n\n\t\tvoid setStart(sint32 startIndex);\n\t\tvoid setEnd(sint32 endIndex);\n\n\t\tvoid addSourceFromPreviousBlock(RALivenessRange_t* source)\n\t\t{\n\t\t\tif (m_source != SOURCE::NONE && m_source != SOURCE::PREVIOUS_BLOCK)\n\t\t\t\tassert_dbg();\n\t\t\tm_source = SOURCE::PREVIOUS_BLOCK;\n\t\t\tm_sourceRanges.emplace_back(source);\n\t\t\tsource->m_destinationRanges.emplace_back(this);\n\t\t}\n\n\t\tvoid addSourceFromSameBlock(RALivenessRange_t* source)\n\t\t{\n\t\t\tif (m_source != SOURCE::NONE)\n\t\t\t\tassert_dbg();\n\t\t\tm_source = SOURCE::PREVIOUS_RANGE;\n\t\t\tm_sourceRanges.emplace_back(source);\n\t\t\tsource->m_destinationRanges.emplace_back(this);\n\t\t}\n\n\t\tbool isOverlapping(sint32 start, sint32 end) const\n\t\t{\n\t\t\treturn m_startIndex < end && m_endIndex >= start;\n\t\t}\n\n\t\tbool isOverlapping(RALivenessRange_t* range) const\n\t\t{\n\t\t\treturn isOverlapping(range->m_startIndex, range->m_endIndex);\n\t\t}\n\n\t\tvoid assignPhysicalRegister(ZpIR::ZpIRPhysicalReg physReg);\n\n\t\tRABlock_t* m_block;\n\t\tZpIR::IRReg m_irReg;\n\t\tZpIR::DataType m_irDataType;\n\t\tsint32 m_startIndex{ -1 };\n\t\tsint32 m_endIndex{ -1 }; // inclusive\n\n\t\t//std::vector<bool> m_reservedPhysRegisters; // unavailable physical registers\n\t\tstd::vector<RALivenessRange_t*> m_overlappingRanges;\n\n\t\t// state / assigned location\n\t\tLOCATION m_location{ LOCATION::UNASSIGNED };\n\t\tsint32 m_physicalRegister;\n\n\t\t// source\n\t\tSOURCE m_source{ SOURCE::NONE };\n\t\tstd::vector<RALivenessRange_t*> m_sourceRanges;\n\n\t\t// destination\n\t\t//RALivenessRange_t* m_destinationRange{ nullptr };\n\t\tstd::vector<RALivenessRange_t*> m_destinationRanges;\n\n\t};\n\n\tstruct RABlock_t\n\t{\n\t\tstd::unordered_map<ZpIR::IRReg, RALivenessRange_t*> livenessRanges;\n\n\t\tstruct Compare\n\t\t{\n\t\t\tbool operator()(const RALivenessRange_t* lhs, const RALivenessRange_t* rhs) const /* noexcept */\n\t\t\t{\n\t\t\t\t// order for unassignedRanges\n\t\t\t\t// aka order in which ranges should be assigned physical registers\n\t\t\t\treturn lhs->m_startIndex < rhs->m_startIndex;\n\t\t\t}\n\t\t};\n\n\tpublic:\n\t\tstd::multiset<RALivenessRange_t*, Compare> unassignedRanges;\n\t};\n\n\tclass RARegular : public ZpIRPass\n\t{\n\tpublic:\n\t\tRARegular(ZpIR::ZpIRFunction* irFunction) : ZpIRPass(irFunction) {};\n\n\t\tvoid applyPass()\n\t\t{\n\t\t\tprepareRABlocks();\n\t\t\tgenerateLivenessRanges();\n\t\t\tassignPhysicalRegisters();\n\t\t\tassert_dbg(); // todo -> rewrite doesnt need to be separate any longer since we store a separate physical register index now (in IRReg)\n\t\t\trewrite();\n\t\t\tm_irFunction->state.registersAllocated = true;\n\t\t}\n\n\n\tprivate:\n\t\tvoid prepareRABlocks();\n\t\tvoid generateLivenessRanges();\n\t\tvoid assignPhysicalRegisters();\n\t\tvoid rewrite();\n\n\t\tvoid assignPhysicalRegistersForBlock(RABlock_t& raBlock);\n\t\tvoid rewriteBlock(ZpIR::ZpIRBasicBlock& basicBlock, RABlock_t& raBlock);\n\n\t\tstd::span<sint32> extGetSuitablePhysicalRegisters(ZpIR::DataType dataType)\n\t\t{\n\t\t\tconst sint32 OFFSET_U64 = 0;\n\t\t\tconst sint32 OFFSET_U32 = 16;\n\n\t\t\tstatic sint32 _regCandidatesU64[] = { OFFSET_U64 + 0, OFFSET_U64 + 1, OFFSET_U64 + 2, OFFSET_U64 + 3, OFFSET_U64 + 4, OFFSET_U64 + 5, OFFSET_U64 + 6, OFFSET_U64 + 7, OFFSET_U64 + 8, OFFSET_U64 + 9, OFFSET_U64 + 10, OFFSET_U64 + 11, OFFSET_U64 + 12, OFFSET_U64 + 13, OFFSET_U64 + 14, OFFSET_U64 + 15 };\n\t\t\tstatic sint32 _regCandidatesU32[] = { OFFSET_U32 + 0, OFFSET_U32 + 1, OFFSET_U32 + 2, OFFSET_U32 + 3, OFFSET_U32 + 4, OFFSET_U32 + 5, OFFSET_U32 + 6, OFFSET_U32 + 7, OFFSET_U32 + 8, OFFSET_U32 + 9, OFFSET_U32 + 10, OFFSET_U32 + 11, OFFSET_U32 + 12, OFFSET_U32 + 13, OFFSET_U32 + 14, OFFSET_U32 + 15 };\n\n\n\n\t\t\tif (dataType == ZpIR::DataType::POINTER || dataType == ZpIR::DataType::U64)\n\t\t\t\treturn _regCandidatesU64;\n\t\t\tif (dataType == ZpIR::DataType::U32)\n\t\t\t\treturn _regCandidatesU32;\n\n\t\t\t//if (dataType != ZpIRDataType::POINTER)\n\t\t\t//{\n\n\t\t\t//}\n\t\t\tassert_dbg();\n\n\t\t\treturn _regCandidatesU32;\n\t\t}\n\n\t\tvoid extFilterPhysicalRegisters(std::vector<sint32>& physRegCandidates, ZpIR::ZpIRPhysicalReg registerToFilter)\n\t\t{\n\t\t\t// todo - this is quite complex on x86 where registers overlap (e.g. RAX and EAX/AL/AH/AX)\n\t\t\t// so registerToFilter can translate to multiple filtered values\n\n\t\t\t// but for now we use a simplified placeholder implementation\n\n\n\t\t\tif (registerToFilter >= 0 && registerToFilter < 16)\n\t\t\t{\n\t\t\t\tphysRegCandidates.erase(std::remove(physRegCandidates.begin(), physRegCandidates.end(), (sint32)registerToFilter), physRegCandidates.end());\n\t\t\t\tphysRegCandidates.erase(std::remove(physRegCandidates.begin(), physRegCandidates.end(), (sint32)registerToFilter + 16), physRegCandidates.end());\n\t\t\t}\n\t\t\telse if (registerToFilter >= 16 && registerToFilter < 32)\n\t\t\t{\n\t\t\t\tphysRegCandidates.erase(std::remove(physRegCandidates.begin(), physRegCandidates.end(), (sint32)registerToFilter), physRegCandidates.end());\n\t\t\t\tphysRegCandidates.erase(std::remove(physRegCandidates.begin(), physRegCandidates.end(), (sint32)registerToFilter - 16), physRegCandidates.end());\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t}\n\n\t\tZpIR::ZpIRPhysicalReg extPickPreferredRegister(std::vector<sint32>& physRegCandidates)\n\t\t{\n\t\t\tif (physRegCandidates.empty())\n\t\t\t\tassert_dbg();\n\t\t\treturn physRegCandidates[0];\n\t\t}\n\n\t\tvoid debugPrint(RABlock_t& raBlock)\n\t\t{\n\t\t\tstd::multiset<RALivenessRange_t*, RABlock_t::Compare> sortedRanges;\n\n\t\t\tfor (auto& itr : raBlock.livenessRanges)\n\t\t\t\tsortedRanges.emplace(itr.second);\n\n\t\t\tfor (auto& itr : sortedRanges)\n\t\t\t{\n\t\t\t\tprintf(\"%04x - %04x reg %04d: \", (uint32)(uint16)itr->m_startIndex, (uint32)(uint16)itr->m_endIndex, (uint32)itr->m_irReg);\n\n\t\t\t\tif (itr->m_location == RALivenessRange_t::LOCATION::PHYSICAL_REGISTER)\n\t\t\t\t\tprintf(\"PHYS_REG %d\", (int)itr->m_physicalRegister);\n\t\t\t\telse if (itr->m_location == RALivenessRange_t::LOCATION::UNASSIGNED)\n\t\t\t\t\tprintf(\"UNASSIGNED\");\n\t\t\t\telse\n\t\t\t\t\tassert_dbg();\n\n\t\t\t\tprintf(\"\\n\");\n\t\t\t}\n\t\t}\n\n\t\t// remove all physical registers from physRegCandidates which are already reserved by any of the overlapping ranges\n\t\tvoid filterCandidates(std::vector<sint32>& physRegCandidates, RALivenessRange_t* range)\n\t\t{\n\t\t\tfor (auto& itr : range->m_overlappingRanges)\n\t\t\t{\n\t\t\t\tif (itr->m_location != RALivenessRange_t::LOCATION::PHYSICAL_REGISTER)\n\t\t\t\t\tcontinue;\n\t\t\t\textFilterPhysicalRegisters(physRegCandidates, itr->m_physicalRegister);\n\t\t\t}\n\t\t}\n\n\n\t\tstd::vector<RABlock_t> m_raBlockArray;\n\t};\n\n\n\tclass RegisterAllocatorForGLSL : public ZpIRPass\n\t{\n\t\tenum class PHYS_REG_TYPE : uint8\n\t\t{\n\t\t\tU32 = 0,\n\t\t\tS32 = 1,\n\t\t\tF32 = 2\n\t\t};\n\n\tpublic:\n\t\tRegisterAllocatorForGLSL(ZpIR::ZpIRFunction* irFunction) : ZpIRPass(irFunction) {};\n\n\t\tvoid applyPass()\n\t\t{\n\t\t\tassignPhysicalRegisters();\n\t\t\tm_irFunction->state.registersAllocated = true;\n\t\t}\n\n\t\tstatic bool IsPhysRegTypeU32(ZpIR::ZpIRPhysicalReg physReg)\n\t\t{\n\t\t\treturn ((uint32)physReg >> 30) == (uint32)PHYS_REG_TYPE::U32;\n\t\t}\n\n\t\tstatic bool IsPhysRegTypeS32(ZpIR::ZpIRPhysicalReg physReg)\n\t\t{\n\t\t\treturn ((uint32)physReg >> 30) == (uint32)PHYS_REG_TYPE::S32;\n\t\t}\n\n\t\tstatic bool IsPhysRegTypeF32(ZpIR::ZpIRPhysicalReg physReg)\n\t\t{\n\t\t\treturn ((uint32)physReg >> 30) == (uint32)PHYS_REG_TYPE::F32;\n\t\t}\n\n\t\tstatic uint32 GetPhysRegIndex(ZpIR::ZpIRPhysicalReg physReg)\n\t\t{\n\t\t\treturn (uint32)physReg & 0x3FFFFFFF;\n\t\t}\n\n\t\tstatic std::string DebugPrintHelper_getPhysRegisterName(ZpIR::ZpIRBasicBlock* block, ZpIR::ZpIRPhysicalReg r);\n\n\tprivate:\n\t\tvoid assignPhysicalRegisters();\n\n\t\tvoid assignPhysicalRegistersForBlock(ZpIR::ZpIRBasicBlock* basicBlock);\n\n\t\tuint32 m_physicalRegisterCounterU32{};\n\t\tuint32 m_physicalRegisterCounterS32{};\n\t\tuint32 m_physicalRegisterCounterF32{};\n\n\t\tZpIR::ZpIRPhysicalReg MakePhysReg(PHYS_REG_TYPE regType, uint32 index)\n\t\t{\n\t\t\tuint32 v = (uint32)regType << 30;\n\t\t\tv |= index;\n\t\t\treturn (ZpIR::ZpIRPhysicalReg)v;\n\t\t}\n\t};\n\n};\n"
  },
  {
    "path": "src/util/Zir/Core/ZpIRScheduler.h",
    "content": "#pragma once\n#include \"util/Zir/Core/IR.h\"\n#include \"util/Zir/Core/ZirUtility.h\"\n\n"
  },
  {
    "path": "src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp",
    "content": "#include \"util/Zir/Core/IR.h\"\n#include \"util/Zir/Core/ZirUtility.h\"\n#include \"util/Zir/Core/ZpIRPasses.h\"\n#include \"util/Zir/EmitterGLSL/ZpIREmitGLSL.h\"\n#include \"util/Zir/Core/ZpIRScheduler.h\"\n\n// string buffer helper class which keeps buffer space at the front and end, allow fast prepend and append\nclass DualStringBuffer\n{\n\tstatic constexpr size_t N = 1024;\n\npublic:\n\tDualStringBuffer() : m_offsetBegin(N / 2), m_offsetEnd(N / 2) { }\n\n\t~DualStringBuffer() = default;\n\n\tstatic_assert(sizeof(char) == sizeof(uint8));\n\n\tvoid reset()\n\t{\n\t\tm_offsetBegin = N / 2;\n\t\tm_offsetEnd = m_offsetBegin;\n\t}\n\n\tvoid append(std::string_view strView)\n\t{\n\t\tcemu_assert_debug((m_offsetEnd + strView.size()) <= N);\n\t\tstd::memcpy(m_strBuffer + m_offsetEnd, strView.data(), strView.size());\n\t\tm_offsetEnd += (uint32)strView.size();\n\t}\n\n\ttemplate <typename... Args>\n\tvoid appendFmt(const char* format_str, Args... args)\n\t{\n\t\tchar* buf = (char*)(m_strBuffer + m_offsetEnd);\n\t\tchar* r = fmt::format_to(buf, fmt::runtime(format_str), std::forward<Args>(args)...);\n\t\tcemu_assert_debug(r <= (char*)(m_strBuffer + N));\n\t\tm_offsetEnd += (uint32)(r - buf);\n\t}\n\n\tvoid prepend(std::string_view strView)\n\t{\n\t\tassert_dbg();\n\t}\n\n\tsize_t size() const\n\t{\n\t\treturn m_offsetEnd - m_offsetBegin;\n\t}\n\n\toperator std::string_view()\n\t{\n\t\treturn std::basic_string_view<char>((char*)(m_strBuffer + m_offsetBegin), m_offsetEnd - m_offsetBegin);\n\t}\n\nprivate:\n\t//void resizeBuffer(uint32 spaceRequiredFront, uint32 spaceRequiredBack)\n\t//{\n\t//\tuint32 newTotalSize = spaceRequiredFront + size() + spaceRequiredBack;\n\t//\t// round to next multiple of 32 and add extra buffer\n\t//\tnewTotalSize = (newTotalSize + 31) & ~31;\n\t//\tnewTotalSize += (newTotalSize / 4);\n\t//\t// \n\t//}\n\n\t//uint8* m_bufferPtr{ nullptr };\n\t//size_t m_bufferSize{ 0 };\n\t//std::vector<uint8> m_buffer;\n\tuint32 m_offsetBegin;\n\tuint32 m_offsetEnd;\n\n\tuint8 m_strBuffer[N];\n};\n\n\n\nnamespace ZirEmitter\n{\n\tstatic const char g_idx_to_element[] = { 'x' , 'y', 'z', 'w'};\n\n\tvoid GLSL::Emit(ZpIR::ZpIRFunction* irFunction, StringBuf* output)\n\t{\n\t\tm_irFunction = irFunction;\n\t\tm_glslSource = output;\n\n\t\tcemu_assert_debug(m_irFunction->m_entryBlocks.size() == 1);\n\n\t\tcemu_assert_debug(m_irFunction->m_basicBlocks.size() == 1); // other sizes are todo\n\n\t\tm_glslSource->add(\"void main()\\r\\n{\\r\\n\");\n\t\tGenerateBasicBlockCode(*m_irFunction->m_entryBlocks[0]);\n\t\tm_glslSource->add(\"}\\r\\n\");\n\t}\n\n\tvoid GLSL::GenerateBasicBlockCode(ZpIR::ZpIRBasicBlock& basicBlock)\n\t{\n\t\t// init context\t\t\n#ifdef CEMU_DEBUG_ASSERT\n\t\tfor (auto& itr : m_blockContext.regInlinedExpression)\n\t\t{\n\t\t\tcemu_assert_debug(itr == nullptr); // leaked buffer\n\t\t}\n#endif\n\t\tm_blockContext.regReadTracking.clear();\n\t\tm_blockContext.regReadTracking.resize(basicBlock.m_regs.size());\n\t\tm_blockContext.regInlinedExpression.resize(basicBlock.m_regs.size());\n\n\t\tm_blockContext.currentBasicBlock = &basicBlock;\n\n\t\t// we first do an analysis pass in which we determine the read count for each register\n\t\t// every register which is only consumed once can be directly inlined instead of storing and referencing it via a variable\n\t\tZpIR::IR::__InsBase* instruction = basicBlock.m_instructionFirst;\n\t\twhile (instruction)\n\t\t{\n\t\t\tZpIR::ZpIRCmdUtil::forEachAccessedReg(basicBlock, instruction,\n\t\t\t\t[this](ZpIR::IRReg readReg)\n\t\t\t{\n\t\t\t\tif (readReg >= 0x8000)\n\t\t\t\t\tassert_dbg();\n\t\t\t\t// read access\n\t\t\t\tauto& entry = m_blockContext.regReadTracking.at(readReg);\n\t\t\t\tif (entry < 255)\n\t\t\t\t\tentry++;\n\t\t\t},\n\t\t\t\t[](ZpIR::IRReg writtenReg)\n\t\t\t{\n\t\t\t});\n\n\t\t\tinstruction = instruction->next;\n\t\t}\n\n\t\t// emit GLSL for this block\n\t\tinstruction = basicBlock.m_instructionFirst;\n\t\twhile (instruction)\n\t\t{\n\t\t\tif (auto ins = ZpIR::IR::InsRR::getIfForm(instruction))\n\t\t\t\tHandleInstruction(ins);\n\t\t\telse if (auto ins = ZpIR::IR::InsRRR::getIfForm(instruction))\n\t\t\t\tHandleInstruction(ins);\n\t\t\telse if (auto ins = ZpIR::IR::InsIMPORT::getIfForm(instruction))\n\t\t\t\tHandleInstruction(ins);\n\t\t\telse if (auto ins = ZpIR::IR::InsEXPORT::getIfForm(instruction))\n\t\t\t\tHandleInstruction(ins);\n\t\t\telse\n\t\t\t{\n\t\t\t\tassert_dbg();\n\t\t\t}\n\n\t\t\tinstruction = instruction->next;\n\t\t}\n\t}\n\n\tvoid GLSL::HandleInstruction(ZpIR::IR::InsRR* ins)\n\t{\n\t\tDualStringBuffer* expressionBuf = GetStringBuffer();\n\t\tbool forceNoInline = false;\n\n\t\tswitch (ins->opcode)\n\t\t{\n\t\tcase ZpIR::IR::OpCode::BITCAST:\n\t\t{\n\t\t\tauto srcType = m_blockContext.currentBasicBlock->getRegType(ins->rB);\n\t\t\tauto dstType = m_blockContext.currentBasicBlock->getRegType(ins->rA);\n\n\t\t\tif (srcType == ZpIR::DataType::U32 && dstType == ZpIR::DataType::F32)\n\t\t\t\texpressionBuf->append(\"uintBitsToFloat(\");\n\t\t\telse if (srcType == ZpIR::DataType::S32 && dstType == ZpIR::DataType::F32)\n\t\t\t\texpressionBuf->append(\"intBitsToFloat(\");\n\t\t\telse if (srcType == ZpIR::DataType::F32 && dstType == ZpIR::DataType::U32)\n\t\t\t\texpressionBuf->append(\"floatBitsToUint(\");\n\t\t\telse if (srcType == ZpIR::DataType::F32 && dstType == ZpIR::DataType::S32)\n\t\t\t\texpressionBuf->append(\"floatBitsToInt(\");\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\texpressionBuf->append(\")\");\n\t\t\tbreak;\n\t\t}\n\t\tcase ZpIR::IR::OpCode::SWAP_ENDIAN:\n\t\t{\n\t\t\tauto srcType = m_blockContext.currentBasicBlock->getRegType(ins->rB);\n\t\t\tauto dstType = m_blockContext.currentBasicBlock->getRegType(ins->rA);\n\t\t\tcemu_assert_debug(srcType == dstType);\n\n\t\t\t// todo - should we store expressionBuf in a temporary variable? We reference it multiple times and reducing complexity would be good\n\t\t\tif (srcType == ZpIR::DataType::U32)\n\t\t\t{\n\t\t\t\texpressionBuf->append(\"(((\");\n\t\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\t\texpressionBuf->append(\")>>24)\");\n\n\t\t\t\texpressionBuf->append(\"|\");\n\n\t\t\t\texpressionBuf->append(\"(((\");\n\t\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\t\texpressionBuf->append(\")>>8)&0xFF00)\");\n\n\t\t\t\texpressionBuf->append(\"|\");\n\n\t\t\t\texpressionBuf->append(\"(((\");\n\t\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\t\texpressionBuf->append(\")<<8)&0xFF0000)\");\n\n\t\t\t\texpressionBuf->append(\"|\");\n\n\t\t\t\texpressionBuf->append(\"((\");\n\t\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\t\texpressionBuf->append(\")<<24))\");\n\n\t\t\t\t// (v>>24)|((v>>8)&0xFF00)|((v<<8)&0xFF0000)|((v<<24))\n\t\t\t}\n\t\t\telse\n\t\t\t\tassert_dbg();\n\t\t\tforceNoInline = true; // avoid inlining endian-swapping, since it would add too much complexity to expressions\n\t\t\tbreak;\n\t\t}\n\t\tcase ZpIR::IR::OpCode::MOV:\n\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\tbreak;\n\t\tcase ZpIR::IR::OpCode::CONVERT_FLOAT_TO_INT:\n\t\t{\n\t\t\tauto srcType = m_blockContext.currentBasicBlock->getRegType(ins->rB);\n\t\t\tauto dstType = m_blockContext.currentBasicBlock->getRegType(ins->rA);\n\t\t\tcemu_assert_debug(srcType == ZpIR::DataType::F32);\n\t\t\tcemu_assert_debug(dstType == ZpIR::DataType::S32 || dstType == ZpIR::DataType::U32);\n\t\t\tif(dstType == ZpIR::DataType::U32)\n\t\t\t\texpressionBuf->append(\"uint(\");\n\t\t\telse\n\t\t\t\texpressionBuf->append(\"int(\");\n\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\texpressionBuf->append(\")\");\n\t\t\tbreak;\n\t\t}\n\t\tcase ZpIR::IR::OpCode::CONVERT_INT_TO_FLOAT:\n\t\t{\n\t\t\tauto srcType = m_blockContext.currentBasicBlock->getRegType(ins->rB);\n\t\t\tauto dstType = m_blockContext.currentBasicBlock->getRegType(ins->rA);\n\t\t\tcemu_assert_debug(srcType == ZpIR::DataType::S32 || srcType == ZpIR::DataType::U32);\n\t\t\tcemu_assert_debug(dstType == ZpIR::DataType::F32);\n\t\t\texpressionBuf->append(\"float(\");\n\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\texpressionBuf->append(\")\");\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tassert_dbg();\n\t\t}\n\t\tAssignResult(ins->rA, expressionBuf, forceNoInline);\n\t}\n\n\tvoid GLSL::HandleInstruction(ZpIR::IR::InsRRR* ins)\n\t{\n\t\tDualStringBuffer* expressionBuf = GetStringBuffer();\n\n\t\tswitch (ins->opcode)\n\t\t{\n\t\tcase ZpIR::IR::OpCode::ADD:\n\t\t{\n\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\texpressionBuf->append(\" + \");\n\t\t\tappendSourceString(expressionBuf, ins->rC);\n\t\t\tbreak;\n\t\t}\n\t\tcase ZpIR::IR::OpCode::MUL:\n\t\t{\n\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\texpressionBuf->append(\" * \");\n\t\t\tappendSourceString(expressionBuf, ins->rC);\n\t\t\tbreak;\n\t\t}\n\t\tcase ZpIR::IR::OpCode::DIV:\n\t\t{\n\t\t\tappendSourceString(expressionBuf, ins->rB);\n\t\t\texpressionBuf->append(\" / \");\n\t\t\tappendSourceString(expressionBuf, ins->rC);\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\tassert_dbg();\n\t\t}\n\t\tAssignResult(ins->rA, expressionBuf);\n\t}\n\n\tvoid GLSL::HandleInstruction(ZpIR::IR::InsIMPORT* ins)\n\t{\n\t\tZpIR::ShaderSubset::ShaderImportLocation loc(ins->importSymbol);\n\t\tDualStringBuffer* buf = GetStringBuffer();\n\t\tif (loc.IsUniformRegister())\n\t\t{\n\t\t\tuint16 index;\n\t\t\tloc.GetUniformRegister(index);\n\t\t\t// todo - this is complex. Solve via callback\n\t\t\tbuf->appendFmt(\"uf_remappedVS[{}].{}\", index/4, g_idx_to_element[index&3]);\n\t\t\tAssignResult(ins->regArray[0], buf);\n\t\t}\n\t\telse if (loc.IsVertexAttribute())\n\t\t{\n\t\t\tuint16 attributeIndex;\n\t\t\tuint16 channelIndex;\n\t\t\tloc.GetVertexAttribute(attributeIndex, channelIndex);\n\n\t\t\tcemu_assert_debug(ins->count == 1);\n\t\t\tcemu_assert_debug(ZpIR::isRegVar(ins->regArray[0]));\n\t\t\tcemu_assert_debug(channelIndex < 4);\n\t\t\tcemu_assert_debug(m_blockContext.currentBasicBlock->getRegType(ins->regArray[0]) == ZpIR::DataType::U32);\n\n\t\t\tbuf->appendFmt(\"attrDataSem{}.{}\", attributeIndex, g_idx_to_element[channelIndex]);\n\n\t\t\tAssignResult(ins->regArray[0], buf);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\t}\n\n\tvoid GLSL::HandleInstruction(ZpIR::IR::InsEXPORT* ins)\n\t{\n\t\tZpIR::ShaderSubset::ShaderExportLocation loc(ins->exportSymbol);\n\t\tDualStringBuffer* buf = GetStringBuffer();\n\t\tif (loc.IsPosition())\n\t\t{\n\t\t\t// todo - support for output mask (e.g. xyzw, x_zw) ?\n\t\t\tbuf->append(\"SET_POSITION(vec4(\");\n\t\t\tcemu_assert_debug(ins->count == 4);\n\t\t\tfor (uint32 i = 0; i < ins->count; i++)\n\t\t\t{\n\t\t\t\tif(i > 0)\n\t\t\t\t\tbuf->append(\", \");\n\t\t\t\tappendSourceString(buf, ins->regArray[i]);\n\t\t\t}\n\t\t\tm_glslSource->add(*buf);\n\t\t\tm_glslSource->add(\"));\\r\\n\");\n\t\t}\n\t\telse if (loc.IsOutputAttribute())\n\t\t{\n\t\t\tuint16 attributeIndex;\n\t\t\tloc.GetOutputAttribute(attributeIndex);\n\t\t\tbuf->appendFmt(\"passParameterSem{} = vec4(\", attributeIndex);\n\t\t\tcemu_assert_debug(ins->count == 4);\n\t\t\tfor (uint32 i = 0; i < ins->count; i++)\n\t\t\t{\n\t\t\t\tif (i > 0)\n\t\t\t\t\tbuf->append(\", \");\n\t\t\t\tappendSourceString(buf, ins->regArray[i]);\n\t\t\t}\n\t\t\tm_glslSource->add(*buf);\n\t\t\tm_glslSource->add(\");\\r\\n\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tassert_dbg();\n\t\t}\n\t\tReleaseStringBuffer(buf);\n\t}\n\n\tvoid GLSL::AssignResult(ZpIR::IRReg irReg, DualStringBuffer* buf, bool forceNoInline)\n\t{\n\t\tif (buf->size() > 100)\n\t\t\tforceNoInline = true; // expression too long\n\n\t\tif (m_blockContext.CanInlineRegister(irReg) && !forceNoInline)\n\t\t{\n\t\t\tSetRegInlinedExpression(irReg, buf);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tZpIR::DataType regType = m_blockContext.currentBasicBlock->getRegType(irReg);\n\t\t\tif (regType == ZpIR::DataType::F32)\n\t\t\t\tm_glslSource->add(\"float \");\n\t\t\telse if (regType == ZpIR::DataType::S32)\n\t\t\t\tm_glslSource->add(\"int \");\n\t\t\telse if (regType == ZpIR::DataType::U32)\n\t\t\t\tm_glslSource->add(\"uint \");\n\t\t\telse\n\t\t\t{\n\t\t\t\tcemu_assert_debug(false);\n\t\t\t}\n\n\t\t\tchar regName[16];\n\t\t\tgetRegisterName(regName, irReg);\n\t\t\tm_glslSource->add(regName);\n\t\t\tm_glslSource->add(\" = \");\n\t\t\tm_glslSource->add(*buf);\n\t\t\tm_glslSource->add(\";\\r\\n\");\n\t\t\tReleaseStringBuffer(buf);\n\t\t}\n\t}\n\n\tvoid GLSL::appendSourceString(DualStringBuffer* buf, ZpIR::IRReg irReg)\n\t{\n\t\tif (ZpIR::isConstVar(irReg))\n\t\t{\n\t\t\tZpIR::IRRegConstDef* constDef = m_blockContext.currentBasicBlock->getConstant(irReg);\n\t\t\tif (constDef->type == ZpIR::DataType::U32)\n\t\t\t{\n\t\t\t\tbuf->appendFmt(\"{}\", constDef->value_u32);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (constDef->type == ZpIR::DataType::S32)\n\t\t\t{\n\t\t\t\tbuf->appendFmt(\"{}\", constDef->value_s32);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (constDef->type == ZpIR::DataType::F32)\n\t\t\t{\n\t\t\t\tbuf->appendFmt(\"{}\", constDef->value_f32);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tassert_dbg();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcemu_assert_debug(ZpIR::isRegVar(irReg));\n\t\t\tuint16 regIndex = ZpIR::getRegIndex(irReg);\n\t\t\tDualStringBuffer* expressionBuf = m_blockContext.regInlinedExpression[regIndex];\n\t\t\tif (expressionBuf)\n\t\t\t{\n\t\t\t\tbuf->append(*expressionBuf);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tchar regName[16];\n\t\t\tgetRegisterName(regName, irReg);\n\t\t\tbuf->append(regName);\n\t\t}\n\t}\n\n\tvoid GLSL::getRegisterName(char buf[16], ZpIR::IRReg irReg)\n\t{\n\t\tauto& regData = m_blockContext.currentBasicBlock->m_regs[(uint16)irReg & 0x7FFF];\n\t\tcemu_assert_debug(regData.hasAssignedPhysicalRegister());\n\t\tZpIR::ZpIRPhysicalReg physReg = regData.physicalRegister;\n\n\t\tchar typeChar;\n\t\tif (ZirPass::RegisterAllocatorForGLSL::IsPhysRegTypeF32(physReg))\n\t\t\ttypeChar = 'f';\n\t\telse if (ZirPass::RegisterAllocatorForGLSL::IsPhysRegTypeS32(physReg))\n\t\t\ttypeChar = 'i';\n\t\telse if (ZirPass::RegisterAllocatorForGLSL::IsPhysRegTypeU32(physReg))\n\t\t\ttypeChar = 'u';\n\t\telse\n\t\t{\n\t\t\ttypeChar = 'x';\n\t\t\tcemu_assert_debug(false);\n\t\t}\n\n\t\tauto r = fmt::format_to(buf, \"r{}{}\", ZirPass::RegisterAllocatorForGLSL::GetPhysRegIndex(physReg), typeChar);\n\t\t*r = '\\0';\n\t}\n\n\tvoid GLSL::SetRegInlinedExpression(ZpIR::IRReg irReg, DualStringBuffer* buf)\n\t{\n\t\tcemu_assert_debug(ZpIR::isRegVar(irReg));\n\t\tuint16 dstIndex = (uint16)irReg;\n\t\tif (m_blockContext.regInlinedExpression[dstIndex])\n\t\t\tReleaseStringBuffer(m_blockContext.regInlinedExpression[dstIndex]);\n\t\tm_blockContext.regInlinedExpression[dstIndex] = buf;\n\t}\n\n\tvoid GLSL::ResetRegInlinedExpression(ZpIR::IRReg irReg)\n\t{\n\t\tcemu_assert_debug(ZpIR::isRegVar(irReg));\n\t\tuint16 dstIndex = (uint16)irReg;\n\t\tif (m_blockContext.regInlinedExpression[dstIndex])\n\t\t{\n\t\t\tReleaseStringBuffer(m_blockContext.regInlinedExpression[dstIndex]);\n\t\t\tm_blockContext.regInlinedExpression[dstIndex] = nullptr;\n\t\t}\n\t}\n\n\tDualStringBuffer* GLSL::GetRegInlinedExpression(ZpIR::IRReg irReg)\n\t{\n\t\tcemu_assert_debug(ZpIR::isRegVar(irReg));\n\t\tuint16 dstIndex = (uint16)irReg;\n\t\treturn m_blockContext.regInlinedExpression[dstIndex];\n\t}\n\n\tDualStringBuffer* GLSL::GetStringBuffer()\n\t{\n\t\tif (m_stringBufferCache.empty())\n\t\t\treturn new DualStringBuffer();\n\t\tDualStringBuffer* buf = m_stringBufferCache.back();\n\t\tm_stringBufferCache.pop_back();\n\t\tbuf->reset();\n\t\treturn buf;\n\t}\n\n\tvoid GLSL::ReleaseStringBuffer(DualStringBuffer* buf)\n\t{\n\t\tm_stringBufferCache.emplace_back(buf);\n\t}\n};\n"
  },
  {
    "path": "src/util/Zir/EmitterGLSL/ZpIREmitGLSL.h",
    "content": "#pragma once\n#include \"util/Zir/Core/IR.h\"\n#include \"util/Zir/Core/ZpIRPasses.h\"\n#include \"util/helpers/StringBuf.h\"\n\nclass DualStringBuffer;\n\nnamespace ZirEmitter\n{\n\tclass GLSL\n\t{\n\tpublic:\n\t\tGLSL() {};\n\n\t\t// emit function code and append to output string buffer\n\t\tvoid Emit(ZpIR::ZpIRFunction* irFunction, StringBuf* output);\n\n\tprivate:\n\t\tvoid GenerateBasicBlockCode(ZpIR::ZpIRBasicBlock& basicBlock);\n\n\t\tvoid HandleInstruction(ZpIR::IR::InsRR* ins);\n\t\tvoid HandleInstruction(ZpIR::IR::InsRRR* ins);\n\t\tvoid HandleInstruction(ZpIR::IR::InsIMPORT* ins);\n\t\tvoid HandleInstruction(ZpIR::IR::InsEXPORT* ins);\n\n\t\tvoid appendSourceString(DualStringBuffer* buf, ZpIR::IRReg irReg);\n\t\tvoid getRegisterName(char buf[16], ZpIR::IRReg irReg);\n\n\tprivate:\n\t\tZpIR::ZpIRFunction* m_irFunction{};\n\t\tStringBuf* m_glslSource{};\n\n\t\tstruct \n\t\t{\n\t\t\tZpIR::ZpIRBasicBlock* currentBasicBlock{ nullptr };\n\t\t\tstd::vector<uint8> regReadTracking;\n\t\t\tstd::vector<DualStringBuffer*> regInlinedExpression;\n\n\t\t\tbool CanInlineRegister(ZpIR::IRReg reg) const \n\t\t\t{\n\t\t\t\tcemu_assert_debug(ZpIR::isRegVar(reg));\n\t\t\t\treturn regReadTracking[ZpIR::getRegIndex(reg)] <= 1;\n\t\t\t};\n\t\t}m_blockContext;\n\n\t\tvoid AssignResult(ZpIR::IRReg irReg, DualStringBuffer* buf, bool forceNoInline = false);\n\n\t\t// inlined expression cache\n\t\tvoid SetRegInlinedExpression(ZpIR::IRReg irReg, DualStringBuffer* buf);\n\t\tvoid ResetRegInlinedExpression(ZpIR::IRReg irReg);\n\t\tDualStringBuffer* GetRegInlinedExpression(ZpIR::IRReg irReg);\n\n\t\t// memory pool for StringBuffer\n\t\tDualStringBuffer* GetStringBuffer();\n\t\tvoid ReleaseStringBuffer(DualStringBuffer* buf);\n\n\t\tstd::vector<DualStringBuffer*> m_stringBufferCache;\n\t};\n\n}"
  },
  {
    "path": "src/util/Zir/Passes/RegisterAllocatorForGLSL.cpp",
    "content": "#include \"util/Zir/Core/IR.h\"\n#include \"util/Zir/Core/ZirUtility.h\"\n#include \"util/Zir/Core/ZpIRPasses.h\"\n#include \"util/Zir/Core/ZpIRDebug.h\"\n\nnamespace ZirPass\n{\n\n\tvoid RegisterAllocatorForGLSL::assignPhysicalRegisters()\n\t{\n\t\tif (m_irFunction->m_basicBlocks.size() != 1)\n\t\t\tcemu_assert_unimplemented();\n\n\t\tfor (auto& itr : m_irFunction->m_basicBlocks)\n\t\t\tassignPhysicalRegistersForBlock(itr);\n\t}\n\n\tvoid RegisterAllocatorForGLSL::assignPhysicalRegistersForBlock(ZpIR::ZpIRBasicBlock* basicBlock)\n\t{\n\t\t// resolve imports\n\t\tfor (auto& itr : basicBlock->m_imports)\n\t\t{\n\t\t\tassert_dbg(); // todo - If imported reg not assigned physical register yet -> create a shared physical register (MSB set in reg index?) And assign it to this basic block but also all the shared IRRegs in the other linked basic blocks\n\t\t\t// how to handle import:\n\t\t\t// - match physical register of every input/output\n\t\t\t// - every import must have a matching export in all the previous basic blocks. If not all match this is an error.\n\t\t\t//   In our shader emitter this could happen if the original R600 code references an uninitialized register\n\n\t\t\t// note - we also have to make sure the register type matches. If a linked block has a shared register with a different type then we need to create a new register and insert a bitcast instruction in that block\n\t\t}\n\t\t// assign a register index to every virtual register\n\t\tfor (auto& itr : basicBlock->m_regs)\n\t\t{\n\t\t\tif (itr.type != ZpIR::DataType::NONE && !itr.hasAssignedPhysicalRegister())\n\t\t\t{\n\t\t\t\tif (itr.type == ZpIR::DataType::F32)\n\t\t\t\t\titr.assignPhysicalRegister(MakePhysReg(PHYS_REG_TYPE::F32, m_physicalRegisterCounterF32++));\n\t\t\t\telse if (itr.type == ZpIR::DataType::S32)\n\t\t\t\t\titr.assignPhysicalRegister(MakePhysReg(PHYS_REG_TYPE::S32, m_physicalRegisterCounterS32++));\n\t\t\t\telse if (itr.type == ZpIR::DataType::U32)\n\t\t\t\t\titr.assignPhysicalRegister(MakePhysReg(PHYS_REG_TYPE::U32, m_physicalRegisterCounterU32++));\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcemu_assert_debug(false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tstd::string RegisterAllocatorForGLSL::DebugPrintHelper_getPhysRegisterName(ZpIR::ZpIRBasicBlock* block, ZpIR::ZpIRPhysicalReg r)\n\t{\n\t\tstd::string s;\n\t\tuint32 regIndex = GetPhysRegIndex(r);\n\n\t\tif (IsPhysRegTypeF32(r))\n\t\t\ts = fmt::format(\"r{}f\", regIndex);\n\t\telse if (IsPhysRegTypeU32(r))\n\t\t\ts = fmt::format(\"r{}u\", regIndex);\n\t\telse if (IsPhysRegTypeS32(r))\n\t\t\ts = fmt::format(\"r{}i\", regIndex);\n\t\treturn s;\n\t}\n\n}"
  },
  {
    "path": "src/util/Zir/Passes/ZpIRRegisterAllocator.cpp",
    "content": "#include \"util/Zir/Core/IR.h\"\n#include \"util/Zir/Core/ZirUtility.h\"\n#include \"util/Zir/Core/ZpIRPasses.h\"\n#include \"util/Zir/Core/ZpIRDebug.h\"\n\nnamespace ZirPass\n{\n\tusing namespace ZpIR;\n\n\t/*\n\t   Algorithm description:\n\n\t   Prepare phase:\n\t    Assign every basic block an index\n\t\tCreate internal arrays to match index count\n\n\t   First phase:\n\t\tCreate liveness ranges for each basic block\n\t\tLink liveness ranges by import/export\n\t\tConstrained instructions split affected ranges into their own single instruction liveness range\n\n\t   Second phase:\n \t\tAssign registers. Start with constrained ranges first, then process from beginning to end\n\t\tWhenever we assign a register to a range, we also try to propagate it to all the connected/coalesced ranges\n\n\t\n\t\tA liveness range is described by:\n\t\t- Source (Can be any of: List of previous basic blocks, liveness range in same basic block)\n\t\t- Destination (list of liveness ranges)\n\t\t- Index of basic block\n\t\t- First instruction (where register is assigned, -1 if passed from previous block)\n\t\t- Last instruction (where register is last accessed)\n\t\t- IR-Register (within the same basic block)\n\t\tDuring algorithm:\n\t\t- Spillcost (probably can calculate this dynamically)\n\t\t- Physical location (-1 if not assigned. Otherwise register index or spill memory offset)\n\n\t*/\n\n\tRALivenessRange_t::RALivenessRange_t(RABlock_t* block, IRReg irReg, sint32 start, sint32 end, DataType irDataType) : m_block(block), m_irReg(irReg), m_irDataType(irDataType)\n\t{\n\t\tblock->livenessRanges.emplace(irReg, this);\n\t\tm_startIndex = start;\n\t\tm_endIndex = end;\n\t\t// register\n\t\tfor (auto& itr : block->livenessRanges)\n\t\t{\n\t\t\tRALivenessRange_t* itrRange = itr.second;\n\t\t\tif (start < itrRange->m_endIndex && end >= itrRange->m_startIndex)\n\t\t\t{\n\t\t\t\tm_overlappingRanges.emplace_back(itrRange);\n\t\t\t\titrRange->m_overlappingRanges.emplace_back(this);\n\t\t\t\t// todo - also immediately flag physical registers as unavailable\n\t\t\t}\n\t\t}\n\t\tblock->unassignedRanges.emplace(this);\n\t}\n\n\tRALivenessRange_t::~RALivenessRange_t()\n\t{\n\t\tfor (auto& itr : m_overlappingRanges)\n\t\t{\n\t\t\tRALivenessRange_t* overlappedRange = itr;\n\t\t\t// todo - unflag physical register (if this has one set)\n\t\t\toverlappedRange->m_overlappingRanges.erase(std::remove(overlappedRange->m_overlappingRanges.begin(), overlappedRange->m_overlappingRanges.end(), overlappedRange), overlappedRange->m_overlappingRanges.end());\n\t\t}\n\t\tm_overlappingRanges.clear();\n\t\tassert_dbg();\n\t}\n\n\n\tvoid RALivenessRange_t::setStart(sint32 startIndex)\n\t{\n\t\tm_startIndex = startIndex;\n\t\tassert_dbg(); // re-register in sorted range list (if no reg assigned)\n\t}\n\n\tvoid RALivenessRange_t::setEnd(sint32 endIndex)\n\t{\n\t\tif (endIndex > m_endIndex)\n\t\t{\n\t\t\t// add ranges that are now overlapping\n\t\t\tfor (auto& itr : m_block->livenessRanges)\n\t\t\t{\n\t\t\t\tRALivenessRange_t* itrRange = itr.second;\n\t\t\t\tif(itrRange->isOverlapping(this))\n\t\t\t\t\tcontinue; // was overlapping before\n\t\t\t\tif(itrRange == this)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (itrRange->isOverlapping(m_startIndex, endIndex))\n\t\t\t\t{\n\t\t\t\t\tm_overlappingRanges.emplace_back(itrRange);\n\t\t\t\t\titrRange->m_overlappingRanges.emplace_back(this);\n\t\t\t\t\t// todo - also immediately flag physical registers as unavailable\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (endIndex < m_endIndex)\n\t\t{\n\t\t\t// remove ranges that are no longer overlapping\n\t\t\tcemu_assert_suspicious();\n\t\t}\n\t\tm_endIndex = endIndex;\n\t}\n\n\tvoid RALivenessRange_t::assignPhysicalRegister(ZpIRPhysicalReg physReg)\n\t{\n\t\tif (m_location != LOCATION::UNASSIGNED)\n\t\t\tcemu_assert_suspicious();\n\t\tm_location = LOCATION::PHYSICAL_REGISTER;\n\t\tm_physicalRegister = physReg;\n\t\t// remove this from unassignedRanges\n\t\tauto itr = m_block->unassignedRanges.find(this);\n\t\tif (itr == m_block->unassignedRanges.end())\n\t\t\tcemu_assert_suspicious();\n\t\tif (*itr != this)\n\t\t\tcemu_assert_suspicious();\n\t\tm_block->unassignedRanges.erase(itr);\n\t}\n\n\n\tvoid RARegular::prepareRABlocks()\n\t{\n\t\tauto& irBasicBlocks = m_irFunction->m_basicBlocks;\n\n\t\tm_raBlockArray.resize(m_irFunction->m_basicBlocks.size());\n\t}\n\n\tvoid RARegular::generateLivenessRanges()\n\t{\n\t\tauto& irBasicBlocks = m_irFunction->m_basicBlocks;\n\t\t//for (auto& itr : irBasicBlocks)\n\t\tfor (uint32 basicBlockIndex = 0; basicBlockIndex < (uint32)irBasicBlocks.size(); basicBlockIndex++)\n\t\t{\n\t\t\tauto& blockItr = irBasicBlocks[basicBlockIndex];\n\t\t\tRABlock_t* raBlock = m_raBlockArray.data() + basicBlockIndex;\n\t\t\tstd::unordered_map<IRReg, RALivenessRange_t*>& blockRanges = raBlock->livenessRanges;\n\t\t\t// init ranges for imports first\n\t\t\tfor (auto& regImport : blockItr->m_imports)\n\t\t\t{\n\t\t\t\tnew RALivenessRange_t(raBlock, regImport.reg, -1, -1, blockItr->m_regs[(uint16)regImport.reg].type);\n\t\t\t\t// imports start before the current basic block\n\t\t\t}\n\t\t\t// parse instructions and create/update ranges\n\t\t\tIR::__InsBase* ins = blockItr->m_instructionFirst;\n\t\t\tsize_t i = 0;\n\t\t\twhile(ins)\n\t\t\t{\n\t\t\t\tZpIRCmdUtil::forEachAccessedReg(*blockItr, ins,\n\t\t\t\t\t[&blockRanges, i, raBlock](IRReg readReg)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (readReg >= 0x8000)\n\t\t\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\t\t\t// read access\n\t\t\t\t\t\tauto livenessRange = blockRanges.find(readReg);\n\t\t\t\t\t\tif (livenessRange == blockRanges.end())\n\t\t\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\t\t\tlivenessRange->second->setEnd((sint32)i);\n\t\t\t\t\t},\n\t\t\t\t\t[&blockRanges, i, raBlock, blockItr](IRReg writtenReg)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (writtenReg >= 0x8000)\n\t\t\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\t\t\t// write access\n\t\t\t\t\t\tauto livenessRange = blockRanges.find(writtenReg);\n\t\t\t\t\t\tif (livenessRange != blockRanges.end())\n\t\t\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\t\t\tnew RALivenessRange_t(raBlock, writtenReg, (sint32)i, (sint32)i, blockItr->m_regs[(uint16)writtenReg].type);\n\t\t\t\t\t});\n\t\t\t\ti++;\n\t\t\t\tins = ins->next;\n\t\t\t}\n\t\t\t// exports extend ranges to one instruction past the end of the block\n\t\t\tfor (auto& regExport : blockItr->m_exports)\n\t\t\t{\n\t\t\t\tauto livenessRange = blockRanges.find(regExport.reg);\n\t\t\t\tif (livenessRange == blockRanges.end())\n\t\t\t\t\tcemu_assert_suspicious();\n\t\t\t\tcemu_assert_unimplemented();\n\t\t\t\t//livenessRange->second->setEnd((sint32)blockItr->m_cmdsDepr.size());\n\t\t\t}\n\t\t}\n\t\t// connect liveness ranges across basic blocks based on their import/export names\n\t\tstd::unordered_map<LocationSymbolName, RALivenessRange_t*> listExportedRanges;\n\t\tfor (uint32 basicBlockIndex = 0; basicBlockIndex < (uint32)irBasicBlocks.size(); basicBlockIndex++)\n\t\t{\n\t\t\t// for each block take all exported ranges and connect them to the imports of the successor blocks\n\t\t\tauto& blockItr = irBasicBlocks[basicBlockIndex];\n\t\t\t// collect all exported liveness ranges\n\t\t\tstd::unordered_map<IRReg, RALivenessRange_t*>& localRanges = m_raBlockArray[basicBlockIndex].livenessRanges;\n\t\t\tlistExportedRanges.clear();\n\t\t\tfor (auto& regExport : blockItr->m_exports)\n\t\t\t{\n\t\t\t\tauto livenessRange = localRanges.find(regExport.reg);\n\t\t\t\tif (livenessRange == localRanges.end())\n\t\t\t\t\tassert_dbg();\n\t\t\t\tlistExportedRanges.emplace(regExport.name, livenessRange->second);\n\t\t\t}\n\t\t\t// handle imports in the connected blocks\n\t\t\tif (blockItr->m_branchTaken)\n\t\t\t{\n\t\t\t\tZpIRBasicBlock* successorBlock = blockItr->m_branchTaken;\n\t\t\t\tstd::unordered_map<IRReg, RALivenessRange_t*>& successorRanges = localRanges = m_raBlockArray[basicBlockIndex].livenessRanges;\n\t\t\t\tfor (auto& regImport : successorBlock->m_exports)\n\t\t\t\t{\n\t\t\t\t\tauto livenessRange = successorRanges.find(regImport.reg);\n\t\t\t\t\tif (livenessRange == successorRanges.end())\n\t\t\t\t\t\tassert_dbg();\n\t\t\t\t\tauto connectedSourceRange = listExportedRanges.find(regImport.name);\n\t\t\t\t\tif (connectedSourceRange == listExportedRanges.end())\n\t\t\t\t\t\tassert_dbg();\n\t\t\t\t\tlivenessRange->second->addSourceFromPreviousBlock(connectedSourceRange->second);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// handle imports for entry blocks\n\t\t\t// todo\n\t\t\t// handle export for exit blocks\n\t\t\t// todo\n\t\t}\n\t}\n\n\tvoid RARegular::assignPhysicalRegistersForBlock(RABlock_t& raBlock)\n\t{\n\t\tdebugPrint(raBlock);\n\t\tstd::vector<sint32> physRegCandidates;\n\t\tphysRegCandidates.reserve(32);\n\t\t// process livenessRanges ascending by start address\n\t\twhile (!raBlock.unassignedRanges.empty())\n\t\t{\n\t\t\tRALivenessRange_t* range = *raBlock.unassignedRanges.begin();\n\t\t\t// get a list of potential physical registers\n\t\t\tstd::span<sint32> physReg = extGetSuitablePhysicalRegisters(range->m_irDataType);\n\n\t\t\tphysRegCandidates.clear();\n\t\t\tfor (auto& r : physReg)\n\t\t\t\tphysRegCandidates.emplace_back(r);\n\n\t\t\t// try to find a physical register that we can assign to the entire liveness span (current range and all connected ranges)\n\t\t\t// todo\n\t\t\t// handle special cases like copy coalescing\n\t\t\t// todo\n\t\t\t// try to find a register for only the current range\n\n\t\t\tfilterCandidates(physRegCandidates, range);\n\t\t\tif (!physRegCandidates.empty())\n\t\t\t{\n\t\t\t\t// pick preferred register\n\t\t\t\tZpIRPhysicalReg physRegister = extPickPreferredRegister(physRegCandidates);\n\t\t\t\trange->assignPhysicalRegister(physRegister);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// spill is necessary\n\t\t\tassert_dbg();\n\n\n\t\t\tassert_dbg();\n\n\t\t}\n\n\t\tprintf(\"Assigned:\\n\");\n\t\tdebugPrint(raBlock);\n\t}\n\n\tvoid RARegular::assignPhysicalRegisters()\n\t{\n\t\t// todo - first we should assign all the fixed registers. E.g. imports/exports, constrained instructions\n\n\t\tfor (auto& raBlockInfo : m_raBlockArray)\n\t\t\tassignPhysicalRegistersForBlock(raBlockInfo);\n\t}\n\n\tvoid RARegular::rewrite()\n\t{\n\t\tfor (size_t i = 0; i < m_raBlockArray.size(); i++)\n\t\t\trewriteBlock(*m_irFunction->m_basicBlocks[i], m_raBlockArray[i]);\n\t}\n\n\tvoid RARegular::rewriteBlock(ZpIRBasicBlock& basicBlock, RABlock_t& raBlock)\n\t{\n\t\tassert_dbg();\n\t\t//std::vector<ZpIRCmd> cmdOut;\n\n\t\t//std::unordered_map<ZpIRReg, ZpIRReg> translationTable;\n\t\t//for (auto& itr : raBlock.livenessRanges)\n\t\t//\ttranslationTable.emplace(itr.second->m_irReg, itr.second->m_physicalRegister);\n\t\t//// todo - since ir var registers are created in incremental order we could instead use a std::vector for fast look-up instead of a map?\n\n\t\t//for (uint32 i = 0; i < (uint32)basicBlock.m_cmdsDepr.size(); i++)\n\t\t//{\n\t\t//\t// todo - insert spill and load instructions\n\t\t//\t// todo - insert register moves for range-to-range copies\n\t\t//\t\n\t\t//\tZpIRCmd* currentCmd = basicBlock.m_cmdsDepr.data() + i;\n\t\t//\t// replace registers and then insert into output command list\n\t\t//\tZpIRCmdUtil::replaceRegisters(*currentCmd, translationTable);\n\t\t//\tcmdOut.emplace_back(*currentCmd);\n\t\t//}\n\n\t\t//basicBlock.m_cmdsDepr = std::move(cmdOut);\n\n\t\t// todo - should we keep imports/exports but update them to use physical register indices?\n\t\t//        the code emitter needs to know which physical registers are exported in order to determine which optimizations are allowed\n\n\t\tbasicBlock.m_imports.clear();\n\t\tbasicBlock.m_imports.shrink_to_fit();\n\t\tbasicBlock.m_exports.clear();\n\t\tbasicBlock.m_exports.shrink_to_fit();\n\t\tbasicBlock.m_regs.clear();\n\t\tbasicBlock.m_regs.shrink_to_fit();\n\t}\n\n}\n"
  },
  {
    "path": "src/util/boost/bluetooth.h",
    "content": "#pragma once\n\n#include \"platform/platform.h\"\n\n#include <boost/asio.hpp>\n\nnamespace boost\n{\n\tnamespace asio\n\t{\n\t\ttemplate <typename Protocol>\n\t\tclass device_endpoint\n\t\t{\n\t\tpublic:\n\t\t\ttypedef Protocol protocol_type;\n\t\t\ttypedef detail::socket_addr_type data_type;\n\n\t\t\tstruct device_t\n\t\t\t{\n\t\t\t\tdevice_t(long long device_addr)\n\t\t\t\t\t: addr(device_addr)\n\t\t\t\t{\n\t\t\t\t}\n\n\t\t\t\tlong long addr;\n\t\t\t};\n\n\t\t\tdevice_endpoint()\n\t\t\t{\n\t\t\t\tmemset(&addr, 0x00, sizeof(addr));\n\t\t\t}\n\n\t\t\tdevice_endpoint(device_t device_address)\n\t\t\t{\n\t\t\t\tmemset(&addr, 0x00, sizeof(addr));\n\n\t\t\t\taddr.addressFamily = AF_BLUETOOTH;\n\t\t\t\taddr.btAddr = id.addr;\n\t\t\t\taddr.serviceClassId = RFCOMM_PROTOCOL_UUID;\n\t\t\t\taddr.port = BT_PORT_ANY;\n\t\t\t}\n\n\t\t\tdevice_endpoint(const device_endpoint& other)\n\t\t\t\t: addr(other.addr)\n\t\t\t{\n\t\t\t}\n\n\t\t\tdevice_endpoint& operator=(const device_endpoint& other)\n\t\t\t{\n\t\t\t\taddr = other.addr;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tprotocol_type protocol() const\n\t\t\t{\n\t\t\t\treturn protocol_type();\n\t\t\t}\n\n\t\t\tdata_type* data()\n\t\t\t{\n\t\t\t\treturn reinterpret_cast<data_type*>(&addr);\n\t\t\t}\n\n\t\t\tconst data_type* data() const\n\t\t\t{\n\t\t\t\treturn reinterpret_cast<const data_type*>(&addr);\n\t\t\t}\n\n\t\t\tsize_t size() const\n\t\t\t{\n\t\t\t\treturn sizeof(SOCKADDR_BTH);\n\t\t\t}\n\n\t\t\tsize_t capacity() const\n\t\t\t{\n\t\t\t\treturn size();\n\t\t\t}\n\n\t\tprivate:\n\t\t\tSOCKADDR_BTH addr;\n\t\t};\n\n\t\tclass bluetooth\n\t\t{\n\t\tpublic:\n\t\t\tusing endpoint = device_endpoint<bluetooth>;\n\t\t\tusing socket = basic_stream_socket<bluetooth>;\n\t\t\tusing acceptor = basic_socket_acceptor<bluetooth>;\n\t\t\tusing iostream = basic_socket_iostream<bluetooth>;\n\n\t\t\tbluetooth() = default;\n\n\t\t\tint type() const\n\t\t\t{\n\t\t\t\treturn SOCK_STREAM;\n\t\t\t}\n\n\t\t\tint protocol() const\n\t\t\t{\n\t\t\t\treturn BTPROTO_RFCOMM;\n\t\t\t}\n\n\t\t\tint family() const\n\t\t\t{\n\t\t\t\treturn AF_BLUETOOTH;\n\t\t\t}\n\t\t};\n\t}\n}\n"
  },
  {
    "path": "src/util/bootSound/BootSoundReader.cpp",
    "content": "#include \"BootSoundReader.h\"\n#include \"Cafe/CafeSystem.h\"\n\nBootSoundReader::BootSoundReader(FSCVirtualFile* bootsndFile, sint32 blockSize) : bootsndFile(bootsndFile), blockSize(blockSize)\n{\n\t// crash if this constructor is invoked with a blockSize that has a different number of samples per channel\n\tcemu_assert(blockSize % (sizeof(sint16be) * 2) == 0);\n\n\tfsc_setFileSeek(bootsndFile, 0);\n\tfsc_readFile(bootsndFile, &muteBits, 4);\n\tfsc_readFile(bootsndFile, &loopPoint, 4);\n\n\tbuffer.resize(blockSize / sizeof(sint16));\n\tbufferBE.resize(blockSize / sizeof(sint16be));\n\n\t// workaround: SM3DW has incorrect loop point\n\tconst auto titleId = CafeSystem::GetForegroundTitleId();\n\tif(titleId == 0x0005000010145D00 || titleId == 0x0005000010145C00 || titleId == 0x0005000010106100)\n\t\tloopPoint = 113074;\n}\n\nsint16* BootSoundReader::getSamples()\n{\n\tsize_t totalRead = 0;\n\tconst size_t loopPointOffset = 8 + loopPoint * 4;\n\twhile (totalRead < blockSize)\n\t{\n\t\tauto read = fsc_readFile(bootsndFile, bufferBE.data(), blockSize - totalRead);\n\t\tif (read == 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"failed to read PCM samples from bootSound.btsnd\");\n\t\t\treturn nullptr;\n\t\t}\n\t\tif (read % (sizeof(sint16be) * 2) != 0)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"failed to play bootSound.btsnd: reading PCM data stopped at an odd number of samples (is the file corrupt?)\");\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tstd::copy_n(bufferBE.begin(), read / sizeof(sint16be), buffer.begin() + (totalRead / sizeof(sint16)));\n\t\ttotalRead += read;\n\t\tif (totalRead < blockSize)\n\t\t\tfsc_setFileSeek(bootsndFile, loopPointOffset);\n\t}\n\n\t// handle case where the end of a block of samples lines up with the end of the file\n\tif(fsc_getFileSeek(bootsndFile) == fsc_getFileSize(bootsndFile))\n\t\tfsc_setFileSeek(bootsndFile, loopPointOffset);\n\n\treturn buffer.data();\n}\n"
  },
  {
    "path": "src/util/bootSound/BootSoundReader.h",
    "content": "#pragma once\n#include \"Cafe/Filesystem/fsc.h\"\n\nclass BootSoundReader\n{\n  public:\n\tBootSoundReader() = delete;\n\tBootSoundReader(FSCVirtualFile* bootsndFile, sint32 blockSize);\n\n\tsint16* getSamples();\n\n  private:\n\tFSCVirtualFile* bootsndFile{};\n\tsint32 blockSize{};\n\n\tuint32be muteBits{};\n\tuint32be loopPoint{};\n\tstd::vector<sint16> buffer{};\n\tstd::vector<sint16be> bufferBE{};\n};\n"
  },
  {
    "path": "src/util/containers/IntervalBucketContainer.h",
    "content": "#pragma once\n\ntemplate<typename TData, typename TAddr, TAddr TAddressGranularity, int TBucketCount>\nclass IntervalBucketContainer\n{\n\tstruct bucketEntry_t\n\t{\n\t\tTAddr rangeStart;\n\t\tTAddr rangeEnd;\n\t\tTData* data;\n\t\tint bucketStartIndex;\n\t\tbucketEntry_t(TAddr rangeStart, TAddr rangeEnd, TData* data, int bucketStartIndex) : rangeStart(rangeStart), rangeEnd(rangeEnd), data(data), bucketStartIndex(bucketStartIndex) {};\n\t};\n\tstd::vector<bucketEntry_t> list_bucket[TBucketCount];\n\npublic:\n\n\tIntervalBucketContainer() = default;\n\n\t// range is defined as inclusive rangeStart and exclusive rangeEnd\n\tvoid addRange(TAddr rangeStart, TAddr rangeEnd, TData* data)\n\t{\n\t\tassert(rangeStart < rangeEnd);\n\t\tint bucketStartIndex = (rangeStart / TAddressGranularity);\n\t\tint bucketEndIndex = ((rangeEnd + TAddressGranularity - 1) / TAddressGranularity);\n\t\tint bucketItrCount = bucketEndIndex - bucketStartIndex;\n\t\tbucketStartIndex %= TBucketCount;\n\t\tint bucketFirstIndex = bucketStartIndex;\n\t\tbucketItrCount = std::min(bucketItrCount, TBucketCount);\n\t\tassert(bucketItrCount != 0);\n\t\twhile (bucketItrCount--)\n\t\t{\n\t\t\tlist_bucket[bucketStartIndex].emplace_back(rangeStart, rangeEnd, data, bucketFirstIndex);\n\t\t\tbucketStartIndex = (bucketStartIndex + 1) % TBucketCount;\n\t\t}\n\t}\n\n\tvoid removeRange(TAddr rangeStart, TAddr rangeEnd, TData* data)\n\t{\n\t\tassert(rangeStart < rangeEnd);\n\t\tint bucketStartIndex = (rangeStart / TAddressGranularity);\n\t\tint bucketEndIndex = ((rangeEnd + TAddressGranularity - 1) / TAddressGranularity);\n\t\tint bucketItrCount = bucketEndIndex - bucketStartIndex;\n\t\tbucketStartIndex %= TBucketCount;\n\t\tbucketItrCount = std::min(bucketItrCount, TBucketCount);\n\t\tassert(bucketItrCount != 0);\n\t\tint eraseCountVerifier = bucketItrCount;\n\t\twhile (bucketItrCount--)\n\t\t{\n\t\t\tfor (auto it = list_bucket[bucketStartIndex].begin(); it != list_bucket[bucketStartIndex].end(); it++)\n\t\t\t{\n\t\t\t\tif (it->data == data)\n\t\t\t\t{\n\t\t\t\t\tassert(it->rangeStart == rangeStart && it->rangeEnd == rangeEnd);\n\t\t\t\t\t// erase\n\t\t\t\t\tlist_bucket[bucketStartIndex].erase(it);\n\t\t\t\t\teraseCountVerifier--;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbucketStartIndex = (bucketStartIndex + 1) % TBucketCount;\n\t\t}\n\t\tassert(eraseCountVerifier == 0); // triggers if rangeStart/End doesn't match up with any registered range\n\t}\n\n\ttemplate<typename TRangeCallback>\n\tvoid lookupRanges(TAddr rangeStart, TAddr rangeEnd, TRangeCallback cb)\n\t{\n\t\tassert(rangeStart < rangeEnd);\n\t\tint bucketStartIndex = (rangeStart / TAddressGranularity);\n\t\tint bucketEndIndex = ((rangeEnd + TAddressGranularity - 1) / TAddressGranularity);\n\t\tint bucketItrCount = bucketEndIndex - bucketStartIndex;\n\t\tbucketStartIndex %= TBucketCount;\n\t\tbucketItrCount = std::min(bucketItrCount, TBucketCount);\n\t\tassert(bucketItrCount != 0);\n\t\t// in first round we dont need to check if bucket was already visited\n\t\tfor (auto& itr : list_bucket[bucketStartIndex])\n\t\t{\n\t\t\tif (itr.rangeStart < rangeEnd && itr.rangeEnd > rangeStart)\n\t\t\t{\n\t\t\t\tcb(itr.data);\n\t\t\t}\n\t\t}\n\t\tbucketItrCount--;\n\t\tbucketStartIndex = (bucketStartIndex + 1) % TBucketCount;\n\t\t// for remaining buckets check if the range starts in the current bucket\n\t\twhile (bucketItrCount--)\n\t\t{\n\t\t\tfor (auto& itr : list_bucket[bucketStartIndex])\n\t\t\t{\n\t\t\t\tif (itr.rangeStart < rangeEnd && itr.rangeEnd > rangeStart && itr.bucketStartIndex == bucketStartIndex)\n\t\t\t\t{\n\t\t\t\t\tcb(itr.data);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbucketStartIndex = (bucketStartIndex + 1) % TBucketCount;\n\t\t}\n\t}\n\n};"
  },
  {
    "path": "src/util/containers/LookupTableL3.h",
    "content": "#pragma once\n\n// staged lookup table suited for cases where the lookup index range can be very large (e.g. memory addresses)\n// performs 3 consecutive table lookups, where each table's width is defined by TBitsN\n// empty subtables consume no memory beyond the initial two default tables for TBitsY and TBitsZ\ntemplate<int TBitsX, int TBitsY, int TBitsZ, typename T>\nclass LookupTableL3\n{\n\tstruct TableZ // z lookup\n\t{\n\t\tT arr[1 << TBitsZ]{};\n\t};\n\n\tstruct TableY // y lookup\n\t{\n\t\tTableZ* arr[1 << TBitsY];\n\t};\n\n\t// by generating placeholder tables we can avoid conditionals in the lookup code since no null-pointer checking is necessary\n\tTableY* m_placeholderTableY{};\n\tTableZ* m_placeholderTableZ{};\n\n\npublic:\n\tLookupTableL3()\n\t{\n\t\t// init placeholder table Z\n\t\tm_placeholderTableZ = GenerateNewTableZ();\n\t\t// init placeholder table Y (all entries point to placeholder table Z)\n\t\tm_placeholderTableY = GenerateNewTableY();\n\t\t// init x table\n\t\tfor (auto& itr : m_tableXArr)\n\t\t\titr = m_placeholderTableY;\n\t}\n\n\t~LookupTableL3()\n\t{\n\t\tdelete m_placeholderTableY;\n\t\tdelete m_placeholderTableZ;\n\t}\n\n\t// lookup\n\t// only the bottom most N bits bits are used of the offset\n\t// N = TBitsX + TBitsY + TBitsZ\n\t// if no match is found a default-constructed object is returned\n\tT lookup(uint32 offset)\n\t{\n\t\tuint32 indexZ = offset & ((1u << TBitsZ) - 1);\n\t\toffset >>= TBitsZ;\n\t\tuint32 indexY = offset & ((1u << TBitsY) - 1);\n\t\toffset >>= TBitsY;\n\t\tuint32 indexX = offset & ((1u << TBitsX) - 1);\n\t\t//offset >>= TBitsX;\n\t\treturn m_tableXArr[indexX]->arr[indexY]->arr[indexZ];\n\t}\n\n\tvoid store(uint32 offset, T& t)\n\t{\n\t\tuint32 indexZ = offset & ((1u << TBitsZ) - 1);\n\t\toffset >>= TBitsZ;\n\t\tuint32 indexY = offset & ((1u << TBitsY) - 1);\n\t\toffset >>= TBitsY;\n\t\tuint32 indexX = offset & ((1u << TBitsX) - 1);\n\t\tif (m_tableXArr[indexX] == m_placeholderTableY)\n\t\t\tm_tableXArr[indexX] = GenerateNewTableY();\n\t\tTableY* lookupY = m_tableXArr[indexX];\n\t\tif (lookupY->arr[indexY] == m_placeholderTableZ)\n\t\t\tlookupY->arr[indexY] = GenerateNewTableZ();\n\t\tTableZ* lookupZ = lookupY->arr[indexY];\n\t\tlookupZ->arr[indexZ] = t;\n\t}\n\nprivate:\n\t// generate a new Y lookup table which will initially contain only pointers to m_placeholderTableZ\n\tTableY* GenerateNewTableY()\n\t{\n\t\tTableY* tableY = new TableY();\n\t\tfor (auto& itr : tableY->arr)\n\t\t\titr = m_placeholderTableZ;\n\t\treturn tableY;\n\t}\n\n\t// generate a new Z lookup table which will initially contain only default constructed T\n\tTableZ* GenerateNewTableZ()\n\t{\n\t\tTableZ* tableZ = new TableZ();\n\t\treturn tableZ;\n\t}\n\n\tTableY* m_tableXArr[1 << TBitsX]; // x lookup\n};\n"
  },
  {
    "path": "src/util/containers/RangeStore.h",
    "content": "#pragma once\n\ntemplate<typename _OBJ, typename _ADDR, size_t count, size_t granularity>\nclass RangeStore\n{\npublic:\n\n\ttypedef struct\n\t{\n\t\t_ADDR start;\n\t\t_ADDR end;\n\t\t_OBJ data;\n\t\tsize_t lastIterationIndex;\n\t}rangeEntry_t;\n\n\tRangeStore() = default;\n\n\tsize_t getBucket(_ADDR addr)\n\t{\n\t\tsize_t index = addr / granularity;\n\t\tindex %= count;\n\t\treturn index;\n\t}\n\n\tvoid getBucketRange(_ADDR addrStart, _ADDR addrEnd, size_t& bucketFirst, size_t& bucketCount)\n\t{\n\t\tbucketFirst = getBucket(addrStart);\n\t\tsize_t indexStart = addrStart / granularity;\n\t\tsize_t indexEnd = std::max(addrStart, addrEnd - 1) / granularity;\n\t\tbucketCount = indexEnd - indexStart + 1;\n\t}\n\n\t// end address should be supplied as start+size\n\tvoid* storeRange(_OBJ data, _ADDR start, _ADDR end)\n\t{\n\t\tsize_t bucketFirst;\n\t\tsize_t bucketCount;\n\t\tgetBucketRange(start, end, bucketFirst, bucketCount);\n\t\tbucketCount = std::min(bucketCount, count);\n\n\t\t// create range\n\t\trangeEntry_t* rangeEntry = new rangeEntry_t();\n\t\trangeEntry->data = data;\n\t\trangeEntry->start = start;\n\t\trangeEntry->end = end;\n\t\trangeEntry->lastIterationIndex = currentIterationIndex;\n\n\t\t// register range in every bucket it touches\n\t\tsize_t idx = bucketFirst;\n\t\tfor (size_t i = 0; i < bucketCount; i++)\n\t\t{\n\t\t\trangeBuckets[idx].list_ranges.push_back(rangeEntry);\n\t\t\tidx = (idx + 1) % count;\n\t\t}\n\n\t\treturn rangeEntry;\n\t}\n\n\tvoid deleteRange(void* rangePtr)\n\t{\n\t\trangeEntry_t* rangeEntry = (rangeEntry_t*)rangePtr;\n\t\t// get bucket range\n\t\tsize_t bucketFirst;\n\t\tsize_t bucketCount;\n\t\tgetBucketRange(rangeEntry->start, rangeEntry->end, bucketFirst, bucketCount);\n\t\tbucketCount = std::min(bucketCount, count);\n\t\t// remove from buckets\n\t\tsize_t idx = bucketFirst;\n\t\tfor (size_t i = 0; i < bucketCount; i++)\n\t\t{\n\t\t\trangeBuckets[idx].list_ranges.erase(std::remove(rangeBuckets[idx].list_ranges.begin(), rangeBuckets[idx].list_ranges.end(), rangeEntry), rangeBuckets[idx].list_ranges.end());\n\t\t\tidx = (idx + 1) % count;\n\t\t}\n\t\tdelete rangeEntry;\n\t}\n\n\tvoid findRanges(_ADDR start, _ADDR end, std::function <void(_ADDR start, _ADDR end, _OBJ data)> f)\n\t{\n\t\tcurrentIterationIndex++;\n\t\tsize_t bucketFirst;\n\t\tsize_t bucketCount;\n\t\tgetBucketRange(start, end, bucketFirst, bucketCount);\n\t\tbucketCount = std::min(bucketCount, count);\n\t\tsize_t idx = bucketFirst;\n\t\tfor (size_t i = 0; i < bucketCount; i++)\n\t\t{\n\t\t\tfor (auto r : rangeBuckets[idx].list_ranges)\n\t\t\t{\n\t\t\t\tif (start < r->end && end > r->start && r->lastIterationIndex != currentIterationIndex)\n\t\t\t\t{\n\t\t\t\t\tr->lastIterationIndex = currentIterationIndex;\n\t\t\t\t\tf(r->start, r->end, r->data);\n\t\t\t\t}\n\t\t\t}\n\t\t\tidx = (idx + 1) % count;\n\t\t}\n\t}\n\n\tbool findFirstRange(_ADDR start, _ADDR end, _ADDR& rStart, _ADDR& rEnd, _OBJ& rData)\n\t{\n\t\tcurrentIterationIndex++;\n\t\tsize_t bucketFirst;\n\t\tsize_t bucketCount;\n\t\tgetBucketRange(start, end, bucketFirst, bucketCount);\n\t\tbucketCount = std::min(bucketCount, count);\n\t\tsize_t idx = bucketFirst;\n\t\tfor (size_t i = 0; i < bucketCount; i++)\n\t\t{\n\t\t\tfor (auto r : rangeBuckets[idx].list_ranges)\n\t\t\t{\n\t\t\t\tif (start < r->end && end > r->start && r->lastIterationIndex != currentIterationIndex)\n\t\t\t\t{\n\t\t\t\t\tr->lastIterationIndex = currentIterationIndex;\n\t\t\t\t\trStart = r->start;\n\t\t\t\t\trEnd = r->end;\n\t\t\t\t\trData = r->data;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tidx = (idx + 1) % count;\n\t\t}\n\t\treturn false;\n\t}\n\n    void clear()\n    {\n        for(auto& bucket : rangeBuckets)\n        {\n            while(!bucket.list_ranges.empty())\n                deleteRange(bucket.list_ranges[0]);\n        }\n    }\n\nprivate:\n\ttypedef struct\n\t{\n\t\tstd::vector<rangeEntry_t*> list_ranges;\n\t}rangeBucket_t;\n\n\tstd::array<rangeBucket_t, count> rangeBuckets;\n\n\tsize_t currentIterationIndex;\n};\n"
  },
  {
    "path": "src/util/containers/SmallBitset.h",
    "content": "\n// optimized and compact version of std::bitset with no error checking in release mode\n// uses a single uint32 to store the bitmask, thus allowing up to 32 bool values\n\ntemplate<size_t N>\nclass SmallBitset\n{\npublic:\n\tSmallBitset() = default;\n\tstatic_assert(N <= 32);\n\t\n\tbool test(size_t index) const\n\t{\n\t\tcemu_assert_debug(index < N);\n\t\treturn ((m_bits >> index) & 1) != 0;\n\t}\n\n\tvoid set(size_t index, bool val)\n\t{\n\t\tcemu_assert_debug(index < N);\n\t\tm_bits &= ~(1u << index);\n\t\tif (val)\n\t\t\tm_bits |= (1u << index);\n\t}\n\n\tvoid set(size_t index)\n\t{\n\t\tcemu_assert_debug(index < N);\n\t\tm_bits |= (1u << index);\n\t}\n\nprivate:\n\tuint32 m_bits{};\n};"
  },
  {
    "path": "src/util/containers/flat_hash_map.hpp",
    "content": "//          Copyright Malte Skarupke 2017.\n// Distributed under the Boost Software License, Version 1.0.\n//    (See http://www.boost.org/LICENSE_1_0.txt)\n\n#pragma once\n\n#include <cstdint>\n#include <cstddef>\n#include <functional>\n#include <cmath>\n#include <algorithm>\n#include <iterator>\n#include <utility>\n#include <type_traits>\n\n#ifdef _MSC_VER\n#define SKA_NOINLINE(...) __declspec(noinline) __VA_ARGS__\n#else\n#define SKA_NOINLINE(...) __VA_ARGS__ __attribute__((noinline))\n#endif\n\nnamespace ska\n{\n\tstruct prime_number_hash_policy;\n\tstruct power_of_two_hash_policy;\n\tstruct fibonacci_hash_policy;\n\n\tnamespace detailv3\n\t{\n\t\ttemplate<typename Result, typename Functor>\n\t\tstruct functor_storage : Functor\n\t\t{\n\t\t\tfunctor_storage() = default;\n\t\t\tfunctor_storage(const Functor& functor)\n\t\t\t\t: Functor(functor)\n\t\t\t{\n\t\t\t}\n\t\t\ttemplate<typename... Args>\n\t\t\tResult operator()(Args &&... args)\n\t\t\t{\n\t\t\t\treturn static_cast<Functor&>(*this)(std::forward<Args>(args)...);\n\t\t\t}\n\t\t\ttemplate<typename... Args>\n\t\t\tResult operator()(Args &&... args) const\n\t\t\t{\n\t\t\t\treturn static_cast<const Functor&>(*this)(std::forward<Args>(args)...);\n\t\t\t}\n\t\t};\n\t\ttemplate<typename Result, typename... Args>\n\t\tstruct functor_storage<Result, Result(*)(Args...)>\n\t\t{\n\t\t\ttypedef Result(*function_ptr)(Args...);\n\t\t\tfunction_ptr function;\n\t\t\tfunctor_storage(function_ptr function)\n\t\t\t\t: function(function)\n\t\t\t{\n\t\t\t}\n\t\t\tResult operator()(Args... args) const\n\t\t\t{\n\t\t\t\treturn function(std::forward<Args>(args)...);\n\t\t\t}\n\t\t\toperator function_ptr& ()\n\t\t\t{\n\t\t\t\treturn function;\n\t\t\t}\n\t\t\toperator const function_ptr& ()\n\t\t\t{\n\t\t\t\treturn function;\n\t\t\t}\n\t\t};\n\t\ttemplate<typename key_type, typename value_type, typename hasher>\n\t\tstruct KeyOrValueHasher : functor_storage<size_t, hasher>\n\t\t{\n\t\t\ttypedef functor_storage<size_t, hasher> hasher_storage;\n\t\t\tKeyOrValueHasher() = default;\n\t\t\tKeyOrValueHasher(const hasher& hash)\n\t\t\t\t: hasher_storage(hash)\n\t\t\t{\n\t\t\t}\n\t\t\tsize_t operator()(const key_type& key)\n\t\t\t{\n\t\t\t\treturn static_cast<hasher_storage&>(*this)(key);\n\t\t\t}\n\t\t\tsize_t operator()(const key_type& key) const\n\t\t\t{\n\t\t\t\treturn static_cast<const hasher_storage&>(*this)(key);\n\t\t\t}\n\t\t\tsize_t operator()(const value_type& value)\n\t\t\t{\n\t\t\t\treturn static_cast<hasher_storage&>(*this)(value.first);\n\t\t\t}\n\t\t\tsize_t operator()(const value_type& value) const\n\t\t\t{\n\t\t\t\treturn static_cast<const hasher_storage&>(*this)(value.first);\n\t\t\t}\n\t\t\ttemplate<typename F, typename S>\n\t\t\tsize_t operator()(const std::pair<F, S>& value)\n\t\t\t{\n\t\t\t\treturn static_cast<hasher_storage&>(*this)(value.first);\n\t\t\t}\n\t\t\ttemplate<typename F, typename S>\n\t\t\tsize_t operator()(const std::pair<F, S>& value) const\n\t\t\t{\n\t\t\t\treturn static_cast<const hasher_storage&>(*this)(value.first);\n\t\t\t}\n\t\t};\n\t\ttemplate<typename key_type, typename value_type, typename key_equal>\n\t\tstruct KeyOrValueEquality : functor_storage<bool, key_equal>\n\t\t{\n\t\t\ttypedef functor_storage<bool, key_equal> equality_storage;\n\t\t\tKeyOrValueEquality() = default;\n\t\t\tKeyOrValueEquality(const key_equal& equality)\n\t\t\t\t: equality_storage(equality)\n\t\t\t{\n\t\t\t}\n\t\t\tbool operator()(const key_type& lhs, const key_type& rhs)\n\t\t\t{\n\t\t\t\treturn static_cast<equality_storage&>(*this)(lhs, rhs);\n\t\t\t}\n\t\t\tbool operator()(const key_type& lhs, const value_type& rhs)\n\t\t\t{\n\t\t\t\treturn static_cast<equality_storage&>(*this)(lhs, rhs.first);\n\t\t\t}\n\t\t\tbool operator()(const value_type& lhs, const key_type& rhs)\n\t\t\t{\n\t\t\t\treturn static_cast<equality_storage&>(*this)(lhs.first, rhs);\n\t\t\t}\n\t\t\tbool operator()(const value_type& lhs, const value_type& rhs)\n\t\t\t{\n\t\t\t\treturn static_cast<equality_storage&>(*this)(lhs.first, rhs.first);\n\t\t\t}\n\t\t\ttemplate<typename F, typename S>\n\t\t\tbool operator()(const key_type& lhs, const std::pair<F, S>& rhs)\n\t\t\t{\n\t\t\t\treturn static_cast<equality_storage&>(*this)(lhs, rhs.first);\n\t\t\t}\n\t\t\ttemplate<typename F, typename S>\n\t\t\tbool operator()(const std::pair<F, S>& lhs, const key_type& rhs)\n\t\t\t{\n\t\t\t\treturn static_cast<equality_storage&>(*this)(lhs.first, rhs);\n\t\t\t}\n\t\t\ttemplate<typename F, typename S>\n\t\t\tbool operator()(const value_type& lhs, const std::pair<F, S>& rhs)\n\t\t\t{\n\t\t\t\treturn static_cast<equality_storage&>(*this)(lhs.first, rhs.first);\n\t\t\t}\n\t\t\ttemplate<typename F, typename S>\n\t\t\tbool operator()(const std::pair<F, S>& lhs, const value_type& rhs)\n\t\t\t{\n\t\t\t\treturn static_cast<equality_storage&>(*this)(lhs.first, rhs.first);\n\t\t\t}\n\t\t\ttemplate<typename FL, typename SL, typename FR, typename SR>\n\t\t\tbool operator()(const std::pair<FL, SL>& lhs, const std::pair<FR, SR>& rhs)\n\t\t\t{\n\t\t\t\treturn static_cast<equality_storage&>(*this)(lhs.first, rhs.first);\n\t\t\t}\n\t\t};\n\t\tstatic constexpr int8_t min_lookups = 4;\n\t\ttemplate<typename T>\n\t\tstruct sherwood_v3_entry\n\t\t{\n\t\t\tsherwood_v3_entry()\n\t\t\t{\n\t\t\t}\n\t\t\tsherwood_v3_entry(int8_t distance_from_desired)\n\t\t\t\t: distance_from_desired(distance_from_desired)\n\t\t\t{\n\t\t\t}\n\t\t\t~sherwood_v3_entry() = default;\n\t\t\tstatic sherwood_v3_entry* empty_default_table()\n\t\t\t{\n\t\t\t\tstatic sherwood_v3_entry result[min_lookups] = { {}, {}, {}, {special_end_value} };\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tbool has_value() const\n\t\t\t{\n\t\t\t\treturn distance_from_desired >= 0;\n\t\t\t}\n\t\t\tbool is_empty() const\n\t\t\t{\n\t\t\t\treturn distance_from_desired < 0;\n\t\t\t}\n\t\t\tbool is_at_desired_position() const\n\t\t\t{\n\t\t\t\treturn distance_from_desired <= 0;\n\t\t\t}\n\t\t\ttemplate<typename... Args>\n\t\t\tvoid emplace(int8_t distance, Args &&... args)\n\t\t\t{\n\t\t\t\tnew (std::addressof(value)) T(std::forward<Args>(args)...);\n\t\t\t\tdistance_from_desired = distance;\n\t\t\t}\n\n\t\t\tvoid destroy_value()\n\t\t\t{\n\t\t\t\tvalue.~T();\n\t\t\t\tdistance_from_desired = -1;\n\t\t\t}\n\n\t\t\tint8_t distance_from_desired = -1;\n\t\t\tstatic constexpr int8_t special_end_value = 0;\n\t\t\tunion { T value; };\n\t\t};\n\n\t\tinline int8_t log2(size_t value)\n\t\t{\n\t\t\tstatic constexpr int8_t table[64] =\n\t\t\t{\n\t\t\t\t63,  0, 58,  1, 59, 47, 53,  2,\n\t\t\t\t60, 39, 48, 27, 54, 33, 42,  3,\n\t\t\t\t61, 51, 37, 40, 49, 18, 28, 20,\n\t\t\t\t55, 30, 34, 11, 43, 14, 22,  4,\n\t\t\t\t62, 57, 46, 52, 38, 26, 32, 41,\n\t\t\t\t50, 36, 17, 19, 29, 10, 13, 21,\n\t\t\t\t56, 45, 25, 31, 35, 16,  9, 12,\n\t\t\t\t44, 24, 15,  8, 23,  7,  6,  5\n\t\t\t};\n\t\t\tvalue |= value >> 1;\n\t\t\tvalue |= value >> 2;\n\t\t\tvalue |= value >> 4;\n\t\t\tvalue |= value >> 8;\n\t\t\tvalue |= value >> 16;\n\t\t\tvalue |= value >> 32;\n\t\t\treturn table[((value - (value >> 1)) * 0x07EDD5E59A4E28C2) >> 58];\n\t\t}\n\n\t\ttemplate<typename T, bool>\n\t\tstruct AssignIfTrue\n\t\t{\n\t\t\tvoid operator()(T& lhs, const T& rhs)\n\t\t\t{\n\t\t\t\tlhs = rhs;\n\t\t\t}\n\t\t\tvoid operator()(T& lhs, T&& rhs)\n\t\t\t{\n\t\t\t\tlhs = std::move(rhs);\n\t\t\t}\n\t\t};\n\t\ttemplate<typename T>\n\t\tstruct AssignIfTrue<T, false>\n\t\t{\n\t\t\tvoid operator()(T&, const T&)\n\t\t\t{\n\t\t\t}\n\t\t\tvoid operator()(T&, T&&)\n\t\t\t{\n\t\t\t}\n\t\t};\n\n\t\tinline size_t next_power_of_two(size_t i)\n\t\t{\n\t\t\t--i;\n\t\t\ti |= i >> 1;\n\t\t\ti |= i >> 2;\n\t\t\ti |= i >> 4;\n\t\t\ti |= i >> 8;\n\t\t\ti |= i >> 16;\n\t\t\ti |= i >> 32;\n\t\t\t++i;\n\t\t\treturn i;\n\t\t}\n\n\t\ttemplate<typename...> using void_t = void;\n\n\t\ttemplate<typename T, typename = void>\n\t\tstruct HashPolicySelector\n\t\t{\n\t\t\ttypedef fibonacci_hash_policy type;\n\t\t};\n\t\ttemplate<typename T>\n\t\tstruct HashPolicySelector<T, void_t<typename T::hash_policy>>\n\t\t{\n\t\t\ttypedef typename T::hash_policy type;\n\t\t};\n\n\t\ttemplate<typename T, typename FindKey, typename ArgumentHash, typename Hasher, typename ArgumentEqual, typename Equal, typename ArgumentAlloc, typename EntryAlloc>\n\t\tclass sherwood_v3_table : private EntryAlloc, private Hasher, private Equal\n\t\t{\n\t\t\tusing Entry = detailv3::sherwood_v3_entry<T>;\n\t\t\tusing AllocatorTraits = std::allocator_traits<EntryAlloc>;\n\t\t\tusing EntryPointer = typename AllocatorTraits::pointer;\n\t\t\tstruct convertible_to_iterator;\n\n\t\tpublic:\n\n\t\t\tusing value_type = T;\n\t\t\tusing size_type = size_t;\n\t\t\tusing difference_type = std::ptrdiff_t;\n\t\t\tusing hasher = ArgumentHash;\n\t\t\tusing key_equal = ArgumentEqual;\n\t\t\tusing allocator_type = EntryAlloc;\n\t\t\tusing reference = value_type&;\n\t\t\tusing const_reference = const value_type&;\n\t\t\tusing pointer = value_type*;\n\t\t\tusing const_pointer = const value_type*;\n\n\t\t\tsherwood_v3_table() = default;\n\t\t\texplicit sherwood_v3_table(size_type bucket_count, const ArgumentHash& hash = ArgumentHash(), const ArgumentEqual& equal = ArgumentEqual(), const ArgumentAlloc& alloc = ArgumentAlloc())\n\t\t\t\t: EntryAlloc(alloc), Hasher(hash), Equal(equal)\n\t\t\t{\n\t\t\t\trehash(bucket_count);\n\t\t\t}\n\t\t\tsherwood_v3_table(size_type bucket_count, const ArgumentAlloc& alloc)\n\t\t\t\t: sherwood_v3_table(bucket_count, ArgumentHash(), ArgumentEqual(), alloc)\n\t\t\t{\n\t\t\t}\n\t\t\tsherwood_v3_table(size_type bucket_count, const ArgumentHash& hash, const ArgumentAlloc& alloc)\n\t\t\t\t: sherwood_v3_table(bucket_count, hash, ArgumentEqual(), alloc)\n\t\t\t{\n\t\t\t}\n\t\t\texplicit sherwood_v3_table(const ArgumentAlloc& alloc)\n\t\t\t\t: EntryAlloc(alloc)\n\t\t\t{\n\t\t\t}\n\t\t\ttemplate<typename It>\n\t\t\tsherwood_v3_table(It first, It last, size_type bucket_count = 0, const ArgumentHash& hash = ArgumentHash(), const ArgumentEqual& equal = ArgumentEqual(), const ArgumentAlloc& alloc = ArgumentAlloc())\n\t\t\t\t: sherwood_v3_table(bucket_count, hash, equal, alloc)\n\t\t\t{\n\t\t\t\tinsert(first, last);\n\t\t\t}\n\t\t\ttemplate<typename It>\n\t\t\tsherwood_v3_table(It first, It last, size_type bucket_count, const ArgumentAlloc& alloc)\n\t\t\t\t: sherwood_v3_table(first, last, bucket_count, ArgumentHash(), ArgumentEqual(), alloc)\n\t\t\t{\n\t\t\t}\n\t\t\ttemplate<typename It>\n\t\t\tsherwood_v3_table(It first, It last, size_type bucket_count, const ArgumentHash& hash, const ArgumentAlloc& alloc)\n\t\t\t\t: sherwood_v3_table(first, last, bucket_count, hash, ArgumentEqual(), alloc)\n\t\t\t{\n\t\t\t}\n\t\t\tsherwood_v3_table(std::initializer_list<T> il, size_type bucket_count = 0, const ArgumentHash& hash = ArgumentHash(), const ArgumentEqual& equal = ArgumentEqual(), const ArgumentAlloc& alloc = ArgumentAlloc())\n\t\t\t\t: sherwood_v3_table(bucket_count, hash, equal, alloc)\n\t\t\t{\n\t\t\t\tif (bucket_count == 0)\n\t\t\t\t\trehash(il.size());\n\t\t\t\tinsert(il.begin(), il.end());\n\t\t\t}\n\t\t\tsherwood_v3_table(std::initializer_list<T> il, size_type bucket_count, const ArgumentAlloc& alloc)\n\t\t\t\t: sherwood_v3_table(il, bucket_count, ArgumentHash(), ArgumentEqual(), alloc)\n\t\t\t{\n\t\t\t}\n\t\t\tsherwood_v3_table(std::initializer_list<T> il, size_type bucket_count, const ArgumentHash& hash, const ArgumentAlloc& alloc)\n\t\t\t\t: sherwood_v3_table(il, bucket_count, hash, ArgumentEqual(), alloc)\n\t\t\t{\n\t\t\t}\n\t\t\tsherwood_v3_table(const sherwood_v3_table& other)\n\t\t\t\t: sherwood_v3_table(other, AllocatorTraits::select_on_container_copy_construction(other.get_allocator()))\n\t\t\t{\n\t\t\t}\n\t\t\tsherwood_v3_table(const sherwood_v3_table& other, const ArgumentAlloc& alloc)\n\t\t\t\t: EntryAlloc(alloc), Hasher(other), Equal(other), _max_load_factor(other._max_load_factor)\n\t\t\t{\n\t\t\t\trehash_for_other_container(other);\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\tinsert(other.begin(), other.end());\n\t\t\t\t}\n\t\t\t\tcatch (...)\n\t\t\t\t{\n\t\t\t\t\tclear();\n\t\t\t\t\tdeallocate_data(entries, num_slots_minus_one, max_lookups);\n\t\t\t\t\tthrow;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsherwood_v3_table(sherwood_v3_table&& other) noexcept\n\t\t\t\t: EntryAlloc(std::move(other)), Hasher(std::move(other)), Equal(std::move(other))\n\t\t\t{\n\t\t\t\tswap_pointers(other);\n\t\t\t}\n\t\t\tsherwood_v3_table(sherwood_v3_table&& other, const ArgumentAlloc& alloc) noexcept\n\t\t\t\t: EntryAlloc(alloc), Hasher(std::move(other)), Equal(std::move(other))\n\t\t\t{\n\t\t\t\tswap_pointers(other);\n\t\t\t}\n\t\t\tsherwood_v3_table& operator=(const sherwood_v3_table& other)\n\t\t\t{\n\t\t\t\tif (this == std::addressof(other))\n\t\t\t\t\treturn *this;\n\n\t\t\t\tclear();\n\t\t\t\tif (AllocatorTraits::propagate_on_container_copy_assignment::value)\n\t\t\t\t{\n\t\t\t\t\tif (static_cast<EntryAlloc&>(*this) != static_cast<const EntryAlloc&>(other))\n\t\t\t\t\t{\n\t\t\t\t\t\treset_to_empty_state();\n\t\t\t\t\t}\n\t\t\t\t\tAssignIfTrue<EntryAlloc, AllocatorTraits::propagate_on_container_copy_assignment::value>()(*this, other);\n\t\t\t\t}\n\t\t\t\t_max_load_factor = other._max_load_factor;\n\t\t\t\tstatic_cast<Hasher&>(*this) = other;\n\t\t\t\tstatic_cast<Equal&>(*this) = other;\n\t\t\t\trehash_for_other_container(other);\n\t\t\t\tinsert(other.begin(), other.end());\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\tsherwood_v3_table& operator=(sherwood_v3_table&& other) noexcept\n\t\t\t{\n\t\t\t\tif (this == std::addressof(other))\n\t\t\t\t\treturn *this;\n\t\t\t\telse if (AllocatorTraits::propagate_on_container_move_assignment::value)\n\t\t\t\t{\n\t\t\t\t\tclear();\n\t\t\t\t\treset_to_empty_state();\n\t\t\t\t\tAssignIfTrue<EntryAlloc, AllocatorTraits::propagate_on_container_move_assignment::value>()(*this, std::move(other));\n\t\t\t\t\tswap_pointers(other);\n\t\t\t\t}\n\t\t\t\telse if (static_cast<EntryAlloc&>(*this) == static_cast<EntryAlloc&>(other))\n\t\t\t\t{\n\t\t\t\t\tswap_pointers(other);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tclear();\n\t\t\t\t\t_max_load_factor = other._max_load_factor;\n\t\t\t\t\trehash_for_other_container(other);\n\t\t\t\t\tfor (T& elem : other)\n\t\t\t\t\t\templace(std::move(elem));\n\t\t\t\t\tother.clear();\n\t\t\t\t}\n\t\t\t\tstatic_cast<Hasher&>(*this) = std::move(other);\n\t\t\t\tstatic_cast<Equal&>(*this) = std::move(other);\n\t\t\t\treturn *this;\n\t\t\t}\n\t\t\t~sherwood_v3_table()\n\t\t\t{\n\t\t\t\tclear();\n\t\t\t\tdeallocate_data(entries, num_slots_minus_one, max_lookups);\n\t\t\t}\n\n\t\t\tconst allocator_type& get_allocator() const\n\t\t\t{\n\t\t\t\treturn static_cast<const allocator_type&>(*this);\n\t\t\t}\n\t\t\tconst ArgumentEqual& key_eq() const\n\t\t\t{\n\t\t\t\treturn static_cast<const ArgumentEqual&>(*this);\n\t\t\t}\n\t\t\tconst ArgumentHash& hash_function() const\n\t\t\t{\n\t\t\t\treturn static_cast<const ArgumentHash&>(*this);\n\t\t\t}\n\n\t\t\ttemplate<typename ValueType>\n\t\t\tstruct templated_iterator\n\t\t\t{\n\t\t\t\ttemplated_iterator() = default;\n\t\t\t\ttemplated_iterator(EntryPointer current)\n\t\t\t\t\t: current(current)\n\t\t\t\t{\n\t\t\t\t}\n\t\t\t\tEntryPointer current = EntryPointer();\n\n\t\t\t\tusing iterator_category = std::forward_iterator_tag;\n\t\t\t\tusing value_type = ValueType;\n\t\t\t\tusing difference_type = ptrdiff_t;\n\t\t\t\tusing pointer = ValueType*;\n\t\t\t\tusing reference = ValueType&;\n\n\t\t\t\tfriend bool operator==(const templated_iterator& lhs, const templated_iterator& rhs)\n\t\t\t\t{\n\t\t\t\t\treturn lhs.current == rhs.current;\n\t\t\t\t}\n\t\t\t\tfriend bool operator!=(const templated_iterator& lhs, const templated_iterator& rhs)\n\t\t\t\t{\n\t\t\t\t\treturn !(lhs == rhs);\n\t\t\t\t}\n\n\t\t\t\ttemplated_iterator& operator++()\n\t\t\t\t{\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\t++current;\n\t\t\t\t\t} while (current->is_empty());\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\t\t\t\ttemplated_iterator operator++(int)\n\t\t\t\t{\n\t\t\t\t\ttemplated_iterator copy(*this);\n\t\t\t\t\t++* this;\n\t\t\t\t\treturn copy;\n\t\t\t\t}\n\n\t\t\t\tValueType& operator*() const\n\t\t\t\t{\n\t\t\t\t\treturn current->value;\n\t\t\t\t}\n\t\t\t\tValueType* operator->() const\n\t\t\t\t{\n\t\t\t\t\treturn std::addressof(current->value);\n\t\t\t\t}\n\n\t\t\t\toperator templated_iterator<const value_type>() const\n\t\t\t\t{\n\t\t\t\t\treturn { current };\n\t\t\t\t}\n\t\t\t};\n\t\t\tusing iterator = templated_iterator<value_type>;\n\t\t\tusing const_iterator = templated_iterator<const value_type>;\n\n\t\t\titerator begin()\n\t\t\t{\n\t\t\t\tfor (EntryPointer it = entries;; ++it)\n\t\t\t\t{\n\t\t\t\t\tif (it->has_value())\n\t\t\t\t\t\treturn { it };\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst_iterator begin() const\n\t\t\t{\n\t\t\t\tfor (EntryPointer it = entries;; ++it)\n\t\t\t\t{\n\t\t\t\t\tif (it->has_value())\n\t\t\t\t\t\treturn { it };\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst_iterator cbegin() const\n\t\t\t{\n\t\t\t\treturn begin();\n\t\t\t}\n\t\t\titerator end()\n\t\t\t{\n\t\t\t\treturn { entries + static_cast<ptrdiff_t>(num_slots_minus_one + max_lookups) };\n\t\t\t}\n\t\t\tconst_iterator end() const\n\t\t\t{\n\t\t\t\treturn { entries + static_cast<ptrdiff_t>(num_slots_minus_one + max_lookups) };\n\t\t\t}\n\t\t\tconst_iterator cend() const\n\t\t\t{\n\t\t\t\treturn end();\n\t\t\t}\n\n\t\t\titerator find(const FindKey& key)\n\t\t\t{\n\t\t\t\tsize_t index = hash_policy.index_for_hash(hash_object(key), num_slots_minus_one);\n\t\t\t\tEntryPointer it = entries + ptrdiff_t(index);\n\t\t\t\tfor (int8_t distance = 0; it->distance_from_desired >= distance; ++distance, ++it)\n\t\t\t\t{\n\t\t\t\t\tif (compares_equal(key, it->value))\n\t\t\t\t\t\treturn { it };\n\t\t\t\t}\n\t\t\t\treturn end();\n\t\t\t}\n\t\t\tconst_iterator find(const FindKey& key) const\n\t\t\t{\n\t\t\t\treturn const_cast<sherwood_v3_table*>(this)->find(key);\n\t\t\t}\n\t\t\tsize_t count(const FindKey& key) const\n\t\t\t{\n\t\t\t\treturn find(key) == end() ? 0 : 1;\n\t\t\t}\n\t\t\tstd::pair<iterator, iterator> equal_range(const FindKey& key)\n\t\t\t{\n\t\t\t\titerator found = find(key);\n\t\t\t\tif (found == end())\n\t\t\t\t\treturn { found, found };\n\t\t\t\telse\n\t\t\t\t\treturn { found, std::next(found) };\n\t\t\t}\n\t\t\tstd::pair<const_iterator, const_iterator> equal_range(const FindKey& key) const\n\t\t\t{\n\t\t\t\tconst_iterator found = find(key);\n\t\t\t\tif (found == end())\n\t\t\t\t\treturn { found, found };\n\t\t\t\telse\n\t\t\t\t\treturn { found, std::next(found) };\n\t\t\t}\n\n\t\t\ttemplate<typename Key, typename... Args>\n\t\t\tstd::pair<iterator, bool> emplace(Key&& key, Args &&... args)\n\t\t\t{\n\t\t\t\tsize_t index = hash_policy.index_for_hash(hash_object(key), num_slots_minus_one);\n\t\t\t\tEntryPointer current_entry = entries + ptrdiff_t(index);\n\t\t\t\tint8_t distance_from_desired = 0;\n\t\t\t\tfor (; current_entry->distance_from_desired >= distance_from_desired; ++current_entry, ++distance_from_desired)\n\t\t\t\t{\n\t\t\t\t\tif (compares_equal(key, current_entry->value))\n\t\t\t\t\t\treturn { { current_entry }, false };\n\t\t\t\t}\n\t\t\t\treturn emplace_new_key(distance_from_desired, current_entry, std::forward<Key>(key), std::forward<Args>(args)...);\n\t\t\t}\n\n\t\t\tstd::pair<iterator, bool> insert(const value_type& value)\n\t\t\t{\n\t\t\t\treturn emplace(value);\n\t\t\t}\n\t\t\tstd::pair<iterator, bool> insert(value_type&& value)\n\t\t\t{\n\t\t\t\treturn emplace(std::move(value));\n\t\t\t}\n\t\t\ttemplate<typename... Args>\n\t\t\titerator emplace_hint(const_iterator, Args &&... args)\n\t\t\t{\n\t\t\t\treturn emplace(std::forward<Args>(args)...).first;\n\t\t\t}\n\t\t\titerator insert(const_iterator, const value_type& value)\n\t\t\t{\n\t\t\t\treturn emplace(value).first;\n\t\t\t}\n\t\t\titerator insert(const_iterator, value_type&& value)\n\t\t\t{\n\t\t\t\treturn emplace(std::move(value)).first;\n\t\t\t}\n\n\t\t\ttemplate<typename It>\n\t\t\tvoid insert(It begin, It end)\n\t\t\t{\n\t\t\t\tfor (; begin != end; ++begin)\n\t\t\t\t{\n\t\t\t\t\templace(*begin);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvoid insert(std::initializer_list<value_type> il)\n\t\t\t{\n\t\t\t\tinsert(il.begin(), il.end());\n\t\t\t}\n\n\t\t\tvoid rehash(size_t num_buckets)\n\t\t\t{\n\t\t\t\tnum_buckets = std::max(num_buckets, static_cast<size_t>(std::ceil(num_elements / static_cast<double>(_max_load_factor))));\n\t\t\t\tif (num_buckets == 0)\n\t\t\t\t{\n\t\t\t\t\treset_to_empty_state();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tauto new_prime_index = hash_policy.next_size_over(num_buckets);\n\t\t\t\tif (num_buckets == bucket_count())\n\t\t\t\t\treturn;\n\t\t\t\tint8_t new_max_lookups = compute_max_lookups(num_buckets);\n\t\t\t\tEntryPointer new_buckets(AllocatorTraits::allocate(*this, num_buckets + new_max_lookups));\n\t\t\t\tEntryPointer special_end_item = new_buckets + static_cast<ptrdiff_t>(num_buckets + new_max_lookups - 1);\n\t\t\t\tfor (EntryPointer it = new_buckets; it != special_end_item; ++it)\n\t\t\t\t\tit->distance_from_desired = -1;\n\t\t\t\tspecial_end_item->distance_from_desired = Entry::special_end_value;\n\t\t\t\tstd::swap(entries, new_buckets);\n\t\t\t\tstd::swap(num_slots_minus_one, num_buckets);\n\t\t\t\t--num_slots_minus_one;\n\t\t\t\thash_policy.commit(new_prime_index);\n\t\t\t\tint8_t old_max_lookups = max_lookups;\n\t\t\t\tmax_lookups = new_max_lookups;\n\t\t\t\tnum_elements = 0;\n\t\t\t\tfor (EntryPointer it = new_buckets, end = it + static_cast<ptrdiff_t>(num_buckets + old_max_lookups); it != end; ++it)\n\t\t\t\t{\n\t\t\t\t\tif (it->has_value())\n\t\t\t\t\t{\n\t\t\t\t\t\templace(std::move(it->value));\n\t\t\t\t\t\tit->destroy_value();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdeallocate_data(new_buckets, num_buckets, old_max_lookups);\n\t\t\t}\n\n\t\t\tvoid reserve(size_t num_elements)\n\t\t\t{\n\t\t\t\tsize_t required_buckets = num_buckets_for_reserve(num_elements);\n\t\t\t\tif (required_buckets > bucket_count())\n\t\t\t\t\trehash(required_buckets);\n\t\t\t}\n\n\t\t\t// the return value is a type that can be converted to an iterator\n\t\t\t// the reason for doing this is that it's not free to find the\n\t\t\t// iterator pointing at the next element. if you care about the\n\t\t\t// next iterator, turn the return value into an iterator\n\t\t\tconvertible_to_iterator erase(const_iterator to_erase)\n\t\t\t{\n\t\t\t\tEntryPointer current = to_erase.current;\n\t\t\t\tcurrent->destroy_value();\n\t\t\t\t--num_elements;\n\t\t\t\tfor (EntryPointer next = current + ptrdiff_t(1); !next->is_at_desired_position(); ++current, ++next)\n\t\t\t\t{\n\t\t\t\t\tcurrent->emplace(next->distance_from_desired - 1, std::move(next->value));\n\t\t\t\t\tnext->destroy_value();\n\t\t\t\t}\n\t\t\t\treturn { to_erase.current };\n\t\t\t}\n\n\t\t\titerator erase(const_iterator begin_it, const_iterator end_it)\n\t\t\t{\n\t\t\t\tif (begin_it == end_it)\n\t\t\t\t\treturn { begin_it.current };\n\t\t\t\tfor (EntryPointer it = begin_it.current, end = end_it.current; it != end; ++it)\n\t\t\t\t{\n\t\t\t\t\tif (it->has_value())\n\t\t\t\t\t{\n\t\t\t\t\t\tit->destroy_value();\n\t\t\t\t\t\t--num_elements;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (end_it == this->end())\n\t\t\t\t\treturn this->end();\n\t\t\t\tptrdiff_t num_to_move = std::min(static_cast<ptrdiff_t>(end_it.current->distance_from_desired), end_it.current - begin_it.current);\n\t\t\t\tEntryPointer to_return = end_it.current - num_to_move;\n\t\t\t\tfor (EntryPointer it = end_it.current; !it->is_at_desired_position();)\n\t\t\t\t{\n\t\t\t\t\tEntryPointer target = it - num_to_move;\n\t\t\t\t\ttarget->emplace(it->distance_from_desired - num_to_move, std::move(it->value));\n\t\t\t\t\tit->destroy_value();\n\t\t\t\t\t++it;\n\t\t\t\t\tnum_to_move = std::min(static_cast<ptrdiff_t>(it->distance_from_desired), num_to_move);\n\t\t\t\t}\n\t\t\t\treturn { to_return };\n\t\t\t}\n\n\t\t\tsize_t erase(const FindKey& key)\n\t\t\t{\n\t\t\t\tauto found = find(key);\n\t\t\t\tif (found == end())\n\t\t\t\t\treturn 0;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\terase(found);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid clear()\n\t\t\t{\n\t\t\t\tfor (EntryPointer it = entries, end = it + static_cast<ptrdiff_t>(num_slots_minus_one + max_lookups); it != end; ++it)\n\t\t\t\t{\n\t\t\t\t\tif (it->has_value())\n\t\t\t\t\t\tit->destroy_value();\n\t\t\t\t}\n\t\t\t\tnum_elements = 0;\n\t\t\t}\n\n\t\t\tvoid shrink_to_fit()\n\t\t\t{\n\t\t\t\trehash_for_other_container(*this);\n\t\t\t}\n\n\t\t\tvoid swap(sherwood_v3_table& other)\n\t\t\t{\n\t\t\t\tusing std::swap;\n\t\t\t\tswap_pointers(other);\n\t\t\t\tswap(static_cast<ArgumentHash&>(*this), static_cast<ArgumentHash&>(other));\n\t\t\t\tswap(static_cast<ArgumentEqual&>(*this), static_cast<ArgumentEqual&>(other));\n\t\t\t\tif (AllocatorTraits::propagate_on_container_swap::value)\n\t\t\t\t\tswap(static_cast<EntryAlloc&>(*this), static_cast<EntryAlloc&>(other));\n\t\t\t}\n\n\t\t\tsize_t size() const\n\t\t\t{\n\t\t\t\treturn num_elements;\n\t\t\t}\n\t\t\tsize_t max_size() const\n\t\t\t{\n\t\t\t\treturn (AllocatorTraits::max_size(*this)) / sizeof(Entry);\n\t\t\t}\n\t\t\tsize_t bucket_count() const\n\t\t\t{\n\t\t\t\treturn num_slots_minus_one ? num_slots_minus_one + 1 : 0;\n\t\t\t}\n\t\t\tsize_type max_bucket_count() const\n\t\t\t{\n\t\t\t\treturn (AllocatorTraits::max_size(*this) - min_lookups) / sizeof(Entry);\n\t\t\t}\n\t\t\tsize_t bucket(const FindKey& key) const\n\t\t\t{\n\t\t\t\treturn hash_policy.index_for_hash(hash_object(key), num_slots_minus_one);\n\t\t\t}\n\t\t\tfloat load_factor() const\n\t\t\t{\n\t\t\t\tsize_t buckets = bucket_count();\n\t\t\t\tif (buckets)\n\t\t\t\t\treturn static_cast<float>(num_elements) / bucket_count();\n\t\t\t\telse\n\t\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tvoid max_load_factor(float value)\n\t\t\t{\n\t\t\t\t_max_load_factor = value;\n\t\t\t}\n\t\t\tfloat max_load_factor() const\n\t\t\t{\n\t\t\t\treturn _max_load_factor;\n\t\t\t}\n\n\t\t\tbool empty() const\n\t\t\t{\n\t\t\t\treturn num_elements == 0;\n\t\t\t}\n\n\t\tprivate:\n\t\t\tEntryPointer entries = Entry::empty_default_table();\n\t\t\tsize_t num_slots_minus_one = 0;\n\t\t\ttypename HashPolicySelector<ArgumentHash>::type hash_policy;\n\t\t\tint8_t max_lookups = detailv3::min_lookups - 1;\n\t\t\tfloat _max_load_factor = 0.5f;\n\t\t\tsize_t num_elements = 0;\n\n\t\t\tstatic int8_t compute_max_lookups(size_t num_buckets)\n\t\t\t{\n\t\t\t\tint8_t desired = detailv3::log2(num_buckets);\n\t\t\t\treturn std::max(detailv3::min_lookups, desired);\n\t\t\t}\n\n\t\t\tsize_t num_buckets_for_reserve(size_t num_elements) const\n\t\t\t{\n\t\t\t\treturn static_cast<size_t>(std::ceil(num_elements / std::min(0.5, static_cast<double>(_max_load_factor))));\n\t\t\t}\n\t\t\tvoid rehash_for_other_container(const sherwood_v3_table& other)\n\t\t\t{\n\t\t\t\trehash(std::min(num_buckets_for_reserve(other.size()), other.bucket_count()));\n\t\t\t}\n\n\t\t\tvoid swap_pointers(sherwood_v3_table& other)\n\t\t\t{\n\t\t\t\tusing std::swap;\n\t\t\t\tswap(hash_policy, other.hash_policy);\n\t\t\t\tswap(entries, other.entries);\n\t\t\t\tswap(num_slots_minus_one, other.num_slots_minus_one);\n\t\t\t\tswap(num_elements, other.num_elements);\n\t\t\t\tswap(max_lookups, other.max_lookups);\n\t\t\t\tswap(_max_load_factor, other._max_load_factor);\n\t\t\t}\n\n\t\t\ttemplate<typename Key, typename... Args>\n\t\t\tSKA_NOINLINE(std::pair<iterator, bool>) emplace_new_key(int8_t distance_from_desired, EntryPointer current_entry, Key&& key, Args &&... args)\n\t\t\t{\n\t\t\t\tusing std::swap;\n\t\t\t\tif (num_slots_minus_one == 0 || distance_from_desired == max_lookups || num_elements + 1 > (num_slots_minus_one + 1) * static_cast<double>(_max_load_factor))\n\t\t\t\t{\n\t\t\t\t\tgrow();\n\t\t\t\t\treturn emplace(std::forward<Key>(key), std::forward<Args>(args)...);\n\t\t\t\t}\n\t\t\t\telse if (current_entry->is_empty())\n\t\t\t\t{\n\t\t\t\t\tcurrent_entry->emplace(distance_from_desired, std::forward<Key>(key), std::forward<Args>(args)...);\n\t\t\t\t\t++num_elements;\n\t\t\t\t\treturn { { current_entry }, true };\n\t\t\t\t}\n\t\t\t\tvalue_type to_insert(std::forward<Key>(key), std::forward<Args>(args)...);\n\t\t\t\tswap(distance_from_desired, current_entry->distance_from_desired);\n\t\t\t\tswap(to_insert, current_entry->value);\n\t\t\t\titerator result = { current_entry };\n\t\t\t\tfor (++distance_from_desired, ++current_entry;; ++current_entry)\n\t\t\t\t{\n\t\t\t\t\tif (current_entry->is_empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tcurrent_entry->emplace(distance_from_desired, std::move(to_insert));\n\t\t\t\t\t\t++num_elements;\n\t\t\t\t\t\treturn { result, true };\n\t\t\t\t\t}\n\t\t\t\t\telse if (current_entry->distance_from_desired < distance_from_desired)\n\t\t\t\t\t{\n\t\t\t\t\t\tswap(distance_from_desired, current_entry->distance_from_desired);\n\t\t\t\t\t\tswap(to_insert, current_entry->value);\n\t\t\t\t\t\t++distance_from_desired;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t++distance_from_desired;\n\t\t\t\t\t\tif (distance_from_desired == max_lookups)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tswap(to_insert, result.current->value);\n\t\t\t\t\t\t\tgrow();\n\t\t\t\t\t\t\treturn emplace(std::move(to_insert));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid grow()\n\t\t\t{\n\t\t\t\trehash(std::max(size_t(4), 2 * bucket_count()));\n\t\t\t}\n\n\t\t\tvoid deallocate_data(EntryPointer begin, size_t num_slots_minus_one, int8_t max_lookups)\n\t\t\t{\n\t\t\t\tif (begin != Entry::empty_default_table())\n\t\t\t\t{\n\t\t\t\t\tAllocatorTraits::deallocate(*this, begin, num_slots_minus_one + max_lookups + 1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid reset_to_empty_state()\n\t\t\t{\n\t\t\t\tdeallocate_data(entries, num_slots_minus_one, max_lookups);\n\t\t\t\tentries = Entry::empty_default_table();\n\t\t\t\tnum_slots_minus_one = 0;\n\t\t\t\thash_policy.reset();\n\t\t\t\tmax_lookups = detailv3::min_lookups - 1;\n\t\t\t}\n\n\t\t\ttemplate<typename U>\n\t\t\tsize_t hash_object(const U& key)\n\t\t\t{\n\t\t\t\treturn static_cast<Hasher&>(*this)(key);\n\t\t\t}\n\t\t\ttemplate<typename U>\n\t\t\tsize_t hash_object(const U& key) const\n\t\t\t{\n\t\t\t\treturn static_cast<const Hasher&>(*this)(key);\n\t\t\t}\n\t\t\ttemplate<typename L, typename R>\n\t\t\tbool compares_equal(const L& lhs, const R& rhs)\n\t\t\t{\n\t\t\t\treturn static_cast<Equal&>(*this)(lhs, rhs);\n\t\t\t}\n\n\t\t\tstruct convertible_to_iterator\n\t\t\t{\n\t\t\t\tEntryPointer it;\n\n\t\t\t\toperator iterator()\n\t\t\t\t{\n\t\t\t\t\tif (it->has_value())\n\t\t\t\t\t\treturn { it };\n\t\t\t\t\telse\n\t\t\t\t\t\treturn ++iterator{ it };\n\t\t\t\t}\n\t\t\t\toperator const_iterator()\n\t\t\t\t{\n\t\t\t\t\tif (it->has_value())\n\t\t\t\t\t\treturn { it };\n\t\t\t\t\telse\n\t\t\t\t\t\treturn ++const_iterator{ it };\n\t\t\t\t}\n\t\t\t};\n\n\t\t};\n\t}\n\n\tstruct prime_number_hash_policy\n\t{\n\t\tstatic size_t mod0(size_t) { return 0llu; }\n\t\tstatic size_t mod2(size_t hash) { return hash % 2llu; }\n\t\tstatic size_t mod3(size_t hash) { return hash % 3llu; }\n\t\tstatic size_t mod5(size_t hash) { return hash % 5llu; }\n\t\tstatic size_t mod7(size_t hash) { return hash % 7llu; }\n\t\tstatic size_t mod11(size_t hash) { return hash % 11llu; }\n\t\tstatic size_t mod13(size_t hash) { return hash % 13llu; }\n\t\tstatic size_t mod17(size_t hash) { return hash % 17llu; }\n\t\tstatic size_t mod23(size_t hash) { return hash % 23llu; }\n\t\tstatic size_t mod29(size_t hash) { return hash % 29llu; }\n\t\tstatic size_t mod37(size_t hash) { return hash % 37llu; }\n\t\tstatic size_t mod47(size_t hash) { return hash % 47llu; }\n\t\tstatic size_t mod59(size_t hash) { return hash % 59llu; }\n\t\tstatic size_t mod73(size_t hash) { return hash % 73llu; }\n\t\tstatic size_t mod97(size_t hash) { return hash % 97llu; }\n\t\tstatic size_t mod127(size_t hash) { return hash % 127llu; }\n\t\tstatic size_t mod151(size_t hash) { return hash % 151llu; }\n\t\tstatic size_t mod197(size_t hash) { return hash % 197llu; }\n\t\tstatic size_t mod251(size_t hash) { return hash % 251llu; }\n\t\tstatic size_t mod313(size_t hash) { return hash % 313llu; }\n\t\tstatic size_t mod397(size_t hash) { return hash % 397llu; }\n\t\tstatic size_t mod499(size_t hash) { return hash % 499llu; }\n\t\tstatic size_t mod631(size_t hash) { return hash % 631llu; }\n\t\tstatic size_t mod797(size_t hash) { return hash % 797llu; }\n\t\tstatic size_t mod1009(size_t hash) { return hash % 1009llu; }\n\t\tstatic size_t mod1259(size_t hash) { return hash % 1259llu; }\n\t\tstatic size_t mod1597(size_t hash) { return hash % 1597llu; }\n\t\tstatic size_t mod2011(size_t hash) { return hash % 2011llu; }\n\t\tstatic size_t mod2539(size_t hash) { return hash % 2539llu; }\n\t\tstatic size_t mod3203(size_t hash) { return hash % 3203llu; }\n\t\tstatic size_t mod4027(size_t hash) { return hash % 4027llu; }\n\t\tstatic size_t mod5087(size_t hash) { return hash % 5087llu; }\n\t\tstatic size_t mod6421(size_t hash) { return hash % 6421llu; }\n\t\tstatic size_t mod8089(size_t hash) { return hash % 8089llu; }\n\t\tstatic size_t mod10193(size_t hash) { return hash % 10193llu; }\n\t\tstatic size_t mod12853(size_t hash) { return hash % 12853llu; }\n\t\tstatic size_t mod16193(size_t hash) { return hash % 16193llu; }\n\t\tstatic size_t mod20399(size_t hash) { return hash % 20399llu; }\n\t\tstatic size_t mod25717(size_t hash) { return hash % 25717llu; }\n\t\tstatic size_t mod32401(size_t hash) { return hash % 32401llu; }\n\t\tstatic size_t mod40823(size_t hash) { return hash % 40823llu; }\n\t\tstatic size_t mod51437(size_t hash) { return hash % 51437llu; }\n\t\tstatic size_t mod64811(size_t hash) { return hash % 64811llu; }\n\t\tstatic size_t mod81649(size_t hash) { return hash % 81649llu; }\n\t\tstatic size_t mod102877(size_t hash) { return hash % 102877llu; }\n\t\tstatic size_t mod129607(size_t hash) { return hash % 129607llu; }\n\t\tstatic size_t mod163307(size_t hash) { return hash % 163307llu; }\n\t\tstatic size_t mod205759(size_t hash) { return hash % 205759llu; }\n\t\tstatic size_t mod259229(size_t hash) { return hash % 259229llu; }\n\t\tstatic size_t mod326617(size_t hash) { return hash % 326617llu; }\n\t\tstatic size_t mod411527(size_t hash) { return hash % 411527llu; }\n\t\tstatic size_t mod518509(size_t hash) { return hash % 518509llu; }\n\t\tstatic size_t mod653267(size_t hash) { return hash % 653267llu; }\n\t\tstatic size_t mod823117(size_t hash) { return hash % 823117llu; }\n\t\tstatic size_t mod1037059(size_t hash) { return hash % 1037059llu; }\n\t\tstatic size_t mod1306601(size_t hash) { return hash % 1306601llu; }\n\t\tstatic size_t mod1646237(size_t hash) { return hash % 1646237llu; }\n\t\tstatic size_t mod2074129(size_t hash) { return hash % 2074129llu; }\n\t\tstatic size_t mod2613229(size_t hash) { return hash % 2613229llu; }\n\t\tstatic size_t mod3292489(size_t hash) { return hash % 3292489llu; }\n\t\tstatic size_t mod4148279(size_t hash) { return hash % 4148279llu; }\n\t\tstatic size_t mod5226491(size_t hash) { return hash % 5226491llu; }\n\t\tstatic size_t mod6584983(size_t hash) { return hash % 6584983llu; }\n\t\tstatic size_t mod8296553(size_t hash) { return hash % 8296553llu; }\n\t\tstatic size_t mod10453007(size_t hash) { return hash % 10453007llu; }\n\t\tstatic size_t mod13169977(size_t hash) { return hash % 13169977llu; }\n\t\tstatic size_t mod16593127(size_t hash) { return hash % 16593127llu; }\n\t\tstatic size_t mod20906033(size_t hash) { return hash % 20906033llu; }\n\t\tstatic size_t mod26339969(size_t hash) { return hash % 26339969llu; }\n\t\tstatic size_t mod33186281(size_t hash) { return hash % 33186281llu; }\n\t\tstatic size_t mod41812097(size_t hash) { return hash % 41812097llu; }\n\t\tstatic size_t mod52679969(size_t hash) { return hash % 52679969llu; }\n\t\tstatic size_t mod66372617(size_t hash) { return hash % 66372617llu; }\n\t\tstatic size_t mod83624237(size_t hash) { return hash % 83624237llu; }\n\t\tstatic size_t mod105359939(size_t hash) { return hash % 105359939llu; }\n\t\tstatic size_t mod132745199(size_t hash) { return hash % 132745199llu; }\n\t\tstatic size_t mod167248483(size_t hash) { return hash % 167248483llu; }\n\t\tstatic size_t mod210719881(size_t hash) { return hash % 210719881llu; }\n\t\tstatic size_t mod265490441(size_t hash) { return hash % 265490441llu; }\n\t\tstatic size_t mod334496971(size_t hash) { return hash % 334496971llu; }\n\t\tstatic size_t mod421439783(size_t hash) { return hash % 421439783llu; }\n\t\tstatic size_t mod530980861(size_t hash) { return hash % 530980861llu; }\n\t\tstatic size_t mod668993977(size_t hash) { return hash % 668993977llu; }\n\t\tstatic size_t mod842879579(size_t hash) { return hash % 842879579llu; }\n\t\tstatic size_t mod1061961721(size_t hash) { return hash % 1061961721llu; }\n\t\tstatic size_t mod1337987929(size_t hash) { return hash % 1337987929llu; }\n\t\tstatic size_t mod1685759167(size_t hash) { return hash % 1685759167llu; }\n\t\tstatic size_t mod2123923447(size_t hash) { return hash % 2123923447llu; }\n\t\tstatic size_t mod2675975881(size_t hash) { return hash % 2675975881llu; }\n\t\tstatic size_t mod3371518343(size_t hash) { return hash % 3371518343llu; }\n\t\tstatic size_t mod4247846927(size_t hash) { return hash % 4247846927llu; }\n\t\tstatic size_t mod5351951779(size_t hash) { return hash % 5351951779llu; }\n\t\tstatic size_t mod6743036717(size_t hash) { return hash % 6743036717llu; }\n\t\tstatic size_t mod8495693897(size_t hash) { return hash % 8495693897llu; }\n\t\tstatic size_t mod10703903591(size_t hash) { return hash % 10703903591llu; }\n\t\tstatic size_t mod13486073473(size_t hash) { return hash % 13486073473llu; }\n\t\tstatic size_t mod16991387857(size_t hash) { return hash % 16991387857llu; }\n\t\tstatic size_t mod21407807219(size_t hash) { return hash % 21407807219llu; }\n\t\tstatic size_t mod26972146961(size_t hash) { return hash % 26972146961llu; }\n\t\tstatic size_t mod33982775741(size_t hash) { return hash % 33982775741llu; }\n\t\tstatic size_t mod42815614441(size_t hash) { return hash % 42815614441llu; }\n\t\tstatic size_t mod53944293929(size_t hash) { return hash % 53944293929llu; }\n\t\tstatic size_t mod67965551447(size_t hash) { return hash % 67965551447llu; }\n\t\tstatic size_t mod85631228929(size_t hash) { return hash % 85631228929llu; }\n\t\tstatic size_t mod107888587883(size_t hash) { return hash % 107888587883llu; }\n\t\tstatic size_t mod135931102921(size_t hash) { return hash % 135931102921llu; }\n\t\tstatic size_t mod171262457903(size_t hash) { return hash % 171262457903llu; }\n\t\tstatic size_t mod215777175787(size_t hash) { return hash % 215777175787llu; }\n\t\tstatic size_t mod271862205833(size_t hash) { return hash % 271862205833llu; }\n\t\tstatic size_t mod342524915839(size_t hash) { return hash % 342524915839llu; }\n\t\tstatic size_t mod431554351609(size_t hash) { return hash % 431554351609llu; }\n\t\tstatic size_t mod543724411781(size_t hash) { return hash % 543724411781llu; }\n\t\tstatic size_t mod685049831731(size_t hash) { return hash % 685049831731llu; }\n\t\tstatic size_t mod863108703229(size_t hash) { return hash % 863108703229llu; }\n\t\tstatic size_t mod1087448823553(size_t hash) { return hash % 1087448823553llu; }\n\t\tstatic size_t mod1370099663459(size_t hash) { return hash % 1370099663459llu; }\n\t\tstatic size_t mod1726217406467(size_t hash) { return hash % 1726217406467llu; }\n\t\tstatic size_t mod2174897647073(size_t hash) { return hash % 2174897647073llu; }\n\t\tstatic size_t mod2740199326961(size_t hash) { return hash % 2740199326961llu; }\n\t\tstatic size_t mod3452434812973(size_t hash) { return hash % 3452434812973llu; }\n\t\tstatic size_t mod4349795294267(size_t hash) { return hash % 4349795294267llu; }\n\t\tstatic size_t mod5480398654009(size_t hash) { return hash % 5480398654009llu; }\n\t\tstatic size_t mod6904869625999(size_t hash) { return hash % 6904869625999llu; }\n\t\tstatic size_t mod8699590588571(size_t hash) { return hash % 8699590588571llu; }\n\t\tstatic size_t mod10960797308051(size_t hash) { return hash % 10960797308051llu; }\n\t\tstatic size_t mod13809739252051(size_t hash) { return hash % 13809739252051llu; }\n\t\tstatic size_t mod17399181177241(size_t hash) { return hash % 17399181177241llu; }\n\t\tstatic size_t mod21921594616111(size_t hash) { return hash % 21921594616111llu; }\n\t\tstatic size_t mod27619478504183(size_t hash) { return hash % 27619478504183llu; }\n\t\tstatic size_t mod34798362354533(size_t hash) { return hash % 34798362354533llu; }\n\t\tstatic size_t mod43843189232363(size_t hash) { return hash % 43843189232363llu; }\n\t\tstatic size_t mod55238957008387(size_t hash) { return hash % 55238957008387llu; }\n\t\tstatic size_t mod69596724709081(size_t hash) { return hash % 69596724709081llu; }\n\t\tstatic size_t mod87686378464759(size_t hash) { return hash % 87686378464759llu; }\n\t\tstatic size_t mod110477914016779(size_t hash) { return hash % 110477914016779llu; }\n\t\tstatic size_t mod139193449418173(size_t hash) { return hash % 139193449418173llu; }\n\t\tstatic size_t mod175372756929481(size_t hash) { return hash % 175372756929481llu; }\n\t\tstatic size_t mod220955828033581(size_t hash) { return hash % 220955828033581llu; }\n\t\tstatic size_t mod278386898836457(size_t hash) { return hash % 278386898836457llu; }\n\t\tstatic size_t mod350745513859007(size_t hash) { return hash % 350745513859007llu; }\n\t\tstatic size_t mod441911656067171(size_t hash) { return hash % 441911656067171llu; }\n\t\tstatic size_t mod556773797672909(size_t hash) { return hash % 556773797672909llu; }\n\t\tstatic size_t mod701491027718027(size_t hash) { return hash % 701491027718027llu; }\n\t\tstatic size_t mod883823312134381(size_t hash) { return hash % 883823312134381llu; }\n\t\tstatic size_t mod1113547595345903(size_t hash) { return hash % 1113547595345903llu; }\n\t\tstatic size_t mod1402982055436147(size_t hash) { return hash % 1402982055436147llu; }\n\t\tstatic size_t mod1767646624268779(size_t hash) { return hash % 1767646624268779llu; }\n\t\tstatic size_t mod2227095190691797(size_t hash) { return hash % 2227095190691797llu; }\n\t\tstatic size_t mod2805964110872297(size_t hash) { return hash % 2805964110872297llu; }\n\t\tstatic size_t mod3535293248537579(size_t hash) { return hash % 3535293248537579llu; }\n\t\tstatic size_t mod4454190381383713(size_t hash) { return hash % 4454190381383713llu; }\n\t\tstatic size_t mod5611928221744609(size_t hash) { return hash % 5611928221744609llu; }\n\t\tstatic size_t mod7070586497075177(size_t hash) { return hash % 7070586497075177llu; }\n\t\tstatic size_t mod8908380762767489(size_t hash) { return hash % 8908380762767489llu; }\n\t\tstatic size_t mod11223856443489329(size_t hash) { return hash % 11223856443489329llu; }\n\t\tstatic size_t mod14141172994150357(size_t hash) { return hash % 14141172994150357llu; }\n\t\tstatic size_t mod17816761525534927(size_t hash) { return hash % 17816761525534927llu; }\n\t\tstatic size_t mod22447712886978529(size_t hash) { return hash % 22447712886978529llu; }\n\t\tstatic size_t mod28282345988300791(size_t hash) { return hash % 28282345988300791llu; }\n\t\tstatic size_t mod35633523051069991(size_t hash) { return hash % 35633523051069991llu; }\n\t\tstatic size_t mod44895425773957261(size_t hash) { return hash % 44895425773957261llu; }\n\t\tstatic size_t mod56564691976601587(size_t hash) { return hash % 56564691976601587llu; }\n\t\tstatic size_t mod71267046102139967(size_t hash) { return hash % 71267046102139967llu; }\n\t\tstatic size_t mod89790851547914507(size_t hash) { return hash % 89790851547914507llu; }\n\t\tstatic size_t mod113129383953203213(size_t hash) { return hash % 113129383953203213llu; }\n\t\tstatic size_t mod142534092204280003(size_t hash) { return hash % 142534092204280003llu; }\n\t\tstatic size_t mod179581703095829107(size_t hash) { return hash % 179581703095829107llu; }\n\t\tstatic size_t mod226258767906406483(size_t hash) { return hash % 226258767906406483llu; }\n\t\tstatic size_t mod285068184408560057(size_t hash) { return hash % 285068184408560057llu; }\n\t\tstatic size_t mod359163406191658253(size_t hash) { return hash % 359163406191658253llu; }\n\t\tstatic size_t mod452517535812813007(size_t hash) { return hash % 452517535812813007llu; }\n\t\tstatic size_t mod570136368817120201(size_t hash) { return hash % 570136368817120201llu; }\n\t\tstatic size_t mod718326812383316683(size_t hash) { return hash % 718326812383316683llu; }\n\t\tstatic size_t mod905035071625626043(size_t hash) { return hash % 905035071625626043llu; }\n\t\tstatic size_t mod1140272737634240411(size_t hash) { return hash % 1140272737634240411llu; }\n\t\tstatic size_t mod1436653624766633509(size_t hash) { return hash % 1436653624766633509llu; }\n\t\tstatic size_t mod1810070143251252131(size_t hash) { return hash % 1810070143251252131llu; }\n\t\tstatic size_t mod2280545475268481167(size_t hash) { return hash % 2280545475268481167llu; }\n\t\tstatic size_t mod2873307249533267101(size_t hash) { return hash % 2873307249533267101llu; }\n\t\tstatic size_t mod3620140286502504283(size_t hash) { return hash % 3620140286502504283llu; }\n\t\tstatic size_t mod4561090950536962147(size_t hash) { return hash % 4561090950536962147llu; }\n\t\tstatic size_t mod5746614499066534157(size_t hash) { return hash % 5746614499066534157llu; }\n\t\tstatic size_t mod7240280573005008577(size_t hash) { return hash % 7240280573005008577llu; }\n\t\tstatic size_t mod9122181901073924329(size_t hash) { return hash % 9122181901073924329llu; }\n\t\tstatic size_t mod11493228998133068689(size_t hash) { return hash % 11493228998133068689llu; }\n\t\tstatic size_t mod14480561146010017169(size_t hash) { return hash % 14480561146010017169llu; }\n\t\tstatic size_t mod18446744073709551557(size_t hash) { return hash % 18446744073709551557llu; }\n\n\t\tusing mod_function = size_t(*)(size_t);\n\n\t\tmod_function next_size_over(size_t& size) const\n\t\t{\n\t\t\t// prime numbers generated by the following method:\n\t\t\t// 1. start with a prime p = 2\n\t\t\t// 2. go to wolfram alpha and get p = NextPrime(2 * p)\n\t\t\t// 3. repeat 2. until you overflow 64 bits\n\t\t\t// you now have large gaps which you would hit if somebody called reserve() with an unlucky number.\n\t\t\t// 4. to fill the gaps for every prime p go to wolfram alpha and get ClosestPrime(p * 2^(1/3)) and ClosestPrime(p * 2^(2/3)) and put those in the gaps\n\t\t\t// 5. get PrevPrime(2^64) and put it at the end\n\t\t\tstatic constexpr const size_t prime_list[] =\n\t\t\t{\n\t\t\t\t2llu, 3llu, 5llu, 7llu, 11llu, 13llu, 17llu, 23llu, 29llu, 37llu, 47llu,\n\t\t\t\t59llu, 73llu, 97llu, 127llu, 151llu, 197llu, 251llu, 313llu, 397llu,\n\t\t\t\t499llu, 631llu, 797llu, 1009llu, 1259llu, 1597llu, 2011llu, 2539llu,\n\t\t\t\t3203llu, 4027llu, 5087llu, 6421llu, 8089llu, 10193llu, 12853llu, 16193llu,\n\t\t\t\t20399llu, 25717llu, 32401llu, 40823llu, 51437llu, 64811llu, 81649llu,\n\t\t\t\t102877llu, 129607llu, 163307llu, 205759llu, 259229llu, 326617llu,\n\t\t\t\t411527llu, 518509llu, 653267llu, 823117llu, 1037059llu, 1306601llu,\n\t\t\t\t1646237llu, 2074129llu, 2613229llu, 3292489llu, 4148279llu, 5226491llu,\n\t\t\t\t6584983llu, 8296553llu, 10453007llu, 13169977llu, 16593127llu, 20906033llu,\n\t\t\t\t26339969llu, 33186281llu, 41812097llu, 52679969llu, 66372617llu,\n\t\t\t\t83624237llu, 105359939llu, 132745199llu, 167248483llu, 210719881llu,\n\t\t\t\t265490441llu, 334496971llu, 421439783llu, 530980861llu, 668993977llu,\n\t\t\t\t842879579llu, 1061961721llu, 1337987929llu, 1685759167llu, 2123923447llu,\n\t\t\t\t2675975881llu, 3371518343llu, 4247846927llu, 5351951779llu, 6743036717llu,\n\t\t\t\t8495693897llu, 10703903591llu, 13486073473llu, 16991387857llu,\n\t\t\t\t21407807219llu, 26972146961llu, 33982775741llu, 42815614441llu,\n\t\t\t\t53944293929llu, 67965551447llu, 85631228929llu, 107888587883llu,\n\t\t\t\t135931102921llu, 171262457903llu, 215777175787llu, 271862205833llu,\n\t\t\t\t342524915839llu, 431554351609llu, 543724411781llu, 685049831731llu,\n\t\t\t\t863108703229llu, 1087448823553llu, 1370099663459llu, 1726217406467llu,\n\t\t\t\t2174897647073llu, 2740199326961llu, 3452434812973llu, 4349795294267llu,\n\t\t\t\t5480398654009llu, 6904869625999llu, 8699590588571llu, 10960797308051llu,\n\t\t\t\t13809739252051llu, 17399181177241llu, 21921594616111llu, 27619478504183llu,\n\t\t\t\t34798362354533llu, 43843189232363llu, 55238957008387llu, 69596724709081llu,\n\t\t\t\t87686378464759llu, 110477914016779llu, 139193449418173llu,\n\t\t\t\t175372756929481llu, 220955828033581llu, 278386898836457llu,\n\t\t\t\t350745513859007llu, 441911656067171llu, 556773797672909llu,\n\t\t\t\t701491027718027llu, 883823312134381llu, 1113547595345903llu,\n\t\t\t\t1402982055436147llu, 1767646624268779llu, 2227095190691797llu,\n\t\t\t\t2805964110872297llu, 3535293248537579llu, 4454190381383713llu,\n\t\t\t\t5611928221744609llu, 7070586497075177llu, 8908380762767489llu,\n\t\t\t\t11223856443489329llu, 14141172994150357llu, 17816761525534927llu,\n\t\t\t\t22447712886978529llu, 28282345988300791llu, 35633523051069991llu,\n\t\t\t\t44895425773957261llu, 56564691976601587llu, 71267046102139967llu,\n\t\t\t\t89790851547914507llu, 113129383953203213llu, 142534092204280003llu,\n\t\t\t\t179581703095829107llu, 226258767906406483llu, 285068184408560057llu,\n\t\t\t\t359163406191658253llu, 452517535812813007llu, 570136368817120201llu,\n\t\t\t\t718326812383316683llu, 905035071625626043llu, 1140272737634240411llu,\n\t\t\t\t1436653624766633509llu, 1810070143251252131llu, 2280545475268481167llu,\n\t\t\t\t2873307249533267101llu, 3620140286502504283llu, 4561090950536962147llu,\n\t\t\t\t5746614499066534157llu, 7240280573005008577llu, 9122181901073924329llu,\n\t\t\t\t11493228998133068689llu, 14480561146010017169llu, 18446744073709551557llu\n\t\t\t};\n\t\t\tstatic constexpr size_t(* const mod_functions[])(size_t) =\n\t\t\t{\n\t\t\t\t&mod0, &mod2, &mod3, &mod5, &mod7, &mod11, &mod13, &mod17, &mod23, &mod29, &mod37,\n\t\t\t\t&mod47, &mod59, &mod73, &mod97, &mod127, &mod151, &mod197, &mod251, &mod313, &mod397,\n\t\t\t\t&mod499, &mod631, &mod797, &mod1009, &mod1259, &mod1597, &mod2011, &mod2539, &mod3203,\n\t\t\t\t&mod4027, &mod5087, &mod6421, &mod8089, &mod10193, &mod12853, &mod16193, &mod20399,\n\t\t\t\t&mod25717, &mod32401, &mod40823, &mod51437, &mod64811, &mod81649, &mod102877,\n\t\t\t\t&mod129607, &mod163307, &mod205759, &mod259229, &mod326617, &mod411527, &mod518509,\n\t\t\t\t&mod653267, &mod823117, &mod1037059, &mod1306601, &mod1646237, &mod2074129,\n\t\t\t\t&mod2613229, &mod3292489, &mod4148279, &mod5226491, &mod6584983, &mod8296553,\n\t\t\t\t&mod10453007, &mod13169977, &mod16593127, &mod20906033, &mod26339969, &mod33186281,\n\t\t\t\t&mod41812097, &mod52679969, &mod66372617, &mod83624237, &mod105359939, &mod132745199,\n\t\t\t\t&mod167248483, &mod210719881, &mod265490441, &mod334496971, &mod421439783,\n\t\t\t\t&mod530980861, &mod668993977, &mod842879579, &mod1061961721, &mod1337987929,\n\t\t\t\t&mod1685759167, &mod2123923447, &mod2675975881, &mod3371518343, &mod4247846927,\n\t\t\t\t&mod5351951779, &mod6743036717, &mod8495693897, &mod10703903591, &mod13486073473,\n\t\t\t\t&mod16991387857, &mod21407807219, &mod26972146961, &mod33982775741, &mod42815614441,\n\t\t\t\t&mod53944293929, &mod67965551447, &mod85631228929, &mod107888587883, &mod135931102921,\n\t\t\t\t&mod171262457903, &mod215777175787, &mod271862205833, &mod342524915839,\n\t\t\t\t&mod431554351609, &mod543724411781, &mod685049831731, &mod863108703229,\n\t\t\t\t&mod1087448823553, &mod1370099663459, &mod1726217406467, &mod2174897647073,\n\t\t\t\t&mod2740199326961, &mod3452434812973, &mod4349795294267, &mod5480398654009,\n\t\t\t\t&mod6904869625999, &mod8699590588571, &mod10960797308051, &mod13809739252051,\n\t\t\t\t&mod17399181177241, &mod21921594616111, &mod27619478504183, &mod34798362354533,\n\t\t\t\t&mod43843189232363, &mod55238957008387, &mod69596724709081, &mod87686378464759,\n\t\t\t\t&mod110477914016779, &mod139193449418173, &mod175372756929481, &mod220955828033581,\n\t\t\t\t&mod278386898836457, &mod350745513859007, &mod441911656067171, &mod556773797672909,\n\t\t\t\t&mod701491027718027, &mod883823312134381, &mod1113547595345903, &mod1402982055436147,\n\t\t\t\t&mod1767646624268779, &mod2227095190691797, &mod2805964110872297, &mod3535293248537579,\n\t\t\t\t&mod4454190381383713, &mod5611928221744609, &mod7070586497075177, &mod8908380762767489,\n\t\t\t\t&mod11223856443489329, &mod14141172994150357, &mod17816761525534927,\n\t\t\t\t&mod22447712886978529, &mod28282345988300791, &mod35633523051069991,\n\t\t\t\t&mod44895425773957261, &mod56564691976601587, &mod71267046102139967,\n\t\t\t\t&mod89790851547914507, &mod113129383953203213, &mod142534092204280003,\n\t\t\t\t&mod179581703095829107, &mod226258767906406483, &mod285068184408560057,\n\t\t\t\t&mod359163406191658253, &mod452517535812813007, &mod570136368817120201,\n\t\t\t\t&mod718326812383316683, &mod905035071625626043, &mod1140272737634240411,\n\t\t\t\t&mod1436653624766633509, &mod1810070143251252131, &mod2280545475268481167,\n\t\t\t\t&mod2873307249533267101, &mod3620140286502504283, &mod4561090950536962147,\n\t\t\t\t&mod5746614499066534157, &mod7240280573005008577, &mod9122181901073924329,\n\t\t\t\t&mod11493228998133068689, &mod14480561146010017169, &mod18446744073709551557\n\t\t\t};\n\t\t\tconst size_t* found = std::lower_bound(std::begin(prime_list), std::end(prime_list) - 1, size);\n\t\t\tsize = *found;\n\t\t\treturn mod_functions[1 + found - prime_list];\n\t\t}\n\t\tvoid commit(mod_function new_mod_function)\n\t\t{\n\t\t\tcurrent_mod_function = new_mod_function;\n\t\t}\n\t\tvoid reset()\n\t\t{\n\t\t\tcurrent_mod_function = &mod0;\n\t\t}\n\n\t\tsize_t index_for_hash(size_t hash, size_t /*num_slots_minus_one*/) const\n\t\t{\n\t\t\treturn current_mod_function(hash);\n\t\t}\n\t\tsize_t keep_in_range(size_t index, size_t num_slots_minus_one) const\n\t\t{\n\t\t\treturn index > num_slots_minus_one ? current_mod_function(index) : index;\n\t\t}\n\n\tprivate:\n\t\tmod_function current_mod_function = &mod0;\n\t};\n\n\tstruct power_of_two_hash_policy\n\t{\n\t\tsize_t index_for_hash(size_t hash, size_t num_slots_minus_one) const\n\t\t{\n\t\t\treturn hash & num_slots_minus_one;\n\t\t}\n\t\tsize_t keep_in_range(size_t index, size_t num_slots_minus_one) const\n\t\t{\n\t\t\treturn index_for_hash(index, num_slots_minus_one);\n\t\t}\n\t\tint8_t next_size_over(size_t& size) const\n\t\t{\n\t\t\tsize = detailv3::next_power_of_two(size);\n\t\t\treturn 0;\n\t\t}\n\t\tvoid commit(int8_t)\n\t\t{\n\t\t}\n\t\tvoid reset()\n\t\t{\n\t\t}\n\n\t};\n\n\tstruct fibonacci_hash_policy\n\t{\n\t\tsize_t index_for_hash(size_t hash, size_t /*num_slots_minus_one*/) const\n\t\t{\n\t\t\treturn (11400714819323198485ull * hash) >> shift;\n\t\t}\n\t\tsize_t keep_in_range(size_t index, size_t num_slots_minus_one) const\n\t\t{\n\t\t\treturn index & num_slots_minus_one;\n\t\t}\n\n\t\tint8_t next_size_over(size_t& size) const\n\t\t{\n\t\t\tsize = std::max(size_t(2), detailv3::next_power_of_two(size));\n\t\t\treturn 64 - detailv3::log2(size);\n\t\t}\n\t\tvoid commit(int8_t shift)\n\t\t{\n\t\t\tthis->shift = shift;\n\t\t}\n\t\tvoid reset()\n\t\t{\n\t\t\tshift = 63;\n\t\t}\n\n\tprivate:\n\t\tint8_t shift = 63;\n\t};\n\n\ttemplate<typename K, typename V, typename H = std::hash<K>, typename E = std::equal_to<K>, typename A = std::allocator<std::pair<K, V> > >\n\tclass flat_hash_map\n\t\t: public detailv3::sherwood_v3_table\n\t\t<\n\t\tstd::pair<K, V>,\n\t\tK,\n\t\tH,\n\t\tdetailv3::KeyOrValueHasher<K, std::pair<K, V>, H>,\n\t\tE,\n\t\tdetailv3::KeyOrValueEquality<K, std::pair<K, V>, E>,\n\t\tA,\n\t\ttypename std::allocator_traits<A>::template rebind_alloc<detailv3::sherwood_v3_entry<std::pair<K, V>>>\n\t\t>\n\t{\n\t\tusing Table = detailv3::sherwood_v3_table\n\t\t\t<\n\t\t\tstd::pair<K, V>,\n\t\t\tK,\n\t\t\tH,\n\t\t\tdetailv3::KeyOrValueHasher<K, std::pair<K, V>, H>,\n\t\t\tE,\n\t\t\tdetailv3::KeyOrValueEquality<K, std::pair<K, V>, E>,\n\t\t\tA,\n\t\t\ttypename std::allocator_traits<A>::template rebind_alloc<detailv3::sherwood_v3_entry<std::pair<K, V>>>\n\t\t\t>;\n\tpublic:\n\n\t\tusing key_type = K;\n\t\tusing mapped_type = V;\n\n\t\tusing Table::Table;\n\t\tflat_hash_map() = default;\n\n\t\tinline V& operator[](const K& key)\n\t\t{\n\t\t\treturn emplace(key, convertible_to_value()).first->second;\n\t\t}\n\t\tinline V& operator[](K&& key)\n\t\t{\n\t\t\treturn emplace(std::move(key), convertible_to_value()).first->second;\n\t\t}\n\t\tV& at(const K& key)\n\t\t{\n\t\t\tauto found = this->find(key);\n\t\t\tif (found == this->end())\n\t\t\t\tthrow std::out_of_range(\"Argument passed to at() was not in the map.\");\n\t\t\treturn found->second;\n\t\t}\n\t\tconst V& at(const K& key) const\n\t\t{\n\t\t\tauto found = this->find(key);\n\t\t\tif (found == this->end())\n\t\t\t\tthrow std::out_of_range(\"Argument passed to at() was not in the map.\");\n\t\t\treturn found->second;\n\t\t}\n\n\t\tusing Table::emplace;\n\t\tstd::pair<typename Table::iterator, bool> emplace()\n\t\t{\n\t\t\treturn emplace(key_type(), convertible_to_value());\n\t\t}\n\t\ttemplate<typename M>\n\t\tstd::pair<typename Table::iterator, bool> insert_or_assign(const key_type& key, M&& m)\n\t\t{\n\t\t\tauto emplace_result = emplace(key, std::forward<M>(m));\n\t\t\tif (!emplace_result.second)\n\t\t\t\templace_result.first->second = std::forward<M>(m);\n\t\t\treturn emplace_result;\n\t\t}\n\t\ttemplate<typename M>\n\t\tstd::pair<typename Table::iterator, bool> insert_or_assign(key_type&& key, M&& m)\n\t\t{\n\t\t\tauto emplace_result = emplace(std::move(key), std::forward<M>(m));\n\t\t\tif (!emplace_result.second)\n\t\t\t\templace_result.first->second = std::forward<M>(m);\n\t\t\treturn emplace_result;\n\t\t}\n\t\ttemplate<typename M>\n\t\ttypename Table::iterator insert_or_assign(typename Table::const_iterator, const key_type& key, M&& m)\n\t\t{\n\t\t\treturn insert_or_assign(key, std::forward<M>(m)).first;\n\t\t}\n\t\ttemplate<typename M>\n\t\ttypename Table::iterator insert_or_assign(typename Table::const_iterator, key_type&& key, M&& m)\n\t\t{\n\t\t\treturn insert_or_assign(std::move(key), std::forward<M>(m)).first;\n\t\t}\n\n\t\tfriend bool operator==(const flat_hash_map& lhs, const flat_hash_map& rhs)\n\t\t{\n\t\t\tif (lhs.size() != rhs.size())\n\t\t\t\treturn false;\n\t\t\tfor (const typename Table::value_type& value : lhs)\n\t\t\t{\n\t\t\t\tauto found = rhs.find(value.first);\n\t\t\t\tif (found == rhs.end())\n\t\t\t\t\treturn false;\n\t\t\t\telse if (value.second != found->second)\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\tfriend bool operator!=(const flat_hash_map& lhs, const flat_hash_map& rhs)\n\t\t{\n\t\t\treturn !(lhs == rhs);\n\t\t}\n\n\tprivate:\n\t\tstruct convertible_to_value\n\t\t{\n\t\t\toperator V() const\n\t\t\t{\n\t\t\t\treturn V();\n\t\t\t}\n\t\t};\n\t};\n\n\ttemplate<typename T, typename H = std::hash<T>, typename E = std::equal_to<T>, typename A = std::allocator<T> >\n\tclass flat_hash_set\n\t\t: public detailv3::sherwood_v3_table\n\t\t<\n\t\tT,\n\t\tT,\n\t\tH,\n\t\tdetailv3::functor_storage<size_t, H>,\n\t\tE,\n\t\tdetailv3::functor_storage<bool, E>,\n\t\tA,\n\t\ttypename std::allocator_traits<A>::template rebind_alloc<detailv3::sherwood_v3_entry<T>>\n\t\t>\n\t{\n\t\tusing Table = detailv3::sherwood_v3_table\n\t\t\t<\n\t\t\tT,\n\t\t\tT,\n\t\t\tH,\n\t\t\tdetailv3::functor_storage<size_t, H>,\n\t\t\tE,\n\t\t\tdetailv3::functor_storage<bool, E>,\n\t\t\tA,\n\t\t\ttypename std::allocator_traits<A>::template rebind_alloc<detailv3::sherwood_v3_entry<T>>\n\t\t\t>;\n\tpublic:\n\n\t\tusing key_type = T;\n\n\t\tusing Table::Table;\n\t\tflat_hash_set() = default;\n\n\t\ttemplate<typename... Args>\n\t\tstd::pair<typename Table::iterator, bool> emplace(Args &&... args)\n\t\t{\n\t\t\treturn Table::emplace(T(std::forward<Args>(args)...));\n\t\t}\n\t\tstd::pair<typename Table::iterator, bool> emplace(const key_type& arg)\n\t\t{\n\t\t\treturn Table::emplace(arg);\n\t\t}\n\t\tstd::pair<typename Table::iterator, bool> emplace(key_type& arg)\n\t\t{\n\t\t\treturn Table::emplace(arg);\n\t\t}\n\t\tstd::pair<typename Table::iterator, bool> emplace(const key_type&& arg)\n\t\t{\n\t\t\treturn Table::emplace(std::move(arg));\n\t\t}\n\t\tstd::pair<typename Table::iterator, bool> emplace(key_type&& arg)\n\t\t{\n\t\t\treturn Table::emplace(std::move(arg));\n\t\t}\n\n\t\tfriend bool operator==(const flat_hash_set& lhs, const flat_hash_set& rhs)\n\t\t{\n\t\t\tif (lhs.size() != rhs.size())\n\t\t\t\treturn false;\n\t\t\tfor (const T& value : lhs)\n\t\t\t{\n\t\t\t\tif (rhs.find(value) == rhs.end())\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\tfriend bool operator!=(const flat_hash_set& lhs, const flat_hash_set& rhs)\n\t\t{\n\t\t\treturn !(lhs == rhs);\n\t\t}\n\t};\n\n\n\ttemplate<typename T>\n\tstruct power_of_two_std_hash : std::hash<T>\n\t{\n\t\ttypedef ska::power_of_two_hash_policy hash_policy;\n\t};\n\n} // end namespace ska\n"
  },
  {
    "path": "src/util/containers/robin_hood.h",
    "content": "//                 ______  _____                 ______                _________\n//  ______________ ___  /_ ___(_)_______         ___  /_ ______ ______ ______  /\n//  __  ___/_  __ \\__  __ \\__  / __  __ \\        __  __ \\_  __ \\_  __ \\_  __  /\n//  _  /    / /_/ /_  /_/ /_  /  _  / / /        _  / / // /_/ // /_/ // /_/ /\n//  /_/     \\____/ /_.___/ /_/   /_/ /_/ ________/_/ /_/ \\____/ \\____/ \\__,_/\n//                                      _/_____/\n//\n// Fast & memory efficient hashtable based on robin hood hashing for C++11/14/17/20\n// https://github.com/martinus/robin-hood-hashing\n//\n// Licensed under the MIT License <http://opensource.org/licenses/MIT>.\n// SPDX-License-Identifier: MIT\n// Copyright (c) 2018-2020 Martin Ankerl <http://martin.ankerl.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#ifndef ROBIN_HOOD_H_INCLUDED\n#define ROBIN_HOOD_H_INCLUDED\n\n// see https://semver.org/\n#define ROBIN_HOOD_VERSION_MAJOR 3  // for incompatible API changes\n#define ROBIN_HOOD_VERSION_MINOR 10 // for adding functionality in a backwards-compatible manner\n#define ROBIN_HOOD_VERSION_PATCH 0  // for backwards-compatible bug fixes\n\n#include <algorithm>\n#include <cstdlib>\n#include <cstring>\n#include <functional>\n#include <memory> // only to support hash of smart pointers\n#include <stdexcept>\n#include <string>\n#include <type_traits>\n#include <utility>\n#if __cplusplus >= 201703L\n#    include <string_view>\n#endif\n\n// #define ROBIN_HOOD_LOG_ENABLED\n#ifdef ROBIN_HOOD_LOG_ENABLED\n#    include <iostream>\n#    define ROBIN_HOOD_LOG(...) \\\n        std::cout << __FUNCTION__ << \"@\" << __LINE__ << \": \" << __VA_ARGS__ << std::endl;\n#else\n#    define ROBIN_HOOD_LOG(x)\n#endif\n\n// #define ROBIN_HOOD_TRACE_ENABLED\n#ifdef ROBIN_HOOD_TRACE_ENABLED\n#    include <iostream>\n#    define ROBIN_HOOD_TRACE(...) \\\n        std::cout << __FUNCTION__ << \"@\" << __LINE__ << \": \" << __VA_ARGS__ << std::endl;\n#else\n#    define ROBIN_HOOD_TRACE(x)\n#endif\n\n// #define ROBIN_HOOD_COUNT_ENABLED\n#ifdef ROBIN_HOOD_COUNT_ENABLED\n#    include <iostream>\n#    define ROBIN_HOOD_COUNT(x) ++counts().x;\nnamespace robin_hood {\n\tstruct Counts {\n\t\tuint64_t shiftUp{};\n\t\tuint64_t shiftDown{};\n\t};\n\tinline std::ostream& operator<<(std::ostream& os, Counts const& c) {\n\t\treturn os << c.shiftUp << \" shiftUp\" << std::endl << c.shiftDown << \" shiftDown\" << std::endl;\n\t}\n\n\tstatic Counts& counts() {\n\t\tstatic Counts counts{};\n\t\treturn counts;\n\t}\n} // namespace robin_hood\n#else\n#    define ROBIN_HOOD_COUNT(x)\n#endif\n\n// all non-argument macros should use this facility. See\n// https://www.fluentcpp.com/2019/05/28/better-macros-better-flags/\n#define ROBIN_HOOD(x) ROBIN_HOOD_PRIVATE_DEFINITION_##x()\n\n// mark unused members with this macro\n#define ROBIN_HOOD_UNUSED(identifier)\n\n// bitness\n#if SIZE_MAX == UINT32_MAX\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 32\n#elif SIZE_MAX == UINT64_MAX\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 64\n#else\n#    error Unsupported bitness\n#endif\n\n// endianess\n#ifdef _MSC_VER\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() 1\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() 0\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() \\\n        (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)\n#endif\n\n// inline\n#ifdef _MSC_VER\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __declspec(noinline)\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __attribute__((noinline))\n#endif\n\n// exceptions\n#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 0\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 1\n#endif\n\n// count leading/trailing bits\n#if !defined(ROBIN_HOOD_DISABLE_INTRINSICS)\n#    ifdef _MSC_VER\n#        if ROBIN_HOOD(BITNESS) == 32\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward\n#        else\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward64\n#        endif\n#        include <intrin.h>\n#        pragma intrinsic(ROBIN_HOOD(BITSCANFORWARD))\n#        define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x)                                       \\\n            [](size_t mask) noexcept -> int {                                             \\\n                unsigned long index;                                                      \\\n                return ROBIN_HOOD(BITSCANFORWARD)(&index, mask) ? static_cast<int>(index) \\\n                                                                : ROBIN_HOOD(BITNESS);    \\\n            }(x)\n#    else\n#        if ROBIN_HOOD(BITNESS) == 32\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl\n#        else\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll\n#            define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll\n#        endif\n#        define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS))\n#        define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS))\n#    endif\n#endif\n\n// fallthrough\n#ifndef __has_cpp_attribute // For backwards compatibility\n#    define __has_cpp_attribute(x) 0\n#endif\n#if __has_cpp_attribute(clang::fallthrough)\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[clang::fallthrough]]\n#elif __has_cpp_attribute(gnu::fallthrough)\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[gnu::fallthrough]]\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH()\n#endif\n\n// likely/unlikely\n#ifdef _MSC_VER\n#    define ROBIN_HOOD_LIKELY(condition) condition\n#    define ROBIN_HOOD_UNLIKELY(condition) condition\n#else\n#    define ROBIN_HOOD_LIKELY(condition) __builtin_expect(condition, 1)\n#    define ROBIN_HOOD_UNLIKELY(condition) __builtin_expect(condition, 0)\n#endif\n\n// detect if native wchar_t type is availiable in MSVC\n#ifdef _MSC_VER\n#    ifdef _NATIVE_WCHAR_T_DEFINED\n#        define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1\n#    else\n#        define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 0\n#    endif\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1\n#endif\n\n// workaround missing \"is_trivially_copyable\" in g++ < 5.0\n// See https://stackoverflow.com/a/31798726/48181\n#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)\n#    define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)\n#else\n#    define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value\n#endif\n\n// helpers for C++ versions, see https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html\n#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX() __cplusplus\n#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX98() 199711L\n#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX11() 201103L\n#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX14() 201402L\n#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX17() 201703L\n\n#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() [[nodiscard]]\n#else\n#    define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD()\n#endif\n\nnamespace robin_hood {\n\n#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)\n#    define ROBIN_HOOD_STD std\n#else\n\n\t// c++11 compatibility layer\n\tnamespace ROBIN_HOOD_STD {\n\t\ttemplate <class T>\n\t\tstruct alignment_of\n\t\t\t: std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {};\n\n\t\ttemplate <class T, T... Ints>\n\t\tclass integer_sequence {\n\t\tpublic:\n\t\t\tusing value_type = T;\n\t\t\tstatic_assert(std::is_integral<value_type>::value, \"not integral type\");\n\t\t\tstatic constexpr std::size_t size() noexcept {\n\t\t\t\treturn sizeof...(Ints);\n\t\t\t}\n\t\t};\n\t\ttemplate <std::size_t... Inds>\n\t\tusing index_sequence = integer_sequence<std::size_t, Inds...>;\n\n\t\tnamespace detail_ {\n\t\t\ttemplate <class T, T Begin, T End, bool>\n\t\t\tstruct IntSeqImpl {\n\t\t\t\tusing TValue = T;\n\t\t\t\tstatic_assert(std::is_integral<TValue>::value, \"not integral type\");\n\t\t\t\tstatic_assert(Begin >= 0 && Begin < End, \"unexpected argument (Begin<0 || Begin<=End)\");\n\n\t\t\t\ttemplate <class, class>\n\t\t\t\tstruct IntSeqCombiner;\n\n\t\t\t\ttemplate <TValue... Inds0, TValue... Inds1>\n\t\t\t\tstruct IntSeqCombiner<integer_sequence<TValue, Inds0...>, integer_sequence<TValue, Inds1...>> {\n\t\t\t\t\tusing TResult = integer_sequence<TValue, Inds0..., Inds1...>;\n\t\t\t\t};\n\n\t\t\t\tusing TResult =\n\t\t\t\t\ttypename IntSeqCombiner<typename IntSeqImpl<TValue, Begin, Begin + (End - Begin) / 2,\n\t\t\t\t\t(End - Begin) / 2 == 1>::TResult,\n\t\t\t\t\ttypename IntSeqImpl<TValue, Begin + (End - Begin) / 2, End,\n\t\t\t\t\t(End - Begin + 1) / 2 == 1>::TResult>::TResult;\n\t\t\t};\n\n\t\t\ttemplate <class T, T Begin>\n\t\t\tstruct IntSeqImpl<T, Begin, Begin, false> {\n\t\t\t\tusing TValue = T;\n\t\t\t\tstatic_assert(std::is_integral<TValue>::value, \"not integral type\");\n\t\t\t\tstatic_assert(Begin >= 0, \"unexpected argument (Begin<0)\");\n\t\t\t\tusing TResult = integer_sequence<TValue>;\n\t\t\t};\n\n\t\t\ttemplate <class T, T Begin, T End>\n\t\t\tstruct IntSeqImpl<T, Begin, End, true> {\n\t\t\t\tusing TValue = T;\n\t\t\t\tstatic_assert(std::is_integral<TValue>::value, \"not integral type\");\n\t\t\t\tstatic_assert(Begin >= 0, \"unexpected argument (Begin<0)\");\n\t\t\t\tusing TResult = integer_sequence<TValue, Begin>;\n\t\t\t};\n\t\t} // namespace detail_\n\n\t\ttemplate <class T, T N>\n\t\tusing make_integer_sequence = typename detail_::IntSeqImpl<T, 0, N, (N - 0) == 1>::TResult;\n\n\t\ttemplate <std::size_t N>\n\t\tusing make_index_sequence = make_integer_sequence<std::size_t, N>;\n\n\t\ttemplate <class... T>\n\t\tusing index_sequence_for = make_index_sequence<sizeof...(T)>;\n\n\t} // namespace ROBIN_HOOD_STD\n\n#endif\n\n\tnamespace detail {\n\n\t\t// make sure we static_cast to the correct type for hash_int\n#if ROBIN_HOOD(BITNESS) == 64\n\t\tusing SizeT = uint64_t;\n#else\n\t\tusing SizeT = uint32_t;\n#endif\n\n\t\ttemplate <typename T>\n\t\tT rotr(T x, unsigned k) {\n\t\t\treturn (x >> k) | (x << (8U * sizeof(T) - k));\n\t\t}\n\n\t\t// This cast gets rid of warnings like \"cast from 'uint8_t*' {aka 'unsigned char*'} to\n\t\t// 'uint64_t*' {aka 'long unsigned int*'} increases required alignment of target type\". Use with\n\t\t// care!\n\t\ttemplate <typename T>\n\t\tinline T reinterpret_cast_no_cast_align_warning(void* ptr) noexcept {\n\t\t\treturn reinterpret_cast<T>(ptr);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tinline T reinterpret_cast_no_cast_align_warning(void const* ptr) noexcept {\n\t\t\treturn reinterpret_cast<T>(ptr);\n\t\t}\n\n\t\t// make sure this is not inlined as it is slow and dramatically enlarges code, thus making other\n\t\t// inlinings more difficult. Throws are also generally the slow path.\n\t\ttemplate <typename E, typename... Args>\n\t\t[[noreturn]] ROBIN_HOOD(NOINLINE)\n#if ROBIN_HOOD(HAS_EXCEPTIONS)\n\t\t\tvoid doThrow(Args&&... args) {\n\t\t\t// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)\n\t\t\tthrow E(std::forward<Args>(args)...);\n\t\t}\n#else\n\t\t\tvoid doThrow(Args&&... ROBIN_HOOD_UNUSED(args) /*unused*/) {\n\t\t\tabort();\n\t\t}\n#endif\n\n\t\ttemplate <typename E, typename T, typename... Args>\n\t\tT* assertNotNull(T* t, Args&&... args) {\n\t\t\tif (ROBIN_HOOD_UNLIKELY(nullptr == t)) {\n\t\t\t\tdoThrow<E>(std::forward<Args>(args)...);\n\t\t\t}\n\t\t\treturn t;\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tinline T unaligned_load(void const* ptr) noexcept {\n\t\t\t// using memcpy so we don't get into unaligned load problems.\n\t\t\t// compiler should optimize this very well anyways.\n\t\t\tT t;\n\t\t\tstd::memcpy(&t, ptr, sizeof(T));\n\t\t\treturn t;\n\t\t}\n\n\t\t// Allocates bulks of memory for objects of type T. This deallocates the memory in the destructor,\n\t\t// and keeps a linked list of the allocated memory around. Overhead per allocation is the size of a\n\t\t// pointer.\n\t\ttemplate <typename T, size_t MinNumAllocs = 4, size_t MaxNumAllocs = 256>\n\t\tclass BulkPoolAllocator {\n\t\tpublic:\n\t\t\tBulkPoolAllocator() noexcept = default;\n\n\t\t\t// does not copy anything, just creates a new allocator.\n\t\t\tBulkPoolAllocator(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept\n\t\t\t\t: mHead(nullptr)\n\t\t\t\t, mListForFree(nullptr) {}\n\n\t\t\tBulkPoolAllocator(BulkPoolAllocator&& o) noexcept\n\t\t\t\t: mHead(o.mHead)\n\t\t\t\t, mListForFree(o.mListForFree) {\n\t\t\t\to.mListForFree = nullptr;\n\t\t\t\to.mHead = nullptr;\n\t\t\t}\n\n\t\t\tBulkPoolAllocator& operator=(BulkPoolAllocator&& o) noexcept {\n\t\t\t\treset();\n\t\t\t\tmHead = o.mHead;\n\t\t\t\tmListForFree = o.mListForFree;\n\t\t\t\to.mListForFree = nullptr;\n\t\t\t\to.mHead = nullptr;\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tBulkPoolAllocator&\n\t\t\t\t// NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)\n\t\t\t\toperator=(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept {\n\t\t\t\t// does not do anything\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\t~BulkPoolAllocator() noexcept {\n\t\t\t\treset();\n\t\t\t}\n\n\t\t\t// Deallocates all allocated memory.\n\t\t\tvoid reset() noexcept {\n\t\t\t\twhile (mListForFree) {\n\t\t\t\t\tT* tmp = *mListForFree;\n\t\t\t\t\tROBIN_HOOD_LOG(\"std::free\")\n\t\t\t\t\t\tstd::free(mListForFree);\n\t\t\t\t\tmListForFree = reinterpret_cast_no_cast_align_warning<T**>(tmp);\n\t\t\t\t}\n\t\t\t\tmHead = nullptr;\n\t\t\t}\n\n\t\t\t// allocates, but does NOT initialize. Use in-place new constructor, e.g.\n\t\t\t//   T* obj = pool.allocate();\n\t\t\t//   ::new (static_cast<void*>(obj)) T();\n\t\t\tT* allocate() {\n\t\t\t\tT* tmp = mHead;\n\t\t\t\tif (!tmp) {\n\t\t\t\t\ttmp = performAllocation();\n\t\t\t\t}\n\n\t\t\t\tmHead = *reinterpret_cast_no_cast_align_warning<T**>(tmp);\n\t\t\t\treturn tmp;\n\t\t\t}\n\n\t\t\t// does not actually deallocate but puts it in store.\n\t\t\t// make sure you have already called the destructor! e.g. with\n\t\t\t//  obj->~T();\n\t\t\t//  pool.deallocate(obj);\n\t\t\tvoid deallocate(T* obj) noexcept {\n\t\t\t\t*reinterpret_cast_no_cast_align_warning<T**>(obj) = mHead;\n\t\t\t\tmHead = obj;\n\t\t\t}\n\n\t\t\t// Adds an already allocated block of memory to the allocator. This allocator is from now on\n\t\t\t// responsible for freeing the data (with free()). If the provided data is not large enough to\n\t\t\t// make use of, it is immediately freed. Otherwise it is reused and freed in the destructor.\n\t\t\tvoid addOrFree(void* ptr, const size_t numBytes) noexcept {\n\t\t\t\t// calculate number of available elements in ptr\n\t\t\t\tif (numBytes < ALIGNMENT + ALIGNED_SIZE) {\n\t\t\t\t\t// not enough data for at least one element. Free and return.\n\t\t\t\t\tROBIN_HOOD_LOG(\"std::free\")\n\t\t\t\t\t\tstd::free(ptr);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tROBIN_HOOD_LOG(\"add to buffer\")\n\t\t\t\t\t\tadd(ptr, numBytes);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid swap(BulkPoolAllocator<T, MinNumAllocs, MaxNumAllocs>& other) noexcept {\n\t\t\t\tusing std::swap;\n\t\t\t\tswap(mHead, other.mHead);\n\t\t\t\tswap(mListForFree, other.mListForFree);\n\t\t\t}\n\n\t\tprivate:\n\t\t\t// iterates the list of allocated memory to calculate how many to alloc next.\n\t\t\t// Recalculating this each time saves us a size_t member.\n\t\t\t// This ignores the fact that memory blocks might have been added manually with addOrFree. In\n\t\t\t// practice, this should not matter much.\n\t\t\tROBIN_HOOD(NODISCARD) size_t calcNumElementsToAlloc() const noexcept {\n\t\t\t\tauto tmp = mListForFree;\n\t\t\t\tsize_t numAllocs = MinNumAllocs;\n\n\t\t\t\twhile (numAllocs * 2 <= MaxNumAllocs && tmp) {\n\t\t\t\t\tauto x = reinterpret_cast<T***>(tmp);\n\t\t\t\t\ttmp = *x;\n\t\t\t\t\tnumAllocs *= 2;\n\t\t\t\t}\n\n\t\t\t\treturn numAllocs;\n\t\t\t}\n\n\t\t\t// WARNING: Underflow if numBytes < ALIGNMENT! This is guarded in addOrFree().\n\t\t\tvoid add(void* ptr, const size_t numBytes) noexcept {\n\t\t\t\tconst size_t numElements = (numBytes - ALIGNMENT) / ALIGNED_SIZE;\n\n\t\t\t\tauto data = reinterpret_cast<T**>(ptr);\n\n\t\t\t\t// link free list\n\t\t\t\tauto x = reinterpret_cast<T***>(data);\n\t\t\t\t*x = mListForFree;\n\t\t\t\tmListForFree = data;\n\n\t\t\t\t// create linked list for newly allocated data\n\t\t\t\tauto* const headT =\n\t\t\t\t\treinterpret_cast_no_cast_align_warning<T*>(reinterpret_cast<char*>(ptr) + ALIGNMENT);\n\n\t\t\t\tauto* const head = reinterpret_cast<char*>(headT);\n\n\t\t\t\t// Visual Studio compiler automatically unrolls this loop, which is pretty cool\n\t\t\t\tfor (size_t i = 0; i < numElements; ++i) {\n\t\t\t\t\t*reinterpret_cast_no_cast_align_warning<char**>(head + i * ALIGNED_SIZE) =\n\t\t\t\t\t\thead + (i + 1) * ALIGNED_SIZE;\n\t\t\t\t}\n\n\t\t\t\t// last one points to 0\n\t\t\t\t*reinterpret_cast_no_cast_align_warning<T**>(head + (numElements - 1) * ALIGNED_SIZE) =\n\t\t\t\t\tmHead;\n\t\t\t\tmHead = headT;\n\t\t\t}\n\n\t\t\t// Called when no memory is available (mHead == 0).\n\t\t\t// Don't inline this slow path.\n\t\t\tROBIN_HOOD(NOINLINE) T* performAllocation() {\n\t\t\t\tsize_t const numElementsToAlloc = calcNumElementsToAlloc();\n\n\t\t\t\t// alloc new memory: [prev |T, T, ... T]\n\t\t\t\tsize_t const bytes = ALIGNMENT + ALIGNED_SIZE * numElementsToAlloc;\n\t\t\t\tROBIN_HOOD_LOG(\"std::malloc \" << bytes << \" = \" << ALIGNMENT << \" + \" << ALIGNED_SIZE\n\t\t\t\t\t<< \" * \" << numElementsToAlloc)\n\t\t\t\t\tadd(assertNotNull<std::bad_alloc>(std::malloc(bytes)), bytes);\n\t\t\t\treturn mHead;\n\t\t\t}\n\n\t\t\t// enforce byte alignment of the T's\n#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)\n\t\t\tstatic constexpr size_t ALIGNMENT =\n\t\t\t\t(std::max)(std::alignment_of<T>::value, std::alignment_of<T*>::value);\n#else\n\t\t\tstatic const size_t ALIGNMENT =\n\t\t\t\t(ROBIN_HOOD_STD::alignment_of<T>::value > ROBIN_HOOD_STD::alignment_of<T*>::value)\n\t\t\t\t? ROBIN_HOOD_STD::alignment_of<T>::value\n\t\t\t\t: +ROBIN_HOOD_STD::alignment_of<T*>::value; // the + is for walkarround\n#endif\n\n\t\t\tstatic constexpr size_t ALIGNED_SIZE = ((sizeof(T) - 1) / ALIGNMENT + 1) * ALIGNMENT;\n\n\t\t\tstatic_assert(MinNumAllocs >= 1, \"MinNumAllocs\");\n\t\t\tstatic_assert(MaxNumAllocs >= MinNumAllocs, \"MaxNumAllocs\");\n\t\t\tstatic_assert(ALIGNED_SIZE >= sizeof(T*), \"ALIGNED_SIZE\");\n\t\t\tstatic_assert(0 == (ALIGNED_SIZE % sizeof(T*)), \"ALIGNED_SIZE mod\");\n\t\t\tstatic_assert(ALIGNMENT >= sizeof(T*), \"ALIGNMENT\");\n\n\t\t\tT* mHead{ nullptr };\n\t\t\tT** mListForFree{ nullptr };\n\t\t};\n\n\t\ttemplate <typename T, size_t MinSize, size_t MaxSize, bool IsFlat>\n\t\tstruct NodeAllocator;\n\n\t\t// dummy allocator that does nothing\n\t\ttemplate <typename T, size_t MinSize, size_t MaxSize>\n\t\tstruct NodeAllocator<T, MinSize, MaxSize, true> {\n\n\t\t\t// we are not using the data, so just free it.\n\t\t\tvoid addOrFree(void* ptr, size_t ROBIN_HOOD_UNUSED(numBytes) /*unused*/) noexcept {\n\t\t\t\tROBIN_HOOD_LOG(\"std::free\")\n\t\t\t\t\tstd::free(ptr);\n\t\t\t}\n\t\t};\n\n\t\ttemplate <typename T, size_t MinSize, size_t MaxSize>\n\t\tstruct NodeAllocator<T, MinSize, MaxSize, false> : public BulkPoolAllocator<T, MinSize, MaxSize> {};\n\n\t\t// dummy hash, unsed as mixer when robin_hood::hash is already used\n\t\ttemplate <typename T>\n\t\tstruct identity_hash {\n\t\t\tconstexpr size_t operator()(T const& obj) const noexcept {\n\t\t\t\treturn static_cast<size_t>(obj);\n\t\t\t}\n\t\t};\n\n\t\t// c++14 doesn't have is_nothrow_swappable, and clang++ 6.0.1 doesn't like it either, so I'm making\n\t\t// my own here.\n\t\tnamespace swappable {\n#if ROBIN_HOOD(CXX) < ROBIN_HOOD(CXX17)\n\t\t\tusing std::swap;\n\t\t\ttemplate <typename T>\n\t\t\tstruct nothrow {\n\t\t\t\tstatic const bool value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));\n\t\t\t};\n#else\n\t\t\ttemplate <typename T>\n\t\t\tstruct nothrow {\n\t\t\t\tstatic const bool value = std::is_nothrow_swappable<T>::value;\n\t\t\t};\n#endif\n\t\t} // namespace swappable\n\n\t} // namespace detail\n\n\tstruct is_transparent_tag {};\n\n\t// A custom pair implementation is used in the map because std::pair is not is_trivially_copyable,\n\t// which means it would  not be allowed to be used in std::memcpy. This struct is copyable, which is\n\t// also tested.\n\ttemplate <typename T1, typename T2>\n\tstruct pair {\n\t\tusing first_type = T1;\n\t\tusing second_type = T2;\n\n\t\ttemplate <typename U1 = T1, typename U2 = T2,\n\t\t\ttypename = typename std::enable_if<std::is_default_constructible<U1>::value&&\n\t\t\tstd::is_default_constructible<U2>::value>::type>\n\t\t\tconstexpr pair() noexcept(noexcept(U1()) && noexcept(U2()))\n\t\t\t: first()\n\t\t\t, second() {}\n\n\t\t// pair constructors are explicit so we don't accidentally call this ctor when we don't have to.\n\t\texplicit constexpr pair(std::pair<T1, T2> const& o) noexcept(\n\t\t\tnoexcept(T1(std::declval<T1 const&>())) && noexcept(T2(std::declval<T2 const&>())))\n\t\t\t: first(o.first)\n\t\t\t, second(o.second) {}\n\n\t\t// pair constructors are explicit so we don't accidentally call this ctor when we don't have to.\n\t\texplicit constexpr pair(std::pair<T1, T2>&& o) noexcept(noexcept(\n\t\t\tT1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))\n\t\t\t: first(std::move(o.first))\n\t\t\t, second(std::move(o.second)) {}\n\n\t\tconstexpr pair(T1&& a, T2&& b) noexcept(noexcept(\n\t\t\tT1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))\n\t\t\t: first(std::move(a))\n\t\t\t, second(std::move(b)) {}\n\n\t\ttemplate <typename U1, typename U2>\n\t\tconstexpr pair(U1&& a, U2&& b) noexcept(noexcept(T1(std::forward<U1>(\n\t\t\tstd::declval<U1&&>()))) && noexcept(T2(std::forward<U2>(std::declval<U2&&>()))))\n\t\t\t: first(std::forward<U1>(a))\n\t\t\t, second(std::forward<U2>(b)) {}\n\n\t\ttemplate <typename... U1, typename... U2>\n\t\tconstexpr pair(\n\t\t\tstd::piecewise_construct_t /*unused*/, std::tuple<U1...> a,\n\t\t\tstd::tuple<U2...> b) noexcept(noexcept(pair(std::declval<std::tuple<U1...>&>(),\n\t\t\t\tstd::declval<std::tuple<U2...>&>(),\n\t\t\t\tROBIN_HOOD_STD::index_sequence_for<U1...>(),\n\t\t\t\tROBIN_HOOD_STD::index_sequence_for<U2...>())))\n\t\t\t: pair(a, b, ROBIN_HOOD_STD::index_sequence_for<U1...>(),\n\t\t\t\tROBIN_HOOD_STD::index_sequence_for<U2...>()) {}\n\n\t\t// constructor called from the std::piecewise_construct_t ctor\n\t\ttemplate <typename... U1, size_t... I1, typename... U2, size_t... I2>\n\t\tpair(std::tuple<U1...>& a, std::tuple<U2...>& b, ROBIN_HOOD_STD::index_sequence<I1...> /*unused*/, ROBIN_HOOD_STD::index_sequence<I2...> /*unused*/) noexcept(\n\t\t\tnoexcept(T1(std::forward<U1>(std::get<I1>(\n\t\t\t\tstd::declval<std::tuple<\n\t\t\t\tU1...>&>()))...)) && noexcept(T2(std::\n\t\t\t\t\tforward<U2>(std::get<I2>(\n\t\t\t\t\t\tstd::declval<std::tuple<U2...>&>()))...)))\n\t\t\t: first(std::forward<U1>(std::get<I1>(a))...)\n\t\t\t, second(std::forward<U2>(std::get<I2>(b))...) {\n\t\t\t// make visual studio compiler happy about warning about unused a & b.\n\t\t\t// Visual studio's pair implementation disables warning 4100.\n\t\t\t(void)a;\n\t\t\t(void)b;\n\t\t}\n\n\t\tvoid swap(pair<T1, T2>& o) noexcept((detail::swappable::nothrow<T1>::value) &&\n\t\t\t(detail::swappable::nothrow<T2>::value)) {\n\t\t\tusing std::swap;\n\t\t\tswap(first, o.first);\n\t\t\tswap(second, o.second);\n\t\t}\n\n\t\tT1 first;  // NOLINT(misc-non-private-member-variables-in-classes)\n\t\tT2 second; // NOLINT(misc-non-private-member-variables-in-classes)\n\t};\n\n\ttemplate <typename A, typename B>\n\tinline void swap(pair<A, B>& a, pair<A, B>& b) noexcept(\n\t\tnoexcept(std::declval<pair<A, B>&>().swap(std::declval<pair<A, B>&>()))) {\n\t\ta.swap(b);\n\t}\n\n\ttemplate <typename A, typename B>\n\tinline constexpr bool operator==(pair<A, B> const& x, pair<A, B> const& y) {\n\t\treturn (x.first == y.first) && (x.second == y.second);\n\t}\n\ttemplate <typename A, typename B>\n\tinline constexpr bool operator!=(pair<A, B> const& x, pair<A, B> const& y) {\n\t\treturn !(x == y);\n\t}\n\ttemplate <typename A, typename B>\n\tinline constexpr bool operator<(pair<A, B> const& x, pair<A, B> const& y) noexcept(noexcept(\n\t\tstd::declval<A const&>() < std::declval<A const&>()) && noexcept(std::declval<B const&>() <\n\t\t\tstd::declval<B const&>())) {\n\t\treturn x.first < y.first || (!(y.first < x.first) && x.second < y.second);\n\t}\n\ttemplate <typename A, typename B>\n\tinline constexpr bool operator>(pair<A, B> const& x, pair<A, B> const& y) {\n\t\treturn y < x;\n\t}\n\ttemplate <typename A, typename B>\n\tinline constexpr bool operator<=(pair<A, B> const& x, pair<A, B> const& y) {\n\t\treturn !(x > y);\n\t}\n\ttemplate <typename A, typename B>\n\tinline constexpr bool operator>=(pair<A, B> const& x, pair<A, B> const& y) {\n\t\treturn !(x < y);\n\t}\n\n\tinline size_t hash_bytes(void const* ptr, size_t len) noexcept {\n\t\tstatic constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995);\n\t\tstatic constexpr uint64_t seed = UINT64_C(0xe17a1465);\n\t\tstatic constexpr unsigned int r = 47;\n\n\t\tauto const* const data64 = static_cast<uint64_t const*>(ptr);\n\t\tuint64_t h = seed ^ (len * m);\n\n\t\tsize_t const n_blocks = len / 8;\n\t\tfor (size_t i = 0; i < n_blocks; ++i) {\n\t\t\tauto k = detail::unaligned_load<uint64_t>(data64 + i);\n\n\t\t\tk *= m;\n\t\t\tk ^= k >> r;\n\t\t\tk *= m;\n\n\t\t\th ^= k;\n\t\t\th *= m;\n\t\t}\n\n\t\tauto const* const data8 = reinterpret_cast<uint8_t const*>(data64 + n_blocks);\n\t\tswitch (len & 7U) {\n\t\tcase 7:\n\t\t\th ^= static_cast<uint64_t>(data8[6]) << 48U;\n\t\t\tROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n\t\tcase 6:\n\t\t\th ^= static_cast<uint64_t>(data8[5]) << 40U;\n\t\t\tROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n\t\tcase 5:\n\t\t\th ^= static_cast<uint64_t>(data8[4]) << 32U;\n\t\t\tROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n\t\tcase 4:\n\t\t\th ^= static_cast<uint64_t>(data8[3]) << 24U;\n\t\t\tROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n\t\tcase 3:\n\t\t\th ^= static_cast<uint64_t>(data8[2]) << 16U;\n\t\t\tROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n\t\tcase 2:\n\t\t\th ^= static_cast<uint64_t>(data8[1]) << 8U;\n\t\t\tROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n\t\tcase 1:\n\t\t\th ^= static_cast<uint64_t>(data8[0]);\n\t\t\th *= m;\n\t\t\tROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\n\t\th ^= h >> r;\n\t\th *= m;\n\t\th ^= h >> r;\n\t\treturn static_cast<size_t>(h);\n\t}\n\n\tinline size_t hash_int(uint64_t x) noexcept {\n\t\t// inspired by lemire's strongly universal hashing\n\t\t// https://lemire.me/blog/2018/08/15/fast-strongly-universal-64-bit-hashing-everywhere/\n\t\t//\n\t\t// Instead of shifts, we use rotations so we don't lose any bits.\n\t\t//\n\t\t// Added a final multiplcation with a constant for more mixing. It is most important that\n\t\t// the lower bits are well mixed.\n\t\tauto h1 = x * UINT64_C(0xA24BAED4963EE407);\n\t\tauto h2 = detail::rotr(x, 32U) * UINT64_C(0x9FB21C651E98DF25);\n\t\tauto h = detail::rotr(h1 + h2, 32U);\n\t\treturn static_cast<size_t>(h);\n\t}\n\n\t// A thin wrapper around std::hash, performing an additional simple mixing step of the result.\n\ttemplate <typename T, typename Enable = void>\n\tstruct hash : public std::hash<T> {\n\t\tsize_t operator()(T const& obj) const\n\t\t\tnoexcept(noexcept(std::declval<std::hash<T>>().operator()(std::declval<T const&>()))) {\n\t\t\t// call base hash\n\t\t\tauto result = std::hash<T>::operator()(obj);\n\t\t\t// return mixed of that, to be save against identity has\n\t\t\treturn hash_int(static_cast<detail::SizeT>(result));\n\t\t}\n\t};\n\n\ttemplate <typename CharT>\n\tstruct hash<std::basic_string<CharT>> {\n\t\tsize_t operator()(std::basic_string<CharT> const& str) const noexcept {\n\t\t\treturn hash_bytes(str.data(), sizeof(CharT) * str.size());\n\t\t}\n\t};\n\n#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)\n\ttemplate <typename CharT>\n\tstruct hash<std::basic_string_view<CharT>> {\n\t\tsize_t operator()(std::basic_string_view<CharT> const& sv) const noexcept {\n\t\t\treturn hash_bytes(sv.data(), sizeof(CharT) * sv.size());\n\t\t}\n\t};\n#endif\n\n\ttemplate <class T>\n\tstruct hash<T*> {\n\t\tsize_t operator()(T* ptr) const noexcept {\n\t\t\treturn hash_int(reinterpret_cast<detail::SizeT>(ptr));\n\t\t}\n\t};\n\n\ttemplate <class T>\n\tstruct hash<std::unique_ptr<T>> {\n\t\tsize_t operator()(std::unique_ptr<T> const& ptr) const noexcept {\n\t\t\treturn hash_int(reinterpret_cast<detail::SizeT>(ptr.get()));\n\t\t}\n\t};\n\n\ttemplate <class T>\n\tstruct hash<std::shared_ptr<T>> {\n\t\tsize_t operator()(std::shared_ptr<T> const& ptr) const noexcept {\n\t\t\treturn hash_int(reinterpret_cast<detail::SizeT>(ptr.get()));\n\t\t}\n\t};\n\n\ttemplate <typename Enum>\n\tstruct hash<Enum, typename std::enable_if<std::is_enum<Enum>::value>::type> {\n\t\tsize_t operator()(Enum e) const noexcept {\n\t\t\tusing Underlying = typename std::underlying_type<Enum>::type;\n\t\t\treturn hash<Underlying>{}(static_cast<Underlying>(e));\n\t\t}\n\t};\n\n#define ROBIN_HOOD_HASH_INT(T)                           \\\n    template <>                                          \\\n    struct hash<T> {                                     \\\n        size_t operator()(T const& obj) const noexcept { \\\n            return hash_int(static_cast<uint64_t>(obj)); \\\n        }                                                \\\n    }\n\n#if defined(__GNUC__) && !defined(__clang__)\n#    pragma GCC diagnostic push\n#    pragma GCC diagnostic ignored \"-Wuseless-cast\"\n#endif\n\t// see https://en.cppreference.com/w/cpp/utility/hash\n\tROBIN_HOOD_HASH_INT(bool);\n\tROBIN_HOOD_HASH_INT(char);\n\tROBIN_HOOD_HASH_INT(signed char);\n\tROBIN_HOOD_HASH_INT(unsigned char);\n\tROBIN_HOOD_HASH_INT(char16_t);\n\tROBIN_HOOD_HASH_INT(char32_t);\n#if ROBIN_HOOD(HAS_NATIVE_WCHART)\n\tROBIN_HOOD_HASH_INT(wchar_t);\n#endif\n\tROBIN_HOOD_HASH_INT(short);\n\tROBIN_HOOD_HASH_INT(unsigned short);\n\tROBIN_HOOD_HASH_INT(int);\n\tROBIN_HOOD_HASH_INT(unsigned int);\n\tROBIN_HOOD_HASH_INT(long);\n\tROBIN_HOOD_HASH_INT(long long);\n\tROBIN_HOOD_HASH_INT(unsigned long);\n\tROBIN_HOOD_HASH_INT(unsigned long long);\n#if defined(__GNUC__) && !defined(__clang__)\n#    pragma GCC diagnostic pop\n#endif\n\tnamespace detail {\n\n\t\ttemplate <typename T>\n\t\tstruct void_type {\n\t\t\tusing type = void;\n\t\t};\n\n\t\ttemplate <typename T, typename = void>\n\t\tstruct has_is_transparent : public std::false_type {};\n\n\t\ttemplate <typename T>\n\t\tstruct has_is_transparent<T, typename void_type<typename T::is_transparent>::type>\n\t\t\t: public std::true_type {};\n\n\t\t// using wrapper classes for hash and key_equal prevents the diamond problem when the same type\n\t\t// is used. see https://stackoverflow.com/a/28771920/48181\n\t\ttemplate <typename T>\n\t\tstruct WrapHash : public T {\n\t\t\tWrapHash() = default;\n\t\t\texplicit WrapHash(T const& o) noexcept(noexcept(T(std::declval<T const&>())))\n\t\t\t\t: T(o) {}\n\t\t};\n\n\t\ttemplate <typename T>\n\t\tstruct WrapKeyEqual : public T {\n\t\t\tWrapKeyEqual() = default;\n\t\t\texplicit WrapKeyEqual(T const& o) noexcept(noexcept(T(std::declval<T const&>())))\n\t\t\t\t: T(o) {}\n\t\t};\n\n\t\t// A highly optimized hashmap implementation, using the Robin Hood algorithm.\n\t\t//\n\t\t// In most cases, this map should be usable as a drop-in replacement for std::unordered_map, but\n\t\t// be about 2x faster in most cases and require much less allocations.\n\t\t//\n\t\t// This implementation uses the following memory layout:\n\t\t//\n\t\t// [Node, Node, ... Node | info, info, ... infoSentinel ]\n\t\t//\n\t\t// * Node: either a DataNode that directly has the std::pair<key, val> as member,\n\t\t//   or a DataNode with a pointer to std::pair<key,val>. Which DataNode representation to use\n\t\t//   depends on how fast the swap() operation is. Heuristically, this is automatically choosen\n\t\t//   based on sizeof(). there are always 2^n Nodes.\n\t\t//\n\t\t// * info: Each Node in the map has a corresponding info byte, so there are 2^n info bytes.\n\t\t//   Each byte is initialized to 0, meaning the corresponding Node is empty. Set to 1 means the\n\t\t//   corresponding node contains data. Set to 2 means the corresponding Node is filled, but it\n\t\t//   actually belongs to the previous position and was pushed out because that place is already\n\t\t//   taken.\n\t\t//\n\t\t// * infoSentinel: Sentinel byte set to 1, so that iterator's ++ can stop at end() without the\n\t\t//   need for a idx variable.\n\t\t//\n\t\t// According to STL, order of templates has effect on throughput. That's why I've moved the\n\t\t// boolean to the front.\n\t\t// https://www.reddit.com/r/cpp/comments/ahp6iu/compile_time_binary_size_reductions_and_cs_future/eeguck4/\n\t\ttemplate <bool IsFlat, size_t MaxLoadFactor100, typename Key, typename T, typename Hash,\n\t\t\ttypename KeyEqual>\n\t\t\tclass Table\n\t\t\t: public WrapHash<Hash>,\n\t\t\tpublic WrapKeyEqual<KeyEqual>,\n\t\t\tdetail::NodeAllocator<\n\t\t\ttypename std::conditional<\n\t\t\tstd::is_void<T>::value, Key,\n\t\t\trobin_hood::pair<typename std::conditional<IsFlat, Key, Key const>::type, T>>::type,\n\t\t\t4, 16384, IsFlat> {\n\t\t\tpublic:\n\t\t\t\tstatic constexpr bool is_flat = IsFlat;\n\t\t\t\tstatic constexpr bool is_map = !std::is_void<T>::value;\n\t\t\t\tstatic constexpr bool is_set = !is_map;\n\t\t\t\tstatic constexpr bool is_transparent =\n\t\t\t\t\thas_is_transparent<Hash>::value && has_is_transparent<KeyEqual>::value;\n\n\t\t\t\tusing key_type = Key;\n\t\t\t\tusing mapped_type = T;\n\t\t\t\tusing value_type = typename std::conditional<\n\t\t\t\t\tis_set, Key,\n\t\t\t\t\trobin_hood::pair<typename std::conditional<is_flat, Key, Key const>::type, T>>::type;\n\t\t\t\tusing size_type = size_t;\n\t\t\t\tusing hasher = Hash;\n\t\t\t\tusing key_equal = KeyEqual;\n\t\t\t\tusing Self = Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;\n\n\t\t\tprivate:\n\t\t\t\tstatic_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100,\n\t\t\t\t\t\"MaxLoadFactor100 needs to be >10 && < 100\");\n\n\t\t\t\tusing WHash = WrapHash<Hash>;\n\t\t\t\tusing WKeyEqual = WrapKeyEqual<KeyEqual>;\n\n\t\t\t\t// configuration defaults\n\n\t\t\t\t// make sure we have 8 elements, needed to quickly rehash mInfo\n\t\t\t\tstatic constexpr size_t InitialNumElements = sizeof(uint64_t);\n\t\t\t\tstatic constexpr uint32_t InitialInfoNumBits = 5;\n\t\t\t\tstatic constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits;\n\t\t\t\tstatic constexpr size_t InfoMask = InitialInfoInc - 1U;\n\t\t\t\tstatic constexpr uint8_t InitialInfoHashShift = 0;\n\t\t\t\tusing DataPool = detail::NodeAllocator<value_type, 4, 16384, IsFlat>;\n\n\t\t\t\t// type needs to be wider than uint8_t.\n\t\t\t\tusing InfoType = uint32_t;\n\n\t\t\t\t// DataNode ////////////////////////////////////////////////////////\n\n\t\t\t\t// Primary template for the data node. We have special implementations for small and big\n\t\t\t\t// objects. For large objects it is assumed that swap() is fairly slow, so we allocate these\n\t\t\t\t// on the heap so swap merely swaps a pointer.\n\t\t\t\ttemplate <typename M, bool>\n\t\t\t\tclass DataNode {};\n\n\t\t\t\t// Small: just allocate on the stack.\n\t\t\t\ttemplate <typename M>\n\t\t\t\tclass DataNode<M, true> final {\n\t\t\t\tpublic:\n\t\t\t\t\ttemplate <typename... Args>\n\t\t\t\t\texplicit DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, Args&&... args) noexcept(\n\t\t\t\t\t\tnoexcept(value_type(std::forward<Args>(args)...)))\n\t\t\t\t\t\t: mData(std::forward<Args>(args)...) {}\n\n\t\t\t\t\tDataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode<M, true>&& n) noexcept(\n\t\t\t\t\t\tstd::is_nothrow_move_constructible<value_type>::value)\n\t\t\t\t\t\t: mData(std::move(n.mData)) {}\n\n\t\t\t\t\t// doesn't do anything\n\t\t\t\t\tvoid destroy(M& ROBIN_HOOD_UNUSED(map) /*unused*/) noexcept {}\n\t\t\t\t\tvoid destroyDoNotDeallocate() noexcept {}\n\n\t\t\t\t\tvalue_type const* operator->() const noexcept {\n\t\t\t\t\t\treturn &mData;\n\t\t\t\t\t}\n\t\t\t\t\tvalue_type* operator->() noexcept {\n\t\t\t\t\t\treturn &mData;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst value_type& operator*() const noexcept {\n\t\t\t\t\t\treturn mData;\n\t\t\t\t\t}\n\n\t\t\t\t\tvalue_type& operator*() noexcept {\n\t\t\t\t\t\treturn mData;\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <typename VT = value_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {\n\t\t\t\t\t\treturn mData.first;\n\t\t\t\t\t}\n\t\t\t\t\ttemplate <typename VT = value_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_set, VT&>::type getFirst() noexcept {\n\t\t\t\t\t\treturn mData;\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <typename VT = value_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_map, typename VT::first_type const&>::type\n\t\t\t\t\t\tgetFirst() const noexcept {\n\t\t\t\t\t\treturn mData.first;\n\t\t\t\t\t}\n\t\t\t\t\ttemplate <typename VT = value_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {\n\t\t\t\t\t\treturn mData;\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <typename MT = mapped_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_map, MT&>::type getSecond() noexcept {\n\t\t\t\t\t\treturn mData.second;\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <typename MT = mapped_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_set, MT const&>::type getSecond() const noexcept {\n\t\t\t\t\t\treturn mData.second;\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid swap(DataNode<M, true>& o) noexcept(\n\t\t\t\t\t\tnoexcept(std::declval<value_type>().swap(std::declval<value_type>()))) {\n\t\t\t\t\t\tmData.swap(o.mData);\n\t\t\t\t\t}\n\n\t\t\t\tprivate:\n\t\t\t\t\tvalue_type mData;\n\t\t\t\t};\n\n\t\t\t\t// big object: allocate on heap.\n\t\t\t\ttemplate <typename M>\n\t\t\t\tclass DataNode<M, false> {\n\t\t\t\tpublic:\n\t\t\t\t\ttemplate <typename... Args>\n\t\t\t\t\texplicit DataNode(M& map, Args&&... args)\n\t\t\t\t\t\t: mData(map.allocate()) {\n\t\t\t\t\t\t::new (static_cast<void*>(mData)) value_type(std::forward<Args>(args)...);\n\t\t\t\t\t}\n\n\t\t\t\t\tDataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode<M, false>&& n) noexcept\n\t\t\t\t\t\t: mData(std::move(n.mData)) {}\n\n\t\t\t\t\tvoid destroy(M& map) noexcept {\n\t\t\t\t\t\t// don't deallocate, just put it into list of datapool.\n\t\t\t\t\t\tmData->~value_type();\n\t\t\t\t\t\tmap.deallocate(mData);\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid destroyDoNotDeallocate() noexcept {\n\t\t\t\t\t\tmData->~value_type();\n\t\t\t\t\t}\n\n\t\t\t\t\tvalue_type const* operator->() const noexcept {\n\t\t\t\t\t\treturn mData;\n\t\t\t\t\t}\n\n\t\t\t\t\tvalue_type* operator->() noexcept {\n\t\t\t\t\t\treturn mData;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst value_type& operator*() const {\n\t\t\t\t\t\treturn *mData;\n\t\t\t\t\t}\n\n\t\t\t\t\tvalue_type& operator*() {\n\t\t\t\t\t\treturn *mData;\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <typename VT = value_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {\n\t\t\t\t\t\treturn mData->first;\n\t\t\t\t\t}\n\t\t\t\t\ttemplate <typename VT = value_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_set, VT&>::type getFirst() noexcept {\n\t\t\t\t\t\treturn *mData;\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <typename VT = value_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_map, typename VT::first_type const&>::type\n\t\t\t\t\t\tgetFirst() const noexcept {\n\t\t\t\t\t\treturn mData->first;\n\t\t\t\t\t}\n\t\t\t\t\ttemplate <typename VT = value_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {\n\t\t\t\t\t\treturn *mData;\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <typename MT = mapped_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_map, MT&>::type getSecond() noexcept {\n\t\t\t\t\t\treturn mData->second;\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <typename MT = mapped_type>\n\t\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\t\ttypename std::enable_if<is_map, MT const&>::type getSecond() const noexcept {\n\t\t\t\t\t\treturn mData->second;\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid swap(DataNode<M, false>& o) noexcept {\n\t\t\t\t\t\tusing std::swap;\n\t\t\t\t\t\tswap(mData, o.mData);\n\t\t\t\t\t}\n\n\t\t\t\tprivate:\n\t\t\t\t\tvalue_type* mData;\n\t\t\t\t};\n\n\t\t\t\tusing Node = DataNode<Self, IsFlat>;\n\n\t\t\t\t// helpers for doInsert: extract first entry (only const required)\n\t\t\t\tROBIN_HOOD(NODISCARD) key_type const& getFirstConst(Node const& n) const noexcept {\n\t\t\t\t\treturn n.getFirst();\n\t\t\t\t}\n\n\t\t\t\t// in case we have void mapped_type, we are not using a pair, thus we just route k through.\n\t\t\t\t// No need to disable this because it's just not used if not applicable.\n\t\t\t\tROBIN_HOOD(NODISCARD) key_type const& getFirstConst(key_type const& k) const noexcept {\n\t\t\t\t\treturn k;\n\t\t\t\t}\n\n\t\t\t\t// in case we have non-void mapped_type, we have a standard robin_hood::pair\n\t\t\t\ttemplate <typename Q = mapped_type>\n\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\ttypename std::enable_if<!std::is_void<Q>::value, key_type const&>::type\n\t\t\t\t\tgetFirstConst(value_type const& vt) const noexcept {\n\t\t\t\t\treturn vt.first;\n\t\t\t\t}\n\n\t\t\t\t// Cloner //////////////////////////////////////////////////////////\n\n\t\t\t\ttemplate <typename M, bool UseMemcpy>\n\t\t\t\tstruct Cloner;\n\n\t\t\t\t// fast path: Just copy data, without allocating anything.\n\t\t\t\ttemplate <typename M>\n\t\t\t\tstruct Cloner<M, true> {\n\t\t\t\t\tvoid operator()(M const& source, M& target) const {\n\t\t\t\t\t\tauto const* const src = reinterpret_cast<char const*>(source.mKeyVals);\n\t\t\t\t\t\tauto* tgt = reinterpret_cast<char*>(target.mKeyVals);\n\t\t\t\t\t\tauto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1);\n\t\t\t\t\t\tstd::copy(src, src + target.calcNumBytesTotal(numElementsWithBuffer), tgt);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\ttemplate <typename M>\n\t\t\t\tstruct Cloner<M, false> {\n\t\t\t\t\tvoid operator()(M const& s, M& t) const {\n\t\t\t\t\t\tauto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1);\n\t\t\t\t\t\tstd::copy(s.mInfo, s.mInfo + t.calcNumBytesInfo(numElementsWithBuffer), t.mInfo);\n\n\t\t\t\t\t\tfor (size_t i = 0; i < numElementsWithBuffer; ++i) {\n\t\t\t\t\t\t\tif (t.mInfo[i]) {\n\t\t\t\t\t\t\t\t::new (static_cast<void*>(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Destroyer ///////////////////////////////////////////////////////\n\n\t\t\t\ttemplate <typename M, bool IsFlatAndTrivial>\n\t\t\t\tstruct Destroyer {};\n\n\t\t\t\ttemplate <typename M>\n\t\t\t\tstruct Destroyer<M, true> {\n\t\t\t\t\tvoid nodes(M& m) const noexcept {\n\t\t\t\t\t\tm.mNumElements = 0;\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid nodesDoNotDeallocate(M& m) const noexcept {\n\t\t\t\t\t\tm.mNumElements = 0;\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\ttemplate <typename M>\n\t\t\t\tstruct Destroyer<M, false> {\n\t\t\t\t\tvoid nodes(M& m) const noexcept {\n\t\t\t\t\t\tm.mNumElements = 0;\n\t\t\t\t\t\t// clear also resets mInfo to 0, that's sometimes not necessary.\n\t\t\t\t\t\tauto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);\n\n\t\t\t\t\t\tfor (size_t idx = 0; idx < numElementsWithBuffer; ++idx) {\n\t\t\t\t\t\t\tif (0 != m.mInfo[idx]) {\n\t\t\t\t\t\t\t\tNode& n = m.mKeyVals[idx];\n\t\t\t\t\t\t\t\tn.destroy(m);\n\t\t\t\t\t\t\t\tn.~Node();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tvoid nodesDoNotDeallocate(M& m) const noexcept {\n\t\t\t\t\t\tm.mNumElements = 0;\n\t\t\t\t\t\t// clear also resets mInfo to 0, that's sometimes not necessary.\n\t\t\t\t\t\tauto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);\n\t\t\t\t\t\tfor (size_t idx = 0; idx < numElementsWithBuffer; ++idx) {\n\t\t\t\t\t\t\tif (0 != m.mInfo[idx]) {\n\t\t\t\t\t\t\t\tNode& n = m.mKeyVals[idx];\n\t\t\t\t\t\t\t\tn.destroyDoNotDeallocate();\n\t\t\t\t\t\t\t\tn.~Node();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Iter ////////////////////////////////////////////////////////////\n\n\t\t\t\tstruct fast_forward_tag {};\n\n\t\t\t\t// generic iterator for both const_iterator and iterator.\n\t\t\t\ttemplate <bool IsConst>\n\t\t\t\t// NOLINTNEXTLINE(hicpp-special-member-functions,cppcoreguidelines-special-member-functions)\n\t\t\t\tclass Iter {\n\t\t\t\tprivate:\n\t\t\t\t\tusing NodePtr = typename std::conditional<IsConst, Node const*, Node*>::type;\n\n\t\t\t\tpublic:\n\t\t\t\t\tusing difference_type = std::ptrdiff_t;\n\t\t\t\t\tusing value_type = typename Self::value_type;\n\t\t\t\t\tusing reference = typename std::conditional<IsConst, value_type const&, value_type&>::type;\n\t\t\t\t\tusing pointer = typename std::conditional<IsConst, value_type const*, value_type*>::type;\n\t\t\t\t\tusing iterator_category = std::forward_iterator_tag;\n\n\t\t\t\t\t// default constructed iterator can be compared to itself, but WON'T return true when\n\t\t\t\t\t// compared to end().\n\t\t\t\t\tIter() = default;\n\n\t\t\t\t\t// Rule of zero: nothing specified. The conversion constructor is only enabled for\n\t\t\t\t\t// iterator to const_iterator, so it doesn't accidentally work as a copy ctor.\n\n\t\t\t\t\t// Conversion constructor from iterator to const_iterator.\n\t\t\t\t\ttemplate <bool OtherIsConst,\n\t\t\t\t\t\ttypename = typename std::enable_if<IsConst && !OtherIsConst>::type>\n\t\t\t\t\t\t// NOLINTNEXTLINE(hicpp-explicit-conversions)\n\t\t\t\t\t\tIter(Iter<OtherIsConst> const& other) noexcept\n\t\t\t\t\t\t: mKeyVals(other.mKeyVals)\n\t\t\t\t\t\t, mInfo(other.mInfo) {}\n\n\t\t\t\t\tIter(NodePtr valPtr, uint8_t const* infoPtr) noexcept\n\t\t\t\t\t\t: mKeyVals(valPtr)\n\t\t\t\t\t\t, mInfo(infoPtr) {}\n\n\t\t\t\t\tIter(NodePtr valPtr, uint8_t const* infoPtr,\n\t\t\t\t\t\tfast_forward_tag ROBIN_HOOD_UNUSED(tag) /*unused*/) noexcept\n\t\t\t\t\t\t: mKeyVals(valPtr)\n\t\t\t\t\t\t, mInfo(infoPtr) {\n\t\t\t\t\t\tfastForward();\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <bool OtherIsConst,\n\t\t\t\t\t\ttypename = typename std::enable_if<IsConst && !OtherIsConst>::type>\n\t\t\t\t\t\tIter& operator=(Iter<OtherIsConst> const& other) noexcept {\n\t\t\t\t\t\tmKeyVals = other.mKeyVals;\n\t\t\t\t\t\tmInfo = other.mInfo;\n\t\t\t\t\t\treturn *this;\n\t\t\t\t\t}\n\n\t\t\t\t\t// prefix increment. Undefined behavior if we are at end()!\n\t\t\t\t\tIter& operator++() noexcept {\n\t\t\t\t\t\tmInfo++;\n\t\t\t\t\t\tmKeyVals++;\n\t\t\t\t\t\tfastForward();\n\t\t\t\t\t\treturn *this;\n\t\t\t\t\t}\n\n\t\t\t\t\tIter operator++(int) noexcept {\n\t\t\t\t\t\tIter tmp = *this;\n\t\t\t\t\t\t++(*this);\n\t\t\t\t\t\treturn tmp;\n\t\t\t\t\t}\n\n\t\t\t\t\treference operator*() const {\n\t\t\t\t\t\treturn **mKeyVals;\n\t\t\t\t\t}\n\n\t\t\t\t\tpointer operator->() const {\n\t\t\t\t\t\treturn &**mKeyVals;\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <bool O>\n\t\t\t\t\tbool operator==(Iter<O> const& o) const noexcept {\n\t\t\t\t\t\treturn mKeyVals == o.mKeyVals;\n\t\t\t\t\t}\n\n\t\t\t\t\ttemplate <bool O>\n\t\t\t\t\tbool operator!=(Iter<O> const& o) const noexcept {\n\t\t\t\t\t\treturn mKeyVals != o.mKeyVals;\n\t\t\t\t\t}\n\n\t\t\t\tprivate:\n\t\t\t\t\t// fast forward to the next non-free info byte\n\t\t\t\t\t// I've tried a few variants that don't depend on intrinsics, but unfortunately they are\n\t\t\t\t\t// quite a bit slower than this one. So I've reverted that change again. See map_benchmark.\n\t\t\t\t\tvoid fastForward() noexcept {\n\t\t\t\t\t\tsize_t n = 0;\n\t\t\t\t\t\twhile (0U == (n = detail::unaligned_load<size_t>(mInfo))) {\n\t\t\t\t\t\t\tmInfo += sizeof(size_t);\n\t\t\t\t\t\t\tmKeyVals += sizeof(size_t);\n\t\t\t\t\t\t}\n#if defined(ROBIN_HOOD_DISABLE_INTRINSICS)\n\t\t\t\t\t\t// we know for certain that within the next 8 bytes we'll find a non-zero one.\n\t\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint32_t>(mInfo))) {\n\t\t\t\t\t\t\tmInfo += 4;\n\t\t\t\t\t\t\tmKeyVals += 4;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint16_t>(mInfo))) {\n\t\t\t\t\t\t\tmInfo += 2;\n\t\t\t\t\t\t\tmKeyVals += 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(0U == *mInfo)) {\n\t\t\t\t\t\t\tmInfo += 1;\n\t\t\t\t\t\t\tmKeyVals += 1;\n\t\t\t\t\t\t}\n#else\n#    if ROBIN_HOOD(LITTLE_ENDIAN)\n\t\t\t\t\t\tauto inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8;\n#    else\n\t\t\t\t\t\tauto inc = ROBIN_HOOD_COUNT_LEADING_ZEROES(n) / 8;\n#    endif\n\t\t\t\t\t\tmInfo += inc;\n\t\t\t\t\t\tmKeyVals += inc;\n#endif\n\t\t\t\t\t}\n\n\t\t\t\t\tfriend class Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;\n\t\t\t\t\tNodePtr mKeyVals{ nullptr };\n\t\t\t\t\tuint8_t const* mInfo{ nullptr };\n\t\t\t\t};\n\n\t\t\t\t////////////////////////////////////////////////////////////////////\n\n\t\t\t\t// highly performance relevant code.\n\t\t\t\t// Lower bits are used for indexing into the array (2^n size)\n\t\t\t\t// The upper 1-5 bits need to be a reasonable good hash, to save comparisons.\n\t\t\t\ttemplate <typename HashKey>\n\t\t\t\tvoid keyToIdx(HashKey&& key, size_t* idx, InfoType* info) const {\n\t\t\t\t\t// for a user-specified hash that is *not* robin_hood::hash, apply robin_hood::hash as\n\t\t\t\t\t// an additional mixing step. This serves as a bad hash prevention, if the given data is\n\t\t\t\t\t// badly mixed.\n\t\t\t\t\tusing Mix =\n\t\t\t\t\t\ttypename std::conditional<std::is_same<::robin_hood::hash<key_type>, hasher>::value,\n\t\t\t\t\t\t::robin_hood::detail::identity_hash<size_t>,\n\t\t\t\t\t\t::robin_hood::hash<size_t>>::type;\n\n\t\t\t\t\t// the lower InitialInfoNumBits are reserved for info.\n\t\t\t\t\tauto h = Mix{}(WHash::operator()(key));\n\t\t\t\t\t*info = mInfoInc + static_cast<InfoType>((h & InfoMask) >> mInfoHashShift);\n\t\t\t\t\t*idx = (h >> InitialInfoNumBits) & mMask;\n\t\t\t\t}\n\n\t\t\t\t// forwards the index by one, wrapping around at the end\n\t\t\t\tvoid next(InfoType* info, size_t* idx) const noexcept {\n\t\t\t\t\t*idx = *idx + 1;\n\t\t\t\t\t*info += mInfoInc;\n\t\t\t\t}\n\n\t\t\t\tvoid nextWhileLess(InfoType* info, size_t* idx) const noexcept {\n\t\t\t\t\t// unrolling this by hand did not bring any speedups.\n\t\t\t\t\twhile (*info < mInfo[*idx]) {\n\t\t\t\t\t\tnext(info, idx);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Shift everything up by one element. Tries to move stuff around.\n\t\t\t\tvoid\n\t\t\t\t\tshiftUp(size_t startIdx,\n\t\t\t\t\t\tsize_t const insertion_idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {\n\t\t\t\t\tauto idx = startIdx;\n\t\t\t\t\t::new (static_cast<void*>(mKeyVals + idx)) Node(std::move(mKeyVals[idx - 1]));\n\t\t\t\t\twhile (--idx != insertion_idx) {\n\t\t\t\t\t\tmKeyVals[idx] = std::move(mKeyVals[idx - 1]);\n\t\t\t\t\t}\n\n\t\t\t\t\tidx = startIdx;\n\t\t\t\t\twhile (idx != insertion_idx) {\n\t\t\t\t\t\tROBIN_HOOD_COUNT(shiftUp)\n\t\t\t\t\t\t\tmInfo[idx] = static_cast<uint8_t>(mInfo[idx - 1] + mInfoInc);\n\t\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(mInfo[idx] + mInfoInc > 0xFF)) {\n\t\t\t\t\t\t\tmMaxNumElementsAllowed = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t--idx;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvoid shiftDown(size_t idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {\n\t\t\t\t\t// until we find one that is either empty or has zero offset.\n\t\t\t\t\t// TODO(martinus) we don't need to move everything, just the last one for the same\n\t\t\t\t\t// bucket.\n\t\t\t\t\tmKeyVals[idx].destroy(*this);\n\n\t\t\t\t\t// until we find one that is either empty or has zero offset.\n\t\t\t\t\twhile (mInfo[idx + 1] >= 2 * mInfoInc) {\n\t\t\t\t\t\tROBIN_HOOD_COUNT(shiftDown)\n\t\t\t\t\t\t\tmInfo[idx] = static_cast<uint8_t>(mInfo[idx + 1] - mInfoInc);\n\t\t\t\t\t\tmKeyVals[idx] = std::move(mKeyVals[idx + 1]);\n\t\t\t\t\t\t++idx;\n\t\t\t\t\t}\n\n\t\t\t\t\tmInfo[idx] = 0;\n\t\t\t\t\t// don't destroy, we've moved it\n\t\t\t\t\t// mKeyVals[idx].destroy(*this);\n\t\t\t\t\tmKeyVals[idx].~Node();\n\t\t\t\t}\n\n\t\t\t\t// copy of find(), except that it returns iterator instead of const_iterator.\n\t\t\t\ttemplate <typename Other>\n\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\tsize_t findIdx(Other const& key) const {\n\t\t\t\t\tsize_t idx{};\n\t\t\t\t\tInfoType info{};\n\t\t\t\t\tkeyToIdx(key, &idx, &info);\n\n\t\t\t\t\tdo {\n\t\t\t\t\t\t// unrolling this twice gives a bit of a speedup. More unrolling did not help.\n\t\t\t\t\t\tif (info == mInfo[idx] &&\n\t\t\t\t\t\t\tROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {\n\t\t\t\t\t\t\treturn idx;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnext(&info, &idx);\n\t\t\t\t\t\tif (info == mInfo[idx] &&\n\t\t\t\t\t\t\tROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {\n\t\t\t\t\t\t\treturn idx;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnext(&info, &idx);\n\t\t\t\t\t} while (info <= mInfo[idx]);\n\n\t\t\t\t\t// nothing found!\n\t\t\t\t\treturn mMask == 0 ? 0\n\t\t\t\t\t\t: static_cast<size_t>(std::distance(\n\t\t\t\t\t\t\tmKeyVals, reinterpret_cast_no_cast_align_warning<Node*>(mInfo)));\n\t\t\t\t}\n\n\t\t\t\tvoid cloneData(const Table& o) {\n\t\t\t\t\tCloner<Table, IsFlat&& ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(Node)>()(o, *this);\n\t\t\t\t}\n\n\t\t\t\t// inserts a keyval that is guaranteed to be new, e.g. when the hashmap is resized.\n\t\t\t\t// @return index where the element was created\n\t\t\t\tsize_t insert_move(Node&& keyval) {\n\t\t\t\t\t// we don't retry, fail if overflowing\n\t\t\t\t\t// don't need to check max num elements\n\t\t\t\t\tif (0 == mMaxNumElementsAllowed && !try_increase_info()) {\n\t\t\t\t\t\tthrowOverflowError(); // impossible to reach LCOV_EXCL_LINE\n\t\t\t\t\t}\n\n\t\t\t\t\tsize_t idx{};\n\t\t\t\t\tInfoType info{};\n\t\t\t\t\tkeyToIdx(keyval.getFirst(), &idx, &info);\n\n\t\t\t\t\t// skip forward. Use <= because we are certain that the element is not there.\n\t\t\t\t\twhile (info <= mInfo[idx]) {\n\t\t\t\t\t\tidx = idx + 1;\n\t\t\t\t\t\tinfo += mInfoInc;\n\t\t\t\t\t}\n\n\t\t\t\t\t// key not found, so we are now exactly where we want to insert it.\n\t\t\t\t\tauto const insertion_idx = idx;\n\t\t\t\t\tauto const insertion_info = static_cast<uint8_t>(info);\n\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {\n\t\t\t\t\t\tmMaxNumElementsAllowed = 0;\n\t\t\t\t\t}\n\n\t\t\t\t\t// find an empty spot\n\t\t\t\t\twhile (0 != mInfo[idx]) {\n\t\t\t\t\t\tnext(&info, &idx);\n\t\t\t\t\t}\n\n\t\t\t\t\tauto& l = mKeyVals[insertion_idx];\n\t\t\t\t\tif (idx == insertion_idx) {\n\t\t\t\t\t\t::new (static_cast<void*>(&l)) Node(std::move(keyval));\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tshiftUp(idx, insertion_idx);\n\t\t\t\t\t\tl = std::move(keyval);\n\t\t\t\t\t}\n\n\t\t\t\t\t// put at empty spot\n\t\t\t\t\tmInfo[insertion_idx] = insertion_info;\n\n\t\t\t\t\t++mNumElements;\n\t\t\t\t\treturn insertion_idx;\n\t\t\t\t}\n\n\t\t\tpublic:\n\t\t\t\tusing iterator = Iter<false>;\n\t\t\t\tusing const_iterator = Iter<true>;\n\n\t\t\t\tTable() noexcept(noexcept(Hash()) && noexcept(KeyEqual()))\n\t\t\t\t\t: WHash()\n\t\t\t\t\t, WKeyEqual() {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t}\n\n\t\t\t\t// Creates an empty hash map. Nothing is allocated yet, this happens at the first insert.\n\t\t\t\t// This tremendously speeds up ctor & dtor of a map that never receives an element. The\n\t\t\t\t// penalty is payed at the first insert, and not before. Lookup of this empty map works\n\t\t\t\t// because everybody points to DummyInfoByte::b. parameter bucket_count is dictated by the\n\t\t\t\t// standard, but we can ignore it.\n\t\t\t\texplicit Table(\n\t\t\t\t\tsize_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/, const Hash& h = Hash{},\n\t\t\t\t\tconst KeyEqual& equal = KeyEqual{}) noexcept(noexcept(Hash(h)) && noexcept(KeyEqual(equal)))\n\t\t\t\t\t: WHash(h)\n\t\t\t\t\t, WKeyEqual(equal) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename Iter>\n\t\t\t\tTable(Iter first, Iter last, size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0,\n\t\t\t\t\tconst Hash& h = Hash{}, const KeyEqual& equal = KeyEqual{})\n\t\t\t\t\t: WHash(h)\n\t\t\t\t\t, WKeyEqual(equal) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tinsert(first, last);\n\t\t\t\t}\n\n\t\t\t\tTable(std::initializer_list<value_type> initlist,\n\t\t\t\t\tsize_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0, const Hash& h = Hash{},\n\t\t\t\t\tconst KeyEqual& equal = KeyEqual{})\n\t\t\t\t\t: WHash(h)\n\t\t\t\t\t, WKeyEqual(equal) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tinsert(initlist.begin(), initlist.end());\n\t\t\t\t}\n\n\t\t\t\tTable(Table&& o) noexcept\n\t\t\t\t\t: WHash(std::move(static_cast<WHash&>(o)))\n\t\t\t\t\t, WKeyEqual(std::move(static_cast<WKeyEqual&>(o)))\n\t\t\t\t\t, DataPool(std::move(static_cast<DataPool&>(o))) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tif (o.mMask) {\n\t\t\t\t\t\t\tmKeyVals = std::move(o.mKeyVals);\n\t\t\t\t\t\t\tmInfo = std::move(o.mInfo);\n\t\t\t\t\t\t\tmNumElements = std::move(o.mNumElements);\n\t\t\t\t\t\t\tmMask = std::move(o.mMask);\n\t\t\t\t\t\t\tmMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);\n\t\t\t\t\t\t\tmInfoInc = std::move(o.mInfoInc);\n\t\t\t\t\t\t\tmInfoHashShift = std::move(o.mInfoHashShift);\n\t\t\t\t\t\t\t// set other's mask to 0 so its destructor won't do anything\n\t\t\t\t\t\t\to.init();\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tTable& operator=(Table&& o) noexcept {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tif (&o != this) {\n\t\t\t\t\t\t\tif (o.mMask) {\n\t\t\t\t\t\t\t\t// only move stuff if the other map actually has some data\n\t\t\t\t\t\t\t\tdestroy();\n\t\t\t\t\t\t\t\tmKeyVals = std::move(o.mKeyVals);\n\t\t\t\t\t\t\t\tmInfo = std::move(o.mInfo);\n\t\t\t\t\t\t\t\tmNumElements = std::move(o.mNumElements);\n\t\t\t\t\t\t\t\tmMask = std::move(o.mMask);\n\t\t\t\t\t\t\t\tmMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);\n\t\t\t\t\t\t\t\tmInfoInc = std::move(o.mInfoInc);\n\t\t\t\t\t\t\t\tmInfoHashShift = std::move(o.mInfoHashShift);\n\t\t\t\t\t\t\t\tWHash::operator=(std::move(static_cast<WHash&>(o)));\n\t\t\t\t\t\t\t\tWKeyEqual::operator=(std::move(static_cast<WKeyEqual&>(o)));\n\t\t\t\t\t\t\t\tDataPool::operator=(std::move(static_cast<DataPool&>(o)));\n\n\t\t\t\t\t\t\t\to.init();\n\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t// nothing in the other map => just clear us.\n\t\t\t\t\t\t\t\tclear();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\n\t\t\t\tTable(const Table& o)\n\t\t\t\t\t: WHash(static_cast<const WHash&>(o))\n\t\t\t\t\t, WKeyEqual(static_cast<const WKeyEqual&>(o))\n\t\t\t\t\t, DataPool(static_cast<const DataPool&>(o)) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tif (!o.empty()) {\n\t\t\t\t\t\t\t// not empty: create an exact copy. it is also possible to just iterate through all\n\t\t\t\t\t\t\t// elements and insert them, but copying is probably faster.\n\n\t\t\t\t\t\t\tauto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);\n\t\t\t\t\t\t\tauto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);\n\n\t\t\t\t\t\t\tROBIN_HOOD_LOG(\"std::malloc \" << numBytesTotal << \" = calcNumBytesTotal(\"\n\t\t\t\t\t\t\t\t<< numElementsWithBuffer << \")\")\n\t\t\t\t\t\t\t\tmKeyVals = static_cast<Node*>(\n\t\t\t\t\t\t\t\t\tdetail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));\n\t\t\t\t\t\t\t// no need for calloc because clonData does memcpy\n\t\t\t\t\t\t\tmInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);\n\t\t\t\t\t\t\tmNumElements = o.mNumElements;\n\t\t\t\t\t\t\tmMask = o.mMask;\n\t\t\t\t\t\t\tmMaxNumElementsAllowed = o.mMaxNumElementsAllowed;\n\t\t\t\t\t\t\tmInfoInc = o.mInfoInc;\n\t\t\t\t\t\t\tmInfoHashShift = o.mInfoHashShift;\n\t\t\t\t\t\t\tcloneData(o);\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Creates a copy of the given map. Copy constructor of each entry is used.\n\t\t\t\t// Not sure why clang-tidy thinks this doesn't handle self assignment, it does\n\t\t\t\t// NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)\n\t\t\t\tTable& operator=(Table const& o) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tif (&o == this) {\n\t\t\t\t\t\t\t// prevent assigning of itself\n\t\t\t\t\t\t\treturn *this;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t// we keep using the old allocator and not assign the new one, because we want to keep\n\t\t\t\t\t// the memory available. when it is the same size.\n\t\t\t\t\tif (o.empty()) {\n\t\t\t\t\t\tif (0 == mMask) {\n\t\t\t\t\t\t\t// nothing to do, we are empty too\n\t\t\t\t\t\t\treturn *this;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// not empty: destroy what we have there\n\t\t\t\t\t\t// clear also resets mInfo to 0, that's sometimes not necessary.\n\t\t\t\t\t\tdestroy();\n\t\t\t\t\t\tinit();\n\t\t\t\t\t\tWHash::operator=(static_cast<const WHash&>(o));\n\t\t\t\t\t\tWKeyEqual::operator=(static_cast<const WKeyEqual&>(o));\n\t\t\t\t\t\tDataPool::operator=(static_cast<DataPool const&>(o));\n\n\t\t\t\t\t\treturn *this;\n\t\t\t\t\t}\n\n\t\t\t\t\t// clean up old stuff\n\t\t\t\t\tDestroyer<Self, IsFlat&& std::is_trivially_destructible<Node>::value>{}.nodes(*this);\n\n\t\t\t\t\tif (mMask != o.mMask) {\n\t\t\t\t\t\t// no luck: we don't have the same array size allocated, so we need to realloc.\n\t\t\t\t\t\tif (0 != mMask) {\n\t\t\t\t\t\t\t// only deallocate if we actually have data!\n\t\t\t\t\t\t\tROBIN_HOOD_LOG(\"std::free\")\n\t\t\t\t\t\t\t\tstd::free(mKeyVals);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tauto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);\n\t\t\t\t\t\tauto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);\n\t\t\t\t\t\tROBIN_HOOD_LOG(\"std::malloc \" << numBytesTotal << \" = calcNumBytesTotal(\"\n\t\t\t\t\t\t\t<< numElementsWithBuffer << \")\")\n\t\t\t\t\t\t\tmKeyVals = static_cast<Node*>(\n\t\t\t\t\t\t\t\tdetail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));\n\n\t\t\t\t\t\t// no need for calloc here because cloneData performs a memcpy.\n\t\t\t\t\t\tmInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);\n\t\t\t\t\t\t// sentinel is set in cloneData\n\t\t\t\t\t}\n\t\t\t\t\tWHash::operator=(static_cast<const WHash&>(o));\n\t\t\t\t\tWKeyEqual::operator=(static_cast<const WKeyEqual&>(o));\n\t\t\t\t\tDataPool::operator=(static_cast<DataPool const&>(o));\n\t\t\t\t\tmNumElements = o.mNumElements;\n\t\t\t\t\tmMask = o.mMask;\n\t\t\t\t\tmMaxNumElementsAllowed = o.mMaxNumElementsAllowed;\n\t\t\t\t\tmInfoInc = o.mInfoInc;\n\t\t\t\t\tmInfoHashShift = o.mInfoHashShift;\n\t\t\t\t\tcloneData(o);\n\n\t\t\t\t\treturn *this;\n\t\t\t\t}\n\n\t\t\t\t// Swaps everything between the two maps.\n\t\t\t\tvoid swap(Table& o) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tusing std::swap;\n\t\t\t\t\tswap(o, *this);\n\t\t\t\t}\n\n\t\t\t\t// Clears all data, without resizing.\n\t\t\t\tvoid clear() {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tif (empty()) {\n\t\t\t\t\t\t\t// don't do anything! also important because we don't want to write to\n\t\t\t\t\t\t\t// DummyInfoByte::b, even though we would just write 0 to it.\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\tDestroyer<Self, IsFlat&& std::is_trivially_destructible<Node>::value>{}.nodes(*this);\n\n\t\t\t\t\tauto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);\n\t\t\t\t\t// clear everything, then set the sentinel again\n\t\t\t\t\tuint8_t const z = 0;\n\t\t\t\t\tstd::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z);\n\t\t\t\t\tmInfo[numElementsWithBuffer] = 1;\n\n\t\t\t\t\tmInfoInc = InitialInfoInc;\n\t\t\t\t\tmInfoHashShift = InitialInfoHashShift;\n\t\t\t\t}\n\n\t\t\t\t// Destroys the map and all it's contents.\n\t\t\t\t~Table() {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tdestroy();\n\t\t\t\t}\n\n\t\t\t\t// Checks if both tables contain the same entries. Order is irrelevant.\n\t\t\t\tbool operator==(const Table& other) const {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tif (other.size() != size()) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\tfor (auto const& otherEntry : other) {\n\t\t\t\t\t\tif (!has(otherEntry)) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tbool operator!=(const Table& other) const {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn !operator==(other);\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename Q = mapped_type>\n\t\t\t\ttypename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](const key_type& key) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn doCreateByKey(key);\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename Q = mapped_type>\n\t\t\t\ttypename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](key_type&& key) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn doCreateByKey(std::move(key));\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename Iter>\n\t\t\t\tvoid insert(Iter first, Iter last) {\n\t\t\t\t\tfor (; first != last; ++first) {\n\t\t\t\t\t\t// value_type ctor needed because this might be called with std::pair's\n\t\t\t\t\t\tinsert(value_type(*first));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename... Args>\n\t\t\t\tstd::pair<iterator, bool> emplace(Args&&... args) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tNode n {\n\t\t\t\t\t\t*this, std::forward<Args>(args)...\n\t\t\t\t\t};\n\t\t\t\t\tauto r = doInsert(std::move(n));\n\t\t\t\t\tif (!r.second) {\n\t\t\t\t\t\t// insertion not possible: destroy node\n\t\t\t\t\t\t// NOLINTNEXTLINE(bugprone-use-after-move)\n\t\t\t\t\t\tn.destroy(*this);\n\t\t\t\t\t}\n\t\t\t\t\treturn r;\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename... Args>\n\t\t\t\tstd::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) {\n\t\t\t\t\treturn try_emplace_impl(key, std::forward<Args>(args)...);\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename... Args>\n\t\t\t\tstd::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {\n\t\t\t\t\treturn try_emplace_impl(std::move(key), std::forward<Args>(args)...);\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename... Args>\n\t\t\t\tstd::pair<iterator, bool> try_emplace(const_iterator hint, const key_type& key,\n\t\t\t\t\tArgs&&... args) {\n\t\t\t\t\t(void)hint;\n\t\t\t\t\treturn try_emplace_impl(key, std::forward<Args>(args)...);\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename... Args>\n\t\t\t\tstd::pair<iterator, bool> try_emplace(const_iterator hint, key_type&& key, Args&&... args) {\n\t\t\t\t\t(void)hint;\n\t\t\t\t\treturn try_emplace_impl(std::move(key), std::forward<Args>(args)...);\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename Mapped>\n\t\t\t\tstd::pair<iterator, bool> insert_or_assign(const key_type& key, Mapped&& obj) {\n\t\t\t\t\treturn insert_or_assign_impl(key, std::forward<Mapped>(obj));\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename Mapped>\n\t\t\t\tstd::pair<iterator, bool> insert_or_assign(key_type&& key, Mapped&& obj) {\n\t\t\t\t\treturn insert_or_assign_impl(std::move(key), std::forward<Mapped>(obj));\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename Mapped>\n\t\t\t\tstd::pair<iterator, bool> insert_or_assign(const_iterator hint, const key_type& key,\n\t\t\t\t\tMapped&& obj) {\n\t\t\t\t\t(void)hint;\n\t\t\t\t\treturn insert_or_assign_impl(key, std::forward<Mapped>(obj));\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename Mapped>\n\t\t\t\tstd::pair<iterator, bool> insert_or_assign(const_iterator hint, key_type&& key, Mapped&& obj) {\n\t\t\t\t\t(void)hint;\n\t\t\t\t\treturn insert_or_assign_impl(std::move(key), std::forward<Mapped>(obj));\n\t\t\t\t}\n\n\t\t\t\tstd::pair<iterator, bool> insert(const value_type& keyval) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn doInsert(keyval);\n\t\t\t\t}\n\n\t\t\t\tstd::pair<iterator, bool> insert(value_type&& keyval) {\n\t\t\t\t\treturn doInsert(std::move(keyval));\n\t\t\t\t}\n\n\t\t\t\t// Returns 1 if key is found, 0 otherwise.\n\t\t\t\tsize_t count(const key_type& key) const { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tauto kv = mKeyVals + findIdx(key);\n\t\t\t\t\tif (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename OtherKey, typename Self_ = Self>\n\t\t\t\t// NOLINTNEXTLINE(modernize-use-nodiscard)\n\t\t\t\ttypename std::enable_if<Self_::is_transparent, size_t>::type count(const OtherKey& key) const {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tauto kv = mKeyVals + findIdx(key);\n\t\t\t\t\tif (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {\n\t\t\t\t\t\treturn 1;\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\tbool contains(const key_type& key) const { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\treturn 1U == count(key);\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename OtherKey, typename Self_ = Self>\n\t\t\t\t// NOLINTNEXTLINE(modernize-use-nodiscard)\n\t\t\t\ttypename std::enable_if<Self_::is_transparent, bool>::type contains(const OtherKey& key) const {\n\t\t\t\t\treturn 1U == count(key);\n\t\t\t\t}\n\n\t\t\t\t// Returns a reference to the value found for key.\n\t\t\t\t// Throws std::out_of_range if element cannot be found\n\t\t\t\ttemplate <typename Q = mapped_type>\n\t\t\t\t// NOLINTNEXTLINE(modernize-use-nodiscard)\n\t\t\t\ttypename std::enable_if<!std::is_void<Q>::value, Q&>::type at(key_type const& key) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tauto kv = mKeyVals + findIdx(key);\n\t\t\t\t\tif (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {\n\t\t\t\t\t\tdoThrow<std::out_of_range>(\"key not found\");\n\t\t\t\t\t}\n\t\t\t\t\treturn kv->getSecond();\n\t\t\t\t}\n\n\t\t\t\t// Returns a reference to the value found for key.\n\t\t\t\t// Throws std::out_of_range if element cannot be found\n\t\t\t\ttemplate <typename Q = mapped_type>\n\t\t\t\t// NOLINTNEXTLINE(modernize-use-nodiscard)\n\t\t\t\ttypename std::enable_if<!std::is_void<Q>::value, Q const&>::type at(key_type const& key) const {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tauto kv = mKeyVals + findIdx(key);\n\t\t\t\t\tif (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {\n\t\t\t\t\t\tdoThrow<std::out_of_range>(\"key not found\");\n\t\t\t\t\t}\n\t\t\t\t\treturn kv->getSecond();\n\t\t\t\t}\n\n\t\t\t\tconst_iterator find(const key_type& key) const { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tconst size_t idx = findIdx(key);\n\t\t\t\t\treturn const_iterator{ mKeyVals + idx, mInfo + idx };\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename OtherKey>\n\t\t\t\tconst_iterator find(const OtherKey& key, is_transparent_tag /*unused*/) const {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tconst size_t idx = findIdx(key);\n\t\t\t\t\treturn const_iterator{ mKeyVals + idx, mInfo + idx };\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename OtherKey, typename Self_ = Self>\n\t\t\t\ttypename std::enable_if<Self_::is_transparent, // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tconst_iterator>::type  // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tfind(const OtherKey& key) const {              // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tconst size_t idx = findIdx(key);\n\t\t\t\t\treturn const_iterator{ mKeyVals + idx, mInfo + idx };\n\t\t\t\t}\n\n\t\t\t\titerator find(const key_type& key) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tconst size_t idx = findIdx(key);\n\t\t\t\t\treturn iterator{ mKeyVals + idx, mInfo + idx };\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename OtherKey>\n\t\t\t\titerator find(const OtherKey& key, is_transparent_tag /*unused*/) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tconst size_t idx = findIdx(key);\n\t\t\t\t\treturn iterator{ mKeyVals + idx, mInfo + idx };\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename OtherKey, typename Self_ = Self>\n\t\t\t\ttypename std::enable_if<Self_::is_transparent, iterator>::type find(const OtherKey& key) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tconst size_t idx = findIdx(key);\n\t\t\t\t\treturn iterator{ mKeyVals + idx, mInfo + idx };\n\t\t\t\t}\n\n\t\t\t\titerator begin() {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tif (empty()) {\n\t\t\t\t\t\t\treturn end();\n\t\t\t\t\t\t}\n\t\t\t\t\treturn iterator(mKeyVals, mInfo, fast_forward_tag{});\n\t\t\t\t}\n\t\t\t\tconst_iterator begin() const { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn cbegin();\n\t\t\t\t}\n\t\t\t\tconst_iterator cbegin() const { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tif (empty()) {\n\t\t\t\t\t\t\treturn cend();\n\t\t\t\t\t\t}\n\t\t\t\t\treturn const_iterator(mKeyVals, mInfo, fast_forward_tag{});\n\t\t\t\t}\n\n\t\t\t\titerator end() {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\t// no need to supply valid info pointer: end() must not be dereferenced, and only node\n\t\t\t\t\t\t// pointer is compared.\n\t\t\t\t\t\treturn iterator{ reinterpret_cast_no_cast_align_warning<Node*>(mInfo), nullptr };\n\t\t\t\t}\n\t\t\t\tconst_iterator end() const { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn cend();\n\t\t\t\t}\n\t\t\t\tconst_iterator cend() const { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn const_iterator{ reinterpret_cast_no_cast_align_warning<Node*>(mInfo), nullptr };\n\t\t\t\t}\n\n\t\t\t\titerator erase(const_iterator pos) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\t// its safe to perform const cast here\n\t\t\t\t\t\t// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)\n\t\t\t\t\t\treturn erase(iterator{ const_cast<Node*>(pos.mKeyVals), const_cast<uint8_t*>(pos.mInfo) });\n\t\t\t\t}\n\n\t\t\t\t// Erases element at pos, returns iterator to the next element.\n\t\t\t\titerator erase(iterator pos) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\t// we assume that pos always points to a valid entry, and not end().\n\t\t\t\t\t\tauto const idx = static_cast<size_t>(pos.mKeyVals - mKeyVals);\n\n\t\t\t\t\tshiftDown(idx);\n\t\t\t\t\t--mNumElements;\n\n\t\t\t\t\tif (*pos.mInfo) {\n\t\t\t\t\t\t// we've backward shifted, return this again\n\t\t\t\t\t\treturn pos;\n\t\t\t\t\t}\n\n\t\t\t\t\t// no backward shift, return next element\n\t\t\t\t\treturn ++pos;\n\t\t\t\t}\n\n\t\t\t\tsize_t erase(const key_type& key) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tsize_t idx {};\n\t\t\t\t\tInfoType info{};\n\t\t\t\t\tkeyToIdx(key, &idx, &info);\n\n\t\t\t\t\t// check while info matches with the source idx\n\t\t\t\t\tdo {\n\t\t\t\t\t\tif (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {\n\t\t\t\t\t\t\tshiftDown(idx);\n\t\t\t\t\t\t\t--mNumElements;\n\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnext(&info, &idx);\n\t\t\t\t\t} while (info <= mInfo[idx]);\n\n\t\t\t\t\t// nothing found to delete\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\t// reserves space for the specified number of elements. Makes sure the old data fits.\n\t\t\t\t// exactly the same as reserve(c).\n\t\t\t\tvoid rehash(size_t c) {\n\t\t\t\t\t// forces a reserve\n\t\t\t\t\treserve(c, true);\n\t\t\t\t}\n\n\t\t\t\t// reserves space for the specified number of elements. Makes sure the old data fits.\n\t\t\t\t// Exactly the same as rehash(c). Use rehash(0) to shrink to fit.\n\t\t\t\tvoid reserve(size_t c) {\n\t\t\t\t\t// reserve, but don't force rehash\n\t\t\t\t\treserve(c, false);\n\t\t\t\t}\n\n\t\t\t\t// If possible reallocates the map to a smaller one. This frees the underlying table.\n\t\t\t\t// Does not do anything if load_factor is too large for decreasing the table's size.\n\t\t\t\tvoid compact() {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tauto newSize = InitialNumElements;\n\t\t\t\t\twhile (calcMaxNumElementsAllowed(newSize) < mNumElements && newSize != 0) {\n\t\t\t\t\t\tnewSize *= 2;\n\t\t\t\t\t}\n\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(newSize == 0)) {\n\t\t\t\t\t\tthrowOverflowError();\n\t\t\t\t\t}\n\n\t\t\t\t\tROBIN_HOOD_LOG(\"newSize > mMask + 1: \" << newSize << \" > \" << mMask << \" + 1\")\n\n\t\t\t\t\t\t// only actually do anything when the new size is bigger than the old one. This prevents to\n\t\t\t\t\t\t// continuously allocate for each reserve() call.\n\t\t\t\t\t\tif (newSize < mMask + 1) {\n\t\t\t\t\t\t\trehashPowerOfTwo(newSize, true);\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsize_type size() const noexcept { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn mNumElements;\n\t\t\t\t}\n\n\t\t\t\tsize_type max_size() const noexcept { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn static_cast<size_type>(-1);\n\t\t\t\t}\n\n\t\t\t\tROBIN_HOOD(NODISCARD) bool empty() const noexcept {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn 0 == mNumElements;\n\t\t\t\t}\n\n\t\t\t\tfloat max_load_factor() const noexcept { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn MaxLoadFactor100 / 100.0F;\n\t\t\t\t}\n\n\t\t\t\t// Average number of elements per bucket. Since we allow only 1 per bucket\n\t\t\t\tfloat load_factor() const noexcept { // NOLINT(modernize-use-nodiscard)\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn static_cast<float>(size()) / static_cast<float>(mMask + 1);\n\t\t\t\t}\n\n\t\t\t\tROBIN_HOOD(NODISCARD) size_t mask() const noexcept {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn mMask;\n\t\t\t\t}\n\n\t\t\t\tROBIN_HOOD(NODISCARD) size_t calcMaxNumElementsAllowed(size_t maxElements) const noexcept {\n\t\t\t\t\tif (ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits<size_t>::max)() / 100)) {\n\t\t\t\t\t\treturn maxElements * MaxLoadFactor100 / 100;\n\t\t\t\t\t}\n\n\t\t\t\t\t// we might be a bit inprecise, but since maxElements is quite large that doesn't matter\n\t\t\t\t\treturn (maxElements / 100) * MaxLoadFactor100;\n\t\t\t\t}\n\n\t\t\t\tROBIN_HOOD(NODISCARD) size_t calcNumBytesInfo(size_t numElements) const noexcept {\n\t\t\t\t\t// we add a uint64_t, which houses the sentinel (first byte) and padding so we can load\n\t\t\t\t\t// 64bit types.\n\t\t\t\t\treturn numElements + sizeof(uint64_t);\n\t\t\t\t}\n\n\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\tsize_t calcNumElementsWithBuffer(size_t numElements) const noexcept {\n\t\t\t\t\tauto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements);\n\t\t\t\t\treturn numElements + (std::min)(maxNumElementsAllowed, (static_cast<size_t>(0xFF)));\n\t\t\t\t}\n\n\t\t\t\t// calculation only allowed for 2^n values\n\t\t\t\tROBIN_HOOD(NODISCARD) size_t calcNumBytesTotal(size_t numElements) const {\n#if ROBIN_HOOD(BITNESS) == 64\n\t\t\t\t\treturn numElements * sizeof(Node) + calcNumBytesInfo(numElements);\n#else\n\t\t\t\t\t// make sure we're doing 64bit operations, so we are at least safe against 32bit overflows.\n\t\t\t\t\tauto const ne = static_cast<uint64_t>(numElements);\n\t\t\t\t\tauto const s = static_cast<uint64_t>(sizeof(Node));\n\t\t\t\t\tauto const infos = static_cast<uint64_t>(calcNumBytesInfo(numElements));\n\n\t\t\t\t\tauto const total64 = ne * s + infos;\n\t\t\t\t\tauto const total = static_cast<size_t>(total64);\n\n\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(static_cast<uint64_t>(total) != total64)) {\n\t\t\t\t\t\tthrowOverflowError();\n\t\t\t\t\t}\n\t\t\t\t\treturn total;\n#endif\n\t\t\t\t}\n\n\t\t\tprivate:\n\t\t\t\ttemplate <typename Q = mapped_type>\n\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\ttypename std::enable_if<!std::is_void<Q>::value, bool>::type has(const value_type& e) const {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tauto it = find(e.first);\n\t\t\t\t\treturn it != end() && it->second == e.second;\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename Q = mapped_type>\n\t\t\t\tROBIN_HOOD(NODISCARD)\n\t\t\t\t\ttypename std::enable_if<std::is_void<Q>::value, bool>::type has(const value_type& e) const {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\treturn find(e) != end();\n\t\t\t\t}\n\n\t\t\t\tvoid reserve(size_t c, bool forceRehash) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tauto const minElementsAllowed = (std::max)(c, mNumElements);\n\t\t\t\t\tauto newSize = InitialNumElements;\n\t\t\t\t\twhile (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) {\n\t\t\t\t\t\tnewSize *= 2;\n\t\t\t\t\t}\n\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(newSize == 0)) {\n\t\t\t\t\t\tthrowOverflowError();\n\t\t\t\t\t}\n\n\t\t\t\t\tROBIN_HOOD_LOG(\"newSize > mMask + 1: \" << newSize << \" > \" << mMask << \" + 1\")\n\n\t\t\t\t\t\t// only actually do anything when the new size is bigger than the old one. This prevents to\n\t\t\t\t\t\t// continuously allocate for each reserve() call.\n\t\t\t\t\t\tif (forceRehash || newSize > mMask + 1) {\n\t\t\t\t\t\t\trehashPowerOfTwo(newSize, false);\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// reserves space for at least the specified number of elements.\n\t\t\t\t// only works if numBuckets if power of two\n\t\t\t\tvoid rehashPowerOfTwo(size_t numBuckets, bool forceFree) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\n\t\t\t\t\t\tNode* const oldKeyVals = mKeyVals;\n\t\t\t\t\tuint8_t const* const oldInfo = mInfo;\n\n\t\t\t\t\tconst size_t oldMaxElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);\n\n\t\t\t\t\t// resize operation: move stuff\n\t\t\t\t\tinit_data(numBuckets);\n\t\t\t\t\tif (oldMaxElementsWithBuffer > 1) {\n\t\t\t\t\t\tfor (size_t i = 0; i < oldMaxElementsWithBuffer; ++i) {\n\t\t\t\t\t\t\tif (oldInfo[i] != 0) {\n\t\t\t\t\t\t\t\tinsert_move(std::move(oldKeyVals[i]));\n\t\t\t\t\t\t\t\t// destroy the node but DON'T destroy the data.\n\t\t\t\t\t\t\t\toldKeyVals[i].~Node();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// this check is not necessary as it's guarded by the previous if, but it helps silence\n\t\t\t\t\t\t// g++'s overeager \"attempt to free a non-heap object 'map'\n\t\t\t\t\t\t// [-Werror=free-nonheap-object]\" warning.\n\t\t\t\t\t\tif (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {\n\t\t\t\t\t\t\t// don't destroy old data: put it into the pool instead\n\t\t\t\t\t\t\tif (forceFree) {\n\t\t\t\t\t\t\t\tstd::free(oldKeyVals);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tDataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tROBIN_HOOD(NOINLINE) void throwOverflowError() const {\n#if ROBIN_HOOD(HAS_EXCEPTIONS)\n\t\t\t\t\tthrow std::overflow_error(\"robin_hood::map overflow\");\n#else\n\t\t\t\t\tabort();\n#endif\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename OtherKey, typename... Args>\n\t\t\t\tstd::pair<iterator, bool> try_emplace_impl(OtherKey&& key, Args&&... args) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tauto it = find(key);\n\t\t\t\t\tif (it == end()) {\n\t\t\t\t\t\treturn emplace(std::piecewise_construct,\n\t\t\t\t\t\t\tstd::forward_as_tuple(std::forward<OtherKey>(key)),\n\t\t\t\t\t\t\tstd::forward_as_tuple(std::forward<Args>(args)...));\n\t\t\t\t\t}\n\t\t\t\t\treturn { it, false };\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename OtherKey, typename Mapped>\n\t\t\t\tstd::pair<iterator, bool> insert_or_assign_impl(OtherKey&& key, Mapped&& obj) {\n\t\t\t\t\tROBIN_HOOD_TRACE(this)\n\t\t\t\t\t\tauto it = find(key);\n\t\t\t\t\tif (it == end()) {\n\t\t\t\t\t\treturn emplace(std::forward<OtherKey>(key), std::forward<Mapped>(obj));\n\t\t\t\t\t}\n\t\t\t\t\tit->second = std::forward<Mapped>(obj);\n\t\t\t\t\treturn { it, false };\n\t\t\t\t}\n\n\t\t\t\tvoid init_data(size_t max_elements) {\n\t\t\t\t\tmNumElements = 0;\n\t\t\t\t\tmMask = max_elements - 1;\n\t\t\t\t\tmMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements);\n\n\t\t\t\t\tauto const numElementsWithBuffer = calcNumElementsWithBuffer(max_elements);\n\n\t\t\t\t\t// calloc also zeroes everything\n\t\t\t\t\tauto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);\n\t\t\t\t\tROBIN_HOOD_LOG(\"std::calloc \" << numBytesTotal << \" = calcNumBytesTotal(\"\n\t\t\t\t\t\t<< numElementsWithBuffer << \")\")\n\t\t\t\t\t\tmKeyVals = reinterpret_cast<Node*>(\n\t\t\t\t\t\t\tdetail::assertNotNull<std::bad_alloc>(std::calloc(1, numBytesTotal)));\n\t\t\t\t\tmInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);\n\n\t\t\t\t\t// set sentinel\n\t\t\t\t\tmInfo[numElementsWithBuffer] = 1;\n\n\t\t\t\t\tmInfoInc = InitialInfoInc;\n\t\t\t\t\tmInfoHashShift = InitialInfoHashShift;\n\t\t\t\t}\n\n\t\t\t\ttemplate <typename Arg, typename Q = mapped_type>\n\t\t\t\ttypename std::enable_if<!std::is_void<Q>::value, Q&>::type doCreateByKey(Arg&& key) {\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tsize_t idx{};\n\t\t\t\t\t\tInfoType info{};\n\t\t\t\t\t\tkeyToIdx(key, &idx, &info);\n\t\t\t\t\t\tnextWhileLess(&info, &idx);\n\n\t\t\t\t\t\t// while we potentially have a match. Can't do a do-while here because when mInfo is\n\t\t\t\t\t\t// 0 we don't want to skip forward\n\t\t\t\t\t\twhile (info == mInfo[idx]) {\n\t\t\t\t\t\t\tif (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {\n\t\t\t\t\t\t\t\t// key already exists, do not insert.\n\t\t\t\t\t\t\t\treturn mKeyVals[idx].getSecond();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnext(&info, &idx);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// unlikely that this evaluates to true\n\t\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(mNumElements >= mMaxNumElementsAllowed)) {\n\t\t\t\t\t\t\tincrease_size();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// key not found, so we are now exactly where we want to insert it.\n\t\t\t\t\t\tauto const insertion_idx = idx;\n\t\t\t\t\t\tauto const insertion_info = info;\n\t\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {\n\t\t\t\t\t\t\tmMaxNumElementsAllowed = 0;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// find an empty spot\n\t\t\t\t\t\twhile (0 != mInfo[idx]) {\n\t\t\t\t\t\t\tnext(&info, &idx);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tauto& l = mKeyVals[insertion_idx];\n\t\t\t\t\t\tif (idx == insertion_idx) {\n\t\t\t\t\t\t\t// put at empty spot. This forwards all arguments into the node where the object\n\t\t\t\t\t\t\t// is constructed exactly where it is needed.\n\t\t\t\t\t\t\t::new (static_cast<void*>(&l))\n\t\t\t\t\t\t\t\tNode(*this, std::piecewise_construct,\n\t\t\t\t\t\t\t\t\tstd::forward_as_tuple(std::forward<Arg>(key)), std::forward_as_tuple());\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tshiftUp(idx, insertion_idx);\n\t\t\t\t\t\t\tl = Node(*this, std::piecewise_construct,\n\t\t\t\t\t\t\t\tstd::forward_as_tuple(std::forward<Arg>(key)), std::forward_as_tuple());\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// mKeyVals[idx].getFirst() = std::move(key);\n\t\t\t\t\t\tmInfo[insertion_idx] = static_cast<uint8_t>(insertion_info);\n\n\t\t\t\t\t\t++mNumElements;\n\t\t\t\t\t\treturn mKeyVals[insertion_idx].getSecond();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// This is exactly the same code as operator[], except for the return values\n\t\t\t\ttemplate <typename Arg>\n\t\t\t\tstd::pair<iterator, bool> doInsert(Arg&& keyval) {\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\tsize_t idx{};\n\t\t\t\t\t\tInfoType info{};\n\t\t\t\t\t\tkeyToIdx(getFirstConst(keyval), &idx, &info);\n\t\t\t\t\t\tnextWhileLess(&info, &idx);\n\n\t\t\t\t\t\t// while we potentially have a match\n\t\t\t\t\t\twhile (info == mInfo[idx]) {\n\t\t\t\t\t\t\tif (WKeyEqual::operator()(getFirstConst(keyval), mKeyVals[idx].getFirst())) {\n\t\t\t\t\t\t\t\t// key already exists, do NOT insert.\n\t\t\t\t\t\t\t\t// see http://en.cppreference.com/w/cpp/container/unordered_map/insert\n\t\t\t\t\t\t\t\treturn std::make_pair<iterator, bool>(iterator(mKeyVals + idx, mInfo + idx),\n\t\t\t\t\t\t\t\t\tfalse);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnext(&info, &idx);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// unlikely that this evaluates to true\n\t\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(mNumElements >= mMaxNumElementsAllowed)) {\n\t\t\t\t\t\t\tincrease_size();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// key not found, so we are now exactly where we want to insert it.\n\t\t\t\t\t\tauto const insertion_idx = idx;\n\t\t\t\t\t\tauto const insertion_info = info;\n\t\t\t\t\t\tif (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {\n\t\t\t\t\t\t\tmMaxNumElementsAllowed = 0;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// find an empty spot\n\t\t\t\t\t\twhile (0 != mInfo[idx]) {\n\t\t\t\t\t\t\tnext(&info, &idx);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tauto& l = mKeyVals[insertion_idx];\n\t\t\t\t\t\tif (idx == insertion_idx) {\n\t\t\t\t\t\t\t::new (static_cast<void*>(&l)) Node(*this, std::forward<Arg>(keyval));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tshiftUp(idx, insertion_idx);\n\t\t\t\t\t\t\tl = Node(*this, std::forward<Arg>(keyval));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// put at empty spot\n\t\t\t\t\t\tmInfo[insertion_idx] = static_cast<uint8_t>(insertion_info);\n\n\t\t\t\t\t\t++mNumElements;\n\t\t\t\t\t\treturn std::make_pair(iterator(mKeyVals + insertion_idx, mInfo + insertion_idx), true);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbool try_increase_info() {\n\t\t\t\t\tROBIN_HOOD_LOG(\"mInfoInc=\" << mInfoInc << \", numElements=\" << mNumElements\n\t\t\t\t\t\t<< \", maxNumElementsAllowed=\"\n\t\t\t\t\t\t<< calcMaxNumElementsAllowed(mMask + 1))\n\t\t\t\t\t\tif (mInfoInc <= 2) {\n\t\t\t\t\t\t\t// need to be > 2 so that shift works (otherwise undefined behavior!)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t// we got space left, try to make info smaller\n\t\t\t\t\tmInfoInc = static_cast<uint8_t>(mInfoInc >> 1U);\n\n\t\t\t\t\t// remove one bit of the hash, leaving more space for the distance info.\n\t\t\t\t\t// This is extremely fast because we can operate on 8 bytes at once.\n\t\t\t\t\t++mInfoHashShift;\n\t\t\t\t\tauto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);\n\n\t\t\t\t\tfor (size_t i = 0; i < numElementsWithBuffer; i += 8) {\n\t\t\t\t\t\tauto val = unaligned_load<uint64_t>(mInfo + i);\n\t\t\t\t\t\tval = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f);\n\t\t\t\t\t\tstd::memcpy(mInfo + i, &val, sizeof(val));\n\t\t\t\t\t}\n\t\t\t\t\t// update sentinel, which might have been cleared out!\n\t\t\t\t\tmInfo[numElementsWithBuffer] = 1;\n\n\t\t\t\t\tmMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tvoid increase_size() {\n\t\t\t\t\t// nothing allocated yet? just allocate InitialNumElements\n\t\t\t\t\tif (0 == mMask) {\n\t\t\t\t\t\tinit_data(InitialNumElements);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tauto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);\n\t\t\t\t\tif (mNumElements < maxNumElementsAllowed && try_increase_info()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tROBIN_HOOD_LOG(\"mNumElements=\" << mNumElements << \", maxNumElementsAllowed=\"\n\t\t\t\t\t\t<< maxNumElementsAllowed << \", load=\"\n\t\t\t\t\t\t<< (static_cast<double>(mNumElements) * 100.0 /\n\t\t\t\t\t\t\t(static_cast<double>(mMask) + 1)))\n\t\t\t\t\t\t// it seems we have a really bad hash function! don't try to resize again\n\t\t\t\t\t\tif (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) {\n\t\t\t\t\t\t\tthrowOverflowError();\n\t\t\t\t\t\t}\n\n\t\t\t\t\trehashPowerOfTwo((mMask + 1) * 2, false);\n\t\t\t\t}\n\n\t\t\t\tvoid destroy() {\n\t\t\t\t\tif (0 == mMask) {\n\t\t\t\t\t\t// don't deallocate!\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tDestroyer<Self, IsFlat&& std::is_trivially_destructible<Node>::value>{}\n\t\t\t\t\t.nodesDoNotDeallocate(*this);\n\n\t\t\t\t\t// This protection against not deleting mMask shouldn't be needed as it's sufficiently\n\t\t\t\t\t// protected with the 0==mMask check, but I have this anyways because g++ 7 otherwise\n\t\t\t\t\t// reports a compile error: attempt to free a non-heap object 'fm'\n\t\t\t\t\t// [-Werror=free-nonheap-object]\n\t\t\t\t\tif (mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {\n\t\t\t\t\t\tROBIN_HOOD_LOG(\"std::free\")\n\t\t\t\t\t\t\tstd::free(mKeyVals);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvoid init() noexcept {\n\t\t\t\t\tmKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);\n\t\t\t\t\tmInfo = reinterpret_cast<uint8_t*>(&mMask);\n\t\t\t\t\tmNumElements = 0;\n\t\t\t\t\tmMask = 0;\n\t\t\t\t\tmMaxNumElementsAllowed = 0;\n\t\t\t\t\tmInfoInc = InitialInfoInc;\n\t\t\t\t\tmInfoHashShift = InitialInfoHashShift;\n\t\t\t\t}\n\n\t\t\t\t// members are sorted so no padding occurs\n\t\t\t\tNode* mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask); // 8 byte  8\n\t\t\t\tuint8_t* mInfo = reinterpret_cast<uint8_t*>(&mMask);                    // 8 byte 16\n\t\t\t\tsize_t mNumElements = 0;                                                // 8 byte 24\n\t\t\t\tsize_t mMask = 0;                                                       // 8 byte 32\n\t\t\t\tsize_t mMaxNumElementsAllowed = 0;                                      // 8 byte 40\n\t\t\t\tInfoType mInfoInc = InitialInfoInc;                                     // 4 byte 44\n\t\t\t\tInfoType mInfoHashShift = InitialInfoHashShift;                         // 4 byte 48\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 16 byte 56 if NodeAllocator\n\t\t};\n\n\t} // namespace detail\n\n\t// map\n\n\ttemplate <typename Key, typename T, typename Hash = hash<Key>,\n\t\ttypename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>\n\t\tusing unordered_flat_map = detail::Table<true, MaxLoadFactor100, Key, T, Hash, KeyEqual>;\n\n\ttemplate <typename Key, typename T, typename Hash = hash<Key>,\n\t\ttypename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>\n\t\tusing unordered_node_map = detail::Table<false, MaxLoadFactor100, Key, T, Hash, KeyEqual>;\n\n\ttemplate <typename Key, typename T, typename Hash = hash<Key>,\n\t\ttypename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>\n\t\tusing unordered_map =\n\t\tdetail::Table<sizeof(robin_hood::pair<Key, T>) <= sizeof(size_t) * 6 &&\n\t\tstd::is_nothrow_move_constructible<robin_hood::pair<Key, T>>::value &&\n\t\tstd::is_nothrow_move_assignable<robin_hood::pair<Key, T>>::value,\n\t\tMaxLoadFactor100, Key, T, Hash, KeyEqual>;\n\n\t// set\n\n\ttemplate <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,\n\t\tsize_t MaxLoadFactor100 = 80>\n\t\tusing unordered_flat_set = detail::Table<true, MaxLoadFactor100, Key, void, Hash, KeyEqual>;\n\n\ttemplate <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,\n\t\tsize_t MaxLoadFactor100 = 80>\n\t\tusing unordered_node_set = detail::Table<false, MaxLoadFactor100, Key, void, Hash, KeyEqual>;\n\n\ttemplate <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,\n\t\tsize_t MaxLoadFactor100 = 80>\n\t\tusing unordered_set = detail::Table<sizeof(Key) <= sizeof(size_t) * 6 &&\n\t\tstd::is_nothrow_move_constructible<Key>::value &&\n\t\tstd::is_nothrow_move_assignable<Key>::value,\n\t\tMaxLoadFactor100, Key, void, Hash, KeyEqual>;\n\n} // namespace robin_hood\n\n#endif\n"
  },
  {
    "path": "src/util/crypto/aes128.cpp",
    "content": "/*\n\tOriginal implementation based on Tiny-AES-c (2015)\n\thttps://github.com/kokke/tiny-AES-c\n\n\tModified by Exzap\n*/\n\n\n/*****************************************************************************/\n/* Includes:                                                                 */\n/*****************************************************************************/\n#include \"aes128.h\"\n#include \"Common/cpu_features.h\"\n\n/*****************************************************************************/\n/* Defines:                                                                  */\n/*****************************************************************************/\n// The number of columns comprising a state in AES. This is a constant in AES. Value=4\n#define Nb 4\n// The number of 32 bit words in a key.\n#define Nk 4\n// Key length in bytes [128 bit]\n#define KEYLEN 16\n// The number of rounds in AES Cipher.\n#define Nr 10\n\ntypedef uint8 state_t[4][4];\n\ntypedef struct\n{\n\tstate_t* state;\n\tuint8 RoundKey[176];\n}aes128Ctx_t;\n\n#define stateVal(__x, __y) ((*aesCtx->state)[__x][__y])\n#define stateValU32(__x) (*(uint32*)((*aesCtx->state)[__x]))\n\n// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM\n// The numbers below can be computed dynamically trading ROM for RAM - \n// This can be useful in (embedded) bootloader applications, where ROM is often limited.\nstatic const uint8 sbox[256] = {\n\t//0     1    2      3     4    5     6     7      8    9     A      B    C     D     E     F\n\t0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,\n\t0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,\n\t0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,\n\t0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,\n\t0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,\n\t0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,\n\t0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,\n\t0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,\n\t0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,\n\t0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,\n\t0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,\n\t0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,\n\t0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,\n\t0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,\n\t0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,\n\t0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };\n\nstatic const uint8 rsbox[256] =\n{ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,\n  0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,\n  0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,\n  0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,\n  0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,\n  0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,\n  0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,\n  0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,\n  0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,\n  0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,\n  0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,\n  0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,\n  0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,\n  0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,\n  0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,\n  0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };\n\n\n// The round constant word array, Rcon[i], contains the values given by \n// x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)\n// Note that i starts at 1, not 0).\nstatic const uint8 Rcon[255] = {\n  0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,\n  0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,\n  0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,\n  0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,\n  0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,\n  0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,\n  0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,\n  0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,\n  0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,\n  0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,\n  0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,\n  0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,\n  0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,\n  0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,\n  0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,\n  0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb };\n\n\n/*****************************************************************************/\n/* Private functions:                                                        */\n/*****************************************************************************/\nuint8 getSBoxValue(uint8 num)\n{\n\treturn sbox[num];\n}\n\nuint8 getSBoxInvert(uint8 num)\n{\n\treturn rsbox[num];\n}\n\n// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. \nvoid KeyExpansion(aes128Ctx_t* aesCtx, const uint8* key)\n{\n\tuint32 i, j, k;\n\tuint8 tempa[4]; // Used for the column/row operations\n\n\t// The first round key is the key itself.\n\tfor (i = 0; i < Nk; ++i)\n\t{\n\t\taesCtx->RoundKey[(i * 4) + 0] = key[(i * 4) + 0];\n\t\taesCtx->RoundKey[(i * 4) + 1] = key[(i * 4) + 1];\n\t\taesCtx->RoundKey[(i * 4) + 2] = key[(i * 4) + 2];\n\t\taesCtx->RoundKey[(i * 4) + 3] = key[(i * 4) + 3];\n\t}\n\n\t// All other round keys are found from the previous round keys.\n\tfor (; (i < (Nb * (Nr + 1))); ++i)\n\t{\n\t\tfor (j = 0; j < 4; ++j)\n\t\t{\n\t\t\ttempa[j] = aesCtx->RoundKey[(i - 1) * 4 + j];\n\t\t}\n\t\tif (i % Nk == 0)\n\t\t{\n\t\t\t// This function rotates the 4 bytes in a word to the left once.\n\t\t\t// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]\n\n\t\t\t// Function RotWord()\n\t\t\t{\n\t\t\t\tk = tempa[0];\n\t\t\t\ttempa[0] = tempa[1];\n\t\t\t\ttempa[1] = tempa[2];\n\t\t\t\ttempa[2] = tempa[3];\n\t\t\t\ttempa[3] = k;\n\t\t\t}\n\n\t\t\t// SubWord() is a function that takes a four-byte input word and \n\t\t\t// applies the S-box to each of the four bytes to produce an output word.\n\n\t\t\t// Function Subword()\n\t\t\t{\n\t\t\t\ttempa[0] = getSBoxValue(tempa[0]);\n\t\t\t\ttempa[1] = getSBoxValue(tempa[1]);\n\t\t\t\ttempa[2] = getSBoxValue(tempa[2]);\n\t\t\t\ttempa[3] = getSBoxValue(tempa[3]);\n\t\t\t}\n\n\t\t\ttempa[0] = tempa[0] ^ Rcon[i / Nk];\n\t\t}\n\t\telse if (Nk > 6 && i % Nk == 4)\n\t\t{\n\t\t\t// Function Subword()\n\t\t\t{\n\t\t\t\ttempa[0] = getSBoxValue(tempa[0]);\n\t\t\t\ttempa[1] = getSBoxValue(tempa[1]);\n\t\t\t\ttempa[2] = getSBoxValue(tempa[2]);\n\t\t\t\ttempa[3] = getSBoxValue(tempa[3]);\n\t\t\t}\n\t\t}\n\t\taesCtx->RoundKey[i * 4 + 0] = aesCtx->RoundKey[(i - Nk) * 4 + 0] ^ tempa[0];\n\t\taesCtx->RoundKey[i * 4 + 1] = aesCtx->RoundKey[(i - Nk) * 4 + 1] ^ tempa[1];\n\t\taesCtx->RoundKey[i * 4 + 2] = aesCtx->RoundKey[(i - Nk) * 4 + 2] ^ tempa[2];\n\t\taesCtx->RoundKey[i * 4 + 3] = aesCtx->RoundKey[(i - Nk) * 4 + 3] ^ tempa[3];\n\t}\n}\n\n// This function adds the round key to state.\n// The round key is added to the state by an XOR function.\nvoid AddRoundKey(aes128Ctx_t* aesCtx, uint8 round)\n{\n\t// note: replacing this with two 64bit xor operations decreased performance in benchmarks, probably because the state bytes need to be stored back in memory\n\n\tstateVal(0, 0) ^= aesCtx->RoundKey[round * Nb * 4 + 0 * Nb + 0];\n\tstateVal(0, 1) ^= aesCtx->RoundKey[round * Nb * 4 + 0 * Nb + 1];\n\tstateVal(0, 2) ^= aesCtx->RoundKey[round * Nb * 4 + 0 * Nb + 2];\n\tstateVal(0, 3) ^= aesCtx->RoundKey[round * Nb * 4 + 0 * Nb + 3];\n\n\tstateVal(1, 0) ^= aesCtx->RoundKey[round * Nb * 4 + 1 * Nb + 0];\n\tstateVal(1, 1) ^= aesCtx->RoundKey[round * Nb * 4 + 1 * Nb + 1];\n\tstateVal(1, 2) ^= aesCtx->RoundKey[round * Nb * 4 + 1 * Nb + 2];\n\tstateVal(1, 3) ^= aesCtx->RoundKey[round * Nb * 4 + 1 * Nb + 3];\n\n\tstateVal(2, 0) ^= aesCtx->RoundKey[round * Nb * 4 + 2 * Nb + 0];\n\tstateVal(2, 1) ^= aesCtx->RoundKey[round * Nb * 4 + 2 * Nb + 1];\n\tstateVal(2, 2) ^= aesCtx->RoundKey[round * Nb * 4 + 2 * Nb + 2];\n\tstateVal(2, 3) ^= aesCtx->RoundKey[round * Nb * 4 + 2 * Nb + 3];\n\n\tstateVal(3, 0) ^= aesCtx->RoundKey[round * Nb * 4 + 3 * Nb + 0];\n\tstateVal(3, 1) ^= aesCtx->RoundKey[round * Nb * 4 + 3 * Nb + 1];\n\tstateVal(3, 2) ^= aesCtx->RoundKey[round * Nb * 4 + 3 * Nb + 2];\n\tstateVal(3, 3) ^= aesCtx->RoundKey[round * Nb * 4 + 3 * Nb + 3];\n}\n\n// The SubBytes Function Substitutes the values in the\n// state matrix with values in an S-box.\nvoid SubBytes(aes128Ctx_t* aesCtx)\n{\n\tuint8 i, j;\n\tfor (i = 0; i < 4; ++i)\n\t{\n\t\tfor (j = 0; j < 4; ++j)\n\t\t{\n\t\t\tstateVal(j, i) = getSBoxValue(stateVal(j, i));\n\t\t}\n\t}\n}\n\n// The ShiftRows() function shifts the rows in the state to the left.\n// Each row is shifted with different offset.\n// Offset = Row number. So the first row is not shifted.\nvoid ShiftRows(aes128Ctx_t* aesCtx)\n{\n\tuint8 temp;\n\n\t// Rotate first row 1 columns to left  \n\ttemp = stateVal(0, 1);\n\tstateVal(0, 1) = stateVal(1, 1);\n\tstateVal(1, 1) = stateVal(2, 1);\n\tstateVal(2, 1) = stateVal(3, 1);\n\tstateVal(3, 1) = temp;\n\n\t// Rotate second row 2 columns to left  \n\ttemp = stateVal(0, 2);\n\tstateVal(0, 2) = stateVal(2, 2);\n\tstateVal(2, 2) = temp;\n\n\ttemp = stateVal(1, 2);\n\tstateVal(1, 2) = stateVal(3, 2);\n\tstateVal(3, 2) = temp;\n\n\t// Rotate third row 3 columns to left\n\ttemp = stateVal(0, 3);\n\tstateVal(0, 3) = stateVal(3, 3);\n\tstateVal(3, 3) = stateVal(2, 3);\n\tstateVal(2, 3) = stateVal(1, 3);\n\tstateVal(1, 3) = temp;\n}\n\nuint8 aes_xtime(uint8 x)\n{\n\treturn ((x << 1) ^ (((x >> 7) & 1) * 0x1b));\n}\n\n// MixColumns function mixes the columns of the state matrix\nvoid MixColumns(aes128Ctx_t* aesCtx)\n{\n\tuint8 i;\n\tuint8 Tmp, Tm, t;\n\tfor (i = 0; i < 4; ++i)\n\t{\n\t\tt = stateVal(i, 0);\n\t\tTmp = stateVal(i, 0) ^ stateVal(i, 1) ^ stateVal(i, 2) ^ stateVal(i, 3);\n\t\tTm = stateVal(i, 0) ^ stateVal(i, 1); Tm = aes_xtime(Tm);  stateVal(i, 0) ^= Tm ^ Tmp;\n\t\tTm = stateVal(i, 1) ^ stateVal(i, 2); Tm = aes_xtime(Tm);  stateVal(i, 1) ^= Tm ^ Tmp;\n\t\tTm = stateVal(i, 2) ^ stateVal(i, 3); Tm = aes_xtime(Tm);  stateVal(i, 2) ^= Tm ^ Tmp;\n\t\tTm = stateVal(i, 3) ^ t;             Tm = aes_xtime(Tm);  stateVal(i, 3) ^= Tm ^ Tmp;\n\t}\n}\n\n// Multiply is used to multiply numbers in the field GF(2^8)\n#define Multiply(x, y)                                \\\n      (  ((y & 1) * x) ^                              \\\n      ((y>>1 & 1) * aes_xtime(x)) ^                       \\\n      ((y>>2 & 1) * aes_xtime(aes_xtime(x))) ^                \\\n      ((y>>3 & 1) * aes_xtime(aes_xtime(aes_xtime(x)))) ^         \\\n      ((y>>4 & 1) * aes_xtime(aes_xtime(aes_xtime(aes_xtime(x))))))\n\nuint32 lookupTable_multiply[256];\n\n//// MixColumns function mixes the columns of the state matrix.\n//// The method used to multiply may be difficult to understand for the inexperienced.\n//// Please use the references to gain more information.\n//void InvMixColumns(aes128Ctx_t* aesCtx)\n//{\n//\tint i;\n//\tuint8 a, b, c, d;\n//\tfor (i = 0; i < 4; ++i)\n//\t{\n//\t\ta = stateVal(i, 0);\n//\t\tb = stateVal(i, 1);\n//\t\tc = stateVal(i, 2);\n//\t\td = stateVal(i, 3);\n//\n//\t\tuint32 _a = lookupTable_multiply[a];\n//\t\tuint32 _b = lookupTable_multiply[b];\n//\t\tuint32 _c = lookupTable_multiply[c];\n//\t\tuint32 _d = lookupTable_multiply[d];\n//\n//\n//\t\t//stateVal(i, 0) = entryA->vE ^ entryB->vB ^ entryC->vD ^ entryD->v9;\n//\t\t//stateVal(i, 1) = entryA->v9 ^ entryB->vE ^ entryC->vB ^ entryD->vD;\n//\t\t//stateVal(i, 2) = entryA->vD ^ entryB->v9 ^ entryC->vE ^ entryD->vB;\n//\t\t//stateVal(i, 3) = entryA->vB ^ entryB->vD ^ entryC->v9 ^ entryD->vE;\n//\n//\t\t//stateVal(i, 0) = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);\n//\t\t//stateVal(i, 1) = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);\n//\t\t//stateVal(i, 2) = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);\n//\t\t//stateVal(i, 3) = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);\n//\n//\t\t//stateVal(i, 0) = Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);\n//\t\t//stateVal(i, 1) = Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);\n//\t\t//stateVal(i, 2) = Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);\n//\t\t//stateVal(i, 3) = Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);\n//\n//\t\tstateValU32(i) = _a ^ _rotl(_b, 8) ^ _rotl(_c, 16) ^ _rotl(_d, 24);\n//\n//\t}\n//}\n\n// MixColumns function mixes the columns of the state matrix.\n// The method used to multiply may be difficult to understand for the inexperienced.\n// Please use the references to gain more information.\nvoid InvMixColumns(aes128Ctx_t* aesCtx)\n{\n\tuint8 a, b, c, d;\n\t// i0\n\ta = stateVal(0, 0);\n\tb = stateVal(0, 1);\n\tc = stateVal(0, 2);\n\td = stateVal(0, 3);\n\tstateValU32(0) = lookupTable_multiply[a] ^ std::rotl<uint32>(lookupTable_multiply[b], 8) ^ std::rotl<uint32>(lookupTable_multiply[c], 16) ^ std::rotl<uint32>(lookupTable_multiply[d], 24);\n\t// i1\n\ta = stateVal(1, 0);\n\tb = stateVal(1, 1);\n\tc = stateVal(1, 2);\n\td = stateVal(1, 3);\n\tstateValU32(1) = lookupTable_multiply[a] ^ std::rotl<uint32>(lookupTable_multiply[b], 8) ^ std::rotl<uint32>(lookupTable_multiply[c], 16) ^ std::rotl<uint32>(lookupTable_multiply[d], 24);\n\t// i2\n\ta = stateVal(2, 0);\n\tb = stateVal(2, 1);\n\tc = stateVal(2, 2);\n\td = stateVal(2, 3);\n\tstateValU32(2) = lookupTable_multiply[a] ^ std::rotl<uint32>(lookupTable_multiply[b], 8) ^ std::rotl<uint32>(lookupTable_multiply[c], 16) ^ std::rotl<uint32>(lookupTable_multiply[d], 24);\n\t// i3\n\ta = stateVal(3, 0);\n\tb = stateVal(3, 1);\n\tc = stateVal(3, 2);\n\td = stateVal(3, 3);\n\tstateValU32(3) = lookupTable_multiply[a] ^ std::rotl<uint32>(lookupTable_multiply[b], 8) ^ std::rotl<uint32>(lookupTable_multiply[c], 16) ^ std::rotl<uint32>(lookupTable_multiply[d], 24);\n}\n\n// The SubBytes Function Substitutes the values in the\n// state matrix with values in an S-box.\nvoid InvSubBytes(aes128Ctx_t* aesCtx)\n{\n\tstateVal(0, 0) = rsbox[stateVal(0, 0)];\n\tstateVal(1, 0) = rsbox[stateVal(1, 0)];\n\tstateVal(2, 0) = rsbox[stateVal(2, 0)];\n\tstateVal(3, 0) = rsbox[stateVal(3, 0)];\n\n\tstateVal(0, 1) = rsbox[stateVal(0, 1)];\n\tstateVal(1, 1) = rsbox[stateVal(1, 1)];\n\tstateVal(2, 1) = rsbox[stateVal(2, 1)];\n\tstateVal(3, 1) = rsbox[stateVal(3, 1)];\n\n\tstateVal(0, 2) = rsbox[stateVal(0, 2)];\n\tstateVal(1, 2) = rsbox[stateVal(1, 2)];\n\tstateVal(2, 2) = rsbox[stateVal(2, 2)];\n\tstateVal(3, 2) = rsbox[stateVal(3, 2)];\n\n\tstateVal(0, 3) = rsbox[stateVal(0, 3)];\n\tstateVal(1, 3) = rsbox[stateVal(1, 3)];\n\tstateVal(2, 3) = rsbox[stateVal(2, 3)];\n\tstateVal(3, 3) = rsbox[stateVal(3, 3)];\n}\n\nvoid InvShiftRows(aes128Ctx_t* aesCtx)\n{\n\tuint8 temp;\n\n\t// Rotate first row 1 columns to right  \n\ttemp = stateVal(3, 1);\n\tstateVal(3, 1) = stateVal(2, 1);\n\tstateVal(2, 1) = stateVal(1, 1);\n\tstateVal(1, 1) = stateVal(0, 1);\n\tstateVal(0, 1) = temp;\n\n\t// Rotate second row 2 columns to right \n\ttemp = stateVal(0, 2);\n\tstateVal(0, 2) = stateVal(2, 2);\n\tstateVal(2, 2) = temp;\n\n\ttemp = stateVal(1, 2);\n\tstateVal(1, 2) = stateVal(3, 2);\n\tstateVal(3, 2) = temp;\n\n\t// Rotate third row 3 columns to right\n\ttemp = stateVal(0, 3);\n\tstateVal(0, 3) = stateVal(1, 3);\n\tstateVal(1, 3) = stateVal(2, 3);\n\tstateVal(2, 3) = stateVal(3, 3);\n\tstateVal(3, 3) = temp;\n}\n\n\n// Cipher is the main function that encrypts the PlainText.\nvoid Cipher(aes128Ctx_t* aesCtx)\n{\n\tuint8 round = 0;\n\n\t// Add the First round key to the state before starting the rounds.\n\tAddRoundKey(aesCtx, 0);\n\n\t// There will be Nr rounds.\n\t// The first Nr-1 rounds are identical.\n\t// These Nr-1 rounds are executed in the loop below.\n\tfor (round = 1; round < Nr; ++round)\n\t{\n\t\tSubBytes(aesCtx);\n\t\tShiftRows(aesCtx);\n\t\tMixColumns(aesCtx);\n\t\tAddRoundKey(aesCtx, round);\n\t}\n\n\t// The last round is given below.\n\t// The MixColumns function is not here in the last round.\n\tSubBytes(aesCtx);\n\tShiftRows(aesCtx);\n\tAddRoundKey(aesCtx, Nr);\n}\n\nvoid InvCipher(aes128Ctx_t* aesCtx)\n{\n\tuint8 round = 0;\n\n\t// Add the First round key to the state before starting the rounds.\n\tAddRoundKey(aesCtx, Nr);\n\n\t// There will be Nr rounds.\n\t// The first Nr-1 rounds are identical.\n\t// These Nr-1 rounds are executed in the loop below.\n\tfor (round = Nr - 1; round > 0; round--)\n\t{\n\t\tInvShiftRows(aesCtx);\n\t\tInvSubBytes(aesCtx);\n\t\tAddRoundKey(aesCtx, round);\n\t\tInvMixColumns(aesCtx);\n\t}\n\n\t// The last round is given below.\n\t// The MixColumns function is not here in the last round.\n\tInvShiftRows(aesCtx);\n\tInvSubBytes(aesCtx);\n\tAddRoundKey(aesCtx, 0);\n}\n\nstatic void BlockCopy(uint8* output, uint8* input)\n{\n\tuint8 i;\n\tfor (i = 0; i < KEYLEN; ++i)\n\t{\n\t\toutput[i] = input[i];\n\t}\n}\n\n\n\n/*****************************************************************************/\n/* Public functions:                                                         */\n/*****************************************************************************/\n\nvoid __soft__AES128_ECB_encrypt(uint8* input, const uint8* key, uint8* output)\n{\n\taes128Ctx_t aesCtx;\n\t// Copy input to output, and work in-memory on output\n\tBlockCopy(output, input);\n\taesCtx.state = (state_t*)output;\n\n\tKeyExpansion(&aesCtx, key);\n\n\t// The next function call encrypts the PlainText with the Key using AES algorithm.\n\tCipher(&aesCtx);\n}\n\nvoid AES128_ECB_decrypt(uint8* input, const uint8* key, uint8 *output)\n{\n\taes128Ctx_t aesCtx;\n\t// Copy input to output, and work in-memory on output\n\tBlockCopy(output, input);\n\taesCtx.state = (state_t*)output;\n\t\n\t// The KeyExpansion routine must be called before encryption.\n\tKeyExpansion(&aesCtx, key);\n\n\tInvCipher(&aesCtx);\n}\n\nvoid XorWithIv(uint8* buf, const uint8* iv)\n{\n\tuint8 i;\n\tfor (i = 0; i < KEYLEN; ++i)\n\t{\n\t\tbuf[i] ^= iv[i];\n\t}\n}\n\nvoid AES128_CBC_encrypt(uint8* output, uint8* input, uint32 length, const uint8* key, const uint8* iv)\n{\n\taes128Ctx_t aesCtx;\n\tintptr_t i;\n\tuint8 remainders = length % KEYLEN; /* Remaining bytes in the last non-full block */\n\n\tBlockCopy(output, input);\n\taesCtx.state = (state_t*)output;\n\n\tKeyExpansion(&aesCtx, key);\n\n\tconst uint8* currentIv = iv;\n\n\tfor (i = 0; i < length; i += KEYLEN)\n\t{\n\t\tXorWithIv(input, currentIv);\n\t\tBlockCopy(output, input);\n\t\taesCtx.state = (state_t*)output;\n\t\tCipher(&aesCtx);\n\t\tcurrentIv = output;\n\t\tinput += KEYLEN;\n\t\toutput += KEYLEN;\n\t}\n\tcemu_assert_debug(remainders == 0);\n}\n\nvoid __soft__AES128_CBC_decrypt(uint8* output, uint8* input, uint32 length, const uint8* key, const uint8* iv)\n{\n\taes128Ctx_t aesCtx;\n\tintptr_t i;\n\tuint8 remainders = length % KEYLEN;\n\n\tKeyExpansion(&aesCtx, key);\n\n\tuint8 currentIv[KEYLEN];\n\tuint8 nextIv[KEYLEN];\n\tif (iv)\n\t\tBlockCopy(currentIv, (uint8*)iv);\n\telse\n\t\tmemset(currentIv, 0, sizeof(currentIv));\n\n\tfor (i = 0; i < length; i += KEYLEN)\n\t{\n\t\taesCtx.state = (state_t*)output;\n\t\tBlockCopy(output, input);\n\t\tBlockCopy(nextIv, input);\n\t\tInvCipher(&aesCtx);\n\t\tXorWithIv(output, currentIv);\n\t\tBlockCopy(currentIv, nextIv);\n\t\toutput += KEYLEN;\n\t\tinput += KEYLEN;\n\t}\n\n\tcemu_assert_debug(remainders == 0);\n}\n\nvoid AES128_CBC_decrypt_buffer_depr(uint8* output, uint8* input, uint32 length, const uint8* key, const uint8* iv)\n{\n\taes128Ctx_t aesCtx;\n\tintptr_t i;\n\tuint8 remainders = length % KEYLEN; /* Remaining bytes in the last non-full block */\n\n\tBlockCopy(output, input);\n\n\tKeyExpansion(&aesCtx, key);\n\n\tconst uint8* currentIv = iv;\n\n\tfor (i = 0; i < length; i += KEYLEN)\n\t{\n\t\tBlockCopy(output, input);\n\t\taesCtx.state = (state_t*)output;\n\t\tInvCipher(&aesCtx);\n\t\tXorWithIv(output, currentIv);\n\t\tcurrentIv = input;\n\t\tinput += KEYLEN;\n\t\toutput += KEYLEN;\n\t}\n\tcemu_assert_debug(remainders == 0);\n}\n\nvoid AES128_CBC_decrypt_updateIV(uint8* output, uint8* input, uint32 length, const uint8* key, uint8* iv)\n{\n\tlength &= ~0xF;\n\tuint8 newIv[16];\n\tif (length == 0)\n\t\treturn;\n\tcemu_assert_debug((length&0xF) == 0);\n\tmemcpy(newIv, input + (length - 16), KEYLEN);\n\tAES128_CBC_decrypt(output, input, length, key, iv);\n\tmemcpy(iv, newIv, KEYLEN);\n}\n\n#if defined(ARCH_X86_64)\nATTRIBUTE_AESNI inline __m128i AESNI128_ASSIST(\n\t__m128i temp1,\n\t__m128i temp2)\n{\n\t__m128i temp3;\n\ttemp2 = _mm_shuffle_epi32(temp2, 0xff);\n\ttemp3 = _mm_slli_si128(temp1, 0x4);\n\ttemp1 = _mm_xor_si128(temp1, temp3);\n\ttemp3 =\n\t\t_mm_slli_si128(temp3, 0x4);\n\ttemp1 =\n\t\t_mm_xor_si128(temp1, temp3);\n\ttemp3 =\n\t\t_mm_slli_si128(temp3, 0x4);\n\ttemp1 =\n\t\t_mm_xor_si128(temp1, temp3);\n\ttemp1 = _mm_xor_si128(temp1, temp2);\n\treturn temp1;\n}\n\nATTRIBUTE_AESNI void AESNI128_KeyExpansionEncrypt(const unsigned char *userkey, unsigned char *key)\n{\n\t__m128i temp1, temp2;\n\t__m128i *Key_Schedule = (__m128i*)key;\n\ttemp1 = _mm_loadu_si128((__m128i*)userkey);\n\tKey_Schedule[0] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x1);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[1] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x2);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[2] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x4);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[3] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x8);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[4] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x10);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[5] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x20);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[6] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x40);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[7] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x80);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[8] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x1b);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[9] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x36);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[10] = temp1;\n}\n\nATTRIBUTE_AESNI void AESNI128_KeyExpansionDecrypt(const unsigned char *userkey, unsigned char *key)\n{\n\t__m128i temp1, temp2;\n\t__m128i *Key_Schedule = (__m128i*)key;\n\ttemp1 = _mm_loadu_si128((__m128i*)userkey);\n\tKey_Schedule[0] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x1);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[1] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x2);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[2] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x4);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[3] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x8);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[4] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x10);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[5] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x20);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[6] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x40);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[7] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x80);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[8] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x1b);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[9] = temp1;\n\ttemp2 = _mm_aeskeygenassist_si128(temp1, 0x36);\n\ttemp1 = AESNI128_ASSIST(temp1, temp2);\n\tKey_Schedule[10] = temp1;\n\t// inverse\n\tfor (sint32 i = 1; i < 10; i++)\n\t{\n\t\tKey_Schedule[i] = _mm_aesimc_si128(Key_Schedule[i]);\n\t}\n}\n\nATTRIBUTE_AESNI void AESNI128_CBC_encrypt(const unsigned char *in,\n\tunsigned char *out,\n\tunsigned char ivec[16],\n\tunsigned long length,\n\tunsigned char *key,\n\tint number_of_rounds)\n{\n\t__m128i feedback, data;\n\tint j;\n\tif (length % 16)\n\t\tlength = length / 16 + 1;\n\telse length /= 16;\n\tfeedback = _mm_loadu_si128((__m128i*)ivec);\n\tfor (unsigned long i = 0; i < length; i++) \n\t{\n\t\tdata =\n\t\t\t_mm_loadu_si128(&((__m128i*)in)[i]);\n\t\tfeedback = _mm_xor_si128(data, feedback);\n\t\tfeedback = _mm_xor_si128(feedback, ((__m128i*)key)[0]);\n\t\tfor (j = 1; j < number_of_rounds; j++)\n\t\t\tfeedback =\n\t\t\t_mm_aesenc_si128(feedback, ((__m128i*)key)[j]);\n\t\tfeedback =\n\t\t\t_mm_aesenclast_si128(feedback, ((__m128i*)key)[j]);\n\t\t_mm_storeu_si128(&((__m128i*)out)[i], feedback);\n\t}\n}\n\nATTRIBUTE_AESNI void AESNI128_CBC_decryptWithExpandedKey(const unsigned char *in,\n\tunsigned char *out,\n\tconst unsigned char ivec[16],\n\tunsigned long length,\n\tunsigned char *key)\n{\n\t__m128i data, feedback, lastin;\n\tint j;\n\tif (length % 16)\n\t\tlength = length / 16 + 1;\n\telse length /= 16;\n\tfeedback = _mm_loadu_si128((__m128i*)ivec);\n\tfor (unsigned long i = 0; i < length; i++)\n\t{\n\t\tlastin = _mm_loadu_si128(&((__m128i*)in)[i]);\n\t\tdata = _mm_xor_si128(lastin, ((__m128i*)key)[10]);\n\t\tfor (j = 9; j > 0; j--)\n\t\t{\n\t\t\tdata = _mm_aesdec_si128(data, ((__m128i*)key)[j]);\n\t\t}\n\t\tdata = _mm_aesdeclast_si128(data, ((__m128i*)key)[0]);\n\t\tdata = _mm_xor_si128(data, feedback);\n\t\t_mm_storeu_si128(&((__m128i*)out)[i], data);\n\t\tfeedback = lastin;\n\t}\n}\n\nATTRIBUTE_AESNI void __aesni__AES128_CBC_decrypt(uint8* output, uint8* input, uint32 length, const uint8* key, const uint8* iv)\n{\n\talignas(16) uint8 expandedKey[11 * 16];\n\tAESNI128_KeyExpansionDecrypt(key, expandedKey);\n\tif (iv)\n\t{\n\t\tAESNI128_CBC_decryptWithExpandedKey(input, output, iv, length, expandedKey);\n\t}\n\telse\n\t{\n\t\tuint8 zeroIv[16] = { 0 };\n\t\tAESNI128_CBC_decryptWithExpandedKey(input, output, zeroIv, length, expandedKey);\n\t}\n}\n\nATTRIBUTE_AESNI void __aesni__AES128_ECB_encrypt(uint8* input, const uint8* key, uint8* output)\n{\n\talignas(16) uint8 expandedKey[11 * 16];\n\tAESNI128_KeyExpansionEncrypt(key, expandedKey);\n\t// encrypt single ECB block\n\t__m128i feedback;\n\tfeedback = _mm_loadu_si128(&((__m128i*)input)[0]);\n\tfeedback = _mm_xor_si128(feedback, ((__m128i*)expandedKey)[0]);\n\tfeedback = _mm_aesenc_si128(feedback, ((__m128i*)expandedKey)[1]);\n\tfeedback = _mm_aesenc_si128(feedback, ((__m128i*)expandedKey)[2]);\n\tfeedback = _mm_aesenc_si128(feedback, ((__m128i*)expandedKey)[3]);\n\tfeedback = _mm_aesenc_si128(feedback, ((__m128i*)expandedKey)[4]);\n\tfeedback = _mm_aesenc_si128(feedback, ((__m128i*)expandedKey)[5]);\n\tfeedback = _mm_aesenc_si128(feedback, ((__m128i*)expandedKey)[6]);\n\tfeedback = _mm_aesenc_si128(feedback, ((__m128i*)expandedKey)[7]);\n\tfeedback = _mm_aesenc_si128(feedback, ((__m128i*)expandedKey)[8]);\n\tfeedback = _mm_aesenc_si128(feedback, ((__m128i*)expandedKey)[9]);\n\tfeedback = _mm_aesenclast_si128(feedback, ((__m128i*)expandedKey)[10]);\n\t_mm_storeu_si128(&((__m128i*)output)[0], feedback);\n}\n#endif\n\nvoid(*AES128_ECB_encrypt)(uint8* input, const uint8* key, uint8* output);\nvoid (*AES128_CBC_decrypt)(uint8* output, uint8* input, uint32 length, const uint8* key, const uint8* iv) = nullptr;\n\n// AES128-CTR encrypt/decrypt\nvoid AES128CTR_transform(uint8* data, sint32 length, uint8* key, uint8* nonceIv)\n{\n\tfor (sint32 i = 0; i < length; i += 16)\n\t{\n\t\tuint8* d = data + i;\n\t\tuint8 tempArray[16];\n\t\tAES128_ECB_encrypt(nonceIv, key, tempArray);\n\t\tfor (sint32 f = 0; f < 16; f++)\n\t\t{\n\t\t\td[f] ^= tempArray[f];\n\t\t}\n\t\t// increase nonce\n\t\t*(uint32*)(nonceIv + 0xC) = _swapEndianU32(_swapEndianU32(*(uint32*)(nonceIv + 0xC)) + 1);\n\t\tif (*(uint32*)(nonceIv + 0xC) == 0)\n\t\t{\n\t\t\t*(uint32*)(nonceIv + 0x8) = _swapEndianU32(_swapEndianU32(*(uint32*)(nonceIv + 0x8)) + 1);\n\t\t\tif (*(uint32*)(nonceIv + 0x8) == 0)\n\t\t\t{\n\t\t\t\t*(uint32*)(nonceIv + 0x4) = _swapEndianU32(_swapEndianU32(*(uint32*)(nonceIv + 0x4)) + 1);\n\t\t\t\tif (*(uint32*)(nonceIv + 0x4) == 0)\n\t\t\t\t{\n\t\t\t\t\t*(uint32*)(nonceIv + 0) = _swapEndianU32(_swapEndianU32(*(uint32*)(nonceIv + 0)) + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid AES128_init()\n{\n\tfor (uint32 i = 0; i <= 0xFF; i++)\n\t{\n\t\tuint32 vE = Multiply((uint8)(i & 0xFF), 0x0E) & 0xFF;\n\t\tuint32 v9 = Multiply((uint8)(i & 0xFF), 0x09) & 0xFF;\n\t\tuint32 vD = Multiply((uint8)(i & 0xFF), 0x0D) & 0xFF;\n\t\tuint32 vB = Multiply((uint8)(i & 0xFF), 0x0B) & 0xFF;\n\t\tlookupTable_multiply[i] = (vE << 0) | (v9 << 8) | (vD << 16) | (vB << 24);\n\t}\n\t// check if AES-NI is available\n\t#if defined(ARCH_X86_64)\n\tif (g_CPUFeatures.x86.aesni)\n\t{\n\t\t// AES-NI implementation\n\t\tAES128_CBC_decrypt = __aesni__AES128_CBC_decrypt;\n\t\tAES128_ECB_encrypt = __aesni__AES128_ECB_encrypt;\n\t}\n\telse\n\t{\n\t\t// basic software implementation\n\t\tAES128_CBC_decrypt = __soft__AES128_CBC_decrypt;\n\t\tAES128_ECB_encrypt = __soft__AES128_ECB_encrypt;\n\t}\n    #else\n\tAES128_CBC_decrypt = __soft__AES128_CBC_decrypt;\n\tAES128_ECB_encrypt = __soft__AES128_ECB_encrypt;\n    #endif\n}\n"
  },
  {
    "path": "src/util/crypto/aes128.h",
    "content": "#ifndef _AES_H_\n#define _AES_H_\n\nvoid AES128_init();\n\nextern void(*AES128_ECB_encrypt)(uint8* input, const uint8* key, uint8* output);\n\nvoid AES128_ECB_decrypt(uint8* input, const uint8* key, uint8 *output);\n\nvoid AES128_CBC_encrypt(uint8* output, uint8* input, uint32 length, const uint8* key, const uint8* iv);\n\nextern void(*AES128_CBC_decrypt)(uint8* output, uint8* input, uint32 length, const uint8* key, const uint8* iv);\n\nvoid AES128_CBC_decrypt_updateIV(uint8* output, uint8* input, uint32 length, const uint8* key, uint8* iv);\n\nvoid AES128CTR_transform(uint8* data, sint32 length, uint8* key, uint8* nonceIv);\n\n#endif //_AES_H_\n"
  },
  {
    "path": "src/util/crypto/crc32.cpp",
    "content": "#include \"crc32.h\"\n\nconstexpr uint32 Crc32Lookup[8][256] =\n{\n\t{\n\t\t0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,\n\t\t0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,\n\t\t0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,\n\t\t0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,\n\t\t0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,\n\t\t0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,\n\t\t0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,\n\t\t0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,\n\t\t0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,\n\t\t0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,\n\t\t0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,\n\t\t0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,\n\t\t0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,\n\t\t0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,\n\t\t0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,\n\t\t0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,\n\t\t0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,\n\t\t0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,\n\t\t0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,\n\t\t0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,\n\t\t0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,\n\t\t0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,\n\t\t0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,\n\t\t0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,\n\t\t0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,\n\t\t0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,\n\t\t0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,\n\t\t0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,\n\t\t0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,\n\t\t0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,\n\t\t0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,\n\t\t0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,\n\t  }\n\t  ,\n\t  {\n\t\t0x00000000,0x191B3141,0x32366282,0x2B2D53C3,0x646CC504,0x7D77F445,0x565AA786,0x4F4196C7,\n\t\t0xC8D98A08,0xD1C2BB49,0xFAEFE88A,0xE3F4D9CB,0xACB54F0C,0xB5AE7E4D,0x9E832D8E,0x87981CCF,\n\t\t0x4AC21251,0x53D92310,0x78F470D3,0x61EF4192,0x2EAED755,0x37B5E614,0x1C98B5D7,0x05838496,\n\t\t0x821B9859,0x9B00A918,0xB02DFADB,0xA936CB9A,0xE6775D5D,0xFF6C6C1C,0xD4413FDF,0xCD5A0E9E,\n\t\t0x958424A2,0x8C9F15E3,0xA7B24620,0xBEA97761,0xF1E8E1A6,0xE8F3D0E7,0xC3DE8324,0xDAC5B265,\n\t\t0x5D5DAEAA,0x44469FEB,0x6F6BCC28,0x7670FD69,0x39316BAE,0x202A5AEF,0x0B07092C,0x121C386D,\n\t\t0xDF4636F3,0xC65D07B2,0xED705471,0xF46B6530,0xBB2AF3F7,0xA231C2B6,0x891C9175,0x9007A034,\n\t\t0x179FBCFB,0x0E848DBA,0x25A9DE79,0x3CB2EF38,0x73F379FF,0x6AE848BE,0x41C51B7D,0x58DE2A3C,\n\t\t0xF0794F05,0xE9627E44,0xC24F2D87,0xDB541CC6,0x94158A01,0x8D0EBB40,0xA623E883,0xBF38D9C2,\n\t\t0x38A0C50D,0x21BBF44C,0x0A96A78F,0x138D96CE,0x5CCC0009,0x45D73148,0x6EFA628B,0x77E153CA,\n\t\t0xBABB5D54,0xA3A06C15,0x888D3FD6,0x91960E97,0xDED79850,0xC7CCA911,0xECE1FAD2,0xF5FACB93,\n\t\t0x7262D75C,0x6B79E61D,0x4054B5DE,0x594F849F,0x160E1258,0x0F152319,0x243870DA,0x3D23419B,\n\t\t0x65FD6BA7,0x7CE65AE6,0x57CB0925,0x4ED03864,0x0191AEA3,0x188A9FE2,0x33A7CC21,0x2ABCFD60,\n\t\t0xAD24E1AF,0xB43FD0EE,0x9F12832D,0x8609B26C,0xC94824AB,0xD05315EA,0xFB7E4629,0xE2657768,\n\t\t0x2F3F79F6,0x362448B7,0x1D091B74,0x04122A35,0x4B53BCF2,0x52488DB3,0x7965DE70,0x607EEF31,\n\t\t0xE7E6F3FE,0xFEFDC2BF,0xD5D0917C,0xCCCBA03D,0x838A36FA,0x9A9107BB,0xB1BC5478,0xA8A76539,\n\t\t0x3B83984B,0x2298A90A,0x09B5FAC9,0x10AECB88,0x5FEF5D4F,0x46F46C0E,0x6DD93FCD,0x74C20E8C,\n\t\t0xF35A1243,0xEA412302,0xC16C70C1,0xD8774180,0x9736D747,0x8E2DE606,0xA500B5C5,0xBC1B8484,\n\t\t0x71418A1A,0x685ABB5B,0x4377E898,0x5A6CD9D9,0x152D4F1E,0x0C367E5F,0x271B2D9C,0x3E001CDD,\n\t\t0xB9980012,0xA0833153,0x8BAE6290,0x92B553D1,0xDDF4C516,0xC4EFF457,0xEFC2A794,0xF6D996D5,\n\t\t0xAE07BCE9,0xB71C8DA8,0x9C31DE6B,0x852AEF2A,0xCA6B79ED,0xD37048AC,0xF85D1B6F,0xE1462A2E,\n\t\t0x66DE36E1,0x7FC507A0,0x54E85463,0x4DF36522,0x02B2F3E5,0x1BA9C2A4,0x30849167,0x299FA026,\n\t\t0xE4C5AEB8,0xFDDE9FF9,0xD6F3CC3A,0xCFE8FD7B,0x80A96BBC,0x99B25AFD,0xB29F093E,0xAB84387F,\n\t\t0x2C1C24B0,0x350715F1,0x1E2A4632,0x07317773,0x4870E1B4,0x516BD0F5,0x7A468336,0x635DB277,\n\t\t0xCBFAD74E,0xD2E1E60F,0xF9CCB5CC,0xE0D7848D,0xAF96124A,0xB68D230B,0x9DA070C8,0x84BB4189,\n\t\t0x03235D46,0x1A386C07,0x31153FC4,0x280E0E85,0x674F9842,0x7E54A903,0x5579FAC0,0x4C62CB81,\n\t\t0x8138C51F,0x9823F45E,0xB30EA79D,0xAA1596DC,0xE554001B,0xFC4F315A,0xD7626299,0xCE7953D8,\n\t\t0x49E14F17,0x50FA7E56,0x7BD72D95,0x62CC1CD4,0x2D8D8A13,0x3496BB52,0x1FBBE891,0x06A0D9D0,\n\t\t0x5E7EF3EC,0x4765C2AD,0x6C48916E,0x7553A02F,0x3A1236E8,0x230907A9,0x0824546A,0x113F652B,\n\t\t0x96A779E4,0x8FBC48A5,0xA4911B66,0xBD8A2A27,0xF2CBBCE0,0xEBD08DA1,0xC0FDDE62,0xD9E6EF23,\n\t\t0x14BCE1BD,0x0DA7D0FC,0x268A833F,0x3F91B27E,0x70D024B9,0x69CB15F8,0x42E6463B,0x5BFD777A,\n\t\t0xDC656BB5,0xC57E5AF4,0xEE530937,0xF7483876,0xB809AEB1,0xA1129FF0,0x8A3FCC33,0x9324FD72,\n\t  },\n\t  {\n\t\t0x00000000,0x01C26A37,0x0384D46E,0x0246BE59,0x0709A8DC,0x06CBC2EB,0x048D7CB2,0x054F1685,\n\t\t0x0E1351B8,0x0FD13B8F,0x0D9785D6,0x0C55EFE1,0x091AF964,0x08D89353,0x0A9E2D0A,0x0B5C473D,\n\t\t0x1C26A370,0x1DE4C947,0x1FA2771E,0x1E601D29,0x1B2F0BAC,0x1AED619B,0x18ABDFC2,0x1969B5F5,\n\t\t0x1235F2C8,0x13F798FF,0x11B126A6,0x10734C91,0x153C5A14,0x14FE3023,0x16B88E7A,0x177AE44D,\n\t\t0x384D46E0,0x398F2CD7,0x3BC9928E,0x3A0BF8B9,0x3F44EE3C,0x3E86840B,0x3CC03A52,0x3D025065,\n\t\t0x365E1758,0x379C7D6F,0x35DAC336,0x3418A901,0x3157BF84,0x3095D5B3,0x32D36BEA,0x331101DD,\n\t\t0x246BE590,0x25A98FA7,0x27EF31FE,0x262D5BC9,0x23624D4C,0x22A0277B,0x20E69922,0x2124F315,\n\t\t0x2A78B428,0x2BBADE1F,0x29FC6046,0x283E0A71,0x2D711CF4,0x2CB376C3,0x2EF5C89A,0x2F37A2AD,\n\t\t0x709A8DC0,0x7158E7F7,0x731E59AE,0x72DC3399,0x7793251C,0x76514F2B,0x7417F172,0x75D59B45,\n\t\t0x7E89DC78,0x7F4BB64F,0x7D0D0816,0x7CCF6221,0x798074A4,0x78421E93,0x7A04A0CA,0x7BC6CAFD,\n\t\t0x6CBC2EB0,0x6D7E4487,0x6F38FADE,0x6EFA90E9,0x6BB5866C,0x6A77EC5B,0x68315202,0x69F33835,\n\t\t0x62AF7F08,0x636D153F,0x612BAB66,0x60E9C151,0x65A6D7D4,0x6464BDE3,0x662203BA,0x67E0698D,\n\t\t0x48D7CB20,0x4915A117,0x4B531F4E,0x4A917579,0x4FDE63FC,0x4E1C09CB,0x4C5AB792,0x4D98DDA5,\n\t\t0x46C49A98,0x4706F0AF,0x45404EF6,0x448224C1,0x41CD3244,0x400F5873,0x4249E62A,0x438B8C1D,\n\t\t0x54F16850,0x55330267,0x5775BC3E,0x56B7D609,0x53F8C08C,0x523AAABB,0x507C14E2,0x51BE7ED5,\n\t\t0x5AE239E8,0x5B2053DF,0x5966ED86,0x58A487B1,0x5DEB9134,0x5C29FB03,0x5E6F455A,0x5FAD2F6D,\n\t\t0xE1351B80,0xE0F771B7,0xE2B1CFEE,0xE373A5D9,0xE63CB35C,0xE7FED96B,0xE5B86732,0xE47A0D05,\n\t\t0xEF264A38,0xEEE4200F,0xECA29E56,0xED60F461,0xE82FE2E4,0xE9ED88D3,0xEBAB368A,0xEA695CBD,\n\t\t0xFD13B8F0,0xFCD1D2C7,0xFE976C9E,0xFF5506A9,0xFA1A102C,0xFBD87A1B,0xF99EC442,0xF85CAE75,\n\t\t0xF300E948,0xF2C2837F,0xF0843D26,0xF1465711,0xF4094194,0xF5CB2BA3,0xF78D95FA,0xF64FFFCD,\n\t\t0xD9785D60,0xD8BA3757,0xDAFC890E,0xDB3EE339,0xDE71F5BC,0xDFB39F8B,0xDDF521D2,0xDC374BE5,\n\t\t0xD76B0CD8,0xD6A966EF,0xD4EFD8B6,0xD52DB281,0xD062A404,0xD1A0CE33,0xD3E6706A,0xD2241A5D,\n\t\t0xC55EFE10,0xC49C9427,0xC6DA2A7E,0xC7184049,0xC25756CC,0xC3953CFB,0xC1D382A2,0xC011E895,\n\t\t0xCB4DAFA8,0xCA8FC59F,0xC8C97BC6,0xC90B11F1,0xCC440774,0xCD866D43,0xCFC0D31A,0xCE02B92D,\n\t\t0x91AF9640,0x906DFC77,0x922B422E,0x93E92819,0x96A63E9C,0x976454AB,0x9522EAF2,0x94E080C5,\n\t\t0x9FBCC7F8,0x9E7EADCF,0x9C381396,0x9DFA79A1,0x98B56F24,0x99770513,0x9B31BB4A,0x9AF3D17D,\n\t\t0x8D893530,0x8C4B5F07,0x8E0DE15E,0x8FCF8B69,0x8A809DEC,0x8B42F7DB,0x89044982,0x88C623B5,\n\t\t0x839A6488,0x82580EBF,0x801EB0E6,0x81DCDAD1,0x8493CC54,0x8551A663,0x8717183A,0x86D5720D,\n\t\t0xA9E2D0A0,0xA820BA97,0xAA6604CE,0xABA46EF9,0xAEEB787C,0xAF29124B,0xAD6FAC12,0xACADC625,\n\t\t0xA7F18118,0xA633EB2F,0xA4755576,0xA5B73F41,0xA0F829C4,0xA13A43F3,0xA37CFDAA,0xA2BE979D,\n\t\t0xB5C473D0,0xB40619E7,0xB640A7BE,0xB782CD89,0xB2CDDB0C,0xB30FB13B,0xB1490F62,0xB08B6555,\n\t\t0xBBD72268,0xBA15485F,0xB853F606,0xB9919C31,0xBCDE8AB4,0xBD1CE083,0xBF5A5EDA,0xBE9834ED,\n\t  },\n\t  {\n\t\t0x00000000,0xB8BC6765,0xAA09C88B,0x12B5AFEE,0x8F629757,0x37DEF032,0x256B5FDC,0x9DD738B9,\n\t\t0xC5B428EF,0x7D084F8A,0x6FBDE064,0xD7018701,0x4AD6BFB8,0xF26AD8DD,0xE0DF7733,0x58631056,\n\t\t0x5019579F,0xE8A530FA,0xFA109F14,0x42ACF871,0xDF7BC0C8,0x67C7A7AD,0x75720843,0xCDCE6F26,\n\t\t0x95AD7F70,0x2D111815,0x3FA4B7FB,0x8718D09E,0x1ACFE827,0xA2738F42,0xB0C620AC,0x087A47C9,\n\t\t0xA032AF3E,0x188EC85B,0x0A3B67B5,0xB28700D0,0x2F503869,0x97EC5F0C,0x8559F0E2,0x3DE59787,\n\t\t0x658687D1,0xDD3AE0B4,0xCF8F4F5A,0x7733283F,0xEAE41086,0x525877E3,0x40EDD80D,0xF851BF68,\n\t\t0xF02BF8A1,0x48979FC4,0x5A22302A,0xE29E574F,0x7F496FF6,0xC7F50893,0xD540A77D,0x6DFCC018,\n\t\t0x359FD04E,0x8D23B72B,0x9F9618C5,0x272A7FA0,0xBAFD4719,0x0241207C,0x10F48F92,0xA848E8F7,\n\t\t0x9B14583D,0x23A83F58,0x311D90B6,0x89A1F7D3,0x1476CF6A,0xACCAA80F,0xBE7F07E1,0x06C36084,\n\t\t0x5EA070D2,0xE61C17B7,0xF4A9B859,0x4C15DF3C,0xD1C2E785,0x697E80E0,0x7BCB2F0E,0xC377486B,\n\t\t0xCB0D0FA2,0x73B168C7,0x6104C729,0xD9B8A04C,0x446F98F5,0xFCD3FF90,0xEE66507E,0x56DA371B,\n\t\t0x0EB9274D,0xB6054028,0xA4B0EFC6,0x1C0C88A3,0x81DBB01A,0x3967D77F,0x2BD27891,0x936E1FF4,\n\t\t0x3B26F703,0x839A9066,0x912F3F88,0x299358ED,0xB4446054,0x0CF80731,0x1E4DA8DF,0xA6F1CFBA,\n\t\t0xFE92DFEC,0x462EB889,0x549B1767,0xEC277002,0x71F048BB,0xC94C2FDE,0xDBF98030,0x6345E755,\n\t\t0x6B3FA09C,0xD383C7F9,0xC1366817,0x798A0F72,0xE45D37CB,0x5CE150AE,0x4E54FF40,0xF6E89825,\n\t\t0xAE8B8873,0x1637EF16,0x048240F8,0xBC3E279D,0x21E91F24,0x99557841,0x8BE0D7AF,0x335CB0CA,\n\t\t0xED59B63B,0x55E5D15E,0x47507EB0,0xFFEC19D5,0x623B216C,0xDA874609,0xC832E9E7,0x708E8E82,\n\t\t0x28ED9ED4,0x9051F9B1,0x82E4565F,0x3A58313A,0xA78F0983,0x1F336EE6,0x0D86C108,0xB53AA66D,\n\t\t0xBD40E1A4,0x05FC86C1,0x1749292F,0xAFF54E4A,0x322276F3,0x8A9E1196,0x982BBE78,0x2097D91D,\n\t\t0x78F4C94B,0xC048AE2E,0xD2FD01C0,0x6A4166A5,0xF7965E1C,0x4F2A3979,0x5D9F9697,0xE523F1F2,\n\t\t0x4D6B1905,0xF5D77E60,0xE762D18E,0x5FDEB6EB,0xC2098E52,0x7AB5E937,0x680046D9,0xD0BC21BC,\n\t\t0x88DF31EA,0x3063568F,0x22D6F961,0x9A6A9E04,0x07BDA6BD,0xBF01C1D8,0xADB46E36,0x15080953,\n\t\t0x1D724E9A,0xA5CE29FF,0xB77B8611,0x0FC7E174,0x9210D9CD,0x2AACBEA8,0x38191146,0x80A57623,\n\t\t0xD8C66675,0x607A0110,0x72CFAEFE,0xCA73C99B,0x57A4F122,0xEF189647,0xFDAD39A9,0x45115ECC,\n\t\t0x764DEE06,0xCEF18963,0xDC44268D,0x64F841E8,0xF92F7951,0x41931E34,0x5326B1DA,0xEB9AD6BF,\n\t\t0xB3F9C6E9,0x0B45A18C,0x19F00E62,0xA14C6907,0x3C9B51BE,0x842736DB,0x96929935,0x2E2EFE50,\n\t\t0x2654B999,0x9EE8DEFC,0x8C5D7112,0x34E11677,0xA9362ECE,0x118A49AB,0x033FE645,0xBB838120,\n\t\t0xE3E09176,0x5B5CF613,0x49E959FD,0xF1553E98,0x6C820621,0xD43E6144,0xC68BCEAA,0x7E37A9CF,\n\t\t0xD67F4138,0x6EC3265D,0x7C7689B3,0xC4CAEED6,0x591DD66F,0xE1A1B10A,0xF3141EE4,0x4BA87981,\n\t\t0x13CB69D7,0xAB770EB2,0xB9C2A15C,0x017EC639,0x9CA9FE80,0x241599E5,0x36A0360B,0x8E1C516E,\n\t\t0x866616A7,0x3EDA71C2,0x2C6FDE2C,0x94D3B949,0x090481F0,0xB1B8E695,0xA30D497B,0x1BB12E1E,\n\t\t0x43D23E48,0xFB6E592D,0xE9DBF6C3,0x516791A6,0xCCB0A91F,0x740CCE7A,0x66B96194,0xDE0506F1,\n\t  }\n\t  ,\n\t  {\n\t\t0x00000000,0x3D6029B0,0x7AC05360,0x47A07AD0,0xF580A6C0,0xC8E08F70,0x8F40F5A0,0xB220DC10,\n\t\t0x30704BC1,0x0D106271,0x4AB018A1,0x77D03111,0xC5F0ED01,0xF890C4B1,0xBF30BE61,0x825097D1,\n\t\t0x60E09782,0x5D80BE32,0x1A20C4E2,0x2740ED52,0x95603142,0xA80018F2,0xEFA06222,0xD2C04B92,\n\t\t0x5090DC43,0x6DF0F5F3,0x2A508F23,0x1730A693,0xA5107A83,0x98705333,0xDFD029E3,0xE2B00053,\n\t\t0xC1C12F04,0xFCA106B4,0xBB017C64,0x866155D4,0x344189C4,0x0921A074,0x4E81DAA4,0x73E1F314,\n\t\t0xF1B164C5,0xCCD14D75,0x8B7137A5,0xB6111E15,0x0431C205,0x3951EBB5,0x7EF19165,0x4391B8D5,\n\t\t0xA121B886,0x9C419136,0xDBE1EBE6,0xE681C256,0x54A11E46,0x69C137F6,0x2E614D26,0x13016496,\n\t\t0x9151F347,0xAC31DAF7,0xEB91A027,0xD6F18997,0x64D15587,0x59B17C37,0x1E1106E7,0x23712F57,\n\t\t0x58F35849,0x659371F9,0x22330B29,0x1F532299,0xAD73FE89,0x9013D739,0xD7B3ADE9,0xEAD38459,\n\t\t0x68831388,0x55E33A38,0x124340E8,0x2F236958,0x9D03B548,0xA0639CF8,0xE7C3E628,0xDAA3CF98,\n\t\t0x3813CFCB,0x0573E67B,0x42D39CAB,0x7FB3B51B,0xCD93690B,0xF0F340BB,0xB7533A6B,0x8A3313DB,\n\t\t0x0863840A,0x3503ADBA,0x72A3D76A,0x4FC3FEDA,0xFDE322CA,0xC0830B7A,0x872371AA,0xBA43581A,\n\t\t0x9932774D,0xA4525EFD,0xE3F2242D,0xDE920D9D,0x6CB2D18D,0x51D2F83D,0x167282ED,0x2B12AB5D,\n\t\t0xA9423C8C,0x9422153C,0xD3826FEC,0xEEE2465C,0x5CC29A4C,0x61A2B3FC,0x2602C92C,0x1B62E09C,\n\t\t0xF9D2E0CF,0xC4B2C97F,0x8312B3AF,0xBE729A1F,0x0C52460F,0x31326FBF,0x7692156F,0x4BF23CDF,\n\t\t0xC9A2AB0E,0xF4C282BE,0xB362F86E,0x8E02D1DE,0x3C220DCE,0x0142247E,0x46E25EAE,0x7B82771E,\n\t\t0xB1E6B092,0x8C869922,0xCB26E3F2,0xF646CA42,0x44661652,0x79063FE2,0x3EA64532,0x03C66C82,\n\t\t0x8196FB53,0xBCF6D2E3,0xFB56A833,0xC6368183,0x74165D93,0x49767423,0x0ED60EF3,0x33B62743,\n\t\t0xD1062710,0xEC660EA0,0xABC67470,0x96A65DC0,0x248681D0,0x19E6A860,0x5E46D2B0,0x6326FB00,\n\t\t0xE1766CD1,0xDC164561,0x9BB63FB1,0xA6D61601,0x14F6CA11,0x2996E3A1,0x6E369971,0x5356B0C1,\n\t\t0x70279F96,0x4D47B626,0x0AE7CCF6,0x3787E546,0x85A73956,0xB8C710E6,0xFF676A36,0xC2074386,\n\t\t0x4057D457,0x7D37FDE7,0x3A978737,0x07F7AE87,0xB5D77297,0x88B75B27,0xCF1721F7,0xF2770847,\n\t\t0x10C70814,0x2DA721A4,0x6A075B74,0x576772C4,0xE547AED4,0xD8278764,0x9F87FDB4,0xA2E7D404,\n\t\t0x20B743D5,0x1DD76A65,0x5A7710B5,0x67173905,0xD537E515,0xE857CCA5,0xAFF7B675,0x92979FC5,\n\t\t0xE915E8DB,0xD475C16B,0x93D5BBBB,0xAEB5920B,0x1C954E1B,0x21F567AB,0x66551D7B,0x5B3534CB,\n\t\t0xD965A31A,0xE4058AAA,0xA3A5F07A,0x9EC5D9CA,0x2CE505DA,0x11852C6A,0x562556BA,0x6B457F0A,\n\t\t0x89F57F59,0xB49556E9,0xF3352C39,0xCE550589,0x7C75D999,0x4115F029,0x06B58AF9,0x3BD5A349,\n\t\t0xB9853498,0x84E51D28,0xC34567F8,0xFE254E48,0x4C059258,0x7165BBE8,0x36C5C138,0x0BA5E888,\n\t\t0x28D4C7DF,0x15B4EE6F,0x521494BF,0x6F74BD0F,0xDD54611F,0xE03448AF,0xA794327F,0x9AF41BCF,\n\t\t0x18A48C1E,0x25C4A5AE,0x6264DF7E,0x5F04F6CE,0xED242ADE,0xD044036E,0x97E479BE,0xAA84500E,\n\t\t0x4834505D,0x755479ED,0x32F4033D,0x0F942A8D,0xBDB4F69D,0x80D4DF2D,0xC774A5FD,0xFA148C4D,\n\t\t0x78441B9C,0x4524322C,0x028448FC,0x3FE4614C,0x8DC4BD5C,0xB0A494EC,0xF704EE3C,0xCA64C78C,\n\t  },\n\t  {\n\t\t0x00000000,0xCB5CD3A5,0x4DC8A10B,0x869472AE,0x9B914216,0x50CD91B3,0xD659E31D,0x1D0530B8,\n\t\t0xEC53826D,0x270F51C8,0xA19B2366,0x6AC7F0C3,0x77C2C07B,0xBC9E13DE,0x3A0A6170,0xF156B2D5,\n\t\t0x03D6029B,0xC88AD13E,0x4E1EA390,0x85427035,0x9847408D,0x531B9328,0xD58FE186,0x1ED33223,\n\t\t0xEF8580F6,0x24D95353,0xA24D21FD,0x6911F258,0x7414C2E0,0xBF481145,0x39DC63EB,0xF280B04E,\n\t\t0x07AC0536,0xCCF0D693,0x4A64A43D,0x81387798,0x9C3D4720,0x57619485,0xD1F5E62B,0x1AA9358E,\n\t\t0xEBFF875B,0x20A354FE,0xA6372650,0x6D6BF5F5,0x706EC54D,0xBB3216E8,0x3DA66446,0xF6FAB7E3,\n\t\t0x047A07AD,0xCF26D408,0x49B2A6A6,0x82EE7503,0x9FEB45BB,0x54B7961E,0xD223E4B0,0x197F3715,\n\t\t0xE82985C0,0x23755665,0xA5E124CB,0x6EBDF76E,0x73B8C7D6,0xB8E41473,0x3E7066DD,0xF52CB578,\n\t\t0x0F580A6C,0xC404D9C9,0x4290AB67,0x89CC78C2,0x94C9487A,0x5F959BDF,0xD901E971,0x125D3AD4,\n\t\t0xE30B8801,0x28575BA4,0xAEC3290A,0x659FFAAF,0x789ACA17,0xB3C619B2,0x35526B1C,0xFE0EB8B9,\n\t\t0x0C8E08F7,0xC7D2DB52,0x4146A9FC,0x8A1A7A59,0x971F4AE1,0x5C439944,0xDAD7EBEA,0x118B384F,\n\t\t0xE0DD8A9A,0x2B81593F,0xAD152B91,0x6649F834,0x7B4CC88C,0xB0101B29,0x36846987,0xFDD8BA22,\n\t\t0x08F40F5A,0xC3A8DCFF,0x453CAE51,0x8E607DF4,0x93654D4C,0x58399EE9,0xDEADEC47,0x15F13FE2,\n\t\t0xE4A78D37,0x2FFB5E92,0xA96F2C3C,0x6233FF99,0x7F36CF21,0xB46A1C84,0x32FE6E2A,0xF9A2BD8F,\n\t\t0x0B220DC1,0xC07EDE64,0x46EAACCA,0x8DB67F6F,0x90B34FD7,0x5BEF9C72,0xDD7BEEDC,0x16273D79,\n\t\t0xE7718FAC,0x2C2D5C09,0xAAB92EA7,0x61E5FD02,0x7CE0CDBA,0xB7BC1E1F,0x31286CB1,0xFA74BF14,\n\t\t0x1EB014D8,0xD5ECC77D,0x5378B5D3,0x98246676,0x852156CE,0x4E7D856B,0xC8E9F7C5,0x03B52460,\n\t\t0xF2E396B5,0x39BF4510,0xBF2B37BE,0x7477E41B,0x6972D4A3,0xA22E0706,0x24BA75A8,0xEFE6A60D,\n\t\t0x1D661643,0xD63AC5E6,0x50AEB748,0x9BF264ED,0x86F75455,0x4DAB87F0,0xCB3FF55E,0x006326FB,\n\t\t0xF135942E,0x3A69478B,0xBCFD3525,0x77A1E680,0x6AA4D638,0xA1F8059D,0x276C7733,0xEC30A496,\n\t\t0x191C11EE,0xD240C24B,0x54D4B0E5,0x9F886340,0x828D53F8,0x49D1805D,0xCF45F2F3,0x04192156,\n\t\t0xF54F9383,0x3E134026,0xB8873288,0x73DBE12D,0x6EDED195,0xA5820230,0x2316709E,0xE84AA33B,\n\t\t0x1ACA1375,0xD196C0D0,0x5702B27E,0x9C5E61DB,0x815B5163,0x4A0782C6,0xCC93F068,0x07CF23CD,\n\t\t0xF6999118,0x3DC542BD,0xBB513013,0x700DE3B6,0x6D08D30E,0xA65400AB,0x20C07205,0xEB9CA1A0,\n\t\t0x11E81EB4,0xDAB4CD11,0x5C20BFBF,0x977C6C1A,0x8A795CA2,0x41258F07,0xC7B1FDA9,0x0CED2E0C,\n\t\t0xFDBB9CD9,0x36E74F7C,0xB0733DD2,0x7B2FEE77,0x662ADECF,0xAD760D6A,0x2BE27FC4,0xE0BEAC61,\n\t\t0x123E1C2F,0xD962CF8A,0x5FF6BD24,0x94AA6E81,0x89AF5E39,0x42F38D9C,0xC467FF32,0x0F3B2C97,\n\t\t0xFE6D9E42,0x35314DE7,0xB3A53F49,0x78F9ECEC,0x65FCDC54,0xAEA00FF1,0x28347D5F,0xE368AEFA,\n\t\t0x16441B82,0xDD18C827,0x5B8CBA89,0x90D0692C,0x8DD55994,0x46898A31,0xC01DF89F,0x0B412B3A,\n\t\t0xFA1799EF,0x314B4A4A,0xB7DF38E4,0x7C83EB41,0x6186DBF9,0xAADA085C,0x2C4E7AF2,0xE712A957,\n\t\t0x15921919,0xDECECABC,0x585AB812,0x93066BB7,0x8E035B0F,0x455F88AA,0xC3CBFA04,0x089729A1,\n\t\t0xF9C19B74,0x329D48D1,0xB4093A7F,0x7F55E9DA,0x6250D962,0xA90C0AC7,0x2F987869,0xE4C4ABCC,\n\t  },\n\t  {\n\t\t0x00000000,0xA6770BB4,0x979F1129,0x31E81A9D,0xF44F2413,0x52382FA7,0x63D0353A,0xC5A73E8E,\n\t\t0x33EF4E67,0x959845D3,0xA4705F4E,0x020754FA,0xC7A06A74,0x61D761C0,0x503F7B5D,0xF64870E9,\n\t\t0x67DE9CCE,0xC1A9977A,0xF0418DE7,0x56368653,0x9391B8DD,0x35E6B369,0x040EA9F4,0xA279A240,\n\t\t0x5431D2A9,0xF246D91D,0xC3AEC380,0x65D9C834,0xA07EF6BA,0x0609FD0E,0x37E1E793,0x9196EC27,\n\t\t0xCFBD399C,0x69CA3228,0x582228B5,0xFE552301,0x3BF21D8F,0x9D85163B,0xAC6D0CA6,0x0A1A0712,\n\t\t0xFC5277FB,0x5A257C4F,0x6BCD66D2,0xCDBA6D66,0x081D53E8,0xAE6A585C,0x9F8242C1,0x39F54975,\n\t\t0xA863A552,0x0E14AEE6,0x3FFCB47B,0x998BBFCF,0x5C2C8141,0xFA5B8AF5,0xCBB39068,0x6DC49BDC,\n\t\t0x9B8CEB35,0x3DFBE081,0x0C13FA1C,0xAA64F1A8,0x6FC3CF26,0xC9B4C492,0xF85CDE0F,0x5E2BD5BB,\n\t\t0x440B7579,0xE27C7ECD,0xD3946450,0x75E36FE4,0xB044516A,0x16335ADE,0x27DB4043,0x81AC4BF7,\n\t\t0x77E43B1E,0xD19330AA,0xE07B2A37,0x460C2183,0x83AB1F0D,0x25DC14B9,0x14340E24,0xB2430590,\n\t\t0x23D5E9B7,0x85A2E203,0xB44AF89E,0x123DF32A,0xD79ACDA4,0x71EDC610,0x4005DC8D,0xE672D739,\n\t\t0x103AA7D0,0xB64DAC64,0x87A5B6F9,0x21D2BD4D,0xE47583C3,0x42028877,0x73EA92EA,0xD59D995E,\n\t\t0x8BB64CE5,0x2DC14751,0x1C295DCC,0xBA5E5678,0x7FF968F6,0xD98E6342,0xE86679DF,0x4E11726B,\n\t\t0xB8590282,0x1E2E0936,0x2FC613AB,0x89B1181F,0x4C162691,0xEA612D25,0xDB8937B8,0x7DFE3C0C,\n\t\t0xEC68D02B,0x4A1FDB9F,0x7BF7C102,0xDD80CAB6,0x1827F438,0xBE50FF8C,0x8FB8E511,0x29CFEEA5,\n\t\t0xDF879E4C,0x79F095F8,0x48188F65,0xEE6F84D1,0x2BC8BA5F,0x8DBFB1EB,0xBC57AB76,0x1A20A0C2,\n\t\t0x8816EAF2,0x2E61E146,0x1F89FBDB,0xB9FEF06F,0x7C59CEE1,0xDA2EC555,0xEBC6DFC8,0x4DB1D47C,\n\t\t0xBBF9A495,0x1D8EAF21,0x2C66B5BC,0x8A11BE08,0x4FB68086,0xE9C18B32,0xD82991AF,0x7E5E9A1B,\n\t\t0xEFC8763C,0x49BF7D88,0x78576715,0xDE206CA1,0x1B87522F,0xBDF0599B,0x8C184306,0x2A6F48B2,\n\t\t0xDC27385B,0x7A5033EF,0x4BB82972,0xEDCF22C6,0x28681C48,0x8E1F17FC,0xBFF70D61,0x198006D5,\n\t\t0x47ABD36E,0xE1DCD8DA,0xD034C247,0x7643C9F3,0xB3E4F77D,0x1593FCC9,0x247BE654,0x820CEDE0,\n\t\t0x74449D09,0xD23396BD,0xE3DB8C20,0x45AC8794,0x800BB91A,0x267CB2AE,0x1794A833,0xB1E3A387,\n\t\t0x20754FA0,0x86024414,0xB7EA5E89,0x119D553D,0xD43A6BB3,0x724D6007,0x43A57A9A,0xE5D2712E,\n\t\t0x139A01C7,0xB5ED0A73,0x840510EE,0x22721B5A,0xE7D525D4,0x41A22E60,0x704A34FD,0xD63D3F49,\n\t\t0xCC1D9F8B,0x6A6A943F,0x5B828EA2,0xFDF58516,0x3852BB98,0x9E25B02C,0xAFCDAAB1,0x09BAA105,\n\t\t0xFFF2D1EC,0x5985DA58,0x686DC0C5,0xCE1ACB71,0x0BBDF5FF,0xADCAFE4B,0x9C22E4D6,0x3A55EF62,\n\t\t0xABC30345,0x0DB408F1,0x3C5C126C,0x9A2B19D8,0x5F8C2756,0xF9FB2CE2,0xC813367F,0x6E643DCB,\n\t\t0x982C4D22,0x3E5B4696,0x0FB35C0B,0xA9C457BF,0x6C636931,0xCA146285,0xFBFC7818,0x5D8B73AC,\n\t\t0x03A0A617,0xA5D7ADA3,0x943FB73E,0x3248BC8A,0xF7EF8204,0x519889B0,0x6070932D,0xC6079899,\n\t\t0x304FE870,0x9638E3C4,0xA7D0F959,0x01A7F2ED,0xC400CC63,0x6277C7D7,0x539FDD4A,0xF5E8D6FE,\n\t\t0x647E3AD9,0xC209316D,0xF3E12BF0,0x55962044,0x90311ECA,0x3646157E,0x07AE0FE3,0xA1D90457,\n\t\t0x579174BE,0xF1E67F0A,0xC00E6597,0x66796E23,0xA3DE50AD,0x05A95B19,0x34414184,0x92364A30,\n\t  },\n\t  {\n\t\t0x00000000,0xCCAA009E,0x4225077D,0x8E8F07E3,0x844A0EFA,0x48E00E64,0xC66F0987,0x0AC50919,\n\t\t0xD3E51BB5,0x1F4F1B2B,0x91C01CC8,0x5D6A1C56,0x57AF154F,0x9B0515D1,0x158A1232,0xD92012AC,\n\t\t0x7CBB312B,0xB01131B5,0x3E9E3656,0xF23436C8,0xF8F13FD1,0x345B3F4F,0xBAD438AC,0x767E3832,\n\t\t0xAF5E2A9E,0x63F42A00,0xED7B2DE3,0x21D12D7D,0x2B142464,0xE7BE24FA,0x69312319,0xA59B2387,\n\t\t0xF9766256,0x35DC62C8,0xBB53652B,0x77F965B5,0x7D3C6CAC,0xB1966C32,0x3F196BD1,0xF3B36B4F,\n\t\t0x2A9379E3,0xE639797D,0x68B67E9E,0xA41C7E00,0xAED97719,0x62737787,0xECFC7064,0x205670FA,\n\t\t0x85CD537D,0x496753E3,0xC7E85400,0x0B42549E,0x01875D87,0xCD2D5D19,0x43A25AFA,0x8F085A64,\n\t\t0x562848C8,0x9A824856,0x140D4FB5,0xD8A74F2B,0xD2624632,0x1EC846AC,0x9047414F,0x5CED41D1,\n\t\t0x299DC2ED,0xE537C273,0x6BB8C590,0xA712C50E,0xADD7CC17,0x617DCC89,0xEFF2CB6A,0x2358CBF4,\n\t\t0xFA78D958,0x36D2D9C6,0xB85DDE25,0x74F7DEBB,0x7E32D7A2,0xB298D73C,0x3C17D0DF,0xF0BDD041,\n\t\t0x5526F3C6,0x998CF358,0x1703F4BB,0xDBA9F425,0xD16CFD3C,0x1DC6FDA2,0x9349FA41,0x5FE3FADF,\n\t\t0x86C3E873,0x4A69E8ED,0xC4E6EF0E,0x084CEF90,0x0289E689,0xCE23E617,0x40ACE1F4,0x8C06E16A,\n\t\t0xD0EBA0BB,0x1C41A025,0x92CEA7C6,0x5E64A758,0x54A1AE41,0x980BAEDF,0x1684A93C,0xDA2EA9A2,\n\t\t0x030EBB0E,0xCFA4BB90,0x412BBC73,0x8D81BCED,0x8744B5F4,0x4BEEB56A,0xC561B289,0x09CBB217,\n\t\t0xAC509190,0x60FA910E,0xEE7596ED,0x22DF9673,0x281A9F6A,0xE4B09FF4,0x6A3F9817,0xA6959889,\n\t\t0x7FB58A25,0xB31F8ABB,0x3D908D58,0xF13A8DC6,0xFBFF84DF,0x37558441,0xB9DA83A2,0x7570833C,\n\t\t0x533B85DA,0x9F918544,0x111E82A7,0xDDB48239,0xD7718B20,0x1BDB8BBE,0x95548C5D,0x59FE8CC3,\n\t\t0x80DE9E6F,0x4C749EF1,0xC2FB9912,0x0E51998C,0x04949095,0xC83E900B,0x46B197E8,0x8A1B9776,\n\t\t0x2F80B4F1,0xE32AB46F,0x6DA5B38C,0xA10FB312,0xABCABA0B,0x6760BA95,0xE9EFBD76,0x2545BDE8,\n\t\t0xFC65AF44,0x30CFAFDA,0xBE40A839,0x72EAA8A7,0x782FA1BE,0xB485A120,0x3A0AA6C3,0xF6A0A65D,\n\t\t0xAA4DE78C,0x66E7E712,0xE868E0F1,0x24C2E06F,0x2E07E976,0xE2ADE9E8,0x6C22EE0B,0xA088EE95,\n\t\t0x79A8FC39,0xB502FCA7,0x3B8DFB44,0xF727FBDA,0xFDE2F2C3,0x3148F25D,0xBFC7F5BE,0x736DF520,\n\t\t0xD6F6D6A7,0x1A5CD639,0x94D3D1DA,0x5879D144,0x52BCD85D,0x9E16D8C3,0x1099DF20,0xDC33DFBE,\n\t\t0x0513CD12,0xC9B9CD8C,0x4736CA6F,0x8B9CCAF1,0x8159C3E8,0x4DF3C376,0xC37CC495,0x0FD6C40B,\n\t\t0x7AA64737,0xB60C47A9,0x3883404A,0xF42940D4,0xFEEC49CD,0x32464953,0xBCC94EB0,0x70634E2E,\n\t\t0xA9435C82,0x65E95C1C,0xEB665BFF,0x27CC5B61,0x2D095278,0xE1A352E6,0x6F2C5505,0xA386559B,\n\t\t0x061D761C,0xCAB77682,0x44387161,0x889271FF,0x825778E6,0x4EFD7878,0xC0727F9B,0x0CD87F05,\n\t\t0xD5F86DA9,0x19526D37,0x97DD6AD4,0x5B776A4A,0x51B26353,0x9D1863CD,0x1397642E,0xDF3D64B0,\n\t\t0x83D02561,0x4F7A25FF,0xC1F5221C,0x0D5F2282,0x079A2B9B,0xCB302B05,0x45BF2CE6,0x89152C78,\n\t\t0x50353ED4,0x9C9F3E4A,0x121039A9,0xDEBA3937,0xD47F302E,0x18D530B0,0x965A3753,0x5AF037CD,\n\t\t0xFF6B144A,0x33C114D4,0xBD4E1337,0x71E413A9,0x7B211AB0,0xB78B1A2E,0x39041DCD,0xF5AE1D53,\n\t\t0x2C8E0FFF,0xE0240F61,0x6EAB0882,0xA201081C,0xA8C40105,0x646E019B,0xEAE10678,0x264B06E6,\n\t  }\n};\n\nuint32 crc32_calc_slice_by_8(uint32 previousCrc32, const void* data, size_t length)\n{\n\tuint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF\n\tconst uint32_t* current = (const uint32_t*)data;\n\n\t// process eight bytes at once (Slicing-by-8)\n\twhile (length >= 8)\n\t{\n\t\tif constexpr (std::endian::native == std::endian::big){\n\t\t\tuint32_t one = *current++ ^ _swapEndianU32(crc);\n\t\t\tuint32_t two = *current++;\n\t\t\tcrc = Crc32Lookup[0][two & 0xFF] ^\n\t\t\t\t  Crc32Lookup[1][(two >> 8) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[2][(two >> 16) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[3][(two >> 24) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[4][one & 0xFF] ^\n\t\t\t\t  Crc32Lookup[5][(one >> 8) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[6][(one >> 16) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[7][(one >> 24) & 0xFF];\n\t\t}\n\t\telse if constexpr (std::endian::native == std::endian::little)\n\t\t{\n\t\t\tuint32_t one = *current++ ^ crc;\n\t\t\tuint32_t two = *current++;\n\t\t\tcrc = Crc32Lookup[0][(two >> 24) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[1][(two >> 16) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[2][(two >> 8) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[3][two & 0xFF] ^\n\t\t\t\t  Crc32Lookup[4][(one >> 24) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[5][(one >> 16) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[6][(one >> 8) & 0xFF] ^\n\t\t\t\t  Crc32Lookup[7][one & 0xFF];\n\t\t}\n\t\telse {\n\t\t\tstatic_assert(std::endian::native == std::endian::big || std::endian::native == std::endian::little,\n\t\t\t\t\t\t  \"Platform byte-order is unsupported\");\n\t\t}\n\n\t\tlength -= 8;\n\t}\n\n\tconst uint8* currentChar = (const uint8*)current;\n\t// remaining 1 to 7 bytes (standard algorithm)\n\twhile (length-- != 0)\n\t\tcrc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++];\n\n\treturn ~crc; // same as crc ^ 0xFFFFFFFF\n}\n\nuint32 crc32_calc(uint32 c, const void* data, size_t length)\n{\n\tif (length >= 16)\n\t{\n\t\treturn crc32_calc_slice_by_8(c, data, length);\n\t}\n\tconst uint8* p = (const uint8*)data;\n\tif (length == 0)\n\t\treturn c;\n\tc ^= 0xFFFFFFFF;\n\twhile (length)\n\t{\n\t\tuint8 temp = *p;\n\t\ttemp ^= (uint8)c;\n\t\tc = (c >> 8) ^ Crc32Lookup[0][temp];\n\t\t// next\n\t\tlength--;\n\t\tp++;\n\t}\n\treturn ~c;\n}\n\nvoid CRCTest()\n{\n\tstd::vector<uint8> testData;\n\tfor (uint8 i = 0; i < 89; i++)\n\t\ttestData.emplace_back(i);\n\tuint32 r = crc32_calc(0, testData.data(), testData.size());\n\tcemu_assert(r == 0x3fc61683);\n}"
  },
  {
    "path": "src/util/crypto/crc32.h",
    "content": "#pragma once\n\nuint32 crc32_calc(uint32 c, const void* data, size_t length);\n\ninline uint32 crc32_calc(const void* data, size_t length)\n{\n\treturn crc32_calc(0, data, length);\n}"
  },
  {
    "path": "src/util/crypto/md5.cpp",
    "content": "/*\n* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n* MD5 Message-Digest Algorithm (RFC 1321).\n*\n* Homepage:\n* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5\n*\n* Author:\n* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n*\n* This software was written by Alexander Peslyak in 2001.  No copyright is\n* claimed, and the software is hereby placed in the public domain.\n* In case this attempt to disclaim copyright and place the software in the\n* public domain is deemed null and void, then the software is\n* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n* general public under the following terms:\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted.\n*\n* There's ABSOLUTELY NO WARRANTY, express or implied.\n*\n* (This is a heavily cut-down \"BSD license\".)\n*\n* This differs from Colin Plumb's older public domain implementation in that\n* no exactly 32-bit integer data type is required (any 32-bit or wider\n* unsigned integer data type will do), there's no compile-time endianness\n* configuration, and the function prototypes match OpenSSL's.  No code from\n* Colin Plumb's implementation has been reused; this comment merely compares\n* the properties of the two independent implementations.\n*\n* The primary goals of this implementation are portability and ease of use.\n* It is meant to be fast, but not as fast as possible.  Some known\n* optimizations are not included to reduce source code size and avoid\n* compile-time configuration.\n*/\n\n#ifndef HAVE_OPENSSL\n\n#include <string.h>\n\n#include \"md5.h\"\n\n/*\n* The basic MD5 functions.\n*\n* F and G are optimized compared to their RFC 1321 definitions for\n* architectures that lack an AND-NOT instruction, just like in Colin Plumb's\n* implementation.\n*/\n#define F(x, y, z)\t\t\t((z) ^ ((x) & ((y) ^ (z))))\n#define G(x, y, z)\t\t\t((y) ^ ((z) & ((x) ^ (y))))\n#define H(x, y, z)\t\t\t(((x) ^ (y)) ^ (z))\n#define H2(x, y, z)\t\t\t((x) ^ ((y) ^ (z)))\n#define I(x, y, z)\t\t\t((y) ^ ((x) | ~(z)))\n\n/*\n* The MD5 transformation for all four rounds.\n*/\n#define STEP(f, a, b, c, d, x, t, s) \\\n\t(a) += f((b), (c), (d)) + (x) + (t); \\\n\t(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \\\n\t(a) += (b);\n\n/*\n* SET reads 4 input bytes in little-endian byte order and stores them in a\n* properly aligned word in host byte order.\n*\n* The check for little-endian architectures that tolerate unaligned memory\n* accesses is just an optimization.  Nothing will break if it fails to detect\n* a suitable architecture.\n*\n* Unfortunately, this optimization may be a C strict aliasing rules violation\n* if the caller's data buffer has effective type that cannot be aliased by\n* MD5_u32plus.  In practice, this problem may occur if these MD5 routines are\n* inlined into a calling function, or with future and dangerously advanced\n* link-time optimizations.  For the time being, keeping these MD5 routines in\n* their own translation unit avoids the problem.\n*/\n#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)\n#define SET(n) \\\n\t(*(MD5_u32plus *)&ptr[(n) * 4])\n#define GET(n) \\\n\tSET(n)\n#else\n#define SET(n) \\\n\t(ctx->block[(n)] = \\\n\t(MD5_u32plus)ptr[(n) * 4] | \\\n\t((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \\\n\t((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \\\n\t((MD5_u32plus)ptr[(n) * 4 + 3] << 24))\n#define GET(n) \\\n\t(ctx->block[(n)])\n#endif\n\n/*\n* This processes one or more 64-byte data blocks, but does NOT update the bit\n* counters.  There are no alignment requirements.\n*/\nstatic const void *body(MD5_CTX *ctx, const void *data, unsigned long size)\n{\n\tconst unsigned char *ptr;\n\tMD5_u32plus a, b, c, d;\n\tMD5_u32plus saved_a, saved_b, saved_c, saved_d;\n\n\tptr = (const unsigned char *)data;\n\n\ta = ctx->a;\n\tb = ctx->b;\n\tc = ctx->c;\n\td = ctx->d;\n\n\tdo {\n\t\tsaved_a = a;\n\t\tsaved_b = b;\n\t\tsaved_c = c;\n\t\tsaved_d = d;\n\n\t\t/* Round 1 */\n\t\tSTEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)\n\t\t\tSTEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)\n\t\t\tSTEP(F, c, d, a, b, SET(2), 0x242070db, 17)\n\t\t\tSTEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)\n\t\t\tSTEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)\n\t\t\tSTEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)\n\t\t\tSTEP(F, c, d, a, b, SET(6), 0xa8304613, 17)\n\t\t\tSTEP(F, b, c, d, a, SET(7), 0xfd469501, 22)\n\t\t\tSTEP(F, a, b, c, d, SET(8), 0x698098d8, 7)\n\t\t\tSTEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)\n\t\t\tSTEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)\n\t\t\tSTEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)\n\t\t\tSTEP(F, a, b, c, d, SET(12), 0x6b901122, 7)\n\t\t\tSTEP(F, d, a, b, c, SET(13), 0xfd987193, 12)\n\t\t\tSTEP(F, c, d, a, b, SET(14), 0xa679438e, 17)\n\t\t\tSTEP(F, b, c, d, a, SET(15), 0x49b40821, 22)\n\n\t\t\t/* Round 2 */\n\t\t\tSTEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)\n\t\t\tSTEP(G, d, a, b, c, GET(6), 0xc040b340, 9)\n\t\t\tSTEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)\n\t\t\tSTEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)\n\t\t\tSTEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)\n\t\t\tSTEP(G, d, a, b, c, GET(10), 0x02441453, 9)\n\t\t\tSTEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)\n\t\t\tSTEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)\n\t\t\tSTEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)\n\t\t\tSTEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)\n\t\t\tSTEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)\n\t\t\tSTEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)\n\t\t\tSTEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)\n\t\t\tSTEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)\n\t\t\tSTEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)\n\t\t\tSTEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)\n\n\t\t\t/* Round 3 */\n\t\t\tSTEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)\n\t\t\tSTEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)\n\t\t\tSTEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)\n\t\t\tSTEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)\n\t\t\tSTEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)\n\t\t\tSTEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)\n\t\t\tSTEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)\n\t\t\tSTEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)\n\t\t\tSTEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)\n\t\t\tSTEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)\n\t\t\tSTEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)\n\t\t\tSTEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)\n\t\t\tSTEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)\n\t\t\tSTEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)\n\t\t\tSTEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)\n\t\t\tSTEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)\n\n\t\t\t/* Round 4 */\n\t\t\tSTEP(I, a, b, c, d, GET(0), 0xf4292244, 6)\n\t\t\tSTEP(I, d, a, b, c, GET(7), 0x432aff97, 10)\n\t\t\tSTEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)\n\t\t\tSTEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)\n\t\t\tSTEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)\n\t\t\tSTEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)\n\t\t\tSTEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)\n\t\t\tSTEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)\n\t\t\tSTEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)\n\t\t\tSTEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)\n\t\t\tSTEP(I, c, d, a, b, GET(6), 0xa3014314, 15)\n\t\t\tSTEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)\n\t\t\tSTEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)\n\t\t\tSTEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)\n\t\t\tSTEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)\n\t\t\tSTEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)\n\n\t\t\ta += saved_a;\n\t\tb += saved_b;\n\t\tc += saved_c;\n\t\td += saved_d;\n\n\t\tptr += 64;\n\t} while (size -= 64);\n\n\tctx->a = a;\n\tctx->b = b;\n\tctx->c = c;\n\tctx->d = d;\n\n\treturn ptr;\n}\n\nvoid MD5_Init(MD5_CTX *ctx)\n{\n\tctx->a = 0x67452301;\n\tctx->b = 0xefcdab89;\n\tctx->c = 0x98badcfe;\n\tctx->d = 0x10325476;\n\n\tctx->lo = 0;\n\tctx->hi = 0;\n}\n\nvoid MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)\n{\n\tMD5_u32plus saved_lo;\n\tunsigned long used, available;\n\n\tsaved_lo = ctx->lo;\n\tif ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)\n\t\tctx->hi++;\n\tctx->hi += size >> 29;\n\n\tused = saved_lo & 0x3f;\n\n\tif (used) {\n\t\tavailable = 64 - used;\n\n\t\tif (size < available) {\n\t\t\tmemcpy(&ctx->buffer[used], data, size);\n\t\t\treturn;\n\t\t}\n\n\t\tmemcpy(&ctx->buffer[used], data, available);\n\t\tdata = (const unsigned char *)data + available;\n\t\tsize -= available;\n\t\tbody(ctx, ctx->buffer, 64);\n\t}\n\n\tif (size >= 64) {\n\t\tdata = body(ctx, data, size & ~(unsigned long)0x3f);\n\t\tsize &= 0x3f;\n\t}\n\n\tmemcpy(ctx->buffer, data, size);\n}\n\n#define OUT_MD5(dst, src) \\\n\t(dst)[0] = (unsigned char)(src); \\\n\t(dst)[1] = (unsigned char)((src) >> 8); \\\n\t(dst)[2] = (unsigned char)((src) >> 16); \\\n\t(dst)[3] = (unsigned char)((src) >> 24);\n\nvoid MD5_Final(unsigned char *result, MD5_CTX *ctx)\n{\n\tunsigned long used, available;\n\n\tused = ctx->lo & 0x3f;\n\n\tctx->buffer[used++] = 0x80;\n\n\tavailable = 64 - used;\n\n\tif (available < 8)\n\t{\n\t\tmemset(&ctx->buffer[used], 0, available);\n\t\tbody(ctx, ctx->buffer, 64);\n\t\tused = 0;\n\t\tavailable = 64;\n\t}\n\n\tmemset(&ctx->buffer[used], 0, available - 8);\n\n\tctx->lo <<= 3;\n\tOUT_MD5(&ctx->buffer[56], ctx->lo)\n\tOUT_MD5(&ctx->buffer[60], ctx->hi)\n\n\tbody(ctx, ctx->buffer, 64);\n\n\tOUT_MD5(&result[0], ctx->a)\n\tOUT_MD5(&result[4], ctx->b)\n\tOUT_MD5(&result[8], ctx->c)\n\tOUT_MD5(&result[12], ctx->d)\n\n\tmemset(ctx, 0, sizeof(*ctx));\n}\n\n#endif\n\n// HMAC-MD5\n\nvoid hmacMD5_init_rfc2104(const unsigned char* key, int key_len, HMACMD5Ctx *ctx)\n{\n\tint i;\n\tmemset(ctx, 0, sizeof(HMACMD5Ctx));\n\t/* if key is longer than 64 bytes reset it to key=MD5(key) */\n\tif (key_len > 64)\n\t{\n\t\tunsigned char tk[16];\n\t\tMD5_CTX tctx;\n\n\t\tMD5_Init(&tctx);\n\t\tMD5_Update(&tctx, key, key_len);\n\t\tMD5_Final(tk, &tctx);\n\n\t\tkey = tk;\n\t\tkey_len = 16;\n\t}\n\n\t/* start out by storing key in pads */\n\tmemcpy(ctx->k_ipad, key, key_len);\n\tmemcpy(ctx->k_opad, key, key_len);\n\n\t/* XOR key with ipad and opad values */\n\tfor (i = 0; i < 64; i++)\n\t{\n\t\tctx->k_ipad[i] ^= 0x36;\n\t\tctx->k_opad[i] ^= 0x5c;\n\t}\n\n\tMD5_Init(&ctx->ctx);\n\tMD5_Update(&ctx->ctx, ctx->k_ipad, 64);\n}\n\nvoid hmacMD5_init_limK_to_64(const unsigned char* key, int key_len, HMACMD5Ctx *ctx)\n{\n\tif (key_len > 64)\n\t{\n\t\tkey_len = 64;\n\t}\n\thmacMD5_init_rfc2104(key, key_len, ctx);\n}\n\nvoid hmacMD5_update(const unsigned char* text, int text_len, HMACMD5Ctx *ctx)\n{\n\tMD5_Update(&ctx->ctx, text, text_len);\n}\n\nvoid hmacMD5_final(unsigned char* digest, HMACMD5Ctx *ctx)\n{\n\tMD5_CTX ctx_o;\n\tMD5_Final(digest, &ctx->ctx);\n\n\tMD5_Init(&ctx_o);\n\tMD5_Update(&ctx_o, ctx->k_opad, 64);\n\tMD5_Update(&ctx_o, digest, 16);\n\tMD5_Final(digest, &ctx_o);\n}\n\nvoid hmacMD5(const unsigned char* key, int keyLen, const unsigned char* text, int textLen, unsigned char* digest)\n{\n\tHMACMD5Ctx ctx;\n\thmacMD5_init_limK_to_64(key, keyLen, &ctx);\n\thmacMD5_update(text, textLen, &ctx);\n\thmacMD5_final(digest, &ctx);\n}"
  },
  {
    "path": "src/util/crypto/md5.h",
    "content": "/*\n* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n* MD5 Message-Digest Algorithm (RFC 1321).\n*\n* Homepage:\n* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5\n*\n* Author:\n* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n*\n* This software was written by Alexander Peslyak in 2001.  No copyright is\n* claimed, and the software is hereby placed in the public domain.\n* In case this attempt to disclaim copyright and place the software in the\n* public domain is deemed null and void, then the software is\n* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n* general public under the following terms:\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted.\n*\n* There's ABSOLUTELY NO WARRANTY, express or implied.\n*\n* See md5.c for more information.\n*/\n\n#ifdef HAVE_OPENSSL\n#include <openssl/md5.h>\n#elif !defined(_MD5_H)\n#define _MD5_H\n\n/* Any 32-bit or wider unsigned integer data type will do */\ntypedef unsigned int MD5_u32plus;\n\ntypedef struct \n{\n\tMD5_u32plus lo, hi;\n\tMD5_u32plus a, b, c, d;\n\tunsigned char buffer[64];\n\tMD5_u32plus block[16];\n}MD5_CTX;\n\nextern void MD5_Init(MD5_CTX *ctx);\nextern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);\nextern void MD5_Final(unsigned char *result, MD5_CTX *ctx);\n\n#endif\n\n// HMAC-MD5\n\ntypedef struct\n{\n\tMD5_CTX ctx;\n\tunsigned char k_ipad[64];\n\tunsigned char k_opad[64];\n}HMACMD5Ctx;\n\nvoid hmacMD5_init_limK_to_64(const unsigned char* key, int key_len, HMACMD5Ctx *ctx);\nvoid hmacMD5_update(const unsigned char* text, int text_len, HMACMD5Ctx *ctx);\nvoid hmacMD5_final(unsigned char* digest, HMACMD5Ctx *ctx);\nvoid hmacMD5(const unsigned char* key, int keyLen, const unsigned char* text, int textLen, unsigned char* digest);"
  },
  {
    "path": "src/util/helpers/ClassWrapper.h",
    "content": "#pragma once\n\n#include <mutex>\n#include <memory>\n\ntemplate<typename T>\nclass SingletonClass\n{\npublic:\n\tstatic T* getInstance()\n\t{\n\t\tstatic T instance;\n\t\treturn &instance;\n\t}\n\nprotected:\n\tSingletonClass() = default;\n};\n\ntemplate<typename T>\nclass SingletonRef\n{\npublic:\n\t/*static std::shared_ptr<T> getInstance() C++20 only\n\t{\n\t\tstatic std::atomic<std::weak_ptr<T>> s_instance;\n\t\tstd::shared_ptr<T> result;\n\t\ts_instance.compare_exchange_weak(result, std::make_shared<T>());\n\t\treturn result;\n\t}*/\n\t\n\tstatic std::shared_ptr<T> getInstance()\n\t{\n\t\tstd::scoped_lock lock(s_mutex);\n\t\t\n\t\tauto result = s_instance.lock();\n\t\tif(!result)\n\t\t{\n\t\t\tresult = std::make_shared<T>();\n\t\t\ts_instance = result;\n\t\t}\n\t\t\n\t\treturn result;\n\t}\n\nprotected:\n\tSingletonRef() = default;\n\nprivate:\n\tstatic inline std::weak_ptr<T> s_instance;\n\tstatic inline std::mutex s_mutex;\n};"
  },
  {
    "path": "src/util/helpers/ConcurrentQueue.h",
    "content": "#pragma once\n\n#include <mutex>\n#include <condition_variable>\n#include <queue>\n\ntemplate <typename T> \nclass ConcurrentQueue\n{\npublic:\n\tConcurrentQueue() = default;\n\tConcurrentQueue(const ConcurrentQueue&) = delete;\n\tConcurrentQueue& operator=(const ConcurrentQueue&) = delete;\n\n\tsize_t push(const T& item)\n\t{\n\t\tstd::unique_lock<std::mutex> mlock(m_mutex);\n\t\tm_queue.push(item);\n\t\tconst size_t result = m_queue.size();\n\t\tmlock.unlock();\n\t\tm_condVar.notify_one();\n\t\treturn result;\n\t}\n\n\ttemplate<typename ... Args>\n\tsize_t push(Args&& ... args)\n\t{\n\t\tstd::unique_lock<std::mutex> mlock(m_mutex);\n\t\tm_queue.emplace(std::forward<Args>(args)...);\n\t\tconst size_t result = m_queue.size();\n\t\tmlock.unlock();\n\t\tm_condVar.notify_one();\n\t\treturn result;\n\t}\n\n\tT peek()\n\t{\n\t\tstd::unique_lock<std::mutex> mlock(m_mutex);\n\t\twhile (m_queue.empty())\n\t\t{\n\t\t\tm_condVar.wait(mlock);\n\t\t}\n\n\t\treturn m_queue.front();\n\t}\n\n\tbool peek2(T& item)\n\t{\n\t\tstd::unique_lock<std::mutex> mlock(m_mutex);\n\t\tif (m_queue.empty())\n\t\t\treturn false;\n\t\titem = m_queue.front();\n\t\tm_queue.pop();\n\t\treturn true;\n\t}\n\n\tT pop()\n\t{\n\t\tstd::unique_lock<std::mutex> mlock(m_mutex);\n\t\twhile (m_queue.empty())\n\t\t{\n\t\t\tm_condVar.wait(mlock);\n\t\t}\n\n\t\tauto val = m_queue.front();\n\t\tm_queue.pop();\n\t\treturn val;\n\t}\n\n\tvoid pop(T& item)\n\t{\n\t\tstd::unique_lock<std::mutex> mlock(m_mutex);\n\t\twhile (m_queue.empty())\n\t\t{\n\t\t\tm_condVar.wait(mlock);\n\t\t}\n\n\t\titem = m_queue.front();\n\t\tm_queue.pop();\n\t}\n\n\tvoid clear()\n\t{\n\t\tstd::unique_lock<std::mutex> mlock(m_mutex);\n\t\twhile (!m_queue.empty())\n\t\t\tm_queue.pop();\n\t}\n\n\tsize_t size()\n\t{\n\t\tstd::unique_lock<std::mutex> mlock(m_mutex);\n\t\treturn m_queue.size();\n\t}\n\n\tbool empty()\n\t{\n\t\tstd::unique_lock<std::mutex> mlock(m_mutex);\n\t\treturn m_queue.empty();\n\t}\n\nprivate:\n\tstd::mutex m_mutex;\n\tstd::condition_variable m_condVar;\n\tstd::queue<T> m_queue;\n};\n"
  },
  {
    "path": "src/util/helpers/MapAdaptor.h",
    "content": "#pragma once\n\n// https://ideone.com/k0H8Ei\n\n#include <iostream>\n#include <map>\n#include <boost/iterator/transform_iterator.hpp>\n\ntemplate <typename T, typename F>\nstruct map_adaptor\n{\n\tmap_adaptor(const T& t, const F& f) : _t(t), _f(f) {}\n\tmap_adaptor(map_adaptor& a) = delete;\n\tmap_adaptor(map_adaptor&& a) = default;\n\n\t[[nodiscard]] auto begin() { return boost::make_transform_iterator(_t.begin(), _f); }\n\t[[nodiscard]] auto end() { return boost::make_transform_iterator(_t.end(), _f); }\n\n\t[[nodiscard]] auto cbegin() const { return boost::make_transform_iterator(_t.cbegin(), _f); }\n\t[[nodiscard]] auto cend() const { return boost::make_transform_iterator(_t.cend(), _f); }\n\nprotected:\n\tconst T& _t;\n\tF _f;\n};\n\n\ntemplate <typename T, typename F>\nauto get_map_adaptor(const T& t, const F& f) { return map_adaptor<T, F>(t, f); }\n\ntemplate <typename T>\nauto get_keys(const T& t) { return get_map_adaptor(t, [](const auto& p) { return p.first; }); }\n\ntemplate <typename T>\nauto get_values(const T& t) { return get_map_adaptor(t, [](const auto& p) { return p.second; }); }\n"
  },
  {
    "path": "src/util/helpers/MemoryPool.h",
    "content": "#pragma once\n\ntemplate<typename T>\nclass MemoryPool\n{\n\tstatic_assert(sizeof(T) >= sizeof(void*)); // object must be large enough to store a single pointer\n\npublic:\n\tMemoryPool(int allocationGranularity)\n\t\t: m_numObjectsAllocated(0)\n\t{\n\t\tm_allocationGranularity = allocationGranularity;\n\t\tm_nextFreeObject = nullptr;\n\t}\n\n\ttemplate <typename... Ts>\n\tT* allocObj(Ts&&... args)\n\t{\n\t\tif (m_nextFreeObject)\n\t\t{\n\t\t\tT* allocatedObj = m_nextFreeObject;\n\t\t\tm_nextFreeObject = *(T**)allocatedObj;\n\t\t\tnew (allocatedObj) T(std::forward<Ts>(args)...);\n\t\t\treturn allocatedObj;\n\t\t}\n\t\t// enlarge pool\n\t\tincreasePoolSize();\n\t\tT* allocatedObj = m_nextFreeObject;\n\t\tm_nextFreeObject = *(T**)allocatedObj;\n\t\tnew (allocatedObj) T(std::forward<Ts>(args)...);\n\t\treturn allocatedObj;\n\t}\n\n\tvoid freeObj(T* obj)\n\t{\n\t\tobj->~T();\n\t\tpushElementOnFreeStack(obj);\n\t}\n\nprivate:\n\tvoid pushElementOnFreeStack(T* obj)\n\t{\n\t\t*(T**)obj = m_nextFreeObject;\n\t\tm_nextFreeObject = obj;\n\t}\n\n\tvoid increasePoolSize()\n\t{\n\t\tT* newElements = static_cast<T*>(::operator new(m_allocationGranularity * sizeof(T), std::nothrow));\n\t\tm_numObjectsAllocated += m_allocationGranularity;\n\t\tfor (int i = 0; i < m_allocationGranularity; i++)\n\t\t{\n\t\t\tpushElementOnFreeStack(newElements);\n\t\t\tnewElements++;\n\t\t}\n\t}\n\nprivate:\n\tT* m_nextFreeObject;\n\tint m_allocationGranularity;\n\tint m_numObjectsAllocated;\n};\n\n// this memory pool calls the default constructor when the internal pool is allocated\n// no constructor/destructor will be called on acquire/release\ntemplate<typename T>\nclass MemoryPoolPermanentObjects\n{\n\tstruct internalObject_t\n\t{\n\t\tT v;\n\t\tinternalObject_t* next;\n\t};\n\npublic:\n\tMemoryPoolPermanentObjects(int allocationGranularity)\n\t\t: m_numObjectsAllocated(0)\n\t{\n\t\tm_allocationGranularity = allocationGranularity;\n\t\tm_nextFreeObject = nullptr;\n\t}\n\n\ttemplate <typename... Ts>\n\tT* acquireObj(Ts&&... args)\n\t{\n\t\tif (m_nextFreeObject)\n\t\t{\n\t\t\tinternalObject_t* allocatedObject = m_nextFreeObject;\n\t\t\tm_nextFreeObject = allocatedObject->next;\n\t\t\treturn &allocatedObject->v;\n\t\t}\n\t\t// enlarge pool\n\t\tincreasePoolSize();\n\t\tinternalObject_t* allocatedObject = m_nextFreeObject;\n\t\tm_nextFreeObject = allocatedObject->next;\n\t\treturn &allocatedObject->v;\n\t}\n\n\tvoid releaseObj(T* obj)\n\t{\n\t\tinternalObject_t* internalObj = (internalObject_t*)((uint8*)obj - offsetof(internalObject_t, v));\n\t\tpushElementOnFreeStack(internalObj);\n\t}\n\nprivate:\n\tvoid pushElementOnFreeStack(internalObject_t* obj)\n\t{\n\t\tobj->next = m_nextFreeObject;\n\t\tm_nextFreeObject = obj;\n\t}\n\n\tvoid increasePoolSize()\n\t{\n\t\tinternalObject_t* newElements = static_cast<internalObject_t*>(::operator new(m_allocationGranularity * sizeof(internalObject_t), std::nothrow));\n\t\tm_numObjectsAllocated += m_allocationGranularity;\n\t\tfor (int i = 0; i < m_allocationGranularity; i++)\n\t\t{\n\t\t\tnew (&newElements->v) T();\n\t\t\tpushElementOnFreeStack(newElements);\n\t\t\tnewElements++;\n\t\t}\n\t}\n\nprivate:\n\tinternalObject_t* m_nextFreeObject;\n\tint m_allocationGranularity;\n\tint m_numObjectsAllocated;\n};"
  },
  {
    "path": "src/util/helpers/Semaphore.h",
    "content": "#pragma once\n\n#include <mutex>\n#include <condition_variable>\n\nclass Semaphore\n{\npublic:\n\tvoid notify() \n\t{\n\t\tstd::lock_guard lock(m_mutex);\n\t\t++m_count;\n\t\tm_condition.notify_one();\n\t}\n\n\tvoid wait() \n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\twhile (m_count == 0)\n\t\t{\n\t\t\tm_condition.wait(lock);\n\t\t}\n\n\t\t--m_count;\n\t}\n\n\tbool try_wait() \n\t{\n\t\tstd::lock_guard lock(m_mutex);\n\t\tif (m_count == 0)\n\t\t\treturn false;\n\n\t\t--m_count;\n\t\treturn true;\n\t}\n\n\tvoid reset()\n\t{\n\t\tstd::lock_guard lock(m_mutex);\n\t\tm_count = 0;\n\t}\n\nprivate:\n\tstd::mutex m_mutex;\n\tstd::condition_variable m_condition;\n\tuint64 m_count = 0;\n};\n\nclass CounterSemaphore\n{\npublic:\n\tvoid reset()\n\t{\n\t\tstd::lock_guard lock(m_mutex);\n\t\tm_count = 0;\n\t}\n\n\tvoid increment()\n\t{\n\t\tstd::lock_guard lock(m_mutex);\n\t\t++m_count;\n\t\tif (m_count == 1)\n\t\t\tm_condition.notify_all();\n\t}\n\n\tvoid decrement()\n\t{\n\t\tstd::lock_guard lock(m_mutex);\n\t\t--m_count;\n\t\tcemu_assert_debug(m_count >= 0);\n\t\tif (m_count == 0)\n\t\t\tm_condition.notify_all();\n\t}\n\n\t// decrement only if non-zero\n\t// otherwise wait\n\tvoid decrementWithWait()\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\twhile (m_count == 0)\n\t\t\tm_condition.wait(lock);\n\t\tm_count--;\n\t}\n\n\t// decrement only if non-zero\n\t// otherwise wait\n\t// may wake up spuriously\n\tbool decrementWithWaitAndTimeout(uint32 ms)\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\tif (m_count == 0)\n\t\t{\n\t\t\tm_condition.wait_for(lock, std::chrono::milliseconds(ms));\n\t\t}\n\t\tif (m_count == 0)\n\t\t\treturn false;\n\t\tm_count--;\n\t\treturn true;\n\t}\n\n\tvoid waitUntilZero()\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\twhile (m_count != 0)\n\t\t\tm_condition.wait(lock);\n\t}\n\n\tvoid waitUntilNonZero()\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\twhile (m_count == 0)\n\t\t\tm_condition.wait(lock);\n\t}\n\n\tbool isZero() const\n\t{\n\t\treturn m_count == 0;\n\t}\n\nprivate:\n\tstd::mutex m_mutex;\n\tstd::condition_variable m_condition;\n\tsint64 m_count = 0;\n};\n\ntemplate<typename T>\nclass StateSemaphore\n{\npublic:\n\tStateSemaphore(T initialState) : m_state(initialState) {};\n\n\tT getValue()\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\treturn m_state;\n\t}\n\n\tbool hasState(T state)\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\treturn m_state == state;\n\t}\n\n\tvoid setValue(T newState)\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\tm_state = newState;\n\t\tm_condition.notify_all();\n\t}\n\n\tvoid setValue(T newState, T expectedValue)\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\twhile (m_state != expectedValue)\n\t\t\tm_condition.wait(lock);\n\t\tm_state = newState;\n\t\tm_condition.notify_all();\n\t}\n\n\tvoid waitUntilValue(T state)\n\t{\n\t\tstd::unique_lock lock(m_mutex);\n\t\twhile (m_state != state)\n\t\t\tm_condition.wait(lock);\n\t}\n\nprivate:\n\tstd::mutex m_mutex;\n\tstd::condition_variable m_condition;\n\tT m_state;\n};"
  },
  {
    "path": "src/util/helpers/Serializer.cpp",
    "content": "#include \"Serializer.h\"\n\ntemplate<>\nuint8 MemStreamReader::readBE()\n{\n\tif (!reserveReadLength(sizeof(uint8)))\n\t\treturn 0;\n\tuint8 v = m_data[m_cursorPos];\n\tm_cursorPos += sizeof(uint8);\n\treturn v;\n}\n\ntemplate<>\nuint16 MemStreamReader::readBE()\n{\n\tif (!reserveReadLength(sizeof(uint16)))\n\t\treturn 0;\n\tconst uint8* p = m_data + m_cursorPos;\n\tuint16 v;\n\tstd::memcpy(&v, p, sizeof(v));\n\tv = _BE(v);\n\tm_cursorPos += sizeof(uint16);\n\treturn v;\n}\n\ntemplate<>\nuint32 MemStreamReader::readBE()\n{\n\tif (!reserveReadLength(sizeof(uint32)))\n\t\treturn 0;\n\tconst uint8* p = m_data + m_cursorPos;\n\tuint32 v;\n\tstd::memcpy(&v, p, sizeof(v));\n\tv = _BE(v);\n\tm_cursorPos += sizeof(uint32);\n\treturn v;\n}\n\ntemplate<>\nuint64 MemStreamReader::readBE()\n{\n\tif (!reserveReadLength(sizeof(uint64)))\n\t\treturn 0;\n\tconst uint8* p = m_data + m_cursorPos;\n\tuint64 v;\n\tstd::memcpy(&v, p, sizeof(v));\n\tv = _BE(v);\n\tm_cursorPos += sizeof(uint64);\n\treturn v;\n}\n\ntemplate<>\nstd::string MemStreamReader::readBE()\n{\n\tstd::string s;\n\tuint32 stringSize = readBE<uint32>();\n\tif (hasError())\n\t\treturn s;\n\tif (stringSize >= (32 * 1024 * 1024))\n\t{\n\t\t// out of bounds read or suspiciously large string\n\t\tm_hasError = true;\n\t\treturn std::string();\n\t}\n\ts.resize(stringSize);\n\treadData(s.data(), stringSize);\n\treturn s;\n}\n\ntemplate<>\nuint8 MemStreamReader::readLE()\n{\n\treturn readBE<uint8>();\n}\n\ntemplate<>\nuint32 MemStreamReader::readLE()\n{\n\tif (!reserveReadLength(sizeof(uint32)))\n\t\treturn 0;\n\tconst uint8* p = m_data + m_cursorPos;\n\tuint32 v;\n\tstd::memcpy(&v, p, sizeof(v));\n\tv = _LE(v);\n\tm_cursorPos += sizeof(uint32);\n\treturn v;\n}\n\ntemplate<>\nuint64 MemStreamReader::readLE()\n{\n\tif (!reserveReadLength(sizeof(uint64)))\n\t\treturn 0;\n\tconst uint8* p = m_data + m_cursorPos;\n\tuint64 v;\n\tstd::memcpy(&v, p, sizeof(v));\n\tv = _LE(v);\n\tm_cursorPos += sizeof(uint64);\n\treturn v;\n}\n\ntemplate<>\nvoid MemStreamWriter::writeBE<uint64>(const uint64& v)\n{\n\tm_buffer.resize(m_buffer.size() + 8);\n\tuint8* p = m_buffer.data() + m_buffer.size() - 8;\n\tuint64 tmp = _BE(v);\n\tstd::memcpy(p, &tmp, sizeof(tmp));\n}\n\ntemplate<>\nvoid MemStreamWriter::writeBE<uint32>(const uint32& v)\n{\n\tm_buffer.resize(m_buffer.size() + 4);\n\tuint8* p = m_buffer.data() + m_buffer.size() - 4;\n\tuint32 tmp = _BE(v);\n\tstd::memcpy(p, &tmp, sizeof(tmp));\n}\n\n\ntemplate<>\nvoid MemStreamWriter::writeBE<uint16>(const uint16& v)\n{\n\tm_buffer.resize(m_buffer.size() + 2);\n\tuint8* p = m_buffer.data() + m_buffer.size() - 2;\n\tuint16 tmp = _BE(v);\n\tstd::memcpy(p, &tmp, sizeof(tmp));\n}\n\n\ntemplate<>\nvoid MemStreamWriter::writeBE<uint8>(const uint8& v)\n{\n\tm_buffer.emplace_back(v);\n}\n\n\ntemplate<>\nvoid MemStreamWriter::writeBE<std::string>(const std::string& v)\n{\n\twriteBE<uint32>((uint32)v.size());\n\twriteData(v.data(), v.size());\n}\n\ntemplate<>\nvoid MemStreamWriter::writeLE<uint64>(const uint64& v)\n{\n\tm_buffer.resize(m_buffer.size() + 8);\n\tuint8* p = m_buffer.data() + m_buffer.size() - 8;\n\tuint64 tmp = _LE(v);\n\tstd::memcpy(p, &tmp, sizeof(tmp));\n}\n\n\ntemplate<>\nvoid MemStreamWriter::writeLE<uint32>(const uint32& v)\n{\n\tm_buffer.resize(m_buffer.size() + 4);\n\tuint8* p = m_buffer.data() + m_buffer.size() - 4;\n\tuint32 tmp = _LE(v);\n\tstd::memcpy(p, &tmp, sizeof(tmp));\n}"
  },
  {
    "path": "src/util/helpers/Serializer.h",
    "content": "#pragma once\n\nclass MemStreamReader\n{\npublic:\n\tMemStreamReader(const uint8* data, sint32 size) : m_data(data), m_size(size)\n\t{\n\t\tm_cursorPos = 0;\n\t}\n\n\ttemplate<typename T> T readBE();\n\ttemplate<typename T> T readLE();\n\n\ttemplate<typename T>\n\tstd::vector<T> readPODVector()\n\t{\n\t\tuint32 numElements = readBE<uint32>();\n\t\tif (hasError())\n\t\t{\n\t\t\treturn std::vector<T>();\n\t\t}\n\t\tstd::vector<T> v;\n\t\tv.reserve(numElements);\n\t\tv.resize(numElements);\n\t\treadData(v.data(), v.size() * sizeof(T));\n\t\treturn v;\n\t}\n\n\t// read string terminated by newline character (or end of stream)\n\t// will also trim off any carriage return\n\tstd::string_view readLine()\n\t{\n\t\tsize_t length = 0;\n\t\tif (m_cursorPos >= m_size)\n\t\t{\n\t\t\tm_hasError = true;\n\t\t\treturn std::basic_string_view((const char*)nullptr, 0);\n\t\t}\n\t\t// end of line is determined by '\\n'\n\t\tconst char* lineStrBegin = (const char*)(m_data + m_cursorPos);\n\t\tconst char* lineStrEnd = nullptr;\n\t\twhile (m_cursorPos < m_size)\n\t\t{\n\t\t\tif (m_data[m_cursorPos] == '\\n')\n\t\t\t{\n\t\t\t\tlineStrEnd = (const char*)(m_data + m_cursorPos);\n\t\t\t\tm_cursorPos++; // skip the newline character\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tm_cursorPos++;\n\t\t}\n\t\tif(lineStrEnd == nullptr)\n\t\t\tlineStrEnd = (const char*)(m_data + m_cursorPos);\n\t\t// truncate any '\\r' at the beginning and end\n\t\twhile (lineStrBegin < lineStrEnd)\n\t\t{\n\t\t\tif (lineStrBegin[0] != '\\r')\n\t\t\t\tbreak;\n\t\t\tlineStrBegin++;\n\t\t}\n\t\twhile (lineStrEnd > lineStrBegin)\n\t\t{\n\t\t\tif (lineStrEnd[-1] != '\\r')\n\t\t\t\tbreak;\n\t\t\tlineStrEnd--;\n\t\t}\n\t\tlength = (lineStrEnd - lineStrBegin);\n\t\treturn std::basic_string_view((const char*)lineStrBegin, length);\n\t}\n\n\tbool readData(void* ptr, size_t size)\n\t{\n\t\tif (m_cursorPos + size > m_size)\n\t\t{\n\t\t\tm_cursorPos = m_size;\n\t\t\tm_hasError = true;\n\t\t\treturn false;\n\t\t}\n\t\tmemcpy(ptr, m_data + m_cursorPos, size);\n\t\tm_cursorPos += (sint32)size;\n\t\treturn true;\n\t}\n\n\tstd::span<uint8> readDataNoCopy(size_t size)\n\t{\n\t\tif (m_cursorPos + size > m_size)\n\t\t{\n\t\t\tm_cursorPos = m_size;\n\t\t\tm_hasError = true;\n\t\t\treturn std::span<uint8>();\n\t\t}\n\t\tauto r = std::span<uint8>((uint8*)m_data + m_cursorPos, size);\n\t\tm_cursorPos += (sint32)size;\n\t\treturn r;\n\t}\n\n\t// returns true if any of the reads was out of bounds\n\tbool hasError() const\n\t{\n\t\treturn m_hasError;\n\t}\n\n\tbool isEndOfStream() const\n\t{\n\t\treturn m_cursorPos == m_size;\n\t}\n\nprivate:\n\tbool reserveReadLength(size_t length)\n\t{\n\t\tif (m_cursorPos + length > m_size)\n\t\t{\n\t\t\tm_cursorPos = m_size;\n\t\t\tm_hasError = true;\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid skipCRLF()\n\t{\n\t\twhile (m_cursorPos < m_size)\n\t\t{\n\t\t\tif (m_data[m_cursorPos] != '\\r' && m_data[m_cursorPos] != '\\n')\n\t\t\t\tbreak;\n\t\t\tm_cursorPos++;\n\t\t}\n\t}\n\n\tconst uint8* m_data;\n\tsint32 m_size;\n\tsint32 m_cursorPos;\n\tbool m_hasError{ false };\n};\n\nclass MemStreamWriter\n{\npublic:\n\tMemStreamWriter(size_t reservedSize)\n\t{\n\t\tif (reservedSize > 0)\n\t\t\tm_buffer.reserve(reservedSize);\n\t\telse\n\t\t\tm_buffer.reserve(128);\n\t}\n\n\tvoid writeData(const void* ptr, size_t size)\n\t{\n\t\tm_buffer.resize(m_buffer.size() + size);\n\t\tuint8* p = m_buffer.data() + m_buffer.size() - size;\n\t\tmemcpy(p, ptr, size);\n\t}\n\n\ttemplate<typename T> void writeBE(const T& v);\n\ttemplate<typename T> void writeLE(const T& v);\n\n\ttemplate<typename T>\n\tvoid writePODVector(const std::vector<T>& v)\n\t{\n\t\twriteBE<uint32>(v.size());\n\t\twriteData(v.data(), v.size() * sizeof(T));\n\t}\n\n\t// get result buffer without copy\n\t// resets internal state\n\tvoid getResultAndReset(std::vector<uint8>& data)\n\t{\n\t\tstd::swap(m_buffer, data);\n\t\tm_buffer.clear();\n\t}\n\n\tstd::span<uint8> getResult()\n\t{\n\t\treturn std::span<uint8>(m_buffer.data(), m_buffer.size());\n\t}\n\nprivate:\n\tstd::vector<uint8> m_buffer;\n};\n\nclass SerializerHelper \n{\npublic:\n\tbool serialize(std::vector<uint8>& data)\n\t{\n\t\tMemStreamWriter streamWriter(0);\n\t\tbool r = serializeImpl(streamWriter);\n\t\tif (!r)\n\t\t\treturn false;\n\t\tstreamWriter.getResultAndReset(data);\n\t\treturn true;\n\t}\n\n\tbool deserialize(std::vector<uint8>& data)\n\t{\n\t\tMemStreamReader memStreamReader(data.data(), (sint32)data.size());\n\t\treturn deserializeImpl(memStreamReader);\n\t}\n\nprotected:\n\tvirtual bool serializeImpl(MemStreamWriter& streamWriter) = 0;\n\tvirtual bool deserializeImpl(MemStreamReader& streamReader) = 0;\n};"
  },
  {
    "path": "src/util/helpers/Singleton.h",
    "content": "#pragma once\n\ntemplate<typename TType>\nclass Singleton\n{\nprotected:\n\tSingleton() = default;\n\tSingleton(const Singleton&) = delete;\n\tSingleton(Singleton&&) noexcept = delete;\n\npublic:\n\tstatic TType& instance() noexcept\n\t{\n\t\tstatic TType s_instance;\n\t\treturn s_instance;\n\t}\n};\n"
  },
  {
    "path": "src/util/helpers/StringBuf.h",
    "content": "#pragma once\n\nclass StringBuf\n{\npublic:\n\tStringBuf(uint32 bufferSize)\n\t{\n\t\tthis->str = (uint8*)malloc(bufferSize + 4);\n\t\tthis->allocated = true;\n\t\tthis->length = 0;\n\t\tthis->limit = bufferSize;\n\t}\n\n\t~StringBuf()\n\t{\n\t\tif (this->allocated)\n\t\t\tfree(this->str);\n\t}\n\n\ttemplate<typename TFmt, typename ... TArgs>\n\tvoid addFmt(const TFmt& format, TArgs&&... args)\n\t{\n\t\tauto r = fmt::vformat_to_n((char*)(this->str + this->length), (size_t)(this->limit - this->length), fmt::detail::to_string_view(format), fmt::make_format_args(args...));\n\t\tthis->length += (uint32)r.size;\n\t}\n\n\tvoid add(const char* appendedStr)\n\t{\n\t\tconst char* outputStart = (char*)(this->str + this->length);\n\t\tchar* output = (char*)outputStart;\n\t\tconst char* outputEnd = (char*)(this->str + this->limit - 1);\n\t\twhile (output < outputEnd)\n\t\t{\n\t\t\tchar c = *appendedStr;\n\t\t\tif (c == '\\0')\n\t\t\t\tbreak;\n\t\t\t*output = c;\n\t\t\tappendedStr++;\n\t\t\toutput++;\n\t\t}\n\t\tthis->length += (uint32)(output - outputStart);\n\t\t*output = '\\0';\n\t}\n\n\tvoid add(std::string_view appendedStr)\n\t{\n\t\tsize_t copyLen = appendedStr.size();\n\t\tif (this->length + copyLen + 1 >= this->limit)\n\t\t\t_reserve(std::max<uint32>(this->length + copyLen + 64, this->limit + this->limit / 2));\n\t\tchar* outputStart = (char*)(this->str + this->length);\n\t\tstd::copy(appendedStr.data(), appendedStr.data() + copyLen, outputStart);\n\t\tlength += copyLen;\n\t\toutputStart[copyLen] = '\\0';\n\t}\n\n\tvoid reset()\n\t{\n\t\tlength = 0;\n\t}\n\n\tuint32 getLen() const\n\t{\n\t\treturn length;\n\t}\n\n\tconst char* c_str() const\n\t{\n\t\tstr[length] = '\\0';\n\t\treturn (const char*)str;\n\t}\n\n\tvoid shrink_to_fit()\n\t{\n\t\tif (!this->allocated)\n\t\t\treturn;\n\t\tuint32 newLimit = this->length;\n\t\tthis->str = (uint8*)realloc(this->str, newLimit + 4);\n\t\tthis->limit = newLimit;\n\t}\n\nprivate:\n\tvoid _reserve(uint32 newLimit)\n\t{\n\t\tcemu_assert_debug(newLimit > length);\n\t\tthis->str = (uint8*)realloc(this->str, newLimit + 4);\n\t\tthis->limit = newLimit;\n\t}\n\n\tuint8*\tstr;\n\tuint32\tlength; /* in bytes */\n\tuint32\tlimit; /* in bytes */\n\tbool\tallocated;\n};"
  },
  {
    "path": "src/util/helpers/StringHelpers.h",
    "content": "#pragma once\n#include \"boost/nowide/convert.hpp\"\n#include <charconv>\n\n// Definition for removed templates in Apple Clang 17\n#if defined(__apple_build_version__) && (__apple_build_version__ >= 17000000)\nnamespace std {\n\ttemplate<>\n\tstruct char_traits<uint16be> {\n\t\tusing char_type = uint16be;\n\t\tusing int_type = int;\n\t\tusing off_type = streamoff;\n\t\tusing pos_type = streampos;\n\t\tusing state_type = mbstate_t;\n\n\t\tstatic inline void constexpr assign(char_type& c1, const char_type& c2) noexcept {\n\t\t\tc1 = c2;\n\t\t}\n\n\t\tstatic inline constexpr bool eq(char_type c1, char_type c2) noexcept {\n\t\t\treturn c1 == c2;\n\t\t}\n\n\t\tstatic inline constexpr bool lt(char_type c1, char_type c2) noexcept {\n\t\t\treturn c1 < c2;\n\t\t}\n\n\t\tstatic constexpr int compare(const char_type* s1, const char_type* s2, size_t n) {\n\t\t\tfor (; n; --n, ++s1, ++s2) {\n\t\t\t\tif (lt(*s1, *s2)) return -1;\n\t\t\t\tif (lt(*s2, *s1)) return 1;\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\n\t\tstatic constexpr size_t length(const char_type* s) {\n\t\t\tsize_t len = 0;\n\t\t\tfor (; !eq(*s, char_type(0)); ++s) ++len;\n\t\t\treturn len;\n\t\t}\n\n\t\tstatic constexpr const char_type* find(const char_type* s, size_t n, const char_type& a) {\n\t\t\tfor (; n; --n) {\n\t\t\t\tif (eq(*s, a))\n\t\t\t\t\treturn s;\n\t\t\t\t++s;\n\t\t\t}\n\t\t\treturn nullptr;\n\t\t}\n\n\t\tstatic constexpr char_type* move(char_type* s1, const char_type* s2, size_t n) {\n\t\t\tif (n == 0) return s1;\n\t\t\treturn static_cast<char_type*>(memmove(s1, s2, n * sizeof(char_type)));\n\t\t}\n\n\t\tstatic constexpr char_type* copy(char_type* s1, const char_type* s2, size_t n) {\n\t\t\tif (n == 0) return s1;\n\t\t\treturn static_cast<char_type*>(memcpy(s1, s2, n * sizeof(char_type)));\n\t\t}\n\n\t\tstatic constexpr char_type* assign(char_type* s, size_t n, char_type a) {\n\t\t\tchar_type* r = s;\n\t\t\tfor (; n; --n, ++s)\n\t\t\t\tassign(*s, a);\n\t\t\treturn r;\n\t\t}\n\n\t\tstatic inline constexpr char_type to_char_type(int_type c) noexcept {\n\t\t\treturn char_type(c);\n\t\t}\n\n\t\tstatic inline constexpr int_type to_int_type(char_type c) noexcept {\n\t\t\treturn int_type(c);\n\t\t}\n\n\t\tstatic inline constexpr bool eq_int_type(int_type c1, int_type c2) noexcept {\n\t\t\treturn c1 == c2;\n\t\t}\n\n\t\tstatic inline constexpr int_type eof() noexcept {\n\t\t\treturn static_cast<int_type>(EOF);\n\t\t}\n\n\t\tstatic inline constexpr int_type not_eof(int_type c) noexcept {\n\t\t\treturn eq_int_type(c, eof()) ? ~eof() : c;\n\t\t}\n\t};\n}\n#endif\n\n// todo - move the Cafe/PPC specific parts to CafeString.h eventually\nnamespace StringHelpers\n{\n\t// convert Wii U big-endian wchar_t string to utf8 string\n\tstatic std::string ToUtf8(const uint16be* ptr, size_t maxLength)\n\t{\n\t\tstd::wstringstream result;\n\t\twhile (*ptr != 0 && maxLength > 0)\n\t\t{\n\t\t\tauto c = (uint16)*ptr;\n\t\t\tresult << static_cast<wchar_t>(c);\n\t\t\tptr++;\n\t\t\tmaxLength--;\n\t\t}\n\t\treturn boost::nowide::narrow(result.str());\n\t}\n\n\tstatic std::string ToUtf8(std::span<uint16be> input)\n\t{\n\t\treturn ToUtf8(input.data(), input.size());\n\t}\n\n\t// convert utf8 string to Wii U big-endian wchar_t string\n\tstatic std::vector<uint16be> FromUtf8(std::string_view str)\n\t{\n\t\tstd::vector<uint16be> tmpStr;\n\t\tstd::wstring w = boost::nowide::widen(str.data(), str.size());\n\t\tfor (auto& c : w)\n\t\t\ttmpStr.push_back((uint16)c);\n\t\treturn tmpStr;\n\t}\n\n\tstatic sint32 ToInt(const std::string_view& input, sint32 defaultValue = 0)\n\t{\n\t\tsint32 value = defaultValue;\n\t\tif (input.size() >= 2 && (input[0] == '0' && (input[1] == 'x' || input[1] == 'X')))\n\t\t{\n\t\t\t// hex number\n\t\t\tconst std::from_chars_result result = std::from_chars(input.data() + 2, input.data() + input.size(), value, 16);\n\t\t\tif (result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range)\n\t\t\t\treturn defaultValue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// decimal value\n\t\t\tconst std::from_chars_result result = std::from_chars(input.data(), input.data() + input.size(), value);\n\t\t\tif (result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range)\n\t\t\t\treturn defaultValue;\n\t\t}\n\t\treturn value;\n\t}\n\n\tstatic sint64 ToInt64(const std::string_view& input, sint64 defaultValue = 0)\n\t{\n\t\tsint64 value = defaultValue;\n\t\tif (input.size() >= 2 && (input[0] == '0' && (input[1] == 'x' || input[1] == 'X')))\n\t\t{\n\t\t\t// hex number\n\t\t\tconst std::from_chars_result result = std::from_chars(input.data() + 2, input.data() + input.size(), value, 16);\n\t\t\tif (result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range)\n\t\t\t\treturn defaultValue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// decimal value\n\t\t\tconst std::from_chars_result result = std::from_chars(input.data(), input.data() + input.size(), value);\n\t\t\tif (result.ec == std::errc::invalid_argument || result.ec == std::errc::result_out_of_range)\n\t\t\t\treturn defaultValue;\n\t\t}\n\t\treturn value;\n\t}\n\n\tstatic size_t ParseHexString(std::string_view input, uint8* output, size_t maxOutputLength)\n\t{\n\t\tsize_t parsedLen = 0;\n\t\tfor (size_t i = 0; i < input.size() - 1; i += 2)\n\t\t{\n\t\t\tif (maxOutputLength <= 0)\n\t\t\t\tbreak;\n\t\t\tuint8 b = 0;\n\t\t\tuint8 c = input[i + 0];\n\t\t\t// high nibble\n\t\t\tif (c >= '0' && c <= '9')\n\t\t\t\tb |= ((c - '0') << 4);\n\t\t\telse if (c >= 'a' && c <= 'f')\n\t\t\t\tb |= ((c - 'a' + 10) << 4);\n\t\t\telse if (c >= 'A' && c <= 'F')\n\t\t\t\tb |= ((c - 'A' + 10) << 4);\n\t\t\telse\n\t\t\t\tbreak;\n\t\t\t// low nibble\n\t\t\tc = input[i + 1];\n\t\t\tif (c >= '0' && c <= '9')\n\t\t\t\tb |= (c - '0');\n\t\t\telse if (c >= 'a' && c <= 'f')\n\t\t\t\tb |= (c - 'a' + 10);\n\t\t\telse if (c >= 'A' && c <= 'F')\n\t\t\t\tb |= (c - 'A' + 10);\n\t\t\telse\n\t\t\t\tbreak;\n\t\t\t*output = b;\n\t\t\toutput++;\n\t\t\tmaxOutputLength--;\n\t\t\tparsedLen++;\n\t\t}\n\t\treturn parsedLen;\n\t}\n\n\tclass StringLineIterator\n\t{\n\tpublic:\n\t\tclass Iterator\n\t\t{\n\t\tpublic:\n\t\t\tusing iterator_category = std::input_iterator_tag;\n\t\t\tusing value_type = std::string_view;\n\t\t\tusing difference_type = std::ptrdiff_t;\n\t\t\tusing pointer = const std::string_view*;\n\t\t\tusing reference = const std::string_view&;\n\n\t\t\tIterator(std::string_view str, sint32 pos) : m_str(str), m_pos(pos)\n\t\t\t{\n\t\t\t\tupdate_line();\n\t\t\t}\n\n\t\t\treference operator*() const\n\t\t\t{\n\t\t\t\treturn m_line;\n\t\t\t}\n\n\t\t\tpointer operator->() const\n\t\t\t{\n\t\t\t\treturn &m_line;\n\t\t\t}\n\n\t\t\tIterator& operator++()\n\t\t\t{\n\t\t\t\tm_pos = m_nextPos;\n\t\t\t\tupdate_line();\n\t\t\t\treturn *this;\n\t\t\t}\n\n\t\t\tfriend bool operator==(const Iterator& lhs, const Iterator& rhs)\n\t\t\t{\n\t\t\t\treturn lhs.m_str.data() == rhs.m_str.data() && lhs.m_pos == rhs.m_pos;\n\t\t\t}\n\n\t\t\tfriend bool operator!=(const Iterator& lhs, const Iterator& rhs)\n\t\t\t{\n\t\t\t\treturn !(lhs == rhs);\n\t\t\t}\n\n\t\tprivate:\n\t\t\tvoid update_line()\n\t\t\t{\n\t\t\t\tif (m_pos >= m_str.size())\n\t\t\t\t{\n\t\t\t\t\tm_pos = -1;\n\t\t\t\t\tm_line = {};\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tauto pos = m_str.find('\\n', m_pos);\n\t\t\t\tm_nextPos = pos != std::string_view::npos ? pos : -1;\n\t\t\t\tif(m_nextPos < 0)\n\t\t\t\t\tm_line = m_str.substr(m_pos, std::string::npos);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tm_line = m_str.substr(m_pos, m_nextPos - m_pos);\n\t\t\t\t\t++m_nextPos; // skip \\n\n\t\t\t\t}\n\t\t\t\twhile (!m_line.empty() && m_line.back() == '\\r')\n\t\t\t\t\tm_line.remove_suffix(1);\n\t\t\t}\n\n\t\t\tstd::string_view m_str;\n\t\t\tsint32 m_pos;\n\t\t\tsint32 m_nextPos;\n\t\t\tstd::string_view m_line;\n\t\t};\n\n\t\tStringLineIterator(std::string_view str) : m_str(str) {}\n\t\tStringLineIterator(std::span<uint8> str) : m_str((const char*)str.data(), str.size()) {}\n\n\t\tIterator begin() const\n\t\t{\n\t\t\treturn Iterator{m_str, 0 };\n\t\t}\n\n\t\tIterator end() const\n\t\t{\n\t\t\treturn Iterator{m_str, -1 };\n\t\t}\n\n\tprivate:\n\t\tstd::string_view m_str;\n\t};\n};\n\n"
  },
  {
    "path": "src/util/helpers/StringParser.h",
    "content": "#pragma once\n\nclass StringTokenParser\n{\npublic:\n\tStringTokenParser() : m_str(nullptr), m_len(0) {};\n\n\tStringTokenParser(const char* input, sint32 inputLen) : m_str(input), m_len(inputLen) {};\n\tStringTokenParser(std::string_view str) : m_str(str.data()), m_len((sint32)str.size()) {};\n\n\t// skip whitespaces at current ptr position\n\tvoid skipWhitespaces()\n\t{\n\t\tm_str = _skipWhitespaces(m_str, m_len);\n\t}\n\n\t// decrease string length as long as there is a whitespace at the end\n\tvoid trimWhitespaces()\n\t{\n\t\twhile (m_len > 0)\n\t\t{\n\t\t\tconst char c = m_str[m_len - 1];\n\t\t\tif (c != ' ' && c != '\\t')\n\t\t\t\tbreak;\n\t\t\tm_len--;\n\t\t}\n\t}\n\n\tbool isEndOfString()\n\t{\n\t\treturn m_len <= 0;\n\t}\n\n\tsint32 skipToCharacter(const char c)\n\t{\n\t\tauto str = m_str;\n\t\tauto len = m_len;\n\t\tsint32 idx = 0;\n\t\twhile (len > 0)\n\t\t{\n\t\t\tif (*str == c)\n\t\t\t{\n\t\t\t\tm_str = str;\n\t\t\t\tm_len = len;\n\t\t\t\treturn idx;\n\t\t\t}\n\t\t\tlen--;\n\t\t\tstr++;\n\t\t\tidx++;\n\t\t}\n\t\treturn -1;\n\t}\n\n\tbool matchWordI(const char* word)\n\t{\n\t\tauto str = m_str;\n\t\tauto length = m_len;\n\t\tstr = _skipWhitespaces(str, length);\n\t\tfor (sint32 i = 0; i <= length; i++)\n\t\t{\n\t\t\tif (word[i] == '\\0')\n\t\t\t{\n\t\t\t\tm_str = str + i;\n\t\t\t\tm_len = length - i;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (i == length)\n\t\t\t\treturn false;\n\n\t\t\tchar c1 = str[i];\n\t\t\tchar c2 = word[i];\n\t\t\tc1 = _toUpperCase(c1);\n\t\t\tc2 = _toUpperCase(c2);\n\t\t\tif (c1 != c2)\n\t\t\t\treturn false;\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool compareCharacter(sint32 relativeIndex, const char c)\n\t{\n\t\tif (relativeIndex >= m_len)\n\t\t\treturn false;\n\t\treturn m_str[relativeIndex] == c;\n\t}\n\n\tbool compareCharacterI(sint32 relativeIndex, const char c)\n\t{\n\t\tif (relativeIndex >= m_len)\n\t\t\treturn false;\n\t\treturn _toUpperCase(m_str[relativeIndex]) == _toUpperCase(c);\n\t}\n\n\tvoid skipCharacters(sint32 count)\n\t{\n\t\tif (count > m_len)\n\t\t\tcount = m_len;\n\t\tm_str += count;\n\t\tm_len -= count;\n\t}\n\n\tbool parseU32(uint32& val)\n\t{\n\t\tauto str = m_str;\n\t\tauto length = m_len;\n\t\tstr = _skipWhitespaces(str, length);\n\t\tuint32 value = 0;\n\t\tsint32 index = 0;\n\t\tbool isHex = false;\n\t\tif (length <= 0)\n\t\t\treturn false;\n\t\tif (length >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))\n\t\t{\n\t\t\tisHex = true;\n\t\t\tindex += 2;\n\t\t}\n\t\telse if (str[index] == '0')\n\t\t{\n\t\t\tisHex = true;\n\t\t\tindex++;\n\t\t}\n\t\tif (length <= index)\n\t\t\treturn false;\n\t\tif (isHex)\n\t\t{\n\t\t\tsint32 firstDigitIndex = index;\n\t\t\tfor (; index < length; index++)\n\t\t\t{\n\t\t\t\tconst char c = str[index];\n\t\t\t\tif (c >= '0' && c <= '9')\n\t\t\t\t{\n\t\t\t\t\tvalue *= 0x10;\n\t\t\t\t\tvalue += (c - '0');\n\t\t\t\t}\n\t\t\t\telse if (c >= 'a' && c <= 'f')\n\t\t\t\t{\n\t\t\t\t\tvalue *= 0x10;\n\t\t\t\t\tvalue += (c - 'a' + 10);\n\t\t\t\t}\n\t\t\t\telse if (c >= 'A' && c <= 'F')\n\t\t\t\t{\n\t\t\t\t\tvalue *= 0x10;\n\t\t\t\t\tvalue += (c - 'A' + 10);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (index == firstDigitIndex)\n\t\t\t\treturn false;\n\t\t\tm_str = str + index;\n\t\t\tm_len = length - index;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsint32 firstDigitIndex = index;\n\t\t\tfor (; index < length; index++)\n\t\t\t{\n\t\t\t\tconst char c = str[index];\n\t\t\t\tif (c >= '0' && c <= '9')\n\t\t\t\t{\n\t\t\t\t\tvalue *= 10;\n\t\t\t\t\tvalue += (c - '0');\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (index == firstDigitIndex)\n\t\t\t\treturn false;\n\t\t\tm_str = str + index;\n\t\t\tm_len = length - index;\n\t\t}\n\t\tval = value;\n\t\treturn true;\n\t}\n\n\tbool parseSymbolName(const char*& symbolStr, sint32& symbolLength)\n\t{\n\t\tauto str = m_str;\n\t\tauto length = m_len;\n\t\tstr = _skipWhitespaces(str, length);\n\t\t// symbols must start with a letter or _\n\t\tif (length <= 0)\n\t\t\treturn false;\n\t\tif (!(str[0] >= 'a' && str[0] <= 'z') &&\n\t\t\t!(str[0] >= 'A' && str[0] <= 'Z') &&\n\t\t\t!(str[0] == '_'))\n\t\t\treturn false;\n\t\tsint32 idx = 1;\n\t\twhile (idx < length)\n\t\t{\n\t\t\tconst char c = str[idx];\n\t\t\tif (!(c >= 'a' && c <= 'z') &&\n\t\t\t\t!(c >= 'A' && c <= 'Z') &&\n\t\t\t\t!(c >= '0' && c <= '9') &&\n\t\t\t\t!(c == '_') && !(c == '.'))\n\t\t\t\tbreak;\n\t\t\tidx++;\n\t\t}\n\t\tsymbolStr = str;\n\t\tsymbolLength = idx;\n\t\tm_str = str + idx;\n\t\tm_len = length - idx;\n\t\treturn true;\n\t}\n\n\tconst char* getCurrentPtr()\n\t{\n\t\treturn m_str;\n\t}\n\n\tsint32 getCurrentLen()\n\t{\n\t\treturn m_len;\n\t}\n\n\tvoid storeParserState(StringTokenParser* bak)\n\t{\n\t\tbak->m_str = m_str;\n\t\tbak->m_len = m_len;\n\t}\n\n\tvoid restoreParserState(const StringTokenParser* bak)\n\t{\n\t\tm_str = bak->m_str;\n\t\tm_len = bak->m_len;\n\t}\n\n\tprivate:\n\t\tconst char* _skipWhitespaces(const char* str, sint32& length)\n\t\t{\n\t\t\twhile (length > 0)\n\t\t\t{\n\t\t\t\tif (*str != ' ' && *str != '\\t')\n\t\t\t\t\tbreak;\n\t\t\t\tstr++;\n\t\t\t\tlength--;\n\t\t\t}\n\t\t\treturn str;\n\t\t}\n\n\t\tchar _toUpperCase(const char c)\n\t\t{\n\t\t\tif (c >= 'a' && c <= 'z') \n\t\t\t\treturn c + ('A' - 'a');\n\t\t\treturn c;\n\t\t}\n\n\tprivate:\n\t\tconst char* m_str;\n\t\tsint32 m_len;\n};\n\n"
  },
  {
    "path": "src/util/helpers/SystemException.h",
    "content": "#pragma once\n\n#include \"util/helpers/helpers.h\"\n\nclass SystemException : public std::runtime_error\n{\npublic:\n\tSystemException()\n\t\t: std::runtime_error(GetSystemErrorMessage().c_str()), m_error_code(GetExceptionError())\n\t{}\n\n\tSystemException(const std::exception& ex)\n\t\t: std::runtime_error(GetSystemErrorMessage(ex).c_str()), m_error_code(GetExceptionError())\n\t{}\n\t\n\tSystemException(const std::error_code& ec)\n\t\t: std::runtime_error(GetSystemErrorMessage(ec).c_str()), m_error_code(GetExceptionError())\n\t{}\n\n\t[[nodiscard]] DWORD GetErrorCode() const { return m_error_code; }\nprivate:\n\tDWORD m_error_code;\n};\n"
  },
  {
    "path": "src/util/helpers/TempState.h",
    "content": "#pragma once\n\ntemplate<typename TCtor, typename TDtor>\nclass TempState\n{\npublic:\n\tTempState(TCtor ctor, TDtor dtor)\n\t\t: m_dtor(std::move(dtor))\n\t{\n\t\tctor();\n\t}\n\n\t~TempState()\n\t{\n\t\tm_dtor();\n\t}\n\nprivate:\n\tTDtor m_dtor;\n};\n"
  },
  {
    "path": "src/util/helpers/enum_array.hpp",
    "content": "#pragma once\n\n// expects the enum class (T) to have a value called ENUM_COUNT which is the maximum value + 1\n\ntemplate<typename E, class T>\nclass enum_array : public std::array<T, static_cast<size_t>(E::ENUM_COUNT)> {\npublic:\n\tT& operator[] (E e) {\n\t\treturn std::array<T, static_cast<size_t>(E::ENUM_COUNT)>::operator[]((std::size_t)e);\n\t}\n\n\tconst T& operator[] (E e) const {\n\t\treturn std::array<T, static_cast<size_t>(E::ENUM_COUNT)>::operator[]((std::size_t)e);\n\t}\n};"
  },
  {
    "path": "src/util/helpers/fixedSizeList.h",
    "content": "#pragma once\n\n#include<array>\n\ntemplate<typename T, uint32 maxElements, bool checkMaxSize = true>\nclass FixedSizeList\n{\npublic:\n\tstd::array<T, maxElements> m_elementArray;\n\tint count = 0;\n\n\tvoid add(T n)\n\t{\n\t\tif (checkMaxSize && count >= maxElements)\n\t\t\treturn;\n\t\tm_elementArray[count] = n;\n\t\tcount++;\n\t}\n\n\tvoid addUnique(T n)\n\t{\n\t\tif (checkMaxSize && count >= maxElements)\n\t\t\treturn;\n\t\tfor (int i = 0; i < count; i++)\n\t\t{\n\t\t\tif (m_elementArray[i] == n)\n\t\t\t\treturn;\n\t\t}\n\t\tm_elementArray[count] = n;\n\t\tcount++;\n\t}\n\n\tvoid remove(T n)\n\t{\n\t\tfor (int i = 0; i < count; i++)\n\t\t{\n\t\t\tif (m_elementArray[i] == n)\n\t\t\t{\n\t\t\t\tm_elementArray[i] = m_elementArray[count - 1];\n\t\t\t\tcount--;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tbool containsAndRemove(T n)\n\t{\n\t\tfor (int i = 0; i < count; i++)\n\t\t{\n\t\t\tif (m_elementArray[i] == n)\n\t\t\t{\n\t\t\t\tm_elementArray[i] = m_elementArray[count - 1];\n\t\t\t\tcount--;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tsint32 find(T n)\n\t{\n\t\tfor (int i = 0; i < count; i++)\n\t\t{\n\t\t\tif (m_elementArray[i] == n)\n\t\t\t{\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\nprivate:\n};\n\n"
  },
  {
    "path": "src/util/helpers/fspinlock.h",
    "content": "#pragma once\n\n// minimal but efficient non-recursive spinlock implementation\n\n#include <atomic>\n\nclass FSpinlock\n{\npublic:\n\tbool is_locked() const\n\t{\n\t\treturn m_lockBool.load(std::memory_order_relaxed);\n\t}\n\n\t// implement BasicLockable and Lockable\n\tvoid lock() const\n\t{\n\t\twhile (true)\n\t\t{\n\t\t\tif (!m_lockBool.exchange(true, std::memory_order_acquire))\n\t\t\t\tbreak;\n\t\t\twhile (m_lockBool.load(std::memory_order_relaxed)) \n                _mm_pause();\n\t\t}\n\t}\n\n\tbool try_lock() const\n\t{\n\t\treturn !m_lockBool.exchange(true, std::memory_order_acquire);\n\t}\n\n\tvoid unlock() const\n\t{\n\t\tm_lockBool.store(false, std::memory_order_release);\n\t}\n\nprivate:\n\t\n\tmutable std::atomic<bool> m_lockBool = false;\n};\n"
  },
  {
    "path": "src/util/helpers/helpers.cpp",
    "content": "#include \"helpers.h\"\n\n#include <algorithm> \n#include <functional> \n#include <cctype>\n#include <random>\n\n#include \"config/ActiveSettings.h\"\n\n#include <boost/random/uniform_int.hpp>\n\n#include <zlib.h>\n\n\n#if BOOST_OS_WINDOWS\n#include <TlHelp32.h>\n#endif\n\nstd::string& ltrim(std::string& str, const std::string& chars)\n{\n\tstr.erase(0, str.find_first_not_of(chars));\n\treturn str;\n}\n\nstd::string& rtrim(std::string& str, const std::string& chars)\n{\n\tstr.erase(str.find_last_not_of(chars) + 1);\n\treturn str;\n}\n\nstd::string& trim(std::string& str, const std::string& chars)\n{\n\treturn ltrim(rtrim(str, chars), chars);\n}\n\n\nstd::string_view& ltrim(std::string_view& str, const std::string& chars)\n{\n\tstr.remove_prefix(std::min(str.find_first_not_of(chars), str.size()));\n\treturn str;\n}\nstd::string_view& rtrim(std::string_view& str, const std::string& chars)\n{\n\tstr.remove_suffix(std::max(str.size() - str.find_last_not_of(chars) - 1, (size_t)0));\n\treturn str;\n}\nstd::string_view& trim(std::string_view& str, const std::string& chars)\n{\n\treturn ltrim(rtrim(str, chars), chars);\n}\n\n#if BOOST_OS_WINDOWS\n\nstd::string GetSystemErrorMessage(DWORD error_code)\n{\n\tif(error_code == ERROR_SUCCESS)\n\t\treturn {};\n\n\tLPSTR lpMsgBuf = nullptr;\n\tFormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, error_code, 0, (LPSTR)&lpMsgBuf, 0, nullptr);\n\tif (lpMsgBuf)\n\t{\n\t\tstd::string str = fmt::format(\"{}: {}\", _tr(\"Error\"), lpMsgBuf); // TRANSLATE\n\t\tLocalFree(lpMsgBuf);\n\t\treturn str;\n\t}\n\n\treturn fmt::format(\"{}: {:#x}\", _tr(\"Error code\"), error_code);\n}\n\nstd::string GetSystemErrorMessage()\n{\n\treturn GetSystemErrorMessage(GetLastError());\n}\n\n#else\n\nstd::string GetSystemErrorMessage()\n{\n\treturn \"\";\n}\n\n#endif\n\nstd::string GetSystemErrorMessage(const std::exception& ex)\n{\n\tconst std::string msg = GetSystemErrorMessage();\n\tif(msg.empty())\n\t\treturn ex.what();\n\n\treturn fmt::format(\"{}\\n{}\",msg, ex.what());\n}\n\nstd::string GetSystemErrorMessage(const std::error_code& ec)\n{\n\tconst std::string msg = GetSystemErrorMessage();\n\tif(msg.empty())\n\t\treturn ec.message();\n\n\treturn fmt::format(\"{}\\n{}\",msg, ec.message());\n}\n\n#if BOOST_OS_WINDOWS\nconst DWORD MS_VC_EXCEPTION = 0x406D1388;\n#pragma pack(push,8)\ntypedef struct tagTHREADNAME_INFO\n{\n\tDWORD dwType; // Must be 0x1000.\n\tLPCSTR szName; // Pointer to name (in user addr space).\n\tDWORD dwThreadID; // Thread ID (-1=caller thread).\n\tDWORD dwFlags; // Reserved for future use, must be zero.\n} THREADNAME_INFO;\n#pragma pack(pop)\n#endif\n\nvoid SetThreadName(const char* name)\n{\n#if BOOST_OS_WINDOWS\n\tusing SetThreadDescription_t = HRESULT (*)(HANDLE hThread, PCWSTR lpThreadDescription);\n\tstatic SetThreadDescription_t pSetThreadDescription = nullptr;\n\tif (!pSetThreadDescription)\n\t\tpSetThreadDescription = (SetThreadDescription_t)GetProcAddress(LoadLibraryW(L\"Kernel32.dll\"), \"SetThreadDescription\");\n\tif (pSetThreadDescription)\n\t{\n\t\tsize_t len = strlen(name) * 2 + 1;\n\t\tauto threadDescription = new wchar_t[len];\n\t\tif (boost::nowide::widen(threadDescription, len, name))\n\t\t\tpSetThreadDescription(GetCurrentThread(), threadDescription);\n\t\tdelete[] threadDescription;\n\t}\n#ifdef _MSC_VER\n\tTHREADNAME_INFO info;\n\tinfo.dwType = 0x1000;\n\tinfo.szName = name;\n\tinfo.dwThreadID = GetCurrentThreadId();\n\tinfo.dwFlags = 0;\n#pragma warning(push)\n#pragma warning(disable: 6320 6322)\n\t__try {\n\t\tRaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);\n\t}\n\t__except (EXCEPTION_EXECUTE_HANDLER) {\n\t}\n#pragma warning(pop)\n#endif\n#elif BOOST_OS_MACOS\n\tpthread_setname_np(name);\n#else\n\tif(std::strlen(name) > 15)\n\t\tcemuLog_log(LogType::Force, \"Truncating thread name {} because it was longer than 15 characters\", name);\n\tpthread_setname_np(pthread_self(), std::string{name}.substr(0,15).c_str());\n#endif\n}\n\n#if BOOST_OS_WINDOWS\nstd::pair<DWORD, DWORD> GetWindowsVersion()\n{\n\tusing RtlGetVersion_t = LONG(*)(POSVERSIONINFOEXW);\n\tstatic RtlGetVersion_t pRtlGetVersion = nullptr;\n\tif(!pRtlGetVersion) \n\t\tpRtlGetVersion = (RtlGetVersion_t)GetProcAddress(GetModuleHandleA(\"ntdll.dll\"), \"RtlGetVersion\");\n\tcemu_assert(pRtlGetVersion);\n\n\tOSVERSIONINFOEXW version_info{};\n\tpRtlGetVersion(&version_info);\n\treturn { version_info.dwMajorVersion, version_info.dwMinorVersion };\n}\n\nbool IsWindows81OrGreater()\n{\n\tconst auto [major, minor] = GetWindowsVersion();\n\treturn major > 6 || (major == 6 && minor >= 3);\n}\n\nbool IsWindows10OrGreater()\n{\n\tconst auto [major, minor] = GetWindowsVersion();\n\treturn major >= 10;\n}\n#endif\n\nfs::path GetParentProcess()\n{\n\tfs::path result;\n\t\n#if BOOST_OS_WINDOWS\n\tHANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);\n\tif(hSnapshot != INVALID_HANDLE_VALUE)\n\t{\n\t\tDWORD pid = GetCurrentProcessId();\n\t\t\n\t\tPROCESSENTRY32 pe{};\n\t\tpe.dwSize = sizeof(pe);\n\t\tfor(BOOL ret = Process32First(hSnapshot, &pe); ret; ret = Process32Next(hSnapshot, &pe))\n\t\t{\n\t\t\tif(pe.th32ProcessID == pid)\n\t\t\t{\n\t\t\t\tHANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ParentProcessID);\n\t\t\t\tif(hProcess)\n\t\t\t\t{\n\t\t\t\t\twchar_t tmp[MAX_PATH];\n\t\t\t\t\tDWORD size = std::size(tmp);\n\t\t\t\t\tif (QueryFullProcessImageNameW(hProcess, 0, tmp, &size) && size > 0)\n\t\t\t\t\t\tresult = tmp;\n\t\t\t\t\t\n\t\t\t\t\tCloseHandle(hProcess);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t\n\t\tCloseHandle(hSnapshot);\n\t}\n#else\n\tassert_dbg();\n#endif\n\n\treturn result;\n}\n\nstd::string ltrim_copy(const std::string& s)\n{\n\tstd::string result = s;\n\tltrim(result);\n\treturn result;\n}\n\nstd::string rtrim_copy(const std::string& s)\n{\n\tstd::string result = s;\n\trtrim(result);\n\treturn result;\n}\n\nuint32_t GetPhysicalCoreCount()\n{\n\tstatic uint32_t s_core_count = 0;\n\tif (s_core_count != 0)\n\t\treturn s_core_count;\n\t\n#if BOOST_OS_WINDOWS\n\tauto core_count = std::thread::hardware_concurrency();\n\n\t// Get physical cores\n\tPSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = nullptr;\n\tDWORD returnLength = 0;\n\tGetLogicalProcessorInformation(buffer, &returnLength);\n\tif (returnLength > 0)\n\t{\n\t\tbuffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(returnLength);\n\t\tif (GetLogicalProcessorInformation(buffer, &returnLength))\n\t\t{\n\t\t\tuint32_t counter = 0;\n\t\t\tfor (DWORD i = 0; i < returnLength / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i)\n\t\t\t{\n\t\t\t\tif (buffer[i].Relationship == RelationProcessorCore)\n\t\t\t\t\t++counter;\n\t\t\t}\n\n\t\t\tif (counter > 0 && counter < core_count)\n\t\t\t\tcore_count = counter;\n\t\t}\n\n\t\tfree(buffer);\n\t}\n\n\ts_core_count = core_count;\n\treturn core_count;\n#else\n\treturn std::thread::hardware_concurrency();\n#endif\n}\n\nbool TestWriteAccess(const fs::path& p)\n{\n\tstd::error_code ec;\n\t// must be path and must exist\n\tif (!fs::exists(p, ec) || !fs::is_directory(p, ec))\n\t\treturn false;\n\n\t// retry 3 times\n\tfor (int i = 0; i < 3; ++i)\n\t{\n\t\tconst auto filename = p / fmt::format(\"_{}.tmp\", GenerateRandomString(8));\n\t\tif (fs::exists(filename, ec))\n\t\t\tcontinue;\n\n\t\tstd::ofstream file(filename);\n\t\tif (!file.is_open()) // file couldn't be created\n\t\t\tbreak;\n\t\t\n\t\tfile.close();\n\n\t\tfs::remove(filename, ec);\n\t\treturn true;\n\t}\n\t\n\treturn false;\n}\n\n// make path relative to Cemu directory\nfs::path MakeRelativePath(const fs::path& base, const fs::path& path)\n{\n\ttry\n\t{\n\t\treturn fs::relative(path, base);\n\t}\n\tcatch (const std::exception&)\n\t{\n\t\treturn path;\n\t}\n}\n\n#ifdef HAS_DIRECTINPUT\nbool GUIDFromString(const char* string, GUID& guid)\n{\n\tunsigned long p0;\n\tint p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;\n\tconst sint32 count = sscanf_s(string, \"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\", &p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);\n\tif (count != 11)\n\t\treturn false;\n\n\tguid.Data1 = p0;\n\tguid.Data2 = p1;\n\tguid.Data3 = p2;\n\tguid.Data4[0] = p3;\n\tguid.Data4[1] = p4;\n\tguid.Data4[2] = p5;\n\tguid.Data4[3] = p6;\n\tguid.Data4[4] = p7;\n\tguid.Data4[5] = p8;\n\tguid.Data4[6] = p9;\n\tguid.Data4[7] = p10;\n\treturn count == 11;\n}\n\nstd::string StringFromGUID(const GUID& guid)\n{\n\tchar temp[256];\n\tsprintf(temp, \"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\",\n\t\tguid.Data1, guid.Data2, guid.Data3,\n\t\tguid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);\n\treturn std::string(temp);\n}\n\nstd::wstring WStringFromGUID(const GUID& guid)\n{\n\twchar_t temp[256];\n\tswprintf_s(temp, L\"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\",\n\t\tguid.Data1, guid.Data2, guid.Data3,\n\t\tguid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);\n\n\treturn std::wstring(temp);\n}\n#endif\n\nstd::vector<std::string_view> TokenizeView(std::string_view str, char delimiter)\n{\n\tstd::vector<std::string_view> result;\n\n\tsize_t last_token_index = 0;\n\tfor (auto index = str.find(delimiter); index != std::string_view::npos; index = str.find(delimiter, index + 1))\n\t{\n\t\tconst auto token = str.substr(last_token_index, index - last_token_index);\n\t\tresult.emplace_back(token);\n\n\t\tlast_token_index = index + 1;\n\t}\n\n\ttry\n\t{\n\t\tconst auto token = str.substr(last_token_index);\n\t\tresult.emplace_back(token);\n\t}\n\tcatch (const std::invalid_argument&) {}\n\n\treturn result;\n}\n\nstd::vector<std::string> Tokenize(std::string_view str, char delimiter)\n{\n\tstd::vector<std::string> result;\n\n\tsize_t last_token_index = 0;\n\tfor (auto index = str.find(delimiter); index != std::string_view::npos; index = str.find(delimiter, index + 1))\n\t{\n\t\tconst auto token = str.substr(last_token_index, index - last_token_index);\n\t\tresult.emplace_back(token);\n\n\t\tlast_token_index = index + 1;\n\t}\n\n\ttry\n\t{\n\t\tconst auto token = str.substr(last_token_index);\n\t\tresult.emplace_back(token);\n\t}\n\tcatch (const std::invalid_argument&) {}\n\n\treturn result;\n}\n\nstd::string GenerateRandomString(size_t length)\n{\n\tconst std::string kCharacters{\n\t\"abcdefghijklmnopqrstuvwxyz\"\n\t\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\t\"1234567890\" };\n\treturn GenerateRandomString(length, kCharacters);\n}\n\nstd::string GenerateRandomString(const size_t length, const std::string_view characters)\n{\n\tassert(!characters.empty());\n\tstd::string result;\n\tresult.resize(length);\n\n\tstd::random_device rd;\n\tstd::mt19937 gen(rd());\n     \n        // workaround for static asserts using boost\n        boost::random::uniform_int_distribution<decltype(characters.size())> index_dist(0, characters.size() - 1);\n\tstd::generate_n(\n\t\tresult.begin(),\n\t\tlength,\n\t\t[&] { return characters[index_dist(gen)]; }\n\t);\n\n\treturn result;\n}\n\nstd::optional<std::vector<uint8>> zlibDecompress(const std::vector<uint8>& compressed, size_t sizeHint)\n{\n\tint err;\n\tstd::vector<uint8> decompressed;\n\tsize_t outWritten = 0;\n\tsize_t bytesPerIteration = sizeHint;\n\tz_stream stream;\n\tstream.zalloc = Z_NULL;\n\tstream.zfree = Z_NULL;\n\tstream.opaque = Z_NULL;\n\tstream.avail_in = compressed.size();\n\tstream.next_in = (Bytef*)compressed.data();\n\terr = inflateInit2(&stream, 32); // 32 is a zlib magic value to enable header detection\n\tif (err != Z_OK)\n\t\treturn {};\n\n\tdo\n\t{\n\t\tdecompressed.resize(decompressed.size() + bytesPerIteration);\n\t\tconst auto availBefore = decompressed.size() - outWritten;\n\t\tstream.avail_out = availBefore;\n\t\tstream.next_out = decompressed.data() + outWritten;\n\t\terr = inflate(&stream, Z_NO_FLUSH);\n\t\tif (!(err == Z_OK || err == Z_STREAM_END))\n\t\t{\n\t\t\tinflateEnd(&stream);\n\t\t\treturn {};\n\t\t}\n\t\toutWritten += availBefore - stream.avail_out;\n\t\tbytesPerIteration *= 2;\n\t}\n\twhile (err != Z_STREAM_END);\n\n\tinflateEnd(&stream);\n\tdecompressed.resize(stream.total_out);\n\n\treturn decompressed;\n}\n"
  },
  {
    "path": "src/util/helpers/helpers.h",
    "content": "#pragma once\n\n#include <charconv>\n#include <filesystem>\n#include <string_view>\n#include <set>\n\n#include \"util/math/vector2.h\"\n#include \"util/math/vector3.h\"\n\n#ifdef __clang__\n#include \"Common/unix/fast_float.h\"\n#endif\n\ntemplate <typename TType>\nconstexpr auto to_underlying(TType v) noexcept\n{\n\treturn static_cast<std::underlying_type_t<TType>>(v);\n}\n\n// wrapper to allow reverse iteration with range-based loops before C++20\ntemplate<typename T>\nclass reverse_itr {\nprivate:\n\tT& iterable_;\npublic:\n\texplicit reverse_itr(T& iterable) : iterable_{ iterable } {}\n\tauto begin() const { return std::rbegin(iterable_); }\n\tauto end() const { return std::rend(iterable_); }\n};\n\n#ifndef M_PI\n#define M_PI       3.14159265358979323846\n#endif\n\ntemplate<typename T>\nT deg2rad(T v) { return v * static_cast<T>(M_PI) / static_cast<T>(180); }\ntemplate<typename T>\nT rad2deg(T v) { return v * static_cast<T>(180) / static_cast<T>(M_PI); }\n\ntemplate<typename T>\nVector3<T> deg2rad(const Vector3<T>& v) { return { deg2rad(v.x), deg2rad(v.y), deg2rad(v.z) }; }\ntemplate<typename T>\nVector3<T> rad2deg(const Vector3<T>& v) { return { rad2deg(v.x), rad2deg(v.y), rad2deg(v.z) }; }\n\ntemplate<typename T>\nVector2<T> deg2rad(const Vector2<T>& v) { return { deg2rad(v.x), deg2rad(v.y) }; }\ntemplate<typename T>\nVector2<T> rad2deg(const Vector2<T>& v) { return { rad2deg(v.x), rad2deg(v.y) }; }\n\nuint32_t GetPhysicalCoreCount();\n\n// Creates a temporary file to test for write access\nbool TestWriteAccess(const fs::path& p);\n\nfs::path MakeRelativePath(const fs::path& base, const fs::path& path);\n\n#ifdef HAS_DIRECTINPUT\nbool GUIDFromString(const char* string, GUID& guid);\nstd::string StringFromGUID(const GUID& guid);\nstd::wstring WStringFromGUID(const GUID& guid);\n#endif\n\nstd::vector<std::string_view> TokenizeView(std::string_view string, char delimiter);\nstd::vector<std::string> Tokenize(std::string_view string, char delimiter);\n\nstd::string ltrim_copy(const std::string& s);\nstd::string rtrim_copy(const std::string& s);\nstd::string& ltrim(std::string& str, const std::string& chars = \"\\t\\n\\v\\f\\r \");\nstd::string& rtrim(std::string& str, const std::string& chars = \"\\t\\n\\v\\f\\r \");\nstd::string& trim(std::string& str, const std::string& chars = \"\\t\\n\\v\\f\\r \");\n\nstd::string_view& ltrim(std::string_view& str, const std::string& chars = \"\\t\\n\\v\\f\\r \");\nstd::string_view& rtrim(std::string_view& str, const std::string& chars = \"\\t\\n\\v\\f\\r \");\nstd::string_view& trim(std::string_view& str, const std::string& chars = \"\\t\\n\\v\\f\\r \");\n\nstd::string GenerateRandomString(size_t length);\nstd::string GenerateRandomString(size_t length, std::string_view characters);\n\nstd::string GetSystemErrorMessage();\nstd::string GetSystemErrorMessage(DWORD error_code);\nstd::string GetSystemErrorMessage(const std::exception& ex);\nstd::string GetSystemErrorMessage(const std::error_code& ec);\n\ntemplate<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };\ntemplate<class... Ts> overloaded(Ts...)->overloaded<Ts...>;\n\ntemplate<typename T>\nbool equals(T v1, T v2)\n{\n\t/*\n\treturn std::fabs(x-y) <= std::numeric_limits<T>::epsilon() * std::fabs(x+y) * ulp\n        // unless the result is subnormal\n        || std::fabs(x-y) < std::numeric_limits<T>::min();\n\t */\n\tif constexpr (std::is_floating_point_v<T>)\n\t\treturn std::abs(v1 - v2) < (T)0.000001;\n\telse if constexpr (std::is_same_v<T, const char*>)\n\t\treturn strcmp(v1, v2) == 0;\n\telse\n\t\treturn v1 == v2;\n}\n\ntemplate<typename T>\nT ConvertString(std::string_view str, sint32 base)\n{\n\tif (str.empty())\n\t\treturn {};\n\t\n\tstatic_assert(std::is_integral_v<T>);\n\tT result;\n\tltrim(str);\n\n\t// from_chars cant deal with hex numbers starting with \"0x\"\n\tif (base == 16)\n\t{\n\t\tconst sint32 index = str[0] == '-' ? 1 : 0;\n\t\tif (str.size() >= 2 && str[index+0] == '0' && tolower(str[index+1]) == 'x')\n\t\t\tstr = str.substr(index + 2);\n\n\t\tif (std::from_chars(str.data(), str.data() + str.size(), result, base).ec == std::errc())\n\t\t{\n\t\t\tif (index == 1)\n\t\t\t{\n\t\t\t\tif constexpr(std::is_unsigned_v<T>)\n\t\t\t\t\tresult = static_cast<T>(-static_cast<std::make_signed_t<T>>(result));\n\t\t\t\telse\n\t\t\t\t\tresult = -result;\n\t\t\t}\t\n\t\t\t\n\t\t\treturn result;\n\t\t}\n\n\t\treturn {};\n\t}\n\t\n\tif(std::from_chars(str.data(), str.data() + str.size(), result, base).ec == std::errc())\n\t\treturn result;\n\n\treturn {};\n}\n\ntemplate<typename T>\nT ConvertString(std::string_view str)\n{\n\tif (str.empty())\n\t\treturn {};\n\t\n\tT result;\n\tltrim(str);\n\tif constexpr (std::is_same_v<T, bool>)\n\t{\n\t\treturn str == \"1\" || boost::iequals(str, \"true\");\n\t}\n\telse if constexpr(std::is_floating_point_v<T>)\n\t{\n\t\t// from_chars can't deal with float conversation starting with \"+\"\n\t\tltrim(str, \"+\");\n#ifdef __clang__\n\t\tif (fast_float::from_chars(str.data(), str.data() + str.size(), result).ec == std::errc())\n\t\t\treturn result;\n#else\n\t\tif (std::from_chars(str.data(), str.data() + str.size(), result).ec == std::errc())\n\t\t\treturn result;\n#endif\n\t\treturn {};\n\t}\n\telse if constexpr(std::is_enum_v<T>)\n\t{\n\t\treturn (T)ConvertString<std::underlying_type_t<T>>(str);\n\t}\n\telse\n\t{\n\t\tconst sint32 index = str[0] == '-' ? 1 : 0;\n\t\tif (str.size() >= 2 && str[index + 0] == '0' && tolower(str[index + 1]) == 'x')\n\t\t\tresult = ConvertString<T>(str, 16);\n\t\telse\n\t\t\tresult = ConvertString<T>(str, 10);\n\t}\n\n\treturn result;\n}\n\ntemplate <typename T>\nconstexpr T DegToRad(T deg) { return (T)((double)deg * M_PI / 180); }\ntemplate <typename T>\nconstexpr T RadToDeg(T rad) { return (T)((double)rad * 180 / M_PI); }\n\ntemplate<typename T>\nstd::string ToString(T value)\n{\n\tstd::ostringstream str;\n\tstr.imbue(std::locale(\"C\"));\n\tstr << value;\n\treturn str.str();\n}\n\ntemplate<typename T>\nT FromString(std::string value)\n{\n\tstd::istringstream str(value);\n\tstr.imbue(std::locale(\"C\"));\n\n\tT tmp;\n\tstr >> tmp;\n\treturn tmp;\n}\n\ntemplate<typename T>\nsize_t RemoveDuplicatesKeepOrder(std::vector<T>& vec)\n{\n\tstd::set<T> tmp;\n\tauto new_end = std::remove_if(vec.begin(), vec.end(), [&tmp](const T& value)\n\t\t{\n\t\t\tif (tmp.find(value) != std::end(tmp))\n\t\t\t\treturn true;\n\n\t\t\ttmp.insert(value);\n\t\t\treturn false;\n\t\t});\n\n\tvec.erase(new_end, vec.end());\n\treturn vec.size();\n}\n\nvoid SetThreadName(const char* name);\n\ninline uint64 MakeU64(uint32 high, uint32 low)\n{\n\treturn ((uint64)high << 32) | ((uint64)low);\n}\n\nstatic bool IsValidFilename(std::string_view sv)\n{\n\tfor (auto& it : sv)\n\t{\n\t\tuint8 c = (uint8)it;\n\t\tif (c < 0x20)\n\t\t\treturn false;\n\t\tif (c == '.' || c == '#' || c == '/' || c == '\\\\' ||\n\t\t\tc == '<' || c == '>' || c == '|' || c == ':' ||\n\t\t\tc == '\\\"')\n\t\t\treturn false;\n\t}\n\tif (!sv.empty())\n\t{\n\t\tif (sv.back() == ' ' || sv.back() == '.')\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\n// MAJOR; MINOR\nstd::pair<DWORD, DWORD> GetWindowsVersion();\nbool IsWindows81OrGreater();\nbool IsWindows10OrGreater();\n\nfs::path GetParentProcess();\n\nstd::optional<std::vector<uint8>> zlibDecompress(const std::vector<uint8>& compressed, size_t sizeHint = 32*1024);\n"
  },
  {
    "path": "src/util/helpers/ringbuffer.h",
    "content": "﻿#pragma once\n\n#include <mutex>\n\ntemplate<typename T, uint32 elements, typename P = uint32>\nclass RingBuffer\n{\npublic:\n\tRingBuffer();\n\n\tbool Push(const T& v);\n\n\tT Pop()\n\t\trequires (!std::is_array_v<T>)\n\t{\n\t\tstd::unique_lock<std::mutex> lock(m_mutex);\n\t\tif (m_readPointer == m_writePointer)\n\t\t{\n\t\t\treturn T();\n\t\t}\n\n\t\tconst T& tmp = m_data[m_readPointer];\n\t\tm_readPointer = (m_readPointer + 1) % elements;\n\t\treturn tmp;\n\t}\n\n\tT& GetSlot();\n\tT& GetSlotAndAdvance();\n\tvoid Advance();\n\n\tvoid Clear();\n\tP GetReadPointer();\n\tP GetWritePointer();\n\tbool HasData();\n\nprivate:\n\tT m_data[elements];\n\tP m_readPointer;\n\tP m_writePointer;\n\tstd::mutex m_mutex;\n};\n\ntemplate <typename T, uint32 elements, typename P>\nRingBuffer<T, elements, P>::RingBuffer()\n\t: m_readPointer(0), m_writePointer(0)\n{\n\t\n}\n\ntemplate <typename T, uint32 elements, typename P>\nbool RingBuffer<T, elements, P>::Push(const T& v)\n{\n\tstd::unique_lock<std::mutex> lock(m_mutex);\n\tif (m_readPointer == ((m_writePointer + 1) % elements))\n\t{\n\t\tdebugBreakpoint(); // buffer is full\n\t\treturn false;\n\t}\n\n\tm_data[m_writePointer] = v;\n\tm_writePointer = (m_writePointer + 1) % elements;\n\treturn true;\n}\n\ntemplate <typename T, uint32 elements, typename P>\nT& RingBuffer<T, elements, P>::GetSlot()\n{\n\tstd::unique_lock<std::mutex> lock(m_mutex);\n\tT& result = m_data[m_writePointer];\n\tm_writePointer = (m_writePointer + 1) % elements;\n\treturn result;\n}\n\ntemplate <typename T, uint32 elements, typename P>\nT& RingBuffer<T, elements, P>::GetSlotAndAdvance()\n{\n\tstd::unique_lock<std::mutex> lock(m_mutex);\n\tT& result = m_data[m_writePointer];\n\tm_writePointer = (m_writePointer + 1) % elements;\n\tm_readPointer = (m_readPointer + 1) % elements;\n\treturn result;\n}\n\ntemplate <typename T, uint32 elements, typename P>\nvoid RingBuffer<T, elements, P>::Advance()\n{\n\tstd::unique_lock<std::mutex> lock(m_mutex);\n\tif (m_readPointer != m_writePointer)\n\t{\n\t\tm_readPointer = (m_readPointer + 1) % elements;\n\t}\n}\n\ntemplate <typename T, uint32 elements, typename P>\nvoid RingBuffer<T, elements, P>::Clear()\n{\n\tstd::unique_lock<std::mutex> lock(m_mutex);\n\tm_readPointer = 0;\n\tm_writePointer = 0;\n}\n\ntemplate <typename T, uint32 elements, typename P>\nP RingBuffer<T, elements, P>::GetReadPointer()\n{\n\tstd::unique_lock<std::mutex> lock(m_mutex);\n\tP tmp = m_readPointer;\n\treturn tmp;\n}\n\ntemplate <typename T, uint32 elements, typename P>\nP RingBuffer<T, elements, P>::GetWritePointer()\n{\n\tstd::unique_lock<std::mutex> lock(m_mutex);\n\tP tmp = m_writePointer;\n\treturn tmp;\n}\n\ntemplate <typename T, uint32 elements, typename P>\nbool RingBuffer<T, elements, P>::HasData()\n{\n\tstd::unique_lock<std::mutex> lock(m_mutex);\n\treturn m_readPointer != m_writePointer;\n}\n"
  },
  {
    "path": "src/util/highresolutiontimer/HighResolutionTimer.cpp",
    "content": "#include \"util/highresolutiontimer/HighResolutionTimer.h\"\n#include \"Common/precompiled.h\"\n\nHighResolutionTimer HighResolutionTimer::now()\n{\n#if BOOST_OS_WINDOWS\n\tLARGE_INTEGER pc;\n\tQueryPerformanceCounter(&pc);\n\treturn HighResolutionTimer(pc.QuadPart);\n#elif BOOST_OS_LINUX\n    timespec pc;\n    clock_gettime(CLOCK_MONOTONIC_RAW, &pc);\n    uint64 nsec = (uint64)pc.tv_sec * (uint64)1000000000 + (uint64)pc.tv_nsec;\n    return HighResolutionTimer(nsec);\n#elif BOOST_OS_MACOS\n\treturn HighResolutionTimer(clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW));\n#elif BOOST_OS_BSD\n    timespec pc;\n    clock_gettime(CLOCK_MONOTONIC, &pc);\n    uint64 nsec = (uint64)pc.tv_sec * (uint64)1000000000 + (uint64)pc.tv_nsec;\n    return HighResolutionTimer(nsec);\n#endif\n}\n\nHRTick HighResolutionTimer::getFrequency()\n{\n\treturn m_freq;\n}\n\nuint64 HighResolutionTimer::m_freq = []() -> uint64 {\n#if BOOST_OS_WINDOWS\n\tLARGE_INTEGER freq;\n\tQueryPerformanceFrequency(&freq);\n\treturn (uint64)(freq.QuadPart);\n#elif BOOST_OS_MACOS\n\treturn 1000000000;\n#elif BOOST_OS_BSD\n\ttimespec pc;\n\tclock_getres(CLOCK_MONOTONIC, &pc);\n\treturn (uint64)1000000000 / (uint64)pc.tv_nsec;\n#else\n    timespec pc;\n    clock_getres(CLOCK_MONOTONIC_RAW, &pc);\n    return (uint64)1000000000 / (uint64)pc.tv_nsec;\n#endif\n}();\n"
  },
  {
    "path": "src/util/highresolutiontimer/HighResolutionTimer.h",
    "content": "#pragma once\n\nusing HRTick = uint64;\n\nclass HighResolutionTimer\n{\npublic:\n\tHighResolutionTimer()\n\t{\n\t\tm_timePoint = 0;\n\t}\n\n\tHRTick getTick() const\n\t{\n\t\treturn m_timePoint;\n\t}\n\n\tuint64 getTickInSeconds() const\n\t{\n\t\treturn m_timePoint / m_freq;\n\t}\n\n\t// return time difference in seconds, this is an utility function mainly intended for debugging/benchmarking purposes. Avoid using doubles for precise timing\n\tstatic double getTimeDiff(HRTick startTime, HRTick endTime)\n\t{\n\t\treturn (double)(endTime - startTime) / (double)m_freq;\n\t}\n\n\t// returns tick difference and frequency\n\tstatic uint64 getTimeDiffEx(HRTick startTime, HRTick endTime, uint64& freq)\n\t{\n\t\tfreq = m_freq;\n\t\treturn endTime - startTime;\n\t}\n\n\tstatic HighResolutionTimer now();\n\tstatic HRTick getFrequency();\n\n\tstatic HRTick microsecondsToTicks(uint64 microseconds)\n\t{\n\t\treturn microseconds * m_freq / 1000000;\n\t}\n\n\tstatic uint64 ticksToMicroseconds(HRTick ticks)\n\t{\n\t\treturn ticks * 1000000 / m_freq;\n\t}\n\nprivate:\n\tHighResolutionTimer(uint64 timePoint) : m_timePoint(timePoint) {};\n\n\tuint64 m_timePoint;\n\tstatic uint64 m_freq;\n};\n\n// benchmark helper utility\n// measures time between Start() and Stop() call\nclass BenchmarkTimer\n{\npublic:\n\tvoid Start()\n\t{\n\t\tm_startTime = HighResolutionTimer::now().getTick();\n\t}\n\n\tvoid Stop()\n\t{\n\t\tm_stopTime = HighResolutionTimer::now().getTick();\n\t}\n\n\tdouble GetElapsedMilliseconds() const\n\t{\n\t\tcemu_assert_debug(m_startTime != 0 && m_stopTime != 0);\n\t\tcemu_assert_debug(m_startTime <= m_stopTime);\n\t\tuint64 tickDif = m_stopTime - m_startTime;\n\t\tdouble freq = (double)HighResolutionTimer::now().getFrequency();\n\t\tdouble elapsedMS = (double)tickDif * 1000.0 / freq;\n\t\treturn elapsedMS;\n\t}\n\nprivate:\n\tHRTick m_startTime{};\n\tHRTick m_stopTime{};\n};\n\n"
  },
  {
    "path": "src/util/libusbWrapper/libusbWrapper.cpp",
    "content": "#include \"libusbWrapper.h\"\n\n/*\n\n#include \"config/ActiveSettings.h\"\n\nlibusbWrapper::libusbWrapper()\n{\n}\n\nvoid libusbWrapper::init()\n{\n#if BOOST_OS_WINDOWS\n    if (m_isInitialized)\n\t\treturn;\n\tm_isInitialized = true;\n\t// load module\n\tm_module = LoadLibraryW(L\"libusb-1.0.dll\");\n\tif (!m_module)\n\t{\n\t\tconst auto path = ActiveSettings::GetDataPath(\"resources/libusb-1.0.dll\");\n\t\tm_module = LoadLibraryW(path.generic_wstring().c_str());\n\t\tif (!m_module)\n\t\t{\n\t\t\tcemuLog_log(LogType::Force, \"libusbWrapper: can't load libusb-1.0.dll\");\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// grab imports\n#define FETCH_IMPORT(__NAME__) p_##__NAME__ = (decltype(&__NAME__))GetProcAddress(m_module, #__NAME__)\n\tFETCH_IMPORT(libusb_init);\n\tFETCH_IMPORT(libusb_exit);\n\tFETCH_IMPORT(libusb_interrupt_transfer);\n\tFETCH_IMPORT(libusb_get_device_list);\n\tFETCH_IMPORT(libusb_get_device_descriptor);\n\tFETCH_IMPORT(libusb_open);\n\tFETCH_IMPORT(libusb_close);\n\tFETCH_IMPORT(libusb_kernel_driver_active);\n\tFETCH_IMPORT(libusb_detach_kernel_driver);\n\tFETCH_IMPORT(libusb_claim_interface);\n\tFETCH_IMPORT(libusb_free_device_list);\n\tFETCH_IMPORT(libusb_get_config_descriptor);\n\tFETCH_IMPORT(libusb_hotplug_register_callback);\n\tFETCH_IMPORT(libusb_hotplug_deregister_callback);\n\tFETCH_IMPORT(libusb_has_capability);\n\tFETCH_IMPORT(libusb_error_name);\n\tFETCH_IMPORT(libusb_get_string_descriptor);\n\tFETCH_IMPORT(libusb_get_string_descriptor_ascii);\n\tFETCH_IMPORT(libusb_free_config_descriptor);\n#undef FETCH_IMPORT\n\n\t// create default context\n\tif (p_libusb_init)\n\t\tp_libusb_init(nullptr);\n#else\n\tcemuLog_log(LogType::Force, \"libusbWrapper: Not supported on this OS\");\n#endif\n}\n\nlibusbWrapper::~libusbWrapper()\n{\n#if BOOST_OS_WINDOWS\n\t// destroy default context\n\tif(p_libusb_exit)\n\t\tp_libusb_exit(nullptr);\n\n\t// unload module\n\tif(m_module)\n\t\tFreeLibrary(m_module);\n#endif\n}\n\n*/"
  },
  {
    "path": "src/util/libusbWrapper/libusbWrapper.h",
    "content": "#pragma once\n\n// todo - port to cmake build\n\n/*\n\n#include \"util/helpers/ClassWrapper.h\"\n\n#pragma warning(disable:4200)\n#include \"libusb-1.0/libusb.h\"\n#pragma warning(default:4200)\n\nclass libusbWrapper : public SingletonRef<libusbWrapper>\n{\npublic:\n\tlibusbWrapper();\n\t~libusbWrapper();\n\n\tvoid init();\n\tbool isAvailable() const { return p_libusb_init != nullptr; };\n\t\n\tdecltype(&libusb_init) p_libusb_init = nullptr;\n\tdecltype(&libusb_exit) p_libusb_exit = nullptr;\n\tdecltype(&libusb_interrupt_transfer) p_libusb_interrupt_transfer;\n\tdecltype(&libusb_get_device_list) p_libusb_get_device_list;\n\tdecltype(&libusb_get_device_descriptor) p_libusb_get_device_descriptor;\n\tdecltype(&libusb_open) p_libusb_open;\n\tdecltype(&libusb_kernel_driver_active) p_libusb_kernel_driver_active;\n\tdecltype(&libusb_detach_kernel_driver) p_libusb_detach_kernel_driver;\n\tdecltype(&libusb_claim_interface) p_libusb_claim_interface;\n\tdecltype(&libusb_free_device_list) p_libusb_free_device_list;\n\tdecltype(&libusb_get_config_descriptor) p_libusb_get_config_descriptor;\n\tdecltype(&libusb_free_config_descriptor) p_libusb_free_config_descriptor;\n\tdecltype(&libusb_close) p_libusb_close;\n\tdecltype(&libusb_hotplug_register_callback) p_libusb_hotplug_register_callback;\n\tdecltype(&libusb_hotplug_deregister_callback) p_libusb_hotplug_deregister_callback;\n\tdecltype(&libusb_has_capability) p_libusb_has_capability;\n\tdecltype(&libusb_error_name) p_libusb_error_name;\n\tdecltype(&libusb_get_string_descriptor) p_libusb_get_string_descriptor;\n\tdecltype(&libusb_get_string_descriptor_ascii) p_libusb_get_string_descriptor_ascii;\n\t\n\t\nprivate:\n#if BOOST_OS_WINDOWS\n\tHMODULE m_module = nullptr;\n\tbool m_isInitialized = false;\n#endif\n};\n\n*/"
  },
  {
    "path": "src/util/math/glm.h",
    "content": "#pragma once\n\nnamespace glm\n{\n\tinline quat normalize_xyz(const quat& q)\n\t{\n\t\tconst auto xyzTargetLength = std::sqrt(1.0f - q.w * q.w);\n\t\tconst auto lengthScaler = xyzTargetLength / sqrtf(q.x * q.x + q.y * q.y + q.z * q.z);\n\t\treturn quat(q.w, q.x * lengthScaler, q.y * lengthScaler, q.z * lengthScaler);\n\t}\n\n\tinline vec3 GetVectorX(const quat& q)\n\t{\n\t\treturn vec3(\n\t\t\t2.0f * (q.w * q.w + q.x * q.x) - 1.0f,\n\t\t\t2.0f * (q.x * q.y - q.w * q.z),\n\t\t\t2.0f * (q.x * q.z + q.w * q.y));\n\t}\n\n\tinline vec3 GetVectorY(const quat& q)\n\t{\n\t\treturn vec3(\n\t\t\t2.0f * (q.x * q.y + q.w * q.z),\n\t\t\t2.0f * (q.w * q.w + q.y * q.y) - 1.0f,\n\t\t\t2.0f * (q.y * q.z - q.w * q.x)\n\t\t);\n\t}\n\n\tinline vec3 GetVectorZ(const quat& q)\n\t{\n\t\treturn vec3 (\n\t\t\t2.0f * (q.x * q.z - q.w * q.y),\n\t\t\t2.0f * (q.y * q.z + q.w * q.x),\n\t\t\t2.0f * (q.w * q.w + q.z * q.z) - 1.0f);\n\t}\n}\n"
  },
  {
    "path": "src/util/math/quaternion.h",
    "content": "#pragma once\n\n#include <tuple>\n#include \"util/helpers/helpers.h\"\n#include \"util/math/vector3.h\"\n#define DEG2RAD(__d__) ((__d__ * M_PI) / 180.0f )\n#define RAD2DEG(__r__) ((__r__ * 180.0f) / M_PI)\n\n\ntemplate<typename T> \nclass Quaternion\n{\npublic:\n\tT w;\n\tT x;\n\tT y;\n\tT z;\n\n\tQuaternion();\n\tQuaternion(const T& w, const T& x, const T& y, const T& z);\n\tQuaternion(float x, float y, float z);\n\n\tvoid Assign(float w, float x, float y, float z)\n\t{\n\t\tthis->w = w;\n\t\tthis->x = x;\n\t\tthis->y = y;\n\t\tthis->z = z;\n\t}\n\n\tstatic Quaternion FromAngleAxis(float inAngle, float inX, float inY, float inZ);\n\n\tstd::tuple<Vector3<T>, Vector3<T>, Vector3<T>> GetRotationMatrix();\n\tstd::tuple<Vector3<T>, Vector3<T>, Vector3<T>> GetTransposedRotationMatrix();\n\n\t// normalize but keep W\n\tvoid NormalizeXYZ()\n\t{\n\t\tconst T xyzTargetLength = sqrtf((T)1.0 - w * w);\n\t\tconst T lengthScaler = xyzTargetLength / sqrtf(x * x + y * y + z * z);\n\t\tx *= lengthScaler;\n\t\ty *= lengthScaler;\n\t\tz *= lengthScaler;\n\t}\n\n\tvoid NormalizeXYZW()\n\t{\n\t\tconst T lengthScaler = 1.0f / sqrtf(w * w + x * x + y * y + z * z);\n\t\tw *= lengthScaler;\n\t\tx *= lengthScaler;\n\t\ty *= lengthScaler;\n\t\tz *= lengthScaler;\n\t}\n\n\tVector3<T> GetVectorX() const\n\t{\n\t\treturn Vector3<T>(\n\t\t\t2.0f * (w * w + x * x) - 1.0f,\n\t\t\t2.0f * (x * y - w * z),\n\t\t\t2.0f * (x * z + w * y));\n\t}\n\n\tVector3<T> GetVectorY() const\n\t{\n\t\treturn Vector3<T>(\n\t\t\t2.0f * (x * y + w * z),\n\t\t\t2.0f * (w * w + y * y) - 1.0f,\n\t\t\t2.0f * (y * z - w * x)\n\t\t\t);\n\t}\n\n\tVector3<T> GetVectorZ() const\n\t{\n\t\treturn Vector3<T>(\n\t\t\t2.0f * (x * z - w * y),\n\t\t\t2.0f * (y * z + w * x),\n\t\t\t2.0f * (w * w + z * z) - 1.0f);\n\t}\n\n\tQuaternion& operator*=(const Quaternion<T>& rhs)\n\t{\n\t\tAssign(w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z,\n\t\t\tw * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y,\n\t\t\tw * rhs.y - x * rhs.z + y * rhs.w + z * rhs.x,\n\t\t\tw * rhs.z + x * rhs.y - y * rhs.x + z * rhs.w);\n\t\treturn *this;\n\t}\n\n\tQuaternion& operator+=(const Quaternion<T>& rhs)\n\t{\n\t\tw += rhs.w;\n\t\tx += rhs.x;\n\t\ty += rhs.y;\n\t\tz += rhs.z;\n\t\treturn *this;\n\t}\n\n\tfriend Quaternion operator*(Quaternion<T> lhs, const Quaternion<T>& rhs)\n\t{\n\t\tlhs *= rhs;\n\t\treturn lhs;\n\t}\n\n};\n\ntemplate <typename T>\nQuaternion<T>::Quaternion() \n\t: w(), x(), y(), z()\n{}\n\ntemplate <typename T>\nQuaternion<T>::Quaternion(const T& w, const T& x, const T& y, const T& z)\n\t: w(w), x(x), y(y), z(z)\n{}\n\ntemplate <typename T>\nQuaternion<T>::Quaternion(float x, float y, float z)\n{\n\tfloat pitch = DEG2RAD(x);\n\tfloat yaw = DEG2RAD(y);\n\tfloat roll = DEG2RAD(z);\n\n\tfloat cyaw = cos(0.5f * yaw);\n\tfloat cpitch = cos(0.5f * pitch);\n\tfloat croll = cos(0.5f * roll);\n\tfloat syaw = sin(0.5f * yaw);\n\tfloat spitch = sin(0.5f * pitch);\n\tfloat sroll = sin(0.5f * roll);\n\n\tfloat cyawcpitch = cyaw * cpitch;\n\tfloat syawspitch = syaw * spitch;\n\tfloat cyawspitch = cyaw * spitch;\n\tfloat syawcpitch = syaw * cpitch;\n\n\tthis->w = cyawcpitch * croll + syawspitch * sroll;\n\tthis->x = cyawspitch * croll + syawcpitch * sroll;\n\tthis->y = syawcpitch * croll - cyawspitch * sroll;\n\tthis->z = cyawcpitch * sroll - syawspitch * croll;\n}\n\ntemplate<typename T>\nQuaternion<T> Quaternion<T>::FromAngleAxis(float inAngle, float inX, float inY, float inZ)\n{\n\tQuaternion<T> result = Quaternion<T>(cosf(inAngle * 0.5f), inX, inY, inZ);\n\tresult.NormalizeXYZ();\n\treturn result;\n}\n\ntemplate <typename T>\nstd::tuple<Vector3<T>, Vector3<T>, Vector3<T>> Quaternion<T>::GetRotationMatrix()\n{\n\tfloat sqw = w*w;\n\tfloat sqx = x*x;\n\tfloat sqy = y*y;\n\tfloat sqz = z*z;\n\n\t// invs (inverse square length) is only required if quaternion is not already normalised\n\tfloat invs = 1.0f / (sqx + sqy + sqz + sqw);\n\t\n\tVector3<T> v1, v2, v3;\n\tv1.x = (sqx - sqy - sqz + sqw) * invs; // since sqw + sqx + sqy + sqz =1/invs*invs\n\tv2.y = (-sqx + sqy - sqz + sqw) * invs;\n\tv3.z = (-sqx - sqy + sqz + sqw) * invs;\n\n\tfloat tmp1 = x*y;\n\tfloat tmp2 = z*w;\n\tv2.x = 2.0 * (tmp1 + tmp2)*invs;\n\tv1.y = 2.0 * (tmp1 - tmp2)*invs;\n\n\ttmp1 = x*z;\n\ttmp2 = y*w;\n\tv3.x = 2.0 * (tmp1 - tmp2)*invs;\n\tv1.z = 2.0 * (tmp1 + tmp2)*invs;\n\n\ttmp1 = y*z;\n\ttmp2 = x*w;\n\tv3.y = 2.0 * (tmp1 + tmp2)*invs;\n\tv2.z = 2.0 * (tmp1 - tmp2)*invs;\n\n\treturn std::make_tuple(v1, v2, v3);\n}\n\ntemplate <typename T>\nstd::tuple<Vector3<T>, Vector3<T>, Vector3<T>> Quaternion<T>::GetTransposedRotationMatrix()\n{\n\tfloat sqw = w*w;\n\tfloat sqx = x*x;\n\tfloat sqy = y*y;\n\tfloat sqz = z*z;\n\n\t// invs (inverse square length) is only required if quaternion is not already normalised\n\tfloat invs = 1.0f / (sqx + sqy + sqz + sqw);\n\n\tVector3<T> v1, v2, v3;\n\tv1.x = (sqx - sqy - sqz + sqw) * invs; // since sqw + sqx + sqy + sqz =1/invs*invs\n\tv2.y = (-sqx + sqy - sqz + sqw) * invs;\n\tv3.z = (-sqx - sqy + sqz + sqw) * invs;\n\n\tfloat tmp1 = x*y;\n\tfloat tmp2 = z*w;\n\tv1.y = 2.0 * (tmp1 + tmp2)*invs;\n\tv2.x = 2.0 * (tmp1 - tmp2)*invs;\n\n\ttmp1 = x*z;\n\ttmp2 = y*w;\n\tv1.z = 2.0 * (tmp1 - tmp2)*invs;\n\tv3.x = 2.0 * (tmp1 + tmp2)*invs;\n\n\ttmp1 = y*z;\n\ttmp2 = x*w;\n\tv2.z = 2.0 * (tmp1 + tmp2)*invs;\n\tv3.y = 2.0 * (tmp1 - tmp2)*invs;\n\n\treturn std::make_tuple(v1, v2, v3);\n}\n\nusing Quaternionf = Quaternion<float>;"
  },
  {
    "path": "src/util/math/vector2.h",
    "content": "#pragma once\n#include <cassert>\n\ntemplate <typename T>\nclass Vector2\n{\npublic:\n\tT x;\n\tT y;\n\n\tVector2()\n\t\t: x{}, y{} {}\n\n\tVector2(T x, T y)\n\t\t: x(x), y(y) {}\n\n\ttemplate <typename U = T>\n\tVector2(const Vector2<U>& v)\n\t\t: x((T)v.x), y((T)v.y) {}\n\n\tfloat Length() const\n\t{\n\t\treturn (float)std::sqrt((x * x) + (y * y));\n\t}\n\n\tfloat Cross(const Vector2& v) const\n\t{\n\t\treturn x * v.y - y * v.x;\n\t}\n\n\tfloat Dot(const Vector2& v) const\n\t{\n\t\treturn x * v.x + y * v.y;\n\t}\n\n\tVector2 Ortho() const\n\t{\n\t\treturn Vector2(y, -x);\n\t}\n\n\tVector2 Normalized() const\n\t{\n\t\tconst auto len = Length();\n\t\tif (len == 0)\n\t\t\treturn Vector2<T>();\n\n\t\treturn Vector2<T>((T)((float)x / len), (T)((float)y / len));\n\t}\n\n\tVector2& Normalize()\n\t{\n\t\tconst auto len = Length();\n\t\tif (len != 0)\n\t\t{\n\t\t\tx = (T)((float)x / len);\n\t\t\ty = (T)((float)y / len);\n\t\t}\n\n\t\treturn *this;\n\t}\n\n\tstatic Vector2 Max(const Vector2& v1, const Vector2& v2)\n\t{\n\t\treturn Vector2(std::max(v1.x, v2.x), std::max(v1.y, v2.y));\n\t}\n\n\tstatic Vector2 Min(const Vector2& v1, const Vector2& v2)\n\t{\n\t\treturn Vector2(std::min(v1.x, v2.x), std::min(v1.y, v2.y));\n\t}\n\n\tbool operator==(const Vector2& v) const\n\t{\n\t\treturn x == v.x && y == v.y;\n\t}\n\tbool operator!=(const Vector2& v) const\n\t{\n\t\treturn !(*this == v);\n\t}\n\n\tVector2& operator+=(const Vector2& v)\n\t{\n\t\tx += v.x;\n\t\ty += v.y;\n\t\treturn *this;\n\t}\n\tVector2& operator-=(const Vector2& v)\n\t{\n\t\tx -= v.x;\n\t\ty -= v.y;\n\t\treturn *this;\n\t}\n\n\tVector2 operator+(const Vector2& v) const\n\t{\n\t\treturn Vector2(x + v.x, y + v.y);\n\t}\n\tVector2 operator-(const Vector2& v) const\n\t{\n\t\treturn Vector2(x - v.x, y - v.y);\n\t}\n\n\tVector2& operator+=(const T& v)\n\t{\n\t\tx += v;\n\t\ty += v;\n\t\treturn *this;\n\t}\n\tVector2& operator-=(const T& v)\n\t{\n\t\tx -= v;\n\t\ty -= v;\n\t\treturn *this;\n\t}\n\tVector2& operator*=(const T& v)\n\t{\n\t\tx *= v;\n\t\ty *= v;\n\t\treturn *this;\n\t}\n\tVector2& operator/=(const T& v)\n\t{\n\t\tassert(v != 0);\n\t\tx /= v;\n\t\ty /= v;\n\t\treturn *this;\n\t}\n\n\tVector2 operator+(const T& v)\n\t{\n\t\treturn Vector2(x + v, y + v);\n\t}\n\tVector2 operator-(const T& v)\n\t{\n\t\treturn Vector2(x - v, y - v);\n\t}\n\tVector2 operator*(const T& v)\n\t{\n\t\treturn Vector2(x * v, y * v);\n\t}\n\tVector2 operator/(const T& v)\n\t{\n\t\tassert(v != 0);\n\t\treturn Vector2(x / v, y / v);\n\t}\n};\n\nusing Vector2f = Vector2<float>;\nusing Vector2i = Vector2<int>;\n\n"
  },
  {
    "path": "src/util/math/vector3.h",
    "content": "#pragma once\n#include <cassert>\n\ntemplate <typename T>\nclass Vector3 {\npublic:\n\tT x;\n\tT y;\n\tT z;\n\n\tVector3() : x{}, y{}, z{} {}\n\tVector3(T x, T y, T z) : x(x), y(y), z(z) {}\n\n\ttemplate <typename U=T>\n\tVector3(const Vector3<U>& v)\n\t\t: x((T)v.x), y((T)v.y), z((T)v.z) {}\n\n\tfloat Length() const\n\t{\n\t\treturn std::sqrt((x * x) + (y * y) + (z * z));\n\t}\n\n\tfloat Dot(const Vector3& v) const\n\t{\n\t\treturn x * v.x + y * v.y + z * v.z;\n\t}\n\n\tVector3 Cross(const Vector3& v) const\n\t{\n\t\treturn Vector3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);\n\t}\n\n\tVector3 Normalized() const\n\t{\n\t\tconst auto len = Length();\n\t\tif (len == 0)\n\t\t\treturn {};\n\n\t\treturn *this / len;\n\t}\n\n\tVector3& Normalize()\n\t{\n\t\tconst auto len = Length();\n\t\tif (len != 0) \n\t\t\t*this /= len;\n\n\t\treturn *this;\n\t}\n\n\t//Vector3& Scale(const Vector3& v)\n\t//{\n\t//\t*this *= v;\n\t//\treturn *this;\n\t//}\n\n\tvoid Scale(const float s)\n\t{\n\t\tthis->x *= s;\n\t\tthis->y *= s;\n\t\tthis->z *= s;\n\t}\n\n\tVector3& RotateX(float theta);\n\tVector3& RotateY(float theta);\n\tVector3& RotateZ(float theta);\n\n\n\tbool operator==(const Vector3& v)\n\t{\n\t\treturn x == v.x && y == v.y && z == v.z;\n\t}\n\n\tbool operator!=(const Vector3& v)\n\t{\n\t\treturn !(*this == v);\n\t}\n\n\ttemplate <typename U = T>\n\tVector3& operator+=(const Vector3<U>& v)\n\t{\n\t\tx += (T)v.x;\n\t\ty += (T)v.y;\n\t\tz += (T)v.z;\n\t\treturn *this;\n\t}\n\n\ttemplate <typename U = T>\n\tVector3& operator-=(const Vector3<U>& v)\n\t{\n\t\tx -= (T)v.x;\n\t\ty -= (T)v.y;\n\t\tz -= (T)v.z;\n\t\treturn *this;\n\t}\n\n\ttemplate <typename U = T>\n\tVector3& operator*=(const Vector3<U>& v)\n\t{\n\t\tx *= (T)v.x;\n\t\ty *= (T)v.y;\n\t\tz *= (T)v.z;\n\t\treturn *this;\n\t}\n\n\ttemplate <typename U = T>\n\tVector3& operator/=(const Vector3<U>& v)\n\t{\n\t\tassert(v.x != 0 && v.y != 0 && v.z != 0);\n\t\tx /= (T)v.x;\n\t\ty /= (T)v.y;\n\t\tz /= (T)v.z;\n\t\treturn *this;\n\t}\n\n\ttemplate <typename U = T>\n\tVector3 operator+(const Vector3<U>& v) const\n\t{\n\t\treturn Vector3(x + (T)v.x, y + (T)v.y, z + (T)v.z);\n\t}\n\n\ttemplate <typename U = T>\n\tVector3 operator-(const Vector3<U>& v) const\n\t{\n\t\treturn Vector3(x - (T)v.x, y - (T)v.y, z - (T)v.z);\n\t}\n\n\ttemplate <typename U = T>\n\tVector3 operator*(const Vector3<U>& v) const\n\t{\n\t\treturn Vector3(x * (T)v.x, y * (T)v.y, z * (T)v.z);\n\t}\n\n\ttemplate <typename U = T>\n\tVector3 operator/(const Vector3<U>& v) const\n\t{\n\t\tassert(v.x != 0 && v.y != 0 && v.z != 0);\n\t\treturn Vector3(x / (T)v.x, y / (T)v.y, z / (T)v.z);\n\t}\n\n\tVector3& operator+=(T v)\n\t{\n\t\tx += v;\n\t\ty += v;\n\t\tz += v;\n\t\treturn *this;\n\t}\n\tVector3& operator-=(T v)\n\t{\n\t\tx -= v;\n\t\ty -= v;\n\t\tz -= v;\n\t\treturn *this;\n\t}\n\tVector3& operator*=(T v)\n\t{\n\t\tx *= v;\n\t\ty *= v;\n\t\tz *= v;\n\t\treturn *this;\n\t}\n\tVector3& operator/=(T v)\n\t{\n\t\tassert(v != 0);\n\t\tx /= v;\n\t\ty /= v;\n\t\tz /= v;\n\t\treturn *this;\n\t}\n\n\tVector3 operator+(T v) const\n\t{\n\t\treturn Vector3(x + v, y + v, z + v);\n\t}\n\tVector3 operator-(T v) const\n\t{\n\t\treturn Vector3(x - v, y - v, z - v);\n\t}\n\tVector3 operator*(T v) const\n\t{\n\t\treturn Vector3(x * v, y * v, z * v);\n\t}\n\tVector3 operator/(T v) const\n\t{\n\t\tassert(v != 0);\n\t\treturn Vector3(x / (T)v, y / (T)v, z / (T)v);\n\t}\n\n\tbool IsZero() const\n\t{\n\t\treturn x == 0 && y == 0 && z == 0;\n\t}\n\tbool HasZero() const\n\t{\n\t\treturn x == 0 || y == 0 || z == 0;\n\t}\n};\n\n\n\ntemplate <typename T>\nVector3<T>& Vector3<T>::RotateX(float theta)\n{\n\tconst float sin = std::sin(theta);\n\tconst float cos = std::cos(theta);\n\ty = y * cos - z * sin;\n\tz = y * sin + z * cos;\n\treturn *this;\n}\n\ntemplate <typename T>\nVector3<T>& Vector3<T>::RotateY(float theta)\n{\n\tconst float sin = std::sin(theta);\n\tconst float cos = std::cos(theta);\n\tx = x * cos + z * sin;\n\tz = -x * sin + z * cos;\n\treturn *this;\n}\n\ntemplate <typename T>\nVector3<T>& Vector3<T>::RotateZ(float theta)\n{\n\tconst float sin = std::sin(theta);\n\tconst float cos = std::cos(theta);\n\tx = x * cos - y * sin;\n\ty = x * sin + y * cos;\n\treturn *this;\n}\n\n\nusing Vector3f = Vector3<float>;\nusing Vector3i = Vector3<int>;\n"
  },
  {
    "path": "src/util/tinyxml2/tinyxml2.cpp",
    "content": "/*\nOriginal code by Lee Thomason (www.grinninglizard.com)\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any\ndamages arising from the use of this software.\n\nPermission is granted to anyone to use this software for any\npurpose, including commercial applications, and to alter it and\nredistribute it freely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must\nnot claim that you wrote the original software. If you use this\nsoftware in a product, an acknowledgment in the product documentation\nwould be appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and\nmust not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source\ndistribution.\n*/\n\n#include \"tinyxml2.h\"\n\n#include <new>\t\t// yes, this one new style header, is in the Android SDK.\n#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)\n#   include <stddef.h>\n#   include <stdarg.h>\n#else\n#   include <cstddef>\n#   include <cstdarg>\n#endif\n\n#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)\n// Microsoft Visual Studio, version 2005 and higher. Not WinCE.\n/*int _snprintf_s(\nchar *buffer,\nsize_t sizeOfBuffer,\nsize_t count,\nconst char *format [,\nargument] ...\n);*/\nstatic inline int TIXML_SNPRINTF(char* buffer, size_t size, const char* format, ...)\n{\n\tva_list va;\n\tva_start(va, format);\n\tint result = vsnprintf_s(buffer, size, _TRUNCATE, format, va);\n\tva_end(va);\n\treturn result;\n}\n\nstatic inline int TIXML_VSNPRINTF(char* buffer, size_t size, const char* format, va_list va)\n{\n\tint result = vsnprintf_s(buffer, size, _TRUNCATE, format, va);\n\treturn result;\n}\n\n#define TIXML_VSCPRINTF\t_vscprintf\n#define TIXML_SSCANF\tsscanf_s\n#elif defined _MSC_VER\n// Microsoft Visual Studio 2003 and earlier or WinCE\n#define TIXML_SNPRINTF\t_snprintf\n#define TIXML_VSNPRINTF _vsnprintf\n#define TIXML_SSCANF\tsscanf\n#if (_MSC_VER < 1400 ) && (!defined WINCE)\n// Microsoft Visual Studio 2003 and not WinCE.\n#define TIXML_VSCPRINTF   _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.\n#else\n// Microsoft Visual Studio 2003 and earlier or WinCE.\nstatic inline int TIXML_VSCPRINTF(const char* format, va_list va)\n{\n\tint len = 512;\n\tfor (;;) {\n\t\tlen = len * 2;\n\t\tchar* str = new char[len]();\n\t\tconst int required = _vsnprintf(str, len, format, va);\n\t\tdelete[] str;\n\t\tif (required != -1) {\n\t\t\tTIXMLASSERT(required >= 0);\n\t\t\tlen = required;\n\t\t\tbreak;\n\t\t}\n\t}\n\tTIXMLASSERT(len >= 0);\n\treturn len;\n}\n#endif\n#else\n// GCC version 3 and higher\n//#warning( \"Using sn* functions.\" )\n#define TIXML_SNPRINTF\tsnprintf\n#define TIXML_VSNPRINTF\tvsnprintf\nstatic inline int TIXML_VSCPRINTF(const char* format, va_list va)\n{\n\tint len = vsnprintf(0, 0, format, va);\n\tTIXMLASSERT(len >= 0);\n\treturn len;\n}\n#define TIXML_SSCANF   sscanf\n#endif\n\n\nstatic const char LINE_FEED = (char)0x0a;\t\t\t// all line endings are normalized to LF\nstatic const char LF = LINE_FEED;\nstatic const char CARRIAGE_RETURN = (char)0x0d;\t\t\t// CR gets filtered out\nstatic const char CR = CARRIAGE_RETURN;\nstatic const char SINGLE_QUOTE = '\\'';\nstatic const char DOUBLE_QUOTE = '\\\"';\n\n// Bunch of unicode info at:\n//\t\thttp://www.unicode.org/faq/utf_bom.html\n//\tef bb bf (Microsoft \"lead bytes\") - designates UTF-8\n\nstatic const unsigned char TIXML_UTF_LEAD_0 = 0xefU;\nstatic const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;\nstatic const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;\n\nnamespace tinyxml2\n{\n\n\tstruct Entity {\n\t\tconst char* pattern;\n\t\tint length;\n\t\tchar value;\n\t};\n\n\tstatic const int NUM_ENTITIES = 5;\n\tstatic const Entity entities[NUM_ENTITIES] = {\n\t\t{ \"quot\", 4,\tDOUBLE_QUOTE },\n\t\t{ \"amp\", 3,\t\t'&' },\n\t\t{ \"apos\", 4,\tSINGLE_QUOTE },\n\t\t{ \"lt\",\t2, \t\t'<' },\n\t\t{ \"gt\",\t2,\t\t'>' }\n\t};\n\n\n\tStrPair::~StrPair()\n\t{\n\t\tReset();\n\t}\n\n\n\tvoid StrPair::TransferTo(StrPair* other)\n\t{\n\t\tif (this == other) {\n\t\t\treturn;\n\t\t}\n\t\t// This in effect implements the assignment operator by \"moving\"\n\t\t// ownership (as in auto_ptr).\n\n\t\tTIXMLASSERT(other != 0);\n\t\tTIXMLASSERT(other->_flags == 0);\n\t\tTIXMLASSERT(other->_start == 0);\n\t\tTIXMLASSERT(other->_end == 0);\n\n\t\tother->Reset();\n\n\t\tother->_flags = _flags;\n\t\tother->_start = _start;\n\t\tother->_end = _end;\n\n\t\t_flags = 0;\n\t\t_start = 0;\n\t\t_end = 0;\n\t}\n\n\tvoid StrPair::Reset()\n\t{\n\t\tif (_flags & NEEDS_DELETE) {\n\t\t\tdelete[] _start;\n\t\t}\n\t\t_flags = 0;\n\t\t_start = 0;\n\t\t_end = 0;\n\t}\n\n\n\tvoid StrPair::SetStr(const char* str, int flags)\n\t{\n\t\tTIXMLASSERT(str);\n\t\tReset();\n\t\tsize_t len = strlen(str);\n\t\tTIXMLASSERT(_start == 0);\n\t\t_start = new char[len + 1];\n\t\tmemcpy(_start, str, len + 1);\n\t\t_end = _start + len;\n\t\t_flags = flags | NEEDS_DELETE;\n\t}\n\n\n\tchar* StrPair::ParseText(char* p, const char* endTag, int strFlags, int* curLineNumPtr)\n\t{\n\t\tTIXMLASSERT(p);\n\t\tTIXMLASSERT(endTag && *endTag);\n\t\tTIXMLASSERT(curLineNumPtr);\n\n\t\tchar* start = p;\n\t\tchar  endChar = *endTag;\n\t\tsize_t length = strlen(endTag);\n\n\t\t// Inner loop of text parsing.\n\t\twhile (*p) {\n\t\t\tif (*p == endChar && strncmp(p, endTag, length) == 0) {\n\t\t\t\tSet(start, p, strFlags);\n\t\t\t\treturn p + length;\n\t\t\t}\n\t\t\telse if (*p == '\\n') {\n\t\t\t\t++(*curLineNumPtr);\n\t\t\t}\n\t\t\t++p;\n\t\t\tTIXMLASSERT(p);\n\t\t}\n\t\treturn 0;\n\t}\n\n\n\tchar* StrPair::ParseName(char* p)\n\t{\n\t\tif (!p || !(*p)) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (!XMLUtil::IsNameStartChar(*p)) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tchar* const start = p;\n\t\t++p;\n\t\twhile (*p && XMLUtil::IsNameChar(*p)) {\n\t\t\t++p;\n\t\t}\n\n\t\tSet(start, p, 0);\n\t\treturn p;\n\t}\n\n\n\tvoid StrPair::CollapseWhitespace()\n\t{\n\t\t// Adjusting _start would cause undefined behavior on delete[]\n\t\tTIXMLASSERT((_flags & NEEDS_DELETE) == 0);\n\t\t// Trim leading space.\n\t\t_start = XMLUtil::SkipWhiteSpace(_start, 0);\n\n\t\tif (*_start) {\n\t\t\tconst char* p = _start;\t// the read pointer\n\t\t\tchar* q = _start;\t// the write pointer\n\n\t\t\twhile (*p) {\n\t\t\t\tif (XMLUtil::IsWhiteSpace(*p)) {\n\t\t\t\t\tp = XMLUtil::SkipWhiteSpace(p, 0);\n\t\t\t\t\tif (*p == 0) {\n\t\t\t\t\t\tbreak;    // don't write to q; this trims the trailing space.\n\t\t\t\t\t}\n\t\t\t\t\t*q = ' ';\n\t\t\t\t\t++q;\n\t\t\t\t}\n\t\t\t\t*q = *p;\n\t\t\t\t++q;\n\t\t\t\t++p;\n\t\t\t}\n\t\t\t*q = 0;\n\t\t}\n\t}\n\n\n\tconst char* StrPair::GetStr()\n\t{\n\t\tTIXMLASSERT(_start);\n\t\tTIXMLASSERT(_end);\n\t\tif (_flags & NEEDS_FLUSH) {\n\t\t\t*_end = 0;\n\t\t\t_flags ^= NEEDS_FLUSH;\n\n\t\t\tif (_flags) {\n\t\t\t\tconst char* p = _start;\t// the read pointer\n\t\t\t\tchar* q = _start;\t// the write pointer\n\n\t\t\t\twhile (p < _end) {\n\t\t\t\t\tif ((_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR) {\n\t\t\t\t\t\t// CR-LF pair becomes LF\n\t\t\t\t\t\t// CR alone becomes LF\n\t\t\t\t\t\t// LF-CR becomes LF\n\t\t\t\t\t\tif (*(p + 1) == LF) {\n\t\t\t\t\t\t\tp += 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t++p;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t*q = LF;\n\t\t\t\t\t\t++q;\n\t\t\t\t\t}\n\t\t\t\t\telse if ((_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF) {\n\t\t\t\t\t\tif (*(p + 1) == CR) {\n\t\t\t\t\t\t\tp += 2;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t++p;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t*q = LF;\n\t\t\t\t\t\t++q;\n\t\t\t\t\t}\n\t\t\t\t\telse if ((_flags & NEEDS_ENTITY_PROCESSING) && *p == '&') {\n\t\t\t\t\t\t// Entities handled by tinyXML2:\n\t\t\t\t\t\t// - special entities in the entity table [in/out]\n\t\t\t\t\t\t// - numeric character reference [in]\n\t\t\t\t\t\t//   &#20013; or &#x4e2d;\n\n\t\t\t\t\t\tif (*(p + 1) == '#') {\n\t\t\t\t\t\t\tconst int buflen = 10;\n\t\t\t\t\t\t\tchar buf[buflen] = { 0 };\n\t\t\t\t\t\t\tint len = 0;\n\t\t\t\t\t\t\tchar* adjusted = const_cast<char*>(XMLUtil::GetCharacterRef(p, buf, &len));\n\t\t\t\t\t\t\tif (adjusted == 0) {\n\t\t\t\t\t\t\t\t*q = *p;\n\t\t\t\t\t\t\t\t++p;\n\t\t\t\t\t\t\t\t++q;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tTIXMLASSERT(0 <= len && len <= buflen);\n\t\t\t\t\t\t\t\tTIXMLASSERT(q + len <= adjusted);\n\t\t\t\t\t\t\t\tp = adjusted;\n\t\t\t\t\t\t\t\tmemcpy(q, buf, len);\n\t\t\t\t\t\t\t\tq += len;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbool entityFound = false;\n\t\t\t\t\t\t\tfor (int i = 0; i < NUM_ENTITIES; ++i) {\n\t\t\t\t\t\t\t\tconst Entity& entity = entities[i];\n\t\t\t\t\t\t\t\tif (strncmp(p + 1, entity.pattern, entity.length) == 0\n\t\t\t\t\t\t\t\t\t&& *(p + entity.length + 1) == ';') {\n\t\t\t\t\t\t\t\t\t// Found an entity - convert.\n\t\t\t\t\t\t\t\t\t*q = entity.value;\n\t\t\t\t\t\t\t\t\t++q;\n\t\t\t\t\t\t\t\t\tp += entity.length + 2;\n\t\t\t\t\t\t\t\t\tentityFound = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!entityFound) {\n\t\t\t\t\t\t\t\t// fixme: treat as error?\n\t\t\t\t\t\t\t\t++p;\n\t\t\t\t\t\t\t\t++q;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t*q = *p;\n\t\t\t\t\t\t++p;\n\t\t\t\t\t\t++q;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t*q = 0;\n\t\t\t}\n\t\t\t// The loop below has plenty going on, and this\n\t\t\t// is a less useful mode. Break it out.\n\t\t\tif (_flags & NEEDS_WHITESPACE_COLLAPSING) {\n\t\t\t\tCollapseWhitespace();\n\t\t\t}\n\t\t\t_flags = (_flags & NEEDS_DELETE);\n\t\t}\n\t\tTIXMLASSERT(_start);\n\t\treturn _start;\n\t}\n\n\n\n\n\t// --------- XMLUtil ----------- //\n\n\tconst char* XMLUtil::writeBoolTrue = \"true\";\n\tconst char* XMLUtil::writeBoolFalse = \"false\";\n\n\tvoid XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)\n\t{\n\t\tstatic const char* defTrue = \"true\";\n\t\tstatic const char* defFalse = \"false\";\n\n\t\twriteBoolTrue = (writeTrue) ? writeTrue : defTrue;\n\t\twriteBoolFalse = (writeFalse) ? writeFalse : defFalse;\n\t}\n\n\n\tconst char* XMLUtil::ReadBOM(const char* p, bool* bom)\n\t{\n\t\tTIXMLASSERT(p);\n\t\tTIXMLASSERT(bom);\n\t\t*bom = false;\n\t\tconst unsigned char* pu = reinterpret_cast<const unsigned char*>(p);\n\t\t// Check for BOM:\n\t\tif (*(pu + 0) == TIXML_UTF_LEAD_0\n\t\t\t&& *(pu + 1) == TIXML_UTF_LEAD_1\n\t\t\t&& *(pu + 2) == TIXML_UTF_LEAD_2) {\n\t\t\t*bom = true;\n\t\t\tp += 3;\n\t\t}\n\t\tTIXMLASSERT(p);\n\t\treturn p;\n\t}\n\n\n\tvoid XMLUtil::ConvertUTF32ToUTF8(unsigned long input, char* output, int* length)\n\t{\n\t\tconst unsigned long BYTE_MASK = 0xBF;\n\t\tconst unsigned long BYTE_MARK = 0x80;\n\t\tconst unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };\n\n\t\tif (input < 0x80) {\n\t\t\t*length = 1;\n\t\t}\n\t\telse if (input < 0x800) {\n\t\t\t*length = 2;\n\t\t}\n\t\telse if (input < 0x10000) {\n\t\t\t*length = 3;\n\t\t}\n\t\telse if (input < 0x200000) {\n\t\t\t*length = 4;\n\t\t}\n\t\telse {\n\t\t\t*length = 0;    // This code won't convert this correctly anyway.\n\t\t\treturn;\n\t\t}\n\n\t\toutput += *length;\n\n\t\t// Scary scary fall throughs are annotated with carefully designed comments\n\t\t// to suppress compiler warnings such as -Wimplicit-fallthrough in gcc\n\t\tswitch (*length) {\n\t\tcase 4:\n\t\t\t--output;\n\t\t\t*output = (char)((input | BYTE_MARK) & BYTE_MASK);\n\t\t\tinput >>= 6;\n\t\t\t//fall through\n\t\tcase 3:\n\t\t\t--output;\n\t\t\t*output = (char)((input | BYTE_MARK) & BYTE_MASK);\n\t\t\tinput >>= 6;\n\t\t\t//fall through\n\t\tcase 2:\n\t\t\t--output;\n\t\t\t*output = (char)((input | BYTE_MARK) & BYTE_MASK);\n\t\t\tinput >>= 6;\n\t\t\t//fall through\n\t\tcase 1:\n\t\t\t--output;\n\t\t\t*output = (char)(input | FIRST_BYTE_MARK[*length]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tTIXMLASSERT(false);\n\t\t}\n\t}\n\n\n\tconst char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length)\n\t{\n\t\t// Presume an entity, and pull it out.\n\t\t*length = 0;\n\n\t\tif (*(p + 1) == '#' && *(p + 2)) {\n\t\t\tunsigned long ucs = 0;\n\t\t\tTIXMLASSERT(sizeof(ucs) >= 4);\n\t\t\tptrdiff_t delta = 0;\n\t\t\tunsigned mult = 1;\n\t\t\tstatic const char SEMICOLON = ';';\n\n\t\t\tif (*(p + 2) == 'x') {\n\t\t\t\t// Hexadecimal.\n\t\t\t\tconst char* q = p + 3;\n\t\t\t\tif (!(*q)) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\tq = strchr(q, SEMICOLON);\n\n\t\t\t\tif (!q) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tTIXMLASSERT(*q == SEMICOLON);\n\n\t\t\t\tdelta = q - p;\n\t\t\t\t--q;\n\n\t\t\t\twhile (*q != 'x') {\n\t\t\t\t\tunsigned int digit = 0;\n\n\t\t\t\t\tif (*q >= '0' && *q <= '9') {\n\t\t\t\t\t\tdigit = *q - '0';\n\t\t\t\t\t}\n\t\t\t\t\telse if (*q >= 'a' && *q <= 'f') {\n\t\t\t\t\t\tdigit = *q - 'a' + 10;\n\t\t\t\t\t}\n\t\t\t\t\telse if (*q >= 'A' && *q <= 'F') {\n\t\t\t\t\t\tdigit = *q - 'A' + 10;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\t\t\t\t\tTIXMLASSERT(digit < 16);\n\t\t\t\t\tTIXMLASSERT(digit == 0 || mult <= UINT_MAX / digit);\n\t\t\t\t\tconst unsigned int digitScaled = mult * digit;\n\t\t\t\t\tTIXMLASSERT(ucs <= ULONG_MAX - digitScaled);\n\t\t\t\t\tucs += digitScaled;\n\t\t\t\t\tTIXMLASSERT(mult <= UINT_MAX / 16);\n\t\t\t\t\tmult *= 16;\n\t\t\t\t\t--q;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Decimal.\n\t\t\t\tconst char* q = p + 2;\n\t\t\t\tif (!(*q)) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\tq = strchr(q, SEMICOLON);\n\n\t\t\t\tif (!q) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tTIXMLASSERT(*q == SEMICOLON);\n\n\t\t\t\tdelta = q - p;\n\t\t\t\t--q;\n\n\t\t\t\twhile (*q != '#') {\n\t\t\t\t\tif (*q >= '0' && *q <= '9') {\n\t\t\t\t\t\tconst unsigned int digit = *q - '0';\n\t\t\t\t\t\tTIXMLASSERT(digit < 10);\n\t\t\t\t\t\tTIXMLASSERT(digit == 0 || mult <= UINT_MAX / digit);\n\t\t\t\t\t\tconst unsigned int digitScaled = mult * digit;\n\t\t\t\t\t\tTIXMLASSERT(ucs <= ULONG_MAX - digitScaled);\n\t\t\t\t\t\tucs += digitScaled;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\t\t\t\t\tTIXMLASSERT(mult <= UINT_MAX / 10);\n\t\t\t\t\tmult *= 10;\n\t\t\t\t\t--q;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// convert the UCS to UTF-8\n\t\t\tConvertUTF32ToUTF8(ucs, value, length);\n\t\t\treturn p + delta + 1;\n\t\t}\n\t\treturn p + 1;\n\t}\n\n\n\tvoid XMLUtil::ToStr(int v, char* buffer, int bufferSize)\n\t{\n\t\tTIXML_SNPRINTF(buffer, bufferSize, \"%d\", v);\n\t}\n\n\n\tvoid XMLUtil::ToStr(unsigned v, char* buffer, int bufferSize)\n\t{\n\t\tTIXML_SNPRINTF(buffer, bufferSize, \"%u\", v);\n\t}\n\n\n\tvoid XMLUtil::ToStr(bool v, char* buffer, int bufferSize)\n\t{\n\t\tTIXML_SNPRINTF(buffer, bufferSize, \"%s\", v ? writeBoolTrue : writeBoolFalse);\n\t}\n\n\t/*\n\tToStr() of a number is a very tricky topic.\n\thttps://github.com/leethomason/tinyxml2/issues/106\n\t*/\n\tvoid XMLUtil::ToStr(float v, char* buffer, int bufferSize)\n\t{\n\t\tTIXML_SNPRINTF(buffer, bufferSize, \"%.8g\", v);\n\t}\n\n\n\tvoid XMLUtil::ToStr(double v, char* buffer, int bufferSize)\n\t{\n\t\tTIXML_SNPRINTF(buffer, bufferSize, \"%.17g\", v);\n\t}\n\n\n\tvoid XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)\n\t{\n\t\t// horrible syntax trick to make the compiler happy about %lld\n\t\tTIXML_SNPRINTF(buffer, bufferSize, \"%lld\", (long long)v);\n\t}\n\n\n\tbool XMLUtil::ToInt(const char* str, int* value)\n\t{\n\t\tif (TIXML_SSCANF(str, \"%d\", value) == 1) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool XMLUtil::ToUnsigned(const char* str, unsigned *value)\n\t{\n\t\tif (TIXML_SSCANF(str, \"%u\", value) == 1) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool XMLUtil::ToBool(const char* str, bool* value)\n\t{\n\t\tint ival = 0;\n\t\tif (ToInt(str, &ival)) {\n\t\t\t*value = (ival == 0) ? false : true;\n\t\t\treturn true;\n\t\t}\n\t\tif (StringEqual(str, \"true\")) {\n\t\t\t*value = true;\n\t\t\treturn true;\n\t\t}\n\t\telse if (StringEqual(str, \"false\")) {\n\t\t\t*value = false;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\n\tbool XMLUtil::ToFloat(const char* str, float* value)\n\t{\n\t\tif (TIXML_SSCANF(str, \"%f\", value) == 1) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\n\tbool XMLUtil::ToDouble(const char* str, double* value)\n\t{\n\t\tif (TIXML_SSCANF(str, \"%lf\", value) == 1) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\n\tbool XMLUtil::ToInt64(const char* str, int64_t* value)\n\t{\n\t\tlong long v = 0;\t// horrible syntax trick to make the compiler happy about %lld\n\t\tif (TIXML_SSCANF(str, \"%lld\", &v) == 1) {\n\t\t\t*value = (int64_t)v;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\n\tchar* XMLDocument::Identify(char* p, XMLNode** node)\n\t{\n\t\tTIXMLASSERT(node);\n\t\tTIXMLASSERT(p);\n\t\tchar* const start = p;\n\t\tint const startLine = _parseCurLineNum;\n\t\tp = XMLUtil::SkipWhiteSpace(p, &_parseCurLineNum);\n\t\tif (!*p) {\n\t\t\t*node = 0;\n\t\t\tTIXMLASSERT(p);\n\t\t\treturn p;\n\t\t}\n\n\t\t// These strings define the matching patterns:\n\t\tstatic const char* xmlHeader = { \"<?\" };\n\t\tstatic const char* commentHeader = { \"<!--\" };\n\t\tstatic const char* cdataHeader = { \"<![CDATA[\" };\n\t\tstatic const char* dtdHeader = { \"<!\" };\n\t\tstatic const char* elementHeader = { \"<\" };\t// and a header for everything else; check last.\n\n\t\tstatic const int xmlHeaderLen = 2;\n\t\tstatic const int commentHeaderLen = 4;\n\t\tstatic const int cdataHeaderLen = 9;\n\t\tstatic const int dtdHeaderLen = 2;\n\t\tstatic const int elementHeaderLen = 1;\n\n\t\tTIXMLASSERT(sizeof(XMLComment) == sizeof(XMLUnknown));\t\t// use same memory pool\n\t\tTIXMLASSERT(sizeof(XMLComment) == sizeof(XMLDeclaration));\t// use same memory pool\n\t\tXMLNode* returnNode = 0;\n\t\tif (XMLUtil::StringEqual(p, xmlHeader, xmlHeaderLen)) {\n\t\t\treturnNode = CreateUnlinkedNode<XMLDeclaration>(_commentPool);\n\t\t\treturnNode->_parseLineNum = _parseCurLineNum;\n\t\t\tp += xmlHeaderLen;\n\t\t}\n\t\telse if (XMLUtil::StringEqual(p, commentHeader, commentHeaderLen)) {\n\t\t\treturnNode = CreateUnlinkedNode<XMLComment>(_commentPool);\n\t\t\treturnNode->_parseLineNum = _parseCurLineNum;\n\t\t\tp += commentHeaderLen;\n\t\t}\n\t\telse if (XMLUtil::StringEqual(p, cdataHeader, cdataHeaderLen)) {\n\t\t\tXMLText* text = CreateUnlinkedNode<XMLText>(_textPool);\n\t\t\treturnNode = text;\n\t\t\treturnNode->_parseLineNum = _parseCurLineNum;\n\t\t\tp += cdataHeaderLen;\n\t\t\ttext->SetCData(true);\n\t\t}\n\t\telse if (XMLUtil::StringEqual(p, dtdHeader, dtdHeaderLen)) {\n\t\t\treturnNode = CreateUnlinkedNode<XMLUnknown>(_commentPool);\n\t\t\treturnNode->_parseLineNum = _parseCurLineNum;\n\t\t\tp += dtdHeaderLen;\n\t\t}\n\t\telse if (XMLUtil::StringEqual(p, elementHeader, elementHeaderLen)) {\n\t\t\treturnNode = CreateUnlinkedNode<XMLElement>(_elementPool);\n\t\t\treturnNode->_parseLineNum = _parseCurLineNum;\n\t\t\tp += elementHeaderLen;\n\t\t}\n\t\telse {\n\t\t\treturnNode = CreateUnlinkedNode<XMLText>(_textPool);\n\t\t\treturnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character\n\t\t\tp = start;\t// Back it up, all the text counts.\n\t\t\t_parseCurLineNum = startLine;\n\t\t}\n\n\t\tTIXMLASSERT(returnNode);\n\t\tTIXMLASSERT(p);\n\t\t*node = returnNode;\n\t\treturn p;\n\t}\n\n\n\tbool XMLDocument::Accept(XMLVisitor* visitor) const\n\t{\n\t\tTIXMLASSERT(visitor);\n\t\tif (visitor->VisitEnter(*this)) {\n\t\t\tfor (const XMLNode* node = FirstChild(); node; node = node->NextSibling()) {\n\t\t\t\tif (!node->Accept(visitor)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn visitor->VisitExit(*this);\n\t}\n\n\n\t// --------- XMLNode ----------- //\n\n\tXMLNode::XMLNode(XMLDocument* doc) :\n\t\t_document(doc),\n\t\t_parent(0),\n\t\t_value(),\n\t\t_parseLineNum(0),\n\t\t_firstChild(0), _lastChild(0),\n\t\t_prev(0), _next(0),\n\t\t_userData(0),\n\t\t_memPool(0)\n\t{\n\t}\n\n\n\tXMLNode::~XMLNode()\n\t{\n\t\tDeleteChildren();\n\t\tif (_parent) {\n\t\t\t_parent->Unlink(this);\n\t\t}\n\t}\n\n\tconst char* XMLNode::Value() const\n\t{\n\t\t// Edge case: XMLDocuments don't have a Value. Return null.\n\t\tif (this->ToDocument())\n\t\t\treturn 0;\n\t\treturn _value.GetStr();\n\t}\n\n\tvoid XMLNode::SetValue(const char* str, bool staticMem)\n\t{\n\t\tif (staticMem) {\n\t\t\t_value.SetInternedStr(str);\n\t\t}\n\t\telse {\n\t\t\t_value.SetStr(str);\n\t\t}\n\t}\n\n\tXMLNode* XMLNode::DeepClone(XMLDocument* target) const\n\t{\n\t\tXMLNode* clone = this->ShallowClone(target);\n\t\tif (!clone) return 0;\n\n\t\tfor (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {\n\t\t\tXMLNode* childClone = child->DeepClone(target);\n\t\t\tTIXMLASSERT(childClone);\n\t\t\tclone->InsertEndChild(childClone);\n\t\t}\n\t\treturn clone;\n\t}\n\n\tvoid XMLNode::DeleteChildren()\n\t{\n\t\twhile (_firstChild) {\n\t\t\tTIXMLASSERT(_lastChild);\n\t\t\tDeleteChild(_firstChild);\n\t\t}\n\t\t_firstChild = _lastChild = 0;\n\t}\n\n\n\tvoid XMLNode::Unlink(XMLNode* child)\n\t{\n\t\tTIXMLASSERT(child);\n\t\tTIXMLASSERT(child->_document == _document);\n\t\tTIXMLASSERT(child->_parent == this);\n\t\tif (child == _firstChild) {\n\t\t\t_firstChild = _firstChild->_next;\n\t\t}\n\t\tif (child == _lastChild) {\n\t\t\t_lastChild = _lastChild->_prev;\n\t\t}\n\n\t\tif (child->_prev) {\n\t\t\tchild->_prev->_next = child->_next;\n\t\t}\n\t\tif (child->_next) {\n\t\t\tchild->_next->_prev = child->_prev;\n\t\t}\n\t\tchild->_next = 0;\n\t\tchild->_prev = 0;\n\t\tchild->_parent = 0;\n\t}\n\n\n\tvoid XMLNode::DeleteChild(XMLNode* node)\n\t{\n\t\tTIXMLASSERT(node);\n\t\tTIXMLASSERT(node->_document == _document);\n\t\tTIXMLASSERT(node->_parent == this);\n\t\tUnlink(node);\n\t\tTIXMLASSERT(node->_prev == 0);\n\t\tTIXMLASSERT(node->_next == 0);\n\t\tTIXMLASSERT(node->_parent == 0);\n\t\tDeleteNode(node);\n\t}\n\n\n\tXMLNode* XMLNode::InsertEndChild(XMLNode* addThis)\n\t{\n\t\tTIXMLASSERT(addThis);\n\t\tif (addThis->_document != _document) {\n\t\t\tTIXMLASSERT(false);\n\t\t\treturn 0;\n\t\t}\n\t\tInsertChildPreamble(addThis);\n\n\t\tif (_lastChild) {\n\t\t\tTIXMLASSERT(_firstChild);\n\t\t\tTIXMLASSERT(_lastChild->_next == 0);\n\t\t\t_lastChild->_next = addThis;\n\t\t\taddThis->_prev = _lastChild;\n\t\t\t_lastChild = addThis;\n\n\t\t\taddThis->_next = 0;\n\t\t}\n\t\telse {\n\t\t\tTIXMLASSERT(_firstChild == 0);\n\t\t\t_firstChild = _lastChild = addThis;\n\n\t\t\taddThis->_prev = 0;\n\t\t\taddThis->_next = 0;\n\t\t}\n\t\taddThis->_parent = this;\n\t\treturn addThis;\n\t}\n\n\n\tXMLNode* XMLNode::InsertFirstChild(XMLNode* addThis)\n\t{\n\t\tTIXMLASSERT(addThis);\n\t\tif (addThis->_document != _document) {\n\t\t\tTIXMLASSERT(false);\n\t\t\treturn 0;\n\t\t}\n\t\tInsertChildPreamble(addThis);\n\n\t\tif (_firstChild) {\n\t\t\tTIXMLASSERT(_lastChild);\n\t\t\tTIXMLASSERT(_firstChild->_prev == 0);\n\n\t\t\t_firstChild->_prev = addThis;\n\t\t\taddThis->_next = _firstChild;\n\t\t\t_firstChild = addThis;\n\n\t\t\taddThis->_prev = 0;\n\t\t}\n\t\telse {\n\t\t\tTIXMLASSERT(_lastChild == 0);\n\t\t\t_firstChild = _lastChild = addThis;\n\n\t\t\taddThis->_prev = 0;\n\t\t\taddThis->_next = 0;\n\t\t}\n\t\taddThis->_parent = this;\n\t\treturn addThis;\n\t}\n\n\n\tXMLNode* XMLNode::InsertAfterChild(XMLNode* afterThis, XMLNode* addThis)\n\t{\n\t\tTIXMLASSERT(addThis);\n\t\tif (addThis->_document != _document) {\n\t\t\tTIXMLASSERT(false);\n\t\t\treturn 0;\n\t\t}\n\n\t\tTIXMLASSERT(afterThis);\n\n\t\tif (afterThis->_parent != this) {\n\t\t\tTIXMLASSERT(false);\n\t\t\treturn 0;\n\t\t}\n\t\tif (afterThis == addThis) {\n\t\t\t// Current state: BeforeThis -> AddThis -> OneAfterAddThis\n\t\t\t// Now AddThis must disappear from it's location and then\n\t\t\t// reappear between BeforeThis and OneAfterAddThis.\n\t\t\t// So just leave it where it is.\n\t\t\treturn addThis;\n\t\t}\n\n\t\tif (afterThis->_next == 0) {\n\t\t\t// The last node or the only node.\n\t\t\treturn InsertEndChild(addThis);\n\t\t}\n\t\tInsertChildPreamble(addThis);\n\t\taddThis->_prev = afterThis;\n\t\taddThis->_next = afterThis->_next;\n\t\tafterThis->_next->_prev = addThis;\n\t\tafterThis->_next = addThis;\n\t\taddThis->_parent = this;\n\t\treturn addThis;\n\t}\n\n\n\n\n\tconst XMLElement* XMLNode::FirstChildElement(const char* name) const\n\t{\n\t\tfor (const XMLNode* node = _firstChild; node; node = node->_next) {\n\t\t\tconst XMLElement* element = node->ToElementWithName(name);\n\t\t\tif (element) {\n\t\t\t\treturn element;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\n\tconst XMLElement* XMLNode::LastChildElement(const char* name) const\n\t{\n\t\tfor (const XMLNode* node = _lastChild; node; node = node->_prev) {\n\t\t\tconst XMLElement* element = node->ToElementWithName(name);\n\t\t\tif (element) {\n\t\t\t\treturn element;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\n\tconst XMLElement* XMLNode::NextSiblingElement(const char* name) const\n\t{\n\t\tfor (const XMLNode* node = _next; node; node = node->_next) {\n\t\t\tconst XMLElement* element = node->ToElementWithName(name);\n\t\t\tif (element) {\n\t\t\t\treturn element;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\n\tconst XMLElement* XMLNode::PreviousSiblingElement(const char* name) const\n\t{\n\t\tfor (const XMLNode* node = _prev; node; node = node->_prev) {\n\t\t\tconst XMLElement* element = node->ToElementWithName(name);\n\t\t\tif (element) {\n\t\t\t\treturn element;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\n\tchar* XMLNode::ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr)\n\t{\n\t\t// This is a recursive method, but thinking about it \"at the current level\"\n\t\t// it is a pretty simple flat list:\n\t\t//\t\t<foo/>\n\t\t//\t\t<!-- comment -->\n\t\t//\n\t\t// With a special case:\n\t\t//\t\t<foo>\n\t\t//\t\t</foo>\n\t\t//\t\t<!-- comment -->\n\t\t//\n\t\t// Where the closing element (/foo) *must* be the next thing after the opening\n\t\t// element, and the names must match. BUT the tricky bit is that the closing\n\t\t// element will be read by the child.\n\t\t//\n\t\t// 'endTag' is the end tag for this node, it is returned by a call to a child.\n\t\t// 'parentEnd' is the end tag for the parent, which is filled in and returned.\n\n\t\twhile (p && *p) {\n\t\t\tXMLNode* node = 0;\n\n\t\t\tp = _document->Identify(p, &node);\n\t\t\tTIXMLASSERT(p);\n\t\t\tif (node == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tint initialLineNum = node->_parseLineNum;\n\n\t\t\tStrPair endTag;\n\t\t\tp = node->ParseDeep(p, &endTag, curLineNumPtr);\n\t\t\tif (!p) {\n\t\t\t\tDeleteNode(node);\n\t\t\t\tif (!_document->Error()) {\n\t\t\t\t\t_document->SetError(XML_ERROR_PARSING, 0, 0, initialLineNum);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tXMLDeclaration* decl = node->ToDeclaration();\n\t\t\tif (decl) {\n\t\t\t\t// Declarations are only allowed at document level\n\t\t\t\tbool wellLocated = (ToDocument() != 0);\n\t\t\t\tif (wellLocated) {\n\t\t\t\t\t// Multiple declarations are allowed but all declarations\n\t\t\t\t\t// must occur before anything else\n\t\t\t\t\tfor (const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling()) {\n\t\t\t\t\t\tif (!existingNode->ToDeclaration()) {\n\t\t\t\t\t\t\twellLocated = false;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!wellLocated) {\n\t\t\t\t\t_document->SetError(XML_ERROR_PARSING_DECLARATION, decl->Value(), 0, initialLineNum);\n\t\t\t\t\tDeleteNode(node);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tXMLElement* ele = node->ToElement();\n\t\t\tif (ele) {\n\t\t\t\t// We read the end tag. Return it to the parent.\n\t\t\t\tif (ele->ClosingType() == XMLElement::CLOSING) {\n\t\t\t\t\tif (parentEndTag) {\n\t\t\t\t\t\tele->_value.TransferTo(parentEndTag);\n\t\t\t\t\t}\n\t\t\t\t\tnode->_memPool->SetTracked();   // created and then immediately deleted.\n\t\t\t\t\tDeleteNode(node);\n\t\t\t\t\treturn p;\n\t\t\t\t}\n\n\t\t\t\t// Handle an end tag returned to this level.\n\t\t\t\t// And handle a bunch of annoying errors.\n\t\t\t\tbool mismatch = false;\n\t\t\t\tif (endTag.Empty()) {\n\t\t\t\t\tif (ele->ClosingType() == XMLElement::OPEN) {\n\t\t\t\t\t\tmismatch = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (ele->ClosingType() != XMLElement::OPEN) {\n\t\t\t\t\t\tmismatch = true;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!XMLUtil::StringEqual(endTag.GetStr(), ele->Name())) {\n\t\t\t\t\t\tmismatch = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (mismatch) {\n\t\t\t\t\t_document->SetError(XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0, initialLineNum);\n\t\t\t\t\tDeleteNode(node);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tInsertEndChild(node);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/*static*/ void XMLNode::DeleteNode(XMLNode* node)\n\t{\n\t\tif (node == 0) {\n\t\t\treturn;\n\t\t}\n\t\tTIXMLASSERT(node->_document);\n\t\tif (!node->ToDocument()) {\n\t\t\tnode->_document->MarkInUse(node);\n\t\t}\n\n\t\tMemPool* pool = node->_memPool;\n\t\tnode->~XMLNode();\n\t\tpool->Free(node);\n\t}\n\n\tvoid XMLNode::InsertChildPreamble(XMLNode* insertThis) const\n\t{\n\t\tTIXMLASSERT(insertThis);\n\t\tTIXMLASSERT(insertThis->_document == _document);\n\n\t\tif (insertThis->_parent) {\n\t\t\tinsertThis->_parent->Unlink(insertThis);\n\t\t}\n\t\telse {\n\t\t\tinsertThis->_document->MarkInUse(insertThis);\n\t\t\tinsertThis->_memPool->SetTracked();\n\t\t}\n\t}\n\n\tconst XMLElement* XMLNode::ToElementWithName(const char* name) const\n\t{\n\t\tconst XMLElement* element = this->ToElement();\n\t\tif (element == 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (name == 0) {\n\t\t\treturn element;\n\t\t}\n\t\tif (XMLUtil::StringEqual(element->Name(), name)) {\n\t\t\treturn element;\n\t\t}\n\t\treturn 0;\n\t}\n\n\t// --------- XMLText ---------- //\n\tchar* XMLText::ParseDeep(char* p, StrPair*, int* curLineNumPtr)\n\t{\n\t\tconst char* start = p;\n\t\tif (this->CData()) {\n\t\t\tp = _value.ParseText(p, \"]]>\", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr);\n\t\t\tif (!p) {\n\t\t\t\t_document->SetError(XML_ERROR_PARSING_CDATA, start, 0, _parseLineNum);\n\t\t\t}\n\t\t\treturn p;\n\t\t}\n\t\telse {\n\t\t\tint flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;\n\t\t\tif (_document->WhitespaceMode() == COLLAPSE_WHITESPACE) {\n\t\t\t\tflags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;\n\t\t\t}\n\n\t\t\tp = _value.ParseText(p, \"<\", flags, curLineNumPtr);\n\t\t\tif (p && *p) {\n\t\t\t\treturn p - 1;\n\t\t\t}\n\t\t\tif (!p) {\n\t\t\t\t_document->SetError(XML_ERROR_PARSING_TEXT, start, 0, _parseLineNum);\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\n\tXMLNode* XMLText::ShallowClone(XMLDocument* doc) const\n\t{\n\t\tif (!doc) {\n\t\t\tdoc = _document;\n\t\t}\n\t\tXMLText* text = doc->NewText(Value());\t// fixme: this will always allocate memory. Intern?\n\t\ttext->SetCData(this->CData());\n\t\treturn text;\n\t}\n\n\n\tbool XMLText::ShallowEqual(const XMLNode* compare) const\n\t{\n\t\tTIXMLASSERT(compare);\n\t\tconst XMLText* text = compare->ToText();\n\t\treturn (text && XMLUtil::StringEqual(text->Value(), Value()));\n\t}\n\n\n\tbool XMLText::Accept(XMLVisitor* visitor) const\n\t{\n\t\tTIXMLASSERT(visitor);\n\t\treturn visitor->Visit(*this);\n\t}\n\n\n\t// --------- XMLComment ---------- //\n\n\tXMLComment::XMLComment(XMLDocument* doc) : XMLNode(doc)\n\t{\n\t}\n\n\n\tXMLComment::~XMLComment()\n\t{\n\t}\n\n\n\tchar* XMLComment::ParseDeep(char* p, StrPair*, int* curLineNumPtr)\n\t{\n\t\t// Comment parses as text.\n\t\tconst char* start = p;\n\t\tp = _value.ParseText(p, \"-->\", StrPair::COMMENT, curLineNumPtr);\n\t\tif (p == 0) {\n\t\t\t_document->SetError(XML_ERROR_PARSING_COMMENT, start, 0, _parseLineNum);\n\t\t}\n\t\treturn p;\n\t}\n\n\n\tXMLNode* XMLComment::ShallowClone(XMLDocument* doc) const\n\t{\n\t\tif (!doc) {\n\t\t\tdoc = _document;\n\t\t}\n\t\tXMLComment* comment = doc->NewComment(Value());\t// fixme: this will always allocate memory. Intern?\n\t\treturn comment;\n\t}\n\n\n\tbool XMLComment::ShallowEqual(const XMLNode* compare) const\n\t{\n\t\tTIXMLASSERT(compare);\n\t\tconst XMLComment* comment = compare->ToComment();\n\t\treturn (comment && XMLUtil::StringEqual(comment->Value(), Value()));\n\t}\n\n\n\tbool XMLComment::Accept(XMLVisitor* visitor) const\n\t{\n\t\tTIXMLASSERT(visitor);\n\t\treturn visitor->Visit(*this);\n\t}\n\n\n\t// --------- XMLDeclaration ---------- //\n\n\tXMLDeclaration::XMLDeclaration(XMLDocument* doc) : XMLNode(doc)\n\t{\n\t}\n\n\n\tXMLDeclaration::~XMLDeclaration()\n\t{\n\t\t//printf( \"~XMLDeclaration\\n\" );\n\t}\n\n\n\tchar* XMLDeclaration::ParseDeep(char* p, StrPair*, int* curLineNumPtr)\n\t{\n\t\t// Declaration parses as text.\n\t\tconst char* start = p;\n\t\tp = _value.ParseText(p, \"?>\", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr);\n\t\tif (p == 0) {\n\t\t\t_document->SetError(XML_ERROR_PARSING_DECLARATION, start, 0, _parseLineNum);\n\t\t}\n\t\treturn p;\n\t}\n\n\n\tXMLNode* XMLDeclaration::ShallowClone(XMLDocument* doc) const\n\t{\n\t\tif (!doc) {\n\t\t\tdoc = _document;\n\t\t}\n\t\tXMLDeclaration* dec = doc->NewDeclaration(Value());\t// fixme: this will always allocate memory. Intern?\n\t\treturn dec;\n\t}\n\n\n\tbool XMLDeclaration::ShallowEqual(const XMLNode* compare) const\n\t{\n\t\tTIXMLASSERT(compare);\n\t\tconst XMLDeclaration* declaration = compare->ToDeclaration();\n\t\treturn (declaration && XMLUtil::StringEqual(declaration->Value(), Value()));\n\t}\n\n\n\n\tbool XMLDeclaration::Accept(XMLVisitor* visitor) const\n\t{\n\t\tTIXMLASSERT(visitor);\n\t\treturn visitor->Visit(*this);\n\t}\n\n\t// --------- XMLUnknown ---------- //\n\n\tXMLUnknown::XMLUnknown(XMLDocument* doc) : XMLNode(doc)\n\t{\n\t}\n\n\n\tXMLUnknown::~XMLUnknown()\n\t{\n\t}\n\n\n\tchar* XMLUnknown::ParseDeep(char* p, StrPair*, int* curLineNumPtr)\n\t{\n\t\t// Unknown parses as text.\n\t\tconst char* start = p;\n\n\t\tp = _value.ParseText(p, \">\", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr);\n\t\tif (!p) {\n\t\t\t_document->SetError(XML_ERROR_PARSING_UNKNOWN, start, 0, _parseLineNum);\n\t\t}\n\t\treturn p;\n\t}\n\n\n\tXMLNode* XMLUnknown::ShallowClone(XMLDocument* doc) const\n\t{\n\t\tif (!doc) {\n\t\t\tdoc = _document;\n\t\t}\n\t\tXMLUnknown* text = doc->NewUnknown(Value());\t// fixme: this will always allocate memory. Intern?\n\t\treturn text;\n\t}\n\n\n\tbool XMLUnknown::ShallowEqual(const XMLNode* compare) const\n\t{\n\t\tTIXMLASSERT(compare);\n\t\tconst XMLUnknown* unknown = compare->ToUnknown();\n\t\treturn (unknown && XMLUtil::StringEqual(unknown->Value(), Value()));\n\t}\n\n\n\tbool XMLUnknown::Accept(XMLVisitor* visitor) const\n\t{\n\t\tTIXMLASSERT(visitor);\n\t\treturn visitor->Visit(*this);\n\t}\n\n\t// --------- XMLAttribute ---------- //\n\n\tconst char* XMLAttribute::Name() const\n\t{\n\t\treturn _name.GetStr();\n\t}\n\n\tconst char* XMLAttribute::Value() const\n\t{\n\t\treturn _value.GetStr();\n\t}\n\n\tchar* XMLAttribute::ParseDeep(char* p, bool processEntities, int* curLineNumPtr)\n\t{\n\t\t// Parse using the name rules: bug fix, was using ParseText before\n\t\tp = _name.ParseName(p);\n\t\tif (!p || !*p) {\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Skip white space before =\n\t\tp = XMLUtil::SkipWhiteSpace(p, curLineNumPtr);\n\t\tif (*p != '=') {\n\t\t\treturn 0;\n\t\t}\n\n\t\t++p;\t// move up to opening quote\n\t\tp = XMLUtil::SkipWhiteSpace(p, curLineNumPtr);\n\t\tif (*p != '\\\"' && *p != '\\'') {\n\t\t\treturn 0;\n\t\t}\n\n\t\tchar endTag[2] = { *p, 0 };\n\t\t++p;\t// move past opening quote\n\n\t\tp = _value.ParseText(p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr);\n\t\treturn p;\n\t}\n\n\n\tvoid XMLAttribute::SetName(const char* n)\n\t{\n\t\t_name.SetStr(n);\n\t}\n\n\n\tXMLError XMLAttribute::QueryIntValue(int* value) const\n\t{\n\t\tif (XMLUtil::ToInt(Value(), value)) {\n\t\t\treturn XML_SUCCESS;\n\t\t}\n\t\treturn XML_WRONG_ATTRIBUTE_TYPE;\n\t}\n\n\n\tXMLError XMLAttribute::QueryUnsignedValue(unsigned int* value) const\n\t{\n\t\tif (XMLUtil::ToUnsigned(Value(), value)) {\n\t\t\treturn XML_SUCCESS;\n\t\t}\n\t\treturn XML_WRONG_ATTRIBUTE_TYPE;\n\t}\n\n\n\tXMLError XMLAttribute::QueryInt64Value(int64_t* value) const\n\t{\n\t\tif (XMLUtil::ToInt64(Value(), value)) {\n\t\t\treturn XML_SUCCESS;\n\t\t}\n\t\treturn XML_WRONG_ATTRIBUTE_TYPE;\n\t}\n\n\n\tXMLError XMLAttribute::QueryBoolValue(bool* value) const\n\t{\n\t\tif (XMLUtil::ToBool(Value(), value)) {\n\t\t\treturn XML_SUCCESS;\n\t\t}\n\t\treturn XML_WRONG_ATTRIBUTE_TYPE;\n\t}\n\n\n\tXMLError XMLAttribute::QueryFloatValue(float* value) const\n\t{\n\t\tif (XMLUtil::ToFloat(Value(), value)) {\n\t\t\treturn XML_SUCCESS;\n\t\t}\n\t\treturn XML_WRONG_ATTRIBUTE_TYPE;\n\t}\n\n\n\tXMLError XMLAttribute::QueryDoubleValue(double* value) const\n\t{\n\t\tif (XMLUtil::ToDouble(Value(), value)) {\n\t\t\treturn XML_SUCCESS;\n\t\t}\n\t\treturn XML_WRONG_ATTRIBUTE_TYPE;\n\t}\n\n\n\tvoid XMLAttribute::SetAttribute(const char* v)\n\t{\n\t\t_value.SetStr(v);\n\t}\n\n\n\tvoid XMLAttribute::SetAttribute(int v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\t_value.SetStr(buf);\n\t}\n\n\n\tvoid XMLAttribute::SetAttribute(unsigned v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\t_value.SetStr(buf);\n\t}\n\n\n\tvoid XMLAttribute::SetAttribute(int64_t v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\t_value.SetStr(buf);\n\t}\n\n\n\n\tvoid XMLAttribute::SetAttribute(bool v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\t_value.SetStr(buf);\n\t}\n\n\tvoid XMLAttribute::SetAttribute(double v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\t_value.SetStr(buf);\n\t}\n\n\tvoid XMLAttribute::SetAttribute(float v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\t_value.SetStr(buf);\n\t}\n\n\n\t// --------- XMLElement ---------- //\n\tXMLElement::XMLElement(XMLDocument* doc) : XMLNode(doc),\n\t\t_closingType(OPEN),\n\t\t_rootAttribute(0)\n\t{\n\t}\n\n\n\tXMLElement::~XMLElement()\n\t{\n\t\twhile (_rootAttribute) {\n\t\t\tXMLAttribute* next = _rootAttribute->_next;\n\t\t\tDeleteAttribute(_rootAttribute);\n\t\t\t_rootAttribute = next;\n\t\t}\n\t}\n\n\n\tconst XMLAttribute* XMLElement::FindAttribute(const char* name) const\n\t{\n\t\tfor (XMLAttribute* a = _rootAttribute; a; a = a->_next) {\n\t\t\tif (XMLUtil::StringEqual(a->Name(), name)) {\n\t\t\t\treturn a;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\n\tconst char* XMLElement::Attribute(const char* name, const char* value) const\n\t{\n\t\tconst XMLAttribute* a = FindAttribute(name);\n\t\tif (!a) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (!value || XMLUtil::StringEqual(a->Value(), value)) {\n\t\t\treturn a->Value();\n\t\t}\n\t\treturn 0;\n\t}\n\n\tint XMLElement::IntAttribute(const char* name, int defaultValue) const\n\t{\n\t\tint i = defaultValue;\n\t\tQueryIntAttribute(name, &i);\n\t\treturn i;\n\t}\n\n\tunsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const\n\t{\n\t\tunsigned i = defaultValue;\n\t\tQueryUnsignedAttribute(name, &i);\n\t\treturn i;\n\t}\n\n\tint64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const\n\t{\n\t\tint64_t i = defaultValue;\n\t\tQueryInt64Attribute(name, &i);\n\t\treturn i;\n\t}\n\n\tbool XMLElement::BoolAttribute(const char* name, bool defaultValue) const\n\t{\n\t\tbool b = defaultValue;\n\t\tQueryBoolAttribute(name, &b);\n\t\treturn b;\n\t}\n\n\tdouble XMLElement::DoubleAttribute(const char* name, double defaultValue) const\n\t{\n\t\tdouble d = defaultValue;\n\t\tQueryDoubleAttribute(name, &d);\n\t\treturn d;\n\t}\n\n\tfloat XMLElement::FloatAttribute(const char* name, float defaultValue) const\n\t{\n\t\tfloat f = defaultValue;\n\t\tQueryFloatAttribute(name, &f);\n\t\treturn f;\n\t}\n\n\tconst char* XMLElement::GetText() const\n\t{\n\t\tif (FirstChild() && FirstChild()->ToText()) {\n\t\t\treturn FirstChild()->Value();\n\t\t}\n\t\treturn 0;\n\t}\n\n\n\tvoid\tXMLElement::SetText(const char* inText)\n\t{\n\t\tif (FirstChild() && FirstChild()->ToText())\n\t\t\tFirstChild()->SetValue(inText);\n\t\telse {\n\t\t\tXMLText*\ttheText = GetDocument()->NewText(inText);\n\t\t\tInsertFirstChild(theText);\n\t\t}\n\t}\n\n\n\tvoid XMLElement::SetText(int v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tSetText(buf);\n\t}\n\n\n\tvoid XMLElement::SetText(unsigned v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tSetText(buf);\n\t}\n\n\n\tvoid XMLElement::SetText(int64_t v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tSetText(buf);\n\t}\n\n\n\tvoid XMLElement::SetText(bool v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tSetText(buf);\n\t}\n\n\n\tvoid XMLElement::SetText(float v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tSetText(buf);\n\t}\n\n\n\tvoid XMLElement::SetText(double v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tSetText(buf);\n\t}\n\n\n\tXMLError XMLElement::QueryIntText(int* ival) const\n\t{\n\t\tif (FirstChild() && FirstChild()->ToText()) {\n\t\t\tconst char* t = FirstChild()->Value();\n\t\t\tif (XMLUtil::ToInt(t, ival)) {\n\t\t\t\treturn XML_SUCCESS;\n\t\t\t}\n\t\t\treturn XML_CAN_NOT_CONVERT_TEXT;\n\t\t}\n\t\treturn XML_NO_TEXT_NODE;\n\t}\n\n\n\tXMLError XMLElement::QueryUnsignedText(unsigned* uval) const\n\t{\n\t\tif (FirstChild() && FirstChild()->ToText()) {\n\t\t\tconst char* t = FirstChild()->Value();\n\t\t\tif (XMLUtil::ToUnsigned(t, uval)) {\n\t\t\t\treturn XML_SUCCESS;\n\t\t\t}\n\t\t\treturn XML_CAN_NOT_CONVERT_TEXT;\n\t\t}\n\t\treturn XML_NO_TEXT_NODE;\n\t}\n\n\n\tXMLError XMLElement::QueryInt64Text(int64_t* ival) const\n\t{\n\t\tif (FirstChild() && FirstChild()->ToText()) {\n\t\t\tconst char* t = FirstChild()->Value();\n\t\t\tif (XMLUtil::ToInt64(t, ival)) {\n\t\t\t\treturn XML_SUCCESS;\n\t\t\t}\n\t\t\treturn XML_CAN_NOT_CONVERT_TEXT;\n\t\t}\n\t\treturn XML_NO_TEXT_NODE;\n\t}\n\n\n\tXMLError XMLElement::QueryBoolText(bool* bval) const\n\t{\n\t\tif (FirstChild() && FirstChild()->ToText()) {\n\t\t\tconst char* t = FirstChild()->Value();\n\t\t\tif (XMLUtil::ToBool(t, bval)) {\n\t\t\t\treturn XML_SUCCESS;\n\t\t\t}\n\t\t\treturn XML_CAN_NOT_CONVERT_TEXT;\n\t\t}\n\t\treturn XML_NO_TEXT_NODE;\n\t}\n\n\n\tXMLError XMLElement::QueryDoubleText(double* dval) const\n\t{\n\t\tif (FirstChild() && FirstChild()->ToText()) {\n\t\t\tconst char* t = FirstChild()->Value();\n\t\t\tif (XMLUtil::ToDouble(t, dval)) {\n\t\t\t\treturn XML_SUCCESS;\n\t\t\t}\n\t\t\treturn XML_CAN_NOT_CONVERT_TEXT;\n\t\t}\n\t\treturn XML_NO_TEXT_NODE;\n\t}\n\n\n\tXMLError XMLElement::QueryFloatText(float* fval) const\n\t{\n\t\tif (FirstChild() && FirstChild()->ToText()) {\n\t\t\tconst char* t = FirstChild()->Value();\n\t\t\tif (XMLUtil::ToFloat(t, fval)) {\n\t\t\t\treturn XML_SUCCESS;\n\t\t\t}\n\t\t\treturn XML_CAN_NOT_CONVERT_TEXT;\n\t\t}\n\t\treturn XML_NO_TEXT_NODE;\n\t}\n\n\tint XMLElement::IntText(int defaultValue) const\n\t{\n\t\tint i = defaultValue;\n\t\tQueryIntText(&i);\n\t\treturn i;\n\t}\n\n\tunsigned XMLElement::UnsignedText(unsigned defaultValue) const\n\t{\n\t\tunsigned i = defaultValue;\n\t\tQueryUnsignedText(&i);\n\t\treturn i;\n\t}\n\n\tint64_t XMLElement::Int64Text(int64_t defaultValue) const\n\t{\n\t\tint64_t i = defaultValue;\n\t\tQueryInt64Text(&i);\n\t\treturn i;\n\t}\n\n\tbool XMLElement::BoolText(bool defaultValue) const\n\t{\n\t\tbool b = defaultValue;\n\t\tQueryBoolText(&b);\n\t\treturn b;\n\t}\n\n\tdouble XMLElement::DoubleText(double defaultValue) const\n\t{\n\t\tdouble d = defaultValue;\n\t\tQueryDoubleText(&d);\n\t\treturn d;\n\t}\n\n\tfloat XMLElement::FloatText(float defaultValue) const\n\t{\n\t\tfloat f = defaultValue;\n\t\tQueryFloatText(&f);\n\t\treturn f;\n\t}\n\n\n\tXMLAttribute* XMLElement::FindOrCreateAttribute(const char* name)\n\t{\n\t\tXMLAttribute* last = 0;\n\t\tXMLAttribute* attrib = 0;\n\t\tfor (attrib = _rootAttribute;\n\t\t\tattrib;\n\t\t\tlast = attrib, attrib = attrib->_next) {\n\t\t\tif (XMLUtil::StringEqual(attrib->Name(), name)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!attrib) {\n\t\t\tattrib = CreateAttribute();\n\t\t\tTIXMLASSERT(attrib);\n\t\t\tif (last) {\n\t\t\t\tTIXMLASSERT(last->_next == 0);\n\t\t\t\tlast->_next = attrib;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tTIXMLASSERT(_rootAttribute == 0);\n\t\t\t\t_rootAttribute = attrib;\n\t\t\t}\n\t\t\tattrib->SetName(name);\n\t\t}\n\t\treturn attrib;\n\t}\n\n\n\tvoid XMLElement::DeleteAttribute(const char* name)\n\t{\n\t\tXMLAttribute* prev = 0;\n\t\tfor (XMLAttribute* a = _rootAttribute; a; a = a->_next) {\n\t\t\tif (XMLUtil::StringEqual(name, a->Name())) {\n\t\t\t\tif (prev) {\n\t\t\t\t\tprev->_next = a->_next;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_rootAttribute = a->_next;\n\t\t\t\t}\n\t\t\t\tDeleteAttribute(a);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tprev = a;\n\t\t}\n\t}\n\n\n\tchar* XMLElement::ParseAttributes(char* p, int* curLineNumPtr)\n\t{\n\t\tconst char* start = p;\n\t\tXMLAttribute* prevAttribute = 0;\n\n\t\t// Read the attributes.\n\t\twhile (p) {\n\t\t\tp = XMLUtil::SkipWhiteSpace(p, curLineNumPtr);\n\t\t\tif (!(*p)) {\n\t\t\t\t_document->SetError(XML_ERROR_PARSING_ELEMENT, start, Name(), _parseLineNum);\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\t// attribute.\n\t\t\tif (XMLUtil::IsNameStartChar(*p)) {\n\t\t\t\tXMLAttribute* attrib = CreateAttribute();\n\t\t\t\tTIXMLASSERT(attrib);\n\t\t\t\tattrib->_parseLineNum = _document->_parseCurLineNum;\n\n\t\t\t\tint attrLineNum = attrib->_parseLineNum;\n\n\t\t\t\tp = attrib->ParseDeep(p, _document->ProcessEntities(), curLineNumPtr);\n\t\t\t\tif (!p || Attribute(attrib->Name())) {\n\t\t\t\t\tDeleteAttribute(attrib);\n\t\t\t\t\t_document->SetError(XML_ERROR_PARSING_ATTRIBUTE, start, p, attrLineNum);\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\t// There is a minor bug here: if the attribute in the source xml\n\t\t\t\t// document is duplicated, it will not be detected and the\n\t\t\t\t// attribute will be doubly added. However, tracking the 'prevAttribute'\n\t\t\t\t// avoids re-scanning the attribute list. Preferring performance for\n\t\t\t\t// now, may reconsider in the future.\n\t\t\t\tif (prevAttribute) {\n\t\t\t\t\tTIXMLASSERT(prevAttribute->_next == 0);\n\t\t\t\t\tprevAttribute->_next = attrib;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tTIXMLASSERT(_rootAttribute == 0);\n\t\t\t\t\t_rootAttribute = attrib;\n\t\t\t\t}\n\t\t\t\tprevAttribute = attrib;\n\t\t\t}\n\t\t\t// end of the tag\n\t\t\telse if (*p == '>') {\n\t\t\t\t++p;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// end of the tag\n\t\t\telse if (*p == '/' && *(p + 1) == '>') {\n\t\t\t\t_closingType = CLOSED;\n\t\t\t\treturn p + 2;\t// done; sealed element.\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_document->SetError(XML_ERROR_PARSING_ELEMENT, start, p, _parseLineNum);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\treturn p;\n\t}\n\n\tvoid XMLElement::DeleteAttribute(XMLAttribute* attribute)\n\t{\n\t\tif (attribute == 0) {\n\t\t\treturn;\n\t\t}\n\t\tMemPool* pool = attribute->_memPool;\n\t\tattribute->~XMLAttribute();\n\t\tpool->Free(attribute);\n\t}\n\n\tXMLAttribute* XMLElement::CreateAttribute()\n\t{\n\t\tTIXMLASSERT(sizeof(XMLAttribute) == _document->_attributePool.ItemSize());\n\t\tXMLAttribute* attrib = new (_document->_attributePool.Alloc()) XMLAttribute();\n\t\tTIXMLASSERT(attrib);\n\t\tattrib->_memPool = &_document->_attributePool;\n\t\tattrib->_memPool->SetTracked();\n\t\treturn attrib;\n\t}\n\n\t//\n\t//\t<ele></ele>\n\t//\t<ele>foo<b>bar</b></ele>\n\t//\n\tchar* XMLElement::ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr)\n\t{\n\t\t// Read the element name.\n\t\tp = XMLUtil::SkipWhiteSpace(p, curLineNumPtr);\n\n\t\t// The closing element is the </element> form. It is\n\t\t// parsed just like a regular element then deleted from\n\t\t// the DOM.\n\t\tif (*p == '/') {\n\t\t\t_closingType = CLOSING;\n\t\t\t++p;\n\t\t}\n\n\t\tp = _value.ParseName(p);\n\t\tif (_value.Empty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tp = ParseAttributes(p, curLineNumPtr);\n\t\tif (!p || !*p || _closingType != OPEN) {\n\t\t\treturn p;\n\t\t}\n\n\t\tp = XMLNode::ParseDeep(p, parentEndTag, curLineNumPtr);\n\t\treturn p;\n\t}\n\n\n\n\tXMLNode* XMLElement::ShallowClone(XMLDocument* doc) const\n\t{\n\t\tif (!doc) {\n\t\t\tdoc = _document;\n\t\t}\n\t\tXMLElement* element = doc->NewElement(Value());\t\t\t\t\t// fixme: this will always allocate memory. Intern?\n\t\tfor (const XMLAttribute* a = FirstAttribute(); a; a = a->Next()) {\n\t\t\telement->SetAttribute(a->Name(), a->Value());\t\t\t\t\t// fixme: this will always allocate memory. Intern?\n\t\t}\n\t\treturn element;\n\t}\n\n\n\tbool XMLElement::ShallowEqual(const XMLNode* compare) const\n\t{\n\t\tTIXMLASSERT(compare);\n\t\tconst XMLElement* other = compare->ToElement();\n\t\tif (other && XMLUtil::StringEqual(other->Name(), Name())) {\n\n\t\t\tconst XMLAttribute* a = FirstAttribute();\n\t\t\tconst XMLAttribute* b = other->FirstAttribute();\n\n\t\t\twhile (a && b) {\n\t\t\t\tif (!XMLUtil::StringEqual(a->Value(), b->Value())) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\ta = a->Next();\n\t\t\t\tb = b->Next();\n\t\t\t}\n\t\t\tif (a || b) {\n\t\t\t\t// different count\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\n\tbool XMLElement::Accept(XMLVisitor* visitor) const\n\t{\n\t\tTIXMLASSERT(visitor);\n\t\tif (visitor->VisitEnter(*this, _rootAttribute)) {\n\t\t\tfor (const XMLNode* node = FirstChild(); node; node = node->NextSibling()) {\n\t\t\t\tif (!node->Accept(visitor)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn visitor->VisitExit(*this);\n\t}\n\n\n\t// --------- XMLDocument ----------- //\n\n\t// Warning: List must match 'enum XMLError'\n\tconst char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {\n\t\t\"XML_SUCCESS\",\n\t\t\"XML_NO_ATTRIBUTE\",\n\t\t\"XML_WRONG_ATTRIBUTE_TYPE\",\n\t\t\"XML_ERROR_FILE_NOT_FOUND\",\n\t\t\"XML_ERROR_FILE_COULD_NOT_BE_OPENED\",\n\t\t\"XML_ERROR_FILE_READ_ERROR\",\n\t\t\"UNUSED_XML_ERROR_ELEMENT_MISMATCH\",\n\t\t\"XML_ERROR_PARSING_ELEMENT\",\n\t\t\"XML_ERROR_PARSING_ATTRIBUTE\",\n\t\t\"UNUSED_XML_ERROR_IDENTIFYING_TAG\",\n\t\t\"XML_ERROR_PARSING_TEXT\",\n\t\t\"XML_ERROR_PARSING_CDATA\",\n\t\t\"XML_ERROR_PARSING_COMMENT\",\n\t\t\"XML_ERROR_PARSING_DECLARATION\",\n\t\t\"XML_ERROR_PARSING_UNKNOWN\",\n\t\t\"XML_ERROR_EMPTY_DOCUMENT\",\n\t\t\"XML_ERROR_MISMATCHED_ELEMENT\",\n\t\t\"XML_ERROR_PARSING\",\n\t\t\"XML_CAN_NOT_CONVERT_TEXT\",\n\t\t\"XML_NO_TEXT_NODE\"\n\t};\n\n\n\tXMLDocument::XMLDocument(bool processEntities, Whitespace whitespaceMode) :\n\t\tXMLNode(0),\n\t\t_writeBOM(false),\n\t\t_processEntities(processEntities),\n\t\t_errorID(XML_SUCCESS),\n\t\t_whitespaceMode(whitespaceMode),\n\t\t_errorStr1(),\n\t\t_errorStr2(),\n\t\t_errorLineNum(0),\n\t\t_charBuffer(0),\n\t\t_parseCurLineNum(0),\n\t\t_unlinked(),\n\t\t_elementPool(),\n\t\t_attributePool(),\n\t\t_textPool(),\n\t\t_commentPool()\n\t{\n\t\t// avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)\n\t\t_document = this;\n\t}\n\n\n\tXMLDocument::~XMLDocument()\n\t{\n\t\tClear();\n\t}\n\n\n\tvoid XMLDocument::MarkInUse(XMLNode* node)\n\t{\n\t\tTIXMLASSERT(node);\n\t\tTIXMLASSERT(node->_parent == 0);\n\n\t\tfor (int i = 0; i < _unlinked.Size(); ++i) {\n\t\t\tif (node == _unlinked[i]) {\n\t\t\t\t_unlinked.SwapRemove(i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid XMLDocument::Clear()\n\t{\n\t\tDeleteChildren();\n\t\twhile (_unlinked.Size()) {\n\t\t\tDeleteNode(_unlinked[0]);\t// Will remove from _unlinked as part of delete.\n\t\t}\n\n#ifdef DEBUG\n\t\tconst bool hadError = Error();\n#endif\n\t\tClearError();\n\n\t\tdelete[] _charBuffer;\n\t\t_charBuffer = 0;\n\n#if 0\n\t\t_textPool.Trace(\"text\");\n\t\t_elementPool.Trace(\"element\");\n\t\t_commentPool.Trace(\"comment\");\n\t\t_attributePool.Trace(\"attribute\");\n#endif\n\n#ifdef DEBUG\n\t\tif (!hadError) {\n\t\t\tTIXMLASSERT(_elementPool.CurrentAllocs() == _elementPool.Untracked());\n\t\t\tTIXMLASSERT(_attributePool.CurrentAllocs() == _attributePool.Untracked());\n\t\t\tTIXMLASSERT(_textPool.CurrentAllocs() == _textPool.Untracked());\n\t\t\tTIXMLASSERT(_commentPool.CurrentAllocs() == _commentPool.Untracked());\n\t\t}\n#endif\n\t}\n\n\n\tvoid XMLDocument::DeepCopy(XMLDocument* target) const\n\t{\n\t\tTIXMLASSERT(target);\n\t\tif (target == this) {\n\t\t\treturn; // technically success - a no-op.\n\t\t}\n\n\t\ttarget->Clear();\n\t\tfor (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {\n\t\t\ttarget->InsertEndChild(node->DeepClone(target));\n\t\t}\n\t}\n\n\tXMLElement* XMLDocument::NewElement(const char* name)\n\t{\n\t\tXMLElement* ele = CreateUnlinkedNode<XMLElement>(_elementPool);\n\t\tele->SetName(name);\n\t\treturn ele;\n\t}\n\n\n\tXMLComment* XMLDocument::NewComment(const char* str)\n\t{\n\t\tXMLComment* comment = CreateUnlinkedNode<XMLComment>(_commentPool);\n\t\tcomment->SetValue(str);\n\t\treturn comment;\n\t}\n\n\n\tXMLText* XMLDocument::NewText(const char* str)\n\t{\n\t\tXMLText* text = CreateUnlinkedNode<XMLText>(_textPool);\n\t\ttext->SetValue(str);\n\t\treturn text;\n\t}\n\n\n\tXMLDeclaration* XMLDocument::NewDeclaration(const char* str)\n\t{\n\t\tXMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>(_commentPool);\n\t\tdec->SetValue(str ? str : \"xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"\");\n\t\treturn dec;\n\t}\n\n\n\tXMLUnknown* XMLDocument::NewUnknown(const char* str)\n\t{\n\t\tXMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>(_commentPool);\n\t\tunk->SetValue(str);\n\t\treturn unk;\n\t}\n\n\tstatic FILE* callfopen(const char* filepath, const char* mode)\n\t{\n\t\tTIXMLASSERT(filepath);\n\t\tTIXMLASSERT(mode);\n#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)\n\t\tFILE* fp = 0;\n\t\terrno_t err = fopen_s(&fp, filepath, mode);\n\t\tif (err) {\n\t\t\treturn 0;\n\t\t}\n#else\n\t\tFILE* fp = fopen(filepath, mode);\n#endif\n\t\treturn fp;\n\t}\n\n\tvoid XMLDocument::DeleteNode(XMLNode* node) {\n\t\tTIXMLASSERT(node);\n\t\tTIXMLASSERT(node->_document == this);\n\t\tif (node->_parent) {\n\t\t\tnode->_parent->DeleteChild(node);\n\t\t}\n\t\telse {\n\t\t\t// Isn't in the tree.\n\t\t\t// Use the parent delete.\n\t\t\t// Also, we need to mark it tracked: we 'know'\n\t\t\t// it was never used.\n\t\t\tnode->_memPool->SetTracked();\n\t\t\t// Call the static XMLNode version:\n\t\t\tXMLNode::DeleteNode(node);\n\t\t}\n\t}\n\n\n\tXMLError XMLDocument::LoadFile(const char* filename)\n\t{\n\t\tClear();\n\t\tFILE* fp = callfopen(filename, \"rb\");\n\t\tif (!fp) {\n\t\t\tSetError(XML_ERROR_FILE_NOT_FOUND, filename, 0, 0);\n\t\t\treturn _errorID;\n\t\t}\n\t\tLoadFile(fp);\n\t\tfclose(fp);\n\t\treturn _errorID;\n\t}\n\n\t// This is likely overengineered template art to have a check that unsigned long value incremented\n\t// by one still fits into size_t. If size_t type is larger than unsigned long type\n\t// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit\n\t// -Wtype-limits warning. This piece makes the compiler select code with a check when a check\n\t// is useful and code with no check when a check is redundant depending on how size_t and unsigned long\n\t// types sizes relate to each other.\n\ttemplate\n\t\t<bool = (sizeof(unsigned long) >= sizeof(size_t))>\n\t\tstruct LongFitsIntoSizeTMinusOne {\n\t\tstatic bool Fits(unsigned long value)\n\t\t{\n\t\t\treturn value < (size_t)-1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct LongFitsIntoSizeTMinusOne<false> {\n\t\tstatic bool Fits(unsigned long)\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t};\n\n\tXMLError XMLDocument::LoadFile(FILE* fp)\n\t{\n\t\tClear();\n\n\t\tfseek(fp, 0, SEEK_SET);\n\t\tif (fgetc(fp) == EOF && ferror(fp) != 0) {\n\t\t\tSetError(XML_ERROR_FILE_READ_ERROR, 0, 0, 0);\n\t\t\treturn _errorID;\n\t\t}\n\n\t\tfseek(fp, 0, SEEK_END);\n\t\tconst long filelength = ftell(fp);\n\t\tfseek(fp, 0, SEEK_SET);\n\t\tif (filelength == -1L) {\n\t\t\tSetError(XML_ERROR_FILE_READ_ERROR, 0, 0, 0);\n\t\t\treturn _errorID;\n\t\t}\n\t\tTIXMLASSERT(filelength >= 0);\n\n\t\tif (!LongFitsIntoSizeTMinusOne<>::Fits(filelength)) {\n\t\t\t// Cannot handle files which won't fit in buffer together with null terminator\n\t\t\tSetError(XML_ERROR_FILE_READ_ERROR, 0, 0, 0);\n\t\t\treturn _errorID;\n\t\t}\n\n\t\tif (filelength == 0) {\n\t\t\tSetError(XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0);\n\t\t\treturn _errorID;\n\t\t}\n\n\t\tconst size_t size = filelength;\n\t\tTIXMLASSERT(_charBuffer == 0);\n\t\t_charBuffer = new char[size + 1];\n\t\tsize_t read = fread(_charBuffer, 1, size, fp);\n\t\tif (read != size) {\n\t\t\tSetError(XML_ERROR_FILE_READ_ERROR, 0, 0, 0);\n\t\t\treturn _errorID;\n\t\t}\n\n\t\t_charBuffer[size] = 0;\n\n\t\tParse();\n\t\treturn _errorID;\n\t}\n\n\n\tXMLError XMLDocument::SaveFile(const char* filename, bool compact)\n\t{\n\t\tFILE* fp = callfopen(filename, \"w\");\n\t\tif (!fp) {\n\t\t\tSetError(XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0, 0);\n\t\t\treturn _errorID;\n\t\t}\n\t\tSaveFile(fp, compact);\n\t\tfclose(fp);\n\t\treturn _errorID;\n\t}\n\n\n\tXMLError XMLDocument::SaveFile(FILE* fp, bool compact)\n\t{\n\t\t// Clear any error from the last save, otherwise it will get reported\n\t\t// for *this* call.\n\t\tClearError();\n\t\tXMLPrinter stream(fp, compact);\n\t\tPrint(&stream);\n\t\treturn _errorID;\n\t}\n\n\n\tXMLError XMLDocument::Parse(const char* p, size_t len)\n\t{\n\t\tClear();\n\n\t\tif (len == 0 || !p || !*p) {\n\t\t\tSetError(XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0);\n\t\t\treturn _errorID;\n\t\t}\n\t\tif (len == (size_t)(-1)) {\n\t\t\tlen = strlen(p);\n\t\t}\n\t\tTIXMLASSERT(_charBuffer == 0);\n\t\t_charBuffer = new char[len + 1];\n\t\tmemcpy(_charBuffer, p, len);\n\t\t_charBuffer[len] = 0;\n\n\t\tParse();\n\t\tif (Error()) {\n\t\t\t// clean up now essentially dangling memory.\n\t\t\t// and the parse fail can put objects in the\n\t\t\t// pools that are dead and inaccessible.\n\t\t\tDeleteChildren();\n\t\t\t_elementPool.Clear();\n\t\t\t_attributePool.Clear();\n\t\t\t_textPool.Clear();\n\t\t\t_commentPool.Clear();\n\t\t}\n\t\treturn _errorID;\n\t}\n\n\n\tvoid XMLDocument::Print(XMLPrinter* streamer) const\n\t{\n\t\tif (streamer) {\n\t\t\tAccept(streamer);\n\t\t}\n\t\telse {\n\t\t\tXMLPrinter stdoutStreamer(stdout);\n\t\t\tAccept(&stdoutStreamer);\n\t\t}\n\t}\n\n\n\tvoid XMLDocument::SetError(XMLError error, const char* str1, const char* str2, int lineNum)\n\t{\n\t\tTIXMLASSERT(error >= 0 && error < XML_ERROR_COUNT);\n\t\t_errorID = error;\n\n\t\t_errorStr1.Reset();\n\t\t_errorStr2.Reset();\n\t\t_errorLineNum = lineNum;\n\n\t\tif (str1)\n\t\t\t_errorStr1.SetStr(str1);\n\t\tif (str2)\n\t\t\t_errorStr2.SetStr(str2);\n\t}\n\n\t/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)\n\t{\n\t\tTIXMLASSERT(errorID >= 0 && errorID < XML_ERROR_COUNT);\n\t\tconst char* errorName = _errorNames[errorID];\n\t\tTIXMLASSERT(errorName && errorName[0]);\n\t\treturn errorName;\n\t}\n\n\tconst char* XMLDocument::GetErrorStr1() const\n\t{\n\t\treturn _errorStr1.GetStr();\n\t}\n\n\tconst char* XMLDocument::GetErrorStr2() const\n\t{\n\t\treturn _errorStr2.GetStr();\n\t}\n\n\tconst char* XMLDocument::ErrorName() const\n\t{\n\t\treturn ErrorIDToName(_errorID);\n\t}\n\n\tvoid XMLDocument::PrintError() const\n\t{\n\t\tif (Error()) {\n\t\t\tstatic const int LEN = 20;\n\t\t\tchar buf1[LEN] = { 0 };\n\t\t\tchar buf2[LEN] = { 0 };\n\n\t\t\tif (!_errorStr1.Empty()) {\n\t\t\t\tTIXML_SNPRINTF(buf1, LEN, \"%s\", _errorStr1.GetStr());\n\t\t\t}\n\t\t\tif (!_errorStr2.Empty()) {\n\t\t\t\tTIXML_SNPRINTF(buf2, LEN, \"%s\", _errorStr2.GetStr());\n\t\t\t}\n\n\t\t\t// Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that\n\t\t\t// causes a clang \"always true\" -Wtautological-constant-out-of-range-compare warning\n\t\t\tTIXMLASSERT(0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX);\n\t\t\tprintf(\"XMLDocument error id=%d '%s' str1=%s str2=%s line=%d\\n\",\n\t\t\t\tstatic_cast<int>(_errorID), ErrorName(), buf1, buf2, _errorLineNum);\n\t\t}\n\t}\n\n\tvoid XMLDocument::Parse()\n\t{\n\t\tTIXMLASSERT(NoChildren()); // Clear() must have been called previously\n\t\tTIXMLASSERT(_charBuffer);\n\t\t_parseCurLineNum = 1;\n\t\t_parseLineNum = 1;\n\t\tchar* p = _charBuffer;\n\t\tp = XMLUtil::SkipWhiteSpace(p, &_parseCurLineNum);\n\t\tp = const_cast<char*>(XMLUtil::ReadBOM(p, &_writeBOM));\n\t\tif (!*p) {\n\t\t\tSetError(XML_ERROR_EMPTY_DOCUMENT, 0, 0, 0);\n\t\t\treturn;\n\t\t}\n\t\tParseDeep(p, 0, &_parseCurLineNum);\n\t}\n\n\tXMLPrinter::XMLPrinter(FILE* file, bool compact, int depth) :\n\t\t_elementJustOpened(false),\n\t\t_stack(),\n\t\t_firstElement(true),\n\t\t_fp(file),\n\t\t_depth(depth),\n\t\t_textDepth(-1),\n\t\t_processEntities(true),\n\t\t_compactMode(compact),\n\t\t_buffer()\n\t{\n\t\tfor (int i = 0; i<ENTITY_RANGE; ++i) {\n\t\t\t_entityFlag[i] = false;\n\t\t\t_restrictedEntityFlag[i] = false;\n\t\t}\n\t\tfor (int i = 0; i<NUM_ENTITIES; ++i) {\n\t\t\tconst char entityValue = entities[i].value;\n\t\t\tconst unsigned char flagIndex = (unsigned char)entityValue;\n\t\t\tTIXMLASSERT(flagIndex < ENTITY_RANGE);\n\t\t\t_entityFlag[flagIndex] = true;\n\t\t}\n\t\t_restrictedEntityFlag[(unsigned char)'&'] = true;\n\t\t_restrictedEntityFlag[(unsigned char)'<'] = true;\n\t\t_restrictedEntityFlag[(unsigned char)'>'] = true;\t// not required, but consistency is nice\n\t\t_buffer.Push(0);\n\t}\n\n\n\tvoid XMLPrinter::Print(const char* format, ...)\n\t{\n\t\tva_list     va;\n\t\tva_start(va, format);\n\n\t\tif (_fp) {\n\t\t\tvfprintf(_fp, format, va);\n\t\t}\n\t\telse {\n\t\t\tconst int len = TIXML_VSCPRINTF(format, va);\n\t\t\t// Close out and re-start the va-args\n\t\t\tva_end(va);\n\t\t\tTIXMLASSERT(len >= 0);\n\t\t\tva_start(va, format);\n\t\t\tTIXMLASSERT(_buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0);\n\t\t\tchar* p = _buffer.PushArr(len) - 1;\t// back up over the null terminator.\n\t\t\tTIXML_VSNPRINTF(p, len + 1, format, va);\n\t\t}\n\t\tva_end(va);\n\t}\n\n\n\tvoid XMLPrinter::PrintSpace(int depth)\n\t{\n\t\tfor (int i = 0; i<depth; ++i) {\n\t\t\tPrint(\"    \");\n\t\t}\n\t}\n\n\n\tvoid XMLPrinter::PrintString(const char* p, bool restricted)\n\t{\n\t\t// Look for runs of bytes between entities to print.\n\t\tconst char* q = p;\n\n\t\tif (_processEntities) {\n\t\t\tconst bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;\n\t\t\twhile (*q) {\n\t\t\t\tTIXMLASSERT(p <= q);\n\t\t\t\t// Remember, char is sometimes signed. (How many times has that bitten me?)\n\t\t\t\tif (*q > 0 && *q < ENTITY_RANGE) {\n\t\t\t\t\t// Check for entities. If one is found, flush\n\t\t\t\t\t// the stream up until the entity, write the\n\t\t\t\t\t// entity, and keep looking.\n\t\t\t\t\tif (flag[(unsigned char)(*q)]) {\n\t\t\t\t\t\twhile (p < q) {\n\t\t\t\t\t\t\tconst size_t delta = q - p;\n\t\t\t\t\t\t\t// %.*s accepts type int as \"precision\"\n\t\t\t\t\t\t\tconst int toPrint = (INT_MAX < delta) ? INT_MAX : (int)delta;\n\t\t\t\t\t\t\tPrint(\"%.*s\", toPrint, p);\n\t\t\t\t\t\t\tp += toPrint;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbool entityPatternPrinted = false;\n\t\t\t\t\t\tfor (int i = 0; i<NUM_ENTITIES; ++i) {\n\t\t\t\t\t\t\tif (entities[i].value == *q) {\n\t\t\t\t\t\t\t\tPrint(\"&%s;\", entities[i].pattern);\n\t\t\t\t\t\t\t\tentityPatternPrinted = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!entityPatternPrinted) {\n\t\t\t\t\t\t\t// TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release\n\t\t\t\t\t\t\tTIXMLASSERT(false);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t++p;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t++q;\n\t\t\t\tTIXMLASSERT(p <= q);\n\t\t\t}\n\t\t}\n\t\t// Flush the remaining string. This will be the entire\n\t\t// string if an entity wasn't found.\n\t\tTIXMLASSERT(p <= q);\n\t\tif (!_processEntities || (p < q)) {\n\t\t\tPrint(\"%s\", p);\n\t\t}\n\t}\n\n\n\tvoid XMLPrinter::PushHeader(bool writeBOM, bool writeDec)\n\t{\n\t\tif (writeBOM) {\n\t\t\tstatic const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };\n\t\t\tPrint(\"%s\", bom);\n\t\t}\n\t\tif (writeDec) {\n\t\t\tPushDeclaration(\"xml version=\\\"1.0\\\"\");\n\t\t}\n\t}\n\n\n\tvoid XMLPrinter::OpenElement(const char* name, bool compactMode)\n\t{\n\t\tSealElementIfJustOpened();\n\t\t_stack.Push(name);\n\n\t\tif (_textDepth < 0 && !_firstElement && !compactMode) {\n\t\t\tPrint(\"\\n\");\n\t\t}\n\t\tif (!compactMode) {\n\t\t\tPrintSpace(_depth);\n\t\t}\n\n\t\tPrint(\"<%s\", name);\n\t\t_elementJustOpened = true;\n\t\t_firstElement = false;\n\t\t++_depth;\n\t}\n\n\n\tvoid XMLPrinter::PushAttribute(const char* name, const char* value)\n\t{\n\t\tTIXMLASSERT(_elementJustOpened);\n\t\tPrint(\" %s=\\\"\", name);\n\t\tPrintString(value, false);\n\t\tPrint(\"\\\"\");\n\t}\n\n\n\tvoid XMLPrinter::PushAttribute(const char* name, int v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tPushAttribute(name, buf);\n\t}\n\n\n\tvoid XMLPrinter::PushAttribute(const char* name, unsigned v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tPushAttribute(name, buf);\n\t}\n\n\n\tvoid XMLPrinter::PushAttribute(const char* name, int64_t v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tPushAttribute(name, buf);\n\t}\n\n\n\tvoid XMLPrinter::PushAttribute(const char* name, bool v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tPushAttribute(name, buf);\n\t}\n\n\n\tvoid XMLPrinter::PushAttribute(const char* name, double v)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t\tPushAttribute(name, buf);\n\t}\n\n\n\tvoid XMLPrinter::CloseElement(bool compactMode)\n\t{\n\t\t--_depth;\n\t\tconst char* name = _stack.Pop();\n\n\t\tif (_elementJustOpened) {\n\t\t\tPrint(\"/>\");\n\t\t}\n\t\telse {\n\t\t\tif (_textDepth < 0 && !compactMode) {\n\t\t\t\tPrint(\"\\n\");\n\t\t\t\tPrintSpace(_depth);\n\t\t\t}\n\t\t\tPrint(\"</%s>\", name);\n\t\t}\n\n\t\tif (_textDepth == _depth) {\n\t\t\t_textDepth = -1;\n\t\t}\n\t\tif (_depth == 0 && !compactMode) {\n\t\t\tPrint(\"\\n\");\n\t\t}\n\t\t_elementJustOpened = false;\n\t}\n\n\n\tvoid XMLPrinter::SealElementIfJustOpened()\n\t{\n\t\tif (!_elementJustOpened) {\n\t\t\treturn;\n\t\t}\n\t\t_elementJustOpened = false;\n\t\tPrint(\">\");\n\t}\n\n\n\tvoid XMLPrinter::PushText(const char* text, bool cdata)\n\t{\n\t\t_textDepth = _depth - 1;\n\n\t\tSealElementIfJustOpened();\n\t\tif (cdata) {\n\t\t\tPrint(\"<![CDATA[%s]]>\", text);\n\t\t}\n\t\telse {\n\t\t\tPrintString(text, true);\n\t\t}\n\t}\n\n\tvoid XMLPrinter::PushText(int64_t value)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(value, buf, BUF_SIZE);\n\t\tPushText(buf, false);\n\t}\n\n\tvoid XMLPrinter::PushText(int value)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(value, buf, BUF_SIZE);\n\t\tPushText(buf, false);\n\t}\n\n\n\tvoid XMLPrinter::PushText(unsigned value)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(value, buf, BUF_SIZE);\n\t\tPushText(buf, false);\n\t}\n\n\n\tvoid XMLPrinter::PushText(bool value)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(value, buf, BUF_SIZE);\n\t\tPushText(buf, false);\n\t}\n\n\n\tvoid XMLPrinter::PushText(float value)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(value, buf, BUF_SIZE);\n\t\tPushText(buf, false);\n\t}\n\n\n\tvoid XMLPrinter::PushText(double value)\n\t{\n\t\tchar buf[BUF_SIZE];\n\t\tXMLUtil::ToStr(value, buf, BUF_SIZE);\n\t\tPushText(buf, false);\n\t}\n\n\n\tvoid XMLPrinter::PushComment(const char* comment)\n\t{\n\t\tSealElementIfJustOpened();\n\t\tif (_textDepth < 0 && !_firstElement && !_compactMode) {\n\t\t\tPrint(\"\\n\");\n\t\t\tPrintSpace(_depth);\n\t\t}\n\t\t_firstElement = false;\n\t\tPrint(\"<!--%s-->\", comment);\n\t}\n\n\n\tvoid XMLPrinter::PushDeclaration(const char* value)\n\t{\n\t\tSealElementIfJustOpened();\n\t\tif (_textDepth < 0 && !_firstElement && !_compactMode) {\n\t\t\tPrint(\"\\n\");\n\t\t\tPrintSpace(_depth);\n\t\t}\n\t\t_firstElement = false;\n\t\tPrint(\"<?%s?>\", value);\n\t}\n\n\n\tvoid XMLPrinter::PushUnknown(const char* value)\n\t{\n\t\tSealElementIfJustOpened();\n\t\tif (_textDepth < 0 && !_firstElement && !_compactMode) {\n\t\t\tPrint(\"\\n\");\n\t\t\tPrintSpace(_depth);\n\t\t}\n\t\t_firstElement = false;\n\t\tPrint(\"<!%s>\", value);\n\t}\n\n\n\tbool XMLPrinter::VisitEnter(const XMLDocument& doc)\n\t{\n\t\t_processEntities = doc.ProcessEntities();\n\t\tif (doc.HasBOM()) {\n\t\t\tPushHeader(true, false);\n\t\t}\n\t\treturn true;\n\t}\n\n\n\tbool XMLPrinter::VisitEnter(const XMLElement& element, const XMLAttribute* attribute)\n\t{\n\t\tconst XMLElement* parentElem = 0;\n\t\tif (element.Parent()) {\n\t\t\tparentElem = element.Parent()->ToElement();\n\t\t}\n\t\tconst bool compactMode = parentElem ? CompactMode(*parentElem) : _compactMode;\n\t\tOpenElement(element.Name(), compactMode);\n\t\twhile (attribute) {\n\t\t\tPushAttribute(attribute->Name(), attribute->Value());\n\t\t\tattribute = attribute->Next();\n\t\t}\n\t\treturn true;\n\t}\n\n\n\tbool XMLPrinter::VisitExit(const XMLElement& element)\n\t{\n\t\tCloseElement(CompactMode(element));\n\t\treturn true;\n\t}\n\n\n\tbool XMLPrinter::Visit(const XMLText& text)\n\t{\n\t\tPushText(text.Value(), text.CData());\n\t\treturn true;\n\t}\n\n\n\tbool XMLPrinter::Visit(const XMLComment& comment)\n\t{\n\t\tPushComment(comment.Value());\n\t\treturn true;\n\t}\n\n\tbool XMLPrinter::Visit(const XMLDeclaration& declaration)\n\t{\n\t\tPushDeclaration(declaration.Value());\n\t\treturn true;\n\t}\n\n\n\tbool XMLPrinter::Visit(const XMLUnknown& unknown)\n\t{\n\t\tPushUnknown(unknown.Value());\n\t\treturn true;\n\t}\n\n}   // namespace tinyxml2\n\n"
  },
  {
    "path": "src/util/tinyxml2/tinyxml2.h",
    "content": "/*\nOriginal code by Lee Thomason (www.grinninglizard.com)\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any\ndamages arising from the use of this software.\n\nPermission is granted to anyone to use this software for any\npurpose, including commercial applications, and to alter it and\nredistribute it freely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must\nnot claim that you wrote the original software. If you use this\nsoftware in a product, an acknowledgment in the product documentation\nwould be appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and\nmust not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source\ndistribution.\n*/\n\n#ifndef TINYXML2_INCLUDED\n#define TINYXML2_INCLUDED\n\n#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)\n#   include <ctype.h>\n#   include <limits.h>\n#   include <stdio.h>\n#   include <stdlib.h>\n#   include <string.h>\n#\tif defined(__PS3__)\n#\t\tinclude <stddef.h>\n#\tendif\n#else\n#   include <cctype>\n#   include <climits>\n#   include <cstdio>\n#   include <cstdlib>\n#   include <cstring>\n#endif\n#include <stdint.h>\n\n/*\nTODO: intern strings instead of allocation.\n*/\n/*\ngcc:\ng++ -Wall -DDEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe\n\nFormatting, Artistic Style:\nAStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h\n*/\n\n#if defined( _DEBUG ) || defined (__DEBUG__)\n#   ifndef DEBUG\n#       define DEBUG\n#   endif\n#endif\n\n#ifdef _MSC_VER\n#   pragma warning(push)\n#   pragma warning(disable: 4251)\n#endif\n\n#ifdef _WIN32\n#   ifdef TINYXML2_EXPORT\n#       define TINYXML2_LIB __declspec(dllexport)\n#   elif defined(TINYXML2_IMPORT)\n#       define TINYXML2_LIB __declspec(dllimport)\n#   else\n#       define TINYXML2_LIB\n#   endif\n#elif __GNUC__ >= 4\n#   define TINYXML2_LIB __attribute__((visibility(\"default\")))\n#else\n#   define TINYXML2_LIB\n#endif\n\n\n#if defined(DEBUG)\n#   if defined(_MSC_VER)\n#       // \"(void)0,\" is for suppressing C4127 warning in \"assert(false)\", \"assert(true)\" and the like\n#       define TIXMLASSERT( x )           if ( !((void)0,(x))) { __debugbreak(); }\n#   elif defined (ANDROID_NDK)\n#       include <android/log.h>\n#       define TIXMLASSERT( x )           if ( !(x)) { __android_log_assert( \"assert\", \"grinliz\", \"ASSERT in '%s' at %d.\", __FILE__, __LINE__ ); }\n#   else\n#       include <assert.h>\n#       define TIXMLASSERT                assert\n#   endif\n#else\n#   define TIXMLASSERT( x )               {}\n#endif\n\n\n/* Versioning, past 1.0.14:\nhttp://semver.org/\n*/\nstatic const int TIXML2_MAJOR_VERSION = 5;\nstatic const int TIXML2_MINOR_VERSION = 0;\nstatic const int TIXML2_PATCH_VERSION = 1;\n\nnamespace tinyxml2\n{\n\tclass XMLDocument;\n\tclass XMLElement;\n\tclass XMLAttribute;\n\tclass XMLComment;\n\tclass XMLText;\n\tclass XMLDeclaration;\n\tclass XMLUnknown;\n\tclass XMLPrinter;\n\n\t/*\n\tA class that wraps strings. Normally stores the start and end\n\tpointers into the XML file itself, and will apply normalization\n\tand entity translation if actually read. Can also store (and memory\n\tmanage) a traditional char[]\n\t*/\n\tclass StrPair\n\t{\n\tpublic:\n\t\tenum {\n\t\t\tNEEDS_ENTITY_PROCESSING = 0x01,\n\t\t\tNEEDS_NEWLINE_NORMALIZATION = 0x02,\n\t\t\tNEEDS_WHITESPACE_COLLAPSING = 0x04,\n\n\t\t\tTEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,\n\t\t\tTEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,\n\t\t\tATTRIBUTE_NAME = 0,\n\t\t\tATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,\n\t\t\tATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,\n\t\t\tCOMMENT = NEEDS_NEWLINE_NORMALIZATION\n\t\t};\n\n\t\tStrPair() : _flags(0), _start(0), _end(0) {}\n\t\t~StrPair();\n\n\t\tvoid Set(char* start, char* end, int flags) {\n\t\t\tTIXMLASSERT(start);\n\t\t\tTIXMLASSERT(end);\n\t\t\tReset();\n\t\t\t_start = start;\n\t\t\t_end = end;\n\t\t\t_flags = flags | NEEDS_FLUSH;\n\t\t}\n\n\t\tconst char* GetStr();\n\n\t\tbool Empty() const {\n\t\t\treturn _start == _end;\n\t\t}\n\n\t\tvoid SetInternedStr(const char* str) {\n\t\t\tReset();\n\t\t\t_start = const_cast<char*>(str);\n\t\t}\n\n\t\tvoid SetStr(const char* str, int flags = 0);\n\n\t\tchar* ParseText(char* in, const char* endTag, int strFlags, int* curLineNumPtr);\n\t\tchar* ParseName(char* in);\n\n\t\tvoid TransferTo(StrPair* other);\n\t\tvoid Reset();\n\n\tprivate:\n\t\tvoid CollapseWhitespace();\n\n\t\tenum {\n\t\t\tNEEDS_FLUSH = 0x100,\n\t\t\tNEEDS_DELETE = 0x200\n\t\t};\n\n\t\tint     _flags;\n\t\tchar*   _start;\n\t\tchar*   _end;\n\n\t\tStrPair(const StrPair& other);\t// not supported\n\t\tvoid operator=(StrPair& other);\t// not supported, use TransferTo()\n\t};\n\n\n\t/*\n\tA dynamic array of Plain Old Data. Doesn't support constructors, etc.\n\tHas a small initial memory pool, so that low or no usage will not\n\tcause a call to new/delete\n\t*/\n\ttemplate <class T, int INITIAL_SIZE>\n\tclass DynArray\n\t{\n\tpublic:\n\t\tDynArray() :\n\t\t\t_mem(_pool),\n\t\t\t_allocated(INITIAL_SIZE),\n\t\t\t_size(0)\n\t\t{\n\t\t}\n\n\t\t~DynArray() {\n\t\t\tif (_mem != _pool) {\n\t\t\t\tdelete[] _mem;\n\t\t\t}\n\t\t}\n\n\t\tvoid Clear() {\n\t\t\t_size = 0;\n\t\t}\n\n\t\tvoid Push(T t) {\n\t\t\tTIXMLASSERT(_size < INT_MAX);\n\t\t\tEnsureCapacity(_size + 1);\n\t\t\t_mem[_size] = t;\n\t\t\t++_size;\n\t\t}\n\n\t\tT* PushArr(int count) {\n\t\t\tTIXMLASSERT(count >= 0);\n\t\t\tTIXMLASSERT(_size <= INT_MAX - count);\n\t\t\tEnsureCapacity(_size + count);\n\t\t\tT* ret = &_mem[_size];\n\t\t\t_size += count;\n\t\t\treturn ret;\n\t\t}\n\n\t\tT Pop() {\n\t\t\tTIXMLASSERT(_size > 0);\n\t\t\t--_size;\n\t\t\treturn _mem[_size];\n\t\t}\n\n\t\tvoid PopArr(int count) {\n\t\t\tTIXMLASSERT(_size >= count);\n\t\t\t_size -= count;\n\t\t}\n\n\t\tbool Empty() const {\n\t\t\treturn _size == 0;\n\t\t}\n\n\t\tT& operator[](int i) {\n\t\t\tTIXMLASSERT(i >= 0 && i < _size);\n\t\t\treturn _mem[i];\n\t\t}\n\n\t\tconst T& operator[](int i) const {\n\t\t\tTIXMLASSERT(i >= 0 && i < _size);\n\t\t\treturn _mem[i];\n\t\t}\n\n\t\tconst T& PeekTop() const {\n\t\t\tTIXMLASSERT(_size > 0);\n\t\t\treturn _mem[_size - 1];\n\t\t}\n\n\t\tint Size() const {\n\t\t\tTIXMLASSERT(_size >= 0);\n\t\t\treturn _size;\n\t\t}\n\n\t\tint Capacity() const {\n\t\t\tTIXMLASSERT(_allocated >= INITIAL_SIZE);\n\t\t\treturn _allocated;\n\t\t}\n\n\t\tvoid SwapRemove(int i) {\n\t\t\tTIXMLASSERT(i >= 0 && i < _size);\n\t\t\tTIXMLASSERT(_size > 0);\n\t\t\t_mem[i] = _mem[_size - 1];\n\t\t\t--_size;\n\t\t}\n\n\t\tconst T* Mem() const {\n\t\t\tTIXMLASSERT(_mem);\n\t\t\treturn _mem;\n\t\t}\n\n\t\tT* Mem() {\n\t\t\tTIXMLASSERT(_mem);\n\t\t\treturn _mem;\n\t\t}\n\n\tprivate:\n\t\tDynArray(const DynArray&); // not supported\n\t\tvoid operator=(const DynArray&); // not supported\n\n\t\tvoid EnsureCapacity(int cap) {\n\t\t\tTIXMLASSERT(cap > 0);\n\t\t\tif (cap > _allocated) {\n\t\t\t\tTIXMLASSERT(cap <= INT_MAX / 2);\n\t\t\t\tint newAllocated = cap * 2;\n\t\t\t\tT* newMem = new T[newAllocated];\n\t\t\t\tTIXMLASSERT(newAllocated >= _size);\n\t\t\t\tmemcpy(newMem, _mem, sizeof(T)*_size);\t// warning: not using constructors, only works for PODs\n\t\t\t\tif (_mem != _pool) {\n\t\t\t\t\tdelete[] _mem;\n\t\t\t\t}\n\t\t\t\t_mem = newMem;\n\t\t\t\t_allocated = newAllocated;\n\t\t\t}\n\t\t}\n\n\t\tT*  _mem;\n\t\tT   _pool[INITIAL_SIZE];\n\t\tint _allocated;\t\t// objects allocated\n\t\tint _size;\t\t\t// number objects in use\n\t};\n\n\n\t/*\n\tParent virtual class of a pool for fast allocation\n\tand deallocation of objects.\n\t*/\n\tclass MemPool\n\t{\n\tpublic:\n\t\tMemPool() {}\n\t\tvirtual ~MemPool() {}\n\n\t\tvirtual int ItemSize() const = 0;\n\t\tvirtual void* Alloc() = 0;\n\t\tvirtual void Free(void*) = 0;\n\t\tvirtual void SetTracked() = 0;\n\t\tvirtual void Clear() = 0;\n\t};\n\n\n\t/*\n\tTemplate child class to create pools of the correct type.\n\t*/\n\ttemplate< int ITEM_SIZE >\n\tclass MemPoolT : public MemPool\n\t{\n\tpublic:\n\t\tMemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}\n\t\t~MemPoolT() {\n\t\t\tClear();\n\t\t}\n\n\t\tvoid Clear() {\n\t\t\t// Delete the blocks.\n\t\t\twhile (!_blockPtrs.Empty()) {\n\t\t\t\tBlock* lastBlock = _blockPtrs.Pop();\n\t\t\t\tdelete lastBlock;\n\t\t\t}\n\t\t\t_root = 0;\n\t\t\t_currentAllocs = 0;\n\t\t\t_nAllocs = 0;\n\t\t\t_maxAllocs = 0;\n\t\t\t_nUntracked = 0;\n\t\t}\n\n\t\tvirtual int ItemSize() const {\n\t\t\treturn ITEM_SIZE;\n\t\t}\n\t\tint CurrentAllocs() const {\n\t\t\treturn _currentAllocs;\n\t\t}\n\n\t\tvirtual void* Alloc() {\n\t\t\tif (!_root) {\n\t\t\t\t// Need a new block.\n\t\t\t\tBlock* block = new Block();\n\t\t\t\t_blockPtrs.Push(block);\n\n\t\t\t\tItem* blockItems = block->items;\n\t\t\t\tfor (int i = 0; i < ITEMS_PER_BLOCK - 1; ++i) {\n\t\t\t\t\tblockItems[i].next = &(blockItems[i + 1]);\n\t\t\t\t}\n\t\t\t\tblockItems[ITEMS_PER_BLOCK - 1].next = 0;\n\t\t\t\t_root = blockItems;\n\t\t\t}\n\t\t\tItem* const result = _root;\n\t\t\tTIXMLASSERT(result != 0);\n\t\t\t_root = _root->next;\n\n\t\t\t++_currentAllocs;\n\t\t\tif (_currentAllocs > _maxAllocs) {\n\t\t\t\t_maxAllocs = _currentAllocs;\n\t\t\t}\n\t\t\t++_nAllocs;\n\t\t\t++_nUntracked;\n\t\t\treturn result;\n\t\t}\n\n\t\tvirtual void Free(void* mem) {\n\t\t\tif (!mem) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t--_currentAllocs;\n\t\t\tItem* item = static_cast<Item*>(mem);\n#ifdef DEBUG\n\t\t\tmemset(item, 0xfe, sizeof(*item));\n#endif\n\t\t\titem->next = _root;\n\t\t\t_root = item;\n\t\t}\n\t\tvoid Trace(const char* name) {\n\t\t\tprintf(\"Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\\n\",\n\t\t\t\tname, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs,\n\t\t\t\tITEM_SIZE, _nAllocs, _blockPtrs.Size());\n\t\t}\n\n\t\tvoid SetTracked() {\n\t\t\t--_nUntracked;\n\t\t}\n\n\t\tint Untracked() const {\n\t\t\treturn _nUntracked;\n\t\t}\n\n\t\t// This number is perf sensitive. 4k seems like a good tradeoff on my machine.\n\t\t// The test file is large, 170k.\n\t\t// Release:\t\tVS2010 gcc(no opt)\n\t\t//\t\t1k:\t\t4000\n\t\t//\t\t2k:\t\t4000\n\t\t//\t\t4k:\t\t3900\t21000\n\t\t//\t\t16k:\t5200\n\t\t//\t\t32k:\t4300\n\t\t//\t\t64k:\t4000\t21000\n\t\t// Declared public because some compilers do not accept to use ITEMS_PER_BLOCK\n\t\t// in private part if ITEMS_PER_BLOCK is private\n\t\tenum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE };\n\n\tprivate:\n\t\tMemPoolT(const MemPoolT&); // not supported\n\t\tvoid operator=(const MemPoolT&); // not supported\n\n\t\tunion Item {\n\t\t\tItem*   next;\n\t\t\tchar    itemData[ITEM_SIZE];\n\t\t};\n\t\tstruct Block {\n\t\t\tItem items[ITEMS_PER_BLOCK];\n\t\t};\n\t\tDynArray< Block*, 10 > _blockPtrs;\n\t\tItem* _root;\n\n\t\tint _currentAllocs;\n\t\tint _nAllocs;\n\t\tint _maxAllocs;\n\t\tint _nUntracked;\n\t};\n\n\n\n\t/**\n\tImplements the interface to the \"Visitor pattern\" (see the Accept() method.)\n\tIf you call the Accept() method, it requires being passed a XMLVisitor\n\tclass to handle callbacks. For nodes that contain other nodes (Document, Element)\n\tyou will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs\n\tare simply called with Visit().\n\n\tIf you return 'true' from a Visit method, recursive parsing will continue. If you return\n\tfalse, <b>no children of this node or its siblings</b> will be visited.\n\n\tAll flavors of Visit methods have a default implementation that returns 'true' (continue\n\tvisiting). You need to only override methods that are interesting to you.\n\n\tGenerally Accept() is called on the XMLDocument, although all nodes support visiting.\n\n\tYou should never change the document from a callback.\n\n\t@sa XMLNode::Accept()\n\t*/\n\tclass TINYXML2_LIB XMLVisitor\n\t{\n\tpublic:\n\t\tvirtual ~XMLVisitor() {}\n\n\t\t/// Visit a document.\n\t\tvirtual bool VisitEnter(const XMLDocument& /*doc*/) {\n\t\t\treturn true;\n\t\t}\n\t\t/// Visit a document.\n\t\tvirtual bool VisitExit(const XMLDocument& /*doc*/) {\n\t\t\treturn true;\n\t\t}\n\n\t\t/// Visit an element.\n\t\tvirtual bool VisitEnter(const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/) {\n\t\t\treturn true;\n\t\t}\n\t\t/// Visit an element.\n\t\tvirtual bool VisitExit(const XMLElement& /*element*/) {\n\t\t\treturn true;\n\t\t}\n\n\t\t/// Visit a declaration.\n\t\tvirtual bool Visit(const XMLDeclaration& /*declaration*/) {\n\t\t\treturn true;\n\t\t}\n\t\t/// Visit a text node.\n\t\tvirtual bool Visit(const XMLText& /*text*/) {\n\t\t\treturn true;\n\t\t}\n\t\t/// Visit a comment node.\n\t\tvirtual bool Visit(const XMLComment& /*comment*/) {\n\t\t\treturn true;\n\t\t}\n\t\t/// Visit an unknown node.\n\t\tvirtual bool Visit(const XMLUnknown& /*unknown*/) {\n\t\t\treturn true;\n\t\t}\n\t};\n\n\t// WARNING: must match XMLDocument::_errorNames[]\n\tenum XMLError {\n\t\tXML_SUCCESS = 0,\n\t\tXML_NO_ATTRIBUTE,\n\t\tXML_WRONG_ATTRIBUTE_TYPE,\n\t\tXML_ERROR_FILE_NOT_FOUND,\n\t\tXML_ERROR_FILE_COULD_NOT_BE_OPENED,\n\t\tXML_ERROR_FILE_READ_ERROR,\n\t\tUNUSED_XML_ERROR_ELEMENT_MISMATCH,\t// remove at next major version\n\t\tXML_ERROR_PARSING_ELEMENT,\n\t\tXML_ERROR_PARSING_ATTRIBUTE,\n\t\tUNUSED_XML_ERROR_IDENTIFYING_TAG,\t// remove at next major version\n\t\tXML_ERROR_PARSING_TEXT,\n\t\tXML_ERROR_PARSING_CDATA,\n\t\tXML_ERROR_PARSING_COMMENT,\n\t\tXML_ERROR_PARSING_DECLARATION,\n\t\tXML_ERROR_PARSING_UNKNOWN,\n\t\tXML_ERROR_EMPTY_DOCUMENT,\n\t\tXML_ERROR_MISMATCHED_ELEMENT,\n\t\tXML_ERROR_PARSING,\n\t\tXML_CAN_NOT_CONVERT_TEXT,\n\t\tXML_NO_TEXT_NODE,\n\n\t\tXML_ERROR_COUNT\n\t};\n\n\n\t/*\n\tUtility functionality.\n\t*/\n\tclass TINYXML2_LIB XMLUtil\n\t{\n\tpublic:\n\t\tstatic const char* SkipWhiteSpace(const char* p, int* curLineNumPtr) {\n\t\t\tTIXMLASSERT(p);\n\n\t\t\twhile (IsWhiteSpace(*p)) {\n\t\t\t\tif (curLineNumPtr && *p == '\\n') {\n\t\t\t\t\t++(*curLineNumPtr);\n\t\t\t\t}\n\t\t\t\t++p;\n\t\t\t}\n\t\t\tTIXMLASSERT(p);\n\t\t\treturn p;\n\t\t}\n\t\tstatic char* SkipWhiteSpace(char* p, int* curLineNumPtr) {\n\t\t\treturn const_cast<char*>(SkipWhiteSpace(const_cast<const char*>(p), curLineNumPtr));\n\t\t}\n\n\t\t// Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't\n\t\t// correct, but simple, and usually works.\n\t\tstatic bool IsWhiteSpace(char p) {\n\t\t\treturn !IsUTF8Continuation(p) && isspace(static_cast<unsigned char>(p));\n\t\t}\n\n\t\tinline static bool IsNameStartChar(unsigned char ch) {\n\t\t\tif (ch >= 128) {\n\t\t\t\t// This is a heuristic guess in attempt to not implement Unicode-aware isalpha()\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (isalpha(ch)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn ch == ':' || ch == '_';\n\t\t}\n\n\t\tinline static bool IsNameChar(unsigned char ch) {\n\t\t\treturn IsNameStartChar(ch)\n\t\t\t\t|| isdigit(ch)\n\t\t\t\t|| ch == '.'\n\t\t\t\t|| ch == '-';\n\t\t}\n\n\t\tinline static bool StringEqual(const char* p, const char* q, int nChar = INT_MAX) {\n\t\t\tif (p == q) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tTIXMLASSERT(p);\n\t\t\tTIXMLASSERT(q);\n\t\t\tTIXMLASSERT(nChar >= 0);\n\t\t\treturn strncmp(p, q, nChar) == 0;\n\t\t}\n\n\t\tinline static bool IsUTF8Continuation(char p) {\n\t\t\treturn (p & 0x80) != 0;\n\t\t}\n\n\t\tstatic const char* ReadBOM(const char* p, bool* hasBOM);\n\t\t// p is the starting location,\n\t\t// the UTF-8 value of the entity will be placed in value, and length filled in.\n\t\tstatic const char* GetCharacterRef(const char* p, char* value, int* length);\n\t\tstatic void ConvertUTF32ToUTF8(unsigned long input, char* output, int* length);\n\n\t\t// converts primitive types to strings\n\t\tstatic void ToStr(int v, char* buffer, int bufferSize);\n\t\tstatic void ToStr(unsigned v, char* buffer, int bufferSize);\n\t\tstatic void ToStr(bool v, char* buffer, int bufferSize);\n\t\tstatic void ToStr(float v, char* buffer, int bufferSize);\n\t\tstatic void ToStr(double v, char* buffer, int bufferSize);\n\t\tstatic void ToStr(int64_t v, char* buffer, int bufferSize);\n\n\t\t// converts strings to primitive types\n\t\tstatic bool\tToInt(const char* str, int* value);\n\t\tstatic bool ToUnsigned(const char* str, unsigned* value);\n\t\tstatic bool\tToBool(const char* str, bool* value);\n\t\tstatic bool\tToFloat(const char* str, float* value);\n\t\tstatic bool ToDouble(const char* str, double* value);\n\t\tstatic bool ToInt64(const char* str, int64_t* value);\n\n\t\t// Changes what is serialized for a boolean value.\n\t\t// Default to \"true\" and \"false\". Shouldn't be changed\n\t\t// unless you have a special testing or compatibility need.\n\t\t// Be careful: static, global, & not thread safe.\n\t\t// Be sure to set static const memory as parameters.\n\t\tstatic void SetBoolSerialization(const char* writeTrue, const char* writeFalse);\n\n\tprivate:\n\t\tstatic const char* writeBoolTrue;\n\t\tstatic const char* writeBoolFalse;\n\t};\n\n\n\t/** XMLNode is a base class for every object that is in the\n\tXML Document Object Model (DOM), except XMLAttributes.\n\tNodes have siblings, a parent, and children which can\n\tbe navigated. A node is always in a XMLDocument.\n\tThe type of a XMLNode can be queried, and it can\n\tbe cast to its more defined type.\n\n\tA XMLDocument allocates memory for all its Nodes.\n\tWhen the XMLDocument gets deleted, all its Nodes\n\twill also be deleted.\n\n\t@verbatim\n\tA Document can contain:\tElement\t(container or leaf)\n\tComment (leaf)\n\tUnknown (leaf)\n\tDeclaration( leaf )\n\n\tAn Element can contain:\tElement (container or leaf)\n\tText\t(leaf)\n\tAttributes (not on tree)\n\tComment (leaf)\n\tUnknown (leaf)\n\n\t@endverbatim\n\t*/\n\tclass TINYXML2_LIB XMLNode\n\t{\n\t\tfriend class XMLDocument;\n\t\tfriend class XMLElement;\n\tpublic:\n\n\t\t/// Get the XMLDocument that owns this XMLNode.\n\t\tconst XMLDocument* GetDocument() const {\n\t\t\tTIXMLASSERT(_document);\n\t\t\treturn _document;\n\t\t}\n\t\t/// Get the XMLDocument that owns this XMLNode.\n\t\tXMLDocument* GetDocument() {\n\t\t\tTIXMLASSERT(_document);\n\t\t\treturn _document;\n\t\t}\n\n\t\t/// Safely cast to an Element, or null.\n\t\tvirtual XMLElement*\t\tToElement() {\n\t\t\treturn 0;\n\t\t}\n\t\t/// Safely cast to Text, or null.\n\t\tvirtual XMLText*\t\tToText() {\n\t\t\treturn 0;\n\t\t}\n\t\t/// Safely cast to a Comment, or null.\n\t\tvirtual XMLComment*\t\tToComment() {\n\t\t\treturn 0;\n\t\t}\n\t\t/// Safely cast to a Document, or null.\n\t\tvirtual XMLDocument*\tToDocument() {\n\t\t\treturn 0;\n\t\t}\n\t\t/// Safely cast to a Declaration, or null.\n\t\tvirtual XMLDeclaration*\tToDeclaration() {\n\t\t\treturn 0;\n\t\t}\n\t\t/// Safely cast to an Unknown, or null.\n\t\tvirtual XMLUnknown*\t\tToUnknown() {\n\t\t\treturn 0;\n\t\t}\n\n\t\tvirtual const XMLElement*\t\tToElement() const {\n\t\t\treturn 0;\n\t\t}\n\t\tvirtual const XMLText*\t\t\tToText() const {\n\t\t\treturn 0;\n\t\t}\n\t\tvirtual const XMLComment*\t\tToComment() const {\n\t\t\treturn 0;\n\t\t}\n\t\tvirtual const XMLDocument*\t\tToDocument() const {\n\t\t\treturn 0;\n\t\t}\n\t\tvirtual const XMLDeclaration*\tToDeclaration() const {\n\t\t\treturn 0;\n\t\t}\n\t\tvirtual const XMLUnknown*\t\tToUnknown() const {\n\t\t\treturn 0;\n\t\t}\n\n\t\t/** The meaning of 'value' changes for the specific type.\n\t\t@verbatim\n\t\tDocument:\tempty (NULL is returned, not an empty string)\n\t\tElement:\tname of the element\n\t\tComment:\tthe comment text\n\t\tUnknown:\tthe tag contents\n\t\tText:\t\tthe text string\n\t\t@endverbatim\n\t\t*/\n\t\tconst char* Value() const;\n\n\t\t/** Set the Value of an XML node.\n\t\t@sa Value()\n\t\t*/\n\t\tvoid SetValue(const char* val, bool staticMem = false);\n\n\t\t/// Gets the line number the node is in, if the document was parsed from a file.\n\t\tint GetLineNum() const { return _parseLineNum; }\n\n\t\t/// Get the parent of this node on the DOM.\n\t\tconst XMLNode*\tParent() const {\n\t\t\treturn _parent;\n\t\t}\n\n\t\tXMLNode* Parent() {\n\t\t\treturn _parent;\n\t\t}\n\n\t\t/// Returns true if this node has no children.\n\t\tbool NoChildren() const {\n\t\t\treturn !_firstChild;\n\t\t}\n\n\t\t/// Get the first child node, or null if none exists.\n\t\tconst XMLNode*  FirstChild() const {\n\t\t\treturn _firstChild;\n\t\t}\n\n\t\tXMLNode*\t\tFirstChild() {\n\t\t\treturn _firstChild;\n\t\t}\n\n\t\t/** Get the first child element, or optionally the first child\n\t\telement with the specified name.\n\t\t*/\n\t\tconst XMLElement* FirstChildElement(const char* name = 0) const;\n\n\t\tXMLElement* FirstChildElement(const char* name = 0) {\n\t\t\treturn const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement(name));\n\t\t}\n\n\t\t/// Get the last child node, or null if none exists.\n\t\tconst XMLNode*\tLastChild() const {\n\t\t\treturn _lastChild;\n\t\t}\n\n\t\tXMLNode*\t\tLastChild() {\n\t\t\treturn _lastChild;\n\t\t}\n\n\t\t/** Get the last child element or optionally the last child\n\t\telement with the specified name.\n\t\t*/\n\t\tconst XMLElement* LastChildElement(const char* name = 0) const;\n\n\t\tXMLElement* LastChildElement(const char* name = 0) {\n\t\t\treturn const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name));\n\t\t}\n\n\t\t/// Get the previous (left) sibling node of this node.\n\t\tconst XMLNode*\tPreviousSibling() const {\n\t\t\treturn _prev;\n\t\t}\n\n\t\tXMLNode*\tPreviousSibling() {\n\t\t\treturn _prev;\n\t\t}\n\n\t\t/// Get the previous (left) sibling element of this node, with an optionally supplied name.\n\t\tconst XMLElement*\tPreviousSiblingElement(const char* name = 0) const;\n\n\t\tXMLElement*\tPreviousSiblingElement(const char* name = 0) {\n\t\t\treturn const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement(name));\n\t\t}\n\n\t\t/// Get the next (right) sibling node of this node.\n\t\tconst XMLNode*\tNextSibling() const {\n\t\t\treturn _next;\n\t\t}\n\n\t\tXMLNode*\tNextSibling() {\n\t\t\treturn _next;\n\t\t}\n\n\t\t/// Get the next (right) sibling element of this node, with an optionally supplied name.\n\t\tconst XMLElement*\tNextSiblingElement(const char* name = 0) const;\n\n\t\tXMLElement*\tNextSiblingElement(const char* name = 0) {\n\t\t\treturn const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement(name));\n\t\t}\n\n\t\t/**\n\t\tAdd a child node as the last (right) child.\n\t\tIf the child node is already part of the document,\n\t\tit is moved from its old location to the new location.\n\t\tReturns the addThis argument or 0 if the node does not\n\t\tbelong to the same document.\n\t\t*/\n\t\tXMLNode* InsertEndChild(XMLNode* addThis);\n\n\t\tXMLNode* LinkEndChild(XMLNode* addThis) {\n\t\t\treturn InsertEndChild(addThis);\n\t\t}\n\t\t/**\n\t\tAdd a child node as the first (left) child.\n\t\tIf the child node is already part of the document,\n\t\tit is moved from its old location to the new location.\n\t\tReturns the addThis argument or 0 if the node does not\n\t\tbelong to the same document.\n\t\t*/\n\t\tXMLNode* InsertFirstChild(XMLNode* addThis);\n\t\t/**\n\t\tAdd a node after the specified child node.\n\t\tIf the child node is already part of the document,\n\t\tit is moved from its old location to the new location.\n\t\tReturns the addThis argument or 0 if the afterThis node\n\t\tis not a child of this node, or if the node does not\n\t\tbelong to the same document.\n\t\t*/\n\t\tXMLNode* InsertAfterChild(XMLNode* afterThis, XMLNode* addThis);\n\n\t\t/**\n\t\tDelete all the children of this node.\n\t\t*/\n\t\tvoid DeleteChildren();\n\n\t\t/**\n\t\tDelete a child of this node.\n\t\t*/\n\t\tvoid DeleteChild(XMLNode* node);\n\n\t\t/**\n\t\tMake a copy of this node, but not its children.\n\t\tYou may pass in a Document pointer that will be\n\t\tthe owner of the new Node. If the 'document' is\n\t\tnull, then the node returned will be allocated\n\t\tfrom the current Document. (this->GetDocument())\n\n\t\tNote: if called on a XMLDocument, this will return null.\n\t\t*/\n\t\tvirtual XMLNode* ShallowClone(XMLDocument* document) const = 0;\n\n\t\t/**\n\t\tMake a copy of this node and all its children.\n\n\t\tIf the 'target' is null, then the nodes will\n\t\tbe allocated in the current document. If 'target'\n\t\tis specified, the memory will be allocated is the\n\t\tspecified XMLDocument.\n\n\t\tNOTE: This is probably not the correct tool to\n\t\tcopy a document, since XMLDocuments can have multiple\n\t\ttop level XMLNodes. You probably want to use\n\t\tXMLDocument::DeepCopy()\n\t\t*/\n\t\tXMLNode* DeepClone(XMLDocument* target) const;\n\n\t\t/**\n\t\tTest if 2 nodes are the same, but don't test children.\n\t\tThe 2 nodes do not need to be in the same Document.\n\n\t\tNote: if called on a XMLDocument, this will return false.\n\t\t*/\n\t\tvirtual bool ShallowEqual(const XMLNode* compare) const = 0;\n\n\t\t/** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the\n\t\tXML tree will be conditionally visited and the host will be called back\n\t\tvia the XMLVisitor interface.\n\n\t\tThis is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse\n\t\tthe XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this\n\t\tinterface versus any other.)\n\n\t\tThe interface has been based on ideas from:\n\n\t\t- http://www.saxproject.org/\n\t\t- http://c2.com/cgi/wiki?HierarchicalVisitorPattern\n\n\t\tWhich are both good references for \"visiting\".\n\n\t\tAn example of using Accept():\n\t\t@verbatim\n\t\tXMLPrinter printer;\n\t\ttinyxmlDoc.Accept( &printer );\n\t\tconst char* xmlcstr = printer.CStr();\n\t\t@endverbatim\n\t\t*/\n\t\tvirtual bool Accept(XMLVisitor* visitor) const = 0;\n\n\t\t/**\n\t\tSet user data into the XMLNode. TinyXML-2 in\n\t\tno way processes or interprets user data.\n\t\tIt is initially 0.\n\t\t*/\n\t\tvoid SetUserData(void* userData) { _userData = userData; }\n\n\t\t/**\n\t\tGet user data set into the XMLNode. TinyXML-2 in\n\t\tno way processes or interprets user data.\n\t\tIt is initially 0.\n\t\t*/\n\t\tvoid* GetUserData() const { return _userData; }\n\n\tprotected:\n\t\tXMLNode(XMLDocument*);\n\t\tvirtual ~XMLNode();\n\n\t\tvirtual char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);\n\n\t\tXMLDocument*\t_document;\n\t\tXMLNode*\t\t_parent;\n\t\tmutable StrPair\t_value;\n\t\tint             _parseLineNum;\n\n\t\tXMLNode*\t\t_firstChild;\n\t\tXMLNode*\t\t_lastChild;\n\n\t\tXMLNode*\t\t_prev;\n\t\tXMLNode*\t\t_next;\n\n\t\tvoid*\t\t\t_userData;\n\n\tprivate:\n\t\tMemPool*\t\t_memPool;\n\t\tvoid Unlink(XMLNode* child);\n\t\tstatic void DeleteNode(XMLNode* node);\n\t\tvoid InsertChildPreamble(XMLNode* insertThis) const;\n\t\tconst XMLElement* ToElementWithName(const char* name) const;\n\n\t\tXMLNode(const XMLNode&);\t// not supported\n\t\tXMLNode& operator=(const XMLNode&);\t// not supported\n\t};\n\n\n\t/** XML text.\n\n\tNote that a text node can have child element nodes, for example:\n\t@verbatim\n\t<root>This is <b>bold</b></root>\n\t@endverbatim\n\n\tA text node can have 2 ways to output the next. \"normal\" output\n\tand CDATA. It will default to the mode it was parsed from the XML file and\n\tyou generally want to leave it alone, but you can change the output mode with\n\tSetCData() and query it with CData().\n\t*/\n\tclass TINYXML2_LIB XMLText : public XMLNode\n\t{\n\t\tfriend class XMLDocument;\n\tpublic:\n\t\tvirtual bool Accept(XMLVisitor* visitor) const;\n\n\t\tvirtual XMLText* ToText() {\n\t\t\treturn this;\n\t\t}\n\t\tvirtual const XMLText* ToText() const {\n\t\t\treturn this;\n\t\t}\n\n\t\t/// Declare whether this should be CDATA or standard text.\n\t\tvoid SetCData(bool isCData) {\n\t\t\t_isCData = isCData;\n\t\t}\n\t\t/// Returns true if this is a CDATA text element.\n\t\tbool CData() const {\n\t\t\treturn _isCData;\n\t\t}\n\n\t\tvirtual XMLNode* ShallowClone(XMLDocument* document) const;\n\t\tvirtual bool ShallowEqual(const XMLNode* compare) const;\n\n\tprotected:\n\t\tXMLText(XMLDocument* doc) : XMLNode(doc), _isCData(false) {}\n\t\tvirtual ~XMLText() {}\n\n\t\tchar* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);\n\n\tprivate:\n\t\tbool _isCData;\n\n\t\tXMLText(const XMLText&);\t// not supported\n\t\tXMLText& operator=(const XMLText&);\t// not supported\n\t};\n\n\n\t/** An XML Comment. */\n\tclass TINYXML2_LIB XMLComment : public XMLNode\n\t{\n\t\tfriend class XMLDocument;\n\tpublic:\n\t\tvirtual XMLComment*\tToComment() {\n\t\t\treturn this;\n\t\t}\n\t\tvirtual const XMLComment* ToComment() const {\n\t\t\treturn this;\n\t\t}\n\n\t\tvirtual bool Accept(XMLVisitor* visitor) const;\n\n\t\tvirtual XMLNode* ShallowClone(XMLDocument* document) const;\n\t\tvirtual bool ShallowEqual(const XMLNode* compare) const;\n\n\tprotected:\n\t\tXMLComment(XMLDocument* doc);\n\t\tvirtual ~XMLComment();\n\n\t\tchar* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);\n\n\tprivate:\n\t\tXMLComment(const XMLComment&);\t// not supported\n\t\tXMLComment& operator=(const XMLComment&);\t// not supported\n\t};\n\n\n\t/** In correct XML the declaration is the first entry in the file.\n\t@verbatim\n\t<?xml version=\"1.0\" standalone=\"yes\"?>\n\t@endverbatim\n\n\tTinyXML-2 will happily read or write files without a declaration,\n\thowever.\n\n\tThe text of the declaration isn't interpreted. It is parsed\n\tand written as a string.\n\t*/\n\tclass TINYXML2_LIB XMLDeclaration : public XMLNode\n\t{\n\t\tfriend class XMLDocument;\n\tpublic:\n\t\tvirtual XMLDeclaration*\tToDeclaration() {\n\t\t\treturn this;\n\t\t}\n\t\tvirtual const XMLDeclaration* ToDeclaration() const {\n\t\t\treturn this;\n\t\t}\n\n\t\tvirtual bool Accept(XMLVisitor* visitor) const;\n\n\t\tvirtual XMLNode* ShallowClone(XMLDocument* document) const;\n\t\tvirtual bool ShallowEqual(const XMLNode* compare) const;\n\n\tprotected:\n\t\tXMLDeclaration(XMLDocument* doc);\n\t\tvirtual ~XMLDeclaration();\n\n\t\tchar* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);\n\n\tprivate:\n\t\tXMLDeclaration(const XMLDeclaration&);\t// not supported\n\t\tXMLDeclaration& operator=(const XMLDeclaration&);\t// not supported\n\t};\n\n\n\t/** Any tag that TinyXML-2 doesn't recognize is saved as an\n\tunknown. It is a tag of text, but should not be modified.\n\tIt will be written back to the XML, unchanged, when the file\n\tis saved.\n\n\tDTD tags get thrown into XMLUnknowns.\n\t*/\n\tclass TINYXML2_LIB XMLUnknown : public XMLNode\n\t{\n\t\tfriend class XMLDocument;\n\tpublic:\n\t\tvirtual XMLUnknown*\tToUnknown() {\n\t\t\treturn this;\n\t\t}\n\t\tvirtual const XMLUnknown* ToUnknown() const {\n\t\t\treturn this;\n\t\t}\n\n\t\tvirtual bool Accept(XMLVisitor* visitor) const;\n\n\t\tvirtual XMLNode* ShallowClone(XMLDocument* document) const;\n\t\tvirtual bool ShallowEqual(const XMLNode* compare) const;\n\n\tprotected:\n\t\tXMLUnknown(XMLDocument* doc);\n\t\tvirtual ~XMLUnknown();\n\n\t\tchar* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);\n\n\tprivate:\n\t\tXMLUnknown(const XMLUnknown&);\t// not supported\n\t\tXMLUnknown& operator=(const XMLUnknown&);\t// not supported\n\t};\n\n\n\n\t/** An attribute is a name-value pair. Elements have an arbitrary\n\tnumber of attributes, each with a unique name.\n\n\t@note The attributes are not XMLNodes. You may only query the\n\tNext() attribute in a list.\n\t*/\n\tclass TINYXML2_LIB XMLAttribute\n\t{\n\t\tfriend class XMLElement;\n\tpublic:\n\t\t/// The name of the attribute.\n\t\tconst char* Name() const;\n\n\t\t/// The value of the attribute.\n\t\tconst char* Value() const;\n\n\t\t/// Gets the line number the attribute is in, if the document was parsed from a file.\n\t\tint GetLineNum() const { return _parseLineNum; }\n\n\t\t/// The next attribute in the list.\n\t\tconst XMLAttribute* Next() const {\n\t\t\treturn _next;\n\t\t}\n\n\t\t/** IntValue interprets the attribute as an integer, and returns the value.\n\t\tIf the value isn't an integer, 0 will be returned. There is no error checking;\n\t\tuse QueryIntValue() if you need error checking.\n\t\t*/\n\t\tint\tIntValue() const {\n\t\t\tint i = 0;\n\t\t\tQueryIntValue(&i);\n\t\t\treturn i;\n\t\t}\n\n\t\tint64_t Int64Value() const {\n\t\t\tint64_t i = 0;\n\t\t\tQueryInt64Value(&i);\n\t\t\treturn i;\n\t\t}\n\n\t\t/// Query as an unsigned integer. See IntValue()\n\t\tunsigned UnsignedValue() const {\n\t\t\tunsigned i = 0;\n\t\t\tQueryUnsignedValue(&i);\n\t\t\treturn i;\n\t\t}\n\t\t/// Query as a boolean. See IntValue()\n\t\tbool\t BoolValue() const {\n\t\t\tbool b = false;\n\t\t\tQueryBoolValue(&b);\n\t\t\treturn b;\n\t\t}\n\t\t/// Query as a double. See IntValue()\n\t\tdouble \t DoubleValue() const {\n\t\t\tdouble d = 0;\n\t\t\tQueryDoubleValue(&d);\n\t\t\treturn d;\n\t\t}\n\t\t/// Query as a float. See IntValue()\n\t\tfloat\t FloatValue() const {\n\t\t\tfloat f = 0;\n\t\t\tQueryFloatValue(&f);\n\t\t\treturn f;\n\t\t}\n\n\t\t/** QueryIntValue interprets the attribute as an integer, and returns the value\n\t\tin the provided parameter. The function will return XML_SUCCESS on success,\n\t\tand XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.\n\t\t*/\n\t\tXMLError QueryIntValue(int* value) const;\n\t\t/// See QueryIntValue\n\t\tXMLError QueryUnsignedValue(unsigned int* value) const;\n\t\t/// See QueryIntValue\n\t\tXMLError QueryInt64Value(int64_t* value) const;\n\t\t/// See QueryIntValue\n\t\tXMLError QueryBoolValue(bool* value) const;\n\t\t/// See QueryIntValue\n\t\tXMLError QueryDoubleValue(double* value) const;\n\t\t/// See QueryIntValue\n\t\tXMLError QueryFloatValue(float* value) const;\n\n\t\t/// Set the attribute to a string value.\n\t\tvoid SetAttribute(const char* value);\n\t\t/// Set the attribute to value.\n\t\tvoid SetAttribute(int value);\n\t\t/// Set the attribute to value.\n\t\tvoid SetAttribute(unsigned value);\n\t\t/// Set the attribute to value.\n\t\tvoid SetAttribute(int64_t value);\n\t\t/// Set the attribute to value.\n\t\tvoid SetAttribute(bool value);\n\t\t/// Set the attribute to value.\n\t\tvoid SetAttribute(double value);\n\t\t/// Set the attribute to value.\n\t\tvoid SetAttribute(float value);\n\n\tprivate:\n\t\tenum { BUF_SIZE = 200 };\n\n\t\tXMLAttribute() : _name(), _value(), _parseLineNum(0), _next(0), _memPool(0) {}\n\t\tvirtual ~XMLAttribute() {}\n\n\t\tXMLAttribute(const XMLAttribute&);\t// not supported\n\t\tvoid operator=(const XMLAttribute&);\t// not supported\n\t\tvoid SetName(const char* name);\n\n\t\tchar* ParseDeep(char* p, bool processEntities, int* curLineNumPtr);\n\n\t\tmutable StrPair _name;\n\t\tmutable StrPair _value;\n\t\tint             _parseLineNum;\n\t\tXMLAttribute*   _next;\n\t\tMemPool*        _memPool;\n\t};\n\n\n\t/** The element is a container class. It has a value, the element name,\n\tand can contain other elements, text, comments, and unknowns.\n\tElements also contain an arbitrary number of attributes.\n\t*/\n\tclass TINYXML2_LIB XMLElement : public XMLNode\n\t{\n\t\tfriend class XMLDocument;\n\tpublic:\n\t\t/// Get the name of an element (which is the Value() of the node.)\n\t\tconst char* Name() const {\n\t\t\treturn Value();\n\t\t}\n\t\t/// Set the name of the element.\n\t\tvoid SetName(const char* str, bool staticMem = false) {\n\t\t\tSetValue(str, staticMem);\n\t\t}\n\n\t\tvirtual XMLElement* ToElement() {\n\t\t\treturn this;\n\t\t}\n\t\tvirtual const XMLElement* ToElement() const {\n\t\t\treturn this;\n\t\t}\n\t\tvirtual bool Accept(XMLVisitor* visitor) const;\n\n\t\t/** Given an attribute name, Attribute() returns the value\n\t\tfor the attribute of that name, or null if none\n\t\texists. For example:\n\n\t\t@verbatim\n\t\tconst char* value = ele->Attribute( \"foo\" );\n\t\t@endverbatim\n\n\t\tThe 'value' parameter is normally null. However, if specified,\n\t\tthe attribute will only be returned if the 'name' and 'value'\n\t\tmatch. This allow you to write code:\n\n\t\t@verbatim\n\t\tif ( ele->Attribute( \"foo\", \"bar\" ) ) callFooIsBar();\n\t\t@endverbatim\n\n\t\trather than:\n\t\t@verbatim\n\t\tif ( ele->Attribute( \"foo\" ) ) {\n\t\tif ( strcmp( ele->Attribute( \"foo\" ), \"bar\" ) == 0 ) callFooIsBar();\n\t\t}\n\t\t@endverbatim\n\t\t*/\n\t\tconst char* Attribute(const char* name, const char* value = 0) const;\n\n\t\t/** Given an attribute name, IntAttribute() returns the value\n\t\tof the attribute interpreted as an integer. The default\n\t\tvalue will be returned if the attribute isn't present,\n\t\tor if there is an error. (For a method with error\n\t\tchecking, see QueryIntAttribute()).\n\t\t*/\n\t\tint IntAttribute(const char* name, int defaultValue = 0) const;\n\t\t/// See IntAttribute()\n\t\tunsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;\n\t\t/// See IntAttribute()\n\t\tint64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;\n\t\t/// See IntAttribute()\n\t\tbool BoolAttribute(const char* name, bool defaultValue = false) const;\n\t\t/// See IntAttribute()\n\t\tdouble DoubleAttribute(const char* name, double defaultValue = 0) const;\n\t\t/// See IntAttribute()\n\t\tfloat FloatAttribute(const char* name, float defaultValue = 0) const;\n\n\t\t/** Given an attribute name, QueryIntAttribute() returns\n\t\tXML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion\n\t\tcan't be performed, or XML_NO_ATTRIBUTE if the attribute\n\t\tdoesn't exist. If successful, the result of the conversion\n\t\twill be written to 'value'. If not successful, nothing will\n\t\tbe written to 'value'. This allows you to provide default\n\t\tvalue:\n\n\t\t@verbatim\n\t\tint value = 10;\n\t\tQueryIntAttribute( \"foo\", &value );\t\t// if \"foo\" isn't found, value will still be 10\n\t\t@endverbatim\n\t\t*/\n\t\tXMLError QueryIntAttribute(const char* name, int* value) const {\n\t\t\tconst XMLAttribute* a = FindAttribute(name);\n\t\t\tif (!a) {\n\t\t\t\treturn XML_NO_ATTRIBUTE;\n\t\t\t}\n\t\t\treturn a->QueryIntValue(value);\n\t\t}\n\n\t\t/// See QueryIntAttribute()\n\t\tXMLError QueryUnsignedAttribute(const char* name, unsigned int* value) const {\n\t\t\tconst XMLAttribute* a = FindAttribute(name);\n\t\t\tif (!a) {\n\t\t\t\treturn XML_NO_ATTRIBUTE;\n\t\t\t}\n\t\t\treturn a->QueryUnsignedValue(value);\n\t\t}\n\n\t\t/// See QueryIntAttribute()\n\t\tXMLError QueryInt64Attribute(const char* name, int64_t* value) const {\n\t\t\tconst XMLAttribute* a = FindAttribute(name);\n\t\t\tif (!a) {\n\t\t\t\treturn XML_NO_ATTRIBUTE;\n\t\t\t}\n\t\t\treturn a->QueryInt64Value(value);\n\t\t}\n\n\t\t/// See QueryIntAttribute()\n\t\tXMLError QueryBoolAttribute(const char* name, bool* value) const {\n\t\t\tconst XMLAttribute* a = FindAttribute(name);\n\t\t\tif (!a) {\n\t\t\t\treturn XML_NO_ATTRIBUTE;\n\t\t\t}\n\t\t\treturn a->QueryBoolValue(value);\n\t\t}\n\t\t/// See QueryIntAttribute()\n\t\tXMLError QueryDoubleAttribute(const char* name, double* value) const {\n\t\t\tconst XMLAttribute* a = FindAttribute(name);\n\t\t\tif (!a) {\n\t\t\t\treturn XML_NO_ATTRIBUTE;\n\t\t\t}\n\t\t\treturn a->QueryDoubleValue(value);\n\t\t}\n\t\t/// See QueryIntAttribute()\n\t\tXMLError QueryFloatAttribute(const char* name, float* value) const {\n\t\t\tconst XMLAttribute* a = FindAttribute(name);\n\t\t\tif (!a) {\n\t\t\t\treturn XML_NO_ATTRIBUTE;\n\t\t\t}\n\t\t\treturn a->QueryFloatValue(value);\n\t\t}\n\n\n\t\t/** Given an attribute name, QueryAttribute() returns\n\t\tXML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion\n\t\tcan't be performed, or XML_NO_ATTRIBUTE if the attribute\n\t\tdoesn't exist. It is overloaded for the primitive types,\n\t\tand is a generally more convenient replacement of\n\t\tQueryIntAttribute() and related functions.\n\n\t\tIf successful, the result of the conversion\n\t\twill be written to 'value'. If not successful, nothing will\n\t\tbe written to 'value'. This allows you to provide default\n\t\tvalue:\n\n\t\t@verbatim\n\t\tint value = 10;\n\t\tQueryAttribute( \"foo\", &value );\t\t// if \"foo\" isn't found, value will still be 10\n\t\t@endverbatim\n\t\t*/\n\t\tint QueryAttribute(const char* name, int* value) const {\n\t\t\treturn QueryIntAttribute(name, value);\n\t\t}\n\n\t\tint QueryAttribute(const char* name, unsigned int* value) const {\n\t\t\treturn QueryUnsignedAttribute(name, value);\n\t\t}\n\n\t\tint QueryAttribute(const char* name, int64_t* value) const {\n\t\t\treturn QueryInt64Attribute(name, value);\n\t\t}\n\n\t\tint QueryAttribute(const char* name, bool* value) const {\n\t\t\treturn QueryBoolAttribute(name, value);\n\t\t}\n\n\t\tint QueryAttribute(const char* name, double* value) const {\n\t\t\treturn QueryDoubleAttribute(name, value);\n\t\t}\n\n\t\tint QueryAttribute(const char* name, float* value) const {\n\t\t\treturn QueryFloatAttribute(name, value);\n\t\t}\n\n\t\t/// Sets the named attribute to value.\n\t\tvoid SetAttribute(const char* name, const char* value) {\n\t\t\tXMLAttribute* a = FindOrCreateAttribute(name);\n\t\t\ta->SetAttribute(value);\n\t\t}\n\t\t/// Sets the named attribute to value.\n\t\tvoid SetAttribute(const char* name, int value) {\n\t\t\tXMLAttribute* a = FindOrCreateAttribute(name);\n\t\t\ta->SetAttribute(value);\n\t\t}\n\t\t/// Sets the named attribute to value.\n\t\tvoid SetAttribute(const char* name, unsigned value) {\n\t\t\tXMLAttribute* a = FindOrCreateAttribute(name);\n\t\t\ta->SetAttribute(value);\n\t\t}\n\n\t\t/// Sets the named attribute to value.\n\t\tvoid SetAttribute(const char* name, int64_t value) {\n\t\t\tXMLAttribute* a = FindOrCreateAttribute(name);\n\t\t\ta->SetAttribute(value);\n\t\t}\n\n\t\t/// Sets the named attribute to value.\n\t\tvoid SetAttribute(const char* name, bool value) {\n\t\t\tXMLAttribute* a = FindOrCreateAttribute(name);\n\t\t\ta->SetAttribute(value);\n\t\t}\n\t\t/// Sets the named attribute to value.\n\t\tvoid SetAttribute(const char* name, double value) {\n\t\t\tXMLAttribute* a = FindOrCreateAttribute(name);\n\t\t\ta->SetAttribute(value);\n\t\t}\n\t\t/// Sets the named attribute to value.\n\t\tvoid SetAttribute(const char* name, float value) {\n\t\t\tXMLAttribute* a = FindOrCreateAttribute(name);\n\t\t\ta->SetAttribute(value);\n\t\t}\n\n\t\t/**\n\t\tDelete an attribute.\n\t\t*/\n\t\tvoid DeleteAttribute(const char* name);\n\n\t\t/// Return the first attribute in the list.\n\t\tconst XMLAttribute* FirstAttribute() const {\n\t\t\treturn _rootAttribute;\n\t\t}\n\t\t/// Query a specific attribute in the list.\n\t\tconst XMLAttribute* FindAttribute(const char* name) const;\n\n\t\t/** Convenience function for easy access to the text inside an element. Although easy\n\t\tand concise, GetText() is limited compared to getting the XMLText child\n\t\tand accessing it directly.\n\n\t\tIf the first child of 'this' is a XMLText, the GetText()\n\t\treturns the character string of the Text node, else null is returned.\n\n\t\tThis is a convenient method for getting the text of simple contained text:\n\t\t@verbatim\n\t\t<foo>This is text</foo>\n\t\tconst char* str = fooElement->GetText();\n\t\t@endverbatim\n\n\t\t'str' will be a pointer to \"This is text\".\n\n\t\tNote that this function can be misleading. If the element foo was created from\n\t\tthis XML:\n\t\t@verbatim\n\t\t<foo><b>This is text</b></foo>\n\t\t@endverbatim\n\n\t\tthen the value of str would be null. The first child node isn't a text node, it is\n\t\tanother element. From this XML:\n\t\t@verbatim\n\t\t<foo>This is <b>text</b></foo>\n\t\t@endverbatim\n\t\tGetText() will return \"This is \".\n\t\t*/\n\t\tconst char* GetText() const;\n\n\t\t/** Convenience function for easy access to the text inside an element. Although easy\n\t\tand concise, SetText() is limited compared to creating an XMLText child\n\t\tand mutating it directly.\n\n\t\tIf the first child of 'this' is a XMLText, SetText() sets its value to\n\t\tthe given string, otherwise it will create a first child that is an XMLText.\n\n\t\tThis is a convenient method for setting the text of simple contained text:\n\t\t@verbatim\n\t\t<foo>This is text</foo>\n\t\tfooElement->SetText( \"Hullaballoo!\" );\n\t\t<foo>Hullaballoo!</foo>\n\t\t@endverbatim\n\n\t\tNote that this function can be misleading. If the element foo was created from\n\t\tthis XML:\n\t\t@verbatim\n\t\t<foo><b>This is text</b></foo>\n\t\t@endverbatim\n\n\t\tthen it will not change \"This is text\", but rather prefix it with a text element:\n\t\t@verbatim\n\t\t<foo>Hullaballoo!<b>This is text</b></foo>\n\t\t@endverbatim\n\n\t\tFor this XML:\n\t\t@verbatim\n\t\t<foo />\n\t\t@endverbatim\n\t\tSetText() will generate\n\t\t@verbatim\n\t\t<foo>Hullaballoo!</foo>\n\t\t@endverbatim\n\t\t*/\n\t\tvoid SetText(const char* inText);\n\t\t/// Convenience method for setting text inside an element. See SetText() for important limitations.\n\t\tvoid SetText(int value);\n\t\t/// Convenience method for setting text inside an element. See SetText() for important limitations.\n\t\tvoid SetText(unsigned value);\n\t\t/// Convenience method for setting text inside an element. See SetText() for important limitations.\n\t\tvoid SetText(int64_t value);\n\t\t/// Convenience method for setting text inside an element. See SetText() for important limitations.\n\t\tvoid SetText(bool value);\n\t\t/// Convenience method for setting text inside an element. See SetText() for important limitations.\n\t\tvoid SetText(double value);\n\t\t/// Convenience method for setting text inside an element. See SetText() for important limitations.\n\t\tvoid SetText(float value);\n\n\t\t/**\n\t\tConvenience method to query the value of a child text node. This is probably best\n\t\tshown by example. Given you have a document is this form:\n\t\t@verbatim\n\t\t<point>\n\t\t<x>1</x>\n\t\t<y>1.4</y>\n\t\t</point>\n\t\t@endverbatim\n\n\t\tThe QueryIntText() and similar functions provide a safe and easier way to get to the\n\t\t\"value\" of x and y.\n\n\t\t@verbatim\n\t\tint x = 0;\n\t\tfloat y = 0;\t// types of x and y are contrived for example\n\t\tconst XMLElement* xElement = pointElement->FirstChildElement( \"x\" );\n\t\tconst XMLElement* yElement = pointElement->FirstChildElement( \"y\" );\n\t\txElement->QueryIntText( &x );\n\t\tyElement->QueryFloatText( &y );\n\t\t@endverbatim\n\n\t\t@returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted\n\t\tto the requested type, and XML_NO_TEXT_NODE if there is no child text to query.\n\n\t\t*/\n\t\tXMLError QueryIntText(int* ival) const;\n\t\t/// See QueryIntText()\n\t\tXMLError QueryUnsignedText(unsigned* uval) const;\n\t\t/// See QueryIntText()\n\t\tXMLError QueryInt64Text(int64_t* uval) const;\n\t\t/// See QueryIntText()\n\t\tXMLError QueryBoolText(bool* bval) const;\n\t\t/// See QueryIntText()\n\t\tXMLError QueryDoubleText(double* dval) const;\n\t\t/// See QueryIntText()\n\t\tXMLError QueryFloatText(float* fval) const;\n\n\t\tint IntText(int defaultValue = 0) const;\n\n\t\t/// See QueryIntText()\n\t\tunsigned UnsignedText(unsigned defaultValue = 0) const;\n\t\t/// See QueryIntText()\n\t\tint64_t Int64Text(int64_t defaultValue = 0) const;\n\t\t/// See QueryIntText()\n\t\tbool BoolText(bool defaultValue = false) const;\n\t\t/// See QueryIntText()\n\t\tdouble DoubleText(double defaultValue = 0) const;\n\t\t/// See QueryIntText()\n\t\tfloat FloatText(float defaultValue = 0) const;\n\n\t\t// internal:\n\t\tenum ElementClosingType {\n\t\t\tOPEN,\t\t// <foo>\n\t\t\tCLOSED,\t\t// <foo/>\n\t\t\tCLOSING\t\t// </foo>\n\t\t};\n\t\tElementClosingType ClosingType() const {\n\t\t\treturn _closingType;\n\t\t}\n\t\tvirtual XMLNode* ShallowClone(XMLDocument* document) const;\n\t\tvirtual bool ShallowEqual(const XMLNode* compare) const;\n\n\tprotected:\n\t\tchar* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);\n\n\tprivate:\n\t\tXMLElement(XMLDocument* doc);\n\t\tvirtual ~XMLElement();\n\t\tXMLElement(const XMLElement&);\t// not supported\n\t\tvoid operator=(const XMLElement&);\t// not supported\n\n\t\tXMLAttribute* FindAttribute(const char* name) {\n\t\t\treturn const_cast<XMLAttribute*>(const_cast<const XMLElement*>(this)->FindAttribute(name));\n\t\t}\n\t\tXMLAttribute* FindOrCreateAttribute(const char* name);\n\t\t//void LinkAttribute( XMLAttribute* attrib );\n\t\tchar* ParseAttributes(char* p, int* curLineNumPtr);\n\t\tstatic void DeleteAttribute(XMLAttribute* attribute);\n\t\tXMLAttribute* CreateAttribute();\n\n\t\tenum { BUF_SIZE = 200 };\n\t\tElementClosingType _closingType;\n\t\t// The attribute list is ordered; there is no 'lastAttribute'\n\t\t// because the list needs to be scanned for dupes before adding\n\t\t// a new attribute.\n\t\tXMLAttribute* _rootAttribute;\n\t};\n\n\n\tenum Whitespace {\n\t\tPRESERVE_WHITESPACE,\n\t\tCOLLAPSE_WHITESPACE\n\t};\n\n\n\t/** A Document binds together all the functionality.\n\tIt can be saved, loaded, and printed to the screen.\n\tAll Nodes are connected and allocated to a Document.\n\tIf the Document is deleted, all its Nodes are also deleted.\n\t*/\n\tclass TINYXML2_LIB XMLDocument : public XMLNode\n\t{\n\t\tfriend class XMLElement;\n\tpublic:\n\t\t/// constructor\n\t\tXMLDocument(bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE);\n\t\t~XMLDocument();\n\n\t\tvirtual XMLDocument* ToDocument() {\n\t\t\tTIXMLASSERT(this == _document);\n\t\t\treturn this;\n\t\t}\n\t\tvirtual const XMLDocument* ToDocument() const {\n\t\t\tTIXMLASSERT(this == _document);\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\tParse an XML file from a character string.\n\t\tReturns XML_SUCCESS (0) on success, or\n\t\tan errorID.\n\n\t\tYou may optionally pass in the 'nBytes', which is\n\t\tthe number of bytes which will be parsed. If not\n\t\tspecified, TinyXML-2 will assume 'xml' points to a\n\t\tnull terminated string.\n\t\t*/\n\t\tXMLError Parse(const char* xml, size_t nBytes = (size_t)(-1));\n\n\t\t/**\n\t\tLoad an XML file from disk.\n\t\tReturns XML_SUCCESS (0) on success, or\n\t\tan errorID.\n\t\t*/\n\t\tXMLError LoadFile(const char* filename);\n\n\t\t/**\n\t\tLoad an XML file from disk. You are responsible\n\t\tfor providing and closing the FILE*.\n\n\t\tNOTE: The file should be opened as binary (\"rb\")\n\t\tnot text in order for TinyXML-2 to correctly\n\t\tdo newline normalization.\n\n\t\tReturns XML_SUCCESS (0) on success, or\n\t\tan errorID.\n\t\t*/\n\t\tXMLError LoadFile(FILE*);\n\n\t\t/**\n\t\tSave the XML file to disk.\n\t\tReturns XML_SUCCESS (0) on success, or\n\t\tan errorID.\n\t\t*/\n\t\tXMLError SaveFile(const char* filename, bool compact = false);\n\n\t\t/**\n\t\tSave the XML file to disk. You are responsible\n\t\tfor providing and closing the FILE*.\n\n\t\tReturns XML_SUCCESS (0) on success, or\n\t\tan errorID.\n\t\t*/\n\t\tXMLError SaveFile(FILE* fp, bool compact = false);\n\n\t\tbool ProcessEntities() const {\n\t\t\treturn _processEntities;\n\t\t}\n\t\tWhitespace WhitespaceMode() const {\n\t\t\treturn _whitespaceMode;\n\t\t}\n\n\t\t/**\n\t\tReturns true if this document has a leading Byte Order Mark of UTF8.\n\t\t*/\n\t\tbool HasBOM() const {\n\t\t\treturn _writeBOM;\n\t\t}\n\t\t/** Sets whether to write the BOM when writing the file.\n\t\t*/\n\t\tvoid SetBOM(bool useBOM) {\n\t\t\t_writeBOM = useBOM;\n\t\t}\n\n\t\t/** Return the root element of DOM. Equivalent to FirstChildElement().\n\t\tTo get the first node, use FirstChild().\n\t\t*/\n\t\tXMLElement* RootElement() {\n\t\t\treturn FirstChildElement();\n\t\t}\n\t\tconst XMLElement* RootElement() const {\n\t\t\treturn FirstChildElement();\n\t\t}\n\n\t\t/** Print the Document. If the Printer is not provided, it will\n\t\tprint to stdout. If you provide Printer, this can print to a file:\n\t\t@verbatim\n\t\tXMLPrinter printer( fp );\n\t\tdoc.Print( &printer );\n\t\t@endverbatim\n\n\t\tOr you can use a printer to print to memory:\n\t\t@verbatim\n\t\tXMLPrinter printer;\n\t\tdoc.Print( &printer );\n\t\t// printer.CStr() has a const char* to the XML\n\t\t@endverbatim\n\t\t*/\n\t\tvoid Print(XMLPrinter* streamer = 0) const;\n\t\tvirtual bool Accept(XMLVisitor* visitor) const;\n\n\t\t/**\n\t\tCreate a new Element associated with\n\t\tthis Document. The memory for the Element\n\t\tis managed by the Document.\n\t\t*/\n\t\tXMLElement* NewElement(const char* name);\n\t\t/**\n\t\tCreate a new Comment associated with\n\t\tthis Document. The memory for the Comment\n\t\tis managed by the Document.\n\t\t*/\n\t\tXMLComment* NewComment(const char* comment);\n\t\t/**\n\t\tCreate a new Text associated with\n\t\tthis Document. The memory for the Text\n\t\tis managed by the Document.\n\t\t*/\n\t\tXMLText* NewText(const char* text);\n\t\t/**\n\t\tCreate a new Declaration associated with\n\t\tthis Document. The memory for the object\n\t\tis managed by the Document.\n\n\t\tIf the 'text' param is null, the standard\n\t\tdeclaration is used.:\n\t\t@verbatim\n\t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\t\t@endverbatim\n\t\t*/\n\t\tXMLDeclaration* NewDeclaration(const char* text = 0);\n\t\t/**\n\t\tCreate a new Unknown associated with\n\t\tthis Document. The memory for the object\n\t\tis managed by the Document.\n\t\t*/\n\t\tXMLUnknown* NewUnknown(const char* text);\n\n\t\t/**\n\t\tDelete a node associated with this document.\n\t\tIt will be unlinked from the DOM.\n\t\t*/\n\t\tvoid DeleteNode(XMLNode* node);\n\n\t\tvoid SetError(XMLError error, const char* str1, const char* str2, int lineNum);\n\n\t\tvoid ClearError() {\n\t\t\tSetError(XML_SUCCESS, 0, 0, 0);\n\t\t}\n\n\t\t/// Return true if there was an error parsing the document.\n\t\tbool Error() const {\n\t\t\treturn _errorID != XML_SUCCESS;\n\t\t}\n\t\t/// Return the errorID.\n\t\tXMLError  ErrorID() const {\n\t\t\treturn _errorID;\n\t\t}\n\t\tconst char* ErrorName() const;\n\t\tstatic const char* ErrorIDToName(XMLError errorID);\n\n\t\t/// Return a possibly helpful diagnostic location or string.\n\t\tconst char* GetErrorStr1() const;\n\n\t\t/// Return a possibly helpful secondary diagnostic location or string.\n\t\tconst char* GetErrorStr2() const;\n\n\t\t/// Return the line where the error occured, or zero if unknown.\n\t\tint GetErrorLineNum() const\n\t\t{\n\t\t\treturn _errorLineNum;\n\t\t}\n\t\t/// If there is an error, print it to stdout.\n\t\tvoid PrintError() const;\n\n\t\t/// Clear the document, resetting it to the initial state.\n\t\tvoid Clear();\n\n\t\t/**\n\t\tCopies this document to a target document.\n\t\tThe target will be completely cleared before the copy.\n\t\tIf you want to copy a sub-tree, see XMLNode::DeepClone().\n\n\t\tNOTE: that the 'target' must be non-null.\n\t\t*/\n\t\tvoid DeepCopy(XMLDocument* target) const;\n\n\t\t// internal\n\t\tchar* Identify(char* p, XMLNode** node);\n\n\t\t// internal\n\t\tvoid MarkInUse(XMLNode*);\n\n\t\tvirtual XMLNode* ShallowClone(XMLDocument* /*document*/) const {\n\t\t\treturn 0;\n\t\t}\n\t\tvirtual bool ShallowEqual(const XMLNode* /*compare*/) const {\n\t\t\treturn false;\n\t\t}\n\n\tprivate:\n\t\tXMLDocument(const XMLDocument&);\t// not supported\n\t\tvoid operator=(const XMLDocument&);\t// not supported\n\n\t\tbool\t\t\t_writeBOM;\n\t\tbool\t\t\t_processEntities;\n\t\tXMLError\t\t_errorID;\n\t\tWhitespace\t\t_whitespaceMode;\n\t\tmutable StrPair\t_errorStr1;\n\t\tmutable StrPair\t_errorStr2;\n\t\tint             _errorLineNum;\n\t\tchar*\t\t\t_charBuffer;\n\t\tint\t\t\t\t_parseCurLineNum;\n\t\t// Memory tracking does add some overhead.\n\t\t// However, the code assumes that you don't\n\t\t// have a bunch of unlinked nodes around.\n\t\t// Therefore it takes less memory to track\n\t\t// in the document vs. a linked list in the XMLNode,\n\t\t// and the performance is the same.\n\t\tDynArray<XMLNode*, 10> _unlinked;\n\n\t\tMemPoolT< sizeof(XMLElement) >\t _elementPool;\n\t\tMemPoolT< sizeof(XMLAttribute) > _attributePool;\n\t\tMemPoolT< sizeof(XMLText) >\t\t _textPool;\n\t\tMemPoolT< sizeof(XMLComment) >\t _commentPool;\n\n\t\tstatic const char* _errorNames[XML_ERROR_COUNT];\n\n\t\tvoid Parse();\n\n\t\ttemplate<class NodeType, int PoolElementSize>\n\t\tNodeType* CreateUnlinkedNode(MemPoolT<PoolElementSize>& pool);\n\t};\n\n\ttemplate<class NodeType, int PoolElementSize>\n\tinline NodeType* XMLDocument::CreateUnlinkedNode(MemPoolT<PoolElementSize>& pool)\n\t{\n\t\tTIXMLASSERT(sizeof(NodeType) == PoolElementSize);\n\t\tTIXMLASSERT(sizeof(NodeType) == pool.ItemSize());\n\t\tNodeType* returnNode = new (pool.Alloc()) NodeType(this);\n\t\tTIXMLASSERT(returnNode);\n\t\treturnNode->_memPool = &pool;\n\n\t\t_unlinked.Push(returnNode);\n\t\treturn returnNode;\n\t}\n\n\t/**\n\tA XMLHandle is a class that wraps a node pointer with null checks; this is\n\tan incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2\n\tDOM structure. It is a separate utility class.\n\n\tTake an example:\n\t@verbatim\n\t<Document>\n\t<Element attributeA = \"valueA\">\n\t<Child attributeB = \"value1\" />\n\t<Child attributeB = \"value2\" />\n\t</Element>\n\t</Document>\n\t@endverbatim\n\n\tAssuming you want the value of \"attributeB\" in the 2nd \"Child\" element, it's very\n\teasy to write a *lot* of code that looks like:\n\n\t@verbatim\n\tXMLElement* root = document.FirstChildElement( \"Document\" );\n\tif ( root )\n\t{\n\tXMLElement* element = root->FirstChildElement( \"Element\" );\n\tif ( element )\n\t{\n\tXMLElement* child = element->FirstChildElement( \"Child\" );\n\tif ( child )\n\t{\n\tXMLElement* child2 = child->NextSiblingElement( \"Child\" );\n\tif ( child2 )\n\t{\n\t// Finally do something useful.\n\t@endverbatim\n\n\tAnd that doesn't even cover \"else\" cases. XMLHandle addresses the verbosity\n\tof such code. A XMLHandle checks for null pointers so it is perfectly safe\n\tand correct to use:\n\n\t@verbatim\n\tXMLHandle docHandle( &document );\n\tXMLElement* child2 = docHandle.FirstChildElement( \"Document\" ).FirstChildElement( \"Element\" ).FirstChildElement().NextSiblingElement();\n\tif ( child2 )\n\t{\n\t// do something useful\n\t@endverbatim\n\n\tWhich is MUCH more concise and useful.\n\n\tIt is also safe to copy handles - internally they are nothing more than node pointers.\n\t@verbatim\n\tXMLHandle handleCopy = handle;\n\t@endverbatim\n\n\tSee also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.\n\t*/\n\tclass TINYXML2_LIB XMLHandle\n\t{\n\tpublic:\n\t\t/// Create a handle from any node (at any depth of the tree.) This can be a null pointer.\n\t\tXMLHandle(XMLNode* node) : _node(node) {\n\t\t}\n\t\t/// Create a handle from a node.\n\t\tXMLHandle(XMLNode& node) : _node(&node) {\n\t\t}\n\t\t/// Copy constructor\n\t\tXMLHandle(const XMLHandle& ref) : _node(ref._node) {\n\t\t}\n\t\t/// Assignment\n\t\tXMLHandle& operator=(const XMLHandle& ref) {\n\t\t\t_node = ref._node;\n\t\t\treturn *this;\n\t\t}\n\n\t\t/// Get the first child of this handle.\n\t\tXMLHandle FirstChild() {\n\t\t\treturn XMLHandle(_node ? _node->FirstChild() : 0);\n\t\t}\n\t\t/// Get the first child element of this handle.\n\t\tXMLHandle FirstChildElement(const char* name = 0) {\n\t\t\treturn XMLHandle(_node ? _node->FirstChildElement(name) : 0);\n\t\t}\n\t\t/// Get the last child of this handle.\n\t\tXMLHandle LastChild() {\n\t\t\treturn XMLHandle(_node ? _node->LastChild() : 0);\n\t\t}\n\t\t/// Get the last child element of this handle.\n\t\tXMLHandle LastChildElement(const char* name = 0) {\n\t\t\treturn XMLHandle(_node ? _node->LastChildElement(name) : 0);\n\t\t}\n\t\t/// Get the previous sibling of this handle.\n\t\tXMLHandle PreviousSibling() {\n\t\t\treturn XMLHandle(_node ? _node->PreviousSibling() : 0);\n\t\t}\n\t\t/// Get the previous sibling element of this handle.\n\t\tXMLHandle PreviousSiblingElement(const char* name = 0) {\n\t\t\treturn XMLHandle(_node ? _node->PreviousSiblingElement(name) : 0);\n\t\t}\n\t\t/// Get the next sibling of this handle.\n\t\tXMLHandle NextSibling() {\n\t\t\treturn XMLHandle(_node ? _node->NextSibling() : 0);\n\t\t}\n\t\t/// Get the next sibling element of this handle.\n\t\tXMLHandle NextSiblingElement(const char* name = 0) {\n\t\t\treturn XMLHandle(_node ? _node->NextSiblingElement(name) : 0);\n\t\t}\n\n\t\t/// Safe cast to XMLNode. This can return null.\n\t\tXMLNode* ToNode() {\n\t\t\treturn _node;\n\t\t}\n\t\t/// Safe cast to XMLElement. This can return null.\n\t\tXMLElement* ToElement() {\n\t\t\treturn (_node ? _node->ToElement() : 0);\n\t\t}\n\t\t/// Safe cast to XMLText. This can return null.\n\t\tXMLText* ToText() {\n\t\t\treturn (_node ? _node->ToText() : 0);\n\t\t}\n\t\t/// Safe cast to XMLUnknown. This can return null.\n\t\tXMLUnknown* ToUnknown() {\n\t\t\treturn (_node ? _node->ToUnknown() : 0);\n\t\t}\n\t\t/// Safe cast to XMLDeclaration. This can return null.\n\t\tXMLDeclaration* ToDeclaration() {\n\t\t\treturn (_node ? _node->ToDeclaration() : 0);\n\t\t}\n\n\tprivate:\n\t\tXMLNode* _node;\n\t};\n\n\n\t/**\n\tA variant of the XMLHandle class for working with const XMLNodes and Documents. It is the\n\tsame in all regards, except for the 'const' qualifiers. See XMLHandle for API.\n\t*/\n\tclass TINYXML2_LIB XMLConstHandle\n\t{\n\tpublic:\n\t\tXMLConstHandle(const XMLNode* node) : _node(node) {\n\t\t}\n\t\tXMLConstHandle(const XMLNode& node) : _node(&node) {\n\t\t}\n\t\tXMLConstHandle(const XMLConstHandle& ref) : _node(ref._node) {\n\t\t}\n\n\t\tXMLConstHandle& operator=(const XMLConstHandle& ref) {\n\t\t\t_node = ref._node;\n\t\t\treturn *this;\n\t\t}\n\n\t\tconst XMLConstHandle FirstChild() const {\n\t\t\treturn XMLConstHandle(_node ? _node->FirstChild() : 0);\n\t\t}\n\t\tconst XMLConstHandle FirstChildElement(const char* name = 0) const {\n\t\t\treturn XMLConstHandle(_node ? _node->FirstChildElement(name) : 0);\n\t\t}\n\t\tconst XMLConstHandle LastChild()\tconst {\n\t\t\treturn XMLConstHandle(_node ? _node->LastChild() : 0);\n\t\t}\n\t\tconst XMLConstHandle LastChildElement(const char* name = 0) const {\n\t\t\treturn XMLConstHandle(_node ? _node->LastChildElement(name) : 0);\n\t\t}\n\t\tconst XMLConstHandle PreviousSibling() const {\n\t\t\treturn XMLConstHandle(_node ? _node->PreviousSibling() : 0);\n\t\t}\n\t\tconst XMLConstHandle PreviousSiblingElement(const char* name = 0) const {\n\t\t\treturn XMLConstHandle(_node ? _node->PreviousSiblingElement(name) : 0);\n\t\t}\n\t\tconst XMLConstHandle NextSibling() const {\n\t\t\treturn XMLConstHandle(_node ? _node->NextSibling() : 0);\n\t\t}\n\t\tconst XMLConstHandle NextSiblingElement(const char* name = 0) const {\n\t\t\treturn XMLConstHandle(_node ? _node->NextSiblingElement(name) : 0);\n\t\t}\n\n\n\t\tconst XMLNode* ToNode() const {\n\t\t\treturn _node;\n\t\t}\n\t\tconst XMLElement* ToElement() const {\n\t\t\treturn (_node ? _node->ToElement() : 0);\n\t\t}\n\t\tconst XMLText* ToText() const {\n\t\t\treturn (_node ? _node->ToText() : 0);\n\t\t}\n\t\tconst XMLUnknown* ToUnknown() const {\n\t\t\treturn (_node ? _node->ToUnknown() : 0);\n\t\t}\n\t\tconst XMLDeclaration* ToDeclaration() const {\n\t\t\treturn (_node ? _node->ToDeclaration() : 0);\n\t\t}\n\n\tprivate:\n\t\tconst XMLNode* _node;\n\t};\n\n\n\t/**\n\tPrinting functionality. The XMLPrinter gives you more\n\toptions than the XMLDocument::Print() method.\n\n\tIt can:\n\t-# Print to memory.\n\t-# Print to a file you provide.\n\t-# Print XML without a XMLDocument.\n\n\tPrint to Memory\n\n\t@verbatim\n\tXMLPrinter printer;\n\tdoc.Print( &printer );\n\tSomeFunction( printer.CStr() );\n\t@endverbatim\n\n\tPrint to a File\n\n\tYou provide the file pointer.\n\t@verbatim\n\tXMLPrinter printer( fp );\n\tdoc.Print( &printer );\n\t@endverbatim\n\n\tPrint without a XMLDocument\n\n\tWhen loading, an XML parser is very useful. However, sometimes\n\twhen saving, it just gets in the way. The code is often set up\n\tfor streaming, and constructing the DOM is just overhead.\n\n\tThe Printer supports the streaming case. The following code\n\tprints out a trivially simple XML file without ever creating\n\tan XML document.\n\n\t@verbatim\n\tXMLPrinter printer( fp );\n\tprinter.OpenElement( \"foo\" );\n\tprinter.PushAttribute( \"foo\", \"bar\" );\n\tprinter.CloseElement();\n\t@endverbatim\n\t*/\n\tclass TINYXML2_LIB XMLPrinter : public XMLVisitor\n\t{\n\tpublic:\n\t\t/** Construct the printer. If the FILE* is specified,\n\t\tthis will print to the FILE. Else it will print\n\t\tto memory, and the result is available in CStr().\n\t\tIf 'compact' is set to true, then output is created\n\t\twith only required whitespace and newlines.\n\t\t*/\n\t\tXMLPrinter(FILE* file = 0, bool compact = false, int depth = 0);\n\t\tvirtual ~XMLPrinter() {}\n\n\t\t/** If streaming, write the BOM and declaration. */\n\t\tvoid PushHeader(bool writeBOM, bool writeDeclaration);\n\t\t/** If streaming, start writing an element.\n\t\tThe element must be closed with CloseElement()\n\t\t*/\n\t\tvoid OpenElement(const char* name, bool compactMode = false);\n\t\t/// If streaming, add an attribute to an open element.\n\t\tvoid PushAttribute(const char* name, const char* value);\n\t\tvoid PushAttribute(const char* name, int value);\n\t\tvoid PushAttribute(const char* name, unsigned value);\n\t\tvoid PushAttribute(const char* name, int64_t value);\n\t\tvoid PushAttribute(const char* name, bool value);\n\t\tvoid PushAttribute(const char* name, double value);\n\t\t/// If streaming, close the Element.\n\t\tvirtual void CloseElement(bool compactMode = false);\n\n\t\t/// Add a text node.\n\t\tvoid PushText(const char* text, bool cdata = false);\n\t\t/// Add a text node from an integer.\n\t\tvoid PushText(int value);\n\t\t/// Add a text node from an unsigned.\n\t\tvoid PushText(unsigned value);\n\t\t/// Add a text node from an unsigned.\n\t\tvoid PushText(int64_t value);\n\t\t/// Add a text node from a bool.\n\t\tvoid PushText(bool value);\n\t\t/// Add a text node from a float.\n\t\tvoid PushText(float value);\n\t\t/// Add a text node from a double.\n\t\tvoid PushText(double value);\n\n\t\t/// Add a comment\n\t\tvoid PushComment(const char* comment);\n\n\t\tvoid PushDeclaration(const char* value);\n\t\tvoid PushUnknown(const char* value);\n\n\t\tvirtual bool VisitEnter(const XMLDocument& /*doc*/);\n\t\tvirtual bool VisitExit(const XMLDocument& /*doc*/) {\n\t\t\treturn true;\n\t\t}\n\n\t\tvirtual bool VisitEnter(const XMLElement& element, const XMLAttribute* attribute);\n\t\tvirtual bool VisitExit(const XMLElement& element);\n\n\t\tvirtual bool Visit(const XMLText& text);\n\t\tvirtual bool Visit(const XMLComment& comment);\n\t\tvirtual bool Visit(const XMLDeclaration& declaration);\n\t\tvirtual bool Visit(const XMLUnknown& unknown);\n\n\t\t/**\n\t\tIf in print to memory mode, return a pointer to\n\t\tthe XML file in memory.\n\t\t*/\n\t\tconst char* CStr() const {\n\t\t\treturn _buffer.Mem();\n\t\t}\n\t\t/**\n\t\tIf in print to memory mode, return the size\n\t\tof the XML file in memory. (Note the size returned\n\t\tincludes the terminating null.)\n\t\t*/\n\t\tint CStrSize() const {\n\t\t\treturn _buffer.Size();\n\t\t}\n\t\t/**\n\t\tIf in print to memory mode, reset the buffer to the\n\t\tbeginning.\n\t\t*/\n\t\tvoid ClearBuffer() {\n\t\t\t_buffer.Clear();\n\t\t\t_buffer.Push(0);\n\t\t\t_firstElement = true;\n\t\t}\n\n\tprotected:\n\t\tvirtual bool CompactMode(const XMLElement&) { return _compactMode; }\n\n\t\t/** Prints out the space before an element. You may override to change\n\t\tthe space and tabs used. A PrintSpace() override should call Print().\n\t\t*/\n\t\tvirtual void PrintSpace(int depth);\n\t\tvoid Print(const char* format, ...);\n\n\t\tvoid SealElementIfJustOpened();\n\t\tbool _elementJustOpened;\n\t\tDynArray< const char*, 10 > _stack;\n\n\tprivate:\n\t\tvoid PrintString(const char*, bool restrictedEntitySet);\t// prints out, after detecting entities.\n\n\t\tbool _firstElement;\n\t\tFILE* _fp;\n\t\tint _depth;\n\t\tint _textDepth;\n\t\tbool _processEntities;\n\t\tbool _compactMode;\n\n\t\tenum {\n\t\t\tENTITY_RANGE = 64,\n\t\t\tBUF_SIZE = 200\n\t\t};\n\t\tbool _entityFlag[ENTITY_RANGE];\n\t\tbool _restrictedEntityFlag[ENTITY_RANGE];\n\n\t\tDynArray< char, 20 > _buffer;\n\n\t\t// Prohibit cloning, intentionally not implemented\n\t\tXMLPrinter(const XMLPrinter&);\n\t\tXMLPrinter& operator=(const XMLPrinter&);\n\t};\n\n\n}\t// tinyxml2\n\n#if defined(_MSC_VER)\n#   pragma warning(pop)\n#endif\n\n#endif // TINYXML2_INCLUDED\n"
  },
  {
    "path": "vcpkg.json",
    "content": "{\n  \"name\": \"cemu\",\n  \"version-string\": \"1.0\",\n  \"builtin-baseline\": \"f0fb3ddba5135b80982668de39dbaa139c00d281\",\n  \"dependencies\": [\n    \"pugixml\",\n    \"zlib\",\n    \"zstd\",\n    {\n      \"name\": \"libzip\",\n      \"default-features\": false\n    },\n    \"rapidjson\",\n    \"sdl2\",\n    \"boost-tokenizer\",\n    \"boost-container\",\n    \"boost-program-options\",\n    \"boost-nowide\",\n    \"boost-algorithm\",\n    \"boost-functional\",\n    \"boost-optional\",\n    \"boost-signals2\",\n    \"boost-asio\",\n    \"boost-ptr-container\",\n    \"boost-property-tree\",\n    \"boost-static-string\",\n    \"boost-random\",\n    {\n      \"name\": \"fmt\",\n      \"version>=\": \"12.1.0\"\n    },\n    \"hidapi\",\n    \"libpng\",\n    \"glm\",\n    {\n      \"name\": \"glslang\",\n      \"default-features\": false\n    },\n    \"zstd\",\n    \"wxwidgets\",\n    \"openssl\",\n    {\n      \"name\": \"curl\",\n      \"default-features\": false,\n      \"features\": [\n        \"openssl\"\n      ]\n    },\n    {\n      \"name\": \"dbus\",\n      \"default-features\": false,\n      \"platform\": \"linux\"\n    },\n    {\n      \"name\": \"tiff\",\n      \"default-features\": false,\n      \"features\": [\n        \"jpeg\",\n        \"zip\"\n      ]\n    },\n    \"libusb\"\n  ],\n  \"overrides\": [\n    {\n      \"name\": \"glslang\",\n      \"version\": \"15.1.0\"\n    },\n    {\n      \"name\": \"sdl2\",\n      \"version\": \"2.32.10\"\n    },\n    {\n      \"name\": \"wxwidgets\",\n      \"version\": \"3.3.1\"\n    }\n  ]\n}\n"
  }
]